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:
authorClément Foucault <foucault.clem@gmail.com>2022-01-26 23:57:44 +0300
committerClément Foucault <foucault.clem@gmail.com>2022-01-27 00:03:58 +0300
commit4226c484bdbe7336f1221094916fcdfb12850034 (patch)
tree33428e72be40105c222ca77935ee1554b702facc /source/blender
parent55a6a8900aec81e94f4d82401d6051e3b5507c0e (diff)
parentaf87b6d8cb75d9d625378dee25d726a0d55f75c6 (diff)
Merge branch 'draw-viewport-data' into eevee-rewrite
# Conflicts: # release/scripts/startup/bl_ui/properties_data_camera.py # source/blender/blenkernel/BKE_camera.h # source/blender/blenkernel/BKE_node.h # source/blender/blenkernel/intern/camera.c # source/blender/blenlib/BLI_float2.hh # source/blender/blenlib/BLI_float3.hh # source/blender/blenlib/BLI_float4.hh # source/blender/blenlib/BLI_math_geom.h # source/blender/blenlib/intern/math_geom.c # source/blender/draw/CMakeLists.txt # source/blender/draw/engines/basic/basic_engine.c # source/blender/draw/engines/eevee/eevee_cryptomatte.c # source/blender/draw/engines/eevee/eevee_effects.c # source/blender/draw/engines/eevee/eevee_engine.c # source/blender/draw/engines/eevee/eevee_lightcache.c # source/blender/draw/engines/eevee/eevee_lightcache.h # source/blender/draw/engines/eevee/eevee_lightprobes.c # source/blender/draw/engines/eevee/eevee_lights.c # source/blender/draw/engines/eevee/eevee_materials.c # source/blender/draw/engines/eevee/eevee_motion_blur.c # source/blender/draw/engines/eevee/eevee_occlusion.c # source/blender/draw/engines/eevee/eevee_private.h # source/blender/draw/engines/eevee/eevee_render.c # source/blender/draw/engines/eevee/eevee_renderpasses.c # source/blender/draw/engines/eevee/eevee_sampling.c # source/blender/draw/engines/eevee/eevee_screen_raytrace.c # source/blender/draw/engines/eevee/eevee_shaders.c # source/blender/draw/engines/eevee/eevee_shadows.c # source/blender/draw/engines/eevee/eevee_shadows_cube.c # source/blender/draw/engines/eevee/eevee_temporal_sampling.c # source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl # source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl # source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl # source/blender/draw/engines/eevee/shaders/effect_dof_bokeh_frag.glsl # source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl # source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl # source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl # source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl # source/blender/draw/engines/eevee/shaders/random_lib.glsl # source/blender/draw/engines/eevee/shaders/shadow_vert.glsl # source/blender/draw/engines/eevee/shaders/surface_lib.glsl # source/blender/draw/engines/eevee/shaders/surface_vert.glsl # source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl # source/blender/draw/engines/external/external_engine.c # source/blender/draw/engines/gpencil/gpencil_engine.c # source/blender/draw/engines/image/image_engine.c # source/blender/draw/engines/overlay/overlay_engine.c # source/blender/draw/engines/select/select_engine.c # source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl # source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl # source/blender/draw/engines/workbench/workbench_engine.c # source/blender/draw/engines/workbench/workbench_shader.c # source/blender/draw/intern/DRW_render.h # source/blender/draw/intern/draw_debug.h # source/blender/draw/intern/draw_manager_data.c # source/blender/draw/intern/draw_manager_exec.c # source/blender/draw/intern/draw_view_data.h # source/blender/gpu/CMakeLists.txt # source/blender/gpu/GPU_material.h # source/blender/gpu/GPU_shader.h # source/blender/gpu/GPU_state.h # source/blender/gpu/GPU_vertex_buffer.h # source/blender/gpu/intern/gpu_codegen.c # source/blender/gpu/intern/gpu_material.c # source/blender/gpu/intern/gpu_material_library.h # source/blender/gpu/intern/gpu_node_graph.c # source/blender/gpu/intern/gpu_texture_private.hh # source/blender/gpu/intern/gpu_vertex_buffer.cc # source/blender/gpu/opengl/gl_shader.cc # source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl # source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl # source/blender/nodes/shader/node_shader_tree.cc # source/blender/nodes/shader/nodes/node_shader_background.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c # source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c # source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc # source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc # source/blender/nodes/shader/nodes/node_shader_emission.cc # source/blender/nodes/shader/nodes/node_shader_holdout.cc # source/blender/nodes/shader/nodes/node_shader_output_material.cc # source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c # source/blender/nodes/shader/nodes/node_shader_tex_coord.cc # source/blender/nodes/shader/nodes/node_shader_vector_transform.cc # source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc # source/blender/nodes/shader/nodes/node_shader_volume_principled.cc # source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc # source/blender/render/RE_pipeline.h # source/blender/render/intern/initrender.c
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/CMakeLists.txt9
-rw-r--r--source/blender/blendthumb/CMakeLists.txt57
-rw-r--r--source/blender/blendthumb/src/BlenderThumb.cpp321
-rw-r--r--source/blender/blendthumb/src/blender_thumbnailer.cc113
-rw-r--r--source/blender/blendthumb/src/blendthumb.hh69
-rw-r--r--source/blender/blendthumb/src/blendthumb_extract.cc253
-rw-r--r--source/blender/blendthumb/src/blendthumb_png.cc158
-rw-r--r--source/blender/blendthumb/src/blendthumb_win32.cc237
-rw-r--r--source/blender/blendthumb/src/blendthumb_win32.def (renamed from source/blender/blendthumb/src/BlendThumb.def)0
-rw-r--r--source/blender/blendthumb/src/blendthumb_win32.rc (renamed from source/blender/blendthumb/src/BlendThumb.rc)0
-rw-r--r--source/blender/blendthumb/src/blendthumb_win32_dll.cc (renamed from source/blender/blendthumb/src/Dll.cpp)87
-rw-r--r--source/blender/blenfont/BLF_api.h152
-rw-r--r--source/blender/blenfont/CMakeLists.txt3
-rw-r--r--source/blender/blenfont/intern/blf.c15
-rw-r--r--source/blender/blenfont/intern/blf_default.c16
-rw-r--r--source/blender/blenfont/intern/blf_dir.c4
-rw-r--r--source/blender/blenfont/intern/blf_font.c255
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c484
-rw-r--r--source/blender/blenfont/intern/blf_internal.h36
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h16
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c9
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h104
-rw-r--r--source/blender/blenkernel/BKE_action.h226
-rw-r--r--source/blender/blenkernel/BKE_anim_data.h78
-rw-r--r--source/blender/blenkernel/BKE_anim_path.h11
-rw-r--r--source/blender/blenkernel/BKE_anim_visualization.h21
-rw-r--r--source/blender/blenkernel/BKE_animsys.h140
-rw-r--r--source/blender/blenkernel/BKE_appdir.h130
-rw-r--r--source/blender/blenkernel/BKE_armature.h219
-rw-r--r--source/blender/blenkernel/BKE_asset.h20
-rw-r--r--source/blender/blenkernel/BKE_asset_catalog.hh292
-rw-r--r--source/blender/blenkernel/BKE_asset_catalog_path.hh146
-rw-r--r--source/blender/blenkernel/BKE_asset_library.h16
-rw-r--r--source/blender/blenkernel/BKE_asset_library.hh34
-rw-r--r--source/blender/blenkernel/BKE_attribute.h30
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh424
-rw-r--r--source/blender/blenkernel/BKE_attribute_math.hh67
-rw-r--r--source/blender/blenkernel/BKE_autoexec.h4
-rw-r--r--source/blender/blenkernel/BKE_blender.h11
-rw-r--r--source/blender/blenkernel/BKE_blender_copybuffer.h54
-rw-r--r--source/blender/blenkernel/BKE_blender_undo.h4
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h6
-rw-r--r--source/blender/blenkernel/BKE_blendfile.h49
-rw-r--r--source/blender/blenkernel/BKE_blendfile_link_append.h222
-rw-r--r--source/blender/blenkernel/BKE_boids.h6
-rw-r--r--source/blender/blenkernel/BKE_bpath.h213
-rw-r--r--source/blender/blenkernel/BKE_brush.h103
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h129
-rw-r--r--source/blender/blenkernel/BKE_cachefile.h22
-rw-r--r--source/blender/blenkernel/BKE_callbacks.h7
-rw-r--r--source/blender/blenkernel/BKE_camera.h37
-rw-r--r--source/blender/blenkernel/BKE_cloth.h2
-rw-r--r--source/blender/blenkernel/BKE_collection.h136
-rw-r--r--source/blender/blenkernel/BKE_collision.h26
-rw-r--r--source/blender/blenkernel/BKE_colorband.h2
-rw-r--r--source/blender/blenkernel/BKE_colortools.h80
-rw-r--r--source/blender/blenkernel/BKE_constraint.h117
-rw-r--r--source/blender/blenkernel/BKE_context.h45
-rw-r--r--source/blender/blenkernel/BKE_crazyspace.h37
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.h5
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.hh22
-rw-r--r--source/blender/blenkernel/BKE_curve.h219
-rw-r--r--source/blender/blenkernel/BKE_curve_to_mesh.hh20
-rw-r--r--source/blender/blenkernel/BKE_curveprofile.h105
-rw-r--r--source/blender/blenkernel/BKE_customdata.h364
-rw-r--r--source/blender/blenkernel/BKE_data_transfer.h74
-rw-r--r--source/blender/blenkernel/BKE_deform.h198
-rw-r--r--source/blender/blenkernel/BKE_displist.h12
-rw-r--r--source/blender/blenkernel/BKE_duplilist.h5
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h40
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h33
-rw-r--r--source/blender/blenkernel/BKE_editmesh_bvh.h28
-rw-r--r--source/blender/blenkernel/BKE_editmesh_tangent.h9
-rw-r--r--source/blender/blenkernel/BKE_effect.h29
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h273
-rw-r--r--source/blender/blenkernel/BKE_fcurve_driver.h58
-rw-r--r--source/blender/blenkernel/BKE_fluid.h10
-rw-r--r--source/blender/blenkernel/BKE_freestyle.h8
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.h2
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh599
-rw-r--r--source/blender/blenkernel/BKE_geometry_set_instances.hh18
-rw-r--r--source/blender/blenkernel/BKE_global.h96
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h450
-rw-r--r--source/blender/blenkernel/BKE_gpencil_curve.h47
-rw-r--r--source/blender/blenkernel/BKE_gpencil_geom.h344
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h146
-rw-r--r--source/blender/blenkernel/BKE_icons.h128
-rw-r--r--source/blender/blenkernel/BKE_idprop.h172
-rw-r--r--source/blender/blenkernel/BKE_idprop.hh93
-rw-r--r--source/blender/blenkernel/BKE_idtype.h117
-rw-r--r--source/blender/blenkernel/BKE_image.h322
-rw-r--r--source/blender/blenkernel/BKE_ipo.h13
-rw-r--r--source/blender/blenkernel/BKE_key.h103
-rw-r--r--source/blender/blenkernel/BKE_keyconfig.h12
-rw-r--r--source/blender/blenkernel/BKE_lattice.h31
-rw-r--r--source/blender/blenkernel/BKE_layer.h155
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h371
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h273
-rw-r--r--source/blender/blenkernel/BKE_lib_query.h115
-rw-r--r--source/blender/blenkernel/BKE_lib_remap.h122
-rw-r--r--source/blender/blenkernel/BKE_lightprobe.h2
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h14
-rw-r--r--source/blender/blenkernel/BKE_main.h137
-rw-r--r--source/blender/blenkernel/BKE_main_idmap.h18
-rw-r--r--source/blender/blenkernel/BKE_mask.h190
-rw-r--r--source/blender/blenkernel/BKE_material.h94
-rw-r--r--source/blender/blenkernel/BKE_mball.h53
-rw-r--r--source/blender/blenkernel/BKE_mesh.h587
-rw-r--r--source/blender/blenkernel/BKE_mesh_boolean_convert.hh16
-rw-r--r--source/blender/blenkernel/BKE_mesh_fair.h4
-rw-r--r--source/blender/blenkernel/BKE_mesh_iterators.h22
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h158
-rw-r--r--source/blender/blenkernel/BKE_mesh_mirror.h11
-rw-r--r--source/blender/blenkernel/BKE_mesh_remap.h88
-rw-r--r--source/blender/blenkernel/BKE_mesh_runtime.h39
-rw-r--r--source/blender/blenkernel/BKE_mesh_sample.hh12
-rw-r--r--source/blender/blenkernel/BKE_mesh_tangent.h34
-rw-r--r--source/blender/blenkernel/BKE_mesh_wrapper.h3
-rw-r--r--source/blender/blenkernel/BKE_modifier.h86
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h31
-rw-r--r--source/blender/blenkernel/BKE_multires.h98
-rw-r--r--source/blender/blenkernel/BKE_nla.h218
-rw-r--r--source/blender/blenkernel/BKE_node.h599
-rw-r--r--source/blender/blenkernel/BKE_node_tree_update.h110
-rw-r--r--source/blender/blenkernel/BKE_object.h340
-rw-r--r--source/blender/blenkernel/BKE_object_deform.h100
-rw-r--r--source/blender/blenkernel/BKE_ocean.h54
-rw-r--r--source/blender/blenkernel/BKE_packedFile.h48
-rw-r--r--source/blender/blenkernel/BKE_paint.h128
-rw-r--r--source/blender/blenkernel/BKE_particle.h151
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h99
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h83
-rw-r--r--source/blender/blenkernel/BKE_pointcloud.h6
-rw-r--r--source/blender/blenkernel/BKE_preferences.h16
-rw-r--r--source/blender/blenkernel/BKE_report.h27
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h139
-rw-r--r--source/blender/blenkernel/BKE_scene.h150
-rw-r--r--source/blender/blenkernel/BKE_screen.h115
-rw-r--r--source/blender/blenkernel/BKE_shader_fx.h28
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h92
-rw-r--r--source/blender/blenkernel/BKE_softbody.h39
-rw-r--r--source/blender/blenkernel/BKE_spline.hh261
-rw-r--r--source/blender/blenkernel/BKE_studiolight.h8
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h40
-rw-r--r--source/blender/blenkernel/BKE_subdiv_ccg.h13
-rw-r--r--source/blender/blenkernel/BKE_subdiv_eval.h95
-rw-r--r--source/blender/blenkernel/BKE_subdiv_foreach.h93
-rw-r--r--source/blender/blenkernel/BKE_subdiv_modifier.h79
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h18
-rw-r--r--source/blender/blenkernel/BKE_text.h94
-rw-r--r--source/blender/blenkernel/BKE_text_suggestions.h2
-rw-r--r--source/blender/blenkernel/BKE_texture.h14
-rw-r--r--source/blender/blenkernel/BKE_tracking.h277
-rw-r--r--source/blender/blenkernel/BKE_type_conversions.hh (renamed from source/blender/nodes/NOD_type_conversions.hh)11
-rw-r--r--source/blender/blenkernel/BKE_undo_system.h129
-rw-r--r--source/blender/blenkernel/BKE_unit.h54
-rw-r--r--source/blender/blenkernel/BKE_vfont.h (renamed from source/blender/blenkernel/BKE_font.h)7
-rw-r--r--source/blender/blenkernel/BKE_vfontdata.h (renamed from source/blender/blenlib/BLI_vfontdata.h)16
-rw-r--r--source/blender/blenkernel/BKE_volume.h23
-rw-r--r--source/blender/blenkernel/BKE_volume_to_mesh.hh47
-rw-r--r--source/blender/blenkernel/BKE_workspace.h67
-rw-r--r--source/blender/blenkernel/BKE_writeavi.h6
-rw-r--r--source/blender/blenkernel/CMakeLists.txt49
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.h17
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_legacy.c4
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc447
-rw-r--r--source/blender/blenkernel/intern/action.c216
-rw-r--r--source/blender/blenkernel/intern/action_mirror.c8
-rw-r--r--source/blender/blenkernel/intern/action_test.cc95
-rw-r--r--source/blender/blenkernel/intern/anim_data.c124
-rw-r--r--source/blender/blenkernel/intern/anim_path.c12
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c75
-rw-r--r--source/blender/blenkernel/intern/anim_visualization.c14
-rw-r--r--source/blender/blenkernel/intern/anonymous_attribute.cc1
-rw-r--r--source/blender/blenkernel/intern/appdir.c158
-rw-r--r--source/blender/blenkernel/intern/armature.c348
-rw-r--r--source/blender/blenkernel/intern/armature_deform.c1
-rw-r--r--source/blender/blenkernel/intern/armature_test.cc303
-rw-r--r--source/blender/blenkernel/intern/armature_update.c90
-rw-r--r--source/blender/blenkernel/intern/asset.cc32
-rw-r--r--source/blender/blenkernel/intern/asset_catalog.cc767
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_path.cc238
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_path_test.cc284
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_test.cc993
-rw-r--r--source/blender/blenkernel/intern/asset_library.cc107
-rw-r--r--source/blender/blenkernel/intern/asset_library_service.cc161
-rw-r--r--source/blender/blenkernel/intern/asset_library_service.hh93
-rw-r--r--source/blender/blenkernel/intern/asset_library_service_test.cc214
-rw-r--r--source/blender/blenkernel/intern/asset_library_test.cc34
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc664
-rw-r--r--source/blender/blenkernel/intern/attribute_access_intern.hh46
-rw-r--r--source/blender/blenkernel/intern/autoexec.c4
-rw-r--r--source/blender/blenkernel/intern/blender.c10
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c135
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c4
-rw-r--r--source/blender/blenkernel/intern/blender_user_menu.c2
-rw-r--r--source/blender/blenkernel/intern/blendfile.c74
-rw-r--r--source/blender/blenkernel/intern/blendfile_link_append.c1649
-rw-r--r--source/blender/blenkernel/intern/boids.c2
-rw-r--r--source/blender/blenkernel/intern/bpath.c920
-rw-r--r--source/blender/blenkernel/intern/bpath_test.cc181
-rw-r--r--source/blender/blenkernel/intern/brush.c76
-rw-r--r--source/blender/blenkernel/intern/bvhutils.cc111
-rw-r--r--source/blender/blenkernel/intern/cachefile.c62
-rw-r--r--source/blender/blenkernel/intern/callbacks.c32
-rw-r--r--source/blender/blenkernel/intern/camera.c20
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c26
-rw-r--r--source/blender/blenkernel/intern/cloth.c6
-rw-r--r--source/blender/blenkernel/intern/collection.c217
-rw-r--r--source/blender/blenkernel/intern/collision.c10
-rw-r--r--source/blender/blenkernel/intern/colortools.c44
-rw-r--r--source/blender/blenkernel/intern/constraint.c106
-rw-r--r--source/blender/blenkernel/intern/context.c13
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c90
-rw-r--r--source/blender/blenkernel/intern/cryptomatte.cc22
-rw-r--r--source/blender/blenkernel/intern/curve.cc (renamed from source/blender/blenkernel/intern/curve.c)699
-rw-r--r--source/blender/blenkernel/intern/curve_bevel.c44
-rw-r--r--source/blender/blenkernel/intern/curve_convert.c2
-rw-r--r--source/blender/blenkernel/intern/curve_deform.c10
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc115
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc125
-rw-r--r--source/blender/blenkernel/intern/curveprofile.cc (renamed from source/blender/blenkernel/intern/curveprofile.c)470
-rw-r--r--source/blender/blenkernel/intern/customdata.cc (renamed from source/blender/blenkernel/intern/customdata.c)1162
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c41
-rw-r--r--source/blender/blenkernel/intern/data_transfer_intern.h55
-rw-r--r--source/blender/blenkernel/intern/deform.c134
-rw-r--r--source/blender/blenkernel/intern/displist.cc88
-rw-r--r--source/blender/blenkernel/intern/displist_tangent.c4
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c61
-rw-r--r--source/blender/blenkernel/intern/editmesh.c58
-rw-r--r--source/blender/blenkernel/intern/editmesh_bvh.c8
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.c7
-rw-r--r--source/blender/blenkernel/intern/effect.c66
-rw-r--r--source/blender/blenkernel/intern/fcurve.c128
-rw-r--r--source/blender/blenkernel/intern/fcurve_cache.c5
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c37
-rw-r--r--source/blender/blenkernel/intern/fluid.c77
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c56
-rw-r--r--source/blender/blenkernel/intern/freestyle.c4
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc832
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc196
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc675
-rw-r--r--source/blender/blenkernel/intern/geometry_component_pointcloud.cc31
-rw-r--r--source/blender/blenkernel/intern/geometry_component_volume.cc7
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc387
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc452
-rw-r--r--source/blender/blenkernel/intern/gpencil.c410
-rw-r--r--source/blender/blenkernel/intern/gpencil_curve.c31
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc406
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c225
-rw-r--r--source/blender/blenkernel/intern/hair.cc (renamed from source/blender/blenkernel/intern/hair.c)115
-rw-r--r--source/blender/blenkernel/intern/icons.cc70
-rw-r--r--source/blender/blenkernel/intern/idprop.c124
-rw-r--r--source/blender/blenkernel/intern/idprop_create.cc140
-rw-r--r--source/blender/blenkernel/intern/idprop_serialize.cc844
-rw-r--r--source/blender/blenkernel/intern/idprop_serialize_test.cc448
-rw-r--r--source/blender/blenkernel/intern/idtype.c71
-rw-r--r--source/blender/blenkernel/intern/image.c923
-rw-r--r--source/blender/blenkernel/intern/image_gen.c11
-rw-r--r--source/blender/blenkernel/intern/image_gpu.cc (renamed from source/blender/blenkernel/intern/image_gpu.c)133
-rw-r--r--source/blender/blenkernel/intern/image_save.c53
-rw-r--r--source/blender/blenkernel/intern/ipo.c13
-rw-r--r--source/blender/blenkernel/intern/key.c89
-rw-r--r--source/blender/blenkernel/intern/keyconfig.c5
-rw-r--r--source/blender/blenkernel/intern/lattice.c10
-rw-r--r--source/blender/blenkernel/intern/lattice_deform.c2
-rw-r--r--source/blender/blenkernel/intern/lattice_deform_test.cc2
-rw-r--r--source/blender/blenkernel/intern/layer.c253
-rw-r--r--source/blender/blenkernel/intern/layer_test.cc8
-rw-r--r--source/blender/blenkernel/intern/layer_utils.c8
-rw-r--r--source/blender/blenkernel/intern/lib_id.c389
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c91
-rw-r--r--source/blender/blenkernel/intern/lib_id_eval.c5
-rw-r--r--source/blender/blenkernel/intern/lib_id_remapper.cc175
-rw-r--r--source/blender/blenkernel/intern/lib_id_remapper_test.cc83
-rw-r--r--source/blender/blenkernel/intern/lib_override.c544
-rw-r--r--source/blender/blenkernel/intern/lib_query.c218
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c449
-rw-r--r--source/blender/blenkernel/intern/lib_remap_test.cc369
-rw-r--r--source/blender/blenkernel/intern/library.c25
-rw-r--r--source/blender/blenkernel/intern/light.c5
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c6
-rw-r--r--source/blender/blenkernel/intern/linestyle.c21
-rw-r--r--source/blender/blenkernel/intern/main.c117
-rw-r--r--source/blender/blenkernel/intern/main_idmap.c12
-rw-r--r--source/blender/blenkernel/intern/mask.c35
-rw-r--r--source/blender/blenkernel/intern/mask_evaluate.c5
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c5
-rw-r--r--source/blender/blenkernel/intern/material.c55
-rw-r--r--source/blender/blenkernel/intern/mball.c74
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c18
-rw-r--r--source/blender/blenkernel/intern/mesh.cc (renamed from source/blender/blenkernel/intern/mesh.c)603
-rw-r--r--source/blender/blenkernel/intern/mesh_boolean_convert.cc12
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc125
-rw-r--r--source/blender/blenkernel/intern/mesh_debug.cc115
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.cc81
-rw-r--r--source/blender/blenkernel/intern/mesh_fair.cc4
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.c68
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c88
-rw-r--r--source/blender/blenkernel/intern/mesh_merge.c48
-rw-r--r--source/blender/blenkernel/intern/mesh_mirror.c77
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc305
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c87
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.cc5
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c188
-rw-r--r--source/blender/blenkernel/intern/mesh_sample.cc71
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c32
-rw-r--r--source/blender/blenkernel/intern/mesh_tessellate.c22
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c74
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.cc3
-rw-r--r--source/blender/blenkernel/intern/mesh_wrapper.c91
-rw-r--r--source/blender/blenkernel/intern/modifier.c96
-rw-r--r--source/blender/blenkernel/intern/movieclip.c59
-rw-r--r--source/blender/blenkernel/intern/multires.c17
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.c4
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.h136
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_smooth.c99
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_util.c19
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_vertcos.c4
-rw-r--r--source/blender/blenkernel/intern/multires_unsubdivide.c14
-rw-r--r--source/blender/blenkernel/intern/multires_versioning.c2
-rw-r--r--source/blender/blenkernel/intern/nla.c218
-rw-r--r--source/blender/blenkernel/intern/node.cc1874
-rw-r--r--source/blender/blenkernel/intern/node_tree_update.cc1670
-rw-r--r--source/blender/blenkernel/intern/object.cc (renamed from source/blender/blenkernel/intern/object.c)1698
-rw-r--r--source/blender/blenkernel/intern/object_deform.c84
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc114
-rw-r--r--source/blender/blenkernel/intern/object_update.c37
-rw-r--r--source/blender/blenkernel/intern/ocean.c12
-rw-r--r--source/blender/blenkernel/intern/ocean_intern.h2
-rw-r--r--source/blender/blenkernel/intern/ocean_spectrum.c17
-rw-r--r--source/blender/blenkernel/intern/packedFile.c37
-rw-r--r--source/blender/blenkernel/intern/paint.c40
-rw-r--r--source/blender/blenkernel/intern/paint_toolslots.c4
-rw-r--r--source/blender/blenkernel/intern/particle.c133
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c10
-rw-r--r--source/blender/blenkernel/intern/particle_system.c22
-rw-r--r--source/blender/blenkernel/intern/pbvh.c48
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c8
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h14
-rw-r--r--source/blender/blenkernel/intern/pointcache.c128
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc90
-rw-r--r--source/blender/blenkernel/intern/preferences.c16
-rw-r--r--source/blender/blenkernel/intern/report.c25
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c82
-rw-r--r--source/blender/blenkernel/intern/scene.c499
-rw-r--r--source/blender/blenkernel/intern/screen.c175
-rw-r--r--source/blender/blenkernel/intern/shader_fx.c14
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c130
-rw-r--r--source/blender/blenkernel/intern/simulation.cc7
-rw-r--r--source/blender/blenkernel/intern/softbody.c25
-rw-r--r--source/blender/blenkernel/intern/sound.c34
-rw-r--r--source/blender/blenkernel/intern/speaker.c4
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc98
-rw-r--r--source/blender/blenkernel/intern/spline_bezier.cc219
-rw-r--r--source/blender/blenkernel/intern/spline_nurbs.cc108
-rw-r--r--source/blender/blenkernel/intern/spline_poly.cc23
-rw-r--r--source/blender/blenkernel/intern/studiolight.c6
-rw-r--r--source/blender/blenkernel/intern/subdiv.c12
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c28
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter_mesh.c15
-rw-r--r--source/blender/blenkernel/intern/subdiv_deform.c8
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c250
-rw-r--r--source/blender/blenkernel/intern/subdiv_foreach.c3
-rw-r--r--source/blender/blenkernel/intern/subdiv_inline.h6
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c156
-rw-r--r--source/blender/blenkernel/intern/subdiv_modifier.c160
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c206
-rw-r--r--source/blender/blenkernel/intern/text.c56
-rw-r--r--source/blender/blenkernel/intern/texture.c21
-rw-r--r--source/blender/blenkernel/intern/tracking.c223
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c6
-rw-r--r--source/blender/blenkernel/intern/tracking_detect.c2
-rw-r--r--source/blender/blenkernel/intern/tracking_plane_tracker.c1
-rw-r--r--source/blender/blenkernel/intern/tracking_region_tracker.c13
-rw-r--r--source/blender/blenkernel/intern/tracking_solver.c22
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c36
-rw-r--r--source/blender/blenkernel/intern/tracking_test.cc2
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c17
-rw-r--r--source/blender/blenkernel/intern/type_conversions.cc (renamed from source/blender/nodes/intern/type_conversions.cc)92
-rw-r--r--source/blender/blenkernel/intern/undo_system.c160
-rw-r--r--source/blender/blenkernel/intern/unit.c17
-rw-r--r--source/blender/blenkernel/intern/vfont.c (renamed from source/blender/blenkernel/intern/font.c)49
-rw-r--r--source/blender/blenkernel/intern/vfontdata_freetype.c (renamed from source/blender/blenlib/intern/freetypefont.c)31
-rw-r--r--source/blender/blenkernel/intern/volume.cc98
-rw-r--r--source/blender/blenkernel/intern/volume_render.cc2
-rw-r--r--source/blender/blenkernel/intern/volume_to_mesh.cc86
-rw-r--r--source/blender/blenkernel/intern/workspace.c48
-rw-r--r--source/blender/blenkernel/intern/world.c5
-rw-r--r--source/blender/blenkernel/intern/writeavi.c1
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c28
-rw-r--r--source/blender/blenkernel/nla_private.h47
-rw-r--r--source/blender/blenkernel/tracking_private.h38
-rw-r--r--source/blender/blenlib/BLI_any.hh319
-rw-r--r--source/blender/blenlib/BLI_array.h55
-rw-r--r--source/blender/blenlib/BLI_array.hh10
-rw-r--r--source/blender/blenlib/BLI_array_store.h69
-rw-r--r--source/blender/blenlib/BLI_array_store_utils.h6
-rw-r--r--source/blender/blenlib/BLI_array_utils.h64
-rw-r--r--source/blender/blenlib/BLI_assert.h5
-rw-r--r--source/blender/blenlib/BLI_astar.h75
-rw-r--r--source/blender/blenlib/BLI_bitmap.h59
-rw-r--r--source/blender/blenlib/BLI_bitmap_draw_2d.h30
-rw-r--r--source/blender/blenlib/BLI_boxpack_2d.h31
-rw-r--r--source/blender/blenlib/BLI_buffer.h32
-rw-r--r--source/blender/blenlib/BLI_color.hh19
-rw-r--r--source/blender/blenlib/BLI_compiler_compat.h2
-rw-r--r--source/blender/blenlib/BLI_convexhull_2d.h37
-rw-r--r--source/blender/blenlib/BLI_delaunay_2d.h6
-rw-r--r--source/blender/blenlib/BLI_dlrbTree.h144
-rw-r--r--source/blender/blenlib/BLI_double2.hh143
-rw-r--r--source/blender/blenlib/BLI_double3.hh246
-rw-r--r--source/blender/blenlib/BLI_dynstr.h62
-rw-r--r--source/blender/blenlib/BLI_edgehash.h99
-rw-r--r--source/blender/blenlib/BLI_endian_switch.h18
-rw-r--r--source/blender/blenlib/BLI_endian_switch_inline.h3
-rw-r--r--source/blender/blenlib/BLI_expr_pylike_eval.h22
-rw-r--r--source/blender/blenlib/BLI_fileops.h186
-rw-r--r--source/blender/blenlib/BLI_fileops.hh52
-rw-r--r--source/blender/blenlib/BLI_filereader.h18
-rw-r--r--source/blender/blenlib/BLI_float2.hh244
-rw-r--r--source/blender/blenlib/BLI_float3.hh295
-rw-r--r--source/blender/blenlib/BLI_float4.hh129
-rw-r--r--source/blender/blenlib/BLI_float4x4.hh10
-rw-r--r--source/blender/blenlib/BLI_function_ref.hh6
-rw-r--r--source/blender/blenlib/BLI_ghash.h281
-rw-r--r--source/blender/blenlib/BLI_gsqueue.h22
-rw-r--r--source/blender/blenlib/BLI_hash.hh10
-rw-r--r--source/blender/blenlib/BLI_hash_md5.h19
-rw-r--r--source/blender/blenlib/BLI_hash_mm2a.h3
-rw-r--r--source/blender/blenlib/BLI_heap.h36
-rw-r--r--source/blender/blenlib/BLI_heap_simple.h15
-rw-r--r--source/blender/blenlib/BLI_index_mask.hh23
-rw-r--r--source/blender/blenlib/BLI_index_range.hh2
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h130
-rw-r--r--source/blender/blenlib/BLI_kdtree.h2
-rw-r--r--source/blender/blenlib/BLI_kdtree_impl.h14
-rw-r--r--source/blender/blenlib/BLI_lasso_2d.h16
-rw-r--r--source/blender/blenlib/BLI_linklist.h13
-rw-r--r--source/blender/blenlib/BLI_linklist_lockfree.h11
-rw-r--r--source/blender/blenlib/BLI_listbase.h217
-rw-r--r--source/blender/blenlib/BLI_math_base.h94
-rw-r--r--source/blender/blenlib/BLI_math_bits.h5
-rw-r--r--source/blender/blenlib/BLI_math_boolean.hh33
-rw-r--r--source/blender/blenlib/BLI_math_color.h110
-rw-r--r--source/blender/blenlib/BLI_math_geom.h788
-rw-r--r--source/blender/blenlib/BLI_math_interp.h11
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h298
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h305
-rw-r--r--source/blender/blenlib/BLI_math_solvers.h66
-rw-r--r--source/blender/blenlib/BLI_math_statistics.h36
-rw-r--r--source/blender/blenlib/BLI_math_time.h29
-rw-r--r--source/blender/blenlib/BLI_math_vec_mpq_types.hh92
-rw-r--r--source/blender/blenlib/BLI_math_vec_types.hh566
-rw-r--r--source/blender/blenlib/BLI_math_vector.h462
-rw-r--r--source/blender/blenlib/BLI_math_vector.hh404
-rw-r--r--source/blender/blenlib/BLI_memarena.h22
-rw-r--r--source/blender/blenlib/BLI_memblock.h9
-rw-r--r--source/blender/blenlib/BLI_memiter.h21
-rw-r--r--source/blender/blenlib/BLI_memory_utils.h2
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh6
-rw-r--r--source/blender/blenlib/BLI_mempool.h48
-rw-r--r--source/blender/blenlib/BLI_mesh_intersect.hh35
-rw-r--r--source/blender/blenlib/BLI_mpq2.hh184
-rw-r--r--source/blender/blenlib/BLI_mpq3.hh297
-rw-r--r--source/blender/blenlib/BLI_noise.h78
-rw-r--r--source/blender/blenlib/BLI_noise.hh323
-rw-r--r--source/blender/blenlib/BLI_path_util.h313
-rw-r--r--source/blender/blenlib/BLI_polyfill_2d.h24
-rw-r--r--source/blender/blenlib/BLI_polyfill_2d_beautify.h25
-rw-r--r--source/blender/blenlib/BLI_quadric.h13
-rw-r--r--source/blender/blenlib/BLI_rand.h27
-rw-r--r--source/blender/blenlib/BLI_rand.hh9
-rw-r--r--source/blender/blenlib/BLI_rect.h95
-rw-r--r--source/blender/blenlib/BLI_resource_scope.hh195
-rw-r--r--source/blender/blenlib/BLI_scanfill.h13
-rw-r--r--source/blender/blenlib/BLI_serialize.hh329
-rw-r--r--source/blender/blenlib/BLI_session_uuid.h7
-rw-r--r--source/blender/blenlib/BLI_set.hh22
-rw-r--r--source/blender/blenlib/BLI_smallhash.h24
-rw-r--r--source/blender/blenlib/BLI_sort.h2
-rw-r--r--source/blender/blenlib/BLI_span.hh40
-rw-r--r--source/blender/blenlib/BLI_stack.h55
-rw-r--r--source/blender/blenlib/BLI_string.h366
-rw-r--r--source/blender/blenlib/BLI_string_ref.hh684
-rw-r--r--source/blender/blenlib/BLI_string_search.h30
-rw-r--r--source/blender/blenlib/BLI_string_utf8.h139
-rw-r--r--source/blender/blenlib/BLI_string_utils.h88
-rw-r--r--source/blender/blenlib/BLI_sys_types.h2
-rw-r--r--source/blender/blenlib/BLI_system.h10
-rw-r--r--source/blender/blenlib/BLI_task.h225
-rw-r--r--source/blender/blenlib/BLI_task.hh17
-rw-r--r--source/blender/blenlib/BLI_threads.h29
-rw-r--r--source/blender/blenlib/BLI_timecode.h55
-rw-r--r--source/blender/blenlib/BLI_timer.h13
-rw-r--r--source/blender/blenlib/BLI_utildefines.h19
-rw-r--r--source/blender/blenlib/BLI_uvproject.h24
-rw-r--r--source/blender/blenlib/BLI_vector.hh16
-rw-r--r--source/blender/blenlib/BLI_vector_set.hh10
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh1085
-rw-r--r--source/blender/blenlib/BLI_virtual_vector_array.hh6
-rw-r--r--source/blender/blenlib/BLI_voxel.h6
-rw-r--r--source/blender/blenlib/BLI_winstuff.h9
-rw-r--r--source/blender/blenlib/CMakeLists.txt30
-rw-r--r--source/blender/blenlib/intern/BLI_array.c5
-rw-r--r--source/blender/blenlib/intern/BLI_assert.c13
-rw-r--r--source/blender/blenlib/intern/BLI_dynstr.c61
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c33
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c225
-rw-r--r--source/blender/blenlib/intern/BLI_ghash_utils.c12
-rw-r--r--source/blender/blenlib/intern/BLI_heap.c31
-rw-r--r--source/blender/blenlib/intern/BLI_heap_simple.c15
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c47
-rw-r--r--source/blender/blenlib/intern/BLI_linklist.c10
-rw-r--r--source/blender/blenlib/intern/BLI_memarena.c14
-rw-r--r--source/blender/blenlib/intern/BLI_memblock.c5
-rw-r--r--source/blender/blenlib/intern/BLI_memiter.c10
-rw-r--r--source/blender/blenlib/intern/BLI_mempool.c63
-rw-r--r--source/blender/blenlib/intern/BLI_mempool_private.h23
-rw-r--r--source/blender/blenlib/intern/DLRB_tree.c15
-rw-r--r--source/blender/blenlib/intern/array_store.c62
-rw-r--r--source/blender/blenlib/intern/array_utils.c60
-rw-r--r--source/blender/blenlib/intern/astar.c50
-rw-r--r--source/blender/blenlib/intern/bitmap.c5
-rw-r--r--source/blender/blenlib/intern/bitmap_draw_2d.c20
-rw-r--r--source/blender/blenlib/intern/boxpack_2d.c37
-rw-r--r--source/blender/blenlib/intern/buffer.c7
-rw-r--r--source/blender/blenlib/intern/convexhull_2d.c33
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.cc49
-rw-r--r--source/blender/blenlib/intern/edgehash.c98
-rw-r--r--source/blender/blenlib/intern/expr_pylike_eval.c16
-rw-r--r--source/blender/blenlib/intern/fileops.c35
-rw-r--r--source/blender/blenlib/intern/fileops.cc51
-rw-r--r--source/blender/blenlib/intern/filereader_gzip.c2
-rw-r--r--source/blender/blenlib/intern/filereader_zstd.c3
-rw-r--r--source/blender/blenlib/intern/gsqueue.c20
-rw-r--r--source/blender/blenlib/intern/hash_md5.c10
-rw-r--r--source/blender/blenlib/intern/hash_mm2a.c1
-rw-r--r--source/blender/blenlib/intern/index_mask.cc20
-rw-r--r--source/blender/blenlib/intern/kdtree_impl.h6
-rw-r--r--source/blender/blenlib/intern/lasso_2d.c1
-rw-r--r--source/blender/blenlib/intern/list_sort_impl.h4
-rw-r--r--source/blender/blenlib/intern/listbase.c194
-rw-r--r--source/blender/blenlib/intern/math_base.c22
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c68
-rw-r--r--source/blender/blenlib/intern/math_boolean.cc22
-rw-r--r--source/blender/blenlib/intern/math_color.c33
-rw-r--r--source/blender/blenlib/intern/math_color_blend_inline.c16
-rw-r--r--source/blender/blenlib/intern/math_color_inline.c26
-rw-r--r--source/blender/blenlib/intern/math_geom.c442
-rw-r--r--source/blender/blenlib/intern/math_geom_inline.c31
-rw-r--r--source/blender/blenlib/intern/math_interp.c3
-rw-r--r--source/blender/blenlib/intern/math_matrix.c265
-rw-r--r--source/blender/blenlib/intern/math_rotation.c103
-rw-r--r--source/blender/blenlib/intern/math_solvers.c46
-rw-r--r--source/blender/blenlib/intern/math_statistics.c20
-rw-r--r--source/blender/blenlib/intern/math_time.c7
-rw-r--r--source/blender/blenlib/intern/math_vec.cc133
-rw-r--r--source/blender/blenlib/intern/math_vector.c112
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c73
-rw-r--r--source/blender/blenlib/intern/memory_utils.c3
-rw-r--r--source/blender/blenlib/intern/mesh_boolean.cc68
-rw-r--r--source/blender/blenlib/intern/mesh_intersect.cc264
-rw-r--r--source/blender/blenlib/intern/noise.c79
-rw-r--r--source/blender/blenlib/intern/noise.cc1690
-rw-r--r--source/blender/blenlib/intern/path_util.c314
-rw-r--r--source/blender/blenlib/intern/polyfill_2d.c20
-rw-r--r--source/blender/blenlib/intern/polyfill_2d_beautify.c23
-rw-r--r--source/blender/blenlib/intern/rand.cc29
-rw-r--r--source/blender/blenlib/intern/rct.c88
-rw-r--r--source/blender/blenlib/intern/resource_scope.cc32
-rw-r--r--source/blender/blenlib/intern/scanfill.c18
-rw-r--r--source/blender/blenlib/intern/scanfill_utils.c11
-rw-r--r--source/blender/blenlib/intern/serialize.cc217
-rw-r--r--source/blender/blenlib/intern/session_uuid.c2
-rw-r--r--source/blender/blenlib/intern/smallhash.c14
-rw-r--r--source/blender/blenlib/intern/stack.c49
-rw-r--r--source/blender/blenlib/intern/storage.c61
-rw-r--r--source/blender/blenlib/intern/storage_apple.mm19
-rw-r--r--source/blender/blenlib/intern/string.c570
-rw-r--r--source/blender/blenlib/intern/string_cursor_utf8.c2
-rw-r--r--source/blender/blenlib/intern/string_search.cc53
-rw-r--r--source/blender/blenlib/intern/string_utf8.c135
-rw-r--r--source/blender/blenlib/intern/string_utils.c70
-rw-r--r--source/blender/blenlib/intern/system.c3
-rw-r--r--source/blender/blenlib/intern/system_win32.c3
-rw-r--r--source/blender/blenlib/intern/task_graph.cc2
-rw-r--r--source/blender/blenlib/intern/task_iterator.c36
-rw-r--r--source/blender/blenlib/intern/task_pool.cc14
-rw-r--r--source/blender/blenlib/intern/task_scheduler.cc6
-rw-r--r--source/blender/blenlib/intern/threads.cc140
-rw-r--r--source/blender/blenlib/intern/timecode.c37
-rw-r--r--source/blender/blenlib/intern/uuid.cc4
-rw-r--r--source/blender/blenlib/intern/uvproject.c3
-rw-r--r--source/blender/blenlib/intern/voxel.c2
-rw-r--r--source/blender/blenlib/intern/winstuff.c4
-rw-r--r--source/blender/blenlib/tests/BLI_any_test.cc110
-rw-r--r--source/blender/blenlib/tests/BLI_color_test.cc4
-rw-r--r--source/blender/blenlib/tests/BLI_delaunay_2d_test.cc3
-rw-r--r--source/blender/blenlib/tests/BLI_fileops_test.cc40
-rw-r--r--source/blender/blenlib/tests/BLI_listbase_test.cc83
-rw-r--r--source/blender/blenlib/tests/BLI_math_vec_types_test.cc149
-rw-r--r--source/blender/blenlib/tests/BLI_memory_utils_test.cc9
-rw-r--r--source/blender/blenlib/tests/BLI_mesh_boolean_test.cc2
-rw-r--r--source/blender/blenlib/tests/BLI_mesh_intersect_test.cc2
-rw-r--r--source/blender/blenlib/tests/BLI_serialize_test.cc207
-rw-r--r--source/blender/blenlib/tests/BLI_set_test.cc26
-rw-r--r--source/blender/blenlib/tests/BLI_string_search_test.cc10
-rw-r--r--source/blender/blenlib/tests/BLI_task_test.cc4
-rw-r--r--source/blender/blenlib/tests/BLI_uuid_test.cc6
-rw-r--r--source/blender/blenlib/tests/BLI_vector_test.cc11
-rw-r--r--source/blender/blenlib/tests/BLI_virtual_array_test.cc55
-rw-r--r--source/blender/blenlib/tests/performance/CMakeLists.txt1
-rw-r--r--source/blender/blenloader/BLO_blend_validate.h9
-rw-r--r--source/blender/blenloader/BLO_read_write.h148
-rw-r--r--source/blender/blenloader/BLO_readfile.h226
-rw-r--r--source/blender/blenloader/BLO_undofile.h21
-rw-r--r--source/blender/blenloader/BLO_writefile.h18
-rw-r--r--source/blender/blenloader/CMakeLists.txt2
-rw-r--r--source/blender/blenloader/intern/blend_validate.c5
-rw-r--r--source/blender/blenloader/intern/readblenentry.c97
-rw-r--r--source/blender/blenloader/intern/readfile.c557
-rw-r--r--source/blender/blenloader/intern/readfile.h60
-rw-r--r--source/blender/blenloader/intern/readfile_tempload.c2
-rw-r--r--source/blender/blenloader/intern/undofile.c9
-rw-r--r--source/blender/blenloader/intern/versioning_250.c19
-rw-r--r--source/blender/blenloader/intern/versioning_260.c4
-rw-r--r--source/blender/blenloader/intern/versioning_280.c63
-rw-r--r--source/blender/blenloader/intern/versioning_290.c35
-rw-r--r--source/blender/blenloader/intern/versioning_300.c928
-rw-r--r--source/blender/blenloader/intern/versioning_common.cc162
-rw-r--r--source/blender/blenloader/intern/versioning_common.h69
-rw-r--r--source/blender/blenloader/intern/versioning_cycles.c37
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c17
-rw-r--r--source/blender/blenloader/intern/versioning_dna.c10
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c7
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c91
-rw-r--r--source/blender/blenloader/intern/writefile.c60
-rw-r--r--source/blender/blenloader/tests/blendfile_loading_base_test.cc12
-rw-r--r--source/blender/blentranslation/BLT_lang.h9
-rw-r--r--source/blender/blentranslation/BLT_translation.h5
-rw-r--r--source/blender/blentranslation/intern/blt_lang.c13
-rw-r--r--source/blender/blentranslation/msgfmt/CMakeLists.txt1
-rw-r--r--source/blender/bmesh/CMakeLists.txt6
-rw-r--r--source/blender/bmesh/bmesh.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c145
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.h141
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c287
-rw-r--r--source/blender/bmesh/intern/bmesh_core.h343
-rw-r--r--source/blender/bmesh/intern/bmesh_delete.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_delete.h16
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.c13
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.h23
-rw-r--r--source/blender/bmesh/intern/bmesh_error.h18
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c46
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.h76
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c45
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.h83
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c134
-rw-r--r--source/blender/bmesh/intern/bmesh_log.h130
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c73
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.h158
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c83
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h118
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.cc (renamed from source/blender/bmesh/intern/bmesh_mesh_convert.c)364
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.h35
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_debug.c86
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_debug.h30
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_duplicate.c3
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_duplicate.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_normals.c78
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_normals.h57
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_partial_update.c28
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_partial_update.h38
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_tessellate.c3
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_tessellate.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_validate.c6
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_validate.h6
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c187
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.h223
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c1
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h361
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c152
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.h100
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c193
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h194
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.c16
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.h22
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h26
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c533
-rw-r--r--source/blender/bmesh/intern/bmesh_query.h614
-rw-r--r--source/blender/bmesh/intern/bmesh_query_uv.c23
-rw-r--r--source/blender/bmesh/intern/bmesh_query_uv.h51
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.c63
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.h65
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.c72
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.h52
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_impl.c17
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c11
-rw-r--r--source/blender/bmesh/operators/bmo_create.c9
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c5
-rw-r--r--source/blender/bmesh/operators/bmo_fill_edgeloop.c2
-rw-r--r--source/blender/bmesh/operators/bmo_hull.c2
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c42
-rw-r--r--source/blender/bmesh/operators/bmo_split_edges.c1
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide.c6
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c3
-rw-r--r--source/blender/bmesh/operators/bmo_unsubdivide.c5
-rw-r--r--source/blender/bmesh/tests/bmesh_core_test.cc6
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.c48
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.h23
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c24
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.h52
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.c7
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.h15
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.cc8
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.h34
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate.h42
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c18
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.c9
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.h11
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.c5
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.h10
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c10
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.h26
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.h2
-rw-r--r--source/blender/bmesh/tools/bmesh_path.c1
-rw-r--r--source/blender/bmesh/tools/bmesh_path_region_uv.h6
-rw-r--r--source/blender/bmesh/tools/bmesh_path_uv.c1
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.c7
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.h6
-rw-r--r--source/blender/bmesh/tools/bmesh_separate.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_separate.h4
-rw-r--r--source/blender/bmesh/tools/bmesh_triangulate.h8
-rw-r--r--source/blender/bmesh/tools/bmesh_wireframe.c6
-rw-r--r--source/blender/bmesh/tools/bmesh_wireframe.h34
-rw-r--r--source/blender/compositor/CMakeLists.txt22
-rw-r--r--source/blender/compositor/COM_compositor.h69
-rw-r--r--source/blender/compositor/COM_defines.h6
-rw-r--r--source/blender/compositor/COM_precomp.h33
-rw-r--r--source/blender/compositor/intern/COM_BufferOperation.cc33
-rw-r--r--source/blender/compositor/intern/COM_BufferOperation.h11
-rw-r--r--source/blender/compositor/intern/COM_BufferRange.h1
-rw-r--r--source/blender/compositor/intern/COM_CPUDevice.cc13
-rw-r--r--source/blender/compositor/intern/COM_CPUDevice.h4
-rw-r--r--source/blender/compositor/intern/COM_ChunkOrder.cc4
-rw-r--r--source/blender/compositor/intern/COM_CompositorContext.cc35
-rw-r--r--source/blender/compositor/intern/COM_CompositorContext.h133
-rw-r--r--source/blender/compositor/intern/COM_ConstantFolder.cc41
-rw-r--r--source/blender/compositor/intern/COM_ConstantFolder.h14
-rw-r--r--source/blender/compositor/intern/COM_Converter.cc153
-rw-r--r--source/blender/compositor/intern/COM_Converter.h7
-rw-r--r--source/blender/compositor/intern/COM_Debug.cc98
-rw-r--r--source/blender/compositor/intern/COM_Debug.h41
-rw-r--r--source/blender/compositor/intern/COM_Device.h6
-rw-r--r--source/blender/compositor/intern/COM_Enums.cc1
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.cc437
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.h154
-rw-r--r--source/blender/compositor/intern/COM_ExecutionModel.cc7
-rw-r--r--source/blender/compositor/intern/COM_ExecutionModel.h9
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cc66
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.h52
-rw-r--r--source/blender/compositor/intern/COM_FullFrameExecutionModel.cc84
-rw-r--r--source/blender/compositor/intern/COM_FullFrameExecutionModel.h37
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.cc174
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h254
-rw-r--r--source/blender/compositor/intern/COM_MemoryProxy.cc18
-rw-r--r--source/blender/compositor/intern/COM_MemoryProxy.h32
-rw-r--r--source/blender/compositor/intern/COM_MetaData.cc35
-rw-r--r--source/blender/compositor/intern/COM_MetaData.h20
-rw-r--r--source/blender/compositor/intern/COM_MultiThreadedOperation.cc2
-rw-r--r--source/blender/compositor/intern/COM_MultiThreadedRowOperation.h2
-rw-r--r--source/blender/compositor/intern/COM_Node.cc104
-rw-r--r--source/blender/compositor/intern/COM_Node.h149
-rw-r--r--source/blender/compositor/intern/COM_NodeConverter.cc113
-rw-r--r--source/blender/compositor/intern/COM_NodeConverter.h36
-rw-r--r--source/blender/compositor/intern/COM_NodeGraph.cc43
-rw-r--r--source/blender/compositor/intern/COM_NodeGraph.h15
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.cc237
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.h310
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cc419
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.h61
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.cc207
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.h88
-rw-r--r--source/blender/compositor/intern/COM_SharedOperationBuffers.cc35
-rw-r--r--source/blender/compositor/intern/COM_SharedOperationBuffers.h38
-rw-r--r--source/blender/compositor/intern/COM_SingleThreadedOperation.cc40
-rw-r--r--source/blender/compositor/intern/COM_SingleThreadedOperation.h16
-rw-r--r--source/blender/compositor/intern/COM_TiledExecutionModel.cc44
-rw-r--r--source/blender/compositor/intern/COM_TiledExecutionModel.h1
-rw-r--r--source/blender/compositor/intern/COM_WorkPackage.cc1
-rw-r--r--source/blender/compositor/intern/COM_WorkPackage.h4
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cc54
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.h14
-rw-r--r--source/blender/compositor/intern/COM_compositor.cc22
-rw-r--r--source/blender/compositor/nodes/COM_AlphaOverNode.cc52
-rw-r--r--source/blender/compositor/nodes/COM_AlphaOverNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_AntiAliasingNode.cc29
-rw-r--r--source/blender/compositor/nodes/COM_AntiAliasingNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_BilateralBlurNode.cc22
-rw-r--r--source/blender/compositor/nodes/COM_BilateralBlurNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_BlurNode.cc156
-rw-r--r--source/blender/compositor/nodes/COM_BlurNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_BokehBlurNode.cc57
-rw-r--r--source/blender/compositor/nodes/COM_BokehBlurNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_BokehImageNode.cc15
-rw-r--r--source/blender/compositor/nodes/COM_BokehImageNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_BoxMaskNode.cc58
-rw-r--r--source/blender/compositor/nodes/COM_BoxMaskNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_BrightnessNode.cc21
-rw-r--r--source/blender/compositor/nodes/COM_BrightnessNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ChannelMatteNode.cc55
-rw-r--r--source/blender/compositor/nodes/COM_ChannelMatteNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ChromaMatteNode.cc51
-rw-r--r--source/blender/compositor/nodes/COM_ChromaMatteNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ColorBalanceNode.cc37
-rw-r--r--source/blender/compositor/nodes/COM_ColorBalanceNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ColorCorrectionNode.cc25
-rw-r--r--source/blender/compositor/nodes/COM_ColorCorrectionNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ColorCurveNode.cc43
-rw-r--r--source/blender/compositor/nodes/COM_ColorCurveNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ColorExposureNode.cc15
-rw-r--r--source/blender/compositor/nodes/COM_ColorExposureNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ColorMatteNode.cc47
-rw-r--r--source/blender/compositor/nodes/COM_ColorMatteNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ColorNode.cc17
-rw-r--r--source/blender/compositor/nodes/COM_ColorNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ColorRampNode.cc33
-rw-r--r--source/blender/compositor/nodes/COM_ColorRampNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ColorSpillNode.cc31
-rw-r--r--source/blender/compositor/nodes/COM_ColorSpillNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ColorToBWNode.cc19
-rw-r--r--source/blender/compositor/nodes/COM_ColorToBWNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNode.cc54
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNode.h24
-rw-r--r--source/blender/compositor/nodes/COM_CompositorNode.cc47
-rw-r--r--source/blender/compositor/nodes/COM_CompositorNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ConvertAlphaNode.cc13
-rw-r--r--source/blender/compositor/nodes/COM_ConvertAlphaNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ConvertColorSpaceNode.cc100
-rw-r--r--source/blender/compositor/nodes/COM_ConvertColorSpaceNode.h46
-rw-r--r--source/blender/compositor/nodes/COM_CornerPinNode.cc29
-rw-r--r--source/blender/compositor/nodes/COM_CornerPinNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_CropNode.cc24
-rw-r--r--source/blender/compositor/nodes/COM_CropNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.cc100
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.h4
-rw-r--r--source/blender/compositor/nodes/COM_DefocusNode.cc106
-rw-r--r--source/blender/compositor/nodes/COM_DefocusNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_DenoiseNode.cc39
-rw-r--r--source/blender/compositor/nodes/COM_DenoiseNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_DespeckleNode.cc31
-rw-r--r--source/blender/compositor/nodes/COM_DespeckleNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_DifferenceMatteNode.cc39
-rw-r--r--source/blender/compositor/nodes/COM_DifferenceMatteNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_DilateErodeNode.cc136
-rw-r--r--source/blender/compositor/nodes/COM_DilateErodeNode.h8
-rw-r--r--source/blender/compositor/nodes/COM_DirectionalBlurNode.cc20
-rw-r--r--source/blender/compositor/nodes/COM_DirectionalBlurNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_DisplaceNode.cc21
-rw-r--r--source/blender/compositor/nodes/COM_DisplaceNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_DistanceMatteNode.cc77
-rw-r--r--source/blender/compositor/nodes/COM_DistanceMatteNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc21
-rw-r--r--source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_EllipseMaskNode.cc58
-rw-r--r--source/blender/compositor/nodes/COM_EllipseMaskNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_FilterNode.cc27
-rw-r--r--source/blender/compositor/nodes/COM_FilterNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_FlipNode.cc19
-rw-r--r--source/blender/compositor/nodes/COM_FlipNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_GammaNode.cc15
-rw-r--r--source/blender/compositor/nodes/COM_GammaNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_GlareNode.cc41
-rw-r--r--source/blender/compositor/nodes/COM_GlareNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc41
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueNode.cc50
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_IDMaskNode.cc33
-rw-r--r--source/blender/compositor/nodes/COM_IDMaskNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cc244
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.h24
-rw-r--r--source/blender/compositor/nodes/COM_InpaintNode.cc21
-rw-r--r--source/blender/compositor/nodes/COM_InpaintNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_InvertNode.cc21
-rw-r--r--source/blender/compositor/nodes/COM_InvertNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_KeyingNode.cc380
-rw-r--r--source/blender/compositor/nodes/COM_KeyingNode.h58
-rw-r--r--source/blender/compositor/nodes/COM_KeyingScreenNode.cc27
-rw-r--r--source/blender/compositor/nodes/COM_KeyingScreenNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_LensDistortionNode.cc41
-rw-r--r--source/blender/compositor/nodes/COM_LensDistortionNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_LuminanceMatteNode.cc36
-rw-r--r--source/blender/compositor/nodes/COM_LuminanceMatteNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_MapRangeNode.cc37
-rw-r--r--source/blender/compositor/nodes/COM_MapRangeNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_MapUVNode.cc19
-rw-r--r--source/blender/compositor/nodes/COM_MapUVNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_MapValueNode.cc23
-rw-r--r--source/blender/compositor/nodes/COM_MapValueNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_MaskNode.cc55
-rw-r--r--source/blender/compositor/nodes/COM_MaskNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_MathNode.cc21
-rw-r--r--source/blender/compositor/nodes/COM_MathNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_MixNode.cc78
-rw-r--r--source/blender/compositor/nodes/COM_MixNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_MovieClipNode.cc84
-rw-r--r--source/blender/compositor/nodes/COM_MovieClipNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_MovieDistortionNode.cc24
-rw-r--r--source/blender/compositor/nodes/COM_MovieDistortionNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_NormalNode.cc38
-rw-r--r--source/blender/compositor/nodes/COM_NormalNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_NormalizeNode.cc13
-rw-r--r--source/blender/compositor/nodes/COM_NormalizeNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_OutputFileNode.cc144
-rw-r--r--source/blender/compositor/nodes/COM_OutputFileNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_PixelateNode.cc25
-rw-r--r--source/blender/compositor/nodes/COM_PixelateNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc59
-rw-r--r--source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_PosterizeNode.cc15
-rw-r--r--source/blender/compositor/nodes/COM_PosterizeNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.cc94
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.h30
-rw-r--r--source/blender/compositor/nodes/COM_RotateNode.cc31
-rw-r--r--source/blender/compositor/nodes/COM_RotateNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ScaleNode.cc84
-rw-r--r--source/blender/compositor/nodes/COM_ScaleNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_SceneTimeNode.cc50
-rw-r--r--source/blender/compositor/nodes/COM_SceneTimeNode.h (renamed from source/blender/functions/FN_multi_function_parallel.hh)29
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNode.cc74
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNode.h24
-rw-r--r--source/blender/compositor/nodes/COM_SetAlphaNode.cc19
-rw-r--r--source/blender/compositor/nodes/COM_SetAlphaNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_SocketProxyNode.cc78
-rw-r--r--source/blender/compositor/nodes/COM_SocketProxyNode.h26
-rw-r--r--source/blender/compositor/nodes/COM_SplitViewerNode.cc65
-rw-r--r--source/blender/compositor/nodes/COM_SplitViewerNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_Stabilize2dNode.cc217
-rw-r--r--source/blender/compositor/nodes/COM_Stabilize2dNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_SunBeamsNode.cc20
-rw-r--r--source/blender/compositor/nodes/COM_SunBeamsNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_SwitchNode.cc14
-rw-r--r--source/blender/compositor/nodes/COM_SwitchNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_SwitchViewNode.cc17
-rw-r--r--source/blender/compositor/nodes/COM_SwitchViewNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_TextureNode.cc55
-rw-r--r--source/blender/compositor/nodes/COM_TextureNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_TimeNode.cc22
-rw-r--r--source/blender/compositor/nodes/COM_TimeNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_TonemapNode.cc17
-rw-r--r--source/blender/compositor/nodes/COM_TonemapNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_TrackPositionNode.cc95
-rw-r--r--source/blender/compositor/nodes/COM_TrackPositionNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_TransformNode.cc103
-rw-r--r--source/blender/compositor/nodes/COM_TransformNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_TranslateNode.cc47
-rw-r--r--source/blender/compositor/nodes/COM_TranslateNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ValueNode.cc15
-rw-r--r--source/blender/compositor/nodes/COM_ValueNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_VectorBlurNode.cc25
-rw-r--r--source/blender/compositor/nodes/COM_VectorBlurNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_VectorCurveNode.cc15
-rw-r--r--source/blender/compositor/nodes/COM_VectorCurveNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ViewLevelsNode.cc33
-rw-r--r--source/blender/compositor/nodes/COM_ViewLevelsNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ViewerNode.cc75
-rw-r--r--source/blender/compositor/nodes/COM_ViewerNode.h6
-rw-r--r--source/blender/compositor/nodes/COM_ZCombineNode.cc70
-rw-r--r--source/blender/compositor/nodes/COM_ZCombineNode.h6
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc38
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverKeyOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc44
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverMixedOperation.h6
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc38
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_AntiAliasOperation.cc52
-rw-r--r--source/blender/compositor/operations/COM_AntiAliasOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_BilateralBlurOperation.cc104
-rw-r--r--source/blender/compositor/operations/COM_BilateralBlurOperation.h26
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.cc93
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.h36
-rw-r--r--source/blender/compositor/operations/COM_BokehBlurOperation.cc283
-rw-r--r--source/blender/compositor/operations/COM_BokehBlurOperation.h58
-rw-r--r--source/blender/compositor/operations/COM_BokehImageOperation.cc150
-rw-r--r--source/blender/compositor/operations/COM_BokehImageOperation.h44
-rw-r--r--source/blender/compositor/operations/COM_BoxMaskOperation.cc113
-rw-r--r--source/blender/compositor/operations/COM_BoxMaskOperation.h30
-rw-r--r--source/blender/compositor/operations/COM_BrightnessOperation.cc76
-rw-r--r--source/blender/compositor/operations/COM_BrightnessOperation.h18
-rw-r--r--source/blender/compositor/operations/COM_CalculateMeanOperation.cc92
-rw-r--r--source/blender/compositor/operations/COM_CalculateMeanOperation.h26
-rw-r--r--source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc50
-rw-r--r--source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.h6
-rw-r--r--source/blender/compositor/operations/COM_ChangeHSVOperation.cc60
-rw-r--r--source/blender/compositor/operations/COM_ChangeHSVOperation.h14
-rw-r--r--source/blender/compositor/operations/COM_ChannelMatteOperation.cc83
-rw-r--r--source/blender/compositor/operations/COM_ChannelMatteOperation.h36
-rw-r--r--source/blender/compositor/operations/COM_ChromaMatteOperation.cc79
-rw-r--r--source/blender/compositor/operations/COM_ChromaMatteOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc62
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.h30
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc62
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceLGGOperation.h30
-rw-r--r--source/blender/compositor/operations/COM_ColorCorrectionOperation.cc211
-rw-r--r--source/blender/compositor/operations/COM_ColorCorrectionOperation.h36
-rw-r--r--source/blender/compositor/operations/COM_ColorCurveOperation.cc114
-rw-r--r--source/blender/compositor/operations/COM_ColorCurveOperation.h42
-rw-r--r--source/blender/compositor/operations/COM_ColorExposureOperation.cc48
-rw-r--r--source/blender/compositor/operations/COM_ColorExposureOperation.h12
-rw-r--r--source/blender/compositor/operations/COM_ColorMatteOperation.cc64
-rw-r--r--source/blender/compositor/operations/COM_ColorMatteOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_ColorRampOperation.cc32
-rw-r--r--source/blender/compositor/operations/COM_ColorRampOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_ColorSpillOperation.cc130
-rw-r--r--source/blender/compositor/operations/COM_ColorSpillOperation.h36
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.cc156
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.h64
-rw-r--r--source/blender/compositor/operations/COM_ConstantOperation.cc6
-rw-r--r--source/blender/compositor/operations/COM_ConstantOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc28
-rw-r--r--source/blender/compositor/operations/COM_ConvertColorProfileOperation.h28
-rw-r--r--source/blender/compositor/operations/COM_ConvertColorSpaceOperation.cc91
-rw-r--r--source/blender/compositor/operations/COM_ConvertColorSpaceOperation.h57
-rw-r--r--source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc91
-rw-r--r--source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.h46
-rw-r--r--source/blender/compositor/operations/COM_ConvertOperation.cc404
-rw-r--r--source/blender/compositor/operations/COM_ConvertOperation.h72
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc113
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc158
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionFilterOperation.h22
-rw-r--r--source/blender/compositor/operations/COM_CropOperation.cc125
-rw-r--r--source/blender/compositor/operations/COM_CropOperation.h38
-rw-r--r--source/blender/compositor/operations/COM_CryptomatteOperation.cc22
-rw-r--r--source/blender/compositor/operations/COM_CryptomatteOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_CurveBaseOperation.cc30
-rw-r--r--source/blender/compositor/operations/COM_CurveBaseOperation.h13
-rw-r--r--source/blender/compositor/operations/COM_DenoiseOperation.cc130
-rw-r--r--source/blender/compositor/operations/COM_DenoiseOperation.h36
-rw-r--r--source/blender/compositor/operations/COM_DespeckleOperation.cc108
-rw-r--r--source/blender/compositor/operations/COM_DespeckleOperation.h32
-rw-r--r--source/blender/compositor/operations/COM_DifferenceMatteOperation.cc59
-rw-r--r--source/blender/compositor/operations/COM_DifferenceMatteOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.cc388
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.h123
-rw-r--r--source/blender/compositor/operations/COM_DirectionalBlurOperation.cc184
-rw-r--r--source/blender/compositor/operations/COM_DirectionalBlurOperation.h38
-rw-r--r--source/blender/compositor/operations/COM_DisplaceOperation.cc110
-rw-r--r--source/blender/compositor/operations/COM_DisplaceOperation.h22
-rw-r--r--source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc119
-rw-r--r--source/blender/compositor/operations/COM_DisplaceSimpleOperation.h26
-rw-r--r--source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc61
-rw-r--r--source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h18
-rw-r--r--source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc3
-rw-r--r--source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_DotproductOperation.cc36
-rw-r--r--source/blender/compositor/operations/COM_DotproductOperation.h10
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc194
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h36
-rw-r--r--source/blender/compositor/operations/COM_EllipseMaskOperation.cc126
-rw-r--r--source/blender/compositor/operations/COM_EllipseMaskOperation.h30
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc220
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.h50
-rw-r--r--source/blender/compositor/operations/COM_FlipOperation.cc98
-rw-r--r--source/blender/compositor/operations/COM_FlipOperation.h23
-rw-r--r--source/blender/compositor/operations/COM_GammaCorrectOperation.cc107
-rw-r--r--source/blender/compositor/operations/COM_GammaCorrectOperation.h20
-rw-r--r--source/blender/compositor/operations/COM_GammaOperation.cc45
-rw-r--r--source/blender/compositor/operations/COM_GammaOperation.h12
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc61
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.h31
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc145
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc143
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_GaussianBlurBaseOperation.cc56
-rw-r--r--source/blender/compositor/operations/COM_GaussianBlurBaseOperation.h14
-rw-r--r--source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc353
-rw-r--r--source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h54
-rw-r--r--source/blender/compositor/operations/COM_GaussianXBlurOperation.cc193
-rw-r--r--source/blender/compositor/operations/COM_GaussianXBlurOperation.h32
-rw-r--r--source/blender/compositor/operations/COM_GaussianYBlurOperation.cc195
-rw-r--r--source/blender/compositor/operations/COM_GaussianYBlurOperation.h32
-rw-r--r--source/blender/compositor/operations/COM_GlareBaseOperation.cc59
-rw-r--r--source/blender/compositor/operations/COM_GlareBaseOperation.h28
-rw-r--r--source/blender/compositor/operations/COM_GlareFogGlowOperation.cc97
-rw-r--r--source/blender/compositor/operations/COM_GlareFogGlowOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_GlareGhostOperation.cc69
-rw-r--r--source/blender/compositor/operations/COM_GlareGhostOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc34
-rw-r--r--source/blender/compositor/operations/COM_GlareSimpleStarOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_GlareStreaksOperation.cc33
-rw-r--r--source/blender/compositor/operations/COM_GlareStreaksOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_GlareThresholdOperation.cc33
-rw-r--r--source/blender/compositor/operations/COM_GlareThresholdOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc42
-rw-r--r--source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.h10
-rw-r--r--source/blender/compositor/operations/COM_IDMaskOperation.cc22
-rw-r--r--source/blender/compositor/operations/COM_IDMaskOperation.h10
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.cc123
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.h56
-rw-r--r--source/blender/compositor/operations/COM_InpaintOperation.cc154
-rw-r--r--source/blender/compositor/operations/COM_InpaintOperation.h39
-rw-r--r--source/blender/compositor/operations/COM_InvertOperation.cc65
-rw-r--r--source/blender/compositor/operations/COM_InvertOperation.h24
-rw-r--r--source/blender/compositor/operations/COM_KeyingBlurOperation.cc90
-rw-r--r--source/blender/compositor/operations/COM_KeyingBlurOperation.h26
-rw-r--r--source/blender/compositor/operations/COM_KeyingClipOperation.cc107
-rw-r--r--source/blender/compositor/operations/COM_KeyingClipOperation.h44
-rw-r--r--source/blender/compositor/operations/COM_KeyingDespillOperation.cc69
-rw-r--r--source/blender/compositor/operations/COM_KeyingDespillOperation.h22
-rw-r--r--source/blender/compositor/operations/COM_KeyingOperation.cc55
-rw-r--r--source/blender/compositor/operations/COM_KeyingOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_KeyingScreenOperation.cc100
-rw-r--r--source/blender/compositor/operations/COM_KeyingScreenOperation.h32
-rw-r--r--source/blender/compositor/operations/COM_LuminanceMatteOperation.cc43
-rw-r--r--source/blender/compositor/operations/COM_LuminanceMatteOperation.h14
-rw-r--r--source/blender/compositor/operations/COM_MapRangeOperation.cc64
-rw-r--r--source/blender/compositor/operations/COM_MapRangeOperation.h24
-rw-r--r--source/blender/compositor/operations/COM_MapUVOperation.cc101
-rw-r--r--source/blender/compositor/operations/COM_MapUVOperation.h26
-rw-r--r--source/blender/compositor/operations/COM_MapValueOperation.cc30
-rw-r--r--source/blender/compositor/operations/COM_MapValueOperation.h16
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.cc116
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.h64
-rw-r--r--source/blender/compositor/operations/COM_MathBaseOperation.cc841
-rw-r--r--source/blender/compositor/operations/COM_MathBaseOperation.h104
-rw-r--r--source/blender/compositor/operations/COM_MixOperation.cc920
-rw-r--r--source/blender/compositor/operations/COM_MixOperation.h72
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc52
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.h30
-rw-r--r--source/blender/compositor/operations/COM_MovieClipOperation.cc73
-rw-r--r--source/blender/compositor/operations/COM_MovieClipOperation.h38
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.cc146
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.h37
-rw-r--r--source/blender/compositor/operations/COM_MultilayerImageOperation.cc99
-rw-r--r--source/blender/compositor/operations/COM_MultilayerImageOperation.h24
-rw-r--r--source/blender/compositor/operations/COM_NormalizeOperation.cc80
-rw-r--r--source/blender/compositor/operations/COM_NormalizeOperation.h20
-rw-r--r--source/blender/compositor/operations/COM_OpenCLKernels.cl196
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc211
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h28
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cc275
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.h82
-rw-r--r--source/blender/compositor/operations/COM_PixelateOperation.cc26
-rw-r--r--source/blender/compositor/operations/COM_PixelateOperation.h14
-rw-r--r--source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc130
-rw-r--r--source/blender/compositor/operations/COM_PlaneCornerPinOperation.h22
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc229
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h44
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.cc62
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.h34
-rw-r--r--source/blender/compositor/operations/COM_PosterizeOperation.cc52
-rw-r--r--source/blender/compositor/operations/COM_PosterizeOperation.h12
-rw-r--r--source/blender/compositor/operations/COM_PreviewOperation.cc147
-rw-r--r--source/blender/compositor/operations/COM_PreviewOperation.h42
-rw-r--r--source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc132
-rw-r--r--source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h26
-rw-r--r--source/blender/compositor/operations/COM_QualityStepHelper.cc36
-rw-r--r--source/blender/compositor/operations/COM_QualityStepHelper.h20
-rw-r--r--source/blender/compositor/operations/COM_ReadBufferOperation.cc95
-rw-r--r--source/blender/compositor/operations/COM_ReadBufferOperation.h57
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cc169
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.h80
-rw-r--r--source/blender/compositor/operations/COM_RotateOperation.cc126
-rw-r--r--source/blender/compositor/operations/COM_RotateOperation.h58
-rw-r--r--source/blender/compositor/operations/COM_SMAAOperation.cc333
-rw-r--r--source/blender/compositor/operations/COM_SMAAOperation.h90
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.cc345
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.h101
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc297
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h62
-rw-r--r--source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc36
-rw-r--r--source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.h10
-rw-r--r--source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc36
-rw-r--r--source/blender/compositor/operations/COM_SetAlphaReplaceOperation.h10
-rw-r--r--source/blender/compositor/operations/COM_SetColorOperation.cc14
-rw-r--r--source/blender/compositor/operations/COM_SetColorOperation.h42
-rw-r--r--source/blender/compositor/operations/COM_SetSamplerOperation.cc22
-rw-r--r--source/blender/compositor/operations/COM_SetSamplerOperation.h14
-rw-r--r--source/blender/compositor/operations/COM_SetValueOperation.cc14
-rw-r--r--source/blender/compositor/operations/COM_SetValueOperation.h14
-rw-r--r--source/blender/compositor/operations/COM_SetVectorOperation.cc13
-rw-r--r--source/blender/compositor/operations/COM_SetVectorOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_SocketProxyOperation.cc12
-rw-r--r--source/blender/compositor/operations/COM_SocketProxyOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_SplitOperation.cc61
-rw-r--r--source/blender/compositor/operations/COM_SplitOperation.h22
-rw-r--r--source/blender/compositor/operations/COM_SunBeamsOperation.cc77
-rw-r--r--source/blender/compositor/operations/COM_SunBeamsOperation.h22
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cc130
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.h32
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.cc110
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.h28
-rw-r--r--source/blender/compositor/operations/COM_TrackPositionOperation.cc101
-rw-r--r--source/blender/compositor/operations/COM_TrackPositionOperation.h60
-rw-r--r--source/blender/compositor/operations/COM_TransformOperation.cc29
-rw-r--r--source/blender/compositor/operations/COM_TransformOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.cc88
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.h52
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc399
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h78
-rw-r--r--source/blender/compositor/operations/COM_VectorBlurOperation.cc164
-rw-r--r--source/blender/compositor/operations/COM_VectorBlurOperation.h42
-rw-r--r--source/blender/compositor/operations/COM_VectorCurveOperation.cc32
-rw-r--r--source/blender/compositor/operations/COM_VectorCurveOperation.h10
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.cc178
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.h104
-rw-r--r--source/blender/compositor/operations/COM_WrapOperation.cc81
-rw-r--r--source/blender/compositor/operations/COM_WrapOperation.h18
-rw-r--r--source/blender/compositor/operations/COM_WriteBufferOperation.cc162
-rw-r--r--source/blender/compositor/operations/COM_WriteBufferOperation.h38
-rw-r--r--source/blender/compositor/operations/COM_ZCombineOperation.cc139
-rw-r--r--source/blender/compositor/operations/COM_ZCombineOperation.h30
-rw-r--r--source/blender/compositor/tests/COM_NodeOperation_test.cc22
-rw-r--r--source/blender/datatoc/CMakeLists.txt4
-rw-r--r--source/blender/datatoc/datatoc_icon.c4
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h127
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h53
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_debug.h14
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h94
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc17
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cache.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cache.h10
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc152
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h45
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc17
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc3
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc121
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h9
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc1
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h7
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc27
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc12
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc12
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc8
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc18
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc4
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc1
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_foreach.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc52
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc18
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_update.cc1
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc9
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc103
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h34
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc4
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.h8
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.cc21
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.h22
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.cc32
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.h24
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_factory.h2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.cc1
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.h1
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.cc5
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.h7
-rw-r--r--source/blender/draw/CMakeLists.txt638
-rw-r--r--source/blender/draw/DRW_engine.h65
-rw-r--r--source/blender/draw/DRW_select_buffer.h45
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c99
-rw-r--r--source/blender/draw/engines/basic/basic_private.h35
-rw-r--r--source/blender/draw/engines/basic/basic_shader.c167
-rw-r--r--source/blender/draw/engines/basic/shaders/depth_vert.glsl7
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.h32
-rw-r--r--source/blender/draw/engines/external/external_engine.c5
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_data.c9
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c12
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h28
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c1
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader_fx.c7
-rw-r--r--source/blender/draw/engines/image/image_drawing_mode_image_space.hh147
-rw-r--r--source/blender/draw/engines/image/image_engine.c460
-rw-r--r--source/blender/draw/engines/image/image_engine.cc204
-rw-r--r--source/blender/draw/engines/image/image_engine.h10
-rw-r--r--source/blender/draw/engines/image/image_private.h69
-rw-r--r--source/blender/draw/engines/image/image_private.hh196
-rw-r--r--source/blender/draw/engines/image/image_shader.cc (renamed from source/blender/draw/engines/image/image_shader.c)26
-rw-r--r--source/blender/draw/engines/image/image_space_image.hh182
-rw-r--r--source/blender/draw/engines/image/image_space_node.hh138
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c233
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_mesh.c6
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_text.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_uv.c16
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c19
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c5
-rw-r--r--source/blender/draw/engines/overlay/overlay_grid.c9
-rw-r--r--source/blender/draw/engines/overlay/overlay_image.c5
-rw-r--r--source/blender/draw/engines/overlay/overlay_private.h37
-rw-r--r--source/blender/draw/engines/overlay/overlay_shader.c6
-rw-r--r--source/blender/draw/engines/overlay/overlay_wireframe.c47
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl2
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl6
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl12
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl3
-rw-r--r--source/blender/draw/engines/overlay/shaders/image_vert.glsl11
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl3
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl10
-rw-r--r--source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl19
-rw-r--r--source/blender/draw/engines/select/select_debug_engine.c1
-rw-r--r--source/blender/draw/engines/select/select_draw_utils.c2
-rw-r--r--source/blender/draw/engines/select/select_engine.c2
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh41
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh64
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh31
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_effect_dof_info.hh55
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_effect_outline_info.hh11
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_merge_infront_info.hh9
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh149
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_shadow_info.hh98
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_transparent_resolve_info.hh10
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh114
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl8
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl13
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl11
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl8
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl33
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl8
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl39
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl4
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl5
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl7
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl12
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl10
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl6
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl9
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl16
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl13
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl18
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl15
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shadow_caps_geom.glsl49
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl6
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl36
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl14
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl13
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl7
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl32
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl14
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl8
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_antialiasing.c1
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_cavity.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_dof.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_outline.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c8
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c10
-rw-r--r--source/blender/draw/engines/workbench/workbench_opaque.c14
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h17
-rw-r--r--source/blender/draw/engines/workbench/workbench_render.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_shader.c562
-rw-r--r--source/blender/draw/engines/workbench/workbench_shader.cc444
-rw-r--r--source/blender/draw/engines/workbench/workbench_shader_shared.h (renamed from source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl)26
-rw-r--r--source/blender/draw/engines/workbench/workbench_transparent.c16
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c8
-rw-r--r--source/blender/draw/intern/DRW_gpu_wrapper.hh812
-rw-r--r--source/blender/draw/intern/DRW_render.h267
-rw-r--r--source/blender/draw/intern/draw_cache.c96
-rw-r--r--source/blender/draw/intern/draw_cache.h54
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h73
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc138
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_render_data.c31
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h190
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.cc4
-rw-r--r--source/blender/draw/intern/draw_cache_impl_displist.c4
-rw-r--r--source/blender/draw/intern/draw_cache_impl_gpencil.c29
-rw-r--r--source/blender/draw/intern/draw_cache_impl_hair.cc (renamed from source/blender/draw/intern/draw_cache_impl_hair.c)46
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c548
-rw-r--r--source/blender/draw/intern/draw_cache_impl_metaball.c9
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c3
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc1944
-rw-r--r--source/blender/draw/intern/draw_color_management.cc12
-rw-r--r--source/blender/draw/intern/draw_color_management.h3
-rw-r--r--source/blender/draw/intern/draw_common.c35
-rw-r--r--source/blender/draw/intern/draw_common.h18
-rw-r--r--source/blender/draw/intern/draw_debug.c1
-rw-r--r--source/blender/draw/intern/draw_debug.h11
-rw-r--r--source/blender/draw/intern/draw_fluid.c3
-rw-r--r--source/blender/draw/intern/draw_hair.c5
-rw-r--r--source/blender/draw/intern/draw_hair_private.h6
-rw-r--r--source/blender/draw/intern/draw_instance_data.c23
-rw-r--r--source/blender/draw/intern/draw_instance_data.h48
-rw-r--r--source/blender/draw/intern/draw_manager.c382
-rw-r--r--source/blender/draw/intern/draw_manager.h20
-rw-r--r--source/blender/draw/intern/draw_manager_data.c75
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c19
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.c6
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.h7
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c2
-rw-r--r--source/blender/draw/intern/draw_manager_text.c1
-rw-r--r--source/blender/draw/intern/draw_manager_text.h5
-rw-r--r--source/blender/draw/intern/draw_select_buffer.c26
-rw-r--r--source/blender/draw/intern/draw_shader.c7
-rw-r--r--source/blender/draw/intern/draw_shader_shared.h52
-rw-r--r--source/blender/draw/intern/draw_subdivision.h231
-rw-r--r--source/blender/draw/intern/draw_texture_pool.cc17
-rw-r--r--source/blender/draw/intern/draw_texture_pool.h7
-rw-r--r--source/blender/draw/intern/draw_view.c73
-rw-r--r--source/blender/draw/intern/draw_view.h2
-rw-r--r--source/blender/draw/intern/draw_view_data.cc15
-rw-r--r--source/blender/draw/intern/draw_view_data.h19
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.h107
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc229
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc3
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc31
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc94
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc72
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc30
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc489
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc88
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc125
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc79
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc59
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc65
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc48
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc32
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc132
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc109
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc97
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc89
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc163
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc48
-rw-r--r--source/blender/draw/intern/shaders/common_fullscreen_vert.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_fxaa_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_globals_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_hair_lib.glsl9
-rw-r--r--source/blender/draw/intern/shaders/common_hair_refine_comp.glsl5
-rw-r--r--source/blender/draw/intern/shaders/common_pointcloud_lib.glsl17
-rw-r--r--source/blender/draw/intern/shaders/common_smaa_lib.glsl6
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl230
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl57
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl43
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_lib.glsl176
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl56
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl34
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl416
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl97
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl80
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl31
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl52
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl47
-rw-r--r--source/blender/draw/intern/shaders/common_view_clipping_lib.glsl33
-rw-r--r--source/blender/draw/intern/shaders/common_view_lib.glsl138
-rw-r--r--source/blender/draw/intern/shaders/draw_fullscreen_info.hh8
-rw-r--r--source/blender/draw/intern/shaders/draw_hair_refine_info.hh42
-rw-r--r--source/blender/draw/intern/shaders/draw_object_infos_info.hh6
-rw-r--r--source/blender/draw/intern/shaders/draw_view_info.hh105
-rw-r--r--source/blender/draw/intern/smaa_textures.c15068
-rw-r--r--source/blender/draw/intern/smaa_textures.h15036
-rw-r--r--source/blender/draw/tests/shaders_test.cc20
-rw-r--r--source/blender/editors/animation/CMakeLists.txt12
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c30
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c97
-rw-r--r--source/blender/editors/animation/anim_deps.c6
-rw-r--r--source/blender/editors/animation/anim_draw.c82
-rw-r--r--source/blender/editors/animation/anim_filter.c21
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c31
-rw-r--r--source/blender/editors/animation/anim_markers.c46
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c20
-rw-r--r--source/blender/editors/animation/anim_ops.c12
-rw-r--r--source/blender/editors/animation/drivers.c65
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c27
-rw-r--r--source/blender/editors/animation/keyframes_draw.c24
-rw-r--r--source/blender/editors/animation/keyframes_edit.c89
-rw-r--r--source/blender/editors/animation/keyframes_general.c174
-rw-r--r--source/blender/editors/animation/keyframes_keylist.cc25
-rw-r--r--source/blender/editors/animation/keyframes_keylist_test.cc144
-rw-r--r--source/blender/editors/animation/keyframing.c248
-rw-r--r--source/blender/editors/animation/keyingsets.c40
-rw-r--r--source/blender/editors/animation/time_scrub_ui.c16
-rw-r--r--source/blender/editors/armature/armature_add.c7
-rw-r--r--source/blender/editors/armature/armature_edit.c8
-rw-r--r--source/blender/editors/armature/armature_intern.h98
-rw-r--r--source/blender/editors/armature/armature_naming.c18
-rw-r--r--source/blender/editors/armature/armature_ops.c5
-rw-r--r--source/blender/editors/armature/armature_relations.c95
-rw-r--r--source/blender/editors/armature/armature_select.c20
-rw-r--r--source/blender/editors/armature/armature_utils.c84
-rw-r--r--source/blender/editors/armature/editarmature_undo.c1
-rw-r--r--source/blender/editors/armature/meshlaplacian.c3
-rw-r--r--source/blender/editors/armature/pose_edit.c11
-rw-r--r--source/blender/editors/armature/pose_lib.c2
-rw-r--r--source/blender/editors/armature/pose_lib_2.c12
-rw-r--r--source/blender/editors/armature/pose_select.c18
-rw-r--r--source/blender/editors/armature/pose_slide.c65
-rw-r--r--source/blender/editors/armature/pose_transform.c12
-rw-r--r--source/blender/editors/armature/pose_utils.c13
-rw-r--r--source/blender/editors/asset/CMakeLists.txt8
-rw-r--r--source/blender/editors/asset/ED_asset_catalog.h41
-rw-r--r--source/blender/editors/asset/ED_asset_catalog.hh61
-rw-r--r--source/blender/editors/asset/ED_asset_filter.h14
-rw-r--r--source/blender/editors/asset/ED_asset_handle.h6
-rw-r--r--source/blender/editors/asset/ED_asset_indexer.h50
-rw-r--r--source/blender/editors/asset/ED_asset_library.h20
-rw-r--r--source/blender/editors/asset/ED_asset_list.h26
-rw-r--r--source/blender/editors/asset/ED_asset_list.hh2
-rw-r--r--source/blender/editors/asset/ED_asset_mark_clear.h15
-rw-r--r--source/blender/editors/asset/ED_asset_temp_id_consumer.h5
-rw-r--r--source/blender/editors/asset/ED_asset_type.h60
-rw-r--r--source/blender/editors/asset/intern/asset_catalog.cc187
-rw-r--r--source/blender/editors/asset/intern/asset_filter.cc13
-rw-r--r--source/blender/editors/asset/intern/asset_handle.cc7
-rw-r--r--source/blender/editors/asset/intern/asset_indexer.cc812
-rw-r--r--source/blender/editors/asset/intern/asset_library_reference_enum.cc68
-rw-r--r--source/blender/editors/asset/intern/asset_list.cc44
-rw-r--r--source/blender/editors/asset/intern/asset_mark_clear.cc50
-rw-r--r--source/blender/editors/asset/intern/asset_ops.cc678
-rw-r--r--source/blender/editors/asset/intern/asset_temp_id_consumer.cc6
-rw-r--r--source/blender/editors/asset/intern/asset_type.cc58
-rw-r--r--source/blender/editors/curve/curve_intern.h15
-rw-r--r--source/blender/editors/curve/editcurve.c57
-rw-r--r--source/blender/editors/curve/editcurve_add.c8
-rw-r--r--source/blender/editors/curve/editcurve_paint.c6
-rw-r--r--source/blender/editors/curve/editcurve_select.c11
-rw-r--r--source/blender/editors/curve/editcurve_undo.c1
-rw-r--r--source/blender/editors/curve/editfont.c11
-rw-r--r--source/blender/editors/curve/editfont_undo.c3
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt1
-rw-r--r--source/blender/editors/geometry/CMakeLists.txt8
-rw-r--r--source/blender/editors/geometry/geometry_attributes.c182
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc385
-rw-r--r--source/blender/editors/geometry/geometry_intern.hh (renamed from source/blender/editors/geometry/geometry_intern.h)7
-rw-r--r--source/blender/editors/geometry/geometry_ops.cc (renamed from source/blender/editors/geometry/geometry_ops.c)5
-rw-r--r--source/blender/editors/gizmo_library/gizmo_draw_utils.c3
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_intern.h28
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_utils.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c10
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c8
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c110
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c5
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c604
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c25
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c103
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c30
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c33
-rw-r--r--source/blender/editors/gpencil/gpencil_add_blank.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_add_lineart.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_add_monkey.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_add_stroke.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_bake_animation.c5
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c154
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c46
-rw-r--r--source/blender/editors/gpencil/gpencil_edit_curve.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c37
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h136
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_merge.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_mesh.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c314
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c84
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c7
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_trace.h42
-rw-r--r--source/blender/editors/gpencil/gpencil_trace_utils.c32
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c268
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_ops.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_paint.c12
-rw-r--r--source/blender/editors/gpencil/gpencil_weight_paint.c24
-rw-r--r--source/blender/editors/include/BIF_glutil.h168
-rw-r--r--source/blender/editors/include/ED_anim_api.h366
-rw-r--r--source/blender/editors/include/ED_armature.h163
-rw-r--r--source/blender/editors/include/ED_asset.h3
-rw-r--r--source/blender/editors/include/ED_buttons.h9
-rw-r--r--source/blender/editors/include/ED_clip.h15
-rw-r--r--source/blender/editors/include/ED_curve.h26
-rw-r--r--source/blender/editors/include/ED_file_indexer.h153
-rw-r--r--source/blender/editors/include/ED_fileselect.h46
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h63
-rw-r--r--source/blender/editors/include/ED_gpencil.h311
-rw-r--r--source/blender/editors/include/ED_image.h64
-rw-r--r--source/blender/editors/include/ED_info.h5
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h166
-rw-r--r--source/blender/editors/include/ED_keyframes_keylist.h27
-rw-r--r--source/blender/editors/include/ED_keyframing.h361
-rw-r--r--source/blender/editors/include/ED_lattice.h6
-rw-r--r--source/blender/editors/include/ED_markers.h63
-rw-r--r--source/blender/editors/include/ED_mask.h78
-rw-r--r--source/blender/editors/include/ED_mball.h18
-rw-r--r--source/blender/editors/include/ED_mesh.h390
-rw-r--r--source/blender/editors/include/ED_node.h70
-rw-r--r--source/blender/editors/include/ED_numinput.h8
-rw-r--r--source/blender/editors/include/ED_object.h235
-rw-r--r--source/blender/editors/include/ED_outliner.h17
-rw-r--r--source/blender/editors/include/ED_paint.h16
-rw-r--r--source/blender/editors/include/ED_particle.h15
-rw-r--r--source/blender/editors/include/ED_render.h32
-rw-r--r--source/blender/editors/include/ED_scene.h7
-rw-r--r--source/blender/editors/include/ED_screen.h318
-rw-r--r--source/blender/editors/include/ED_sculpt.h11
-rw-r--r--source/blender/editors/include/ED_select_utils.h30
-rw-r--r--source/blender/editors/include/ED_sequencer.h10
-rw-r--r--source/blender/editors/include/ED_space_api.h25
-rw-r--r--source/blender/editors/include/ED_text.h9
-rw-r--r--source/blender/editors/include/ED_transform.h41
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h65
-rw-r--r--source/blender/editors/include/ED_transverts.h2
-rw-r--r--source/blender/editors/include/ED_undo.h49
-rw-r--r--source/blender/editors/include/ED_util.h47
-rw-r--r--source/blender/editors/include/ED_uvedit.h112
-rw-r--r--source/blender/editors/include/ED_view3d.h643
-rw-r--r--source/blender/editors/include/ED_view3d_offscreen.h29
-rw-r--r--source/blender/editors/include/UI_icons.h6
-rw-r--r--source/blender/editors/include/UI_interface.h912
-rw-r--r--source/blender/editors/include/UI_interface.hh42
-rw-r--r--source/blender/editors/include/UI_interface_icons.h47
-rw-r--r--source/blender/editors/include/UI_resources.h103
-rw-r--r--source/blender/editors/include/UI_tree_view.hh389
-rw-r--r--source/blender/editors/include/UI_view2d.h218
-rw-r--r--source/blender/editors/interface/CMakeLists.txt9
-rw-r--r--source/blender/editors/interface/interface.c909
-rw-r--r--source/blender/editors/interface/interface_align.c7
-rw-r--r--source/blender/editors/interface/interface_anim.c5
-rw-r--r--source/blender/editors/interface/interface_button_group.c6
-rw-r--r--source/blender/editors/interface/interface_context_menu.c24
-rw-r--r--source/blender/editors/interface/interface_context_path.cc85
-rw-r--r--source/blender/editors/interface/interface_draw.c202
-rw-r--r--source/blender/editors/interface/interface_dropboxes.cc95
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c23
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c49
-rw-r--r--source/blender/editors/interface/interface_eyedropper_colorband.c12
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c6
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c12
-rw-r--r--source/blender/editors/interface/interface_eyedropper_driver.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_gpencil_color.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_intern.h20
-rw-r--r--source/blender/editors/interface/interface_handlers.c666
-rw-r--r--source/blender/editors/interface/interface_icons.c106
-rw-r--r--source/blender/editors/interface/interface_icons_event.c26
-rw-r--r--source/blender/editors/interface/interface_intern.h373
-rw-r--r--source/blender/editors/interface/interface_layout.c168
-rw-r--r--source/blender/editors/interface/interface_ops.c266
-rw-r--r--source/blender/editors/interface/interface_panel.c307
-rw-r--r--source/blender/editors/interface/interface_query.c88
-rw-r--r--source/blender/editors/interface/interface_region_color_picker.c3
-rw-r--r--source/blender/editors/interface/interface_region_hud.c1
-rw-r--r--source/blender/editors/interface/interface_region_menu_pie.c17
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.c18
-rw-r--r--source/blender/editors/interface/interface_region_popover.c9
-rw-r--r--source/blender/editors/interface/interface_region_popup.c14
-rw-r--r--source/blender/editors/interface/interface_region_search.cc (renamed from source/blender/editors/interface/interface_region_search.c)185
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c124
-rw-r--r--source/blender/editors/interface/interface_regions_intern.h8
-rw-r--r--source/blender/editors/interface/interface_style.c77
-rw-r--r--source/blender/editors/interface/interface_template_asset_view.cc5
-rw-r--r--source/blender/editors/interface/interface_template_attribute_search.cc126
-rw-r--r--source/blender/editors/interface/interface_template_list.cc9
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.cc (renamed from source/blender/editors/interface/interface_template_search_menu.c)312
-rw-r--r--source/blender/editors/interface/interface_templates.c608
-rw-r--r--source/blender/editors/interface/interface_undo.c11
-rw-r--r--source/blender/editors/interface/interface_utils.c36
-rw-r--r--source/blender/editors/interface/interface_view.cc92
-rw-r--r--source/blender/editors/interface/interface_widgets.c448
-rw-r--r--source/blender/editors/interface/resources.c40
-rw-r--r--source/blender/editors/interface/tree_view.cc726
-rw-r--r--source/blender/editors/interface/view2d.c219
-rw-r--r--source/blender/editors/interface/view2d_draw.c20
-rw-r--r--source/blender/editors/interface/view2d_edge_pan.c27
-rw-r--r--source/blender/editors/interface/view2d_gizmo_navigate.c16
-rw-r--r--source/blender/editors/interface/view2d_ops.c63
-rw-r--r--source/blender/editors/io/CMakeLists.txt4
-rw-r--r--source/blender/editors/io/io_cache.c168
-rw-r--r--source/blender/editors/io/io_cache.h4
-rw-r--r--source/blender/editors/io/io_gpencil_export.c1
-rw-r--r--source/blender/editors/io/io_obj.c369
-rw-r--r--source/blender/editors/io/io_obj.h25
-rw-r--r--source/blender/editors/io/io_ops.c7
-rw-r--r--source/blender/editors/io/io_usd.c2
-rw-r--r--source/blender/editors/lattice/editlattice_select.c5
-rw-r--r--source/blender/editors/lattice/editlattice_tools.c2
-rw-r--r--source/blender/editors/lattice/editlattice_undo.c1
-rw-r--r--source/blender/editors/mask/mask_draw.c67
-rw-r--r--source/blender/editors/mask/mask_editaction.c11
-rw-r--r--source/blender/editors/mask/mask_intern.h24
-rw-r--r--source/blender/editors/mask/mask_ops.c4
-rw-r--r--source/blender/editors/mask/mask_query.c3
-rw-r--r--source/blender/editors/mask/mask_relationships.c1
-rw-r--r--source/blender/editors/mask/mask_select.c1
-rw-r--r--source/blender/editors/mesh/editface.c11
-rw-r--r--source/blender/editors/mesh/editmesh_add_gizmo.c4
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c5
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c5
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin.c2
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c2
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c6
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c120
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c4
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c6
-rw-r--r--source/blender/editors/mesh/editmesh_path.c2
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_elem.c1
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c2
-rw-r--r--source/blender/editors/mesh/editmesh_select.c49
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c30
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c6
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c15
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c66
-rw-r--r--source/blender/editors/mesh/mesh_data.c53
-rw-r--r--source/blender/editors/mesh/mesh_intern.h63
-rw-r--r--source/blender/editors/mesh/mesh_ops.c1
-rw-r--r--source/blender/editors/mesh/meshtools.c33
-rw-r--r--source/blender/editors/metaball/editmball_undo.c1
-rw-r--r--source/blender/editors/metaball/mball_edit.c11
-rw-r--r--source/blender/editors/object/object_add.c316
-rw-r--r--source/blender/editors/object/object_bake.c17
-rw-r--r--source/blender/editors/object/object_bake_api.c59
-rw-r--r--source/blender/editors/object/object_constraint.c37
-rw-r--r--source/blender/editors/object/object_data_transfer.c1
-rw-r--r--source/blender/editors/object/object_edit.c151
-rw-r--r--source/blender/editors/object/object_facemap_ops.c2
-rw-r--r--source/blender/editors/object/object_gpencil_modifier.c15
-rw-r--r--source/blender/editors/object/object_hook.c2
-rw-r--r--source/blender/editors/object/object_intern.h40
-rw-r--r--source/blender/editors/object/object_modes.c61
-rw-r--r--source/blender/editors/object/object_modifier.c37
-rw-r--r--source/blender/editors/object/object_ops.c2
-rw-r--r--source/blender/editors/object/object_relations.c161
-rw-r--r--source/blender/editors/object/object_remesh.cc18
-rw-r--r--source/blender/editors/object/object_select.c31
-rw-r--r--source/blender/editors/object/object_shader_fx.c2
-rw-r--r--source/blender/editors/object/object_shapekey.c3
-rw-r--r--source/blender/editors/object/object_transform.c17
-rw-r--r--source/blender/editors/object/object_utils.c74
-rw-r--r--source/blender/editors/object/object_vgroup.c25
-rw-r--r--source/blender/editors/object/object_volume.c1
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c6
-rw-r--r--source/blender/editors/physics/particle_edit.c31
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c1
-rw-r--r--source/blender/editors/physics/particle_object.c31
-rw-r--r--source/blender/editors/physics/physics_intern.h24
-rw-r--r--source/blender/editors/render/CMakeLists.txt17
-rw-r--r--source/blender/editors/render/render_intern.hh (renamed from source/blender/editors/render/render_intern.h)9
-rw-r--r--source/blender/editors/render/render_internal.cc (renamed from source/blender/editors/render/render_internal.c)148
-rw-r--r--source/blender/editors/render/render_opengl.cc (renamed from source/blender/editors/render/render_opengl.c)189
-rw-r--r--source/blender/editors/render/render_ops.cc (renamed from source/blender/editors/render/render_ops.c)6
-rw-r--r--source/blender/editors/render/render_preview.cc (renamed from source/blender/editors/render/render_preview.c)521
-rw-r--r--source/blender/editors/render/render_shading.cc (renamed from source/blender/editors/render/render_shading.c)195
-rw-r--r--source/blender/editors/render/render_update.cc (renamed from source/blender/editors/render/render_update.c)67
-rw-r--r--source/blender/editors/render/render_view.cc (renamed from source/blender/editors/render/render_view.c)67
-rw-r--r--source/blender/editors/scene/scene_edit.c5
-rw-r--r--source/blender/editors/screen/area.c191
-rw-r--r--source/blender/editors/screen/area_query.c34
-rw-r--r--source/blender/editors/screen/area_utils.c6
-rw-r--r--source/blender/editors/screen/glutil.c398
-rw-r--r--source/blender/editors/screen/screen_context.c122
-rw-r--r--source/blender/editors/screen/screen_draw.c16
-rw-r--r--source/blender/editors/screen/screen_edit.c133
-rw-r--r--source/blender/editors/screen/screen_geometry.c18
-rw-r--r--source/blender/editors/screen/screen_intern.h93
-rw-r--r--source/blender/editors/screen/screen_ops.c226
-rw-r--r--source/blender/editors/screen/screen_user_menu.c10
-rw-r--r--source/blender/editors/screen/screendump.c7
-rw-r--r--source/blender/editors/screen/workspace_edit.c24
-rw-r--r--source/blender/editors/screen/workspace_layout_edit.c13
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt4
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve_undo.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c56
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c98
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc188
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c76
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h203
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c3
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c53
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c111
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_utils.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_proj.c26
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c15
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c11
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c4118
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c7
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_brush_types.c2847
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c14
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c42
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_expand.c12
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mask.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c16
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h1593
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_expand.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c1141
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c47
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c5
-rw-r--r--source/blender/editors/space_action/action_data.c6
-rw-r--r--source/blender/editors/space_action/action_draw.c57
-rw-r--r--source/blender/editors/space_action/action_edit.c8
-rw-r--r--source/blender/editors/space_action/action_intern.h7
-rw-r--r--source/blender/editors/space_action/space_action.c28
-rw-r--r--source/blender/editors/space_api/spacetypes.c27
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c28
-rw-r--r--source/blender/editors/space_buttons/buttons_intern.h6
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c1
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c5
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c76
-rw-r--r--source/blender/editors/space_clip/CMakeLists.txt7
-rw-r--r--source/blender/editors/space_clip/clip_draw.c6
-rw-r--r--source/blender/editors/space_clip/clip_editor.c22
-rw-r--r--source/blender/editors/space_clip/clip_intern.h18
-rw-r--r--source/blender/editors/space_clip/clip_ops.c45
-rw-r--r--source/blender/editors/space_clip/clip_utils.c3
-rw-r--r--source/blender/editors/space_clip/space_clip.c36
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c6
-rw-r--r--source/blender/editors/space_console/space_console.c3
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc773
-rw-r--r--source/blender/editors/space_file/file_draw.c106
-rw-r--r--source/blender/editors/space_file/file_indexer.cc96
-rw-r--r--source/blender/editors/space_file/file_indexer.h36
-rw-r--r--source/blender/editors/space_file/file_intern.h102
-rw-r--r--source/blender/editors/space_file/file_ops.c35
-rw-r--r--source/blender/editors/space_file/file_panels.c60
-rw-r--r--source/blender/editors/space_file/file_utils.c3
-rw-r--r--source/blender/editors/space_file/filelist.c1118
-rw-r--r--source/blender/editors/space_file/filelist.h96
-rw-r--r--source/blender/editors/space_file/filesel.c145
-rw-r--r--source/blender/editors/space_file/fsmenu.c25
-rw-r--r--source/blender/editors/space_file/fsmenu.h2
-rw-r--r--source/blender/editors/space_file/space_file.c67
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c77
-rw-r--r--source/blender/editors/space_graph/graph_draw.c21
-rw-r--r--source/blender/editors/space_graph/graph_edit.c108
-rw-r--r--source/blender/editors/space_graph/graph_intern.h66
-rw-r--r--source/blender/editors/space_graph/graph_ops.c31
-rw-r--r--source/blender/editors/space_graph/graph_select.c96
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c716
-rw-r--r--source/blender/editors/space_graph/graph_utils.c38
-rw-r--r--source/blender/editors/space_graph/graph_view.c55
-rw-r--r--source/blender/editors/space_graph/space_graph.c19
-rw-r--r--source/blender/editors/space_image/image_buttons.c7
-rw-r--r--source/blender/editors/space_image/image_draw.c30
-rw-r--r--source/blender/editors/space_image/image_edit.c19
-rw-r--r--source/blender/editors/space_image/image_intern.h12
-rw-r--r--source/blender/editors/space_image/image_ops.c84
-rw-r--r--source/blender/editors/space_image/image_sequence.c69
-rw-r--r--source/blender/editors/space_image/image_undo.c7
-rw-r--r--source/blender/editors/space_image/space_image.c30
-rw-r--r--source/blender/editors/space_info/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_info/info_ops.c12
-rw-r--r--source/blender/editors/space_info/info_report.c1
-rw-r--r--source/blender/editors/space_info/info_stats.cc (renamed from source/blender/editors/space_info/info_stats.c)94
-rw-r--r--source/blender/editors/space_info/space_info.c1
-rw-r--r--source/blender/editors/space_info/textview.c7
-rw-r--r--source/blender/editors/space_info/textview.h9
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c2
-rw-r--r--source/blender/editors/space_nla/nla_channels.c2
-rw-r--r--source/blender/editors/space_nla/nla_draw.c66
-rw-r--r--source/blender/editors/space_nla/nla_edit.c19
-rw-r--r--source/blender/editors/space_nla/nla_intern.h18
-rw-r--r--source/blender/editors/space_nla/nla_ops.c3
-rw-r--r--source/blender/editors/space_nla/space_nla.c17
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt11
-rw-r--r--source/blender/editors/space_node/drawnode.cc2837
-rw-r--r--source/blender/editors/space_node/link_drag_search.cc327
-rw-r--r--source/blender/editors/space_node/node_add.cc235
-rw-r--r--source/blender/editors/space_node/node_context_path.cc184
-rw-r--r--source/blender/editors/space_node/node_draw.cc2080
-rw-r--r--source/blender/editors/space_node/node_edit.cc506
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc119
-rw-r--r--source/blender/editors/space_node/node_gizmo.cc (renamed from source/blender/editors/space_node/node_gizmo.c)123
-rw-r--r--source/blender/editors/space_node/node_group.cc285
-rw-r--r--source/blender/editors/space_node/node_intern.h343
-rw-r--r--source/blender/editors/space_node/node_intern.hh352
-rw-r--r--source/blender/editors/space_node/node_ops.cc (renamed from source/blender/editors/space_node/node_ops.c)29
-rw-r--r--source/blender/editors/space_node/node_relationships.cc1333
-rw-r--r--source/blender/editors/space_node/node_select.cc284
-rw-r--r--source/blender/editors/space_node/node_templates.cc242
-rw-r--r--source/blender/editors/space_node/node_view.cc99
-rw-r--r--source/blender/editors/space_node/space_node.cc (renamed from source/blender/editors/space_node/space_node.c)299
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt31
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.cc (renamed from source/blender/editors/space_outliner/outliner_collections.c)265
-rw-r--r--source/blender/editors/space_outliner/outliner_context.cc (renamed from source/blender/editors/space_outliner/outliner_context.c)4
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.cc (renamed from source/blender/editors/space_outliner/outliner_dragdrop.c)236
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc (renamed from source/blender/editors/space_outliner/outliner_draw.c)442
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.cc (renamed from source/blender/editors/space_outliner/outliner_edit.c)213
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.hh (renamed from source/blender/editors/space_outliner/outliner_intern.h)156
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.cc (renamed from source/blender/editors/space_outliner/outliner_ops.c)2
-rw-r--r--source/blender/editors/space_outliner/outliner_select.cc (renamed from source/blender/editors/space_outliner/outliner_select.c)160
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.cc (renamed from source/blender/editors/space_outliner/outliner_sync.c)35
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc (renamed from source/blender/editors/space_outliner/outliner_tools.c)496
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.cc (renamed from source/blender/editors/space_outliner/outliner_tree.c)387
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.cc (renamed from source/blender/editors/space_outliner/outliner_utils.c)77
-rw-r--r--source/blender/editors/space_outliner/space_outliner.cc (renamed from source/blender/editors/space_outliner/space_outliner.c)143
-rw-r--r--source/blender/editors/space_outliner/tree/common.cc38
-rw-r--r--source/blender/editors/space_outliner/tree/common.hh28
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.cc45
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.h68
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.hh42
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_data.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_libraries.cc15
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_orphaned.cc6
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_override_library.cc17
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_scenes.cc7
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_sequencer.cc8
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_view_layer.cc6
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.cc135
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.h48
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.hh51
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_anim_data.cc4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_collection.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_driver.cc4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.cc13
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.hh5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_library.cc3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_library.hh2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_scene.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_nla.cc4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_rna.cc249
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_rna.hh75
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc6
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_view_layer.cc5
-rw-r--r--source/blender/editors/space_script/space_script.c1
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c74
-rw-r--r--source/blender/editors/space_sequencer/sequencer_buttons.c5
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c661
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c412
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h49
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_proxy.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c419
-rw-r--r--source/blender/editors/space_sequencer/sequencer_thumbnails.c592
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c13
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c158
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt16
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc169
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_cache.cc79
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_cache.hh78
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh63
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc43
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.hh2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh65
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_context.cc34
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh6
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc603
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh46
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc354
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh42
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc112
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh68
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_draw.cc8
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_intern.hh33
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc153
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.hh2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_panels.cc37
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc412
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh8
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc19
-rw-r--r--source/blender/editors/space_statusbar/space_statusbar.c1
-rw-r--r--source/blender/editors/space_text/space_text.c18
-rw-r--r--source/blender/editors/space_text/text_draw.c12
-rw-r--r--source/blender/editors/space_text/text_format.c13
-rw-r--r--source/blender/editors/space_text/text_format.h31
-rw-r--r--source/blender/editors/space_text/text_format_lua.c2
-rw-r--r--source/blender/editors/space_text/text_format_osl.c4
-rw-r--r--source/blender/editors/space_text/text_format_pov.c8
-rw-r--r--source/blender/editors/space_text/text_format_pov_ini.c6
-rw-r--r--source/blender/editors/space_text/text_format_py.c2
-rw-r--r--source/blender/editors/space_text/text_intern.h11
-rw-r--r--source/blender/editors/space_text/text_ops.c60
-rw-r--r--source/blender/editors/space_text/text_undo.c3
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c61
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c5
-rw-r--r--source/blender/editors/space_userpref/userpref_ops.c37
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_view3d/drawobject.c52
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c324
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c68
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c16
-rw-r--r--source/blender/editors/space_view3d/view3d_cursor_snap.c1017
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c158
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c120
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_armature.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c76
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c36
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h82
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c16
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_fly.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_walk.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c933
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c127
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c54
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c115
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c179
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c78
-rw-r--r--source/blender/editors/transform/transform.c57
-rw-r--r--source/blender/editors/transform/transform.h69
-rw-r--r--source/blender/editors/transform/transform_constraints.c106
-rw-r--r--source/blender/editors/transform/transform_constraints.h25
-rw-r--r--source/blender/editors/transform/transform_convert.c60
-rw-r--r--source/blender/editors/transform/transform_convert.h107
-rw-r--r--source/blender/editors/transform/transform_convert_action.c8
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c15
-rw-r--r--source/blender/editors/transform/transform_convert_cursor.c114
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c35
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c22
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c10
-rw-r--r--source/blender/editors/transform/transform_convert_mask.c7
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c18
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_edge.c4
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_skin.c1
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_uv.c1
-rw-r--r--source/blender/editors/transform/transform_convert_nla.c1
-rw-r--r--source/blender/editors/transform/transform_convert_node.c11
-rw-r--r--source/blender/editors/transform/transform_convert_object.c30
-rw-r--r--source/blender/editors/transform/transform_convert_object_texspace.c3
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c42
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c82
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c11
-rw-r--r--source/blender/editors/transform/transform_data.h6
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.c8
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.h9
-rw-r--r--source/blender/editors/transform/transform_generics.c262
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c453
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c167
-rw-r--r--source/blender/editors/transform/transform_gizmo_extrude_3d.c7
-rw-r--r--source/blender/editors/transform/transform_mode.c52
-rw-r--r--source/blender/editors/transform/transform_mode.h26
-rw-r--r--source/blender/editors/transform/transform_mode_align.c1
-rw-r--r--source/blender/editors/transform/transform_mode_baketime.c1
-rw-r--r--source/blender/editors/transform/transform_mode_bbone_resize.c2
-rw-r--r--source/blender/editors/transform/transform_mode_bend.c1
-rw-r--r--source/blender/editors/transform/transform_mode_boneenvelope.c2
-rw-r--r--source/blender/editors/transform/transform_mode_boneroll.c3
-rw-r--r--source/blender/editors/transform/transform_mode_curveshrinkfatten.c3
-rw-r--r--source/blender/editors/transform/transform_mode_edge_bevelweight.c3
-rw-r--r--source/blender/editors/transform/transform_mode_edge_crease.c15
-rw-r--r--source/blender/editors/transform/transform_mode_edge_rotate_normal.c3
-rw-r--r--source/blender/editors/transform/transform_mode_edge_slide.c5
-rw-r--r--source/blender/editors/transform/transform_mode_gpopacity.c3
-rw-r--r--source/blender/editors/transform/transform_mode_gpshrinkfatten.c3
-rw-r--r--source/blender/editors/transform/transform_mode_maskshrinkfatten.c3
-rw-r--r--source/blender/editors/transform/transform_mode_mirror.c1
-rw-r--r--source/blender/editors/transform/transform_mode_push_pull.c3
-rw-r--r--source/blender/editors/transform/transform_mode_resize.c36
-rw-r--r--source/blender/editors/transform/transform_mode_rotate.c1
-rw-r--r--source/blender/editors/transform/transform_mode_shear.c3
-rw-r--r--source/blender/editors/transform/transform_mode_shrink_fatten.c7
-rw-r--r--source/blender/editors/transform/transform_mode_skin_resize.c2
-rw-r--r--source/blender/editors/transform/transform_mode_tilt.c3
-rw-r--r--source/blender/editors/transform/transform_mode_timescale.c1
-rw-r--r--source/blender/editors/transform/transform_mode_timeslide.c1
-rw-r--r--source/blender/editors/transform/transform_mode_timetranslate.c16
-rw-r--r--source/blender/editors/transform/transform_mode_tosphere.c3
-rw-r--r--source/blender/editors/transform/transform_mode_trackball.c1
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c10
-rw-r--r--source/blender/editors/transform/transform_mode_vert_slide.c3
-rw-r--r--source/blender/editors/transform/transform_ops.c45
-rw-r--r--source/blender/editors/transform/transform_orientations.c46
-rw-r--r--source/blender/editors/transform/transform_orientations.h21
-rw-r--r--source/blender/editors/transform/transform_snap.c198
-rw-r--r--source/blender/editors/transform/transform_snap.h22
-rw-r--r--source/blender/editors/transform/transform_snap_animation.c13
-rw-r--r--source/blender/editors/transform/transform_snap_object.c1070
-rw-r--r--source/blender/editors/transform/transform_snap_sequencer.c12
-rw-r--r--source/blender/editors/undo/ed_undo.c148
-rw-r--r--source/blender/editors/undo/memfile_undo.c58
-rw-r--r--source/blender/editors/undo/undo_intern.h2
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/editors/util/ed_draw.c85
-rw-r--r--source/blender/editors/util/ed_transverts.c12
-rw-r--r--source/blender/editors/util/ed_util.c122
-rw-r--r--source/blender/editors/util/ed_util_imbuf.c130
-rw-r--r--source/blender/editors/util/ed_util_ops.cc67
-rw-r--r--source/blender/editors/util/gizmo_utils.c1
-rw-r--r--source/blender/editors/util/numinput.c7
-rw-r--r--source/blender/editors/util/select_utils.c14
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h33
-rw-r--r--source/blender/editors/uvedit/uvedit_islands.c38
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c11
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c17
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c106
-rw-r--r--source/blender/freestyle/CMakeLists.txt5
-rw-r--r--source/blender/freestyle/FRS_freestyle.h4
-rw-r--r--source/blender/freestyle/FRS_precomp.cpp2
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp15
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp12
-rw-r--r--source/blender/freestyle/intern/image/GaussianFilter.h18
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp2
-rw-r--r--source/blender/freestyle/intern/scene_graph/FrsMaterial.h18
-rw-r--r--source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h2
-rw-r--r--source/blender/freestyle/intern/stroke/ChainingIterators.h6
-rw-r--r--source/blender/freestyle/intern/stroke/Curve.h2
-rw-r--r--source/blender/freestyle/intern/stroke/Operators.cpp6
-rw-r--r--source/blender/freestyle/intern/system/PythonInterpreter.h2
-rw-r--r--source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp2
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapIO.h6
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.cpp66
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.h63
-rw-r--r--source/blender/freestyle/intern/winged_edge/WEdge.h4
-rw-r--r--source/blender/freestyle/intern/winged_edge/WXEdge.h2
-rw-r--r--source/blender/functions/CMakeLists.txt9
-rw-r--r--source/blender/functions/FN_cpp_type.hh12
-rw-r--r--source/blender/functions/FN_field.hh472
-rw-r--r--source/blender/functions/FN_field_cpp_type.hh95
-rw-r--r--source/blender/functions/FN_generic_array.hh270
-rw-r--r--source/blender/functions/FN_generic_span.hh10
-rw-r--r--source/blender/functions/FN_generic_vector_array.hh3
-rw-r--r--source/blender/functions/FN_generic_virtual_array.hh1262
-rw-r--r--source/blender/functions/FN_generic_virtual_vector_array.hh32
-rw-r--r--source/blender/functions/FN_multi_function.hh38
-rw-r--r--source/blender/functions/FN_multi_function_builder.hh34
-rw-r--r--source/blender/functions/FN_multi_function_params.hh55
-rw-r--r--source/blender/functions/FN_multi_function_procedure.hh77
-rw-r--r--source/blender/functions/FN_multi_function_procedure_executor.hh5
-rw-r--r--source/blender/functions/FN_multi_function_procedure_optimization.hh61
-rw-r--r--source/blender/functions/FN_multi_function_signature.hh47
-rw-r--r--source/blender/functions/intern/cpp_types.cc3
-rw-r--r--source/blender/functions/intern/field.cc556
-rw-r--r--source/blender/functions/intern/generic_vector_array.cc5
-rw-r--r--source/blender/functions/intern/generic_virtual_array.cc719
-rw-r--r--source/blender/functions/intern/generic_virtual_vector_array.cc10
-rw-r--r--source/blender/functions/intern/multi_function.cc142
-rw-r--r--source/blender/functions/intern/multi_function_builder.cc36
-rw-r--r--source/blender/functions/intern/multi_function_parallel.cc95
-rw-r--r--source/blender/functions/intern/multi_function_params.cc44
-rw-r--r--source/blender/functions/intern/multi_function_procedure.cc2
-rw-r--r--source/blender/functions/intern/multi_function_procedure_executor.cc144
-rw-r--r--source/blender/functions/intern/multi_function_procedure_optimization.cc90
-rw-r--r--source/blender/functions/tests/FN_field_test.cc62
-rw-r--r--source/blender/functions/tests/FN_generic_array_test.cc118
-rw-r--r--source/blender/functions/tests/FN_multi_function_procedure_test.cc49
-rw-r--r--source/blender/functions/tests/FN_multi_function_test.cc2
-rw-r--r--source/blender/geometry/CMakeLists.txt61
-rw-r--r--source/blender/geometry/GEO_mesh_merge_by_distance.hh55
-rw-r--r--source/blender/geometry/GEO_mesh_to_curve.hh40
-rw-r--r--source/blender/geometry/GEO_point_merge_by_distance.hh38
-rw-r--r--source/blender/geometry/GEO_realize_instances.hh52
-rw-r--r--source/blender/geometry/intern/mesh_merge_by_distance.cc1729
-rw-r--r--source/blender/geometry/intern/mesh_to_curve_convert.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc)208
-rw-r--r--source/blender/geometry/intern/point_merge_by_distance.cc183
-rw-r--r--source/blender/geometry/intern/realize_instances.cc1347
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt1
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_lineart.h1
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c20
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h12
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c18
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h20
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencildash.c5
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillength.c107
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c92
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c350
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h139
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c248
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c346
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c8
-rw-r--r--source/blender/gpu/CMakeLists.txt474
-rw-r--r--source/blender/gpu/GPU_batch.h48
-rw-r--r--source/blender/gpu/GPU_batch_presets.h10
-rw-r--r--source/blender/gpu/GPU_batch_utils.h16
-rw-r--r--source/blender/gpu/GPU_buffers.h64
-rw-r--r--source/blender/gpu/GPU_capabilities.h3
-rw-r--r--source/blender/gpu/GPU_context.h8
-rw-r--r--source/blender/gpu/GPU_debug.h7
-rw-r--r--source/blender/gpu/GPU_framebuffer.h29
-rw-r--r--source/blender/gpu/GPU_immediate.h30
-rw-r--r--source/blender/gpu/GPU_immediate_util.h96
-rw-r--r--source/blender/gpu/GPU_index_buffer.h14
-rw-r--r--source/blender/gpu/GPU_material.h37
-rw-r--r--source/blender/gpu/GPU_matrix.h33
-rw-r--r--source/blender/gpu/GPU_platform.h3
-rw-r--r--source/blender/gpu/GPU_select.h33
-rw-r--r--source/blender/gpu/GPU_shader.h113
-rw-r--r--source/blender/gpu/GPU_shader_shared.h84
-rw-r--r--source/blender/gpu/GPU_state.h30
-rw-r--r--source/blender/gpu/GPU_texture.h46
-rw-r--r--source/blender/gpu/GPU_uniform_buffer.h6
-rw-r--r--source/blender/gpu/GPU_vertex_buffer.h57
-rw-r--r--source/blender/gpu/GPU_vertex_format.h35
-rw-r--r--source/blender/gpu/GPU_viewport.h30
-rw-r--r--source/blender/gpu/intern/gpu_backend.hh14
-rw-r--r--source/blender/gpu/intern/gpu_batch.cc14
-rw-r--r--source/blender/gpu/intern/gpu_batch_presets.c2
-rw-r--r--source/blender/gpu/intern/gpu_batch_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_batch_utils.c9
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c15
-rw-r--r--source/blender/gpu/intern/gpu_capabilities.cc47
-rw-r--r--source/blender/gpu/intern/gpu_capabilities_private.hh4
-rw-r--r--source/blender/gpu/intern/gpu_context.cc19
-rw-r--r--source/blender/gpu/intern/gpu_context_private.hh14
-rw-r--r--source/blender/gpu/intern/gpu_debug.cc7
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.cc45
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer_private.hh8
-rw-r--r--source/blender/gpu/intern/gpu_immediate.cc8
-rw-r--r--source/blender/gpu/intern/gpu_immediate_private.hh8
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c206
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer.cc21
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer_private.hh10
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c8
-rw-r--r--source/blender/gpu/intern/gpu_material.c16
-rw-r--r--source/blender/gpu/intern/gpu_material_library.c16
-rw-r--r--source/blender/gpu/intern/gpu_material_library.h2
-rw-r--r--source/blender/gpu/intern/gpu_matrix.cc26
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c113
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h9
-rw-r--r--source/blender/gpu/intern/gpu_platform.cc11
-rw-r--r--source/blender/gpu/intern/gpu_platform_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_query.hh4
-rw-r--r--source/blender/gpu/intern/gpu_select.c101
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c45
-rw-r--r--source/blender/gpu/intern/gpu_select_private.h5
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.cc6
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc230
-rw-r--r--source/blender/gpu/intern/gpu_shader_builder.cc102
-rw-r--r--source/blender/gpu/intern/gpu_shader_builder_stubs.cc258
-rw-r--r--source/blender/gpu/intern/gpu_shader_builtin.c350
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.cc263
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.hh622
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info_private.hh46
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc388
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency_private.h44
-rw-r--r--source/blender/gpu/intern/gpu_shader_info_baked.cc24
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.cc9
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.hh53
-rw-r--r--source/blender/gpu/intern/gpu_shader_private.hh34
-rw-r--r--source/blender/gpu/intern/gpu_shader_shared_utils.h116
-rw-r--r--source/blender/gpu/intern/gpu_state.cc11
-rw-r--r--source/blender/gpu/intern/gpu_state_private.hh10
-rw-r--r--source/blender/gpu/intern/gpu_texture.cc22
-rw-r--r--source/blender/gpu/intern/gpu_texture_private.hh82
-rw-r--r--source/blender/gpu/intern/gpu_uniform_buffer.cc8
-rw-r--r--source/blender/gpu/intern/gpu_uniform_buffer_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.cc37
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer_private.hh26
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.cc27
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c35
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc24
-rw-r--r--source/blender/gpu/opengl/gl_backend.hh20
-rw-r--r--source/blender/gpu/opengl/gl_batch.cc5
-rw-r--r--source/blender/gpu/opengl/gl_batch.hh27
-rw-r--r--source/blender/gpu/opengl/gl_context.hh22
-rw-r--r--source/blender/gpu/opengl/gl_debug.cc1
-rw-r--r--source/blender/gpu/opengl/gl_debug.hh12
-rw-r--r--source/blender/gpu/opengl/gl_debug_layer.cc5
-rw-r--r--source/blender/gpu/opengl/gl_drawlist.cc2
-rw-r--r--source/blender/gpu/opengl/gl_drawlist.hh4
-rw-r--r--source/blender/gpu/opengl/gl_framebuffer.cc4
-rw-r--r--source/blender/gpu/opengl/gl_framebuffer.hh14
-rw-r--r--source/blender/gpu/opengl/gl_immediate.hh10
-rw-r--r--source/blender/gpu/opengl/gl_index_buffer.cc10
-rw-r--r--source/blender/gpu/opengl/gl_index_buffer.hh8
-rw-r--r--source/blender/gpu/opengl/gl_query.hh4
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc523
-rw-r--r--source/blender/gpu/opengl/gl_shader.hh29
-rw-r--r--source/blender/gpu/opengl/gl_shader_interface.cc159
-rw-r--r--source/blender/gpu/opengl/gl_shader_interface.hh2
-rw-r--r--source/blender/gpu/opengl/gl_state.cc5
-rw-r--r--source/blender/gpu/opengl/gl_state.hh50
-rw-r--r--source/blender/gpu/opengl/gl_texture.cc22
-rw-r--r--source/blender/gpu/opengl/gl_texture.hh35
-rw-r--r--source/blender/gpu/opengl/gl_uniform_buffer.hh4
-rw-r--r--source/blender/gpu/opengl/gl_vertex_array.cc2
-rw-r--r--source/blender/gpu/opengl/gl_vertex_array.hh10
-rw-r--r--source/blender/gpu/opengl/gl_vertex_buffer.cc16
-rw-r--r--source/blender/gpu/opengl/gl_vertex_buffer.hh17
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_area_borders_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_frag.glsl30
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl38
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl19
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl26
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl44
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl98
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl5
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl76
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl28
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_vert.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl15
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl5
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl21
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl33
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_vert.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_checker_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_geometry.glsl5
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl138
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_keyframe_shape_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl18
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl33
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl17
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl17
-rw-r--r--source/blender/gpu/shaders/infos/gpu_clip_planes_info.hh (renamed from source/blender/editors/space_node/node_toolbar.cc)24
-rw-r--r--source/blender/gpu/shaders/infos/gpu_interface_info.hh36
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_area_borders_info.hh39
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_checker_info.hh35
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_diag_stripes_info.hh36
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_flat_color_info.hh37
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_color_info.hh30
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_desaturate_color_info.hh31
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_info.hh39
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_multi_rect_color_info.hh13
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_merge_info.hh39
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh36
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_rect_color_info.hh37
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_shuffle_color_info.hh31
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_line_dashed_uniform_color_info.hh34
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_nodelink_info.hh72
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_aa_info.hh36
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_outline_aa_info.hh38
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_point_varying_size_varying_color_info.hh36
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_smooth_color_info.hh36
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_uniform_color_info.hh34
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_depth_only_info.hh37
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_flat_color_info.hh40
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_image_modulate_alpha_info.hh37
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_line_dashed_uniform_color_info.hh34
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh60
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh32
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_smooth_color_info.hh40
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh38
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_gpencil_stroke_info.hh50
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh38
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_keyframe_shape_info.hh46
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_simple_lighting_info.hh40
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_text_info.hh45
-rw-r--r--source/blender/gpu/shaders/infos/gpu_srgb_to_framebuffer_space_info.hh27
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl33
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl11
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl11
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl147
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl13
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl3
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl40
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl8
-rw-r--r--source/blender/gpu/tests/gpu_shader_builtin_test.cc21
-rw-r--r--source/blender/gpu/tests/gpu_testing.cc1
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp15
-rw-r--r--source/blender/imbuf/CMakeLists.txt1
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h222
-rw-r--r--source/blender/imbuf/IMB_imbuf.h277
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h29
-rw-r--r--source/blender/imbuf/IMB_metadata.h5
-rw-r--r--source/blender/imbuf/IMB_moviecache.h5
-rw-r--r--source/blender/imbuf/IMB_thumbs.h39
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h129
-rw-r--r--source/blender/imbuf/intern/IMB_filter.h3
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c15
-rw-r--r--source/blender/imbuf/intern/anim_movie.c254
-rw-r--r--source/blender/imbuf/intern/bmp.c4
-rw-r--r--source/blender/imbuf/intern/cache.c2
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.c4
-rw-r--r--source/blender/imbuf/intern/colormanagement.c61
-rw-r--r--source/blender/imbuf/intern/colormanagement_inline.c12
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.cpp18
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.h18
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.cpp5
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.h5
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.cpp2
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.h7
-rw-r--r--source/blender/imbuf/intern/dds/FlipDXT.cpp23
-rw-r--r--source/blender/imbuf/intern/dds/FlipDXT.h15
-rw-r--r--source/blender/imbuf/intern/dds/Stream.cpp25
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.cpp9
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.h2
-rw-r--r--source/blender/imbuf/intern/divers.c29
-rw-r--r--source/blender/imbuf/intern/filter.c8
-rw-r--r--source/blender/imbuf/intern/imageprocess.c188
-rw-r--r--source/blender/imbuf/intern/indexer.c140
-rw-r--r--source/blender/imbuf/intern/iris.c12
-rw-r--r--source/blender/imbuf/intern/jp2.c16
-rw-r--r--source/blender/imbuf/intern/jpeg.c5
-rw-r--r--source/blender/imbuf/intern/moviecache.c39
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.cpp2
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.h2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp31
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.h6
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_multi.h29
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_stub.cpp2
-rw-r--r--source/blender/imbuf/intern/png.c4
-rw-r--r--source/blender/imbuf/intern/radiance_hdr.c31
-rw-r--r--source/blender/imbuf/intern/readimage.c2
-rw-r--r--source/blender/imbuf/intern/rectop.c35
-rw-r--r--source/blender/imbuf/intern/rotate.c62
-rw-r--r--source/blender/imbuf/intern/scaling.c11
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c2
-rw-r--r--source/blender/imbuf/intern/thumbs.c3
-rw-r--r--source/blender/imbuf/intern/tiff.c40
-rw-r--r--source/blender/imbuf/intern/transform.cc604
-rw-r--r--source/blender/imbuf/intern/util.c2
-rw-r--r--source/blender/imbuf/intern/util_gpu.c5
-rw-r--r--source/blender/io/CMakeLists.txt1
-rw-r--r--source/blender/io/alembic/ABC_alembic.h10
-rw-r--r--source/blender/io/alembic/exporter/abc_archive.cc2
-rw-r--r--source/blender/io/alembic/exporter/abc_subdiv_disabler.cc2
-rw-r--r--source/blender/io/alembic/exporter/abc_subdiv_disabler.h4
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_hair.cc33
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_mesh.cc72
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_points.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_axis_conversion.cc4
-rw-r--r--source/blender/io/alembic/intern/abc_axis_conversion.h17
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.cc91
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.h18
-rw-r--r--source/blender/io/alembic/intern/abc_reader_archive.cc49
-rw-r--r--source/blender/io/alembic/intern/abc_reader_archive.h10
-rw-r--r--source/blender/io/alembic/intern/abc_reader_curves.cc6
-rw-r--r--source/blender/io/alembic/intern/abc_reader_curves.h11
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc130
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.h10
-rw-r--r--source/blender/io/alembic/intern/abc_reader_object.cc26
-rw-r--r--source/blender/io/alembic/intern/abc_reader_object.h11
-rw-r--r--source/blender/io/alembic/intern/abc_reader_points.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_reader_points.h2
-rw-r--r--source/blender/io/alembic/intern/abc_util.cc9
-rw-r--r--source/blender/io/alembic/intern/abc_util.h11
-rw-r--r--source/blender/io/alembic/intern/alembic_capi.cc24
-rw-r--r--source/blender/io/avi/intern/avi.c4
-rw-r--r--source/blender/io/avi/intern/avi_mjpeg.c4
-rw-r--r--source/blender/io/avi/intern/avi_rgb.c2
-rw-r--r--source/blender/io/collada/AnimationExporter.cpp29
-rw-r--r--source/blender/io/collada/AnimationExporter.h48
-rw-r--r--source/blender/io/collada/AnimationImporter.cpp33
-rw-r--r--source/blender/io/collada/AnimationImporter.h58
-rw-r--r--source/blender/io/collada/ArmatureExporter.cpp2
-rw-r--r--source/blender/io/collada/ArmatureExporter.h8
-rw-r--r--source/blender/io/collada/ArmatureImporter.cpp15
-rw-r--r--source/blender/io/collada/ArmatureImporter.h19
-rw-r--r--source/blender/io/collada/BCAnimationCurve.h16
-rw-r--r--source/blender/io/collada/BCAnimationSampler.cpp11
-rw-r--r--source/blender/io/collada/BCAnimationSampler.h14
-rw-r--r--source/blender/io/collada/BCMath.cpp2
-rw-r--r--source/blender/io/collada/BCMath.h22
-rw-r--r--source/blender/io/collada/BCSampleData.cpp1
-rw-r--r--source/blender/io/collada/BCSampleData.h3
-rw-r--r--source/blender/io/collada/BlenderContext.cpp6
-rw-r--r--source/blender/io/collada/BlenderContext.h6
-rw-r--r--source/blender/io/collada/ControllerExporter.cpp3
-rw-r--r--source/blender/io/collada/ControllerExporter.h6
-rw-r--r--source/blender/io/collada/DocumentImporter.cpp58
-rw-r--r--source/blender/io/collada/DocumentImporter.h60
-rw-r--r--source/blender/io/collada/GeometryExporter.cpp7
-rw-r--r--source/blender/io/collada/GeometryExporter.h8
-rw-r--r--source/blender/io/collada/Materials.cpp5
-rw-r--r--source/blender/io/collada/Materials.h1
-rw-r--r--source/blender/io/collada/MeshImporter.cpp69
-rw-r--r--source/blender/io/collada/MeshImporter.h70
-rw-r--r--source/blender/io/collada/SkinInfo.cpp14
-rw-r--r--source/blender/io/collada/SkinInfo.h26
-rw-r--r--source/blender/io/collada/collada_internal.cpp1
-rw-r--r--source/blender/io/collada/collada_internal.h1
-rw-r--r--source/blender/io/collada/collada_utils.cpp74
-rw-r--r--source/blender/io/collada/collada_utils.h75
-rw-r--r--source/blender/io/common/IO_abstract_hierarchy_iterator.h2
-rw-r--r--source/blender/io/common/intern/abstract_hierarchy_iterator.cc10
-rw-r--r--source/blender/io/gpencil/gpencil_io.h7
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_base.cc15
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_base.hh15
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_capi.cc53
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc13
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh24
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_svg.cc39
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_svg.hh57
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_import_base.hh2
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_import_svg.cc2
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_import_svg.hh4
-rw-r--r--source/blender/io/usd/intern/usd_capi_export.cc2
-rw-r--r--source/blender/io/usd/intern/usd_reader_curve.cc6
-rw-r--r--source/blender/io/usd/intern/usd_reader_material.cc15
-rw-r--r--source/blender/io/usd/intern/usd_reader_material.h16
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc76
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.h2
-rw-r--r--source/blender/io/usd/intern/usd_reader_nurbs.cc4
-rw-r--r--source/blender/io/usd/intern/usd_reader_stage.cc10
-rw-r--r--source/blender/io/usd/intern/usd_reader_stage.h14
-rw-r--r--source/blender/io/usd/intern/usd_reader_xform.h2
-rw-r--r--source/blender/io/usd/intern/usd_writer_abstract.cc3
-rw-r--r--source/blender/io/usd/intern/usd_writer_abstract.h14
-rw-r--r--source/blender/io/usd/intern/usd_writer_mesh.cc56
-rw-r--r--source/blender/io/usd/usd.h4
-rw-r--r--source/blender/io/wavefront_obj/CMakeLists.txt84
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.cc34
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.h97
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc521
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh217
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_io.hh353
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc468
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh226
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc360
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh104
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc105
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh72
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_exporter.cc291
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_exporter.hh101
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc430
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh149
-rw-r--r--source/blender/makesdna/DNA_ID.h47
-rw-r--r--source/blender/makesdna/DNA_action_types.h10
-rw-r--r--source/blender/makesdna/DNA_anim_types.h2
-rw-r--r--source/blender/makesdna/DNA_armature_types.h4
-rw-r--r--source/blender/makesdna/DNA_asset_types.h7
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h6
-rw-r--r--source/blender/makesdna/DNA_brush_types.h2
-rw-r--r--source/blender/makesdna/DNA_cachefile_types.h19
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h4
-rw-r--r--source/blender/makesdna/DNA_curve_defaults.h2
-rw-r--r--source/blender/makesdna/DNA_curve_types.h13
-rw-r--r--source/blender/makesdna/DNA_curveprofile_types.h7
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h11
-rw-r--r--source/blender/makesdna/DNA_defaults.h8
-rw-r--r--source/blender/makesdna/DNA_effect_types.h2
-rw-r--r--source/blender/makesdna/DNA_fileglobal_types.h2
-rw-r--r--source/blender/makesdna/DNA_fluid_types.h4
-rw-r--r--source/blender/makesdna/DNA_genfile.h68
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_defaults.h30
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h76
-rw-r--r--source/blender/makesdna/DNA_gpu_types.h2
-rw-r--r--source/blender/makesdna/DNA_image_types.h17
-rw-r--r--source/blender/makesdna/DNA_layer_types.h2
-rw-r--r--source/blender/makesdna/DNA_lightprobe_types.h2
-rw-r--r--source/blender/makesdna/DNA_lineart_types.h5
-rw-r--r--source/blender/makesdna/DNA_material_types.h2
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h286
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h32
-rw-r--r--source/blender/makesdna/DNA_meta_types.h4
-rw-r--r--source/blender/makesdna/DNA_modifier_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h298
-rw-r--r--source/blender/makesdna/DNA_movieclip_defaults.h28
-rw-r--r--source/blender/makesdna/DNA_movieclip_types.h10
-rw-r--r--source/blender/makesdna/DNA_nla_types.h4
-rw-r--r--source/blender/makesdna/DNA_node_types.h386
-rw-r--r--source/blender/makesdna/DNA_object_force_types.h4
-rw-r--r--source/blender/makesdna/DNA_object_types.h74
-rw-r--r--source/blender/makesdna/DNA_outliner_types.h6
-rw-r--r--source/blender/makesdna/DNA_particle_types.h47
-rw-r--r--source/blender/makesdna/DNA_pointcache_types.h2
-rw-r--r--source/blender/makesdna/DNA_pointcloud_types.h2
-rw-r--r--source/blender/makesdna/DNA_rigidbody_types.h16
-rw-r--r--source/blender/makesdna/DNA_scene_defaults.h6
-rw-r--r--source/blender/makesdna/DNA_scene_types.h80
-rw-r--r--source/blender/makesdna/DNA_screen_types.h23
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h117
-rw-r--r--source/blender/makesdna/DNA_shader_fx_types.h2
-rw-r--r--source/blender/makesdna/DNA_simulation_types.h2
-rw-r--r--source/blender/makesdna/DNA_space_defaults.h67
-rw-r--r--source/blender/makesdna/DNA_space_types.h249
-rw-r--r--source/blender/makesdna/DNA_texture_types.h18
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h44
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h51
-rw-r--r--source/blender/makesdna/DNA_view2d_types.h18
-rw-r--r--source/blender/makesdna/DNA_view3d_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_view3d_enums.h3
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h33
-rw-r--r--source/blender/makesdna/DNA_volume_types.h22
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h49
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h4
-rw-r--r--source/blender/makesdna/DNA_xr_types.h15
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt1
-rw-r--r--source/blender/makesdna/intern/dna_defaults.c22
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c67
-rw-r--r--source/blender/makesdna/intern/dna_rename_defs.h36
-rw-r--r--source/blender/makesdna/intern/dna_utils.c32
-rw-r--r--source/blender/makesdna/intern/dna_utils.h31
-rw-r--r--source/blender/makesdna/intern/makesdna.c10
-rw-r--r--source/blender/makesrna/RNA_access.h359
-rw-r--r--source/blender/makesrna/RNA_define.h54
-rw-r--r--source/blender/makesrna/RNA_enum_items.h10
-rw-r--r--source/blender/makesrna/RNA_enum_types.h10
-rw-r--r--source/blender/makesrna/RNA_types.h5
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt6
-rw-r--r--source/blender/makesrna/intern/makesrna.c25
-rw-r--r--source/blender/makesrna/intern/rna_ID.c40
-rw-r--r--source/blender/makesrna/intern/rna_access.c214
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c94
-rw-r--r--source/blender/makesrna/intern/rna_access_internal.h7
-rw-r--r--source/blender/makesrna/intern/rna_action.c114
-rw-r--r--source/blender/makesrna/intern/rna_animation.c10
-rw-r--r--source/blender/makesrna/intern/rna_animviz.c8
-rw-r--r--source/blender/makesrna/intern/rna_armature.c8
-rw-r--r--source/blender/makesrna/intern/rna_armature_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_asset.c67
-rw-r--r--source/blender/makesrna/intern/rna_attribute.c26
-rw-r--r--source/blender/makesrna/intern/rna_brush.c2
-rw-r--r--source/blender/makesrna/intern/rna_cachefile.c167
-rw-r--r--source/blender/makesrna/intern/rna_cloth.c19
-rw-r--r--source/blender/makesrna/intern/rna_color.c5
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c12
-rw-r--r--source/blender/makesrna/intern/rna_curve.c22
-rw-r--r--source/blender/makesrna/intern/rna_define.c36
-rw-r--r--source/blender/makesrna/intern/rna_depsgraph.c4
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c1
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c3
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c1
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c3
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c350
-rw-r--r--source/blender/makesrna/intern/rna_image.c2
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c52
-rw-r--r--source/blender/makesrna/intern/rna_internal.h47
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h18
-rw-r--r--source/blender/makesrna/intern/rna_key.c2
-rw-r--r--source/blender/makesrna/intern/rna_layer.c2
-rw-r--r--source/blender/makesrna/intern/rna_light.c2
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c12
-rw-r--r--source/blender/makesrna/intern/rna_main.c15
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c8
-rw-r--r--source/blender/makesrna/intern/rna_mask.c3
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c202
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c102
-rw-r--r--source/blender/makesrna/intern/rna_nla.c13
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c1158
-rw-r--r--source/blender/makesrna/intern/rna_object.c95
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c86
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c35
-rw-r--r--source/blender/makesrna/intern/rna_palette.c13
-rw-r--r--source/blender/makesrna/intern/rna_particle.c3
-rw-r--r--source/blender/makesrna/intern/rna_pose.c31
-rw-r--r--source/blender/makesrna/intern/rna_render.c17
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c9
-rw-r--r--source/blender/makesrna/intern/rna_rna.c23
-rw-r--r--source/blender/makesrna/intern/rna_scene.c61
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c3
-rw-r--r--source/blender/makesrna/intern/rna_screen.c1
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c2
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c145
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c19
-rw-r--r--source/blender/makesrna/intern/rna_space.c338
-rw-r--r--source/blender/makesrna/intern/rna_space_api.c15
-rw-r--r--source/blender/makesrna/intern/rna_texture.c2
-rw-r--r--source/blender/makesrna/intern/rna_texture_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c11
-rw-r--r--source/blender/makesrna/intern/rna_ui.c10
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c70
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c117
-rw-r--r--source/blender/makesrna/intern/rna_vfont.c2
-rw-r--r--source/blender/makesrna/intern/rna_volume.c54
-rw-r--r--source/blender/makesrna/intern/rna_wm.c163
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c13
-rw-r--r--source/blender/makesrna/intern/rna_world.c1
-rw-r--r--source/blender/makesrna/intern/rna_xr.c379
-rw-r--r--source/blender/modifiers/CMakeLists.txt4
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h4
-rw-r--r--source/blender/modifiers/MOD_nodes.h5
-rw-r--r--source/blender/modifiers/intern/MOD_array.c44
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.cc31
-rw-r--r--source/blender/modifiers/intern/MOD_build.c4
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c12
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c2
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c2
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c2
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c9
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c4
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c9
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c2
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c4
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c2
-rw-r--r--source/blender/modifiers/intern/MOD_fluid.c46
-rw-r--r--source/blender/modifiers/intern/MOD_mask.cc68
-rw-r--r--source/blender/modifiers/intern/MOD_mesh_to_volume.cc4
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_util.h53
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c2
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c95
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c10
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc449
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc818
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c47
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c4
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c2
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c2
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c6
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c2
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c2
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_extrude.c62
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c38
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c100
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c2
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c16
-rw-r--r--source/blender/modifiers/intern/MOD_ui_common.c25
-rw-r--r--source/blender/modifiers/intern/MOD_ui_common.h15
-rw-r--r--source/blender/modifiers/intern/MOD_util.c10
-rw-r--r--source/blender/modifiers/intern/MOD_util.h12
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c4
-rw-r--r--source/blender/modifiers/intern/MOD_volume_displace.cc7
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c8
-rw-r--r--source/blender/modifiers/intern/MOD_weighted_normal.c27
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c21
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.h52
-rw-r--r--source/blender/modifiers/intern/MOD_weld.c2079
-rw-r--r--source/blender/modifiers/intern/MOD_weld.cc239
-rw-r--r--source/blender/nodes/CMakeLists.txt370
-rw-r--r--source/blender/nodes/NOD_common.h6
-rw-r--r--source/blender/nodes/NOD_composite.h71
-rw-r--r--source/blender/nodes/NOD_derived_node_tree.hh100
-rw-r--r--source/blender/nodes/NOD_function.h10
-rw-r--r--source/blender/nodes/NOD_geometry.h71
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh107
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh95
-rw-r--r--source/blender/nodes/NOD_math_functions.hh93
-rw-r--r--source/blender/nodes/NOD_multi_function.hh60
-rw-r--r--source/blender/nodes/NOD_node_declaration.hh295
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh104
-rw-r--r--source/blender/nodes/NOD_shader.h23
-rw-r--r--source/blender/nodes/NOD_socket_declarations.hh335
-rw-r--r--source/blender/nodes/NOD_socket_declarations_geometry.hh55
-rw-r--r--source/blender/nodes/NOD_socket_search_link.hh151
-rw-r--r--source/blender/nodes/NOD_static_types.h114
-rw-r--r--source/blender/nodes/NOD_texture.h16
-rw-r--r--source/blender/nodes/composite/CMakeLists.txt163
-rw-r--r--source/blender/nodes/composite/node_composite_tree.cc87
-rw-r--r--source/blender/nodes/composite/node_composite_util.cc10
-rw-r--r--source/blender/nodes/composite/node_composite_util.hh8
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_alpha_over.cc (renamed from source/blender/nodes/composite/nodes/node_composite_alphaOver.cc)39
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_antialiasing.cc41
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc47
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_blur.cc76
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehblur.cc44
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehimage.cc42
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_boxmask.cc50
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_brightness.cc35
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_channelMatte.cc64
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_channel_matte.cc114
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc60
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_chroma_matte.cc84
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorMatte.cc60
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorSpill.cc60
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_color_matte.cc85
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_color_spill.cc115
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorbalance.cc119
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc246
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_common.cc12
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_composite.cc32
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_convert_color_space.cc83
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cornerpin.cc50
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_crop.cc57
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc102
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_curves.cc83
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_defocus.cc81
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_denoise.cc57
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_despeckle.cc44
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_diffMatte.cc58
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_diff_matte.cc75
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_dilate.cc45
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_directionalblur.cc51
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_displace.cc37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc58
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_distance_matte.cc83
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc50
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_double_edge_mask.cc67
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc49
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_exposure.cc18
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_filter.cc42
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_flip.cc34
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_gamma.cc23
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_glare.cc73
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_hue_sat_val.cc (renamed from source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc)28
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_huecorrect.cc22
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_id_mask.cc (renamed from source/blender/nodes/composite/nodes/node_composite_idMask.cc)35
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.cc145
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_inpaint.cc29
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_invert.cc36
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_keying.cc64
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc60
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_lensdist.cc52
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_levels.cc32
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_luma_matte.cc (renamed from source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc)47
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapRange.cc48
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapValue.cc51
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_map_range.cc64
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_map_uv.cc (renamed from source/blender/nodes/composite/nodes/node_composite_mapUV.cc)38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_map_value.cc82
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mask.cc61
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_math.cc33
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mixrgb.cc24
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_movieclip.cc83
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc63
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normal.cc35
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normalize.cc21
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_output_file.cc (renamed from source/blender/nodes/composite/nodes/node_composite_outputFile.cc)191
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_pixelate.cc20
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc85
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_posterize.cc29
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_premulkey.cc34
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rgb.cc14
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rotate.cc42
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_scale.cc60
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_scene_time.cc39
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc70
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc70
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc68
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc77
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc77
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc (renamed from source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc)66
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc78
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_setalpha.cc41
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_split_viewer.cc (renamed from source/blender/nodes/composite/nodes/node_composite_splitViewer.cc)48
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc57
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sunbeams.cc44
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switch.cc47
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switchview.cc37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_texture.cc21
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_tonemap.cc50
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_trackpos.cc79
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_transform.cc49
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_translate.cc46
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc (renamed from source/blender/nodes/composite/nodes/node_composite_valToRgb.cc)58
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_value.cc14
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_vecBlur.cc54
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_vec_blur.cc86
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_viewer.cc57
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_zcombine.cc38
-rw-r--r--source/blender/nodes/function/CMakeLists.txt75
-rw-r--r--source/blender/nodes/function/node_function_util.cc10
-rw-r--r--source/blender/nodes/function/node_function_util.hh5
-rw-r--r--source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc24
-rw-r--r--source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc224
-rw-r--r--source/blender/nodes/function/nodes/node_fn_boolean_math.cc103
-rw-r--r--source/blender/nodes/function/nodes/node_fn_compare.cc552
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_compare.cc120
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_to_int.cc49
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_bool.cc66
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_color.cc67
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_int.cc66
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_special_characters.cc19
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_string.cc31
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_vector.cc33
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_value.cc141
-rw-r--r--source/blender/nodes/function/nodes/node_fn_replace_string.cc68
-rw-r--r--source/blender/nodes/function/nodes/node_fn_rotate_euler.cc142
-rw-r--r--source/blender/nodes/function/nodes/node_fn_slice_string.cc (renamed from source/blender/nodes/function/nodes/node_fn_string_substring.cc)38
-rw-r--r--source/blender/nodes/function/nodes/node_fn_string_length.cc26
-rw-r--r--source/blender/nodes/function/nodes/node_fn_value_to_string.cc28
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt290
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc16
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc47
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh70
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc)65
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc)87
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc)46
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc)66
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc)103
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc)45
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc)72
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc)56
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc)90
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc)67
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc)87
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc)48
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc)131
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc)31
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc)56
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc)68
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc)126
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc)115
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc)44
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc)27
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc)44
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc)41
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc)41
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc)64
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc)181
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc)125
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc)30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc80
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc)94
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc)76
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc)60
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc)51
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc)40
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc)47
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc)70
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc)84
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc)26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc)41
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc176
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc430
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc149
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc154
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc27
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc253
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc63
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc178
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_collection_info.cc87
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_common.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc147
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc37
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc105
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc169
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_length.cc22
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc206
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc391
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc116
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc127
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc80
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc61
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc179
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc74
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc84
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc157
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc91
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc149
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc326
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc434
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc366
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc62
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc414
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc376
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc1399
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc191
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc931
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc97
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc1365
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc193
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc114
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc55
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_image_texture.cc428
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc128
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc44
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_id.cc44
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_index.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material.cc22
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc44
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc222
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc93
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc186
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc96
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc158
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc157
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc155
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_normal.cc273
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_position.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_radius.cc44
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc50
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc44
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc44
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc163
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc45
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc62
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc201
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc137
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc356
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_assign.cc97
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_replace.cc25
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_selection.cc84
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc108
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc66
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc1099
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc104
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc138
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc194
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc37
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc178
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc60
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc71
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc70
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_object_info.cc106
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc284
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_proximity.cc76
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc462
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc36
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc119
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc485
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc98
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_components.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc117
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc181
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc82
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc78
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_id.cc94
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material.cc134
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc77
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc83
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc133
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc77
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc78
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc95
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_join.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc99
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc166
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_switch.cc326
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc842
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc226
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc84
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc95
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_viewer.cc131
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc197
-rw-r--r--source/blender/nodes/intern/derived_node_tree.cc116
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc115
-rw-r--r--source/blender/nodes/intern/math_functions.cc12
-rw-r--r--source/blender/nodes/intern/node_common.cc (renamed from source/blender/nodes/intern/node_common.c)415
-rw-r--r--source/blender/nodes/intern/node_common.h10
-rw-r--r--source/blender/nodes/intern/node_declaration.cc22
-rw-r--r--source/blender/nodes/intern/node_exec.cc9
-rw-r--r--source/blender/nodes/intern/node_exec.h2
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc116
-rw-r--r--source/blender/nodes/intern/node_multi_function.cc9
-rw-r--r--source/blender/nodes/intern/node_socket.cc178
-rw-r--r--source/blender/nodes/intern/node_socket_declarations.cc291
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc163
-rw-r--r--source/blender/nodes/intern/node_util.c260
-rw-r--r--source/blender/nodes/intern/node_util.h68
-rw-r--r--source/blender/nodes/intern/socket_search_link.cc199
-rw-r--r--source/blender/nodes/shader/CMakeLists.txt174
-rw-r--r--source/blender/nodes/shader/node_shader_tree.cc (renamed from source/blender/nodes/shader/node_shader_tree.c)282
-rw-r--r--source/blender/nodes/shader/node_shader_util.cc (renamed from source/blender/nodes/shader/node_shader_util.c)62
-rw-r--r--source/blender/nodes/shader/node_shader_util.hh (renamed from source/blender/nodes/shader/node_shader_util.h)77
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_add_shader.cc (renamed from source/blender/nodes/shader/nodes/node_shader_add_shader.c)34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc (renamed from source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c)50
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.cc (renamed from source/blender/nodes/shader/nodes/node_shader_attribute.c)50
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_background.cc (renamed from source/blender/nodes/shader/nodes/node_shader_background.c)35
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bevel.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bevel.c)42
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_blackbody.cc (renamed from source/blender/nodes/shader/nodes/node_shader_blackbody.c)33
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_brightness.cc (renamed from source/blender/nodes/shader/nodes/node_shader_brightness.c)36
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c80
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc96
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c)44
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c96
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc85
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c)52
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c)60
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c135
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc145
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c195
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc259
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c)47
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c)57
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c)38
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c)36
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c)44
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bump.c)56
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_camera.cc (renamed from source/blender/nodes/shader/nodes/node_shader_camera.c)30
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.cc39
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_color_ramp.cc (renamed from source/blender/nodes/shader/nodes/node_shader_valToRgb.cc)96
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_common.c270
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_common.cc130
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.cc219
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_displacement.cc (renamed from source/blender/nodes/shader/nodes/node_shader_displacement.c)39
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_eevee_specular.c103
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc97
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_emission.cc (renamed from source/blender/nodes/shader/nodes/node_shader_emission.c)38
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_fresnel.cc (renamed from source/blender/nodes/shader/nodes/node_shader_fresnel.c)41
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_gamma.c73
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_gamma.cc57
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geometry.cc (renamed from source/blender/nodes/shader/nodes/node_shader_geometry.c)48
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hair_info.cc (renamed from source/blender/nodes/shader/nodes/node_shader_hair_info.c)39
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_holdout.cc (renamed from source/blender/nodes/shader/nodes/node_shader_holdout.c)32
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hueSatVal.c99
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc61
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ies_light.c53
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ies_light.cc74
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_invert.c78
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_invert.cc57
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_layer_weight.cc (renamed from source/blender/nodes/shader/nodes/node_shader_layer_weight.c)44
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_falloff.cc (renamed from source/blender/nodes/shader/nodes/node_shader_light_falloff.c)40
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_path.c62
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_path.cc64
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.cc508
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.c77
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.cc110
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.cc81
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc (renamed from source/blender/nodes/shader/nodes/node_shader_mixRgb.cc)57
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix_shader.cc (renamed from source/blender/nodes/shader/nodes/node_shader_mix_shader.c)36
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal.cc (renamed from source/blender/nodes/shader/nodes/node_shader_normal.c)55
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.cc (renamed from source/blender/nodes/shader/nodes/node_shader_normal_map.c)76
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_object_info.cc (renamed from source/blender/nodes/shader/nodes/node_shader_object_info.c)32
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_aov.cc (renamed from source/blender/nodes/shader/nodes/node_shader_output_aov.c)42
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_light.cc (renamed from source/blender/nodes/shader/nodes/node_shader_output_light.c)28
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_linestyle.c45
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc72
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_material.c85
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_material.cc83
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_world.cc (renamed from source/blender/nodes/shader/nodes/node_shader_output_world.c)31
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_particle_info.cc (renamed from source/blender/nodes/shader/nodes/node_shader_particle_info.c)48
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_point_info.cc54
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_rgb.cc (renamed from source/blender/nodes/shader/nodes/node_shader_rgb.c)25
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc58
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_script.c70
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_script.cc112
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c118
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc96
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc (renamed from source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc)88
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc (renamed from source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc)58
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc (renamed from source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c)34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_squeeze.c71
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_squeeze.cc58
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c76
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc113
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tangent.cc (renamed from source/blender/nodes/shader/nodes/node_shader_tangent.c)62
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.c181
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.cc306
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.c90
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.cc137
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_coord.cc (renamed from source/blender/nodes/shader/nodes/node_shader_tex_coord.c)70
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.cc (renamed from source/blender/nodes/shader/nodes/node_shader_tex_environment.c)40
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc141
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.cc (renamed from source/blender/nodes/shader/nodes/node_shader_tex_image.c)61
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.c84
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.cc204
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc482
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.cc88
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c82
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.cc131
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_sky.cc (renamed from source/blender/nodes/shader/nodes/node_shader_tex_sky.c)91
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc1284
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.c101
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.cc250
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc171
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc (renamed from source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c)32
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uvmap.cc (renamed from source/blender/nodes/shader/nodes/node_shader_uvmap.c)50
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_value.cc24
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc (renamed from source/blender/nodes/shader/nodes/node_shader_vector_displacement.c)38
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_math.cc128
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc54
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_transform.cc (renamed from source/blender/nodes/shader/nodes/node_shader_vectTransform.c)100
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vertex_color.cc (renamed from source/blender/nodes/shader/nodes/node_shader_vertex_color.c)57
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc (renamed from source/blender/nodes/shader/nodes/node_shader_volume_absorption.c)35
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_info.cc (renamed from source/blender/nodes/shader/nodes/node_shader_volume_info.c)30
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_principled.cc (renamed from source/blender/nodes/shader/nodes/node_shader_volume_principled.c)76
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc (renamed from source/blender/nodes/shader/nodes/node_shader_volume_scatter.c)41
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_wavelength.cc (renamed from source/blender/nodes/shader/nodes/node_shader_wavelength.c)33
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_wireframe.cc (renamed from source/blender/nodes/shader/nodes/node_shader_wireframe.c)40
-rw-r--r--source/blender/nodes/texture/CMakeLists.txt89
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c21
-rw-r--r--source/blender/nodes/texture/node_texture_util.c25
-rw-r--r--source/blender/nodes/texture/node_texture_util.h10
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_at.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_bricks.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_checker.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_common.c6
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_compose.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_coord.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_curves.c6
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_decompose.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_distance.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_hueSatVal.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_image.c6
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_invert.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_math.c5
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_mixRgb.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_output.c11
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_proc.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_rotate.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_scale.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_texture.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_translate.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_valToNor.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_valToRgb.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_viewer.c14
-rw-r--r--source/blender/python/BPY_extern.h38
-rw-r--r--source/blender/python/BPY_extern_python.h2
-rw-r--r--source/blender/python/BPY_extern_run.h136
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.c3
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.h3
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c19
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.h37
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c7
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.h21
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.c1
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.h1
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_select.c3
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_select.h3
-rw-r--r--source/blender/python/generic/bgl.c7
-rw-r--r--source/blender/python/generic/bgl.h9
-rw-r--r--source/blender/python/generic/bl_math_py_api.c40
-rw-r--r--source/blender/python/generic/blf_py_api.c7
-rw-r--r--source/blender/python/generic/bpy_threads.c2
-rw-r--r--source/blender/python/generic/idprop_py_api.c9
-rw-r--r--source/blender/python/generic/idprop_py_api.h9
-rw-r--r--source/blender/python/generic/idprop_py_ui_api.c4
-rw-r--r--source/blender/python/generic/py_capi_rna.c24
-rw-r--r--source/blender/python/generic/py_capi_rna.h24
-rw-r--r--source/blender/python/generic/py_capi_utils.c67
-rw-r--r--source/blender/python/generic/py_capi_utils.h113
-rw-r--r--source/blender/python/generic/python_utildefines.h12
-rw-r--r--source/blender/python/gpu/gpu_py.c1
-rw-r--r--source/blender/python/gpu/gpu_py_buffer.c7
-rw-r--r--source/blender/python/gpu/gpu_py_buffer.h11
-rw-r--r--source/blender/python/gpu/gpu_py_framebuffer.c2
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c50
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.h4
-rw-r--r--source/blender/python/gpu/gpu_py_select.c1
-rw-r--r--source/blender/python/gpu/gpu_py_texture.c3
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_buffer.c2
-rw-r--r--source/blender/python/intern/bpy.c85
-rw-r--r--source/blender/python/intern/bpy.h2
-rw-r--r--source/blender/python/intern/bpy_app_translations.c4
-rw-r--r--source/blender/python/intern/bpy_capi_utils.c3
-rw-r--r--source/blender/python/intern/bpy_capi_utils.h12
-rw-r--r--source/blender/python/intern/bpy_driver.c42
-rw-r--r--source/blender/python/intern/bpy_driver.h8
-rw-r--r--source/blender/python/intern/bpy_interface.c23
-rw-r--r--source/blender/python/intern/bpy_interface_run.c34
-rw-r--r--source/blender/python/intern/bpy_library_load.c266
-rw-r--r--source/blender/python/intern/bpy_msgbus.c10
-rw-r--r--source/blender/python/intern/bpy_operator.c19
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.c8
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.h8
-rw-r--r--source/blender/python/intern/bpy_props.c28
-rw-r--r--source/blender/python/intern/bpy_props.h4
-rw-r--r--source/blender/python/intern/bpy_rna.c37
-rw-r--r--source/blender/python/intern/bpy_rna.h7
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c4
-rw-r--r--source/blender/python/intern/bpy_rna_array.c5
-rw-r--r--source/blender/python/intern/bpy_rna_callback.c19
-rw-r--r--source/blender/python/intern/bpy_rna_data.c2
-rw-r--r--source/blender/python/intern/bpy_rna_driver.c3
-rw-r--r--source/blender/python/intern/bpy_rna_driver.h3
-rw-r--r--source/blender/python/intern/bpy_rna_gizmo.c231
-rw-r--r--source/blender/python/intern/bpy_rna_operator.c2
-rw-r--r--source/blender/python/mathutils/mathutils.c17
-rw-r--r--source/blender/python/mathutils/mathutils.h40
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.h6
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c5
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.h19
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c23
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.h18
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c2
-rw-r--r--source/blender/python/mathutils/mathutils_noise.c2
-rw-r--r--source/blender/render/CMakeLists.txt2
-rw-r--r--source/blender/render/RE_bake.h48
-rw-r--r--source/blender/render/RE_engine.h12
-rw-r--r--source/blender/render/RE_multires_bake.h3
-rw-r--r--source/blender/render/RE_pipeline.h168
-rw-r--r--source/blender/render/RE_texture.h71
-rw-r--r--source/blender/render/RE_texture_margin.h54
-rw-r--r--source/blender/render/intern/bake.c36
-rw-r--r--source/blender/render/intern/engine.c83
-rw-r--r--source/blender/render/intern/initrender.c14
-rw-r--r--source/blender/render/intern/multires_bake.c29
-rw-r--r--source/blender/render/intern/pipeline.c46
-rw-r--r--source/blender/render/intern/pipeline.h4
-rw-r--r--source/blender/render/intern/render_result.c97
-rw-r--r--source/blender/render/intern/render_result.h46
-rw-r--r--source/blender/render/intern/render_types.h2
-rw-r--r--source/blender/render/intern/texture_common.h4
-rw-r--r--source/blender/render/intern/texture_image.c4
-rw-r--r--source/blender/render/intern/texture_margin.cc555
-rw-r--r--source/blender/render/intern/texture_pointdensity.c20
-rw-r--r--source/blender/render/intern/texture_procedural.c31
-rw-r--r--source/blender/render/intern/zbuf.c7
-rw-r--r--source/blender/render/intern/zbuf.h9
-rw-r--r--source/blender/sequencer/CMakeLists.txt4
-rw-r--r--source/blender/sequencer/SEQ_add.h107
-rw-r--r--source/blender/sequencer/SEQ_animation.h41
-rw-r--r--source/blender/sequencer/SEQ_clipboard.h8
-rw-r--r--source/blender/sequencer/SEQ_edit.h55
-rw-r--r--source/blender/sequencer/SEQ_effects.h20
-rw-r--r--source/blender/sequencer/SEQ_iterator.h153
-rw-r--r--source/blender/sequencer/SEQ_prefetch.h4
-rw-r--r--source/blender/sequencer/SEQ_proxy.h3
-rw-r--r--source/blender/sequencer/SEQ_relations.h26
-rw-r--r--source/blender/sequencer/SEQ_render.h18
-rw-r--r--source/blender/sequencer/SEQ_sequencer.h72
-rw-r--r--source/blender/sequencer/SEQ_time.h44
-rw-r--r--source/blender/sequencer/SEQ_transform.h64
-rw-r--r--source/blender/sequencer/SEQ_utils.h33
-rw-r--r--source/blender/sequencer/intern/animation.c122
-rw-r--r--source/blender/sequencer/intern/clipboard.c22
-rw-r--r--source/blender/sequencer/intern/disk_cache.c699
-rw-r--r--source/blender/sequencer/intern/disk_cache.h56
-rw-r--r--source/blender/sequencer/intern/effects.c1430
-rw-r--r--source/blender/sequencer/intern/effects.h7
-rw-r--r--source/blender/sequencer/intern/image_cache.c672
-rw-r--r--source/blender/sequencer/intern/image_cache.h25
-rw-r--r--source/blender/sequencer/intern/iterator.c145
-rw-r--r--source/blender/sequencer/intern/modifier.c112
-rw-r--r--source/blender/sequencer/intern/multiview.c1
-rw-r--r--source/blender/sequencer/intern/multiview.h9
-rw-r--r--source/blender/sequencer/intern/prefetch.c23
-rw-r--r--source/blender/sequencer/intern/prefetch.h9
-rw-r--r--source/blender/sequencer/intern/proxy.c34
-rw-r--r--source/blender/sequencer/intern/proxy.h2
-rw-r--r--source/blender/sequencer/intern/render.c214
-rw-r--r--source/blender/sequencer/intern/render.h3
-rw-r--r--source/blender/sequencer/intern/sequence_lookup.c21
-rw-r--r--source/blender/sequencer/intern/sequencer.c192
-rw-r--r--source/blender/sequencer/intern/sequencer.h12
-rw-r--r--source/blender/sequencer/intern/sound.c21
-rw-r--r--source/blender/sequencer/intern/strip_add.c130
-rw-r--r--source/blender/sequencer/intern/strip_edit.c99
-rw-r--r--source/blender/sequencer/intern/strip_relations.c105
-rw-r--r--source/blender/sequencer/intern/strip_time.c130
-rw-r--r--source/blender/sequencer/intern/strip_time.h11
-rw-r--r--source/blender/sequencer/intern/strip_transform.c149
-rw-r--r--source/blender/sequencer/intern/utils.c43
-rw-r--r--source/blender/sequencer/intern/utils.h3
-rw-r--r--source/blender/shader_fx/intern/FX_ui_common.c23
-rw-r--r--source/blender/shader_fx/intern/FX_ui_common.h15
-rw-r--r--source/blender/simulation/intern/ConstrainedConjugateGradient.h8
-rw-r--r--source/blender/simulation/intern/SIM_mass_spring.cpp5
-rw-r--r--source/blender/simulation/intern/hair_volume.cpp12
-rw-r--r--source/blender/simulation/intern/implicit.h65
-rw-r--r--source/blender/simulation/intern/implicit_blender.c18
-rw-r--r--source/blender/windowmanager/CMakeLists.txt1
-rw-r--r--source/blender/windowmanager/WM_api.h731
-rw-r--r--source/blender/windowmanager/WM_keymap.h98
-rw-r--r--source/blender/windowmanager/WM_toolsystem.h22
-rw-r--r--source/blender/windowmanager/WM_types.h184
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_api.h140
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_types.h7
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo.c45
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c35
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c6
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h28
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c238
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c7
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c5
-rw-r--r--source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h42
-rw-r--r--source/blender/windowmanager/intern/wm.c28
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c8
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c593
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c12
-rw-r--r--source/blender/windowmanager/intern/wm_event_query.c55
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c611
-rw-r--r--source/blender/windowmanager/intern/wm_files.c388
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c1249
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c17
-rw-r--r--source/blender/windowmanager/intern/wm_gesture_ops.c81
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c37
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c19
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c94
-rw-r--r--source/blender/windowmanager/intern/wm_keymap_utils.c5
-rw-r--r--source/blender/windowmanager/intern/wm_menu_type.c1
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c56
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c34
-rw-r--r--source/blender/windowmanager/intern/wm_operator_utils.c7
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c274
-rw-r--r--source/blender/windowmanager/intern/wm_panel_type.c1
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c3
-rw-r--r--source/blender/windowmanager/intern/wm_splash_screen.c8
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c6
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c1
-rw-r--r--source/blender/windowmanager/intern/wm_surface.c18
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c51
-rw-r--r--source/blender/windowmanager/intern/wm_tooltip.c2
-rw-r--r--source/blender/windowmanager/intern/wm_uilist_type.c16
-rw-r--r--source/blender/windowmanager/intern/wm_window.c154
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus.c13
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h3
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c10
-rw-r--r--source/blender/windowmanager/message_bus/wm_message_bus.h55
-rw-r--r--source/blender/windowmanager/wm.h55
-rw-r--r--source/blender/windowmanager/wm_event_system.h54
-rw-r--r--source/blender/windowmanager/wm_event_types.h177
-rw-r--r--source/blender/windowmanager/wm_files.h25
-rw-r--r--source/blender/windowmanager/wm_surface.h5
-rw-r--r--source/blender/windowmanager/wm_window.h75
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr.c17
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_action.c2
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_actionmap.c45
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_draw.c256
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_intern.h67
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_operators.c1537
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c833
-rw-r--r--source/blender/windowmanager/xr/wm_xr.h3
3430 files changed, 203152 insertions, 119398 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index fbc0ec440cf..c6112344208 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -119,6 +119,7 @@ add_subdirectory(blenloader)
add_subdirectory(depsgraph)
add_subdirectory(ikplugin)
add_subdirectory(simulation)
+add_subdirectory(geometry)
add_subdirectory(gpu)
add_subdirectory(imbuf)
add_subdirectory(nodes)
@@ -131,6 +132,10 @@ add_subdirectory(functions)
add_subdirectory(makesdna)
add_subdirectory(makesrna)
+if(WITH_BLENDER_THUMBNAILER)
+ add_subdirectory(blendthumb)
+endif()
+
if(WITH_COMPOSITOR)
add_subdirectory(compositor)
endif()
@@ -158,7 +163,3 @@ endif()
if(WITH_FREESTYLE)
add_subdirectory(freestyle)
endif()
-
-if(WIN32)
- add_subdirectory(blendthumb)
-endif()
diff --git a/source/blender/blendthumb/CMakeLists.txt b/source/blender/blendthumb/CMakeLists.txt
index b42ca284ecb..e2d278255ba 100644
--- a/source/blender/blendthumb/CMakeLists.txt
+++ b/source/blender/blendthumb/CMakeLists.txt
@@ -19,23 +19,52 @@
# ***** END GPL LICENSE BLOCK *****
#-----------------------------------------------------------------------------
-include_directories(${ZLIB_INCLUDE_DIRS})
+# Shared Thumbnail Extraction Logic
+
+include_directories(
+ ../blenlib
+ ../makesdna
+ ../../../intern/guardedalloc
+)
+
+include_directories(
+ SYSTEM
+ ${ZLIB_INCLUDE_DIRS}
+)
set(SRC
- src/BlenderThumb.cpp
- src/BlendThumb.def
- src/BlendThumb.rc
- src/Dll.cpp
+ src/blendthumb.hh
+ src/blendthumb_extract.cc
+ src/blendthumb_png.cc
)
-string(APPEND CMAKE_SHARED_LINKER_FLAGS_DEBUG " /nodefaultlib:MSVCRT.lib")
+if(WIN32)
+ # -----------------------------------------------------------------------------
+ # Build `BlendThumb.dll`
-add_library(BlendThumb SHARED ${SRC})
-setup_platform_linker_flags(BlendThumb)
-target_link_libraries(BlendThumb ${ZLIB_LIBRARIES})
+ set(SRC_WIN32
+ src/blendthumb_win32.cc
+ src/blendthumb_win32.def
+ src/blendthumb_win32.rc
+ src/blendthumb_win32_dll.cc
+ )
-install(
- FILES $<TARGET_FILE:BlendThumb>
- COMPONENT Blender
- DESTINATION "."
-)
+ add_definitions(-DNOMINMAX)
+
+ add_library(BlendThumb SHARED ${SRC} ${SRC_WIN32})
+
+ target_link_libraries(BlendThumb bf_blenlib dbghelp.lib Version.lib)
+ set_target_properties(BlendThumb PROPERTIES LINK_FLAGS_DEBUG "/NODEFAULTLIB:msvcrt")
+
+else()
+ # -----------------------------------------------------------------------------
+ # Build `blender-thumbnailer` executable
+
+ set(SRC_CMD
+ src/blender_thumbnailer.cc
+ )
+
+ add_executable(blender-thumbnailer ${SRC} ${SRC_CMD})
+ target_link_libraries(blender-thumbnailer bf_blenlib)
+ target_link_libraries(blender-thumbnailer ${PTHREADS_LIBRARIES})
+endif()
diff --git a/source/blender/blendthumb/src/BlenderThumb.cpp b/source/blender/blendthumb/src/BlenderThumb.cpp
deleted file mode 100644
index 939e7bbf67c..00000000000
--- a/source/blender/blendthumb/src/BlenderThumb.cpp
+++ /dev/null
@@ -1,321 +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.
- */
-
-#include <new>
-#include <shlwapi.h>
-#include <thumbcache.h> // For IThumbnailProvider.
-
-#pragma comment(lib, "shlwapi.lib")
-
-// this thumbnail provider implements IInitializeWithStream to enable being hosted
-// in an isolated process for robustness
-
-class CBlendThumb : public IInitializeWithStream, public IThumbnailProvider {
- public:
- CBlendThumb() : _cRef(1), _pStream(NULL)
- {
- }
-
- virtual ~CBlendThumb()
- {
- if (_pStream) {
- _pStream->Release();
- }
- }
-
- // IUnknown
- IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
- {
- static const QITAB qit[] = {
- QITABENT(CBlendThumb, IInitializeWithStream),
- QITABENT(CBlendThumb, IThumbnailProvider),
- {0},
- };
- return QISearch(this, qit, riid, ppv);
- }
-
- IFACEMETHODIMP_(ULONG) AddRef()
- {
- return InterlockedIncrement(&_cRef);
- }
-
- IFACEMETHODIMP_(ULONG) Release()
- {
- ULONG cRef = InterlockedDecrement(&_cRef);
- if (!cRef) {
- delete this;
- }
- return cRef;
- }
-
- // IInitializeWithStream
- IFACEMETHODIMP Initialize(IStream *pStream, DWORD grfMode);
-
- // IThumbnailProvider
- IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha);
-
- private:
- long _cRef;
- IStream *_pStream; // provided during initialization.
-};
-
-HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv)
-{
- CBlendThumb *pNew = new (std::nothrow) CBlendThumb();
- HRESULT hr = pNew ? S_OK : E_OUTOFMEMORY;
- if (SUCCEEDED(hr)) {
- hr = pNew->QueryInterface(riid, ppv);
- pNew->Release();
- }
- return hr;
-}
-
-// IInitializeWithStream
-IFACEMETHODIMP CBlendThumb::Initialize(IStream *pStream, DWORD)
-{
- HRESULT hr = E_UNEXPECTED; // can only be inited once
- if (_pStream == NULL) {
- // take a reference to the stream if we have not been inited yet
- hr = pStream->QueryInterface(&_pStream);
- }
- return hr;
-}
-
-#include "Wincodec.h"
-#include <math.h>
-#include <zlib.h>
-const unsigned char gzip_magic[3] = {0x1f, 0x8b, 0x08};
-
-// IThumbnailProvider
-IFACEMETHODIMP CBlendThumb::GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha)
-{
- ULONG BytesRead;
- HRESULT hr = S_FALSE;
- LARGE_INTEGER SeekPos;
-
- // Compressed?
- unsigned char in_magic[3];
- _pStream->Read(&in_magic, 3, &BytesRead);
- bool gzipped = true;
- for (int i = 0; i < 3; i++)
- if (in_magic[i] != gzip_magic[i]) {
- gzipped = false;
- break;
- }
-
- if (gzipped) {
- // Zlib inflate
- z_stream stream;
- stream.zalloc = Z_NULL;
- stream.zfree = Z_NULL;
- stream.opaque = Z_NULL;
-
- // Get compressed file length
- SeekPos.QuadPart = 0;
- _pStream->Seek(SeekPos, STREAM_SEEK_END, NULL);
-
- // Get compressed and uncompressed size
- uLong source_size;
- uLongf dest_size;
- // SeekPos.QuadPart = -4; // last 4 bytes define size of uncompressed file
- // ULARGE_INTEGER Tell;
- //_pStream->Seek(SeekPos,STREAM_SEEK_END,&Tell);
- // source_size = (uLong)Tell.QuadPart + 4; // src
- //_pStream->Read(&dest_size,4,&BytesRead); // dest
- dest_size = 1024 * 70; // thumbnail is currently always inside the first 65KB...if it moves or
- // enlargens this line will have to change or go!
- source_size = (uLong)max(SeekPos.QuadPart, dest_size); // for safety, assume no compression
-
- // Input
- Bytef *src = new Bytef[source_size];
- stream.next_in = (Bytef *)src;
- stream.avail_in = (uInt)source_size;
-
- // Output
- Bytef *dest = new Bytef[dest_size];
- stream.next_out = (Bytef *)dest;
- stream.avail_out = dest_size;
-
- // IStream to src
- SeekPos.QuadPart = 0;
- _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
- _pStream->Read(src, source_size, &BytesRead);
-
- // Do the inflation
- int err;
- err = inflateInit2(&stream, 16); // 16 means "gzip"...nice!
- err = inflate(&stream, Z_FINISH);
- err = inflateEnd(&stream);
-
- // Replace the IStream, which is read-only
- _pStream->Release();
- _pStream = SHCreateMemStream(dest, dest_size);
-
- delete[] src;
- delete[] dest;
- }
-
- // Blender version, early out if sub 2.5
- SeekPos.QuadPart = 9;
- _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
- char version[4];
- version[3] = '\0';
- _pStream->Read(&version, 3, &BytesRead);
- if (BytesRead != 3) {
- return E_UNEXPECTED;
- }
- int iVersion = atoi(version);
- if (iVersion < 250) {
- return S_FALSE;
- }
-
- // 32 or 64 bit blend?
- SeekPos.QuadPart = 7;
- _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
-
- char _PointerSize;
- _pStream->Read(&_PointerSize, 1, &BytesRead);
-
- int PointerSize = _PointerSize == '_' ? 4 : 8;
- int HeaderSize = 16 + PointerSize;
-
- // Find and read thumbnail ("TEST") block
- SeekPos.QuadPart = 12;
- _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
- int BlockOffset = 12;
- while (_pStream) {
- // Scan current block
- char BlockName[5];
- BlockName[4] = '\0';
- int BlockSize = 0;
-
- if (_pStream->Read(BlockName, 4, &BytesRead) == S_OK &&
- _pStream->Read((void *)&BlockSize, 4, &BytesRead) == S_OK) {
- if (strcmp(BlockName, "TEST") != 0) {
- SeekPos.QuadPart = BlockOffset += HeaderSize + BlockSize;
- _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
- continue;
- }
- }
- else {
- break; // eof
- }
-
- // Found the block
- SeekPos.QuadPart = BlockOffset + HeaderSize;
- _pStream->Seek(SeekPos, STREAM_SEEK_SET, NULL);
-
- int width, height;
- _pStream->Read((char *)&width, 4, &BytesRead);
- _pStream->Read((char *)&height, 4, &BytesRead);
- BlockSize -= 8;
-
- // Isolate RGBA data
- char *pRGBA = new char[BlockSize];
- _pStream->Read(pRGBA, BlockSize, &BytesRead);
-
- if (BytesRead != (ULONG)BlockSize) {
- return E_UNEXPECTED;
- }
-
- // Convert to BGRA for Windows
- for (int i = 0; i < BlockSize; i += 4) {
-#define RED_BYTE pRGBA[i]
-#define BLUE_BYTE pRGBA[i + 2]
-
- char red = RED_BYTE;
- RED_BYTE = BLUE_BYTE;
- BLUE_BYTE = red;
- }
-
- // Flip vertically (Blender stores it upside-down)
- unsigned int LineSize = width * 4;
- char *FlippedImage = new char[BlockSize];
- for (int i = 0; i < height; i++) {
- if (0 != memcpy_s(&FlippedImage[(height - i - 1) * LineSize],
- LineSize,
- &pRGBA[i * LineSize],
- LineSize)) {
- return E_UNEXPECTED;
- }
- }
- delete[] pRGBA;
- pRGBA = FlippedImage;
-
- // Create image
- *phbmp = CreateBitmap(width, height, 1, 32, pRGBA);
- if (!*phbmp) {
- return E_FAIL;
- }
- *pdwAlpha = WTSAT_ARGB; // it's actually BGRA, not sure why this works
-
- // Scale down if required
- if ((unsigned)width > cx || (unsigned)height > cx) {
- float scale = 1.0f / (max(width, height) / (float)cx);
- LONG NewWidth = (LONG)(width * scale);
- LONG NewHeight = (LONG)(height * scale);
-
-#ifdef _DEBUG
-# if 0
- MessageBox(0, "Attach now", "Debugging", MB_OK);
-# endif
-#endif
- IWICImagingFactory *pImgFac;
- hr = CoCreateInstance(
- CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pImgFac));
-
- IWICBitmap *WICBmp;
- hr = pImgFac->CreateBitmapFromHBITMAP(*phbmp, 0, WICBitmapUseAlpha, &WICBmp);
-
- BITMAPINFO bmi = {};
- bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
- bmi.bmiHeader.biWidth = NewWidth;
- bmi.bmiHeader.biHeight = -NewHeight;
- bmi.bmiHeader.biPlanes = 1;
- bmi.bmiHeader.biBitCount = 32;
- bmi.bmiHeader.biCompression = BI_RGB;
-
- BYTE *pBits;
- HBITMAP ResizedHBmp = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&pBits, NULL, 0);
- hr = ResizedHBmp ? S_OK : E_OUTOFMEMORY;
- if (SUCCEEDED(hr)) {
- IWICBitmapScaler *pIScaler;
- hr = pImgFac->CreateBitmapScaler(&pIScaler);
- hr = pIScaler->Initialize(WICBmp, NewWidth, NewHeight, WICBitmapInterpolationModeFant);
-
- WICRect rect = {0, 0, NewWidth, NewHeight};
- hr = pIScaler->CopyPixels(&rect, NewWidth * 4, NewWidth * NewHeight * 4, pBits);
-
- if (SUCCEEDED(hr)) {
- DeleteObject(*phbmp);
- *phbmp = ResizedHBmp;
- }
- else {
- DeleteObject(ResizedHBmp);
- }
-
- pIScaler->Release();
- }
- WICBmp->Release();
- pImgFac->Release();
- }
- else {
- hr = S_OK;
- }
- break;
- }
- return hr;
-}
diff --git a/source/blender/blendthumb/src/blender_thumbnailer.cc b/source/blender/blendthumb/src/blender_thumbnailer.cc
new file mode 100644
index 00000000000..8dd9d5c0c0a
--- /dev/null
+++ b/source/blender/blendthumb/src/blender_thumbnailer.cc
@@ -0,0 +1,113 @@
+/*
+ * 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 blendthumb
+ *
+ * This file defines the thumbnail generation command (typically used on UNIX).
+ *
+ * To run automatically with a file manager such as Nautilus, save this file
+ * in a directory that is listed in PATH environment variable, and create
+ * `blender.thumbnailer` file in `${HOME}/.local/share/thumbnailers/` directory
+ * with the following contents:
+ *
+ * \code{.txt}
+ * [Thumbnailer Entry]
+ * TryExec=blender-thumbnailer
+ * Exec=blender-thumbnailer %u %o
+ * MimeType=application/x-blender;
+ * \endcode
+ */
+
+#include <fstream>
+#include <optional>
+
+#include <fcntl.h>
+#ifndef WIN32
+# include <unistd.h> /* For read close. */
+#else
+# include "BLI_winstuff.h"
+# include "winsock2.h"
+# include <io.h> /* For open close read. */
+#endif
+
+#include "BLI_fileops.h"
+#include "BLI_filereader.h"
+#include "BLI_vector.hh"
+
+#include "blendthumb.hh"
+
+/**
+ * This function opens .blend file from src_blend, extracts thumbnail from file if there is one,
+ * and writes `.png` image into `dst_png`.
+ * Returns exit code (0 if successful).
+ */
+static eThumbStatus extract_png_from_blend_file(const char *src_blend, const char *dst_png)
+{
+ eThumbStatus err;
+
+ /* Open source file `src_blend`. */
+ const int src_file = BLI_open(src_blend, O_BINARY | O_RDONLY, 0);
+ if (src_file == -1) {
+ return BT_FILE_ERR;
+ }
+
+ /* Thumbnail reading is responsible for freeing `file` and closing `src_file`. */
+ FileReader *file = BLI_filereader_new_file(src_file);
+ if (file == nullptr) {
+ close(src_file);
+ return BT_FILE_ERR;
+ }
+
+ /* Extract thumbnail from file. */
+ Thumbnail thumb;
+ err = blendthumb_create_thumb_from_file(file, &thumb);
+ if (err != BT_OK) {
+ return err;
+ }
+
+ /* Write thumbnail to `dst_png`. */
+ const int dst_file = BLI_open(dst_png, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (dst_file == -1) {
+ return BT_FILE_ERR;
+ }
+
+ std::optional<blender::Vector<uint8_t>> png_buf_opt = blendthumb_create_png_data_from_thumb(
+ &thumb);
+ if (png_buf_opt == std::nullopt) {
+ err = BT_ERROR;
+ }
+ else {
+ blender::Vector<uint8_t> png_buf = *png_buf_opt;
+ err = (write(dst_file, png_buf.data(), png_buf.size()) == png_buf.size()) ? BT_OK :
+ BT_FILE_ERR;
+ }
+ close(dst_file);
+
+ return err;
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc < 3) {
+ std::cerr << "Usage: blender-thumbnailer <input.blend> <output.png>" << std::endl;
+ return -1;
+ }
+
+ eThumbStatus ret = extract_png_from_blend_file(argv[1], argv[2]);
+
+ return (int)ret;
+}
diff --git a/source/blender/blendthumb/src/blendthumb.hh b/source/blender/blendthumb/src/blendthumb.hh
new file mode 100644
index 00000000000..0bcb160519e
--- /dev/null
+++ b/source/blender/blendthumb/src/blendthumb.hh
@@ -0,0 +1,69 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008-2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup blendthumb
+ *
+ * Shared thumbnail extraction logic.
+ *
+ * Used for both MS-Windows DLL and Unix command line.
+ */
+
+#pragma once
+
+#include <optional>
+
+#include "BLI_array.hh"
+#include "BLI_vector.hh"
+
+struct FileReader;
+
+struct Thumbnail {
+ blender::Array<uint8_t> data;
+ int width;
+ int height;
+};
+
+enum eThumbStatus {
+ BT_OK = 0,
+ BT_FILE_ERR = 1,
+ BT_COMPRES_ERR = 2,
+ BT_DECOMPRESS_ERR = 3,
+ BT_INVALID_FILE = 4,
+ BT_EARLY_VERSION = 5,
+ BT_INVALID_THUMB = 6,
+ BT_ERROR = 9
+};
+
+std::optional<blender::Vector<uint8_t>> blendthumb_create_png_data_from_thumb(
+ const Thumbnail *thumb);
+/**
+ * This function extracts the thumbnail from the .blend file into thumb.
+ * Returns #BT_OK for success and the relevant error code otherwise.
+ */
+eThumbStatus blendthumb_create_thumb_from_file(struct FileReader *rawfile, Thumbnail *thumb);
+
+/* INTEGER CODES */
+#ifdef __BIG_ENDIAN__
+/* Big Endian */
+# define MAKE_ID(a, b, c, d) ((int)(a) << 24 | (int)(b) << 16 | (c) << 8 | (d))
+#else
+/* Little Endian */
+# define MAKE_ID(a, b, c, d) ((int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a))
+#endif
diff --git a/source/blender/blendthumb/src/blendthumb_extract.cc b/source/blender/blendthumb/src/blendthumb_extract.cc
new file mode 100644
index 00000000000..2d14a88c904
--- /dev/null
+++ b/source/blender/blendthumb/src/blendthumb_extract.cc
@@ -0,0 +1,253 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup blendthumb
+ *
+ * Expose #blendthumb_create_thumb_from_file that creates the PNG data
+ * but does not write it to a file.
+ */
+
+#include <cstring>
+
+#include "BLI_alloca.h"
+#include "BLI_endian_defines.h"
+#include "BLI_endian_switch.h"
+#include "BLI_fileops.h"
+#include "BLI_filereader.h"
+#include "BLI_string.h"
+
+#include "blendthumb.hh"
+
+static bool blend_header_check_magic(const char header[12])
+{
+ /* Check magic string at start of file. */
+ if (!BLI_str_startswith(header, "BLENDER")) {
+ return false;
+ }
+ /* Check pointer size and endianness indicators. */
+ if (!ELEM(header[7], '_', '-') || !ELEM(header[8], 'v', 'V')) {
+ return false;
+ }
+ /* Check version number. */
+ if (!isdigit(header[9]) || !isdigit(header[10]) || !isdigit(header[11])) {
+ return false;
+ }
+ return true;
+}
+
+static bool blend_header_is_version_valid(const char header[12])
+{
+ /* Thumbnails are only in files with version >= 2.50 */
+ char num[4];
+ memcpy(num, header + 9, 3);
+ num[3] = 0;
+ return atoi(num) >= 250;
+}
+
+static int blend_header_pointer_size(const char header[12])
+{
+ return header[7] == '_' ? 4 : 8;
+}
+
+static bool blend_header_is_endian_switch_needed(const char header[12])
+{
+ return (((header[8] == 'v') ? L_ENDIAN : B_ENDIAN) != ENDIAN_ORDER);
+}
+
+static void thumb_data_vertical_flip(Thumbnail *thumb)
+{
+ uint32_t *rect = (uint32_t *)thumb->data.data();
+ int x = thumb->width, y = thumb->height;
+ uint32_t *top = rect;
+ uint32_t *bottom = top + ((y - 1) * x);
+ uint32_t *line = (uint32_t *)malloc(x * sizeof(uint32_t));
+
+ y >>= 1;
+ for (; y > 0; y--) {
+ memcpy(line, top, x * sizeof(uint32_t));
+ memcpy(top, bottom, x * sizeof(uint32_t));
+ memcpy(bottom, line, x * sizeof(uint32_t));
+ bottom -= x;
+ top += x;
+ }
+ free(line);
+}
+
+static int32_t bytes_to_native_i32(const uint8_t bytes[4], bool endian_switch)
+{
+ int32_t data;
+ memcpy(&data, bytes, 4);
+ if (endian_switch) {
+ BLI_endian_switch_int32(&data);
+ }
+ return data;
+}
+
+static bool file_read(FileReader *file, uint8_t *buf, size_t buf_len)
+{
+ return (file->read(file, buf, buf_len) == buf_len);
+}
+
+static bool file_seek(FileReader *file, size_t len)
+{
+ if (file->seek != nullptr) {
+ if (file->seek(file, len, SEEK_CUR) == -1) {
+ return false;
+ }
+ return true;
+ }
+
+ /* File doesn't support seeking (e.g. gzip), so read and discard in chunks. */
+ constexpr size_t dummy_data_size = 4096;
+ blender::Array<char> dummy_data(dummy_data_size);
+ while (len > 0) {
+ const size_t len_chunk = std::min(len, dummy_data_size);
+ if ((size_t)file->read(file, dummy_data.data(), len_chunk) != len_chunk) {
+ return false;
+ }
+ len -= len_chunk;
+ }
+ return true;
+}
+
+static eThumbStatus blendthumb_extract_from_file_impl(FileReader *file,
+ Thumbnail *thumb,
+ const size_t bhead_size,
+ const bool endian_switch)
+{
+ /* Iterate over file blocks until we find the thumbnail or run out of data. */
+ uint8_t *bhead_data = (uint8_t *)BLI_array_alloca(bhead_data, bhead_size);
+ while (file_read(file, bhead_data, bhead_size)) {
+ /* Parse type and size from `BHead`. */
+ const int32_t block_size = bytes_to_native_i32(&bhead_data[4], endian_switch);
+
+ /* We're looking for the thumbnail, so skip any other block. */
+ switch (*((int32_t *)bhead_data)) {
+ case MAKE_ID('T', 'E', 'S', 'T'): {
+ uint8_t shape[8];
+ if (!file_read(file, shape, sizeof(shape))) {
+ return BT_INVALID_THUMB;
+ }
+ thumb->width = bytes_to_native_i32(&shape[0], endian_switch);
+ thumb->height = bytes_to_native_i32(&shape[4], endian_switch);
+
+ /* Verify that image dimensions and data size make sense. */
+ size_t data_size = block_size - 8;
+ const size_t expected_size = thumb->width * thumb->height * 4;
+ if (thumb->width < 0 || thumb->height < 0 || data_size != expected_size) {
+ return BT_INVALID_THUMB;
+ }
+
+ thumb->data = blender::Array<uint8_t>(data_size);
+ if (!file_read(file, thumb->data.data(), data_size)) {
+ return BT_INVALID_THUMB;
+ }
+ return BT_OK;
+ }
+ case MAKE_ID('R', 'E', 'N', 'D'): {
+ if (!file_seek(file, block_size)) {
+ return BT_INVALID_THUMB;
+ }
+ /* Check the next block. */
+ break;
+ }
+ default: {
+ /* Early exit if there are no `TEST` or `REND` blocks.
+ * This saves scanning the entire blend file which could be slow. */
+ return BT_INVALID_THUMB;
+ }
+ }
+ }
+
+ return BT_INVALID_THUMB;
+}
+
+eThumbStatus blendthumb_create_thumb_from_file(FileReader *rawfile, Thumbnail *thumb)
+{
+ /* Read header in order to identify file type. */
+ char header[12];
+ if (rawfile->read(rawfile, header, sizeof(header)) != sizeof(header)) {
+ rawfile->close(rawfile);
+ return BT_ERROR;
+ }
+
+ /* Rewind the file after reading the header. */
+ rawfile->seek(rawfile, 0, SEEK_SET);
+
+ /* Try to identify the file type from the header. */
+ FileReader *file = nullptr;
+ if (BLI_str_startswith(header, "BLENDER")) {
+ file = rawfile;
+ rawfile = nullptr;
+ }
+ else if (BLI_file_magic_is_gzip(header)) {
+ file = BLI_filereader_new_gzip(rawfile);
+ if (file != nullptr) {
+ rawfile = nullptr; /* The Gzip #FileReader takes ownership of raw-file. */
+ }
+ }
+ else if (BLI_file_magic_is_zstd(header)) {
+ file = BLI_filereader_new_zstd(rawfile);
+ if (file != nullptr) {
+ rawfile = nullptr; /* The Zstd #FileReader takes ownership of raw-file. */
+ }
+ }
+
+ /* Clean up rawfile if it wasn't taken over. */
+ if (rawfile != nullptr) {
+ rawfile->close(rawfile);
+ }
+
+ if (file == nullptr) {
+ return BT_ERROR;
+ }
+
+ /* Re-read header in case we had compression. */
+ if (file->read(file, header, sizeof(header)) != sizeof(header)) {
+ file->close(file);
+ return BT_ERROR;
+ }
+
+ /* Check if the header format is valid for a .blend file. */
+ if (!blend_header_check_magic(header)) {
+ file->close(file);
+ return BT_INVALID_FILE;
+ }
+
+ /* Check if the file is new enough to contain a thumbnail. */
+ if (!blend_header_is_version_valid(header)) {
+ file->close(file);
+ return BT_EARLY_VERSION;
+ }
+
+ /* Depending on where it was saved, the file can use different pointer size or endianness. */
+ int bhead_size = 16 + blend_header_pointer_size(header);
+ const bool endian_switch = blend_header_is_endian_switch_needed(header);
+
+ /* Read the thumbnail. */
+ eThumbStatus err = blendthumb_extract_from_file_impl(file, thumb, bhead_size, endian_switch);
+ file->close(file);
+ if (err != BT_OK) {
+ return err;
+ }
+
+ thumb_data_vertical_flip(thumb);
+ return BT_OK;
+}
diff --git a/source/blender/blendthumb/src/blendthumb_png.cc b/source/blender/blendthumb/src/blendthumb_png.cc
new file mode 100644
index 00000000000..d8156150078
--- /dev/null
+++ b/source/blender/blendthumb/src/blendthumb_png.cc
@@ -0,0 +1,158 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup blendthumb
+ *
+ * Expose #blendthumb_create_png_data_from_thumb that creates the PNG data
+ * but does not write it to a file.
+ */
+
+#include <cstring>
+#include <optional>
+#include <zlib.h>
+
+#include "blendthumb.hh"
+
+#include "BLI_endian_defines.h"
+#include "BLI_endian_switch.h"
+#include "BLI_vector.hh"
+
+static void png_extend_native_int32(blender::Vector<uint8_t> &output, int32_t data)
+{
+ if (ENDIAN_ORDER == L_ENDIAN) {
+ BLI_endian_switch_int32(&data);
+ }
+ output.extend_unchecked(blender::Span((uint8_t *)&data, 4));
+}
+
+/** The number of bytes each chunk uses on top of the data that's written. */
+#define PNG_CHUNK_EXTRA 12
+
+static void png_chunk_create(blender::Vector<uint8_t> &output,
+ const uint32_t tag,
+ const blender::Vector<uint8_t> &data)
+{
+ uint32_t crc = crc32(0, nullptr, 0);
+ crc = crc32(crc, (uint8_t *)&tag, sizeof(tag));
+ crc = crc32(crc, (uint8_t *)data.data(), data.size());
+
+ png_extend_native_int32(output, data.size());
+ output.extend_unchecked(blender::Span((uint8_t *)&tag, sizeof(tag)));
+ output.extend_unchecked(data);
+ png_extend_native_int32(output, crc);
+}
+
+static blender::Vector<uint8_t> filtered_rows_from_thumb(const Thumbnail *thumb)
+{
+ /* In the image data sent to the compression step, each scan-line is preceded by a filter type
+ * byte containing the numeric code of the filter algorithm used for that scan-line. */
+ const size_t line_size = thumb->width * 4;
+ blender::Vector<uint8_t> filtered{};
+ size_t final_size = thumb->height * (line_size + 1);
+ filtered.reserve(final_size);
+ for (int i = 0; i < thumb->height; i++) {
+ filtered.append_unchecked(0x00);
+ filtered.extend_unchecked(blender::Span(&thumb->data[i * line_size], line_size));
+ }
+ BLI_assert(final_size == filtered.size());
+ return filtered;
+}
+
+static std::optional<blender::Vector<uint8_t>> zlib_compress(const blender::Vector<uint8_t> &data)
+{
+ unsigned long uncompressed_size = data.size();
+ uLongf compressed_size = compressBound(uncompressed_size);
+
+ blender::Vector<uint8_t> compressed(compressed_size, 0x00);
+
+ int return_value = compress2((uchar *)compressed.data(),
+ &compressed_size,
+ (uchar *)data.data(),
+ uncompressed_size,
+ Z_NO_COMPRESSION);
+ if (return_value != Z_OK) {
+ /* Something went wrong with compression of data. */
+ return std::nullopt;
+ }
+ compressed.resize(compressed_size);
+ return compressed;
+}
+
+std::optional<blender::Vector<uint8_t>> blendthumb_create_png_data_from_thumb(
+ const Thumbnail *thumb)
+{
+ if (thumb->data.is_empty()) {
+ return std::nullopt;
+ }
+
+ /* Create `IDAT` chunk data. */
+ blender::Vector<uint8_t> image_data{};
+ {
+ auto image_data_opt = zlib_compress(filtered_rows_from_thumb(thumb));
+ if (image_data_opt == std::nullopt) {
+ return std::nullopt;
+ }
+ image_data = *image_data_opt;
+ }
+
+ /* Create the IHDR chunk data. */
+ blender::Vector<uint8_t> ihdr_data{};
+ {
+ const size_t ihdr_data_final_size = 4 + 4 + 5;
+ ihdr_data.reserve(ihdr_data_final_size);
+ png_extend_native_int32(ihdr_data, thumb->width);
+ png_extend_native_int32(ihdr_data, thumb->height);
+ ihdr_data.extend_unchecked({
+ 0x08, /* Bit Depth. */
+ 0x06, /* Color Type. */
+ 0x00, /* Compression method. */
+ 0x00, /* Filter method. */
+ 0x00, /* Interlace method. */
+ });
+ BLI_assert((size_t)ihdr_data.size() == ihdr_data_final_size);
+ }
+
+ /* Join it all together to create a PNG image. */
+ blender::Vector<uint8_t> png_buf{};
+ {
+ const size_t png_buf_final_size = (
+ /* Header. */
+ 8 +
+ /* `IHDR` chunk. */
+ (ihdr_data.size() + PNG_CHUNK_EXTRA) +
+ /* `IDAT` chunk. */
+ (image_data.size() + PNG_CHUNK_EXTRA) +
+ /* `IEND` chunk. */
+ PNG_CHUNK_EXTRA);
+
+ png_buf.reserve(png_buf_final_size);
+
+ /* This is the standard PNG file header. Every PNG file starts with it. */
+ png_buf.extend_unchecked({0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A});
+
+ png_chunk_create(png_buf, MAKE_ID('I', 'H', 'D', 'R'), ihdr_data);
+ png_chunk_create(png_buf, MAKE_ID('I', 'D', 'A', 'T'), image_data);
+ png_chunk_create(png_buf, MAKE_ID('I', 'E', 'N', 'D'), {});
+
+ BLI_assert((size_t)png_buf.size() == png_buf_final_size);
+ }
+
+ return png_buf;
+}
diff --git a/source/blender/blendthumb/src/blendthumb_win32.cc b/source/blender/blendthumb/src/blendthumb_win32.cc
new file mode 100644
index 00000000000..d757bb1c97e
--- /dev/null
+++ b/source/blender/blendthumb/src/blendthumb_win32.cc
@@ -0,0 +1,237 @@
+/*
+ * 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 blendthumb
+ *
+ * Thumbnail from Blend file extraction for MS-Windows.
+ */
+
+#include <math.h>
+#include <new>
+#include <shlwapi.h>
+#include <string>
+#include <thumbcache.h> /* for #IThumbnailProvider */
+
+#include "Wincodec.h"
+
+#include "blendthumb.hh"
+
+#include "BLI_filereader.h"
+
+#pragma comment(lib, "shlwapi.lib")
+
+/**
+ * This thumbnail provider implements #IInitializeWithStream to enable being hosted
+ * in an isolated process for robustness.
+ */
+class CBlendThumb : public IInitializeWithStream, public IThumbnailProvider {
+ public:
+ CBlendThumb() : _cRef(1), _pStream(NULL)
+ {
+ }
+
+ virtual ~CBlendThumb()
+ {
+ if (_pStream) {
+ _pStream->Release();
+ }
+ }
+
+ IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
+ {
+ static const QITAB qit[] = {
+ QITABENT(CBlendThumb, IInitializeWithStream),
+ QITABENT(CBlendThumb, IThumbnailProvider),
+ {0},
+ };
+ return QISearch(this, qit, riid, ppv);
+ }
+
+ IFACEMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement(&_cRef);
+ }
+
+ IFACEMETHODIMP_(ULONG) Release()
+ {
+ ULONG cRef = InterlockedDecrement(&_cRef);
+ if (!cRef) {
+ delete this;
+ }
+ return cRef;
+ }
+
+ /** IInitializeWithStream */
+ IFACEMETHODIMP Initialize(IStream *pStream, DWORD grfMode);
+
+ /** IThumbnailProvider */
+ IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha);
+
+ private:
+ long _cRef;
+ IStream *_pStream; /* provided in Initialize(). */
+};
+
+HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv)
+{
+ CBlendThumb *pNew = new (std::nothrow) CBlendThumb();
+ HRESULT hr = pNew ? S_OK : E_OUTOFMEMORY;
+ if (SUCCEEDED(hr)) {
+ hr = pNew->QueryInterface(riid, ppv);
+ pNew->Release();
+ }
+ return hr;
+}
+
+IFACEMETHODIMP CBlendThumb::Initialize(IStream *pStream, DWORD)
+{
+ if (_pStream != NULL) {
+ /* Can only be initialized once. */
+ return E_UNEXPECTED;
+ }
+ /* Take a reference to the stream. */
+ return pStream->QueryInterface(&_pStream);
+}
+
+/**
+ * #FileReader compatible wrapper around the Windows stream that gives access to the .blend file.
+ */
+typedef struct {
+ FileReader reader;
+
+ IStream *_pStream;
+} StreamReader;
+
+static ssize_t stream_read(FileReader *reader, void *buffer, size_t size)
+{
+ StreamReader *stream = (StreamReader *)reader;
+
+ ULONG readsize;
+ stream->_pStream->Read(buffer, size, &readsize);
+ stream->reader.offset += readsize;
+
+ return (ssize_t)readsize;
+}
+
+static off64_t stream_seek(FileReader *reader, off64_t offset, int whence)
+{
+ StreamReader *stream = (StreamReader *)reader;
+
+ DWORD origin = STREAM_SEEK_SET;
+ switch (whence) {
+ case SEEK_CUR:
+ origin = STREAM_SEEK_CUR;
+ break;
+ case SEEK_END:
+ origin = STREAM_SEEK_END;
+ break;
+ }
+ LARGE_INTEGER offsetI;
+ offsetI.QuadPart = offset;
+ ULARGE_INTEGER newPos;
+ stream->_pStream->Seek(offsetI, origin, &newPos);
+ stream->reader.offset = newPos.QuadPart;
+
+ return stream->reader.offset;
+}
+
+static void stream_close(FileReader *reader)
+{
+ StreamReader *stream = (StreamReader *)reader;
+ delete stream;
+}
+
+IFACEMETHODIMP CBlendThumb::GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha)
+{
+ HRESULT hr = S_FALSE;
+
+ StreamReader *file = new StreamReader;
+ file->reader.read = stream_read;
+ file->reader.seek = stream_seek;
+ file->reader.close = stream_close;
+ file->reader.offset = 0;
+ file->_pStream = _pStream;
+
+ file->reader.seek(&file->reader, 0, SEEK_SET);
+
+ /* Extract thumbnail from stream. */
+ Thumbnail thumb;
+ if (blendthumb_create_thumb_from_file(&file->reader, &thumb) != BT_OK) {
+ return S_FALSE;
+ }
+
+ /* Convert to BGRA for Windows. */
+ for (int i = 0; i < thumb.width * thumb.height; i++) {
+ std::swap(thumb.data[4 * i], thumb.data[4 * i + 2]);
+ }
+
+ *phbmp = CreateBitmap(thumb.width, thumb.height, 1, 32, thumb.data.data());
+ if (!*phbmp) {
+ return E_FAIL;
+ }
+ *pdwAlpha = WTSAT_ARGB;
+
+ /* Scale down the thumbnail if required. */
+ if ((unsigned)thumb.width > cx || (unsigned)thumb.height > cx) {
+ float scale = 1.0f / (std::max(thumb.width, thumb.height) / (float)cx);
+ LONG NewWidth = (LONG)(thumb.width * scale);
+ LONG NewHeight = (LONG)(thumb.height * scale);
+
+ IWICImagingFactory *pImgFac;
+ hr = CoCreateInstance(
+ CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pImgFac));
+
+ IWICBitmap *WICBmp;
+ hr = pImgFac->CreateBitmapFromHBITMAP(*phbmp, 0, WICBitmapUseAlpha, &WICBmp);
+
+ BITMAPINFO bmi = {};
+ bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
+ bmi.bmiHeader.biWidth = NewWidth;
+ bmi.bmiHeader.biHeight = -NewHeight;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+
+ BYTE *pBits;
+ HBITMAP ResizedHBmp = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&pBits, NULL, 0);
+ hr = ResizedHBmp ? S_OK : E_OUTOFMEMORY;
+ if (SUCCEEDED(hr)) {
+ IWICBitmapScaler *pIScaler;
+ hr = pImgFac->CreateBitmapScaler(&pIScaler);
+ hr = pIScaler->Initialize(WICBmp, NewWidth, NewHeight, WICBitmapInterpolationModeFant);
+
+ WICRect rect = {0, 0, NewWidth, NewHeight};
+ hr = pIScaler->CopyPixels(&rect, NewWidth * 4, NewWidth * NewHeight * 4, pBits);
+
+ if (SUCCEEDED(hr)) {
+ DeleteObject(*phbmp);
+ *phbmp = ResizedHBmp;
+ }
+ else {
+ DeleteObject(ResizedHBmp);
+ }
+
+ pIScaler->Release();
+ }
+ WICBmp->Release();
+ pImgFac->Release();
+ }
+ else {
+ hr = S_OK;
+ }
+ return hr;
+}
diff --git a/source/blender/blendthumb/src/BlendThumb.def b/source/blender/blendthumb/src/blendthumb_win32.def
index 71f9236735f..71f9236735f 100644
--- a/source/blender/blendthumb/src/BlendThumb.def
+++ b/source/blender/blendthumb/src/blendthumb_win32.def
diff --git a/source/blender/blendthumb/src/BlendThumb.rc b/source/blender/blendthumb/src/blendthumb_win32.rc
index 5dfd416b0c5..5dfd416b0c5 100644
--- a/source/blender/blendthumb/src/BlendThumb.rc
+++ b/source/blender/blendthumb/src/blendthumb_win32.rc
diff --git a/source/blender/blendthumb/src/Dll.cpp b/source/blender/blendthumb/src/blendthumb_win32_dll.cc
index 6516540034e..7f10777f884 100644
--- a/source/blender/blendthumb/src/Dll.cpp
+++ b/source/blender/blendthumb/src/blendthumb_win32_dll.cc
@@ -14,11 +14,17 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+/** \file
+ * \ingroup blendthumb
+ *
+ * Thumbnail from Blend file extraction for MS-Windows (DLL).
+ */
+
#include <new>
#include <objbase.h>
-#include <shlobj.h> // For SHChangeNotify
+#include <shlobj.h> /* For #SHChangeNotify */
#include <shlwapi.h>
-#include <thumbcache.h> // For IThumbnailProvider.
+#include <thumbcache.h> /* For IThumbnailProvider */
extern HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv);
@@ -33,16 +39,16 @@ struct CLASS_OBJECT_INIT {
PFNCREATEINSTANCE pfnCreate;
};
-// add classes supported by this module here
+/* Add classes supported by this module here. */
const CLASS_OBJECT_INIT c_rgClassObjectInit[] = {
{&CLSID_BlendThumbHandler, CBlendThumb_CreateInstance}};
long g_cRefModule = 0;
-// Handle the DLL's module
-HINSTANCE g_hInst = NULL;
+/** Handle the DLL's module */
+HINSTANCE g_hInst = nullptr;
-// Standard DLL functions
+/** Standard DLL functions. */
STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, void *)
{
if (dwReason == DLL_PROCESS_ATTACH) {
@@ -54,7 +60,7 @@ STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, void *)
STDAPI DllCanUnloadNow()
{
- // Only allow the DLL to be unloaded after all outstanding references have been released
+ /* Only allow the DLL to be unloaded after all outstanding references have been released. */
return (g_cRefModule == 0) ? S_OK : S_FALSE;
}
@@ -76,7 +82,7 @@ class CClassFactory : public IClassFactory {
REFIID riid,
void **ppv)
{
- *ppv = NULL;
+ *ppv = nullptr;
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
for (size_t i = 0; i < cClassObjectInits; i++) {
if (clsid == *pClassObjectInits[i].pClsid) {
@@ -87,7 +93,8 @@ class CClassFactory : public IClassFactory {
hr = pClassFactory->QueryInterface(riid, ppv);
pClassFactory->Release();
}
- break; // match found
+ /* Match found. */
+ break;
}
}
return hr;
@@ -98,7 +105,7 @@ class CClassFactory : public IClassFactory {
DllAddRef();
}
- // IUnknown
+ /** #IUnknown */
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] = {QITABENT(CClassFactory, IClassFactory), {0}};
@@ -119,7 +126,7 @@ class CClassFactory : public IClassFactory {
return cRef;
}
- // IClassFactory
+ /** #IClassFactory */
IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
{
return punkOuter ? CLASS_E_NOAGGREGATION : _pfnCreate(riid, ppv);
@@ -152,33 +159,37 @@ STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv)
clsid, c_rgClassObjectInit, ARRAYSIZE(c_rgClassObjectInit), riid, ppv);
}
-// A struct to hold the information required for a registry entry
-
+/**
+ * A struct to hold the information required for a registry entry.
+ */
struct REGISTRY_ENTRY {
HKEY hkeyRoot;
PCWSTR pszKeyName;
PCWSTR pszValueName;
DWORD dwValueType;
- PCWSTR pszData; // These two fields could/should have been a union, but C++
- DWORD dwData; // only lets you initialize the first field in a union.
+ /** These two fields could/should have been a union, but C++ */
+ PCWSTR pszData;
+ /** Only lets you initialize the first field in a union. */
+ DWORD dwData;
};
-// Creates a registry key (if needed) and sets the default value of the key
-
+/**
+ * Creates a registry key (if needed) and sets the default value of the key.
+ */
HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry)
{
HKEY hKey;
HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(pRegistryEntry->hkeyRoot,
pRegistryEntry->pszKeyName,
0,
- NULL,
+ nullptr,
REG_OPTION_NON_VOLATILE,
KEY_SET_VALUE,
- NULL,
+ nullptr,
&hKey,
- NULL));
+ nullptr));
if (SUCCEEDED(hr)) {
- // All this just to support REG_DWORD...
+ /* All this just to support #REG_DWORD. */
DWORD size;
DWORD data;
BYTE *lpData = (LPBYTE)pRegistryEntry->pszData;
@@ -202,9 +213,9 @@ HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry)
return hr;
}
-//
-// Registers this COM server
-//
+/**
+ * Registers this COM server.
+ */
STDAPI DllRegisterServer()
{
HRESULT hr;
@@ -216,15 +227,15 @@ STDAPI DllRegisterServer()
}
else {
const REGISTRY_ENTRY rgRegistryEntries[] = {
- // RootKey KeyName ValueName ValueType Data
+ /* `RootKey KeyName ValueName ValueType Data` */
{HKEY_CURRENT_USER,
L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER,
- NULL,
+ nullptr,
REG_SZ,
SZ_BLENDTHUMBHANDLER},
{HKEY_CURRENT_USER,
L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32",
- NULL,
+ nullptr,
REG_SZ,
szModuleName},
{HKEY_CURRENT_USER,
@@ -237,10 +248,10 @@ STDAPI DllRegisterServer()
L"Treatment",
REG_DWORD,
0,
- 0}, // doesn't appear to do anything...
+ 0}, /* This doesn't appear to do anything. */
{HKEY_CURRENT_USER,
L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}",
- NULL,
+ nullptr,
REG_SZ,
SZ_CLSID_BLENDTHUMBHANDLER},
};
@@ -251,17 +262,17 @@ STDAPI DllRegisterServer()
}
}
if (SUCCEEDED(hr)) {
- // This tells the shell to invalidate the thumbnail cache. This is important because any
- // .blend files viewed before registering this handler would otherwise show cached blank
- // thumbnails.
- SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+ /* This tells the shell to invalidate the thumbnail cache.
+ * This is important because any `.blend` files viewed before registering this handler
+ * would otherwise show cached blank thumbnails. */
+ SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
}
return hr;
}
-//
-// Unregisters this COM server
-//
+/**
+ * Unregisters this COM server
+ */
STDAPI DllUnregisterServer()
{
HRESULT hr = S_OK;
@@ -270,11 +281,11 @@ STDAPI DllUnregisterServer()
L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER,
L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}"};
- // Delete the registry entries
+ /* Delete the registry entries. */
for (int i = 0; i < ARRAYSIZE(rgpszKeys) && SUCCEEDED(hr); i++) {
hr = HRESULT_FROM_WIN32(RegDeleteTreeW(HKEY_CURRENT_USER, rgpszKeys[i]));
if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
- // If the registry entry has already been deleted, say S_OK.
+ /* If the registry entry has already been deleted, say S_OK. */
hr = S_OK;
}
}
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 78252bdb08b..169107b19cb 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -43,7 +43,14 @@ void BLF_exit(void);
void BLF_cache_clear(void);
-/* Loads a font, or returns an already loaded font and increments its reference count. */
+/**
+ * Optional cache flushing function, called before #blf_batch_draw.
+ */
+void BLF_cache_flush_set_fn(void (*cache_flush_fn)(void));
+
+/**
+ * Loads a font, or returns an already loaded font and increments its reference count.
+ */
int BLF_load(const char *name) ATTR_NONNULL();
int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL();
@@ -55,17 +62,22 @@ void BLF_unload_id(int fontid);
char *BLF_display_name_from_file(const char *filename);
-/* Check if font supports a particular glyph. */
+/**
+ * Check if font supports a particular glyph.
+ */
bool BLF_has_glyph(int fontid, unsigned int unicode);
-/* Attach a file with metrics information from memory. */
+/**
+ * Attach a file with metrics information from memory.
+ */
void BLF_metrics_attach(int fontid, unsigned char *mem, int mem_size);
void BLF_aspect(int fontid, float x, float y, float z);
void BLF_position(int fontid, float x, float y, float z);
-void BLF_size(int fontid, int size, int dpi);
+void BLF_size(int fontid, float size, int dpi);
+
+/* Goal: small but useful color API. */
-/* goal: small but useful color API */
void BLF_color4ubv(int fontid, const unsigned char rgba[4]);
void BLF_color3ubv(int fontid, const unsigned char rgb[3]);
void BLF_color3ubv_alpha(int fontid, const unsigned char rgb[3], unsigned char alpha);
@@ -78,39 +90,53 @@ void BLF_color3f(int fontid, float r, float g, float b);
void BLF_color3fv_alpha(int fontid, const float rgb[3], float alpha);
/* Also available: `UI_FontThemeColor(fontid, colorid)`. */
-/* Set a 4x4 matrix to be multiplied before draw the text.
+/**
+ * Set a 4x4 matrix to be multiplied before draw the text.
* Remember that you need call BLF_enable(BLF_MATRIX)
* to enable this.
*
* The order of the matrix is like GL:
- *
+ * \code{.unparsed}
* | m[0] m[4] m[8] m[12] |
* | m[1] m[5] m[9] m[13] |
* | m[2] m[6] m[10] m[14] |
* | m[3] m[7] m[11] m[15] |
+ * \endcode
*/
void BLF_matrix(int fontid, const float m[16]);
-/* Batch draw-calls together as long as
- * the model-view matrix and the font remain unchanged. */
+/**
+ * Batch draw-calls together as long as
+ * the model-view matrix and the font remain unchanged.
+ */
void BLF_batch_draw_begin(void);
void BLF_batch_draw_flush(void);
void BLF_batch_draw_end(void);
-/* Draw the string using the current font. */
+/**
+ * Draw the string using the current font.
+ */
void BLF_draw_ex(int fontid, const char *str, size_t str_len, struct ResultBLF *r_info)
ATTR_NONNULL(2);
void BLF_draw(int fontid, const char *str, size_t str_len) ATTR_NONNULL(2);
int BLF_draw_mono(int fontid, const char *str, size_t str_len, int cwidth) ATTR_NONNULL(2);
typedef bool (*BLF_GlyphBoundsFn)(const char *str,
- const size_t str_step_ofs,
+ size_t str_step_ofs,
const struct rcti *glyph_step_bounds,
- const int glyph_advance_x,
+ int glyph_advance_x,
const struct rctf *glyph_bounds,
const int glyph_bearing[2],
void *user_data);
+/**
+ * Run \a user_fn for each character, with the bound-box that would be used for drawing.
+ *
+ * \param user_fn: Callback that runs on each glyph, returning false early exits.
+ * \param user_data: User argument passed to \a user_fn.
+ *
+ * \note The font position, clipping, matrix and rotation are not applied.
+ */
void BLF_boundbox_foreach_glyph_ex(int fontid,
const char *str,
size_t str_len,
@@ -123,14 +149,19 @@ void BLF_boundbox_foreach_glyph(int fontid,
BLF_GlyphBoundsFn user_fn,
void *user_data) ATTR_NONNULL(2);
-/* Get the string byte offset that fits within a given width */
+/**
+ * Get the string byte offset that fits within a given width.
+ */
size_t BLF_width_to_strlen(
int fontid, const char *str, size_t str_len, float width, float *r_width) ATTR_NONNULL(2);
-/* Same as BLF_width_to_strlen but search from the string end */
+/**
+ * Same as BLF_width_to_strlen but search from the string end.
+ */
size_t BLF_width_to_rstrlen(
int fontid, const char *str, size_t str_len, float width, float *r_width) ATTR_NONNULL(2);
-/* This function return the bounding box of the string
+/**
+ * This function return the bounding box of the string
* and are not multiplied by the aspect.
*/
void BLF_boundbox_ex(int fontid,
@@ -140,7 +171,8 @@ void BLF_boundbox_ex(int fontid,
struct ResultBLF *r_info) ATTR_NONNULL(2);
void BLF_boundbox(int fontid, const char *str, size_t str_len, struct rctf *box) ATTR_NONNULL();
-/* The next both function return the width and height
+/**
+ * The next both function return the width and height
* of the string, using the current font and both value
* are multiplied by the aspect of the font.
*/
@@ -153,24 +185,29 @@ float BLF_height_ex(int fontid, const char *str, size_t str_len, struct ResultBL
float BLF_height(int fontid, const char *str, size_t str_len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-/* Return dimensions of the font without any sample text. */
+/**
+ * Return dimensions of the font without any sample text.
+ */
int BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT;
float BLF_width_max(int fontid) ATTR_WARN_UNUSED_RESULT;
float BLF_descender(int fontid) ATTR_WARN_UNUSED_RESULT;
float BLF_ascender(int fontid) ATTR_WARN_UNUSED_RESULT;
-/* The following function return the width and height of the string, but
+/**
+ * The following function return the width and height of the string, but
* just in one call, so avoid extra freetype2 stuff.
*/
void BLF_width_and_height(
int fontid, const char *str, size_t str_len, float *r_width, float *r_height) ATTR_NONNULL();
-/* For fixed width fonts only, returns the width of a
+/**
+ * For fixed width fonts only, returns the width of a
* character.
*/
float BLF_fixed_width(int fontid) ATTR_WARN_UNUSED_RESULT;
-/* By default, rotation and clipping are disable and
+/**
+ * By default, rotation and clipping are disable and
* have to be enable/disable using BLF_enable/disable.
*/
void BLF_rotation(int fontid, float angle);
@@ -184,27 +221,31 @@ void BLF_blur(int fontid, int size);
void BLF_enable(int fontid, int option);
void BLF_disable(int fontid, int option);
-/* Shadow options, level is the blur level, can be 3, 5 or 0 and
- * the other argument are the rgba color.
- * Take care that shadow need to be enable using BLF_enable!!!
+/**
+ * Shadow options, level is the blur level, can be 3, 5 or 0 and
+ * the other argument are the RGBA color.
+ * Take care that shadow need to be enable using #BLF_enable!
*/
void BLF_shadow(int fontid, int level, const float rgba[4]) ATTR_NONNULL(3);
-/* Set the offset for shadow text, this is the current cursor
+/**
+ * Set the offset for shadow text, this is the current cursor
* position plus this offset, don't need call BLF_position before
* this function, the current position is calculate only on
* BLF_draw, so it's safe call this whenever you like.
*/
void BLF_shadow_offset(int fontid, int x, int y);
-/* Set the buffer, size and number of channels to draw, one thing to take care is call
+/**
+ * Set the buffer, size and number of channels to draw, one thing to take care is call
* this function with NULL pointer when we finish, for example:
+ * \code{.c}
+ * BLF_buffer(my_fbuf, my_cbuf, 100, 100, 4, true, NULL);
*
- * BLF_buffer(my_fbuf, my_cbuf, 100, 100, 4, true, NULL);
- *
- * ... set color, position and draw ...
+ * ... set color, position and draw ...
*
- * BLF_buffer(NULL, NULL, NULL, 0, 0, false, NULL);
+ * BLF_buffer(NULL, NULL, NULL, 0, 0, false, NULL);
+ * \endcode
*/
void BLF_buffer(int fontid,
float *fbuf,
@@ -214,52 +255,79 @@ void BLF_buffer(int fontid,
int nch,
struct ColorManagedDisplay *display);
-/* Set the color to be used for text. */
+/**
+ * Set the color to be used for text.
+ */
void BLF_buffer_col(int fontid, const float rgba[4]) ATTR_NONNULL(2);
-/* Draw the string into the buffer, this function draw in both buffer,
+/**
+ * Draw the string into the buffer, this function draw in both buffer,
* float and unsigned char _BUT_ it's not necessary set both buffer, NULL is valid here.
*/
void BLF_draw_buffer_ex(int fontid, const char *str, size_t str_len, struct ResultBLF *r_info)
ATTR_NONNULL(2);
void BLF_draw_buffer(int fontid, const char *str, size_t str_len) ATTR_NONNULL(2);
-/* Add a path to the font dir paths. */
+/**
+ * Add a path to the font dir paths.
+ */
void BLF_dir_add(const char *path) ATTR_NONNULL();
-/* Remove a path from the font dir paths. */
+/**
+ * Remove a path from the font dir paths.
+ */
void BLF_dir_rem(const char *path) ATTR_NONNULL();
-/* Return an array with all the font dir (this can be used for filesel) */
+/**
+ * Return an array with all the font dir (this can be used for file-selector).
+ */
char **BLF_dir_get(int *ndir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* Free the data return by BLF_dir_get. */
+/**
+ * Free the data return by #BLF_dir_get.
+ */
void BLF_dir_free(char **dirs, int count) ATTR_NONNULL();
/* blf_thumbs.c */
+
+/**
+ * This function is used for generating thumbnail previews.
+ *
+ * \note called from a thread, so it bypasses the normal BLF_* api (which isn't thread-safe).
+ */
void BLF_thumb_preview(const char *filename,
const char **draw_str,
const char **i18n_draw_str,
- const unsigned char draw_str_lines,
+ unsigned char draw_str_lines,
const float font_color[4],
- const int font_size,
+ int font_size,
unsigned char *buf,
int w,
int h,
int channels) ATTR_NONNULL();
/* blf_default.c */
+
void BLF_default_dpi(int dpi);
+void BLF_default_size(int size);
void BLF_default_set(int fontid);
-int BLF_default(void); /* get default font ID so we can pass it to other functions */
-/* Draw the string using the default font, size and dpi. */
+/**
+ * Get default font ID so we can pass it to other functions.
+ */
+int BLF_default(void);
+/**
+ * Draw the string using the default font, size and DPI.
+ */
void BLF_draw_default(float x, float y, float z, const char *str, size_t str_len) ATTR_NONNULL();
-/* Set size and DPI, and return default font ID. */
+/**
+ * Set size and DPI, and return default font ID.
+ */
int BLF_set_default(void);
/* blf_font_default.c */
-int BLF_load_default(const bool unique);
-int BLF_load_mono_default(const bool unique);
+
+int BLF_load_default(bool unique);
+int BLF_load_mono_default(bool unique);
#ifdef DEBUG
void BLF_state_print(int fontid);
diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt
index 59a9072de57..dd22bc2e7e0 100644
--- a/source/blender/blenfont/CMakeLists.txt
+++ b/source/blender/blenfont/CMakeLists.txt
@@ -23,7 +23,6 @@ set(INC
../blenkernel
../blenlib
../blentranslation
- ../editors/include
../gpu
../imbuf
../makesdna
@@ -55,7 +54,7 @@ set(LIB
bf_gpu
bf_intern_guardedalloc
- ${FREETYPE_LIBRARY}
+ ${FREETYPE_LIBRARIES} ${BROTLI_LIBRARIES}
)
if(WIN32)
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 34ddb6f22d2..c69a0b1eb73 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -66,7 +66,8 @@
/* Font array. */
static FontBLF *global_font[BLF_MAX_FONT] = {NULL};
-/* XXX, should these be made into global_font_'s too? */
+/* XXX: should these be made into global_font_'s too? */
+
int blf_mono_font = -1;
int blf_mono_font_render = -1;
@@ -363,7 +364,7 @@ void BLF_position(int fontid, float x, float y, float z)
}
}
-void BLF_size(int fontid, int size, int dpi)
+void BLF_size(int fontid, float size, int dpi)
{
FontBLF *font = blf_get(fontid);
@@ -568,14 +569,6 @@ int BLF_draw_mono(int fontid, const char *str, const size_t str_len, int cwidth)
return columns;
}
-/**
- * Run \a user_fn for each character, with the bound-box that would be used for drawing.
- *
- * \param user_fn: Callback that runs on each glyph, returning false early exits.
- * \param user_data: User argument passed to \a user_fn.
- *
- * \note The font position, clipping, matrix and rotation are not applied.
- */
void BLF_boundbox_foreach_glyph_ex(int fontid,
const char *str,
size_t str_len,
@@ -910,7 +903,7 @@ void BLF_state_print(int fontid)
if (font) {
printf("fontid %d %p\n", fontid, (void *)font);
printf(" name: '%s'\n", font->name);
- printf(" size: %u\n", font->size);
+ printf(" size: %f\n", font->size);
printf(" dpi: %u\n", font->dpi);
printf(" pos: %.6f %.6f %.6f\n", UNPACK3(font->pos));
printf(" aspect: (%d) %.6f %.6f %.6f\n",
diff --git a/source/blender/blenfont/intern/blf_default.c b/source/blender/blenfont/intern/blf_default.c
index 2bac0bf8904..57eeaa6768d 100644
--- a/source/blender/blenfont/intern/blf_default.c
+++ b/source/blender/blenfont/intern/blf_default.c
@@ -29,8 +29,6 @@
#include "BLF_api.h"
-#include "UI_interface.h"
-
#include "blf_internal.h"
/* call BLF_default_set first! */
@@ -39,12 +37,19 @@
/* Default size and dpi, for BLF_draw_default. */
static int global_font_default = -1;
static int global_font_dpi = 72;
+/* Keep in sync with `UI_style_get()->widgetlabel.points` */
+static int global_font_size = 11;
void BLF_default_dpi(int dpi)
{
global_font_dpi = dpi;
}
+void BLF_default_size(int size)
+{
+ global_font_size = size;
+}
+
void BLF_default_set(int fontid)
{
if ((fontid == -1) || blf_font_id_is_valid(fontid)) {
@@ -62,8 +67,7 @@ int BLF_set_default(void)
{
ASSERT_DEFAULT_SET;
- const uiStyle *style = UI_style_get();
- BLF_size(global_font_default, style->widgetlabel.points, global_font_dpi);
+ BLF_size(global_font_default, global_font_size, global_font_dpi);
return global_font_default;
}
@@ -71,9 +75,7 @@ int BLF_set_default(void)
void BLF_draw_default(float x, float y, float z, const char *str, const size_t str_len)
{
ASSERT_DEFAULT_SET;
-
- const uiStyle *style = UI_style_get();
- BLF_size(global_font_default, style->widgetlabel.points, global_font_dpi);
+ BLF_size(global_font_default, global_font_size, global_font_dpi);
BLF_position(global_font_default, x, y, z);
BLF_draw(global_font_default, str, str_len);
}
diff --git a/source/blender/blenfont/intern/blf_dir.c b/source/blender/blenfont/intern/blf_dir.c
index f4a20faf109..8eb148a8a9a 100644
--- a/source/blender/blenfont/intern/blf_dir.c
+++ b/source/blender/blenfont/intern/blf_dir.c
@@ -148,10 +148,6 @@ char *blf_dir_search(const char *file)
return s;
}
-/**
- * Some font have additional file with metrics information,
- * in general, the extension of the file is: `.afm` or `.pfm`
- */
char *blf_dir_metrics_search(const char *filename)
{
char *mfile;
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 27478bd7f8e..14d3a208f69 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -34,6 +34,7 @@
#include FT_FREETYPE_H
#include FT_GLYPH_H
+#include FT_ADVANCES_H /* For FT_Get_Advance */
#include "MEM_guardedalloc.h"
@@ -49,8 +50,6 @@
#include "BLF_api.h"
-#include "UI_interface.h"
-
#include "GPU_batch.h"
#include "GPU_matrix.h"
@@ -64,6 +63,7 @@
#endif
/* Batching buffer for drawing. */
+
BatchBLF g_batch;
/* freetype2 handle ONLY for this file! */
@@ -71,6 +71,9 @@ static FT_Library ft_lib;
static SpinLock ft_lib_mutex;
static SpinLock blf_glyph_cache_mutex;
+/* May be set to #UI_widgetbase_draw_cache_flush. */
+static void (*blf_draw_cache_flush)(void) = NULL;
+
/* -------------------------------------------------------------------- */
/** \name FreeType Utilities (Internal)
* \{ */
@@ -254,10 +257,10 @@ void blf_batch_draw(void)
GPU_blend(GPU_BLEND_ALPHA);
-#ifndef BLF_STANDALONE
/* We need to flush widget base first to ensure correct ordering. */
- UI_widgetbase_draw_cache_flush();
-#endif
+ if (blf_draw_cache_flush != NULL) {
+ blf_draw_cache_flush();
+ }
GPUTexture *texture = blf_batch_cache_texture_load();
GPU_vertbuf_data_len_set(g_batch.verts, g_batch.glyph_len);
@@ -297,44 +300,27 @@ static void blf_batch_draw_end(void)
* characters.
*/
-BLI_INLINE GlyphBLF *blf_utf8_next_fast(
- FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t str_len, size_t *i_p, uint *r_c)
+BLI_INLINE GlyphBLF *blf_glyph_from_utf8_and_step(
+ FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t str_len, size_t *i_p)
{
- GlyphBLF *g;
- if ((*r_c = str[*i_p]) < GLYPH_ASCII_TABLE_SIZE) {
- g = (gc->glyph_ascii_table)[*r_c];
- if (UNLIKELY(g == NULL)) {
- g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, *r_c), *r_c);
- gc->glyph_ascii_table[*r_c] = g;
- }
- (*i_p)++;
- }
- else {
- *r_c = BLI_str_utf8_as_unicode_step(str, str_len, i_p);
- g = blf_glyph_search(gc, *r_c);
- if (UNLIKELY(g == NULL)) {
- g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, *r_c), *r_c);
- }
- }
- return g;
+ uint charcode = BLI_str_utf8_as_unicode_step(str, str_len, i_p);
+ /* Invalid unicode sequences return the byte value, stepping forward one.
+ * This allows `latin1` to display (which is sometimes used for file-paths). */
+ BLI_assert(charcode != BLI_UTF8_ERR);
+ return blf_glyph_ensure(font, gc, charcode);
}
-BLI_INLINE void blf_kerning_step_fast(FontBLF *font,
- const GlyphBLF *g_prev,
- const GlyphBLF *g,
- const uint c_prev,
- const uint c,
- int *pen_x_p)
+BLI_INLINE int blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g)
{
if (!FT_HAS_KERNING(font->face) || g_prev == NULL) {
- return;
+ return 0;
}
FT_Vector delta = {KERNING_ENTRY_UNSET};
/* Get unscaled kerning value from our cache if ASCII. */
- if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) {
- delta.x = font->kerning_cache->ascii_table[c][c_prev];
+ if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) {
+ delta.x = font->kerning_cache->ascii_table[g->c][g_prev->c];
}
/* If not ASCII or not found in cache, ask FreeType for kerning. */
@@ -344,14 +330,16 @@ BLI_INLINE void blf_kerning_step_fast(FontBLF *font,
}
/* If ASCII we save this value to our cache for quicker access next time. */
- if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) {
- font->kerning_cache->ascii_table[c][c_prev] = (int)delta.x;
+ if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) {
+ font->kerning_cache->ascii_table[g->c][g_prev->c] = (int)delta.x;
}
if (delta.x != 0) {
/* Convert unscaled design units to pixels and move pen. */
- *pen_x_p += blf_unscaled_F26Dot6_to_pixels(font, delta.x);
+ return blf_unscaled_F26Dot6_to_pixels(font, delta.x);
}
+
+ return 0;
}
/** \} */
@@ -367,7 +355,6 @@ static void blf_font_draw_ex(FontBLF *font,
struct ResultBLF *r_info,
int pen_y)
{
- unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
size_t i = 0;
@@ -380,22 +367,18 @@ static void blf_font_draw_ex(FontBLF *font,
blf_batch_draw_begin(font);
while ((i < str_len) && str[i]) {
- g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c);
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
- if (UNLIKELY(c == BLI_UTF8_ERR)) {
- break;
- }
if (UNLIKELY(g == NULL)) {
continue;
}
- blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x);
+ pen_x += blf_kerning(font, g_prev, g);
/* do not return this loop if clipped, we want every character tested */
- blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y);
+ blf_glyph_draw(font, gc, g, (float)pen_x, (float)pen_y);
pen_x += g->advance_i;
g_prev = g;
- c_prev = c;
}
blf_batch_draw_end();
@@ -412,10 +395,8 @@ void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, struct
blf_glyph_cache_release(font);
}
-/* use fixed column width, but an utf8 character may occupy multiple columns */
int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int cwidth)
{
- unsigned int c;
GlyphBLF *g;
int col, columns = 0;
int pen_x = 0, pen_y = 0;
@@ -426,19 +407,15 @@ int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int
blf_batch_draw_begin(font);
while ((i < str_len) && str[i]) {
- g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c);
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
- if (UNLIKELY(c == BLI_UTF8_ERR)) {
- break;
- }
if (UNLIKELY(g == NULL)) {
continue;
}
-
/* do not return this loop if clipped, we want every character tested */
- blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y);
+ blf_glyph_draw(font, gc, g, (float)pen_x, (float)pen_y);
- col = BLI_wcwidth((char32_t)c);
+ col = BLI_wcwidth((char32_t)g->c);
if (col < 0) {
col = 1;
}
@@ -467,7 +444,6 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
struct ResultBLF *r_info,
int pen_y)
{
- unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = (int)font->pos[0];
int pen_y_basis = (int)font->pos[1] + pen_y;
@@ -483,15 +459,12 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
/* another buffer specific call for color conversion */
while ((i < str_len) && str[i]) {
- g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c);
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
- if (UNLIKELY(c == BLI_UTF8_ERR)) {
- break;
- }
if (UNLIKELY(g == NULL)) {
continue;
}
- blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x);
+ pen_x += blf_kerning(font, g_prev, g);
chx = pen_x + ((int)g->pos[0]);
chy = pen_y_basis + g->dims[1];
@@ -588,7 +561,6 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
pen_x += g->advance_i;
g_prev = g;
- c_prev = c;
}
if (r_info) {
@@ -610,38 +582,29 @@ void blf_font_draw_buffer(FontBLF *font,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Text Evaluation: Width to Sting Length
+/** \name Text Evaluation: Width to String Length
*
* Use to implement exported functions:
* - #BLF_width_to_strlen
* - #BLF_width_to_rstrlen
* \{ */
-static bool blf_font_width_to_strlen_glyph_process(FontBLF *font,
- const uint c_prev,
- const uint c,
- GlyphBLF *g_prev,
- GlyphBLF *g,
- int *pen_x,
- const int width_i)
+static bool blf_font_width_to_strlen_glyph_process(
+ FontBLF *font, GlyphBLF *g_prev, GlyphBLF *g, int *pen_x, const int width_i)
{
- if (UNLIKELY(c == BLI_UTF8_ERR)) {
- return true; /* break the calling loop. */
- }
if (UNLIKELY(g == NULL)) {
return false; /* continue the calling loop. */
}
- blf_kerning_step_fast(font, g_prev, g, c_prev, c, pen_x);
-
+ *pen_x += blf_kerning(font, g_prev, g);
*pen_x += g->advance_i;
+ /* When true, break the calling loop. */
return (*pen_x >= width_i);
}
size_t blf_font_width_to_strlen(
FontBLF *font, const char *str, const size_t str_len, float width, float *r_width)
{
- unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev;
int pen_x, width_new;
size_t i, i_prev;
@@ -649,11 +612,11 @@ size_t blf_font_width_to_strlen(
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
const int width_i = (int)width;
- for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0; (i < str_len) && str[i];
- i_prev = i, width_new = pen_x, c_prev = c, g_prev = g) {
- g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c);
+ for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL; (i < str_len) && str[i];
+ i_prev = i, width_new = pen_x, g_prev = g) {
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
- if (blf_font_width_to_strlen_glyph_process(font, c_prev, c, g_prev, g, &pen_x, width_i)) {
+ if (blf_font_width_to_strlen_glyph_process(font, g_prev, g, &pen_x, width_i)) {
break;
}
}
@@ -669,7 +632,6 @@ size_t blf_font_width_to_strlen(
size_t blf_font_width_to_rstrlen(
FontBLF *font, const char *str, const size_t str_len, float width, float *r_width)
{
- unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev;
int pen_x, width_new;
size_t i, i_prev, i_tmp;
@@ -685,19 +647,19 @@ size_t blf_font_width_to_rstrlen(
i_prev = (size_t)(s_prev - str);
i_tmp = i;
- g = blf_utf8_next_fast(font, gc, str, str_len, &i_tmp, &c);
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i_tmp);
for (width_new = pen_x = 0; (s != NULL);
- i = i_prev, s = s_prev, c = c_prev, g = g_prev, g_prev = NULL, width_new = pen_x) {
+ i = i_prev, s = s_prev, g = g_prev, g_prev = NULL, width_new = pen_x) {
s_prev = BLI_str_find_prev_char_utf8(s, str);
i_prev = (size_t)(s_prev - str);
if (s_prev != NULL) {
i_tmp = i_prev;
- g_prev = blf_utf8_next_fast(font, gc, str, str_len, &i_tmp, &c_prev);
+ g_prev = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i_tmp);
BLI_assert(i_tmp == i);
}
- if (blf_font_width_to_strlen_glyph_process(font, c_prev, c, g_prev, g, &pen_x, width_i)) {
+ if (blf_font_width_to_strlen_glyph_process(font, g_prev, g, &pen_x, width_i)) {
break;
}
}
@@ -724,7 +686,6 @@ static void blf_font_boundbox_ex(FontBLF *font,
struct ResultBLF *r_info,
int pen_y)
{
- unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
size_t i = 0;
@@ -736,15 +697,12 @@ static void blf_font_boundbox_ex(FontBLF *font,
box->ymax = -32000.0f;
while ((i < str_len) && str[i]) {
- g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c);
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
- if (UNLIKELY(c == BLI_UTF8_ERR)) {
- break;
- }
if (UNLIKELY(g == NULL)) {
continue;
}
- blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x);
+ pen_x += blf_kerning(font, g_prev, g);
gbox.xmin = (float)pen_x;
gbox.xmax = (float)pen_x + g->advance;
@@ -767,7 +725,6 @@ static void blf_font_boundbox_ex(FontBLF *font,
pen_x += g->advance_i;
g_prev = g;
- c_prev = c;
}
if (box->xmin > box->xmax) {
@@ -869,22 +826,7 @@ float blf_font_height(FontBLF *font,
float blf_font_fixed_width(FontBLF *font)
{
- const unsigned int c = ' ';
-
- GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
- GlyphBLF *g = blf_glyph_search(gc, c);
- if (!g) {
- g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, c), c);
-
- /* if we don't find the glyph. */
- if (!g) {
- blf_glyph_cache_release(font);
- return 0.0f;
- }
- }
-
- blf_glyph_cache_release(font);
- return g->advance;
+ return (float)font->fixed_width;
}
static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
@@ -896,7 +838,6 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
struct ResultBLF *r_info,
int pen_y)
{
- unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
size_t i = 0, i_curr;
@@ -909,15 +850,12 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
while ((i < str_len) && str[i]) {
i_curr = i;
- g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c);
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
- if (UNLIKELY(c == BLI_UTF8_ERR)) {
- break;
- }
if (UNLIKELY(g == NULL)) {
continue;
}
- blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x);
+ pen_x += blf_kerning(font, g_prev, g);
gbox.xmin = pen_x;
gbox.xmax = gbox.xmin + MIN2(g->advance_i, g->dims[0]);
@@ -931,7 +869,6 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
}
g_prev = g;
- c_prev = c;
}
if (r_info) {
@@ -978,7 +915,6 @@ static void blf_font_wrap_apply(FontBLF *font,
void *userdata),
void *userdata)
{
- unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0, pen_y = 0;
size_t i = 0;
@@ -999,15 +935,12 @@ static void blf_font_wrap_apply(FontBLF *font,
size_t i_curr = i;
bool do_draw = false;
- g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c);
+ g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
- if (UNLIKELY(c == BLI_UTF8_ERR)) {
- break;
- }
if (UNLIKELY(g == NULL)) {
continue;
}
- blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x);
+ pen_x += blf_kerning(font, g_prev, g);
/**
* Implementation Detail (utf8).
@@ -1045,16 +978,14 @@ static void blf_font_wrap_apply(FontBLF *font,
wrap.start = wrap.last[0];
i = wrap.last[1];
pen_x = 0;
- pen_y -= gc->glyph_height_max;
+ pen_y -= blf_font_height_max(font);
g_prev = NULL;
- c_prev = BLI_UTF8_ERR;
lines += 1;
continue;
}
pen_x = pen_x_next;
g_prev = g;
- c_prev = c;
}
// printf("done! lines: %d, width, %d\n", lines, pen_x_next);
@@ -1170,45 +1101,41 @@ int blf_font_count_missing_chars(FontBLF *font,
int blf_font_height_max(FontBLF *font)
{
int height_max;
-
- GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
- height_max = gc->glyph_height_max;
-
- blf_glyph_cache_release(font);
- return height_max;
+ if (FT_IS_SCALABLE(font->face)) {
+ height_max = (int)((float)(font->face->ascender - font->face->descender) *
+ (((float)font->face->size->metrics.y_ppem) /
+ ((float)font->face->units_per_EM)));
+ }
+ else {
+ height_max = (int)(((float)font->face->size->metrics.height) / 64.0f);
+ }
+ /* can happen with size 1 fonts */
+ return MAX2(height_max, 1);
}
int blf_font_width_max(FontBLF *font)
{
int width_max;
-
- GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
- width_max = gc->glyph_width_max;
-
- blf_glyph_cache_release(font);
- return width_max;
+ if (FT_IS_SCALABLE(font->face)) {
+ width_max = (int)((float)(font->face->bbox.xMax - font->face->bbox.xMin) *
+ (((float)font->face->size->metrics.x_ppem) /
+ ((float)font->face->units_per_EM)));
+ }
+ else {
+ width_max = (int)(((float)font->face->size->metrics.max_advance) / 64.0f);
+ }
+ /* can happen with size 1 fonts */
+ return MAX2(width_max, 1);
}
float blf_font_descender(FontBLF *font)
{
- float descender;
-
- GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
- descender = gc->descender;
-
- blf_glyph_cache_release(font);
- return descender;
+ return ((float)font->face->size->metrics.descender) / 64.0f;
}
float blf_font_ascender(FontBLF *font)
{
- float ascender;
-
- GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
- ascender = gc->ascender;
-
- blf_glyph_cache_release(font);
- return ascender;
+ return ((float)font->face->size->metrics.ascender) / 64.0f;
}
char *blf_display_name(FontBLF *font)
@@ -1241,6 +1168,11 @@ void blf_font_exit(void)
blf_batch_draw_exit();
}
+void BLF_cache_flush_set_fn(void (*cache_flush_fn)(void))
+{
+ blf_draw_cache_flush = cache_flush_fn;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1415,19 +1347,24 @@ void blf_font_free(FontBLF *font)
/** \name Font Configure
* \{ */
-void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi)
+void blf_font_size(FontBLF *font, float size, unsigned int dpi)
{
blf_glyph_cache_acquire(font);
+ /* FreeType uses fixed-point integers in 64ths. */
+ FT_F26Dot6 ft_size = lroundf(size * 64.0f);
+ /* Adjust our size to be on even 64ths. */
+ size = (float)ft_size / 64.0f;
+
GlyphCacheBLF *gc = blf_glyph_cache_find(font, size, dpi);
if (gc && (font->size == size && font->dpi == dpi)) {
/* Optimization: do not call FT_Set_Char_Size if size did not change. */
}
else {
- const FT_Error err = FT_Set_Char_Size(font->face, 0, ((FT_F26Dot6)(size)) * 64, dpi, dpi);
+ const FT_Error err = FT_Set_Char_Size(font->face, 0, ft_size, dpi, dpi);
if (err) {
/* FIXME: here we can go through the fixed size and choice a close one */
- printf("The current font don't support the size, %u and dpi, %u\n", size, dpi);
+ printf("The current font don't support the size, %f and dpi, %u\n", size, dpi);
}
else {
font->size = size;
@@ -1439,6 +1376,22 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi)
}
blf_glyph_cache_release(font);
+
+ /* Set fixed-width size for monospaced output. */
+ FT_UInt gindex = FT_Get_Char_Index(font->face, U'0');
+ if (gindex) {
+ FT_Fixed advance = 0;
+ FT_Get_Advance(font->face, gindex, FT_LOAD_NO_HINTING, &advance);
+ /* Use CSS 'ch unit' width, advance of zero character. */
+ font->fixed_width = (int)(advance >> 16);
+ }
+ else {
+ /* Font does not contain "0" so use CSS fallback of 1/2 of em. */
+ font->fixed_width = (int)((font->face->size->metrics.height / 2) >> 6);
+ }
+ if (font->fixed_width < 1) {
+ font->fixed_width = 1;
+ }
}
/** \} */
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 6cdf5fc5996..4f25f99b65c 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -55,27 +55,41 @@
#include "BLI_math_vector.h"
#include "BLI_strict_flags.h"
-GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, unsigned int size, unsigned int dpi)
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
+/**
+ * Convert a floating point value to a FreeType 16.16 fixed point value.
+ */
+static FT_Fixed to_16dot16(double val)
{
- GlyphCacheBLF *p;
+ return (FT_Fixed)(lround(val * 65536.0));
+}
- p = (GlyphCacheBLF *)font->cache.first;
- while (p) {
- if (p->size == size && p->dpi == dpi && (p->bold == ((font->flags & BLF_BOLD) != 0)) &&
- (p->italic == ((font->flags & BLF_ITALIC) != 0))) {
- return p;
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Glyph Cache
+ * \{ */
+
+GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, float size, unsigned int dpi)
+{
+ GlyphCacheBLF *gc = (GlyphCacheBLF *)font->cache.first;
+ while (gc) {
+ if (gc->size == size && gc->dpi == dpi && (gc->bold == ((font->flags & BLF_BOLD) != 0)) &&
+ (gc->italic == ((font->flags & BLF_ITALIC) != 0))) {
+ return gc;
}
- p = p->next;
+ gc = gc->next;
}
return NULL;
}
-/* Create a new glyph cache for the current size, dpi, bold, italic. */
GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
{
- GlyphCacheBLF *gc;
+ GlyphCacheBLF *gc = (GlyphCacheBLF *)MEM_callocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new");
- gc = (GlyphCacheBLF *)MEM_callocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new");
gc->next = NULL;
gc->prev = NULL;
gc->size = font->size;
@@ -86,27 +100,6 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
memset(gc->glyph_ascii_table, 0, sizeof(gc->glyph_ascii_table));
memset(gc->bucket, 0, sizeof(gc->bucket));
- gc->ascender = ((float)font->face->size->metrics.ascender) / 64.0f;
- gc->descender = ((float)font->face->size->metrics.descender) / 64.0f;
-
- if (FT_IS_SCALABLE(font->face)) {
- gc->glyph_width_max = (int)((float)(font->face->bbox.xMax - font->face->bbox.xMin) *
- (((float)font->face->size->metrics.x_ppem) /
- ((float)font->face->units_per_EM)));
-
- gc->glyph_height_max = (int)((float)(font->face->bbox.yMax - font->face->bbox.yMin) *
- (((float)font->face->size->metrics.y_ppem) /
- ((float)font->face->units_per_EM)));
- }
- else {
- gc->glyph_width_max = (int)(((float)font->face->size->metrics.max_advance) / 64.0f);
- gc->glyph_height_max = (int)(((float)font->face->size->metrics.height) / 64.0f);
- }
-
- /* can happen with size 1 fonts */
- CLAMP_MIN(gc->glyph_width_max, 1);
- CLAMP_MIN(gc->glyph_height_max, 1);
-
BLI_addhead(&font->cache, gc);
return gc;
}
@@ -159,59 +152,95 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc)
MEM_freeN(gc);
}
-GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c)
+/**
+ * Try to find a glyph in cache.
+ *
+ * \return NULL if not found.
+ */
+static GlyphBLF *blf_glyph_cache_find_glyph(GlyphCacheBLF *gc, uint charcode)
{
- GlyphBLF *p;
- unsigned int key;
-
- key = blf_hash(c);
- p = gc->bucket[key].first;
- while (p) {
- if (p->c == c) {
- return p;
+ if (charcode < GLYPH_ASCII_TABLE_SIZE) {
+ return gc->glyph_ascii_table[charcode];
+ }
+
+ GlyphBLF *g = gc->bucket[blf_hash(charcode)].first;
+ while (g) {
+ if (g->c == charcode) {
+ return g;
}
- p = p->next;
+ g = g->next;
}
return NULL;
}
-GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, unsigned int c)
+/**
+ * Add a rendered glyph to a cache.
+ */
+static GlyphBLF *blf_glyph_cache_add_glyph(
+ FontBLF *font, GlyphCacheBLF *gc, FT_GlyphSlot glyph, uint charcode, FT_UInt glyph_index)
{
- FT_GlyphSlot slot;
- GlyphBLF *g;
- FT_Error err;
- FT_Bitmap bitmap, tempbitmap;
+ GlyphBLF *g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_get");
+ g->c = charcode;
+ g->idx = glyph_index;
+ g->advance = ((float)glyph->advance.x) / 64.0f;
+ g->advance_i = (int)g->advance;
+ g->pos[0] = glyph->bitmap_left;
+ g->pos[1] = glyph->bitmap_top;
+ g->dims[0] = (int)glyph->bitmap.width;
+ g->dims[1] = (int)glyph->bitmap.rows;
+ g->pitch = glyph->bitmap.pitch;
+
FT_BBox bbox;
- unsigned int key;
+ FT_Outline_Get_CBox(&(glyph->outline), &bbox);
+ g->box.xmin = ((float)bbox.xMin) / 64.0f;
+ g->box.xmax = ((float)bbox.xMax) / 64.0f;
+ g->box.ymin = ((float)bbox.yMin) / 64.0f;
+ g->box.ymax = ((float)bbox.yMax) / 64.0f;
- g = blf_glyph_search(gc, c);
- if (g) {
- return g;
+ const int buffer_size = (int)(glyph->bitmap.width * glyph->bitmap.rows);
+ if (buffer_size != 0) {
+ if (font->flags & BLF_MONOCHROME) {
+ /* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range. */
+ for (int i = 0; i < buffer_size; i++) {
+ glyph->bitmap.buffer[i] = glyph->bitmap.buffer[i] ? 255 : 0;
+ }
+ }
+ g->bitmap = MEM_mallocN((size_t)buffer_size, "glyph bitmap");
+ memcpy(g->bitmap, glyph->bitmap.buffer, (size_t)buffer_size);
}
- /* glyphs are dynamically created as needed by font rendering. this means that
- * to make font rendering thread safe we have to do locking here. note that this
- * must be a lock for the whole library and not just per font, because the font
- * renderer uses a shared buffer internally */
- BLI_spin_lock(font->ft_lib_mutex);
-
- /* search again after locking */
- g = blf_glyph_search(gc, c);
- if (g) {
- BLI_spin_unlock(font->ft_lib_mutex);
- return g;
+ unsigned int key = blf_hash(g->c);
+ BLI_addhead(&(gc->bucket[key]), g);
+ if (charcode < GLYPH_ASCII_TABLE_SIZE) {
+ gc->glyph_ascii_table[charcode] = g;
}
+ return g;
+}
+
+/**
+ * Return a glyph index from `charcode`. Not found returns zero, which is a valid
+ * printable character (`.notdef` or `tofu`). Font is allowed to change here.
+ */
+static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode)
+{
+ FT_UInt glyph_index = FT_Get_Char_Index((*font)->face, charcode);
+ /* TODO: If not found in this font, check others, update font pointer. */
+ return glyph_index;
+}
+
+/**
+ * Load a glyph into the glyph slot of a font's face object.
+ */
+static FT_GlyphSlot blf_glyph_load(FontBLF *font, FT_UInt glyph_index)
+{
int load_flags;
- int render_mode;
if (font->flags & BLF_MONOCHROME) {
load_flags = FT_LOAD_TARGET_MONO;
- render_mode = FT_RENDER_MODE_MONO;
}
else {
load_flags = FT_LOAD_NO_BITMAP;
- render_mode = FT_RENDER_MODE_NORMAL;
if (font->flags & BLF_HINTING_NONE) {
load_flags |= FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING;
}
@@ -228,104 +257,219 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un
}
}
- err = FT_Load_Glyph(font->face, (FT_UInt)index, load_flags);
-
- /* Do not oblique a font that is designed to be italic! */
- if (((font->flags & BLF_ITALIC) != 0) && !(font->face->style_flags & FT_STYLE_FLAG_ITALIC) &&
- (font->face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)) {
- /* For (fake) italic: a shear transform with a 6 degree angle. */
- FT_Matrix transform;
- transform.xx = 0x10000L;
- transform.yx = 0x00000L;
- transform.xy = 0x03000L;
- transform.yy = 0x10000L;
- FT_Outline_Transform(&font->face->glyph->outline, &transform);
- }
-
- /* Do not embolden an already bold font! */
- if (((font->flags & BLF_BOLD) != 0) &&
- !(font->face->style_flags & FT_STYLE_FLAG_BOLD) &
- (font->face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)) {
- /* Strengthen the width more than the height. */
- const FT_Pos extra_x = FT_MulFix(font->face->units_per_EM, font->face->size->metrics.x_scale) /
- 14;
- const FT_Pos extra_y = FT_MulFix(font->face->units_per_EM, font->face->size->metrics.y_scale) /
- 28;
- FT_Outline_EmboldenXY(&font->face->glyph->outline, extra_x, extra_y);
- if ((font->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) == 0) {
- /* Need to increase advance, but not for fixed-width fonts. */
- font->face->glyph->advance.x += (FT_Pos)(((float)extra_x) * 1.05f);
- font->face->glyph->advance.y += extra_y;
- }
- else {
- /* Widened fixed-pitch font gets a nudge left. */
- FT_Outline_Translate(&font->face->glyph->outline, (extra_x / -2), 0);
- }
+ if (FT_Load_Glyph(font->face, glyph_index, load_flags) == 0) {
+ return font->face->glyph;
}
+ return NULL;
+}
- if (err) {
- BLI_spin_unlock(font->ft_lib_mutex);
- return NULL;
+/**
+ * Convert a glyph from outlines to a bitmap that we can display.
+ */
+static bool blf_glyph_render_bitmap(FontBLF *font, FT_GlyphSlot glyph)
+{
+ int render_mode;
+
+ if (font->flags & BLF_MONOCHROME) {
+ render_mode = FT_RENDER_MODE_MONO;
+ }
+ else {
+ render_mode = FT_RENDER_MODE_NORMAL;
+ }
+
+ /* Render the glyph curves to a bitmap. */
+ FT_Error err = FT_Render_Glyph(glyph, render_mode);
+ if (err != 0) {
+ return false;
}
- /* get the glyph. */
- slot = font->face->glyph;
- err = FT_Render_Glyph(slot, render_mode);
+ FT_Bitmap tempbitmap;
if (font->flags & BLF_MONOCHROME) {
/* Convert result from 1 bit per pixel to 8 bit per pixel */
- /* Accum errors for later, fine if not interested beyond "ok vs any error" */
+ /* Accumulate errors for later, fine if not interested beyond "ok vs any error" */
FT_Bitmap_New(&tempbitmap);
/* Does Blender use Pitch 1 always? It works so far */
- err += FT_Bitmap_Convert(font->ft_lib, &slot->bitmap, &tempbitmap, 1);
- err += FT_Bitmap_Copy(font->ft_lib, &tempbitmap, &slot->bitmap);
+ err += FT_Bitmap_Convert(font->ft_lib, &glyph->bitmap, &tempbitmap, 1);
+ err += FT_Bitmap_Copy(font->ft_lib, &tempbitmap, &glyph->bitmap);
err += FT_Bitmap_Done(font->ft_lib, &tempbitmap);
}
- if (err || slot->format != FT_GLYPH_FORMAT_BITMAP) {
- BLI_spin_unlock(font->ft_lib_mutex);
- return NULL;
+ if (err || glyph->format != FT_GLYPH_FORMAT_BITMAP) {
+ return false;
}
- g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_add");
- g->c = c;
- g->idx = (FT_UInt)index;
- bitmap = slot->bitmap;
- g->dims[0] = (int)bitmap.width;
- g->dims[1] = (int)bitmap.rows;
+ return true;
+}
- const int buffer_size = g->dims[0] * g->dims[1];
+/** \} */
- if (buffer_size != 0) {
- if (font->flags & BLF_MONOCHROME) {
- /* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */
- for (int i = 0; i < buffer_size; i++) {
- bitmap.buffer[i] = bitmap.buffer[i] ? 255 : 0;
- }
+/* -------------------------------------------------------------------- */
+/** \name Glyph Transformations
+ * \{ */
+
+/**
+ * Adjust the glyphs weight by a factor.
+ *
+ * \param factor: -1 (min stroke width) <= 0 (normal) => 1 (max boldness).
+ */
+static bool blf_glyph_transform_weight(FT_GlyphSlot glyph, float factor, bool monospaced)
+{
+ if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
+ /* Fake bold if the font does not have this variable axis. */
+ const FT_Pos average_width = FT_MulFix(glyph->face->units_per_EM,
+ glyph->face->size->metrics.x_scale);
+ FT_Pos change = (FT_Pos)((float)average_width * factor * 0.1f);
+ FT_Outline_EmboldenXY(&glyph->outline, change, change / 2);
+ if (monospaced) {
+ /* Widened fixed-pitch font needs a nudge left. */
+ FT_Outline_Translate(&glyph->outline, change / -2, 0);
+ }
+ else {
+ /* Need to increase advance. */
+ glyph->advance.x += change;
+ glyph->advance.y += change / 2;
}
+ return true;
+ }
+ return false;
+}
- g->bitmap = MEM_mallocN((size_t)buffer_size, "glyph bitmap");
- memcpy(g->bitmap, bitmap.buffer, (size_t)buffer_size);
+/**
+ * Adjust the glyphs slant by a factor (making it oblique).
+ *
+ * \param factor: -1 (max negative) <= 0 (no slant) => 1 (max positive).
+ *
+ * \note that left-leaning italics are possible in some RTL writing systems.
+ */
+static bool blf_glyph_transform_slant(FT_GlyphSlot glyph, float factor)
+{
+ if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
+ FT_Matrix transform = {to_16dot16(1), to_16dot16(factor / 2.0f), 0, to_16dot16(1)};
+ FT_Outline_Transform(&glyph->outline, &transform);
+ return true;
}
+ return false;
+}
- g->advance = ((float)slot->advance.x) / 64.0f;
- g->advance_i = (int)g->advance;
- g->pos[0] = slot->bitmap_left;
- g->pos[1] = slot->bitmap_top;
- g->pitch = slot->bitmap.pitch;
+/**
+ * Adjust the glyph width by factor.
+ *
+ * \param factor: -1 (min width) <= 0 (normal) => 1 (max width).
+ */
+static bool UNUSED_FUNCTION(blf_glyph_transform_width)(FT_GlyphSlot glyph, float factor)
+{
+ if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
+ float scale = (factor * 0.4f) + 1.0f; /* 0.6f - 1.4f */
+ FT_Matrix matrix = {to_16dot16(scale), 0, 0, to_16dot16(1)};
+ FT_Outline_Transform(&glyph->outline, &matrix);
+ glyph->advance.x = (FT_Pos)((double)glyph->advance.x * scale);
+ return true;
+ }
+ return false;
+}
- FT_Outline_Get_CBox(&(slot->outline), &bbox);
- g->box.xmin = ((float)bbox.xMin) / 64.0f;
- g->box.xmax = ((float)bbox.xMax) / 64.0f;
- g->box.ymin = ((float)bbox.yMin) / 64.0f;
- g->box.ymax = ((float)bbox.yMax) / 64.0f;
+/**
+ * Transform glyph to fit nicely within a fixed column width.
+ */
+static bool UNUSED_FUNCTION(blf_glyph_transform_monospace)(FT_GlyphSlot glyph, int width)
+{
+ if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
+ int gwidth = (int)(glyph->linearHoriAdvance >> 16);
+ if (gwidth > width) {
+ float scale = (float)width / (float)gwidth;
+ FT_Matrix matrix = {to_16dot16(scale), 0, 0, to_16dot16(1)};
+ /* Narrowing all points also thins vertical strokes. */
+ FT_Outline_Transform(&glyph->outline, &matrix);
+ const FT_Pos extra_x = (int)((float)(gwidth - width) * 5.65f);
+ /* Horizontally widen strokes to counteract narrowing. */
+ FT_Outline_EmboldenXY(&glyph->outline, extra_x, 0);
+ }
+ else if (gwidth < width) {
+ /* Narrow glyphs only need to be centered. */
+ int nudge = (width - gwidth) / 2;
+ FT_Outline_Translate(&glyph->outline, (FT_Pos)nudge * 64, 0);
+ }
+ return true;
+ }
+ return false;
+}
- key = blf_hash(g->c);
- BLI_addhead(&(gc->bucket[key]), g);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Glyph Access (Ensure/Free)
+ * \{ */
+
+/**
+ * Create and return a fully-rendered bitmap glyph.
+ */
+static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
+ FontBLF *glyph_font,
+ FT_UInt glyph_index)
+{
+ if (glyph_font != settings_font) {
+ FT_Set_Char_Size(glyph_font->face,
+ 0,
+ ((FT_F26Dot6)(settings_font->size)) * 64,
+ settings_font->dpi,
+ settings_font->dpi);
+ glyph_font->size = settings_font->size;
+ glyph_font->dpi = settings_font->dpi;
+ }
+
+ FT_GlyphSlot glyph = blf_glyph_load(glyph_font, glyph_index);
+ if (!glyph) {
+ return NULL;
+ }
+
+ if ((settings_font->flags & BLF_ITALIC) != 0) {
+ /* 37.5% of maximum rightward slant results in 6 degree slope, matching italic
+ * version (`DejaVuSans-Oblique.ttf`) of our current font. But a nice median when
+ * checking others. Worth reevaluating if we change default font. We could also
+ * narrow the glyph slightly as most italics do, but this one does not. */
+ blf_glyph_transform_slant(glyph, 0.375f);
+ }
+
+ if ((settings_font->flags & BLF_BOLD) != 0) {
+ /* 70% of maximum weight results in the same amount of boldness and horizontal
+ * expansion as the bold version (`DejaVuSans-Bold.ttf`) of our default font.
+ * Worth reevaluating if we change default font. */
+ blf_glyph_transform_weight(glyph, 0.7f, glyph->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH);
+ }
+
+ if (blf_glyph_render_bitmap(glyph_font, glyph)) {
+ return glyph;
+ }
+ return NULL;
+}
+
+GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode)
+{
+ GlyphBLF *g = blf_glyph_cache_find_glyph(gc, charcode);
+ if (g) {
+ return g;
+ }
- BLI_spin_unlock(font->ft_lib_mutex);
+ /* Glyph might not come from the initial font. */
+ FontBLF *font_with_glyph = font;
+ FT_UInt glyph_index = blf_glyph_index_from_charcode(&font_with_glyph, charcode);
+ /* Glyphs are dynamically created as needed by font rendering. this means that
+ * to make font rendering thread safe we have to do locking here. note that this
+ * must be a lock for the whole library and not just per font, because the font
+ * renderer uses a shared buffer internally. */
+ BLI_spin_lock(font_with_glyph->ft_lib_mutex);
+
+ FT_GlyphSlot glyph = blf_glyph_render(font, font_with_glyph, glyph_index);
+
+ if (glyph) {
+ /* Save this glyph in the initial font's cache. */
+ g = blf_glyph_cache_add_glyph(font, gc, glyph, charcode, glyph_index);
+ }
+
+ BLI_spin_unlock(font_with_glyph->ft_lib_mutex);
return g;
}
@@ -337,6 +481,42 @@ void blf_glyph_free(GlyphBLF *g)
MEM_freeN(g);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Glyph Bounds Calculation
+ * \{ */
+
+static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y)
+{
+ rect->xmin = floorf(x + (float)g->pos[0]);
+ rect->xmax = rect->xmin + (float)g->dims[0];
+ rect->ymin = floorf(y + (float)g->pos[1]);
+ rect->ymax = rect->ymin - (float)g->dims[1];
+}
+
+static void blf_glyph_calc_rect_test(rctf *rect, GlyphBLF *g, float x, float y)
+{
+ /* Intentionally check with `g->advance`, because this is the
+ * width used by BLF_width. This allows that the text slightly
+ * overlaps the clipping border to achieve better alignment. */
+ rect->xmin = floorf(x);
+ rect->xmax = rect->xmin + MIN2(g->advance, (float)g->dims[0]);
+ rect->ymin = floorf(y);
+ rect->ymax = rect->ymin - (float)g->dims[1];
+}
+
+static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y, FontBLF *font)
+{
+ blf_glyph_calc_rect(rect, g, x + (float)font->shadow_x, y + (float)font->shadow_y);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Glyph Drawing
+ * \{ */
+
static void blf_texture_draw(const unsigned char color[4],
const int glyph_size[2],
const int offset,
@@ -395,31 +575,7 @@ static void blf_texture3_draw(const unsigned char color_in[4],
blf_texture_draw(color_in, glyph_size_flag, offset, x1, y1, x2, y2);
}
-static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y)
-{
- rect->xmin = floorf(x + (float)g->pos[0]);
- rect->xmax = rect->xmin + (float)g->dims[0];
- rect->ymin = floorf(y + (float)g->pos[1]);
- rect->ymax = rect->ymin - (float)g->dims[1];
-}
-
-static void blf_glyph_calc_rect_test(rctf *rect, GlyphBLF *g, float x, float y)
-{
- /* Intentionally check with g->advance, because this is the
- * width used by BLF_width. This allows that the text slightly
- * overlaps the clipping border to achieve better alignment. */
- rect->xmin = floorf(x);
- rect->xmax = rect->xmin + MIN2(g->advance, (float)g->dims[0]);
- rect->ymin = floorf(y);
- rect->ymax = rect->ymin - (float)g->dims[1];
-}
-
-static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y, FontBLF *font)
-{
- blf_glyph_calc_rect(rect, g, x + (float)font->shadow_x, y + (float)font->shadow_y);
-}
-
-void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, float y)
+void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, float y)
{
if ((!g->dims[0]) || (!g->dims[1])) {
return;
@@ -526,3 +682,5 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
blf_texture_draw(font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
#endif
}
+
+/** \} */
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 6fd5e8b7503..4e36f522981 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -37,6 +37,10 @@ unsigned int blf_next_p2(unsigned int x);
unsigned int blf_hash(unsigned int val);
char *blf_dir_search(const char *file);
+/**
+ * Some font have additional file with metrics information,
+ * in general, the extension of the file is: `.afm` or `.pfm`
+ */
char *blf_dir_metrics_search(const char *filename);
/* int blf_dir_split(const char *str, char *file, int *size); */ /* UNUSED */
@@ -52,7 +56,7 @@ struct FontBLF *blf_font_new(const char *name, const char *filename);
struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size);
void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, int mem_size);
-void blf_font_size(struct FontBLF *font, unsigned int size, unsigned int dpi);
+void blf_font_size(struct FontBLF *font, float size, unsigned int dpi);
void blf_font_draw(struct FontBLF *font,
const char *str,
size_t str_len,
@@ -65,6 +69,9 @@ void blf_font_draw_ascii(struct FontBLF *font,
const char *str,
size_t str_len,
struct ResultBLF *r_info);
+/**
+ * Use fixed column width, but an utf8 character may occupy multiple columns.
+ */
int blf_font_draw_mono(struct FontBLF *font, const char *str, size_t str_len, int cwidth);
void blf_font_draw_buffer(struct FontBLF *font,
const char *str,
@@ -114,9 +121,9 @@ void blf_font_boundbox_foreach_glyph(struct FontBLF *font,
const char *str,
size_t str_len,
bool (*user_fn)(const char *str,
- const size_t str_step_ofs,
+ size_t str_step_ofs,
const struct rcti *glyph_step_bounds,
- const int glyph_advance_x,
+ int glyph_advance_x,
const struct rctf *glyph_bounds,
const int glyph_bearing[2],
void *user_data),
@@ -125,28 +132,31 @@ void blf_font_boundbox_foreach_glyph(struct FontBLF *font,
int blf_font_count_missing_chars(struct FontBLF *font,
const char *str,
- const size_t str_len,
+ size_t str_len,
int *r_tot_chars);
void blf_font_free(struct FontBLF *font);
-struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font,
- unsigned int size,
- unsigned int dpi);
+/**
+ * Find a glyph cache that matches a size, DPI & styles.
+ */
+struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, float size, unsigned int dpi);
+/**
+ * Create a new glyph cache for the current size, DPI & styles.
+ */
struct GlyphCacheBLF *blf_glyph_cache_new(struct FontBLF *font);
struct GlyphCacheBLF *blf_glyph_cache_acquire(struct FontBLF *font);
void blf_glyph_cache_release(struct FontBLF *font);
void blf_glyph_cache_clear(struct FontBLF *font);
void blf_glyph_cache_free(struct GlyphCacheBLF *gc);
-struct GlyphBLF *blf_glyph_search(struct GlyphCacheBLF *gc, unsigned int c);
-struct GlyphBLF *blf_glyph_add(struct FontBLF *font,
- struct GlyphCacheBLF *gc,
- unsigned int index,
- unsigned int c);
+/**
+ * Create (or load from cache) a fully-rendered bitmap glyph.
+ */
+struct GlyphBLF *blf_glyph_ensure(struct FontBLF *font, struct GlyphCacheBLF *gc, uint charcode);
void blf_glyph_free(struct GlyphBLF *g);
-void blf_glyph_render(
+void blf_glyph_draw(
struct FontBLF *font, struct GlyphCacheBLF *gc, struct GlyphBLF *g, float x, float y);
#ifdef WIN32
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 38d7d7b6e21..46156edbb1f 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -65,7 +65,7 @@ typedef struct GlyphCacheBLF {
struct GlyphCacheBLF *prev;
/* font size. */
- unsigned int size;
+ float size;
/* and dpi. */
unsigned int dpi;
@@ -86,13 +86,6 @@ typedef struct GlyphCacheBLF {
int bitmap_len_landed;
int bitmap_len_alloc;
- /* and the bigger glyph in the font. */
- int glyph_width_max;
- int glyph_height_max;
-
- /* ascender and descender value. */
- float ascender;
- float descender;
} GlyphCacheBLF;
typedef struct GlyphBLF {
@@ -152,7 +145,7 @@ typedef struct FontBufInfoBLF {
struct ColorManagedDisplay *display;
/* and the color, the alphas is get from the glyph!
- * color is srgb space */
+ * color is sRGB space */
float col_init[4];
/* cached conversion from 'col_init' */
unsigned char col_char[4];
@@ -212,7 +205,10 @@ typedef struct FontBLF {
unsigned int dpi;
/* font size. */
- unsigned int size;
+ float size;
+
+ /* Column width when printing monospaced. */
+ int fixed_width;
/* max texture size. */
int tex_size_max;
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index 3153a55b697..06bbd0cf521 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -43,11 +43,6 @@
#include "BLI_strict_flags.h"
-/**
- * This function is used for generating thumbnail previews.
- *
- * \note called from a thread, so it bypasses the normal BLF_* api (which isn't thread-safe).
- */
void BLF_thumb_preview(const char *filename,
const char **draw_str,
const char **i18n_draw_str,
@@ -95,7 +90,7 @@ void BLF_thumb_preview(const char *filename,
const size_t draw_str_i18n_len = strlen(draw_str_i18n);
int draw_str_i18n_nbr = 0;
- blf_font_size(font, (unsigned int)MAX2(font_size_min, font_size_curr), dpi);
+ blf_font_size(font, (float)MAX2(font_size_min, font_size_curr), dpi);
gc = blf_glyph_cache_find(font, font->size, font->dpi);
/* There will be no matching glyph cache if blf_font_size() failed to set font size. */
if (!gc) {
@@ -106,7 +101,7 @@ void BLF_thumb_preview(const char *filename,
font_size_curr -= (font_size_curr / font_shrink);
font_shrink += 1;
- font->pos[1] -= gc->ascender * 1.1f;
+ font->pos[1] -= blf_font_ascender(font) * 1.1f;
/* We fallback to default english strings in case not enough chars are available in current
* font for given translated string (useful in non-latin i18n context, like Chinese,
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index e3954e134da..1801c1ee1c9 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -157,15 +157,6 @@ struct DerivedMesh {
int (*getNumLoops)(DerivedMesh *dm);
int (*getNumPolys)(DerivedMesh *dm);
- /** Copy a single vert/edge/tessellated face from the derived mesh into
- * `*r_{vert/edge/face}`. note that the current implementation
- * of this function can be quite slow, iterating over all
- * elements (editmesh)
- */
- void (*getVert)(DerivedMesh *dm, int index, struct MVert *r_vert);
- void (*getEdge)(DerivedMesh *dm, int index, struct MEdge *r_edge);
- void (*getTessFace)(DerivedMesh *dm, int index, struct MFace *r_face);
-
/** Return a pointer to the entire array of verts/edges/face from the
* derived mesh. if such an array does not exist yet, it will be created,
* and freed on the next ->release(). consider using getVert/Edge/Face if
@@ -251,8 +242,17 @@ struct DerivedMesh {
void (*release)(DerivedMesh *dm);
};
+/**
+ * Utility function to initialize a #DerivedMesh's function pointers to
+ * the default implementation (for those functions which have a default).
+ */
void DM_init_funcs(DerivedMesh *dm);
+/**
+ * Utility function to initialize a #DerivedMesh for the desired number
+ * of vertices, edges and faces (doesn't allocate memory for them, just
+ * sets up the custom data layers)>
+ */
void DM_init(DerivedMesh *dm,
DerivedMeshType type,
int numVerts,
@@ -261,6 +261,10 @@ void DM_init(DerivedMesh *dm,
int numLoops,
int numPolys);
+/**
+ * Utility function to initialize a DerivedMesh for the desired number
+ * of vertices, edges and faces, with a layer setup copied from source
+ */
void DM_from_template_ex(DerivedMesh *dm,
DerivedMesh *source,
DerivedMeshType type,
@@ -285,43 +289,59 @@ void DM_from_template(DerivedMesh *dm,
*/
bool DM_release(DerivedMesh *dm);
+/**
+ * set the #CD_FLAG_NOCOPY flag in custom data layers where the mask is
+ * zero for the layer type, so only layer types specified by the mask
+ * will be copied
+ */
void DM_set_only_copy(DerivedMesh *dm, const struct CustomData_MeshMasks *mask);
-/* adds a vertex/edge/face custom data layer to a DerivedMesh, optionally
+/* Adds a vertex/edge/face custom data layer to a DerivedMesh, optionally
* backed by an external data array
* alloctype defines how the layer is allocated or copied, and how it is
- * freed, see BKE_customdata.h for the different options
- */
+ * freed, see BKE_customdata.h for the different options. */
+
void DM_add_vert_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
void DM_add_edge_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
void DM_add_tessface_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
void DM_add_loop_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
void DM_add_poly_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
-/* custom data access functions
- * return pointer to data from first layer which matches type
- * if they return NULL for valid indices, data doesn't exist
- * note these return pointers - any change modifies the internals of the mesh
- */
+/* -------------------------------------------------------------------- */
+/** \name Custom Data Access Functions
+ *
+ * \return pointer to data from first layer which matches type
+ * if they return NULL for valid indices, data doesn't exist.
+ * \note these return pointers - any change modifies the internals of the mesh.
+ * \{ */
+
void *DM_get_vert_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_edge_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_tessface_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_poly_data(struct DerivedMesh *dm, int index, int type);
-/* custom data layer access functions
- * return pointer to first data layer which matches type (a flat array)
- * if they return NULL, data doesn't exist
- * note these return pointers - any change modifies the internals of the mesh
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom Data Layer Access Functions
+ *
+ * \return pointer to first data layer which matches type (a flat array)
+ * if they return NULL, data doesn't exist.
+ * \note these return pointers - any change modifies the internals of the mesh.
+ * \{ */
+
void *DM_get_vert_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_edge_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_tessface_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_poly_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_loop_data_layer(struct DerivedMesh *dm, int type);
-/* custom data copy functions
+/** \} */
+
+/**
+ * Custom data copy functions
* copy count elements from source_index in source to dest_index in dest
- * these copy all layers for which the CD_FLAG_NOCOPY flag is not set
+ * these copy all layers for which the CD_FLAG_NOCOPY flag is not set.
*/
void DM_copy_vert_data(struct DerivedMesh *source,
struct DerivedMesh *dest,
@@ -329,13 +349,26 @@ void DM_copy_vert_data(struct DerivedMesh *source,
int dest_index,
int count);
-/* Sets up mpolys for a DM based on face iterators in source. */
+/**
+ * Sets up mpolys for a DM based on face iterators in source.
+ */
void DM_DupPolys(DerivedMesh *source, DerivedMesh *target);
void DM_ensure_normals(DerivedMesh *dm);
+/**
+ * Ensure the array is large enough.
+ *
+ * \note This function must always be thread-protected by caller.
+ * It should only be used by internal code.
+ */
void DM_ensure_looptri_data(DerivedMesh *dm);
+/**
+ * Interpolates vertex data from the vertices indexed by `src_indices` in the
+ * source mesh using the given weights and stores the result in the vertex
+ * indexed by `dest_index` in the `dest` mesh.
+ */
void DM_interp_vert_data(struct DerivedMesh *source,
struct DerivedMesh *dest,
int *src_indices,
@@ -343,9 +376,11 @@ void DM_interp_vert_data(struct DerivedMesh *source,
int count,
int dest_index);
-void mesh_get_mapped_verts_coords(struct Mesh *me_eval, float (*r_cos)[3], const int totcos);
+void mesh_get_mapped_verts_coords(struct Mesh *me_eval, float (*r_cos)[3], int totcos);
-/* same as above but won't use render settings */
+/**
+ * Same as above but won't use render settings.
+ */
struct Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *,
@@ -355,12 +390,6 @@ struct Mesh *editbmesh_get_eval_cage_from_orig(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *obedit,
const struct CustomData_MeshMasks *dataMask);
-struct Mesh *editbmesh_get_eval_cage_and_final(struct Depsgraph *depsgraph,
- struct Scene *scene,
- struct Object *,
- struct BMEditMesh *em,
- const struct CustomData_MeshMasks *dataMask,
- struct Mesh **r_final);
float (*editbmesh_vert_coords_alloc(struct BMEditMesh *em, int *r_vert_len))[3];
bool editbmesh_modifier_is_enabled(struct Scene *scene,
@@ -370,7 +399,6 @@ bool editbmesh_modifier_is_enabled(struct Scene *scene,
void makeDerivedMesh(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
- struct BMEditMesh *em,
const struct CustomData_MeshMasks *dataMask);
void DM_calc_loop_tangents(DerivedMesh *dm,
@@ -378,14 +406,6 @@ void DM_calc_loop_tangents(DerivedMesh *dm,
const char (*tangent_names)[MAX_NAME],
int tangent_names_len);
-/* debug only */
-#ifndef NDEBUG
-char *DM_debug_info(DerivedMesh *dm);
-void DM_debug_print(DerivedMesh *dm);
-
-bool DM_is_valid(DerivedMesh *dm);
-#endif
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 9f69c5e3976..0b09bfd8730 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -79,70 +79,143 @@ typedef enum eAction_TransformFlags {
ACT_TRANS_ALL = (ACT_TRANS_ONLY | ACT_TRANS_PROP),
} eAction_TransformFlags;
-/* Return flags indicating which transforms the given object/posechannel has
+/**
+ * Return flags indicating which transforms the given object/posechannel has
* - if 'curves' is provided, a list of links to these curves are also returned
- * whose nodes WILL NEED FREEING
+ * whose nodes WILL NEED FREEING.
*/
short action_get_item_transforms(struct bAction *act,
struct Object *ob,
struct bPoseChannel *pchan,
ListBase *curves);
-/* Some kind of bounding box operation on the action */
+/**
+ * Calculate the extents of given action.
+ */
void calc_action_range(const struct bAction *act, float *start, float *end, short incl_modifiers);
-/* Does action have any motion data at all? */
+/* Retrieve the intended playback frame range, using the manually set range if available,
+ * or falling back to scanning F-Curves for their first & last frames otherwise. */
+void BKE_action_get_frame_range(const struct bAction *act, float *r_start, float *r_end);
+
+/**
+ * Check if the given action has any keyframes.
+ */
bool action_has_motion(const struct bAction *act);
+/**
+ * Is the action configured as cyclic.
+ */
+bool BKE_action_is_cyclic(const struct bAction *act);
+
/* Action Groups API ----------------- */
-/* Get the active action-group for an Action */
+/**
+ * Get the active action-group for an Action.
+ */
struct bActionGroup *get_active_actiongroup(struct bAction *act);
-/* Make the given Action Group the active one */
+/**
+ * Make the given Action-Group the active one.
+ */
void set_active_action_group(struct bAction *act, struct bActionGroup *agrp, short select);
-/* Sync colors used for action/bone group with theme settings */
+/**
+ * Sync colors used for action/bone group with theme settings.
+ */
void action_group_colors_sync(struct bActionGroup *grp, const struct bActionGroup *ref_grp);
-/* Add a new action group with the given name to the action */
+/**
+ * Add a new action group with the given name to the action>
+ */
struct bActionGroup *action_groups_add_new(struct bAction *act, const char name[]);
-/* Add given channel into (active) group */
+/**
+ * Add given channel into (active) group
+ * - assumes that channel is not linked to anything anymore
+ * - always adds at the end of the group
+ */
void action_groups_add_channel(struct bAction *act,
struct bActionGroup *agrp,
struct FCurve *fcurve);
-/* Remove the given channel from all groups */
+/**
+ * Remove the given channel from all groups.
+ */
void action_groups_remove_channel(struct bAction *act, struct FCurve *fcu);
-/* Reconstruct group channel pointers. */
+/**
+ * Reconstruct group channel pointers.
+ * Assumes that the groups referred to by the FCurves are already in act->groups.
+ * Reorders the main channel list to match group order.
+ */
void BKE_action_groups_reconstruct(struct bAction *act);
-/* Find a group with the given name */
+/**
+ * Find a group with the given name.
+ */
struct bActionGroup *BKE_action_group_find_name(struct bAction *act, const char name[]);
-/* Clear all 'temp' flags on all groups */
+/**
+ * Clear all 'temp' flags on all groups.
+ */
void action_groups_clear_tempflags(struct bAction *act);
+/**
+ * Return whether the action has one unique point in time keyed.
+ *
+ * This is mostly for the pose library, which will have different behavior depending on whether an
+ * Action corresponds to a "pose" (one keyframe) or "animation snippet" (multiple keyframes).
+ *
+ * \return `false` when there is no keyframe at all or keys on different points in time, `true`
+ * when exactly one point in time is keyed.
+ */
+bool BKE_action_has_single_frame(const struct bAction *act);
+
/* Pose API ----------------- */
void BKE_pose_channel_free(struct bPoseChannel *pchan);
+/**
+ * Deallocates a pose channel.
+ * Does not free the pose channel itself.
+ */
void BKE_pose_channel_free_ex(struct bPoseChannel *pchan, bool do_id_user);
+/**
+ * Clears the runtime cache of a pose channel without free.
+ */
void BKE_pose_channel_runtime_reset(struct bPoseChannel_Runtime *runtime);
+/**
+ * Reset all non-persistent fields.
+ */
void BKE_pose_channel_runtime_reset_on_copy(struct bPoseChannel_Runtime *runtime);
+/**
+ * Deallocates runtime cache of a pose channel
+ */
void BKE_pose_channel_runtime_free(struct bPoseChannel_Runtime *runtime);
+/**
+ * Deallocates runtime cache of a pose channel's B-Bone shape.
+ */
void BKE_pose_channel_free_bbone_cache(struct bPoseChannel_Runtime *runtime);
void BKE_pose_channels_free(struct bPose *pose);
+/**
+ * Removes and deallocates all channels from a pose.
+ * Does not free the pose itself.
+ */
void BKE_pose_channels_free_ex(struct bPose *pose, bool do_id_user);
+/**
+ * Removes the hash for quick lookup of channels, must be done when adding/removing channels.
+ */
void BKE_pose_channels_hash_ensure(struct bPose *pose);
void BKE_pose_channels_hash_free(struct bPose *pose);
+/**
+ * Selectively remove pose channels.
+ */
void BKE_pose_channels_remove(struct Object *ob,
bool (*filter_fn)(const char *bone_name, void *user_data),
void *user_data);
@@ -150,18 +223,79 @@ void BKE_pose_channels_remove(struct Object *ob,
void BKE_pose_free_data_ex(struct bPose *pose, bool do_id_user);
void BKE_pose_free_data(struct bPose *pose);
void BKE_pose_free(struct bPose *pose);
+/**
+ * Removes and deallocates all data from a pose, and also frees the pose.
+ */
void BKE_pose_free_ex(struct bPose *pose, bool do_id_user);
+/**
+ * Allocate a new pose on the heap, and copy the src pose and its channels
+ * into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL.
+ *
+ * \param dst: Should be freed already, makes entire duplicate.
+ */
void BKE_pose_copy_data_ex(struct bPose **dst,
const struct bPose *src,
- const int flag,
- const bool copy_constraints);
-void BKE_pose_copy_data(struct bPose **dst, const struct bPose *src, const bool copy_constraints);
+ int flag,
+ bool copy_constraints);
+void BKE_pose_copy_data(struct bPose **dst, const struct bPose *src, bool copy_constraints);
+/**
+ * Copy the internal members of each pose channel including constraints
+ * and ID-Props, used when duplicating bones in edit-mode.
+ * (unlike copy_pose_channel_data which only does posing-related stuff).
+ *
+ * \note use when copying bones in edit-mode (on returned value from #BKE_pose_channel_ensure)
+ */
void BKE_pose_channel_copy_data(struct bPoseChannel *pchan, const struct bPoseChannel *pchan_from);
void BKE_pose_channel_session_uuid_generate(struct bPoseChannel *pchan);
+/**
+ * Return a pointer to the pose channel of the given name
+ * from this pose.
+ */
struct bPoseChannel *BKE_pose_channel_find_name(const struct bPose *pose, const char *name);
-struct bPoseChannel *BKE_pose_channel_active(struct Object *ob);
+/**
+ * Checks if the bone is on a visible armature layer
+ *
+ * \return true if on a visible layer, false otherwise.
+ */
+bool BKE_pose_is_layer_visible(const struct bArmature *arm, const struct bPoseChannel *pchan);
+/**
+ * Find the active pose-channel for an object
+ *
+ * \param check_arm_layer: checks if the bone is on a visible armature layer (this might be skipped
+ * (e.g. for "Show Active" from the Outliner).
+ * \return #bPoseChannel if found or NULL.
+ * \note #Object, not #bPose is used here, as we need info (layer/active bone) from Armature.
+ */
+struct bPoseChannel *BKE_pose_channel_active(struct Object *ob, bool check_arm_layer);
+/**
+ * Find the active pose-channel for an object if it is on a visible armature layer
+ * (calls #BKE_pose_channel_active with check_arm_layer set to true)
+ *
+ * \return #bPoseChannel if found or NULL.
+ * \note #Object, not #bPose is used here, as we need info (layer/active bone) from Armature.
+ */
+struct bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob);
+/**
+ * Use this when detecting the "other selected bone",
+ * when we have multiple armatures in pose mode.
+ *
+ * In this case the active-selected is an obvious choice when finding the target for a
+ * constraint for eg. however from the users perspective the active pose bone of the
+ * active object is the _real_ active bone, so any other non-active selected bone
+ * is a candidate for being the other selected bone, see: T58447.
+ */
struct bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob);
+/**
+ * Looks to see if the channel with the given name already exists
+ * in this pose - if not a new one is allocated and initialized.
+ *
+ * \note Use with care, not on Armature poses but for temporal ones.
+ * \note (currently used for action constraints and in rebuild_pose).
+ */
struct bPoseChannel *BKE_pose_channel_ensure(struct bPose *pose, const char *name);
+/**
+ * \see #ED_armature_ebone_get_mirrored (edit-mode, matching function)
+ */
struct bPoseChannel *BKE_pose_channel_get_mirrored(const struct bPose *pose, const char *name);
void BKE_pose_check_uuids_unique_and_report(const struct bPose *pose);
@@ -170,37 +304,60 @@ void BKE_pose_check_uuids_unique_and_report(const struct bPose *pose);
bool BKE_pose_channels_is_valid(const struct bPose *pose);
#endif
-/* sets constraint flags */
+/**
+ * Checks for IK constraint, Spline IK, and also for Follow-Path constraint.
+ * can do more constraints flags later. pose should be entirely OK.
+ */
void BKE_pose_update_constraint_flags(struct bPose *pose);
-/* tag constraint flags for update */
+/**
+ * Tag constraint flags for update.
+ */
void BKE_pose_tag_update_constraint_flags(struct bPose *pose);
-/* return the name of structure pointed by pose->ikparam */
+/**
+ * Return the name of structure pointed by `pose->ikparam`.
+ */
const char *BKE_pose_ikparam_get_name(struct bPose *pose);
-/* allocate and initialize pose->ikparam according to pose->iksolver */
+/**
+ * Allocate and initialize `pose->ikparam` according to `pose->iksolver`.
+ */
void BKE_pose_ikparam_init(struct bPose *pose);
-/* initialize a bItasc structure with default value */
+/**
+ * Initialize a #bItasc structure with default value.
+ */
void BKE_pose_itasc_init(struct bItasc *itasc);
-/* Checks if a bone is part of an IK chain or not */
+/**
+ * Checks if a bone is part of an IK chain or not.
+ */
bool BKE_pose_channel_in_IK_chain(struct Object *ob, struct bPoseChannel *pchan);
/* Bone Groups API --------------------- */
-/* Adds a new bone-group */
+/**
+ * Adds a new bone-group (name may be NULL).
+ */
struct bActionGroup *BKE_pose_add_group(struct bPose *pose, const char *name);
-/* Remove a bone-group */
-void BKE_pose_remove_group(struct bPose *pose, struct bActionGroup *grp, const int index);
-/* Remove the matching bone-group from its index */
-void BKE_pose_remove_group_index(struct bPose *pose, const int index);
+/**
+ * Remove the given bone-group (expects 'virtual' index (+1 one, used by active_group etc.))
+ * index might be invalid ( < 1), in which case it will be find from grp.
+ */
+void BKE_pose_remove_group(struct bPose *pose, struct bActionGroup *grp, int index);
+/**
+ * Remove the indexed bone-group (expects 'virtual' index (+1 one, used by active_group etc.)).
+ */
+void BKE_pose_remove_group_index(struct bPose *pose, int index);
/* Assorted Evaluation ----------------- */
-/* Used for the Action Constraint */
+/**
+ * For the calculation of the effects of an Action at the given frame on an object
+ * This is currently only used for the Action Constraint
+ */
void what_does_obaction(struct Object *ob,
struct Object *workob,
struct bPose *pose,
@@ -211,11 +368,18 @@ void what_does_obaction(struct Object *ob,
/* for proxy */
void BKE_pose_copy_pchan_result(struct bPoseChannel *pchanto,
const struct bPoseChannel *pchanfrom);
+/**
+ * Both poses should be in sync.
+ */
bool BKE_pose_copy_result(struct bPose *to, struct bPose *from);
-/* Clear transforms. */
+/**
+ * Zero the pose transforms for the entire pose or only for selected bones.
+ */
void BKE_pose_rest(struct bPose *pose, bool selected_bones_only);
-/* Tag pose for recalc. Also tag all related data to be recalc. */
+/**
+ * Tag pose for recalculation. Also tag all related data to be recalculated.
+ */
void BKE_pose_tag_recalc(struct Main *bmain, struct bPose *pose);
void BKE_pose_blend_write(struct BlendWriter *writer, struct bPose *pose, struct bArmature *arm);
diff --git a/source/blender/blenkernel/BKE_anim_data.h b/source/blender/blenkernel/BKE_anim_data.h
index 14ab9f21424..81c49917b63 100644
--- a/source/blender/blenkernel/BKE_anim_data.h
+++ b/source/blender/blenkernel/BKE_anim_data.h
@@ -43,48 +43,81 @@ struct bAction;
/* ************************************* */
/* AnimData API */
-/* Check if the given ID-block can have AnimData */
-bool id_type_can_have_animdata(const short id_type);
+/**
+ * Check if the given ID-block can have AnimData.
+ */
+bool id_type_can_have_animdata(short id_type);
bool id_can_have_animdata(const struct ID *id);
-/* Get AnimData from the given ID-block */
+/**
+ * Get #AnimData from the given ID-block.
+ */
struct AnimData *BKE_animdata_from_id(struct ID *id);
-/* Ensure AnimData is present in the ID-block (when supported). */
+/**
+ * Ensure #AnimData exists in the given ID-block (when supported).
+ */
struct AnimData *BKE_animdata_ensure_id(struct ID *id);
-/* Set active action used by AnimData from the given ID-block */
+/**
+ * Set active action used by AnimData from the given ID-block.
+ *
+ * Called when user tries to change the active action of an #AnimData block
+ * (via RNA, Outliner, etc.)
+ *
+ * \param reports: Can be NULL.
+ * \param id: The owner of the animation data
+ * \param act: The Action to set, or NULL to clear.
+ *
+ * \return true when the action was successfully updated, false otherwise.
+ */
bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act);
bool BKE_animdata_action_editable(const struct AnimData *adt);
-/* Ensure that the action's idroot is set correctly given the ID type of the owner.
- * Return true if it is, false if it was already set to an incompatible type. */
+/**
+ * Ensure that the action's idroot is set correctly given the ID type of the owner.
+ * Return true if it is, false if it was already set to an incompatible type.
+ */
bool BKE_animdata_action_ensure_idroot(const struct ID *owner, struct bAction *action);
-/* Free AnimData */
-void BKE_animdata_free(struct ID *id, const bool do_id_user);
+/**
+ * Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer.
+ */
+void BKE_animdata_free(struct ID *id, bool do_id_user);
-/* Return true if the ID-block has non-empty AnimData. */
+/**
+ * Return true if the ID-block has non-empty AnimData.
+ */
bool BKE_animdata_id_is_animated(const struct ID *id);
+/**
+ * Callback used by lib_query to walk over all ID usages
+ * (mimics `foreach_id` callback of #IDTypeInfo structure).
+ */
void BKE_animdata_foreach_id(struct AnimData *adt, struct LibraryForeachIDData *data);
-/* Copy AnimData */
-struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const int flag);
+/**
+ * Make a copy of the given AnimData - to be used when copying data-blocks.
+ * \param flag: Control ID pointers management,
+ * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
+ * \return The copied animdata.
+ */
+struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, int flag);
-/* Copy AnimData */
-bool BKE_animdata_copy_id(struct Main *bmain,
- struct ID *id_to,
- struct ID *id_from,
- const int flag);
+/**
+ * \param flag: Control ID pointers management,
+ * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
+ * \return true is successfully copied.
+ */
+bool BKE_animdata_copy_id(struct Main *bmain, struct ID *id_to, struct ID *id_from, int flag);
-/* Copy AnimData Actions */
+/**
+ * Copy AnimData Actions.
+ */
void BKE_animdata_copy_id_action(struct Main *bmain, struct ID *id);
-void BKE_animdata_duplicate_id_action(struct Main *bmain,
- struct ID *id,
- const uint duplicate_flags);
+void BKE_animdata_duplicate_id_action(struct Main *bmain, struct ID *id, uint duplicate_flags);
/* Merge copies of data from source AnimData block */
typedef enum eAnimData_MergeCopy_Modes {
@@ -98,6 +131,9 @@ typedef enum eAnimData_MergeCopy_Modes {
ADT_MERGECOPY_SRC_REF = 2,
} eAnimData_MergeCopy_Modes;
+/**
+ * Merge copies of the data from the src AnimData into the destination AnimData.
+ */
void BKE_animdata_merge_copy(struct Main *bmain,
struct ID *dst_id,
struct ID *src_id,
diff --git a/source/blender/blenkernel/BKE_anim_path.h b/source/blender/blenkernel/BKE_anim_path.h
index 9db63080fd9..6bc09eb35ed 100644
--- a/source/blender/blenkernel/BKE_anim_path.h
+++ b/source/blender/blenkernel/BKE_anim_path.h
@@ -35,12 +35,21 @@ struct Object;
int BKE_anim_path_get_array_size(const struct CurveCache *curve_cache);
float BKE_anim_path_get_length(const struct CurveCache *curve_cache);
-/* This function populates the 'ob->runtime.curve_cache->anim_path_accum_length' data.
+/**
+ * This function populates the 'ob->runtime.curve_cache->anim_path_accum_length' data.
* You should never have to call this manually as it should already have been called by
* 'BKE_displist_make_curveTypes'. Do not call this manually unless you know what you are doing.
*/
void BKE_anim_path_calc_data(struct Object *ob);
+/**
+ * Calculate the deformation implied by the curve path at a given parametric position,
+ * and returns whether this operation succeeded.
+ *
+ * \param ctime: Time is normalized range <0-1>.
+ *
+ * \return success.
+ */
bool BKE_where_on_path(const struct Object *ob,
float ctime,
float r_vec[4],
diff --git a/source/blender/blenkernel/BKE_anim_visualization.h b/source/blender/blenkernel/BKE_anim_visualization.h
index 4e86abeed8d..3b8c91b7fd2 100644
--- a/source/blender/blenkernel/BKE_anim_visualization.h
+++ b/source/blender/blenkernel/BKE_anim_visualization.h
@@ -38,13 +38,34 @@ struct bPoseChannel;
/* ---------------------------------------------------- */
/* Animation Visualization */
+/**
+ * Initialize the default settings for animation visualization.
+ */
void animviz_settings_init(struct bAnimVizSettings *avs);
+/**
+ * Make a copy of motion-path data, so that viewing with copy on write works.
+ */
struct bMotionPath *animviz_copy_motionpath(const struct bMotionPath *mpath_src);
+/**
+ * Free the given motion path's cache.
+ */
void animviz_free_motionpath_cache(struct bMotionPath *mpath);
+/**
+ * Free the given motion path instance and its data.
+ * \note this frees the motion path given!
+ */
void animviz_free_motionpath(struct bMotionPath *mpath);
+/**
+ * Setup motion paths for the given data.
+ * \note Only used when explicitly calculating paths on bones which may/may not be consider already
+ *
+ * \param scene: Current scene (for frame ranges, etc.)
+ * \param ob: Object to add paths for (must be provided)
+ * \param pchan: Posechannel to add paths for (optional; if not provided, object-paths are assumed)
+ */
struct bMotionPath *animviz_verify_motionpaths(struct ReportList *reports,
struct Scene *scene,
struct Object *ob,
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 07da9d75e59..4845807de39 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -69,12 +69,17 @@ AnimationEvalContext BKE_animsys_eval_context_construct_at(
/* ************************************* */
/* KeyingSets API */
-/* Used to create a new 'custom' KeyingSet for the user,
- * that will be automatically added to the stack */
+/**
+ * Used to create a new 'custom' KeyingSet for the user,
+ * that will be automatically added to the stack.
+ */
struct KeyingSet *BKE_keyingset_add(
struct ListBase *list, const char idname[], const char name[], short flag, short keyingflag);
-/* Add a path to a KeyingSet */
+/**
+ * Add a path to a KeyingSet. Nothing is returned for now.
+ * Checks are performed to ensure that destination is appropriate for the KeyingSet in question
+ */
struct KS_Path *BKE_keyingset_add_path(struct KeyingSet *ks,
struct ID *id,
const char group_name[],
@@ -83,7 +88,10 @@ struct KS_Path *BKE_keyingset_add_path(struct KeyingSet *ks,
short flag,
short groupmode);
-/* Find the destination matching the criteria given */
+/**
+ * Find the destination matching the criteria given.
+ * TODO: do we want some method to perform partial matches too?
+ */
struct KS_Path *BKE_keyingset_find_path(struct KeyingSet *ks,
struct ID *id,
const char group_name[],
@@ -113,7 +121,15 @@ void BKE_keyingsets_blend_read_expand(struct BlendExpander *expander, struct Lis
/* ************************************* */
/* Path Fixing API */
-/* Get a "fixed" version of the given path (oldPath) */
+/**
+ * Get a "fixed" version of the given path `old_path`.
+ *
+ * This is just an external wrapper for the RNA-Path fixing function,
+ * with input validity checks on top of the basic method.
+ *
+ * \note it is assumed that the structure we're replacing is `<prefix><["><name><"]>`
+ * i.e. `pose.bones["Bone"]`.
+ */
char *BKE_animsys_fix_rna_path_rename(struct ID *owner_id,
char *old_path,
const char *prefix,
@@ -123,7 +139,15 @@ char *BKE_animsys_fix_rna_path_rename(struct ID *owner_id,
int newSubscript,
bool verify_paths);
-/* Fix all the paths for the given ID + Action */
+/**
+ * Fix all the paths for the given ID + Action.
+ *
+ * This is just an external wrapper for the F-Curve fixing function,
+ * with input validity checks on top of the basic method.
+ *
+ * \note it is assumed that the structure we're replacing is `<prefix><["><name><"]>`
+ * i.e. `pose.bones["Bone"]`.
+ */
void BKE_action_fix_paths_rename(struct ID *owner_id,
struct bAction *act,
const char *prefix,
@@ -133,7 +157,12 @@ void BKE_action_fix_paths_rename(struct ID *owner_id,
int newSubscript,
bool verify_paths);
-/* Fix all the paths for the given ID+AnimData */
+/**
+ * Fix all the paths for the given ID+AnimData
+ *
+ * \note it is assumed that the structure we're replacing is `<prefix><["><name><"]>`
+ * i.e. `pose.bones["Bone"]`.
+ */
void BKE_animdata_fix_paths_rename(struct ID *owner_id,
struct AnimData *adt,
struct ID *ref_id,
@@ -144,24 +173,31 @@ void BKE_animdata_fix_paths_rename(struct ID *owner_id,
int newSubscript,
bool verify_paths);
-/* Fix all the paths for the entire database... */
-void BKE_animdata_fix_paths_rename_all(struct ID *ref_id,
- const char *prefix,
- const char *oldName,
- const char *newName);
-
-/* Fix all the paths for the entire bmain with extra parameters. */
+/**
+ * Fix all RNA-Paths throughout the database (directly access the #Global.main version).
+ *
+ * \note it is assumed that the structure we're replacing is `<prefix><["><name><"]>`
+ * i.e. `pose.bones["Bone"]`
+ */
void BKE_animdata_fix_paths_rename_all_ex(struct Main *bmain,
struct ID *ref_id,
const char *prefix,
const char *oldName,
const char *newName,
- const int oldSubscript,
- const int newSubscript,
- const bool verify_paths);
+ int oldSubscript,
+ int newSubscript,
+ bool verify_paths);
+
+/** See #BKE_animdata_fix_paths_rename_all_ex */
+void BKE_animdata_fix_paths_rename_all(struct ID *ref_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName);
-/* Fix the path after removing elements that are not ID (e.g., node).
- * Return true if any animation data was affected. */
+/**
+ * Fix the path after removing elements that are not ID (e.g., node).
+ * Return true if any animation data was affected.
+ */
bool BKE_animdata_fix_paths_remove(struct ID *id, const char *path);
/* -------------------------------------- */
@@ -172,17 +208,19 @@ typedef struct AnimationBasePathChange {
const char *dst_basepath;
} AnimationBasePathChange;
-/* Move animation data from src to destination if its paths are based on basepaths */
+/**
+ * Move animation data from source to destination if its paths are based on `basepaths`.
+ *
+ * Transfer the animation data from `srcID` to `dstID` where the `srcID` animation data
+ * is based off `basepath`, creating new #AnimData and associated data as necessary.
+ *
+ * \param basepaths: A list of #AnimationBasePathChange.
+ */
void BKE_animdata_transfer_by_basepath(struct Main *bmain,
struct ID *srcID,
struct ID *dstID,
struct ListBase *basepaths);
-char *BKE_animdata_driver_path_hack(struct bContext *C,
- struct PointerRNA *ptr,
- struct PropertyRNA *prop,
- char *base_path);
-
/* ************************************* */
/* Batch AnimData API */
@@ -195,7 +233,7 @@ typedef void (*ID_FCurve_Edit_Callback)(struct ID *id, struct FCurve *fcu, void
/* Loop over all datablocks applying callback */
void BKE_animdata_main_cb(struct Main *bmain, ID_AnimData_Edit_Callback func, void *user_data);
-/* Loop over all datablocks applying callback to all its F-Curves */
+/** Apply the given callback function on all F-Curves attached to data in `main` database. */
void BKE_fcurves_main_cb(struct Main *bmain, ID_FCurve_Edit_Callback func, void *user_data);
/* Look over all f-curves of a given ID. */
@@ -208,11 +246,32 @@ void BKE_fcurves_id_cb(struct ID *id, ID_FCurve_Edit_Callback func, void *user_d
typedef struct NlaKeyframingContext NlaKeyframingContext;
+/**
+ * Prepare data necessary to compute correct keyframe values for NLA strips
+ * with non-Replace mode or influence different from 1.
+ *
+ * \param cache: List used to cache contexts for reuse when keying
+ * multiple channels in one operation.
+ * \param ptr: RNA pointer to the Object with the animation.
+ * \return Keyframing context, or NULL if not necessary.
+ */
struct NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
struct ListBase *cache,
struct PointerRNA *ptr,
struct AnimData *adt,
const struct AnimationEvalContext *anim_eval_context);
+/**
+ * Apply correction from the NLA context to the values about to be keyframed.
+ *
+ * \param context: Context to use (may be NULL).
+ * \param prop_ptr: Property about to be keyframed.
+ * \param[in,out] values: Array of property values to adjust.
+ * \param count: Number of values in the array.
+ * \param index: Index of the element about to be updated, or -1.
+ * \param[out] r_force_all: Set to true if all channels must be inserted. May be NULL.
+ * \return False if correction fails due to a division by zero,
+ * or null r_force_all when all channels are required.
+ */
bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
struct PointerRNA *prop_ptr,
struct PropertyRNA *prop,
@@ -220,6 +279,9 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
int count,
int index,
bool *r_force_all);
+/**
+ * Free all cached contexts from the list.
+ */
void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache);
/* ************************************* */
@@ -237,19 +299,35 @@ typedef enum eAnimData_Recalc {
bool BKE_animsys_rna_path_resolve(struct PointerRNA *ptr,
const char *rna_path,
- const int array_index,
+ int array_index,
struct PathResolvedRNA *r_result);
bool BKE_animsys_read_from_rna_path(struct PathResolvedRNA *anim_rna, float *r_value);
-bool BKE_animsys_write_to_rna_path(struct PathResolvedRNA *anim_rna, const float value);
+/**
+ * Write the given value to a setting using RNA, and return success.
+ */
+bool BKE_animsys_write_to_rna_path(struct PathResolvedRNA *anim_rna, float value);
-/* Evaluation loop for evaluating animation data. */
+/**
+ * Evaluation loop for evaluation animation data
+ *
+ * This assumes that the animation-data provided belongs to the ID block in question,
+ * and that the flags for which parts of the animation-data settings need to be recalculated
+ * have been set already by the depsgraph. Now, we use the recalculate.
+ */
void BKE_animsys_evaluate_animdata(struct ID *id,
struct AnimData *adt,
const struct AnimationEvalContext *anim_eval_context,
eAnimData_Recalc recalc,
- const bool flush_to_original);
+ bool flush_to_original);
-/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only */
+/**
+ * Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only
+ *
+ * This will evaluate only the animation info available in the animation data-blocks
+ * encountered. In order to enforce the system by which some settings controlled by a
+ * 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a
+ * standard 'root') block are overridden by a larger 'user'
+ */
void BKE_animsys_evaluate_all_animation(struct Main *main,
struct Depsgraph *depsgraph,
float ctime);
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index fee52479cd0..a7baaed141f 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -16,62 +16,150 @@
#pragma once
/** \file
- * \ingroup bli
+ * \ingroup bke
+ *
+ * \note on naming: typical _get() suffix is omitted here,
+ * since its the main purpose of the API.
*/
#include <stddef.h>
+#include "BLI_compiler_attrs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
struct ListBase;
+/**
+ * Sanity check to ensure correct API use in debug mode.
+ *
+ * Run this once the first level of arguments has been passed so we can be sure
+ * `--env-system-datafiles`, and other `--env-*` arguments has been passed.
+ *
+ * Without this any callers to this module that run early on,
+ * will miss out on changes from parsing arguments.
+ */
void BKE_appdir_init(void);
void BKE_appdir_exit(void);
-/* note on naming: typical _get() suffix is omitted here,
- * since its the main purpose of the API. */
-const char *BKE_appdir_folder_default(void);
+/**
+ * Get the folder that's the "natural" starting point for browsing files on an OS.
+ * - Unix: `$HOME`
+ * - Windows: `%userprofile%/Documents`
+ *
+ * \note On Windows `Users/{MyUserName}/Documents` is used as it's the default location to save
+ * documents.
+ */
+const char *BKE_appdir_folder_default(void) ATTR_WARN_UNUSED_RESULT;
+const char *BKE_appdir_folder_root(void) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
+const char *BKE_appdir_folder_default_or_root(void) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
+/**
+ * Get the user's home directory, i.e.
+ * - Unix: `$HOME`
+ * - Windows: `%userprofile%`
+ */
const char *BKE_appdir_folder_home(void);
+/**
+ * Get the user's document directory, i.e.
+ * - Linux: `$HOME/Documents`
+ * - Windows: `%userprofile%/Documents`
+ *
+ * If this can't be found using OS queries (via Ghost), try manually finding it.
+ *
+ * \returns True if the path is valid and points to an existing directory.
+ */
bool BKE_appdir_folder_documents(char *dir);
-bool BKE_appdir_folder_id_ex(const int folder_id,
- const char *subfolder,
- char *path,
- size_t path_len);
-const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder);
-const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder);
-const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder);
-const char *BKE_appdir_folder_id_version(const int folder_id,
- const int version,
- const bool check_is_dir);
+/**
+ * Get the user's cache directory, i.e.
+ * - Linux: `$HOME/.cache/blender/`
+ * - Windows: `%USERPROFILE%\AppData\Local\Blender Foundation\Blender\`
+ * - MacOS: `/Library/Caches/Blender`
+ *
+ * \returns True if the path is valid. It doesn't create or checks format
+ * if the `blender` folder exists. It does check if the parent of the path exists.
+ */
+bool BKE_appdir_folder_caches(char *r_path, size_t path_len);
+/**
+ * Get a folder out of the \a folder_id presets for paths.
+ *
+ * \param subfolder: The name of a directory to check for,
+ * this may contain path separators but must resolve to a directory, checked with #BLI_is_dir.
+ * \return The path if found, NULL string if not.
+ */
+bool BKE_appdir_folder_id_ex(int folder_id, const char *subfolder, char *path, size_t path_len);
+const char *BKE_appdir_folder_id(int folder_id, const char *subfolder);
+/**
+ * Returns the path to a folder in the user area, creating it if it doesn't exist.
+ */
+const char *BKE_appdir_folder_id_create(int folder_id, const char *subfolder);
+/**
+ * Returns the path to a folder in the user area without checking that it actually exists first.
+ */
+const char *BKE_appdir_folder_id_user_notest(int folder_id, const char *subfolder);
+/**
+ * Returns the path of the top-level version-specific local, user or system directory.
+ * If check_is_dir, then the result will be NULL if the directory doesn't exist.
+ */
+const char *BKE_appdir_folder_id_version(int folder_id, int version, bool check_is_dir);
+/**
+ * Check if this is an install with user files kept together
+ * with the Blender executable and its installation files.
+ */
bool BKE_appdir_app_is_portable_install(void);
+/**
+ * Return true if templates exist
+ */
bool BKE_appdir_app_template_any(void);
bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len);
bool BKE_appdir_app_template_has_userpref(const char *app_template);
void BKE_appdir_app_templates(struct ListBase *templates);
-/* Initialize path to program executable */
+/**
+ * Initialize path to program executable.
+ */
void BKE_appdir_program_path_init(const char *argv0);
+/**
+ * Path to executable
+ */
const char *BKE_appdir_program_path(void);
+/**
+ * Path to directory of executable
+ */
const char *BKE_appdir_program_dir(void);
-/* Return OS fonts directory. */
+/**
+ * Gets a good default directory for fonts.
+ */
bool BKE_appdir_font_folder_default(char *dir);
-/* find python executable */
+/**
+ * Find Python executable.
+ */
bool BKE_appdir_program_python_search(char *fullpath,
- const size_t fullpath_len,
- const int version_major,
- const int version_minor);
+ size_t fullpath_len,
+ int version_major,
+ int version_minor);
-/* Initialize path to temporary directory. */
+/**
+ * Initialize path to temporary directory.
+ */
void BKE_tempdir_init(const char *userdir);
+/**
+ * Path to persistent temporary directory (with trailing slash)
+ */
const char *BKE_tempdir_base(void);
+/**
+ * Path to temporary directory (with trailing slash)
+ */
const char *BKE_tempdir_session(void);
+/**
+ * Delete content of this instance's temp dir.
+ */
void BKE_tempdir_session_purge(void);
/* folder_id */
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index e13475fd78c..8584ce6f508 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -152,13 +152,13 @@ typedef struct PoseTree {
struct bArmature *BKE_armature_add(struct Main *bmain, const char *name);
struct bArmature *BKE_armature_from_object(struct Object *ob);
int BKE_armature_bonelist_count(const struct ListBase *lb);
-void BKE_armature_bonelist_free(struct ListBase *lb, const bool do_id_user);
-void BKE_armature_editbonelist_free(struct ListBase *lb, const bool do_id_user);
+void BKE_armature_bonelist_free(struct ListBase *lb, bool do_id_user);
+void BKE_armature_editbonelist_free(struct ListBase *lb, bool do_id_user);
void BKE_armature_copy_bone_transforms(struct bArmature *armature_dst,
const struct bArmature *armature_src);
-void BKE_armature_transform(struct bArmature *arm, const float mat[4][4], const bool do_props);
+void BKE_armature_transform(struct bArmature *arm, const float mat[4][4], bool do_props);
/* Bounding box. */
struct BoundBox *BKE_armature_boundbox_get(struct Object *ob);
@@ -166,8 +166,20 @@ struct BoundBox *BKE_armature_boundbox_get(struct Object *ob);
bool BKE_pose_minmax(
struct Object *ob, float r_min[3], float r_max[3], bool use_hidden, bool use_select);
+/**
+ * Finds the best possible extension to the name on a particular axis.
+ * (For renaming, check for unique names afterwards)
+ * \param strip_number: removes number extensions (TODO: not used).
+ * \param axis: The axis to name on.
+ * \param head: The head co-ordinate of the bone on the specified axis.
+ * \param tail: The tail co-ordinate of the bone on the specified axis.
+ */
bool bone_autoside_name(char name[64], int strip_number, short axis, float head, float tail);
+/**
+ * Walk the list until the bone is found (slow!),
+ * use #BKE_armature_bone_from_name_map for multiple lookups.
+ */
struct Bone *BKE_armature_find_bone_name(struct bArmature *arm, const char *name);
void BKE_armature_bone_hash_make(struct bArmature *arm);
@@ -177,40 +189,87 @@ bool BKE_armature_bone_flag_test_recursive(const struct Bone *bone, int flag);
void BKE_armature_refresh_layer_used(struct Depsgraph *depsgraph, struct bArmature *arm);
+/**
+ * Using `vec` with dist to bone `b1 - b2`.
+ */
float distfactor_to_bone(
const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist);
+/**
+ * Updates vectors and matrices on rest-position level, only needed
+ * after editing armature itself, now only on reading file.
+ */
void BKE_armature_where_is(struct bArmature *arm);
+/**
+ * Recursive part, calculates rest-position of entire tree of children.
+ * \note Used when exiting edit-mode too.
+ */
void BKE_armature_where_is_bone(struct Bone *bone,
const struct Bone *bone_parent,
- const bool use_recursion);
+ bool use_recursion);
+/**
+ * Clear pointers of object's pose
+ * (needed in remap case, since we cannot always wait for a complete pose rebuild).
+ */
void BKE_pose_clear_pointers(struct bPose *pose);
void BKE_pose_remap_bone_pointers(struct bArmature *armature, struct bPose *pose);
+/**
+ * Update the links for the B-Bone handles from Bone data.
+ */
void BKE_pchan_rebuild_bbone_handles(struct bPose *pose, struct bPoseChannel *pchan);
-void BKE_pose_channels_clear_with_null_bone(struct bPose *pose, const bool do_id_user);
+void BKE_pose_channels_clear_with_null_bone(struct bPose *pose, bool do_id_user);
+/**
+ * Only after leave edit-mode, duplicating, validating older files, library syncing.
+ *
+ * \note pose->flag is set for it.
+ *
+ * \param bmain: May be NULL, only used to tag depsgraph as being dirty.
+ */
void BKE_pose_rebuild(struct Main *bmain,
struct Object *ob,
struct bArmature *arm,
- const bool do_id_user);
+ bool do_id_user);
+/**
+ * Ensures object's pose is rebuilt if needed.
+ *
+ * \param bmain: May be NULL, only used to tag depsgraph as being dirty.
+ */
void BKE_pose_ensure(struct Main *bmain,
struct Object *ob,
struct bArmature *arm,
- const bool do_id_user);
+ bool do_id_user);
+/**
+ * \note This is the only function adding poses.
+ * \note This only reads anim data from channels, and writes to channels.
+ */
void BKE_pose_where_is(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
+/**
+ * The main armature solver, does all constraints excluding IK.
+ *
+ * \param pchan: pose-channel - validated, as having bone and parent pointer.
+ * \param do_extra: when zero skips loc/size/rot, constraints and strip modifiers.
+ */
void BKE_pose_where_is_bone(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct bPoseChannel *pchan,
float ctime,
bool do_extra);
+/**
+ * Calculate tail of pose-channel.
+ */
void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan);
-/* Evaluate the action and apply it to the pose. If any pose bones are selected, only FCurves that
- * relate to those bones are evaluated. */
+/**
+ * Evaluate the action and apply it to the pose. If any pose bones are selected, only FCurves that
+ * relate to those bones are evaluated.
+ */
void BKE_pose_apply_action_selected_bones(struct Object *ob,
struct bAction *action,
struct AnimationEvalContext *anim_eval_context);
-/* Evaluate the action and apply it to the pose. Ignore selection state of the bones. */
+/**
+ * Evaluate the action and apply it to the pose. Ignore selection state of the bones.
+ */
void BKE_pose_apply_action_all_bones(struct Object *ob,
struct bAction *action,
struct AnimationEvalContext *anim_eval_context);
@@ -220,25 +279,64 @@ void BKE_pose_apply_action_blend(struct Object *ob,
struct AnimationEvalContext *anim_eval_context,
float blend_factor);
-void vec_roll_to_mat3(const float vec[3], const float roll, float r_mat[3][3]);
-void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_mat[3][3]);
+void vec_roll_to_mat3(const float vec[3], float roll, float r_mat[3][3]);
+
+/**
+ * Calculates the rest matrix of a bone based on its vector and a roll around that vector.
+ */
+void vec_roll_to_mat3_normalized(const float nor[3], float roll, float r_mat[3][3]);
+/**
+ * Computes vector and roll based on a rotation.
+ * "mat" must contain only a rotation, and no scaling.
+ */
void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll);
+/**
+ * Computes roll around the vector that best approximates the matrix.
+ * If `vec` is the Y vector from purely rotational `mat`, result should be exact.
+ */
void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll);
/* Common Conversions Between Co-ordinate Spaces */
+
+/**
+ * Convert World-Space Matrix to Pose-Space Matrix.
+ */
void BKE_armature_mat_world_to_pose(struct Object *ob,
const float inmat[4][4],
float outmat[4][4]);
+/**
+ * Convert World-Space Location to Pose-Space Location
+ * \note this cannot be used to convert to pose-space location of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing).
+ */
void BKE_armature_loc_world_to_pose(struct Object *ob, const float inloc[3], float outloc[3]);
+/**
+ * Convert Pose-Space Matrix to Bone-Space Matrix.
+ * \note this cannot be used to convert to pose-space transforms of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing).
+ */
void BKE_armature_mat_pose_to_bone(struct bPoseChannel *pchan,
const float inmat[4][4],
float outmat[4][4]);
+/**
+ * Convert Pose-Space Location to Bone-Space Location
+ * \note this cannot be used to convert to pose-space location of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing).
+ */
void BKE_armature_loc_pose_to_bone(struct bPoseChannel *pchan,
const float inloc[3],
float outloc[3]);
+/**
+ * Convert Bone-Space Matrix to Pose-Space Matrix.
+ */
void BKE_armature_mat_bone_to_pose(struct bPoseChannel *pchan,
const float inmat[4][4],
float outmat[4][4]);
+/**
+ * Remove rest-position effects from pose-transform for obtaining
+ * 'visual' transformation of pose-channel.
+ * (used by the Visual-Keyframing stuff).
+ */
void BKE_armature_mat_pose_to_delta(float delta_mat[4][4],
float pose_mat[4][4],
float arm_mat[4][4]);
@@ -249,13 +347,34 @@ void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph,
const float inmat[4][4],
float outmat[4][4]);
+/**
+ * Same as #BKE_object_mat3_to_rot().
+ */
void BKE_pchan_mat3_to_rot(struct bPoseChannel *pchan, const float mat[3][3], bool use_compat);
+/**
+ * Same as #BKE_object_rot_to_mat3().
+ */
void BKE_pchan_rot_to_mat3(const struct bPoseChannel *pchan, float r_mat[3][3]);
+/**
+ * Apply a 4x4 matrix to the pose bone,
+ * similar to #BKE_object_apply_mat4().
+ */
void BKE_pchan_apply_mat4(struct bPoseChannel *pchan, const float mat[4][4], bool use_compat);
+/**
+ * Convert the loc/rot/size to \a r_chanmat (typically #bPoseChannel.chan_mat).
+ */
void BKE_pchan_to_mat4(const struct bPoseChannel *pchan, float r_chanmat[4][4]);
+
+/**
+ * Convert the loc/rot/size to mat4 (`pchan.chan_mat`),
+ * used in `constraint.c` too.
+ */
void BKE_pchan_calc_mat(struct bPoseChannel *pchan);
-/* Simple helper, computes the offset bone matrix. */
+/**
+ * Simple helper, computes the offset bone matrix:
+ * `offs_bone = yoffs(b-1) + root(b) + bonemat(b)`.
+ */
void BKE_bone_offset_matrix_get(const struct Bone *bone, float offs_bone[4][4]);
/* Transformation inherited from the parent bone. These matrices apply the effects of
@@ -277,9 +396,38 @@ void BKE_bone_parent_transform_apply(const struct BoneParentTransform *bpt,
const float inmat[4][4],
float outmat[4][4]);
-/* Get the current parent transformation for the given pose bone. */
+/**
+ * Get the current parent transformation for the given pose bone.
+ *
+ * Construct the matrices (rot/scale and loc)
+ * to apply the PoseChannels into the armature (object) space.
+ * I.e. (roughly) the `pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b)` in the
+ * `pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b)`
+ * ...function.
+ *
+ * This allows to get the transformations of a bone in its object space,
+ * *before* constraints (and IK) get applied (used by pose evaluation code).
+ * And reverse: to find pchan transformations needed to place a bone at a given loc/rot/scale
+ * in object space (used by interactive transform, and snapping code).
+ *
+ * Note that, with the HINGE/NO_SCALE/NO_LOCAL_LOCATION options, the location matrix
+ * will differ from the rotation/scale matrix...
+ *
+ * \note This cannot be used to convert to pose-space transforms of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing).
+ * (NOTE(@mont29): I don't understand that, so I keep it :p).
+ */
void BKE_bone_parent_transform_calc_from_pchan(const struct bPoseChannel *pchan,
struct BoneParentTransform *r_bpt);
+/**
+ * Compute the parent transform using data decoupled from specific data structures.
+ *
+ * \param bone_flag: #Bone.flag containing settings.
+ * \param offs_bone: delta from parent to current arm_mat (or just arm_mat if no parent).
+ * \param parent_arm_mat: arm_mat of parent, or NULL.
+ * \param parent_pose_mat: pose_mat of parent, or NULL.
+ * \param r_bpt: OUTPUT parent transform.
+ */
void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
int inherit_scale_mode,
const float offs_bone[4][4],
@@ -287,7 +435,13 @@ void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
const float parent_pose_mat[4][4],
struct BoneParentTransform *r_bpt);
-/* Rotation Mode Conversions - Used for PoseChannels + Objects... */
+/**
+ * Rotation Mode Conversions - Used for Pose-Channels + Objects.
+ *
+ * Called from RNA when rotation mode changes
+ * - the result should be that the rotations given in the provided pointers have had conversions
+ * applied (as appropriate), such that the rotation of the element hasn't 'visually' changed.
+ */
void BKE_rotMode_change_values(
float quat[4], float eul[3], float axis[3], float *angle, short oldMode, short newMode);
@@ -320,18 +474,31 @@ typedef struct BBoneSplineParameters {
float curve_in_x, curve_in_z, curve_out_x, curve_out_z;
} BBoneSplineParameters;
+/**
+ * Get "next" and "prev" bones - these are used for handle calculations.
+ */
void BKE_pchan_bbone_handles_get(struct bPoseChannel *pchan,
struct bPoseChannel **r_prev,
struct bPoseChannel **r_next);
+/**
+ * Compute B-Bone spline parameters for the given channel.
+ */
void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
- const bool rest,
+ bool rest,
struct BBoneSplineParameters *r_param);
+/**
+ * Fills the array with the desired amount of bone->segments elements.
+ * This calculation is done within unit bone space.
+ */
void BKE_pchan_bbone_spline_setup(struct bPoseChannel *pchan,
- const bool rest,
- const bool for_deform,
+ bool rest,
+ bool for_deform,
Mat4 *result_array);
+/**
+ * Computes the bezier handle vectors and rolls coming from custom handles.
+ */
void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
float h1[3],
float *r_roll1,
@@ -339,14 +506,28 @@ void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
float *r_roll2,
bool ease,
bool offsets);
+/**
+ * Fills the array with the desired amount of `bone->segments` elements.
+ * This calculation is done within unit bone space.
+ */
int BKE_pchan_bbone_spline_compute(struct BBoneSplineParameters *param,
- const bool for_deform,
+ bool for_deform,
Mat4 *result_array);
+/**
+ * Compute and cache the B-Bone shape in the channel runtime struct.
+ */
void BKE_pchan_bbone_segments_cache_compute(struct bPoseChannel *pchan);
+/**
+ * Copy cached B-Bone segments from one channel to another.
+ */
void BKE_pchan_bbone_segments_cache_copy(struct bPoseChannel *pchan,
struct bPoseChannel *pchan_from);
+/**
+ * Calculate index and blend factor for the two B-Bone segment nodes
+ * affecting the point at 0 <= pos <= 1.
+ */
void BKE_pchan_bbone_deform_segment_index(const struct bPoseChannel *pchan,
float pos,
int *r_index,
diff --git a/source/blender/blenkernel/BKE_asset.h b/source/blender/blenkernel/BKE_asset.h
index 42eea41b7a7..58c50fb736f 100644
--- a/source/blender/blenkernel/BKE_asset.h
+++ b/source/blender/blenkernel/BKE_asset.h
@@ -20,6 +20,7 @@
#pragma once
+#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
#include "DNA_asset_types.h"
@@ -29,11 +30,23 @@ extern "C" {
#endif
struct AssetLibraryReference;
+struct AssetMetaData;
struct BlendDataReader;
struct BlendWriter;
struct ID;
+struct IDProperty;
struct PreviewImage;
+typedef void (*PreSaveFn)(void *asset_ptr, struct AssetMetaData *asset_data);
+
+typedef struct AssetTypeInfo {
+ /**
+ * For local assets (assets in the current .blend file), a callback to execute before the file is
+ * saved.
+ */
+ PreSaveFn pre_save_fn;
+} AssetTypeInfo;
+
struct AssetMetaData *BKE_asset_metadata_create(void);
void BKE_asset_metadata_free(struct AssetMetaData **asset_data);
@@ -44,6 +57,9 @@ struct AssetTagEnsureResult {
};
struct AssetTag *BKE_asset_metadata_tag_add(struct AssetMetaData *asset_data, const char *name);
+/**
+ * Make sure there is a tag with name \a name, create one if needed.
+ */
struct AssetTagEnsureResult BKE_asset_metadata_tag_ensure(struct AssetMetaData *asset_data,
const char *name);
void BKE_asset_metadata_tag_remove(struct AssetMetaData *asset_data, struct AssetTag *tag);
@@ -56,6 +72,10 @@ void BKE_asset_metadata_catalog_id_set(struct AssetMetaData *asset_data,
void BKE_asset_library_reference_init_default(struct AssetLibraryReference *library_ref);
+void BKE_asset_metadata_idprop_ensure(struct AssetMetaData *asset_data, struct IDProperty *prop);
+struct IDProperty *BKE_asset_metadata_idprop_find(const struct AssetMetaData *asset_data,
+ const char *name) ATTR_WARN_UNUSED_RESULT;
+
struct PreviewImage *BKE_asset_metadata_preview_get_from_id(const struct AssetMetaData *asset_data,
const struct ID *owner_id);
diff --git a/source/blender/blenkernel/BKE_asset_catalog.hh b/source/blender/blenkernel/BKE_asset_catalog.hh
index 05db3c808cf..004b70c2925 100644
--- a/source/blender/blenkernel/BKE_asset_catalog.hh
+++ b/source/blender/blenkernel/BKE_asset_catalog.hh
@@ -26,10 +26,13 @@
#include "BLI_function_ref.hh"
#include "BLI_map.hh"
+#include "BLI_set.hh"
#include "BLI_string_ref.hh"
#include "BLI_uuid.h"
#include "BLI_vector.hh"
+#include "BKE_asset_catalog_path.hh"
+
#include <map>
#include <memory>
#include <set>
@@ -37,35 +40,46 @@
namespace blender::bke {
+class AssetCatalog;
+class AssetCatalogCollection;
+class AssetCatalogDefinitionFile;
+class AssetCatalogFilter;
+class AssetCatalogTree;
+
using CatalogID = bUUID;
-using CatalogPath = std::string;
using CatalogPathComponent = std::string;
/* Would be nice to be able to use `std::filesystem::path` for this, but it's currently not
* available on the minimum macOS target version. */
using CatalogFilePath = std::string;
-
-class AssetCatalog;
-class AssetCatalogDefinitionFile;
-class AssetCatalogTree;
+using OwningAssetCatalogMap = Map<CatalogID, std::unique_ptr<AssetCatalog>>;
/* Manages the asset catalogs of a single asset library (i.e. of catalogs defined in a single
* directory hierarchy). */
class AssetCatalogService {
public:
- static const char PATH_SEPARATOR;
static const CatalogFilePath DEFAULT_CATALOG_FILENAME;
public:
- AssetCatalogService() = default;
+ AssetCatalogService();
explicit AssetCatalogService(const CatalogFilePath &asset_library_root);
+ /**
+ * Set tag indicating that some catalog modifications are unsaved, which could
+ * get lost on exit. This tag is not set by internal catalog code, the catalog
+ * service user is responsible for it. It is cleared by #write_to_disk().
+ *
+ * This "dirty" state is tracked per catalog, so that it's possible to gracefully load changes
+ * from disk. Any catalog with unsaved changes will not be overwritten by on-disk changes. */
+ void tag_has_unsaved_changes(AssetCatalog *edited_catalog);
+ bool has_unsaved_changes() const;
+
/** Load asset catalog definitions from the files found in the asset library. */
void load_from_disk();
/** Load asset catalog definitions from the given file or directory. */
void load_from_disk(const CatalogFilePath &file_or_directory_path);
/**
- * Write the catalog definitions to disk in response to the blend file being saved.
+ * Write the catalog definitions to disk.
*
* The location where the catalogs are saved is variable, and depends on the location of the
* blend file. The first matching rule wins:
@@ -81,7 +95,16 @@ class AssetCatalogService {
*
* Return true on success, which either means there were no in-memory categories to save,
* or the save was successful. */
- bool write_to_disk_on_blendfile_save(const CatalogFilePath &blend_file_path);
+ bool write_to_disk(const CatalogFilePath &blend_file_path);
+
+ /**
+ * Ensure that the next call to #on_blend_save_post() will choose a new location for the CDF
+ * suitable for the location of the blend file (regardless of where the current catalogs come
+ * from), and that catalogs will be merged with already-existing ones in that location.
+ *
+ * Use this for a "Save as..." that has to write the catalogs to the new blend file location,
+ * instead of updating the previously read CDF. */
+ void prepare_to_merge_on_write();
/**
* Merge on-disk changes into the in-memory asset catalogs.
@@ -91,45 +114,113 @@ class AssetCatalogService {
* - Already-known on-disk catalogs are ignored (so will be overwritten with our in-memory
* data). This includes in-memory marked-as-deleted catalogs.
*/
- void merge_from_disk_before_writing();
+ void reload_catalogs();
/** Return catalog with the given ID. Return nullptr if not found. */
- AssetCatalog *find_catalog(CatalogID catalog_id);
+ AssetCatalog *find_catalog(CatalogID catalog_id) const;
- /** Return first catalog with the given path. Return nullptr if not found. This is not an
- * efficient call as it's just a linear search over the catalogs. */
- AssetCatalog *find_catalog_by_path(const CatalogPath &path) const;
+ /**
+ * Return first catalog with the given path. Return nullptr if not found. This is not an
+ * efficient call as it's just a linear search over the catalogs.
+ *
+ * If there are multiple catalogs with the same path, return the first-loaded one. If there is
+ * none marked as "first loaded", return the one with the lowest UUID. */
+ AssetCatalog *find_catalog_by_path(const AssetCatalogPath &path) const;
+
+ /**
+ * Return true only if this catalog is known.
+ * This treats deleted catalogs as "unknown". */
+ bool is_catalog_known(CatalogID catalog_id) const;
+
+ /**
+ * Create a filter object that can be used to determine whether an asset belongs to the given
+ * catalog, or any of the catalogs in the sub-tree rooted at the given catalog.
+ *
+ * \see #AssetCatalogFilter
+ */
+ AssetCatalogFilter create_catalog_filter(CatalogID active_catalog_id) const;
/** Create a catalog with some sensible auto-generated catalog ID.
- * The catalog will be saved to the default catalog file.*/
- AssetCatalog *create_catalog(const CatalogPath &catalog_path);
+ * The catalog will be saved to the default catalog file. */
+ AssetCatalog *create_catalog(const AssetCatalogPath &catalog_path);
+
+ /**
+ * Delete all catalogs with the given path, and their children.
+ */
+ void prune_catalogs_by_path(const AssetCatalogPath &path);
/**
- * Soft-delete the catalog, ensuring it actually gets deleted when the catalog definition file is
- * written. */
- void delete_catalog(CatalogID catalog_id);
+ * Delete all catalogs with the same path as the identified catalog, and their children.
+ * This call is the same as calling `prune_catalogs_by_path(find_catalog(catalog_id)->path)`.
+ */
+ void prune_catalogs_by_id(CatalogID catalog_id);
/**
* Update the catalog path, also updating the catalog path of all sub-catalogs.
*/
- void update_catalog_path(CatalogID catalog_id, const CatalogPath &new_catalog_path);
+ void update_catalog_path(CatalogID catalog_id, const AssetCatalogPath &new_catalog_path);
AssetCatalogTree *get_catalog_tree();
/** Return true only if there are no catalogs known. */
bool is_empty() const;
+ /**
+ * Store the current catalogs in the undo stack.
+ * This snapshots everything in the #AssetCatalogCollection. */
+ void undo_push();
+ /**
+ * Restore the last-saved undo snapshot, pushing the current state onto the redo stack.
+ * The caller is responsible for first checking that undoing is possible.
+ */
+ void undo();
+ bool is_undo_possbile() const;
+ /**
+ * Restore the last-saved redo snapshot, pushing the current state onto the undo stack.
+ * The caller is responsible for first checking that undoing is possible. */
+ void redo();
+ bool is_redo_possbile() const;
+
protected:
- /* These pointers are owned by this AssetCatalogService. */
- Map<CatalogID, std::unique_ptr<AssetCatalog>> catalogs_;
- Map<CatalogID, std::unique_ptr<AssetCatalog>> deleted_catalogs_;
- std::unique_ptr<AssetCatalogDefinitionFile> catalog_definition_file_;
- std::unique_ptr<AssetCatalogTree> catalog_tree_;
+ std::unique_ptr<AssetCatalogCollection> catalog_collection_;
+ std::unique_ptr<AssetCatalogTree> catalog_tree_ = std::make_unique<AssetCatalogTree>();
CatalogFilePath asset_library_root_;
+ Vector<std::unique_ptr<AssetCatalogCollection>> undo_snapshots_;
+ Vector<std::unique_ptr<AssetCatalogCollection>> redo_snapshots_;
+
void load_directory_recursive(const CatalogFilePath &directory_path);
void load_single_file(const CatalogFilePath &catalog_definition_file_path);
+ /** Implementation of #write_to_disk() that doesn't clear the "has unsaved changes" tag. */
+ bool write_to_disk_ex(const CatalogFilePath &blend_file_path);
+ void untag_has_unsaved_changes();
+ bool is_catalog_known_with_unsaved_changes(CatalogID catalog_id) const;
+
+ /**
+ * Delete catalogs, only keeping them when they are either listed in
+ * \a catalogs_to_keep or have unsaved changes.
+ *
+ * \note Deleted catalogs are hard-deleted, i.e. they just vanish instead of
+ * remembering them as "deleted".
+ */
+ void purge_catalogs_not_listed(const Set<CatalogID> &catalogs_to_keep);
+
+ /**
+ * Delete a catalog, without deleting any of its children and without rebuilding the catalog
+ * tree. The deletion in "Soft", in the sense that the catalog pointer is moved from `catalogs_`
+ * to `deleted_catalogs_`; the AssetCatalog instance itself is kept in memory. As a result, it
+ * will be removed from a CDF when saved to disk.
+ *
+ * This is a lower-level function than #prune_catalogs_by_path.
+ */
+ void delete_catalog_by_id_soft(CatalogID catalog_id);
+
+ /**
+ * Hard delete a catalog. This simply removes the catalog from existence. The deletion will not
+ * be remembered, and reloading the CDF will bring it back. */
+ void delete_catalog_by_id_hard(CatalogID catalog_id);
+
std::unique_ptr<AssetCatalogDefinitionFile> parse_catalog_file(
const CatalogFilePath &catalog_definition_file_path);
@@ -150,6 +241,55 @@ class AssetCatalogService {
std::unique_ptr<AssetCatalogTree> read_into_tree();
void rebuild_tree();
+
+ /**
+ * For every catalog, ensure that its parent path also has a known catalog.
+ */
+ void create_missing_catalogs();
+
+ /**
+ * For every catalog, mark it as "dirty".
+ */
+ void tag_all_catalogs_as_unsaved_changes();
+
+ /* For access by subclasses, as those will not be marked as friend by #AssetCatalogCollection. */
+ AssetCatalogDefinitionFile *get_catalog_definition_file();
+ OwningAssetCatalogMap &get_catalogs();
+ OwningAssetCatalogMap &get_deleted_catalogs();
+};
+
+/**
+ * All catalogs that are owned by a single asset library, and managed by a single instance of
+ * #AssetCatalogService. The undo system for asset catalog edits contains historical copies of this
+ * struct.
+ */
+class AssetCatalogCollection {
+ friend AssetCatalogService;
+
+ public:
+ AssetCatalogCollection() = default;
+ AssetCatalogCollection(const AssetCatalogCollection &other) = delete;
+ AssetCatalogCollection(AssetCatalogCollection &&other) noexcept = default;
+
+ std::unique_ptr<AssetCatalogCollection> deep_copy() const;
+
+ protected:
+ /** All catalogs known, except the known-but-deleted ones. */
+ OwningAssetCatalogMap catalogs_;
+
+ /** Catalogs that have been deleted. They are kept around so that the load-merge-save of catalog
+ * definition files can actually delete them if they already existed on disk (instead of the
+ * merge operation resurrecting them). */
+ OwningAssetCatalogMap deleted_catalogs_;
+
+ /* For now only a single catalog definition file is supported.
+ * The aim is to support an arbitrary number of such files per asset library in the future. */
+ std::unique_ptr<AssetCatalogDefinitionFile> catalog_definition_file_;
+
+ /** Whether any of the catalogs have unsaved changes. */
+ bool has_unsaved_changes_ = false;
+
+ static OwningAssetCatalogMap copy_catalog_map(const OwningAssetCatalogMap &orig);
};
/**
@@ -166,13 +306,16 @@ class AssetCatalogTreeItem {
AssetCatalogTreeItem(StringRef name,
CatalogID catalog_id,
+ StringRef simple_name,
const AssetCatalogTreeItem *parent = nullptr);
CatalogID get_catalog_id() const;
- StringRef get_name() const;
+ StringRefNull get_simple_name() const;
+ StringRefNull get_name() const;
+ bool has_unsaved_changes() const;
/** Return the full catalog path, defined as the name of this catalog prefixed by the full
* catalog path of its parent and a separator. */
- CatalogPath catalog_path() const;
+ AssetCatalogPath catalog_path() const;
int count_parents() const;
bool has_children() const;
@@ -186,6 +329,10 @@ class AssetCatalogTreeItem {
/** The user visible name of this component. */
CatalogPathComponent name_;
CatalogID catalog_id_;
+ /** Copy of #AssetCatalog::simple_name. */
+ std::string simple_name_;
+ /** Copy of #AssetCatalog::flags.has_unsaved_changes. */
+ bool has_unsaved_changes_ = false;
/** Pointer back to the parent item. Used to reconstruct the hierarchy from an item (e.g. to
* build a path). */
@@ -230,6 +377,9 @@ class AssetCatalogDefinitionFile {
/* For now this is the only version of the catalog definition files that is supported.
* Later versioning code may be added to handle older files. */
const static int SUPPORTED_VERSION;
+ /* String that's matched in the catalog definition file to know that the line is the version
+ * declaration. It has to start with a space to ensure it won't match any hypothetical future
+ * field that starts with "VERSION". */
const static std::string VERSION_MARKER;
const static std::string HEADER;
@@ -252,13 +402,21 @@ class AssetCatalogDefinitionFile {
bool write_to_disk(const CatalogFilePath &dest_file_path) const;
bool contains(CatalogID catalog_id) const;
- /* Add a new catalog. Undefined behavior if a catalog with the same ID was already added. */
+ /** Add a catalog, overwriting the one with the same catalog ID. */
+ void add_overwrite(AssetCatalog *catalog);
+ /** Add a new catalog. Undefined behavior if a catalog with the same ID was already added. */
void add_new(AssetCatalog *catalog);
+ /** Remove the catalog from the collection of catalogs stored in this file. */
+ void forget(CatalogID catalog_id);
+
using AssetCatalogParsedFn = FunctionRef<bool(std::unique_ptr<AssetCatalog>)>;
void parse_catalog_file(const CatalogFilePath &catalog_definition_file_path,
AssetCatalogParsedFn callback);
+ std::unique_ptr<AssetCatalogDefinitionFile> copy_and_remap(
+ const OwningAssetCatalogMap &catalogs, const OwningAssetCatalogMap &deleted_catalogs) const;
+
protected:
/* Catalogs stored in this file. They are mapped by ID to make it possible to query whether a
* catalog is already known, without having to find the corresponding `AssetCatalog*`. */
@@ -280,31 +438,38 @@ class AssetCatalogDefinitionFile {
class AssetCatalog {
public:
AssetCatalog() = default;
- AssetCatalog(CatalogID catalog_id, const CatalogPath &path, const std::string &simple_name);
+ AssetCatalog(CatalogID catalog_id, const AssetCatalogPath &path, const std::string &simple_name);
CatalogID catalog_id;
- CatalogPath path;
+ AssetCatalogPath path;
/**
* Simple, human-readable name for the asset catalog. This is stored on assets alongside the
* catalog ID; the catalog ID is a UUID that is not human-readable,
* so to avoid complete data-loss when the catalog definition file gets lost,
- * we also store a human-readable simple name for the catalog. */
+ * we also store a human-readable simple name for the catalog.
+ *
+ * It should fit in sizeof(AssetMetaData::catalog_simple_name) bytes. */
std::string simple_name;
struct Flags {
/* Treat this catalog as deleted. Keeping deleted catalogs around is necessary to support
* merging of on-disk changes with in-memory changes. */
bool is_deleted = false;
- } flags;
- /**
- * \return true only if this catalog's path is contained within the given path.
- * When this catalog's path is equal to the given path, return true as well.
- *
- * Note that non-normalized paths (so for example starting or ending with a slash) are not
- * supported, and result in undefined behavior.
- */
- bool is_contained_in(const CatalogPath &other_path) const;
+ /* Sort this catalog first when there are multiple catalogs with the same catalog path. This
+ * ensures that in a situation where missing catalogs were auto-created, and then
+ * load-and-merged with a file that also has these catalogs, the first one in that file is
+ * always sorted first, regardless of the sort order of its UUID. */
+ bool is_first_loaded = false;
+
+ /* Merging on-disk changes into memory will not overwrite this catalog.
+ * For example, when a catalog was renamed (i.e. changed path) in this Blender session,
+ * reloading the catalog definition file should not overwrite that change.
+ *
+ * Note that this flag is ignored when is_deleted=true; deleted catalogs that are still in
+ * memory are considered "unsaved" by definition. */
+ bool has_unsaved_changes = false;
+ } flags;
/**
* Create a new Catalog with the given path, auto-generating a sensible catalog simple-name.
@@ -312,28 +477,57 @@ class AssetCatalog {
* NOTE: the given path will be cleaned up (trailing spaces removed, etc.), so the returned
* `AssetCatalog`'s path differ from the given one.
*/
- static std::unique_ptr<AssetCatalog> from_path(const CatalogPath &path);
- static CatalogPath cleanup_path(const CatalogPath &path);
+ static std::unique_ptr<AssetCatalog> from_path(const AssetCatalogPath &path);
+
+ /** Make a new simple name for the catalog, based on its path. */
+ void simple_name_refresh();
protected:
/** Generate a sensible catalog ID for the given path. */
- static std::string sensible_simple_name_for_path(const CatalogPath &path);
+ static std::string sensible_simple_name_for_path(const AssetCatalogPath &path);
};
-/** Comparator for asset catalogs, ordering by (path, UUID). */
-struct AssetCatalogPathCmp {
+/** Comparator for asset catalogs, ordering by (path, first_seen, UUID). */
+struct AssetCatalogLessThan {
bool operator()(const AssetCatalog *lhs, const AssetCatalog *rhs) const
{
- if (lhs->path == rhs->path) {
- return lhs->catalog_id < rhs->catalog_id;
+ if (lhs->path != rhs->path) {
+ return lhs->path < rhs->path;
+ }
+
+ if (lhs->flags.is_first_loaded != rhs->flags.is_first_loaded) {
+ return lhs->flags.is_first_loaded;
}
- return lhs->path < rhs->path;
+
+ return lhs->catalog_id < rhs->catalog_id;
}
};
/**
* Set that stores catalogs ordered by (path, UUID).
* Being a set, duplicates are removed. The catalog's simple name is ignored in this. */
-using AssetCatalogOrderedSet = std::set<const AssetCatalog *, AssetCatalogPathCmp>;
+using AssetCatalogOrderedSet = std::set<const AssetCatalog *, AssetCatalogLessThan>;
+using MutableAssetCatalogOrderedSet = std::set<AssetCatalog *, AssetCatalogLessThan>;
+
+/**
+ * Filter that can determine whether an asset should be visible or not, based on its catalog ID.
+ *
+ * \see AssetCatalogService::create_catalog_filter()
+ */
+class AssetCatalogFilter {
+ public:
+ bool contains(CatalogID asset_catalog_id) const;
+
+ /* So that all unknown catalogs can be shown under "Unassigned". */
+ bool is_known(CatalogID asset_catalog_id) const;
+
+ protected:
+ friend AssetCatalogService;
+ const Set<CatalogID> matching_catalog_ids;
+ const Set<CatalogID> known_catalog_ids;
+
+ explicit AssetCatalogFilter(Set<CatalogID> &&matching_catalog_ids,
+ Set<CatalogID> &&known_catalog_ids);
+};
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_asset_catalog_path.hh b/source/blender/blenkernel/BKE_asset_catalog_path.hh
new file mode 100644
index 00000000000..f51232334f2
--- /dev/null
+++ b/source/blender/blenkernel/BKE_asset_catalog_path.hh
@@ -0,0 +1,146 @@
+/*
+ * 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
+ */
+
+#pragma once
+
+#ifndef __cplusplus
+# error This is a C++ header.
+#endif
+
+#include "BLI_function_ref.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_sys_types.h"
+
+#include <string>
+
+namespace blender::bke {
+
+/**
+ * Location of an Asset Catalog in the catalog tree, denoted by slash-separated path components.
+ *
+ * Each path component is a string that is not allowed to have slashes or colons. The latter is to
+ * make things easy to save in the colon-delimited Catalog Definition File format.
+ *
+ * The path of a catalog determines where in the catalog hierarchy the catalog is shown. Examples
+ * are "Characters/Ellie/Poses/Hand" or "Kit_bash/City/Skyscrapers". The path looks like a
+ * file-system path, with a few differences:
+ *
+ * - Only slashes are used as path component separators.
+ * - All paths are absolute, so there is no need for a leading slash.
+ *
+ * See https://wiki.blender.org/wiki/Source/Architecture/Asset_System/Catalogs
+ *
+ * Paths are stored as byte sequences, and assumed to be UTF-8.
+ */
+class AssetCatalogPath {
+ friend std::ostream &operator<<(std::ostream &stream, const AssetCatalogPath &path_to_append);
+
+ private:
+ /**
+ * The path itself, such as "Agents/Secret/327".
+ */
+ std::string path_ = "";
+
+ public:
+ static const char SEPARATOR;
+
+ AssetCatalogPath() = default;
+ AssetCatalogPath(StringRef path);
+ AssetCatalogPath(const std::string &path);
+ AssetCatalogPath(const char *path);
+ AssetCatalogPath(const AssetCatalogPath &other_path) = default;
+ AssetCatalogPath(AssetCatalogPath &&other_path) noexcept;
+ ~AssetCatalogPath() = default;
+
+ uint64_t hash() const;
+ uint64_t length() const; /* Length of the path in bytes. */
+
+ /** C-string representation of the path. */
+ const char *c_str() const;
+ const std::string &str() const;
+
+ /* The last path component, used as label in the tree view. */
+ StringRefNull name() const;
+
+ /* In-class operators, because of the implicit `AssetCatalogPath(StringRef)` constructor.
+ * Otherwise `string == string` could cast both sides to `AssetCatalogPath`. */
+ bool operator==(const AssetCatalogPath &other_path) const;
+ bool operator!=(const AssetCatalogPath &other_path) const;
+ bool operator<(const AssetCatalogPath &other_path) const;
+ AssetCatalogPath &operator=(const AssetCatalogPath &other_path) = default;
+ AssetCatalogPath &operator=(AssetCatalogPath &&other_path) = default;
+
+ /** Concatenate two paths, returning the new path. */
+ AssetCatalogPath operator/(const AssetCatalogPath &path_to_append) const;
+
+ /* False when the path is empty, true otherwise. */
+ operator bool() const;
+
+ /**
+ * Clean up the path. This ensures:
+ * - Every path component is stripped of its leading/trailing spaces.
+ * - Empty components (caused by double slashes or leading/trailing slashes) are removed.
+ * - Invalid characters are replaced with valid ones.
+ */
+ [[nodiscard]] AssetCatalogPath cleanup() const;
+
+ /**
+ * \return true only if the given path is a parent of this catalog's path.
+ * When this catalog's path is equal to the given path, return true as well.
+ * In other words, this defines a weak subset.
+ *
+ * True: "some/path/there" is contained in "some/path" and "some".
+ * False: "path/there" is not contained in "some/path/there".
+ *
+ * Note that non-cleaned-up paths (so for example starting or ending with a
+ * slash) are not supported, and result in undefined behavior.
+ */
+ bool is_contained_in(const AssetCatalogPath &other_path) const;
+
+ /**
+ * \return the parent path, or an empty path if there is no parent.
+ */
+ AssetCatalogPath parent() const;
+
+ /**
+ * Change the initial part of the path from `from_path` to `to_path`.
+ * If this path does not start with `from_path`, return an empty path as result.
+ *
+ * Example:
+ *
+ * AssetCatalogPath path("some/path/to/some/catalog");
+ * path.rebase("some/path", "new/base") -> "new/base/to/some/catalog"
+ */
+ AssetCatalogPath rebase(const AssetCatalogPath &from_path,
+ const AssetCatalogPath &to_path) const;
+
+ /** Call the callback function for each path component, in left-to-right order. */
+ using ComponentIteratorFn = FunctionRef<void(StringRef component_name, bool is_last_component)>;
+ void iterate_components(ComponentIteratorFn callback) const;
+
+ protected:
+ /** Strip leading/trailing spaces and replace disallowed characters. */
+ static std::string cleanup_component(StringRef component_name);
+};
+
+/** Output the path as string. */
+std::ostream &operator<<(std::ostream &stream, const AssetCatalogPath &path_to_append);
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_asset_library.h b/source/blender/blenkernel/BKE_asset_library.h
index 04486a7c132..ca12fd6f4fb 100644
--- a/source/blender/blenkernel/BKE_asset_library.h
+++ b/source/blender/blenkernel/BKE_asset_library.h
@@ -29,9 +29,14 @@ extern "C" {
/** Forward declaration, defined in intern/asset_library.hh */
typedef struct AssetLibrary AssetLibrary;
-/** TODO(@sybren): properly have a think/discussion about the API for this. */
+/**
+ * Return the #AssetLibrary rooted at the given directory path.
+ *
+ * Will return the same pointer for repeated calls, until another blend file is loaded.
+ *
+ * To get the in-memory-only "current file" asset library, pass an empty path.
+ */
struct AssetLibrary *BKE_asset_library_load(const char *library_path);
-void BKE_asset_library_free(struct AssetLibrary *asset_library);
/**
* Try to find an appropriate location for an asset library root from a file or directory path.
@@ -68,6 +73,13 @@ bool BKE_asset_library_find_suitable_root_path_from_path(
bool BKE_asset_library_find_suitable_root_path_from_main(
const struct Main *bmain, char r_library_path[768 /* FILE_MAXDIR */]);
+/** Look up the asset's catalog and copy its simple name into #asset_data. */
+void BKE_asset_library_refresh_catalog_simplename(struct AssetLibrary *asset_library,
+ struct AssetMetaData *asset_data);
+
+/** Return whether any loaded AssetLibrary has unsaved changes to its catalogs. */
+bool BKE_asset_library_has_any_unsaved_catalogs(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_asset_library.hh b/source/blender/blenkernel/BKE_asset_library.hh
index fc5e137dd3e..37e2ad38a29 100644
--- a/source/blender/blenkernel/BKE_asset_library.hh
+++ b/source/blender/blenkernel/BKE_asset_library.hh
@@ -33,18 +33,44 @@
namespace blender::bke {
+/**
+ * AssetLibrary provides access to an asset library's data.
+ * For now this is only for catalogs, later this can be expanded to indexes/caches/more.
+ */
struct AssetLibrary {
+ /* Controlled by #ED_asset_catalogs_set_save_catalogs_when_file_is_saved,
+ * for managing the "Save Catalog Changes" in the quit-confirmation dialog box. */
+ static bool save_catalogs_when_file_is_saved;
+
std::unique_ptr<AssetCatalogService> catalog_service;
+ AssetLibrary();
+ ~AssetLibrary();
+
void load(StringRefNull library_root_directory);
- void on_save_handler_register();
- void on_save_handler_unregister();
+ /** Load catalogs that have changed on disk. */
+ void refresh();
- void on_save_post(struct Main *, struct PointerRNA **pointers, const int num_pointers);
+ /**
+ * Update `catalog_simple_name` by looking up the asset's catalog by its ID.
+ *
+ * No-op if the catalog cannot be found. This could be the kind of "the
+ * catalog definition file is corrupt/lost" scenario that the simple name is
+ * meant to help recover from. */
+ void refresh_catalog_simplename(struct AssetMetaData *asset_data);
+
+ void on_blend_save_handler_register();
+ void on_blend_save_handler_unregister();
+
+ void on_blend_save_post(struct Main *, struct PointerRNA **pointers, int num_pointers);
private:
- bCallbackFuncStore on_save_callback_store_;
+ bCallbackFuncStore on_save_callback_store_{};
};
} // namespace blender::bke
+
+blender::bke::AssetCatalogService *BKE_asset_library_get_catalog_service(
+ const ::AssetLibrary *library);
+blender::bke::AssetCatalogTree *BKE_asset_library_get_catalog_tree(const ::AssetLibrary *library);
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h
index 7476474258b..6020da08f51 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -38,17 +38,14 @@ struct ID;
struct ReportList;
/* Attribute.domain */
-/**
- * \warning Careful when changing existing items.
- * Arrays may be initialized from this (e.g. #DATASET_layout_hierarchy).
- */
typedef enum AttributeDomain {
- ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */
- ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */
- ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */
- ATTR_DOMAIN_FACE = 2, /* Mesh Face */
- ATTR_DOMAIN_CORNER = 3, /* Mesh Corner */
- ATTR_DOMAIN_CURVE = 4, /* Hair Curve */
+ ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */
+ ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */
+ ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */
+ ATTR_DOMAIN_FACE = 2, /* Mesh Face */
+ ATTR_DOMAIN_CORNER = 3, /* Mesh Corner */
+ ATTR_DOMAIN_CURVE = 4, /* Hair Curve */
+ ATTR_DOMAIN_INSTANCE = 5, /* Instance */
ATTR_DOMAIN_NUM
} AttributeDomain;
@@ -57,19 +54,16 @@ typedef enum AttributeDomain {
bool BKE_id_attributes_supported(struct ID *id);
-struct CustomDataLayer *BKE_id_attribute_new(struct ID *id,
- const char *name,
- const int type,
- const AttributeDomain domain,
- struct ReportList *reports);
+struct CustomDataLayer *BKE_id_attribute_new(
+ struct ID *id, const char *name, int type, AttributeDomain domain, struct ReportList *reports);
bool BKE_id_attribute_remove(struct ID *id,
struct CustomDataLayer *layer,
struct ReportList *reports);
struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
const char *name,
- const int type,
- const AttributeDomain domain);
+ int type,
+ AttributeDomain domain);
AttributeDomain BKE_id_attribute_domain(struct ID *id, struct CustomDataLayer *layer);
int BKE_id_attribute_data_length(struct ID *id, struct CustomDataLayer *layer);
@@ -79,7 +73,7 @@ bool BKE_id_attribute_rename(struct ID *id,
const char *new_name,
struct ReportList *reports);
-int BKE_id_attributes_length(struct ID *id, const CustomDataMask mask);
+int BKE_id_attributes_length(struct ID *id, CustomDataMask mask);
struct CustomDataLayer *BKE_id_attributes_active_get(struct ID *id);
void BKE_id_attributes_active_set(struct ID *id, struct CustomDataLayer *layer);
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index da3de2f08bd..3ffdcee05eb 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -26,9 +26,41 @@
#include "BKE_attribute.h"
#include "BLI_color.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
#include "BLI_function_ref.hh"
+#include "BLI_math_vec_types.hh"
+
+/**
+ * This file defines classes that help to provide access to attribute data on a #GeometryComponent.
+ * The API for retrieving attributes is defined in `BKE_geometry_set.hh`, but this comment has some
+ * general comments about the system.
+ *
+ * Attributes are stored in geometry data, though they can also be stored in instances. Their
+ * storage is often tied to `CustomData`, which is a system to store "layers" of data with specific
+ * types and names. However, since `CustomData` was added to Blender before attributes were
+ * conceptualized, it combines the "legacy" style of task-specific attribute types with generic
+ * types like "Float". The attribute API here only provides access to generic types.
+ *
+ * Attributes are retrieved from geometry components by providing an "id" (#AttributeIDRef). This
+ * is most commonly just an attribute name. The attribute API on geometry components has some more
+ * advanced capabilities:
+ * 1. Read-only access: With a `const` geometry component, an attribute on the geometry cannot be
+ * modified, so the `for_write` and `for_output` versions of the API are not available. This is
+ * extremely important for writing coherent bug-free code. When an attribute is retrieved with
+ * write access, via #WriteAttributeLookup or #OutputAttribute, the geometry component must be
+ * tagged to clear caches that depend on the changed data.
+ * 2. Domain interpolation: When retrieving an attribute, a domain (#AttributeDomain) can be
+ * provided. If the attribute is stored on a different domain and conversion is possible, a
+ * version of the data interpolated to the requested domain will be provided. These conversions
+ * are implemented in each #GeometryComponent by `attribute_try_adapt_domain_impl`.
+ * 3. Implicit type conversion: In addition to interpolating domains, attribute types can be
+ * converted, using the conversions in `BKE_type_conversions.hh`. The #VArray / #GVArray system
+ * makes it possible to only convert necessary indices on-demand.
+ * 4. Anonymous attributes: The "id" used to look up an attribute can also be an anonymous
+ * attribute reference. Currently anonymous attributes are only used in geometry nodes.
+ * 5. Abstracted storage: Since the data returned from the API is usually a virtual array,
+ * it doesn't have to be stored contiguously (even though that is generally preferred). This
+ * allows accessing "legacy" attributes like `material_index`, which is stored in `MPoly`.
+ */
namespace blender::bke {
@@ -42,66 +74,22 @@ class AttributeIDRef {
const AnonymousAttributeID *anonymous_id_ = nullptr;
public:
- AttributeIDRef() = default;
-
- AttributeIDRef(StringRef name) : name_(name)
- {
- }
-
- AttributeIDRef(StringRefNull name) : name_(name)
- {
- }
-
- AttributeIDRef(const char *name) : name_(name)
- {
- }
-
- AttributeIDRef(const std::string &name) : name_(name)
- {
- }
-
- /* The anonymous id is only borrowed, the caller has to keep a reference to it. */
- AttributeIDRef(const AnonymousAttributeID *anonymous_id) : anonymous_id_(anonymous_id)
- {
- }
-
- operator bool() const
- {
- return this->is_named() || this->is_anonymous();
- }
-
- friend bool operator==(const AttributeIDRef &a, const AttributeIDRef &b)
- {
- return a.anonymous_id_ == b.anonymous_id_ && a.name_ == b.name_;
- }
-
- uint64_t hash() const
- {
- return get_default_hash_2(name_, anonymous_id_);
- }
-
- bool is_named() const
- {
- return !name_.is_empty();
- }
-
- bool is_anonymous() const
- {
- return anonymous_id_ != nullptr;
- }
-
- StringRef name() const
- {
- BLI_assert(this->is_named());
- return name_;
- }
-
- const AnonymousAttributeID &anonymous_id() const
- {
- BLI_assert(this->is_anonymous());
- return *anonymous_id_;
- }
-
+ AttributeIDRef();
+ AttributeIDRef(StringRef name);
+ AttributeIDRef(StringRefNull name);
+ AttributeIDRef(const char *name);
+ AttributeIDRef(const std::string &name);
+ AttributeIDRef(const AnonymousAttributeID *anonymous_id);
+
+ operator bool() const;
+ uint64_t hash() const;
+ bool is_named() const;
+ bool is_anonymous() const;
+ StringRef name() const;
+ const AnonymousAttributeID &anonymous_id() const;
+ bool should_be_kept() const;
+
+ friend bool operator==(const AttributeIDRef &a, const AttributeIDRef &b);
friend std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_id);
};
@@ -159,10 +147,10 @@ struct AttributeInitDefault : public AttributeInit {
* Note that this can be used to fill the new attribute with the default
*/
struct AttributeInitVArray : public AttributeInit {
- const blender::fn::GVArray *varray;
+ blender::fn::GVArray varray;
- AttributeInitVArray(const blender::fn::GVArray *varray)
- : AttributeInit(Type::VArray), varray(varray)
+ AttributeInitVArray(blender::fn::GVArray varray)
+ : AttributeInit(Type::VArray), varray(std::move(varray))
{
}
};
@@ -194,13 +182,15 @@ namespace blender::bke {
using fn::CPPType;
using fn::GVArray;
-using fn::GVArrayPtr;
using fn::GVMutableArray;
-using fn::GVMutableArrayPtr;
const CPPType *custom_data_type_to_cpp_type(const CustomDataType type);
CustomDataType cpp_type_to_custom_data_type(const CPPType &type);
CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_types);
+/**
+ * Domains with a higher "information density" have a higher priority,
+ * in order to choose a domain that will not lose data through domain conversion.
+ */
AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains);
/**
@@ -208,14 +198,14 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
*/
struct ReadAttributeLookup {
/* The virtual array that is used to read from this attribute. */
- GVArrayPtr varray;
+ GVArray varray;
/* Domain the attribute lives on in the geometry. */
AttributeDomain domain;
/* Convenience function to check if the attribute has been found. */
operator bool() const
{
- return this->varray.get() != nullptr;
+ return this->varray;
}
};
@@ -223,15 +213,20 @@ struct ReadAttributeLookup {
* Used when looking up a "plain attribute" based on a name for reading from it and writing to it.
*/
struct WriteAttributeLookup {
- /* The virtual array that is used to read from and write to the attribute. */
- GVMutableArrayPtr varray;
- /* Domain the attributes lives on in the geometry. */
+ /** The virtual array that is used to read from and write to the attribute. */
+ GVMutableArray varray;
+ /** Domain the attributes lives on in the geometry component. */
AttributeDomain domain;
+ /**
+ * Call this after changing the attribute to invalidate caches that depend on this attribute.
+ * \note Do not call this after the component the attribute is from has been destructed.
+ */
+ std::function<void()> tag_modified_fn;
/* Convenience function to check if the attribute has been found. */
operator bool() const
{
- return this->varray.get() != nullptr;
+ return this->varray;
}
};
@@ -245,87 +240,44 @@ struct WriteAttributeLookup {
* VMutableArray_Span in many cases).
* - An output attribute can live side by side with an existing attribute with a different domain
* or data type. The old attribute will only be overwritten when the #save function is called.
+ *
+ * \note The lifetime of an output attribute should not be longer than the the lifetime of the
+ * geometry component it comes from, since it can keep a reference to the component for use in
+ * the #save method.
*/
class OutputAttribute {
public:
using SaveFn = std::function<void(OutputAttribute &)>;
private:
- GVMutableArrayPtr varray_;
- AttributeDomain domain_;
+ GVMutableArray varray_;
+ AttributeDomain domain_ = ATTR_DOMAIN_AUTO;
SaveFn save_;
std::unique_ptr<fn::GVMutableArray_GSpan> optional_span_varray_;
bool ignore_old_values_ = false;
bool save_has_been_called_ = false;
public:
- OutputAttribute() = default;
-
- OutputAttribute(GVMutableArrayPtr varray,
+ OutputAttribute();
+ OutputAttribute(OutputAttribute &&other);
+ OutputAttribute(GVMutableArray varray,
AttributeDomain domain,
SaveFn save,
- const bool ignore_old_values)
- : varray_(std::move(varray)),
- domain_(domain),
- save_(std::move(save)),
- ignore_old_values_(ignore_old_values)
- {
- }
-
- OutputAttribute(OutputAttribute &&other) = default;
+ bool ignore_old_values);
~OutputAttribute();
- operator bool() const
- {
- return varray_.get() != nullptr;
- }
-
- GVMutableArray &operator*()
- {
- return *varray_;
- }
-
- GVMutableArray *operator->()
- {
- return varray_.get();
- }
-
- GVMutableArray &varray()
- {
- return *varray_;
- }
-
- AttributeDomain domain() const
- {
- return domain_;
- }
+ operator bool() const;
- const CPPType &cpp_type() const
- {
- return varray_->type();
- }
+ GVMutableArray &operator*();
+ fn::GVMutableArray *operator->();
+ GVMutableArray &varray();
+ AttributeDomain domain() const;
+ const CPPType &cpp_type() const;
+ CustomDataType custom_data_type() const;
- CustomDataType custom_data_type() const
- {
- return cpp_type_to_custom_data_type(this->cpp_type());
- }
-
- fn::GMutableSpan as_span()
- {
- if (!optional_span_varray_) {
- const bool materialize_old_values = !ignore_old_values_;
- optional_span_varray_ = std::make_unique<fn::GVMutableArray_GSpan>(*varray_,
- materialize_old_values);
- }
- fn::GVMutableArray_GSpan &span_varray = *optional_span_varray_;
- return span_varray;
- }
-
- template<typename T> MutableSpan<T> as_span()
- {
- return this->as_span().typed<T>();
- }
+ fn::GMutableSpan as_span();
+ template<typename T> MutableSpan<T> as_span();
void save();
};
@@ -336,36 +288,48 @@ class OutputAttribute {
template<typename T> class OutputAttribute_Typed {
private:
OutputAttribute attribute_;
- std::optional<fn::GVMutableArray_Typed<T>> optional_varray_;
- VMutableArray<T> *varray_ = nullptr;
+ VMutableArray<T> varray_;
public:
+ OutputAttribute_Typed();
OutputAttribute_Typed(OutputAttribute attribute) : attribute_(std::move(attribute))
{
if (attribute_) {
- optional_varray_.emplace(attribute_.varray());
- varray_ = &**optional_varray_;
+ varray_ = attribute_.varray().template typed<T>();
}
}
+ OutputAttribute_Typed(OutputAttribute_Typed &&other);
+ ~OutputAttribute_Typed();
+
+ OutputAttribute_Typed &operator=(OutputAttribute_Typed &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+ this->~OutputAttribute_Typed();
+ new (this) OutputAttribute_Typed(std::move(other));
+ return *this;
+ }
+
operator bool() const
{
- return varray_ != nullptr;
+ return varray_;
}
VMutableArray<T> &operator*()
{
- return *varray_;
+ return varray_;
}
VMutableArray<T> *operator->()
{
- return varray_;
+ return &varray_;
}
VMutableArray<T> &varray()
{
- return *varray_;
+ return varray_;
}
AttributeDomain domain() const
@@ -394,6 +358,13 @@ template<typename T> class OutputAttribute_Typed {
}
};
+/* These are not defined in the class directly, because when defining them there, the external
+ * template instantiation does not work, resulting in longer compile times. */
+template<typename T> inline OutputAttribute_Typed<T>::OutputAttribute_Typed() = default;
+template<typename T>
+inline OutputAttribute_Typed<T>::OutputAttribute_Typed(OutputAttribute_Typed &&other) = default;
+template<typename T> inline OutputAttribute_Typed<T>::~OutputAttribute_Typed() = default;
+
/**
* A basic container around DNA CustomData so that its users
* don't have to implement special copy and move constructors.
@@ -415,22 +386,28 @@ class CustomDataAttributes {
CustomDataAttributes(CustomDataAttributes &&other);
CustomDataAttributes &operator=(const CustomDataAttributes &other);
- void reallocate(const int size);
+ void reallocate(int size);
+
+ void clear();
std::optional<blender::fn::GSpan> get_for_read(const AttributeIDRef &attribute_id) const;
- blender::fn::GVArrayPtr get_for_read(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
- const void *default_value) const;
+ /**
+ * Return a virtual array for a stored attribute, or a single value virtual array with the
+ * default value if the attribute doesn't exist. If no default value is provided, the default
+ * value for the type will be used.
+ */
+ blender::fn::GVArray get_for_read(const AttributeIDRef &attribute_id,
+ const CustomDataType data_type,
+ const void *default_value) const;
template<typename T>
- blender::fn::GVArray_Typed<T> get_for_read(const AttributeIDRef &attribute_id,
- const T &default_value) const
+ blender::VArray<T> get_for_read(const AttributeIDRef &attribute_id, const T &default_value) const
{
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- GVArrayPtr varray = this->get_for_read(attribute_id, type, &default_value);
- return blender::fn::GVArray_Typed<T>(std::move(varray));
+ GVArray varray = this->get_for_read(attribute_id, type, &default_value);
+ return varray.typed<T>();
}
std::optional<blender::fn::GMutableSpan> get_for_write(const AttributeIDRef &attribute_id);
@@ -440,8 +417,149 @@ class CustomDataAttributes {
void *buffer);
bool remove(const AttributeIDRef &attribute_id);
- bool foreach_attribute(const AttributeForeachCallback callback,
- const AttributeDomain domain) const;
+ /**
+ * Change the order of the attributes to match the order of IDs in the argument.
+ */
+ void reorder(Span<AttributeIDRef> new_order);
+
+ bool foreach_attribute(const AttributeForeachCallback callback, AttributeDomain domain) const;
};
+/* -------------------------------------------------------------------- */
+/** \name #AttributeIDRef Inline Methods
+ * \{ */
+
+inline AttributeIDRef::AttributeIDRef() = default;
+
+inline AttributeIDRef::AttributeIDRef(StringRef name) : name_(name)
+{
+}
+
+inline AttributeIDRef::AttributeIDRef(StringRefNull name) : name_(name)
+{
+}
+
+inline AttributeIDRef::AttributeIDRef(const char *name) : name_(name)
+{
+}
+
+inline AttributeIDRef::AttributeIDRef(const std::string &name) : name_(name)
+{
+}
+
+/* The anonymous id is only borrowed, the caller has to keep a reference to it. */
+inline AttributeIDRef::AttributeIDRef(const AnonymousAttributeID *anonymous_id)
+ : anonymous_id_(anonymous_id)
+{
+}
+
+inline bool operator==(const AttributeIDRef &a, const AttributeIDRef &b)
+{
+ return a.anonymous_id_ == b.anonymous_id_ && a.name_ == b.name_;
+}
+
+inline AttributeIDRef::operator bool() const
+{
+ return this->is_named() || this->is_anonymous();
+}
+
+inline uint64_t AttributeIDRef::hash() const
+{
+ return get_default_hash_2(name_, anonymous_id_);
+}
+
+inline bool AttributeIDRef::is_named() const
+{
+ return !name_.is_empty();
+}
+
+inline bool AttributeIDRef::is_anonymous() const
+{
+ return anonymous_id_ != nullptr;
+}
+
+inline StringRef AttributeIDRef::name() const
+{
+ BLI_assert(this->is_named());
+ return name_;
+}
+
+inline const AnonymousAttributeID &AttributeIDRef::anonymous_id() const
+{
+ BLI_assert(this->is_anonymous());
+ return *anonymous_id_;
+}
+
+/**
+ * \return True if the attribute should not be removed automatically as an optimization during
+ * processing or copying. Anonymous attributes can be removed when they no longer have any
+ * references.
+ */
+inline bool AttributeIDRef::should_be_kept() const
+{
+ return this->is_named() || BKE_anonymous_attribute_id_has_strong_references(anonymous_id_);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #OutputAttribute Inline Methods
+ * \{ */
+
+inline OutputAttribute::OutputAttribute() = default;
+inline OutputAttribute::OutputAttribute(OutputAttribute &&other) = default;
+
+inline OutputAttribute::OutputAttribute(GVMutableArray varray,
+ AttributeDomain domain,
+ SaveFn save,
+ const bool ignore_old_values)
+ : varray_(std::move(varray)),
+ domain_(domain),
+ save_(std::move(save)),
+ ignore_old_values_(ignore_old_values)
+{
+}
+
+inline OutputAttribute::operator bool() const
+{
+ return varray_;
+}
+
+inline GVMutableArray &OutputAttribute::operator*()
+{
+ return varray_;
+}
+
+inline fn::GVMutableArray *OutputAttribute::operator->()
+{
+ return &varray_;
+}
+
+inline GVMutableArray &OutputAttribute::varray()
+{
+ return varray_;
+}
+
+inline AttributeDomain OutputAttribute::domain() const
+{
+ return domain_;
+}
+
+inline const CPPType &OutputAttribute::cpp_type() const
+{
+ return varray_.type();
+}
+
+inline CustomDataType OutputAttribute::custom_data_type() const
+{
+ return cpp_type_to_custom_data_type(this->cpp_type());
+}
+
+template<typename T> inline MutableSpan<T> OutputAttribute::as_span()
+{
+ return this->as_span().typed<T>();
+}
+
+/** \} */
+
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh
index 2ce41e95b65..90f349125c9 100644
--- a/source/blender/blenkernel/BKE_attribute_math.hh
+++ b/source/blender/blenkernel/BKE_attribute_math.hh
@@ -18,8 +18,7 @@
#include "BLI_array.hh"
#include "BLI_color.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
#include "DNA_customdata_types.h"
@@ -141,7 +140,7 @@ inline ColorGeometry4f mix3(const float3 &weights,
* This is just basic linear interpolation.
* \{ */
-template<typename T> T mix2(const float factor, const T &a, const T &b);
+template<typename T> T mix2(float factor, const T &a, const T &b);
template<> inline bool mix2(const float factor, const bool &a, const bool &b)
{
@@ -160,12 +159,12 @@ template<> inline float mix2(const float factor, const float &a, const float &b)
template<> inline float2 mix2(const float factor, const float2 &a, const float2 &b)
{
- return float2::interpolate(a, b, factor);
+ return math::interpolate(a, b, factor);
}
template<> inline float3 mix2(const float factor, const float3 &a, const float3 &b)
{
- return float3::interpolate(a, b, factor);
+ return math::interpolate(a, b, factor);
}
template<>
@@ -232,6 +231,43 @@ template<typename T> class SimpleMixer {
};
/**
+ * Mixes together booleans with "or" while fitting the same interface as the other
+ * mixers in order to be simpler to use. This mixing method has a few benefits:
+ * - An "average" for selections is relatively meaningless.
+ * - Predictable selection propagation is very super important.
+ * - It's generally easier to remove an element from a selection that is slightly too large than
+ * the opposite.
+ */
+class BooleanPropagationMixer {
+ private:
+ MutableSpan<bool> buffer_;
+
+ public:
+ /**
+ * \param buffer: Span where the interpolated values should be stored.
+ */
+ BooleanPropagationMixer(MutableSpan<bool> buffer) : buffer_(buffer)
+ {
+ buffer_.fill(false);
+ }
+
+ /**
+ * Mix a #value into the element with the given #index.
+ */
+ void mix_in(const int64_t index, const bool value, [[maybe_unused]] const float weight = 1.0f)
+ {
+ buffer_[index] |= value;
+ }
+
+ /**
+ * Does not do anything, since the mixing is trivial.
+ */
+ void finalize()
+ {
+ }
+};
+
+/**
* This mixer accumulates values in a type that is different from the one that is mixed.
* Some types cannot encode the floating point weights in their values (e.g. int and bool).
*/
@@ -287,12 +323,12 @@ class ColorGeometryMixer {
public:
ColorGeometryMixer(MutableSpan<ColorGeometry4f> buffer,
ColorGeometry4f default_color = ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f));
- void mix_in(const int64_t index, const ColorGeometry4f &color, const float weight = 1.0f);
+ void mix_in(int64_t index, const ColorGeometry4f &color, float weight = 1.0f);
void finalize();
};
template<typename T> struct DefaultMixerStruct {
- /* Use void by default. This can be check for in `if constexpr` statements. */
+ /* Use void by default. This can be checked for in `if constexpr` statements. */
using type = void;
};
template<> struct DefaultMixerStruct<float> {
@@ -328,6 +364,23 @@ template<> struct DefaultMixerStruct<bool> {
using type = SimpleMixerWithAccumulationType<bool, float, float_to_bool>;
};
+template<typename T> struct DefaultPropatationMixerStruct {
+ /* Use void by default. This can be checked for in `if constexpr` statements. */
+ using type = typename DefaultMixerStruct<T>::type;
+};
+
+template<> struct DefaultPropatationMixerStruct<bool> {
+ using type = BooleanPropagationMixer;
+};
+
+/**
+ * This mixer is meant for propagating attributes when creating new geometry. A key difference
+ * with the default mixer is that booleans are mixed with "or" instead of "at least half"
+ * (the default mixing for booleans).
+ */
+template<typename T>
+using DefaultPropatationMixer = typename DefaultPropatationMixerStruct<T>::type;
+
/* Utility to get a good default mixer for a given type. This is `void` when there is no default
* mixer for the given type. */
template<typename T> using DefaultMixer = typename DefaultMixerStruct<T>::type;
diff --git a/source/blender/blenkernel/BKE_autoexec.h b/source/blender/blenkernel/BKE_autoexec.h
index 84d83ae5d30..55bb3e8877f 100644
--- a/source/blender/blenkernel/BKE_autoexec.h
+++ b/source/blender/blenkernel/BKE_autoexec.h
@@ -23,6 +23,10 @@
extern "C" {
#endif
+/**
+ * \param path: The path to check against.
+ * \return Success
+ */
bool BKE_autoexec_match(const char *path);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 813472715fa..8c0512edb1d 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -29,6 +29,9 @@ extern "C" {
struct UserDef;
+/**
+ * Only to be called on exit Blender.
+ */
void BKE_blender_free(void);
void BKE_blender_globals_init(void);
@@ -38,11 +41,19 @@ void BKE_blender_userdef_data_swap(struct UserDef *userdef_a, struct UserDef *us
void BKE_blender_userdef_data_set(struct UserDef *userdef);
void BKE_blender_userdef_data_set_and_free(struct UserDef *userdef);
+/**
+ * Write U from userdef.
+ * This function defines which settings a template will override for the user preferences.
+ */
void BKE_blender_userdef_app_template_data_swap(struct UserDef *userdef_a,
struct UserDef *userdef_b);
void BKE_blender_userdef_app_template_data_set(struct UserDef *userdef);
void BKE_blender_userdef_app_template_data_set_and_free(struct UserDef *userdef);
+/**
+ * When loading a new userdef from file,
+ * or when exiting Blender.
+ */
void BKE_blender_userdef_data_free(struct UserDef *userdef, bool clear_fonts);
/* Blenders' own atexit (avoids leaking) */
diff --git a/source/blender/blenkernel/BKE_blender_copybuffer.h b/source/blender/blenkernel/BKE_blender_copybuffer.h
index 1dd6d495276..d1faf88a90c 100644
--- a/source/blender/blenkernel/BKE_blender_copybuffer.h
+++ b/source/blender/blenkernel/BKE_blender_copybuffer.h
@@ -30,19 +30,59 @@ struct Main;
struct ReportList;
struct bContext;
-/* copybuffer (wrapper for BKE_blendfile_write_partial) */
-void BKE_copybuffer_begin(struct Main *bmain_src);
-void BKE_copybuffer_tag_ID(struct ID *id);
-bool BKE_copybuffer_save(struct Main *bmain_src, const char *filename, struct ReportList *reports);
+/* Copy-buffer (wrapper for BKE_blendfile_write_partial). */
+
+/**
+ * Initialize a copy operation.
+ */
+void BKE_copybuffer_copy_begin(struct Main *bmain_src);
+/**
+ * Mark an ID to be copied. Should only be called after a call to #BKE_copybuffer_copy_begin.
+ */
+void BKE_copybuffer_copy_tag_ID(struct ID *id);
+/**
+ * Finalize a copy operation into given .blend file 'buffer'.
+ *
+ * \param filename: Full path to the .blend file used as copy/paste buffer.
+ *
+ * \return true on success, false otherwise.
+ */
+bool BKE_copybuffer_copy_end(struct Main *bmain_src,
+ const char *filename,
+ struct ReportList *reports);
+/**
+ * Paste data-blocks from the given .blend file 'buffer' (i.e. append them).
+ *
+ * Unlike #BKE_copybuffer_paste, it does not perform any instantiation of collections/objects/etc.
+ *
+ * \param libname: Full path to the .blend file used as copy/paste buffer.
+ * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer.
+ *
+ * \return true on success, false otherwise.
+ */
bool BKE_copybuffer_read(struct Main *bmain_dst,
const char *libname,
struct ReportList *reports,
- const uint64_t id_types_mask);
+ uint64_t id_types_mask);
+/**
+ * Paste data-blocks from the given .blend file 'buffer' (i.e. append them).
+ *
+ * Similar to #BKE_copybuffer_read, but also handles instantiation of collections/objects/etc.
+ *
+ * \param libname: Full path to the .blend file used as copy/paste buffer.
+ * \param flag: A combination of #eBLOLibLinkFlags and ##eFileSel_Params_Flag to control
+ * link/append behavior.
+ * \note Ignores #FILE_LINK flag, since it always appends IDs.
+ * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer.
+ *
+ * \return Number of IDs directly pasted from the buffer
+ * (does not includes indirectly linked ones).
+ */
int BKE_copybuffer_paste(struct bContext *C,
const char *libname,
- const short flag,
+ int flag,
struct ReportList *reports,
- const uint64_t id_types_mask);
+ uint64_t id_types_mask);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h
index 1febe75b6f2..d60d048ee5f 100644
--- a/source/blender/blenkernel/BKE_blender_undo.h
+++ b/source/blender/blenkernel/BKE_blender_undo.h
@@ -34,8 +34,8 @@ enum eUndoStepDir;
struct MemFileUndoData *BKE_memfile_undo_encode(struct Main *bmain,
struct MemFileUndoData *mfu_prev);
bool BKE_memfile_undo_decode(struct MemFileUndoData *mfu,
- const enum eUndoStepDir undo_direction,
- const bool use_old_bmain_data,
+ enum eUndoStepDir undo_direction,
+ bool use_old_bmain_data,
struct bContext *C);
void BKE_memfile_undo_free(struct MemFileUndoData *mfu);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index b04bbdfb187..d0ab8be9a29 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -31,7 +31,7 @@ extern "C" {
*/
/* Blender major and minor version. */
-#define BLENDER_VERSION 300
+#define BLENDER_VERSION 301
/* Blender patch version for bugfix releases. */
#define BLENDER_VERSION_PATCH 0
/** Blender release cycle stage: alpha/beta/rc/release. */
@@ -39,13 +39,13 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 31
+#define BLENDER_FILE_SUBVERSION 5
/* 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
* was written with too new a version. */
#define BLENDER_FILE_MIN_VERSION 300
-#define BLENDER_FILE_MIN_SUBVERSION 26
+#define BLENDER_FILE_MIN_SUBVERSION 42
/** User readable version string. */
const char *BKE_blender_version_string(void);
diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h
index 3e0a343a766..db86d4685b7 100644
--- a/source/blender/blenkernel/BKE_blendfile.h
+++ b/source/blender/blenkernel/BKE_blendfile.h
@@ -33,12 +33,20 @@ struct ReportList;
struct UserDef;
struct bContext;
+/**
+ * Shared setup function that makes the data from `bfd` into the current blend file,
+ * replacing the contents of #G.main.
+ * This uses the bfd #BKE_blendfile_read and similarly named functions.
+ *
+ * This is done in a separate step so the caller may perform actions after it is known the file
+ * loaded correctly but before the file replaces the existing blend file contents.
+ */
void BKE_blendfile_read_setup_ex(struct bContext *C,
struct BlendFileData *bfd,
const struct BlendFileReadParams *params,
struct BlendFileReadReport *reports,
/* Extra args. */
- const bool startup_update_defaults,
+ bool startup_update_defaults,
const char *startup_app_template);
void BKE_blendfile_read_setup(struct bContext *C,
@@ -46,28 +54,56 @@ void BKE_blendfile_read_setup(struct bContext *C,
const struct BlendFileReadParams *params,
struct BlendFileReadReport *reports);
+/**
+ * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
+ */
struct BlendFileData *BKE_blendfile_read(const char *filepath,
const struct BlendFileReadParams *params,
struct BlendFileReadReport *reports);
+/**
+ * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
+ */
struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
int filelength,
const struct BlendFileReadParams *params,
struct ReportList *reports);
+/**
+ * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
+ * \note `memfile` is the undo buffer.
+ */
struct BlendFileData *BKE_blendfile_read_from_memfile(struct Main *bmain,
struct MemFile *memfile,
const struct BlendFileReadParams *params,
struct ReportList *reports);
+/**
+ * Utility to make a file 'empty' used for startup to optionally give an empty file.
+ * Handy for tests.
+ */
void BKE_blendfile_read_make_empty(struct bContext *C);
+/**
+ * Only read the #UserDef from a .blend.
+ */
struct UserDef *BKE_blendfile_userdef_read(const char *filepath, struct ReportList *reports);
struct UserDef *BKE_blendfile_userdef_read_from_memory(const void *filebuf,
int filelength,
struct ReportList *reports);
struct UserDef *BKE_blendfile_userdef_from_defaults(void);
+/**
+ * Only write the #UserDef in a `.blend`.
+ * \return success.
+ */
bool BKE_blendfile_userdef_write(const char *filepath, struct ReportList *reports);
+/**
+ * Only write the #UserDef in a `.blend`, merging with the existing blend file.
+ * \return success.
+ *
+ * \note In the future we should re-evaluate user preferences,
+ * possibly splitting out system/hardware specific preferences.
+ */
bool BKE_blendfile_userdef_write_app_template(const char *filepath, struct ReportList *reports);
bool BKE_blendfile_userdef_write_all(struct ReportList *reports);
@@ -81,13 +117,18 @@ bool BKE_blendfile_workspace_config_write(struct Main *bmain,
struct ReportList *reports);
void BKE_blendfile_workspace_config_data_free(struct WorkspaceConfigFileData *workspace_config);
-/* partial blend file writing */
+/* Partial blend file writing. */
+
void BKE_blendfile_write_partial_tag_ID(struct ID *id, bool set);
void BKE_blendfile_write_partial_begin(struct Main *bmain_src);
+/**
+ * \param remap_mode: Choose the kind of path remapping or none #eBLO_WritePathRemap.
+ * \return Success.
+ */
bool BKE_blendfile_write_partial(struct Main *bmain_src,
const char *filepath,
- const int write_flags,
- const int remap_mode,
+ int write_flags,
+ int remap_mode,
struct ReportList *reports);
void BKE_blendfile_write_partial_end(struct Main *bmain_src);
diff --git a/source/blender/blenkernel/BKE_blendfile_link_append.h b/source/blender/blenkernel/BKE_blendfile_link_append.h
new file mode 100644
index 00000000000..983c93223a1
--- /dev/null
+++ b/source/blender/blenkernel/BKE_blendfile_link_append.h
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct BlendHandle;
+struct ID;
+struct Library;
+struct LibraryLink_Params;
+struct Main;
+struct ReportList;
+struct Scene;
+struct View3D;
+struct ViewLayer;
+
+typedef struct BlendfileLinkAppendContext BlendfileLinkAppendContext;
+typedef struct BlendfileLinkAppendContextItem BlendfileLinkAppendContextItem;
+
+/**
+ * Allocate and initialize a new context to link/append data-blocks.
+ */
+BlendfileLinkAppendContext *BKE_blendfile_link_append_context_new(
+ struct LibraryLink_Params *params);
+/**
+ * Free a link/append context.
+ */
+void BKE_blendfile_link_append_context_free(struct BlendfileLinkAppendContext *lapp_context);
+/**
+ * Set or clear flags in given \a lapp_context.
+ *
+ * \param flag: A combination of:
+ * - #eFileSel_Params_Flag from `DNA_space_types.h` &
+ * - #eBLOLibLinkFlags * from `BLO_readfile.h`.
+ * \param do_set: Set the given \a flag if true, clear it otherwise.
+ */
+void BKE_blendfile_link_append_context_flag_set(struct BlendfileLinkAppendContext *lapp_context,
+ int flag,
+ bool do_set);
+
+/**
+ * Store reference to a Blender's embedded memfile into the context.
+ *
+ * \note This is required since embedded startup blender file is handled in `ED` module, which
+ * cannot be linked in BKE code.
+ */
+void BKE_blendfile_link_append_context_embedded_blendfile_set(
+ struct BlendfileLinkAppendContext *lapp_context,
+ const void *blendfile_mem,
+ int blendfile_memsize);
+/** Clear reference to Blender's embedded startup file into the context. */
+void BKE_blendfile_link_append_context_embedded_blendfile_clear(
+ struct BlendfileLinkAppendContext *lapp_context);
+
+/**
+ * Add a new source library to search for items to be linked to the given link/append context.
+ *
+ * \param libname: the absolute path to the library blend file.
+ * \param blo_handle: the blend file handle of the library, NULL is not available. Note that this
+ * is only borrowed for linking purpose, no releasing or other management will
+ * be performed by #BKE_blendfile_link_append code on it.
+ *
+ * \note *Never* call #BKE_blendfile_link_append_context_library_add()
+ * after having added some items.
+ */
+void BKE_blendfile_link_append_context_library_add(struct BlendfileLinkAppendContext *lapp_context,
+ const char *libname,
+ struct BlendHandle *blo_handle);
+/**
+ * Add a new item (data-block name and `idcode`) to be searched and linked/appended from libraries
+ * associated to the given context.
+ *
+ * \param userdata: an opaque user-data pointer stored in generated link/append item.
+ *
+ * TODO: Add a more friendly version of this that combines it with the call to
+ * #BKE_blendfile_link_append_context_item_library_index_enable to enable the added item for all
+ * added library sources.
+ */
+struct BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add(
+ struct BlendfileLinkAppendContext *lapp_context,
+ const char *idname,
+ short idcode,
+ void *userdata);
+
+#define BLENDFILE_LINK_APPEND_INVALID -1
+/**
+ * Search for all ID matching given `id_types_filter` in given `library_index`, and add them to
+ * the list of items to process.
+ *
+ * \note #BKE_blendfile_link_append_context_library_add should never be called on the same
+ *`lapp_context` after this function.
+ *
+ * \param id_types_filter: A set of `FILTER_ID` bitflags, the types of IDs to add to the items
+ * list.
+ * \param library_index: The index of the library to look into, in given `lapp_context`.
+ *
+ * \return The number of items found and added to the list, or `BLENDFILE_LINK_APPEND_INVALID` if
+ * it could not open the .blend file.
+ */
+int BKE_blendfile_link_append_context_item_idtypes_from_library_add(
+ struct BlendfileLinkAppendContext *lapp_context,
+ struct ReportList *reports,
+ uint64_t id_types_filter,
+ int library_index);
+
+/**
+ * Enable search of the given \a item into the library stored at given index in the link/append
+ * context.
+ */
+void BKE_blendfile_link_append_context_item_library_index_enable(
+ struct BlendfileLinkAppendContext *lapp_context,
+ struct BlendfileLinkAppendContextItem *item,
+ int library_index);
+/**
+ * Check if given link/append context is empty (has no items to process) or not.
+ */
+bool BKE_blendfile_link_append_context_is_empty(struct BlendfileLinkAppendContext *lapp_context);
+
+void *BKE_blendfile_link_append_context_item_userdata_get(
+ struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item);
+struct ID *BKE_blendfile_link_append_context_item_newid_get(
+ struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item);
+short BKE_blendfile_link_append_context_item_idcode_get(
+ struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item);
+
+typedef enum eBlendfileLinkAppendForeachItemFlag {
+ /** Loop over directly linked items (i.e. those explicitly defined by user code). */
+ BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT = 1 << 0,
+ /** Loop over indirectly linked items (i.e. those defined by internal code, as dependencies of
+ * direct ones).
+ *
+ * IMPORTANT: Those 'indirect' items currently may not cover **all** indirectly linked data.
+ * See comments in #foreach_libblock_link_append_callback. */
+ BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT = 1 << 1,
+} eBlendfileLinkAppendForeachItemFlag;
+/**
+ * Callback called by #BKE_blendfile_link_append_context_item_foreach over each (or a subset of
+ * each) of the items in given #BlendfileLinkAppendContext.
+ *
+ * \param userdata: An opaque void pointer passed to the `callback_function`.
+ *
+ * \return `true` if iteration should continue, `false` otherwise.
+ */
+typedef bool (*BKE_BlendfileLinkAppendContexteItemFunction)(
+ struct BlendfileLinkAppendContext *lapp_context,
+ struct BlendfileLinkAppendContextItem *item,
+ void *userdata);
+/**
+ * Iterate over all (or a subset) of the items listed in given #BlendfileLinkAppendContext,
+ * and call the `callback_function` on them.
+ *
+ * \param flag: Control which type of items to process (see
+ * #eBlendfileLinkAppendForeachItemFlag enum flags).
+ * \param userdata: An opaque void pointer passed to the `callback_function`.
+ */
+void BKE_blendfile_link_append_context_item_foreach(
+ struct BlendfileLinkAppendContext *lapp_context,
+ BKE_BlendfileLinkAppendContexteItemFunction callback_function,
+ eBlendfileLinkAppendForeachItemFlag flag,
+ void *userdata);
+
+/**
+ * Perform append operation, using modern ID usage looper to detect which ID should be kept
+ * linked, made local, duplicated as local, re-used from local etc.
+ *
+ * The IDs processed by this functions are the one that have been linked by a previous call to
+ * #BKE_blendfile_link on the same `lapp_context`.
+ */
+void BKE_blendfile_append(struct BlendfileLinkAppendContext *lapp_context,
+ struct ReportList *reports);
+/**
+ * Perform linking operation on all items added to given `lapp_context`.
+ */
+void BKE_blendfile_link(struct BlendfileLinkAppendContext *lapp_context,
+ struct ReportList *reports);
+
+/**
+ * Try to relocate all linked IDs added to `lapp_context`, belonging to the given `library`.
+ *
+ * This function searches for matching IDs (type and name) in all libraries added to the given
+ * `lapp_context`.
+ *
+ * Typical usages include:
+ * - Relocating a library:
+ * - Add the new target library path to `lapp_context`.
+ * - Add all IDs from the library to relocate to `lapp_context`
+ * - Mark the new target library to be considered for each ID.
+ * - Call this function.
+ *
+ * - Searching for (e.g.missing) linked IDs in a set or sub-set of libraries:
+ * - Add all potential library sources paths to `lapp_context`.
+ * - Add all IDs to search for to `lapp_context`.
+ * - Mark which libraries should be considered for each ID.
+ * - Call this function.
+ */
+void BKE_blendfile_library_relocate(struct BlendfileLinkAppendContext *lapp_context,
+ struct ReportList *reports,
+ struct Library *library,
+ bool do_reload);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_boids.h b/source/blender/blenkernel/BKE_boids.h
index 71a4d35767f..a9c8ad6422f 100644
--- a/source/blender/blenkernel/BKE_boids.h
+++ b/source/blender/blenkernel/BKE_boids.h
@@ -51,7 +51,13 @@ typedef struct BoidBrainData {
} BoidBrainData;
void boids_precalc_rules(struct ParticleSettings *part, float cfra);
+/**
+ * Determines the velocity the boid wants to have.
+ */
void boid_brain(BoidBrainData *bbd, int p, struct ParticleData *pa);
+/**
+ * Tries to realize the wanted velocity taking all constraints into account.
+ */
void boid_body(BoidBrainData *bbd, struct ParticleData *pa);
void boid_default_settings(struct BoidSettings *boids);
struct BoidRule *boid_new_rule(int type);
diff --git a/source/blender/blenkernel/BKE_bpath.h b/source/blender/blenkernel/BKE_bpath.h
index 3ec5409ca7f..ccbd0d4cbe4 100644
--- a/source/blender/blenkernel/BKE_bpath.h
+++ b/source/blender/blenkernel/BKE_bpath.h
@@ -16,10 +16,14 @@
/** \file
* \ingroup bke
- * \attention Based on ghash, difference is ghash is not a fixed size,
- * so for BPath we don't need to malloc
+ *
+ * \warning All paths manipulated by this API are assumed to be either constant char buffers of
+ * `FILE_MAX` size, or allocated char buffers not bigger than `FILE_MAX`.
*/
+/* TODO: Make this module handle a bit more safely string length, instead of assuming buffers are
+ * FILE_MAX length etc. */
+
#pragma once
#ifdef __cplusplus
@@ -31,66 +35,181 @@ struct ListBase;
struct Main;
struct ReportList;
-/* Function that does something with an ID's file path. Should return 1 if the
- * path has changed, and in that case, should write the result to pathOut. */
-typedef bool (*BPathVisitor)(void *userdata, char *path_dst, const char *path_src);
-/* Executes 'visit' for each path associated with 'id'. */
-void BKE_bpath_traverse_id(struct Main *bmain,
- struct ID *id,
- BPathVisitor visit_cb,
- const int flag,
- void *bpath_user_data);
-void BKE_bpath_traverse_id_list(struct Main *bmain,
- struct ListBase *lb,
- BPathVisitor visit_cb,
- const int flag,
- void *bpath_user_data);
-void BKE_bpath_traverse_main(struct Main *bmain,
- BPathVisitor visit_cb,
- const int flag,
- void *bpath_user_data);
-bool BKE_bpath_relocate_visitor(void *oldbasepath, char *path_dst, const char *path_src);
-
-/* Functions for temp backup/restore of paths, path count must NOT change */
-void *BKE_bpath_list_backup(struct Main *bmain, const int flag);
-void BKE_bpath_list_restore(struct Main *bmain, const int flag, void *ls_handle);
-void BKE_bpath_list_free(void *ls_handle);
-
-enum {
- /* convert paths to absolute */
- BKE_BPATH_TRAVERSE_ABS = (1 << 0),
- /* skip library paths */
- BKE_BPATH_TRAVERSE_SKIP_LIBRARY = (1 << 1),
- /* skip packed data */
- BKE_BPATH_TRAVERSE_SKIP_PACKED = (1 << 2),
- /* skip paths where a single dir is used with an array of files, eg.
- * sequence strip images and pointcache. in this case only use the first
- * file, this is needed for directory manipulation functions which might
- * otherwise modify the same directory multiple times */
- BKE_BPATH_TRAVERSE_SKIP_MULTIFILE = (1 << 3),
- /* reload data (when the path is edited) */
- BKE_BPATH_TRAVERSE_RELOAD_EDITED = (1 << 4),
-};
-
-/* high level funcs */
-
-/* creates a text file with missing files if there are any */
+/** \name Core `foreach_path` API.
+ * \{ */
+
+typedef enum eBPathForeachFlag {
+ /** Flags controlling the behavior of the generic BPath API. */
+
+ /** Ensures the `absolute_base_path` member of #BPathForeachPathData is initialized properly with
+ * the path of the current .blend file. This can be used by the callbacks to convert relative
+ * paths to absolute ones. */
+ BKE_BPATH_FOREACH_PATH_ABSOLUTE = (1 << 0),
+ /** Skip paths of linked IDs. */
+ BKE_BPATH_FOREACH_PATH_SKIP_LINKED = (1 << 1),
+ /** Skip paths when their matching data is packed. */
+ BKE_BPATH_FOREACH_PATH_SKIP_PACKED = (1 << 2),
+ /** Resolve tokens within a virtual filepath to a single, concrete, filepath. */
+ BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN = (1 << 3),
+ /* Skip weak reference paths. Those paths are typically 'nice to have' extra information, but are
+ * not used as actual source of data by the current .blend file.
+ *
+ * NOTE: Currently this only concerns the weak reference to a library file stored in
+ * `ID::library_weak_reference`. */
+ BKE_BPATH_TRAVERSE_SKIP_WEAK_REFERENCES = (1 << 5),
+
+ /** Flags not affecting the generic BPath API. Those may be used by specific IDTypeInfo
+ * `foreach_path` implementations and/or callbacks to implement specific behaviors. */
+
+ /** Skip paths where a single dir is used with an array of files, eg. sequence strip images or
+ * point-caches. In this case only use the first file path is processed.
+ *
+ * This is needed for directory manipulation callbacks which might otherwise modify the same
+ * directory multiple times. */
+ BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE = (1 << 8),
+ /** Reload data (when the path is edited).
+ * \note Only used by Image IDType currently. */
+ BKE_BPATH_FOREACH_PATH_RELOAD_EDITED = (1 << 9),
+} eBPathForeachFlag;
+
+struct BPathForeachPathData;
+
+/** Callback used to iterate over an ID's file paths.
+ *
+ * \note `path`s parameters should be considered as having a maximal `FILE_MAX` string length.
+ *
+ * \return `true` if the path has been changed, and in that case, result should be written into
+ * `r_path_dst`. */
+typedef bool (*BPathForeachPathFunctionCallback)(struct BPathForeachPathData *bpath_data,
+ char *r_path_dst,
+ const char *path_src);
+
+/** Storage for common data needed across the BPath 'foreach_path' code. */
+typedef struct BPathForeachPathData {
+ struct Main *bmain;
+
+ BPathForeachPathFunctionCallback callback_function;
+ eBPathForeachFlag flag;
+
+ void *user_data;
+
+ /* 'Private' data, caller don't need to set those. */
+
+ /** The root to use as base for relative paths. Only set if `BKE_BPATH_FOREACH_PATH_ABSOLUTE`
+ * flag is set, NULL otherwise. */
+ const char *absolute_base_path;
+} BPathForeachPathData;
+
+/** Run `bpath_data.callback_function` on all paths contained in `id`. */
+void BKE_bpath_foreach_path_id(BPathForeachPathData *bpath_data, struct ID *id);
+
+/** Run `bpath_data.callback_function` on all paths of all IDs in `bmain`. */
+void BKE_bpath_foreach_path_main(BPathForeachPathData *bpath_data);
+
+/** \} */
+
+/** \name Helpers to handle common cases from `IDTypeInfo`'s `foreach_path` functions.
+ * \{ */
+
+/* TODO: Investigate using macros around those calls to check a bit better about actual
+ * strings/buffers length (e,g, with static asserts). */
+
+/**
+ * Run the callback on a path, replacing the content of the string as needed.
+ *
+ * \param path: A fixed, FILE_MAX-sized char buffer.
+ *
+ * \return true is \a path was modified, false otherwise.
+ */
+bool BKE_bpath_foreach_path_fixed_process(struct BPathForeachPathData *bpath_data, char *path);
+
+/**
+ * Run the callback on a (directory + file) path, replacing the content of the two strings as
+ * needed.
+ *
+ * \param path_dir: A fixed, FILE_MAXDIR-sized char buffer.
+ * \param path_file: A fixed, FILE_MAXFILE-sized char buffer.
+ *
+ * \return true is \a path_dir and/or \a path_file were modified, false otherwise.
+ */
+bool BKE_bpath_foreach_path_dirfile_fixed_process(struct BPathForeachPathData *bpath_data,
+ char *path_dir,
+ char *path_file);
+
+/**
+ * Run the callback on a path, replacing the content of the string as needed.
+ *
+ * \param path: A pointer to a MEM-allocated string. If modified, it will be freed and replaced by
+ * a new allocated string.
+ * \note path is expected to be FILE_MAX size or smaller.
+ *
+ * \return true is \a path was modified and re-allocated, false otherwise.
+ */
+bool BKE_bpath_foreach_path_allocated_process(struct BPathForeachPathData *bpath_data,
+ char **path);
+
+/** \} */
+
+/** \name High level features.
+ * \{ */
+
+/** Check for missing files. */
void BKE_bpath_missing_files_check(struct Main *bmain, struct ReportList *reports);
+
+/** Recursively search into given search directory, for all file paths of all IDs in given \a
+ * bmain, and replace existing paths as needed.
+ *
+ * \note The search will happen into the whole search directory tree recursively (with a limit of
+ * MAX_DIR_RECURSE), if several files are found matching a searched filename, the biggest one will
+ * be used. This is so that things like thumbnails don't get selected instead of the actual image
+ * e.g.
+ *
+ * \param searchpath: The root directory in which the new filepaths should be searched for.
+ * \param find_all: If `true`, also search for files which current path is still valid, if `false`
+ * skip those still valid paths.
+ * */
void BKE_bpath_missing_files_find(struct Main *bmain,
const char *searchpath,
struct ReportList *reports,
- const bool find_all);
+ bool find_all);
+
+/** Rebase all relative file paths in given \a bmain from \a basedir_src to \a basedir_dst. */
void BKE_bpath_relative_rebase(struct Main *bmain,
const char *basedir_src,
const char *basedir_dst,
struct ReportList *reports);
+
+/** Make all absolute file paths in given \a bmain relative to given \a basedir. */
void BKE_bpath_relative_convert(struct Main *bmain,
const char *basedir,
struct ReportList *reports);
+
+/** Make all relative file paths in given \a bmain absolute, using given \a basedir as root. */
void BKE_bpath_absolute_convert(struct Main *bmain,
const char *basedir,
struct ReportList *reports);
+/** Temp backup of paths from all IDs in given \a bmain.
+ *
+ * \return An opaque handle to pass to #BKE_bpath_list_restore and #BKE_bpath_list_free.
+ */
+void *BKE_bpath_list_backup(struct Main *bmain, eBPathForeachFlag flag);
+
+/** Restore the temp backup of paths from \a path_list_handle into all IDs in given \a bmain.
+ *
+ * \note This function assumes that the data in given Main did not change (no
+ * addition/deletion/re-ordering of IDs, or their file paths) since the call to
+ * #BKE_bpath_list_backup that generated the given \a path_list_handle. */
+void BKE_bpath_list_restore(struct Main *bmain, eBPathForeachFlag flag, void *path_list_handle);
+
+/** Free the temp backup of paths in \a path_list_handle.
+ *
+ * \note This function assumes that the path list has already been restored with a call to
+ * #BKE_bpath_list_restore, and is therefore empty. */
+void BKE_bpath_list_free(void *path_list_handle);
+
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 452a08bc9c8..ee5ab905d70 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -39,70 +39,109 @@ struct UnifiedPaintSettings;
// enum eCurveMappingPreset;
-/* globals for brush execution */
+/* Globals for brush execution. */
+
void BKE_brush_system_init(void);
void BKE_brush_system_exit(void);
-/* datablock functions */
-struct Brush *BKE_brush_add(struct Main *bmain, const char *name, const eObjectMode ob_mode);
+/* Data-block functions. */
+
+/**
+ * \note Resulting brush will have two users: one as a fake user,
+ * another is assumed to be used by the caller.
+ */
+struct Brush *BKE_brush_add(struct Main *bmain, const char *name, eObjectMode ob_mode);
+/**
+ * Add a new gp-brush.
+ */
struct Brush *BKE_brush_add_gpencil(struct Main *bmain,
struct ToolSettings *ts,
const char *name,
eObjectMode mode);
+/**
+ * Delete a Brush.
+ */
bool BKE_brush_delete(struct Main *bmain, struct Brush *brush);
+/**
+ * Add grease pencil settings.
+ */
void BKE_brush_init_gpencil_settings(struct Brush *brush);
-struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode);
+struct Brush *BKE_brush_first_search(struct Main *bmain, eObjectMode ob_mode);
void BKE_brush_sculpt_reset(struct Brush *brush);
-void BKE_brush_gpencil_paint_presets(struct Main *bmain,
- struct ToolSettings *ts,
- const bool reset);
-void BKE_brush_gpencil_vertex_presets(struct Main *bmain,
- struct ToolSettings *ts,
- const bool reset);
-void BKE_brush_gpencil_sculpt_presets(struct Main *bmain,
- struct ToolSettings *ts,
- const bool reset);
-void BKE_brush_gpencil_weight_presets(struct Main *bmain,
- struct ToolSettings *ts,
- const bool reset);
-void BKE_gpencil_brush_preset_set(struct Main *bmain, struct Brush *brush, const short type);
-
-/* jitter */
+/**
+ * Create a set of grease pencil Drawing presets.
+ */
+void BKE_brush_gpencil_paint_presets(struct Main *bmain, struct ToolSettings *ts, bool reset);
+/**
+ * Create a set of grease pencil Vertex Paint presets.
+ */
+void BKE_brush_gpencil_vertex_presets(struct Main *bmain, struct ToolSettings *ts, bool reset);
+/**
+ * Create a set of grease pencil Sculpt Paint presets.
+ */
+void BKE_brush_gpencil_sculpt_presets(struct Main *bmain, struct ToolSettings *ts, bool reset);
+/**
+ * Create a set of grease pencil Weight Paint presets.
+ */
+void BKE_brush_gpencil_weight_presets(struct Main *bmain, struct ToolSettings *ts, bool reset);
+void BKE_gpencil_brush_preset_set(struct Main *bmain, struct Brush *brush, short type);
+
void BKE_brush_jitter_pos(const struct Scene *scene,
struct Brush *brush,
const float pos[2],
float jitterpos[2]);
void BKE_brush_randomize_texture_coords(struct UnifiedPaintSettings *ups, bool mask);
-/* brush curve */
+/* Brush curve. */
+
+/**
+ * Library Operations
+ */
void BKE_brush_curve_preset(struct Brush *b, enum eCurveMappingPreset preset);
-float BKE_brush_curve_strength_clamped(struct Brush *br, float p, const float len);
-float BKE_brush_curve_strength(const struct Brush *br, float p, const float len);
+/**
+ * Uses the brush curve control to find a strength value between 0 and 1.
+ */
+float BKE_brush_curve_strength_clamped(const struct Brush *br, float p, float len);
+/**
+ * Uses the brush curve control to find a strength value.
+ */
+float BKE_brush_curve_strength(const struct Brush *br, float p, float len);
+
+/* Sampling. */
-/* sampling */
+/**
+ * Generic texture sampler for 3D painting systems.
+ * point has to be either in region space mouse coordinates,
+ * or 3d world coordinates for 3D mapping.
+ *
+ * RGBA outputs straight alpha.
+ */
float BKE_brush_sample_tex_3d(const struct Scene *scene,
const struct Brush *br,
const float point[3],
float rgba[4],
- const int thread,
+ int thread,
struct ImagePool *pool);
float BKE_brush_sample_masktex(const struct Scene *scene,
struct Brush *br,
const float point[2],
- const int thread,
+ int thread,
struct ImagePool *pool);
-/* texture */
+/* Texture. */
+
unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool use_secondary);
-/* radial control */
+/**
+ * Radial control.
+ */
struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br,
bool secondary,
bool display_gradient);
-/* unified strength size and color */
+/* Unified strength size and color. */
const float *BKE_brush_color_get(const struct Scene *scene, const struct Brush *brush);
const float *BKE_brush_secondary_color_get(const struct Scene *scene, const struct Brush *brush);
@@ -127,12 +166,16 @@ bool BKE_brush_use_size_pressure(const struct Brush *brush);
bool BKE_brush_sculpt_has_secondary_color(const struct Brush *brush);
-/* scale unprojected radius to reflect a change in the brush's 2D size */
+/**
+ * Scale unprojected radius to reflect a change in the brush's 2D size.
+ */
void BKE_brush_scale_unprojected_radius(float *unprojected_radius,
int new_brush_size,
int old_brush_size);
-/* scale brush size to reflect a change in the brush's unprojected radius */
+/**
+ * Scale brush size to reflect a change in the brush's unprojected radius.
+ */
void BKE_brush_scale_size(int *r_brush_size,
float new_unprojected_radius,
float old_unprojected_radius);
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index 06be8ec80fc..c454e441551 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -48,7 +48,7 @@ struct BVHCache;
typedef struct BVHTreeFromEditMesh {
struct BVHTree *tree;
- /* default callbacks to bvh nearest and raycast */
+ /** Default callbacks to BVH nearest and ray-cast. */
BVHTree_NearestPointCallback nearest_callback;
BVHTree_RayCastCallback raycast_callback;
@@ -60,18 +60,19 @@ typedef struct BVHTreeFromEditMesh {
} BVHTreeFromEditMesh;
/**
- * Struct that stores basic information about a BVHTree built from a mesh.
+ * Struct that stores basic information about a #BVHTree built from a mesh.
*/
typedef struct BVHTreeFromMesh {
struct BVHTree *tree;
- /* default callbacks to bvh nearest and raycast */
+ /** Default callbacks to BVH nearest and ray-cast. */
BVHTree_NearestPointCallback nearest_callback;
BVHTree_RayCastCallback raycast_callback;
/* Vertex array, so that callbacks have instant access to data. */
const struct MVert *vert;
- const struct MEdge *edge; /* only used for BVHTreeFromMeshEdges */
+ const float (*vert_normals)[3];
+ const struct MEdge *edge; /* only used for #BVHTreeFromMeshEdges */
const struct MFace *face;
const struct MLoop *loop;
const struct MLoopTri *looptri;
@@ -105,7 +106,7 @@ typedef enum BVHCacheType {
} BVHCacheType;
/**
- * Builds a bvh tree where nodes are the relevant elements of the given mesh.
+ * Builds a BVH tree where nodes are the relevant elements of the given mesh.
* Configures #BVHTreeFromMesh.
*
* The tree is build in mesh space coordinates, this means special care must be made on queries
@@ -113,11 +114,14 @@ typedef enum BVHCacheType {
* Reason for this is that bvh_from_mesh_* can use a cache in some cases and so it
* becomes possible to reuse a #BVHTree.
*
- * free_bvhtree_from_mesh should be called when the tree is no longer needed.
+ * #free_bvhtree_from_mesh should be called when the tree is no longer needed.
*/
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
+/**
+ * Builds a BVH-tree where nodes are the vertices of the given `em`.
+ */
BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const BLI_bitmap *mask,
@@ -125,26 +129,36 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const BVHCacheType bvh_cache_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds a BVH-tree where nodes are the given vertices (NOTE: does not copy given `vert`!).
+ * \param vert_allocated: if true, vert freeing will be done when freeing data.
+ * \param verts_mask: if not null, true elements give which vert to add to BVH-tree.
+ * \param verts_num_active: if >= 0, number of active verts to add to BVH-tree
+ * (else will be computed from mask).
+ */
BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
- const int verts_num,
- const bool vert_allocated,
- const BLI_bitmap *mask,
+ int verts_num,
+ bool vert_allocated,
+ const BLI_bitmap *verts_mask,
int verts_num_active,
float epsilon,
int tree_type,
int axis,
- const BVHCacheType bvh_cache_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
+/**
+ * Builds a BVH-tree where nodes are the edges of the given `em`.
+ */
BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const BLI_bitmap *edges_mask,
@@ -152,43 +166,63 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const BVHCacheType bvh_cache_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds a BVH-tree where nodes are the given edges.
+ * \param vert, vert_allocated: if true, elem freeing will be done when freeing data.
+ * \param edge, edge_allocated: if true, elem freeing will be done when freeing data.
+ * \param edges_mask: if not null, true elements give which vert to add to BVH-tree.
+ * \param edges_num_active: if >= 0, number of active edges to add to BVH-tree
+ * (else will be computed from mask).
+ */
BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
- const bool vert_allocated,
+ bool vert_allocated,
const struct MEdge *edge,
- const int edges_num,
- const bool edge_allocated,
+ int edges_num,
+ bool edge_allocated,
const BLI_bitmap *edges_mask,
int edges_num_active,
float epsilon,
int tree_type,
int axis,
- const BVHCacheType bvh_cache_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds a BVH-tree where nodes are the given tessellated faces
+ * (NOTE: does not copy given mfaces!).
+ * \param vert_allocated: if true, vert freeing will be done when freeing data.
+ * \param face_allocated: if true, face freeing will be done when freeing data.
+ * \param faces_mask: if not null, true elements give which faces to add to BVH-tree.
+ * \param faces_num_active: if >= 0, number of active faces to add to BVH-tree
+ * (else will be computed from mask).
+ */
BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
- const bool vert_allocated,
+ bool vert_allocated,
const struct MFace *face,
- const int numFaces,
- const bool face_allocated,
- const BLI_bitmap *mask,
+ int numFaces,
+ bool face_allocated,
+ const BLI_bitmap *faces_mask,
int faces_num_active,
float epsilon,
int tree_type,
int axis,
- const BVHCacheType bvh_cache_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_editmesh_looptri(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
+/**
+ * Builds a BVH-tree where nodes are the `looptri` faces of the given `bm`.
+ */
BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const BLI_bitmap *mask,
@@ -196,56 +230,70 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const BVHCacheType bvh_cache_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds a BVH-tree where nodes are the looptri faces of the given mesh.
+ *
+ * \note for edit-mesh this is currently a duplicate of #bvhtree_from_mesh_faces_ex
+ */
BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
- const bool vert_allocated,
+ bool vert_allocated,
const struct MLoop *mloop,
- const bool loop_allocated,
+ bool loop_allocated,
const struct MLoopTri *looptri,
- const int looptri_num,
- const bool looptri_allocated,
+ int looptri_num,
+ bool looptri_allocated,
const BLI_bitmap *mask,
int looptri_num_active,
float epsilon,
int tree_type,
int axis,
- const BVHCacheType bvh_cache_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds or queries a BVH-cache for the cache BVH-tree of the request type.
+ *
+ * \note This function only fills a cache, and therefore the mesh argument can
+ * be considered logically const. Concurrent access is protected by a mutex.
+ */
BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
const struct Mesh *mesh,
- const BVHCacheType bvh_cache_type,
- const int tree_type);
+ BVHCacheType bvh_cache_type,
+ int tree_type);
+/**
+ * Builds or queries a BVH-cache for the cache BVH-tree of the request type.
+ */
BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
- const int tree_type,
- const BVHCacheType bvh_cache_type,
+ int tree_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
/**
- * Frees data allocated by a call to bvhtree_from_mesh_*.
+ * Frees data allocated by a call to `bvhtree_from_editmesh_*`.
*/
void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data);
+/**
+ * Frees data allocated by a call to `bvhtree_from_mesh_*`.
+ */
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data);
/**
* Math functions used by callbacks
*/
-float bvhtree_ray_tri_intersection(const BVHTreeRay *ray,
- const float m_dist,
- const float v0[3],
- const float v1[3],
- const float v2[3]);
+float bvhtree_ray_tri_intersection(
+ const BVHTreeRay *ray, float m_dist, const float v0[3], const float v1[3], const float v2[3]);
float bvhtree_sphereray_tri_intersection(const BVHTreeRay *ray,
float radius,
- const float m_dist,
+ float m_dist,
const float v0[3],
const float v1[3],
const float v2[3]);
@@ -260,7 +308,7 @@ typedef struct BVHTreeFromPointCloud {
BVHTree *BKE_bvhtree_from_pointcloud_get(struct BVHTreeFromPointCloud *data,
const struct PointCloud *pointcloud,
- const int tree_type);
+ int tree_type);
void free_bvhtree_from_pointcloud(struct BVHTreeFromPointCloud *data);
@@ -272,6 +320,9 @@ void free_bvhtree_from_pointcloud(struct BVHTreeFromPointCloud *data);
bool bvhcache_has_tree(const struct BVHCache *bvh_cache, const BVHTree *tree);
struct BVHCache *bvhcache_init(void);
+/**
+ * Frees a BVH-cache.
+ */
void bvhcache_free(struct BVHCache *bvh_cache);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h
index 836597f95da..c6821d88d2a 100644
--- a/source/blender/blenkernel/BKE_cachefile.h
+++ b/source/blender/blenkernel/BKE_cachefile.h
@@ -28,6 +28,7 @@ extern "C" {
#endif
struct CacheFile;
+struct CacheFileLayer;
struct CacheReader;
struct Depsgraph;
struct Main;
@@ -50,9 +51,7 @@ bool BKE_cachefile_filepath_get(const struct Main *bmain,
const struct CacheFile *cache_file,
char r_filename[1024]);
-float BKE_cachefile_time_offset(const struct CacheFile *cache_file,
- const float time,
- const float fps);
+float BKE_cachefile_time_offset(const struct CacheFile *cache_file, float time, float fps);
/* Modifiers and constraints open and free readers through these. */
void BKE_cachefile_reader_open(struct CacheFile *cache_file,
@@ -61,9 +60,24 @@ void BKE_cachefile_reader_open(struct CacheFile *cache_file,
const char *object_path);
void BKE_cachefile_reader_free(struct CacheFile *cache_file, struct CacheReader **reader);
+/**
+ * Determine whether the #CacheFile should use a render engine procedural. If so, data is not read
+ * from the file and bounding boxes are used to represent the objects in the Scene.
+ * Render engines will receive the bounding box as a placeholder but can instead
+ * load the data directly if they support it.
+ */
bool BKE_cache_file_uses_render_procedural(const struct CacheFile *cache_file,
struct Scene *scene,
- const int dag_eval_mode);
+ int dag_eval_mode);
+
+/* Add a layer to the cache_file. Return NULL if the filename is already that of an existing layer
+ * or if the number of layers exceeds the maximum allowed layer count. */
+struct CacheFileLayer *BKE_cachefile_add_layer(struct CacheFile *cache_file,
+ const char filename[1024]);
+
+struct CacheFileLayer *BKE_cachefile_get_active_layer(struct CacheFile *cache_file);
+
+void BKE_cachefile_remove_layer(struct CacheFile *cache_file, struct CacheFileLayer *layer);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_callbacks.h b/source/blender/blenkernel/BKE_callbacks.h
index 7c518f33c89..2e4923ff3d2 100644
--- a/source/blender/blenkernel/BKE_callbacks.h
+++ b/source/blender/blenkernel/BKE_callbacks.h
@@ -114,14 +114,14 @@ typedef enum {
typedef struct bCallbackFuncStore {
struct bCallbackFuncStore *next, *prev;
- void (*func)(struct Main *, struct PointerRNA **, const int num_pointers, void *arg);
+ void (*func)(struct Main *, struct PointerRNA **, int num_pointers, void *arg);
void *arg;
short alloc;
} bCallbackFuncStore;
void BKE_callback_exec(struct Main *bmain,
struct PointerRNA **pointers,
- const int num_pointers,
+ int num_pointers,
eCbEvent evt);
void BKE_callback_exec_null(struct Main *bmain, eCbEvent evt);
void BKE_callback_exec_id(struct Main *bmain, struct ID *id, eCbEvent evt);
@@ -133,6 +133,9 @@ void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt);
void BKE_callback_remove(bCallbackFuncStore *funcstore, eCbEvent evt);
void BKE_callback_global_init(void);
+/**
+ * Call on application exit.
+ */
void BKE_callback_global_finalize(void);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index 9c775f75a38..ee78621c11f 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -37,22 +37,26 @@ struct Scene;
struct View3D;
struct rctf;
-/* Camera Datablock */
+/* Camera Data-block */
void *BKE_camera_add(struct Main *bmain, const char *name);
/* Camera Usage */
-float BKE_camera_object_dof_distance(const struct Object *ob);
+/**
+ * Get the camera's DOF value, takes the DOF object into account.
+ */
+float BKE_camera_object_dof_distance(struct Object *ob);
int BKE_camera_sensor_fit(int sensor_fit, float sizex, float sizey);
float BKE_camera_sensor_size(int sensor_fit, float sensor_x, float sensor_y);
-/* Camera Parameters:
+/**
+ * Camera Parameters:
*
* Intermediate struct for storing camera parameters from various sources,
- * to unify computation of viewplane, window matrix, ... */
-
+ * to unify computation of view-plane, window matrix, ... etc.
+ */
typedef struct CameraParams {
/* lens */
bool is_ortho;
@@ -84,7 +88,7 @@ typedef struct CameraParams {
float winmat[4][4];
} CameraParams;
-/* values for CameraParams.zoom, need to be taken into account for some operations */
+/* Values for CameraParams.zoom, need to be taken into account for some operations. */
#define CAMERA_PARAM_ZOOM_INIT_CAMOB 1.0f
#define CAMERA_PARAM_ZOOM_INIT_PERSP 2.0f
@@ -97,14 +101,17 @@ void BKE_camera_params_from_view3d(CameraParams *params,
void BKE_camera_params_compute_viewplane(
CameraParams *params, int winx, int winy, float aspx, float aspy);
+/**
+ * View-plane is assumed to be already computed.
+ */
void BKE_camera_params_compute_matrix(CameraParams *params);
/* Camera View Frame */
void BKE_camera_view_frame_ex(const struct Scene *scene,
const struct Camera *camera,
- const float drawsize,
- const bool do_clip,
+ float drawsize,
+ bool do_clip,
const float scale[3],
float r_asp[2],
float r_shift[2],
@@ -114,6 +121,11 @@ void BKE_camera_view_frame(const struct Scene *scene,
const struct Camera *camera,
float r_vec[4][3]);
+/**
+ * \param r_scale: only valid/useful for orthographic cameras.
+ *
+ * \note Don't move the camera, just yield the fit location.
+ */
bool BKE_camera_view_frame_fit_to_scene(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Object *camera_ob,
@@ -128,12 +140,18 @@ bool BKE_camera_view_frame_fit_to_coords(const struct Depsgraph *depsgraph,
/* Camera multi-view API */
+/**
+ * Returns the camera to be used for render.
+ */
struct Object *BKE_camera_multiview_render(const struct Scene *scene,
struct Object *camera,
const char *viewname);
+/**
+ * The view matrix is used by the viewport drawing, it is basically the inverted model matrix.
+ */
void BKE_camera_multiview_view_matrix(const struct RenderData *rd,
const struct Object *camera,
- const bool is_left,
+ bool is_left,
float r_viewmat[4][4]);
void BKE_camera_multiview_model_matrix(const struct RenderData *rd,
const struct Object *camera,
@@ -158,6 +176,7 @@ bool BKE_camera_multiview_spherical_stereo(const struct RenderData *rd,
const struct Object *camera);
/* Camera background image API */
+
struct CameraBGImage *BKE_camera_background_image_new(struct Camera *cam);
void BKE_camera_background_image_remove(struct Camera *cam, struct CameraBGImage *bgpic);
void BKE_camera_background_image_clear(struct Camera *cam);
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index dbf285feb92..ee73b926886 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -235,7 +235,9 @@ int cloth_bvh_collision(struct Depsgraph *depsgraph,
/* cloth.c */
/* Needed for modifier.c */
+/** Frees all. */
void cloth_free_modifier_extern(struct ClothModifierData *clmd);
+/** Frees all. */
void cloth_free_modifier(struct ClothModifierData *clmd);
void clothModifier_do(struct ClothModifierData *clmd,
struct Depsgraph *depsgraph,
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index 2c7143be60e..402bffea91d 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -54,25 +54,56 @@ typedef struct CollectionParent {
/* Collections */
+/**
+ * Add a collection to a collection ListBase and synchronize all render layers
+ * The ListBase is NULL when the collection is to be added to the master collection
+ */
struct Collection *BKE_collection_add(struct Main *bmain,
struct Collection *parent,
const char *name);
+/**
+ * Add \a collection_dst to all scene collections that reference object \a ob_src is in.
+ * Used to replace an instance object with a collection (library override operator).
+ *
+ * Logic is very similar to #BKE_collection_object_add_from().
+ */
void BKE_collection_add_from_object(struct Main *bmain,
struct Scene *scene,
const struct Object *ob_src,
struct Collection *collection_dst);
+/**
+ * Add \a collection_dst to all scene collections that reference collection \a collection_src is
+ * in.
+ *
+ * Logic is very similar to #BKE_collection_object_add_from().
+ */
void BKE_collection_add_from_collection(struct Main *bmain,
struct Scene *scene,
struct Collection *collection_src,
struct Collection *collection_dst);
+/**
+ * Free (or release) any data used by this collection (does not free the collection itself).
+ */
void BKE_collection_free_data(struct Collection *collection);
+/**
+ * Remove a collection, optionally removing its child objects or moving
+ * them to parent collections.
+ */
bool BKE_collection_delete(struct Main *bmain, struct Collection *collection, bool hierarchy);
+/**
+ * Make a deep copy (aka duplicate) of the given collection and all of its children, recursively.
+ *
+ * \warning This functions will clear all \a bmain #ID.idnew pointers, unless \a
+ * #LIB_ID_DUPLICATE_IS_SUBPROCESS duplicate option is passed on, in which case caller is
+ * responsible to reconstruct collection dependencies information's
+ * (i.e. call #BKE_main_collection_sync).
+ */
struct Collection *BKE_collection_duplicate(struct Main *bmain,
struct Collection *parent,
struct Collection *collection,
- const uint duplicate_flags,
- const uint duplicate_options);
+ uint duplicate_flags,
+ uint duplicate_options);
/* Master Collection for Scene */
@@ -91,28 +122,74 @@ struct Collection *BKE_collection_object_find(struct Main *bmain,
struct Object *ob);
bool BKE_collection_is_empty(const struct Collection *collection);
+/**
+ * Add object to collection
+ */
bool BKE_collection_object_add(struct Main *bmain,
struct Collection *collection,
struct Object *ob);
+/**
+ * Add \a ob_dst to all scene collections that reference object \a ob_src is in.
+ * Used for copying objects.
+ *
+ * Logic is very similar to #BKE_collection_add_from_object()
+ */
void BKE_collection_object_add_from(struct Main *bmain,
struct Scene *scene,
struct Object *ob_src,
struct Object *ob_dst);
+/**
+ * Remove object from collection.
+ */
bool BKE_collection_object_remove(struct Main *bmain,
struct Collection *collection,
struct Object *object,
- const bool free_us);
+ bool free_us);
+/**
+ * Move object from a collection into another
+ *
+ * If source collection is NULL move it from all the existing collections.
+ */
void BKE_collection_object_move(struct Main *bmain,
struct Scene *scene,
struct Collection *collection_dst,
struct Collection *collection_src,
struct Object *ob);
+/**
+ * Remove object from all collections of scene
+ */
bool BKE_scene_collections_object_remove(struct Main *bmain,
struct Scene *scene,
struct Object *object,
- const bool free_us);
+ bool free_us);
+
+/**
+ * Check all collections in \a bmain (including embedded ones in scenes) for CollectionObject with
+ * NULL object pointer, and remove them.
+ */
void BKE_collections_object_remove_nulls(struct Main *bmain);
+
+/**
+ * Check all collections in \a bmain (including embedded ones in scenes) for duplicate
+ * CollectionObject with a same object pointer within a same object, and remove them.
+ *
+ * NOTE: Always keeps the first of the detected duplicates.
+ */
+void BKE_collections_object_remove_duplicates(struct Main *bmain);
+
+/**
+ * Remove all NULL children from parent collections of changed \a collection.
+ * This is used for library remapping, where these pointers have been set to NULL.
+ * Otherwise this should never happen.
+ *
+ * \note caller must ensure #BKE_main_collection_sync_remap() is called afterwards!
+ *
+ * \param parent_collection: The collection owning the pointers that were remapped. May be \a NULL,
+ * in which case whole \a bmain database of collections is checked.
+ * \param child_collection: The collection that was remapped to another pointer. May be \a NULL,
+ * in which case whole \a bmain database of collections is checked.
+ */
void BKE_collections_child_remove_nulls(struct Main *bmain,
struct Collection *parent_collection,
struct Collection *child_collection);
@@ -136,9 +213,24 @@ struct Base *BKE_collection_or_layer_objects(const struct ViewLayer *view_layer,
/* Editing. */
-struct Collection *BKE_collection_from_index(struct Scene *scene, const int index);
+/**
+ * Return Scene Collection for a given index.
+ *
+ * The index is calculated from top to bottom counting the children before the siblings.
+ */
+struct Collection *BKE_collection_from_index(struct Scene *scene, int index);
+/**
+ * The automatic/fallback name of a new collection.
+ */
void BKE_collection_new_name_get(struct Collection *collection_parent, char *rname);
+/**
+ * The name to show in the interface.
+ */
const char *BKE_collection_ui_name_get(struct Collection *collection);
+/**
+ * Select all the objects in this Collection (and its nested collections) for this ViewLayer.
+ * Return true if any object was selected.
+ */
bool BKE_collection_objects_select(struct ViewLayer *view_layer,
struct Collection *collection,
bool deselect);
@@ -162,13 +254,36 @@ bool BKE_collection_move(struct Main *bmain,
bool relative_after,
struct Collection *collection);
+/**
+ * Find potential cycles in collections.
+ *
+ * \param new_ancestor: the potential new owner of given \a collection,
+ * or the collection to check if the later is NULL.
+ * \param collection: the collection we want to add to \a new_ancestor,
+ * may be NULL if we just want to ensure \a new_ancestor does not already have cycles.
+ * \return true if a cycle is found.
+ */
bool BKE_collection_cycle_find(struct Collection *new_ancestor, struct Collection *collection);
+/**
+ * Find and fix potential cycles in collections.
+ *
+ * \param collection: The collection to check for existing cycles.
+ * \return true if cycles are found and fixed.
+ */
bool BKE_collection_cycles_fix(struct Main *bmain, struct Collection *collection);
bool BKE_collection_has_collection(const struct Collection *parent,
const struct Collection *collection);
+/**
+ * Rebuild parent relationships from child ones, for all children of given \a collection.
+ *
+ * \note Given collection is assumed to already have valid parents.
+ */
void BKE_collection_parent_relations_rebuild(struct Collection *collection);
+/**
+ * Rebuild parent relationships from child ones, for all collections in given \a bmain.
+ */
void BKE_main_collections_parent_relations_rebuild(struct Main *bmain);
/* .blend file I/O */
@@ -224,6 +339,10 @@ typedef void (*BKE_scene_collections_Cb)(struct Collection *ob, void *data);
/* Iteration over collections in scene. */
+/**
+ * Only use this in non-performance critical situations
+ * (it iterates over all scene collections twice)
+ */
void BKE_scene_collections_iterator_begin(struct BLI_Iterator *iter, void *data_in);
void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter);
void BKE_scene_collections_iterator_end(struct BLI_Iterator *iter);
@@ -232,6 +351,13 @@ void BKE_scene_objects_iterator_begin(struct BLI_Iterator *iter, void *data_in);
void BKE_scene_objects_iterator_next(struct BLI_Iterator *iter);
void BKE_scene_objects_iterator_end(struct BLI_Iterator *iter);
+/**
+ * Generate a new #GSet (or extend given `objects_gset` if not NULL) with all objects referenced by
+ * all collections of given `scene`.
+ *
+ * \note This will include objects without a base currently
+ * (because they would belong to excluded collections only e.g.).
+ */
struct GSet *BKE_scene_objects_as_gset(struct Scene *scene, struct GSet *objects_gset);
#define FOREACH_SCENE_COLLECTION_BEGIN(scene, _instance) \
diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h
index 2c21b7355d6..d4c5c03ea79 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -116,12 +116,15 @@ void bvhtree_update_from_mvert(struct BVHTree *bvhtree,
/////////////////////////////////////////////////
-/* move Collision modifier object inter-frame with step = [0,1]
- * defined in collisions.c */
+/**
+ * Move Collision modifier object inter-frame with step = [0,1]
+ *
+ * \param step: is limited from 0 (frame start position) to 1 (frame end position).
+ */
void collision_move_object(struct CollisionModifierData *collmd,
- const float step,
- const float prevstep,
- const bool moving_bvh);
+ float step,
+ float prevstep,
+ bool moving_bvh);
void collision_get_collider_velocity(float vel_old[3],
float vel_new[3],
@@ -135,6 +138,11 @@ typedef struct CollisionRelation {
struct Object *ob;
} CollisionRelation;
+/**
+ * Create list of collision relations in the collection or entire scene.
+ * This is used by the depsgraph to build relations, as well as faster
+ * lookup of colliders during evaluation.
+ */
struct ListBase *BKE_collision_relations_create(struct Depsgraph *depsgraph,
struct Collection *collection,
unsigned int modifier_type);
@@ -142,6 +150,10 @@ void BKE_collision_relations_free(struct ListBase *relations);
/* Collision object lists for physics simulation evaluation. */
+/**
+ * Create effective list of colliders from relations built beforehand.
+ * Self will be excluded.
+ */
struct Object **BKE_collision_objects_create(struct Depsgraph *depsgraph,
struct Object *self,
struct Collection *collection,
@@ -155,6 +167,10 @@ typedef struct ColliderCache {
struct CollisionModifierData *collmd;
} ColliderCache;
+/**
+ * Create effective list of colliders from relations built beforehand.
+ * Self will be excluded.
+ */
struct ListBase *BKE_collider_cache_create(struct Depsgraph *depsgraph,
struct Object *self,
struct Collection *collection);
diff --git a/source/blender/blenkernel/BKE_colorband.h b/source/blender/blenkernel/BKE_colorband.h
index 0f46ced8b06..554b0f36b60 100644
--- a/source/blender/blenkernel/BKE_colorband.h
+++ b/source/blender/blenkernel/BKE_colorband.h
@@ -34,7 +34,7 @@ struct ColorBand;
void BKE_colorband_init(struct ColorBand *coba, bool rangetype);
void BKE_colorband_init_from_table_rgba(struct ColorBand *coba,
const float (*array)[4],
- const int array_len,
+ int array_len,
bool filter_sample);
struct ColorBand *BKE_colorband_add(bool rangetype);
bool BKE_colorband_evaluate(const struct ColorBand *coba, float in, float out[4]);
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
index ec2262d4f60..5ded49106da 100644
--- a/source/blender/blenkernel/BKE_colortools.h
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -59,52 +59,104 @@ enum {
CURVEMAP_SLOPE_POS_NEG = 2,
};
+/**
+ * Reset the view for current curve.
+ */
void BKE_curvemapping_reset_view(struct CurveMapping *cumap);
void BKE_curvemap_reset(struct CurveMap *cuma, const struct rctf *clipr, int preset, int slope);
-void BKE_curvemap_remove(struct CurveMap *cuma, const short flag);
+/**
+ * Removes with flag set.
+ */
+void BKE_curvemap_remove(struct CurveMap *cuma, short flag);
+/**
+ * Remove specified point.
+ */
bool BKE_curvemap_remove_point(struct CurveMap *cuma, struct CurveMapPoint *cmp);
struct CurveMapPoint *BKE_curvemap_insert(struct CurveMap *cuma, float x, float y);
+/**
+ * \param type: #eBezTriple_Handle
+ */
void BKE_curvemap_handle_set(struct CurveMap *cuma, int type);
-void BKE_curvemapping_changed(struct CurveMapping *cumap, const bool rem_doubles);
+/**
+ * \note only does current curvemap!.
+ */
+void BKE_curvemapping_changed(struct CurveMapping *cumap, bool rem_doubles);
void BKE_curvemapping_changed_all(struct CurveMapping *cumap);
-/* call before _all_ evaluation functions */
+/**
+ * Call before _all_ evaluation functions.
+ */
void BKE_curvemapping_init(struct CurveMapping *cumap);
-/* keep these (const CurveMap) - to help with thread safety */
-/* single curve, no table check */
+/**
+ * Keep these `const CurveMap` - to help with thread safety.
+ * \note Single curve, no table check.
+ * \note Table should be verified.
+ */
float BKE_curvemap_evaluateF(const struct CurveMapping *cumap,
const struct CurveMap *cuma,
float value);
-/* single curve, with table check */
+/**
+ * Single curve, with table check.
+ * Works with curve 'cur'.
+ */
float BKE_curvemapping_evaluateF(const struct CurveMapping *cumap, int cur, float value);
+/**
+ * Vector case.
+ */
void BKE_curvemapping_evaluate3F(const struct CurveMapping *cumap,
float vecout[3],
const float vecin[3]);
+/**
+ * RGB case, no black/white points, no pre-multiply.
+ */
void BKE_curvemapping_evaluateRGBF(const struct CurveMapping *cumap,
float vecout[3],
const float vecin[3]);
+/**
+ * Byte version of #BKE_curvemapping_evaluateRGBF.
+ */
void BKE_curvemapping_evaluate_premulRGB(const struct CurveMapping *cumap,
unsigned char vecout_byte[3],
const unsigned char vecin_byte[3]);
+/**
+ * Same as #BKE_curvemapping_evaluate_premulRGBF
+ * but black/bwmul are passed as args for the compositor
+ * where they can change per pixel.
+ *
+ * Use in conjunction with #BKE_curvemapping_set_black_white_ex
+ *
+ * \param black: Use instead of cumap->black
+ * \param bwmul: Use instead of cumap->bwmul
+ */
void BKE_curvemapping_evaluate_premulRGBF_ex(const struct CurveMapping *cumap,
float vecout[3],
const float vecin[3],
const float black[3],
const float bwmul[3]);
+/**
+ * RGB with black/white points and pre-multiply. tables are checked.
+ */
void BKE_curvemapping_evaluate_premulRGBF(const struct CurveMapping *cumap,
float vecout[3],
const float vecin[3]);
bool BKE_curvemapping_RGBA_does_something(const struct CurveMapping *cumap);
+void BKE_curvemapping_table_F(const struct CurveMapping *cumap, float **array, int *size);
void BKE_curvemapping_table_RGBA(const struct CurveMapping *cumap, float **array, int *size);
-/* non-const, these modify the curve */
-void BKE_curvemapping_premultiply(struct CurveMapping *cumap, int restore);
+/**
+ * Call when you do images etc, needs restore too. also verifies tables.
+ * non-const (these modify the curve).
+ */
+void BKE_curvemapping_premultiply(struct CurveMapping *cumap, bool restore);
void BKE_curvemapping_blend_write(struct BlendWriter *writer, const struct CurveMapping *cumap);
void BKE_curvemapping_curves_blend_write(struct BlendWriter *writer,
const struct CurveMapping *cumap);
+/**
+ * \note `cumap` itself has been read already.
+ */
void BKE_curvemapping_blend_read(struct BlendDataReader *reader, struct CurveMapping *cumap);
void BKE_histogram_update_sample_line(struct Histogram *hist,
@@ -122,16 +174,20 @@ void BKE_color_managed_display_settings_init(struct ColorManagedDisplaySettings
void BKE_color_managed_display_settings_copy(struct ColorManagedDisplaySettings *new_settings,
const struct ColorManagedDisplaySettings *settings);
-/* Initialize view settings to be best suitable for render type of viewing.
+/**
+ * Initialize view settings to be best suitable for render type of viewing.
* This will use default view transform from the OCIO configuration if none
- * is specified. */
+ * is specified.
+ */
void BKE_color_managed_view_settings_init_render(
struct ColorManagedViewSettings *settings,
const struct ColorManagedDisplaySettings *display_settings,
const char *view_transform);
-/* Initialize view settings which are best suitable for viewing non-render
- * images. For example,s movie clips while tracking. */
+/**
+ * Initialize view settings which are best suitable for viewing non-render images.
+ * For example,s movie clips while tracking.
+ */
void BKE_color_managed_view_settings_init_default(
struct ColorManagedViewSettings *settings,
const struct ColorManagedDisplaySettings *display_settings);
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index 784b395dfa5..55e5cd0a149 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -45,7 +45,7 @@ extern "C" {
typedef struct bConstraintOb {
/** to get evaluated armature. */
struct Depsgraph *depsgraph;
- /** for system time, part of deglobalization, code nicer later with local time (ton) */
+ /** for system time, part of de-globalization, code nicer later with local time (ton) */
struct Scene *scene;
/** if pchan, then armature that it comes from, otherwise constraint owner */
struct Object *ob;
@@ -61,7 +61,7 @@ typedef struct bConstraintOb {
/** type of owner. */
short type;
- /** rotation order for constraint owner (as defined in eEulerRotationOrders in BLI_math.h) */
+ /** rotation order for constraint owner (as defined in #eEulerRotationOrders in BLI_math.h) */
short rotOrder;
} bConstraintOb;
@@ -76,7 +76,7 @@ typedef void (*ConstraintIDFunc)(struct bConstraint *con,
/* ....... */
/**
- * Constraint Type-Info (shorthand in code = cti):
+ * Constraint Type-Info (shorthand in code = `cti`):
* This struct provides function pointers for runtime, so that functions can be
* written more generally (with fewer/no special exceptions for various constraints).
*
@@ -138,49 +138,105 @@ typedef struct bConstraintTypeInfo {
} bConstraintTypeInfo;
/* Function Prototypes for bConstraintTypeInfo's */
+
+/**
+ * This function should always be used to get the appropriate type-info, as it
+ * has checks which prevent segfaults in some weird cases.
+ */
const bConstraintTypeInfo *BKE_constraint_typeinfo_get(struct bConstraint *con);
+/**
+ * This function should be used for getting the appropriate type-info when only
+ * a constraint type is known.
+ */
const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type);
/* ---------------------------------------------------------------------------- */
/* Constraint function prototypes */
+
+/**
+ * Find the first available, non-duplicate name for a given constraint.
+ */
void BKE_constraint_unique_name(struct bConstraint *con, struct ListBase *list);
-struct bConstraint *BKE_constraint_duplicate_ex(struct bConstraint *src,
- const int flag,
- const bool do_extern);
+/**
+ * Allocate and duplicate a single constraint, outside of any object/pose context.
+ */
+struct bConstraint *BKE_constraint_duplicate_ex(struct bConstraint *src, int flag, bool do_extern);
+/**
+ * Add a copy of the given constraint for the given bone.
+ */
struct bConstraint *BKE_constraint_copy_for_pose(struct Object *ob,
struct bPoseChannel *pchan,
struct bConstraint *src);
+/**
+ * Add a copy of the given constraint for the given object.
+ */
struct bConstraint *BKE_constraint_copy_for_object(struct Object *ob, struct bConstraint *src);
void BKE_constraints_free(struct ListBase *list);
+/**
+ * Free all constraints from a constraint-stack.
+ */
void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user);
void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern);
+/**
+ * Duplicate all of the constraints in a constraint stack.
+ */
void BKE_constraints_copy_ex(struct ListBase *dst,
const struct ListBase *src,
- const int flag,
+ int flag,
bool do_extern);
+/**
+ * Run the given callback on all ID-blocks in list of constraints.
+ */
void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, void *userdata);
void BKE_constraint_free_data(struct bConstraint *con);
+/**
+ * Free data of a specific constraint if it has any info.
+ * Be sure to run #BIK_clear_data() when freeing an IK constraint,
+ * unless #DAG_relations_tag_update is called.
+ */
void BKE_constraint_free_data_ex(struct bConstraint *con, bool do_id_user);
bool BKE_constraint_target_uses_bbone(struct bConstraint *con, struct bConstraintTarget *ct);
/* Constraint API function prototypes */
+
+/**
+ * Finds the 'active' constraint in a constraint stack.
+ */
struct bConstraint *BKE_constraints_active_get(struct ListBase *list);
+/**
+ * Set the given constraint as the active one (clearing all the others).
+ */
void BKE_constraints_active_set(ListBase *list, struct bConstraint *con);
struct bConstraint *BKE_constraints_find_name(struct ListBase *list, const char *name);
+/**
+ * Finds the constraint that owns the given target within the object.
+ */
struct bConstraint *BKE_constraint_find_from_target(struct Object *ob,
struct bConstraintTarget *tgt,
struct bPoseChannel **r_pchan);
+/**
+ * Check whether given constraint is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param con: May be NULL, in which case we consider it as a non-local constraint case.
+ */
bool BKE_constraint_is_nonlocal_in_liboverride(const struct Object *ob,
const struct bConstraint *con);
+/**
+ * Add new constraint for the given object.
+ */
struct bConstraint *BKE_constraint_add_for_object(struct Object *ob, const char *name, short type);
+/**
+ * Add new constraint for the given bone.
+ */
struct bConstraint *BKE_constraint_add_for_pose(struct Object *ob,
struct bPoseChannel *pchan,
const char *name,
@@ -190,8 +246,14 @@ bool BKE_constraint_remove_ex(ListBase *list,
struct Object *ob,
struct bConstraint *con,
bool clear_dep);
+/**
+ * Remove the specified constraint from the given constraint stack.
+ */
bool BKE_constraint_remove(ListBase *list, struct bConstraint *con);
+/**
+ * Apply the specified constraint in the given constraint stack.
+ */
bool BKE_constraint_apply_for_object(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -217,25 +279,54 @@ bool BKE_constraint_apply_and_remove_for_pose(struct Depsgraph *depsgraph,
void BKE_constraint_panel_expand(struct bConstraint *con);
/* Constraints + Proxies function prototypes */
+
+/**
+ * Rescue all constraints tagged as being #CONSTRAINT_PROXY_LOCAL
+ * (i.e. added to bone that's proxy-synced in this file).
+ */
void BKE_constraints_proxylocal_extract(struct ListBase *dst, struct ListBase *src);
+/**
+ * Returns if the owner of the constraint is proxy-protected.
+ */
bool BKE_constraints_proxylocked_owner(struct Object *ob, struct bPoseChannel *pchan);
/* Constraint Evaluation function prototypes */
+
+/**
+ * This function MEM_calloc's a #bConstraintOb struct,
+ * that will need to be freed after evaluation.
+ */
struct bConstraintOb *BKE_constraints_make_evalob(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
void *subdata,
short datatype);
+/**
+ * Cleanup after constraint evaluation.
+ */
void BKE_constraints_clear_evalob(struct bConstraintOb *cob);
+/**
+ * This function is responsible for the correct transformations/conversions
+ * of a matrix from one space to another for constraint evaluation.
+ * For now, this is only implemented for objects and pose-channels.
+ */
void BKE_constraint_mat_convertspace(struct Object *ob,
struct bPoseChannel *pchan,
struct bConstraintOb *cob,
float mat[4][4],
short from,
short to,
- const bool keep_scale);
+ bool keep_scale);
+/**
+ * This function is a relic from the prior implementations of the constraints system, when all
+ * constraints either had one or no targets. It used to be called during the main constraint
+ * solving loop, but is now only used for the remaining cases for a few constraints.
+ *
+ * None of the actual calculations of the matrices should be done here! Also, this function is
+ * not to be used by any new constraints, particularly any that have multiple targets.
+ */
void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
struct Scene *scene,
struct bConstraint *con,
@@ -244,12 +335,22 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
void *ownerdata,
float mat[4][4],
float ctime);
+/**
+ * Get the list of targets required for solving a constraint.
+ */
void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph,
struct bConstraint *con,
struct bConstraintOb *ob,
struct ListBase *targets,
float ctime);
void BKE_constraint_custom_object_space_get(float r_mat[4][4], struct bConstraint *con);
+/**
+ * This function is called whenever constraints need to be evaluated. Currently, all
+ * constraints that can be evaluated are every time this gets run.
+ *
+ * #BKE_constraints_make_evalob and #BKE_constraints_clear_evalob should be called before and
+ * after running this function, to sort out cob.
+ */
void BKE_constraints_solve(struct Depsgraph *depsgraph,
struct ListBase *conlist,
struct bConstraintOb *cob,
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index b0705ff411f..18c1848b737 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -247,10 +247,13 @@ PointerRNA CTX_data_pointer_get_type_silent(const bContext *C,
const char *member,
StructRNA *type);
ListBase CTX_data_collection_get(const bContext *C, const char *member);
-ListBase CTX_data_dir_get_ex(const bContext *C,
- const bool use_store,
- const bool use_rna,
- const bool use_all);
+/**
+ * \param C: Context.
+ * \param use_store: Use 'C->wm.store'.
+ * \param use_rna: Use Include the properties from 'RNA_Context'.
+ * \param use_all: Don't skip values (currently only "scene").
+ */
+ListBase CTX_data_dir_get_ex(const bContext *C, bool use_store, bool use_rna, bool use_all);
ListBase CTX_data_dir_get(const bContext *C);
int /*eContextResult*/ CTX_data_get(
const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb, short *r_type);
@@ -276,8 +279,9 @@ bool CTX_data_dir(const char *member);
ListBase ctx_data_list; \
CollectionPointerLink *ctx_link; \
CTX_data_##member(C, &ctx_data_list); \
- for (ctx_link = ctx_data_list.first; ctx_link; ctx_link = ctx_link->next) { \
- Type instance = ctx_link->ptr.data;
+ for (ctx_link = (CollectionPointerLink *)ctx_data_list.first; ctx_link; \
+ ctx_link = ctx_link->next) { \
+ Type instance = (Type)ctx_link->ptr.data;
#define CTX_DATA_END \
} \
@@ -297,6 +301,13 @@ int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBas
struct Main *CTX_data_main(const bContext *C);
struct Scene *CTX_data_scene(const bContext *C);
+/**
+ * This is tricky. Sometimes the user overrides the render_layer
+ * but not the scene_collection. In this case what to do?
+ *
+ * If the scene_collection is linked to the #ViewLayer we use it.
+ * Otherwise we fallback to the active one of the #ViewLayer.
+ */
struct LayerCollection *CTX_data_layer_collection(const bContext *C);
struct Collection *CTX_data_collection(const bContext *C);
struct ViewLayer *CTX_data_view_layer(const bContext *C);
@@ -306,7 +317,7 @@ struct ToolSettings *CTX_data_tool_settings(const bContext *C);
const char *CTX_data_mode_string(const bContext *C);
enum eContextObjectMode CTX_data_mode_enum_ex(const struct Object *obedit,
const struct Object *ob,
- const eObjectMode object_mode);
+ eObjectMode object_mode);
enum eContextObjectMode CTX_data_mode_enum(const bContext *C);
void CTX_data_main_set(bContext *C, struct Main *bmain);
@@ -367,28 +378,34 @@ struct AssetHandle CTX_wm_asset_handle(const bContext *C, bool *r_is_valid);
bool CTX_wm_interface_locked(const bContext *C);
-/* Gets pointer to the dependency graph.
+/**
+ * Gets pointer to the dependency graph.
* If it doesn't exist yet, it will be allocated.
*
* The result dependency graph is NOT guaranteed to be up-to-date neither from relation nor from
* evaluated data points of view.
*
- * NOTE: Can not be used if access to a fully evaluated datablock is needed. */
+ * \note Can not be used if access to a fully evaluated data-block is needed.
+ */
struct Depsgraph *CTX_data_depsgraph_pointer(const bContext *C);
-/* Get dependency graph which is expected to be fully evaluated.
+/**
+ * Get dependency graph which is expected to be fully evaluated.
*
* In the release builds it is the same as CTX_data_depsgraph_pointer(). In the debug builds extra
* sanity checks are done. Additionally, this provides more semantic meaning to what is exactly
- * expected to happen. */
+ * expected to happen.
+ */
struct Depsgraph *CTX_data_expect_evaluated_depsgraph(const bContext *C);
-/* Gets fully updated and evaluated dependency graph.
+/**
+ * Gets fully updated and evaluated dependency graph.
*
* All the relations and evaluated objects are guaranteed to be up to date.
*
- * NOTE: Will be expensive if there are relations or objects tagged for update.
- * NOTE: If there are pending updates depsgraph hooks will be invoked. */
+ * \note Will be expensive if there are relations or objects tagged for update.
+ * \note If there are pending updates depsgraph hooks will be invoked.
+ */
struct Depsgraph *CTX_data_ensure_evaluated_depsgraph(const bContext *C);
/* Will Return NULL if depsgraph is not allocated yet.
diff --git a/source/blender/blenkernel/BKE_crazyspace.h b/source/blender/blenkernel/BKE_crazyspace.h
index b95be70379f..42d85c70bc1 100644
--- a/source/blender/blenkernel/BKE_crazyspace.h
+++ b/source/blender/blenkernel/BKE_crazyspace.h
@@ -26,24 +26,34 @@
#ifdef __cplusplus
extern "C" {
#endif
+
struct BMEditMesh;
struct Depsgraph;
struct Mesh;
struct Object;
+struct ReportList;
struct Scene;
/* crazyspace.c */
+
+/**
+ * Disable subdivision-surface temporal, get mapped coordinates, and enable it.
+ */
float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph,
struct Object *obedit))[3];
void BKE_crazyspace_set_quats_editmesh(struct BMEditMesh *em,
float (*origcos)[3],
float (*mappedcos)[3],
float (*quats)[4],
- const bool use_select);
+ bool use_select);
void BKE_crazyspace_set_quats_mesh(struct Mesh *me,
float (*origcos)[3],
float (*mappedcos)[3],
float (*quats)[4]);
+/**
+ * Returns an array of deform matrices for crazy-space correction,
+ * and the number of modifiers left.
+ */
int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgraph,
struct Scene *,
struct Object *,
@@ -61,6 +71,31 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
float (**deformmats)[3][3],
float (**deformcos)[3]);
+/* -------------------------------------------------------------------- */
+/** \name Crazy-Space API
+ * \{ */
+
+void BKE_crazyspace_api_eval(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *object,
+ struct ReportList *reports);
+
+void BKE_crazyspace_api_displacement_to_deformed(struct Object *object,
+ struct ReportList *reports,
+ int vertex_index,
+ float displacement[3],
+ float r_displacement_deformed[3]);
+
+void BKE_crazyspace_api_displacement_to_original(struct Object *object,
+ struct ReportList *reports,
+ int vertex_index,
+ float displacement_deformed[3],
+ float r_displacement[3]);
+
+void BKE_crazyspace_api_eval_clear(struct Object *object);
+
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h
index e98a9b2b1fd..64fbb00b143 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.h
+++ b/source/blender/blenkernel/BKE_cryptomatte.h
@@ -55,8 +55,11 @@ uint32_t BKE_cryptomatte_asset_hash(struct CryptomatteSession *session,
const char *layer_name,
const struct Object *object);
float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash);
+/**
+ * Find an ID in the given main that matches the given encoded float.
+ */
bool BKE_cryptomatte_find_name(const struct CryptomatteSession *session,
- const float encoded_hash,
+ float encoded_hash,
char *r_name,
int name_len);
diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh
index 9e205d01765..aa82166aa70 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.hh
+++ b/source/blender/blenkernel/BKE_cryptomatte.hh
@@ -37,7 +37,8 @@ struct ID;
namespace blender::bke::cryptomatte {
-/* Format to a cryptomatte meta data key.
+/**
+ * Format to a cryptomatte meta data key.
*
* Cryptomatte stores meta data. The keys are formatted containing a hash that
* is generated from its layer name.
@@ -48,7 +49,8 @@ namespace blender::bke::cryptomatte {
std::string BKE_cryptomatte_meta_data_key(const StringRef layer_name,
const StringRefNull key_name);
-/* Extract the cryptomatte layer name from the given `render_pass_name`.
+/**
+ * Extract the cryptomatte layer name from the given `render_pass_name`.
*
* Cryptomatte passes are formatted with a trailing number for storing multiple samples that belong
* to the same cryptomatte layer. This function would remove the trailing numbers to determine the
@@ -59,7 +61,7 @@ std::string BKE_cryptomatte_meta_data_key(const StringRef layer_name,
* A render_pass_name could be 'View Layer.CryptoMaterial02'. The cryptomatte layer would be 'View
* Layer.CryptoMaterial'.
*
- * NOTE: The return type is a sub-string of `render_pass_name` and therefore cannot outlive the
+ * \note The return type is a sub-string of `render_pass_name` and therefore cannot outlive the
* `render_pass_name` internal data.
*/
StringRef BKE_cryptomatte_extract_layer_name(const StringRef render_pass_name);
@@ -68,10 +70,22 @@ struct CryptomatteHash {
uint32_t hash;
CryptomatteHash(uint32_t hash);
- CryptomatteHash(const char *name, const int name_len);
+ CryptomatteHash(const char *name, int name_len);
static CryptomatteHash from_hex_encoded(blender::StringRef hex_encoded);
std::string hex_encoded() const;
+ /**
+ Convert a cryptomatte hash to a float.
+ *
+ * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the
+ * cryptomatte specification. See Floating point conversion section in
+ * https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf.
+ *
+ * The conversion uses as many 32 bit floating point values as possible to minimize hash
+ * collisions. Unfortunately not all 32 bits can be used as NaN and Inf can be problematic.
+ *
+ * Note that this conversion assumes to be running on a L-endian system.
+ */
float float_encoded() const;
};
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 5e474c0c5ac..25d49544330 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -75,8 +75,8 @@ typedef struct CVKeyIndex {
#define SEGMENTSV(nu) (((nu)->flagv & CU_NURB_CYCLIC) ? (nu)->pntsv : (nu)->pntsv - 1)
#define CU_DO_RADIUS(cu, nu) \
- ((((cu)->flag & (CU_PATH_RADIUS | CU_3D)) || (cu)->bevobj || (cu)->ext1 != 0.0f || \
- (cu)->ext2 != 0.0f) ? \
+ ((((cu)->flag & (CU_PATH_RADIUS | CU_3D)) || (cu)->bevobj || (cu)->extrude != 0.0f || \
+ (cu)->bevel_radius != 0.0f) ? \
1 : \
0)
@@ -86,8 +86,11 @@ typedef struct CVKeyIndex {
#define CU_DO_2DFILL(cu) (CU_IS_2D(cu) && (((cu)->flag & (CU_FRONT | CU_BACK)) != 0))
/* ** Curve ** */
+/**
+ * Frees edit-curve entirely.
+ */
void BKE_curve_editfont_free(struct Curve *cu);
-void BKE_curve_init(struct Curve *cu, const short curve_type);
+void BKE_curve_init(struct Curve *cu, short curve_type);
struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type);
short BKE_curve_type_get(const struct Curve *cu);
void BKE_curve_type_test(struct Object *ob);
@@ -98,35 +101,43 @@ struct BoundBox *BKE_curve_boundbox_get(struct Object *ob);
void BKE_curve_texspace_calc(struct Curve *cu);
void BKE_curve_texspace_ensure(struct Curve *cu);
+/* Basic vertex data functions. */
+
bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]);
bool BKE_curve_center_median(struct Curve *cu, float cent[3]);
bool BKE_curve_center_bounds(struct Curve *cu, float cent[3]);
-void BKE_curve_transform_ex(struct Curve *cu,
- const float mat[4][4],
- const bool do_keys,
- const bool do_props,
- const float unit_scale);
-void BKE_curve_transform(struct Curve *cu,
- const float mat[4][4],
- const bool do_keys,
- const bool do_props);
-void BKE_curve_translate(struct Curve *cu, const float offset[3], const bool do_keys);
+void BKE_curve_transform_ex(
+ struct Curve *cu, const float mat[4][4], bool do_keys, bool do_props, float unit_scale);
+void BKE_curve_transform(struct Curve *cu, const float mat[4][4], bool do_keys, bool do_props);
+void BKE_curve_translate(struct Curve *cu, const float offset[3], bool do_keys);
void BKE_curve_material_index_remove(struct Curve *cu, int index);
bool BKE_curve_material_index_used(const struct Curve *cu, int index);
void BKE_curve_material_index_clear(struct Curve *cu);
bool BKE_curve_material_index_validate(struct Curve *cu);
void BKE_curve_material_remap(struct Curve *cu, const unsigned int *remap, unsigned int remap_len);
-void BKE_curve_smooth_flag_set(struct Curve *cu, const bool use_smooth);
+void BKE_curve_smooth_flag_set(struct Curve *cu, bool use_smooth);
+/**
+ * \return edit-nurbs or normal nurbs list.
+ */
ListBase *BKE_curve_nurbs_get(struct Curve *cu);
const ListBase *BKE_curve_nurbs_get_for_read(const struct Curve *cu);
int BKE_curve_nurb_vert_index_get(const struct Nurb *nu, const void *vert);
void BKE_curve_nurb_active_set(struct Curve *cu, const struct Nurb *nu);
struct Nurb *BKE_curve_nurb_active_get(struct Curve *cu);
+/**
+ * Get active vert for curve.
+ */
void *BKE_curve_vert_active_get(struct Curve *cu);
+/**
+ * Set active nurb and active vert for curve.
+ */
void BKE_curve_nurb_vert_active_set(struct Curve *cu, const struct Nurb *nu, const void *vert);
+/**
+ * Get points to the active nurb and active vert for curve.
+ */
bool BKE_curve_nurb_vert_active_get(struct Curve *cu, struct Nurb **r_nu, void **r_vert);
void BKE_curve_nurb_vert_active_validate(struct Curve *cu);
@@ -138,11 +149,11 @@ void BKE_curve_nurbs_vert_coords_get(const struct ListBase *lb,
void BKE_curve_nurbs_vert_coords_apply_with_mat4(struct ListBase *lb,
const float (*vert_coords)[3],
const float mat[4][4],
- const bool constrain_2d);
+ bool constrain_2d);
void BKE_curve_nurbs_vert_coords_apply(struct ListBase *lb,
const float (*vert_coords)[3],
- const bool constrain_2d);
+ bool constrain_2d);
float (*BKE_curve_nurbs_key_vert_coords_alloc(const struct ListBase *lb,
float *key,
@@ -152,6 +163,9 @@ void BKE_curve_nurbs_key_vert_tilts_apply(struct ListBase *lb, const float *key)
void BKE_curve_editNurb_keyIndex_delCV(struct GHash *keyindex, const void *cv);
void BKE_curve_editNurb_keyIndex_free(struct GHash **keyindex);
void BKE_curve_editNurb_free(struct Curve *cu);
+/**
+ * Get list of nurbs from edit-nurbs structure.
+ */
struct ListBase *BKE_curve_editNurbs_get(struct Curve *cu);
const struct ListBase *BKE_curve_editNurbs_get_for_read(const struct Curve *cu);
@@ -159,8 +173,14 @@ void BKE_curve_bevelList_free(struct ListBase *bev);
void BKE_curve_bevelList_make(struct Object *ob, const struct ListBase *nurbs, bool for_render);
ListBase BKE_curve_bevel_make(const struct Curve *curve);
+/**
+ * Forward differencing method for bezier curve.
+ */
void BKE_curve_forward_diff_bezier(
float q0, float q1, float q2, float q3, float *p, int it, int stride);
+/**
+ * Forward differencing method for first derivative of cubic bezier curve.
+ */
void BKE_curve_forward_diff_tangent_bezier(
float q0, float q1, float q2, float q3, float *p, int it, int stride);
@@ -168,36 +188,65 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu,
const struct TextBox *tb,
struct rctf *r_rect);
+/**
+ * This function is almost the same as #BKE_fcurve_correct_bezpart,
+ * but doesn't allow as large a tangent.
+ */
void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2]);
/* ** Nurbs ** */
-bool BKE_nurbList_index_get_co(struct ListBase *editnurb, const int index, float r_co[3]);
+bool BKE_nurbList_index_get_co(struct ListBase *editnurb, int index, float r_co[3]);
int BKE_nurbList_verts_count(const struct ListBase *nurb);
int BKE_nurbList_verts_count_without_handles(const struct ListBase *nurb);
void BKE_nurbList_free(struct ListBase *lb);
void BKE_nurbList_duplicate(struct ListBase *lb1, const struct ListBase *lb2);
-void BKE_nurbList_handles_set(struct ListBase *editnurb, const char code);
-void BKE_nurbList_handles_recalculate(struct ListBase *editnurb,
- const bool calc_length,
- const uint8_t flag);
+/**
+ * \param code:
+ * - 1 (#HD_AUTO): set auto-handle.
+ * - 2 (#HD_VECT): set vector-handle.
+ * - 3 (#HD_ALIGN) it toggle, vector-handles become #HD_FREE.
+ *
+ * - 5: Set align, like 3 but no toggle.
+ * - 6: Clear align (setting #HD_FREE), like 3 but no toggle.
+ */
+void BKE_nurbList_handles_set(struct ListBase *editnurb, char code);
+void BKE_nurbList_handles_recalculate(struct ListBase *editnurb, bool calc_length, uint8_t flag);
void BKE_nurbList_handles_autocalc(ListBase *editnurb, uint8_t flag);
void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set);
+/**
+ * Set \a flag for every point that already has \a from_flag set.
+ */
bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, uint8_t from_flag, uint8_t flag);
void BKE_nurb_free(struct Nurb *nu);
struct Nurb *BKE_nurb_duplicate(const struct Nurb *nu);
+/**
+ * Copy the nurb but allow for different number of points (to be copied after this).
+ */
struct Nurb *BKE_nurb_copy(struct Nurb *src, int pntsu, int pntsv);
void BKE_nurb_project_2d(struct Nurb *nu);
+/**
+ * if use_radius is truth, minmax will take points' radius into account,
+ * which will make bound-box closer to beveled curve.
+ */
void BKE_nurb_minmax(const struct Nurb *nu, bool use_radius, float min[3], float max[3]);
float BKE_nurb_calc_length(const struct Nurb *nu, int resolution);
+/**
+ * \param coord_array: has to be `(3 * 4 * resolu * resolv)` in size, and zero-ed.
+ */
void BKE_nurb_makeFaces(
const struct Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv);
+/**
+ * \param coord_array: Has to be `(3 * 4 * pntsu * resolu)` in size and zero-ed
+ * \param tilt_array: set when non-NULL
+ * \param radius_array: set when non-NULL
+ */
void BKE_nurb_makeCurve(const struct Nurb *nu,
float *coord_array,
float *tilt_array,
@@ -206,18 +255,27 @@ void BKE_nurb_makeCurve(const struct Nurb *nu,
int resolu,
int stride);
-unsigned int BKE_curve_calc_coords_axis_len(const unsigned int bezt_array_len,
- const unsigned int resolu,
- const bool is_cyclic,
- const bool use_cyclic_duplicate_endpoint);
+/**
+ * Calculate the length for arrays filled in by #BKE_curve_calc_coords_axis.
+ */
+unsigned int BKE_curve_calc_coords_axis_len(unsigned int bezt_array_len,
+ unsigned int resolu,
+ bool is_cyclic,
+ bool use_cyclic_duplicate_endpoint);
+/**
+ * Calculate an array for the entire curve (cyclic or non-cyclic).
+ * \note Call for each axis.
+ *
+ * \param use_cyclic_duplicate_endpoint: Duplicate values at the beginning & end of the array.
+ */
void BKE_curve_calc_coords_axis(const struct BezTriple *bezt_array,
- const unsigned int bezt_array_len,
- const unsigned int resolu,
- const bool is_cyclic,
- const bool use_cyclic_duplicate_endpoint,
+ unsigned int bezt_array_len,
+ unsigned int resolu,
+ bool is_cyclic,
+ bool use_cyclic_duplicate_endpoint,
/* array params */
- const unsigned int axis,
- const unsigned int stride,
+ unsigned int axis,
+ unsigned int stride,
float *r_points);
void BKE_nurb_knot_calc_u(struct Nurb *nu);
@@ -232,11 +290,14 @@ bool BKE_nurb_order_clamp_u(struct Nurb *nu);
bool BKE_nurb_order_clamp_v(struct Nurb *nu);
void BKE_nurb_direction_switch(struct Nurb *nu);
-bool BKE_nurb_type_convert(struct Nurb *nu,
- const short type,
- const bool use_handles,
- const char **r_err_msg);
+/**
+ * \note caller must ensure active vertex remains valid.
+ */
+bool BKE_nurb_type_convert(struct Nurb *nu, short type, bool use_handles, const char **r_err_msg);
+/**
+ * Be sure to call #BKE_nurb_knot_calc_u / #BKE_nurb_knot_calc_v after this.
+ */
void BKE_nurb_points_add(struct Nurb *nu, int number);
void BKE_nurb_bezierPoints_add(struct Nurb *nu, int number);
@@ -254,17 +315,31 @@ void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_p
void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, struct BPoint *bp, float r_normal[3]);
void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, struct BPoint *bp, float r_plane[3]);
+/**
+ * Recalculate the handles of a nurb bezier-triple. Acts based on handle selection with `SELECT`
+ * flag. To use a different flag, use #BKE_nurb_handle_calc_ex().
+ */
void BKE_nurb_handle_calc(struct BezTriple *bezt,
struct BezTriple *prev,
struct BezTriple *next,
- const bool is_fcurve,
- const char smoothing);
+ bool is_fcurve,
+ char smoothing);
+/**
+ * Variant of #BKE_nurb_handle_calc() that allows calculating based on a different select flag.
+ *
+ * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection.
+ * Usually #SELECT, but may want to use a different one at times
+ * (if caller does not operate on selection).
+ */
void BKE_nurb_handle_calc_ex(struct BezTriple *bezt,
struct BezTriple *prev,
struct BezTriple *next,
- const eBezTriple_Flag__Alias handle_sel_flag,
- const bool is_fcurve,
- const char smoothing);
+ eBezTriple_Flag__Alias handle_sel_flag,
+ bool is_fcurve,
+ char smoothing);
+/**
+ * Similar to #BKE_nurb_handle_calc but for curves and figures out the previous and next for us.
+ */
void BKE_nurb_handle_calc_simple(struct Nurb *nu, struct BezTriple *bezt);
void BKE_nurb_handle_calc_simple_auto(struct Nurb *nu, struct BezTriple *bezt);
@@ -272,11 +347,23 @@ void BKE_nurb_handle_smooth_fcurve(struct BezTriple *bezt, int total, bool cycli
void BKE_nurb_handles_calc(struct Nurb *nu);
void BKE_nurb_handles_autocalc(struct Nurb *nu, uint8_t flag);
+/**
+ * Update selected handle types to ensure valid state, e.g. deduce "Auto" types to concrete ones.
+ * Thereby \a sel_flag defines what qualifies as selected.
+ * Use when something has changed handle positions.
+ *
+ * The caller needs to recalculate handles.
+ *
+ * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
+ * but may want to use a different one at times (if caller does not operate on * selection).
+ * \param use_handle: Check selection state of individual handles, otherwise always update both
+ * handles if the key is selected.
+ */
void BKE_nurb_bezt_handle_test(struct BezTriple *bezt,
- const eBezTriple_Flag__Alias sel_flag,
- const bool use_handle,
- const bool use_around_local);
-void BKE_nurb_handles_test(struct Nurb *nu, const bool use_handles, const bool use_around_local);
+ eBezTriple_Flag__Alias sel_flag,
+ bool use_handle,
+ bool use_around_local);
+void BKE_nurb_handles_test(struct Nurb *nu, bool use_handles, bool use_around_local);
/* **** Depsgraph evaluation **** */
@@ -300,18 +387,18 @@ extern void (*BKE_curve_batch_cache_free_cb)(struct Curve *cu);
* \{ */
unsigned int BKE_curve_decimate_bezt_array(struct BezTriple *bezt_array,
- const unsigned int bezt_array_len,
- const unsigned int resolu,
- const bool is_cyclic,
- const char flag_test,
- const char flag_set,
- const float error_sq_max,
- const unsigned int error_target_len);
+ unsigned int bezt_array_len,
+ unsigned int resolu,
+ bool is_cyclic,
+ char flag_test,
+ char flag_set,
+ float error_sq_max,
+ unsigned int error_target_len);
void BKE_curve_decimate_nurb(struct Nurb *nu,
- const unsigned int resolu,
- const float error_sq_max,
- const unsigned int error_target_len);
+ unsigned int resolu,
+ float error_sq_max,
+ unsigned int error_target_len);
/** \} */
@@ -322,26 +409,32 @@ void BKE_curve_decimate_nurb(struct Nurb *nu,
void BKE_curve_deform_coords(const struct Object *ob_curve,
const struct Object *ob_target,
float (*vert_coords)[3],
- const int vert_coords_len,
+ int vert_coords_len,
const struct MDeformVert *dvert,
- const int defgrp_index,
- const short flag,
- const short defaxis);
+ int defgrp_index,
+ short flag,
+ short defaxis);
void BKE_curve_deform_coords_with_editmesh(const struct Object *ob_curve,
const struct Object *ob_target,
float (*vert_coords)[3],
- const int vert_coords_len,
- const int defgrp_index,
- const short flag,
- const short defaxis,
+ int vert_coords_len,
+ int defgrp_index,
+ short flag,
+ short defaxis,
struct BMEditMesh *em_target);
+/**
+ * \param orco: Input vec and orco = local coord in curve space
+ * orco is original not-animated or deformed reference point.
+ *
+ * The result written to `vec` and `r_mat`.
+ */
void BKE_curve_deform_co(const struct Object *ob_curve,
const struct Object *ob_target,
const float orco[3],
float vec[3],
- const int no_rot_axis,
+ int no_rot_axis,
float r_mat[3][3]);
/** \} */
diff --git a/source/blender/blenkernel/BKE_curve_to_mesh.hh b/source/blender/blenkernel/BKE_curve_to_mesh.hh
index cc1ef08908d..10649e8703f 100644
--- a/source/blender/blenkernel/BKE_curve_to_mesh.hh
+++ b/source/blender/blenkernel/BKE_curve_to_mesh.hh
@@ -16,16 +16,30 @@
#pragma once
-struct Mesh;
struct CurveEval;
+struct Mesh;
/** \file
- * \ingroup geo
+ * \ingroup bke
*/
namespace blender::bke {
-Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile);
+/**
+ * Extrude all splines in the profile curve along the path of every spline in the curve input.
+ * Transfer curve attributes to the mesh.
+ *
+ * \note Normal calculation is by far the slowest part of calculations relating to the result mesh.
+ * Although it would be a sensible decision to use the better topology information available while
+ * generating the mesh to also generate the normals, that work may wasted if the output mesh is
+ * changed anyway in a way that affects the normals. So currently this code uses the safer /
+ * simpler solution of deferring normal calculation to the rest of Blender.
+ */
+Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile, bool fill_caps);
+/**
+ * Create a loose-edge mesh based on the evaluated path of the curve's splines.
+ * Transfer curve attributes to the mesh.
+ */
Mesh *curve_to_wire_mesh(const CurveEval &curve);
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_curveprofile.h b/source/blender/blenkernel/BKE_curveprofile.h
index 501ae70ecdb..aa79f29760d 100644
--- a/source/blender/blenkernel/BKE_curveprofile.h
+++ b/source/blender/blenkernel/BKE_curveprofile.h
@@ -34,8 +34,15 @@ struct BlendWriter;
struct CurveProfile;
struct CurveProfilePoint;
+/**
+ * Sets the default settings and clip range for the profile widget.
+ * Does not generate either table.
+ */
void BKE_curveprofile_set_defaults(struct CurveProfile *profile);
+/**
+ * Returns a pointer to a newly allocated curve profile, using the given preset.
+ */
struct CurveProfile *BKE_curveprofile_add(eCurveProfilePresets preset);
void BKE_curveprofile_free_data(struct CurveProfile *profile);
@@ -46,35 +53,90 @@ void BKE_curveprofile_copy_data(struct CurveProfile *target, const struct CurveP
struct CurveProfile *BKE_curveprofile_copy(const struct CurveProfile *profile);
+/**
+ * Move a point's handle, accounting for the alignment of handles with the #HD_ALIGN type.
+ *
+ * \param handle_1: Whether to move the 1st or 2nd control point.
+ * \param delta: The *relative* change in the handle's position.
+ * \note Requires #BKE_curveprofile_update call after.
+ * \return Whether the handle moved from its start position.
+ */
bool BKE_curveprofile_move_handle(struct CurveProfilePoint *point,
- const bool handle_1,
- const bool snap,
+ bool handle_1,
+ bool snap,
const float delta[2]);
+/**
+ * Moves a control point, accounting for clipping and snapping, and moving free handles.
+ *
+ * \param snap: Whether to snap the point to the grid
+ * \param delta: The *relative* change of the point's location.
+ * \return Whether the point moved from its start position.
+ * \note Requires #BKE_curveprofile_update call after.
+ */
bool BKE_curveprofile_move_point(struct CurveProfile *profile,
struct CurveProfilePoint *point,
- const bool snap,
+ bool snap,
const float delta[2]);
+/**
+ * Removes a specific point from the path of control points.
+ * \note Requires #BKE_curveprofile_update call after.
+ */
bool BKE_curveprofile_remove_point(struct CurveProfile *profile, struct CurveProfilePoint *point);
-void BKE_curveprofile_remove_by_flag(struct CurveProfile *profile, const short flag);
+/**
+ * Removes every point in the widget with the supplied flag set, except for the first and last.
+ *
+ * \param flag: #CurveProfilePoint.flag.
+ *
+ * \note Requires #BKE_curveprofile_update call after.
+ */
+void BKE_curveprofile_remove_by_flag(struct CurveProfile *profile, short flag);
+/**
+ * Adds a new point at the specified location. The choice for which points to place the new vertex
+ * between is made by checking which control point line segment is closest to the new point and
+ * placing the new vertex in between that segment's points.
+ *
+ * \note Requires #BKE_curveprofile_update call after.
+ */
struct CurveProfilePoint *BKE_curveprofile_insert(struct CurveProfile *profile, float x, float y);
+/**
+ * Sets the handle type of the selected control points.
+ * \param type_1, type_2: Handle type for the first handle. HD_VECT, HD_AUTO, HD_FREE, or HD_ALIGN.
+ * \note Requires #BKE_curveprofile_update call after.
+ */
void BKE_curveprofile_selected_handle_set(struct CurveProfile *profile, int type_1, int type_2);
+/**
+ * Flips the profile across the diagonal so that its orientation is reversed.
+ *
+ * \note Requires #BKE_curveprofile_update call after.
+ */
void BKE_curveprofile_reverse(struct CurveProfile *profile);
+/**
+ * Reset the view to the clipping rectangle.
+ */
void BKE_curveprofile_reset_view(struct CurveProfile *profile);
+/**
+ * Resets the profile to the current preset.
+ *
+ * \note Requires #BKE_curveprofile_update call after.
+ */
void BKE_curveprofile_reset(struct CurveProfile *profile);
-void BKE_curveprofile_create_samples(struct CurveProfile *profile,
- int n_segments,
- bool sample_straight_edges,
- struct CurveProfilePoint *r_samples);
+int BKE_curveprofile_table_size(const struct CurveProfile *profile);
+/**
+ * Refreshes the higher resolution table sampled from the input points. A call to this or
+ * #BKE_curveprofile_update is needed before evaluation functions that use the table.
+ * Also sets the number of segments used for the display preview of the locations
+ * of the sampled points.
+ */
void BKE_curveprofile_init(struct CurveProfile *profile, short segments_len);
/* Called for a complete update of the widget after modifications */
@@ -83,22 +145,31 @@ enum {
PROF_UPDATE_REMOVE_DOUBLES = (1 << 0),
PROF_UPDATE_CLIP = (1 << 1),
};
-void BKE_curveprofile_update(struct CurveProfile *profile, const int update_flags);
-
-/* Need to find the total length of the curve to sample a portion of it */
-float BKE_curveprofile_total_length(const struct CurveProfile *profile);
-
-void BKE_curveprofile_create_samples_even_spacing(struct CurveProfile *profile,
- int n_segments,
- struct CurveProfilePoint *r_samples);
+/**
+ * Should be called after the widget is changed. Does profile and remove double checks and more
+ * importantly, recreates the display / evaluation and segments tables.
+ * \param update_flags: Bit-field with fields defined in header file.
+ * Controls removing doubles and clipping.
+ */
+void BKE_curveprofile_update(struct CurveProfile *profile, int update_flags);
-/* Length portion is the fraction of the total path length where we want the location */
+/**
+ * Does a single evaluation along the profile's path.
+ * Travels down (length_portion * path) length and returns the position at that point.
+ * Where length portion is the fraction of the total path length where we want the location.
+ *
+ * \param length_portion: The portion (0 to 1) of the path's full length to sample at.
+ * \note Requires #BKE_curveprofile_init or #BKE_curveprofile_update call before to fill table.
+ */
void BKE_curveprofile_evaluate_length_portion(const struct CurveProfile *profile,
float length_portion,
float *x_out,
float *y_out);
void BKE_curveprofile_blend_write(struct BlendWriter *writer, const struct CurveProfile *profile);
+/**
+ * Expects that the curve profile itself has been read already.
+ */
void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurveProfile *profile);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 0732f1e5190..00eae2e8e6e 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -84,10 +84,16 @@ void customData_mask_layers__print(const struct CustomData_MeshMasks *mask);
typedef void (*cd_interp)(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest);
typedef void (*cd_copy)(const void *source, void *dest, int count);
-typedef bool (*cd_validate)(void *item, const uint totitems, const bool do_fixes);
+typedef bool (*cd_validate)(void *item, uint totitems, bool do_fixes);
+/**
+ * Update mask_dst with layers defined in mask_src (equivalent to a bit-wise OR).
+ */
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst,
const CustomData_MeshMasks *mask_src);
+/**
+ * Return True if all layers set in \a mask_required are also set in \a mask_ref
+ */
bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref,
const CustomData_MeshMasks *mask_required);
@@ -99,39 +105,50 @@ bool CustomData_layer_has_math(const struct CustomData *data, int layer_n);
bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n);
/**
- * Checks if any of the customdata layers has math.
+ * Checks if any of the custom-data layers has math.
*/
bool CustomData_has_math(const struct CustomData *data);
bool CustomData_has_interp(const struct CustomData *data);
+/**
+ * A non bmesh version would have to check `layer->data`.
+ */
bool CustomData_bmesh_has_free(const struct CustomData *data);
/**
- * Checks if any of the customdata layers is referenced.
+ * Checks if any of the custom-data layers is referenced.
*/
bool CustomData_has_referenced(const struct CustomData *data);
-/* Copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
+/**
+ * Copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
* another, while not overwriting anything else (e.g. flags). probably only
- * implemented for mloopuv/mloopcol, for now. */
+ * implemented for mloopuv/mloopcol, for now.
+ */
void CustomData_data_copy_value(int type, const void *source, void *dest);
-/* Same as above, but doing advanced mixing.
- * Only available for a few types of data (like colors...). */
+/**
+ * Mixes the "value" (e.g. mloopuv uv or mloopcol colors) from one block into
+ * another, while not overwriting anything else (e.g. flags).
+ */
void CustomData_data_mix_value(
- int type, const void *source, void *dest, const int mixmode, const float mixfactor);
+ int type, const void *source, void *dest, int mixmode, float mixfactor);
-/* compares if data1 is equal to data2. type is a valid CustomData type
- * enum (e.g. CD_MLOOPUV). the layer type's equal function is used to compare
- * the data, if it exists, otherwise memcmp is used. */
+/**
+ * Compares if data1 is equal to data2. type is a valid CustomData type
+ * enum (e.g. #CD_MLOOPUV). the layer type's equal function is used to compare
+ * the data, if it exists, otherwise #memcmp is used.
+ */
bool CustomData_data_equals(int type, const void *data1, const void *data2);
void CustomData_data_initminmax(int type, void *min, void *max);
void CustomData_data_dominmax(int type, const void *data, void *min, void *max);
void CustomData_data_multiply(int type, void *data, float fac);
void CustomData_data_add(int type, void *data1, const void *data2);
-/* initializes a CustomData object with the same layer setup as source.
- * mask is a bitfield where (mask & (1 << (layer type))) indicates
- * if a layer should be copied or not. alloctype must be one of the above. */
+/**
+ * Initializes a CustomData object with the same layer setup as source.
+ * mask is a bitfield where `(mask & (1 << (layer type)))` indicates
+ * if a layer should be copied or not. alloctype must be one of the above.
+ */
void CustomData_copy(const struct CustomData *source,
struct CustomData *dest,
CustomDataMask mask,
@@ -141,33 +158,40 @@ void CustomData_copy(const struct CustomData *source,
/* BMESH_TODO, not really a public function but readfile.c needs it */
void CustomData_update_typemap(struct CustomData *data);
-/* same as the above, except that this will preserve existing layers, and only
- * add the layers that were not there yet */
+/**
+ * Same as the above, except that this will preserve existing layers, and only
+ * add the layers that were not there yet.
+ */
bool CustomData_merge(const struct CustomData *source,
struct CustomData *dest,
CustomDataMask mask,
eCDAllocType alloctype,
int totelem);
-/* Reallocate custom data to a new element count.
+/**
+ * Reallocate custom data to a new element count.
* Only affects on data layers which are owned by the CustomData itself,
* referenced data is kept unchanged,
*
- * NOTE: Take care of referenced layers by yourself!
+ * \note Take care of referenced layers by yourself!
*/
void CustomData_realloc(struct CustomData *data, int totelem);
-/* bmesh version of CustomData_merge; merges the layouts of source and dest,
- * then goes through the mesh and makes sure all the customdata blocks are
- * consistent with the new layout. */
+/**
+ * BMesh version of CustomData_merge; merges the layouts of source and `dest`,
+ * then goes through the mesh and makes sure all the custom-data blocks are
+ * consistent with the new layout.
+ */
bool CustomData_bmesh_merge(const struct CustomData *source,
struct CustomData *dest,
CustomDataMask mask,
eCDAllocType alloctype,
struct BMesh *bm,
- const char htype);
+ char htype);
-/** NULL's all members and resets the typemap. */
+/**
+ * NULL's all members and resets the #CustomData.typemap.
+ */
void CustomData_reset(struct CustomData *data);
/**
@@ -175,19 +199,26 @@ void CustomData_reset(struct CustomData *data);
*/
void CustomData_free(struct CustomData *data, int totelem);
-/* same as above, but only frees layers which matches the given mask. */
+/**
+ * Same as above, but only frees layers which matches the given mask.
+ */
void CustomData_free_typemask(struct CustomData *data, int totelem, CustomDataMask mask);
-/* frees all layers with CD_FLAG_TEMPORARY */
+/**
+ * Frees all layers with #CD_FLAG_TEMPORARY.
+ */
void CustomData_free_temporary(struct CustomData *data, int totelem);
-/* adds a data layer of the given type to the CustomData object, optionally
+/**
+ * Adds a data layer of the given type to the #CustomData object, optionally
* backed by an external data array. the different allocation types are
* defined above. returns the data of the layer.
*/
void *CustomData_add_layer(
struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem);
-/* Same as above but accepts a name. */
+/**
+ * Same as above but accepts a name.
+ */
void *CustomData_add_layer_named(struct CustomData *data,
int type,
eCDAllocType alloctype,
@@ -201,63 +232,70 @@ void *CustomData_add_layer_anonymous(struct CustomData *data,
int totelem,
const struct AnonymousAttributeID *anonymous_id);
-/* frees the active or first data layer with the give type.
+/**
+ * Frees the active or first data layer with the give type.
* returns 1 on success, 0 if no layer with the given type is found
*
- * in editmode, use EDBM_data_layer_free instead of this function
+ * In edit-mode, use #EDBM_data_layer_free instead of this function.
*/
bool CustomData_free_layer(struct CustomData *data, int type, int totelem, int index);
-/* frees the layer index with the give type.
- * returns 1 on success, 0 if no layer with the given type is found
+/**
+ * Frees the layer index with the give type.
+ * returns 1 on success, 0 if no layer with the given type is found.
*
- * in editmode, use EDBM_data_layer_free instead of this function
+ * In edit-mode, use #EDBM_data_layer_free instead of this function.
*/
bool CustomData_free_layer_active(struct CustomData *data, int type, int totelem);
-/* same as above, but free all layers with type */
+/**
+ * Same as above, but free all layers with type.
+ */
void CustomData_free_layers(struct CustomData *data, int type, int totelem);
-/* returns 1 if a layer with the specified type exists */
+/**
+ * Returns true if a layer with the specified type exists.
+ */
bool CustomData_has_layer(const struct CustomData *data, int type);
-/* returns the number of layers with this type */
+/**
+ * Returns the number of layers with this type.
+ */
int CustomData_number_of_layers(const struct CustomData *data, int type);
int CustomData_number_of_layers_typemask(const struct CustomData *data, CustomDataMask mask);
-/* duplicate data of a layer with flag NOFREE, and remove that flag.
- * returns the layer data */
-void *CustomData_duplicate_referenced_layer(struct CustomData *data,
- const int type,
- const int totelem);
+/**
+ * Duplicate data of a layer with flag NOFREE, and remove that flag.
+ * \return the layer data.
+ */
+void *CustomData_duplicate_referenced_layer(struct CustomData *data, int type, int totelem);
void *CustomData_duplicate_referenced_layer_n(struct CustomData *data,
- const int type,
- const int n,
- const int totelem);
+ int type,
+ int n,
+ int totelem);
void *CustomData_duplicate_referenced_layer_named(struct CustomData *data,
- const int type,
+ int type,
const char *name,
- const int totelem);
+ int totelem);
void *CustomData_duplicate_referenced_layer_anonymous(
- CustomData *data,
- const int type,
- const struct AnonymousAttributeID *anonymous_id,
- const int totelem);
+ CustomData *data, int type, const struct AnonymousAttributeID *anonymous_id, int totelem);
bool CustomData_is_referenced_layer(struct CustomData *data, int type);
-/* Duplicate all the layers with flag NOFREE, and remove the flag from duplicated layers. */
+/**
+ * Duplicate all the layers with flag NOFREE, and remove the flag from duplicated layers.
+ */
void CustomData_duplicate_referenced_layers(CustomData *data, int totelem);
-/* set the CD_FLAG_NOCOPY flag in custom data layers where the mask is
- * zero for the layer type, so only layer types specified by the mask
- * will be copied
+/**
+ * Set the #CD_FLAG_NOCOPY flag in custom data layers where the mask is
+ * zero for the layer type, so only layer types specified by the mask will be copied
*/
void CustomData_set_only_copy(const struct CustomData *data, CustomDataMask mask);
-/* copies data from one CustomData object to another
+/**
+ * Copies data from one CustomData object to another
* objects need not be compatible, each source layer is copied to the
- * first dest layer of correct type (if there is none, the layer is skipped)
- * return 1 on success, 0 on failure
+ * first dest layer of correct type (if there is none, the layer is skipped).
*/
void CustomData_copy_data(const struct CustomData *source,
struct CustomData *dest,
@@ -285,9 +323,11 @@ void CustomData_bmesh_copy_data_exclude_by_type(const struct CustomData *source,
struct CustomData *dest,
void *src_block,
void **dest_block,
- const CustomDataMask mask_exclude);
+ CustomDataMask mask_exclude);
-/* Copies data of a single layer of a given type. */
+/**
+ * Copies data of a single layer of a given type.
+ */
void CustomData_copy_layer_type_data(const struct CustomData *source,
struct CustomData *destination,
int type,
@@ -295,22 +335,22 @@ void CustomData_copy_layer_type_data(const struct CustomData *source,
int destination_index,
int count);
-/* frees data in a CustomData object
- * return 1 on success, 0 on failure
+/**
+ * Frees data in a #CustomData object.
*/
void CustomData_free_elem(struct CustomData *data, int index, int count);
-/* interpolates data from one CustomData object to another
- * objects need not be compatible, each source layer is interpolated to the
- * first dest layer of correct type (if there is none, the layer is skipped)
- * if weights == NULL or sub_weights == NULL, they default to all 1's
+/**
+ * Interpolate given custom data source items into a single destination one.
*
- * src_indices gives the source elements to interpolate from
- * weights gives the weight for each source element
- * sub_weights is an array of matrices of weights for sub-elements (matrices
- * should be source->subElems * source->subElems in size)
- * count gives the number of source elements to interpolate from
- * dest_index gives the dest element to write the interpolated value to
+ * \param src_indices: Indices of every source items to interpolate into the destination one.
+ * \param weights: The weight to apply to each source value individually. If NULL, they will be
+ * averaged.
+ * \param sub_weights: The weights of sub-items, only used to affect each corners of a
+ * tessellated face data (should always be and array of four values).
+ * \param count: The number of source items to interpolate.
+ * \param dest_index: Index of the destination item, in which to put the result of the
+ * interpolation.
*/
void CustomData_interp(const struct CustomData *source,
struct CustomData *dest,
@@ -319,6 +359,10 @@ void CustomData_interp(const struct CustomData *source,
const float *sub_weights,
int count,
int dest_index);
+/**
+ * \note src_blocks_ofs & dst_block_ofs
+ * must be pointers to the data, offset by layer->offset already.
+ */
void CustomData_bmesh_interp_n(struct CustomData *data,
const void **src_blocks,
const float *weights,
@@ -333,30 +377,45 @@ void CustomData_bmesh_interp(struct CustomData *data,
int count,
void *dst_block);
-/* swaps the data in the element corners, to new corners with indices as
- * specified in corner_indices. for edges this is an array of length 2, for
- * faces an array of length 4 */
+/**
+ * Swap data inside each item, for all layers.
+ * This only applies to item types that may store several sub-item data
+ * (e.g. corner data [UVs, VCol, ...] of tessellated faces).
+ *
+ * \param corner_indices: A mapping 'new_index -> old_index' of sub-item data.
+ */
void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices);
-void CustomData_swap(struct CustomData *data, const int index_a, const int index_b);
+/**
+ * Swap two items of given custom data, in all available layers.
+ */
+void CustomData_swap(struct CustomData *data, int index_a, int index_b);
-/* gets a pointer to the data element at index from the first layer of type
- * returns NULL if there is no layer of type
+/**
+ * Gets a pointer to the data element at index from the first layer of type.
+ * \return NULL if there is no layer of type.
*/
void *CustomData_get(const struct CustomData *data, int index, int type);
void *CustomData_get_n(const struct CustomData *data, int type, int index, int n);
+
+/* BMesh Custom Data Functions.
+ * Should replace edit-mesh ones with these as well, due to more efficient memory alloc. */
+
void *CustomData_bmesh_get(const struct CustomData *data, void *block, int type);
void *CustomData_bmesh_get_n(const struct CustomData *data, void *block, int type, int n);
-/* gets the layer at physical index n, with no type checking.
+/**
+ * Gets from the layer at physical index `n`,
+ * \note doesn't check type.
*/
void *CustomData_bmesh_get_layer_n(const struct CustomData *data, void *block, int n);
bool CustomData_set_layer_name(const struct CustomData *data, int type, int n, const char *name);
const char *CustomData_get_layer_name(const struct CustomData *data, int type, int n);
-/* gets a pointer to the active or first layer of type
- * returns NULL if there is no layer of type
+/**
+ * Gets a pointer to the active or first layer of type.
+ * \return NULL if there is no layer of type.
*/
void *CustomData_get_layer(const struct CustomData *data, int type);
void *CustomData_get_layer_n(const struct CustomData *data, int type, int n);
@@ -377,9 +436,9 @@ int CustomData_get_render_layer(const struct CustomData *data, int type);
int CustomData_get_clone_layer(const struct CustomData *data, int type);
int CustomData_get_stencil_layer(const struct CustomData *data, int type);
-/* copies the data from source to the data element at index in the first
- * layer of type
- * no effect if there is no layer of type
+/**
+ * Copies the data from source to the data element at index in the first layer of type
+ * no effect if there is no layer of type.
*/
void CustomData_set(const struct CustomData *data, int index, int type, const void *source);
@@ -390,42 +449,63 @@ void CustomData_bmesh_set(const struct CustomData *data,
void CustomData_bmesh_set_n(
struct CustomData *data, void *block, int type, int n, const void *source);
-/* sets the data of the block at physical layer n. no real type checking
- * is performed.
+/**
+ * Sets the data of the block at physical layer n.
+ * no real type checking is performed.
*/
void CustomData_bmesh_set_layer_n(struct CustomData *data, void *block, int n, const void *source);
-/* set the pointer of to the first layer of type. the old data is not freed.
- * returns the value of ptr if the layer is found, NULL otherwise
+/**
+ * Set the pointer of to the first layer of type. the old data is not freed.
+ * returns the value of `ptr` if the layer is found, NULL otherwise.
*/
void *CustomData_set_layer(const struct CustomData *data, int type, void *ptr);
void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, void *ptr);
-/* sets the nth layer of type as active */
+/**
+ * Sets the nth layer of type as active.
+ */
void CustomData_set_layer_active(struct CustomData *data, int type, int n);
void CustomData_set_layer_render(struct CustomData *data, int type, int n);
void CustomData_set_layer_clone(struct CustomData *data, int type, int n);
void CustomData_set_layer_stencil(struct CustomData *data, int type, int n);
-/* same as above but works with an index from CustomData_get_layer_index */
+/**
+ * For using with an index from #CustomData_get_active_layer_index and
+ * #CustomData_get_render_layer_index.
+ */
void CustomData_set_layer_active_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_render_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_clone_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_stencil_index(struct CustomData *data, int type, int n);
-/* adds flag to the layer flags */
+/**
+ * Adds flag to the layer flags.
+ */
void CustomData_set_layer_flag(struct CustomData *data, int type, int flag);
void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag);
void CustomData_bmesh_set_default(struct CustomData *data, void **block);
void CustomData_bmesh_free_block(struct CustomData *data, void **block);
+/**
+ * Same as #CustomData_bmesh_free_block but zero the memory rather than freeing.
+ */
void CustomData_bmesh_free_block_data(struct CustomData *data, void *block);
+/**
+ * A selective version of #CustomData_bmesh_free_block_data.
+ */
void CustomData_bmesh_free_block_data_exclude_by_type(struct CustomData *data,
void *block,
- const CustomDataMask mask_exclude);
+ CustomDataMask mask_exclude);
-/* copy custom data to/from layers as in mesh/derivedmesh, to editmesh
- * blocks of data. the CustomData's must not be compatible */
+/**
+ * Copy custom data to/from layers as in mesh/derived-mesh, to edit-mesh
+ * blocks of data. the CustomData's must not be compatible.
+ *
+ * \param use_default_init: initializes data which can't be copied,
+ * typically you'll want to use this if the BM_xxx create function
+ * is called with BM_CREATE_SKIP_CD flag
+ */
void CustomData_to_bmesh_block(const struct CustomData *source,
struct CustomData *dest,
int src_index,
@@ -436,17 +516,34 @@ void CustomData_from_bmesh_block(const struct CustomData *source,
void *src_block,
int dest_index);
-/* query info over types */
+/**
+ * Query info over types.
+ */
void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num);
int CustomData_sizeof(int type);
-/* get the name of a layer type */
+/**
+ * Get the name of a layer type.
+ */
const char *CustomData_layertype_name(int type);
+/**
+ * Can only ever be one of these.
+ */
bool CustomData_layertype_is_singleton(int type);
+/**
+ * Has dynamically allocated members.
+ * This is useful to know if operations such as #memcmp are
+ * valid when comparing data from two layers.
+ */
bool CustomData_layertype_is_dynamic(int type);
-int CustomData_layertype_layers_max(const int type);
+/**
+ * \return Maximum number of layers of given \a type, -1 means 'no limit'.
+ */
+int CustomData_layertype_layers_max(int type);
-/* make sure the name of layer at index is unique */
+/**
+ * Make sure the name of layer at index is unique.
+ */
void CustomData_set_layer_unique_name(struct CustomData *data, int index);
void CustomData_validate_layer_name(const struct CustomData *data,
@@ -454,26 +551,46 @@ void CustomData_validate_layer_name(const struct CustomData *data,
const char *name,
char *outname);
-/* for file reading compatibility, returns false if the layer was freed,
- * only after this test passes, layer->data should be assigned */
+/**
+ * For file reading compatibility, returns false if the layer was freed,
+ * only after this test passes, `layer->data` should be assigned.
+ */
bool CustomData_verify_versions(struct CustomData *data, int index);
-/* BMesh specific custom-data stuff. */
+/* BMesh specific custom-data stuff.
+ *
+ * Needed to convert to/from different face representation (for versioning). */
+
void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int totloop);
void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int total);
void CustomData_bmesh_update_active_layers(struct CustomData *fdata, struct CustomData *ldata);
+/**
+ * Update active indices for active/render/clone/stencil custom data layers
+ * based on indices from fdata layers
+ * used by do_versions in `readfile.c` when creating pdata and ldata for pre-bmesh
+ * meshes and needed to preserve active/render/clone/stencil flags set in pre-bmesh files.
+ */
void CustomData_bmesh_do_versions_update_active_layers(struct CustomData *fdata,
struct CustomData *ldata);
-void CustomData_bmesh_init_pool(struct CustomData *data, int totelem, const char htype);
+void CustomData_bmesh_init_pool(struct CustomData *data, int totelem, char htype);
#ifndef NDEBUG
+/**
+ * Debug check, used to assert when we expect layers to be in/out of sync.
+ *
+ * \param fallback: Use when there are no layers to handle,
+ * since callers may expect success or failure.
+ */
bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback);
#endif
-/* Layer data validation. */
-bool CustomData_layer_validate(struct CustomDataLayer *layer,
- const uint totitems,
- const bool do_fixes);
+/**
+ * Validate and fix data of \a layer,
+ * if possible (needs relevant callback in layer's type to be defined).
+ *
+ * \return True if some errors were found.
+ */
+bool CustomData_layer_validate(struct CustomDataLayer *layer, uint totitems, bool do_fixes);
void CustomData_layers__print(struct CustomData *data);
/* External file storage */
@@ -503,8 +620,8 @@ typedef void (*cd_datatransfer_interp)(const struct CustomDataTransferLayerMap *
void *dest,
const void **sources,
const float *weights,
- const int count,
- const float mix_factor);
+ int count,
+ float mix_factor);
/**
* Fake CD_LAYERS (those are actually 'real' data stored directly into elements' structs,
@@ -587,16 +704,41 @@ typedef struct CustomDataTransferLayerMap {
cd_datatransfer_interp interp;
} CustomDataTransferLayerMap;
-/* Those functions assume src_n and dst_n layers of given type exist in resp. src and dst. */
+/**
+ * Those functions assume src_n and dst_n layers of given type exist in resp. src and dst.
+ */
void CustomData_data_transfer(const struct MeshPairRemap *me_remap,
const CustomDataTransferLayerMap *laymap);
/* .blend file I/O */
+
+/**
+ * Prepare given custom data for file writing.
+ *
+ * \param data: the custom-data to tweak for .blend file writing (modified in place).
+ * \param r_write_layers: contains a reduced set of layers to be written to file,
+ * use it with #writestruct_at_address()
+ * (caller must free it if != \a write_layers_buff).
+ *
+ * \param write_layers_buff: An optional buffer for r_write_layers (to avoid allocating it).
+ * \param write_layers_size: The size of pre-allocated \a write_layer_buff.
+ *
+ * \warning After this funcion has ran, given custom data is no more valid from Blender POV
+ * (its `totlayer` is invalid). This function shall always be called with localized data
+ * (as it is in write_meshes()).
+ *
+ * \note `data->typemap` is not updated here, since it is always rebuilt on file read anyway.
+ * This means written `typemap` does not match written layers (as returned by \a r_write_layers).
+ * Trivial to fix is ever needed.
+ */
void CustomData_blend_write_prepare(struct CustomData *data,
struct CustomDataLayer **r_write_layers,
struct CustomDataLayer *write_layers_buff,
size_t write_layers_size);
+/**
+ * \param layers: The layers argument assigned by #CustomData_blend_write_prepare.
+ */
void CustomData_blend_write(struct BlendWriter *writer,
struct CustomData *data,
CustomDataLayer *layers,
@@ -605,6 +747,14 @@ void CustomData_blend_write(struct BlendWriter *writer,
struct ID *id);
void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count);
+#ifndef NDEBUG
+struct DynStr;
+/** Use to inspect mesh data when debugging. */
+void CustomData_debug_info_from_layers(const struct CustomData *data,
+ const char *indent,
+ struct DynStr *dynstr);
+#endif /* NDEBUG */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_data_transfer.h b/source/blender/blenkernel/BKE_data_transfer.h
index a2544e43c3d..42cf2256e8c 100644
--- a/source/blender/blenkernel/BKE_data_transfer.h
+++ b/source/blender/blenkernel/BKE_data_transfer.h
@@ -63,15 +63,19 @@ enum {
DT_TYPE_POLY_ALL = DT_TYPE_UV | DT_TYPE_SHARP_FACE | DT_TYPE_FREESTYLE_FACE,
};
-void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types,
+void BKE_object_data_transfer_dttypes_to_cdmask(int dtdata_types,
struct CustomData_MeshMasks *r_data_masks);
-bool BKE_object_data_transfer_get_dttypes_capacity(const int dtdata_types,
+/**
+ * Check what can do each layer type
+ * (if it is actually handled by transfer-data, if it supports advanced mixing.
+ */
+bool BKE_object_data_transfer_get_dttypes_capacity(int dtdata_types,
bool *r_advanced_mixing,
bool *r_threshold);
-int BKE_object_data_transfer_get_dttypes_item_types(const int dtdata_types);
+int BKE_object_data_transfer_get_dttypes_item_types(int dtdata_types);
-int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type);
-int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type);
+int BKE_object_data_transfer_dttype_to_cdtype(int dtdata_type);
+int BKE_object_data_transfer_dttype_to_srcdst_index(int dtdata_type);
#define DT_DATATYPE_IS_VERT(_dt) \
ELEM(_dt, DT_TYPE_MDEFORMVERT, DT_TYPE_SHAPEKEY, DT_TYPE_SKIN, DT_TYPE_BWEIGHT_VERT)
@@ -122,12 +126,18 @@ enum {
#endif
};
+/**
+ * Transfer data *layout* of selected types from source to destination object.
+ * By default, it only creates new data layers if needed on \a ob_dst.
+ * If \a use_delete is true, it will also delete data layers on \a ob_dst that do not match those
+ * from \a ob_src, to get (as much as possible) exact copy of source data layout.
+ */
void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_src,
struct Object *ob_dst,
- const int data_types,
- const bool use_delete,
+ int data_types,
+ bool use_delete,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX],
const int tolayers_select[DT_MULTILAYER_INDEX_MAX]);
@@ -135,46 +145,46 @@ bool BKE_object_data_transfer_mesh(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_src,
struct Object *ob_dst,
- const int data_types,
- const bool use_create,
- const int map_vert_mode,
- const int map_edge_mode,
- const int map_loop_mode,
- const int map_poly_mode,
+ int data_types,
+ bool use_create,
+ int map_vert_mode,
+ int map_edge_mode,
+ int map_loop_mode,
+ int map_poly_mode,
struct SpaceTransform *space_transform,
- const bool auto_transform,
- const float max_distance,
- const float ray_radius,
- const float islands_handling_precision,
+ bool auto_transform,
+ float max_distance,
+ float ray_radius,
+ float islands_handling_precision,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX],
const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
- const int mix_mode,
- const float mix_factor,
+ int mix_mode,
+ float mix_factor,
const char *vgroup_name,
- const bool invert_vgroup,
+ bool invert_vgroup,
struct ReportList *reports);
bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_src,
struct Object *ob_dst,
struct Mesh *me_dst,
- const int data_types,
+ int data_types,
bool use_create,
- const int map_vert_mode,
- const int map_edge_mode,
- const int map_loop_mode,
- const int map_poly_mode,
+ int map_vert_mode,
+ int map_edge_mode,
+ int map_loop_mode,
+ int map_poly_mode,
struct SpaceTransform *space_transform,
- const bool auto_transform,
- const float max_distance,
- const float ray_radius,
- const float islands_handling_precision,
+ bool auto_transform,
+ float max_distance,
+ float ray_radius,
+ float islands_handling_precision,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX],
const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
- const int mix_mode,
- const float mix_factor,
+ int mix_mode,
+ float mix_factor,
const char *vgroup_name,
- const bool invert_vgroup,
+ bool invert_vgroup,
struct ReportList *reports);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index f4221d57428..ca0ca03f099 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -44,49 +44,101 @@ const struct ListBase *BKE_object_defgroup_list(const struct Object *ob);
struct ListBase *BKE_object_defgroup_list_mutable(struct Object *ob);
int BKE_object_defgroup_count(const struct Object *ob);
+/**
+ * \note For historical reasons, the index starts at 1 rather than 0.
+ */
int BKE_object_defgroup_active_index_get(const struct Object *ob);
-void BKE_object_defgroup_active_index_set(struct Object *ob, const int new_index);
+/**
+ * \note For historical reasons, the index starts at 1 rather than 0.
+ */
+void BKE_object_defgroup_active_index_set(struct Object *ob, int new_index);
const struct ListBase *BKE_id_defgroup_list_get(const struct ID *id);
struct ListBase *BKE_id_defgroup_list_get_mutable(struct ID *id);
int BKE_id_defgroup_name_index(const struct ID *id, const char *name);
+bool BKE_id_defgroup_name_find(const struct ID *id,
+ const char *name,
+ int *r_index,
+ struct bDeformGroup **r_group);
struct bDeformGroup *BKE_object_defgroup_new(struct Object *ob, const char *name);
void BKE_defgroup_copy_list(struct ListBase *outbase, const struct ListBase *inbase);
struct bDeformGroup *BKE_defgroup_duplicate(const struct bDeformGroup *ingroup);
struct bDeformGroup *BKE_object_defgroup_find_name(const struct Object *ob, const char *name);
-int *BKE_object_defgroup_flip_map(const struct Object *ob,
- int *flip_map_len,
- const bool use_default);
+/**
+ * \note caller must free.
+ */
+int *BKE_object_defgroup_flip_map(const struct Object *ob, int *flip_map_len, bool use_default);
+/**
+ * \note caller must free.
+ */
int *BKE_object_defgroup_flip_map_single(const struct Object *ob,
int *flip_map_len,
- const bool use_default,
+ bool use_default,
int defgroup);
-int BKE_object_defgroup_flip_index(const struct Object *ob, int index, const bool use_default);
+int BKE_object_defgroup_flip_index(const struct Object *ob, int index, bool use_default);
int BKE_object_defgroup_name_index(const struct Object *ob, const char *name);
void BKE_object_defgroup_unique_name(struct bDeformGroup *dg, struct Object *ob);
-struct MDeformWeight *BKE_defvert_find_index(const struct MDeformVert *dv, const int defgroup);
-struct MDeformWeight *BKE_defvert_ensure_index(struct MDeformVert *dv, const int defgroup);
-void BKE_defvert_add_index_notest(struct MDeformVert *dv, int defgroup, const float weight);
+struct MDeformWeight *BKE_defvert_find_index(const struct MDeformVert *dv, int defgroup);
+/**
+ * Ensures that `dv` has a deform weight entry for the specified defweight group.
+ *
+ * \note this function is mirrored in editmesh_tools.c, for use for edit-vertices.
+ */
+struct MDeformWeight *BKE_defvert_ensure_index(struct MDeformVert *dv, int defgroup);
+/**
+ * Adds the given vertex to the specified vertex group, with given weight.
+ *
+ * \warning this does NOT check for existing, assume caller already knows its not there.
+ */
+void BKE_defvert_add_index_notest(struct MDeformVert *dv, int defgroup, float weight);
+/**
+ * Removes the given vertex from the vertex group.
+ *
+ * \warning This function frees the given #MDeformWeight, do not use it afterward!
+ */
void BKE_defvert_remove_group(struct MDeformVert *dvert, struct MDeformWeight *dw);
void BKE_defvert_clear(struct MDeformVert *dvert);
+/**
+ * \return The first group index shared by both deform verts
+ * or -1 if none are found.
+ */
int BKE_defvert_find_shared(const struct MDeformVert *dvert_a, const struct MDeformVert *dvert_b);
-bool BKE_defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgroup_tot);
+/**
+ * \return true if has no weights.
+ */
+bool BKE_defvert_is_weight_zero(const struct MDeformVert *dvert, int defgroup_tot);
void BKE_defvert_array_free_elems(struct MDeformVert *dvert, int totvert);
void BKE_defvert_array_free(struct MDeformVert *dvert, int totvert);
void BKE_defvert_array_copy(struct MDeformVert *dst, const struct MDeformVert *src, int totvert);
-float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgroup);
-float BKE_defvert_array_find_weight_safe(const struct MDeformVert *dvert,
- const int index,
- const int defgroup);
+float BKE_defvert_find_weight(const struct MDeformVert *dvert, int defgroup);
+/**
+ * Take care with this the rationale is:
+ * - if the object has no vertex group. act like vertex group isn't set and return 1.0.
+ * - if the vertex group exists but the 'defgroup' isn't found on this vertex, _still_ return 0.0.
+ *
+ * This is a bit confusing, just saves some checks from the caller.
+ */
+float BKE_defvert_array_find_weight_safe(const struct MDeformVert *dvert, int index, int defgroup);
+/**
+ * \return The total weight in all groups marked in the selection mask.
+ */
float BKE_defvert_total_selected_weight(const struct MDeformVert *dv,
int defbase_tot,
const bool *defbase_sel);
+/**
+ * \return The representative weight of a multi-paint group, used for
+ * viewport colors and actual painting.
+ *
+ * Result equal to sum of weights with auto normalize, and average otherwise.
+ * Value is not clamped, since painting relies on multiplication being always
+ * commutative with the collective weight function.
+ */
float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
int defbase_tot,
const bool *defbase_sel,
@@ -96,9 +148,19 @@ float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
/* This much unlocked weight is considered equivalent to none. */
#define VERTEX_WEIGHT_LOCK_EPSILON 1e-6f
+/**
+ * Computes the display weight for the lock relative weight paint mode.
+ *
+ * \return weight divided by 1-locked_weight with division by zero check
+ */
float BKE_defvert_calc_lock_relative_weight(float weight,
float locked_weight,
float unlocked_weight);
+/**
+ * Computes the display weight for the lock relative weight paint mode, using weight data.
+ *
+ * \return weight divided by unlocked, or 1-locked_weight with division by zero check.
+ */
float BKE_defvert_lock_relative_weight(float weight,
const struct MDeformVert *dv,
int defbase_tot,
@@ -106,79 +168,113 @@ float BKE_defvert_lock_relative_weight(float weight,
const bool *defbase_unlocked);
void BKE_defvert_copy(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src);
+/**
+ * Overwrite weights filtered by vgroup_subset.
+ * - do nothing if neither are set.
+ * - add destination weight if needed
+ */
void BKE_defvert_copy_subset(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const bool *vgroup_subset,
- const int vgroup_tot);
+ int vgroup_tot);
+/**
+ * Overwrite weights filtered by vgroup_subset and with mirroring specified by the flip map
+ * - do nothing if neither are set.
+ * - add destination weight if needed
+ */
void BKE_defvert_mirror_subset(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const bool *vgroup_subset,
- const int vgroup_tot,
+ int vgroup_tot,
const int *flip_map,
- const int flip_map_len);
+ int flip_map_len);
+/**
+ * Copy an index from one #MDeformVert to another.
+ * - do nothing if neither are set.
+ * - add destination weight if needed.
+ */
void BKE_defvert_copy_index(struct MDeformVert *dvert_dst,
- const int defgroup_dst,
+ int defgroup_dst,
const struct MDeformVert *dvert_src,
- const int defgroup_src);
+ int defgroup_src);
+/**
+ * Only sync over matching weights, don't add or remove groups
+ * warning, loop within loop.
+ */
void BKE_defvert_sync(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
- const bool use_ensure);
+ bool use_ensure);
+/**
+ * be sure all flip_map values are valid
+ */
void BKE_defvert_sync_mapped(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const int *flip_map,
- const int flip_map_len,
- const bool use_ensure);
-void BKE_defvert_remap(struct MDeformVert *dvert, const int *map, const int map_len);
-void BKE_defvert_flip(struct MDeformVert *dvert, const int *flip_map, const int flip_map_len);
-void BKE_defvert_flip_merged(struct MDeformVert *dvert,
- const int *flip_map,
- const int flip_map_len);
+ int flip_map_len,
+ bool use_ensure);
+/**
+ * be sure all flip_map values are valid
+ */
+void BKE_defvert_remap(struct MDeformVert *dvert, const int *map, int map_len);
+void BKE_defvert_flip(struct MDeformVert *dvert, const int *flip_map, int flip_map_len);
+void BKE_defvert_flip_merged(struct MDeformVert *dvert, const int *flip_map, int flip_map_len);
void BKE_defvert_normalize(struct MDeformVert *dvert);
+/**
+ * Same as #BKE_defvert_normalize but takes a bool array.
+ */
void BKE_defvert_normalize_subset(struct MDeformVert *dvert,
const bool *vgroup_subset,
- const int vgroup_tot);
+ int vgroup_tot);
+/**
+ * Same as BKE_defvert_normalize() if the locked vgroup is not a member of the subset
+ */
void BKE_defvert_normalize_lock_single(struct MDeformVert *dvert,
const bool *vgroup_subset,
- const int vgroup_tot,
- const uint def_nr_lock);
+ int vgroup_tot,
+ uint def_nr_lock);
+/**
+ * Same as BKE_defvert_normalize() if no locked vgroup is a member of the subset
+ */
void BKE_defvert_normalize_lock_map(struct MDeformVert *dvert,
const bool *vgroup_subset,
- const int vgroup_tot,
+ int vgroup_tot,
const bool *lock_flags,
- const int defbase_tot);
+ int defbase_tot);
/* Utilities to 'extract' a given vgroup into a simple float array,
* for verts, but also edges/polys/loops. */
-void BKE_defvert_extract_vgroup_to_vertweights(struct MDeformVert *dvert,
- const int defgroup,
- const int num_verts,
- float *r_weights,
- const bool invert_vgroup);
+
+void BKE_defvert_extract_vgroup_to_vertweights(
+ struct MDeformVert *dvert, int defgroup, int num_verts, float *r_weights, bool invert_vgroup);
+/**
+ * The following three make basic interpolation,
+ * using temp vert_weights array to avoid looking up same weight several times.
+ */
void BKE_defvert_extract_vgroup_to_edgeweights(struct MDeformVert *dvert,
- const int defgroup,
- const int num_verts,
+ int defgroup,
+ int num_verts,
struct MEdge *edges,
- const int num_edges,
+ int num_edges,
float *r_weights,
- const bool invert_vgroup);
+ bool invert_vgroup);
void BKE_defvert_extract_vgroup_to_loopweights(struct MDeformVert *dvert,
- const int defgroup,
- const int num_verts,
+ int defgroup,
+ int num_verts,
struct MLoop *loops,
- const int num_loops,
+ int num_loops,
float *r_weights,
- const bool invert_vgroup);
+ bool invert_vgroup);
void BKE_defvert_extract_vgroup_to_polyweights(struct MDeformVert *dvert,
- const int defgroup,
- const int num_verts,
+ int defgroup,
+ int num_verts,
struct MLoop *loops,
- const int num_loops,
+ int num_loops,
struct MPoly *polys,
- const int num_polys,
+ int num_polys,
float *r_weights,
- const bool invert_vgroup);
+ bool invert_vgroup);
-void BKE_defvert_weight_to_rgb(float r_rgb[3], const float weight);
+void BKE_defvert_weight_to_rgb(float r_rgb[3], float weight);
void BKE_defvert_blend_write(struct BlendWriter *writer, int count, struct MDeformVert *dvlist);
void BKE_defvert_blend_read(struct BlendDataReader *reader,
diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h
index 8fb596a8096..6467ad36989 100644
--- a/source/blender/blenkernel/BKE_displist.h
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -86,7 +86,7 @@ void BKE_displist_free(struct ListBase *lb);
void BKE_displist_make_curveTypes(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Object *ob,
- const bool for_render);
+ bool for_render);
void BKE_displist_make_mball(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
void BKE_curve_calc_modifiers_pre(struct Depsgraph *depsgraph,
@@ -94,14 +94,20 @@ void BKE_curve_calc_modifiers_pre(struct Depsgraph *depsgraph,
struct Object *ob,
struct ListBase *source_nurb,
struct ListBase *target_nurb,
- const bool for_render);
+ bool for_render);
bool BKE_displist_surfindex_get(
const struct DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4);
+/**
+ * \param normal_proj: Optional normal that's used to project the scan-fill verts into 2D coords.
+ * Pass this along if known since it saves time calculating the normal.
+ * This is also used to initialize #DispList.nors (one normal per display list).
+ * \param flip_normal: Flip the normal (same as passing \a normal_proj negated).
+ */
void BKE_displist_fill(const struct ListBase *dispbase,
struct ListBase *to,
const float normal_proj[3],
- const bool flip_normal);
+ bool flip_normal);
float BKE_displist_calc_taper(struct Depsgraph *depsgraph,
const struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h
index 989b68f4ccb..303a83d921f 100644
--- a/source/blender/blenkernel/BKE_duplilist.h
+++ b/source/blender/blenkernel/BKE_duplilist.h
@@ -27,15 +27,18 @@ extern "C" {
#endif
struct Depsgraph;
+struct ID;
struct ListBase;
struct Object;
struct ParticleSystem;
struct Scene;
-struct ID;
/* ---------------------------------------------------- */
/* Dupli-Geometry */
+/**
+ * \return a #ListBase of #DupliObject.
+ */
struct ListBase *object_duplilist(struct Depsgraph *depsgraph,
struct Scene *sce,
struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index 31f48be2c27..4b34a9490c4 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -64,41 +64,79 @@ typedef struct PaintWavePoint {
short state;
} PaintWavePoint;
+/**
+ * Modifier call. Processes dynamic paint modifier step.
+ */
struct Mesh *dynamicPaint_Modifier_do(struct DynamicPaintModifierData *pmd,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct Mesh *me);
+/**
+ * Free whole dynamic-paint modifier.
+ */
void dynamicPaint_Modifier_free(struct DynamicPaintModifierData *pmd);
void dynamicPaint_Modifier_free_runtime(struct DynamicPaintRuntime *runtime);
void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd,
struct DynamicPaintModifierData *tpmd,
int flag);
+/**
+ * Initialize modifier data.
+ */
bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene);
+/**
+ * Creates a new surface and adds it to the list
+ * If scene is null, frame range of 1-250 is used
+ * A pointer to this surface is returned.
+ */
struct DynamicPaintSurface *dynamicPaint_createNewSurface(
struct DynamicPaintCanvasSettings *canvas, struct Scene *scene);
+/**
+ * Clears surface data back to zero.
+ */
void dynamicPaint_clearSurface(const struct Scene *scene, struct DynamicPaintSurface *surface);
+/**
+ * Completely (re)initializes surface (only for point cache types).
+ */
bool dynamicPaint_resetSurface(const struct Scene *scene, struct DynamicPaintSurface *surface);
void dynamicPaint_freeSurface(const struct DynamicPaintModifierData *pmd,
struct DynamicPaintSurface *surface);
+/**
+ * Free canvas data.
+ */
void dynamicPaint_freeCanvas(struct DynamicPaintModifierData *pmd);
+/* Free brush data */
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd);
void dynamicPaint_freeSurfaceData(struct DynamicPaintSurface *surface);
+/**
+ * Update cache frame range.
+ */
void dynamicPaint_cacheUpdateFrames(struct DynamicPaintSurface *surface);
bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface,
struct Object *ob,
int output);
+/**
+ * Change surface data to defaults on new type.
+ */
void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface);
void dynamicPaintSurface_setUniqueName(struct DynamicPaintSurface *surface, const char *basename);
+/**
+ * Get currently active surface (in user interface).
+ */
struct DynamicPaintSurface *get_activeSurface(struct DynamicPaintCanvasSettings *canvas);
-/* image sequence baking */
+/**
+ * Image sequence baking.
+ */
int dynamicPaint_createUVSurface(struct Scene *scene,
struct DynamicPaintSurface *surface,
float *progress,
short *do_update);
+/**
+ * Calculate a single frame and included sub-frames for surface.
+ */
int dynamicPaint_calculateFrame(struct DynamicPaintSurface *surface,
struct Depsgraph *depsgraph,
struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 2c24b1a5487..1da7ae3da8a 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -19,7 +19,7 @@
/** \file
* \ingroup bke
*
- * The \link edmesh EDBM module\endlink is for editmode bmesh stuff.
+ * The \link edmesh EDBM module \endlink is for editmode bmesh stuff.
* In contrast, this module is for code shared with blenkernel that's
* only concerned with low level operations on the #BMEditMesh structure.
*/
@@ -62,14 +62,6 @@ typedef struct BMEditMesh {
struct BMLoop *(*looptris)[3];
int tottri;
- struct Mesh *mesh_eval_final, *mesh_eval_cage;
-
- /** Cached cage bounding box of `mesh_eval_cage` for selection. */
- struct BoundBox *bb_cage;
-
- /** Evaluated mesh data-mask. */
- CustomData_MeshMasks lastDataMask;
-
/** Selection mode (#SCE_SELECT_VERTEX, #SCE_SELECT_EDGE & #SCE_SELECT_FACE). */
short selectmode;
/** The active material (assigned to newly created faces). */
@@ -102,12 +94,28 @@ void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, struct BMPartialUpda
void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em,
struct BMPartialUpdate *bmpinfo);
+/**
+ * Performing the face normal calculation at the same time as tessellation
+ * gives a reasonable performance boost (approx ~20% faster).
+ */
void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em);
+/**
+ * \note The caller is responsible for ensuring triangulation data,
+ * typically by calling #BKE_editmesh_looptri_calc.
+ */
BMEditMesh *BKE_editmesh_create(BMesh *bm);
BMEditMesh *BKE_editmesh_copy(BMEditMesh *em);
+/**
+ * \brief Return the #BMEditMesh for a given object
+ *
+ * \note this function assumes this is a mesh object,
+ * don't add NULL data check here. caller must do that
+ */
BMEditMesh *BKE_editmesh_from_object(struct Object *ob);
-void BKE_editmesh_free_derived_caches(BMEditMesh *em);
+/**
+ * \note Does not free the #BMEditMesh struct itself.
+ */
void BKE_editmesh_free_data(BMEditMesh *em);
float (*BKE_editmesh_vert_coords_alloc(struct Depsgraph *depsgraph,
@@ -124,8 +132,11 @@ const float (*BKE_editmesh_vert_coords_when_deformed(struct Depsgraph *depsgraph
bool *r_is_alloc))[3];
void BKE_editmesh_lnorspace_update(BMEditMesh *em, struct Mesh *me);
+/**
+ * If auto-smooth not already set, set it.
+ */
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, struct Mesh *me);
-struct BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em);
+struct BoundBox *BKE_editmesh_cage_boundbox_get(struct Object *object, BMEditMesh *em);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h
index 69d1b4819f8..b4368ff363b 100644
--- a/source/blender/blenkernel/BKE_editmesh_bvh.h
+++ b/source/blender/blenkernel/BKE_editmesh_bvh.h
@@ -42,13 +42,13 @@ typedef bool (*BMBVHTree_FaceFilter)(struct BMFace *f, void *userdata);
BMBVHTree *BKE_bmbvh_new_from_editmesh(struct BMEditMesh *em,
int flag,
const float (*cos_cage)[3],
- const bool cos_cage_free);
+ bool cos_cage_free);
BMBVHTree *BKE_bmbvh_new_ex(struct BMesh *bm,
struct BMLoop *(*looptris)[3],
int looptris_tot,
int flag,
const float (*cos_cage)[3],
- const bool cos_cage_free,
+ bool cos_cage_free,
bool (*test_fn)(struct BMFace *, void *user_data),
void *user_data);
BMBVHTree *BKE_bmbvh_new(struct BMesh *bm,
@@ -56,14 +56,14 @@ BMBVHTree *BKE_bmbvh_new(struct BMesh *bm,
int looptris_tot,
int flag,
const float (*cos_cage)[3],
- const bool cos_cage_free);
+ bool cos_cage_free);
void BKE_bmbvh_free(BMBVHTree *tree);
struct BVHTree *BKE_bmbvh_tree_get(BMBVHTree *tree);
struct BMFace *BKE_bmbvh_ray_cast(BMBVHTree *tree,
const float co[3],
const float dir[3],
- const float radius,
+ float radius,
float *r_dist,
float r_hitout[3],
float r_cagehit[3]);
@@ -71,25 +71,29 @@ struct BMFace *BKE_bmbvh_ray_cast(BMBVHTree *tree,
struct BMFace *BKE_bmbvh_ray_cast_filter(BMBVHTree *tree,
const float co[3],
const float dir[3],
- const float radius,
+ float radius,
float *r_dist,
float r_hitout[3],
float r_cagehit[3],
BMBVHTree_FaceFilter filter_cb,
void *filter_userdata);
-/* find a vert closest to co in a sphere of radius dist_max */
-struct BMVert *BKE_bmbvh_find_vert_closest(BMBVHTree *tree,
- const float co[3],
- const float dist_max);
-struct BMFace *BKE_bmbvh_find_face_closest(BMBVHTree *tree,
- const float co[3],
- const float dist_max);
+/**
+ * Find a vert closest to co in a sphere of radius dist_max.
+ */
+struct BMVert *BKE_bmbvh_find_vert_closest(BMBVHTree *tree, const float co[3], float dist_max);
+struct BMFace *BKE_bmbvh_find_face_closest(BMBVHTree *tree, const float co[3], float dist_max);
+/**
+ * Overlap indices reference the looptri's.
+ */
struct BVHTreeOverlap *BKE_bmbvh_overlap(const BMBVHTree *bmtree_a,
const BMBVHTree *bmtree_b,
unsigned int *r_overlap_tot);
+/**
+ * Overlap indices reference the looptri's.
+ */
struct BVHTreeOverlap *BKE_bmbvh_overlap_self(const BMBVHTree *bmtree,
unsigned int *r_overlap_tot);
diff --git a/source/blender/blenkernel/BKE_editmesh_tangent.h b/source/blender/blenkernel/BKE_editmesh_tangent.h
index 0e3f063ae44..3b0569b869a 100644
--- a/source/blender/blenkernel/BKE_editmesh_tangent.h
+++ b/source/blender/blenkernel/BKE_editmesh_tangent.h
@@ -24,6 +24,13 @@
extern "C" {
#endif
+/**
+ * \see #BKE_mesh_calc_loop_tangent, same logic but used arrays instead of #BMesh data.
+ *
+ * \note This function is not so normal, its using #BMesh.ldata as input,
+ * but output's to #Mesh.ldata.
+ * This is done because #CD_TANGENT is cache data used only for drawing.
+ */
void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME],
@@ -32,7 +39,7 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
const float (*loop_normals)[3],
const float (*vert_orco)[3],
CustomData *dm_loopdata_out,
- const uint dm_loopdata_out_len,
+ uint dm_loopdata_out_len,
short *tangent_mask_curr_p);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h
index 3a964ddb1aa..f33ca2f03d1 100644
--- a/source/blender/blenkernel/BKE_effect.h
+++ b/source/blender/blenkernel/BKE_effect.h
@@ -113,16 +113,27 @@ struct PartDeflect *BKE_partdeflect_new(int type);
struct PartDeflect *BKE_partdeflect_copy(const struct PartDeflect *pd_src);
void BKE_partdeflect_free(struct PartDeflect *pd);
+/**
+ * Create list of effector relations in the collection or entire scene.
+ * This is used by the depsgraph to build relations, as well as faster
+ * lookup of effectors during evaluation.
+ */
struct ListBase *BKE_effector_relations_create(struct Depsgraph *depsgraph,
struct ViewLayer *view_layer,
struct Collection *collection);
void BKE_effector_relations_free(struct ListBase *lb);
+/**
+ * Create effective list of effectors from relations built beforehand.
+ */
struct ListBase *BKE_effectors_create(struct Depsgraph *depsgraph,
struct Object *ob_src,
struct ParticleSystem *psys_src,
struct EffectorWeights *weights,
bool use_rotation);
+/**
+ * Generic force/speed system, now used for particles, soft-bodies & dynamic-paint.
+ */
void BKE_effectors_apply(struct ListBase *effectors,
struct ListBase *colliders,
struct EffectorWeights *weights,
@@ -146,15 +157,15 @@ float effector_falloff(struct EffectorCache *eff,
struct EffectorData *efd,
struct EffectedPoint *point,
struct EffectorWeights *weights);
-int closest_point_on_surface(struct SurfaceModifierData *surmd,
- const float co[3],
- float surface_co[3],
- float surface_nor[3],
- float surface_vel[3]);
-int get_effector_data(struct EffectorCache *eff,
- struct EffectorData *efd,
- struct EffectedPoint *point,
- int real_velocity);
+bool closest_point_on_surface(struct SurfaceModifierData *surmd,
+ const float co[3],
+ float surface_co[3],
+ float surface_nor[3],
+ float surface_vel[3]);
+bool get_effector_data(struct EffectorCache *eff,
+ struct EffectorData *efd,
+ struct EffectedPoint *point,
+ int real_velocity);
/* required for particle_system.c */
#if 0
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index f494c2e30cc..121ec7f316b 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -133,20 +133,56 @@ typedef enum eFMI_Requirement_Flags {
} eFMI_Requirement_Flags;
/* Function Prototypes for FModifierTypeInfo's */
+
+/**
+ * This function should always be used to get the appropriate type-info,
+ * as it has checks which prevent segfaults in some weird cases.
+ */
const FModifierTypeInfo *fmodifier_get_typeinfo(const struct FModifier *fcm);
-const FModifierTypeInfo *get_fmodifier_typeinfo(const int type);
+/**
+ * This function should be used for getting the appropriate type-info when only
+ * a F-Curve modifier type is known.
+ */
+const FModifierTypeInfo *get_fmodifier_typeinfo(int type);
/* ---------------------- */
+/**
+ * Add a new F-Curve Modifier to the given F-Curve of a certain type.
+ */
struct FModifier *add_fmodifier(ListBase *modifiers, int type, struct FCurve *owner_fcu);
+/**
+ * Make a copy of the specified F-Modifier.
+ */
struct FModifier *copy_fmodifier(const struct FModifier *src);
+/**
+ * Duplicate all of the F-Modifiers in the Modifier stacks.
+ */
void copy_fmodifiers(ListBase *dst, const ListBase *src);
+/**
+ * Remove and free the given F-Modifier from the given stack.
+ */
bool remove_fmodifier(ListBase *modifiers, struct FModifier *fcm);
+/**
+ * Remove all of a given F-Curve's modifiers.
+ */
void free_fmodifiers(ListBase *modifiers);
+/**
+ * Find the active F-Modifier.
+ */
struct FModifier *find_active_fmodifier(ListBase *modifiers);
+/**
+ * Set the active F-Modifier.
+ */
void set_active_fmodifier(ListBase *modifiers, struct FModifier *fcm);
+/**
+ * Do we have any modifiers which match certain criteria.
+ *
+ * \param mtype: Type of modifier (if 0, doesn't matter).
+ * \param acttype: Type of action to perform (if -1, doesn't matter).
+ */
bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype);
typedef struct FModifiersStackStorage {
@@ -156,17 +192,38 @@ typedef struct FModifiersStackStorage {
} FModifiersStackStorage;
uint evaluate_fmodifiers_storage_size_per_modifier(ListBase *modifiers);
+/**
+ * Evaluate time modifications imposed by some F-Curve Modifiers.
+ *
+ * - This step acts as an optimization to prevent the F-Curve stack being evaluated
+ * several times by modifiers requesting the time be modified, as the final result
+ * would have required using the modified time
+ * - Modifiers only ever receive the unmodified time, as subsequent modifiers should be
+ * working on the 'global' result of the modified curve, not some localized segment,
+ * so \a evaltime gets set to whatever the last time-modifying modifier likes.
+ * - We start from the end of the stack, as only the last one matters for now.
+ *
+ * \param fcu: Can be NULL.
+ */
float evaluate_time_fmodifiers(FModifiersStackStorage *storage,
ListBase *modifiers,
struct FCurve *fcu,
float cvalue,
float evaltime);
+/**
+ * Evaluates the given set of F-Curve Modifiers using the given data
+ * Should only be called after evaluate_time_fmodifiers() has been called.
+ */
void evaluate_value_fmodifiers(FModifiersStackStorage *storage,
ListBase *modifiers,
struct FCurve *fcu,
float *cvalue,
float evaltime);
+/**
+ * Bake modifiers for given F-Curve to curve sample data, in the frame range defined
+ * by start and end (inclusive).
+ */
void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end);
int BKE_fcm_envelope_find_index(struct FCM_EnvelopeData *array,
@@ -182,30 +239,64 @@ int BKE_fcm_envelope_find_index(struct FCM_EnvelopeData *array,
/* -------- Data Management -------- */
struct FCurve *BKE_fcurve_create(void);
+/**
+ * Frees the F-Curve itself too, so make sure #BLI_remlink is called before calling this.
+ */
void BKE_fcurve_free(struct FCurve *fcu);
+/**
+ * Duplicate a F-Curve.
+ */
struct FCurve *BKE_fcurve_copy(const struct FCurve *fcu);
-
+/**
+ * Frees a list of F-Curves.
+ */
void BKE_fcurves_free(ListBase *list);
+/**
+ * Duplicate a list of F-Curves.
+ */
void BKE_fcurves_copy(ListBase *dst, ListBase *src);
+/**
+ * Callback used by lib_query to walk over all ID usages
+ * (mimics `foreach_id` callback of #IDTypeInfo structure).
+ */
void BKE_fcurve_foreach_id(struct FCurve *fcu, struct LibraryForeachIDData *data);
-/* find matching F-Curve in the given list of F-Curves */
-struct FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_index);
+/**
+ * Find the F-Curve affecting the given RNA-access path + index,
+ * in the list of F-Curves provided.
+ */
+struct FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], int array_index);
+/**
+ * Quick way to loop over all f-curves of a given 'path'.
+ */
struct FCurve *BKE_fcurve_iter_step(struct FCurve *fcu_iter, const char rna_path[]);
-/* high level function to get an fcurve from C without having the rna */
+/**
+ * High level function to get an f-curve from C without having the RNA.
+ */
struct FCurve *id_data_find_fcurve(
ID *id, void *data, struct StructRNA *type, const char *prop_name, int index, bool *r_driven);
-/* Get list of LinkData's containing pointers to the F-Curves which control the types of data
- * indicated
- * e.g. numMatches = BKE_fcurves_filter(matches, &act->curves, "pose.bones[", "MyFancyBone");
+/**
+ * Get list of LinkData's containing pointers to the F-curves
+ * which control the types of data indicated.
+ * e.g. `numMatches = BKE_fcurves_filter(matches, &act->curves, "pose.bones[", "MyFancyBone");`
+ *
+ * Lists:
+ * \param dst: list of LinkData's matching the criteria returned.
+ * List must be freed after use, and is assumed to be empty when passed.
+ * \param src: list of F-Curves to search through
+ * Filters:
+ * \param dataPrefix: i.e. `pose.bones[` or `nodes[`.
+ * \param dataName: name of entity within "" immediately following the prefix.
*/
int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName);
-/* Find an f-curve based on an rna property. */
+/**
+ * Find an f-curve based on an rna property.
+ */
struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
struct PropertyRNA *prop,
int rnaindex,
@@ -213,8 +304,10 @@ struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
struct bAction **r_action,
bool *r_driven,
bool *r_special);
-/* Same as above, but takes a context data,
- * temp hack needed for complex paths like texture ones. */
+/**
+ * Same as above, but takes a context data,
+ * temp hack needed for complex paths like texture ones.
+ */
struct FCurve *BKE_fcurve_find_by_rna_context_ui(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
@@ -224,65 +317,105 @@ struct FCurve *BKE_fcurve_find_by_rna_context_ui(struct bContext *C,
bool *r_driven,
bool *r_special);
-/* Binary search algorithm for finding where to 'insert' BezTriple with given frame number.
+/**
+ * Binary search algorithm for finding where to 'insert' #BezTriple with given frame number.
* Returns the index to insert at (data already at that index will be offset if replace is 0)
*/
int BKE_fcurve_bezt_binarysearch_index(const struct BezTriple array[],
- const float frame,
- const int arraylen,
+ float frame,
+ int arraylen,
bool *r_replace);
/* fcurve_cache.c */
-/* Cached f-curve look-ups, use when this needs to be done many times. */
+
+/**
+ * Cached f-curve look-ups, use when this needs to be done many times.
+ */
struct FCurvePathCache;
struct FCurvePathCache *BKE_fcurve_pathcache_create(ListBase *list);
void BKE_fcurve_pathcache_destroy(struct FCurvePathCache *fcache);
struct FCurve *BKE_fcurve_pathcache_find(struct FCurvePathCache *fcache,
const char rna_path[],
- const int array_index);
+ int array_index);
+/**
+ * Fill in an array of F-Curve, leave NULL when not found.
+ *
+ * \return The number of F-Curves found.
+ */
int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache,
const char *rna_path,
struct FCurve **fcurve_result,
int fcurve_result_len);
-/* get the time extents for F-Curve */
+/**
+ * Calculate the extents of F-Curve's keyframes.
+ */
bool BKE_fcurve_calc_range(
- struct FCurve *fcu, float *min, float *max, const bool do_sel_only, const bool do_min_length);
+ struct FCurve *fcu, float *min, float *max, bool do_sel_only, bool do_min_length);
-/* get the bounding-box extents for F-Curve */
+/**
+ * Calculate the extents of F-Curve's data.
+ */
bool BKE_fcurve_calc_bounds(struct FCurve *fcu,
float *xmin,
float *xmax,
float *ymin,
float *ymax,
- const bool do_sel_only,
- const bool include_handles);
+ bool do_sel_only,
+ bool include_handles);
+/**
+ * Return an array of keyed frames, rounded to `interval`.
+ *
+ * \param interval: Set to 1.0 to round to whole keyframes, 0.5 for in-between key-frames, etc.
+ *
+ * \note An interval of zero could be supported (this implies no rounding at all),
+ * however this risks very small differences in float values being treated as separate keyframes.
+ */
float *BKE_fcurves_calc_keyed_frames_ex(struct FCurve **fcurve_array,
- const int fcurve_array_len,
- const float interval,
+ int fcurve_array_len,
+ float interval,
int *r_frames_len);
float *BKE_fcurves_calc_keyed_frames(struct FCurve **fcurve_array,
- const int fcurve_array_len,
+ int fcurve_array_len,
int *r_frames_len);
+/**
+ * Set the index that stores the FCurve's active keyframe, assuming that \a active_bezt
+ * is already part of `fcu->bezt`. If NULL, set active keyframe index to "none."
+ */
void BKE_fcurve_active_keyframe_set(struct FCurve *fcu, const struct BezTriple *active_bezt);
+/**
+ * Get the active keyframe index, with sanity checks for point bounds.
+ */
int BKE_fcurve_active_keyframe_index(const struct FCurve *fcu);
-/* Move the indexed keyframe to the given value, and move the handles with it to ensure the slope
- * remains the same. */
+/**
+ * Move the indexed keyframe to the given value,
+ * and move the handles with it to ensure the slope remains the same.
+ */
void BKE_fcurve_keyframe_move_value_with_handles(struct BezTriple *keyframe, float new_value);
/* .............. */
-/* Are keyframes on F-Curve of any use (to final result, and to show in editors)? */
+/**
+ * Are keyframes on F-Curve of any use (to final result, and to show in editors)?
+ * Usability of keyframes refers to whether they should be displayed,
+ * and also whether they will have any influence on the final result.
+ */
bool BKE_fcurve_are_keyframes_usable(struct FCurve *fcu);
-/* Can keyframes be added to F-Curve? */
+/**
+ * Can keyframes be added to F-Curve?
+ * Keyframes can only be added if they are already visible.
+ */
bool BKE_fcurve_is_keyframable(struct FCurve *fcu);
bool BKE_fcurve_is_protected(struct FCurve *fcu);
-/* The curve is an infinite cycle via Cycles modifier */
+/**
+ * Checks if the F-Curve has a Cycles modifier with simple settings
+ * that warrant transition smoothing.
+ */
bool BKE_fcurve_is_cyclic(struct FCurve *fcu);
/* Type of infinite cycle for a curve. */
@@ -294,9 +427,19 @@ typedef enum eFCU_Cycle_Type {
FCU_CYCLE_OFFSET,
} eFCU_Cycle_Type;
+/**
+ * Checks if the F-Curve has a Cycles modifier, and returns the type of the cycle behavior.
+ */
eFCU_Cycle_Type BKE_fcurve_get_cycle_type(struct FCurve *fcu);
-/* Recompute handles to neatly subdivide the prev-next range at bezt. */
+/**
+ * Recompute bezier handles of all three given BezTriples, so that `bezt` can be inserted between
+ * `prev` and `next` without changing the resulting curve shape.
+ *
+ * \param r_pdelta: return Y difference between `bezt` and the original curve value at its X
+ * position.
+ * \return Whether the split was successful.
+ */
bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt,
struct BezTriple *prev,
struct BezTriple *next,
@@ -304,12 +447,50 @@ bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt,
/* -------- Curve Sanity -------- */
+/**
+ * This function recalculates the handles of an F-Curve. Acts based on selection with `SELECT`
+ * flag. To use a different flag, use #calchandles_fcurve_ex().
+ *
+ * If the BezTriples have been rearranged, sort them first before using this.
+ */
void calchandles_fcurve(struct FCurve *fcu);
+/**
+ * Variant of #calchandles_fcurve() that allows calculating based on a different select flag.
+ *
+ * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection.
+ * Usually `SELECT`, but may want to use a different one at times
+ * (if caller does not operate on selection).
+ */
void calchandles_fcurve_ex(struct FCurve *fcu, eBezTriple_Flag handle_sel_flag);
-void testhandles_fcurve(struct FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_handle);
+/**
+ * Update handles, making sure the handle-types are valid (e.g. correctly deduced from an "Auto"
+ * type), and recalculating their position vectors.
+ * Use when something has changed handle positions.
+ *
+ * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
+ * but may want to use a different one at times (if caller does not operate on selection).
+ * \param use_handle: Check selection state of individual handles, otherwise always update both
+ * handles if the key is selected.
+ */
+void testhandles_fcurve(struct FCurve *fcu, eBezTriple_Flag sel_flag, bool use_handle);
+/**
+ * This function sorts BezTriples so that they are arranged in chronological order,
+ * as tools working on F-Curves expect that the BezTriples are in order.
+ */
void sort_time_fcurve(struct FCurve *fcu);
+/**
+ * This function tests if any BezTriples are out of order, thus requiring a sort.
+ */
bool test_time_fcurve(struct FCurve *fcu);
+/**
+ * The length of each handle is not allowed to be more
+ * than the horizontal distance between (v1-v4).
+ * This is to prevent curve loops.
+ *
+ * This function is very similar to BKE_curve_correct_bezpart(), but allows a steeper tangent for
+ * more snappy animations. This is not desired for other areas in which curves are used, though.
+ */
void BKE_fcurve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2]);
/* -------- Evaluation -------- */
@@ -321,8 +502,14 @@ float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna,
struct FCurve *fcu,
struct ChannelDriver *driver_orig,
const struct AnimationEvalContext *anim_eval_context);
+/**
+ * Checks if the curve has valid keys, drivers or modifiers that produce an actual curve.
+ */
bool BKE_fcurve_is_empty(struct FCurve *fcu);
-/* evaluate fcurve and store value */
+/**
+ * Calculate the value of the given F-Curve at the given frame,
+ * and store it's value in #FCurve.curval.
+ */
float calculate_fcurve(struct PathResolvedRNA *anim_rna,
struct FCurve *fcu,
const struct AnimationEvalContext *anim_eval_context);
@@ -331,27 +518,35 @@ float calculate_fcurve(struct PathResolvedRNA *anim_rna,
/* -------- Defines -------- */
-/* Basic signature for F-Curve sample-creation function
- * - fcu: the F-Curve being operated on
- * - data: pointer to some specific data that may be used by one of the callbacks
+/**
+ * Basic signature for F-Curve sample-creation function.
+ *
+ * \param fcu: the F-Curve being operated on.
+ * \param data: pointer to some specific data that may be used by one of the callbacks.
*/
typedef float (*FcuSampleFunc)(struct FCurve *fcu, void *data, float evaltime);
/* ----- Sampling Callbacks ------ */
-/* Basic sampling callback which acts as a wrapper for evaluate_fcurve() */
+/**
+ * Basic sampling callback which acts as a wrapper for #evaluate_fcurve()
+ * 'data' arg here is unneeded here.
+ */
float fcurve_samplingcb_evalcurve(struct FCurve *fcu, void *data, float evaltime);
/* -------- Main Methods -------- */
-/* Main API function for creating a set of sampled curve data, given some callback function
+/**
+ * Main API function for creating a set of sampled curve data, given some callback function
* used to retrieve the values to store.
*/
void fcurve_store_samples(
struct FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb);
-/* Convert baked/sampled fcurves into bezt/regular fcurves. */
-void fcurve_samples_to_keyframes(struct FCurve *fcu, const int start, const int end);
+/**
+ * Convert baked/sampled f-curves into bezt/regular f-curves.
+ */
+void fcurve_samples_to_keyframes(struct FCurve *fcu, int start, int end);
/* ************* F-Curve .blend file API ******************** */
diff --git a/source/blender/blenkernel/BKE_fcurve_driver.h b/source/blender/blenkernel/BKE_fcurve_driver.h
index 5b4da4a78a4..20667c4dfba 100644
--- a/source/blender/blenkernel/BKE_fcurve_driver.h
+++ b/source/blender/blenkernel/BKE_fcurve_driver.h
@@ -66,34 +66,92 @@ struct PropertyRNA;
/* ---------------------- */
+/**
+ * This frees the driver itself.
+ */
void fcurve_free_driver(struct FCurve *fcu);
+/**
+ * This makes a copy of the given driver.
+ */
struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver);
+/**
+ * Copy driver variables from src_vars list to dst_vars list.
+ */
void driver_variables_copy(struct ListBase *dst_vars, const struct ListBase *src_vars);
+/**
+ * Compute channel values for a rotational Transform Channel driver variable.
+ */
void BKE_driver_target_matrix_to_rot_channels(
float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]);
+/**
+ * Perform actual freeing driver variable and remove it from the given list.
+ */
void driver_free_variable(struct ListBase *variables, struct DriverVar *dvar);
+/**
+ * Free the driver variable and do extra updates.
+ */
void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar);
+/**
+ * Change the type of driver variable.
+ */
void driver_change_variable_type(struct DriverVar *dvar, int type);
+/**
+ * Validate driver variable name (after being renamed).
+ *
+ */
void driver_variable_name_validate(struct DriverVar *dvar);
+/**
+ * Ensure the driver variable's name is unique.
+ *
+ * Assumes the driver variable has already been assigned to the driver, so that
+ * the `prev/next` pointers can be used to find the other variables.
+ */
+void driver_variable_unique_name(struct DriverVar *dvar);
+/**
+ * Add a new driver variable.
+ */
struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
+/**
+ * Evaluate a Driver Variable to get a value that contributes to the final.
+ */
float driver_get_variable_value(struct ChannelDriver *driver, struct DriverVar *dvar);
+/**
+ * Same as 'dtar_get_prop_val'. but get the RNA property.
+ */
bool driver_get_variable_property(struct ChannelDriver *driver,
struct DriverTarget *dtar,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop,
int *r_index);
+/**
+ * Check if the expression in the driver conforms to the simple subset.
+ */
bool BKE_driver_has_simple_expression(struct ChannelDriver *driver);
+/**
+ * Check if the expression in the driver may depend on the current frame.
+ */
bool BKE_driver_expression_depends_on_time(struct ChannelDriver *driver);
+/**
+ * Reset cached compiled expression data.
+ */
void BKE_driver_invalidate_expression(struct ChannelDriver *driver,
bool expr_changed,
bool varname_changed);
+/**
+ * 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(struct PathResolvedRNA *anim_rna,
struct ChannelDriver *driver,
struct ChannelDriver *driver_orig,
diff --git a/source/blender/blenkernel/BKE_fluid.h b/source/blender/blenkernel/BKE_fluid.h
index 33ff6943514..88df8e52dca 100644
--- a/source/blender/blenkernel/BKE_fluid.h
+++ b/source/blender/blenkernel/BKE_fluid.h
@@ -49,7 +49,7 @@ void BKE_fluid_modifier_reset(struct FluidModifierData *fmd);
void BKE_fluid_modifier_create_type_data(struct FluidModifierData *fmd);
void BKE_fluid_modifier_copy(const struct FluidModifierData *fmd,
struct FluidModifierData *tfmd,
- const int flag);
+ int flag);
bool BKE_fluid_reallocate_fluid(struct FluidDomainSettings *fds, int res[3], int free_old);
void BKE_fluid_reallocate_copy_fluid(struct FluidDomainSettings *fds,
@@ -64,6 +64,10 @@ void BKE_fluid_cache_free_all(struct FluidDomainSettings *fds, struct Object *ob
void BKE_fluid_cache_free(struct FluidDomainSettings *fds, struct Object *ob, int cache_map);
void BKE_fluid_cache_new_name_for_current_session(int maxlen, char *r_name);
+/**
+ * Get fluid velocity and density at given coordinates.
+ * \returns fluid density or -1.0f if outside domain.
+ */
float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
int BKE_fluid_get_data_flags(struct FluidDomainSettings *fds);
@@ -72,8 +76,8 @@ void BKE_fluid_particle_system_create(struct Main *bmain,
const char *pset_name,
const char *parts_name,
const char *psys_name,
- const int psys_type);
-void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type);
+ int psys_type);
+void BKE_fluid_particle_system_destroy(struct Object *ob, int particle_type);
void BKE_fluid_cache_startframe_set(struct FluidDomainSettings *settings, int value);
void BKE_fluid_cache_endframe_set(struct FluidDomainSettings *settings, int value);
diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h
index 5e29665d728..3a4301aad6d 100644
--- a/source/blender/blenkernel/BKE_freestyle.h
+++ b/source/blender/blenkernel/BKE_freestyle.h
@@ -38,15 +38,19 @@ typedef struct FreestyleSettings FreestyleSettings;
/* FreestyleConfig */
void BKE_freestyle_config_init(struct FreestyleConfig *config);
-void BKE_freestyle_config_free(struct FreestyleConfig *config, const bool do_id_user);
+void BKE_freestyle_config_free(struct FreestyleConfig *config, bool do_id_user);
void BKE_freestyle_config_copy(struct FreestyleConfig *new_config,
const struct FreestyleConfig *config,
- const int flag);
+ int flag);
/* FreestyleConfig.modules */
struct FreestyleModuleConfig *BKE_freestyle_module_add(struct FreestyleConfig *config);
bool BKE_freestyle_module_delete(struct FreestyleConfig *config,
struct FreestyleModuleConfig *module_conf);
+/**
+ * Reinsert \a module_conf offset by \a direction from current position.
+ * \return if position of \a module_conf changed.
+ */
bool BKE_freestyle_module_move(struct FreestyleConfig *config,
struct FreestyleModuleConfig *module_conf,
int direction);
diff --git a/source/blender/blenkernel/BKE_geometry_set.h b/source/blender/blenkernel/BKE_geometry_set.h
index 17cdb9d6a42..2d6218f1036 100644
--- a/source/blender/blenkernel/BKE_geometry_set.h
+++ b/source/blender/blenkernel/BKE_geometry_set.h
@@ -39,6 +39,8 @@ typedef enum GeometryComponentType {
GEO_COMPONENT_TYPE_CURVE = 4,
} GeometryComponentType;
+#define GEO_COMPONENT_TYPE_ENUM_SIZE 5
+
void BKE_geometry_set_free(struct GeometrySet *geometry_set);
bool BKE_object_has_geometry_set_instances(const struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index f182fb527e1..f92f33b2776 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -23,11 +23,11 @@
#include <atomic>
#include <iostream>
-#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
#include "BLI_function_ref.hh"
#include "BLI_hash.hh"
#include "BLI_map.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_set.hh"
#include "BLI_user_counter.hh"
#include "BLI_vector_set.hh"
@@ -62,7 +62,9 @@ class ComponentAttributeProviders;
class GeometryComponent;
/**
- * This is the base class for specialized geometry component types.
+ * This is the base class for specialized geometry component types. A geometry component handles
+ * a user count to allow avoiding duplication when it is wrapped with #UserCounter. It also handles
+ * the attribute API, which generalizes storing and modifying generic information on a geometry.
*/
class GeometryComponent {
private:
@@ -91,99 +93,142 @@ class GeometryComponent {
GeometryComponentType type() const;
- /* Return true when any attribute with this name exists, including built in attributes. */
+ /**
+ * Return true when any attribute with this name exists, including built in attributes.
+ */
bool attribute_exists(const blender::bke::AttributeIDRef &attribute_id) const;
- /* Return the data type and domain of an attribute with the given name if it exists. */
+ /**
+ * Return the data type and domain of an attribute with the given name if it exists.
+ */
std::optional<AttributeMetaData> attribute_get_meta_data(
const blender::bke::AttributeIDRef &attribute_id) const;
- /* Returns true when the geometry component supports this attribute domain. */
- bool attribute_domain_supported(const AttributeDomain domain) const;
- /* Can only be used with supported domain types. */
- virtual int attribute_domain_size(const AttributeDomain domain) const;
+ /**
+ * Return true when the geometry component supports this attribute domain.
+ * \note Conceptually this function is static, the result is always the same for different
+ * instances of the same geometry component type.
+ */
+ bool attribute_domain_supported(AttributeDomain domain) const;
+ /**
+ * Return the length of a specific domain, or 0 if the domain is not supported.
+ */
+ virtual int attribute_domain_size(AttributeDomain domain) const;
+ /**
+ * Return true if the attribute name corresponds to a built-in attribute with a hardcoded domain
+ * and data type.
+ */
bool attribute_is_builtin(const blender::StringRef attribute_name) const;
bool attribute_is_builtin(const blender::bke::AttributeIDRef &attribute_id) const;
- /* Get read-only access to the highest priority attribute with the given name.
- * Returns null if the attribute does not exist. */
+ /**
+ * Get read-only access to an attribute with the given name or id, on the highest priority domain
+ * if there is a name collision.
+ * \return null if the attribute does not exist.
+ */
blender::bke::ReadAttributeLookup attribute_try_get_for_read(
const blender::bke::AttributeIDRef &attribute_id) const;
- /* Get read and write access to the highest priority attribute with the given name.
- * Returns null if the attribute does not exist. */
+ /**
+ * Get read and write access to an attribute with the given name or id, on the highest priority
+ * domain if there is a name collision.
+ * \note #WriteAttributeLookup.tag_modified_fn must be called after modifying data.
+ * \return null if the attribute does not exist
+ */
blender::bke::WriteAttributeLookup attribute_try_get_for_write(
const blender::bke::AttributeIDRef &attribute_id);
- /* Get a read-only attribute for the domain based on the given attribute. This can be used to
+ /**
+ * Get a read-only attribute for the domain based on the given attribute. This can be used to
* interpolate from one domain to another.
- * Returns null if the interpolation is not implemented. */
- virtual std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain(
- std::unique_ptr<blender::fn::GVArray> varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const;
+ * \return null if the interpolation is not implemented.
+ */
+ blender::fn::GVArray attribute_try_adapt_domain(const blender::fn::GVArray &varray,
+ const AttributeDomain from_domain,
+ const AttributeDomain to_domain) const
+ {
+ return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain);
+ }
+ /* Use instead of the method above when the type is known at compile time for type safety. */
+ template<typename T>
+ blender::VArray<T> attribute_try_adapt_domain(const blender::VArray<T> &varray,
+ const AttributeDomain from_domain,
+ const AttributeDomain to_domain) const
+ {
+ return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain)
+ .template typed<T>();
+ }
- /* Returns true when the attribute has been deleted. */
+ /** Returns true when the attribute has been deleted. */
bool attribute_try_delete(const blender::bke::AttributeIDRef &attribute_id);
- /* Returns true when the attribute has been created. */
+ /** Returns true when the attribute has been created. */
bool attribute_try_create(const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain,
+ AttributeDomain domain,
const CustomDataType data_type,
const AttributeInit &initializer);
- /* Try to create the builtin attribute with the given name. No data type or domain has to be
- * provided, because those are fixed for builtin attributes. */
+ /**
+ * Try to create the builtin attribute with the given name. No data type or domain has to be
+ * provided, because those are fixed for builtin attributes.
+ */
bool attribute_try_create_builtin(const blender::StringRef attribute_name,
const AttributeInit &initializer);
blender::Set<blender::bke::AttributeIDRef> attribute_ids() const;
+ /**
+ * \return False if the callback explicitly returned false at any point, otherwise true,
+ * meaning the callback made it all the way through.
+ */
bool attribute_foreach(const AttributeForeachCallback callback) const;
virtual bool is_empty() const;
- /* Get a virtual array to read the data of an attribute on the given domain and data type.
- * Returns null when the attribute does not exist or cannot be converted to the requested domain
- * and data type. */
- std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read(
- const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type) const;
+ /**
+ * Get a virtual array that refers to the data of an attribute, interpolated to the given domain
+ * and converted to the data type. Returns null when the attribute does not exist or cannot be
+ * interpolated or converted.
+ */
+ blender::fn::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
+ AttributeDomain domain,
+ const CustomDataType data_type) const;
- /* Get a virtual array to read the data of an attribute on the given domain. The data type is
- * left unchanged. Returns null when the attribute does not exist or cannot be adapted to the
- * requested domain. */
- std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read(
- const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain) const;
+ /**
+ * Get a virtual array that refers to the data of an attribute, interpolated to the given domain.
+ * The data type is left unchanged. Returns null when the attribute does not exist or cannot be
+ * interpolated.
+ */
+ blender::fn::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
+ AttributeDomain domain) const;
- /* Get a virtual array to read data of an attribute with the given data type. The domain is
- * left unchanged. Returns null when the attribute does not exist or cannot be converted to the
- * requested data type. */
+ /**
+ * Get a virtual array that refers to the data of an attribute converted to the given data type.
+ * The attribute's domain is left unchanged. Returns null when the attribute does not exist or
+ * cannot be converted.
+ */
blender::bke::ReadAttributeLookup attribute_try_get_for_read(
const blender::bke::AttributeIDRef &attribute_id, const CustomDataType data_type) const;
- /* Get a virtual array to read the data of an attribute. If that is not possible, the returned
- * virtual array will contain a default value. This never returns null. */
- std::unique_ptr<blender::fn::GVArray> attribute_get_for_read(
- const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value = nullptr) const;
-
- /* Should be used instead of the method above when the requested data type is known at compile
- * time for better type safety. */
+ /**
+ * Get a virtual array that refers to the data of an attribute, interpolated to the given domain
+ * and converted to the data type. If that is not possible, the returned virtual array will
+ * contain a default value. This never returns null.
+ */
+ blender::fn::GVArray attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
+ AttributeDomain domain,
+ const CustomDataType data_type,
+ const void *default_value = nullptr) const;
+ /* Use instead of the method above when the type is known at compile time for type safety. */
template<typename T>
- blender::fn::GVArray_Typed<T> attribute_get_for_read(
- const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const T &default_value) const
+ blender::VArray<T> attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
+ const AttributeDomain domain,
+ const T &default_value) const
{
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- std::unique_ptr varray = this->attribute_get_for_read(
- attribute_id, domain, type, &default_value);
- return blender::fn::GVArray_Typed<T>(std::move(varray));
+ return this->attribute_get_for_read(attribute_id, domain, type, &default_value)
+ .template typed<T>();
}
/**
@@ -198,19 +243,10 @@ class GeometryComponent {
*/
blender::bke::OutputAttribute attribute_try_get_for_output(
const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain,
+ AttributeDomain domain,
const CustomDataType data_type,
const void *default_value = nullptr);
-
- /* Same as attribute_try_get_for_output, but should be used when the original values in the
- * attributes are not read, i.e. the attribute is used only for output. Since values are not read
- * from this attribute, no default value is necessary. */
- blender::bke::OutputAttribute attribute_try_get_for_output_only(
- const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type);
-
- /* Statically typed method corresponding to the equally named generic one. */
+ /* Use instead of the method above when the type is known at compile time for type safety. */
template<typename T>
blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output(
const blender::bke::AttributeIDRef &attribute_id,
@@ -222,7 +258,17 @@ class GeometryComponent {
return this->attribute_try_get_for_output(attribute_id, domain, data_type, &default_value);
}
- /* Statically typed method corresponding to the equally named generic one. */
+ /**
+ * Same as #attribute_try_get_for_output, but should be used when the original values in the
+ * attributes are not read, i.e. the attribute is used only for output. The can be faster because
+ * it can avoid interpolation and conversion of existing values. Since values are not read from
+ * this attribute, no default value is necessary.
+ */
+ blender::bke::OutputAttribute attribute_try_get_for_output_only(
+ const blender::bke::AttributeIDRef &attribute_id,
+ AttributeDomain domain,
+ const CustomDataType data_type);
+ /* Use instead of the method above when the type is known at compile time for type safety. */
template<typename T>
blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output_only(
const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain)
@@ -234,25 +280,54 @@ class GeometryComponent {
private:
virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const;
+
+ virtual blender::fn::GVArray attribute_try_adapt_domain_impl(const blender::fn::GVArray &varray,
+ AttributeDomain from_domain,
+ AttributeDomain to_domain) const;
};
template<typename T>
inline constexpr bool is_geometry_component_v = std::is_base_of_v<GeometryComponent, T>;
/**
- * A geometry set contains zero or more geometry components. There is at most one component of each
- * type. Individual components might be shared between multiple geometries. Shared components are
- * copied automatically when write access is requested.
+ * A geometry set is a container for multiple kinds of geometry. It does not own geometry directly
+ * itself, instead geometry is owned by multiple #GeometryComponents, and the geometry set
+ * increases the user count of each component, so they avoid losing the data. This means
+ * individual components might be shared between multiple geometries and other code. Shared
+ * components are copied automatically when write access is requested.
+ *
+ * The components usually do not store data directly, but keep a reference to a data
+ * structure defined elsewhere. There is at most one component of each type:
+ * - #MeshComponent
+ * - #CurveComponent
+ * - #PointCloudComponent
+ * - #InstancesComponent
+ * - #VolumeComponent
*
* Copying a geometry set is a relatively cheap operation, because it does not copy the referenced
- * geometry components.
+ * geometry components, so #GeometrySet can often be passed or moved by value.
*/
struct GeometrySet {
private:
using GeometryComponentPtr = blender::UserCounter<class GeometryComponent>;
- blender::Map<GeometryComponentType, GeometryComponentPtr> components_;
+ /* Indexed by #GeometryComponentType. */
+ std::array<GeometryComponentPtr, GEO_COMPONENT_TYPE_ENUM_SIZE> components_;
public:
+ /**
+ * The methods are defaulted here so that they are not instantiated in every translation unit.
+ */
+ GeometrySet();
+ GeometrySet(const GeometrySet &other);
+ GeometrySet(GeometrySet &&other);
+ ~GeometrySet();
+ GeometrySet &operator=(const GeometrySet &other);
+ GeometrySet &operator=(GeometrySet &&other);
+
+ /**
+ * This method can only be used when the geometry set is mutable. It returns a mutable geometry
+ * component of the given type.
+ */
GeometryComponent &get_component_for_write(GeometryComponentType component_type);
template<typename Component> Component &get_component_for_write()
{
@@ -260,6 +335,9 @@ struct GeometrySet {
return static_cast<Component &>(this->get_component_for_write(Component::static_type));
}
+ /**
+ * Get the component of the given type. Might return null if the component does not exist yet.
+ */
const GeometryComponent *get_component_for_read(GeometryComponentType component_type) const;
template<typename Component> const Component *get_component_for_read() const
{
@@ -281,19 +359,33 @@ struct GeometrySet {
return this->remove(Component::static_type);
}
+ /**
+ * Remove all geometry components with types that are not in the provided list.
+ */
void keep_only(const blender::Span<GeometryComponentType> component_types);
void add(const GeometryComponent &component);
+ /**
+ * Get all geometry components in this geometry set for read-only access.
+ */
blender::Vector<const GeometryComponent *> get_components_for_read() const;
- void compute_boundbox_without_instances(blender::float3 *r_min, blender::float3 *r_max) const;
+ bool compute_boundbox_without_instances(blender::float3 *r_min, blender::float3 *r_max) const;
friend std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set);
+ /**
+ * Remove all geometry components from the geometry set.
+ */
void clear();
bool owns_direct_data() const;
+ /**
+ * Make sure that the geometry can be cached. This does not ensure ownership of object/collection
+ * instances. This is necessary because sometimes components only have read-only or editing
+ * access to their data, which might be freed later if this geometry set outlasts the data.
+ */
void ensure_owns_direct_data();
using AttributeForeachCallback =
@@ -311,48 +403,139 @@ struct GeometrySet {
bool include_instances,
blender::Map<blender::bke::AttributeIDRef, AttributeKind> &r_attributes) const;
+ blender::Vector<GeometryComponentType> gather_component_types(bool include_instances,
+ bool ignore_empty) const;
+
using ForeachSubGeometryCallback = blender::FunctionRef<void(GeometrySet &geometry_set)>;
+ /**
+ * Modify every (recursive) instance separately. This is often more efficient than realizing all
+ * instances just to change the same thing on all of them.
+ */
void modify_geometry_sets(ForeachSubGeometryCallback callback);
/* Utility methods for creation. */
+ /**
+ * Create a new geometry set that only contains the given mesh.
+ */
static GeometrySet create_with_mesh(
Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Create a new geometry set that only contains the given point cloud.
+ */
static GeometrySet create_with_pointcloud(
PointCloud *pointcloud, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Create a new geometry set that only contains the given curve.
+ */
static GeometrySet create_with_curve(
CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/* Utility methods for access. */
+ /**
+ * Returns true when the geometry set has a mesh component that has a mesh.
+ */
bool has_mesh() const;
+ /**
+ * Returns true when the geometry set has a point cloud component that has a point cloud.
+ */
bool has_pointcloud() const;
+ /**
+ * Returns true when the geometry set has an instances component that has at least one instance.
+ */
bool has_instances() const;
+ /**
+ * Returns true when the geometry set has a volume component that has a volume.
+ */
bool has_volume() const;
+ /**
+ * Returns true when the geometry set has a curve component that has a curve.
+ */
bool has_curve() const;
+ /**
+ * Returns true when the geometry set has any data that is not an instance.
+ */
bool has_realized_data() const;
+ /**
+ * Return true if the geometry set has any component that isn't empty.
+ */
bool is_empty() const;
+ /**
+ * Returns a read-only mesh or null.
+ */
const Mesh *get_mesh_for_read() const;
+ /**
+ * Returns a read-only point cloud of null.
+ */
const PointCloud *get_pointcloud_for_read() const;
+ /**
+ * Returns a read-only volume or null.
+ */
const Volume *get_volume_for_read() const;
+ /**
+ * Returns a read-only curve or null.
+ */
const CurveEval *get_curve_for_read() const;
+ /**
+ * Returns a mutable mesh or null. No ownership is transferred.
+ */
Mesh *get_mesh_for_write();
+ /**
+ * Returns a mutable point cloud or null. No ownership is transferred.
+ */
PointCloud *get_pointcloud_for_write();
+ /**
+ * Returns a mutable volume or null. No ownership is transferred.
+ */
Volume *get_volume_for_write();
+ /**
+ * Returns a mutable curve or null. No ownership is transferred.
+ */
CurveEval *get_curve_for_write();
/* Utility methods for replacement. */
+ /**
+ * Clear the existing mesh and replace it with the given one.
+ */
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Clear the existing point cloud and replace with the given one.
+ */
void replace_pointcloud(PointCloud *pointcloud,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Clear the existing volume and replace with the given one.
+ */
void replace_volume(Volume *volume,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Clear the existing curve and replace it with the given one.
+ */
void replace_curve(CurveEval *curve,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+
+ private:
+ /**
+ * Retrieve the pointer to a component without creating it if it does not exist,
+ * unlike #get_component_for_write.
+ */
+ GeometryComponent *get_component_ptr(GeometryComponentType type);
+ template<typename Component> Component *get_component_ptr()
+ {
+ BLI_STATIC_ASSERT(is_geometry_component_v<Component>, "");
+ return static_cast<Component *>(get_component_ptr(Component::static_type));
+ }
};
-/** A geometry component that can store a mesh. */
+/**
+ * A geometry component that can store a mesh, storing the #Mesh data structure.
+ *
+ * Attributes are stored in the mesh itself, on any of the four attribute domains. Generic
+ * attributes are stored in contiguous arrays, but often built-in attributes are stored in an
+ * array of structs fashion for historical reasons, requiring more complex attribute access.
+ */
class MeshComponent : public GeometryComponent {
private:
Mesh *mesh_ = nullptr;
@@ -365,17 +548,28 @@ class MeshComponent : public GeometryComponent {
void clear();
bool has_mesh() const;
+ /**
+ * Clear the component and replace it with the new mesh.
+ */
void replace(Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Return the mesh and clear the component. The caller takes over responsibility for freeing the
+ * mesh (if the component was responsible before).
+ */
Mesh *release();
+ /**
+ * Get the mesh from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned mesh should not be modified. No ownership is transferred.
+ */
const Mesh *get_for_read() const;
+ /**
+ * Get the mesh from this component. This method can only be used when the component is mutable,
+ * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred.
+ */
Mesh *get_for_write();
- int attribute_domain_size(const AttributeDomain domain) const final;
- std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain(
- std::unique_ptr<blender::fn::GVArray> varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const final;
+ int attribute_domain_size(AttributeDomain domain) const final;
bool is_empty() const final;
@@ -386,9 +580,22 @@ class MeshComponent : public GeometryComponent {
private:
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
+
+ blender::fn::GVArray attribute_try_adapt_domain_impl(const blender::fn::GVArray &varray,
+ AttributeDomain from_domain,
+ AttributeDomain to_domain) const final;
};
-/** A geometry component that stores a point cloud. */
+/**
+ * A geometry component that stores a point cloud, corresponding to the #PointCloud data structure.
+ * While a point cloud is technically a subset of a mesh in some respects, it is useful because of
+ * its simplicity, partly on a conceptual level for the user, but also in the code, though partly
+ * for historical reasons. Point clouds can also be rendered in special ways, based on the built-in
+ * `radius` attribute.
+ *
+ * Attributes on point clouds are all stored in contiguous arrays in its #CustomData,
+ * which makes them efficient to process, relative to some legacy built-in mesh attributes.
+ */
class PointCloudComponent : public GeometryComponent {
private:
PointCloud *pointcloud_ = nullptr;
@@ -401,14 +608,31 @@ class PointCloudComponent : public GeometryComponent {
void clear();
bool has_pointcloud() const;
+ /**
+ * Clear the component and replace it with the new point cloud.
+ */
void replace(PointCloud *pointcloud,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Return the point cloud and clear the component. The caller takes over responsibility for
+ * freeing the point cloud (if the component was responsible before).
+ */
PointCloud *release();
+ /**
+ * Get the point cloud from this component. This method can be used by multiple threads at the
+ * same time. Therefore, the returned point cloud should not be modified. No ownership is
+ * transferred.
+ */
const PointCloud *get_for_read() const;
+ /**
+ * Get the point cloud from this component. This method can only be used when the component is
+ * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is
+ * transferred.
+ */
PointCloud *get_for_write();
- int attribute_domain_size(const AttributeDomain domain) const final;
+ int attribute_domain_size(AttributeDomain domain) const final;
bool is_empty() const final;
@@ -421,7 +645,13 @@ class PointCloudComponent : public GeometryComponent {
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
};
-/** A geometry component that stores curve data, in other words, a group of splines. */
+/**
+ * A geometry component that stores curve data, in other words, a group of splines.
+ * Curves are stored differently than other geometry components, because the data structure used
+ * here does not correspond exactly to the #Curve DNA data structure. A #CurveEval is stored here
+ * instead, though the component does give access to a #Curve for interfacing with render engines
+ * and other areas of Blender that expect to use a data-block with an #ID.
+ */
class CurveComponent : public GeometryComponent {
private:
CurveEval *curve_ = nullptr;
@@ -443,31 +673,42 @@ class CurveComponent : public GeometryComponent {
void clear();
bool has_curve() const;
+ /**
+ * Clear the component and replace it with the new curve.
+ */
void replace(CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
CurveEval *release();
const CurveEval *get_for_read() const;
CurveEval *get_for_write();
- int attribute_domain_size(const AttributeDomain domain) const final;
- std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain(
- std::unique_ptr<blender::fn::GVArray> varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const final;
+ int attribute_domain_size(AttributeDomain domain) const final;
bool is_empty() const final;
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
+ /**
+ * Create empty curve data used for rendering the spline's wire edges.
+ * \note See comment on #curve_for_render_ for further explanation.
+ */
const Curve *get_curve_for_render() const;
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE;
private:
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
+
+ blender::fn::GVArray attribute_try_adapt_domain_impl(const blender::fn::GVArray &varray,
+ AttributeDomain from_domain,
+ AttributeDomain to_domain) const final;
};
+/**
+ * Holds a reference to conceptually unique geometry or a pointer to object/collection data
+ * that is is instanced with a transform in #InstancesComponent.
+ */
class InstanceReference {
public:
enum class Type {
@@ -590,7 +831,19 @@ class InstanceReference {
}
};
-/** A geometry component that stores instances. */
+/**
+ * A geometry component that stores instances. The instance data can be any type described by
+ * #InstanceReference. Geometry instances can even contain instances themselves, for nested
+ * instancing. Each instance has an index into an array of unique instance data, and a transform.
+ * The component can also store generic attributes for each instance.
+ *
+ * The component works differently from other geometry components in that it stores
+ * data about instancing directly, rather than owning a pointer to a separate data structure.
+ *
+ * This component is not responsible for handling the interface to a render engine, or other
+ * areas that work with all visible geometry, that is handled by the dependency graph iterator
+ * (see `DEG_depsgraph_query.h`).
+ */
class InstancesComponent : public GeometryComponent {
private:
/**
@@ -603,19 +856,16 @@ class InstancesComponent : public GeometryComponent {
blender::Vector<int> instance_reference_handles_;
/** Transformation of the instances. */
blender::Vector<blender::float4x4> instance_transforms_;
- /**
- * IDs of the instances. They are used for consistency over multiple frames for things like
- * motion blur.
- */
- blender::Vector<int> instance_ids_;
- /* These almost unique ids are generated based on `ids_`, which might not contain unique ids at
- * all. They are *almost* unique, because under certain very unlikely circumstances, they are not
- * unique. Code using these ids should not crash when they are not unique but can generally
- * expect them to be unique. */
+ /* These almost unique ids are generated based on the `id` attribute, which might not contain
+ * unique ids at all. They are *almost* unique, because under certain very unlikely
+ * circumstances, they are not unique. Code using these ids should not crash when they are not
+ * unique but can generally expect them to be unique. */
mutable std::mutex almost_unique_ids_mutex_;
mutable blender::Array<int> almost_unique_ids_;
+ blender::bke::CustomDataAttributes attributes_;
+
public:
InstancesComponent();
~InstancesComponent() = default;
@@ -624,30 +874,63 @@ class InstancesComponent : public GeometryComponent {
void clear();
void reserve(int min_capacity);
+ /**
+ * Resize the transform, handles, and attributes to the specified capacity.
+ *
+ * \note This function should be used carefully, only when it's guaranteed
+ * that the data will be filled.
+ */
void resize(int capacity);
+ /**
+ * Returns a handle for the given reference.
+ * If the reference exists already, the handle of the existing reference is returned.
+ * Otherwise a new handle is added.
+ */
int add_reference(const InstanceReference &reference);
- void add_instance(int instance_handle, const blender::float4x4 &transform, const int id = -1);
+ /**
+ * Add a reference to the instance reference with an index specified by the #instance_handle
+ * argument. For adding many instances, using #resize and accessing the transform array directly
+ * is preferred.
+ */
+ void add_instance(int instance_handle, const blender::float4x4 &transform);
blender::Span<InstanceReference> references() const;
void remove_unused_references();
+ /**
+ * If references have a collection or object type, convert them into geometry instances
+ * recursively. After that, the geometry sets can be edited. There may still be instances of
+ * other types of they can't be converted to geometry sets.
+ */
void ensure_geometry_instances();
- GeometrySet &geometry_set_from_reference(const int reference_index);
+ /**
+ * With write access to the instances component, the data in the instanced geometry sets can be
+ * changed. This is a function on the component rather than each reference to ensure `const`
+ * correctness for that reason.
+ */
+ GeometrySet &geometry_set_from_reference(int reference_index);
blender::Span<int> instance_reference_handles() const;
blender::MutableSpan<int> instance_reference_handles();
blender::MutableSpan<blender::float4x4> instance_transforms();
blender::Span<blender::float4x4> instance_transforms() const;
- blender::MutableSpan<int> instance_ids();
- blender::Span<int> instance_ids() const;
int instances_amount() const;
int references_amount() const;
+ /**
+ * Remove the indices that are not contained in the mask input, and remove unused instance
+ * references afterwards.
+ */
+ void remove_instances(const blender::IndexMask mask);
+
blender::Span<int> almost_unique_ids() const;
- int attribute_domain_size(const AttributeDomain domain) const final;
+ blender::bke::CustomDataAttributes &attributes();
+ const blender::bke::CustomDataAttributes &attributes() const;
+
+ int attribute_domain_size(AttributeDomain domain) const final;
void foreach_referenced_geometry(
blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const;
@@ -663,7 +946,11 @@ class InstancesComponent : public GeometryComponent {
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
};
-/** A geometry component that stores volume grids. */
+/**
+ * A geometry component that stores volume grids, corresponding to the #Volume data structure.
+ * This component does not implement an attribute API, partly because storage of sparse volume
+ * information in grids is much more complicated than it is for other types
+ */
class VolumeComponent : public GeometryComponent {
private:
Volume *volume_ = nullptr;
@@ -676,10 +963,26 @@ class VolumeComponent : public GeometryComponent {
void clear();
bool has_volume() const;
+ /**
+ * Clear the component and replace it with the new volume.
+ */
void replace(Volume *volume, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Return the volume and clear the component. The caller takes over responsibility for freeing
+ * the volume (if the component was responsible before).
+ */
Volume *release();
+ /**
+ * Get the volume from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned volume should not be modified. No ownership is transferred.
+ */
const Volume *get_for_read() const;
+ /**
+ * Get the volume from this component. This method can only be used when the component is
+ * mutable, i.e. it is not shared. The returned volume can be modified. No ownership is
+ * transferred.
+ */
Volume *get_for_write();
bool owns_direct_data() const override;
@@ -712,14 +1015,28 @@ class GeometryComponentFieldContext : public fn::FieldContext {
}
};
-class AttributeFieldInput : public fn::FieldInput {
+class GeometryFieldInput : public fn::FieldInput {
+ public:
+ using fn::FieldInput::FieldInput;
+
+ GVArray get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope &scope) const override;
+
+ virtual GVArray get_varray_for_context(const GeometryComponent &component,
+ AttributeDomain domain,
+ IndexMask mask) const = 0;
+};
+
+class AttributeFieldInput : public GeometryFieldInput {
private:
std::string name_;
public:
AttributeFieldInput(std::string name, const CPPType &type)
- : fn::FieldInput(type, name), name_(std::move(name))
+ : GeometryFieldInput(type, name), name_(std::move(name))
{
+ category_ = Category::NamedAttribute;
}
template<typename T> static fn::Field<T> Create(std::string name)
@@ -734,9 +1051,26 @@ class AttributeFieldInput : public fn::FieldInput {
return name_;
}
- const GVArray *get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const override;
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ AttributeDomain domain,
+ IndexMask mask) const override;
+
+ std::string socket_inspection_name() const override;
+
+ uint64_t hash() const override;
+ bool is_equal_to(const fn::FieldNode &other) const override;
+};
+
+class IDAttributeFieldInput : public GeometryFieldInput {
+ public:
+ IDAttributeFieldInput() : GeometryFieldInput(CPPType::get<int>())
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ AttributeDomain domain,
+ IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -744,31 +1078,62 @@ class AttributeFieldInput : public fn::FieldInput {
bool is_equal_to(const fn::FieldNode &other) const override;
};
-class AnonymousAttributeFieldInput : public fn::FieldInput {
+VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain);
+
+VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
+ const Mesh &mesh,
+ const IndexMask mask,
+ const AttributeDomain domain);
+
+class NormalFieldInput : public GeometryFieldInput {
+ public:
+ NormalFieldInput() : GeometryFieldInput(CPPType::get<float3>())
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const override;
+
+ std::string socket_inspection_name() const override;
+
+ uint64_t hash() const override;
+ bool is_equal_to(const fn::FieldNode &other) const override;
+};
+
+class AnonymousAttributeFieldInput : public GeometryFieldInput {
private:
/**
* A strong reference is required to make sure that the referenced attribute is not removed
* automatically.
*/
StrongAnonymousAttributeID anonymous_id_;
+ std::string producer_name_;
public:
- AnonymousAttributeFieldInput(StrongAnonymousAttributeID anonymous_id, const CPPType &type)
- : fn::FieldInput(type, anonymous_id.debug_name()), anonymous_id_(std::move(anonymous_id))
+ AnonymousAttributeFieldInput(StrongAnonymousAttributeID anonymous_id,
+ const CPPType &type,
+ std::string producer_name)
+ : GeometryFieldInput(type, anonymous_id.debug_name()),
+ anonymous_id_(std::move(anonymous_id)),
+ producer_name_(producer_name)
{
+ category_ = Category::AnonymousAttribute;
}
- template<typename T> static fn::Field<T> Create(StrongAnonymousAttributeID anonymous_id)
+ template<typename T>
+ static fn::Field<T> Create(StrongAnonymousAttributeID anonymous_id, std::string producer_name)
{
const CPPType &type = CPPType::get<T>();
- auto field_input = std::make_shared<AnonymousAttributeFieldInput>(std::move(anonymous_id),
- type);
+ auto field_input = std::make_shared<AnonymousAttributeFieldInput>(
+ std::move(anonymous_id), type, std::move(producer_name));
return fn::Field<T>{field_input};
}
- const GVArray *get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const override;
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ AttributeDomain domain,
+ IndexMask mask) const override;
std::string socket_inspection_name() const override;
diff --git a/source/blender/blenkernel/BKE_geometry_set_instances.hh b/source/blender/blenkernel/BKE_geometry_set_instances.hh
index 653450c7d8e..98120b07f2d 100644
--- a/source/blender/blenkernel/BKE_geometry_set_instances.hh
+++ b/source/blender/blenkernel/BKE_geometry_set_instances.hh
@@ -21,6 +21,11 @@
namespace blender::bke {
/**
+ * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
+ */
+GeometrySet object_get_evaluated_geometry_set(const Object &object);
+
+/**
* Used to keep track of a group of instances using the same geometry data.
*/
struct GeometryInstanceGroup {
@@ -39,12 +44,19 @@ struct GeometryInstanceGroup {
Vector<float4x4> transforms;
};
+/**
+ * Return flattened vector of the geometry component's recursive instances. I.e. all collection
+ * instances and object instances will be expanded into the instances of their geometry components.
+ * Even the instances in those geometry components' will be included.
+ *
+ * \note For convenience (to avoid duplication in the caller), the returned vector also contains
+ * the argument geometry set.
+ *
+ * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
+ */
void geometry_set_gather_instances(const GeometrySet &geometry_set,
Vector<GeometryInstanceGroup> &r_instance_groups);
-GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set);
-GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set);
-
/**
* Add information about all the attributes on every component of the type. The resulting info
* will contain the highest complexity data type and the highest priority domain among every
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 7696b5c0189..0c17636be03 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -37,36 +37,61 @@ struct Main;
typedef struct Global {
- /** Active pointers. */
+ /**
+ * Data for the current active blend file.
+ *
+ * Note that `CTX_data_main(C)` should be used where possible.
+ * Otherwise access via #G_MAIN.
+ */
struct Main *main;
- /** Strings: last saved */
- char ima[1024], lib[1024]; /* 1024 = FILE_MAX */
-
- /** When set: `G_MAIN->name` contains valid relative base path. */
- bool relbase_valid;
- bool file_loaded;
- bool save_over;
+ /** Last saved location for images. */
+ char ima[1024]; /* 1024 = FILE_MAX */
+ /** Last used location for library link/append. */
+ char lib[1024];
- /** Strings of recent opened files. */
+ /**
+ * Strings of recently opened files to show in the file menu.
+ * A list of #RecentFile read from #BLENDER_HISTORY_FILE.
+ */
struct ListBase recent_files;
- /** Has escape been pressed or Ctrl+C pressed in background mode, used for render quit. */
+ /**
+ * Set when Escape been pressed or `Ctrl-C` pressed in background mode.
+ * Used for render quit and some other background tasks such as baking.
+ */
bool is_break;
+ /**
+ * Blender is running without any Windows or OpenGLES context.
+ * Typically set by the `--background` command-line argument.
+ *
+ * Also enabled when build defines `WITH_PYTHON_MODULE` or `WITH_HEADLESS` are set
+ * (which use background mode by definition).
+ */
bool background;
+
+ /**
+ * Skip reading the startup file and user preferences.
+ * Also disable saving the preferences on exit (see #G_FLAG_USERPREF_NO_SAVE_ON_EXIT),
+ * see via the command line argument: `--factory-startup`.
+ */
bool factory_startup;
+ /**
+ * Set when the user is interactively moving (transforming) content.
+ * see: #G_TRANSFORM_OBJ and related flags.
+ */
short moving;
- /** To indicate render is busy, prevent render-window events etc. */
+ /** To indicate render is busy, prevent render-window events, animation playback etc. */
bool is_rendering;
/**
* Debug value, can be set from the UI and python, used for testing nonstandard features.
* DO NOT abuse it with generic checks like `if (G.debug_value > 0)`. Do not use it as bitflags.
* Only precise specific values should be checked for, to avoid unpredictable side-effects.
- * Please document here the value(s) you are using (or a range of values reserved to some area).
+ * Please document here the value(s) you are using (or a range of values reserved to some area):
* * -16384 and below: Reserved for python (add-ons) usage.
* * -1: Disable faster motion paths computation (since 08/2018).
* * 1 - 30: EEVEE debug/stats values (01/2018).
@@ -79,28 +104,55 @@ typedef struct Global {
* * 1234: Disable new dyntopo code fixing skinny faces generation (04/2015).
* * 3001: Enable additional Fluid modifier (Mantaflow) options (02/2020).
* * 4000: Line Art state output and debugging logs (03/2021).
+ * * 4001: Mesh topology information in the spreadsheet (01/2022).
* * 16384 and above: Reserved for python (add-ons) usage.
*/
short debug_value;
- /** Saved to the blend file as #FileGlobal.globalf,
- * however this is now only used for runtime options. */
+ /**
+ * Saved to the blend file as #FileGlobal.globalf
+ *
+ * \note Currently this is only used for runtime options, adding flags to #G_FLAG_ALL_READFILE
+ * will cause them to be written and read to files.
+ */
int f;
struct {
- /** Logging vars (different loggers may use). */
+ /**
+ * Logging vars (different loggers may use).
+ * Set via `--log-level` command line argument.
+ */
int level;
- /** FILE handle or use stderr (we own this so close when done). */
+ /**
+ * FILE handle or use `stderr` (we own this so close when done).
+ * Set via `--log-file` command line argument.
+ */
void *file;
} log;
- /** debug flag, #G_DEBUG, #G_DEBUG_PYTHON & friends, set python or command line args */
+ /**
+ * Debug flag, #G_DEBUG, #G_DEBUG_PYTHON & friends, set via:
+ * - Command line arguments: `--debug`, `--debug-memory` ... etc.
+ * - Python API: `bpy.app.debug`, `bpy.app.debug_memory` ... etc.
+ */
int debug;
- /** This variable is written to / read from #FileGlobal.fileflags */
+ /**
+ * Control behavior of file reading/writing.
+ *
+ * This variable is written to / read from #FileGlobal.fileflags.
+ * See: #G_FILE_COMPRESS and related flags.
+ */
int fileflags;
- /** Message to use when auto execution fails. */
+ /**
+ * Message to show when loading a `.blend` file attempts to execute
+ * a Python script or driver-expression when doing so is disallowed.
+ *
+ * Set when `(G.f & G_FLAG_SCRIPT_AUTOEXEC_FAIL) == 0`,
+ * so users can be alerted to the reason why the file may not be behaving as expected.
+ * Typically Python drivers.
+ */
char autoexec_fail[200];
} Global;
@@ -211,6 +263,12 @@ enum {
G_TRANSFORM_SEQ = (1 << 2),
G_TRANSFORM_FCURVES = (1 << 3),
G_TRANSFORM_WM = (1 << 4),
+ /**
+ * Set when transforming the cursor itself.
+ * Used as a hint to draw the cursor (even when hidden).
+ * Otherwise it's not possible to see what's being transformed.
+ */
+ G_TRANSFORM_CURSOR = (1 << 5),
};
/** Defined in blender.c */
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index b58317f4815..885d0c2fd90 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -86,90 +86,244 @@ struct bGPdata;
/* ------------ Grease-Pencil API ------------------ */
+/* clean vertex groups weights */
void BKE_gpencil_free_point_weights(struct MDeformVert *dvert);
void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps);
void BKE_gpencil_free_stroke_editcurve(struct bGPDstroke *gps);
+/* free stroke, doesn't unlink from any listbase */
void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
+/* Free strokes belonging to a gp-frame */
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
+/* Free all of a gp-layer's frames */
void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
+/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
void BKE_gpencil_free_layers(struct ListBase *list);
+/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
void BKE_gpencil_free_data(struct bGPdata *gpd, bool free_all);
+/**
+ * Delete grease pencil evaluated data
+ * \param gpd_eval: Grease pencil data-block
+ */
void BKE_gpencil_eval_delete(struct bGPdata *gpd_eval);
void BKE_gpencil_free_layer_masks(struct bGPDlayer *gpl);
+/**
+ * Tag data-block for depsgraph update.
+ * Wrapper to avoid include Depsgraph tag functions in other modules.
+ * \param gpd: Grease pencil data-block.
+ */
void BKE_gpencil_tag(struct bGPdata *gpd);
void BKE_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd);
void BKE_gpencil_batch_cache_free(struct bGPdata *gpd);
+/**
+ * Ensure selection status of stroke is in sync with its points.
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_sync_selection(struct bGPdata *gpd, struct bGPDstroke *gps);
void BKE_gpencil_curve_sync_selection(struct bGPdata *gpd, struct bGPDstroke *gps);
+/* Assign unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_set(struct bGPdata *gpd, struct bGPDstroke *gps);
+/* Reset unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_reset(struct bGPDstroke *gps);
+/**
+ * Add a new gp-frame to the given layer.
+ * \param gpl: Grease pencil layer
+ * \param cframe: Frame number
+ * \return Pointer to new frame
+ */
struct bGPDframe *BKE_gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
+/**
+ * Add a copy of the active gp-frame to the given layer.
+ * \param gpl: Grease pencil layer
+ * \param cframe: Frame number
+ * \return Pointer to new frame
+ */
struct bGPDframe *BKE_gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
+/**
+ * Add a new gp-layer and make it the active layer.
+ * \param gpd: Grease pencil data-block
+ * \param name: Name of the layer
+ * \param setactive: Set as active
+ * \param add_to_header: Used to force the layer added at header
+ * \return Pointer to new layer
+ */
struct bGPDlayer *BKE_gpencil_layer_addnew(struct bGPdata *gpd,
const char *name,
- const bool setactive,
- const bool add_to_header);
+ bool setactive,
+ bool add_to_header);
+/**
+ * Add a new grease pencil data-block.
+ * \param bmain: Main pointer
+ * \param name: Name of the datablock
+ * \return Pointer to new data-block
+ */
struct bGPdata *BKE_gpencil_data_addnew(struct Main *bmain, const char name[]);
-struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src,
- const bool dup_strokes);
+/**
+ * Make a copy of a given gpencil frame.
+ * \param gpf_src: Source grease pencil frame
+ * \return Pointer to new frame
+ */
+struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src, bool dup_strokes);
+/**
+ * Make a copy of a given gpencil layer.
+ * \param gpl_src: Source grease pencil layer
+ * \return Pointer to new layer
+ */
struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src,
- const bool dup_frames,
- const bool dup_strokes);
+ bool dup_frames,
+ bool dup_strokes);
+/**
+ * Make a copy of a given gpencil layer settings.
+ */
void BKE_gpencil_layer_copy_settings(const struct bGPDlayer *gpl_src, struct bGPDlayer *gpl_dst);
+/**
+ * Make a copy of strokes between gpencil frames.
+ * \param gpf_src: Source grease pencil frame
+ * \param gpf_dst: Destination grease pencil frame
+ */
void BKE_gpencil_frame_copy_strokes(struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst);
+/* Create a hash with the list of selected frame number. */
void BKE_gpencil_frame_selected_hash(struct bGPdata *gpd, struct GHash *r_list);
+/* Make a copy of a given gpencil stroke editcurve */
struct bGPDcurve *BKE_gpencil_stroke_curve_duplicate(struct bGPDcurve *gpc_src);
+/**
+ * Make a copy of a given grease-pencil stroke.
+ * \param gps_src: Source grease pencil strokes.
+ * \param dup_points: Duplicate points data.
+ * \param dup_curve: Duplicate curve data.
+ * \return Pointer to new stroke.
+ */
struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src,
- const bool dup_points,
- const bool dup_curve);
+ bool dup_points,
+ bool dup_curve);
+/**
+ * Make a copy of a given gpencil data-block.
+ *
+ * XXX: Should this be deprecated?
+ */
struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain,
const struct bGPdata *gpd,
bool internal_copy);
+/**
+ * Delete the last stroke of the given frame.
+ * \param gpl: Grease pencil layer
+ * \param gpf: Grease pencil frame
+ */
void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
/* materials */
+/**
+ * Reassign strokes using a material.
+ * \param gpd: Grease pencil data-block
+ * \param totcol: Total materials
+ * \param index: Index of the material
+ */
void BKE_gpencil_material_index_reassign(struct bGPdata *gpd, int totcol, int index);
+/**
+ * Remove strokes using a material.
+ * \param gpd: Grease pencil data-block
+ * \param index: Index of the material
+ * \return True if removed
+ */
bool BKE_gpencil_material_index_used(struct bGPdata *gpd, int index);
+/**
+ * Remap material
+ * \param gpd: Grease pencil data-block
+ * \param remap: Remap index
+ * \param remap_len: Remap length
+ */
void BKE_gpencil_material_remap(struct bGPdata *gpd,
const unsigned int *remap,
unsigned int remap_len);
+/**
+ * Load a table with material conversion index for merged materials.
+ * \param ob: Grease pencil object.
+ * \param hue_threshold: Threshold for Hue.
+ * \param sat_threshold: Threshold for Saturation.
+ * \param val_threshold: Threshold for Value.
+ * \param r_mat_table: return material table.
+ * \return True if done.
+ */
bool BKE_gpencil_merge_materials_table_get(struct Object *ob,
- const float hue_threshold,
- const float sat_threshold,
- const float val_threshold,
+ float hue_threshold,
+ float sat_threshold,
+ float val_threshold,
struct GHash *r_mat_table);
+/**
+ * Merge similar materials
+ * \param ob: Grease pencil object
+ * \param hue_threshold: Threshold for Hue
+ * \param sat_threshold: Threshold for Saturation
+ * \param val_threshold: Threshold for Value
+ * \param r_removed: Number of materials removed
+ * \return True if done
+ */
bool BKE_gpencil_merge_materials(struct Object *ob,
- const float hue_threshold,
- const float sat_threshold,
- const float val_threshold,
+ float hue_threshold,
+ float sat_threshold,
+ float val_threshold,
int *r_removed);
/* statistics functions */
+/**
+ * Calc grease pencil statistics functions.
+ * \param gpd: Grease pencil data-block
+ */
void BKE_gpencil_stats_update(struct bGPdata *gpd);
+/**
+ * Create a new stroke, with pre-allocated data buffers.
+ * \param mat_idx: Index of the material
+ * \param totpoints: Total points
+ * \param thickness: Stroke thickness
+ * \return Pointer to new stroke
+ */
struct bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness);
+/**
+ * Create a new stroke and add to frame.
+ * \param gpf: Grease pencil frame
+ * \param mat_idx: Material index
+ * \param totpoints: Total points
+ * \param thickness: Stroke thickness
+ * \param insert_at_head: Add to the head of the strokes list
+ * \return Pointer to new stroke
+ */
struct bGPDstroke *BKE_gpencil_stroke_add(
- struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness, const bool insert_at_head);
-
+ struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness, bool insert_at_head);
+
+/**
+ * Add a stroke and copy the temporary drawing color value
+ * from one of the existing stroke.
+ * \param gpf: Grease pencil frame
+ * \param existing: Stroke with the style to copy
+ * \param mat_idx: Material index
+ * \param totpoints: Total points
+ * \param thickness: Stroke thickness
+ * \return Pointer to new stroke
+ */
struct bGPDstroke *BKE_gpencil_stroke_add_existing_style(struct bGPDframe *gpf,
struct bGPDstroke *existing,
int mat_idx,
int totpoints,
short thickness);
-struct bGPDcurve *BKE_gpencil_stroke_editcurve_new(const int tot_curve_points);
+struct bGPDcurve *BKE_gpencil_stroke_editcurve_new(int tot_curve_points);
/* Stroke and Fill - Alpha Visibility Threshold */
#define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
#define GPENCIL_STRENGTH_MIN 0.003f
+/**
+ * Check if the given layer is able to be edited or not.
+ * \param gpl: Grease pencil layer
+ * \return True if layer is editable
+ */
bool BKE_gpencil_layer_is_editable(const struct bGPDlayer *gpl);
/* How gpencil_layer_getframe() should behave when there
@@ -185,28 +339,121 @@ typedef enum eGP_GetFrame_Mode {
GP_GETFRAME_ADD_COPY = 2,
} eGP_GetFrame_Mode;
+/**
+ * Get the appropriate gp-frame from a given layer
+ * - this sets the layer's actframe var (if allowed to)
+ * - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
+ *
+ * \param gpl: Grease pencil layer
+ * \param cframe: Frame number
+ * \param addnew: Add option
+ * \return Pointer to new frame
+ */
struct bGPDframe *BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl,
int cframe,
eGP_GetFrame_Mode addnew);
+/**
+ * Look up the gp-frame on the requested frame number, but don't add a new one.
+ * \param gpl: Grease pencil layer
+ * \param cframe: Frame number
+ * \return Pointer to frame
+ */
struct bGPDframe *BKE_gpencil_layer_frame_find(struct bGPDlayer *gpl, int cframe);
+/**
+ * Delete the given frame from a layer.
+ * \param gpl: Grease pencil layer
+ * \param gpf: Grease pencil frame
+ * \return True if delete was done
+ */
bool BKE_gpencil_layer_frame_delete(struct bGPDlayer *gpl, struct bGPDframe *gpf);
+/**
+ * Get layer by name
+ * \param gpd: Grease pencil data-block
+ * \param name: Layer name
+ * \return Pointer to layer
+ */
struct bGPDlayer *BKE_gpencil_layer_named_get(struct bGPdata *gpd, const char *name);
+/**
+ * Get the active grease pencil layer for editing.
+ * \param gpd: Grease pencil data-block
+ * \return Pointer to layer
+ */
struct bGPDlayer *BKE_gpencil_layer_active_get(struct bGPdata *gpd);
+/**
+ * Set active grease pencil layer.
+ * \param gpd: Grease pencil data-block
+ * \param active: Grease pencil layer to set as active
+ */
void BKE_gpencil_layer_active_set(struct bGPdata *gpd, struct bGPDlayer *active);
+/**
+ * Delete grease pencil layer.
+ * \param gpd: Grease pencil data-block
+ * \param gpl: Grease pencil layer
+ */
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
-void BKE_gpencil_layer_autolock_set(struct bGPdata *gpd, const bool unlock);
+/**
+ * Set locked layers for autolock mode.
+ * \param gpd: Grease pencil data-block
+ * \param unlock: Unlock flag
+ */
+void BKE_gpencil_layer_autolock_set(struct bGPdata *gpd, bool unlock);
+/**
+ * Add grease pencil mask layer.
+ * \param gpl: Grease pencil layer
+ * \param name: Name of the mask
+ * \return Pointer to new mask layer
+ */
struct bGPDlayer_Mask *BKE_gpencil_layer_mask_add(struct bGPDlayer *gpl, const char *name);
+/**
+ * Remove grease pencil mask layer.
+ * \param gpl: Grease pencil layer
+ * \param mask: Grease pencil mask layer
+ */
void BKE_gpencil_layer_mask_remove(struct bGPDlayer *gpl, struct bGPDlayer_Mask *mask);
+/**
+ * Remove any reference to mask layer.
+ * \param gpd: Grease pencil data-block
+ * \param name: Name of the mask layer
+ */
void BKE_gpencil_layer_mask_remove_ref(struct bGPdata *gpd, const char *name);
+/**
+ * Get mask layer by name.
+ * \param gpl: Grease pencil layer
+ * \param name: Mask name
+ * \return Pointer to mask layer
+ */
struct bGPDlayer_Mask *BKE_gpencil_layer_mask_named_get(struct bGPDlayer *gpl, const char *name);
+/**
+ * Sort grease pencil mask layers.
+ * \param gpd: Grease pencil data-block
+ * \param gpl: Grease pencil layer
+ */
void BKE_gpencil_layer_mask_sort(struct bGPdata *gpd, struct bGPDlayer *gpl);
+/**
+ * Sort all grease pencil mask layer.
+ * \param gpd: Grease pencil data-block
+ */
void BKE_gpencil_layer_mask_sort_all(struct bGPdata *gpd);
+/**
+ * Make a copy of a given gpencil mask layers.
+ */
void BKE_gpencil_layer_mask_copy(const struct bGPDlayer *gpl_src, struct bGPDlayer *gpl_dst);
+/**
+ * Clean any invalid mask layer.
+ */
void BKE_gpencil_layer_mask_cleanup(struct bGPdata *gpd, struct bGPDlayer *gpl);
+/**
+ * Clean any invalid mask layer for all layers.
+ */
void BKE_gpencil_layer_mask_cleanup_all_layers(struct bGPdata *gpd);
+/**
+ * Sort grease pencil frames.
+ * \param gpl: Grease pencil layer
+ * \param r_has_duplicate_frames: Duplicated frames flag
+ */
void BKE_gpencil_layer_frames_sort(struct bGPDlayer *gpl, bool *r_has_duplicate_frames);
struct bGPDlayer *BKE_gpencil_layer_get_by_name(struct bGPdata *gpd,
@@ -214,14 +461,43 @@ struct bGPDlayer *BKE_gpencil_layer_get_by_name(struct bGPdata *gpd,
int first_if_not_found);
/* Brush */
+/**
+ * Get grease pencil material from brush.
+ * \param brush: Brush
+ * \return Pointer to material
+ */
struct Material *BKE_gpencil_brush_material_get(struct Brush *brush);
+/**
+ * Set grease pencil brush material.
+ * \param brush: Brush
+ * \param material: Material
+ */
void BKE_gpencil_brush_material_set(struct Brush *brush, struct Material *material);
/* Object */
+/**
+ * Get active color, and add all default settings if we don't find anything.
+ * \param ob: Grease pencil object
+ * \return Material pointer
+ */
struct Material *BKE_gpencil_object_material_ensure_active(struct Object *ob);
+/**
+ * Adds the pinned material to the object if necessary.
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object
+ * \param brush: Brush
+ * \return Pointer to material
+ */
struct Material *BKE_gpencil_object_material_ensure_from_brush(struct Main *bmain,
struct Object *ob,
struct Brush *brush);
+/**
+ * Assigns the material to object (if not already present) and returns its index (mat_nr).
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object
+ * \param material: Material
+ * \return Index of the material
+ */
int BKE_gpencil_object_material_ensure(struct Main *bmain,
struct Object *ob,
struct Material *material);
@@ -230,49 +506,147 @@ struct Material *BKE_gpencil_object_material_ensure_by_name(struct Main *bmain,
const char *name,
int *r_index);
+/**
+ * Creates a new grease-pencil material and assigns it to object.
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object
+ * \param name: Material name
+ * \param r_index: value is set to zero based index of the new material if \a r_index is not NULL.
+ * \return Material pointer.
+ */
struct Material *BKE_gpencil_object_material_new(struct Main *bmain,
struct Object *ob,
const char *name,
int *r_index);
+/**
+ * Get material index (0-based like mat_nr not actcol).
+ * \param ob: Grease pencil object
+ * \param ma: Material
+ * \return Index of the material
+ */
int BKE_gpencil_object_material_index_get(struct Object *ob, struct Material *ma);
int BKE_gpencil_object_material_index_get_by_name(struct Object *ob, const char *name);
+/**
+ * Returns the material for a brush with respect to its pinned state.
+ * \param ob: Grease pencil object
+ * \param brush: Brush
+ * \return Material pointer
+ */
struct Material *BKE_gpencil_object_material_from_brush_get(struct Object *ob,
struct Brush *brush);
+/**
+ * Returns the material index for a brush with respect to its pinned state.
+ * \param ob: Grease pencil object
+ * \param brush: Brush
+ * \return Material index.
+ */
int BKE_gpencil_object_material_get_index_from_brush(struct Object *ob, struct Brush *brush);
+/**
+ * Guaranteed to return a material assigned to object. Returns never NULL.
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object
+ * \return Material pointer.
+ */
struct Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettings(
struct Main *bmain, struct Object *ob, struct ToolSettings *ts);
+/**
+ * Guaranteed to return a material assigned to object. Returns never NULL.
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object.
+ * \param brush: Brush
+ * \return Material pointer
+ */
struct Material *BKE_gpencil_object_material_ensure_from_active_input_brush(struct Main *bmain,
struct Object *ob,
struct Brush *brush);
+/**
+ * Guaranteed to return a material assigned to object. Returns never NULL.
+ * Only use this for materials unrelated to user input.
+ * \param ob: Grease pencil object
+ * \return Material pointer
+ */
struct Material *BKE_gpencil_object_material_ensure_from_active_input_material(struct Object *ob);
+/**
+ * Check if stroke has any point selected
+ * \param gps: Grease pencil stroke
+ * \return True if selected
+ */
bool BKE_gpencil_stroke_select_check(const struct bGPDstroke *gps);
/* vertex groups */
+/**
+ * Ensure stroke has vertex group.
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_dvert_ensure(struct bGPDstroke *gps);
+/**
+ * Remove a vertex group.
+ * \param ob: Grease pencil object
+ * \param defgroup: deform group
+ */
void BKE_gpencil_vgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
+/**
+ * Make a copy of a given gpencil weights.
+ * \param gps_src: Source grease pencil stroke
+ * \param gps_dst: Destination grease pencil stroke
+ */
void BKE_gpencil_stroke_weights_duplicate(struct bGPDstroke *gps_src, struct bGPDstroke *gps_dst);
/* Set active frame by layer. */
+/**
+ * Set current grease pencil active frame.
+ * \param depsgraph: Current depsgraph
+ * \param gpd: Grease pencil data-block.
+ */
void BKE_gpencil_frame_active_set(struct Depsgraph *depsgraph, struct bGPdata *gpd);
+/**
+ * Get range of selected frames in layer.
+ * Always the active frame is considered as selected, so if no more selected the range
+ * will be equal to the current active frame.
+ * \param gpl: Layer.
+ * \param r_initframe: Number of first selected frame.
+ * \param r_endframe: Number of last selected frame.
+ */
void BKE_gpencil_frame_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe);
+/**
+ * Get Falloff factor base on frame range
+ * \param gpf: Frame.
+ * \param actnum: Number of active frame in layer.
+ * \param f_init: Number of first selected frame.
+ * \param f_end: Number of last selected frame.
+ * \param cur_falloff: Curve with falloff factors.
+ */
float BKE_gpencil_multiframe_falloff_calc(
struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff);
+/**
+ * Create a default palette.
+ * \param bmain: Main pointer
+ * \param scene: Scene
+ */
void BKE_gpencil_palette_ensure(struct Main *bmain, struct Scene *scene);
-bool BKE_gpencil_from_image(struct SpaceImage *sima,
- struct bGPdata *gpd,
- struct bGPDframe *gpf,
- const float size,
- const bool mask);
+/**
+ * Create grease pencil strokes from image
+ * \param sima: Image
+ * \param gpd: Grease pencil data-block
+ * \param gpf: Grease pencil frame
+ * \param size: Size
+ * \param mask: Mask
+ * \return True if done
+ */
+bool BKE_gpencil_from_image(
+ struct SpaceImage *sima, struct bGPdata *gpd, struct bGPDframe *gpf, float size, bool mask);
/* Iterators */
-/* frame & stroke are NULL if it is a layer callback. */
+/**
+ * Frame & stroke are NULL if it is a layer callback.
+ */
typedef void (*gpIterCb)(struct bGPDlayer *layer,
struct bGPDframe *frame,
struct bGPDstroke *stroke,
@@ -294,17 +668,45 @@ void BKE_gpencil_visible_stroke_advanced_iter(struct ViewLayer *view_layer,
extern void (*BKE_gpencil_batch_cache_dirty_tag_cb)(struct bGPdata *gpd);
extern void (*BKE_gpencil_batch_cache_free_cb)(struct bGPdata *gpd);
+/**
+ * Update original pointers in evaluated frame.
+ * \param gpf_orig: Original grease-pencil frame.
+ * \param gpf_eval: Evaluated grease pencil frame.
+ */
void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig,
const struct bGPDframe *gpf_eval);
+/**
+ * Update pointers of eval data to original data to keep references.
+ * \param ob_orig: Original grease pencil object
+ * \param ob_eval: Evaluated grease pencil object
+ */
void BKE_gpencil_update_orig_pointers(const struct Object *ob_orig, const struct Object *ob_eval);
+/**
+ * Get parent matrix, including layer parenting.
+ * \param depsgraph: Depsgraph
+ * \param obact: Grease pencil object
+ * \param gpl: Grease pencil layer
+ * \param diff_mat: Result parent matrix
+ */
void BKE_gpencil_layer_transform_matrix_get(const struct Depsgraph *depsgraph,
struct Object *obact,
struct bGPDlayer *gpl,
float diff_mat[4][4]);
+/**
+ * Update parent matrix and local transforms.
+ * \param depsgraph: Depsgraph
+ * \param ob: Grease pencil object
+ */
void BKE_gpencil_update_layer_transforms(const struct Depsgraph *depsgraph, struct Object *ob);
+/**
+ * Find material by name prefix.
+ * \param ob: Object pointer
+ * \param name_prefix: Prefix name of the material
+ * \return Index
+ */
int BKE_gpencil_material_find_index_by_name_prefix(struct Object *ob, const char *name_prefix);
void BKE_gpencil_blend_read_data(struct BlendDataReader *reader, struct bGPdata *gpd);
diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve.h
index 9cbe67af9c1..5c5f96c17f1 100644
--- a/source/blender/blenkernel/BKE_gpencil_curve.h
+++ b/source/blender/blenkernel/BKE_gpencil_curve.h
@@ -35,34 +35,63 @@ struct bGPDlayer;
struct bGPDstroke;
struct bGPdata;
+/**
+ * Convert a curve object to grease pencil stroke.
+ *
+ * \param bmain: Main thread pointer
+ * \param scene: Original scene.
+ * \param ob_gp: Grease pencil object to add strokes.
+ * \param ob_cu: Curve to convert.
+ * \param use_collections: Create layers using collection names.
+ * \param scale_thickness: Scale thickness factor.
+ * \param sample: Sample distance, zero to disable.
+ */
void BKE_gpencil_convert_curve(struct Main *bmain,
struct Scene *scene,
struct Object *ob_gp,
struct Object *ob_cu,
- const bool use_collections,
- const float scale_thickness,
- const float sample);
+ bool use_collections,
+ float scale_thickness,
+ float sample);
+/**
+ * Creates a bGPDcurve by doing a cubic curve fitting on the grease pencil stroke points.
+ */
struct bGPDcurve *BKE_gpencil_stroke_editcurve_generate(struct bGPDstroke *gps,
- const float error_threshold,
- const float corner_angle,
- const float stroke_radius);
+ float error_threshold,
+ float corner_angle,
+ float stroke_radius);
+/**
+ * Updates the edit-curve for a stroke. Frees the old curve if one exists and generates a new one.
+ */
void BKE_gpencil_stroke_editcurve_update(struct bGPdata *gpd,
struct bGPDlayer *gpl,
struct bGPDstroke *gps);
+/**
+ * Sync the selection from stroke to edit-curve.
+ */
void BKE_gpencil_editcurve_stroke_sync_selection(struct bGPdata *gpd,
struct bGPDstroke *gps,
struct bGPDcurve *gpc);
+/**
+ * Sync the selection from edit-curve to stroke.
+ */
void BKE_gpencil_stroke_editcurve_sync_selection(struct bGPdata *gpd,
struct bGPDstroke *gps,
struct bGPDcurve *gpc);
void BKE_gpencil_strokes_selected_update_editcurve(struct bGPdata *gpd);
void BKE_gpencil_strokes_selected_sync_selection_editcurve(struct bGPdata *gpd);
+/**
+ * Recalculate stroke points with the edit-curve of the stroke.
+ */
void BKE_gpencil_stroke_update_geometry_from_editcurve(struct bGPDstroke *gps,
- const uint resolution,
- const bool is_adaptive);
+ uint resolution,
+ bool is_adaptive);
+/**
+ * Recalculate the handles of the edit curve of a grease pencil stroke.
+ */
void BKE_gpencil_editcurve_recalculate_handles(struct bGPDstroke *gps);
-void BKE_gpencil_editcurve_subdivide(struct bGPDstroke *gps, const int cuts);
+void BKE_gpencil_editcurve_subdivide(struct bGPDstroke *gps, int cuts);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h
index a9cd553a8fe..24b820b06cc 100644
--- a/source/blender/blenkernel/BKE_gpencil_geom.h
+++ b/source/blender/blenkernel/BKE_gpencil_geom.h
@@ -38,49 +38,159 @@ struct bGPDspoint;
struct bGPDstroke;
struct bGPdata;
-/* Object boundbox. */
+/* Object bound-box. */
+
+/**
+ * Get min/max bounds of all strokes in grease pencil data-block.
+ * \param gpd: Grease pencil data-block
+ * \param r_min: Result minimum coordinates
+ * \param r_max: Result maximum coordinates
+ * \return True if it was possible to calculate
+ */
bool BKE_gpencil_data_minmax(const struct bGPdata *gpd, float r_min[3], float r_max[3]);
+/**
+ * Get min/max coordinate bounds for single stroke.
+ * \param gps: Grease pencil stroke
+ * \param use_select: Include only selected points
+ * \param r_min: Result minimum coordinates
+ * \param r_max: Result maximum coordinates
+ * \return True if it was possible to calculate
+ */
bool BKE_gpencil_stroke_minmax(const struct bGPDstroke *gps,
- const bool use_select,
+ bool use_select,
float r_min[3],
float r_max[3]);
+/**
+ * Get grease pencil object bounding box.
+ * \param ob: Grease pencil object
+ * \return Bounding box
+ */
struct BoundBox *BKE_gpencil_boundbox_get(struct Object *ob);
+/**
+ * Compute center of bounding box.
+ * \param gpd: Grease pencil data-block
+ * \param r_centroid: Location of the center
+ */
void BKE_gpencil_centroid_3d(struct bGPdata *gpd, float r_centroid[3]);
+/**
+ * Compute stroke bounding box.
+ * \param gps: Grease pencil Stroke
+ */
void BKE_gpencil_stroke_boundingbox_calc(struct bGPDstroke *gps);
-/* stroke geometry utilities */
+/* Stroke geometry utilities. */
+
+/**
+ * Calculate stroke normals.
+ * \param gps: Grease pencil stroke
+ * \param r_normal: Return Normal vector normalized
+ */
void BKE_gpencil_stroke_normal(const struct bGPDstroke *gps, float r_normal[3]);
+/**
+ * Reduce a series of points to a simplified version,
+ * but maintains the general shape of the series.
+ *
+ * Ramer - Douglas - Peucker algorithm
+ * by http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
+ * \param gpd: Grease pencil data-block
+ * \param gps: Grease pencil stroke
+ * \param epsilon: Epsilon value to define precision of the algorithm
+ */
void BKE_gpencil_stroke_simplify_adaptive(struct bGPdata *gpd,
struct bGPDstroke *gps,
float epsilon);
+/**
+ * Simplify alternate vertex of stroke except extremes.
+ * \param gpd: Grease pencil data-block
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_simplify_fixed(struct bGPdata *gpd, struct bGPDstroke *gps);
+/**
+ * Subdivide a stroke
+ * \param gpd: Grease pencil data-block
+ * \param gps: Stroke
+ * \param level: Level of subdivision
+ * \param type: Type of subdivision
+ */
void BKE_gpencil_stroke_subdivide(struct bGPdata *gpd,
struct bGPDstroke *gps,
int level,
int type);
+/**
+ * Trim stroke to the first intersection or loop.
+ * \param gps: Stroke data
+ */
bool BKE_gpencil_stroke_trim(struct bGPdata *gpd, struct bGPDstroke *gps);
+/**
+ * Reduce a series of points when the distance is below a threshold.
+ * Special case for first and last points (both are kept) for other points,
+ * the merge point always is at first point.
+ *
+ * \param gpd: Grease pencil data-block.
+ * \param gpf: Grease Pencil frame.
+ * \param gps: Grease Pencil stroke.
+ * \param threshold: Distance between points.
+ * \param use_unselected: Set to true to analyze all stroke and not only selected points.
+ */
void BKE_gpencil_stroke_merge_distance(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
- const float threshold,
- const bool use_unselected);
+ float threshold,
+ bool use_unselected);
+/**
+ * Get points of stroke always flat to view not affected
+ * by camera view or view position.
+ * \param points: Array of grease pencil points (3D)
+ * \param totpoints: Total of points
+ * \param points2d: Result array of 2D points
+ * \param r_direction: Return Concave (-1), Convex (1), or Auto-detect (0)
+ */
void BKE_gpencil_stroke_2d_flat(const struct bGPDspoint *points,
int totpoints,
float (*points2d)[2],
int *r_direction);
+/**
+ * Get points of stroke always flat to view not affected by camera view or view position
+ * using another stroke as reference.
+ * \param ref_points: Array of reference points (3D)
+ * \param ref_totpoints: Total reference points
+ * \param points: Array of points to flat (3D)
+ * \param totpoints: Total points
+ * \param points2d: Result array of 2D points
+ * \param scale: Scale factor
+ * \param r_direction: Return Concave (-1), Convex (1), or Auto-detect (0)
+ */
void BKE_gpencil_stroke_2d_flat_ref(const struct bGPDspoint *ref_points,
int ref_totpoints,
const struct bGPDspoint *points,
int totpoints,
float (*points2d)[2],
- const float scale,
+ float scale,
int *r_direction);
+/**
+ * Triangulate stroke to generate data for filling areas.
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_fill_triangulate(struct bGPDstroke *gps);
+/**
+ * Recalc all internal geometry data for the stroke
+ * \param gpd: Grease pencil data-block
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_geometry_update(struct bGPdata *gpd, struct bGPDstroke *gps);
+/**
+ * Update Stroke UV data.
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_uv_update(struct bGPDstroke *gps);
+/**
+ * Apply grease pencil Transforms.
+ * \param gpd: Grease pencil data-block
+ * \param mat: Transformation matrix
+ */
void BKE_gpencil_transform(struct bGPdata *gpd, const float mat[4][4]);
typedef struct GPencilPointCoordinates {
@@ -90,45 +200,118 @@ typedef struct GPencilPointCoordinates {
float pressure;
} GPencilPointCoordinates;
+/**
+ * \note Used for "move only origins" in object_data_transform.c.
+ */
int BKE_gpencil_stroke_point_count(const struct bGPdata *gpd);
+/**
+ * \note Used for "move only origins" in object_data_transform.c.
+ */
void BKE_gpencil_point_coords_get(struct bGPdata *gpd, GPencilPointCoordinates *elem_data);
+/**
+ * \note Used for "move only origins" in object_data_transform.c.
+ */
void BKE_gpencil_point_coords_apply(struct bGPdata *gpd, const GPencilPointCoordinates *elem_data);
+/**
+ * \note Used for "move only origins" in object_data_transform.c.
+ */
void BKE_gpencil_point_coords_apply_with_mat4(struct bGPdata *gpd,
const GPencilPointCoordinates *elem_data,
const float mat[4][4]);
+/**
+ * Resample a stroke
+ * \param gpd: Grease pencil data-block
+ * \param gps: Stroke to sample
+ * \param dist: Distance of one segment
+ */
bool BKE_gpencil_stroke_sample(struct bGPdata *gpd,
struct bGPDstroke *gps,
- const float dist,
- const bool select);
-bool BKE_gpencil_stroke_smooth_point(struct bGPDstroke *gps, int i, float inf);
+ float dist,
+ bool select);
+/**
+ * Apply smooth position to stroke point.
+ * \param gps: Stroke to smooth
+ * \param i: Point index
+ * \param inf: Amount of smoothing to apply
+ * \param smooth_caps: Apply smooth to stroke extremes
+ */
+bool BKE_gpencil_stroke_smooth_point(struct bGPDstroke *gps, int i, float inf, bool smooth_caps);
+/**
+ * Apply smooth strength to stroke point.
+ * \param gps: Stroke to smooth
+ * \param point_index: Point index
+ * \param influence: Amount of smoothing to apply
+ */
bool BKE_gpencil_stroke_smooth_strength(struct bGPDstroke *gps, int point_index, float influence);
+/**
+ * Apply smooth for thickness to stroke point (use pressure).
+ * \param gps: Stroke to smooth
+ * \param point_index: Point index
+ * \param influence: Amount of smoothing to apply
+ */
bool BKE_gpencil_stroke_smooth_thickness(struct bGPDstroke *gps, int point_index, float influence);
+/**
+ * Apply smooth for UV rotation to stroke point (use pressure).
+ * \param gps: Stroke to smooth
+ * \param point_index: Point index
+ * \param influence: Amount of smoothing to apply
+ */
bool BKE_gpencil_stroke_smooth_uv(struct bGPDstroke *gps, int point_index, float influence);
+/**
+ * Close grease pencil stroke.
+ * \param gps: Stroke to close
+ */
bool BKE_gpencil_stroke_close(struct bGPDstroke *gps);
+/**
+ * Dissolve points in stroke.
+ * \param gpd: Grease pencil data-block
+ * \param gpf: Grease pencil frame
+ * \param gps: Grease pencil stroke
+ * \param tag: Type of tag for point
+ */
void BKE_gpencil_dissolve_points(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
- const short tag);
+ short tag);
+/**
+ * Backbone stretch similar to Freestyle.
+ * \param gps: Stroke to sample.
+ * \param dist: Length of the added section.
+ * \param overshoot_fac: Relative length of the curve which is used to determine the extension.
+ * \param mode: Affect to Start, End or Both extremes (0->Both, 1->Start, 2->End).
+ * \param follow_curvature: True for approximating curvature of given overshoot.
+ * \param extra_point_count: When follow_curvature is true, use this amount of extra points.
+ */
bool BKE_gpencil_stroke_stretch(struct bGPDstroke *gps,
- const float dist,
- const float overshoot_fac,
- const short mode,
- const bool follow_curvature,
- const int extra_point_count,
- const float segment_influence,
- const float max_angle,
- const bool invert_curvature);
-bool BKE_gpencil_stroke_trim_points(struct bGPDstroke *gps,
- const int index_from,
- const int index_to);
+ float dist,
+ float overshoot_fac,
+ short mode,
+ bool follow_curvature,
+ int extra_point_count,
+ float segment_influence,
+ float max_angle,
+ bool invert_curvature);
+/**
+ * Trim stroke to needed segments.
+ * \param gps: Target stroke.
+ * \param index_from: the index of the first point to be used in the trimmed result.
+ * \param index_to: the index of the last point to be used in the trimmed result.
+ */
+bool BKE_gpencil_stroke_trim_points(struct bGPDstroke *gps, int index_from, int index_to);
+/**
+ * Split the given stroke into several new strokes, partitioning
+ * it based on whether the stroke points have a particular flag
+ * is set (e.g. #GP_SPOINT_SELECT in most cases, but not always).
+ */
struct bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
struct bGPDstroke *next_stroke,
int tag_flags,
bool select,
+ bool flat_cap,
int limit);
void BKE_gpencil_curve_delete_tagged_points(struct bGPdata *gpd,
struct bGPDframe *gpf,
@@ -137,65 +320,148 @@ void BKE_gpencil_curve_delete_tagged_points(struct bGPdata *gpd,
struct bGPDcurve *gpc,
int tag_flags);
+/**
+ * Flip stroke.
+ */
void BKE_gpencil_stroke_flip(struct bGPDstroke *gps);
+/**
+ * Split stroke.
+ * \param gpd: Grease pencil data-block.
+ * \param gpf: Grease pencil frame.
+ * \param gps: Grease pencil original stroke.
+ * \param before_index: Position of the point to split.
+ * \param remaining_gps: Secondary stroke after split.
+ * \return True if the split was done
+ */
bool BKE_gpencil_stroke_split(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
- const int before_index,
+ int before_index,
struct bGPDstroke **remaining_gps);
-bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, const float dist, const short mode);
+/**
+ * Shrink the stroke by length.
+ * \param gps: Stroke to shrink
+ * \param dist: delta length
+ * \param mode: 1->Start, 2->End
+ */
+bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, float dist, short mode);
+/**
+ * Calculate grease pencil stroke length.
+ * \param gps: Grease pencil stroke.
+ * \param use_3d: Set to true to use 3D points.
+ * \return Length of the stroke.
+ */
float BKE_gpencil_stroke_length(const struct bGPDstroke *gps, bool use_3d);
+/** Calculate grease pencil stroke length between points. */
float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps,
- const int start_index,
- const int end_index,
+ int start_index,
+ int end_index,
bool use_3d);
+/**
+ * Set a random color to stroke using vertex color.
+ * \param gps: Stroke
+ */
void BKE_gpencil_stroke_set_random_color(struct bGPDstroke *gps);
+/**
+ * Join two strokes using the shortest distance (reorder stroke if necessary).
+ */
void BKE_gpencil_stroke_join(struct bGPDstroke *gps_a,
struct bGPDstroke *gps_b,
- const bool leave_gaps,
- const bool fit_thickness,
- const bool smooth);
+ bool leave_gaps,
+ bool fit_thickness,
+ bool smooth);
+/**
+ * Copy the stroke of the frame to all frames selected (except current).
+ */
void BKE_gpencil_stroke_copy_to_keyframes(struct bGPdata *gpd,
struct bGPDlayer *gpl,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
- const bool tail);
+ bool tail);
+/**
+ * Convert a mesh object to grease pencil stroke.
+ *
+ * \param bmain: Main thread pointer.
+ * \param depsgraph: Original depsgraph.
+ * \param scene: Original scene.
+ * \param ob_gp: Grease pencil object to add strokes.
+ * \param ob_mesh: Mesh to convert.
+ * \param angle: Limit angle to consider a edge-loop ends.
+ * \param thickness: Thickness of the strokes.
+ * \param offset: Offset along the normals.
+ * \param matrix: Transformation matrix.
+ * \param frame_offset: Destination frame number offset.
+ * \param use_seams: Only export seam edges.
+ * \param use_faces: Export faces as filled strokes.
+ */
bool BKE_gpencil_convert_mesh(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_gp,
struct Object *ob_mesh,
- const float angle,
- const int thickness,
- const float offset,
+ float angle,
+ int thickness,
+ float offset,
const float matrix[4][4],
- const int frame_offset,
- const bool use_seams,
- const bool use_faces,
- const bool use_vgroups);
+ int frame_offset,
+ bool use_seams,
+ bool use_faces,
+ bool use_vgroups);
+/**
+ * Subdivide the grease pencil stroke so the number of points is target_number.
+ * Does not change the shape of the stroke. The new points will be distributed as
+ * uniformly as possible by repeatedly subdividing the current longest edge.
+ *
+ * \param gps: The stroke to be up-sampled.
+ * \param target_number: The number of points the up-sampled stroke should have.
+ * \param select: Select/Deselect the stroke.
+ */
void BKE_gpencil_stroke_uniform_subdivide(struct bGPdata *gpd,
struct bGPDstroke *gps,
- const uint32_t target_number,
- const bool select);
+ uint32_t target_number,
+ bool select);
+/**
+ * Stroke to view space
+ * Transforms a stroke to view space.
+ * This allows for manipulations in 2D but also easy conversion back to 3D.
+ * \note also takes care of parent space transform.
+ */
void BKE_gpencil_stroke_to_view_space(struct RegionView3D *rv3d,
struct bGPDstroke *gps,
const float diff_mat[4][4]);
+/**
+ * Stroke from view space
+ * Transforms a stroke from view space back to world space.
+ * Inverse of #BKE_gpencil_stroke_to_view_space
+ * \note also takes care of parent space transform.
+ */
void BKE_gpencil_stroke_from_view_space(struct RegionView3D *rv3d,
struct bGPDstroke *gps,
const float diff_mat[4][4]);
+/**
+ * Calculates the perimeter of a stroke projected from the view and returns it as a new stroke.
+ * \param subdivisions: Number of subdivisions for the start and end caps.
+ * \return: bGPDstroke pointer to stroke perimeter.
+ */
struct bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,
struct bGPdata *gpd,
const struct bGPDlayer *gpl,
struct bGPDstroke *gps,
- const int subdivisions,
+ int subdivisions,
const float diff_mat[4][4]);
+/**
+ * Get average pressure.
+ */
float BKE_gpencil_stroke_average_pressure_get(struct bGPDstroke *gps);
+/**
+ * Check if the thickness of the stroke is constant.
+ */
bool BKE_gpencil_stroke_is_pressure_constant(struct bGPDstroke *gps);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
index 33524e47473..6df13df1c01 100644
--- a/source/blender/blenkernel/BKE_gpencil_modifier.h
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -207,7 +207,7 @@ typedef struct GpencilModifierTypeInfo {
*/
void (*updateDepsgraph)(struct GpencilModifierData *md,
const struct ModifierUpdateDepsgraphContext *ctx,
- const int mode);
+ int mode);
/**
* Should return true if the modifier needs to be recalculated on time
@@ -249,36 +249,114 @@ typedef struct GpencilModifierTypeInfo {
#define GPENCIL_MODIFIER_TYPE_PANEL_PREFIX "MOD_PT_gpencil_"
-/* Initialize modifier's global data (type info and some common global storage). */
+/**
+ * Initialize modifier's global data (type info and some common global storage).
+ */
void BKE_gpencil_modifier_init(void);
+/**
+ * Get the idname of the modifier type's panel, which was defined in the #panelRegister callback.
+ *
+ * \param type: Type of modifier.
+ * \param r_idname: ID name.
+ */
void BKE_gpencil_modifierType_panel_id(GpencilModifierType type, char *r_idname);
void BKE_gpencil_modifier_panel_expand(struct GpencilModifierData *md);
+/**
+ * Get grease pencil modifier information.
+ * \param type: Type of modifier.
+ * \return Pointer to type
+ */
const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type);
+/**
+ * Create new grease pencil modifier.
+ * \param type: Type of modifier.
+ * \return New modifier pointer.
+ */
struct GpencilModifierData *BKE_gpencil_modifier_new(int type);
-void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag);
+/**
+ * Free grease pencil modifier data
+ * \param md: Modifier data.
+ * \param flag: Flags.
+ */
+void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, int flag);
+/**
+ * Free grease pencil modifier data
+ * \param md: Modifier data.
+ */
void BKE_gpencil_modifier_free(struct GpencilModifierData *md);
+/* check unique name */
bool BKE_gpencil_modifier_unique_name(struct ListBase *modifiers, struct GpencilModifierData *gmd);
+/**
+ * Check if grease pencil modifier depends on time.
+ * \param md: Modifier data.
+ * \return True if depends on time.
+ */
bool BKE_gpencil_modifier_depends_ontime(struct GpencilModifierData *md);
struct GpencilModifierData *BKE_gpencil_modifiers_findby_type(struct Object *ob,
GpencilModifierType type);
+/**
+ * Find grease pencil modifier by name.
+ * \param ob: Grease pencil object.
+ * \param name: Name to find.
+ * \return Pointer to modifier.
+ */
struct GpencilModifierData *BKE_gpencil_modifiers_findby_name(struct Object *ob, const char *name);
+/**
+ * Generic grease pencil modifier copy data.
+ * \param md_src: Source modifier data.
+ * \param md_dst: Target modifier data.
+ */
void BKE_gpencil_modifier_copydata_generic(const struct GpencilModifierData *md_src,
struct GpencilModifierData *md_dst);
+/**
+ * Copy grease pencil modifier data.
+ * \param md: Source modifier data.
+ * \param target: Target modifier data.
+ */
void BKE_gpencil_modifier_copydata(struct GpencilModifierData *md,
struct GpencilModifierData *target);
+/**
+ * Copy grease pencil modifier data.
+ * \param md: Source modifier data.
+ * \param target: Target modifier data.
+ * \param flag: Flags.
+ */
void BKE_gpencil_modifier_copydata_ex(struct GpencilModifierData *md,
struct GpencilModifierData *target,
- const int flag);
+ int flag);
+/**
+ * Set grease pencil modifier error.
+ * \param md: Modifier data.
+ * \param format: Format.
+ */
void BKE_gpencil_modifier_set_error(struct GpencilModifierData *md, const char *format, ...)
ATTR_PRINTF_FORMAT(2, 3);
+/**
+ * Link grease pencil modifier related IDs.
+ * \param ob: Grease pencil object.
+ * \param walk: Walk option.
+ * \param userData: User data.
+ */
void BKE_gpencil_modifiers_foreach_ID_link(struct Object *ob,
GreasePencilIDWalkFunc walk,
void *userData);
+/**
+ * Link grease pencil modifier related Texts.
+ * \param ob: Grease pencil object.
+ * \param walk: Walk option.
+ * \param userData: User data.
+ */
void BKE_gpencil_modifiers_foreach_tex_link(struct Object *ob,
GreasePencilTexWalkFunc walk,
void *userData);
+/**
+ * Check whether given modifier is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param gmd: May be NULL, in which case we consider it as a non-local modifier case.
+ */
bool BKE_gpencil_modifier_is_nonlocal_in_liboverride(const struct Object *ob,
const struct GpencilModifierData *gmd);
@@ -287,11 +365,30 @@ typedef struct GpencilVirtualModifierData {
LatticeGpencilModifierData lmd;
} GpencilVirtualModifierData;
+/**
+ * This is to include things that are not modifiers in the evaluation of the modifier stack,
+ * for example parenting to an armature or lattice without having a real modifier.
+ */
struct GpencilModifierData *BKE_gpencil_modifiers_get_virtual_modifierlist(
const struct Object *ob, struct GpencilVirtualModifierData *data);
+/**
+ * Check if object has grease pencil Geometry modifiers.
+ * \param ob: Grease pencil object.
+ * \return True if exist.
+ */
bool BKE_gpencil_has_geometry_modifiers(struct Object *ob);
+/**
+ * Check if object has grease pencil Time modifiers.
+ * \param ob: Grease pencil object.
+ * \return True if exist.
+ */
bool BKE_gpencil_has_time_modifiers(struct Object *ob);
+/**
+ * Check if object has grease pencil transform stroke modifiers.
+ * \param ob: Grease pencil object.
+ * \return True if exist.
+ */
bool BKE_gpencil_has_transform_modifiers(struct Object *ob);
/* Stores the maximum calculation range in the whole modifier stack for line art so the cache can
@@ -306,31 +403,62 @@ GpencilLineartLimitInfo BKE_gpencil_get_lineart_modifier_limits(const struct Obj
void BKE_gpencil_set_lineart_modifier_limits(struct GpencilModifierData *md,
const struct GpencilLineartLimitInfo *info,
- const bool is_first_lineart);
+ bool is_first_lineart);
bool BKE_gpencil_is_first_lineart_in_stack(const struct Object *ob,
const struct GpencilModifierData *md);
-void BKE_gpencil_lattice_init(struct Object *ob);
-void BKE_gpencil_lattice_clear(struct Object *ob);
+/**
+ * Init grease pencil cache deform data.
+ * \param ob: Grease pencil object
+ */
+void BKE_gpencil_cache_data_init(struct Depsgraph *depsgraph, struct Object *ob);
+/**
+ * Clear grease pencil cache deform data.
+ * \param ob: Grease pencil object
+ */
+void BKE_gpencil_cache_data_clear(struct Object *ob);
+/**
+ * Calculate grease-pencil modifiers.
+ * \param depsgraph: Current depsgraph.
+ * \param scene: Current scene.
+ * \param ob: Grease pencil object.
+ */
void BKE_gpencil_modifiers_calc(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/**
+ * Prepare grease pencil eval data for modifiers
+ * \param depsgraph: Current depsgraph.
+ * \param scene: Current scene.
+ * \param ob: Grease pencil object.
+ */
void BKE_gpencil_prepare_eval_data(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/**
+ * Get the current frame re-timed with time modifiers.
+ * \param depsgraph: Current depsgraph.
+ * \param scene: Current scene.
+ * \param ob: Grease pencil object.
+ * \param gpl: Grease pencil layer.
+ * \return New frame number.
+ */
struct bGPDframe *BKE_gpencil_frame_retime_get(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct bGPDlayer *gpl);
+/**
+ * Get Time modifier frame number.
+ */
int BKE_gpencil_time_modifier_cfra(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct bGPDlayer *gpl,
- const int cfra,
- const bool is_render);
+ int cfra,
+ bool is_render);
void BKE_gpencil_modifier_blend_write(struct BlendWriter *writer, struct ListBase *modbase);
void BKE_gpencil_modifier_blend_read_data(struct BlendDataReader *reader, struct ListBase *lb);
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 28a6f837f61..a65cdcd23af 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -97,88 +97,154 @@ enum eIconSizes;
void BKE_icons_init(int first_dyn_id);
-/* return icon id for library object or create new icon if not found */
+/**
+ * Return icon id for library object or create new icon if not found.
+ */
int BKE_icon_id_ensure(struct ID *id);
-/* return icon id for Grease Pencil layer (color preview) or create new icon if not found */
+/**
+ * Return icon id for Grease Pencil layer (color preview) or create new icon if not found.
+ */
int BKE_icon_gplayer_color_ensure(struct bGPDlayer *gpl);
+/**
+ * Return icon id of given preview, or create new icon if not found.
+ */
int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview);
+/**
+ * Create an icon as owner or \a ibuf. The icon-ID is not stored in \a ibuf,
+ * it needs to be stored separately.
+ * \note Transforms ownership of \a ibuf to the newly created icon.
+ */
int BKE_icon_imbuf_create(struct ImBuf *ibuf) ATTR_WARN_UNUSED_RESULT;
struct ImBuf *BKE_icon_imbuf_get_buffer(int icon_id) ATTR_WARN_UNUSED_RESULT;
-/* retrieve icon for id */
-struct Icon *BKE_icon_get(const int icon_id);
+/**
+ * Retrieve icon for id.
+ */
+struct Icon *BKE_icon_get(int icon_id);
-/* set icon for id if not already defined */
-/* used for inserting the internal icons */
-void BKE_icon_set(const int icon_id, struct Icon *icon);
+/**
+ * Set icon for id if not already defined.
+ * Used for inserting the internal icons.
+ */
+void BKE_icon_set(int icon_id, struct Icon *icon);
-/* remove icon and free data if library object becomes invalid */
+/**
+ * Remove icon and free data if library object becomes invalid.
+ */
void BKE_icon_id_delete(struct ID *id);
-bool BKE_icon_delete(const int icon_id);
-bool BKE_icon_delete_unmanaged(const int icon_id);
+/**
+ * Remove icon and free data.
+ */
+bool BKE_icon_delete(int icon_id);
+bool BKE_icon_delete_unmanaged(int icon_id);
-/* report changes - icon needs to be recalculated */
-void BKE_icon_changed(const int icon_id);
+/**
+ * Report changes - icon needs to be recalculated.
+ */
+void BKE_icon_changed(int icon_id);
-/* free all icons */
+/**
+ * Free all icons.
+ */
void BKE_icons_free(void);
-/* free all icons marked for deferred deletion */
+/**
+ * Free all icons marked for deferred deletion.
+ */
void BKE_icons_deferred_free(void);
-/* free the preview image for use in list */
+/**
+ * Free the preview image for use in list.
+ */
void BKE_previewimg_freefunc(void *link);
-/* free the preview image */
+/**
+ * Free the preview image.
+ */
void BKE_previewimg_free(struct PreviewImage **prv);
-/* clear the preview image or icon, but does not free it */
+/**
+ * Clear the preview image or icon, but does not free it.
+ */
void BKE_previewimg_clear(struct PreviewImage *prv);
-/* clear the preview image or icon at a specific size */
+/**
+ * Clear the preview image or icon at a specific size.
+ */
void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size);
-/* get the preview from any pointer */
+/**
+ * Get the preview from any pointer.
+ */
struct PreviewImage **BKE_previewimg_id_get_p(const struct ID *id);
struct PreviewImage *BKE_previewimg_id_get(const struct ID *id);
bool BKE_previewimg_id_supports_jobs(const struct ID *id);
-/* Trigger deferred loading of a custom image file into the preview buffer. */
+/**
+ * Trigger deferred loading of a custom image file into the preview buffer.
+ */
void BKE_previewimg_id_custom_set(struct ID *id, const char *path);
-/* free the preview image belonging to the id */
+/**
+ * Free the preview image belonging to the id.
+ */
void BKE_previewimg_id_free(struct ID *id);
-/* create a new preview image */
+/**
+ * Create a new preview image.
+ */
struct PreviewImage *BKE_previewimg_create(void);
-/* create a copy of the preview image */
+/**
+ * Create a copy of the preview image.
+ */
struct PreviewImage *BKE_previewimg_copy(const struct PreviewImage *prv);
+/**
+ * Duplicate preview image from \a id and clear icon_id,
+ * to be used by data-block copy functions.
+ */
void BKE_previewimg_id_copy(struct ID *new_id, const struct ID *old_id);
-/* retrieve existing or create new preview image */
+/**
+ * Retrieve existing or create new preview image.
+ */
struct PreviewImage *BKE_previewimg_id_ensure(struct ID *id);
-void BKE_previewimg_ensure(struct PreviewImage *prv, const int size);
+/**
+ * Handle deferred (lazy) loading/generation of preview image, if needed.
+ * For now, only used with file thumbnails.
+ */
+void BKE_previewimg_ensure(struct PreviewImage *prv, int size);
-struct ImBuf *BKE_previewimg_to_imbuf(struct PreviewImage *prv, const int size);
+/**
+ * Create an #ImBuf holding a copy of the preview image buffer in \a prv.
+ * \note The returned image buffer has to be free'd (#IMB_freeImBuf()).
+ */
+struct ImBuf *BKE_previewimg_to_imbuf(struct PreviewImage *prv, int size);
-void BKE_previewimg_finish(struct PreviewImage *prv, const int size);
-bool BKE_previewimg_is_finished(const struct PreviewImage *prv, const int size);
+void BKE_previewimg_finish(struct PreviewImage *prv, int size);
+bool BKE_previewimg_is_finished(const struct PreviewImage *prv, int size);
struct PreviewImage *BKE_previewimg_cached_get(const char *name);
+/**
+ * Generate an empty #PreviewImage, if not yet existing.
+ */
struct PreviewImage *BKE_previewimg_cached_ensure(const char *name);
+/**
+ * Generate a #PreviewImage from given file path, using thumbnails management, if not yet existing.
+ * Does not actually generate the preview, #BKE_previewimg_ensure() must be called for that.
+ */
struct PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
const char *path,
- const int source,
+ int source,
bool force_update);
void BKE_previewimg_cached_release(const char *name);
@@ -193,8 +259,8 @@ struct Icon_Geom *BKE_icon_geom_from_memory(uchar *data, size_t data_len);
struct Icon_Geom *BKE_icon_geom_from_file(const char *filename);
struct ImBuf *BKE_icon_geom_rasterize(const struct Icon_Geom *geom,
- const unsigned int size_x,
- const unsigned int size_y);
+ unsigned int size_x,
+ unsigned int size_y);
void BKE_icon_geom_invert_lightness(struct Icon_Geom *geom);
int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type);
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index c28ac63388b..b0b981e49f0 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -56,11 +56,17 @@ typedef union IDPropertyTemplate {
/* ----------- Property Array Type ---------- */
+/**
+ * \note as a start to move away from the stupid #IDP_New function,
+ * this type has its own allocation function.
+ */
struct IDProperty *IDP_NewIDPArray(const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
struct IDProperty *IDP_CopyIDPArray(const struct IDProperty *array,
- const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+ int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* shallow copies item */
+/**
+ * Shallow copies item.
+ */
void IDP_SetIndexArray(struct IDProperty *prop, int index, struct IDProperty *item) ATTR_NONNULL();
struct IDProperty *IDP_GetIndexArray(struct IDProperty *prop, int index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -68,11 +74,20 @@ void IDP_AppendArray(struct IDProperty *prop, struct IDProperty *item);
void IDP_ResizeIDPArray(struct IDProperty *prop, int len);
/* ----------- Numeric Array Type ----------- */
-/* This function works for strings too! */
+
+/**
+ * This function works for strings too!
+ */
void IDP_ResizeArray(struct IDProperty *prop, int newlen);
void IDP_FreeArray(struct IDProperty *prop);
/* ---------- String Type ------------ */
+/**
+ * \param st: The string to assign.
+ * \param name: The property name.
+ * \param maxlen: The size of the new string (including the \0 terminator).
+ * \return The new string property.
+ */
struct IDProperty *IDP_NewString(const char *st,
const char *name,
int maxlen) ATTR_WARN_UNUSED_RESULT
@@ -87,65 +102,152 @@ void IDP_FreeString(struct IDProperty *prop) ATTR_NONNULL();
typedef void (*IDPWalkFunc)(void *userData, struct IDProperty *idp);
-void IDP_AssignID(struct IDProperty *prop, struct ID *id, const int flag);
+void IDP_AssignID(struct IDProperty *prop, struct ID *id, int flag);
/*-------- Group Functions -------*/
-/** Sync values from one group to another, only where they match */
+/**
+ * Sync values from one group to another when values name and types match,
+ * copy the values, else ignore.
+ *
+ * \note Use for syncing proxies.
+ */
void IDP_SyncGroupValues(struct IDProperty *dest, const struct IDProperty *src) ATTR_NONNULL();
-void IDP_SyncGroupTypes(struct IDProperty *dest,
- const struct IDProperty *src,
- const bool do_arraylen) ATTR_NONNULL();
+void IDP_SyncGroupTypes(struct IDProperty *dest, const struct IDProperty *src, bool do_arraylen)
+ ATTR_NONNULL();
+/**
+ * Replaces all properties with the same name in a destination group from a source group.
+ */
void IDP_ReplaceGroupInGroup(struct IDProperty *dest, const struct IDProperty *src) ATTR_NONNULL();
void IDP_ReplaceInGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
+/**
+ * Checks if a property with the same name as prop exists, and if so replaces it.
+ * Use this to preserve order!
+ */
void IDP_ReplaceInGroup_ex(struct IDProperty *group,
struct IDProperty *prop,
struct IDProperty *prop_exist);
-void IDP_MergeGroup(struct IDProperty *dest, const struct IDProperty *src, const bool do_overwrite)
+/**
+ * If a property is missing in \a dest, add it.
+ * Do it recursively.
+ */
+void IDP_MergeGroup(struct IDProperty *dest, const struct IDProperty *src, bool do_overwrite)
ATTR_NONNULL();
+/**
+ * If a property is missing in \a dest, add it.
+ * Do it recursively.
+ */
void IDP_MergeGroup_ex(struct IDProperty *dest,
const struct IDProperty *src,
- const bool do_overwrite,
- const int flag) ATTR_NONNULL();
+ bool do_overwrite,
+ int flag) ATTR_NONNULL();
+/**
+ * This function has a sanity check to make sure ID properties with the same name don't
+ * get added to the group.
+ *
+ * The sanity check just means the property is not added to the group if another property
+ * exists with the same name; the client code using ID properties then needs to detect this
+ * (the function that adds new properties to groups, #IDP_AddToGroup,
+ * returns false if a property can't be added to the group, and true if it can)
+ * and free the property.
+ */
bool IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
+/**
+ * This is the same as IDP_AddToGroup, only you pass an item
+ * in the group list to be inserted after.
+ */
bool IDP_InsertToGroup(struct IDProperty *group,
struct IDProperty *previous,
struct IDProperty *pnew) ATTR_NONNULL(1 /* group */, 3 /* pnew */);
+/**
+ * \note this does not free the property!
+ *
+ * To free the property, you have to do:
+ * #IDP_FreeProperty(prop);
+ */
void IDP_RemoveFromGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
+/**
+ * Removes the property from the group and frees it.
+ */
void IDP_FreeFromGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
struct IDProperty *IDP_GetPropertyFromGroup(const struct IDProperty *prop,
const char *name) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Same as above but ensure type match.
+ */
struct IDProperty *IDP_GetPropertyTypeFromGroup(const struct IDProperty *prop,
const char *name,
- const char type) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+ char type) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/*-------- Main Functions --------*/
-struct IDProperty *IDP_GetProperties(struct ID *id,
- const bool create_if_needed) ATTR_WARN_UNUSED_RESULT
+/**
+ * Get the Group property that contains the id properties for ID id.
+ *
+ * \param create_if_needed: Set to create the group property and attach it to id if it doesn't
+ * exist; otherwise the function will return NULL if there's no Group property attached to the ID.
+ */
+struct IDProperty *IDP_GetProperties(struct ID *id, bool create_if_needed) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
struct IDProperty *IDP_CopyProperty(const struct IDProperty *prop) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
struct IDProperty *IDP_CopyProperty_ex(const struct IDProperty *prop,
- const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+ int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Copy content from source #IDProperty into destination one,
+ * freeing destination property's content first.
+ */
void IDP_CopyPropertyContent(struct IDProperty *dst, struct IDProperty *src) ATTR_NONNULL();
+/**
+ * \param is_strict: When false treat missing items as a match.
+ */
bool IDP_EqualsProperties_ex(struct IDProperty *prop1,
struct IDProperty *prop2,
- const bool is_strict) ATTR_WARN_UNUSED_RESULT;
+ bool is_strict) ATTR_WARN_UNUSED_RESULT;
bool IDP_EqualsProperties(struct IDProperty *prop1,
struct IDProperty *prop2) ATTR_WARN_UNUSED_RESULT;
-struct IDProperty *IDP_New(const char type,
+/**
+ * Allocate a new ID.
+ *
+ * This function takes three arguments: the ID property type, a union which defines
+ * its initial value, and a name.
+ *
+ * The union is simple to use; see the top of BKE_idprop.h for its definition.
+ * An example of using this function:
+ *
+ * \code{.c}
+ * IDPropertyTemplate val;
+ * IDProperty *group, *idgroup, *color;
+ * group = IDP_New(IDP_GROUP, val, "group1"); // groups don't need a template.
+ *
+ * val.array.len = 4
+ * val.array.type = IDP_FLOAT;
+ * color = IDP_New(IDP_ARRAY, val, "color1");
+ *
+ * idgroup = IDP_GetProperties(some_id, 1);
+ * IDP_AddToGroup(idgroup, color);
+ * IDP_AddToGroup(idgroup, group);
+ * \endcode
+ *
+ * Note that you MUST either attach the id property to an id property group with
+ * IDP_AddToGroup or MEM_freeN the property, doing anything else might result in
+ * a memory leak.
+ */
+struct IDProperty *IDP_New(char type,
const IDPropertyTemplate *val,
const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void IDP_FreePropertyContent_ex(struct IDProperty *prop, const bool do_id_user);
+/**
+ * \note This will free allocated data, all child properties of arrays and groups, and unlink IDs!
+ * But it does not free the actual #IDProperty struct itself.
+ */
+void IDP_FreePropertyContent_ex(struct IDProperty *prop, bool do_id_user);
void IDP_FreePropertyContent(struct IDProperty *prop);
-void IDP_FreeProperty_ex(struct IDProperty *prop, const bool do_id_user);
+void IDP_FreeProperty_ex(struct IDProperty *prop, bool do_id_user);
void IDP_FreeProperty(struct IDProperty *prop);
void IDP_ClearProperty(struct IDProperty *prop);
@@ -184,18 +286,37 @@ void IDP_Reset(struct IDProperty *prop, const struct IDProperty *reference);
# define IDP_Id(prop) ((ID *)(prop)->data.pointer)
#endif
+/**
+ * Return an int from an #IDProperty with a compatible type. This should be avoided, but
+ * it's sometimes necessary, for example when legacy files have incorrect property types.
+ */
int IDP_coerce_to_int_or_zero(const struct IDProperty *prop);
+/**
+ * Return a float from an #IDProperty with a compatible type. This should be avoided, but
+ * it's sometimes necessary, for example when legacy files have incorrect property types.
+ */
float IDP_coerce_to_float_or_zero(const struct IDProperty *prop);
+/**
+ * Return a double from an #IDProperty with a compatible type. This should be avoided, but
+ * it's sometimes necessary, for example when legacy files have incorrect property types.
+ */
double IDP_coerce_to_double_or_zero(const struct IDProperty *prop);
/**
- * Call a callback for each idproperty in the hierarchy under given root one (included).
- *
+ * Call a callback for each #IDproperty in the hierarchy under given root one (included).
*/
typedef void (*IDPForeachPropertyCallback)(struct IDProperty *id_property, void *user_data);
+/**
+ * Loop through all ID properties in hierarchy of given \a id_property_root included.
+ *
+ * \note Container types (groups and arrays) are processed after applying the callback on them.
+ *
+ * \param type_filter: If not 0, only apply callback on properties of matching types, see
+ * IDP_TYPE_FILTER_ enum in DNA_ID.h.
+ */
void IDP_foreach_property(struct IDProperty *id_property_root,
- const int type_filter,
+ int type_filter,
IDPForeachPropertyCallback callback,
void *user_data);
@@ -230,6 +351,11 @@ typedef enum eIDPropertyUIDataType {
bool IDP_ui_data_supported(const struct IDProperty *prop);
eIDPropertyUIDataType IDP_ui_data_type(const struct IDProperty *prop);
void IDP_ui_data_free(struct IDProperty *prop);
+/**
+ * Free allocated pointers in the UI data that isn't shared with the UI data in the `other`
+ * argument. Useful for returning early on failure when updating UI data in place, or when
+ * replacing a subset of the UI data's allocated pointers.
+ */
void IDP_ui_data_free_unique_contents(struct IDPropertyUIData *ui_data,
eIDPropertyUIDataType type,
const struct IDPropertyUIData *other);
diff --git a/source/blender/blenkernel/BKE_idprop.hh b/source/blender/blenkernel/BKE_idprop.hh
new file mode 100644
index 00000000000..782fa9c7404
--- /dev/null
+++ b/source/blender/blenkernel/BKE_idprop.hh
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BKE_idprop.h"
+
+#include "BLI_serialize.hh"
+#include "BLI_span.hh"
+
+namespace blender::bke::idprop {
+
+/**
+ * \brief Convert the given `properties` to `Value` objects for serialization.
+ *
+ * `IDP_ID` and `IDP_IDPARRAY` are not supported and will be ignored.
+ *
+ * UI data such as max/min will not be serialized.
+ */
+std::unique_ptr<io::serialize::ArrayValue> convert_to_serialize_values(
+ const IDProperty *properties);
+
+/**
+ * \brief Convert the given `value` to an `IDProperty`.
+ */
+IDProperty *convert_from_serialize_value(const blender::io::serialize::Value &value);
+
+class IDPropertyDeleter {
+ public:
+ void operator()(IDProperty *id_prop)
+ {
+ IDP_FreeProperty(id_prop);
+ }
+};
+
+/** \brief Allocate a new IDProperty of type IDP_INT, set its name and value. */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, int32_t value);
+
+/** \brief Allocate a new IDProperty of type IDP_FLOAT, set its name and value. */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, float value);
+
+/** \brief Allocate a new IDProperty of type IDP_DOUBLE, set its name and value. */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, double value);
+
+/** \brief Allocate a new IDProperty of type IDP_STRING, set its name and value. */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name,
+ const StringRefNull value);
+
+/**
+ * \brief Allocate a new IDProperty of type IDP_ARRAY and subtype IDP_INT.
+ *
+ * \param values: The values will be copied into the IDProperty.
+ */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name,
+ Span<int32_t> values);
+
+/**
+ * \brief Allocate a new IDProperty of type IDP_ARRAY and subtype IDP_FLOAT.
+ *
+ * \param values: The values will be copied into the IDProperty.
+ */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, Span<float> values);
+
+/**
+ * \brief Allocate a new IDProperty of type IDP_ARRAY and subtype IDP_DOUBLE.
+ *
+ * \param values: The values will be copied into the IDProperty.
+ */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name,
+ Span<double> values);
+
+/**
+ * \brief Allocate a new IDProperty of type IDP_GROUP.
+ *
+ * \param prop_name: The name of the newly created property.
+ */
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create_group(StringRefNull prop_name);
+
+} // namespace blender::bke::idprop
diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h
index cd656d94fce..df50f773a46 100644
--- a/source/blender/blenkernel/BKE_idtype.h
+++ b/source/blender/blenkernel/BKE_idtype.h
@@ -31,6 +31,7 @@
extern "C" {
#endif
+struct BPathForeachPathData;
struct BlendDataReader;
struct BlendExpander;
struct BlendLibReader;
@@ -77,12 +78,12 @@ typedef void (*IDTypeInitDataFunction)(struct ID *id);
typedef void (*IDTypeCopyDataFunction)(struct Main *bmain,
struct ID *id_dst,
const struct ID *id_src,
- const int flag);
+ int flag);
typedef void (*IDTypeFreeDataFunction)(struct ID *id);
-/** \param flag: See BKE_lib_id.h's LIB_ID_MAKELOCAL_... flags. */
-typedef void (*IDTypeMakeLocalFunction)(struct Main *bmain, struct ID *id, const int flags);
+/** \param flags: See BKE_lib_id.h's LIB_ID_MAKELOCAL_... flags. */
+typedef void (*IDTypeMakeLocalFunction)(struct Main *bmain, struct ID *id, int flags);
typedef void (*IDTypeForeachIDFunction)(struct ID *id, struct LibraryForeachIDData *data);
@@ -100,6 +101,8 @@ typedef void (*IDTypeForeachCacheFunction)(struct ID *id,
IDTypeForeachCacheFunctionCallback function_callback,
void *user_data);
+typedef void (*IDTypeForeachPathFunction)(struct ID *id, struct BPathForeachPathData *bpath_data);
+
typedef struct ID *(*IDTypeEmbeddedOwnerGetFunction)(struct Main *bmain, struct ID *id);
typedef void (*IDTypeBlendWriteFunction)(struct BlendWriter *writer,
@@ -149,11 +152,12 @@ typedef struct IDTypeInfo {
/** Generic info flags about that data-block type. */
uint32_t flags;
- /* ********** ID management callbacks ********** */
+ /**
+ * Information and callbacks for assets, based on the type of asset.
+ */
+ struct AssetTypeInfo *asset_type_info;
- /* TODO: Note about callbacks: Ideally we could also handle here `BKE_lib_query`'s behavior, as
- * well as read/write of files. However, this is a bit more involved than basic ID management
- * callbacks, so we'll check on this later. */
+ /* ********** ID management callbacks ********** */
/**
* Initialize a new, empty calloc'ed data-block. May be NULL if there is nothing to do.
@@ -189,6 +193,11 @@ typedef struct IDTypeInfo {
IDTypeForeachCacheFunction foreach_cache;
/**
+ * Iterator over all file paths of given ID.
+ */
+ IDTypeForeachPathFunction foreach_path;
+
+ /**
* For embedded IDs, return their owner ID.
*/
IDTypeEmbeddedOwnerGetFunction owner_get;
@@ -274,6 +283,7 @@ extern IDTypeInfo IDType_ID_PT;
extern IDTypeInfo IDType_ID_VO;
extern IDTypeInfo IDType_ID_SIM;
+/** Empty shell mostly, but needed for read code. */
extern IDTypeInfo IDType_ID_LINK_PLACEHOLDER;
/* ********** Helpers/Utils API. ********** */
@@ -282,35 +292,104 @@ extern IDTypeInfo IDType_ID_LINK_PLACEHOLDER;
void BKE_idtype_init(void);
/* General helpers. */
-const struct IDTypeInfo *BKE_idtype_get_info_from_idcode(const short id_code);
+const struct IDTypeInfo *BKE_idtype_get_info_from_idcode(short id_code);
const struct IDTypeInfo *BKE_idtype_get_info_from_id(const struct ID *id);
-const char *BKE_idtype_idcode_to_name(const short idcode);
-const char *BKE_idtype_idcode_to_name_plural(const short idcode);
-const char *BKE_idtype_idcode_to_translation_context(const short idcode);
+/**
+ * Convert an \a idcode into a name.
+ *
+ * \param idcode: The code to convert.
+ * \return A static string representing the name of the code.
+ */
+const char *BKE_idtype_idcode_to_name(short idcode);
+/**
+ * Convert an \a idcode into a name (plural).
+ *
+ * \param idcode: The code to convert.
+ * \return A static string representing the name of the code.
+ */
+const char *BKE_idtype_idcode_to_name_plural(short idcode);
+/**
+ * Convert an \a idcode into its translations' context.
+ *
+ * \param idcode: The code to convert.
+ * \return A static string representing the i18n context of the code.
+ */
+const char *BKE_idtype_idcode_to_translation_context(short idcode);
-bool BKE_idtype_idcode_is_valid(const short idcode);
+/**
+ * Return if the ID code is a valid ID code.
+ *
+ * \param idcode: The code to check.
+ * \return Boolean, 0 when invalid.
+ */
+bool BKE_idtype_idcode_is_valid(short idcode);
-bool BKE_idtype_idcode_is_linkable(const short idcode);
-bool BKE_idtype_idcode_is_only_appendable(const short idcode);
-bool BKE_idtype_idcode_append_is_reusable(const short idcode);
+/**
+ * Check if an ID type is linkable.
+ *
+ * \param idcode: The IDType code to check.
+ * \return Boolean, false when non linkable, true otherwise.
+ */
+bool BKE_idtype_idcode_is_linkable(short idcode);
+/**
+ * Check if an ID type is only appendable.
+ *
+ * \param idcode: The IDType code to check.
+ * \return Boolean, false when also linkable, true when only appendable.
+ */
+bool BKE_idtype_idcode_is_only_appendable(short idcode);
+/**
+ * Check if an ID type can try to reuse and existing matching local one when being appended again.
+ *
+ * \param idcode: The IDType code to check.
+ * \return Boolean, false when it cannot be re-used, true otherwise.
+ */
+bool BKE_idtype_idcode_append_is_reusable(short idcode);
/* Macro currently, since any linkable IDtype should be localizable. */
#define BKE_idtype_idcode_is_localizable BKE_idtype_idcode_is_linkable
+/**
+ * Convert an ID-type name into an \a idcode (ie. #ID_SCE)
+ *
+ * \param idtype_name: The ID-type's "user visible name" to convert.
+ * \return The \a idcode for the name, or 0 if invalid.
+ */
short BKE_idtype_idcode_from_name(const char *idtype_name);
-uint64_t BKE_idtype_idcode_to_idfilter(const short idcode);
-short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter);
+/**
+ * Convert an \a idcode into an \a idfilter (e.g. #ID_OB -> #FILTER_ID_OB).
+ */
+uint64_t BKE_idtype_idcode_to_idfilter(short idcode);
+/**
+ * Convert an \a idfilter into an \a idcode (e.g. #FILTER_ID_OB -> #ID_OB).
+ */
+short BKE_idtype_idcode_from_idfilter(uint64_t idfilter);
-int BKE_idtype_idcode_to_index(const short idcode);
-short BKE_idtype_idcode_from_index(const int index);
+/**
+ * Convert an \a idcode into an index (e.g. #ID_OB -> #INDEX_ID_OB).
+ */
+int BKE_idtype_idcode_to_index(short idcode);
+/**
+ * Get an \a idcode from an index (e.g. #INDEX_ID_OB -> #ID_OB).
+ */
+short BKE_idtype_idcode_from_index(int index);
+/**
+ * Return an ID code and steps the index forward 1.
+ *
+ * \param index: start as 0.
+ * \return the code, 0 when all codes have been returned.
+ */
short BKE_idtype_idcode_iter_step(int *index);
/* Some helpers/wrappers around callbacks defined in #IDTypeInfo, dealing e.g. with embedded IDs.
* XXX Ideally those would rather belong to #BKE_lib_id, but using callback function pointers makes
* this hard to do properly if we want to avoid headers includes in headers. */
+/**
+ * Wrapper around #IDTypeInfo foreach_cache that also handles embedded IDs.
+ */
void BKE_idtype_id_foreach_cache(struct ID *id,
IDTypeForeachCacheFunctionCallback function_callback,
void *user_data);
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index b62ad3ad24a..80c6b155be0 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -36,6 +36,7 @@ struct ImageFormatData;
struct ImagePool;
struct ImageTile;
struct ImbFormatOptions;
+struct ListBase;
struct Main;
struct Object;
struct RenderResult;
@@ -47,15 +48,19 @@ struct anim;
#define IMA_MAX_SPACE 64
#define IMA_UDIM_MAX 2000
-void BKE_images_init(void);
-void BKE_images_exit(void);
-
void BKE_image_free_packedfiles(struct Image *image);
void BKE_image_free_views(struct Image *image);
void BKE_image_free_buffers(struct Image *image);
+/**
+ * Simply free the image data from memory,
+ * on display the image can load again (except for render buffers).
+ */
void BKE_image_free_buffers_ex(struct Image *image, bool do_lock);
void BKE_image_free_gputextures(struct Image *ima);
-/* call from library */
+/**
+ * Free (or release) any data used by this image (does not free the image itself).
+ * \note Call from library.
+ */
void BKE_image_free_data(struct Image *image);
typedef void(StampCallback)(void *data, const char *propname, char *propvalue, int len);
@@ -69,6 +74,9 @@ void BKE_render_result_stamp_info(struct Scene *scene,
* The caller is responsible for freeing the allocated memory.
*/
struct StampData *BKE_stamp_info_from_scene_static(const struct Scene *scene);
+/**
+ * Check whether the given metadata field name translates to a known field of a stamp.
+ */
bool BKE_stamp_is_known_field(const char *field_name);
void BKE_imbuf_stamp_info(struct RenderResult *rr, struct ImBuf *ibuf);
void BKE_stamp_info_from_imbuf(struct RenderResult *rr, struct ImBuf *ibuf);
@@ -93,46 +101,60 @@ int BKE_imbuf_write_stamp(struct Scene *scene,
struct ImBuf *ibuf,
const char *name,
const struct ImageFormatData *imf);
+/**
+ * \note imf->planes is ignored here, its assumed the image channels are already set.
+ */
void BKE_imbuf_write_prepare(struct ImBuf *ibuf, const struct ImageFormatData *imf);
int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, const struct ImageFormatData *imf);
+/**
+ * Same as #BKE_imbuf_write() but crappy workaround not to permanently modify _some_,
+ * values in the imbuf.
+ */
int BKE_imbuf_write_as(struct ImBuf *ibuf,
const char *name,
struct ImageFormatData *imf,
- const bool save_copy);
+ bool save_copy);
void BKE_image_path_from_imformat(char *string,
const char *base,
const char *relbase,
int frame,
const struct ImageFormatData *im_format,
- const bool use_ext,
- const bool use_frames,
+ bool use_ext,
+ bool use_frames,
const char *suffix);
void BKE_image_path_from_imtype(char *string,
const char *base,
const char *relbase,
int frame,
- const char imtype,
- const bool use_ext,
- const bool use_frames,
+ char imtype,
+ bool use_ext,
+ bool use_frames,
const char *suffix);
int BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format);
-int BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype);
-char BKE_image_ftype_to_imtype(const int ftype, const struct ImbFormatOptions *options);
-int BKE_image_imtype_to_ftype(const char imtype, struct ImbFormatOptions *r_options);
-
-bool BKE_imtype_is_movie(const char imtype);
-bool BKE_imtype_supports_zbuf(const char imtype);
-bool BKE_imtype_supports_compress(const char imtype);
-bool BKE_imtype_supports_quality(const char imtype);
-bool BKE_imtype_requires_linear_float(const char imtype);
-char BKE_imtype_valid_channels(const char imtype, bool write_file);
-char BKE_imtype_valid_depths(const char imtype);
+int BKE_image_path_ensure_ext_from_imtype(char *string, char imtype);
+char BKE_image_ftype_to_imtype(int ftype, const struct ImbFormatOptions *options);
+int BKE_image_imtype_to_ftype(char imtype, struct ImbFormatOptions *r_options);
+
+bool BKE_imtype_is_movie(char imtype);
+bool BKE_imtype_supports_zbuf(char imtype);
+bool BKE_imtype_supports_compress(char imtype);
+bool BKE_imtype_supports_quality(char imtype);
+bool BKE_imtype_requires_linear_float(char imtype);
+char BKE_imtype_valid_channels(char imtype, bool write_file);
+char BKE_imtype_valid_depths(char imtype);
+/**
+ * String is from command line `--render-format` argument,
+ * keep in sync with `creator_args.c` help info.
+ */
char BKE_imtype_from_arg(const char *arg);
void BKE_imformat_defaults(struct ImageFormatData *im_format);
void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const struct ImBuf *imbuf);
+/**
+ * Used by sequencer too.
+ */
struct anim *openanim(const char *name,
int flags,
int streamindex,
@@ -153,10 +175,6 @@ struct RenderData;
struct RenderPass;
struct RenderResult;
-/* ima->ok */
-#define IMA_OK 1
-#define IMA_OK_LOADED 2
-
/* signals */
/* reload only frees, doesn't read until image_get_ibuf() called */
#define IMA_SIGNAL_RELOAD 0
@@ -171,11 +189,18 @@ struct RenderResult;
#define IMA_CHAN_FLAG_RGB 2
#define IMA_CHAN_FLAG_ALPHA 4
-/* checks whether there's an image buffer for given image and user */
+/**
+ * Checks whether there's an image buffer for given image and user.
+ */
bool BKE_image_has_ibuf(struct Image *ima, struct ImageUser *iuser);
-/* same as above, but can be used to retrieve images being rendered in
- * a thread safe way, always call both acquire and release */
+/**
+ * Return image buffer for given image and user:
+ * - will lock render result if image type is render result and lock is not NULL
+ * - will return NULL if image is NULL or image type is render or composite result and lock is NULL
+ *
+ * References the result, #BKE_image_release_ibuf should be used to de-reference.
+ */
struct ImBuf *BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock);
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock);
@@ -186,17 +211,28 @@ struct ImBuf *BKE_image_pool_acquire_ibuf(struct Image *ima,
struct ImagePool *pool);
void BKE_image_pool_release_ibuf(struct Image *ima, struct ImBuf *ibuf, struct ImagePool *pool);
-/* set an alpha mode based on file extension */
+/**
+ * Set an alpha mode based on file extension.
+ */
char BKE_image_alpha_mode_from_extension_ex(const char *filepath);
void BKE_image_alpha_mode_from_extension(struct Image *image);
-/* returns a new image or NULL if it can't load */
+/**
+ * Returns a new image or NULL if it can't load.
+ */
struct Image *BKE_image_load(struct Main *bmain, const char *filepath);
-/* returns existing Image when filename/type is same (frame optional) */
+/**
+ * Returns existing Image when filename/type is same.
+ *
+ * Checks if image was already loaded, then returns same image otherwise creates new
+ * (does not load ibuf itself).
+ */
struct Image *BKE_image_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists);
struct Image *BKE_image_load_exists(struct Main *bmain, const char *filepath);
-/* adds image, adds ibuf, generates color or pattern */
+/**
+ * Adds new image block, creates ImBuf and initializes color.
+ */
struct Image *BKE_image_add_generated(struct Main *bmain,
unsigned int width,
unsigned int height,
@@ -205,13 +241,18 @@ struct Image *BKE_image_add_generated(struct Main *bmain,
int floatbuf,
short gen_type,
const float color[4],
- const bool stereo3d,
- const bool is_data,
- const bool tiled);
-/* adds image from imbuf, owns imbuf */
+ bool stereo3d,
+ bool is_data,
+ bool tiled);
+/**
+ * Create an image from ibuf. The reference-count of ibuf is increased,
+ * caller should take care to drop its reference by calling #IMB_freeImBuf if needed.
+ */
struct Image *BKE_image_add_from_imbuf(struct Main *bmain, struct ImBuf *ibuf, const char *name);
-/* for reload, refresh, pack */
+/**
+ * For reload, refresh, pack.
+ */
void BKE_imageuser_default(struct ImageUser *iuser);
void BKE_image_init_imageuser(struct Image *ima, struct ImageUser *iuser);
void BKE_image_signal(struct Main *bmain, struct Image *ima, struct ImageUser *iuser, int signal);
@@ -223,89 +264,156 @@ void BKE_image_walk_all_users(const struct Main *mainp,
struct ImageUser *iuser,
void *customdata));
-/* ensures an Image exists for viewing nodes or render */
+/**
+ * Ensures an Image exists for viewing nodes or render
+ * forces existence of 1 Image for render-output or nodes, returns Image.
+ *
+ * \param name: Only for default, when making new one.
+ */
struct Image *BKE_image_ensure_viewer(struct Main *bmain, int type, const char *name);
-/* ensures the view node cache is compatible with the scene views */
+/**
+ * Ensures the view node cache is compatible with the scene views.
+ * Reset the image cache and views when the Viewer Nodes views don't match the scene views.
+ */
void BKE_image_ensure_viewer_views(const struct RenderData *rd,
struct Image *ima,
struct ImageUser *iuser);
-/* called on frame change or before render */
+/**
+ * Called on frame change or before render.
+ */
void BKE_image_user_frame_calc(struct Image *ima, struct ImageUser *iuser, int cfra);
int BKE_image_user_frame_get(const struct ImageUser *iuser, int cfra, bool *r_is_in_range);
void BKE_image_user_file_path(struct ImageUser *iuser, struct Image *ima, char *path);
+void BKE_image_user_file_path_ex(struct ImageUser *iuser,
+ struct Image *ima,
+ char *path,
+ bool resolve_udim);
void BKE_image_editors_update_frame(const struct Main *bmain, int cfra);
-/* dependency graph update for image user users */
+/**
+ * Dependency graph update for image user users.
+ */
bool BKE_image_user_id_has_animation(struct ID *id);
void BKE_image_user_id_eval_animation(struct Depsgraph *depsgraph, struct ID *id);
-/* sets index offset for multilayer files */
+/**
+ * Sets index offset for multi-layer files and because rendered results use fake layer/passes,
+ * don't correct for wrong indices here.
+ */
struct RenderPass *BKE_image_multilayer_index(struct RenderResult *rr, struct ImageUser *iuser);
-/* sets index offset for multiview files */
+/**
+ * Sets index offset for multi-view files.
+ */
void BKE_image_multiview_index(struct Image *ima, struct ImageUser *iuser);
-/* for multilayer images as well as for render-viewer */
+/**
+ * For multi-layer images as well as for render-viewer
+ * and because rendered results use fake layer/passes, don't correct for wrong indices here.
+ */
bool BKE_image_is_multilayer(struct Image *ima);
bool BKE_image_is_multiview(struct Image *ima);
bool BKE_image_is_stereo(struct Image *ima);
struct RenderResult *BKE_image_acquire_renderresult(struct Scene *scene, struct Image *ima);
void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima);
-/* for multilayer images as well as for singlelayer */
+/**
+ * For multi-layer images as well as for single-layer.
+ */
bool BKE_image_is_openexr(struct Image *ima);
-/* for multiple slot render, call this before render */
+/**
+ * For multiple slot render, call this before render.
+ */
void BKE_image_backup_render(struct Scene *scene, struct Image *ima, bool free_current_slot);
-/* for singlelayer openexr saving */
+/**
+ * For single-layer OpenEXR saving.
+ */
bool BKE_image_save_openexr_multiview(struct Image *ima,
struct ImBuf *ibuf,
const char *filepath,
- const int flags);
+ int flags);
-/* goes over all textures that use images */
+/**
+ * Goes over all textures that use images.
+ */
void BKE_image_free_all_textures(struct Main *bmain);
-/* does one image! */
+/**
+ * Operates on one image only!
+ * \param except_frame: This is weak, only works for sequences without offset.
+ */
void BKE_image_free_anim_ibufs(struct Image *ima, int except_frame);
-/* does all images with type MOVIE or SEQUENCE */
+/**
+ * Does all images with type MOVIE or SEQUENCE.
+ */
void BKE_image_all_free_anim_ibufs(struct Main *bmain, int cfra);
void BKE_image_free_all_gputextures(struct Main *bmain);
+/**
+ * Same as above but only free animated images.
+ */
void BKE_image_free_anim_gputextures(struct Main *bmain);
void BKE_image_free_old_gputextures(struct Main *bmain);
+/**
+ * Pack image to memory.
+ */
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,
struct Image *ima,
char *data,
- const size_t data_len);
+ size_t data_len);
-/* prints memory statistics for images */
+/**
+ * Prints memory statistics for images.
+ */
void BKE_image_print_memlist(struct Main *bmain);
-/* merge source into dest, and free source */
+/**
+ * Merge source into `dest`, and free `source`.
+ */
void BKE_image_merge(struct Main *bmain, struct Image *dest, struct Image *source);
-/* scale the image */
+/**
+ * Scale the image.
+ */
bool BKE_image_scale(struct Image *image, int width, int height);
-/* check if texture has alpha (depth=32) */
+/**
+ * Check if texture has alpha (depth=32).
+ */
bool BKE_image_has_alpha(struct Image *image);
-/* check if texture has gpu texture code */
+/**
+ * Check if texture has GPU texture code.
+ */
bool BKE_image_has_opengl_texture(struct Image *ima);
-/* get tile index for tiled images */
+/**
+ * Get tile index for tiled images.
+ */
void BKE_image_get_tile_label(struct Image *ima,
struct ImageTile *tile,
char *label,
int len_label);
+/**
+ * Checks whether the given filepath refers to a UDIM tiled texture.
+ * If yes, the range from the lowest to the highest tile is returned.
+ *
+ * `filepath` may be modified to ensure a UDIM token is present.
+ * `tiles` may be filled even if the result ultimately is false!
+ */
+bool BKE_image_get_tile_info(char *filepath,
+ struct ListBase *tiles,
+ int *tile_start,
+ int *tile_range);
+
struct ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label);
bool BKE_image_remove_tile(struct Image *ima, struct ImageTile *tile);
void BKE_image_reassign_tile(struct Image *ima, struct ImageTile *tile, int new_tile_number);
@@ -320,6 +428,41 @@ bool BKE_image_fill_tile(struct Image *ima,
int planes,
bool is_float);
+typedef enum {
+ UDIM_TILE_FORMAT_NONE = 0,
+ UDIM_TILE_FORMAT_UDIM = 1,
+ UDIM_TILE_FORMAT_UVTILE = 2
+} eUDIM_TILE_FORMAT;
+
+/**
+ * Ensures that `filename` contains a UDIM token if we find a supported format pattern.
+ * \note This must only be the name component (without slashes).
+ */
+void BKE_image_ensure_tile_token(char *filename);
+
+/**
+ * When provided with an absolute virtual filepath, check to see if at least
+ * one concrete file exists.
+ * Note: This function requires directory traversal and may be inefficient in time-critical,
+ * or iterative, code paths.
+ */
+bool BKE_image_tile_filepath_exists(const char *filepath);
+
+/**
+ * Retrieves the UDIM token format and returns the pattern from the provided `filepath`.
+ * The returned pattern is typically passed to either `BKE_image_get_tile_number_from_filepath` or
+ * `BKE_image_set_filepath_from_tile_number`.
+ */
+char *BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format);
+bool BKE_image_get_tile_number_from_filepath(const char *filepath,
+ const char *pattern,
+ eUDIM_TILE_FORMAT tile_format,
+ int *r_tile_number);
+void BKE_image_set_filepath_from_tile_number(char *filepath,
+ const char *pattern,
+ eUDIM_TILE_FORMAT tile_format,
+ int tile_number);
+
struct ImageTile *BKE_image_get_tile(struct Image *ima, int tile_number);
struct ImageTile *BKE_image_get_tile_from_iuser(struct Image *ima, const struct ImageUser *iuser);
@@ -327,6 +470,9 @@ int BKE_image_get_tile_from_pos(struct Image *ima,
const float uv[2],
float r_uv[2],
float r_ofs[2]);
+/**
+ * Return the tile_number for the closest UDIM tile.
+ */
int BKE_image_find_nearest_tile(const struct Image *image, const float co[2]);
void BKE_image_get_size(struct Image *image, struct ImageUser *iuser, int *r_width, int *r_height);
@@ -334,6 +480,7 @@ void BKE_image_get_size_fl(struct Image *image, struct ImageUser *iuser, float r
void BKE_image_get_aspect(struct Image *image, float *r_aspx, float *r_aspy);
/* image_gen.c */
+
void BKE_image_buf_fill_color(
unsigned char *rect, float *rect_float, int width, int height, const float color[4]);
void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height);
@@ -343,36 +490,64 @@ void BKE_image_buf_fill_checker_color(unsigned char *rect,
int height);
/* Cycles hookup */
+
unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame, int tile);
float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int tile);
/* Image modifications */
+
bool BKE_image_is_dirty(struct Image *image);
void BKE_image_mark_dirty(struct Image *image, struct ImBuf *ibuf);
bool BKE_image_buffer_format_writable(struct ImBuf *ibuf);
+
bool BKE_image_is_dirty_writable(struct Image *image, bool *is_format_writable);
-/* Guess offset for the first frame in the sequence */
+/**
+ * Guess offset for the first frame in the sequence.
+ */
int BKE_image_sequence_guess_offset(struct Image *image);
bool BKE_image_has_anim(struct Image *image);
-bool BKE_image_has_packedfile(struct Image *image);
+bool BKE_image_has_packedfile(const struct Image *image);
bool BKE_image_has_filepath(struct Image *ima);
+/**
+ * Checks the image buffer changes with time (not keyframed values).
+ */
bool BKE_image_is_animated(struct Image *image);
+/**
+ * Checks whether the image consists of multiple buffers.
+ */
bool BKE_image_has_multiple_ibufs(struct Image *image);
void BKE_image_file_format_set(struct Image *image,
int ftype,
const struct ImbFormatOptions *options);
bool BKE_image_has_loaded_ibuf(struct Image *image);
+/**
+ * References the result, #BKE_image_release_ibuf is to be called to de-reference.
+ * Use lock=NULL when calling #BKE_image_release_ibuf().
+ */
struct ImBuf *BKE_image_get_ibuf_with_name(struct Image *image, const char *name);
+/**
+ * References the result, #BKE_image_release_ibuf is to be called to de-reference.
+ * Use lock=NULL when calling #BKE_image_release_ibuf().
+ *
+ * TODO(sergey): This is actually "get first item from the cache", which is
+ * not so much predictable. But using first loaded image buffer
+ * was also malicious logic and all the areas which uses this
+ * function are to be re-considered.
+ */
struct ImBuf *BKE_image_get_first_ibuf(struct Image *image);
-/* Not to be use directly. */
+/**
+ * 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`.
+/**
+ * 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. */
+ * 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);
@@ -382,14 +557,33 @@ struct GPUTexture *BKE_image_get_gpu_tiles(struct Image *image,
struct GPUTexture *BKE_image_get_gpu_tilemap(struct Image *image,
struct ImageUser *iuser,
struct ImBuf *ibuf);
+/**
+ * Is the alpha of the `GPUTexture` for a given image/ibuf premultiplied.
+ */
bool BKE_image_has_gpu_texture_premultiplied_alpha(struct Image *image, struct ImBuf *ibuf);
+/**
+ * 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(
struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h);
+/**
+ * Mark areas on the #GPUTexture that needs to be updated. The areas are marked in chunks.
+ * The next time the #GPUTexture is used these tiles will be refreshes. This saves time
+ * when writing to the same place multiple times This happens for during foreground rendering.
+ */
void BKE_image_update_gputexture_delayed(
struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h);
+/**
+ * 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(struct Main *bmain, bool mipmap);
-/* Delayed free of OpenGL buffers by main thread */
+/**
+ * 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);
diff --git a/source/blender/blenkernel/BKE_ipo.h b/source/blender/blenkernel/BKE_ipo.h
index f4871c83caf..5899db6c6ce 100644
--- a/source/blender/blenkernel/BKE_ipo.h
+++ b/source/blender/blenkernel/BKE_ipo.h
@@ -28,6 +28,19 @@ extern "C" {
struct Main;
+/**
+ * Called from #do_versions() in `readfile.c` to convert the old 'IPO/adrcode' system
+ * to the new 'Animato/RNA' system.
+ *
+ * The basic method used here, is to loop over data-blocks which have IPO-data,
+ * and add those IPO's to new AnimData blocks as Actions.
+ * Action/NLA data only works well for Objects, so these only need to be checked for there.
+ *
+ * Data that has been converted should be freed immediately, which means that it is immediately
+ * clear which data-blocks have yet to be converted, and also prevent freeing errors when we exit.
+ *
+ * \note Currently done after all file reading.
+ */
void do_versions_ipos_to_animato(struct Main *main);
/* --------------------- xxx stuff ------------------------ */
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index cb4fc607703..07e816558df 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -36,42 +36,90 @@ struct Object;
extern "C" {
#endif
+/**
+ * Free (or release) any data used by this shapekey (does not free the key itself).
+ */
void BKE_key_free_data(struct Key *key);
void BKE_key_free_nolib(struct Key *key);
struct Key *BKE_key_add(struct Main *bmain, struct ID *id);
+/**
+ * Sort shape keys after a change.
+ * This assumes that at most one key was moved,
+ * which is a valid assumption for the places it's currently being called.
+ */
void BKE_key_sort(struct Key *key);
void key_curve_position_weights(float t, float data[4], int type);
+/**
+ * First derivative.
+ */
void key_curve_tangent_weights(float t, float data[4], int type);
+/**
+ * Second derivative.
+ */
void key_curve_normal_weights(float t, float data[4], int type);
+/**
+ * Returns key coordinates (+ tilt) when key applied, NULL otherwise.
+ */
float *BKE_key_evaluate_object_ex(struct Object *ob, int *r_totelem, float *arr, size_t arr_size);
float *BKE_key_evaluate_object(struct Object *ob, int *r_totelem);
-int BKE_keyblock_element_count_from_shape(const struct Key *key, const int shape_index);
+/**
+ * \param shape_index: The index to use or all (when -1).
+ */
+int BKE_keyblock_element_count_from_shape(const struct Key *key, int shape_index);
int BKE_keyblock_element_count(const struct Key *key);
-size_t BKE_keyblock_element_calc_size_from_shape(const struct Key *key, const int shape_index);
+/**
+ * \param shape_index: The index to use or all (when -1).
+ */
+size_t BKE_keyblock_element_calc_size_from_shape(const struct Key *key, int shape_index);
size_t BKE_keyblock_element_calc_size(const struct Key *key);
-bool BKE_key_idtype_support(const short id_type);
+bool BKE_key_idtype_support(short id_type);
struct Key **BKE_key_from_id_p(struct ID *id);
struct Key *BKE_key_from_id(struct ID *id);
struct Key **BKE_key_from_object_p(const struct Object *ob);
struct Key *BKE_key_from_object(const struct Object *ob);
+/**
+ * Only the active key-block.
+ */
struct KeyBlock *BKE_keyblock_from_object(struct Object *ob);
struct KeyBlock *BKE_keyblock_from_object_reference(struct Object *ob);
struct KeyBlock *BKE_keyblock_add(struct Key *key, const char *name);
-struct KeyBlock *BKE_keyblock_add_ctime(struct Key *key, const char *name, const bool do_force);
+/**
+ * \note sorting is a problematic side effect in some cases,
+ * better only do this explicitly by having its own function,
+ *
+ * \param key: The key datablock to add to.
+ * \param name: Optional name for the new keyblock.
+ * \param do_force: always use ctime even for relative keys.
+ */
+struct KeyBlock *BKE_keyblock_add_ctime(struct Key *key, const char *name, bool do_force);
+/**
+ * Get the appropriate #KeyBlock given an index.
+ */
struct KeyBlock *BKE_keyblock_from_key(struct Key *key, int index);
+/**
+ * Get the appropriate #KeyBlock given a name to search for.
+ */
struct KeyBlock *BKE_keyblock_find_name(struct Key *key, const char name[]);
+/**
+ * \brief copy shape-key attributes, but not key data or name/UID.
+ */
void BKE_keyblock_copy_settings(struct KeyBlock *kb_dst, const struct KeyBlock *kb_src);
+/**
+ * Get RNA-Path for 'value' setting of the given shape-key.
+ * \note the user needs to free the returned string once they're finished with it.
+ */
char *BKE_keyblock_curval_rnapath_get(struct Key *key, struct KeyBlock *kb);
/* conversion functions */
/* NOTE: 'update_from' versions do not (re)allocate mem in kb, while 'convert_from' do. */
+
void BKE_keyblock_update_from_lattice(struct Lattice *lt, struct KeyBlock *kb);
void BKE_keyblock_convert_from_lattice(struct Lattice *lt, struct KeyBlock *kb);
void BKE_keyblock_convert_to_lattice(struct KeyBlock *kb, struct Lattice *lt);
@@ -88,6 +136,15 @@ void BKE_keyblock_convert_to_curve(struct KeyBlock *kb, struct Curve *cu, struct
void BKE_keyblock_update_from_mesh(struct Mesh *me, struct KeyBlock *kb);
void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct Key *key, struct KeyBlock *kb);
void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct Mesh *me);
+/**
+ * Computes normals (vertices, polygons and/or loops ones) of given mesh for given shape key.
+ *
+ * \param kb: the KeyBlock to use to compute normals.
+ * \param mesh: the Mesh to apply key-block to.
+ * \param r_vertnors: if non-NULL, an array of vectors, same length as number of vertices.
+ * \param r_polynors: if non-NULL, an array of vectors, same length as number of polygons.
+ * \param r_loopnors: if non-NULL, an array of vectors, same length as number of loops.
+ */
void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
struct Mesh *mesh,
float (*r_vertnors)[3],
@@ -107,29 +164,53 @@ void BKE_keyblock_update_from_offset(struct Object *ob,
const float (*ofs)[3]);
/* other management */
+
+/**
+ * Move shape key from org_index to new_index. Safe, clamps index to valid range,
+ * updates reference keys, the object's active shape index,
+ * the 'frame' value in case of absolute keys, etc.
+ * Note indices are expected in real values (not 'fake' shapenr +1 ones).
+ *
+ * \param org_index: if < 0, current object's active shape will be used as skey to move.
+ * \return true if something was done, else false.
+ */
bool BKE_keyblock_move(struct Object *ob, int org_index, int new_index);
-bool BKE_keyblock_is_basis(struct Key *key, const int index);
+/**
+ * Check if given key-block (as index) is used as basis by others in given key.
+ */
+bool BKE_keyblock_is_basis(struct Key *key, int index);
/* -------------------------------------------------------------------- */
/** \name Key-Block Data Access
* \{ */
-void BKE_keyblock_data_get_from_shape(const struct Key *key,
- float (*arr)[3],
- const int shape_index);
+/**
+ * \param shape_index: The index to use or all (when -1).
+ */
+void BKE_keyblock_data_get_from_shape(const struct Key *key, float (*arr)[3], int shape_index);
void BKE_keyblock_data_get(const struct Key *key, float (*arr)[3]);
+/**
+ * Set the data to all key-blocks (or shape_index if != -1).
+ */
void BKE_keyblock_data_set_with_mat4(struct Key *key,
- const int shape_index,
+ int shape_index,
const float (*coords)[3],
const float mat[4][4]);
+/**
+ * Set the data for all key-blocks (or shape_index if != -1),
+ * transforming by \a mat.
+ */
void BKE_keyblock_curve_data_set_with_mat4(struct Key *key,
const struct ListBase *nurb,
- const int shape_index,
+ int shape_index,
const void *data,
const float mat[4][4]);
-void BKE_keyblock_data_set(struct Key *key, const int shape_index, const void *data);
+/**
+ * Set the data for all key-blocks (or shape_index if != -1).
+ */
+void BKE_keyblock_data_set(struct Key *key, int shape_index, const void *data);
/** \} */
diff --git a/source/blender/blenkernel/BKE_keyconfig.h b/source/blender/blenkernel/BKE_keyconfig.h
index 1cacbf61976..132994ede3a 100644
--- a/source/blender/blenkernel/BKE_keyconfig.h
+++ b/source/blender/blenkernel/BKE_keyconfig.h
@@ -43,10 +43,12 @@ typedef struct wmKeyConfigPrefType_Runtime {
typedef struct wmKeyConfigPrefType_Runtime wmKeyConfigPrefType_Runtime;
#endif
-/* KeyConfig preferences (UserDef). */
+/* KeyConfig preferences (#UserDef). */
+
struct wmKeyConfigPref *BKE_keyconfig_pref_ensure(struct UserDef *userdef, const char *kc_idname);
/* KeyConfig preferences (RNA). */
+
struct wmKeyConfigPrefType_Runtime *BKE_keyconfig_pref_type_find(const char *idname, bool quiet);
void BKE_keyconfig_pref_type_add(struct wmKeyConfigPrefType_Runtime *kpt_rt);
void BKE_keyconfig_pref_type_remove(const struct wmKeyConfigPrefType_Runtime *kpt_rt);
@@ -55,6 +57,10 @@ void BKE_keyconfig_pref_type_init(void);
void BKE_keyconfig_pref_type_free(void);
/* Versioning. */
+
+/**
+ * Set select mouse, for versioning code.
+ */
void BKE_keyconfig_pref_set_select_mouse(struct UserDef *userdef, int value, bool override);
struct wmKeyConfigFilterItemParams {
@@ -67,6 +73,10 @@ void BKE_keyconfig_keymap_filter_item(struct wmKeyMap *keymap,
const struct wmKeyConfigFilterItemParams *params,
bool (*filter_fn)(struct wmKeyMapItem *kmi, void *user_data),
void *user_data);
+/**
+ * Filter & optionally remove key-map items,
+ * intended for versioning, but may be used in other situations too.
+ */
void BKE_keyconfig_pref_filter_items(struct UserDef *userdef,
const struct wmKeyConfigFilterItemParams *params,
bool (*filter_fn)(struct wmKeyMapItem *kmi, void *user_data),
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index 02fa8b306d3..35260aa3852 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -69,15 +69,11 @@ void BKE_lattice_transform(struct Lattice *lt, const float mat[4][4], bool do_ke
bool BKE_lattice_is_any_selected(const struct Lattice *lt);
-int BKE_lattice_index_from_uvw(struct Lattice *lt, const int u, const int v, const int w);
-void BKE_lattice_index_to_uvw(struct Lattice *lt, const int index, int *r_u, int *r_v, int *r_w);
-int BKE_lattice_index_flip(
- struct Lattice *lt, const int index, const bool flip_u, const bool flip_v, const bool flip_w);
-void BKE_lattice_bitmap_from_flag(struct Lattice *lt,
- unsigned int *bitmap,
- const uint8_t flag,
- const bool clear,
- const bool respecthide);
+int BKE_lattice_index_from_uvw(struct Lattice *lt, int u, int v, int w);
+void BKE_lattice_index_to_uvw(struct Lattice *lt, int index, int *r_u, int *r_v, int *r_w);
+int BKE_lattice_index_flip(struct Lattice *lt, int index, bool flip_u, bool flip_v, bool flip_w);
+void BKE_lattice_bitmap_from_flag(
+ struct Lattice *lt, unsigned int *bitmap, uint8_t flag, bool clear, bool respecthide);
/* **** Depsgraph evaluation **** */
@@ -110,28 +106,29 @@ void BKE_lattice_deform_data_destroy(struct LatticeDeformData *lattice_deform_da
void BKE_lattice_deform_coords(const struct Object *ob_lattice,
const struct Object *ob_target,
float (*vert_coords)[3],
- const int vert_coords_len,
- const short flag,
+ int vert_coords_len,
+ short flag,
const char *defgrp_name,
float fac);
void BKE_lattice_deform_coords_with_mesh(const struct Object *ob_lattice,
const struct Object *ob_target,
float (*vert_coords)[3],
- const int vert_coords_len,
- const short flag,
+ int vert_coords_len,
+ short flag,
const char *defgrp_name,
- const float fac,
+ float fac,
const struct Mesh *me_target);
void BKE_lattice_deform_coords_with_editmesh(const struct Object *ob_lattice,
const struct Object *ob_target,
float (*vert_coords)[3],
- const int vert_coords_len,
- const short flag,
+ int vert_coords_len,
+ short flag,
const char *defgrp_name,
- const float fac,
+ float fac,
struct BMEditMesh *em_target);
+
/** \} */
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index c8af1a91725..accdfe1ca25 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -52,23 +52,57 @@ typedef enum eViewLayerCopyMethod {
VIEWLAYER_ADD_COPY = 2,
} eViewLayerCopyMethod;
+/**
+ * Returns the default view layer to view in work-spaces if there is
+ * none linked to the workspace yet.
+ */
struct ViewLayer *BKE_view_layer_default_view(const struct Scene *scene);
+/**
+ * Returns the default view layer to render if we need to render just one.
+ */
struct ViewLayer *BKE_view_layer_default_render(const struct Scene *scene);
+/**
+ * Returns view layer with matching name, or NULL if not found.
+ */
struct ViewLayer *BKE_view_layer_find(const struct Scene *scene, const char *layer_name);
+/**
+ * Add a new view layer by default, a view layer has the master collection.
+ */
struct ViewLayer *BKE_view_layer_add(struct Scene *scene,
const char *name,
struct ViewLayer *view_layer_source,
- const int type);
+ int type);
/* DEPRECATED */
+/**
+ * This is a placeholder to know which areas of the code need to be addressed
+ * for the Workspace changes. Never use this, you should typically get the
+ * active layer from the context or window.
+ */
struct ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const struct Scene *scene);
void BKE_view_layer_free(struct ViewLayer *view_layer);
-void BKE_view_layer_free_ex(struct ViewLayer *view_layer, const bool do_id_user);
+/**
+ * Free (or release) any data used by this #ViewLayer.
+ */
+void BKE_view_layer_free_ex(struct ViewLayer *view_layer, bool do_id_user);
-void BKE_view_layer_selected_objects_tag(struct ViewLayer *view_layer, const int tag);
+/**
+ * Tag all the selected objects of a render-layer.
+ */
+void BKE_view_layer_selected_objects_tag(struct ViewLayer *view_layer, int tag);
+/**
+ * Fallback for when a Scene has no camera to use.
+ *
+ * \param view_layer: in general you want to use the same #ViewLayer that is used for depsgraph.
+ * If rendering you pass the scene active layer, when viewing in the viewport
+ * you want to get #ViewLayer from context.
+ */
struct Object *BKE_view_layer_camera_find(struct ViewLayer *view_layer);
+/**
+ * Find the #ViewLayer a #LayerCollection belongs to.
+ */
struct ViewLayer *BKE_view_layer_find_from_collection(const struct Scene *scene,
struct LayerCollection *lc);
struct Base *BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob);
@@ -76,47 +110,100 @@ void BKE_view_layer_base_deselect_all(struct ViewLayer *view_layer);
void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, struct Base *selbase);
+/**
+ * Only copy internal data of #ViewLayer from source to already allocated/initialized destination.
+ *
+ * \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more).
+ */
void BKE_view_layer_copy_data(struct Scene *scene_dst,
const struct Scene *scene_src,
struct ViewLayer *view_layer_dst,
const struct ViewLayer *view_layer_src,
- const int flag);
+ int flag);
void BKE_view_layer_rename(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
const char *name);
+/**
+ * Get the active collection
+ */
struct LayerCollection *BKE_layer_collection_get_active(struct ViewLayer *view_layer);
+/**
+ * Activate collection
+ */
bool BKE_layer_collection_activate(struct ViewLayer *view_layer, struct LayerCollection *lc);
+/**
+ * Activate first parent collection.
+ */
struct LayerCollection *BKE_layer_collection_activate_parent(struct ViewLayer *view_layer,
struct LayerCollection *lc);
+/**
+ * Get the total number of collections (including all the nested collections)
+ */
int BKE_layer_collection_count(const struct ViewLayer *view_layer);
-struct LayerCollection *BKE_layer_collection_from_index(struct ViewLayer *view_layer,
- const int index);
+/**
+ * Get the collection for a given index.
+ */
+struct LayerCollection *BKE_layer_collection_from_index(struct ViewLayer *view_layer, int index);
+/**
+ * \return -1 if not found.
+ */
int BKE_layer_collection_findindex(struct ViewLayer *view_layer, const struct LayerCollection *lc);
void BKE_layer_collection_resync_forbid(void);
void BKE_layer_collection_resync_allow(void);
+/**
+ * Helper to fix older pre-2.80 blend-files.
+ *
+ * Ensures the given `view_layer` as a valid first-level layer collection, i.e. a single one
+ * matching the scene's master collection. This is a requirement for `BKE_layer_collection_sync`.
+ */
+void BKE_layer_collection_doversion_2_80(const struct Scene *scene, struct ViewLayer *view_layer);
+
void BKE_main_collection_sync(const struct Main *bmain);
void BKE_scene_collection_sync(const struct Scene *scene);
+/**
+ * Update view layer collection tree from collections used in the scene.
+ * This is used when collections are removed or added, both while editing
+ * and on file loaded in case linked data changed or went missing.
+ */
void BKE_layer_collection_sync(const struct Scene *scene, struct ViewLayer *view_layer);
void BKE_layer_collection_local_sync(struct ViewLayer *view_layer, const struct View3D *v3d);
+/**
+ * Sync the local collection for all the 3D Viewports.
+ */
void BKE_layer_collection_local_sync_all(const struct Main *bmain);
void BKE_main_collection_sync_remap(const struct Main *bmain);
+/**
+ * Return the first matching #LayerCollection in the #ViewLayer for the Collection.
+ */
struct LayerCollection *BKE_layer_collection_first_from_scene_collection(
const struct ViewLayer *view_layer, const struct Collection *collection);
+/**
+ * See if view layer has the scene collection linked directly, or indirectly (nested).
+ */
bool BKE_view_layer_has_collection(const struct ViewLayer *view_layer,
const struct Collection *collection);
+/**
+ * See if the object is in any of the scene layers of the scene.
+ */
bool BKE_scene_has_object(struct Scene *scene, struct Object *ob);
-/* selection and hiding */
+/* Selection and hiding. */
+/**
+ * Select all the objects of this layer collection
+ *
+ * It also select the objects that are in nested collections.
+ * \note Recursive.
+ */
bool BKE_layer_collection_objects_select(struct ViewLayer *view_layer,
struct LayerCollection *lc,
bool deselect);
@@ -125,28 +212,54 @@ bool BKE_layer_collection_has_selected_objects(struct ViewLayer *view_layer,
bool BKE_layer_collection_has_layer_collection(struct LayerCollection *lc_parent,
struct LayerCollection *lc_child);
+/**
+ * Update after toggling visibility of an object base.
+ */
void BKE_base_set_visible(struct Scene *scene,
struct ViewLayer *view_layer,
struct Base *base,
bool extend);
bool BKE_base_is_visible(const struct View3D *v3d, const struct Base *base);
bool BKE_object_is_visible_in_viewport(const struct View3D *v3d, const struct Object *ob);
+/**
+ * Isolate the collection - hide all other collections but this one.
+ * Make sure to show all the direct parents and all children of the layer collection as well.
+ * When extending we simply show the collections and its direct family.
+ *
+ * If the collection or any of its parents is disabled, make it enabled.
+ * Don't change the children disable state though.
+ */
void BKE_layer_collection_isolate_global(struct Scene *scene,
struct ViewLayer *view_layer,
struct LayerCollection *lc,
bool extend);
+/**
+ * Isolate the collection locally
+ *
+ * Same as #BKE_layer_collection_isolate_local but for a viewport
+ */
void BKE_layer_collection_isolate_local(struct ViewLayer *view_layer,
const struct View3D *v3d,
struct LayerCollection *lc,
bool extend);
+/**
+ * Hide/show all the elements of a collection.
+ * Don't change the collection children enable/disable state,
+ * but it may change it for the collection itself.
+ */
void BKE_layer_collection_set_visible(struct ViewLayer *view_layer,
struct LayerCollection *lc,
- const bool visible,
- const bool hierarchy);
-void BKE_layer_collection_set_flag(struct LayerCollection *lc, const int flag, const bool value);
+ bool visible,
+ bool hierarchy);
+void BKE_layer_collection_set_flag(struct LayerCollection *lc, int flag, bool value);
-/* evaluation */
+/* Evaluation. */
+/**
+ * Applies object's restrict flags on top of flags coming from the collection
+ * and stores those in `base->flag`. #BASE_VISIBLE_DEPSGRAPH ignores viewport flags visibility
+ * (i.e., restriction and local collection).
+ */
void BKE_base_eval_flags(struct Base *base);
void BKE_layer_eval_view_layer_indexed(struct Depsgraph *depsgraph,
@@ -328,7 +441,7 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter);
{ \
Object *_instance; \
Base *_base; \
- for (_base = (view_layer)->object_bases.first; _base; _base = _base->next) { \
+ for (_base = (Base *)(view_layer)->object_bases.first; _base; _base = _base->next) { \
_instance = _base->object;
#define FOREACH_OBJECT_END \
@@ -380,6 +493,13 @@ struct Object **BKE_view_layer_array_selected_objects_params(
uint *r_len,
const struct ObjectsInViewLayerParams *params);
+/**
+ * Use this in rare cases we need to detect a pair of objects (active, selected).
+ * This returns the other non-active selected object.
+ *
+ * Returns NULL with it finds multiple other selected objects
+ * as behavior in this case would be random from the user perspective.
+ */
struct Object *BKE_view_layer_non_active_selected_object(struct ViewLayer *view_layer,
const struct View3D *v3d);
@@ -451,9 +571,20 @@ bool BKE_view_layer_filter_edit_mesh_has_edges(const struct Object *ob, void *us
struct ViewLayerAOV *BKE_view_layer_add_aov(struct ViewLayer *view_layer);
void BKE_view_layer_remove_aov(struct ViewLayer *view_layer, struct ViewLayerAOV *aov);
void BKE_view_layer_set_active_aov(struct ViewLayer *view_layer, struct ViewLayerAOV *aov);
+/**
+ * Update the naming and conflicts of the AOVs.
+ *
+ * Name must be unique between all AOVs.
+ * Conflicts with render passes will show a conflict icon. Reason is that switching a render
+ * engine or activating a render pass could lead to other conflicts that wouldn't be that clear
+ * for the user.
+ */
void BKE_view_layer_verify_aov(struct RenderEngine *engine,
struct Scene *scene,
struct ViewLayer *view_layer);
+/**
+ * Check if the given view layer has at least one valid AOV.
+ */
bool BKE_view_layer_has_valid_aov(struct ViewLayer *view_layer);
struct ViewLayer *BKE_view_layer_find_with_aov(struct Scene *scene,
struct ViewLayerAOV *view_layer_aov);
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 36f57209e33..ebd35cad965 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -46,6 +46,7 @@
*/
#include "BLI_compiler_attrs.h"
+#include "BLI_utildefines.h"
#ifdef __cplusplus
extern "C" {
@@ -61,22 +62,66 @@ struct PointerRNA;
struct PropertyRNA;
struct bContext;
+/**
+ * Get allocation size of a given data-block type and optionally allocation name.
+ */
size_t BKE_libblock_get_alloc_info(short type, const char **name);
+/**
+ * Allocates and returns memory of the right size for the specified block type,
+ * initialized to zero.
+ */
void *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT;
-void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag)
+/**
+ * Allocates and returns a block of the specified type, with the specified name
+ * (adjusted as necessary to ensure uniqueness), and appended to the specified list.
+ * The user count is set to 1, all other content (apart from name and links) being
+ * initialized to zero.
+ */
+void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, int flag)
ATTR_WARN_UNUSED_RESULT;
+/**
+ * Initialize an ID of given type, such that it has valid 'empty' data.
+ * ID is assumed to be just calloc'ed.
+ */
void BKE_libblock_init_empty(struct ID *id) ATTR_NONNULL(1);
/* *** ID's session_uuid management. *** */
-/* When an ID's uuid is of that value, it is unset/invalid (e.g. for runtime IDs, etc.). */
+/**
+ * When an ID's uuid is of that value, it is unset/invalid (e.g. for runtime IDs, etc.).
+ */
#define MAIN_ID_SESSION_UUID_UNSET 0
+/**
+ * Generate a session-wise uuid for the given \a id.
+ *
+ * \note "session-wise" here means while editing a given .blend file. Once a new .blend file is
+ * loaded or created, undo history is cleared/reset, and so is the uuid counter.
+ */
void BKE_lib_libblock_session_uuid_ensure(struct ID *id);
+/**
+ * Re-generate a new session-wise uuid for the given \a id.
+ *
+ * \warning This has a few very specific use-cases, no other usage is expected currently:
+ * - To handle UI-related data-blocks that are kept across new file reading, when we do keep
+ * existing UI.
+ * - For IDs that are made local without needing any copying.
+ */
void BKE_lib_libblock_session_uuid_renew(struct ID *id);
-void *BKE_id_new(struct Main *bmain, const short type, const char *name);
-void *BKE_id_new_nomain(const short type, const char *name);
+/**
+ * Generic helper to create a new empty data-block of given type in given \a bmain database.
+ *
+ * \param name: can be NULL, in which case we get default name for this ID type.
+ */
+void *BKE_id_new(struct Main *bmain, short type, const char *name);
+/**
+ * Generic helper to create a new temporary empty data-block of given type,
+ * *outside* of any Main database.
+ *
+ * \param name: can be NULL, in which case we get default name for this ID type.
+ */
+void *BKE_id_new_nomain(short type, const char *name);
/**
* New ID creation/copying options.
@@ -122,6 +167,9 @@ enum {
LIB_ID_COPY_CD_REFERENCE = 1 << 20,
/** Do not copy id->override_library, used by ID datablock override routines. */
LIB_ID_COPY_NO_LIB_OVERRIDE = 1 << 21,
+ /** When copying local sub-data (like constraints or modifiers), do not set their "library
+ * override local data" flag. */
+ LIB_ID_COPY_NO_LIB_OVERRIDE_LOCAL_DATA_FLAG = 1 << 22,
/* *** XXX Hackish/not-so-nice specific behaviors needed for some corner cases. *** */
/* *** Ideally we should not have those, but we need them for now... *** */
@@ -133,6 +181,11 @@ enum {
LIB_ID_COPY_SHAPEKEY = 1 << 26,
/** EXCEPTION! Specific deep-copy of node trees used e.g. for rendering purposes. */
LIB_ID_COPY_NODETREE_LOCALIZE = 1 << 27,
+ /**
+ * EXCEPTION! Specific handling of RB objects regarding collections differs depending whether we
+ * duplicate scene/collections, or objects.
+ */
+ LIB_ID_COPY_RIGID_BODY_NO_COLLECTION_HANDLING = 1 << 28,
/* *** Helper 'defines' gathering most common flag sets. *** */
/** Shapekeys are not real ID's, more like local data to geometry IDs... */
@@ -149,17 +202,27 @@ enum {
void BKE_libblock_copy_ex(struct Main *bmain,
const struct ID *id,
struct ID **r_newid,
- const int orig_flag);
+ int orig_flag);
+/**
+ * Used everywhere in blenkernel.
+ */
void *BKE_libblock_copy(struct Main *bmain, const struct ID *id) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Sets the name of a block to name, suitably adjusted for uniqueness.
+ */
void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL();
+/**
+ * Use after setting the ID's name
+ * When name exists: call 'new_id'
+ */
void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL();
struct ID *BKE_libblock_find_name(struct Main *bmain,
- const short type,
+ short type,
const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-
+struct ID *BKE_libblock_find_session_uuid(struct Main *bmain, short type, uint32_t session_uuid);
/**
* Duplicate (a.k.a. deep copy) common processing options.
* See also eDupli_ID_Flags for options controlling what kind of IDs to duplicate.
@@ -176,6 +239,8 @@ typedef enum eLibIDDuplicateFlags {
LIB_ID_DUPLICATE_IS_ROOT_ID = 1 << 1,
} eLibIDDuplicateFlags;
+ENUM_OPERATORS(eLibIDDuplicateFlags, LIB_ID_DUPLICATE_IS_ROOT_ID)
+
/* lib_remap.c (keep here since they're general functions) */
/**
* New freeing logic options.
@@ -202,20 +267,73 @@ enum {
LIB_ID_FREE_NO_UI_USER = 1 << 9,
};
-void BKE_libblock_free_datablock(struct ID *id, const int flag) ATTR_NONNULL();
-void BKE_libblock_free_data(struct ID *id, const bool do_id_user) ATTR_NONNULL();
+void BKE_libblock_free_datablock(struct ID *id, int flag) ATTR_NONNULL();
+void BKE_libblock_free_data(struct ID *id, bool do_id_user) ATTR_NONNULL();
+/**
+ * In most cases #BKE_id_free_ex handles this, when lower level functions are called directly
+ * this function will need to be called too, if Python has access to the data.
+ *
+ * ID data-blocks such as #Material.nodetree are not stored in #Main.
+ */
void BKE_libblock_free_data_py(struct ID *id);
-void BKE_id_free_ex(struct Main *bmain, void *idv, int flag, const bool use_flag_from_idtag);
+/**
+ * Complete ID freeing, extended version for corner cases.
+ * Can override default (and safe!) freeing process, to gain some speed up.
+ *
+ * At that point, given id is assumed to not be used by any other data-block already
+ * (might not be actually true, in case e.g. several inter-related IDs get freed together...).
+ * However, they might still be using (referencing) other IDs, this code takes care of it if
+ * #LIB_TAG_NO_USER_REFCOUNT is not defined.
+ *
+ * \param bmain: #Main database containing the freed #ID,
+ * can be NULL in case it's a temp ID outside of any #Main.
+ * \param idv: Pointer to ID to be freed.
+ * \param flag: Set of \a LIB_ID_FREE_... flags controlling/overriding usual freeing process,
+ * 0 to get default safe behavior.
+ * \param use_flag_from_idtag: Still use freeing info flags from given #ID datablock,
+ * even if some overriding ones are passed in \a flag parameter.
+ */
+void BKE_id_free_ex(struct Main *bmain, void *idv, int flag, bool use_flag_from_idtag);
+/**
+ * Complete ID freeing, should be usable in most cases (even for out-of-Main IDs).
+ *
+ * See #BKE_id_free_ex description for full details.
+ *
+ * \param bmain: Main database containing the freed ID,
+ * can be NULL in case it's a temp ID outside of any Main.
+ * \param idv: Pointer to ID to be freed.
+ */
void BKE_id_free(struct Main *bmain, void *idv);
+/**
+ * Not really a freeing function by itself,
+ * it decrements usercount of given id, and only frees it if it reaches 0.
+ */
void BKE_id_free_us(struct Main *bmain, void *idv) ATTR_NONNULL();
+/**
+ * Properly delete a single ID from given \a bmain database.
+ */
void BKE_id_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
+/**
+ * Properly delete all IDs tagged with \a LIB_TAG_DOIT, in given \a bmain database.
+ *
+ * This is more efficient than calling #BKE_id_delete repetitively on a large set of IDs
+ * (several times faster when deleting most of the IDs at once).
+ *
+ * \warning Considered experimental for now, seems to be working OK but this is
+ * risky code in a complicated area.
+ * \return Number of deleted datablocks.
+ */
size_t BKE_id_multi_tagged_delete(struct Main *bmain) ATTR_NONNULL();
+/**
+ * Add a 'NO_MAIN' data-block to given main (also sets usercounts of its IDs if needed).
+ */
void BKE_libblock_management_main_add(struct Main *bmain, void *idv);
+/** Remove a data-block from given main (set it to 'NO_MAIN' status). */
void BKE_libblock_management_main_remove(struct Main *bmain, void *idv);
void BKE_libblock_management_usercounts_set(struct Main *bmain, void *idv);
@@ -223,10 +341,23 @@ void BKE_libblock_management_usercounts_clear(struct Main *bmain, void *idv);
void id_lib_extern(struct ID *id);
void id_lib_indirect_weak_link(struct ID *id);
+/**
+ * Ensure we have a real user
+ *
+ * \note Now that we have flags, we could get rid of the 'fake_user' special case,
+ * flags are enough to ensure we always have a real user.
+ * However, #ID_REAL_USERS is used in several places outside of core lib.c,
+ * so think we can wait later to make this change.
+ */
void id_us_ensure_real(struct ID *id);
void id_us_clear_real(struct ID *id);
+/**
+ * Same as \a id_us_plus, but does not handle lib indirect -> extern.
+ * Only used by readfile.c so far, but simpler/safer to keep it here nonetheless.
+ */
void id_us_plus_no_lib(struct ID *id);
void id_us_plus(struct ID *id);
+/* decrements the user count for *id. */
void id_us_min(struct ID *id);
void id_fake_user_set(struct ID *id);
void id_fake_user_clear(struct ID *id);
@@ -242,84 +373,250 @@ enum {
/** In case caller code already knows this ID should be made local using copying. */
LIB_ID_MAKELOCAL_FORCE_COPY = 1 << 2,
+ /** Clear asset data (in case the ID can actually be made local, in copy case asset data is never
+ * copied over). */
+ LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR = 1 << 3,
+
/* Special type-specific options. */
/** For Objects, do not clear the proxy pointers while making the data-block local. */
LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING = 1 << 16,
};
-void BKE_lib_id_make_local_generic(struct Main *bmain, struct ID *id, const int flags);
-bool BKE_lib_id_make_local(struct Main *bmain, struct ID *id, const int flags);
+/**
+ * Helper to decide whether given `id` can be directly made local, or needs to be copied.
+ * `r_force_local` and `r_force_copy` cannot be true together. But both can be false, in case no
+ * action should be performed.
+ *
+ * \note low-level helper to de-duplicate logic between `BKE_lib_id_make_local_generic` and the
+ * specific corner-cases implementations needed for objects and brushes.
+ */
+void BKE_lib_id_make_local_generic_action_define(
+ struct Main *bmain, struct ID *id, int flags, bool *r_force_local, bool *r_force_copy);
+/**
+ * Generic 'make local' function, works for most of data-block types.
+ */
+void BKE_lib_id_make_local_generic(struct Main *bmain, struct ID *id, int flags);
+/**
+ * Calls the appropriate make_local method for the block, unless test is set.
+ *
+ * \note Always set #ID.newid pointer in case it gets duplicated.
+ *
+ * \param flags: Special flag used when making a whole library's content local,
+ * it needs specific handling.
+ * \return true is the ID has successfully been made local.
+ */
+bool BKE_lib_id_make_local(struct Main *bmain, struct ID *id, int flags);
+/**
+ * \note Does *not* set #ID.newid pointer.
+ */
bool id_single_user(struct bContext *C,
struct ID *id,
struct PointerRNA *ptr,
struct PropertyRNA *prop);
bool BKE_id_copy_is_allowed(const struct ID *id);
+/**
+ * Invokes the appropriate copy method for the block and returns the result in
+ * #ID.newid, unless test. Returns true if the block can be copied.
+ */
struct ID *BKE_id_copy(struct Main *bmain, const struct ID *id);
-struct ID *BKE_id_copy_ex(struct Main *bmain,
- const struct ID *id,
- struct ID **r_newid,
- const int flag);
+/**
+ * Generic entry point for copying a data-block (new API).
+ *
+ * \note Copy is generally only affecting the given data-block
+ * (no ID used by copied one will be affected, besides user-count).
+ *
+ * There are exceptions though:
+ * - Embedded IDs (root node trees and master collections) are always copied with their owner.
+ * - If #LIB_ID_COPY_ACTIONS is defined, actions used by animdata will be duplicated.
+ * - If #LIB_ID_COPY_SHAPEKEY is defined, shape-keys will be duplicated.
+ * - If #LIB_ID_CREATE_LOCAL is defined, root node trees will be deep-duplicated recursively.
+ *
+ * \note User-count of new copy is always set to 1.
+ *
+ * \param bmain: Main database, may be NULL only if LIB_ID_CREATE_NO_MAIN is specified.
+ * \param id: Source data-block.
+ * \param r_newid: Pointer to new (copied) ID pointer, may be NULL.
+ * Used to allow copying into already allocated memory.
+ * \param flag: Set of copy options, see `DNA_ID.h` enum for details
+ * (leave to zero for default, full copy).
+ * \return NULL when copying that ID type is not supported, the new copy otherwise.
+ */
+struct ID *BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, int flag);
+/**
+ * Invokes the appropriate copy method for the block and returns the result in
+ * newid, unless test. Returns true if the block can be copied.
+ */
struct ID *BKE_id_copy_for_duplicate(struct Main *bmain,
struct ID *id,
- const uint duplicate_flags);
+ uint duplicate_flags,
+ int copy_flags);
+/**
+ * Does a mere memory swap over the whole IDs data (including type-specific memory).
+ * \note Most internal ID data itself is not swapped (only IDProperties are).
+ *
+ * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
+ * itself.
+ */
void BKE_lib_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b);
+/**
+ * Does a mere memory swap over the whole IDs data (including type-specific memory).
+ * \note All internal ID data itself is also swapped.
+ *
+ * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
+ * itself.
+ */
void BKE_lib_id_swap_full(struct Main *bmain, struct ID *id_a, struct ID *id_b);
+/**
+ * Sort given \a id into given \a lb list, using case-insensitive comparison of the id names.
+ *
+ * \note All other IDs beside given one are assumed already properly sorted in the list.
+ *
+ * \param id_sorting_hint: Ignored if NULL. Otherwise, used to check if we can insert \a id
+ * immediately before or after that pointer. It must always be into given \a lb list.
+ */
void id_sort_by_name(struct ListBase *lb, struct ID *id, struct ID *id_sorting_hint);
-void BKE_lib_id_expand_local(struct Main *bmain, struct ID *id);
+/**
+ * Expand ID usages of given id as 'extern' (and no more indirect) linked data.
+ * Used by ID copy/make_local functions.
+ */
+void BKE_lib_id_expand_local(struct Main *bmain, struct ID *id, int flags);
+/**
+ * Ensures given ID has a unique name in given listbase.
+ *
+ * Only for local IDs (linked ones already have a unique ID in their library).
+ *
+ * \param do_linked_data: if true, also ensure a unique name in case the given \a id is linked
+ * (otherwise, just ensure that it is properly sorted).
+ *
+ * \return true if a new name had to be created.
+ */
bool BKE_id_new_name_validate(struct ListBase *lb,
struct ID *id,
const char *name,
- const bool do_linked_data) ATTR_NONNULL(1, 2);
-void BKE_lib_id_clear_library_data(struct Main *bmain, struct ID *id);
+ bool do_linked_data) ATTR_NONNULL(1, 2);
+/**
+ * Pull an ID out of a library (make it local). Only call this for IDs that
+ * don't have other library users.
+ *
+ * \param flags: Same set of `LIB_ID_MAKELOCAL_` flags as passed to #BKE_lib_id_make_local.
+ */
+void BKE_lib_id_clear_library_data(struct Main *bmain, struct ID *id, int flags);
-/* Affect whole Main database. */
-void BKE_main_id_tag_idcode(struct Main *mainvar,
- const short type,
- const int tag,
- const bool value);
-void BKE_main_id_tag_listbase(struct ListBase *lb, const int tag, const bool value);
-void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value);
+/**
+ * Clear or set given tags for all ids of given type in `bmain` (runtime tags).
+ *
+ * \note Affect whole Main database.
+ */
+void BKE_main_id_tag_idcode(struct Main *mainvar, short type, int tag, bool value);
+/**
+ * Clear or set given tags for all ids in listbase (runtime tags).
+ */
+void BKE_main_id_tag_listbase(struct ListBase *lb, int tag, bool value);
+/**
+ * Clear or set given tags for all ids in bmain (runtime tags).
+ */
+void BKE_main_id_tag_all(struct Main *mainvar, int tag, bool value);
-void BKE_main_id_flag_listbase(struct ListBase *lb, const int flag, const bool value);
-void BKE_main_id_flag_all(struct Main *bmain, const int flag, const bool value);
+/**
+ * Clear or set given flags for all ids in listbase (persistent flags).
+ */
+void BKE_main_id_flag_listbase(struct ListBase *lb, int flag, bool value);
+/**
+ * Clear or set given flags for all ids in bmain (persistent flags).
+ */
+void BKE_main_id_flag_all(struct Main *bmain, int flag, bool value);
+/**
+ * Next to indirect usage in `readfile.c/writefile.c` also in `editobject.c`, `scene.c`.
+ */
void BKE_main_id_newptr_and_tag_clear(struct Main *bmain);
-void BKE_main_id_refcount_recompute(struct Main *bmain, const bool do_linked_only);
+void BKE_main_id_refcount_recompute(struct Main *bmain, bool do_linked_only);
void BKE_main_lib_objects_recalc_all(struct Main *bmain);
-/* Only for repairing files via versioning, avoid for general use. */
+/**
+ * Only for repairing files via versioning, avoid for general use.
+ */
void BKE_main_id_repair_duplicate_names_listbase(struct ListBase *lb);
#define MAX_ID_FULL_NAME (64 + 64 + 3 + 1) /* 64 is MAX_ID_NAME - 2 */
#define MAX_ID_FULL_NAME_UI (MAX_ID_FULL_NAME + 3) /* Adds 'keycode' two letters at beginning. */
+/**
+ * Generate full name of the data-block (without ID code, but with library if any).
+ *
+ * \note Result is unique to a given ID type in a given Main database.
+ *
+ * \param name: An allocated string of minimal length #MAX_ID_FULL_NAME,
+ * will be filled with generated string.
+ * \param separator_char: Character to use for separating name and library name.
+ * Can be 0 to use default (' ').
+ */
void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const struct ID *id, char separator_char);
+/**
+ * Generate full name of the data-block (without ID code, but with library if any),
+ * with a 2 to 3 character prefix prepended indicating whether it comes from a library,
+ * is overriding, has a fake or no user, etc.
+ *
+ * \note Result is unique to a given ID type in a given Main database.
+ *
+ * \param name: An allocated string of minimal length #MAX_ID_FULL_NAME_UI,
+ * will be filled with generated string.
+ * \param separator_char: Character to use for separating name and library name.
+ * Can be 0 to use default (' ').
+ * \param r_prefix_len: The length of the prefix added.
+ */
void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI],
const struct ID *id,
- const bool add_lib_hint,
+ bool add_lib_hint,
char separator_char,
int *r_prefix_len);
+/**
+ * Generate a concatenation of ID name (including two-chars type code) and its lib name, if any.
+ *
+ * \return A unique allocated string key for any ID in the whole Main database.
+ */
char *BKE_id_to_unique_string_key(const struct ID *id);
+/**
+ * Make linked data-blocks local.
+ *
+ * \param bmain: Almost certainly global main.
+ * \param lib: If not NULL, only make local data-blocks from this library.
+ * \param untagged_only: If true, only make local data-blocks not tagged with
+ * #LIB_TAG_PRE_EXISTING.
+ * \param set_fake: If true, set fake user on all localized data-blocks
+ * (except group and objects ones).
+ */
void BKE_library_make_local(struct Main *bmain,
const struct Library *lib,
struct GHash *old_to_new_ids,
- const bool untagged_only,
- const bool set_fake);
+ bool untagged_only,
+ bool set_fake);
void BKE_id_tag_set_atomic(struct ID *id, int tag);
void BKE_id_tag_clear_atomic(struct ID *id, int tag);
+/**
+ * Check that given ID pointer actually is in G_MAIN.
+ * Main intended use is for debug asserts in places we cannot easily get rid of #G_Main.
+ */
bool BKE_id_is_in_global_main(struct ID *id);
bool BKE_id_can_be_asset(const struct ID *id);
+/**
+ * Returns ordered list of data-blocks for display in the UI.
+ * Result is list of #LinkData of IDs that must be freed.
+ */
void BKE_id_ordered_list(struct ListBase *ordered_lb, const struct ListBase *lb);
+/**
+ * Reorder ID in the list, before or after the "relative" ID.
+ */
void BKE_id_reorder(const struct ListBase *lb, struct ID *id, struct ID *relative, bool after);
void BKE_id_blend_write(struct BlendWriter *writer, struct ID *id);
@@ -327,6 +624,12 @@ void BKE_id_blend_write(struct BlendWriter *writer, struct ID *id);
#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->tag & LIB_TAG_DOIT))
/* lib_id_eval.c */
+
+/**
+ * Copy relatives parameters, from `id` to `id_cow`.
+ * Use handle the #ID_RECALC_PARAMETERS tag.
+ * \note Keep in sync with #ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW.
+ */
void BKE_id_eval_properties_copy(struct ID *id_cow, struct ID *id);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index b94a1b33606..30e75259967 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -57,85 +57,226 @@ struct ReportList;
struct Scene;
struct ViewLayer;
+/**
+ * Initialize empty overriding of \a reference_id by \a local_id.
+ */
struct IDOverrideLibrary *BKE_lib_override_library_init(struct ID *local_id,
struct ID *reference_id);
-void BKE_lib_override_library_copy(struct ID *dst_id,
- const struct ID *src_id,
- const bool do_full_copy);
-void BKE_lib_override_library_clear(struct IDOverrideLibrary *override, const bool do_id_user);
-void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user);
+/**
+ * Shallow or deep copy of a whole override from \a src_id to \a dst_id.
+ */
+void BKE_lib_override_library_copy(struct ID *dst_id, const struct ID *src_id, bool do_full_copy);
+/**
+ * Clear any overriding data from given \a override.
+ */
+void BKE_lib_override_library_clear(struct IDOverrideLibrary *override, bool do_id_user);
+/**
+ * Free given \a override.
+ */
+void BKE_lib_override_library_free(struct IDOverrideLibrary **override, bool do_id_user);
+/**
+ * Check if given ID has some override rules that actually indicate the user edited it.
+ */
bool BKE_lib_override_library_is_user_edited(struct ID *id);
+/**
+ * Create an overridden local copy of linked reference.
+ *
+ * \note This function is very basic, low-level. It does not consider any hierarchical dependency,
+ * and also prevents any automatic re-sync of this local override.
+ */
struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
struct ID *reference_id,
- const bool do_tagged_remap);
+ bool do_tagged_remap);
+/**
+ * Create overridden local copies of all tagged data-blocks in given Main.
+ *
+ * \note Set `id->newid` of overridden libs with newly created overrides,
+ * caller is responsible to clean those pointers before/after usage as needed.
+ *
+ * \note By default, it will only remap newly created local overriding data-blocks between
+ * themselves, to avoid 'enforcing' those overrides into all other usages of the linked data in
+ * main. You can add more local IDs to be remapped to use new overriding ones by setting their
+ * LIB_TAG_DOIT tag.
+ *
+ * \param reference_library: the library from which the linked data being overridden come from
+ * (i.e. the library of the linked reference ID).
+ *
+ * \param do_no_main: Create the new override data outside of Main database.
+ * Used for resyncing of linked overrides.
+ *
+ * \return \a true on success, \a false otherwise.
+ */
bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
const struct Library *reference_library,
- const bool do_no_main);
+ bool do_no_main);
+/**
+ * Advanced 'smart' function to create fully functional overrides.
+ *
+ * \note Currently it only does special things if given \a id_root is an object or collection, more
+ * specific behaviors may be added in the future for other ID types.
+ *
+ * \note It will override all IDs tagged with \a LIB_TAG_DOIT, and it does not clear that tag at
+ * its beginning, so caller code can add extra data-blocks to be overridden as well.
+ *
+ * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
+ * which case \a scene's master collection children hierarchy is used instead).
+ * \param id_root: The root ID to create an override from.
+ * \param id_reference: Some reference ID used to do some post-processing after overrides have been
+ * created, may be NULL. Typically, the Empty object instantiating the linked collection we
+ * override, currently.
+ * \param r_id_root_override: if not NULL, the override generated for the given \a id_root.
+ * \return true if override was successfully created.
+ */
bool BKE_lib_override_library_create(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct ID *id_root,
struct ID *id_reference,
struct ID **r_id_root_override);
+/**
+ * Create a library override template.
+ */
bool BKE_lib_override_library_template_create(struct ID *id);
+/**
+ * Convert a given proxy object into a library override.
+ *
+ * \note This is a thin wrapper around \a BKE_lib_override_library_create, only extra work is to
+ * actually convert the proxy itself into an override first.
+ *
+ * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
+ * which case \a scene's master collection children hierarchy is used instead).
+ * \return true if override was successfully created.
+ */
bool BKE_lib_override_library_proxy_convert(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct Object *ob_proxy);
+/**
+ * Convert all proxy objects into library overrides.
+ *
+ * \note Only affects local proxies, linked ones are not affected.
+ */
void BKE_lib_override_library_main_proxy_convert(struct Main *bmain,
struct BlendFileReadReport *reports);
+/**
+ * Advanced 'smart' function to resync, re-create fully functional overrides up-to-date with linked
+ * data, from an existing override hierarchy.
+ *
+ * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
+ * which case \a scene's master collection children hierarchy is used instead).
+ * \param id_root: The root liboverride ID to resync from.
+ * \return true if override was successfully resynced.
+ */
bool BKE_lib_override_library_resync(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct ID *id_root,
struct Collection *override_resync_residual_storage,
- const bool do_hierarchy_enforce,
- const bool do_post_process,
+ bool do_hierarchy_enforce,
struct BlendFileReadReport *reports);
+/**
+ * Detect and handle required resync of overrides data, when relations between reference linked IDs
+ * have changed.
+ *
+ * This is a fairly complex and costly operation, typically it should be called after
+ * #BKE_lib_override_library_main_update, which would already detect and tag a lot of cases.
+ *
+ * This function will first detect the remaining cases requiring a resync (namely, either when an
+ * existing linked ID that did not require to be overridden before now would be, or when new IDs
+ * are added to the hierarchy).
+ *
+ * Then it will handle the resync of necessary IDs (through calls to
+ * #BKE_lib_override_library_resync).
+ *
+ * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
+ * which case \a scene's master collection children hierarchy is used instead).
+ */
void BKE_lib_override_library_main_resync(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct BlendFileReadReport *reports);
+/**
+ * Advanced 'smart' function to delete library overrides (including their existing override
+ * hierarchy) and remap their usages to their linked reference IDs.
+ *
+ * \note All IDs tagged with #LIB_TAG_DOIT will be deleted.
+ *
+ * \param id_root: The root liboverride ID to delete.
+ */
void BKE_lib_override_library_delete(struct Main *bmain, struct ID *id_root);
+/**
+ * Make given ID fully local.
+ *
+ * \note Only differs from lower-level #BKE_lib_override_library_free in infamous embedded ID
+ * cases.
+ */
void BKE_lib_override_library_make_local(struct ID *id);
+/**
+ * Find override property from given RNA path, if it exists.
+ */
struct IDOverrideLibraryProperty *BKE_lib_override_library_property_find(
struct IDOverrideLibrary *override, const char *rna_path);
+/**
+ * Find override property from given RNA path, or create it if it does not exist.
+ */
struct IDOverrideLibraryProperty *BKE_lib_override_library_property_get(
struct IDOverrideLibrary *override, const char *rna_path, bool *r_created);
+/**
+ * Remove and free given \a override_property from given ID \a override.
+ */
void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override,
struct IDOverrideLibraryProperty *override_property);
+/**
+ * Get the RNA-property matching the \a library_prop override property. Used for UI to query
+ * additional data about the overridden property (e.g. UI name).
+ *
+ * \param idpoin: Pointer to the override ID.
+ * \param library_prop: The library override property to find the matching RNA property for.
+ */
bool BKE_lib_override_rna_property_find(struct PointerRNA *idpoin,
const struct IDOverrideLibraryProperty *library_prop,
struct PointerRNA *r_override_poin,
struct PropertyRNA **r_override_prop);
+/**
+ * Find override property operation from given sub-item(s), if it exists.
+ */
struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_find(
struct IDOverrideLibraryProperty *override_property,
const char *subitem_refname,
const char *subitem_locname,
- const int subitem_refindex,
- const int subitem_locindex,
- const bool strict,
+ int subitem_refindex,
+ int subitem_locindex,
+ bool strict,
bool *r_strict);
+/**
+ * Find override property operation from given sub-item(s), or create it if it does not exist.
+ */
struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_get(
struct IDOverrideLibraryProperty *override_property,
- const short operation,
+ short operation,
const char *subitem_refname,
const char *subitem_locname,
- const int subitem_refindex,
- const int subitem_locindex,
- const bool strict,
+ int subitem_refindex,
+ int subitem_locindex,
+ bool strict,
bool *r_strict,
bool *r_created);
+/**
+ * Remove and free given \a override_property_operation from given ID \a override_property.
+ */
void BKE_lib_override_library_property_operation_delete(
struct IDOverrideLibraryProperty *override_property,
struct IDOverrideLibraryPropertyOperation *override_property_operation);
+/**
+ * Validate that required data for a given operation are available.
+ */
bool BKE_lib_override_library_property_operation_operands_validate(
struct IDOverrideLibraryPropertyOperation *override_property_operation,
struct PointerRNA *ptr_dst,
@@ -145,34 +286,109 @@ bool BKE_lib_override_library_property_operation_operands_validate(
struct PropertyRNA *prop_src,
struct PropertyRNA *prop_storage);
+/**
+ * Check against potential \a bmain.
+ */
void BKE_lib_override_library_validate(struct Main *bmain,
struct ID *id,
struct ReportList *reports);
+/**
+ * Check against potential \a bmain.
+ */
void BKE_lib_override_library_main_validate(struct Main *bmain, struct ReportList *reports);
+/**
+ * Check that status of local data-block is still valid against current reference one.
+ *
+ * It means that all overridable, but not overridden, properties' local values must be equal to
+ * reference ones. Clears #LIB_TAG_OVERRIDE_OK if they do not.
+ *
+ * This is typically used to detect whether some property has been changed in local and a new
+ * #IDOverrideProperty (of #IDOverridePropertyOperation) has to be added.
+ *
+ * \return true if status is OK, false otherwise.
+ */
bool BKE_lib_override_library_status_check_local(struct Main *bmain, struct ID *local);
+/**
+ * Check that status of reference data-block is still valid against current local one.
+ *
+ * It means that all non-overridden properties' local values must be equal to reference ones.
+ * Clears LIB_TAG_OVERRIDE_OK if they do not.
+ *
+ * This is typically used to detect whether some reference has changed and local
+ * needs to be updated against it.
+ *
+ * \return true if status is OK, false otherwise.
+ */
bool BKE_lib_override_library_status_check_reference(struct Main *bmain, struct ID *local);
+/**
+ * Compare local and reference data-blocks and create new override operations as needed,
+ * or reset to reference values if overriding is not allowed.
+ *
+ * \note Defining override operations is only mandatory before saving a `.blend` file on disk
+ * (not for undo!).
+ * Knowing that info at runtime is only useful for UI/UX feedback.
+ *
+ * \note This is by far the biggest operation (the more time-consuming) of the three so far,
+ * since it has to go over all properties in depth (all overridable ones at least).
+ * Generating differential values and applying overrides are much cheaper.
+ *
+ * \return true if any library operation was created.
+ */
bool BKE_lib_override_library_operations_create(struct Main *bmain, struct ID *local);
-bool BKE_lib_override_library_main_operations_create(struct Main *bmain, const bool force_auto);
+/**
+ * Check all overrides from given \a bmain and create/update overriding operations as needed.
+ */
+bool BKE_lib_override_library_main_operations_create(struct Main *bmain, bool force_auto);
+/**
+ * Reset all overrides in given \a id_root, while preserving ID relations.
+ */
void BKE_lib_override_library_id_reset(struct Main *bmain, struct ID *id_root);
+/**
+ * Reset all overrides in given \a id_root and its dependencies, while preserving ID relations.
+ */
void BKE_lib_override_library_id_hierarchy_reset(struct Main *bmain, struct ID *id_root);
+/**
+ * Set or clear given tag in all operations in that override property data.
+ */
void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property,
- const short tag,
- const bool do_set);
+ short tag,
+ bool do_set);
+/**
+ * Set or clear given tag in all properties and operations in that override data.
+ */
void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
- const short tag,
- const bool do_set);
-void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, const bool do_set);
+ short tag,
+ bool do_set);
+/**
+ * Set or clear given tag in all properties and operations in that Main's ID override data.
+ */
+void BKE_lib_override_library_main_tag(struct Main *bmain, short tag, bool do_set);
+/**
+ * Remove all tagged-as-unused properties and operations from that ID override data.
+ */
void BKE_lib_override_library_id_unused_cleanup(struct ID *local);
+/**
+ * Remove all tagged-as-unused properties and operations from that Main's ID override data.
+ */
void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain);
+/**
+ * Update given override from its reference (re-applying overridden properties).
+ */
void BKE_lib_override_library_update(struct Main *bmain, struct ID *local);
+/**
+ * Update all overrides from given \a bmain.
+ */
void BKE_lib_override_library_main_update(struct Main *bmain);
+/**
+ * In case an ID is used by another liboverride ID, user may not be allowed to delete it.
+ */
bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID *id);
/* Storage (.blend file writing) part. */
@@ -180,9 +396,22 @@ bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID
/* For now, we just use a temp main list. */
typedef struct Main OverrideLibraryStorage;
+/**
+ * Initialize an override storage.
+ */
OverrideLibraryStorage *BKE_lib_override_library_operations_store_init(void);
+/**
+ * Generate suitable 'write' data (this only affects differential override operations).
+ *
+ * Note that \a local ID is no more modified by this call,
+ * all extra data are stored in its temp \a storage_id copy.
+ */
struct ID *BKE_lib_override_library_operations_store_start(
struct Main *bmain, OverrideLibraryStorage *override_storage, struct ID *local);
+/**
+ * Restore given ID modified by #BKE_lib_override_library_operations_store_start, to its
+ * original state.
+ */
void BKE_lib_override_library_operations_store_end(OverrideLibraryStorage *override_storage,
struct ID *local);
void BKE_lib_override_library_operations_store_finalize(OverrideLibraryStorage *override_storage);
diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h
index 9c49514e7b8..d853cb16b13 100644
--- a/source/blender/blenkernel/BKE_lib_query.h
+++ b/source/blender/blenkernel/BKE_lib_query.h
@@ -143,59 +143,144 @@ enum {
typedef struct LibraryForeachIDData LibraryForeachIDData;
-bool BKE_lib_query_foreachid_process(struct LibraryForeachIDData *data,
+/**
+ * Check whether current iteration over ID usages should be stopped or not.
+ * \return true if the iteration should be stopped, false otherwise.
+ */
+bool BKE_lib_query_foreachid_iter_stop(struct LibraryForeachIDData *data);
+void BKE_lib_query_foreachid_process(struct LibraryForeachIDData *data,
struct ID **id_pp,
int cb_flag);
int BKE_lib_query_foreachid_process_flags_get(struct LibraryForeachIDData *data);
int BKE_lib_query_foreachid_process_callback_flag_override(struct LibraryForeachIDData *data,
- const int cb_flag,
- const bool do_replace);
+ int cb_flag,
+ bool do_replace);
#define BKE_LIB_FOREACHID_PROCESS_ID(_data, _id, _cb_flag) \
{ \
CHECK_TYPE_ANY((_id), ID *, void *); \
- if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id), (_cb_flag))) { \
+ BKE_lib_query_foreachid_process((_data), (ID **)&(_id), (_cb_flag)); \
+ if (BKE_lib_query_foreachid_iter_stop((_data))) { \
return; \
} \
} \
((void)0)
-#define BKE_LIB_FOREACHID_PROCESS(_data, _id_super, _cb_flag) \
+#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(_data, _id_super, _cb_flag) \
{ \
CHECK_TYPE(&((_id_super)->id), ID *); \
- if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag))) { \
+ BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag)); \
+ if (BKE_lib_query_foreachid_iter_stop((_data))) { \
+ return; \
+ } \
+ } \
+ ((void)0)
+
+#define BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(_data, _func_call) \
+ { \
+ _func_call; \
+ if (BKE_lib_query_foreachid_iter_stop((_data))) { \
return; \
} \
} \
((void)0)
-bool BKE_library_foreach_ID_embedded(struct LibraryForeachIDData *data, struct ID **id_pp);
+/**
+ * Process embedded ID pointers (root node-trees, master collections, ...).
+ *
+ * Those require specific care, since they are technically sub-data of their owner, yet in some
+ * cases they still behave as regular IDs.
+ */
+void BKE_library_foreach_ID_embedded(struct LibraryForeachIDData *data, struct ID **id_pp);
void BKE_lib_query_idpropertiesForeachIDLink_callback(struct IDProperty *id_prop, void *user_data);
-/* Loop over all of the ID's this datablock links to. */
+/**
+ * Loop over all of the ID's this data-block links to.
+ */
void BKE_library_foreach_ID_link(
struct Main *bmain, struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
-void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int cb_flag);
+/**
+ * Re-usable function, use when replacing ID's.
+ */
+void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, int cb_flag);
+/**
+ * Return the number of times given \a id_user uses/references \a id_used.
+ *
+ * \note This only checks for pointer references of an ID, shallow usages
+ * (like e.g. by RNA paths, as done for FCurves) are not detected at all.
+ *
+ * \param id_user: the ID which is supposed to use (reference) \a id_used.
+ * \param id_used: the ID which is supposed to be used (referenced) by \a id_user.
+ * \return the number of direct usages/references of \a id_used by \a id_user.
+ */
int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used);
-bool BKE_library_id_can_use_idtype(struct ID *id_owner, const short id_type_used);
+/**
+ * Say whether given \a id_owner may use (in any way) a data-block of \a id_type_used.
+ *
+ * This is a 'simplified' abstract version of #BKE_library_foreach_ID_link() above,
+ * quite useful to reduce useless iterations in some cases.
+ */
+bool BKE_library_id_can_use_idtype(struct ID *id_owner, short id_type_used);
+/**
+ * Check whether given ID is used locally (i.e. by another non-linked ID).
+ */
bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv);
+/**
+ * Check whether given ID is used indirectly (i.e. by another linked ID).
+ */
bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv);
+/**
+ * Combine #BKE_library_ID_is_locally_used() and #BKE_library_ID_is_indirectly_used()
+ * in a single call.
+ */
void BKE_library_ID_test_usages(struct Main *bmain,
void *idv,
bool *is_used_local,
bool *is_used_linked);
+/**
+ * Tag all unused IDs (a.k.a 'orphaned').
+ *
+ * By default only tag IDs with `0` user count.
+ * If `do_tag_recursive` is set, it will check dependencies to detect all IDs that are not actually
+ * used in current file, including 'archipelagos` (i.e. set of IDs referencing each other in
+ * loops, but without any 'external' valid usages.
+ *
+ * Valid usages here are defined as ref-counting usages, which are not towards embedded or
+ * loop-back data.
+ *
+ * \param r_num_tagged: If non-NULL, must be a zero-initialized array of #INDEX_ID_MAX integers.
+ * Number of tagged-as-unused IDs is then set for each type, and as total in
+ * #INDEX_ID_NULL item.
+ */
void BKE_lib_query_unused_ids_tag(struct Main *bmain,
- const int tag,
- const bool do_local_ids,
- const bool do_linked_ids,
- const bool do_tag_recursive,
+ int tag,
+ bool do_local_ids,
+ bool do_linked_ids,
+ bool do_tag_recursive,
int *r_num_tagged);
-void BKE_library_unused_linked_data_set_tag(struct Main *bmain, const bool do_init_tag);
+/**
+ * Detect orphaned linked data blocks (i.e. linked data not used (directly or indirectly)
+ * in any way by any local data), including complex cases like 'linked archipelagoes', i.e.
+ * linked data-blocks that use each other in loops,
+ * which prevents their deletion by 'basic' usage checks.
+ *
+ * \param do_init_tag: if \a true, all linked data are checked, if \a false,
+ * only linked data-blocks already tagged with #LIB_TAG_DOIT are checked.
+ */
+void BKE_library_unused_linked_data_set_tag(struct Main *bmain, bool do_init_tag);
+/**
+ * Untag linked data blocks used by other untagged linked data-blocks.
+ * Used to detect data-blocks that we can forcefully make local
+ * (instead of copying them to later get rid of original):
+ * All data-blocks we want to make local are tagged by caller,
+ * after this function has ran caller knows data-blocks still tagged can directly be made local,
+ * since they are only used by other data-blocks that will also be made fully local.
+ */
void BKE_library_indirectly_used_data_tag_clear(struct Main *bmain);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h
index c70521f9593..cc970342fbb 100644
--- a/source/blender/blenkernel/BKE_lib_remap.h
+++ b/source/blender/blenkernel/BKE_lib_remap.h
@@ -38,6 +38,9 @@
extern "C" {
#endif
+struct ID;
+struct IDRemapper;
+
/* BKE_libblock_free, delete are declared in BKE_lib_id.h for convenience. */
/* Also IDRemap->flag. */
@@ -89,38 +92,131 @@ enum {
* dealing with IDs temporarily out of Main, but which will be put in it ultimately).
*/
ID_REMAP_FORCE_USER_REFCOUNT = 1 << 8,
+ /**
+ * Force obdata pointers to also be processed, even when object (`id_owner`) is in Edit mode.
+ * This is required by some tools creating/deleting IDs while operating in Edit mode, like e.g.
+ * the 'separate' mesh operator.
+ */
+ ID_REMAP_FORCE_OBDATA_IN_EDITMODE = 1 << 9,
};
-/* NOTE: Requiring new_id to be non-null, this *may* not be the case ultimately,
- * but makes things simpler for now. */
-void BKE_libblock_remap_locked(struct Main *bmain,
- void *old_idv,
- void *new_idv,
- const short remap_flags) ATTR_NONNULL(1, 2);
-void BKE_libblock_remap(struct Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
+/**
+ * Replace all references in given Main using the given \a mappings
+ *
+ * \note Is preferred over BKE_libblock_remap_locked due to performance.
+ */
+void BKE_libblock_remap_multiple_locked(struct Main *bmain,
+ const struct IDRemapper *mappings,
+ const short remap_flags);
+
+void BKE_libblock_remap_multiple(struct Main *bmain,
+ const struct IDRemapper *mappings,
+ const short remap_flags);
+
+/**
+ * Replace all references in given Main to \a old_id by \a new_id
+ * (if \a new_id is NULL, it unlinks \a old_id).
+ *
+ * \note Requiring new_id to be non-null, this *may* not be the case ultimately,
+ * but makes things simpler for now.
+ */
+void BKE_libblock_remap_locked(struct Main *bmain, void *old_idv, void *new_idv, short remap_flags)
+ ATTR_NONNULL(1, 2);
+void BKE_libblock_remap(struct Main *bmain, void *old_idv, void *new_idv, short remap_flags)
ATTR_NONNULL(1, 2);
+/**
+ * Unlink given \a id from given \a bmain
+ * (does not touch to indirect, i.e. library, usages of the ID).
+ *
+ * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by
+ * #LIB_TAG_DOIT flag (quite obviously, 'non-NULL' usages can never be unlinked by this function).
+ */
void BKE_libblock_unlink(struct Main *bmain,
void *idv,
- const bool do_flag_never_null,
- const bool do_skip_indirect) ATTR_NONNULL();
+ bool do_flag_never_null,
+ bool do_skip_indirect) ATTR_NONNULL();
+/**
+ * Similar to libblock_remap, but only affects IDs used by given \a idv ID.
+ *
+ * \param old_idv: Unlike BKE_libblock_remap, can be NULL,
+ * in which case all ID usages by given \a idv will be cleared.
+ */
void BKE_libblock_relink_ex(struct Main *bmain,
void *idv,
void *old_idv,
void *new_idv,
- const short remap_flags) ATTR_NONNULL(1, 2);
+ short remap_flags) ATTR_NONNULL(1, 2);
-void BKE_libblock_relink_to_newid(struct ID *id) ATTR_NONNULL();
-void BKE_libblock_relink_to_newid_new(struct Main *bmain, struct ID *id) ATTR_NONNULL();
+/**
+ * Remaps ID usages of given ID to their `id->newid` pointer if not None, and proceeds recursively
+ * in the dependency tree of IDs for all data-blocks tagged with `LIB_TAG_NEW`.
+ *
+ * \note `LIB_TAG_NEW` is cleared.
+ *
+ * Very specific usage, not sure we'll keep it on the long run,
+ * currently only used in Object/Collection duplication code.
+ */
+void BKE_libblock_relink_to_newid(struct Main *bmain, struct ID *id, int remap_flag)
+ ATTR_NONNULL();
typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
-typedef void (*BKE_library_remap_editor_id_reference_cb)(struct ID *, struct ID *);
+typedef void (*BKE_library_remap_editor_id_reference_cb)(const struct IDRemapper *mappings);
void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func);
void BKE_library_callback_remap_editor_id_reference_set(
BKE_library_remap_editor_id_reference_cb func);
+/* IDRemapper */
+struct IDRemapper;
+typedef enum IDRemapperApplyResult {
+ /** No remapping rules available for the source. */
+ ID_REMAP_RESULT_SOURCE_UNAVAILABLE,
+ /** Source isn't mappable (e.g. NULL). */
+ ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE,
+ /** Source has been remapped to a new pointer. */
+ ID_REMAP_RESULT_SOURCE_REMAPPED,
+ /** Source has been set to NULL. */
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED,
+} IDRemapperApplyResult;
+
+typedef enum IDRemapperApplyOptions {
+ ID_REMAP_APPLY_UPDATE_REFCOUNT = (1 << 0),
+ ID_REMAP_APPLY_ENSURE_REAL = (1 << 1),
+
+ ID_REMAP_APPLY_DEFAULT = 0,
+} IDRemapperApplyOptions;
+
+typedef void (*IDRemapperIterFunction)(struct ID *old_id, struct ID *new_id, void *user_data);
+
+/**
+ * Create a new ID Remapper.
+ *
+ * An ID remapper stores multiple remapping rules.
+ */
+struct IDRemapper *BKE_id_remapper_create(void);
+
+void BKE_id_remapper_clear(struct IDRemapper *id_remapper);
+bool BKE_id_remapper_is_empty(const struct IDRemapper *id_remapper);
+/** Free the given ID Remapper. */
+void BKE_id_remapper_free(struct IDRemapper *id_remapper);
+/** Add a new remapping. */
+void BKE_id_remapper_add(struct IDRemapper *id_remapper, struct ID *old_id, struct ID *new_id);
+
+/**
+ * Apply a remapping.
+ *
+ * Update the id pointer stored in the given r_id_ptr if a remapping rule exists.
+ */
+IDRemapperApplyResult BKE_id_remapper_apply(const struct IDRemapper *id_remapper,
+ struct ID **r_id_ptr,
+ IDRemapperApplyOptions options);
+bool BKE_id_remapper_has_mapping_for(const struct IDRemapper *id_remapper, uint64_t type_filter);
+void BKE_id_remapper_iter(const struct IDRemapper *id_remapper,
+ IDRemapperIterFunction func,
+ void *user_data);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_lightprobe.h b/source/blender/blenkernel/BKE_lightprobe.h
index 764914ee315..59c5d32c03e 100644
--- a/source/blender/blenkernel/BKE_lightprobe.h
+++ b/source/blender/blenkernel/BKE_lightprobe.h
@@ -31,7 +31,7 @@ extern "C" {
struct LightProbe;
struct Main;
-void BKE_lightprobe_type_set(struct LightProbe *probe, const short lightprobe_type);
+void BKE_lightprobe_type_set(struct LightProbe *probe, short lightprobe_type);
void *BKE_lightprobe_add(struct Main *bmain, const char *name);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index 1236a96c8d9..94a5fde5468 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -60,16 +60,16 @@ LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *lines
LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle,
const LineStyleModifier *m,
- const int flag);
+ int flag);
LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle,
const LineStyleModifier *m,
- const int flag);
+ int flag);
LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle,
const LineStyleModifier *m,
- const int flag);
+ int flag);
LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle,
const LineStyleModifier *m,
- const int flag);
+ int flag);
int BKE_linestyle_color_modifier_remove(FreestyleLineStyle *linestyle,
LineStyleModifier *modifier);
@@ -80,6 +80,10 @@ int BKE_linestyle_thickness_modifier_remove(FreestyleLineStyle *linestyle,
int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle,
LineStyleModifier *modifier);
+/**
+ * Reinsert \a modifier in modifier list with an offset of \a direction.
+ * \return if position of \a modifier has changed.
+ */
bool BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle,
LineStyleModifier *modifier,
int direction);
@@ -97,7 +101,7 @@ void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, List
char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle,
struct ColorBand *color_ramp);
-bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes);
+bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, bool use_shading_nodes);
void BKE_linestyle_default_shader(const struct bContext *C, FreestyleLineStyle *linestyle);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 93d5b5c5aa6..4c6eb31db4b 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -90,12 +90,12 @@ typedef struct MainIDRelationsEntry {
} MainIDRelationsEntry;
/* MainIDRelationsEntry.tags */
-typedef enum MainIDRelationsEntryTags {
+typedef enum eMainIDRelationsEntryTags {
/* Generic tag marking the entry as to be processed. */
MAINIDRELATIONS_ENTRY_TAGS_DOIT = 1 << 0,
/* Generic tag marking the entry as processed. */
MAINIDRELATIONS_ENTRY_TAGS_PROCESSED = 1 << 1,
-} MainIDRelationsEntryTags;
+} eMainIDRelationsEntryTags;
typedef struct MainIDRelations {
/* Mapping from an ID pointer to all of its parents (IDs using it) and children (IDs it uses).
@@ -116,12 +116,14 @@ enum {
typedef struct Main {
struct Main *next, *prev;
- char name[1024]; /* 1024 = FILE_MAX */
+ /** The file-path of this blend file, an empty string indicates an unsaved file. */
+ char filepath[1024]; /* 1024 = FILE_MAX */
short versionfile, subversionfile; /* see BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION */
short minversionfile, minsubversionfile;
uint64_t build_commit_timestamp; /* commit's timestamp from buildinfo */
char build_hash[16]; /* hash from buildinfo */
- char recovered; /* indicate the main->name (file) is the recovered one */
+ /** Indicate the #Main.filepath (file) is the recovered one. */
+ char recovered;
/** All current ID's exist in the last memfile undo step. */
char is_memfile_undo_written;
/**
@@ -201,38 +203,97 @@ typedef struct Main {
struct Main *BKE_main_new(void);
void BKE_main_free(struct Main *mainvar);
+/**
+ * Check whether given `bmain` is empty or contains some IDs.
+ */
+bool BKE_main_is_empty(struct Main *bmain);
+
void BKE_main_lock(struct Main *bmain);
void BKE_main_unlock(struct Main *bmain);
-void BKE_main_relations_create(struct Main *bmain, const short flag);
+/** Generate the mappings between used IDs and their users, and vice-versa. */
+void BKE_main_relations_create(struct Main *bmain, short flag);
void BKE_main_relations_free(struct Main *bmain);
-void BKE_main_relations_tag_set(struct Main *bmain,
- const MainIDRelationsEntryTags tag,
- const bool value);
+/** Set or clear given `tag` in all relation entries of given `bmain`. */
+void BKE_main_relations_tag_set(struct Main *bmain, eMainIDRelationsEntryTags tag, bool value);
+/**
+ * Create a #GSet storing all IDs present in given \a bmain, by their pointers.
+ *
+ * \param gset: If not NULL, given GSet will be extended with IDs from given \a bmain,
+ * instead of creating a new one.
+ */
struct GSet *BKE_main_gset_create(struct Main *bmain, struct GSet *gset);
-/*
- * Temporary runtime API to allow re-using local (already appended) IDs instead of appending a new
- * copy again.
- */
+/* Temporary runtime API to allow re-using local (already appended)
+ * IDs instead of appending a new copy again. */
+/**
+ * Generate a mapping between 'library path' of an ID
+ * (as a pair (relative blend file path, id name)), and a current local ID, if any.
+ *
+ * This uses the information stored in `ID.library_weak_reference`.
+ */
struct GHash *BKE_main_library_weak_reference_create(struct Main *bmain) ATTR_NONNULL();
+/**
+ * Destroy the data generated by #BKE_main_library_weak_reference_create.
+ */
void BKE_main_library_weak_reference_destroy(struct GHash *library_weak_reference_mapping)
ATTR_NONNULL();
+/**
+ * Search for a local ID matching the given linked ID reference.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_filepath: the path of a blend file library (relative to current working one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID
+ * type.
+ */
struct ID *BKE_main_library_weak_reference_search_item(
struct GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name) ATTR_NONNULL();
+/**
+ * Add the given ID weak library reference to given local ID and the runtime mapping.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_filepath: the path of a blend file library (relative to current working one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
+ * \param new_id: New local ID matching given weak reference.
+ */
void BKE_main_library_weak_reference_add_item(struct GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
struct ID *new_id) ATTR_NONNULL();
+/**
+ * Update the status of the given ID weak library reference in current local IDs and the runtime
+ * mapping.
+ *
+ * This effectively transfers the 'ownership' of the given weak reference from `old_id` to
+ * `new_id`.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_filepath: the path of a blend file library (relative to current working one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
+ * \param old_id: Existing local ID matching given weak reference.
+ * \param new_id: New local ID matching given weak reference.
+ */
void BKE_main_library_weak_reference_update_item(struct GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
struct ID *old_id,
struct ID *new_id) ATTR_NONNULL();
+/**
+ * Remove the given ID weak library reference from the given local ID and the runtime mapping.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_filepath: the path of a blend file library (relative to current working one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
+ * \param old_id: Existing local ID matching given weak reference.
+ */
void BKE_main_library_weak_reference_remove_item(struct GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
@@ -242,9 +303,9 @@ void BKE_main_library_weak_reference_remove_item(struct GHash *library_weak_refe
#define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id) \
{ \
- ID *_id_next = (_lb)->first; \
+ ID *_id_next = (ID *)(_lb)->first; \
for ((_id) = _id_next; (_id) != NULL; (_id) = _id_next) { \
- _id_next = (_id)->next;
+ _id_next = (ID *)(_id)->next;
#define FOREACH_MAIN_LISTBASE_ID_END \
} \
@@ -284,16 +345,57 @@ void BKE_main_library_weak_reference_remove_item(struct GHash *library_weak_refe
} \
((void)0)
+/**
+ * Generates a raw .blend file thumbnail data from given image.
+ *
+ * \param bmain: If not NULL, also store generated data in this Main.
+ * \param img: ImBuf image to generate thumbnail data from.
+ * \return The generated .blend file raw thumbnail data.
+ */
struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img);
+/**
+ * Generates an image from raw .blend file thumbnail \a data.
+ *
+ * \param bmain: Use this bmain->blen_thumb data if given \a data is NULL.
+ * \param data: Raw .blend file thumbnail data.
+ * \return An ImBuf from given data, or NULL if invalid.
+ */
struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data);
+/**
+ * Generates an empty (black) thumbnail for given Main.
+ */
void BKE_main_thumbnail_create(struct Main *bmain);
+/**
+ * Return file-path of given \a main.
+ */
const char *BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL();
+/**
+ * Return file-path of global main #G_MAIN.
+ *
+ * \warning Usage is not recommended,
+ * you should always try to get a valid Main pointer from context.
+ */
const char *BKE_main_blendfile_path_from_global(void);
+/**
+ * \return A pointer to the \a ListBase of given \a bmain for requested \a type ID type.
+ */
struct ListBase *which_libbase(struct Main *bmain, short type);
//#define INDEX_ID_MAX 41
+/**
+ * Put the pointers to all the #ListBase structs in given `bmain` into the `*lb[INDEX_ID_MAX]`
+ * array, and return the number of those for convenience.
+ *
+ * This is useful for generic traversal of all the blocks in a #Main (by traversing all the lists
+ * in turn), without worrying about block types.
+ *
+ * \param lb: Array of lists #INDEX_ID_MAX in length.
+ *
+ * \note The order of each ID type #ListBase in the array is determined by the `INDEX_ID_<IDTYPE>`
+ * enum definitions in `DNA_ID.h`. See also the #FOREACH_MAIN_ID_BEGIN macro in `BKE_main.h`
+ */
int set_listbasepointers(struct Main *main, struct ListBase *lb[]);
#define MAIN_VERSION_ATLEAST(main, ver, subver) \
@@ -304,6 +406,13 @@ int set_listbasepointers(struct Main *main, struct ListBase *lb[]);
((main)->versionfile < (ver) || \
((main)->versionfile == (ver) && (main)->subversionfile < (subver)))
+/**
+ * The size of thumbnails (optionally) stored in the `.blend` files header.
+ *
+ * NOTE(@campbellbarton): This is kept small as it's stored uncompressed in the `.blend` file,
+ * where a larger size would increase the size of every `.blend` file unreasonably.
+ * If we wanted to increase the size, we'd want to use compression (JPEG or similar).
+ */
#define BLEN_THUMB_SIZE 128
#define BLEN_THUMB_MEMSIZE(_x, _y) \
diff --git a/source/blender/blenkernel/BKE_main_idmap.h b/source/blender/blenkernel/BKE_main_idmap.h
index ff69883f0fb..16b0c710357 100644
--- a/source/blender/blenkernel/BKE_main_idmap.h
+++ b/source/blender/blenkernel/BKE_main_idmap.h
@@ -44,10 +44,21 @@ enum {
MAIN_IDMAP_TYPE_UUID = 1 << 1,
};
+/**
+ * Generate mapping from ID type/name to ID pointer for given \a bmain.
+ *
+ * \note When used during undo/redo, there is no guaranty that ID pointers from UI area are not
+ * pointing to freed memory (when some IDs have been deleted). To avoid crashes in those cases, one
+ * can provide the 'old' (aka current) Main database as reference. #BKE_main_idmap_lookup_id will
+ * then check that given ID does exist in \a old_bmain before trying to use it.
+ *
+ * \param create_valid_ids_set: If \a true, generate a reference to prevent freed memory accesses.
+ * \param old_bmain: If not NULL, its IDs will be added the valid references set.
+ */
struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain,
- const bool create_valid_ids_set,
+ bool create_valid_ids_set,
struct Main *old_bmain,
- const int idmap_types) ATTR_WARN_UNUSED_RESULT
+ int idmap_types) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map) ATTR_NONNULL();
@@ -67,8 +78,7 @@ struct ID *BKE_main_idmap_lookup_id(struct IDNameLib_Map *id_map,
ATTR_NONNULL(1, 2);
struct ID *BKE_main_idmap_lookup_uuid(struct IDNameLib_Map *id_map,
- const uint session_uuid) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL(1);
+ uint session_uuid) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 8e2f6e6f10c..e17f7eb4e85 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -56,16 +56,20 @@ typedef enum {
MASK_HANDLE_MODE_INDIVIDUAL_HANDLES = 2,
} eMaskhandleMode;
-struct MaskSplinePoint *BKE_mask_spline_point_array(struct MaskSpline *spline);
-struct MaskSplinePoint *BKE_mask_spline_point_array_from_point(
- struct MaskSpline *spline, const struct MaskSplinePoint *point_ref);
+/* -------------------------------------------------------------------- */
+/** \name Mask Layers
+ * \{ */
-/* mask layers */
struct MaskLayer *BKE_mask_layer_new(struct Mask *mask, const char *name);
+/**
+ * \note The returned mask-layer may be hidden, caller needs to check.
+ */
struct MaskLayer *BKE_mask_layer_active(struct Mask *mask);
void BKE_mask_layer_active_set(struct Mask *mask, struct MaskLayer *masklay);
void BKE_mask_layer_remove(struct Mask *mask, struct MaskLayer *masklay);
+/** \brief Free all animation keys for a mask layer.
+ */
void BKE_mask_layer_free_shapes(struct MaskLayer *masklay);
void BKE_mask_layer_free(struct MaskLayer *masklay);
void BKE_mask_layer_free_list(struct ListBase *masklayers);
@@ -83,7 +87,16 @@ void BKE_mask_layer_rename(struct Mask *mask,
struct MaskLayer *BKE_mask_layer_copy(const struct MaskLayer *masklay);
void BKE_mask_layer_copy_list(struct ListBase *masklayers_new, const struct ListBase *masklayers);
-/* splines */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Splines
+ * \{ */
+
+struct MaskSplinePoint *BKE_mask_spline_point_array(struct MaskSpline *spline);
+struct MaskSplinePoint *BKE_mask_spline_point_array_from_point(
+ struct MaskSpline *spline, const struct MaskSplinePoint *point_ref);
+
struct MaskSpline *BKE_mask_spline_add(struct MaskLayer *masklay);
bool BKE_mask_spline_remove(struct MaskLayer *mask_layer, struct MaskSpline *spline);
void BKE_mask_point_direction_switch(struct MaskSplinePoint *point);
@@ -102,9 +115,14 @@ float BKE_mask_spline_project_co(struct MaskSpline *spline,
struct MaskSplinePoint *point,
float start_u,
const float co[2],
- const eMaskSign sign);
+ eMaskSign sign);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Point
+ * \{ */
-/* point */
eMaskhandleMode BKE_mask_point_handles_mode_get(const struct MaskSplinePoint *point);
void BKE_mask_point_handle(const struct MaskSplinePoint *point,
eMaskWhichHandle which_handle,
@@ -126,20 +144,23 @@ void BKE_mask_point_normal(struct MaskSpline *spline,
float n[2]);
float BKE_mask_point_weight_scalar(struct MaskSpline *spline,
struct MaskSplinePoint *point,
- const float u);
-float BKE_mask_point_weight(struct MaskSpline *spline,
- struct MaskSplinePoint *point,
- const float u);
+ float u);
+float BKE_mask_point_weight(struct MaskSpline *spline, struct MaskSplinePoint *point, float u);
struct MaskSplinePointUW *BKE_mask_point_sort_uw(struct MaskSplinePoint *point,
struct MaskSplinePointUW *uw);
void BKE_mask_point_add_uw(struct MaskSplinePoint *point, float u, float w);
-void BKE_mask_point_select_set(struct MaskSplinePoint *point, const bool do_select);
+void BKE_mask_point_select_set(struct MaskSplinePoint *point, bool do_select);
void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point,
- const eMaskWhichHandle which_handle,
- const bool do_select);
+ eMaskWhichHandle which_handle,
+ bool do_select);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name General
+ * \{ */
-/* general */
struct Mask *BKE_mask_new(struct Main *bmain, const char *name);
void BKE_mask_coord_from_frame(float r_co[2], const float co[2], const float frame_size[2]);
@@ -151,6 +172,9 @@ void BKE_mask_coord_from_image(struct Image *image,
struct ImageUser *iuser,
float r_co[2],
const float co[2]);
+/**
+ * Inverse of #BKE_mask_coord_from_image.
+ */
void BKE_mask_coord_to_frame(float r_co[2], const float co[2], const float frame_size[2]);
void BKE_mask_coord_to_movieclip(struct MovieClip *clip,
struct MovieClipUser *user,
@@ -161,21 +185,34 @@ void BKE_mask_coord_to_image(struct Image *image,
float r_co[2],
const float co[2]);
-/* parenting */
+/** \} */
-void BKE_mask_evaluate(struct Mask *mask, const float ctime, const bool do_newframe);
-void BKE_mask_layer_evaluate(struct MaskLayer *masklay, const float ctime, const bool do_newframe);
+/* -------------------------------------------------------------------- */
+/** \name Parenting
+ * \{ */
+
+void BKE_mask_evaluate(struct Mask *mask, float ctime, bool do_newframe);
+void BKE_mask_layer_evaluate(struct MaskLayer *masklay, float ctime, bool do_newframe);
void BKE_mask_parent_init(struct MaskParent *parent);
void BKE_mask_calc_handle_adjacent_interp(struct MaskSpline *spline,
struct MaskSplinePoint *point,
- const float u);
+ float u);
+/**
+ * Calculates the tangent of a point by its previous and next
+ * (ignoring handles - as if its a poly line).
+ */
void BKE_mask_calc_tangent_polyline(struct MaskSpline *spline,
struct MaskSplinePoint *point,
float t[2]);
void BKE_mask_calc_handle_point(struct MaskSpline *spline, struct MaskSplinePoint *point);
+/**
+ * \brief Resets auto handles even for non-auto bezier points
+ *
+ * Useful for giving sane defaults.
+ */
void BKE_mask_calc_handle_point_auto(struct MaskSpline *spline,
struct MaskSplinePoint *point,
- const bool do_recalc_length);
+ bool do_recalc_length);
void BKE_mask_get_handle_point_adjacent(struct MaskSpline *spline,
struct MaskSplinePoint *point,
struct MaskSplinePoint **r_point_prev,
@@ -186,24 +223,43 @@ void BKE_mask_point_parent_matrix_get(struct MaskSplinePoint *point,
float ctime,
float parent_matrix[3][3]);
-/* animation */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation
+ * \{ */
+
int BKE_mask_layer_shape_totvert(struct MaskLayer *masklay);
+/**
+ * Inverse of #BKE_mask_layer_shape_to_mask
+ */
void BKE_mask_layer_shape_from_mask(struct MaskLayer *masklay,
struct MaskLayerShape *masklay_shape);
+/**
+ * Inverse of #BKE_mask_layer_shape_from_mask
+ */
void BKE_mask_layer_shape_to_mask(struct MaskLayer *masklay, struct MaskLayerShape *masklay_shape);
+/**
+ * \note Linear interpolation only.
+ */
void BKE_mask_layer_shape_to_mask_interp(struct MaskLayer *masklay,
struct MaskLayerShape *masklay_shape_a,
struct MaskLayerShape *masklay_shape_b,
- const float fac);
-struct MaskLayerShape *BKE_mask_layer_shape_find_frame(struct MaskLayer *masklay, const int frame);
+ float fac);
+struct MaskLayerShape *BKE_mask_layer_shape_find_frame(struct MaskLayer *masklay, int frame);
+/**
+ * When returning 2 - the frame isn't found but before/after frames are.
+ */
int BKE_mask_layer_shape_find_frame_range(struct MaskLayer *masklay,
- const float frame,
+ float frame,
struct MaskLayerShape **r_masklay_shape_a,
struct MaskLayerShape **r_masklay_shape_b);
-struct MaskLayerShape *BKE_mask_layer_shape_alloc(struct MaskLayer *masklay, const int frame);
+/**
+ * \note Does *not* add to the list.
+ */
+struct MaskLayerShape *BKE_mask_layer_shape_alloc(struct MaskLayer *masklay, int frame);
void BKE_mask_layer_shape_free(struct MaskLayerShape *masklay_shape);
-struct MaskLayerShape *BKE_mask_layer_shape_verify_frame(struct MaskLayer *masklay,
- const int frame);
+struct MaskLayerShape *BKE_mask_layer_shape_verify_frame(struct MaskLayer *masklay, int frame);
struct MaskLayerShape *BKE_mask_layer_shape_duplicate(struct MaskLayerShape *masklay_shape);
void BKE_mask_layer_shape_unlink(struct MaskLayer *masklay, struct MaskLayerShape *masklay_shape);
void BKE_mask_layer_shape_sort(struct MaskLayer *masklay);
@@ -214,19 +270,42 @@ bool BKE_mask_layer_shape_spline_from_index(struct MaskLayer *masklay,
int *r_index);
int BKE_mask_layer_shape_spline_to_index(struct MaskLayer *masklay, struct MaskSpline *spline);
+/**
+ * When a new points added, resizing all shape-key arrays.
+ */
void BKE_mask_layer_shape_changed_add(struct MaskLayer *masklay,
int index,
bool do_init,
bool do_init_interpolate);
+/**
+ * Move array elements to account for removed point.
+ */
void BKE_mask_layer_shape_changed_remove(struct MaskLayer *masklay, int index, int count);
int BKE_mask_get_duration(struct Mask *mask);
-/* clipboard */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clipboard
+ * \{ */
+
+/**
+ * Free the clipboard.
+ */
void BKE_mask_clipboard_free(void);
+/**
+ * Copy selected visible splines from the given layer to clipboard.
+ */
void BKE_mask_clipboard_copy_from_layer(struct MaskLayer *mask_layer);
+/**
+ * Check clipboard is empty.
+ */
bool BKE_mask_clipboard_is_empty(void);
+/**
+ * Paste the contents of clipboard to given mask layer.
+ */
void BKE_mask_clipboard_paste_to_layer(struct Main *bmain, struct MaskLayer *mask_layer);
#define MASKPOINT_ISSEL_ANY(p) ((((p)->bezt.f1 | (p)->bezt.f2 | (p)->bezt.f3) & SELECT) != 0)
@@ -260,29 +339,40 @@ void BKE_mask_clipboard_paste_to_layer(struct Main *bmain, struct MaskLayer *mas
} \
(void)0
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation
+ * \{ */
+
#define MASK_RESOL_MAX 128
/* mask_evaluate.c */
+
unsigned int BKE_mask_spline_resolution(struct MaskSpline *spline, int width, int height);
unsigned int BKE_mask_spline_feather_resolution(struct MaskSpline *spline, int width, int height);
-int BKE_mask_spline_differentiate_calc_total(const struct MaskSpline *spline,
- const unsigned int resol);
+int BKE_mask_spline_differentiate_calc_total(const struct MaskSpline *spline, unsigned int resol);
float (*BKE_mask_spline_differentiate_with_resolution(struct MaskSpline *spline,
- const unsigned int resol,
+ unsigned int resol,
unsigned int *r_tot_diff_point))[2];
void BKE_mask_spline_feather_collapse_inner_loops(struct MaskSpline *spline,
float (*feather_points)[2],
- const unsigned int tot_feather_point);
+ unsigned int tot_feather_point);
float (*BKE_mask_spline_differentiate(
struct MaskSpline *spline, int width, int height, unsigned int *r_tot_diff_point))[2];
+/**
+ * values align with #BKE_mask_spline_differentiate_with_resolution
+ * when \a resol arguments match.
+ */
float (*BKE_mask_spline_feather_differentiated_points_with_resolution(
struct MaskSpline *spline,
- const unsigned int resol,
- const bool do_feather_isect,
+ unsigned int resol,
+ bool do_feather_isect,
unsigned int *r_tot_feather_point))[2];
/* *** mask point functions which involve evaluation *** */
+
float (*BKE_mask_spline_feather_points(struct MaskSpline *spline, int *tot_feather_point))[2];
float *BKE_mask_point_segment_diff(struct MaskSpline *spline,
@@ -291,19 +381,28 @@ float *BKE_mask_point_segment_diff(struct MaskSpline *spline,
int height,
unsigned int *r_tot_diff_point);
+/* *** mask point functions which involve evaluation *** */
+
float *BKE_mask_point_segment_feather_diff(struct MaskSpline *spline,
struct MaskSplinePoint *point,
int width,
int height,
unsigned int *tot_feather_point);
-void BKE_mask_layer_evaluate_animation(struct MaskLayer *masklay, const float ctime);
-void BKE_mask_layer_evaluate_deform(struct MaskLayer *masklay, const float ctime);
+void BKE_mask_layer_evaluate_animation(struct MaskLayer *masklay, float ctime);
+void BKE_mask_layer_evaluate_deform(struct MaskLayer *masklay, float ctime);
void BKE_mask_eval_animation(struct Depsgraph *depsgraph, struct Mask *mask);
void BKE_mask_eval_update(struct Depsgraph *depsgraph, struct Mask *mask);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Rasterization
+ * \{ */
+
/* mask_rasterize.c */
+
struct MaskRasterHandle;
typedef struct MaskRasterHandle MaskRasterHandle;
@@ -311,18 +410,23 @@ MaskRasterHandle *BKE_maskrasterize_handle_new(void);
void BKE_maskrasterize_handle_free(MaskRasterHandle *mr_handle);
void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
struct Mask *mask,
- const int width,
- const int height,
- const bool do_aspect_correct,
- const bool do_mask_aa,
- const bool do_feather);
+ int width,
+ int height,
+ bool do_aspect_correct,
+ bool do_mask_aa,
+ bool do_feather);
float BKE_maskrasterize_handle_sample(MaskRasterHandle *mr_handle, const float xy[2]);
+/**
+ * \brief Rasterize a buffer from a single mask (threaded execution).
+ */
void BKE_maskrasterize_buffer(MaskRasterHandle *mr_handle,
- const unsigned int width,
- const unsigned int height,
+ unsigned int width,
+ unsigned int height,
float *buffer);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index b1eaf7207fa..11746f445e4 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -34,23 +34,38 @@ struct Object;
struct Scene;
struct bNode;
-/* Module */
+/* -------------------------------------------------------------------- */
+/** \name Module
+ * \{ */
void BKE_materials_init(void);
void BKE_materials_exit(void);
-/* Materials */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Materials
+ * \{ */
void BKE_object_materials_test(struct Main *bmain, struct Object *ob, struct ID *id);
void BKE_objects_materials_test_all(struct Main *bmain, struct ID *id);
void BKE_object_material_resize(struct Main *bmain,
struct Object *ob,
- const short totcol,
+ short totcol,
bool do_id_user);
void BKE_object_material_remap(struct Object *ob, const unsigned int *remap);
+/**
+ * Calculate a material remapping from \a ob_src to \a ob_dst.
+ *
+ * \param remap_src_to_dst: An array the size of `ob_src->totcol`
+ * where index values are filled in which map to \a ob_dst materials.
+ */
void BKE_object_material_remap_calc(struct Object *ob_dst,
struct Object *ob_src,
short *remap_src_to_dst);
+/**
+ * Copy materials from evaluated geometry to the original geometry of an object.
+ */
void BKE_object_material_from_eval_data(struct Main *bmain,
struct Object *ob_orig,
struct ID *data_eval);
@@ -61,10 +76,17 @@ void BKE_gpencil_material_attr_init(struct Material *ma);
/* UNUSED */
// void automatname(struct Material *);
-/* material slots */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Material Slots
+ * \{ */
struct Material ***BKE_object_material_array_p(struct Object *ob);
short *BKE_object_material_len_p(struct Object *ob);
+/**
+ * \note Same as #BKE_object_material_len_p but for ID's.
+ */
struct Material ***BKE_id_material_array_p(struct ID *id); /* same but for ID's */
short *BKE_id_material_len_p(struct ID *id);
@@ -81,11 +103,14 @@ struct Material *BKE_object_material_get(struct Object *ob, short act);
void BKE_id_material_assign(struct Main *bmain, struct ID *id, struct Material *ma, short act);
void BKE_object_material_assign(
struct Main *bmain, struct Object *ob, struct Material *ma, short act, int assign_type);
+/**
+ * \warning this calls many more update calls per object then are needed, could be optimized.
+ */
void BKE_object_material_array_assign(struct Main *bmain,
struct Object *ob,
struct Material ***matar,
int totcol,
- const bool to_object_only);
+ bool to_object_only);
short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma);
bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob);
@@ -99,7 +124,12 @@ void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob);
struct bNode *BKE_texpaint_slot_material_find_node(struct Material *ma, short texpaint_slot);
-/* rna api */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name RNA API
+ * \{ */
+
void BKE_id_materials_copy(struct Main *bmain, struct ID *id_src, struct ID *id_dst);
void BKE_id_material_resize(struct Main *bmain, struct ID *id, short totcol, bool do_id_user);
void BKE_id_material_append(struct Main *bmain, struct ID *id, struct Material *ma);
@@ -109,23 +139,57 @@ struct Material *BKE_id_material_pop(struct Main *bmain,
int index);
void BKE_id_material_clear(struct Main *bmain, struct ID *id);
-/* eval api */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation API
+ * \{ */
+
+/**
+ * On evaluated objects the number of materials on an object and its data might go out of sync.
+ * This is because during evaluation materials can be added/removed on the object data.
+ *
+ * For rendering or exporting we generally use the materials on the object data. However, some
+ * material indices might be overwritten by the object.
+ */
struct Material *BKE_object_material_get_eval(struct Object *ob, short act);
int BKE_object_material_count_eval(struct Object *ob);
void BKE_id_material_eval_assign(struct ID *id, int slot, struct Material *material);
+/**
+ * Add an empty material slot if the id has no material slots. This material slot allows the
+ * material to be overwritten by object-linked materials.
+ */
void BKE_id_material_eval_ensure_default_slot(struct ID *id);
-/* rendering */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Rendering
+ * \{ */
+
+/**
+ * \param r_col: current value.
+ * \param col: new value.
+ * \param fac: Zero for is no change.
+ */
+void ramp_blend(int type, float r_col[3], float fac, const float col[3]);
+
+/** \} */
-void ramp_blend(int type, float r_col[3], const float fac, const float col[3]);
+/* -------------------------------------------------------------------- */
+/** \name Copy/Paste
+ * \{ */
-/* copy/paste */
void BKE_material_copybuf_clear(void);
void BKE_material_copybuf_free(void);
void BKE_material_copybuf_copy(struct Main *bmain, struct Material *ma);
void BKE_material_copybuf_paste(struct Main *bmain, struct Material *ma);
-/* Default Materials */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Default Materials
+ * \{ */
struct Material *BKE_material_default_empty(void);
struct Material *BKE_material_default_holdout(void);
@@ -135,12 +199,18 @@ struct Material *BKE_material_default_gpencil(void);
void BKE_material_defaults_free_gpu(void);
-/* Dependency graph evaluation. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dependency graph evaluation
+ * \{ */
struct Depsgraph;
void BKE_material_eval(struct Depsgraph *depsgraph, struct Material *material);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index db4dca14535..fb72b361a0a 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -41,27 +41,66 @@ bool BKE_mball_is_any_selected(const struct MetaBall *mb);
bool BKE_mball_is_any_selected_multi(struct Base **bases, int bases_len);
bool BKE_mball_is_any_unselected(const struct MetaBall *mb);
bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2);
+/**
+ * Test, if \a ob is a basis meta-ball.
+ *
+ * It test last character of Object ID name.
+ * If last character is digit it return 0, else it return 1.
+ */
bool BKE_mball_is_basis(struct Object *ob);
+/**
+ * This function finds the basis meta-ball.
+ *
+ * Basis meta-ball doesn't include any number at the end of
+ * its name. All meta-balls with same base of name can be
+ * blended. meta-balls with different basic name can't be blended.
+ *
+ * \warning #BKE_mball_is_basis() can fail on returned object, see function docs for details.
+ */
struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob);
+/**
+ * Compute bounding box of all meta-elements / meta-ball.
+ *
+ * Bounding box is computed from polygonized surface. \a ob is
+ * basic meta-balls (with name `Meta` for example). All other meta-ball objects
+ * (with names `Meta.001`, `Meta.002`, etc) are included in this bounding-box.
+ */
void BKE_mball_texspace_calc(struct Object *ob);
+/**
+ * Return or compute bounding-box for given meta-ball object.
+ */
struct BoundBox *BKE_mball_boundbox_get(struct Object *ob);
float *BKE_mball_make_orco(struct Object *ob, struct ListBase *dispbase);
+/**
+ * Copy some properties from object to other meta-ball object with same base name.
+ *
+ * When some properties (wire-size, threshold, update flags) of meta-ball are changed, then this
+ * properties are copied to all meta-balls in same "group" (meta-balls with same base name:
+ * `MBall`, `MBall.001`, `MBall.002`, etc). The most important is to copy properties to the base
+ * meta-ball, because this meta-ball influence polygonization of meta-balls. */
void BKE_mball_properties_copy(struct Scene *scene, struct Object *active_object);
-bool BKE_mball_minmax_ex(const struct MetaBall *mb,
- float min[3],
- float max[3],
- const float obmat[4][4],
- const short flag);
+bool BKE_mball_minmax_ex(
+ const struct MetaBall *mb, float min[3], float max[3], const float obmat[4][4], short flag);
+
+/* Basic vertex data functions. */
+
bool BKE_mball_minmax(const struct MetaBall *mb, float min[3], float max[3]);
bool BKE_mball_center_median(const struct MetaBall *mb, float r_cent[3]);
bool BKE_mball_center_bounds(const struct MetaBall *mb, float r_cent[3]);
-void BKE_mball_transform(struct MetaBall *mb, const float mat[4][4], const bool do_props);
+void BKE_mball_transform(struct MetaBall *mb, const float mat[4][4], bool do_props);
void BKE_mball_translate(struct MetaBall *mb, const float offset[3]);
-struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type);
+/**
+ * Most simple meta-element adding function.
+ *
+ * \note don't do context manipulation here (rna uses).
+ */
+struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, int type);
+
+/* *** select funcs *** */
int BKE_mball_select_count(const struct MetaBall *mb);
int BKE_mball_select_count_multi(struct Base **bases, int bases_len);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index b0a8fee1178..e1c706a82dc 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -23,6 +23,7 @@
*/
#include "BKE_mesh_types.h"
+#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
struct BLI_Stack;
@@ -74,7 +75,7 @@ struct BMesh *BKE_mesh_to_bmesh_ex(const struct Mesh *me,
const struct BMeshFromMeshParams *convert_params);
struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me,
struct Object *ob,
- const bool add_key_index,
+ bool add_key_index,
const struct BMeshCreateParams *params);
struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm,
@@ -84,23 +85,56 @@ struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm,
const struct CustomData_MeshMasks *cd_mask_extra,
const struct Mesh *me_settings);
+/**
+ * Find the index of the loop in 'poly' which references vertex,
+ * returns -1 if not found
+ */
int poly_find_loop_from_vert(const struct MPoly *poly, const struct MLoop *loopstart, uint vert);
+/**
+ * Fill \a r_adj with the loop indices in \a poly adjacent to the
+ * vertex. Returns the index of the loop matching vertex, or -1 if the
+ * vertex is not in \a poly
+ */
int poly_get_adj_loops_from_vert(const struct MPoly *poly,
const struct MLoop *mloop,
unsigned int vert,
unsigned int r_adj[2]);
+/**
+ * Return the index of the edge vert that is not equal to \a v. If
+ * neither edge vertex is equal to \a v, returns -1.
+ */
int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
+/**
+ * Sets each output array element to the edge index if it is a real edge, or -1.
+ */
void BKE_mesh_looptri_get_real_edges(const struct Mesh *mesh,
const struct MLoopTri *looptri,
int r_edges[3]);
+/**
+ * Free (or release) any data used by this mesh (does not free the mesh itself).
+ * Only use for undo, in most cases `BKE_id_free(nullptr, me)` should be used.
+ */
void BKE_mesh_free_data_for_undo(struct Mesh *me);
void BKE_mesh_clear_geometry(struct Mesh *me);
struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name);
+
+void BKE_mesh_free_editmesh(struct Mesh *mesh);
+
+/**
+ * A version of #BKE_mesh_copy_parameters that is intended for evaluated output
+ * (the modifier stack for example).
+ *
+ * \warning User counts are not handled for ID's.
+ */
void BKE_mesh_copy_parameters_for_eval(struct Mesh *me_dst, const struct Mesh *me_src);
+/**
+ * Copy user editable settings that we want to preserve
+ * when a new mesh is based on an existing mesh.
+ */
void BKE_mesh_copy_parameters(struct Mesh *me_dst, const struct Mesh *me_src);
-void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd);
+void BKE_mesh_update_customdata_pointers(struct Mesh *me, bool do_ensure_tess_cd);
void BKE_mesh_ensure_skin_customdata(struct Mesh *me);
struct Mesh *BKE_mesh_new_nomain(
@@ -121,12 +155,16 @@ struct Mesh *BKE_mesh_new_nomain_from_template_ex(const struct Mesh *me_src,
void BKE_mesh_eval_delete(struct Mesh *mesh_eval);
-/* Performs copy for use during evaluation,
- * optional referencing original arrays to reduce memory. */
+/**
+ * Performs copy for use during evaluation,
+ * optional referencing original arrays to reduce memory.
+ */
struct Mesh *BKE_mesh_copy_for_eval(const struct Mesh *source, bool reference);
-/* These functions construct a new Mesh,
- * contrary to BKE_mesh_to_curve_nurblist which modifies ob itself. */
+/**
+ * These functions construct a new Mesh,
+ * contrary to #BKE_mesh_to_curve_nurblist which modifies ob itself.
+ */
struct Mesh *BKE_mesh_new_nomain_from_curve(const struct Object *ob);
struct Mesh *BKE_mesh_new_nomain_from_curve_displist(const struct Object *ob,
const struct ListBase *dispbase);
@@ -136,6 +174,16 @@ bool BKE_mesh_clear_facemap_customdata(struct Mesh *me);
float (*BKE_mesh_orco_verts_get(struct Object *ob))[3];
void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totvert, int invert);
+
+/**
+ * Add a #CD_ORCO layer to the Mesh if there is none already.
+ */
+void BKE_mesh_orco_ensure(struct Object *ob, struct Mesh *mesh);
+
+/**
+ * Rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0.
+ * this is necessary to make the if #MFace.v4 check for quads work.
+ */
int BKE_mesh_mface_index_validate(struct MFace *mface,
struct CustomData *mfdata,
int mfindex,
@@ -145,7 +193,7 @@ void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *
void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me);
void BKE_mesh_to_curve_nurblist(const struct Mesh *me,
struct ListBase *nurblist,
- const int edge_users_test);
+ int edge_users_test);
void BKE_mesh_to_curve(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -164,11 +212,19 @@ void BKE_mesh_material_index_remove(struct Mesh *me, short index);
bool BKE_mesh_material_index_used(struct Mesh *me, short index);
void BKE_mesh_material_index_clear(struct Mesh *me);
void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len);
-void BKE_mesh_smooth_flag_set(struct Mesh *me, const bool use_smooth);
+void BKE_mesh_smooth_flag_set(struct Mesh *me, bool use_smooth);
-/* Needed after converting a mesh with subsurf optimal display to mesh. */
+/**
+ * Needed after converting a mesh with subsurf optimal display to mesh.
+ */
void BKE_mesh_edges_set_draw_render(struct Mesh *me);
+/**
+ * Used for unit testing; compares two meshes, checking only
+ * differences we care about. should be usable with leaf's
+ * testing framework I get RNA work done, will use hackish
+ * testing code for now.
+ */
const char *BKE_mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
struct BoundBox *BKE_mesh_boundbox_get(struct Object *ob);
@@ -177,41 +233,59 @@ void BKE_mesh_texspace_calc(struct Mesh *me);
void BKE_mesh_texspace_ensure(struct Mesh *me);
void BKE_mesh_texspace_get(struct Mesh *me, float r_loc[3], float r_size[3]);
void BKE_mesh_texspace_get_reference(struct Mesh *me,
- short **r_texflag,
+ char **r_texflag,
float **r_loc,
float **r_size);
void BKE_mesh_texspace_copy_from_object(struct Mesh *me, struct Object *ob);
+/**
+ * Split faces based on the edge angle and loop normals.
+ * Matches behavior of face splitting in render engines.
+ *
+ * \note Will leave #CD_NORMAL loop data layer which is used by render engines to set shading up.
+ */
void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals);
-/* Create new mesh from the given object at its current state.
+/**
+ * Create new mesh from the given object at its current state.
* The owner of this mesh is unknown, it is up to the caller to decide.
*
* If preserve_all_data_layers is truth then the modifier stack is re-evaluated to ensure it
* preserves all possible custom data layers.
*
- * NOTE: Dependency graph argument is required when preserve_all_data_layers is truth, and is
- * ignored otherwise. */
+ * \note Dependency graph argument is required when preserve_all_data_layers is truth, and is
+ * ignored otherwise.
+ */
struct Mesh *BKE_mesh_new_from_object(struct Depsgraph *depsgraph,
struct Object *object,
- const bool preserve_all_data_layers,
- const bool preserve_origindex);
+ bool preserve_all_data_layers,
+ bool preserve_origindex);
-/* This is a version of BKE_mesh_new_from_object() which stores mesh in the given main database.
+/**
+ * This is a version of BKE_mesh_new_from_object() which stores mesh in the given main database.
* However, that function enforces object type to be a geometry one, and ensures a mesh is always
- * generated, be it empty. */
+ * generated, be it empty.
+ */
struct Mesh *BKE_mesh_new_from_object_to_bmain(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Object *object,
bool preserve_all_data_layers);
+/**
+ * \param use_virtual_modifiers: When enabled calculate virtual-modifiers before applying `md_eval`
+ * support this since virtual-modifiers are not modifiers from a user perspective,
+ * allowing shape keys to be included with the modifier being applied, see: T91923.
+ */
struct Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_eval,
struct ModifierData *md_eval,
- const bool build_shapekey_layers);
+ bool use_virtual_modifiers,
+ bool build_shapekey_layers);
-/* Copies a nomain-Mesh into an existing Mesh. */
+/**
+ * Copies a nomain-Mesh into an existing Mesh.
+ */
void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src,
struct Mesh *mesh_dst,
struct Object *ob,
@@ -221,9 +295,10 @@ void BKE_mesh_nomain_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, st
/* vertex level transformations & checks (no derived mesh) */
+/* basic vertex data functions */
bool BKE_mesh_minmax(const struct Mesh *me, float r_min[3], float r_max[3]);
void BKE_mesh_transform(struct Mesh *me, const float mat[4][4], bool do_keys);
-void BKE_mesh_translate(struct Mesh *me, const float offset[3], const bool do_keys);
+void BKE_mesh_translate(struct Mesh *me, const float offset[3], bool do_keys);
void BKE_mesh_tessface_ensure(struct Mesh *mesh);
void BKE_mesh_tessface_clear(struct Mesh *mesh);
@@ -232,7 +307,13 @@ void BKE_mesh_do_versions_cd_flag_init(struct Mesh *mesh);
void BKE_mesh_mselect_clear(struct Mesh *me);
void BKE_mesh_mselect_validate(struct Mesh *me);
+/**
+ * \return the index within `me->mselect`, or -1
+ */
int BKE_mesh_mselect_find(struct Mesh *me, int index, int type);
+/**
+ * \return The index of the active element.
+ */
int BKE_mesh_mselect_active_get(struct Mesh *me, int type);
void BKE_mesh_mselect_active_set(struct Mesh *me, int index, int type);
@@ -245,10 +326,20 @@ void BKE_mesh_vert_coords_apply_with_mat4(struct Mesh *mesh,
const float (*vert_coords)[3],
const float mat[4][4]);
void BKE_mesh_vert_coords_apply(struct Mesh *mesh, const float (*vert_coords)[3]);
-void BKE_mesh_vert_normals_apply(struct Mesh *mesh, const short (*vert_normals)[3]);
/* *** mesh_tessellate.c *** */
+/**
+ * Recreate #MFace Tessellation.
+ *
+ * \param do_face_nor_copy: Controls whether the normals from the poly
+ * are copied to the tessellated faces.
+ *
+ * \return number of tessellation faces.
+ *
+ * \note This doesn't use multi-threading like #BKE_mesh_recalc_looptri since
+ * it's not used in many places and #MFace should be phased out.
+ */
int BKE_mesh_tessface_calc_ex(struct CustomData *fdata,
struct CustomData *ldata,
struct CustomData *pdata,
@@ -256,15 +347,26 @@ int BKE_mesh_tessface_calc_ex(struct CustomData *fdata,
int totface,
int totloop,
int totpoly,
- const bool do_face_nor_copy);
+ bool do_face_nor_copy);
void BKE_mesh_tessface_calc(struct Mesh *mesh);
+/**
+ * Calculate tessellation into #MLoopTri which exist only for this purpose.
+ */
void BKE_mesh_recalc_looptri(const struct MLoop *mloop,
const struct MPoly *mpoly,
const struct MVert *mvert,
int totloop,
int totpoly,
struct MLoopTri *mlooptri);
+/**
+ * A version of #BKE_mesh_recalc_looptri which takes pre-calculated polygon normals
+ * (used to avoid having to calculate the face normal for NGON tessellation).
+ *
+ * \note Only use this function if normals have already been calculated, there is no need
+ * to calculate normals just to use this function as it will cause the normals for triangles
+ * to be calculated which aren't needed for tessellation.
+ */
void BKE_mesh_recalc_looptri_with_normals(const struct MLoop *mloop,
const struct MPoly *mpoly,
const struct MVert *mvert,
@@ -275,7 +377,83 @@ void BKE_mesh_recalc_looptri_with_normals(const struct MLoop *mloop,
/* *** mesh_normals.cc *** */
+/**
+ * Returns the normals for each vertex, which is defined as the weighted average of the normals
+ * from a vertices surrounding faces, or the normalized position of vertices connected to no faces.
+ * \warning May still return null if the mesh is empty.
+ */
+const float (*BKE_mesh_vertex_normals_ensure(const struct Mesh *mesh))[3];
+
+/**
+ * Return the normal direction of every polygon, which is defined by the winding direction of its
+ * corners.
+ * \warning May still return null if the mesh is empty or has no polygons.
+ */
+const float (*BKE_mesh_poly_normals_ensure(const struct Mesh *mesh))[3];
+
+/**
+ * Tag mesh vertex and face normals to be recalculated when/if they are needed later.
+ *
+ * \note Dirty tagged normals are the default state of a new mesh, so tagging them
+ * dirty explicitly is not always necessary if the mesh is created locally.
+ */
void BKE_mesh_normals_tag_dirty(struct Mesh *mesh);
+
+/**
+ * Check that a mesh with non-dirty normals has vertex and face custom data layers.
+ * If these asserts fail, it means some area cleared the dirty flag but didn't copy or add the
+ * normal layers, or removed normals but didn't set the dirty flag.
+ */
+void BKE_mesh_assert_normals_dirty_or_calculated(const struct Mesh *mesh);
+
+/**
+ * Retrieve write access to the vertex normal layer, ensuring that it exists and that it is not
+ * shared. The provided vertex normals should be the same as if they were calculated automatically.
+ *
+ * \note In order to clear the dirty flag, this function should be followed by a call to
+ * #BKE_mesh_vertex_normals_clear_dirty. This is separate so that normals are still tagged dirty
+ * while they are being assigned.
+ */
+float (*BKE_mesh_vertex_normals_for_write(struct Mesh *mesh))[3];
+
+/**
+ * Retrieve write access to the poly normal layer, ensuring that it exists and that it is not
+ * shared. The provided poly normals should be the same as if they were calculated automatically.
+ *
+ * \note In order to clear the dirty flag, this function should be followed by a call to
+ * #BKE_mesh_poly_normals_clear_dirty. This is separate so that normals are still tagged dirty
+ * while they are being assigned.
+ */
+float (*BKE_mesh_poly_normals_for_write(struct Mesh *mesh))[3];
+
+/**
+ * Mark the mesh's vertex normals non-dirty, for when they are calculated or assigned manually.
+ */
+void BKE_mesh_vertex_normals_clear_dirty(struct Mesh *mesh);
+
+/**
+ * Mark the mesh's poly normals non-dirty, for when they are calculated or assigned manually.
+ */
+void BKE_mesh_poly_normals_clear_dirty(struct Mesh *mesh);
+
+/**
+ * Return true if the mesh vertex normals either are not stored or are dirty.
+ * This can be used to help decide whether to transfer them when copying a mesh.
+ */
+bool BKE_mesh_vertex_normals_are_dirty(const struct Mesh *mesh);
+
+/**
+ * Return true if the mesh polygon normals either are not stored or are dirty.
+ * This can be used to help decide whether to transfer them when copying a mesh.
+ */
+bool BKE_mesh_poly_normals_are_dirty(const struct Mesh *mesh);
+
+/**
+ * Calculate face normals directly into a result array.
+ *
+ * \note Usually #BKE_mesh_poly_normals_ensure is the preferred way to access face normals,
+ * since they may already be calculated and cached on the mesh.
+ */
void BKE_mesh_calc_normals_poly(const struct MVert *mvert,
int mvert_len,
const struct MLoop *mloop,
@@ -283,16 +461,19 @@ void BKE_mesh_calc_normals_poly(const struct MVert *mvert,
const struct MPoly *mpoly,
int mpoly_len,
float (*r_poly_normals)[3]);
-void BKE_mesh_calc_normals_poly_and_vertex(struct MVert *mvert,
- int mvert_len,
- const struct MLoop *mloop,
- int mloop_len,
- const struct MPoly *mpolys,
- int mpoly_len,
- float (*r_poly_normals)[3],
- float (*r_vert_normals)[3]);
+
+/**
+ * Calculate vertex and face normals, storing the result in custom data layers on the mesh.
+ *
+ * \note It is usually preferable to calculate normals lazily with
+ * #BKE_mesh_vertex_normals_ensure, but some areas (perhaps unnecessarily)
+ * can also calculate them eagerly.
+ */
void BKE_mesh_calc_normals(struct Mesh *me);
-void BKE_mesh_ensure_normals(struct Mesh *me);
+
+/**
+ * Called after calculating all modifiers.
+ */
void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh);
void BKE_mesh_calc_normals_looptri(struct MVert *mverts,
int numVerts,
@@ -304,22 +485,28 @@ void BKE_mesh_loop_manifold_fan_around_vert_next(const struct MLoop *mloops,
const struct MPoly *mpolys,
const int *loop_to_poly,
const int *e2lfan_curr,
- const uint mv_pivot_index,
+ uint mv_pivot_index,
const struct MLoop **r_mlfan_curr,
int *r_mlfan_curr_index,
int *r_mlfan_vert_index,
int *r_mpfan_curr_index);
+/**
+ * Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
+ *
+ * Used when defining an empty custom loop normals data layer,
+ * to keep same shading as with auto-smooth!
+ */
void BKE_edges_sharp_from_angle_set(const struct MVert *mverts,
- const int numVerts,
+ int numVerts,
struct MEdge *medges,
- const int numEdges,
+ int numEdges,
struct MLoop *mloops,
- const int numLoops,
+ int numLoops,
struct MPoly *mpolys,
const float (*polynors)[3],
- const int numPolys,
- const float split_angle);
+ int numPolys,
+ float split_angle);
/**
* References a contiguous loop-fan with normal offset vars.
@@ -372,28 +559,51 @@ enum {
};
/* Low-level custom normals functions. */
-void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr,
- const int numLoops,
- const char data_type);
+void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, int numLoops, char data_type);
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr);
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr);
+/**
+ * Utility for multi-threaded calculation that ensures
+ * `lnors_spacearr_tls` doesn't share memory with `lnors_spacearr`
+ * that would cause it not to be thread safe.
+ *
+ * \note This works as long as threads never operate on the same loops at once.
+ */
void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpaceArray *lnors_spacearr_tls);
+/**
+ * Utility for multi-threaded calculation
+ * that merges `lnors_spacearr_tls` into `lnors_spacearr`.
+ */
void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpaceArray *lnors_spacearr_tls);
MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr);
+/**
+ * Should only be called once.
+ * Beware, this modifies ref_vec and other_vec in place!
+ * In case no valid space can be generated, ref_alpha and ref_beta are set to zero
+ * (which means 'use auto lnors').
+ */
void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
const float lnor[3],
float vec_ref[3],
float vec_other[3],
struct BLI_Stack *edge_vectors);
+/**
+ * Add a new given loop to given lnor_space.
+ * Depending on \a lnor_space->data_type, we expect \a bm_loop to be a pointer to BMLoop struct
+ * (in case of BMLOOP_PTR), or nullptr (in case of LOOP_INDEX), loop index is then stored in
+ * pointer. If \a is_single is set, the BMLoop or loop index is directly stored in \a
+ * lnor_space->loops pointer (since there is only one loop in this fan), else it is added to the
+ * linked list of loops in the fan.
+ */
void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpace *lnor_space,
- const int ml_index,
+ int ml_index,
void *bm_loop,
- const bool is_single);
+ bool is_single);
void BKE_lnor_space_custom_data_to_normal(MLoopNorSpace *lnor_space,
const short clnor_data[2],
float r_custom_lnor[3]);
@@ -402,59 +612,97 @@ void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space,
short r_clnor_data[2]);
/* Medium-level custom normals functions. */
+
+/**
+ * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
+ * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
+ * (splitting edges).
+ */
void BKE_mesh_normals_loop_split(const struct MVert *mverts,
- const int numVerts,
+ const float (*vert_normals)[3],
+ int numVerts,
struct MEdge *medges,
- const int numEdges,
+ int numEdges,
struct MLoop *mloops,
float (*r_loopnors)[3],
- const int numLoops,
+ int numLoops,
struct MPoly *mpolys,
const float (*polynors)[3],
- const int numPolys,
- const bool use_split_normals,
- const float split_angle,
+ int numPolys,
+ bool use_split_normals,
+ float split_angle,
MLoopNorSpaceArray *r_lnors_spacearr,
short (*clnors_data)[2],
int *r_loop_to_poly);
void BKE_mesh_normals_loop_custom_set(const struct MVert *mverts,
- const int numVerts,
+ const float (*vert_normals)[3],
+ int numVerts,
struct MEdge *medges,
- const int numEdges,
+ int numEdges,
struct MLoop *mloops,
float (*r_custom_loopnors)[3],
- const int numLoops,
+ int numLoops,
struct MPoly *mpolys,
const float (*polynors)[3],
- const int numPolys,
+ int numPolys,
short (*r_clnors_data)[2]);
void BKE_mesh_normals_loop_custom_from_vertices_set(const struct MVert *mverts,
+ const float (*vert_normals)[3],
float (*r_custom_vertnors)[3],
- const int numVerts,
+ int numVerts,
struct MEdge *medges,
- const int numEdges,
+ int numEdges,
struct MLoop *mloops,
- const int numLoops,
+ int numLoops,
struct MPoly *mpolys,
const float (*polynors)[3],
- const int numPolys,
+ int numPolys,
short (*r_clnors_data)[2]);
-void BKE_mesh_normals_loop_to_vertex(const int numVerts,
+/**
+ * Computes average per-vertex normals from given custom loop normals.
+ *
+ * \param clnors: The computed custom loop normals.
+ * \param r_vert_clnors: The (already allocated) array where to store averaged per-vertex normals.
+ */
+void BKE_mesh_normals_loop_to_vertex(int numVerts,
const struct MLoop *mloops,
- const int numLoops,
+ int numLoops,
const float (*clnors)[3],
float (*r_vert_clnors)[3]);
-/* High-level custom normals functions. */
+/**
+ * High-level custom normals functions.
+ */
bool BKE_mesh_has_custom_loop_normals(struct Mesh *me);
void BKE_mesh_calc_normals_split(struct Mesh *mesh);
+/**
+ * Compute 'split' (aka loop, or per face corner's) normals.
+ *
+ * \param r_lnors_spacearr: Allows to get computed loop normal space array.
+ * That data, among other things, contains 'smooth fan' info, useful e.g.
+ * to split geometry along sharp edges.
+ */
void BKE_mesh_calc_normals_split_ex(struct Mesh *mesh,
struct MLoopNorSpaceArray *r_lnors_spacearr);
+/**
+ * Higher level functions hiding most of the code needed around call to
+ * #BKE_mesh_normals_loop_custom_set().
+ *
+ * \param r_custom_loopnors: is not const, since code will replace zero_v3 normals there
+ * with automatically computed vectors.
+ */
void BKE_mesh_set_custom_normals(struct Mesh *mesh, float (*r_custom_loopnors)[3]);
+/**
+ * Higher level functions hiding most of the code needed around call to
+ * #BKE_mesh_normals_loop_custom_from_vertices_set().
+ *
+ * \param r_custom_vertnors: is not const, since code will replace zero_v3 normals there
+ * with automatically computed vectors.
+ */
void BKE_mesh_set_custom_normals_from_vertices(struct Mesh *mesh, float (*r_custom_vertnors)[3]);
/* *** mesh_evaluate.cc *** */
@@ -471,6 +719,7 @@ void BKE_mesh_calc_poly_center(const struct MPoly *mpoly,
const struct MLoop *loopstart,
const struct MVert *mvarray,
float r_cent[3]);
+/* NOTE: passing poly-normal is only a speedup so we can skip calculating it. */
float BKE_mesh_calc_poly_area(const struct MPoly *mpoly,
const struct MLoop *loopstart,
const struct MVert *mvarray);
@@ -489,21 +738,48 @@ void BKE_mesh_poly_edgebitmap_insert(unsigned int *edge_bitmap,
const struct MLoop *mloop);
bool BKE_mesh_center_median(const struct Mesh *me, float r_cent[3]);
+/**
+ * Calculate the center from polygons,
+ * use when we want to ignore vertex locations that don't have connected faces.
+ */
bool BKE_mesh_center_median_from_polys(const struct Mesh *me, float r_cent[3]);
bool BKE_mesh_center_bounds(const struct Mesh *me, float r_cent[3]);
bool BKE_mesh_center_of_surface(const struct Mesh *me, float r_cent[3]);
+/**
+ * \note Mesh must be manifold with consistent face-winding,
+ * see #mesh_calc_poly_volume_centroid for details.
+ */
bool BKE_mesh_center_of_volume(const struct Mesh *me, float r_cent[3]);
+/**
+ * Calculate the volume and center.
+ *
+ * \param r_volume: Volume (unsigned).
+ * \param r_center: Center of mass.
+ */
void BKE_mesh_calc_volume(const struct MVert *mverts,
- const int mverts_num,
+ int mverts_num,
const struct MLoopTri *mlooptri,
- const int looptri_num,
+ int looptri_num,
const struct MLoop *mloop,
float *r_volume,
float r_center[3]);
/* tessface */
void BKE_mesh_convert_mfaces_to_mpolys(struct Mesh *mesh);
+/**
+ * The same as #BKE_mesh_convert_mfaces_to_mpolys
+ * but oriented to be used in #do_versions from `readfile.c`
+ * the difference is how active/render/clone/stencil indices are handled here.
+ *
+ * normally they're being set from `pdata` which totally makes sense for meshes which are already
+ * converted to #BMesh structures, but when loading older files indices shall be updated in other
+ * way around, so newly added `pdata` and `ldata` would have this indices set
+ * based on `fdata` layer.
+ *
+ * this is normally only needed when reading older files,
+ * in all other cases #BKE_mesh_convert_mfaces_to_mpolys shall be always used.
+ */
void BKE_mesh_do_versions_convert_mfaces_to_mpolys(struct Mesh *mesh);
void BKE_mesh_convert_mfaces_to_mpolys_ex(struct ID *id,
struct CustomData *fdata,
@@ -520,15 +796,32 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(struct ID *id,
struct MLoop **r_mloop,
struct MPoly **r_mpoly);
-void BKE_mesh_mdisp_flip(struct MDisps *md, const bool use_loop_mdisp_flip);
+/**
+ * Flip a single MLoop's #MDisps structure,
+ * low level function to be called from face-flipping code which re-arranged the mdisps themselves.
+ */
+void BKE_mesh_mdisp_flip(struct MDisps *md, bool use_loop_mdisp_flip);
+/**
+ * Flip (invert winding of) the given \a mpoly, i.e. reverse order of its loops
+ * (keeping the same vertex as 'start point').
+ *
+ * \param mpoly: the polygon to flip.
+ * \param mloop: the full loops array.
+ * \param ldata: the loops custom data.
+ */
void BKE_mesh_polygon_flip_ex(struct MPoly *mpoly,
struct MLoop *mloop,
struct CustomData *ldata,
float (*lnors)[3],
struct MDisps *mdisp,
- const bool use_loop_mdisp_flip);
+ bool use_loop_mdisp_flip);
void BKE_mesh_polygon_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata);
+/**
+ * Flip (invert winding of) all polygons (used to inverse their normals).
+ *
+ * \note Invalidates tessellation, caller must handle that.
+ */
void BKE_mesh_polygons_flip(struct MPoly *mpoly,
struct MLoop *mloop,
struct CustomData *ldata,
@@ -541,48 +834,98 @@ enum {
MESH_MERGE_VERTS_DUMP_IF_MAPPED,
MESH_MERGE_VERTS_DUMP_IF_EQUAL,
};
+/**
+ * Merge Verts
+ *
+ * This frees the given mesh and returns a new mesh.
+ *
+ * \param vtargetmap: The table that maps vertices to target vertices. a value of -1
+ * indicates a vertex is a target, and is to be kept.
+ * This array is aligned with 'mesh->totvert'
+ * \warning \a vtargetmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.),
+ * this is not supported and will likely generate corrupted geometry.
+ *
+ * \param tot_vtargetmap: The number of non '-1' values in vtargetmap. (not the size)
+ *
+ * \param merge_mode: enum with two modes.
+ * - #MESH_MERGE_VERTS_DUMP_IF_MAPPED
+ * When called by the Mirror Modifier,
+ * In this mode it skips any faces that have all vertices merged (to avoid creating pairs
+ * of faces sharing the same set of vertices)
+ * - #MESH_MERGE_VERTS_DUMP_IF_EQUAL
+ * When called by the Array Modifier,
+ * In this mode, faces where all vertices are merged are double-checked,
+ * to see whether all target vertices actually make up a poly already.
+ * Indeed it could be that all of a poly's vertices are merged,
+ * but merged to vertices that do not make up a single poly,
+ * in which case the original poly should not be dumped.
+ * Actually this later behavior could apply to the Mirror Modifier as well,
+ * but the additional checks are costly and not necessary in the case of mirror,
+ * because each vertex is only merged to its own mirror.
+ *
+ * \note #BKE_mesh_tessface_calc_ex has to run on the returned DM
+ * if you want to access tess-faces.
+ */
struct Mesh *BKE_mesh_merge_verts(struct Mesh *mesh,
const int *vtargetmap,
- const int tot_vtargetmap,
- const int merge_mode);
+ int tot_vtargetmap,
+ int merge_mode);
-/* flush flags */
+/* Flush flags. */
+
+/**
+ * Update the hide flag for edges and faces from the corresponding flag in verts.
+ */
void BKE_mesh_flush_hidden_from_verts_ex(const struct MVert *mvert,
const struct MLoop *mloop,
struct MEdge *medge,
- const int totedge,
+ int totedge,
struct MPoly *mpoly,
- const int totpoly);
+ int totpoly);
void BKE_mesh_flush_hidden_from_verts(struct Mesh *me);
void BKE_mesh_flush_hidden_from_polys_ex(struct MVert *mvert,
const struct MLoop *mloop,
struct MEdge *medge,
- const int totedge,
+ int totedge,
const struct MPoly *mpoly,
- const int totpoly);
+ int totpoly);
void BKE_mesh_flush_hidden_from_polys(struct Mesh *me);
+/**
+ * simple poly -> vert/edge selection.
+ */
void BKE_mesh_flush_select_from_polys_ex(struct MVert *mvert,
- const int totvert,
+ int totvert,
const struct MLoop *mloop,
struct MEdge *medge,
- const int totedge,
+ int totedge,
const struct MPoly *mpoly,
- const int totpoly);
+ int totpoly);
void BKE_mesh_flush_select_from_polys(struct Mesh *me);
void BKE_mesh_flush_select_from_verts_ex(const struct MVert *mvert,
- const int totvert,
+ int totvert,
const struct MLoop *mloop,
struct MEdge *medge,
- const int totedge,
+ int totedge,
struct MPoly *mpoly,
- const int totpoly);
+ int totpoly);
void BKE_mesh_flush_select_from_verts(struct Mesh *me);
/* spatial evaluation */
+/**
+ * This function takes the difference between 2 vertex-coord-arrays
+ * (\a vert_cos_src, \a vert_cos_dst),
+ * and applies the difference to \a vert_cos_new relative to \a vert_cos_org.
+ *
+ * \param vert_cos_src: reference deform source.
+ * \param vert_cos_dst: reference deform destination.
+ *
+ * \param vert_cos_org: reference for the output location.
+ * \param vert_cos_new: resulting coords.
+ */
void BKE_mesh_calc_relative_deform(const struct MPoly *mpoly,
- const int totpoly,
+ int totpoly,
const struct MLoop *mloop,
- const int totvert,
+ int totvert,
const float (*vert_cos_src)[3],
const float (*vert_cos_dst)[3],
@@ -592,10 +935,38 @@ void BKE_mesh_calc_relative_deform(const struct MPoly *mpoly,
/* *** mesh_validate.c *** */
-bool BKE_mesh_validate(struct Mesh *me, const bool do_verbose, const bool cddata_check_mask);
+/**
+ * Validates and corrects a Mesh.
+ *
+ * \returns true if a change is made.
+ */
+bool BKE_mesh_validate(struct Mesh *me, bool do_verbose, bool cddata_check_mask);
+/**
+ * Checks if a Mesh is valid without any modification. This is always verbose.
+ * \returns True if the mesh is valid.
+ */
bool BKE_mesh_is_valid(struct Mesh *me);
+/**
+ * Check all material indices of polygons are valid, invalid ones are set to 0.
+ * \returns True if the material indices are valid.
+ */
bool BKE_mesh_validate_material_indices(struct Mesh *me);
+/**
+ * Validate the mesh, \a do_fixes requires \a mesh to be non-null.
+ *
+ * \return false if no changes needed to be made.
+ *
+ * Vertex Normals
+ * ==============
+ *
+ * While zeroed normals are checked, these checks aren't comprehensive.
+ * Technically, to detect errors here a normal recalculation and comparison is necessary.
+ * However this function is mainly to prevent severe errors in geometry
+ * (invalid data that will crash Blender, or cause some features to behave incorrectly),
+ * not to detect subtle differences in the resulting normals which could be caused
+ * by importers that load normals (for example).
+ */
bool BKE_mesh_validate_arrays(struct Mesh *me,
struct MVert *mverts,
unsigned int totvert,
@@ -608,35 +979,57 @@ bool BKE_mesh_validate_arrays(struct Mesh *me,
struct MPoly *mpolys,
unsigned int totpoly,
struct MDeformVert *dverts, /* assume totvert length */
- const bool do_verbose,
- const bool do_fixes,
+ bool do_verbose,
+ bool do_fixes,
bool *r_change);
+/**
+ * \returns is_valid.
+ */
bool BKE_mesh_validate_all_customdata(struct CustomData *vdata,
- const uint totvert,
+ uint totvert,
struct CustomData *edata,
- const uint totedge,
+ uint totedge,
struct CustomData *ldata,
- const uint totloop,
+ uint totloop,
struct CustomData *pdata,
- const uint totpoly,
- const bool check_meshmask,
- const bool do_verbose,
- const bool do_fixes,
+ uint totpoly,
+ bool check_meshmask,
+ bool do_verbose,
+ bool do_fixes,
bool *r_change);
void BKE_mesh_strip_loose_faces(struct Mesh *me);
+/**
+ * Works on both loops and polys!
+ *
+ * \note It won't try to guess which loops of an invalid poly to remove!
+ * this is the work of the caller, to mark those loops.
+ * See e.g. #BKE_mesh_validate_arrays().
+ */
void BKE_mesh_strip_loose_polysloops(struct Mesh *me);
void BKE_mesh_strip_loose_edges(struct Mesh *me);
-void BKE_mesh_calc_edges_legacy(struct Mesh *me, const bool use_old);
+/**
+ * If the mesh is from a very old blender version,
+ * convert mface->edcode to edge drawflags
+ */
+void BKE_mesh_calc_edges_legacy(struct Mesh *me, bool use_old);
void BKE_mesh_calc_edges_loose(struct Mesh *mesh);
-void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, const bool select_new_edges);
+/**
+ * Calculate edges from polygons.
+ */
+void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, bool select_new_edges);
+/**
+ * Calculate/create edges from tessface data
+ *
+ * \param mesh: The mesh to add edges into
+ */
void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
/* In DerivedMesh.cc */
void BKE_mesh_wrapper_deferred_finalize(struct Mesh *me_eval,
- const CustomData_MeshMasks *cd_mask_finalize);
+ const struct CustomData_MeshMasks *cd_mask_finalize);
/* **** Depsgraph evaluation **** */
@@ -649,11 +1042,17 @@ void BKE_mesh_batch_cache_free(struct Mesh *me);
extern void (*BKE_mesh_batch_cache_dirty_tag_cb)(struct Mesh *me, eMeshBatchDirtyMode mode);
extern void (*BKE_mesh_batch_cache_free_cb)(struct Mesh *me);
+/* mesh_debug.c */
+#ifndef NDEBUG
+char *BKE_mesh_debug_info(const struct Mesh *me)
+ ATTR_NONNULL(1) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+void BKE_mesh_debug_print(const struct Mesh *me) ATTR_NONNULL(1);
+#endif
+
/* Inlines */
-/* Instead of -1 that function uses ORIGINDEX_NONE as defined in BKE_customdata.h,
- * but I don't want to force every user of BKE_mesh.h to also include that file.
- * ~~ Sybren */
+/* NOTE(@sybren): Instead of -1 that function uses ORIGINDEX_NONE as defined in BKE_customdata.h,
+ * but I don't want to force every user of BKE_mesh.h to also include that file. */
BLI_INLINE int BKE_mesh_origindex_mface_mpoly(const int *index_mf_to_mpoly,
const int *index_mp_to_orig,
const int i)
diff --git a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
index 59f6e75183e..5a743999803 100644
--- a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
+++ b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
@@ -32,12 +32,22 @@ struct Mesh;
namespace blender::meshintersect {
+/**
+ * Do a mesh boolean operation directly on meshes (without going back and forth to BMesh).
+ * \param meshes: An array of Mesh pointers.
+ * \param obmats: An array of pointers to the obmat matrices that transform local
+ * coordinates to global ones. It is allowed for the pointers to be null, meaning the
+ * transformation is the identity.
+ * \param material_remaps: An array of pointers to arrays of maps from material slot numbers in the
+ * corresponding mesh to the material slot in the first mesh. It is OK for material_remaps or any
+ * of its constituent arrays to be empty.
+ */
Mesh *direct_mesh_boolean(blender::Span<const Mesh *> meshes,
blender::Span<const float4x4 *> obmats,
const float4x4 &target_transform,
blender::Span<blender::Array<short>> material_remaps,
- const bool use_self,
- const bool hole_tolerant,
- const int boolean_mode);
+ bool use_self,
+ bool hole_tolerant,
+ int boolean_mode);
} // namespace blender::meshintersect
diff --git a/source/blender/blenkernel/BKE_mesh_fair.h b/source/blender/blenkernel/BKE_mesh_fair.h
index 2d5c85d4129..c4c1af054f0 100644
--- a/source/blender/blenkernel/BKE_mesh_fair.h
+++ b/source/blender/blenkernel/BKE_mesh_fair.h
@@ -42,14 +42,14 @@ typedef enum eMeshFairingDepth {
* the vertex should be modified by fairing. */
void BKE_bmesh_prefair_and_fair_vertices(struct BMesh *bm,
bool *affect_vertices,
- const eMeshFairingDepth depth);
+ eMeshFairingDepth depth);
/* This function can optionally use the MVert coordinates of deform_mverts to read and write the
* fairing result. When NULL, the function will use mesh->mverts directly. */
void BKE_mesh_prefair_and_fair_vertices(struct Mesh *mesh,
struct MVert *deform_mverts,
bool *affect_vertices,
- const eMeshFairingDepth depth);
+ eMeshFairingDepth depth);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mesh_iterators.h b/source/blender/blenkernel/BKE_mesh_iterators.h
index a65f25ee182..b28465fc41e 100644
--- a/source/blender/blenkernel/BKE_mesh_iterators.h
+++ b/source/blender/blenkernel/BKE_mesh_iterators.h
@@ -31,14 +31,16 @@ typedef enum MeshForeachFlag {
MESH_FOREACH_USE_NORMAL = (1 << 0),
} MeshForeachFlag;
-void BKE_mesh_foreach_mapped_vert(struct Mesh *mesh,
- void (*func)(void *userData,
- int index,
- const float co[3],
- const float no_f[3],
- const short no_s[3]),
- void *userData,
- MeshForeachFlag flag);
+void BKE_mesh_foreach_mapped_vert(
+ struct Mesh *mesh,
+ void (*func)(void *userData, int index, const float co[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag);
+/**
+ * Copied from #cdDM_foreachMappedEdge.
+ * \param tot_edges: Number of original edges. Used to avoid calling the callback with invalid
+ * edge indices.
+ */
void BKE_mesh_foreach_mapped_edge(
struct Mesh *mesh,
int tot_edges,
@@ -63,9 +65,7 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
void *userData,
MeshForeachFlag flag);
-void BKE_mesh_foreach_mapped_vert_coords_get(struct Mesh *me_eval,
- float (*r_cos)[3],
- const int totcos);
+void BKE_mesh_foreach_mapped_vert_coords_get(struct Mesh *me_eval, float (*r_cos)[3], int totcos);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index 0518f303744..48669278e23 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -100,11 +100,16 @@ UvVertMap *BKE_mesh_uv_vert_map_create(const struct MPoly *mpoly,
unsigned int totpoly,
unsigned int totvert,
const float limit[2],
- const bool selected,
- const bool use_winding);
+ bool selected,
+ bool use_winding);
UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v);
void BKE_mesh_uv_vert_map_free(UvVertMap *vmap);
+/**
+ * Generates a map where the key is the vertex and the value
+ * is a list of polys that use that vertex as a corner.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MPoly *mpoly,
@@ -112,6 +117,11 @@ void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
int totvert,
int totpoly,
int totloop);
+/**
+ * Generates a map where the key is the vertex and the value
+ * is a list of loops that use that vertex as a corner.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MPoly *mpoly,
@@ -119,45 +129,84 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
int totvert,
int totpoly,
int totloop);
+/**
+ * Generates a map where the key is the edge and the value
+ * is a list of looptris that use that edge.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MVert *mvert,
- const int totvert,
+ int totvert,
const struct MLoopTri *mlooptri,
- const int totlooptri,
+ int totlooptri,
const struct MLoop *mloop,
- const int totloop);
+ int totloop);
+/**
+ * Generates a map where the key is the vertex and the value
+ * is a list of edges that use that vertex as an endpoint.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_edge_map_create(
MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge);
+/**
+ * A version of #BKE_mesh_vert_edge_map_create that references connected vertices directly
+ * (not their edges).
+ */
void BKE_mesh_vert_edge_vert_map_create(
MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge);
+/**
+ * Generates a map where the key is the edge and the value is a list of loops that use that edge.
+ * Loops indices of a same poly are contiguous and in winding order.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MEdge *medge,
- const int totedge,
+ int totedge,
const struct MPoly *mpoly,
- const int totpoly,
+ int totpoly,
const struct MLoop *mloop,
- const int totloop);
+ int totloop);
+/**
+ * Generates a map where the key is the edge and the value
+ * is a list of polygons that use that edge.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MEdge *medge,
- const int totedge,
+ int totedge,
const struct MPoly *mpoly,
- const int totpoly,
+ int totpoly,
const struct MLoop *mloop,
- const int totloop);
-void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
- int **r_mem,
- const int totsource,
- const int *final_origindex,
- const int totfinal);
+ int totloop);
+/**
+ * This function creates a map so the source-data (vert/edge/loop/poly)
+ * can loop over the destination data (using the destination arrays origindex).
+ *
+ * This has the advantage that it can operate on any data-types.
+ *
+ * \param totsource: The total number of elements that \a final_origindex points to.
+ * \param totfinal: The size of \a final_origindex
+ * \param final_origindex: The size of the final array.
+ *
+ * \note `totsource` could be `totpoly`,
+ * `totfinal` could be `tottessface` and `final_origindex` its ORIGINDEX custom-data.
+ * This would allow an MPoly to loop over its tessfaces.
+ */
+void BKE_mesh_origindex_map_create(
+ MeshElemMap **r_map, int **r_mem, int totsource, const int *final_origindex, int totfinal);
+/**
+ * A version of #BKE_mesh_origindex_map_create that takes a looptri array.
+ * Making a poly -> looptri map.
+ */
void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
int **r_mem,
const struct MPoly *mpoly,
- const int mpoly_num,
+ int mpoly_num,
const struct MLoopTri *looptri,
- const int looptri_num);
+ int looptri_num);
/* islands */
@@ -187,62 +236,87 @@ typedef struct MeshIslandStore {
} MeshIslandStore;
void BKE_mesh_loop_islands_init(MeshIslandStore *island_store,
- const short item_type,
- const int items_num,
- const short island_type,
- const short innercut_type);
+ short item_type,
+ int items_num,
+ short island_type,
+ short innercut_type);
void BKE_mesh_loop_islands_clear(MeshIslandStore *island_store);
void BKE_mesh_loop_islands_free(MeshIslandStore *island_store);
void BKE_mesh_loop_islands_add(MeshIslandStore *island_store,
- const int item_num,
+ int item_num,
const int *items_indices,
- const int num_island_items,
+ int num_island_items,
int *island_item_indices,
- const int num_innercut_items,
+ int num_innercut_items,
int *innercut_item_indices);
typedef bool (*MeshRemapIslandsCalc)(struct MVert *verts,
- const int totvert,
+ int totvert,
struct MEdge *edges,
- const int totedge,
+ int totedge,
struct MPoly *polys,
- const int totpoly,
+ int totpoly,
struct MLoop *loops,
- const int totloop,
+ int totloop,
struct MeshIslandStore *r_island_store);
/* Above vert/UV mapping stuff does not do what we need here, but does things we do not need here.
- * So better keep them separated for now, I think.
+ * So better keep them separated for now, I think. */
+
+/**
+ * Calculate 'generic' UV islands, i.e. based only on actual geometry data (edge seams),
+ * not some UV layers coordinates.
*/
bool BKE_mesh_calc_islands_loop_poly_edgeseam(struct MVert *verts,
- const int totvert,
+ int totvert,
struct MEdge *edges,
- const int totedge,
+ int totedge,
struct MPoly *polys,
- const int totpoly,
+ int totpoly,
struct MLoop *loops,
- const int totloop,
+ int totloop,
MeshIslandStore *r_island_store);
+/**
+ * Calculate UV islands.
+ *
+ * \note If no MLoopUV layer is passed, we only consider edges tagged as seams as UV boundaries.
+ * This has the advantages of simplicity, and being valid/common to all UV maps.
+ * However, it means actual UV islands without matching UV seams will not be handled correctly.
+ * If a valid UV layer is passed as \a luvs parameter,
+ * UV coordinates are also used to detect islands boundaries.
+ *
+ * \note All this could be optimized.
+ * Not sure it would be worth the more complex code, though,
+ * those loops are supposed to be really quick to do.
+ */
bool BKE_mesh_calc_islands_loop_poly_uvmap(struct MVert *verts,
- const int totvert,
+ int totvert,
struct MEdge *edges,
- const int totedge,
+ int totedge,
struct MPoly *polys,
- const int totpoly,
+ int totpoly,
struct MLoop *loops,
- const int totloop,
+ int totloop,
const struct MLoopUV *luvs,
MeshIslandStore *r_island_store);
+/**
+ * Calculate smooth groups from sharp edges.
+ *
+ * \param r_totgroup: The total number of groups, 1 or more.
+ * \return Polygon aligned array of group index values (bitflags if use_bitflags is true),
+ * starting at 1 (0 being used as 'invalid' flag).
+ * Note it's callers's responsibility to MEM_freeN returned array.
+ */
int *BKE_mesh_calc_smoothgroups(const struct MEdge *medge,
- const int totedge,
+ int totedge,
const struct MPoly *mpoly,
- const int totpoly,
+ int totpoly,
const struct MLoop *mloop,
- const int totloop,
+ int totloop,
int *r_totgroup,
- const bool use_bitflags);
+ bool use_bitflags);
/* use on looptri vertex values */
#define BKE_MESH_TESSTRI_VINDEX_ORDER(_tri, _v) \
diff --git a/source/blender/blenkernel/BKE_mesh_mirror.h b/source/blender/blenkernel/BKE_mesh_mirror.h
index 7b230b04410..c77974d6cc1 100644
--- a/source/blender/blenkernel/BKE_mesh_mirror.h
+++ b/source/blender/blenkernel/BKE_mesh_mirror.h
@@ -40,13 +40,18 @@ struct Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(struct MirrorMo
void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
struct Mesh *mesh,
- const int axis,
- const float dist);
+ int axis,
+ float dist);
+/**
+ * \warning This should _not_ be used to modify original meshes since
+ * it doesn't handle shape-keys, use #BKE_mesh_mirror_apply_mirror_on_axis instead.
+ */
struct Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(struct MirrorModifierData *mmd,
struct Object *ob,
const struct Mesh *mesh,
- const int axis);
+ int axis,
+ bool use_correct_order_on_merge);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h
index 7f8f028c26b..ab07cb0df4e 100644
--- a/source/blender/blenkernel/BKE_mesh_remap.h
+++ b/source/blender/blenkernel/BKE_mesh_remap.h
@@ -50,10 +50,10 @@ typedef struct MeshPairRemap {
} MeshPairRemap;
/* Helpers! */
-void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num);
+void BKE_mesh_remap_init(MeshPairRemap *map, int items_num);
void BKE_mesh_remap_free(MeshPairRemap *map);
-void BKE_mesh_remap_item_define_invalid(MeshPairRemap *map, const int index);
+void BKE_mesh_remap_item_define_invalid(MeshPairRemap *map, int index);
/* TODO:
* Add other 'from/to' mapping sources, like e.g. using an UVMap, etc.
@@ -155,78 +155,88 @@ enum {
};
void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
- const int vert_mode,
- const int edge_mode,
- const int loop_mode,
- const int poly_mode,
+ int vert_mode,
+ int edge_mode,
+ int loop_mode,
+ int poly_mode,
struct CustomData_MeshMasks *cddata_mask);
+/**
+ * Compute a value of the difference between both given meshes.
+ * The smaller the result, the better the match.
+ *
+ * We return the inverse of the average of the inversed
+ * shortest distance from each dst vertex to src ones.
+ * In other words, beyond a certain (relatively small) distance, all differences have more or less
+ * the same weight in final result, which allows to reduce influence of a few high differences,
+ * in favor of a global good matching.
+ */
float BKE_mesh_remap_calc_difference_from_mesh(const struct SpaceTransform *space_transform,
const struct MVert *verts_dst,
- const int numverts_dst,
+ int numverts_dst,
struct Mesh *me_src);
+/**
+ * Set r_space_transform so that best bbox of dst matches best bbox of src.
+ */
void BKE_mesh_remap_find_best_match_from_mesh(const struct MVert *verts_dst,
- const int numverts_dst,
+ int numverts_dst,
struct Mesh *me_src,
struct SpaceTransform *r_space_transform);
-void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
+void BKE_mesh_remap_calc_verts_from_mesh(int mode,
const struct SpaceTransform *space_transform,
- const float max_dist,
- const float ray_radius,
+ float max_dist,
+ float ray_radius,
const struct MVert *verts_dst,
- const int numverts_dst,
- const bool dirty_nors_dst,
+ int numverts_dst,
+ bool dirty_nors_dst,
struct Mesh *me_src,
MeshPairRemap *r_map);
-void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
+void BKE_mesh_remap_calc_edges_from_mesh(int mode,
const struct SpaceTransform *space_transform,
- const float max_dist,
- const float ray_radius,
+ float max_dist,
+ float ray_radius,
const struct MVert *verts_dst,
- const int numverts_dst,
+ int numverts_dst,
const struct MEdge *edges_dst,
- const int numedges_dst,
- const bool dirty_nors_dst,
+ int numedges_dst,
+ bool dirty_nors_dst,
struct Mesh *me_src,
MeshPairRemap *r_map);
-void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
+void BKE_mesh_remap_calc_loops_from_mesh(int mode,
const struct SpaceTransform *space_transform,
- const float max_dist,
- const float ray_radius,
+ float max_dist,
+ float ray_radius,
+ struct Mesh *mesh_dst,
struct MVert *verts_dst,
- const int numverts_dst,
+ int numverts_dst,
struct MEdge *edges_dst,
- const int numedges_dst,
+ int numedges_dst,
struct MLoop *loops_dst,
- const int numloops_dst,
+ int numloops_dst,
struct MPoly *polys_dst,
- const int numpolys_dst,
+ int numpolys_dst,
struct CustomData *ldata_dst,
- struct CustomData *pdata_dst,
- const bool use_split_nors_dst,
- const float split_angle_dst,
- const bool dirty_nors_dst,
+ bool use_split_nors_dst,
+ float split_angle_dst,
+ bool dirty_nors_dst,
struct Mesh *me_src,
MeshRemapIslandsCalc gen_islands_src,
- const float islands_precision_src,
+ float islands_precision_src,
struct MeshPairRemap *r_map);
-void BKE_mesh_remap_calc_polys_from_mesh(const int mode,
+void BKE_mesh_remap_calc_polys_from_mesh(int mode,
const struct SpaceTransform *space_transform,
- const float max_dist,
- const float ray_radius,
+ float max_dist,
+ float ray_radius,
+ struct Mesh *mesh_dst,
struct MVert *verts_dst,
- const int numverts_dst,
struct MLoop *loops_dst,
- const int numloops_dst,
struct MPoly *polys_dst,
- const int numpolys_dst,
- struct CustomData *pdata_dst,
- const bool dirty_nors_dst,
+ int numpolys_dst,
struct Mesh *me_src,
struct MeshPairRemap *r_map);
diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h
index 3efbef94081..ad86f6d8f25 100644
--- a/source/blender/blenkernel/BKE_mesh_runtime.h
+++ b/source/blender/blenkernel/BKE_mesh_runtime.h
@@ -41,17 +41,42 @@ struct Mesh;
struct Object;
struct Scene;
-void BKE_mesh_runtime_reset(struct Mesh *mesh);
-void BKE_mesh_runtime_reset_on_copy(struct Mesh *mesh, const int flag);
+/**
+ * \brief Initialize the runtime of the given mesh.
+ *
+ * Function expects that the runtime is already cleared.
+ */
+void BKE_mesh_runtime_init_data(struct Mesh *mesh);
+/**
+ * \brief Free all data (and mutexes) inside the runtime of the given mesh.
+ */
+void BKE_mesh_runtime_free_data(struct Mesh *mesh);
+/**
+ * Clear all pointers which we don't want to be shared on copying the datablock.
+ * However, keep all the flags which defines what the mesh is (for example, that
+ * it's deformed only, or that its custom data layers are out of date.)
+ */
+void BKE_mesh_runtime_reset_on_copy(struct Mesh *mesh, int flag);
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh);
void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh);
+/**
+ * \note This function only fills a cache, and therefore the mesh argument can
+ * be considered logically const. Concurrent access is protected by a mutex.
+ * \note This is a ported copy of dm_getLoopTriArray(dm).
+ */
const struct MLoopTri *BKE_mesh_runtime_looptri_ensure(const struct Mesh *mesh);
bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh);
bool BKE_mesh_runtime_clear_edit_data(struct Mesh *mesh);
bool BKE_mesh_runtime_reset_edit_data(struct Mesh *mesh);
void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh);
+/**
+ * \brief This function clears runtime cache of the given mesh.
+ *
+ * Call this function to recalculate runtime data when used.
+ */
void BKE_mesh_runtime_clear_cache(struct Mesh *mesh);
+/* This is a copy of DM_verttri_from_looptri(). */
void BKE_mesh_runtime_verttri_from_looptri(struct MVertTri *r_verttri,
const struct MLoop *mloop,
const struct MLoopTri *looptri,
@@ -61,6 +86,7 @@ void BKE_mesh_runtime_verttri_from_looptri(struct MVertTri *r_verttri,
* to a more suitable location when that file is removed.
* They should also be renamed to use conventions from BKE, not old DerivedMesh.cc.
* For now keep the names similar to avoid confusion. */
+
struct Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -76,12 +102,6 @@ struct Mesh *mesh_create_eval_final(struct Depsgraph *depsgraph,
struct Object *ob,
const struct CustomData_MeshMasks *dataMask);
-struct Mesh *mesh_create_eval_final_index_render(struct Depsgraph *depsgraph,
- struct Scene *scene,
- struct Object *ob,
- const struct CustomData_MeshMasks *dataMask,
- int index);
-
struct Mesh *mesh_create_eval_no_deform(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -96,9 +116,6 @@ void BKE_mesh_runtime_eval_to_meshkey(struct Mesh *me_deformed,
struct KeyBlock *kb);
#ifndef NDEBUG
-char *BKE_mesh_runtime_debug_info(struct Mesh *me_eval);
-void BKE_mesh_runtime_debug_print(struct Mesh *me_eval);
-void BKE_mesh_runtime_debug_print_cdlayers(struct CustomData *data);
bool BKE_mesh_runtime_is_valid(struct Mesh *me_eval);
#endif /* NDEBUG */
diff --git a/source/blender/blenkernel/BKE_mesh_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh
index 2fbf7372a09..738b768d906 100644
--- a/source/blender/blenkernel/BKE_mesh_sample.hh
+++ b/source/blender/blenkernel/BKE_mesh_sample.hh
@@ -22,7 +22,7 @@
#include "FN_generic_virtual_array.hh"
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
#include "BKE_attribute.h"
@@ -44,17 +44,20 @@ void sample_point_attribute(const Mesh &mesh,
Span<int> looptri_indices,
Span<float3> bary_coords,
const GVArray &data_in,
+ const IndexMask mask,
GMutableSpan data_out);
void sample_corner_attribute(const Mesh &mesh,
Span<int> looptri_indices,
Span<float3> bary_coords,
const GVArray &data_in,
+ const IndexMask mask,
GMutableSpan data_out);
void sample_face_attribute(const Mesh &mesh,
Span<int> looptri_indices,
const GVArray &data_in,
+ const IndexMask mask,
GMutableSpan data_out);
enum class eAttributeMapMode {
@@ -72,6 +75,7 @@ enum class eAttributeMapMode {
class MeshAttributeInterpolator {
private:
const Mesh *mesh_;
+ const IndexMask mask_;
const Span<float3> positions_;
const Span<int> looptri_indices_;
@@ -80,9 +84,15 @@ class MeshAttributeInterpolator {
public:
MeshAttributeInterpolator(const Mesh *mesh,
+ const IndexMask mask,
const Span<float3> positions,
const Span<int> looptri_indices);
+ void sample_data(const GVArray &src,
+ AttributeDomain domain,
+ eAttributeMapMode mode,
+ const GMutableSpan dst);
+
void sample_attribute(const ReadAttributeLookup &src_attribute,
OutputAttribute &dst_attribute,
eAttributeMapMode mode);
diff --git a/source/blender/blenkernel/BKE_mesh_tangent.h b/source/blender/blenkernel/BKE_mesh_tangent.h
index 96eaa23ce71..320c4e7f36a 100644
--- a/source/blender/blenkernel/BKE_mesh_tangent.h
+++ b/source/blender/blenkernel/BKE_mesh_tangent.h
@@ -25,38 +25,54 @@ extern "C" {
struct ReportList;
+/**
+ * Compute simplified tangent space normals, i.e.
+ * tangent vector + sign of bi-tangent one, which combined with
+ * split normals can be used to recreate the full tangent space.
+ * NOTE: * The mesh should be made of only tris and quads!
+ */
void BKE_mesh_calc_loop_tangent_single_ex(const struct MVert *mverts,
- const int numVerts,
+ int numVerts,
const struct MLoop *mloops,
float (*r_looptangent)[4],
float (*loopnors)[3],
const struct MLoopUV *loopuv,
- const int numLoops,
+ int numLoops,
const struct MPoly *mpolys,
- const int numPolys,
+ int numPolys,
struct ReportList *reports);
+/**
+ * Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code.
+ * \note
+ * - There must be a valid loop's CD_NORMALS available.
+ * - The mesh should be made of only tris and quads!
+ */
void BKE_mesh_calc_loop_tangent_single(struct Mesh *mesh,
const char *uvmap,
float (*r_looptangents)[4],
struct ReportList *reports);
+/**
+ * See: #BKE_editmesh_loop_tangent_calc (matching logic).
+ */
void BKE_mesh_calc_loop_tangent_ex(const struct MVert *mvert,
const struct MPoly *mpoly,
- const uint mpoly_len,
+ uint mpoly_len,
const struct MLoop *mloop,
const struct MLoopTri *looptri,
- const uint looptri_len,
+ uint looptri_len,
struct CustomData *loopdata,
bool calc_active_tangent,
const char (*tangent_names)[64],
int tangent_names_len,
+ const float (*vert_normals)[3],
const float (*poly_normals)[3],
const float (*loop_normals)[3],
const float (*vert_orco)[3],
/* result */
struct CustomData *loopdata_out,
- const uint loopdata_out_len,
+ uint loopdata_out_len,
short *tangent_mask_curr_p);
void BKE_mesh_calc_loop_tangents(struct Mesh *me_eval,
@@ -71,6 +87,12 @@ void BKE_mesh_add_loop_tangent_named_layer_for_uv(struct CustomData *uv_data,
const char *layer_name);
#define DM_TANGENT_MASK_ORCO (1 << 9)
+/**
+ * Here we get some useful information such as active uv layer name and
+ * search if it is already in tangent_names.
+ * Also, we calculate tangent_mask that works as a descriptor of tangents state.
+ * If tangent_mask has changed, then recalculate tangents.
+ */
void BKE_mesh_calc_loop_tangent_step_0(const struct CustomData *loopData,
bool calc_active_tangent,
const char (*tangent_names)[64],
diff --git a/source/blender/blenkernel/BKE_mesh_wrapper.h b/source/blender/blenkernel/BKE_mesh_wrapper.h
index 2fe264fd0f7..12e8fd71503 100644
--- a/source/blender/blenkernel/BKE_mesh_wrapper.h
+++ b/source/blender/blenkernel/BKE_mesh_wrapper.h
@@ -22,6 +22,7 @@
struct BMEditMesh;
struct CustomData_MeshMasks;
struct Mesh;
+struct Object;
#ifdef __cplusplus
extern "C" {
@@ -51,6 +52,8 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const struct Mesh *me,
int vert_coords_len,
const float mat[4][4]);
+struct Mesh *BKE_mesh_wrapper_ensure_subdivision(const struct Object *ob, struct Mesh *me);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 8be563e4c96..80889813b34 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -98,7 +98,7 @@ typedef enum {
eModifierTypeFlag_RequiresOriginalData = (1 << 5),
/**
- * For modifiers that support pointcache,
+ * For modifiers that support point-cache,
* so we can check to see if it has files we need to deal with.
*/
eModifierTypeFlag_UsesPointCache = (1 << 6),
@@ -184,7 +184,7 @@ typedef struct ModifierTypeInfo {
*
* \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more).
*/
- void (*copyData)(const struct ModifierData *md, struct ModifierData *target, const int flag);
+ void (*copyData)(const struct ModifierData *md, struct ModifierData *target, int flag);
/********************* Deform modifier functions *********************/
@@ -322,7 +322,7 @@ typedef struct ModifierTypeInfo {
*
* The dag_eval_mode should be of type eEvaluationMode.
*/
- bool (*dependsOnTime)(struct Scene *scene, struct ModifierData *md, const int dag_eval_mode);
+ bool (*dependsOnTime)(struct Scene *scene, struct ModifierData *md, int dag_eval_mode);
/**
* True when a deform modifier uses normals, the requiredDataMask
@@ -403,6 +403,10 @@ void BKE_modifier_init(void);
const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type);
/* For modifier UI panels. */
+
+/**
+ * Get the idname of the modifier type's panel, which was defined in the #panelRegister callback.
+ */
void BKE_modifier_type_panel_id(ModifierType type, char *r_idname);
void BKE_modifier_panel_expand(struct ModifierData *md);
@@ -411,8 +415,11 @@ void BKE_modifier_panel_expand(struct ModifierData *md);
*/
struct ModifierData *BKE_modifier_new(int type);
-void BKE_modifier_free_ex(struct ModifierData *md, const int flag);
+void BKE_modifier_free_ex(struct ModifierData *md, int flag);
void BKE_modifier_free(struct ModifierData *md);
+/**
+ * Use instead of `BLI_remlink` when the object's active modifier should change.
+ */
void BKE_modifier_remove_from_list(struct Object *ob, struct ModifierData *md);
/* Generate new UUID for the given modifier. */
@@ -420,13 +427,14 @@ void BKE_modifier_session_uuid_generate(struct ModifierData *md);
bool BKE_modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md);
+/**
+ * Callback's can use this to avoid copying every member.
+ */
void BKE_modifier_copydata_generic(const struct ModifierData *md,
struct ModifierData *md_dst,
- const int flag);
+ int flag);
void BKE_modifier_copydata(struct ModifierData *md, struct ModifierData *target);
-void BKE_modifier_copydata_ex(struct ModifierData *md,
- struct ModifierData *target,
- const int flag);
+void BKE_modifier_copydata_ex(struct ModifierData *md, struct ModifierData *target, int flag);
bool BKE_modifier_depends_ontime(struct Scene *scene, struct ModifierData *md, int dag_eval_mode);
bool BKE_modifier_supports_mapping(struct ModifierData *md);
bool BKE_modifier_supports_cage(struct Scene *scene, struct ModifierData *md);
@@ -434,9 +442,21 @@ bool BKE_modifier_couldbe_cage(struct Scene *scene, struct ModifierData *md);
bool BKE_modifier_is_correctable_deformed(struct ModifierData *md);
bool BKE_modifier_is_same_topology(ModifierData *md);
bool BKE_modifier_is_non_geometrical(ModifierData *md);
+/**
+ * Check whether is enabled.
+ *
+ * \param scene: Current scene, may be NULL,
+ * in which case `isDisabled` callback of the modifier is never called.
+ */
bool BKE_modifier_is_enabled(const struct Scene *scene,
struct ModifierData *md,
int required_mode);
+/**
+ * Check whether given modifier is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param md: May be NULL, in which case we consider it as a non-local modifier case.
+ */
bool BKE_modifier_is_nonlocal_in_liboverride(const struct Object *ob,
const struct ModifierData *md);
void BKE_modifier_set_error(const struct Object *ob,
@@ -451,6 +471,12 @@ void BKE_modifiers_foreach_tex_link(struct Object *ob, TexWalkFunc walk, void *u
struct ModifierData *BKE_modifiers_findby_type(const struct Object *ob, ModifierType type);
struct ModifierData *BKE_modifiers_findby_name(const struct Object *ob, const char *name);
void BKE_modifiers_clear_errors(struct Object *ob);
+/**
+ * used for buttons, to find out if the 'draw deformed in edit-mode option is there.
+ *
+ * Also used in transform_conversion.c, to detect crazy-space (2nd arg then is NULL).
+ * Also used for some mesh tools to give warnings.
+ */
int BKE_modifiers_get_cage_index(const struct Scene *scene,
struct Object *ob,
int *r_lastPossibleCageIndex,
@@ -461,9 +487,21 @@ bool BKE_modifiers_is_softbody_enabled(struct Object *ob);
bool BKE_modifiers_is_cloth_enabled(struct Object *ob);
bool BKE_modifiers_is_particle_enabled(struct Object *ob);
+/**
+ * Takes an object and returns its first selected armature, else just its armature.
+ * This should work for multiple armatures per object.
+ */
struct Object *BKE_modifiers_is_deformed_by_armature(struct Object *ob);
struct Object *BKE_modifiers_is_deformed_by_meshdeform(struct Object *ob);
+/**
+ * Takes an object and returns its first selected lattice, else just its lattice.
+ * This should work for multiple lattices per object.
+ */
struct Object *BKE_modifiers_is_deformed_by_lattice(struct Object *ob);
+/**
+ * Takes an object and returns its first selected curve, else just its curve.
+ * This should work for multiple curves per object.
+ */
struct Object *BKE_modifiers_is_deformed_by_curve(struct Object *ob);
bool BKE_modifiers_uses_multires(struct Object *ob);
bool BKE_modifiers_uses_armature(struct Object *ob, struct bArmature *arm);
@@ -500,23 +538,36 @@ typedef struct VirtualModifierData {
ShapeKeyModifierData smd;
} VirtualModifierData;
+/**
+ * This is to include things that are not modifiers in the evaluation of the modifier stack,
+ * for example parenting to an armature.
+ */
struct ModifierData *BKE_modifiers_get_virtual_modifierlist(const struct Object *ob,
struct VirtualModifierData *data);
-/** Ensure modifier correctness when changing ob->data. */
+/**
+ * Ensure modifier correctness when changing `ob->data`.
+ */
void BKE_modifiers_test_object(struct Object *ob);
-/* here for do_versions */
+/**
+ * Here for #do_versions.
+ */
void BKE_modifier_mdef_compact_influences(struct ModifierData *md);
+/**
+ * Initializes `path` with either the blend file or temporary directory.
+ */
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name);
const char *BKE_modifier_path_relbase(struct Main *bmain, struct Object *ob);
const char *BKE_modifier_path_relbase_from_global(struct Object *ob);
/* Accessors of original/evaluated modifiers. */
-/* For a given modifier data, get corresponding original one.
- * If the modifier data is already original, return it as-is. */
+/**
+ * For a given modifier data, get corresponding original one.
+ * If the modifier data is already original, return it as-is.
+ */
struct ModifierData *BKE_modifier_get_original(struct ModifierData *md);
struct ModifierData *BKE_modifier_get_evaluated(struct Depsgraph *depsgraph,
struct Object *object,
@@ -541,8 +592,17 @@ void BKE_modifier_deform_vertsEM(ModifierData *md,
float (*vertexCos)[3],
int numVerts);
+/**
+ * Get evaluated mesh for other evaluated object, which is used as an operand for the modifier,
+ * e.g. second operand for boolean modifier.
+ * Note that modifiers in stack always get fully evaluated COW ID pointers,
+ * never original ones. Makes things simpler.
+ *
+ * \param get_cage_mesh: Return evaluated mesh with only deforming modifiers applied
+ * (i.e. mesh topology remains the same as original one, a.k.a. 'cage' mesh).
+ */
struct Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object *ob_eval,
- const bool get_cage_mesh);
+ bool get_cage_mesh);
void BKE_modifier_check_uuids_unique_and_report(const struct Object *object);
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index 067dc694109..9148d5b760f 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -35,6 +35,10 @@ struct MovieClipScopes;
struct MovieClipUser;
struct MovieDistortion;
+/**
+ * Checks if image was already loaded, then returns same image otherwise creates new.
+ * does not load ibuf itself pass on optional frame for #name images.
+ */
struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain,
const char *filepath,
@@ -44,6 +48,11 @@ void BKE_movieclip_reload(struct Main *bmain, struct MovieClip *clip);
void BKE_movieclip_clear_cache(struct MovieClip *clip);
void BKE_movieclip_clear_proxy_cache(struct MovieClip *clip);
+/**
+ * Will try to make image buffer usable when originating from the multi-layer source.
+ * Internally finds a first combined pass and uses that as a buffer.
+ * Not ideal, but is better than a complete empty buffer.
+ */
void BKE_movieclip_convert_multilayer_ibuf(struct ImBuf *ibuf);
struct ImBuf *BKE_movieclip_get_ibuf(struct MovieClip *clip, struct MovieClipUser *user);
@@ -75,11 +84,18 @@ void BKE_movieclip_update_scopes(struct MovieClip *clip,
struct MovieClipUser *user,
struct MovieClipScopes *scopes);
+/**
+ * Get segments of cached frames. useful for debugging cache policies.
+ */
void BKE_movieclip_get_cache_segments(struct MovieClip *clip,
struct MovieClipUser *user,
int *r_totseg,
int **r_points);
+/**
+ * \note currently used by proxy job for movies, threading happens within single frame
+ * (meaning scaling shall be threaded).
+ */
void BKE_movieclip_build_proxy_frame(struct MovieClip *clip,
int clip_flag,
struct MovieDistortion *distortion,
@@ -88,6 +104,10 @@ void BKE_movieclip_build_proxy_frame(struct MovieClip *clip,
int build_count,
bool undistorted);
+/**
+ * \note currently used by proxy job for sequences, threading happens within sequence
+ * (different threads handles different frames, no threading within frame is needed)
+ */
void BKE_movieclip_build_proxy_frame_for_ibuf(struct MovieClip *clip,
struct ImBuf *ibuf,
struct MovieDistortion *distortion,
@@ -95,6 +115,7 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(struct MovieClip *clip,
int *build_sizes,
int build_count,
bool undistorted);
+bool BKE_movieclip_proxy_enabled(struct MovieClip *clip);
float BKE_movieclip_remap_scene_to_clip_frame(const struct MovieClip *clip, float framenr);
float BKE_movieclip_remap_clip_to_scene_frame(const struct MovieClip *clip, float framenr);
@@ -103,8 +124,10 @@ void BKE_movieclip_filename_for_frame(struct MovieClip *clip,
struct MovieClipUser *user,
char *name);
-/* Read image buffer from the given movie clip without acquiring the `LOCK_MOVIECLIP` lock.
- * Used by a prefetch job which takes care of creating a local copy of the clip. */
+/**
+ * Read image buffer from the given movie clip without acquiring the #LOCK_MOVIECLIP lock.
+ * Used by a prefetch job which takes care of creating a local copy of the clip.
+ */
struct ImBuf *BKE_movieclip_anim_ibuf_for_frame_no_lock(struct MovieClip *clip,
struct MovieClipUser *user);
@@ -125,10 +148,10 @@ void BKE_movieclip_eval_update(struct Depsgraph *depsgraph,
struct MovieClip *clip);
void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, struct MovieClip *clip);
-/* caching flags */
+/** Caching flags. */
#define MOVIECLIP_CACHE_SKIP (1 << 0)
-/* postprocessing flags */
+/** Post-processing flags. */
#define MOVIECLIP_DISABLE_RED (1 << 0)
#define MOVIECLIP_DISABLE_GREEN (1 << 1)
#define MOVIECLIP_DISABLE_BLUE (1 << 2)
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index 11bfc4b2b3a..504771fa733 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -45,7 +45,9 @@ struct MLoopTri;
struct MPoly;
struct MVert;
-/* Delete mesh mdisps and grid paint masks */
+/**
+ * Delete mesh mdisps and grid paint masks.
+ */
void multires_customdata_delete(struct Mesh *me);
void multires_set_tot_level(struct Object *ob, struct MultiresModifierData *mmd, int lvl);
@@ -62,6 +64,9 @@ void multires_force_external_reload(struct Object *object);
void multires_modifier_update_mdisps(struct DerivedMesh *dm, struct Scene *scene);
void multires_modifier_update_hidden(struct DerivedMesh *dm);
+/**
+ * Reset the multi-res levels to match the number of mdisps.
+ */
void multiresModifier_set_levels_from_disps(struct MultiresModifierData *mmd, struct Object *ob);
typedef enum {
@@ -79,6 +84,10 @@ struct DerivedMesh *multires_make_derived_from_derived(struct DerivedMesh *dm,
struct MultiresModifierData *find_multires_modifier_before(struct Scene *scene,
struct ModifierData *lastmd);
+/**
+ * used for applying scale on mdisps layer and syncing subdivide levels when joining objects.
+ * \param use_first: return first multi-res modifier if all multi-res'es are disabled.
+ */
struct MultiresModifierData *get_multires_modifier(struct Scene *scene,
struct Object *ob,
bool use_first);
@@ -88,18 +97,25 @@ int multires_get_level(const struct Scene *scene,
bool render,
bool ignore_simplify);
-/* Creates mesh with multires modifier applied on current object's deform mesh. */
+/**
+ * Creates mesh with multi-res modifier applied on current object's deform mesh.
+ */
struct Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph,
struct Object *object,
struct MultiresModifierData *mmd);
-/* Get coordinates of a deformed base mesh which is an input to the given multires modifier.
- * NOTE: The modifiers will be re-evaluated. */
+/**
+ * Get coordinates of a deformed base mesh which is an input to the given multi-res modifier.
+ * \note The modifiers will be re-evaluated.
+ */
float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *depsgraph,
struct Object *object,
struct MultiresModifierData *mmd,
int *r_num_deformed_verts))[3];
+/**
+ * \param direction: 1 for delete higher, 0 for lower (not implemented yet).
+ */
void multiresModifier_del_levels(struct MultiresModifierData *mmd,
struct Scene *scene,
struct Object *object,
@@ -112,6 +128,10 @@ int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph,
struct MultiresModifierData *mmd,
int rebuild_limit,
bool switch_view_to_lower_level);
+/**
+ * If `ob_src` and `ob_dst` both have multi-res modifiers,
+ * synchronize them such that `ob_dst` has the same total number of levels as `ob_src`.
+ */
void multiresModifier_sync_levels_ex(struct Object *ob_dst,
struct MultiresModifierData *mmd_src,
struct MultiresModifierData *mmd_dst);
@@ -128,22 +148,36 @@ void multiresModifier_prepare_join(struct Depsgraph *depsgraph,
int multires_mdisp_corners(struct MDisps *s);
-/* update multires data after topology changing */
+/**
+ * Update multi-res data after topology changing.
+ */
void multires_topology_changed(struct Mesh *me);
+/**
+ * Makes sure data from an external file is fully read.
+ *
+ * Since the multi-res data files only contain displacement vectors without knowledge about
+ * subdivision level some extra work is needed. Namely make is to all displacement grids have
+ * proper level and number of displacement vectors set.
+ */
void multires_ensure_external_read(struct Mesh *mesh, int top_level);
void multiresModifier_ensure_external_read(struct Mesh *mesh,
const struct MultiresModifierData *mmd);
/**** interpolation stuff ****/
-void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v);
+/* Adapted from `sculptmode.c` */
+
+void old_mdisps_bilinear(float out[3], float (*disps)[3], int st, float u, float v);
+/**
+ * Find per-corner coordinate with given per-face UV coord.
+ */
int mdisp_rot_face_to_crn(struct MVert *mvert,
struct MPoly *mpoly,
struct MLoop *mloop,
const struct MLoopTri *lt,
- const int face_side,
- const float u,
- const float v,
+ int face_side,
+ float u,
+ float v,
float *x,
float *y);
@@ -153,7 +187,13 @@ bool multiresModifier_reshapeFromVertcos(struct Depsgraph *depsgraph,
struct Object *object,
struct MultiresModifierData *mmd,
const float (*vert_coords)[3],
- const int num_vert_coords);
+ int num_vert_coords);
+/**
+ * Returns truth on success, false otherwise.
+ *
+ * This function might fail in cases like source and destination not having
+ * matched amount of vertices.
+ */
bool multiresModifier_reshapeFromObject(struct Depsgraph *depsgraph,
struct MultiresModifierData *mmd,
struct Object *dst,
@@ -162,11 +202,11 @@ bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph,
struct Object *ob,
struct MultiresModifierData *mmd,
struct ModifierData *deform_md);
-bool multiresModifier_reshapeFromCCG(const int tot_level,
+bool multiresModifier_reshapeFromCCG(int tot_level,
struct Mesh *coarse_mesh,
struct SubdivCCG *subdiv_ccg);
-/* Subdivide multires displacement once. */
+/* Subdivide multi-res displacement once. */
typedef enum eMultiresSubdivideModeType {
MULTIRES_SUBDIVIDE_CATMULL_CLARK,
@@ -176,16 +216,18 @@ typedef enum eMultiresSubdivideModeType {
void multiresModifier_subdivide(struct Object *object,
struct MultiresModifierData *mmd,
- const eMultiresSubdivideModeType mode);
+ eMultiresSubdivideModeType mode);
void multires_subdivide_create_tangent_displacement_linear_grids(struct Object *object,
struct MultiresModifierData *mmd);
-/* Subdivide displacement to the given level.
- * If level is lower than the current top level nothing happens. */
+/**
+ * Subdivide displacement to the given level.
+ * If level is lower than the current top level nothing happens.
+ */
void multiresModifier_subdivide_to_level(struct Object *object,
struct MultiresModifierData *mmd,
- const int top_level,
- const eMultiresSubdivideModeType mode);
+ int top_level,
+ eMultiresSubdivideModeType mode);
/* Subdivision integration, defined in multires_subdiv.c */
@@ -200,27 +242,29 @@ void BKE_multires_subdiv_mesh_settings_init(struct SubdivToMeshSettings *mesh_se
const struct Scene *scene,
const struct Object *object,
const struct MultiresModifierData *mmd,
- const bool use_render_params,
- const bool ignore_simplify,
- const bool ignore_control_edges);
+ bool use_render_params,
+ bool ignore_simplify,
+ bool ignore_control_edges);
/* General helpers. */
-/* For a given partial derivatives of a ptex face get tangent matrix for
- * displacement.
+/**
+ * For a given partial derivatives of a PTEX face get tangent matrix for displacement.
*
* Corner needs to be known to properly "rotate" partial derivatives when the
- * matrix is being constructed for quad. For non-quad the corner is to be set
- * to 0. */
+ * matrix is being constructed for quad. For non-quad the corner is to be set to 0.
+ */
BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3],
const float dPdu[3],
const float dPdv[3],
- const int corner);
+ int corner);
/* Versioning. */
-/* Convert displacement which is stored for simply-subdivided mesh to a Catmull-Clark
- * subdivided mesh. */
+/**
+ * Convert displacement which is stored for simply-subdivided mesh to a Catmull-Clark
+ * subdivided mesh.
+ */
void multires_do_versions_simple_to_catmull_clark(struct Object *object,
struct MultiresModifierData *mmd);
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index cf8848fe607..61431547bfb 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -46,106 +46,289 @@ struct PropertyRNA;
/* ----------------------------- */
/* Data Management */
+/**
+ * Remove the given NLA strip from the NLA track it occupies, free the strip's data,
+ * and the strip itself.
+ */
void BKE_nlastrip_free(ListBase *strips, struct NlaStrip *strip, bool do_id_user);
+/**
+ * Remove the given NLA track from the set of NLA tracks, free the track's data,
+ * and the track itself.
+ */
void BKE_nlatrack_free(ListBase *tracks, struct NlaTrack *nlt, bool do_id_user);
+/**
+ * Free the elements of type NLA Tracks provided in the given list, but do not free
+ * the list itself since that is not free-standing
+ */
void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user);
+/**
+ * Copy NLA strip
+ *
+ * \param use_same_action: When true, the existing action is used (instead of being duplicated)
+ * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
+ * flags in BKE_lib_id.h
+ */
struct NlaStrip *BKE_nlastrip_copy(struct Main *bmain,
struct NlaStrip *strip,
- const bool use_same_action,
- const int flag);
+ bool use_same_action,
+ int flag);
+/**
+ * Copy a single NLA Track.
+ * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
+ * flags in BKE_lib_id.h
+ */
struct NlaTrack *BKE_nlatrack_copy(struct Main *bmain,
struct NlaTrack *nlt,
- const bool use_same_actions,
- const int flag);
-void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, const ListBase *src, const int flag);
+ bool use_same_actions,
+ int flag);
+/**
+ * Copy all NLA data.
+ * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
+ * flags in BKE_lib_id.h
+ */
+void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, const ListBase *src, int flag);
-/* Copy NLA tracks from #adt_source to #adt_dest, and update the active track/strip pointers to
- * point at those copies. */
+/**
+ * Copy NLA tracks from #adt_source to #adt_dest, and update the active track/strip pointers to
+ * point at those copies.
+ */
void BKE_nla_tracks_copy_from_adt(struct Main *bmain,
struct AnimData *adt_dest,
const struct AnimData *adt_source,
int flag);
+/**
+ * Add a NLA Track to the given AnimData.
+ * \param prev: NLA-Track to add the new one after.
+ */
struct NlaTrack *BKE_nlatrack_add(struct AnimData *adt,
struct NlaTrack *prev,
bool is_liboverride);
+/**
+ * Create a NLA Strip referencing the given Action.
+ */
struct NlaStrip *BKE_nlastrip_new(struct bAction *act);
+/**
+ * Add new NLA-strip to the top of the NLA stack - i.e.
+ * into the last track if space, or a new one otherwise.
+ */
struct NlaStrip *BKE_nlastack_add_strip(struct AnimData *adt,
struct bAction *act,
- const bool is_liboverride);
+ bool is_liboverride);
+/**
+ * Add a NLA Strip referencing the given speaker's sound.
+ */
struct NlaStrip *BKE_nla_add_soundstrip(struct Main *bmain,
struct Scene *scene,
struct Speaker *speaker);
+/**
+ * Callback used by lib_query to walk over all ID usages
+ * (mimics `foreach_id` callback of #IDTypeInfo structure).
+ */
void BKE_nla_strip_foreach_id(struct NlaStrip *strip, struct LibraryForeachIDData *data);
/* ----------------------------- */
/* API */
+/**
+ * Check if there is any space in the given list to add the given strip.
+ */
bool BKE_nlastrips_has_space(ListBase *strips, float start, float end);
+/**
+ * Rearrange the strips in the track so that they are always in order
+ * (usually only needed after a strip has been moved)
+ */
void BKE_nlastrips_sort_strips(ListBase *strips);
+/**
+ * Add the given NLA-Strip to the given list of strips, assuming that it
+ * isn't currently a member of another list
+ */
bool BKE_nlastrips_add_strip(ListBase *strips, struct NlaStrip *strip);
+/**
+ * Convert 'islands' (i.e. continuous string of) selected strips to be
+ * contained within 'Meta-Strips' which act as strips which contain strips.
+ *
+ * \param is_temp: are the meta-strips to be created 'temporary' ones used for transforms?
+ */
void BKE_nlastrips_make_metas(ListBase *strips, bool is_temp);
+/**
+ * Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips.
+ *
+ * \param only_sel: only consider selected meta-strips, otherwise all meta-strips are removed
+ * \param only_temp: only remove the 'temporary' meta-strips used for transforms
+ */
void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp);
+/**
+ * Split a meta-strip into a set of normal strips.
+ */
void BKE_nlastrips_clear_metastrip(ListBase *strips, struct NlaStrip *strip);
+/**
+ * Add the given NLA-Strip to the given Meta-Strip, assuming that the
+ * strip isn't attached to any list of strips
+ */
bool BKE_nlameta_add_strip(struct NlaStrip *mstrip, struct NlaStrip *strip);
+/**
+ * Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively),
+ * until the Meta-Strips children all fit within the Meta-Strip's new dimensions
+ */
void BKE_nlameta_flush_transforms(struct NlaStrip *mstrip);
/* ............ */
+/**
+ * Find the active NLA-track for the given stack.
+ */
struct NlaTrack *BKE_nlatrack_find_active(ListBase *tracks);
+/**
+ * Make the given NLA-track the active one for the given stack. If no track is provided,
+ * this function can be used to simply deactivate all the NLA tracks in the given stack too.
+ */
void BKE_nlatrack_set_active(ListBase *tracks, struct NlaTrack *nlt);
+/**
+ * Get the NLA Track that the active action/action strip comes from,
+ * since this info is not stored in AnimData. It also isn't as simple
+ * as just using the active track, since multiple tracks may have been
+ * entered at the same time.
+ */
struct NlaTrack *BKE_nlatrack_find_tweaked(struct AnimData *adt);
+/**
+ * Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
+ * that has this status in its AnimData block.
+ */
void BKE_nlatrack_solo_toggle(struct AnimData *adt, struct NlaTrack *nlt);
+/**
+ * Check if there is any space in the given track to add a strip of the given length.
+ */
bool BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end);
+/**
+ * Rearrange the strips in the track so that they are always in order
+ * (usually only needed after a strip has been moved).
+ */
void BKE_nlatrack_sort_strips(struct NlaTrack *nlt);
-bool BKE_nlatrack_add_strip(struct NlaTrack *nlt,
- struct NlaStrip *strip,
- const bool is_liboverride);
+/**
+ * Add the given NLA-Strip to the given NLA-Track, assuming that it
+ * isn't currently attached to another one.
+ */
+bool BKE_nlatrack_add_strip(struct NlaTrack *nlt, struct NlaStrip *strip, bool is_liboverride);
+/**
+ * Get the extents of the given NLA-Track including gaps between strips,
+ * returning whether this succeeded or not
+ */
bool BKE_nlatrack_get_bounds(struct NlaTrack *nlt, float bounds[2]);
-
+/**
+ * Check whether given NLA track is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param nlt: May be NULL, in which case we consider it as a non-local track case.
+ */
bool BKE_nlatrack_is_nonlocal_in_liboverride(const struct ID *id, const struct NlaTrack *nlt);
/* ............ */
+/**
+ * Find the active NLA-strip within the given track.
+ */
struct NlaStrip *BKE_nlastrip_find_active(struct NlaTrack *nlt);
+/**
+ * Make the given NLA-Strip the active one within the given block.
+ */
void BKE_nlastrip_set_active(struct AnimData *adt, struct NlaStrip *strip);
+/**
+ * Does the given NLA-strip fall within the given bounds (times)?.
+ */
bool BKE_nlastrip_within_bounds(struct NlaStrip *strip, float min, float max);
+/**
+ * Recalculate the start and end frames for the current strip, after changing
+ * the extents of the action or the mapping (repeats or scale factor) info.
+ */
void BKE_nlastrip_recalculate_bounds(struct NlaStrip *strip);
+/**
+ * Recalculate the start and end frames for the strip to match the bounds of its action such that
+ * the overall NLA animation result is unchanged.
+ */
void BKE_nlastrip_recalculate_bounds_sync_action(struct NlaStrip *strip);
+/**
+ * Find (and set) a unique name for a strip from the whole AnimData block
+ * Uses a similar method to the BLI method, but is implemented differently
+ * as we need to ensure that the name is unique over several lists of tracks,
+ * not just a single track.
+ */
void BKE_nlastrip_validate_name(struct AnimData *adt, struct NlaStrip *strip);
/* ............ */
+/**
+ * Check if the given NLA-Track has any strips with own F-Curves.
+ */
bool BKE_nlatrack_has_animated_strips(struct NlaTrack *nlt);
+/**
+ * Check if given NLA-Tracks have any strips with own F-Curves.
+ */
bool BKE_nlatracks_have_animated_strips(ListBase *tracks);
+/**
+ * Validate the NLA-Strips 'control' F-Curves based on the flags set.
+ */
void BKE_nlastrip_validate_fcurves(struct NlaStrip *strip);
+/**
+ * Check if the given RNA pointer + property combo should be handled by
+ * NLA strip curves or not.
+ */
bool BKE_nlastrip_has_curves_for_property(const struct PointerRNA *ptr,
const struct PropertyRNA *prop);
+/**
+ * Ensure that auto-blending and other settings are set correctly.
+ */
void BKE_nla_validate_state(struct AnimData *adt);
/* ............ */
+/**
+ * Check if an action is "stashed" in the NLA already
+ *
+ * The criteria for this are:
+ * 1) The action in question lives in a "stash" track.
+ * 2) We only check first-level strips. That is, we will not check inside meta strips.
+ */
bool BKE_nla_action_is_stashed(struct AnimData *adt, struct bAction *act);
-bool BKE_nla_action_stash(struct AnimData *adt, const bool is_liboverride);
+/**
+ * "Stash" an action (i.e. store it as a track/layer in the NLA, but non-contributing)
+ * to retain it in the file for future uses.
+ */
+bool BKE_nla_action_stash(struct AnimData *adt, bool is_liboverride);
/* ............ */
-void BKE_nla_action_pushdown(struct AnimData *adt, const bool is_liboverride);
+/**
+ * For the given AnimData block, add the active action to the NLA
+ * stack (i.e. 'push-down' action). The UI should only allow this
+ * for normal editing only (i.e. not in edit-mode for some strip's action),
+ * so no checks for this are performed.
+ *
+ * TODO: maybe we should have checks for this too.
+ */
+void BKE_nla_action_pushdown(struct AnimData *adt, bool is_liboverride);
+/**
+ * Find the active strip + track combination, and set them up as the tweaking track,
+ * and return if successful or not.
+ */
bool BKE_nla_tweakmode_enter(struct AnimData *adt);
+/**
+ * Exit tweak-mode for this AnimData block.
+ */
void BKE_nla_tweakmode_exit(struct AnimData *adt);
/* ----------------------------- */
@@ -163,6 +346,13 @@ enum eNlaTime_ConvertModes {
NLATIME_CONVERT_MAP,
};
+/**
+ * Non clipped mapping for strip-time <-> global time:
+ * `mode = eNlaTime_ConvertModes -> NLATIME_CONVERT_*`
+ *
+ * Public API method - perform this mapping using the given AnimData block
+ * and perform any necessary sanity checks on the value
+ */
float BKE_nla_tweakedit_remap(struct AnimData *adt, float cframe, short mode);
/* ----------------------------- */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 7084a9ffd20..16d8ba2e6dd 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -34,6 +34,11 @@
#include "RNA_types.h"
#ifdef __cplusplus
+# include "BLI_map.hh"
+# include "BLI_string_ref.hh"
+#endif
+
+#ifdef __cplusplus
extern "C" {
#endif
@@ -114,6 +119,7 @@ namespace nodes {
class NodeMultiFunctionBuilder;
class GeoNodeExecParams;
class NodeDeclarationBuilder;
+class GatherLinkSearchOpParams;
} // namespace nodes
namespace fn {
class CPPType;
@@ -121,23 +127,28 @@ class MFDataType;
} // namespace fn
} // namespace blender
+using CPPTypeHandle = blender::fn::CPPType;
using NodeMultiFunctionBuildFunction = void (*)(blender::nodes::NodeMultiFunctionBuilder &builder);
using NodeGeometryExecFunction = void (*)(blender::nodes::GeoNodeExecParams params);
using NodeDeclareFunction = void (*)(blender::nodes::NodeDeclarationBuilder &builder);
-using SocketGetCPPTypeFunction = const blender::fn::CPPType *(*)();
using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value);
-using SocketGetGeometryNodesCPPTypeFunction = const blender::fn::CPPType *(*)();
using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket &socket,
void *r_value);
+/* Adds socket link operations that are specific to this node type. */
+using NodeGatherSocketLinkOperationsFunction =
+ void (*)(blender::nodes::GatherLinkSearchOpParams &params);
+
#else
typedef void *NodeMultiFunctionBuildFunction;
typedef void *NodeGeometryExecFunction;
typedef void *NodeDeclareFunction;
+typedef void *NodeGatherSocketLinkOperationsFunction;
typedef void *SocketGetCPPTypeFunction;
typedef void *SocketGetGeometryNodesCPPTypeFunction;
typedef void *SocketGetGeometryNodesCPPValueFunction;
typedef void *SocketGetCPPValueFunction;
+typedef struct CPPTypeHandle CPPTypeHandle;
#endif
/**
@@ -164,20 +175,20 @@ typedef struct bNodeSocketType {
void (*interface_draw)(struct bContext *C, struct uiLayout *layout, struct PointerRNA *ptr);
void (*interface_draw_color)(struct bContext *C, struct PointerRNA *ptr, float *r_color);
void (*interface_register_properties)(struct bNodeTree *ntree,
- struct bNodeSocket *stemp,
+ struct bNodeSocket *interface_socket,
struct StructRNA *data_srna);
void (*interface_init_socket)(struct bNodeTree *ntree,
- struct bNodeSocket *stemp,
+ const struct bNodeSocket *interface_socket,
struct bNode *node,
struct bNodeSocket *sock,
const char *data_path);
void (*interface_verify_socket)(struct bNodeTree *ntree,
- struct bNodeSocket *stemp,
+ const struct bNodeSocket *interface_socket,
struct bNode *node,
struct bNodeSocket *sock,
const char *data_path);
void (*interface_from_socket)(struct bNodeTree *ntree,
- struct bNodeSocket *stemp,
+ struct bNodeSocket *interface_socket,
struct bNode *node,
struct bNodeSocket *sock);
@@ -197,11 +208,11 @@ typedef struct bNodeSocketType {
void (*free_self)(struct bNodeSocketType *stype);
/* Return the CPPType of this socket. */
- SocketGetCPPTypeFunction get_base_cpp_type;
+ const CPPTypeHandle *base_cpp_type;
/* Get the value of this socket in a generic way. */
SocketGetCPPValueFunction get_base_cpp_value;
/* Get geometry nodes cpp type. */
- SocketGetGeometryNodesCPPTypeFunction get_geometry_nodes_cpp_type;
+ const CPPTypeHandle *geometry_nodes_cpp_type;
/* Get geometry nodes cpp value. */
SocketGetGeometryNodesCPPValueFunction get_geometry_nodes_cpp_value;
} bNodeSocketType;
@@ -229,8 +240,6 @@ typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat,
* implementing the node behavior.
*/
typedef struct bNodeType {
- void *next, *prev;
-
char idname[64]; /* identifier name */
int type;
@@ -247,18 +256,6 @@ typedef struct bNodeType {
char storagename[64]; /* struct name for DNA */
- /* Main draw function for the node */
- void (*draw_nodetype)(const struct bContext *C,
- struct ARegion *region,
- struct SpaceNode *snode,
- struct bNodeTree *ntree,
- struct bNode *node,
- bNodeInstanceKey key);
- /* Updates the node geometry attributes according to internal state before actual drawing */
- void (*draw_nodetype_prepare)(const struct bContext *C,
- struct bNodeTree *ntree,
- struct bNode *node);
-
/* Draw the option buttons on the node */
void (*draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr);
/* Additional parameters in the side panel */
@@ -272,13 +269,10 @@ typedef struct bNodeType {
* Optional custom label function for the node header.
* \note Used as a fallback when #bNode.label isn't set.
*/
- void (*labelfunc)(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
- /** Optional custom resize handle polling. */
- int (*resize_area_func)(struct bNode *node, int x, int y);
- /** Optional selection area polling. */
- int (*select_area_func)(struct bNode *node, int x, int y);
- /** Optional tweak area polling (for grabbing). */
- int (*tweak_area_func)(struct bNode *node, int x, int y);
+ void (*labelfunc)(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
/** Called when the node is updated in the editor. */
void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node);
@@ -301,7 +295,7 @@ typedef struct bNodeType {
/**
* Can this node type be added to a node tree?
- * \param r_disabled_hint: Optional hint to display in the UI when the poll fails.
+ * \param r_disabled_hint: Hint to display in the UI when the poll fails.
* The callback can set this to a static string without having to
* null-check it (or without setting it to null if it's not used).
* The caller must pass a valid `const char **` and null-initialize it
@@ -318,8 +312,6 @@ typedef struct bNodeType {
/* optional handling of link insertion */
void (*insert_link)(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
- /* Update the internal links list, for muting and disconnect operators. */
- void (*update_internal_links)(struct bNodeTree *, struct bNode *node);
void (*free_self)(struct bNodeType *ntype);
@@ -339,6 +331,20 @@ typedef struct bNodeType {
/* Declares which sockets the node has. */
NodeDeclareFunction declare;
+ /* Different nodes of this type can have different declarations. */
+ bool declaration_is_dynamic;
+ /* Declaration to be used when it is not dynamic. */
+ NodeDeclarationHandle *fixed_declaration;
+
+ /**
+ * Add to the list of search names and operations gathered by node link drag searching.
+ * Usually it isn't necessary to override the default behavior here, but a node type can have
+ * custom behavior here like adding custom search items.
+ */
+ NodeGatherSocketLinkOperationsFunction gather_link_search_ops;
+
+ /** True when the node cannot be muted. */
+ bool no_muting;
/* RNA integration */
ExtensionRNA rna_ext;
@@ -351,22 +357,11 @@ typedef struct bNodeType {
#define NODE_CLASS_OP_VECTOR 4
#define NODE_CLASS_OP_FILTER 5
#define NODE_CLASS_GROUP 6
-// #define NODE_CLASS_FILE 7
#define NODE_CLASS_CONVERTER 8
#define NODE_CLASS_MATTE 9
#define NODE_CLASS_DISTORT 10
-// #define NODE_CLASS_OP_DYNAMIC 11 /* deprecated */
#define NODE_CLASS_PATTERN 12
#define NODE_CLASS_TEXTURE 13
-// #define NODE_CLASS_EXECUTION 14
-// #define NODE_CLASS_GETDATA 15
-// #define NODE_CLASS_SETDATA 16
-// #define NODE_CLASS_MATH 17
-// #define NODE_CLASS_MATH_VECTOR 18
-// #define NODE_CLASS_MATH_ROTATION 19
-// #define NODE_CLASS_PARTICLES 25
-// #define NODE_CLASS_TRANSFORM 30
-// #define NODE_CLASS_COMBINE 31
#define NODE_CLASS_SCRIPT 32
#define NODE_CLASS_INTERFACE 33
#define NODE_CLASS_SHADER 40
@@ -374,12 +369,6 @@ typedef struct bNodeType {
#define NODE_CLASS_ATTRIBUTE 42
#define NODE_CLASS_LAYOUT 100
-/* node resize directions */
-#define NODE_RESIZE_TOP 1
-#define NODE_RESIZE_BOTTOM 2
-#define NODE_RESIZE_RIGHT 4
-#define NODE_RESIZE_LEFT 8
-
typedef enum eNodeSizePreset {
NODE_SIZE_DEFAULT,
NODE_SIZE_SMALL,
@@ -414,13 +403,12 @@ typedef struct bNodeTreeType {
/* calls allowing threaded composite */
void (*localize)(struct bNodeTree *localtree, struct bNodeTree *ntree);
- void (*local_sync)(struct bNodeTree *localtree, struct bNodeTree *ntree);
void (*local_merge)(struct Main *bmain, struct bNodeTree *localtree, struct bNodeTree *ntree);
- /* Tree update. Overrides nodetype->updatetreefunc! */
+ /* Tree update. Overrides `nodetype->updatetreefunc` ! */
void (*update)(struct bNodeTree *ntree);
- bool (*validate_link)(struct bNodeTree *ntree, struct bNodeLink *link);
+ bool (*validate_link)(eNodeSocketDatatype from, eNodeSocketDatatype to);
void (*node_add_init)(struct bNodeTree *ntree, struct bNode *bnode);
@@ -443,7 +431,7 @@ void ntreeTypeFreeLink(const struct bNodeTreeType *nt);
bool ntreeIsRegistered(struct bNodeTree *ntree);
struct GHashIterator *ntreeTypeGetIterator(void);
-/* helper macros for iterating over tree types */
+/* Helper macros for iterating over tree types. */
#define NODE_TREE_TYPES_BEGIN(ntype) \
{ \
GHashIterator *__node_tree_type_iter__ = ntreeTypeGetIterator(); \
@@ -457,36 +445,60 @@ struct GHashIterator *ntreeTypeGetIterator(void);
} \
(void)0
+/**
+ * Try to initialize all type-info in a node tree.
+ *
+ * \note In general undefined type-info is a perfectly valid case,
+ * the type may just be registered later.
+ * In that case the update_typeinfo function will set type-info on registration
+ * and do necessary updates.
+ */
void ntreeSetTypes(const struct bContext *C, struct bNodeTree *ntree);
struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname);
/* copy/free funcs, need to manage ID users */
+
+/**
+ * Free (or release) any data used by this node-tree.
+ * Does not free the node-tree itself and does no ID user counting.
+ */
void ntreeFreeTree(struct bNodeTree *ntree);
-/* Free tree which is embedded into another datablock. */
+/**
+ * Free tree which is embedded into another data-block.
+ */
void ntreeFreeEmbeddedTree(struct bNodeTree *ntree);
struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree,
struct Main *bmain,
- const bool do_id_user);
+ bool do_id_user);
struct bNodeTree *ntreeCopyTree(struct Main *bmain, const struct bNodeTree *ntree);
+/**
+ * Get address of potential node-tree pointer of given ID.
+ *
+ * \warning Using this function directly is potentially dangerous, if you don't know or are not
+ * sure, please use `ntreeFromID()` instead.
+ */
struct bNodeTree **BKE_ntree_ptr_from_id(struct ID *id);
+/**
+ * Returns the private NodeTree object of the data-block, if it has one.
+ */
struct bNodeTree *ntreeFromID(struct ID *id);
void ntreeFreeLocalNode(struct bNodeTree *ntree, struct bNode *node);
void ntreeFreeLocalTree(struct bNodeTree *ntree);
struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type);
-bool ntreeHasType(const struct bNodeTree *ntree, int type);
bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup);
-void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree);
void ntreeUpdateAllNew(struct Main *main);
-void ntreeUpdateAllUsers(struct Main *main, struct ID *id, int tree_update_flag);
+void ntreeUpdateAllUsers(struct Main *main, struct ID *id);
void ntreeGetDependencyList(struct bNodeTree *ntree,
struct bNode ***r_deplist,
int *r_deplist_len);
+void ntreeUpdateNodeLevels(struct bNodeTree *ntree);
-/* XXX old trees handle output flags automatically based on special output
+/**
+ * XXX: old trees handle output flags automatically based on special output
* node types and last active selection.
* New tree types have a per-output socket flag to indicate the final output to use explicitly.
*/
@@ -494,14 +506,25 @@ void ntreeSetOutput(struct bNodeTree *ntree);
void ntreeFreeCache(struct bNodeTree *ntree);
-bool ntreeNodeExists(const struct bNodeTree *ntree, const struct bNode *testnode);
-bool ntreeOutputExists(const struct bNode *node, const struct bNodeSocket *testsock);
-void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable);
+void ntreeNodeFlagSet(const bNodeTree *ntree, int flag, bool enable);
+/**
+ * Returns localized tree for execution in threads.
+ */
struct bNodeTree *ntreeLocalize(struct bNodeTree *ntree);
-void ntreeLocalSync(struct bNodeTree *localtree, struct bNodeTree *ntree);
+/**
+ * Merge local tree results back, and free local tree.
+ *
+ * We have to assume the editor already changed completely.
+ */
void ntreeLocalMerge(struct Main *bmain, struct bNodeTree *localtree, struct bNodeTree *ntree);
+/**
+ * This is only direct data, tree itself should have been written.
+ */
void ntreeBlendWrite(struct BlendWriter *writer, struct bNodeTree *ntree);
+/**
+ * \note `ntree` itself has been read!
+ */
void ntreeBlendReadData(struct BlendDataReader *reader, struct bNodeTree *ntree);
void ntreeBlendReadLib(struct BlendLibReader *reader, struct bNodeTree *ntree);
void ntreeBlendReadExpand(struct BlendExpander *expander, struct bNodeTree *ntree);
@@ -511,6 +534,7 @@ void ntreeBlendReadExpand(struct BlendExpander *expander, struct bNodeTree *ntre
/* -------------------------------------------------------------------- */
/** \name Node Tree Interface
* \{ */
+
struct bNodeSocket *ntreeFindSocketInterface(struct bNodeTree *ntree,
eNodeSocketInOut in_out,
const char *identifier);
@@ -545,10 +569,10 @@ void ntreeInterfaceTypeUpdate(struct bNodeTree *ntree);
struct bNodeType *nodeTypeFind(const char *idname);
void nodeRegisterType(struct bNodeType *ntype);
void nodeUnregisterType(struct bNodeType *ntype);
-bool nodeTypeUndefined(struct bNode *node);
+bool nodeTypeUndefined(const struct bNode *node);
struct GHashIterator *nodeTypeGetIterator(void);
-/* helper macros for iterating over node types */
+/* Helper macros for iterating over node types. */
#define NODE_TYPES_BEGIN(ntype) \
{ \
GHashIterator *__node_type_iter__ = nodeTypeGetIterator(); \
@@ -574,7 +598,7 @@ const char *nodeStaticSocketType(int type, int subtype);
const char *nodeStaticSocketInterfaceType(int type, int subtype);
const char *nodeStaticSocketLabel(int type, int subtype);
-/* helper macros for iterating over node types */
+/* Helper macros for iterating over node types. */
#define NODE_SOCKET_TYPES_BEGIN(stype) \
{ \
GHashIterator *__node_socket_type_iter__ = nodeSocketTypeGetIterator(); \
@@ -598,13 +622,6 @@ struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree,
const char *idname,
const char *identifier,
const char *name);
-struct bNodeSocket *nodeInsertSocket(struct bNodeTree *ntree,
- struct bNode *node,
- eNodeSocketInOut in_out,
- const char *idname,
- struct bNodeSocket *next_sock,
- const char *identifier,
- const char *name);
struct bNodeSocket *nodeAddStaticSocket(struct bNodeTree *ntree,
struct bNode *node,
eNodeSocketInOut in_out,
@@ -612,14 +629,6 @@ struct bNodeSocket *nodeAddStaticSocket(struct bNodeTree *ntree,
int subtype,
const char *identifier,
const char *name);
-struct bNodeSocket *nodeInsertStaticSocket(struct bNodeTree *ntree,
- struct bNode *node,
- eNodeSocketInOut in_out,
- int type,
- int subtype,
- struct bNodeSocket *next_sock,
- const char *identifier,
- const char *name);
void nodeRemoveSocket(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock);
void nodeRemoveSocketEx(struct bNodeTree *ntree,
struct bNode *node,
@@ -635,34 +644,47 @@ void nodeModifySocketTypeStatic(
struct bNode *nodeAddNode(const struct bContext *C, struct bNodeTree *ntree, const char *idname);
struct bNode *nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type);
+/**
+ * \note Goes over entire tree.
+ */
void nodeUnlinkNode(struct bNodeTree *ntree, struct bNode *node);
+/**
+ * Find the first available, non-duplicate name for a given node.
+ */
void nodeUniqueName(struct bNodeTree *ntree, struct bNode *node);
-/* Delete node, associated animation data and ID user count. */
+/**
+ * Delete node, associated animation data and ID user count.
+ */
void nodeRemoveNode(struct Main *bmain,
struct bNodeTree *ntree,
struct bNode *node,
bool do_id_user);
-struct bNode *BKE_node_copy_ex(struct bNodeTree *ntree,
- const struct bNode *node_src,
- const int flag,
- const bool unique_name);
+#ifdef __cplusplus
-/* Same as BKE_node_copy_ex() but stores pointers to a new node and its sockets in the source
- * node.
- *
- * NOTE: DANGER ZONE!
- *
- * TODO(sergey): Maybe it's better to make BKE_node_copy_ex() return a mapping from old node and
- * sockets to new one. */
-struct bNode *BKE_node_copy_store_new_pointers(struct bNodeTree *ntree,
- struct bNode *node_src,
- const int flag);
-struct bNodeTree *ntreeCopyTree_ex_new_pointers(const struct bNodeTree *ntree,
- struct Main *bmain,
- const bool do_id_user);
+namespace blender::bke {
+/**
+ * \note keeps socket list order identical, for copying links.
+ * \note `unique_name` should usually be true, unless the \a dst_tree is temporary,
+ * or the names can already be assumed valid.
+ */
+bNode *node_copy_with_mapping(bNodeTree *dst_tree,
+ const bNode &node_src,
+ int flag,
+ bool unique_name,
+ Map<const bNodeSocket *, bNodeSocket *> &new_socket_map);
+
+bNode *node_copy(bNodeTree *dst_tree, const bNode &src_node, int flag, bool unique_name);
+
+} // namespace blender::bke
+
+#endif
+
+/**
+ * Also used via RNA API, so we check for proper input output direction.
+ */
struct bNodeLink *nodeAddLink(struct bNodeTree *ntree,
struct bNode *fromnode,
struct bNodeSocket *fromsock,
@@ -686,25 +708,62 @@ void nodePositionRelative(struct bNode *from_node,
struct bNodeSocket *to_sock);
void nodePositionPropagate(struct bNode *node);
+/**
+ * Finds a node based on its name.
+ */
struct bNode *nodeFindNodebyName(struct bNodeTree *ntree, const char *name);
+/**
+ * Finds a node based on given socket and returns true on success.
+ */
bool nodeFindNode(struct bNodeTree *ntree,
struct bNodeSocket *sock,
struct bNode **r_node,
int *r_sockindex);
+/**
+ * \note Recursive.
+ */
struct bNode *nodeFindRootParent(bNode *node);
+/**
+ * \returns true if \a child has \a parent as a parent/grandparent/... etc.
+ * \note Recursive
+ */
bool nodeIsChildOf(const bNode *parent, const bNode *child);
+/**
+ * Iterate over a chain of nodes, starting with \a node_start, executing
+ * \a callback for each node (which can return false to end iterator).
+ *
+ * \param reversed: for backwards iteration
+ * \note Recursive
+ */
void nodeChainIter(const bNodeTree *ntree,
const bNode *node_start,
bool (*callback)(bNode *, bNode *, void *, const bool),
void *userdata,
- const bool reversed);
+ bool reversed);
+/**
+ * Iterate over a chain of nodes, starting with \a node_start, executing
+ * \a callback for each node (which can return false to end iterator).
+ *
+ * Faster than nodeChainIter. Iter only once per node.
+ * Can be called recursively (using another nodeChainIterBackwards) by
+ * setting the recursion_lvl accordingly.
+ *
+ * \note Needs updated socket links (ntreeUpdateTree).
+ * \note Recursive
+ */
void nodeChainIterBackwards(const bNodeTree *ntree,
const bNode *node_start,
bool (*callback)(bNode *, bNode *, void *),
void *userdata,
int recursion_lvl);
+/**
+ * Iterate over all parents of \a node, executing \a callback for each parent
+ * (which can return false to end iterator)
+ *
+ * \note Recursive
+ */
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata);
struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
@@ -713,30 +772,49 @@ struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
int nodeCountSocketLinks(const struct bNodeTree *ntree, const struct bNodeSocket *sock);
void nodeSetSelected(struct bNode *node, bool select);
+/**
+ * Two active flags, ID nodes have special flag for buttons display.
+ */
void nodeSetActive(struct bNodeTree *ntree, struct bNode *node);
struct bNode *nodeGetActive(struct bNodeTree *ntree);
-struct bNode *nodeGetActiveID(struct bNodeTree *ntree, short idtype);
-bool nodeSetActiveID(struct bNodeTree *ntree, short idtype, struct ID *id);
void nodeClearActive(struct bNodeTree *ntree);
-void nodeClearActiveID(struct bNodeTree *ntree, short idtype);
+/**
+ * Two active flags, ID nodes have special flag for buttons display.
+ */
struct bNode *nodeGetActiveTexture(struct bNodeTree *ntree);
-void nodeUpdate(struct bNodeTree *ntree, struct bNode *node);
-bool nodeUpdateID(struct bNodeTree *ntree, struct ID *id);
-void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node);
-
int nodeSocketIsHidden(const struct bNodeSocket *sock);
-void ntreeTagUsedSockets(struct bNodeTree *ntree);
-void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available);
+void nodeSetSocketAvailability(struct bNodeTree *ntree,
+ struct bNodeSocket *sock,
+ bool is_available);
int nodeSocketLinkLimit(const struct bNodeSocket *sock);
-void nodeDeclarationEnsure(struct bNodeTree *ntree, struct bNode *node);
+/**
+ * If the node implements a `declare` function, this function makes sure that `node->declaration`
+ * is up to date. It is expected that the sockets of the node are up to date already.
+ */
+bool nodeDeclarationEnsure(struct bNodeTree *ntree, struct bNode *node);
+/**
+ * Just update `node->declaration` if necessary. This can also be called on nodes that may not be
+ * up to date (e.g. because the need versioning or are dynamic).
+ */
+bool nodeDeclarationEnsureOnOutdatedNode(struct bNodeTree *ntree, struct bNode *node);
+/**
+ * Update `socket->declaration` for all sockets in the node. This assumes that the node declaration
+ * and sockets are up to date already.
+ */
+void nodeSocketDeclarationsUpdate(struct bNode *node);
-/* Node Clipboard */
+/**
+ * Node Clipboard.
+ */
void BKE_node_clipboard_init(const struct bNodeTree *ntree);
void BKE_node_clipboard_clear(void);
void BKE_node_clipboard_free(void);
+/**
+ * Return false when one or more ID's are lost.
+ */
bool BKE_node_clipboard_validate(void);
void BKE_node_clipboard_add_node(struct bNode *node);
void BKE_node_clipboard_add_link(struct bNodeLink *link);
@@ -744,13 +822,19 @@ const struct ListBase *BKE_node_clipboard_get_nodes(void);
const struct ListBase *BKE_node_clipboard_get_links(void);
int BKE_node_clipboard_get_type(void);
-/* Node Instance Hash */
+/**
+ * Node Instance Hash.
+ */
typedef struct bNodeInstanceHash {
- GHash *ghash; /* XXX should be made a direct member, GHash allocation needs to support it */
+ /** XXX should be made a direct member, #GHash allocation needs to support it */
+ GHash *ghash;
} bNodeInstanceHash;
typedef void (*bNodeInstanceValueFP)(void *value);
+/**
+ * Magic number for initial hash key.
+ */
extern const bNodeInstanceKey NODE_INSTANCE_KEY_BASE;
extern const bNodeInstanceKey NODE_INSTANCE_KEY_NONE;
@@ -821,40 +905,39 @@ bNodePreview *BKE_node_preview_verify(
struct bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create);
bNodePreview *BKE_node_preview_copy(struct bNodePreview *preview);
void BKE_node_preview_free(struct bNodePreview *preview);
-void BKE_node_preview_init_tree(struct bNodeTree *ntree,
- int xsize,
- int ysize,
- bool create_previews);
-void BKE_node_preview_free_tree(struct bNodeTree *ntree);
+void BKE_node_preview_init_tree(struct bNodeTree *ntree, int xsize, int ysize);
void BKE_node_preview_remove_unused(struct bNodeTree *ntree);
void BKE_node_preview_clear(struct bNodePreview *preview);
void BKE_node_preview_clear_tree(struct bNodeTree *ntree);
-void BKE_node_preview_sync_tree(struct bNodeTree *to_ntree, struct bNodeTree *from_ntree);
void BKE_node_preview_merge_tree(struct bNodeTree *to_ntree,
struct bNodeTree *from_ntree,
bool remove_old);
-void BKE_node_preview_set_pixel(
- struct bNodePreview *preview, const float col[4], int x, int y, bool do_manage);
-
/** \} */
/* -------------------------------------------------------------------- */
/** \name Node Type Access
* \{ */
-void nodeLabel(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
+void nodeLabel(const struct bNodeTree *ntree, const struct bNode *node, char *label, int maxlen);
+/**
+ * Get node socket label if it is set.
+ */
const char *nodeSocketLabel(const struct bNodeSocket *sock);
bool nodeGroupPoll(struct bNodeTree *nodetree,
struct bNodeTree *grouptree,
const char **r_disabled_hint);
-/* Init a new node type struct with default values and callbacks */
-void node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
-void node_type_base_custom(
- struct bNodeType *ntype, const char *idname, const char *name, short nclass, short flag);
+/**
+ * Initialize a new node type struct with default values and callbacks.
+ */
+void node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
+void node_type_base_custom(struct bNodeType *ntype,
+ const char *idname,
+ const char *name,
+ short nclass);
void node_type_socket_templates(struct bNodeType *ntype,
struct bNodeSocketTemplate *inputs,
struct bNodeSocketTemplate *outputs);
@@ -862,15 +945,16 @@ void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwid
void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size);
void node_type_init(struct bNodeType *ntype,
void (*initfunc)(struct bNodeTree *ntree, struct bNode *node));
+/**
+ * \warning Nodes defining a storage type _must_ allocate this for new nodes.
+ * Otherwise nodes will reload as undefined (T46619).
+ */
void node_type_storage(struct bNodeType *ntype,
const char *storagename,
void (*freefunc)(struct bNode *node),
void (*copyfunc)(struct bNodeTree *dest_ntree,
struct bNode *dest_node,
const struct bNode *src_node));
-void node_type_label(
- struct bNodeType *ntype,
- void (*labelfunc)(struct bNodeTree *ntree, struct bNode *, char *label, int maxlen));
void node_type_update(struct bNodeType *ntype,
void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node));
void node_type_group_update(struct bNodeType *ntype,
@@ -882,8 +966,6 @@ void node_type_exec(struct bNodeType *ntype,
NodeFreeExecFunction free_exec_fn,
NodeExecFunction exec_fn);
void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn);
-void node_type_internal_links(struct bNodeType *ntype,
- void (*update_internal_links)(struct bNodeTree *, struct bNode *));
/** \} */
@@ -978,26 +1060,20 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
} \
} \
((void)0)
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Node Tree
*/
-void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
- struct Scene *scene,
- const int layer_index);
+void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, int layer_index);
/* -------------------------------------------------------------------- */
/** \name Shader Nodes
* \{ */
/* NOTE: types are needed to restore callbacks, don't change values. */
-/* range 1 - 100 is reserved for common nodes */
-/* using toolbox, we add node groups by assuming the values below
- * don't exceed NODE_GROUP_MENU for now. */
-
-//#define SH_NODE_OUTPUT 1
//#define SH_NODE_MATERIAL 100
#define SH_NODE_RGB 101
@@ -1021,7 +1097,6 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
#define SH_NODE_SEPRGB 120
#define SH_NODE_COMBRGB 121
#define SH_NODE_HUE_SAT 122
-#define NODE_DYNAMIC 123
#define SH_NODE_OUTPUT_MATERIAL 124
#define SH_NODE_OUTPUT_WORLD 125
@@ -1102,19 +1177,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
#define SH_NODE_VERTEX_COLOR 706
#define SH_NODE_OUTPUT_AOV 707
#define SH_NODE_VECTOR_ROTATE 708
-
-/* custom defines options for Material node */
-// #define SH_NODE_MAT_DIFF 1
-// #define SH_NODE_MAT_SPEC 2
-// #define SH_NODE_MAT_NEG 4
-
-/* API */
-
-struct bNodeTreeExec *ntreeShaderBeginExecTree(struct bNodeTree *ntree);
-void ntreeShaderEndExecTree(struct bNodeTreeExec *exec);
-struct bNode *ntreeShaderOutputNode(struct bNodeTree *ntree, int target);
-
-void ntreeGPUMaterialNodes(struct bNodeTree *localtree, struct GPUMaterial *mat);
+#define SH_NODE_CURVE_FLOAT 709
+#define SH_NODE_POINT_INFO 710
/** \} */
@@ -1125,36 +1189,6 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree, struct GPUMaterial *mat)
/* output socket defines */
#define RRES_OUT_IMAGE 0
#define RRES_OUT_ALPHA 1
-// #define RRES_OUT_Z 2
-// #define RRES_OUT_NORMAL 3
-// #define RRES_OUT_UV 4
-// #define RRES_OUT_VEC 5
-// #define RRES_OUT_RGBA 6
-#define RRES_OUT_DIFF 7
-// #define RRES_OUT_SPEC 8
-// #define RRES_OUT_SHADOW 9
-// #define RRES_OUT_AO 10
-// #define RRES_OUT_REFLECT 11
-// #define RRES_OUT_REFRACT 12
-// #define RRES_OUT_INDIRECT 13
-// #define RRES_OUT_INDEXOB 14
-// #define RRES_OUT_INDEXMA 15
-// #define RRES_OUT_MIST 16
-// #define RRES_OUT_EMIT 17
-// #define RRES_OUT_ENV 18
-// #define RRES_OUT_DIFF_DIRECT 19
-// #define RRES_OUT_DIFF_INDIRECT 20
-// #define RRES_OUT_DIFF_COLOR 21
-// #define RRES_OUT_GLOSSY_DIRECT 22
-// #define RRES_OUT_GLOSSY_INDIRECT 23
-// #define RRES_OUT_GLOSSY_COLOR 24
-// #define RRES_OUT_TRANSM_DIRECT 25
-// #define RRES_OUT_TRANSM_INDIRECT 26
-// #define RRES_OUT_TRANSM_COLOR 27
-// #define RRES_OUT_SUBSURFACE_DIRECT 28
-// #define RRES_OUT_SUBSURFACE_INDIRECT 29
-// #define RRES_OUT_SUBSURFACE_COLOR 30
-// #define RRES_OUT_DEBUG 31
/* NOTE: types are needed to restore callbacks, don't change values. */
#define CMP_NODE_VIEWER 201
@@ -1255,6 +1289,8 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree, struct GPUMaterial *mat)
#define CMP_NODE_EXPOSURE 325
#define CMP_NODE_CRYPTOMATTE 326
#define CMP_NODE_POSTERIZE 327
+#define CMP_NODE_CONVERT_COLOR_SPACE 328
+#define CMP_NODE_SCENE_TIME 329
/* channel toggles */
#define CMP_CHAN_RGB 1
@@ -1293,61 +1329,6 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree, struct GPUMaterial *mat)
#define CMP_DEFAULT_SMAA_CONTRAST_LIMIT 0.2f
#define CMP_DEFAULT_SMAA_CORNER_ROUNDING 0.25f
-/* API */
-void ntreeCompositExecTree(struct Scene *scene,
- struct bNodeTree *ntree,
- struct RenderData *rd,
- int rendering,
- int do_previews,
- const struct ColorManagedViewSettings *view_settings,
- const struct ColorManagedDisplaySettings *display_settings,
- const char *view_name);
-void ntreeCompositTagRender(struct Scene *scene);
-void ntreeCompositUpdateRLayers(struct bNodeTree *ntree);
-void ntreeCompositRegisterPass(struct bNodeTree *ntree,
- struct Scene *scene,
- struct ViewLayer *view_layer,
- const char *name,
- eNodeSocketDatatype type);
-void ntreeCompositClearTags(struct bNodeTree *ntree);
-
-struct bNodeSocket *ntreeCompositOutputFileAddSocket(struct bNodeTree *ntree,
- struct bNode *node,
- const char *name,
- struct ImageFormatData *im_format);
-int ntreeCompositOutputFileRemoveActiveSocket(struct bNodeTree *ntree, struct bNode *node);
-void ntreeCompositOutputFileSetPath(struct bNode *node,
- struct bNodeSocket *sock,
- const char *name);
-void ntreeCompositOutputFileSetLayer(struct bNode *node,
- struct bNodeSocket *sock,
- const char *name);
-/* needed in do_versions */
-void ntreeCompositOutputFileUniquePath(struct ListBase *list,
- struct bNodeSocket *sock,
- const char defname[],
- char delim);
-void ntreeCompositOutputFileUniqueLayer(struct ListBase *list,
- struct bNodeSocket *sock,
- const char defname[],
- char delim);
-
-void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *ntree, bNode *node);
-void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *ntree, bNode *node);
-
-void ntreeCompositCryptomatteSyncFromAdd(const Scene *scene, bNode *node);
-void ntreeCompositCryptomatteSyncFromRemove(bNode *node);
-bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node);
-int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node);
-void ntreeCompositCryptomatteLayerPrefix(const Scene *scene,
- const bNode *node,
- char *r_prefix,
- size_t prefix_len);
-/* Update the runtime layer names with the cryptomatte layer names of the references
- * render layer or image. */
-void ntreeCompositCryptomatteUpdateLayerNames(const Scene *scene, bNode *node);
-struct CryptomatteSession *ntreeCompositCryptomatteSession(const Scene *scene, bNode *node);
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1384,23 +1365,6 @@ struct TexResult;
#define TEX_NODE_PROC 500
#define TEX_NODE_PROC_MAX 600
-/* API */
-void ntreeTexCheckCyclics(struct bNodeTree *ntree);
-
-struct bNodeTreeExec *ntreeTexBeginExecTree(struct bNodeTree *ntree);
-void ntreeTexEndExecTree(struct bNodeTreeExec *exec);
-int ntreeTexExecTree(struct bNodeTree *ntree,
- struct TexResult *target,
- const float co[3],
- float dxt[3],
- float dyt[3],
- int osatex,
- const short thread,
- const struct Tex *tex,
- short which_output,
- int cfra,
- int preview,
- struct MTex *mtex);
/** \} */
/* -------------------------------------------------------------------- */
@@ -1410,7 +1374,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_TRIANGULATE 1000
#define GEO_NODE_LEGACY_EDGE_SPLIT 1001
#define GEO_NODE_TRANSFORM 1002
-#define GEO_NODE_BOOLEAN 1003
+#define GEO_NODE_MESH_BOOLEAN 1003
#define GEO_NODE_LEGACY_POINT_DISTRIBUTE 1004
#define GEO_NODE_LEGACY_POINT_INSTANCE 1005
#define GEO_NODE_LEGACY_SUBDIVISION_SURFACE 1006
@@ -1433,10 +1397,10 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_COLLECTION_INFO 1023
#define GEO_NODE_IS_VIEWPORT 1024
#define GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY 1025
-#define GEO_NODE_VOLUME_TO_MESH 1026
+#define GEO_NODE_LEGACY_VOLUME_TO_MESH 1026
#define GEO_NODE_LEGACY_ATTRIBUTE_COMBINE_XYZ 1027
#define GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ 1028
-#define GEO_NODE_MESH_SUBDIVIDE 1029
+#define GEO_NODE_SUBDIVIDE_MESH 1029
#define GEO_NODE_ATTRIBUTE_REMOVE 1030
#define GEO_NODE_LEGACY_ATTRIBUTE_CONVERT 1031
#define GEO_NODE_MESH_PRIMITIVE_CUBE 1032
@@ -1454,11 +1418,11 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER 1044
#define GEO_NODE_CURVE_TO_MESH 1045
#define GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP 1046
-#define GEO_NODE_CURVE_RESAMPLE 1047
+#define GEO_NODE_RESAMPLE_CURVE 1047
#define GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_ROTATE 1048
#define GEO_NODE_LEGACY_MATERIAL_ASSIGN 1049
#define GEO_NODE_INPUT_MATERIAL 1050
-#define GEO_NODE_MATERIAL_REPLACE 1051
+#define GEO_NODE_REPLACE_MATERIAL 1051
#define GEO_NODE_LEGACY_MESH_TO_CURVE 1052
#define GEO_NODE_LEGACY_DELETE_GEOMETRY 1053
#define GEO_NODE_CURVE_LENGTH 1054
@@ -1478,32 +1442,88 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_CURVE_PRIMITIVE_LINE 1068
#define GEO_NODE_LEGACY_CURVE_ENDPOINTS 1069
#define GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL 1070
-#define GEO_NODE_CURVE_TRIM 1071
+#define GEO_NODE_TRIM_CURVE 1071
#define GEO_NODE_LEGACY_CURVE_SET_HANDLES 1072
#define GEO_NODE_LEGACY_CURVE_SPLINE_TYPE 1073
#define GEO_NODE_LEGACY_CURVE_SELECT_HANDLES 1074
-#define GEO_NODE_CURVE_FILL 1075
+#define GEO_NODE_FILL_CURVE 1075
#define GEO_NODE_INPUT_POSITION 1076
#define GEO_NODE_SET_POSITION 1077
#define GEO_NODE_INPUT_INDEX 1078
#define GEO_NODE_INPUT_NORMAL 1079
-#define GEO_NODE_ATTRIBUTE_CAPTURE 1080
+#define GEO_NODE_CAPTURE_ATTRIBUTE 1080
#define GEO_NODE_MATERIAL_SELECTION 1081
-#define GEO_NODE_MATERIAL_ASSIGN 1082
+#define GEO_NODE_SET_MATERIAL 1082
#define GEO_NODE_REALIZE_INSTANCES 1083
#define GEO_NODE_ATTRIBUTE_STATISTIC 1084
-#define GEO_NODE_CURVE_SAMPLE 1085
+#define GEO_NODE_SAMPLE_CURVE 1085
#define GEO_NODE_INPUT_TANGENT 1086
#define GEO_NODE_STRING_JOIN 1087
-#define GEO_NODE_CURVE_PARAMETER 1088
-#define GEO_NODE_CURVE_FILLET 1089
+#define GEO_NODE_CURVE_SPLINE_PARAMETER 1088
+#define GEO_NODE_FILLET_CURVE 1089
#define GEO_NODE_DISTRIBUTE_POINTS_ON_FACES 1090
#define GEO_NODE_STRING_TO_CURVES 1091
#define GEO_NODE_INSTANCE_ON_POINTS 1092
#define GEO_NODE_MESH_TO_POINTS 1093
#define GEO_NODE_POINTS_TO_VERTICES 1094
-#define GEO_NODE_CURVE_REVERSE 1095
+#define GEO_NODE_REVERSE_CURVE 1095
#define GEO_NODE_PROXIMITY 1096
+#define GEO_NODE_SUBDIVIDE_CURVE 1097
+#define GEO_NODE_INPUT_SPLINE_LENGTH 1098
+#define GEO_NODE_CURVE_SPLINE_TYPE 1099
+#define GEO_NODE_CURVE_SET_HANDLES 1100
+#define GEO_NODE_POINTS_TO_VOLUME 1101
+#define GEO_NODE_CURVE_HANDLE_TYPE_SELECTION 1102
+#define GEO_NODE_DELETE_GEOMETRY 1103
+#define GEO_NODE_SEPARATE_GEOMETRY 1104
+#define GEO_NODE_INPUT_RADIUS 1105
+#define GEO_NODE_INPUT_CURVE_TILT 1106
+#define GEO_NODE_INPUT_CURVE_HANDLES 1107
+#define GEO_NODE_INPUT_SHADE_SMOOTH 1108
+#define GEO_NODE_INPUT_SPLINE_RESOLUTION 1109
+#define GEO_NODE_INPUT_SPLINE_CYCLIC 1110
+#define GEO_NODE_SET_CURVE_RADIUS 1111
+#define GEO_NODE_SET_CURVE_TILT 1112
+#define GEO_NODE_SET_CURVE_HANDLES 1113
+#define GEO_NODE_SET_SHADE_SMOOTH 1114
+#define GEO_NODE_SET_SPLINE_RESOLUTION 1115
+#define GEO_NODE_SET_SPLINE_CYCLIC 1116
+#define GEO_NODE_SET_POINT_RADIUS 1117
+#define GEO_NODE_INPUT_MATERIAL_INDEX 1118
+#define GEO_NODE_SET_MATERIAL_INDEX 1119
+#define GEO_NODE_TRANSLATE_INSTANCES 1120
+#define GEO_NODE_SCALE_INSTANCES 1121
+#define GEO_NODE_ROTATE_INSTANCES 1122
+#define GEO_NODE_SPLIT_EDGES 1123
+#define GEO_NODE_MESH_TO_CURVE 1124
+#define GEO_NODE_TRANSFER_ATTRIBUTE 1125
+#define GEO_NODE_SUBDIVISION_SURFACE 1126
+#define GEO_NODE_CURVE_ENDPOINT_SELECTION 1127
+#define GEO_NODE_RAYCAST 1128
+#define GEO_NODE_CURVE_TO_POINTS 1130
+#define GEO_NODE_INSTANCES_TO_POINTS 1131
+#define GEO_NODE_IMAGE_TEXTURE 1132
+#define GEO_NODE_VOLUME_TO_MESH 1133
+#define GEO_NODE_INPUT_ID 1134
+#define GEO_NODE_SET_ID 1135
+#define GEO_NODE_ATTRIBUTE_DOMAIN_SIZE 1136
+#define GEO_NODE_DUAL_MESH 1137
+#define GEO_NODE_INPUT_MESH_EDGE_VERTICES 1138
+#define GEO_NODE_INPUT_MESH_FACE_AREA 1139
+#define GEO_NODE_INPUT_MESH_FACE_NEIGHBORS 1140
+#define GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS 1141
+#define GEO_NODE_GEOMETRY_TO_INSTANCE 1142
+#define GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS 1143
+#define GEO_NODE_INPUT_MESH_ISLAND 1144
+#define GEO_NODE_INPUT_SCENE_TIME 1145
+#define GEO_NODE_ACCUMULATE_FIELD 1146
+#define GEO_NODE_INPUT_MESH_EDGE_ANGLE 1147
+#define GEO_NODE_FIELD_AT_INDEX 1148
+#define GEO_NODE_CURVE_PRIMITIVE_ARC 1149
+#define GEO_NODE_FLIP_FACES 1150
+#define GEO_NODE_SCALE_ELEMENTS 1151
+#define GEO_NODE_EXTRUDE_MESH 1152
+#define GEO_NODE_MERGE_BY_DISTANCE 1153
/** \} */
@@ -1512,34 +1532,53 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
* \{ */
#define FN_NODE_BOOLEAN_MATH 1200
-#define FN_NODE_FLOAT_COMPARE 1202
+#define FN_NODE_COMPARE 1202
#define FN_NODE_LEGACY_RANDOM_FLOAT 1206
#define FN_NODE_INPUT_VECTOR 1207
#define FN_NODE_INPUT_STRING 1208
#define FN_NODE_FLOAT_TO_INT 1209
#define FN_NODE_VALUE_TO_STRING 1210
#define FN_NODE_STRING_LENGTH 1211
-#define FN_NODE_STRING_SUBSTRING 1212
+#define FN_NODE_SLICE_STRING 1212
#define FN_NODE_INPUT_SPECIAL_CHARACTERS 1213
#define FN_NODE_RANDOM_VALUE 1214
+#define FN_NODE_ROTATE_EULER 1215
+#define FN_NODE_ALIGN_EULER_TO_VECTOR 1216
+#define FN_NODE_INPUT_COLOR 1217
+#define FN_NODE_REPLACE_STRING 1218
+#define FN_NODE_INPUT_BOOL 1219
+#define FN_NODE_INPUT_INT 1220
/** \} */
void BKE_node_system_init(void);
void BKE_node_system_exit(void);
-/* -------------------------------------------------------------------- */
-/* evaluation support, */
-
-struct Depsgraph;
-
-void BKE_nodetree_shading_params_eval(struct Depsgraph *depsgraph,
- struct bNodeTree *ntree_dst,
- const struct bNodeTree *ntree_src);
-
extern struct bNodeType NodeTypeUndefined;
extern struct bNodeSocketType NodeSocketTypeUndefined;
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+
+namespace blender::bke {
+
+bNodeSocket *node_find_enabled_socket(bNode &node, eNodeSocketInOut in_out, StringRef name);
+bNodeSocket *node_find_enabled_input_socket(bNode &node, StringRef name);
+bNodeSocket *node_find_enabled_output_socket(bNode &node, StringRef name);
+
+} // namespace blender::bke
+
+#endif
+
+#define NODE_STORAGE_FUNCS(StorageT) \
+ [[maybe_unused]] static StorageT &node_storage(bNode &node) \
+ { \
+ return *static_cast<StorageT *>(node.storage); \
+ } \
+ [[maybe_unused]] static const StorageT &node_storage(const bNode &node) \
+ { \
+ return *static_cast<const StorageT *>(node.storage); \
+ }
diff --git a/source/blender/blenkernel/BKE_node_tree_update.h b/source/blender/blenkernel/BKE_node_tree_update.h
new file mode 100644
index 00000000000..443ceafb073
--- /dev/null
+++ b/source/blender/blenkernel/BKE_node_tree_update.h
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+struct ID;
+struct Main;
+struct bNode;
+struct bNodeLink;
+struct bNodeSocket;
+struct bNodeTree;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Tag tree as changed without providing any more information about what has changed exactly.
+ * The update process has to assume that everything may have changed.
+ *
+ * Using one of the methods below to tag the tree after changes is preferred when possible.
+ */
+void BKE_ntree_update_tag_all(struct bNodeTree *ntree);
+
+/**
+ * More specialized tag functions that may result in a more efficient update.
+ */
+
+void BKE_ntree_update_tag_node_property(struct bNodeTree *ntree, struct bNode *node);
+void BKE_ntree_update_tag_node_new(struct bNodeTree *ntree, struct bNode *node);
+void BKE_ntree_update_tag_node_removed(struct bNodeTree *ntree);
+void BKE_ntree_update_tag_node_mute(struct bNodeTree *ntree, struct bNode *node);
+void BKE_ntree_update_tag_node_internal_link(struct bNodeTree *ntree, struct bNode *node);
+
+void BKE_ntree_update_tag_socket_property(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_new(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_type(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_availability(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_removed(struct bNodeTree *ntree);
+
+void BKE_ntree_update_tag_link_changed(struct bNodeTree *ntree);
+void BKE_ntree_update_tag_link_removed(struct bNodeTree *ntree);
+void BKE_ntree_update_tag_link_added(struct bNodeTree *ntree, struct bNodeLink *link);
+void BKE_ntree_update_tag_link_mute(struct bNodeTree *ntree, struct bNodeLink *link);
+
+/** Used after file loading when run-time data on the tree has not been initialized yet. */
+void BKE_ntree_update_tag_missing_runtime_data(struct bNodeTree *ntree);
+/** Used when the interface sockets/values have changed. */
+void BKE_ntree_update_tag_interface(struct bNodeTree *ntree);
+/** Used when an id data block changed that might be used by nodes that need to be updated. */
+void BKE_ntree_update_tag_id_changed(struct Main *bmain, struct ID *id);
+
+typedef struct NodeTreeUpdateExtraParams {
+ /**
+ * Data passed into the callbacks.
+ */
+ void *user_data;
+
+ /**
+ * Called for every tree that has been changed during the update. This can be used to send
+ * notifiers to trigger redraws or depsgraph updates.
+ */
+ void (*tree_changed_fn)(struct ID *, struct bNodeTree *, void *user_data);
+
+ /**
+ * Called for every tree whose output value may have changed based on the provided update tags.
+ * This can be used to tag the depsgraph if necessary.
+ */
+ void (*tree_output_changed_fn)(struct ID *, struct bNodeTree *, void *user_data);
+} NodeTreeUpdateExtraParams;
+
+/**
+ * Updates #bmain based on changes to node trees.
+ */
+void BKE_ntree_update_main(struct Main *bmain, struct NodeTreeUpdateExtraParams *params);
+
+/**
+ * Same as #BKE_ntree_update_main, but will first only look at the provided tree and only looks
+ * at #bmain when something relevant for other data-blocks changed. This avoids scanning #bmain in
+ * many cases.
+ *
+ * If #bmain is null, only the provided tree is updated. This should only be used in very rare
+ * cases because it may result it incorrectly synced data in DNA.
+ *
+ * If #tree is null, this is the same as calling #BKE_ntree_update_main.
+ */
+void BKE_ntree_update_main_tree(struct Main *bmain,
+ struct bNodeTree *ntree,
+ struct NodeTreeUpdateExtraParams *params);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 0e153c5a82a..99758f4ad78 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -48,25 +48,35 @@ struct RegionView3D;
struct RigidBodyWorld;
struct Scene;
struct ShaderFxData;
+struct SubsurfModifierData;
struct View3D;
struct ViewLayer;
void BKE_object_workob_clear(struct Object *workob);
+/**
+ * For calculation of the inverse parent transform, only used for editor.
+ *
+ * It assumes the object parent is already in the depsgraph.
+ * Otherwise, after changing ob->parent you need to call:
+ * - #DEG_relations_tag_update(bmain);
+ * - #BKE_scene_graph_update_tagged(depsgraph, bmain);
+ */
void BKE_object_workob_calc_parent(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct Object *workob);
void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src);
-void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag);
-struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys, const int flag);
-void BKE_object_copy_particlesystems(struct Object *ob_dst,
- const struct Object *ob_src,
- const int flag);
+void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, int flag);
+struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys, int flag);
+void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src, int flag);
void BKE_object_free_particlesystems(struct Object *ob);
void BKE_object_free_softbody(struct Object *ob);
void BKE_object_free_curve_cache(struct Object *ob);
+/**
+ * Free data derived from mesh, called when mesh changes or is freed.
+ */
void BKE_object_free_derived_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
@@ -75,29 +85,71 @@ void BKE_object_modifier_gpencil_hook_reset(struct Object *ob,
struct HookGpencilModifierData *hmd);
bool BKE_object_modifier_gpencil_use_time(struct Object *ob, struct GpencilModifierData *md);
-bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *md);
+bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *fx);
+/**
+ * \return True if the object's type supports regular modifiers (not grease pencil modifiers).
+ */
bool BKE_object_supports_modifiers(const struct Object *ob);
bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type);
/* Active modifier. */
+
+/**
+ * Set the object's active modifier.
+ *
+ * \param md: If nullptr, only clear the active modifier, otherwise
+ * it must be in the #Object.modifiers list.
+ */
void BKE_object_modifier_set_active(struct Object *ob, struct ModifierData *md);
struct ModifierData *BKE_object_active_modifier(const struct Object *ob);
+/**
+ * Copy a single modifier.
+ *
+ * \note *Do not* use this function to copy a whole modifier stack (see note below too). Use
+ * `BKE_object_modifier_stack_copy` instead.
+ *
+ * \note Complex modifiers relaying on other data (like e.g. dynamic paint or fluid using particle
+ * systems) are not always 100% 'correctly' copied here, since we have to use heuristics to decide
+ * which particle system to use or add in `ob_dst`, and it's placement in the stack, etc. If used
+ * more than once, this function should preferably be called in stack order.
+ */
bool BKE_object_copy_modifier(struct Main *bmain,
struct Scene *scene,
struct Object *ob_dst,
const struct Object *ob_src,
struct ModifierData *md);
-bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, struct GpencilModifierData *md);
+/**
+ * Copy a single GPencil modifier.
+ *
+ * \note *Do not* use this function to copy a whole modifier stack. Use
+ * `BKE_object_modifier_stack_copy` instead.
+ */
+bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, struct GpencilModifierData *gmd_src);
+/**
+ * Copy the whole stack of modifiers from one object into another.
+ *
+ * \warning *Does not* clear modifier stack and related data (particle systems, soft-body,
+ * etc.) in `ob_dst`, if needed calling code must do it.
+ *
+ * \param do_copy_all: If true, even modifiers that should not support copying (like Hook one)
+ * will be duplicated.
+ */
bool BKE_object_modifier_stack_copy(struct Object *ob_dst,
const struct Object *ob_src,
- const bool do_copy_all,
- const int flag_subdata);
+ bool do_copy_all,
+ int flag_subdata);
void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src);
-void BKE_object_free_modifiers(struct Object *ob, const int flag);
-void BKE_object_free_shaderfx(struct Object *ob, const int flag);
-
+void BKE_object_free_modifiers(struct Object *ob, int flag);
+void BKE_object_free_shaderfx(struct Object *ob, int flag);
+
+/**
+ * Proxy rule:
+ * - `lib_object->proxy_from` == the one we borrow from, set temporally while object_update.
+ * - `local_object->proxy` == pointer to library object, saved in files and read.
+ * - `local_object->proxy_group` == pointer to collection dupli-object, saved in files and read.
+ */
void BKE_object_make_proxy(struct Main *bmain,
struct Object *ob,
struct Object *target,
@@ -105,6 +157,9 @@ void BKE_object_make_proxy(struct Main *bmain,
void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target);
bool BKE_object_exists_check(struct Main *bmain, const struct Object *obtest);
+/**
+ * Actual check for internal data, not context or flags.
+ */
bool BKE_object_is_in_editmode(const struct Object *ob);
bool BKE_object_is_in_editmode_vgroup(const struct Object *ob);
bool BKE_object_is_in_wpaint_select_vert(const struct Object *ob);
@@ -115,6 +170,9 @@ bool BKE_object_data_is_in_editmode(const struct ID *id);
char *BKE_object_data_editmode_flush_ptr_get(struct ID *id);
+/**
+ * Updates select_id of all objects in the given \a bmain.
+ */
void BKE_object_update_select_id(struct Main *bmain);
typedef enum eObjectVisibilityResult {
@@ -124,14 +182,33 @@ typedef enum eObjectVisibilityResult {
OB_VISIBLE_ALL = (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES | OB_VISIBLE_INSTANCES),
} eObjectVisibilityResult;
-int BKE_object_visibility(const struct Object *ob, const int dag_eval_mode);
+/**
+ * Return which parts of the object are visible, as evaluated by depsgraph.
+ */
+int BKE_object_visibility(const struct Object *ob, int dag_eval_mode);
+/**
+ * More general add: creates minimum required data, but without vertices etc.
+ */
struct Object *BKE_object_add_only_object(struct Main *bmain, int type, const char *name)
ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
+/**
+ * General add: to scene, with layer from area and default name.
+ *
+ * Object is added to the active #Collection.
+ * If there is no linked collection to the active #ViewLayer we create a new one.
+ *
+ * \note Creates minimum required data, but without vertices etc.
+ */
struct Object *BKE_object_add(struct Main *bmain,
struct ViewLayer *view_layer,
int type,
const char *name) ATTR_NONNULL(1, 2) ATTR_RETURNS_NONNULL;
+/**
+ * Add a new object, using another one as a reference
+ *
+ * \param ob_src: object to use to determine the collections of the new object.
+ */
struct Object *BKE_object_add_from(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
@@ -139,6 +216,15 @@ struct Object *BKE_object_add_from(struct Main *bmain,
const char *name,
struct Object *ob_src)
ATTR_NONNULL(1, 2, 3, 6) ATTR_RETURNS_NONNULL;
+/**
+ * Add a new object, but assign the given data-block as the `ob->data`
+ * for the newly created object.
+ *
+ * \param data: The data-block to assign as `ob->data` for the new object.
+ * This is assumed to be of the correct type.
+ * \param do_id_user: If true, #id_us_plus() will be called on data when
+ * assigning it to the object.
+ */
struct Object *BKE_object_add_for_data(struct Main *bmain,
struct ViewLayer *view_layer,
int type,
@@ -147,32 +233,66 @@ struct Object *BKE_object_add_for_data(struct Main *bmain,
bool do_id_user) ATTR_RETURNS_NONNULL;
void *BKE_object_obdata_add_from_type(struct Main *bmain, int type, const char *name)
ATTR_NONNULL(1);
+/**
+ * Return -1 on failure.
+ */
int BKE_object_obdata_to_type(const struct ID *id) ATTR_NONNULL(1);
+/**
+ * Returns true if the Object is from an external blend file (libdata).
+ */
bool BKE_object_is_libdata(const struct Object *ob);
+/**
+ * Returns true if the Object data is from an external blend file (libdata).
+ */
bool BKE_object_obdata_is_libdata(const struct Object *ob);
+/**
+ * Perform deep-copy of object and its 'children' data-blocks (obdata, materials, actions, etc.).
+ *
+ * \param dupflag: Controls which sub-data are also duplicated
+ * (see #eDupli_ID_Flags in DNA_userdef_types.h).
+ *
+ * \note This function does not do any remapping to new IDs, caller must do it
+ * (\a #BKE_libblock_relink_to_newid()).
+ * \note Caller MUST free \a newid pointers itself (#BKE_main_id_newptr_and_tag_clear()) and call
+ * updates of DEG too (#DAG_relations_tag_update()).
+ */
struct Object *BKE_object_duplicate(struct Main *bmain,
struct Object *ob,
uint dupflag,
- const uint duplicate_options);
+ uint duplicate_options);
-void BKE_object_obdata_size_init(struct Object *ob, const float size);
+/**
+ * Use with newly created objects to set their size (used to apply scene-scale).
+ */
+void BKE_object_obdata_size_init(struct Object *ob, float size);
void BKE_object_scale_to_mat3(struct Object *ob, float r_mat[3][3]);
void BKE_object_rot_to_mat3(const struct Object *ob, float r_mat[3][3], bool use_drot);
void BKE_object_mat3_to_rot(struct Object *ob, float r_mat[3][3], bool use_compat);
void BKE_object_to_mat3(struct Object *ob, float r_mat[3][3]);
void BKE_object_to_mat4(struct Object *ob, float r_mat[4][4]);
-void BKE_object_apply_mat4(struct Object *ob,
- const float mat[4][4],
- const bool use_compat,
- const bool use_parent);
+/**
+ * Applies the global transformation \a mat to the \a ob using a relative parent space if
+ * supplied.
+ *
+ * \param mat: the global transformation mat that the object should be set object to.
+ * \param parent: the parent space in which this object will be set relative to
+ * (should probably always be parent_eval).
+ * \param use_compat: true to ensure that rotations are set using the
+ * min difference between the old and new orientation.
+ */
void BKE_object_apply_mat4_ex(struct Object *ob,
const float mat[4][4],
struct Object *parent,
const float parentinv[4][4],
- const bool use_compat);
+ bool use_compat);
+/** See #BKE_object_apply_mat4_ex */
+void BKE_object_apply_mat4(struct Object *ob,
+ const float mat[4][4],
+ bool use_compat,
+ bool use_parent);
void BKE_object_matrix_local_get(struct Object *ob, float r_mat[4][4]);
bool BKE_object_pose_context_check(const struct Object *ob);
@@ -181,6 +301,9 @@ struct Object *BKE_object_pose_armature_get_visible(struct Object *ob,
struct ViewLayer *view_layer,
struct View3D *v3d);
+/**
+ * Access pose array with special check to get pose object when in weight paint mode.
+ */
struct Object **BKE_object_pose_array_get_ex(struct ViewLayer *view_layer,
struct View3D *v3d,
unsigned int *r_objects_len,
@@ -205,7 +328,9 @@ struct Base **BKE_object_pose_base_array_get(struct ViewLayer *view_layer,
void BKE_object_get_parent_matrix(struct Object *ob, struct Object *par, float r_parentmat[4][4]);
-/* Compute object world transform and store it in ob->obmat. */
+/**
+ * Compute object world transform and store it in `ob->obmat`.
+ */
void BKE_object_where_is_calc(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
void BKE_object_where_is_calc_ex(struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -216,9 +341,16 @@ void BKE_object_where_is_calc_time(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
float ctime);
+/**
+ * Calculate object transformation matrix without recalculating dependencies and
+ * constraints -- assume dependencies are already solved by depsgraph.
+ * No changes to object and its parent would be done.
+ * Used for bundles orientation in 3d space relative to parented blender camera.
+ */
void BKE_object_where_is_calc_mat4(struct Object *ob, float r_obmat[4][4]);
/* Possibly belong in own module? */
+
struct BoundBox *BKE_boundbox_alloc_unit(void);
void BKE_boundbox_init_from_minmax(struct BoundBox *bb, const float min[3], const float max[3]);
void BKE_boundbox_calc_center_aabb(const struct BoundBox *bb, float r_cent[3]);
@@ -230,6 +362,14 @@ void BKE_boundbox_minmax(const struct BoundBox *bb,
struct BoundBox *BKE_object_boundbox_get(struct Object *ob);
void BKE_object_dimensions_get(struct Object *ob, float r_vec[3]);
+/**
+ * The original scale and object matrix can be passed in so any difference
+ * of the objects matrix and the final matrix can be accounted for,
+ * typically this caused by parenting, constraints or delta-scale.
+ *
+ * Re-using these values from the object causes a feedback loop
+ * when multiple values are modified at once in some situations. see: T69536.
+ */
void BKE_object_dimensions_set_ex(struct Object *ob,
const float value[3],
int axis_mask,
@@ -237,18 +377,24 @@ void BKE_object_dimensions_set_ex(struct Object *ob,
const float ob_obmat_orig[4][4]);
void BKE_object_dimensions_set(struct Object *ob, const float value[3], int axis_mask);
-void BKE_object_empty_draw_type_set(struct Object *ob, const int value);
-void BKE_object_boundbox_flag(struct Object *ob, int flag, const bool set);
+void BKE_object_empty_draw_type_set(struct Object *ob, int value);
+/**
+ * Use this to temporally disable/enable bound-box.
+ */
+void BKE_object_boundbox_flag(struct Object *ob, int flag, bool set);
void BKE_object_boundbox_calc_from_mesh(struct Object *ob, const struct Mesh *me_eval);
-void BKE_object_minmax(struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
+bool BKE_object_boundbox_calc_from_evaluated_geometry(struct Object *ob);
+void BKE_object_minmax(struct Object *ob, float r_min[3], float r_max[3], bool use_hidden);
bool BKE_object_minmax_dupli(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
float r_min[3],
float r_max[3],
- const bool use_hidden);
+ bool use_hidden);
-/* sometimes min-max isn't enough, we need to loop over each point */
+/**
+ * Sometimes min-max isn't enough, we need to loop over each point.
+ */
void BKE_object_foreach_display_point(struct Object *ob,
const float obmat[4][4],
void (*func_cb)(const float[3], void *),
@@ -275,13 +421,22 @@ void BKE_object_tfm_protected_backup(const struct Object *ob, ObjectTfmProtected
void BKE_object_tfm_protected_restore(struct Object *ob,
const ObjectTfmProtectedChannels *obtfm,
- const short protectflag);
+ short protectflag);
void BKE_object_tfm_copy(struct Object *object_dst, const struct Object *object_src);
+/**
+ * Restore the object->data to a non-modifier evaluated state.
+ *
+ * Some changes done directly in evaluated object require them to be reset
+ * before being re-evaluated.
+ * For example, we need to call this before #BKE_mesh_new_from_object(),
+ * in case we removed/added modifiers in the evaluated object.
+ */
void BKE_object_eval_reset(struct Object *ob_eval);
/* Dependency graph evaluation callbacks. */
+
void BKE_object_eval_local_transform(struct Depsgraph *depsgraph, struct Object *ob);
void BKE_object_eval_parent(struct Depsgraph *depsgraph, struct Object *ob);
void BKE_object_eval_constraints(struct Depsgraph *depsgraph,
@@ -294,6 +449,9 @@ void BKE_object_eval_uber_transform(struct Depsgraph *depsgraph, struct Object *
void BKE_object_eval_uber_data(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/**
+ * Assign #Object.data after modifier stack evaluation.
+ */
void BKE_object_eval_assign_data(struct Object *object, struct ID *data, bool is_owned);
void BKE_object_sync_to_original(struct Depsgraph *depsgraph, struct Object *object);
@@ -311,35 +469,74 @@ void BKE_object_select_update(struct Depsgraph *depsgraph, struct Object *object
void BKE_object_eval_eval_base_flags(struct Depsgraph *depsgraph,
struct Scene *scene,
- const int view_layer_index,
+ int view_layer_index,
struct Object *object,
int base_index,
- const bool is_from_set);
+ bool is_from_set);
void BKE_object_handle_data_update(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/**
+ * \warning "scene" here may not be the scene object actually resides in.
+ * When dealing with background-sets, "scene" is actually the active scene.
+ * e.g. "scene" <-- set 1 <-- set 2 ("ob" lives here) <-- set 3 <-- ... <-- set n
+ * rigid bodies depend on their world so use #BKE_object_handle_update_ex()
+ * to also pass along the current rigid body world.
+ */
void BKE_object_handle_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
+/**
+ * Proxy rule:
+ * - lib_object->proxy_from == the one we borrow from, only set temporal and cleared here.
+ * - local_object->proxy == pointer to library object, saved in files and read.
+ *
+ * Function below is polluted with proxy exceptions, cleanup will follow!
+ *
+ * The main object update call, for object matrix, constraints, keys and #DispList (modifiers)
+ * requires flags to be set!
+ *
+ * Ideally we shouldn't have to pass the rigid body world,
+ * but need bigger restructuring to avoid id.
+ */
void BKE_object_handle_update_ex(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct RigidBodyWorld *rbw,
- const bool do_proxy_update);
+ bool do_proxy_update);
void BKE_object_sculpt_data_create(struct Object *ob);
bool BKE_object_obdata_texspace_get(struct Object *ob,
- short **r_texflag,
+ char **r_texflag,
float **r_loc,
float **r_size);
+struct Mesh *BKE_object_get_evaluated_mesh_no_subsurf(const struct Object *object);
+/** Get evaluated mesh for given object. */
struct Mesh *BKE_object_get_evaluated_mesh(const struct Object *object);
+/**
+ * Get mesh which is not affected by modifiers:
+ * - For original objects it will be same as `object->data`, and it is a mesh
+ * which is in the corresponding #Main.
+ * - For copied-on-write objects it will give pointer to a copied-on-write
+ * mesh which corresponds to original object's mesh.
+ */
struct Mesh *BKE_object_get_pre_modified_mesh(const struct Object *object);
+/**
+ * Get a mesh which corresponds to the very original mesh from #Main.
+ * - For original objects it will be object->data.
+ * - For evaluated objects it will be same mesh as corresponding original
+ * object uses as data.
+ */
struct Mesh *BKE_object_get_original_mesh(const struct Object *object);
+struct Mesh *BKE_object_get_editmesh_eval_final(const struct Object *object);
+struct Mesh *BKE_object_get_editmesh_eval_cage(const struct Object *object);
+
/* Lattice accessors.
* These functions return either the regular lattice, or the edit-mode lattice,
* whichever is currently in use. */
+
struct Lattice *BKE_object_get_lattice(const struct Object *object);
struct Lattice *BKE_object_get_evaluated_lattice(const struct Object *object);
@@ -348,7 +545,7 @@ void BKE_object_delete_ptcache(struct Object *ob, int index);
struct KeyBlock *BKE_object_shapekey_insert(struct Main *bmain,
struct Object *ob,
const char *name,
- const bool from_mix);
+ bool from_mix);
bool BKE_object_shapekey_remove(struct Main *bmain, struct Object *ob, struct KeyBlock *kb);
bool BKE_object_shapekey_free(struct Main *bmain, struct Object *ob);
@@ -356,12 +553,38 @@ bool BKE_object_flag_test_recursive(const struct Object *ob, short flag);
bool BKE_object_is_child_recursive(const struct Object *ob_parent, const struct Object *ob_child);
-/* return ModifierMode flag */
+/**
+ * Most important if this is modified it should _always_ return true, in certain
+ * cases false positives are hard to avoid (shape keys for example).
+ *
+ * \return #ModifierMode flag.
+ */
int BKE_object_is_modified(struct Scene *scene, struct Object *ob);
+/**
+ * Test if object is affected by deforming modifiers (for motion blur). again
+ * most important is to avoid false positives, this is to skip computations
+ * and we can still if there was actual deformation afterwards.
+ */
int BKE_object_is_deform_modified(struct Scene *scene, struct Object *ob);
+/**
+ * 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 high.
+ *
+ * \note This function does not consider physics systems.
+ */
bool BKE_object_moves_in_time(const struct Object *object, bool recurse_parent);
+/** Return the number of scenes using (instantiating) that object in their collections. */
int BKE_object_scenes_users_get(struct Main *bmain, struct Object *ob);
struct MovieClip *BKE_object_movieclip_get(struct Scene *scene,
@@ -369,7 +592,16 @@ struct MovieClip *BKE_object_movieclip_get(struct Scene *scene,
bool use_default);
void BKE_object_runtime_reset(struct Object *object);
-void BKE_object_runtime_reset_on_copy(struct Object *object, const int flag);
+/**
+ * Reset all pointers which we don't want to be shared when copying the object.
+ */
+void BKE_object_runtime_reset_on_copy(struct Object *object, int flag);
+/**
+ * The function frees memory used by the runtime data, but not the runtime field itself.
+ *
+ * All runtime data is cleared to ensure it's not used again,
+ * in keeping with other `_free_data(..)` functions.
+ */
void BKE_object_runtime_free_data(struct Object *object);
void BKE_object_batch_cache_dirty_tag(struct Object *ob);
@@ -393,12 +625,31 @@ typedef enum eObjectSet {
OB_SET_ALL, /* All Objects. */
} eObjectSet;
+/**
+ * Iterates over all objects of the given scene layer.
+ * Depending on the #eObjectSet flag:
+ * collect either #OB_SET_ALL, #OB_SET_VISIBLE or #OB_SET_SELECTED objects.
+ * If #OB_SET_VISIBLE or#OB_SET_SELECTED are collected,
+ * then also add related objects according to the given \a includeFilter.
+ */
struct LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer,
eObjectSet objectSet,
eObRelationTypes includeFilter);
+/**
+ * \return All groups this object is a part of, caller must free.
+ */
struct LinkNode *BKE_object_groups(struct Main *bmain, struct Scene *scene, struct Object *ob);
void BKE_object_groups_clear(struct Main *bmain, struct Scene *scene, struct Object *object);
+/**
+ * Return a KDTree_3d from the deformed object (in world-space).
+ *
+ * \note Only mesh objects currently support deforming, others are TODO.
+ *
+ * \param ob:
+ * \param r_tot:
+ * \return The KD-tree or nullptr if it can't be created.
+ */
struct KDTree_3d *BKE_object_as_kdtree(struct Object *ob, int *r_tot);
bool BKE_object_modifier_use_time(struct Scene *scene,
@@ -406,6 +657,10 @@ bool BKE_object_modifier_use_time(struct Scene *scene,
struct ModifierData *md,
int dag_eval_mode);
+/**
+ * \note this function should eventually be replaced by depsgraph functionality.
+ * Avoid calling this in new code unless there is a very good reason for it!
+ */
bool BKE_object_modifier_update_subframe(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -419,7 +674,8 @@ bool BKE_object_empty_image_frame_is_visible_in_view3d(const struct Object *ob,
bool BKE_object_empty_image_data_is_visible_in_view3d(const struct Object *ob,
const struct RegionView3D *rv3d);
-/* This is an utility function for Python's object.to_mesh() (the naming is not very clear though).
+/**
+ * This is an utility function for Python's object.to_mesh() (the naming is not very clear though).
* The result is owned by the object.
*
* The mesh will be freed when object is re-evaluated or is destroyed. It is possible to force to
@@ -436,11 +692,12 @@ struct Mesh *BKE_object_to_mesh(struct Depsgraph *depsgraph,
void BKE_object_to_mesh_clear(struct Object *object);
-/* This is an utility function for Python's object.to_curve().
+/**
+ * This is an utility function for Python's `object.to_curve()`.
* The result is owned by the object.
*
* The curve will be freed when object is re-evaluated or is destroyed. It is possible to force
- * clear memory used by this curve by calling BKE_object_to_curve_clear().
+ * clear memory used by this curve by calling #BKE_object_to_curve_clear().
*
* If apply_modifiers is true and the object is a curve one, then spline deform modifiers are
* applied on the curve control points.
@@ -458,6 +715,15 @@ void BKE_object_modifiers_lib_link_common(void *userData,
struct ID **idpoin,
int cb_flag);
+/**
+ * Return the last subsurf modifier of an object, this does not check whether modifiers on top of
+ * it are disabled. Return NULL if no such modifier is found.
+ *
+ * This does not check if the modifier is enabled as it is assumed that the caller verified that it
+ * is enabled for its evaluation mode.
+ */
+struct SubsurfModifierData *BKE_object_get_last_subsurf_modifier(const struct Object *ob);
+
void BKE_object_replace_data_on_shallow_copy(struct Object *ob, struct ID *new_data);
struct PartEff;
diff --git a/source/blender/blenkernel/BKE_object_deform.h b/source/blender/blenkernel/BKE_object_deform.h
index a10158254c2..fe7a9ddc633 100644
--- a/source/blender/blenkernel/BKE_object_deform.h
+++ b/source/blender/blenkernel/BKE_object_deform.h
@@ -31,24 +31,71 @@ struct MDeformVert;
struct Object;
struct bDeformGroup;
-/* General vgroup operations */
+/* General vgroup operations. */
+
+/**
+ * Update users of vgroups from this object, according to given map.
+ *
+ * Use it when you remove or reorder vgroups in the object.
+ *
+ * \param map: an array mapping old indices to new indices.
+ */
void BKE_object_defgroup_remap_update_users(struct Object *ob, const int *map);
+/**
+ * Get #MDeformVert vgroup data from given object. Should only be used in Object mode.
+ *
+ * \return True if the id type supports weights.
+ */
bool BKE_object_defgroup_array_get(struct ID *id, struct MDeformVert **dvert_arr, int *dvert_tot);
+/**
+ * Add a vgroup of default name to object. *Does not* handle #MDeformVert data at all!
+ */
struct bDeformGroup *BKE_object_defgroup_add(struct Object *ob);
+/**
+ * Add a vgroup of given name to object. *Does not* handle #MDeformVert data at all!
+ */
struct bDeformGroup *BKE_object_defgroup_add_name(struct Object *ob, const char *name);
+/**
+ * Create #MDeformVert data for given ID. Work in Object mode only.
+ */
struct MDeformVert *BKE_object_defgroup_data_create(struct ID *id);
-bool BKE_object_defgroup_clear(struct Object *ob,
- struct bDeformGroup *dg,
- const bool use_selection);
-bool BKE_object_defgroup_clear_all(struct Object *ob, const bool use_selection);
+/**
+ * Remove all verts (or only selected ones) from given vgroup. Work in Object and Edit modes.
+ *
+ * \param use_selection: Only operate on selection.
+ * \return True if any vertex was removed, false otherwise.
+ */
+bool BKE_object_defgroup_clear(struct Object *ob, struct bDeformGroup *dg, bool use_selection);
+/**
+ * Remove all verts (or only selected ones) from all vgroups. Work in Object and Edit modes.
+ *
+ * \param use_selection: Only operate on selection.
+ * \return True if any vertex was removed, false otherwise.
+ */
+bool BKE_object_defgroup_clear_all(struct Object *ob, bool use_selection);
+/**
+ * Remove given vgroup from object. Work in Object and Edit modes.
+ */
void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
+/**
+ * Remove all vgroups from object. Work in Object and Edit modes.
+ * When only_unlocked=true, locked vertex groups are not removed.
+ */
void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked);
+/**
+ * Remove all vgroups from object. Work in Object and Edit modes.
+ */
void BKE_object_defgroup_remove_all(struct Object *ob);
+/**
+ * Compute mapping for vertex groups with matching name, -1 is used for no remapping.
+ * Returns null if no remapping is required.
+ * The returned array has to be freed.
+ */
int *BKE_object_defgroup_index_map_create(struct Object *ob_src,
struct Object *ob_dst,
int *r_map_len);
@@ -57,34 +104,69 @@ void BKE_object_defgroup_index_map_apply(struct MDeformVert *dvert,
const int *map,
int map_len);
-/* Select helpers */
+/* Select helpers. */
+
enum eVGroupSelect;
+/**
+ * Return the subset type of the Vertex Group Selection.
+ */
bool *BKE_object_defgroup_subset_from_select_type(struct Object *ob,
enum eVGroupSelect subset_type,
int *r_defgroup_tot,
int *r_subset_count);
+/**
+ * Store indices from the defgroup_validmap (faster lookups in some cases).
+ */
void BKE_object_defgroup_subset_to_index_array(const bool *defgroup_validmap,
- const int defgroup_tot,
+ int defgroup_tot,
int *r_defgroup_subset_map);
/* ********** */
-bool *BKE_object_defgroup_lock_flags_get(struct Object *ob, const int defbase_tot);
-bool *BKE_object_defgroup_validmap_get(struct Object *ob, const int defbase_tot);
+/**
+ * Gets the status of "flag" for each #bDeformGroup
+ * in the object data's vertex group list and returns an array containing them
+ */
+bool *BKE_object_defgroup_lock_flags_get(struct Object *ob, int defbase_tot);
+bool *BKE_object_defgroup_validmap_get(struct Object *ob, int defbase_tot);
+/**
+ * Returns total selected vgroups,
+ * `wpi.defbase_sel` is assumed malloc'd, all values are set.
+ */
bool *BKE_object_defgroup_selected_get(struct Object *ob,
int defbase_tot,
int *r_dg_flags_sel_tot);
+/**
+ * Checks if the lock relative mode is applicable.
+ *
+ * \return true if an unlocked deform group is active.
+ */
bool BKE_object_defgroup_check_lock_relative(const bool *lock_flags,
const bool *validmap,
int index);
+/**
+ * Additional check for whether the lock relative mode is applicable in multi-paint mode.
+ *
+ * \return true if none of the selected groups are locked.
+ */
bool BKE_object_defgroup_check_lock_relative_multi(int defbase_tot,
const bool *lock_flags,
const bool *selected,
int sel_tot);
+/**
+ * Takes a pair of boolean masks of all locked and all deform groups, and computes
+ * a pair of masks for locked deform and unlocked deform groups. Output buffers may
+ * reuse the input ones.
+ */
void BKE_object_defgroup_split_locked_validmap(
int defbase_tot, const bool *locked, const bool *deform, bool *r_locked, bool *r_unlocked);
+/**
+ * Marks mirror vgroups in output and counts them.
+ * Output and counter assumed to be already initialized.
+ * Designed to be usable after BKE_object_defgroup_selected_get to extend selection to mirror.
+ */
void BKE_object_defgroup_mirror_selection(struct Object *ob,
int defbase_tot,
const bool *selection,
diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h
index 380f9045520..f598fb09773 100644
--- a/source/blender/blenkernel/BKE_ocean.h
+++ b/source/blender/blenkernel/BKE_ocean.h
@@ -19,7 +19,7 @@
#include <stdbool.h>
/** \file
- * \ingroup bli
+ * \ingroup bke
*/
#ifdef __cplusplus
@@ -73,13 +73,22 @@ typedef struct OceanCache {
struct Ocean *BKE_ocean_add(void);
void BKE_ocean_free_data(struct Ocean *oc);
void BKE_ocean_free(struct Ocean *oc);
-bool BKE_ocean_ensure(struct OceanModifierData *omd, const int resolution);
+bool BKE_ocean_ensure(struct OceanModifierData *omd, int resolution);
+/**
+ * Return true if the ocean data is valid and can be used.
+ */
bool BKE_ocean_init_from_modifier(struct Ocean *ocean,
struct OceanModifierData const *omd,
- const int resolution);
+ int resolution);
+/**
+ * Return true if the ocean is valid and can be used.
+ */
bool BKE_ocean_is_valid(const struct Ocean *o);
+/**
+ * Return true if the ocean data is valid and can be used.
+ */
bool BKE_ocean_init(struct Ocean *o,
int M,
int N,
@@ -104,15 +113,26 @@ bool BKE_ocean_init(struct Ocean *o,
int seed);
void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount);
-/* sampling the ocean surface */
float BKE_ocean_jminus_to_foam(float jminus, float coverage);
+/**
+ * Sampling the ocean surface.
+ */
void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float v);
+/**
+ * Use catmullrom interpolation rather than linear.
+ */
void BKE_ocean_eval_uv_catrom(struct Ocean *oc, struct OceanResult *ocr, float u, float v);
void BKE_ocean_eval_xz(struct Ocean *oc, struct OceanResult *ocr, float x, float z);
void BKE_ocean_eval_xz_catrom(struct Ocean *oc, struct OceanResult *ocr, float x, float z);
+/**
+ * Note that this doesn't wrap properly for i, j < 0, but its not really meant for that being
+ * just a way to get the raw data out to save in some image format.
+ */
void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j);
-/* ocean cache handling */
+/**
+ * Ocean cache handling.
+ */
struct OceanCache *BKE_ocean_init_cache(const char *bakepath,
const char *relbase,
int start,
@@ -136,9 +156,27 @@ void BKE_ocean_free_cache(struct OceanCache *och);
void BKE_ocean_free_modifier_cache(struct OceanModifierData *omd);
/* ocean_spectrum.c */
-float BLI_ocean_spectrum_piersonmoskowitz(const struct Ocean *oc, const float kx, const float kz);
-float BLI_ocean_spectrum_texelmarsenarsloe(const struct Ocean *oc, const float kx, const float kz);
-float BLI_ocean_spectrum_jonswap(const struct Ocean *oc, const float kx, const float kz);
+
+/**
+ * Pierson-Moskowitz model, 1964, assumes waves reach equilibrium with wind.
+ * Model is intended for large area 'fully developed' sea, where winds have been steadily blowing
+ * for days over an area that includes hundreds of wavelengths on a side.
+ */
+float BLI_ocean_spectrum_piersonmoskowitz(const struct Ocean *oc, float kx, float kz);
+/**
+ * TMA extends the JONSWAP spectrum.
+ * This spectral model is best suited to shallow water.
+ */
+float BLI_ocean_spectrum_texelmarsenarsloe(const struct Ocean *oc, float kx, float kz);
+/**
+ * Hasselmann et al, 1973. This model extends the Pierson-Moskowitz model with a peak sharpening
+ * function This enhancement is an artificial construct to address the problem that the wave
+ * spectrum is never fully developed.
+ *
+ * The fetch parameter represents the distance from a lee shore,
+ * called the fetch, or the distance over which the wind blows with constant velocity.
+ */
+float BLI_ocean_spectrum_jonswap(const struct Ocean *oc, float kx, float kz);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h
index 8cb0c78d9aa..87a46f5f888 100644
--- a/source/blender/blenkernel/BKE_packedFile.h
+++ b/source/blender/blenkernel/BKE_packedFile.h
@@ -57,17 +57,32 @@ enum ePF_FileStatus {
PF_ASK = 10,
};
-/* pack */
+/* Pack. */
+
struct PackedFile *BKE_packedfile_duplicate(const struct PackedFile *pf_src);
struct PackedFile *BKE_packedfile_new(struct ReportList *reports,
const char *filename,
const char *basepath);
struct PackedFile *BKE_packedfile_new_from_memory(void *mem, int memlen);
+/**
+ * No libraries for now.
+ */
void BKE_packedfile_pack_all(struct Main *bmain, struct ReportList *reports, bool verbose);
void BKE_packedfile_pack_all_libraries(struct Main *bmain, struct ReportList *reports);
-/* unpack */
+/* Unpack. */
+
+/**
+ * #BKE_packedfile_unpack_to_file() looks at the existing files (abs_name, local_name)
+ * and a packed file.
+ *
+ * It returns a char *to the existing file name / new file name or NULL when
+ * there was an error or when the user decides to cancel the operation.
+ *
+ * \warning 'abs_name' may be relative still! (use a "//" prefix)
+ * be sure to run #BLI_path_abs on it first.
+ */
char *BKE_packedfile_unpack_to_file(struct ReportList *reports,
const char *ref_file_name,
const char *abs_name,
@@ -105,25 +120,40 @@ int BKE_packedfile_write_to_file(struct ReportList *reports,
const char *ref_file_name,
const char *filename,
struct PackedFile *pf,
- const bool guimode);
+ bool guimode);
+
+/* Free. */
-/* free */
void BKE_packedfile_free(struct PackedFile *pf);
-/* info */
+/* Info. */
+
int BKE_packedfile_count_all(struct Main *bmain);
+/**
+ * This function compares a packed file to a 'real' file.
+ * It returns an integer indicating if:
+ *
+ * - #PF_EQUAL: the packed file and original file are identical.
+ * - #PF_DIFFERENT: the packed file and original file differ.
+ * - #PF_NOFILE: the original file doesn't exist.
+ */
enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
const char *filename,
struct PackedFile *pf);
-/* read */
+/* Read. */
+
int BKE_packedfile_seek(struct PackedFile *pf, int offset, int whence);
void BKE_packedfile_rewind(struct PackedFile *pf);
int BKE_packedfile_read(struct PackedFile *pf, void *data, int size);
-/* ID should be not NULL, return 1 if there's a packed file */
-bool BKE_packedfile_id_check(struct ID *id);
-/* ID should be not NULL, throws error when ID is Library */
+/**
+ * ID should be not NULL, return true if there's a packed file.
+ */
+bool BKE_packedfile_id_check(const struct ID *id);
+/**
+ * ID should be not NULL, throws error when ID is Library.
+ */
void BKE_packedfile_id_unpack(struct Main *bmain,
struct ID *id,
struct ReportList *reports,
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 73413b61456..4019c4d62c4 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -111,10 +111,11 @@ typedef enum ePaintOverlayControlFlags {
(PAINT_OVERLAY_OVERRIDE_SECONDARY | PAINT_OVERLAY_OVERRIDE_PRIMARY | \
PAINT_OVERLAY_OVERRIDE_CURSOR)
-/* Defines 8 areas resulting of splitting the object space by the XYZ axis planes. This is used to
+/**
+ * Defines 8 areas resulting of splitting the object space by the XYZ axis planes. This is used to
* flip or mirror transform values depending on where the vertex is and where the transform
- * operation started to support XYZ symmetry on those operations in a predictable way. */
-
+ * operation started to support XYZ symmetry on those operations in a predictable way.
+ */
#define PAINT_SYMM_AREA_DEFAULT 0
typedef enum ePaintSymmetryAreas {
@@ -136,29 +137,42 @@ ePaintOverlayControlFlags BKE_paint_get_overlay_flags(void);
void BKE_paint_reset_overlay_invalid(ePaintOverlayControlFlags flag);
void BKE_paint_set_overlay_override(enum eOverlayFlags flag);
-/* palettes */
+/* Palettes. */
+
struct Palette *BKE_palette_add(struct Main *bmain, const char *name);
struct PaletteColor *BKE_palette_color_add(struct Palette *palette);
bool BKE_palette_is_empty(const struct Palette *palette);
+/**
+ * Remove color from palette. Must be certain color is inside the palette!
+ */
void BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color);
void BKE_palette_clear(struct Palette *palette);
-void BKE_palette_sort_hsv(struct tPaletteColorHSV *color_array, const int totcol);
-void BKE_palette_sort_svh(struct tPaletteColorHSV *color_array, const int totcol);
-void BKE_palette_sort_vhs(struct tPaletteColorHSV *color_array, const int totcol);
-void BKE_palette_sort_luminance(struct tPaletteColorHSV *color_array, const int totcol);
+void BKE_palette_sort_hsv(struct tPaletteColorHSV *color_array, int totcol);
+void BKE_palette_sort_svh(struct tPaletteColorHSV *color_array, int totcol);
+void BKE_palette_sort_vhs(struct tPaletteColorHSV *color_array, int totcol);
+void BKE_palette_sort_luminance(struct tPaletteColorHSV *color_array, int totcol);
bool BKE_palette_from_hash(struct Main *bmain,
struct GHash *color_table,
const char *name,
- const bool linear);
+ bool linear);
+
+/* Paint curves. */
-/* paint curves */
struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name);
+/**
+ * Call when entering each respective paint mode.
+ */
bool BKE_paint_ensure(struct ToolSettings *ts, struct Paint **r_paint);
void BKE_paint_init(struct Main *bmain, struct Scene *sce, ePaintMode mode, const char col[3]);
void BKE_paint_free(struct Paint *p);
-void BKE_paint_copy(struct Paint *src, struct Paint *tar, const int flag);
+/**
+ * Called when copying scene settings, so even if 'src' and 'tar' are the same still do a
+ * #id_us_plus(), rather than if we were copying between 2 existing scenes where a matching
+ * value should decrease the existing user count as with #paint_brush_set()
+ */
+void BKE_paint_copy(struct Paint *src, struct Paint *tar, int flag);
void BKE_paint_runtime_init(const struct ToolSettings *ts, struct Paint *paint);
@@ -169,7 +183,7 @@ bool BKE_paint_ensure_from_paintmode(struct Scene *sce, ePaintMode mode);
struct Paint *BKE_paint_get_active_from_paintmode(struct Scene *sce, ePaintMode mode);
const struct EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode);
const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode);
-uint BKE_paint_get_brush_tool_offset_from_paintmode(const ePaintMode mode);
+uint BKE_paint_get_brush_tool_offset_from_paintmode(ePaintMode mode);
struct Paint *BKE_paint_get_active(struct Scene *sce, struct ViewLayer *view_layer);
struct Paint *BKE_paint_get_active_from_context(const struct bContext *C);
ePaintMode BKE_paintmode_get_active_from_context(const struct bContext *C);
@@ -179,28 +193,48 @@ void BKE_paint_brush_set(struct Paint *paint, struct Brush *br);
struct Palette *BKE_paint_palette(struct Paint *paint);
void BKE_paint_palette_set(struct Paint *p, struct Palette *palette);
void BKE_paint_curve_set(struct Brush *br, struct PaintCurve *pc);
-void BKE_paint_curve_clamp_endpoint_add_index(struct PaintCurve *pc, const int add_index);
+void BKE_paint_curve_clamp_endpoint_add_index(struct PaintCurve *pc, int add_index);
-/* testing face select mode
- * Texture paint could be removed since selected faces are not used
- * however hiding faces is useful */
+/**
+ * Return true when in vertex/weight/texture paint + face-select mode?
+ */
bool BKE_paint_select_face_test(struct Object *ob);
+/**
+ * Return true when in vertex/weight paint + vertex-select mode?
+ */
bool BKE_paint_select_vert_test(struct Object *ob);
+/**
+ * used to check if selection is possible
+ * (when we don't care if its face or vert)
+ */
bool BKE_paint_select_elem_test(struct Object *ob);
-/* partial visibility */
+/* Partial visibility. */
+
+/**
+ * Returns non-zero if any of the face's vertices are hidden, zero otherwise.
+ */
bool paint_is_face_hidden(const struct MLoopTri *lt,
const struct MVert *mvert,
const struct MLoop *mloop);
+/**
+ * Returns non-zero if any of the corners of the grid
+ * face whose inner corner is at (x, y) are hidden, zero otherwise.
+ */
bool paint_is_grid_face_hidden(const unsigned int *grid_hidden, int gridsize, int x, int y);
+/**
+ * Return true if all vertices in the face are visible, false otherwise.
+ */
bool paint_is_bmesh_face_hidden(struct BMFace *f);
-/* paint masks */
+/* Paint masks. */
+
float paint_grid_paint_mask(const struct GridPaintMask *gpm, uint level, uint x, uint y);
-void BKE_paint_face_set_overlay_color_get(const int face_set, const int seed, uchar r_color[4]);
+void BKE_paint_face_set_overlay_color_get(int face_set, int seed, uchar r_color[4]);
+
+/* Stroke related. */
-/* stroke related */
bool paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups,
struct Brush *brush,
const float mouse_pos[2]);
@@ -211,14 +245,20 @@ void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups,
void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]);
/* Tool slot API. */
+
void BKE_paint_toolslots_init_from_main(struct Main *bmain);
void BKE_paint_toolslots_len_ensure(struct Paint *paint, int len);
void BKE_paint_toolslots_brush_update_ex(struct Paint *paint, struct Brush *brush);
void BKE_paint_toolslots_brush_update(struct Paint *paint);
+/**
+ * Run this to ensure brush types are set for each slot on entering modes
+ * (for new scenes for example).
+ */
void BKE_paint_toolslots_brush_validate(struct Main *bmain, struct Paint *paint);
struct Brush *BKE_paint_toolslots_brush_get(struct Paint *paint, int slot_index);
/* .blend I/O */
+
void BKE_paint_blend_write(struct BlendWriter *writer, struct Paint *paint);
void BKE_paint_blend_read_data(struct BlendDataReader *reader,
const struct Scene *scene,
@@ -229,7 +269,7 @@ void BKE_paint_blend_read_lib(struct BlendLibReader *reader,
#define SCULPT_FACE_SET_NONE 0
-/* Used for both vertex color and weight paint */
+/** Used for both vertex color and weight paint. */
struct SculptVertexPaintGeomMap {
int *vert_map_mem;
struct MeshElemMap *vert_to_loop;
@@ -237,7 +277,7 @@ struct SculptVertexPaintGeomMap {
struct MeshElemMap *vert_to_poly;
};
-/* Pose Brush IK Chain */
+/** Pose Brush IK Chain. */
typedef struct SculptPoseIKChainSegment {
float orig[3];
float head[3];
@@ -459,6 +499,7 @@ typedef struct SculptSession {
/* These are always assigned to base mesh data when using PBVH_FACES and PBVH_GRIDS. */
struct MVert *mvert;
+ const float (*vert_normals)[3];
struct MPoly *mpoly;
struct MLoop *mloop;
@@ -538,7 +579,7 @@ typedef struct SculptSession {
float cursor_sampled_normal[3];
float cursor_view_normal[3];
- /* For Sculpt trimming gesture tools, initial raycast data from the position of the mouse when
+ /* For Sculpt trimming gesture tools, initial ray-cast data from the position of the mouse when
* the gesture starts (intersection with the surface and if they ray hit the surface or not). */
float gesture_initial_location[3];
float gesture_initial_normal[3];
@@ -576,10 +617,6 @@ typedef struct SculptSession {
float init_pivot_rot[4];
float init_pivot_scale[3];
- float prev_pivot_pos[3];
- float prev_pivot_rot[4];
- float prev_pivot_scale[3];
-
union {
struct {
struct SculptVertexPaintGeomMap gmap;
@@ -620,10 +657,15 @@ void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss);
void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder);
void BKE_sculptsession_bm_to_me_for_render(struct Object *object);
-/* Create new color layer on object if it doesn't have one and if experimental feature set has
- * sculpt vertex color enabled. Returns truth if new layer has been added, false otherwise. */
+/**
+ * Create new color layer on object if it doesn't have one and if experimental feature set has
+ * sculpt vertex color enabled. Returns truth if new layer has been added, false otherwise.
+ */
void BKE_sculpt_color_layer_create_if_needed(struct Object *object);
+/**
+ * \warning Expects a fully evaluated depsgraph.
+ */
void BKE_sculpt_update_object_for_edit(struct Depsgraph *depsgraph,
struct Object *ob_orig,
bool need_pmap,
@@ -632,6 +674,10 @@ void BKE_sculpt_update_object_for_edit(struct Depsgraph *depsgraph,
void BKE_sculpt_update_object_before_eval(struct Object *ob_eval);
void BKE_sculpt_update_object_after_eval(struct Depsgraph *depsgraph, struct Object *ob_eval);
+/**
+ * Sculpt mode handles multi-res differently from regular meshes, but only if
+ * it's the last modifier on the stack and it is not on the first level.
+ */
struct MultiresModifierData *BKE_sculpt_multires_active(struct Scene *scene, struct Object *ob);
int BKE_sculpt_mask_layers_ensure(struct Object *ob, struct MultiresModifierData *mmd);
void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene);
@@ -640,19 +686,37 @@ struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Depsgraph *depsgraph, struct O
void BKE_sculpt_bvh_update_from_ccg(struct PBVH *pbvh, struct SubdivCCG *subdiv_ccg);
-/* This ensure that all elements in the mesh (both vertices and grids) have their visibility
- * updated according to the face sets. */
+/**
+ * This ensure that all elements in the mesh (both vertices and grids) have their visibility
+ * updated according to the face sets.
+ */
void BKE_sculpt_sync_face_set_visibility(struct Mesh *mesh, struct SubdivCCG *subdiv_ccg);
-/* Individual function to sync the Face Set visibility to mesh and grids. */
+/**
+ * Individual function to sync the Face Set visibility to mesh and grids.
+ */
void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(struct Mesh *mesh);
void BKE_sculpt_sync_face_sets_visibility_to_grids(struct Mesh *mesh,
struct SubdivCCG *subdiv_ccg);
+/**
+ * Ensures that a Face Set data-layers exists. If it does not, it creates one respecting the
+ * visibility stored in the vertices of the mesh. If it does, it copies the visibility from the
+ * mesh to the Face Sets. */
void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(struct Mesh *mesh);
+/**
+ * Ensures we do have expected mesh data in original mesh for the sculpt mode.
+ *
+ * \note IDs are expected to be original ones here, and calling code should ensure it updates its
+ * depsgraph properly after calling this function if it needs up-to-date evaluated data.
+ */
void BKE_sculpt_ensure_orig_mesh_data(struct Scene *scene, struct Object *object);
+/**
+ * Test if PBVH can be used directly for drawing, which is faster than
+ * drawing the mesh and all updates that come with it.
+ */
bool BKE_sculptsession_use_pbvh_draw(const struct Object *ob, const struct View3D *v3d);
enum {
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 78a6e47ec48..804331a3412 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -286,18 +286,24 @@ BLI_INLINE void psys_frand_vec(ParticleSystem *psys, unsigned int seed, float ve
/* ----------- functions needed outside particlesystem ---------------- */
/* particle.c */
+
+/* Few helpers for count-all etc. */
+
int count_particles(struct ParticleSystem *psys);
int count_particles_mod(struct ParticleSystem *psys, int totgr, int cur);
int psys_get_child_number(struct Scene *scene,
struct ParticleSystem *psys,
- const bool use_render_params);
-int psys_get_tot_child(struct Scene *scene,
- struct ParticleSystem *psys,
- const bool use_render_params);
+ bool use_render_params);
+int psys_get_tot_child(struct Scene *scene, struct ParticleSystem *psys, bool use_render_params);
+/**
+ * Get object's active particle system safely.
+ */
struct ParticleSystem *psys_get_current(struct Object *ob);
-/* for rna */
+
+/* For RNA API. */
+
short psys_get_current_num(struct Object *ob);
void psys_set_current_num(struct Object *ob, int index);
/* UNUSED */
@@ -305,22 +311,23 @@ void psys_set_current_num(struct Object *ob, int index);
struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim);
-/* For a given evaluated particle system get its original.
+/**
+ * For a given evaluated particle system get its original.
*
- * If this input is an original particle system already, the return value is the
- * same as the input. */
+ * If this input is an original particle system already, the return value is the same as the input.
+ */
struct ParticleSystem *psys_orig_get(struct ParticleSystem *psys);
-/* For a given original object and its particle system, get evaluated particle
- * system within a given dependency graph. */
+/**
+ * For a given original object and its particle system,
+ * get evaluated particle system within a given dependency graph.
+ */
struct ParticleSystem *psys_eval_get(struct Depsgraph *depsgraph,
struct Object *object,
struct ParticleSystem *psys);
bool psys_in_edit_mode(struct Depsgraph *depsgraph, const struct ParticleSystem *psys);
-bool psys_check_enabled(struct Object *ob,
- struct ParticleSystem *psys,
- const bool use_render_params);
+bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, bool use_render_params);
bool psys_check_edited(struct ParticleSystem *psys);
void psys_find_group_weights(struct ParticleSettings *part);
@@ -328,11 +335,17 @@ void psys_check_group_weights(struct ParticleSettings *part);
int psys_uses_gravity(struct ParticleSimulationData *sim);
void BKE_particlesettings_fluid_default_settings(struct ParticleSettings *part);
-/* free */
+/**
+ * Free cache path.
+ */
void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit);
+/**
+ * Free everything.
+ */
void psys_free(struct Object *ob, struct ParticleSystem *psys);
-
-/* Copy. */
+/**
+ * Copy.
+ */
void psys_copy_particles(struct ParticleSystem *psys_dst, struct ParticleSystem *psys_src);
bool psys_render_simplify_params(struct ParticleSystem *psys,
@@ -375,23 +388,27 @@ void object_remove_particle_system(struct Main *bmain,
struct ParticleSettings *BKE_particlesettings_add(struct Main *bmain, const char *name);
void psys_reset(struct ParticleSystem *psys, int mode);
-void psys_find_parents(struct ParticleSimulationData *sim, const bool use_render_params);
+void psys_find_parents(struct ParticleSimulationData *sim, bool use_render_params);
void psys_unique_name(struct Object *object, struct ParticleSystem *psys, const char *defname);
-void psys_cache_paths(struct ParticleSimulationData *sim,
- float cfra,
- const bool use_render_params);
+/**
+ * Calculates paths ready for drawing/rendering
+ * - Useful for making use of opengl vertex arrays for super fast strand drawing.
+ * - Makes child strands possible and creates them too into the cache.
+ * - Cached path data is also used to determine cut position for the edit-mode tool.
+ */
+void psys_cache_paths(struct ParticleSimulationData *sim, float cfra, bool use_render_params);
void psys_cache_edit_paths(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct PTCacheEdit *edit,
float cfra,
- const bool use_render_params);
+ bool use_render_params);
void psys_cache_child_paths(struct ParticleSimulationData *sim,
float cfra,
- const bool editupdate,
- const bool use_render_params);
+ bool editupdate,
+ bool use_render_params);
int do_guides(struct Depsgraph *depsgraph,
struct ParticleSettings *part,
struct ListBase *effectors,
@@ -409,16 +426,24 @@ float psys_get_child_size(struct ParticleSystem *psys,
struct ChildParticle *cpa,
float cfra,
float *pa_time);
+/**
+ * Gets hair (or keyed) particles state at the "path time" specified in `state->time`.
+ */
void psys_get_particle_on_path(struct ParticleSimulationData *sim,
int pa_num,
struct ParticleKey *state,
- const bool vel);
-int psys_get_particle_state(struct ParticleSimulationData *sim,
- int p,
- struct ParticleKey *state,
- int always);
+ bool vel);
+/**
+ * Gets particle's state at a time.
+ * \return true if particle exists and can be seen and false if not.
+ */
+bool psys_get_particle_state(struct ParticleSimulationData *sim,
+ int p,
+ struct ParticleKey *state,
+ bool always);
+
+/* Child paths. */
-/* child paths */
void BKE_particlesettings_clump_curve_init(struct ParticleSettings *part);
void BKE_particlesettings_rough_curve_init(struct ParticleSettings *part);
void BKE_particlesettings_twist_curve_init(struct ParticleSettings *part);
@@ -434,9 +459,13 @@ void psys_apply_child_modifiers(struct ParticleThreadContext *ctx,
void psys_sph_init(struct ParticleSimulationData *sim, struct SPHData *sphdata);
void psys_sph_finalize(struct SPHData *sphdata);
+/**
+ * Sample the density field at a point in space.
+ */
void psys_sph_density(struct BVHTree *tree, struct SPHData *data, float co[3], float vars[2]);
-/* for anim.c */
+/* For anim.c */
+
void psys_get_dupli_texture(struct ParticleSystem *psys,
struct ParticleSettings *part,
struct ParticleSystemModifierData *psmd,
@@ -451,6 +480,9 @@ void psys_get_dupli_path_transform(struct ParticleSimulationData *sim,
float mat[4][4],
float *scale);
+/**
+ * Threaded child particle distribution and path caching.
+ */
void psys_thread_context_init(struct ParticleThreadContext *ctx,
struct ParticleSimulationData *sim);
void psys_thread_context_free(struct ParticleThreadContext *ctx);
@@ -467,9 +499,16 @@ void psys_apply_hair_lattice(struct Depsgraph *depsgraph,
struct ParticleSystem *psys);
/* particle_system.c */
+
struct ParticleSystem *psys_get_target_system(struct Object *ob, struct ParticleTarget *pt);
+/**
+ * Counts valid keyed targets.
+ */
void psys_count_keyed_targets(struct ParticleSimulationData *sim);
void psys_update_particle_tree(struct ParticleSystem *psys, float cfra);
+/**
+ * System type has changed so set sensible defaults and clear non applicable flags.
+ */
void psys_changed_type(struct Object *ob, struct ParticleSystem *psys);
void psys_make_temp_pointcache(struct Object *ob, struct ParticleSystem *psys);
@@ -486,13 +525,19 @@ void psys_get_birth_coords(struct ParticleSimulationData *sim,
float dtime,
float cfra);
+/**
+ * Main particle update call, checks that things are ok on the large scale and
+ * then advances in to actual particle calculations depending on particle type.
+ */
void particle_system_update(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct ParticleSystem *psys,
- const bool use_render_params);
+ bool use_render_params);
-/* Callback format for performing operations on ID-pointers for particle systems */
+/**
+ * Callback format for performing operations on ID-pointers for particle systems.
+ */
typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys,
struct ID **idpoin,
void *userdata,
@@ -502,11 +547,15 @@ void BKE_particlesystem_id_loop(struct ParticleSystem *psys,
ParticleSystemIDFunc func,
void *userdata);
-/* Reset all particle systems in the given object. */
+/**
+ * Reset all particle systems in the given object.
+ */
void BKE_particlesystem_reset_all(struct Object *object);
/* ----------- functions needed only inside particlesystem ------------ */
+
/* particle.c */
+
void psys_disable_all(struct Object *ob);
void psys_enable_all(struct Object *ob);
@@ -544,7 +593,11 @@ void psys_get_texture(struct ParticleSimulationData *sim,
struct ParticleTexture *ptex,
int event,
float cfra);
+/**
+ * Interpolate a location on a face based on face coordinates.
+ */
void psys_interpolate_face(struct MVert *mvert,
+ const float (*vert_normals)[3],
struct MFace *mface,
struct MTFace *tface,
float (*orcodata)[3],
@@ -561,11 +614,16 @@ float psys_particle_value_from_verts(struct Mesh *mesh,
void psys_get_from_key(
struct ParticleKey *key, float loc[3], float vel[3], float rot[4], float *time);
-/* BLI_bvhtree_ray_cast callback */
+/**
+ * Callback for #BVHTree near test.
+ */
void BKE_psys_collision_neartest_cb(void *userdata,
int index,
const struct BVHTreeRay *ray,
struct BVHTreeRayHit *hit);
+/**
+ * Interprets particle data to get a point on a mesh in object space.
+ */
void psys_particle_on_dm(struct Mesh *mesh_final,
int from,
int index,
@@ -579,25 +637,43 @@ void psys_particle_on_dm(struct Mesh *mesh_final,
float orco[3]);
/* particle_system.c */
+
void distribute_particles(struct ParticleSimulationData *sim, int from);
+/**
+ * Set particle parameters that don't change during particle's life.
+ */
void init_particle(struct ParticleSimulationData *sim, struct ParticleData *pa);
void psys_calc_dmcache(struct Object *ob,
struct Mesh *mesh_final,
struct Mesh *mesh_original,
struct ParticleSystem *psys);
+/**
+ * Find the final derived mesh tessface for a particle, from its original tessface index.
+ * This is slow and can be optimized but only for many lookups.
+ *
+ * \param mesh_final: Final mesh, it may not have the same topology as original mesh.
+ * \param mesh_original: Original mesh, use for accessing #MPoly to #MFace mapping.
+ * \param findex_orig: The input tessface index.
+ * \param fw: Face weights (position of the particle inside the \a findex_orig tessface).
+ * \param poly_nodes: May be NULL, otherwise an array of linked list,
+ * one for each final \a mesh_final polygon, containing all its tessfaces indices.
+ * \return The \a mesh_final tessface index.
+ */
int psys_particle_dm_face_lookup(struct Mesh *mesh_final,
struct Mesh *mesh_original,
- int findex,
+ int findex_orig,
const float fw[4],
struct LinkNode **poly_nodes);
+/**
+ * Sets particle to the emitter surface with initial velocity & rotation.
+ */
void reset_particle(struct ParticleSimulationData *sim,
struct ParticleData *pa,
float dtime,
float cfra);
-float psys_get_current_display_percentage(struct ParticleSystem *psys,
- const bool use_render_params);
+float psys_get_current_display_percentage(struct ParticleSystem *psys, bool use_render_params);
/* psys_reset */
#define PSYS_RESET_ALL 1
@@ -629,6 +705,7 @@ extern void (*BKE_particle_batch_cache_dirty_tag_cb)(struct ParticleSystem *psys
extern void (*BKE_particle_batch_cache_free_cb)(struct ParticleSystem *psys);
/* .blend file I/O */
+
void BKE_particle_partdeflect_blend_read_data(struct BlendDataReader *reader,
struct PartDeflect *pd);
void BKE_particle_partdeflect_blend_read_lib(struct BlendLibReader *reader,
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 056a7e2d897..1ef1c98ce83 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -90,7 +90,9 @@ void BKE_pbvh_get_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes);
/* Callbacks */
-/* returns 1 if the search should continue from this node, 0 otherwise */
+/**
+ * Returns true if the search should continue from this node, false otherwise.
+ */
typedef bool (*BKE_pbvh_SearchCallback)(PBVHNode *node, void *data);
typedef void (*BKE_pbvh_HitCallback)(PBVHNode *node, void *data);
@@ -101,8 +103,14 @@ typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float
/* Building */
PBVH *BKE_pbvh_new(void);
+/**
+ * Do a full rebuild with on Mesh data structure.
+ *
+ * \note Unlike mpoly/mloop/verts, looptri is *totally owned* by PBVH
+ * (which means it may rewrite it if needed, see #BKE_pbvh_vert_coords_apply().
+ */
void BKE_pbvh_build_mesh(PBVH *pbvh,
- const struct Mesh *mesh,
+ struct Mesh *mesh,
const struct MPoly *mpoly,
const struct MLoop *mloop,
struct MVert *verts,
@@ -112,6 +120,9 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
struct CustomData *pdata,
const struct MLoopTri *looptri,
int looptri_num);
+/**
+ * Do a full rebuild with on Grids data structure.
+ */
void BKE_pbvh_build_grids(PBVH *pbvh,
struct CCGElem **grids,
int totgrid,
@@ -119,17 +130,20 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
void **gridfaces,
struct DMFlagMat *flagmats,
unsigned int **grid_hidden);
+/**
+ * Build a PBVH from a BMesh.
+ */
void BKE_pbvh_build_bmesh(PBVH *pbvh,
struct BMesh *bm,
bool smooth_shading,
struct BMLog *log,
- const int cd_vert_node_offset,
- const int cd_face_node_offset);
+ int cd_vert_node_offset,
+ int cd_face_node_offset);
void BKE_pbvh_free(PBVH *pbvh);
/* Hierarchical Search in the BVH, two methods:
- * - for each hit calling a callback
- * - gather nodes in an array (easy to multithread) */
+ * - For each hit calling a callback.
+ * - Gather nodes in an array (easy to multi-thread). */
void BKE_pbvh_search_callback(PBVH *pbvh,
BKE_pbvh_SearchCallback scb,
@@ -140,7 +154,7 @@ void BKE_pbvh_search_callback(PBVH *pbvh,
void BKE_pbvh_search_gather(
PBVH *pbvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***array, int *tot);
-/* Raycast
+/* Ray-cast
* the hit callback is called for all leaf nodes intersecting the ray;
* it's up to the callback to find the primitive within the leaves that is
* hit first */
@@ -170,8 +184,10 @@ bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
float *depth,
float *r_edge_length);
-/* for orthographic cameras, project the far away ray segment points to the root node so
- * we can have better precision. */
+/**
+ * For orthographic cameras, project the far away ray segment points to the root node so
+ * we can have better precision.
+ */
void BKE_pbvh_raycast_project_ray_root(
PBVH *pbvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3]);
@@ -215,12 +231,19 @@ typedef enum {
PBVHType BKE_pbvh_type(const PBVH *pbvh);
bool BKE_pbvh_has_faces(const PBVH *pbvh);
-/* Get the PBVH root's bounding box */
+/**
+ * Get the PBVH root's bounding box.
+ */
void BKE_pbvh_bounding_box(const PBVH *pbvh, float min[3], float max[3]);
-/* multires hidden data, only valid for type == PBVH_GRIDS */
+/**
+ * Multi-res hidden data, only valid for type == PBVH_GRIDS.
+ */
unsigned int **BKE_pbvh_grid_hidden(const PBVH *pbvh);
+/**
+ * Returns the number of visible quads in the nodes' grids.
+ */
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
const int *grid_indices,
int totgrid,
@@ -228,7 +251,9 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
void BKE_pbvh_sync_face_sets_to_grids(PBVH *pbvh);
-/* multires level, only valid for type == PBVH_GRIDS */
+/**
+ * Multi-res level, only valid for type == #PBVH_GRIDS.
+ */
const struct CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh);
struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh);
@@ -236,7 +261,9 @@ BLI_bitmap **BKE_pbvh_get_grid_visibility(const PBVH *pbvh);
int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh);
int BKE_pbvh_get_grid_num_faces(const PBVH *pbvh);
-/* Only valid for type == PBVH_BMESH */
+/**
+ * Only valid for type == #PBVH_BMESH.
+ */
struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh);
void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size);
@@ -244,13 +271,16 @@ typedef enum {
PBVH_Subdivide = 1,
PBVH_Collapse = 2,
} PBVHTopologyUpdateMode;
+/**
+ * Collapse short edges, subdivide long edges.
+ */
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],
const float view_normal[3],
float radius,
- const bool use_frontface,
- const bool use_projected);
+ bool use_frontface,
+ bool use_projected);
/* Node Access */
@@ -287,18 +317,28 @@ void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max
float BKE_pbvh_node_get_tmin(PBVHNode *node);
-/* test if AABB is at least partially inside the PBVHFrustumPlanes volume */
+/**
+ * Test if AABB is at least partially inside the #PBVHFrustumPlanes volume.
+ */
bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, void *frustum);
-/* test if AABB is at least partially outside the PBVHFrustumPlanes volume */
+/**
+ * Test if AABB is at least partially outside the #PBVHFrustumPlanes volume.
+ */
bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *frustum);
struct GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
+/**
+ * In order to perform operations on the original node coordinates
+ * (currently just ray-cast), store the node's triangles and vertices.
+ *
+ * Skips triangles that are hidden.
+ */
void BKE_pbvh_bmesh_node_save_orig(struct BMesh *bm, PBVHNode *node);
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh);
-/* Update Bounding Box/Redraw and clear flags */
+/* Update Bounding Box/Redraw and clear flags. */
void BKE_pbvh_update_bounds(PBVH *pbvh, int flags);
void BKE_pbvh_update_vertex_data(PBVH *pbvh, int flags);
@@ -318,14 +358,15 @@ void BKE_pbvh_face_sets_color_set(PBVH *pbvh, int seed, int color_default);
void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide);
-/* vertex deformer */
+/* Vertex Deformer. */
+
float (*BKE_pbvh_vert_coords_alloc(struct PBVH *pbvh))[3];
-void BKE_pbvh_vert_coords_apply(struct PBVH *pbvh, const float (*vertCos)[3], const int totvert);
+void BKE_pbvh_vert_coords_apply(struct PBVH *pbvh, const float (*vertCos)[3], int totvert);
bool BKE_pbvh_is_deformed(struct PBVH *pbvh);
-/* Vertex Iterator */
+/* Vertex Iterator. */
-/* this iterator has quite a lot of code, but it's designed to:
+/* This iterator has quite a lot of code, but it's designed to:
* - allow the compiler to eliminate dead code and variables
* - spend most of the time in the relatively simple inner loop */
@@ -356,6 +397,7 @@ typedef struct PBVHVertexIter {
/* mesh */
struct MVert *mverts;
+ float (*vert_normals)[3];
int totvert;
const int *vert_indices;
struct MPropCol *vcol;
@@ -372,7 +414,7 @@ typedef struct PBVHVertexIter {
struct MVert *mvert;
struct BMVert *bm_vert;
float *co;
- short *no;
+ float *no;
float *fno;
float *mask;
float *col;
@@ -426,7 +468,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
BLI_assert(vi.visible); \
} \
vi.co = vi.mvert->co; \
- vi.no = vi.mvert->no; \
+ vi.no = vi.vert_normals[vi.vert_indices[vi.gx]]; \
vi.index = vi.vert_indices[vi.i]; \
if (vi.vmask) { \
vi.mask = &vi.vmask[vi.index]; \
@@ -469,6 +511,11 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
int *r_orco_tris_num,
float (**r_orco_coords)[3]);
+/**
+ * \note doing a full search on all vertices here seems expensive,
+ * however this is important to avoid having to recalculate bound-box & sync the buffers to the
+ * GPU (which is far more expensive!) See: T47232.
+ */
bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node);
// void BKE_pbvh_node_BB_reset(PBVHNode *node);
@@ -480,12 +527,14 @@ void pbvh_show_mask_set(PBVH *pbvh, bool show_mask);
bool pbvh_has_face_sets(PBVH *pbvh);
void pbvh_show_face_sets_set(PBVH *pbvh, bool show_face_sets);
-/* Parallelization */
+/* Parallelization. */
+
void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings,
bool use_threading,
int totnode);
struct MVert *BKE_pbvh_get_verts(const PBVH *pbvh);
+const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3];
PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node);
void BKE_pbvh_node_color_buffer_free(PBVH *pbvh);
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index c83fca767a1..0749b9d6d49 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -273,19 +273,28 @@ typedef struct PTCacheEdit {
int totpoint, totframes, totcached, edited;
} PTCacheEdit;
-/* Particle functions */
void BKE_ptcache_make_particle_key(struct ParticleKey *key, int index, void **data, float time);
/**************** Creating ID's ****************************/
+
void BKE_ptcache_id_from_softbody(PTCacheID *pid, struct Object *ob, struct SoftBody *sb);
void BKE_ptcache_id_from_particles(PTCacheID *pid, struct Object *ob, struct ParticleSystem *psys);
void BKE_ptcache_id_from_cloth(PTCacheID *pid, struct Object *ob, struct ClothModifierData *clmd);
+/**
+ * The fluid modifier does not actually use this anymore, but some parts of Blender expect that it
+ * still has a point cache currently. For example, the fluid modifier uses
+ * #DEG_add_collision_relations, which internally creates relations with the point cache.
+ */
void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct FluidModifierData *fmd);
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid,
struct Object *ob,
struct DynamicPaintSurface *surface);
void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, struct Object *ob, struct RigidBodyWorld *rbw);
+/**
+ * \param ob: Optional, may be NULL.
+ * \param scene: Optional may be NULL.
+ */
PTCacheID BKE_ptcache_id_find(struct Object *ob, struct Scene *scene, struct PointCache *cache);
void BKE_ptcache_ids_from_object(struct ListBase *lb,
struct Object *ob,
@@ -294,12 +303,11 @@ void BKE_ptcache_ids_from_object(struct ListBase *lb,
/****************** Query funcs ****************************/
-/* Check whether object has a point cache. */
+/**
+ * Check whether object has a point cache.
+ */
bool BKE_ptcache_object_has(struct Scene *scene, struct Object *ob, int duplis);
-/***************** Global funcs ****************************/
-void BKE_ptcache_remove(void);
-
/************ ID specific functions ************************/
void BKE_ptcache_id_clear(PTCacheID *id, int mode, unsigned int cfra);
bool BKE_ptcache_id_exist(PTCacheID *id, int cfra);
@@ -316,23 +324,35 @@ void BKE_ptcache_update_info(PTCacheID *pid);
/*********** General cache reading/writing ******************/
-/* Size of cache data type. */
+/**
+ * Size of cache data type.
+ */
int BKE_ptcache_data_size(int data_type);
-/* Is point with index in memory cache */
+/**
+ * Is point with index in memory cache?
+ * Check to see if point number "index" is in `pm` (uses binary search for index data).
+ */
int BKE_ptcache_mem_index_find(struct PTCacheMem *pm, unsigned int index);
/* Memory cache read/write helpers. */
+
void BKE_ptcache_mem_pointers_init(struct PTCacheMem *pm, void *cur[BPHYS_TOT_DATA]);
void BKE_ptcache_mem_pointers_incr(void *cur[BPHYS_TOT_DATA]);
int BKE_ptcache_mem_pointers_seek(int point_index,
struct PTCacheMem *pm,
void *cur[BPHYS_TOT_DATA]);
-/* Main cache reading call. */
+/**
+ * Main cache reading call.
+ * Possible to get old or interpolated result.
+ */
int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old);
-/* Main cache writing call. */
+/**
+ * Main cache writing call.
+ * Writes cache to disk or memory.
+ */
int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra);
/******************* Allocate & free ***************/
@@ -340,41 +360,56 @@ struct PointCache *BKE_ptcache_add(struct ListBase *ptcaches);
void BKE_ptcache_free_mem(struct ListBase *mem_cache);
void BKE_ptcache_free(struct PointCache *cache);
void BKE_ptcache_free_list(struct ListBase *ptcaches);
+/* returns first point cache */
struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new,
const struct ListBase *ptcaches_old,
- const int flag);
+ int flag);
/********************** Baking *********************/
-/* Bakes cache with cache_step sized jumps in time, not accurate but very fast. */
+/**
+ * Bakes cache with cache_step sized jumps in time, not accurate but very fast.
+ */
void BKE_ptcache_quick_cache_all(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
-/* Bake cache or simulate to current frame with settings defined in the baker. */
+/**
+ * Bake cache or simulate to current frame with settings defined in the baker.
+ * if bake is not given run simulations to current frame.
+ */
void BKE_ptcache_bake(struct PTCacheBaker *baker);
-/* Convert disk cache to memory cache. */
+/**
+ * Convert disk cache to memory cache.
+ */
void BKE_ptcache_disk_to_mem(struct PTCacheID *pid);
-
-/* Convert memory cache to disk cache. */
+/**
+ * Convert memory cache to disk cache.
+ */
void BKE_ptcache_mem_to_disk(struct PTCacheID *pid);
-
-/* Convert disk cache to memory cache and vice versa. Clears the cache that was converted. */
+/**
+ * Convert disk cache to memory cache and vice versa. Clears the cache that was converted.
+ */
void BKE_ptcache_toggle_disk_cache(struct PTCacheID *pid);
-
-/* Rename all disk cache files with a new name. Doesn't touch the actual content of the files. */
+/**
+ * Rename all disk cache files with a new name. Doesn't touch the actual content of the files.
+ */
void BKE_ptcache_disk_cache_rename(struct PTCacheID *pid,
const char *name_src,
const char *name_dst);
-/* Loads simulation from external (disk) cache files. */
+/**
+ * Loads simulation from external (disk) cache files.
+ */
void BKE_ptcache_load_external(struct PTCacheID *pid);
-
-/* Set correct flags after successful simulation step */
+/**
+ * Set correct flags after successful simulation step.
+ */
void BKE_ptcache_validate(struct PointCache *cache, int framenr);
-
-/* Set correct flags after unsuccessful simulation step */
+/**
+ * Set correct flags after unsuccessful simulation step.
+ */
void BKE_ptcache_invalidate(struct PointCache *cache);
/********************** .blend File I/O *********************/
diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h
index d2d390dc786..d330ea41e6a 100644
--- a/source/blender/blenkernel/BKE_pointcloud.h
+++ b/source/blender/blenkernel/BKE_pointcloud.h
@@ -18,7 +18,7 @@
/** \file
* \ingroup bke
- * \brief General operations for point-clouds.
+ * \brief General operations for point clouds.
*/
#ifdef __cplusplus
extern "C" {
@@ -38,10 +38,10 @@ extern const char *POINTCLOUD_ATTR_RADIUS;
void *BKE_pointcloud_add(struct Main *bmain, const char *name);
void *BKE_pointcloud_add_default(struct Main *bmain, const char *name);
-struct PointCloud *BKE_pointcloud_new_nomain(const int totpoint);
+struct PointCloud *BKE_pointcloud_new_nomain(int totpoint);
struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob);
-void BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]);
+bool BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]);
void BKE_pointcloud_update_customdata_pointers(struct PointCloud *pointcloud);
bool BKE_pointcloud_customdata_required(struct PointCloud *pointcloud,
diff --git a/source/blender/blenkernel/BKE_preferences.h b/source/blender/blenkernel/BKE_preferences.h
index bd887c1ea0d..6d6c58e5c1e 100644
--- a/source/blender/blenkernel/BKE_preferences.h
+++ b/source/blender/blenkernel/BKE_preferences.h
@@ -29,9 +29,16 @@ extern "C" {
struct UserDef;
struct bUserAssetLibrary;
+/** Name of the asset library added by default. Needs translation with `DATA_()` still. */
+#define BKE_PREFS_ASSET_LIBRARY_DEFAULT_NAME N_("User Library")
+
struct bUserAssetLibrary *BKE_preferences_asset_library_add(struct UserDef *userdef,
const char *name,
const char *path) ATTR_NONNULL(1);
+/**
+ * Unlink and free a library preference member.
+ * \note Free's \a library itself.
+ */
void BKE_preferences_asset_library_remove(struct UserDef *userdef,
struct bUserAssetLibrary *library) ATTR_NONNULL();
@@ -39,6 +46,15 @@ void BKE_preferences_asset_library_name_set(struct UserDef *userdef,
struct bUserAssetLibrary *library,
const char *name) ATTR_NONNULL();
+/**
+ * Set the library path, ensuring it is pointing to a directory.
+ * Single blend files can only act as "Current File" library; libraries on disk
+ * should always be directories. If the path does not exist, that's fine; it can
+ * created as directory if necessary later.
+ */
+void BKE_preferences_asset_library_path_set(struct bUserAssetLibrary *library, const char *path)
+ ATTR_NONNULL();
+
struct bUserAssetLibrary *BKE_preferences_asset_library_find_from_index(
const struct UserDef *userdef, int index) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
struct bUserAssetLibrary *BKE_preferences_asset_library_find_from_name(
diff --git a/source/blender/blenkernel/BKE_report.h b/source/blender/blenkernel/BKE_report.h
index 5b22918e84c..8b585fd0167 100644
--- a/source/blender/blenkernel/BKE_report.h
+++ b/source/blender/blenkernel/BKE_report.h
@@ -35,32 +35,37 @@ extern "C" {
* These functions also accept NULL in case no error reporting
* is needed. */
-/* report structures are stored in DNA */
+/* Report structures are stored in DNA. */
void BKE_reports_init(ReportList *reports, int flag);
+/**
+ * Only frees the list \a reports.
+ * To make displayed reports disappear, either remove window-manager reports
+ * (#wmWindowManager.reports, or #CTX_wm_reports()), or use #WM_report_banners_cancel().
+ */
void BKE_reports_clear(ReportList *reports);
-void BKE_report(ReportList *reports, ReportType type, const char *message);
-void BKE_reportf(ReportList *reports, ReportType type, const char *format, ...)
+void BKE_report(ReportList *reports, eReportType type, const char *message);
+void BKE_reportf(ReportList *reports, eReportType type, const char *format, ...)
ATTR_PRINTF_FORMAT(3, 4);
void BKE_reports_prepend(ReportList *reports, const char *prepend);
void BKE_reports_prependf(ReportList *reports, const char *prepend, ...) ATTR_PRINTF_FORMAT(2, 3);
-ReportType BKE_report_print_level(ReportList *reports);
-void BKE_report_print_level_set(ReportList *reports, ReportType level);
+eReportType BKE_report_print_level(ReportList *reports);
+void BKE_report_print_level_set(ReportList *reports, eReportType level);
-ReportType BKE_report_store_level(ReportList *reports);
-void BKE_report_store_level_set(ReportList *reports, ReportType level);
+eReportType BKE_report_store_level(ReportList *reports);
+void BKE_report_store_level_set(ReportList *reports, eReportType level);
-char *BKE_reports_string(ReportList *reports, ReportType level);
-void BKE_reports_print(ReportList *reports, ReportType level);
+char *BKE_reports_string(ReportList *reports, eReportType level);
+void BKE_reports_print(ReportList *reports, eReportType level);
Report *BKE_reports_last_displayable(ReportList *reports);
-bool BKE_reports_contain(ReportList *reports, ReportType level);
+bool BKE_reports_contain(ReportList *reports, eReportType level);
-const char *BKE_report_type_str(ReportType type);
+const char *BKE_report_type_str(eReportType type);
bool BKE_report_write_file_fp(FILE *fp, ReportList *reports, const char *header);
bool BKE_report_write_file(const char *filepath, ReportList *reports, const char *header);
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index ae1e437cd60..68f2319106e 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup blenkernel
+ * \ingroup bke
* \brief API for Blender-side Rigid Body stuff
*/
@@ -38,11 +38,21 @@ struct Object;
struct ReportList;
struct Scene;
-/* -------------- */
-/* Memory Management */
+/* -------------------------------------------------------------------- */
+/** \name Memory Management
+ * \{ */
+/**
+ * Free rigid-body world.
+ */
void BKE_rigidbody_free_world(struct Scene *scene);
+/**
+ * Free rigid-body settings and simulation instances.
+ */
void BKE_rigidbody_free_object(struct Object *ob, struct RigidBodyWorld *rbw);
+/**
+ * Free rigid-body constraint and simulation instance.
+ */
void BKE_rigidbody_free_constraint(struct Object *ob);
/* ...... */
@@ -50,9 +60,17 @@ void BKE_rigidbody_free_constraint(struct Object *ob);
void BKE_rigidbody_object_copy(struct Main *bmain,
struct Object *ob_dst,
const struct Object *ob_src,
- const int flag);
+ int flag);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Iterator
+ * \{ */
-/* Callback format for performing operations on ID-pointers for rigidbody world. */
+/**
+ * Callback format for performing operations on ID-pointers for rigid-body world.
+ */
typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw,
struct ID **idpoin,
void *userdata,
@@ -62,43 +80,83 @@ void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw,
RigidbodyWorldIDFunc func,
void *userdata);
-/* -------------- */
-/* Setup */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Setup
+ * \{ */
-/* create Blender-side settings data - physics objects not initialized yet */
+/**
+ * Set up RigidBody world.
+ *
+ * Create Blender-side settings data - physics objects not initialized yet.
+ */
struct RigidBodyWorld *BKE_rigidbody_create_world(struct Scene *scene);
+/**
+ * Add rigid body settings to the specified object.
+ */
struct RigidBodyOb *BKE_rigidbody_create_object(struct Scene *scene,
struct Object *ob,
short type);
+/**
+ * Add rigid body constraint to the specified object.
+ */
struct RigidBodyCon *BKE_rigidbody_create_constraint(struct Scene *scene,
struct Object *ob,
short type);
-/* Ensure newly set collections' objects all have required data. */
+/**
+ * Ensure newly set collections' objects all have required data.
+ */
void BKE_rigidbody_objects_collection_validate(struct Scene *scene, struct RigidBodyWorld *rbw);
void BKE_rigidbody_constraints_collection_validate(struct Scene *scene,
struct RigidBodyWorld *rbw);
-/* Ensure object added to collection gets RB data if that collection is a RB one. */
+/**
+ * Ensure object added to collection gets RB data if that collection is a RB one.
+ */
void BKE_rigidbody_main_collection_object_add(struct Main *bmain,
struct Collection *collection,
struct Object *object);
-/* copy */
-struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw, const int flag);
+/**
+ * Copy.
+ */
+struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw, int flag);
void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw);
-/* 'validate' (i.e. make new or replace old) Physics-Engine objects */
+/**
+ * 'validate' (i.e. make new or replace old) Physics-Engine objects.
+ */
+/**
+ * Create physics sim world given RigidBody world settings
+ *
+ * \note this does NOT update object references that the scene uses,
+ * in case those aren't ready yet!
+ */
void BKE_rigidbody_validate_sim_world(struct Scene *scene,
struct RigidBodyWorld *rbw,
bool rebuild);
+/**
+ * Helper function to calculate volume of rigid-body object.
+
+ * TODO: allow a parameter to specify method used to calculate this?
+ */
void BKE_rigidbody_calc_volume(struct Object *ob, float *r_vol);
void BKE_rigidbody_calc_center_of_mass(struct Object *ob, float r_center[3]);
-/* -------------- */
-/* Utilities */
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+/**
+ * Get RigidBody world for the given scene, creating one if needed
+ *
+ * \param scene: Scene to find active Rigid Body world for.
+ */
struct RigidBodyWorld *BKE_rigidbody_get_world(struct Scene *scene);
bool BKE_rigidbody_add_object(struct Main *bmain,
struct Scene *scene,
@@ -109,47 +167,74 @@ void BKE_rigidbody_ensure_local_object(struct Main *bmain, struct Object *ob);
void BKE_rigidbody_remove_object(struct Main *bmain,
struct Scene *scene,
struct Object *ob,
- const bool free_us);
+ bool free_us);
void BKE_rigidbody_remove_constraint(struct Main *bmain,
struct Scene *scene,
struct Object *ob,
- const bool free_us);
+ bool free_us);
+
+/** \} */
-/* -------------- */
-/* Utility Macros */
+/* -------------------------------------------------------------------- */
+/** \name Utility Macros
+ * \{ */
-/* get mass of Rigid Body Object to supply to RigidBody simulators */
+/**
+ * Get mass of Rigid Body Object to supply to RigidBody simulators.
+ */
#define RBO_GET_MASS(rbo) \
(((rbo) && (((rbo)->type == RBO_TYPE_PASSIVE) || ((rbo)->flag & RBO_FLAG_KINEMATIC) || \
((rbo)->flag & RBO_FLAG_DISABLED))) ? \
(0.0f) : \
((rbo)->mass))
-/* Get collision margin for Rigid Body Object, triangle mesh and cone shapes cannot embed margin,
- * convex hull always uses custom margin. */
+/**
+ * Get collision margin for Rigid Body Object, triangle mesh and cone shapes cannot embed margin,
+ * convex hull always uses custom margin.
+ */
#define RBO_GET_MARGIN(rbo) \
(((rbo)->flag & RBO_FLAG_USE_MARGIN || (rbo)->shape == RB_SHAPE_CONVEXH || \
(rbo)->shape == RB_SHAPE_TRIMESH || (rbo)->shape == RB_SHAPE_CONE) ? \
((rbo)->margin) : \
(0.04f))
-/* -------------- */
-/* Simulation */
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Simulation
+ * \{ */
+
+/**
+ * Used when canceling transforms - return rigidbody and object to initial states.
+ */
void BKE_rigidbody_aftertrans_update(struct Object *ob,
float loc[3],
float rot[3],
float quat[4],
float rotAxis[3],
float rotAngle);
+/**
+ * Sync rigid body and object transformations.
+ */
void BKE_rigidbody_sync_transforms(struct RigidBodyWorld *rbw, struct Object *ob, float ctime);
bool BKE_rigidbody_check_sim_running(struct RigidBodyWorld *rbw, float ctime);
bool BKE_rigidbody_is_affected_by_simulation(struct Object *ob);
void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw);
+/**
+ * Rebuild rigid body world.
+ *
+ * NOTE: this needs to be called before frame update to work correctly.
+ */
void BKE_rigidbody_rebuild_world(struct Depsgraph *depsgraph, struct Scene *scene, float ctime);
+/**
+ * Run RigidBody simulation for the specified physics world.
+ */
void BKE_rigidbody_do_simulation(struct Depsgraph *depsgraph, struct Scene *scene, float ctime);
-/* -------------------- */
-/* Depsgraph evaluation */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Depsgraph evaluation
+ * \{ */
void BKE_rigidbody_rebuild_sim(struct Depsgraph *depsgraph, struct Scene *scene);
@@ -159,6 +244,8 @@ void BKE_rigidbody_object_sync_transforms(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index f3edf8e9f64..a40359e8650 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -22,6 +22,8 @@
* \ingroup bke
*/
+#include "BLI_sys_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -46,7 +48,7 @@ typedef enum eSceneCopyMethod {
SCE_COPY_FULL = 3,
} eSceneCopyMethod;
-/* Use as the contents of a 'for' loop: for (SETLOOPER(...)) { ... */
+/** Use as the contents of a 'for' loop: `for (SETLOOPER(...)) { ... }`. */
#define SETLOOPER(_sce_basis, _sce_iter, _base) \
_sce_iter = _sce_basis, \
_base = _setlooper_base_step( \
@@ -64,6 +66,12 @@ typedef enum eSceneCopyMethod {
_base; \
_base = _setlooper_base_step(&_sce_iter, NULL, _base)
+/**
+ * Helper function for the #SETLOOPER and #SETLOOPER_VIEW_LAYER macros
+ *
+ * It iterates over the bases of the active layer and then the bases
+ * of the active layer of the background (set) scenes recursively.
+ */
struct Base *_setlooper_base_step(struct Scene **sce_iter,
struct ViewLayer *view_layer,
struct Base *base);
@@ -75,8 +83,11 @@ struct Scene *BKE_scene_add(struct Main *bmain, const char *name);
void BKE_scene_remove_rigidbody_object(struct Main *bmain,
struct Scene *scene,
struct Object *ob,
- const bool free_us);
+ bool free_us);
+/**
+ * Check if there is any instance of the object in the scene.
+ */
bool BKE_scene_object_find(struct Scene *scene, struct Object *ob);
struct Object *BKE_scene_object_find_by_name(const struct Scene *scene, const char *name);
@@ -91,6 +102,10 @@ typedef struct SceneBaseIter {
int phase;
} SceneBaseIter;
+/**
+ * Used by meta-balls, return *all* objects (including duplis)
+ * existing in the scene (including scene's sets).
+ */
int BKE_scene_base_iter_next(struct Depsgraph *depsgraph,
struct SceneBaseIter *iter,
struct Scene **scene,
@@ -99,12 +114,34 @@ int BKE_scene_base_iter_next(struct Depsgraph *depsgraph,
struct Object **ob);
void BKE_scene_base_flag_to_objects(struct ViewLayer *view_layer);
+/**
+ * Synchronize object base flags
+ *
+ * This is usually handled by the depsgraph.
+ * However, in rare occasions we need to use the latest object flags
+ * before depsgraph is fully updated.
+ *
+ * It should (ideally) only run for copy-on-written objects since this is
+ * runtime data generated per-view-layer.
+ */
void BKE_scene_object_base_flag_sync_from_base(struct Base *base);
+/**
+ * Sets the active scene, mainly used when running in background mode
+ * (`--scene` command line argument).
+ * This is also called to set the scene directly, bypassing windowing code.
+ * Otherwise #WM_window_set_active_scene is used when changing scenes by the user.
+ */
void BKE_scene_set_background(struct Main *bmain, struct Scene *sce);
+/**
+ * Called from `creator_args.c`.
+ */
struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name);
-struct ToolSettings *BKE_toolsettings_copy(struct ToolSettings *toolsettings, const int flag);
+/**
+ * \param flag: copying options (see BKE_lib_id.h's `LIB_ID_COPY_...` flags for more).
+ */
+struct ToolSettings *BKE_toolsettings_copy(struct ToolSettings *toolsettings, int flag);
void BKE_toolsettings_free(struct ToolSettings *toolsettings);
struct Scene *BKE_scene_duplicate(struct Main *bmain, struct Scene *sce, eSceneCopyMethod type);
@@ -122,23 +159,49 @@ struct Object *BKE_scene_camera_switch_find(struct Scene *scene); /* DURIAN_CAME
bool BKE_scene_camera_switch_update(struct Scene *scene);
const char *BKE_scene_find_marker_name(const struct Scene *scene, int frame);
+/**
+ * Return the current marker for this frame,
+ * we can have more than 1 marker per frame, this just returns the first (unfortunately).
+ */
const char *BKE_scene_find_last_marker_name(const struct Scene *scene, int frame);
int BKE_scene_frame_snap_by_seconds(struct Scene *scene, double interval_in_seconds, int frame);
-/* checks for cycle, returns 1 if it's all OK */
+/**
+ * Checks for cycle, returns true if it's all OK.
+ */
bool BKE_scene_validate_setscene(struct Main *bmain, struct Scene *sce);
+/**
+ * Return fractional frame number taking into account sub-frames and time
+ * remapping. This the time value used by animation, modifiers and physics
+ * evaluation. */
float BKE_scene_ctime_get(const struct Scene *scene);
-float BKE_scene_frame_to_ctime(const struct Scene *scene, const int frame);
+/**
+ * Convert integer frame number to fractional frame number taking into account
+ * sub-frames and time remapping.
+ */
+float BKE_scene_frame_to_ctime(const struct Scene *scene, int frame);
+/**
+ * Get current fractional frame based on frame and sub-frame.
+ */
float BKE_scene_frame_get(const struct Scene *scene);
+/**
+ * Set current frame and sub-frame based on a fractional frame.
+ */
void BKE_scene_frame_set(struct Scene *scene, float frame);
struct TransformOrientationSlot *BKE_scene_orientation_slot_get_from_flag(struct Scene *scene,
int flag);
struct TransformOrientationSlot *BKE_scene_orientation_slot_get(struct Scene *scene,
int slot_index);
+/**
+ * Activate a transform orientation in a 3D view based on an enum value.
+ *
+ * \param orientation: If this is #V3D_ORIENT_CUSTOM or greater, the custom transform orientation
+ * with index \a orientation - #V3D_ORIENT_CUSTOM gets activated.
+ */
void BKE_scene_orientation_slot_set_index(struct TransformOrientationSlot *orient_slot,
int orientation);
int BKE_scene_orientation_slot_get_index(const struct TransformOrientationSlot *orient_slot);
@@ -154,16 +217,29 @@ void BKE_scene_graph_update_tagged(struct Depsgraph *depsgraph, struct Main *bma
void BKE_scene_graph_evaluated_ensure(struct Depsgraph *depsgraph, struct Main *bmain);
void BKE_scene_graph_update_for_newframe(struct Depsgraph *depsgraph);
-void BKE_scene_graph_update_for_newframe_ex(struct Depsgraph *depsgraph, const bool clear_recalc);
+/**
+ * Applies changes right away, does all sets too.
+ */
+void BKE_scene_graph_update_for_newframe_ex(struct Depsgraph *depsgraph, bool clear_recalc);
+/**
+ * Ensures given scene/view_layer pair has a valid, up-to-date depsgraph.
+ *
+ * \warning Sets matching depsgraph as active,
+ * so should only be called from the active editing context (usually, from operators).
+ */
void BKE_scene_view_layer_graph_evaluated_ensure(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
+/**
+ * Return default view.
+ */
struct SceneRenderView *BKE_scene_add_render_view(struct Scene *sce, const char *name);
bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *srv);
-/* render profile */
+/* Render profile. */
+
int get_render_subsurf_level(const struct RenderData *r, int lvl, bool for_render);
int get_render_child_particle_number(const struct RenderData *r, int num, bool for_render);
@@ -174,8 +250,12 @@ bool BKE_scene_uses_blender_eevee(const struct Scene *scene);
bool BKE_scene_uses_blender_workbench(const struct Scene *scene);
bool BKE_scene_uses_cycles(const struct Scene *scene);
-/* Return whether the Cycles experimental feature is enabled. It is invalid to call without first
- * ensuring that Cycles is the active render engine (e.g. with BKE_scene_uses_cycles). */
+/**
+ * Return whether the Cycles experimental feature is enabled. It is invalid to call without first
+ * ensuring that Cycles is the active render engine (e.g. with #BKE_scene_uses_cycles).
+ *
+ * \note We cannot use `const` as RNA_id_pointer_create is not using a const ID.
+ */
bool BKE_scene_uses_cycles_experimental_features(struct Scene *scene);
void BKE_scene_copy_data_eevee(struct Scene *sce_dst, const struct Scene *sce_src);
@@ -191,38 +271,54 @@ int BKE_render_preview_pixel_size(const struct RenderData *r);
/**********************************/
-double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value);
+/**
+ * Apply the needed correction factor to value, based on unit_type
+ * (only length-related are affected currently) and `unit->scale_length`.
+ */
+double BKE_scene_unit_scale(const struct UnitSettings *unit, int unit_type, double value);
+
+/* Multi-view. */
-/* multiview */
bool BKE_scene_multiview_is_stereo3d(const struct RenderData *rd);
+/**
+ * Return whether to render this #SceneRenderView.
+ */
bool BKE_scene_multiview_is_render_view_active(const struct RenderData *rd,
const struct SceneRenderView *srv);
+/**
+ * \return true if `viewname` is the first or if the name is NULL or not found.
+ */
bool BKE_scene_multiview_is_render_view_first(const struct RenderData *rd, const char *viewname);
+/**
+ * \return true if `viewname` is the last or if the name is NULL or not found.
+ */
bool BKE_scene_multiview_is_render_view_last(const struct RenderData *rd, const char *viewname);
int BKE_scene_multiview_num_views_get(const struct RenderData *rd);
struct SceneRenderView *BKE_scene_multiview_render_view_findindex(const struct RenderData *rd,
- const int view_id);
-const char *BKE_scene_multiview_render_view_name_get(const struct RenderData *rd,
- const int view_id);
+ int view_id);
+const char *BKE_scene_multiview_render_view_name_get(const struct RenderData *rd, int view_id);
int BKE_scene_multiview_view_id_get(const struct RenderData *rd, const char *viewname);
void BKE_scene_multiview_filepath_get(struct SceneRenderView *srv,
const char *filepath,
char *r_filepath);
+/**
+ * When multi-view is not used the `filepath` is as usual (e.g., `Image.jpg`).
+ * When multi-view is on, even if only one view is enabled the view is incorporated
+ * into the file name (e.g., `Image_L.jpg`). That allows for the user to re-render
+ * individual views.
+ */
void BKE_scene_multiview_view_filepath_get(const struct RenderData *rd,
const char *filepath,
const char *view,
char *r_filepath);
const char *BKE_scene_multiview_view_suffix_get(const struct RenderData *rd, const char *viewname);
-const char *BKE_scene_multiview_view_id_suffix_get(const struct RenderData *rd, const int view_id);
+const char *BKE_scene_multiview_view_id_suffix_get(const struct RenderData *rd, int view_id);
void BKE_scene_multiview_view_prefix_get(struct Scene *scene,
const char *name,
char *r_prefix,
const char **r_ext);
-void BKE_scene_multiview_videos_dimensions_get(const struct RenderData *rd,
- const size_t width,
- const size_t height,
- size_t *r_width,
- size_t *r_height);
+void BKE_scene_multiview_videos_dimensions_get(
+ const struct RenderData *rd, size_t width, size_t height, size_t *r_width, size_t *r_height);
int BKE_scene_multiview_num_videos_get(const struct RenderData *rd);
/* depsgraph */
@@ -231,10 +327,14 @@ void BKE_scene_ensure_depsgraph_hash(struct Scene *scene);
void BKE_scene_free_depsgraph_hash(struct Scene *scene);
void BKE_scene_free_view_layer_depsgraph(struct Scene *scene, struct ViewLayer *view_layer);
-/* Do not allocate new depsgraph. */
+/**
+ * \note Do not allocate new depsgraph.
+ */
struct Depsgraph *BKE_scene_get_depsgraph(const struct Scene *scene,
const struct ViewLayer *view_layer);
-/* Allocate new depsgraph if necessary. */
+/**
+ * \note Allocate new depsgraph if necessary.
+ */
struct Depsgraph *BKE_scene_ensure_depsgraph(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
@@ -245,7 +345,11 @@ void BKE_scene_undo_depsgraphs_restore(struct Main *bmain, struct GHash *depsgra
void BKE_scene_transform_orientation_remove(struct Scene *scene,
struct TransformOrientation *orientation);
struct TransformOrientation *BKE_scene_transform_orientation_find(const struct Scene *scene,
- const int index);
+ int index);
+/**
+ * \return the index that \a orientation has within \a scene's transform-orientation list
+ * or -1 if not found.
+ */
int BKE_scene_transform_orientation_get_index(const struct Scene *scene,
const struct TransformOrientation *orientation);
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 6f341a12b82..c85ae04a492 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -38,6 +38,7 @@ struct BlendLibReader;
struct BlendWriter;
struct Header;
struct ID;
+struct IDRemapper;
struct LibraryForeachIDData;
struct ListBase;
struct Menu;
@@ -117,10 +118,7 @@ typedef struct SpaceType {
bContextDataCallback context;
/* Used when we want to replace an ID by another (or NULL). */
- void (*id_remap)(struct ScrArea *area,
- struct SpaceLink *sl,
- struct ID *old_id,
- struct ID *new_id);
+ void (*id_remap)(struct ScrArea *area, struct SpaceLink *sl, const struct IDRemapper *mappings);
int (*space_subtype_get)(struct ScrArea *area);
void (*space_subtype_set)(struct ScrArea *area, int value);
@@ -301,8 +299,6 @@ enum {
PANEL_TYPE_LAYOUT_VERT_BAR = (1 << 3),
/** This panel type represents data external to the UI. */
PANEL_TYPE_INSTANCED = (1 << 4),
- /** Draw panel like a box widget. */
- PANEL_TYPE_DRAW_BOX = (1 << 6),
/** Don't search panels with this type during property search. */
PANEL_TYPE_NO_SEARCH = (1 << 7),
};
@@ -398,7 +394,8 @@ typedef struct Menu {
struct uiLayout *layout; /* runtime for drawing */
} Menu;
-/* spacetypes */
+/* Space-types. */
+
struct SpaceType *BKE_spacetype_from_id(int spaceid);
struct ARegionType *BKE_regiontype_from_id_or_first(const struct SpaceType *st, int regionid);
struct ARegionType *BKE_regiontype_from_id(const struct SpaceType *st, int regionid);
@@ -407,11 +404,26 @@ void BKE_spacetype_register(struct SpaceType *st);
bool BKE_spacetype_exists(int spaceid);
void BKE_spacetypes_free(void); /* only for quitting blender */
-/* spacedata */
+/* Space-data. */
+
void BKE_spacedata_freelist(ListBase *lb);
-void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);
+/**
+ * \param lb_dst: should be empty (will be cleared).
+ */
+void BKE_spacedata_copylist(ListBase *lb_dst, ListBase *lb_src);
+
+/**
+ * Facility to set locks for drawing to survive (render) threads accessing drawing data.
+ *
+ * \note Lock can become bit-flag too.
+ * \note Should be replaced in future by better local data handling for threads.
+ */
void BKE_spacedata_draw_locks(bool set);
+/**
+ * Version of #BKE_area_find_region_type that also works if \a slink
+ * is not the active space of \a area.
+ */
struct ARegion *BKE_spacedata_find_region_type(const struct SpaceLink *slink,
const struct ScrArea *area,
int region_type) ATTR_WARN_UNUSED_RESULT
@@ -419,42 +431,68 @@ struct ARegion *BKE_spacedata_find_region_type(const struct SpaceLink *slink,
void BKE_spacedata_callback_id_remap_set(void (*func)(
struct ScrArea *area, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id));
+/**
+ * Currently unused!
+ */
void BKE_spacedata_id_unref(struct ScrArea *area, struct SpaceLink *sl, struct ID *id);
-/* area/regions */
+/* Area/regions. */
+
struct ARegion *BKE_area_region_copy(const struct SpaceType *st, const struct ARegion *region);
+/**
+ * Doesn't free the region itself.
+ */
void BKE_area_region_free(struct SpaceType *st, struct ARegion *region);
void BKE_area_region_panels_free(struct ListBase *panels);
+/**
+ * Doesn't free the area itself.
+ */
void BKE_screen_area_free(struct ScrArea *area);
-/* Gizmo-maps of a region need to be freed with the region.
- * Uses callback to avoid low-level call. */
+/**
+ * Gizmo-maps of a region need to be freed with the region.
+ * Uses callback to avoid low-level call.
+ */
void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *));
void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *));
+/**
+ * Find a region of type \a region_type in the currently active space of \a area.
+ *
+ * \note This does _not_ work if the region to look up is not in the active space.
+ * Use #BKE_spacedata_find_region_type if that may be the case.
+ */
struct ARegion *BKE_area_find_region_type(const struct ScrArea *area, int type);
struct ARegion *BKE_area_find_region_active_win(struct ScrArea *area);
-struct ARegion *BKE_area_find_region_xy(struct ScrArea *area, const int regiontype, int x, int y);
+struct ARegion *BKE_area_find_region_xy(struct ScrArea *area, int regiontype, const int xy[2])
+ ATTR_NONNULL(3);
+/**
+ * \note This is only for screen level regions (typically menus/popups).
+ */
struct ARegion *BKE_screen_find_region_xy(struct bScreen *screen,
- const int regiontype,
- int x,
- int y) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ int regiontype,
+ const int xy[2]) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL(1, 3);
struct ARegion *BKE_screen_find_main_region_at_xy(struct bScreen *screen,
- const int space_type,
- const int x,
- const int y);
-
+ int space_type,
+ const int xy[2]) ATTR_NONNULL(1, 3);
+/**
+ * \note Ideally we can get the area from the context,
+ * there are a few places however where this isn't practical.
+ */
struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen,
struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
-struct ScrArea *BKE_screen_find_big_area(struct bScreen *screen,
- const int spacetype,
- const short min);
+/**
+ * \note Using this function is generally a last resort, you really want to be
+ * using the context when you can - campbell
+ */
+struct ScrArea *BKE_screen_find_big_area(struct bScreen *screen, int spacetype, short min);
struct ScrArea *BKE_screen_area_map_find_area_xy(const struct ScrAreaMap *areamap,
- const int spacetype,
- int x,
- int y);
-struct ScrArea *BKE_screen_find_area_xy(struct bScreen *screen, const int spacetype, int x, int y);
+ int spacetype,
+ const int xy[2]) ATTR_NONNULL(1, 3);
+struct ScrArea *BKE_screen_find_area_xy(struct bScreen *screen, int spacetype, const int xy[2])
+ ATTR_NONNULL(1, 3);
void BKE_screen_gizmo_tag_refresh(struct bScreen *screen);
@@ -464,15 +502,24 @@ bool BKE_screen_is_fullscreen_area(const struct bScreen *screen) ATTR_WARN_UNUSE
ATTR_NONNULL();
bool BKE_screen_is_used(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* zoom factor conversion */
+/* Zoom factor conversion. */
+
float BKE_screen_view3d_zoom_to_fac(float camzoom);
float BKE_screen_view3d_zoom_from_fac(float zoomfac);
void BKE_screen_view3d_shading_init(struct View3DShading *shading);
-/* screen */
+/* Screen. */
+
+/**
+ * Callback used by lib_query to walk over all ID usages
+ * (mimics `foreach_id` callback of #IDTypeInfo structure).
+ */
void BKE_screen_foreach_id_screen_area(struct LibraryForeachIDData *data, struct ScrArea *area);
+/**
+ * Free (or release) any data used by this screen (does not free the screen itself).
+ */
void BKE_screen_free_data(struct bScreen *screen);
void BKE_screen_area_map_free(struct ScrAreaMap *area_map) ATTR_NONNULL();
@@ -488,18 +535,28 @@ void BKE_screen_remove_unused_scrverts(struct bScreen *screen);
void BKE_screen_header_alignment_reset(struct bScreen *screen);
/* .blend file I/O */
+
void BKE_screen_view3d_shading_blend_write(struct BlendWriter *writer,
struct View3DShading *shading);
void BKE_screen_view3d_shading_blend_read_data(struct BlendDataReader *reader,
struct View3DShading *shading);
void BKE_screen_area_map_blend_write(struct BlendWriter *writer, struct ScrAreaMap *area_map);
+/**
+ * \return false on error.
+ */
bool BKE_screen_area_map_blend_read_data(struct BlendDataReader *reader,
struct ScrAreaMap *area_map);
+/**
+ * And as patch for 2.48 and older.
+ */
void BKE_screen_view3d_do_versions_250(struct View3D *v3d, ListBase *regions);
void BKE_screen_area_blend_read_lib(struct BlendLibReader *reader,
struct ID *parent_id,
struct ScrArea *area);
+/**
+ * Cannot use #IDTypeInfo callback yet, because of the return value.
+ */
bool BKE_screen_blend_read_data(struct BlendDataReader *reader, struct bScreen *screen);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h
index 8d1fe709355..432b334a676 100644
--- a/source/blender/blenkernel/BKE_shader_fx.h
+++ b/source/blender/blenkernel/BKE_shader_fx.h
@@ -149,29 +149,47 @@ typedef struct ShaderFxTypeInfo {
#define SHADERFX_TYPE_PANEL_PREFIX "FX_PT_"
-/* Initialize global data (type info and some common global storage). */
+/**
+ * Initialize global data (type info and some common global storage).
+ */
void BKE_shaderfx_init(void);
+/**
+ * Get an effect's panel type, which was defined in the #panelRegister callback.
+ *
+ * \note ShaderFx panel types are assumed to be named with the struct name field concatenated to
+ * the defined prefix.
+ */
void BKE_shaderfxType_panel_id(ShaderFxType type, char *r_idname);
void BKE_shaderfx_panel_expand(struct ShaderFxData *fx);
const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type);
struct ShaderFxData *BKE_shaderfx_new(int type);
-void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag);
+void BKE_shaderfx_free_ex(struct ShaderFxData *fx, int flag);
void BKE_shaderfx_free(struct ShaderFxData *fx);
+/**
+ * Check unique name.
+ */
bool BKE_shaderfx_unique_name(struct ListBase *shaderfx, struct ShaderFxData *fx);
bool BKE_shaderfx_depends_ontime(struct ShaderFxData *fx);
+/**
+ * Check whether given shaderfx is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param shaderfx: May be NULL, in which case we consider it as a non-local shaderfx case.
+ */
bool BKE_shaderfx_is_nonlocal_in_liboverride(const struct Object *ob,
const struct ShaderFxData *shaderfx);
struct ShaderFxData *BKE_shaderfx_findby_type(struct Object *ob, ShaderFxType type);
struct ShaderFxData *BKE_shaderfx_findby_name(struct Object *ob, const char *name);
void BKE_shaderfx_copydata_generic(const struct ShaderFxData *fx_src, struct ShaderFxData *fx_dst);
void BKE_shaderfx_copydata(struct ShaderFxData *fx, struct ShaderFxData *target);
-void BKE_shaderfx_copydata_ex(struct ShaderFxData *fx,
- struct ShaderFxData *target,
- const int flag);
+void BKE_shaderfx_copydata_ex(struct ShaderFxData *fx, struct ShaderFxData *target, int flag);
void BKE_shaderfx_copy(struct ListBase *dst, const struct ListBase *src);
void BKE_shaderfx_foreach_ID_link(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
+/**
+ * Check if exist grease pencil effects.
+ */
bool BKE_shaderfx_has_gpencil(const struct Object *ob);
void BKE_shaderfx_blend_write(struct BlendWriter *writer, struct ListBase *fxbase);
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 70aeb37d995..ea816812344 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -34,11 +34,11 @@ extern "C" {
* Shrinkwrap is composed by a set of functions and options that define the type of shrink.
*
* 3 modes are available:
- * - Nearest vertex
- * - Nearest surface
- * - Normal projection
+ * - Nearest vertex.
+ * - Nearest surface.
+ * - Normal projection.
*
- * ShrinkwrapCalcData encapsulates all needed data for shrinkwrap functions.
+ * #ShrinkwrapCalcData encapsulates all needed data for shrink-wrap functions.
* (So that you don't have to pass an enormous amount of arguments to functions)
*/
@@ -47,6 +47,7 @@ struct MDeformVert;
struct Mesh;
struct ModifierEvalContext;
struct Object;
+struct ShrinkwrapGpencilModifierData;
struct ShrinkwrapModifierData;
struct SpaceTransform;
@@ -74,6 +75,9 @@ typedef struct ShrinkwrapBoundaryData {
const ShrinkwrapBoundaryVertData *boundary_verts;
} ShrinkwrapBoundaryData;
+/**
+ * Free boundary data for target project.
+ */
void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh);
void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh);
@@ -84,72 +88,104 @@ typedef struct ShrinkwrapTreeData {
BVHTree *bvh;
BVHTreeFromMesh treeData;
- float (*pnors)[3];
+ const float (*pnors)[3];
float (*clnors)[3];
ShrinkwrapBoundaryData *boundary;
} ShrinkwrapTreeData;
-/* Checks if the modifier needs target normals with these settings. */
+/**
+ * Checks if the modifier needs target normals with these settings.
+ */
bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode);
-/* Initializes the mesh data structure from the given mesh and settings. */
+/**
+ * Initializes the mesh data structure from the given mesh and settings.
+ */
bool BKE_shrinkwrap_init_tree(struct ShrinkwrapTreeData *data,
Mesh *mesh,
int shrinkType,
int shrinkMode,
bool force_normals);
-/* Frees the tree data if necessary. */
+/**
+ * Frees the tree data if necessary.
+ */
void BKE_shrinkwrap_free_tree(struct ShrinkwrapTreeData *data);
-/* Implementation of the Shrinkwrap modifier */
+/**
+ * Main shrink-wrap function (implementation of the shrink-wrap modifier).
+ */
void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd,
const struct ModifierEvalContext *ctx,
struct Scene *scene,
struct Object *ob,
struct Mesh *mesh,
struct MDeformVert *dvert,
- const int defgrp_index,
+ int defgrp_index,
float (*vertexCos)[3],
int numVerts);
-
-/* Used in editmesh_mask_extract.c to shrinkwrap the extracted mesh to the sculpt */
+/* Implementation of the Shrinkwrap Grease Pencil modifier. */
+void shrinkwrapGpencilModifier_deform(struct ShrinkwrapGpencilModifierData *mmd,
+ struct Object *ob,
+ struct MDeformVert *dvert,
+ int defgrp_index,
+ float (*vertexCos)[3],
+ int numVerts);
+
+/**
+ * Used in `editmesh_mask_extract.c` to shrink-wrap the extracted mesh to the sculpt.
+ */
void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
struct Object *ob_source,
struct Object *ob_target);
-/* Used in object_remesh.cc to preserve the details and volume in the voxel remesher */
+/**
+ * Used in `object_remesh.cc` to preserve the details and volume in the voxel remesher.
+ */
void BKE_shrinkwrap_remesh_target_project(struct Mesh *src_me,
struct Mesh *target_me,
struct Object *ob_target);
-/*
- * This function casts a ray in the given BVHTree.
- * but it takes into consideration the space_transform, that is:
+/**
+ * This function ray-cast a single vertex and updates the hit if the "hit" is considered valid.
*
- * if transf was configured with "SPACE_TRANSFORM_SETUP( &transf, ob1, ob2 )"
- * then the input (vert, dir, BVHTreeRayHit) must be defined in ob1 coordinates space
- * and the BVHTree must be built in ob2 coordinate space.
+ * \param options: Opts control whether an hit is valid or not.
+ * Supported options are:
+ * - #MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored)
+ * - #MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored)
*
+ * \param transf: Take into consideration the space_transform, that is:
+ * if `transf` was configured with `SPACE_TRANSFORM_SETUP( &transf, ob1, ob2)`
+ * then the input (vert, dir, #BVHTreeRayHit) must be defined in ob1 coordinates space
+ * and the #BVHTree must be built in ob2 coordinate space.
* Thus it provides an easy way to cast the same ray across several trees
- * (where each tree was built on its own coords space)
+ * (where each tree was built on its own coords space).
+ *
+ * \return true if "hit" was updated.
*/
bool BKE_shrinkwrap_project_normal(char options,
const float vert[3],
const float dir[3],
- const float ray_radius,
+ float ray_radius,
const struct SpaceTransform *transf,
struct ShrinkwrapTreeData *tree,
BVHTreeRayHit *hit);
-/* Maps the point to the nearest surface, either by simple nearest,
- * or by target normal projection. */
+/**
+ * Maps the point to the nearest surface, either by simple nearest, or by target normal projection.
+ */
void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree,
struct BVHTreeNearest *nearest,
float co[3],
int type);
-/* Computes a smooth normal of the target (if applicable) at the hit location. */
+/**
+ * Compute a smooth normal of the target (if applicable) at the hit location.
+ *
+ * \param tree: information about the mesh.
+ * \param transform: transform from the hit coordinate space to the object space; may be null.
+ * \param r_no: output in hit coordinate space; may be shared with inputs.
+ */
void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
const struct SpaceTransform *transform,
int looptri_idx,
@@ -157,7 +193,13 @@ void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
const float hit_no[3],
float r_no[3]);
-/* Apply the shrink to surface modes to the given original coordinates and nearest point. */
+/**
+ * Apply the shrink to surface modes to the given original coordinates and nearest point.
+ *
+ * \param tree: mesh data for smooth normals.
+ * \param transform: transform from the hit coordinate space to the object space; may be null.
+ * \param r_point_co: may be the same memory location as `point_co`, `hit_co`, or `hit_no`.
+ */
void BKE_shrinkwrap_snap_point_to_surface(const struct ShrinkwrapTreeData *tree,
const struct SpaceTransform *transform,
int mode,
diff --git a/source/blender/blenkernel/BKE_softbody.h b/source/blender/blenkernel/BKE_softbody.h
index 58dc90f62dc..5d010fa2155 100644
--- a/source/blender/blenkernel/BKE_softbody.h
+++ b/source/blender/blenkernel/BKE_softbody.h
@@ -46,16 +46,24 @@ typedef struct BodyPoint {
float springweight;
} BodyPoint;
-/* allocates and initializes general main data */
+/**
+ * Allocates and initializes general main data.
+ */
extern struct SoftBody *sbNew(void);
-/* frees internal data and soft-body itself */
+/**
+ * Frees internal data and soft-body itself.
+ */
extern void sbFree(struct Object *ob);
-/* frees simulation data to reset simulation */
+/**
+ * Frees simulation data to reset simulation.
+ */
extern void sbFreeSimulation(struct SoftBody *sb);
-/* do one simul step, reading and writing vertex locs from given array */
+/**
+ * Do one simulation step, reading and writing vertex locs from given array.
+ * */
extern void sbObjectStep(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -63,13 +71,30 @@ extern void sbObjectStep(struct Depsgraph *depsgraph,
float (*vertexCos)[3],
int numVerts);
-/* makes totally fresh start situation, resets time */
+/**
+ * Makes totally fresh start situation, resets time.
+ */
extern void sbObjectToSoftbody(struct Object *ob);
-/* links the soft-body module to a 'test for Interrupt' function */
-/* pass NULL to unlink again */
+/**
+ * Soft-body global visible functions.
+ * Links the soft-body module to a 'test for Interrupt' function, pass NULL to clear the callback.
+ */
extern void sbSetInterruptCallBack(int (*f)(void));
+/**
+ * A precise position vector denoting the motion of the center of mass give a rotation/scale matrix
+ * using averaging method, that's why estimate and not calculate see: this is kind of reverse
+ * engineering: having to states of a point cloud and recover what happened our advantage here we
+ * know the identity of the vertex there are others methods giving other results.
+ *
+ * \param ob: Any object that can do soft-body e.g. mesh, lattice, curve.
+ * \param lloc: Output of the calculated location (or NULL).
+ * \param lrot: Output of the calculated rotation (or NULL).
+ * \param lscale: Output for the calculated scale (or NULL).
+ *
+ * For velocity & 2nd order stuff see: #vcloud_estimate_transform_v3.
+ */
extern void SB_estimate_transform(Object *ob, float lloc[3], float lrot[3][3], float lscale[3][3]);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index 541ff19c1cd..a87f76da8da 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -24,8 +24,8 @@
#include "FN_generic_virtual_array.hh"
-#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_vector.hh"
#include "BKE_attribute_access.hh"
@@ -40,7 +40,8 @@ using SplinePtr = std::unique_ptr<Spline>;
/**
* A spline is an abstraction of a single branch-less curve section, its evaluation methods,
* and data. The spline data itself is just control points and a set of attributes by the set
- * of "evaluated" data is often used instead.
+ * of "evaluated" data is often used instead. Conceptually, the derived vs. original data is
+ * an essential distinction. Derived data is usually calculated lazily and cached on the spline.
*
* Any derived class of Spline has to manage two things:
* 1. Interpolating arbitrary attribute data from the control points to evaluated points.
@@ -106,8 +107,17 @@ class Spline {
copy_base_settings(other, *this);
}
+ /**
+ * Return a new spline with the same data, settings, and attributes.
+ */
SplinePtr copy() const;
+ /**
+ * Return a new spline with the same type and settings like "cyclic", but without any data.
+ */
SplinePtr copy_only_settings() const;
+ /**
+ * The same as #copy, but skips copying dynamic attributes to the new spline.
+ */
SplinePtr copy_without_attributes() const;
static void copy_base_settings(const Spline &src, Spline &dst);
@@ -117,9 +127,9 @@ class Spline {
virtual int size() const = 0;
int segments_size() const;
bool is_cyclic() const;
- void set_cyclic(const bool value);
+ void set_cyclic(bool value);
- virtual void resize(const int size) = 0;
+ virtual void resize(int size) = 0;
virtual blender::MutableSpan<blender::float3> positions() = 0;
virtual blender::Span<blender::float3> positions() const = 0;
virtual blender::MutableSpan<float> radii() = 0;
@@ -147,11 +157,25 @@ class Spline {
virtual blender::Span<blender::float3> evaluated_positions() const = 0;
+ /**
+ * Return non-owning access to the cache of accumulated lengths along the spline. Each item is
+ * the length of the subsequent segment, i.e. the first value is the length of the first segment
+ * rather than 0. This calculation is rather trivial, and only depends on the evaluated
+ * positions. However, the results are used often, and it is necessarily single threaded, so it
+ * is cached.
+ */
blender::Span<float> evaluated_lengths() const;
+ /**
+ * Return non-owning access to the direction of the curve at each evaluated point.
+ */
blender::Span<blender::float3> evaluated_tangents() const;
+ /**
+ * Return non-owning access to the direction vectors perpendicular to the tangents at every
+ * evaluated point. The method used to generate the normal vectors depends on Spline.normal_mode.
+ */
blender::Span<blender::float3> evaluated_normals() const;
- void bounds_min_max(blender::float3 &min, blender::float3 &max, const bool use_evaluated) const;
+ void bounds_min_max(blender::float3 &min, blender::float3 &max, bool use_evaluated) const;
struct LookupResult {
/**
@@ -172,12 +196,32 @@ class Spline {
*/
float factor;
};
- LookupResult lookup_evaluated_factor(const float factor) const;
- LookupResult lookup_evaluated_length(const float length) const;
+ /**
+ * Find the position on the evaluated spline at the given portion of the total length.
+ * The return value is the indices of the two neighboring points at that location and the
+ * factor between them, which can be used to look up any attribute on the evaluated points.
+ * \note This does not support extrapolation.
+ */
+ LookupResult lookup_evaluated_factor(float factor) const;
+ /**
+ * The same as #lookup_evaluated_factor, but looks up a length directly instead of
+ * a portion of the total.
+ */
+ LookupResult lookup_evaluated_length(float length) const;
- blender::Array<float> sample_uniform_index_factors(const int samples_size) const;
- LookupResult lookup_data_from_index_factor(const float index_factor) const;
+ /**
+ * Return an array of evenly spaced samples along the length of the spline. The samples are
+ * indices and factors to the next index encoded in floats. The logic for converting from the
+ * float values to interpolation data is in #lookup_data_from_index_factor.
+ */
+ blender::Array<float> sample_uniform_index_factors(int samples_size) const;
+ LookupResult lookup_data_from_index_factor(float index_factor) const;
+ /**
+ * Sample any input data with a value for each evaluated point (already interpolated to evaluated
+ * points) to arbitrary parameters in between the evaluated points. The interpolation is quite
+ * simple, but this handles the cyclic and end point special cases.
+ */
void sample_with_index_factors(const blender::fn::GVArray &src,
blender::Span<float> index_factors,
blender::fn::GMutableSpan dst) const;
@@ -187,14 +231,14 @@ class Spline {
blender::MutableSpan<T> dst) const
{
this->sample_with_index_factors(
- blender::fn::GVArray_For_VArray(src), index_factors, blender::fn::GMutableSpan(dst));
+ blender::fn::GVArray(src), index_factors, blender::fn::GMutableSpan(dst));
}
template<typename T>
void sample_with_index_factors(blender::Span<T> src,
blender::Span<float> index_factors,
blender::MutableSpan<T> dst) const
{
- this->sample_with_index_factors(blender::VArray_For_Span(src), index_factors, dst);
+ this->sample_with_index_factors(blender::VArray<T>::ForSpan(src), index_factors, dst);
}
/**
@@ -202,13 +246,11 @@ class Spline {
* evaluated points. For poly splines, the lifetime of the returned virtual array must not
* exceed the lifetime of the input data.
*/
- virtual blender::fn::GVArrayPtr interpolate_to_evaluated(
- const blender::fn::GVArray &src) const = 0;
- blender::fn::GVArrayPtr interpolate_to_evaluated(blender::fn::GSpan data) const;
- template<typename T>
- blender::fn::GVArray_Typed<T> interpolate_to_evaluated(blender::Span<T> data) const
+ virtual blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const = 0;
+ blender::fn::GVArray interpolate_to_evaluated(blender::fn::GSpan data) const;
+ template<typename T> blender::VArray<T> interpolate_to_evaluated(blender::Span<T> data) const
{
- return blender::fn::GVArray_Typed<T>(this->interpolate_to_evaluated(blender::fn::GSpan(data)));
+ return this->interpolate_to_evaluated(blender::fn::GSpan(data)).typed<T>();
}
protected:
@@ -286,17 +328,9 @@ class BezierSpline final : public Spline {
int size() const final;
int resolution() const;
- void set_resolution(const int value);
+ void set_resolution(int value);
- void add_point(const blender::float3 position,
- const HandleType handle_type_left,
- const blender::float3 handle_position_left,
- const HandleType handle_type_right,
- const blender::float3 handle_position_right,
- const float radius,
- const float tilt);
-
- void resize(const int size) final;
+ void resize(int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
blender::MutableSpan<float> radii() final;
@@ -306,22 +340,64 @@ class BezierSpline final : public Spline {
blender::Span<HandleType> handle_types_left() const;
blender::MutableSpan<HandleType> handle_types_left();
blender::Span<blender::float3> handle_positions_left() const;
- blender::MutableSpan<blender::float3> handle_positions_left();
+ /**
+ * Get writable access to the handle position.
+ *
+ * \param write_only: pass true for an uninitialized spline, this prevents accessing
+ * uninitialized memory while auto-generating handles.
+ */
+ blender::MutableSpan<blender::float3> handle_positions_left(bool write_only = false);
blender::Span<HandleType> handle_types_right() const;
blender::MutableSpan<HandleType> handle_types_right();
blender::Span<blender::float3> handle_positions_right() const;
- blender::MutableSpan<blender::float3> handle_positions_right();
+ /**
+ * Get writable access to the handle position.
+ *
+ * \param write_only: pass true for an uninitialized spline, this prevents accessing
+ * uninitialized memory while auto-generating handles.
+ */
+ blender::MutableSpan<blender::float3> handle_positions_right(bool write_only = false);
+ /**
+ * Recalculate all #Auto and #Vector handles with positions automatically
+ * derived from the neighboring control points.
+ */
void ensure_auto_handles() const;
void translate(const blender::float3 &translation) override;
void transform(const blender::float4x4 &matrix) override;
- bool point_is_sharp(const int index) const;
+ /**
+ * Set positions for the right handle of the control point, ensuring that
+ * aligned handles stay aligned. Has no effect for auto and vector type handles.
+ */
+ void set_handle_position_right(int index, const blender::float3 &value);
+ /**
+ * Set positions for the left handle of the control point, ensuring that
+ * aligned handles stay aligned. Has no effect for auto and vector type handles.
+ */
+ void set_handle_position_left(int index, const blender::float3 &value);
+
+ bool point_is_sharp(int index) const;
void mark_cache_invalid() final;
int evaluated_points_size() const final;
+ /**
+ * Returns access to a cache of offsets into the evaluated point array for each control point.
+ * While most control point edges generate the number of edges specified by the resolution,
+ * vector segments only generate one edge.
+ *
+ * \note The length of the result is one greater than the number of points, so that the last item
+ * is the total number of evaluated points. This is useful to avoid recalculating the size of the
+ * last segment everywhere.
+ */
blender::Span<int> control_point_offsets() const;
+ /**
+ * Returns non-owning access to an array of values containing the information necessary to
+ * interpolate values from the original control points to evaluated points. The control point
+ * index is the integer part of each value, and the factor used for interpolating to the next
+ * control point is the remaining factional part.
+ */
blender::Span<float> evaluated_mappings() const;
blender::Span<blender::float3> evaluated_positions() const final;
struct InterpolationData {
@@ -333,15 +409,23 @@ class BezierSpline final : public Spline {
*/
float factor;
};
- InterpolationData interpolation_data_from_index_factor(const float index_factor) const;
+ /**
+ * Convert the data encoded in #evaulated_mappings into its parts-- the information necessary
+ * to interpolate data from control points to evaluated points between them. The next control
+ * point index result will not overflow the size of the control point vectors.
+ */
+ InterpolationData interpolation_data_from_index_factor(float index_factor) const;
- virtual blender::fn::GVArrayPtr interpolate_to_evaluated(
+ virtual blender::fn::GVArray interpolate_to_evaluated(
const blender::fn::GVArray &src) const override;
- void evaluate_segment(const int index,
- const int next_index,
+ void evaluate_segment(int index,
+ int next_index,
blender::MutableSpan<blender::float3> positions) const;
- bool segment_is_vector(const int start_index) const;
+ /**
+ * \warning This functional assumes that the spline has more than one point.
+ */
+ bool segment_is_vector(int start_index) const;
/** See comment and diagram for #calculate_segment_insertion. */
struct InsertResult {
@@ -351,11 +435,34 @@ class BezierSpline final : public Spline {
blender::float3 right_handle;
blender::float3 handle_next;
};
- InsertResult calculate_segment_insertion(const int index,
- const int next_index,
- const float parameter);
+ /**
+ * De Casteljau Bezier subdivision.
+ * \param index: The index of the segment's start control point.
+ * \param next_index: The index of the control point at the end of the segment. Could be 0,
+ * if the spline is cyclic.
+ * \param parameter: The factor along the segment, between 0 and 1. Note that this is used
+ * directly by the calculation, it doesn't correspond to a portion of the evaluated length.
+ *
+ * <pre>
+ * handle_prev handle_next
+ * x----------------x
+ * / \
+ * / x---O---x \
+ * / result \
+ * / \
+ * O O
+ * point_prev point_next
+ * </pre>
+ */
+ InsertResult calculate_segment_insertion(int index, int next_index, float parameter);
private:
+ /**
+ * If the spline is not cyclic, the direction for the first and last points is just the
+ * direction formed by the corresponding handles and control points. In the unlikely situation
+ * that the handles define a zero direction, fallback to using the direction defined by the
+ * first and last evaluated segments already calculated in #Spline::evaluated_tangents().
+ */
void correct_end_tangents() const final;
void copy_settings(Spline &dst) const final;
void copy_data(Spline &dst) const final;
@@ -443,19 +550,14 @@ class NURBSpline final : public Spline {
int size() const final;
int resolution() const;
- void set_resolution(const int value);
+ void set_resolution(int value);
uint8_t order() const;
- void set_order(const uint8_t value);
-
- void add_point(const blender::float3 position,
- const float radius,
- const float tilt,
- const float weight);
+ void set_order(uint8_t value);
bool check_valid_size_and_order() const;
int knots_size() const;
- void resize(const int size) final;
+ void resize(int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
blender::MutableSpan<float> radii() final;
@@ -472,7 +574,7 @@ class NURBSpline final : public Spline {
blender::Span<blender::float3> evaluated_positions() const final;
- blender::fn::GVArrayPtr interpolate_to_evaluated(const blender::fn::GVArray &src) const final;
+ blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const final;
protected:
void correct_end_tangents() const final;
@@ -485,9 +587,12 @@ class NURBSpline final : public Spline {
};
/**
- * A Poly spline is like a bezier spline with a resolution of one. The main reason to distinguish
+ * A Poly spline is like a Bézier spline with a resolution of one. The main reason to distinguish
* the two is for reduced complexity and increased performance, since interpolating data to control
* points does not change it.
+ *
+ * Poly spline code is very simple, since it doesn't do anything that the base #Spline doesn't
+ * handle. Mostly it just worries about storing the data used by the base class.
*/
class PolySpline final : public Spline {
blender::Vector<blender::float3> positions_;
@@ -508,9 +613,7 @@ class PolySpline final : public Spline {
int size() const final;
- void add_point(const blender::float3 position, const float radius, const float tilt);
-
- void resize(const int size) final;
+ void resize(int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
blender::MutableSpan<float> radii() final;
@@ -523,7 +626,13 @@ class PolySpline final : public Spline {
blender::Span<blender::float3> evaluated_positions() const final;
- blender::fn::GVArrayPtr interpolate_to_evaluated(const blender::fn::GVArray &src) const final;
+ /**
+ * Poly spline interpolation from control points to evaluated points is a special case, since
+ * the result data is the same as the input data. This function returns a #GVArray that points to
+ * the original data. Therefore the lifetime of the returned virtual array must not be longer
+ * than the source data.
+ */
+ blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const final;
protected:
void correct_end_tangents() const final;
@@ -533,8 +642,12 @@ class PolySpline final : public Spline {
};
/**
- * A #CurveEval corresponds to the #Curve object data. The name is different for clarity, since
- * more of the data is stored in the splines, but also just to be different than the name in DNA.
+ * A collection of #Spline objects with the same attribute types and names. Most data and
+ * functionality is in splines, but this contains some helpers for working with them as a group.
+ *
+ * \note A #CurveEval corresponds to the #Curve object data. The name is different for clarity,
+ * since more of the data is stored in the splines, but also just to be different than the name in
+ * DNA.
*/
struct CurveEval {
private:
@@ -553,20 +666,56 @@ struct CurveEval {
blender::Span<SplinePtr> splines() const;
blender::MutableSpan<SplinePtr> splines();
+ /**
+ * \return True if the curve contains a spline with the given type.
+ *
+ * \note If you are looping over all of the splines in the same scope anyway,
+ * it's better to avoid calling this function, in case there are many splines.
+ */
bool has_spline_with_type(const Spline::Type type) const;
- void resize(const int size);
+ void resize(int size);
+ /**
+ * \warning Call #reallocate on the spline's attributes after adding all splines.
+ */
void add_spline(SplinePtr spline);
+ void add_splines(blender::MutableSpan<SplinePtr> splines);
void remove_splines(blender::IndexMask mask);
void translate(const blender::float3 &translation);
void transform(const blender::float4x4 &matrix);
- void bounds_min_max(blender::float3 &min, blender::float3 &max, const bool use_evaluated) const;
+ bool bounds_min_max(blender::float3 &min, blender::float3 &max, bool use_evaluated) const;
+ /**
+ * Return the start indices for each of the curve spline's control points, if they were part
+ * of a flattened array. This can be used to facilitate parallelism by avoiding the need to
+ * accumulate an offset while doing more complex calculations.
+ *
+ * \note The result is one longer than the spline count; the last element is the total size.
+ */
blender::Array<int> control_point_offsets() const;
+ /**
+ * Exactly like #control_point_offsets, but uses the number of evaluated points instead.
+ */
blender::Array<int> evaluated_point_offsets() const;
+ /**
+ * Return the accumulated length at the start of every spline in the curve.
+ * \note The result is one longer than the spline count; the last element is the total length.
+ */
blender::Array<float> accumulated_spline_lengths() const;
+ float total_length() const;
+ int total_control_point_size() const;
+
+ void mark_cache_invalid();
+
+ /**
+ * Check the invariants that curve control point attributes should always uphold, necessary
+ * because attributes are stored on splines rather than in a flat array on the curve:
+ * - The same set of attributes exists on every spline.
+ * - Attributes with the same name have the same type on every spline.
+ * - Attributes are in the same order on every spline.
+ */
void assert_valid_point_attributes() const;
};
diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h
index 59b1c2b28d9..792186dd260 100644
--- a/source/blender/blenkernel/BKE_studiolight.h
+++ b/source/blender/blenkernel/BKE_studiolight.h
@@ -143,6 +143,8 @@ typedef struct StudioLight {
void *free_function_data;
} StudioLight;
+/* API */
+
void BKE_studiolight_init(void);
void BKE_studiolight_free(void);
void BKE_studiolight_default(SolidLight lights[4], float light_ambient[3]);
@@ -151,12 +153,18 @@ struct StudioLight *BKE_studiolight_findindex(int index, int flag);
struct StudioLight *BKE_studiolight_find_default(int flag);
void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type);
struct ListBase *BKE_studiolight_listbase(void);
+/**
+ * Ensure state of studio-lights.
+ */
void BKE_studiolight_ensure_flag(StudioLight *sl, int flag);
void BKE_studiolight_refresh(void);
StudioLight *BKE_studiolight_load(const char *path, int type);
StudioLight *BKE_studiolight_create(const char *path,
const SolidLight light[4],
const float light_ambient[3]);
+/**
+ * Only useful for workbench while editing the user-preferences.
+ */
StudioLight *BKE_studiolight_studio_edit_get(void);
void BKE_studiolight_remove(StudioLight *sl);
void BKE_studiolight_set_free_function(StudioLight *sl,
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
index 2fb27fad30d..697b3e9ace7 100644
--- a/source/blender/blenkernel/BKE_subdiv.h
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -151,9 +151,9 @@ typedef struct SubdivDisplacement {
* Averaging of displacement for vertices created for over coarse vertices
* and edges is done by subdiv code. */
void (*eval_displacement)(struct SubdivDisplacement *displacement,
- const int ptex_face_index,
- const float u,
- const float v,
+ int ptex_face_index,
+ float u,
+ float v,
const float dPdu[3],
const float dPdv[3],
float r_D[3]);
@@ -188,7 +188,16 @@ typedef struct Subdiv {
/* Cached values, are not supposed to be accessed directly. */
struct {
/* Indexed by base face index, element indicates total number of ptex
- * faces created for preceding base faces. */
+ * faces created for preceding base faces. This also stores the final
+ * ptex offset (the total number of PTex faces) at the end of the array
+ * so that algorithms can compute the number of ptex faces for a given
+ * face by computing the delta with the offset for the next face without
+ * using a separate data structure, e.g.:
+ *
+ * const int num_face_ptex_faces = face_ptex_offset[i + 1] - face_ptex_offset[i];
+ *
+ * In total this array has a size of `num base faces + 1`.
+ */
int *face_ptex_offset;
} cache_;
} Subdiv;
@@ -257,45 +266,48 @@ void BKE_subdiv_displacement_detach(Subdiv *subdiv);
/* ============================ TOPOLOGY HELPERS ============================ */
+/* For each element in the array, this stores the total number of ptex faces up to that element,
+ * with the total number of ptex faces being the last element in the array. The array is of length
+ * `base face count + 1`. */
int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv);
/* =========================== PTEX FACES AND GRIDS ========================= */
/* For a given (ptex_u, ptex_v) within a ptex face get corresponding
* (grid_u, grid_v) within a grid. */
-BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv(const float ptex_u,
- const float ptex_v,
+BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv(float ptex_u,
+ float ptex_v,
float *r_grid_u,
float *r_grid_v);
/* Inverse of above. */
-BLI_INLINE void BKE_subdiv_grid_uv_to_ptex_face_uv(const float grid_u,
- const float grid_v,
+BLI_INLINE void BKE_subdiv_grid_uv_to_ptex_face_uv(float grid_u,
+ float grid_v,
float *r_ptex_u,
float *r_ptex_v);
/* For a given subdivision level (which is NOT refinement level) get size of
* CCG grid (number of grid points on a side).
*/
-BLI_INLINE int BKE_subdiv_grid_size_from_level(const int level);
+BLI_INLINE int BKE_subdiv_grid_size_from_level(int level);
/* Simplified version of mdisp_rot_face_to_crn, only handles quad and
* works in normalized coordinates.
*
* NOTE: Output coordinates are in ptex coordinates. */
-BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(const float quad_u,
- const float quad_v,
+BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(float quad_u,
+ float quad_v,
float *r_corner_u,
float *r_corner_v);
/* Converts (u, v) coordinate from within a grid to a quad coordinate in
* normalized ptex coordinates. */
BLI_INLINE void BKE_subdiv_rotate_grid_to_quad(
- const int corner, const float grid_u, const float grid_v, float *r_quad_u, float *r_quad_v);
+ int corner, float grid_u, float grid_v, float *r_quad_u, float *r_quad_v);
/* Convert Blender edge crease value to OpenSubdiv sharpness. */
-BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_f(float edge_crease);
-BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_char(char edge_crease);
+BLI_INLINE float BKE_subdiv_crease_to_sharpness_f(float edge_crease);
+BLI_INLINE float BKE_subdiv_crease_to_sharpness_char(char edge_crease);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h
index b7d4ab8d8ed..b3aa966e0d0 100644
--- a/source/blender/blenkernel/BKE_subdiv_ccg.h
+++ b/source/blender/blenkernel/BKE_subdiv_ccg.h
@@ -46,9 +46,9 @@ struct Subdiv;
/* Functor which evaluates mask value at a given (u, v) of given ptex face. */
typedef struct SubdivCCGMaskEvaluator {
float (*eval_mask)(struct SubdivCCGMaskEvaluator *mask_evaluator,
- const int ptex_face_index,
- const float u,
- const float v);
+ int ptex_face_index,
+ float u,
+ float v);
/* Free the data, not the evaluator itself. */
void (*free)(struct SubdivCCGMaskEvaluator *mask_evaluator);
@@ -67,8 +67,7 @@ bool BKE_subdiv_ccg_mask_init_from_paint(SubdivCCGMaskEvaluator *mask_evaluator,
/* Functor which evaluates material and flags of a given coarse face. */
typedef struct SubdivCCGMaterialFlagsEvaluator {
DMFlagMat (*eval_material_flags)(
- struct SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator,
- const int coarse_face_index);
+ struct SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator, int coarse_face_index);
/* Free the data, not the evaluator itself. */
void (*free)(struct SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator);
@@ -307,10 +306,10 @@ bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG *subdiv_ccg, const SubdivC
* the current vertex are added at the end of the coords array. */
void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
- const bool include_duplicates,
+ bool include_duplicates,
SubdivCCGNeighbors *r_neighbors);
-int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int grid_index);
+int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, int grid_index);
void BKE_subdiv_ccg_eval_limit_point(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
float r_point[3]);
diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h
index 0b61e62c89c..23bcdcce276 100644
--- a/source/blender/blenkernel/BKE_subdiv_eval.h
+++ b/source/blender/blenkernel/BKE_subdiv_eval.h
@@ -30,16 +30,26 @@ extern "C" {
#endif
struct Mesh;
+struct OpenSubdiv_EvaluatorCache;
struct Subdiv;
+typedef enum eSubdivEvaluatorType {
+ SUBDIV_EVALUATOR_TYPE_CPU,
+ SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE,
+} eSubdivEvaluatorType;
+
/* Returns true if evaluator is ready for use. */
-bool BKE_subdiv_eval_begin(struct Subdiv *subdiv);
+bool BKE_subdiv_eval_begin(struct Subdiv *subdiv,
+ eSubdivEvaluatorType evaluator_type,
+ struct OpenSubdiv_EvaluatorCache *evaluator_cache);
/* coarse_vertex_cos is an optional argument which allows to override coordinates of the coarse
* mesh. */
bool BKE_subdiv_eval_begin_from_mesh(struct Subdiv *subdiv,
const struct Mesh *mesh,
- const float (*coarse_vertex_cos)[3]);
+ const float (*coarse_vertex_cos)[3],
+ eSubdivEvaluatorType evaluator_type,
+ struct OpenSubdiv_EvaluatorCache *evaluator_cache);
bool BKE_subdiv_eval_refine_from_mesh(struct Subdiv *subdiv,
const struct Mesh *mesh,
const float (*coarse_vertex_cos)[3]);
@@ -55,33 +65,23 @@ void BKE_subdiv_eval_init_displacement(struct Subdiv *subdiv);
/* Evaluate point at a limit surface, with optional derivatives and normal. */
void BKE_subdiv_eval_limit_point(
- struct Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3]);
+ struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3]);
void BKE_subdiv_eval_limit_point_and_derivatives(struct Subdiv *subdiv,
- const int ptex_face_index,
- const float u,
- const float v,
+ int ptex_face_index,
+ float u,
+ float v,
float r_P[3],
float r_dPdu[3],
float r_dPdv[3]);
-void BKE_subdiv_eval_limit_point_and_normal(struct Subdiv *subdiv,
- const int ptex_face_index,
- const float u,
- const float v,
- float r_P[3],
- float r_N[3]);
-void BKE_subdiv_eval_limit_point_and_short_normal(struct Subdiv *subdiv,
- const int ptex_face_index,
- const float u,
- const float v,
- float r_P[3],
- short r_N[3]);
+void BKE_subdiv_eval_limit_point_and_normal(
+ struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3], float r_N[3]);
/* Evaluate face-varying layer (such as UV). */
void BKE_subdiv_eval_face_varying(struct Subdiv *subdiv,
- const int face_varying_channel,
- const int ptex_face_index,
- const float u,
- const float v,
+ int face_varying_channel,
+ int ptex_face_index,
+ float u,
+ float v,
float r_face_varying[2]);
/* NOTE: Expects derivatives to be correct.
@@ -91,59 +91,16 @@ void BKE_subdiv_eval_face_varying(struct Subdiv *subdiv,
* Would be nice to have displacement evaluation function which does not require
* knowing derivatives ahead of a time. */
void BKE_subdiv_eval_displacement(struct Subdiv *subdiv,
- const int ptex_face_index,
- const float u,
- const float v,
+ int ptex_face_index,
+ float u,
+ float v,
const float dPdu[3],
const float dPdv[3],
float r_D[3]);
/* Evaluate point on a limit surface with displacement applied to it. */
void BKE_subdiv_eval_final_point(
- struct Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3]);
-
-/* Patch queries at given resolution.
- *
- * Will evaluate patch at uniformly distributed (u, v) coordinates on a grid
- * of given resolution, producing resolution^2 evaluation points. The order
- * goes as u in rows, v in columns. */
-
-void BKE_subdiv_eval_limit_patch_resolution_point(struct Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *buffer,
- const int offset,
- const int stride);
-void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives(struct Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer,
- const int point_offset,
- const int point_stride,
- void *du_buffer,
- const int du_offset,
- const int du_stride,
- void *dv_buffer,
- const int dv_offset,
- const int dv_stride);
-void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(struct Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer,
- const int point_offset,
- const int point_stride,
- void *normal_buffer,
- const int normal_offset,
- const int normal_stride);
-void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(struct Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer,
- const int point_offset,
- const int point_stride,
- void *normal_buffer,
- const int normal_offset,
- const int normal_stride);
+ struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3]);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_subdiv_foreach.h b/source/blender/blenkernel/BKE_subdiv_foreach.h
index 3f74299455d..7d9a589666a 100644
--- a/source/blender/blenkernel/BKE_subdiv_foreach.h
+++ b/source/blender/blenkernel/BKE_subdiv_foreach.h
@@ -35,76 +35,77 @@ struct SubdivForeachContext;
struct SubdivToMeshSettings;
typedef bool (*SubdivForeachTopologyInformationCb)(const struct SubdivForeachContext *context,
- const int num_vertices,
- const int num_edges,
- const int num_loops,
- const int num_polygons);
+ int num_vertices,
+ int num_edges,
+ int num_loops,
+ int num_polygons,
+ const int *subdiv_polygon_offset);
typedef void (*SubdivForeachVertexFromCornerCb)(const struct SubdivForeachContext *context,
void *tls,
- const int ptex_face_index,
- const float u,
- const float v,
- const int coarse_vertex_index,
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_vertex_index);
+ int ptex_face_index,
+ float u,
+ float v,
+ int coarse_vertex_index,
+ int coarse_poly_index,
+ int coarse_corner,
+ int subdiv_vertex_index);
typedef void (*SubdivForeachVertexFromEdgeCb)(const struct SubdivForeachContext *context,
void *tls,
- const int ptex_face_index,
- const float u,
- const float v,
- const int coarse_edge_index,
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_vertex_index);
+ int ptex_face_index,
+ float u,
+ float v,
+ int coarse_edge_index,
+ int coarse_poly_index,
+ int coarse_corner,
+ int subdiv_vertex_index);
typedef void (*SubdivForeachVertexInnerCb)(const struct SubdivForeachContext *context,
void *tls,
- const int ptex_face_index,
- const float u,
- const float v,
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_vertex_index);
+ int ptex_face_index,
+ float u,
+ float v,
+ int coarse_poly_index,
+ int coarse_corner,
+ int subdiv_vertex_index);
typedef void (*SubdivForeachEdgeCb)(const struct SubdivForeachContext *context,
void *tls,
- const int coarse_edge_index,
- const int subdiv_edge_index,
- const int subdiv_v1,
- const int subdiv_v2);
+ int coarse_edge_index,
+ int subdiv_edge_index,
+ int subdiv_v1,
+ int subdiv_v2);
typedef void (*SubdivForeachLoopCb)(const struct SubdivForeachContext *context,
void *tls,
- const int ptex_face_index,
- const float u,
- const float v,
- const int coarse_loop_index,
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_loop_index,
- const int subdiv_vertex_index,
- const int subdiv_edge_index);
+ int ptex_face_index,
+ float u,
+ float v,
+ int coarse_loop_index,
+ int coarse_poly_index,
+ int coarse_corner,
+ int subdiv_loop_index,
+ int subdiv_vertex_index,
+ int subdiv_edge_index);
typedef void (*SubdivForeachPolygonCb)(const struct SubdivForeachContext *context,
void *tls,
- const int coarse_poly_index,
- const int subdiv_poly_index,
- const int start_loop_index,
- const int num_loops);
+ int coarse_poly_index,
+ int subdiv_poly_index,
+ int start_loop_index,
+ int num_loops);
typedef void (*SubdivForeachLooseCb)(const struct SubdivForeachContext *context,
void *tls,
- const int coarse_vertex_index,
- const int subdiv_vertex_index);
+ int coarse_vertex_index,
+ int subdiv_vertex_index);
typedef void (*SubdivForeachVertexOfLooseEdgeCb)(const struct SubdivForeachContext *context,
void *tls,
- const int coarse_edge_index,
- const float u,
- const int subdiv_vertex_index);
+ int coarse_edge_index,
+ float u,
+ int subdiv_vertex_index);
typedef struct SubdivForeachContext {
/* Is called when topology information becomes available.
diff --git a/source/blender/blenkernel/BKE_subdiv_modifier.h b/source/blender/blenkernel/BKE_subdiv_modifier.h
new file mode 100644
index 00000000000..8a179206dd7
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_modifier.h
@@ -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.
+ *
+ * The Original Code is Copyright (C) 2021 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#pragma once
+
+#include "BLI_sys_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Mesh;
+struct Object;
+struct Scene;
+struct Subdiv;
+struct SubdivSettings;
+struct SubsurfModifierData;
+
+void BKE_subsurf_modifier_subdiv_settings_init(struct SubdivSettings *settings,
+ const struct SubsurfModifierData *smd,
+ bool use_render_params);
+
+/**
+ * \param skip_check_is_last: When true, we assume that the modifier passed is the last enabled
+ * modifier in the stack.
+ */
+bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const struct Scene *scene,
+ const struct Object *ob,
+ const struct SubsurfModifierData *smd,
+ int required_mode,
+ bool skip_check_is_last);
+
+bool BKE_subsurf_modifier_can_do_gpu_subdiv(const struct Scene *scene,
+ const struct Object *ob,
+ int required_mode);
+
+extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(struct Subdiv *subdiv);
+
+/**
+ * Main goal of this function is to give usable subdivision surface descriptor
+ * which matches settings and topology.
+ */
+struct Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(
+ const struct SubsurfModifierData *smd,
+ const struct SubdivSettings *subdiv_settings,
+ const struct Mesh *mesh,
+ bool for_draw_code);
+
+struct SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(struct SubsurfModifierData *smd);
+
+/**
+ * Return the #ModifierMode required for the evaluation of the subsurf modifier,
+ * which should be used to check if the modifier is enabled.
+ */
+int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 3816a822279..db57076082c 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -66,18 +66,30 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
void subsurf_calculate_limit_positions(struct Mesh *me, float (*r_positions)[3]);
-/* get gridsize from 'level', level must be greater than zero */
+/**
+ * Get grid-size from 'level', level must be greater than zero.
+ */
int BKE_ccg_gridsize(int level);
-/* x/y grid coordinates at 'low_level' can be multiplied by the result
- * of this function to convert to grid coordinates at 'high_level' */
+/**
+ * X/Y grid coordinates at 'low_level' can be multiplied by the result
+ * of this function to convert to grid coordinates at 'high_level'.
+ */
int BKE_ccg_factor(int low_level, int high_level);
+/**
+ * Translate #GridHidden into the #ME_HIDE flag for MVerts. Assumes
+ * vertices are in the order output by #ccgDM_copyFinalVertArray.
+ */
void subsurf_copy_grid_hidden(struct DerivedMesh *dm,
const struct MPoly *mpoly,
struct MVert *mvert,
const struct MDisps *mdisps);
+/**
+ * Translate #GridPaintMask into vertex paint masks. Assumes vertices
+ * are in the order output by #ccgDM_copyFinalVertArray.
+ */
void subsurf_copy_grid_paint_mask(struct DerivedMesh *dm,
const struct MPoly *mpoly,
float *paint_mask,
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index c7120c60020..7415cb90ff2 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -30,43 +30,78 @@ struct Main;
struct Text;
struct TextLine;
+/**
+ * \note caller must handle `compiled` member.
+ */
void BKE_text_free_lines(struct Text *text);
struct Text *BKE_text_add(struct Main *bmain, const char *name);
+/**
+ * Use to a valid UTF-8 sequences.
+ * this function replaces extended ascii characters.
+ */
int txt_extended_ascii_as_utf8(char **str);
bool BKE_text_reload(struct Text *text);
+/**
+ * Load a text file.
+ *
+ * \param is_internal: If \a true, this text data-block only exists in memory,
+ * not as a file on disk.
+ *
+ * \note text data-blocks have no real user but have 'fake user' enabled by default
+ */
struct Text *BKE_text_load_ex(struct Main *bmain,
const char *file,
const char *relpath,
- const bool is_internal);
+ bool is_internal);
+/**
+ * Load a text file.
+ *
+ * \note Text data-blocks have no user by default, only the 'real user' flag.
+ */
struct Text *BKE_text_load(struct Main *bmain, const char *file, const char *relpath);
void BKE_text_clear(struct Text *text);
void BKE_text_write(struct Text *text, const char *str);
+/**
+ * \return codes:
+ * - 0 if file on disk is the same or Text is in memory only.
+ * - 1 if file has been modified on disk since last local edit.
+ * - 2 if file on disk has been deleted.
+ * - -1 is returned if an error occurs.
+ */
int BKE_text_file_modified_check(struct Text *text);
void BKE_text_file_modified_ignore(struct Text *text);
char *txt_to_buf(struct Text *text, int *r_buf_strlen);
void txt_clean_text(struct Text *text);
-void txt_order_cursors(struct Text *text, const bool reverse);
+void txt_order_cursors(struct Text *text, bool reverse);
int txt_find_string(struct Text *text, const char *findstr, int wrap, int match_case);
bool txt_has_sel(const struct Text *text);
int txt_get_span(struct TextLine *from, struct TextLine *to);
-void txt_move_up(struct Text *text, const bool sel);
-void txt_move_down(struct Text *text, const bool sel);
-void txt_move_left(struct Text *text, const bool sel);
-void txt_move_right(struct Text *text, const bool sel);
-void txt_jump_left(struct Text *text, const bool sel, const bool use_init_step);
-void txt_jump_right(struct Text *text, const bool sel, const bool use_init_step);
-void txt_move_bof(struct Text *text, const bool sel);
-void txt_move_eof(struct Text *text, const bool sel);
-void txt_move_bol(struct Text *text, const bool sel);
-void txt_move_eol(struct Text *text, const bool sel);
-void txt_move_toline(struct Text *text, unsigned int line, const bool sel);
-void txt_move_to(struct Text *text, unsigned int line, unsigned int ch, const bool sel);
+void txt_move_up(struct Text *text, bool sel);
+void txt_move_down(struct Text *text, bool sel);
+void txt_move_left(struct Text *text, bool sel);
+void txt_move_right(struct Text *text, bool sel);
+void txt_jump_left(struct Text *text, bool sel, bool use_init_step);
+void txt_jump_right(struct Text *text, bool sel, bool use_init_step);
+void txt_move_bof(struct Text *text, bool sel);
+void txt_move_eof(struct Text *text, bool sel);
+void txt_move_bol(struct Text *text, bool sel);
+void txt_move_eol(struct Text *text, bool sel);
+void txt_move_toline(struct Text *text, unsigned int line, bool sel);
+/**
+ * Moves to a certain byte in a line, not a certain utf8-character.
+ */
+void txt_move_to(struct Text *text, unsigned int line, unsigned int ch, bool sel);
void txt_pop_sel(struct Text *text);
void txt_delete_char(struct Text *text);
void txt_delete_word(struct Text *text);
void txt_delete_selected(struct Text *text);
void txt_sel_all(struct Text *text);
+/**
+ * Reverse of #txt_pop_sel
+ * Clears the selection and ensures the cursor is located
+ * at the selection (where the cursor is visually while editing).
+ */
void txt_sel_clear(struct Text *text);
void txt_sel_line(struct Text *text);
void txt_sel_set(struct Text *text, int startl, int startc, int endl, int endc);
@@ -82,7 +117,7 @@ bool txt_unindent(struct Text *text);
void txt_comment(struct Text *text);
void txt_indent(struct Text *text);
bool txt_uncomment(struct Text *text);
-void txt_move_lines(struct Text *text, const int direction);
+void txt_move_lines(struct Text *text, int direction);
void txt_duplicate_line(struct Text *text);
int txt_setcurr_tab_spaces(struct Text *text, int space);
bool txt_cursor_is_line_start(const struct Text *text);
@@ -91,18 +126,20 @@ bool txt_cursor_is_line_end(const struct Text *text);
int txt_calc_tab_left(struct TextLine *tl, int ch);
int txt_calc_tab_right(struct TextLine *tl, int ch);
-/* Utility functions, could be moved somewhere more generic but are python/text related. */
-int text_check_bracket(const char ch);
-bool text_check_delim(const char ch);
-bool text_check_digit(const char ch);
-bool text_check_identifier(const char ch);
-bool text_check_identifier_nodigit(const char ch);
-bool text_check_whitespace(const char ch);
+/**
+ * Utility functions, could be moved somewhere more generic but are python/text related.
+ */
+int text_check_bracket(char ch);
+bool text_check_delim(char ch);
+bool text_check_digit(char ch);
+bool text_check_identifier(char ch);
+bool text_check_identifier_nodigit(char ch);
+bool text_check_whitespace(char ch);
int text_find_identifier_start(const char *str, int i);
-/* defined in bpy_interface.c */
-extern int text_check_identifier_unicode(const unsigned int ch);
-extern int text_check_identifier_nodigit_unicode(const unsigned int ch);
+/* EVIL: defined in `bpy_interface.c`. */
+extern int text_check_identifier_unicode(unsigned int ch);
+extern int text_check_identifier_nodigit_unicode(unsigned int ch);
enum {
TXT_MOVE_LINE_UP = -1,
@@ -110,7 +147,14 @@ enum {
};
/* Fast non-validating buffer conversion for undo. */
+
+/**
+ * Create a buffer, the only requirement is #txt_from_buf_for_undo can decode it.
+ */
char *txt_to_buf_for_undo(struct Text *text, int *r_buf_len);
+/**
+ * Decode a buffer from #txt_to_buf_for_undo.
+ */
void txt_from_buf_for_undo(struct Text *text, const char *buf, int buf_len);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_text_suggestions.h b/source/blender/blenkernel/BKE_text_suggestions.h
index 7561e1d1d08..482141c1032 100644
--- a/source/blender/blenkernel/BKE_text_suggestions.h
+++ b/source/blender/blenkernel/BKE_text_suggestions.h
@@ -66,7 +66,7 @@ short texttool_text_is_active(struct Text *text);
/* Suggestions */
void texttool_suggest_add(const char *name, char type);
-void texttool_suggest_prefix(const char *prefix, const int prefix_len);
+void texttool_suggest_prefix(const char *prefix, int prefix_len);
void texttool_suggest_clear(void);
SuggItem *texttool_suggest_first(void);
SuggItem *texttool_suggest_last(void);
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index ef322d0cd31..2683ab00fa4 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -42,6 +42,9 @@ struct TexResult;
/** #ColorBand.data length. */
#define MAXCOLORBAND 32
+/**
+ * Utility for all IDs using those texture slots.
+ */
void BKE_texture_mtex_foreach_id(struct LibraryForeachIDData *data, struct MTex *mtex);
void BKE_texture_default(struct Tex *tex);
@@ -50,6 +53,9 @@ void BKE_texture_type_set(struct Tex *tex, int type);
void BKE_texture_mtex_default(struct MTex *mtex);
struct MTex *BKE_texture_mtex_add(void);
+/**
+ * Slot -1 for first free ID.
+ */
struct MTex *BKE_texture_mtex_add_id(struct ID *id, int slot);
/* UNUSED */
// void autotexname(struct Tex *tex);
@@ -76,9 +82,12 @@ void BKE_texture_pointdensity_init_data(struct PointDensity *pd);
void BKE_texture_pointdensity_free_data(struct PointDensity *pd);
void BKE_texture_pointdensity_free(struct PointDensity *pd);
struct PointDensity *BKE_texture_pointdensity_add(void);
-struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd, const int flag);
+struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd, int flag);
bool BKE_texture_dependsOnTime(const struct Tex *texture);
+/**
+ * \returns true if this texture can use its #Texture.ima (even if its NULL).
+ */
bool BKE_texture_is_image_user(const struct Tex *tex);
void BKE_texture_get_value_ex(const struct Scene *scene,
@@ -94,6 +103,9 @@ void BKE_texture_get_value(const struct Scene *scene,
struct TexResult *texres,
bool use_color_management);
+/**
+ * Make sure all images used by texture are loaded into pool.
+ */
void BKE_texture_fetch_images_for_pool(struct Tex *texture, struct ImagePool *pool);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 47145a7d6bd..7769215d616 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -46,20 +46,53 @@ struct rcti;
/* **** Common functions **** */
+/**
+ * Free tracking structure, only frees structure contents
+ * (if structure is allocated in heap, it shall be handled outside).
+ *
+ * All the pointers inside structure becomes invalid after this call.
+ */
void BKE_tracking_free(struct MovieTracking *tracking);
+/**
+ * Copy tracking structure content.
+ */
void BKE_tracking_copy(struct MovieTracking *tracking_dst,
const struct MovieTracking *tracking_src,
- const int flag);
+ int flag);
+/**
+ * Initialize motion tracking settings to default values,
+ * used when new movie clip data-block is created.
+ */
void BKE_tracking_settings_init(struct MovieTracking *tracking);
+/**
+ * Get list base of active object's tracks.
+ */
struct ListBase *BKE_tracking_get_active_tracks(struct MovieTracking *tracking);
+/**
+ * Get list base of active object's plane tracks.
+ */
struct ListBase *BKE_tracking_get_active_plane_tracks(struct MovieTracking *tracking);
+/**
+ * Get reconstruction data of active object.
+ */
struct MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(
struct MovieTracking *tracking);
-/* matrices for constraints and drawing */
+/* Matrices for constraints and drawing. */
+
+/**
+ * Get transformation matrix for a given object which is used
+ * for parenting motion tracker reconstruction to 3D world.
+ */
void BKE_tracking_get_camera_object_matrix(struct Object *camera_object, float mat[4][4]);
+/**
+ * Get projection matrix for camera specified by given tracking object
+ * and frame number.
+ *
+ * \note frame number should be in clip space, not scene space.
+ */
void BKE_tracking_get_projection_matrix(struct MovieTracking *tracking,
struct MovieTrackingObject *object,
int framenr,
@@ -68,16 +101,45 @@ void BKE_tracking_get_projection_matrix(struct MovieTracking *tracking,
float mat[4][4]);
/* **** Clipboard **** */
+/**
+ * Free clipboard by freeing memory used by all tracks in it.
+ */
void BKE_tracking_clipboard_free(void);
+/**
+ * Copy selected tracks from specified object to the clipboard.
+ */
void BKE_tracking_clipboard_copy_tracks(struct MovieTracking *tracking,
struct MovieTrackingObject *object);
+/**
+ * Check whether there are any tracks in the clipboard.
+ */
bool BKE_tracking_clipboard_has_tracks(void);
+/**
+ * Paste tracks from clipboard to specified object.
+ *
+ * Names of new tracks in object are guaranteed to be unique here.
+ */
void BKE_tracking_clipboard_paste_tracks(struct MovieTracking *tracking,
struct MovieTrackingObject *object);
/* **** Track **** */
+
+/**
+ * Add new empty track to the given list of tracks.
+ *
+ * It is required that caller will append at least one marker to avoid degenerate tracks.
+ */
struct MovieTrackingTrack *BKE_tracking_track_add_empty(struct MovieTracking *tracking,
struct ListBase *tracks_list);
+/**
+ * Add new track to a specified tracks base.
+ *
+ * Coordinates are expected to be in normalized 0..1 space,
+ * frame number is expected to be in clip space.
+ *
+ * Width and height are clip's dimension used to scale track's
+ * pattern and search regions.
+ */
struct MovieTrackingTrack *BKE_tracking_track_add(struct MovieTracking *tracking,
struct ListBase *tracksbase,
float x,
@@ -85,33 +147,87 @@ struct MovieTrackingTrack *BKE_tracking_track_add(struct MovieTracking *tracking
int framenr,
int width,
int height);
+/**
+ * Duplicate the specified track, result will no belong to any list.
+ */
struct MovieTrackingTrack *BKE_tracking_track_duplicate(struct MovieTrackingTrack *track);
+/**
+ * Ensure specified track has got unique name,
+ * if it's not name of specified track will be changed
+ * keeping names of all other tracks unchanged.
+ */
void BKE_tracking_track_unique_name(struct ListBase *tracksbase, struct MovieTrackingTrack *track);
+/**
+ * Free specified track, only frees contents of a structure
+ * (if track is allocated in heap, it shall be handled outside).
+ *
+ * All the pointers inside track becomes invalid after this call.
+ */
void BKE_tracking_track_free(struct MovieTrackingTrack *track);
+/**
+ * Get frame numbers of the very first and last markers.
+ * There is no check on whether the marker is enabled or not.
+ */
void BKE_tracking_track_first_last_frame_get(const struct MovieTrackingTrack *track,
int *r_first_frame,
int *r_last_frame);
+/**
+ * Find the minimum starting frame and maximum ending frame within given set of tracks.
+ */
void BKE_tracking_tracks_first_last_frame_minmax(/*const*/ struct MovieTrackingTrack **tracks,
- const int num_tracks,
+ int num_tracks,
int *r_first_frame,
int *r_last_frame);
int BKE_tracking_count_selected_tracks_in_list(const struct ListBase *tracks_list);
int BKE_tracking_count_selected_tracks_in_active_object(/*const*/ struct MovieTracking *tracking);
-/* Get array of selected tracks from the current active object in the tracking structure.
- * If nothing is selected then the result is nullptr and `r_num_tracks` is set to 0. */
+/**
+ * Get array of selected tracks from the current active object in the tracking structure.
+ * If nothing is selected then the result is nullptr and `r_num_tracks` is set to 0.
+ */
struct MovieTrackingTrack **BKE_tracking_selected_tracks_in_active_object(
struct MovieTracking *tracking, int *r_num_tracks);
+/**
+ * Set flag for all specified track's areas.
+ *
+ * \param area: which part of marker should be selected. see TRACK_AREA_* constants.
+ * \param flag: flag to be set for areas.
+ */
void BKE_tracking_track_flag_set(struct MovieTrackingTrack *track, int area, int flag);
+/**
+ * Clear flag from all specified track's areas.
+ *
+ * \param area: which part of marker should be selected. see TRACK_AREA_* constants.
+ * \param flag: flag to be cleared for areas.
+ */
void BKE_tracking_track_flag_clear(struct MovieTrackingTrack *track, int area, int flag);
+/**
+ * Check whether track has got marker at specified frame.
+ *
+ * \note frame number should be in clip space, not scene space.
+ */
bool BKE_tracking_track_has_marker_at_frame(struct MovieTrackingTrack *track, int framenr);
+/**
+ * Check whether track has got enabled marker at specified frame.
+ *
+ * \note frame number should be in clip space, not scene space.
+ */
bool BKE_tracking_track_has_enabled_marker_at_frame(struct MovieTrackingTrack *track, int framenr);
+/**
+ * Clear track's path:
+ *
+ * - If action is #TRACK_CLEAR_REMAINED path from `ref_frame+1` up to end will be clear.
+ * - If action is #TRACK_CLEAR_UPTO path from the beginning up to `ref_frame-1` will be clear.
+ * - If action is #TRACK_CLEAR_ALL only marker at frame ref_frame will remain.
+ *
+ * \note frame number should be in clip space, not scene space.
+ */
void BKE_tracking_track_path_clear(struct MovieTrackingTrack *track, int ref_frame, int action);
void BKE_tracking_tracks_join(struct MovieTracking *tracking,
@@ -120,7 +236,7 @@ void BKE_tracking_tracks_join(struct MovieTracking *tracking,
void BKE_tracking_tracks_average(struct MovieTrackingTrack *dst_track,
/*const*/ struct MovieTrackingTrack **src_tracks,
- const int num_src_tracks);
+ int num_src_tracks);
struct MovieTrackingTrack *BKE_tracking_track_get_named(struct MovieTracking *tracking,
struct MovieTrackingObject *object,
@@ -140,7 +256,11 @@ float BKE_tracking_track_get_weight_for_marker(struct MovieClip *clip,
struct MovieTrackingTrack *track,
struct MovieTrackingMarker *marker);
-/* selection */
+/* Selection */
+
+/**
+ * \param area: which part of marker should be selected. see TRACK_AREA_* constants.
+ */
void BKE_tracking_track_select(struct ListBase *tracksbase,
struct MovieTrackingTrack *track,
int area,
@@ -155,21 +275,33 @@ void BKE_tracking_marker_delete(struct MovieTrackingTrack *track, int framenr);
void BKE_tracking_marker_clamp(struct MovieTrackingMarker *marker, int event);
+/**
+ * Get marker closest to the given frame number.
+ *
+ * If there is maker with exact frame number it returned.
+ * Otherwise, marker with highest frame number but lower than the requested
+ * frame is returned if such marker exists. Otherwise, the marker with lowest
+ * frame number greater than the requested frame number is returned.
+ *
+ * This function has complexity of `O(log number_of_markers)`.
+ */
struct MovieTrackingMarker *BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr);
struct MovieTrackingMarker *BKE_tracking_marker_get_exact(struct MovieTrackingTrack *track,
int framenr);
struct MovieTrackingMarker *BKE_tracking_marker_ensure(struct MovieTrackingTrack *track,
int framenr);
-/* Get marker position, possibly interpolating gap between key-framed/tracked markers.
+/**
+ * Get marker position, possibly interpolating gap between key-framed/tracked markers.
*
* The result marker frame number is set to the requested frame number. Its flags are 0 if the
* marker is interpolated, and is set to original marker flag if there were no interpolation
* involved.
*
- * Returns truth if the result is usable. */
+ * \returns truth if the result is usable.
+ */
bool BKE_tracking_marker_get_interpolated(struct MovieTrackingTrack *track,
- const int framenr,
+ int framenr,
struct MovieTrackingMarker *r_marker);
void BKE_tracking_marker_pattern_minmax(const struct MovieTrackingMarker *marker,
@@ -181,12 +313,21 @@ void BKE_tracking_marker_get_subframe_position(struct MovieTrackingTrack *track,
float pos[2]);
/* **** Plane Track **** */
+/**
+ * Creates new plane track out of selected point tracks.
+ */
struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(struct MovieTracking *tracking,
struct ListBase *plane_tracks_base,
struct ListBase *tracks,
int framenr);
void BKE_tracking_plane_track_unique_name(struct ListBase *plane_tracks_base,
struct MovieTrackingPlaneTrack *plane_track);
+/**
+ * Free specified plane track, only frees contents of a structure
+ * (if track is allocated in heap, it shall be handled outside).
+ *
+ * All the pointers inside track becomes invalid after this call.
+ */
void BKE_tracking_plane_track_free(struct MovieTrackingPlaneTrack *plane_track);
bool BKE_tracking_plane_track_has_marker_at_frame(struct MovieTrackingPlaneTrack *plane_track,
@@ -222,10 +363,21 @@ struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(
struct MovieTrackingPlaneTrack *plane_track, struct MovieTrackingPlaneMarker *plane_marker);
void BKE_tracking_plane_marker_delete(struct MovieTrackingPlaneTrack *plane_track, int framenr);
+/**
+ * Get a plane marker at given frame,
+ * If there's no such marker, closest one from the left side will be returned.
+ */
struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(
struct MovieTrackingPlaneTrack *plane_track, int framenr);
+/**
+ * Get a plane marker at exact given frame, if there's no marker at the frame,
+ * NULL will be returned.
+ */
struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(
struct MovieTrackingPlaneTrack *plane_track, int framenr);
+/**
+ * Ensure there's a marker for the given frame.
+ */
struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(
struct MovieTrackingPlaneTrack *plane_track, int framenr);
void BKE_tracking_plane_marker_get_subframe_corners(struct MovieTrackingPlaneTrack *plane_track,
@@ -255,6 +407,9 @@ struct MovieTrackingReconstruction *BKE_tracking_object_get_reconstruction(
struct MovieTracking *tracking, struct MovieTrackingObject *object);
/* **** Camera **** */
+/**
+ * Converts principal offset from center to offset of blender's camera.
+ */
void BKE_tracking_camera_shift_get(
struct MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty);
void BKE_tracking_camera_to_blender(struct MovieTracking *tracking,
@@ -346,10 +501,21 @@ struct ImBuf *BKE_tracking_get_search_imbuf(struct ImBuf *ibuf,
bool anchored,
bool disable_channels);
+/**
+ * Zap channels from the imbuf that are disabled by the user. this can lead to
+ * better tracks sometimes. however, instead of simply zeroing the channels
+ * out, do a partial gray-scale conversion so the display is better.
+ */
void BKE_tracking_disable_channels(
struct ImBuf *ibuf, bool disable_red, bool disable_green, bool disable_blue, bool grayscale);
/* **** 2D tracking **** */
+
+/**
+ * Refine marker's position using previously known keyframe.
+ * Direction of searching for a keyframe depends on backwards flag,
+ * which means if backwards is false, previous keyframe will be as reference.
+ */
void BKE_tracking_refine_marker(struct MovieClip *clip,
struct MovieTrackingTrack *track,
struct MovieTrackingMarker *marker,
@@ -359,7 +525,7 @@ void BKE_tracking_refine_marker(struct MovieClip *clip,
struct AutoTrackContext *BKE_autotrack_context_new(struct MovieClip *clip,
struct MovieClipUser *user,
- const bool is_backwards);
+ bool is_backwards);
bool BKE_autotrack_context_step(struct AutoTrackContext *context);
void BKE_autotrack_context_sync(struct AutoTrackContext *context);
void BKE_autotrack_context_sync_user(struct AutoTrackContext *context, struct MovieClipUser *user);
@@ -368,6 +534,9 @@ void BKE_autotrack_context_free(struct AutoTrackContext *context);
/* **** Plane tracking **** */
+/**
+ * \note frame number should be in clip space, not scene space.
+ */
void BKE_tracking_track_plane_from_existing_motion(struct MovieTrackingPlaneTrack *plane_track,
int start_frame);
void BKE_tracking_retrack_plane_from_existing_motion_at_segment(
@@ -377,11 +546,20 @@ void BKE_tracking_homography_between_two_quads(/*const*/ float reference_corners
float H[3][3]);
/* **** Camera solving **** */
+
+/**
+ * Perform early check on whether everything is fine to start reconstruction.
+ */
bool BKE_tracking_reconstruction_check(struct MovieTracking *tracking,
struct MovieTrackingObject *object,
char *error_msg,
int error_size);
+/**
+ * Create context for camera/object motion reconstruction.
+ * Copies all data needed for reconstruction from movie clip datablock,
+ * so editing this clip is safe during reconstruction job is in progress.
+ */
struct MovieReconstructContext *BKE_tracking_reconstruction_context_new(
struct MovieClip *clip,
struct MovieTrackingObject *object,
@@ -389,13 +567,29 @@ struct MovieReconstructContext *BKE_tracking_reconstruction_context_new(
int keyframe2,
int width,
int height);
+/**
+ * Free memory used by a reconstruction process.
+ */
void BKE_tracking_reconstruction_context_free(struct MovieReconstructContext *context);
+/**
+ * Solve camera/object motion and reconstruct 3D markers position
+ * from a prepared reconstruction context.
+ *
+ * stop is not actually used at this moment, so reconstruction
+ * job could not be stopped.
+ *
+ * do_update, progress and stat_message are set by reconstruction
+ * callback in libmv side and passing to an interface.
+ */
void BKE_tracking_reconstruction_solve(struct MovieReconstructContext *context,
short *stop,
short *do_update,
float *progress,
char *stats_message,
int message_size);
+/**
+ * Finish reconstruction process by copying reconstructed data to an actual movie clip data-block.
+ */
bool BKE_tracking_reconstruction_finish(struct MovieReconstructContext *context,
struct MovieTracking *tracking);
@@ -405,9 +599,16 @@ void BKE_tracking_reconstruction_report_error_message(struct MovieReconstructCon
const char *BKE_tracking_reconstruction_error_message_get(
const struct MovieReconstructContext *context);
+/**
+ * Apply scale on all reconstructed cameras and bundles, used by camera scale apply operator.
+ */
void BKE_tracking_reconstruction_scale(struct MovieTracking *tracking, float scale[3]);
/* **** Feature detection **** */
+
+/**
+ * Detect features using FAST detector.
+ */
void BKE_tracking_detect_fast(struct MovieTracking *tracking,
struct ListBase *tracksbase,
struct ImBuf *ibuf,
@@ -418,6 +619,9 @@ void BKE_tracking_detect_fast(struct MovieTracking *tracking,
struct bGPDlayer *layer,
bool place_outside_layer);
+/**
+ * Detect features using Harris detector.
+ */
void BKE_tracking_detect_harris(struct MovieTracking *tracking,
struct ListBase *tracksbase,
struct ImBuf *ibuf,
@@ -429,6 +633,24 @@ void BKE_tracking_detect_harris(struct MovieTracking *tracking,
bool place_outside_layer);
/* **** 2D stabilization **** */
+
+/**
+ * Get stabilization data (translation, scaling and angle) for a given frame.
+ * Returned data describes how to compensate the detected movement, but with any
+ * chosen scale factor already applied and any target frame position already compensated.
+ * In case stabilization fails or is disabled, neutral values are returned.
+ *
+ * \param framenr: is a frame number, relative to the clip (not relative to the scene timeline).
+ * \param width: is an effective width of the canvas (square pixels), used to scale the
+ * determined translation.
+ *
+ * Outputs:
+ * \param translation: of the lateral shift, absolute canvas coordinates (square pixels).
+ * \param scale: of the scaling to apply.
+ * \param angle: of the rotation angle, relative to the frame center.
+ *
+ * TODO(sergey): Use `r_` prefix for output parameters here.
+ */
void BKE_tracking_stabilization_data_get(struct MovieClip *clip,
int framenr,
int width,
@@ -436,12 +658,30 @@ void BKE_tracking_stabilization_data_get(struct MovieClip *clip,
float translation[2],
float *scale,
float *angle);
+/**
+ * Stabilize given image buffer using stabilization data for a specified frame number.
+ *
+ * \note frame number should be in clip space, not scene space.
+ *
+ * TODO(sergey): Use `r_` prefix for output parameters here.
+ */
struct ImBuf *BKE_tracking_stabilize_frame(struct MovieClip *clip,
int framenr,
struct ImBuf *ibuf,
float translation[2],
float *scale,
float *angle);
+/**
+ * Build a 4x4 transformation matrix based on the given 2D stabilization data.
+ * mat is a 4x4 matrix in homogeneous coordinates, adapted to the
+ * final image buffer size and compensated for pixel aspect ratio,
+ * ready for direct OpenGL drawing.
+ *
+ * TODO(sergey): The signature of this function should be changed. we actually
+ * don't need the dimensions of the image buffer. Instead we
+ * should consider to provide the pivot point of the rotation as a
+ * further stabilization data parameter.
+ */
void BKE_tracking_stabilization_data_to_mat4(int width,
int height,
float aspect,
@@ -450,17 +690,30 @@ void BKE_tracking_stabilization_data_to_mat4(int width,
float angle,
float mat[4][4]);
-/* Dopesheet */
+/* Dope-sheet */
+
+/**
+ * Tag dope-sheet for update, actual update will happen later when it'll be actually needed.
+ */
void BKE_tracking_dopesheet_tag_update(struct MovieTracking *tracking);
+/**
+ * Do dope-sheet update, if update is not needed nothing will happen.
+ */
void BKE_tracking_dopesheet_update(struct MovieTracking *tracking);
/* **** Query/search **** */
+/**
+ * \note Returns NULL if the track comes from camera object,.
+ */
struct MovieTrackingObject *BKE_tracking_find_object_for_track(
const struct MovieTracking *tracking, const struct MovieTrackingTrack *track);
struct ListBase *BKE_tracking_find_tracks_list_for_track(struct MovieTracking *tracking,
const struct MovieTrackingTrack *track);
+/**
+ * \note Returns NULL if the track comes from camera object,.
+ */
struct MovieTrackingObject *BKE_tracking_find_object_for_plane_track(
const struct MovieTracking *tracking, const struct MovieTrackingPlaneTrack *plane_track);
struct ListBase *BKE_tracking_find_tracks_list_for_plane_track(
diff --git a/source/blender/nodes/NOD_type_conversions.hh b/source/blender/blenkernel/BKE_type_conversions.hh
index ec4859f0657..ebfb13cd08f 100644
--- a/source/blender/nodes/NOD_type_conversions.hh
+++ b/source/blender/blenkernel/BKE_type_conversions.hh
@@ -18,10 +18,9 @@
#include "FN_multi_function.hh"
-namespace blender::nodes {
+namespace blender::bke {
using fn::CPPType;
-using fn::GVArray;
struct ConversionFunctions {
const fn::MultiFunction *multi_function;
@@ -73,11 +72,13 @@ class DataTypeConversions {
const void *from_value,
void *to_value) const;
- fn::GVArrayPtr try_convert(fn::GVArrayPtr varray, const CPPType &to_type) const;
+ void convert_to_initialized_n(fn::GSpan from_span, fn::GMutableSpan to_span) const;
- fn::GVMutableArrayPtr try_convert(fn::GVMutableArrayPtr varray, const CPPType &to_type) const;
+ fn::GVArray try_convert(fn::GVArray varray, const CPPType &to_type) const;
+
+ fn::GVMutableArray try_convert(fn::GVMutableArray varray, const CPPType &to_type) const;
};
const DataTypeConversions &get_implicit_type_conversions();
-} // namespace blender::nodes
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h
index 2973a432723..88a9ac9d0bf 100644
--- a/source/blender/blenkernel/BKE_undo_system.h
+++ b/source/blender/blenkernel/BKE_undo_system.h
@@ -91,7 +91,7 @@ typedef struct UndoStep {
/** When this is true, undo/memfile read code is allowed to re-use old data-blocks for unchanged
* IDs, and existing depsgraphes. This has to be forbidden in some cases (like renamed IDs). */
bool use_old_bmain_data;
- /** For use by undo systems that accumulate changes (text editor, painting). */
+ /** For use by undo systems that accumulate changes (mesh-sculpt & image-painting). */
bool is_applied;
/* Over alloc 'type->struct_size'. */
} UndoStep;
@@ -102,11 +102,11 @@ typedef enum eUndoStepDir {
STEP_INVALID = 0,
} eUndoStepDir;
-typedef enum UndoPushReturn {
+typedef enum eUndoPushReturn {
UNDO_PUSH_RET_FAILURE = 0,
UNDO_PUSH_RET_SUCCESS = (1 << 0),
UNDO_PUSH_RET_OVERRIDE_CHANGED = (1 << 1),
-} UndoPushReturn;
+} eUndoPushReturn;
typedef void (*UndoTypeForEachIDRefFn)(void *user_data, struct UndoRefID *id_ref);
@@ -133,7 +133,7 @@ typedef struct UndoType {
bool (*step_encode)(struct bContext *C, struct Main *bmain, UndoStep *us);
void (*step_decode)(
- struct bContext *C, struct Main *bmain, UndoStep *us, const eUndoStepDir dir, bool is_final);
+ struct bContext *C, struct Main *bmain, UndoStep *us, eUndoStepDir dir, bool is_final);
/**
* \note When freeing all steps,
@@ -156,7 +156,7 @@ typedef struct UndoType {
} UndoType;
/** #UndoType.flag bitflags. */
-typedef enum UndoTypeFlags {
+typedef enum eUndoTypeFlags {
/**
* This undo type `encode` callback needs a valid context, it will fail otherwise.
* \note Callback is still supposed to properly deal with a NULL context pointer.
@@ -169,9 +169,14 @@ typedef enum UndoTypeFlags {
* This is typically used for undo systems that store both before/after states.
*/
UNDOTYPE_FLAG_DECODE_ACTIVE_STEP = 1 << 1,
-} UndoTypeFlags;
+} eUndoTypeFlags;
+
+/* -------------------------------------------------------------------- */
+/** \name Public Undo Types
+ *
+ * Expose since we need to perform operations on specific undo types (rarely).
+ * \{ */
-/* Expose since we need to perform operations on specific undo types (rarely). */
extern const UndoType *BKE_UNDOSYS_TYPE_IMAGE;
extern const UndoType *BKE_UNDOSYS_TYPE_MEMFILE;
extern const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE;
@@ -179,17 +184,25 @@ extern const UndoType *BKE_UNDOSYS_TYPE_PARTICLE;
extern const UndoType *BKE_UNDOSYS_TYPE_SCULPT;
extern const UndoType *BKE_UNDOSYS_TYPE_TEXT;
+/** \} */
+
#define BKE_UNDOSYS_TYPE_IS_MEMFILE_SKIP(ty) ELEM(ty, BKE_UNDOSYS_TYPE_IMAGE)
UndoStack *BKE_undosys_stack_create(void);
void BKE_undosys_stack_destroy(UndoStack *ustack);
void BKE_undosys_stack_clear(UndoStack *ustack);
void BKE_undosys_stack_clear_active(UndoStack *ustack);
+/* name optional */
bool BKE_undosys_stack_has_undo(const UndoStack *ustack, const char *name);
void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain);
+/* called after 'BKE_undosys_stack_init_from_main' */
void BKE_undosys_stack_init_from_context(UndoStack *ustack, struct bContext *C);
UndoStep *BKE_undosys_stack_active_with_type(UndoStack *ustack, const UndoType *ut);
UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut);
+/**
+ * \param steps: Limit the number of undo steps.
+ * \param memory_limit: Limit the amount of memory used by the undo stack.
+ */
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit);
#define BKE_undosys_stack_limit_steps_and_memory_defaults(ustack) \
BKE_undosys_stack_limit_steps_and_memory(ustack, U.undosteps, (size_t)U.undomemory * 1024 * 1024)
@@ -197,18 +210,23 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size
void BKE_undosys_stack_group_begin(UndoStack *ustack);
void BKE_undosys_stack_group_end(UndoStack *ustack);
-/* Only some UndoType's require init. */
+/**
+ * Only some UndoType's require init.
+ */
UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack,
struct bContext *C,
const char *name,
const UndoType *ut);
UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, struct bContext *C, const char *name);
-UndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack,
- struct bContext *C,
- const char *name,
- const UndoType *ut);
-UndoPushReturn BKE_undosys_step_push(UndoStack *ustack, struct bContext *C, const char *name);
+/**
+ * \param C: Can be NULL from some callers if their encoding function doesn't need it
+ */
+eUndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack,
+ struct bContext *C,
+ const char *name,
+ const UndoType *ut);
+eUndoPushReturn BKE_undosys_step_push(UndoStack *ustack, struct bContext *C, const char *name);
UndoStep *BKE_undosys_step_find_by_name_with_type(UndoStack *ustack,
const char *name,
@@ -216,40 +234,117 @@ UndoStep *BKE_undosys_step_find_by_name_with_type(UndoStack *ustack,
UndoStep *BKE_undosys_step_find_by_type(UndoStack *ustack, const UndoType *ut);
UndoStep *BKE_undosys_step_find_by_name(UndoStack *ustack, const char *name);
+/**
+ * Return direction of the undo/redo from `us_reference` (or `ustack->step_active` if NULL), and
+ * `us_target`.
+ *
+ * \note If `us_reference` and `us_target` are the same, we consider this is an undo.
+ *
+ * \return -1 for undo, 1 for redo, 0 in case of error.
+ */
eUndoStepDir BKE_undosys_step_calc_direction(const UndoStack *ustack,
const UndoStep *us_target,
const UndoStep *us_reference);
+/**
+ * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
+ *
+ * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target`
+ * will become the active step.
+ *
+ * \note In case `use_skip` is true, the final target will always be **beyond** the given one
+ * (if the given one has to be skipped).
+ *
+ * \param us_reference: If NULL, will be set to current active step in the undo stack. Otherwise,
+ * it is assumed to match the current state, and will be used as basis for the undo/redo process
+ * (i.e. all steps in-between `us_reference` and `us_target` will be processed).
+ */
bool BKE_undosys_step_load_data_ex(UndoStack *ustack,
struct bContext *C,
UndoStep *us_target,
UndoStep *us_reference,
- const bool use_skip);
+ bool use_skip);
+/**
+ * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
+ */
bool BKE_undosys_step_load_data(UndoStack *ustack, struct bContext *C, UndoStep *us_target);
-void BKE_undosys_step_load_from_index(UndoStack *ustack, struct bContext *C, const int index);
+/**
+ * Undo/Redo until the step matching given `index` in the undo stack becomes the active
+ * (currently loaded) one.
+ */
+void BKE_undosys_step_load_from_index(UndoStack *ustack, struct bContext *C, int index);
+/**
+ * Undo until `us_target` step becomes the active (currently loaded) one.
+ *
+ * \warning This function assumes that the given target step is _before_ current active one.
+ *
+ * \note Unless `us_target` is a 'skipped' one and `use_skip` is true,
+ * `us_target` will become the active step.
+ *
+ * \note In case `use_skip` is true, the final target will always be **before** the given one
+ * (if the given one has to be skipped).
+ */
bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack,
struct bContext *C,
UndoStep *us,
bool use_skip);
+/**
+ * Undo until `us_target` step becomes the active (currently loaded) one.
+ *
+ * \note See #BKE_undosys_step_undo_with_data_ex for details.
+ */
bool BKE_undosys_step_undo_with_data(UndoStack *ustack, struct bContext *C, UndoStep *us_target);
+/**
+ * Undo one step from current active (currently loaded) one.
+ */
bool BKE_undosys_step_undo(UndoStack *ustack, struct bContext *C);
+/**
+ * Redo until `us_target` step becomes the active (currently loaded) one.
+ *
+ * \warning This function assumes that the given target step is _after_ current active one.
+ *
+ * \note Unless `us_target` is a 'skipped' one and `use_skip` is true,
+ * `us_target` will become the active step.
+ *
+ * \note In case `use_skip` is true, the final target will always be **after** the given one
+ * (if the given one has to be skipped).
+ */
bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack,
struct bContext *C,
UndoStep *us,
bool use_skip);
+/**
+ * Redo until `us_target` step becomes the active (currently loaded) one.
+ *
+ * \note See #BKE_undosys_step_redo_with_data_ex for details.
+ */
bool BKE_undosys_step_redo_with_data(UndoStack *ustack, struct bContext *C, UndoStep *us_target);
+/**
+ * Redo one step from current active one.
+ */
bool BKE_undosys_step_redo(UndoStack *ustack, struct bContext *C);
+/**
+ * Useful when we want to diff against previous undo data but can't be sure the types match.
+ */
UndoStep *BKE_undosys_step_same_type_next(UndoStep *us);
+/**
+ * Useful when we want to diff against previous undo data but can't be sure the types match.
+ */
UndoStep *BKE_undosys_step_same_type_prev(UndoStep *us);
-/* Type System */
+/* Type System. */
+
+/**
+ * Similar to #WM_operatortype_append
+ */
UndoType *BKE_undosys_type_append(void (*undosys_fn)(UndoType *));
void BKE_undosys_type_free_all(void);
-/* ID Accessor */
+/* ID Accessor. */
+
#if 0 /* functionality is only used internally for now. */
void BKE_undosys_foreach_ID_ref(UndoStack *ustack,
UndoTypeForEachIDRefFn foreach_ID_ref_fn,
diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h
index b28215a72d1..505cfee3adf 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -26,9 +26,11 @@ extern "C" {
struct UnitSettings;
-/* in all cases the value is assumed to be scaled by the user preference */
+/* In all cases the value is assumed to be scaled by the user-preference. */
-/* humanly readable representation of a value in units (used for button drawing) */
+/**
+ * Humanly readable representation of a value in units (used for button drawing).
+ */
size_t BKE_unit_value_as_string_adaptive(
char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad);
size_t BKE_unit_value_as_string(char *str,
@@ -39,29 +41,59 @@ size_t BKE_unit_value_as_string(char *str,
const struct UnitSettings *settings,
bool pad);
-/* replace units with values, used before python button evaluation */
+/**
+ * Replace units with values, used before python button evaluation.
+ *
+ * Make a copy of the string that replaces the units with numbers.
+ * This is only used when evaluating user input and can afford to be a bit slower
+ *
+ * This is to be used before python evaluation so:
+ * `10.1km -> 10.1*1000.0`
+ * ...will be resolved by Python.
+ *
+ * Values will be split by an add sign:
+ * `5'2" -> 5*0.3048 + 2*0.0254`
+ *
+ * \param str_prev: is optional, when valid it is used to get a base unit when none is set.
+ *
+ * \return True of a change was made.
+ */
bool BKE_unit_replace_string(
char *str, int len_max, const char *str_prev, double scale_pref, int system, int type);
-/* return true if the string contains any valid unit for the given type */
+/**
+ * \return true if the string contains any valid unit for the given type.
+ */
bool BKE_unit_string_contains_unit(const char *str, int type);
-/* If user does not specify a unit, this converts it to the unit from the settings. */
+/**
+ * If user does not specify a unit, this converts it to the unit from the settings.
+ */
double BKE_unit_apply_preferred_unit(const struct UnitSettings *settings, int type, double value);
-/* make string keyboard-friendly: 10µm --> 10um */
+/**
+ * Make string keyboard-friendly, e.g: `10µm -> 10um`.
+ */
void BKE_unit_name_to_alt(char *str, int len_max, const char *orig_str, int system, int type);
-/* the size of the unit used for this value (used for calculating the ckickstep) */
+/**
+ * The size of the unit used for this value (used for calculating the click-step).
+ */
double BKE_unit_closest_scalar(double value, int system, int type);
-/* base scale for these units */
+/**
+ * Base scale for these units.
+ */
double BKE_unit_base_scalar(int system, int type);
-/* return true is the unit system exists */
+/**
+ * \return true is the unit system exists.
+ */
bool BKE_unit_is_valid(int system, int type);
-/* loop over scales, could add names later */
+/**
+ * Loop over scales, could add names later.
+ */
// double bUnit_Iter(void **unit, char **name, int system, int type);
void BKE_unit_system_get(int system, int type, const void **r_usys_pt, int *r_len);
@@ -73,7 +105,7 @@ const char *BKE_unit_identifier_get(const void *usys_pt, int index);
double BKE_unit_scalar_get(const void *usys_pt, int index);
bool BKE_unit_is_suppressed(const void *usys_pt, int index);
-/* aligned with PropertyUnit */
+/** Aligned with #PropertyUnit. */
enum {
B_UNIT_NONE = 0,
B_UNIT_LENGTH = 1,
diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_vfont.h
index 827ae1b6a0f..3397f2ef82a 100644
--- a/source/blender/blenkernel/BKE_font.h
+++ b/source/blender/blenkernel/BKE_vfont.h
@@ -84,6 +84,9 @@ bool BKE_vfont_to_curve_ex(struct Object *ob,
bool *r_text_free,
struct CharTrans **r_chartransdata);
bool BKE_vfont_to_curve_nubase(struct Object *ob, int mode, struct ListBase *r_nubase);
+/**
+ * \warning Expects to have access to evaluated data (i.e. passed object should be evaluated one).
+ */
bool BKE_vfont_to_curve(struct Object *ob, int mode);
void BKE_vfont_build_char(struct Curve *cu,
struct ListBase *nubase,
@@ -93,7 +96,7 @@ void BKE_vfont_build_char(struct Curve *cu,
float ofsy,
float rot,
int charidx,
- const float fsize);
+ float fsize);
int BKE_vfont_select_get(struct Object *ob, int *r_start, int *r_end);
void BKE_vfont_select_clamp(struct Object *ob);
@@ -101,7 +104,7 @@ void BKE_vfont_select_clamp(struct Object *ob);
void BKE_vfont_clipboard_free(void);
void BKE_vfont_clipboard_set(const char32_t *text_buf,
const struct CharInfo *info_buf,
- const size_t len);
+ size_t len);
void BKE_vfont_clipboard_get(char32_t **r_text_buf,
struct CharInfo **r_info_buf,
size_t *r_len_utf8,
diff --git a/source/blender/blenlib/BLI_vfontdata.h b/source/blender/blenkernel/BKE_vfontdata.h
index 0bb32ca24b7..01ca59828fc 100644
--- a/source/blender/blenlib/BLI_vfontdata.h
+++ b/source/blender/blenkernel/BKE_vfontdata.h
@@ -20,7 +20,7 @@
#pragma once
/** \file
- * \ingroup bli
+ * \ingroup bke
* \brief A structure to represent vector fonts,
* and to load them from PostScript fonts.
*/
@@ -49,11 +49,17 @@ typedef struct VChar {
float width;
} VChar;
-VFontData *BLI_vfontdata_from_freetypefont(struct PackedFile *pf);
-VFontData *BLI_vfontdata_copy(const VFontData *vfont_src, const int flag);
+/**
+ * Construct a new #VFontData structure from free-type font data in `pf`.
+ *
+ * \param pf: The font data.
+ * \retval A new #VFontData structure, or NULL if unable to load.
+ */
+VFontData *BKE_vfontdata_from_freetypefont(struct PackedFile *pf);
+VFontData *BKE_vfontdata_copy(const VFontData *vfont_src, int flag);
-VChar *BLI_vfontchar_from_freetypefont(struct VFont *vfont, unsigned long character);
-VChar *BLI_vfontchar_copy(const VChar *vchar_src, const int flag);
+VChar *BKE_vfontdata_char_from_freetypefont(struct VFont *vfont, unsigned long character);
+VChar *BKE_vfontdata_char_copy(const VChar *vchar_src);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h
index 5fe0d54c2cf..8b42de7303d 100644
--- a/source/blender/blenkernel/BKE_volume.h
+++ b/source/blender/blenkernel/BKE_volume.h
@@ -88,6 +88,7 @@ const char *BKE_volume_grids_frame_filepath(const struct Volume *volume);
const VolumeGrid *BKE_volume_grid_get_for_read(const struct Volume *volume, int grid_index);
VolumeGrid *BKE_volume_grid_get_for_write(struct Volume *volume, int grid_index);
const VolumeGrid *BKE_volume_grid_active_get_for_read(const struct Volume *volume);
+/* Tries to find a grid with the given name. Make sure that the volume has been loaded. */
const VolumeGrid *BKE_volume_grid_find_for_read(const struct Volume *volume, const char *name);
/* Grid
@@ -115,9 +116,13 @@ void BKE_volume_grid_unload(const struct Volume *volume, const struct VolumeGrid
bool BKE_volume_grid_is_loaded(const struct VolumeGrid *grid);
/* Metadata */
+
const char *BKE_volume_grid_name(const struct VolumeGrid *grid);
VolumeGridType BKE_volume_grid_type(const struct VolumeGrid *grid);
int BKE_volume_grid_channels(const struct VolumeGrid *grid);
+/**
+ * Transformation from index space to object space.
+ */
void BKE_volume_grid_transform_matrix(const struct VolumeGrid *grid, float mat[4][4]);
/* Volume Editing
@@ -158,8 +163,9 @@ bool BKE_volume_save(const struct Volume *volume,
* file or copy shared grids to make them writeable. */
#ifdef __cplusplus
-# include "BLI_float3.hh"
# include "BLI_float4x4.hh"
+# include "BLI_math_vec_types.hh"
+# include "BLI_string_ref.hh"
bool BKE_volume_min_max(const Volume *volume, blender::float3 &r_min, blender::float3 &r_max);
@@ -167,10 +173,19 @@ bool BKE_volume_min_max(const Volume *volume, blender::float3 &r_min, blender::f
# include <openvdb/openvdb.h>
# include <openvdb/points/PointDataGrid.h>
+VolumeGrid *BKE_volume_grid_add_vdb(Volume &volume,
+ blender::StringRef name,
+ openvdb::GridBase::Ptr vdb_grid);
+
bool BKE_volume_grid_bounds(openvdb::GridBase::ConstPtr grid,
blender::float3 &r_min,
blender::float3 &r_max);
+/**
+ * Return a new grid pointer with only the metadata and transform changed.
+ * This is useful for instances, where there is a separate transform on top of the original
+ * grid transform that must be applied for some operations that only take a grid argument.
+ */
openvdb::GridBase::ConstPtr BKE_volume_grid_shallow_transform(openvdb::GridBase::ConstPtr grid,
const blender::float4x4 &transform);
@@ -179,7 +194,7 @@ openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_read(const struct Volume
const struct VolumeGrid *grid);
openvdb::GridBase::Ptr BKE_volume_grid_openvdb_for_write(const struct Volume *volume,
struct VolumeGrid *grid,
- const bool clear);
+ bool clear);
VolumeGridType BKE_volume_grid_type_openvdb(const openvdb::GridBase &grid);
@@ -219,9 +234,7 @@ auto BKE_volume_grid_type_operation(const VolumeGridType grid_type, OpType &&op)
}
openvdb::GridBase::Ptr BKE_volume_grid_create_with_changed_resolution(
- const VolumeGridType grid_type,
- const openvdb::GridBase &old_grid,
- const float resolution_factor);
+ const VolumeGridType grid_type, const openvdb::GridBase &old_grid, float resolution_factor);
# endif
#endif
diff --git a/source/blender/blenkernel/BKE_volume_to_mesh.hh b/source/blender/blenkernel/BKE_volume_to_mesh.hh
index 1f6e89636c4..123cb33f24f 100644
--- a/source/blender/blenkernel/BKE_volume_to_mesh.hh
+++ b/source/blender/blenkernel/BKE_volume_to_mesh.hh
@@ -14,6 +14,10 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#pragma once
+
+#include "BLI_span.hh"
+
#include "DNA_modifier_types.h"
#ifdef WITH_OPENVDB
@@ -33,10 +37,49 @@ struct VolumeToMeshResolution {
};
#ifdef WITH_OPENVDB
+
+/**
+ * The result of converting a volume grid to mesh data, in the format used by the OpenVDB API.
+ */
+struct OpenVDBMeshData {
+ std::vector<openvdb::Vec3s> verts;
+ std::vector<openvdb::Vec3I> tris;
+ std::vector<openvdb::Vec4I> quads;
+ bool is_empty() const
+ {
+ return verts.empty();
+ }
+};
+
struct Mesh *volume_to_mesh(const openvdb::GridBase &grid,
const VolumeToMeshResolution &resolution,
- const float threshold,
- const float adaptivity);
+ float threshold,
+ float adaptivity);
+
+/**
+ * Convert an OpenVDB volume grid to corresponding mesh data: vertex positions and quad and
+ * triangle indices.
+ */
+struct OpenVDBMeshData volume_to_mesh_data(const openvdb::GridBase &grid,
+ const VolumeToMeshResolution &resolution,
+ float threshold,
+ float adaptivity);
+
+/**
+ * Convert mesh data from the format provided by OpenVDB into Blender's #Mesh data structure.
+ * This can be used to add mesh data from a grid into an existing mesh rather than merging multiple
+ * meshes later on.
+ */
+void fill_mesh_from_openvdb_data(const Span<openvdb::Vec3s> vdb_verts,
+ const Span<openvdb::Vec3I> vdb_tris,
+ const Span<openvdb::Vec4I> vdb_quads,
+ int vert_offset,
+ int poly_offset,
+ int loop_offset,
+ MutableSpan<MVert> verts,
+ MutableSpan<MPoly> polys,
+ MutableSpan<MLoop> loops);
+
#endif
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h
index 82a4e5fe08e..0f609be67de 100644
--- a/source/blender/blenkernel/BKE_workspace.h
+++ b/source/blender/blenkernel/BKE_workspace.h
@@ -31,16 +31,27 @@ struct bScreen;
struct bToolRef;
/* -------------------------------------------------------------------- */
-/* Create, delete, init */
+/** \name Create, Delete, Initialize
+ * \{ */
struct WorkSpace *BKE_workspace_add(struct Main *bmain, const char *name);
+/**
+ * Remove \a workspace by freeing itself and its data. This is a higher-level wrapper that
+ * calls #workspace_free_data (through #BKE_id_free) to free the workspace data, and frees
+ * other data-blocks owned by \a workspace and its layouts (currently that is screens only).
+ *
+ * Always use this to remove (and free) workspaces. Don't free non-ID workspace members here.
+ */
void BKE_workspace_remove(struct Main *bmain, struct WorkSpace *workspace);
struct WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const struct Main *bmain,
- const int winid);
+ int winid);
void BKE_workspace_instance_hook_free(const struct Main *bmain,
struct WorkSpaceInstanceHook *hook);
+/**
+ * Add a new layout to \a workspace for \a screen.
+ */
struct WorkSpaceLayout *BKE_workspace_layout_add(struct Main *bmain,
struct WorkSpace *workspace,
struct bScreen *screen,
@@ -51,29 +62,51 @@ void BKE_workspace_layout_remove(struct Main *bmain,
void BKE_workspace_relations_free(ListBase *relation_list);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* General Utils */
+/** \name General Utilities
+ * \{ */
struct WorkSpaceLayout *BKE_workspace_layout_find(const struct WorkSpace *workspace,
const struct bScreen *screen)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Find the layout for \a screen without knowing which workspace to look in.
+ * Can also be used to find the workspace that contains \a screen.
+ *
+ * \param r_workspace: Optionally return the workspace that contains the
+ * looked up layout (if found).
+ */
struct WorkSpaceLayout *BKE_workspace_layout_find_global(const struct Main *bmain,
const struct bScreen *screen,
struct WorkSpace **r_workspace)
ATTR_NONNULL(1, 2);
+/**
+ * Circular workspace layout iterator.
+ *
+ * \param callback: Custom function which gets executed for each layout.
+ * Can return false to stop iterating.
+ * \param arg: Custom data passed to each \a callback call.
+ *
+ * \return the layout at which \a callback returned false.
+ */
struct WorkSpaceLayout *BKE_workspace_layout_iter_circular(
const struct WorkSpace *workspace,
struct WorkSpaceLayout *start,
bool (*callback)(const struct WorkSpaceLayout *layout, void *arg),
void *arg,
- const bool iter_backward);
+ bool iter_backward);
void BKE_workspace_tool_remove(struct WorkSpace *workspace, struct bToolRef *tref)
ATTR_NONNULL(1, 2);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* Getters/Setters */
+/** \name Getters/Setters
+ * \{ */
#define GETTER_ATTRS ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
#define SETTER_ATTRS ATTR_NONNULL(1)
@@ -81,16 +114,31 @@ void BKE_workspace_tool_remove(struct WorkSpace *workspace, struct bToolRef *tre
struct WorkSpace *BKE_workspace_active_get(struct WorkSpaceInstanceHook *hook) GETTER_ATTRS;
void BKE_workspace_active_set(struct WorkSpaceInstanceHook *hook,
struct WorkSpace *workspace) SETTER_ATTRS;
+/**
+ * Get the layout that is active for \a hook (which is the visible layout for the active workspace
+ * in \a hook).
+ */
struct WorkSpaceLayout *BKE_workspace_active_layout_get(const struct WorkSpaceInstanceHook *hook)
GETTER_ATTRS;
+/**
+ * \brief Activate a layout
+ *
+ * Sets \a layout as active for \a workspace when activated through or already active in \a hook.
+ * So when the active workspace of \a hook is \a workspace, \a layout becomes the active layout of
+ * \a hook too. See #BKE_workspace_active_set().
+ *
+ * \a workspace does not need to be active for this.
+ *
+ * #WorkSpaceInstanceHook.act_layout should only be modified directly to update the layout pointer.
+ */
void BKE_workspace_active_layout_set(struct WorkSpaceInstanceHook *hook,
- const int winid,
+ int winid,
struct WorkSpace *workspace,
struct WorkSpaceLayout *layout) SETTER_ATTRS;
struct bScreen *BKE_workspace_active_screen_get(const struct WorkSpaceInstanceHook *hook)
GETTER_ATTRS;
void BKE_workspace_active_screen_set(struct WorkSpaceInstanceHook *hook,
- const int winid,
+ int winid,
struct WorkSpace *workspace,
struct bScreen *screen) SETTER_ATTRS;
@@ -100,6 +148,9 @@ void BKE_workspace_layout_name_set(struct WorkSpace *workspace,
const char *new_name) ATTR_NONNULL();
struct bScreen *BKE_workspace_layout_screen_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS;
+/**
+ * Get the layout to be activated should \a workspace become or be the active workspace in \a hook.
+ */
struct WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(
const struct WorkSpaceInstanceHook *hook, const struct WorkSpace *workspace) GETTER_ATTRS;
@@ -111,6 +162,8 @@ void BKE_workspace_id_tag_all_visible(struct Main *bmain, int tag) ATTR_NONNULL(
#undef GETTER_ATTRS
#undef SETTER_ATTRS
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h
index 97f998cc1c1..c20de4df901 100644
--- a/source/blender/blenkernel/BKE_writeavi.h
+++ b/source/blender/blenkernel/BKE_writeavi.h
@@ -63,7 +63,11 @@ typedef struct bMovieHandle {
void (*context_free)(void *context_v);
} bMovieHandle;
-bMovieHandle *BKE_movie_handle_get(const char imtype);
+bMovieHandle *BKE_movie_handle_get(char imtype);
+
+/**
+ * \note Similar to #BKE_image_path_from_imformat()
+ */
void BKE_movie_filepath_get(char *string,
const struct RenderData *rd,
bool preview,
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 24de91959bb..6d6579f49f6 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -60,6 +60,9 @@ set(INC
set(INC_SYS
${ZLIB_INCLUDE_DIRS}
+
+ # For `vfontdata_freetype.c`.
+ ${FREETYPE_INCLUDE_DIRS}
)
set(SRC
@@ -85,7 +88,9 @@ set(SRC
intern/armature_update.c
intern/asset.cc
intern/asset_catalog.cc
+ intern/asset_catalog_path.cc
intern/asset_library.cc
+ intern/asset_library_service.cc
intern/attribute.c
intern/attribute_access.cc
intern/attribute_math.cc
@@ -95,6 +100,7 @@ set(SRC
intern/blender_undo.c
intern/blender_user_menu.c
intern/blendfile.c
+ intern/blendfile_link_append.c
intern/boids.c
intern/bpath.c
intern/brush.c
@@ -112,15 +118,15 @@ set(SRC
intern/context.c
intern/crazyspace.c
intern/cryptomatte.cc
- intern/curve.c
+ intern/curve.cc
intern/curve_bevel.c
intern/curve_convert.c
intern/curve_decimate.c
intern/curve_deform.c
intern/curve_eval.cc
intern/curve_to_mesh_convert.cc
- intern/curveprofile.c
- intern/customdata.c
+ intern/curveprofile.cc
+ intern/customdata.cc
intern/customdata_file.c
intern/data_transfer.c
intern/deform.c
@@ -138,7 +144,6 @@ set(SRC
intern/fcurve_driver.c
intern/fluid.c
intern/fmodifier.c
- intern/font.c
intern/freestyle.c
intern/geometry_component_curve.cc
intern/geometry_component_instances.cc
@@ -151,15 +156,17 @@ set(SRC
intern/gpencil_curve.c
intern/gpencil_geom.cc
intern/gpencil_modifier.c
- intern/hair.c
+ intern/hair.cc
intern/icons.cc
intern/icons_rasterize.c
intern/idprop.c
+ intern/idprop_create.cc
+ intern/idprop_serialize.cc
intern/idprop_utils.c
intern/idtype.c
intern/image.c
intern/image_gen.c
- intern/image_gpu.c
+ intern/image_gpu.cc
intern/image_save.c
intern/ipo.c
intern/kelvinlet.c
@@ -172,6 +179,7 @@ set(SRC
intern/lib_id.c
intern/lib_id_delete.c
intern/lib_id_eval.c
+ intern/lib_id_remapper.cc
intern/lib_override.c
intern/lib_query.c
intern/lib_remap.c
@@ -187,9 +195,10 @@ set(SRC
intern/material.c
intern/mball.c
intern/mball_tessellate.c
- intern/mesh.c
+ intern/mesh.cc
intern/mesh_boolean_convert.cc
intern/mesh_convert.cc
+ intern/mesh_debug.cc
intern/mesh_evaluate.cc
intern/mesh_fair.cc
intern/mesh_iterators.c
@@ -221,7 +230,8 @@ set(SRC
intern/multires_versioning.c
intern/nla.c
intern/node.cc
- intern/object.c
+ intern/node_tree_update.cc
+ intern/object.cc
intern/object_deform.c
intern/object_dupli.cc
intern/object_facemap.c
@@ -268,6 +278,7 @@ set(SRC
intern/subdiv_eval.c
intern/subdiv_foreach.c
intern/subdiv_mesh.c
+ intern/subdiv_modifier.c
intern/subdiv_stats.c
intern/subdiv_topology.c
intern/subsurf_ccg.c
@@ -282,8 +293,11 @@ set(SRC
intern/tracking_solver.c
intern/tracking_stabilize.c
intern/tracking_util.c
+ intern/type_conversions.cc
intern/undo_system.c
intern/unit.c
+ intern/vfont.c
+ intern/vfontdata_freetype.c
intern/volume.cc
intern/volume_render.cc
intern/volume_to_mesh.cc
@@ -306,6 +320,7 @@ set(SRC
BKE_armature.hh
BKE_asset.h
BKE_asset_catalog.hh
+ BKE_asset_catalog_path.hh
BKE_asset_library.h
BKE_asset_library.hh
BKE_attribute.h
@@ -318,6 +333,7 @@ set(SRC
BKE_blender_user_menu.h
BKE_blender_version.h
BKE_blendfile.h
+ BKE_blendfile_link_append.h
BKE_boids.h
BKE_bpath.h
BKE_brush.h
@@ -357,7 +373,6 @@ set(SRC
BKE_fcurve.h
BKE_fcurve_driver.h
BKE_fluid.h
- BKE_font.h
BKE_freestyle.h
BKE_geometry_set.h
BKE_geometry_set.hh
@@ -370,6 +385,7 @@ set(SRC
BKE_hair.h
BKE_icons.h
BKE_idprop.h
+ BKE_idprop.hh
BKE_idtype.h
BKE_image.h
BKE_image_save.h
@@ -411,6 +427,7 @@ set(SRC
BKE_multires.h
BKE_nla.h
BKE_node.h
+ BKE_node_tree_update.h
BKE_object.h
BKE_object_deform.h
BKE_object_facemap.h
@@ -442,14 +459,18 @@ set(SRC
BKE_subdiv_eval.h
BKE_subdiv_foreach.h
BKE_subdiv_mesh.h
+ BKE_subdiv_modifier.h
BKE_subdiv_topology.h
BKE_subsurf.h
BKE_text.h
BKE_text_suggestions.h
BKE_texture.h
BKE_tracking.h
+ BKE_type_conversions.hh
BKE_undo_system.h
BKE_unit.h
+ BKE_vfont.h
+ BKE_vfontdata.h
BKE_volume.h
BKE_volume_render.h
BKE_volume_to_mesh.hh
@@ -463,6 +484,7 @@ set(SRC
intern/CCGSubSurf.h
intern/CCGSubSurf_inline.h
intern/CCGSubSurf_intern.h
+ intern/asset_library_service.hh
intern/attribute_access_intern.hh
intern/data_transfer_intern.h
intern/lib_intern.h
@@ -499,6 +521,9 @@ set(LIB
bf_rna
bf_shader_fx
bf_simulation
+
+ # For `vfontdata_freetype.c`.
+ ${FREETYPE_LIBRARIES} ${BROTLI_LIBRARIES}
)
if(WITH_BINRELOC)
@@ -788,14 +813,20 @@ if(WITH_GTESTS)
set(TEST_SRC
intern/action_test.cc
intern/armature_test.cc
+ intern/asset_catalog_path_test.cc
intern/asset_catalog_test.cc
+ intern/asset_library_service_test.cc
intern/asset_library_test.cc
intern/asset_test.cc
+ intern/bpath_test.cc
intern/cryptomatte_test.cc
intern/fcurve_test.cc
+ intern/idprop_serialize_test.cc
intern/lattice_deform_test.cc
intern/layer_test.cc
+ intern/lib_id_remapper_test.cc
intern/lib_id_test.cc
+ intern/lib_remap_test.cc
intern/tracking_test.cc
)
set(TEST_INC
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index 67e7b890548..74f848ac580 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -939,7 +939,6 @@ void ccgSubSurf__effectedFaceNeighbors(CCGSubSurf *ss,
*numEdges = numE;
}
-/* copy face grid coordinates to other places */
CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
int i, S, x, gridSize, cornerIdx, subdivLevels;
@@ -986,7 +985,6 @@ CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF
return eCCGError_None;
}
-/* copy other places to face grid coordinates */
CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
int i, S, x, gridSize, cornerIdx, subdivLevels;
@@ -1035,8 +1033,6 @@ CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF,
return eCCGError_None;
}
-/* stitch together face grids, averaging coordinates at edges
- * and vertices, for multires displacements */
CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
CCGVert **effectedV;
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h
index a9e0d6882c1..9349c33d72a 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -100,13 +100,30 @@ CCGError ccgSubSurf_syncFaceDel(CCGSubSurf *ss, CCGFaceHDL fHDL);
CCGError ccgSubSurf_processSync(CCGSubSurf *ss);
+/**
+ * Copy face grid coordinates to other places.
+ */
CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss,
int lvl,
CCGFace **effectedF,
int numEffectedF);
+/**
+ * Copy other places to face grid coordinates.
+ */
CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF);
+/**
+ * Update normals for specified faces.
+ */
CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF);
+/**
+ * Compute subdivision levels from a given starting point, used by multi-res subdivide/propagate,
+ * by filling in coordinates at a certain level, and then subdividing that up to the highest level.
+ */
CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF);
+/**
+ * Stitch together face grids, averaging coordinates at edges and vertices, for multi-res
+ * displacements.
+ */
CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF);
CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels);
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
index 99ea1fb9607..e19e01ec034 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
@@ -1309,7 +1309,6 @@ void ccgSubSurf__sync_legacy(CCGSubSurf *ss)
/* ** Public API exposed to other areas which depends on old CCG code. ** */
-/* Update normals for specified faces. */
CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF)
{
CCGVert **effectedV;
@@ -1344,9 +1343,6 @@ CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEf
return eCCGError_None;
}
-/* compute subdivision levels from a given starting point, used by
- * multires subdivide/propagate, by filling in coordinates at a
- * certain level, and then subdividing that up to the highest level */
CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
CCGVert **effectedV;
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 59e81938e79..d0d19ff199d 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -38,9 +38,9 @@
#include "BLI_array.h"
#include "BLI_bitmap.h"
#include "BLI_blenlib.h"
-#include "BLI_float2.hh"
#include "BLI_linklist.h"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_task.h"
#include "BLI_task.hh"
#include "BLI_utildefines.h"
@@ -295,10 +295,6 @@ static CustomData *dm_getPolyCData(DerivedMesh *dm)
return &dm->polyData;
}
-/**
- * Utility function to initialize a DerivedMesh's function pointers to
- * the default implementation (for those functions which have a default)
- */
void DM_init_funcs(DerivedMesh *dm)
{
/* default function implementations */
@@ -335,11 +331,6 @@ void DM_init_funcs(DerivedMesh *dm)
dm->getLoopDataArray = DM_get_loop_data_layer;
}
-/**
- * Utility function to initialize a DerivedMesh for the desired number
- * of vertices, edges and faces (doesn't allocate memory for them, just
- * sets up the custom data layers)
- */
void DM_init(DerivedMesh *dm,
DerivedMeshType type,
int numVerts,
@@ -368,10 +359,6 @@ void DM_init(DerivedMesh *dm,
copy_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1);
}
-/**
- * Utility function to initialize a DerivedMesh for the desired number
- * of vertices, edges and faces, with a layer setup copied from source
- */
void DM_from_template_ex(DerivedMesh *dm,
DerivedMesh *source,
DerivedMeshType type,
@@ -485,12 +472,6 @@ void DM_ensure_normals(DerivedMesh *dm)
BLI_assert((dm->dirty & DM_DIRTY_NORMALS) == 0);
}
-/**
- * Ensure the array is large enough
- *
- * \note This function must always be thread-protected by caller.
- * It should only be used by internal code.
- */
void DM_ensure_looptri_data(DerivedMesh *dm)
{
const unsigned int totpoly = dm->numPolyData;
@@ -519,11 +500,11 @@ void DM_ensure_looptri_data(DerivedMesh *dm)
}
}
-/** Utility function to convert an (evaluated) Mesh to a shape key block. */
-/* Just a shallow wrapper around BKE_keyblock_convert_from_mesh,
- * that ensures both evaluated mesh and original one has same number of vertices. */
void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *me, KeyBlock *kb)
{
+ /* Just a shallow wrapper around #BKE_keyblock_convert_from_mesh,
+ * that ensures both evaluated mesh and original one has same number of vertices. */
+
const int totvert = me_deformed->totvert;
if (totvert == 0 || me->totvert == 0 || me->totvert != totvert) {
@@ -533,11 +514,6 @@ void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *me, KeyBlock *kb)
BKE_keyblock_convert_from_mesh(me_deformed, me->key, kb);
}
-/**
- * set the CD_FLAG_NOCOPY flag in custom data layers where the mask is
- * zero for the layer type, so only layer types specified by the mask
- * will be copied
- */
void DM_set_only_copy(DerivedMesh *dm, const CustomData_MeshMasks *mask)
{
CustomData_set_only_copy(&dm->vertData, mask->vmask);
@@ -658,11 +634,6 @@ void DM_copy_vert_data(
CustomData_copy_data(&source->vertData, &dest->vertData, source_index, dest_index, count);
}
-/**
- * interpolates vertex data from the vertices indexed by src_indices in the
- * source mesh using the given weights and stores the result in the vertex
- * indexed by dest_index in the dest mesh
- */
void DM_interp_vert_data(DerivedMesh *source,
DerivedMesh *dest,
int *src_indices,
@@ -804,28 +775,6 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
/* Compute normals. */
const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
- /* Some modifiers may need this info from their target (other) object,
- * simpler to generate it here as well.
- * Note that they will always be generated when no loop normals are computed,
- * since they are needed by drawing code. */
- const bool do_poly_normals = ((final_datamask->pmask & CD_MASK_NORMAL) != 0);
-
- /* In case we also need poly normals, add the layer and compute them here
- * (BKE_mesh_calc_normals_split() assumes that if that data exists, it is always valid). */
- if (do_poly_normals) {
- if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
- float(*polynors)[3] = (float(*)[3])CustomData_add_layer(
- &mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly);
- BKE_mesh_calc_normals_poly_and_vertex(mesh_final->mvert,
- mesh_final->totvert,
- mesh_final->mloop,
- mesh_final->totloop,
- mesh_final->mpoly,
- mesh_final->totpoly,
- polynors,
- nullptr);
- }
- }
if (do_loop_normals) {
/* Compute loop normals (NOTE: will compute poly and vert normals as well, if needed!). */
@@ -843,11 +792,7 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
* normals and will also have to calculate normals on the fly, try avoid
* this where possible since calculating polygon normals isn't fast,
* note that this isn't a problem for subsurf (only quads) or editmode
- * which deals with drawing differently.
- *
- * Only calc vertex normals if they are flagged as dirty.
- * If using loop normals, poly nors have already been computed.
- */
+ * which deals with drawing differently. */
if (!do_loop_normals) {
BKE_mesh_ensure_normals_for_display(mesh_final);
}
@@ -886,33 +831,6 @@ void BKE_mesh_wrapper_deferred_finalize(Mesh *me_eval,
}
/**
- * Some modifiers don't work on geometry sets directly, but expect a single mesh as input.
- * Therefore, we convert data from the geometry set into a single mesh, so that those
- * modifiers can work on it as well.
- */
-static Mesh *prepare_geometry_set_for_mesh_modifier(Mesh *mesh, GeometrySet &r_geometry_set)
-{
- if (!r_geometry_set.has_instances() && !r_geometry_set.has_pointcloud()) {
- return mesh;
- }
-
- {
- /* Add the mesh to the geometry set. */
- MeshComponent &mesh_component = r_geometry_set.get_component_for_write<MeshComponent>();
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- }
- {
- /* Combine mesh and all instances into a single mesh that can be passed to the modifier. */
- GeometrySet new_geometry_set = blender::bke::geometry_set_realize_mesh_for_modifier(
- r_geometry_set);
- MeshComponent &mesh_component = new_geometry_set.get_component_for_write<MeshComponent>();
- Mesh *new_mesh = mesh_component.release();
- r_geometry_set = new_geometry_set;
- return new_mesh;
- }
-}
-
-/**
* Modifies the given mesh and geometry set. The mesh is not passed as part of the mesh component
* in the \a geometry_set input, it is only passed in \a input_mesh and returned in the return
* value.
@@ -928,14 +846,7 @@ static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md,
Mesh *mesh_output = nullptr;
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
if (mti->modifyGeometrySet == nullptr) {
- Mesh *new_input_mesh = prepare_geometry_set_for_mesh_modifier(input_mesh, geometry_set);
- mesh_output = BKE_modifier_modify_mesh(md, &mectx, new_input_mesh);
-
- /* The caller is responsible for freeing `input_mesh` and `mesh_output`. The intermediate
- * `new_input_mesh` has to be freed here. */
- if (!ELEM(new_input_mesh, input_mesh, mesh_output)) {
- BKE_id_free(nullptr, new_input_mesh);
- }
+ mesh_output = BKE_modifier_modify_mesh(md, &mectx, input_mesh);
}
else {
/* For performance reasons, this should be called by the modifier and/or nodes themselves at
@@ -955,6 +866,10 @@ static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md,
/* Release the mesh from the geometry set again. */
if (geometry_set.has<MeshComponent>()) {
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ if (mesh_component.get_for_read() != input_mesh) {
+ /* Make sure the mesh component actually owns the mesh before taking over ownership. */
+ mesh_component.ensure_owns_direct_data();
+ }
mesh_output = mesh_component.release();
}
@@ -986,6 +901,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
* constructive modifier is executed, or a deform modifier needs normals
* or certain data layers. */
Mesh *mesh_input = (Mesh *)ob->data;
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh_input);
Mesh *mesh_final = nullptr;
Mesh *mesh_deform = nullptr;
/* This geometry set contains the non-mesh data that might be generated by modifiers. */
@@ -1177,14 +1093,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* No existing verts to deform, need to build them. */
if (!deformed_verts) {
if (mesh_final) {
- Mesh *mesh_final_new = prepare_geometry_set_for_mesh_modifier(mesh_final,
- geometry_set_final);
- if (mesh_final_new != mesh_final) {
- BLI_assert(mesh_final != mesh_input);
- BKE_id_free(nullptr, mesh_final);
- mesh_final = mesh_final_new;
- }
-
/* Deforming a mesh, read the vertex locations
* out of the mesh and deform them. Once done with this
* run of deformers verts will be written back. */
@@ -1525,26 +1433,6 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
const bool do_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
- /* Some modifiers may need this info from their target (other) object,
- * simpler to generate it here as well. */
- const bool do_poly_normals = ((final_datamask->pmask & CD_MASK_NORMAL) != 0);
-
- /* In case we also need poly normals, add the layer and compute them here
- * (BKE_mesh_calc_normals_split() assumes that if that data exists, it is always valid). */
- if (do_poly_normals) {
- if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
- float(*polynors)[3] = (float(*)[3])CustomData_add_layer(
- &mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly);
- BKE_mesh_calc_normals_poly_and_vertex(mesh_final->mvert,
- mesh_final->totvert,
- mesh_final->mloop,
- mesh_final->totloop,
- mesh_final->mpoly,
- mesh_final->totpoly,
- polynors,
- nullptr);
- }
- }
if (do_loop_normals) {
/* Compute loop normals */
@@ -1875,31 +1763,12 @@ static void mesh_build_extra_data(struct Depsgraph *depsgraph, Object *ob, Mesh
}
}
-static void mesh_runtime_check_normals_valid(const Mesh *mesh)
-{
- UNUSED_VARS_NDEBUG(mesh);
- BLI_assert(!(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL));
- BLI_assert(!(mesh->runtime.cd_dirty_loop & CD_MASK_NORMAL));
- BLI_assert(!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL));
-}
-
static void mesh_build_data(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask,
const bool need_mapping)
{
- BLI_assert(ob->type == OB_MESH);
-
- /* Evaluated meshes aren't supposed to be created on original instances. If you do,
- * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
- BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
-
- BKE_object_free_derived_caches(ob);
- if (DEG_is_active(depsgraph)) {
- BKE_sculpt_update_object_before_eval(ob);
- }
-
#if 0 /* XXX This is already taken care of in mesh_calc_modifiers()... */
if (need_mapping) {
/* Also add the flag so that it is recorded in lastDataMask. */
@@ -1934,9 +1803,9 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
const bool is_mesh_eval_owned = (mesh_eval != mesh->runtime.mesh_eval);
BKE_object_eval_assign_data(ob, &mesh_eval->id, is_mesh_eval_owned);
- /* Add the final mesh as read-only non-owning component to the geometry set. */
+ /* Add the final mesh as a non-owning component to the geometry set. */
MeshComponent &mesh_component = geometry_set_eval->get_component_for_write<MeshComponent>();
- mesh_component.replace(mesh_eval, GeometryOwnershipType::ReadOnly);
+ mesh_component.replace(mesh_eval, GeometryOwnershipType::Editable);
ob->runtime.geometry_set_eval = geometry_set_eval;
ob->runtime.mesh_deform_eval = mesh_deform_eval;
@@ -1957,7 +1826,6 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
}
}
- mesh_runtime_check_normals_valid(mesh_eval);
mesh_build_extra_data(depsgraph, ob, mesh_eval);
}
@@ -1967,15 +1835,7 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph,
BMEditMesh *em,
CustomData_MeshMasks *dataMask)
{
- BLI_assert(obedit->id.tag & LIB_TAG_COPIED_ON_WRITE);
-
- BKE_object_free_derived_caches(obedit);
- if (DEG_is_active(depsgraph)) {
- BKE_sculpt_update_object_before_eval(obedit);
- }
-
- BKE_editmesh_free_derived_caches(em);
-
+ Mesh *mesh = static_cast<Mesh *>(obedit->data);
Mesh *me_cage;
Mesh *me_final;
GeometrySet *non_mesh_components;
@@ -1983,15 +1843,33 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph,
editbmesh_calc_modifiers(
depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final, &non_mesh_components);
- em->mesh_eval_final = me_final;
- em->mesh_eval_cage = me_cage;
- obedit->runtime.geometry_set_eval = non_mesh_components;
+ /* The modifier stack result is expected to share edit mesh pointer with the input.
+ * This is similar `mesh_calc_finalize()`. */
+ BKE_mesh_free_editmesh(me_final);
+ BKE_mesh_free_editmesh(me_cage);
+ me_final->edit_mesh = me_cage->edit_mesh = em;
+
+ /* Object has edit_mesh but is not in edit mode (object shares mesh datablock with another object
+ * with is in edit mode).
+ * Convert edit mesh to mesh until the draw manager can draw mesh wrapper which is not in the
+ * edit mode. */
+ if (!(obedit->mode & OB_MODE_EDIT)) {
+ BKE_mesh_wrapper_ensure_mdata(me_final);
+ if (me_final != me_cage) {
+ BKE_mesh_wrapper_ensure_mdata(me_cage);
+ }
+ }
- BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final);
+ const bool is_mesh_eval_owned = (me_final != mesh->runtime.mesh_eval);
+ BKE_object_eval_assign_data(obedit, &me_final->id, is_mesh_eval_owned);
- em->lastDataMask = *dataMask;
+ obedit->runtime.editmesh_eval_cage = me_cage;
- mesh_runtime_check_normals_valid(em->mesh_eval_final);
+ obedit->runtime.geometry_set_eval = non_mesh_components;
+
+ BKE_object_boundbox_calc_from_mesh(obedit, me_final);
+
+ obedit->runtime.last_data_mask = *dataMask;
}
static void object_get_datamask(const Depsgraph *depsgraph,
@@ -2047,9 +1925,25 @@ static void object_get_datamask(const Depsgraph *depsgraph,
void makeDerivedMesh(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
- BMEditMesh *em,
const CustomData_MeshMasks *dataMask)
{
+ BLI_assert(ob->type == OB_MESH);
+
+ /* Evaluated meshes aren't supposed to be created on original instances. If you do,
+ * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
+ BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
+
+ BKE_object_free_derived_caches(ob);
+ if (DEG_is_active(depsgraph)) {
+ BKE_sculpt_update_object_before_eval(ob);
+ }
+
+ /* NOTE: Access the `edit_mesh` after freeing the derived caches, so that `ob->data` is restored
+ * to the pre-evaluated state. This is because the evaluated state is not necessarily sharing the
+ * `edit_mesh` pointer with the input. For example, if the object is first evaluated in the
+ * object mode, and then user in another scene moves object to edit mode. */
+ BMEditMesh *em = ((Mesh *)ob->data)->edit_mesh;
+
bool need_mapping;
CustomData_MeshMasks cddata_masks = *dataMask;
object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
@@ -2088,8 +1982,9 @@ Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
!CustomData_MeshMasks_are_matching(&(ob->runtime.last_data_mask), &cddata_masks) ||
(need_mapping && !ob->runtime.last_need_mapping)) {
CustomData_MeshMasks_update(&cddata_masks, &ob->runtime.last_data_mask);
- mesh_build_data(
- depsgraph, scene, ob, &cddata_masks, need_mapping || ob->runtime.last_need_mapping);
+
+ makeDerivedMesh(depsgraph, scene, ob, dataMask);
+
mesh_eval = BKE_object_get_evaluated_mesh(ob);
}
@@ -2104,6 +1999,15 @@ Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
+ BMEditMesh *em = ((Mesh *)ob->data)->edit_mesh;
+ if (em != nullptr) {
+ /* There is no such a concept as deformed mesh in edit mode.
+ * Explicitly disallow this request so that the evaluated result is not modified with evaluated
+ * result from the wrong mode. */
+ BLI_assert_msg(0, "Request of derformed mesh of object which is in edit mode");
+ return nullptr;
+ }
+
/* This function isn't thread-safe and can't be used during evaluation. */
BLI_assert(DEG_is_evaluating(depsgraph) == false);
@@ -2135,26 +2039,10 @@ Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
- Mesh *final;
-
+ Mesh *result;
mesh_calc_modifiers(
- depsgraph, scene, ob, true, false, dataMask, -1, false, false, nullptr, &final, nullptr);
-
- return final;
-}
-
-Mesh *mesh_create_eval_final_index_render(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- const CustomData_MeshMasks *dataMask,
- int index)
-{
- Mesh *final;
-
- mesh_calc_modifiers(
- depsgraph, scene, ob, true, false, dataMask, index, false, false, nullptr, &final, nullptr);
-
- return final;
+ depsgraph, scene, ob, true, false, dataMask, -1, false, false, nullptr, &result, nullptr);
+ return result;
}
Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
@@ -2162,12 +2050,10 @@ Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
- Mesh *final;
-
+ Mesh *result;
mesh_calc_modifiers(
- depsgraph, scene, ob, false, false, dataMask, -1, false, false, nullptr, &final, nullptr);
-
- return final;
+ depsgraph, scene, ob, false, false, dataMask, -1, false, false, nullptr, &result, nullptr);
+ return result;
}
Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
@@ -2175,43 +2061,14 @@ Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
- Mesh *final;
-
+ Mesh *result;
mesh_calc_modifiers(
- depsgraph, scene, ob, false, false, dataMask, -1, false, false, nullptr, &final, nullptr);
-
- return final;
+ depsgraph, scene, ob, false, false, dataMask, -1, false, false, nullptr, &result, nullptr);
+ return result;
}
/***/
-Mesh *editbmesh_get_eval_cage_and_final(Depsgraph *depsgraph,
- Scene *scene,
- Object *obedit,
- BMEditMesh *em,
- const CustomData_MeshMasks *dataMask,
- /* return args */
- Mesh **r_final)
-{
- CustomData_MeshMasks cddata_masks = *dataMask;
-
- /* if there's no derived mesh or the last data mask used doesn't include
- * the data we need, rebuild the derived mesh
- */
- object_get_datamask(depsgraph, obedit, &cddata_masks, nullptr);
-
- if (!em->mesh_eval_cage ||
- !CustomData_MeshMasks_are_matching(&(em->lastDataMask), &cddata_masks)) {
- editbmesh_build_data(depsgraph, scene, obedit, em, &cddata_masks);
- }
-
- *r_final = em->mesh_eval_final;
- if (em->mesh_eval_final) {
- BLI_assert(!(em->mesh_eval_final->runtime.cd_dirty_vert & DM_DIRTY_NORMALS));
- }
- return em->mesh_eval_cage;
-}
-
Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
Scene *scene,
Object *obedit,
@@ -2225,12 +2082,12 @@ Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
*/
object_get_datamask(depsgraph, obedit, &cddata_masks, nullptr);
- if (!em->mesh_eval_cage ||
- !CustomData_MeshMasks_are_matching(&(em->lastDataMask), &cddata_masks)) {
+ if (!obedit->runtime.editmesh_eval_cage ||
+ !CustomData_MeshMasks_are_matching(&(obedit->runtime.last_data_mask), &cddata_masks)) {
editbmesh_build_data(depsgraph, scene, obedit, em, &cddata_masks);
}
- return em->mesh_eval_cage;
+ return obedit->runtime.editmesh_eval_cage;
}
Mesh *editbmesh_get_eval_cage_from_orig(struct Depsgraph *depsgraph,
@@ -2256,8 +2113,7 @@ struct MappedUserData {
static void make_vertexcos__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
MappedUserData *mappedData = (MappedUserData *)userData;
@@ -2304,6 +2160,7 @@ void DM_calc_loop_tangents(DerivedMesh *dm,
calc_active_tangent,
tangent_names,
tangent_names_len,
+ (const float(*)[3])CustomData_get_layer(&dm->vertData, CD_NORMAL),
(const float(*)[3])CustomData_get_layer(&dm->polyData, CD_NORMAL),
(const float(*)[3])dm->getLoopDataArray(dm, CD_NORMAL),
(const float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* may be nullptr */
@@ -2386,145 +2243,3 @@ static void mesh_init_origspace(Mesh *mesh)
BKE_mesh_tessface_clear(mesh);
}
-
-/* derivedmesh info printing function,
- * to help track down differences DM output */
-
-#ifndef NDEBUG
-# include "BLI_dynstr.h"
-
-static void dm_debug_info_layers(DynStr *dynstr,
- DerivedMesh *dm,
- CustomData *cd,
- void *(*getElemDataArray)(DerivedMesh *, int))
-{
- int type;
-
- for (type = 0; type < CD_NUMTYPES; type++) {
- if (CustomData_has_layer(cd, type)) {
- /* NOTE: doesn't account for multiple layers. */
- const char *name = CustomData_layertype_name(type);
- const int size = CustomData_sizeof(type);
- const void *pt = getElemDataArray(dm, type);
- const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
- const char *structname;
- int structnum;
- CustomData_file_write_info(type, &structname, &structnum);
- BLI_dynstr_appendf(
- dynstr,
- " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
- name,
- structname,
- type,
- (const void *)pt,
- size,
- pt_size);
- }
- }
-}
-
-char *DM_debug_info(DerivedMesh *dm)
-{
- DynStr *dynstr = BLI_dynstr_new();
- char *ret;
- const char *tstr;
-
- BLI_dynstr_append(dynstr, "{\n");
- BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)dm);
- switch (dm->type) {
- case DM_TYPE_CDDM:
- tstr = "DM_TYPE_CDDM";
- break;
- case DM_TYPE_CCGDM:
- tstr = "DM_TYPE_CCGDM";
- break;
- default:
- tstr = "UNKNOWN";
- break;
- }
- BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr);
- BLI_dynstr_appendf(dynstr, " 'numVertData': %d,\n", dm->numVertData);
- BLI_dynstr_appendf(dynstr, " 'numEdgeData': %d,\n", dm->numEdgeData);
- BLI_dynstr_appendf(dynstr, " 'numTessFaceData': %d,\n", dm->numTessFaceData);
- BLI_dynstr_appendf(dynstr, " 'numPolyData': %d,\n", dm->numPolyData);
- BLI_dynstr_appendf(dynstr, " 'deformedOnly': %d,\n", dm->deformedOnly);
-
- BLI_dynstr_append(dynstr, " 'vertexLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->vertData, dm->getVertDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'edgeLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->edgeData, dm->getEdgeDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'loopLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->loopData, dm->getLoopDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'polyLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->polyData, dm->getPolyDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'tessFaceLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->faceData, dm->getTessFaceDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, "}\n");
-
- ret = BLI_dynstr_get_cstring(dynstr);
- BLI_dynstr_free(dynstr);
- return ret;
-}
-
-void DM_debug_print(DerivedMesh *dm)
-{
- char *str = DM_debug_info(dm);
- puts(str);
- fflush(stdout);
- MEM_freeN(str);
-}
-
-bool DM_is_valid(DerivedMesh *dm)
-{
- const bool do_verbose = true;
- const bool do_fixes = false;
-
- bool is_valid = true;
- bool changed = true;
-
- is_valid &= BKE_mesh_validate_all_customdata(
- dm->getVertDataLayout(dm),
- dm->getNumVerts(dm),
- dm->getEdgeDataLayout(dm),
- dm->getNumEdges(dm),
- dm->getLoopDataLayout(dm),
- dm->getNumLoops(dm),
- dm->getPolyDataLayout(dm),
- dm->getNumPolys(dm),
- false, /* setting mask here isn't useful, gives false positives */
- do_verbose,
- do_fixes,
- &changed);
-
- is_valid &= BKE_mesh_validate_arrays(nullptr,
- dm->getVertArray(dm),
- dm->getNumVerts(dm),
- dm->getEdgeArray(dm),
- dm->getNumEdges(dm),
- dm->getTessFaceArray(dm),
- dm->getNumTessFaces(dm),
- dm->getLoopArray(dm),
- dm->getNumLoops(dm),
- dm->getPolyArray(dm),
- dm->getNumPolys(dm),
- (MDeformVert *)dm->getVertDataArray(dm, CD_MDEFORMVERT),
- do_verbose,
- do_fixes,
- &changed);
-
- BLI_assert(changed == false);
-
- return is_valid;
-}
-
-#endif /* NDEBUG */
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 16d269f9e26..fde42304185 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -51,6 +51,7 @@
#include "BKE_anim_visualization.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
+#include "BKE_asset.h"
#include "BKE_constraint.h"
#include "BKE_deform.h"
#include "BKE_fcurve.h"
@@ -175,11 +176,11 @@ static void action_foreach_id(ID *id, LibraryForeachIDData *data)
bAction *act = (bAction *)id;
LISTBASE_FOREACH (FCurve *, fcu, &act->curves) {
- BKE_fcurve_foreach_id(fcu, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data));
}
LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) {
- BKE_LIB_FOREACHID_PROCESS(data, marker->camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, marker->camera, IDWALK_CB_NOP);
}
}
@@ -286,6 +287,30 @@ static void action_blend_read_expand(BlendExpander *expander, ID *id)
}
}
+static IDProperty *action_asset_type_property(const bAction *action)
+{
+ const bool is_single_frame = BKE_action_has_single_frame(action);
+
+ IDPropertyTemplate idprop = {0};
+ idprop.i = is_single_frame;
+
+ IDProperty *property = IDP_New(IDP_INT, &idprop, "is_single_frame");
+ return property;
+}
+
+static void action_asset_pre_save(void *asset_ptr, struct AssetMetaData *asset_data)
+{
+ bAction *action = (bAction *)asset_ptr;
+ BLI_assert(GS(action->id.name) == ID_AC);
+
+ IDProperty *action_type = action_asset_type_property(action);
+ BKE_asset_metadata_idprop_ensure(asset_data, action_type);
+}
+
+static AssetTypeInfo AssetType_AC = {
+ /* pre_save_fn */ action_asset_pre_save,
+};
+
IDTypeInfo IDType_ID_AC = {
.id_code = ID_AC,
.id_filter = FILTER_ID_AC,
@@ -295,6 +320,7 @@ IDTypeInfo IDType_ID_AC = {
.name_plural = "actions",
.translation_context = BLT_I18NCONTEXT_ID_ACTION,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = &AssetType_AC,
.init_data = NULL,
.copy_data = action_copy_data,
@@ -302,6 +328,7 @@ IDTypeInfo IDType_ID_AC = {
.make_local = NULL,
.foreach_id = action_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = action_blend_write,
@@ -329,7 +356,6 @@ bAction *BKE_action_add(Main *bmain, const char name[])
/* *************** Action Groups *************** */
-/* Get the active action-group for an Action */
bActionGroup *get_active_actiongroup(bAction *act)
{
bActionGroup *agrp = NULL;
@@ -345,7 +371,6 @@ bActionGroup *get_active_actiongroup(bAction *act)
return agrp;
}
-/* Make the given Action-Group the active one */
void set_active_action_group(bAction *act, bActionGroup *agrp, short select)
{
bActionGroup *grp;
@@ -366,7 +391,6 @@ void set_active_action_group(bAction *act, bActionGroup *agrp, short select)
}
}
-/* Sync colors used for action/bone group with theme settings */
void action_group_colors_sync(bActionGroup *grp, const bActionGroup *ref_grp)
{
/* Only do color copying if using a custom color (i.e. not default color). */
@@ -397,7 +421,6 @@ void action_group_colors_sync(bActionGroup *grp, const bActionGroup *ref_grp)
}
}
-/* Add a new action group with the given name to the action */
bActionGroup *action_groups_add_new(bAction *act, const char name[])
{
bActionGroup *agrp;
@@ -423,10 +446,6 @@ bActionGroup *action_groups_add_new(bAction *act, const char name[])
return agrp;
}
-/* Add given channel into (active) group
- * - assumes that channel is not linked to anything anymore
- * - always adds at the end of the group
- */
void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve)
{
/* sanity checks */
@@ -495,10 +514,6 @@ void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve)
fcurve->grp = agrp;
}
-/* Reconstruct group channel pointers.
- * Assumes that the groups referred to by the FCurves are already in act->groups.
- * Reorders the main channel list to match group order.
- */
void BKE_action_groups_reconstruct(bAction *act)
{
/* Sanity check. */
@@ -538,7 +553,6 @@ void BKE_action_groups_reconstruct(bAction *act)
BLI_movelisttolist(&act->curves, &ungrouped);
}
-/* Remove the given channel from all groups */
void action_groups_remove_channel(bAction *act, FCurve *fcu)
{
/* sanity checks */
@@ -579,7 +593,6 @@ void action_groups_remove_channel(bAction *act, FCurve *fcu)
BLI_remlink(&act->curves, fcu);
}
-/* Find a group with the given name */
bActionGroup *BKE_action_group_find_name(bAction *act, const char name[])
{
/* sanity checks */
@@ -591,7 +604,6 @@ bActionGroup *BKE_action_group_find_name(bAction *act, const char name[])
return BLI_findstring(&act->groups, name, offsetof(bActionGroup, name));
}
-/* Clear all 'temp' flags on all groups */
void action_groups_clear_tempflags(bAction *act)
{
bActionGroup *agrp;
@@ -614,10 +626,6 @@ void BKE_pose_channel_session_uuid_generate(bPoseChannel *pchan)
pchan->runtime.session_uuid = BLI_session_uuid_generate();
}
-/**
- * Return a pointer to the pose channel of the given name
- * from this pose.
- */
bPoseChannel *BKE_pose_channel_find_name(const bPose *pose, const char *name)
{
if (ELEM(NULL, pose, name) || (name[0] == '\0')) {
@@ -631,14 +639,6 @@ bPoseChannel *BKE_pose_channel_find_name(const bPose *pose, const char *name)
return BLI_findstring(&pose->chanbase, name, offsetof(bPoseChannel, name));
}
-/**
- * Looks to see if the channel with the given name
- * already exists in this pose - if not a new one is
- * allocated and initialized.
- *
- * \note Use with care, not on Armature poses but for temporal ones.
- * \note (currently used for action constraints and in rebuild_pose).
- */
bPoseChannel *BKE_pose_channel_ensure(bPose *pose, const char *name)
{
bPoseChannel *chan;
@@ -705,13 +705,12 @@ bool BKE_pose_channels_is_valid(const bPose *pose)
#endif
-/**
- * Find the active pose-channel for an object
- * (we can't just use pose, as layer info is in armature)
- *
- * \note #Object, not #bPose is used here, as we need layer info from Armature.
- */
-bPoseChannel *BKE_pose_channel_active(Object *ob)
+bool BKE_pose_is_layer_visible(const bArmature *arm, const bPoseChannel *pchan)
+{
+ return (pchan->bone->layer & arm->layer);
+}
+
+bPoseChannel *BKE_pose_channel_active(Object *ob, const bool check_arm_layer)
{
bArmature *arm = (ob) ? ob->data : NULL;
bPoseChannel *pchan;
@@ -722,23 +721,21 @@ bPoseChannel *BKE_pose_channel_active(Object *ob)
/* find active */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone) && (pchan->bone == arm->act_bone) && (pchan->bone->layer & arm->layer)) {
- return pchan;
+ if ((pchan->bone) && (pchan->bone == arm->act_bone)) {
+ if (!check_arm_layer || BKE_pose_is_layer_visible(arm, pchan)) {
+ return pchan;
+ }
}
}
return NULL;
}
-/**
- * Use this when detecting the "other selected bone",
- * when we have multiple armatures in pose mode.
- *
- * In this case the active-selected is an obvious choice when finding the target for a
- * constraint for eg. however from the users perspective the active pose bone of the
- * active object is the _real_ active bone, so any other non-active selected bone
- * is a candidate for being the other selected bone, see: T58447.
- */
+bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob)
+{
+ return BKE_pose_channel_active(ob, true);
+}
+
bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob)
{
bArmature *arm = (ob) ? ob->data : NULL;
@@ -747,7 +744,7 @@ bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob)
return NULL;
}
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && (pchan->bone->flag & BONE_SELECTED) && PBONE_VISIBLE(arm, pchan->bone)) {
return pchan;
}
@@ -762,9 +759,6 @@ bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob)
return NULL;
}
-/**
- * \see #ED_armature_ebone_get_mirrored (edit-mode, matching function)
- */
bPoseChannel *BKE_pose_channel_get_mirrored(const bPose *pose, const char *name)
{
char name_flip[MAXBONENAME];
@@ -791,12 +785,6 @@ const char *BKE_pose_ikparam_get_name(bPose *pose)
return NULL;
}
-/**
- * Allocate a new pose on the heap, and copy the src pose and its channels
- * into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL.
- *
- * \param dst: Should be freed already, makes entire duplicate.
- */
void BKE_pose_copy_data_ex(bPose **dst,
const bPose *src,
const int flag,
@@ -948,10 +936,6 @@ bool BKE_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
return pose_channel_in_IK_chain(ob, pchan, 0);
}
-/**
- * Removes the hash for quick lookup of channels, must
- * be done when adding/removing channels.
- */
void BKE_pose_channels_hash_ensure(bPose *pose)
{
if (!pose->chanhash) {
@@ -987,9 +971,6 @@ static void pose_channels_remove_internal_links(Object *ob, bPoseChannel *unlink
}
}
-/**
- * Selectively remove pose channels.
- */
void BKE_pose_channels_remove(Object *ob,
bool (*filter_fn)(const char *bone_name, void *user_data),
void *user_data)
@@ -1059,10 +1040,6 @@ void BKE_pose_channels_remove(Object *ob,
}
}
-/**
- * Deallocates a pose channel.
- * Does not free the pose channel itself.
- */
void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user)
{
if (pchan->custom) {
@@ -1091,13 +1068,11 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user)
BKE_pose_channel_runtime_free(&pchan->runtime);
}
-/** Clears the runtime cache of a pose channel without free. */
void BKE_pose_channel_runtime_reset(bPoseChannel_Runtime *runtime)
{
memset(runtime, 0, sizeof(*runtime));
}
-/* Reset all non-persistent fields. */
void BKE_pose_channel_runtime_reset_on_copy(bPoseChannel_Runtime *runtime)
{
const SessionUUID uuid = runtime->session_uuid;
@@ -1105,13 +1080,11 @@ void BKE_pose_channel_runtime_reset_on_copy(bPoseChannel_Runtime *runtime)
runtime->session_uuid = uuid;
}
-/** Deallocates runtime cache of a pose channel */
void BKE_pose_channel_runtime_free(bPoseChannel_Runtime *runtime)
{
BKE_pose_channel_free_bbone_cache(runtime);
}
-/** Deallocates runtime cache of a pose channel's B-Bone shape. */
void BKE_pose_channel_free_bbone_cache(bPoseChannel_Runtime *runtime)
{
runtime->bbone_segments = 0;
@@ -1126,10 +1099,6 @@ void BKE_pose_channel_free(bPoseChannel *pchan)
BKE_pose_channel_free_ex(pchan, true);
}
-/**
- * Removes and deallocates all channels from a pose.
- * Does not free the pose itself.
- */
void BKE_pose_channels_free_ex(bPose *pose, bool do_id_user)
{
bPoseChannel *pchan;
@@ -1176,9 +1145,6 @@ void BKE_pose_free_data(bPose *pose)
BKE_pose_free_data_ex(pose, true);
}
-/**
- * Removes and deallocates all data from a pose, and also frees the pose.
- */
void BKE_pose_free_ex(bPose *pose, bool do_id_user)
{
if (pose) {
@@ -1193,13 +1159,6 @@ void BKE_pose_free(bPose *pose)
BKE_pose_free_ex(pose, true);
}
-/**
- * Copy the internal members of each pose channel including constraints
- * and ID-Props, used when duplicating bones in editmode.
- * (unlike copy_pose_channel_data which only does posing-related stuff).
- *
- * \note use when copying bones in editmode (on returned value from #BKE_pose_channel_ensure)
- */
void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_from)
{
/* copy transform locks */
@@ -1211,7 +1170,7 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f
/* copy bone group */
pchan->agrp_index = pchan_from->agrp_index;
- /* ik (dof) settings */
+ /* IK (DOF) settings. */
pchan->ikflag = pchan_from->ikflag;
copy_v3_v3(pchan->limitmin, pchan_from->limitmin);
copy_v3_v3(pchan->limitmax, pchan_from->limitmax);
@@ -1249,10 +1208,6 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f
pchan->drawflag = pchan_from->drawflag;
}
-/* checks for IK constraint, Spline IK, and also for Follow-Path constraint.
- * can do more constraints flags later
- */
-/* pose should be entirely OK */
void BKE_pose_update_constraint_flags(bPose *pose)
{
bPoseChannel *pchan, *parchan;
@@ -1327,7 +1282,6 @@ void BKE_pose_tag_update_constraint_flags(bPose *pose)
/* ************************** Bone Groups ************************** */
-/* Adds a new bone-group (name may be NULL) */
bActionGroup *BKE_pose_add_group(bPose *pose, const char *name)
{
bActionGroup *grp;
@@ -1346,8 +1300,6 @@ bActionGroup *BKE_pose_add_group(bPose *pose, const char *name)
return grp;
}
-/* Remove the given bone-group (expects 'virtual' index (+1 one, used by active_group etc.))
- * index might be invalid ( < 1), in which case it will be find from grp. */
void BKE_pose_remove_group(bPose *pose, bActionGroup *grp, const int index)
{
bPoseChannel *pchan;
@@ -1386,7 +1338,6 @@ void BKE_pose_remove_group(bPose *pose, bActionGroup *grp, const int index)
}
}
-/* Remove the indexed bone-group (expects 'virtual' index (+1 one, used by active_group etc.)) */
void BKE_pose_remove_group_index(bPose *pose, const int index)
{
bActionGroup *grp = NULL;
@@ -1400,7 +1351,6 @@ void BKE_pose_remove_group_index(bPose *pose, const int index)
/* ************** F-Curve Utilities for Actions ****************** */
-/* Check if the given action has any keyframes */
bool action_has_motion(const bAction *act)
{
FCurve *fcu;
@@ -1418,7 +1368,47 @@ bool action_has_motion(const bAction *act)
return false;
}
-/* Calculate the extents of given action */
+bool BKE_action_has_single_frame(const struct bAction *act)
+{
+ if (act == NULL || BLI_listbase_is_empty(&act->curves)) {
+ return false;
+ }
+
+ bool found_key = false;
+ float found_key_frame = 0.0f;
+
+ LISTBASE_FOREACH (FCurve *, fcu, &act->curves) {
+ switch (fcu->totvert) {
+ case 0:
+ /* No keys, so impossible to come to a conclusion on this curve alone. */
+ continue;
+ case 1:
+ /* Single key, which is the complex case, so handle below. */
+ break;
+ default:
+ /* Multiple keys, so there is animation. */
+ return false;
+ }
+
+ const float this_key_frame = fcu->bezt != NULL ? fcu->bezt[0].vec[1][0] : fcu->fpt[0].vec[0];
+ if (!found_key) {
+ found_key = true;
+ found_key_frame = this_key_frame;
+ continue;
+ }
+
+ /* The graph editor rounds to 1/1000th of a frame, so it's not necessary to be really precise
+ * with these comparisons. */
+ if (!compare_ff(found_key_frame, this_key_frame, 0.001f)) {
+ /* This key differs from the already-found key, so this Action represents animation. */
+ return false;
+ }
+ }
+
+ /* There is only a single frame if we found at least one key. */
+ return found_key;
+}
+
void calc_action_range(const bAction *act, float *start, float *end, short incl_modifiers)
{
FCurve *fcu;
@@ -1506,9 +1496,27 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
}
}
-/* Return flags indicating which transforms the given object/posechannel has
- * - if 'curves' is provided, a list of links to these curves are also returned
- */
+void BKE_action_get_frame_range(const struct bAction *act, float *r_start, float *r_end)
+{
+ if (act && (act->flag & ACT_FRAME_RANGE)) {
+ *r_start = act->frame_start;
+ *r_end = act->frame_end;
+ }
+ else {
+ calc_action_range(act, r_start, r_end, false);
+ }
+
+ /* Ensure that action is at least 1 frame long (for NLA strips to have a valid length). */
+ if (*r_start >= *r_end) {
+ *r_end = *r_start + 1.0f;
+ }
+}
+
+bool BKE_action_is_cyclic(const struct bAction *act)
+{
+ return act && (act->flag & ACT_FRAME_RANGE) && (act->flag & ACT_CYCLIC);
+}
+
short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan, ListBase *curves)
{
PointerRNA ptr;
@@ -1639,9 +1647,6 @@ short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan,
/* ************** Pose Management Tools ****************** */
-/**
- * Zero the pose transforms for the entire pose or only for selected bones.
- */
void BKE_pose_rest(bPose *pose, bool selected_bones_only)
{
bPoseChannel *pchan;
@@ -1706,7 +1711,6 @@ void BKE_pose_copy_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchan
pchanto->protectflag = pchanfrom->protectflag;
}
-/* both poses should be in sync */
bool BKE_pose_copy_result(bPose *to, bPose *from)
{
bPoseChannel *pchanto, *pchanfrom;
@@ -1731,7 +1735,6 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
return true;
}
-/* Tag pose for recalc. Also tag all related data to be recalc. */
void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
{
pose->flag |= POSE_RECALC;
@@ -1741,9 +1744,6 @@ void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
DEG_relations_tag_update(bmain);
}
-/* For the calculation of the effects of an Action at the given frame on an object
- * This is currently only used for the Action Constraint
- */
void what_does_obaction(Object *ob,
Object *workob,
bPose *pose,
diff --git a/source/blender/blenkernel/intern/action_mirror.c b/source/blender/blenkernel/intern/action_mirror.c
index 48472dfc9b3..cc3a15aa546 100644
--- a/source/blender/blenkernel/intern/action_mirror.c
+++ b/source/blender/blenkernel/intern/action_mirror.c
@@ -327,10 +327,10 @@ static void action_flip_pchan(Object *ob_arm,
* the X-axis, it turns into a 180 degree rotation over the Y-axis.
* This has only been observed with bones that can't be flipped,
* hence the check for `pchan_flip`. */
- const float unit_x[4] = {1.0f, 0.0f, 0.0f, 0.0f};
- const bool is_problematic = pchan_flip == NULL &&
- fabsf(dot_v4v4(pchan->bone->arm_mat[0], unit_x)) <= 1e-6;
- if (is_problematic) {
+ const float unit_x[3] = {1.0f, 0.0f, 0.0f};
+ const bool is_x_axis_orthogonal = (pchan_flip == NULL) &&
+ (fabsf(dot_v3v3(pchan->bone->arm_mat[0], unit_x)) <= 1e-6f);
+ if (is_x_axis_orthogonal) {
/* Matrix needs to flip both the X and Z axes to come out right. */
float extra_mat[4][4] = {
{-1.0f, 0.0f, 0.0f, 0.0f},
diff --git a/source/blender/blenkernel/intern/action_test.cc b/source/blender/blenkernel/intern/action_test.cc
index c02eca966ad..8423bc923f3 100644
--- a/source/blender/blenkernel/intern/action_test.cc
+++ b/source/blender/blenkernel/intern/action_test.cc
@@ -24,6 +24,8 @@
#include "BLI_listbase.h"
+#include "MEM_guardedalloc.h"
+
#include "testing/testing.h"
namespace blender::bke::tests {
@@ -141,4 +143,97 @@ TEST(action_groups, ReconstructGroupsWithReordering)
EXPECT_EQ(groupDcurve2.next, nullptr);
}
+namespace {
+
+/* Allocate fcu->bezt, and also return a unique_ptr to it for easily freeing the memory. */
+std::unique_ptr<BezTriple[]> allocate_keyframes(FCurve *fcu, const size_t num_keyframes)
+{
+ auto bezt_uptr = std::make_unique<BezTriple[]>(num_keyframes);
+ fcu->bezt = bezt_uptr.get();
+ return bezt_uptr;
+}
+
+/* Append keyframe, assumes that fcu->bezt is allocated and has enough space. */
+void add_keyframe(FCurve *fcu, float x, float y)
+{
+ /* The insert_keyframe functions are in the editors, so we cannot link to those here. */
+ BezTriple the_keyframe;
+ memset(&the_keyframe, 0, sizeof(the_keyframe));
+
+ /* Copied from insert_vert_fcurve() in keyframing.c. */
+ the_keyframe.vec[0][0] = x - 1.0f;
+ the_keyframe.vec[0][1] = y;
+ the_keyframe.vec[1][0] = x;
+ the_keyframe.vec[1][1] = y;
+ the_keyframe.vec[2][0] = x + 1.0f;
+ the_keyframe.vec[2][1] = y;
+
+ memcpy(&fcu->bezt[fcu->totvert], &the_keyframe, sizeof(the_keyframe));
+ fcu->totvert++;
+}
+
+} // namespace
+
+TEST(action_assets, BKE_action_has_single_frame)
+{
+ /* NULL action. */
+ EXPECT_FALSE(BKE_action_has_single_frame(nullptr)) << "NULL Action cannot have a single frame.";
+
+ /* No FCurves. */
+ {
+ const bAction empty = {{nullptr}};
+ EXPECT_FALSE(BKE_action_has_single_frame(&empty))
+ << "Action without FCurves cannot have a single frame.";
+ }
+
+ /* One curve with one key. */
+ {
+ FCurve fcu = {nullptr};
+ std::unique_ptr<BezTriple[]> bezt = allocate_keyframes(&fcu, 1);
+ add_keyframe(&fcu, 1.0f, 2.0f);
+
+ bAction action = {{nullptr}};
+ BLI_addtail(&action.curves, &fcu);
+
+ EXPECT_TRUE(BKE_action_has_single_frame(&action))
+ << "Action with one FCurve and one key should have single frame.";
+ }
+
+ /* Two curves with one key each. */
+ {
+ FCurve fcu1 = {nullptr};
+ FCurve fcu2 = {nullptr};
+ std::unique_ptr<BezTriple[]> bezt1 = allocate_keyframes(&fcu1, 1);
+ std::unique_ptr<BezTriple[]> bezt2 = allocate_keyframes(&fcu2, 1);
+ add_keyframe(&fcu1, 1.0f, 327.0f);
+ add_keyframe(&fcu2, 1.0f, 47.0f); /* Same X-coordinate as the other one. */
+
+ bAction action = {{nullptr}};
+ BLI_addtail(&action.curves, &fcu1);
+ BLI_addtail(&action.curves, &fcu2);
+
+ EXPECT_TRUE(BKE_action_has_single_frame(&action))
+ << "Two FCurves with keys on the same frame should have single frame.";
+
+ /* Modify the 2nd curve so it's keyed on a different frame. */
+ fcu2.bezt[0].vec[1][0] = 2.0f;
+ EXPECT_FALSE(BKE_action_has_single_frame(&action))
+ << "Two FCurves with keys on different frames should have animation.";
+ }
+
+ /* One curve with two keys. */
+ {
+ FCurve fcu = {nullptr};
+ std::unique_ptr<BezTriple[]> bezt = allocate_keyframes(&fcu, 2);
+ add_keyframe(&fcu, 1.0f, 2.0f);
+ add_keyframe(&fcu, 2.0f, 2.5f);
+
+ bAction action = {{nullptr}};
+ BLI_addtail(&action.curves, &fcu);
+
+ EXPECT_FALSE(BKE_action_has_single_frame(&action))
+ << "Action with one FCurve and two keys must have animation.";
+ }
+}
+
} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index 7e4ab754500..42b72a7cd66 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -69,7 +69,6 @@ static CLG_LogRef LOG = {"bke.anim_sys"};
/* Getter/Setter -------------------------------------------- */
-/* Check if ID can have AnimData */
bool id_type_can_have_animdata(const short id_type)
{
const IDTypeInfo *typeinfo = BKE_idtype_get_info_from_idcode(id_type);
@@ -89,9 +88,6 @@ bool id_can_have_animdata(const ID *id)
return id_type_can_have_animdata(GS(id->name));
}
-/**
- * Get #AnimData from the given ID-block.
- */
AnimData *BKE_animdata_from_id(ID *id)
{
/* In order for this to work, we assume that the #AnimData pointer is stored
@@ -106,9 +102,6 @@ AnimData *BKE_animdata_from_id(ID *id)
return NULL;
}
-/**
- * Ensure #AnimData exists in the given ID-block (when supported).
- */
AnimData *BKE_animdata_ensure_id(ID *id)
{
/* In order for this to work, we assume that the #AnimData pointer is stored
@@ -137,16 +130,6 @@ AnimData *BKE_animdata_ensure_id(ID *id)
/* Action Setter --------------------------------------- */
-/**
- * Called when user tries to change the active action of an #AnimData block
- * (via RNA, Outliner, etc.)
- *
- * \param reports: Can be NULL.
- * \param id: The owner of the animation data
- * \param act: The Action to set, or NULL to clear.
- *
- * \return true when the action was successfully updated, false otherwise.
- */
bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
{
AnimData *adt = BKE_animdata_from_id(id);
@@ -226,7 +209,6 @@ bool BKE_animdata_action_ensure_idroot(const ID *owner, bAction *action)
/* Freeing -------------------------------------------- */
-/* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */
void BKE_animdata_free(ID *id, const bool do_id_user)
{
/* Only some ID-blocks have this info for now, so we cast the
@@ -287,18 +269,14 @@ bool BKE_animdata_id_is_animated(const struct ID *id)
!BLI_listbase_is_empty(&adt->overrides);
}
-/**
- * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
- * `IDTypeInfo` structure).
- */
void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
{
LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
- BKE_fcurve_foreach_id(fcu, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data));
}
- BKE_LIB_FOREACHID_PROCESS(data, adt->action, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, adt->tmpact, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, adt->action, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, adt->tmpact, IDWALK_CB_USER);
LISTBASE_FOREACH (NlaTrack *, nla_track, &adt->nla_tracks) {
LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) {
@@ -309,12 +287,6 @@ void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
/* Copying -------------------------------------------- */
-/**
- * Make a copy of the given AnimData - to be used when copying data-blocks.
- * \param flag: Control ID pointers management,
- * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
- * \return The copied animdata.
- */
AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
{
AnimData *dadt;
@@ -367,11 +339,6 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
return dadt;
}
-/**
- * \param flag: Control ID pointers management,
- * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
- * \return true is successfully copied.
- */
bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
{
AnimData *adt;
@@ -432,7 +399,6 @@ void BKE_animdata_duplicate_id_action(struct Main *bmain,
}
}
-/* Merge copies of the data from the src AnimData into the destination AnimData */
void BKE_animdata_merge_copy(
Main *bmain, ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
{
@@ -647,12 +613,6 @@ static void animdata_move_drivers_by_basepath(AnimData *srcAdt,
}
}
-/* Transfer the animation data from srcID to dstID where the srcID
- * animation data is based off "basepath", creating new AnimData and
- * associated data as necessary.
- *
- * basepaths is a list of AnimationBasePathChange.
- */
void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths)
{
AnimData *srcAdt = NULL, *dstAdt = NULL;
@@ -716,52 +676,6 @@ void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBa
}
}
-/**
- * Temporary wrapper for driver operators for buttons to make it easier to create
- * such drivers by rerouting all paths through the active object instead so that
- * they will get picked up by the dependency system.
- *
- * \param C: Context pointer - for getting active data
- * \param[in,out] ptr: RNA pointer for property's data-block.
- * May be modified as result of path remapping.
- * \param prop: RNA definition of property to add for
- * \return MEM_alloc'd string representing the path to the property from the given #PointerRNA
- */
-char *BKE_animdata_driver_path_hack(bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- char *base_path)
-{
- ID *id = ptr->owner_id;
- ScrArea *area = CTX_wm_area(C);
-
- /* get standard path which may be extended */
- char *basepath = base_path ? base_path : RNA_path_from_ID_to_property(ptr, prop);
- char *path = basepath; /* in case no remapping is needed */
-
- /* Remapping will only be performed in the Properties Editor, as only this
- * restricts the subspace of options to the 'active' data (a manageable state)
- */
- /* TODO: watch out for pinned context? */
- if ((area) && (area->spacetype == SPACE_PROPERTIES)) {
- Object *ob = CTX_data_active_object(C);
-
- if (ob && id) {
- /* TODO: after material textures were removed, this function serves
- * no purpose anymore, but could be used again so was not removed. */
-
- /* fix RNA pointer, as we've now changed the ID root by changing the paths */
- if (basepath != path) {
- /* rebase provided pointer so that it starts from object... */
- RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr);
- }
- }
- }
-
- /* the path should now have been corrected for use */
- return path;
-}
-
/* Path Validation -------------------------------------------- */
/* Check if a given RNA Path is valid, by tracing it from the given ID,
@@ -956,14 +870,6 @@ static bool nlastrips_path_rename_fix(ID *owner_id,
/* Rename Sub-ID Entities in RNA Paths ----------------------- */
-/* Fix up the given RNA-Path
- *
- * This is just an external wrapper for the RNA-Path fixing function,
- * with input validity checks on top of the basic method.
- *
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
char *BKE_animsys_fix_rna_path_rename(ID *owner_id,
char *old_path,
const char *prefix,
@@ -1019,14 +925,6 @@ char *BKE_animsys_fix_rna_path_rename(ID *owner_id,
return result;
}
-/* Fix all RNA_Paths in the given Action, relative to the given ID block
- *
- * This is just an external wrapper for the F-Curve fixing function,
- * with input validity checks on top of the basic method.
- *
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
void BKE_action_fix_paths_rename(ID *owner_id,
bAction *act,
const char *prefix,
@@ -1070,10 +968,6 @@ void BKE_action_fix_paths_rename(ID *owner_id,
MEM_freeN(newN);
}
-/* Fix all RNA-Paths in the AnimData block used by the given ID block
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
void BKE_animdata_fix_paths_rename(ID *owner_id,
AnimData *adt,
ID *ref_id,
@@ -1282,7 +1176,6 @@ void BKE_fcurves_id_cb(ID *id, ID_FCurve_Edit_Callback func, void *user_data)
}
}
-/* apply the given callback function on all F-Curves attached to data in main database */
void BKE_fcurves_main_cb(Main *bmain, ID_FCurve_Edit_Callback func, void *user_data)
{
/* Wrap F-Curve operation stuff to pass to the general AnimData-level func */
@@ -1294,7 +1187,6 @@ void BKE_fcurves_main_cb(Main *bmain, ID_FCurve_Edit_Callback func, void *user_d
/* Whole Database Ops -------------------------------------------- */
-/* apply the given callback function on all data in main database */
void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *user_data)
{
ID *id;
@@ -1405,10 +1297,6 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use
ANIMDATA_IDS_CB(bmain->simulations.first);
}
-/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
void BKE_animdata_fix_paths_rename_all(ID *ref_id,
const char *prefix,
const char *oldName,
@@ -1418,11 +1306,6 @@ void BKE_animdata_fix_paths_rename_all(ID *ref_id,
BKE_animdata_fix_paths_rename_all_ex(bmain, ref_id, prefix, oldName, newName, 0, 0, 1);
}
-/* Fix all RNA-Paths throughout the database
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
-/* TODO: use BKE_animdata_main_cb for looping over all data. */
void BKE_animdata_fix_paths_rename_all_ex(Main *bmain,
ID *ref_id,
const char *prefix,
@@ -1432,6 +1315,7 @@ void BKE_animdata_fix_paths_rename_all_ex(Main *bmain,
const int newSubscript,
const bool verify_paths)
{
+ /* TODO: use BKE_animdata_main_cb for looping over all data. */
ID *id;
diff --git a/source/blender/blenkernel/intern/anim_path.c b/source/blender/blenkernel/intern/anim_path.c
index de470a15041..43af55e9b6b 100644
--- a/source/blender/blenkernel/intern/anim_path.c
+++ b/source/blender/blenkernel/intern/anim_path.c
@@ -230,14 +230,6 @@ static bool binary_search_anim_path(const float *accum_len_arr,
}
}
-/**
- * Calculate the deformation implied by the curve path at a given parametric position,
- * and returns whether this operation succeeded.
- *
- * \param ctime: Time is normalized range <0-1>.
- *
- * \return success.
- */
bool BKE_where_on_path(const Object *ob,
float ctime,
float r_vec[4],
@@ -254,6 +246,10 @@ bool BKE_where_on_path(const Object *ob,
CLOG_WARN(&LOG, "No curve cache!");
return false;
}
+ if (ob->runtime.curve_cache->anim_path_accum_length == NULL) {
+ CLOG_WARN(&LOG, "No anim path!");
+ return false;
+ }
/* We only use the first curve. */
BevList *bl = ob->runtime.curve_cache->bev.first;
if (bl == NULL || !bl->nr) {
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 92b0db5b214..b5ea68aaadc 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -84,8 +84,6 @@ static CLG_LogRef LOG = {"bke.anim_sys"};
/* Finding Tools --------------------------- */
-/* Find the first path that matches the given criteria */
-/* TODO: do we want some method to perform partial matches too? */
KS_Path *BKE_keyingset_find_path(KeyingSet *ks,
ID *id,
const char group_name[],
@@ -138,8 +136,6 @@ KS_Path *BKE_keyingset_find_path(KeyingSet *ks,
/* Defining Tools --------------------------- */
-/* Used to create a new 'custom' KeyingSet for the user,
- * that will be automatically added to the stack */
KeyingSet *BKE_keyingset_add(
ListBase *list, const char idname[], const char name[], short flag, short keyingflag)
{
@@ -174,9 +170,6 @@ KeyingSet *BKE_keyingset_add(
return ks;
}
-/* Add a path to a KeyingSet. Nothing is returned for now...
- * Checks are performed to ensure that destination is appropriate for the KeyingSet in question
- */
KS_Path *BKE_keyingset_add_path(KeyingSet *ks,
ID *id,
const char group_name[],
@@ -240,7 +233,6 @@ KS_Path *BKE_keyingset_add_path(KeyingSet *ks,
return ksp;
}
-/* Free the given Keying Set path */
void BKE_keyingset_free_path(KeyingSet *ks, KS_Path *ksp)
{
/* sanity check */
@@ -257,7 +249,6 @@ void BKE_keyingset_free_path(KeyingSet *ks, KS_Path *ksp)
BLI_freelinkN(&ks->paths, ksp);
}
-/* Copy all KeyingSets in the given list */
void BKE_keyingsets_copy(ListBase *newlist, const ListBase *list)
{
KeyingSet *ksn;
@@ -276,7 +267,6 @@ void BKE_keyingsets_copy(ListBase *newlist, const ListBase *list)
/* Freeing Tools --------------------------- */
-/* Free data for KeyingSet but not set itself */
void BKE_keyingset_free(KeyingSet *ks)
{
KS_Path *ksp, *kspn;
@@ -293,7 +283,6 @@ void BKE_keyingset_free(KeyingSet *ks)
}
}
-/* Free all the KeyingSets in the given list */
void BKE_keyingsets_free(ListBase *list)
{
KeyingSet *ks, *ksn;
@@ -490,7 +479,6 @@ bool BKE_animsys_read_from_rna_path(PathResolvedRNA *anim_rna, float *r_value)
return true;
}
-/* Write the given value to a setting using RNA, and return success */
bool BKE_animsys_write_to_rna_path(PathResolvedRNA *anim_rna, const float value)
{
PropertyRNA *prop = anim_rna->prop;
@@ -831,7 +819,6 @@ static void action_idcode_patch_check(ID *id, bAction *act)
/* ----------------------------------------- */
-/* Evaluate Action Group */
void animsys_evaluate_action_group(PointerRNA *ptr,
bAction *act,
bActionGroup *agrp,
@@ -864,7 +851,6 @@ void animsys_evaluate_action_group(PointerRNA *ptr,
}
}
-/* Evaluate Action (F-Curve Bag) */
void animsys_evaluate_action(PointerRNA *ptr,
bAction *act,
const AnimationEvalContext *anim_eval_context,
@@ -881,7 +867,6 @@ void animsys_evaluate_action(PointerRNA *ptr,
animsys_evaluate_fcurves(ptr, &act->curves, anim_eval_context, flush_to_original);
}
-/* Evaluate Action and blend it into the current values of the animated properties. */
void animsys_blend_in_action(PointerRNA *ptr,
bAction *act,
const AnimationEvalContext *anim_eval_context,
@@ -960,7 +945,6 @@ static void nlastrip_evaluate_controls(NlaStrip *strip,
}
}
-/* gets the strip active at the current time for a list of strips for evaluation purposes */
NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list,
ListBase *strips,
short index,
@@ -1383,7 +1367,7 @@ static void nlaevalchan_get_default_values(NlaEvalChannel *nec, float *r_values)
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
- tmp_bool = MEM_malloc_arrayN(sizeof(*tmp_bool), length, __func__);
+ tmp_bool = MEM_malloc_arrayN(length, sizeof(*tmp_bool), __func__);
RNA_property_boolean_get_default_array(ptr, prop, tmp_bool);
for (int i = 0; i < length; i++) {
r_values[i] = (float)tmp_bool[i];
@@ -1391,7 +1375,7 @@ static void nlaevalchan_get_default_values(NlaEvalChannel *nec, float *r_values)
MEM_freeN(tmp_bool);
break;
case PROP_INT:
- tmp_int = MEM_malloc_arrayN(sizeof(*tmp_int), length, __func__);
+ tmp_int = MEM_malloc_arrayN(length, sizeof(*tmp_int), __func__);
RNA_property_int_get_default_array(ptr, prop, tmp_int);
for (int i = 0; i < length; i++) {
r_values[i] = (float)tmp_int[i];
@@ -2402,7 +2386,6 @@ static void nlastrip_evaluate_meta(PointerRNA *ptr,
nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers);
}
-/* evaluates the given evaluation strip */
void nlastrip_evaluate(PointerRNA *ptr,
NlaEvalData *channels,
ListBase *modifiers,
@@ -2447,7 +2430,6 @@ void nlastrip_evaluate(PointerRNA *ptr,
strip->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED;
}
-/* write the accumulated settings to */
void nladata_flush_channels(PointerRNA *ptr,
NlaEvalData *channels,
NlaEvalSnapshot *snapshot,
@@ -2977,14 +2959,6 @@ void nlasnapshot_ensure_channels(NlaEvalData *eval_data, NlaEvalSnapshot *snapsh
}
}
-/**
- * Blends the \a lower_snapshot with the \a upper_snapshot into \a r_blended_snapshot according
- * to the given \a upper_blendmode and \a upper_influence.
- *
- * For \a upper_snapshot, blending limited to values in the \a blend_domain.
- * For Replace blend-mode, this allows the upper snapshot to have a location XYZ channel
- * where only a subset of values are blended.
- */
void nlasnapshot_blend(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *upper_snapshot,
@@ -3012,14 +2986,6 @@ void nlasnapshot_blend(NlaEvalData *eval_data,
}
}
-/**
- * Using \a blended_snapshot and \a lower_snapshot, we can solve for the \a r_upper_snapshot.
- *
- * Only channels that exist within \a blended_snapshot are inverted.
- *
- * For \a r_upper_snapshot, disables \a NlaEvalChannelSnapshot->remap_domain for failed inversions.
- * Only values within the \a remap_domain are processed.
- */
void nlasnapshot_blend_get_inverted_upper_snapshot(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *blended_snapshot,
@@ -3050,15 +3016,6 @@ void nlasnapshot_blend_get_inverted_upper_snapshot(NlaEvalData *eval_data,
/* ---------------------- */
-/**
- * Prepare data necessary to compute correct keyframe values for NLA strips
- * with non-Replace mode or influence different from 1.
- *
- * \param cache: List used to cache contexts for reuse when keying
- * multiple channels in one operation.
- * \param ptr: RNA pointer to the Object with the animation.
- * \return Keyframing context, or NULL if not necessary.
- */
NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
struct ListBase *cache,
struct PointerRNA *ptr,
@@ -3095,18 +3052,6 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
return ctx;
}
-/**
- * Apply correction from the NLA context to the values about to be keyframed.
- *
- * \param context: Context to use (may be NULL).
- * \param prop_ptr: Property about to be keyframed.
- * \param[in,out] values: Array of property values to adjust.
- * \param count: Number of values in the array.
- * \param index: Index of the element about to be updated, or -1.
- * \param[out] r_force_all: Set to true if all channels must be inserted. May be NULL.
- * \return False if correction fails due to a division by zero,
- * or null r_force_all when all channels are required.
- */
bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
struct PointerRNA *prop_ptr,
struct PropertyRNA *prop,
@@ -3202,9 +3147,6 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
return successful_remap;
}
-/**
- * Free all cached contexts from the list.
- */
void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache)
{
LISTBASE_FOREACH (NlaKeyframingContext *, ctx, cache) {
@@ -3270,12 +3212,6 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
* However, the code for this is relatively harmless, so is left in the code for now.
*/
-/* Evaluation loop for evaluation animation data
- *
- * This assumes that the animation-data provided belongs to the ID block in question,
- * and that the flags for which parts of the anim-data settings need to be recalculated
- * have been set already by the depsgraph. Now, we use the recalc
- */
void BKE_animsys_evaluate_animdata(ID *id,
AnimData *adt,
const AnimationEvalContext *anim_eval_context,
@@ -3329,13 +3265,6 @@ void BKE_animsys_evaluate_animdata(ID *id,
animsys_evaluate_overrides(&id_ptr, adt);
}
-/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only
- *
- * This will evaluate only the animation info available in the animation data-blocks
- * encountered. In order to enforce the system by which some settings controlled by a
- * 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a
- * standard 'root') block are overridden by a larger 'user'
- */
void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, float ctime)
{
ID *id;
diff --git a/source/blender/blenkernel/intern/anim_visualization.c b/source/blender/blenkernel/intern/anim_visualization.c
index 56bd8e769bc..fdea52bcd64 100644
--- a/source/blender/blenkernel/intern/anim_visualization.c
+++ b/source/blender/blenkernel/intern/anim_visualization.c
@@ -39,7 +39,6 @@
/* ******************************************************************** */
/* Animation Visualization */
-/* Initialize the default settings for animation visualization */
void animviz_settings_init(bAnimVizSettings *avs)
{
/* sanity check */
@@ -62,7 +61,6 @@ void animviz_settings_init(bAnimVizSettings *avs)
/* ------------------- */
-/* Free the given motion path's cache */
void animviz_free_motionpath_cache(bMotionPath *mpath)
{
/* sanity check */
@@ -84,9 +82,6 @@ void animviz_free_motionpath_cache(bMotionPath *mpath)
mpath->length = 0;
}
-/* Free the given motion path instance and its data
- * NOTE: this frees the motion path given!
- */
void animviz_free_motionpath(bMotionPath *mpath)
{
/* sanity check */
@@ -103,7 +98,6 @@ void animviz_free_motionpath(bMotionPath *mpath)
/* ------------------- */
-/* Make a copy of motionpath data, so that viewing with copy on write works */
bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
{
bMotionPath *mpath_dst;
@@ -125,14 +119,6 @@ bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
/* ------------------- */
-/**
- * Setup motion paths for the given data.
- * \note Only used when explicitly calculating paths on bones which may/may not be consider already
- *
- * \param scene: Current scene (for frame ranges, etc.)
- * \param ob: Object to add paths for (must be provided)
- * \param pchan: Posechannel to add paths for (optional; if not provided, object-paths are assumed)
- */
bMotionPath *animviz_verify_motionpaths(ReportList *reports,
Scene *scene,
Object *ob,
diff --git a/source/blender/blenkernel/intern/anonymous_attribute.cc b/source/blender/blenkernel/intern/anonymous_attribute.cc
index 67611053d83..22c2f83e8be 100644
--- a/source/blender/blenkernel/intern/anonymous_attribute.cc
+++ b/source/blender/blenkernel/intern/anonymous_attribute.cc
@@ -97,6 +97,7 @@ void BKE_anonymous_attribute_id_decrement_weak(const AnonymousAttributeID *anony
{
const int new_refcount = anonymous_id->refcount_tot.fetch_sub(1) - 1;
if (new_refcount == 0) {
+ BLI_assert(anonymous_id->refcount_strong == 0);
delete anonymous_id;
}
}
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index eae331fc7d1..9dd4c7e503a 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -99,15 +99,6 @@ static bool is_appdir_init = false;
# define ASSERT_IS_INIT() ((void)0)
#endif
-/**
- * Sanity check to ensure correct API use in debug mode.
- *
- * Run this once the first level of arguments has been passed so we can be sure
- * `--env-system-datafiles`, and other `--env-*` arguments has been passed.
- *
- * Without this any callers to this module that run early on,
- * will miss out on changes from parsing arguments.
- */
void BKE_appdir_init(void)
{
#ifndef NDEBUG
@@ -147,13 +138,6 @@ static char *blender_version_decimal(const int version)
/** \name Default Directories
* \{ */
-/**
- * Get the folder that's the "natural" starting point for browsing files on an OS. On Unix that is
- * $HOME, on Windows it is %userprofile%/Documents.
- *
- * \note On Windows `Users/{MyUserName}/Documents` is used as it's the default location to save
- * documents.
- */
const char *BKE_appdir_folder_default(void)
{
#ifndef WIN32
@@ -169,24 +153,37 @@ const char *BKE_appdir_folder_default(void)
#endif /* WIN32 */
}
-/**
- * Get the user's home directory, i.e. $HOME on UNIX, %userprofile% on Windows.
- */
-const char *BKE_appdir_folder_home(void)
+const char *BKE_appdir_folder_root(void)
{
#ifndef WIN32
- return BLI_getenv("HOME");
-#else /* Windows */
+ return "/";
+#else
+ static char root[4];
+ BLI_windows_get_default_root_dir(root);
+ return root;
+#endif
+}
+
+const char *BKE_appdir_folder_default_or_root(void)
+{
+ const char *path = BKE_appdir_folder_default();
+ if (path == NULL) {
+ path = BKE_appdir_folder_root();
+ }
+ return path;
+}
+
+const char *BKE_appdir_folder_home(void)
+{
+#ifdef WIN32
return BLI_getenv("userprofile");
+#elif defined(__APPLE__)
+ return BLI_expand_tilde("~/");
+#else
+ return BLI_getenv("HOME");
#endif
}
-/**
- * Get the user's document directory, i.e. $HOME/Documents on Linux, %userprofile%/Documents on
- * Windows. If this can't be found using OS queries (via Ghost), try manually finding it.
- *
- * \returns True if the path is valid and points to an existing directory.
- */
bool BKE_appdir_folder_documents(char *dir)
{
dir[0] = '\0';
@@ -217,26 +214,53 @@ bool BKE_appdir_folder_documents(char *dir)
return true;
}
-/**
- * Gets a good default directory for fonts.
- */
-bool BKE_appdir_font_folder_default(
- /* This parameter can only be `const` on non-windows platforms.
- * NOLINTNEXTLINE: readability-non-const-parameter. */
- char *dir)
+bool BKE_appdir_folder_caches(char *r_path, const size_t path_len)
{
- bool success = false;
+ r_path[0] = '\0';
+
+ const char *caches_root_path = GHOST_getUserSpecialDir(GHOST_kUserSpecialDirCaches);
+ if (caches_root_path == NULL || !BLI_is_dir(caches_root_path)) {
+ caches_root_path = BKE_tempdir_base();
+ }
+ if (caches_root_path == NULL || !BLI_is_dir(caches_root_path)) {
+ return false;
+ }
+
+#ifdef WIN32
+ BLI_path_join(
+ r_path, path_len, caches_root_path, "Blender Foundation", "Blender", "Cache", SEP_STR, NULL);
+#elif defined(__APPLE__)
+ BLI_path_join(r_path, path_len, caches_root_path, "Blender", SEP_STR, NULL);
+#else /* __linux__ */
+ BLI_path_join(r_path, path_len, caches_root_path, "blender", SEP_STR, NULL);
+#endif
+
+ return true;
+}
+
+bool BKE_appdir_font_folder_default(char *dir)
+{
+ char test_dir[FILE_MAXDIR];
+ test_dir[0] = '\0';
+
#ifdef WIN32
wchar_t wpath[FILE_MAXDIR];
- success = SHGetSpecialFolderPathW(0, wpath, CSIDL_FONTS, 0);
- if (success) {
+ if (SHGetSpecialFolderPathW(0, wpath, CSIDL_FONTS, 0)) {
wcscat(wpath, L"\\");
- BLI_strncpy_wchar_as_utf8(dir, wpath, FILE_MAXDIR);
+ BLI_strncpy_wchar_as_utf8(test_dir, wpath, sizeof(test_dir));
}
+#elif defined(__APPLE__)
+ STRNCPY(test_dir, BLI_expand_tilde("~/Library/Fonts/"));
+ BLI_path_slash_ensure(test_dir);
+#else
+ STRNCPY(test_dir, "/usr/share/fonts");
#endif
- /* TODO: Values for other platforms. */
- UNUSED_VARS(dir);
- return success;
+
+ if (test_dir[0] && BLI_exists(test_dir)) {
+ BLI_strncpy(dir, test_dir, FILE_MAXDIR);
+ return true;
+ }
+ return false;
}
/** \} */
@@ -391,10 +415,6 @@ static bool get_path_local(char *targetpath,
targetpath, targetpath_len, folder_name, subfolder_name, version, check_is_dir);
}
-/**
- * Check if this is an install with user files kept together
- * with the Blender executable and its installation files.
- */
bool BKE_appdir_app_is_portable_install(void)
{
/* Detect portable install by the existence of `config` folder. */
@@ -559,13 +579,6 @@ static bool get_path_system(char *targetpath,
/** \name Path Presets API
* \{ */
-/**
- * Get a folder out of the \a folder_id presets for paths.
- *
- * \param subfolder: The name of a directory to check for,
- * this may contain path separators but must resolve to a directory, checked with #BLI_is_dir.
- * \return The path if found, NULL string if not.
- */
bool BKE_appdir_folder_id_ex(const int folder_id,
const char *subfolder,
char *path,
@@ -679,9 +692,6 @@ const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder)
return NULL;
}
-/**
- * Returns the path to a folder in the user area without checking that it actually exists first.
- */
const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder)
{
const int version = BLENDER_VERSION;
@@ -728,9 +738,6 @@ const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *su
return path;
}
-/**
- * Returns the path to a folder in the user area, creating it if it doesn't exist.
- */
const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder)
{
const char *path;
@@ -756,10 +763,6 @@ const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfold
return path;
}
-/**
- * Returns the path of the top-level version-specific local, user or system directory.
- * If check_is_dir, then the result will be NULL if the directory doesn't exist.
- */
const char *BKE_appdir_folder_id_version(const int folder_id,
const int version,
const bool check_is_dir)
@@ -875,18 +878,12 @@ void BKE_appdir_program_path_init(const char *argv0)
BLI_split_dir_part(g_app.program_filename, g_app.program_dirname, sizeof(g_app.program_dirname));
}
-/**
- * Path to executable
- */
const char *BKE_appdir_program_path(void)
{
BLI_assert(g_app.program_filename[0]);
return g_app.program_filename;
}
-/**
- * Path to directory of executable
- */
const char *BKE_appdir_program_dir(void)
{
BLI_assert(g_app.program_dirname[0]);
@@ -980,9 +977,6 @@ static const int app_template_directory_id[2] = {
BLENDER_SYSTEM_SCRIPTS,
};
-/**
- * Return true if templates exist
- */
bool BKE_appdir_app_template_any(void)
{
char temp_dir[FILE_MAX];
@@ -1150,14 +1144,13 @@ static void tempdir_session_create(char *tempdir_session,
BLI_strncpy(tempdir_session, tempdir, tempdir_session_len);
}
-/**
- * Sets #g_app.temp_dirname_base to \a userdir if specified and is a valid directory,
- * otherwise chooses a suitable OS-specific temporary directory.
- * Sets #g_app.temp_dirname_session to a #mkdtemp
- * generated sub-dir of #g_app.temp_dirname_base.
- */
void BKE_tempdir_init(const char *userdir)
{
+ /* Sets #g_app.temp_dirname_base to \a userdir if specified and is a valid directory,
+ * otherwise chooses a suitable OS-specific temporary directory.
+ * Sets #g_app.temp_dirname_session to a #mkdtemp
+ * generated sub-dir of #g_app.temp_dirname_base. */
+
where_is_temp(g_app.temp_dirname_base, sizeof(g_app.temp_dirname_base), userdir);
/* Clear existing temp dir, if needed. */
@@ -1167,25 +1160,16 @@ void BKE_tempdir_init(const char *userdir)
g_app.temp_dirname_session, sizeof(g_app.temp_dirname_session), g_app.temp_dirname_base);
}
-/**
- * Path to temporary directory (with trailing slash)
- */
const char *BKE_tempdir_session(void)
{
return g_app.temp_dirname_session[0] ? g_app.temp_dirname_session : BKE_tempdir_base();
}
-/**
- * Path to persistent temporary directory (with trailing slash)
- */
const char *BKE_tempdir_base(void)
{
return g_app.temp_dirname_base;
}
-/**
- * Delete content of this instance's temp dir.
- */
void BKE_tempdir_session_purge(void)
{
if (g_app.temp_dirname_session[0] && BLI_is_dir(g_app.temp_dirname_session)) {
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index a86f436185e..5704ef6e42f 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -161,30 +161,36 @@ static void armature_free_data(struct ID *id)
static void armature_foreach_id_bone(Bone *bone, LibraryForeachIDData *data)
{
- IDP_foreach_property(
- bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ IDP_foreach_property(
+ bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data));
LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) {
- armature_foreach_id_bone(curbone, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_bone(curbone, data));
}
}
static void armature_foreach_id_editbone(EditBone *edit_bone, LibraryForeachIDData *data)
{
- IDP_foreach_property(
- edit_bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ IDP_foreach_property(edit_bone->prop,
+ IDP_TYPE_FILTER_ID,
+ BKE_lib_query_idpropertiesForeachIDLink_callback,
+ data));
}
static void armature_foreach_id(ID *id, LibraryForeachIDData *data)
{
bArmature *arm = (bArmature *)id;
LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
- armature_foreach_id_bone(bone, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_bone(bone, data));
}
if (arm->edbo != NULL) {
LISTBASE_FOREACH (EditBone *, edit_bone, arm->edbo) {
- armature_foreach_id_editbone(edit_bone, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_editbone(edit_bone, data));
}
}
}
@@ -316,6 +322,7 @@ IDTypeInfo IDType_ID_AR = {
.name_plural = "armatures",
.translation_context = BLT_I18NCONTEXT_ID_ARMATURE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = armature_init_data,
.copy_data = armature_copy_data,
@@ -323,6 +330,7 @@ IDTypeInfo IDType_ID_AR = {
.make_local = NULL,
.foreach_id = armature_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = armature_blend_write,
@@ -601,10 +609,6 @@ static Bone *get_named_bone_bonechildren(ListBase *lb, const char *name)
return NULL;
}
-/**
- * Walk the list until the bone is found (slow!),
- * use #BKE_armature_bone_from_name_map for multiple lookups.
- */
Bone *BKE_armature_find_bone_name(bArmature *arm, const char *name)
{
if (!arm) {
@@ -709,10 +713,6 @@ void BKE_armature_refresh_layer_used(struct Depsgraph *depsgraph, struct bArmatu
/** \name Armature Layer Refresh Used
* \{ */
-/* Finds the best possible extension to the name on a particular axis. (For renaming, check for
- * unique names afterwards) strip_number: removes number extensions (TODO: not used)
- * axis: the axis to name on
- * head/tail: the head/tail co-ordinate of the bone on the specified axis */
bool bone_autoside_name(
char name[MAXBONENAME], int UNUSED(strip_number), short axis, float head, float tail)
{
@@ -924,7 +924,6 @@ static void evaluate_cubic_bezier(const float control[4][3],
madd_v3_v3v3fl(r_pos, layer2[0], r_tangent, t);
}
-/* Get "next" and "prev" bones - these are used for handle calculations. */
void BKE_pchan_bbone_handles_get(bPoseChannel *pchan, bPoseChannel **r_prev, bPoseChannel **r_next)
{
if (pchan->bone->bbone_prev_type == BBONE_HANDLE_AUTO) {
@@ -951,7 +950,6 @@ void BKE_pchan_bbone_handles_get(bPoseChannel *pchan, bPoseChannel **r_prev, bPo
}
}
-/* Compute B-Bone spline parameters for the given channel. */
void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
const bool rest,
struct BBoneSplineParameters *param)
@@ -1197,8 +1195,6 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
}
}
-/* Fills the array with the desired amount of bone->segments elements.
- * This calculation is done within unit bone space. */
void BKE_pchan_bbone_spline_setup(bPoseChannel *pchan,
const bool rest,
const bool for_deform,
@@ -1211,7 +1207,6 @@ void BKE_pchan_bbone_spline_setup(bPoseChannel *pchan,
pchan->bone->segments = BKE_pchan_bbone_spline_compute(&param, for_deform, result_array);
}
-/* Computes the bezier handle vectors and rolls coming from custom handles. */
void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
float h1[3],
float *r_roll1,
@@ -1361,16 +1356,17 @@ static void ease_handle_axis(const float deriv1[3], const float deriv2[3], float
copy_v3_v3(r_axis, deriv1);
- float len1 = len_squared_v3(deriv1), len2 = len_squared_v3(deriv2);
- float ratio = len1 / len2;
-
+ const float len2 = len_squared_v3(deriv2);
+ if (UNLIKELY(len2 == 0.0f)) {
+ return;
+ }
+ const float len1 = len_squared_v3(deriv1);
+ const float ratio = len1 / len2;
if (ratio < gap * gap) {
madd_v3_v3fl(r_axis, deriv2, gap - sqrtf(ratio));
}
}
-/* Fills the array with the desired amount of bone->segments elements.
- * This calculation is done within unit bone space. */
int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param,
const bool for_deform,
Mat4 *result_array)
@@ -1495,17 +1491,16 @@ static void allocate_bbone_cache(bPoseChannel *pchan, int segments)
runtime->bbone_segments = segments;
runtime->bbone_rest_mats = MEM_malloc_arrayN(
- sizeof(Mat4), 1 + (uint)segments, "bPoseChannel_Runtime::bbone_rest_mats");
+ 1 + (uint)segments, sizeof(Mat4), "bPoseChannel_Runtime::bbone_rest_mats");
runtime->bbone_pose_mats = MEM_malloc_arrayN(
- sizeof(Mat4), 1 + (uint)segments, "bPoseChannel_Runtime::bbone_pose_mats");
+ 1 + (uint)segments, sizeof(Mat4), "bPoseChannel_Runtime::bbone_pose_mats");
runtime->bbone_deform_mats = MEM_malloc_arrayN(
- sizeof(Mat4), 2 + (uint)segments, "bPoseChannel_Runtime::bbone_deform_mats");
+ 2 + (uint)segments, sizeof(Mat4), "bPoseChannel_Runtime::bbone_deform_mats");
runtime->bbone_dual_quats = MEM_malloc_arrayN(
- sizeof(DualQuat), 1 + (uint)segments, "bPoseChannel_Runtime::bbone_dual_quats");
+ 1 + (uint)segments, sizeof(DualQuat), "bPoseChannel_Runtime::bbone_dual_quats");
}
}
-/** Compute and cache the B-Bone shape in the channel runtime struct. */
void BKE_pchan_bbone_segments_cache_compute(bPoseChannel *pchan)
{
bPoseChannel_Runtime *runtime = &pchan->runtime;
@@ -1557,7 +1552,6 @@ void BKE_pchan_bbone_segments_cache_compute(bPoseChannel *pchan)
}
}
-/** Copy cached B-Bone segments from one channel to another */
void BKE_pchan_bbone_segments_cache_copy(bPoseChannel *pchan, bPoseChannel *pchan_from)
{
bPoseChannel_Runtime *runtime = &pchan->runtime;
@@ -1581,10 +1575,6 @@ void BKE_pchan_bbone_segments_cache_copy(bPoseChannel *pchan, bPoseChannel *pcha
}
}
-/**
- * Calculate index and blend factor for the two B-Bone segment nodes
- * affecting the point at 0 <= pos <= 1.
- */
void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan,
float pos,
int *r_index,
@@ -1616,7 +1606,6 @@ void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan,
/** \name Bone Space to Space Conversion API
* \{ */
-/* Convert World-Space Matrix to Pose-Space Matrix */
void BKE_armature_mat_world_to_pose(Object *ob, const float inmat[4][4], float outmat[4][4])
{
float obmat[4][4];
@@ -1633,9 +1622,6 @@ void BKE_armature_mat_world_to_pose(Object *ob, const float inmat[4][4], float o
mul_m4_m4m4(outmat, inmat, obmat);
}
-/* Convert World-Space Location to Pose-Space Location
- * NOTE: this cannot be used to convert to pose-space location of the supplied
- * pose-channel into its local space (i.e. 'visual'-keyframing) */
void BKE_armature_loc_world_to_pose(Object *ob, const float inloc[3], float outloc[3])
{
float xLocMat[4][4];
@@ -1656,8 +1642,6 @@ void BKE_armature_loc_world_to_pose(Object *ob, const float inloc[3], float outl
/** \name Bone Matrix Calculation API
* \{ */
-/* Simple helper, computes the offset bone matrix.
- * offs_bone = yoffs(b-1) + root(b) + bonemat(b). */
void BKE_bone_offset_matrix_get(const Bone *bone, float offs_bone[4][4])
{
BLI_assert(bone->parent != NULL);
@@ -1672,24 +1656,6 @@ void BKE_bone_offset_matrix_get(const Bone *bone, float offs_bone[4][4])
offs_bone[3][1] += bone->parent->length;
}
-/* Construct the matrices (rot/scale and loc)
- * to apply the PoseChannels into the armature (object) space.
- * I.e. (roughly) the "pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b)" in the
- * pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b)
- * ...function.
- *
- * This allows to get the transformations of a bone in its object space,
- * *before* constraints (and IK) get applied (used by pose evaluation code).
- * And reverse: to find pchan transformations needed to place a bone at a given loc/rot/scale
- * in object space (used by interactive transform, and snapping code).
- *
- * Note that, with the HINGE/NO_SCALE/NO_LOCAL_LOCATION options, the location matrix
- * will differ from the rotation/scale matrix...
- *
- * NOTE: This cannot be used to convert to pose-space transforms of the supplied
- * pose-channel into its local space (i.e. 'visual'-keyframing).
- * (note: I don't understand that, so I keep it :p --mont29).
- */
void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan,
BoneParentTransform *r_bpt)
{
@@ -1719,12 +1685,6 @@ void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan,
}
}
-/* Compute the parent transform using data decoupled from specific data structures.
- *
- * bone_flag: Bone->flag containing settings
- * offs_bone: delta from parent to current arm_mat (or just arm_mat if no parent)
- * parent_arm_mat, parent_pose_mat: arm_mat and pose_mat of parent, or NULL
- * r_bpt: OUTPUT parent transform */
void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
int inherit_scale_mode,
const float offs_bone[4][4],
@@ -1906,9 +1866,6 @@ void BKE_bone_parent_transform_apply(const struct BoneParentTransform *bpt,
rescale_m4(outmat, bpt->post_scale);
}
-/* Convert Pose-Space Matrix to Bone-Space Matrix.
- * NOTE: this cannot be used to convert to pose-space transforms of the supplied
- * pose-channel into its local space (i.e. 'visual'-keyframing) */
void BKE_armature_mat_pose_to_bone(bPoseChannel *pchan,
const float inmat[4][4],
float outmat[4][4])
@@ -1920,7 +1877,6 @@ void BKE_armature_mat_pose_to_bone(bPoseChannel *pchan,
BKE_bone_parent_transform_apply(&bpt, inmat, outmat);
}
-/* Convert Bone-Space Matrix to Pose-Space Matrix. */
void BKE_armature_mat_bone_to_pose(bPoseChannel *pchan,
const float inmat[4][4],
float outmat[4][4])
@@ -1931,9 +1887,6 @@ void BKE_armature_mat_bone_to_pose(bPoseChannel *pchan,
BKE_bone_parent_transform_apply(&bpt, inmat, outmat);
}
-/* Convert Pose-Space Location to Bone-Space Location
- * NOTE: this cannot be used to convert to pose-space location of the supplied
- * pose-channel into its local space (i.e. 'visual'-keyframing) */
void BKE_armature_loc_pose_to_bone(bPoseChannel *pchan, const float inloc[3], float outloc[3])
{
float xLocMat[4][4];
@@ -1976,9 +1929,6 @@ void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph,
BKE_armature_mat_pose_to_bone(&work_pchan, inmat, outmat);
}
-/**
- * Same as #BKE_object_mat3_to_rot().
- */
void BKE_pchan_mat3_to_rot(bPoseChannel *pchan, const float mat[3][3], bool use_compat)
{
BLI_ASSERT_UNIT_M3(mat);
@@ -2001,9 +1951,6 @@ void BKE_pchan_mat3_to_rot(bPoseChannel *pchan, const float mat[3][3], bool use_
}
}
-/**
- * Same as #BKE_object_rot_to_mat3().
- */
void BKE_pchan_rot_to_mat3(const bPoseChannel *pchan, float r_mat[3][3])
{
/* rotations may either be quats, eulers (with various rotation orders), or axis-angle */
@@ -2028,10 +1975,6 @@ void BKE_pchan_rot_to_mat3(const bPoseChannel *pchan, float r_mat[3][3])
}
}
-/**
- * Apply a 4x4 matrix to the pose bone,
- * similar to #BKE_object_apply_mat4().
- */
void BKE_pchan_apply_mat4(bPoseChannel *pchan, const float mat[4][4], bool use_compat)
{
float rot[3][3];
@@ -2039,11 +1982,6 @@ void BKE_pchan_apply_mat4(bPoseChannel *pchan, const float mat[4][4], bool use_c
BKE_pchan_mat3_to_rot(pchan, rot, use_compat);
}
-/**
- * Remove rest-position effects from pose-transform for obtaining
- * 'visual' transformation of pose-channel.
- * (used by the Visual-Keyframing stuff).
- */
void BKE_armature_mat_pose_to_delta(float delta_mat[4][4],
float pose_mat[4][4],
float arm_mat[4][4])
@@ -2062,11 +2000,6 @@ void BKE_armature_mat_pose_to_delta(float delta_mat[4][4],
* Used for Objects and Pose Channels, since both can have multiple rotation representations.
* \{ */
-/**
- * Called from RNA when rotation mode changes
- * - the result should be that the rotations given in the provided pointers have had conversions
- * applied (as appropriate), such that the rotation of the element hasn't 'visually' changed.
- */
void BKE_rotMode_change_values(
float quat[4], float eul[3], float axis[3], float *angle, short oldMode, short newMode)
{
@@ -2140,8 +2073,6 @@ void BKE_rotMode_change_values(
*
* \{ */
-/* Computes vector and roll based on a rotation.
- * "mat" must contain only a rotation, and no scaling. */
void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll)
{
if (r_vec) {
@@ -2153,8 +2084,6 @@ void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll)
}
}
-/* Computes roll around the vector that best approximates the matrix.
- * If vec is the Y vector from purely rotational mat, result should be exact. */
void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll)
{
float vecmat[3][3], vecmatinv[3][3], rollmat[3][3], q[4];
@@ -2170,98 +2099,105 @@ void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll)
*r_roll = quat_split_swing_and_twist(q, 1, NULL, NULL);
}
-/* Calculates the rest matrix of a bone based on its vector and a roll around that vector. */
-/**
- * Given `v = (v.x, v.y, v.z)` our (normalized) bone vector, we want the rotation matrix M
- * from the Y axis (so that `M * (0, 1, 0) = v`).
- * - The rotation axis a lays on XZ plane, and it is orthonormal to v,
- * hence to the projection of v onto XZ plane.
- * - `a = (v.z, 0, -v.x)`
- *
- * We know a is eigenvector of M (so M * a = a).
- * Finally, we have w, such that M * w = (0, 1, 0)
- * (i.e. the vector that will be aligned with Y axis once transformed).
- * We know w is symmetric to v by the Y axis.
- * - `w = (-v.x, v.y, -v.z)`
- *
- * Solving this, we get (x, y and z being the components of v):
- * <pre>
- * ┌ (x^2 * y + z^2) / (x^2 + z^2), x, x * z * (y - 1) / (x^2 + z^2) ┐
- * M = │ x * (y^2 - 1) / (x^2 + z^2), y, z * (y^2 - 1) / (x^2 + z^2) │
- * └ x * z * (y - 1) / (x^2 + z^2), z, (x^2 + z^2 * y) / (x^2 + z^2) ┘
- * </pre>
- *
- * This is stable as long as v (the bone) is not too much aligned with +/-Y
- * (i.e. x and z components are not too close to 0).
- *
- * Since v is normalized, we have `x^2 + y^2 + z^2 = 1`,
- * hence `x^2 + z^2 = 1 - y^2 = (1 - y)(1 + y)`.
- *
- * This allows to simplifies M like this:
- * <pre>
- * ┌ 1 - x^2 / (1 + y), x, -x * z / (1 + y) ┐
- * M = │ -x, y, -z │
- * └ -x * z / (1 + y), z, 1 - z^2 / (1 + y) ┘
- * </pre>
- *
- * Written this way, we see the case v = +Y is no more a singularity.
- * The only one
- * remaining is the bone being aligned with -Y.
- *
- * Let's handle
- * the asymptotic behavior when bone vector is reaching the limit of y = -1.
- * Each of the four corner elements can vary from -1 to 1,
- * depending on the axis a chosen for doing the rotation.
- * And the "rotation" here is in fact established by mirroring XZ plane by that given axis,
- * then inversing the Y-axis.
- * For sufficiently small x and z, and with y approaching -1,
- * all elements but the four corner ones of M will degenerate.
- * So let's now focus on these corner elements.
- *
- * We rewrite M so that it only contains its four corner elements,
- * and combine the `1 / (1 + y)` factor:
- * <pre>
- * ┌ 1 + y - x^2, -x * z ┐
- * M* = 1 / (1 + y) * │ │
- * └ -x * z, 1 + y - z^2 ┘
- * </pre>
- *
- * When y is close to -1, computing 1 / (1 + y) will cause severe numerical instability,
- * so we ignore it and normalize M instead.
- * We know `y^2 = 1 - (x^2 + z^2)`, and `y < 0`, hence `y = -sqrt(1 - (x^2 + z^2))`.
- *
- * Since x and z are both close to 0, we apply the binomial expansion to the first order:
- * `y = -sqrt(1 - (x^2 + z^2)) = -1 + (x^2 + z^2) / 2`. Which gives:
- * <pre>
- * ┌ z^2 - x^2, -2 * x * z ┐
- * M* = 1 / (x^2 + z^2) * │ │
- * └ -2 * x * z, x^2 - z^2 ┘
- * </pre>
- */
void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_mat[3][3])
{
- const float THETA_SAFE = 1.0e-5f; /* theta above this value are always safe to use. */
- const float THETA_CRITICAL = 1.0e-9f; /* above this is safe under certain conditions. */
+ /**
+ * Given `v = (v.x, v.y, v.z)` our (normalized) bone vector, we want the rotation matrix M
+ * from the Y axis (so that `M * (0, 1, 0) = v`).
+ * - The rotation axis a lays on XZ plane, and it is orthonormal to v,
+ * hence to the projection of v onto XZ plane.
+ * - `a = (v.z, 0, -v.x)`
+ *
+ * We know a is eigenvector of M (so M * a = a).
+ * Finally, we have w, such that M * w = (0, 1, 0)
+ * (i.e. the vector that will be aligned with Y axis once transformed).
+ * We know w is symmetric to v by the Y axis.
+ * - `w = (-v.x, v.y, -v.z)`
+ *
+ * Solving this, we get (x, y and z being the components of v):
+ * <pre>
+ * ┌ (x^2 * y + z^2) / (x^2 + z^2), x, x * z * (y - 1) / (x^2 + z^2) ┐
+ * M = │ x * (y^2 - 1) / (x^2 + z^2), y, z * (y^2 - 1) / (x^2 + z^2) │
+ * └ x * z * (y - 1) / (x^2 + z^2), z, (x^2 + z^2 * y) / (x^2 + z^2) ┘
+ * </pre>
+ *
+ * This is stable as long as v (the bone) is not too much aligned with +/-Y
+ * (i.e. x and z components are not too close to 0).
+ *
+ * Since v is normalized, we have `x^2 + y^2 + z^2 = 1`,
+ * hence `x^2 + z^2 = 1 - y^2 = (1 - y)(1 + y)`.
+ *
+ * This allows to simplifies M like this:
+ * <pre>
+ * ┌ 1 - x^2 / (1 + y), x, -x * z / (1 + y) ┐
+ * M = │ -x, y, -z │
+ * └ -x * z / (1 + y), z, 1 - z^2 / (1 + y) ┘
+ * </pre>
+ *
+ * Written this way, we see the case v = +Y is no more a singularity.
+ * The only one
+ * remaining is the bone being aligned with -Y.
+ *
+ * Let's handle
+ * the asymptotic behavior when bone vector is reaching the limit of y = -1.
+ * Each of the four corner elements can vary from -1 to 1,
+ * depending on the axis a chosen for doing the rotation.
+ * And the "rotation" here is in fact established by mirroring XZ plane by that given axis,
+ * then inversing the Y-axis.
+ * For sufficiently small x and z, and with y approaching -1,
+ * all elements but the four corner ones of M will degenerate.
+ * So let's now focus on these corner elements.
+ *
+ * We rewrite M so that it only contains its four corner elements,
+ * and combine the `1 / (1 + y)` factor:
+ * <pre>
+ * ┌ 1 + y - x^2, -x * z ┐
+ * M* = 1 / (1 + y) * │ │
+ * └ -x * z, 1 + y - z^2 ┘
+ * </pre>
+ *
+ * When y is close to -1, computing 1 / (1 + y) will cause severe numerical instability,
+ * so we use a different approach based on x and z as inputs.
+ * We know `y^2 = 1 - (x^2 + z^2)`, and `y < 0`, hence `y = -sqrt(1 - (x^2 + z^2))`.
+ *
+ * Since x and z are both close to 0, we apply the binomial expansion to the second order:
+ * `y = -sqrt(1 - (x^2 + z^2)) = -1 + (x^2 + z^2) / 2 + (x^2 + z^2)^2 / 8`, which allows
+ * eliminating the problematic `1` constant.
+ *
+ * A first order expansion allows simplifying to this, but second order is more precise:
+ * <pre>
+ * ┌ z^2 - x^2, -2 * x * z ┐
+ * M* = 1 / (x^2 + z^2) * │ │
+ * └ -2 * x * z, x^2 - z^2 ┘
+ * </pre>
+ *
+ * P.S. In the end, this basically is a heavily optimized version of Damped Track +Y.
+ */
+
+ const float SAFE_THRESHOLD = 6.1e-3f; /* Theta above this value has good enough precision. */
+ const float CRITICAL_THRESHOLD = 2.5e-4f; /* True singularity if XZ distance is below this. */
+ const float THRESHOLD_SQUARED = CRITICAL_THRESHOLD * CRITICAL_THRESHOLD;
const float x = nor[0];
const float y = nor[1];
const float z = nor[2];
- const float theta = 1.0f + y;
- const float theta_alt = x * x + z * z;
+ float theta = 1.0f + y; /* remapping Y from [-1,+1] to [0,2]. */
+ const float theta_alt = x * x + z * z; /* squared distance from origin in x,z plane. */
float rMatrix[3][3], bMatrix[3][3];
BLI_ASSERT_UNIT_V3(nor);
- /* When theta is close to zero (nor is aligned close to negative Y Axis),
+ /* Determine if the input is far enough from the true singularity of this type of
+ * transformation at (0,-1,0), where roll becomes 0/0 undefined without a limit.
+ *
+ * When theta is close to zero (nor is aligned close to negative Y Axis),
* we have to check we do have non-null X/Z components as well.
* Also, due to float precision errors, nor can be (0.0, -0.99999994, 0.0) which results
* in theta being close to zero. This will cause problems when theta is used as divisor.
*/
- if (theta > THETA_SAFE || ((x || z) && theta > THETA_CRITICAL)) {
- /* nor is *not* aligned to negative Y-axis (0,-1,0).
- * We got these values for free... so be happy with it... ;)
- */
+ if (theta > SAFE_THRESHOLD || theta_alt > THRESHOLD_SQUARED) {
+ /* nor is *not* aligned to negative Y-axis (0,-1,0). */
bMatrix[0][1] = -x;
bMatrix[1][0] = x;
@@ -2269,18 +2205,15 @@ void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_m
bMatrix[1][2] = z;
bMatrix[2][1] = -z;
- if (theta > THETA_SAFE) {
- /* nor differs significantly from negative Y axis (0,-1,0): apply the general case. */
- bMatrix[0][0] = 1 - x * x / theta;
- bMatrix[2][2] = 1 - z * z / theta;
- bMatrix[2][0] = bMatrix[0][2] = -x * z / theta;
- }
- else {
- /* nor is close to negative Y axis (0,-1,0): apply the special case. */
- bMatrix[0][0] = (x + z) * (x - z) / -theta_alt;
- bMatrix[2][2] = -bMatrix[0][0];
- bMatrix[2][0] = bMatrix[0][2] = 2.0f * x * z / theta_alt;
+ if (theta <= SAFE_THRESHOLD) {
+ /* When nor is close to negative Y axis (0,-1,0) the theta precision is very bad,
+ * so recompute it from x and z instead, using the series expansion for sqrt. */
+ theta = theta_alt * 0.5f + theta_alt * theta_alt * 0.125f;
}
+
+ bMatrix[0][0] = 1 - x * x / theta;
+ bMatrix[2][2] = 1 - z * z / theta;
+ bMatrix[2][0] = bMatrix[0][2] = -x * z / theta;
}
else {
/* nor is very close to negative Y axis (0,-1,0): use simple symmetry by Z axis. */
@@ -2309,10 +2242,6 @@ void vec_roll_to_mat3(const float vec[3], const float roll, float r_mat[3][3])
/** \name Armature Bone Matrix Calculation (Recursive)
* \{ */
-/**
- * Recursive part, calculates rest-position of entire tree of children.
- * \note Used when exiting edit-mode too.
- */
void BKE_armature_where_is_bone(Bone *bone, const Bone *bone_parent, const bool use_recursion)
{
float vec[3];
@@ -2351,8 +2280,6 @@ void BKE_armature_where_is_bone(Bone *bone, const Bone *bone_parent, const bool
}
}
-/* updates vectors and matrices on rest-position level, only needed
- * after editing armature itself, now only on reading file */
void BKE_armature_where_is(bArmature *arm)
{
Bone *bone;
@@ -2569,10 +2496,6 @@ static int rebuild_pose_bone(
return counter;
}
-/**
- * Clear pointers of object's pose
- * (needed in remap case, since we cannot always wait for a complete pose rebuild).
- */
void BKE_pose_clear_pointers(bPose *pose)
{
LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
@@ -2594,7 +2517,6 @@ static bPoseChannel *pose_channel_find_bone(bPose *pose, Bone *bone)
return (bone != NULL) ? BKE_pose_channel_find_name(pose, bone->name) : NULL;
}
-/** Update the links for the B-Bone handles from Bone data. */
void BKE_pchan_rebuild_bbone_handles(bPose *pose, bPoseChannel *pchan)
{
pchan->bbone_prev = pose_channel_find_bone(pose, pchan->bone->bbone_prev);
@@ -2612,13 +2534,6 @@ void BKE_pose_channels_clear_with_null_bone(bPose *pose, const bool do_id_user)
}
}
-/**
- * Only after leave editmode, duplicating, validating older files, library syncing.
- *
- * \note pose->flag is set for it.
- *
- * \param bmain: May be NULL, only used to tag depsgraph as being dirty...
- */
void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_user)
{
Bone *bone;
@@ -2686,11 +2601,6 @@ void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_
}
}
-/**
- * Ensures object's pose is rebuilt if needed.
- *
- * \param bmain: May be NULL, only used to tag depsgraph as being dirty...
- */
void BKE_pose_ensure(Main *bmain, Object *ob, bArmature *arm, const bool do_id_user)
{
BLI_assert(!ELEM(NULL, arm, ob));
@@ -2706,9 +2616,6 @@ void BKE_pose_ensure(Main *bmain, Object *ob, bArmature *arm, const bool do_id_u
/** \name Pose Solver
* \{ */
-/**
- * Convert the loc/rot/size to \a r_chanmat (typically #bPoseChannel.chan_mat).
- */
void BKE_pchan_to_mat4(const bPoseChannel *pchan, float r_chanmat[4][4])
{
float smat[3][3];
@@ -2732,8 +2639,6 @@ void BKE_pchan_to_mat4(const bPoseChannel *pchan, float r_chanmat[4][4])
}
}
-/* loc/rot/size to mat4 */
-/* used in constraint.c too */
void BKE_pchan_calc_mat(bPoseChannel *pchan)
{
/* this is just a wrapper around the copy of this function which calculates the matrix
@@ -2742,7 +2647,6 @@ void BKE_pchan_calc_mat(bPoseChannel *pchan)
BKE_pchan_to_mat4(pchan, pchan->chan_mat);
}
-/* calculate tail of posechannel */
void BKE_pose_where_is_bone_tail(bPoseChannel *pchan)
{
float vec[3];
@@ -2752,10 +2656,6 @@ void BKE_pose_where_is_bone_tail(bPoseChannel *pchan)
add_v3_v3v3(pchan->pose_tail, pchan->pose_head, vec);
}
-/* The main armature solver, does all constraints excluding IK */
-/* pchan is validated, as having bone and parent pointer
- * 'do_extra': when zero skips loc/size/rot, constraints and strip modifiers.
- */
void BKE_pose_where_is_bone(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -2763,7 +2663,7 @@ void BKE_pose_where_is_bone(struct Depsgraph *depsgraph,
float ctime,
bool do_extra)
{
- /* This gives a chan_mat with actions (ipos) results. */
+ /* This gives a chan_mat with actions (F-curve) results. */
if (do_extra) {
BKE_pchan_calc_mat(pchan);
}
@@ -2820,8 +2720,6 @@ void BKE_pose_where_is_bone(struct Depsgraph *depsgraph,
BKE_pose_where_is_bone_tail(pchan);
}
-/* This only reads anim data from channels, and writes to channels */
-/* This is the only function adding poses */
void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
bArmature *arm;
@@ -2966,10 +2864,16 @@ bool BKE_pose_minmax(Object *ob, float r_min[3], float r_max[3], bool use_hidden
BKE_object_boundbox_get(pchan->custom) :
NULL;
if (bb_custom) {
- float mat[4][4], smat[4][4];
+ float mat[4][4], smat[4][4], rmat[4][4], tmp[4][4];
scale_m4_fl(smat, PCHAN_CUSTOM_BONE_LENGTH(pchan));
rescale_m4(smat, pchan->custom_scale_xyz);
- mul_m4_series(mat, ob->obmat, pchan_tx->pose_mat, smat);
+ eulO_to_mat4(rmat, pchan->custom_rotation_euler, ROT_MODE_XYZ);
+ copy_m4_m4(tmp, pchan_tx->pose_mat);
+ translate_m4(tmp,
+ pchan->custom_translation[0],
+ pchan->custom_translation[1],
+ pchan->custom_translation[2]);
+ mul_m4_series(mat, ob->obmat, tmp, rmat, smat);
BKE_boundbox_minmax(bb_custom, mat, r_min, r_max);
}
else {
diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c
index 5f721b49361..a8e74f6b4c3 100644
--- a/source/blender/blenkernel/intern/armature_deform.c
+++ b/source/blender/blenkernel/intern/armature_deform.c
@@ -121,7 +121,6 @@ static void b_bone_deform(const bPoseChannel *pchan,
&quats[index + 1], mats[index + 2].mat, co, weight * blend, vec, dq, defmat);
}
-/* using vec with dist to bone b1 - b2 */
float distfactor_to_bone(
const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist)
{
diff --git a/source/blender/blenkernel/intern/armature_test.cc b/source/blender/blenkernel/intern/armature_test.cc
index 2994563175f..a6d9a1f41e9 100644
--- a/source/blender/blenkernel/intern/armature_test.cc
+++ b/source/blender/blenkernel/intern/armature_test.cc
@@ -30,6 +30,36 @@ namespace blender::bke::tests {
static const float FLOAT_EPSILON = 1.2e-7;
+static const float SCALE_EPSILON = 3.71e-5;
+static const float ORTHO_EPSILON = 5e-5;
+
+/** Test that the matrix is orthogonal, i.e. has no scale or shear within acceptable precision. */
+static double EXPECT_M3_ORTHOGONAL(const float mat[3][3],
+ double epsilon_scale,
+ double epsilon_ortho)
+{
+ /* Do the checks in double precision to avoid precision issues in the checks themselves. */
+ double dmat[3][3];
+ copy_m3d_m3(dmat, mat);
+
+ /* Check individual axis scaling. */
+ EXPECT_NEAR(len_v3_db(dmat[0]), 1.0, epsilon_scale);
+ EXPECT_NEAR(len_v3_db(dmat[1]), 1.0, epsilon_scale);
+ EXPECT_NEAR(len_v3_db(dmat[2]), 1.0, epsilon_scale);
+
+ /* Check orthogonality. */
+ EXPECT_NEAR(dot_v3v3_db(dmat[0], dmat[1]), 0.0, epsilon_ortho);
+ EXPECT_NEAR(dot_v3v3_db(dmat[0], dmat[2]), 0.0, epsilon_ortho);
+ EXPECT_NEAR(dot_v3v3_db(dmat[1], dmat[2]), 0.0, epsilon_ortho);
+
+ /* Check determinant to detect flipping and as a secondary volume change check. */
+ double determinant = determinant_m3_array_db(dmat);
+
+ EXPECT_NEAR(determinant, 1.0, epsilon_ortho);
+
+ return determinant;
+}
+
TEST(mat3_vec_to_roll, UnitMatrix)
{
float unit_matrix[3][3];
@@ -93,73 +123,246 @@ TEST(mat3_vec_to_roll, Rotationmatrix)
}
}
-TEST(vec_roll_to_mat3_normalized, Rotationmatrix)
+/** Generic function to test vec_roll_to_mat3_normalized. */
+static double test_vec_roll_to_mat3_normalized(const float input[3],
+ float roll,
+ const float expected_roll_mat[3][3],
+ bool normalize = true)
{
- float negative_y_axis[3][3];
- unit_m3(negative_y_axis);
- negative_y_axis[0][0] = negative_y_axis[1][1] = -1.0f;
-
- const float roll = 0.0f;
+ float input_normalized[3];
float roll_mat[3][3];
- /* If normalized_vector is -Y, simple symmetry by Z axis. */
- {
- const float normalized_vector[3] = {0.0f, -1.0f, 0.0f};
- vec_roll_to_mat3_normalized(normalized_vector, roll, roll_mat);
- EXPECT_M3_NEAR(roll_mat, negative_y_axis, FLT_EPSILON);
+ if (normalize) {
+ /* The vector is re-normalized to replicate the actual usage. */
+ normalize_v3_v3(input_normalized, input);
+ }
+ else {
+ copy_v3_v3(input_normalized, input);
}
- /* If normalized_vector is far enough from -Y, apply the general case. */
- {
- const float expected_roll_mat[3][3] = {{1.000000f, 0.000000f, 0.000000f},
- {0.000000f, -0.999989986f, -0.000000f},
- {0.000000f, 0.000000f, 1.000000f}};
+ vec_roll_to_mat3_normalized(input_normalized, roll, roll_mat);
+
+ EXPECT_V3_NEAR(roll_mat[1], input_normalized, FLT_EPSILON);
- const float normalized_vector[3] = {0.0f, -1.0f + 1e-5f, 0.0f};
- vec_roll_to_mat3_normalized(normalized_vector, roll, roll_mat);
+ if (expected_roll_mat) {
EXPECT_M3_NEAR(roll_mat, expected_roll_mat, FLT_EPSILON);
}
-#if 0
- /* TODO: This test will pass after fixing T82455) */
- /* If normalized_vector is close to -Y and
- * it has X and Z values above a threshold,
- * apply the special case. */
- {
- const float expected_roll_mat[3][3] = {{0.000000f, -9.99999975e-06f, 1.000000f},
- {9.99999975e-06f, -0.999999881f, 9.99999975e-06f},
- {1.000000f, -9.99999975e-06, 0.000000f}};
- const float normalized_vector[3] = {1e-24, -0.999999881, 0};
- vec_roll_to_mat3_normalized(normalized_vector, roll, roll_mat);
- EXPECT_M3_NEAR(roll_mat, expected_roll_mat, FLT_EPSILON);
+ return EXPECT_M3_ORTHOGONAL(roll_mat, SCALE_EPSILON, ORTHO_EPSILON);
+}
+
+/** Binary search to test where the code switches to the most degenerate special case. */
+static double find_flip_boundary(double x, double z)
+{
+ /* Irrational scale factor to ensure values aren't 'nice', have a lot of rounding errors,
+ * and can't accidentally produce the exact result returned by the special case. */
+ const double scale = M_1_PI / 10;
+ double theta = x * x + z * z;
+ double minv = 0, maxv = 1e-2;
+
+ while (maxv - minv > FLT_EPSILON * 1e-3) {
+ double mid = (minv + maxv) / 2;
+
+ float roll_mat[3][3];
+ float input[3] = {float(x * mid * scale),
+ -float(sqrt(1 - theta * mid * mid) * scale),
+ float(z * mid * scale)};
+
+ normalize_v3(input);
+ vec_roll_to_mat3_normalized(input, 0, roll_mat);
+
+ /* The special case assigns exact constants rather than computing. */
+ if (roll_mat[0][0] == -1 && roll_mat[0][1] == 0 && roll_mat[2][1] == 0) {
+ minv = mid;
+ }
+ else {
+ maxv = mid;
+ }
}
-#endif
+ return sqrt(theta) * (minv + maxv) * 0.5;
+}
+
+TEST(vec_roll_to_mat3_normalized, FlippedBoundary1)
+{
+ EXPECT_NEAR(find_flip_boundary(0, 1), 2.50e-4, 0.01e-4);
+}
+
+TEST(vec_roll_to_mat3_normalized, FlippedBoundary2)
+{
+ EXPECT_NEAR(find_flip_boundary(1, 1), 2.50e-4, 0.01e-4);
+}
+
+/* Test cases close to the -Y axis. */
+TEST(vec_roll_to_mat3_normalized, Flipped1)
+{
+ /* If normalized_vector is -Y, simple symmetry by Z axis. */
+ const float input[3] = {0.0f, -1.0f, 0.0f};
+ const float expected_roll_mat[3][3] = {
+ {-1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
+ test_vec_roll_to_mat3_normalized(input, 0.0f, expected_roll_mat, false);
+}
+
+TEST(vec_roll_to_mat3_normalized, Flipped2)
+{
+ /* If normalized_vector is close to -Y and
+ * it has X and Z values below a threshold,
+ * simple symmetry by Z axis. */
+ const float input[3] = {1e-24, -0.999999881, 0};
+ const float expected_roll_mat[3][3] = {
+ {-1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
+ test_vec_roll_to_mat3_normalized(input, 0.0f, expected_roll_mat, false);
+}
+
+TEST(vec_roll_to_mat3_normalized, Flipped3)
+{
/* If normalized_vector is in a critical range close to -Y, apply the special case. */
- {
- const float expected_roll_mat[3][3] = {{0.000000f, -9.99999975e-06f, 1.000000f},
- {9.99999975e-06f, -0.999999881f, 9.99999975e-06f},
- {1.000000f, -9.99999975e-06f, 0.000000f}};
+ const float input[3] = {2.5e-4f, -0.999999881f, 2.5e-4f}; /* Corner Case. */
+ const float expected_roll_mat[3][3] = {{0.000000f, -2.5e-4f, -1.000000f},
+ {2.5e-4f, -0.999999881f, 2.5e-4f},
+ {-1.000000f, -2.5e-4f, 0.000000f}};
+ test_vec_roll_to_mat3_normalized(input, 0.0f, expected_roll_mat, false);
+}
- const float normalized_vector[3] = {1e-5f, -0.999999881f, 1e-5f}; /* Corner Case. */
- vec_roll_to_mat3_normalized(normalized_vector, roll, roll_mat);
- EXPECT_M3_NEAR(roll_mat, expected_roll_mat, FLT_EPSILON);
- }
+/* Test 90 degree rotations. */
+TEST(vec_roll_to_mat3_normalized, Rotate90_Z_CW)
+{
+ /* Rotate 90 around Z. */
+ const float input[3] = {1, 0, 0};
+ const float expected_roll_mat[3][3] = {{0, -1, 0}, {1, 0, 0}, {0, 0, 1}};
+ test_vec_roll_to_mat3_normalized(input, 0.0f, expected_roll_mat);
+}
- /* If normalized_vector is far enough from -Y, apply the general case. */
- {
- const float expected_roll_mat[3][3] = {{0.788675129f, -0.577350259f, -0.211324856f},
- {0.577350259f, 0.577350259f, 0.577350259f},
- {-0.211324856f, -0.577350259f, 0.788675129f}};
-
- const float vector[3] = {1.0f, 1.0f, 1.0f}; /* Arbitrary Value. */
- float normalized_vector[3];
- normalize_v3_v3(normalized_vector, vector);
- vec_roll_to_mat3_normalized(normalized_vector, roll, roll_mat);
- EXPECT_M3_NEAR(roll_mat, expected_roll_mat, FLT_EPSILON);
+TEST(vec_roll_to_mat3_normalized, Rotate90_Z_CCW)
+{
+ /* Rotate 90 around Z. */
+ const float input[3] = {-1, 0, 0};
+ const float expected_roll_mat[3][3] = {{0, 1, 0}, {-1, 0, 0}, {0, 0, 1}};
+ test_vec_roll_to_mat3_normalized(input, 0.0f, expected_roll_mat);
+}
+
+TEST(vec_roll_to_mat3_normalized, Rotate90_X_CW)
+{
+ /* Rotate 90 around X. */
+ const float input[3] = {0, 0, -1};
+ const float expected_roll_mat[3][3] = {{1, 0, 0}, {0, 0, -1}, {0, 1, 0}};
+ test_vec_roll_to_mat3_normalized(input, 0.0f, expected_roll_mat);
+}
+
+TEST(vec_roll_to_mat3_normalized, Rotate90_X_CCW)
+{
+ /* Rotate 90 around X. */
+ const float input[3] = {0, 0, 1};
+ const float expected_roll_mat[3][3] = {{1, 0, 0}, {0, 0, 1}, {0, -1, 0}};
+ test_vec_roll_to_mat3_normalized(input, 0.0f, expected_roll_mat);
+}
+
+/* Test the general case when the vector is far enough from -Y. */
+TEST(vec_roll_to_mat3_normalized, Generic1)
+{
+ const float input[3] = {1.0f, 1.0f, 1.0f}; /* Arbitrary Value. */
+ const float expected_roll_mat[3][3] = {{0.788675129f, -0.577350259f, -0.211324856f},
+ {0.577350259f, 0.577350259f, 0.577350259f},
+ {-0.211324856f, -0.577350259f, 0.788675129f}};
+ test_vec_roll_to_mat3_normalized(input, 0.0f, expected_roll_mat);
+}
+
+TEST(vec_roll_to_mat3_normalized, Generic2)
+{
+ const float input[3] = {1.0f, -1.0f, 1.0f}; /* Arbitrary Value. */
+ const float expected_roll_mat[3][3] = {{0.211324856f, -0.577350259f, -0.788675129f},
+ {0.577350259f, -0.577350259f, 0.577350259f},
+ {-0.788675129f, -0.577350259f, 0.211324856f}};
+ test_vec_roll_to_mat3_normalized(input, 0.0f, expected_roll_mat);
+}
+
+TEST(vec_roll_to_mat3_normalized, Generic3)
+{
+ const float input[3] = {-1.0f, -1.0f, 1.0f}; /* Arbitrary Value. */
+ const float expected_roll_mat[3][3] = {{0.211324856f, 0.577350259f, 0.788675129f},
+ {-0.577350259f, -0.577350259f, 0.577350259f},
+ {0.788675129f, -0.577350259f, 0.211324856f}};
+ test_vec_roll_to_mat3_normalized(input, 0.0f, expected_roll_mat);
+}
+
+TEST(vec_roll_to_mat3_normalized, Generic4)
+{
+ const float input[3] = {-1.0f, -1.0f, -1.0f}; /* Arbitrary Value. */
+ const float expected_roll_mat[3][3] = {{0.211324856f, 0.577350259f, -0.788675129f},
+ {-0.577350259f, -0.577350259f, -0.577350259f},
+ {-0.788675129f, 0.577350259f, 0.211324856f}};
+ test_vec_roll_to_mat3_normalized(input, 0.0f, expected_roll_mat);
+}
+
+/* Test roll. */
+TEST(vec_roll_to_mat3_normalized, Roll1)
+{
+ const float input[3] = {1.0f, 1.0f, 1.0f}; /* Arbitrary Value. */
+ const float expected_roll_mat[3][3] = {{0.211324856f, 0.577350259f, -0.788675129f},
+ {0.577350259f, 0.577350259f, 0.577350259f},
+ {0.788675129f, -0.577350259f, -0.211324856f}};
+ test_vec_roll_to_mat3_normalized(input, float(M_PI * 0.5), expected_roll_mat);
+}
+
+/** Test that the matrix is orthogonal for an input close to -Y. */
+static double test_vec_roll_to_mat3_orthogonal(double s, double x, double z)
+{
+ const float input[3] = {float(x), float(s * sqrt(1 - x * x - z * z)), float(z)};
+
+ return test_vec_roll_to_mat3_normalized(input, 0.0f, nullptr);
+}
+
+/** Test that the matrix is orthogonal for a range of inputs close to -Y. */
+static void test_vec_roll_to_mat3_orthogonal(double s, double x1, double x2, double y1, double y2)
+{
+ const int count = 5000;
+ double delta = 0;
+ double tmax = 0;
+
+ for (int i = 0; i <= count; i++) {
+ double t = double(i) / count;
+ double det = test_vec_roll_to_mat3_orthogonal(s, interpd(x2, x1, t), interpd(y2, y1, t));
+
+ /* Find and report maximum error in the matrix determinant. */
+ double curdelta = abs(det - 1);
+ if (curdelta > delta) {
+ delta = curdelta;
+ tmax = t;
+ }
}
+
+ printf(" Max determinant deviation %.10f at %f.\n", delta, tmax);
}
+#define TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(name, s, x1, x2, y1, y2) \
+ TEST(vec_roll_to_mat3_normalized, name) \
+ { \
+ test_vec_roll_to_mat3_orthogonal(s, x1, x2, y1, y2); \
+ }
+
+/* Moving from -Y towards X. */
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoN_000_005, -1, 0, 0, 3e-4, 0.005)
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoN_000_010, -1, 0, 0, 0.005, 0.010)
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoN_000_050, -1, 0, 0, 0.010, 0.050)
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoN_000_100, -1, 0, 0, 0.050, 0.100)
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoN_000_200, -1, 0, 0, 0.100, 0.200)
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoN_000_300, -1, 0, 0, 0.200, 0.300)
+
+/* Moving from -Y towards X and Y. */
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoN_005_005, -1, 3e-4, 0.005, 3e-4, 0.005)
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoN_010_010, -1, 0.005, 0.010, 0.005, 0.010)
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoN_050_050, -1, 0.010, 0.050, 0.010, 0.050)
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoN_100_100, -1, 0.050, 0.100, 0.050, 0.100)
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoN_200_200, -1, 0.100, 0.200, 0.100, 0.200)
+
+/* Moving from +Y towards X. */
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoP_000_005, 1, 0, 0, 0, 0.005)
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoP_000_100, 1, 0, 0, 0.005, 0.100)
+
+/* Moving from +Y towards X and Y. */
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoP_005_005, 1, 0, 0.005, 0, 0.005)
+TEST_VEC_ROLL_TO_MAT3_ORTHOGONAL(OrthoP_100_100, 1, 0.005, 0.100, 0.005, 0.100)
+
class BKE_armature_find_selected_bones_test : public testing::Test {
protected:
bArmature arm;
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 35ae2d2dbef..05c318663e9 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -277,46 +277,59 @@ static void apply_curve_transform(
*r_radius = (radius + *r_radius) / 2;
}
+static float dist_to_sphere_shell(const float sphere_origin[3],
+ const float sphere_radius,
+ const float point[3])
+{
+ float vec[3];
+ sub_v3_v3v3(vec, sphere_origin, point);
+ return sphere_radius - len_v3(vec);
+}
+
/* This function positions the tail of the bone so that it preserves the length of it.
* The length of the bone can be seen as a sphere radius.
*/
static int position_tail_on_spline(bSplineIKConstraint *ik_data,
const float head_pos[3],
const float sphere_radius,
- const int prev_seg_idx,
+ int prev_seg_idx,
float r_tail_pos[3],
float *r_new_curve_pos,
float *r_radius)
{
/* This is using the tessellated curve data.
* So we are working with piece-wise linear curve segments.
- * The same method is use in #BKE_where_on_path to get curve location data. */
+ * The same method is used in #BKE_where_on_path to get curve location data. */
const CurveCache *cache = ik_data->tar->runtime.curve_cache;
- const BevList *bl = cache->bev.first;
- BevPoint *bp = bl->bevpoints;
- const float spline_len = BKE_anim_path_get_length(cache);
const float *seg_accum_len = cache->anim_path_accum_length;
int max_seg_idx = BKE_anim_path_get_array_size(cache) - 1;
- /* Convert our initial intersection point guess to a point index.
- * If the curve was a straight line, then pointEnd would be the correct location.
+ /* Make an initial guess of where our intersection point will be.
+ * If the curve was a straight line, then the faction passed in r_new_curve_pos
+ * would be the correct location.
* So make it our first initial guess.
*/
+ const float spline_len = BKE_anim_path_get_length(cache);
const float guessed_len = *r_new_curve_pos * spline_len;
BLI_assert(prev_seg_idx >= 0);
-
int cur_seg_idx = prev_seg_idx;
while (cur_seg_idx < max_seg_idx && guessed_len > seg_accum_len[cur_seg_idx]) {
cur_seg_idx++;
}
+ /* Convert the segment to bev points.
+ * For example, the segment with index 0 will have bev points 0 and 1.
+ */
int bp_idx = cur_seg_idx + 1;
- bp = bp + bp_idx;
+ const BevList *bl = cache->bev.first;
bool is_cyclic = bl->poly >= 0;
- BevPoint *prev_bp = bp - 1;
+ BevPoint *bp = bl->bevpoints;
+ BevPoint *prev_bp;
+ bp = bp + bp_idx;
+ prev_bp = bp - 1;
/* Go to the next tessellated curve point until we cross to outside of the sphere. */
while (len_v3v3(head_pos, bp->vec) < sphere_radius) {
@@ -337,35 +350,53 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
bp_idx++;
}
- float isect_1[3], isect_2[3];
-
- /* Calculate the intersection point. */
- int ret = isect_line_sphere_v3(prev_bp->vec, bp->vec, head_pos, sphere_radius, isect_1, isect_2);
+ /* Calculate the intersection point using the secant root finding method */
+ float x0 = 0.0f, x1 = 1.0f, x2 = 0.5f;
+ float x0_point[3], x1_point[3], start_p[3];
+ float epsilon = max_fff(1.0f, len_v3(head_pos), len_v3(bp->vec)) * FLT_EPSILON;
- if (ret > 0) {
- /* Because of how `isect_line_sphere_v3` works, we know that `isect_1` contains the
- * intersection point we want. And it will always intersect as we go from inside to outside
- * of the sphere.
+ if (prev_seg_idx == bp_idx - 1) {
+ /* The intersection lies inside the same segment as the last point.
+ * Set the last point to be the start search point so we minimize the risks of going backwards
+ * on the curve.
*/
- copy_v3_v3(r_tail_pos, isect_1);
+ copy_v3_v3(start_p, head_pos);
}
else {
- /* Couldn't find an intersection point. This means that the floating point
- * values are too small and thus the intersection check fails.
- * So assume that the distance is so small that tail_pos == head_pos.
- */
- copy_v3_v3(r_tail_pos, head_pos);
+ copy_v3_v3(start_p, prev_bp->vec);
}
- cur_seg_idx = bp_idx - 2;
+ for (int i = 0; i < 10; i++) {
+ interp_v3_v3v3(x0_point, start_p, bp->vec, x0);
+ interp_v3_v3v3(x1_point, start_p, bp->vec, x1);
+
+ float f_x0 = dist_to_sphere_shell(head_pos, sphere_radius, x0_point);
+ float f_x1 = dist_to_sphere_shell(head_pos, sphere_radius, x1_point);
+
+ if (fabsf(f_x1) <= epsilon || f_x0 == f_x1) {
+ break;
+ }
+
+ x2 = x1 - f_x1 * (x1 - x0) / (f_x1 - f_x0);
+ x0 = x1;
+ x1 = x2;
+ }
+ /* Found the bone tail position! */
+ copy_v3_v3(r_tail_pos, x1_point);
+
+ /* Because our intersection point lies inside the current segment,
+ * Convert our bevpoint index back to the previous segment index (-2 instead of -1).
+ * This is because our actual location is prev_seg_len + isect_seg_len.
+ */
+ prev_seg_idx = bp_idx - 2;
float prev_seg_len = 0;
- if (cur_seg_idx < 0) {
- cur_seg_idx = 0;
+ if (prev_seg_idx < 0) {
+ prev_seg_idx = 0;
prev_seg_len = 0;
}
else {
- prev_seg_len = seg_accum_len[cur_seg_idx];
+ prev_seg_len = seg_accum_len[prev_seg_idx];
}
/* Convert the point back into the 0-1 interpolation range. */
@@ -380,7 +411,8 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
*r_radius = (1.0f - frac) * prev_bp->radius + frac * bp->radius;
}
- return cur_seg_idx;
+ /* Return the current segment. */
+ return bp_idx - 1;
}
/* Evaluate spline IK for a given bone. */
diff --git a/source/blender/blenkernel/intern/asset.cc b/source/blender/blenkernel/intern/asset.cc
index ae9ded3c754..e5509b09e20 100644
--- a/source/blender/blenkernel/intern/asset.cc
+++ b/source/blender/blenkernel/intern/asset.cc
@@ -21,14 +21,12 @@
#include <cstring>
#include "DNA_ID.h"
-#include "DNA_asset_types.h"
#include "DNA_defaults.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
#include "BLI_string_utils.h"
-#include "BLI_utildefines.h"
#include "BLI_uuid.h"
#include "BKE_asset.h"
@@ -41,7 +39,7 @@
using namespace blender;
-AssetMetaData *BKE_asset_metadata_create(void)
+AssetMetaData *BKE_asset_metadata_create()
{
AssetMetaData *asset_data = (AssetMetaData *)MEM_callocN(sizeof(*asset_data), __func__);
memcpy(asset_data, DNA_struct_default_get(AssetMetaData), sizeof(*asset_data));
@@ -53,6 +51,7 @@ void BKE_asset_metadata_free(AssetMetaData **asset_data)
if ((*asset_data)->properties) {
IDP_FreeProperty((*asset_data)->properties);
}
+ MEM_SAFE_FREE((*asset_data)->author);
MEM_SAFE_FREE((*asset_data)->description);
BLI_freelistN(&(*asset_data)->tags);
@@ -79,9 +78,6 @@ AssetTag *BKE_asset_metadata_tag_add(AssetMetaData *asset_data, const char *name
return tag;
}
-/**
- * Make sure there is a tag with name \a name, create one if needed.
- */
struct AssetTagEnsureResult BKE_asset_metadata_tag_ensure(AssetMetaData *asset_data,
const char *name)
{
@@ -140,6 +136,25 @@ void BKE_asset_metadata_catalog_id_set(struct AssetMetaData *asset_data,
trimmed_id.copy(asset_data->catalog_simple_name, max_simple_name_length);
}
+void BKE_asset_metadata_idprop_ensure(AssetMetaData *asset_data, IDProperty *prop)
+{
+ if (!asset_data->properties) {
+ IDPropertyTemplate val = {0};
+ asset_data->properties = IDP_New(IDP_GROUP, &val, "AssetMetaData.properties");
+ }
+ /* Important: The property may already exist. For now just allow always allow a newly allocated
+ * property, and replace the existing one as a way of updating. */
+ IDP_ReplaceInGroup(asset_data->properties, prop);
+}
+
+IDProperty *BKE_asset_metadata_idprop_find(const AssetMetaData *asset_data, const char *name)
+{
+ if (!asset_data->properties) {
+ return nullptr;
+ }
+ return IDP_GetPropertyFromGroup(asset_data->properties, name);
+}
+
/* Queries -------------------------------------------- */
PreviewImage *BKE_asset_metadata_preview_get_from_id(const AssetMetaData *UNUSED(asset_data),
@@ -158,6 +173,9 @@ void BKE_asset_metadata_write(BlendWriter *writer, AssetMetaData *asset_data)
IDP_BlendWrite(writer, asset_data->properties);
}
+ if (asset_data->author) {
+ BLO_write_string(writer, asset_data->author);
+ }
if (asset_data->description) {
BLO_write_string(writer, asset_data->description);
}
@@ -169,12 +187,14 @@ void BKE_asset_metadata_write(BlendWriter *writer, AssetMetaData *asset_data)
void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data)
{
/* asset_data itself has been read already. */
+ asset_data->local_type_info = nullptr;
if (asset_data->properties) {
BLO_read_data_address(reader, &asset_data->properties);
IDP_BlendDataRead(reader, &asset_data->properties);
}
+ BLO_read_data_address(reader, &asset_data->author);
BLO_read_data_address(reader, &asset_data->description);
BLO_read_list(reader, &asset_data->tags);
BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags);
diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc
index b00f4305aa6..06dd623ff28 100644
--- a/source/blender/blenkernel/intern/asset_catalog.cc
+++ b/source/blender/blenkernel/intern/asset_catalog.cc
@@ -18,35 +18,29 @@
* \ingroup bke
*/
+#include <fstream>
+#include <set>
+
#include "BKE_asset_catalog.hh"
#include "BKE_asset_library.h"
-#include "BKE_preferences.h"
-#include "BLI_fileops.h"
+#include "BLI_fileops.hh"
#include "BLI_path_util.h"
-#include "BLI_string_ref.hh"
-
-#include "DNA_userdef_types.h"
/* For S_ISREG() and S_ISDIR() on Windows. */
#ifdef WIN32
# include "BLI_winstuff.h"
#endif
-#include <fstream>
-#include <set>
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"bke.asset_service"};
namespace blender::bke {
-const char AssetCatalogService::PATH_SEPARATOR = '/';
const CatalogFilePath AssetCatalogService::DEFAULT_CATALOG_FILENAME = "blender_assets.cats.txt";
-/* For now this is the only version of the catalog definition files that is supported.
- * Later versioning code may be added to handle older files. */
const int AssetCatalogDefinitionFile::SUPPORTED_VERSION = 1;
-/* String that's matched in the catalog definition file to know that the line is the version
- * declaration. It has to start with a space to ensure it won't match any hypothetical future field
- * that starts with "VERSION". */
const std::string AssetCatalogDefinitionFile::VERSION_MARKER = "VERSION ";
const std::string AssetCatalogDefinitionFile::HEADER =
@@ -56,39 +50,146 @@ const std::string AssetCatalogDefinitionFile::HEADER =
"# The first non-ignored line should be the version indicator.\n"
"# Other lines are of the format \"UUID:catalog/path/for/assets:simple catalog name\"\n";
+AssetCatalogService::AssetCatalogService()
+ : catalog_collection_(std::make_unique<AssetCatalogCollection>())
+{
+}
+
AssetCatalogService::AssetCatalogService(const CatalogFilePath &asset_library_root)
- : asset_library_root_(asset_library_root)
+ : catalog_collection_(std::make_unique<AssetCatalogCollection>()),
+ asset_library_root_(asset_library_root)
+{
+}
+
+void AssetCatalogService::tag_has_unsaved_changes(AssetCatalog *edited_catalog)
{
+ if (edited_catalog) {
+ edited_catalog->flags.has_unsaved_changes = true;
+ }
+ BLI_assert(catalog_collection_);
+ catalog_collection_->has_unsaved_changes_ = true;
+}
+
+void AssetCatalogService::untag_has_unsaved_changes()
+{
+ BLI_assert(catalog_collection_);
+ catalog_collection_->has_unsaved_changes_ = false;
+
+ /* TODO(Sybren): refactor; this is more like "post-write cleanup" than "remove a tag" code. */
+
+ /* Forget about any deleted catalogs. */
+ if (catalog_collection_->catalog_definition_file_) {
+ for (CatalogID catalog_id : catalog_collection_->deleted_catalogs_.keys()) {
+ catalog_collection_->catalog_definition_file_->forget(catalog_id);
+ }
+ }
+ catalog_collection_->deleted_catalogs_.clear();
+
+ /* Mark all remaining catalogs as "without unsaved changes". */
+ for (auto &catalog_uptr : catalog_collection_->catalogs_.values()) {
+ catalog_uptr->flags.has_unsaved_changes = false;
+ }
+}
+
+bool AssetCatalogService::has_unsaved_changes() const
+{
+ BLI_assert(catalog_collection_);
+ return catalog_collection_->has_unsaved_changes_;
+}
+
+void AssetCatalogService::tag_all_catalogs_as_unsaved_changes()
+{
+ for (auto &catalog : catalog_collection_->catalogs_.values()) {
+ catalog->flags.has_unsaved_changes = true;
+ }
+ catalog_collection_->has_unsaved_changes_ = true;
}
bool AssetCatalogService::is_empty() const
{
- return catalogs_.is_empty();
+ BLI_assert(catalog_collection_);
+ return catalog_collection_->catalogs_.is_empty();
}
-AssetCatalog *AssetCatalogService::find_catalog(CatalogID catalog_id)
+OwningAssetCatalogMap &AssetCatalogService::get_catalogs()
+{
+ return catalog_collection_->catalogs_;
+}
+OwningAssetCatalogMap &AssetCatalogService::get_deleted_catalogs()
{
- std::unique_ptr<AssetCatalog> *catalog_uptr_ptr = this->catalogs_.lookup_ptr(catalog_id);
+ return catalog_collection_->deleted_catalogs_;
+}
+
+AssetCatalogDefinitionFile *AssetCatalogService::get_catalog_definition_file()
+{
+ return catalog_collection_->catalog_definition_file_.get();
+}
+
+AssetCatalog *AssetCatalogService::find_catalog(CatalogID catalog_id) const
+{
+ const std::unique_ptr<AssetCatalog> *catalog_uptr_ptr =
+ catalog_collection_->catalogs_.lookup_ptr(catalog_id);
if (catalog_uptr_ptr == nullptr) {
return nullptr;
}
return catalog_uptr_ptr->get();
}
-AssetCatalog *AssetCatalogService::find_catalog_by_path(const CatalogPath &path) const
+AssetCatalog *AssetCatalogService::find_catalog_by_path(const AssetCatalogPath &path) const
{
- for (const auto &catalog : catalogs_.values()) {
+ /* Use an AssetCatalogOrderedSet to find the 'best' catalog for this path. This will be the first
+ * one loaded from disk, or if that does not exist the one with the lowest UUID. This ensures
+ * stable, predictable results. */
+ MutableAssetCatalogOrderedSet ordered_catalogs;
+
+ for (const auto &catalog : catalog_collection_->catalogs_.values()) {
if (catalog->path == path) {
- return catalog.get();
+ ordered_catalogs.insert(catalog.get());
+ }
+ }
+
+ if (ordered_catalogs.empty()) {
+ return nullptr;
+ }
+
+ MutableAssetCatalogOrderedSet::iterator best_choice_it = ordered_catalogs.begin();
+ return *best_choice_it;
+}
+
+bool AssetCatalogService::is_catalog_known(CatalogID catalog_id) const
+{
+ BLI_assert(catalog_collection_);
+ return catalog_collection_->catalogs_.contains(catalog_id);
+}
+
+AssetCatalogFilter AssetCatalogService::create_catalog_filter(
+ const CatalogID active_catalog_id) const
+{
+ Set<CatalogID> matching_catalog_ids;
+ Set<CatalogID> known_catalog_ids;
+ matching_catalog_ids.add(active_catalog_id);
+
+ const AssetCatalog *active_catalog = find_catalog(active_catalog_id);
+
+ /* This cannot just iterate over tree items to get all the required data, because tree items only
+ * represent single UUIDs. It could be used to get the main UUIDs of the children, though, and
+ * then only do an exact match on the path (instead of the more complex `is_contained_in()`
+ * call). Without an extra indexed-by-path acceleration structure, this is still going to require
+ * a linear search, though. */
+ for (const auto &catalog_uptr : catalog_collection_->catalogs_.values()) {
+ if (active_catalog && catalog_uptr->path.is_contained_in(active_catalog->path)) {
+ matching_catalog_ids.add(catalog_uptr->catalog_id);
}
+ known_catalog_ids.add(catalog_uptr->catalog_id);
}
- return nullptr;
+ return AssetCatalogFilter(std::move(matching_catalog_ids), std::move(known_catalog_ids));
}
-void AssetCatalogService::delete_catalog(CatalogID catalog_id)
+void AssetCatalogService::delete_catalog_by_id_soft(const CatalogID catalog_id)
{
- std::unique_ptr<AssetCatalog> *catalog_uptr_ptr = this->catalogs_.lookup_ptr(catalog_id);
+ std::unique_ptr<AssetCatalog> *catalog_uptr_ptr = catalog_collection_->catalogs_.lookup_ptr(
+ catalog_id);
if (catalog_uptr_ptr == nullptr) {
/* Catalog cannot be found, which is fine. */
return;
@@ -98,37 +199,79 @@ void AssetCatalogService::delete_catalog(CatalogID catalog_id)
AssetCatalog *catalog = catalog_uptr_ptr->get();
catalog->flags.is_deleted = true;
- /* Move ownership from this->catalogs_ to this->deleted_catalogs_. */
- this->deleted_catalogs_.add(catalog_id, std::move(*catalog_uptr_ptr));
+ /* Move ownership from catalog_collection_->catalogs_ to catalog_collection_->deleted_catalogs_.
+ */
+ catalog_collection_->deleted_catalogs_.add(catalog_id, std::move(*catalog_uptr_ptr));
/* The catalog can now be removed from the map without freeing the actual AssetCatalog. */
- this->catalogs_.remove(catalog_id);
+ catalog_collection_->catalogs_.remove(catalog_id);
+}
+
+void AssetCatalogService::delete_catalog_by_id_hard(CatalogID catalog_id)
+{
+ catalog_collection_->catalogs_.remove(catalog_id);
+ catalog_collection_->deleted_catalogs_.remove(catalog_id);
+
+ /* TODO(@sybren): adjust this when supporting multiple CDFs. */
+ catalog_collection_->catalog_definition_file_->forget(catalog_id);
+}
+
+void AssetCatalogService::prune_catalogs_by_path(const AssetCatalogPath &path)
+{
+ /* Build a collection of catalog IDs to delete. */
+ Set<CatalogID> catalogs_to_delete;
+ for (const auto &catalog_uptr : catalog_collection_->catalogs_.values()) {
+ const AssetCatalog *cat = catalog_uptr.get();
+ if (cat->path.is_contained_in(path)) {
+ catalogs_to_delete.add(cat->catalog_id);
+ }
+ }
+
+ /* Delete the catalogs. */
+ for (const CatalogID cat_id : catalogs_to_delete) {
+ this->delete_catalog_by_id_soft(cat_id);
+ }
this->rebuild_tree();
}
-void AssetCatalogService::update_catalog_path(CatalogID catalog_id,
- const CatalogPath &new_catalog_path)
+void AssetCatalogService::prune_catalogs_by_id(const CatalogID catalog_id)
+{
+ const AssetCatalog *catalog = find_catalog(catalog_id);
+ BLI_assert_msg(catalog, "trying to prune asset catalogs by the path of a non-existent catalog");
+ if (!catalog) {
+ return;
+ }
+ this->prune_catalogs_by_path(catalog->path);
+}
+
+void AssetCatalogService::update_catalog_path(const CatalogID catalog_id,
+ const AssetCatalogPath &new_catalog_path)
{
AssetCatalog *renamed_cat = this->find_catalog(catalog_id);
- const CatalogPath old_cat_path = renamed_cat->path;
+ const AssetCatalogPath old_cat_path = renamed_cat->path;
- for (auto &catalog_uptr : catalogs_.values()) {
+ for (auto &catalog_uptr : catalog_collection_->catalogs_.values()) {
AssetCatalog *cat = catalog_uptr.get();
- if (!cat->is_contained_in(old_cat_path)) {
+
+ const AssetCatalogPath new_path = cat->path.rebase(old_cat_path, new_catalog_path);
+ if (!new_path) {
continue;
}
+ cat->path = new_path;
+ cat->simple_name_refresh();
- const CatalogPath path_suffix = cat->path.substr(old_cat_path.length());
- cat->path = new_catalog_path + path_suffix;
+ /* TODO(Sybren): go over all assets that are assigned to this catalog, defined in the current
+ * blend file, and update the catalog simple name stored there. */
}
this->rebuild_tree();
}
-AssetCatalog *AssetCatalogService::create_catalog(const CatalogPath &catalog_path)
+AssetCatalog *AssetCatalogService::create_catalog(const AssetCatalogPath &catalog_path)
{
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path(catalog_path);
+ catalog->flags.has_unsaved_changes = true;
/* So we can std::move(catalog) and still use the non-owning pointer: */
AssetCatalog *const catalog_ptr = catalog.get();
@@ -136,20 +279,18 @@ AssetCatalog *AssetCatalogService::create_catalog(const CatalogPath &catalog_pat
/* TODO(@sybren): move the `AssetCatalog::from_path()` function to another place, that can reuse
* catalogs when a catalog with the given path is already known, and avoid duplicate catalog IDs.
*/
- BLI_assert_msg(!catalogs_.contains(catalog->catalog_id), "duplicate catalog ID not supported");
- catalogs_.add_new(catalog->catalog_id, std::move(catalog));
+ BLI_assert_msg(!catalog_collection_->catalogs_.contains(catalog->catalog_id),
+ "duplicate catalog ID not supported");
+ catalog_collection_->catalogs_.add_new(catalog->catalog_id, std::move(catalog));
- if (catalog_definition_file_) {
+ if (catalog_collection_->catalog_definition_file_) {
/* Ensure the new catalog gets written to disk at some point. If there is no CDF in memory yet,
* it's enough to have the catalog known to the service as it'll be saved to a new file. */
- catalog_definition_file_->add_new(catalog_ptr);
+ catalog_collection_->catalog_definition_file_->add_new(catalog_ptr);
}
- /* The tree may not exist; this happens when no catalog definition file has been loaded yet. When
- * the tree is created any in-memory catalogs will be added, so it doesn't need to happen now. */
- if (catalog_tree_) {
- catalog_tree_->insert_item(*catalog_ptr);
- }
+ BLI_assert_msg(catalog_tree_, "An Asset Catalog tree should always exist.");
+ catalog_tree_->insert_item(*catalog_ptr);
return catalog_ptr;
}
@@ -173,7 +314,8 @@ void AssetCatalogService::load_from_disk(const CatalogFilePath &file_or_director
{
BLI_stat_t status;
if (BLI_stat(file_or_directory_path.data(), &status) == -1) {
- // TODO(@sybren): throw an appropriate exception.
+ /* TODO(@sybren): throw an appropriate exception. */
+ CLOG_WARN(&LOG, "path not found: %s", file_or_directory_path.data());
return;
}
@@ -184,22 +326,23 @@ void AssetCatalogService::load_from_disk(const CatalogFilePath &file_or_director
load_directory_recursive(file_or_directory_path);
}
else {
- // TODO(@sybren): throw an appropriate exception.
+ /* TODO(@sybren): throw an appropriate exception. */
}
/* TODO: Should there be a sanitize step? E.g. to remove catalogs with identical paths? */
- catalog_tree_ = read_into_tree();
+ rebuild_tree();
}
void AssetCatalogService::load_directory_recursive(const CatalogFilePath &directory_path)
{
- // TODO(@sybren): implement proper multi-file support. For now, just load
- // the default file if it is there.
+ /* TODO(@sybren): implement proper multi-file support. For now, just load
+ * the default file if it is there. */
CatalogFilePath file_path = asset_definition_default_file_path_from_dir(directory_path);
if (!BLI_exists(file_path.data())) {
/* No file to be loaded is perfectly fine. */
+ CLOG_INFO(&LOG, 2, "path not found: %s", file_path.data());
return;
}
@@ -213,9 +356,9 @@ void AssetCatalogService::load_single_file(const CatalogFilePath &catalog_defini
std::unique_ptr<AssetCatalogDefinitionFile> cdf = parse_catalog_file(
catalog_definition_file_path);
- BLI_assert_msg(!this->catalog_definition_file_,
+ BLI_assert_msg(!catalog_collection_->catalog_definition_file_,
"Only loading of a single catalog definition file is supported.");
- this->catalog_definition_file_ = std::move(cdf);
+ catalog_collection_->catalog_definition_file_ = std::move(cdf);
}
std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogService::parse_catalog_file(
@@ -224,18 +367,23 @@ std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogService::parse_catalog_f
auto cdf = std::make_unique<AssetCatalogDefinitionFile>();
cdf->file_path = catalog_definition_file_path;
- auto catalog_parsed_callback = [this, catalog_definition_file_path](
+ /* TODO(Sybren): this might have to move to a higher level when supporting multiple CDFs. */
+ Set<AssetCatalogPath> seen_paths;
+
+ auto catalog_parsed_callback = [this, catalog_definition_file_path, &seen_paths](
std::unique_ptr<AssetCatalog> catalog) {
- if (this->catalogs_.contains(catalog->catalog_id)) {
- // TODO(@sybren): apparently another CDF was already loaded. This is not supported yet.
+ if (catalog_collection_->catalogs_.contains(catalog->catalog_id)) {
+ /* TODO(@sybren): apparently another CDF was already loaded. This is not supported yet. */
std::cerr << catalog_definition_file_path << ": multiple definitions of catalog "
<< catalog->catalog_id << " in multiple files, ignoring this one." << std::endl;
/* Don't store 'catalog'; unique_ptr will free its memory. */
return false;
}
+ catalog->flags.is_first_loaded = seen_paths.add(catalog->path);
+
/* The AssetCatalog pointer is now owned by the AssetCatalogService. */
- this->catalogs_.add_new(catalog->catalog_id, std::move(catalog));
+ catalog_collection_->catalogs_.add_new(catalog->catalog_id, std::move(catalog));
return true;
};
@@ -244,57 +392,125 @@ std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogService::parse_catalog_f
return cdf;
}
-void AssetCatalogService::merge_from_disk_before_writing()
+void AssetCatalogService::reload_catalogs()
{
/* TODO(Sybren): expand to support multiple CDFs. */
-
- if (!catalog_definition_file_ || catalog_definition_file_->file_path.empty() ||
- !BLI_is_file(catalog_definition_file_->file_path.c_str())) {
+ AssetCatalogDefinitionFile *const cdf = catalog_collection_->catalog_definition_file_.get();
+ if (!cdf || cdf->file_path.empty() || !BLI_is_file(cdf->file_path.c_str())) {
return;
}
- auto catalog_parsed_callback = [this](std::unique_ptr<AssetCatalog> catalog) {
- const bUUID catalog_id = catalog->catalog_id;
+ /* Keeps track of the catalog IDs that are seen in the CDF, so that we also know what was deleted
+ * from the file on disk. */
+ Set<CatalogID> cats_in_file;
- /* The following two conditions could be or'ed together. Keeping them separated helps when
- * adding debug prints, breakpoints, etc. */
- if (this->catalogs_.contains(catalog_id)) {
- /* This catalog was already seen, so just ignore it. */
- return false;
- }
- if (this->deleted_catalogs_.contains(catalog_id)) {
- /* This catalog was already seen and subsequently deleted, so just ignore it. */
+ auto catalog_parsed_callback = [this, &cats_in_file](std::unique_ptr<AssetCatalog> catalog) {
+ const CatalogID catalog_id = catalog->catalog_id;
+ cats_in_file.add(catalog_id);
+
+ const bool should_skip = is_catalog_known_with_unsaved_changes(catalog_id);
+ if (should_skip) {
+ /* Do not overwrite unsaved local changes. */
return false;
}
- /* This is a new catalog, so let's keep it around. */
- this->catalogs_.add_new(catalog_id, std::move(catalog));
+ /* This is either a new catalog, or we can just replace the in-memory one with the newly loaded
+ * one. */
+ catalog_collection_->catalogs_.add_overwrite(catalog_id, std::move(catalog));
return true;
};
- catalog_definition_file_->parse_catalog_file(catalog_definition_file_->file_path,
- catalog_parsed_callback);
+ cdf->parse_catalog_file(cdf->file_path, catalog_parsed_callback);
+ this->purge_catalogs_not_listed(cats_in_file);
+ this->rebuild_tree();
+}
+
+void AssetCatalogService::purge_catalogs_not_listed(const Set<CatalogID> &catalogs_to_keep)
+{
+ Set<CatalogID> cats_to_remove;
+ for (CatalogID cat_id : this->catalog_collection_->catalogs_.keys()) {
+ if (catalogs_to_keep.contains(cat_id)) {
+ continue;
+ }
+ if (is_catalog_known_with_unsaved_changes(cat_id)) {
+ continue;
+ }
+ /* This catalog is not on disk, but also not modified, so get rid of it. */
+ cats_to_remove.add(cat_id);
+ }
+
+ for (CatalogID cat_id : cats_to_remove) {
+ delete_catalog_by_id_hard(cat_id);
+ }
+}
+
+bool AssetCatalogService::is_catalog_known_with_unsaved_changes(const CatalogID catalog_id) const
+{
+ if (catalog_collection_->deleted_catalogs_.contains(catalog_id)) {
+ /* Deleted catalogs are always considered modified, by definition. */
+ return true;
+ }
+
+ const std::unique_ptr<AssetCatalog> *catalog_uptr_ptr =
+ catalog_collection_->catalogs_.lookup_ptr(catalog_id);
+ if (!catalog_uptr_ptr) {
+ /* Catalog is unknown. */
+ return false;
+ }
+
+ const bool has_unsaved_changes = (*catalog_uptr_ptr)->flags.has_unsaved_changes;
+ return has_unsaved_changes;
}
-bool AssetCatalogService::write_to_disk_on_blendfile_save(const CatalogFilePath &blend_file_path)
+bool AssetCatalogService::write_to_disk(const CatalogFilePath &blend_file_path)
+{
+ if (!write_to_disk_ex(blend_file_path)) {
+ return false;
+ }
+
+ untag_has_unsaved_changes();
+ rebuild_tree();
+ return true;
+}
+
+bool AssetCatalogService::write_to_disk_ex(const CatalogFilePath &blend_file_path)
{
/* TODO(Sybren): expand to support multiple CDFs. */
/* - Already loaded a CDF from disk? -> Always write to that file. */
- if (this->catalog_definition_file_) {
- merge_from_disk_before_writing();
- return catalog_definition_file_->write_to_disk();
+ if (catalog_collection_->catalog_definition_file_) {
+ reload_catalogs();
+ return catalog_collection_->catalog_definition_file_->write_to_disk();
}
- if (catalogs_.is_empty() && deleted_catalogs_.is_empty()) {
+ if (catalog_collection_->catalogs_.is_empty() &&
+ catalog_collection_->deleted_catalogs_.is_empty()) {
/* Avoid saving anything, when there is nothing to save. */
return true; /* Writing nothing when there is nothing to write is still a success. */
}
const CatalogFilePath cdf_path_to_write = find_suitable_cdf_path_for_writing(blend_file_path);
- this->catalog_definition_file_ = construct_cdf_in_memory(cdf_path_to_write);
- merge_from_disk_before_writing();
- return catalog_definition_file_->write_to_disk();
+ catalog_collection_->catalog_definition_file_ = construct_cdf_in_memory(cdf_path_to_write);
+ reload_catalogs();
+ return catalog_collection_->catalog_definition_file_->write_to_disk();
+}
+
+void AssetCatalogService::prepare_to_merge_on_write()
+{
+ /* TODO(Sybren): expand to support multiple CDFs. */
+
+ if (!catalog_collection_->catalog_definition_file_) {
+ /* There is no CDF connected, so it's a no-op. */
+ return;
+ }
+
+ /* Remove any association with the CDF, so that a new location will be chosen
+ * when the blend file is saved. */
+ catalog_collection_->catalog_definition_file_.reset();
+
+ /* Mark all in-memory catalogs as "dirty", to force them to be kept around on
+ * the next "load-merge-write" cycle. */
+ tag_all_catalogs_as_unsaved_changes();
}
CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing(
@@ -304,31 +520,26 @@ CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing(
"A non-empty .blend file path is required to be able to determine where the "
"catalog definition file should be put");
+ /* Ask the asset library API for an appropriate location. */
+ char suitable_root_path[PATH_MAX];
+ const bool asset_lib_root_found = BKE_asset_library_find_suitable_root_path_from_path(
+ blend_file_path.c_str(), suitable_root_path);
+ if (asset_lib_root_found) {
+ char asset_lib_cdf_path[PATH_MAX];
+ BLI_path_join(asset_lib_cdf_path,
+ sizeof(asset_lib_cdf_path),
+ suitable_root_path,
+ DEFAULT_CATALOG_FILENAME.c_str(),
+ NULL);
+ return asset_lib_cdf_path;
+ }
+
/* Determine the default CDF path in the same directory of the blend file. */
char blend_dir_path[PATH_MAX];
BLI_split_dir_part(blend_file_path.c_str(), blend_dir_path, sizeof(blend_dir_path));
const CatalogFilePath cdf_path_next_to_blend = asset_definition_default_file_path_from_dir(
blend_dir_path);
-
- if (BLI_exists(cdf_path_next_to_blend.c_str())) {
- /* - The directory containing the blend file has a blender_assets.cats.txt file?
- * -> Merge with & write to that file. */
- return cdf_path_next_to_blend;
- }
-
- /* - There's no definition file next to the .blend file.
- * -> Ask the asset library API for an appropriate location. */
- char suitable_root_path[PATH_MAX];
- BKE_asset_library_find_suitable_root_path_from_path(blend_file_path.c_str(),
- suitable_root_path);
- char asset_lib_cdf_path[PATH_MAX];
- BLI_path_join(asset_lib_cdf_path,
- sizeof(asset_lib_cdf_path),
- suitable_root_path,
- DEFAULT_CATALOG_FILENAME.c_str(),
- NULL);
-
- return asset_lib_cdf_path;
+ return cdf_path_next_to_blend;
}
std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogService::construct_cdf_in_memory(
@@ -337,19 +548,24 @@ std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogService::construct_cdf_i
auto cdf = std::make_unique<AssetCatalogDefinitionFile>();
cdf->file_path = file_path;
- for (auto &catalog : catalogs_.values()) {
+ for (auto &catalog : catalog_collection_->catalogs_.values()) {
cdf->add_new(catalog.get());
}
return cdf;
}
+AssetCatalogTree *AssetCatalogService::get_catalog_tree()
+{
+ return catalog_tree_.get();
+}
+
std::unique_ptr<AssetCatalogTree> AssetCatalogService::read_into_tree()
{
auto tree = std::make_unique<AssetCatalogTree>();
/* Go through the catalogs, insert each path component into the tree where needed. */
- for (auto &catalog : catalogs_.values()) {
+ for (auto &catalog : catalog_collection_->catalogs_.values()) {
tree->insert_item(*catalog);
}
@@ -358,15 +574,122 @@ std::unique_ptr<AssetCatalogTree> AssetCatalogService::read_into_tree()
void AssetCatalogService::rebuild_tree()
{
+ create_missing_catalogs();
this->catalog_tree_ = read_into_tree();
}
+void AssetCatalogService::create_missing_catalogs()
+{
+ /* Construct an ordered set of paths to check, so that parents are ordered before children. */
+ std::set<AssetCatalogPath> paths_to_check;
+ for (auto &catalog : catalog_collection_->catalogs_.values()) {
+ paths_to_check.insert(catalog->path);
+ }
+
+ std::set<AssetCatalogPath> seen_paths;
+ /* The empty parent should never be created, so always be considered "seen". */
+ seen_paths.insert(AssetCatalogPath(""));
+
+ /* Find and create missing direct parents (so ignoring parents-of-parents). */
+ while (!paths_to_check.empty()) {
+ /* Pop the first path of the queue. */
+ const AssetCatalogPath path = *paths_to_check.begin();
+ paths_to_check.erase(paths_to_check.begin());
+
+ if (seen_paths.find(path) != seen_paths.end()) {
+ /* This path has been seen already, so it can be ignored. */
+ continue;
+ }
+ seen_paths.insert(path);
+
+ const AssetCatalogPath parent_path = path.parent();
+ if (seen_paths.find(parent_path) != seen_paths.end()) {
+ /* The parent exists, continue to the next path. */
+ continue;
+ }
+
+ /* The parent doesn't exist, so create it and queue it up for checking its parent. */
+ AssetCatalog *parent_catalog = create_catalog(parent_path);
+ parent_catalog->flags.has_unsaved_changes = true;
+
+ paths_to_check.insert(parent_path);
+ }
+
+ /* TODO(Sybren): bind the newly created catalogs to a CDF, if we know about it. */
+}
+
+bool AssetCatalogService::is_undo_possbile() const
+{
+ return !undo_snapshots_.is_empty();
+}
+
+bool AssetCatalogService::is_redo_possbile() const
+{
+ return !redo_snapshots_.is_empty();
+}
+
+void AssetCatalogService::undo()
+{
+ BLI_assert_msg(is_undo_possbile(), "Undo stack is empty");
+
+ redo_snapshots_.append(std::move(catalog_collection_));
+ catalog_collection_ = undo_snapshots_.pop_last();
+ rebuild_tree();
+}
+
+void AssetCatalogService::redo()
+{
+ BLI_assert_msg(is_redo_possbile(), "Redo stack is empty");
+
+ undo_snapshots_.append(std::move(catalog_collection_));
+ catalog_collection_ = redo_snapshots_.pop_last();
+ rebuild_tree();
+}
+
+void AssetCatalogService::undo_push()
+{
+ std::unique_ptr<AssetCatalogCollection> snapshot = catalog_collection_->deep_copy();
+ undo_snapshots_.append(std::move(snapshot));
+ redo_snapshots_.clear();
+}
+
+/* ---------------------------------------------------------------------- */
+
+std::unique_ptr<AssetCatalogCollection> AssetCatalogCollection::deep_copy() const
+{
+ auto copy = std::make_unique<AssetCatalogCollection>();
+
+ copy->has_unsaved_changes_ = this->has_unsaved_changes_;
+ copy->catalogs_ = copy_catalog_map(this->catalogs_);
+ copy->deleted_catalogs_ = copy_catalog_map(this->deleted_catalogs_);
+
+ if (catalog_definition_file_) {
+ copy->catalog_definition_file_ = catalog_definition_file_->copy_and_remap(
+ copy->catalogs_, copy->deleted_catalogs_);
+ }
+
+ return copy;
+}
+
+OwningAssetCatalogMap AssetCatalogCollection::copy_catalog_map(const OwningAssetCatalogMap &orig)
+{
+ OwningAssetCatalogMap copy;
+
+ for (const auto &orig_catalog_uptr : orig.values()) {
+ auto copy_catalog_uptr = std::make_unique<AssetCatalog>(*orig_catalog_uptr);
+ copy.add_new(copy_catalog_uptr->catalog_id, std::move(copy_catalog_uptr));
+ }
+
+ return copy;
+}
+
/* ---------------------------------------------------------------------- */
AssetCatalogTreeItem::AssetCatalogTreeItem(StringRef name,
CatalogID catalog_id,
+ StringRef simple_name,
const AssetCatalogTreeItem *parent)
- : name_(name), catalog_id_(catalog_id), parent_(parent)
+ : name_(name), catalog_id_(catalog_id), simple_name_(simple_name), parent_(parent)
{
}
@@ -375,16 +698,25 @@ CatalogID AssetCatalogTreeItem::get_catalog_id() const
return catalog_id_;
}
-StringRef AssetCatalogTreeItem::get_name() const
+StringRefNull AssetCatalogTreeItem::get_name() const
{
return name_;
}
-CatalogPath AssetCatalogTreeItem::catalog_path() const
+StringRefNull AssetCatalogTreeItem::get_simple_name() const
+{
+ return simple_name_;
+}
+bool AssetCatalogTreeItem::has_unsaved_changes() const
+{
+ return has_unsaved_changes_;
+}
+
+AssetCatalogPath AssetCatalogTreeItem::catalog_path() const
{
- std::string current_path = name_;
+ AssetCatalogPath current_path = name_;
for (const AssetCatalogTreeItem *parent = parent_; parent; parent = parent->parent_) {
- current_path = parent->name_ + AssetCatalogService::PATH_SEPARATOR + current_path;
+ current_path = AssetCatalogPath(parent->name_) / current_path;
}
return current_path;
}
@@ -403,34 +735,24 @@ bool AssetCatalogTreeItem::has_children() const
return !children_.empty();
}
-/* ---------------------------------------------------------------------- */
-
-/**
- * Iterate over path components, calling \a callback for each component. E.g. "just/some/path"
- * iterates over "just", then "some" then "path".
- */
-static void iterate_over_catalog_path_components(
- const CatalogPath &path,
- FunctionRef<void(StringRef component_name, bool is_last_component)> callback)
+void AssetCatalogTreeItem::foreach_item_recursive(AssetCatalogTreeItem::ChildMap &children,
+ const ItemIterFn callback)
{
- const char *next_slash_ptr;
-
- for (const char *path_component = path.data(); path_component && path_component[0];
- /* Jump to one after the next slash if there is any. */
- path_component = next_slash_ptr ? next_slash_ptr + 1 : nullptr) {
- next_slash_ptr = BLI_path_slash_find(path_component);
-
- const bool is_last_component = next_slash_ptr == nullptr;
- /* Note that this won't be null terminated. */
- const StringRef component_name = is_last_component ?
- path_component :
- StringRef(path_component,
- next_slash_ptr - path_component);
+ for (auto &[key, item] : children) {
+ callback(item);
+ foreach_item_recursive(item.children_, callback);
+ }
+}
- callback(component_name, is_last_component);
+void AssetCatalogTreeItem::foreach_child(const ItemIterFn callback)
+{
+ for (auto &[key, item] : children_) {
+ callback(item);
}
}
+/* ---------------------------------------------------------------------- */
+
void AssetCatalogTree::insert_item(const AssetCatalog &catalog)
{
const AssetCatalogTreeItem *parent = nullptr;
@@ -438,30 +760,34 @@ void AssetCatalogTree::insert_item(const AssetCatalog &catalog)
* added to (if not there yet). */
AssetCatalogTreeItem::ChildMap *current_item_children = &root_items_;
- BLI_assert_msg(!ELEM(catalog.path[0], '/', '\\'),
+ BLI_assert_msg(!ELEM(catalog.path.str()[0], '/', '\\'),
"Malformed catalog path; should not start with a separator");
const CatalogID nil_id{};
- iterate_over_catalog_path_components(
- catalog.path, [&](StringRef component_name, const bool is_last_component) {
- /* Insert new tree element - if no matching one is there yet! */
- auto [key_and_item, was_inserted] = current_item_children->emplace(
- component_name,
- AssetCatalogTreeItem(
- component_name, is_last_component ? catalog.catalog_id : nil_id, parent));
- AssetCatalogTreeItem &item = key_and_item->second;
-
- /* If full path of this catalog already exists as parent path of a previously read catalog,
- * we can ensure this tree item's UUID is set here. */
- if (is_last_component && BLI_uuid_is_nil(item.catalog_id_)) {
- item.catalog_id_ = catalog.catalog_id;
- }
+ catalog.path.iterate_components([&](StringRef component_name, const bool is_last_component) {
+ /* Insert new tree element - if no matching one is there yet! */
+ auto [key_and_item, was_inserted] = current_item_children->emplace(
+ component_name,
+ AssetCatalogTreeItem(component_name,
+ is_last_component ? catalog.catalog_id : nil_id,
+ is_last_component ? catalog.simple_name : "",
+ parent));
+ AssetCatalogTreeItem &item = key_and_item->second;
+
+ /* If full path of this catalog already exists as parent path of a previously read catalog,
+ * we can ensure this tree item's UUID is set here. */
+ if (is_last_component) {
+ if (BLI_uuid_is_nil(item.catalog_id_) || catalog.flags.is_first_loaded) {
+ item.catalog_id_ = catalog.catalog_id;
+ }
+ item.has_unsaved_changes_ = catalog.flags.has_unsaved_changes;
+ }
- /* Walk further into the path (no matter if a new item was created or not). */
- parent = &item;
- current_item_children = &item.children_;
- });
+ /* Walk further into the path (no matter if a new item was created or not). */
+ parent = &item;
+ current_item_children = &item.children_;
+ });
}
void AssetCatalogTree::foreach_item(AssetCatalogTreeItem::ItemIterFn callback)
@@ -469,15 +795,6 @@ void AssetCatalogTree::foreach_item(AssetCatalogTreeItem::ItemIterFn callback)
AssetCatalogTreeItem::foreach_item_recursive(root_items_, callback);
}
-void AssetCatalogTreeItem::foreach_item_recursive(AssetCatalogTreeItem::ChildMap &children,
- const ItemIterFn callback)
-{
- for (auto &[key, item] : children) {
- callback(item);
- foreach_item_recursive(item.children_, callback);
- }
-}
-
void AssetCatalogTree::foreach_root_item(const ItemIterFn callback)
{
for (auto &[key, item] : root_items_) {
@@ -485,17 +802,9 @@ void AssetCatalogTree::foreach_root_item(const ItemIterFn callback)
}
}
-void AssetCatalogTreeItem::foreach_child(const ItemIterFn callback)
-{
- for (auto &[key, item] : children_) {
- callback(item);
- }
-}
+/* ---------------------------------------------------------------------- */
-AssetCatalogTree *AssetCatalogService::get_catalog_tree()
-{
- return catalog_tree_.get();
-}
+/* ---------------------------------------------------------------------- */
bool AssetCatalogDefinitionFile::contains(const CatalogID catalog_id) const
{
@@ -507,12 +816,26 @@ void AssetCatalogDefinitionFile::add_new(AssetCatalog *catalog)
catalogs_.add_new(catalog->catalog_id, catalog);
}
+void AssetCatalogDefinitionFile::add_overwrite(AssetCatalog *catalog)
+{
+ catalogs_.add_overwrite(catalog->catalog_id, catalog);
+}
+
+void AssetCatalogDefinitionFile::forget(CatalogID catalog_id)
+{
+ catalogs_.remove(catalog_id);
+}
+
void AssetCatalogDefinitionFile::parse_catalog_file(
const CatalogFilePath &catalog_definition_file_path,
AssetCatalogParsedFn catalog_loaded_callback)
{
- std::fstream infile(catalog_definition_file_path);
+ fstream infile(catalog_definition_file_path, std::ios::in);
+ if (!infile.is_open()) {
+ CLOG_ERROR(&LOG, "%s: unable to open file", catalog_definition_file_path.c_str());
+ return;
+ }
bool seen_version_number = false;
std::string line;
while (std::getline(infile, line)) {
@@ -544,16 +867,8 @@ void AssetCatalogDefinitionFile::parse_catalog_file(
continue;
}
- if (this->contains(non_owning_ptr->catalog_id)) {
- std::cerr << catalog_definition_file_path << ": multiple definitions of catalog "
- << non_owning_ptr->catalog_id << " in the same file, using first occurrence."
- << std::endl;
- /* Don't store 'catalog'; unique_ptr will free its memory. */
- continue;
- }
-
/* The AssetDefinitionFile should include this catalog when writing it back to disk. */
- this->add_new(non_owning_ptr);
+ this->add_overwrite(non_owning_ptr);
}
}
@@ -592,7 +907,7 @@ std::unique_ptr<AssetCatalog> AssetCatalogDefinitionFile::parse_catalog_line(con
const StringRef path_and_simple_name = line.substr(first_delim + 1);
const int64_t second_delim = path_and_simple_name.find_first_of(delim);
- CatalogPath catalog_path;
+ std::string path_in_file;
std::string simple_name;
if (second_delim == 0) {
/* Delimiter as first character means there is no path. These lines are to be ignored. */
@@ -601,16 +916,16 @@ std::unique_ptr<AssetCatalog> AssetCatalogDefinitionFile::parse_catalog_line(con
if (second_delim == StringRef::not_found) {
/* No delimiter means no simple name, just treat it as all "path". */
- catalog_path = path_and_simple_name;
+ path_in_file = path_and_simple_name;
simple_name = "";
}
else {
- catalog_path = path_and_simple_name.substr(0, second_delim);
+ path_in_file = path_and_simple_name.substr(0, second_delim);
simple_name = path_and_simple_name.substr(second_delim + 1).trim();
}
- catalog_path = AssetCatalog::cleanup_path(catalog_path);
- return std::make_unique<AssetCatalog>(catalog_id, catalog_path, simple_name);
+ AssetCatalogPath catalog_path = path_in_file;
+ return std::make_unique<AssetCatalog>(catalog_id, catalog_path.cleanup(), simple_name);
}
bool AssetCatalogDefinitionFile::write_to_disk() const
@@ -651,18 +966,18 @@ bool AssetCatalogDefinitionFile::write_to_disk_unsafe(const CatalogFilePath &des
return false;
}
- std::ofstream output(dest_file_path);
+ fstream output(dest_file_path, std::ios::out);
- // TODO(@sybren): remember the line ending style that was originally read, then use that to write
- // the file again.
+ /* TODO(@sybren): remember the line ending style that was originally read, then use that to write
+ * the file again. */
- // Write the header.
+ /* Write the header. */
output << HEADER;
output << "" << std::endl;
output << VERSION_MARKER << SUPPORTED_VERSION << std::endl;
output << "" << std::endl;
- // Write the catalogs, ordered by path (primary) and UUID (secondary).
+ /* Write the catalogs, ordered by path (primary) and UUID (secondary). */
AssetCatalogOrderedSet catalogs_by_path;
for (const AssetCatalog *catalog : catalogs_.values()) {
if (catalog->flags.is_deleted) {
@@ -715,26 +1030,59 @@ bool AssetCatalogDefinitionFile::ensure_directory_exists(
return true;
}
+std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogDefinitionFile::copy_and_remap(
+ const OwningAssetCatalogMap &catalogs, const OwningAssetCatalogMap &deleted_catalogs) const
+{
+ auto copy = std::make_unique<AssetCatalogDefinitionFile>(*this);
+ copy->catalogs_.clear();
+
+ /* Remap pointers of the copy from the original AssetCatalogCollection to the given one. */
+ for (CatalogID catalog_id : catalogs_.keys()) {
+ /* The catalog can be in the regular or the deleted map. */
+ const std::unique_ptr<AssetCatalog> *remapped_catalog_uptr_ptr = catalogs.lookup_ptr(
+ catalog_id);
+ if (remapped_catalog_uptr_ptr) {
+ copy->catalogs_.add_new(catalog_id, remapped_catalog_uptr_ptr->get());
+ continue;
+ }
+
+ remapped_catalog_uptr_ptr = deleted_catalogs.lookup_ptr(catalog_id);
+ if (remapped_catalog_uptr_ptr) {
+ copy->catalogs_.add_new(catalog_id, remapped_catalog_uptr_ptr->get());
+ continue;
+ }
+
+ BLI_assert(!"A CDF should only reference known catalogs.");
+ }
+
+ return copy;
+}
+
AssetCatalog::AssetCatalog(const CatalogID catalog_id,
- const CatalogPath &path,
+ const AssetCatalogPath &path,
const std::string &simple_name)
: catalog_id(catalog_id), path(path), simple_name(simple_name)
{
}
-std::unique_ptr<AssetCatalog> AssetCatalog::from_path(const CatalogPath &path)
+std::unique_ptr<AssetCatalog> AssetCatalog::from_path(const AssetCatalogPath &path)
{
- const CatalogPath clean_path = cleanup_path(path);
+ const AssetCatalogPath clean_path = path.cleanup();
const CatalogID cat_id = BLI_uuid_generate_random();
const std::string simple_name = sensible_simple_name_for_path(clean_path);
auto catalog = std::make_unique<AssetCatalog>(cat_id, clean_path, simple_name);
return catalog;
}
-std::string AssetCatalog::sensible_simple_name_for_path(const CatalogPath &path)
+void AssetCatalog::simple_name_refresh()
+{
+ this->simple_name = sensible_simple_name_for_path(this->path);
+}
+
+std::string AssetCatalog::sensible_simple_name_for_path(const AssetCatalogPath &path)
{
- std::string name = path;
- std::replace(name.begin(), name.end(), AssetCatalogService::PATH_SEPARATOR, '-');
+ std::string name = path.str();
+ std::replace(name.begin(), name.end(), AssetCatalogPath::SEPARATOR, '-');
if (name.length() < MAX_NAME - 1) {
return name;
}
@@ -744,33 +1092,24 @@ std::string AssetCatalog::sensible_simple_name_for_path(const CatalogPath &path)
return "..." + name.substr(name.length() - 60);
}
-CatalogPath AssetCatalog::cleanup_path(const CatalogPath &path)
+AssetCatalogFilter::AssetCatalogFilter(Set<CatalogID> &&matching_catalog_ids,
+ Set<CatalogID> &&known_catalog_ids)
+ : matching_catalog_ids(std::move(matching_catalog_ids)),
+ known_catalog_ids(std::move(known_catalog_ids))
{
- /* TODO(@sybren): maybe go over each element of the path, and trim those? */
- CatalogPath clean_path = StringRef(path).trim().trim(AssetCatalogService::PATH_SEPARATOR).trim();
- return clean_path;
}
-bool AssetCatalog::is_contained_in(const CatalogPath &other_path) const
+bool AssetCatalogFilter::contains(const CatalogID asset_catalog_id) const
{
- if (other_path.empty()) {
- return true;
- }
-
- if (this->path == other_path) {
- return true;
- }
+ return matching_catalog_ids.contains(asset_catalog_id);
+}
- /* To be a child path of 'other_path', our path must be at least a separator and another
- * character longer. */
- if (this->path.length() < other_path.length() + 2) {
+bool AssetCatalogFilter::is_known(const CatalogID asset_catalog_id) const
+{
+ if (BLI_uuid_is_nil(asset_catalog_id)) {
return false;
}
-
- const StringRef this_path(this->path);
- const bool prefix_ok = this_path.startswith(other_path);
- const char next_char = this_path[other_path.length()];
- return prefix_ok && next_char == AssetCatalogService::PATH_SEPARATOR;
+ return known_catalog_ids.contains(asset_catalog_id);
}
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/asset_catalog_path.cc b/source/blender/blenkernel/intern/asset_catalog_path.cc
new file mode 100644
index 00000000000..d789150dba5
--- /dev/null
+++ b/source/blender/blenkernel/intern/asset_catalog_path.cc
@@ -0,0 +1,238 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_asset_catalog_path.hh"
+
+#include "BLI_path_util.h"
+
+namespace blender::bke {
+
+const char AssetCatalogPath::SEPARATOR = '/';
+
+AssetCatalogPath::AssetCatalogPath(const std::string &path) : path_(path)
+{
+}
+
+AssetCatalogPath::AssetCatalogPath(StringRef path) : path_(path)
+{
+}
+
+AssetCatalogPath::AssetCatalogPath(const char *path) : path_(path)
+{
+}
+
+AssetCatalogPath::AssetCatalogPath(AssetCatalogPath &&other_path) noexcept
+ : path_(std::move(other_path.path_))
+{
+}
+
+uint64_t AssetCatalogPath::hash() const
+{
+ std::hash<std::string> hasher{};
+ return hasher(this->path_);
+}
+
+uint64_t AssetCatalogPath::length() const
+{
+ return this->path_.length();
+}
+
+const char *AssetCatalogPath::c_str() const
+{
+ return this->path_.c_str();
+}
+
+const std::string &AssetCatalogPath::str() const
+{
+ return this->path_;
+}
+
+StringRefNull AssetCatalogPath::name() const
+{
+ const size_t last_sep_index = this->path_.rfind(SEPARATOR);
+ if (last_sep_index == std::string::npos) {
+ return StringRefNull(this->path_);
+ }
+
+ return StringRefNull(this->path_.c_str() + last_sep_index + 1);
+}
+
+bool AssetCatalogPath::operator==(const AssetCatalogPath &other_path) const
+{
+ return this->path_ == other_path.path_;
+}
+
+bool AssetCatalogPath::operator!=(const AssetCatalogPath &other_path) const
+{
+ return !(*this == other_path);
+}
+
+bool AssetCatalogPath::operator<(const AssetCatalogPath &other_path) const
+{
+ return this->path_ < other_path.path_;
+}
+
+AssetCatalogPath AssetCatalogPath::operator/(const AssetCatalogPath &path_to_append) const
+{
+ /* `"" / "path"` or `"path" / ""` should just result in `"path"` */
+ if (!*this) {
+ return path_to_append;
+ }
+ if (!path_to_append) {
+ return *this;
+ }
+
+ std::stringstream new_path;
+ new_path << this->path_ << SEPARATOR << path_to_append.path_;
+ return AssetCatalogPath(new_path.str());
+}
+
+AssetCatalogPath::operator bool() const
+{
+ return !this->path_.empty();
+}
+
+std::ostream &operator<<(std::ostream &stream, const AssetCatalogPath &path_to_append)
+{
+ stream << path_to_append.path_;
+ return stream;
+}
+
+AssetCatalogPath AssetCatalogPath::cleanup() const
+{
+ std::stringstream clean_components;
+ bool first_component_seen = false;
+
+ this->iterate_components([&clean_components, &first_component_seen](StringRef component_name,
+ bool /*is_last_component*/) {
+ const std::string clean_component = cleanup_component(component_name);
+
+ if (clean_component.empty()) {
+ /* These are caused by leading, trailing, or double slashes. */
+ return;
+ }
+
+ /* If a previous path component has been streamed already, we need a path separator. This
+ * cannot use the `is_last_component` boolean, because the last component might be skipped due
+ * to the condition above. */
+ if (first_component_seen) {
+ clean_components << SEPARATOR;
+ }
+ first_component_seen = true;
+
+ clean_components << clean_component;
+ });
+
+ return AssetCatalogPath(clean_components.str());
+}
+
+std::string AssetCatalogPath::cleanup_component(StringRef component)
+{
+ std::string cleaned = component.trim();
+ /* Replace colons with something else, as those are used in the CDF file as delimiter. */
+ std::replace(cleaned.begin(), cleaned.end(), ':', '-');
+ return cleaned;
+}
+
+bool AssetCatalogPath::is_contained_in(const AssetCatalogPath &other_path) const
+{
+ if (!other_path) {
+ /* The empty path contains all other paths. */
+ return true;
+ }
+
+ if (this->path_ == other_path.path_) {
+ /* Weak is-in relation: equal paths contain each other. */
+ return true;
+ }
+
+ /* To be a child path of 'other_path', our path must be at least a separator and another
+ * character longer. */
+ if (this->length() < other_path.length() + 2) {
+ return false;
+ }
+
+ /* Create StringRef to be able to use .startswith(). */
+ const StringRef this_path(this->path_);
+ const bool prefix_ok = this_path.startswith(other_path.path_);
+ const char next_char = this_path[other_path.length()];
+ return prefix_ok && next_char == SEPARATOR;
+}
+
+AssetCatalogPath AssetCatalogPath::parent() const
+{
+ if (!*this) {
+ return AssetCatalogPath("");
+ }
+ std::string::size_type last_sep_index = this->path_.rfind(SEPARATOR);
+ if (last_sep_index == std::string::npos) {
+ return AssetCatalogPath("");
+ }
+ return AssetCatalogPath(this->path_.substr(0, last_sep_index));
+}
+
+void AssetCatalogPath::iterate_components(ComponentIteratorFn callback) const
+{
+ const char *next_slash_ptr;
+
+ for (const char *path_component = this->path_.data(); path_component && path_component[0];
+ /* Jump to one after the next slash if there is any. */
+ path_component = next_slash_ptr ? next_slash_ptr + 1 : nullptr) {
+ /* Note that this also treats backslashes as component separators, which
+ * helps in cleaning up backslash-separated paths. */
+ next_slash_ptr = BLI_path_slash_find(path_component);
+
+ const bool is_last_component = next_slash_ptr == nullptr;
+ /* Note that this won't be null terminated. */
+ const StringRef component_name = is_last_component ?
+ path_component :
+ StringRef(path_component,
+ next_slash_ptr - path_component);
+
+ callback(component_name, is_last_component);
+ }
+}
+
+AssetCatalogPath AssetCatalogPath::rebase(const AssetCatalogPath &from_path,
+ const AssetCatalogPath &to_path) const
+{
+ if (!from_path) {
+ if (!to_path) {
+ return AssetCatalogPath("");
+ }
+ return to_path / *this;
+ }
+
+ if (!this->is_contained_in(from_path)) {
+ return AssetCatalogPath("");
+ }
+
+ if (*this == from_path) {
+ /* Early return, because otherwise the length+1 below is going to cause problems. */
+ return to_path;
+ }
+
+ /* When from_path = "test", we need to skip "test/" to get the rest of the path, hence the +1. */
+ const StringRef suffix = StringRef(this->path_).substr(from_path.length() + 1);
+ const AssetCatalogPath path_suffix(suffix);
+ return to_path / path_suffix;
+}
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/asset_catalog_path_test.cc b/source/blender/blenkernel/intern/asset_catalog_path_test.cc
new file mode 100644
index 00000000000..f248863ce77
--- /dev/null
+++ b/source/blender/blenkernel/intern/asset_catalog_path_test.cc
@@ -0,0 +1,284 @@
+/*
+ * 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) 2020 Blender Foundation
+ * All rights reserved.
+ */
+
+#include "BKE_asset_catalog_path.hh"
+
+#include "BLI_set.hh"
+#include "BLI_vector.hh"
+
+#include <set>
+#include <sstream>
+
+#include "testing/testing.h"
+
+namespace blender::bke::tests {
+
+TEST(AssetCatalogPathTest, construction)
+{
+ AssetCatalogPath default_constructed;
+ /* Use `.str()` to use `std:string`'s comparison operators here, not our own (which are tested
+ * later). */
+ EXPECT_EQ(default_constructed.str(), "");
+
+ /* C++ considers this construction special, it doesn't call the default constructor but does
+ * recursive, member-wise value initialization. See https://stackoverflow.com/a/4982720. */
+ AssetCatalogPath value_initialized = AssetCatalogPath();
+ EXPECT_EQ(value_initialized.str(), "");
+
+ AssetCatalogPath from_char_literal("the/path");
+
+ const std::string str_const = "the/path";
+ AssetCatalogPath from_string_constant(str_const);
+
+ std::string str_variable = "the/path";
+ AssetCatalogPath from_string_variable(str_variable);
+
+ std::string long_string = "this is a long/string/with/a/path in the middle";
+ StringRef long_string_ref(long_string);
+ StringRef middle_bit = long_string_ref.substr(10, 23);
+ AssetCatalogPath from_string_ref(middle_bit);
+ EXPECT_EQ(from_string_ref, "long/string/with/a/path");
+}
+
+TEST(AssetCatalogPathTest, length)
+{
+ const AssetCatalogPath one("1");
+ EXPECT_EQ(1, one.length());
+
+ const AssetCatalogPath empty("");
+ EXPECT_EQ(0, empty.length());
+
+ const AssetCatalogPath utf8("some/родитель");
+ EXPECT_EQ(21, utf8.length()) << "13 characters should be 21 bytes.";
+}
+
+TEST(AssetCatalogPathTest, name)
+{
+ EXPECT_EQ(StringRefNull(""), AssetCatalogPath("").name());
+ EXPECT_EQ(StringRefNull("word"), AssetCatalogPath("word").name());
+ EXPECT_EQ(StringRefNull("Пермь"), AssetCatalogPath("дорога/в/Пермь").name());
+ EXPECT_EQ(StringRefNull("windows\\paths"),
+ AssetCatalogPath("these/are/not/windows\\paths").name());
+}
+
+TEST(AssetCatalogPathTest, comparison_operators)
+{
+ const AssetCatalogPath empty("");
+ const AssetCatalogPath the_path("the/path");
+ const AssetCatalogPath the_path_child("the/path/child");
+ const AssetCatalogPath unrelated_path("unrelated/path");
+ const AssetCatalogPath other_instance_same_path("the/path");
+
+ EXPECT_LT(empty, the_path);
+ EXPECT_LT(the_path, the_path_child);
+ EXPECT_LT(the_path, unrelated_path);
+
+ EXPECT_EQ(empty, empty) << "Identical empty instances should compare equal.";
+ EXPECT_EQ(empty, "") << "Comparison to empty string should be possible.";
+ EXPECT_EQ(the_path, the_path) << "Identical non-empty instances should compare equal.";
+ EXPECT_EQ(the_path, "the/path") << "Comparison to string should be possible.";
+ EXPECT_EQ(the_path, other_instance_same_path)
+ << "Different instances with equal path should compare equal.";
+
+ EXPECT_NE(the_path, the_path_child);
+ EXPECT_NE(the_path, unrelated_path);
+ EXPECT_NE(the_path, empty);
+
+ EXPECT_FALSE(empty);
+ EXPECT_TRUE(the_path);
+}
+
+TEST(AssetCatalogPathTest, move_semantics)
+{
+ AssetCatalogPath source_path("source/path");
+ EXPECT_TRUE(source_path);
+
+ AssetCatalogPath dest_path = std::move(source_path);
+ EXPECT_FALSE(source_path); /* NOLINT: bugprone-use-after-move */
+ EXPECT_TRUE(dest_path);
+}
+
+TEST(AssetCatalogPathTest, concatenation)
+{
+ AssetCatalogPath some_parent("some/родитель");
+ AssetCatalogPath child = some_parent / "ребенок";
+
+ EXPECT_EQ(some_parent, "some/родитель")
+ << "Appending a child path should not modify the parent.";
+ EXPECT_EQ(child, "some/родитель/ребенок");
+
+ AssetCatalogPath appended_compound_path = some_parent / "ребенок/внук";
+ EXPECT_EQ(appended_compound_path, "some/родитель/ребенок/внук");
+
+ AssetCatalogPath empty("");
+ AssetCatalogPath child_of_the_void = empty / "child";
+ EXPECT_EQ(child_of_the_void, "child")
+ << "Appending to an empty path should not create an initial slash.";
+
+ AssetCatalogPath parent_of_the_void = some_parent / empty;
+ EXPECT_EQ(parent_of_the_void, "some/родитель")
+ << "Prepending to an empty path should not create a trailing slash.";
+
+ std::string subpath = "child";
+ AssetCatalogPath concatenated_with_string = some_parent / subpath;
+ EXPECT_EQ(concatenated_with_string, "some/родитель/child");
+}
+
+TEST(AssetCatalogPathTest, hashable)
+{
+ AssetCatalogPath path("heyyyyy");
+
+ std::set<AssetCatalogPath> path_std_set;
+ path_std_set.insert(path);
+
+ blender::Set<AssetCatalogPath> path_blender_set;
+ path_blender_set.add(path);
+}
+
+TEST(AssetCatalogPathTest, stream_operator)
+{
+ AssetCatalogPath path("путь/в/Пермь");
+ std::stringstream sstream;
+ sstream << path;
+ EXPECT_EQ("путь/в/Пермь", sstream.str());
+}
+
+TEST(AssetCatalogPathTest, is_contained_in)
+{
+ const AssetCatalogPath catpath("simple/path/child");
+ EXPECT_FALSE(catpath.is_contained_in("unrelated"));
+ EXPECT_FALSE(catpath.is_contained_in("sim"));
+ EXPECT_FALSE(catpath.is_contained_in("simple/pathx"));
+ EXPECT_FALSE(catpath.is_contained_in("simple/path/c"));
+ EXPECT_FALSE(catpath.is_contained_in("simple/path/child/grandchild"));
+ EXPECT_FALSE(catpath.is_contained_in("simple/path/"))
+ << "Non-normalized paths are not expected to work.";
+
+ EXPECT_TRUE(catpath.is_contained_in(""));
+ EXPECT_TRUE(catpath.is_contained_in("simple"));
+ EXPECT_TRUE(catpath.is_contained_in("simple/path"));
+
+ /* Test with some UTF8 non-ASCII characters. */
+ AssetCatalogPath some_parent("some/родитель");
+ AssetCatalogPath child = some_parent / "ребенок";
+
+ EXPECT_TRUE(child.is_contained_in(some_parent));
+ EXPECT_TRUE(child.is_contained_in("some"));
+
+ AssetCatalogPath appended_compound_path = some_parent / "ребенок/внук";
+ EXPECT_TRUE(appended_compound_path.is_contained_in(some_parent));
+ EXPECT_TRUE(appended_compound_path.is_contained_in(child));
+
+ /* Test "going up" directory-style. */
+ AssetCatalogPath child_with_dotdot = some_parent / "../../other/hierarchy/part";
+ EXPECT_TRUE(child_with_dotdot.is_contained_in(some_parent))
+ << "dotdot path components should have no meaning";
+}
+
+TEST(AssetCatalogPathTest, cleanup)
+{
+ {
+ AssetCatalogPath ugly_path("/ some / родитель / ");
+ AssetCatalogPath clean_path = ugly_path.cleanup();
+ EXPECT_EQ(AssetCatalogPath("/ some / родитель / "), ugly_path)
+ << "cleanup should not modify the path instance itself";
+ EXPECT_EQ(AssetCatalogPath("some/родитель"), clean_path);
+ }
+ {
+ AssetCatalogPath double_slashed("some//родитель");
+ EXPECT_EQ(AssetCatalogPath("some/родитель"), double_slashed.cleanup());
+ }
+ {
+ AssetCatalogPath with_colons("some/key:subkey=value/path");
+ EXPECT_EQ(AssetCatalogPath("some/key-subkey=value/path"), with_colons.cleanup());
+ }
+ {
+ const AssetCatalogPath with_backslashes("windows\\for\\life");
+ EXPECT_EQ(AssetCatalogPath("windows/for/life"), with_backslashes.cleanup());
+ }
+ {
+ const AssetCatalogPath with_mixed("windows\\for/life");
+ EXPECT_EQ(AssetCatalogPath("windows/for/life"), with_mixed.cleanup());
+ }
+ {
+ const AssetCatalogPath with_punctuation("is!/this?/¿valid?");
+ EXPECT_EQ(AssetCatalogPath("is!/this?/¿valid?"), with_punctuation.cleanup());
+ }
+}
+
+TEST(AssetCatalogPathTest, iterate_components)
+{
+ AssetCatalogPath path("путь/в/Пермь");
+ Vector<std::pair<std::string, bool>> seen_components;
+
+ path.iterate_components([&seen_components](StringRef component_name, bool is_last_component) {
+ std::pair<std::string, bool> parameter_pair = std::make_pair<std::string, bool>(
+ component_name, bool(is_last_component));
+ seen_components.append(parameter_pair);
+ });
+
+ ASSERT_EQ(3, seen_components.size());
+
+ EXPECT_EQ("путь", seen_components[0].first);
+ EXPECT_EQ("в", seen_components[1].first);
+ EXPECT_EQ("Пермь", seen_components[2].first);
+
+ EXPECT_FALSE(seen_components[0].second);
+ EXPECT_FALSE(seen_components[1].second);
+ EXPECT_TRUE(seen_components[2].second);
+}
+
+TEST(AssetCatalogPathTest, rebase)
+{
+ AssetCatalogPath path("some/path/to/some/catalog");
+ EXPECT_EQ(path.rebase("some/path", "new/base"), "new/base/to/some/catalog");
+ EXPECT_EQ(path.rebase("", "new/base"), "new/base/some/path/to/some/catalog");
+
+ EXPECT_EQ(path.rebase("some/path/to/some/catalog", "some/path/to/some/catalog"),
+ "some/path/to/some/catalog")
+ << "Rebasing to itself should not change the path.";
+
+ EXPECT_EQ(path.rebase("path/to", "new/base"), "")
+ << "Non-matching base path should return empty string to indicate 'NO'.";
+
+ /* Empty strings should be handled without crashing or other nasty side-effects. */
+ AssetCatalogPath empty("");
+ EXPECT_EQ(empty.rebase("path/to", "new/base"), "");
+ EXPECT_EQ(empty.rebase("", "new/base"), "new/base");
+ EXPECT_EQ(empty.rebase("", ""), "");
+}
+
+TEST(AssetCatalogPathTest, parent)
+{
+ const AssetCatalogPath ascii_path("path/with/missing/parents");
+ EXPECT_EQ(ascii_path.parent(), "path/with/missing");
+
+ const AssetCatalogPath path("путь/в/Пермь/долог/и/далек");
+ EXPECT_EQ(path.parent(), "путь/в/Пермь/долог/и");
+ EXPECT_EQ(path.parent().parent(), "путь/в/Пермь/долог");
+ EXPECT_EQ(path.parent().parent().parent(), "путь/в/Пермь");
+
+ const AssetCatalogPath one_level("one");
+ EXPECT_EQ(one_level.parent(), "");
+
+ const AssetCatalogPath empty("");
+ EXPECT_EQ(empty.parent(), "");
+}
+
+} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc
index 5b94f021797..8c39bfc9770 100644
--- a/source/blender/blenkernel/intern/asset_catalog_test.cc
+++ b/source/blender/blenkernel/intern/asset_catalog_test.cc
@@ -24,8 +24,11 @@
#include "BLI_fileops.h"
#include "BLI_path_util.h"
+#include "DNA_asset_types.h"
#include "DNA_userdef_types.h"
+#include "CLG_log.h"
+
#include "testing/testing.h"
namespace blender::bke::tests {
@@ -35,10 +38,12 @@ const bUUID UUID_ID_WITHOUT_PATH("e34dd2c5-5d2e-4668-9794-1db5de2a4f71");
const bUUID UUID_POSES_ELLIE("df60e1f6-2259-475b-93d9-69a1b4a8db78");
const bUUID UUID_POSES_ELLIE_WHITESPACE("b06132f6-5687-4751-a6dd-392740eb3c46");
const bUUID UUID_POSES_ELLIE_TRAILING_SLASH("3376b94b-a28d-4d05-86c1-bf30b937130d");
+const bUUID UUID_POSES_ELLIE_BACKSLASHES("a51e17ae-34fc-47d5-ba0f-64c2c9b771f7");
const bUUID UUID_POSES_RUZENA("79a4f887-ab60-4bd4-94da-d572e27d6aed");
const bUUID UUID_POSES_RUZENA_HAND("81811c31-1a88-4bd7-bb34-c6fc2607a12e");
const bUUID UUID_POSES_RUZENA_FACE("82162c1f-06cc-4d91-a9bf-4f72c104e348");
const bUUID UUID_WITHOUT_SIMPLENAME("d7916a31-6ca9-4909-955f-182ca2b81fa3");
+const bUUID UUID_ANOTHER_RUZENA("00000000-d9fa-4b91-b704-e6af1f1339ef");
/* UUIDs from lib/tests/asset_library/modified_assets.cats.txt */
const bUUID UUID_AGENT_47("c5744ba5-43f5-4f73-8e52-010ad4a61b34");
@@ -55,7 +60,33 @@ class TestableAssetCatalogService : public AssetCatalogService {
AssetCatalogDefinitionFile *get_catalog_definition_file()
{
- return catalog_definition_file_.get();
+ return AssetCatalogService::get_catalog_definition_file();
+ }
+
+ OwningAssetCatalogMap &get_deleted_catalogs()
+ {
+ return AssetCatalogService::get_deleted_catalogs();
+ }
+
+ void create_missing_catalogs()
+ {
+ AssetCatalogService::create_missing_catalogs();
+ }
+
+ void delete_catalog_by_id_soft(CatalogID catalog_id)
+ {
+ AssetCatalogService::delete_catalog_by_id_soft(catalog_id);
+ }
+
+ int64_t count_catalogs_with_path(const CatalogFilePath &path)
+ {
+ int64_t count = 0;
+ for (auto &catalog_uptr : get_catalogs().values()) {
+ if (catalog_uptr->path == path) {
+ count++;
+ }
+ }
+ return count;
}
};
@@ -64,6 +95,18 @@ class AssetCatalogTest : public testing::Test {
CatalogFilePath asset_library_root_;
CatalogFilePath temp_library_path_;
+ static void SetUpTestSuite()
+ {
+ testing::Test::SetUpTestSuite();
+ CLG_init();
+ }
+
+ static void TearDownTestSuite()
+ {
+ CLG_exit();
+ testing::Test::TearDownTestSuite();
+ }
+
void SetUp() override
{
const std::string test_files_dir = blender::tests::flags_test_asset_dir();
@@ -75,6 +118,14 @@ class AssetCatalogTest : public testing::Test {
temp_library_path_ = "";
}
+ void TearDown() override
+ {
+ if (!temp_library_path_.empty()) {
+ BLI_delete(temp_library_path_.c_str(), true, true);
+ temp_library_path_ = "";
+ }
+ }
+
/* Register a temporary path, which will be removed at the end of the test.
* The returned path ends in a slash. */
CatalogFilePath use_temp_path()
@@ -92,21 +143,23 @@ class AssetCatalogTest : public testing::Test {
return path;
}
- struct CatalogPathInfo {
- StringRef name;
- int parent_count;
- };
-
- void assert_expected_item(const CatalogPathInfo &expected_path,
+ void assert_expected_item(const AssetCatalogPath &expected_path,
const AssetCatalogTreeItem &actual_item)
{
- char expected_filename[FILE_MAXFILE];
+ if (expected_path != actual_item.catalog_path().str()) {
+ /* This will fail, but with a nicer error message than just calling FAIL(). */
+ EXPECT_EQ(expected_path, actual_item.catalog_path());
+ return;
+ }
+
/* Is the catalog name as expected? "character", "Ellie", ... */
- BLI_split_file_part(expected_path.name.data(), expected_filename, sizeof(expected_filename));
- EXPECT_EQ(expected_filename, actual_item.get_name());
+ EXPECT_EQ(expected_path.name(), actual_item.get_name());
+
/* Does the computed number of parents match? */
- EXPECT_EQ(expected_path.parent_count, actual_item.count_parents());
- EXPECT_EQ(expected_path.name, actual_item.catalog_path());
+ const std::string expected_path_str = expected_path.str();
+ const size_t expected_parent_count = std::count(
+ expected_path_str.begin(), expected_path_str.end(), AssetCatalogPath::SEPARATOR);
+ EXPECT_EQ(expected_parent_count, actual_item.count_parents());
}
/**
@@ -114,7 +167,7 @@ class AssetCatalogTest : public testing::Test {
* the items map exactly to \a expected_paths.
*/
void assert_expected_tree_items(AssetCatalogTree *tree,
- const std::vector<CatalogPathInfo> &expected_paths)
+ const std::vector<AssetCatalogPath> &expected_paths)
{
int i = 0;
tree->foreach_item([&](const AssetCatalogTreeItem &actual_item) {
@@ -131,7 +184,7 @@ class AssetCatalogTest : public testing::Test {
* #AssetCatalogTree::foreach_root_item() instead of #AssetCatalogTree::foreach_item().
*/
void assert_expected_tree_root_items(AssetCatalogTree *tree,
- const std::vector<CatalogPathInfo> &expected_paths)
+ const std::vector<AssetCatalogPath> &expected_paths)
{
int i = 0;
tree->foreach_root_item([&](const AssetCatalogTreeItem &actual_item) {
@@ -149,7 +202,7 @@ class AssetCatalogTest : public testing::Test {
* #AssetCatalogTreeItem::foreach_child() instead of #AssetCatalogTree::foreach_item().
*/
void assert_expected_tree_item_child_items(AssetCatalogTreeItem *parent_item,
- const std::vector<CatalogPathInfo> &expected_paths)
+ const std::vector<AssetCatalogPath> &expected_paths)
{
int i = 0;
parent_item->foreach_child([&](const AssetCatalogTreeItem &actual_item) {
@@ -161,12 +214,74 @@ class AssetCatalogTest : public testing::Test {
});
}
- void TearDown() override
+ /* Used by on_blendfile_save__from_memory_into_existing_asset_lib* test functions. */
+ void save_from_memory_into_existing_asset_lib(const bool should_top_level_cdf_exist)
{
- if (!temp_library_path_.empty()) {
- BLI_delete(temp_library_path_.c_str(), true, true);
- temp_library_path_ = "";
+ const CatalogFilePath target_dir = create_temp_path(); /* Has trailing slash. */
+ const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
+ const CatalogFilePath registered_asset_lib = target_dir + "my_asset_library/";
+ const CatalogFilePath asset_lib_subdir = registered_asset_lib + "subdir/";
+ CatalogFilePath cdf_toplevel = registered_asset_lib +
+ AssetCatalogService::DEFAULT_CATALOG_FILENAME;
+ CatalogFilePath cdf_in_subdir = asset_lib_subdir +
+ AssetCatalogService::DEFAULT_CATALOG_FILENAME;
+ BLI_path_slash_native(cdf_toplevel.data());
+ BLI_path_slash_native(cdf_in_subdir.data());
+
+ /* Set up a temporary asset library for testing. */
+ bUserAssetLibrary *asset_lib_pref = BKE_preferences_asset_library_add(
+ &U, "Test", registered_asset_lib.c_str());
+ ASSERT_NE(nullptr, asset_lib_pref);
+ ASSERT_TRUE(BLI_dir_create_recursive(asset_lib_subdir.c_str()));
+
+ if (should_top_level_cdf_exist) {
+ ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), cdf_toplevel.c_str()));
+ }
+
+ /* Create an empty CDF to add complexity. It should not save to this, but to the top-level
+ * one. */
+ ASSERT_TRUE(BLI_file_touch(cdf_in_subdir.c_str()));
+ ASSERT_EQ(0, BLI_file_size(cdf_in_subdir.c_str()));
+
+ /* Create the catalog service without loading the already-existing CDF. */
+ TestableAssetCatalogService service;
+ const CatalogFilePath blendfilename = asset_lib_subdir + "some_file.blend";
+ const AssetCatalog *cat = service.create_catalog("some/catalog/path");
+
+ /* Mock that the blend file is written to the directory already containing a CDF. */
+ ASSERT_TRUE(service.write_to_disk(blendfilename));
+
+ /* Test that the CDF still exists in the expected location. */
+ EXPECT_TRUE(BLI_exists(cdf_toplevel.c_str()));
+ const CatalogFilePath backup_filename = cdf_toplevel + "~";
+ const bool backup_exists = BLI_exists(backup_filename.c_str());
+ EXPECT_EQ(should_top_level_cdf_exist, backup_exists)
+ << "Overwritten CDF should have been backed up.";
+
+ /* Test that the in-memory CDF has the expected file path. */
+ AssetCatalogDefinitionFile *cdf = service.get_catalog_definition_file();
+ BLI_path_slash_native(cdf->file_path.data());
+ EXPECT_EQ(cdf_toplevel, cdf->file_path);
+
+ /* Test that the in-memory catalogs have been merged with the on-disk one. */
+ AssetCatalogService loaded_service(cdf_toplevel);
+ loaded_service.load_from_disk();
+ EXPECT_NE(nullptr, loaded_service.find_catalog(cat->catalog_id));
+
+ /* This catalog comes from a pre-existing CDF that should have been merged.
+ * However, if the file doesn't exist, so does the catalog. */
+ AssetCatalog *poses_ellie_catalog = loaded_service.find_catalog(UUID_POSES_ELLIE);
+ if (should_top_level_cdf_exist) {
+ EXPECT_NE(nullptr, poses_ellie_catalog);
}
+ else {
+ EXPECT_EQ(nullptr, poses_ellie_catalog);
+ }
+
+ /* Test that the "red herring" CDF has not been touched. */
+ EXPECT_EQ(0, BLI_file_size(cdf_in_subdir.c_str()));
+
+ BKE_preferences_asset_library_remove(&U, asset_lib_pref);
}
};
@@ -186,22 +301,72 @@ TEST_F(AssetCatalogTest, load_single_file)
AssetCatalog *poses_ellie = service.find_catalog(UUID_POSES_ELLIE);
ASSERT_NE(nullptr, poses_ellie);
EXPECT_EQ(UUID_POSES_ELLIE, poses_ellie->catalog_id);
- EXPECT_EQ("character/Ellie/poselib", poses_ellie->path);
+ EXPECT_EQ("character/Ellie/poselib", poses_ellie->path.str());
EXPECT_EQ("POSES_ELLIE", poses_ellie->simple_name);
/* Test white-space stripping and support in the path. */
AssetCatalog *poses_whitespace = service.find_catalog(UUID_POSES_ELLIE_WHITESPACE);
ASSERT_NE(nullptr, poses_whitespace);
EXPECT_EQ(UUID_POSES_ELLIE_WHITESPACE, poses_whitespace->catalog_id);
- EXPECT_EQ("character/Ellie/poselib/white space", poses_whitespace->path);
+ EXPECT_EQ("character/Ellie/poselib/white space", poses_whitespace->path.str());
EXPECT_EQ("POSES_ELLIE WHITESPACE", poses_whitespace->simple_name);
/* Test getting a UTF-8 catalog ID. */
AssetCatalog *poses_ruzena = service.find_catalog(UUID_POSES_RUZENA);
ASSERT_NE(nullptr, poses_ruzena);
EXPECT_EQ(UUID_POSES_RUZENA, poses_ruzena->catalog_id);
- EXPECT_EQ("character/Ružena/poselib", poses_ruzena->path);
+ EXPECT_EQ("character/Ružena/poselib", poses_ruzena->path.str());
EXPECT_EQ("POSES_RUŽENA", poses_ruzena->simple_name);
+
+ /* Test getting a catalog that aliases an earlier-defined catalog. */
+ AssetCatalog *another_ruzena = service.find_catalog(UUID_ANOTHER_RUZENA);
+ ASSERT_NE(nullptr, another_ruzena);
+ EXPECT_EQ(UUID_ANOTHER_RUZENA, another_ruzena->catalog_id);
+ EXPECT_EQ("character/Ružena/poselib", another_ruzena->path.str());
+ EXPECT_EQ("Another Ružena", another_ruzena->simple_name);
+}
+
+TEST_F(AssetCatalogTest, load_catalog_path_backslashes)
+{
+ AssetCatalogService service(asset_library_root_);
+ service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+
+ const AssetCatalog *found_by_id = service.find_catalog(UUID_POSES_ELLIE_BACKSLASHES);
+ ASSERT_NE(nullptr, found_by_id);
+ EXPECT_EQ(AssetCatalogPath("character/Ellie/backslashes"), found_by_id->path)
+ << "Backslashes should be normalised when loading from disk.";
+ EXPECT_EQ(StringRefNull("Windows For Life!"), found_by_id->simple_name);
+
+ const AssetCatalog *found_by_path = service.find_catalog_by_path("character/Ellie/backslashes");
+ EXPECT_EQ(found_by_id, found_by_path)
+ << "Catalog with backslashed path should be findable by the normalized path.";
+
+ EXPECT_EQ(nullptr, service.find_catalog_by_path("character\\Ellie\\backslashes"))
+ << "Nothing should be found when searching for backslashes.";
+}
+
+TEST_F(AssetCatalogTest, is_first_loaded_flag)
+{
+ AssetCatalogService service(asset_library_root_);
+ service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+
+ AssetCatalog *new_cat = service.create_catalog("never/before/seen/path");
+ EXPECT_FALSE(new_cat->flags.is_first_loaded)
+ << "Adding a catalog at runtime should never mark it as 'first loaded'; "
+ "only loading from disk is allowed to do that.";
+
+ AssetCatalog *alias_cat = service.create_catalog("character/Ružena/poselib");
+ EXPECT_FALSE(alias_cat->flags.is_first_loaded)
+ << "Adding a new catalog with an already-loaded path should not mark it as 'first loaded'";
+
+ EXPECT_TRUE(service.find_catalog(UUID_POSES_ELLIE)->flags.is_first_loaded);
+ EXPECT_TRUE(service.find_catalog(UUID_POSES_ELLIE_WHITESPACE)->flags.is_first_loaded);
+ EXPECT_TRUE(service.find_catalog(UUID_POSES_RUZENA)->flags.is_first_loaded);
+ EXPECT_FALSE(service.find_catalog(UUID_ANOTHER_RUZENA)->flags.is_first_loaded);
+
+ AssetCatalog *ruzena = service.find_catalog_by_path("character/Ružena/poselib");
+ EXPECT_EQ(UUID_POSES_RUZENA, ruzena->catalog_id)
+ << "The first-seen definition of a catalog should be returned";
}
TEST_F(AssetCatalogTest, insert_item_into_tree)
@@ -219,32 +384,30 @@ TEST_F(AssetCatalogTest, insert_item_into_tree)
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("item");
tree.insert_item(*catalog);
- assert_expected_tree_items(&tree, {{"item", 0}});
+ assert_expected_tree_items(&tree, {"item"});
/* Insert child after parent already exists. */
std::unique_ptr<AssetCatalog> child_catalog = AssetCatalog::from_path("item/child");
tree.insert_item(*catalog);
- assert_expected_tree_items(&tree, {{"item", 0}, {"item/child", 1}});
+ assert_expected_tree_items(&tree, {"item", "item/child"});
- std::vector<CatalogPathInfo> expected_paths;
+ std::vector<AssetCatalogPath> expected_paths;
/* Test inserting multi-component sub-path. */
std::unique_ptr<AssetCatalog> grandgrandchild_catalog = AssetCatalog::from_path(
"item/child/grandchild/grandgrandchild");
tree.insert_item(*catalog);
- expected_paths = {{"item", 0},
- {"item/child", 1},
- {"item/child/grandchild", 2},
- {"item/child/grandchild/grandgrandchild", 3}};
+ expected_paths = {
+ "item", "item/child", "item/child/grandchild", "item/child/grandchild/grandgrandchild"};
assert_expected_tree_items(&tree, expected_paths);
std::unique_ptr<AssetCatalog> root_level_catalog = AssetCatalog::from_path("root level");
tree.insert_item(*catalog);
- expected_paths = {{"item", 0},
- {"item/child", 1},
- {"item/child/grandchild", 2},
- {"item/child/grandchild/grandgrandchild", 3},
- {"root level", 0}};
+ expected_paths = {"item",
+ "item/child",
+ "item/child/grandchild",
+ "item/child/grandchild/grandgrandchild",
+ "root level"};
assert_expected_tree_items(&tree, expected_paths);
}
@@ -253,7 +416,7 @@ TEST_F(AssetCatalogTest, insert_item_into_tree)
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("item/child");
tree.insert_item(*catalog);
- assert_expected_tree_items(&tree, {{"item", 0}, {"item/child", 1}});
+ assert_expected_tree_items(&tree, {"item", "item/child"});
}
{
@@ -261,7 +424,7 @@ TEST_F(AssetCatalogTest, insert_item_into_tree)
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("white space");
tree.insert_item(*catalog);
- assert_expected_tree_items(&tree, {{"white space", 0}});
+ assert_expected_tree_items(&tree, {"white space"});
}
{
@@ -269,7 +432,7 @@ TEST_F(AssetCatalogTest, insert_item_into_tree)
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("/item/white space");
tree.insert_item(*catalog);
- assert_expected_tree_items(&tree, {{"item", 0}, {"item/white space", 1}});
+ assert_expected_tree_items(&tree, {"item", "item/white space"});
}
{
@@ -277,11 +440,11 @@ TEST_F(AssetCatalogTest, insert_item_into_tree)
std::unique_ptr<AssetCatalog> catalog_unicode_path = AssetCatalog::from_path("Ružena");
tree.insert_item(*catalog_unicode_path);
- assert_expected_tree_items(&tree, {{"Ružena", 0}});
+ assert_expected_tree_items(&tree, {"Ružena"});
catalog_unicode_path = AssetCatalog::from_path("Ružena/Ružena");
tree.insert_item(*catalog_unicode_path);
- assert_expected_tree_items(&tree, {{"Ružena", 0}, {"Ružena/Ružena", 1}});
+ assert_expected_tree_items(&tree, {"Ružena", "Ružena/Ružena"});
}
}
@@ -292,19 +455,20 @@ TEST_F(AssetCatalogTest, load_single_file_into_tree)
/* Contains not only paths from the CDF but also the missing parents (implicitly defined
* catalogs). */
- std::vector<CatalogPathInfo> expected_paths{
- {"character", 0},
- {"character/Ellie", 1},
- {"character/Ellie/poselib", 2},
- {"character/Ellie/poselib/tailslash", 3},
- {"character/Ellie/poselib/white space", 3},
- {"character/Ružena", 1},
- {"character/Ružena/poselib", 2},
- {"character/Ružena/poselib/face", 3},
- {"character/Ružena/poselib/hand", 3},
- {"path", 0}, /* Implicit. */
- {"path/without", 1}, /* Implicit. */
- {"path/without/simplename", 2}, /* From CDF. */
+ std::vector<AssetCatalogPath> expected_paths{
+ "character",
+ "character/Ellie",
+ "character/Ellie/backslashes",
+ "character/Ellie/poselib",
+ "character/Ellie/poselib/tailslash",
+ "character/Ellie/poselib/white space",
+ "character/Ružena",
+ "character/Ružena/poselib",
+ "character/Ružena/poselib/face",
+ "character/Ružena/poselib/hand",
+ "path", /* Implicit. */
+ "path/without", /* Implicit. */
+ "path/without/simplename", /* From CDF. */
};
AssetCatalogTree *tree = service.get_catalog_tree();
@@ -315,7 +479,7 @@ TEST_F(AssetCatalogTest, foreach_in_tree)
{
{
AssetCatalogTree tree{};
- const std::vector<CatalogPathInfo> no_catalogs{};
+ const std::vector<AssetCatalogPath> no_catalogs{};
assert_expected_tree_items(&tree, no_catalogs);
assert_expected_tree_root_items(&tree, no_catalogs);
@@ -330,16 +494,16 @@ TEST_F(AssetCatalogTest, foreach_in_tree)
AssetCatalogService service(asset_library_root_);
service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
- std::vector<CatalogPathInfo> expected_root_items{{"character", 0}, {"path", 0}};
+ std::vector<AssetCatalogPath> expected_root_items{{"character", "path"}};
AssetCatalogTree *tree = service.get_catalog_tree();
assert_expected_tree_root_items(tree, expected_root_items);
/* Test if the direct children of the root item are what's expected. */
- std::vector<std::vector<CatalogPathInfo>> expected_root_child_items = {
+ std::vector<std::vector<AssetCatalogPath>> expected_root_child_items = {
/* Children of the "character" root item. */
- {{"character/Ellie", 1}, {"character/Ružena", 1}},
+ {"character/Ellie", "character/Ružena"},
/* Children of the "path" root item. */
- {{"path/without", 1}},
+ {"path/without"},
};
int i = 0;
tree->foreach_root_item([&expected_root_child_items, &i, this](AssetCatalogTreeItem &item) {
@@ -399,11 +563,35 @@ TEST_F(AssetCatalogTest, write_single_file)
/* TODO(@sybren): test ordering of catalogs in the file. */
}
+TEST_F(AssetCatalogTest, read_write_unicode_filepath)
+{
+ TestableAssetCatalogService service(asset_library_root_);
+ const CatalogFilePath load_from_path = asset_library_root_ + "/новый/" +
+ AssetCatalogService::DEFAULT_CATALOG_FILENAME;
+ service.load_from_disk(load_from_path);
+
+ const CatalogFilePath save_to_path = use_temp_path() + "новый.cats.txt";
+ AssetCatalogDefinitionFile *cdf = service.get_catalog_definition_file();
+ ASSERT_NE(nullptr, cdf) << "unable to load " << load_from_path;
+ EXPECT_TRUE(cdf->write_to_disk(save_to_path));
+
+ AssetCatalogService loaded_service(save_to_path);
+ loaded_service.load_from_disk();
+
+ /* Test that the file was loaded correctly. */
+ const bUUID materials_uuid("a2151dff-dead-4f29-b6bc-b2c7d6cccdb4");
+ const AssetCatalog *cat = loaded_service.find_catalog(materials_uuid);
+ ASSERT_NE(nullptr, cat);
+ EXPECT_EQ(materials_uuid, cat->catalog_id);
+ EXPECT_EQ(AssetCatalogPath("Материалы"), cat->path);
+ EXPECT_EQ("Russian Materials", cat->simple_name);
+}
+
TEST_F(AssetCatalogTest, no_writing_empty_files)
{
const CatalogFilePath temp_lib_root = create_temp_path();
AssetCatalogService service(temp_lib_root);
- service.write_to_disk_on_blendfile_save(temp_lib_root + "phony.blend");
+ service.write_to_disk(temp_lib_root + "phony.blend");
const CatalogFilePath default_cdf_path = temp_lib_root +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
@@ -429,7 +617,7 @@ TEST_F(AssetCatalogTest, on_blendfile_save__with_existing_cdf)
const AssetCatalog *cat = service.create_catalog("some/catalog/path");
const CatalogFilePath blendfilename = top_level_dir + "subdir/some_file.blend";
- ASSERT_TRUE(service.write_to_disk_on_blendfile_save(blendfilename.c_str()));
+ ASSERT_TRUE(service.write_to_disk(blendfilename));
EXPECT_EQ(cdf_filename, service.get_catalog_definition_file()->file_path);
/* Test that the CDF was created in the expected location. */
@@ -456,7 +644,7 @@ TEST_F(AssetCatalogTest, on_blendfile_save__from_memory_into_empty_directory)
const AssetCatalog *cat = service.create_catalog("some/catalog/path");
const CatalogFilePath blendfilename = target_dir + "some_file.blend";
- ASSERT_TRUE(service.write_to_disk_on_blendfile_save(blendfilename.c_str()));
+ ASSERT_TRUE(service.write_to_disk(blendfilename));
/* Test that the CDF was created in the expected location. */
const CatalogFilePath expected_cdf_path = target_dir +
@@ -479,8 +667,8 @@ TEST_F(AssetCatalogTest, on_blendfile_save__from_memory_into_existing_cdf_and_me
{
const CatalogFilePath target_dir = create_temp_path(); /* Has trailing slash. */
const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath writable_cdf_file = target_dir +
- AssetCatalogService::DEFAULT_CATALOG_FILENAME;
+ CatalogFilePath writable_cdf_file = target_dir + AssetCatalogService::DEFAULT_CATALOG_FILENAME;
+ BLI_path_slash_native(writable_cdf_file.data());
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str()));
/* Create the catalog service without loading the already-existing CDF. */
@@ -489,7 +677,7 @@ TEST_F(AssetCatalogTest, on_blendfile_save__from_memory_into_existing_cdf_and_me
/* Mock that the blend file is written to a subdirectory of the asset library. */
const CatalogFilePath blendfilename = target_dir + "some_file.blend";
- ASSERT_TRUE(service.write_to_disk_on_blendfile_save(blendfilename.c_str()));
+ ASSERT_TRUE(service.write_to_disk(blendfilename));
/* Test that the CDF still exists in the expected location. */
const CatalogFilePath backup_filename = writable_cdf_file + "~";
@@ -509,51 +697,21 @@ TEST_F(AssetCatalogTest, on_blendfile_save__from_memory_into_existing_cdf_and_me
EXPECT_NE(nullptr, loaded_service.find_catalog(UUID_POSES_ELLIE));
}
-/* Create some catalogs in memory, save to subdirectory of a registered asset library. */
-TEST_F(AssetCatalogTest, on_blendfile_save__from_memory_into_existing_asset_lib)
+/* Create some catalogs in memory, save to subdirectory of a registered asset library, where the
+ * subdirectory also contains a CDF. This should still write to the top-level dir of the asset
+ * library. */
+TEST_F(AssetCatalogTest,
+ on_blendfile_save__from_memory_into_existing_asset_lib_without_top_level_cdf)
{
- const CatalogFilePath target_dir = create_temp_path(); /* Has trailing slash. */
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath registered_asset_lib = target_dir + "my_asset_library/";
- CatalogFilePath writable_cdf_file = registered_asset_lib +
- AssetCatalogService::DEFAULT_CATALOG_FILENAME;
- BLI_path_slash_native(writable_cdf_file.data());
-
- /* Set up a temporary asset library for testing. */
- bUserAssetLibrary *asset_lib_pref = BKE_preferences_asset_library_add(
- &U, "Test", registered_asset_lib.c_str());
- ASSERT_NE(nullptr, asset_lib_pref);
- ASSERT_TRUE(BLI_dir_create_recursive(registered_asset_lib.c_str()));
- ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str()));
-
- /* Create the catalog service without loading the already-existing CDF. */
- TestableAssetCatalogService service;
- const CatalogFilePath blenddirname = registered_asset_lib + "subdirectory/";
- const CatalogFilePath blendfilename = blenddirname + "some_file.blend";
- ASSERT_TRUE(BLI_dir_create_recursive(blenddirname.c_str()));
- const AssetCatalog *cat = service.create_catalog("some/catalog/path");
-
- /* Mock that the blend file is written to the directory already containing a CDF. */
- ASSERT_TRUE(service.write_to_disk_on_blendfile_save(blendfilename.c_str()));
-
- /* Test that the CDF still exists in the expected location. */
- EXPECT_TRUE(BLI_exists(writable_cdf_file.c_str()));
- const CatalogFilePath backup_filename = writable_cdf_file + "~";
- EXPECT_TRUE(BLI_exists(backup_filename.c_str()))
- << "Overwritten CDF should have been backed up.";
-
- /* Test that the in-memory CDF has the expected file path. */
- AssetCatalogDefinitionFile *cdf = service.get_catalog_definition_file();
- BLI_path_slash_native(cdf->file_path.data());
- EXPECT_EQ(writable_cdf_file, cdf->file_path);
-
- /* Test that the in-memory catalogs have been merged with the on-disk one. */
- AssetCatalogService loaded_service(writable_cdf_file);
- loaded_service.load_from_disk();
- EXPECT_NE(nullptr, loaded_service.find_catalog(cat->catalog_id));
- EXPECT_NE(nullptr, loaded_service.find_catalog(UUID_POSES_ELLIE));
+ save_from_memory_into_existing_asset_lib(true);
+}
- BKE_preferences_asset_library_remove(&U, asset_lib_pref);
+/* Create some catalogs in memory, save to subdirectory of a registered asset library, where the
+ * subdirectory contains a CDF, but the top-level directory does not. This should still write to
+ * the top-level dir of the asset library. */
+TEST_F(AssetCatalogTest, on_blendfile_save__from_memory_into_existing_asset_lib)
+{
+ save_from_memory_into_existing_asset_lib(false);
}
TEST_F(AssetCatalogTest, create_first_catalog_from_scratch)
@@ -574,7 +732,7 @@ TEST_F(AssetCatalogTest, create_first_catalog_from_scratch)
EXPECT_FALSE(BLI_exists(temp_lib_root.c_str()));
/* Writing to disk should create the directory + the default file. */
- service.write_to_disk_on_blendfile_save(temp_lib_root + "phony.blend");
+ service.write_to_disk(temp_lib_root + "phony.blend");
EXPECT_TRUE(BLI_is_dir(temp_lib_root.c_str()));
const CatalogFilePath definition_file_path = temp_lib_root + "/" +
@@ -588,7 +746,7 @@ TEST_F(AssetCatalogTest, create_first_catalog_from_scratch)
AssetCatalog *written_cat = loaded_service.find_catalog(cat->catalog_id);
ASSERT_NE(nullptr, written_cat);
EXPECT_EQ(written_cat->catalog_id, cat->catalog_id);
- EXPECT_EQ(written_cat->path, cat->path);
+ EXPECT_EQ(written_cat->path, cat->path.str());
}
TEST_F(AssetCatalogTest, create_catalog_after_loading_file)
@@ -625,7 +783,7 @@ TEST_F(AssetCatalogTest, create_catalog_after_loading_file)
<< "expecting newly added catalog to not yet be saved to " << temp_lib_root;
/* Write and reload the catalog file. */
- service.write_to_disk_on_blendfile_save(temp_lib_root + "phony.blend");
+ service.write_to_disk(temp_lib_root + "phony.blend");
AssetCatalogService reloaded_service(temp_lib_root);
reloaded_service.load_from_disk();
EXPECT_NE(nullptr, reloaded_service.find_catalog(UUID_POSES_ELLIE))
@@ -640,7 +798,7 @@ TEST_F(AssetCatalogTest, create_catalog_path_cleanup)
AssetCatalog *cat = service.create_catalog(" /some/path / ");
EXPECT_FALSE(BLI_uuid_is_nil(cat->catalog_id));
- EXPECT_EQ("some/path", cat->path);
+ EXPECT_EQ("some/path", cat->path.str());
EXPECT_EQ("some-path", cat->simple_name);
}
@@ -652,7 +810,7 @@ TEST_F(AssetCatalogTest, create_catalog_simple_name)
EXPECT_FALSE(BLI_uuid_is_nil(cat->catalog_id));
EXPECT_EQ("production/Spite Fright/Characters/Victora/Pose Library/Approved/Body Parts/Hands",
- cat->path);
+ cat->path.str());
EXPECT_EQ("...ht-Characters-Victora-Pose Library-Approved-Body Parts-Hands", cat->simple_name);
}
@@ -663,24 +821,79 @@ TEST_F(AssetCatalogTest, delete_catalog_leaf)
/* Delete a leaf catalog, i.e. one that is not a parent of another catalog.
* This keeps this particular test easy. */
- service.delete_catalog(UUID_POSES_RUZENA_HAND);
+ service.prune_catalogs_by_id(UUID_POSES_RUZENA_HAND);
EXPECT_EQ(nullptr, service.find_catalog(UUID_POSES_RUZENA_HAND));
/* Contains not only paths from the CDF but also the missing parents (implicitly defined
* catalogs). This is why a leaf catalog was deleted. */
- std::vector<CatalogPathInfo> expected_paths{
- {"character", 0},
- {"character/Ellie", 1},
- {"character/Ellie/poselib", 2},
- {"character/Ellie/poselib/tailslash", 3},
- {"character/Ellie/poselib/white space", 3},
- {"character/Ružena", 1},
- {"character/Ružena/poselib", 2},
- {"character/Ružena/poselib/face", 3},
- // {"character/Ružena/poselib/hand", 3}, /* This is the deleted one. */
- {"path", 0},
- {"path/without", 1},
- {"path/without/simplename", 2},
+ std::vector<AssetCatalogPath> expected_paths{
+ "character",
+ "character/Ellie",
+ "character/Ellie/backslashes",
+ "character/Ellie/poselib",
+ "character/Ellie/poselib/tailslash",
+ "character/Ellie/poselib/white space",
+ "character/Ružena",
+ "character/Ružena/poselib",
+ "character/Ružena/poselib/face",
+ // "character/Ružena/poselib/hand", /* This is the deleted one. */
+ "path",
+ "path/without",
+ "path/without/simplename",
+ };
+
+ AssetCatalogTree *tree = service.get_catalog_tree();
+ assert_expected_tree_items(tree, expected_paths);
+}
+
+TEST_F(AssetCatalogTest, delete_catalog_parent_by_id)
+{
+ TestableAssetCatalogService service(asset_library_root_);
+ service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+
+ /* Delete a parent catalog. */
+ service.delete_catalog_by_id_soft(UUID_POSES_RUZENA);
+
+ /* The catalog should have been deleted, but its children should still be there. */
+ EXPECT_EQ(nullptr, service.find_catalog(UUID_POSES_RUZENA));
+ EXPECT_NE(nullptr, service.find_catalog(UUID_POSES_RUZENA_FACE));
+ EXPECT_NE(nullptr, service.find_catalog(UUID_POSES_RUZENA_HAND));
+}
+
+TEST_F(AssetCatalogTest, delete_catalog_parent_by_path)
+{
+ AssetCatalogService service(asset_library_root_);
+ service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+
+ /* Create an extra catalog with the to-be-deleted path, and one with a child of that.
+ * This creates some duplicates that are bound to occur in production asset libraries as well.
+ */
+ const bUUID cat1_uuid = service.create_catalog("character/Ružena/poselib")->catalog_id;
+ const bUUID cat2_uuid = service.create_catalog("character/Ružena/poselib/body")->catalog_id;
+
+ /* Delete a parent catalog. */
+ service.prune_catalogs_by_path("character/Ružena/poselib");
+
+ /* The catalogs and their children should have been deleted. */
+ EXPECT_EQ(nullptr, service.find_catalog(UUID_POSES_RUZENA));
+ EXPECT_EQ(nullptr, service.find_catalog(UUID_POSES_RUZENA_FACE));
+ EXPECT_EQ(nullptr, service.find_catalog(UUID_POSES_RUZENA_HAND));
+ EXPECT_EQ(nullptr, service.find_catalog(cat1_uuid));
+ EXPECT_EQ(nullptr, service.find_catalog(cat2_uuid));
+
+ /* Contains not only paths from the CDF but also the missing parents (implicitly defined
+ * catalogs). This is why a leaf catalog was deleted. */
+ std::vector<AssetCatalogPath> expected_paths{
+ "character",
+ "character/Ellie",
+ "character/Ellie/backslashes",
+ "character/Ellie/poselib",
+ "character/Ellie/poselib/tailslash",
+ "character/Ellie/poselib/white space",
+ "character/Ružena",
+ "path",
+ "path/without",
+ "path/without/simplename",
};
AssetCatalogTree *tree = service.get_catalog_tree();
@@ -693,7 +906,7 @@ TEST_F(AssetCatalogTest, delete_catalog_write_to_disk)
service.load_from_disk(asset_library_root_ + "/" +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
- service.delete_catalog(UUID_POSES_ELLIE);
+ service.delete_catalog_by_id_soft(UUID_POSES_ELLIE);
const CatalogFilePath save_to_path = use_temp_path();
AssetCatalogDefinitionFile *cdf = service.get_catalog_definition_file();
@@ -718,7 +931,7 @@ TEST_F(AssetCatalogTest, update_catalog_path)
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
const AssetCatalog *orig_cat = service.find_catalog(UUID_POSES_RUZENA);
- const CatalogPath orig_path = orig_cat->path;
+ const AssetCatalogPath orig_path = orig_cat->path;
service.update_catalog_path(UUID_POSES_RUZENA, "charlib/Ružena");
@@ -728,17 +941,94 @@ TEST_F(AssetCatalogTest, update_catalog_path)
const AssetCatalog *renamed_cat = service.find_catalog(UUID_POSES_RUZENA);
ASSERT_NE(nullptr, renamed_cat);
ASSERT_EQ(orig_cat, renamed_cat) << "Changing the path should not reallocate the catalog.";
- EXPECT_EQ(orig_cat->simple_name, renamed_cat->simple_name)
- << "Changing the path should not change the simple name.";
EXPECT_EQ(orig_cat->catalog_id, renamed_cat->catalog_id)
<< "Changing the path should not change the catalog ID.";
- EXPECT_EQ("charlib/Ružena", renamed_cat->path)
+ EXPECT_EQ("charlib/Ružena", renamed_cat->path.str())
<< "Changing the path should change the path. Surprise.";
- EXPECT_EQ("charlib/Ružena/hand", service.find_catalog(UUID_POSES_RUZENA_HAND)->path)
+ EXPECT_EQ("charlib/Ružena/hand", service.find_catalog(UUID_POSES_RUZENA_HAND)->path.str())
<< "Changing the path should update children.";
- EXPECT_EQ("charlib/Ružena/face", service.find_catalog(UUID_POSES_RUZENA_FACE)->path)
+ EXPECT_EQ("charlib/Ružena/face", service.find_catalog(UUID_POSES_RUZENA_FACE)->path.str())
+ << "Changing the path should update children.";
+}
+
+TEST_F(AssetCatalogTest, update_catalog_path_simple_name)
+{
+ AssetCatalogService service(asset_library_root_);
+ service.load_from_disk(asset_library_root_ + "/" +
+ AssetCatalogService::DEFAULT_CATALOG_FILENAME);
+ service.update_catalog_path(UUID_POSES_RUZENA, "charlib/Ružena");
+
+ /* This may not be valid forever; maybe at some point we'll expose the simple name to users &
+ * let them change it from the UI. Until then, automatically updating it is better, because
+ * otherwise all simple names would be "Catalog". */
+ EXPECT_EQ("charlib-Ružena", service.find_catalog(UUID_POSES_RUZENA)->simple_name)
+ << "Changing the path should update the simplename.";
+ EXPECT_EQ("charlib-Ružena-face", service.find_catalog(UUID_POSES_RUZENA_FACE)->simple_name)
+ << "Changing the path should update the simplename of children.";
+}
+
+TEST_F(AssetCatalogTest, update_catalog_path_longer_than_simplename)
+{
+ AssetCatalogService service(asset_library_root_);
+ service.load_from_disk(asset_library_root_ + "/" +
+ AssetCatalogService::DEFAULT_CATALOG_FILENAME);
+ const std::string new_path =
+ "this/is/a/very/long/path/that/exceeds/the/simple-name/length/of/assets";
+ ASSERT_GT(new_path.length(), sizeof(AssetMetaData::catalog_simple_name))
+ << "This test case should work with paths longer than AssetMetaData::catalog_simple_name";
+
+ service.update_catalog_path(UUID_POSES_RUZENA, new_path);
+
+ const std::string new_simple_name = service.find_catalog(UUID_POSES_RUZENA)->simple_name;
+ EXPECT_LT(new_simple_name.length(), sizeof(AssetMetaData::catalog_simple_name))
+ << "The new simple name should fit in the asset metadata.";
+ EXPECT_EQ("...very-long-path-that-exceeds-the-simple-name-length-of-assets", new_simple_name)
+ << "Changing the path should update the simplename.";
+ EXPECT_EQ("...long-path-that-exceeds-the-simple-name-length-of-assets-face",
+ service.find_catalog(UUID_POSES_RUZENA_FACE)->simple_name)
+ << "Changing the path should update the simplename of children.";
+}
+
+TEST_F(AssetCatalogTest, update_catalog_path_add_slashes)
+{
+ AssetCatalogService service(asset_library_root_);
+ service.load_from_disk(asset_library_root_ + "/" +
+ AssetCatalogService::DEFAULT_CATALOG_FILENAME);
+
+ const AssetCatalog *orig_cat = service.find_catalog(UUID_POSES_RUZENA);
+ const AssetCatalogPath orig_path = orig_cat->path;
+
+ /* Original path is `character/Ružena/poselib`.
+ * This rename will also create a new catalog for `character/Ružena/poses`. */
+ service.update_catalog_path(UUID_POSES_RUZENA, "character/Ružena/poses/general");
+
+ EXPECT_EQ(nullptr, service.find_catalog_by_path(orig_path))
+ << "The original (pre-rename) path should not be associated with a catalog any more.";
+
+ const AssetCatalog *renamed_cat = service.find_catalog(UUID_POSES_RUZENA);
+ ASSERT_NE(nullptr, renamed_cat);
+ EXPECT_EQ(orig_cat->catalog_id, renamed_cat->catalog_id)
+ << "Changing the path should not change the catalog ID.";
+
+ EXPECT_EQ("character/Ružena/poses/general", renamed_cat->path.str())
+ << "When creating a new catalog by renaming + adding a slash, the renamed catalog should be "
+ "assigned the path passed to update_catalog_path()";
+
+ /* Test the newly created catalog. */
+ const AssetCatalog *new_cat = service.find_catalog_by_path("character/Ružena/poses");
+ ASSERT_NE(nullptr, new_cat) << "Renaming to .../X/Y should cause .../X to exist as well.";
+ EXPECT_EQ("character/Ružena/poses", new_cat->path.str());
+ EXPECT_EQ("character-Ružena-poses", new_cat->simple_name);
+ EXPECT_TRUE(new_cat->flags.has_unsaved_changes);
+
+ /* Test the children. */
+ EXPECT_EQ("character/Ružena/poses/general/hand",
+ service.find_catalog(UUID_POSES_RUZENA_HAND)->path.str())
+ << "Changing the path should update children.";
+ EXPECT_EQ("character/Ružena/poses/general/face",
+ service.find_catalog(UUID_POSES_RUZENA_FACE)->path.str())
<< "Changing the path should update children.";
}
@@ -758,24 +1048,100 @@ TEST_F(AssetCatalogTest, merge_catalog_files)
* CDF after we loaded it. */
ASSERT_EQ(0, BLI_copy(modified_cdf_file.c_str(), temp_cdf_file.c_str()));
- /* Overwrite the modified file. This should merge the on-disk file with our catalogs. */
- service.write_to_disk_on_blendfile_save(cdf_dir + "phony.blend");
+ /* Overwrite the modified file. This should merge the on-disk file with our catalogs.
+ * No catalog was marked as "has unsaved changes", so effectively this should not
+ * save anything, and reload what's on disk. */
+ service.write_to_disk(cdf_dir + "phony.blend");
AssetCatalogService loaded_service(cdf_dir);
loaded_service.load_from_disk();
/* Test that the expected catalogs are there. */
EXPECT_NE(nullptr, loaded_service.find_catalog(UUID_POSES_ELLIE));
- EXPECT_NE(nullptr, loaded_service.find_catalog(UUID_POSES_ELLIE_WHITESPACE));
- EXPECT_NE(nullptr, loaded_service.find_catalog(UUID_POSES_ELLIE_TRAILING_SLASH));
- EXPECT_NE(nullptr, loaded_service.find_catalog(UUID_POSES_RUZENA));
- EXPECT_NE(nullptr, loaded_service.find_catalog(UUID_POSES_RUZENA_HAND));
EXPECT_NE(nullptr, loaded_service.find_catalog(UUID_POSES_RUZENA_FACE));
EXPECT_NE(nullptr, loaded_service.find_catalog(UUID_AGENT_47)); /* New in the modified file. */
- /* When there are overlaps, the in-memory (i.e. last-saved) paths should win. */
+ /* Test that catalogs removed from modified CDF are gone. */
+ EXPECT_EQ(nullptr, loaded_service.find_catalog(UUID_POSES_ELLIE_WHITESPACE));
+ EXPECT_EQ(nullptr, loaded_service.find_catalog(UUID_POSES_ELLIE_TRAILING_SLASH));
+ EXPECT_EQ(nullptr, loaded_service.find_catalog(UUID_POSES_RUZENA));
+ EXPECT_EQ(nullptr, loaded_service.find_catalog(UUID_POSES_RUZENA_HAND));
+
+ /* On-disk changed catalogs should have overridden in-memory not-changed ones. */
const AssetCatalog *ruzena_face = loaded_service.find_catalog(UUID_POSES_RUZENA_FACE);
- EXPECT_EQ("character/Ružena/poselib/face", ruzena_face->path);
+ EXPECT_EQ("character/Ružena/poselib/gezicht", ruzena_face->path.str());
+}
+
+TEST_F(AssetCatalogTest, refresh_catalogs_with_modification)
+{
+ const CatalogFilePath cdf_dir = create_temp_path();
+ const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
+ const CatalogFilePath modified_cdf_file = asset_library_root_ + "/catalog_reload_test.cats.txt";
+ const CatalogFilePath temp_cdf_file = cdf_dir + "blender_assets.cats.txt";
+ ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), temp_cdf_file.c_str()));
+
+ /* Load the unmodified, original CDF. */
+ TestableAssetCatalogService service(asset_library_root_);
+ service.load_from_disk(cdf_dir);
+
+ /* === Perform changes that should be handled gracefully by the reloading code: */
+
+ /* 1. Delete a subtree of catalogs. */
+ service.prune_catalogs_by_id(UUID_POSES_RUZENA);
+ /* 2. Rename a catalog. */
+ service.tag_has_unsaved_changes(service.find_catalog(UUID_POSES_ELLIE_TRAILING_SLASH));
+ service.update_catalog_path(UUID_POSES_ELLIE_TRAILING_SLASH, "character/Ellie/test-value");
+
+ /* Copy a modified file, to mimic a situation where someone changed the
+ * CDF after we loaded it. */
+ ASSERT_EQ(0, BLI_copy(modified_cdf_file.c_str(), temp_cdf_file.c_str()));
+
+ AssetCatalog *const ellie_whitespace_before_reload = service.find_catalog(
+ UUID_POSES_ELLIE_WHITESPACE);
+
+ /* This should merge the on-disk file with our catalogs. */
+ service.reload_catalogs();
+
+ /* === Test that the expected catalogs are there. */
+ EXPECT_NE(nullptr, service.find_catalog(UUID_POSES_ELLIE));
+ EXPECT_NE(nullptr, service.find_catalog(UUID_POSES_ELLIE_WHITESPACE));
+ EXPECT_NE(nullptr, service.find_catalog(UUID_POSES_ELLIE_TRAILING_SLASH));
+
+ /* === Test changes made to the CDF: */
+
+ /* Removed from the file. */
+ EXPECT_EQ(nullptr, service.find_catalog(UUID_POSES_ELLIE_BACKSLASHES));
+ /* Added to the file. */
+ EXPECT_NE(nullptr, service.find_catalog(UUID_AGENT_47));
+ /* Path modified in file. */
+ AssetCatalog *ellie_whitespace_after_reload = service.find_catalog(UUID_POSES_ELLIE_WHITESPACE);
+ EXPECT_EQ(AssetCatalogPath("whitespace from file"), ellie_whitespace_after_reload->path);
+ EXPECT_NE(ellie_whitespace_after_reload, ellie_whitespace_before_reload);
+ /* Simple name modified in file. */
+ EXPECT_EQ(std::string("Hah simple name after all"),
+ service.find_catalog(UUID_WITHOUT_SIMPLENAME)->simple_name);
+
+ /* === Test persistence of in-memory changes: */
+
+ /* This part of the tree we deleted, but still existed in the CDF. They should remain deleted
+ * after reloading: */
+ EXPECT_EQ(nullptr, service.find_catalog(UUID_POSES_RUZENA));
+ EXPECT_EQ(nullptr, service.find_catalog(UUID_POSES_RUZENA_HAND));
+ EXPECT_EQ(nullptr, service.find_catalog(UUID_POSES_RUZENA_FACE));
+
+ /* This catalog had its path changed in the test and in the CDF. The change from the test (i.e.
+ * the in-memory, yet-unsaved change) should persist. */
+ EXPECT_EQ(AssetCatalogPath("character/Ellie/test-value"),
+ service.find_catalog(UUID_POSES_ELLIE_TRAILING_SLASH)->path);
+
+ /* Overwrite the modified file. This should merge the on-disk file with our catalogs, and clear
+ * the "has_unsaved_changes" flags. */
+ service.write_to_disk(cdf_dir + "phony.blend");
+
+ EXPECT_FALSE(service.find_catalog(UUID_POSES_ELLIE_TRAILING_SLASH)->flags.has_unsaved_changes)
+ << "The catalogs whose path we changed should now be saved";
+ EXPECT_TRUE(service.get_deleted_catalogs().is_empty())
+ << "Deleted catalogs should not be remembered after saving.";
}
TEST_F(AssetCatalogTest, backups)
@@ -786,10 +1152,10 @@ TEST_F(AssetCatalogTest, backups)
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str()));
/* Read a CDF, modify, and write it. */
- AssetCatalogService service(cdf_dir);
+ TestableAssetCatalogService service(cdf_dir);
service.load_from_disk();
- service.delete_catalog(UUID_POSES_ELLIE);
- service.write_to_disk_on_blendfile_save(cdf_dir + "phony.blend");
+ service.delete_catalog_by_id_soft(UUID_POSES_ELLIE);
+ service.write_to_disk(cdf_dir + "phony.blend");
const CatalogFilePath backup_path = writable_cdf_file + "~";
ASSERT_TRUE(BLI_is_file(backup_path.c_str()));
@@ -846,21 +1212,338 @@ TEST_F(AssetCatalogTest, order_by_path)
}
}
-TEST_F(AssetCatalogTest, is_contained_in)
+TEST_F(AssetCatalogTest, order_by_path_and_first_seen)
+{
+ AssetCatalogService service;
+ service.load_from_disk(asset_library_root_);
+
+ const bUUID first_seen_uuid("3d451c87-27d1-40fd-87fc-f4c9e829c848");
+ const bUUID first_sorted_uuid("00000000-0000-0000-0000-000000000001");
+ const bUUID last_sorted_uuid("ffffffff-ffff-ffff-ffff-ffffffffffff");
+
+ AssetCatalog first_seen_cat(first_seen_uuid, "simple/path/child", "");
+ const AssetCatalog first_sorted_cat(first_sorted_uuid, "simple/path/child", "");
+ const AssetCatalog last_sorted_cat(last_sorted_uuid, "simple/path/child", "");
+
+ /* Mimic that this catalog was first-seen when loading from disk. */
+ first_seen_cat.flags.is_first_loaded = true;
+
+ /* Just an assertion of the defaults; this is more to avoid confusing errors later on than an
+ * actual test of these defaults. */
+ ASSERT_FALSE(first_sorted_cat.flags.is_first_loaded);
+ ASSERT_FALSE(last_sorted_cat.flags.is_first_loaded);
+
+ AssetCatalogOrderedSet by_path;
+ by_path.insert(&first_seen_cat);
+ by_path.insert(&first_sorted_cat);
+ by_path.insert(&last_sorted_cat);
+
+ AssetCatalogOrderedSet::const_iterator set_iter = by_path.begin();
+
+ EXPECT_EQ(1, by_path.count(&first_seen_cat));
+ EXPECT_EQ(1, by_path.count(&first_sorted_cat));
+ EXPECT_EQ(1, by_path.count(&last_sorted_cat));
+ ASSERT_EQ(3, by_path.size());
+
+ EXPECT_EQ(first_seen_uuid, (*(set_iter++))->catalog_id);
+ EXPECT_EQ(first_sorted_uuid, (*(set_iter++))->catalog_id);
+ EXPECT_EQ(last_sorted_uuid, (*(set_iter++))->catalog_id);
+
+ if (set_iter != by_path.end()) {
+ const AssetCatalog *next_cat = *set_iter;
+ FAIL() << "Did not expect more items in the set, had at least " << next_cat->catalog_id << ":"
+ << next_cat->path;
+ }
+}
+
+TEST_F(AssetCatalogTest, create_missing_catalogs)
+{
+ TestableAssetCatalogService new_service;
+ new_service.create_catalog("path/with/missing/parents");
+
+ EXPECT_EQ(nullptr, new_service.find_catalog_by_path("path/with/missing"))
+ << "Missing parents should not be immediately created.";
+ EXPECT_EQ(nullptr, new_service.find_catalog_by_path("")) << "Empty path should never be valid";
+
+ new_service.create_missing_catalogs();
+
+ EXPECT_NE(nullptr, new_service.find_catalog_by_path("path/with/missing"));
+ EXPECT_NE(nullptr, new_service.find_catalog_by_path("path/with"));
+ EXPECT_NE(nullptr, new_service.find_catalog_by_path("path"));
+ EXPECT_EQ(nullptr, new_service.find_catalog_by_path(""))
+ << "Empty path should never be valid, even when after missing catalogs";
+}
+
+TEST_F(AssetCatalogTest, create_missing_catalogs_after_loading)
+{
+ TestableAssetCatalogService loaded_service(asset_library_root_);
+ loaded_service.load_from_disk();
+
+ const AssetCatalog *cat_char = loaded_service.find_catalog_by_path("character");
+ const AssetCatalog *cat_ellie = loaded_service.find_catalog_by_path("character/Ellie");
+ const AssetCatalog *cat_ruzena = loaded_service.find_catalog_by_path("character/Ružena");
+ ASSERT_NE(nullptr, cat_char) << "Missing parents should be created immediately after loading.";
+ ASSERT_NE(nullptr, cat_ellie) << "Missing parents should be created immediately after loading.";
+ ASSERT_NE(nullptr, cat_ruzena) << "Missing parents should be created immediately after loading.";
+
+ EXPECT_TRUE(cat_char->flags.has_unsaved_changes)
+ << "Missing parents should be marked as having changes.";
+ EXPECT_TRUE(cat_ellie->flags.has_unsaved_changes)
+ << "Missing parents should be marked as having changes.";
+ EXPECT_TRUE(cat_ruzena->flags.has_unsaved_changes)
+ << "Missing parents should be marked as having changes.";
+
+ AssetCatalogDefinitionFile *cdf = loaded_service.get_catalog_definition_file();
+ ASSERT_NE(nullptr, cdf);
+ EXPECT_TRUE(cdf->contains(cat_char->catalog_id)) << "Missing parents should be saved to a CDF.";
+ EXPECT_TRUE(cdf->contains(cat_ellie->catalog_id)) << "Missing parents should be saved to a CDF.";
+ EXPECT_TRUE(cdf->contains(cat_ruzena->catalog_id))
+ << "Missing parents should be saved to a CDF.";
+
+ /* Check that each missing parent is only created once. The CDF contains multiple paths that
+ * could trigger the creation of missing parents, so this test makes sense. */
+ EXPECT_EQ(1, loaded_service.count_catalogs_with_path("character"));
+ EXPECT_EQ(1, loaded_service.count_catalogs_with_path("character/Ellie"));
+ EXPECT_EQ(1, loaded_service.count_catalogs_with_path("character/Ružena"));
+}
+
+TEST_F(AssetCatalogTest, create_catalog_filter)
+{
+ AssetCatalogService service(asset_library_root_);
+ service.load_from_disk();
+
+ /* Alias for the same catalog as the main one. */
+ AssetCatalog *alias_ruzena = service.create_catalog("character/Ružena/poselib");
+ /* Alias for a sub-catalog. */
+ AssetCatalog *alias_ruzena_hand = service.create_catalog("character/Ružena/poselib/hand");
+
+ AssetCatalogFilter filter = service.create_catalog_filter(UUID_POSES_RUZENA);
+
+ /* Positive test for loaded-from-disk catalogs. */
+ EXPECT_TRUE(filter.contains(UUID_POSES_RUZENA))
+ << "Main catalog should be included in the filter.";
+ EXPECT_TRUE(filter.contains(UUID_POSES_RUZENA_HAND))
+ << "Sub-catalog should be included in the filter.";
+ EXPECT_TRUE(filter.contains(UUID_POSES_RUZENA_FACE))
+ << "Sub-catalog should be included in the filter.";
+
+ /* Positive test for newly-created catalogs. */
+ EXPECT_TRUE(filter.contains(alias_ruzena->catalog_id))
+ << "Alias of main catalog should be included in the filter.";
+ EXPECT_TRUE(filter.contains(alias_ruzena_hand->catalog_id))
+ << "Alias of sub-catalog should be included in the filter.";
+
+ /* Negative test for unrelated catalogs. */
+ EXPECT_FALSE(filter.contains(BLI_uuid_nil())) << "Nil catalog should not be included.";
+ EXPECT_FALSE(filter.contains(UUID_ID_WITHOUT_PATH));
+ EXPECT_FALSE(filter.contains(UUID_POSES_ELLIE));
+ EXPECT_FALSE(filter.contains(UUID_POSES_ELLIE_WHITESPACE));
+ EXPECT_FALSE(filter.contains(UUID_POSES_ELLIE_TRAILING_SLASH));
+ EXPECT_FALSE(filter.contains(UUID_WITHOUT_SIMPLENAME));
+}
+
+TEST_F(AssetCatalogTest, create_catalog_filter_for_unknown_uuid)
+{
+ AssetCatalogService service;
+ const bUUID unknown_uuid = BLI_uuid_generate_random();
+
+ AssetCatalogFilter filter = service.create_catalog_filter(unknown_uuid);
+ EXPECT_TRUE(filter.contains(unknown_uuid));
+
+ EXPECT_FALSE(filter.contains(BLI_uuid_nil())) << "Nil catalog should not be included.";
+ EXPECT_FALSE(filter.contains(UUID_POSES_ELLIE));
+}
+
+TEST_F(AssetCatalogTest, create_catalog_filter_for_unassigned_assets)
+{
+ AssetCatalogService service;
+
+ AssetCatalogFilter filter = service.create_catalog_filter(BLI_uuid_nil());
+ EXPECT_TRUE(filter.contains(BLI_uuid_nil()));
+ EXPECT_FALSE(filter.contains(UUID_POSES_ELLIE));
+}
+
+TEST_F(AssetCatalogTest, cat_collection_deep_copy__empty)
+{
+ const AssetCatalogCollection empty;
+ auto copy = empty.deep_copy();
+ EXPECT_NE(&empty, copy.get());
+}
+
+class TestableAssetCatalogCollection : public AssetCatalogCollection {
+ public:
+ OwningAssetCatalogMap &get_catalogs()
+ {
+ return catalogs_;
+ }
+ OwningAssetCatalogMap &get_deleted_catalogs()
+ {
+ return deleted_catalogs_;
+ }
+ AssetCatalogDefinitionFile *get_catalog_definition_file()
+ {
+ return catalog_definition_file_.get();
+ }
+ AssetCatalogDefinitionFile *allocate_catalog_definition_file()
+ {
+ catalog_definition_file_ = std::make_unique<AssetCatalogDefinitionFile>();
+ return get_catalog_definition_file();
+ }
+};
+
+TEST_F(AssetCatalogTest, cat_collection_deep_copy__nonempty_nocdf)
+{
+ TestableAssetCatalogCollection catcoll;
+ auto cat1 = std::make_unique<AssetCatalog>(UUID_POSES_RUZENA, "poses/Henrik", "");
+ auto cat2 = std::make_unique<AssetCatalog>(UUID_POSES_RUZENA_FACE, "poses/Henrik/face", "");
+ auto cat3 = std::make_unique<AssetCatalog>(UUID_POSES_RUZENA_HAND, "poses/Henrik/hands", "");
+ cat3->flags.is_deleted = true;
+
+ AssetCatalog *cat1_ptr = cat1.get();
+ AssetCatalog *cat3_ptr = cat3.get();
+
+ catcoll.get_catalogs().add_new(cat1->catalog_id, std::move(cat1));
+ catcoll.get_catalogs().add_new(cat2->catalog_id, std::move(cat2));
+ catcoll.get_deleted_catalogs().add_new(cat3->catalog_id, std::move(cat3));
+
+ auto copy = catcoll.deep_copy();
+ EXPECT_NE(&catcoll, copy.get());
+
+ TestableAssetCatalogCollection *testcopy = reinterpret_cast<TestableAssetCatalogCollection *>(
+ copy.get());
+
+ /* Test catalogs & deleted catalogs. */
+ EXPECT_EQ(2, testcopy->get_catalogs().size());
+ EXPECT_EQ(1, testcopy->get_deleted_catalogs().size());
+
+ ASSERT_TRUE(testcopy->get_catalogs().contains(UUID_POSES_RUZENA));
+ ASSERT_TRUE(testcopy->get_catalogs().contains(UUID_POSES_RUZENA_FACE));
+ ASSERT_TRUE(testcopy->get_deleted_catalogs().contains(UUID_POSES_RUZENA_HAND));
+
+ EXPECT_NE(nullptr, testcopy->get_catalogs().lookup(UUID_POSES_RUZENA));
+ EXPECT_NE(cat1_ptr, testcopy->get_catalogs().lookup(UUID_POSES_RUZENA).get())
+ << "AssetCatalogs should be actual copies.";
+
+ EXPECT_NE(nullptr, testcopy->get_deleted_catalogs().lookup(UUID_POSES_RUZENA_HAND));
+ EXPECT_NE(cat3_ptr, testcopy->get_deleted_catalogs().lookup(UUID_POSES_RUZENA_HAND).get())
+ << "AssetCatalogs should be actual copies.";
+}
+
+class TestableAssetCatalogDefinitionFile : public AssetCatalogDefinitionFile {
+ public:
+ Map<CatalogID, AssetCatalog *> get_catalogs()
+ {
+ return catalogs_;
+ }
+};
+
+TEST_F(AssetCatalogTest, cat_collection_deep_copy__nonempty_cdf)
+{
+ TestableAssetCatalogCollection catcoll;
+ auto cat1 = std::make_unique<AssetCatalog>(UUID_POSES_RUZENA, "poses/Henrik", "");
+ auto cat2 = std::make_unique<AssetCatalog>(UUID_POSES_RUZENA_FACE, "poses/Henrik/face", "");
+ auto cat3 = std::make_unique<AssetCatalog>(UUID_POSES_RUZENA_HAND, "poses/Henrik/hands", "");
+ cat3->flags.is_deleted = true;
+
+ AssetCatalog *cat1_ptr = cat1.get();
+ AssetCatalog *cat2_ptr = cat2.get();
+ AssetCatalog *cat3_ptr = cat3.get();
+
+ catcoll.get_catalogs().add_new(cat1->catalog_id, std::move(cat1));
+ catcoll.get_catalogs().add_new(cat2->catalog_id, std::move(cat2));
+ catcoll.get_deleted_catalogs().add_new(cat3->catalog_id, std::move(cat3));
+
+ AssetCatalogDefinitionFile *cdf = catcoll.allocate_catalog_definition_file();
+ cdf->file_path = "path/to/somewhere.cats.txt";
+ cdf->add_new(cat1_ptr);
+ cdf->add_new(cat2_ptr);
+ cdf->add_new(cat3_ptr);
+
+ /* Test CDF remapping. */
+ auto copy = catcoll.deep_copy();
+ TestableAssetCatalogCollection *testable_copy = static_cast<TestableAssetCatalogCollection *>(
+ copy.get());
+
+ TestableAssetCatalogDefinitionFile *cdf_copy = static_cast<TestableAssetCatalogDefinitionFile *>(
+ testable_copy->get_catalog_definition_file());
+ EXPECT_EQ(testable_copy->get_catalogs().lookup(UUID_POSES_RUZENA).get(),
+ cdf_copy->get_catalogs().lookup(UUID_POSES_RUZENA))
+ << "AssetCatalog pointers should have been remapped to the copy.";
+
+ EXPECT_EQ(testable_copy->get_deleted_catalogs().lookup(UUID_POSES_RUZENA_HAND).get(),
+ cdf_copy->get_catalogs().lookup(UUID_POSES_RUZENA_HAND))
+ << "Deleted AssetCatalog pointers should have been remapped to the copy.";
+}
+
+TEST_F(AssetCatalogTest, undo_redo_one_step)
+{
+ TestableAssetCatalogService service(asset_library_root_);
+ service.load_from_disk();
+
+ EXPECT_FALSE(service.is_undo_possbile());
+ EXPECT_FALSE(service.is_redo_possbile());
+
+ service.create_catalog("some/catalog/path");
+ EXPECT_FALSE(service.is_undo_possbile())
+ << "Undo steps should be created explicitly, and not after creating any catalog.";
+
+ service.undo_push();
+ const bUUID other_catalog_id = service.create_catalog("other/catalog/path")->catalog_id;
+ EXPECT_TRUE(service.is_undo_possbile())
+ << "Undo should be possible after creating an undo snapshot.";
+
+ /* Undo the creation of the catalog. */
+ service.undo();
+ EXPECT_FALSE(service.is_undo_possbile())
+ << "Undoing the only stored step should make it impossible to undo further.";
+ EXPECT_TRUE(service.is_redo_possbile()) << "Undoing a step should make redo possible.";
+ EXPECT_EQ(nullptr, service.find_catalog_by_path("other/catalog/path"))
+ << "Undone catalog should not exist after undo.";
+ EXPECT_NE(nullptr, service.find_catalog_by_path("some/catalog/path"))
+ << "First catalog should still exist after undo.";
+ EXPECT_FALSE(service.get_catalog_definition_file()->contains(other_catalog_id))
+ << "The CDF should also not contain the undone catalog.";
+
+ /* Redo the creation of the catalog. */
+ service.redo();
+ EXPECT_TRUE(service.is_undo_possbile())
+ << "Undoing and then redoing a step should make it possible to undo again.";
+ EXPECT_FALSE(service.is_redo_possbile())
+ << "Undoing and then redoing a step should make redo impossible.";
+ EXPECT_NE(nullptr, service.find_catalog_by_path("other/catalog/path"))
+ << "Redone catalog should exist after redo.";
+ EXPECT_NE(nullptr, service.find_catalog_by_path("some/catalog/path"))
+ << "First catalog should still exist after redo.";
+ EXPECT_TRUE(service.get_catalog_definition_file()->contains(other_catalog_id))
+ << "The CDF should contain the redone catalog.";
+}
+
+TEST_F(AssetCatalogTest, undo_redo_more_complex)
{
- const AssetCatalog cat(BLI_uuid_generate_random(), "simple/path/child", "");
+ TestableAssetCatalogService service(asset_library_root_);
+ service.load_from_disk();
+
+ service.undo_push();
+ service.find_catalog(UUID_POSES_ELLIE_WHITESPACE)->simple_name = "Edited simple name";
+
+ service.undo_push();
+ service.find_catalog(UUID_POSES_ELLIE)->path = "poselib/EllieWithEditedPath";
+
+ service.undo();
+ service.undo();
+
+ service.undo_push();
+ service.find_catalog(UUID_POSES_ELLIE)->simple_name = "Ellie Simple";
- EXPECT_FALSE(cat.is_contained_in("unrelated"));
- EXPECT_FALSE(cat.is_contained_in("sim"));
- EXPECT_FALSE(cat.is_contained_in("simple/pathx"));
- EXPECT_FALSE(cat.is_contained_in("simple/path/c"));
- EXPECT_FALSE(cat.is_contained_in("simple/path/child/grandchild"));
- EXPECT_FALSE(cat.is_contained_in("simple/path/"))
- << "Non-normalized paths are not expected to work.";
+ EXPECT_FALSE(service.is_redo_possbile())
+ << "After storing an undo snapshot, the redo buffer should be empty.";
+ EXPECT_TRUE(service.is_undo_possbile())
+ << "After storing an undo snapshot, undoing should be possible";
- EXPECT_TRUE(cat.is_contained_in(""));
- EXPECT_TRUE(cat.is_contained_in("simple"));
- EXPECT_TRUE(cat.is_contained_in("simple/path"));
+ EXPECT_EQ(service.find_catalog(UUID_POSES_ELLIE)->simple_name, "Ellie Simple"); /* Not undone. */
+ EXPECT_EQ(service.find_catalog(UUID_POSES_ELLIE_WHITESPACE)->simple_name,
+ "POSES_ELLIE WHITESPACE"); /* Undone. */
+ EXPECT_EQ(service.find_catalog(UUID_POSES_ELLIE)->path, "character/Ellie/poselib"); /* Undone. */
}
} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/asset_library.cc b/source/blender/blenkernel/intern/asset_library.cc
index 1086efe45fd..74de9b93c25 100644
--- a/source/blender/blenkernel/intern/asset_library.cc
+++ b/source/blender/blenkernel/intern/asset_library.cc
@@ -18,18 +18,20 @@
* \ingroup bke
*/
+#include <memory>
+
#include "BKE_asset_library.hh"
-#include "BKE_callbacks.h"
#include "BKE_main.h"
#include "BKE_preferences.h"
#include "BLI_path_util.h"
+#include "DNA_asset_types.h"
#include "DNA_userdef_types.h"
-#include "MEM_guardedalloc.h"
+#include "asset_library_service.hh"
-#include <memory>
+bool blender::bke::AssetLibrary::save_catalogs_when_file_is_saved = true;
/**
* Loading an asset library at this point only means loading the catalogs. Later on this should
@@ -37,17 +39,21 @@
*/
struct AssetLibrary *BKE_asset_library_load(const char *library_path)
{
- blender::bke::AssetLibrary *lib = new blender::bke::AssetLibrary();
- lib->on_save_handler_register();
- lib->load(library_path);
+ blender::bke::AssetLibraryService *service = blender::bke::AssetLibraryService::get();
+ blender::bke::AssetLibrary *lib;
+ if (library_path == nullptr || library_path[0] == '\0') {
+ lib = service->get_asset_library_current_file();
+ }
+ else {
+ lib = service->get_asset_library_on_disk(library_path);
+ }
return reinterpret_cast<struct AssetLibrary *>(lib);
}
-void BKE_asset_library_free(struct AssetLibrary *asset_library)
+bool BKE_asset_library_has_any_unsaved_catalogs()
{
- blender::bke::AssetLibrary *lib = reinterpret_cast<blender::bke::AssetLibrary *>(asset_library);
- lib->on_save_handler_unregister();
- delete lib;
+ blender::bke::AssetLibraryService *service = blender::bke::AssetLibraryService::get();
+ return service->has_any_unsaved_catalogs();
}
bool BKE_asset_library_find_suitable_root_path_from_path(const char *input_path,
@@ -65,11 +71,52 @@ bool BKE_asset_library_find_suitable_root_path_from_path(const char *input_path,
bool BKE_asset_library_find_suitable_root_path_from_main(const Main *bmain, char *r_library_path)
{
- return BKE_asset_library_find_suitable_root_path_from_path(bmain->name, r_library_path);
+ return BKE_asset_library_find_suitable_root_path_from_path(bmain->filepath, r_library_path);
+}
+
+blender::bke::AssetCatalogService *BKE_asset_library_get_catalog_service(
+ const ::AssetLibrary *library_c)
+{
+ if (library_c == nullptr) {
+ return nullptr;
+ }
+
+ const blender::bke::AssetLibrary &library = reinterpret_cast<const blender::bke::AssetLibrary &>(
+ *library_c);
+ return library.catalog_service.get();
+}
+
+blender::bke::AssetCatalogTree *BKE_asset_library_get_catalog_tree(const ::AssetLibrary *library)
+{
+ blender::bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(
+ library);
+ if (catalog_service == nullptr) {
+ return nullptr;
+ }
+
+ return catalog_service->get_catalog_tree();
+}
+
+void BKE_asset_library_refresh_catalog_simplename(struct AssetLibrary *asset_library,
+ struct AssetMetaData *asset_data)
+{
+ blender::bke::AssetLibrary *lib = reinterpret_cast<blender::bke::AssetLibrary *>(asset_library);
+ lib->refresh_catalog_simplename(asset_data);
}
namespace blender::bke {
+AssetLibrary::AssetLibrary() : catalog_service(std::make_unique<AssetCatalogService>())
+{
+}
+
+AssetLibrary::~AssetLibrary()
+{
+ if (on_save_callback_store_.func) {
+ on_blend_save_handler_unregister();
+ }
+}
+
void AssetLibrary::load(StringRefNull library_root_directory)
{
auto catalog_service = std::make_unique<AssetCatalogService>(library_root_directory);
@@ -77,6 +124,11 @@ void AssetLibrary::load(StringRefNull library_root_directory)
this->catalog_service = std::move(catalog_service);
}
+void AssetLibrary::refresh()
+{
+ this->catalog_service->reload_catalogs();
+}
+
namespace {
void asset_library_on_save_post(struct Main *main,
struct PointerRNA **pointers,
@@ -84,11 +136,12 @@ void asset_library_on_save_post(struct Main *main,
void *arg)
{
AssetLibrary *asset_lib = static_cast<AssetLibrary *>(arg);
- asset_lib->on_save_post(main, pointers, num_pointers);
+ asset_lib->on_blend_save_post(main, pointers, num_pointers);
}
+
} // namespace
-void AssetLibrary::on_save_handler_register()
+void AssetLibrary::on_blend_save_handler_register()
{
/* The callback system doesn't own `on_save_callback_store_`. */
on_save_callback_store_.alloc = false;
@@ -99,20 +152,38 @@ void AssetLibrary::on_save_handler_register()
BKE_callback_add(&on_save_callback_store_, BKE_CB_EVT_SAVE_POST);
}
-void AssetLibrary::on_save_handler_unregister()
+void AssetLibrary::on_blend_save_handler_unregister()
{
BKE_callback_remove(&on_save_callback_store_, BKE_CB_EVT_SAVE_POST);
+ on_save_callback_store_.func = nullptr;
+ on_save_callback_store_.arg = nullptr;
}
-void AssetLibrary::on_save_post(struct Main *main,
- struct PointerRNA ** /*pointers*/,
- const int /*num_pointers*/)
+void AssetLibrary::on_blend_save_post(struct Main *main,
+ struct PointerRNA ** /*pointers*/,
+ const int /*num_pointers*/)
{
if (this->catalog_service == nullptr) {
return;
}
- this->catalog_service->write_to_disk_on_blendfile_save(main->name);
+ if (save_catalogs_when_file_is_saved) {
+ this->catalog_service->write_to_disk(main->filepath);
+ }
}
+void AssetLibrary::refresh_catalog_simplename(struct AssetMetaData *asset_data)
+{
+ if (BLI_uuid_is_nil(asset_data->catalog_id)) {
+ asset_data->catalog_simple_name[0] = '\0';
+ return;
+ }
+ const AssetCatalog *catalog = this->catalog_service->find_catalog(asset_data->catalog_id);
+ if (catalog == nullptr) {
+ /* No-op if the catalog cannot be found. This could be the kind of "the catalog definition file
+ * is corrupt/lost" scenario that the simple name is meant to help recover from. */
+ return;
+ }
+ STRNCPY(asset_data->catalog_simple_name, catalog->simple_name.c_str());
+}
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/asset_library_service.cc b/source/blender/blenkernel/intern/asset_library_service.cc
new file mode 100644
index 00000000000..6b3f1fa3408
--- /dev/null
+++ b/source/blender/blenkernel/intern/asset_library_service.cc
@@ -0,0 +1,161 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "asset_library_service.hh"
+
+#include "BKE_blender.h"
+
+#include "BLI_fileops.h" /* For PATH_MAX (at least on Windows). */
+#include "BLI_path_util.h"
+#include "BLI_string_ref.hh"
+
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"bke.asset_service"};
+
+namespace blender::bke {
+
+std::unique_ptr<AssetLibraryService> AssetLibraryService::instance_;
+bool AssetLibraryService::atexit_handler_registered_ = false;
+
+AssetLibraryService *AssetLibraryService::get()
+{
+ if (!instance_) {
+ allocate_service_instance();
+ }
+ return instance_.get();
+}
+
+void AssetLibraryService::destroy()
+{
+ if (!instance_) {
+ return;
+ }
+ instance_->app_handler_unregister();
+ instance_.reset();
+}
+
+namespace {
+std::string normalize_directory_path(StringRefNull directory)
+{
+
+ char dir_normalized[PATH_MAX];
+ STRNCPY(dir_normalized, directory.c_str());
+ BLI_path_normalize_dir(nullptr, dir_normalized);
+ return std::string(dir_normalized);
+}
+} // namespace
+
+AssetLibrary *AssetLibraryService::get_asset_library_on_disk(StringRefNull top_level_directory)
+{
+ BLI_assert_msg(!top_level_directory.is_empty(),
+ "top level directory must be given for on-disk asset library");
+
+ std::string top_dir_trailing_slash = normalize_directory_path(top_level_directory);
+
+ AssetLibraryPtr *lib_uptr_ptr = on_disk_libraries_.lookup_ptr(top_dir_trailing_slash);
+ if (lib_uptr_ptr != nullptr) {
+ CLOG_INFO(&LOG, 2, "get \"%s\" (cached)", top_dir_trailing_slash.c_str());
+ AssetLibrary *lib = lib_uptr_ptr->get();
+ lib->refresh();
+ return lib;
+ }
+
+ AssetLibraryPtr lib_uptr = std::make_unique<AssetLibrary>();
+ AssetLibrary *lib = lib_uptr.get();
+
+ lib->on_blend_save_handler_register();
+ lib->load(top_dir_trailing_slash);
+
+ on_disk_libraries_.add_new(top_dir_trailing_slash, std::move(lib_uptr));
+ CLOG_INFO(&LOG, 2, "get \"%s\" (loaded)", top_dir_trailing_slash.c_str());
+ return lib;
+}
+
+AssetLibrary *AssetLibraryService::get_asset_library_current_file()
+{
+ if (current_file_library_) {
+ CLOG_INFO(&LOG, 2, "get current file lib (cached)");
+ }
+ else {
+ CLOG_INFO(&LOG, 2, "get current file lib (loaded)");
+ current_file_library_ = std::make_unique<AssetLibrary>();
+ current_file_library_->on_blend_save_handler_register();
+ }
+
+ AssetLibrary *lib = current_file_library_.get();
+ return lib;
+}
+
+void AssetLibraryService::allocate_service_instance()
+{
+ instance_ = std::make_unique<AssetLibraryService>();
+ instance_->app_handler_register();
+
+ if (!atexit_handler_registered_) {
+ /* Ensure the instance gets freed before Blender's memory leak detector runs. */
+ BKE_blender_atexit_register([](void * /*user_data*/) { AssetLibraryService::destroy(); },
+ nullptr);
+ atexit_handler_registered_ = true;
+ }
+}
+
+static void on_blendfile_load(struct Main * /*bMain*/,
+ struct PointerRNA ** /*pointers*/,
+ const int /*num_pointers*/,
+ void * /*arg*/)
+{
+ AssetLibraryService::destroy();
+}
+
+void AssetLibraryService::app_handler_register()
+{
+ /* The callback system doesn't own `on_load_callback_store_`. */
+ on_load_callback_store_.alloc = false;
+
+ on_load_callback_store_.func = &on_blendfile_load;
+ on_load_callback_store_.arg = this;
+
+ BKE_callback_add(&on_load_callback_store_, BKE_CB_EVT_LOAD_PRE);
+}
+
+void AssetLibraryService::app_handler_unregister()
+{
+ BKE_callback_remove(&on_load_callback_store_, BKE_CB_EVT_LOAD_PRE);
+ on_load_callback_store_.func = nullptr;
+ on_load_callback_store_.arg = nullptr;
+}
+
+bool AssetLibraryService::has_any_unsaved_catalogs() const
+{
+ if (current_file_library_ && current_file_library_->catalog_service->has_unsaved_changes()) {
+ return true;
+ }
+
+ for (const auto &asset_lib_uptr : on_disk_libraries_.values()) {
+ if (asset_lib_uptr->catalog_service->has_unsaved_changes()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/asset_library_service.hh b/source/blender/blenkernel/intern/asset_library_service.hh
new file mode 100644
index 00000000000..03df706bc42
--- /dev/null
+++ b/source/blender/blenkernel/intern/asset_library_service.hh
@@ -0,0 +1,93 @@
+/*
+ * 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
+ */
+
+#pragma once
+
+#ifndef __cplusplus
+# error This is a C++-only header file.
+#endif
+
+#include "BKE_asset_library.hh"
+
+#include "BLI_map.hh"
+
+#include <memory>
+
+namespace blender::bke {
+
+/**
+ * Global singleton-ish that provides access to individual #AssetLibrary instances.
+ *
+ * Whenever a blend file is loaded, the existing instance of AssetLibraryService is destructed, and
+ * a new one is created -- hence the "singleton-ish". This ensures only information about relevant
+ * asset libraries is loaded.
+ *
+ * \note How Asset libraries are identified may change in the future.
+ * For now they are assumed to be:
+ * - on disk (identified by the absolute directory), or
+ * - the "current file" library (which is in memory but could have catalogs
+ * loaded from a file on disk).
+ */
+class AssetLibraryService {
+ public:
+ using AssetLibraryPtr = std::unique_ptr<AssetLibrary>;
+
+ AssetLibraryService() = default;
+ ~AssetLibraryService() = default;
+
+ /** Return the AssetLibraryService singleton, allocating it if necessary. */
+ static AssetLibraryService *get();
+
+ /** Destroy the AssetLibraryService singleton. It will be reallocated by #get() if necessary. */
+ static void destroy();
+
+ /**
+ * Get the given asset library. Opens it (i.e. creates a new AssetLibrary instance) if necessary.
+ */
+ AssetLibrary *get_asset_library_on_disk(StringRefNull top_level_directory);
+
+ /** Get the "Current File" asset library. */
+ AssetLibrary *get_asset_library_current_file();
+
+ /** Returns whether there are any known asset libraries with unsaved catalog edits. */
+ bool has_any_unsaved_catalogs() const;
+
+ protected:
+ static std::unique_ptr<AssetLibraryService> instance_;
+
+ /* Mapping absolute path of the library's top-level directory to the AssetLibrary instance. */
+ Map<std::string, AssetLibraryPtr> on_disk_libraries_;
+ AssetLibraryPtr current_file_library_;
+
+ /* Handlers for managing the life cycle of the AssetLibraryService instance. */
+ bCallbackFuncStore on_load_callback_store_;
+ static bool atexit_handler_registered_;
+
+ /** Allocate a new instance of the service and assign it to `instance_`. */
+ static void allocate_service_instance();
+
+ /**
+ * Ensure the AssetLibraryService instance is destroyed before a new blend file is loaded.
+ * This makes memory management simple, and ensures a fresh start for every blend file. */
+ void app_handler_register();
+ void app_handler_unregister();
+};
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/asset_library_service_test.cc b/source/blender/blenkernel/intern/asset_library_service_test.cc
new file mode 100644
index 00000000000..9fa6d100a53
--- /dev/null
+++ b/source/blender/blenkernel/intern/asset_library_service_test.cc
@@ -0,0 +1,214 @@
+/*
+ * 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) 2020 Blender Foundation
+ * All rights reserved.
+ */
+
+#include "asset_library_service.hh"
+
+#include "BLI_fileops.h" /* For PATH_MAX (at least on Windows). */
+#include "BLI_path_util.h"
+
+#include "BKE_appdir.h"
+#include "BKE_callbacks.h"
+
+#include "CLG_log.h"
+
+#include "testing/testing.h"
+
+namespace blender::bke::tests {
+
+const bUUID UUID_POSES_ELLIE("df60e1f6-2259-475b-93d9-69a1b4a8db78");
+
+class AssetLibraryServiceTest : public testing::Test {
+ public:
+ CatalogFilePath asset_library_root_;
+ CatalogFilePath temp_library_path_;
+
+ static void SetUpTestSuite()
+ {
+ CLG_init();
+ BKE_callback_global_init();
+ }
+ static void TearDownTestSuite()
+ {
+ CLG_exit();
+ BKE_callback_global_finalize();
+ }
+
+ void SetUp() override
+ {
+ const std::string test_files_dir = blender::tests::flags_test_asset_dir();
+ if (test_files_dir.empty()) {
+ FAIL();
+ }
+ asset_library_root_ = test_files_dir + "/" + "asset_library";
+ temp_library_path_ = "";
+ }
+
+ void TearDown() override
+ {
+ AssetLibraryService::destroy();
+
+ if (!temp_library_path_.empty()) {
+ BLI_delete(temp_library_path_.c_str(), true, true);
+ temp_library_path_ = "";
+ }
+ }
+
+ /* Register a temporary path, which will be removed at the end of the test.
+ * The returned path ends in a slash. */
+ CatalogFilePath use_temp_path()
+ {
+ BKE_tempdir_init("");
+ const CatalogFilePath tempdir = BKE_tempdir_session();
+ temp_library_path_ = tempdir + "test-temporary-path/";
+ return temp_library_path_;
+ }
+
+ CatalogFilePath create_temp_path()
+ {
+ CatalogFilePath path = use_temp_path();
+ BLI_dir_create_recursive(path.c_str());
+ return path;
+ }
+};
+
+TEST_F(AssetLibraryServiceTest, get_destroy)
+{
+ AssetLibraryService *const service = AssetLibraryService::get();
+ EXPECT_EQ(service, AssetLibraryService::get())
+ << "Calling twice without destroying in between should return the same instance.";
+
+ /* This should not crash. */
+ AssetLibraryService::destroy();
+ AssetLibraryService::destroy();
+
+ /* NOTE: there used to be a test for the opposite here, that after a call to
+ * AssetLibraryService::destroy() the above calls should return freshly allocated objects. This
+ * cannot be reliably tested by just pointer comparison, though. */
+}
+
+TEST_F(AssetLibraryServiceTest, library_pointers)
+{
+ AssetLibraryService *service = AssetLibraryService::get();
+ AssetLibrary *const lib = service->get_asset_library_on_disk(asset_library_root_);
+ AssetLibrary *const curfile_lib = service->get_asset_library_current_file();
+
+ EXPECT_EQ(lib, service->get_asset_library_on_disk(asset_library_root_))
+ << "Calling twice without destroying in between should return the same instance.";
+ EXPECT_EQ(curfile_lib, service->get_asset_library_current_file())
+ << "Calling twice without destroying in between should return the same instance.";
+
+ /* NOTE: there used to be a test for the opposite here, that after a call to
+ * AssetLibraryService::destroy() the above calls should return freshly allocated objects. This
+ * cannot be reliably tested by just pointer comparison, though. */
+}
+
+TEST_F(AssetLibraryServiceTest, library_path_trailing_slashes)
+{
+ AssetLibraryService *service = AssetLibraryService::get();
+
+ char asset_lib_no_slash[PATH_MAX];
+ char asset_lib_with_slash[PATH_MAX];
+ STRNCPY(asset_lib_no_slash, asset_library_root_.c_str());
+ STRNCPY(asset_lib_with_slash, asset_library_root_.c_str());
+
+ /* Ensure #asset_lib_no_slash has no trailing slash, regardless of what was passed on the CLI to
+ * the unit test. */
+ while (strlen(asset_lib_no_slash) &&
+ ELEM(asset_lib_no_slash[strlen(asset_lib_no_slash) - 1], SEP, ALTSEP)) {
+ asset_lib_no_slash[strlen(asset_lib_no_slash) - 1] = '\0';
+ }
+
+ BLI_path_slash_ensure(asset_lib_with_slash);
+
+ AssetLibrary *const lib_no_slash = service->get_asset_library_on_disk(asset_lib_no_slash);
+
+ EXPECT_EQ(lib_no_slash, service->get_asset_library_on_disk(asset_lib_with_slash))
+ << "With or without trailing slash shouldn't matter.";
+}
+
+TEST_F(AssetLibraryServiceTest, catalogs_loaded)
+{
+ AssetLibraryService *const service = AssetLibraryService::get();
+ AssetLibrary *const lib = service->get_asset_library_on_disk(asset_library_root_);
+ AssetCatalogService *const cat_service = lib->catalog_service.get();
+
+ const bUUID UUID_POSES_ELLIE("df60e1f6-2259-475b-93d9-69a1b4a8db78");
+ EXPECT_NE(nullptr, cat_service->find_catalog(UUID_POSES_ELLIE))
+ << "Catalogs should be loaded after getting an asset library from disk.";
+}
+
+TEST_F(AssetLibraryServiceTest, has_any_unsaved_catalogs)
+{
+ AssetLibraryService *const service = AssetLibraryService::get();
+ EXPECT_FALSE(service->has_any_unsaved_catalogs())
+ << "Empty AssetLibraryService should have no unsaved catalogs";
+
+ AssetLibrary *const lib = service->get_asset_library_on_disk(asset_library_root_);
+ AssetCatalogService *const cat_service = lib->catalog_service.get();
+ EXPECT_FALSE(service->has_any_unsaved_catalogs())
+ << "Unchanged AssetLibrary should have no unsaved catalogs";
+
+ const bUUID UUID_POSES_ELLIE("df60e1f6-2259-475b-93d9-69a1b4a8db78");
+ cat_service->prune_catalogs_by_id(UUID_POSES_ELLIE);
+ EXPECT_FALSE(service->has_any_unsaved_catalogs())
+ << "Deletion of catalogs via AssetCatalogService should not automatically tag as 'unsaved "
+ "changes'.";
+
+ const bUUID UUID_POSES_RUZENA("79a4f887-ab60-4bd4-94da-d572e27d6aed");
+ AssetCatalog *cat = cat_service->find_catalog(UUID_POSES_RUZENA);
+ ASSERT_NE(nullptr, cat) << "Catalog " << UUID_POSES_RUZENA << " should be known";
+
+ cat_service->tag_has_unsaved_changes(cat);
+ EXPECT_TRUE(service->has_any_unsaved_catalogs())
+ << "Tagging as having unsaved changes of a single catalog service should result in unsaved "
+ "changes being reported.";
+ EXPECT_TRUE(cat->flags.has_unsaved_changes);
+}
+
+TEST_F(AssetLibraryServiceTest, has_any_unsaved_catalogs_after_write)
+{
+ const CatalogFilePath writable_dir = create_temp_path(); /* Has trailing slash. */
+ const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
+ CatalogFilePath writable_cdf_file = writable_dir + AssetCatalogService::DEFAULT_CATALOG_FILENAME;
+ BLI_path_slash_native(writable_cdf_file.data());
+ ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str()));
+
+ AssetLibraryService *const service = AssetLibraryService::get();
+ AssetLibrary *const lib = service->get_asset_library_on_disk(writable_dir);
+
+ EXPECT_FALSE(service->has_any_unsaved_catalogs())
+ << "Unchanged AssetLibrary should have no unsaved catalogs";
+
+ AssetCatalogService *const cat_service = lib->catalog_service.get();
+ AssetCatalog *cat = cat_service->find_catalog(UUID_POSES_ELLIE);
+
+ cat_service->tag_has_unsaved_changes(cat);
+
+ EXPECT_TRUE(service->has_any_unsaved_catalogs())
+ << "Tagging as having unsaved changes of a single catalog service should result in unsaved "
+ "changes being reported.";
+ EXPECT_TRUE(cat->flags.has_unsaved_changes);
+
+ cat_service->write_to_disk(writable_dir + "dummy_path.blend");
+ EXPECT_FALSE(service->has_any_unsaved_catalogs())
+ << "Written AssetCatalogService should have no unsaved catalogs";
+ EXPECT_FALSE(cat->flags.has_unsaved_changes);
+}
+
+} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/asset_library_test.cc b/source/blender/blenkernel/intern/asset_library_test.cc
index 37686175aed..702008fed96 100644
--- a/source/blender/blenkernel/intern/asset_library_test.cc
+++ b/source/blender/blenkernel/intern/asset_library_test.cc
@@ -20,12 +20,36 @@
#include "BKE_appdir.h"
#include "BKE_asset_catalog.hh"
#include "BKE_asset_library.hh"
+#include "BKE_callbacks.h"
+
+#include "asset_library_service.hh"
+
+#include "CLG_log.h"
#include "testing/testing.h"
namespace blender::bke::tests {
-TEST(AssetLibraryTest, load_and_free_c_functions)
+class AssetLibraryTest : public testing::Test {
+ public:
+ static void SetUpTestSuite()
+ {
+ CLG_init();
+ BKE_callback_global_init();
+ }
+ static void TearDownTestSuite()
+ {
+ CLG_exit();
+ BKE_callback_global_finalize();
+ }
+
+ void TearDown() override
+ {
+ AssetLibraryService::destroy();
+ }
+};
+
+TEST_F(AssetLibraryTest, bke_asset_library_load)
{
const std::string test_files_dir = blender::tests::flags_test_asset_dir();
if (test_files_dir.empty()) {
@@ -49,12 +73,10 @@ TEST(AssetLibraryTest, load_and_free_c_functions)
const bUUID uuid_poses_ellie("df60e1f6-2259-475b-93d9-69a1b4a8db78");
AssetCatalog *poses_ellie = service->find_catalog(uuid_poses_ellie);
ASSERT_NE(nullptr, poses_ellie) << "unable to find POSES_ELLIE catalog";
- EXPECT_EQ("character/Ellie/poselib", poses_ellie->path);
-
- BKE_asset_library_free(library_c_ptr);
+ EXPECT_EQ("character/Ellie/poselib", poses_ellie->path.str());
}
-TEST(AssetLibraryTest, load_nonexistent_directory)
+TEST_F(AssetLibraryTest, load_nonexistent_directory)
{
const std::string test_files_dir = blender::tests::flags_test_asset_dir();
if (test_files_dir.empty()) {
@@ -75,8 +97,6 @@ TEST(AssetLibraryTest, load_nonexistent_directory)
/* Check that the catalog service doesn't have any catalogs. */
EXPECT_TRUE(service->is_empty());
-
- BKE_asset_library_free(library_c_ptr);
}
} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index c2837b522c4..cc43a3e26a8 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -23,21 +23,20 @@
#include "BKE_geometry_set.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
+#include "BKE_type_conversions.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_pointcloud_types.h"
#include "BLI_color.hh"
-#include "BLI_float2.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "BLT_translation.h"
#include "CLG_log.h"
-#include "NOD_type_conversions.hh"
-
#include "attribute_access_intern.hh"
static CLG_LogRef LOG = {"bke.attribute_access"};
@@ -50,8 +49,7 @@ using blender::bke::AttributeIDRef;
using blender::bke::OutputAttribute;
using blender::fn::GMutableSpan;
using blender::fn::GSpan;
-using blender::fn::GVArray_For_GSpan;
-using blender::fn::GVArray_For_SingleValue;
+using blender::fn::GVArrayImpl_For_GSpan;
namespace blender::bke {
@@ -165,16 +163,18 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_
static int attribute_domain_priority(const AttributeDomain domain)
{
switch (domain) {
- case ATTR_DOMAIN_CURVE:
+ case ATTR_DOMAIN_INSTANCE:
return 0;
- case ATTR_DOMAIN_FACE:
+ case ATTR_DOMAIN_CURVE:
return 1;
- case ATTR_DOMAIN_EDGE:
+ case ATTR_DOMAIN_FACE:
return 2;
- case ATTR_DOMAIN_POINT:
+ case ATTR_DOMAIN_EDGE:
return 3;
- case ATTR_DOMAIN_CORNER:
+ case ATTR_DOMAIN_POINT:
return 4;
+ case ATTR_DOMAIN_CORNER:
+ return 5;
default:
/* Domain not supported in nodes yet. */
BLI_assert_unreachable();
@@ -182,10 +182,6 @@ static int attribute_domain_priority(const AttributeDomain domain)
}
}
-/**
- * Domains with a higher "information density" have a higher priority, in order
- * to choose a domain that will not lose data through domain conversion.
- */
AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
{
int highest_priority = INT_MIN;
@@ -202,6 +198,17 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
return highest_priority_domain;
}
+fn::GMutableSpan OutputAttribute::as_span()
+{
+ if (!optional_span_varray_) {
+ const bool materialize_old_values = !ignore_old_values_;
+ optional_span_varray_ = std::make_unique<fn::GVMutableArray_GSpan>(varray_,
+ materialize_old_values);
+ }
+ fn::GVMutableArray_GSpan &span_varray = *optional_span_varray_;
+ return span_varray;
+}
+
void OutputAttribute::save()
{
save_has_been_called_ = true;
@@ -222,23 +229,140 @@ OutputAttribute::~OutputAttribute()
}
}
-GVArrayPtr BuiltinCustomDataLayerProvider::try_get_for_read(
- const GeometryComponent &component) const
+static AttributeIDRef attribute_id_from_custom_data_layer(const CustomDataLayer &layer)
+{
+ if (layer.anonymous_id != nullptr) {
+ return layer.anonymous_id;
+ }
+ return layer.name;
+}
+
+static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data,
+ const CustomDataType data_type,
+ const int domain_size,
+ const AttributeInit &initializer)
+{
+ switch (initializer.type) {
+ case AttributeInit::Type::Default: {
+ void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size);
+ return data != nullptr;
+ }
+ case AttributeInit::Type::VArray: {
+ void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size);
+ if (data == nullptr) {
+ return false;
+ }
+ const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray;
+ varray.materialize_to_uninitialized(varray.index_range(), data);
+ return true;
+ }
+ case AttributeInit::Type::MoveArray: {
+ void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
+ void *data = CustomData_add_layer(
+ &custom_data, data_type, CD_ASSIGN, source_data, domain_size);
+ if (data == nullptr) {
+ MEM_freeN(source_data);
+ return false;
+ }
+ return true;
+ }
+ }
+
+ BLI_assert_unreachable();
+ return false;
+}
+
+static void *add_generic_custom_data_layer(CustomData &custom_data,
+ const CustomDataType data_type,
+ const eCDAllocType alloctype,
+ void *layer_data,
+ const int domain_size,
+ const AttributeIDRef &attribute_id)
+{
+ if (attribute_id.is_named()) {
+ char attribute_name_c[MAX_NAME];
+ attribute_id.name().copy(attribute_name_c);
+ return CustomData_add_layer_named(
+ &custom_data, data_type, alloctype, layer_data, domain_size, attribute_name_c);
+ }
+ const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id();
+ return CustomData_add_layer_anonymous(
+ &custom_data, data_type, alloctype, layer_data, domain_size, &anonymous_id);
+}
+
+static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id,
+ CustomData &custom_data,
+ const CustomDataType data_type,
+ const int domain_size,
+ const AttributeInit &initializer)
+{
+ switch (initializer.type) {
+ case AttributeInit::Type::Default: {
+ void *data = add_generic_custom_data_layer(
+ custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_id);
+ return data != nullptr;
+ }
+ case AttributeInit::Type::VArray: {
+ void *data = add_generic_custom_data_layer(
+ custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_id);
+ if (data == nullptr) {
+ return false;
+ }
+ const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray;
+ varray.materialize_to_uninitialized(varray.index_range(), data);
+ return true;
+ }
+ case AttributeInit::Type::MoveArray: {
+ void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
+ void *data = add_generic_custom_data_layer(
+ custom_data, data_type, CD_ASSIGN, source_data, domain_size, attribute_id);
+ if (data == nullptr) {
+ MEM_freeN(source_data);
+ return false;
+ }
+ return true;
+ }
+ }
+
+ BLI_assert_unreachable();
+ return false;
+}
+
+static bool custom_data_layer_matches_attribute_id(const CustomDataLayer &layer,
+ const AttributeIDRef &attribute_id)
+{
+ if (!attribute_id) {
+ return false;
+ }
+ if (attribute_id.is_anonymous()) {
+ return layer.anonymous_id == &attribute_id.anonymous_id();
+ }
+ return layer.name == attribute_id.name();
+}
+
+GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const GeometryComponent &component) const
{
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
if (custom_data == nullptr) {
return {};
}
- const int domain_size = component.attribute_domain_size(domain_);
- const void *data = CustomData_get_layer(custom_data, stored_type_);
+ const void *data;
+ if (stored_as_named_attribute_) {
+ data = CustomData_get_layer_named(custom_data, stored_type_, name_.c_str());
+ }
+ else {
+ data = CustomData_get_layer(custom_data, stored_type_);
+ }
if (data == nullptr) {
return {};
}
+
+ const int domain_size = component.attribute_domain_size(domain_);
return as_read_attribute_(data, domain_size);
}
-GVMutableArrayPtr BuiltinCustomDataLayerProvider::try_get_for_write(
+WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write(
GeometryComponent &component) const
{
if (writable_ != Writable) {
@@ -249,19 +373,42 @@ GVMutableArrayPtr BuiltinCustomDataLayerProvider::try_get_for_write(
return {};
}
const int domain_size = component.attribute_domain_size(domain_);
- void *data = CustomData_get_layer(custom_data, stored_type_);
+
+ void *data;
+ if (stored_as_named_attribute_) {
+ data = CustomData_get_layer_named(custom_data, stored_type_, name_.c_str());
+ }
+ else {
+ data = CustomData_get_layer(custom_data, stored_type_);
+ }
if (data == nullptr) {
return {};
}
- void *new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size);
+
+ void *new_data;
+ if (stored_as_named_attribute_) {
+ new_data = CustomData_duplicate_referenced_layer_named(
+ custom_data, stored_type_, name_.c_str(), domain_size);
+ }
+ else {
+ new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size);
+ }
+
if (data != new_data) {
- custom_data_access_.update_custom_data_pointers(component);
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
data = new_data;
}
+
+ std::function<void()> tag_modified_fn;
if (update_on_write_ != nullptr) {
- update_on_write_(component);
+ tag_modified_fn = [component = &component, update = update_on_write_]() {
+ update(*component);
+ };
}
- return as_write_attribute_(data, domain_size);
+
+ return {as_write_attribute_(data, domain_size), domain_, std::move(tag_modified_fn)};
}
bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) const
@@ -275,48 +422,27 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co
}
const int domain_size = component.attribute_domain_size(domain_);
- const int layer_index = CustomData_get_layer_index(custom_data, stored_type_);
+ int layer_index;
+ if (stored_as_named_attribute_) {
+ for (const int i : IndexRange(custom_data->totlayer)) {
+ if (custom_data_layer_matches_attribute_id(custom_data->layers[i], name_)) {
+ layer_index = i;
+ break;
+ }
+ }
+ }
+ else {
+ layer_index = CustomData_get_layer_index(custom_data, stored_type_);
+ }
+
const bool delete_success = CustomData_free_layer(
custom_data, stored_type_, domain_size, layer_index);
if (delete_success) {
- custom_data_access_.update_custom_data_pointers(component);
- }
- return delete_success;
-}
-
-static bool add_custom_data_layer_from_attribute_init(CustomData &custom_data,
- const CustomDataType data_type,
- const int domain_size,
- const AttributeInit &initializer)
-{
- switch (initializer.type) {
- case AttributeInit::Type::Default: {
- void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size);
- return data != nullptr;
- }
- case AttributeInit::Type::VArray: {
- void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size);
- if (data == nullptr) {
- return false;
- }
- const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray;
- varray->materialize_to_uninitialized(IndexRange(varray->size()), data);
- return true;
- }
- case AttributeInit::Type::MoveArray: {
- void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
- void *data = CustomData_add_layer(
- &custom_data, data_type, CD_ASSIGN, source_data, domain_size);
- if (data == nullptr) {
- MEM_freeN(source_data);
- return false;
- }
- return true;
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
}
}
-
- BLI_assert_unreachable();
- return false;
+ return delete_success;
}
bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
@@ -329,16 +455,29 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
if (custom_data == nullptr) {
return false;
}
- if (CustomData_get_layer(custom_data, stored_type_) != nullptr) {
- /* Exists already. */
- return false;
- }
const int domain_size = component.attribute_domain_size(domain_);
- const bool success = add_custom_data_layer_from_attribute_init(
- *custom_data, stored_type_, domain_size, initializer);
+ bool success;
+ if (stored_as_named_attribute_) {
+ if (CustomData_get_layer_named(custom_data, data_type_, name_.c_str())) {
+ /* Exists already. */
+ return false;
+ }
+ success = add_custom_data_layer_from_attribute_init(
+ name_, *custom_data, stored_type_, domain_size, initializer);
+ }
+ else {
+ if (CustomData_get_layer(custom_data, stored_type_) != nullptr) {
+ /* Exists already. */
+ return false;
+ }
+ success = add_builtin_type_custom_data_layer_from_init(
+ *custom_data, stored_type_, domain_size, initializer);
+ }
if (success) {
- custom_data_access_.update_custom_data_pointers(component);
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
}
return success;
}
@@ -349,20 +488,10 @@ bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component)
if (custom_data == nullptr) {
return false;
}
- const void *data = CustomData_get_layer(custom_data, stored_type_);
- return data != nullptr;
-}
-
-static bool custom_data_layer_matches_attribute_id(const CustomDataLayer &layer,
- const AttributeIDRef &attribute_id)
-{
- if (!attribute_id) {
- return false;
+ if (stored_as_named_attribute_) {
+ return CustomData_get_layer_named(custom_data, stored_type_, name_.c_str()) != nullptr;
}
- if (attribute_id.is_anonymous()) {
- return layer.anonymous_id == &attribute_id.anonymous_id();
- }
- return layer.name == attribute_id.name();
+ return CustomData_get_layer(custom_data, stored_type_) != nullptr;
}
ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
@@ -377,23 +506,12 @@ ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) {
continue;
}
- const CustomDataType data_type = (CustomDataType)layer.type;
- switch (data_type) {
- case CD_PROP_FLOAT:
- return this->layer_to_read_attribute<float>(layer, domain_size);
- case CD_PROP_FLOAT2:
- return this->layer_to_read_attribute<float2>(layer, domain_size);
- case CD_PROP_FLOAT3:
- return this->layer_to_read_attribute<float3>(layer, domain_size);
- case CD_PROP_INT32:
- return this->layer_to_read_attribute<int>(layer, domain_size);
- case CD_PROP_COLOR:
- return this->layer_to_read_attribute<ColorGeometry4f>(layer, domain_size);
- case CD_PROP_BOOL:
- return this->layer_to_read_attribute<bool>(layer, domain_size);
- default:
- break;
+ const CPPType *type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
+ if (type == nullptr) {
+ continue;
}
+ GSpan data{*type, layer.data, domain_size};
+ return {GVArray::ForSpan(data), domain_};
}
return {};
}
@@ -418,23 +536,12 @@ WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write(
CustomData_duplicate_referenced_layer_anonymous(
custom_data, layer.type, &attribute_id.anonymous_id(), domain_size);
}
- const CustomDataType data_type = (CustomDataType)layer.type;
- switch (data_type) {
- case CD_PROP_FLOAT:
- return this->layer_to_write_attribute<float>(layer, domain_size);
- case CD_PROP_FLOAT2:
- return this->layer_to_write_attribute<float2>(layer, domain_size);
- case CD_PROP_FLOAT3:
- return this->layer_to_write_attribute<float3>(layer, domain_size);
- case CD_PROP_INT32:
- return this->layer_to_write_attribute<int>(layer, domain_size);
- case CD_PROP_COLOR:
- return this->layer_to_write_attribute<ColorGeometry4f>(layer, domain_size);
- case CD_PROP_BOOL:
- return this->layer_to_write_attribute<bool>(layer, domain_size);
- default:
- break;
+ const CPPType *type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
+ if (type == nullptr) {
+ continue;
}
+ GMutableSpan data{*type, layer.data, domain_size};
+ return {GVMutableArray::ForSpan(data), domain_};
}
return {};
}
@@ -458,62 +565,6 @@ bool CustomDataAttributeProvider::try_delete(GeometryComponent &component,
return false;
}
-static void *add_generic_custom_data_layer(CustomData &custom_data,
- const CustomDataType data_type,
- const eCDAllocType alloctype,
- void *layer_data,
- const int domain_size,
- const AttributeIDRef &attribute_id)
-{
- if (attribute_id.is_named()) {
- char attribute_name_c[MAX_NAME];
- attribute_id.name().copy(attribute_name_c);
- return CustomData_add_layer_named(
- &custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
- }
- const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id();
- return CustomData_add_layer_anonymous(
- &custom_data, data_type, alloctype, layer_data, domain_size, &anonymous_id);
-}
-
-static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id,
- CustomData &custom_data,
- const CustomDataType data_type,
- const int domain_size,
- const AttributeInit &initializer)
-{
- switch (initializer.type) {
- case AttributeInit::Type::Default: {
- void *data = add_generic_custom_data_layer(
- custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_id);
- return data != nullptr;
- }
- case AttributeInit::Type::VArray: {
- void *data = add_generic_custom_data_layer(
- custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_id);
- if (data == nullptr) {
- return false;
- }
- const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray;
- varray->materialize_to_uninitialized(IndexRange(varray->size()), data);
- return true;
- }
- case AttributeInit::Type::MoveArray: {
- void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
- void *data = add_generic_custom_data_layer(
- custom_data, data_type, CD_ASSIGN, source_data, domain_size, attribute_id);
- if (data == nullptr) {
- MEM_freeN(source_data);
- return false;
- }
- return true;
- }
- }
-
- BLI_assert_unreachable();
- return false;
-}
-
bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
const AttributeIDRef &attribute_id,
const AttributeDomain domain,
@@ -552,13 +603,7 @@ bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &com
const CustomDataType data_type = (CustomDataType)layer.type;
if (this->type_is_supported(data_type)) {
AttributeMetaData meta_data{domain_, data_type};
- AttributeIDRef attribute_id;
- if (layer.anonymous_id != nullptr) {
- attribute_id = layer.anonymous_id;
- }
- else {
- attribute_id = layer.name;
- }
+ const AttributeIDRef attribute_id = attribute_id_from_custom_data_layer(layer);
if (!callback(attribute_id, meta_data)) {
return false;
}
@@ -600,7 +645,9 @@ WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write(
void *data_new = CustomData_duplicate_referenced_layer_named(
custom_data, stored_type_, layer.name, domain_size);
if (data_old != data_new) {
- custom_data_access_.update_custom_data_pointers(component);
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
}
return {as_write_attribute_(layer.data, domain_size), domain_};
}
@@ -622,7 +669,9 @@ bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component,
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
const int domain_size = component.attribute_domain_size(domain_);
CustomData_free_layer(custom_data, stored_type_, domain_size, i);
- custom_data_access_.update_custom_data_pointers(component);
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
return true;
}
}
@@ -690,7 +739,6 @@ CustomDataAttributes &CustomDataAttributes::operator=(const CustomDataAttributes
std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id) const
{
- BLI_assert(size_ != 0);
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
const CPPType *cpp_type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
@@ -701,36 +749,29 @@ std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &at
return {};
}
-/**
- * Return a virtual array for a stored attribute, or a single value virtual array with the default
- * value if the attribute doesn't exist. If no default value is provided, the default value for the
- * type will be used.
- */
-GVArrayPtr CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
- const void *default_value) const
+GVArray CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id,
+ const CustomDataType data_type,
+ const void *default_value) const
{
const CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
std::optional<GSpan> attribute = this->get_for_read(attribute_id);
if (!attribute) {
const int domain_size = this->size_;
- return std::make_unique<GVArray_For_SingleValue>(
+ return GVArray::ForSingle(
*type, domain_size, (default_value == nullptr) ? type->default_value() : default_value);
}
if (attribute->type() == *type) {
- return std::make_unique<GVArray_For_GSpan>(*attribute);
+ return GVArray::ForSpan(*attribute);
}
- const blender::nodes::DataTypeConversions &conversions =
- blender::nodes::get_implicit_type_conversions();
- return conversions.try_convert(std::make_unique<GVArray_For_GSpan>(*attribute), *type);
+ const blender::bke::DataTypeConversions &conversions =
+ blender::bke::get_implicit_type_conversions();
+ return conversions.try_convert(GVArray::ForSpan(*attribute), *type);
}
std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeIDRef &attribute_id)
{
- /* If this assert hits, it most likely means that #reallocate was not called at some point. */
- BLI_assert(size_ != 0);
for (CustomDataLayer &layer : MutableSpan(data.layers, data.totlayer)) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
const CPPType *cpp_type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
@@ -777,18 +818,18 @@ void CustomDataAttributes::reallocate(const int size)
CustomData_realloc(&data, size);
}
+void CustomDataAttributes::clear()
+{
+ CustomData_free(&data, size_);
+ size_ = 0;
+}
+
bool CustomDataAttributes::foreach_attribute(const AttributeForeachCallback callback,
const AttributeDomain domain) const
{
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
AttributeMetaData meta_data{domain, (CustomDataType)layer.type};
- AttributeIDRef attribute_id;
- if (layer.anonymous_id != nullptr) {
- attribute_id = layer.anonymous_id;
- }
- else {
- attribute_id = layer.name;
- }
+ const AttributeIDRef attribute_id = attribute_id_from_custom_data_layer(layer);
if (!callback(attribute_id, meta_data)) {
return false;
}
@@ -796,6 +837,26 @@ bool CustomDataAttributes::foreach_attribute(const AttributeForeachCallback call
return true;
}
+void CustomDataAttributes::reorder(Span<AttributeIDRef> new_order)
+{
+ BLI_assert(new_order.size() == data.totlayer);
+
+ Map<AttributeIDRef, int> old_order;
+ old_order.reserve(data.totlayer);
+ Array<CustomDataLayer> old_layers(Span(data.layers, data.totlayer));
+ for (const int i : old_layers.index_range()) {
+ old_order.add_new(attribute_id_from_custom_data_layer(old_layers[i]), i);
+ }
+
+ MutableSpan layers(data.layers, data.totlayer);
+ for (const int i : layers.index_range()) {
+ const int old_index = old_order.lookup(new_order[i]);
+ layers[i] = old_layers[old_index];
+ }
+
+ CustomData_update_typemap(&data);
+}
+
} // namespace blender::bke
/* -------------------------------------------------------------------- */
@@ -863,8 +924,8 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
return {};
}
-std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_adapt_domain(
- std::unique_ptr<blender::fn::GVArray> varray,
+blender::fn::GVArray GeometryComponent::attribute_try_adapt_domain_impl(
+ const blender::fn::GVArray &varray,
const AttributeDomain from_domain,
const AttributeDomain to_domain) const
{
@@ -886,7 +947,7 @@ blender::bke::WriteAttributeLookup GeometryComponent::attribute_try_get_for_writ
const BuiltinAttributeProvider *builtin_provider =
providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr);
if (builtin_provider != nullptr) {
- return {builtin_provider->try_get_for_write(*this), builtin_provider->domain()};
+ return builtin_provider->try_get_for_write(*this);
}
}
for (const DynamicAttributesProvider *dynamic_provider :
@@ -986,10 +1047,6 @@ Set<AttributeIDRef> GeometryComponent::attribute_ids() const
return attributes;
}
-/**
- * \return False if the callback explicitly returned false at any point, otherwise true,
- * meaning the callback made it all the way through.
- */
bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callback) const
{
using namespace blender::bke;
@@ -1051,15 +1108,15 @@ std::optional<AttributeMetaData> GeometryComponent::attribute_get_meta_data(
return result;
}
-static std::unique_ptr<blender::fn::GVArray> try_adapt_data_type(
- std::unique_ptr<blender::fn::GVArray> varray, const blender::fn::CPPType &to_type)
+static blender::fn::GVArray try_adapt_data_type(blender::fn::GVArray varray,
+ const blender::fn::CPPType &to_type)
{
- const blender::nodes::DataTypeConversions &conversions =
- blender::nodes::get_implicit_type_conversions();
+ const blender::bke::DataTypeConversions &conversions =
+ blender::bke::get_implicit_type_conversions();
return conversions.try_convert(std::move(varray), to_type);
}
-std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_read(
+blender::fn::GVArray GeometryComponent::attribute_try_get_for_read(
const AttributeIDRef &attribute_id,
const AttributeDomain domain,
const CustomDataType data_type) const
@@ -1069,8 +1126,8 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r
return {};
}
- std::unique_ptr<blender::fn::GVArray> varray = std::move(attribute.varray);
- if (domain != ATTR_DOMAIN_AUTO && attribute.domain != domain) {
+ blender::fn::GVArray varray = std::move(attribute.varray);
+ if (!ELEM(domain, ATTR_DOMAIN_AUTO, attribute.domain)) {
varray = this->attribute_try_adapt_domain(std::move(varray), attribute.domain, domain);
if (!varray) {
return {};
@@ -1079,7 +1136,7 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r
const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
- if (varray->type() != *cpp_type) {
+ if (varray.type() != *cpp_type) {
varray = try_adapt_data_type(std::move(varray), *cpp_type);
if (!varray) {
return {};
@@ -1089,7 +1146,7 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r
return varray;
}
-std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_try_get_for_read(
+blender::fn::GVArray GeometryComponent::attribute_try_get_for_read(
const AttributeIDRef &attribute_id, const AttributeDomain domain) const
{
if (!this->attribute_domain_supported(domain)) {
@@ -1117,22 +1174,20 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
}
const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(type != nullptr);
- if (attribute.varray->type() == *type) {
+ if (attribute.varray.type() == *type) {
return attribute;
}
- const blender::nodes::DataTypeConversions &conversions =
- blender::nodes::get_implicit_type_conversions();
+ const blender::bke::DataTypeConversions &conversions =
+ blender::bke::get_implicit_type_conversions();
return {conversions.try_convert(std::move(attribute.varray), *type), attribute.domain};
}
-std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read(
- const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value) const
+blender::fn::GVArray GeometryComponent::attribute_get_for_read(const AttributeIDRef &attribute_id,
+ const AttributeDomain domain,
+ const CustomDataType data_type,
+ const void *default_value) const
{
- std::unique_ptr<blender::bke::GVArray> varray = this->attribute_try_get_for_read(
- attribute_id, domain, data_type);
+ blender::fn::GVArray varray = this->attribute_try_get_for_read(attribute_id, domain, data_type);
if (varray) {
return varray;
}
@@ -1141,11 +1196,10 @@ std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read
default_value = type->default_value();
}
const int domain_size = this->attribute_domain_size(domain);
- return std::make_unique<blender::fn::GVArray_For_SingleValue>(*type, domain_size, default_value);
+ return blender::fn::GVArray::ForSingle(*type, domain_size, default_value);
}
-class GVMutableAttribute_For_OutputAttribute
- : public blender::fn::GVMutableArray_For_GMutableSpan {
+class GVMutableAttribute_For_OutputAttribute : public blender::fn::GVArrayImpl_For_GSpan {
public:
GeometryComponent *component;
std::string attribute_name;
@@ -1154,7 +1208,7 @@ class GVMutableAttribute_For_OutputAttribute
GVMutableAttribute_For_OutputAttribute(GMutableSpan data,
GeometryComponent &component,
const AttributeIDRef &attribute_id)
- : blender::fn::GVMutableArray_For_GMutableSpan(data), component(&component)
+ : blender::fn::GVArrayImpl_For_GSpan(data), component(&component)
{
if (attribute_id.is_named()) {
this->attribute_name = attribute_id.name();
@@ -1180,7 +1234,8 @@ static void save_output_attribute(OutputAttribute &output_attribute)
using namespace blender::bke;
GVMutableAttribute_For_OutputAttribute &varray =
- dynamic_cast<GVMutableAttribute_For_OutputAttribute &>(output_attribute.varray());
+ dynamic_cast<GVMutableAttribute_For_OutputAttribute &>(
+ *output_attribute.varray().get_implementation());
GeometryComponent &component = *varray.component;
AttributeIDRef attribute_id;
@@ -1208,10 +1263,24 @@ static void save_output_attribute(OutputAttribute &output_attribute)
BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), buffer);
for (const int i : IndexRange(varray.size())) {
varray.get(i, buffer);
- write_attribute.varray->set_by_relocate(i, buffer);
+ write_attribute.varray.set_by_relocate(i, buffer);
+ }
+ if (write_attribute.tag_modified_fn) {
+ write_attribute.tag_modified_fn();
}
}
+static std::function<void(OutputAttribute &)> get_simple_output_attribute_save_method(
+ const blender::bke::WriteAttributeLookup &attribute)
+{
+ if (!attribute.tag_modified_fn) {
+ return {};
+ }
+ return [tag_modified_fn = attribute.tag_modified_fn](OutputAttribute &UNUSED(attribute)) {
+ tag_modified_fn();
+ };
+}
+
static OutputAttribute create_output_attribute(GeometryComponent &component,
const AttributeIDRef &attribute_id,
const AttributeDomain domain,
@@ -1229,7 +1298,7 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
const CPPType *cpp_type = custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
- const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions();
+ const DataTypeConversions &conversions = get_implicit_type_conversions();
if (component.attribute_is_builtin(attribute_id)) {
const StringRef attribute_name = attribute_id.name();
@@ -1237,9 +1306,9 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
if (!attribute) {
if (default_value) {
const int64_t domain_size = component.attribute_domain_size(domain);
- const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value};
- component.attribute_try_create_builtin(attribute_name,
- AttributeInitVArray(&default_varray));
+ component.attribute_try_create_builtin(
+ attribute_name,
+ AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_size, default_value)));
}
else {
component.attribute_try_create_builtin(attribute_name, AttributeInitDefault());
@@ -1254,14 +1323,20 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
/* Builtin attribute is on different domain. */
return {};
}
- GVMutableArrayPtr varray = std::move(attribute.varray);
- if (varray->type() == *cpp_type) {
+ GVMutableArray varray = std::move(attribute.varray);
+ if (varray.type() == *cpp_type) {
/* Builtin attribute matches exactly. */
- return OutputAttribute(std::move(varray), domain, {}, ignore_old_values);
+ return OutputAttribute(std::move(varray),
+ domain,
+ get_simple_output_attribute_save_method(attribute),
+ ignore_old_values);
}
/* Builtin attribute is on the same domain but has a different data type. */
varray = conversions.try_convert(std::move(varray), *cpp_type);
- return OutputAttribute(std::move(varray), domain, {}, ignore_old_values);
+ return OutputAttribute(std::move(varray),
+ domain,
+ get_simple_output_attribute_save_method(attribute),
+ ignore_old_values);
}
const int domain_size = component.attribute_domain_size(domain);
@@ -1269,9 +1344,11 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_id);
if (!attribute) {
if (default_value) {
- const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value};
component.attribute_try_create(
- attribute_id, domain, data_type, AttributeInitVArray(&default_varray));
+ attribute_id,
+ domain,
+ data_type,
+ AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_size, default_value)));
}
else {
component.attribute_try_create(attribute_id, domain, data_type, AttributeInitDefault());
@@ -1283,9 +1360,13 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
return {};
}
}
- if (attribute.domain == domain && attribute.varray->type() == *cpp_type) {
+ if (attribute.domain == domain && attribute.varray.type() == *cpp_type) {
/* Existing generic attribute matches exactly. */
- return OutputAttribute(std::move(attribute.varray), domain, {}, ignore_old_values);
+
+ return OutputAttribute(std::move(attribute.varray),
+ domain,
+ get_simple_output_attribute_save_method(attribute),
+ ignore_old_values);
}
/* Allocate a new array that lives next to the existing attribute. It will overwrite the existing
@@ -1298,11 +1379,11 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
}
else {
/* Fill the temporary array with values from the existing attribute. */
- GVArrayPtr old_varray = component.attribute_get_for_read(
+ GVArray old_varray = component.attribute_get_for_read(
attribute_id, domain, data_type, default_value);
- old_varray->materialize_to_uninitialized(IndexRange(domain_size), data);
+ old_varray.materialize_to_uninitialized(IndexRange(domain_size), data);
}
- GVMutableArrayPtr varray = std::make_unique<GVMutableAttribute_For_OutputAttribute>(
+ GVMutableArray varray = GVMutableArray::For<GVMutableAttribute_For_OutputAttribute>(
GMutableSpan{*cpp_type, data, domain_size}, component, attribute_id);
return OutputAttribute(std::move(varray), domain, save_output_attribute, true);
@@ -1326,27 +1407,31 @@ OutputAttribute GeometryComponent::attribute_try_get_for_output_only(
namespace blender::bke {
-const GVArray *AttributeFieldInput::get_varray_for_context(const fn::FieldContext &context,
- IndexMask UNUSED(mask),
- ResourceScope &scope) const
+GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope &UNUSED(scope)) const
{
if (const GeometryComponentFieldContext *geometry_context =
dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
const GeometryComponent &component = geometry_context->geometry_component();
const AttributeDomain domain = geometry_context->domain();
- const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
- GVArrayPtr attribute = component.attribute_try_get_for_read(name_, domain, data_type);
- if (attribute) {
- return scope.add(std::move(attribute));
- }
+ return this->get_varray_for_context(component, domain, mask);
}
- return nullptr;
+ return {};
+}
+
+GVArray AttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const
+{
+ const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
+ return component.attribute_try_get_for_read(name_, domain, data_type);
}
std::string AttributeFieldInput::socket_inspection_name() const
{
std::stringstream ss;
- ss << TIP_("Attribute: ") << name_;
+ ss << '"' << name_ << '"' << TIP_(" attribute from geometry");
return ss.str();
}
@@ -1363,25 +1448,62 @@ bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
return false;
}
-const GVArray *AnonymousAttributeFieldInput::get_varray_for_context(
- const fn::FieldContext &context, IndexMask UNUSED(mask), ResourceScope &scope) const
+static StringRef get_random_id_attribute_name(const AttributeDomain domain)
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
- GVArrayPtr attribute = component.attribute_try_get_for_read(
- anonymous_id_.get(), domain, data_type);
- return scope.add(std::move(attribute));
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ case ATTR_DOMAIN_INSTANCE:
+ return "id";
+ default:
+ return "";
}
- return nullptr;
+}
+
+GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const
+{
+
+ const StringRef name = get_random_id_attribute_name(domain);
+ GVArray attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32);
+ if (attribute) {
+ BLI_assert(attribute.size() == component.attribute_domain_size(domain));
+ return attribute;
+ }
+
+ /* Use the index as the fallback if no random ID attribute exists. */
+ return fn::IndexFieldInput::get_index_varray(mask);
+}
+
+std::string IDAttributeFieldInput::socket_inspection_name() const
+{
+ return TIP_("ID / Index");
+}
+
+uint64_t IDAttributeFieldInput::hash() const
+{
+ /* All random ID attribute inputs are the same within the same evaluation context. */
+ return 92386459827;
+}
+
+bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
+{
+ /* All random ID attribute inputs are the same within the same evaluation context. */
+ return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr;
+}
+
+GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const
+{
+ const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
+ return component.attribute_try_get_for_read(anonymous_id_.get(), domain, data_type);
}
std::string AnonymousAttributeFieldInput::socket_inspection_name() const
{
std::stringstream ss;
- ss << TIP_("Anonymous Attribute: ") << debug_name_;
+ ss << '"' << debug_name_ << '"' << TIP_(" from ") << producer_name_;
return ss.str();
}
@@ -1400,3 +1522,5 @@ bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
}
} // namespace blender::bke
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh
index 261cb26d4e5..2cd128081eb 100644
--- a/source/blender/blenkernel/intern/attribute_access_intern.hh
+++ b/source/blender/blenkernel/intern/attribute_access_intern.hh
@@ -24,9 +24,6 @@
namespace blender::bke {
-using fn::GVArrayPtr;
-using fn::GVMutableArrayPtr;
-
/**
* Utility to group together multiple functions that are used to access custom data on geometry
* components in a generic way.
@@ -86,8 +83,8 @@ class BuiltinAttributeProvider {
{
}
- virtual GVArrayPtr try_get_for_read(const GeometryComponent &component) const = 0;
- virtual GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const = 0;
+ virtual GVArray try_get_for_read(const GeometryComponent &component) const = 0;
+ virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component) const = 0;
virtual bool try_delete(GeometryComponent &component) const = 0;
virtual bool try_create(GeometryComponent &UNUSED(component),
const AttributeInit &UNUSED(initializer)) const = 0;
@@ -164,7 +161,7 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
bool try_create(GeometryComponent &component,
const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
+ AttributeDomain domain,
const CustomDataType data_type,
const AttributeInit &initializer) const final;
@@ -177,24 +174,6 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
}
private:
- template<typename T>
- ReadAttributeLookup layer_to_read_attribute(const CustomDataLayer &layer,
- const int domain_size) const
- {
- return {std::make_unique<fn::GVArray_For_Span<T>>(
- Span(static_cast<const T *>(layer.data), domain_size)),
- domain_};
- }
-
- template<typename T>
- WriteAttributeLookup layer_to_write_attribute(CustomDataLayer &layer,
- const int domain_size) const
- {
- return {std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>(
- MutableSpan(static_cast<T *>(layer.data), domain_size)),
- domain_};
- }
-
bool type_is_supported(CustomDataType data_type) const
{
return ((1ULL << data_type) & supported_types_mask) != 0;
@@ -206,8 +185,8 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
*/
class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
private:
- using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size);
- using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size);
+ using AsReadAttribute = GVArray (*)(const void *data, int domain_size);
+ using AsWriteAttribute = GVMutableArray (*)(void *data, int domain_size);
const AttributeDomain domain_;
const CustomDataType attribute_type_;
const CustomDataType stored_type_;
@@ -245,10 +224,13 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
* This provider is used to provide access to builtin attributes. It supports making internal types
* available as different types. For example, the vertex position attribute is stored as part of
* the #MVert struct, but is exposed as float3 attribute.
+ *
+ * It also supports named builtin attributes, and will look up attributes in #CustomData by name
+ * if the stored type is the same as the attribute type.
*/
class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
- using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size);
- using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size);
+ using AsReadAttribute = GVArray (*)(const void *data, int domain_size);
+ using AsWriteAttribute = GVMutableArray (*)(void *data, int domain_size);
using UpdateOnRead = void (*)(const GeometryComponent &component);
using UpdateOnWrite = void (*)(GeometryComponent &component);
const CustomDataType stored_type_;
@@ -256,6 +238,7 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
const AsReadAttribute as_read_attribute_;
const AsWriteAttribute as_write_attribute_;
const UpdateOnWrite update_on_write_;
+ bool stored_as_named_attribute_;
public:
BuiltinCustomDataLayerProvider(std::string attribute_name,
@@ -275,12 +258,13 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
custom_data_access_(custom_data_access),
as_read_attribute_(as_read_attribute),
as_write_attribute_(as_write_attribute),
- update_on_write_(update_on_write)
+ update_on_write_(update_on_write),
+ stored_as_named_attribute_(data_type_ == stored_type_)
{
}
- GVArrayPtr try_get_for_read(const GeometryComponent &component) const final;
- GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final;
+ GVArray try_get_for_read(const GeometryComponent &component) const final;
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final;
bool try_delete(GeometryComponent &component) const final;
bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final;
bool exists(const GeometryComponent &component) const final;
diff --git a/source/blender/blenkernel/intern/autoexec.c b/source/blender/blenkernel/intern/autoexec.c
index 3aec646b024..ed2b4e4ab1b 100644
--- a/source/blender/blenkernel/intern/autoexec.c
+++ b/source/blender/blenkernel/intern/autoexec.c
@@ -36,10 +36,6 @@
#include "BKE_autoexec.h" /* own include */
-/**
- * \param path: The path to check against.
- * \return Success
- */
bool BKE_autoexec_match(const char *path)
{
bPathCompare *path_cmp;
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 97f8bddc043..b914b0cdf66 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -71,7 +71,6 @@ UserDef U;
/** \name Blender Free on Exit
* \{ */
-/* only to be called on exit blender */
void BKE_blender_free(void)
{
/* samples are in a global list..., also sets G_MAIN->sound->sample NULL */
@@ -90,7 +89,6 @@ void BKE_blender_free(void)
IMB_exit();
BKE_cachefiles_exit();
- BKE_images_exit();
DEG_free_node_types();
BKE_brush_system_exit();
@@ -273,10 +271,6 @@ static void userdef_free_addons(UserDef *userdef)
BLI_listbase_clear(&userdef->addons);
}
-/**
- * When loading a new userdef from file,
- * or when exiting Blender.
- */
void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
{
#define U BLI_STATIC_ASSERT(false, "Global 'U' not allowed, only use arguments passed in!")
@@ -311,10 +305,6 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
/** \name Blender Preferences (Application Templates)
* \{ */
-/**
- * Write U from userdef.
- * This function defines which settings a template will override for the user preferences.
- */
void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *userdef_b)
{
/* TODO:
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index 9c9f898afef..211d7f693d4 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -38,6 +38,7 @@
#include "BKE_blender_copybuffer.h" /* own include */
#include "BKE_blendfile.h"
+#include "BKE_blendfile_link_append.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_layer.h"
@@ -57,20 +58,17 @@
/** \name Copy/Paste `.blend`, partial saves.
* \{ */
-void BKE_copybuffer_begin(Main *bmain_src)
+void BKE_copybuffer_copy_begin(Main *bmain_src)
{
BKE_blendfile_write_partial_begin(bmain_src);
}
-void BKE_copybuffer_tag_ID(ID *id)
+void BKE_copybuffer_copy_tag_ID(ID *id)
{
BKE_blendfile_write_partial_tag_ID(id, true);
}
-/**
- * \return Success.
- */
-bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *reports)
+bool BKE_copybuffer_copy_end(Main *bmain_src, const char *filename, ReportList *reports)
{
const int write_flags = 0;
const eBLO_WritePathRemap remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE;
@@ -82,46 +80,63 @@ bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *repo
return retval;
}
+/* Common helper for paste functions. */
+static void copybuffer_append(BlendfileLinkAppendContext *lapp_context,
+ Main *bmain,
+ ReportList *reports)
+{
+ /* Tag existing IDs in given `bmain_dst` as already existing. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+
+ BKE_blendfile_link(lapp_context, reports);
+
+ /* Mark all library linked objects to be updated. */
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
+
+ /* Append, rather than linking */
+ BKE_blendfile_append(lapp_context, reports);
+
+ /* This must be unset, otherwise these object won't link into other scenes from this blend
+ * file. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+ /* Recreate dependency graph to include new objects. */
+ DEG_relations_tag_update(bmain);
+}
+
bool BKE_copybuffer_read(Main *bmain_dst,
const char *libname,
ReportList *reports,
const uint64_t id_types_mask)
{
- BlendFileReadReport bf_reports = {.reports = reports};
- BlendHandle *bh = BLO_blendhandle_from_file(libname, &bf_reports);
- if (bh == NULL) {
- /* Error reports will have been made by BLO_blendhandle_from_file(). */
- return false;
- }
- /* Here appending/linking starts. */
+ /* Note: No recursive append here (no `BLO_LIBLINK_APPEND_RECURSIVE`), external linked data
+ * should remain linked. */
const int flag = 0;
const int id_tag_extra = 0;
struct LibraryLink_Params liblink_params;
BLO_library_link_params_init(&liblink_params, bmain_dst, flag, id_tag_extra);
- Main *mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
- BLO_library_link_copypaste(mainl, bh, id_types_mask);
- BLO_library_link_end(mainl, &bh, &liblink_params);
- /* Mark all library linked objects to be updated. */
- BKE_main_lib_objects_recalc_all(bmain_dst);
- IMB_colormanagement_check_file_config(bmain_dst);
- /* Append, rather than linking. */
- Library *lib = BLI_findstring(&bmain_dst->libraries, libname, offsetof(Library, filepath_abs));
- BKE_library_make_local(bmain_dst, lib, NULL, true, false);
- /* Important we unset, otherwise these object won't
- * link into other scenes from this blend file.
- */
- BKE_main_id_tag_all(bmain_dst, LIB_TAG_PRE_EXISTING, false);
- BLO_blendhandle_close(bh);
+
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(
+ &liblink_params);
+ BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL);
+
+ const int num_pasted = BKE_blendfile_link_append_context_item_idtypes_from_library_add(
+ lapp_context, reports, id_types_mask, 0);
+ if (num_pasted == BLENDFILE_LINK_APPEND_INVALID) {
+ BKE_blendfile_link_append_context_free(lapp_context);
+ return false;
+ }
+
+ copybuffer_append(lapp_context, bmain_dst, reports);
+
+ BKE_blendfile_link_append_context_free(lapp_context);
return true;
}
-/**
- * \return Number of IDs directly pasted from the buffer
- * (does not includes indirectly pulled out ones).
- */
int BKE_copybuffer_paste(bContext *C,
const char *libname,
- const short flag,
+ const int flag,
ReportList *reports,
const uint64_t id_types_mask)
{
@@ -129,59 +144,31 @@ int BKE_copybuffer_paste(bContext *C,
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C); /* may be NULL. */
- Main *mainl = NULL;
- Library *lib;
- BlendHandle *bh;
const int id_tag_extra = 0;
- BlendFileReadReport bf_reports = {.reports = reports};
- bh = BLO_blendhandle_from_file(libname, &bf_reports);
-
- if (bh == NULL) {
- /* error reports will have been made by BLO_blendhandle_from_file() */
- return 0;
- }
+ /* Note: No recursive append here, external linked data should remain linked. */
+ BLI_assert((flag & BLO_LIBLINK_APPEND_RECURSIVE) == 0);
- BKE_view_layer_base_deselect_all(view_layer);
-
- /* tag everything, all untagged data can be made local
- * its also generally useful to know what is new
- *
- * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
-
- /* here appending/linking starts */
struct LibraryLink_Params liblink_params;
BLO_library_link_params_init_with_context(
&liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d);
- mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
-
- const int num_pasted = BLO_library_link_copypaste(mainl, bh, id_types_mask);
- BLO_library_link_end(mainl, &bh, &liblink_params);
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(
+ &liblink_params);
+ BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL);
- /* mark all library linked objects to be updated */
- BKE_main_lib_objects_recalc_all(bmain);
- IMB_colormanagement_check_file_config(bmain);
-
- /* append, rather than linking */
- lib = BLI_findstring(&bmain->libraries, libname, offsetof(Library, filepath_abs));
- BKE_library_make_local(bmain, lib, NULL, true, false);
-
- /* important we unset, otherwise these object won't
- * link into other scenes from this blend file */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
-
- /* recreate dependency graph to include new objects */
- DEG_relations_tag_update(bmain);
+ const int num_pasted = BKE_blendfile_link_append_context_item_idtypes_from_library_add(
+ lapp_context, reports, id_types_mask, 0);
+ if (num_pasted == BLENDFILE_LINK_APPEND_INVALID) {
+ BKE_blendfile_link_append_context_free(lapp_context);
+ return 0;
+ }
- /* Tag update the scene to flush base collection settings, since the new object is added to a
- * new (active) collection, not its original collection, thus need recalculation. */
- DEG_id_tag_update(&scene->id, 0);
+ BKE_view_layer_base_deselect_all(view_layer);
- BLO_blendhandle_close(bh);
- /* remove library... */
+ copybuffer_append(lapp_context, bmain, reports);
+ BKE_blendfile_link_append_context_free(lapp_context);
return num_pasted;
}
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index 411ece21599..6c443a94def 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -68,7 +68,7 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu,
bContext *C)
{
Main *bmain = CTX_data_main(C);
- char mainstr[sizeof(bmain->name)];
+ char mainstr[sizeof(bmain->filepath)];
int success = 0, fileflags;
BLI_strncpy(mainstr, BKE_main_blendfile_path(bmain), sizeof(mainstr)); /* temporal store */
@@ -101,7 +101,7 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu,
/* Restore, bmain has been re-allocated. */
bmain = CTX_data_main(C);
- BLI_strncpy(bmain->name, mainstr, sizeof(bmain->name));
+ STRNCPY(bmain->filepath, mainstr);
G.fileflags = fileflags;
if (success) {
diff --git a/source/blender/blenkernel/intern/blender_user_menu.c b/source/blender/blenkernel/intern/blender_user_menu.c
index edd89357fd5..b186d376e52 100644
--- a/source/blender/blenkernel/intern/blender_user_menu.c
+++ b/source/blender/blenkernel/intern/blender_user_menu.c
@@ -110,3 +110,5 @@ void BKE_blender_user_menu_item_free_list(ListBase *lb)
}
BLI_listbase_clear(lb);
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 6957f9b5a69..6ae19c8036f 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -78,7 +78,9 @@
/** \name High Level `.blend` file read/write.
* \{ */
-static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src)
+static bool foreach_path_clean_cb(BPathForeachPathData *UNUSED(bpath_data),
+ char *path_dst,
+ const char *path_src)
{
strcpy(path_dst, path_src);
BLI_path_slash_native(path_dst);
@@ -86,13 +88,16 @@ static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const c
}
/* make sure path names are correct for OS */
-static void clean_paths(Main *main)
+static void clean_paths(Main *bmain)
{
- Scene *scene;
-
- BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL);
-
- for (scene = main->scenes.first; scene; scene = scene->id.next) {
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){
+ .bmain = bmain,
+ .callback_function = foreach_path_clean_cb,
+ .flag = BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE,
+ .user_data = NULL,
+ });
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
BLI_path_slash_native(scene->r.pic);
}
}
@@ -251,7 +256,7 @@ static void setup_app_data(bContext *C,
* replace it with 'curscene' if its needed */
}
/* and we enforce curscene to be in current screen */
- else if (win) { /* can run in bgmode */
+ else if (win) { /* The window may be NULL in background-mode. */
win->scene = curscene;
}
@@ -347,7 +352,7 @@ static void setup_app_data(bContext *C,
/* FIXME: Same as above, readfile's `do_version` do not allow to create new IDs. */
/* TODO: Once this is definitively validated for 3.0 and option to not do it is removed, add a
* version bump and check here. */
- if (!USER_EXPERIMENTAL_TEST(&U, no_proxy_to_override_conversion)) {
+ if (mode != LOAD_UNDO && !USER_EXPERIMENTAL_TEST(&U, no_proxy_to_override_conversion)) {
BKE_lib_override_library_main_proxy_convert(bmain, reports);
}
@@ -355,12 +360,12 @@ static void setup_app_data(bContext *C,
/* startup.blend or recovered startup */
if (is_startup) {
- bmain->name[0] = '\0';
+ bmain->filepath[0] = '\0';
}
else if (recover) {
- /* In case of autosave or quit.blend, use original filename instead. */
+ /* In case of autosave or quit.blend, use original filepath instead. */
bmain->recovered = 1;
- BLI_strncpy(bmain->name, bfd->filename, FILE_MAX);
+ STRNCPY(bmain->filepath, bfd->filepath);
}
/* baseflags, groups, make depsgraph, etc */
@@ -447,14 +452,6 @@ static void handle_subversion_warning(Main *main, BlendFileReadReport *reports)
}
}
-/**
- * Shared setup function that makes the data from `bfd` into the current blend file,
- * replacing the contents of #G.main.
- * This uses the bfd #BKE_blendfile_read and similarly named functions.
- *
- * This is done in a separate step so the caller may perform actions after it is known the file
- * loaded correctly but before the file replaces the existing blend file contents.
- */
void BKE_blendfile_read_setup_ex(bContext *C,
BlendFileData *bfd,
const struct BlendFileReadParams *params,
@@ -480,9 +477,6 @@ void BKE_blendfile_read_setup(bContext *C,
BKE_blendfile_read_setup_ex(C, bfd, params, reports, false, NULL);
}
-/**
- * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
- */
struct BlendFileData *BKE_blendfile_read(const char *filepath,
const struct BlendFileReadParams *params,
BlendFileReadReport *reports)
@@ -502,9 +496,6 @@ struct BlendFileData *BKE_blendfile_read(const char *filepath,
return bfd;
}
-/**
- * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
- */
struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
int filelength,
const struct BlendFileReadParams *params,
@@ -520,10 +511,6 @@ struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
return bfd;
}
-/**
- * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
- * \note `memfile` is the undo buffer.
- */
struct BlendFileData *BKE_blendfile_read_from_memfile(Main *bmain,
struct MemFile *memfile,
const struct BlendFileReadParams *params,
@@ -546,10 +533,6 @@ struct BlendFileData *BKE_blendfile_read_from_memfile(Main *bmain,
return bfd;
}
-/**
- * Utility to make a file 'empty' used for startup to optionally give an empty file.
- * Handy for tests.
- */
void BKE_blendfile_read_make_empty(bContext *C)
{
Main *bmain = CTX_data_main(C);
@@ -568,7 +551,6 @@ void BKE_blendfile_read_make_empty(bContext *C)
FOREACH_MAIN_LISTBASE_END;
}
-/* only read the userdef from a .blend */
UserDef *BKE_blendfile_userdef_read(const char *filepath, ReportList *reports)
{
BlendFileData *bfd;
@@ -671,10 +653,6 @@ UserDef *BKE_blendfile_userdef_from_defaults(void)
return userdef;
}
-/**
- * Only write the userdef in a .blend
- * \return success
- */
bool BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
{
Main *mainb = MEM_callocN(sizeof(Main), "empty main");
@@ -695,13 +673,6 @@ bool BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
return ok;
}
-/**
- * Only write the userdef in a .blend, merging with the existing blend file.
- * \return success
- *
- * \note In the future we should re-evaluate user preferences,
- * possibly splitting out system/hardware specific prefs.
- */
bool BKE_blendfile_userdef_write_app_template(const char *filepath, ReportList *reports)
{
/* if it fails, overwrite is OK. */
@@ -872,10 +843,6 @@ static void blendfile_write_partial_cb(void *UNUSED(handle), Main *UNUSED(bmain)
}
}
-/**
- * \param remap_mode: Choose the kind of path remapping or none #eBLO_WritePathRemap.
- * \return Success.
- */
bool BKE_blendfile_write_partial(Main *bmain_src,
const char *filepath,
const int write_flags,
@@ -887,11 +854,12 @@ bool BKE_blendfile_write_partial(Main *bmain_src,
int a, retval;
void *path_list_backup = NULL;
- const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
+ const eBPathForeachFlag path_list_flag = (BKE_BPATH_FOREACH_PATH_SKIP_LINKED |
+ BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE);
/* This is needed to be able to load that file as a real one later
- * (otherwise main->name will not be set at read time). */
- BLI_strncpy(bmain_dst->name, bmain_src->name, sizeof(bmain_dst->name));
+ * (otherwise `main->filepath` will not be set at read time). */
+ STRNCPY(bmain_dst->filepath, bmain_src->filepath);
BLO_main_expander(blendfile_write_partial_cb);
BLO_expand_main(NULL, bmain_src);
diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c
new file mode 100644
index 00000000000..9b3f4c2fae8
--- /dev/null
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -0,0 +1,1649 @@
+/*
+ * 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
+ *
+ * High level `.blend` file link/append code,
+ * including linking/appending several IDs from different libraries, handling instantiations of
+ * collections/objects/object-data in current scene.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_collection_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_idtype.h"
+#include "BKE_key.h"
+#include "BKE_layer.h"
+#include "BKE_lib_id.h"
+#include "BKE_lib_override.h"
+#include "BKE_lib_query.h"
+#include "BKE_lib_remap.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_rigidbody.h"
+#include "BKE_scene.h"
+
+#include "BKE_blendfile_link_append.h"
+
+#include "BLO_readfile.h"
+#include "BLO_writefile.h"
+
+static CLG_LogRef LOG = {"bke.blendfile_link_append"};
+
+/* -------------------------------------------------------------------- */
+/** \name Link/append context implementation and public management API.
+ * \{ */
+
+typedef struct BlendfileLinkAppendContextItem {
+ /** Name of the ID (without the heading two-chars IDcode). */
+ char *name;
+ /** All libs (from BlendfileLinkAppendContext.libraries) to try to load this ID from. */
+ BLI_bitmap *libraries;
+ /** ID type. */
+ short idcode;
+
+ /** Type of action to perform on this item, and general status tag information.
+ * NOTE: Mostly used by append post-linking processing. */
+ char action;
+ char tag;
+
+ /** Newly linked ID (NULL until it has been successfully linked). */
+ ID *new_id;
+ /** Library ID from which the #new_id has been linked (NULL until it has been successfully
+ * linked). */
+ Library *source_library;
+ /** Opaque user data pointer. */
+ void *userdata;
+} BlendfileLinkAppendContextItem;
+
+/* A blendfile library entry in the `libraries` list of #BlendfileLinkAppendContext. */
+typedef struct BlendfileLinkAppendContextLibrary {
+ char *path; /* Absolute .blend file path. */
+ BlendHandle *blo_handle; /* Blend file handle, if any. */
+ bool blo_handle_is_owned; /* Whether the blend file handle is owned, or borrowed. */
+ /* The blendfile report associated with the `blo_handle`, if owned. */
+ BlendFileReadReport bf_reports;
+} BlendfileLinkAppendContextLibrary;
+
+typedef struct BlendfileLinkAppendContext {
+ /** List of library paths to search IDs in. */
+ LinkNodePair libraries;
+ /** List of all ID to try to link from #libraries. */
+ LinkNodePair items;
+ int num_libraries;
+ int num_items;
+ /** Linking/appending parameters. Including `bmain`, `scene`, `viewlayer` and `view3d`. */
+ LibraryLink_Params *params;
+
+ /** Allows to easily find an existing items from an ID pointer. */
+ GHash *new_id_to_item;
+
+ /** Runtime info used by append code to manage re-use of already appended matching IDs. */
+ GHash *library_weak_reference_mapping;
+
+ /** Embedded blendfile and its size, if needed. */
+ const void *blendfile_mem;
+ size_t blendfile_memsize;
+
+ /** Internal 'private' data */
+ MemArena *memarena;
+} BlendfileLinkAppendContext;
+
+typedef struct BlendfileLinkAppendContextCallBack {
+ BlendfileLinkAppendContext *lapp_context;
+ BlendfileLinkAppendContextItem *item;
+ ReportList *reports;
+
+} BlendfileLinkAppendContextCallBack;
+
+/* Actions to apply to an item (i.e. linked ID). */
+enum {
+ LINK_APPEND_ACT_UNSET = 0,
+ LINK_APPEND_ACT_KEEP_LINKED,
+ LINK_APPEND_ACT_REUSE_LOCAL,
+ LINK_APPEND_ACT_MAKE_LOCAL,
+ LINK_APPEND_ACT_COPY_LOCAL,
+};
+
+/* Various status info about an item (i.e. linked ID). */
+enum {
+ /* An indirectly linked ID. */
+ LINK_APPEND_TAG_INDIRECT = 1 << 0,
+};
+
+static BlendHandle *link_append_context_library_blohandle_ensure(
+ BlendfileLinkAppendContext *lapp_context,
+ BlendfileLinkAppendContextLibrary *lib_context,
+ ReportList *reports)
+{
+ if (reports != NULL) {
+ lib_context->bf_reports.reports = reports;
+ }
+
+ char *libname = lib_context->path;
+ BlendHandle *blo_handle = lib_context->blo_handle;
+ if (blo_handle == NULL) {
+ if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) {
+ blo_handle = BLO_blendhandle_from_memory(lapp_context->blendfile_mem,
+ (int)lapp_context->blendfile_memsize,
+ &lib_context->bf_reports);
+ }
+ else {
+ blo_handle = BLO_blendhandle_from_file(libname, &lib_context->bf_reports);
+ }
+ lib_context->blo_handle = blo_handle;
+ lib_context->blo_handle_is_owned = true;
+ }
+
+ return blo_handle;
+}
+
+static void link_append_context_library_blohandle_release(
+ BlendfileLinkAppendContext *UNUSED(lapp_context),
+ BlendfileLinkAppendContextLibrary *lib_context)
+{
+ if (lib_context->blo_handle_is_owned && lib_context->blo_handle != NULL) {
+ BLO_blendhandle_close(lib_context->blo_handle);
+ lib_context->blo_handle = NULL;
+ }
+}
+
+BlendfileLinkAppendContext *BKE_blendfile_link_append_context_new(LibraryLink_Params *params)
+{
+ MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ BlendfileLinkAppendContext *lapp_context = BLI_memarena_calloc(ma, sizeof(*lapp_context));
+
+ lapp_context->params = params;
+ lapp_context->memarena = ma;
+
+ return lapp_context;
+}
+
+void BKE_blendfile_link_append_context_free(BlendfileLinkAppendContext *lapp_context)
+{
+ if (lapp_context->new_id_to_item != NULL) {
+ BLI_ghash_free(lapp_context->new_id_to_item, NULL, NULL);
+ }
+
+ for (LinkNode *liblink = lapp_context->libraries.list; liblink != NULL;
+ liblink = liblink->next) {
+ BlendfileLinkAppendContextLibrary *lib_context = liblink->link;
+ link_append_context_library_blohandle_release(lapp_context, lib_context);
+ }
+
+ BLI_assert(lapp_context->library_weak_reference_mapping == NULL);
+
+ BLI_memarena_free(lapp_context->memarena);
+}
+
+void BKE_blendfile_link_append_context_flag_set(BlendfileLinkAppendContext *lapp_context,
+ const int flag,
+ const bool do_set)
+{
+ if (do_set) {
+ lapp_context->params->flag |= flag;
+ }
+ else {
+ lapp_context->params->flag &= ~flag;
+ }
+}
+
+void BKE_blendfile_link_append_context_embedded_blendfile_set(
+ BlendfileLinkAppendContext *lapp_context, const void *blendfile_mem, int blendfile_memsize)
+{
+ BLI_assert_msg(lapp_context->blendfile_mem == NULL,
+ "Please explicitly clear reference to an embedded blender memfile before "
+ "setting a new one");
+ lapp_context->blendfile_mem = blendfile_mem;
+ lapp_context->blendfile_memsize = (size_t)blendfile_memsize;
+}
+
+void BKE_blendfile_link_append_context_embedded_blendfile_clear(
+ BlendfileLinkAppendContext *lapp_context)
+{
+ lapp_context->blendfile_mem = NULL;
+ lapp_context->blendfile_memsize = 0;
+}
+
+void BKE_blendfile_link_append_context_library_add(BlendfileLinkAppendContext *lapp_context,
+ const char *libname,
+ BlendHandle *blo_handle)
+{
+ BLI_assert(lapp_context->items.list == NULL);
+
+ BlendfileLinkAppendContextLibrary *lib_context = BLI_memarena_calloc(lapp_context->memarena,
+ sizeof(*lib_context));
+
+ size_t len = strlen(libname) + 1;
+ char *libpath = BLI_memarena_alloc(lapp_context->memarena, len);
+ BLI_strncpy(libpath, libname, len);
+
+ lib_context->path = libpath;
+ lib_context->blo_handle = blo_handle;
+ lib_context->blo_handle_is_owned = (blo_handle == NULL);
+
+ BLI_linklist_append_arena(&lapp_context->libraries, lib_context, lapp_context->memarena);
+ lapp_context->num_libraries++;
+}
+
+BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add(
+ BlendfileLinkAppendContext *lapp_context,
+ const char *idname,
+ const short idcode,
+ void *userdata)
+{
+ BlendfileLinkAppendContextItem *item = BLI_memarena_calloc(lapp_context->memarena,
+ sizeof(*item));
+ size_t len = strlen(idname) + 1;
+
+ item->name = BLI_memarena_alloc(lapp_context->memarena, len);
+ BLI_strncpy(item->name, idname, len);
+ item->idcode = idcode;
+ item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_context->memarena, lapp_context->num_libraries);
+
+ item->new_id = NULL;
+ item->action = LINK_APPEND_ACT_UNSET;
+ item->userdata = userdata;
+
+ BLI_linklist_append_arena(&lapp_context->items, item, lapp_context->memarena);
+ lapp_context->num_items++;
+
+ return item;
+}
+
+int BKE_blendfile_link_append_context_item_idtypes_from_library_add(
+ BlendfileLinkAppendContext *lapp_context,
+ ReportList *reports,
+ const uint64_t id_types_filter,
+ const int library_index)
+{
+ int id_num = 0;
+ int id_code_iter = 0;
+ short id_code;
+
+ LinkNode *lib_context_link = BLI_linklist_find(lapp_context->libraries.list, library_index);
+ BlendfileLinkAppendContextLibrary *lib_context = lib_context_link->link;
+ BlendHandle *blo_handle = link_append_context_library_blohandle_ensure(
+ lapp_context, lib_context, reports);
+
+ if (blo_handle == NULL) {
+ return BLENDFILE_LINK_APPEND_INVALID;
+ }
+
+ const bool use_assets_only = (lapp_context->params->flag & FILE_ASSETS_ONLY) != 0;
+
+ while ((id_code = BKE_idtype_idcode_iter_step(&id_code_iter))) {
+ if (!BKE_idtype_idcode_is_linkable(id_code) ||
+ (id_types_filter != 0 &&
+ (BKE_idtype_idcode_to_idfilter(id_code) & id_types_filter) == 0)) {
+ continue;
+ }
+
+ int id_names_num;
+ LinkNode *id_names_list = BLO_blendhandle_get_datablock_names(
+ blo_handle, id_code, use_assets_only, &id_names_num);
+
+ for (LinkNode *link_next = NULL; id_names_list != NULL; id_names_list = link_next) {
+ link_next = id_names_list->next;
+
+ char *id_name = id_names_list->link;
+ BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, id_name, id_code, NULL);
+ BKE_blendfile_link_append_context_item_library_index_enable(
+ lapp_context, item, library_index);
+
+ MEM_freeN(id_name);
+ MEM_freeN(id_names_list);
+ }
+
+ id_num += id_names_num;
+ }
+
+ return id_num;
+}
+
+void BKE_blendfile_link_append_context_item_library_index_enable(
+ BlendfileLinkAppendContext *UNUSED(lapp_context),
+ BlendfileLinkAppendContextItem *item,
+ const int library_index)
+{
+ BLI_BITMAP_ENABLE(item->libraries, library_index);
+}
+
+bool BKE_blendfile_link_append_context_is_empty(struct BlendfileLinkAppendContext *lapp_context)
+{
+ return lapp_context->num_items == 0;
+}
+
+void *BKE_blendfile_link_append_context_item_userdata_get(
+ BlendfileLinkAppendContext *UNUSED(lapp_context), BlendfileLinkAppendContextItem *item)
+{
+ return item->userdata;
+}
+
+ID *BKE_blendfile_link_append_context_item_newid_get(
+ BlendfileLinkAppendContext *UNUSED(lapp_context), BlendfileLinkAppendContextItem *item)
+{
+ return item->new_id;
+}
+
+short BKE_blendfile_link_append_context_item_idcode_get(
+ struct BlendfileLinkAppendContext *UNUSED(lapp_context),
+ struct BlendfileLinkAppendContextItem *item)
+{
+ return item->idcode;
+}
+
+void BKE_blendfile_link_append_context_item_foreach(
+ struct BlendfileLinkAppendContext *lapp_context,
+ BKE_BlendfileLinkAppendContexteItemFunction callback_function,
+ const eBlendfileLinkAppendForeachItemFlag flag,
+ void *userdata)
+{
+ for (LinkNode *itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+
+ if ((flag & BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT) == 0 &&
+ (item->tag & LINK_APPEND_TAG_INDIRECT) == 0) {
+ continue;
+ }
+ if ((flag & BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT) == 0 &&
+ (item->tag & LINK_APPEND_TAG_INDIRECT) != 0) {
+ continue;
+ }
+
+ if (!callback_function(lapp_context, item, userdata)) {
+ break;
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Library link/append helper functions.
+ *
+ * \{ */
+
+/* Struct gathering all required data to handle instantiation of loose data-blocks. */
+typedef struct LooseDataInstantiateContext {
+ BlendfileLinkAppendContext *lapp_context;
+
+ /* The collection in which to add loose collections/objects. */
+ Collection *active_collection;
+} LooseDataInstantiateContext;
+
+static bool object_in_any_scene(Main *bmain, Object *ob)
+{
+ LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
+ if (BKE_scene_object_find(sce, ob)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool object_in_any_collection(Main *bmain, Object *ob)
+{
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ if (BKE_collection_has_object(collection, ob)) {
+ return true;
+ }
+ }
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->master_collection != NULL &&
+ BKE_collection_has_object(scene->master_collection, ob)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool collection_instantiated_by_any_object(Main *bmain, Collection *collection)
+{
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->type == OB_EMPTY && ob->instance_collection == collection) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static ID *loose_data_instantiate_process_check(LooseDataInstantiateContext *instantiate_context,
+ BlendfileLinkAppendContextItem *item)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ /* In linking case, we always want to handle instantiation. */
+ if (lapp_context->params->flag & FILE_LINK) {
+ return item->new_id;
+ }
+
+ /* We consider that if we either kept it linked, or re-used already local data, instantiation
+ * status of those should not be modified. */
+ if (!ELEM(item->action, LINK_APPEND_ACT_COPY_LOCAL, LINK_APPEND_ACT_MAKE_LOCAL)) {
+ return NULL;
+ }
+
+ ID *id = item->new_id;
+ if (id == NULL) {
+ return NULL;
+ }
+
+ if (item->action == LINK_APPEND_ACT_COPY_LOCAL) {
+ BLI_assert(ID_IS_LINKED(id));
+ id = id->newid;
+ if (id == NULL) {
+ return NULL;
+ }
+
+ BLI_assert(!ID_IS_LINKED(id));
+ return id;
+ }
+
+ BLI_assert(!ID_IS_LINKED(id));
+ return id;
+}
+
+static void loose_data_instantiate_ensure_active_collection(
+ LooseDataInstantiateContext *instantiate_context)
+{
+
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = instantiate_context->lapp_context->params->bmain;
+ Scene *scene = instantiate_context->lapp_context->params->context.scene;
+ ViewLayer *view_layer = instantiate_context->lapp_context->params->context.view_layer;
+
+ /* Find or add collection as needed. */
+ if (instantiate_context->active_collection == NULL) {
+ if (lapp_context->params->flag & FILE_ACTIVE_COLLECTION) {
+ LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
+ instantiate_context->active_collection = lc->collection;
+ }
+ else {
+ if (lapp_context->params->flag & FILE_LINK) {
+ instantiate_context->active_collection = BKE_collection_add(
+ bmain, scene->master_collection, DATA_("Linked Data"));
+ }
+ else {
+ instantiate_context->active_collection = BKE_collection_add(
+ bmain, scene->master_collection, DATA_("Appended Data"));
+ }
+ }
+ }
+}
+
+static void loose_data_instantiate_object_base_instance_init(Main *bmain,
+ Collection *collection,
+ Object *ob,
+ ViewLayer *view_layer,
+ const View3D *v3d,
+ const int flag,
+ bool set_active)
+{
+ /* Auto-select and appending. */
+ if ((flag & FILE_AUTOSELECT) && ((flag & FILE_LINK) == 0)) {
+ /* While in general the object should not be manipulated,
+ * when the user requests the object to be selected, ensure it's visible and selectable. */
+ ob->visibility_flag &= ~(OB_HIDE_VIEWPORT | OB_HIDE_SELECT);
+ }
+
+ BKE_collection_object_add(bmain, collection, ob);
+
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (v3d != NULL) {
+ base->local_view_bits |= v3d->local_view_uuid;
+ }
+
+ if (flag & FILE_AUTOSELECT) {
+ /* All objects that use #FILE_AUTOSELECT must be selectable (unless linking data). */
+ BLI_assert((base->flag & BASE_SELECTABLE) || (flag & FILE_LINK));
+ if (base->flag & BASE_SELECTABLE) {
+ base->flag |= BASE_SELECTED;
+ }
+ }
+
+ if (set_active) {
+ view_layer->basact = base;
+ }
+
+ BKE_scene_object_base_flag_sync_from_base(base);
+}
+
+/* Tag obdata that actually need to be instantiated (those referenced by an object do not, since
+ * the object will be instantiated instead if needed. */
+static void loose_data_instantiate_obdata_preprocess(
+ LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ LinkNode *itemlink;
+
+ /* First pass on obdata to enable their instantiation by default, then do a second pass on
+ * objects to clear it for any obdata already in use. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL) {
+ continue;
+ }
+ const ID_Type idcode = GS(id->name);
+ if (!OB_DATA_SUPPORT_ID(idcode)) {
+ continue;
+ }
+
+ id->tag |= LIB_TAG_DOIT;
+ }
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL || GS(id->name) != ID_OB) {
+ continue;
+ }
+
+ Object *ob = (Object *)id;
+ Object *new_ob = (Object *)id->newid;
+ if (ob->data != NULL) {
+ ((ID *)(ob->data))->tag &= ~LIB_TAG_DOIT;
+ }
+ if (new_ob != NULL && new_ob->data != NULL) {
+ ((ID *)(new_ob->data))->tag &= ~LIB_TAG_DOIT;
+ }
+ }
+}
+
+/* Test whether some ancestor collection is also tagged for instantiation (return true) or not
+ * (return false). */
+static bool loose_data_instantiate_collection_parents_check_recursive(Collection *collection)
+{
+ for (CollectionParent *parent_collection = collection->parents.first; parent_collection != NULL;
+ parent_collection = parent_collection->next) {
+ if ((parent_collection->collection->id.tag & LIB_TAG_DOIT) != 0) {
+ return true;
+ }
+ if (loose_data_instantiate_collection_parents_check_recursive(parent_collection->collection)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void loose_data_instantiate_collection_process(
+ LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = lapp_context->params->bmain;
+ Scene *scene = lapp_context->params->context.scene;
+ ViewLayer *view_layer = lapp_context->params->context.view_layer;
+ const View3D *v3d = lapp_context->params->context.v3d;
+
+ const bool do_append = (lapp_context->params->flag & FILE_LINK) == 0;
+ const bool do_instantiate_as_empty = (lapp_context->params->flag &
+ BLO_LIBLINK_COLLECTION_INSTANCE) != 0;
+
+ /* NOTE: For collections we only view_layer-instantiate duplicated collections that have
+ * non-instantiated objects in them.
+ * NOTE: Also avoid view-layer-instantiating of collections children of other instantiated
+ * collections. This is why we need two passes here. */
+ LinkNode *itemlink;
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL || GS(id->name) != ID_GR) {
+ continue;
+ }
+
+ /* Forced instantiation of indirectly appended collections is not wanted. Users can now
+ * easily instantiate collections (and their objects) as needed by themselves. See T67032. */
+ /* We need to check that objects in that collections are already instantiated in a scene.
+ * Otherwise, it's better to add the collection to the scene's active collection, than to
+ * instantiate its objects in active scene's collection directly. See T61141.
+ *
+ * NOTE: We only check object directly into that collection, not recursively into its
+ * children.
+ */
+ Collection *collection = (Collection *)id;
+ /* The collection could be linked/appended together with an Empty object instantiating it,
+ * better not instantiate the collection in the view-layer in that case.
+ *
+ * Can easily happen when copy/pasting such instantiating empty, see T93839. */
+ const bool collection_is_instantiated = collection_instantiated_by_any_object(bmain,
+ collection);
+ /* Always consider adding collections directly selected by the user. */
+ bool do_add_collection = (item->tag & LINK_APPEND_TAG_INDIRECT) == 0 &&
+ !collection_is_instantiated;
+ /* In linking case, do not enforce instantiating non-directly linked collections/objects.
+ * This avoids cluttering the view-layers, user can instantiate themselves specific collections
+ * or objects easily from the Outliner if needed. */
+ if (!do_add_collection && do_append && !collection_is_instantiated) {
+ LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
+ Object *ob = coll_ob->ob;
+ if (!object_in_any_scene(bmain, ob)) {
+ do_add_collection = true;
+ break;
+ }
+ }
+ }
+ if (do_add_collection) {
+ collection->id.tag |= LIB_TAG_DOIT;
+ }
+ }
+
+ /* Second loop to actually instantiate collections tagged as such in first loop, unless some of
+ * their ancestor is also instantiated in case this is not an empty-instantiation. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL || GS(id->name) != ID_GR) {
+ continue;
+ }
+
+ Collection *collection = (Collection *)id;
+ bool do_add_collection = (id->tag & LIB_TAG_DOIT) != 0;
+
+ if (!do_add_collection) {
+ continue;
+ }
+ /* When instantiated into view-layer, do not add collections if one of their parents is also
+ * instantiated. */
+ if (!do_instantiate_as_empty &&
+ loose_data_instantiate_collection_parents_check_recursive(collection)) {
+ continue;
+ }
+ /* When instantiated as empty, do not add indirectly linked (i.e. non-user-selected)
+ * collections. */
+ if (do_instantiate_as_empty && (item->tag & LINK_APPEND_TAG_INDIRECT) != 0) {
+ continue;
+ }
+
+ loose_data_instantiate_ensure_active_collection(instantiate_context);
+ Collection *active_collection = instantiate_context->active_collection;
+
+ if (do_instantiate_as_empty) {
+ /* BKE_object_add(...) messes with the selection. */
+ Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2);
+ ob->type = OB_EMPTY;
+ ob->empty_drawsize = U.collection_instance_empty_size;
+
+ const bool set_selected = (lapp_context->params->flag & FILE_AUTOSELECT) != 0;
+ /* TODO: why is it OK to make this active here but not in other situations?
+ * See other callers of #object_base_instance_init */
+ const bool set_active = set_selected;
+ loose_data_instantiate_object_base_instance_init(
+ bmain, active_collection, ob, view_layer, v3d, lapp_context->params->flag, set_active);
+
+ /* Assign the collection. */
+ ob->instance_collection = collection;
+ id_us_plus(&collection->id);
+ ob->transflag |= OB_DUPLICOLLECTION;
+ copy_v3_v3(ob->loc, scene->cursor.location);
+ }
+ else {
+ /* Add collection as child of active collection. */
+ BKE_collection_child_add(bmain, active_collection, collection);
+
+ if ((lapp_context->params->flag & FILE_AUTOSELECT) != 0) {
+ LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
+ Object *ob = coll_ob->ob;
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ if (base) {
+ base->flag |= BASE_SELECTED;
+ BKE_scene_object_base_flag_sync_from_base(base);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void loose_data_instantiate_object_process(LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = lapp_context->params->bmain;
+ ViewLayer *view_layer = lapp_context->params->context.view_layer;
+ const View3D *v3d = lapp_context->params->context.v3d;
+
+ /* Do NOT make base active here! screws up GUI stuff,
+ * if you want it do it at the editor level. */
+ const bool object_set_active = false;
+
+ const bool is_linking = (lapp_context->params->flag & FILE_LINK) != 0;
+
+ /* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used
+ * anywhere. */
+ LinkNode *itemlink;
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL || GS(id->name) != ID_OB) {
+ continue;
+ }
+
+ /* In linking case, never instantiate stray objects that are not directly linked.
+ *
+ * While this is not ideal (in theory no object should remain un-owned), in case of indirectly
+ * linked objects, the other solution would be to add them to a local collection, which would
+ * make them directly linked. Think for now keeping them indirectly linked is more important.
+ * Ref. T93757.
+ */
+ if (is_linking && (item->tag & LINK_APPEND_TAG_INDIRECT) != 0) {
+ continue;
+ }
+
+ Object *ob = (Object *)id;
+
+ if (object_in_any_collection(bmain, ob)) {
+ continue;
+ }
+
+ loose_data_instantiate_ensure_active_collection(instantiate_context);
+ Collection *active_collection = instantiate_context->active_collection;
+
+ CLAMP_MIN(ob->id.us, 0);
+ ob->mode = OB_MODE_OBJECT;
+
+ loose_data_instantiate_object_base_instance_init(bmain,
+ active_collection,
+ ob,
+ view_layer,
+ v3d,
+ lapp_context->params->flag,
+ object_set_active);
+ }
+}
+
+static void loose_data_instantiate_obdata_process(LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = lapp_context->params->bmain;
+ Scene *scene = lapp_context->params->context.scene;
+ ViewLayer *view_layer = lapp_context->params->context.view_layer;
+ const View3D *v3d = lapp_context->params->context.v3d;
+
+ /* Do NOT make base active here! screws up GUI stuff,
+ * if you want it do it at the editor level. */
+ const bool object_set_active = false;
+
+ LinkNode *itemlink;
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL) {
+ continue;
+ }
+ const ID_Type idcode = GS(id->name);
+ if (!OB_DATA_SUPPORT_ID(idcode)) {
+ continue;
+ }
+ if ((id->tag & LIB_TAG_DOIT) == 0) {
+ continue;
+ }
+
+ loose_data_instantiate_ensure_active_collection(instantiate_context);
+ Collection *active_collection = instantiate_context->active_collection;
+
+ const int type = BKE_object_obdata_to_type(id);
+ BLI_assert(type != -1);
+ Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2);
+ ob->data = id;
+ id_us_plus(id);
+ BKE_object_materials_test(bmain, ob, ob->data);
+
+ loose_data_instantiate_object_base_instance_init(bmain,
+ active_collection,
+ ob,
+ view_layer,
+ v3d,
+ lapp_context->params->flag,
+ object_set_active);
+
+ copy_v3_v3(ob->loc, scene->cursor.location);
+
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+}
+
+static void loose_data_instantiate_object_rigidbody_postprocess(
+ LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = lapp_context->params->bmain;
+
+ LinkNode *itemlink;
+ /* Add rigid body objects and constraints to current RB world(s). */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL || GS(id->name) != ID_OB) {
+ continue;
+ }
+ BKE_rigidbody_ensure_local_object(bmain, (Object *)id);
+ }
+}
+
+static void loose_data_instantiate(LooseDataInstantiateContext *instantiate_context)
+{
+ if (instantiate_context->lapp_context->params->context.scene == NULL) {
+ /* In some cases, like the asset drag&drop e.g., the caller code manages instantiation itself.
+ */
+ return;
+ }
+
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ const bool do_obdata = (lapp_context->params->flag & BLO_LIBLINK_OBDATA_INSTANCE) != 0;
+
+ /* First pass on obdata to enable their instantiation by default, then do a second pass on
+ * objects to clear it for any obdata already in use. */
+ if (do_obdata) {
+ loose_data_instantiate_obdata_preprocess(instantiate_context);
+ }
+
+ /* First do collections, then objects, then obdata. */
+ loose_data_instantiate_collection_process(instantiate_context);
+ loose_data_instantiate_object_process(instantiate_context);
+ if (do_obdata) {
+ loose_data_instantiate_obdata_process(instantiate_context);
+ }
+
+ loose_data_instantiate_object_rigidbody_postprocess(instantiate_context);
+}
+
+static void new_id_to_item_mapping_add(BlendfileLinkAppendContext *lapp_context,
+ ID *id,
+ BlendfileLinkAppendContextItem *item)
+{
+ BLI_ghash_insert(lapp_context->new_id_to_item, id, item);
+
+ /* This ensures that if a liboverride reference is also linked/used by some other appended
+ * data, it gets a local copy instead of being made directly local, so that the liboverride
+ * references remain valid (i.e. linked data). */
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ id->override_library->reference->tag |= LIB_TAG_PRE_EXISTING;
+ }
+}
+
+/* Generate a mapping between newly linked IDs and their items, and tag linked IDs used as
+ * liboverride references as already existing. */
+static void new_id_to_item_mapping_create(BlendfileLinkAppendContext *lapp_context)
+{
+ lapp_context->new_id_to_item = BLI_ghash_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ for (LinkNode *itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+
+ new_id_to_item_mapping_add(lapp_context, id, item);
+ }
+}
+
+static int foreach_libblock_link_append_callback(LibraryIDLinkCallbackData *cb_data)
+{
+ /* NOTE: It is important to also skip liboverride references here, as those should never be made
+ * local. */
+ if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK |
+ IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
+ return IDWALK_RET_NOP;
+ }
+
+ BlendfileLinkAppendContextCallBack *data = cb_data->user_data;
+ ID *id = *cb_data->id_pointer;
+
+ if (id == NULL) {
+ return IDWALK_RET_NOP;
+ }
+
+ if (!BKE_idtype_idcode_is_linkable(GS(id->name))) {
+ /* While we do not want to add non-linkable ID (shape keys...) to the list of linked items,
+ * unfortunately they can use fully linkable valid IDs too, like actions. Those need to be
+ * processed, so we need to recursively deal with them here. */
+ /* NOTE: Since we are by-passing checks in `BKE_library_foreach_ID_link` by manually calling it
+ * recursively, we need to take care of potential recursion cases ourselves (e.g.animdata of
+ * shape-key referencing the shape-key itself). */
+ if (id != cb_data->id_self) {
+ BKE_library_foreach_ID_link(
+ cb_data->bmain, id, foreach_libblock_link_append_callback, data, IDWALK_NOP);
+ }
+ return IDWALK_RET_NOP;
+ }
+
+ /* In linking case, we always consider all linked IDs, even indirectly ones, for instantiation,
+ * so we need to add them all to the items list.
+ *
+ * In appending case, when `do_recursive` is false, we only make local IDs from same
+ * library(-ies) as the initially directly linked ones.
+ *
+ * NOTE: Since in append case, linked IDs are also fully skipped during instantiation step (see
+ * #append_loose_data_instantiate_process_check), we can avoid adding them to the items list
+ * completely. */
+ const bool do_link = (data->lapp_context->params->flag & FILE_LINK) != 0;
+ const bool do_recursive = (data->lapp_context->params->flag & BLO_LIBLINK_APPEND_RECURSIVE) !=
+ 0 ||
+ do_link;
+ if (!do_recursive && cb_data->id_owner->lib != id->lib) {
+ return IDWALK_RET_NOP;
+ }
+
+ BlendfileLinkAppendContextItem *item = BLI_ghash_lookup(data->lapp_context->new_id_to_item, id);
+ if (item == NULL) {
+ item = BKE_blendfile_link_append_context_item_add(
+ data->lapp_context, id->name, GS(id->name), NULL);
+ item->new_id = id;
+ item->source_library = id->lib;
+ /* Since we did not have an item for that ID yet, we know user did not selected it explicitly,
+ * it was rather linked indirectly. This info is important for instantiation of collections. */
+ item->tag |= LINK_APPEND_TAG_INDIRECT;
+ /* In linking case we already know what we want to do with those items. */
+ if (do_link) {
+ item->action = LINK_APPEND_ACT_KEEP_LINKED;
+ }
+ new_id_to_item_mapping_add(data->lapp_context, id, item);
+ }
+
+ /* NOTE: currently there is no need to do anything else here, but in the future this would be
+ * the place to add specific per-usage decisions on how to append an ID. */
+
+ return IDWALK_RET_NOP;
+}
+
+/** \} */
+
+/** \name Library link/append code.
+ * \{ */
+
+void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
+{
+ if (lapp_context->num_items == 0) {
+ /* Nothing to append. */
+ return;
+ }
+
+ Main *bmain = lapp_context->params->bmain;
+
+ BLI_assert((lapp_context->params->flag & FILE_LINK) == 0);
+
+ const bool set_fakeuser = (lapp_context->params->flag & BLO_LIBLINK_APPEND_SET_FAKEUSER) != 0;
+ const bool do_reuse_local_id = (lapp_context->params->flag &
+ BLO_LIBLINK_APPEND_LOCAL_ID_REUSE) != 0;
+
+ const int make_local_common_flags = LIB_ID_MAKELOCAL_FULL_LIBRARY |
+ ((lapp_context->params->flag &
+ BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR) != 0 ?
+ LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR :
+ 0);
+
+ LinkNode *itemlink;
+
+ new_id_to_item_mapping_create(lapp_context);
+ lapp_context->library_weak_reference_mapping = BKE_main_library_weak_reference_create(bmain);
+
+ /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect
+ * dependencies), this list will grow and we will process those IDs later, leading to a flatten
+ * recursive processing of all the linked dependencies. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ BLI_assert(item->userdata == NULL);
+
+ ID *existing_local_id = BKE_idtype_idcode_append_is_reusable(GS(id->name)) ?
+ BKE_main_library_weak_reference_search_item(
+ lapp_context->library_weak_reference_mapping,
+ id->lib->filepath,
+ id->name) :
+ NULL;
+
+ if (item->action != LINK_APPEND_ACT_UNSET) {
+ /* Already set, pass. */
+ }
+ if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) {
+ CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name);
+ item->action = LINK_APPEND_ACT_KEEP_LINKED;
+ }
+ else if (do_reuse_local_id && existing_local_id != NULL) {
+ CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name);
+ item->action = LINK_APPEND_ACT_REUSE_LOCAL;
+ item->userdata = existing_local_id;
+ }
+ else if (id->tag & LIB_TAG_PRE_EXISTING) {
+ CLOG_INFO(&LOG, 3, "Appended ID '%s' was already linked, need to copy it...", id->name);
+ item->action = LINK_APPEND_ACT_COPY_LOCAL;
+ }
+ else {
+ CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name);
+ item->action = LINK_APPEND_ACT_MAKE_LOCAL;
+ }
+
+ /* Only check dependencies if we are not keeping linked data, nor re-using existing local data.
+ */
+ if (!ELEM(item->action, LINK_APPEND_ACT_KEEP_LINKED, LINK_APPEND_ACT_REUSE_LOCAL)) {
+ BlendfileLinkAppendContextCallBack cb_data = {
+ .lapp_context = lapp_context, .item = item, .reports = reports};
+ BKE_library_foreach_ID_link(
+ bmain, id, foreach_libblock_link_append_callback, &cb_data, IDWALK_NOP);
+ }
+
+ /* If we found a matching existing local id but are not re-using it, we need to properly clear
+ * its weak reference to linked data. */
+ if (existing_local_id != NULL &&
+ !ELEM(item->action, LINK_APPEND_ACT_KEEP_LINKED, LINK_APPEND_ACT_REUSE_LOCAL)) {
+ BKE_main_library_weak_reference_remove_item(lapp_context->library_weak_reference_mapping,
+ id->lib->filepath,
+ id->name,
+ existing_local_id);
+ }
+ }
+
+ /* Effectively perform required operation on every linked ID. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+
+ ID *local_appended_new_id = NULL;
+ char lib_filepath[FILE_MAX];
+ BLI_strncpy(lib_filepath, id->lib->filepath, sizeof(lib_filepath));
+ char lib_id_name[MAX_ID_NAME];
+ BLI_strncpy(lib_id_name, id->name, sizeof(lib_id_name));
+
+ switch (item->action) {
+ case LINK_APPEND_ACT_COPY_LOCAL:
+ BKE_lib_id_make_local(bmain, id, make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_COPY);
+ local_appended_new_id = id->newid;
+ break;
+ case LINK_APPEND_ACT_MAKE_LOCAL:
+ BKE_lib_id_make_local(bmain,
+ id,
+ make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL |
+ LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING);
+ BLI_assert(id->newid == NULL);
+ local_appended_new_id = id;
+ break;
+ case LINK_APPEND_ACT_KEEP_LINKED:
+ /* Nothing to do here. */
+ break;
+ case LINK_APPEND_ACT_REUSE_LOCAL:
+ /* We only need to set `newid` to ID found in previous loop, for proper remapping. */
+ ID_NEW_SET(id, item->userdata);
+ /* This is not a 'new' local appended id, do not set `local_appended_new_id` here. */
+ break;
+ case LINK_APPEND_ACT_UNSET:
+ CLOG_ERROR(
+ &LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name);
+ break;
+ default:
+ BLI_assert(0);
+ }
+
+ if (local_appended_new_id != NULL) {
+ if (BKE_idtype_idcode_append_is_reusable(GS(local_appended_new_id->name))) {
+ BKE_main_library_weak_reference_add_item(lapp_context->library_weak_reference_mapping,
+ lib_filepath,
+ lib_id_name,
+ local_appended_new_id);
+ }
+
+ if (set_fakeuser) {
+ if (!ELEM(GS(local_appended_new_id->name), ID_OB, ID_GR)) {
+ /* Do not set fake user on objects nor collections (instancing). */
+ id_fake_user_set(local_appended_new_id);
+ }
+ }
+ }
+ }
+
+ BKE_main_library_weak_reference_destroy(lapp_context->library_weak_reference_mapping);
+ lapp_context->library_weak_reference_mapping = NULL;
+
+ /* Remap IDs as needed. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+
+ if (item->action == LINK_APPEND_ACT_KEEP_LINKED) {
+ continue;
+ }
+
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ if (ELEM(item->action, LINK_APPEND_ACT_COPY_LOCAL, LINK_APPEND_ACT_REUSE_LOCAL)) {
+ BLI_assert(ID_IS_LINKED(id));
+ id = id->newid;
+ if (id == NULL) {
+ continue;
+ }
+ }
+
+ BLI_assert(!ID_IS_LINKED(id));
+
+ BKE_libblock_relink_to_newid(bmain, id, 0);
+ }
+
+ /* Remove linked IDs when a local existing data has been reused instead. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+
+ if (item->action != LINK_APPEND_ACT_REUSE_LOCAL) {
+ continue;
+ }
+
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ BLI_assert(ID_IS_LINKED(id));
+ BLI_assert(id->newid != NULL);
+
+ id->tag |= LIB_TAG_DOIT;
+ item->new_id = id->newid;
+ }
+ BKE_id_multi_tagged_delete(bmain);
+
+ /* Instantiate newly created (duplicated) IDs as needed. */
+ LooseDataInstantiateContext instantiate_context = {.lapp_context = lapp_context,
+ .active_collection = NULL};
+ loose_data_instantiate(&instantiate_context);
+
+ /* Attempt to deal with object proxies.
+ *
+ * NOTE: Copied from `BKE_library_make_local`, but this is not really working (as in, not
+ * producing any useful result in any known use case), neither here nor in
+ * `BKE_library_make_local` currently.
+ * Proxies are end of life anyway, so not worth spending time on this. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+
+ if (item->action != LINK_APPEND_ACT_COPY_LOCAL) {
+ continue;
+ }
+
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ BLI_assert(ID_IS_LINKED(id));
+
+ /* Attempt to re-link copied proxy objects. This allows appending of an entire scene
+ * from another blend file into this one, even when that blend file contains proxified
+ * armatures that have local references. Since the proxified object needs to be linked
+ * (not local), this will only work when the "Localize all" checkbox is disabled.
+ * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
+ if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
+ Object *ob = (Object *)id;
+ Object *ob_new = (Object *)id->newid;
+ bool is_local = false, is_lib = false;
+
+ /* Proxies only work when the proxified object is linked-in from a library. */
+ if (!ID_IS_LINKED(ob->proxy)) {
+ CLOG_WARN(&LOG,
+ "Proxy object %s will lose its link to %s, because the "
+ "proxified object is local",
+ id->newid->name,
+ ob->proxy->id.name);
+ continue;
+ }
+
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+
+ /* We can only switch the proxy'ing to a made-local proxy if it is no longer
+ * referred to from a library. Not checking for local use; if new local proxy
+ * was not used locally would be a nasty bug! */
+ if (is_local || is_lib) {
+ CLOG_WARN(&LOG,
+ "Made-local proxy object %s will lose its link to %s, "
+ "because the linked-in proxy is referenced (is_local=%i, is_lib=%i)",
+ id->newid->name,
+ ob->proxy->id.name,
+ is_local,
+ is_lib);
+ }
+ else {
+ /* we can switch the proxy'ing from the linked-in to the made-local proxy.
+ * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
+ * was already allocated by object_make_local() (which called BKE_object_copy). */
+ ob_new->proxy = ob->proxy;
+ ob_new->proxy_group = ob->proxy_group;
+ ob_new->proxy_from = ob->proxy_from;
+ ob_new->proxy->proxy_from = ob_new;
+ ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
+ }
+ }
+ }
+
+ BKE_main_id_newptr_and_tag_clear(bmain);
+}
+
+void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
+{
+ if (lapp_context->num_items == 0) {
+ /* Nothing to be linked. */
+ return;
+ }
+
+ BLI_assert(lapp_context->num_libraries != 0);
+
+ Main *mainl;
+ Library *lib;
+
+ LinkNode *liblink, *itemlink;
+ int lib_idx, item_idx;
+
+ for (lib_idx = 0, liblink = lapp_context->libraries.list; liblink;
+ lib_idx++, liblink = liblink->next) {
+ BlendfileLinkAppendContextLibrary *lib_context = liblink->link;
+ char *libname = lib_context->path;
+ BlendHandle *blo_handle = link_append_context_library_blohandle_ensure(
+ lapp_context, lib_context, reports);
+
+ if (blo_handle == NULL) {
+ /* Unlikely since we just browsed it, but possible
+ * Error reports will have been made by BLO_blendhandle_from_file() */
+ continue;
+ }
+
+ /* here appending/linking starts */
+
+ mainl = BLO_library_link_begin(&blo_handle, libname, lapp_context->params);
+ lib = mainl->curlib;
+ BLI_assert(lib);
+ UNUSED_VARS_NDEBUG(lib);
+
+ if (mainl->versionfile < 250) {
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Linking or appending from a very old .blend file format (%d.%d), no animation "
+ "conversion will "
+ "be done! You may want to re-save your lib file with current Blender",
+ mainl->versionfile,
+ mainl->subversionfile);
+ }
+
+ /* For each lib file, we try to link all items belonging to that lib,
+ * and tag those successful to not try to load them again with the other libs. */
+ for (item_idx = 0, itemlink = lapp_context->items.list; itemlink;
+ item_idx++, itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *new_id;
+
+ if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) {
+ continue;
+ }
+
+ new_id = BLO_library_link_named_part(
+ mainl, &blo_handle, item->idcode, item->name, lapp_context->params);
+
+ if (new_id) {
+ /* If the link is successful, clear item's libs 'todo' flags.
+ * This avoids trying to link same item with other libraries to come. */
+ BLI_bitmap_set_all(item->libraries, false, lapp_context->num_libraries);
+ item->new_id = new_id;
+ item->source_library = new_id->lib;
+ }
+ }
+
+ BLO_library_link_end(mainl, &blo_handle, lapp_context->params);
+ link_append_context_library_blohandle_release(lapp_context, lib_context);
+ }
+
+ /* Instantiate newly linked IDs as needed, if no append is scheduled. */
+ if ((lapp_context->params->flag & FILE_LINK) != 0 &&
+ lapp_context->params->context.scene != NULL) {
+ new_id_to_item_mapping_create(lapp_context);
+ /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect
+ * dependencies), this list will grow and we will process those IDs later, leading to a flatten
+ * recursive processing of all the linked dependencies. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ BLI_assert(item->userdata == NULL);
+
+ BlendfileLinkAppendContextCallBack cb_data = {
+ .lapp_context = lapp_context, .item = item, .reports = reports};
+ BKE_library_foreach_ID_link(lapp_context->params->bmain,
+ id,
+ foreach_libblock_link_append_callback,
+ &cb_data,
+ IDWALK_NOP);
+ }
+
+ LooseDataInstantiateContext instantiate_context = {.lapp_context = lapp_context,
+ .active_collection = NULL};
+ loose_data_instantiate(&instantiate_context);
+ }
+}
+
+/** \} */
+
+/** \name Library relocating code.
+ * \{ */
+
+static void blendfile_library_relocate_remap(Main *bmain,
+ ID *old_id,
+ ID *new_id,
+ ReportList *reports,
+ const bool do_reload,
+ const short remap_flags)
+{
+ BLI_assert(old_id);
+ if (do_reload) {
+ /* Since we asked for placeholders in case of missing IDs,
+ * we expect to always get a valid one. */
+ BLI_assert(new_id);
+ }
+ if (new_id) {
+ CLOG_INFO(&LOG,
+ 4,
+ "Before remap of %s, old_id users: %d, new_id users: %d",
+ old_id->name,
+ old_id->us,
+ new_id->us);
+ BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags);
+
+ if (old_id->flag & LIB_FAKEUSER) {
+ id_fake_user_clear(old_id);
+ id_fake_user_set(new_id);
+ }
+
+ CLOG_INFO(&LOG,
+ 4,
+ "After remap of %s, old_id users: %d, new_id users: %d",
+ old_id->name,
+ old_id->us,
+ new_id->us);
+
+ /* In some cases, new_id might become direct link, remove parent of library in this case. */
+ if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) {
+ if (do_reload) {
+ BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */
+ }
+ new_id->lib->parent = NULL;
+ }
+ }
+
+ if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) {
+ /* Note that this *should* not happen - but better be safe than sorry in this area,
+ * at least until we are 100% sure this cannot ever happen.
+ * Also, we can safely assume names were unique so far,
+ * so just replacing '.' by '~' should work,
+ * but this does not totally rules out the possibility of name collision. */
+ size_t len = strlen(old_id->name);
+ size_t dot_pos;
+ bool has_num = false;
+
+ for (dot_pos = len; dot_pos--;) {
+ char c = old_id->name[dot_pos];
+ if (c == '.') {
+ break;
+ }
+ if (c < '0' || c > '9') {
+ has_num = false;
+ break;
+ }
+ has_num = true;
+ }
+
+ if (has_num) {
+ old_id->name[dot_pos] = '~';
+ }
+ else {
+ len = MIN2(len, MAX_ID_NAME - 7);
+ BLI_strncpy(&old_id->name[len], "~000", 7);
+ }
+
+ id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id, NULL);
+
+ BKE_reportf(
+ reports,
+ RPT_WARNING,
+ "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, "
+ "old one (%d remaining users) had to be kept and was renamed to '%s'",
+ new_id->name,
+ old_id->us,
+ old_id->name);
+ }
+}
+
+void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
+ ReportList *reports,
+ Library *library,
+ const bool do_reload)
+{
+ ListBase *lbarray[INDEX_ID_MAX];
+ int lba_idx;
+
+ LinkNode *itemlink;
+ int item_idx;
+
+ Main *bmain = lapp_context->params->bmain;
+
+ /* All override rules need to be up to date, since there will be no do_version here, otherwise
+ * older, now-invalid rules might be applied and likely fail, or some changes might be missing,
+ * etc. See T93353. */
+ BKE_lib_override_library_main_operations_create(bmain, true);
+
+ /* Remove all IDs to be reloaded from Main. */
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id = lbarray[lba_idx]->first;
+ const short idcode = id ? GS(id->name) : 0;
+
+ if (!id || !BKE_idtype_idcode_is_linkable(idcode)) {
+ /* No need to reload non-linkable datatypes,
+ * those will get relinked with their 'users ID'. */
+ continue;
+ }
+
+ for (; id; id = id->next) {
+ if (id->lib == library) {
+ BlendfileLinkAppendContextItem *item;
+
+ /* We remove it from current Main, and add it to items to link... */
+ /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */
+ BLI_remlink(lbarray[lba_idx], id);
+ /* Usual special code for ShapeKeys snowflakes... */
+ Key *old_key = BKE_key_from_id(id);
+ if (old_key != NULL) {
+ BLI_remlink(which_libbase(bmain, GS(old_key->id.name)), &old_key->id);
+ }
+
+ item = BKE_blendfile_link_append_context_item_add(lapp_context, id->name + 2, idcode, id);
+ BLI_bitmap_set_all(item->libraries, true, (size_t)lapp_context->num_libraries);
+
+ CLOG_INFO(&LOG, 4, "Datablock to seek for: %s", id->name);
+ }
+ }
+ }
+
+ if (lapp_context->num_items == 0) {
+ /* Early out in case there is nothing to do. */
+ return;
+ }
+
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+
+ /* We do not want any instantiation here! */
+ BKE_blendfile_link(lapp_context, reports);
+
+ BKE_main_lock(bmain);
+
+ /* We add back old id to bmain.
+ * We need to do this in a first, separated loop, otherwise some of those may not be handled by
+ * ID remapping, which means they would still reference old data to be deleted... */
+ for (item_idx = 0, itemlink = lapp_context->items.list; itemlink;
+ item_idx++, itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *old_id = item->userdata;
+
+ BLI_assert(old_id);
+ BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id);
+
+ /* Usual special code for ShapeKeys snowflakes... */
+ Key *old_key = BKE_key_from_id(old_id);
+ if (old_key != NULL) {
+ BLI_addtail(which_libbase(bmain, GS(old_key->id.name)), &old_key->id);
+ }
+ }
+
+ /* Since our (old) reloaded IDs were removed from main, the user count done for them in linking
+ * code is wrong, we need to redo it here after adding them back to main. */
+ BKE_main_id_refcount_recompute(bmain, false);
+
+ /* Note that in reload case, we also want to replace indirect usages. */
+ const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE |
+ ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE |
+ (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
+ for (item_idx = 0, itemlink = lapp_context->items.list; itemlink;
+ item_idx++, itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *old_id = item->userdata;
+ ID *new_id = item->new_id;
+
+ blendfile_library_relocate_remap(bmain, old_id, new_id, reports, do_reload, remap_flags);
+ if (new_id == NULL) {
+ continue;
+ }
+ /* Usual special code for ShapeKeys snowflakes... */
+ Key **old_key_p = BKE_key_from_id_p(old_id);
+ if (old_key_p == NULL) {
+ continue;
+ }
+ Key *old_key = *old_key_p;
+ Key *new_key = BKE_key_from_id(new_id);
+ if (old_key != NULL) {
+ *old_key_p = NULL;
+ id_us_min(&old_key->id);
+ blendfile_library_relocate_remap(
+ bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags);
+ *old_key_p = old_key;
+ id_us_plus_no_lib(&old_key->id);
+ }
+ }
+
+ BKE_main_unlock(bmain);
+
+ for (item_idx = 0, itemlink = lapp_context->items.list; itemlink;
+ item_idx++, itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *old_id = item->userdata;
+
+ if (old_id->us == 0) {
+ BKE_id_free(bmain, old_id);
+ }
+ }
+
+ /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable
+ * (shape keys e.g.), so we need another loop here to clear old ones if possible. */
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id, *id_next;
+ for (id = lbarray[lba_idx]->first; id; id = id_next) {
+ id_next = id->next;
+ /* XXX That check may be a bit to generic/permissive? */
+ if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) {
+ BKE_id_free(bmain, id);
+ }
+ }
+ }
+
+ /* Get rid of no more used libraries... */
+ BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true);
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id;
+ for (id = lbarray[lba_idx]->first; id; id = id->next) {
+ if (id->lib) {
+ id->lib->id.tag &= ~LIB_TAG_DOIT;
+ }
+ }
+ }
+ Library *lib, *lib_next;
+ for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) {
+ lib_next = lib->id.next;
+ if (lib->id.tag & LIB_TAG_DOIT) {
+ id_us_clear_real(&lib->id);
+ if (lib->id.us == 0) {
+ BKE_id_free(bmain, (ID *)lib);
+ }
+ }
+ }
+
+ /* Update overrides of reloaded linked data-blocks. */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id) ||
+ (id->tag & LIB_TAG_PRE_EXISTING) == 0) {
+ continue;
+ }
+ if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) {
+ BKE_lib_override_library_update(bmain, id);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+
+ /* Resync overrides if needed. */
+ if (!USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) {
+ BKE_lib_override_library_main_resync(bmain,
+ lapp_context->params->context.scene,
+ lapp_context->params->context.view_layer,
+ &(struct BlendFileReadReport){
+ .reports = reports,
+ });
+ /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */
+ BKE_lib_override_library_main_operations_create(bmain, true);
+ }
+
+ BKE_main_collection_sync(bmain);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index a7257133821..a9f26d00007 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -1061,7 +1061,6 @@ static int boid_condition_is_true(BoidCondition *cond)
}
#endif
-/* determines the velocity the boid wants to have */
void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
{
BoidRule *rule;
@@ -1218,7 +1217,6 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
}
}
}
-/* tries to realize the wanted velocity taking all constraints into account */
void boid_body(BoidBrainData *bbd, ParticleData *pa)
{
BoidSettings *boids = bbd->part->boids;
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 371ec14876b..a1570b4e031 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -15,7 +15,7 @@
*/
/** \file
- * \ingroup bli
+ * \ingroup bke
*/
/* TODO:
@@ -66,13 +66,14 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BKE_font.h"
+#include "BKE_idtype.h"
#include "BKE_image.h"
#include "BKE_lib_id.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_report.h"
+#include "BKE_vfont.h"
#include "BKE_bpath.h" /* own include */
@@ -87,213 +88,157 @@
static CLG_LogRef LOG = {"bke.bpath"};
/* -------------------------------------------------------------------- */
-/** \name Check Missing Files
+/** \name Generic File Path Traversal API
* \{ */
-static bool checkMissingFiles_visit_cb(void *userdata,
- char *UNUSED(path_dst),
- const char *path_src)
+void BKE_bpath_foreach_path_id(BPathForeachPathData *bpath_data, ID *id)
{
- ReportList *reports = (ReportList *)userdata;
+ const eBPathForeachFlag flag = bpath_data->flag;
+ const char *absbase = (flag & BKE_BPATH_FOREACH_PATH_ABSOLUTE) ?
+ ID_BLEND_PATH(bpath_data->bmain, id) :
+ NULL;
+ bpath_data->absolute_base_path = absbase;
- if (!BLI_exists(path_src)) {
- BKE_reportf(reports, RPT_WARNING, "Path '%s' not found", path_src);
+ if ((flag & BKE_BPATH_FOREACH_PATH_SKIP_LINKED) && ID_IS_LINKED(id)) {
+ return;
}
- return false;
-}
-
-/* high level function */
-void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports)
-{
- BKE_bpath_traverse_main(bmain,
- checkMissingFiles_visit_cb,
- BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_SKIP_PACKED,
- reports);
-}
+ if (id->library_weak_reference != NULL &&
+ (flag & BKE_BPATH_TRAVERSE_SKIP_WEAK_REFERENCES) == 0) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, id->library_weak_reference->library_filepath);
+ }
-/** \} */
+ bNodeTree *embedded_node_tree = ntreeFromID(id);
+ if (embedded_node_tree != NULL) {
+ BKE_bpath_foreach_path_id(bpath_data, &embedded_node_tree->id);
+ }
-/* -------------------------------------------------------------------- */
-/** \name Rebase Relative Paths
- * \{ */
+ const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
-typedef struct BPathRebase_Data {
- const char *basedir_src;
- const char *basedir_dst;
- ReportList *reports;
+ BLI_assert(id_type != NULL);
+ if (id_type == NULL || id_type->foreach_path == NULL) {
+ return;
+ }
- int count_tot;
- int count_changed;
- int count_failed;
-} BPathRebase_Data;
+ id_type->foreach_path(id, bpath_data);
+}
-static bool bpath_relative_rebase_visit_cb(void *userdata, char *path_dst, const char *path_src)
+void BKE_bpath_foreach_path_main(BPathForeachPathData *bpath_data)
{
- BPathRebase_Data *data = (BPathRebase_Data *)userdata;
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bpath_data->bmain, id) {
+ BKE_bpath_foreach_path_id(bpath_data, id);
+ }
+ FOREACH_MAIN_ID_END;
+}
- data->count_tot++;
+bool BKE_bpath_foreach_path_fixed_process(BPathForeachPathData *bpath_data, char *path)
+{
+ const char *absolute_base_path = bpath_data->absolute_base_path;
- if (BLI_path_is_rel(path_src)) {
- char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
- BLI_strncpy(filepath, path_src, FILE_MAX);
- if (BLI_path_abs(filepath, data->basedir_src)) {
- BLI_path_normalize(NULL, filepath);
+ char path_src_buf[FILE_MAX];
+ const char *path_src;
+ char path_dst[FILE_MAX];
- /* This may fail, if so it's fine to leave absolute since the path is still valid. */
- BLI_path_rel(filepath, data->basedir_dst);
+ if (absolute_base_path) {
+ BLI_strncpy(path_src_buf, path, sizeof(path_src_buf));
+ BLI_path_abs(path_src_buf, absolute_base_path);
+ path_src = path_src_buf;
+ }
+ else {
+ path_src = path;
+ }
- BLI_strncpy(path_dst, filepath, FILE_MAX);
- data->count_changed++;
- return true;
- }
+ /* so functions can check old value */
+ BLI_strncpy(path_dst, path, FILE_MAX);
- /* Failed to make relative path absolute. */
- BLI_assert(0);
- BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
- data->count_failed++;
- return false;
+ if (bpath_data->callback_function(bpath_data, path_dst, path_src)) {
+ BLI_strncpy(path, path_dst, FILE_MAX);
+ return true;
}
- /* Absolute, leave this as-is. */
return false;
}
-void BKE_bpath_relative_rebase(Main *bmain,
- const char *basedir_src,
- const char *basedir_dst,
- ReportList *reports)
+bool BKE_bpath_foreach_path_dirfile_fixed_process(BPathForeachPathData *bpath_data,
+ char *path_dir,
+ char *path_file)
{
- BPathRebase_Data data = {NULL};
- const int flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
-
- BLI_assert(basedir_src[0] != '\0');
- BLI_assert(basedir_dst[0] != '\0');
+ const char *absolute_base_path = bpath_data->absolute_base_path;
- data.basedir_src = basedir_src;
- data.basedir_dst = basedir_dst;
- data.reports = reports;
-
- BKE_bpath_traverse_main(bmain, bpath_relative_rebase_visit_cb, flag, (void *)&data);
+ char path_src[FILE_MAX];
+ char path_dst[FILE_MAX];
- BKE_reportf(reports,
- data.count_failed ? RPT_WARNING : RPT_INFO,
- "Total files %d | Changed %d | Failed %d",
- data.count_tot,
- data.count_changed,
- data.count_failed);
-}
+ BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
-/** \} */
+ /* So that functions can access the old value. */
+ BLI_strncpy(path_dst, path_src, FILE_MAX);
-/* -------------------------------------------------------------------- */
-/** \name Make Paths Relative
- * \{ */
+ if (absolute_base_path) {
+ BLI_path_abs(path_src, absolute_base_path);
+ }
-typedef struct BPathRemap_Data {
- const char *basedir;
- ReportList *reports;
+ if (bpath_data->callback_function(bpath_data, path_dst, (const char *)path_src)) {
+ BLI_split_dirfile(path_dst, path_dir, path_file, FILE_MAXDIR, FILE_MAXFILE);
+ return true;
+ }
- int count_tot;
- int count_changed;
- int count_failed;
-} BPathRemap_Data;
+ return false;
+}
-static bool bpath_relative_convert_visit_cb(void *userdata, char *path_dst, const char *path_src)
+bool BKE_bpath_foreach_path_allocated_process(BPathForeachPathData *bpath_data, char **path)
{
- BPathRemap_Data *data = (BPathRemap_Data *)userdata;
+ const char *absolute_base_path = bpath_data->absolute_base_path;
- data->count_tot++;
-
- if (BLI_path_is_rel(path_src)) {
- return false; /* already relative */
- }
+ char path_src_buf[FILE_MAX];
+ const char *path_src;
+ char path_dst[FILE_MAX];
- strcpy(path_dst, path_src);
- BLI_path_rel(path_dst, data->basedir);
- if (BLI_path_is_rel(path_dst)) {
- data->count_changed++;
+ if (absolute_base_path) {
+ BLI_strncpy(path_src_buf, *path, sizeof(path_src_buf));
+ BLI_path_abs(path_src_buf, absolute_base_path);
+ path_src = path_src_buf;
}
else {
- BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made relative", path_src);
- data->count_failed++;
+ path_src = *path;
}
- return true;
-}
-
-void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *reports)
-{
- BPathRemap_Data data = {NULL};
- const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
- if (basedir[0] == '\0') {
- CLOG_ERROR(&LOG, "basedir='', this is a bug");
- return;
+ if (bpath_data->callback_function(bpath_data, path_dst, path_src)) {
+ MEM_freeN(*path);
+ (*path) = BLI_strdup(path_dst);
+ return true;
}
- data.basedir = basedir;
- data.reports = reports;
-
- BKE_bpath_traverse_main(bmain, bpath_relative_convert_visit_cb, flag, (void *)&data);
-
- BKE_reportf(reports,
- data.count_failed ? RPT_WARNING : RPT_INFO,
- "Total files %d | Changed %d | Failed %d",
- data.count_tot,
- data.count_changed,
- data.count_failed);
+ return false;
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Make Paths Absolute
+/** \name Check Missing Files
* \{ */
-static bool bpath_absolute_convert_visit_cb(void *userdata, char *path_dst, const char *path_src)
+static bool check_missing_files_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *UNUSED(path_dst),
+ const char *path_src)
{
- BPathRemap_Data *data = (BPathRemap_Data *)userdata;
-
- data->count_tot++;
+ ReportList *reports = (ReportList *)bpath_data->user_data;
- if (BLI_path_is_rel(path_src) == false) {
- return false; /* already absolute */
+ if (!BLI_exists(path_src)) {
+ BKE_reportf(reports, RPT_WARNING, "Path '%s' not found", path_src);
}
- strcpy(path_dst, path_src);
- BLI_path_abs(path_dst, data->basedir);
- if (BLI_path_is_rel(path_dst) == false) {
- data->count_changed++;
- }
- else {
- BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
- data->count_failed++;
- }
- return true;
+ return false;
}
-/* similar to BKE_bpath_relative_convert - keep in sync! */
-void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *reports)
+void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports)
{
- BPathRemap_Data data = {NULL};
- const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
-
- if (basedir[0] == '\0') {
- CLOG_ERROR(&LOG, "basedir='', this is a bug");
- return;
- }
-
- data.basedir = basedir;
- data.reports = reports;
-
- BKE_bpath_traverse_main(bmain, bpath_absolute_convert_visit_cb, flag, (void *)&data);
-
- BKE_reportf(reports,
- data.count_failed ? RPT_WARNING : RPT_INFO,
- "Total files %d | Changed %d | Failed %d",
- data.count_tot,
- data.count_changed,
- data.count_failed);
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){
+ .bmain = bmain,
+ .callback_function = check_missing_files_foreach_path_cb,
+ .flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_SKIP_PACKED |
+ BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN | BKE_BPATH_TRAVERSE_SKIP_WEAK_REFERENCES,
+ .user_data = reports});
}
/** \} */
@@ -302,72 +247,79 @@ void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *re
/** \name Find Missing Files
* \{ */
-/**
- * find this file recursively, use the biggest file so thumbnails don't get used by mistake
- * \param filename_new: the path will be copied here, caller must initialize as empty string.
- * \param dirname: subdir to search
- * \param filename: set this filename
- * \param filesize: filesize for the file
+#define MAX_DIR_RECURSE 16
+#define FILESIZE_INVALID_DIRECTORY -1
+
+/** Find the given filename recursively in the given search directory and its sub-directories.
+ *
+ * \note Use the biggest matching file found, so that thumbnails don't get used by mistake.
+ *
+ * \param search_directory: Directory to search in.
+ * \param filename_src: Search for this filename.
+ * \param r_filename_new: The path of the new found file will be copied here, caller must
+ * initialize as empty string.
+ * \param r_filesize: Size of the file, `FILESIZE_INVALID_DIRECTORY` if search directory could not
+ * be opened.
+ * \param r_recurse_depth: Current recursion depth.
*
- * \returns found: 1/0.
+ * \return true if found, false otherwise.
*/
-#define MAX_RECUR 16
-static bool missing_files_find__recursive(char *filename_new,
- const char *dirname,
- const char *filename,
+static bool missing_files_find__recursive(const char *search_directory,
+ const char *filename_src,
+ char r_filename_new[FILE_MAX],
int64_t *r_filesize,
- int *r_recur_depth)
+ int *r_recurse_depth)
{
- /* file searching stuff */
+ /* TODO: Move this function to BLI_path_utils? The 'biggest size' behavior is quite specific
+ * though... */
DIR *dir;
- struct dirent *de;
BLI_stat_t status;
char path[FILE_MAX];
int64_t size;
bool found = false;
- dir = opendir(dirname);
+ dir = opendir(search_directory);
if (dir == NULL) {
return found;
}
- if (*r_filesize == -1) {
- *r_filesize = 0; /* dir opened fine */
+ if (*r_filesize == FILESIZE_INVALID_DIRECTORY) {
+ *r_filesize = 0; /* The directory opened fine. */
}
- while ((de = readdir(dir)) != NULL) {
-
+ for (struct dirent *de = readdir(dir); de != NULL; de = readdir(dir)) {
if (FILENAME_IS_CURRPAR(de->d_name)) {
continue;
}
- BLI_join_dirfile(path, sizeof(path), dirname, de->d_name);
+ BLI_join_dirfile(path, sizeof(path), search_directory, de->d_name);
if (BLI_stat(path, &status) == -1) {
- continue; /* can't stat, don't bother with this file, could print debug info here */
+ CLOG_WARN(&LOG, "Cannot get file status (`stat()`) of '%s'", path);
+ continue;
}
- if (S_ISREG(status.st_mode)) { /* is file */
- if (BLI_path_ncmp(filename, de->d_name, FILE_MAX) == 0) { /* name matches */
- /* open the file to read its size */
+ if (S_ISREG(status.st_mode)) { /* It is a file. */
+ if (BLI_path_ncmp(filename_src, de->d_name, FILE_MAX) == 0) { /* Names match. */
size = status.st_size;
- if ((size > 0) && (size > *r_filesize)) { /* find the biggest file */
+ if ((size > 0) && (size > *r_filesize)) { /* Find the biggest matching file. */
*r_filesize = size;
- BLI_strncpy(filename_new, path, FILE_MAX);
+ BLI_strncpy(r_filename_new, path, FILE_MAX);
found = true;
}
}
}
- else if (S_ISDIR(status.st_mode)) { /* is subdir */
- if (*r_recur_depth <= MAX_RECUR) {
- (*r_recur_depth)++;
+ else if (S_ISDIR(status.st_mode)) { /* It is a sub-directory. */
+ if (*r_recurse_depth <= MAX_DIR_RECURSE) {
+ (*r_recurse_depth)++;
found |= missing_files_find__recursive(
- filename_new, path, filename, r_filesize, r_recur_depth);
- (*r_recur_depth)--;
+ path, filename_src, r_filename_new, r_filesize, r_recurse_depth);
+ (*r_recurse_depth)--;
}
}
}
+
closedir(dir);
return found;
}
@@ -376,37 +328,37 @@ typedef struct BPathFind_Data {
const char *basedir;
const char *searchdir;
ReportList *reports;
- bool find_all;
+ bool find_all; /* Also search for files which current path is still valid. */
} BPathFind_Data;
-static bool missing_files_find__visit_cb(void *userdata, char *path_dst, const char *path_src)
+static bool missing_files_find_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- BPathFind_Data *data = (BPathFind_Data *)userdata;
+ BPathFind_Data *data = (BPathFind_Data *)bpath_data->user_data;
char filename_new[FILE_MAX];
- int64_t filesize = -1;
- int recur_depth = 0;
- bool found;
+ int64_t filesize = FILESIZE_INVALID_DIRECTORY;
+ int recurse_depth = 0;
+ bool is_found;
- if (data->find_all == false) {
- if (BLI_exists(path_src)) {
- return false;
- }
+ if (!data->find_all && BLI_exists(path_src)) {
+ return false;
}
filename_new[0] = '\0';
- found = missing_files_find__recursive(
- filename_new, data->searchdir, BLI_path_basename(path_src), &filesize, &recur_depth);
+ is_found = missing_files_find__recursive(
+ data->searchdir, BLI_path_basename(path_src), filename_new, &filesize, &recurse_depth);
- if (filesize == -1) { /* could not open dir */
+ if (filesize == FILESIZE_INVALID_DIRECTORY) {
BKE_reportf(data->reports,
RPT_WARNING,
- "Could not open directory '%s'",
+ "Could not open the directory '%s'",
BLI_path_basename(data->searchdir));
return false;
}
- if (found == false) {
+ if (is_found == false) {
BKE_reportf(data->reports,
RPT_WARNING,
"Could not find '%s' in '%s'",
@@ -419,7 +371,7 @@ static bool missing_files_find__visit_cb(void *userdata, char *path_dst, const c
BLI_strncpy(path_dst, filename_new, FILE_MAX);
- /* keep path relative if the previous one was relative */
+ /* Keep the path relative if the previous one was relative. */
if (was_relative) {
BLI_path_rel(path_dst, data->basedir);
}
@@ -433,480 +385,282 @@ void BKE_bpath_missing_files_find(Main *bmain,
const bool find_all)
{
struct BPathFind_Data data = {NULL};
- const int flag = BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_RELOAD_EDITED;
+ const int flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_RELOAD_EDITED |
+ BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN;
data.basedir = BKE_main_blendfile_path(bmain);
data.reports = reports;
data.searchdir = searchpath;
data.find_all = find_all;
- BKE_bpath_traverse_main(bmain, missing_files_find__visit_cb, flag, (void *)&data);
+ BKE_bpath_foreach_path_main(
+ &(BPathForeachPathData){.bmain = bmain,
+ .callback_function = missing_files_find_foreach_path_cb,
+ .flag = flag,
+ .user_data = &data});
}
+#undef MAX_DIR_RECURSE
+#undef FILESIZE_INVALID_DIRECTORY
+
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Generic File Path Traversal API
+/** \name Rebase Relative Paths
* \{ */
-/**
- * Run a visitor on a string, replacing the contents of the string as needed.
- */
-static bool rewrite_path_fixed(char *path,
- BPathVisitor visit_cb,
- const char *absbase,
- void *userdata)
+typedef struct BPathRebase_Data {
+ const char *basedir_src;
+ const char *basedir_dst;
+ ReportList *reports;
+
+ int count_tot;
+ int count_changed;
+ int count_failed;
+} BPathRebase_Data;
+
+static bool relative_rebase_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- char path_src_buf[FILE_MAX];
- const char *path_src;
- char path_dst[FILE_MAX];
+ BPathRebase_Data *data = (BPathRebase_Data *)bpath_data->user_data;
- if (absbase) {
- BLI_strncpy(path_src_buf, path, sizeof(path_src_buf));
- BLI_path_abs(path_src_buf, absbase);
- path_src = path_src_buf;
+ data->count_tot++;
+
+ if (!BLI_path_is_rel(path_src)) {
+ /* Absolute, leave this as-is. */
+ return false;
}
- else {
- path_src = path;
+
+ char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
+ BLI_strncpy(filepath, path_src, FILE_MAX);
+ if (!BLI_path_abs(filepath, data->basedir_src)) {
+ BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
+ data->count_failed++;
+ return false;
}
- /* so functions can check old value */
- BLI_strncpy(path_dst, path, FILE_MAX);
+ BLI_path_normalize(NULL, filepath);
- if (visit_cb(userdata, path_dst, path_src)) {
- BLI_strncpy(path, path_dst, FILE_MAX);
- return true;
- }
+ /* This may fail, if so it's fine to leave absolute since the path is still valid. */
+ BLI_path_rel(filepath, data->basedir_dst);
- return false;
+ BLI_strncpy(path_dst, filepath, FILE_MAX);
+ data->count_changed++;
+ return true;
}
-static bool rewrite_path_fixed_dirfile(char path_dir[FILE_MAXDIR],
- char path_file[FILE_MAXFILE],
- BPathVisitor visit_cb,
- const char *absbase,
- void *userdata)
+void BKE_bpath_relative_rebase(Main *bmain,
+ const char *basedir_src,
+ const char *basedir_dst,
+ ReportList *reports)
{
- char path_src[FILE_MAX];
- char path_dst[FILE_MAX];
-
- BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
+ BPathRebase_Data data = {NULL};
+ const int flag = (BKE_BPATH_FOREACH_PATH_SKIP_LINKED | BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE);
- /* so functions can check old value */
- BLI_strncpy(path_dst, path_src, FILE_MAX);
+ BLI_assert(basedir_src[0] != '\0');
+ BLI_assert(basedir_dst[0] != '\0');
- if (absbase) {
- BLI_path_abs(path_src, absbase);
- }
+ data.basedir_src = basedir_src;
+ data.basedir_dst = basedir_dst;
+ data.reports = reports;
- if (visit_cb(userdata, path_dst, (const char *)path_src)) {
- BLI_split_dirfile(path_dst, path_dir, path_file, FILE_MAXDIR, FILE_MAXFILE);
- return true;
- }
+ BKE_bpath_foreach_path_main(
+ &(BPathForeachPathData){.bmain = bmain,
+ .callback_function = relative_rebase_foreach_path_cb,
+ .flag = flag,
+ .user_data = &data});
- return false;
+ BKE_reportf(reports,
+ data.count_failed ? RPT_WARNING : RPT_INFO,
+ "Total files %d | Changed %d | Failed %d",
+ data.count_tot,
+ data.count_changed,
+ data.count_failed);
}
-static bool rewrite_path_alloc(char **path,
- BPathVisitor visit_cb,
- const char *absbase,
- void *userdata)
-{
- char path_src_buf[FILE_MAX];
- const char *path_src;
- char path_dst[FILE_MAX];
-
- if (absbase) {
- BLI_strncpy(path_src_buf, *path, sizeof(path_src_buf));
- BLI_path_abs(path_src_buf, absbase);
- path_src = path_src_buf;
- }
- else {
- path_src = *path;
- }
+/** \} */
- if (visit_cb(userdata, path_dst, path_src)) {
- MEM_freeN(*path);
- (*path) = BLI_strdup(path_dst);
- return true;
- }
+/* -------------------------------------------------------------------- */
+/** \name Make Paths Relative Or Absolute
+ * \{ */
- return false;
-}
+typedef struct BPathRemap_Data {
+ const char *basedir;
+ ReportList *reports;
-typedef struct Seq_callback_data {
- const char *absbase;
- void *bpath_user_data;
- BPathVisitor visit_cb;
- const int flag;
-} Seq_callback_data;
+ int count_tot;
+ int count_changed;
+ int count_failed;
+} BPathRemap_Data;
-static bool seq_rewrite_path_callback(Sequence *seq, void *user_data)
+static bool relative_convert_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- if (SEQ_HAS_PATH(seq)) {
- StripElem *se = seq->strip->stripdata;
- Seq_callback_data *cd = (Seq_callback_data *)user_data;
+ BPathRemap_Data *data = (BPathRemap_Data *)bpath_data->user_data;
- if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM) && se) {
- rewrite_path_fixed_dirfile(
- seq->strip->dir, se->name, cd->visit_cb, cd->absbase, cd->bpath_user_data);
- }
- else if ((seq->type == SEQ_TYPE_IMAGE) && se) {
- /* might want an option not to loop over all strips */
- unsigned int len = (unsigned int)MEM_allocN_len(se) / (unsigned int)sizeof(*se);
- unsigned int i;
-
- if (cd->flag & BKE_BPATH_TRAVERSE_SKIP_MULTIFILE) {
- /* only operate on one path */
- len = MIN2(1u, len);
- }
+ data->count_tot++;
- for (i = 0; i < len; i++, se++) {
- rewrite_path_fixed_dirfile(
- seq->strip->dir, se->name, cd->visit_cb, cd->absbase, cd->bpath_user_data);
- }
- }
- else {
- /* simple case */
- rewrite_path_fixed(seq->strip->dir, cd->visit_cb, cd->absbase, cd->bpath_user_data);
- }
+ if (BLI_path_is_rel(path_src)) {
+ return false; /* Already relative. */
+ }
+
+ BLI_strncpy(path_dst, path_src, FILE_MAX);
+ BLI_path_rel(path_dst, data->basedir);
+ if (BLI_path_is_rel(path_dst)) {
+ data->count_changed++;
+ }
+ else {
+ BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made relative", path_src);
+ data->count_failed++;
}
return true;
}
-/**
- * Run visitor function 'visit' on all paths contained in 'id'.
- */
-void BKE_bpath_traverse_id(
- Main *bmain, ID *id, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
+static bool absolute_convert_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL;
+ BPathRemap_Data *data = (BPathRemap_Data *)bpath_data->user_data;
- if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED(id)) {
- return;
- }
+ data->count_tot++;
- if (id->library_weak_reference != NULL) {
- rewrite_path_fixed(
- id->library_weak_reference->library_filepath, visit_cb, absbase, bpath_user_data);
+ if (!BLI_path_is_rel(path_src)) {
+ return false; /* Already absolute. */
}
- switch (GS(id->name)) {
- case ID_IM: {
- Image *ima;
- ima = (Image *)id;
- if (BKE_image_has_packedfile(ima) == false || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- /* Skip empty file paths, these are typically from generated images and
- * don't make sense to add directories to until the image has been saved
- * once to give it a meaningful value. */
- if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED) &&
- ima->filepath[0]) {
- if (rewrite_path_fixed(ima->filepath, visit_cb, absbase, bpath_user_data)) {
- if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) {
- if (!BKE_image_has_packedfile(ima) &&
- /* image may have been painted onto (and not saved, T44543) */
- !BKE_image_is_dirty(ima)) {
- BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_RELOAD);
- }
- }
- }
- }
- }
- break;
- }
- case ID_BR: {
- Brush *brush = (Brush *)id;
- if (brush->icon_filepath[0]) {
- rewrite_path_fixed(brush->icon_filepath, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_OB: {
- Object *ob = (Object *)id;
- ModifierData *md;
- ParticleSystem *psys;
-
-#define BPATH_TRAVERSE_POINTCACHE(ptcaches) \
- { \
- PointCache *cache; \
- for (cache = (ptcaches).first; cache; cache = cache->next) { \
- if (cache->flag & PTCACHE_DISK_CACHE) { \
- rewrite_path_fixed(cache->path, visit_cb, absbase, bpath_user_data); \
- } \
- } \
- } \
- (void)0
-
- for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Fluidsim) {
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
- if (fluidmd->fss) {
- rewrite_path_fixed(fluidmd->fss->surfdataPath, visit_cb, absbase, bpath_user_data);
- }
- }
- else if (md->type == eModifierType_Fluid) {
- FluidModifierData *fmd = (FluidModifierData *)md;
- if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
- rewrite_path_fixed(fmd->domain->cache_directory, visit_cb, absbase, bpath_user_data);
- }
- }
- else if (md->type == eModifierType_Cloth) {
- ClothModifierData *clmd = (ClothModifierData *)md;
- BPATH_TRAVERSE_POINTCACHE(clmd->ptcaches);
- }
- else if (md->type == eModifierType_Ocean) {
- OceanModifierData *omd = (OceanModifierData *)md;
- rewrite_path_fixed(omd->cachepath, visit_cb, absbase, bpath_user_data);
- }
- else if (md->type == eModifierType_MeshCache) {
- MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md;
- rewrite_path_fixed(mcmd->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
-
- if (ob->soft) {
- BPATH_TRAVERSE_POINTCACHE(ob->soft->shared->ptcaches);
- }
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- BPATH_TRAVERSE_POINTCACHE(psys->ptcaches);
- }
-
-#undef BPATH_TRAVERSE_POINTCACHE
-
- break;
- }
- case ID_SO: {
- bSound *sound = (bSound *)id;
- if (sound->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- rewrite_path_fixed(sound->filepath, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_VO: {
- Volume *volume = (Volume *)id;
- if (volume->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- rewrite_path_fixed(volume->filepath, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_TXT:
- if (((Text *)id)->filepath) {
- rewrite_path_alloc(&((Text *)id)->filepath, visit_cb, absbase, bpath_user_data);
- }
- break;
- case ID_VF: {
- VFont *vfont = (VFont *)id;
- if (vfont->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- if (BKE_vfont_is_builtin(vfont) == false) {
- rewrite_path_fixed(((VFont *)id)->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
- break;
- }
- case ID_MA: {
- Material *ma = (Material *)id;
- bNodeTree *ntree = ma->nodetree;
-
- if (ntree) {
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_SCRIPT) {
- NodeShaderScript *nss = (NodeShaderScript *)node->storage;
- rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data);
- }
- else if (node->type == SH_NODE_TEX_IES) {
- NodeShaderTexIES *ies = (NodeShaderTexIES *)node->storage;
- rewrite_path_fixed(ies->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
- }
- break;
- }
- case ID_NT: {
- bNodeTree *ntree = (bNodeTree *)id;
- bNode *node;
-
- if (ntree->type == NTREE_SHADER) {
- /* same as lines above */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_SCRIPT) {
- NodeShaderScript *nss = (NodeShaderScript *)node->storage;
- rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data);
- }
- else if (node->type == SH_NODE_TEX_IES) {
- NodeShaderTexIES *ies = (NodeShaderTexIES *)node->storage;
- rewrite_path_fixed(ies->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
- }
- break;
- }
- case ID_SCE: {
- Scene *scene = (Scene *)id;
- if (scene->ed) {
- Seq_callback_data user_data = {absbase, bpath_user_data, visit_cb, flag};
- SEQ_for_each_callback(&scene->ed->seqbase, seq_rewrite_path_callback, &user_data);
- }
- break;
- }
- case ID_ME: {
- Mesh *me = (Mesh *)id;
- if (me->ldata.external) {
- rewrite_path_fixed(me->ldata.external->filename, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_LI: {
- Library *lib = (Library *)id;
- /* keep packedfile paths always relative to the blend */
- if (lib->packedfile == NULL) {
- if (rewrite_path_fixed(lib->filepath, visit_cb, absbase, bpath_user_data)) {
- BKE_library_filepath_set(bmain, lib, lib->filepath);
- }
- }
- break;
- }
- case ID_MC: {
- MovieClip *clip = (MovieClip *)id;
- rewrite_path_fixed(clip->filepath, visit_cb, absbase, bpath_user_data);
- break;
- }
- case ID_CF: {
- CacheFile *cache_file = (CacheFile *)id;
- rewrite_path_fixed(cache_file->filepath, visit_cb, absbase, bpath_user_data);
- break;
- }
- default:
- /* Nothing to do for other IDs that don't contain file paths. */
- break;
+ BLI_strncpy(path_dst, path_src, FILENAME_MAX);
+ BLI_path_abs(path_dst, data->basedir);
+ if (BLI_path_is_rel(path_dst) == false) {
+ data->count_changed++;
+ }
+ else {
+ BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
+ data->count_failed++;
}
+ return true;
}
-void BKE_bpath_traverse_id_list(
- Main *bmain, ListBase *lb, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
+static void bpath_absolute_relative_convert(Main *bmain,
+ const char *basedir,
+ ReportList *reports,
+ BPathForeachPathFunctionCallback callback_function)
{
- ID *id;
- for (id = lb->first; id; id = id->next) {
- BKE_bpath_traverse_id(bmain, id, visit_cb, flag, bpath_user_data);
+ BPathRemap_Data data = {NULL};
+ const int flag = BKE_BPATH_FOREACH_PATH_SKIP_LINKED;
+
+ BLI_assert(basedir[0] != '\0');
+ if (basedir[0] == '\0') {
+ CLOG_ERROR(&LOG, "basedir='', this is a bug");
+ return;
}
+
+ data.basedir = basedir;
+ data.reports = reports;
+
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){
+ .bmain = bmain, .callback_function = callback_function, .flag = flag, .user_data = &data});
+
+ BKE_reportf(reports,
+ data.count_failed ? RPT_WARNING : RPT_INFO,
+ "Total files %d | Changed %d | Failed %d",
+ data.count_tot,
+ data.count_changed,
+ data.count_failed);
}
-void BKE_bpath_traverse_main(Main *bmain,
- BPathVisitor visit_cb,
- const int flag,
- void *bpath_user_data)
+void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *reports)
{
- ListBase *lbarray[INDEX_ID_MAX];
- int a = set_listbasepointers(bmain, lbarray);
- while (a--) {
- BKE_bpath_traverse_id_list(bmain, lbarray[a], visit_cb, flag, bpath_user_data);
- }
+ bpath_absolute_relative_convert(bmain, basedir, reports, relative_convert_foreach_path_cb);
}
-/**
- * Rewrites a relative path to be relative to the main file - unless the path is
- * absolute, in which case it is not altered.
- */
-bool BKE_bpath_relocate_visitor(void *pathbase_v, char *path_dst, const char *path_src)
+void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *reports)
{
- /* be sure there is low chance of the path being too short */
- char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
- const char *base_new = ((char **)pathbase_v)[0];
- const char *base_old = ((char **)pathbase_v)[1];
-
- if (BLI_path_is_rel(base_old)) {
- CLOG_ERROR(&LOG, "old base path '%s' is not absolute.", base_old);
- return false;
- }
-
- /* Make referenced file absolute. This would be a side-effect of
- * BLI_path_normalize, but we do it explicitly so we know if it changed. */
- BLI_strncpy(filepath, path_src, FILE_MAX);
- if (BLI_path_abs(filepath, base_old)) {
- /* Path was relative and is now absolute. Remap.
- * Important BLI_path_normalize runs before the path is made relative
- * because it won't work for paths that start with "//../" */
- BLI_path_normalize(base_new, filepath);
- BLI_path_rel(filepath, base_new);
- BLI_strncpy(path_dst, filepath, FILE_MAX);
- return true;
- }
-
- /* Path was not relative to begin with. */
- return false;
+ bpath_absolute_relative_convert(bmain, basedir, reports, absolute_convert_foreach_path_cb);
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Backup/Restore/Free functions,
+/** \name Backup/Restore/Free paths list functions.
*
- * \note These functions assume the data won't change order.
* \{ */
struct PathStore {
struct PathStore *next, *prev;
};
-static bool bpath_list_append(void *userdata, char *UNUSED(path_dst), const char *path_src)
+static bool bpath_list_append(BPathForeachPathData *bpath_data,
+ char *UNUSED(path_dst),
+ const char *path_src)
{
- /* store the path and string in a single alloc */
- ListBase *ls = userdata;
+ ListBase *path_list = bpath_data->user_data;
size_t path_size = strlen(path_src) + 1;
+
+ /* NOTE: the PathStore and its string are allocated together in a single alloc. */
struct PathStore *path_store = MEM_mallocN(sizeof(struct PathStore) + path_size, __func__);
char *filepath = (char *)(path_store + 1);
- memcpy(filepath, path_src, path_size);
- BLI_addtail(ls, path_store);
+ BLI_strncpy(filepath, path_src, path_size);
+ BLI_addtail(path_list, path_store);
return false;
}
-static bool bpath_list_restore(void *userdata, char *path_dst, const char *path_src)
+static bool bpath_list_restore(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- /* assume ls->first won't be NULL because the number of paths can't change!
- * (if they do caller is wrong) */
- ListBase *ls = userdata;
- struct PathStore *path_store = ls->first;
+ ListBase *path_list = bpath_data->user_data;
+
+ /* `ls->first` should never be NULL, because the number of paths should not change.
+ * If this happens, there is a bug in caller code. */
+ BLI_assert(!BLI_listbase_is_empty(path_list));
+
+ struct PathStore *path_store = path_list->first;
const char *filepath = (char *)(path_store + 1);
- bool ret;
+ bool is_path_changed = false;
- if (STREQ(path_src, filepath)) {
- ret = false;
- }
- else {
+ if (!STREQ(path_src, filepath)) {
BLI_strncpy(path_dst, filepath, FILE_MAX);
- ret = true;
+ is_path_changed = true;
}
- BLI_freelinkN(ls, path_store);
- return ret;
+ BLI_freelinkN(path_list, path_store);
+ return is_path_changed;
}
-/* return ls_handle */
-void *BKE_bpath_list_backup(Main *bmain, const int flag)
+void *BKE_bpath_list_backup(Main *bmain, const eBPathForeachFlag flag)
{
- ListBase *ls = MEM_callocN(sizeof(ListBase), __func__);
+ ListBase *path_list = MEM_callocN(sizeof(ListBase), __func__);
- BKE_bpath_traverse_main(bmain, bpath_list_append, flag, ls);
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){.bmain = bmain,
+ .callback_function = bpath_list_append,
+ .flag = flag,
+ .user_data = path_list});
- return ls;
+ return path_list;
}
-void BKE_bpath_list_restore(Main *bmain, const int flag, void *ls_handle)
+void BKE_bpath_list_restore(Main *bmain, const eBPathForeachFlag flag, void *path_list_handle)
{
- ListBase *ls = ls_handle;
+ ListBase *path_list = path_list_handle;
- BKE_bpath_traverse_main(bmain, bpath_list_restore, flag, ls);
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){.bmain = bmain,
+ .callback_function = bpath_list_restore,
+ .flag = flag,
+ .user_data = path_list});
}
-void BKE_bpath_list_free(void *ls_handle)
+void BKE_bpath_list_free(void *path_list_handle)
{
- ListBase *ls = ls_handle;
- BLI_assert(BLI_listbase_is_empty(ls)); /* assumes we were used */
- BLI_freelistN(ls);
- MEM_freeN(ls);
+ ListBase *path_list = path_list_handle;
+ /* The whole list should have been consumed by #BKE_bpath_list_restore, see also comment in
+ * #bpath_list_restore. */
+ BLI_assert(BLI_listbase_is_empty(path_list));
+
+ BLI_freelistN(path_list);
+ MEM_freeN(path_list);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/bpath_test.cc b/source/blender/blenkernel/intern/bpath_test.cc
new file mode 100644
index 00000000000..121d47af75f
--- /dev/null
+++ b/source/blender/blenkernel/intern/bpath_test.cc
@@ -0,0 +1,181 @@
+/*
+ * 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) 2021 by Blender Foundation.
+ */
+#include "testing/testing.h"
+
+#include "CLG_log.h"
+
+#include "BKE_bpath.h"
+#include "BKE_idtype.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_movieclip_types.h"
+#include "DNA_text_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+namespace blender::bke::tests {
+
+#ifdef WIN32
+# define ABSOLUTE_ROOT "C:" SEP_STR
+#else
+# define ABSOLUTE_ROOT SEP_STR
+#endif
+
+#define RELATIVE_ROOT "//"
+#define BASE_DIR ABSOLUTE_ROOT "blendfiles" SEP_STR
+#define REBASE_DIR BASE_DIR "rebase" SEP_STR
+
+#define BLENDFILE_NAME "bpath.blend"
+#define BLENDFILE_PATH BASE_DIR BLENDFILE_NAME
+
+#define TEXT_PATH_ITEM "texts" SEP_STR "text.txt"
+#define TEXT_PATH_ABSOLUTE ABSOLUTE_ROOT TEXT_PATH_ITEM
+#define TEXT_PATH_ABSOLUTE_MADE_RELATIVE RELATIVE_ROOT ".." SEP_STR TEXT_PATH_ITEM
+#define TEXT_PATH_RELATIVE RELATIVE_ROOT TEXT_PATH_ITEM
+#define TEXT_PATH_RELATIVE_MADE_ABSOLUTE BASE_DIR TEXT_PATH_ITEM
+
+#define MOVIECLIP_PATH_ITEM "movieclips" SEP_STR "movieclip.avi"
+#define MOVIECLIP_PATH_ABSOLUTE ABSOLUTE_ROOT MOVIECLIP_PATH_ITEM
+#define MOVIECLIP_PATH_ABSOLUTE_MADE_RELATIVE RELATIVE_ROOT ".." SEP_STR MOVIECLIP_PATH_ITEM
+#define MOVIECLIP_PATH_RELATIVE RELATIVE_ROOT MOVIECLIP_PATH_ITEM
+#define MOVIECLIP_PATH_RELATIVE_MADE_ABSOLUTE BASE_DIR MOVIECLIP_PATH_ITEM
+
+class BPathTest : public testing::Test {
+ public:
+ static void SetUpTestSuite()
+ {
+ CLG_init();
+ BKE_idtype_init();
+ }
+ static void TearDownTestSuite()
+ {
+ CLG_exit();
+ }
+
+ void SetUp() override
+ {
+ bmain = BKE_main_new();
+ STRNCPY(bmain->filepath, BLENDFILE_PATH);
+
+ BKE_id_new(bmain, ID_TXT, nullptr);
+ BKE_id_new(bmain, ID_MC, nullptr);
+ }
+
+ void TearDown() override
+ {
+ BKE_main_free(bmain);
+ }
+
+ Main *bmain;
+};
+
+TEST_F(BPathTest, rebase_on_relative)
+{
+ // Test on relative paths, should be modified.
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_RELATIVE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_RELATIVE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_relative_rebase(bmain, BASE_DIR, REBASE_DIR, nullptr);
+
+ EXPECT_STREQ(text->filepath, RELATIVE_ROOT ".." SEP_STR TEXT_PATH_ITEM);
+ EXPECT_STREQ(movie_clip->filepath, RELATIVE_ROOT ".." SEP_STR MOVIECLIP_PATH_ITEM);
+}
+
+TEST_F(BPathTest, rebase_on_absolute)
+{
+ // Test on absolute paths, should not be modified.
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_ABSOLUTE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_relative_rebase(bmain, BASE_DIR, REBASE_DIR, nullptr);
+
+ EXPECT_STREQ(text->filepath, TEXT_PATH_ABSOLUTE);
+ EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE);
+}
+
+TEST_F(BPathTest, convert_to_relative)
+{
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_RELATIVE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_relative_convert(bmain, BASE_DIR, nullptr);
+
+ // Already relative path should not be modified.
+ EXPECT_STREQ(text->filepath, TEXT_PATH_RELATIVE);
+ // Absolute path should be modified.
+ EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE_MADE_RELATIVE);
+}
+
+TEST_F(BPathTest, convert_to_absolute)
+{
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_RELATIVE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_absolute_convert(bmain, BASE_DIR, nullptr);
+
+ // Relative path should be modified.
+ EXPECT_STREQ(text->filepath, TEXT_PATH_RELATIVE_MADE_ABSOLUTE);
+ // Already absolute path should not be modified.
+ EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE);
+}
+
+TEST_F(BPathTest, list_backup_restore)
+{
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_RELATIVE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE, sizeof(movie_clip->filepath));
+
+ void *path_list_handle = BKE_bpath_list_backup(bmain, static_cast<eBPathForeachFlag>(0));
+
+ ListBase *path_list = reinterpret_cast<ListBase *>(path_list_handle);
+ EXPECT_EQ(BLI_listbase_count(path_list), 2);
+
+ MEM_freeN(text->filepath);
+ text->filepath = BLI_strdup(TEXT_PATH_ABSOLUTE);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_RELATIVE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_list_restore(bmain, static_cast<eBPathForeachFlag>(0), path_list_handle);
+
+ EXPECT_STREQ(text->filepath, TEXT_PATH_RELATIVE);
+ EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE);
+ EXPECT_EQ(BLI_listbase_count(path_list), 0);
+
+ BKE_bpath_list_free(path_list_handle);
+}
+
+} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index d70b941695e..c86d4658cc9 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -33,6 +33,7 @@
#include "BLT_translation.h"
+#include "BKE_bpath.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
@@ -148,16 +149,9 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
Brush *brush = (Brush *)id;
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
- bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
- bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
- BLI_assert(force_copy == false || force_copy != force_local);
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing (unless force_local is set)
- * - only local users: set flag
- * - mixed: make copy
- */
+ bool force_local, force_copy;
+ BKE_lib_id_make_local_generic_action_define(bmain, id, flags, &force_local, &force_copy);
if (brush->clone.image) {
/* Special case: ima always local immediately. Clone image should only have one user anyway. */
@@ -170,21 +164,9 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
BLI_assert(brush->clone.image->id.lib == NULL && brush->clone.image->id.newid == NULL);
}
- if (!force_local && !force_copy) {
- BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib);
- if (lib_local || is_local) {
- if (!is_lib) {
- force_local = true;
- }
- else {
- force_copy = true;
- }
- }
- }
-
if (force_local) {
- BKE_lib_id_clear_library_data(bmain, &brush->id);
- BKE_lib_id_expand_local(bmain, &brush->id);
+ BKE_lib_id_clear_library_data(bmain, &brush->id, flags);
+ BKE_lib_id_expand_local(bmain, &brush->id, flags);
/* enable fake user by default */
id_fake_user_set(&brush->id);
@@ -207,14 +189,23 @@ static void brush_foreach_id(ID *id, LibraryForeachIDData *data)
{
Brush *brush = (Brush *)id;
- BKE_LIB_FOREACHID_PROCESS(data, brush->toggle_brush, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, brush->clone.image, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, brush->paint_curve, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->toggle_brush, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->clone.image, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->paint_curve, IDWALK_CB_USER);
if (brush->gpencil_settings) {
- BKE_LIB_FOREACHID_PROCESS(data, brush->gpencil_settings->material, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->gpencil_settings->material, IDWALK_CB_USER);
+ }
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_texture_mtex_foreach_id(data, &brush->mtex));
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data,
+ BKE_texture_mtex_foreach_id(data, &brush->mask_mtex));
+}
+
+static void brush_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Brush *brush = (Brush *)id;
+ if (brush->icon_filepath[0] != '\0') {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, brush->icon_filepath);
}
- BKE_texture_mtex_foreach_id(data, &brush->mtex);
- BKE_texture_mtex_foreach_id(data, &brush->mask_mtex);
}
static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_address)
@@ -413,6 +404,7 @@ IDTypeInfo IDType_ID_BR = {
.name_plural = "brushes",
.translation_context = BLT_I18NCONTEXT_ID_BRUSH,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = brush_init_data,
.copy_data = brush_copy_data,
@@ -420,6 +412,7 @@ IDTypeInfo IDType_ID_BR = {
.make_local = brush_make_local,
.foreach_id = brush_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = brush_foreach_path,
.owner_get = NULL,
.blend_write = brush_blend_write,
@@ -502,10 +495,6 @@ static void brush_defaults(Brush *brush)
/* Datablock add/copy/free/make_local */
-/**
- * \note Resulting brush will have two users: one as a fake user,
- * another is assumed to be used by the caller.
- */
Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
{
Brush *brush;
@@ -517,7 +506,6 @@ Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
return brush;
}
-/* add grease pencil settings */
void BKE_brush_init_gpencil_settings(Brush *brush)
{
if (brush->gpencil_settings == NULL) {
@@ -545,7 +533,6 @@ void BKE_brush_init_gpencil_settings(Brush *brush)
brush->gpencil_settings->curve_rand_value = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
}
-/* add a new gp-brush */
Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name, eObjectMode mode)
{
Paint *paint = NULL;
@@ -585,7 +572,6 @@ Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name, eO
return brush;
}
-/* Delete a Brush. */
bool BKE_brush_delete(Main *bmain, Brush *brush)
{
if (brush->id.tag & LIB_TAG_INDIRECT) {
@@ -1319,7 +1305,6 @@ static Brush *gpencil_brush_ensure(
return brush;
}
-/* Create a set of grease pencil Drawing presets. */
void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
bool r_new = false;
@@ -1421,7 +1406,6 @@ void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, const bool r
}
}
-/* Create a set of grease pencil Vertex Paint presets. */
void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
bool r_new = false;
@@ -1468,7 +1452,6 @@ void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool
}
}
-/* Create a set of grease pencil Sculpt Paint presets. */
void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
bool r_new = false;
@@ -1543,7 +1526,6 @@ void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool
}
}
-/* Create a set of grease pencil Weight Paint presets. */
void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
bool r_new = false;
@@ -1945,9 +1927,6 @@ void BKE_brush_sculpt_reset(Brush *br)
}
}
-/**
- * Library Operations
- */
void BKE_brush_curve_preset(Brush *b, eCurveMappingPreset preset)
{
CurveMapping *cumap = NULL;
@@ -1965,10 +1944,6 @@ void BKE_brush_curve_preset(Brush *b, eCurveMappingPreset preset)
BKE_curvemapping_changed(cumap, false);
}
-/* Generic texture sampler for 3D painting systems. point has to be either in
- * region space mouse coordinates, or 3d world coordinates for 3D mapping.
- *
- * rgba outputs straight alpha. */
float BKE_brush_sample_tex_3d(const Scene *scene,
const Brush *br,
const float point[3],
@@ -2361,7 +2336,6 @@ void BKE_brush_weight_set(const Scene *scene, Brush *brush, float value)
}
}
-/* scale unprojected radius to reflect a change in the brush's 2D size */
void BKE_brush_scale_unprojected_radius(float *unprojected_radius,
int new_brush_size,
int old_brush_size)
@@ -2374,7 +2348,6 @@ void BKE_brush_scale_unprojected_radius(float *unprojected_radius,
(*unprojected_radius) *= scale;
}
-/* scale brush size to reflect a change in the brush's unprojected radius */
void BKE_brush_scale_size(int *r_brush_size,
float new_unprojected_radius,
float old_unprojected_radius)
@@ -2425,7 +2398,6 @@ void BKE_brush_randomize_texture_coords(UnifiedPaintSettings *ups, bool mask)
}
}
-/* Uses the brush curve control to find a strength value */
float BKE_brush_curve_strength(const Brush *br, float p, const float len)
{
float strength = 1.0f;
@@ -2473,8 +2445,7 @@ float BKE_brush_curve_strength(const Brush *br, float p, const float len)
return strength;
}
-/* Uses the brush curve control to find a strength value between 0 and 1 */
-float BKE_brush_curve_strength_clamped(Brush *br, float p, const float len)
+float BKE_brush_curve_strength_clamped(const Brush *br, float p, const float len)
{
float strength = BKE_brush_curve_strength(br, p, len);
@@ -2516,7 +2487,6 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec
return texcache;
}
-/**** Radial Control ****/
struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary, bool display_gradient)
{
ImBuf *im = MEM_callocN(sizeof(ImBuf), "radial control texture");
diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc
index 707201207d9..5e7a4eea0cd 100644
--- a/source/blender/blenkernel/intern/bvhutils.cc
+++ b/source/blender/blenkernel/intern/bvhutils.cc
@@ -125,9 +125,9 @@ bool bvhcache_has_tree(const BVHCache *bvh_cache, const BVHTree *tree)
return false;
}
-BVHCache *bvhcache_init(void)
+BVHCache *bvhcache_init()
{
- BVHCache *cache = (BVHCache *)MEM_callocN(sizeof(BVHCache), __func__);
+ BVHCache *cache = MEM_cnew<BVHCache>(__func__);
BLI_mutex_init(&cache->mutex);
return cache;
}
@@ -147,9 +147,6 @@ static void bvhcache_insert(BVHCache *bvh_cache, BVHTree *tree, BVHCacheType typ
item->is_filled = true;
}
-/**
- * frees a bvhcache
- */
void bvhcache_free(BVHCache *bvh_cache)
{
for (int index = 0; index < BVHTREE_MAX_ITEM; index++) {
@@ -161,9 +158,11 @@ void bvhcache_free(BVHCache *bvh_cache)
MEM_freeN(bvh_cache);
}
-/* BVH tree balancing inside a mutex lock must be run in isolation. Balancing
+/**
+ * BVH-tree balancing inside a mutex lock must be run in isolation. Balancing
* is multithreaded, and we do not want the current thread to start another task
- * that may involve acquiring the same mutex lock that it is waiting for. */
+ * that may involve acquiring the same mutex lock that it is waiting for.
+ */
static void bvhtree_balance_isolated(void *userdata)
{
BLI_bvhtree_balance((BVHTree *)userdata);
@@ -182,6 +181,7 @@ static void bvhtree_balance(BVHTree *tree, const bool isolate)
}
/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Local Callbacks
* \{ */
@@ -233,8 +233,12 @@ float bvhtree_sphereray_tri_intersection(const BVHTreeRay *ray,
* BVH from meshes callbacks
*/
-/* Callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_faces.
- * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
+/**
+ * Callback to BVH-tree nearest point.
+ * The tree must have been built using #bvhtree_from_mesh_faces.
+ *
+ * \param userdata: Must be a #BVHMeshCallbackUserdata built from the same mesh as the tree.
+ */
static void mesh_faces_nearest_point(void *userdata,
int index,
const float co[3],
@@ -325,8 +329,12 @@ static void editmesh_looptri_nearest_point(void *userdata,
}
}
-/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_faces.
- * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
+/**
+ * Callback to BVH-tree ray-cast.
+ * The tree must have been built using bvhtree_from_mesh_faces.
+ *
+ * \param userdata: Must be a #BVHMeshCallbackUserdata built from the same mesh as the tree.
+ */
static void mesh_faces_spherecast(void *userdata,
int index,
const BVHTreeRay *ray,
@@ -430,8 +438,12 @@ static void editmesh_looptri_spherecast(void *userdata,
}
}
-/* Callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_edges.
- * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
+/**
+ * Callback to BVH-tree nearest point.
+ * The tree must have been built using #bvhtree_from_mesh_edges.
+ *
+ * \param userdata: Must be a #BVHMeshCallbackUserdata built from the same mesh as the tree.
+ */
static void mesh_edges_nearest_point(void *userdata,
int index,
const float co[3],
@@ -491,8 +503,12 @@ static void editmesh_verts_spherecast(void *userdata,
mesh_verts_spherecast_do(index, eve->co, ray, hit);
}
-/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_verts.
- * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
+/**
+ * Callback to BVH-tree ray-cast.
+ * The tree must have been built using bvhtree_from_mesh_verts.
+ *
+ * \param userdata: Must be a #BVHMeshCallbackUserdata built from the same mesh as the tree.
+ */
static void mesh_verts_spherecast(void *userdata,
int index,
const BVHTreeRay *ray,
@@ -504,8 +520,12 @@ static void mesh_verts_spherecast(void *userdata,
mesh_verts_spherecast_do(index, v, ray, hit);
}
-/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_edges.
- * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
+/**
+ * Callback to BVH-tree ray-cast.
+ * The tree must have been built using bvhtree_from_mesh_edges.
+ *
+ * \param userdata: Must be a #BVHMeshCallbackUserdata built from the same mesh as the tree.
+ */
static void mesh_edges_spherecast(void *userdata,
int index,
const BVHTreeRay *ray,
@@ -647,7 +667,6 @@ static void bvhtree_from_mesh_verts_setup_data(BVHTreeFromMesh *data,
data->vert_allocated = vert_allocated;
}
-/* Builds a bvh tree where nodes are the vertices of the given em */
BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
BMEditMesh *em,
const BLI_bitmap *verts_mask,
@@ -703,13 +722,6 @@ BVHTree *bvhtree_from_editmesh_verts(
data, em, nullptr, -1, epsilon, tree_type, axis, BVHTREE_FROM_VERTS, nullptr, nullptr);
}
-/**
- * Builds a bvh tree where nodes are the given vertices (NOTE: does not copy given `vert`!).
- * \param vert_allocated: if true, vert freeing will be done when freeing data.
- * \param verts_mask: if not null, true elements give which vert to add to BVH tree.
- * \param verts_num_active: if >= 0, number of active verts to add to BVH tree
- * (else will be computed from mask).
- */
BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data,
const MVert *vert,
const int verts_num,
@@ -860,7 +872,6 @@ static void bvhtree_from_mesh_edges_setup_data(BVHTreeFromMesh *data,
data->edge_allocated = edge_allocated;
}
-/* Builds a bvh tree where nodes are the edges of the given em */
BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
BMEditMesh *em,
const BLI_bitmap *edges_mask,
@@ -915,14 +926,6 @@ BVHTree *bvhtree_from_editmesh_edges(
data, em, nullptr, -1, epsilon, tree_type, axis, BVHTREE_FROM_VERTS, nullptr, nullptr);
}
-/**
- * Builds a bvh tree where nodes are the given edges .
- * \param vert, vert_allocated: if true, elem freeing will be done when freeing data.
- * \param edge, edge_allocated: if true, elem freeing will be done when freeing data.
- * \param edges_mask: if not null, true elements give which vert to add to BVH tree.
- * \param edges_num_active: if >= 0, number of active edges to add to BVH tree
- * (else will be computed from mask).
- */
BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
const MVert *vert,
const bool vert_allocated,
@@ -1049,15 +1052,6 @@ static void bvhtree_from_mesh_faces_setup_data(BVHTreeFromMesh *data,
data->face_allocated = face_allocated;
}
-/**
- * Builds a bvh tree where nodes are the given tessellated faces
- * (NOTE: does not copy given mfaces!).
- * \param vert_allocated: if true, vert freeing will be done when freeing data.
- * \param face_allocated: if true, face freeing will be done when freeing data.
- * \param faces_mask: if not null, true elements give which faces to add to BVH tree.
- * \param faces_num_active: if >= 0, number of active faces to add to BVH tree
- * (else will be computed from mask).
- */
BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data,
const MVert *vert,
const bool vert_allocated,
@@ -1135,7 +1129,7 @@ static BVHTree *bvhtree_from_editmesh_looptri_create_tree(float epsilon,
if (tree) {
const BMLoop *(*looptris)[3] = (const BMLoop *(*)[3])em->looptris;
- /* Insert BMesh-tessellation triangles into the bvh tree, unless they are hidden
+ /* Insert BMesh-tessellation triangles into the BVH-tree, unless they are hidden
* and/or selected. Even if the faces themselves are not selected for the snapped
* transform, having a vertex selected means the face (and thus it's tessellated
* triangles) will be moving and will not be a good snap targets. */
@@ -1231,9 +1225,6 @@ static void bvhtree_from_mesh_looptri_setup_data(BVHTreeFromMesh *data,
data->looptri_allocated = looptri_allocated;
}
-/**
- * Builds a bvh tree where nodes are the looptri faces of the given bm
- */
BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
BMEditMesh *em,
const BLI_bitmap *looptri_mask,
@@ -1288,11 +1279,6 @@ BVHTree *bvhtree_from_editmesh_looptri(
data, em, nullptr, -1, epsilon, tree_type, axis, BVHTREE_FROM_VERTS, nullptr, nullptr);
}
-/**
- * Builds a BVH-tree where nodes are the looptri faces of the given mesh.
- *
- * \note for edit-mesh this is currently a duplicate of #bvhtree_from_mesh_faces_ex
- */
BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
const struct MVert *vert,
const bool vert_allocated,
@@ -1435,12 +1421,6 @@ static BLI_bitmap *looptri_no_hidden_map_get(const MPoly *mpoly,
return looptri_mask;
}
-/**
- * Builds or queries a bvhcache for the cache bvhtree of the request type.
- *
- * \note This function only fills a cache, and therefore the mesh argument can
- * be considered logically const. Concurrent access is protected by a mutex.
- */
BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
const struct Mesh *mesh,
const BVHCacheType bvh_cache_type,
@@ -1621,12 +1601,11 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
memset(data, 0, sizeof(*data));
}
+ data->vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
+
return tree;
}
-/**
- * Builds or queries a bvhcache for the cache bvhtree of the request type.
- */
BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const int tree_type,
@@ -1684,7 +1663,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
mesh_eval_mutex);
}
else {
- /* Setup BVHTreeFromMesh */
+ /* Setup #BVHTreeFromMesh */
data->nearest_callback = nullptr; /* TODO */
data->raycast_callback = nullptr; /* TODO */
}
@@ -1704,7 +1683,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
mesh_eval_mutex);
}
else {
- /* Setup BVHTreeFromMesh */
+ /* Setup #BVHTreeFromMesh */
data->nearest_callback = editmesh_looptri_nearest_point;
data->raycast_callback = editmesh_looptri_spherecast;
}
@@ -1741,7 +1720,10 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
/** \} */
-/* Frees data allocated by a call to bvhtree_from_editmesh_*. */
+/* -------------------------------------------------------------------- */
+/** \name Free Functions
+ * \{ */
+
void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
{
if (data->tree) {
@@ -1752,7 +1734,6 @@ void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
}
}
-/* Frees data allocated by a call to bvhtree_from_mesh_*. */
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
{
if (data->tree && !data->cached) {
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index e642bbc9e06..75df2e98fcd 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -40,6 +40,7 @@
#include "BLT_translation.h"
#include "BKE_anim_data.h"
+#include "BKE_bpath.h"
#include "BKE_cachefile.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -53,6 +54,8 @@
#include "BLO_read_write.h"
+#include "MEM_guardedalloc.h"
+
#ifdef WITH_ALEMBIC
# include "ABC_alembic.h"
#endif
@@ -85,6 +88,7 @@ static void cache_file_copy_data(Main *UNUSED(bmain),
cache_file_dst->handle = NULL;
cache_file_dst->handle_readers = NULL;
BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_src->object_paths);
+ BLI_duplicatelist(&cache_file_dst->layers, &cache_file_src->layers);
}
static void cache_file_free_data(ID *id)
@@ -92,6 +96,13 @@ static void cache_file_free_data(ID *id)
CacheFile *cache_file = (CacheFile *)id;
cachefile_handle_free(cache_file);
BLI_freelistN(&cache_file->object_paths);
+ BLI_freelistN(&cache_file->layers);
+}
+
+static void cache_file_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ CacheFile *cache_file = (CacheFile *)id;
+ BKE_bpath_foreach_path_fixed_process(bpath_data, cache_file->filepath);
}
static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_address)
@@ -110,6 +121,11 @@ static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_a
if (cache_file->adt) {
BKE_animdata_blend_write(writer, cache_file->adt);
}
+
+ /* write layers */
+ LISTBASE_FOREACH (CacheFileLayer *, layer, &cache_file->layers) {
+ BLO_write_struct(writer, CacheFileLayer, layer);
+ }
}
static void cache_file_blend_read_data(BlendDataReader *reader, ID *id)
@@ -123,6 +139,9 @@ static void cache_file_blend_read_data(BlendDataReader *reader, ID *id)
/* relink animdata */
BLO_read_data_address(reader, &cache_file->adt);
BKE_animdata_blend_read_data(reader, cache_file->adt);
+
+ /* relink layers */
+ BLO_read_list(reader, &cache_file->layers);
}
IDTypeInfo IDType_ID_CF = {
@@ -134,6 +153,7 @@ IDTypeInfo IDType_ID_CF = {
.name_plural = "cache_files",
.translation_context = BLT_I18NCONTEXT_ID_CACHEFILE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = cache_file_init_data,
.copy_data = cache_file_copy_data,
@@ -141,6 +161,7 @@ IDTypeInfo IDType_ID_CF = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = cache_file_foreach_path,
.owner_get = NULL,
.blend_write = cache_file_blend_write,
@@ -355,7 +376,8 @@ void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file
#ifdef WITH_ALEMBIC
if (BLI_path_extension_check_glob(filepath, "*abc")) {
cache_file->type = CACHEFILE_TYPE_ALEMBIC;
- cache_file->handle = ABC_create_handle(bmain, filepath, &cache_file->object_paths);
+ cache_file->handle = ABC_create_handle(
+ bmain, filepath, cache_file->layers.first, &cache_file->object_paths);
BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX);
}
#endif
@@ -411,12 +433,6 @@ float BKE_cachefile_time_offset(const CacheFile *cache_file, const float time, c
return cache_file->is_sequence ? frame : frame / fps - time_offset;
}
-/**
- * Determine whether the #CacheFile should use a render engine procedural. If so, data is not read
- * from the file and bounding boxes are used to represent the objects in the Scene.
- * Render engines will receive the bounding box as a placeholder but can instead
- * load the data directly if they support it.
- */
bool BKE_cache_file_uses_render_procedural(const CacheFile *cache_file,
Scene *scene,
const int dag_eval_mode)
@@ -432,3 +448,35 @@ bool BKE_cache_file_uses_render_procedural(const CacheFile *cache_file,
const bool is_final_render = (eEvaluationMode)dag_eval_mode == DAG_EVAL_RENDER;
return cache_file->use_render_procedural && !is_final_render;
}
+
+CacheFileLayer *BKE_cachefile_add_layer(CacheFile *cache_file, const char filename[1024])
+{
+ for (CacheFileLayer *layer = cache_file->layers.first; layer; layer = layer->next) {
+ if (STREQ(layer->filepath, filename)) {
+ return NULL;
+ }
+ }
+
+ const int num_layers = BLI_listbase_count(&cache_file->layers);
+
+ CacheFileLayer *layer = MEM_callocN(sizeof(CacheFileLayer), "CacheFileLayer");
+ BLI_strncpy(layer->filepath, filename, sizeof(layer->filepath));
+
+ BLI_addtail(&cache_file->layers, layer);
+
+ cache_file->active_layer = (char)(num_layers + 1);
+
+ return layer;
+}
+
+CacheFileLayer *BKE_cachefile_get_active_layer(CacheFile *cache_file)
+{
+ return BLI_findlink(&cache_file->layers, cache_file->active_layer - 1);
+}
+
+void BKE_cachefile_remove_layer(CacheFile *cache_file, CacheFileLayer *layer)
+{
+ cache_file->active_layer = 0;
+ BLI_remlink(&cache_file->layers, layer);
+ MEM_freeN(layer);
+}
diff --git a/source/blender/blenkernel/intern/callbacks.c b/source/blender/blenkernel/intern/callbacks.c
index 87d5961b12e..992eb896d2d 100644
--- a/source/blender/blenkernel/intern/callbacks.c
+++ b/source/blender/blenkernel/intern/callbacks.c
@@ -30,15 +30,23 @@
static ListBase callback_slots[BKE_CB_EVT_TOT] = {{NULL}};
+static bool callbacks_initialized = false;
+
+#define ASSERT_CALLBACKS_INITIALIZED() \
+ BLI_assert_msg(callbacks_initialized, \
+ "Callbacks should be initialized with BKE_callback_global_init() before using " \
+ "the callback system.")
+
void BKE_callback_exec(struct Main *bmain,
struct PointerRNA **pointers,
const int num_pointers,
eCbEvent evt)
{
- ListBase *lb = &callback_slots[evt];
- bCallbackFuncStore *funcstore;
+ ASSERT_CALLBACKS_INITIALIZED();
- for (funcstore = lb->first; funcstore; funcstore = funcstore->next) {
+ /* Use mutable iteration so handlers are able to remove themselves. */
+ ListBase *lb = &callback_slots[evt];
+ LISTBASE_FOREACH_MUTABLE (bCallbackFuncStore *, funcstore, lb) {
funcstore->func(bmain, pointers, num_pointers, funcstore->arg);
}
}
@@ -76,14 +84,27 @@ void BKE_callback_exec_id_depsgraph(struct Main *bmain,
void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt)
{
+ ASSERT_CALLBACKS_INITIALIZED();
ListBase *lb = &callback_slots[evt];
BLI_addtail(lb, funcstore);
}
void BKE_callback_remove(bCallbackFuncStore *funcstore, eCbEvent evt)
{
+ /* The callback may have already been removed by BKE_callback_global_finalize(), for
+ * example when removing callbacks in response to a BKE_blender_atexit_register callback
+ * function. `BKE_blender_atexit()` runs after `BKE_callback_global_finalize()`. */
+ if (!callbacks_initialized) {
+ return;
+ }
+
ListBase *lb = &callback_slots[evt];
+
+ /* Be noisy about potential programming errors. */
+ BLI_assert_msg(BLI_findindex(lb, funcstore) != -1, "To-be-removed callback not found");
+
BLI_remlink(lb, funcstore);
+
if (funcstore->alloc) {
MEM_freeN(funcstore);
}
@@ -91,10 +112,9 @@ void BKE_callback_remove(bCallbackFuncStore *funcstore, eCbEvent evt)
void BKE_callback_global_init(void)
{
- /* do nothing */
+ callbacks_initialized = true;
}
-/* call on application exit */
void BKE_callback_global_finalize(void)
{
eCbEvent evt;
@@ -107,4 +127,6 @@ void BKE_callback_global_finalize(void)
BKE_callback_remove(funcstore, evt);
}
}
+
+ callbacks_initialized = false;
}
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index f922f497d20..7940936b64a 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -103,13 +103,13 @@ static void camera_foreach_id(ID *id, LibraryForeachIDData *data)
{
Camera *camera = (Camera *)id;
- BKE_LIB_FOREACHID_PROCESS(data, camera->dof.focus_object, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, camera->dof.focus_object, IDWALK_CB_NOP);
LISTBASE_FOREACH (CameraBGImage *, bgpic, &camera->bg_images) {
if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
- BKE_LIB_FOREACHID_PROCESS(data, bgpic->ima, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, bgpic->ima, IDWALK_CB_USER);
}
else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
- BKE_LIB_FOREACHID_PROCESS(data, bgpic->clip, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, bgpic->clip, IDWALK_CB_USER);
}
}
}
@@ -140,7 +140,6 @@ static void camera_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_list(reader, &ca->bg_images);
LISTBASE_FOREACH (CameraBGImage *, bgpic, &ca->bg_images) {
- bgpic->iuser.ok = 1;
bgpic->iuser.scene = NULL;
}
}
@@ -183,6 +182,7 @@ IDTypeInfo IDType_ID_CA = {
.name_plural = "cameras",
.translation_context = BLT_I18NCONTEXT_ID_CAMERA,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = camera_init_data,
.copy_data = camera_copy_data,
@@ -190,6 +190,7 @@ IDTypeInfo IDType_ID_CA = {
.make_local = NULL,
.foreach_id = camera_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = camera_blend_write,
@@ -217,10 +218,9 @@ void *BKE_camera_add(Main *bmain, const char *name)
return cam;
}
-/* get the camera's dof value, takes the dof object into account */
-float BKE_camera_object_dof_distance(const Object *ob)
+float BKE_camera_object_dof_distance(Object *ob)
{
- const Camera *cam = (const Camera *)ob->data;
+ Camera *cam = (Camera *)ob->data;
if (ob->type != OB_CAMERA) {
return 0.0f;
}
@@ -426,7 +426,6 @@ void BKE_camera_params_compute_viewplane(
params->viewplane = viewplane;
}
-/* viewplane is assumed to be already computed */
void BKE_camera_params_compute_matrix(CameraParams *params)
{
rctf viewplane = params->viewplane;
@@ -757,8 +756,6 @@ static bool camera_frame_fit_calc_from_data(CameraParams *params,
return false;
}
-/* don't move the camera, just yield the fit location */
-/* r_scale only valid/useful for ortho cameras */
bool BKE_camera_view_frame_fit_to_scene(
Depsgraph *depsgraph, const Scene *scene, Object *camera_ob, float r_co[3], float *r_scale)
{
@@ -909,7 +906,6 @@ static void camera_stereo3d_model_matrix(const Object *camera,
}
}
-/* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */
void BKE_camera_multiview_view_matrix(const RenderData *rd,
const Object *camera,
const bool is_left,
@@ -1032,7 +1028,6 @@ static Object *camera_multiview_advanced(const Scene *scene, Object *camera, con
return camera;
}
-/* returns the camera to be used for render */
Object *BKE_camera_multiview_render(const Scene *scene, Object *camera, const char *viewname)
{
const bool is_multiview = (camera != NULL) && (scene->r.scemode & R_MULTIVIEW) != 0;
@@ -1128,7 +1123,6 @@ CameraBGImage *BKE_camera_background_image_new(Camera *cam)
bgpic->scale = 1.0f;
bgpic->alpha = 0.5f;
- bgpic->iuser.ok = 1;
bgpic->iuser.flag |= IMA_ANIM_ALWAYS;
bgpic->flag |= CAM_BGIMG_FLAG_EXPANDED;
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 039a971fe2c..a4f3e84a2bf 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -56,6 +56,7 @@ typedef struct {
/* these point to data in the DerivedMesh custom data layers,
* they are only here for efficiency and convenience */
MVert *mvert;
+ const float (*vert_normals)[3];
MEdge *medge;
MFace *mface;
MLoop *mloop;
@@ -103,24 +104,6 @@ static int cdDM_getNumPolys(DerivedMesh *dm)
return dm->numPolyData;
}
-static void cdDM_getVert(DerivedMesh *dm, int index, MVert *r_vert)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- *r_vert = cddm->mvert[index];
-}
-
-static void cdDM_getEdge(DerivedMesh *dm, int index, MEdge *r_edge)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- *r_edge = cddm->medge[index];
-}
-
-static void cdDM_getTessFace(DerivedMesh *dm, int index, MFace *r_face)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- *r_face = cddm->mface[index];
-}
-
static void cdDM_copyVertArray(DerivedMesh *dm, MVert *r_vert)
{
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
@@ -161,7 +144,7 @@ static void cdDM_getVertCo(DerivedMesh *dm, int index, float r_co[3])
static void cdDM_getVertNo(DerivedMesh *dm, int index, float r_no[3])
{
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- normal_short_to_float_v3(r_no, cddm->mvert[index].no);
+ copy_v3_v3(r_no, cddm->vert_normals[index]);
}
static const MeshElemMap *cdDM_getPolyMap(Object *ob, DerivedMesh *dm)
@@ -231,10 +214,6 @@ static CDDerivedMesh *cdDM_create(const char *desc)
dm->getNumLoops = cdDM_getNumLoops;
dm->getNumPolys = cdDM_getNumPolys;
- dm->getVert = cdDM_getVert;
- dm->getEdge = cdDM_getEdge;
- dm->getTessFace = cdDM_getTessFace;
-
dm->copyVertArray = cdDM_copyVertArray;
dm->copyEdgeArray = cdDM_copyEdgeArray;
dm->copyTessFaceArray = cdDM_copyTessFaceArray;
@@ -303,6 +282,7 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh,
CustomData_merge(&mesh->pdata, &dm->polyData, cddata_masks.pmask, alloctype, mesh->totpoly);
cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
+ cddm->vert_normals = CustomData_get_layer(&dm->vertData, CD_NORMAL);
cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 080a7c90c46..43b8690e219 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -326,6 +326,7 @@ static int do_step_cloth(
/************************************************
* clothModifier_do - main simulation function
************************************************/
+
void clothModifier_do(ClothModifierData *clmd,
Depsgraph *depsgraph,
Scene *scene,
@@ -433,7 +434,6 @@ void clothModifier_do(ClothModifierData *clmd,
clmd->clothObject->last_frame = framenr;
}
-/* frees all */
void cloth_free_modifier(ClothModifierData *clmd)
{
Cloth *cloth = NULL;
@@ -504,7 +504,6 @@ void cloth_free_modifier(ClothModifierData *clmd)
}
}
-/* frees all */
void cloth_free_modifier_extern(ClothModifierData *clmd)
{
Cloth *cloth = NULL;
@@ -1401,8 +1400,7 @@ static bool find_internal_spring_target_vertex(BVHTreeFromMesh *treedata,
float radius;
copy_v3_v3(co, treedata->vert[v_idx].co);
- normal_short_to_float_v3(no, treedata->vert[v_idx].no);
- negate_v3(no);
+ negate_v3_v3(no, treedata->vert_normals[v_idx]);
float vec_len = sin(max_diversion);
float offset[3];
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 2d172f23428..e6ce4eb9440 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -158,10 +158,11 @@ static void collection_foreach_id(ID *id, LibraryForeachIDData *data)
Collection *collection = (Collection *)id;
LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
- BKE_LIB_FOREACHID_PROCESS(data, cob->ob, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, cob->ob, IDWALK_CB_USER);
}
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
- BKE_LIB_FOREACHID_PROCESS(data, child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
+ data, child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER);
}
LISTBASE_FOREACH (CollectionParent *, parent, &collection->parents) {
/* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad
@@ -170,7 +171,7 @@ static void collection_foreach_id(ID *id, LibraryForeachIDData *data)
(parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
IDWALK_CB_EMBEDDED :
IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag);
}
}
@@ -185,7 +186,7 @@ static ID *collection_owner_get(Main *bmain, ID *id)
Collection *master_collection = (Collection *)id;
BLI_assert((master_collection->flag & COLLECTION_IS_MASTER) != 0);
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
if (scene->master_collection == master_collection) {
return &scene->id;
}
@@ -374,6 +375,7 @@ IDTypeInfo IDType_ID_GR = {
.name_plural = "collections",
.translation_context = BLT_I18NCONTEXT_ID_COLLECTION,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = collection_init_data,
.copy_data = collection_copy_data,
@@ -381,6 +383,7 @@ IDTypeInfo IDType_ID_GR = {
.make_local = NULL,
.foreach_id = collection_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = collection_owner_get,
.blend_write = collection_blend_write,
@@ -428,10 +431,6 @@ static Collection *collection_add(Main *bmain,
return collection;
}
-/**
- * Add a collection to a collection ListBase and synchronize all render layers
- * The ListBase is NULL when the collection is to be added to the master collection
- */
Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
{
Collection *collection = collection_add(bmain, collection_parent, name_custom);
@@ -439,12 +438,6 @@ Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const
return collection;
}
-/**
- * Add \a collection_dst to all scene collections that reference object \a ob_src is in.
- * Used to replace an instance object with a collection (library override operator).
- *
- * Logic is very similar to #BKE_collection_object_add_from().
- */
void BKE_collection_add_from_object(Main *bmain,
Scene *scene,
const Object *ob_src,
@@ -467,12 +460,6 @@ void BKE_collection_add_from_object(Main *bmain,
BKE_main_collection_sync(bmain);
}
-/**
- * Add \a collection_dst to all scene collections that reference collection \a collection_src is
- * in.
- *
- * Logic is very similar to #BKE_collection_object_add_from().
- */
void BKE_collection_add_from_collection(Main *bmain,
Scene *scene,
Collection *collection_src,
@@ -506,17 +493,12 @@ void BKE_collection_add_from_collection(Main *bmain,
/** \name Free and Delete Collection
* \{ */
-/** Free (or release) any data used by this collection (does not free the collection itself). */
void BKE_collection_free_data(Collection *collection)
{
BKE_libblock_free_data(&collection->id, false);
collection_free_data(&collection->id);
}
-/**
- * Remove a collection, optionally removing its child objects or moving
- * them to parent collections.
- */
bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
{
/* Master collection is not real datablock, can't be removed. */
@@ -597,7 +579,7 @@ static Collection *collection_duplicate_recursive(Main *bmain,
}
else if (collection_old->id.newid == NULL) {
collection_new = (Collection *)BKE_id_copy_for_duplicate(
- bmain, (ID *)collection_old, duplicate_flags);
+ bmain, (ID *)collection_old, duplicate_flags, LIB_ID_COPY_DEFAULT);
if (collection_new == collection_old) {
return collection_new;
@@ -677,14 +659,6 @@ static Collection *collection_duplicate_recursive(Main *bmain,
return collection_new;
}
-/**
- * Make a deep copy (aka duplicate) of the given collection and all of its children, recursively.
- *
- * \warning This functions will clear all \a bmain #ID.idnew pointers, unless \a
- * #LIB_ID_DUPLICATE_IS_SUBPROCESS duplicate option is passed on, in which case caller is
- * responsible to reconstruct collection dependencies information's
- * (i.e. call #BKE_main_collection_sync).
- */
Collection *BKE_collection_duplicate(Main *bmain,
Collection *parent,
Collection *collection,
@@ -715,7 +689,7 @@ Collection *BKE_collection_duplicate(Main *bmain,
collection_new->id.tag &= ~LIB_TAG_NEW;
/* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */
- BKE_libblock_relink_to_newid(&collection_new->id);
+ BKE_libblock_relink_to_newid(bmain, &collection_new->id, 0);
#ifndef NDEBUG
/* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */
@@ -743,9 +717,6 @@ Collection *BKE_collection_duplicate(Main *bmain,
/** \name Collection Naming
* \{ */
-/**
- * The automatic/fallback name of a new collection.
- */
void BKE_collection_new_name_get(Collection *collection_parent, char *rname)
{
char *name;
@@ -768,9 +739,6 @@ void BKE_collection_new_name_get(Collection *collection_parent, char *rname)
MEM_freeN(name);
}
-/**
- * The name to show in the interface.
- */
const char *BKE_collection_ui_name_get(struct Collection *collection)
{
if (collection->flag & COLLECTION_IS_MASTER) {
@@ -1126,9 +1094,6 @@ static bool collection_object_remove(Main *bmain,
return true;
}
-/**
- * Add object to collection
- */
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
{
if (ELEM(NULL, collection, ob)) {
@@ -1157,12 +1122,6 @@ bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
return true;
}
-/**
- * Add \a ob_dst to all scene collections that reference object \a ob_src is in.
- * Used for copying objects.
- *
- * Logic is very similar to #BKE_collection_add_from_object()
- */
void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
{
bool is_instantiated = false;
@@ -1185,9 +1144,6 @@ void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, O
BKE_main_collection_sync(bmain);
}
-/**
- * Remove object from collection.
- */
bool BKE_collection_object_remove(Main *bmain,
Collection *collection,
Object *ob,
@@ -1235,9 +1191,6 @@ static bool scene_collections_object_remove(
return removed;
}
-/**
- * Remove object from all collections of scene
- */
bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us)
{
return scene_collections_object_remove(bmain, scene, ob, free_us, NULL);
@@ -1252,9 +1205,7 @@ static void collection_object_remove_nulls(Collection *collection)
{
bool changed = false;
- for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) {
- cob_next = cob->next;
-
+ LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) {
if (cob->ob == NULL) {
BLI_freelinkN(&collection->gobject, cob);
changed = true;
@@ -1268,22 +1219,61 @@ static void collection_object_remove_nulls(Collection *collection)
void BKE_collections_object_remove_nulls(Main *bmain)
{
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
collection_object_remove_nulls(scene->master_collection);
}
- for (Collection *collection = bmain->collections.first; collection;
- collection = collection->id.next) {
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
collection_object_remove_nulls(collection);
}
}
-static void collection_null_children_remove(Collection *collection)
+/*
+ * Remove all duplicate objects from collections.
+ * This is used for library remapping, happens when remapping an object to another one already
+ * present in the collection. Otherwise this should never happen.
+ */
+static void collection_object_remove_duplicates(Collection *collection)
+{
+ bool changed = false;
+
+ LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) {
+ if (cob->ob->runtime.collection_management) {
+ BLI_freelinkN(&collection->gobject, cob);
+ changed = true;
+ continue;
+ }
+ cob->ob->runtime.collection_management = true;
+ }
+
+ /* Cleanup. */
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
+ cob->ob->runtime.collection_management = false;
+ }
+
+ if (changed) {
+ BKE_collection_object_cache_free(collection);
+ }
+}
+
+void BKE_collections_object_remove_duplicates(struct Main *bmain)
{
- for (CollectionChild *child = collection->children.first, *child_next = NULL; child;
- child = child_next) {
- child_next = child->next;
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ ob->runtime.collection_management = false;
+ }
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ collection_object_remove_duplicates(scene->master_collection);
+ }
+
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ collection_object_remove_duplicates(collection);
+ }
+}
+static void collection_null_children_remove(Collection *collection)
+{
+ LISTBASE_FOREACH_MUTABLE (CollectionChild *, child, &collection->children) {
if (child->collection == NULL) {
BLI_freelinkN(&collection->children, child);
}
@@ -1292,27 +1282,13 @@ static void collection_null_children_remove(Collection *collection)
static void collection_missing_parents_remove(Collection *collection)
{
- for (CollectionParent *parent = collection->parents.first, *parent_next; parent != NULL;
- parent = parent_next) {
- parent_next = parent->next;
+ LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &collection->parents) {
if ((parent->collection == NULL) || !collection_find_child(parent->collection, collection)) {
BLI_freelinkN(&collection->parents, parent);
}
}
}
-/**
- * Remove all NULL children from parent collections of changed \a collection.
- * This is used for library remapping, where these pointers have been set to NULL.
- * Otherwise this should never happen.
- *
- * \note caller must ensure #BKE_main_collection_sync_remap() is called afterwards!
- *
- * \param parent_collection: The collection owning the pointers that were remapped. May be \a NULL,
- * in which case whole \a bmain database of collections is checked.
- * \param child_collection: The collection that was remapped to another pointer. May be \a NULL,
- * in which case whole \a bmain database of collections is checked.
- */
void BKE_collections_child_remove_nulls(Main *bmain,
Collection *parent_collection,
Collection *child_collection)
@@ -1326,28 +1302,23 @@ void BKE_collections_child_remove_nulls(Main *bmain,
* otherwise we can miss some cases...
* Also, master collections are not in bmain, so we also need to loop over scenes.
*/
- for (child_collection = bmain->collections.first; child_collection != NULL;
- child_collection = child_collection->id.next) {
- collection_null_children_remove(child_collection);
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ collection_null_children_remove(collection);
}
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
collection_null_children_remove(scene->master_collection);
}
}
- for (child_collection = bmain->collections.first; child_collection != NULL;
- child_collection = child_collection->id.next) {
- collection_missing_parents_remove(child_collection);
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ collection_missing_parents_remove(collection);
}
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
collection_missing_parents_remove(scene->master_collection);
}
}
else {
- for (CollectionParent *parent = child_collection->parents.first, *parent_next; parent;
- parent = parent_next) {
- parent_next = parent->next;
-
+ LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &child_collection->parents) {
collection_null_children_remove(parent->collection);
if (!collection_find_child(parent->collection, child_collection)) {
@@ -1357,11 +1328,6 @@ void BKE_collections_child_remove_nulls(Main *bmain,
}
}
-/**
- * Move object from a collection into another
- *
- * If source collection is NULL move it from all the existing collections.
- */
void BKE_collection_object_move(
Main *bmain, Scene *scene, Collection *collection_dst, Collection *collection_src, Object *ob)
{
@@ -1436,15 +1402,6 @@ static bool collection_instance_find_recursive(Collection *collection,
return false;
}
-/**
- * Find potential cycles in collections.
- *
- * \param new_ancestor: the potential new owner of given \a collection,
- * or the collection to check if the later is NULL.
- * \param collection: the collection we want to add to \a new_ancestor,
- * may be NULL if we just want to ensure \a new_ancestor does not already have cycles.
- * \return true if a cycle is found.
- */
bool BKE_collection_cycle_find(Collection *new_ancestor, Collection *collection)
{
if (collection == new_ancestor) {
@@ -1508,12 +1465,6 @@ static bool collection_cycle_fix_recursive(Main *bmain,
return cycles_found;
}
-/**
- * Find and fix potential cycles in collections.
- *
- * \param collection: The collection to check for existing cycles.
- * \return true if cycles are found and fixed.
- */
bool BKE_collection_cycles_fix(Main *bmain, Collection *collection)
{
return collection_cycle_fix_recursive(bmain, collection, collection) ||
@@ -1626,11 +1577,6 @@ bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *ch
return true;
}
-/**
- * Rebuild parent relationships from child ones, for all children of given \a collection.
- *
- * \note Given collection is assumed to already have valid parents.
- */
void BKE_collection_parent_relations_rebuild(Collection *collection)
{
LISTBASE_FOREACH_MUTABLE (CollectionChild *, child, &collection->children) {
@@ -1670,23 +1616,19 @@ static void collection_parents_rebuild_recursive(Collection *collection)
BKE_collection_parent_relations_rebuild(collection);
collection->tag &= ~COLLECTION_TAG_RELATION_REBUILD;
- for (CollectionChild *child = collection->children.first; child != NULL; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
/* See comment above in `BKE_collection_parent_relations_rebuild`. */
- if ((collection->id.tag & (LIB_TAG_NO_MAIN | LIB_TAG_COPIED_ON_WRITE)) != 0) {
+ if ((child->collection->id.tag & (LIB_TAG_NO_MAIN | LIB_TAG_COPIED_ON_WRITE)) != 0) {
continue;
}
collection_parents_rebuild_recursive(child->collection);
}
}
-/**
- * Rebuild parent relationships from child ones, for all collections in given \a bmain.
- */
void BKE_main_collections_parent_relations_rebuild(Main *bmain)
{
/* Only collections not in bmain (master ones in scenes) have no parent... */
- for (Collection *collection = bmain->collections.first; collection != NULL;
- collection = collection->id.next) {
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
BLI_freelistN(&collection->parents);
collection->tag |= COLLECTION_TAG_RELATION_REBUILD;
@@ -1694,7 +1636,7 @@ void BKE_main_collections_parent_relations_rebuild(Main *bmain)
/* Scene's master collections will be 'root' parent of most of our collections, so start with
* them. */
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
/* This function can be called from readfile.c, when this pointer is not guaranteed to be NULL.
*/
if (scene->master_collection != NULL) {
@@ -1706,8 +1648,7 @@ void BKE_main_collections_parent_relations_rebuild(Main *bmain)
/* We may have parent chains outside of scene's master_collection context? At least, readfile's
* lib_link_collection_data() seems to assume that, so do the same here. */
- for (Collection *collection = bmain->collections.first; collection != NULL;
- collection = collection->id.next) {
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
if (collection->tag & COLLECTION_TAG_RELATION_REBUILD) {
/* NOTE: we do not have easy access to 'which collections is root' info in that case, which
* means test for cycles in collection relationships may fail here. I don't think that is an
@@ -1742,11 +1683,6 @@ static Collection *collection_from_index_recursive(Collection *collection,
return NULL;
}
-/**
- * Return Scene Collection for a given index.
- *
- * The index is calculated from top to bottom counting the children before the siblings.
- */
Collection *BKE_collection_from_index(Scene *scene, const int index)
{
int index_current = 0;
@@ -1790,10 +1726,6 @@ static bool collection_objects_select(ViewLayer *view_layer, Collection *collect
return changed;
}
-/**
- * Select all the objects in this Collection (and its nested collections) for this ViewLayer.
- * Return true if any object was selected.
- */
bool BKE_collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect)
{
LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(view_layer,
@@ -1919,10 +1851,6 @@ static void scene_collections_array(Scene *scene,
scene_collection_callback(collection, scene_collections_build_array, &array);
}
-/**
- * Only use this in non-performance critical situations
- * (it iterates over all scene collections twice)
- */
void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in)
{
Scene *scene = data_in;
@@ -2064,13 +1992,6 @@ void BKE_scene_objects_iterator_end(BLI_Iterator *iter)
}
}
-/**
- * Generate a new GSet (or extend given `objects_gset` if not NULL) with all objects referenced by
- * all collections of given `scene`.
- *
- * \note This will include objects without a base currently
- * (because they would belong to excluded collections only e.g.).
- */
GSet *BKE_scene_objects_as_gset(Scene *scene, GSet *objects_gset)
{
BLI_Iterator iter;
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 1c24dae430c..671c6530685 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -78,7 +78,6 @@ typedef struct SelfColDetectData {
* Collision modifier code start
***********************************/
-/* step is limited from 0 (frame start position) to 1 (frame end position) */
void collision_move_object(CollisionModifierData *collmd,
const float step,
const float prevstep,
@@ -577,7 +576,7 @@ static float compute_collision_point_edge_tri(const float a1[3],
return dist;
}
-// w3 is not perfect
+/* `w3` is not perfect. */
static void collision_compute_barycentric(const float pv[3],
const float p1[3],
const float p2[3],
@@ -1261,9 +1260,6 @@ static void add_collision_object(ListBase *relations,
}
}
-/* Create list of collision relations in the collection or entire scene.
- * This is used by the depsgraph to build relations, as well as faster
- * lookup of colliders during evaluation. */
ListBase *BKE_collision_relations_create(Depsgraph *depsgraph,
Collection *collection,
unsigned int modifier_type)
@@ -1292,8 +1288,6 @@ void BKE_collision_relations_free(ListBase *relations)
}
}
-/* Create effective list of colliders from relations built beforehand.
- * Self will be excluded. */
Object **BKE_collision_objects_create(Depsgraph *depsgraph,
Object *self,
Collection *collection,
@@ -1341,8 +1335,6 @@ void BKE_collision_objects_free(Object **objects)
}
}
-/* Create effective list of colliders from relations built beforehand.
- * Self will be excluded. */
ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collection *collection)
{
ListBase *relations = DEG_get_collision_relations(
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index f2c2e552a9f..b12b19453ae 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -183,7 +183,6 @@ void BKE_curvemapping_set_black_white(CurveMapping *cumap,
/* ***************** operations on single curve ************* */
/* ********** NOTE: requires BKE_curvemapping_changed() call after ******** */
-/* remove specified point */
bool BKE_curvemap_remove_point(CurveMap *cuma, CurveMapPoint *point)
{
CurveMapPoint *cmp;
@@ -213,7 +212,6 @@ bool BKE_curvemap_remove_point(CurveMap *cuma, CurveMapPoint *point)
return (removed != 0);
}
-/* removes with flag set */
void BKE_curvemap_remove(CurveMap *cuma, const short flag)
{
CurveMapPoint *cmp = MEM_mallocN((cuma->totpoint) * sizeof(CurveMapPoint), "curve points");
@@ -439,9 +437,6 @@ void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope
}
}
-/**
- * \param type: eBezTriple_Handle
- */
void BKE_curvemap_handle_set(CurveMap *cuma, int type)
{
int a;
@@ -800,10 +795,10 @@ static void curvemap_make_table(const CurveMapping *cumap, CurveMap *cuma)
cuma->table = cmp;
}
-/* call when you do images etc, needs restore too. also verifies tables */
-/* it uses a flag to prevent premul or free to happen twice */
-void BKE_curvemapping_premultiply(CurveMapping *cumap, int restore)
+void BKE_curvemapping_premultiply(CurveMapping *cumap, bool restore)
{
+ /* It uses a flag to prevent pre-multiply or free to happen twice. */
+
int a;
if (restore) {
@@ -873,7 +868,6 @@ static int sort_curvepoints(const void *a1, const void *a2)
/* ************************ more CurveMapping calls *************** */
-/* NOTE: only does current curvemap! */
void BKE_curvemapping_changed(CurveMapping *cumap, const bool rem_doubles)
{
CurveMap *cuma = cumap->cm + cumap->cur;
@@ -965,13 +959,11 @@ void BKE_curvemapping_changed_all(CurveMapping *cumap)
cumap->cur = cur;
}
-/* Reset the view for current curve. */
void BKE_curvemapping_reset_view(CurveMapping *cumap)
{
cumap->curr = cumap->clipr;
}
-/* table should be verified */
float BKE_curvemap_evaluateF(const CurveMapping *cumap, const CurveMap *cuma, float value)
{
/* index in table */
@@ -994,7 +986,6 @@ float BKE_curvemap_evaluateF(const CurveMapping *cumap, const CurveMap *cuma, fl
return (1.0f - fi) * cuma->table[i].y + (fi)*cuma->table[i + 1].y;
}
-/* works with curve 'cur' */
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
{
const CurveMap *cuma = cumap->cm + cur;
@@ -1013,7 +1004,6 @@ float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value
return val;
}
-/* vector case */
void BKE_curvemapping_evaluate3F(const CurveMapping *cumap, float vecout[3], const float vecin[3])
{
vecout[0] = BKE_curvemap_evaluateF(cumap, &cumap->cm[0], vecin[0]);
@@ -1021,7 +1011,6 @@ void BKE_curvemapping_evaluate3F(const CurveMapping *cumap, float vecout[3], con
vecout[2] = BKE_curvemap_evaluateF(cumap, &cumap->cm[2], vecin[2]);
}
-/* RGB case, no black/white points, no premult */
void BKE_curvemapping_evaluateRGBF(const CurveMapping *cumap,
float vecout[3],
const float vecin[3])
@@ -1052,16 +1041,6 @@ static void curvemapping_evaluateRGBF_filmlike(const CurveMapping *cumap,
vecout[channel_offset[2]] = v2;
}
-/**
- * Same as #BKE_curvemapping_evaluate_premulRGBF
- * but black/bwmul are passed as args for the compositor
- * where they can change per pixel.
- *
- * Use in conjunction with #BKE_curvemapping_set_black_white_ex
- *
- * \param black: Use instead of cumap->black
- * \param bwmul: Use instead of cumap->bwmul
- */
void BKE_curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap,
float vecout[3],
const float vecin[3],
@@ -1127,7 +1106,6 @@ void BKE_curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap,
}
}
-/* RGB with black/white points and premult. tables are checked */
void BKE_curvemapping_evaluate_premulRGBF(const CurveMapping *cumap,
float vecout[3],
const float vecin[3])
@@ -1135,7 +1113,6 @@ void BKE_curvemapping_evaluate_premulRGBF(const CurveMapping *cumap,
BKE_curvemapping_evaluate_premulRGBF_ex(cumap, vecout, vecin, cumap->black, cumap->bwmul);
}
-/* same as above, byte version */
void BKE_curvemapping_evaluate_premulRGB(const CurveMapping *cumap,
unsigned char vecout_byte[3],
const unsigned char vecin_byte[3])
@@ -1212,6 +1189,20 @@ void BKE_curvemapping_init(CurveMapping *cumap)
}
}
+void BKE_curvemapping_table_F(const CurveMapping *cumap, float **array, int *size)
+{
+ int a;
+
+ *size = CM_TABLE + 1;
+ *array = MEM_callocN(sizeof(float) * (*size) * 4, "CurveMapping");
+
+ for (a = 0; a < *size; a++) {
+ if (cumap->cm[0].table) {
+ (*array)[a * 4 + 0] = cumap->cm[0].table[a].y;
+ }
+ }
+}
+
void BKE_curvemapping_table_RGBA(const CurveMapping *cumap, float **array, int *size)
{
int a;
@@ -1248,7 +1239,6 @@ void BKE_curvemapping_curves_blend_write(BlendWriter *writer, const CurveMapping
}
}
-/* cumap itself has been read already. */
void BKE_curvemapping_blend_read(BlendDataReader *reader, CurveMapping *cumap)
{
/* flag seems to be able to hang? Maybe old files... not bad to clear anyway */
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index b2b03d28483..f013ef99dde 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -34,6 +34,7 @@
#include "BLI_blenlib.h"
#include "BLI_kdopbvh.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
@@ -71,6 +72,7 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_movieclip.h"
#include "BKE_object.h"
@@ -123,7 +125,6 @@ static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bCon
/* -------------- Naming -------------- */
-/* Find the first available, non-duplicate name for a given constraint */
void BKE_constraint_unique_name(bConstraint *con, ListBase *list)
{
BLI_uniquename(list, con, DATA_("Const"), '.', offsetof(bConstraint, name), sizeof(con->name));
@@ -132,8 +133,6 @@ void BKE_constraint_unique_name(bConstraint *con, ListBase *list)
/* ----------------- Evaluation Loop Preparation --------------- */
/* package an object/bone for use in constraint evaluation */
-/* This function MEM_calloc's a bConstraintOb struct,
- * that will need to be freed after evaluation */
bConstraintOb *BKE_constraints_make_evalob(
Depsgraph *depsgraph, Scene *scene, Object *ob, void *subdata, short datatype)
{
@@ -211,7 +210,6 @@ bConstraintOb *BKE_constraints_make_evalob(
return cob;
}
-/* cleanup after constraint evaluation */
void BKE_constraints_clear_evalob(bConstraintOb *cob)
{
float delta[4][4], imat[4][4];
@@ -261,10 +259,6 @@ void BKE_constraints_clear_evalob(bConstraintOb *cob)
/* -------------- Space-Conversion API -------------- */
-/* This function is responsible for the correct transformations/conversions
- * of a matrix from one space to another for constraint evaluation.
- * For now, this is only implemented for Objects and PoseChannels.
- */
void BKE_constraint_mat_convertspace(Object *ob,
bPoseChannel *pchan,
bConstraintOb *cob,
@@ -551,6 +545,7 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[
float vec[3] = {0.0f, 0.0f, 0.0f};
float normal[3] = {0.0f, 0.0f, 0.0f};
float weightsum = 0.0f;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me_eval);
if (me_eval) {
const MDeformVert *dvert = CustomData_get_layer(&me_eval->vdata, CD_MDEFORMVERT);
int numVerts = me_eval->totvert;
@@ -565,10 +560,8 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[
const MDeformWeight *dw = BKE_defvert_find_index(dv, defgroup);
if (dw && dw->weight > 0.0f) {
- float nor[3];
- normal_short_to_float_v3(nor, mv->no);
madd_v3_v3fl(vec, mv->co, dw->weight);
- madd_v3_v3fl(normal, nor, dw->weight);
+ madd_v3_v3fl(normal, vert_normals[i], dw->weight);
weightsum += dw->weight;
}
}
@@ -2010,7 +2003,7 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
/* We must get compatible eulers from the beginning because
* some of them can be modified below (see bug T21875).
* Additionally, since this constraint is based on euler rotation math, it doesn't work well
- * with shear. The Y axis is chosen as the main axis when we orthoganalize the matrix because
+ * with shear. The Y axis is chosen as the main axis when we orthogonalize the matrix because
* constraints are used most commonly on bones. */
float mat[4][4];
copy_m4_m4(mat, ct->matrix);
@@ -3763,7 +3756,7 @@ static void minmax_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targ
copy_m4_m4(tarmat, ct->matrix);
if (data->flag & MINMAX_USEROT) {
- /* take rotation of target into account by doing the transaction in target's localspace */
+ /* Take rotation of target into account by doing the transaction in target's local-space. */
invert_m4_m4(imat, tarmat);
mul_m4_m4m4(tmat, imat, obmat);
copy_m4_m4(obmat, tmat);
@@ -3808,7 +3801,7 @@ static void minmax_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targ
if (val1 > val2) {
obmat[3][index] = tarmat[3][index] + data->offset;
if (data->flag & MINMAX_USEROT) {
- /* get out of localspace */
+ /* Get out of local-space. */
mul_m4_m4m4(tmat, ct->matrix, obmat);
copy_m4_m4(cob->matrix, tmat);
}
@@ -5556,9 +5549,6 @@ static void constraints_init_typeinfo(void)
constraintsTypeInfo[30] = &CTI_ARMATURE; /* Armature Constraint */
}
-/* This function should be used for getting the appropriate type-info when only
- * a constraint type is known
- */
const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type)
{
/* initialize the type-info list? */
@@ -5578,9 +5568,6 @@ const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type)
return NULL;
}
-/* This function should always be used to get the appropriate type-info, as it
- * has checks which prevent segfaults in some weird cases.
- */
const bConstraintTypeInfo *BKE_constraint_typeinfo_get(bConstraint *con)
{
/* only return typeinfo for valid constraints */
@@ -5611,11 +5598,6 @@ static void con_unlink_refs_cb(bConstraint *UNUSED(con),
}
}
-/**
- * Free data of a specific constraint if it has any info.
- * be sure to run #BIK_clear_data() when freeing an IK constraint,
- * unless DAG_relations_tag_update is called.
- */
void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user)
{
if (con->data) {
@@ -5643,7 +5625,6 @@ void BKE_constraint_free_data(bConstraint *con)
BKE_constraint_free_data_ex(con, true);
}
-/* Free all constraints from a constraint-stack */
void BKE_constraints_free_ex(ListBase *list, bool do_id_user)
{
/* Free constraint data and also any extra data */
@@ -5660,7 +5641,6 @@ void BKE_constraints_free(ListBase *list)
BKE_constraints_free_ex(list, true);
}
-/* Remove the specified constraint from the given constraint stack */
bool BKE_constraint_remove(ListBase *list, bConstraint *con)
{
if (con) {
@@ -5686,7 +5666,6 @@ bool BKE_constraint_remove_ex(ListBase *list, Object *ob, bConstraint *con, bool
return false;
}
-/* Apply the specified constraint in the given constraint stack */
bool BKE_constraint_apply_for_object(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -5698,13 +5677,19 @@ bool BKE_constraint_apply_for_object(Depsgraph *depsgraph,
const float ctime = BKE_scene_frame_get(scene);
- bConstraint *new_con = BKE_constraint_duplicate_ex(con, 0, !ID_IS_LINKED(ob));
+ /* Do this all in the evaluated domain (e.g. shrinkwrap needs to access evaluated constraint
+ * target mesh). */
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ bConstraint *con_eval = BKE_constraints_find_name(&ob_eval->constraints, con->name);
+
+ bConstraint *new_con = BKE_constraint_duplicate_ex(con_eval, 0, !ID_IS_LINKED(ob));
ListBase single_con = {new_con, new_con};
bConstraintOb *cob = BKE_constraints_make_evalob(
- depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ depsgraph, scene_eval, ob_eval, NULL, CONSTRAINT_OBTYPE_OBJECT);
/* Undo the effect of the current constraint stack evaluation. */
- mul_m4_m4m4(cob->matrix, ob->constinv, cob->matrix);
+ mul_m4_m4m4(cob->matrix, ob_eval->constinv, cob->matrix);
/* Evaluate single constraint. */
BKE_constraints_solve(depsgraph, &single_con, cob, ctime);
@@ -5717,7 +5702,7 @@ bool BKE_constraint_apply_for_object(Depsgraph *depsgraph,
BLI_freelinkN(&single_con, new_con);
/* Apply transform from matrix. */
- BKE_object_apply_mat4(ob, ob->obmat, true, true);
+ BKE_object_apply_mat4(ob, ob_eval->obmat, true, true);
return true;
}
@@ -5744,18 +5729,25 @@ bool BKE_constraint_apply_for_pose(
const float ctime = BKE_scene_frame_get(scene);
- bConstraint *new_con = BKE_constraint_duplicate_ex(con, 0, !ID_IS_LINKED(ob));
+ /* Do this all in the evaluated domain (e.g. shrinkwrap needs to access evaluated constraint
+ * target mesh). */
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
+ bConstraint *con_eval = BKE_constraints_find_name(&pchan_eval->constraints, con->name);
+
+ bConstraint *new_con = BKE_constraint_duplicate_ex(con_eval, 0, !ID_IS_LINKED(ob));
ListBase single_con;
single_con.first = new_con;
single_con.last = new_con;
float vec[3];
- copy_v3_v3(vec, pchan->pose_mat[3]);
+ copy_v3_v3(vec, pchan_eval->pose_mat[3]);
bConstraintOb *cob = BKE_constraints_make_evalob(
- depsgraph, scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
+ depsgraph, scene_eval, ob_eval, pchan_eval, CONSTRAINT_OBTYPE_BONE);
/* Undo the effects of currently applied constraints. */
- mul_m4_m4m4(cob->matrix, pchan->constinv, cob->matrix);
+ mul_m4_m4m4(cob->matrix, pchan_eval->constinv, cob->matrix);
/* Evaluate single constraint. */
BKE_constraints_solve(depsgraph, &single_con, cob, ctime);
BKE_constraints_clear_evalob(cob);
@@ -5766,12 +5758,12 @@ bool BKE_constraint_apply_for_pose(
/* Prevent constraints breaking a chain. */
if (pchan->bone->flag & BONE_CONNECTED) {
- copy_v3_v3(pchan->pose_mat[3], vec);
+ copy_v3_v3(pchan_eval->pose_mat[3], vec);
}
/* Apply transform from matrix. */
float mat[4][4];
- BKE_armature_mat_pose_to_bone(pchan, pchan->pose_mat, mat);
+ BKE_armature_mat_pose_to_bone(pchan, pchan_eval->pose_mat, mat);
BKE_pchan_apply_mat4(pchan, mat, true);
return true;
@@ -5920,7 +5912,6 @@ bool BKE_constraint_target_uses_bbone(struct bConstraint *con,
/* ......... */
-/* Add new constraint for the given bone */
bConstraint *BKE_constraint_add_for_pose(Object *ob,
bPoseChannel *pchan,
const char *name,
@@ -5933,7 +5924,6 @@ bConstraint *BKE_constraint_add_for_pose(Object *ob,
return add_new_constraint(ob, pchan, name, type);
}
-/* Add new constraint for the given object */
bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short type)
{
return add_new_constraint(ob, NULL, name, type);
@@ -5941,7 +5931,6 @@ bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short t
/* ......... */
-/* Run the given callback on all ID-blocks in list of constraints */
void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *userdata)
{
LISTBASE_FOREACH (bConstraint *, con, conlist) {
@@ -6016,17 +6005,14 @@ static void constraint_copy_data_ex(bConstraint *dst,
}
}
-/** Allocate and duplicate a single constraint, outside of any object/pose context. */
bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const bool do_extern)
{
bConstraint *dst = MEM_dupallocN(src);
constraint_copy_data_ex(dst, src, flag, do_extern);
dst->next = dst->prev = NULL;
- dst->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL;
return dst;
}
-/* Add a copy of the given constraint for the given bone */
bConstraint *BKE_constraint_copy_for_pose(Object *ob, bPoseChannel *pchan, bConstraint *src)
{
if (pchan == NULL) {
@@ -6038,7 +6024,6 @@ bConstraint *BKE_constraint_copy_for_pose(Object *ob, bPoseChannel *pchan, bCons
return new_con;
}
-/* Add a copy of the given constraint for the given object */
bConstraint *BKE_constraint_copy_for_object(Object *ob, bConstraint *src)
{
bConstraint *new_con = BKE_constraint_duplicate_ex(src, 0, !ID_IS_LINKED(ob));
@@ -6046,7 +6031,6 @@ bConstraint *BKE_constraint_copy_for_object(Object *ob, bConstraint *src)
return new_con;
}
-/* duplicate all of the constraints in a constraint stack */
void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern)
{
bConstraint *con, *srccon;
@@ -6057,7 +6041,9 @@ void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag,
for (con = dst->first, srccon = src->first; con && srccon;
srccon = srccon->next, con = con->next) {
constraint_copy_data_ex(con, srccon, flag, do_extern);
- con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL;
+ if ((flag & LIB_ID_COPY_NO_LIB_OVERRIDE_LOCAL_DATA_FLAG) == 0) {
+ con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL;
+ }
}
}
@@ -6073,7 +6059,6 @@ bConstraint *BKE_constraints_find_name(ListBase *list, const char *name)
return BLI_findstring(list, name, offsetof(bConstraint, name));
}
-/* finds the 'active' constraint in a constraint stack */
bConstraint *BKE_constraints_active_get(ListBase *list)
{
@@ -6090,7 +6075,6 @@ bConstraint *BKE_constraints_active_get(ListBase *list)
return NULL;
}
-/* Set the given constraint as the active one (clearing all the others) */
void BKE_constraints_active_set(ListBase *list, bConstraint *con)
{
@@ -6126,7 +6110,6 @@ static bConstraint *constraint_list_find_from_target(ListBase *constraints, bCon
return NULL;
}
-/* Finds the constraint that owns the given target within the object. */
bConstraint *BKE_constraint_find_from_target(Object *ob,
bConstraintTarget *tgt,
bPoseChannel **r_pchan)
@@ -6224,12 +6207,6 @@ static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bCon
return orig_con;
}
-/**
- * Check whether given constraint is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param con: May be NULL, in which case we consider it as a non-local constraint case.
- */
bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstraint *con)
{
return (ID_IS_OVERRIDE_LIBRARY(ob) &&
@@ -6238,8 +6215,6 @@ bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstrai
/* -------- Constraints and Proxies ------- */
-/* Rescue all constraints tagged as being CONSTRAINT_PROXY_LOCAL
- * (i.e. added to bone that's proxy-synced in this file) */
void BKE_constraints_proxylocal_extract(ListBase *dst, ListBase *src)
{
bConstraint *con, *next;
@@ -6256,7 +6231,6 @@ void BKE_constraints_proxylocal_extract(ListBase *dst, ListBase *src)
}
}
-/* Returns if the owner of the constraint is proxy-protected */
bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
{
/* Currently, constraints can only be on object or bone level */
@@ -6280,13 +6254,6 @@ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
/* -------- Target-Matrix Stuff ------- */
-/* This function is a relic from the prior implementations of the constraints system, when all
- * constraints either had one or no targets. It used to be called during the main constraint
- * solving loop, but is now only used for the remaining cases for a few constraints.
- *
- * None of the actual calculations of the matrices should be done here! Also, this function is
- * not to be used by any new constraints, particularly any that have multiple targets.
- */
void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
Scene *scene,
bConstraint *con,
@@ -6363,7 +6330,6 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
}
}
-/* Get the list of targets required for solving a constraint */
void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph,
bConstraint *con,
bConstraintOb *cob,
@@ -6433,12 +6399,6 @@ void BKE_constraint_custom_object_space_get(float r_mat[4][4], bConstraint *con)
/* ---------- Evaluation ----------- */
-/* This function is called whenever constraints need to be evaluated. Currently, all
- * constraints that can be evaluated are every time this gets run.
- *
- * BKE_constraints_make_evalob and BKE_constraints_clear_evalob should be called before and
- * after running this function, to sort out cob
- */
void BKE_constraints_solve(struct Depsgraph *depsgraph,
ListBase *conlist,
bConstraintOb *cob,
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index c235a1bbb6a..ceaed5d2bba 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -547,12 +547,6 @@ static void data_dir_add(ListBase *lb, const char *member, const bool use_all)
BLI_addtail(lb, link);
}
-/**
- * \param C: Context
- * \param use_store: Use 'C->wm.store'
- * \param use_rna: Use Include the properties from 'RNA_Context'
- * \param use_all: Don't skip values (currently only "scene")
- */
ListBase CTX_data_dir_get_ex(const bContext *C,
const bool use_store,
const bool use_rna,
@@ -1127,13 +1121,6 @@ RenderEngineType *CTX_data_engine_type(const bContext *C)
return RE_engines_find(scene->r.engine);
}
-/**
- * This is tricky. Sometimes the user overrides the render_layer
- * but not the scene_collection. In this case what to do?
- *
- * If the scene_collection is linked to the ViewLayer we use it.
- * Otherwise we fallback to the active one of the ViewLayer.
- */
LayerCollection *CTX_data_layer_collection(const bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 26894495777..573595b6f90 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -41,6 +41,7 @@
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
+#include "BKE_report.h"
#include "DEG_depsgraph_query.h"
@@ -98,7 +99,6 @@ static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob)
return disabled;
}
-/* disable subsurf temporal, get mapped cos, and enable it */
float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object *obedit))[3]
{
Scene *scene = DEG_get_input_scene(depsgraph);
@@ -110,7 +110,7 @@ float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object
/* disable subsurf temporal, get mapped cos, and enable it */
if (modifiers_disable_subsurf_temporary(scene_eval, obedit_eval)) {
/* need to make new derivemesh */
- makeDerivedMesh(depsgraph, scene_eval, obedit_eval, editmesh_eval, &CD_MASK_BAREMESH);
+ makeDerivedMesh(depsgraph, scene_eval, obedit_eval, &CD_MASK_BAREMESH);
}
/* now get the cage */
@@ -243,10 +243,6 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me,
}
}
-/**
- * Returns an array of deform matrices for crazy-space correction,
- * and the number of modifiers left.
- */
int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -521,3 +517,85 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
}
}
}
+
+/* -------------------------------------------------------------------- */
+/** \name Crazyspace API
+ * \{ */
+
+void BKE_crazyspace_api_eval(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *object,
+ struct ReportList *reports)
+{
+ if (object->runtime.crazyspace_deform_imats != NULL ||
+ object->runtime.crazyspace_deform_cos != NULL) {
+ return;
+ }
+
+ if (object->type != OB_MESH) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "Crazyspace transformation is only available for Mesh type of objects");
+ return;
+ }
+
+ const Mesh *mesh = (const Mesh *)object->data;
+ object->runtime.crazyspace_num_verts = mesh->totvert;
+ BKE_crazyspace_build_sculpt(depsgraph,
+ scene,
+ object,
+ &object->runtime.crazyspace_deform_imats,
+ &object->runtime.crazyspace_deform_cos);
+}
+
+void BKE_crazyspace_api_displacement_to_deformed(struct Object *object,
+ struct ReportList *reports,
+ int vertex_index,
+ float displacement[3],
+ float r_displacement_deformed[3])
+{
+ if (vertex_index < 0 || vertex_index >= object->runtime.crazyspace_num_verts) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Invalid vertex index %d (expected to be within 0 to %d range)",
+ vertex_index,
+ object->runtime.crazyspace_num_verts);
+ return;
+ }
+
+ mul_v3_m3v3(r_displacement_deformed,
+ object->runtime.crazyspace_deform_imats[vertex_index],
+ displacement);
+}
+
+void BKE_crazyspace_api_displacement_to_original(struct Object *object,
+ struct ReportList *reports,
+ int vertex_index,
+ float displacement_deformed[3],
+ float r_displacement[3])
+{
+ if (vertex_index < 0 || vertex_index >= object->runtime.crazyspace_num_verts) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Invalid vertex index %d (expected to be within 0 to %d range))",
+ vertex_index,
+ object->runtime.crazyspace_num_verts);
+ return;
+ }
+
+ float mat[3][3];
+ if (!invert_m3_m3(mat, object->runtime.crazyspace_deform_imats[vertex_index])) {
+ copy_v3_v3(r_displacement, displacement_deformed);
+ return;
+ }
+
+ mul_v3_m3v3(r_displacement, mat, displacement_deformed);
+}
+
+void BKE_crazyspace_api_eval_clear(Object *object)
+{
+ MEM_SAFE_FREE(object->runtime.crazyspace_deform_imats);
+ MEM_SAFE_FREE(object->runtime.crazyspace_deform_cos);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc
index 1ff0ca92306..7481d4df351 100644
--- a/source/blender/blenkernel/intern/cryptomatte.cc
+++ b/source/blender/blenkernel/intern/cryptomatte.cc
@@ -139,7 +139,7 @@ std::optional<std::string> CryptomatteSession::operator[](float encoded_hash) co
return std::nullopt;
}
-CryptomatteSession *BKE_cryptomatte_init(void)
+CryptomatteSession *BKE_cryptomatte_init()
{
CryptomatteSession *session = new CryptomatteSession();
return session;
@@ -212,7 +212,6 @@ float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
return blender::bke::cryptomatte::CryptomatteHash(cryptomatte_hash).float_encoded();
}
-/* Find an ID in the given main that matches the given encoded float. */
bool BKE_cryptomatte_find_name(const CryptomatteSession *session,
const float encoded_hash,
char *r_name,
@@ -279,13 +278,13 @@ void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const ch
token = token.substr(first, (last - first + 1));
if (*token.begin() == '<' && *(--token.end()) == '>') {
float encoded_hash = atof(token.substr(1, token.length() - 2).c_str());
- entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__);
+ entry = MEM_cnew<CryptomatteEntry>(__func__);
entry->encoded_hash = encoded_hash;
}
else {
const char *name = token.c_str();
int name_len = token.length();
- entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__);
+ entry = MEM_cnew<CryptomatteEntry>(__func__);
STRNCPY(entry->name, name);
uint32_t hash = BKE_cryptomatte_hash(name, name_len);
entry->encoded_hash = BKE_cryptomatte_hash_to_float(hash);
@@ -489,10 +488,6 @@ std::string BKE_cryptomatte_meta_data_key(const StringRef layer_name, const Stri
return "cryptomatte/" + cryptomatte_layer_name_hash(layer_name) + "/" + key_name;
}
-/* Extracts the cryptomatte name from a render pass name.
- *
- * Example: A render pass could be named `CryptoObject00`. This
- * function would remove the trailing digits and return `CryptoObject`. */
StringRef BKE_cryptomatte_extract_layer_name(const StringRef render_pass_name)
{
int64_t last_token = render_pass_name.size();
@@ -525,16 +520,6 @@ std::string CryptomatteHash::hex_encoded() const
return encoded.str();
}
-/* Convert a cryptomatte hash to a float.
- *
- * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the
- * cryptomatte specification. See Floating point conversion section in
- * https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf.
- *
- * The conversion uses as many 32 bit floating point values as possible to minimize hash
- * collisions. Unfortunately not all 32 bits can be used as NaN and Inf can be problematic.
- *
- * Note that this conversion assumes to be running on a L-endian system. */
float CryptomatteHash::float_encoded() const
{
uint32_t mantissa = hash & ((1 << 23) - 1);
@@ -626,7 +611,6 @@ void CryptomatteStampDataCallbackData::extract_layer_names(void *_data,
data->hash_to_layer_name.add(layer_hash, propvalue);
}
-/* C type callback function (StampCallback). */
void CryptomatteStampDataCallbackData::extract_layer_manifest(void *_data,
const char *propname,
char *propvalue,
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.cc
index 0dcfea78ca5..70edaccb244 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.cc
@@ -21,15 +21,16 @@
* \ingroup bke
*/
-#include <math.h> /* floor */
-#include <stdlib.h>
-#include <string.h>
+#include <cmath> /* floor */
+#include <cstdlib>
+#include <cstring>
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_endian_switch.h"
#include "BLI_ghash.h"
+#include "BLI_index_range.hh"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -43,7 +44,7 @@
#include "DNA_defaults.h"
#include "DNA_material_types.h"
-/* for dereferencing pointers */
+/* For dereferencing pointers. */
#include "DNA_key_types.h"
#include "DNA_object_types.h"
#include "DNA_vfont_types.h"
@@ -52,13 +53,13 @@
#include "BKE_curve.h"
#include "BKE_curveprofile.h"
#include "BKE_displist.h"
-#include "BKE_font.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_object.h"
+#include "BKE_vfont.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -67,10 +68,12 @@
#include "BLO_read_write.h"
+using blender::IndexRange;
+
/* globals */
/* local */
-static CLG_LogRef LOG = {"bke.curve"};
+// static CLG_LogRef LOG = {"bke.curve"};
static void curve_init_data(ID *id)
{
@@ -89,12 +92,12 @@ static void curve_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
BLI_listbase_clear(&curve_dst->nurb);
BKE_nurbList_duplicate(&(curve_dst->nurb), &(curve_src->nurb));
- curve_dst->mat = MEM_dupallocN(curve_src->mat);
+ curve_dst->mat = (Material **)MEM_dupallocN(curve_src->mat);
- curve_dst->str = MEM_dupallocN(curve_src->str);
- curve_dst->strinfo = MEM_dupallocN(curve_src->strinfo);
- curve_dst->tb = MEM_dupallocN(curve_src->tb);
- curve_dst->batch_cache = NULL;
+ curve_dst->str = (char *)MEM_dupallocN(curve_src->str);
+ curve_dst->strinfo = (CharInfo *)MEM_dupallocN(curve_src->strinfo);
+ curve_dst->tb = (TextBox *)MEM_dupallocN(curve_src->tb);
+ curve_dst->batch_cache = nullptr;
curve_dst->bevel_profile = BKE_curveprofile_copy(curve_src->bevel_profile);
@@ -104,8 +107,8 @@ static void curve_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
curve_dst->key->from = &curve_dst->id;
}
- curve_dst->editnurb = NULL;
- curve_dst->editfont = NULL;
+ curve_dst->editnurb = nullptr;
+ curve_dst->editfont = nullptr;
}
static void curve_free_data(ID *id)
@@ -130,17 +133,17 @@ static void curve_free_data(ID *id)
static void curve_foreach_id(ID *id, LibraryForeachIDData *data)
{
Curve *curve = (Curve *)id;
- BKE_LIB_FOREACHID_PROCESS(data, curve->bevobj, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, curve->taperobj, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, curve->textoncurve, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, curve->key, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->bevobj, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->taperobj, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->textoncurve, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->key, IDWALK_CB_USER);
for (int i = 0; i < curve->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, curve->mat[i], IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->mat[i], IDWALK_CB_USER);
}
- BKE_LIB_FOREACHID_PROCESS(data, curve->vfont, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, curve->vfontb, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, curve->vfonti, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, curve->vfontbi, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->vfont, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->vfontb, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->vfonti, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->vfontbi, IDWALK_CB_USER);
}
static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_address)
@@ -148,9 +151,9 @@ static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_addres
Curve *cu = (Curve *)id;
/* Clean up, important in undo case to reduce false detection of changed datablocks. */
- cu->editnurb = NULL;
- cu->editfont = NULL;
- cu->batch_cache = NULL;
+ cu->editnurb = nullptr;
+ cu->editfont = nullptr;
+ cu->batch_cache = nullptr;
/* write LibData */
BLO_write_id_struct(writer, Curve, id_address, &cu->id);
@@ -188,7 +191,7 @@ static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_addres
}
}
- if (cu->bevel_profile != NULL) {
+ if (cu->bevel_profile != nullptr) {
BKE_curveprofile_blend_write(writer, cu->bevel_profile);
}
}
@@ -218,13 +221,13 @@ static void curve_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_data_address(reader, &cu->strinfo);
BLO_read_data_address(reader, &cu->tb);
- if (cu->vfont == NULL) {
+ if (cu->vfont == nullptr) {
BLO_read_list(reader, &(cu->nurb));
}
else {
- cu->nurb.first = cu->nurb.last = NULL;
+ cu->nurb.first = cu->nurb.last = nullptr;
- TextBox *tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBoxread");
+ TextBox *tb = (TextBox *)MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBoxread");
if (cu->tb) {
memcpy(tb, cu->tb, cu->totbox * sizeof(TextBox));
MEM_freeN(cu->tb);
@@ -241,16 +244,16 @@ static void curve_blend_read_data(BlendDataReader *reader, ID *id)
}
}
- cu->editnurb = NULL;
- cu->editfont = NULL;
- cu->batch_cache = NULL;
+ cu->editnurb = nullptr;
+ cu->editfont = nullptr;
+ cu->batch_cache = nullptr;
LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
BLO_read_data_address(reader, &nu->bezt);
BLO_read_data_address(reader, &nu->bp);
BLO_read_data_address(reader, &nu->knotsu);
BLO_read_data_address(reader, &nu->knotsv);
- if (cu->vfont == NULL) {
+ if (cu->vfont == nullptr) {
nu->charidx = 0;
}
@@ -261,7 +264,7 @@ static void curve_blend_read_data(BlendDataReader *reader, ID *id)
cu->texflag &= ~CU_AUTOSPACE_EVALUATED;
BLO_read_data_address(reader, &cu->bevel_profile);
- if (cu->bevel_profile != NULL) {
+ if (cu->bevel_profile != nullptr) {
BKE_curveprofile_blend_read(reader, cu->bevel_profile);
}
}
@@ -304,34 +307,35 @@ static void curve_blend_read_expand(BlendExpander *expander, ID *id)
}
IDTypeInfo IDType_ID_CU = {
- .id_code = ID_CU,
- .id_filter = FILTER_ID_CU,
- .main_listbase_index = INDEX_ID_CU,
- .struct_size = sizeof(Curve),
- .name = "Curve",
- .name_plural = "curves",
- .translation_context = BLT_I18NCONTEXT_ID_CURVE,
- .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
-
- .init_data = curve_init_data,
- .copy_data = curve_copy_data,
- .free_data = curve_free_data,
- .make_local = NULL,
- .foreach_id = curve_foreach_id,
- .foreach_cache = NULL,
- .owner_get = NULL,
-
- .blend_write = curve_blend_write,
- .blend_read_data = curve_blend_read_data,
- .blend_read_lib = curve_blend_read_lib,
- .blend_read_expand = curve_blend_read_expand,
-
- .blend_read_undo_preserve = NULL,
-
- .lib_override_apply_post = NULL,
+ /* id_code */ ID_CU,
+ /* id_filter */ FILTER_ID_CU,
+ /* main_listbase_index */ INDEX_ID_CU,
+ /* struct_size */ sizeof(Curve),
+ /* name */ "Curve",
+ /* name_plural */ "curves",
+ /* translation_context */ BLT_I18NCONTEXT_ID_CURVE,
+ /* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
+
+ /* init_data */ curve_init_data,
+ /* copy_data */ curve_copy_data,
+ /* free_data */ curve_free_data,
+ /* make_local */ nullptr,
+ /* foreach_id */ curve_foreach_id,
+ /* foreach_cache */ nullptr,
+ /* foreach_path */ nullptr,
+ /* owner_get */ nullptr,
+
+ /* blend_write */ curve_blend_write,
+ /* blend_read_data */ curve_blend_read_data,
+ /* blend_read_lib */ curve_blend_read_lib,
+ /* blend_read_expand */ curve_blend_read_expand,
+
+ /* blend_read_undo_preserve */ nullptr,
+
+ /* lib_override_apply_post */ nullptr,
};
-/* frees editcurve entirely */
void BKE_curve_editfont_free(Curve *cu)
{
if (cu->editfont) {
@@ -348,21 +352,21 @@ void BKE_curve_editfont_free(Curve *cu)
}
MEM_freeN(ef);
- cu->editfont = NULL;
+ cu->editfont = nullptr;
}
}
static void curve_editNurb_keyIndex_cv_free_cb(void *val)
{
- CVKeyIndex *index = val;
+ CVKeyIndex *index = (CVKeyIndex *)val;
MEM_freeN(index->orig_cv);
MEM_freeN(val);
}
void BKE_curve_editNurb_keyIndex_delCV(GHash *keyindex, const void *cv)
{
- BLI_assert(keyindex != NULL);
- BLI_ghash_remove(keyindex, cv, NULL, curve_editNurb_keyIndex_cv_free_cb);
+ BLI_assert(keyindex != nullptr);
+ BLI_ghash_remove(keyindex, cv, nullptr, curve_editNurb_keyIndex_cv_free_cb);
}
void BKE_curve_editNurb_keyIndex_free(GHash **keyindex)
@@ -370,8 +374,8 @@ void BKE_curve_editNurb_keyIndex_free(GHash **keyindex)
if (!(*keyindex)) {
return;
}
- BLI_ghash_free(*keyindex, NULL, curve_editNurb_keyIndex_cv_free_cb);
- *keyindex = NULL;
+ BLI_ghash_free(*keyindex, nullptr, curve_editNurb_keyIndex_cv_free_cb);
+ *keyindex = nullptr;
}
void BKE_curve_editNurb_free(Curve *cu)
@@ -380,7 +384,7 @@ void BKE_curve_editNurb_free(Curve *cu)
BKE_nurbList_free(&cu->editnurb->nurbs);
BKE_curve_editNurb_keyIndex_free(&cu->editnurb->keyindex);
MEM_freeN(cu->editnurb);
- cu->editnurb = NULL;
+ cu->editnurb = nullptr;
}
}
@@ -394,12 +398,12 @@ void BKE_curve_init(Curve *cu, const short curve_type)
cu->flag |= CU_FRONT | CU_BACK;
cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get();
cu->vfont->id.us += 4;
- cu->str = MEM_malloc_arrayN(12, sizeof(unsigned char), "str");
+ cu->str = (char *)MEM_malloc_arrayN(12, sizeof(unsigned char), "str");
BLI_strncpy(cu->str, "Text", 12);
cu->len = cu->len_char32 = cu->pos = 4;
- cu->strinfo = MEM_calloc_arrayN(12, sizeof(CharInfo), "strinfo new");
+ cu->strinfo = (CharInfo *)MEM_calloc_arrayN(12, sizeof(CharInfo), "strinfo new");
cu->totbox = cu->actbox = 1;
- cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox");
+ cu->tb = (TextBox *)MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox");
cu->tb[0].w = cu->tb[0].h = 0.0;
}
else if (cu->type == OB_SURF) {
@@ -407,7 +411,7 @@ void BKE_curve_init(Curve *cu, const short curve_type)
cu->resolu = 4;
cu->resolv = 4;
}
- cu->bevel_profile = NULL;
+ cu->bevel_profile = nullptr;
}
Curve *BKE_curve_add(Main *bmain, const char *name, int type)
@@ -415,21 +419,20 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
Curve *cu;
/* We cannot use #BKE_id_new here as we need some custom initialization code. */
- cu = BKE_libblock_alloc(bmain, ID_CU, name, 0);
+ cu = (Curve *)BKE_libblock_alloc(bmain, ID_CU, name, 0);
BKE_curve_init(cu, type);
return cu;
}
-/* Get list of nurbs from editnurbs structure */
ListBase *BKE_curve_editNurbs_get(Curve *cu)
{
if (cu->editnurb) {
return &cu->editnurb->nurbs;
}
- return NULL;
+ return nullptr;
}
const ListBase *BKE_curve_editNurbs_get_for_read(const Curve *cu)
@@ -438,7 +441,7 @@ const ListBase *BKE_curve_editNurbs_get_for_read(const Curve *cu)
return &cu->editnurb->nurbs;
}
- return NULL;
+ return nullptr;
}
short BKE_curve_type_get(const Curve *cu)
@@ -481,10 +484,10 @@ void BKE_curve_dimension_update(Curve *cu)
void BKE_curve_type_test(Object *ob)
{
- ob->type = BKE_curve_type_get(ob->data);
+ ob->type = BKE_curve_type_get((Curve *)ob->data);
if (ob->type == OB_CURVE) {
- Curve *cu = ob->data;
+ Curve *cu = (Curve *)ob->data;
if (CU_IS_2D(cu)) {
BKE_curve_dimension_update(cu);
}
@@ -495,15 +498,15 @@ BoundBox *BKE_curve_boundbox_get(Object *ob)
{
/* This is Object-level data access,
* DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
- if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
- Curve *cu = ob->data;
+ if (ob->runtime.bb == nullptr || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
+ Curve *cu = (Curve *)ob->data;
float min[3], max[3];
INIT_MINMAX(min, max);
BKE_curve_minmax(cu, true, min, max);
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
+ if (ob->runtime.bb == nullptr) {
+ ob->runtime.bb = (BoundBox *)MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
@@ -618,26 +621,26 @@ int BKE_nurbList_verts_count_without_handles(const ListBase *nurb)
void BKE_nurb_free(Nurb *nu)
{
- if (nu == NULL) {
+ if (nu == nullptr) {
return;
}
if (nu->bezt) {
MEM_freeN(nu->bezt);
}
- nu->bezt = NULL;
+ nu->bezt = nullptr;
if (nu->bp) {
MEM_freeN(nu->bp);
}
- nu->bp = NULL;
+ nu->bp = nullptr;
if (nu->knotsu) {
MEM_freeN(nu->knotsu);
}
- nu->knotsu = NULL;
+ nu->knotsu = nullptr;
if (nu->knotsv) {
MEM_freeN(nu->knotsv);
}
- nu->knotsv = NULL;
+ nu->knotsv = nullptr;
// if (nu->trim.first) freeNurblist(&(nu->trim));
MEM_freeN(nu);
@@ -645,7 +648,7 @@ void BKE_nurb_free(Nurb *nu)
void BKE_nurbList_free(ListBase *lb)
{
- if (lb == NULL) {
+ if (lb == nullptr) {
return;
}
@@ -661,8 +664,8 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu)
int len;
newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "duplicateNurb");
- if (newnu == NULL) {
- return NULL;
+ if (newnu == nullptr) {
+ return nullptr;
}
memcpy(newnu, nu, sizeof(Nurb));
@@ -675,19 +678,19 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu)
newnu->bp = (BPoint *)MEM_malloc_arrayN(len, sizeof(BPoint), "duplicateNurb3");
memcpy(newnu->bp, nu->bp, len * sizeof(BPoint));
- newnu->knotsu = newnu->knotsv = NULL;
+ newnu->knotsu = newnu->knotsv = nullptr;
if (nu->knotsu) {
len = KNOTSU(nu);
if (len) {
- newnu->knotsu = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb4");
+ newnu->knotsu = (float *)MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb4");
memcpy(newnu->knotsu, nu->knotsu, sizeof(float) * len);
}
}
if (nu->pntsv > 1 && nu->knotsv) {
len = KNOTSV(nu);
if (len) {
- newnu->knotsv = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb5");
+ newnu->knotsv = (float *)MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb5");
memcpy(newnu->knotsv, nu->knotsv, sizeof(float) * len);
}
}
@@ -695,7 +698,6 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu)
return newnu;
}
-/* copy the nurb but allow for different number of points (to be copied after this) */
Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
{
Nurb *newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "copyNurb");
@@ -708,8 +710,8 @@ Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
newnu->pntsv = pntsv;
/* caller can manually handle these arrays */
- newnu->knotsu = NULL;
- newnu->knotsv = NULL;
+ newnu->knotsu = nullptr;
+ newnu->knotsv = nullptr;
if (src->bezt) {
newnu->bezt = (BezTriple *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BezTriple), "copyNurb2");
@@ -757,10 +759,6 @@ void BKE_nurb_project_2d(Nurb *nu)
}
}
-/**
- * if use_radius is truth, minmax will take points' radius into account,
- * which will make boundbox closer to beveled curve.
- */
void BKE_nurb_minmax(const Nurb *nu, bool use_radius, float min[3], float max[3])
{
BezTriple *bezt;
@@ -842,7 +840,7 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
}
}
else if (nu->type == CU_BEZIER) {
- points = MEM_mallocN(sizeof(float[3]) * (resolu + 1), "getLength_bezier");
+ points = (float *)MEM_mallocN(sizeof(float[3]) * (resolu + 1), "getLength_bezier");
a = nu->pntsu - 1;
bezt = nu->bezt;
if (nu->flagu & CU_NURB_CYCLIC) {
@@ -886,9 +884,9 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
else if (nu->type == CU_NURBS) {
if (nu->pntsv == 1) {
/* important to zero for BKE_nurb_makeCurve. */
- points = MEM_callocN(sizeof(float[3]) * pntsu * resolu, "getLength_nurbs");
+ points = (float *)MEM_callocN(sizeof(float[3]) * pntsu * resolu, "getLength_nurbs");
- BKE_nurb_makeCurve(nu, points, NULL, NULL, NULL, resolu, sizeof(float[3]));
+ BKE_nurb_makeCurve(nu, points, nullptr, nullptr, nullptr, resolu, sizeof(float[3]));
if (nu->flagu & CU_NURB_CYCLIC) {
b = pntsu * resolu + 1;
@@ -914,10 +912,9 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
return length;
}
-/* be sure to call makeknots after this */
void BKE_nurb_points_add(Nurb *nu, int number)
{
- nu->bp = MEM_recallocN(nu->bp, (nu->pntsu + number) * sizeof(BPoint));
+ nu->bp = (BPoint *)MEM_recallocN(nu->bp, (nu->pntsu + number) * sizeof(BPoint));
BPoint *bp;
int i;
@@ -933,7 +930,7 @@ void BKE_nurb_bezierPoints_add(Nurb *nu, int number)
BezTriple *bezt;
int i;
- nu->bezt = MEM_recallocN(nu->bezt, (nu->pntsu + number) * sizeof(BezTriple));
+ nu->bezt = (BezTriple *)MEM_recallocN(nu->bezt, (nu->pntsu + number) * sizeof(BezTriple));
for (i = 0, bezt = &nu->bezt[nu->pntsu]; i < number; i++, bezt++) {
bezt->radius = 1.0f;
@@ -984,7 +981,7 @@ BezTriple *BKE_nurb_bezt_get_next(Nurb *nu, BezTriple *bezt)
bezt_next = nu->bezt;
}
else {
- bezt_next = NULL;
+ bezt_next = nullptr;
}
}
else {
@@ -1005,7 +1002,7 @@ BPoint *BKE_nurb_bpoint_get_next(Nurb *nu, BPoint *bp)
bp_next = nu->bp;
}
else {
- bp_next = NULL;
+ bp_next = nullptr;
}
}
else {
@@ -1027,7 +1024,7 @@ BezTriple *BKE_nurb_bezt_get_prev(Nurb *nu, BezTriple *bezt)
bezt_prev = &nu->bezt[nu->pntsu - 1];
}
else {
- bezt_prev = NULL;
+ bezt_prev = nullptr;
}
}
else {
@@ -1049,7 +1046,7 @@ BPoint *BKE_nurb_bpoint_get_prev(Nurb *nu, BPoint *bp)
bp_prev = &nu->bp[nu->pntsu - 1];
}
else {
- bp_prev = NULL;
+ bp_prev = nullptr;
}
}
else {
@@ -1166,81 +1163,34 @@ void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, BPoint *bp, float r_plane[3])
static void calcknots(float *knots, const int pnts, const short order, const short flag)
{
- /* knots: number of pnts NOT corrected for cyclic */
- const int pnts_order = pnts + order;
- float k;
- int a;
+ const bool is_cyclic = flag & CU_NURB_CYCLIC;
+ const bool is_bezier = flag & CU_NURB_BEZIER && !(flag & CU_NURB_ENDPOINT);
+ const bool is_end_point = flag & CU_NURB_ENDPOINT && !(flag & CU_NURB_BEZIER);
+ /* Inner knots are always repeated once except on Bezier case. */
+ const int repeat_inner = is_bezier ? order - 1 : 1;
+ /* How many times to repeat 0.0 at the beginning of knot. */
+ const int head = is_end_point && !is_cyclic ? order : (is_bezier ? order / 2 : 1);
+ /* Number of knots replicating widths of the starting knots.
+ * Covers both Cyclic and EndPoint cases. */
+ const int tail = is_cyclic ? 2 * order - 1 : (is_end_point ? order : 0);
- switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) {
- case CU_NURB_ENDPOINT:
- k = 0.0;
- for (a = 1; a <= pnts_order; a++) {
- knots[a - 1] = k;
- if (a >= order && a <= pnts) {
- k += 1.0f;
- }
- }
- break;
- case CU_NURB_BEZIER:
- /* Warning, the order MUST be 2 or 4,
- * if this is not enforced, the displist will be corrupt */
- if (order == 4) {
- k = 0.34;
- for (a = 0; a < pnts_order; a++) {
- knots[a] = floorf(k);
- k += (1.0f / 3.0f);
- }
- }
- else if (order == 3) {
- k = 0.6f;
- for (a = 0; a < pnts_order; a++) {
- if (a >= order && a <= pnts) {
- k += 0.5f;
- }
- knots[a] = floorf(k);
- }
- }
- else {
- CLOG_ERROR(&LOG, "bez nurb curve order is not 3 or 4, should never happen");
- }
- break;
- default:
- for (a = 0; a < pnts_order; a++) {
- knots[a] = (float)a;
- }
- break;
- }
-}
-
-static void makecyclicknots(float *knots, int pnts, short order)
-/* pnts, order: number of pnts NOT corrected for cyclic */
-{
- int a, b, order2, c;
-
- if (knots == NULL) {
- return;
- }
+ const int knot_count = pnts + order + (is_cyclic ? order - 1 : 0);
- order2 = order - 1;
+ int r = head;
+ float current = 0.0f;
- /* do first long rows (order -1), remove identical knots at endpoints */
- if (order > 2) {
- b = pnts + order2;
- for (a = 1; a < order2; a++) {
- if (knots[b] != knots[b - a]) {
- break;
- }
- }
- if (a == order2) {
- knots[pnts + order - 2] += 1.0f;
+ for (const int i : IndexRange(knot_count - tail)) {
+ knots[i] = current;
+ r--;
+ if (r == 0) {
+ current += 1.0;
+ r = repeat_inner;
}
}
- b = order;
- c = pnts + order + order2;
- for (a = pnts + order2; a < c; a++) {
- knots[a] = knots[a - 1] + (knots[b] - knots[b - 1]);
- b--;
+ const int tail_index = knot_count - tail;
+ for (const int i : IndexRange(tail)) {
+ knots[tail_index + i] = current + (knots[i] - knots[0]);
}
}
@@ -1252,17 +1202,11 @@ static void makeknots(Nurb *nu, short uv)
MEM_freeN(nu->knotsu);
}
if (BKE_nurb_check_valid_u(nu)) {
- nu->knotsu = MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots");
- if (nu->flagu & CU_NURB_CYCLIC) {
- calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0); /* cyclic should be uniform */
- makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu);
- }
- else {
- calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu);
- }
+ nu->knotsu = (float *)MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots");
+ calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu);
}
else {
- nu->knotsu = NULL;
+ nu->knotsu = nullptr;
}
}
else if (uv == 2) {
@@ -1270,17 +1214,11 @@ static void makeknots(Nurb *nu, short uv)
MEM_freeN(nu->knotsv);
}
if (BKE_nurb_check_valid_v(nu)) {
- nu->knotsv = MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots");
- if (nu->flagv & CU_NURB_CYCLIC) {
- calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0); /* cyclic should be uniform */
- makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv);
- }
- else {
- calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv);
- }
+ nu->knotsv = (float *)MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots");
+ calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv);
}
else {
- nu->knotsv = NULL;
+ nu->knotsv = nullptr;
}
}
}
@@ -1374,9 +1312,6 @@ static void basisNurb(
}
}
-/**
- * \param coord_array: has to be (3 * 4 * resolu * resolv) in size, and zero-ed.
- */
void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv)
{
BPoint *bp;
@@ -1387,7 +1322,7 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
int totu = nu->pntsu * resolu, totv = nu->pntsv * resolv;
- if (nu->knotsu == NULL || nu->knotsv == NULL) {
+ if (nu->knotsu == nullptr || nu->knotsv == nullptr) {
return;
}
if (nu->orderu > nu->pntsu) {
@@ -1396,7 +1331,7 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
if (nu->orderv > nu->pntsv) {
return;
}
- if (coord_array == NULL) {
+ if (coord_array == nullptr) {
return;
}
@@ -1447,7 +1382,7 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
jstart = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces4");
jend = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces5");
- /* precalculation of basisv and jstart, jend */
+ /* Pre-calculation of `basisv` and `jstart`, `jend`. */
if (nu->flagv & CU_NURB_CYCLIC) {
cycl = nu->orderv - 1;
}
@@ -1569,11 +1504,6 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
MEM_freeN(jend);
}
-/**
- * \param coord_array: Has to be 3 * 4 * pntsu * resolu in size and zero-ed
- * \param tilt_array: set when non-NULL
- * \param radius_array: set when non-NULL
- */
void BKE_nurb_makeCurve(const Nurb *nu,
float *coord_array,
float *tilt_array,
@@ -1590,13 +1520,13 @@ void BKE_nurb_makeCurve(const Nurb *nu,
*weight_fp = weight_array;
int i, len, istart, iend, cycl;
- if (nu->knotsu == NULL) {
+ if (nu->knotsu == nullptr) {
return;
}
if (nu->orderu > nu->pntsu) {
return;
}
- if (coord_array == NULL) {
+ if (coord_array == nullptr) {
return;
}
@@ -1690,16 +1620,16 @@ void BKE_nurb_makeCurve(const Nurb *nu,
}
}
- coord_fp = POINTER_OFFSET(coord_fp, stride);
+ coord_fp = (float *)POINTER_OFFSET(coord_fp, stride);
if (tilt_fp) {
- tilt_fp = POINTER_OFFSET(tilt_fp, stride);
+ tilt_fp = (float *)POINTER_OFFSET(tilt_fp, stride);
}
if (radius_fp) {
- radius_fp = POINTER_OFFSET(radius_fp, stride);
+ radius_fp = (float *)POINTER_OFFSET(radius_fp, stride);
}
if (weight_fp) {
- weight_fp = POINTER_OFFSET(weight_fp, stride);
+ weight_fp = (float *)POINTER_OFFSET(weight_fp, stride);
}
u += ustep;
@@ -1710,9 +1640,6 @@ void BKE_nurb_makeCurve(const Nurb *nu,
MEM_freeN(basisu);
}
-/**
- * Calculate the length for arrays filled in by #BKE_curve_calc_coords_axis.
- */
unsigned int BKE_curve_calc_coords_axis_len(const unsigned int bezt_array_len,
const unsigned int resolu,
const bool is_cyclic,
@@ -1724,12 +1651,6 @@ unsigned int BKE_curve_calc_coords_axis_len(const unsigned int bezt_array_len,
return points_len;
}
-/**
- * Calculate an array for the entire curve (cyclic or non-cyclic).
- * \note Call for each axis.
- *
- * \param use_cyclic_duplicate_endpoint: Duplicate values at the beginning & end of the array.
- */
void BKE_curve_calc_coords_axis(const BezTriple *bezt_array,
const unsigned int bezt_array_len,
const unsigned int resolu,
@@ -1757,7 +1678,7 @@ void BKE_curve_calc_coords_axis(const BezTriple *bezt_array,
r_points_offset,
(int)resolu,
stride);
- r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride);
+ r_points_offset = (float *)POINTER_OFFSET(r_points_offset, resolu_stride);
}
if (is_cyclic) {
@@ -1770,23 +1691,22 @@ void BKE_curve_calc_coords_axis(const BezTriple *bezt_array,
r_points_offset,
(int)resolu,
stride);
- r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride);
+ r_points_offset = (float *)POINTER_OFFSET(r_points_offset, resolu_stride);
if (use_cyclic_duplicate_endpoint) {
*r_points_offset = *r_points;
- r_points_offset = POINTER_OFFSET(r_points_offset, stride);
+ r_points_offset = (float *)POINTER_OFFSET(r_points_offset, stride);
}
}
else {
- float *r_points_last = POINTER_OFFSET(r_points, bezt_array_last * resolu_stride);
+ float *r_points_last = (float *)POINTER_OFFSET(r_points, bezt_array_last * resolu_stride);
*r_points_last = bezt_array[bezt_array_last].vec[1][axis];
- r_points_offset = POINTER_OFFSET(r_points_offset, stride);
+ r_points_offset = (float *)POINTER_OFFSET(r_points_offset, stride);
}
- BLI_assert(POINTER_OFFSET(r_points, points_len * stride) == r_points_offset);
+ BLI_assert((float *)POINTER_OFFSET(r_points, points_len * stride) == r_points_offset);
UNUSED_VARS_NDEBUG(points_len);
}
-/* forward differencing method for bezier curve */
void BKE_curve_forward_diff_bezier(
float q0, float q1, float q2, float q3, float *p, int it, int stride)
{
@@ -1808,14 +1728,13 @@ void BKE_curve_forward_diff_bezier(
for (a = 0; a <= it; a++) {
*p = q0;
- p = POINTER_OFFSET(p, stride);
+ p = (float *)POINTER_OFFSET(p, stride);
q0 += q1;
q1 += q2;
q2 += q3;
}
}
-/* forward differencing method for first derivative of cubic bezier curve */
void BKE_curve_forward_diff_tangent_bezier(
float q0, float q1, float q2, float q3, float *p, int it, int stride)
{
@@ -1834,7 +1753,7 @@ void BKE_curve_forward_diff_tangent_bezier(
for (a = 0; a <= it; a++) {
*p = q0;
- p = POINTER_OFFSET(p, stride);
+ p = (float *)POINTER_OFFSET(p, stride);
q0 += q1;
q1 += q2;
}
@@ -1860,7 +1779,7 @@ static void forward_diff_bezier_cotangent(const float p0[3],
(-18.0f * t + 6.0f) * p2[i] + (6.0f * t) * p3[i];
}
normalize_v3(p);
- p = POINTER_OFFSET(p, stride);
+ p = (float *)POINTER_OFFSET(p, stride);
}
}
@@ -1973,7 +1892,7 @@ struct BevelSort {
static int vergxcobev(const void *a1, const void *a2)
{
- const struct BevelSort *x1 = a1, *x2 = a2;
+ const struct BevelSort *x1 = (BevelSort *)a1, *x2 = (BevelSort *)a2;
if (x1->left > x2->left) {
return 1;
@@ -2047,7 +1966,7 @@ static void tilt_bezpart(const BezTriple *prevbezt,
float fac, dfac, t[4];
int a;
- if (tilt_array == NULL && radius_array == NULL) {
+ if (tilt_array == nullptr && radius_array == nullptr) {
return;
}
@@ -2095,7 +2014,7 @@ static void tilt_bezpart(const BezTriple *prevbezt,
t[3] * next->tilt;
}
- tilt_array = POINTER_OFFSET(tilt_array, stride);
+ tilt_array = (float *)POINTER_OFFSET(tilt_array, stride);
}
if (radius_array) {
@@ -2109,14 +2028,14 @@ static void tilt_bezpart(const BezTriple *prevbezt,
else {
/* reuse interpolation from tilt if we can */
- if (tilt_array == NULL || nu->tilt_interp != nu->radius_interp) {
+ if (tilt_array == nullptr || nu->tilt_interp != nu->radius_interp) {
key_curve_position_weights(fac, t, nu->radius_interp);
}
*radius_array = t[0] * pprev->radius + t[1] * prevbezt->radius + t[2] * bezt->radius +
t[3] * next->radius;
}
- radius_array = POINTER_OFFSET(radius_array, stride);
+ radius_array = (float *)POINTER_OFFSET(radius_array, stride);
}
if (weight_array) {
@@ -2124,15 +2043,15 @@ static void tilt_bezpart(const BezTriple *prevbezt,
*weight_array = prevbezt->weight + (bezt->weight - prevbezt->weight) *
(3.0f * fac * fac - 2.0f * fac * fac * fac);
- weight_array = POINTER_OFFSET(weight_array, stride);
+ weight_array = (float *)POINTER_OFFSET(weight_array, stride);
}
}
}
-/* make_bevel_list_3D_* funcs, at a minimum these must
- * fill in the bezp->quat and bezp->dir values */
+/* `make_bevel_list_3D_*` functions, at a minimum these must
+ * fill in the #BevPoint.quat and #BevPoint.dir values. */
-/* utility for make_bevel_list_3D_* funcs */
+/** Utility for `make_bevel_list_3D_*` functions. */
static void bevel_list_calc_bisect(BevList *bl)
{
BevPoint *bevp2, *bevp1, *bevp0;
@@ -2354,14 +2273,14 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl)
/* Need to correct for the start/end points not matching
* do this by calculating the tilt angle difference, then apply
- * the rotation gradually over the entire curve
+ * the rotation gradually over the entire curve.
*
- * note that the split is between last and second last, rather than first/last as youd expect.
+ * Note that the split is between last and second last, rather than first/last as you'd expect.
*
* real order is like this
* 0,1,2,3,4 --> 1,2,3,4,0
*
- * this is why we compare last with second last
+ * This is why we compare last with second last.
*/
float vec_1[3] = {0, 1, 0}, vec_2[3] = {0, 1, 0}, angle, ang_fac, cross_tmp[3];
@@ -2514,12 +2433,15 @@ static void make_bevel_list_segment_3D(BevList *bl)
normalize_v3(bevp1->dir);
vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
-
axis_angle_to_quat(q, bevp1->dir, bevp1->tilt);
mul_qt_qtqt(bevp1->quat, q, bevp1->quat);
normalize_qt(bevp1->quat);
+
copy_v3_v3(bevp2->dir, bevp1->dir);
- copy_qt_qt(bevp2->quat, bevp1->quat);
+ vec_to_quat(bevp2->quat, bevp2->dir, 5, 1);
+ axis_angle_to_quat(q, bevp2->dir, bevp2->tilt);
+ mul_qt_qtqt(bevp2->quat, q, bevp2->quat);
+ normalize_qt(bevp2->quat);
}
/* only for 2 points */
@@ -2622,13 +2544,13 @@ static void bevlist_firstlast_direction_calc_from_bpoint(const Nurb *nu, BevList
void BKE_curve_bevelList_free(ListBase *bev)
{
LISTBASE_FOREACH_MUTABLE (BevList *, bl, bev) {
- if (bl->seglen != NULL) {
+ if (bl->seglen != nullptr) {
MEM_freeN(bl->seglen);
}
- if (bl->segbevcount != NULL) {
+ if (bl->segbevcount != nullptr) {
MEM_freeN(bl->segbevcount);
}
- if (bl->bevpoints != NULL) {
+ if (bl->bevpoints != nullptr) {
MEM_freeN(bl->bevpoints);
}
MEM_freeN(bl);
@@ -2639,22 +2561,21 @@ void BKE_curve_bevelList_free(ListBase *bev)
void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_render)
{
- /*
- * - convert all curves to polys, with indication of resol and flags for double-vertices
- * - possibly; do a smart vertice removal (in case Nurb)
- * - separate in individual blocks with BoundBox
- * - AutoHole detection
+ /* - Convert all curves to polys, with indication of resolution and flags for double-vertices.
+ * - Possibly; do a smart vertex removal (in case #Nurb).
+ * - Separate in individual blocks with #BoundBox.
+ * - Auto-hole detection.
*/
- /* this function needs an object, because of tflag and upflag */
- Curve *cu = ob->data;
+ /* This function needs an object, because of `tflag` and `upflag`. */
+ Curve *cu = (Curve *)ob->data;
BezTriple *bezt, *prevbezt;
BPoint *bp;
BevList *blnew;
- BevPoint *bevp2, *bevp1 = NULL, *bevp0;
+ BevPoint *bevp2, *bevp1 = nullptr, *bevp0;
const float threshold = 0.00001f;
float min, inp;
- float *seglen = NULL;
+ float *seglen = nullptr;
struct BevelSort *sortdata, *sd, *sd1;
int a, b, nr, poly, resolu = 0, len = 0, segcount;
int *segbevcount;
@@ -2662,7 +2583,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
bool is_editmode = false;
ListBase *bev;
- /* segbevcount alsp requires seglen. */
+ /* segbevcount also requires seglen. */
const bool need_seglen = ELEM(
cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) ||
ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE);
@@ -2679,7 +2600,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
if (cu->editnurb && ob->type != OB_FONT) {
- is_editmode = 1;
+ is_editmode = true;
}
LISTBASE_FOREACH (const Nurb *, nu, nurbs) {
@@ -2690,8 +2611,8 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
/* check we are a single point? also check we are not a surface and that the orderu is sane,
* enforced in the UI but can go wrong possibly */
if (!BKE_nurb_check_valid_u(nu)) {
- BevList *bl = MEM_callocN(sizeof(BevList), "makeBevelList1");
- bl->bevpoints = MEM_calloc_arrayN(1, sizeof(BevPoint), "makeBevelPoints1");
+ BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), "makeBevelList1");
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(1, sizeof(BevPoint), "makeBevelPoints1");
BLI_addtail(bev, bl);
bl->nr = 0;
bl->charidx = nu->charidx;
@@ -2720,11 +2641,11 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
if (nu->type == CU_POLY) {
len = nu->pntsu;
- BevList *bl = MEM_callocN(sizeof(BevList), "makeBevelList2");
- bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints2");
+ BevList *bl = MEM_cnew<BevList>(__func__);
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList2_seglen");
- bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList2_segbevcount");
+ bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
+ bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
}
BLI_addtail(bev, bl);
@@ -2744,7 +2665,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
bevp->radius = bp->radius;
bevp->weight = bp->weight;
bp++;
- if (seglen != NULL && len != 0) {
+ if (seglen != nullptr && len != 0) {
*seglen = len_v3v3(bevp->vec, bp->vec);
bevp++;
bevp->offset = *seglen;
@@ -2770,11 +2691,11 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
/* in case last point is not cyclic */
len = segcount * resolu + 1;
- BevList *bl = MEM_callocN(sizeof(BevList), "makeBevelBPoints");
- bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelBPointsPoints");
+ BevList *bl = MEM_cnew<BevList>(__func__);
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelBPoints_seglen");
- bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelBPoints_segbevcount");
+ bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
+ bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
}
BLI_addtail(bev, bl);
@@ -2786,7 +2707,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
segbevcount = bl->segbevcount;
bevp->offset = 0;
- if (seglen != NULL) {
+ if (seglen != nullptr) {
*seglen = 0;
*segbevcount = 0;
}
@@ -2818,7 +2739,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
bevp++;
bl->nr++;
bl->dupe_nr = 1;
- if (seglen != NULL) {
+ if (seglen != nullptr) {
*seglen = len_v3v3(prevbezt->vec[1], bezt->vec[1]);
bevp->offset = *seglen;
seglen++;
@@ -2830,10 +2751,10 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
}
}
else {
- /* always do all three, to prevent data hanging around */
+ /* Always do all three, to prevent data hanging around. */
int j;
- /* BevPoint must stay aligned to 4 so sizeof(BevPoint)/sizeof(float) works */
+ /* #BevPoint must stay aligned to 4 so `sizeof(BevPoint) / sizeof(float)` works. */
for (j = 0; j < 3; j++) {
BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
prevbezt->vec[2][j],
@@ -2844,13 +2765,13 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
sizeof(BevPoint));
}
- /* if both arrays are NULL do nothiong */
+ /* If both arrays are `nullptr` do nothing. */
tilt_bezpart(prevbezt,
bezt,
nu,
- do_tilt ? &bevp->tilt : NULL,
- do_radius ? &bevp->radius : NULL,
- do_weight ? &bevp->weight : NULL,
+ do_tilt ? &bevp->tilt : nullptr,
+ do_radius ? &bevp->radius : nullptr,
+ do_weight ? &bevp->weight : nullptr,
resolu,
sizeof(BevPoint));
@@ -2864,15 +2785,15 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
sizeof(BevPoint));
}
- /* seglen */
- if (seglen != NULL) {
+ /* `seglen`. */
+ if (seglen != nullptr) {
*seglen = 0;
*segbevcount = 0;
for (j = 0; j < resolu; j++) {
bevp0 = bevp;
bevp++;
bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
- /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
+ /* Match `seglen` and `segbevcount` to the cleaned up bevel lists (see STEP 2). */
if (bevp->offset > threshold) {
*seglen += bevp->offset;
*segbevcount += 1;
@@ -2906,11 +2827,11 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
if (nu->pntsv == 1) {
len = (resolu * segcount);
- BevList *bl = MEM_callocN(sizeof(BevList), "makeBevelList3");
- bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints3");
+ BevList *bl = MEM_cnew<BevList>(__func__);
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList3_seglen");
- bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList3_segbevcount");
+ bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
+ bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
}
BLI_addtail(bev, bl);
bl->nr = len;
@@ -2924,14 +2845,14 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BKE_nurb_makeCurve(nu,
&bevp->vec[0],
- do_tilt ? &bevp->tilt : NULL,
- do_radius ? &bevp->radius : NULL,
- do_weight ? &bevp->weight : NULL,
+ do_tilt ? &bevp->tilt : nullptr,
+ do_radius ? &bevp->radius : nullptr,
+ do_weight ? &bevp->weight : nullptr,
resolu,
sizeof(BevPoint));
/* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
- if (seglen != NULL) {
+ if (seglen != nullptr) {
nr = segcount;
bevp0 = bevp;
bevp++;
@@ -2983,7 +2904,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
}
nr--;
while (nr--) {
- if (seglen != NULL) {
+ if (seglen != nullptr) {
if (fabsf(bevp1->offset) < threshold) {
bevp0->dupe_tag = true;
bl->dupe_nr++;
@@ -3005,10 +2926,10 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
continue;
}
- nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */
- blnew = MEM_mallocN(sizeof(BevList), "makeBevelList4");
+ nr = bl->nr - bl->dupe_nr + 1; /* +1 because vector-bezier sets flag too. */
+ blnew = (BevList *)MEM_mallocN(sizeof(BevList), "makeBevelList4");
memcpy(blnew, bl, sizeof(BevList));
- blnew->bevpoints = MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4");
+ blnew->bevpoints = (BevPoint *)MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4");
if (!blnew->bevpoints) {
MEM_freeN(blnew);
break;
@@ -3017,7 +2938,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
blnew->seglen = bl->seglen;
blnew->nr = 0;
BLI_remlink(bev, bl);
- BLI_insertlinkbefore(bev, bl->next, blnew); /* to make sure bevlist is tuned with nurblist */
+ BLI_insertlinkbefore(bev, bl->next, blnew); /* Ensure `bevlist` is tuned with `nurblist`. */
bevp0 = bl->bevpoints;
bevp1 = blnew->bevpoints;
nr = bl->nr;
@@ -3029,7 +2950,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
}
bevp0++;
}
- if (bl->bevpoints != NULL) {
+ if (bl->bevpoints != nullptr) {
MEM_freeN(bl->bevpoints);
}
MEM_freeN(bl);
@@ -3048,7 +2969,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
/* find extreme left points, also test (turning) direction */
if (poly > 0) {
- sd = sortdata = MEM_malloc_arrayN(poly, sizeof(struct BevelSort), "makeBevelList5");
+ sd = sortdata = (BevelSort *)MEM_malloc_arrayN(poly, sizeof(struct BevelSort), __func__);
LISTBASE_FOREACH (BevList *, bl, bev) {
if (bl->poly > 0) {
BevPoint *bevp;
@@ -3139,7 +3060,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BevPoint *bevp = bl->bevpoints;
unit_qt(bevp->quat);
}
- else if (bl->nr == 2) { /* 2 pnt, treat separate */
+ else if (bl->nr == 2) { /* 2 points, treat separately. */
make_bevel_list_segment_2D(bl);
}
else {
@@ -3154,7 +3075,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BevPoint *bevp = bl->bevpoints;
unit_qt(bevp->quat);
}
- else if (bl->nr == 2) { /* 2 pnt, treat separate */
+ else if (bl->nr == 2) { /* 2 points, treat separately. */
make_bevel_list_segment_3D(bl);
}
else {
@@ -3194,7 +3115,7 @@ static void calchandleNurb_intern(BezTriple *bezt,
p2 = bezt->vec[1];
- if (prev == NULL) {
+ if (prev == nullptr) {
p3 = next->vec[1];
pt[0] = 2.0f * p2[0] - p3[0];
pt[1] = 2.0f * p2[1] - p3[1];
@@ -3205,7 +3126,7 @@ static void calchandleNurb_intern(BezTriple *bezt,
p1 = prev->vec[1];
}
- if (next == NULL) {
+ if (next == nullptr) {
pt[0] = 2.0f * p2[0] - p1[0];
pt[1] = 2.0f * p2[1] - p1[1];
pt[2] = 2.0f * p2[2] - p1[2];
@@ -3283,13 +3204,13 @@ static void calchandleNurb_intern(BezTriple *bezt,
if (ydiff1 <= 0.0f) {
if (prev->vec[1][1] > bezt->vec[0][1]) {
bezt->vec[0][1] = prev->vec[1][1];
- leftviolate = 1;
+ leftviolate = true;
}
}
else {
if (prev->vec[1][1] < bezt->vec[0][1]) {
bezt->vec[0][1] = prev->vec[1][1];
- leftviolate = 1;
+ leftviolate = true;
}
}
}
@@ -3310,13 +3231,13 @@ static void calchandleNurb_intern(BezTriple *bezt,
if (ydiff1 <= 0.0f) {
if (next->vec[1][1] < bezt->vec[2][1]) {
bezt->vec[2][1] = next->vec[1][1];
- rightviolate = 1;
+ rightviolate = true;
}
}
else {
if (next->vec[1][1] > bezt->vec[2][1]) {
bezt->vec[2][1] = next->vec[1][1];
- rightviolate = 1;
+ rightviolate = true;
}
}
}
@@ -3346,13 +3267,13 @@ static void calchandleNurb_intern(BezTriple *bezt,
}
if (skip_align ||
- /* when one handle is free, alignming makes no sense, see: T35952 */
- (ELEM(HD_FREE, bezt->h1, bezt->h2)) ||
- /* also when no handles are aligned, skip this step */
+ /* When one handle is free, aligning makes no sense, see: T35952 */
+ ELEM(HD_FREE, bezt->h1, bezt->h2) ||
+ /* Also when no handles are aligned, skip this step. */
(!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) {
- /* handles need to be updated during animation and applying stuff like hooks,
+ /* Handles need to be updated during animation and applying stuff like hooks,
* but in such situations it's quite difficult to distinguish in which order
- * align handles should be aligned so skip them for now */
+ * align handles should be aligned so skip them for now. */
return;
}
@@ -3427,19 +3348,19 @@ static void calchandlesNurb_intern(Nurb *nu, eBezTriple_Flag handle_sel_flag, bo
prev = bezt + (a - 1);
}
else {
- prev = NULL;
+ prev = nullptr;
}
next = bezt + 1;
while (a--) {
- calchandleNurb_intern(bezt, prev, next, handle_sel_flag, 0, skip_align, 0);
+ calchandleNurb_intern(bezt, prev, next, handle_sel_flag, false, skip_align, 0);
prev = bezt;
if (a == 1) {
if (nu->flagu & CU_NURB_CYCLIC) {
next = nu->bezt;
}
else {
- next = NULL;
+ next = nullptr;
}
}
else {
@@ -3455,7 +3376,8 @@ static void calchandlesNurb_intern(Nurb *nu, eBezTriple_Flag handle_sel_flag, bo
* with easy error checking and de-allocation, and an easy way to add or remove
* arrays that are processed in this way when changing code.
*
- * floats, chars: NULL-terminated arrays of pointers to array pointers that need to be allocated.
+ * floats, chars: null-terminated arrays of pointers to array pointers that need to be
+ * allocated.
*
* Returns: pointer to the buffer that contains all of the arrays.
*/
@@ -3474,10 +3396,10 @@ static void *allocate_arrays(int count, float ***floats, char ***chars, const ch
void *buffer = (float *)MEM_malloc_arrayN(count, (sizeof(float) * num_floats + num_chars), name);
if (!buffer) {
- return NULL;
+ return nullptr;
}
- float *fptr = buffer;
+ float *fptr = (float *)buffer;
for (int i = 0; i < num_floats; i++, fptr += count) {
*floats[i] = fptr;
@@ -3546,9 +3468,9 @@ static bool tridiagonal_solve_with_limits(float *a,
int solve_count)
{
float *a0, *b0, *c0, *d0;
- float **arrays[] = {&a0, &b0, &c0, &d0, NULL};
+ float **arrays[] = {&a0, &b0, &c0, &d0, nullptr};
char *is_locked, *num_unlocks;
- char **flagarrays[] = {&is_locked, &num_unlocks, NULL};
+ char **flagarrays[] = {&is_locked, &num_unlocks, nullptr};
void *tmps = allocate_arrays(solve_count, arrays, flagarrays, "tridiagonal_solve_with_limits");
if (!tmps) {
@@ -3815,7 +3737,7 @@ static void bezier_handle_calc_smooth_fcurve(
BezTriple *bezt, int total, int start, int count, bool cycle)
{
float *dx, *dy, *l, *a, *b, *c, *d, *h, *hmax, *hmin;
- float **arrays[] = {&dx, &dy, &l, &a, &b, &c, &d, &h, &hmax, &hmin, NULL};
+ float **arrays[] = {&dx, &dy, &l, &a, &b, &c, &d, &h, &hmax, &hmin, nullptr};
int solve_count = count;
@@ -3844,7 +3766,7 @@ static void bezier_handle_calc_smooth_fcurve(
/* allocate all */
- void *tmp_buffer = allocate_arrays(count, arrays, NULL, "bezier_calc_smooth_tmp");
+ void *tmp_buffer = allocate_arrays(count, arrays, nullptr, "bezier_calc_smooth_tmp");
if (!tmp_buffer) {
return;
}
@@ -4020,8 +3942,8 @@ void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
}
}
- /* Find continuous subsequences of free auto handles and smooth them, starting at
- * search_base. In cyclic mode these subsequences can span the cycle boundary. */
+ /* Find continuous sub-sequences of free auto handles and smooth them, starting at search_base.
+ * In cyclic mode these sub-sequences can span the cycle boundary. */
int start = search_base, count = 1;
for (int i = 1, j = start + 1; i < total; i++, j++) {
@@ -4046,23 +3968,12 @@ void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
}
}
-/**
- * Recalculate the handles of a nurb bezier-triple. Acts based on handle selection with `SELECT`
- * flag. To use a different flag, use #BKE_nurb_handle_calc_ex().
- */
void BKE_nurb_handle_calc(
BezTriple *bezt, BezTriple *prev, BezTriple *next, const bool is_fcurve, const char smoothing)
{
- calchandleNurb_intern(bezt, prev, next, SELECT, is_fcurve, false, smoothing);
+ calchandleNurb_intern(bezt, prev, next, (eBezTriple_Flag)SELECT, is_fcurve, false, smoothing);
}
-/**
- * Variant of #BKE_nurb_handle_calc() that allows calculating based on a different select flag.
- *
- * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection.
- * Usually #SELECT, but may want to use a different one at times
- * (if caller does not operate on selection).
- */
void BKE_nurb_handle_calc_ex(BezTriple *bezt,
BezTriple *prev,
BezTriple *next,
@@ -4070,12 +3981,13 @@ void BKE_nurb_handle_calc_ex(BezTriple *bezt,
const bool is_fcurve,
const char smoothing)
{
- calchandleNurb_intern(bezt, prev, next, handle_sel_flag, is_fcurve, false, smoothing);
+ calchandleNurb_intern(
+ bezt, prev, next, (eBezTriple_Flag)handle_sel_flag, is_fcurve, false, smoothing);
}
void BKE_nurb_handles_calc(Nurb *nu) /* first, if needed, set handle flags */
{
- calchandlesNurb_intern(nu, SELECT, false);
+ calchandlesNurb_intern(nu, (eBezTriple_Flag)SELECT, false);
}
/**
@@ -4103,14 +4015,12 @@ static void nurb_handles_calc__align_selected(Nurb *nu)
nurbList_handles_swap_select(nu);
}
-/* similar to BKE_nurb_handle_calc but for curves and
- * figures out the previous and next for us */
void BKE_nurb_handle_calc_simple(Nurb *nu, BezTriple *bezt)
{
if (nu->pntsu > 1) {
BezTriple *prev = BKE_nurb_bezt_get_prev(nu, bezt);
BezTriple *next = BKE_nurb_bezt_get_next(nu, bezt);
- BKE_nurb_handle_calc(bezt, prev, next, 0, 0);
+ BKE_nurb_handle_calc(bezt, prev, next, false, 0);
}
}
@@ -4129,19 +4039,6 @@ void BKE_nurb_handle_calc_simple_auto(Nurb *nu, BezTriple *bezt)
}
}
-/**
- * Update selected handle types to ensure valid state, e.g. deduce "Auto" types to concrete ones.
- * Thereby \a sel_flag defines what qualifies as selected.
- * Use when something has changed handle positions.
- *
- * The caller needs to recalculate handles.
- *
- * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
- * but may want to use a different one at times (if caller does not operate on
- * selection).
- * \param use_handle: Check selection state of individual handles, otherwise always update both
- * handles if the key is selected.
- */
void BKE_nurb_bezt_handle_test(BezTriple *bezt,
const eBezTriple_Flag__Alias sel_flag,
const bool use_handle,
@@ -4223,7 +4120,7 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
const float eps = 0.0001f;
const float eps_sq = eps * eps;
- if (nu == NULL || nu->bezt == NULL) {
+ if (nu == nullptr || nu->bezt == nullptr) {
return;
}
@@ -4238,13 +4135,13 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
/* left handle: */
if (flag == 0 || (bezt1->f1 & flag)) {
bezt1->h1 = HD_FREE;
- /* distance too short: vectorhandle */
+ /* Distance too short: vector-handle. */
if (len_squared_v3v3(bezt1->vec[1], bezt0->vec[1]) < eps_sq) {
bezt1->h1 = HD_VECT;
leftsmall = true;
}
else {
- /* aligned handle? */
+ /* Aligned handle? */
if (dist_squared_to_line_v3(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < eps_sq) {
align = true;
bezt1->h1 = HD_ALIGN;
@@ -4258,13 +4155,13 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
/* right handle: */
if (flag == 0 || (bezt1->f3 & flag)) {
bezt1->h2 = HD_FREE;
- /* distance too short: vectorhandle */
+ /* Distance too short: vector-handle. */
if (len_squared_v3v3(bezt1->vec[1], bezt2->vec[1]) < eps_sq) {
bezt1->h2 = HD_VECT;
rightsmall = true;
}
else {
- /* aligned handle? */
+ /* Aligned handle? */
if (align) {
bezt1->h2 = HD_ALIGN;
}
@@ -4305,15 +4202,6 @@ void BKE_nurbList_handles_autocalc(ListBase *editnurb, uint8_t flag)
}
}
-/**
- * \param code:
- * - 1 (#HD_AUTO): set auto-handle.
- * - 2 (#HD_VECT): set vector-handle.
- * - 3 (#HD_ALIGN) it toggle, vector-handles become #HD_FREE.
- *
- * - 5: Set align, like 3 but no toggle.
- * - 6: Clear align (setting #HD_FREE), like 3 but no toggle.
- */
void BKE_nurbList_handles_set(ListBase *editnurb, const char code)
{
BezTriple *bezt;
@@ -4491,9 +4379,6 @@ void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set)
}
}
-/**
- * Set \a flag for every point that already has \a from_flag set.
- */
bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, uint8_t from_flag, uint8_t flag)
{
bool changed = false;
@@ -4608,7 +4493,7 @@ void BKE_nurb_direction_switch(Nurb *nu)
/* and make in increasing order again */
a = KNOTSU(nu);
fp1 = nu->knotsu;
- fp2 = tempf = MEM_malloc_arrayN(a, sizeof(float), "switchdirect");
+ fp2 = tempf = (float *)MEM_malloc_arrayN(a, sizeof(float), "switchdirect");
a--;
fp2[a] = fp1[a];
while (a--) {
@@ -4678,7 +4563,8 @@ void BKE_curve_nurbs_vert_coords_get(const ListBase *lb, float (*vert_coords)[3]
float (*BKE_curve_nurbs_vert_coords_alloc(const ListBase *lb, int *r_vert_len))[3]
{
const int vert_len = BKE_nurbList_verts_count(lb);
- float(*vert_coords)[3] = MEM_malloc_arrayN(vert_len, sizeof(*vert_coords), __func__);
+ float(*vert_coords)[3] = (float(*)[3])MEM_malloc_arrayN(
+ vert_len, sizeof(*vert_coords), __func__);
BKE_curve_nurbs_vert_coords_get(lb, vert_coords, vert_len);
*r_vert_len = vert_len;
return vert_coords;
@@ -4717,7 +4603,7 @@ void BKE_curve_nurbs_vert_coords_apply_with_mat4(ListBase *lb,
BKE_nurb_project_2d(nu);
}
- calchandlesNurb_intern(nu, SELECT, true);
+ calchandlesNurb_intern(nu, (eBezTriple_Flag)SELECT, true);
}
}
@@ -4753,14 +4639,14 @@ void BKE_curve_nurbs_vert_coords_apply(ListBase *lb,
BKE_nurb_project_2d(nu);
}
- calchandlesNurb_intern(nu, SELECT, true);
+ calchandlesNurb_intern(nu, (eBezTriple_Flag)SELECT, true);
}
}
float (*BKE_curve_nurbs_key_vert_coords_alloc(const ListBase *lb, float *key, int *r_vert_len))[3]
{
int vert_len = BKE_nurbList_verts_count(lb);
- float(*cos)[3] = MEM_malloc_arrayN(vert_len, sizeof(*cos), __func__);
+ float(*cos)[3] = (float(*)[3])MEM_malloc_arrayN(vert_len, sizeof(*cos), __func__);
float *co = cos[0];
LISTBASE_FOREACH (const Nurb *, nu, lb) {
@@ -4910,9 +4796,6 @@ bool BKE_nurb_order_clamp_v(struct Nurb *nu)
return changed;
}
-/**
- * \note caller must ensure active vertex remains valid.
- */
bool BKE_nurb_type_convert(Nurb *nu,
const short type,
const bool use_handles,
@@ -4923,7 +4806,7 @@ bool BKE_nurb_type_convert(Nurb *nu,
int a, c, nr;
if (nu->type == CU_POLY) {
- if (type == CU_BEZIER) { /* To Bezier with vecthandles. */
+ if (type == CU_BEZIER) { /* To Bezier with vector-handles. */
nr = nu->pntsu;
bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
nu->bezt = bezt;
@@ -4939,7 +4822,7 @@ bool BKE_nurb_type_convert(Nurb *nu,
bezt++;
}
MEM_freeN(nu->bp);
- nu->bp = NULL;
+ nu->bp = nullptr;
nu->pntsu = nr;
nu->pntsv = 0;
nu->type = CU_BEZIER;
@@ -4961,7 +4844,7 @@ bool BKE_nurb_type_convert(Nurb *nu,
else if (nu->type == CU_BEZIER) { /* Bezier */
if (ELEM(type, CU_POLY, CU_NURBS)) {
nr = use_handles ? (3 * nu->pntsu) : nu->pntsu;
- nu->bp = MEM_calloc_arrayN(nr, sizeof(BPoint), "setsplinetype");
+ nu->bp = (BPoint *)MEM_calloc_arrayN(nr, sizeof(BPoint), "setsplinetype");
a = nu->pntsu;
bezt = nu->bezt;
bp = nu->bp;
@@ -4993,7 +4876,7 @@ bool BKE_nurb_type_convert(Nurb *nu,
bezt++;
}
MEM_freeN(nu->bezt);
- nu->bezt = NULL;
+ nu->bezt = nullptr;
nu->pntsu = nr;
nu->pntsv = 1;
nu->orderu = 4;
@@ -5013,20 +4896,20 @@ bool BKE_nurb_type_convert(Nurb *nu,
if (nu->knotsu) {
MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
}
- nu->knotsu = NULL;
+ nu->knotsu = nullptr;
MEM_SAFE_FREE(nu->knotsv);
}
else if (type == CU_BEZIER) { /* to Bezier */
nr = nu->pntsu / 3;
if (nr < 2) {
- if (r_err_msg != NULL) {
+ if (r_err_msg != nullptr) {
*r_err_msg = "At least 6 points required for conversion";
}
return false; /* conversion impossible */
}
- bezt = MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
+ bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
nu->bezt = bezt;
a = nr;
bp = nu->bp;
@@ -5045,9 +4928,9 @@ bool BKE_nurb_type_convert(Nurb *nu,
bezt++;
}
MEM_freeN(nu->bp);
- nu->bp = NULL;
+ nu->bp = nullptr;
MEM_freeN(nu->knotsu);
- nu->knotsu = NULL;
+ nu->knotsu = nullptr;
nu->pntsu = nr;
nu->type = CU_BEZIER;
}
@@ -5056,7 +4939,6 @@ bool BKE_nurb_type_convert(Nurb *nu,
return true;
}
-/* Get edit nurbs or normal nurbs list */
ListBase *BKE_curve_nurbs_get(Curve *cu)
{
if (cu->editnurb) {
@@ -5077,7 +4959,7 @@ const ListBase *BKE_curve_nurbs_get_for_read(const Curve *cu)
void BKE_curve_nurb_active_set(Curve *cu, const Nurb *nu)
{
- if (nu == NULL) {
+ if (nu == nullptr) {
cu->actnu = CU_ACT_NONE;
}
else {
@@ -5090,14 +4972,13 @@ void BKE_curve_nurb_active_set(Curve *cu, const Nurb *nu)
Nurb *BKE_curve_nurb_active_get(Curve *cu)
{
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- return BLI_findlink(nurbs, cu->actnu);
+ return (Nurb *)BLI_findlink(nurbs, cu->actnu);
}
-/* Get active vert for curve */
void *BKE_curve_vert_active_get(Curve *cu)
{
- Nurb *nu = NULL;
- void *vert = NULL;
+ Nurb *nu = nullptr;
+ void *vert = nullptr;
BKE_curve_nurb_vert_active_get(cu, &nu, &vert);
return vert;
@@ -5114,7 +4995,6 @@ int BKE_curve_nurb_vert_index_get(const Nurb *nu, const void *vert)
return (BPoint *)vert - nu->bp;
}
-/* Set active nurb and active vert for curve */
void BKE_curve_nurb_vert_active_set(Curve *cu, const Nurb *nu, const void *vert)
{
if (nu) {
@@ -5132,15 +5012,14 @@ void BKE_curve_nurb_vert_active_set(Curve *cu, const Nurb *nu, const void *vert)
}
}
-/* Get points to the active nurb and active vert for curve. */
bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert)
{
- Nurb *nu = NULL;
- void *vert = NULL;
+ Nurb *nu = nullptr;
+ void *vert = nullptr;
if (cu->actvert != CU_ACT_NONE) {
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- nu = BLI_findlink(nurbs, cu->actnu);
+ nu = (Nurb *)BLI_findlink(nurbs, cu->actnu);
if (nu) {
if (nu->type == CU_BEZIER) {
@@ -5157,7 +5036,7 @@ bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert)
*r_nu = nu;
*r_vert = vert;
- return (*r_vert != NULL);
+ return (*r_vert != nullptr);
}
void BKE_curve_nurb_vert_active_validate(Curve *cu)
@@ -5167,13 +5046,13 @@ void BKE_curve_nurb_vert_active_validate(Curve *cu)
if (BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) {
if (nu->type == CU_BEZIER) {
- BezTriple *bezt = vert;
+ BezTriple *bezt = (BezTriple *)vert;
if (BEZT_ISSEL_ANY(bezt) == 0) {
cu->actvert = CU_ACT_NONE;
}
}
else {
- BPoint *bp = vert;
+ BPoint *bp = (BPoint *)vert;
if ((bp->f1 & SELECT) == 0) {
cu->actvert = CU_ACT_NONE;
}
@@ -5185,11 +5064,10 @@ void BKE_curve_nurb_vert_active_validate(Curve *cu)
}
}
-/* basic vertex data functions */
bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3])
{
ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
- ListBase temp_nurb_lb = {NULL, NULL};
+ ListBase temp_nurb_lb = {nullptr, nullptr};
const bool is_font = (BLI_listbase_is_empty(nurb_lb)) && (cu->len != 0);
/* For font curves we generate temp list of splines.
*
@@ -5198,7 +5076,7 @@ bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3])
*/
if (is_font) {
nurb_lb = &temp_nurb_lb;
- BKE_vfont_to_curve_ex(NULL, cu, FO_EDIT, nurb_lb, NULL, NULL, NULL, NULL);
+ BKE_vfont_to_curve_ex(nullptr, cu, FO_EDIT, nurb_lb, nullptr, nullptr, nullptr, nullptr);
use_radius = false;
}
/* Do bounding box based on splines. */
@@ -5303,7 +5181,7 @@ void BKE_curve_transform_ex(Curve *cu,
if (do_keys && cu->key) {
LISTBASE_FOREACH (KeyBlock *, kb, &cu->key->block) {
- float *fp = kb->data;
+ float *fp = (float *)kb->data;
int n = kb->totelem;
LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
@@ -5361,7 +5239,7 @@ void BKE_curve_translate(Curve *cu, const float offset[3], const bool do_keys)
if (do_keys && cu->key) {
LISTBASE_FOREACH (KeyBlock *, kb, &cu->key->block) {
- float *fp = kb->data;
+ float *fp = (float *)kb->data;
int n = kb->totelem;
LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
@@ -5513,11 +5391,10 @@ void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int
}
}
else {
- Nurb *nu;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
if (nurbs) {
- for (nu = nurbs->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, nurbs) {
MAT_NR_REMAP(nu->mat_nr);
}
}
@@ -5551,8 +5428,6 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu,
r_rect->ymin = r_rect->ymax - tb->h;
}
-/* This function is almost the same as BKE_fcurve_correct_bezpart(), but doesn't allow as large a
- * tangent. */
void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
{
float h1[2], h2[2], len1, len2, len, fac;
@@ -5609,8 +5484,8 @@ void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve)
}
/* Draw Engine */
-void (*BKE_curve_batch_cache_dirty_tag_cb)(Curve *cu, int mode) = NULL;
-void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = NULL;
+void (*BKE_curve_batch_cache_dirty_tag_cb)(Curve *cu, int mode) = nullptr;
+void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = nullptr;
void BKE_curve_batch_cache_dirty_tag(Curve *cu, int mode)
{
diff --git a/source/blender/blenkernel/intern/curve_bevel.c b/source/blender/blenkernel/intern/curve_bevel.c
index d205d8cca46..18e4ab3ade1 100644
--- a/source/blender/blenkernel/intern/curve_bevel.c
+++ b/source/blender/blenkernel/intern/curve_bevel.c
@@ -64,8 +64,8 @@ static void bevel_quarter_fill(const Curve *curve,
float angle = 0.0f;
const float dangle = (float)M_PI_2 / (curve->bevresol + 1);
for (int i = 0; i < curve->bevresol + 1; i++) {
- quarter_coords_x[i] = (float)(cosf(angle) * (curve->ext2));
- quarter_coords_y[i] = (float)(sinf(angle) * (curve->ext2));
+ quarter_coords_x[i] = (float)(cosf(angle) * (curve->bevel_radius));
+ quarter_coords_y[i] = (float)(sinf(angle) * (curve->bevel_radius));
angle += dangle;
}
}
@@ -76,11 +76,11 @@ static void bevel_quarter_fill(const Curve *curve,
/* If there aren't enough samples, the curveprofile won't
* sample the start vertex, so set it manually instead. */
- quarter_coords_x[0] = curve->ext2;
+ quarter_coords_x[0] = curve->bevel_radius;
quarter_coords_y[0] = 0.0f;
for (int i = 1; i < curve->bevresol + 1; i++) {
- quarter_coords_x[i] = (float)(curve->bevel_profile->segments[i].x * (curve->ext2));
- quarter_coords_y[i] = (float)(curve->bevel_profile->segments[i].y * (curve->ext2));
+ quarter_coords_x[i] = (float)(curve->bevel_profile->segments[i].x * (curve->bevel_radius));
+ quarter_coords_y[i] = (float)(curve->bevel_profile->segments[i].y * (curve->bevel_radius));
}
}
}
@@ -133,13 +133,13 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
/* Add the bottom vertex. */
fp[0] = 0.0f;
fp[1] = 0.0f;
- fp[2] = -cu->ext1 - cu->ext2;
+ fp[2] = -cu->extrude - cu->bevel_radius;
fp += 3;
for (int i = cu->bevresol; i >= 0; i--) {
fp[0] = 0.0f;
fp[1] = quarter_coords_x[i];
- fp[2] = -quarter_coords_y[i] - cu->ext1;
+ fp[2] = -quarter_coords_y[i] - cu->extrude;
fp += 3;
}
}
@@ -147,8 +147,8 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
/* Add the extrusion if we're only building either the back or the front. */
if (use_extrude && ELEM(fill_type, FRONT, BACK)) {
fp[0] = 0.0f;
- fp[1] = cu->ext2;
- fp[2] = (fill_type == FRONT) ? -cu->ext1 : cu->ext1;
+ fp[1] = cu->bevel_radius;
+ fp[2] = (fill_type == FRONT) ? -cu->extrude : cu->extrude;
fp += 3;
}
@@ -159,13 +159,13 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
for (int i = front_start; i < cu->bevresol + 1; i++) {
fp[0] = 0.0f;
fp[1] = quarter_coords_x[i];
- fp[2] = quarter_coords_y[i] + cu->ext1;
+ fp[2] = quarter_coords_y[i] + cu->extrude;
fp += 3;
}
/* Add the top vertex. */
fp[0] = 0.0f;
fp[1] = 0.0f;
- fp[2] = cu->ext1 + cu->ext2;
+ fp[2] = cu->extrude + cu->bevel_radius;
fp += 3;
}
@@ -174,22 +174,22 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
for (int i = cu->bevresol; i > 0; i--) {
fp[0] = 0.0f;
fp[1] = -quarter_coords_x[i];
- fp[2] = quarter_coords_y[i] + cu->ext1;
+ fp[2] = quarter_coords_y[i] + cu->extrude;
fp += 3;
}
if (use_extrude) {
/* Add the extrusion. */
fp[0] = 0.0f;
- fp[1] = -cu->ext2;
- fp[2] = cu->ext1;
+ fp[1] = -cu->bevel_radius;
+ fp[2] = cu->extrude;
fp += 3;
}
for (int i = 0; i < cu->bevresol + 1; i++) {
fp[0] = 0.0f;
fp[1] = -quarter_coords_x[i];
- fp[2] = -quarter_coords_y[i] - cu->ext1;
+ fp[2] = -quarter_coords_y[i] - cu->extrude;
fp += 3;
}
}
@@ -213,8 +213,8 @@ static void curve_bevel_make_full_circle(const Curve *cu, ListBase *disp)
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;
+ fp[1] = (cosf(angle) * (cu->bevel_radius));
+ fp[2] = (sinf(angle) * (cu->bevel_radius)) - cu->extrude;
angle += dangle;
fp += 3;
}
@@ -232,9 +232,9 @@ static void curve_bevel_make_only_extrude(const Curve *cu, ListBase *disp)
float *fp = dl->verts;
fp[0] = fp[1] = 0.0;
- fp[2] = -cu->ext1;
+ fp[2] = -cu->extrude;
fp[3] = fp[4] = 0.0;
- fp[5] = cu->ext1;
+ fp[5] = cu->extrude;
}
static void curve_bevel_make_from_object(const Curve *cu, ListBase *disp)
@@ -247,7 +247,7 @@ static void curve_bevel_make_from_object(const Curve *cu, ListBase *disp)
}
Curve *bevcu = cu->bevobj->data;
- if (bevcu->ext1 == 0.0f && bevcu->ext2 == 0.0f) {
+ if (bevcu->extrude == 0.0f && bevcu->bevel_radius == 0.0f) {
ListBase bevdisp = {NULL, NULL};
float facx = cu->bevobj->scale[0];
float facy = cu->bevobj->scale[1];
@@ -299,8 +299,8 @@ ListBase BKE_curve_bevel_make(const Curve *curve)
}
}
else {
- const bool use_extrude = curve->ext1 != 0.0f;
- const bool use_bevel = curve->ext2 != 0.0f;
+ const bool use_extrude = curve->extrude != 0.0f;
+ const bool use_bevel = curve->bevel_radius != 0.0f;
/* Pass. */
if (use_extrude && !use_bevel) {
curve_bevel_make_only_extrude(curve, &bevel_shape);
diff --git a/source/blender/blenkernel/intern/curve_convert.c b/source/blender/blenkernel/intern/curve_convert.c
index 5bcce9c339e..98a9cbc2bcf 100644
--- a/source/blender/blenkernel/intern/curve_convert.c
+++ b/source/blender/blenkernel/intern/curve_convert.c
@@ -26,9 +26,9 @@
#include "BKE_curve.h"
#include "BKE_displist.h"
-#include "BKE_font.h"
#include "BKE_lib_id.h"
#include "BKE_modifier.h"
+#include "BKE_vfont.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
diff --git a/source/blender/blenkernel/intern/curve_deform.c b/source/blender/blenkernel/intern/curve_deform.c
index 28b7c2dfba0..d754f8cc27d 100644
--- a/source/blender/blenkernel/intern/curve_deform.c
+++ b/source/blender/blenkernel/intern/curve_deform.c
@@ -311,7 +311,7 @@ static void curve_deform_coords_impl(const Object *ob_curve,
} \
((void)0)
- /* already in 'cd.curvespace', prev for loop */
+ /* Already in 'cd.curvespace', previous for loop. */
#define DEFORM_OP_CLAMPED(dvert) \
{ \
const float weight = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dvert, defgrp_index) : \
@@ -369,7 +369,7 @@ static void curve_deform_coords_impl(const Object *ob_curve,
}
for (a = 0; a < vert_coords_len; a++) {
- /* already in 'cd.curvespace', prev for loop */
+ /* Already in 'cd.curvespace', previous for loop. */
calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL);
mul_m4_v3(cd.objectspace, vert_coords[a]);
}
@@ -410,12 +410,6 @@ void BKE_curve_deform_coords_with_editmesh(const Object *ob_curve,
em_target);
}
-/**
- * \param orco: Input vec and orco = local coord in curve space
- * orco is original not-animated or deformed reference point.
- *
- * The result written in vec and r_mat.
- */
void BKE_curve_deform_co(const Object *ob_curve,
const Object *ob_target,
const float orco[3],
diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index 8eec7f5dfab..e2461adaaca 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -50,12 +50,6 @@ blender::MutableSpan<SplinePtr> CurveEval::splines()
return splines_;
}
-/**
- * \return True if the curve contains a spline with the given type.
- *
- * \note If you are looping over all of the splines in the same scope anyway,
- * it's better to avoid calling this function, in case there are many splines.
- */
bool CurveEval::has_spline_with_type(const Spline::Type type) const
{
for (const SplinePtr &spline : this->splines()) {
@@ -72,14 +66,18 @@ void CurveEval::resize(const int size)
attributes.reallocate(size);
}
-/**
- * \warning Call #reallocate on the spline's attributes after adding all splines.
- */
void CurveEval::add_spline(SplinePtr spline)
{
splines_.append(std::move(spline));
}
+void CurveEval::add_splines(MutableSpan<SplinePtr> splines)
+{
+ for (SplinePtr &spline : splines) {
+ this->add_spline(std::move(spline));
+ }
+}
+
void CurveEval::remove_splines(blender::IndexMask mask)
{
for (int i = mask.size() - 1; i >= 0; i--) {
@@ -102,20 +100,37 @@ void CurveEval::transform(const float4x4 &matrix)
}
}
-void CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const
+bool CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const
{
+ bool have_minmax = false;
for (const SplinePtr &spline : this->splines()) {
- spline->bounds_min_max(min, max, use_evaluated);
+ if (spline->size()) {
+ spline->bounds_min_max(min, max, use_evaluated);
+ have_minmax = true;
+ }
}
+
+ return have_minmax;
+}
+
+float CurveEval::total_length() const
+{
+ float length = 0.0f;
+ for (const SplinePtr &spline : this->splines()) {
+ length += spline->length();
+ }
+ return length;
+}
+
+int CurveEval::total_control_point_size() const
+{
+ int count = 0;
+ for (const SplinePtr &spline : this->splines()) {
+ count += spline->size();
+ }
+ return count;
}
-/**
- * Return the start indices for each of the curve spline's control points, if they were part
- * of a flattened array. This can be used to facilitate parallelism by avoiding the need to
- * accumulate an offset while doing more complex calculations.
- *
- * \note The result array is one longer than the spline count; the last element is the total size.
- */
blender::Array<int> CurveEval::control_point_offsets() const
{
Array<int> offsets(splines_.size() + 1);
@@ -128,9 +143,6 @@ blender::Array<int> CurveEval::control_point_offsets() const
return offsets;
}
-/**
- * Exactly like #control_point_offsets, but uses the number of evaluated points instead.
- */
blender::Array<int> CurveEval::evaluated_point_offsets() const
{
Array<int> offsets(splines_.size() + 1);
@@ -143,11 +155,6 @@ blender::Array<int> CurveEval::evaluated_point_offsets() const
return offsets;
}
-/**
- * Return the accumulated length at the start of every spline in the curve.
- *
- * \note The result is one longer than the spline count; the last element is the total length.
- */
blender::Array<float> CurveEval::accumulated_spline_lengths() const
{
Array<float> spline_lengths(splines_.size() + 1);
@@ -160,6 +167,13 @@ blender::Array<float> CurveEval::accumulated_spline_lengths() const
return spline_lengths;
}
+void CurveEval::mark_cache_invalid()
+{
+ for (SplinePtr &spline : splines_) {
+ spline->mark_cache_invalid();
+ }
+}
+
static BezierSpline::HandleType handle_type_from_dna_bezt(const eBezTriple_Handle dna_handle_type)
{
switch (dna_handle_type) {
@@ -218,8 +232,8 @@ static SplinePtr spline_from_dna_bezier(const Nurb &nurb)
Span<const BezTriple> src_points{nurb.bezt, nurb.pntsu};
spline->resize(src_points.size());
MutableSpan<float3> positions = spline->positions();
- MutableSpan<float3> handle_positions_left = spline->handle_positions_left();
- MutableSpan<float3> handle_positions_right = spline->handle_positions_right();
+ MutableSpan<float3> handle_positions_left = spline->handle_positions_left(true);
+ MutableSpan<float3> handle_positions_right = spline->handle_positions_right(true);
MutableSpan<BezierSpline::HandleType> handle_types_left = spline->handle_types_left();
MutableSpan<BezierSpline::HandleType> handle_types_right = spline->handle_types_right();
MutableSpan<float> radii = spline->radii();
@@ -336,12 +350,6 @@ std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve)
return curve_eval_from_dna_curve(dna_curve, *BKE_curve_nurbs_get_for_read(&dna_curve));
}
-/**
- * Check the invariants that curve control point attributes should always uphold, necessary
- * because attributes are stored on splines rather than in a flat array on the curve:
- * - The same set of attributes exists on every spline.
- * - Attributes with the same name have the same type on every spline.
- */
void CurveEval::assert_valid_point_attributes() const
{
#ifdef DEBUG
@@ -349,25 +357,40 @@ void CurveEval::assert_valid_point_attributes() const
return;
}
const int layer_len = splines_.first()->attributes.data.totlayer;
- Map<AttributeIDRef, AttributeMetaData> map;
+
+ Array<AttributeIDRef> ids_in_order(layer_len);
+ Array<AttributeMetaData> meta_data_in_order(layer_len);
+
+ {
+ int i = 0;
+ splines_.first()->attributes.foreach_attribute(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ ids_in_order[i] = attribute_id;
+ meta_data_in_order[i] = meta_data;
+ i++;
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+ }
+
for (const SplinePtr &spline : splines_) {
+ /* All splines should have the same number of attributes. */
BLI_assert(spline->attributes.data.totlayer == layer_len);
+
+ int i = 0;
spline->attributes.foreach_attribute(
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- map.add_or_modify(
- attribute_id,
- [&](AttributeMetaData *map_data) {
- /* All unique attribute names should be added on the first spline. */
- BLI_assert(spline == splines_.first());
- *map_data = meta_data;
- },
- [&](AttributeMetaData *map_data) {
- /* Attributes on different splines should all have the same type. */
- BLI_assert(meta_data == *map_data);
- });
+ /* Attribute names and IDs should have the same order and exist on all splines. */
+ BLI_assert(attribute_id == ids_in_order[i]);
+
+ /* Attributes with the same ID different splines should all have the same type. */
+ BLI_assert(meta_data == meta_data_in_order[i]);
+
+ i++;
return true;
},
ATTR_DOMAIN_POINT);
}
+
#endif
}
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index 5f2f945192c..073d9d18a04 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -32,8 +32,6 @@
using blender::fn::GMutableSpan;
using blender::fn::GSpan;
-using blender::fn::GVArray_Typed;
-using blender::fn::GVArrayPtr;
namespace blender::bke {
@@ -58,9 +56,8 @@ static void vert_extrude_to_mesh_data(const Spline &spline,
const int vert_offset,
const int edge_offset)
{
- Span<float3> positions = spline.evaluated_positions();
-
- for (const int i : IndexRange(positions.size() - 1)) {
+ const int eval_size = spline.evaluated_points_size();
+ for (const int i : IndexRange(eval_size - 1)) {
MEdge &edge = r_edges[edge_offset + i];
edge.v1 = vert_offset + i;
edge.v2 = vert_offset + i + 1;
@@ -70,13 +67,21 @@ static void vert_extrude_to_mesh_data(const Spline &spline,
if (spline.is_cyclic() && spline.evaluated_edges_size() > 1) {
MEdge &edge = r_edges[edge_offset + spline.evaluated_edges_size() - 1];
edge.v1 = vert_offset;
- edge.v2 = vert_offset + positions.size() - 1;
+ edge.v2 = vert_offset + eval_size - 1;
edge.flag = ME_LOOSEEDGE;
}
- for (const int i : positions.index_range()) {
+ Span<float3> positions = spline.evaluated_positions();
+ Span<float3> tangents = spline.evaluated_tangents();
+ Span<float3> normals = spline.evaluated_normals();
+ VArray<float> radii = spline.interpolate_to_evaluated(spline.radii());
+ for (const int i : IndexRange(eval_size)) {
+ float4x4 point_matrix = float4x4::from_normalized_axis_data(
+ positions[i], normals[i], tangents[i]);
+ point_matrix.apply_scale(radii[i]);
+
MVert &vert = r_verts[vert_offset + i];
- copy_v3_v3(vert.co, positions[i] + profile_vert);
+ copy_v3_v3(vert.co, point_matrix * profile_vert);
}
}
@@ -88,6 +93,7 @@ static void mark_edges_sharp(MutableSpan<MEdge> edges)
}
static void spline_extrude_to_mesh_data(const ResultInfo &info,
+ const bool fill_caps,
MutableSpan<MVert> r_verts,
MutableSpan<MEdge> r_edges,
MutableSpan<MLoop> r_loops,
@@ -180,13 +186,46 @@ static void spline_extrude_to_mesh_data(const ResultInfo &info,
}
}
+ if (fill_caps && profile.is_cyclic()) {
+ const int poly_size = info.spline_edge_len * info.profile_edge_len;
+ const int cap_loop_offset = info.loop_offset + poly_size * 4;
+ const int cap_poly_offset = info.poly_offset + poly_size;
+
+ MPoly &poly_start = r_polys[cap_poly_offset];
+ poly_start.loopstart = cap_loop_offset;
+ poly_start.totloop = info.profile_edge_len;
+ MPoly &poly_end = r_polys[cap_poly_offset + 1];
+ poly_end.loopstart = cap_loop_offset + info.profile_edge_len;
+ poly_end.totloop = info.profile_edge_len;
+
+ const int last_ring_index = info.spline_vert_len - 1;
+ const int last_ring_vert_offset = info.vert_offset + info.profile_vert_len * last_ring_index;
+ const int last_ring_edge_offset = profile_edges_start +
+ info.profile_edge_len * last_ring_index;
+
+ for (const int i : IndexRange(info.profile_edge_len)) {
+ const int i_inv = info.profile_edge_len - i - 1;
+ MLoop &loop_start = r_loops[cap_loop_offset + i];
+ loop_start.v = info.vert_offset + i_inv;
+ loop_start.e = profile_edges_start + ((i == (info.profile_edge_len - 1)) ?
+ (info.profile_edge_len - 1) :
+ (i_inv - 1));
+ MLoop &loop_end = r_loops[cap_loop_offset + info.profile_edge_len + i];
+ loop_end.v = last_ring_vert_offset + i;
+ loop_end.e = last_ring_edge_offset + i;
+ }
+
+ mark_edges_sharp(r_edges.slice(profile_edges_start, info.profile_edge_len));
+ mark_edges_sharp(r_edges.slice(last_ring_edge_offset, info.profile_edge_len));
+ }
+
/* Calculate the positions of each profile ring profile along the spline. */
Span<float3> positions = spline.evaluated_positions();
Span<float3> tangents = spline.evaluated_tangents();
Span<float3> normals = spline.evaluated_normals();
Span<float3> profile_positions = profile.evaluated_positions();
- GVArray_Typed<float> radii = spline.interpolate_to_evaluated(spline.radii());
+ VArray<float> radii = spline.interpolate_to_evaluated(spline.radii());
for (const int i_ring : IndexRange(info.spline_vert_len)) {
float4x4 point_matrix = float4x4::from_normalized_axis_data(
positions[i_ring], normals[i_ring], tangents[i_ring]);
@@ -226,14 +265,22 @@ static inline int spline_extrude_edge_size(const Spline &curve, const Spline &pr
curve.evaluated_edges_size() * profile.evaluated_points_size();
}
-static inline int spline_extrude_loop_size(const Spline &curve, const Spline &profile)
+static inline int spline_extrude_loop_size(const Spline &curve,
+ const Spline &profile,
+ const bool fill_caps)
{
- return curve.evaluated_edges_size() * profile.evaluated_edges_size() * 4;
+ const int tube = curve.evaluated_edges_size() * profile.evaluated_edges_size() * 4;
+ const int caps = (fill_caps && profile.is_cyclic()) ? profile.evaluated_edges_size() * 2 : 0;
+ return tube + caps;
}
-static inline int spline_extrude_poly_size(const Spline &curve, const Spline &profile)
+static inline int spline_extrude_poly_size(const Spline &curve,
+ const Spline &profile,
+ const bool fill_caps)
{
- return curve.evaluated_edges_size() * profile.evaluated_edges_size();
+ const int tube = curve.evaluated_edges_size() * profile.evaluated_edges_size();
+ const int caps = (fill_caps && profile.is_cyclic()) ? 2 : 0;
+ return tube + caps;
}
struct ResultOffsets {
@@ -242,7 +289,9 @@ struct ResultOffsets {
Array<int> loop;
Array<int> poly;
};
-static ResultOffsets calculate_result_offsets(Span<SplinePtr> profiles, Span<SplinePtr> curves)
+static ResultOffsets calculate_result_offsets(Span<SplinePtr> profiles,
+ Span<SplinePtr> curves,
+ const bool fill_caps)
{
const int total = profiles.size() * curves.size();
Array<int> vert(total + 1);
@@ -263,8 +312,8 @@ static ResultOffsets calculate_result_offsets(Span<SplinePtr> profiles, Span<Spl
poly[mesh_index] = poly_offset;
vert_offset += spline_extrude_vert_size(*curves[i_spline], *profiles[i_profile]);
edge_offset += spline_extrude_edge_size(*curves[i_spline], *profiles[i_profile]);
- loop_offset += spline_extrude_loop_size(*curves[i_spline], *profiles[i_profile]);
- poly_offset += spline_extrude_poly_size(*curves[i_spline], *profiles[i_profile]);
+ loop_offset += spline_extrude_loop_size(*curves[i_spline], *profiles[i_profile], fill_caps);
+ poly_offset += spline_extrude_poly_size(*curves[i_spline], *profiles[i_profile], fill_caps);
mesh_index++;
}
}
@@ -352,10 +401,8 @@ struct ResultAttributes {
};
static ResultAttributes create_result_attributes(const CurveEval &curve,
const CurveEval &profile,
- Mesh &mesh)
+ MeshComponent &mesh_component)
{
- MeshComponent mesh_component;
- mesh_component.replace(&mesh, GeometryOwnershipType::Editable);
Set<AttributeIDRef> curve_attributes;
/* In order to prefer attributes on the main curve input when there are name collisions, first
@@ -444,8 +491,8 @@ static void copy_curve_point_attribute_to_mesh(const GSpan src,
const ResultInfo &info,
ResultAttributeData &dst)
{
- GVArrayPtr interpolated_gvarray = info.spline.interpolate_to_evaluated(src);
- GSpan interpolated = interpolated_gvarray->get_internal_span();
+ GVArray interpolated_gvarray = info.spline.interpolate_to_evaluated(src);
+ GSpan interpolated = interpolated_gvarray.get_internal_span();
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
@@ -510,8 +557,8 @@ static void copy_profile_point_attribute_to_mesh(const GSpan src,
const ResultInfo &info,
ResultAttributeData &dst)
{
- GVArrayPtr interpolated_gvarray = info.profile.interpolate_to_evaluated(src);
- GSpan interpolated = interpolated_gvarray->get_internal_span();
+ GVArray interpolated_gvarray = info.profile.interpolate_to_evaluated(src);
+ GSpan interpolated = interpolated_gvarray.get_internal_span();
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
@@ -642,22 +689,12 @@ static void copy_spline_domain_attributes_to_mesh(const CurveEval &curve,
}
}
-/**
- * Extrude all splines in the profile curve along the path of every spline in the curve input.
- * Transfer curve attributes to the mesh.
- *
- * \note Normal calculation is by far the slowest part of calculations relating to the result mesh.
- * Although it would be a sensible decision to use the better topology information available while
- * generating the mesh to also generate the normals, that work may wasted if the output mesh is
- * changed anyway in a way that affects the normals. So currently this code uses the safer /
- * simpler solution of deferring normal calculation to the rest of Blender.
- */
-Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile)
+Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile, const bool fill_caps)
{
Span<SplinePtr> profiles = profile.splines();
Span<SplinePtr> curves = curve.splines();
- const ResultOffsets offsets = calculate_result_offsets(profiles, curves);
+ const ResultOffsets offsets = calculate_result_offsets(profiles, curves, fill_caps);
if (offsets.vert.last() == 0) {
return nullptr;
}
@@ -669,7 +706,11 @@ Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile)
mesh->smoothresh = DEG2RADF(180.0f);
BKE_mesh_normals_tag_dirty(mesh);
- ResultAttributes attributes = create_result_attributes(curve, profile, *mesh);
+ /* Create the mesh component for retrieving attributes at this scope, since output attributes
+ * can keep a reference to the component for updating after retrieving write access. */
+ MeshComponent mesh_component;
+ mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ ResultAttributes attributes = create_result_attributes(curve, profile, mesh_component);
threading::parallel_for(curves.index_range(), 128, [&](IndexRange curves_range) {
for (const int i_spline : curves_range) {
@@ -696,6 +737,7 @@ Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile)
};
spline_extrude_to_mesh_data(info,
+ fill_caps,
{mesh->mvert, mesh->totvert},
{mesh->medge, mesh->totedge},
{mesh->mloop, mesh->totloop},
@@ -720,20 +762,19 @@ static CurveEval get_curve_single_vert()
{
CurveEval curve;
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- spline->add_point(float3(0), 0, 0.0f);
+ spline->resize(1.0f);
+ spline->positions().fill(float3(0));
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
curve.add_spline(std::move(spline));
return curve;
}
-/**
- * Create a loose-edge mesh based on the evaluated path of the curve's splines.
- * Transfer curve attributes to the mesh.
- */
Mesh *curve_to_wire_mesh(const CurveEval &curve)
{
static const CurveEval vert_curve = get_curve_single_vert();
- return curve_to_mesh_sweep(curve, vert_curve);
+ return curve_to_mesh_sweep(curve, vert_curve, false);
}
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/curveprofile.c b/source/blender/blenkernel/intern/curveprofile.cc
index 00cdc7b3031..8f387be41d3 100644
--- a/source/blender/blenkernel/intern/curveprofile.c
+++ b/source/blender/blenkernel/intern/curveprofile.cc
@@ -21,28 +21,41 @@
* \ingroup bke
*/
-#include <float.h>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
+#include <algorithm>
#include "MEM_guardedalloc.h"
#include "DNA_curve_types.h"
#include "DNA_curveprofile_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_task.h"
-#include "BLI_threads.h"
+#include "BLI_math_vector.h"
+#include "BLI_rect.h"
#include "BLI_utildefines.h"
#include "BKE_curve.h"
#include "BKE_curveprofile.h"
-#include "BKE_fcurve.h"
#include "BLO_read_write.h"
+/** Number of points in high resolution table is dynamic up to a maximum. */
+#define PROF_TABLE_MAX 512
+
+/* -------------------------------------------------------------------- */
+/** \name Data Handling
+ * \{ */
+
+struct CurveProfile *BKE_curveprofile_add(eCurveProfilePresets preset)
+{
+ CurveProfile *profile = MEM_cnew<CurveProfile>(__func__);
+
+ BKE_curveprofile_set_defaults(profile);
+ profile->preset = preset;
+ BKE_curveprofile_reset(profile);
+ BKE_curveprofile_update(profile, 0);
+
+ return profile;
+}
+
void BKE_curveprofile_free_data(CurveProfile *profile)
{
MEM_SAFE_FREE(profile->path);
@@ -62,9 +75,9 @@ void BKE_curveprofile_copy_data(CurveProfile *target, const CurveProfile *profil
{
*target = *profile;
- target->path = MEM_dupallocN(profile->path);
- target->table = MEM_dupallocN(profile->table);
- target->segments = MEM_dupallocN(profile->segments);
+ target->path = (CurveProfilePoint *)MEM_dupallocN(profile->path);
+ target->table = (CurveProfilePoint *)MEM_dupallocN(profile->table);
+ target->segments = (CurveProfilePoint *)MEM_dupallocN(profile->segments);
/* Update the reference the points have to the profile. */
for (int i = 0; i < target->path_len; i++) {
@@ -75,21 +88,39 @@ void BKE_curveprofile_copy_data(CurveProfile *target, const CurveProfile *profil
CurveProfile *BKE_curveprofile_copy(const CurveProfile *profile)
{
if (profile) {
- CurveProfile *new_prdgt = MEM_dupallocN(profile);
+ CurveProfile *new_prdgt = (CurveProfile *)MEM_dupallocN(profile);
BKE_curveprofile_copy_data(new_prdgt, profile);
return new_prdgt;
}
- return NULL;
+ return nullptr;
}
-/**
- * Move a point's handle, accounting for the alignment of handles with the #HD_ALIGN type.
- *
- * \param handle_1: Whether to move the 1st or 2nd control point.
- * \param delta: The *relative* change in the handle's position.
- * \note Requires #BKE_curveprofile_update call after.
- * \return Whether the handle moved from its start position.
- */
+void BKE_curveprofile_blend_write(struct BlendWriter *writer, const struct CurveProfile *profile)
+{
+ BLO_write_struct(writer, CurveProfile, profile);
+ BLO_write_struct_array(writer, CurveProfilePoint, profile->path_len, profile->path);
+}
+
+void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurveProfile *profile)
+{
+ BLO_read_data_address(reader, &profile->path);
+ profile->table = nullptr;
+ profile->segments = nullptr;
+
+ /* Reset the points' pointers to the profile. */
+ for (int i = 0; i < profile->path_len; i++) {
+ profile->path[i].profile = profile;
+ }
+
+ BKE_curveprofile_init(profile, profile->segments_len);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Editing
+ * \{ */
+
bool BKE_curveprofile_move_handle(struct CurveProfilePoint *point,
const bool handle_1,
const bool snap,
@@ -130,14 +161,6 @@ bool BKE_curveprofile_move_handle(struct CurveProfilePoint *point,
return false;
}
-/**
- * Moves a control point, accounting for clipping and snapping, and moving free handles.
- *
- * \param snap: Whether to snap the point to the grid
- * \param delta: The *relative* change of the point's location.
- * \return Whether the point moved from its start position.
- * \note Requires #BKE_curveprofile_update call after.
- */
bool BKE_curveprofile_move_point(struct CurveProfile *profile,
struct CurveProfilePoint *point,
const bool snap,
@@ -185,10 +208,6 @@ bool BKE_curveprofile_move_point(struct CurveProfile *profile,
return false;
}
-/**
- * Removes a specific point from the path of control points.
- * \note Requires #BKE_curveprofile_update call after.
- */
bool BKE_curveprofile_remove_point(CurveProfile *profile, CurveProfilePoint *point)
{
/* Must have 2 points minimum. */
@@ -201,8 +220,8 @@ bool BKE_curveprofile_remove_point(CurveProfile *profile, CurveProfilePoint *poi
return false;
}
- CurveProfilePoint *new_path = MEM_mallocN(sizeof(CurveProfilePoint) * profile->path_len,
- "profile path");
+ CurveProfilePoint *new_path = (CurveProfilePoint *)MEM_mallocN(
+ sizeof(CurveProfilePoint) * profile->path_len, __func__);
int i_delete = (int)(point - profile->path);
BLI_assert(i_delete > 0);
@@ -219,18 +238,11 @@ bool BKE_curveprofile_remove_point(CurveProfile *profile, CurveProfilePoint *poi
return true;
}
-/**
- * Removes every point in the widget with the supplied flag set, except for the first and last.
- *
- * \param flag: #CurveProfilePoint.flag.
- *
- * \note Requires #BKE_curveprofile_update call after.
- */
void BKE_curveprofile_remove_by_flag(CurveProfile *profile, const short flag)
{
/* Copy every point without the flag into the new path. */
- CurveProfilePoint *new_path = MEM_mallocN(sizeof(CurveProfilePoint) * profile->path_len,
- "profile path");
+ CurveProfilePoint *new_path = (CurveProfilePoint *)MEM_mallocN(
+ sizeof(CurveProfilePoint) * profile->path_len, __func__);
/* Build the new list without any of the points with the flag. Keep the first and last points. */
int i_new = 1;
@@ -265,20 +277,13 @@ static void point_init(CurveProfilePoint *point, float x, float y, short flag, c
point->h2 = h2;
}
-/**
- * Adds a new point at the specified location. The choice for which points to place the new vertex
- * between is made by checking which control point line segment is closest to the new point and
- * placing the new vertex in between that segment's points.
- *
- * \note Requires #BKE_curveprofile_update call after.
- */
CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float y)
{
const float new_loc[2] = {x, y};
/* Don't add more control points than the maximum size of the higher resolution table. */
if (profile->path_len == PROF_TABLE_MAX - 1) {
- return NULL;
+ return nullptr;
}
/* Find the index at the line segment that's closest to the new position. */
@@ -297,9 +302,9 @@ CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float
/* Insert the new point at the location we found and copy all of the old points in as well. */
profile->path_len++;
- CurveProfilePoint *new_path = MEM_mallocN(sizeof(CurveProfilePoint) * profile->path_len,
- "profile path");
- CurveProfilePoint *new_pt = NULL;
+ CurveProfilePoint *new_path = (CurveProfilePoint *)MEM_mallocN(
+ sizeof(CurveProfilePoint) * profile->path_len, __func__);
+ CurveProfilePoint *new_pt = nullptr;
for (int i_new = 0, i_old = 0; i_new < profile->path_len; i_new++) {
if (i_new != i_insert) {
/* Insert old points. */
@@ -327,11 +332,6 @@ CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float
return new_pt;
}
-/**
- * Sets the handle type of the selected control points.
- * \param type_1, type_2: Handle type for the first handle. HD_VECT, HD_AUTO, HD_FREE, or HD_ALIGN.
- * \note Requires #BKE_curveprofile_update call after.
- */
void BKE_curveprofile_selected_handle_set(CurveProfile *profile, int type_1, int type_2)
{
for (int i = 0; i < profile->path_len; i++) {
@@ -341,7 +341,7 @@ void BKE_curveprofile_selected_handle_set(CurveProfile *profile, int type_1, int
if (type_1 == HD_ALIGN && type_2 == HD_ALIGN) {
/* Align the handles. */
- BKE_curveprofile_move_handle(&profile->path[i], true, false, NULL);
+ BKE_curveprofile_move_handle(&profile->path[i], true, false, nullptr);
}
}
}
@@ -354,19 +354,14 @@ static CurveProfilePoint mirror_point(const CurveProfilePoint *point)
return new_point;
}
-/**
- * Flips the profile across the diagonal so that its orientation is reversed.
- *
- * \note Requires #BKE_curveprofile_update call after.
- */
void BKE_curveprofile_reverse(CurveProfile *profile)
{
/* When there are only two points, reversing shouldn't do anything. */
if (profile->path_len == 2) {
return;
}
- CurveProfilePoint *new_path = MEM_mallocN(sizeof(CurveProfilePoint) * profile->path_len,
- "profile path");
+ CurveProfilePoint *new_path = (CurveProfilePoint *)MEM_mallocN(
+ sizeof(CurveProfilePoint) * profile->path_len, __func__);
/* Mirror the new points across the y = x line */
for (int i = 0; i < profile->path_len; i++) {
int i_reversed = profile->path_len - i - 1;
@@ -435,24 +430,16 @@ static void curveprofile_build_steps(CurveProfile *profile)
}
}
-/**
- * Reset the view to the clipping rectangle.
- */
void BKE_curveprofile_reset_view(CurveProfile *profile)
{
profile->view_rect = profile->clip_rect;
}
-/**
- * Resets the profile to the current preset.
- *
- * \note Requires #BKE_curveprofile_update call after.
- */
void BKE_curveprofile_reset(CurveProfile *profile)
{
MEM_SAFE_FREE(profile->path);
- eCurveProfilePresets preset = profile->preset;
+ eCurveProfilePresets preset = static_cast<eCurveProfilePresets>(profile->preset);
switch (preset) {
case PROF_PRESET_LINE:
profile->path_len = 2;
@@ -485,7 +472,8 @@ void BKE_curveprofile_reset(CurveProfile *profile)
break;
}
- profile->path = MEM_callocN(sizeof(CurveProfilePoint) * profile->path_len, "profile path");
+ profile->path = (CurveProfilePoint *)MEM_callocN(sizeof(CurveProfilePoint) * profile->path_len,
+ __func__);
switch (preset) {
case PROF_PRESET_LINE:
@@ -536,7 +524,22 @@ void BKE_curveprofile_reset(CurveProfile *profile)
}
MEM_SAFE_FREE(profile->table);
- profile->table = NULL;
+ profile->table = nullptr;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sampling and Evaluation
+ * \{ */
+
+int BKE_curveprofile_table_size(const CurveProfile *profile)
+{
+ /** Number of table points per control point. */
+ const int resolution = 16;
+
+ /* Make sure there is always one sample, even if there are no control points. */
+ return std::clamp((profile->path_len - 1) * resolution + 1, 1, PROF_TABLE_MAX);
}
/**
@@ -564,7 +567,7 @@ static void point_calculate_handle(CurveProfilePoint *point,
float pt[2];
const float *prev_loc, *next_loc;
- if (prev == NULL) {
+ if (prev == nullptr) {
next_loc = &next->x;
pt[0] = 2.0f * point_loc[0] - next_loc[0];
pt[1] = 2.0f * point_loc[1] - next_loc[1];
@@ -574,7 +577,7 @@ static void point_calculate_handle(CurveProfilePoint *point,
prev_loc = &prev->x;
}
- if (next == NULL) {
+ if (next == nullptr) {
prev_loc = &prev->x;
pt[0] = 2.0f * point_loc[0] - prev_loc[0];
pt[1] = 2.0f * point_loc[1] - prev_loc[1];
@@ -625,15 +628,15 @@ static void point_calculate_handle(CurveProfilePoint *point,
static void calculate_path_handles(CurveProfilePoint *path, int path_len)
{
- point_calculate_handle(&path[0], NULL, &path[1]);
+ point_calculate_handle(&path[0], nullptr, &path[1]);
for (int i = 1; i < path_len - 1; i++) {
point_calculate_handle(&path[i], &path[i - 1], &path[i + 1]);
}
- point_calculate_handle(&path[path_len - 1], &path[path_len - 2], NULL);
+ point_calculate_handle(&path[path_len - 1], &path[path_len - 2], nullptr);
}
/**
- * Helper function for 'BKE_curveprofile_create_samples.' Calculates the angle between the
+ * Helper function for #create_samples. Calculates the angle between the
* handles on the inside of the edge starting at index i. A larger angle means the edge is
* more curved.
* \param i_edge: The start index of the edge to calculate the angle for.
@@ -651,15 +654,15 @@ static float bezt_edge_handle_angle(const CurveProfilePoint *path, int i_edge)
}
/** Struct to sort curvature of control point edges. */
-typedef struct {
+struct CurvatureSortPoint {
/** The index of the corresponding profile point. */
int point_index;
/** The curvature of the edge with the above index. */
float point_curvature;
-} CurvatureSortPoint;
+};
/**
- * Helper function for 'BKE_curveprofile_create_samples' for sorting edges based on curvature.
+ * Helper function for #create_samples for sorting edges based on curvature.
*/
static int sort_points_curvature(const void *in_a, const void *in_b)
{
@@ -686,10 +689,10 @@ static int sort_points_curvature(const void *in_a, const void *in_b)
* n_segments. Fill the array with the sampled locations and if the point corresponds to a
* control point, its handle type.
*/
-void BKE_curveprofile_create_samples(CurveProfile *profile,
- int n_segments,
- bool sample_straight_edges,
- CurveProfilePoint *r_samples)
+static void create_samples(CurveProfile *profile,
+ int n_segments,
+ bool sample_straight_edges,
+ CurveProfilePoint *r_samples)
{
CurveProfilePoint *path = profile->path;
int totpoints = profile->path_len;
@@ -700,8 +703,8 @@ void BKE_curveprofile_create_samples(CurveProfile *profile,
calculate_path_handles(path, totpoints);
/* Create a list of edge indices with the most curved at the start, least curved at the end. */
- CurvatureSortPoint *curve_sorted = MEM_callocN(sizeof(CurvatureSortPoint) * totedges,
- "curve sorted");
+ CurvatureSortPoint *curve_sorted = (CurvatureSortPoint *)MEM_callocN(
+ sizeof(CurvatureSortPoint) * totedges, __func__);
for (int i = 0; i < totedges; i++) {
curve_sorted[i].point_index = i;
/* Calculate the curvature of each edge once for use when sorting for curvature. */
@@ -710,7 +713,7 @@ void BKE_curveprofile_create_samples(CurveProfile *profile,
qsort(curve_sorted, totedges, sizeof(CurvatureSortPoint), sort_points_curvature);
/* Assign the number of sampled points for each edge. */
- int16_t *n_samples = MEM_callocN(sizeof(int16_t) * totedges, "samples numbers");
+ int16_t *n_samples = (int16_t *)MEM_callocN(sizeof(int16_t) * totedges, "samples numbers");
int n_added = 0;
int n_left;
if (n_segments >= totedges) {
@@ -812,55 +815,6 @@ void BKE_curveprofile_create_samples(CurveProfile *profile,
MEM_freeN(n_samples);
}
-/**
- * Creates a higher resolution table by sampling the curved points.
- * This table is used for display and evenly spaced evaluation.
- */
-static void curveprofile_make_table(CurveProfile *profile)
-{
- int n_samples = PROF_TABLE_LEN(profile->path_len);
- CurveProfilePoint *new_table = MEM_callocN(sizeof(CurveProfilePoint) * (n_samples + 1),
- __func__);
-
- BKE_curveprofile_create_samples(profile, n_samples - 1, false, new_table);
- /* Manually add last point at the end of the profile */
- new_table[n_samples - 1].x = 0.0f;
- new_table[n_samples - 1].y = 1.0f;
-
- MEM_SAFE_FREE(profile->table);
- profile->table = new_table;
-}
-
-/**
- * Creates the table of points used for displaying a preview of the sampled segment locations on
- * the widget itself.
- */
-static void curveprofile_make_segments_table(CurveProfile *profile)
-{
- int n_samples = profile->segments_len;
- if (n_samples <= 0) {
- return;
- }
- CurveProfilePoint *new_table = MEM_callocN(sizeof(CurveProfilePoint) * (n_samples + 1),
- __func__);
-
- if (profile->flag & PROF_SAMPLE_EVEN_LENGTHS) {
- /* Even length sampling incompatible with only straight edge sampling for now. */
- BKE_curveprofile_create_samples_even_spacing(profile, n_samples, new_table);
- }
- else {
- BKE_curveprofile_create_samples(
- profile, n_samples, profile->flag & PROF_SAMPLE_STRAIGHT_EDGES, new_table);
- }
-
- MEM_SAFE_FREE(profile->segments);
- profile->segments = new_table;
-}
-
-/**
- * Sets the default settings and clip range for the profile widget.
- * Does not generate either table.
- */
void BKE_curveprofile_set_defaults(CurveProfile *profile)
{
profile->flag = PROF_USE_CLIP;
@@ -869,7 +823,7 @@ void BKE_curveprofile_set_defaults(CurveProfile *profile)
profile->clip_rect = profile->view_rect;
profile->path_len = 2;
- profile->path = MEM_callocN(2 * sizeof(CurveProfilePoint), "path points");
+ profile->path = (CurveProfilePoint *)MEM_callocN(2 * sizeof(CurveProfilePoint), __func__);
profile->path[0].x = 1.0f;
profile->path[0].y = 0.0f;
@@ -881,88 +835,6 @@ void BKE_curveprofile_set_defaults(CurveProfile *profile)
profile->changed_timestamp = 0;
}
-/**
- * Returns a pointer to a newly allocated curve profile, using the given preset.
- */
-struct CurveProfile *BKE_curveprofile_add(eCurveProfilePresets preset)
-{
- CurveProfile *profile = MEM_callocN(sizeof(CurveProfile), "curve profile");
-
- BKE_curveprofile_set_defaults(profile);
- profile->preset = preset;
- BKE_curveprofile_reset(profile);
- curveprofile_make_table(profile);
-
- return profile;
-}
-
-/**
- * Should be called after the widget is changed. Does profile and remove double checks and more
- * importantly, recreates the display / evaluation and segments tables.
- * \param update_flags: Bitfield with fields defined in header file. Controls removing doubles and
- * clipping.
- */
-void BKE_curveprofile_update(CurveProfile *profile, const int update_flags)
-{
- CurveProfilePoint *points = profile->path;
- rctf *clipr = &profile->clip_rect;
-
- profile->changed_timestamp++;
-
- /* Clamp with the clipping rect in case something got past. */
- if (profile->flag & PROF_USE_CLIP) {
- /* Move points inside the clip rectangle. */
- if (update_flags & PROF_UPDATE_CLIP) {
- for (int i = 0; i < profile->path_len; i++) {
- points[i].x = clamp_f(points[i].x, clipr->xmin, clipr->xmax);
- points[i].y = clamp_f(points[i].y, clipr->ymin, clipr->ymax);
-
- /* Extra sanity assert to make sure the points have the right profile pointer. */
- BLI_assert(points[i].profile == profile);
- }
- }
- /* Ensure zoom-level respects clipping. */
- if (BLI_rctf_size_x(&profile->view_rect) > BLI_rctf_size_x(&profile->clip_rect)) {
- profile->view_rect.xmin = profile->clip_rect.xmin;
- profile->view_rect.xmax = profile->clip_rect.xmax;
- }
- if (BLI_rctf_size_y(&profile->view_rect) > BLI_rctf_size_y(&profile->clip_rect)) {
- profile->view_rect.ymin = profile->clip_rect.ymin;
- profile->view_rect.ymax = profile->clip_rect.ymax;
- }
- }
-
- /* Remove doubles with a threshold set at 1% of default range. */
- float thresh = pow2f(0.01f * BLI_rctf_size_x(clipr));
- if (update_flags & PROF_UPDATE_REMOVE_DOUBLES && profile->path_len > 2) {
- for (int i = 0; i < profile->path_len - 1; i++) {
- if (len_squared_v2v2(&points[i].x, &points[i + 1].x) < thresh) {
- if (i == 0) {
- BKE_curveprofile_remove_point(profile, &points[1]);
- }
- else {
- BKE_curveprofile_remove_point(profile, &points[i]);
- }
- break; /* Assumes 1 deletion per update call is ok. */
- }
- }
- }
-
- /* Create the high resolution table for drawing and some evaluation functions. */
- curveprofile_make_table(profile);
-
- /* Store a table of samples for the segment locations for a preview and the table's user. */
- if (profile->segments_len > 0) {
- curveprofile_make_segments_table(profile);
- }
-}
-
-/**
- * Refreshes the higher resolution table sampled from the input points. A call to this or
- * #BKE_curveprofile_update is needed before evaluation functions that use the table.
- * Also sets the number of segments used for the display preview of the locations
- * of the sampled points.
- */
void BKE_curveprofile_init(CurveProfile *profile, short segments_len)
{
if (segments_len != profile->segments_len) {
@@ -982,7 +854,7 @@ void BKE_curveprofile_init(CurveProfile *profile, short segments_len)
*/
static float curveprofile_distance_to_next_table_point(const CurveProfile *profile, int i)
{
- BLI_assert(i < PROF_TABLE_LEN(profile->path_len));
+ BLI_assert(i < BKE_curveprofile_table_size(profile));
return len_v2v2(&profile->table[i].x, &profile->table[i + 1].x);
}
@@ -992,10 +864,10 @@ static float curveprofile_distance_to_next_table_point(const CurveProfile *profi
*
* \note Requires #BKE_curveprofile_init or #BKE_curveprofile_update call before to fill table.
*/
-float BKE_curveprofile_total_length(const CurveProfile *profile)
+static float curveprofile_total_length(const CurveProfile *profile)
{
float total_length = 0;
- for (int i = 0; i < PROF_TABLE_LEN(profile->path_len) - 1; i++) {
+ for (int i = 0; i < BKE_curveprofile_table_size(profile) - 1; i++) {
total_length += len_v2v2(&profile->table[i].x, &profile->table[i + 1].x);
}
return total_length;
@@ -1009,11 +881,11 @@ float BKE_curveprofile_total_length(const CurveProfile *profile)
* \note Working, but would conflict with "Sample Straight Edges" option, so this is unused for
* now.
*/
-void BKE_curveprofile_create_samples_even_spacing(CurveProfile *profile,
- int n_segments,
- CurveProfilePoint *r_samples)
+static void create_samples_even_spacing(CurveProfile *profile,
+ int n_segments,
+ CurveProfilePoint *r_samples)
{
- const float total_length = BKE_curveprofile_total_length(profile);
+ const float total_length = curveprofile_total_length(profile);
const float segment_length = total_length / n_segments;
float distance_to_next_table_point = curveprofile_distance_to_next_table_point(profile, 0);
float distance_to_previous_table_point = 0.0f;
@@ -1060,18 +932,113 @@ void BKE_curveprofile_create_samples_even_spacing(CurveProfile *profile,
}
/**
- * Does a single evaluation along the profile's path.
- * Travels down (length_portion * path) length and returns the position at that point.
- *
- * \param length_portion: The portion (0 to 1) of the path's full length to sample at.
- * \note Requires #BKE_curveprofile_init or #BKE_curveprofile_update call before to fill table.
+ * Creates a higher resolution table by sampling the curved points.
+ * This table is used for display and evenly spaced evaluation.
*/
+static void curveprofile_make_table(CurveProfile *profile)
+{
+ int n_samples = BKE_curveprofile_table_size(profile);
+ CurveProfilePoint *new_table = (CurveProfilePoint *)MEM_callocN(
+ sizeof(CurveProfilePoint) * (n_samples + 1), __func__);
+
+ if (n_samples > 1) {
+ create_samples(profile, n_samples - 1, false, new_table);
+ }
+
+ /* Manually add last point at the end of the profile */
+ new_table[n_samples - 1].x = 0.0f;
+ new_table[n_samples - 1].y = 1.0f;
+
+ MEM_SAFE_FREE(profile->table);
+ profile->table = new_table;
+}
+
+/**
+ * Creates the table of points used for displaying a preview of the sampled segment locations on
+ * the widget itself.
+ */
+static void curveprofile_make_segments_table(CurveProfile *profile)
+{
+ int n_samples = profile->segments_len;
+ if (n_samples <= 0) {
+ return;
+ }
+ CurveProfilePoint *new_table = (CurveProfilePoint *)MEM_callocN(
+ sizeof(CurveProfilePoint) * (n_samples + 1), __func__);
+
+ if (profile->flag & PROF_SAMPLE_EVEN_LENGTHS) {
+ /* Even length sampling incompatible with only straight edge sampling for now. */
+ create_samples_even_spacing(profile, n_samples, new_table);
+ }
+ else {
+ create_samples(profile, n_samples, profile->flag & PROF_SAMPLE_STRAIGHT_EDGES, new_table);
+ }
+
+ MEM_SAFE_FREE(profile->segments);
+ profile->segments = new_table;
+}
+
+void BKE_curveprofile_update(CurveProfile *profile, const int update_flags)
+{
+ CurveProfilePoint *points = profile->path;
+ rctf *clipr = &profile->clip_rect;
+
+ profile->changed_timestamp++;
+
+ /* Clamp with the clipping rect in case something got past. */
+ if (profile->flag & PROF_USE_CLIP) {
+ /* Move points inside the clip rectangle. */
+ if (update_flags & PROF_UPDATE_CLIP) {
+ for (int i = 0; i < profile->path_len; i++) {
+ points[i].x = clamp_f(points[i].x, clipr->xmin, clipr->xmax);
+ points[i].y = clamp_f(points[i].y, clipr->ymin, clipr->ymax);
+
+ /* Extra sanity assert to make sure the points have the right profile pointer. */
+ BLI_assert(points[i].profile == profile);
+ }
+ }
+ /* Ensure zoom-level respects clipping. */
+ if (BLI_rctf_size_x(&profile->view_rect) > BLI_rctf_size_x(&profile->clip_rect)) {
+ profile->view_rect.xmin = profile->clip_rect.xmin;
+ profile->view_rect.xmax = profile->clip_rect.xmax;
+ }
+ if (BLI_rctf_size_y(&profile->view_rect) > BLI_rctf_size_y(&profile->clip_rect)) {
+ profile->view_rect.ymin = profile->clip_rect.ymin;
+ profile->view_rect.ymax = profile->clip_rect.ymax;
+ }
+ }
+
+ /* Remove doubles with a threshold set at 1% of default range. */
+ float thresh = pow2f(0.01f * BLI_rctf_size_x(clipr));
+ if (update_flags & PROF_UPDATE_REMOVE_DOUBLES && profile->path_len > 2) {
+ for (int i = 0; i < profile->path_len - 1; i++) {
+ if (len_squared_v2v2(&points[i].x, &points[i + 1].x) < thresh) {
+ if (i == 0) {
+ BKE_curveprofile_remove_point(profile, &points[1]);
+ }
+ else {
+ BKE_curveprofile_remove_point(profile, &points[i]);
+ }
+ break; /* Assumes 1 deletion per update call is ok. */
+ }
+ }
+ }
+
+ /* Create the high resolution table for drawing and some evaluation functions. */
+ curveprofile_make_table(profile);
+
+ /* Store a table of samples for the segment locations for a preview and the table's user. */
+ if (profile->segments_len > 0) {
+ curveprofile_make_segments_table(profile);
+ }
+}
+
void BKE_curveprofile_evaluate_length_portion(const CurveProfile *profile,
float length_portion,
float *x_out,
float *y_out)
{
- const float total_length = BKE_curveprofile_total_length(profile);
+ const float total_length = curveprofile_total_length(profile);
const float requested_length = length_portion * total_length;
/* Find the last point along the path with a lower length portion than the input. */
@@ -1079,7 +1046,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_TABLE_LEN(profile->path_len) - 2) {
+ if (i == BKE_curveprofile_table_size(profile) - 2) {
break;
}
float new_length = curveprofile_distance_to_next_table_point(profile, i);
@@ -1110,23 +1077,4 @@ void BKE_curveprofile_evaluate_length_portion(const CurveProfile *profile,
*y_out = interpf(profile->table[i].y, profile->table[i + 1].y, lerp_factor);
}
-void BKE_curveprofile_blend_write(struct BlendWriter *writer, const struct CurveProfile *profile)
-{
- BLO_write_struct(writer, CurveProfile, profile);
- BLO_write_struct_array(writer, CurveProfilePoint, profile->path_len, profile->path);
-}
-
-/* Expects that the curve profile itself has been read already. */
-void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurveProfile *profile)
-{
- BLO_read_data_address(reader, &profile->path);
- profile->table = NULL;
- profile->segments = NULL;
-
- /* Reset the points' pointers to the profile. */
- for (int i = 0; i < profile->path_len; i++) {
- profile->path[i].profile = profile;
- }
-
- BKE_curveprofile_init(profile, profile->segments_len);
-}
+/** \} */
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.cc
index 3bb02e1856b..5e3beab9b72 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -44,6 +44,10 @@
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
+#ifndef NDEBUG
+# include "BLI_dynstr.h"
+#endif
+
#include "BLT_translation.h"
#include "BKE_anonymous_attribute.h"
@@ -69,11 +73,10 @@
#define CUSTOMDATA_GROW 5
/* ensure typemap size is ok */
-BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "size mismatch");
+BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)nullptr)->typemap) == CD_NUMTYPES, "size mismatch");
static CLG_LogRef LOG = {"bke.customdata"};
-/** Update mask_dst with layers defined in mask_src (equivalent to a bitwise OR). */
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst,
const CustomData_MeshMasks *mask_src)
{
@@ -84,7 +87,6 @@ void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst,
mask_dst->lmask |= mask_src->lmask;
}
-/** Return True if all layers set in \a mask_required are also set in \a mask_ref */
bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref,
const CustomData_MeshMasks *mask_required)
{
@@ -96,7 +98,7 @@ bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref,
}
/********************* Layer type information **********************/
-typedef struct LayerTypeInfo {
+struct LayerTypeInfo {
int size; /* the memory size of one element of this layer's data */
/** name of the struct used, for file writing */
@@ -107,7 +109,7 @@ typedef struct LayerTypeInfo {
/**
* default layer name.
*
- * \note when NULL this is a way to ensure there is only ever one item
+ * \note when null this is a way to ensure there is only ever one item
* see: CustomData_layertype_is_singleton().
*/
const char *defaultname;
@@ -115,7 +117,7 @@ typedef struct LayerTypeInfo {
/**
* a function to copy count elements of this layer's data
* (deep copy if appropriate)
- * if NULL, memcpy is used
+ * if null, memcpy is used
*/
cd_copy copy;
@@ -130,7 +132,7 @@ typedef struct LayerTypeInfo {
/**
* a function to interpolate between count source elements of this
* layer's data and store the result in dest
- * if weights == NULL or sub_weights == NULL, they should default to 1
+ * if weights == null or sub_weights == null, they should default to 1
*
* weights gives the weight for each element in sources
* sub_weights gives the sub-element weights for each element in sources
@@ -148,7 +150,7 @@ typedef struct LayerTypeInfo {
void (*swap)(void *data, const int *corner_indices);
/**
- * a function to set a layer's data to default values. if NULL, the
+ * a function to set a layer's data to default values. if null, the
* default is assumed to be all zeros */
void (*set_default)(void *data, int count);
@@ -173,9 +175,9 @@ typedef struct LayerTypeInfo {
size_t (*filesize)(CDataFile *cdf, const void *data, int count);
/** a function to determine max allowed number of layers,
- * should be NULL or return -1 if no limit */
- int (*layers_max)(void);
-} LayerTypeInfo;
+ * should be null or return -1 if no limit */
+ int (*layers_max)();
+};
static void layerCopy_mdeformvert(const void *source, void *dest, int count)
{
@@ -184,17 +186,17 @@ static void layerCopy_mdeformvert(const void *source, void *dest, int count)
memcpy(dest, source, count * size);
for (i = 0; i < count; i++) {
- MDeformVert *dvert = POINTER_OFFSET(dest, i * size);
+ MDeformVert *dvert = static_cast<MDeformVert *>(POINTER_OFFSET(dest, i * size));
if (dvert->totweight) {
- MDeformWeight *dw = MEM_malloc_arrayN(
- dvert->totweight, sizeof(*dw), "layerCopy_mdeformvert dw");
+ MDeformWeight *dw = static_cast<MDeformWeight *>(
+ MEM_malloc_arrayN(dvert->totweight, sizeof(*dw), __func__));
memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw));
dvert->dw = dw;
}
else {
- dvert->dw = NULL;
+ dvert->dw = nullptr;
}
}
}
@@ -202,11 +204,11 @@ static void layerCopy_mdeformvert(const void *source, void *dest, int count)
static void layerFree_mdeformvert(void *data, int count, int size)
{
for (int i = 0; i < count; i++) {
- MDeformVert *dvert = POINTER_OFFSET(data, i * size);
+ MDeformVert *dvert = static_cast<MDeformVert *>(POINTER_OFFSET(data, i * size));
if (dvert->dw) {
MEM_freeN(dvert->dw);
- dvert->dw = NULL;
+ dvert->dw = nullptr;
dvert->totweight = 0;
}
}
@@ -218,8 +220,8 @@ static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest,
const int size = sizeof(void *);
for (int i = 0; i < count; i++) {
- void **ptr = POINTER_OFFSET(dest, i * size);
- *ptr = NULL;
+ void **ptr = (void **)POINTER_OFFSET(dest, i * size);
+ *ptr = nullptr;
}
}
@@ -233,9 +235,9 @@ void bpy_bm_generic_invalidate(struct BPy_BMGeneric *UNUSED(self))
static void layerFree_bmesh_elem_py_ptr(void *data, int count, int size)
{
for (int i = 0; i < count; i++) {
- void **ptr = POINTER_OFFSET(data, i * size);
+ void **ptr = (void **)POINTER_OFFSET(data, i * size);
if (*ptr) {
- bpy_bm_generic_invalidate(*ptr);
+ bpy_bm_generic_invalidate(static_cast<BPy_BMGeneric *>(*ptr));
}
}
}
@@ -253,14 +255,14 @@ static void layerInterp_mdeformvert(const void **sources,
MDeformWeight dw;
};
- MDeformVert *dvert = dest;
- struct MDeformWeight_Link *dest_dwlink = NULL;
+ MDeformVert *dvert = static_cast<MDeformVert *>(dest);
+ struct MDeformWeight_Link *dest_dwlink = nullptr;
struct MDeformWeight_Link *node;
/* build a list of unique def_nrs for dest */
int totweight = 0;
for (int i = 0; i < count; i++) {
- const MDeformVert *source = sources[i];
+ const MDeformVert *source = static_cast<const MDeformVert *>(sources[i]);
float interp_weight = weights[i];
for (int j = 0; j < source->totweight; j++) {
@@ -282,11 +284,12 @@ static void layerInterp_mdeformvert(const void **sources,
/* if this def_nr is not in the list, add it */
if (!node) {
- struct MDeformWeight_Link *tmp_dwlink = alloca(sizeof(*tmp_dwlink));
+ struct MDeformWeight_Link *tmp_dwlink = static_cast<MDeformWeight_Link *>(
+ alloca(sizeof(*tmp_dwlink)));
tmp_dwlink->dw.def_nr = dw->def_nr;
tmp_dwlink->dw.weight = weight;
- /* inline linklist */
+ /* Inline linked-list. */
tmp_dwlink->next = dest_dwlink;
dest_dwlink = tmp_dwlink;
@@ -307,7 +310,8 @@ static void layerInterp_mdeformvert(const void **sources,
}
if (totweight) {
- dvert->dw = MEM_malloc_arrayN(totweight, sizeof(*dvert->dw), __func__);
+ dvert->dw = static_cast<MDeformWeight *>(
+ MEM_malloc_arrayN(totweight, sizeof(*dvert->dw), __func__));
}
}
@@ -345,37 +349,13 @@ static void layerInterp_normal(const void **sources,
normalize_v3_v3((float *)dest, no);
}
-static bool layerValidate_normal(void *data, const uint totitems, const bool do_fixes)
-{
- static const float no_default[3] = {0.0f, 0.0f, 1.0f}; /* Z-up default normal... */
- float(*no)[3] = data;
- bool has_errors = false;
-
- for (int i = 0; i < totitems; i++, no++) {
- if (!is_finite_v3((float *)no)) {
- has_errors = true;
- if (do_fixes) {
- copy_v3_v3((float *)no, no_default);
- }
- }
- else if (!compare_ff(len_squared_v3((float *)no), 1.0f, 1e-6f)) {
- has_errors = true;
- if (do_fixes) {
- normalize_v3((float *)no);
- }
- }
- }
-
- return has_errors;
-}
-
static void layerCopyValue_normal(const void *source,
void *dest,
const int mixmode,
const float mixfactor)
{
- const float *no_src = source;
- float *no_dst = dest;
+ const float *no_src = (const float *)source;
+ float *no_dst = (float *)dest;
float no_tmp[3];
if (ELEM(mixmode,
@@ -418,13 +398,13 @@ static void layerCopy_tface(const void *source, void *dest, int count)
static void layerInterp_tface(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
{
- MTFace *tf = dest;
+ MTFace *tf = static_cast<MTFace *>(dest);
float uv[4][2] = {{0.0f}};
const float *sub_weight = sub_weights;
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MTFace *src = sources[i];
+ const MTFace *src = static_cast<const MTFace *>(sources[i]);
for (int j = 0; j < 4; j++) {
if (sub_weights) {
@@ -445,7 +425,7 @@ static void layerInterp_tface(
static void layerSwap_tface(void *data, const int *corner_indices)
{
- MTFace *tf = data;
+ MTFace *tf = static_cast<MTFace *>(data);
float uv[4][2];
for (int j = 0; j < 4; j++) {
@@ -466,7 +446,7 @@ static void layerDefault_tface(void *data, int count)
}
}
-static int layerMaxNum_tface(void)
+static int layerMaxNum_tface()
{
return MAX_MTFACE;
}
@@ -493,7 +473,7 @@ static void layerInterp_propFloat(const void **sources,
static bool layerValidate_propFloat(void *data, const uint totitems, const bool do_fixes)
{
- MFloatProperty *fp = data;
+ MFloatProperty *fp = static_cast<MFloatProperty *>(data);
bool has_errors = false;
for (int i = 0; i < totitems; i++, fp++) {
@@ -531,13 +511,13 @@ static void layerCopy_origspace_face(const void *source, void *dest, int count)
static void layerInterp_origspace_face(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
{
- OrigSpaceFace *osf = dest;
+ OrigSpaceFace *osf = static_cast<OrigSpaceFace *>(dest);
float uv[4][2] = {{0.0f}};
const float *sub_weight = sub_weights;
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const OrigSpaceFace *src = sources[i];
+ const OrigSpaceFace *src = static_cast<const OrigSpaceFace *>(sources[i]);
for (int j = 0; j < 4; j++) {
if (sub_weights) {
@@ -557,7 +537,7 @@ static void layerInterp_origspace_face(
static void layerSwap_origspace_face(void *data, const int *corner_indices)
{
- OrigSpaceFace *osf = data;
+ OrigSpaceFace *osf = static_cast<OrigSpaceFace *>(data);
float uv[4][2];
for (int j = 0; j < 4; j++) {
@@ -578,7 +558,7 @@ static void layerDefault_origspace_face(void *data, int count)
static void layerSwap_mdisps(void *data, const int *ci)
{
- MDisps *s = data;
+ MDisps *s = static_cast<MDisps *>(data);
if (s->disps) {
int nverts = (ci[1] == 3) ? 4 : 3; /* silly way to know vertex count of face */
@@ -591,11 +571,11 @@ static void layerSwap_mdisps(void *data, const int *ci)
MEM_freeN(s->disps);
s->totdisp = (s->totdisp / corners) * nverts;
- s->disps = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisp swap");
+ s->disps = (float(*)[3])MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisp swap");
return;
}
- float(*d)[3] = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap");
+ float(*d)[3] = (float(*)[3])MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap");
for (int S = 0; S < corners; S++) {
memcpy(d + cornersize * S, s->disps + cornersize * ci[S], sizeof(float[3]) * cornersize);
@@ -608,17 +588,17 @@ static void layerSwap_mdisps(void *data, const int *ci)
static void layerCopy_mdisps(const void *source, void *dest, int count)
{
- const MDisps *s = source;
- MDisps *d = dest;
+ const MDisps *s = static_cast<const MDisps *>(source);
+ MDisps *d = static_cast<MDisps *>(dest);
for (int i = 0; i < count; i++) {
if (s[i].disps) {
- d[i].disps = MEM_dupallocN(s[i].disps);
- d[i].hidden = MEM_dupallocN(s[i].hidden);
+ d[i].disps = static_cast<float(*)[3]>(MEM_dupallocN(s[i].disps));
+ d[i].hidden = static_cast<unsigned int *>(MEM_dupallocN(s[i].hidden));
}
else {
- d[i].disps = NULL;
- d[i].hidden = NULL;
+ d[i].disps = nullptr;
+ d[i].hidden = nullptr;
}
/* still copy even if not in memory, displacement can be external */
@@ -629,7 +609,7 @@ static void layerCopy_mdisps(const void *source, void *dest, int count)
static void layerFree_mdisps(void *data, int count, int UNUSED(size))
{
- MDisps *d = data;
+ MDisps *d = static_cast<MDisps *>(data);
for (int i = 0; i < count; i++) {
if (d[i].disps) {
@@ -638,8 +618,8 @@ static void layerFree_mdisps(void *data, int count, int UNUSED(size))
if (d[i].hidden) {
MEM_freeN(d[i].hidden);
}
- d[i].disps = NULL;
- d[i].hidden = NULL;
+ d[i].disps = nullptr;
+ d[i].hidden = nullptr;
d[i].totdisp = 0;
d[i].level = 0;
}
@@ -647,16 +627,16 @@ static void layerFree_mdisps(void *data, int count, int UNUSED(size))
static bool layerRead_mdisps(CDataFile *cdf, void *data, int count)
{
- MDisps *d = data;
+ MDisps *d = static_cast<MDisps *>(data);
for (int i = 0; i < count; i++) {
if (!d[i].disps) {
- d[i].disps = MEM_calloc_arrayN(d[i].totdisp, sizeof(float[3]), "mdisps read");
+ d[i].disps = (float(*)[3])MEM_calloc_arrayN(d[i].totdisp, sizeof(float[3]), "mdisps read");
}
if (!cdf_read_data(cdf, sizeof(float[3]) * d[i].totdisp, d[i].disps)) {
CLOG_ERROR(&LOG, "failed to read multires displacement %d/%d %d", i, count, d[i].totdisp);
- return 0;
+ return false;
}
}
@@ -665,12 +645,12 @@ static bool layerRead_mdisps(CDataFile *cdf, void *data, int count)
static bool layerWrite_mdisps(CDataFile *cdf, const void *data, int count)
{
- const MDisps *d = data;
+ const MDisps *d = static_cast<const MDisps *>(data);
for (int i = 0; i < count; i++) {
if (!cdf_write_data(cdf, sizeof(float[3]) * d[i].totdisp, d[i].disps)) {
CLOG_ERROR(&LOG, "failed to write multires displacement %d/%d %d", i, count, d[i].totdisp);
- return 0;
+ return false;
}
}
@@ -679,7 +659,7 @@ static bool layerWrite_mdisps(CDataFile *cdf, const void *data, int count)
static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int count)
{
- const MDisps *d = data;
+ const MDisps *d = static_cast<const MDisps *>(data);
size_t size = 0;
for (int i = 0; i < count; i++) {
@@ -697,7 +677,7 @@ static void layerInterp_paint_mask(const void **sources,
float mask = 0.0f;
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const float *src = sources[i];
+ const float *src = static_cast<const float *>(sources[i]);
mask += (*src) * interp_weight;
}
*(float *)dest = mask;
@@ -705,16 +685,16 @@ static void layerInterp_paint_mask(const void **sources,
static void layerCopy_grid_paint_mask(const void *source, void *dest, int count)
{
- const GridPaintMask *s = source;
- GridPaintMask *d = dest;
+ const GridPaintMask *s = static_cast<const GridPaintMask *>(source);
+ GridPaintMask *d = static_cast<GridPaintMask *>(dest);
for (int i = 0; i < count; i++) {
if (s[i].data) {
- d[i].data = MEM_dupallocN(s[i].data);
+ d[i].data = static_cast<float *>(MEM_dupallocN(s[i].data));
d[i].level = s[i].level;
}
else {
- d[i].data = NULL;
+ d[i].data = nullptr;
d[i].level = 0;
}
}
@@ -722,7 +702,7 @@ static void layerCopy_grid_paint_mask(const void *source, void *dest, int count)
static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size))
{
- GridPaintMask *gpm = data;
+ GridPaintMask *gpm = static_cast<GridPaintMask *>(data);
for (int i = 0; i < count; i++) {
MEM_SAFE_FREE(gpm[i].data);
@@ -736,8 +716,8 @@ static void layerCopyValue_mloopcol(const void *source,
const int mixmode,
const float mixfactor)
{
- const MLoopCol *m1 = source;
- MLoopCol *m2 = dest;
+ const MLoopCol *m1 = static_cast<const MLoopCol *>(source);
+ MLoopCol *m2 = static_cast<MLoopCol *>(dest);
unsigned char tmp_col[4];
if (ELEM(mixmode,
@@ -791,7 +771,8 @@ static void layerCopyValue_mloopcol(const void *source,
static bool layerEqual_mloopcol(const void *data1, const void *data2)
{
- const MLoopCol *m1 = data1, *m2 = data2;
+ const MLoopCol *m1 = static_cast<const MLoopCol *>(data1);
+ const MLoopCol *m2 = static_cast<const MLoopCol *>(data2);
float r, g, b, a;
r = m1->r - m2->r;
@@ -804,7 +785,7 @@ static bool layerEqual_mloopcol(const void *data1, const void *data2)
static void layerMultiply_mloopcol(void *data, float fac)
{
- MLoopCol *m = data;
+ MLoopCol *m = static_cast<MLoopCol *>(data);
m->r = (float)m->r * fac;
m->g = (float)m->g * fac;
@@ -814,8 +795,8 @@ static void layerMultiply_mloopcol(void *data, float fac)
static void layerAdd_mloopcol(void *data1, const void *data2)
{
- MLoopCol *m = data1;
- const MLoopCol *m2 = data2;
+ MLoopCol *m = static_cast<MLoopCol *>(data1);
+ const MLoopCol *m2 = static_cast<const MLoopCol *>(data2);
m->r += m2->r;
m->g += m2->g;
@@ -825,8 +806,9 @@ static void layerAdd_mloopcol(void *data1, const void *data2)
static void layerDoMinMax_mloopcol(const void *data, void *vmin, void *vmax)
{
- const MLoopCol *m = data;
- MLoopCol *min = vmin, *max = vmax;
+ const MLoopCol *m = static_cast<const MLoopCol *>(data);
+ MLoopCol *min = static_cast<MLoopCol *>(vmin);
+ MLoopCol *max = static_cast<MLoopCol *>(vmax);
if (m->r < min->r) {
min->r = m->r;
@@ -856,7 +838,8 @@ static void layerDoMinMax_mloopcol(const void *data, void *vmin, void *vmax)
static void layerInitMinMax_mloopcol(void *vmin, void *vmax)
{
- MLoopCol *min = vmin, *max = vmax;
+ MLoopCol *min = static_cast<MLoopCol *>(vmin);
+ MLoopCol *max = static_cast<MLoopCol *>(vmax);
min->r = 255;
min->g = 255;
@@ -884,7 +867,7 @@ static void layerInterp_mloopcol(const void **sources,
int count,
void *dest)
{
- MLoopCol *mc = dest;
+ MLoopCol *mc = static_cast<MLoopCol *>(dest);
struct {
float a;
float r;
@@ -894,7 +877,7 @@ static void layerInterp_mloopcol(const void **sources,
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MLoopCol *src = sources[i];
+ const MLoopCol *src = static_cast<const MLoopCol *>(sources[i]);
col.r += src->r * interp_weight;
col.g += src->g * interp_weight;
col.b += src->b * interp_weight;
@@ -911,7 +894,7 @@ static void layerInterp_mloopcol(const void **sources,
mc->a = round_fl_to_uchar_clamp(col.a);
}
-static int layerMaxNum_mloopcol(void)
+static int layerMaxNum_mloopcol()
{
return MAX_MCOL;
}
@@ -921,8 +904,8 @@ static void layerCopyValue_mloopuv(const void *source,
const int mixmode,
const float mixfactor)
{
- const MLoopUV *luv1 = source;
- MLoopUV *luv2 = dest;
+ const MLoopUV *luv1 = static_cast<const MLoopUV *>(source);
+ MLoopUV *luv2 = static_cast<MLoopUV *>(dest);
/* We only support a limited subset of advanced mixing here -
* namely the mixfactor interpolation. */
@@ -937,37 +920,40 @@ static void layerCopyValue_mloopuv(const void *source,
static bool layerEqual_mloopuv(const void *data1, const void *data2)
{
- const MLoopUV *luv1 = data1, *luv2 = data2;
+ const MLoopUV *luv1 = static_cast<const MLoopUV *>(data1);
+ const MLoopUV *luv2 = static_cast<const MLoopUV *>(data2);
return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
}
static void layerMultiply_mloopuv(void *data, float fac)
{
- MLoopUV *luv = data;
+ MLoopUV *luv = static_cast<MLoopUV *>(data);
mul_v2_fl(luv->uv, fac);
}
static void layerInitMinMax_mloopuv(void *vmin, void *vmax)
{
- MLoopUV *min = vmin, *max = vmax;
+ MLoopUV *min = static_cast<MLoopUV *>(vmin);
+ MLoopUV *max = static_cast<MLoopUV *>(vmax);
INIT_MINMAX2(min->uv, max->uv);
}
static void layerDoMinMax_mloopuv(const void *data, void *vmin, void *vmax)
{
- const MLoopUV *luv = data;
- MLoopUV *min = vmin, *max = vmax;
+ const MLoopUV *luv = static_cast<const MLoopUV *>(data);
+ MLoopUV *min = static_cast<MLoopUV *>(vmin);
+ MLoopUV *max = static_cast<MLoopUV *>(vmax);
minmax_v2v2_v2(min->uv, max->uv, luv->uv);
}
static void layerAdd_mloopuv(void *data1, const void *data2)
{
- MLoopUV *l1 = data1;
- const MLoopUV *l2 = data2;
+ MLoopUV *l1 = static_cast<MLoopUV *>(data1);
+ const MLoopUV *l2 = static_cast<const MLoopUV *>(data2);
add_v2_v2(l1->uv, l2->uv);
}
@@ -985,7 +971,7 @@ static void layerInterp_mloopuv(const void **sources,
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MLoopUV *src = sources[i];
+ const MLoopUV *src = static_cast<const MLoopUV *>(sources[i]);
madd_v2_v2fl(uv, src->uv, interp_weight);
if (interp_weight > 0.0f) {
flag |= src->flag;
@@ -999,7 +985,7 @@ static void layerInterp_mloopuv(const void **sources,
static bool layerValidate_mloopuv(void *data, const uint totitems, const bool do_fixes)
{
- MLoopUV *uv = data;
+ MLoopUV *uv = static_cast<MLoopUV *>(data);
bool has_errors = false;
for (int i = 0; i < totitems; i++, uv++) {
@@ -1020,45 +1006,48 @@ static void layerCopyValue_mloop_origspace(const void *source,
const int UNUSED(mixmode),
const float UNUSED(mixfactor))
{
- const OrigSpaceLoop *luv1 = source;
- OrigSpaceLoop *luv2 = dest;
+ const OrigSpaceLoop *luv1 = static_cast<const OrigSpaceLoop *>(source);
+ OrigSpaceLoop *luv2 = static_cast<OrigSpaceLoop *>(dest);
copy_v2_v2(luv2->uv, luv1->uv);
}
static bool layerEqual_mloop_origspace(const void *data1, const void *data2)
{
- const OrigSpaceLoop *luv1 = data1, *luv2 = data2;
+ const OrigSpaceLoop *luv1 = static_cast<const OrigSpaceLoop *>(data1);
+ const OrigSpaceLoop *luv2 = static_cast<const OrigSpaceLoop *>(data2);
return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
}
static void layerMultiply_mloop_origspace(void *data, float fac)
{
- OrigSpaceLoop *luv = data;
+ OrigSpaceLoop *luv = static_cast<OrigSpaceLoop *>(data);
mul_v2_fl(luv->uv, fac);
}
static void layerInitMinMax_mloop_origspace(void *vmin, void *vmax)
{
- OrigSpaceLoop *min = vmin, *max = vmax;
+ OrigSpaceLoop *min = static_cast<OrigSpaceLoop *>(vmin);
+ OrigSpaceLoop *max = static_cast<OrigSpaceLoop *>(vmax);
INIT_MINMAX2(min->uv, max->uv);
}
static void layerDoMinMax_mloop_origspace(const void *data, void *vmin, void *vmax)
{
- const OrigSpaceLoop *luv = data;
- OrigSpaceLoop *min = vmin, *max = vmax;
+ const OrigSpaceLoop *luv = static_cast<const OrigSpaceLoop *>(data);
+ OrigSpaceLoop *min = static_cast<OrigSpaceLoop *>(vmin);
+ OrigSpaceLoop *max = static_cast<OrigSpaceLoop *>(vmax);
minmax_v2v2_v2(min->uv, max->uv, luv->uv);
}
static void layerAdd_mloop_origspace(void *data1, const void *data2)
{
- OrigSpaceLoop *l1 = data1;
- const OrigSpaceLoop *l2 = data2;
+ OrigSpaceLoop *l1 = static_cast<OrigSpaceLoop *>(data1);
+ const OrigSpaceLoop *l2 = static_cast<const OrigSpaceLoop *>(data2);
add_v2_v2(l1->uv, l2->uv);
}
@@ -1074,7 +1063,7 @@ static void layerInterp_mloop_origspace(const void **sources,
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const OrigSpaceLoop *src = sources[i];
+ const OrigSpaceLoop *src = static_cast<const OrigSpaceLoop *>(sources[i]);
madd_v2_v2fl(uv, src->uv, interp_weight);
}
@@ -1086,7 +1075,7 @@ static void layerInterp_mloop_origspace(const void **sources,
static void layerInterp_mcol(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
{
- MCol *mc = dest;
+ MCol *mc = static_cast<MCol *>(dest);
struct {
float a;
float r;
@@ -1100,7 +1089,7 @@ static void layerInterp_mcol(
for (int j = 0; j < 4; j++) {
if (sub_weights) {
- const MCol *src = sources[i];
+ const MCol *src = static_cast<const MCol *>(sources[i]);
for (int k = 0; k < 4; k++, sub_weight++, src++) {
const float w = (*sub_weight) * interp_weight;
col[j].a += src->a * w;
@@ -1110,7 +1099,7 @@ static void layerInterp_mcol(
}
}
else {
- const MCol *src = sources[i];
+ const MCol *src = static_cast<const MCol *>(sources[i]);
col[j].a += src[j].a * interp_weight;
col[j].r += src[j].r * interp_weight;
col[j].g += src[j].g * interp_weight;
@@ -1133,7 +1122,7 @@ static void layerInterp_mcol(
static void layerSwap_mcol(void *data, const int *corner_indices)
{
- MCol *mcol = data;
+ MCol *mcol = static_cast<MCol *>(data);
MCol col[4];
for (int j = 0; j < 4; j++) {
@@ -1207,7 +1196,7 @@ static void layerInterp_shapekey(const void **sources,
static void layerDefault_mvert_skin(void *data, int count)
{
- MVertSkin *vs = data;
+ MVertSkin *vs = static_cast<MVertSkin *>(data);
for (int i = 0; i < count; i++) {
copy_v3_fl(vs[i].radius, 0.25f);
@@ -1231,20 +1220,20 @@ static void layerInterp_mvert_skin(const void **sources,
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MVertSkin *vs_src = sources[i];
+ const MVertSkin *vs_src = static_cast<const MVertSkin *>(sources[i]);
madd_v3_v3fl(radius, vs_src->radius, interp_weight);
}
/* Delay writing to the destination in case dest is in sources. */
- MVertSkin *vs_dst = dest;
+ MVertSkin *vs_dst = static_cast<MVertSkin *>(dest);
copy_v3_v3(vs_dst->radius, radius);
vs_dst->flag &= ~MVERT_SKIN_ROOT;
}
static void layerSwap_flnor(void *data, const int *corner_indices)
{
- short(*flnors)[4][3] = data;
+ short(*flnors)[4][3] = static_cast<short(*)[4][3]>(data);
short nors[4][3];
int i = 4;
@@ -1268,8 +1257,8 @@ static void layerCopyValue_propcol(const void *source,
const int mixmode,
const float mixfactor)
{
- const MPropCol *m1 = source;
- MPropCol *m2 = dest;
+ const MPropCol *m1 = static_cast<const MPropCol *>(source);
+ MPropCol *m2 = static_cast<MPropCol *>(dest);
float tmp_col[4];
if (ELEM(mixmode,
@@ -1313,7 +1302,8 @@ static void layerCopyValue_propcol(const void *source,
static bool layerEqual_propcol(const void *data1, const void *data2)
{
- const MPropCol *m1 = data1, *m2 = data2;
+ const MPropCol *m1 = static_cast<const MPropCol *>(data1);
+ const MPropCol *m2 = static_cast<const MPropCol *>(data2);
float tot = 0;
for (int i = 0; i < 4; i++) {
@@ -1326,27 +1316,29 @@ static bool layerEqual_propcol(const void *data1, const void *data2)
static void layerMultiply_propcol(void *data, float fac)
{
- MPropCol *m = data;
+ MPropCol *m = static_cast<MPropCol *>(data);
mul_v4_fl(m->color, fac);
}
static void layerAdd_propcol(void *data1, const void *data2)
{
- MPropCol *m = data1;
- const MPropCol *m2 = data2;
+ MPropCol *m = static_cast<MPropCol *>(data1);
+ const MPropCol *m2 = static_cast<const MPropCol *>(data2);
add_v4_v4(m->color, m2->color);
}
static void layerDoMinMax_propcol(const void *data, void *vmin, void *vmax)
{
- const MPropCol *m = data;
- MPropCol *min = vmin, *max = vmax;
+ const MPropCol *m = static_cast<const MPropCol *>(data);
+ MPropCol *min = static_cast<MPropCol *>(vmin);
+ MPropCol *max = static_cast<MPropCol *>(vmax);
minmax_v4v4_v4(min->color, max->color, m->color);
}
static void layerInitMinMax_propcol(void *vmin, void *vmax)
{
- MPropCol *min = vmin, *max = vmax;
+ MPropCol *min = static_cast<MPropCol *>(vmin);
+ MPropCol *max = static_cast<MPropCol *>(vmax);
copy_v4_fl(min->color, FLT_MAX);
copy_v4_fl(max->color, FLT_MIN);
@@ -1368,17 +1360,17 @@ static void layerInterp_propcol(const void **sources,
int count,
void *dest)
{
- MPropCol *mc = dest;
+ MPropCol *mc = static_cast<MPropCol *>(dest);
float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MPropCol *src = sources[i];
+ const MPropCol *src = static_cast<const MPropCol *>(sources[i]);
madd_v4_v4fl(col, src->color, interp_weight);
}
copy_v4_v4(mc->color, col);
}
-static int layerMaxNum_propcol(void)
+static int layerMaxNum_propcol()
{
return MAX_MCOL;
}
@@ -1392,7 +1384,7 @@ static void layerInterp_propfloat3(const void **sources,
vec3f result = {0.0f, 0.0f, 0.0f};
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const vec3f *src = sources[i];
+ const vec3f *src = static_cast<const vec3f *>(sources[i]);
madd_v3_v3fl(&result.x, &src->x, interp_weight);
}
copy_v3_v3((float *)dest, &result.x);
@@ -1400,7 +1392,7 @@ static void layerInterp_propfloat3(const void **sources,
static void layerMultiply_propfloat3(void *data, float fac)
{
- vec3f *vec = data;
+ vec3f *vec = static_cast<vec3f *>(data);
vec->x *= fac;
vec->y *= fac;
vec->z *= fac;
@@ -1408,8 +1400,8 @@ static void layerMultiply_propfloat3(void *data, float fac)
static void layerAdd_propfloat3(void *data1, const void *data2)
{
- vec3f *vec1 = data1;
- const vec3f *vec2 = data2;
+ vec3f *vec1 = static_cast<vec3f *>(data1);
+ const vec3f *vec2 = static_cast<const vec3f *>(data2);
vec1->x += vec2->x;
vec1->y += vec2->y;
vec1->z += vec2->z;
@@ -1417,7 +1409,7 @@ static void layerAdd_propfloat3(void *data1, const void *data2)
static bool layerValidate_propfloat3(void *data, const uint totitems, const bool do_fixes)
{
- float *values = data;
+ float *values = static_cast<float *>(data);
bool has_errors = false;
for (int i = 0; i < totitems * 3; i++) {
if (!isfinite(values[i])) {
@@ -1439,7 +1431,7 @@ static void layerInterp_propfloat2(const void **sources,
vec2f result = {0.0f, 0.0f};
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const vec2f *src = sources[i];
+ const vec2f *src = static_cast<const vec2f *>(sources[i]);
madd_v2_v2fl(&result.x, &src->x, interp_weight);
}
copy_v2_v2((float *)dest, &result.x);
@@ -1447,22 +1439,22 @@ static void layerInterp_propfloat2(const void **sources,
static void layerMultiply_propfloat2(void *data, float fac)
{
- vec2f *vec = data;
+ vec2f *vec = static_cast<vec2f *>(data);
vec->x *= fac;
vec->y *= fac;
}
static void layerAdd_propfloat2(void *data1, const void *data2)
{
- vec2f *vec1 = data1;
- const vec2f *vec2 = data2;
+ vec2f *vec1 = static_cast<vec2f *>(data1);
+ const vec2f *vec2 = static_cast<const vec2f *>(data2);
vec1->x += vec2->x;
vec1->y += vec2->y;
}
static bool layerValidate_propfloat2(void *data, const uint totitems, const bool do_fixes)
{
- float *values = data;
+ float *values = static_cast<float *>(data);
bool has_errors = false;
for (int i = 0; i < totitems * 2; i++) {
if (!isfinite(values[i])) {
@@ -1477,136 +1469,130 @@ static bool layerValidate_propfloat2(void *data, const uint totitems, const bool
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 0: CD_MVERT */
- {sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MVert), "MVert", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 1: CD_MSTICKY */ /* DEPRECATED */
- {sizeof(float[2]), "", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[2]), "", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 2: CD_MDEFORMVERT */
{sizeof(MDeformVert),
"MDeformVert",
1,
- NULL,
+ nullptr,
layerCopy_mdeformvert,
layerFree_mdeformvert,
layerInterp_mdeformvert,
- NULL,
- NULL},
+ nullptr,
+ nullptr},
/* 3: CD_MEDGE */
- {sizeof(MEdge), "MEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MEdge), "MEdge", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 4: CD_MFACE */
- {sizeof(MFace), "MFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MFace), "MFace", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 5: CD_MTFACE */
- {sizeof(MTFace),
- "MTFace",
- 1,
- N_("UVMap"),
- layerCopy_tface,
- NULL,
- layerInterp_tface,
- layerSwap_tface,
- layerDefault_tface,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- layerMaxNum_tface},
+ {sizeof(MTFace), "MTFace", 1,
+ N_("UVMap"), layerCopy_tface, nullptr,
+ layerInterp_tface, layerSwap_tface, layerDefault_tface,
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr,
+ nullptr, layerMaxNum_tface},
/* 6: CD_MCOL */
/* 4 MCol structs per face */
{sizeof(MCol[4]),
"MCol",
4,
N_("Col"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mcol,
layerSwap_mcol,
layerDefault_mcol,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
layerMaxNum_mloopcol},
/* 7: CD_ORIGINDEX */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_origindex},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_origindex},
/* 8: CD_NORMAL */
/* 3 floats per normal vector */
{sizeof(float[3]),
"vec3f",
1,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerInterp_normal,
- NULL,
- NULL,
- layerValidate_normal,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
layerCopyValue_normal},
/* 9: CD_FACEMAP */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_fmap, NULL},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_fmap, nullptr},
/* 10: CD_PROP_FLOAT */
{sizeof(MFloatProperty),
"MFloatProperty",
1,
N_("Float"),
layerCopy_propFloat,
- NULL,
+ nullptr,
layerInterp_propFloat,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerValidate_propFloat},
/* 11: CD_PROP_INT32 */
- {sizeof(MIntProperty), "MIntProperty", 1, N_("Int"), layerCopy_propInt, NULL, NULL, NULL},
+ {sizeof(MIntProperty),
+ "MIntProperty",
+ 1,
+ N_("Int"),
+ layerCopy_propInt,
+ nullptr,
+ nullptr,
+ nullptr},
/* 12: CD_PROP_STRING */
{sizeof(MStringProperty),
"MStringProperty",
1,
N_("String"),
layerCopy_propString,
- NULL,
- NULL,
- NULL},
+ nullptr,
+ nullptr,
+ nullptr},
/* 13: CD_ORIGSPACE */
{sizeof(OrigSpaceFace),
"OrigSpaceFace",
1,
N_("UVMap"),
layerCopy_origspace_face,
- NULL,
+ nullptr,
layerInterp_origspace_face,
layerSwap_origspace_face,
layerDefault_origspace_face},
/* 14: CD_ORCO */
- {sizeof(float[3]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[3]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 15: CD_MTEXPOLY */ /* DEPRECATED */
/* NOTE: when we expose the UV Map / TexFace split to the user,
* change this back to face Texture. */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 16: CD_MLOOPUV */
{sizeof(MLoopUV),
"MLoopUV",
1,
N_("UVMap"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mloopuv,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerValidate_mloopuv,
layerEqual_mloopuv,
layerMultiply_mloopuv,
@@ -1614,50 +1600,50 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerAdd_mloopuv,
layerDoMinMax_mloopuv,
layerCopyValue_mloopuv,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerMaxNum_tface},
/* 17: CD_MLOOPCOL */
{sizeof(MLoopCol),
"MLoopCol",
1,
N_("Col"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mloopcol,
- NULL,
+ nullptr,
layerDefault_mloopcol,
- NULL,
+ nullptr,
layerEqual_mloopcol,
layerMultiply_mloopcol,
layerInitMinMax_mloopcol,
layerAdd_mloopcol,
layerDoMinMax_mloopcol,
layerCopyValue_mloopcol,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerMaxNum_mloopcol},
/* 18: CD_TANGENT */
- {sizeof(float[4][4]), "", 0, N_("Tangent"), NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[4][4]), "", 0, N_("Tangent"), nullptr, nullptr, nullptr, nullptr, nullptr},
/* 19: CD_MDISPS */
{sizeof(MDisps),
"MDisps",
1,
- NULL,
+ nullptr,
layerCopy_mdisps,
layerFree_mdisps,
- NULL,
+ nullptr,
layerSwap_mdisps,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
layerRead_mdisps,
layerWrite_mdisps,
layerFilesize_mdisps},
@@ -1666,52 +1652,60 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
"MCol",
4,
N_("PreviewCol"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mcol,
layerSwap_mcol,
layerDefault_mcol},
/* 21: CD_ID_MCOL */ /* DEPRECATED */
- {sizeof(MCol[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MCol[4]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 22: CD_TEXTURE_MCOL */
{sizeof(MCol[4]),
"MCol",
4,
N_("TexturedCol"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mcol,
layerSwap_mcol,
layerDefault_mcol},
/* 23: CD_CLOTH_ORCO */
- {sizeof(float[3]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[3]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 24: CD_RECAST */
- {sizeof(MRecast), "MRecast", 1, N_("Recast"), NULL, NULL, NULL, NULL},
-
- /* BMESH ONLY */
+ {sizeof(MRecast), "MRecast", 1, N_("Recast"), nullptr, nullptr, nullptr, nullptr},
/* 25: CD_MPOLY */
- {sizeof(MPoly), "MPoly", 1, N_("NGon Face"), NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MPoly), "MPoly", 1, N_("NGon Face"), nullptr, nullptr, nullptr, nullptr, nullptr},
/* 26: CD_MLOOP */
- {sizeof(MLoop), "MLoop", 1, N_("NGon Face-Vertex"), NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MLoop),
+ "MLoop",
+ 1,
+ N_("NGon Face-Vertex"),
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr},
/* 27: CD_SHAPE_KEYINDEX */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 28: CD_SHAPEKEY */
- {sizeof(float[3]), "", 0, N_("ShapeKey"), NULL, NULL, layerInterp_shapekey},
+ {sizeof(float[3]), "", 0, N_("ShapeKey"), nullptr, nullptr, layerInterp_shapekey},
/* 29: CD_BWEIGHT */
- {sizeof(float), "", 0, N_("BevelWeight"), NULL, NULL, layerInterp_bweight},
+ {sizeof(float), "", 0, N_("BevelWeight"), nullptr, nullptr, layerInterp_bweight},
/* 30: CD_CREASE */
- {sizeof(float), "", 0, N_("SubSurfCrease"), NULL, NULL, layerInterp_bweight},
+ /* NOTE: we do not interpolate crease data as it should be either inherited for subdivided
+ * edges, or for vertex creases, only present on the original vertex. */
+ {sizeof(float), "", 0, N_("SubSurfCrease"), nullptr, nullptr, nullptr},
/* 31: CD_ORIGSPACE_MLOOP */
{sizeof(OrigSpaceLoop),
"OrigSpaceLoop",
1,
N_("OS Loop"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mloop_origspace,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerEqual_mloop_origspace,
layerMultiply_mloop_origspace,
layerInitMinMax_mloop_origspace,
@@ -1723,12 +1717,12 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
"MLoopCol",
1,
N_("PreviewLoopCol"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mloopcol,
- NULL,
+ nullptr,
layerDefault_mloopcol,
- NULL,
+ nullptr,
layerEqual_mloopcol,
layerMultiply_mloopcol,
layerInitMinMax_mloopcol,
@@ -1739,125 +1733,138 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(void *),
"",
1,
- NULL,
+ nullptr,
layerCopy_bmesh_elem_py_ptr,
layerFree_bmesh_elem_py_ptr,
- NULL,
- NULL,
- NULL},
-
- /* END BMESH ONLY */
-
+ nullptr,
+ nullptr,
+ nullptr},
/* 34: CD_PAINT_MASK */
- {sizeof(float), "", 0, NULL, NULL, NULL, layerInterp_paint_mask, NULL, NULL},
+ {sizeof(float), "", 0, nullptr, nullptr, nullptr, layerInterp_paint_mask, nullptr, nullptr},
/* 35: CD_GRID_PAINT_MASK */
{sizeof(GridPaintMask),
"GridPaintMask",
1,
- NULL,
+ nullptr,
layerCopy_grid_paint_mask,
layerFree_grid_paint_mask,
- NULL,
- NULL,
- NULL},
+ nullptr,
+ nullptr,
+ nullptr},
/* 36: CD_MVERT_SKIN */
{sizeof(MVertSkin),
"MVertSkin",
1,
- NULL,
+ nullptr,
layerCopy_mvert_skin,
- NULL,
+ nullptr,
layerInterp_mvert_skin,
- NULL,
+ nullptr,
layerDefault_mvert_skin},
/* 37: CD_FREESTYLE_EDGE */
- {sizeof(FreestyleEdge), "FreestyleEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(FreestyleEdge),
+ "FreestyleEdge",
+ 1,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr},
/* 38: CD_FREESTYLE_FACE */
- {sizeof(FreestyleFace), "FreestyleFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(FreestyleFace),
+ "FreestyleFace",
+ 1,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr},
/* 39: CD_MLOOPTANGENT */
- {sizeof(float[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[4]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 40: CD_TESSLOOPNORMAL */
- {sizeof(short[4][3]), "", 0, NULL, NULL, NULL, NULL, layerSwap_flnor, NULL},
+ {sizeof(short[4][3]), "", 0, nullptr, nullptr, nullptr, nullptr, layerSwap_flnor, nullptr},
/* 41: CD_CUSTOMLOOPNORMAL */
- {sizeof(short[2]), "vec2s", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(short[2]), "vec2s", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 42: CD_SCULPT_FACE_SETS */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 43: CD_LOCATION */
- {sizeof(float[3]), "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[3]), "vec3f", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 44: CD_RADIUS */
- {sizeof(float), "MFloatProperty", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float), "MFloatProperty", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 45: CD_HAIRCURVE */
- {sizeof(HairCurve), "HairCurve", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(HairCurve), "HairCurve", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 46: CD_HAIRMAPPING */
- {sizeof(HairMapping), "HairMapping", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(HairMapping), "HairMapping", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 47: CD_PROP_COLOR */
{sizeof(MPropCol),
"MPropCol",
1,
N_("Color"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_propcol,
- NULL,
+ nullptr,
layerDefault_propcol,
- NULL,
+ nullptr,
layerEqual_propcol,
layerMultiply_propcol,
layerInitMinMax_propcol,
layerAdd_propcol,
layerDoMinMax_propcol,
layerCopyValue_propcol,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerMaxNum_propcol},
/* 48: CD_PROP_FLOAT3 */
{sizeof(float[3]),
"vec3f",
1,
N_("Float3"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_propfloat3,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerValidate_propfloat3,
- NULL,
+ nullptr,
layerMultiply_propfloat3,
- NULL,
+ nullptr,
layerAdd_propfloat3},
/* 49: CD_PROP_FLOAT2 */
{sizeof(float[2]),
"vec2f",
1,
N_("Float2"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_propfloat2,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerValidate_propfloat2,
- NULL,
+ nullptr,
layerMultiply_propfloat2,
- NULL,
+ nullptr,
layerAdd_propfloat2},
/* 50: CD_PROP_BOOL */
{sizeof(bool),
"bool",
1,
N_("Boolean"),
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr},
/* 51: CD_HAIRLENGTH */
- {sizeof(float), "float", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float), "float", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
};
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
@@ -1918,95 +1925,106 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
};
const CustomData_MeshMasks CD_MASK_BAREMESH = {
- .vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT,
- .emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT,
- .fmask = 0,
- .lmask = CD_MASK_MLOOP,
- .pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP,
+ /* vmask */ CD_MASK_MVERT | CD_MASK_BWEIGHT,
+ /* emask */ CD_MASK_MEDGE | CD_MASK_BWEIGHT,
+ /* fmask */ 0,
+ /* pmask */ CD_MASK_MPOLY | CD_MASK_FACEMAP,
+ /* lmask */ CD_MASK_MLOOP,
};
const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
- .vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
- .emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
- .fmask = 0,
- .lmask = CD_MASK_MLOOP,
- .pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_ORIGINDEX,
+ /* vmask */ CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
+ /* emask */ CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
+ /* fmask */ 0,
+ /* pmask */ CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_ORIGINDEX,
+ /* lmask */ CD_MASK_MLOOP,
};
const CustomData_MeshMasks CD_MASK_MESH = {
- .vmask = (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
- CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
- .fmask = 0,
- .lmask = (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL |
- CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
- .pmask = (CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL |
- CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
+ CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ /* emask */ (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
+ /* fmask */ 0,
+ /* pmask */
+ (CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL |
+ CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL |
+ CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
};
const CustomData_MeshMasks CD_MASK_EDITMESH = {
- .vmask = (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
- CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_PROP_ALL),
- .fmask = 0,
- .lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
- .pmask = (CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
+ CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ /* emask */ (CD_MASK_PROP_ALL),
+ /* fmask */ 0,
+ /* pmask */ (CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
};
const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
- .vmask = (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
- CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL |
- CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
- .fmask = (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
- .lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
- CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
- CD_MASK_PROP_ALL), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */
- .pmask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
- CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
+ CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL |
+ CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ /* emask */ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
+ /* fmask */ (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
+ /* pmask */
+ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
+ CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_PREVIEW_MLOOPCOL |
+ CD_MASK_ORIGSPACE_MLOOP | CD_MASK_PROP_ALL), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */
};
const CustomData_MeshMasks CD_MASK_BMESH = {
- .vmask = (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
- CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
- .fmask = 0,
- .lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
- .pmask = (CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
- CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
+ CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL |
+ CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ /* emask */ (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
+ /* fmask */ 0,
+ /* pmask */
+ (CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
};
/**
* cover values copied by #mesh_loops_to_tessdata
*/
const CustomData_MeshMasks CD_MASK_FACECORNERS = {
- .vmask = 0,
- .emask = 0,
- .fmask = (CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_PREVIEW_MCOL | CD_MASK_ORIGSPACE |
- CD_MASK_TESSLOOPNORMAL | CD_MASK_TANGENT),
- .lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL |
- CD_MASK_ORIGSPACE_MLOOP | CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT),
- .pmask = 0,
+ /* vmask */ 0,
+ /* emask */ 0,
+ /* fmask */
+ (CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_PREVIEW_MCOL | CD_MASK_ORIGSPACE |
+ CD_MASK_TESSLOOPNORMAL | CD_MASK_TANGENT),
+ /* pmask */ 0,
+ /* lmask */
+ (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
+ CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT),
};
const CustomData_MeshMasks CD_MASK_EVERYTHING = {
- .vmask = (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL |
- CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO |
- CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK |
- CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT |
- CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
- .fmask = (CD_MASK_MFACE | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MTFACE | CD_MASK_MCOL |
- CD_MASK_ORIGSPACE | CD_MASK_TANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_PREVIEW_MCOL |
- CD_MASK_PROP_ALL),
- .lmask = (CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL |
- CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
- CD_MASK_MLOOPTANGENT | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
- .pmask = (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL |
- CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL |
- CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL |
+ CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO |
+ CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX |
+ CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ /* emask */
+ (CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT | CD_MASK_CREASE |
+ CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
+ /* fmask */
+ (CD_MASK_MFACE | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MTFACE | CD_MASK_MCOL |
+ CD_MASK_ORIGSPACE | CD_MASK_TANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_PREVIEW_MCOL |
+ CD_MASK_PROP_ALL),
+ /* pmask */
+ (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_FACEMAP |
+ CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL | CD_MASK_MLOOPUV |
+ CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_MLOOPTANGENT |
+ CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_GRID_PAINT_MASK |
+ CD_MASK_PROP_ALL),
};
static const LayerTypeInfo *layerType_getInfo(int type)
{
if (type < 0 || type >= CD_NUMTYPES) {
- return NULL;
+ return nullptr;
}
return &LAYERTYPEINFO[type];
@@ -2015,7 +2033,7 @@ static const LayerTypeInfo *layerType_getInfo(int type)
static const char *layerType_getName(int type)
{
if (type < 0 || type >= CD_NUMTYPES) {
- return NULL;
+ return nullptr;
}
return LAYERTYPENAMES[type];
@@ -2131,11 +2149,6 @@ bool CustomData_merge(const struct CustomData *source,
if (flag & CD_FLAG_NOCOPY) {
continue;
}
- if (layer->anonymous_id &&
- !BKE_anonymous_attribute_id_has_strong_references(layer->anonymous_id)) {
- /* This attribute is not referenced anymore, so it can be treated as if it didn't exist. */
- continue;
- }
if (!(mask & CD_TYPE_AS_MASK(type))) {
continue;
}
@@ -2154,7 +2167,7 @@ bool CustomData_merge(const struct CustomData *source,
data = layer->data;
break;
default:
- data = NULL;
+ data = nullptr;
break;
}
@@ -2176,7 +2189,7 @@ bool CustomData_merge(const struct CustomData *source,
newlayer->flag |= flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY);
changed = true;
- if (layer->anonymous_id != NULL) {
+ if (layer->anonymous_id != nullptr) {
BKE_anonymous_attribute_id_increment_weak(layer->anonymous_id);
newlayer->anonymous_id = layer->anonymous_id;
}
@@ -2187,7 +2200,6 @@ bool CustomData_merge(const struct CustomData *source,
return changed;
}
-/* NOTE: Take care of referenced layers by yourself! */
void CustomData_realloc(CustomData *data, int totelem)
{
for (int i = 0; i < data->totlayer; i++) {
@@ -2197,7 +2209,9 @@ void CustomData_realloc(CustomData *data, int totelem)
continue;
}
typeInfo = layerType_getInfo(layer->type);
- layer->data = MEM_reallocN(layer->data, (size_t)totelem * typeInfo->size);
+ /* Use calloc to avoid the need to manually initialize new data in layers.
+ * Useful for types like #MDeformVert which contain a pointer. */
+ layer->data = MEM_recallocN(layer->data, (size_t)totelem * typeInfo->size);
}
}
@@ -2210,7 +2224,7 @@ void CustomData_copy(const struct CustomData *source,
CustomData_reset(dest);
if (source->external) {
- dest->external = MEM_dupallocN(source->external);
+ dest->external = static_cast<CustomDataExternal *>(MEM_dupallocN(source->external));
}
CustomData_merge(source, dest, mask, alloctype, totelem);
@@ -2220,9 +2234,9 @@ static void customData_free_layer__internal(CustomDataLayer *layer, int totelem)
{
const LayerTypeInfo *typeInfo;
- if (layer->anonymous_id != NULL) {
+ if (layer->anonymous_id != nullptr) {
BKE_anonymous_attribute_id_decrement_weak(layer->anonymous_id);
- layer->anonymous_id = NULL;
+ layer->anonymous_id = nullptr;
}
if (!(layer->flag & CD_FLAG_NOFREE) && layer->data) {
typeInfo = layerType_getInfo(layer->type);
@@ -2241,7 +2255,7 @@ static void CustomData_external_free(CustomData *data)
{
if (data->external) {
MEM_freeN(data->external);
- data->external = NULL;
+ data->external = nullptr;
}
}
@@ -2449,8 +2463,6 @@ void CustomData_set_layer_stencil(CustomData *data, int type, int n)
}
}
-/* For using with an index from CustomData_get_active_layer_index and
- * CustomData_get_render_layer_index. */
void CustomData_set_layer_active_index(CustomData *data, int type, int n)
{
for (int i = 0; i < data->totlayer; i++) {
@@ -2509,8 +2521,8 @@ void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag)
static bool customData_resize(CustomData *data, int amount)
{
- CustomDataLayer *tmp = MEM_calloc_arrayN(
- (data->maxlayer + amount), sizeof(*tmp), "CustomData->layers");
+ CustomDataLayer *tmp = static_cast<CustomDataLayer *>(
+ MEM_calloc_arrayN((data->maxlayer + amount), sizeof(*tmp), __func__));
if (!tmp) {
return false;
}
@@ -2534,7 +2546,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
int flag = 0, index = data->totlayer;
- void *newlayerdata = NULL;
+ void *newlayerdata = nullptr;
/* Passing a layer-data to copy from with an alloctype that won't copy is
* most likely a bug */
@@ -2556,7 +2568,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
}
if (!newlayerdata) {
- return NULL;
+ return nullptr;
}
}
@@ -2584,7 +2596,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
if (newlayerdata != layerdata) {
MEM_freeN(newlayerdata);
}
- return NULL;
+ return nullptr;
}
}
@@ -2595,6 +2607,11 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
data->layers[index] = data->layers[index - 1];
}
+ /* Clear remaining data on the layer. The original data on the layer has been moved to another
+ * index. Without this, it can happen that information from the previous layer at that index
+ * leaks into the new layer. */
+ memset(data->layers + index, 0, sizeof(CustomDataLayer));
+
data->layers[index].type = type;
data->layers[index].flag = flag;
data->layers[index].data = newlayerdata;
@@ -2645,10 +2662,9 @@ void *CustomData_add_layer(
return layer->data;
}
- return NULL;
+ return nullptr;
}
-/* Same as above but accepts a name. */
void *CustomData_add_layer_named(CustomData *data,
int type,
eCDAllocType alloctype,
@@ -2664,7 +2680,7 @@ void *CustomData_add_layer_named(CustomData *data,
return layer->data;
}
- return NULL;
+ return nullptr;
}
void *CustomData_add_layer_anonymous(struct CustomData *data,
@@ -2679,8 +2695,8 @@ void *CustomData_add_layer_anonymous(struct CustomData *data,
data, type, alloctype, layerdata, totelem, name);
CustomData_update_typemap(data);
- if (layer == NULL) {
- return NULL;
+ if (layer == nullptr) {
+ return nullptr;
}
BKE_anonymous_attribute_id_increment_weak(anonymous_id);
@@ -2793,7 +2809,7 @@ static void *customData_duplicate_referenced_layer_index(CustomData *data,
const int totelem)
{
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
CustomDataLayer *layer = &data->layers[layer_index];
@@ -2862,7 +2878,7 @@ void *CustomData_duplicate_referenced_layer_anonymous(CustomData *data,
}
}
BLI_assert_unreachable();
- return NULL;
+ return nullptr;
}
void CustomData_duplicate_referenced_layers(CustomData *data, int totelem)
@@ -2958,7 +2974,7 @@ void CustomData_copy_data_layer(const CustomData *source,
const size_t dst_offset = (size_t)dst_index * typeInfo->size;
if (!count || !src_data || !dst_data) {
- if (count && !(src_data == NULL && dst_data == NULL)) {
+ if (count && !(src_data == nullptr && dst_data == nullptr)) {
CLOG_WARN(&LOG,
"null data for %s type (%p --> %p), skipping",
layerType_getName(source->layers[src_layer_index].type),
@@ -3068,18 +3084,6 @@ void CustomData_free_elem(CustomData *data, int index, int count)
#define SOURCE_BUF_SIZE 100
-/**
- * Interpolate given custom data source items into a single destination one.
- *
- * \param src_indices: Indices of every source items to interpolate into the destination one.
- * \param weights: The weight to apply to each source value individually. If NULL, they will be
- * averaged.
- * \param sub_weights: The weights of sub-items, only used to affect each corners of a
- * tessellated face data (should always be and array of four values).
- * \param count: The number of source items to interpolate.
- * \param dest_index: Index of the destination item, in which to put the result of the
- * interpolation.
- */
void CustomData_interp(const CustomData *source,
CustomData *dest,
const int *src_indices,
@@ -3097,15 +3101,16 @@ void CustomData_interp(const CustomData *source,
/* Slow fallback in case we're interpolating a ridiculous number of elements. */
if (count > SOURCE_BUF_SIZE) {
- sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__);
+ sources = static_cast<const void **>(MEM_malloc_arrayN(count, sizeof(*sources), __func__));
}
/* If no weights are given, generate default ones to produce an average result. */
float default_weights_buf[SOURCE_BUF_SIZE];
- float *default_weights = NULL;
- if (weights == NULL) {
+ float *default_weights = nullptr;
+ if (weights == nullptr) {
default_weights = (count > SOURCE_BUF_SIZE) ?
- MEM_mallocN(sizeof(*weights) * (size_t)count, __func__) :
+ static_cast<float *>(
+ MEM_mallocN(sizeof(*weights) * (size_t)count, __func__)) :
default_weights_buf;
copy_vn_fl(default_weights, count, 1.0f / count);
weights = default_weights;
@@ -3157,18 +3162,11 @@ void CustomData_interp(const CustomData *source,
if (count > SOURCE_BUF_SIZE) {
MEM_freeN((void *)sources);
}
- if (!ELEM(default_weights, NULL, default_weights_buf)) {
+ if (!ELEM(default_weights, nullptr, default_weights_buf)) {
MEM_freeN(default_weights);
}
}
-/**
- * Swap data inside each item, for all layers.
- * This only applies to item types that may store several sub-item data
- * (e.g. corner data [UVs, VCol, ...] of tessellated faces).
- *
- * \param corner_indices: A mapping 'new_index -> old_index' of sub-item data.
- */
void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices)
{
for (int i = 0; i < data->totlayer; i++) {
@@ -3182,9 +3180,6 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn
}
}
-/**
- * Swap two items of given custom data, in all available layers.
- */
void CustomData_swap(struct CustomData *data, const int index_a, const int index_b)
{
char buff_static[256];
@@ -3219,7 +3214,7 @@ void *CustomData_get(const CustomData *data, int index, int type)
/* get the layer index of the active layer of type */
int layer_index = CustomData_get_active_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
/* get the offset of the desired element */
@@ -3235,7 +3230,7 @@ void *CustomData_get_n(const CustomData *data, int type, int index, int n)
/* get the layer index of the first layer of type */
int layer_index = data->typemap[type];
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
const size_t offset = (size_t)index * layerType_getInfo(type)->size;
@@ -3247,7 +3242,7 @@ void *CustomData_get_layer(const CustomData *data, int type)
/* get the layer index of the active layer of type */
int layer_index = CustomData_get_active_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return data->layers[layer_index].data;
@@ -3258,7 +3253,7 @@ void *CustomData_get_layer_n(const CustomData *data, int type, int n)
/* get the layer index of the active layer of type */
int layer_index = CustomData_get_layer_index_n(data, type, n);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return data->layers[layer_index].data;
@@ -3268,7 +3263,7 @@ void *CustomData_get_layer_named(const struct CustomData *data, int type, const
{
int layer_index = CustomData_get_named_layer_index(data, type, name);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return data->layers[layer_index].data;
@@ -3314,7 +3309,7 @@ const char *CustomData_get_layer_name(const CustomData *data, int type, int n)
{
const int layer_index = CustomData_get_layer_index_n(data, type, n);
- return (layer_index == -1) ? NULL : data->layers[layer_index].name;
+ return (layer_index == -1) ? nullptr : data->layers[layer_index].name;
}
void *CustomData_set_layer(const CustomData *data, int type, void *ptr)
@@ -3323,7 +3318,7 @@ void *CustomData_set_layer(const CustomData *data, int type, void *ptr)
int layer_index = CustomData_get_active_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
data->layers[layer_index].data = ptr;
@@ -3336,7 +3331,7 @@ void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, voi
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_layer_index_n(data, type, n);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
data->layers[layer_index].data = ptr;
@@ -3362,25 +3357,25 @@ void CustomData_set(const CustomData *data, int index, int type, const void *sou
}
/* BMesh functions */
-/* needed to convert to/from different face reps */
+
void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop)
{
for (int i = 0; i < fdata->totlayer; i++) {
if (fdata->layers[i].type == CD_MTFACE) {
CustomData_add_layer_named(
- ldata, CD_MLOOPUV, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ ldata, CD_MLOOPUV, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
}
else if (fdata->layers[i].type == CD_MCOL) {
CustomData_add_layer_named(
- ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ ldata, CD_MLOOPCOL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
}
else if (fdata->layers[i].type == CD_MDISPS) {
CustomData_add_layer_named(
- ldata, CD_MDISPS, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ ldata, CD_MDISPS, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
}
else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) {
CustomData_add_layer_named(
- ldata, CD_NORMAL, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ ldata, CD_NORMAL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
}
}
}
@@ -3392,25 +3387,27 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *ldata, int total)
for (int i = 0; i < ldata->totlayer; i++) {
if (ldata->layers[i].type == CD_MLOOPUV) {
- CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ CustomData_add_layer_named(
+ fdata, CD_MTFACE, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
if (ldata->layers[i].type == CD_MLOOPCOL) {
- CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_PREVIEW_MLOOPCOL) {
CustomData_add_layer_named(
- fdata, CD_PREVIEW_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ fdata, CD_PREVIEW_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) {
CustomData_add_layer_named(
- fdata, CD_ORIGSPACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ fdata, CD_ORIGSPACE, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_NORMAL) {
CustomData_add_layer_named(
- fdata, CD_TESSLOOPNORMAL, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ fdata, CD_TESSLOOPNORMAL, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_TANGENT) {
- CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ CustomData_add_layer_named(
+ fdata, CD_TANGENT, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
}
@@ -3418,12 +3415,6 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *ldata, int total)
}
#ifndef NDEBUG
-/**
- * Debug check, used to assert when we expect layers to be in/out of sync.
- *
- * \param fallback: Use when there are no layers to handle,
- * since callers may expect success or failure.
- */
bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback)
{
int a_num = 0, b_num = 0;
@@ -3491,11 +3482,6 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata)
}
}
-/* update active indices for active/render/clone/stencil custom data layers
- * based on indices from fdata layers
- * used by do_versions in readfile.c when creating pdata and ldata for pre-bmesh
- * meshes and needed to preserve active/render/clone/stencil flags set in pre-bmesh files
- */
void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *ldata)
{
int act;
@@ -3534,7 +3520,7 @@ void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
int chunksize;
/* Dispose old pools before calling here to avoid leaks */
- BLI_assert(data->pool == NULL);
+ BLI_assert(data->pool == nullptr);
switch (htype) {
case BM_VERT:
@@ -3577,7 +3563,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
* the new allocation */
CustomData destold = *dest;
if (destold.layers) {
- destold.layers = MEM_dupallocN(destold.layers);
+ destold.layers = static_cast<CustomDataLayer *>(MEM_dupallocN(destold.layers));
}
if (CustomData_merge(source, dest, mask, alloctype, 0) == false) {
@@ -3613,7 +3599,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
break;
}
- dest->pool = NULL;
+ dest->pool = nullptr;
CustomData_bmesh_init_pool(dest, totelem, htype);
if (iter_type != BM_LOOPS_OF_FACE) {
@@ -3621,7 +3607,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
BMIter iter;
/* Ensure all current elements follow new customdata layout. */
BM_ITER_MESH (h, &iter, bm, iter_type) {
- void *tmp = NULL;
+ void *tmp = nullptr;
CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp);
CustomData_bmesh_free_block(&destold, &h->data);
h->data = tmp;
@@ -3636,7 +3622,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
/* Ensure all current elements follow new customdata layout. */
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- void *tmp = NULL;
+ void *tmp = nullptr;
CustomData_bmesh_copy_data(&destold, dest, l->head.data, &tmp);
CustomData_bmesh_free_block(&destold, &l->head.data);
l->head.data = tmp;
@@ -3655,7 +3641,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
void CustomData_bmesh_free_block(CustomData *data, void **block)
{
- if (*block == NULL) {
+ if (*block == nullptr) {
return;
}
@@ -3674,15 +3660,12 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
BLI_mempool_free(data->pool, *block);
}
- *block = NULL;
+ *block = nullptr;
}
-/**
- * Same as #CustomData_bmesh_free_block but zero the memory rather than freeing.
- */
void CustomData_bmesh_free_block_data(CustomData *data, void *block)
{
- if (block == NULL) {
+ if (block == nullptr) {
return;
}
for (int i = 0; i < data->totlayer; i++) {
@@ -3709,18 +3692,15 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
*block = BLI_mempool_alloc(data->pool);
}
else {
- *block = NULL;
+ *block = nullptr;
}
}
-/**
- * A selective version of #CustomData_bmesh_free_block_data.
- */
void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
void *block,
const CustomDataMask mask_exclude)
{
- if (block == NULL) {
+ if (block == nullptr) {
return;
}
for (int i = 0; i < data->totlayer; i++) {
@@ -3752,7 +3732,7 @@ static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n
void CustomData_bmesh_set_default(CustomData *data, void **block)
{
- if (*block == NULL) {
+ if (*block == nullptr) {
CustomData_bmesh_alloc_block(data, block);
}
@@ -3771,7 +3751,7 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
* would cause too much duplicate code, so add a check instead. */
const bool no_mask = (mask_exclude == 0);
- if (*dest_block == NULL) {
+ if (*dest_block == nullptr) {
CustomData_bmesh_alloc_block(dest, dest_block);
if (*dest_block) {
memset(*dest_block, 0, dest->totsize);
@@ -3832,15 +3812,12 @@ void CustomData_bmesh_copy_data(const CustomData *source,
CustomData_bmesh_copy_data_exclude_by_type(source, dest, src_block, dest_block, 0);
}
-/* BMesh Custom Data Functions.
- * Should replace edit-mesh ones with these as well, due to more efficient memory alloc.
- */
void *CustomData_bmesh_get(const CustomData *data, void *block, int type)
{
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_active_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return POINTER_OFFSET(block, data->layers[layer_index].offset);
@@ -3851,17 +3828,16 @@ void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return POINTER_OFFSET(block, data->layers[layer_index + n].offset);
}
-/* Gets from the layer at physical index n, NOTE: doesn't check type. */
void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
{
if (n < 0 || n >= data->totlayer) {
- return NULL;
+ return nullptr;
}
return POINTER_OFFSET(block, data->layers[n].offset);
@@ -3902,7 +3878,6 @@ bool CustomData_has_math(const struct CustomData *data)
return false;
}
-/* a non bmesh version would have to check layer->data */
bool CustomData_bmesh_has_free(const struct CustomData *data)
{
for (int i = 0; i < data->totlayer; i++) {
@@ -3938,8 +3913,6 @@ bool CustomData_has_referenced(const struct CustomData *data)
return false;
}
-/* copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
- * another, while not overwriting anything else (e.g. flags). */
void CustomData_data_copy_value(int type, const void *source, void *dest)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -3956,8 +3929,6 @@ void CustomData_data_copy_value(int type, const void *source, void *dest)
}
}
-/* Mixes the "value" (e.g. mloopuv uv or mloopcol colors) from one block into
- * another, while not overwriting anything else (e.g. flags). */
void CustomData_data_mix_value(
int type, const void *source, void *dest, const int mixmode, const float mixfactor)
{
@@ -4074,10 +4045,6 @@ void CustomData_bmesh_set_layer_n(CustomData *data, void *block, int n, const vo
}
}
-/**
- * \note src_blocks_ofs & dst_block_ofs
- * must be pointers to the data, offset by layer->offset already.
- */
void CustomData_bmesh_interp_n(CustomData *data,
const void **src_blocks_ofs,
const float *weights,
@@ -4086,7 +4053,7 @@ void CustomData_bmesh_interp_n(CustomData *data,
void *dst_block_ofs,
int n)
{
- BLI_assert(weights != NULL);
+ BLI_assert(weights != nullptr);
BLI_assert(count > 0);
CustomDataLayer *layer = &data->layers[n];
@@ -4111,15 +4078,15 @@ void CustomData_bmesh_interp(CustomData *data,
/* Slow fallback in case we're interpolating a ridiculous number of elements. */
if (count > SOURCE_BUF_SIZE) {
- sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__);
+ sources = (const void **)MEM_malloc_arrayN(count, sizeof(*sources), __func__);
}
/* If no weights are given, generate default ones to produce an average result. */
float default_weights_buf[SOURCE_BUF_SIZE];
- float *default_weights = NULL;
- if (weights == NULL) {
+ float *default_weights = nullptr;
+ if (weights == nullptr) {
default_weights = (count > SOURCE_BUF_SIZE) ?
- MEM_mallocN(sizeof(*weights) * (size_t)count, __func__) :
+ (float *)MEM_mallocN(sizeof(*weights) * (size_t)count, __func__) :
default_weights_buf;
copy_vn_fl(default_weights, count, 1.0f / count);
weights = default_weights;
@@ -4141,23 +4108,18 @@ void CustomData_bmesh_interp(CustomData *data,
if (count > SOURCE_BUF_SIZE) {
MEM_freeN((void *)sources);
}
- if (!ELEM(default_weights, NULL, default_weights_buf)) {
+ if (!ELEM(default_weights, nullptr, default_weights_buf)) {
MEM_freeN(default_weights);
}
}
-/**
- * \param use_default_init: initializes data which can't be copied,
- * typically you'll want to use this if the BM_xxx create function
- * is called with BM_CREATE_SKIP_CD flag
- */
void CustomData_to_bmesh_block(const CustomData *source,
CustomData *dest,
int src_index,
void **dest_block,
bool use_default_init)
{
- if (*dest_block == NULL) {
+ if (*dest_block == nullptr) {
CustomData_bmesh_alloc_block(dest, dest_block);
}
@@ -4265,25 +4227,6 @@ void CustomData_file_write_info(int type, const char **r_struct_name, int *r_str
*r_struct_num = typeInfo->structnum;
}
-/**
- * Prepare given custom data for file writing.
- *
- * \param data: the customdata to tweak for .blend file writing (modified in place).
- * \param r_write_layers: contains a reduced set of layers to be written to file,
- * use it with writestruct_at_address()
- * (caller must free it if != \a write_layers_buff).
- *
- * \param write_layers_buff: an optional buffer for r_write_layers (to avoid allocating it).
- * \param write_layers_size: the size of pre-allocated \a write_layer_buff.
- *
- * \warning After this func has ran, given custom data is no more valid from Blender PoV
- * (its totlayer is invalid). This func shall always be called with localized data
- * (as it is in write_meshes()).
- *
- * \note data->typemap is not updated here, since it is always rebuilt on file read anyway.
- * This means written typemap does not match written layers (as returned by \a r_write_layers).
- * Trivial to fix is ever needed.
- */
void CustomData_blend_write_prepare(CustomData *data,
CustomDataLayer **r_write_layers,
CustomDataLayer *write_layers_buff,
@@ -4298,22 +4241,22 @@ void CustomData_blend_write_prepare(CustomData *data,
for (i = 0, j = 0; i < totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
/* Layers with this flag set are not written to file. */
- if ((layer->flag & CD_FLAG_NOCOPY) || layer->anonymous_id != NULL) {
+ if ((layer->flag & CD_FLAG_NOCOPY) || layer->anonymous_id != nullptr) {
data->totlayer--;
// CLOG_WARN(&LOG, "skipping layer %p (%s)", layer, layer->name);
}
else {
if (UNLIKELY((size_t)j >= write_layers_size)) {
if (write_layers == write_layers_buff) {
- write_layers = MEM_malloc_arrayN(
+ write_layers = (CustomDataLayer *)MEM_malloc_arrayN(
(write_layers_size + chunk_size), sizeof(*write_layers), __func__);
if (write_layers_buff) {
memcpy(write_layers, write_layers_buff, sizeof(*write_layers) * write_layers_size);
}
}
else {
- write_layers = MEM_reallocN(write_layers,
- sizeof(*write_layers) * (write_layers_size + chunk_size));
+ write_layers = (CustomDataLayer *)MEM_reallocN(
+ write_layers, sizeof(*write_layers) * (write_layers_size + chunk_size));
}
write_layers_size += chunk_size;
}
@@ -4337,39 +4280,28 @@ const char *CustomData_layertype_name(int type)
return layerType_getName(type);
}
-/**
- * Can only ever be one of these.
- */
bool CustomData_layertype_is_singleton(int type)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- return typeInfo->defaultname == NULL;
+ return typeInfo->defaultname == nullptr;
}
-/**
- * Has dynamically allocated members.
- * This is useful to know if operations such as #memcmp are
- * valid when comparing data from two layers.
- */
bool CustomData_layertype_is_dynamic(int type)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- return (typeInfo->free != NULL);
+ return (typeInfo->free != nullptr);
}
-/**
- * \return Maximum number of layers of given \a type, -1 means 'no limit'.
- */
int CustomData_layertype_layers_max(const int type)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
/* Same test as for singleton above. */
- if (typeInfo->defaultname == NULL) {
+ if (typeInfo->defaultname == nullptr) {
return 1;
}
- if (typeInfo->layers_max == NULL) {
+ if (typeInfo->layers_max == nullptr) {
return -1;
}
@@ -4399,13 +4331,15 @@ static bool cd_layer_find_dupe(CustomData *data, const char *name, int type, int
return false;
}
+struct CustomDataUniqueCheckData {
+ CustomData *data;
+ int type;
+ int index;
+};
+
static bool customdata_unique_check(void *arg, const char *name)
{
- struct {
- CustomData *data;
- int type;
- int index;
- } *data_arg = arg;
+ CustomDataUniqueCheckData *data_arg = static_cast<CustomDataUniqueCheckData *>(arg);
return cd_layer_find_dupe(data_arg->data, name, data_arg->type, data_arg->index);
}
@@ -4414,14 +4348,7 @@ void CustomData_set_layer_unique_name(CustomData *data, int index)
CustomDataLayer *nlayer = &data->layers[index];
const LayerTypeInfo *typeInfo = layerType_getInfo(nlayer->type);
- struct {
- CustomData *data;
- int type;
- int index;
- } data_arg;
- data_arg.data = data;
- data_arg.type = nlayer->type;
- data_arg.index = index;
+ CustomDataUniqueCheckData data_arg{data, nlayer->type, index};
if (!typeInfo->defaultname) {
return;
@@ -4434,7 +4361,7 @@ void CustomData_set_layer_unique_name(CustomData *data, int index)
}
BLI_uniquename_cb(
- customdata_unique_check, &data_arg, NULL, '.', nlayer->name, sizeof(nlayer->name));
+ customdata_unique_check, &data_arg, nullptr, '.', nlayer->name, sizeof(nlayer->name));
}
void CustomData_validate_layer_name(const CustomData *data,
@@ -4486,7 +4413,12 @@ bool CustomData_verify_versions(struct CustomData *data, int index)
/* 0 structnum is used in writing code to tag layer types that should not be written. */
else if (typeInfo->structnum == 0 &&
/* XXX Not sure why those three are exception, maybe that should be fixed? */
- !ELEM(layer->type, CD_PAINT_MASK, CD_FACEMAP, CD_MTEXPOLY, CD_SCULPT_FACE_SETS)) {
+ !ELEM(layer->type,
+ CD_PAINT_MASK,
+ CD_FACEMAP,
+ CD_MTEXPOLY,
+ CD_SCULPT_FACE_SETS,
+ CD_CREASE)) {
keeplayer = false;
CLOG_WARN(&LOG, ".blend file read: removing a data layer that should not have been written");
}
@@ -4502,17 +4434,11 @@ bool CustomData_verify_versions(struct CustomData *data, int index)
return keeplayer;
}
-/**
- * Validate and fix data of \a layer,
- * if possible (needs relevant callback in layer's type to be defined).
- *
- * \return True if some errors were found.
- */
bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, const bool do_fixes)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
- if (typeInfo->validate != NULL) {
+ if (typeInfo->validate != nullptr) {
return typeInfo->validate(layer->data, totitems, do_fixes);
}
@@ -4764,7 +4690,7 @@ void CustomData_external_add(
}
if (!external) {
- external = MEM_callocN(sizeof(CustomDataExternal), "CustomDataExternal");
+ external = MEM_cnew<CustomDataExternal>(__func__);
data->external = external;
}
BLI_strncpy(external->filename, filename, sizeof(external->filename));
@@ -4863,7 +4789,7 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
const int count,
const float mix_factor)
{
- BLI_assert(weights != NULL);
+ BLI_assert(weights != nullptr);
BLI_assert(count > 0);
/* Fake interpolation, we actually copy highest weighted source to dest.
@@ -4878,8 +4804,8 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
size_t data_size;
const uint64_t data_flag = laymap->data_flag;
- cd_interp interp_cd = NULL;
- cd_copy copy_cd = NULL;
+ cd_interp interp_cd = nullptr;
+ cd_copy copy_cd = nullptr;
if (!sources) {
/* Not supported here, abort. */
@@ -4933,7 +4859,7 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
BLI_assert(best_src_idx >= 0);
if (interp_cd) {
- interp_cd(sources, weights, NULL, count, tmp_dst);
+ interp_cd(sources, weights, nullptr, count, tmp_dst);
}
else if (data_flag) {
copy_bit_flag(tmp_dst, sources[best_src_idx], data_size, data_flag);
@@ -4971,7 +4897,6 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
MEM_freeN(tmp_dst);
}
-/* Normals are special, we need to take care of source & destination spaces... */
void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLayerMap *laymap,
void *data_dst,
const void **sources,
@@ -4979,13 +4904,13 @@ void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLaye
const int count,
const float mix_factor)
{
- BLI_assert(weights != NULL);
+ BLI_assert(weights != nullptr);
BLI_assert(count > 0);
const int data_type = laymap->data_type;
const int mix_mode = laymap->mix_mode;
- SpaceTransform *space_transform = laymap->interp_data;
+ SpaceTransform *space_transform = static_cast<SpaceTransform *>(laymap->interp_data);
const LayerTypeInfo *type_info = layerType_getInfo(data_type);
cd_interp interp_cd = type_info->interp;
@@ -4999,7 +4924,7 @@ void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLaye
return;
}
- interp_cd(sources, weights, NULL, count, tmp_dst);
+ interp_cd(sources, weights, nullptr, count, tmp_dst);
if (space_transform) {
/* tmp_dst is in source space so far, bring it back in destination space. */
BLI_space_transform_invert_normal(space_transform, tmp_dst);
@@ -5022,18 +4947,19 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap,
size_t data_size;
size_t data_offset;
- cd_datatransfer_interp interp = NULL;
+ cd_datatransfer_interp interp = nullptr;
size_t tmp_buff_size = 32;
- const void **tmp_data_src = NULL;
+ const void **tmp_data_src = nullptr;
- /* NOTE: NULL data_src may happen and be valid (see vgroups...). */
+ /* NOTE: null data_src may happen and be valid (see vgroups...). */
if (!data_dst) {
return;
}
if (data_src) {
- tmp_data_src = MEM_malloc_arrayN(tmp_buff_size, sizeof(*tmp_data_src), __func__);
+ tmp_data_src = (const void **)MEM_malloc_arrayN(
+ tmp_buff_size, sizeof(*tmp_data_src), __func__);
}
if (data_type & CD_FAKE) {
@@ -5065,7 +4991,8 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap,
if (tmp_data_src) {
if (UNLIKELY(sources_num > tmp_buff_size)) {
tmp_buff_size = (size_t)sources_num;
- tmp_data_src = MEM_reallocN((void *)tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size);
+ tmp_data_src = (const void **)MEM_reallocN((void *)tmp_data_src,
+ sizeof(*tmp_data_src) * tmp_buff_size);
}
for (int j = 0; j < sources_num; j++) {
@@ -5118,9 +5045,6 @@ static void write_grid_paint_mask(BlendWriter *writer, int count, GridPaintMask
}
}
-/**
- * \param layers: The layers argument assigned by #CustomData_blend_write_prepare.
- */
void CustomData_blend_write(BlendWriter *writer,
CustomData *data,
CustomDataLayer *layers,
@@ -5140,28 +5064,33 @@ void CustomData_blend_write(BlendWriter *writer,
if (layer->type == CD_MDEFORMVERT) {
/* layer types that allocate own memory need special handling */
- BKE_defvert_blend_write(writer, count, layer->data);
+ BKE_defvert_blend_write(writer, count, static_cast<struct MDeformVert *>(layer->data));
}
else if (layer->type == CD_MDISPS) {
- write_mdisps(writer, count, layer->data, layer->flag & CD_FLAG_EXTERNAL);
+ write_mdisps(
+ writer, count, static_cast<MDisps *>(layer->data), layer->flag & CD_FLAG_EXTERNAL);
}
else if (layer->type == CD_PAINT_MASK) {
- const float *layer_data = layer->data;
+ const float *layer_data = static_cast<const float *>(layer->data);
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else if (layer->type == CD_SCULPT_FACE_SETS) {
- const float *layer_data = layer->data;
+ const float *layer_data = static_cast<const float *>(layer->data);
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else if (layer->type == CD_GRID_PAINT_MASK) {
- write_grid_paint_mask(writer, count, layer->data);
+ write_grid_paint_mask(writer, count, static_cast<GridPaintMask *>(layer->data));
}
else if (layer->type == CD_FACEMAP) {
- const int *layer_data = layer->data;
+ const int *layer_data = static_cast<const int *>(layer->data);
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else if (layer->type == CD_PROP_BOOL) {
- const bool *layer_data = layer->data;
+ const bool *layer_data = static_cast<const bool *>(layer->data);
+ BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
+ }
+ else if (layer->type == CD_CREASE) {
+ const float *layer_data = static_cast<const float *>(layer->data);
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else {
@@ -5234,7 +5163,7 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
/* Annoying workaround for bug T31079 loading legacy files with
* no polygons _but_ have stale custom-data. */
- if (UNLIKELY(count == 0 && data->layers == NULL && data->totlayer != 0)) {
+ if (UNLIKELY(count == 0 && data->layers == nullptr && data->totlayer != 0)) {
CustomData_reset(data);
return;
}
@@ -5253,7 +5182,7 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
if (CustomData_verify_versions(data, i)) {
BLO_read_data_address(reader, &layer->data);
- if (layer->data == NULL && count > 0 && layer->type == CD_PROP_BOOL) {
+ if (layer->data == nullptr && count > 0 && layer->type == CD_PROP_BOOL) {
/* Usually this should never happen, except when a custom data layer has not been written
* to a file correctly. */
CLOG_WARN(&LOG, "Reallocating custom data layer that was not saved correctly.");
@@ -5264,10 +5193,11 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
}
}
if (layer->type == CD_MDISPS) {
- blend_read_mdisps(reader, count, layer->data, layer->flag & CD_FLAG_EXTERNAL);
+ blend_read_mdisps(
+ reader, count, static_cast<MDisps *>(layer->data), layer->flag & CD_FLAG_EXTERNAL);
}
else if (layer->type == CD_GRID_PAINT_MASK) {
- blend_read_paint_mask(reader, count, layer->data);
+ blend_read_paint_mask(reader, count, static_cast<GridPaintMask *>(layer->data));
}
i++;
}
@@ -5275,3 +5205,33 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
CustomData_update_typemap(data);
}
+
+#ifndef NDEBUG
+
+void CustomData_debug_info_from_layers(const CustomData *data, const char *indent, DynStr *dynstr)
+{
+ for (int type = 0; type < CD_NUMTYPES; type++) {
+ if (CustomData_has_layer(data, type)) {
+ /* NOTE: doesn't account for multiple layers. */
+ const char *name = CustomData_layertype_name(type);
+ const int size = CustomData_sizeof(type);
+ const void *pt = CustomData_get_layer(data, type);
+ const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
+ const char *structname;
+ int structnum;
+ CustomData_file_write_info(type, &structname, &structnum);
+ BLI_dynstr_appendf(
+ dynstr,
+ "%sdict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
+ indent,
+ name,
+ structname,
+ type,
+ (const void *)pt,
+ size,
+ pt_size);
+ }
+ }
+}
+
+#endif /* NDEBUG */
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index b83621e8b79..0ad7efb6347 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -93,10 +93,6 @@ void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types,
}
}
-/**
- * Check what can do each layer type
- * (if it is actually handled by transfer-data, if it supports advanced mixing.
- */
bool BKE_object_data_transfer_get_dttypes_capacity(const int dtdata_types,
bool *r_advanced_mixing,
bool *r_threshold)
@@ -277,7 +273,6 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
const int num_polys_dst = me_dst->totpoly;
MLoop *loops_dst = me_dst->mloop;
const int num_loops_dst = me_dst->totloop;
- CustomData *pdata_dst = &me_dst->pdata;
CustomData *ldata_dst = &me_dst->ldata;
const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0;
@@ -288,26 +283,9 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
BLI_assert(CustomData_get_layer(&me_src->pdata, CD_NORMAL) != NULL);
(void)me_src;
- float(*poly_nors_dst)[3];
float(*loop_nors_dst)[3];
short(*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- const bool do_poly_nors_dst = (poly_nors_dst == NULL);
- if (do_poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst || do_poly_nors_dst) {
- BKE_mesh_calc_normals_poly(verts_dst,
- num_verts_dst,
- loops_dst,
- num_loops_dst,
- polys_dst,
- num_polys_dst,
- poly_nors_dst);
- }
/* Cache loop nors into a temp CDLayer. */
loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
const bool do_loop_nors_dst = (loop_nors_dst == NULL);
@@ -317,6 +295,7 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
}
if (dirty_nors_dst || do_loop_nors_dst) {
BKE_mesh_normals_loop_split(verts_dst,
+ BKE_mesh_vertex_normals_ensure(me_dst),
num_verts_dst,
edges_dst,
num_edges_dst,
@@ -324,7 +303,7 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
loop_nors_dst,
num_loops_dst,
polys_dst,
- (const float(*)[3])poly_nors_dst,
+ BKE_mesh_poly_normals_ensure(me_dst),
num_polys_dst,
use_split_nors_dst,
split_angle_dst,
@@ -372,6 +351,7 @@ static void data_transfer_dtdata_type_postprocess(Object *UNUSED(ob_src),
/* Note loop_nors_dst contains our custom normals as transferred from source... */
BKE_mesh_normals_loop_custom_set(verts_dst,
+ BKE_mesh_vertex_normals_ensure(me_dst),
num_verts_dst,
edges_dst,
num_edges_dst,
@@ -1232,12 +1212,6 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
return false;
}
-/**
- * Transfer data *layout* of selected types from source to destination object.
- * By default, it only creates new data layers if needed on \a ob_dst.
- * If \a use_delete is true, it will also delete data layers on \a ob_dst that do not match those
- * from \a ob_src, to get (as much as possible) exact copy of source data layout.
- */
void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob_src,
@@ -1661,7 +1635,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
const int num_polys_dst = me_dst->totpoly;
MLoop *loops_dst = me_dst->mloop;
const int num_loops_dst = me_dst->totloop;
- CustomData *pdata_dst = &me_dst->pdata;
CustomData *ldata_dst = &me_dst->ldata;
MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type);
@@ -1695,6 +1668,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
space_transform,
max_distance,
ray_radius,
+ me_dst,
verts_dst,
num_verts_dst,
edges_dst,
@@ -1704,7 +1678,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
polys_dst,
num_polys_dst,
ldata_dst,
- pdata_dst,
(me_dst->flag & ME_AUTOSMOOTH) != 0,
me_dst->smoothresh,
dirty_nors_dst,
@@ -1755,7 +1728,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
const int num_polys_dst = me_dst->totpoly;
MLoop *loops_dst = me_dst->mloop;
const int num_loops_dst = me_dst->totloop;
- CustomData *pdata_dst = &me_dst->pdata;
if (!geom_map_init[PDATA]) {
const int num_polys_src = me_src->totpoly;
@@ -1786,14 +1758,11 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
space_transform,
max_distance,
ray_radius,
+ me_dst,
verts_dst,
- num_verts_dst,
loops_dst,
- num_loops_dst,
polys_dst,
num_polys_dst,
- pdata_dst,
- dirty_nors_dst,
me_src,
&geom_map[PDATA]);
geom_map_init[PDATA] = true;
diff --git a/source/blender/blenkernel/intern/data_transfer_intern.h b/source/blender/blenkernel/intern/data_transfer_intern.h
index c5d7dd42cb8..b5b3db31fbf 100644
--- a/source/blender/blenkernel/intern/data_transfer_intern.h
+++ b/source/blender/blenkernel/intern/data_transfer_intern.h
@@ -25,52 +25,61 @@
#include "BKE_customdata.h" /* For cd_datatransfer_interp */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct CustomData;
struct CustomDataTransferLayerMap;
struct ListBase;
-float data_transfer_interp_float_do(const int mix_mode,
- const float val_dst,
- const float val_src,
- const float mix_factor);
+float data_transfer_interp_float_do(int mix_mode, float val_dst, float val_src, float mix_factor);
void data_transfer_layersmapping_add_item(struct ListBase *r_map,
- const int data_type,
- const int mix_mode,
- const float mix_factor,
+ int data_type,
+ int mix_mode,
+ float mix_factor,
const float *mix_weights,
const void *data_src,
void *data_dst,
- const int data_src_n,
- const int data_dst_n,
- const size_t elem_size,
- const size_t data_size,
- const size_t data_offset,
- const uint64_t data_flag,
+ int data_src_n,
+ int data_dst_n,
+ size_t elem_size,
+ size_t data_size,
+ size_t data_offset,
+ uint64_t data_flag,
cd_datatransfer_interp interp,
void *interp_data);
/* Type-specific. */
bool data_transfer_layersmapping_vgroups(struct ListBase *r_map,
- const int mix_mode,
- const float mix_factor,
+ int mix_mode,
+ float mix_factor,
const float *mix_weights,
- const int num_elem_dst,
- const bool use_create,
- const bool use_delete,
+ int num_elem_dst,
+ bool use_create,
+ bool use_delete,
struct Object *ob_src,
struct Object *ob_dst,
struct CustomData *cd_src,
struct CustomData *cd_dst,
- const bool use_dupref_dst,
- const int fromlayers,
- const int tolayers);
+ bool use_dupref_dst,
+ int fromlayers,
+ int tolayers);
/* Defined in customdata.c */
+
+/**
+ * Normals are special, we need to take care of source & destination spaces.
+ */
void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLayerMap *laymap,
void *data_dst,
const void **sources,
const float *weights,
- const int count,
- const float mix_factor);
+ int count,
+ float mix_factor);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 13222747a52..6b429a146d4 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -107,11 +107,6 @@ bDeformGroup *BKE_defgroup_duplicate(const bDeformGroup *ingroup)
return outgroup;
}
-/**
- * Overwrite weights filtered by vgroup_subset.
- * - do nothing if neither are set.
- * - add destination weight if needed
- */
void BKE_defvert_copy_subset(MDeformVert *dvert_dst,
const MDeformVert *dvert_src,
const bool *vgroup_subset,
@@ -125,11 +120,6 @@ void BKE_defvert_copy_subset(MDeformVert *dvert_dst,
}
}
-/**
- * Overwrite weights filtered by vgroup_subset and with mirroring specified by the flip map
- * - do nothing if neither are set.
- * - add destination weight if needed
- */
void BKE_defvert_mirror_subset(MDeformVert *dvert_dst,
const MDeformVert *dvert_src,
const bool *vgroup_subset,
@@ -168,11 +158,6 @@ void BKE_defvert_copy(MDeformVert *dvert_dst, const MDeformVert *dvert_src)
}
}
-/**
- * Copy an index from one dvert to another.
- * - do nothing if neither are set.
- * - add destination weight if needed.
- */
void BKE_defvert_copy_index(MDeformVert *dvert_dst,
const int defgroup_dst,
const MDeformVert *dvert_src,
@@ -197,10 +182,6 @@ void BKE_defvert_copy_index(MDeformVert *dvert_dst,
}
}
-/**
- * Only sync over matching weights, don't add or remove groups
- * warning, loop within loop.
- */
void BKE_defvert_sync(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const bool use_ensure)
{
if (dvert_src->totweight && dvert_dst->totweight) {
@@ -221,9 +202,6 @@ void BKE_defvert_sync(MDeformVert *dvert_dst, const MDeformVert *dvert_src, cons
}
}
-/**
- * be sure all flip_map values are valid
- */
void BKE_defvert_sync_mapped(MDeformVert *dvert_dst,
const MDeformVert *dvert_src,
const int *flip_map,
@@ -250,9 +228,6 @@ void BKE_defvert_sync_mapped(MDeformVert *dvert_dst,
}
}
-/**
- * be sure all flip_map values are valid
- */
void BKE_defvert_remap(MDeformVert *dvert, const int *map, const int map_len)
{
MDeformWeight *dw = dvert->dw;
@@ -265,9 +240,6 @@ void BKE_defvert_remap(MDeformVert *dvert, const int *map, const int map_len)
}
}
-/**
- * Same as #BKE_defvert_normalize but takes a bool array.
- */
void BKE_defvert_normalize_subset(MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot)
@@ -334,9 +306,6 @@ void BKE_defvert_normalize(MDeformVert *dvert)
}
}
-/**
- * Same as BKE_defvert_normalize() if the locked vgroup is not a member of the subset
- */
void BKE_defvert_normalize_lock_single(MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot,
@@ -391,9 +360,6 @@ void BKE_defvert_normalize_lock_single(MDeformVert *dvert,
}
}
-/**
- * Same as BKE_defvert_normalize() if no locked vgroup is a member of the subset
- */
void BKE_defvert_normalize_lock_map(MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot,
@@ -557,11 +523,35 @@ bDeformGroup *BKE_object_defgroup_find_name(const Object *ob, const char *name)
int BKE_id_defgroup_name_index(const ID *id, const char *name)
{
- if (name == NULL || name[0] == '\0') {
+ int index;
+ if (!BKE_id_defgroup_name_find(id, name, &index, NULL)) {
return -1;
}
+ return index;
+}
+
+bool BKE_id_defgroup_name_find(const struct ID *id,
+ const char *name,
+ int *r_index,
+ struct bDeformGroup **r_group)
+{
+ if (name == NULL || name[0] == '\0') {
+ return false;
+ }
const ListBase *defbase = BKE_id_defgroup_list_get(id);
- return BLI_findstringindex(defbase, name, offsetof(bDeformGroup, name));
+ int index;
+ LISTBASE_FOREACH_INDEX (bDeformGroup *, group, defbase, index) {
+ if (STREQ(name, group->name)) {
+ if (r_index != NULL) {
+ *r_index = index;
+ }
+ if (r_group != NULL) {
+ *r_group = group;
+ }
+ return true;
+ }
+ }
+ return false;
}
const ListBase *BKE_object_defgroup_list(const Object *ob)
@@ -586,17 +576,11 @@ int BKE_object_defgroup_count(const Object *ob)
return BLI_listbase_count(BKE_object_defgroup_list(ob));
}
-/**
- * \note For historical reasons, the index starts at 1 rather than 0.
- */
int BKE_object_defgroup_active_index_get(const Object *ob)
{
return *object_defgroup_active_index_get_p(ob);
}
-/**
- * \note For historical reasons, the index starts at 1 rather than 0.
- */
void BKE_object_defgroup_active_index_set(Object *ob, const int new_index)
{
/* Cast away const just for the accessor. */
@@ -604,9 +588,6 @@ void BKE_object_defgroup_active_index_set(Object *ob, const int new_index)
*index = new_index;
}
-/**
- * \note caller must free.
- */
int *BKE_object_defgroup_flip_map(const Object *ob, int *flip_map_len, const bool use_default)
{
const ListBase *defbase = BKE_object_defgroup_list(ob);
@@ -646,9 +627,6 @@ int *BKE_object_defgroup_flip_map(const Object *ob, int *flip_map_len, const boo
return map;
}
-/**
- * \note caller must free.
- */
int *BKE_object_defgroup_flip_map_single(const Object *ob,
int *flip_map_len,
const bool use_default,
@@ -745,13 +723,6 @@ float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgrou
return dw ? dw->weight : 0.0f;
}
-/**
- * Take care with this the rationale is:
- * - if the object has no vertex group. act like vertex group isn't set and return 1.0,
- * - if the vertex group exists but the 'defgroup' isn't found on this vertex, _still_ return 0.0
- *
- * This is a bit confusing, just saves some checks from the caller.
- */
float BKE_defvert_array_find_weight_safe(const struct MDeformVert *dvert,
const int index,
const int defgroup)
@@ -790,11 +761,6 @@ MDeformWeight *BKE_defvert_find_index(const MDeformVert *dvert, const int defgro
return NULL;
}
-/**
- * Ensures that mv has a deform weight entry for the specified defweight group.
- *
- * \note this function is mirrored in editmesh_tools.c, for use for editvertices.
- */
MDeformWeight *BKE_defvert_ensure_index(MDeformVert *dvert, const int defgroup)
{
MDeformWeight *dw_new;
@@ -826,15 +792,10 @@ MDeformWeight *BKE_defvert_ensure_index(MDeformVert *dvert, const int defgroup)
return dw_new;
}
-/* TODO: merge with code above! */
-
-/**
- * Adds the given vertex to the specified vertex group, with given weight.
- *
- * \warning this does NOT check for existing, assume caller already knows its not there.
- */
void BKE_defvert_add_index_notest(MDeformVert *dvert, int defgroup, const float weight)
{
+ /* TODO: merge with #BKE_defvert_ensure_index! */
+
MDeformWeight *dw_new;
/* do this check always, this function is used to check for it */
@@ -856,11 +817,6 @@ void BKE_defvert_add_index_notest(MDeformVert *dvert, int defgroup, const float
dvert->totweight++;
}
-/**
- * Removes the given vertex from the vertex group.
- *
- * \warning This function frees the given MDeformWeight, do not use it afterward!
- */
void BKE_defvert_remove_group(MDeformVert *dvert, MDeformWeight *dw)
{
if (dvert && dw) {
@@ -899,10 +855,6 @@ void BKE_defvert_clear(MDeformVert *dvert)
dvert->totweight = 0;
}
-/**
- * \return The first group index shared by both deform verts
- * or -1 if none are found.
- */
int BKE_defvert_find_shared(const MDeformVert *dvert_a, const MDeformVert *dvert_b)
{
if (dvert_a->totweight && dvert_b->totweight) {
@@ -919,9 +871,6 @@ int BKE_defvert_find_shared(const MDeformVert *dvert_a, const MDeformVert *dvert
return -1;
}
-/**
- * return true if has no weights
- */
bool BKE_defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgroup_tot)
{
MDeformWeight *dw = dvert->dw;
@@ -936,9 +885,6 @@ bool BKE_defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgr
return true;
}
-/**
- * \return The total weight in all groups marked in the selection mask.
- */
float BKE_defvert_total_selected_weight(const struct MDeformVert *dv,
int defbase_tot,
const bool *defbase_sel)
@@ -961,14 +907,6 @@ float BKE_defvert_total_selected_weight(const struct MDeformVert *dv,
return total;
}
-/**
- * \return The representative weight of a multipaint group, used for
- * viewport colors and actual painting.
- *
- * Result equal to sum of weights with auto normalize, and average otherwise.
- * Value is not clamped, since painting relies on multiplication being always
- * commutative with the collective weight function.
- */
float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
int defbase_tot,
const bool *defbase_sel,
@@ -986,11 +924,6 @@ float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
return total;
}
-/**
- * Computes the display weight for the lock relative weight paint mode.
- *
- * \return weight divided by 1-locked_weight with division by zero check
- */
float BKE_defvert_calc_lock_relative_weight(float weight,
float locked_weight,
float unlocked_weight)
@@ -1019,11 +952,6 @@ float BKE_defvert_calc_lock_relative_weight(float weight,
return weight / (1.0f - locked_weight);
}
-/**
- * Computes the display weight for the lock relative weight paint mode, using weight data.
- *
- * \return weight divided by unlocked, or 1-locked_weight with division by zero check.
- */
float BKE_defvert_lock_relative_weight(float weight,
const struct MDeformVert *dv,
int defbase_tot,
@@ -1115,10 +1043,6 @@ void BKE_defvert_extract_vgroup_to_vertweights(MDeformVert *dvert,
}
}
-/**
- * The following three make basic interpolation,
- * using temp vert_weights array to avoid looking up same weight several times.
- */
void BKE_defvert_extract_vgroup_to_edgeweights(MDeformVert *dvert,
const int defgroup,
const int num_verts,
@@ -1451,7 +1375,7 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map,
* and even have to support NULL data_src in transfer data code
* (we always create a data_dst, though).
*
- * Note: Above comment is outdated, but this function was written when that was true.
+ * NOTE: Above comment is outdated, but this function was written when that was true.
*/
const ListBase *src_defbase = BKE_object_defgroup_list(ob_src);
diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc
index 0776f3b9a68..78177095a77 100644
--- a/source/blender/blenkernel/intern/displist.cc
+++ b/source/blender/blenkernel/intern/displist.cc
@@ -47,7 +47,6 @@
#include "BKE_anim_path.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
-#include "BKE_font.h"
#include "BKE_geometry_set.hh"
#include "BKE_key.h"
#include "BKE_lattice.h"
@@ -58,6 +57,7 @@
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_spline.hh"
+#include "BKE_vfont.h"
#include "BLI_sys_types.h" /* For #intptr_t support. */
@@ -66,8 +66,6 @@
using blender::IndexRange;
-static void boundbox_displist_object(Object *ob);
-
static void displist_elem_free(DispList *dl)
{
if (dl) {
@@ -318,7 +316,7 @@ static void curve_to_displist(const Curve *cu,
* and resolution > 1. */
const bool use_cyclic_sample = is_cyclic && (samples_len != 2);
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
/* Add one to the length because of 'BKE_curve_forward_diff_bezier'. */
dl->verts = (float *)MEM_mallocN(sizeof(float[3]) * (samples_len + 1), __func__);
BLI_addtail(r_dispbase, dl);
@@ -373,7 +371,7 @@ static void curve_to_displist(const Curve *cu,
}
else if (nu->type == CU_NURBS) {
const int len = (resolution * SEGMENTSU(nu));
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__);
BLI_addtail(r_dispbase, dl);
dl->parts = 1;
@@ -386,7 +384,7 @@ static void curve_to_displist(const Curve *cu,
}
else if (nu->type == CU_POLY) {
const int len = nu->pntsu;
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__);
BLI_addtail(r_dispbase, dl);
dl->parts = 1;
@@ -404,12 +402,6 @@ static void curve_to_displist(const Curve *cu,
}
}
-/**
- * \param normal_proj: Optional normal that's used to project the scanfill verts into 2d coords.
- * Pass this along if known since it saves time calculating the normal.
- * This is also used to initialize #DispList.nors (one normal per display list).
- * \param flipnormal: Flip the normal (same as passing \a normal_proj negated)
- */
void BKE_displist_fill(const ListBase *dispbase,
ListBase *to,
const float normal_proj[3],
@@ -483,7 +475,7 @@ void BKE_displist_fill(const ListBase *dispbase,
const int triangles_len = BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal_proj);
if (totvert != 0 && triangles_len != 0) {
- DispList *dlnew = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dlnew = MEM_cnew<DispList>(__func__);
dlnew->type = DL_INDEX3;
dlnew->flag = (dl_flag_accum & (DL_BACK_CURVE | DL_FRONT_CURVE));
dlnew->rt = (dl_rt_accum & CU_SMOOTH);
@@ -538,7 +530,7 @@ static void bevels_to_filledpoly(const Curve *cu, ListBase *dispbase)
if (dl->type == DL_SURF) {
if ((dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U) == 0) {
if ((cu->flag & CU_BACK) && (dl->flag & DL_BACK_CURVE)) {
- DispList *dlnew = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dlnew = MEM_cnew<DispList>(__func__);
BLI_addtail(&front, dlnew);
dlnew->verts = (float *)MEM_mallocN(sizeof(float[3]) * dl->parts, __func__);
dlnew->nr = dl->parts;
@@ -557,7 +549,7 @@ static void bevels_to_filledpoly(const Curve *cu, ListBase *dispbase)
}
}
if ((cu->flag & CU_FRONT) && (dl->flag & DL_FRONT_CURVE)) {
- DispList *dlnew = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dlnew = MEM_cnew<DispList>(__func__);
BLI_addtail(&back, dlnew);
dlnew->verts = (float *)MEM_mallocN(sizeof(float[3]) * dl->parts, __func__);
dlnew->nr = dl->parts;
@@ -673,7 +665,7 @@ void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob)
BKE_displist_free(&(ob->runtime.curve_cache->disp));
}
else {
- ob->runtime.curve_cache = (CurveCache *)MEM_callocN(sizeof(CurveCache), __func__);
+ ob->runtime.curve_cache = MEM_cnew<CurveCache>(__func__);
}
BKE_mball_polygonize(depsgraph, scene, ob, &ob->runtime.curve_cache->disp);
@@ -832,7 +824,7 @@ static bool do_curve_implicit_mesh_conversion(const Curve *curve,
}
/* Curve objects with implicit "tube" meshes should convert implicitly to a mesh. */
- if (curve->ext1 != 0.0f || curve->ext2 != 0.0f) {
+ if (curve->extrude != 0.0f || curve->bevel_radius != 0.0f) {
return true;
}
@@ -912,7 +904,7 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
int totvert;
float(*vertex_coords)[3] = BKE_mesh_vert_coords_alloc(mesh, &totvert);
if (mti->dependsOnNormals != nullptr && mti->dependsOnNormals(md)) {
- BKE_mesh_ensure_normals(mesh);
+ BKE_mesh_vertex_normals_ensure(mesh);
}
mti->deformVerts(md, &mectx_deform, mesh, vertex_coords, totvert);
BKE_mesh_vert_coords_apply(mesh, vertex_coords);
@@ -920,7 +912,7 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
}
else {
if (mti->dependsOnNormals != nullptr && mti->dependsOnNormals(md)) {
- BKE_mesh_ensure_normals(mesh);
+ BKE_mesh_vertex_normals_ensure(mesh);
}
Mesh *output_mesh = mti->modifyMesh(md, &mectx_apply, mesh);
if (mesh != output_mesh) {
@@ -932,7 +924,7 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
if (geometry_set.has_mesh()) {
Mesh *final_mesh = geometry_set.get_mesh_for_write();
- BKE_mesh_calc_normals(final_mesh);
+ BKE_mesh_ensure_normals_for_display(final_mesh);
BLI_strncpy(final_mesh->id.name, cu->id.name, sizeof(final_mesh->id.name));
*((short *)final_mesh->id.name) = ID_ME;
@@ -1004,7 +996,7 @@ static void evaluate_surface_object(Depsgraph *depsgraph,
if (nu->pntsv == 1) {
const int len = SEGMENTSU(nu) * resolu;
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__);
BLI_addtail(r_dispbase, dl);
@@ -1027,7 +1019,7 @@ static void evaluate_surface_object(Depsgraph *depsgraph,
else {
const int len = (nu->pntsu * resolu) * (nu->pntsv * resolv);
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__);
BLI_addtail(r_dispbase, dl);
@@ -1130,7 +1122,7 @@ static void fillBevelCap(const Nurb *nu,
const float *prev_fp,
ListBase *dispbase)
{
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(sizeof(float[3]) * dlb->nr, __func__);
memcpy(dl->verts, prev_fp, sizeof(float[3]) * dlb->nr);
@@ -1312,11 +1304,11 @@ static GeometrySet evaluate_curve_type_object(Depsgraph *depsgraph,
ListBase dlbev = BKE_curve_bevel_make(cu);
/* no bevel or extrude, and no width correction? */
- if (BLI_listbase_is_empty(&dlbev) && cu->width == 1.0f) {
+ if (BLI_listbase_is_empty(&dlbev) && cu->offset == 1.0f) {
curve_to_displist(cu, deformed_nurbs, for_render, r_dispbase);
}
else {
- const float widfac = cu->width - 1.0f;
+ const float widfac = cu->offset - 1.0f;
const BevList *bl = (BevList *)ob->runtime.curve_cache->bev.first;
const Nurb *nu = (Nurb *)deformed_nurbs->first;
@@ -1329,7 +1321,7 @@ static GeometrySet evaluate_curve_type_object(Depsgraph *depsgraph,
/* exception handling; curve without bevel or extrude, with width correction */
if (BLI_listbase_is_empty(&dlbev)) {
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), "makeDispListbev");
+ DispList *dl = MEM_cnew<DispList>("makeDispListbev");
dl->verts = (float *)MEM_mallocN(sizeof(float[3]) * bl->nr, "dlverts");
BLI_addtail(r_dispbase, dl);
@@ -1379,7 +1371,7 @@ static GeometrySet evaluate_curve_type_object(Depsgraph *depsgraph,
LISTBASE_FOREACH (DispList *, dlb, &dlbev) {
/* for each part of the bevel use a separate displblock */
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = data = (float *)MEM_mallocN(sizeof(float[3]) * dlb->nr * steps, __func__);
BLI_addtail(r_dispbase, dl);
@@ -1503,7 +1495,7 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph,
BKE_object_free_derived_caches(ob);
cow_curve.curve_eval = nullptr;
- ob->runtime.curve_cache = (CurveCache *)MEM_callocN(sizeof(CurveCache), __func__);
+ ob->runtime.curve_cache = MEM_cnew<CurveCache>(__func__);
ListBase *dispbase = &ob->runtime.curve_cache->disp;
if (ob->type == OB_SURF) {
@@ -1524,20 +1516,11 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph,
cow_curve.curve_eval = curve_component.get_for_write();
BKE_object_eval_assign_data(ob, &cow_curve.id, false);
}
- else if (geometry.has_mesh()) {
- /* Most areas of Blender don't yet know how to look in #geometry_set_eval for evaluated mesh
- * data, and look in #data_eval instead. When the object evaluates to a curve, that field
- * must be used for the evaluated curve data, but otherwise we can use the field to store a
- * pointer to the mesh, so more areas can retrieve the mesh. */
- MeshComponent &mesh_component = geometry.get_component_for_write<MeshComponent>();
- Mesh *mesh_eval = mesh_component.get_for_write();
- BKE_object_eval_assign_data(ob, &mesh_eval->id, false);
- }
ob->runtime.geometry_set_eval = new GeometrySet(std::move(geometry));
}
- boundbox_displist_object(ob);
+ BKE_object_boundbox_calc_from_evaluated_geometry(ob);
}
void BKE_displist_minmax(const ListBase *dispbase, float min[3], float max[3])
@@ -1545,7 +1528,7 @@ void BKE_displist_minmax(const ListBase *dispbase, float min[3], float max[3])
bool doit = false;
LISTBASE_FOREACH (const DispList *, dl, dispbase) {
- const int tot = (dl->type == DL_INDEX3) ? dl->nr : dl->nr * dl->parts;
+ const int tot = (ELEM(dl->type, DL_INDEX3, DL_INDEX4)) ? dl->nr : dl->nr * dl->parts;
for (const int i : IndexRange(tot)) {
minmax_v3v3_v3(min, max, &dl->verts[i * 3]);
}
@@ -1560,30 +1543,3 @@ void BKE_displist_minmax(const ListBase *dispbase, float min[3], float max[3])
zero_v3(max);
}
}
-
-/* this is confusing, there's also min_max_object, applying the obmat... */
-static void boundbox_displist_object(Object *ob)
-{
- BLI_assert(ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT));
- /* Curve's BB is already calculated as a part of modifier stack,
- * here we only calculate object BB based on final display list. */
-
- /* object's BB is calculated from final displist */
- if (ob->runtime.bb == nullptr) {
- ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), __func__);
- }
-
- const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
- if (mesh_eval) {
- BKE_object_boundbox_calc_from_mesh(ob, mesh_eval);
- }
- else {
- float min[3], max[3];
-
- INIT_MINMAX(min, max);
- BKE_displist_minmax(&ob->runtime.curve_cache->disp, min, max);
- BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
-
- ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
- }
-}
diff --git a/source/blender/blenkernel/intern/displist_tangent.c b/source/blender/blenkernel/intern/displist_tangent.c
index 5c969d52aea..4451961ad94 100644
--- a/source/blender/blenkernel/intern/displist_tangent.c
+++ b/source/blender/blenkernel/intern/displist_tangent.c
@@ -29,6 +29,10 @@
/* interface */
#include "mikktspace.h"
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
typedef struct {
const DispList *dl;
float (*tangent)[4]; /* destination */
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 9083c507160..64e0427a810 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -112,7 +112,7 @@ static int neighStraightY[8] = {0, 1, 0, -1, 1, 1, -1, -1};
#define SUBFRAME_RECURSION 5
/* surface_getBrushFlags() return vals */
#define BRUSH_USES_VELOCITY (1 << 0)
-/* brush mesh raycast status */
+/* Brush mesh ray-cast status. */
#define HIT_VOLUME 1
#define HIT_PROXIMITY 2
/* dynamicPaint_findNeighborPixel() return codes */
@@ -327,7 +327,6 @@ static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface)
return 0;
}
-/* get currently active surface (in user interface) */
DynamicPaintSurface *get_activeSurface(DynamicPaintCanvasSettings *canvas)
{
return BLI_findlink(&canvas->surfaces, canvas->active_sur);
@@ -420,7 +419,6 @@ void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, const char
surface_duplicateNameExists, surface, name, '.', surface->name, sizeof(surface->name));
}
-/* change surface data to defaults on new type */
void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface)
{
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
@@ -763,7 +761,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
copy_v3_v3(bData->dim, dim);
min_dim = max_fff(td[0], td[1], td[2]) / 1000.0f;
- /* deactivate zero axises */
+ /* deactivate zero axes */
for (i = 0; i < 3; i++) {
if (td[i] < min_dim) {
td[i] = 1.0f;
@@ -784,7 +782,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
dim_factor = (float)pow((double)volume / ((double)sData->total_points / 10000.0),
1.0 / (double)axis);
- /* define final grid size using dim_factor, use min 3 for active axises */
+ /* define final grid size using dim_factor, use min 3 for active axes */
for (i = 0; i < 3; i++) {
grid->dim[i] = (int)floor(td[i] / dim_factor);
CLAMP(grid->dim[i], (dim[i] >= min_dim) ? 3 : 1, 100);
@@ -855,7 +853,6 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
/***************************** Freeing data ******************************/
-/* Free brush data */
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
{
if (pmd->brush) {
@@ -992,7 +989,6 @@ void dynamicPaint_freeSurface(const DynamicPaintModifierData *pmd, DynamicPaintS
MEM_freeN(surface);
}
-/* Free canvas data */
void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
{
if (pmd->canvas) {
@@ -1011,7 +1007,6 @@ void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
}
}
-/* Free whole dp modifier */
void dynamicPaint_Modifier_free(DynamicPaintModifierData *pmd)
{
if (pmd == NULL) {
@@ -1024,11 +1019,6 @@ void dynamicPaint_Modifier_free(DynamicPaintModifierData *pmd)
/***************************** Initialize and reset ******************************/
-/*
- * Creates a new surface and adds it to the list
- * If scene is null, frame range of 1-250 is used
- * A pointer to this surface is returned
- */
DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *canvas,
Scene *scene)
{
@@ -1106,9 +1096,6 @@ DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *c
return surface;
}
-/*
- * Initialize modifier data
- */
bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene)
{
if (pmd) {
@@ -1721,7 +1708,6 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
}
}
-/* clears surface data back to zero */
void dynamicPaint_clearSurface(const Scene *scene, DynamicPaintSurface *surface)
{
PaintSurfaceData *sData = surface->data;
@@ -1751,7 +1737,6 @@ void dynamicPaint_clearSurface(const Scene *scene, DynamicPaintSurface *surface)
}
}
-/* Completely (re)initializes surface (only for point cache types). */
bool dynamicPaint_resetSurface(const Scene *scene, DynamicPaintSurface *surface)
{
int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
@@ -1804,6 +1789,7 @@ typedef struct DynamicPaintModifierApplyData {
Object *ob;
MVert *mvert;
+ const float (*vert_normals)[3];
const MLoop *mloop;
const MPoly *mpoly;
@@ -1821,14 +1807,11 @@ static void dynamic_paint_apply_surface_displace_cb(void *__restrict userdata,
const DynamicPaintSurface *surface = data->surface;
MVert *mvert = data->mvert;
- float normal[3];
const float *value = (float *)surface->data->type_data;
const float val = value[i] * surface->disp_factor;
- normal_short_to_float_v3(normal, mvert[i].no);
-
/* same as 'mvert[i].co[0] -= normal[0] * val' etc. */
- madd_v3_v3fl(mvert[i].co, normal, -val);
+ madd_v3_v3fl(mvert[i].co, data->vert_normals[i], -val);
}
/* apply displacing vertex surface to the derived mesh */
@@ -1847,6 +1830,7 @@ static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Mesh
DynamicPaintModifierApplyData data = {
.surface = surface,
.mvert = mvert,
+ .vert_normals = BKE_mesh_vertex_normals_ensure(result),
};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -1913,10 +1897,8 @@ static void dynamic_paint_apply_surface_wave_cb(void *__restrict userdata,
PaintWavePoint *wPoint = (PaintWavePoint *)data->surface->data->type_data;
MVert *mvert = data->mvert;
- float normal[3];
- normal_short_to_float_v3(normal, mvert[i].no);
- madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
+ madd_v3_v3fl(mvert[i].co, data->vert_normals[i], wPoint[i].height);
}
/*
@@ -2045,6 +2027,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *
DynamicPaintModifierApplyData data = {
.surface = surface,
.mvert = mvert,
+ .vert_normals = BKE_mesh_vertex_normals_ensure(result),
};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -2079,7 +2062,6 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *
return result;
}
-/* update cache frame range */
void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface)
{
if (surface->pointcache) {
@@ -2189,7 +2171,6 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd,
}
}
-/* Modifier call. Processes dynamic paint modifier step. */
Mesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd,
struct Depsgraph *depsgraph,
Scene *scene,
@@ -3436,7 +3417,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface,
/***************************** Ray / Nearest Point Utils ******************************/
-/* A modified callback to bvh tree raycast.
+/* A modified callback to bvh tree ray-cast.
* The tree must have been built using bvhtree_from_mesh_looptri.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
*
@@ -4107,7 +4088,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
hit.index = -1;
hit.dist = brush_radius;
- /* Do a face normal directional raycast, and use that distance */
+ /* Do a face normal directional ray-cast, and use that distance. */
BLI_bvhtree_ray_cast(
treeData->tree, ray_start, proj_ray, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
if (hit.index != -1) {
@@ -4304,6 +4285,7 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph,
mesh = BKE_mesh_copy_for_eval(brush_mesh, false);
mvert = mesh->mvert;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
mloop = mesh->mloop;
numOfVerts = mesh->totvert;
@@ -4318,7 +4300,7 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph,
/* for proximity project calculate average normal */
if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
float nor[3];
- normal_short_to_float_v3(nor, mvert[ii].no);
+ copy_v3_v3(nor, vert_normals[ii]);
mul_mat3_m4_v3(brushOb->obmat, nor);
normalize_v3(nor);
@@ -4597,7 +4579,7 @@ static bool dynamicPaint_paintParticles(DynamicPaintSurface *surface,
}
/*
- * Build a kd-tree to optimize distance search
+ * Build a KD-tree to optimize distance search
*/
tree = BLI_kdtree_3d_new(psys->totpart);
@@ -5883,8 +5865,7 @@ static void dynamic_paint_surface_pre_step_cb(void *__restrict userdata,
}
/* dissolve for float types */
else if (surface->flags & MOD_DPAINT_DISSOLVE &&
- (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)) {
+ ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WEIGHT)) {
float *point = &((float *)sData->type_data)[index];
/* log or linear */
value_dissolve(
@@ -5927,6 +5908,7 @@ typedef struct DynamicPaintGenerateBakeData {
Object *ob;
const MVert *mvert;
+ const float (*vert_normals)[3];
const Vec3f *canvas_verts;
const bool do_velocity_data;
@@ -5946,7 +5928,6 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
Object *ob = data->ob;
- const MVert *mvert = data->mvert;
const Vec3f *canvas_verts = data->canvas_verts;
const bool do_velocity_data = data->do_velocity_data;
@@ -5980,9 +5961,9 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
}
/* Calculate current pixel surface normal */
- normal_short_to_float_v3(n1, mvert[tPoint->v1].no);
- normal_short_to_float_v3(n2, mvert[tPoint->v2].no);
- normal_short_to_float_v3(n3, mvert[tPoint->v3].no);
+ copy_v3_v3(n1, data->vert_normals[tPoint->v1]);
+ copy_v3_v3(n2, data->vert_normals[tPoint->v2]);
+ copy_v3_v3(n3, data->vert_normals[tPoint->v3]);
interp_v3_v3v3v3(
temp_nor, n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
@@ -6024,7 +6005,7 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
}
/* normal */
- normal_short_to_float_v3(temp_nor, mvert[index].no);
+ copy_v3_v3(temp_nor, data->vert_normals[index]);
if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
/* Prepare surface normal directional scale to easily convert
* brush intersection amount between global and local space */
@@ -6163,6 +6144,7 @@ static bool dynamicPaint_generateBakeData(DynamicPaintSurface *surface,
.surface = surface,
.ob = ob,
.mvert = mvert,
+ .vert_normals = BKE_mesh_vertex_normals_ensure(mesh),
.canvas_verts = canvas_verts,
.do_velocity_data = do_velocity_data,
.new_bdata = new_bdata,
@@ -6370,9 +6352,6 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph,
return ret;
}
-/**
- * Calculate a single frame and included sub-frames for surface.
- */
int dynamicPaint_calculateFrame(DynamicPaintSurface *surface,
struct Depsgraph *depsgraph,
Scene *scene,
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 83e03ef44f5..0774a1a3d88 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -39,10 +39,8 @@
#include "BKE_mesh_wrapper.h"
#include "BKE_object.h"
-/**
- * \note The caller is responsible for ensuring triangulation data,
- * typically by calling #BKE_editmesh_looptri_calc.
- */
+#include "DEG_depsgraph_query.h"
+
BMEditMesh *BKE_editmesh_create(BMesh *bm)
{
BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__);
@@ -55,9 +53,6 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
BMEditMesh *em_copy = MEM_callocN(sizeof(BMEditMesh), __func__);
*em_copy = *em;
- em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL;
- em_copy->bb_cage = NULL;
-
em_copy->bm = BM_mesh_copy(em->bm);
/* The tessellation is NOT calculated on the copy here,
@@ -75,12 +70,6 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
return em_copy;
}
-/**
- * \brief Return the BMEditMesh for a given object
- *
- * \note this function assumes this is a mesh object,
- * don't add NULL data check here. caller must do that
- */
BMEditMesh *BKE_editmesh_from_object(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
@@ -158,10 +147,6 @@ void BKE_editmesh_looptri_calc(BMEditMesh *em)
});
}
-/**
- * Performing the face normal calculation at the same time as tessellation
- * gives a reasonable performance boost (approx ~20% faster).
- */
void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em)
{
BKE_editmesh_looptri_calc_ex(em,
@@ -208,23 +193,8 @@ void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em,
});
}
-void BKE_editmesh_free_derived_caches(BMEditMesh *em)
-{
- if (em->mesh_eval_cage) {
- BKE_id_free(NULL, em->mesh_eval_cage);
- }
- if (em->mesh_eval_final && em->mesh_eval_final != em->mesh_eval_cage) {
- BKE_id_free(NULL, em->mesh_eval_final);
- }
- em->mesh_eval_cage = em->mesh_eval_final = NULL;
-
- MEM_SAFE_FREE(em->bb_cage);
-}
-
-/* Does not free the #BMEditMesh struct itself. */
void BKE_editmesh_free_data(BMEditMesh *em)
{
- BKE_editmesh_free_derived_caches(em);
if (em->looptris) {
MEM_freeN(em->looptris);
@@ -244,8 +214,7 @@ struct CageUserData {
static void cage_mapped_verts_callback(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
struct CageUserData *data = userData;
@@ -299,13 +268,15 @@ const float (*BKE_editmesh_vert_coords_when_deformed(struct Depsgraph *depsgraph
*r_is_alloc = false;
Mesh *me = ob->data;
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object_eval);
if ((me->runtime.edit_data != NULL) && (me->runtime.edit_data->vertexCos != NULL)) {
/* Deformed, and we have deformed coords already. */
coords = me->runtime.edit_data->vertexCos;
}
- else if ((em->mesh_eval_final != NULL) &&
- (em->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
+ else if ((editmesh_eval_final != NULL) &&
+ (editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
/* If this is an edit-mesh type, leave NULL as we can use the vertex coords. */
}
else {
@@ -342,7 +313,6 @@ void BKE_editmesh_lnorspace_update(BMEditMesh *em, Mesh *me)
BM_lnorspace_update(bm);
}
-/* If autosmooth not already set, set it */
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, Mesh *me)
{
if (!(me->flag & ME_AUTOSMOOTH)) {
@@ -351,18 +321,18 @@ void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, Mesh *me)
}
}
-BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em)
+BoundBox *BKE_editmesh_cage_boundbox_get(struct Object *object, BMEditMesh *UNUSED(em))
{
- if (em->bb_cage == NULL) {
+ if (object->runtime.editmesh_bb_cage == NULL) {
float min[3], max[3];
INIT_MINMAX(min, max);
- if (em->mesh_eval_cage) {
- BKE_mesh_wrapper_minmax(em->mesh_eval_cage, min, max);
+ if (object->runtime.editmesh_eval_cage) {
+ BKE_mesh_wrapper_minmax(object->runtime.editmesh_eval_cage, min, max);
}
- em->bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage");
- BKE_boundbox_init_from_minmax(em->bb_cage, min, max);
+ object->runtime.editmesh_bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage");
+ BKE_boundbox_init_from_minmax(object->runtime.editmesh_bb_cage, min, max);
}
- return em->bb_cage;
+ return object->runtime.editmesh_bb_cage;
}
diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c
index 087481b1b5d..e200a504b5d 100644
--- a/source/blender/blenkernel/intern/editmesh_bvh.c
+++ b/source/blender/blenkernel/intern/editmesh_bvh.c
@@ -221,7 +221,7 @@ static void bmbvh_tri_from_face(const float *cos[3],
}
}
-/* taken from bvhutils.c */
+/* Taken from `bvhutils.c`. */
/* -------------------------------------------------------------------- */
/* BKE_bmbvh_ray_cast */
@@ -565,9 +565,6 @@ static bool bmbvh_overlap_cb(void *userdata, int index_a, int index_b, int UNUSE
((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon)));
}
-/**
- * Overlap indices reference the looptri's
- */
BVHTreeOverlap *BKE_bmbvh_overlap(const BMBVHTree *bmtree_a,
const BMBVHTree *bmtree_b,
unsigned int *r_overlap_tot)
@@ -591,9 +588,6 @@ static bool bmbvh_overlap_self_cb(void *userdata, int index_a, int index_b, int
return false;
}
-/**
- * Overlap indices reference the looptri's
- */
BVHTreeOverlap *BKE_bmbvh_overlap_self(const BMBVHTree *bmtree, unsigned int *r_overlap_tot)
{
struct BMBVHTree_OverlapData data;
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c
index da4ea742656..ff0d47e534e 100644
--- a/source/blender/blenkernel/intern/editmesh_tangent.c
+++ b/source/blender/blenkernel/intern/editmesh_tangent.c
@@ -273,13 +273,6 @@ static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), vo
}
}
-/**
- * \see #BKE_mesh_calc_loop_tangent, same logic but used arrays instead of #BMesh data.
- *
- * \note This function is not so normal, its using #BMesh.ldata as input,
- * but output's to #Mesh.ldata.
- * This is done because #CD_TANGENT is cache data used only for drawing.
- */
void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME],
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index a88339082fe..bbf9e9edfd2 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -59,6 +59,7 @@
#include "BKE_fluid.h"
#include "BKE_global.h"
#include "BKE_layer.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -221,9 +222,6 @@ static void add_effector_evaluation(ListBase **effectors,
precalculate_effector(depsgraph, eff);
}
-/* Create list of effector relations in the collection or entire scene.
- * This is used by the depsgraph to build relations, as well as faster
- * lookup of effectors during evaluation. */
ListBase *BKE_effector_relations_create(Depsgraph *depsgraph,
ViewLayer *view_layer,
Collection *collection)
@@ -329,7 +327,6 @@ static bool is_effector_relevant(PartDeflect *pd, EffectorWeights *weights, bool
is_effector_nonzero_strength(pd);
}
-/* Create effective list of effectors from relations built beforehand. */
ListBase *BKE_effectors_create(Depsgraph *depsgraph,
Object *ob_src,
ParticleSystem *psys_src,
@@ -656,11 +653,11 @@ float effector_falloff(EffectorCache *eff,
return falloff;
}
-int closest_point_on_surface(SurfaceModifierData *surmd,
- const float co[3],
- float surface_co[3],
- float surface_nor[3],
- float surface_vel[3])
+bool closest_point_on_surface(SurfaceModifierData *surmd,
+ const float co[3],
+ float surface_co[3],
+ float surface_nor[3],
+ float surface_vel[3])
{
BVHTreeNearest nearest;
@@ -687,18 +684,18 @@ int closest_point_on_surface(SurfaceModifierData *surmd,
mul_v3_fl(surface_vel, (1.0f / 3.0f));
}
- return 1;
+ return true;
}
- return 0;
+ return false;
}
-int get_effector_data(EffectorCache *eff,
- EffectorData *efd,
- EffectedPoint *point,
- int real_velocity)
+bool get_effector_data(EffectorCache *eff,
+ EffectorData *efd,
+ EffectedPoint *point,
+ int real_velocity)
{
float cfra = DEG_get_ctime(eff->depsgraph);
- int ret = 0;
+ bool ret = false;
/* In case surface object is in Edit mode when loading the .blend,
* surface modifier is never executed and bvhtree never built, see T48415. */
@@ -719,9 +716,10 @@ int get_effector_data(EffectorCache *eff,
else if (eff->pd && eff->pd->shape == PFIELD_SHAPE_POINTS) {
/* TODO: hair and points object support */
const Mesh *me_eval = BKE_object_get_evaluated_mesh(eff->ob);
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me_eval);
if (me_eval != NULL) {
copy_v3_v3(efd->loc, me_eval->mvert[*efd->index].co);
- normal_short_to_float_v3(efd->nor, me_eval->mvert[*efd->index].no);
+ copy_v3_v3(efd->nor, vert_normals[*efd->index]);
mul_m4_v3(eff->ob->obmat, efd->loc);
mul_mat3_m4_v3(eff->ob->obmat, efd->nor);
@@ -730,7 +728,7 @@ int get_effector_data(EffectorCache *eff,
efd->size = 0.0f;
- ret = 1;
+ ret = true;
}
}
else if (eff->psys) {
@@ -798,7 +796,7 @@ int get_effector_data(EffectorCache *eff,
zero_v3(efd->vel);
efd->size = 0.0f;
- ret = 1;
+ ret = true;
}
if (ret) {
@@ -1130,20 +1128,6 @@ static void do_physical_effector(EffectorCache *eff,
}
}
-/* -------- BKE_effectors_apply() --------
- * generic force/speed system, now used for particles and softbodies
- * scene = scene where it runs in, for time and stuff
- * lb = listbase with objects that take part in effecting
- * opco = global coord, as input
- * force = accumulator for force
- * wind_force = accumulator for force only acting perpendicular to a surface
- * speed = actual current speed which can be altered
- * cur_time = "external" time in frames, is constant for static particles
- * loc_time = "local" time in frames, range <0-1> for the lifetime of particle
- * par_layer = layer the caller is in
- * flags = only used for softbody wind now
- * guide = old speed of particle
- */
void BKE_effectors_apply(ListBase *effectors,
ListBase *colliders,
EffectorWeights *weights,
@@ -1152,6 +1136,22 @@ void BKE_effectors_apply(ListBase *effectors,
float *wind_force,
float *impulse)
{
+ /* WARNING(@campbellbarton): historic comment?
+ * Many of these parameters don't exist!
+ *
+ * scene = scene where it runs in, for time and stuff.
+ * lb = listbase with objects that take part in effecting.
+ * opco = global coord, as input.
+ * force = accumulator for force.
+ * wind_force = accumulator for force only acting perpendicular to a surface.
+ * speed = actual current speed which can be altered.
+ * cur_time = "external" time in frames, is constant for static particles.
+ * loc_time = "local" time in frames, range <0-1> for the lifetime of particle.
+ * par_layer = layer the caller is in.
+ * flags = only used for soft-body wind now.
+ * guide = old speed of particle.
+ */
+
/*
* Modifies the force on a particle according to its
* relation with the effector object
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 8e9c504dcbf..f7a547543af 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -77,7 +77,6 @@ FCurve *BKE_fcurve_create(void)
/** \name F-Curve Data Free
* \{ */
-/* Frees the F-Curve itself too, so make sure BLI_remlink is called before calling this... */
void BKE_fcurve_free(FCurve *fcu)
{
if (fcu == NULL) {
@@ -99,7 +98,6 @@ void BKE_fcurve_free(FCurve *fcu)
MEM_freeN(fcu);
}
-/* Frees a list of F-Curves. */
void BKE_fcurves_free(ListBase *list)
{
FCurve *fcu, *fcn;
@@ -128,7 +126,6 @@ void BKE_fcurves_free(ListBase *list)
/** \name F-Curve Data Copy
* \{ */
-/* Duplicate a F-Curve. */
FCurve *BKE_fcurve_copy(const FCurve *fcu)
{
FCurve *fcu_d;
@@ -161,7 +158,6 @@ FCurve *BKE_fcurve_copy(const FCurve *fcu)
return fcu_d;
}
-/* Duplicate a list of F-Curves. */
void BKE_fcurves_copy(ListBase *dst, ListBase *src)
{
FCurve *dfcu, *sfcu;
@@ -181,10 +177,6 @@ void BKE_fcurves_copy(ListBase *dst, ListBase *src)
}
}
-/**
- * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
- * `IDTypeInfo` structure).
- */
void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data)
{
ChannelDriver *driver = fcu->driver;
@@ -203,21 +195,24 @@ void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data)
switch (fcm->type) {
case FMODIFIER_TYPE_PYTHON: {
FMod_Python *fcm_py = (FMod_Python *)fcm->data;
- BKE_LIB_FOREACHID_PROCESS(data, fcm_py->script, IDWALK_CB_NOP);
-
- IDP_foreach_property(fcm_py->prop,
- IDP_TYPE_FILTER_ID,
- BKE_lib_query_idpropertiesForeachIDLink_callback,
- data);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, fcm_py->script, IDWALK_CB_NOP);
+
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ IDP_foreach_property(fcm_py->prop,
+ IDP_TYPE_FILTER_ID,
+ BKE_lib_query_idpropertiesForeachIDLink_callback,
+ data));
break;
}
+ default:
+ break;
}
}
}
/* ----------------- Finding F-Curves -------------------------- */
-/* High level function to get an fcurve from C without having the RNA. */
FCurve *id_data_find_fcurve(
ID *id, void *data, StructRNA *type, const char *prop_name, int index, bool *r_driven)
{
@@ -269,8 +264,6 @@ FCurve *id_data_find_fcurve(
return fcu;
}
-/* Find the F-Curve affecting the given RNA-access path + index,
- * in the list of F-Curves provided. */
FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_index)
{
FCurve *fcu;
@@ -300,7 +293,6 @@ FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_i
/** \name FCurve Iteration
* \{ */
-/* Quick way to loop over all fcurves of a given 'path'. */
FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[])
{
FCurve *fcu;
@@ -321,18 +313,6 @@ FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[])
return NULL;
}
-/**
- * Get list of LinkData's containing pointers to the F-Curves
- * which control the types of data indicated.
- *
- * Lists...
- * - dst: list of LinkData's matching the criteria returned.
- * List must be freed after use, and is assumed to be empty when passed.
- * - src: list of F-Curves to search through
- * Filters...
- * - dataPrefix: i.e. 'pose.bones[' or 'nodes['
- * - dataName: name of entity within "" immediately following the prefix
- */
int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName)
{
FCurve *fcu;
@@ -432,7 +412,7 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
char *path = NULL;
if (!adt && C) {
- path = BKE_animdata_driver_path_hack(C, &tptr, prop, NULL);
+ path = RNA_path_from_ID_to_property(&tptr, prop);
adt = BKE_animdata_from_id(tptr.owner_id);
step--;
}
@@ -483,7 +463,7 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
}
if (step) {
- char *tpath = BKE_animdata_driver_path_hack(C, &tptr, prop, path);
+ char *tpath = path ? path : RNA_path_from_ID_to_property(&tptr, prop);
if (tpath && tpath != path) {
MEM_freeN(path);
path = tpath;
@@ -597,9 +577,6 @@ static int BKE_fcurve_bezt_binarysearch_index_ex(const BezTriple array[],
return start;
}
-/* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_fcurve)
- * Returns the index to insert at (data already at that index will be offset if replace is 0)
- */
int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[],
const float frame,
const int arraylen,
@@ -663,7 +640,6 @@ static short get_fcurve_end_keyframes(FCurve *fcu,
return found;
}
-/* Calculate the extents of F-Curve's data. */
bool BKE_fcurve_calc_bounds(FCurve *fcu,
float *xmin,
float *xmax,
@@ -794,7 +770,6 @@ bool BKE_fcurve_calc_bounds(FCurve *fcu,
return foundvert;
}
-/* Calculate the extents of F-Curve's keyframes. */
bool BKE_fcurve_calc_range(
FCurve *fcu, float *start, float *end, const bool do_sel_only, const bool do_min_length)
{
@@ -842,14 +817,6 @@ bool BKE_fcurve_calc_range(
return foundvert;
}
-/**
- * Return an array of keyed frames, rounded to `interval`.
- *
- * \param interval: Set to 1.0 to round to whole keyframes, 0.5 for in-between key-frames, etc.
- *
- * \note An interval of zero could be supported (this implies no rounding at all),
- * however this risks very small differences in float values being treated as separate keyframes.
- */
float *BKE_fcurves_calc_keyed_frames_ex(FCurve **fcurve_array,
int fcurve_array_len,
const float interval,
@@ -898,10 +865,6 @@ float *BKE_fcurves_calc_keyed_frames(FCurve **fcurve_array,
/** \name Active Keyframe
* \{ */
-/**
- * Set the index that stores the FCurve's active keyframe, assuming that \a active_bezt
- * is already part of `fcu->bezt`. If NULL, set active keyframe index to "none."
- */
void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt)
{
if (active_bezt == NULL) {
@@ -923,9 +886,6 @@ void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt)
fcu->active_keyframe_index = (int)offset;
}
-/**
- * Get the active keyframe index, with sanity checks for point bounds.
- */
int BKE_fcurve_active_keyframe_index(const FCurve *fcu)
{
const int active_keyframe_index = fcu->active_keyframe_index;
@@ -959,10 +919,6 @@ void BKE_fcurve_keyframe_move_value_with_handles(struct BezTriple *keyframe, con
/** \name Status Checks
* \{ */
-/* Are keyframes on F-Curve of any use?
- * Usability of keyframes refers to whether they should be displayed,
- * and also whether they will have any influence on the final result.
- */
bool BKE_fcurve_are_keyframes_usable(FCurve *fcu)
{
/* F-Curve must exist. */
@@ -1028,9 +984,6 @@ bool BKE_fcurve_is_protected(FCurve *fcu)
return ((fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)));
}
-/* Can keyframes be added to F-Curve?
- * Keyframes can only be added if they are already visible.
- */
bool BKE_fcurve_is_keyframable(FCurve *fcu)
{
/* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */
@@ -1053,7 +1006,6 @@ bool BKE_fcurve_is_keyframable(FCurve *fcu)
/** \name Keyframe Column Tools
* \{ */
-/* Add a BezTriple to a column. */
static void UNUSED_FUNCTION(bezt_add_to_cfra_elem)(ListBase *lb, BezTriple *bezt)
{
CfraElem *ce, *cen;
@@ -1096,18 +1048,12 @@ static void UNUSED_FUNCTION(bezt_add_to_cfra_elem)(ListBase *lb, BezTriple *bezt
* which BezTriples/Keyframe data are ill equipped to do.
*/
-/* Basic sampling callback which acts as a wrapper for evaluate_fcurve()
- * 'data' arg here is unneeded here...
- */
float fcurve_samplingcb_evalcurve(FCurve *fcu, void *UNUSED(data), float evaltime)
{
/* Assume any interference from drivers on the curve is intended... */
return evaluate_fcurve(fcu, evaltime);
}
-/* Main API function for creating a set of sampled curve data, given some callback function
- * used to retrieve the values to store.
- */
void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb)
{
FPoint *fpt, *new_fpt;
@@ -1155,7 +1101,6 @@ static void init_unbaked_bezt_data(BezTriple *bezt)
bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
}
-/* Convert baked/sampled fcurves into bezt/regular fcurves. */
void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end)
{
@@ -1231,7 +1176,6 @@ void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end)
* that the handles are correct.
*/
-/* Checks if the F-Curve has a Cycles modifier, and returns the type of the cycle behavior. */
eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu)
{
FModifier *fcm = fcu->modifiers.first;
@@ -1265,8 +1209,6 @@ eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu)
return FCU_CYCLE_NONE;
}
-/* Checks if the F-Curve has a Cycles modifier with simple settings
- * that warrant transition smoothing. */
bool BKE_fcurve_is_cyclic(FCurve *fcu)
{
return BKE_fcurve_get_cycle_type(fcu) != FCU_CYCLE_NONE;
@@ -1295,13 +1237,6 @@ static BezTriple *cycle_offset_triple(
return out;
}
-/**
- * Variant of #calchandles_fcurve() that allows calculating based on a different select flag.
- *
- * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection.
- * Usually `SELECT`, but may want to use a different one at times
- * (if caller does not operate on selection).
- */
void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag)
{
BezTriple *bezt, *prev, *next;
@@ -1385,28 +1320,11 @@ void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag)
}
}
-/**
- * This function recalculates the handles of an F-Curve. Acts based on selection with `SELECT`
- * flag. To use a different flag, use #calchandles_fcurve_ex().
- *
- * If the BezTriples have been rearranged, sort them first before using this.
- */
void calchandles_fcurve(FCurve *fcu)
{
calchandles_fcurve_ex(fcu, SELECT);
}
-/**
- * Update handles, making sure the handle-types are valid (e.g. correctly deduced from an "Auto"
- * type), and recalculating their position vectors.
- * Use when something has changed handle positions.
- *
- * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
- * but may want to use a different one at times (if caller does not operate on
- * selection).
- * \param use_handle: Check selection state of individual handles, otherwise always update both
- * handles if the key is selected.
- */
void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_handle)
{
BezTriple *bezt;
@@ -1426,9 +1344,6 @@ void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_ha
calchandles_fcurve_ex(fcu, sel_flag);
}
-/* This function sorts BezTriples so that they are arranged in chronological order,
- * as tools working on F-Curves expect that the BezTriples are in order.
- */
void sort_time_fcurve(FCurve *fcu)
{
if (fcu->bezt == NULL) {
@@ -1471,7 +1386,6 @@ void sort_time_fcurve(FCurve *fcu)
}
}
-/* This function tests if any BezTriples are out of order, thus requiring a sort. */
bool test_time_fcurve(FCurve *fcu)
{
unsigned int a;
@@ -1513,14 +1427,6 @@ bool test_time_fcurve(FCurve *fcu)
/** \name F-Curve Calculations
* \{ */
-/**
- * The length of each handle is not allowed to be more
- * than the horizontal distance between (v1-v4).
- * This is to prevent curve loops.
- *
- * This function is very similar to BKE_curve_correct_bezpart(), but allows a steeper tangent for
- * more snappy animations. This is not desired for other areas in which curves are used, though.
- */
void BKE_fcurve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
{
float h1[2], h2[2], len1, len2, len, fac;
@@ -1705,14 +1611,6 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b)
}
}
-/**
- * Adjust Bezier handles of all three given BezTriples, so that `bezt` can be inserted between
- * `prev` and `next` without changing the resulting curve shape.
- *
- * \param r_pdelta: return Y difference between `bezt` and the original curve value at its X
- * position.
- * \return Whether the split was successful.
- */
bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt,
struct BezTriple *prev,
struct BezTriple *next,
@@ -2248,14 +2146,12 @@ float evaluate_fcurve_driver(PathResolvedRNA *anim_rna,
return evaluate_fcurve_ex(fcu, evaltime, cvalue);
}
-/* Checks if the curve has valid keys, drivers or modifiers that produce an actual curve. */
bool BKE_fcurve_is_empty(FCurve *fcu)
{
return (fcu->totvert == 0) && (fcu->driver == NULL) &&
!list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE);
}
-/* Calculate the value of the given F-Curve at the given frame, and set its curval. */
float calculate_fcurve(PathResolvedRNA *anim_rna,
FCurve *fcu,
const AnimationEvalContext *anim_eval_context)
diff --git a/source/blender/blenkernel/intern/fcurve_cache.c b/source/blender/blenkernel/intern/fcurve_cache.c
index 8142b871edd..4f27bad5b91 100644
--- a/source/blender/blenkernel/intern/fcurve_cache.c
+++ b/source/blender/blenkernel/intern/fcurve_cache.c
@@ -155,11 +155,6 @@ FCurve *BKE_fcurve_pathcache_find(struct FCurvePathCache *fcache,
return NULL;
}
-/**
- * Fill in an array of F-Curve, leave NULL when not found.
- *
- * \return The number of F-Curves found.
- */
int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache,
const char *rna_path,
FCurve **fcurve_result,
diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c
index d1bf523acef..ce30f80ba65 100644
--- a/source/blender/blenkernel/intern/fcurve_driver.c
+++ b/source/blender/blenkernel/intern/fcurve_driver.c
@@ -29,6 +29,7 @@
#include "BLI_alloca.h"
#include "BLI_expr_pylike_eval.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string_utils.h"
#include "BLI_threads.h"
@@ -199,9 +200,6 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
return value;
}
-/**
- * Same as 'dtar_get_prop_val'. but get the RNA property.
- */
bool driver_get_variable_property(ChannelDriver *driver,
DriverTarget *dtar,
PointerRNA *r_ptr,
@@ -326,7 +324,7 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
float(*mat[2])[4];
- /* NOTE: for now, these are all just worldspace */
+ /* NOTE: for now, these are all just world-space. */
for (int i = 0; i < 2; i++) {
/* Get pointer to loc values to store in. */
DriverTarget *dtar = &dvar->targets[i];
@@ -422,7 +420,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
}
}
else {
- /* Convert to worldspace. */
+ /* Convert to world-space. */
copy_v3_v3(tmp_loc, pchan->pose_head);
mul_m4_v3(ob->obmat, tmp_loc);
}
@@ -621,7 +619,6 @@ static void quaternion_to_angles(float quat[4], int channel)
}
}
-/* Compute channel values for a rotational Transform Channel driver variable. */
void BKE_driver_target_matrix_to_rot_channels(
float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4])
{
@@ -720,7 +717,6 @@ static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
/** \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. */
@@ -745,7 +741,6 @@ void driver_free_variable(ListBase *variables, DriverVar *dvar)
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. */
@@ -755,7 +750,6 @@ void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
BKE_driver_invalidate_expression(driver, false, true);
}
-/* Copy driver variables from src_vars list to dst_vars list */
void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
{
BLI_assert(BLI_listbase_is_empty(dst_vars));
@@ -773,7 +767,6 @@ void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
}
}
-/* Change the type of driver variable */
void driver_change_variable_type(DriverVar *dvar, int type)
{
const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
@@ -803,7 +796,6 @@ void driver_change_variable_type(DriverVar *dvar, int type)
DRIVER_TARGETS_LOOPER_END;
}
-/* Validate driver name (after being renamed) */
void driver_variable_name_validate(DriverVar *dvar)
{
/* Special character blacklist */
@@ -873,7 +865,12 @@ void driver_variable_name_validate(DriverVar *dvar)
}
}
-/* Add a new driver variable */
+void driver_variable_unique_name(DriverVar *dvar)
+{
+ ListBase variables = BLI_listbase_from_link((Link *)dvar);
+ BLI_uniquename(&variables, dvar, dvar->name, '_', offsetof(DriverVar, name), sizeof(dvar->name));
+}
+
DriverVar *driver_add_new_variable(ChannelDriver *driver)
{
DriverVar *dvar;
@@ -906,7 +903,6 @@ DriverVar *driver_add_new_variable(ChannelDriver *driver)
return dvar;
}
-/* This frees the driver itself */
void fcurve_free_driver(FCurve *fcu)
{
ChannelDriver *driver;
@@ -939,7 +935,6 @@ void fcurve_free_driver(FCurve *fcu)
fcu->driver = NULL;
}
-/* This makes a copy of the given driver */
ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
{
ChannelDriver *ndriver;
@@ -1082,7 +1077,6 @@ static bool driver_try_evaluate_simple_expr(ChannelDriver *driver,
driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time);
}
-/* Check if the expression in the driver conforms to the simple subset. */
bool BKE_driver_has_simple_expression(ChannelDriver *driver)
{
return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple);
@@ -1109,7 +1103,6 @@ static bool python_driver_exression_depends_on_time(const char *expression)
return false;
}
-/* Check if the expression in the driver may depend on the current frame. */
bool BKE_driver_expression_depends_on_time(ChannelDriver *driver)
{
if (driver->type != DRIVER_TYPE_PYTHON) {
@@ -1125,7 +1118,6 @@ bool BKE_driver_expression_depends_on_time(ChannelDriver *driver)
return python_driver_exression_depends_on_time(driver->expression);
}
-/* Reset cached compiled expression data */
void BKE_driver_invalidate_expression(ChannelDriver *driver,
bool expr_changed,
bool varname_changed)
@@ -1152,7 +1144,6 @@ void BKE_driver_invalidate_expression(ChannelDriver *driver,
/** \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;
@@ -1269,14 +1260,6 @@ static void evaluate_driver_python(PathResolvedRNA *anim_rna,
}
}
-/**
- * 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,
@@ -1309,3 +1292,5 @@ float evaluate_driver(PathResolvedRNA *anim_rna,
/* Return value for driver. */
return driver->curval;
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index e272b71acb8..0c9e352da12 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -1030,7 +1030,6 @@ static void obstacles_from_mesh(Object *coll_ob,
CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
}
- BKE_mesh_ensure_normals(me);
mvert = me->mvert;
mloop = me->mloop;
looptri = BKE_mesh_runtime_looptri_ensure(me);
@@ -1053,9 +1052,11 @@ static void obstacles_from_mesh(Object *coll_ob,
}
}
- /* Transform mesh vertices to domain grid space for fast lookups */
+ /* Transform mesh vertices to domain grid space for fast lookups.
+ * This is valid because the mesh is copied above. */
+ BKE_mesh_vertex_normals_ensure(me);
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(me);
for (i = 0; i < numverts; i++) {
- float n[3];
float co[3];
/* Vertex position. */
@@ -1063,11 +1064,9 @@ static void obstacles_from_mesh(Object *coll_ob,
manta_pos_to_cell(fds, mvert[i].co);
/* Vertex normal. */
- normal_short_to_float_v3(n, mvert[i].no);
- mul_mat3_m4_v3(coll_ob->obmat, n);
- mul_mat3_m4_v3(fds->imat, n);
- normalize_v3(n);
- normal_float_to_short_v3(mvert[i].no, n);
+ mul_mat3_m4_v3(coll_ob->obmat, vert_normals[i]);
+ mul_mat3_m4_v3(fds->imat, vert_normals[i]);
+ normalize_v3(vert_normals[i]);
/* Vertex velocity. */
add_v3fl_v3fl_v3i(co, mvert[i].co, fds->shift);
@@ -1826,6 +1825,7 @@ static void update_distances(int index,
static void sample_mesh(FluidFlowSettings *ffs,
const MVert *mvert,
+ const float (*vert_normals)[3],
const MLoop *mloop,
const MLoopTri *mlooptri,
const MLoopUV *mloopuv,
@@ -1906,7 +1906,7 @@ static void sample_mesh(FluidFlowSettings *ffs,
tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
float weights[3];
int v1, v2, v3, f_index = nearest.index;
- float n1[3], n2[3], n3[3], hit_normal[3];
+ float hit_normal[3];
/* Calculate barycentric weights for nearest point. */
v1 = mloop[mlooptri[f_index].tri[0]].v;
@@ -1969,10 +1969,8 @@ static void sample_mesh(FluidFlowSettings *ffs,
/* Apply normal directional velocity. */
if (ffs->vel_normal) {
/* Interpolate vertex normal vectors to get nearest point normal. */
- normal_short_to_float_v3(n1, mvert[v1].no);
- normal_short_to_float_v3(n2, mvert[v2].no);
- normal_short_to_float_v3(n3, mvert[v3].no);
- interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
+ interp_v3_v3v3v3(
+ hit_normal, vert_normals[v1], vert_normals[v2], vert_normals[v3], weights);
normalize_v3(hit_normal);
/* Apply normal directional velocity. */
@@ -2022,6 +2020,7 @@ typedef struct EmitFromDMData {
FluidFlowSettings *ffs;
const MVert *mvert;
+ const float (*vert_normals)[3];
const MLoop *mloop;
const MLoopTri *mlooptri;
const MLoopUV *mloopuv;
@@ -2056,6 +2055,7 @@ static void emit_from_mesh_task_cb(void *__restrict userdata,
(data->ffs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW)) {
sample_mesh(data->ffs,
data->mvert,
+ data->vert_normals,
data->mloop,
data->mlooptri,
data->mloopuv,
@@ -2117,7 +2117,6 @@ static void emit_from_mesh(
CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
}
- BKE_mesh_ensure_normals(me);
mvert = me->mvert;
mloop = me->mloop;
mlooptri = BKE_mesh_runtime_looptri_ensure(me);
@@ -2140,20 +2139,19 @@ static void emit_from_mesh(
}
}
- /* Transform mesh vertices to domain grid space for fast lookups */
+ /* Transform mesh vertices to domain grid space for fast lookups.
+ * This is valid because the mesh is copied above. */
+ BKE_mesh_vertex_normals_ensure(me);
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(me);
for (i = 0; i < numverts; i++) {
- float n[3];
-
/* Vertex position. */
mul_m4_v3(flow_ob->obmat, mvert[i].co);
manta_pos_to_cell(fds, mvert[i].co);
/* Vertex normal. */
- normal_short_to_float_v3(n, mvert[i].no);
- mul_mat3_m4_v3(flow_ob->obmat, n);
- mul_mat3_m4_v3(fds->imat, n);
- normalize_v3(n);
- normal_float_to_short_v3(mvert[i].no, n);
+ mul_mat3_m4_v3(flow_ob->obmat, vert_normals[i]);
+ mul_mat3_m4_v3(fds->imat, vert_normals[i]);
+ normalize_v3(vert_normals[i]);
/* Vertex velocity. */
if (ffs->flags & FLUID_FLOW_INITVELOCITY) {
@@ -2193,6 +2191,7 @@ static void emit_from_mesh(
.fds = fds,
.ffs = ffs,
.mvert = mvert,
+ .vert_normals = vert_normals,
.mloop = mloop,
.mlooptri = mlooptri,
.mloopuv = mloopuv,
@@ -2676,7 +2675,7 @@ static void update_flowsflags(FluidDomainSettings *fds, Object **flowobjs, int n
}
/* Activate color field if flows add smoke with varying colors. */
if (ffs->density != 0.0 &&
- (ffs->type == FLUID_FLOW_TYPE_SMOKE || ffs->type == FLUID_FLOW_TYPE_SMOKEFIRE)) {
+ ELEM(ffs->type, FLUID_FLOW_TYPE_SMOKE, FLUID_FLOW_TYPE_SMOKEFIRE)) {
if (!(active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET)) {
copy_v3_v3(fds->active_color, ffs->color);
active_fields |= FLUID_DOMAIN_ACTIVE_COLOR_SET;
@@ -3265,8 +3264,6 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
MVert *mverts;
MPoly *mpolys;
MLoop *mloops;
- short *normals, *no_s;
- float no[3];
float min[3];
float max[3];
float size[3];
@@ -3285,26 +3282,23 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
const char mp_flag = mp_example.flag;
int i;
- int num_verts, num_normals, num_faces;
+ int num_verts, num_faces;
if (!fds->fluid) {
return NULL;
}
num_verts = manta_liquid_get_num_verts(fds->fluid);
- num_normals = manta_liquid_get_num_normals(fds->fluid);
num_faces = manta_liquid_get_num_triangles(fds->fluid);
# ifdef DEBUG_PRINT
/* Debugging: Print number of vertices, normals, and faces. */
- printf("num_verts: %d, num_normals: %d, num_faces: %d\n", num_verts, num_normals, num_faces);
+ printf("num_verts: %d, num_faces: %d\n", num_verts, num_faces);
# endif
if (!num_verts || !num_faces) {
return NULL;
}
- /* Normals are per vertex, so these must match. */
- BLI_assert(num_verts == num_normals);
me = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 3, num_faces);
if (!me) {
@@ -3334,9 +3328,6 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
co_offset[1] = (fds->p0[1] + fds->p1[1]) / 2.0f;
co_offset[2] = (fds->p0[2] + fds->p1[2]) / 2.0f;
- /* Normals. */
- normals = MEM_callocN(sizeof(short[3]) * num_normals, "Fluidmesh_tmp_normals");
-
/* Velocities. */
/* If needed, vertex velocities will be read too. */
bool use_speedvectors = fds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS;
@@ -3350,7 +3341,7 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
}
/* Loop for vertices and normals. */
- for (i = 0, no_s = normals; i < num_verts && i < num_normals; i++, mverts++, no_s += 3) {
+ for (i = 0; i < num_verts; i++, mverts++) {
/* Vertices (data is normalized cube around domain origin). */
mverts->co[0] = manta_liquid_get_vertex_x_at(fds->fluid, i);
@@ -3376,12 +3367,6 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
mverts->co[2]);
# endif
- /* Normals (data is normalized cube around domain origin). */
- no[0] = manta_liquid_get_normal_x_at(fds->fluid, i);
- no[1] = manta_liquid_get_normal_y_at(fds->fluid, i);
- no[2] = manta_liquid_get_normal_z_at(fds->fluid, i);
-
- normal_float_to_short_v3(no_s, no);
# ifdef DEBUG_PRINT
/* Debugging: Print coordinates of normals. */
printf("no_s[0]: %d, no_s[1]: %d, no_s[2]: %d\n", no_s[0], no_s[1], no_s[2]);
@@ -3425,11 +3410,7 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
# endif
}
- BKE_mesh_ensure_normals(me);
BKE_mesh_calc_edges(me, false, false);
- BKE_mesh_vert_normals_apply(me, (short(*)[3])normals);
-
- MEM_freeN(normals);
return me;
}
@@ -4437,8 +4418,6 @@ static void manta_smoke_calc_transparency(FluidDomainSettings *fds, ViewLayer *v
}
}
-/* Get fluid velocity and density at given coordinates
- * Returns fluid density or -1.0f if outside domain. */
float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
{
FluidModifierData *fmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
@@ -4575,10 +4554,10 @@ void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_typ
}
}
-#endif /* WITH_FLUID */
-
/** \} */
+#endif /* WITH_FLUID */
+
/* -------------------------------------------------------------------- */
/** \name Public Data Access API
*
@@ -5090,7 +5069,7 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *fmd,
copy_v4_v4(tfds->gridlines_range_color, fds->gridlines_range_color);
tfds->gridlines_cell_filter = fds->gridlines_cell_filter;
- /* -- Deprecated / unsed options (below)-- */
+ /* -- Deprecated / unused options (below)-- */
/* pointcache options */
BKE_ptcache_free_list(&(tfds->ptcaches[0]));
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index 121927513cc..d140e70978a 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -1065,10 +1065,6 @@ static void fmods_init_typeinfo(void)
fmodifiersTypeInfo[9] = &FMI_STEPPED; /* Stepped F-Curve Modifier */
}
-/**
- * This function should be used for getting the appropriate type-info when only
- * a F-Curve modifier type is known.
- */
const FModifierTypeInfo *get_fmodifier_typeinfo(const int type)
{
/* initialize the type-info list? */
@@ -1088,10 +1084,6 @@ const FModifierTypeInfo *get_fmodifier_typeinfo(const int type)
return NULL;
}
-/**
- * This function should always be used to get the appropriate type-info,
- * as it has checks which prevent segfaults in some weird cases.
- */
const FModifierTypeInfo *fmodifier_get_typeinfo(const FModifier *fcm)
{
/* only return typeinfo for valid modifiers */
@@ -1108,9 +1100,6 @@ const FModifierTypeInfo *fmodifier_get_typeinfo(const FModifier *fcm)
/** \name F-Curve Modifier Public API
* \{ */
-/**
- * Add a new F-Curve Modifier to the given F-Curve of a certain type.
- */
FModifier *add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
{
const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
@@ -1161,9 +1150,6 @@ FModifier *add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
return fcm;
}
-/**
- * Make a copy of the specified F-Modifier.
- */
FModifier *copy_fmodifier(const FModifier *src)
{
const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src);
@@ -1191,9 +1177,6 @@ FModifier *copy_fmodifier(const FModifier *src)
return dst;
}
-/**
- * Duplicate all of the F-Modifiers in the Modifier stacks.
- */
void copy_fmodifiers(ListBase *dst, const ListBase *src)
{
FModifier *fcm, *srcfcm;
@@ -1220,9 +1203,6 @@ void copy_fmodifiers(ListBase *dst, const ListBase *src)
}
}
-/**
- * Remove and free the given F-Modifier from the given stack.
- */
bool remove_fmodifier(ListBase *modifiers, FModifier *fcm)
{
const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
@@ -1263,9 +1243,6 @@ bool remove_fmodifier(ListBase *modifiers, FModifier *fcm)
return false;
}
-/**
- * Remove all of a given F-Curve's modifiers.
- */
void free_fmodifiers(ListBase *modifiers)
{
FModifier *fcm, *fmn;
@@ -1282,9 +1259,6 @@ void free_fmodifiers(ListBase *modifiers)
}
}
-/**
- * Find the active F-Modifier.
- */
FModifier *find_active_fmodifier(ListBase *modifiers)
{
FModifier *fcm;
@@ -1305,9 +1279,6 @@ FModifier *find_active_fmodifier(ListBase *modifiers)
return NULL;
}
-/**
- * Set the active F-Modifier.
- */
void set_active_fmodifier(ListBase *modifiers, FModifier *fcm)
{
FModifier *fm;
@@ -1328,12 +1299,6 @@ void set_active_fmodifier(ListBase *modifiers, FModifier *fcm)
}
}
-/**
- * Do we have any modifiers which match certain criteria.
- *
- * \param mtype: Type of modifier (if 0, doesn't matter).
- * \param acttype: Type of action to perform (if -1, doesn't matter).
- */
bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype)
{
FModifier *fcm;
@@ -1443,19 +1408,6 @@ static float eval_fmodifier_influence(FModifier *fcm, float evaltime)
return influence;
}
-/**
- * Evaluate time modifications imposed by some F-Curve Modifiers.
- *
- * - This step acts as an optimization to prevent the F-Curve stack being evaluated
- * several times by modifiers requesting the time be modified, as the final result
- * would have required using the modified time
- * - Modifiers only ever receive the unmodified time, as subsequent modifiers should be
- * working on the 'global' result of the modified curve, not some localized segment,
- * so \a evaltime gets set to whatever the last time-modifying modifier likes.
- * - We start from the end of the stack, as only the last one matters for now.
- *
- * \param fcu: Can be NULL.
- */
float evaluate_time_fmodifiers(FModifiersStackStorage *storage,
ListBase *modifiers,
FCurve *fcu,
@@ -1513,10 +1465,6 @@ float evaluate_time_fmodifiers(FModifiersStackStorage *storage,
return evaltime;
}
-/**
- * Evaluates the given set of F-Curve Modifiers using the given data
- * Should only be called after evaluate_time_fmodifiers() has been called.
- */
void evaluate_value_fmodifiers(FModifiersStackStorage *storage,
ListBase *modifiers,
FCurve *fcu,
@@ -1565,10 +1513,6 @@ void evaluate_value_fmodifiers(FModifiersStackStorage *storage,
/* ---------- */
-/**
- * Bake modifiers for given F-Curve to curve sample data, in the frame range defined
- * by start and end (inclusive).
- */
void fcurve_bake_modifiers(FCurve *fcu, int start, int end)
{
ChannelDriver *driver;
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index d9b3faf8623..68b7e274970 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -152,10 +152,6 @@ bool BKE_freestyle_module_delete(FreestyleConfig *config, FreestyleModuleConfig
return true;
}
-/**
- * Reinsert \a module_conf offset by \a direction from current position.
- * \return if position of \a module_conf changed.
- */
bool BKE_freestyle_module_move(FreestyleConfig *config,
FreestyleModuleConfig *module_conf,
int direction)
diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc
index 7d0537178ef..16edbc36f9c 100644
--- a/source/blender/blenkernel/intern/geometry_component_curve.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curve.cc
@@ -14,6 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BLI_task.hh"
+
#include "DNA_ID_enums.h"
#include "DNA_curve_types.h"
@@ -28,10 +30,8 @@
using blender::fn::GMutableSpan;
using blender::fn::GSpan;
-using blender::fn::GVArray_For_GSpan;
+using blender::fn::GVArray;
using blender::fn::GVArray_GSpan;
-using blender::fn::GVArrayPtr;
-using blender::fn::GVMutableArray_For_GMutableSpan;
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
@@ -79,7 +79,6 @@ bool CurveComponent::has_curve() const
return curve_ != nullptr;
}
-/* Clear the component and replace it with the new curve. */
void CurveComponent::replace(CurveEval *curve, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
@@ -130,10 +129,6 @@ void CurveComponent::ensure_owns_direct_data()
}
}
-/**
- * Create empty curve data used for rendering the spline's wire edges.
- * \note See comment on #curve_for_render_ for further explanation.
- */
const Curve *CurveComponent::get_curve_for_render() const
{
if (curve_ == nullptr) {
@@ -253,15 +248,15 @@ void adapt_curve_domain_point_to_spline_impl(const CurveEval &curve,
}
}
-static GVArrayPtr adapt_curve_domain_point_to_spline(const CurveEval &curve, GVArrayPtr varray)
+static GVArray adapt_curve_domain_point_to_spline(const CurveEval &curve, GVArray varray)
{
- GVArrayPtr new_varray;
- attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
+ GVArray new_varray;
+ attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(curve.splines().size());
- adapt_curve_domain_point_to_spline_impl<T>(curve, varray->typed<T>(), values);
- new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ adapt_curve_domain_point_to_spline_impl<T>(curve, varray.typed<T>(), values);
+ new_varray = VArray<T>::ForContainer(std::move(values));
}
});
return new_varray;
@@ -272,29 +267,29 @@ static GVArrayPtr adapt_curve_domain_point_to_spline(const CurveEval &curve, GVA
* attributes. The goal is to avoid copying the spline value for every one of its control points
* unless it is necessary (in that case the materialize functions will be called).
*/
-template<typename T> class VArray_For_SplineToPoint final : public VArray<T> {
- GVArrayPtr original_varray_;
+template<typename T> class VArray_For_SplineToPoint final : public VArrayImpl<T> {
+ GVArray original_varray_;
/* Store existing data materialized if it was not already a span. This is expected
* to be worth it because a single spline's value will likely be accessed many times. */
- fn::GVArray_Span<T> original_data_;
+ VArray_Span<T> original_data_;
Array<int> offsets_;
public:
- VArray_For_SplineToPoint(GVArrayPtr original_varray, Array<int> offsets)
- : VArray<T>(offsets.last()),
+ VArray_For_SplineToPoint(GVArray original_varray, Array<int> offsets)
+ : VArrayImpl<T>(offsets.last()),
original_varray_(std::move(original_varray)),
- original_data_(*original_varray_),
+ original_data_(original_varray_.typed<T>()),
offsets_(std::move(offsets))
{
}
- T get_impl(const int64_t index) const final
+ T get(const int64_t index) const final
{
const PointIndices indices = lookup_point_indices(offsets_, index);
return original_data_[indices.spline_index];
}
- void materialize_impl(const IndexMask mask, MutableSpan<T> r_span) const final
+ void materialize(const IndexMask mask, MutableSpan<T> r_span) const final
{
const int total_size = offsets_.last();
if (mask.is_range() && mask.as_range() == IndexRange(total_size)) {
@@ -315,7 +310,7 @@ template<typename T> class VArray_For_SplineToPoint final : public VArray<T> {
}
}
- void materialize_to_uninitialized_impl(const IndexMask mask, MutableSpan<T> r_span) const final
+ void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final
{
T *dst = r_span.data();
const int total_size = offsets_.last();
@@ -338,29 +333,29 @@ template<typename T> class VArray_For_SplineToPoint final : public VArray<T> {
}
};
-static GVArrayPtr adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArrayPtr varray)
+static GVArray adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArray varray)
{
- GVArrayPtr new_varray;
- attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
+ GVArray new_varray;
+ attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
Array<int> offsets = curve.control_point_offsets();
- new_varray = std::make_unique<fn::GVArray_For_EmbeddedVArray<T, VArray_For_SplineToPoint<T>>>(
- offsets.last(), std::move(varray), std::move(offsets));
+ new_varray = VArray<T>::template For<VArray_For_SplineToPoint<T>>(std::move(varray),
+ std::move(offsets));
});
return new_varray;
}
} // namespace blender::bke
-GVArrayPtr CurveComponent::attribute_try_adapt_domain(GVArrayPtr varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const
+GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray,
+ const AttributeDomain from_domain,
+ const AttributeDomain to_domain) const
{
if (!varray) {
return {};
}
- if (varray->size() == 0) {
+ if (varray.is_empty()) {
return {};
}
if (from_domain == to_domain) {
@@ -393,17 +388,109 @@ static const CurveEval *get_curve_from_component_for_read(const GeometryComponen
/** \} */
+namespace blender::bke {
+
+/* -------------------------------------------------------------------- */
+/** \name Curve Normals Access
+ * \{ */
+
+static void calculate_bezier_normals(const BezierSpline &spline, MutableSpan<float3> normals)
+{
+ Span<int> offsets = spline.control_point_offsets();
+ Span<float3> evaluated_normals = spline.evaluated_normals();
+ for (const int i : IndexRange(spline.size())) {
+ normals[i] = evaluated_normals[offsets[i]];
+ }
+}
+
+static void calculate_poly_normals(const PolySpline &spline, MutableSpan<float3> normals)
+{
+ normals.copy_from(spline.evaluated_normals());
+}
+
+/**
+ * Because NURBS control points are not necessarily on the path, the normal at the control points
+ * is not well defined, so create a temporary poly spline to find the normals. This requires extra
+ * copying currently, but may be more efficient in the future if attributes have some form of CoW.
+ */
+static void calculate_nurbs_normals(const NURBSpline &spline, MutableSpan<float3> normals)
+{
+ PolySpline poly_spline;
+ poly_spline.resize(spline.size());
+ poly_spline.positions().copy_from(spline.positions());
+ poly_spline.tilts().copy_from(spline.tilts());
+ normals.copy_from(poly_spline.evaluated_normals());
+}
+
+static Array<float3> curve_normal_point_domain(const CurveEval &curve)
+{
+ Span<SplinePtr> splines = curve.splines();
+ Array<int> offsets = curve.control_point_offsets();
+ const int total_size = offsets.last();
+ Array<float3> normals(total_size);
+
+ threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ const Spline &spline = *splines[i];
+ MutableSpan spline_normals{normals.as_mutable_span().slice(offsets[i], spline.size())};
+ switch (splines[i]->type()) {
+ case Spline::Type::Bezier:
+ calculate_bezier_normals(static_cast<const BezierSpline &>(spline), spline_normals);
+ break;
+ case Spline::Type::Poly:
+ calculate_poly_normals(static_cast<const PolySpline &>(spline), spline_normals);
+ break;
+ case Spline::Type::NURBS:
+ calculate_nurbs_normals(static_cast<const NURBSpline &>(spline), spline_normals);
+ break;
+ }
+ }
+ });
+ return normals;
+}
+
+VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain)
+{
+ const CurveEval *curve = component.get_for_read();
+ if (curve == nullptr) {
+ return nullptr;
+ }
+
+ if (domain == ATTR_DOMAIN_POINT) {
+ const Span<SplinePtr> splines = curve->splines();
+
+ /* Use a reference to evaluated normals if possible to avoid an allocation and a copy.
+ * This is only possible when there is only one poly spline. */
+ if (splines.size() == 1 && splines.first()->type() == Spline::Type::Poly) {
+ const PolySpline &spline = static_cast<PolySpline &>(*splines.first());
+ return VArray<float3>::ForSpan(spline.evaluated_normals());
+ }
+
+ Array<float3> normals = curve_normal_point_domain(*curve);
+ return VArray<float3>::ForContainer(std::move(normals));
+ }
+
+ if (domain == ATTR_DOMAIN_CURVE) {
+ Array<float3> point_normals = curve_normal_point_domain(*curve);
+ VArray<float3> varray = VArray<float3>::ForContainer(std::move(point_normals));
+ return component.attribute_try_adapt_domain<float3>(
+ std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
+ }
+
+ return nullptr;
+}
+
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Builtin Spline Attributes
*
* Attributes with a value for every spline, stored contiguously or in every spline separately.
* \{ */
-namespace blender::bke {
-
class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
- using AsReadAttribute = GVArrayPtr (*)(const CurveEval &data);
- using AsWriteAttribute = GVMutableArrayPtr (*)(CurveEval &data);
+ using AsReadAttribute = GVArray (*)(const CurveEval &data);
+ using AsWriteAttribute = GVMutableArray (*)(CurveEval &data);
const AsReadAttribute as_read_attribute_;
const AsWriteAttribute as_write_attribute_;
@@ -424,7 +511,7 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
{
}
- GVArrayPtr try_get_for_read(const GeometryComponent &component) const final
+ GVArray try_get_for_read(const GeometryComponent &component) const final
{
const CurveEval *curve = get_curve_from_component_for_read(component);
if (curve == nullptr) {
@@ -433,7 +520,7 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
return as_read_attribute_(*curve);
}
- GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
{
if (writable_ != Writable) {
return {};
@@ -442,7 +529,7 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
if (curve == nullptr) {
return {};
}
- return as_write_attribute_(*curve);
+ return {as_write_attribute_(*curve), domain_};
}
bool try_delete(GeometryComponent &UNUSED(component)) const final
@@ -483,19 +570,15 @@ static void set_spline_resolution(SplinePtr &spline, const int resolution)
}
}
-static GVArrayPtr make_resolution_read_attribute(const CurveEval &curve)
+static GVArray make_resolution_read_attribute(const CurveEval &curve)
{
- return std::make_unique<fn::GVArray_For_DerivedSpan<SplinePtr, int, get_spline_resolution>>(
- curve.splines());
+ return VArray<int>::ForDerivedSpan<SplinePtr, get_spline_resolution>(curve.splines());
}
-static GVMutableArrayPtr make_resolution_write_attribute(CurveEval &curve)
+static GVMutableArray make_resolution_write_attribute(CurveEval &curve)
{
- return std::make_unique<fn::GVMutableArray_For_DerivedSpan<SplinePtr,
- int,
- get_spline_resolution,
- set_spline_resolution>>(
- curve.splines());
+ return VMutableArray<int>::
+ ForDerivedSpan<SplinePtr, get_spline_resolution, set_spline_resolution>(curve.splines());
}
static bool get_cyclic_value(const SplinePtr &spline)
@@ -511,16 +594,14 @@ static void set_cyclic_value(SplinePtr &spline, const bool value)
}
}
-static GVArrayPtr make_cyclic_read_attribute(const CurveEval &curve)
+static GVArray make_cyclic_read_attribute(const CurveEval &curve)
{
- return std::make_unique<fn::GVArray_For_DerivedSpan<SplinePtr, bool, get_cyclic_value>>(
- curve.splines());
+ return VArray<bool>::ForDerivedSpan<SplinePtr, get_cyclic_value>(curve.splines());
}
-static GVMutableArrayPtr make_cyclic_write_attribute(CurveEval &curve)
+static GVMutableArray make_cyclic_write_attribute(CurveEval &curve)
{
- return std::make_unique<
- fn::GVMutableArray_For_DerivedSpan<SplinePtr, bool, get_cyclic_value, set_cyclic_value>>(
+ return VMutableArray<bool>::ForDerivedSpan<SplinePtr, get_cyclic_value, set_cyclic_value>(
curve.splines());
}
@@ -535,6 +616,9 @@ static GVMutableArrayPtr make_cyclic_write_attribute(CurveEval &curve)
* array implementations try to make it workable in common situations.
* \{ */
+/**
+ * Individual spans in \a data may be empty if that spline contains no data for the attribute.
+ */
template<typename T>
static void point_attribute_materialize(Span<Span<T>> data,
Span<int> offsets,
@@ -546,22 +630,40 @@ static void point_attribute_materialize(Span<Span<T>> data,
for (const int spline_index : data.index_range()) {
const int offset = offsets[spline_index];
const int next_offset = offsets[spline_index + 1];
- r_span.slice(offset, next_offset - offset).copy_from(data[spline_index]);
+
+ Span<T> src = data[spline_index];
+ MutableSpan<T> dst = r_span.slice(offset, next_offset - offset);
+ if (src.is_empty()) {
+ dst.fill(T());
+ }
+ else {
+ dst.copy_from(src);
+ }
}
}
else {
int spline_index = 0;
for (const int dst_index : mask) {
- while (offsets[spline_index] < dst_index) {
+ /* Skip splines that don't have any control points in the mask. */
+ while (dst_index >= offsets[spline_index + 1]) {
spline_index++;
}
const int index_in_spline = dst_index - offsets[spline_index];
- r_span[dst_index] = data[spline_index][index_in_spline];
+ Span<T> src = data[spline_index];
+ if (src.is_empty()) {
+ r_span[dst_index] = T();
+ }
+ else {
+ r_span[dst_index] = src[index_in_spline];
+ }
}
}
}
+/**
+ * Individual spans in \a data may be empty if that spline contains no data for the attribute.
+ */
template<typename T>
static void point_attribute_materialize_to_uninitialized(Span<Span<T>> data,
Span<int> offsets,
@@ -574,80 +676,159 @@ static void point_attribute_materialize_to_uninitialized(Span<Span<T>> data,
for (const int spline_index : data.index_range()) {
const int offset = offsets[spline_index];
const int next_offset = offsets[spline_index + 1];
- uninitialized_copy_n(data[spline_index].data(), next_offset - offset, dst + offset);
+
+ Span<T> src = data[spline_index];
+ if (src.is_empty()) {
+ uninitialized_fill_n(dst + offset, next_offset - offset, T());
+ }
+ else {
+ uninitialized_copy_n(src.data(), next_offset - offset, dst + offset);
+ }
}
}
else {
int spline_index = 0;
for (const int dst_index : mask) {
- while (offsets[spline_index] < dst_index) {
+ /* Skip splines that don't have any control points in the mask. */
+ while (dst_index >= offsets[spline_index + 1]) {
spline_index++;
}
const int index_in_spline = dst_index - offsets[spline_index];
- new (dst + dst_index) T(data[spline_index][index_in_spline]);
+ Span<T> src = data[spline_index];
+ if (src.is_empty()) {
+ new (dst + dst_index) T();
+ }
+ else {
+ new (dst + dst_index) T(src[index_in_spline]);
+ }
}
}
}
-/**
- * Virtual array for any control point data accessed with spans and an offset array.
- */
-template<typename T> class VArray_For_SplinePoints : public VArray<T> {
- private:
- const Array<Span<T>> data_;
- Array<int> offsets_;
+static GVArray varray_from_initializer(const AttributeInit &initializer,
+ const CustomDataType data_type,
+ const Span<SplinePtr> splines)
+{
+ switch (initializer.type) {
+ case AttributeInit::Type::Default:
+ /* This function shouldn't be called in this case, since there
+ * is no need to copy anything to the new custom data array. */
+ BLI_assert_unreachable();
+ return {};
+ case AttributeInit::Type::VArray:
+ return static_cast<const AttributeInitVArray &>(initializer).varray;
+ case AttributeInit::Type::MoveArray:
+ int total_size = 0;
+ for (const SplinePtr &spline : splines) {
+ total_size += spline->size();
+ }
+ return GVArray::ForSpan(GSpan(*bke::custom_data_type_to_cpp_type(data_type),
+ static_cast<const AttributeInitMove &>(initializer).data,
+ total_size));
+ }
+ BLI_assert_unreachable();
+ return {};
+}
- public:
- VArray_For_SplinePoints(Array<Span<T>> data, Array<int> offsets)
- : VArray<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets))
- {
+static bool create_point_attribute(GeometryComponent &component,
+ const AttributeIDRef &attribute_id,
+ const AttributeInit &initializer,
+ const CustomDataType data_type)
+{
+ CurveEval *curve = get_curve_from_component_for_write(component);
+ if (curve == nullptr || curve->splines().size() == 0) {
+ return false;
}
- T get_impl(const int64_t index) const final
- {
- const PointIndices indices = lookup_point_indices(offsets_, index);
- return data_[indices.spline_index][indices.point_index];
+ MutableSpan<SplinePtr> splines = curve->splines();
+
+ /* First check the one case that allows us to avoid copying the input data. */
+ if (splines.size() == 1 && initializer.type == AttributeInit::Type::MoveArray) {
+ void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
+ if (!splines.first()->attributes.create_by_move(attribute_id, data_type, source_data)) {
+ MEM_freeN(source_data);
+ return false;
+ }
+ return true;
}
- void materialize_impl(const IndexMask mask, MutableSpan<T> r_span) const final
- {
- point_attribute_materialize(data_.as_span(), offsets_, mask, r_span);
+ /* Otherwise just create a custom data layer on each of the splines. */
+ for (const int i : splines.index_range()) {
+ if (!splines[i]->attributes.create(attribute_id, data_type)) {
+ /* If attribute creation fails on one of the splines, we cannot leave the custom data
+ * layers in the previous splines around, so delete them before returning. However,
+ * this is not an expected case. */
+ BLI_assert_unreachable();
+ return false;
+ }
}
- void materialize_to_uninitialized_impl(const IndexMask mask, MutableSpan<T> r_span) const final
- {
- point_attribute_materialize_to_uninitialized(data_.as_span(), offsets_, mask, r_span);
+ /* With a default initializer type, we can keep the values at their initial values. */
+ if (initializer.type == AttributeInit::Type::Default) {
+ return true;
}
-};
+
+ WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(attribute_id);
+ /* We just created the attribute, it should exist. */
+ BLI_assert(write_attribute);
+
+ GVArray source_varray = varray_from_initializer(initializer, data_type, splines);
+ /* TODO: When we can call a variant of #set_all with a virtual array argument,
+ * this theoretically unnecessary materialize step could be removed. */
+ GVArray_GSpan source_varray_span{source_varray};
+ write_attribute.varray.set_all(source_varray_span.data());
+
+ if (initializer.type == AttributeInit::Type::MoveArray) {
+ MEM_freeN(static_cast<const AttributeInitMove &>(initializer).data);
+ }
+
+ return true;
+}
+
+static bool remove_point_attribute(GeometryComponent &component,
+ const AttributeIDRef &attribute_id)
+{
+ CurveEval *curve = get_curve_from_component_for_write(component);
+ if (curve == nullptr) {
+ return false;
+ }
+
+ /* Reuse the boolean for all splines; we expect all splines to have the same attributes. */
+ bool layer_freed = false;
+ for (SplinePtr &spline : curve->splines()) {
+ layer_freed = spline->attributes.remove(attribute_id);
+ }
+ return layer_freed;
+}
/**
* Mutable virtual array for any control point data accessed with spans and an offset array.
*/
-template<typename T> class VMutableArray_For_SplinePoints final : public VMutableArray<T> {
+template<typename T> class VArrayImpl_For_SplinePoints final : public VMutableArrayImpl<T> {
private:
Array<MutableSpan<T>> data_;
Array<int> offsets_;
public:
- VMutableArray_For_SplinePoints(Array<MutableSpan<T>> data, Array<int> offsets)
- : VMutableArray<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets))
+ VArrayImpl_For_SplinePoints(Array<MutableSpan<T>> data, Array<int> offsets)
+ : VMutableArrayImpl<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets))
{
}
- T get_impl(const int64_t index) const final
+ T get(const int64_t index) const final
{
const PointIndices indices = lookup_point_indices(offsets_, index);
return data_[indices.spline_index][indices.point_index];
}
- void set_impl(const int64_t index, T value) final
+ void set(const int64_t index, T value) final
{
const PointIndices indices = lookup_point_indices(offsets_, index);
data_[indices.spline_index][indices.point_index] = value;
}
- void set_all_impl(Span<T> src) final
+ void set_all(Span<T> src) final
{
for (const int spline_index : data_.index_range()) {
const int offset = offsets_[spline_index];
@@ -656,30 +837,29 @@ template<typename T> class VMutableArray_For_SplinePoints final : public VMutabl
}
}
- void materialize_impl(const IndexMask mask, MutableSpan<T> r_span) const final
+ void materialize(const IndexMask mask, MutableSpan<T> r_span) const final
{
point_attribute_materialize({(Span<T> *)data_.data(), data_.size()}, offsets_, mask, r_span);
}
- void materialize_to_uninitialized_impl(const IndexMask mask, MutableSpan<T> r_span) const final
+ void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final
{
point_attribute_materialize_to_uninitialized(
{(Span<T> *)data_.data(), data_.size()}, offsets_, mask, r_span);
}
};
-template<typename T> GVArrayPtr point_data_gvarray(Array<Span<T>> spans, Array<int> offsets)
+template<typename T> VArray<T> point_data_varray(Array<MutableSpan<T>> spans, Array<int> offsets)
{
- return std::make_unique<fn::GVArray_For_EmbeddedVArray<T, VArray_For_SplinePoints<T>>>(
- offsets.last(), std::move(spans), std::move(offsets));
+ return VArray<T>::template For<VArrayImpl_For_SplinePoints<T>>(std::move(spans),
+ std::move(offsets));
}
template<typename T>
-GVMutableArrayPtr point_data_gvarray(Array<MutableSpan<T>> spans, Array<int> offsets)
+VMutableArray<T> point_data_varray_mutable(Array<MutableSpan<T>> spans, Array<int> offsets)
{
- return std::make_unique<
- fn::GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_SplinePoints<T>>>(
- offsets.last(), std::move(spans), std::move(offsets));
+ return VMutableArray<T>::template For<VArrayImpl_For_SplinePoints<T>>(std::move(spans),
+ std::move(offsets));
}
/**
@@ -690,24 +870,24 @@ GVMutableArrayPtr point_data_gvarray(Array<MutableSpan<T>> spans, Array<int> off
* \note There is no need to check the handle type to avoid changing auto handles, since
* retrieving write access to the position data will mark them for recomputation anyway.
*/
-class VMutableArray_For_SplinePosition final : public VMutableArray<float3> {
+class VArrayImpl_For_SplinePosition final : public VMutableArrayImpl<float3> {
private:
MutableSpan<SplinePtr> splines_;
Array<int> offsets_;
public:
- VMutableArray_For_SplinePosition(MutableSpan<SplinePtr> splines, Array<int> offsets)
- : VMutableArray<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets))
+ VArrayImpl_For_SplinePosition(MutableSpan<SplinePtr> splines, Array<int> offsets)
+ : VMutableArrayImpl<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets))
{
}
- float3 get_impl(const int64_t index) const final
+ float3 get(const int64_t index) const final
{
const PointIndices indices = lookup_point_indices(offsets_, index);
return splines_[indices.spline_index]->positions()[indices.point_index];
}
- void set_impl(const int64_t index, float3 value) final
+ void set(const int64_t index, float3 value) final
{
const PointIndices indices = lookup_point_indices(offsets_, index);
Spline &spline = *splines_[indices.spline_index];
@@ -722,7 +902,7 @@ class VMutableArray_For_SplinePosition final : public VMutableArray<float3> {
}
}
- void set_all_impl(Span<float3> src) final
+ void set_all(Span<float3> src) final
{
for (const int spline_index : splines_.index_range()) {
Spline &spline = *splines_[spline_index];
@@ -755,20 +935,122 @@ class VMutableArray_For_SplinePosition final : public VMutableArray<float3> {
return spans;
}
- void materialize_impl(const IndexMask mask, MutableSpan<float3> r_span) const final
+ void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final
{
Array<Span<float3>> spans = this->get_position_spans();
point_attribute_materialize(spans.as_span(), offsets_, mask, r_span);
}
- void materialize_to_uninitialized_impl(const IndexMask mask,
- MutableSpan<float3> r_span) const final
+ void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final
{
Array<Span<float3>> spans = this->get_position_spans();
point_attribute_materialize_to_uninitialized(spans.as_span(), offsets_, mask, r_span);
}
};
+class VArrayImpl_For_BezierHandles final : public VMutableArrayImpl<float3> {
+ private:
+ MutableSpan<SplinePtr> splines_;
+ Array<int> offsets_;
+ bool is_right_;
+
+ public:
+ VArrayImpl_For_BezierHandles(MutableSpan<SplinePtr> splines,
+ Array<int> offsets,
+ const bool is_right)
+ : VMutableArrayImpl<float3>(offsets.last()),
+ splines_(splines),
+ offsets_(std::move(offsets)),
+ is_right_(is_right)
+ {
+ }
+
+ float3 get(const int64_t index) const final
+ {
+ const PointIndices indices = lookup_point_indices(offsets_, index);
+ const Spline &spline = *splines_[indices.spline_index];
+ if (spline.type() == Spline::Type::Bezier) {
+ const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(spline);
+ return is_right_ ? bezier_spline.handle_positions_right()[indices.point_index] :
+ bezier_spline.handle_positions_left()[indices.point_index];
+ }
+ return float3(0);
+ }
+
+ void set(const int64_t index, float3 value) final
+ {
+ const PointIndices indices = lookup_point_indices(offsets_, index);
+ Spline &spline = *splines_[indices.spline_index];
+ if (spline.type() == Spline::Type::Bezier) {
+ BezierSpline &bezier_spline = static_cast<BezierSpline &>(spline);
+ if (is_right_) {
+ bezier_spline.set_handle_position_right(indices.point_index, value);
+ }
+ else {
+ bezier_spline.set_handle_position_left(indices.point_index, value);
+ }
+ bezier_spline.mark_cache_invalid();
+ }
+ }
+
+ void set_all(Span<float3> src) final
+ {
+ for (const int spline_index : splines_.index_range()) {
+ Spline &spline = *splines_[spline_index];
+ if (spline.type() == Spline::Type::Bezier) {
+ const int offset = offsets_[spline_index];
+
+ BezierSpline &bezier_spline = static_cast<BezierSpline &>(spline);
+ if (is_right_) {
+ for (const int i : IndexRange(bezier_spline.size())) {
+ bezier_spline.set_handle_position_right(i, src[offset + i]);
+ }
+ }
+ else {
+ for (const int i : IndexRange(bezier_spline.size())) {
+ bezier_spline.set_handle_position_left(i, src[offset + i]);
+ }
+ }
+ bezier_spline.mark_cache_invalid();
+ }
+ }
+ }
+
+ void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final
+ {
+ Array<Span<float3>> spans = get_handle_spans(splines_, is_right_);
+ point_attribute_materialize(spans.as_span(), offsets_, mask, r_span);
+ }
+
+ void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final
+ {
+ Array<Span<float3>> spans = get_handle_spans(splines_, is_right_);
+ point_attribute_materialize_to_uninitialized(spans.as_span(), offsets_, mask, r_span);
+ }
+
+ /**
+ * Utility so we can pass handle positions to the materialize functions above.
+ *
+ * \note This relies on the ability of the materialize implementations to
+ * handle empty spans, since only Bezier splines have handles.
+ */
+ static Array<Span<float3>> get_handle_spans(Span<SplinePtr> splines, const bool is_right)
+ {
+ Array<Span<float3>> spans(splines.size());
+ for (const int i : spans.index_range()) {
+ if (splines[i]->type() == Spline::Type::Bezier) {
+ BezierSpline &bezier_spline = static_cast<BezierSpline &>(*splines[i]);
+ spans[i] = is_right ? bezier_spline.handle_positions_right() :
+ bezier_spline.handle_positions_left();
+ }
+ else {
+ spans[i] = {};
+ }
+ }
+ return spans;
+ }
+};
+
/**
* Provider for any builtin control point attribute that doesn't need
* special handling like access to other arrays in the spline.
@@ -781,85 +1063,140 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu
const GetSpan get_span_;
const GetMutableSpan get_mutable_span_;
const UpdateOnWrite update_on_write_;
+ bool stored_in_custom_data_;
public:
BuiltinPointAttributeProvider(std::string attribute_name,
- const WritableEnum writable,
+ const CreatableEnum creatable,
+ const DeletableEnum deletable,
const GetSpan get_span,
const GetMutableSpan get_mutable_span,
- const UpdateOnWrite update_on_write)
+ const UpdateOnWrite update_on_write,
+ const bool stored_in_custom_data)
: BuiltinAttributeProvider(std::move(attribute_name),
ATTR_DOMAIN_POINT,
bke::cpp_type_to_custom_data_type(CPPType::get<T>()),
- BuiltinAttributeProvider::NonCreatable,
- writable,
- BuiltinAttributeProvider::NonDeletable),
+ creatable,
+ WritableEnum::Writable,
+ deletable),
get_span_(get_span),
get_mutable_span_(get_mutable_span),
- update_on_write_(update_on_write)
+ update_on_write_(update_on_write),
+ stored_in_custom_data_(stored_in_custom_data)
{
}
- GVArrayPtr try_get_for_read(const GeometryComponent &component) const override
+ GVArray try_get_for_read(const GeometryComponent &component) const override
{
const CurveEval *curve = get_curve_from_component_for_read(component);
if (curve == nullptr) {
return {};
}
+ if (!this->exists(component)) {
+ return {};
+ }
+
Span<SplinePtr> splines = curve->splines();
if (splines.size() == 1) {
- return std::make_unique<fn::GVArray_For_GSpan>(get_span_(*splines.first()));
+ return GVArray::ForSpan(get_span_(*splines.first()));
}
Array<int> offsets = curve->control_point_offsets();
- Array<Span<T>> spans(splines.size());
+ Array<MutableSpan<T>> spans(splines.size());
for (const int i : splines.index_range()) {
- spans[i] = get_span_(*splines[i]);
+ Span<T> span = get_span_(*splines[i]);
+ /* Use const-cast because the underlying virtual array implementation is shared between const
+ * and non const data. */
+ spans[i] = MutableSpan<T>(const_cast<T *>(span.data()), span.size());
}
- return point_data_gvarray(spans, offsets);
+ return point_data_varray(spans, offsets);
}
- GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const override
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override
{
CurveEval *curve = get_curve_from_component_for_write(component);
if (curve == nullptr) {
return {};
}
+ if (!this->exists(component)) {
+ return {};
+ }
+
+ std::function<void()> tag_modified_fn;
+ if (update_on_write_ != nullptr) {
+ tag_modified_fn = [curve, update = update_on_write_]() {
+ for (SplinePtr &spline : curve->splines()) {
+ update(*spline);
+ }
+ };
+ }
+
MutableSpan<SplinePtr> splines = curve->splines();
if (splines.size() == 1) {
- return std::make_unique<fn::GVMutableArray_For_GMutableSpan>(
- get_mutable_span_(*splines.first()));
+ return {GVMutableArray::ForSpan(get_mutable_span_(*splines.first())),
+ domain_,
+ std::move(tag_modified_fn)};
}
Array<int> offsets = curve->control_point_offsets();
Array<MutableSpan<T>> spans(splines.size());
for (const int i : splines.index_range()) {
spans[i] = get_mutable_span_(*splines[i]);
- if (update_on_write_) {
- update_on_write_(*splines[i]);
- }
}
- return point_data_gvarray(spans, offsets);
+ return {point_data_varray_mutable(spans, offsets), domain_, tag_modified_fn};
}
- bool try_delete(GeometryComponent &UNUSED(component)) const final
+ bool try_delete(GeometryComponent &component) const final
{
- return false;
+ if (deletable_ == DeletableEnum::NonDeletable) {
+ return false;
+ }
+ return remove_point_attribute(component, name_);
}
- bool try_create(GeometryComponent &UNUSED(component),
- const AttributeInit &UNUSED(initializer)) const final
+ bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final
{
- return false;
+ if (createable_ == CreatableEnum::NonCreatable) {
+ return false;
+ }
+ return create_point_attribute(component, name_, initializer, CD_PROP_INT32);
}
bool exists(const GeometryComponent &component) const final
{
- return component.attribute_domain_size(ATTR_DOMAIN_POINT) != 0;
+ const CurveEval *curve = get_curve_from_component_for_read(component);
+ if (curve == nullptr) {
+ return false;
+ }
+
+ Span<SplinePtr> splines = curve->splines();
+ if (splines.size() == 0) {
+ return false;
+ }
+
+ if (stored_in_custom_data_) {
+ if (!curve->splines().first()->attributes.get_for_read(name_)) {
+ return false;
+ }
+ }
+
+ bool has_point = false;
+ for (const SplinePtr &spline : curve->splines()) {
+ if (spline->size() != 0) {
+ has_point = true;
+ break;
+ }
+ }
+
+ if (!has_point) {
+ return false;
+ }
+
+ return true;
}
};
@@ -873,14 +1210,16 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo
PositionAttributeProvider()
: BuiltinPointAttributeProvider(
"position",
- BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::NonDeletable,
[](const Spline &spline) { return spline.positions(); },
[](Spline &spline) { return spline.positions(); },
- [](Spline &spline) { spline.mark_cache_invalid(); })
+ [](Spline &spline) { spline.mark_cache_invalid(); },
+ false)
{
}
- GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
{
CurveEval *curve = get_curve_from_component_for_write(component);
if (curve == nullptr) {
@@ -893,16 +1232,94 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo
return BuiltinPointAttributeProvider<float3>::try_get_for_write(component);
}
- /* Changing the positions requires recalculation of cached evaluated data in many cases.
- * This could set more specific flags in the future to avoid unnecessary recomputation. */
- for (SplinePtr &spline : curve->splines()) {
- spline->mark_cache_invalid();
+ auto tag_modified_fn = [curve]() {
+ /* Changing the positions requires recalculation of cached evaluated data in many cases.
+ * This could set more specific flags in the future to avoid unnecessary recomputation. */
+ curve->mark_cache_invalid();
+ };
+
+ Array<int> offsets = curve->control_point_offsets();
+ return {VMutableArray<float3>::For<VArrayImpl_For_SplinePosition>(curve->splines(),
+ std::move(offsets)),
+ domain_,
+ tag_modified_fn};
+ }
+};
+
+class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
+ private:
+ bool is_right_;
+
+ public:
+ BezierHandleAttributeProvider(const bool is_right)
+ : BuiltinAttributeProvider(is_right ? "handle_right" : "handle_left",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT3,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonDeletable),
+ is_right_(is_right)
+ {
+ }
+
+ GVArray try_get_for_read(const GeometryComponent &component) const override
+ {
+ const CurveEval *curve = get_curve_from_component_for_read(component);
+ if (curve == nullptr) {
+ return {};
+ }
+
+ if (!curve->has_spline_with_type(Spline::Type::Bezier)) {
+ return {};
+ }
+
+ Array<int> offsets = curve->control_point_offsets();
+ /* Use const-cast because the underlying virtual array implementation is shared between const
+ * and non const data. */
+ return VArray<float3>::For<VArrayImpl_For_BezierHandles>(
+ const_cast<CurveEval *>(curve)->splines(), std::move(offsets), is_right_);
+ }
+
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override
+ {
+ CurveEval *curve = get_curve_from_component_for_write(component);
+ if (curve == nullptr) {
+ return {};
+ }
+
+ if (!curve->has_spline_with_type(Spline::Type::Bezier)) {
+ return {};
}
+ auto tag_modified_fn = [curve]() { curve->mark_cache_invalid(); };
+
Array<int> offsets = curve->control_point_offsets();
- return std::make_unique<
- fn::GVMutableArray_For_EmbeddedVMutableArray<float3, VMutableArray_For_SplinePosition>>(
- offsets.last(), curve->splines(), std::move(offsets));
+ return {VMutableArray<float3>::For<VArrayImpl_For_BezierHandles>(
+ curve->splines(), std::move(offsets), is_right_),
+ domain_,
+ tag_modified_fn};
+ }
+
+ bool try_delete(GeometryComponent &UNUSED(component)) const final
+ {
+ return false;
+ }
+
+ bool try_create(GeometryComponent &UNUSED(component),
+ const AttributeInit &UNUSED(initializer)) const final
+ {
+ return false;
+ }
+
+ bool exists(const GeometryComponent &component) const final
+ {
+ const CurveEval *curve = get_curve_from_component_for_read(component);
+ if (curve == nullptr) {
+ return false;
+ }
+
+ return curve->has_spline_with_type(Spline::Type::Bezier) &&
+ component.attribute_domain_size(ATTR_DOMAIN_POINT) != 0;
}
};
@@ -959,19 +1376,22 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
/* First check for the simpler situation when we can return a simpler span virtual array. */
if (spans.size() == 1) {
- return {std::make_unique<GVArray_For_GSpan>(spans.first()), ATTR_DOMAIN_POINT};
+ return {GVArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT};
}
ReadAttributeLookup attribute = {};
Array<int> offsets = curve->control_point_offsets();
attribute_math::convert_to_static_type(spans[0].type(), [&](auto dummy) {
using T = decltype(dummy);
- Array<Span<T>> data(splines.size());
+ Array<MutableSpan<T>> data(splines.size());
for (const int i : splines.index_range()) {
- data[i] = spans[i].typed<T>();
+ Span<T> span = spans[i].typed<T>();
+ /* Use const-cast because the underlying virtual array implementation is shared between
+ * const and non const data. */
+ data[i] = MutableSpan<T>(const_cast<T *>(span.data()), span.size());
BLI_assert(data[i].data() != nullptr);
}
- attribute = {point_data_gvarray(data, offsets), ATTR_DOMAIN_POINT};
+ attribute = {point_data_varray(data, offsets), ATTR_DOMAIN_POINT};
});
return attribute;
}
@@ -1012,7 +1432,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
/* First check for the simpler situation when we can return a simpler span virtual array. */
if (spans.size() == 1) {
- return {std::make_unique<GVMutableArray_For_GMutableSpan>(spans.first()), ATTR_DOMAIN_POINT};
+ return {GVMutableArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT};
}
WriteAttributeLookup attribute = {};
@@ -1024,46 +1444,14 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
data[i] = spans[i].typed<T>();
BLI_assert(data[i].data() != nullptr);
}
- attribute = {point_data_gvarray(data, offsets), ATTR_DOMAIN_POINT};
+ attribute = {point_data_varray_mutable(data, offsets), ATTR_DOMAIN_POINT};
});
return attribute;
}
bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final
{
- CurveEval *curve = get_curve_from_component_for_write(component);
- if (curve == nullptr) {
- return false;
- }
-
- /* Reuse the boolean for all splines; we expect all splines to have the same attributes. */
- bool layer_freed = false;
- for (SplinePtr &spline : curve->splines()) {
- layer_freed = spline->attributes.remove(attribute_id);
- }
- return layer_freed;
- }
-
- static GVArrayPtr varray_from_initializer(const AttributeInit &initializer,
- const CustomDataType data_type,
- const int total_size)
- {
- switch (initializer.type) {
- case AttributeInit::Type::Default:
- /* This function shouldn't be called in this case, since there
- * is no need to copy anything to the new custom data array. */
- BLI_assert_unreachable();
- return {};
- case AttributeInit::Type::VArray:
- return static_cast<const AttributeInitVArray &>(initializer).varray->shallow_copy();
- case AttributeInit::Type::MoveArray:
- return std::make_unique<fn::GVArray_For_GSpan>(
- GSpan(*bke::custom_data_type_to_cpp_type(data_type),
- static_cast<const AttributeInitMove &>(initializer).data,
- total_size));
- }
- BLI_assert_unreachable();
- return {};
+ return remove_point_attribute(component, attribute_id);
}
bool try_create(GeometryComponent &component,
@@ -1076,55 +1464,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
if (domain != ATTR_DOMAIN_POINT) {
return false;
}
- CurveEval *curve = get_curve_from_component_for_write(component);
- if (curve == nullptr || curve->splines().size() == 0) {
- return false;
- }
-
- MutableSpan<SplinePtr> splines = curve->splines();
-
- /* First check the one case that allows us to avoid copying the input data. */
- if (splines.size() == 1 && initializer.type == AttributeInit::Type::MoveArray) {
- void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
- if (!splines[0]->attributes.create_by_move(attribute_id, data_type, source_data)) {
- MEM_freeN(source_data);
- return false;
- }
- return true;
- }
-
- /* Otherwise just create a custom data layer on each of the splines. */
- for (const int i : splines.index_range()) {
- if (!splines[i]->attributes.create(attribute_id, data_type)) {
- /* If attribute creation fails on one of the splines, we cannot leave the custom data
- * layers in the previous splines around, so delete them before returning. However,
- * this is not an expected case. */
- BLI_assert_unreachable();
- return false;
- }
- }
-
- /* With a default initializer type, we can keep the values at their initial values. */
- if (initializer.type == AttributeInit::Type::Default) {
- return true;
- }
-
- WriteAttributeLookup write_attribute = this->try_get_for_write(component, attribute_id);
- /* We just created the attribute, it should exist. */
- BLI_assert(write_attribute);
-
- const int total_size = curve->control_point_offsets().last();
- GVArrayPtr source_varray = varray_from_initializer(initializer, data_type, total_size);
- /* TODO: When we can call a variant of #set_all with a virtual array argument,
- * this theoretically unnecessary materialize step could be removed. */
- GVArray_GSpan source_varray_span{*source_varray};
- write_attribute.varray->set_all(source_varray_span.data());
-
- if (initializer.type == AttributeInit::Type::MoveArray) {
- MEM_freeN(static_cast<const AttributeInitMove &>(initializer).data);
- }
-
- return true;
+ return create_point_attribute(component, attribute_id, initializer, data_type);
}
bool foreach_attribute(const GeometryComponent &component,
@@ -1196,27 +1536,51 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
spline_custom_data_access);
static PositionAttributeProvider position;
+ static BezierHandleAttributeProvider handles_start(false);
+ static BezierHandleAttributeProvider handles_end(true);
+
+ static BuiltinPointAttributeProvider<int> id(
+ "id",
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Deletable,
+ [](const Spline &spline) {
+ std::optional<GSpan> span = spline.attributes.get_for_read("id");
+ return span ? span->typed<int>() : Span<int>();
+ },
+ [](Spline &spline) {
+ std::optional<GMutableSpan> span = spline.attributes.get_for_write("id");
+ return span ? span->typed<int>() : MutableSpan<int>();
+ },
+ {},
+ true);
static BuiltinPointAttributeProvider<float> radius(
"radius",
- BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::NonDeletable,
[](const Spline &spline) { return spline.radii(); },
[](Spline &spline) { return spline.radii(); },
- nullptr);
+ nullptr,
+ false);
static BuiltinPointAttributeProvider<float> tilt(
"tilt",
- BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::NonDeletable,
[](const Spline &spline) { return spline.tilts(); },
[](Spline &spline) { return spline.tilts(); },
- [](Spline &spline) { spline.mark_cache_invalid(); });
+ [](Spline &spline) { spline.mark_cache_invalid(); },
+ false);
static DynamicPointAttributeProvider point_custom_data;
- return ComponentAttributeProviders({&position, &radius, &tilt, &resolution, &cyclic},
- {&spline_custom_data, &point_custom_data});
+ return ComponentAttributeProviders(
+ {&position, &id, &radius, &tilt, &handles_start, &handles_end, &resolution, &cyclic},
+ {&spline_custom_data, &point_custom_data});
}
+/** \} */
+
} // namespace blender::bke
const blender::bke::ComponentAttributeProviders *CurveComponent::get_attribute_providers() const
@@ -1225,5 +1589,3 @@ const blender::bke::ComponentAttributeProviders *CurveComponent::get_attribute_p
blender::bke::create_attribute_providers_for_curve();
return &providers;
}
-
-/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 4204d62e1a7..b411c793298 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -17,6 +17,7 @@
#include <mutex>
#include "BLI_float4x4.hh"
+#include "BLI_index_mask.hh"
#include "BLI_map.hh"
#include "BLI_rand.hh"
#include "BLI_set.hh"
@@ -26,17 +27,25 @@
#include "DNA_collection_types.h"
+#include "BKE_attribute_access.hh"
+#include "BKE_attribute_math.hh"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
#include "attribute_access_intern.hh"
+#include "FN_cpp_type_make.hh"
+
using blender::float4x4;
+using blender::IndexMask;
using blender::Map;
using blender::MutableSpan;
using blender::Set;
using blender::Span;
using blender::VectorSet;
+using blender::fn::GSpan;
+
+MAKE_CPP_TYPE(InstanceReference, InstanceReference, CPPTypeFlags::None)
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
@@ -51,8 +60,8 @@ GeometryComponent *InstancesComponent::copy() const
InstancesComponent *new_component = new InstancesComponent();
new_component->instance_reference_handles_ = instance_reference_handles_;
new_component->instance_transforms_ = instance_transforms_;
- new_component->instance_ids_ = instance_ids_;
new_component->references_ = references_;
+ new_component->attributes_ = attributes_;
return new_component;
}
@@ -60,40 +69,31 @@ void InstancesComponent::reserve(int min_capacity)
{
instance_reference_handles_.reserve(min_capacity);
instance_transforms_.reserve(min_capacity);
- instance_ids_.reserve(min_capacity);
+ attributes_.reallocate(min_capacity);
}
-/**
- * Resize the transform, handles, and ID vectors to the specified capacity.
- *
- * \note This function should be used carefully, only when it's guaranteed
- * that the data will be filled.
- */
void InstancesComponent::resize(int capacity)
{
instance_reference_handles_.resize(capacity);
instance_transforms_.resize(capacity);
- instance_ids_.resize(capacity);
+ attributes_.reallocate(capacity);
}
void InstancesComponent::clear()
{
instance_reference_handles_.clear();
instance_transforms_.clear();
- instance_ids_.clear();
-
+ attributes_.clear();
references_.clear();
}
-void InstancesComponent::add_instance(const int instance_handle,
- const float4x4 &transform,
- const int id)
+void InstancesComponent::add_instance(const int instance_handle, const float4x4 &transform)
{
BLI_assert(instance_handle >= 0);
BLI_assert(instance_handle < references_.size());
instance_reference_handles_.append(instance_handle);
instance_transforms_.append(transform);
- instance_ids_.append(id);
+ attributes_.reallocate(this->instances_amount());
}
blender::Span<int> InstancesComponent::instance_reference_handles() const
@@ -115,20 +115,6 @@ blender::Span<blender::float4x4> InstancesComponent::instance_transforms() const
return instance_transforms_;
}
-blender::MutableSpan<int> InstancesComponent::instance_ids()
-{
- return instance_ids_;
-}
-blender::Span<int> InstancesComponent::instance_ids() const
-{
- return instance_ids_;
-}
-
-/**
- * With write access to the instances component, the data in the instanced geometry sets can be
- * changed. This is a function on the component rather than each reference to ensure `const`
- * correctness for that reason.
- */
GeometrySet &InstancesComponent::geometry_set_from_reference(const int reference_index)
{
/* If this assert fails, it means #ensure_geometry_instances must be called first or that the
@@ -140,11 +126,6 @@ GeometrySet &InstancesComponent::geometry_set_from_reference(const int reference
return const_cast<GeometrySet &>(references_[reference_index].geometry_set());
}
-/**
- * Returns a handle for the given reference.
- * If the reference exists already, the handle of the existing reference is returned.
- * Otherwise a new handle is added.
- */
int InstancesComponent::add_reference(const InstanceReference &reference)
{
return references_.index_of_or_add_as(reference);
@@ -155,6 +136,62 @@ blender::Span<InstanceReference> InstancesComponent::references() const
return references_;
}
+template<typename T>
+static void copy_data_based_on_mask(Span<T> src, MutableSpan<T> dst, IndexMask mask)
+{
+ BLI_assert(src.data() != dst.data());
+ using namespace blender;
+ threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ dst[i] = src[mask[i]];
+ }
+ });
+}
+
+void InstancesComponent::remove_instances(const IndexMask mask)
+{
+ using namespace blender;
+ if (mask.is_range() && mask.as_range().start() == 0) {
+ /* Deleting from the end of the array can be much faster since no data has to be shifted. */
+ this->resize(mask.size());
+ this->remove_unused_references();
+ return;
+ }
+
+ Vector<int> new_handles(mask.size());
+ copy_data_based_on_mask<int>(this->instance_reference_handles(), new_handles, mask);
+ instance_reference_handles_ = std::move(new_handles);
+ Vector<float4x4> new_transforms(mask.size());
+ copy_data_based_on_mask<float4x4>(this->instance_transforms(), new_transforms, mask);
+ instance_transforms_ = std::move(new_transforms);
+
+ const bke::CustomDataAttributes &src_attributes = attributes_;
+
+ bke::CustomDataAttributes dst_attributes;
+ dst_attributes.reallocate(mask.size());
+
+ src_attributes.foreach_attribute(
+ [&](const bke::AttributeIDRef &id, const AttributeMetaData &meta_data) {
+ if (!id.should_be_kept()) {
+ return true;
+ }
+
+ GSpan src = *src_attributes.get_for_read(id);
+ dst_attributes.create(id, meta_data.data_type);
+ fn::GMutableSpan dst = *dst_attributes.get_for_write(id);
+
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_data_based_on_mask<T>(src.typed<T>(), dst.typed<T>(), mask);
+ });
+ return true;
+ },
+ ATTR_DOMAIN_INSTANCE);
+
+ attributes_ = std::move(dst_attributes);
+ this->remove_unused_references();
+}
+
void InstancesComponent::remove_unused_references()
{
using namespace blender;
@@ -327,20 +364,40 @@ static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
blender::Span<int> InstancesComponent::almost_unique_ids() const
{
std::lock_guard lock(almost_unique_ids_mutex_);
- if (almost_unique_ids_.size() != instance_ids_.size()) {
- almost_unique_ids_ = generate_unique_instance_ids(instance_ids_);
+ std::optional<GSpan> instance_ids_gspan = attributes_.get_for_read("id");
+ if (instance_ids_gspan) {
+ Span<int> instance_ids = instance_ids_gspan->typed<int>();
+ if (almost_unique_ids_.size() != instance_ids.size()) {
+ almost_unique_ids_ = generate_unique_instance_ids(instance_ids);
+ }
+ }
+ else {
+ almost_unique_ids_.reinitialize(this->instances_amount());
+ for (const int i : almost_unique_ids_.index_range()) {
+ almost_unique_ids_[i] = i;
+ }
}
return almost_unique_ids_;
}
int InstancesComponent::attribute_domain_size(const AttributeDomain domain) const
{
- if (domain != ATTR_DOMAIN_POINT) {
+ if (domain != ATTR_DOMAIN_INSTANCE) {
return 0;
}
return this->instances_amount();
}
+blender::bke::CustomDataAttributes &InstancesComponent::attributes()
+{
+ return this->attributes_;
+}
+
+const blender::bke::CustomDataAttributes &InstancesComponent::attributes() const
+{
+ return this->attributes_;
+}
+
namespace blender::bke {
static float3 get_transform_position(const float4x4 &transform)
@@ -357,28 +414,26 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
public:
InstancePositionAttributeProvider()
: BuiltinAttributeProvider(
- "position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, NonCreatable, Writable, NonDeletable)
+ "position", ATTR_DOMAIN_INSTANCE, CD_PROP_FLOAT3, NonCreatable, Writable, NonDeletable)
{
}
- GVArrayPtr try_get_for_read(const GeometryComponent &component) const final
+ GVArray try_get_for_read(const GeometryComponent &component) const final
{
const InstancesComponent &instances_component = static_cast<const InstancesComponent &>(
component);
Span<float4x4> transforms = instances_component.instance_transforms();
- return std::make_unique<fn::GVArray_For_DerivedSpan<float4x4, float3, get_transform_position>>(
- transforms);
+ return VArray<float3>::ForDerivedSpan<float4x4, get_transform_position>(transforms);
}
- GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
{
InstancesComponent &instances_component = static_cast<InstancesComponent &>(component);
MutableSpan<float4x4> transforms = instances_component.instance_transforms();
- return std::make_unique<fn::GVMutableArray_For_DerivedSpan<float4x4,
- float3,
- get_transform_position,
- set_transform_position>>(
- transforms);
+ return {VMutableArray<float3>::ForDerivedSpan<float4x4,
+ get_transform_position,
+ set_transform_position>(transforms),
+ domain_};
}
bool try_delete(GeometryComponent &UNUSED(component)) const final
@@ -398,11 +453,54 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
}
};
+template<typename T>
+static GVArray make_array_read_attribute(const void *data, const int domain_size)
+{
+ return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size));
+}
+
+template<typename T>
+static GVMutableArray make_array_write_attribute(void *data, const int domain_size)
+{
+ return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size));
+}
+
static ComponentAttributeProviders create_attribute_providers_for_instances()
{
static InstancePositionAttributeProvider position;
-
- return ComponentAttributeProviders({&position}, {});
+ static CustomDataAccessInfo instance_custom_data_access = {
+ [](GeometryComponent &component) -> CustomData * {
+ InstancesComponent &inst = static_cast<InstancesComponent &>(component);
+ return &inst.attributes().data;
+ },
+ [](const GeometryComponent &component) -> const CustomData * {
+ const InstancesComponent &inst = static_cast<const InstancesComponent &>(component);
+ return &inst.attributes().data;
+ },
+ nullptr};
+
+ /**
+ * IDs of the instances. They are used for consistency over multiple frames for things like
+ * motion blur. Proper stable ID data that actually helps when rendering can only be generated
+ * in some situations, so this vector is allowed to be empty, in which case the index of each
+ * instance will be used for the final ID.
+ */
+ static BuiltinCustomDataLayerProvider id("id",
+ ATTR_DOMAIN_INSTANCE,
+ CD_PROP_INT32,
+ CD_PROP_INT32,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ instance_custom_data_access,
+ make_array_read_attribute<int>,
+ make_array_write_attribute<int>,
+ nullptr);
+
+ static CustomDataAttributeProvider instance_custom_data(ATTR_DOMAIN_INSTANCE,
+ instance_custom_data_access);
+
+ return ComponentAttributeProviders({&position, &id}, {&instance_custom_data});
}
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 0c98aa5551b..2509448d8aa 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -15,6 +15,7 @@
*/
#include "BLI_listbase.h"
+#include "BLI_task.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -29,11 +30,8 @@
#include "attribute_access_intern.hh"
-/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */
extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
-using blender::fn::GVArray;
-
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
* \{ */
@@ -73,7 +71,6 @@ bool MeshComponent::has_mesh() const
return mesh_ != nullptr;
}
-/* Clear the component and replace it with the new mesh. */
void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
@@ -82,8 +79,6 @@ void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership)
ownership_ = ownership;
}
-/* Return the mesh and clear the component. The caller takes over responsibility for freeing the
- * mesh (if the component was responsible before). */
Mesh *MeshComponent::release()
{
BLI_assert(this->is_mutable());
@@ -92,15 +87,11 @@ Mesh *MeshComponent::release()
return mesh;
}
-/* Get the mesh from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned mesh should not be modified. No ownership is transferred. */
const Mesh *MeshComponent::get_for_read() const
{
return mesh_;
}
-/* Get the mesh from this component. This method can only be used when the component is mutable,
- * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred. */
Mesh *MeshComponent::get_for_write()
{
BLI_assert(this->is_mutable());
@@ -133,6 +124,61 @@ void MeshComponent::ensure_owns_direct_data()
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Mesh Normals Field Input
+ * \{ */
+
+namespace blender::bke {
+
+VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
+ const Mesh &mesh,
+ const IndexMask mask,
+ const AttributeDomain domain)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_FACE: {
+ return VArray<float3>::ForSpan(
+ {(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly});
+ }
+ case ATTR_DOMAIN_POINT: {
+ return VArray<float3>::ForSpan(
+ {(float3 *)BKE_mesh_vertex_normals_ensure(&mesh), mesh.totvert});
+ }
+ case ATTR_DOMAIN_EDGE: {
+ /* In this case, start with vertex normals and convert to the edge domain, since the
+ * conversion from edges to vertices is very simple. Use "manual" domain interpolation
+ * instead of the GeometryComponent API to avoid calculating unnecessary values and to
+ * allow normalizing the result more simply. */
+ Span<float3> vert_normals{(float3 *)BKE_mesh_vertex_normals_ensure(&mesh), mesh.totvert};
+ Array<float3> edge_normals(mask.min_array_size());
+ Span<MEdge> edges{mesh.medge, mesh.totedge};
+ for (const int i : mask) {
+ const MEdge &edge = edges[i];
+ edge_normals[i] = math::normalize(
+ math::interpolate(vert_normals[edge.v1], vert_normals[edge.v2], 0.5f));
+ }
+
+ return VArray<float3>::ForContainer(std::move(edge_normals));
+ }
+ case ATTR_DOMAIN_CORNER: {
+ /* The normals on corners are just the mesh's face normals, so start with the face normal
+ * array and copy the face normal for each of its corners. In this case using the mesh
+ * component's generic domain interpolation is fine, the data will still be normalized,
+ * since the face normal is just copied to every corner. */
+ return mesh_component.attribute_try_adapt_domain(
+ VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly}),
+ ATTR_DOMAIN_FACE,
+ ATTR_DOMAIN_CORNER);
+ }
+ default:
+ return {};
+ }
+}
+
+} // namespace blender::bke
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Attribute Access
* \{ */
@@ -203,17 +249,17 @@ void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
}
}
-static GVArrayPtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, GVArrayPtr varray)
+static GVArray adapt_mesh_domain_corner_to_point(const Mesh &mesh, const GVArray &varray)
{
- GVArrayPtr new_varray;
- attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
+ GVArray new_varray;
+ attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
/* We compute all interpolated values at once, because for this interpolation, one has to
* iterate over all loops anyway. */
Array<T> values(mesh.totvert);
- adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray->typed<T>(), values);
- new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray.typed<T>(), values);
+ new_varray = VArray<T>::ForContainer(std::move(values));
}
});
return new_varray;
@@ -221,89 +267,54 @@ static GVArrayPtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, GVArrayPtr
/**
* Each corner's value is simply a copy of the value at its vertex.
- *
- * \note Theoretically this interpolation does not need to compute all values at once.
- * However, doing that makes the implementation simpler, and this can be optimized in the future if
- * only some values are required.
*/
-template<typename T>
-static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh,
- const VArray<T> &old_values,
- MutableSpan<T> r_values)
-{
- BLI_assert(r_values.size() == mesh.totloop);
-
- for (const int loop_index : IndexRange(mesh.totloop)) {
- const int vertex_index = mesh.mloop[loop_index].v;
- r_values[loop_index] = old_values[vertex_index];
- }
-}
-
-static GVArrayPtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, GVArrayPtr varray)
+static GVArray adapt_mesh_domain_point_to_corner(const Mesh &mesh, const GVArray &varray)
{
- GVArrayPtr new_varray;
- attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
+ GVArray new_varray;
+ attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
- Array<T> values(mesh.totloop);
- adapt_mesh_domain_point_to_corner_impl<T>(mesh, varray->typed<T>(), values);
- new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ new_varray = VArray<T>::ForFunc(mesh.totloop,
+ [mesh, varray = varray.typed<T>()](const int64_t loop_index) {
+ const int vertex_index = mesh.mloop[loop_index].v;
+ return varray[vertex_index];
+ });
});
return new_varray;
}
-/**
- * \note Theoretically this interpolation does not need to compute all values at once.
- * However, doing that makes the implementation simpler, and this can be optimized in the future if
- * only some values are required.
- */
-template<typename T>
-static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
- const VArray<T> &old_values,
- MutableSpan<T> r_values)
+static GVArray adapt_mesh_domain_corner_to_face(const Mesh &mesh, const GVArray &varray)
{
- BLI_assert(r_values.size() == mesh.totpoly);
- attribute_math::DefaultMixer<T> mixer(r_values);
-
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const T value = old_values[loop_index];
- mixer.mix_in(poly_index, value);
- }
- }
-
- mixer.finalize();
-}
-
-/* A face is selected if all of its corners were selected. */
-template<>
-void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
- const VArray<bool> &old_values,
- MutableSpan<bool> r_values)
-{
- BLI_assert(r_values.size() == mesh.totpoly);
-
- r_values.fill(true);
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- if (!old_values[loop_index]) {
- r_values[poly_index] = false;
- break;
- }
- }
- }
-}
-
-static GVArrayPtr adapt_mesh_domain_corner_to_face(const Mesh &mesh, GVArrayPtr varray)
-{
- GVArrayPtr new_varray;
- attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
+ GVArray new_varray;
+ attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
- Array<T> values(mesh.totpoly);
- adapt_mesh_domain_corner_to_face_impl<T>(mesh, varray->typed<T>(), values);
- new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ if constexpr (std::is_same_v<T, bool>) {
+ new_varray = VArray<T>::ForFunc(
+ mesh.totpoly, [mesh, varray = varray.typed<bool>()](const int face_index) {
+ /* A face is selected if all of its corners were selected. */
+ const MPoly &poly = mesh.mpoly[face_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ if (!varray[loop_index]) {
+ return false;
+ }
+ }
+ return true;
+ });
+ }
+ else {
+ new_varray = VArray<T>::ForFunc(
+ mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) {
+ T return_value;
+ attribute_math::DefaultMixer<T> mixer({&return_value, 1});
+ const MPoly &poly = mesh.mpoly[face_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const T value = varray[loop_index];
+ mixer.mix_in(0, value);
+ }
+ mixer.finalize();
+ return return_value;
+ });
+ }
}
});
return new_varray;
@@ -361,22 +372,24 @@ void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
}
/* Deselect loose edges without corners that are still selected from the 'true' default. */
- for (const int edge_index : IndexRange(mesh.totedge)) {
- if (loose_edges[edge_index]) {
- r_values[edge_index] = false;
+ threading::parallel_for(IndexRange(mesh.totedge), 2048, [&](const IndexRange range) {
+ for (const int edge_index : range) {
+ if (loose_edges[edge_index]) {
+ r_values[edge_index] = false;
+ }
}
- }
+ });
}
-static GVArrayPtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh, GVArrayPtr varray)
+static GVArray adapt_mesh_domain_corner_to_edge(const Mesh &mesh, const GVArray &varray)
{
- GVArrayPtr new_varray;
- attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
+ GVArray new_varray;
+ attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totedge);
- adapt_mesh_domain_corner_to_edge_impl<T>(mesh, varray->typed<T>(), values);
- new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ adapt_mesh_domain_corner_to_edge_impl<T>(mesh, varray.typed<T>(), values);
+ new_varray = VArray<T>::ForContainer(std::move(values));
}
});
return new_varray;
@@ -424,15 +437,15 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
}
}
-static GVArrayPtr adapt_mesh_domain_face_to_point(const Mesh &mesh, GVArrayPtr varray)
+static GVArray adapt_mesh_domain_face_to_point(const Mesh &mesh, const GVArray &varray)
{
- GVArrayPtr new_varray;
- attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
+ GVArray new_varray;
+ attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totvert);
- adapt_mesh_domain_face_to_point_impl<T>(mesh, varray->typed<T>(), values);
- new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ adapt_mesh_domain_face_to_point_impl<T>(mesh, varray.typed<T>(), values);
+ new_varray = VArray<T>::ForContainer(std::move(values));
}
});
return new_varray;
@@ -446,22 +459,24 @@ void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh,
{
BLI_assert(r_values.size() == mesh.totloop);
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- MutableSpan<T> poly_corner_values = r_values.slice(poly.loopstart, poly.totloop);
- poly_corner_values.fill(old_values[poly_index]);
- }
+ threading::parallel_for(IndexRange(mesh.totpoly), 1024, [&](const IndexRange range) {
+ for (const int poly_index : range) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ MutableSpan<T> poly_corner_values = r_values.slice(poly.loopstart, poly.totloop);
+ poly_corner_values.fill(old_values[poly_index]);
+ }
+ });
}
-static GVArrayPtr adapt_mesh_domain_face_to_corner(const Mesh &mesh, GVArrayPtr varray)
+static GVArray adapt_mesh_domain_face_to_corner(const Mesh &mesh, const GVArray &varray)
{
- GVArrayPtr new_varray;
- attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
+ GVArray new_varray;
+ attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totloop);
- adapt_mesh_domain_face_to_corner_impl<T>(mesh, varray->typed<T>(), values);
- new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ adapt_mesh_domain_face_to_corner_impl<T>(mesh, varray.typed<T>(), values);
+ new_varray = VArray<T>::ForContainer(std::move(values));
}
});
return new_varray;
@@ -507,125 +522,86 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
}
}
-static GVArrayPtr adapt_mesh_domain_face_to_edge(const Mesh &mesh, GVArrayPtr varray)
+static GVArray adapt_mesh_domain_face_to_edge(const Mesh &mesh, const GVArray &varray)
{
- GVArrayPtr new_varray;
- attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
+ GVArray new_varray;
+ attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totedge);
- adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray->typed<T>(), values);
- new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray.typed<T>(), values);
+ new_varray = VArray<T>::ForContainer(std::move(values));
}
});
return new_varray;
}
-/**
- * \note Theoretically this interpolation does not need to compute all values at once.
- * However, doing that makes the implementation simpler, and this can be optimized in the future if
- * only some values are required.
- */
-template<typename T>
-static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
- const VArray<T> &old_values,
- MutableSpan<T> r_values)
-{
- BLI_assert(r_values.size() == mesh.totpoly);
- attribute_math::DefaultMixer<T> mixer(r_values);
-
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- MLoop &loop = mesh.mloop[loop_index];
- const int point_index = loop.v;
- mixer.mix_in(poly_index, old_values[point_index]);
- }
- }
- mixer.finalize();
-}
-
-/* A face is selected if all of its vertices were selected too. */
-template<>
-void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
- const VArray<bool> &old_values,
- MutableSpan<bool> r_values)
+static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray &varray)
{
- BLI_assert(r_values.size() == mesh.totpoly);
-
- r_values.fill(true);
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- MLoop &loop = mesh.mloop[loop_index];
- const int vert_index = loop.v;
- if (!old_values[vert_index]) {
- r_values[poly_index] = false;
- break;
- }
- }
- }
-}
-
-static GVArrayPtr adapt_mesh_domain_point_to_face(const Mesh &mesh, GVArrayPtr varray)
-{
- GVArrayPtr new_varray;
- attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
+ GVArray new_varray;
+ attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
- Array<T> values(mesh.totpoly);
- adapt_mesh_domain_point_to_face_impl<T>(mesh, varray->typed<T>(), values);
- new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ if constexpr (std::is_same_v<T, bool>) {
+ new_varray = VArray<T>::ForFunc(
+ mesh.totpoly, [mesh, varray = varray.typed<bool>()](const int face_index) {
+ /* A face is selected if all of its vertices were selected. */
+ const MPoly &poly = mesh.mpoly[face_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ if (!varray[loop.v]) {
+ return false;
+ }
+ }
+ return true;
+ });
+ }
+ else {
+ new_varray = VArray<T>::ForFunc(
+ mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) {
+ T return_value;
+ attribute_math::DefaultMixer<T> mixer({&return_value, 1});
+ const MPoly &poly = mesh.mpoly[face_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ const T value = varray[loop.v];
+ mixer.mix_in(0, value);
+ }
+ mixer.finalize();
+ return return_value;
+ });
+ }
}
});
return new_varray;
}
-/**
- * \note Theoretically this interpolation does not need to compute all values at once.
- * However, doing that makes the implementation simpler, and this can be optimized in the future if
- * only some values are required.
- */
-template<typename T>
-static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
- const VArray<T> &old_values,
- MutableSpan<T> r_values)
-{
- BLI_assert(r_values.size() == mesh.totedge);
- attribute_math::DefaultMixer<T> mixer(r_values);
-
- for (const int edge_index : IndexRange(mesh.totedge)) {
- const MEdge &edge = mesh.medge[edge_index];
- mixer.mix_in(edge_index, old_values[edge.v1]);
- mixer.mix_in(edge_index, old_values[edge.v2]);
- }
-
- mixer.finalize();
-}
-
-/* An edge is selected if both of its vertices were selected. */
-template<>
-void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
- const VArray<bool> &old_values,
- MutableSpan<bool> r_values)
-{
- BLI_assert(r_values.size() == mesh.totedge);
-
- for (const int edge_index : IndexRange(mesh.totedge)) {
- const MEdge &edge = mesh.medge[edge_index];
- r_values[edge_index] = old_values[edge.v1] && old_values[edge.v2];
- }
-}
-
-static GVArrayPtr adapt_mesh_domain_point_to_edge(const Mesh &mesh, GVArrayPtr varray)
+static GVArray adapt_mesh_domain_point_to_edge(const Mesh &mesh, const GVArray &varray)
{
- GVArrayPtr new_varray;
- attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
+ GVArray new_varray;
+ attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
- Array<T> values(mesh.totedge);
- adapt_mesh_domain_point_to_edge_impl<T>(mesh, varray->typed<T>(), values);
- new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ if constexpr (std::is_same_v<T, bool>) {
+ /* An edge is selected if both of its vertices were selected. */
+ new_varray = VArray<bool>::ForFunc(
+ mesh.totedge, [mesh, varray = varray.typed<bool>()](const int edge_index) {
+ const MEdge &edge = mesh.medge[edge_index];
+ return varray[edge.v1] && varray[edge.v2];
+ });
+ }
+ else {
+ new_varray = VArray<T>::ForFunc(
+ mesh.totedge, [mesh, varray = varray.typed<T>()](const int edge_index) {
+ T return_value;
+ attribute_math::DefaultMixer<T> mixer({&return_value, 1});
+ const MEdge &edge = mesh.medge[edge_index];
+ mixer.mix_in(0, varray[edge.v1]);
+ mixer.mix_in(0, varray[edge.v2]);
+ mixer.finalize();
+ return return_value;
+ });
+ }
}
});
return new_varray;
@@ -678,15 +654,15 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
}
}
-static GVArrayPtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh, GVArrayPtr varray)
+static GVArray adapt_mesh_domain_edge_to_corner(const Mesh &mesh, const GVArray &varray)
{
- GVArrayPtr new_varray;
- attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
+ GVArray new_varray;
+ attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totloop);
- adapt_mesh_domain_edge_to_corner_impl<T>(mesh, varray->typed<T>(), values);
- new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ adapt_mesh_domain_edge_to_corner_impl<T>(mesh, varray.typed<T>(), values);
+ new_varray = VArray<T>::ForContainer(std::move(values));
}
});
return new_varray;
@@ -728,75 +704,55 @@ void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
}
}
-static GVArrayPtr adapt_mesh_domain_edge_to_point(const Mesh &mesh, GVArrayPtr varray)
+static GVArray adapt_mesh_domain_edge_to_point(const Mesh &mesh, const GVArray &varray)
{
- GVArrayPtr new_varray;
- attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
+ GVArray new_varray;
+ attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totvert);
- adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray->typed<T>(), values);
- new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray.typed<T>(), values);
+ new_varray = VArray<T>::ForContainer(std::move(values));
}
});
return new_varray;
}
-/**
- * \note Theoretically this interpolation does not need to compute all values at once.
- * However, doing that makes the implementation simpler, and this can be optimized in the future if
- * only some values are required.
- */
-template<typename T>
-static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
- const VArray<T> &old_values,
- MutableSpan<T> r_values)
-{
- BLI_assert(r_values.size() == mesh.totpoly);
- attribute_math::DefaultMixer<T> mixer(r_values);
-
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = mesh.mloop[loop_index];
- mixer.mix_in(poly_index, old_values[loop.e]);
- }
- }
-
- mixer.finalize();
-}
-
-/* A face is selected if all of its edges are selected. */
-template<>
-void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
- const VArray<bool> &old_values,
- MutableSpan<bool> r_values)
-{
- BLI_assert(r_values.size() == mesh.totpoly);
-
- r_values.fill(true);
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = mesh.mloop[loop_index];
- const int edge_index = loop.e;
- if (!old_values[edge_index]) {
- r_values[poly_index] = false;
- break;
- }
- }
- }
-}
-
-static GVArrayPtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, GVArrayPtr varray)
+static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &varray)
{
- GVArrayPtr new_varray;
- attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
+ GVArray new_varray;
+ attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
- Array<T> values(mesh.totpoly);
- adapt_mesh_domain_edge_to_face_impl<T>(mesh, varray->typed<T>(), values);
- new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ if constexpr (std::is_same_v<T, bool>) {
+ /* A face is selected if all of its edges are selected. */
+ new_varray = VArray<bool>::ForFunc(
+ mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) {
+ const MPoly &poly = mesh.mpoly[face_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ if (!varray[loop.e]) {
+ return false;
+ }
+ }
+ return true;
+ });
+ }
+ else {
+ new_varray = VArray<T>::ForFunc(
+ mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) {
+ T return_value;
+ attribute_math::DefaultMixer<T> mixer({&return_value, 1});
+ const MPoly &poly = mesh.mpoly[face_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ const T value = varray[loop.e];
+ mixer.mix_in(0, value);
+ }
+ mixer.finalize();
+ return return_value;
+ });
+ }
}
});
return new_varray;
@@ -804,15 +760,15 @@ static GVArrayPtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, GVArrayPtr va
} // namespace blender::bke
-blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain(
- blender::fn::GVArrayPtr varray,
+blender::fn::GVArray MeshComponent::attribute_try_adapt_domain_impl(
+ const blender::fn::GVArray &varray,
const AttributeDomain from_domain,
const AttributeDomain to_domain) const
{
if (!varray) {
return {};
}
- if (varray->size() == 0) {
+ if (varray.size() == 0) {
return {};
}
if (from_domain == to_domain) {
@@ -823,11 +779,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain(
case ATTR_DOMAIN_CORNER: {
switch (to_domain) {
case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(varray));
+ return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, varray);
case ATTR_DOMAIN_FACE:
- return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(varray));
+ return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, varray);
case ATTR_DOMAIN_EDGE:
- return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(varray));
+ return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, varray);
default:
break;
}
@@ -836,11 +792,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain(
case ATTR_DOMAIN_POINT: {
switch (to_domain) {
case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(varray));
+ return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, varray);
case ATTR_DOMAIN_FACE:
- return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(varray));
+ return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, varray);
case ATTR_DOMAIN_EDGE:
- return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(varray));
+ return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, varray);
default:
break;
}
@@ -849,11 +805,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain(
case ATTR_DOMAIN_FACE: {
switch (to_domain) {
case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(varray));
+ return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, varray);
case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(varray));
+ return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, varray);
case ATTR_DOMAIN_EDGE:
- return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(varray));
+ return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, varray);
default:
break;
}
@@ -862,11 +818,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain(
case ATTR_DOMAIN_EDGE: {
switch (to_domain) {
case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(varray));
+ return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, varray);
case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(varray));
+ return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, varray);
case ATTR_DOMAIN_FACE:
- return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(varray));
+ return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, varray);
default:
break;
}
@@ -896,9 +852,9 @@ static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &com
namespace blender::bke {
template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
-static GVArrayPtr make_derived_read_attribute(const void *data, const int domain_size)
+static GVArray make_derived_read_attribute(const void *data, const int domain_size)
{
- return std::make_unique<fn::GVArray_For_DerivedSpan<StructT, ElemT, GetFunc>>(
+ return VArray<ElemT>::template ForDerivedSpan<StructT, GetFunc>(
Span<StructT>((const StructT *)data, domain_size));
}
@@ -906,12 +862,24 @@ template<typename StructT,
typename ElemT,
ElemT (*GetFunc)(const StructT &),
void (*SetFunc)(StructT &, ElemT)>
-static GVMutableArrayPtr make_derived_write_attribute(void *data, const int domain_size)
+static GVMutableArray make_derived_write_attribute(void *data, const int domain_size)
{
- return std::make_unique<fn::GVMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>(
+ return VMutableArray<ElemT>::template ForDerivedSpan<StructT, GetFunc, SetFunc>(
MutableSpan<StructT>((StructT *)data, domain_size));
}
+template<typename T>
+static GVArray make_array_read_attribute(const void *data, const int domain_size)
+{
+ return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size));
+}
+
+template<typename T>
+static GVMutableArray make_array_write_attribute(void *data, const int domain_size)
+{
+ return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size));
+}
+
static float3 get_vertex_position(const MVert &vert)
{
return float3(vert.co);
@@ -986,57 +954,36 @@ static void set_crease(MEdge &edge, float value)
edge.crease = round_fl_to_uchar_clamp(value * 255.0f);
}
-class VMutableArray_For_VertexWeights final : public VMutableArray<float> {
+class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl<float> {
private:
MDeformVert *dverts_;
const int dvert_index_;
public:
- VMutableArray_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index)
- : VMutableArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
- {
- }
-
- float get_impl(const int64_t index) const override
- {
- return get_internal(dverts_, dvert_index_, index);
- }
-
- void set_impl(const int64_t index, const float value) override
+ VArrayImpl_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index)
+ : VMutableArrayImpl<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
{
- MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
- weight->weight = value;
}
- static float get_internal(const MDeformVert *dverts, const int dvert_index, const int64_t index)
+ float get(const int64_t index) const override
{
- if (dverts == nullptr) {
+ if (dverts_ == nullptr) {
return 0.0f;
}
- const MDeformVert &dvert = dverts[index];
+ const MDeformVert &dvert = dverts_[index];
for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) {
- if (weight.def_nr == dvert_index) {
+ if (weight.def_nr == dvert_index_) {
return weight.weight;
}
}
return 0.0f;
- }
-};
-
-class VArray_For_VertexWeights final : public VArray<float> {
- private:
- const MDeformVert *dverts_;
- const int dvert_index_;
-
- public:
- VArray_For_VertexWeights(const MDeformVert *dverts, const int totvert, const int dvert_index)
- : VArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
- {
+ ;
}
- float get_impl(const int64_t index) const override
+ void set(const int64_t index, const float value) override
{
- return VMutableArray_For_VertexWeights::get_internal(dverts_, dvert_index_, index);
+ MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
+ weight->weight = value;
}
};
@@ -1065,12 +1012,10 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
}
if (mesh->dvert == nullptr) {
static const float default_value = 0.0f;
- return {std::make_unique<fn::GVArray_For_SingleValueRef>(
- CPPType::get<float>(), mesh->totvert, &default_value),
- ATTR_DOMAIN_POINT};
+ return {VArray<float>::ForSingle(default_value, mesh->totvert), ATTR_DOMAIN_POINT};
}
- return {std::make_unique<fn::GVArray_For_EmbeddedVArray<float, VArray_For_VertexWeights>>(
- mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index),
+ return {VArray<float>::For<VArrayImpl_For_VertexWeights>(
+ mesh->dvert, mesh->totvert, vertex_group_index),
ATTR_DOMAIN_POINT};
}
@@ -1101,11 +1046,9 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer(
&mesh->vdata, CD_MDEFORMVERT, mesh->totvert);
}
- return {
- std::make_unique<
- fn::GVMutableArray_For_EmbeddedVMutableArray<float, VMutableArray_For_VertexWeights>>(
- mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index),
- ATTR_DOMAIN_POINT};
+ return {VMutableArray<float>::For<VArrayImpl_For_VertexWeights>(
+ mesh->dvert, mesh->totvert, vertex_group_index),
+ ATTR_DOMAIN_POINT};
}
bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final
@@ -1121,16 +1064,19 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
}
const std::string name = attribute_id.name();
- const int vertex_group_index = BLI_findstringindex(
- &mesh->vertex_group_names, name.c_str(), offsetof(bDeformGroup, name));
- if (vertex_group_index < 0) {
+
+ int index;
+ bDeformGroup *group;
+ if (!BKE_id_defgroup_name_find(&mesh->id, name.c_str(), &index, &group)) {
return false;
}
+ BLI_remlink(&mesh->vertex_group_names, group);
+ MEM_freeN(group);
if (mesh->dvert == nullptr) {
return true;
}
for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) {
- MDeformWeight *weight = BKE_defvert_find_index(&dvert, vertex_group_index);
+ MDeformWeight *weight = BKE_defvert_find_index(&dvert, index);
BKE_defvert_remove_group(&dvert, weight);
}
return true;
@@ -1171,33 +1117,17 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
{
}
- GVArrayPtr try_get_for_read(const GeometryComponent &component) const final
+ GVArray try_get_for_read(const GeometryComponent &component) const final
{
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
+ if (mesh == nullptr || mesh->totpoly == 0) {
return {};
}
-
- /* Use existing normals if possible. */
- if (!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL) &&
- CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
- const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
-
- return std::make_unique<fn::GVArray_For_Span<float3>>(
- Span<float3>((const float3 *)data, mesh->totpoly));
- }
-
- Array<float3> normals(mesh->totpoly);
- for (const int i : IndexRange(mesh->totpoly)) {
- const MPoly *poly = &mesh->mpoly[i];
- BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]);
- }
-
- return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals));
+ return VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(mesh), mesh->totpoly});
}
- GVMutableArrayPtr try_get_for_write(GeometryComponent &UNUSED(component)) const final
+ WriteAttributeLookup try_get_for_write(GeometryComponent &UNUSED(component)) const final
{
return {};
}
@@ -1274,6 +1204,18 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
static NormalAttributeProvider normal;
+ static BuiltinCustomDataLayerProvider id("id",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_INT32,
+ CD_PROP_INT32,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ point_access,
+ make_array_read_attribute<int>,
+ make_array_write_attribute<int>,
+ nullptr);
+
static BuiltinCustomDataLayerProvider material_index(
"material_index",
ATTR_DOMAIN_FACE,
@@ -1335,14 +1277,15 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access);
static CustomDataAttributeProvider face_custom_data(ATTR_DOMAIN_FACE, face_access);
- return ComponentAttributeProviders({&position, &material_index, &shade_smooth, &normal, &crease},
- {&uvs,
- &vertex_colors,
- &corner_custom_data,
- &vertex_groups,
- &point_custom_data,
- &edge_custom_data,
- &face_custom_data});
+ return ComponentAttributeProviders(
+ {&position, &id, &material_index, &shade_smooth, &normal, &crease},
+ {&uvs,
+ &vertex_colors,
+ &corner_custom_data,
+ &vertex_groups,
+ &point_custom_data,
+ &edge_custom_data,
+ &face_custom_data});
}
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
index 6c4af7a6d23..80c09a7ed4a 100644
--- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
+++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
@@ -62,7 +62,6 @@ bool PointCloudComponent::has_pointcloud() const
return pointcloud_ != nullptr;
}
-/* Clear the component and replace it with the new point cloud. */
void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
@@ -71,8 +70,6 @@ void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType
ownership_ = ownership;
}
-/* Return the point cloud and clear the component. The caller takes over responsibility for freeing
- * the point cloud (if the component was responsible before). */
PointCloud *PointCloudComponent::release()
{
BLI_assert(this->is_mutable());
@@ -81,17 +78,11 @@ PointCloud *PointCloudComponent::release()
return pointcloud;
}
-/* Get the point cloud from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned point cloud should not be modified. No ownership is transferred.
- */
const PointCloud *PointCloudComponent::get_for_read() const
{
return pointcloud_;
}
-/* Get the point cloud from this component. This method can only be used when the component is
- * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is
- * transferred. */
PointCloud *PointCloudComponent::get_for_write()
{
BLI_assert(this->is_mutable());
@@ -141,16 +132,15 @@ int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) con
namespace blender::bke {
template<typename T>
-static GVArrayPtr make_array_read_attribute(const void *data, const int domain_size)
+static GVArray make_array_read_attribute(const void *data, const int domain_size)
{
- return std::make_unique<fn::GVArray_For_Span<T>>(Span<T>((const T *)data, domain_size));
+ return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size));
}
template<typename T>
-static GVMutableArrayPtr make_array_write_attribute(void *data, const int domain_size)
+static GVMutableArray make_array_write_attribute(void *data, const int domain_size)
{
- return std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>(
- MutableSpan<T>((T *)data, domain_size));
+ return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size));
}
/**
@@ -202,8 +192,19 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
make_array_read_attribute<float>,
make_array_write_attribute<float>,
nullptr);
+ static BuiltinCustomDataLayerProvider id("id",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_INT32,
+ CD_PROP_INT32,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ point_access,
+ make_array_read_attribute<int>,
+ make_array_write_attribute<int>,
+ nullptr);
static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
- return ComponentAttributeProviders({&position, &radius}, {&point_custom_data});
+ return ComponentAttributeProviders({&position, &radius, &id}, {&point_custom_data});
}
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/geometry_component_volume.cc b/source/blender/blenkernel/intern/geometry_component_volume.cc
index 94ed07a63de..e9874153b4c 100644
--- a/source/blender/blenkernel/intern/geometry_component_volume.cc
+++ b/source/blender/blenkernel/intern/geometry_component_volume.cc
@@ -59,7 +59,6 @@ bool VolumeComponent::has_volume() const
return volume_ != nullptr;
}
-/* Clear the component and replace it with the new volume. */
void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
@@ -68,8 +67,6 @@ void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership)
ownership_ = ownership;
}
-/* Return the volume and clear the component. The caller takes over responsibility for freeing the
- * volume (if the component was responsible before). */
Volume *VolumeComponent::release()
{
BLI_assert(this->is_mutable());
@@ -78,15 +75,11 @@ Volume *VolumeComponent::release()
return volume;
}
-/* Get the volume from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned volume should not be modified. No ownership is transferred. */
const Volume *VolumeComponent::get_for_read() const
{
return volume_;
}
-/* Get the volume from this component. This method can only be used when the component is mutable,
- * i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */
Volume *VolumeComponent::get_for_write()
{
BLI_assert(this->is_mutable());
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 0aac6ae3adf..c1e386c626b 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -17,6 +17,8 @@
#include "BLI_map.hh"
#include "BLI_task.hh"
+#include "BLT_translation.h"
+
#include "BKE_attribute.h"
#include "BKE_attribute_access.hh"
#include "BKE_geometry_set.hh"
@@ -105,105 +107,105 @@ bool GeometryComponent::is_empty() const
/** \name Geometry Set
* \{ */
-/* This method can only be used when the geometry set is mutable. It returns a mutable geometry
- * component of the given type.
- */
+GeometrySet::GeometrySet() = default;
+GeometrySet::GeometrySet(const GeometrySet &other) = default;
+GeometrySet::GeometrySet(GeometrySet &&other) = default;
+GeometrySet::~GeometrySet() = default;
+GeometrySet &GeometrySet::operator=(const GeometrySet &other) = default;
+GeometrySet &GeometrySet::operator=(GeometrySet &&other) = default;
+
GeometryComponent &GeometrySet::get_component_for_write(GeometryComponentType component_type)
{
- return components_.add_or_modify(
- component_type,
- [&](GeometryComponentPtr *value_ptr) -> GeometryComponent & {
- /* If the component did not exist before, create a new one. */
- new (value_ptr) GeometryComponentPtr(GeometryComponent::create(component_type));
- return **value_ptr;
- },
- [&](GeometryComponentPtr *value_ptr) -> GeometryComponent & {
- GeometryComponentPtr &value = *value_ptr;
- if (value->is_mutable()) {
- /* If the referenced component is already mutable, return it directly. */
- return *value;
- }
- /* If the referenced component is shared, make a copy. The copy is not shared and is
- * therefore mutable. */
- GeometryComponent *copied_component = value->copy();
- value = GeometryComponentPtr{copied_component};
- return *copied_component;
- });
+ GeometryComponentPtr &component_ptr = components_[component_type];
+ if (!component_ptr) {
+ /* If the component did not exist before, create a new one. */
+ component_ptr = GeometryComponent::create(component_type);
+ return *component_ptr;
+ }
+ if (component_ptr->is_mutable()) {
+ /* If the referenced component is already mutable, return it directly. */
+ return *component_ptr;
+ }
+ /* If the referenced component is shared, make a copy. The copy is not shared and is
+ * therefore mutable. */
+ component_ptr = component_ptr->copy();
+ return *component_ptr;
}
-/* Get the component of the given type. Might return null if the component does not exist yet. */
-const GeometryComponent *GeometrySet::get_component_for_read(
- GeometryComponentType component_type) const
+GeometryComponent *GeometrySet::get_component_ptr(GeometryComponentType type)
{
- const GeometryComponentPtr *component = components_.lookup_ptr(component_type);
- if (component != nullptr) {
- return component->get();
+ if (this->has(type)) {
+ return &this->get_component_for_write(type);
}
return nullptr;
}
+const GeometryComponent *GeometrySet::get_component_for_read(
+ GeometryComponentType component_type) const
+{
+ return components_[component_type].get();
+}
+
bool GeometrySet::has(const GeometryComponentType component_type) const
{
- return components_.contains(component_type);
+ return components_[component_type].has_value();
}
void GeometrySet::remove(const GeometryComponentType component_type)
{
- components_.remove(component_type);
+ components_[component_type].reset();
}
-/**
- * Remove all geometry components with types that are not in the provided list.
- */
void GeometrySet::keep_only(const blender::Span<GeometryComponentType> component_types)
{
- for (auto it = components_.keys().begin(); it != components_.keys().end(); ++it) {
- const GeometryComponentType type = *it;
- if (!component_types.contains(type)) {
- components_.remove(it);
+ for (GeometryComponentPtr &component_ptr : components_) {
+ if (component_ptr) {
+ if (!component_types.contains(component_ptr->type())) {
+ component_ptr.reset();
+ }
}
}
}
void GeometrySet::add(const GeometryComponent &component)
{
- BLI_assert(!components_.contains(component.type()));
+ BLI_assert(!components_[component.type()]);
component.user_add();
- GeometryComponentPtr component_ptr{const_cast<GeometryComponent *>(&component)};
- components_.add_new(component.type(), std::move(component_ptr));
+ components_[component.type()] = const_cast<GeometryComponent *>(&component);
}
-/**
- * Get all geometry components in this geometry set for read-only access.
- */
Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const
{
Vector<const GeometryComponent *> components;
- for (const GeometryComponentPtr &ptr : components_.values()) {
- components.append(ptr.get());
+ for (const GeometryComponentPtr &component_ptr : components_) {
+ if (component_ptr) {
+ components.append(component_ptr.get());
+ }
}
return components;
}
-void GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const
+bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const
{
+ bool have_minmax = false;
const PointCloud *pointcloud = this->get_pointcloud_for_read();
if (pointcloud != nullptr) {
- BKE_pointcloud_minmax(pointcloud, *r_min, *r_max);
+ have_minmax |= BKE_pointcloud_minmax(pointcloud, *r_min, *r_max);
}
const Mesh *mesh = this->get_mesh_for_read();
if (mesh != nullptr) {
- BKE_mesh_wrapper_minmax(mesh, *r_min, *r_max);
+ have_minmax |= BKE_mesh_wrapper_minmax(mesh, *r_min, *r_max);
}
const Volume *volume = this->get_volume_for_read();
if (volume != nullptr) {
- BKE_volume_min_max(volume, *r_min, *r_max);
+ have_minmax |= BKE_volume_min_max(volume, *r_min, *r_max);
}
const CurveEval *curve = this->get_curve_for_read();
if (curve != nullptr) {
/* Using the evaluated positions is somewhat arbitrary, but it is probably expected. */
- curve->bounds_min_max(*r_min, *r_max, true);
+ have_minmax |= curve->bounds_min_max(*r_min, *r_max, true);
}
+ return have_minmax;
}
std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)
@@ -213,203 +215,220 @@ std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)
return stream;
}
-/* Remove all geometry components from the geometry set. */
void GeometrySet::clear()
{
- components_.clear();
+ for (GeometryComponentPtr &component_ptr : components_) {
+ component_ptr.reset();
+ }
}
-/* Make sure that the geometry can be cached. This does not ensure ownership of object/collection
- * instances. */
void GeometrySet::ensure_owns_direct_data()
{
- for (GeometryComponentType type : components_.keys()) {
- const GeometryComponent *component = this->get_component_for_read(type);
- if (!component->owns_direct_data()) {
- GeometryComponent &component_for_write = this->get_component_for_write(type);
- component_for_write.ensure_owns_direct_data();
+ for (GeometryComponentPtr &component_ptr : components_) {
+ if (!component_ptr) {
+ continue;
+ }
+ if (component_ptr->owns_direct_data()) {
+ continue;
}
+ GeometryComponent &component_for_write = this->get_component_for_write(component_ptr->type());
+ component_for_write.ensure_owns_direct_data();
}
}
bool GeometrySet::owns_direct_data() const
{
- for (const GeometryComponentPtr &component : components_.values()) {
- if (!component->owns_direct_data()) {
- return false;
+ for (const GeometryComponentPtr &component_ptr : components_) {
+ if (component_ptr) {
+ if (!component_ptr->owns_direct_data()) {
+ return false;
+ }
}
}
return true;
}
-/* Returns a read-only mesh or null. */
const Mesh *GeometrySet::get_mesh_for_read() const
{
const MeshComponent *component = this->get_component_for_read<MeshComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
}
-/* Returns true when the geometry set has a mesh component that has a mesh. */
bool GeometrySet::has_mesh() const
{
const MeshComponent *component = this->get_component_for_read<MeshComponent>();
return component != nullptr && component->has_mesh();
}
-/* Returns a read-only point cloud of null. */
const PointCloud *GeometrySet::get_pointcloud_for_read() const
{
const PointCloudComponent *component = this->get_component_for_read<PointCloudComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
}
-/* Returns a read-only volume or null. */
const Volume *GeometrySet::get_volume_for_read() const
{
const VolumeComponent *component = this->get_component_for_read<VolumeComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
}
-/* Returns a read-only curve or null. */
const CurveEval *GeometrySet::get_curve_for_read() const
{
const CurveComponent *component = this->get_component_for_read<CurveComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
}
-/* Returns true when the geometry set has a point cloud component that has a point cloud. */
bool GeometrySet::has_pointcloud() const
{
const PointCloudComponent *component = this->get_component_for_read<PointCloudComponent>();
return component != nullptr && component->has_pointcloud();
}
-/* Returns true when the geometry set has an instances component that has at least one instance. */
bool GeometrySet::has_instances() const
{
const InstancesComponent *component = this->get_component_for_read<InstancesComponent>();
return component != nullptr && component->instances_amount() >= 1;
}
-/* Returns true when the geometry set has a volume component that has a volume. */
bool GeometrySet::has_volume() const
{
const VolumeComponent *component = this->get_component_for_read<VolumeComponent>();
return component != nullptr && component->has_volume();
}
-/* Returns true when the geometry set has a curve component that has a curve. */
bool GeometrySet::has_curve() const
{
const CurveComponent *component = this->get_component_for_read<CurveComponent>();
return component != nullptr && component->has_curve();
}
-/* Returns true when the geometry set has any data that is not an instance. */
bool GeometrySet::has_realized_data() const
{
- if (components_.is_empty()) {
- return false;
- }
- if (components_.size() > 1) {
- return true;
+ for (const GeometryComponentPtr &component_ptr : components_) {
+ if (component_ptr) {
+ if (component_ptr->type() != GEO_COMPONENT_TYPE_INSTANCES) {
+ return true;
+ }
+ }
}
- /* Check if the only component is an #InstancesComponent. */
- return this->get_component_for_read<InstancesComponent>() == nullptr;
+ return false;
}
-/* Return true if the geometry set has any component that isn't empty. */
bool GeometrySet::is_empty() const
{
- if (components_.is_empty()) {
- return true;
- }
- return !(this->has_mesh() || this->has_curve() || this->has_pointcloud() ||
+ return !(this->has_mesh() || this->has_curve() || this->has_pointcloud() || this->has_volume() ||
this->has_instances());
}
-/* Create a new geometry set that only contains the given mesh. */
GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
- MeshComponent &component = geometry_set.get_component_for_write<MeshComponent>();
- component.replace(mesh, ownership);
+ if (mesh != nullptr) {
+ MeshComponent &component = geometry_set.get_component_for_write<MeshComponent>();
+ component.replace(mesh, ownership);
+ }
return geometry_set;
}
-/* Create a new geometry set that only contains the given point cloud. */
GeometrySet GeometrySet::create_with_pointcloud(PointCloud *pointcloud,
GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
- PointCloudComponent &component = geometry_set.get_component_for_write<PointCloudComponent>();
- component.replace(pointcloud, ownership);
+ if (pointcloud != nullptr) {
+ PointCloudComponent &component = geometry_set.get_component_for_write<PointCloudComponent>();
+ component.replace(pointcloud, ownership);
+ }
return geometry_set;
}
-/* Create a new geometry set that only contains the given curve. */
GeometrySet GeometrySet::create_with_curve(CurveEval *curve, GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
- CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
- component.replace(curve, ownership);
+ if (curve != nullptr) {
+ CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
+ component.replace(curve, ownership);
+ }
return geometry_set;
}
-/* Clear the existing mesh and replace it with the given one. */
void GeometrySet::replace_mesh(Mesh *mesh, GeometryOwnershipType ownership)
{
+ if (mesh == nullptr) {
+ this->remove<MeshComponent>();
+ return;
+ }
+ if (mesh == this->get_mesh_for_read()) {
+ return;
+ }
+ this->remove<MeshComponent>();
MeshComponent &component = this->get_component_for_write<MeshComponent>();
component.replace(mesh, ownership);
}
-/* Clear the existing curve and replace it with the given one. */
void GeometrySet::replace_curve(CurveEval *curve, GeometryOwnershipType ownership)
{
+ if (curve == nullptr) {
+ this->remove<CurveComponent>();
+ return;
+ }
+ if (curve == this->get_curve_for_read()) {
+ return;
+ }
+ this->remove<CurveComponent>();
CurveComponent &component = this->get_component_for_write<CurveComponent>();
component.replace(curve, ownership);
}
-/* Clear the existing point cloud and replace with the given one. */
void GeometrySet::replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership)
{
- PointCloudComponent &pointcloud_component = this->get_component_for_write<PointCloudComponent>();
- pointcloud_component.replace(pointcloud, ownership);
+ if (pointcloud == nullptr) {
+ this->remove<PointCloudComponent>();
+ return;
+ }
+ if (pointcloud == this->get_pointcloud_for_read()) {
+ return;
+ }
+ this->remove<PointCloudComponent>();
+ PointCloudComponent &component = this->get_component_for_write<PointCloudComponent>();
+ component.replace(pointcloud, ownership);
}
-/* Clear the existing volume and replace with the given one. */
void GeometrySet::replace_volume(Volume *volume, GeometryOwnershipType ownership)
{
- VolumeComponent &volume_component = this->get_component_for_write<VolumeComponent>();
- volume_component.replace(volume, ownership);
+ if (volume == nullptr) {
+ this->remove<VolumeComponent>();
+ return;
+ }
+ if (volume == this->get_volume_for_read()) {
+ return;
+ }
+ this->remove<VolumeComponent>();
+ VolumeComponent &component = this->get_component_for_write<VolumeComponent>();
+ component.replace(volume, ownership);
}
-/* Returns a mutable mesh or null. No ownership is transferred. */
Mesh *GeometrySet::get_mesh_for_write()
{
- MeshComponent &component = this->get_component_for_write<MeshComponent>();
- return component.get_for_write();
+ MeshComponent *component = this->get_component_ptr<MeshComponent>();
+ return component == nullptr ? nullptr : component->get_for_write();
}
-/* Returns a mutable point cloud or null. No ownership is transferred. */
PointCloud *GeometrySet::get_pointcloud_for_write()
{
- PointCloudComponent &component = this->get_component_for_write<PointCloudComponent>();
- return component.get_for_write();
+ PointCloudComponent *component = this->get_component_ptr<PointCloudComponent>();
+ return component == nullptr ? nullptr : component->get_for_write();
}
-/* Returns a mutable volume or null. No ownership is transferred. */
Volume *GeometrySet::get_volume_for_write()
{
- VolumeComponent &component = this->get_component_for_write<VolumeComponent>();
- return component.get_for_write();
+ VolumeComponent *component = this->get_component_ptr<VolumeComponent>();
+ return component == nullptr ? nullptr : component->get_for_write();
}
-/* Returns a mutable curve or null. No ownership is transferred. */
CurveEval *GeometrySet::get_curve_for_write()
{
- CurveComponent &component = this->get_component_for_write<CurveComponent>();
- return component.get_for_write();
+ CurveComponent *component = this->get_component_ptr<CurveComponent>();
+ return component == nullptr ? nullptr : component->get_for_write();
}
void GeometrySet::attribute_foreach(const Span<GeometryComponentType> component_types,
@@ -461,19 +480,23 @@ void GeometrySet::gather_attributes_for_propagation(
return;
}
}
- if (attribute_id.is_anonymous()) {
- if (!BKE_anonymous_attribute_id_has_strong_references(&attribute_id.anonymous_id())) {
- /* Don't propagate anonymous attributes that are not used anymore. */
- return;
- }
+
+ if (!attribute_id.should_be_kept()) {
+ return;
}
+
+ AttributeDomain domain = meta_data.domain;
+ if (dst_component_type != GEO_COMPONENT_TYPE_INSTANCES && domain == ATTR_DOMAIN_INSTANCE) {
+ domain = ATTR_DOMAIN_POINT;
+ }
+
auto add_info = [&](AttributeKind *attribute_kind) {
- attribute_kind->domain = meta_data.domain;
+ attribute_kind->domain = domain;
attribute_kind->data_type = meta_data.data_type;
};
auto modify_info = [&](AttributeKind *attribute_kind) {
attribute_kind->domain = bke::attribute_domain_highest_priority(
- {attribute_kind->domain, meta_data.domain});
+ {attribute_kind->domain, domain});
attribute_kind->data_type = bke::attribute_data_type_highest_complexity(
{attribute_kind->data_type, meta_data.data_type});
};
@@ -482,6 +505,40 @@ void GeometrySet::gather_attributes_for_propagation(
delete dummy_component;
}
+static void gather_component_types_recursive(const GeometrySet &geometry_set,
+ const bool include_instances,
+ const bool ignore_empty,
+ Vector<GeometryComponentType> &r_types)
+{
+ for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
+ if (ignore_empty) {
+ if (component->is_empty()) {
+ continue;
+ }
+ }
+ r_types.append_non_duplicates(component->type());
+ }
+ if (!include_instances) {
+ return;
+ }
+ const InstancesComponent *instances = geometry_set.get_component_for_read<InstancesComponent>();
+ if (instances == nullptr) {
+ return;
+ }
+ instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
+ gather_component_types_recursive(
+ instance_geometry_set, include_instances, ignore_empty, r_types);
+ });
+}
+
+blender::Vector<GeometryComponentType> GeometrySet::gather_component_types(
+ const bool include_instances, bool ignore_empty) const
+{
+ Vector<GeometryComponentType> types;
+ gather_component_types_recursive(*this, include_instances, ignore_empty, types);
+ return types;
+}
+
static void gather_mutable_geometry_sets(GeometrySet &geometry_set,
Vector<GeometrySet *> &r_geometry_sets)
{
@@ -502,10 +559,6 @@ static void gather_mutable_geometry_sets(GeometrySet &geometry_set,
}
}
-/**
- * Modify every (recursive) instance separately. This is often more efficient than realizing all
- * instances just to change the same thing on all of them.
- */
void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback)
{
Vector<GeometrySet *> geometry_sets;
@@ -517,6 +570,48 @@ void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Mesh and Curve Normals Field Input
+ * \{ */
+
+namespace blender::bke {
+
+GVArray NormalFieldInput::get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const
+{
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ if (const Mesh *mesh = mesh_component.get_for_read()) {
+ return mesh_normals_varray(mesh_component, *mesh, mask, domain);
+ }
+ }
+ else if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return curve_normals_varray(curve_component, domain);
+ }
+ return {};
+}
+
+std::string NormalFieldInput::socket_inspection_name() const
+{
+ return TIP_("Normal");
+}
+
+uint64_t NormalFieldInput::hash() const
+{
+ return 213980475983;
+}
+
+bool NormalFieldInput::is_equal_to(const fn::FieldNode &other) const
+{
+ return dynamic_cast<const NormalFieldInput *>(&other) != nullptr;
+}
+
+} // namespace blender::bke
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name C API
* \{ */
@@ -531,24 +626,32 @@ bool BKE_object_has_geometry_set_instances(const Object *ob)
if (geometry_set == nullptr) {
return false;
}
- if (geometry_set->has_instances()) {
- return true;
- }
- const bool has_mesh = geometry_set->has_mesh();
- const bool has_pointcloud = geometry_set->has_pointcloud();
- const bool has_volume = geometry_set->has_volume();
- const bool has_curve = geometry_set->has_curve();
- if (ob->type == OB_MESH) {
- return has_pointcloud || has_volume || has_curve;
- }
- if (ob->type == OB_POINTCLOUD) {
- return has_mesh || has_volume || has_curve;
- }
- if (ob->type == OB_VOLUME) {
- return has_mesh || has_pointcloud || has_curve;
- }
- if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
- return has_mesh || has_pointcloud || has_volume;
+ for (const GeometryComponent *component : geometry_set->get_components_for_read()) {
+ if (component->is_empty()) {
+ continue;
+ }
+ const GeometryComponentType type = component->type();
+ bool is_instance = false;
+ switch (type) {
+ case GEO_COMPONENT_TYPE_MESH:
+ is_instance = ob->type != OB_MESH;
+ break;
+ case GEO_COMPONENT_TYPE_POINT_CLOUD:
+ is_instance = ob->type != OB_POINTCLOUD;
+ break;
+ case GEO_COMPONENT_TYPE_INSTANCES:
+ is_instance = true;
+ break;
+ case GEO_COMPONENT_TYPE_VOLUME:
+ is_instance = ob->type != OB_VOLUME;
+ break;
+ case GEO_COMPONENT_TYPE_CURVE:
+ is_instance = !ELEM(ob->type, OB_CURVE, OB_FONT);
+ break;
+ }
+ if (is_instance) {
+ return true;
+ }
}
return false;
}
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index ad13342ad9e..42d2211c360 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -53,10 +53,7 @@ static void add_final_mesh_as_geometry_component(const Object &object, GeometryS
}
}
-/**
- * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
- */
-static GeometrySet object_get_geometry_set_for_read(const Object &object)
+GeometrySet object_get_evaluated_geometry_set(const Object &object)
{
if (object.type == OB_MESH && object.mode == OB_MODE_EDIT) {
GeometrySet geometry_set;
@@ -72,25 +69,33 @@ static GeometrySet object_get_geometry_set_for_read(const Object &object)
}
/* Otherwise, construct a new geometry set with the component based on the object type. */
- GeometrySet geometry_set;
if (object.type == OB_MESH) {
+ GeometrySet geometry_set;
add_final_mesh_as_geometry_component(object, geometry_set);
+ return geometry_set;
+ }
+ if (object.type == OB_EMPTY && object.instance_collection != nullptr) {
+ GeometrySet geometry_set;
+ Collection &collection = *object.instance_collection;
+ InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ const int handle = instances.add_reference(collection);
+ instances.add_instance(handle, float4x4::identity());
+ return geometry_set;
}
- /* TODO: Cover the case of point-clouds without modifiers-- they may not be covered by the
+ /* TODO: Cover the case of point clouds without modifiers-- they may not be covered by the
* #geometry_set_eval case above. */
/* TODO: Add volume support. */
/* Return by value since there is not always an existing geometry set owned elsewhere to use. */
- return geometry_set;
+ return {};
}
static void geometry_set_collect_recursive_collection_instance(
const Collection &collection, const float4x4 &transform, Vector<GeometryInstanceGroup> &r_sets)
{
- float4x4 offset_matrix;
- unit_m4(offset_matrix.values);
+ float4x4 offset_matrix = float4x4::identity();
sub_v3_v3(offset_matrix.values[3], collection.instance_offset);
const float4x4 instance_transform = transform * offset_matrix;
geometry_set_collect_recursive_collection(collection, instance_transform, r_sets);
@@ -100,15 +105,8 @@ static void geometry_set_collect_recursive_object(const Object &object,
const float4x4 &transform,
Vector<GeometryInstanceGroup> &r_sets)
{
- GeometrySet instance_geometry_set = object_get_geometry_set_for_read(object);
+ GeometrySet instance_geometry_set = object_get_evaluated_geometry_set(object);
geometry_set_collect_recursive(instance_geometry_set, transform, r_sets);
-
- if (object.type == OB_EMPTY) {
- const Collection *collection_instance = object.instance_collection;
- if (collection_instance != nullptr) {
- geometry_set_collect_recursive_collection_instance(*collection_instance, transform, r_sets);
- }
- }
}
static void geometry_set_collect_recursive_collection(const Collection &collection,
@@ -170,23 +168,10 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
}
}
-/**
- * Return flattened vector of the geometry component's recursive instances. I.e. all collection
- * instances and object instances will be expanded into the instances of their geometry components.
- * Even the instances in those geometry components' will be included.
- *
- * \note For convenience (to avoid duplication in the caller), the returned vector also contains
- * the argument geometry set.
- *
- * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
- */
void geometry_set_gather_instances(const GeometrySet &geometry_set,
Vector<GeometryInstanceGroup> &r_instance_groups)
{
- float4x4 unit_transform;
- unit_m4(unit_transform.values);
-
- geometry_set_collect_recursive(geometry_set, unit_transform, r_instance_groups);
+ geometry_set_collect_recursive(geometry_set, float4x4::identity(), r_instance_groups);
}
void geometry_set_gather_instances_attribute_info(Span<GeometryInstanceGroup> set_groups,
@@ -224,400 +209,6 @@ void geometry_set_gather_instances_attribute_info(Span<GeometryInstanceGroup> se
}
}
-static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGroup> set_groups,
- const bool convert_points_to_vertices)
-{
- int totverts = 0;
- int totloops = 0;
- int totedges = 0;
- int totpolys = 0;
- int64_t cd_dirty_vert = 0;
- int64_t cd_dirty_poly = 0;
- int64_t cd_dirty_edge = 0;
- int64_t cd_dirty_loop = 0;
- VectorSet<Material *> materials;
-
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- const int tot_transforms = set_group.transforms.size();
- if (set.has_mesh()) {
- const Mesh &mesh = *set.get_mesh_for_read();
- totverts += mesh.totvert * tot_transforms;
- totloops += mesh.totloop * tot_transforms;
- totedges += mesh.totedge * tot_transforms;
- totpolys += mesh.totpoly * tot_transforms;
- cd_dirty_vert |= mesh.runtime.cd_dirty_vert;
- cd_dirty_poly |= mesh.runtime.cd_dirty_poly;
- cd_dirty_edge |= mesh.runtime.cd_dirty_edge;
- cd_dirty_loop |= mesh.runtime.cd_dirty_loop;
- for (const int slot_index : IndexRange(mesh.totcol)) {
- Material *material = mesh.mat[slot_index];
- materials.add(material);
- }
- }
- if (convert_points_to_vertices && set.has_pointcloud()) {
- const PointCloud &pointcloud = *set.get_pointcloud_for_read();
- totverts += pointcloud.totpoint * tot_transforms;
- }
- }
-
- /* Don't create an empty mesh. */
- if ((totverts + totloops + totedges + totpolys) == 0) {
- return nullptr;
- }
-
- Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys);
- /* Copy settings from the first input geometry set with a mesh. */
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (set.has_mesh()) {
- const Mesh &mesh = *set.get_mesh_for_read();
- BKE_mesh_copy_parameters_for_eval(new_mesh, &mesh);
- break;
- }
- }
- for (const int i : IndexRange(materials.size())) {
- Material *material = materials[i];
- BKE_id_material_eval_assign(&new_mesh->id, i + 1, material);
- }
- new_mesh->runtime.cd_dirty_vert = cd_dirty_vert;
- new_mesh->runtime.cd_dirty_poly = cd_dirty_poly;
- new_mesh->runtime.cd_dirty_edge = cd_dirty_edge;
- new_mesh->runtime.cd_dirty_loop = cd_dirty_loop;
-
- int vert_offset = 0;
- int loop_offset = 0;
- int edge_offset = 0;
- int poly_offset = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (set.has_mesh()) {
- const Mesh &mesh = *set.get_mesh_for_read();
-
- Array<int> material_index_map(mesh.totcol);
- for (const int i : IndexRange(mesh.totcol)) {
- Material *material = mesh.mat[i];
- const int new_material_index = materials.index_of(material);
- material_index_map[i] = new_material_index;
- }
-
- for (const float4x4 &transform : set_group.transforms) {
- for (const int i : IndexRange(mesh.totvert)) {
- const MVert &old_vert = mesh.mvert[i];
- MVert &new_vert = new_mesh->mvert[vert_offset + i];
-
- new_vert = old_vert;
-
- const float3 new_position = transform * float3(old_vert.co);
- copy_v3_v3(new_vert.co, new_position);
- }
- for (const int i : IndexRange(mesh.totedge)) {
- const MEdge &old_edge = mesh.medge[i];
- MEdge &new_edge = new_mesh->medge[edge_offset + i];
- new_edge = old_edge;
- new_edge.v1 += vert_offset;
- new_edge.v2 += vert_offset;
- }
- for (const int i : IndexRange(mesh.totloop)) {
- const MLoop &old_loop = mesh.mloop[i];
- MLoop &new_loop = new_mesh->mloop[loop_offset + i];
- new_loop = old_loop;
- new_loop.v += vert_offset;
- new_loop.e += edge_offset;
- }
- for (const int i : IndexRange(mesh.totpoly)) {
- const MPoly &old_poly = mesh.mpoly[i];
- MPoly &new_poly = new_mesh->mpoly[poly_offset + i];
- new_poly = old_poly;
- new_poly.loopstart += loop_offset;
- if (old_poly.mat_nr >= 0 && old_poly.mat_nr < mesh.totcol) {
- new_poly.mat_nr = material_index_map[new_poly.mat_nr];
- }
- else {
- /* The material index was invalid before. */
- new_poly.mat_nr = 0;
- }
- }
-
- vert_offset += mesh.totvert;
- loop_offset += mesh.totloop;
- edge_offset += mesh.totedge;
- poly_offset += mesh.totpoly;
- }
- }
-
- const float3 point_normal{0.0f, 0.0f, 1.0f};
- short point_normal_short[3];
- normal_float_to_short_v3(point_normal_short, point_normal);
-
- if (convert_points_to_vertices && set.has_pointcloud()) {
- const PointCloud &pointcloud = *set.get_pointcloud_for_read();
- for (const float4x4 &transform : set_group.transforms) {
- for (const int i : IndexRange(pointcloud.totpoint)) {
- MVert &new_vert = new_mesh->mvert[vert_offset + i];
- const float3 old_position = pointcloud.co[i];
- const float3 new_position = transform * old_position;
- copy_v3_v3(new_vert.co, new_position);
- memcpy(&new_vert.no, point_normal_short, sizeof(point_normal_short));
- }
- vert_offset += pointcloud.totpoint;
- }
- }
- }
-
- /* A possible optimization is to only tag the normals dirty when there are transforms that change
- * normals. */
- BKE_mesh_normals_tag_dirty(new_mesh);
-
- return new_mesh;
-}
-
-static void join_attributes(Span<GeometryInstanceGroup> set_groups,
- Span<GeometryComponentType> component_types,
- const Map<AttributeIDRef, AttributeKind> &attribute_info,
- GeometryComponent &result)
-{
- for (Map<AttributeIDRef, AttributeKind>::Item entry : attribute_info.items()) {
- const AttributeIDRef attribute_id = entry.key;
- const AttributeDomain domain_output = entry.value.domain;
- const CustomDataType data_type_output = entry.value.data_type;
- const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type_output);
- BLI_assert(cpp_type != nullptr);
-
- result.attribute_try_create(
- entry.key, domain_output, data_type_output, AttributeInitDefault());
- WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(attribute_id);
- if (!write_attribute || &write_attribute.varray->type() != cpp_type ||
- write_attribute.domain != domain_output) {
- continue;
- }
-
- fn::GVMutableArray_GSpan dst_span{*write_attribute.varray};
-
- int offset = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- for (const GeometryComponentType component_type : component_types) {
- if (set.has(component_type)) {
- const GeometryComponent &component = *set.get_component_for_read(component_type);
- const int domain_size = component.attribute_domain_size(domain_output);
- if (domain_size == 0) {
- continue; /* Domain size is 0, so no need to increment the offset. */
- }
- GVArrayPtr source_attribute = component.attribute_try_get_for_read(
- attribute_id, domain_output, data_type_output);
-
- if (source_attribute) {
- fn::GVArray_GSpan src_span{*source_attribute};
- const void *src_buffer = src_span.data();
- for (const int UNUSED(i) : set_group.transforms.index_range()) {
- void *dst_buffer = dst_span[offset];
- cpp_type->copy_assign_n(src_buffer, dst_buffer, domain_size);
- offset += domain_size;
- }
- }
- else {
- offset += domain_size * set_group.transforms.size();
- }
- }
- }
- }
-
- dst_span.save();
- }
-}
-
-static PointCloud *join_pointcloud_position_attribute(Span<GeometryInstanceGroup> set_groups)
-{
- /* Count the total number of points. */
- int totpoint = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (set.has<PointCloudComponent>()) {
- const PointCloudComponent &component = *set.get_component_for_read<PointCloudComponent>();
- totpoint += component.attribute_domain_size(ATTR_DOMAIN_POINT);
- }
- }
- if (totpoint == 0) {
- return nullptr;
- }
-
- PointCloud *new_pointcloud = BKE_pointcloud_new_nomain(totpoint);
- MutableSpan new_positions{(float3 *)new_pointcloud->co, new_pointcloud->totpoint};
-
- /* Transform each instance's point locations into the new point cloud. */
- int offset = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- const PointCloud *pointcloud = set.get_pointcloud_for_read();
- if (pointcloud == nullptr) {
- continue;
- }
- for (const float4x4 &transform : set_group.transforms) {
- for (const int i : IndexRange(pointcloud->totpoint)) {
- new_positions[offset + i] = transform * float3(pointcloud->co[i]);
- }
- offset += pointcloud->totpoint;
- }
- }
-
- return new_pointcloud;
-}
-
-static CurveEval *join_curve_splines_and_builtin_attributes(Span<GeometryInstanceGroup> set_groups)
-{
- Vector<SplinePtr> new_splines;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (!set.has_curve()) {
- continue;
- }
-
- const CurveEval &source_curve = *set.get_curve_for_read();
- for (const SplinePtr &source_spline : source_curve.splines()) {
- for (const float4x4 &transform : set_group.transforms) {
- SplinePtr new_spline = source_spline->copy_without_attributes();
- new_spline->transform(transform);
- new_splines.append(std::move(new_spline));
- }
- }
- }
- if (new_splines.is_empty()) {
- return nullptr;
- }
-
- CurveEval *new_curve = new CurveEval();
- for (SplinePtr &new_spline : new_splines) {
- new_curve->add_spline(std::move(new_spline));
- }
-
- new_curve->attributes.reallocate(new_curve->splines().size());
- return new_curve;
-}
-
-static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups,
- bool convert_points_to_vertices,
- GeometrySet &result)
-{
- Mesh *new_mesh = join_mesh_topology_and_builtin_attributes(set_groups,
- convert_points_to_vertices);
- if (new_mesh == nullptr) {
- return;
- }
-
- MeshComponent &dst_component = result.get_component_for_write<MeshComponent>();
- dst_component.replace(new_mesh);
-
- Vector<GeometryComponentType> component_types;
- component_types.append(GEO_COMPONENT_TYPE_MESH);
- if (convert_points_to_vertices) {
- component_types.append(GEO_COMPONENT_TYPE_POINT_CLOUD);
- }
-
- /* Don't copy attributes that are stored directly in the mesh data structs. */
- Map<AttributeIDRef, AttributeKind> attributes;
- geometry_set_gather_instances_attribute_info(
- set_groups,
- component_types,
- {"position", "material_index", "normal", "shade_smooth", "crease"},
- attributes);
- join_attributes(
- set_groups, component_types, attributes, static_cast<GeometryComponent &>(dst_component));
-}
-
-static void join_instance_groups_pointcloud(Span<GeometryInstanceGroup> set_groups,
- GeometrySet &result)
-{
- PointCloud *new_pointcloud = join_pointcloud_position_attribute(set_groups);
- if (new_pointcloud == nullptr) {
- return;
- }
-
- PointCloudComponent &dst_component = result.get_component_for_write<PointCloudComponent>();
- dst_component.replace(new_pointcloud);
-
- Map<AttributeIDRef, AttributeKind> attributes;
- geometry_set_gather_instances_attribute_info(
- set_groups, {GEO_COMPONENT_TYPE_POINT_CLOUD}, {"position"}, attributes);
- join_attributes(set_groups,
- {GEO_COMPONENT_TYPE_POINT_CLOUD},
- attributes,
- static_cast<GeometryComponent &>(dst_component));
-}
-
-static void join_instance_groups_volume(Span<GeometryInstanceGroup> set_groups,
- GeometrySet &result)
-{
- /* Not yet supported; for now only return the first volume. Joining volume grids with the same
- * name requires resampling of at least one of the grids. The cell size of the resulting volume
- * has to be determined somehow. */
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (set.has<VolumeComponent>()) {
- result.add(*set.get_component_for_read<VolumeComponent>());
- return;
- }
- }
-}
-
-static void join_instance_groups_curve(Span<GeometryInstanceGroup> set_groups, GeometrySet &result)
-{
- CurveEval *curve = join_curve_splines_and_builtin_attributes(set_groups);
- if (curve == nullptr) {
- return;
- }
-
- CurveComponent &dst_component = result.get_component_for_write<CurveComponent>();
- dst_component.replace(curve);
-
- Map<AttributeIDRef, AttributeKind> attributes;
- geometry_set_gather_instances_attribute_info(
- set_groups,
- {GEO_COMPONENT_TYPE_CURVE},
- {"position", "radius", "tilt", "cyclic", "resolution"},
- attributes);
- join_attributes(set_groups,
- {GEO_COMPONENT_TYPE_CURVE},
- attributes,
- static_cast<GeometryComponent &>(dst_component));
-}
-
-GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set)
-{
- if (!geometry_set.has_instances() && !geometry_set.has_pointcloud()) {
- return geometry_set;
- }
-
- GeometrySet new_geometry_set = geometry_set;
- Vector<GeometryInstanceGroup> set_groups;
- geometry_set_gather_instances(geometry_set, set_groups);
- join_instance_groups_mesh(set_groups, true, new_geometry_set);
- /* Remove all instances, even though some might contain other non-mesh data. We can't really
- * keep only non-mesh instances in general. */
- new_geometry_set.remove<InstancesComponent>();
- /* If there was a point cloud, it is now part of the mesh. */
- new_geometry_set.remove<PointCloudComponent>();
- return new_geometry_set;
-}
-
-GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set)
-{
- if (!geometry_set.has_instances()) {
- return geometry_set;
- }
-
- GeometrySet new_geometry_set;
-
- Vector<GeometryInstanceGroup> set_groups;
- geometry_set_gather_instances(geometry_set, set_groups);
- join_instance_groups_mesh(set_groups, false, new_geometry_set);
- join_instance_groups_pointcloud(set_groups, new_geometry_set);
- join_instance_groups_volume(set_groups, new_geometry_set);
- join_instance_groups_curve(set_groups, new_geometry_set);
-
- return new_geometry_set;
-}
-
} // namespace blender::bke
void InstancesComponent::foreach_referenced_geometry(
@@ -628,14 +219,14 @@ void InstancesComponent::foreach_referenced_geometry(
switch (reference.type()) {
case InstanceReference::Type::Object: {
const Object &object = reference.object();
- const GeometrySet object_geometry_set = object_get_geometry_set_for_read(object);
+ const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(object);
callback(object_geometry_set);
break;
}
case InstanceReference::Type::Collection: {
Collection &collection = reference.collection();
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
- const GeometrySet object_geometry_set = object_get_geometry_set_for_read(*object);
+ const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(*object);
callback(object_geometry_set);
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
@@ -653,11 +244,6 @@ void InstancesComponent::foreach_referenced_geometry(
}
}
-/**
- * If references have a collection or object type, convert them into geometry instances
- * recursively. After that, the geometry sets can be edited. There may still be instances of other
- * types of they can't be converted to geometry sets.
- */
void InstancesComponent::ensure_geometry_instances()
{
using namespace blender;
@@ -676,7 +262,7 @@ void InstancesComponent::ensure_geometry_instances()
/* Create a new reference that contains the geometry set of the object. We may want to
* treat e.g. lamps and similar object types separately here. */
const Object &object = reference.object();
- GeometrySet object_geometry_set = object_get_geometry_set_for_read(object);
+ GeometrySet object_geometry_set = object_get_evaluated_geometry_set(object);
if (object_geometry_set.has_instances()) {
InstancesComponent &component =
object_geometry_set.get_component_for_write<InstancesComponent>();
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index ed84694a919..13338f33bd6 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -139,11 +139,11 @@ static void greasepencil_foreach_id(ID *id, LibraryForeachIDData *data)
bGPdata *gpencil = (bGPdata *)id;
/* materials */
for (int i = 0; i < gpencil->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, gpencil->mat[i], IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, gpencil->mat[i], IDWALK_CB_USER);
}
LISTBASE_FOREACH (bGPDlayer *, gplayer, &gpencil->layers) {
- BKE_LIB_FOREACHID_PROCESS(data, gplayer->parent, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, gplayer->parent, IDWALK_CB_NOP);
}
}
@@ -320,6 +320,7 @@ IDTypeInfo IDType_ID_GD = {
.name_plural = "grease_pencils",
.translation_context = BLT_I18NCONTEXT_ID_GPENCIL,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = greasepencil_copy_data,
@@ -327,6 +328,7 @@ IDTypeInfo IDType_ID_GD = {
.make_local = NULL,
.foreach_id = greasepencil_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = greasepencil_blend_write,
@@ -363,7 +365,6 @@ void BKE_gpencil_batch_cache_free(bGPdata *gpd)
/* ************************************************** */
/* Memory Management */
-/* clean vertex groups weights */
void BKE_gpencil_free_point_weights(MDeformVert *dvert)
{
if (dvert == NULL) {
@@ -402,7 +403,6 @@ void BKE_gpencil_free_stroke_editcurve(bGPDstroke *gps)
gps->editcurve = NULL;
}
-/* free stroke, doesn't unlink from any listbase */
void BKE_gpencil_free_stroke(bGPDstroke *gps)
{
if (gps == NULL) {
@@ -426,7 +426,6 @@ void BKE_gpencil_free_stroke(bGPDstroke *gps)
MEM_freeN(gps);
}
-/* Free strokes belonging to a gp-frame */
bool BKE_gpencil_free_strokes(bGPDframe *gpf)
{
bool changed = (BLI_listbase_is_empty(&gpf->strokes) == false);
@@ -440,7 +439,6 @@ bool BKE_gpencil_free_strokes(bGPDframe *gpf)
return changed;
}
-/* Free all of a gp-layer's frames */
void BKE_gpencil_free_frames(bGPDlayer *gpl)
{
bGPDframe *gpf_next;
@@ -470,7 +468,6 @@ void BKE_gpencil_free_layer_masks(bGPDlayer *gpl)
BLI_freelinkN(&gpl->mask_layers, mask);
}
}
-/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
void BKE_gpencil_free_layers(ListBase *list)
{
bGPDlayer *gpl_next;
@@ -494,7 +491,6 @@ void BKE_gpencil_free_layers(ListBase *list)
}
}
-/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
void BKE_gpencil_free_data(bGPdata *gpd, bool free_all)
{
/* free layers */
@@ -512,10 +508,6 @@ void BKE_gpencil_free_data(bGPdata *gpd, bool free_all)
}
}
-/**
- * Delete grease pencil evaluated data
- * \param gpd_eval: Grease pencil data-block
- */
void BKE_gpencil_eval_delete(bGPdata *gpd_eval)
{
BKE_gpencil_free_data(gpd_eval, true);
@@ -524,11 +516,6 @@ void BKE_gpencil_eval_delete(bGPdata *gpd_eval)
MEM_freeN(gpd_eval);
}
-/**
- * Tag data-block for depsgraph update.
- * Wrapper to avoid include Depsgraph tag functions in other modules.
- * \param gpd: Grease pencil data-block.
- */
void BKE_gpencil_tag(bGPdata *gpd)
{
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
@@ -537,12 +524,6 @@ void BKE_gpencil_tag(bGPdata *gpd)
/* ************************************************** */
/* Container Creation */
-/**
- * Add a new gp-frame to the given layer.
- * \param gpl: Grease pencil layer
- * \param cframe: Frame number
- * \return Pointer to new frame
- */
bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
{
bGPDframe *gpf = NULL, *gf = NULL;
@@ -596,12 +577,6 @@ bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
return gpf;
}
-/**
- * Add a copy of the active gp-frame to the given layer.
- * \param gpl: Grease pencil layer
- * \param cframe: Frame number
- * \return Pointer to new frame
- */
bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
{
bGPDframe *new_frame;
@@ -656,14 +631,6 @@ bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
return new_frame;
}
-/**
- * Add a new gp-layer and make it the active layer.
- * \param gpd: Grease pencil data-block
- * \param name: Name of the layer
- * \param setactive: Set as active
- * \param add_to_header: Used to force the layer added at header
- * \return Pointer to new layer
- */
bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd,
const char *name,
const bool setactive,
@@ -748,12 +715,6 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd,
return gpl;
}
-/**
- * Add a new grease pencil data-block.
- * \param bmain: Main pointer
- * \param name: Name of the datablock
- * \return Pointer to new data-block
- */
bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
{
bGPdata *gpd;
@@ -805,13 +766,6 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
/* Primitive Creation */
/* Utilities for easier bulk-creation of geometry */
-/**
- * Create a new stroke, with pre-allocated data buffers.
- * \param mat_idx: Index of the material
- * \param totpoints: Total points
- * \param thickness: Stroke thickness
- * \return Pointer to new stroke
- */
bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness)
{
/* allocate memory for a new stroke */
@@ -848,15 +802,6 @@ bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness)
return gps;
}
-/**
- * Create a new stroke and add to frame.
- * \param gpf: Grease pencil frame
- * \param mat_idx: Material index
- * \param totpoints: Total points
- * \param thickness: Stroke thickness
- * \param insert_at_head: Add to the head of the strokes list
- * \return Pointer to new stroke
- */
bGPDstroke *BKE_gpencil_stroke_add(
bGPDframe *gpf, int mat_idx, int totpoints, short thickness, const bool insert_at_head)
{
@@ -875,16 +820,6 @@ bGPDstroke *BKE_gpencil_stroke_add(
return gps;
}
-/**
- * Add a stroke and copy the temporary drawing color value
- * from one of the existing stroke.
- * \param gpf: Grease pencil frame
- * \param existing: Stroke with the style to copy
- * \param mat_idx: Material index
- * \param totpoints: Total points
- * \param thickness: Stroke thickness
- * \return Pointer to new stroke
- */
bGPDstroke *BKE_gpencil_stroke_add_existing_style(
bGPDframe *gpf, bGPDstroke *existing, int mat_idx, int totpoints, short thickness)
{
@@ -909,11 +844,6 @@ bGPDcurve *BKE_gpencil_stroke_editcurve_new(const int tot_curve_points)
/* ************************************************** */
/* Data Duplication */
-/**
- * Make a copy of a given gpencil weights.
- * \param gps_src: Source grease pencil stroke
- * \param gps_dst: Destination grease pencil stroke
- */
void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_dst)
{
if (gps_src == NULL) {
@@ -924,7 +854,6 @@ void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_d
BKE_defvert_array_copy(gps_dst->dvert, gps_src->dvert, gps_src->totpoints);
}
-/* Make a copy of a given gpencil stroke editcurve */
bGPDcurve *BKE_gpencil_stroke_curve_duplicate(bGPDcurve *gpc_src)
{
bGPDcurve *gpc_dst = MEM_dupallocN(gpc_src);
@@ -936,13 +865,6 @@ bGPDcurve *BKE_gpencil_stroke_curve_duplicate(bGPDcurve *gpc_src)
return gpc_dst;
}
-/**
- * Make a copy of a given grease-pencil stroke.
- * \param gps_src: Source grease pencil strokes.
- * \param dup_points: Duplicate points data.
- * \param dup_curve: Duplicate curve data.
- * \return Pointer to new stroke.
- */
bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src,
const bool dup_points,
const bool dup_curve)
@@ -980,11 +902,6 @@ bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src,
return gps_dst;
}
-/**
- * Make a copy of a given gpencil frame.
- * \param gpf_src: Source grease pencil frame
- * \return Pointer to new frame
- */
bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src, const bool dup_strokes)
{
bGPDstroke *gps_dst = NULL;
@@ -1013,11 +930,6 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src, const bool dup_
return gpf_dst;
}
-/**
- * Make a copy of strokes between gpencil frames.
- * \param gpf_src: Source grease pencil frame
- * \param gpf_dst: Destination grease pencil frame
- */
void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_dst)
{
bGPDstroke *gps_dst = NULL;
@@ -1035,16 +947,10 @@ void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_ds
}
}
-/**
- * Make a copy of a given gpencil layer.
- * \param gpl_src: Source grease pencil layer
- * \return Pointer to new layer
- */
bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src,
const bool dup_frames,
const bool dup_strokes)
{
- const bGPDframe *gpf_src;
bGPDframe *gpf_dst;
bGPDlayer *gpl_dst;
@@ -1063,7 +969,7 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src,
/* copy frames */
BLI_listbase_clear(&gpl_dst->frames);
if (dup_frames) {
- for (gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
/* make a copy of source frame */
gpf_dst = BKE_gpencil_frame_duplicate(gpf_src, dup_strokes);
BLI_addtail(&gpl_dst->frames, gpf_dst);
@@ -1079,9 +985,6 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src,
return gpl_dst;
}
-/**
- * Make a copy of a given gpencil layer settings.
- */
void BKE_gpencil_layer_copy_settings(const bGPDlayer *gpl_src, bGPDlayer *gpl_dst)
{
gpl_dst->line_change = gpl_src->line_change;
@@ -1103,11 +1006,6 @@ void BKE_gpencil_layer_copy_settings(const bGPDlayer *gpl_src, bGPDlayer *gpl_ds
gpl_dst->flag = gpl_src->flag;
}
-/**
- * Make a copy of a given gpencil data-block.
- *
- * XXX: Should this be deprecated?
- */
bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
{
bGPdata *gpd_dst;
@@ -1140,10 +1038,6 @@ bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool in
/* ************************************************** */
/* GP Stroke API */
-/**
- * Ensure selection status of stroke is in sync with its points.
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_stroke_sync_selection(bGPdata *gpd, bGPDstroke *gps)
{
bGPDspoint *pt;
@@ -1207,14 +1101,12 @@ void BKE_gpencil_curve_sync_selection(bGPdata *gpd, bGPDstroke *gps)
}
}
-/* Assign unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_set(bGPdata *gpd, bGPDstroke *gps)
{
gpd->select_last_index++;
gps->select_index = gpd->select_last_index;
}
-/* Reset unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_reset(bGPDstroke *gps)
{
gps->select_index = 0;
@@ -1223,11 +1115,6 @@ void BKE_gpencil_stroke_select_index_reset(bGPDstroke *gps)
/* ************************************************** */
/* GP Frame API */
-/**
- * Delete the last stroke of the given frame.
- * \param gpl: Grease pencil layer
- * \param gpf: Grease pencil frame
- */
void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
{
bGPDstroke *gps = (gpf) ? gpf->strokes.last : NULL;
@@ -1259,11 +1146,6 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
/* ************************************************** */
/* GP Layer API */
-/**
- * Check if the given layer is able to be edited or not.
- * \param gpl: Grease pencil layer
- * \return True if layer is editable
- */
bool BKE_gpencil_layer_is_editable(const bGPDlayer *gpl)
{
/* Sanity check */
@@ -1280,12 +1162,6 @@ bool BKE_gpencil_layer_is_editable(const bGPDlayer *gpl)
return false;
}
-/**
- * Look up the gp-frame on the requested frame number, but don't add a new one.
- * \param gpl: Grease pencil layer
- * \param cframe: Frame number
- * \return Pointer to frame
- */
bGPDframe *BKE_gpencil_layer_frame_find(bGPDlayer *gpl, int cframe)
{
bGPDframe *gpf;
@@ -1302,16 +1178,6 @@ bGPDframe *BKE_gpencil_layer_frame_find(bGPDlayer *gpl, int cframe)
return NULL;
}
-/**
- * Get the appropriate gp-frame from a given layer
- * - this sets the layer's actframe var (if allowed to)
- * - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
- *
- * \param gpl: Grease pencil layer
- * \param cframe: Frame number
- * \param addnew: Add option
- * \return Pointer to new frame
- */
bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
{
bGPDframe *gpf = NULL;
@@ -1466,12 +1332,6 @@ bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_
return gpl->actframe;
}
-/**
- * Delete the given frame from a layer.
- * \param gpl: Grease pencil layer
- * \param gpf: Grease pencil frame
- * \return True if delete was done
- */
bool BKE_gpencil_layer_frame_delete(bGPDlayer *gpl, bGPDframe *gpf)
{
bool changed = false;
@@ -1495,12 +1355,6 @@ bool BKE_gpencil_layer_frame_delete(bGPDlayer *gpl, bGPDframe *gpf)
return changed;
}
-/**
- * Get layer by name
- * \param gpd: Grease pencil data-block
- * \param name: Layer name
- * \return Pointer to layer
- */
bGPDlayer *BKE_gpencil_layer_named_get(bGPdata *gpd, const char *name)
{
if (name[0] == '\0') {
@@ -1509,12 +1363,6 @@ bGPDlayer *BKE_gpencil_layer_named_get(bGPdata *gpd, const char *name)
return BLI_findstring(&gpd->layers, name, offsetof(bGPDlayer, info));
}
-/**
- * Get mask layer by name.
- * \param gpl: Grease pencil layer
- * \param name: Mask name
- * \return Pointer to mask layer
- */
bGPDlayer_Mask *BKE_gpencil_layer_mask_named_get(bGPDlayer *gpl, const char *name)
{
if (name[0] == '\0') {
@@ -1523,12 +1371,6 @@ bGPDlayer_Mask *BKE_gpencil_layer_mask_named_get(bGPDlayer *gpl, const char *nam
return BLI_findstring(&gpl->mask_layers, name, offsetof(bGPDlayer_Mask, name));
}
-/**
- * Add grease pencil mask layer.
- * \param gpl: Grease pencil layer
- * \param name: Name of the mask
- * \return Pointer to new mask layer
- */
bGPDlayer_Mask *BKE_gpencil_layer_mask_add(bGPDlayer *gpl, const char *name)
{
@@ -1540,11 +1382,6 @@ bGPDlayer_Mask *BKE_gpencil_layer_mask_add(bGPDlayer *gpl, const char *name)
return mask;
}
-/**
- * Remove grease pencil mask layer.
- * \param gpl: Grease pencil layer
- * \param mask: Grease pencil mask layer
- */
void BKE_gpencil_layer_mask_remove(bGPDlayer *gpl, bGPDlayer_Mask *mask)
{
BLI_freelinkN(&gpl->mask_layers, mask);
@@ -1552,11 +1389,6 @@ void BKE_gpencil_layer_mask_remove(bGPDlayer *gpl, bGPDlayer_Mask *mask)
CLAMP_MIN(gpl->act_mask, 0);
}
-/**
- * Remove any reference to mask layer.
- * \param gpd: Grease pencil data-block
- * \param name: Name of the mask layer
- */
void BKE_gpencil_layer_mask_remove_ref(bGPdata *gpd, const char *name)
{
bGPDlayer_Mask *mask_next;
@@ -1588,11 +1420,6 @@ static int gpencil_cb_sort_masks(const void *arg1, const void *arg2)
return val;
}
-/**
- * Sort grease pencil mask layers.
- * \param gpd: Grease pencil data-block
- * \param gpl: Grease pencil layer
- */
void BKE_gpencil_layer_mask_sort(bGPdata *gpd, bGPDlayer *gpl)
{
/* Update sort index. */
@@ -1608,10 +1435,6 @@ void BKE_gpencil_layer_mask_sort(bGPdata *gpd, bGPDlayer *gpl)
BLI_listbase_sort(&gpl->mask_layers, gpencil_cb_sort_masks);
}
-/**
- * Sort all grease pencil mask layer.
- * \param gpd: Grease pencil data-block
- */
void BKE_gpencil_layer_mask_sort_all(bGPdata *gpd)
{
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
@@ -1619,9 +1442,6 @@ void BKE_gpencil_layer_mask_sort_all(bGPdata *gpd)
}
}
-/**
- * Make a copy of a given gpencil mask layers.
- */
void BKE_gpencil_layer_mask_copy(const bGPDlayer *gpl_src, bGPDlayer *gpl_dst)
{
BLI_listbase_clear(&gpl_dst->mask_layers);
@@ -1632,9 +1452,6 @@ void BKE_gpencil_layer_mask_copy(const bGPDlayer *gpl_src, bGPDlayer *gpl_dst)
}
}
-/**
- * Clean any invalid mask layer.
- */
void BKE_gpencil_layer_mask_cleanup(bGPdata *gpd, bGPDlayer *gpl)
{
LISTBASE_FOREACH_MUTABLE (bGPDlayer_Mask *, mask, &gpl->mask_layers) {
@@ -1644,9 +1461,6 @@ void BKE_gpencil_layer_mask_cleanup(bGPdata *gpd, bGPDlayer *gpl)
}
}
-/**
- * Clean any invalid mask layer for all layers.
- */
void BKE_gpencil_layer_mask_cleanup_all_layers(bGPdata *gpd)
{
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
@@ -1675,21 +1489,11 @@ static int gpencil_cb_cmp_frame(void *thunk, const void *a, const void *b)
return 0;
}
-/**
- * Sort grease pencil frames.
- * \param gpl: Grease pencil layer
- * \param r_has_duplicate_frames: Duplicated frames flag
- */
void BKE_gpencil_layer_frames_sort(struct bGPDlayer *gpl, bool *r_has_duplicate_frames)
{
BLI_listbase_sort_r(&gpl->frames, gpencil_cb_cmp_frame, r_has_duplicate_frames);
}
-/**
- * Get the active grease pencil layer for editing.
- * \param gpd: Grease pencil data-block
- * \return Pointer to layer
- */
bGPDlayer *BKE_gpencil_layer_active_get(bGPdata *gpd)
{
/* error checking */
@@ -1733,11 +1537,6 @@ bGPDlayer *BKE_gpencil_layer_get_by_name(bGPdata *gpd, char *name, int first_if_
return NULL;
}
-/**
- * Set active grease pencil layer.
- * \param gpd: Grease pencil data-block
- * \param active: Grease pencil layer to set as active
- */
void BKE_gpencil_layer_active_set(bGPdata *gpd, bGPDlayer *active)
{
/* error checking */
@@ -1760,11 +1559,6 @@ void BKE_gpencil_layer_active_set(bGPdata *gpd, bGPDlayer *active)
}
}
-/**
- * Set locked layers for autolock mode.
- * \param gpd: Grease pencil data-block
- * \param unlock: Unlock flag
- */
void BKE_gpencil_layer_autolock_set(bGPdata *gpd, const bool unlock)
{
BLI_assert(gpd != NULL);
@@ -1795,11 +1589,6 @@ void BKE_gpencil_layer_autolock_set(bGPdata *gpd, const bool unlock)
}
}
-/**
- * Delete grease pencil layer.
- * \param gpd: Grease pencil data-block
- * \param gpl: Grease pencil layer
- */
void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
{
/* error checking */
@@ -1822,11 +1611,6 @@ void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
BLI_freelinkN(&gpd->layers, gpl);
}
-/**
- * Get grease pencil material from brush.
- * \param brush: Brush
- * \return Pointer to material
- */
Material *BKE_gpencil_brush_material_get(Brush *brush)
{
Material *ma = NULL;
@@ -1839,11 +1623,6 @@ Material *BKE_gpencil_brush_material_get(Brush *brush)
return ma;
}
-/**
- * Set grease pencil brush material.
- * \param brush: Brush
- * \param ma: Material
- */
void BKE_gpencil_brush_material_set(Brush *brush, Material *ma)
{
BLI_assert(brush);
@@ -1859,13 +1638,6 @@ void BKE_gpencil_brush_material_set(Brush *brush, Material *ma)
}
}
-/**
- * Adds the pinned material to the object if necessary.
- * \param bmain: Main pointer
- * \param ob: Grease pencil object
- * \param brush: Brush
- * \return Pointer to material
- */
Material *BKE_gpencil_object_material_ensure_from_brush(Main *bmain, Object *ob, Brush *brush)
{
if (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED) {
@@ -1884,13 +1656,6 @@ Material *BKE_gpencil_object_material_ensure_from_brush(Main *bmain, Object *ob,
return BKE_object_material_get(ob, ob->actcol);
}
-/**
- * Assigns the material to object (if not already present) and returns its index (mat_nr).
- * \param bmain: Main pointer
- * \param ob: Grease pencil object
- * \param material: Material
- * \return Index of the material
- */
int BKE_gpencil_object_material_ensure(Main *bmain, Object *ob, Material *material)
{
if (!material) {
@@ -1905,14 +1670,6 @@ int BKE_gpencil_object_material_ensure(Main *bmain, Object *ob, Material *materi
return index;
}
-/**
- * Creates a new grease-pencil material and assigns it to object.
- * \param bmain: Main pointer
- * \param ob: Grease pencil object
- * \param name: Material name
- * \param r_index: value is set to zero based index of the new material if \a r_index is not NULL.
- * \return Material pointer.
- */
Material *BKE_gpencil_object_material_new(Main *bmain, Object *ob, const char *name, int *r_index)
{
Material *ma = BKE_gpencil_material_add(bmain, name);
@@ -1927,12 +1684,6 @@ Material *BKE_gpencil_object_material_new(Main *bmain, Object *ob, const char *n
return ma;
}
-/**
- * Returns the material for a brush with respect to its pinned state.
- * \param ob: Grease pencil object
- * \param brush: Brush
- * \return Material pointer
- */
Material *BKE_gpencil_object_material_from_brush_get(Object *ob, Brush *brush)
{
if ((brush) && (brush->gpencil_settings) &&
@@ -1944,12 +1695,6 @@ Material *BKE_gpencil_object_material_from_brush_get(Object *ob, Brush *brush)
return BKE_object_material_get(ob, ob->actcol);
}
-/**
- * Returns the material index for a brush with respect to its pinned state.
- * \param ob: Grease pencil object
- * \param brush: Brush
- * \return Material index.
- */
int BKE_gpencil_object_material_get_index_from_brush(Object *ob, Brush *brush)
{
if ((brush) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) {
@@ -1959,12 +1704,6 @@ int BKE_gpencil_object_material_get_index_from_brush(Object *ob, Brush *brush)
return ob->actcol - 1;
}
-/**
- * Guaranteed to return a material assigned to object. Returns never NULL.
- * \param bmain: Main pointer
- * \param ob: Grease pencil object
- * \return Material pointer.
- */
Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettings(Main *bmain,
Object *ob,
ToolSettings *ts)
@@ -1977,13 +1716,6 @@ Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettings(Main
return BKE_gpencil_object_material_ensure_from_active_input_brush(bmain, ob, NULL);
}
-/**
- * Guaranteed to return a material assigned to object. Returns never NULL.
- * \param bmain: Main pointer
- * \param ob: Grease pencil object.
- * \param brush: Brush
- * \return Material pointer
- */
Material *BKE_gpencil_object_material_ensure_from_active_input_brush(Main *bmain,
Object *ob,
Brush *brush)
@@ -2001,12 +1733,6 @@ Material *BKE_gpencil_object_material_ensure_from_active_input_brush(Main *bmain
return BKE_gpencil_object_material_ensure_from_active_input_material(ob);
}
-/**
- * Guaranteed to return a material assigned to object. Returns never NULL.
- * Only use this for materials unrelated to user input.
- * \param ob: Grease pencil object
- * \return Material pointer
- */
Material *BKE_gpencil_object_material_ensure_from_active_input_material(Object *ob)
{
Material *ma = BKE_object_material_get(ob, ob->actcol);
@@ -2017,11 +1743,6 @@ Material *BKE_gpencil_object_material_ensure_from_active_input_material(Object *
return BKE_material_default_gpencil();
}
-/**
- * Get active color, and add all default settings if we don't find anything.
- * \param ob: Grease pencil object
- * \return Material pointer
- */
Material *BKE_gpencil_object_material_ensure_active(Object *ob)
{
Material *ma = NULL;
@@ -2040,11 +1761,6 @@ Material *BKE_gpencil_object_material_ensure_active(Object *ob)
}
/* ************************************************** */
-/**
- * Check if stroke has any point selected
- * \param gps: Grease pencil stroke
- * \return True if selected
- */
bool BKE_gpencil_stroke_select_check(const bGPDstroke *gps)
{
const bGPDspoint *pt;
@@ -2060,11 +1776,6 @@ bool BKE_gpencil_stroke_select_check(const bGPDstroke *gps)
/* ************************************************** */
/* GP Object - Vertex Groups */
-/**
- * Remove a vertex group.
- * \param ob: Grease pencil object
- * \param defgroup: deform group
- */
void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
{
bGPdata *gpd = ob->data;
@@ -2104,10 +1815,6 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
-/**
- * Ensure stroke has vertex group.
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_dvert_ensure(bGPDstroke *gps)
{
if (gps->dvert == NULL) {
@@ -2117,14 +1824,6 @@ void BKE_gpencil_dvert_ensure(bGPDstroke *gps)
/* ************************************************** */
-/**
- * Get range of selected frames in layer.
- * Always the active frame is considered as selected, so if no more selected the range
- * will be equal to the current active frame.
- * \param gpl: Layer.
- * \param r_initframe: Number of first selected frame.
- * \param r_endframe: Number of last selected frame.
- */
void BKE_gpencil_frame_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_endframe)
{
*r_initframe = gpl->actframe->framenum;
@@ -2142,14 +1841,6 @@ void BKE_gpencil_frame_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_e
}
}
-/**
- * Get Falloff factor base on frame range
- * \param gpf: Frame.
- * \param actnum: Number of active frame in layer.
- * \param f_init: Number of first selected frame.
- * \param f_end: Number of last selected frame.
- * \param cur_falloff: Curve with falloff factors.
- */
float BKE_gpencil_multiframe_falloff_calc(
bGPDframe *gpf, int actnum, int f_init, int f_end, CurveMapping *cur_falloff)
{
@@ -2181,12 +1872,6 @@ float BKE_gpencil_multiframe_falloff_calc(
return value;
}
-/**
- * Reassign strokes using a material.
- * \param gpd: Grease pencil data-block
- * \param totcol: Total materials
- * \param index: Index of the material
- */
void BKE_gpencil_material_index_reassign(bGPdata *gpd, int totcol, int index)
{
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
@@ -2202,12 +1887,6 @@ void BKE_gpencil_material_index_reassign(bGPdata *gpd, int totcol, int index)
}
}
-/**
- * Remove strokes using a material.
- * \param gpd: Grease pencil data-block
- * \param index: Index of the material
- * \return True if removed
- */
bool BKE_gpencil_material_index_used(bGPdata *gpd, int index)
{
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
@@ -2223,12 +1902,6 @@ bool BKE_gpencil_material_index_used(bGPdata *gpd, int index)
return false;
}
-/**
- * Remap material
- * \param gpd: Grease pencil data-block
- * \param remap: Remap index
- * \param remap_len: Remap length
- */
void BKE_gpencil_material_remap(struct bGPdata *gpd,
const unsigned int *remap,
unsigned int remap_len)
@@ -2254,15 +1927,6 @@ void BKE_gpencil_material_remap(struct bGPdata *gpd,
#undef MAT_NR_REMAP
}
-/**
- * Load a table with material conversion index for merged materials.
- * \param ob: Grease pencil object.
- * \param hue_threshold: Threshold for Hue.
- * \param sat_threshold: Threshold for Saturation.
- * \param val_threshold: Threshold for Value.
- * \param r_mat_table: return material table.
- * \return True if done.
- */
bool BKE_gpencil_merge_materials_table_get(Object *ob,
const float hue_threshold,
const float sat_threshold,
@@ -2382,15 +2046,6 @@ bool BKE_gpencil_merge_materials_table_get(Object *ob,
return changed;
}
-/**
- * Merge similar materials
- * \param ob: Grease pencil object
- * \param hue_threshold: Threshold for Hue
- * \param sat_threshold: Threshold for Saturation
- * \param val_threshold: Threshold for Value
- * \param r_removed: Number of materials removed
- * \return True if done
- */
bool BKE_gpencil_merge_materials(Object *ob,
const float hue_threshold,
const float sat_threshold,
@@ -2449,10 +2104,6 @@ bool BKE_gpencil_merge_materials(Object *ob,
return changed;
}
-/**
- * Calc grease pencil statistics functions.
- * \param gpd: Grease pencil data-block
- */
void BKE_gpencil_stats_update(bGPdata *gpd)
{
gpd->totlayer = 0;
@@ -2472,12 +2123,6 @@ void BKE_gpencil_stats_update(bGPdata *gpd)
}
}
-/**
- * Get material index (0-based like mat_nr not actcol).
- * \param ob: Grease pencil object
- * \param ma: Material
- * \return Index of the material
- */
int BKE_gpencil_object_material_index_get(Object *ob, Material *ma)
{
short *totcol = BKE_object_material_len_p(ob);
@@ -2520,11 +2165,6 @@ Material *BKE_gpencil_object_material_ensure_by_name(Main *bmain,
return BKE_gpencil_object_material_new(bmain, ob, name, r_index);
}
-/**
- * Create a default palette.
- * \param bmain: Main pointer
- * \param scene: Scene
- */
void BKE_gpencil_palette_ensure(Main *bmain, Scene *scene)
{
const char *hexcol[] = {
@@ -2574,15 +2214,6 @@ void BKE_gpencil_palette_ensure(Main *bmain, Scene *scene)
BKE_paint_palette_set(&ts->gp_vertexpaint->paint, palette);
}
-/**
- * Create grease pencil strokes from image
- * \param sima: Image
- * \param gpd: Grease pencil data-block
- * \param gpf: Grease pencil frame
- * \param size: Size
- * \param mask: Mask
- * \return True if done
- */
bool BKE_gpencil_from_image(
SpaceImage *sima, bGPdata *gpd, bGPDframe *gpf, const float size, const bool mask)
{
@@ -2714,6 +2345,8 @@ void BKE_gpencil_visible_stroke_iter(bGPdata *gpd,
}
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Advanced Iterator
*
@@ -2918,11 +2551,6 @@ void BKE_gpencil_visible_stroke_advanced_iter(ViewLayer *view_layer,
}
}
-/**
- * Update original pointers in evaluated frame.
- * \param gpf_orig: Original grease-pencil frame.
- * \param gpf_eval: Evaluated grease pencil frame.
- */
void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig,
const struct bGPDframe *gpf_eval)
{
@@ -2951,11 +2579,6 @@ void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig
}
}
-/**
- * Update pointers of eval data to original data to keep references.
- * \param ob_orig: Original grease pencil object
- * \param ob_eval: Evaluated grease pencil object
- */
void BKE_gpencil_update_orig_pointers(const Object *ob_orig, const Object *ob_eval)
{
bGPdata *gpd_eval = (bGPdata *)ob_eval->data;
@@ -2986,13 +2609,6 @@ void BKE_gpencil_update_orig_pointers(const Object *ob_orig, const Object *ob_ev
}
}
-/**
- * Get parent matrix, including layer parenting.
- * \param depsgraph: Depsgraph
- * \param obact: Grease pencil object
- * \param gpl: Grease pencil layer
- * \param diff_mat: Result parent matrix
- */
void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph,
Object *obact,
bGPDlayer *gpl,
@@ -3041,11 +2657,6 @@ void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph,
unit_m4(diff_mat); /* not defined type */
}
-/**
- * Update parent matrix and local transforms.
- * \param depsgraph: Depsgraph
- * \param ob: Grease pencil object
- */
void BKE_gpencil_update_layer_transforms(const Depsgraph *depsgraph, Object *ob)
{
if (ob->type != OB_GPENCIL) {
@@ -3105,12 +2716,6 @@ void BKE_gpencil_update_layer_transforms(const Depsgraph *depsgraph, Object *ob)
}
}
-/**
- * Find material by name prefix.
- * \param ob: Object pointer
- * \param name_prefix: Prefix name of the material
- * \return Index
- */
int BKE_gpencil_material_find_index_by_name_prefix(Object *ob, const char *name_prefix)
{
const int name_prefix_len = strlen(name_prefix);
@@ -3125,7 +2730,6 @@ int BKE_gpencil_material_find_index_by_name_prefix(Object *ob, const char *name_
return -1;
}
-/* Create a hash with the list of selected frame number. */
void BKE_gpencil_frame_selected_hash(bGPdata *gpd, struct GHash *r_list)
{
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c
index 3819c0699f4..d633678b873 100644
--- a/source/blender/blenkernel/intern/gpencil_curve.c
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -477,17 +477,6 @@ static void gpencil_editstroke_deselect_all(bGPDcurve *gpc)
gpc->flag &= ~GP_CURVE_SELECT;
}
-/**
- * Convert a curve object to grease pencil stroke.
- *
- * \param bmain: Main thread pointer
- * \param scene: Original scene.
- * \param ob_gp: Grease pencil object to add strokes.
- * \param ob_cu: Curve to convert.
- * \param use_collections: Create layers using collection names.
- * \param scale_thickness: Scale thickness factor.
- * \param sample: Sample distance, zero to disable.
- */
void BKE_gpencil_convert_curve(Main *bmain,
Scene *scene,
Object *ob_gp,
@@ -639,9 +628,6 @@ static bGPDcurve *gpencil_stroke_editcurve_generate_edgecases(bGPDstroke *gps,
return NULL;
}
-/**
- * Creates a bGPDcurve by doing a cubic curve fitting on the grease pencil stroke points.
- */
bGPDcurve *BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps,
const float error_threshold,
const float corner_angle,
@@ -753,9 +739,6 @@ bGPDcurve *BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps,
return editcurve;
}
-/**
- * Updates the editcurve for a stroke. Frees the old curve if one exists and generates a new one.
- */
void BKE_gpencil_stroke_editcurve_update(bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps)
{
if (gps == NULL || gps->totpoints < 0) {
@@ -778,9 +761,6 @@ void BKE_gpencil_stroke_editcurve_update(bGPdata *gpd, bGPDlayer *gpl, bGPDstrok
gps->editcurve = editcurve;
}
-/**
- * Sync the selection from stroke to editcurve
- */
void BKE_gpencil_editcurve_stroke_sync_selection(bGPdata *UNUSED(gpd),
bGPDstroke *gps,
bGPDcurve *gpc)
@@ -807,9 +787,6 @@ void BKE_gpencil_editcurve_stroke_sync_selection(bGPdata *UNUSED(gpd),
}
}
-/**
- * Sync the selection from editcurve to stroke
- */
void BKE_gpencil_stroke_editcurve_sync_selection(bGPdata *gpd, bGPDstroke *gps, bGPDcurve *gpc)
{
if (gpc->flag & GP_CURVE_SELECT) {
@@ -1055,9 +1032,6 @@ static float *gpencil_stroke_points_from_editcurve_fixed_resolu(bGPDcurve_point
return (float(*))r_points;
}
-/**
- * Recalculate stroke points with the editcurve of the stroke.
- */
void BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps,
const uint resolution,
const bool adaptive)
@@ -1142,9 +1116,6 @@ void BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps,
MEM_freeN(points);
}
-/**
- * Recalculate the handles of the edit curve of a grease pencil stroke
- */
void BKE_gpencil_editcurve_recalculate_handles(bGPDstroke *gps)
{
if (gps == NULL || gps->editcurve == NULL) {
@@ -1167,7 +1138,7 @@ void BKE_gpencil_editcurve_recalculate_handles(bGPDstroke *gps)
bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
bGPDcurve_point *gpc_pt_prev = &gpc->curve_points[i - 1];
bGPDcurve_point *gpc_pt_next = &gpc->curve_points[i + 1];
- /* update handle if point or neighbour is selected */
+ /* update handle if point or neighbor is selected */
if (gpc_pt->flag & GP_CURVE_POINT_SELECT || gpc_pt_prev->flag & GP_CURVE_POINT_SELECT ||
gpc_pt_next->flag & GP_CURVE_POINT_SELECT) {
BezTriple *bezt = &gpc_pt->bezt;
diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc
index debdf44b0bb..9abdbceec61 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.cc
+++ b/source/blender/blenkernel/intern/gpencil_geom.cc
@@ -33,10 +33,10 @@
#include "BLI_array_utils.h"
#include "BLI_blenlib.h"
-#include "BLI_float3.hh"
#include "BLI_ghash.h"
#include "BLI_hash.h"
#include "BLI_heap.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.h"
#include "BLI_polyfill_2d.h"
#include "BLI_span.hh"
@@ -60,6 +60,7 @@
#include "BKE_gpencil_geom.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "DEG_depsgraph_query.h"
@@ -67,15 +68,10 @@
using blender::float3;
using blender::Span;
-/* GP Object - Boundbox Support */
-/**
- *Get min/max coordinate bounds for single stroke.
- * \param gps: Grease pencil stroke
- * \param use_select: Include only selected points
- * \param r_min: Result minimum coordinates
- * \param r_max: Result maximum coordinates
- * \return True if it was possible to calculate
- */
+/* -------------------------------------------------------------------- */
+/** \name Grease Pencil Object: Bound-box Support
+ * \{ */
+
bool BKE_gpencil_stroke_minmax(const bGPDstroke *gps,
const bool use_select,
float r_min[3],
@@ -104,13 +100,6 @@ bool BKE_gpencil_stroke_minmax(const bGPDstroke *gps,
return changed;
}
-/**
- * Get min/max bounds of all strokes in grease pencil data-block.
- * \param gpd: Grease pencil datablock
- * \param r_min: Result minimum coordinates
- * \param r_max: Result maximum coordinates
- * \return True if it was possible to calculate
- */
bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3])
{
bool changed = false;
@@ -134,11 +123,6 @@ bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3])
return changed;
}
-/**
- * Compute center of bounding box.
- * \param gpd: Grease pencil data-block
- * \param r_centroid: Location of the center
- */
void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3])
{
float3 min;
@@ -149,10 +133,6 @@ void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3])
mul_v3_v3fl(r_centroid, tot, 0.5f);
}
-/**
- * Compute stroke bounding box.
- * \param gps: Grease pencil Stroke
- */
void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps)
{
INIT_MINMAX(gps->boundbox_min, gps->boundbox_max);
@@ -166,7 +146,7 @@ void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps)
static void boundbox_gpencil(Object *ob)
{
if (ob->runtime.bb == nullptr) {
- ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
+ ob->runtime.bb = MEM_cnew<BoundBox>("GPencil boundbox");
}
BoundBox *bb = ob->runtime.bb;
@@ -184,11 +164,6 @@ static void boundbox_gpencil(Object *ob)
bb->flag &= ~BOUNDBOX_DIRTY;
}
-/**
- * Get grease pencil object bounding box.
- * \param ob: Grease pencil object
- * \return Bounding box
- */
BoundBox *BKE_gpencil_boundbox_get(Object *ob)
{
if (ELEM(nullptr, ob, ob->data)) {
@@ -208,7 +183,7 @@ BoundBox *BKE_gpencil_boundbox_get(Object *ob)
* to keep both values synchronized. */
if (!ELEM(ob_orig, nullptr, ob)) {
if (ob_orig->runtime.bb == nullptr) {
- ob_orig->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
+ ob_orig->runtime.bb = MEM_cnew<BoundBox>("GPencil boundbox");
}
for (int i = 0; i < 8; i++) {
copy_v3_v3(ob_orig->runtime.bb->vec[i], ob->runtime.bb->vec[i]);
@@ -218,7 +193,11 @@ BoundBox *BKE_gpencil_boundbox_get(Object *ob)
return ob->runtime.bb;
}
-/* ************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Sample
+ * \{ */
static int stroke_march_next_point(const bGPDstroke *gps,
const int index_next_pt,
@@ -386,7 +365,7 @@ static void stroke_defvert_create_nr_list(MDeformVert *dv_list,
}
}
if (!found) {
- ld = (LinkData *)MEM_callocN(sizeof(LinkData), "def_nr_item");
+ ld = MEM_cnew<LinkData>("def_nr_item");
ld->data = POINTER_FROM_INT(dw->def_nr);
BLI_addtail(result, ld);
tw++;
@@ -431,12 +410,6 @@ static void stroke_interpolate_deform_weights(
}
}
-/**
- * Resample a stroke
- * \param gpd: Grease pencil data-block
- * \param gps: Stroke to sample
- * \param dist: Distance of one segment
- */
bool BKE_gpencil_stroke_sample(bGPdata *gpd, bGPDstroke *gps, const float dist, const bool select)
{
bGPDspoint *pt = gps->points;
@@ -594,15 +567,6 @@ static bool BKE_gpencil_stroke_extra_points(bGPDstroke *gps,
return true;
}
-/**
- * Backbone stretch similar to Freestyle.
- * \param gps: Stroke to sample.
- * \param dist: Length of the added section.
- * \param overshoot_fac: Relative length of the curve which is used to determine the extension.
- * \param mode: Affect to Start, End or Both extremes (0->Both, 1->Start, 2->End)
- * \param follow_curvature: True for approximating curvature of given overshoot.
- * \param extra_point_count: When follow_curvature is true, use this amount of extra points
- */
bool BKE_gpencil_stroke_stretch(bGPDstroke *gps,
const float dist,
const float overshoot_fac,
@@ -779,12 +743,12 @@ bool BKE_gpencil_stroke_stretch(bGPDstroke *gps,
return true;
}
-/**
- * Trim stroke to needed segments
- * \param gps: Target stroke
- * \param index_from: the index of the first point to be used in the trimmed result
- * \param index_to: the index of the last point to be used in the trimmed result
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Trim
+ * \{ */
+
bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const int index_to)
{
bGPDspoint *pt = gps->points, *new_pt;
@@ -837,15 +801,12 @@ bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const
return true;
}
-/**
- * Split stroke.
- * \param gpd: Grease pencil data-block
- * \param gpf: Grease pencil frame
- * \param gps: Grease pencil original stroke
- * \param before_index: Position of the point to split
- * \param remaining_gps: Secondary stroke after split.
- * \return True if the split was done
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Split
+ * \{ */
+
bool BKE_gpencil_stroke_split(bGPdata *gpd,
bGPDframe *gpf,
bGPDstroke *gps,
@@ -898,12 +859,12 @@ bool BKE_gpencil_stroke_split(bGPdata *gpd,
return true;
}
-/**
- * Shrink the stroke by length.
- * \param gps: Stroke to shrink
- * \param dist: delta length
- * \param mode: 1->Start, 2->End
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Shrink
+ * \{ */
+
bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist, const short mode)
{
#define START 1
@@ -976,13 +937,14 @@ bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist, const short mo
return true;
}
-/**
- * Apply smooth position to stroke point.
- * \param gps: Stroke to smooth
- * \param i: Point index
- * \param inf: Amount of smoothing to apply
- */
-bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Smooth Positions
+ * \{ */
+
+bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf, const bool smooth_caps)
{
bGPDspoint *pt = &gps->points[i];
float sco[3] = {0.0f};
@@ -996,7 +958,7 @@ bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf)
/* Only affect endpoints by a fraction of the normal strength,
* to prevent the stroke from shrinking too much
*/
- if (!is_cyclic && ELEM(i, 0, gps->totpoints - 1)) {
+ if ((!smooth_caps) && (!is_cyclic && ELEM(i, 0, gps->totpoints - 1))) {
inf *= 0.1f;
}
@@ -1054,12 +1016,12 @@ bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf)
return true;
}
-/**
- * Apply smooth strength to stroke point.
- * \param gps: Stroke to smooth
- * \param point_index: Point index
- * \param influence: Amount of smoothing to apply
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Smooth Strength
+ * \{ */
+
bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float influence)
{
bGPDspoint *ptb = &gps->points[point_index];
@@ -1132,12 +1094,12 @@ bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float
return true;
}
-/**
- * Apply smooth for thickness to stroke point (use pressure).
- * \param gps: Stroke to smooth
- * \param point_index: Point index
- * \param influence: Amount of smoothing to apply
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Smooth Thickness
+ * \{ */
+
bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float influence)
{
bGPDspoint *ptb = &gps->points[point_index];
@@ -1209,12 +1171,12 @@ bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float
return true;
}
-/**
- * Apply smooth for UV rotation to stroke point (use pressure).
- * \param gps: Stroke to smooth
- * \param point_index: Point index
- * \param influence: Amount of smoothing to apply
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Smooth UV
+ * \{ */
+
bool BKE_gpencil_stroke_smooth_uv(bGPDstroke *gps, int point_index, float influence)
{
bGPDspoint *ptb = &gps->points[point_index];
@@ -1266,14 +1228,6 @@ bool BKE_gpencil_stroke_smooth_uv(bGPDstroke *gps, int point_index, float influe
return true;
}
-/**
- * Get points of stroke always flat to view not affected
- * by camera view or view position.
- * \param points: Array of grease pencil points (3D)
- * \param totpoints: Total of points
- * \param points2d: Result array of 2D points
- * \param r_direction: Return Concave (-1), Convex (1), or Auto-detect (0)
- */
void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points,
int totpoints,
float (*points2d)[2],
@@ -1348,17 +1302,6 @@ void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points,
*r_direction = (cross >= 0.0f) ? 1 : -1;
}
-/**
- * Get points of stroke always flat to view not affected by camera view or view position
- * using another stroke as reference.
- * \param ref_points: Array of reference points (3D)
- * \param ref_totpoints: Total reference points
- * \param points: Array of points to flat (3D)
- * \param totpoints: Total points
- * \param points2d: Result array of 2D points
- * \param scale: Scale factor
- * \param r_direction: Return Concave (-1), Convex (1), or Auto-detect (0)
- */
void BKE_gpencil_stroke_2d_flat_ref(const bGPDspoint *ref_points,
int ref_totpoints,
const bGPDspoint *points,
@@ -1482,10 +1425,12 @@ static void gpencil_calc_stroke_fill_uv(const float (*points2d)[2],
}
}
-/**
- * Triangulate stroke to generate data for filling areas.
- * \param gps: Grease pencil stroke
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Fill Triangulate
+ * \{ */
+
void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps)
{
BLI_assert(gps->totpoints >= 3);
@@ -1545,10 +1490,6 @@ void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps)
MEM_SAFE_FREE(uv);
}
-/**
- * Update Stroke UV data.
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_stroke_uv_update(bGPDstroke *gps)
{
if (gps == nullptr || gps->totpoints == 0) {
@@ -1564,11 +1505,6 @@ void BKE_gpencil_stroke_uv_update(bGPDstroke *gps)
}
}
-/**
- * Recalc all internal geometry data for the stroke
- * \param gpd: Grease pencil data-block
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_stroke_geometry_update(bGPdata *gpd, bGPDstroke *gps)
{
if (gps == nullptr) {
@@ -1606,12 +1542,6 @@ void BKE_gpencil_stroke_geometry_update(bGPdata *gpd, bGPDstroke *gps)
BKE_gpencil_stroke_boundingbox_calc(gps);
}
-/**
- * Calculate grease pencil stroke length.
- * \param gps: Grease pencil stroke
- * \param use_3d: Set to true to use 3D points
- * \return Length of the stroke
- */
float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d)
{
if (!gps->points || gps->totpoints < 2) {
@@ -1632,7 +1562,6 @@ float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d)
return total_length;
}
-/** Calculate grease pencil stroke length between points. */
float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps,
const int start_index,
const int end_index,
@@ -1660,10 +1589,6 @@ float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps,
return total_length;
}
-/**
- * Trim stroke to the first intersection or loop.
- * \param gps: Stroke data
- */
bool BKE_gpencil_stroke_trim(bGPdata *gpd, bGPDstroke *gps)
{
if (gps->totpoints < 4) {
@@ -1756,10 +1681,6 @@ bool BKE_gpencil_stroke_trim(bGPdata *gpd, bGPDstroke *gps)
return intersect;
}
-/**
- * Close grease pencil stroke.
- * \param gps: Stroke to close
- */
bool BKE_gpencil_stroke_close(bGPDstroke *gps)
{
bGPDspoint *pt1 = nullptr;
@@ -1845,13 +1766,12 @@ bool BKE_gpencil_stroke_close(bGPDstroke *gps)
return true;
}
-/**
- * Dissolve points in stroke.
- * \param gpd: Grease pencil data-block
- * \param gpf: Grease pencil frame
- * \param gps: Grease pencil stroke
- * \param tag: Type of tag for point
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dissolve Points
+ * \{ */
+
void BKE_gpencil_dissolve_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, const short tag)
{
bGPDspoint *pt;
@@ -1934,11 +1854,12 @@ void BKE_gpencil_dissolve_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps,
}
}
-/**
- * Calculate stroke normals.
- * \param gps: Grease pencil stroke
- * \param r_normal: Return Normal vector normalized
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Normal Calculation
+ * \{ */
+
void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
{
if (gps->totpoints < 3) {
@@ -1969,18 +1890,12 @@ void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
normalize_v3(r_normal);
}
-/* Stroke Simplify ------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Simplify
+ * \{ */
-/**
- * Reduce a series of points to a simplified version, but
- * maintains the general shape of the series
- *
- * Ramer - Douglas - Peucker algorithm
- * by http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
- * \param gpd: Grease pencil data-block
- * \param gps: Grease pencil stroke
- * \param epsilon: Epsilon value to define precision of the algorithm
- */
void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float epsilon)
{
bGPDspoint *old_points = (bGPDspoint *)MEM_dupallocN(gps->points);
@@ -2085,11 +2000,6 @@ void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float e
MEM_SAFE_FREE(marked);
}
-/**
- * Simplify alternate vertex of stroke except extremes.
- * \param gpd: Grease pencil data-block
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps)
{
if (gps->totpoints < 5) {
@@ -2150,13 +2060,6 @@ void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps)
MEM_SAFE_FREE(old_dvert);
}
-/**
- * Subdivide a stroke
- * \param gpd: Grease pencil data-block
- * \param gps: Stroke
- * \param level: Level of subdivision
- * \param type: Type of subdivision
- */
void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int type)
{
bGPDspoint *temp_points;
@@ -2269,19 +2172,12 @@ void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int
BKE_gpencil_stroke_geometry_update(gpd, gps);
}
-/* Merge by distance ------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Merge by Distance
+ * \{ */
-/**
- * Reduce a series of points when the distance is below a threshold.
- * Special case for first and last points (both are kept) for other points,
- * the merge point always is at first point.
- *
- * \param gpd: Grease pencil data-block.
- * \param gpf: Grease Pencil frame.
- * \param gps: Grease Pencil stroke.
- * \param threshold: Distance between points.
- * \param use_unselected: Set to true to analyze all stroke and not only selected points.
- */
void BKE_gpencil_stroke_merge_distance(bGPdata *gpd,
bGPDframe *gpf,
bGPDstroke *gps,
@@ -2455,6 +2351,7 @@ static void gpencil_generate_edgeloops(Object *ob,
if (me->totedge == 0) {
return;
}
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me);
/* Arrays for all edge vertices (forward and backward) that form a edge loop.
* This is reused for each edge-loop to create gpencil stroke. */
@@ -2469,13 +2366,13 @@ static void gpencil_generate_edgeloops(Object *ob,
MEdge *ed = &me->medge[i];
gped = &gp_edges[i];
MVert *mv1 = &me->mvert[ed->v1];
- normal_short_to_float_v3(gped->n1, mv1->no);
+ copy_v3_v3(gped->n1, vert_normals[ed->v1]);
gped->v1 = ed->v1;
copy_v3_v3(gped->v1_co, mv1->co);
MVert *mv2 = &me->mvert[ed->v2];
- normal_short_to_float_v3(gped->n2, mv2->no);
+ copy_v3_v3(gped->n2, vert_normals[ed->v2]);
gped->v2 = ed->v2;
copy_v3_v3(gped->v2_co, mv2->co);
@@ -2544,7 +2441,7 @@ static void gpencil_generate_edgeloops(Object *ob,
/* Add segment. */
bGPDspoint *pt = &gps_stroke->points[i];
- normal_short_to_float_v3(fpt, mv->no);
+ copy_v3_v3(fpt, vert_normals[vertex_index]);
mul_v3_v3fl(fpt, fpt, offset);
add_v3_v3v3(&pt->x, mv->co, fpt);
mul_m4_v3(matrix, &pt->x);
@@ -2639,22 +2536,6 @@ static void make_element_name(const char *obname, const char *name, const int ma
BLI_strncpy_utf8(r_name, str, maxlen);
}
-/**
- * Convert a mesh object to grease pencil stroke.
- *
- * \param bmain: Main thread pointer.
- * \param depsgraph: Original depsgraph.
- * \param scene: Original scene.
- * \param ob_gp: Grease pencil object to add strokes.
- * \param ob_mesh: Mesh to convert.
- * \param angle: Limit angle to consider a edge-loop ends.
- * \param thickness: Thickness of the strokes.
- * \param offset: Offset along the normals.
- * \param matrix: Transformation matrix.
- * \param frame_offset: Destination frame number offset.
- * \param use_seams: Only export seam edges.
- * \param use_faces: Export faces as filled strokes.
- */
bool BKE_gpencil_convert_mesh(Main *bmain,
Depsgraph *depsgraph,
Scene *scene,
@@ -2807,11 +2688,6 @@ bool BKE_gpencil_convert_mesh(Main *bmain,
return true;
}
-/**
- * Apply grease pencil Transforms.
- * \param gpd: Grease pencil data-block
- * \param mat: Transformation matrix
- */
void BKE_gpencil_transform(bGPdata *gpd, const float mat[4][4])
{
if (gpd == nullptr) {
@@ -2845,7 +2721,6 @@ void BKE_gpencil_transform(bGPdata *gpd, const float mat[4][4])
}
}
-/* Used for "move only origins" in object_data_transform.c */
int BKE_gpencil_stroke_point_count(const bGPdata *gpd)
{
int total_points = 0;
@@ -2872,7 +2747,6 @@ int BKE_gpencil_stroke_point_count(const bGPdata *gpd)
return total_points;
}
-/* Used for "move only origins" in object_data_transform.c */
void BKE_gpencil_point_coords_get(bGPdata *gpd, GPencilPointCoordinates *elem_data)
{
if (gpd == nullptr) {
@@ -2903,7 +2777,6 @@ void BKE_gpencil_point_coords_get(bGPdata *gpd, GPencilPointCoordinates *elem_da
}
}
-/* Used for "move only origins" in object_data_transform.c */
void BKE_gpencil_point_coords_apply(bGPdata *gpd, const GPencilPointCoordinates *elem_data)
{
if (gpd == nullptr) {
@@ -2937,7 +2810,6 @@ void BKE_gpencil_point_coords_apply(bGPdata *gpd, const GPencilPointCoordinates
}
}
-/* Used for "move only origins" in object_data_transform.c */
void BKE_gpencil_point_coords_apply_with_mat4(bGPdata *gpd,
const GPencilPointCoordinates *elem_data,
const float mat[4][4])
@@ -2974,10 +2846,6 @@ void BKE_gpencil_point_coords_apply_with_mat4(bGPdata *gpd,
}
}
-/**
- * Set a random color to stroke using vertex color.
- * \param gps: Stroke
- */
void BKE_gpencil_stroke_set_random_color(bGPDstroke *gps)
{
BLI_assert(gps->totpoints > 0);
@@ -2993,7 +2861,6 @@ void BKE_gpencil_stroke_set_random_color(bGPDstroke *gps)
}
}
-/* Flip stroke. */
void BKE_gpencil_stroke_flip(bGPDstroke *gps)
{
/* Reverse points. */
@@ -3103,28 +2970,25 @@ static void gpencil_stroke_join_islands(bGPdata *gpd,
BKE_gpencil_free_stroke(gps_last);
}
-/* Split the given stroke into several new strokes, partitioning
- * it based on whether the stroke points have a particular flag
- * is set (e.g. "GP_SPOINT_SELECT" in most cases, but not always)
- *
- * The algorithm used here is as follows:
- * 1) We firstly identify the number of "islands" of non-tagged points
- * which will all end up being in new strokes.
- * - In the most extreme case (i.e. every other vert is a 1-vert island),
- * we have at most n / 2 islands
- * - Once we start having larger islands than that, the number required
- * becomes much less
- * 2) Each island gets converted to a new stroke
- * If the number of points is <= limit, the stroke is deleted
- */
bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
bGPDframe *gpf,
bGPDstroke *gps,
bGPDstroke *next_stroke,
int tag_flags,
- bool select,
- int limit)
+ const bool select,
+ const bool flat_cap,
+ const int limit)
{
+ /* The algorithm used here is as follows:
+ * 1) We firstly identify the number of "islands" of non-tagged points
+ * which will all end up being in new strokes.
+ * - In the most extreme case (i.e. every other vert is a 1-vert island),
+ * we have at most `n / 2` islands
+ * - Once we start having larger islands than that, the number required
+ * becomes much less
+ * 2) Each island gets converted to a new stroke
+ * If the number of points is <= limit, the stroke is deleted. */
+
tGPDeleteIsland *islands = (tGPDeleteIsland *)MEM_callocN(
sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands");
bool in_island = false;
@@ -3171,6 +3035,9 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
for (idx = 0; idx < num_islands; idx++) {
tGPDeleteIsland *island = &islands[idx];
new_stroke = BKE_gpencil_stroke_duplicate(gps, false, true);
+ if (flat_cap) {
+ new_stroke->caps[1 - (idx % 2)] = GP_STROKE_CAP_FLAT;
+ }
/* if cyclic and first stroke, save to join later */
if ((is_cyclic) && (gps_first == nullptr)) {
@@ -3426,7 +3293,6 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps,
}
}
-/* Join two strokes using the shortest distance (reorder stroke if necessary ) */
void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
bGPDstroke *gps_b,
const bool leave_gaps,
@@ -3544,7 +3410,7 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
for (i = start; i < end; i++) {
pt = &gps_a->points[i];
pt->pressure += (avg_pressure - pt->pressure) * ratio;
- BKE_gpencil_stroke_smooth_point(gps_a, i, ratio * 0.6f);
+ BKE_gpencil_stroke_smooth_point(gps_a, i, ratio * 0.6f, false);
ratio += step;
/* In the center, reverse the ratio. */
@@ -3556,7 +3422,6 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
}
}
-/* Copy the stroke of the frame to all frames selected (except current). */
void BKE_gpencil_stroke_copy_to_keyframes(
bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, const bool tail)
{
@@ -3595,7 +3460,11 @@ void BKE_gpencil_stroke_copy_to_keyframes(
BLI_ghash_free(frame_list, nullptr, nullptr);
}
-/* Stroke Uniform Subdivide ------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Uniform Subdivide
+ * \{ */
struct tSamplePoint {
struct tSamplePoint *next, *prev;
@@ -3615,7 +3484,7 @@ struct tSampleEdge {
/* Helper: creates a tSamplePoint from a bGPDspoint and (optionally) a MDeformVert. */
static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const MDeformVert *dvert)
{
- tSamplePoint *new_pt = (tSamplePoint *)MEM_callocN(sizeof(tSamplePoint), __func__);
+ tSamplePoint *new_pt = MEM_cnew<tSamplePoint>(__func__);
copy_v3_v3(&new_pt->x, &pt->x);
new_pt->pressure = pt->pressure;
new_pt->strength = pt->strength;
@@ -3638,22 +3507,13 @@ static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const
* the edge. */
static tSampleEdge *new_sample_edge_from_sample_points(tSamplePoint *from, tSamplePoint *to)
{
- tSampleEdge *new_edge = (tSampleEdge *)MEM_callocN(sizeof(tSampleEdge), __func__);
+ tSampleEdge *new_edge = MEM_cnew<tSampleEdge>(__func__);
new_edge->from = from;
new_edge->to = to;
new_edge->length_sq = len_squared_v3v3(&from->x, &to->x);
return new_edge;
}
-/**
- * Subdivide the grease pencil stroke so the number of points is target_number.
- * Does not change the shape of the stroke. The new points will be distributed as
- * uniformly as possible by repeatedly subdividing the current longest edge.
- *
- * \param gps: The stroke to be up-sampled.
- * \param target_number: The number of points the up-sampled stroke should have.
- * \param select: Select/Deselect the stroke.
- */
void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
bGPDstroke *gps,
const uint32_t target_number,
@@ -3703,7 +3563,7 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
tSamplePoint *sp_next = se->to;
/* Subdivide the edge. */
- tSamplePoint *new_sp = (tSamplePoint *)MEM_callocN(sizeof(tSamplePoint), __func__);
+ tSamplePoint *new_sp = MEM_cnew<tSamplePoint>(__func__);
interp_v3_v3v3(&new_sp->x, &sp->x, &sp_next->x, 0.5f);
new_sp->pressure = interpf(sp->pressure, sp_next->pressure, 0.5f);
new_sp->strength = interpf(sp->strength, sp_next->strength, 0.5f);
@@ -3789,12 +3649,6 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
BKE_gpencil_stroke_geometry_update(gpd, gps);
}
-/**
- * Stroke to view space
- * Transforms a stroke to view space. This allows for manipulations in 2D but also easy conversion
- * back to 3D.
- * NOTE: also takes care of parent space transform
- */
void BKE_gpencil_stroke_to_view_space(RegionView3D *rv3d,
bGPDstroke *gps,
const float diff_mat[4][4])
@@ -3808,12 +3662,6 @@ void BKE_gpencil_stroke_to_view_space(RegionView3D *rv3d,
}
}
-/**
- * Stroke from view space
- * Transforms a stroke from view space back to world space. Inverse of
- * BKE_gpencil_stroke_to_view_space
- * NOTE: also takes care of parent space transform
- */
void BKE_gpencil_stroke_from_view_space(RegionView3D *rv3d,
bGPDstroke *gps,
const float diff_mat[4][4])
@@ -3828,8 +3676,11 @@ void BKE_gpencil_stroke_from_view_space(RegionView3D *rv3d,
}
}
-/* ----------------------------------------------------------------------------- */
-/* Stroke to perimeter */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke to Perimeter
+ * \{ */
struct tPerimeterPoint {
struct tPerimeterPoint *next, *prev;
@@ -3838,7 +3689,7 @@ struct tPerimeterPoint {
static tPerimeterPoint *new_perimeter_point(const float pt[3])
{
- tPerimeterPoint *new_pt = (tPerimeterPoint *)MEM_callocN(sizeof(tPerimeterPoint), __func__);
+ tPerimeterPoint *new_pt = MEM_cnew<tPerimeterPoint>(__func__);
copy_v3_v3(&new_pt->x, pt);
return new_pt;
}
@@ -4007,8 +3858,8 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
float defaultpixsize = 1000.0f / gpd->pixfactor;
float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize) / 2.0f;
- ListBase *perimeter_right_side = (ListBase *)MEM_callocN(sizeof(ListBase), __func__);
- ListBase *perimeter_left_side = (ListBase *)MEM_callocN(sizeof(ListBase), __func__);
+ ListBase *perimeter_right_side = MEM_cnew<ListBase>(__func__);
+ ListBase *perimeter_left_side = MEM_cnew<ListBase>(__func__);
int num_perimeter_points = 0;
bGPDspoint *first = &gps->points[0];
@@ -4234,12 +4085,6 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
return perimeter_list;
}
-/**
- * Calculates the perimeter of a stroke projected from the view and
- * returns it as a new stroke.
- * \param subdivisions: Number of subdivisions for the start and end caps
- * \return: bGPDstroke pointer to stroke perimeter
- */
bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,
bGPdata *gpd,
const bGPDlayer *gpl,
@@ -4306,7 +4151,6 @@ bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,
return perimeter_stroke;
}
-/** Get average pressure. */
float BKE_gpencil_stroke_average_pressure_get(bGPDstroke *gps)
{
@@ -4323,7 +4167,6 @@ float BKE_gpencil_stroke_average_pressure_get(bGPDstroke *gps)
return tot / (float)gps->totpoints;
}
-/** Check if the thickness of the stroke is constant. */
bool BKE_gpencil_stroke_is_pressure_constant(bGPDstroke *gps)
{
if (gps->totpoints == 1) {
@@ -4340,4 +4183,5 @@ bool BKE_gpencil_stroke_is_pressure_constant(bGPDstroke *gps)
return true;
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index a6164340477..74db151261f 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -36,6 +36,7 @@
#include "DNA_armature_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
@@ -50,7 +51,9 @@
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_material.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
+#include "BKE_shrinkwrap.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -76,44 +79,76 @@ static GpencilVirtualModifierData virtualModifierCommonData;
* each loop over all the geometry being evaluated.
*/
-/**
- * Init grease pencil lattice deform data.
- * \param ob: Grease pencil object
- */
-void BKE_gpencil_lattice_init(Object *ob)
+void BKE_gpencil_cache_data_init(Depsgraph *depsgraph, Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
- if (md->type == eGpencilModifierType_Lattice) {
- LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
- Object *latob = NULL;
+ switch (md->type) {
+ case eGpencilModifierType_Lattice: {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ Object *latob = NULL;
+
+ latob = mmd->object;
+ if ((!latob) || (latob->type != OB_LATTICE)) {
+ return;
+ }
+ if (mmd->cache_data) {
+ BKE_lattice_deform_data_destroy(mmd->cache_data);
+ }
- latob = mmd->object;
- if ((!latob) || (latob->type != OB_LATTICE)) {
- return;
+ /* init deform data */
+ mmd->cache_data = BKE_lattice_deform_data_create(latob, ob);
+ break;
}
- if (mmd->cache_data) {
- BKE_lattice_deform_data_destroy(mmd->cache_data);
+ case eGpencilModifierType_Shrinkwrap: {
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ ob = mmd->target;
+ if (!ob) {
+ return;
+ }
+ if (mmd->cache_data) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ Object *ob_target = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
+ mmd->cache_data = MEM_callocN(sizeof(ShrinkwrapTreeData), __func__);
+ if (BKE_shrinkwrap_init_tree(
+ mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false)) {
+ }
+ else {
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ break;
}
- /* init deform data */
- mmd->cache_data = BKE_lattice_deform_data_create(latob, ob);
+ default:
+ break;
}
}
}
-/**
- * Clear grease pencil lattice deform data.
- * \param ob: Grease pencil object
- */
-void BKE_gpencil_lattice_clear(Object *ob)
+void BKE_gpencil_cache_data_clear(Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
- if (md->type == eGpencilModifierType_Lattice) {
- LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
- if ((mmd) && (mmd->cache_data)) {
- BKE_lattice_deform_data_destroy(mmd->cache_data);
- mmd->cache_data = NULL;
+ switch (md->type) {
+ case eGpencilModifierType_Lattice: {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ if ((mmd) && (mmd->cache_data)) {
+ BKE_lattice_deform_data_destroy(mmd->cache_data);
+ mmd->cache_data = NULL;
+ }
+ break;
+ }
+ case eGpencilModifierType_Shrinkwrap: {
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ if ((mmd) && (mmd->cache_data)) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ break;
}
+ default:
+ break;
}
}
}
@@ -121,8 +156,6 @@ void BKE_gpencil_lattice_clear(Object *ob)
/* *************************************************** */
/* Modifier Methods - Evaluation Loops, etc. */
-/* This is to include things that are not modifiers in the evaluation of the modifier stack, for
- * example parenting to an armature or lattice without having a real modifier. */
GpencilModifierData *BKE_gpencil_modifiers_get_virtual_modifierlist(
const Object *ob, GpencilVirtualModifierData *UNUSED(virtualModifierData))
{
@@ -150,11 +183,6 @@ GpencilModifierData *BKE_gpencil_modifiers_get_virtual_modifierlist(
return md;
}
-/**
- * Check if object has grease pencil Geometry modifiers.
- * \param ob: Grease pencil object
- * \return True if exist
- */
bool BKE_gpencil_has_geometry_modifiers(Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
@@ -167,11 +195,6 @@ bool BKE_gpencil_has_geometry_modifiers(Object *ob)
return false;
}
-/**
- * Check if object has grease pencil Time modifiers.
- * \param ob: Grease pencil object
- * \return True if exist
- */
bool BKE_gpencil_has_time_modifiers(Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
@@ -184,11 +207,6 @@ bool BKE_gpencil_has_time_modifiers(Object *ob)
return false;
}
-/**
- * Check if object has grease pencil transform stroke modifiers.
- * \param ob: Grease pencil object
- * \return True if exist
- */
bool BKE_gpencil_has_transform_modifiers(Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
@@ -258,7 +276,6 @@ bool BKE_gpencil_is_first_lineart_in_stack(const Object *ob, const GpencilModifi
return false;
}
-/* Get Time modifier frame number. */
int BKE_gpencil_time_modifier_cfra(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -292,11 +309,6 @@ int BKE_gpencil_time_modifier_cfra(Depsgraph *depsgraph,
return nfra;
}
-/**
- * Set current grease pencil active frame.
- * \param depsgraph: Current depsgraph
- * \param gpd: Grease pencil data-block.
- */
void BKE_gpencil_frame_active_set(Depsgraph *depsgraph, bGPdata *gpd)
{
DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd);
@@ -320,9 +332,6 @@ void BKE_gpencil_frame_active_set(Depsgraph *depsgraph, bGPdata *gpd)
}
}
-/**
- * Initialize grease pencil modifier.
- */
void BKE_gpencil_modifier_init(void)
{
/* Initialize modifier types */
@@ -346,11 +355,6 @@ void BKE_gpencil_modifier_init(void)
#endif
}
-/**
- * Create new grease pencil modifier.
- * \param type: Type of modifier
- * \return New modifier pointer
- */
GpencilModifierData *BKE_gpencil_modifier_new(int type)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type);
@@ -386,11 +390,6 @@ static void modifier_free_data_id_us_cb(void *UNUSED(userData),
}
}
-/**
- * Free grease pencil modifier data
- * \param md: Modifier data
- * \param flag: Flags
- */
void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
@@ -411,16 +410,11 @@ void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
MEM_freeN(md);
}
-/**
- * Free grease pencil modifier data
- * \param md: Modifier data
- */
void BKE_gpencil_modifier_free(GpencilModifierData *md)
{
BKE_gpencil_modifier_free_ex(md, 0);
}
-/* check unique name */
bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd)
{
if (modifiers && gmd) {
@@ -435,11 +429,6 @@ bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *
return false;
}
-/**
- * Check if grease pencil modifier depends on time.
- * \param md: Modifier data
- * \return True if depends on time
- */
bool BKE_gpencil_modifier_depends_ontime(GpencilModifierData *md)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
@@ -447,11 +436,6 @@ bool BKE_gpencil_modifier_depends_ontime(GpencilModifierData *md)
return mti->dependsOnTime && mti->dependsOnTime(md);
}
-/**
- * Get grease pencil modifier information.
- * \param type: Type of modifier
- * \return Pointer to type
- */
const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type)
{
/* type unsigned, no need to check < 0 */
@@ -463,12 +447,6 @@ const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType
return NULL;
}
-/**
- * Get the idname of the modifier type's panel, which was defined in the #panelRegister callback.
- *
- * \param type: Type of modifier
- * \param r_idname: ID name
- */
void BKE_gpencil_modifierType_panel_id(GpencilModifierType type, char *r_idname)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type);
@@ -482,11 +460,6 @@ void BKE_gpencil_modifier_panel_expand(GpencilModifierData *md)
md->ui_expand_flag |= UI_PANEL_DATA_EXPAND_ROOT;
}
-/**
- * Generic grease pencil modifier copy data.
- * \param md_src: Source modifier data
- * \param md_dst: Target modifier data
- */
void BKE_gpencil_modifier_copydata_generic(const GpencilModifierData *md_src,
GpencilModifierData *md_dst)
{
@@ -516,12 +489,6 @@ static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData),
}
}
-/**
- * Copy grease pencil modifier data.
- * \param md: Source modifier data
- * \param target: Target modifier data
- * \param flag: Flags
- */
void BKE_gpencil_modifier_copydata_ex(GpencilModifierData *md,
GpencilModifierData *target,
const int flag)
@@ -543,11 +510,6 @@ void BKE_gpencil_modifier_copydata_ex(GpencilModifierData *md,
}
}
-/**
- * Copy grease pencil modifier data.
- * \param md: Source modifier data
- * \param target: Target modifier data
- */
void BKE_gpencil_modifier_copydata(GpencilModifierData *md, GpencilModifierData *target)
{
BKE_gpencil_modifier_copydata_ex(md, target, 0);
@@ -566,19 +528,14 @@ GpencilModifierData *BKE_gpencil_modifiers_findby_type(Object *ob, GpencilModifi
return md;
}
-/**
- * Set grease pencil modifier error.
- * \param md: Modifier data
- * \param _format: Format
- */
-void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *_format, ...)
+void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *format, ...)
{
char buffer[512];
va_list ap;
- const char *format = TIP_(_format);
+ const char *format_tip = TIP_(format);
- va_start(ap, _format);
- vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_start(ap, format);
+ vsnprintf(buffer, sizeof(buffer), format_tip, ap);
va_end(ap);
buffer[sizeof(buffer) - 1] = '\0';
@@ -591,12 +548,6 @@ void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *_format
CLOG_STR_ERROR(&LOG, md->error);
}
-/**
- * Check whether given modifier is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param gmd: May be NULL, in which case we consider it as a non-local modifier case.
- */
bool BKE_gpencil_modifier_is_nonlocal_in_liboverride(const Object *ob,
const GpencilModifierData *gmd)
{
@@ -604,12 +555,6 @@ bool BKE_gpencil_modifier_is_nonlocal_in_liboverride(const Object *ob,
(gmd == NULL || (gmd->flag & eGpencilModifierFlag_OverrideLibrary_Local) == 0));
}
-/**
- * Link grease pencil modifier related IDs.
- * \param ob: Grease pencil object
- * \param walk: Walk option
- * \param userData: User data
- */
void BKE_gpencil_modifiers_foreach_ID_link(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
{
GpencilModifierData *md = ob->greasepencil_modifiers.first;
@@ -623,12 +568,6 @@ void BKE_gpencil_modifiers_foreach_ID_link(Object *ob, GreasePencilIDWalkFunc wa
}
}
-/**
- * Link grease pencil modifier related Texts.
- * \param ob: Grease pencil object
- * \param walk: Walk option
- * \param userData: User data
- */
void BKE_gpencil_modifiers_foreach_tex_link(Object *ob,
GreasePencilTexWalkFunc walk,
void *userData)
@@ -644,12 +583,6 @@ void BKE_gpencil_modifiers_foreach_tex_link(Object *ob,
}
}
-/**
- * Find grease pencil modifier by name.
- * \param ob: Grease pencil object
- * \param name: Name to find
- * \return Pointer to modifier
- */
GpencilModifierData *BKE_gpencil_modifiers_findby_name(Object *ob, const char *name)
{
return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name));
@@ -677,14 +610,6 @@ static int gpencil_remap_time_get(Depsgraph *depsgraph, Scene *scene, Object *ob
return remap_cfra;
}
-/**
- * Get the current frame re-timed with time modifiers.
- * \param depsgraph: Current depsgraph.
- * \param scene: Current scene
- * \param ob: Grease pencil object
- * \param gpl: Grease pencil layer
- * \return New frame number
- */
bGPDframe *BKE_gpencil_frame_retime_get(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -753,12 +678,6 @@ static bGPdata *gpencil_copy_for_eval(bGPdata *gpd)
return result;
}
-/**
- * Prepare grease pencil eval data for modifiers
- * \param depsgraph: Current depsgraph
- * \param scene: Current scene
- * \param ob: Grease pencil object
- */
void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
bGPdata *gpd_eval = (bGPdata *)ob->data;
@@ -808,12 +727,6 @@ void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *o
BKE_gpencil_update_orig_pointers(ob_orig, ob);
}
-/**
- * Calculate gpencil modifiers.
- * \param depsgraph: Current depsgraph
- * \param scene: Current scene
- * \param ob: Grease pencil object
- */
void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -829,7 +742,7 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
}
/* Init general modifiers data. */
- BKE_gpencil_lattice_init(ob);
+ BKE_gpencil_cache_data_init(depsgraph, ob);
const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
bool is_first_lineart = true;
@@ -872,8 +785,8 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
}
}
- /* Clear any lattice data. */
- BKE_gpencil_lattice_clear(ob);
+ /* Clear any cache data. */
+ BKE_gpencil_cache_data_clear(ob);
MOD_lineart_clear_cache(&gpd->runtime.lineart_cache);
}
@@ -1031,6 +944,10 @@ void BKE_gpencil_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb)
gpmd->segments[i].dmd = gpmd;
}
}
+ if (md->type == eGpencilModifierType_Shrinkwrap) {
+ ShrinkwrapGpencilModifierData *gpmd = (ShrinkwrapGpencilModifierData *)md;
+ gpmd->cache_data = NULL;
+ }
}
}
diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.cc
index cf346e9cac7..b7ba159f631 100644
--- a/source/blender/blenkernel/intern/hair.c
+++ b/source/blender/blenkernel/intern/hair.cc
@@ -18,6 +18,9 @@
* \ingroup bke
*/
+#include <cmath>
+#include <cstring>
+
#include "MEM_guardedalloc.h"
#include "DNA_defaults.h"
@@ -26,7 +29,8 @@
#include "DNA_object_types.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_base.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_rand.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -49,6 +53,8 @@
#include "BLO_read_write.h"
+using blender::float3;
+
static const char *HAIR_ATTR_POSITION = "position";
static const char *HAIR_ATTR_RADIUS = "radius";
@@ -67,10 +73,10 @@ static void hair_init_data(ID *id)
CustomData_reset(&hair->cdata);
CustomData_add_layer_named(
- &hair->pdata, CD_PROP_FLOAT3, CD_CALLOC, NULL, hair->totpoint, HAIR_ATTR_POSITION);
+ &hair->pdata, CD_PROP_FLOAT3, CD_CALLOC, nullptr, hair->totpoint, HAIR_ATTR_POSITION);
CustomData_add_layer_named(
- &hair->pdata, CD_PROP_FLOAT, CD_CALLOC, NULL, hair->totpoint, HAIR_ATTR_RADIUS);
- CustomData_add_layer(&hair->cdata, CD_HAIRCURVE, CD_CALLOC, NULL, hair->totcurve);
+ &hair->pdata, CD_PROP_FLOAT, CD_CALLOC, nullptr, hair->totpoint, HAIR_ATTR_RADIUS);
+ CustomData_add_layer(&hair->cdata, CD_HAIRCURVE, CD_CALLOC, nullptr, hair->totcurve);
BKE_hair_update_customdata_pointers(hair);
hair_random(hair);
@@ -80,14 +86,14 @@ static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, co
{
Hair *hair_dst = (Hair *)id_dst;
const Hair *hair_src = (const Hair *)id_src;
- hair_dst->mat = MEM_dupallocN(hair_dst->mat);
+ hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat));
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
CustomData_copy(&hair_src->pdata, &hair_dst->pdata, CD_MASK_ALL, alloc_type, hair_dst->totpoint);
CustomData_copy(&hair_src->cdata, &hair_dst->cdata, CD_MASK_ALL, alloc_type, hair_dst->totcurve);
BKE_hair_update_customdata_pointers(hair_dst);
- hair_dst->batch_cache = NULL;
+ hair_dst->batch_cache = nullptr;
}
static void hair_free_data(ID *id)
@@ -107,7 +113,7 @@ static void hair_foreach_id(ID *id, LibraryForeachIDData *data)
{
Hair *hair = (Hair *)id;
for (int i = 0; i < hair->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, hair->mat[i], IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, hair->mat[i], IDWALK_CB_USER);
}
}
@@ -115,8 +121,8 @@ static void hair_blend_write(BlendWriter *writer, ID *id, const void *id_address
{
Hair *hair = (Hair *)id;
- CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *clayers = NULL, clayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *clayers = nullptr, clayers_buff[CD_TEMP_CHUNK_SIZE];
CustomData_blend_write_prepare(&hair->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
CustomData_blend_write_prepare(&hair->cdata, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff));
@@ -174,31 +180,33 @@ static void hair_blend_read_expand(BlendExpander *expander, ID *id)
}
IDTypeInfo IDType_ID_HA = {
- .id_code = ID_HA,
- .id_filter = FILTER_ID_HA,
- .main_listbase_index = INDEX_ID_HA,
- .struct_size = sizeof(Hair),
- .name = "Hair",
- .name_plural = "hairs",
- .translation_context = BLT_I18NCONTEXT_ID_HAIR,
- .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
-
- .init_data = hair_init_data,
- .copy_data = hair_copy_data,
- .free_data = hair_free_data,
- .make_local = NULL,
- .foreach_id = hair_foreach_id,
- .foreach_cache = NULL,
- .owner_get = NULL,
-
- .blend_write = hair_blend_write,
- .blend_read_data = hair_blend_read_data,
- .blend_read_lib = hair_blend_read_lib,
- .blend_read_expand = hair_blend_read_expand,
-
- .blend_read_undo_preserve = NULL,
-
- .lib_override_apply_post = NULL,
+ /*id_code */ ID_HA,
+ /*id_filter */ FILTER_ID_HA,
+ /*main_listbase_index */ INDEX_ID_HA,
+ /*struct_size */ sizeof(Hair),
+ /*name */ "Hair",
+ /*name_plural */ "hairs",
+ /*translation_context */ BLT_I18NCONTEXT_ID_HAIR,
+ /*flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /*asset_type_info */ nullptr,
+
+ /*init_data */ hair_init_data,
+ /*copy_data */ hair_copy_data,
+ /*free_data */ hair_free_data,
+ /*make_local */ nullptr,
+ /*foreach_id */ hair_foreach_id,
+ /*foreach_cache */ nullptr,
+ /*foreach_path */ nullptr,
+ /*owner_get */ nullptr,
+
+ /*blend_write */ hair_blend_write,
+ /*blend_read_data */ hair_blend_read_data,
+ /*blend_read_lib */ hair_blend_read_lib,
+ /*blend_read_expand */ hair_blend_read_expand,
+
+ /*blend_read_undo_preserve */ nullptr,
+
+ /*lib_override_apply_post */ nullptr,
};
static void hair_random(Hair *hair)
@@ -248,7 +256,7 @@ static void hair_random(Hair *hair)
void *BKE_hair_add(Main *bmain, const char *name)
{
- Hair *hair = BKE_id_new(bmain, ID_HA, name);
+ Hair *hair = static_cast<Hair *>(BKE_id_new(bmain, ID_HA, name));
return hair;
}
@@ -256,14 +264,14 @@ void *BKE_hair_add(Main *bmain, const char *name)
BoundBox *BKE_hair_boundbox_get(Object *ob)
{
BLI_assert(ob->type == OB_HAIR);
- Hair *hair = ob->data;
+ Hair *hair = static_cast<Hair *>(ob->data);
- if (ob->runtime.bb != NULL && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
+ if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
return ob->runtime.bb;
}
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "hair boundbox");
+ if (ob->runtime.bb == nullptr) {
+ ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
float min[3], max[3];
INIT_MINMAX(min, max);
@@ -287,10 +295,12 @@ BoundBox *BKE_hair_boundbox_get(Object *ob)
void BKE_hair_update_customdata_pointers(Hair *hair)
{
- hair->co = CustomData_get_layer_named(&hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION);
- hair->radius = CustomData_get_layer_named(&hair->pdata, CD_PROP_FLOAT, HAIR_ATTR_RADIUS);
- hair->curves = CustomData_get_layer(&hair->cdata, CD_HAIRCURVE);
- hair->mapping = CustomData_get_layer(&hair->cdata, CD_HAIRMAPPING);
+ hair->co = (float(*)[3])CustomData_get_layer_named(
+ &hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION);
+ hair->radius = (float *)CustomData_get_layer_named(
+ &hair->pdata, CD_PROP_FLOAT, HAIR_ATTR_RADIUS);
+ hair->curves = (HairCurve *)CustomData_get_layer(&hair->cdata, CD_HAIRCURVE);
+ hair->mapping = (HairMaping *)CustomData_get_layer(&hair->cdata, CD_HAIRMAPPING);
}
bool BKE_hair_customdata_required(Hair *UNUSED(hair), CustomDataLayer *layer)
@@ -302,10 +312,10 @@ bool BKE_hair_customdata_required(Hair *UNUSED(hair), CustomDataLayer *layer)
Hair *BKE_hair_new_for_eval(const Hair *hair_src, int totpoint, int totcurve)
{
- Hair *hair_dst = BKE_id_new_nomain(ID_HA, NULL);
+ Hair *hair_dst = static_cast<Hair *>(BKE_id_new_nomain(ID_HA, nullptr));
STRNCPY(hair_dst->id.name, hair_src->id.name);
- hair_dst->mat = MEM_dupallocN(hair_src->mat);
+ hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat));
hair_dst->totcol = hair_src->totcol;
hair_dst->totpoint = totpoint;
@@ -325,7 +335,7 @@ Hair *BKE_hair_copy_for_eval(Hair *hair_src, bool reference)
flags |= LIB_ID_COPY_CD_REFERENCE;
}
- Hair *result = (Hair *)BKE_id_copy_ex(NULL, &hair_src->id, NULL, flags);
+ Hair *result = (Hair *)BKE_id_copy_ex(nullptr, &hair_src->id, nullptr, flags);
return result;
}
@@ -349,7 +359,7 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
/* Evaluate modifiers. */
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(static_cast<ModifierType>(md->type));
if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
@@ -368,7 +378,7 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
BKE_hair_update_customdata_pointers(hair);
/* Created deformed coordinates array on demand. */
- mti->deformVerts(md, &mectx, NULL, hair->co, hair->totpoint);
+ mti->deformVerts(md, &mectx, nullptr, hair->co, hair->totpoint);
}
else if (mti->modifyHair) {
/* Ensure we are not modifying the input. */
@@ -381,7 +391,7 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
if (hair_next && hair_next != hair) {
/* If the modifier returned a new hair, release the old one. */
if (hair != hair_input) {
- BKE_id_free(NULL, hair);
+ BKE_id_free(nullptr, hair);
}
hair = hair_next;
}
@@ -397,7 +407,7 @@ void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Obje
BKE_object_free_derived_caches(object);
/* Evaluate modifiers. */
- Hair *hair = object->data;
+ Hair *hair = static_cast<Hair *>(object->data);
Hair *hair_eval = hair_evaluate_modifiers(depsgraph, scene, object, hair);
/* Assign evaluated object. */
@@ -406,8 +416,9 @@ void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Obje
}
/* Draw Cache */
-void (*BKE_hair_batch_cache_dirty_tag_cb)(Hair *hair, int mode) = NULL;
-void (*BKE_hair_batch_cache_free_cb)(Hair *hair) = NULL;
+
+void (*BKE_hair_batch_cache_dirty_tag_cb)(Hair *hair, int mode) = nullptr;
+void (*BKE_hair_batch_cache_free_cb)(Hair *hair) = nullptr;
void BKE_hair_batch_cache_dirty_tag(Hair *hair, int mode)
{
diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc
index 97c742b1ec1..059caaa27f9 100644
--- a/source/blender/blenkernel/intern/icons.cc
+++ b/source/blender/blenkernel/intern/icons.cc
@@ -35,6 +35,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_light_types.h"
#include "DNA_material_types.h"
+#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -209,7 +210,7 @@ void BKE_icons_init(int first_dyn_id)
}
}
-void BKE_icons_free(void)
+void BKE_icons_free()
{
BLI_assert(BLI_thread_is_main());
@@ -226,7 +227,7 @@ void BKE_icons_free(void)
BLI_linklist_lockfree_free(&g_icon_delete_queue, MEM_freeN);
}
-void BKE_icons_deferred_free(void)
+void BKE_icons_deferred_free()
{
std::scoped_lock lock(gIconMutex);
@@ -250,7 +251,7 @@ static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
}
for (int i = 0; i < NUM_ICON_SIZES; i++) {
- prv_img->flag[i] |= (PRV_CHANGED | PRV_UNFINISHED);
+ prv_img->flag[i] |= PRV_CHANGED;
prv_img->changed_timestamp[i] = 0;
}
return prv_img;
@@ -270,7 +271,7 @@ static PreviewImage *previewimg_deferred_create(const char *path, int source)
return prv;
}
-PreviewImage *BKE_previewimg_create(void)
+PreviewImage *BKE_previewimg_create()
{
return previewimg_create_ex(0);
}
@@ -307,7 +308,7 @@ void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
GPU_texture_free(prv->gputexture[size]);
}
prv->h[size] = prv->w[size] = 0;
- prv->flag[size] |= (PRV_CHANGED | PRV_UNFINISHED);
+ prv->flag[size] |= PRV_CHANGED;
prv->flag[size] &= ~PRV_USER_EDITED;
prv->changed_timestamp[size] = 0;
}
@@ -335,10 +336,6 @@ PreviewImage *BKE_previewimg_copy(const PreviewImage *prv)
return prv_img;
}
-/**
- * Duplicate preview image from \a id and clear icon_id,
- * to be used by datablock copy functions.
- */
void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
{
PreviewImage **old_prv_p = BKE_previewimg_id_get_p(old_id);
@@ -364,17 +361,18 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id)
return &((id_struct *)id)->preview; \
} \
((void)0)
+ ID_PRV_CASE(ID_OB, Object);
ID_PRV_CASE(ID_MA, Material);
ID_PRV_CASE(ID_TE, Tex);
ID_PRV_CASE(ID_WO, World);
ID_PRV_CASE(ID_LA, Light);
ID_PRV_CASE(ID_IM, Image);
ID_PRV_CASE(ID_BR, Brush);
- ID_PRV_CASE(ID_OB, Object);
ID_PRV_CASE(ID_GR, Collection);
ID_PRV_CASE(ID_SCE, Scene);
ID_PRV_CASE(ID_SCR, bScreen);
ID_PRV_CASE(ID_AC, bAction);
+ ID_PRV_CASE(ID_NT, bNodeTree);
#undef ID_PRV_CASE
default:
break;
@@ -458,9 +456,6 @@ PreviewImage *BKE_previewimg_cached_get(const char *name)
return (PreviewImage *)BLI_ghash_lookup(gCachedPreviews, name);
}
-/**
- * Generate an empty PreviewImage, if not yet existing.
- */
PreviewImage *BKE_previewimg_cached_ensure(const char *name)
{
BLI_assert(BLI_thread_is_main());
@@ -478,10 +473,6 @@ PreviewImage *BKE_previewimg_cached_ensure(const char *name)
return prv;
}
-/**
- * Generate a PreviewImage from given file path, using thumbnails management, if not yet existing.
- * Does not actually generate the preview, #BKE_previewimg_ensure() must be called for that.
- */
PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
const char *path,
const int source,
@@ -536,10 +527,6 @@ void BKE_previewimg_cached_release(const char *name)
BKE_previewimg_deferred_release(prv);
}
-/**
- * Handle deferred (lazy) loading/generation of preview image, if needed.
- * For now, only used with file thumbnails.
- */
void BKE_previewimg_ensure(PreviewImage *prv, const int size)
{
if ((prv->tag & PRV_TAG_DEFFERED) != 0) {
@@ -563,7 +550,7 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
prv->w[ICON_SIZE_PREVIEW] = thumb->x;
prv->h[ICON_SIZE_PREVIEW] = thumb->y;
prv->rect[ICON_SIZE_PREVIEW] = (uint *)MEM_dupallocN(thumb->rect);
- prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_UNFINISHED);
+ prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_RENDERING);
}
if (do_icon) {
if (thumb->x > thumb->y) {
@@ -582,7 +569,7 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
prv->w[ICON_SIZE_ICON] = icon_w;
prv->h[ICON_SIZE_ICON] = icon_h;
prv->rect[ICON_SIZE_ICON] = (uint *)MEM_dupallocN(thumb->rect);
- prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_UNFINISHED);
+ prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_RENDERING);
}
IMB_freeImBuf(thumb);
}
@@ -590,10 +577,6 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
}
}
-/**
- * Create an #ImBuf holding a copy of the preview image buffer in \a prv.
- * \note The returned image buffer has to be free'd (#IMB_freeImBuf()).
- */
ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, const int size)
{
const unsigned int w = prv->w[size];
@@ -614,12 +597,12 @@ ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, const int size)
void BKE_previewimg_finish(PreviewImage *prv, const int size)
{
/* Previews may be calculated on a thread. */
- atomic_fetch_and_and_int16(&prv->flag[size], ~PRV_UNFINISHED);
+ atomic_fetch_and_and_int16(&prv->flag[size], ~PRV_RENDERING);
}
bool BKE_previewimg_is_finished(const PreviewImage *prv, const int size)
{
- return (prv->flag[size] & PRV_UNFINISHED) == 0;
+ return (prv->flag[size] & PRV_RENDERING) == 0;
}
void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
@@ -653,16 +636,11 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
BLO_read_data_address(reader, &prv->rect[i]);
}
prv->gputexture[i] = nullptr;
- /* For now consider previews read from file as finished to not confuse File Browser preview
- * loading. That could be smarter and check if there's a preview job running instead.
- * If the preview is tagged as changed, it needs to be updated anyway, so don't remove the tag.
- */
- if ((prv->flag[i] & PRV_CHANGED) == 0) {
- BKE_previewimg_finish(prv, i);
- }
- else {
- /* Only for old files that didn't write the flag. */
- prv->flag[i] |= PRV_UNFINISHED;
+
+ /* PRV_RENDERING is a runtime only flag currently, but don't mess with it on undo! It gets
+ * special handling in #memfile_undosys_restart_unfinished_id_previews() then. */
+ if (!BLO_read_data_is_undo(reader)) {
+ prv->flag[i] &= ~PRV_RENDERING;
}
}
prv->icon_id = 0;
@@ -692,7 +670,7 @@ void BKE_icon_changed(const int icon_id)
/* If we have previews, they all are now invalid changed. */
if (p_prv && *p_prv) {
for (int i = 0; i < NUM_ICON_SIZES; i++) {
- (*p_prv)->flag[i] |= (PRV_CHANGED | PRV_UNFINISHED);
+ (*p_prv)->flag[i] |= PRV_CHANGED;
(*p_prv)->changed_timestamp[i]++;
}
}
@@ -799,9 +777,6 @@ int BKE_icon_gplayer_color_ensure(bGPDlayer *gpl)
return icon_gplayer_color_ensure_create_icon(gpl);
}
-/**
- * Return icon id of given preview, or create new icon if not found.
- */
int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
{
if (!preview || G.background) {
@@ -842,11 +817,6 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
return preview->icon_id;
}
-/**
- * Create an icon as owner or \a ibuf. The icon-ID is not stored in \a ibuf, it needs to be stored
- * separately.
- * \note Transforms ownership of \a ibuf to the newly created icon.
- */
int BKE_icon_imbuf_create(ImBuf *ibuf)
{
int icon_id = get_next_free_id();
@@ -928,9 +898,6 @@ void BKE_icon_id_delete(struct ID *id)
BLI_ghash_remove(gIcons, POINTER_FROM_INT(icon_id), nullptr, icon_free);
}
-/**
- * Remove icon and free data.
- */
bool BKE_icon_delete(const int icon_id)
{
if (icon_id == 0) {
@@ -1055,4 +1022,5 @@ int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type)
icon->id_type = id_type;
return icon_id;
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index f7411f541b7..bb6458331da 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -76,10 +76,6 @@ static size_t idp_size_table[] = {
/* --------- property array type -------------*/
-/**
- * \note as a start to move away from the stupid IDP_New function, this type
- * has its own allocation function.
- */
IDProperty *IDP_NewIDPArray(const char *name)
{
IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty prop array");
@@ -127,7 +123,6 @@ static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
}
}
-/* shallow copies item */
void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
{
BLI_assert(prop->type == IDP_IDPARRAY);
@@ -229,7 +224,6 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
}
}
-/* This function works for strings too! */
void IDP_ResizeArray(IDProperty *prop, int newlen)
{
const bool is_grow = newlen >= prop->len;
@@ -351,19 +345,13 @@ static IDProperty *IDP_CopyArray(const IDProperty *prop, const int flag)
return newp;
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name String Functions (IDProperty String API)
* \{ */
-/**
- *
- * \param st: The string to assign.
- * \param name: The property name.
- * \param maxlen: The size of the new string (including the \0 terminator).
- * \return The new string property.
- */
IDProperty *IDP_NewString(const char *st, const char *name, int maxlen)
{
IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
@@ -457,6 +445,7 @@ void IDP_FreeString(IDProperty *prop)
MEM_freeN(prop->data.pointer);
}
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -514,8 +503,6 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
return newp;
}
-/* use for syncing proxies.
- * When values name and types match, copy the values, else ignore */
void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
{
BLI_assert(dest->type == IDP_GROUP);
@@ -565,9 +552,6 @@ void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_a
}
}
-/**
- * Replaces all properties with the same name in a destination group from a source group.
- */
void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
{
BLI_assert(dest->type == IDP_GROUP);
@@ -592,10 +576,6 @@ void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
}
}
-/**
- * Checks if a property with the same name as prop exists, and if so replaces it.
- * Use this to preserve order!
- */
void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop_exist)
{
BLI_assert(group->type == IDP_GROUP);
@@ -618,10 +598,6 @@ void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
IDP_ReplaceInGroup_ex(group, prop, prop_exist);
}
-/**
- * If a property is missing in \a dest, add it.
- * Do it recursively.
- */
void IDP_MergeGroup_ex(IDProperty *dest,
const IDProperty *src,
const bool do_overwrite,
@@ -663,25 +639,11 @@ void IDP_MergeGroup_ex(IDProperty *dest,
}
}
-/**
- * If a property is missing in \a dest, add it.
- * Do it recursively.
- */
void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
{
IDP_MergeGroup_ex(dest, src, do_overwrite, 0);
}
-/**
- * This function has a sanity check to make sure ID properties with the same name don't
- * get added to the group.
- *
- * The sanity check just means the property is not added to the group if another property
- * exists with the same name; the client code using ID properties then needs to detect this
- * (the function that adds new properties to groups, #IDP_AddToGroup,
- * returns false if a property can't be added to the group, and true if it can)
- * and free the property.
- */
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop)
{
BLI_assert(group->type == IDP_GROUP);
@@ -695,10 +657,6 @@ bool IDP_AddToGroup(IDProperty *group, IDProperty *prop)
return false;
}
-/**
- * This is the same as IDP_AddToGroup, only you pass an item
- * in the group list to be inserted after.
- */
bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
{
BLI_assert(group->type == IDP_GROUP);
@@ -712,12 +670,6 @@ bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew
return false;
}
-/**
- * \note this does not free the property!!
- *
- * To free the property, you have to do:
- * IDP_FreeProperty(prop);
- */
void IDP_RemoveFromGroup(IDProperty *group, IDProperty *prop)
{
BLI_assert(group->type == IDP_GROUP);
@@ -727,9 +679,6 @@ void IDP_RemoveFromGroup(IDProperty *group, IDProperty *prop)
BLI_remlink(&group->data.group, prop);
}
-/**
- * Removes the property from the group and frees it.
- */
void IDP_FreeFromGroup(IDProperty *group, IDProperty *prop)
{
IDP_RemoveFromGroup(group, prop);
@@ -742,7 +691,6 @@ IDProperty *IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name)
return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name));
}
-/** same as above but ensure type match */
IDProperty *IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *name, const char type)
{
IDProperty *idprop = IDP_GetPropertyFromGroup(prop, name);
@@ -762,16 +710,13 @@ static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
}
BLI_freelistN(&prop->data.group);
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Main Functions (IDProperty Main API)
* \{ */
-/**
- * Return an int from an IDProperty with a compatible type. This should be avoided, but
- * it's sometimes necessary, for example when legacy files have incorrect property types.
- */
int IDP_coerce_to_int_or_zero(const IDProperty *prop)
{
switch (prop->type) {
@@ -786,10 +731,6 @@ int IDP_coerce_to_int_or_zero(const IDProperty *prop)
}
}
-/**
- * Return a double from an IDProperty with a compatible type. This should be avoided, but
- * it's sometimes necessary, for example when legacy files have incorrect property types.
- */
double IDP_coerce_to_double_or_zero(const IDProperty *prop)
{
switch (prop->type) {
@@ -804,10 +745,6 @@ double IDP_coerce_to_double_or_zero(const IDProperty *prop)
}
}
-/**
- * Return a float from an IDProperty with a compatible type. This should be avoided, but
- * it's sometimes necessary, for example when legacy files have incorrect property types.
- */
float IDP_coerce_to_float_or_zero(const IDProperty *prop)
{
switch (prop->type) {
@@ -845,10 +782,6 @@ IDProperty *IDP_CopyProperty(const IDProperty *prop)
return IDP_CopyProperty_ex(prop, 0);
}
-/**
- * Copy content from source IDProperty into destination one, freeing destination property's content
- * first.
- */
void IDP_CopyPropertyContent(IDProperty *dst, IDProperty *src)
{
IDProperty *idprop_tmp = IDP_CopyProperty(src);
@@ -858,11 +791,6 @@ void IDP_CopyPropertyContent(IDProperty *dst, IDProperty *src)
IDP_FreeProperty(idprop_tmp);
}
-/**
- * Get the Group property that contains the id properties for ID id. Set create_if_needed
- * to create the Group property and attach it to id if it doesn't exist; otherwise
- * the function will return NULL if there's no Group property attached to the ID.
- */
IDProperty *IDP_GetProperties(ID *id, const bool create_if_needed)
{
if (id->properties) {
@@ -880,8 +808,6 @@ IDProperty *IDP_GetProperties(ID *id, const bool create_if_needed)
return id->properties;
}
-/**
- * \param is_strict: When false treat missing items as a match */
bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is_strict)
{
if (prop1 == NULL && prop2 == NULL) {
@@ -974,33 +900,6 @@ bool IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
return IDP_EqualsProperties_ex(prop1, prop2, true);
}
-/**
- * Allocate a new ID.
- *
- * This function takes three arguments: the ID property type, a union which defines
- * its initial value, and a name.
- *
- * The union is simple to use; see the top of BKE_idprop.h for its definition.
- * An example of using this function:
- *
- * \code{.c}
- * IDPropertyTemplate val;
- * IDProperty *group, *idgroup, *color;
- * group = IDP_New(IDP_GROUP, val, "group1"); // groups don't need a template.
- *
- * val.array.len = 4
- * val.array.type = IDP_FLOAT;
- * color = IDP_New(IDP_ARRAY, val, "color1");
- *
- * idgroup = IDP_GetProperties(some_id, 1);
- * IDP_AddToGroup(idgroup, color);
- * IDP_AddToGroup(idgroup, group);
- * \endcode
- *
- * Note that you MUST either attach the id property to an id property group with
- * IDP_AddToGroup or MEM_freeN the property, doing anything else might result in
- * a memory leak.
- */
IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *name)
{
IDProperty *prop = NULL;
@@ -1096,11 +995,6 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
return prop;
}
-/**
- * Free allocated pointers in the UI data that isn't shared with the UI data in the #other
- * argument. Useful for returning early on failure when updating UI data in place, or when
- * replacing a subset of the UI data's allocated pointers.
- */
void IDP_ui_data_free_unique_contents(IDPropertyUIData *ui_data,
const eIDPropertyUIDataType type,
const IDPropertyUIData *other)
@@ -1175,10 +1069,6 @@ void IDP_ui_data_free(IDProperty *prop)
prop->ui_data = NULL;
}
-/**
- * \note This will free allocated data, all child properties of arrays and groups, and unlink IDs!
- * But it does not free the actual IDProperty struct itself.
- */
void IDP_FreePropertyContent_ex(IDProperty *prop, const bool do_id_user)
{
switch (prop->type) {
@@ -1241,14 +1131,6 @@ void IDP_Reset(IDProperty *prop, const IDProperty *reference)
}
}
-/**
- * Loop through all ID properties in hierarchy of given \a id_property_root included.
- *
- * \note Container types (groups and arrays) are processed after applying the callback on them.
- *
- * \param type_filter: If not 0, only apply callback on properties of matching types, see
- * IDP_TYPE_FILTER_ enum in DNA_ID.h.
- */
void IDP_foreach_property(IDProperty *id_property_root,
const int type_filter,
IDPForeachPropertyCallback callback,
diff --git a/source/blender/blenkernel/intern/idprop_create.cc b/source/blender/blenkernel/intern/idprop_create.cc
new file mode 100644
index 00000000000..12f2fdc6a63
--- /dev/null
+++ b/source/blender/blenkernel/intern/idprop_create.cc
@@ -0,0 +1,140 @@
+/*
+ * 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) 2021 by Blender Foundation.
+ */
+
+#include <type_traits>
+
+#include "DNA_ID.h"
+
+#include "BKE_idprop.hh"
+
+namespace blender::bke::idprop {
+
+/* -------------------------------------------------------------------- */
+/** \name Create Functions
+ * \{ */
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name, int32_t value)
+{
+ IDPropertyTemplate prop_template{0};
+ prop_template.i = value;
+ IDProperty *property = IDP_New(IDP_INT, &prop_template, prop_name.c_str());
+ return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
+}
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name, float value)
+{
+ IDPropertyTemplate prop_template{0};
+ prop_template.f = value;
+ IDProperty *property = IDP_New(IDP_FLOAT, &prop_template, prop_name.c_str());
+ return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
+}
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name, double value)
+{
+ IDPropertyTemplate prop_template{0};
+ prop_template.d = value;
+ IDProperty *property = IDP_New(IDP_DOUBLE, &prop_template, prop_name.c_str());
+ return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
+}
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name,
+ const StringRefNull value)
+{
+ IDProperty *property = IDP_NewString(value.c_str(), prop_name.c_str(), value.size() + 1);
+ return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
+}
+
+static std::unique_ptr<IDProperty, IDPropertyDeleter> array_create(const StringRefNull prop_name,
+ eIDPropertyType subtype,
+ size_t array_len)
+{
+ IDPropertyTemplate prop_template{0};
+ prop_template.array.len = array_len;
+ prop_template.array.type = subtype;
+ IDProperty *property = IDP_New(IDP_ARRAY, &prop_template, prop_name.c_str());
+ return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
+}
+
+static void array_values_set(IDProperty *property,
+ const void *values,
+ size_t values_len,
+ size_t value_size)
+{
+ BLI_assert(values);
+ BLI_assert(property->len == values_len);
+ memcpy(IDP_Array(property), values, values_len * value_size);
+}
+
+/**
+ * Create a IDProperty array of `id_property_subtype` and fill it with the given values.
+ */
+template<
+ /** C-Primitive type of the array. Can be int32_t, float, double. */
+ typename PrimitiveType,
+ /** Subtype of the ID_ARRAY. Must match PrimitiveType. */
+ eIDPropertyType id_property_subtype>
+std::unique_ptr<IDProperty, IDPropertyDeleter> create_array(StringRefNull prop_name,
+ Span<PrimitiveType> values)
+{
+ static_assert(std::is_same_v<PrimitiveType, int32_t> || std::is_same_v<PrimitiveType, float_t> ||
+ std::is_same_v<PrimitiveType, double>,
+ "Allowed values for PrimitiveType are int32_t, float and double.");
+ static_assert(!std::is_same_v<PrimitiveType, int32_t> || id_property_subtype == IDP_INT,
+ "PrimitiveType and id_property_type do not match (int32_t).");
+ static_assert(!std::is_same_v<PrimitiveType, float> || id_property_subtype == IDP_FLOAT,
+ "PrimitiveType and id_property_type do not match (float).");
+ static_assert(!std::is_same_v<PrimitiveType, double> || id_property_subtype == IDP_DOUBLE,
+ "PrimitiveType and id_property_type do not match (double).");
+
+ const int64_t values_len = values.size();
+ BLI_assert(values_len > 0);
+ std::unique_ptr<IDProperty, IDPropertyDeleter> property = array_create(
+ prop_name.c_str(), id_property_subtype, values_len);
+ array_values_set(
+ property.get(), static_cast<const void *>(values.data()), values_len, sizeof(PrimitiveType));
+ return property;
+}
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name,
+ Span<int32_t> values)
+{
+ return create_array<int32_t, IDP_INT>(prop_name, values);
+}
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name,
+ Span<float> values)
+{
+ return create_array<float, IDP_FLOAT>(prop_name, values);
+}
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name,
+ Span<double> values)
+{
+ return create_array<double, IDP_DOUBLE>(prop_name, values);
+}
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create_group(const StringRefNull prop_name)
+{
+ IDPropertyTemplate prop_template{0};
+ IDProperty *property = IDP_New(IDP_GROUP, &prop_template, prop_name.c_str());
+ return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
+}
+
+/* \} */
+
+} // namespace blender::bke::idprop
diff --git a/source/blender/blenkernel/intern/idprop_serialize.cc b/source/blender/blenkernel/intern/idprop_serialize.cc
new file mode 100644
index 00000000000..08a7f13b806
--- /dev/null
+++ b/source/blender/blenkernel/intern/idprop_serialize.cc
@@ -0,0 +1,844 @@
+/*
+ * 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) 2021 by Blender Foundation.
+ */
+
+#include <optional>
+
+#include "DNA_ID.h"
+
+#include "BKE_idprop.hh"
+
+#include "BLI_listbase.h"
+
+namespace blender::bke::idprop {
+using namespace blender::io::serialize;
+
+/* Forward declarations */
+class IDPropertySerializer;
+struct DictionaryEntryParser;
+static IDProperty *idprop_from_value(const DictionaryValue &value);
+static const IDPropertySerializer &serializer_for(eIDPropertyType property_type);
+static const IDPropertySerializer &serializer_for(StringRef idprop_typename);
+
+/* -------------------------------------------------------------------- */
+/** \name ID property serialization.
+ * \{ */
+
+/* Definitions */
+static constexpr StringRef IDP_KEY_NAME("name");
+static constexpr StringRef IDP_KEY_TYPE("type");
+static constexpr StringRef IDP_KEY_SUBTYPE("subtype");
+static constexpr StringRef IDP_KEY_VALUE("value");
+
+static constexpr StringRef IDP_PROPERTY_TYPENAME_STRING("IDP_STRING");
+static constexpr StringRef IDP_PROPERTY_TYPENAME_INT("IDP_INT");
+static constexpr StringRef IDP_PROPERTY_TYPENAME_FLOAT("IDP_FLOAT");
+static constexpr StringRef IDP_PROPERTY_TYPENAME_DOUBLE("IDP_DOUBLE");
+static constexpr StringRef IDP_PROPERTY_TYPENAME_ARRAY("IDP_ARRAY");
+static constexpr StringRef IDP_PROPERTY_TYPENAME_GROUP("IDP_GROUP");
+static constexpr StringRef IDP_PROPERTY_TYPENAME_UNKNOWN("IDP_UNKNOWN");
+
+/**
+ * \brief Base class for (de)serializing IDProperties.
+ *
+ * Has a subclass for supported IDProperties and one for unsupported IDProperties.
+ */
+class IDPropertySerializer {
+ public:
+ constexpr IDPropertySerializer() = default;
+
+ /**
+ * \brief return the type name for (de)serializing.
+ * Type name is stored in the `type` or `subtype` attribute of the serialized id_property.
+ */
+ virtual std::string type_name() const = 0;
+
+ /**
+ * \brief return the IDPropertyType for (de)serializing.
+ */
+ virtual std::optional<eIDPropertyType> property_type() const = 0;
+
+ /**
+ * \brief create dictionary containing the given id_property.
+ */
+ virtual std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *id_property) const = 0;
+
+ /**
+ * \brief convert the entry to an id property.
+ */
+ virtual std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &entry_reader) const = 0;
+
+ /**
+ * \brief Can the serializer be used?
+ *
+ * IDP_ID and IDP_IDPARRAY aren't supported for serialization.
+ */
+ virtual bool supports_serializing() const
+ {
+ return true;
+ }
+
+ protected:
+ /**
+ * \brief Create a new DictionaryValue instance.
+ *
+ * Only fill the dictionary with common attributes (name, type).
+ */
+ std::shared_ptr<DictionaryValue> create_dictionary(const struct IDProperty *id_property) const
+ {
+ std::shared_ptr<DictionaryValue> result = std::make_shared<DictionaryValue>();
+ DictionaryValue::Items &attributes = result->elements();
+ attributes.append_as(std::pair(IDP_KEY_NAME, new StringValue(id_property->name)));
+ attributes.append_as(std::pair(IDP_KEY_TYPE, new StringValue(type_name())));
+ return result;
+ }
+};
+
+/**
+ * \brief Helper class for parsing DictionaryValues.
+ */
+struct DictionaryEntryParser {
+ const DictionaryValue::Lookup lookup;
+
+ public:
+ explicit DictionaryEntryParser(const DictionaryValue &value) : lookup(value.create_lookup())
+ {
+ }
+
+ std::optional<eIDPropertyType> get_type() const
+ {
+ return get_id_property_type(IDP_KEY_TYPE);
+ }
+
+ std::optional<eIDPropertyType> get_subtype() const
+ {
+ return get_id_property_type(IDP_KEY_SUBTYPE);
+ }
+
+ std::optional<std::string> get_name() const
+ {
+ return get_string(IDP_KEY_NAME);
+ }
+
+ std::optional<std::string> get_string_value() const
+ {
+ return get_string(IDP_KEY_VALUE);
+ }
+
+ std::optional<int32_t> get_int_value() const
+ {
+ return get_int(IDP_KEY_VALUE);
+ }
+
+ std::optional<float> get_float_value() const
+ {
+ return get_float(IDP_KEY_VALUE);
+ }
+
+ std::optional<double> get_double_value() const
+ {
+ return get_double(IDP_KEY_VALUE);
+ }
+
+ const ArrayValue *get_array_value() const
+ {
+ return get_array(IDP_KEY_VALUE);
+ }
+
+ std::optional<Vector<int32_t>> get_array_int_value() const
+ {
+ return get_array_primitive<int32_t, IntValue>(IDP_KEY_VALUE);
+ }
+
+ std::optional<Vector<float>> get_array_float_value() const
+ {
+ return get_array_primitive<float, DoubleValue>(IDP_KEY_VALUE);
+ }
+
+ std::optional<Vector<double>> get_array_double_value() const
+ {
+ return get_array_primitive<double, DoubleValue>(IDP_KEY_VALUE);
+ }
+
+ private:
+ std::optional<std::string> get_string(StringRef key) const
+ {
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
+ if (value_ptr == nullptr) {
+ return std::nullopt;
+ }
+ const DictionaryValue::LookupValue &value = *value_ptr;
+
+ if (value->type() != eValueType::String) {
+ return std::nullopt;
+ }
+
+ return value->as_string_value()->value();
+ }
+
+ const ArrayValue *get_array(StringRef key) const
+ {
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
+ if (value_ptr == nullptr) {
+ return nullptr;
+ }
+ const DictionaryValue::LookupValue &value = *value_ptr;
+
+ if (value->type() != eValueType::Array) {
+ return nullptr;
+ }
+
+ return value->as_array_value();
+ }
+
+ std::optional<int32_t> get_int(StringRef key) const
+ {
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
+ if (value_ptr == nullptr) {
+ return std::nullopt;
+ }
+ const DictionaryValue::LookupValue &value = *value_ptr;
+
+ if (value->type() != eValueType::Int) {
+ return std::nullopt;
+ }
+
+ return value->as_int_value()->value();
+ }
+
+ std::optional<double> get_double(StringRef key) const
+ {
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
+ if (value_ptr == nullptr) {
+ return std::nullopt;
+ }
+ const DictionaryValue::LookupValue &value = *value_ptr;
+
+ if (value->type() != eValueType::Double) {
+ return std::nullopt;
+ }
+
+ return value->as_double_value()->value();
+ }
+
+ std::optional<float> get_float(StringRef key) const
+ {
+ return static_cast<std::optional<float>>(get_double(key));
+ }
+
+ template<typename PrimitiveType, typename ValueType>
+ std::optional<Vector<PrimitiveType>> get_array_primitive(StringRef key) const
+ {
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
+ if (value_ptr == nullptr) {
+ return std::nullopt;
+ }
+ const DictionaryValue::LookupValue &value = *value_ptr;
+
+ if (value->type() != eValueType::Array) {
+ return std::nullopt;
+ }
+
+ Vector<PrimitiveType> result;
+ const ArrayValue::Items &elements = value->as_array_value()->elements();
+ for (const ArrayValue::Item &element : elements) {
+ const ValueType *value_type = static_cast<const ValueType *>(element.get());
+ PrimitiveType primitive_value = value_type->value();
+ result.append_as(primitive_value);
+ }
+
+ return result;
+ }
+
+ std::optional<eIDPropertyType> get_id_property_type(StringRef key) const
+ {
+ std::optional<std::string> string_value = get_string(key);
+ if (!string_value.has_value()) {
+ return std::nullopt;
+ }
+ const IDPropertySerializer &serializer = serializer_for(*string_value);
+ return serializer.property_type();
+ }
+};
+
+/** \brief IDPSerializer for IDP_STRING. */
+class IDPStringSerializer : public IDPropertySerializer {
+ public:
+ constexpr IDPStringSerializer() = default;
+
+ std::string type_name() const override
+ {
+ return IDP_PROPERTY_TYPENAME_STRING;
+ }
+
+ std::optional<eIDPropertyType> property_type() const override
+ {
+ return IDP_STRING;
+ }
+
+ std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *id_property) const override
+ {
+ std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
+ DictionaryValue::Items &attributes = result->elements();
+ attributes.append_as(std::pair(IDP_KEY_VALUE, new StringValue(IDP_String(id_property))));
+ return result;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &entry_reader) const override
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_STRING);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+ std::optional<std::string> string_value = entry_reader.get_string_value();
+ if (!string_value.has_value()) {
+ return nullptr;
+ }
+ return create(name->c_str(), string_value->c_str());
+ }
+};
+
+/** \brief IDPSerializer for IDP_INT. */
+class IDPIntSerializer : public IDPropertySerializer {
+ public:
+ constexpr IDPIntSerializer() = default;
+
+ std::string type_name() const override
+ {
+ return IDP_PROPERTY_TYPENAME_INT;
+ }
+
+ std::optional<eIDPropertyType> property_type() const override
+ {
+ return IDP_INT;
+ }
+
+ std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *id_property) const override
+ {
+ std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
+ DictionaryValue::Items &attributes = result->elements();
+ attributes.append_as(std::pair(IDP_KEY_VALUE, new IntValue(IDP_Int(id_property))));
+ return result;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &entry_reader) const override
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_INT);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+ std::optional<int32_t> extracted_value = entry_reader.get_int_value();
+ if (!extracted_value.has_value()) {
+ return nullptr;
+ }
+ return create(name->c_str(), *extracted_value);
+ }
+};
+
+/** \brief IDPSerializer for IDP_FLOAT. */
+class IDPFloatSerializer : public IDPropertySerializer {
+ public:
+ constexpr IDPFloatSerializer() = default;
+
+ std::string type_name() const override
+ {
+ return IDP_PROPERTY_TYPENAME_FLOAT;
+ }
+
+ std::optional<eIDPropertyType> property_type() const override
+ {
+ return IDP_FLOAT;
+ }
+
+ std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *id_property) const override
+ {
+ std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
+ DictionaryValue::Items &attributes = result->elements();
+ attributes.append_as(std::pair(IDP_KEY_VALUE, new DoubleValue(IDP_Float(id_property))));
+ return result;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &entry_reader) const override
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_FLOAT);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+ std::optional<float> extracted_value = entry_reader.get_float_value();
+ if (!extracted_value.has_value()) {
+ return nullptr;
+ }
+ return create(name->c_str(), *extracted_value);
+ }
+};
+
+/** \brief IDPSerializer for IDP_DOUBLE. */
+class IDPDoubleSerializer : public IDPropertySerializer {
+ public:
+ constexpr IDPDoubleSerializer() = default;
+
+ std::string type_name() const override
+ {
+ return IDP_PROPERTY_TYPENAME_DOUBLE;
+ }
+
+ std::optional<eIDPropertyType> property_type() const override
+ {
+ return IDP_DOUBLE;
+ }
+
+ std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *id_property) const override
+ {
+ std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
+ DictionaryValue::Items &attributes = result->elements();
+ attributes.append_as(std::pair(IDP_KEY_VALUE, new DoubleValue(IDP_Double(id_property))));
+ return result;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &entry_reader) const override
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_DOUBLE);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+ std::optional<double> extracted_value = entry_reader.get_double_value();
+ if (!extracted_value.has_value()) {
+ return nullptr;
+ }
+ return create(name->c_str(), *extracted_value);
+ }
+};
+
+/** \brief IDPSerializer for IDP_ARRAY. */
+class IDPArraySerializer : public IDPropertySerializer {
+ public:
+ constexpr IDPArraySerializer() = default;
+
+ std::string type_name() const override
+ {
+ return IDP_PROPERTY_TYPENAME_ARRAY;
+ }
+
+ std::optional<eIDPropertyType> property_type() const override
+ {
+ return IDP_ARRAY;
+ }
+
+ std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *id_property) const override
+ {
+ std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
+ DictionaryValue::Items &attributes = result->elements();
+ const IDPropertySerializer &subtype_serializer = serializer_for(
+ static_cast<eIDPropertyType>(id_property->subtype));
+ attributes.append_as(
+ std::pair(IDP_KEY_SUBTYPE, new StringValue(subtype_serializer.type_name())));
+
+ std::shared_ptr<ArrayValue> array = std::make_shared<ArrayValue>();
+ switch (static_cast<eIDPropertyType>(id_property->subtype)) {
+ case IDP_INT: {
+ int32_t *values = static_cast<int32_t *>(IDP_Array(id_property));
+ add_values<int32_t, IntValue>(array.get(), Span<int32_t>(values, id_property->len));
+ break;
+ }
+
+ case IDP_FLOAT: {
+ float *values = static_cast<float *>(IDP_Array(id_property));
+ add_values<float, DoubleValue>(array.get(), Span<float>(values, id_property->len));
+ break;
+ }
+
+ case IDP_DOUBLE: {
+ double *values = static_cast<double *>(IDP_Array(id_property));
+ add_values<double, DoubleValue>(array.get(), Span<double>(values, id_property->len));
+ break;
+ }
+
+ case IDP_GROUP: {
+ IDProperty *values = static_cast<IDProperty *>(IDP_Array(id_property));
+ add_values(array.get(), Span<IDProperty>(values, id_property->len));
+ break;
+ }
+
+ default: {
+ /* IDP_ARRAY only supports IDP_INT, IDP_FLOAT, IDP_DOUBLE and IDP_GROUP. */
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+ attributes.append_as(std::pair(IDP_KEY_VALUE, std::move(array)));
+
+ return result;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &entry_reader) const override
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY);
+ std::optional<eIDPropertyType> property_subtype = entry_reader.get_subtype();
+ if (!property_subtype.has_value()) {
+ return nullptr;
+ }
+
+ switch (*property_subtype) {
+ case IDP_INT:
+ return idprop_array_int_from_value(entry_reader);
+
+ case IDP_FLOAT:
+ return idprop_array_float_from_value(entry_reader);
+
+ case IDP_DOUBLE:
+ return idprop_array_double_from_value(entry_reader);
+
+ default:
+ break;
+ }
+ return nullptr;
+ }
+
+ private:
+ /** Add the given values to array. */
+ template</* C-primitive type of the values to add. Possible types are `float`, `int32_t` or
+ * `double`. */
+ typename PrimitiveType,
+ /* Type of value that can store the PrimitiveType in the Array. */
+ typename ValueType>
+ void add_values(ArrayValue *array, Span<PrimitiveType> values) const
+ {
+ ArrayValue::Items &items = array->elements();
+ for (PrimitiveType value : values) {
+ items.append_as(std::make_shared<ValueType>(value));
+ }
+ }
+
+ void add_values(ArrayValue *array, Span<IDProperty> values) const
+ {
+ ArrayValue::Items &items = array->elements();
+ for (const IDProperty &id_property : values) {
+ const IDPropertySerializer &value_serializer = serializer_for(
+ static_cast<eIDPropertyType>(id_property.type));
+ if (!value_serializer.supports_serializing()) {
+ continue;
+ }
+ std::shared_ptr<DictionaryValue> value = value_serializer.idprop_to_dictionary(&id_property);
+ items.append_as(value);
+ }
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> idprop_array_int_from_value(
+ DictionaryEntryParser &entry_reader) const
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY);
+ BLI_assert(*(entry_reader.get_subtype()) == IDP_INT);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+ std::optional<Vector<int32_t>> extracted_value = entry_reader.get_array_int_value();
+ if (!extracted_value.has_value()) {
+ return nullptr;
+ }
+ return create(name->c_str(), *extracted_value);
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> idprop_array_float_from_value(
+ DictionaryEntryParser &entry_reader) const
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY);
+ BLI_assert(*(entry_reader.get_subtype()) == IDP_FLOAT);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+ std::optional<Vector<float>> extracted_value = entry_reader.get_array_float_value();
+ if (!extracted_value.has_value()) {
+ return nullptr;
+ }
+ return create(name->c_str(), *extracted_value);
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> idprop_array_double_from_value(
+ DictionaryEntryParser &entry_reader) const
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY);
+ BLI_assert(*(entry_reader.get_subtype()) == IDP_DOUBLE);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+ std::optional<Vector<double>> extracted_value = entry_reader.get_array_double_value();
+ if (!extracted_value.has_value()) {
+ return nullptr;
+ }
+ return create(name->c_str(), *extracted_value);
+ }
+};
+
+/** \brief IDPSerializer for IDP_GROUP. */
+class IDPGroupSerializer : public IDPropertySerializer {
+ public:
+ constexpr IDPGroupSerializer() = default;
+
+ std::string type_name() const override
+ {
+ return IDP_PROPERTY_TYPENAME_GROUP;
+ }
+
+ std::optional<eIDPropertyType> property_type() const override
+ {
+ return IDP_GROUP;
+ }
+
+ std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *id_property) const override
+ {
+ std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
+ DictionaryValue::Items &attributes = result->elements();
+ std::shared_ptr<ArrayValue> array = std::make_shared<ArrayValue>();
+ ArrayValue::Items &elements = array->elements();
+
+ LISTBASE_FOREACH (IDProperty *, sub_property, &id_property->data.group) {
+
+ const IDPropertySerializer &sub_property_serializer = serializer_for(
+ static_cast<eIDPropertyType>(sub_property->type));
+ elements.append_as(sub_property_serializer.idprop_to_dictionary(sub_property));
+ }
+
+ attributes.append_as(std::pair(IDP_KEY_VALUE, array));
+ return result;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &entry_reader) const override
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_GROUP);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+
+ const ArrayValue *array = entry_reader.get_array_value();
+ if (array == nullptr) {
+ return nullptr;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> result = create_group(name->c_str());
+ for (const ArrayValue::Item &element : array->elements()) {
+ if (element->type() != eValueType::Dictionary) {
+ continue;
+ }
+ const DictionaryValue *subobject = element->as_dictionary_value();
+ IDProperty *subproperty = idprop_from_value(*subobject);
+ IDP_AddToGroup(result.get(), subproperty);
+ }
+
+ return result;
+ }
+};
+
+/**
+ * \brief Dummy serializer for unknown and unsupported types.
+ */
+class IDPUnknownSerializer : public IDPropertySerializer {
+ public:
+ constexpr IDPUnknownSerializer() = default;
+ std::string type_name() const override
+ {
+ return IDP_PROPERTY_TYPENAME_UNKNOWN;
+ }
+ std::optional<eIDPropertyType> property_type() const override
+ {
+ return std::nullopt;
+ }
+
+ std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *UNUSED(id_property)) const override
+ {
+ BLI_assert_unreachable();
+ return nullptr;
+ }
+
+ bool supports_serializing() const override
+ {
+ return false;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &UNUSED(entry_reader)) const override
+ {
+ return nullptr;
+ }
+};
+
+/* Serializers are constructed statically to remove construction/destruction. */
+static constexpr IDPStringSerializer IDP_SERIALIZER_STRING;
+static constexpr IDPIntSerializer IDP_SERIALIZER_INT;
+static constexpr IDPFloatSerializer IDP_SERIALIZER_FLOAT;
+static constexpr IDPDoubleSerializer IDP_SERIALIZER_DOUBLE;
+static constexpr IDPArraySerializer IDP_SERIALIZER_ARRAY;
+static constexpr IDPGroupSerializer IDP_SERIALIZER_GROUP;
+static constexpr IDPUnknownSerializer IDP_SERIALIZER_UNKNOWN;
+
+/** \brief get the serializer for the given property type. */
+static const IDPropertySerializer &serializer_for(eIDPropertyType property_type)
+{
+ switch (property_type) {
+ case IDP_STRING:
+ return IDP_SERIALIZER_STRING;
+
+ case IDP_INT:
+ return IDP_SERIALIZER_INT;
+
+ case IDP_FLOAT:
+ return IDP_SERIALIZER_FLOAT;
+
+ case IDP_DOUBLE:
+ return IDP_SERIALIZER_DOUBLE;
+
+ case IDP_ARRAY:
+ return IDP_SERIALIZER_ARRAY;
+
+ case IDP_GROUP:
+ return IDP_SERIALIZER_GROUP;
+
+ default:
+ BLI_assert_msg(false, "Trying to convert an unsupported/unknown property type to a string");
+ return IDP_SERIALIZER_UNKNOWN;
+ }
+}
+
+/** \brief get serializer for the given typename. */
+static const IDPropertySerializer &serializer_for(StringRef idprop_typename)
+{
+ if (idprop_typename == IDP_PROPERTY_TYPENAME_STRING) {
+ return IDP_SERIALIZER_STRING;
+ }
+ if (idprop_typename == IDP_PROPERTY_TYPENAME_INT) {
+ return IDP_SERIALIZER_INT;
+ }
+ if (idprop_typename == IDP_PROPERTY_TYPENAME_FLOAT) {
+ return IDP_SERIALIZER_FLOAT;
+ }
+ if (idprop_typename == IDP_PROPERTY_TYPENAME_DOUBLE) {
+ return IDP_SERIALIZER_DOUBLE;
+ }
+ if (idprop_typename == IDP_PROPERTY_TYPENAME_ARRAY) {
+ return IDP_SERIALIZER_ARRAY;
+ }
+ if (idprop_typename == IDP_PROPERTY_TYPENAME_GROUP) {
+ return IDP_SERIALIZER_GROUP;
+ }
+ return IDP_SERIALIZER_UNKNOWN;
+}
+
+/* \} */
+
+/* -------------------------------------------------------------------- */
+/** \name IDProperty to Value
+ * \{ */
+std::unique_ptr<ArrayValue> convert_to_serialize_values(const struct IDProperty *properties)
+{
+ BLI_assert(properties != nullptr);
+ std::unique_ptr<ArrayValue> result = std::make_unique<ArrayValue>();
+ ArrayValue::Items &elements = result->elements();
+ const struct IDProperty *current_property = properties;
+ while (current_property != nullptr) {
+ const IDPropertySerializer &serializer = serializer_for(
+ static_cast<eIDPropertyType>(current_property->type));
+ if (serializer.supports_serializing()) {
+ elements.append_as(serializer.idprop_to_dictionary(current_property));
+ }
+ current_property = current_property->next;
+ }
+
+ return result;
+}
+
+/* \} */
+
+/* -------------------------------------------------------------------- */
+/** \name IDProperty from Value
+ * \{ */
+
+static IDProperty *idprop_from_value(const DictionaryValue &value)
+{
+ DictionaryEntryParser entry_reader(value);
+ std::optional<eIDPropertyType> property_type = entry_reader.get_type();
+ if (!property_type.has_value()) {
+ return nullptr;
+ }
+
+ const IDPropertySerializer &serializer = serializer_for(*property_type);
+ return serializer.entry_to_idprop(entry_reader).release();
+}
+
+static IDProperty *idprop_from_value(const ArrayValue &value)
+{
+ IDProperty *result = nullptr;
+ IDProperty *previous_added = nullptr;
+
+ const ArrayValue::Items &elements = value.elements();
+ for (const ArrayValue::Item &element : elements) {
+ if (element->type() != eValueType::Dictionary) {
+ continue;
+ }
+ const DictionaryValue *object_value = element->as_dictionary_value();
+ IDProperty *last_created = idprop_from_value(*object_value);
+ if (last_created == nullptr) {
+ continue;
+ }
+
+ if (result == nullptr) {
+ result = last_created;
+ }
+
+ if (previous_added) {
+ previous_added->next = last_created;
+ }
+ last_created->prev = previous_added;
+ previous_added = last_created;
+ }
+
+ return result;
+}
+
+IDProperty *convert_from_serialize_value(const Value &value)
+{
+ if (value.type() != eValueType::Array) {
+ return nullptr;
+ }
+
+ return idprop_from_value(*value.as_array_value());
+}
+
+/* \} */
+
+} // namespace blender::bke::idprop
diff --git a/source/blender/blenkernel/intern/idprop_serialize_test.cc b/source/blender/blenkernel/intern/idprop_serialize_test.cc
new file mode 100644
index 00000000000..eeee3fc2aea
--- /dev/null
+++ b/source/blender/blenkernel/intern/idprop_serialize_test.cc
@@ -0,0 +1,448 @@
+/*
+ * 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) 2021 by Blender Foundation.
+ */
+
+#include "testing/testing.h"
+
+#include "DNA_ID.h"
+
+#include "BKE_idprop.hh"
+
+namespace blender::bke::idprop::tests {
+
+using namespace blender::io::serialize;
+
+static void check_container_value(ArrayValue *value)
+{
+ ASSERT_NE(value, nullptr);
+ ASSERT_EQ(value->type(), eValueType::Array);
+ const ArrayValue::Items elements = value->elements();
+ EXPECT_FALSE(elements.is_empty());
+ EXPECT_EQ(elements.size(), 1);
+
+ const ArrayValue::Item &item = value->elements()[0];
+ ASSERT_EQ(item->type(), eValueType::Dictionary);
+}
+
+static void check_object_attribute(const DictionaryValue::Lookup &lookup,
+ const std::string expected_key,
+ const std::string expected_value)
+{
+ EXPECT_TRUE(lookup.contains(expected_key));
+ const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
+ ASSERT_EQ(element->type(), eValueType::String);
+ EXPECT_EQ(element->as_string_value()->value(), expected_value);
+}
+
+static void check_object_attribute(const DictionaryValue::Lookup &lookup,
+ const std::string expected_key,
+ const int32_t expected_value)
+{
+ EXPECT_TRUE(lookup.contains(expected_key));
+ const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
+ ASSERT_EQ(element->type(), eValueType::Int);
+ EXPECT_EQ(element->as_int_value()->value(), expected_value);
+}
+
+static void check_object_attribute(const DictionaryValue::Lookup &lookup,
+ const std::string expected_key,
+ const float expected_value)
+{
+ EXPECT_TRUE(lookup.contains(expected_key));
+ const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
+ ASSERT_EQ(element->type(), eValueType::Double);
+ EXPECT_EQ(element->as_double_value()->value(), expected_value);
+}
+
+static void check_object_attribute(const DictionaryValue::Lookup &lookup,
+ const std::string expected_key,
+ const double expected_value)
+{
+ EXPECT_TRUE(lookup.contains(expected_key));
+ const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
+ ASSERT_EQ(element->type(), eValueType::Double);
+ EXPECT_EQ(element->as_double_value()->value(), expected_value);
+}
+
+static void test_string_to_value(const StringRefNull prop_name, const StringRefNull prop_content)
+{
+ std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
+
+ std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
+ check_container_value(value.get());
+ const ArrayValue::Item &item = value->elements()[0];
+ const DictionaryValue *object = item->as_dictionary_value();
+ const DictionaryValue::Lookup lookup = object->create_lookup();
+
+ EXPECT_EQ(lookup.size(), 3);
+ check_object_attribute(lookup, "name", prop_name);
+ check_object_attribute(lookup, "type", "IDP_STRING");
+ check_object_attribute(lookup, "value", prop_content);
+}
+
+TEST(idprop, convert_idp_string_to_value)
+{
+ test_string_to_value("mykey", "mycontent");
+}
+
+static void test_int_to_value(const StringRefNull prop_name, int32_t prop_content)
+{
+ std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
+
+ std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
+ check_container_value(value.get());
+ const ArrayValue::Item &item = value->elements()[0];
+ const DictionaryValue *object = item->as_dictionary_value();
+ const DictionaryValue::Lookup lookup = object->create_lookup();
+
+ EXPECT_EQ(lookup.size(), 3);
+ check_object_attribute(lookup, "name", prop_name);
+ check_object_attribute(lookup, "type", "IDP_INT");
+ check_object_attribute(lookup, "value", prop_content);
+}
+
+TEST(idprop, convert_idp_int_to_value)
+{
+ test_int_to_value("mykey", 0);
+}
+
+static void test_float_to_value(const StringRefNull prop_name, float prop_content)
+{
+ std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
+
+ std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
+ check_container_value(value.get());
+ const ArrayValue::Item &item = value->elements()[0];
+ const DictionaryValue *object = item->as_dictionary_value();
+ const DictionaryValue::Lookup lookup = object->create_lookup();
+
+ EXPECT_EQ(lookup.size(), 3);
+ check_object_attribute(lookup, "name", prop_name);
+ check_object_attribute(lookup, "type", "IDP_FLOAT");
+ check_object_attribute(lookup, "value", prop_content);
+}
+
+TEST(idprop, convert_idp_float_to_value)
+{
+ test_float_to_value("mykey", 0.2f);
+}
+
+static void test_double_to_value(const StringRefNull prop_name, double prop_content)
+{
+ std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
+
+ std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
+ check_container_value(value.get());
+ const ArrayValue::Item &item = value->elements()[0];
+ const DictionaryValue *object = item->as_dictionary_value();
+ const DictionaryValue::Lookup lookup = object->create_lookup();
+
+ EXPECT_EQ(lookup.size(), 3);
+ check_object_attribute(lookup, "name", prop_name);
+ check_object_attribute(lookup, "type", "IDP_DOUBLE");
+ check_object_attribute(lookup, "value", prop_content);
+}
+
+TEST(idprop, convert_idp_double_to_value)
+{
+ test_double_to_value("mykey", 0.2);
+}
+
+template<typename PrimitiveType, typename ValueType>
+static void test_array_to_value(const StringRefNull prop_name, Vector<PrimitiveType> prop_content)
+{
+ std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
+ std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
+
+ check_container_value(value.get());
+ const ArrayValue::Item &item = value->elements()[0];
+ const DictionaryValue *object = item->as_dictionary_value();
+ const DictionaryValue::Lookup lookup = object->create_lookup();
+
+ EXPECT_EQ(lookup.size(), 4);
+ check_object_attribute(lookup, "name", prop_name);
+ check_object_attribute(lookup, "type", "IDP_ARRAY");
+
+ const std::shared_ptr<Value> &element = *lookup.lookup_ptr("value");
+ const ArrayValue *subvalues = element->as_array_value();
+ ASSERT_NE(subvalues, nullptr);
+ const ArrayValue::Items &subitems = subvalues->elements();
+ ASSERT_EQ(subitems.size(), prop_content.size());
+
+ for (size_t i = 0; i < prop_content.size(); i++) {
+ EXPECT_EQ(static_cast<ValueType *>(subitems[i].get())->value(), prop_content[i]);
+ }
+}
+
+TEST(idprop, convert_idp_int_array_to_value)
+{
+ test_array_to_value<int32_t, IntValue>("my_integer_array",
+ {-16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16});
+}
+
+TEST(idprop, convert_idp_float_array_to_value)
+{
+ test_array_to_value<float, DoubleValue>(
+ "my_float_array", {-16.8f, -8.4f, -4.2f, -2.1f, -1.0f, 0.0f, 1.0f, 2.1f, 4.2f, 8.4f, 16.8f});
+}
+
+TEST(idprop, convert_idp_double_array_to_value)
+{
+ test_array_to_value<double, DoubleValue>(
+ "my_double_array", {-16.8, -8.4, -4.2, -2.1, -1.0, 0.0, 1.0, 2.1, 4.2, 8.4, 16.8});
+}
+
+static std::unique_ptr<Value> parse_json(StringRef input)
+{
+ std::stringstream is(input);
+ JsonFormatter json;
+ std::unique_ptr<Value> value = json.deserialize(is);
+ return value;
+}
+
+static std::string to_json(const Value &value)
+{
+ std::stringstream out;
+ JsonFormatter json;
+ json.serialize(out, value);
+ return out.str();
+}
+
+static void test_idprop(const IDProperty *id_property,
+ StringRef expected_name,
+ StringRef expected_value)
+{
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_STRING);
+ EXPECT_EQ(id_property->name, expected_name);
+ EXPECT_EQ(IDP_String(id_property), expected_value);
+}
+
+static void test_idprop(const IDProperty *id_property,
+ StringRef expected_name,
+ int32_t expected_value)
+{
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_INT);
+ EXPECT_EQ(id_property->name, expected_name);
+ EXPECT_EQ(IDP_Int(id_property), expected_value);
+}
+
+static void test_idprop(const IDProperty *id_property,
+ StringRef expected_name,
+ float expected_value)
+{
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_FLOAT);
+ EXPECT_EQ(id_property->name, expected_name);
+ EXPECT_EQ(IDP_Float(id_property), expected_value);
+}
+
+static void test_idprop(const IDProperty *id_property,
+ StringRef expected_name,
+ double expected_value)
+{
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_DOUBLE);
+ EXPECT_EQ(id_property->name, expected_name);
+ EXPECT_EQ(IDP_Double(id_property), expected_value);
+}
+
+static void test_idprop(const IDProperty *id_property,
+ StringRef expected_name,
+ const Vector<int32_t> &values)
+{
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_ARRAY);
+ EXPECT_EQ(id_property->subtype, IDP_INT);
+ EXPECT_EQ(id_property->len, values.size());
+ EXPECT_EQ(id_property->name, expected_name);
+ int32_t *idprop_values = static_cast<int32_t *>(IDP_Array(id_property));
+ for (int i = 0; i < values.size(); i++) {
+ EXPECT_EQ(idprop_values[i], values[i]);
+ }
+}
+
+static void test_idprop(const IDProperty *id_property,
+ StringRef expected_name,
+ const Vector<float> &values)
+{
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_ARRAY);
+ EXPECT_EQ(id_property->subtype, IDP_FLOAT);
+ EXPECT_EQ(id_property->len, values.size());
+ EXPECT_EQ(id_property->name, expected_name);
+ float *idprop_values = static_cast<float *>(IDP_Array(id_property));
+ for (int i = 0; i < values.size(); i++) {
+ EXPECT_EQ(idprop_values[i], values[i]);
+ }
+}
+
+static void test_idprop(const IDProperty *id_property,
+ StringRef expected_name,
+ const Vector<double> &values)
+{
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_ARRAY);
+ EXPECT_EQ(id_property->subtype, IDP_DOUBLE);
+ EXPECT_EQ(id_property->len, values.size());
+ EXPECT_EQ(id_property->name, expected_name);
+ double *idprop_values = static_cast<double *>(IDP_Array(id_property));
+ for (int i = 0; i < values.size(); i++) {
+ EXPECT_EQ(idprop_values[i], values[i]);
+ }
+}
+
+template<typename Type>
+static void test_convert_idprop_from_value(StringRef input,
+ StringRef expected_name,
+ Type expected_value)
+{
+ std::unique_ptr<Value> value = parse_json(input);
+ IDProperty *id_property = convert_from_serialize_value(*value);
+ test_idprop(id_property, expected_name, expected_value);
+ IDP_FreeProperty(id_property);
+}
+
+TEST(idprop, convert_idp_string_from_value)
+{
+ test_convert_idprop_from_value(
+ R"([{"name":"MyStringName","type":"IDP_STRING","value":"MyString"}])",
+ "MyStringName",
+ "MyString");
+}
+
+TEST(idprop, convert_idp_int_from_value)
+{
+ test_convert_idprop_from_value(
+ R"([{"name":"MyIntegerName","type":"IDP_INT","value":42}])", "MyIntegerName", 42);
+}
+
+TEST(idprop, convert_idp_float_from_value)
+{
+ test_convert_idprop_from_value(
+ R"([{"name":"MyFloatName","type":"IDP_FLOAT","value":42.24}])", "MyFloatName", 42.24f);
+}
+
+TEST(idprop, convert_idp_double_from_value)
+{
+ test_convert_idprop_from_value(
+ R"([{"name":"MyDoubleName","type":"IDP_DOUBLE","value":42.24}])", "MyDoubleName", 42.24);
+}
+
+TEST(idprop, convert_idp_array_int_from_value)
+{
+ test_convert_idprop_from_value(
+ R"([{"name":"MyArrayName","type":"IDP_ARRAY","subtype":"IDP_INT","value":[42, 24, 35]}])",
+ "MyArrayName",
+ Vector<int32_t>{42, 24, 35});
+}
+
+TEST(idprop, convert_idp_array_float_from_value)
+{
+ test_convert_idprop_from_value(
+ R"([{"name":"MyArrayName","type":"IDP_ARRAY","subtype":"IDP_FLOAT","value":[42.0, 24.4, 35.2]}])",
+ "MyArrayName",
+ Vector<float>{42.0f, 24.4f, 35.2f});
+}
+
+TEST(idprop, convert_idp_array_double_from_value)
+{
+ test_convert_idprop_from_value(
+ R"([{"name":"MyArrayName","type":"IDP_ARRAY","subtype":"IDP_DOUBLE","value":[42.43,24.5,35.8]}])",
+ "MyArrayName",
+ Vector<double>{42.43, 24.5, 35.8});
+}
+
+TEST(idprop, convert_idp_multiple_from_value)
+{
+ static const std::string input_json =
+ R"([{"name":"MyIntegerName","type":"IDP_INT","value":42},{"name":"MyStringName","type":"IDP_STRING","value":"MyString"},{"name":"MyFloatName","type":"IDP_FLOAT","value":42.24},{"name":"MyDoubleName","type":"IDP_DOUBLE","value":42.24}])";
+ std::unique_ptr<Value> value = parse_json(input_json);
+
+ IDProperty *id_property = convert_from_serialize_value(*value);
+ IDProperty *id_property_1 = id_property;
+ ASSERT_NE(id_property_1, nullptr);
+ IDProperty *id_property_2 = id_property_1->next;
+ ASSERT_NE(id_property_2, nullptr);
+ IDProperty *id_property_3 = id_property_2->next;
+ ASSERT_NE(id_property_3, nullptr);
+ IDProperty *id_property_4 = id_property_3->next;
+ ASSERT_NE(id_property_4, nullptr);
+
+ EXPECT_EQ(id_property_1->prev, nullptr);
+ EXPECT_EQ(id_property_2->prev, id_property_1);
+ EXPECT_EQ(id_property_3->prev, id_property_2);
+ EXPECT_EQ(id_property_4->prev, id_property_3);
+ EXPECT_EQ(id_property_4->next, nullptr);
+
+ test_idprop(id_property_1, "MyIntegerName", 42);
+ test_idprop(id_property_2, "MyStringName", "MyString");
+ test_idprop(id_property_3, "MyFloatName", 42.24f);
+ test_idprop(id_property_4, "MyDoubleName", 42.24);
+
+ IDP_FreeProperty(id_property_1);
+ IDP_FreeProperty(id_property_2);
+ IDP_FreeProperty(id_property_3);
+ IDP_FreeProperty(id_property_4);
+}
+
+TEST(idprop, convert_idp_multiple_roundtrip)
+{
+ static const std::string input_json =
+ R"([{"name":"MyIntegerName","type":"IDP_INT","value":42},{"name":"MyStringName","type":"IDP_STRING","value":"MyString"},{"name":"MyFloatName","type":"IDP_FLOAT","value":42.2400016784668},{"name":"MyDoubleName","type":"IDP_DOUBLE","value":42.24}])";
+ std::unique_ptr<Value> value = parse_json(input_json);
+
+ IDProperty *id_property = convert_from_serialize_value(*value);
+ IDProperty *id_property_1 = id_property;
+ ASSERT_NE(id_property_1, nullptr);
+ IDProperty *id_property_2 = id_property_1->next;
+ ASSERT_NE(id_property_2, nullptr);
+ IDProperty *id_property_3 = id_property_2->next;
+ ASSERT_NE(id_property_3, nullptr);
+ IDProperty *id_property_4 = id_property_3->next;
+ ASSERT_NE(id_property_4, nullptr);
+
+ std::unique_ptr<Value> value_from_id_properties = convert_to_serialize_values(id_property);
+ std::string output_json = to_json(*value_from_id_properties);
+ EXPECT_EQ(input_json, output_json);
+
+ IDP_FreeProperty(id_property_1);
+ IDP_FreeProperty(id_property_2);
+ IDP_FreeProperty(id_property_3);
+ IDP_FreeProperty(id_property_4);
+}
+
+TEST(idprop, convert_idp_group_from_value)
+{
+ static const std::string input_json =
+ R"([{"name":"AssetMetaData.properties","type":"IDP_GROUP","value":[{"name":"dimensions","type":"IDP_ARRAY","subtype":"IDP_FLOAT","value":[2.0,2.0,2.0]}]}])";
+ std::unique_ptr<Value> value = parse_json(input_json);
+
+ IDProperty *id_property = convert_from_serialize_value(*value);
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_GROUP);
+ EXPECT_EQ(BLI_listbase_count(&id_property->data.group), 1);
+
+ test_idprop(static_cast<IDProperty *>(id_property->data.group.first),
+ "dimensions",
+ Vector<float>{2.0f, 2.0f, 2.0f});
+
+ IDP_FreeProperty(id_property);
+}
+
+} // namespace blender::bke::idprop::tests
diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c
index d9dc68b1a4f..e6fd6c14d42 100644
--- a/source/blender/blenkernel/intern/idtype.c
+++ b/source/blender/blenkernel/intern/idtype.c
@@ -158,13 +158,6 @@ static const IDTypeInfo *idtype_get_info_from_name(const char *idtype_name)
/* Various helpers/wrappers around #IDTypeInfo structure. */
-/**
- * Convert an \a idcode into a name.
- *
- * \param idcode: The code to convert.
- * \return A static string representing the name of
- * the code.
- */
const char *BKE_idtype_idcode_to_name(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -172,13 +165,6 @@ const char *BKE_idtype_idcode_to_name(const short idcode)
return id_type != NULL ? id_type->name : NULL;
}
-/**
- * Convert an \a idcode into a name (plural).
- *
- * \param idcode: The code to convert.
- * \return A static string representing the name of
- * the code.
- */
const char *BKE_idtype_idcode_to_name_plural(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -186,12 +172,6 @@ const char *BKE_idtype_idcode_to_name_plural(const short idcode)
return id_type != NULL ? id_type->name_plural : NULL;
}
-/**
- * Convert an \a idcode into its translations' context.
- *
- * \param idcode: The code to convert.
- * \return A static string representing the i18n context of the code.
- */
const char *BKE_idtype_idcode_to_translation_context(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -199,12 +179,6 @@ const char *BKE_idtype_idcode_to_translation_context(const short idcode)
return id_type != NULL ? id_type->translation_context : BLT_I18NCONTEXT_DEFAULT;
}
-/**
- * Convert an ID-type name into an \a idcode (ie. #ID_SCE)
- *
- * \param idtype_name: The ID-type's "user visible name" to convert.
- * \return The \a idcode for the name, or 0 if invalid.
- */
short BKE_idtype_idcode_from_name(const char *idtype_name)
{
const IDTypeInfo *id_type = idtype_get_info_from_name(idtype_name);
@@ -212,23 +186,11 @@ short BKE_idtype_idcode_from_name(const char *idtype_name)
return id_type != NULL ? id_type->id_code : 0;
}
-/**
- * Return if the ID code is a valid ID code.
- *
- * \param idcode: The code to check.
- * \return Boolean, 0 when invalid.
- */
bool BKE_idtype_idcode_is_valid(const short idcode)
{
return BKE_idtype_get_info_from_idcode(idcode) != NULL ? true : false;
}
-/**
- * Check if an ID type is linkable.
- *
- * \param idcode: The IDType code to check.
- * \return Boolean, false when non linkable, true otherwise.
- */
bool BKE_idtype_idcode_is_linkable(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -236,12 +198,6 @@ bool BKE_idtype_idcode_is_linkable(const short idcode)
return id_type != NULL ? (id_type->flags & IDTYPE_FLAGS_NO_LIBLINKING) == 0 : false;
}
-/**
- * Check if an ID type is only appendable.
- *
- * \param idcode: The IDType code to check.
- * \return Boolean, false when also linkable, true when only appendable.
- */
bool BKE_idtype_idcode_is_only_appendable(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -254,12 +210,6 @@ bool BKE_idtype_idcode_is_only_appendable(const short idcode)
return false;
}
-/**
- * Check if an ID type can try to reuse and existing matching local one when being appended again.
- *
- * \param idcode: The IDType code to check.
- * \return Boolean, false when it cannot be re-used, true otherwise.
- */
bool BKE_idtype_idcode_append_is_reusable(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -272,9 +222,6 @@ bool BKE_idtype_idcode_append_is_reusable(const short idcode)
return false;
}
-/**
- * Convert an \a idcode into an \a idfilter (e.g. ID_OB -> FILTER_ID_OB).
- */
uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
{
#define CASE_IDFILTER(_id) \
@@ -324,9 +271,6 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
#undef CASE_IDFILTER
}
-/**
- * Convert an \a idfilter into an \a idcode (e.g. #FILTER_ID_OB -> #ID_OB).
- */
short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
{
#define CASE_IDFILTER(_id) \
@@ -375,9 +319,6 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
#undef CASE_IDFILTER
}
-/**
- * Convert an \a idcode into an index (e.g. #ID_OB -> #INDEX_ID_OB).
- */
int BKE_idtype_idcode_to_index(const short idcode)
{
#define CASE_IDINDEX(_id) \
@@ -437,9 +378,6 @@ int BKE_idtype_idcode_to_index(const short idcode)
#undef CASE_IDINDEX
}
-/**
- * Get an \a idcode from an index (e.g. #INDEX_ID_OB -> #ID_OB).
- */
short BKE_idtype_idcode_from_index(const int index)
{
#define CASE_IDCODE(_id) \
@@ -499,20 +437,11 @@ short BKE_idtype_idcode_from_index(const int index)
#undef CASE_IDCODE
}
-/**
- * Return an ID code and steps the index forward 1.
- *
- * \param index: start as 0.
- * \return the code, 0 when all codes have been returned.
- */
short BKE_idtype_idcode_iter_step(int *index)
{
return (*index < ARRAY_SIZE(id_types)) ? BKE_idtype_idcode_from_index((*index)++) : 0;
}
-/**
- * Wrapper around #IDTypeInfo foreach_cache that also handles embedded IDs.
- */
void BKE_idtype_id_foreach_cache(struct ID *id,
IDTypeForeachCacheFunctionCallback function_callback,
void *user_data)
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index b993d743044..c7d58a277e0 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -21,6 +21,7 @@
* \ingroup bke
*/
+#include <ctype.h>
#include <fcntl.h>
#include <math.h>
#include <stdio.h>
@@ -75,6 +76,7 @@
#include "BLT_translation.h"
+#include "BKE_bpath.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_icons.h"
@@ -83,6 +85,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -96,6 +99,7 @@
#include "SEQ_utils.h" /* SEQ_get_topmost_sequence() */
+#include "GPU_material.h"
#include "GPU_texture.h"
#include "BLI_sys_types.h" /* for intptr_t support */
@@ -112,12 +116,26 @@
#include "DNA_view3d_types.h"
static CLG_LogRef LOG = {"bke.image"};
-static ThreadMutex *image_mutex;
static void image_init(Image *ima, short source, short type);
static void image_free_packedfiles(Image *ima);
static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src);
+/* Reset runtime image fields when data-block is being initialized. */
+static void image_runtime_reset(struct Image *image)
+{
+ memset(&image->runtime, 0, sizeof(image->runtime));
+ image->runtime.cache_mutex = MEM_mallocN(sizeof(ThreadMutex), "image runtime cache_mutex");
+ BLI_mutex_init(image->runtime.cache_mutex);
+}
+
+/* Reset runtime image fields when data-block is being copied. */
+static void image_runtime_reset_on_copy(struct Image *image)
+{
+ image->runtime.cache_mutex = MEM_mallocN(sizeof(ThreadMutex), "image runtime cache_mutex");
+ BLI_mutex_init(image->runtime.cache_mutex);
+}
+
static void image_init_data(ID *id)
{
Image *image = (Image *)id;
@@ -167,6 +185,8 @@ static void image_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
else {
image_dst->preview = NULL;
}
+
+ image_runtime_reset_on_copy(image_dst);
}
static void image_free_data(ID *id)
@@ -194,6 +214,9 @@ static void image_free_data(ID *id)
BLI_freelistN(&image->tiles);
BLI_freelistN(&image->gpu_refresh_areas);
+
+ BLI_mutex_end(image->runtime.cache_mutex);
+ MEM_freeN(image->runtime.cache_mutex);
}
static void image_foreach_cache(ID *id,
@@ -211,8 +234,12 @@ static void image_foreach_cache(ID *id,
for (int eye = 0; eye < 2; eye++) {
for (int a = 0; a < TEXTARGET_COUNT; a++) {
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
+ GPUTexture *texture = image->gputexture[a][eye][resolution];
+ if (texture == NULL) {
+ continue;
+ }
key.offset_in_ID = offsetof(Image, gputexture[a][eye][resolution]);
- key.cache_v = image->gputexture[a][eye];
+ key.cache_v = texture;
function_callback(id, &key, (void **)&image->gputexture[a][eye][resolution], 0, user_data);
}
}
@@ -229,6 +256,60 @@ static void image_foreach_cache(ID *id,
}
}
+static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Image *ima = (Image *)id;
+ const eBPathForeachFlag flag = bpath_data->flag;
+
+ if (BKE_image_has_packedfile(ima) && (flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
+ return;
+ }
+ /* Skip empty file paths, these are typically from generated images and
+ * don't make sense to add directories to until the image has been saved
+ * once to give it a meaningful value. */
+ /* TODO re-assess whether this behavior is desired in the new generic code context. */
+ if (!ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED) ||
+ ima->filepath[0] == '\0') {
+ return;
+ }
+
+ /* If this is a tiled image, and we're asked to resolve the tokens in the virtual
+ * filepath, use the first tile to generate a concrete path for use during processing. */
+ bool result = false;
+ if (ima->source == IMA_SRC_TILED && (flag & BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN) != 0) {
+ char temp_path[FILE_MAX], orig_file[FILE_MAXFILE];
+ BLI_strncpy(temp_path, ima->filepath, sizeof(temp_path));
+ BLI_split_file_part(temp_path, orig_file, sizeof(orig_file));
+
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = BKE_image_get_tile_strformat(temp_path, &tile_format);
+ BKE_image_set_filepath_from_tile_number(
+ temp_path, udim_pattern, tile_format, ((ImageTile *)ima->tiles.first)->tile_number);
+ MEM_SAFE_FREE(udim_pattern);
+
+ result = BKE_bpath_foreach_path_fixed_process(bpath_data, temp_path);
+ if (result) {
+ /* Put the filepath back together using the new directory and the original file name. */
+ char new_dir[FILE_MAXDIR];
+ BLI_split_dir_part(temp_path, new_dir, sizeof(new_dir));
+ BLI_join_dirfile(ima->filepath, sizeof(ima->filepath), new_dir, orig_file);
+ }
+ }
+ else {
+ result = BKE_bpath_foreach_path_fixed_process(bpath_data, ima->filepath);
+ }
+
+ if (result) {
+ if (flag & BKE_BPATH_FOREACH_PATH_RELOAD_EDITED) {
+ if (!BKE_image_has_packedfile(ima) &&
+ /* Image may have been painted onto (and not saved, T44543). */
+ !BKE_image_is_dirty(ima)) {
+ BKE_image_signal(bpath_data->bmain, ima, NULL, IMA_SIGNAL_RELOAD);
+ }
+ }
+ }
+}
+
static void image_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Image *ima = (Image *)id;
@@ -317,12 +398,12 @@ static void image_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_data_address(reader, &ima->preview);
BKE_previewimg_blend_read(reader, ima->preview);
BLO_read_data_address(reader, &ima->stereo3d_format);
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- tile->ok = IMA_OK;
- }
+
ima->lastused = 0;
ima->gpuflag = 0;
BLI_listbase_clear(&ima->gpu_refresh_areas);
+
+ image_runtime_reset(ima);
}
static void image_blend_read_lib(BlendLibReader *UNUSED(reader), ID *id)
@@ -346,6 +427,7 @@ IDTypeInfo IDType_ID_IM = {
.name_plural = "images",
.translation_context = BLT_I18NCONTEXT_ID_IMAGE,
.flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = image_init_data,
.copy_data = image_copy_data,
@@ -353,6 +435,7 @@ IDTypeInfo IDType_ID_IM = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = image_foreach_cache,
+ .foreach_path = image_foreach_path,
.owner_get = NULL,
.blend_write = image_blend_write,
@@ -439,27 +522,17 @@ static void imagecache_remove(Image *image, int index)
IMB_moviecache_remove(image->cache, &key);
}
-static struct ImBuf *imagecache_get(Image *image, int index)
+static struct ImBuf *imagecache_get(Image *image, int index, bool *r_is_cached_empty)
{
if (image->cache) {
ImageCacheKey key;
key.index = index;
- return IMB_moviecache_get(image->cache, &key);
+ return IMB_moviecache_get(image->cache, &key, r_is_cached_empty);
}
return NULL;
}
-void BKE_images_init(void)
-{
- image_mutex = BLI_mutex_alloc();
-}
-
-void BKE_images_exit(void)
-{
- BLI_mutex_free(image_mutex);
-}
-
/* ***************** ALLOC & FREE, DATA MANAGING *************** */
static void image_free_cached_frames(Image *image)
@@ -505,14 +578,10 @@ static void image_free_anims(Image *ima)
}
}
-/**
- * Simply free the image data from memory,
- * on display the image can load again (except for render buffers).
- */
void BKE_image_free_buffers_ex(Image *ima, bool do_lock)
{
if (do_lock) {
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(ima->runtime.cache_mutex);
}
image_free_cached_frames(ima);
@@ -525,12 +594,8 @@ void BKE_image_free_buffers_ex(Image *ima, bool do_lock)
BKE_image_free_gputextures(ima);
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- tile->ok = IMA_OK;
- }
-
if (do_lock) {
- BLI_mutex_unlock(image_mutex);
+ BLI_mutex_unlock(ima->runtime.cache_mutex);
}
}
@@ -539,7 +604,6 @@ void BKE_image_free_buffers(Image *ima)
BKE_image_free_buffers_ex(ima, false);
}
-/** Free (or release) any data used by this image (does not free the image itself). */
void BKE_image_free_data(Image *ima)
{
image_free_data(&ima->id);
@@ -560,7 +624,6 @@ static void image_init(Image *ima, short source, short type)
}
ImageTile *tile = MEM_callocN(sizeof(ImageTile), "Image Tiles");
- tile->ok = IMA_OK;
tile->tile_number = 1001;
BLI_addtail(&ima->tiles, tile);
@@ -570,6 +633,8 @@ static void image_init(Image *ima, short source, short type)
}
}
+ image_runtime_reset(ima);
+
BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings);
ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format");
}
@@ -593,25 +658,25 @@ static Image *image_alloc(Main *bmain, const char *name, short source, short typ
* call IMB_freeImBuf to de-reference the image buffer after
* it's done handling it.
*/
-static ImBuf *image_get_cached_ibuf_for_index_entry(Image *ima, int index, int entry)
+static ImBuf *image_get_cached_ibuf_for_index_entry(Image *ima,
+ int index,
+ int entry,
+ bool *r_is_cached_empty)
{
if (index != IMA_NO_INDEX) {
index = IMA_MAKE_INDEX(entry, index);
}
- return imagecache_get(ima, index);
+ return imagecache_get(ima, index, r_is_cached_empty);
}
-/* no ima->ibuf anymore, but listbase */
static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int entry)
{
- if (ibuf) {
- if (index != IMA_NO_INDEX) {
- index = IMA_MAKE_INDEX(entry, index);
- }
-
- imagecache_put(ima, index, ibuf);
+ if (index != IMA_NO_INDEX) {
+ index = IMA_MAKE_INDEX(entry, index);
}
+
+ imagecache_put(ima, index, ibuf);
}
static void image_remove_ibuf(Image *ima, int index, int entry)
@@ -643,7 +708,9 @@ void BKE_image_merge(Main *bmain, Image *dest, Image *source)
{
/* sanity check */
if (dest && source && dest != source) {
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(source->runtime.cache_mutex);
+ BLI_mutex_lock(dest->runtime.cache_mutex);
+
if (source->cache != NULL) {
struct MovieCacheIter *iter;
iter = IMB_moviecacheIter_new(source->cache);
@@ -655,15 +722,19 @@ void BKE_image_merge(Main *bmain, Image *dest, Image *source)
}
IMB_moviecacheIter_free(iter);
}
- BLI_mutex_unlock(image_mutex);
+
+ BLI_mutex_unlock(dest->runtime.cache_mutex);
+ BLI_mutex_unlock(source->runtime.cache_mutex);
BKE_id_free(bmain, source);
}
}
-/* NOTE: We could be clever and scale all imbuf's but since some are mipmaps its not so simple. */
bool BKE_image_scale(Image *image, int width, int height)
{
+ /* NOTE: We could be clever and scale all imbuf's
+ * but since some are mipmaps its not so simple. */
+
ImBuf *ibuf;
void *lock;
@@ -762,9 +833,6 @@ int BKE_image_get_tile_from_pos(struct Image *ima,
return tile_number;
}
-/**
- * Return the tile_number for the closest UDIM tile.
- */
int BKE_image_find_nearest_tile(const Image *image, const float co[2])
{
const float co_floor[2] = {floorf(co[0]), floorf(co[1])};
@@ -847,9 +915,13 @@ Image *BKE_image_load(Main *bmain, const char *filepath)
/* exists? */
file = BLI_open(str, O_BINARY | O_RDONLY, 0);
if (file == -1) {
- return NULL;
+ if (!BKE_image_tile_filepath_exists(str)) {
+ return NULL;
+ }
+ }
+ else {
+ close(file);
}
- close(file);
ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE);
STRNCPY(ima->filepath, filepath);
@@ -863,17 +935,13 @@ Image *BKE_image_load(Main *bmain, const char *filepath)
return ima;
}
-/* checks if image was already loaded, then returns same image */
-/* otherwise creates new. */
-/* does not load ibuf itself */
-/* pass on optional frame for #name images */
Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
{
Image *ima;
char str[FILE_MAX], strtest[FILE_MAX];
STRNCPY(str, filepath);
- BLI_path_abs(str, bmain->name);
+ BLI_path_abs(str, bmain->filepath);
/* first search an identical filepath */
for (ima = bmain->images.first; ima; ima = ima->id.next) {
@@ -884,11 +952,6 @@ Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exist
if (BLI_path_cmp(strtest, str) == 0) {
if ((BKE_image_has_anim(ima) == false) || (ima->id.us == 0)) {
id_us_plus(&ima->id); /* officially should not, it doesn't link here! */
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- if (tile->ok == 0) {
- tile->ok = IMA_OK;
- }
- }
if (r_exists) {
*r_exists = true;
}
@@ -1018,7 +1081,6 @@ static ImBuf *add_ibuf_size(unsigned int width,
return ibuf;
}
-/* adds new image block, creates ImBuf and initializes color */
Image *BKE_image_add_generated(Main *bmain,
unsigned int width,
unsigned int height,
@@ -1076,17 +1138,9 @@ Image *BKE_image_add_generated(Main *bmain,
image_add_view(ima, names[view_id], "");
}
- ImageTile *tile = BKE_image_get_tile(ima, 0);
- tile->ok = IMA_OK_LOADED;
-
return ima;
}
-/**
- * Create an image from ibuf. The refcount of ibuf is increased,
- * caller should take care to drop its reference by calling
- * #IMB_freeImBuf if needed.
- */
Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
{
/* on save, type is changed to FILE in editsima.c */
@@ -1101,8 +1155,6 @@ Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
if (ima) {
STRNCPY(ima->filepath, ibuf->name);
image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
- ImageTile *tile = BKE_image_get_tile(ima, 0);
- tile->ok = IMA_OK_LOADED;
}
return ima;
@@ -1140,7 +1192,6 @@ static bool image_memorypack_imbuf(Image *ima, ImBuf *ibuf, const char *filepath
return true;
}
-/* Pack image to memory. */
bool BKE_image_memorypack(Image *ima)
{
bool ok = true;
@@ -1153,7 +1204,7 @@ bool BKE_image_memorypack(Image *ima)
int i;
for (i = 0, iv = ima->views.first; iv; iv = iv->next, i++) {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, i, 0);
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, i, 0, NULL);
if (!ibuf) {
ok = false;
@@ -1173,7 +1224,7 @@ bool BKE_image_memorypack(Image *ima)
ima->views_format = R_IMF_VIEWS_INDIVIDUAL;
}
else {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0);
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0, NULL);
if (ibuf) {
ok = ok && image_memorypack_imbuf(ima, ibuf, ibuf->name);
@@ -1256,12 +1307,17 @@ static uintptr_t image_mem_size(Image *image)
return 0;
}
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(image->runtime.cache_mutex);
+
if (image->cache != NULL) {
struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
while (!IMB_moviecacheIter_done(iter)) {
ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
+ IMB_moviecacheIter_step(iter);
+ if (ibuf == NULL) {
+ continue;
+ }
ImBuf *ibufm;
int level;
@@ -1283,12 +1339,11 @@ static uintptr_t image_mem_size(Image *image)
}
}
}
-
- IMB_moviecacheIter_step(iter);
}
IMB_moviecacheIter_free(iter);
}
- BLI_mutex_unlock(image_mutex);
+
+ BLI_mutex_unlock(image->runtime.cache_mutex);
return size;
}
@@ -1315,6 +1370,9 @@ void BKE_image_print_memlist(Main *bmain)
static bool imagecache_check_dirty(ImBuf *ibuf, void *UNUSED(userkey), void *UNUSED(userdata))
{
+ if (ibuf == NULL) {
+ return false;
+ }
return (ibuf->userflags & IB_BITMAPDIRTY) == 0;
}
@@ -1358,19 +1416,21 @@ void BKE_image_free_all_textures(Main *bmain)
static bool imagecache_check_free_anim(ImBuf *ibuf, void *UNUSED(userkey), void *userdata)
{
+ if (ibuf == NULL) {
+ return true;
+ }
int except_frame = *(int *)userdata;
return (ibuf->userflags & IB_BITMAPDIRTY) == 0 && (ibuf->index != IMA_NO_INDEX) &&
(except_frame != IMA_INDEX_ENTRY(ibuf->index));
}
-/* except_frame is weak, only works for seqs without offset... */
void BKE_image_free_anim_ibufs(Image *ima, int except_frame)
{
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(ima->runtime.cache_mutex);
if (ima->cache != NULL) {
IMB_moviecache_cleanup(ima->cache, imagecache_check_free_anim, &except_frame);
}
- BLI_mutex_unlock(image_mutex);
+ BLI_mutex_unlock(ima->runtime.cache_mutex);
}
void BKE_image_all_free_anim_ibufs(Main *bmain, int cfra)
@@ -1560,9 +1620,9 @@ bool BKE_imtype_requires_linear_float(const char imtype)
char BKE_imtype_valid_channels(const char imtype, bool write_file)
{
- char chan_flag = IMA_CHAN_FLAG_RGB; /* assume all support rgb */
+ char chan_flag = IMA_CHAN_FLAG_RGB; /* Assume all support RGB. */
- /* alpha */
+ /* Alpha. */
switch (imtype) {
case R_IMF_IMTYPE_BMP:
if (write_file) {
@@ -1583,7 +1643,7 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file)
break;
}
- /* bw */
+ /* BW. */
switch (imtype) {
case R_IMF_IMTYPE_BMP:
case R_IMF_IMTYPE_PNG:
@@ -1625,8 +1685,6 @@ char BKE_imtype_valid_depths(const char imtype)
}
}
-/* string is from command line --render-format arg, keep in sync with
- * creator_args.c help info */
char BKE_imtype_from_arg(const char *imtype_arg)
{
if (STREQ(imtype_arg, "TGA")) {
@@ -2037,9 +2095,10 @@ static void stampdata(
time_t t;
if (scene->r.stamp & R_STAMP_FILENAME) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
SNPRINTF(stamp_data->file,
do_prefix ? "File %s" : "%s",
- G.relbase_valid ? BKE_main_blendfile_path_from_global() : "<untitled>");
+ (blendfile_path[0] != '\0') ? blendfile_path : "<untitled>");
}
else {
stamp_data->file[0] = '\0';
@@ -2387,7 +2446,7 @@ void BKE_image_stamp_buf(Scene *scene,
/* and draw the text. */
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.file, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.file, sizeof(stamp_data.file));
/* the extra pixel for background. */
y -= BUFF_MARGIN_Y * 2;
@@ -2410,7 +2469,7 @@ void BKE_image_stamp_buf(Scene *scene,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.date, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.date, sizeof(stamp_data.date));
/* the extra pixel for background. */
y -= BUFF_MARGIN_Y * 2;
@@ -2433,7 +2492,7 @@ void BKE_image_stamp_buf(Scene *scene,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.rendertime, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.rendertime, sizeof(stamp_data.rendertime));
/* the extra pixel for background. */
y -= BUFF_MARGIN_Y * 2;
@@ -2456,7 +2515,7 @@ void BKE_image_stamp_buf(Scene *scene,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.memory, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.memory, sizeof(stamp_data.memory));
/* the extra pixel for background. */
y -= BUFF_MARGIN_Y * 2;
@@ -2479,7 +2538,7 @@ void BKE_image_stamp_buf(Scene *scene,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.hostname, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.hostname, sizeof(stamp_data.hostname));
/* the extra pixel for background. */
y -= BUFF_MARGIN_Y * 2;
@@ -2503,7 +2562,7 @@ void BKE_image_stamp_buf(Scene *scene,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs + (h - h_fixed), 0.0);
- BLF_draw_buffer(mono, stamp_data.note, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.note, sizeof(stamp_data.note));
}
BLF_disable(mono, BLF_WORD_WRAP);
@@ -2527,7 +2586,7 @@ void BKE_image_stamp_buf(Scene *scene,
/* and pad the text. */
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.marker, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.marker, sizeof(stamp_data.marker));
/* space width. */
x += w + pad;
@@ -2550,7 +2609,7 @@ void BKE_image_stamp_buf(Scene *scene,
/* and pad the text. */
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.time, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.time, sizeof(stamp_data.time));
/* space width. */
x += w + pad;
@@ -2572,7 +2631,7 @@ void BKE_image_stamp_buf(Scene *scene,
/* and pad the text. */
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.frame, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.frame, sizeof(stamp_data.frame));
/* space width. */
x += w + pad;
@@ -2592,7 +2651,7 @@ void BKE_image_stamp_buf(Scene *scene,
x + w + BUFF_MARGIN_X,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.camera, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.camera, sizeof(stamp_data.camera));
/* space width. */
x += w + pad;
@@ -2612,7 +2671,7 @@ void BKE_image_stamp_buf(Scene *scene,
x + w + BUFF_MARGIN_X,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.cameralens, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.cameralens, sizeof(stamp_data.cameralens));
}
if (TEXT_SIZE_CHECK(stamp_data.scene, w, h)) {
@@ -2634,7 +2693,7 @@ void BKE_image_stamp_buf(Scene *scene,
/* and pad the text. */
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.scene, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.scene, sizeof(stamp_data.scene));
}
if (TEXT_SIZE_CHECK(stamp_data.strip, w, h)) {
@@ -2656,7 +2715,7 @@ void BKE_image_stamp_buf(Scene *scene,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.strip, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.strip, sizeof(stamp_data.strip));
}
/* cleanup the buffer. */
@@ -2730,8 +2789,6 @@ static const char *stamp_metadata_fields[] = {
NULL,
};
-/* Check whether the given metadata field name translates to a known field of
- * a stamp. */
bool BKE_stamp_is_known_field(const char *field_name)
{
int i = 0;
@@ -2893,8 +2950,6 @@ bool BKE_imbuf_alpha_test(ImBuf *ibuf)
return false;
}
-/* NOTE: imf->planes is ignored here, its assumed the image channels
- * are already set */
void BKE_imbuf_write_prepare(ImBuf *ibuf, const ImageFormatData *imf)
{
char imtype = imf->imtype;
@@ -3071,15 +3126,12 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, const ImageFormatData *imf)
return ok;
}
-/* same as BKE_imbuf_write() but crappy workaround not to permanently modify
- * _some_, values in the imbuf */
int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf, const bool save_copy)
{
ImBuf ibuf_back = *ibuf;
int ok;
- /* all data is rgba anyway,
- * this just controls how to save for some formats */
+ /* All data is RGBA anyway, this just controls how to save for some formats. */
ibuf->planes = imf->planes;
ok = BKE_imbuf_write(ibuf, name, imf);
@@ -3172,7 +3224,6 @@ struct anim *openanim_noload(const char *name,
return anim;
}
-/* used by sequencer too */
struct anim *openanim(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE])
{
struct anim *anim;
@@ -3218,8 +3269,6 @@ struct anim *openanim(const char *name, int flags, int streamindex, char colorsp
* -> comes from packedfile or filename or generated
*/
-/* forces existence of 1 Image for renderout or nodes, returns Image */
-/* name is only for default, when making new one */
Image *BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
{
Image *ima;
@@ -3260,7 +3309,6 @@ static void image_viewer_create_views(const RenderData *rd, Image *ima)
}
}
-/* Reset the image cache and views when the Viewer Nodes views don't match the scene views */
void BKE_image_ensure_viewer_views(const RenderData *rd, Image *ima, ImageUser *iuser)
{
bool do_reset;
@@ -3290,7 +3338,7 @@ void BKE_image_ensure_viewer_views(const RenderData *rd, Image *ima, ImageUser *
}
if (do_reset) {
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(ima->runtime.cache_mutex);
image_free_cached_frames(ima);
BKE_image_free_views(ima);
@@ -3298,7 +3346,7 @@ void BKE_image_ensure_viewer_views(const RenderData *rd, Image *ima, ImageUser *
/* add new views */
image_viewer_create_views(rd, ima);
- BLI_mutex_unlock(image_mutex);
+ BLI_mutex_unlock(ima->runtime.cache_mutex);
}
BLI_thread_unlock(LOCK_DRAW_IMAGE);
@@ -3348,6 +3396,23 @@ static void image_walk_ntree_all_users(
}
}
+static void image_walk_gpu_materials(
+ ID *id,
+ ListBase *gpu_materials,
+ void *customdata,
+ void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata))
+{
+ LISTBASE_FOREACH (LinkData *, link, gpu_materials) {
+ GPUMaterial *gpu_material = (GPUMaterial *)link->data;
+ ListBase textures = GPU_material_textures(gpu_material);
+ LISTBASE_FOREACH (GPUMaterialTexture *, gpu_material_texture, &textures) {
+ if (gpu_material_texture->iuser_available) {
+ callback(gpu_material_texture->ima, id, &gpu_material_texture->iuser, customdata);
+ }
+ }
+ }
+}
+
static void image_walk_id_all_users(
ID *id,
bool skip_nested_nodes,
@@ -3367,6 +3432,7 @@ static void image_walk_id_all_users(
if (ma->nodetree && ma->use_nodes && !skip_nested_nodes) {
image_walk_ntree_all_users(ma->nodetree, &ma->id, customdata, callback);
}
+ image_walk_gpu_materials(id, &ma->gpumaterial, customdata, callback);
break;
}
case ID_LA: {
@@ -3381,6 +3447,7 @@ static void image_walk_id_all_users(
if (world->nodetree && world->use_nodes && !skip_nested_nodes) {
image_walk_ntree_all_users(world->nodetree, &world->id, customdata, callback);
}
+ image_walk_gpu_materials(id, &world->gpumaterial, customdata, callback);
break;
}
case ID_TE: {
@@ -3484,10 +3551,9 @@ static void image_tag_frame_recalc(Image *ima, ID *iuser_id, ImageUser *iuser, v
if (ima == changed_image && BKE_image_is_animated(ima)) {
iuser->flag |= IMA_NEED_FRAME_RECALC;
- iuser->ok = 1;
if (iuser_id) {
- /* Must copy image user changes to CoW datablock. */
+ /* Must copy image user changes to CoW data-block. */
DEG_id_tag_update(iuser_id, ID_RECALC_COPY_ON_WRITE);
}
}
@@ -3498,12 +3564,11 @@ static void image_tag_reload(Image *ima, ID *iuser_id, ImageUser *iuser, void *c
Image *changed_image = customdata;
if (ima == changed_image) {
- iuser->ok = 1;
if (iuser->scene) {
image_update_views_format(ima, iuser);
}
if (iuser_id) {
- /* Must copy image user changes to CoW datablock. */
+ /* Must copy image user changes to CoW data-block. */
DEG_id_tag_update(iuser_id, ID_RECALC_COPY_ON_WRITE);
}
}
@@ -3512,7 +3577,6 @@ static void image_tag_reload(Image *ima, ID *iuser_id, ImageUser *iuser, void *c
void BKE_imageuser_default(ImageUser *iuser)
{
memset(iuser, 0, sizeof(ImageUser));
- iuser->ok = 1;
iuser->frames = 100;
iuser->sfra = 1;
}
@@ -3565,14 +3629,13 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
return;
}
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(ima->runtime.cache_mutex);
switch (signal) {
case IMA_SIGNAL_FREE:
BKE_image_free_buffers(ima);
if (iuser) {
- iuser->ok = 1;
if (iuser->scene) {
image_update_views_format(ima, iuser);
}
@@ -3587,7 +3650,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
if (ima->source == IMA_SRC_GENERATED) {
if (ima->gen_x == 0 || ima->gen_y == 0) {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0);
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0, NULL);
if (ibuf) {
ima->gen_x = ibuf->x;
ima->gen_y = ibuf->y;
@@ -3627,10 +3690,6 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
*/
BKE_image_free_buffers(ima);
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- tile->ok = 1;
- }
-
if (iuser) {
image_tag_frame_recalc(ima, NULL, iuser, ima);
}
@@ -3671,6 +3730,43 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
BKE_image_free_buffers(ima);
}
+ if (ima->source == IMA_SRC_TILED) {
+ ListBase new_tiles = {NULL, NULL};
+ int new_start, new_range;
+
+ char filepath[FILE_MAX];
+ BLI_strncpy(filepath, ima->filepath, sizeof(filepath));
+ BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
+ bool result = BKE_image_get_tile_info(filepath, &new_tiles, &new_start, &new_range);
+ if (result) {
+ /* Because the prior and new list of tiles are both sparse sequences, we need to be sure
+ * to account for how the two sets might or might not overlap. To be complete, we start
+ * the refresh process by clearing all existing tiles, stopping when there's only 1 tile
+ * left. */
+ while (BKE_image_remove_tile(ima, ima->tiles.last)) {
+ ;
+ }
+
+ int remaining_tile_number = ((ImageTile *)ima->tiles.first)->tile_number;
+ bool needs_final_cleanup = true;
+
+ /* Add in all the new tiles. */
+ LISTBASE_FOREACH (LinkData *, new_tile, &new_tiles) {
+ int new_tile_number = POINTER_AS_INT(new_tile->data);
+ BKE_image_add_tile(ima, new_tile_number, NULL);
+ if (new_tile_number == remaining_tile_number) {
+ needs_final_cleanup = false;
+ }
+ }
+
+ /* Final cleanup if the prior remaining tile was never encountered in the new list. */
+ if (needs_final_cleanup) {
+ BKE_image_remove_tile(ima, BKE_image_get_tile(ima, remaining_tile_number));
+ }
+ }
+ BLI_freelistN(&new_tiles);
+ }
+
if (iuser) {
image_tag_reload(ima, NULL, iuser, ima);
}
@@ -3678,7 +3774,6 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
break;
case IMA_SIGNAL_USER_NEW_IMAGE:
if (iuser) {
- iuser->ok = 1;
if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
if (ima->type == IMA_TYPE_MULTILAYER) {
BKE_image_init_imageuser(ima, iuser);
@@ -3688,30 +3783,13 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
break;
case IMA_SIGNAL_COLORMANAGE:
BKE_image_free_buffers(ima);
-
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- tile->ok = 1;
- }
-
- if (iuser) {
- iuser->ok = 1;
- }
-
break;
}
- BLI_mutex_unlock(image_mutex);
+ BLI_mutex_unlock(ima->runtime.cache_mutex);
- /* don't use notifiers because they are not 100% sure to succeeded
- * this also makes sure all scenes are accounted for. */
- {
- Scene *scene;
- for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
- if (scene->nodetree) {
- nodeUpdateID(scene->nodetree, &ima->id);
- }
- }
- }
+ BKE_ntree_update_tag_id_changed(bmain, &ima->id);
+ BKE_ntree_update_main(bmain, NULL);
}
/* return renderpass for a given pass index and active view */
@@ -3772,6 +3850,57 @@ void BKE_image_get_tile_label(Image *ima, ImageTile *tile, char *label, int len_
}
}
+bool BKE_image_get_tile_info(char *filepath,
+ ListBase *udim_tiles,
+ int *udim_start,
+ int *udim_range)
+{
+ char filename[FILE_MAXFILE], dirname[FILE_MAXDIR];
+ BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
+
+ BKE_image_ensure_tile_token(filename);
+
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = BKE_image_get_tile_strformat(filename, &tile_format);
+
+ bool is_udim = true;
+ int min_udim = IMA_UDIM_MAX + 1;
+ int max_udim = 0;
+ int id;
+
+ struct direntry *dir;
+ uint totfile = BLI_filelist_dir_contents(dirname, &dir);
+ for (int i = 0; i < totfile; i++) {
+ if (!(dir[i].type & S_IFREG)) {
+ continue;
+ }
+
+ if (!BKE_image_get_tile_number_from_filepath(dir[i].relname, udim_pattern, tile_format, &id)) {
+ continue;
+ }
+
+ if (id < 1001 || id > IMA_UDIM_MAX) {
+ is_udim = false;
+ break;
+ }
+
+ BLI_addtail(udim_tiles, BLI_genericNodeN(POINTER_FROM_INT(id)));
+ min_udim = min_ii(min_udim, id);
+ max_udim = max_ii(max_udim, id);
+ }
+ BLI_filelist_free(dir, totfile);
+ MEM_SAFE_FREE(udim_pattern);
+
+ if (is_udim && min_udim <= IMA_UDIM_MAX) {
+ BLI_join_dirfile(filepath, FILE_MAX, dirname, filename);
+
+ *udim_start = min_udim;
+ *udim_range = max_udim - min_udim + 1;
+ return true;
+ }
+ return false;
+}
+
ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label)
{
if (ima->source != IMA_SRC_TILED) {
@@ -3796,7 +3925,6 @@ ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *la
}
ImageTile *tile = MEM_callocN(sizeof(ImageTile), "image new tile");
- tile->ok = IMA_OK;
tile->tile_number = tile_number;
if (next_tile) {
@@ -3861,14 +3989,14 @@ void BKE_image_reassign_tile(struct Image *ima, ImageTile *tile, int new_tile_nu
if (BKE_image_is_multiview(ima)) {
const int totviews = BLI_listbase_count(&ima->views);
for (int i = 0; i < totviews; i++) {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, i, old_tile_number);
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, i, old_tile_number, NULL);
image_remove_ibuf(ima, i, old_tile_number);
image_assign_ibuf(ima, ibuf, i, new_tile_number);
IMB_freeImBuf(ibuf);
}
}
else {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, 0, old_tile_number);
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, 0, old_tile_number, NULL);
image_remove_ibuf(ima, 0, old_tile_number);
image_assign_ibuf(ima, ibuf, 0, new_tile_number);
IMB_freeImBuf(ibuf);
@@ -3927,15 +4055,191 @@ bool BKE_image_fill_tile(struct Image *ima,
if (tile_ibuf != NULL) {
image_assign_ibuf(ima, tile_ibuf, 0, tile->tile_number);
BKE_image_release_ibuf(ima, tile_ibuf, NULL);
- tile->ok = IMA_OK;
return true;
}
return false;
}
+void BKE_image_ensure_tile_token(char *filename)
+{
+ BLI_assert_msg(BLI_path_slash_find(filename) == NULL,
+ "Only the file-name component should be used!");
+
+ /* Is there a '<' character in the filename? Assume tokens already present. */
+ if (strstr(filename, "<") != NULL) {
+ return;
+ }
+
+ /* Is there a sequence of digits in the filename? */
+ ushort digits;
+ char head[FILE_MAX], tail[FILE_MAX];
+ BLI_path_sequence_decode(filename, head, tail, &digits);
+ if (digits == 4) {
+ sprintf(filename, "%s<UDIM>%s", head, tail);
+ return;
+ }
+
+ /* Is there a sequence like u##_v#### in the filename? */
+ uint cur = 0;
+ uint name_end = strlen(filename);
+ uint u_digits = 0;
+ uint v_digits = 0;
+ uint u_start = (uint)-1;
+ bool u_found = false;
+ bool v_found = false;
+ bool sep_found = false;
+ while (cur < name_end) {
+ if (filename[cur] == 'u') {
+ u_found = true;
+ u_digits = 0;
+ u_start = cur;
+ }
+ else if (filename[cur] == 'v') {
+ v_found = true;
+ v_digits = 0;
+ }
+ else if (u_found && !v_found) {
+ if (isdigit(filename[cur]) && u_digits < 2) {
+ u_digits++;
+ }
+ else if (filename[cur] == '_') {
+ sep_found = true;
+ }
+ else {
+ u_found = false;
+ }
+ }
+ else if (u_found && u_digits > 0 && v_found) {
+ if (isdigit(filename[cur])) {
+ if (v_digits < 4) {
+ v_digits++;
+ }
+ else {
+ u_found = false;
+ v_found = false;
+ }
+ }
+ else if (v_digits > 0) {
+ break;
+ }
+ }
+
+ cur++;
+ }
+
+ if (u_found && sep_found && v_found && (u_digits + v_digits > 1)) {
+ const char *token = "<UVTILE>";
+ const size_t token_length = strlen(token);
+ memmove(filename + u_start + token_length, filename + cur, name_end - cur);
+ memcpy(filename + u_start, token, token_length);
+ filename[u_start + token_length + (name_end - cur)] = '\0';
+ }
+}
+
+bool BKE_image_tile_filepath_exists(const char *filepath)
+{
+ BLI_assert(!BLI_path_is_rel(filepath));
+
+ char dirname[FILE_MAXDIR];
+ BLI_split_dir_part(filepath, dirname, sizeof(dirname));
+
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = BKE_image_get_tile_strformat(filepath, &tile_format);
+
+ bool found = false;
+ struct direntry *dir;
+ uint totfile = BLI_filelist_dir_contents(dirname, &dir);
+ for (int i = 0; i < totfile; i++) {
+ if (!(dir[i].type & S_IFREG)) {
+ continue;
+ }
+
+ int id;
+ if (!BKE_image_get_tile_number_from_filepath(dir[i].path, udim_pattern, tile_format, &id)) {
+ continue;
+ }
+
+ if (id < 1001 || id > IMA_UDIM_MAX) {
+ continue;
+ }
+
+ found = true;
+ break;
+ }
+ BLI_filelist_free(dir, totfile);
+ MEM_SAFE_FREE(udim_pattern);
+
+ return found;
+}
+
+char *BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format)
+{
+ if (filepath == NULL || r_tile_format == NULL) {
+ return NULL;
+ }
+
+ if (strstr(filepath, "<UDIM>") != NULL) {
+ *r_tile_format = UDIM_TILE_FORMAT_UDIM;
+ return BLI_str_replaceN(filepath, "<UDIM>", "%d");
+ }
+ if (strstr(filepath, "<UVTILE>") != NULL) {
+ *r_tile_format = UDIM_TILE_FORMAT_UVTILE;
+ return BLI_str_replaceN(filepath, "<UVTILE>", "u%d_v%d");
+ }
+
+ *r_tile_format = UDIM_TILE_FORMAT_NONE;
+ return NULL;
+}
+
+bool BKE_image_get_tile_number_from_filepath(const char *filepath,
+ const char *pattern,
+ eUDIM_TILE_FORMAT tile_format,
+ int *r_tile_number)
+{
+ if (filepath == NULL || pattern == NULL || r_tile_number == NULL) {
+ return false;
+ }
+
+ int u, v;
+ bool result = false;
+
+ if (tile_format == UDIM_TILE_FORMAT_UDIM) {
+ if (sscanf(filepath, pattern, &u) == 1) {
+ *r_tile_number = u;
+ result = true;
+ }
+ }
+ else if (tile_format == UDIM_TILE_FORMAT_UVTILE) {
+ if (sscanf(filepath, pattern, &u, &v) == 2) {
+ *r_tile_number = 1001 + (u - 1) + ((v - 1) * 10);
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+void BKE_image_set_filepath_from_tile_number(char *filepath,
+ const char *pattern,
+ eUDIM_TILE_FORMAT tile_format,
+ int tile_number)
+{
+ if (filepath == NULL || pattern == NULL) {
+ return;
+ }
+
+ if (tile_format == UDIM_TILE_FORMAT_UDIM) {
+ sprintf(filepath, pattern, tile_number);
+ }
+ else if (tile_format == UDIM_TILE_FORMAT_UVTILE) {
+ int u = ((tile_number - 1001) % 10);
+ int v = ((tile_number - 1001) / 10);
+ sprintf(filepath, pattern, u + 1, v + 1);
+ }
+}
+
/* if layer or pass changes, we need an index for the imbufs list */
/* note it is called for rendered results, but it doesn't use the index! */
-/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
{
RenderLayer *rl;
@@ -3990,7 +4294,6 @@ void BKE_image_multiview_index(Image *ima, ImageUser *iuser)
/* if layer or pass changes, we need an index for the imbufs list */
/* note it is called for rendered results, but it doesn't use the index! */
-/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
bool BKE_image_is_multilayer(Image *ima)
{
if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
@@ -4205,9 +4508,7 @@ static void image_init_after_load(Image *ima, ImageUser *iuser, ImBuf *UNUSED(ib
/* Images should never get loaded if the corresponding tile does not exist,
* but we should at least not crash if it happens due to a bug elsewhere. */
BLI_assert(tile != NULL);
- if (tile != NULL) {
- tile->ok = IMA_OK_LOADED;
- }
+ UNUSED_VARS_NDEBUG(tile);
}
static int imbuf_alpha_flags_for_image(Image *ima)
@@ -4243,13 +4544,15 @@ static int image_num_files(Image *ima)
}
static ImBuf *load_sequence_single(
- Image *ima, ImageUser *iuser, int frame, const int view_id, bool *r_assign)
+ Image *ima, ImageUser *iuser, int frame, const int view_id, bool *r_cache_ibuf)
{
struct ImBuf *ibuf;
char name[FILE_MAX];
int flag;
ImageUser iuser_t = {0};
+ *r_cache_ibuf = true;
+
ima->lastframe = frame;
if (iuser) {
@@ -4289,23 +4592,18 @@ static ImBuf *load_sequence_single(
ima->type = IMA_TYPE_MULTILAYER;
IMB_freeImBuf(ibuf);
ibuf = NULL;
+ /* NULL ibuf in the cache means the image failed to load. However for multilayer we load
+ * pixels into RenderResult instead and intentionally leave ibuf NULL. */
+ *r_cache_ibuf = false;
}
}
else {
image_init_after_load(ima, iuser, ibuf);
- *r_assign = true;
}
#else
image_init_after_load(ima, iuser, ibuf);
- *r_assign = true;
#endif
}
- else {
- ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
- if (tile != NULL) {
- tile->ok = 0;
- }
- }
return ibuf;
}
@@ -4315,11 +4613,11 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry,
struct ImBuf *ibuf = NULL;
const bool is_multiview = BKE_image_is_multiview(ima);
const int totfiles = image_num_files(ima);
- bool assign = false;
if (!is_multiview) {
- ibuf = load_sequence_single(ima, iuser, frame, 0, &assign);
- if (assign) {
+ bool put_in_cache;
+ ibuf = load_sequence_single(ima, iuser, frame, 0, &put_in_cache);
+ if (put_in_cache) {
image_assign_ibuf(ima, ibuf, 0, entry);
}
}
@@ -4328,9 +4626,10 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry,
struct ImBuf **ibuf_arr;
ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
+ bool *cache_ibuf_arr = MEM_mallocN(sizeof(bool) * totviews, "Image View Put In Cache");
for (int i = 0; i < totfiles; i++) {
- ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, &assign);
+ ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, cache_ibuf_arr + i);
}
if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D) {
@@ -4340,8 +4639,8 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry,
/* return the original requested ImBuf */
ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)];
- if (assign) {
- for (int i = 0; i < totviews; i++) {
+ for (int i = 0; i < totviews; i++) {
+ if (cache_ibuf_arr[i]) {
image_assign_ibuf(ima, ibuf_arr[i], i, entry);
}
}
@@ -4355,6 +4654,7 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry,
/* cleanup */
MEM_freeN(ibuf_arr);
+ MEM_freeN(cache_ibuf_arr);
}
return ibuf;
@@ -4363,7 +4663,6 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry,
static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int entry, int frame)
{
struct ImBuf *ibuf = NULL;
- ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
/* either we load from RenderResult, or we have to load a new one */
@@ -4405,13 +4704,6 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int e
}
// else printf("pass not found\n");
}
- else {
- tile->ok = 0;
- }
-
- if (iuser) {
- iuser->ok = tile->ok;
- }
return ibuf;
}
@@ -4423,8 +4715,6 @@ static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const i
ia = BLI_findlink(&ima->anims, view_id);
- ImageTile *tile = BKE_image_get_tile(ima, 0);
-
if (ia->anim == NULL) {
char str[FILE_MAX];
int flags = IB_rect;
@@ -4466,12 +4756,6 @@ static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const i
if (ibuf) {
image_init_after_load(ima, iuser, ibuf);
}
- else {
- tile->ok = 0;
- }
- }
- else {
- tile->ok = 0;
}
return ibuf;
@@ -4482,7 +4766,6 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
struct ImBuf *ibuf = NULL;
const bool is_multiview = BKE_image_is_multiview(ima);
const int totfiles = image_num_files(ima);
- ImageTile *tile = BKE_image_get_tile(ima, 0);
if (totfiles != BLI_listbase_count_at_most(&ima->anims, totfiles + 1)) {
image_free_anims(ima);
@@ -4513,12 +4796,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
}
for (int i = 0; i < totviews; i++) {
- if (ibuf_arr[i]) {
- image_assign_ibuf(ima, ibuf_arr[i], i, frame);
- }
- else {
- tile->ok = 0;
- }
+ image_assign_ibuf(ima, ibuf_arr[i], i, frame);
}
/* return the original requested ImBuf */
@@ -4535,10 +4813,6 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
MEM_freeN(ibuf_arr);
}
- if (iuser) {
- iuser->ok = tile->ok;
- }
-
return ibuf;
}
@@ -4547,12 +4821,14 @@ static ImBuf *load_image_single(Image *ima,
int cfra,
const int view_id,
const bool has_packed,
- bool *r_assign)
+ bool *r_cache_ibuf)
{
char filepath[FILE_MAX];
struct ImBuf *ibuf = NULL;
int flag;
+ *r_cache_ibuf = true;
+
/* is there a PackedFile with this image ? */
if (has_packed) {
ImagePackedFile *imapf;
@@ -4603,15 +4879,17 @@ static ImBuf *load_image_single(Image *ima,
ima->type = IMA_TYPE_MULTILAYER;
IMB_freeImBuf(ibuf);
ibuf = NULL;
+ /* NULL ibuf in the cache means the image failed to load. However for multilayer we load
+ * pixels into RenderResult instead and intentionally leave ibuf NULL. */
+ *r_cache_ibuf = false;
}
}
else
#endif
{
image_init_after_load(ima, iuser, ibuf);
- *r_assign = true;
- /* make packed file for autopack */
+ /* Make packed file for auto-pack. */
if ((has_packed == false) && (G.fileflags & G_FILE_AUTOPACK)) {
ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Pack-file");
BLI_addtail(&ima->packedfiles, imapf);
@@ -4622,10 +4900,6 @@ static ImBuf *load_image_single(Image *ima,
}
}
}
- else {
- ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
- tile->ok = 0;
- }
return ibuf;
}
@@ -4636,7 +4910,6 @@ static ImBuf *load_image_single(Image *ima,
static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
{
struct ImBuf *ibuf = NULL;
- bool assign = false;
const bool is_multiview = BKE_image_is_multiview(ima);
const int totfiles = image_num_files(ima);
bool has_packed = BKE_image_has_packedfile(ima);
@@ -4653,8 +4926,9 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
}
if (!is_multiview) {
- ibuf = load_image_single(ima, iuser, cfra, 0, has_packed, &assign);
- if (assign) {
+ bool put_in_cache;
+ ibuf = load_image_single(ima, iuser, cfra, 0, has_packed, &put_in_cache);
+ if (put_in_cache) {
image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
}
}
@@ -4664,9 +4938,10 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
BLI_assert(totviews > 0);
ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
+ bool *cache_ibuf_arr = MEM_mallocN(sizeof(bool) * totviews, "Image Views Put In Cache");
for (int i = 0; i < totfiles; i++) {
- ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, &assign);
+ ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, cache_ibuf_arr + i);
}
/* multi-views/multi-layers OpenEXR files directly populate ima, and return NULL ibuf... */
@@ -4679,8 +4954,8 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
int i = (iuser && iuser->multi_index < totviews) ? iuser->multi_index : 0;
ibuf = ibuf_arr[i];
- if (assign) {
- for (i = 0; i < totviews; i++) {
+ for (i = 0; i < totviews; i++) {
+ if (cache_ibuf_arr[i]) {
image_assign_ibuf(ima, ibuf_arr[i], i, 0);
}
}
@@ -4694,11 +4969,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
/* cleanup */
MEM_freeN(ibuf_arr);
- }
-
- if (iuser) {
- ImageTile *tile = BKE_image_get_tile(ima, 0);
- iuser->ok = tile->ok;
+ MEM_freeN(cache_ibuf_arr);
}
return ibuf;
@@ -4733,14 +5004,6 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
}
}
- ImageTile *tile = BKE_image_get_tile(ima, 0);
- if (ibuf == NULL) {
- tile->ok = 0;
- }
- if (iuser) {
- iuser->ok = tile->ok;
- }
-
return ibuf;
}
@@ -4858,7 +5121,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
}
}
- ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0, NULL);
/* make ibuf if needed, and initialize it */
if (ibuf == NULL) {
@@ -4935,9 +5198,6 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
ibuf->dither = dither;
- ImageTile *tile = BKE_image_get_tile(ima, 0);
- tile->ok = IMA_OK_LOADED;
-
return ibuf;
}
@@ -4994,7 +5254,8 @@ static void image_get_entry_and_index(Image *ima, ImageUser *iuser, int *r_entry
* call IMB_freeImBuf to de-reference the image buffer after
* it's done handling it.
*/
-static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_entry, int *r_index)
+static ImBuf *image_get_cached_ibuf(
+ Image *ima, ImageUser *iuser, int *r_entry, int *r_index, bool *r_is_cached_empty)
{
ImBuf *ibuf = NULL;
int entry = 0, index = image_get_multiview_index(ima, iuser);
@@ -5002,42 +5263,30 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_entry,
/* see if we already have an appropriate ibuf, with image source and type */
if (ima->source == IMA_SRC_MOVIE) {
entry = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry, r_is_cached_empty);
ima->lastframe = entry;
}
else if (ima->source == IMA_SRC_SEQUENCE) {
if (ima->type == IMA_TYPE_IMAGE) {
entry = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry, r_is_cached_empty);
ima->lastframe = entry;
-
- /* counter the fact that image is set as invalid when loading a frame
- * that is not in the cache (through image_acquire_ibuf for instance),
- * yet we have valid frames in the cache loaded */
- if (ibuf) {
- ImageTile *tile = BKE_image_get_tile(ima, 0);
- tile->ok = IMA_OK_LOADED;
-
- if (iuser) {
- iuser->ok = tile->ok;
- }
- }
}
else if (ima->type == IMA_TYPE_MULTILAYER) {
entry = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry, r_is_cached_empty);
}
}
else if (ima->source == IMA_SRC_FILE) {
if (ima->type == IMA_TYPE_IMAGE) {
- ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0, r_is_cached_empty);
}
else if (ima->type == IMA_TYPE_MULTILAYER) {
- ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0, r_is_cached_empty);
}
}
else if (ima->source == IMA_SRC_GENERATED) {
- ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, 0, r_is_cached_empty);
}
else if (ima->source == IMA_SRC_VIEWER) {
/* always verify entirely, not that this shouldn't happen
@@ -5047,17 +5296,7 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_entry,
else if (ima->source == IMA_SRC_TILED) {
if (ELEM(ima->type, IMA_TYPE_IMAGE, IMA_TYPE_MULTILAYER)) {
entry = image_get_tile_number_from_iuser(ima, iuser);
- ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
-
- if ((ima->type == IMA_TYPE_IMAGE) && ibuf != NULL) {
- ImageTile *tile = BKE_image_get_tile(ima, entry);
- tile->ok = IMA_OK_LOADED;
-
- /* iuser->ok is useless for tiled images because iuser->tile changes all the time. */
- if (iuser != NULL) {
- iuser->ok = 1;
- }
- }
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry, r_is_cached_empty);
}
}
@@ -5078,26 +5317,18 @@ BLI_INLINE bool image_quick_test(Image *ima, const ImageUser *iuser)
return false;
}
- if (iuser) {
- if (iuser->ok == 0) {
- return false;
- }
- }
-
ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
if (tile == NULL) {
return false;
}
- if (tile->ok == 0) {
- return false;
- }
return true;
}
-/* Checks optional ImageUser and verifies/creates ImBuf.
+/**
+ * Checks optional #ImageUser and verifies/creates #ImBuf.
*
- * not thread-safe, so callee should worry about thread locks
+ * \warning Not thread-safe, so callee should worry about thread locks.
*/
static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
@@ -5113,7 +5344,11 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
return NULL;
}
- ibuf = image_get_cached_ibuf(ima, iuser, &entry, &index);
+ bool is_cached_empty = false;
+ ibuf = image_get_cached_ibuf(ima, iuser, &entry, &index, &is_cached_empty);
+ if (is_cached_empty) {
+ return NULL;
+ }
if (ibuf == NULL) {
/* we are sure we have to load the ibuf, using source and type */
@@ -5175,8 +5410,6 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
ima->gen_color,
&ima->colorspace_settings);
image_assign_ibuf(ima, ibuf, index, 0);
- ImageTile *tile = BKE_image_get_tile(ima, 0);
- tile->ok = IMA_OK_LOADED;
}
else if (ima->source == IMA_SRC_VIEWER) {
if (ima->type == IMA_TYPE_R_RESULT) {
@@ -5193,7 +5426,7 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
/* XXX anim play for viewer nodes not yet supported */
entry = 0; // XXX iuser ? iuser->framenr : 0;
- ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry);
+ ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry, NULL);
if (!ibuf) {
/* Composite Viewer, all handled in compositor */
@@ -5216,22 +5449,22 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
return ibuf;
}
-/* return image buffer for given image and user
- *
- * - will lock render result if image type is render result and lock is not NULL
- * - will return NULL if image type if render or composite result and lock is NULL
- *
- * references the result, BKE_image_release_ibuf should be used to de-reference
- */
ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
+ /* NOTE: same as #image_acquire_ibuf, but can be used to retrieve images being rendered in
+ * a thread safe way, always call both acquire and release. */
+
+ if (ima == NULL) {
+ return NULL;
+ }
+
ImBuf *ibuf;
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(ima->runtime.cache_mutex);
ibuf = image_acquire_ibuf(ima, iuser, r_lock);
- BLI_mutex_unlock(image_mutex);
+ BLI_mutex_unlock(ima->runtime.cache_mutex);
return ibuf;
}
@@ -5250,13 +5483,12 @@ void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
}
if (ibuf) {
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(ima->runtime.cache_mutex);
IMB_freeImBuf(ibuf);
- BLI_mutex_unlock(image_mutex);
+ BLI_mutex_unlock(ima->runtime.cache_mutex);
}
}
-/* checks whether there's an image buffer for given image and user */
bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser)
{
ImBuf *ibuf;
@@ -5266,15 +5498,15 @@ bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser)
return false;
}
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(ima->runtime.cache_mutex);
- ibuf = image_get_cached_ibuf(ima, iuser, NULL, NULL);
+ ibuf = image_get_cached_ibuf(ima, iuser, NULL, NULL, NULL);
if (!ibuf) {
ibuf = image_acquire_ibuf(ima, iuser, NULL);
}
- BLI_mutex_unlock(image_mutex);
+ BLI_mutex_unlock(ima->runtime.cache_mutex);
IMB_freeImBuf(ibuf);
@@ -5294,6 +5526,7 @@ typedef struct ImagePoolItem {
typedef struct ImagePool {
ListBase image_buffers;
BLI_mempool *memory_pool;
+ ThreadMutex mutex;
} ImagePool;
ImagePool *BKE_image_pool_new(void)
@@ -5301,21 +5534,28 @@ ImagePool *BKE_image_pool_new(void)
ImagePool *pool = MEM_callocN(sizeof(ImagePool), "Image Pool");
pool->memory_pool = BLI_mempool_create(sizeof(ImagePoolItem), 0, 128, BLI_MEMPOOL_NOP);
+ BLI_mutex_init(&pool->mutex);
+
return pool;
}
void BKE_image_pool_free(ImagePool *pool)
{
/* Use single lock to dereference all the image buffers. */
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(&pool->mutex);
for (ImagePoolItem *item = pool->image_buffers.first; item != NULL; item = item->next) {
if (item->ibuf != NULL) {
+ BLI_mutex_lock(item->image->runtime.cache_mutex);
IMB_freeImBuf(item->ibuf);
+ BLI_mutex_unlock(item->image->runtime.cache_mutex);
}
}
- BLI_mutex_unlock(image_mutex);
+ BLI_mutex_unlock(&pool->mutex);
BLI_mempool_destroy(pool->memory_pool);
+
+ BLI_mutex_end(&pool->mutex);
+
MEM_freeN(pool);
}
@@ -5347,28 +5587,34 @@ ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool
}
if (pool == NULL) {
- /* pool could be NULL, in this case use general acquire function */
+ /* Pool could be NULL, in this case use general acquire function. */
return BKE_image_acquire_ibuf(ima, iuser, NULL);
}
image_get_entry_and_index(ima, iuser, &entry, &index);
+ /* Use double-checked locking, to avoid locking when the requested image buffer is already in the
+ * pool. */
+
ibuf = image_pool_find_item(pool, ima, entry, index, &found);
if (found) {
return ibuf;
}
- BLI_mutex_lock(image_mutex);
+ /* Lock the pool, to allow thread-safe modification of the content of the pool. */
+ BLI_mutex_lock(&pool->mutex);
ibuf = image_pool_find_item(pool, ima, entry, index, &found);
- /* will also create item even in cases image buffer failed to load,
- * prevents trying to load the same buggy file multiple times
- */
+ /* Will also create item even in cases image buffer failed to load,
+ * prevents trying to load the same buggy file multiple times. */
if (!found) {
ImagePoolItem *item;
- ibuf = image_acquire_ibuf(ima, iuser, NULL);
+ /* Thread-safe acquisition of an image buffer from the image.
+ * The acquisition does not use image pools, so there is no risk of recursive or out-of-order
+ * mutex locking. */
+ ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
item = BLI_mempool_alloc(pool->memory_pool);
item->image = ima;
@@ -5379,7 +5625,7 @@ ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool
BLI_addtail(&pool->image_buffers, item);
}
- BLI_mutex_unlock(image_mutex);
+ BLI_mutex_unlock(&pool->mutex);
return ibuf;
}
@@ -5489,18 +5735,6 @@ void BKE_image_user_frame_calc(Image *ima, ImageUser *iuser, int cfra)
ima->gpuframenr = iuser->framenr;
}
- if (iuser->ok == 0) {
- iuser->ok = 1;
- }
-
- if (ima) {
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- if (tile->ok == 0) {
- tile->ok = IMA_OK;
- }
- }
- }
-
iuser->flag &= ~IMA_NEED_FRAME_RECALC;
}
}
@@ -5539,7 +5773,7 @@ static void image_user_id_has_animation(Image *ima,
bool BKE_image_user_id_has_animation(ID *id)
{
/* For the dependency graph, this does not consider nested node
- * trees as these are handled as their own datablock. */
+ * trees as these are handled as their own data-block. */
bool has_animation = false;
bool skip_nested_nodes = true;
image_walk_id_all_users(id, skip_nested_nodes, &has_animation, image_user_id_has_animation);
@@ -5576,6 +5810,11 @@ void BKE_image_user_id_eval_animation(Depsgraph *depsgraph, ID *id)
void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
{
+ BKE_image_user_file_path_ex(iuser, ima, filepath, true);
+}
+
+void BKE_image_user_file_path_ex(ImageUser *iuser, Image *ima, char *filepath, bool resolve_udim)
+{
if (BKE_image_is_multiview(ima)) {
ImageView *iv = BLI_findlink(&ima->views, iuser->view);
if (iv->filepath[0]) {
@@ -5596,13 +5835,17 @@ void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
int index;
if (ima->source == IMA_SRC_SEQUENCE) {
index = iuser ? iuser->framenr : ima->lastframe;
+ BLI_path_sequence_decode(filepath, head, tail, &numlen);
+ BLI_path_sequence_encode(filepath, head, tail, numlen, index);
}
- else {
+ else if (resolve_udim) {
index = image_get_tile_number_from_iuser(ima, iuser);
- }
- BLI_path_sequence_decode(filepath, head, tail, &numlen);
- BLI_path_sequence_encode(filepath, head, tail, numlen, index);
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = BKE_image_get_tile_strformat(filepath, &tile_format);
+ BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, tile_format, index);
+ MEM_SAFE_FREE(udim_pattern);
+ }
}
BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
@@ -5750,7 +5993,7 @@ bool BKE_image_has_anim(Image *ima)
return (BLI_listbase_is_empty(&ima->anims) == false);
}
-bool BKE_image_has_packedfile(Image *ima)
+bool BKE_image_has_packedfile(const Image *ima)
{
return (BLI_listbase_is_empty(&ima->packedfiles) == false);
}
@@ -5762,31 +6005,28 @@ bool BKE_image_has_filepath(Image *ima)
return ima->filepath[0] != '\0';
}
-/* Checks the image buffer changes with time (not keyframed values). */
bool BKE_image_is_animated(Image *image)
{
return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE);
}
-/* Checks whether the image consists of multiple buffers. */
bool BKE_image_has_multiple_ibufs(Image *image)
{
return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED);
}
-/* Image modifications */
bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable)
{
bool is_dirty = false;
bool is_writable = false;
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(image->runtime.cache_mutex);
if (image->cache != NULL) {
struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
while (!IMB_moviecacheIter_done(iter)) {
ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
- if (ibuf->userflags & IB_BITMAPDIRTY) {
+ if (ibuf != NULL && ibuf->userflags & IB_BITMAPDIRTY) {
is_writable = BKE_image_buffer_format_writable(ibuf);
is_dirty = true;
break;
@@ -5795,7 +6035,7 @@ bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable)
}
IMB_moviecacheIter_free(iter);
}
- BLI_mutex_unlock(image_mutex);
+ BLI_mutex_unlock(image->runtime.cache_mutex);
if (r_is_writable) {
*r_is_writable = is_writable;
@@ -5824,55 +6064,57 @@ bool BKE_image_buffer_format_writable(ImBuf *ibuf)
void BKE_image_file_format_set(Image *image, int ftype, const ImbFormatOptions *options)
{
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(image->runtime.cache_mutex);
if (image->cache != NULL) {
struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
while (!IMB_moviecacheIter_done(iter)) {
ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
- ibuf->ftype = ftype;
- ibuf->foptions = *options;
+ if (ibuf != NULL) {
+ ibuf->ftype = ftype;
+ ibuf->foptions = *options;
+ }
IMB_moviecacheIter_step(iter);
}
IMB_moviecacheIter_free(iter);
}
- BLI_mutex_unlock(image_mutex);
+ BLI_mutex_unlock(image->runtime.cache_mutex);
}
bool BKE_image_has_loaded_ibuf(Image *image)
{
bool has_loaded_ibuf = false;
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(image->runtime.cache_mutex);
if (image->cache != NULL) {
struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
while (!IMB_moviecacheIter_done(iter)) {
- has_loaded_ibuf = true;
- break;
+ ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
+ if (ibuf != NULL) {
+ has_loaded_ibuf = true;
+ break;
+ }
+ IMB_moviecacheIter_step(iter);
}
IMB_moviecacheIter_free(iter);
}
- BLI_mutex_unlock(image_mutex);
+ BLI_mutex_unlock(image->runtime.cache_mutex);
return has_loaded_ibuf;
}
-/**
- * References the result, #BKE_image_release_ibuf is to be called to de-reference.
- * Use lock=NULL when calling #BKE_image_release_ibuf().
- */
ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name)
{
ImBuf *ibuf = NULL;
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(image->runtime.cache_mutex);
if (image->cache != NULL) {
struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
while (!IMB_moviecacheIter_done(iter)) {
ImBuf *current_ibuf = IMB_moviecacheIter_getImBuf(iter);
- if (STREQ(current_ibuf->name, name)) {
+ if (current_ibuf != NULL && STREQ(current_ibuf->name, name)) {
ibuf = current_ibuf;
IMB_refImBuf(ibuf);
break;
@@ -5881,36 +6123,29 @@ ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name)
}
IMB_moviecacheIter_free(iter);
}
- BLI_mutex_unlock(image_mutex);
+ BLI_mutex_unlock(image->runtime.cache_mutex);
return ibuf;
}
-/**
- * References the result, #BKE_image_release_ibuf is to be called to de-reference.
- * Use lock=NULL when calling #BKE_image_release_ibuf().
- *
- * TODO(sergey): This is actually "get first item from the cache", which is
- * not so much predictable. But using first loaded image buffer
- * was also malicious logic and all the areas which uses this
- * function are to be re-considered.
- */
ImBuf *BKE_image_get_first_ibuf(Image *image)
{
ImBuf *ibuf = NULL;
- BLI_mutex_lock(image_mutex);
+ BLI_mutex_lock(image->runtime.cache_mutex);
if (image->cache != NULL) {
struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
while (!IMB_moviecacheIter_done(iter)) {
ibuf = IMB_moviecacheIter_getImBuf(iter);
- IMB_refImBuf(ibuf);
+ if (ibuf != NULL) {
+ IMB_refImBuf(ibuf);
+ }
break;
}
IMB_moviecacheIter_free(iter);
}
- BLI_mutex_unlock(image_mutex);
+ BLI_mutex_unlock(image->runtime.cache_mutex);
return ibuf;
}
diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c
index 1a0cc8c2924..bef14b6ad70 100644
--- a/source/blender/blenkernel/intern/image_gen.c
+++ b/source/blender/blenkernel/intern/image_gen.c
@@ -101,13 +101,12 @@ static void image_buf_fill_checker_slice(
/* these two passes could be combined into one, but it's more readable and
* easy to tweak like this, speed isn't really that much of an issue in this situation... */
- int checkerwidth = 32, dark = 1;
+ int checkerwidth = 32;
int x, y;
unsigned char *rect_orig = rect;
float *rect_float_orig = rect_float;
- float h = 0.0, hoffs = 0.0;
float hsv[3] = {0.0f, 0.9f, 0.9f};
float rgb[3];
@@ -119,7 +118,7 @@ static void image_buf_fill_checker_slice(
/* checkers */
for (y = offset; y < height + offset; y++) {
- dark = powf(-1.0f, floorf(y / checkerwidth));
+ int dark = powf(-1.0f, floorf(y / checkerwidth));
for (x = 0; x < width; x++) {
if (x % checkerwidth == 0) {
@@ -156,10 +155,10 @@ static void image_buf_fill_checker_slice(
/* 2nd pass, colored + */
for (y = offset; y < height + offset; y++) {
- hoffs = 0.125f * floorf(y / checkerwidth);
+ float hoffs = 0.125f * floorf(y / checkerwidth);
for (x = 0; x < width; x++) {
- h = 0.125f * floorf(x / checkerwidth);
+ float h = 0.125f * floorf(x / checkerwidth);
if ((abs((x % checkerwidth) - (checkerwidth / 2)) < 4) &&
(abs((y % checkerwidth) - (checkerwidth / 2)) < 4)) {
@@ -370,7 +369,7 @@ static void checker_board_text(
char text[3] = {'A', '1', '\0'};
const int mono = blf_mono_font_render;
- BLF_size(mono, 54, 72); /* hard coded size! */
+ BLF_size(mono, 54.0f, 72); /* hard coded size! */
/* OCIO_TODO: using NULL as display will assume using sRGB display
* this is correct since currently generated images are assumed to be in sRGB space,
diff --git a/source/blender/blenkernel/intern/image_gpu.c b/source/blender/blenkernel/intern/image_gpu.cc
index 9712e912bed..c82de02e52a 100644
--- a/source/blender/blenkernel/intern/image_gpu.c
+++ b/source/blender/blenkernel/intern/image_gpu.cc
@@ -47,7 +47,7 @@
#include "PIL_time.h"
/* Prototypes. */
-static void gpu_free_unused_buffers(void);
+static void gpu_free_unused_buffers();
static void image_free_gpu(Image *ima, const bool immediate);
static void image_free_gpu_limited_scale(Image *ima);
static void image_update_gputexture_ex(
@@ -55,13 +55,12 @@ static void image_update_gputexture_ex(
/* Internal structs. */
#define IMA_PARTIAL_REFRESH_TILE_SIZE 256
-typedef struct ImagePartialRefresh {
+struct ImagePartialRefresh {
struct ImagePartialRefresh *next, *prev;
int tile_x;
int tile_y;
-} ImagePartialRefresh;
+};
-/* Is the alpha of the `GPUTexture` for a given image/ibuf premultiplied. */
bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
{
if (image) {
@@ -71,7 +70,7 @@ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
}
/* Generated images use pre multiplied float buffer, but straight alpha for byte buffers. */
if (image->type == IMA_TYPE_UV_TEST && ibuf) {
- return ibuf->rect_float != NULL;
+ return ibuf->rect_float != nullptr;
}
}
if (ibuf) {
@@ -85,8 +84,9 @@ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
}
/* -------------------------------------------------------------------- */
-/** \name UDIM gpu texture
+/** \name UDIM GPU Texture
* \{ */
+
static bool is_over_resolution_limit(int w, int h, bool limit_gl_texture_size)
{
return (w > GPU_texture_size_with_limit(w, limit_gl_texture_size) ||
@@ -104,8 +104,8 @@ static GPUTexture *gpu_texture_create_tile_mapping(
const int resolution = (texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED) ? 1 : 0;
GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye][resolution];
- if (tilearray == NULL) {
- return 0;
+ if (tilearray == nullptr) {
+ return nullptr;
}
float array_w = GPU_texture_width(tilearray);
@@ -142,11 +142,11 @@ static GPUTexture *gpu_texture_create_tile_mapping(
return tex;
}
-typedef struct PackTile {
+struct PackTile {
FixedSizeBoxPack boxpack;
ImageTile *tile;
float pack_score;
-} PackTile;
+};
static int compare_packtile(const void *a, const void *b)
{
@@ -163,16 +163,16 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
const bool limit_gl_texture_size = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED;
const int resolution = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED ? 1 : 0;
int arraywidth = 0, arrayheight = 0;
- ListBase boxes = {NULL};
+ ListBase boxes = {nullptr};
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);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
if (ibuf) {
- PackTile *packtile = (PackTile *)MEM_callocN(sizeof(PackTile), __func__);
+ PackTile *packtile = MEM_cnew<PackTile>(__func__);
packtile->tile = tile;
packtile->boxpack.w = ibuf->x;
packtile->boxpack.h = ibuf->y;
@@ -190,7 +190,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
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);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
BLI_addtail(&boxes, packtile);
}
}
@@ -200,10 +200,10 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
BLI_listbase_sort(&boxes, compare_packtile);
int arraylayers = 0;
/* Keep adding layers until all tiles are packed. */
- while (boxes.first != NULL) {
- ListBase packed = {NULL};
+ while (boxes.first != nullptr) {
+ ListBase packed = {nullptr};
BLI_box_pack_2d_fixedarea(&boxes, arraywidth, arrayheight, &packed);
- BLI_assert(packed.first != NULL);
+ BLI_assert(packed.first != nullptr);
LISTBASE_FOREACH (PackTile *, packtile, &packed) {
ImageTile *tile = packtile->tile;
@@ -241,7 +241,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
ImageUser iuser;
BKE_imageuser_default(&iuser);
iuser.tile = tile->tile_number;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
if (ibuf) {
const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, ibuf);
@@ -254,7 +254,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
store_premultiplied);
}
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
}
if (GPU_mipmap_enabled()) {
@@ -305,7 +305,7 @@ static GPUTexture **get_image_gpu_texture_ptr(Image *ima,
if (in_range) {
return &(ima->gputexture[textarget][multiview_eye][resolution]);
}
- return NULL;
+ return nullptr;
}
static GPUTexture *image_gpu_texture_error_create(eGPUTextureTarget textarget)
@@ -342,8 +342,8 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
ImBuf *ibuf,
eGPUTextureTarget textarget)
{
- if (ima == NULL) {
- return NULL;
+ if (ima == nullptr) {
+ return nullptr;
}
/* Free any unused GPU textures, since we know we are in a thread with OpenGL
@@ -373,17 +373,17 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
/* Check if image has been updated and tagged to be updated (full or partial). */
ImageTile *tile = BKE_image_get_tile(ima, 0);
if (((ima->gpuflag & IMA_GPU_REFRESH) != 0) ||
- ((ibuf == NULL || tile == NULL || !tile->ok) &&
- ((ima->gpuflag & IMA_GPU_PARTIAL_REFRESH) != 0))) {
+ ((ibuf == nullptr || tile == nullptr) && ((ima->gpuflag & IMA_GPU_PARTIAL_REFRESH) != 0))) {
image_free_gpu(ima, true);
BLI_freelistN(&ima->gpu_refresh_areas);
ima->gpuflag &= ~(IMA_GPU_REFRESH | IMA_GPU_PARTIAL_REFRESH);
}
else if (ima->gpuflag & IMA_GPU_PARTIAL_REFRESH) {
BLI_assert(ibuf);
- BLI_assert(tile && tile->ok);
+ BLI_assert(tile);
ImagePartialRefresh *refresh_area;
- while ((refresh_area = BLI_pophead(&ima->gpu_refresh_areas))) {
+ while ((
+ refresh_area = static_cast<ImagePartialRefresh *>(BLI_pophead(&ima->gpu_refresh_areas)))) {
const int tile_offset_x = refresh_area->tile_x * IMA_PARTIAL_REFRESH_TILE_SIZE;
const int tile_offset_y = refresh_area->tile_y * IMA_PARTIAL_REFRESH_TILE_SIZE;
const int tile_width = MIN2(IMA_PARTIAL_REFRESH_TILE_SIZE, ibuf->x - tile_offset_x);
@@ -405,7 +405,7 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
const bool limit_resolution = U.glreslimit != 0 &&
((iuser && (iuser->flag & IMA_SHOW_MAX_RESOLUTION) == 0) ||
- (iuser == NULL)) &&
+ (iuser == nullptr)) &&
((ima->gpuflag & IMA_GPU_REUSE_MAX_RESOLUTION) == 0);
const eImageTextureResolution texture_resolution = limit_resolution ?
IMA_TEXTURE_RESOLUTION_LIMITED :
@@ -417,16 +417,16 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
/* Check if we have a valid image. If not, we return a dummy
* texture with zero bind-code so we don't keep trying. */
- if (tile == NULL || tile->ok == 0) {
+ if (tile == nullptr) {
*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) {
+ if (ibuf_intern == nullptr) {
+ ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, nullptr);
+ if (ibuf_intern == nullptr) {
*tex = image_gpu_texture_error_create(textarget);
return *tex;
}
@@ -478,8 +478,8 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
/* if `ibuf` was given, we don't own the `ibuf_intern` */
- if (ibuf == NULL) {
- BKE_image_release_ibuf(ima, ibuf_intern, NULL);
+ if (ibuf == nullptr) {
+ BKE_image_release_ibuf(ima, ibuf_intern, nullptr);
}
if (*tex) {
@@ -513,19 +513,19 @@ GPUTexture *BKE_image_get_gpu_tilemap(Image *image, ImageUser *iuser, ImBuf *ibu
* In that case we push them into a queue and free the buffers later.
* \{ */
-static LinkNode *gpu_texture_free_queue = NULL;
+static LinkNode *gpu_texture_free_queue = nullptr;
static ThreadMutex gpu_texture_queue_mutex = BLI_MUTEX_INITIALIZER;
-static void gpu_free_unused_buffers(void)
+static void gpu_free_unused_buffers()
{
- if (gpu_texture_free_queue == NULL) {
+ if (gpu_texture_free_queue == nullptr) {
return;
}
BLI_mutex_lock(&gpu_texture_queue_mutex);
- while (gpu_texture_free_queue != NULL) {
- GPUTexture *tex = BLI_linklist_pop(&gpu_texture_free_queue);
+ while (gpu_texture_free_queue != nullptr) {
+ GPUTexture *tex = static_cast<GPUTexture *>(BLI_linklist_pop(&gpu_texture_free_queue));
GPU_texture_free(tex);
}
@@ -550,7 +550,7 @@ 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++) {
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- if (ima->gputexture[i][eye][resolution] != NULL) {
+ if (ima->gputexture[i][eye][resolution] != nullptr) {
if (immediate) {
GPU_texture_free(ima->gputexture[i][eye][resolution]);
}
@@ -560,7 +560,7 @@ static void image_free_gpu(Image *ima, const bool immediate)
BLI_mutex_unlock(&gpu_texture_queue_mutex);
}
- ima->gputexture[i][eye][resolution] = NULL;
+ ima->gputexture[i][eye][resolution] = nullptr;
}
}
}
@@ -574,9 +574,9 @@ static void image_free_gpu_limited_scale(Image *ima)
const eImageTextureResolution resolution = IMA_TEXTURE_RESOLUTION_LIMITED;
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (ima->gputexture[i][eye][resolution] != NULL) {
+ if (ima->gputexture[i][eye][resolution] != nullptr) {
GPU_texture_free(ima->gputexture[i][eye][resolution]);
- ima->gputexture[i][eye][resolution] = NULL;
+ ima->gputexture[i][eye][resolution] = nullptr;
}
}
}
@@ -598,7 +598,6 @@ void BKE_image_free_all_gputextures(Main *bmain)
}
}
-/* same as above but only free animated images */
void BKE_image_free_anim_gputextures(Main *bmain)
{
if (bmain) {
@@ -645,6 +644,7 @@ void BKE_image_free_old_gputextures(Main *bmain)
}
}
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -770,7 +770,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
{
const int resolution = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED ? 1 : 0;
bool scaled;
- if (tile != NULL) {
+ if (tile != nullptr) {
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
int *tilesize = tile_runtime->tilearray_size;
scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]);
@@ -797,14 +797,14 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
int tex_offset = ibuf->channels * (y * ibuf->x + x);
const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, ibuf);
- if (rect_float == NULL) {
+ if (rect_float == nullptr) {
/* 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) {
+ if (rect == nullptr) {
return;
}
@@ -821,7 +821,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
/* Float pixels. */
if (ibuf->channels != 4 || scaled || !store_premultiplied) {
rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__);
- if (rect_float == NULL) {
+ if (rect_float == nullptr) {
return;
}
@@ -835,7 +835,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
if (scaled) {
/* Slower update where we first have to scale the input pixels. */
- if (tile != NULL) {
+ if (tile != nullptr) {
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
int *tileoffset = tile_runtime->tilearray_offset;
int *tilesize = tile_runtime->tilearray_size;
@@ -845,12 +845,12 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
}
else {
gpu_texture_update_scaled(
- tex, rect, rect_float, ibuf->x, ibuf->y, x, y, -1, NULL, NULL, w, h);
+ tex, rect, rect_float, ibuf->x, ibuf->y, x, y, -1, nullptr, nullptr, w, h);
}
}
else {
/* Fast update at same resolution. */
- if (tile != NULL) {
+ if (tile != nullptr) {
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
int *tileoffset = tile_runtime->tilearray_offset;
int tilelayer = tile_runtime->tilearray_layer;
@@ -859,7 +859,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
}
else {
gpu_texture_update_unscaled(
- tex, rect, rect_float, x, y, -1, NULL, w, h, tex_stride, tex_offset);
+ tex, rect, rect_float, x, y, -1, nullptr, w, h, tex_stride, tex_offset);
}
}
@@ -887,39 +887,33 @@ static void image_update_gputexture_ex(
const int eye = 0;
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
GPUTexture *tex = ima->gputexture[TEXTARGET_2D][eye][resolution];
- eImageTextureResolution texture_resolution = resolution;
+ eImageTextureResolution texture_resolution = static_cast<eImageTextureResolution>(resolution);
/* 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, texture_resolution);
+ if (tex != nullptr && tile == ima->tiles.first) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, nullptr, x, y, w, h, texture_resolution);
}
/* Check if we need to update the array gputexture. */
tex = ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution];
- if (tex != NULL) {
+ if (tex != nullptr) {
gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h, texture_resolution);
}
}
}
-/* 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);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, nullptr);
ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
- if ((ibuf == NULL) || (w == 0) || (h == 0)) {
+ if ((ibuf == nullptr) || (w == 0) || (h == 0)) {
/* Full reload of texture. */
BKE_image_free_gputextures(ima);
}
image_update_gputexture_ex(ima, tile, ibuf, x, y, w, h);
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
}
-/* Mark areas on the GPUTexture that needs to be updated. The areas are marked in chunks.
- * The next time the GPUTexture is used these tiles will be refreshes. This saves time
- * when writing to the same place multiple times This happens for during foreground
- * rendering. */
void BKE_image_update_gputexture_delayed(
struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h)
{
@@ -947,7 +941,7 @@ void BKE_image_update_gputexture_delayed(
const int num_tiles_y = (end_tile_y + 1) - (start_tile_y);
const int num_tiles = num_tiles_x * num_tiles_y;
const bool allocate_on_heap = BLI_BITMAP_SIZE(num_tiles) > 16;
- BLI_bitmap *requested_tiles = NULL;
+ BLI_bitmap *requested_tiles = nullptr;
if (allocate_on_heap) {
requested_tiles = BLI_BITMAP_NEW(num_tiles, __func__);
}
@@ -977,7 +971,8 @@ void BKE_image_update_gputexture_delayed(
for (int tile_y = start_tile_y; tile_y <= end_tile_y; tile_y++) {
for (int tile_x = start_tile_x; tile_x <= end_tile_x; tile_x++) {
if (!BLI_BITMAP_TEST_BOOL(requested_tiles, tile_index)) {
- ImagePartialRefresh *area = MEM_mallocN(sizeof(ImagePartialRefresh), __func__);
+ ImagePartialRefresh *area = static_cast<ImagePartialRefresh *>(
+ MEM_mallocN(sizeof(ImagePartialRefresh), __func__));
area->tile_x = tile_x;
area->tile_y = tile_y;
BLI_addtail(&ima->gpu_refresh_areas, area);
@@ -992,10 +987,6 @@ void BKE_image_update_gputexture_delayed(
}
}
-/* 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) {
@@ -1006,7 +997,7 @@ void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
for (int eye = 0; eye < 2; eye++) {
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
GPUTexture *tex = ima->gputexture[a][eye][resolution];
- if (tex != NULL) {
+ if (tex != nullptr) {
GPU_texture_mipmap_mode(tex, mipmap, true);
}
}
diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c
index f93ede517a9..329bc7b498b 100644
--- a/source/blender/blenkernel/intern/image_save.c
+++ b/source/blender/blenkernel/intern/image_save.c
@@ -30,6 +30,8 @@
#include "DNA_image_types.h"
+#include "MEM_guardedalloc.h"
+
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -402,15 +404,17 @@ bool BKE_image_save(
bool colorspace_changed = false;
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = NULL;
+
if (ima->source == IMA_SRC_TILED) {
- /* Verify filepath for tiles images. */
- ImageTile *first_tile = ima->tiles.first;
- if (BLI_path_sequence_decode(opts->filepath, NULL, NULL, NULL) != first_tile->tile_number) {
+ /* Verify filepath for tiled images contains a valid UDIM marker. */
+ udim_pattern = BKE_image_get_tile_strformat(opts->filepath, &tile_format);
+ if (tile_format == UDIM_TILE_FORMAT_NONE) {
BKE_reportf(reports,
RPT_ERROR,
- "When saving a tiled image, the path '%s' must contain the UDIM tile number %d",
- opts->filepath,
- first_tile->tile_number);
+ "When saving a tiled image, the path '%s' must contain a valid UDIM marker",
+ opts->filepath);
return false;
}
@@ -420,36 +424,29 @@ bool BKE_image_save(
}
}
- /* Save image - or, for tiled images, the first tile. */
- bool ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
-
- if (ok && ima->source == IMA_SRC_TILED) {
+ /* Save images */
+ bool ok = false;
+ if (ima->source != IMA_SRC_TILED) {
+ ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
+ }
+ else {
char filepath[FILE_MAX];
BLI_strncpy(filepath, opts->filepath, sizeof(filepath));
- char head[FILE_MAX], tail[FILE_MAX];
- unsigned short numlen;
- BLI_path_sequence_decode(filepath, head, tail, &numlen);
-
- /* Save all other tiles. */
- int index;
- LISTBASE_FOREACH_INDEX (ImageTile *, tile, &ima->tiles, index) {
- /* First tile was already saved before the loop. */
- if (index == 0) {
- continue;
- }
+ /* Save all the tiles. */
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ BKE_image_set_filepath_from_tile_number(
+ opts->filepath, udim_pattern, tile_format, tile->tile_number);
+ iuser->tile = tile->tile_number;
+ ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
if (!ok) {
- continue;
+ break;
}
-
- /* Build filepath of the tile. */
- BLI_path_sequence_encode(opts->filepath, head, tail, numlen, tile->tile_number);
-
- iuser->tile = tile->tile_number;
- ok = ok && image_save_single(reports, ima, iuser, opts, &colorspace_changed);
}
+ BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
BLI_strncpy(opts->filepath, filepath, sizeof(opts->filepath));
+ MEM_freeN(udim_pattern);
}
if (colorspace_changed) {
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 26a1240080f..d87331fd65c 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -185,6 +185,7 @@ IDTypeInfo IDType_ID_IP = {
.name_plural = "ipos",
.translation_context = "",
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -192,6 +193,7 @@ IDTypeInfo IDType_ID_IP = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = NULL,
@@ -2093,17 +2095,6 @@ static bool seq_convert_callback(Sequence *seq, void *userdata)
/* *************************************************** */
/* External API - Only Called from do_versions() */
-/* Called from do_versions() in readfile.c to convert the old 'IPO/adrcode' system
- * to the new 'Animato/RNA' system.
- *
- * The basic method used here, is to loop over data-blocks which have IPO-data,
- * and add those IPO's to new AnimData blocks as Actions.
- * Action/NLA data only works well for Objects, so these only need to be checked for there.
- *
- * Data that has been converted should be freed immediately, which means that it is immediately
- * clear which data-blocks have yet to be converted, and also prevent freeing errors when we exit.
- */
-/* XXX currently done after all file reading... */
void do_versions_ipos_to_animato(Main *bmain)
{
ListBase drivers = {NULL, NULL};
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 44fc86877a7..0df493e28c0 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -213,6 +213,7 @@ IDTypeInfo IDType_ID_KE = {
.name_plural = "shape_keys",
.translation_context = BLT_I18NCONTEXT_ID_SHAPEKEY,
.flags = IDTYPE_FLAGS_NO_LIBLINKING,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = shapekey_copy_data,
@@ -220,6 +221,7 @@ IDTypeInfo IDType_ID_KE = {
.make_local = NULL,
.foreach_id = shapekey_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
/* A bit weird, due to shapekeys not being strictly speaking embedded data... But they also
* share a lot with those (non linkable, only ever used by one owner ID, etc.). */
.owner_get = shapekey_owner_get,
@@ -244,7 +246,6 @@ typedef struct WeightsArrayCache {
float **defgroup_weights;
} WeightsArrayCache;
-/** Free (or release) any data used by this shapekey (does not free the key itself). */
void BKE_key_free_data(Key *key)
{
shapekey_free_data(&key->id);
@@ -314,11 +315,6 @@ Key *BKE_key_add(Main *bmain, ID *id) /* common function */
return key;
}
-/**
- * Sort shape keys after a change.
- * This assumes that at most one key was moved,
- * which is a valid assumption for the places it's currently being called.
- */
void BKE_key_sort(Key *key)
{
KeyBlock *kb;
@@ -392,7 +388,6 @@ void key_curve_position_weights(float t, float data[4], int type)
}
}
-/* first derivative */
void key_curve_tangent_weights(float t, float data[4], int type)
{
float t2, fc;
@@ -431,7 +426,6 @@ void key_curve_tangent_weights(float t, float data[4], int type)
}
}
-/* second derivative */
void key_curve_normal_weights(float t, float data[4], int type)
{
float fc;
@@ -1522,7 +1516,6 @@ static void do_latt_key(Object *ob, Key *key, char *out, const int tot)
}
}
-/* returns key coordinates (+ tilt) when key applied, NULL otherwise */
float *BKE_key_evaluate_object_ex(Object *ob, int *r_totelem, float *arr, size_t arr_size)
{
Key *key = BKE_key_from_object(ob);
@@ -1624,9 +1617,6 @@ float *BKE_key_evaluate_object(Object *ob, int *r_totelem)
return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0);
}
-/**
- * \param shape_index: The index to use or all (when -1).
- */
int BKE_keyblock_element_count_from_shape(const Key *key, const int shape_index)
{
int result = 0;
@@ -1644,9 +1634,6 @@ int BKE_keyblock_element_count(const Key *key)
return BKE_keyblock_element_count_from_shape(key, -1);
}
-/**
- * \param shape_index: The index to use or all (when -1).
- */
size_t BKE_keyblock_element_calc_size_from_shape(const Key *key, const int shape_index)
{
return (size_t)BKE_keyblock_element_count_from_shape(key, shape_index) * key->elemsize;
@@ -1664,9 +1651,6 @@ size_t BKE_keyblock_element_calc_size(const Key *key)
* use #BKE_keyblock_element_calc_size to allocate the size of the data needed.
* \{ */
-/**
- * \param shape_index: The index to use or all (when -1).
- */
void BKE_keyblock_data_get_from_shape(const Key *key, float (*arr)[3], const int shape_index)
{
uint8_t *elements = (uint8_t *)arr;
@@ -1685,9 +1669,6 @@ void BKE_keyblock_data_get(const Key *key, float (*arr)[3])
BKE_keyblock_data_get_from_shape(key, arr, -1);
}
-/**
- * Set the data to all key-blocks (or shape_index if != -1).
- */
void BKE_keyblock_data_set_with_mat4(Key *key,
const int shape_index,
const float (*coords)[3],
@@ -1715,10 +1696,6 @@ void BKE_keyblock_data_set_with_mat4(Key *key,
}
}
-/**
- * Set the data for all key-blocks (or shape_index if != -1),
- * transforming by \a mat.
- */
void BKE_keyblock_curve_data_set_with_mat4(
Key *key, const ListBase *nurb, const int shape_index, const void *data, const float mat[4][4])
{
@@ -1734,9 +1711,6 @@ void BKE_keyblock_curve_data_set_with_mat4(
}
}
-/**
- * Set the data for all key-blocks (or shape_index if != -1).
- */
void BKE_keyblock_data_set(Key *key, const int shape_index, const void *data)
{
const uint8_t *elements = data;
@@ -1868,14 +1842,6 @@ KeyBlock *BKE_keyblock_add(Key *key, const char *name)
return kb;
}
-/**
- * \note sorting is a problematic side effect in some cases,
- * better only do this explicitly by having its own function,
- *
- * \param key: The key datablock to add to.
- * \param name: Optional name for the new keyblock.
- * \param do_force: always use ctime even for relative keys.
- */
KeyBlock *BKE_keyblock_add_ctime(Key *key, const char *name, const bool do_force)
{
KeyBlock *kb = BKE_keyblock_add(key, name);
@@ -1904,7 +1870,6 @@ KeyBlock *BKE_keyblock_add_ctime(Key *key, const char *name, const bool do_force
return kb;
}
-/* only the active keyblock */
KeyBlock *BKE_keyblock_from_object(Object *ob)
{
Key *key = BKE_key_from_object(ob);
@@ -1928,7 +1893,6 @@ KeyBlock *BKE_keyblock_from_object_reference(Object *ob)
return NULL;
}
-/* get the appropriate KeyBlock given an index */
KeyBlock *BKE_keyblock_from_key(Key *key, int index)
{
if (key) {
@@ -1946,15 +1910,11 @@ KeyBlock *BKE_keyblock_from_key(Key *key, int index)
return NULL;
}
-/* get the appropriate KeyBlock given a name to search for */
KeyBlock *BKE_keyblock_find_name(Key *key, const char name[])
{
return BLI_findstring(&key->block, name, offsetof(KeyBlock, name));
}
-/**
- * \brief copy shape-key attributes, but not key data.or name/uid
- */
void BKE_keyblock_copy_settings(KeyBlock *kb_dst, const KeyBlock *kb_src)
{
kb_dst->pos = kb_src->pos;
@@ -1966,9 +1926,6 @@ void BKE_keyblock_copy_settings(KeyBlock *kb_dst, const KeyBlock *kb_src)
kb_dst->slidermax = kb_src->slidermax;
}
-/* Get RNA-Path for 'value' setting of the given ShapeKey
- * NOTE: the user needs to free the returned string once they're finish with it
- */
char *BKE_keyblock_curval_rnapath_get(Key *key, KeyBlock *kb)
{
PointerRNA ptr;
@@ -1991,6 +1948,7 @@ char *BKE_keyblock_curval_rnapath_get(Key *key, KeyBlock *kb)
/* conversion functions */
/************************* Lattice ************************/
+
void BKE_keyblock_update_from_lattice(Lattice *lt, KeyBlock *kb)
{
BPoint *bp;
@@ -2191,6 +2149,7 @@ void BKE_keyblock_convert_to_curve(KeyBlock *kb, Curve *UNUSED(cu), ListBase *nu
}
/************************* Mesh ************************/
+
void BKE_keyblock_update_from_mesh(Mesh *me, KeyBlock *kb)
{
MVert *mvert;
@@ -2243,15 +2202,6 @@ void BKE_keyblock_convert_to_mesh(KeyBlock *kb, Mesh *me)
}
}
-/**
- * Computes normals (vertices, polygons and/or loops ones) of given mesh for given shape key.
- *
- * \param kb: the KeyBlock to use to compute normals.
- * \param mesh: the Mesh to apply keyblock to.
- * \param r_vertnors: if non-NULL, an array of vectors, same length as number of vertices.
- * \param r_polynors: if non-NULL, an array of vectors, same length as number of polygons.
- * \param r_loopnors: if non-NULL, an array of vectors, same length as number of loops.
- */
void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
struct Mesh *mesh,
float (*r_vertnors)[3],
@@ -2280,13 +2230,20 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
r_polynors = MEM_mallocN(sizeof(float[3]) * me.totpoly, __func__);
free_polynors = true;
}
- BKE_mesh_calc_normals_poly_and_vertex(
- me.mvert, me.totvert, me.mloop, me.totloop, me.mpoly, me.totpoly, r_polynors, r_vertnors);
+
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ if (r_vertnors) {
+ memcpy(r_vertnors, vert_normals, sizeof(float[3]) * me.totvert);
+ }
+
+ const float(*face_normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
+ memcpy(r_polynors, face_normals, sizeof(float[3]) * me.totpoly);
if (r_loopnors) {
short(*clnors)[2] = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); /* May be NULL. */
BKE_mesh_normals_loop_split(me.mvert,
+ vert_normals,
me.totvert,
me.medge,
me.totedge,
@@ -2294,7 +2251,7 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
r_loopnors,
me.totloop,
me.mpoly,
- r_polynors,
+ face_normals,
me.totpoly,
(me.flag & ME_AUTOSMOOTH) != 0,
me.smoothresh,
@@ -2316,6 +2273,7 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
}
/************************* raw coords ************************/
+
void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
{
const float(*co)[3] = vertCos;
@@ -2345,7 +2303,7 @@ void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, const float (*ve
return;
}
- /* Copy coords to keyblock */
+ /* Copy coords to key-block. */
if (ELEM(ob->type, OB_MESH, OB_LATTICE)) {
for (a = 0; a < tot; a++, fp += 3, co++) {
copy_v3_v3(fp, *co);
@@ -2405,7 +2363,7 @@ void BKE_keyblock_convert_from_vertcos(Object *ob, KeyBlock *kb, const float (*v
kb->data = MEM_mallocN(tot * elemsize, __func__);
- /* Copy coords to keyblock */
+ /* Copy coords to key-block. */
BKE_keyblock_update_from_vertcos(ob, kb, vertCos);
}
@@ -2469,6 +2427,7 @@ float (*BKE_keyblock_convert_to_vertcos(Object *ob, KeyBlock *kb))[3]
}
/************************* raw coord offsets ************************/
+
void BKE_keyblock_update_from_offset(Object *ob, KeyBlock *kb, const float (*ofs)[3])
{
int a;
@@ -2506,15 +2465,6 @@ void BKE_keyblock_update_from_offset(Object *ob, KeyBlock *kb, const float (*ofs
/* ==========================================================*/
-/**
- * Move shape key from org_index to new_index. Safe, clamps index to valid range,
- * updates reference keys, the object's active shape index,
- * the 'frame' value in case of absolute keys, etc.
- * Note indices are expected in real values (not 'fake' shapenr +1 ones).
- *
- * \param org_index: if < 0, current object's active shape will be used as skey to move.
- * \return true if something was done, else false.
- */
bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
{
Key *key = BKE_key_from_object(ob);
@@ -2593,9 +2543,6 @@ bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
return true;
}
-/**
- * Check if given keyblock (as index) is used as basis by others in given key.
- */
bool BKE_keyblock_is_basis(Key *key, const int index)
{
KeyBlock *kb;
diff --git a/source/blender/blenkernel/intern/keyconfig.c b/source/blender/blenkernel/intern/keyconfig.c
index d25f475c140..84e11c1166e 100644
--- a/source/blender/blenkernel/intern/keyconfig.c
+++ b/source/blender/blenkernel/intern/keyconfig.c
@@ -121,7 +121,6 @@ void BKE_keyconfig_pref_type_free(void)
/** \name Key-Config Versioning
* \{ */
-/* Set select mouse, for versioning code. */
void BKE_keyconfig_pref_set_select_mouse(UserDef *userdef, int value, bool override)
{
wmKeyConfigPref *kpt = BKE_keyconfig_pref_ensure(userdef, WM_KEYCONFIG_STR_DEFAULT);
@@ -201,10 +200,6 @@ void BKE_keyconfig_keymap_filter_item(wmKeyMap *keymap,
}
}
-/**
- * Filter & optionally remove key-map items,
- * intended for versioning, but may be used in other situations too.
- */
void BKE_keyconfig_pref_filter_items(struct UserDef *userdef,
const struct wmKeyConfigFilterItemParams *params,
bool (*filter_fn)(wmKeyMapItem *kmi, void *user_data),
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 9bca8172e64..2f5c5d0a0d5 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -131,7 +131,7 @@ static void lattice_free_data(ID *id)
static void lattice_foreach_id(ID *id, LibraryForeachIDData *data)
{
Lattice *lattice = (Lattice *)id;
- BKE_LIB_FOREACHID_PROCESS(data, lattice->key, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, lattice->key, IDWALK_CB_USER);
}
static void lattice_blend_write(BlendWriter *writer, ID *id, const void *id_address)
@@ -197,6 +197,7 @@ IDTypeInfo IDType_ID_LT = {
.name_plural = "lattices",
.translation_context = BLT_I18NCONTEXT_ID_LATTICE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = lattice_init_data,
.copy_data = lattice_copy_data,
@@ -204,6 +205,7 @@ IDTypeInfo IDType_ID_LT = {
.make_local = NULL,
.foreach_id = lattice_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = lattice_blend_write,
@@ -464,7 +466,7 @@ void outside_lattice(Lattice *lt)
bp->hide = 1;
bp->f1 &= ~SELECT;
- /* u extrema */
+ /* U extrema. */
bp1 = latt_bp(lt, 0, v, w);
bp2 = latt_bp(lt, lt->pntsu - 1, v, w);
@@ -473,7 +475,7 @@ void outside_lattice(Lattice *lt)
bp->vec[1] = (1.0f - fac1) * bp1->vec[1] + fac1 * bp2->vec[1];
bp->vec[2] = (1.0f - fac1) * bp1->vec[2] + fac1 * bp2->vec[2];
- /* v extrema */
+ /* V extrema. */
bp1 = latt_bp(lt, u, 0, w);
bp2 = latt_bp(lt, u, lt->pntsv - 1, w);
@@ -482,7 +484,7 @@ void outside_lattice(Lattice *lt)
bp->vec[1] += (1.0f - fac1) * bp1->vec[1] + fac1 * bp2->vec[1];
bp->vec[2] += (1.0f - fac1) * bp1->vec[2] + fac1 * bp2->vec[2];
- /* w extrema */
+ /* W extrema. */
bp1 = latt_bp(lt, u, v, 0);
bp2 = latt_bp(lt, u, v, lt->pntsw - 1);
diff --git a/source/blender/blenkernel/intern/lattice_deform.c b/source/blender/blenkernel/intern/lattice_deform.c
index f9437eeaffa..af721412472 100644
--- a/source/blender/blenkernel/intern/lattice_deform.c
+++ b/source/blender/blenkernel/intern/lattice_deform.c
@@ -115,7 +115,7 @@ LatticeDeformData *BKE_lattice_deform_data_create(const Object *oblatt, const Ob
defgrp_index = BKE_id_defgroup_name_index(&lt->id, lt->vgroup);
if (defgrp_index != -1) {
- lattice_weights = MEM_malloc_arrayN(sizeof(float), num_points, "lattice_weights");
+ lattice_weights = MEM_malloc_arrayN(num_points, sizeof(float), "lattice_weights");
for (int index = 0; index < num_points; index++) {
lattice_weights[index] = BKE_defvert_find_weight(dvert + index, defgrp_index);
}
diff --git a/source/blender/blenkernel/intern/lattice_deform_test.cc b/source/blender/blenkernel/intern/lattice_deform_test.cc
index a7cd5c36ec2..bface94d9d4 100644
--- a/source/blender/blenkernel/intern/lattice_deform_test.cc
+++ b/source/blender/blenkernel/intern/lattice_deform_test.cc
@@ -44,7 +44,7 @@ static void test_lattice_deform_init(LatticeDeformTestContext *ctx,
int32_t num_items)
{
/* Generate random input data between -5 and 5. */
- ctx->coords = (float(*)[3])MEM_malloc_arrayN(sizeof(float[3]), num_items, __func__);
+ ctx->coords = (float(*)[3])MEM_malloc_arrayN(num_items, sizeof(float[3]), __func__);
for (uint32_t index = 0; index < num_items; index++) {
ctx->coords[index][0] = (rng->get_float() - 0.5f) * 10;
ctx->coords[index][1] = (rng->get_float() - 0.5f) * 10;
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 434a2296d95..a59dd6f2e0e 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -77,7 +77,9 @@ static const short g_base_collection_flags = (BASE_VISIBLE_DEPSGRAPH | BASE_VISI
/* prototype */
static void object_bases_iterator_next(BLI_Iterator *iter, const int flag);
-/*********************** Layer Collections and bases *************************/
+/* -------------------------------------------------------------------- */
+/** \name Layer Collections and Bases
+ * \{ */
static LayerCollection *layer_collection_add(ListBase *lb_parent, Collection *collection)
{
@@ -113,12 +115,14 @@ static Base *object_base_new(Object *ob)
return base;
}
-/********************************* View Layer ********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Layer
+ * \{ */
/* RenderLayer */
-/* Returns the default view layer to view in workspaces if there is
- * none linked to the workspace yet. */
ViewLayer *BKE_view_layer_default_view(const Scene *scene)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -131,7 +135,6 @@ ViewLayer *BKE_view_layer_default_view(const Scene *scene)
return scene->view_layers.first;
}
-/* Returns the default view layer to render if we need to render just one. */
ViewLayer *BKE_view_layer_default_render(const Scene *scene)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -144,7 +147,6 @@ ViewLayer *BKE_view_layer_default_render(const Scene *scene)
return scene->view_layers.first;
}
-/* Returns view layer with matching name, or NULL if not found. */
ViewLayer *BKE_view_layer_find(const Scene *scene, const char *layer_name)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -156,11 +158,6 @@ ViewLayer *BKE_view_layer_find(const Scene *scene, const char *layer_name)
return NULL;
}
-/**
- * This is a placeholder to know which areas of the code need to be addressed
- * for the Workspace changes. Never use this, you should typically get the
- * active layer from the context or window.
- */
ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene)
{
BLI_assert(scene->view_layers.first);
@@ -170,7 +167,7 @@ ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene)
static ViewLayer *view_layer_add(const char *name)
{
if (!name) {
- name = DATA_("View Layer");
+ name = DATA_("ViewLayer");
}
ViewLayer *view_layer = MEM_callocN(sizeof(ViewLayer), "View Layer");
@@ -183,6 +180,7 @@ static ViewLayer *view_layer_add(const char *name)
view_layer->passflag = SCE_PASS_COMBINED;
view_layer->pass_alpha_threshold = 0.5f;
view_layer->cryptomatte_levels = 6;
+ view_layer->cryptomatte_flag = VIEW_LAYER_CRYPTOMATTE_ACCURATE;
BKE_freestyle_config_init(&view_layer->freestyle_config);
return view_layer;
@@ -197,10 +195,6 @@ static void layer_collection_exclude_all(LayerCollection *layer_collection)
}
}
-/**
- * Add a new view layer
- * by default, a view layer has the master collection
- */
ViewLayer *BKE_view_layer_add(Scene *scene,
const char *name,
ViewLayer *view_layer_source,
@@ -248,7 +242,7 @@ ViewLayer *BKE_view_layer_add(Scene *scene,
BLI_uniquename(&scene->view_layers,
view_layer_new,
DATA_("ViewLayer"),
- '.',
+ '_',
offsetof(ViewLayer, name),
sizeof(view_layer_new->name));
@@ -260,9 +254,6 @@ void BKE_view_layer_free(ViewLayer *view_layer)
BKE_view_layer_free_ex(view_layer, true);
}
-/**
- * Free (or release) any data used by this ViewLayer.
- */
void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
{
view_layer->basact = NULL;
@@ -303,9 +294,6 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
MEM_freeN(view_layer);
}
-/**
- * Tag all the selected objects of a render-layer.
- */
void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag)
{
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
@@ -331,13 +319,6 @@ static bool find_scene_collection_in_scene_collections(ListBase *lb, const Layer
return false;
}
-/**
- * Fallback for when a Scene has no camera to use
- *
- * \param view_layer: in general you want to use the same ViewLayer that is used
- * for depsgraph. If rendering you pass the scene active layer, when viewing in the viewport
- * you want to get ViewLayer from context.
- */
Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
{
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
@@ -349,9 +330,6 @@ Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
return NULL;
}
-/**
- * Find the ViewLayer a LayerCollection belongs to
- */
ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollection *lc)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -365,7 +343,7 @@ ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollecti
/* Base */
-static void view_layer_bases_hash_create(ViewLayer *view_layer)
+static void view_layer_bases_hash_create(ViewLayer *view_layer, const bool do_base_duplicates_fix)
{
static ThreadMutex hash_lock = BLI_MUTEX_INITIALIZER;
@@ -375,15 +353,29 @@ static void view_layer_bases_hash_create(ViewLayer *view_layer)
if (view_layer->object_bases_hash == NULL) {
GHash *hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
+ LISTBASE_FOREACH_MUTABLE (Base *, base, &view_layer->object_bases) {
if (base->object) {
- /* Some processes, like ID remapping, may lead to having several bases with the same
- * object. So just take the first one here, and ignore all others
- * (#BKE_layer_collection_sync will clean this up anyway). */
void **val_pp;
if (!BLI_ghash_ensure_p(hash, base->object, &val_pp)) {
*val_pp = base;
}
+ /* The same object has several bases.
+ *
+ * In normal cases this is a serious bug, but this is a common situation when remapping
+ * an object into another one already present in the same View Layer. While ideally we
+ * would process this case separately, for performances reasons it makes more sense to
+ * tackle it here. */
+ else if (do_base_duplicates_fix) {
+ if (view_layer->basact == base) {
+ view_layer->basact = NULL;
+ }
+ BLI_freelinkN(&view_layer->object_bases, base);
+ }
+ else {
+ CLOG_FATAL(&LOG,
+ "Object '%s' has more than one entry in view layer's object bases listbase",
+ base->object->id.name + 2);
+ }
}
}
@@ -398,7 +390,7 @@ static void view_layer_bases_hash_create(ViewLayer *view_layer)
Base *BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
{
if (!view_layer->object_bases_hash) {
- view_layer_bases_hash_create(view_layer);
+ view_layer_bases_hash_create(view_layer, false);
}
return BLI_ghash_lookup(view_layer->object_bases_hash, ob);
@@ -421,7 +413,12 @@ void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, Bas
}
}
-/**************************** Copy View Layer and Layer Collections ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Copy View Layer and Layer Collections
+ * \{ */
+
static void layer_aov_copy_data(ViewLayer *view_layer_dst,
const ViewLayer *view_layer_src,
ListBase *aovs_dst,
@@ -470,11 +467,6 @@ static void layer_collections_copy_data(ViewLayer *view_layer_dst,
}
}
-/**
- * Only copy internal data of ViewLayer from source to already allocated/initialized destination.
- *
- * \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more).
- */
void BKE_view_layer_copy_data(Scene *scene_dst,
const Scene *UNUSED(scene_src),
ViewLayer *view_layer_dst,
@@ -619,26 +611,17 @@ static bool layer_collection_hidden(ViewLayer *view_layer, LayerCollection *lc)
return false;
}
-/**
- * Get the collection for a given index
- */
LayerCollection *BKE_layer_collection_from_index(ViewLayer *view_layer, const int index)
{
int i = 0;
return collection_from_index(&view_layer->layer_collections, index, &i);
}
-/**
- * Get the active collection
- */
LayerCollection *BKE_layer_collection_get_active(ViewLayer *view_layer)
{
return view_layer->active_collection;
}
-/*
- * Activate collection
- */
bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc)
{
if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
@@ -649,9 +632,6 @@ bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc)
return true;
}
-/**
- * Activate first parent collection
- */
LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, LayerCollection *lc)
{
CollectionParent *parent = lc->collection->parents.first;
@@ -689,10 +669,6 @@ static int collection_count(const ListBase *lb)
return i;
}
-/**
- * Get the total number of collections
- * (including all the nested collections)
- */
int BKE_layer_collection_count(const ViewLayer *view_layer)
{
return collection_count(&view_layer->layer_collections);
@@ -720,16 +696,16 @@ static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i
return -1;
}
-/**
- * Return -1 if not found
- */
int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection *lc)
{
int i = 0;
return index_from_collection(&view_layer->layer_collections, lc, &i);
}
-/*********************************** Syncing *********************************
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Syncing
*
* The layer collection tree mirrors the scene collection tree. Whenever that
* changes we need to synchronize them so that there is a corresponding layer
@@ -739,9 +715,9 @@ int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection
*
* The view layer also contains a list of bases for each object that exists
* in at least one layer collection. That list is also synchronized here, and
- * stores state like selection. */
-
-/* This API allows to temporarily forbid resync of LayerCollections.
+ * stores state like selection.
+ *
+ * This API allows to temporarily forbid resync of LayerCollections.
*
* This can greatly improve performances in cases where those functions get
* called a lot (e.g. during massive remappings of IDs).
@@ -750,19 +726,20 @@ int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection
* code must ensures it resync LayerCollections before any UI/Event loop
* handling can happen.
*
- * WARNING: This is not threadsafe at all, only use from main thread.
+ * \warning This is not threadsafe at all, only use from main thread.
*
- * NOTE: It is probably needed to use #BKE_main_collection_sync_remap instead
+ * \note It is probably needed to use #BKE_main_collection_sync_remap instead
* of just #BKE_main_collection_sync after disabling LayerCollection resync,
* unless it is absolutely certain that no ID remapping (or any other process
* that may invalidate the caches) will happen while it is disabled.
*
- * NOTE: This is a quick and safe band-aid around the long-known issue
+ * \note This is a quick and safe band-aid around the long-known issue
* regarding this resync process.
* Proper fix would be to make resync itself lazy, i.e. only happen
* when actually needed.
* See also T73411.
- */
+ * \{ */
+
static bool no_resync = false;
void BKE_layer_collection_resync_forbid(void)
@@ -1219,11 +1196,23 @@ static bool view_layer_objects_base_cache_validate(ViewLayer *UNUSED(view_layer)
}
#endif
-/**
- * Update view layer collection tree from collections used in the scene.
- * This is used when collections are removed or added, both while editing
- * and on file loaded in case linked data changed or went missing.
- */
+void BKE_layer_collection_doversion_2_80(const Scene *scene, ViewLayer *view_layer)
+{
+ LayerCollection *first_layer_collection = view_layer->layer_collections.first;
+ if (BLI_listbase_count_at_most(&view_layer->layer_collections, 2) > 1 ||
+ first_layer_collection->collection != scene->master_collection) {
+ /* In some cases (from older files) we do have a master collection, but no matching layer,
+ * instead all the children of the master collection have their layer collections in the
+ * viewlayer's list. This is not a valid situation, add a layer for the master collection and
+ * add all existing first-level layers as children of that new master layer. */
+ ListBase layer_collections = view_layer->layer_collections;
+ BLI_listbase_clear(&view_layer->layer_collections);
+ LayerCollection *master_layer_collection = layer_collection_add(&view_layer->layer_collections,
+ scene->master_collection);
+ master_layer_collection->layer_collections = layer_collections;
+ }
+}
+
void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
{
if (no_resync) {
@@ -1235,18 +1224,32 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
return;
}
- /* In some cases (from older files) we do have a master collection, yet no matching layer. Create
- * the master one here, so that the rest of the code can work as expected. */
if (BLI_listbase_is_empty(&view_layer->layer_collections)) {
+ /* In some cases (from older files, or when creating a new ViewLayer from
+ * #BKE_view_layer_add), we do have a master collection, yet no matching layer. Create the
+ * master one here, so that the rest of the code can work as expected. */
layer_collection_add(&view_layer->layer_collections, scene->master_collection);
}
+#ifndef NDEBUG
+ {
+ BLI_assert_msg(BLI_listbase_count_at_most(&view_layer->layer_collections, 2) == 1,
+ "ViewLayer's first level of children layer collections should always have "
+ "exactly one item");
+
+ LayerCollection *first_layer_collection = view_layer->layer_collections.first;
+ BLI_assert_msg(first_layer_collection->collection == scene->master_collection,
+ "ViewLayer's first layer collection should always be the one for the scene's "
+ "master collection");
+ }
+#endif
+
/* Free cache. */
MEM_SAFE_FREE(view_layer->object_bases_array);
/* Create object to base hash if it does not exist yet. */
if (!view_layer->object_bases_hash) {
- view_layer_bases_hash_create(view_layer);
+ view_layer_bases_hash_create(view_layer, false);
}
/* Clear visible and selectable flags to be reset. */
@@ -1359,6 +1362,11 @@ void BKE_main_collection_sync_remap(const Main *bmain)
if (view_layer->object_bases_hash) {
BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
view_layer->object_bases_hash = NULL;
+
+ /* Directly re-create the mapping here, so that we can also deal with duplicates in
+ * `view_layer->object_bases` list of bases properly. This is the only place where such
+ * duplicates should be fixed, and not considered as a critical error. */
+ view_layer_bases_hash_create(view_layer, true);
}
}
@@ -1376,14 +1384,12 @@ void BKE_main_collection_sync_remap(const Main *bmain)
BKE_main_collection_sync(bmain);
}
-/* ---------------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Selection
+ * \{ */
-/**
- * Select all the objects of this layer collection
- *
- * It also select the objects that are in nested collections.
- * \note Recursive
- */
bool BKE_layer_collection_objects_select(ViewLayer *view_layer, LayerCollection *lc, bool deselect)
{
if (lc->collection->flag & COLLECTION_HIDE_SELECT) {
@@ -1460,9 +1466,12 @@ bool BKE_layer_collection_has_layer_collection(LayerCollection *lc_parent,
return false;
}
-/* ---------------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Visibility
+ * \{ */
-/* Update after toggling visibility of an object base. */
void BKE_base_set_visible(Scene *scene, ViewLayer *view_layer, Base *base, bool extend)
{
if (!extend) {
@@ -1535,6 +1544,12 @@ bool BKE_object_is_visible_in_viewport(const View3D *v3d, const struct Object *o
return true;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Collection Isolation & Local View
+ * \{ */
+
static void layer_collection_flag_set_recursive(LayerCollection *lc, const int flag)
{
lc->flag |= flag;
@@ -1551,14 +1566,6 @@ static void layer_collection_flag_unset_recursive(LayerCollection *lc, const int
}
}
-/**
- * Isolate the collection - hide all other collections but this one.
- * Make sure to show all the direct parents and all children of the layer collection as well.
- * When extending we simply show the collections and its direct family.
- *
- * If the collection or any of its parents is disabled, make it enabled.
- * Don't change the children disable state though.
- */
void BKE_layer_collection_isolate_global(Scene *scene,
ViewLayer *view_layer,
LayerCollection *lc,
@@ -1667,9 +1674,6 @@ void BKE_layer_collection_local_sync(ViewLayer *view_layer, const View3D *v3d)
}
}
-/**
- * Sync the local collection for all the 3D Viewports.
- */
void BKE_layer_collection_local_sync_all(const Main *bmain)
{
if (no_resync) {
@@ -1693,11 +1697,6 @@ void BKE_layer_collection_local_sync_all(const Main *bmain)
}
}
-/**
- * Isolate the collection locally
- *
- * Same as BKE_layer_collection_isolate_local but for a viewport
- */
void BKE_layer_collection_isolate_local(ViewLayer *view_layer,
const View3D *v3d,
LayerCollection *lc,
@@ -1770,11 +1769,6 @@ static void layer_collection_bases_hide_recursive(ViewLayer *view_layer, LayerCo
}
}
-/**
- * Hide/show all the elements of a collection.
- * Don't change the collection children enable/disable state,
- * but it may change it for the collection itself.
- */
void BKE_layer_collection_set_visible(ViewLayer *view_layer,
LayerCollection *lc,
const bool visible,
@@ -1861,9 +1855,6 @@ static LayerCollection *find_layer_collection_by_scene_collection(LayerCollectio
return NULL;
}
-/**
- * Return the first matching LayerCollection in the ViewLayer for the Collection.
- */
LayerCollection *BKE_layer_collection_first_from_scene_collection(const ViewLayer *view_layer,
const Collection *collection)
{
@@ -1877,17 +1868,11 @@ LayerCollection *BKE_layer_collection_first_from_scene_collection(const ViewLaye
return NULL;
}
-/**
- * See if view layer has the scene collection linked directly, or indirectly (nested)
- */
bool BKE_view_layer_has_collection(const ViewLayer *view_layer, const Collection *collection)
{
return BKE_layer_collection_first_from_scene_collection(view_layer, collection) != NULL;
}
-/**
- * See if the object is in any of the scene layers of the scene
- */
bool BKE_scene_has_object(Scene *scene, Object *ob)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -1998,6 +1983,8 @@ static void objects_iterator_end(BLI_Iterator *iter)
object_bases_iterator_end(iter);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name BKE_view_layer_selected_objects_iterator
* See: #FOREACH_SELECTED_OBJECT_BEGIN
@@ -2187,11 +2174,10 @@ void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *UNUSED(iter))
/** \} */
-/* Evaluation. */
+/* -------------------------------------------------------------------- */
+/** \name Evaluation
+ * \{ */
-/* Applies object's restrict flags on top of flags coming from the collection
- * and stores those in base->flag. BASE_VISIBLE_DEPSGRAPH ignores viewport flags visibility
- * (i.e., restriction and local collection). */
void BKE_base_eval_flags(Base *base)
{
/* Apply collection flags. */
@@ -2250,6 +2236,12 @@ void BKE_layer_eval_view_layer_indexed(struct Depsgraph *depsgraph,
layer_eval_view_layer(depsgraph, scene, view_layer);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend File I/O
+ * \{ */
+
static void write_layer_collections(BlendWriter *writer, ListBase *lb)
{
LISTBASE_FOREACH (LayerCollection *, lc, lb) {
@@ -2370,6 +2362,8 @@ void BKE_view_layer_blend_read_lib(BlendLibReader *reader, Library *lib, ViewLay
IDP_BlendReadLib(reader, view_layer->id_properties);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Shader AOV
* \{ */
@@ -2380,8 +2374,12 @@ static void viewlayer_aov_make_name_unique(ViewLayer *view_layer)
if (aov == NULL) {
return;
}
+
+ /* Don't allow dots, it's incompatible with OpenEXR convention to store channels
+ * as "layer.pass.channel". */
+ BLI_str_replace_char(aov->name, '.', '_');
BLI_uniquename(
- &view_layer->aovs, aov, DATA_("AOV"), '.', offsetof(ViewLayerAOV, name), sizeof(aov->name));
+ &view_layer->aovs, aov, DATA_("AOV"), '_', offsetof(ViewLayerAOV, name), sizeof(aov->name));
}
static void viewlayer_aov_active_set(ViewLayer *view_layer, ViewLayerAOV *aov)
@@ -2450,12 +2448,6 @@ static void bke_view_layer_verify_aov_cb(void *userdata,
}
}
-/* Update the naming and conflicts of the AOVs.
- *
- * Name must be unique between all AOVs.
- * Conflicts with render passes will show a conflict icon. Reason is that switching a render
- * engine or activating a render pass could lead to other conflicts that wouldn't be that clear
- * for the user. */
void BKE_view_layer_verify_aov(struct RenderEngine *engine,
struct Scene *scene,
struct ViewLayer *view_layer)
@@ -2473,7 +2465,6 @@ void BKE_view_layer_verify_aov(struct RenderEngine *engine,
BLI_ghash_free(name_count, MEM_freeN, NULL);
}
-/* Check if the given view layer has at least one valid AOV. */
bool BKE_view_layer_has_valid_aov(ViewLayer *view_layer)
{
LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
diff --git a/source/blender/blenkernel/intern/layer_test.cc b/source/blender/blenkernel/intern/layer_test.cc
index c918c0cab67..c8e5de75bfa 100644
--- a/source/blender/blenkernel/intern/layer_test.cc
+++ b/source/blender/blenkernel/intern/layer_test.cc
@@ -33,6 +33,8 @@
#include "RNA_access.h"
+#include "GHOST_Path-api.h"
+
namespace blender::bke::tests {
TEST(view_layer, aov_unique_names)
@@ -69,7 +71,7 @@ TEST(view_layer, aov_unique_names)
EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0);
EXPECT_FALSE((aov2->flag & AOV_CONFLICT) != 0);
EXPECT_TRUE(STREQ(aov1->name, "AOV"));
- EXPECT_TRUE(STREQ(aov2->name, "AOV.001"));
+ EXPECT_TRUE(STREQ(aov2->name, "AOV_001"));
/* Revert previous resolution */
BLI_strncpy(aov2->name, "AOV", MAX_NAME);
@@ -78,7 +80,7 @@ TEST(view_layer, aov_unique_names)
EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0);
EXPECT_FALSE((aov2->flag & AOV_CONFLICT) != 0);
EXPECT_TRUE(STREQ(aov1->name, "AOV"));
- EXPECT_TRUE(STREQ(aov2->name, "AOV.001"));
+ EXPECT_TRUE(STREQ(aov2->name, "AOV_001"));
/* Resolve by removing AOV resolution */
BKE_view_layer_remove_aov(view_layer, aov2);
@@ -94,6 +96,7 @@ TEST(view_layer, aov_unique_names)
IMB_exit();
BKE_appdir_exit();
CLG_exit();
+ GHOST_DisposeSystemPaths();
}
static void test_render_pass_conflict(Scene *scene,
@@ -173,6 +176,7 @@ TEST(view_layer, aov_conflict)
IMB_exit();
BKE_appdir_exit();
CLG_exit();
+ GHOST_DisposeSystemPaths();
}
} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/layer_utils.c b/source/blender/blenkernel/intern/layer_utils.c
index 48179e0c3bf..3760fe8a976 100644
--- a/source/blender/blenkernel/intern/layer_utils.c
+++ b/source/blender/blenkernel/intern/layer_utils.c
@@ -193,13 +193,6 @@ bool BKE_view_layer_filter_edit_mesh_has_edges(const Object *ob, void *UNUSED(us
return false;
}
-/**
- * Use this in rare cases we need to detect a pair of objects (active, selected).
- * This returns the other non-active selected object.
- *
- * Returns NULL with it finds multiple other selected objects
- * as behavior in this case would be random from the user perspective.
- */
Object *BKE_view_layer_non_active_selected_object(struct ViewLayer *view_layer,
const struct View3D *v3d)
{
@@ -221,4 +214,5 @@ Object *BKE_view_layer_non_active_selected_object(struct ViewLayer *view_layer,
FOREACH_SELECTED_OBJECT_END;
return ob_result;
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 18824e73ee5..49a518607f1 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -89,7 +89,6 @@
static CLG_LogRef LOG = {.identifier = "bke.lib_id"};
-/* Empty shell mostly, but needed for read code. */
IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
.id_code = ID_LINK_PLACEHOLDER,
.id_filter = 0,
@@ -99,6 +98,7 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
.name_plural = "link_placeholders",
.translation_context = BLT_I18NCONTEXT_ID_ID,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -106,6 +106,8 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = NULL,
+ .owner_get = NULL,
.blend_write = NULL,
.blend_read_data = NULL,
@@ -124,18 +126,56 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
/* ************* general ************************ */
/**
+ * Rewrites a relative path to be relative to the main file - unless the path is
+ * absolute, in which case it is not altered.
+ */
+static bool lib_id_library_local_paths_callback(BPathForeachPathData *bpath_data,
+ char *r_path_dst,
+ const char *path_src)
+{
+ const char **data = bpath_data->user_data;
+ /* be sure there is low chance of the path being too short */
+ char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
+ const char *base_new = data[0];
+ const char *base_old = data[1];
+
+ if (BLI_path_is_rel(base_old)) {
+ CLOG_ERROR(&LOG, "old base path '%s' is not absolute.", base_old);
+ return false;
+ }
+
+ /* Make referenced file absolute. This would be a side-effect of
+ * BLI_path_normalize, but we do it explicitly so we know if it changed. */
+ BLI_strncpy(filepath, path_src, FILE_MAX);
+ if (BLI_path_abs(filepath, base_old)) {
+ /* Path was relative and is now absolute. Remap.
+ * Important BLI_path_normalize runs before the path is made relative
+ * because it won't work for paths that start with "//../" */
+ BLI_path_normalize(base_new, filepath);
+ BLI_path_rel(filepath, base_new);
+ BLI_strncpy(r_path_dst, filepath, FILE_MAX);
+ return true;
+ }
+
+ /* Path was not relative to begin with. */
+ return false;
+}
+
+/**
* This has to be called from each make_local_* func, we could call from BKE_lib_id_make_local()
* but then the make local functions would not be self contained.
* Also note that the id _must_ have a library - campbell */
+/* TODO: This can probably be replaced by an ID-level version of #BKE_bpath_relative_rebase. */
static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id)
{
const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath_abs};
- BKE_bpath_traverse_id(bmain,
- id,
- BKE_bpath_relocate_visitor,
- BKE_BPATH_TRAVERSE_SKIP_MULTIFILE,
- (void *)bpath_user_data);
+ BKE_bpath_foreach_path_id(
+ &(BPathForeachPathData){.bmain = bmain,
+ .callback_function = lib_id_library_local_paths_callback,
+ .flag = BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE,
+ .user_data = (void *)bpath_user_data},
+ id);
}
static int lib_id_clear_library_data_users_update_cb(LibraryIDLinkCallbackData *cb_data)
@@ -149,11 +189,7 @@ static int lib_id_clear_library_data_users_update_cb(LibraryIDLinkCallbackData *
return IDWALK_RET_NOP;
}
-/**
- * Pull an ID out of a library (make it local). Only call this for IDs that
- * don't have other library users.
- */
-void BKE_lib_id_clear_library_data(Main *bmain, ID *id)
+void BKE_lib_id_clear_library_data(Main *bmain, ID *id, const int flags)
{
const bool id_in_mainlist = (id->tag & LIB_TAG_NO_MAIN) == 0 &&
(id->flag & LIB_EMBEDDED_DATA) == 0;
@@ -177,6 +213,16 @@ void BKE_lib_id_clear_library_data(Main *bmain, ID *id)
BKE_lib_libblock_session_uuid_renew(id);
}
+ if (ID_IS_ASSET(id)) {
+ if ((flags & LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR) != 0) {
+ BKE_asset_metadata_free(&id->asset_data);
+ }
+ else {
+ /* Assets should always have a fake user. Ensure this is the case after "Make Local". */
+ id_fake_user_set(id);
+ }
+ }
+
/* We need to tag this IDs and all of its users, conceptually new local ID and original linked
* ones are two completely different data-blocks that were virtually remapped, even though in
* reality they remain the same data. For undo this info is critical now. */
@@ -193,7 +239,7 @@ void BKE_lib_id_clear_library_data(Main *bmain, ID *id)
* IDs here, this is down automatically in `lib_id_expand_local_cb()`. */
Key *key = BKE_key_from_id(id);
if (key != NULL) {
- BKE_lib_id_clear_library_data(bmain, &key->id);
+ BKE_lib_id_clear_library_data(bmain, &key->id, flags);
}
DEG_relations_tag_update(bmain);
@@ -222,14 +268,6 @@ void id_lib_indirect_weak_link(ID *id)
}
}
-/**
- * Ensure we have a real user
- *
- * \note Now that we have flags, we could get rid of the 'fake_user' special case,
- * flags are enough to ensure we always have a real user.
- * However, #ID_REAL_USERS is used in several places outside of core lib.c,
- * so think we can wait later to make this change.
- */
void id_us_ensure_real(ID *id)
{
if (id) {
@@ -260,10 +298,6 @@ void id_us_clear_real(ID *id)
}
}
-/**
- * Same as \a id_us_plus, but does not handle lib indirect -> extern.
- * Only used by readfile.c so far, but simpler/safer to keep it here nonetheless.
- */
void id_us_plus_no_lib(ID *id)
{
if (id) {
@@ -288,7 +322,6 @@ void id_us_plus(ID *id)
}
}
-/* decrements the user count for *id. */
void id_us_min(ID *id)
{
if (id) {
@@ -372,6 +405,7 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
ID *id_self = cb_data->id_self;
ID **id_pointer = cb_data->id_pointer;
int const cb_flag = cb_data->cb_flag;
+ const int flags = POINTER_AS_INT(cb_data->user_data);
if (cb_flag & IDWALK_CB_LOOPBACK) {
/* We should never have anything to do with loop-back pointers here. */
@@ -386,7 +420,7 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
if (*id_pointer != NULL && ID_IS_LINKED(*id_pointer)) {
BLI_assert(*id_pointer != id_self);
- BKE_lib_id_clear_library_data(bmain, *id_pointer);
+ BKE_lib_id_clear_library_data(bmain, *id_pointer, flags);
}
return IDWALK_RET_NOP;
}
@@ -403,64 +437,77 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
-/**
- * Expand ID usages of given id as 'extern' (and no more indirect) linked data.
- * Used by ID copy/make_local functions.
- */
-void BKE_lib_id_expand_local(Main *bmain, ID *id)
+void BKE_lib_id_expand_local(Main *bmain, ID *id, const int flags)
{
- BKE_library_foreach_ID_link(bmain, id, lib_id_expand_local_cb, bmain, IDWALK_READONLY);
+ BKE_library_foreach_ID_link(
+ bmain, id, lib_id_expand_local_cb, POINTER_FROM_INT(flags), IDWALK_READONLY);
}
/**
* Ensure new (copied) ID is fully made local.
*/
-static void lib_id_copy_ensure_local(Main *bmain, const ID *old_id, ID *new_id)
+static void lib_id_copy_ensure_local(Main *bmain, const ID *old_id, ID *new_id, const int flags)
{
if (ID_IS_LINKED(old_id)) {
- BKE_lib_id_expand_local(bmain, new_id);
+ BKE_lib_id_expand_local(bmain, new_id, flags);
lib_id_library_local_paths(bmain, old_id->lib, new_id);
}
}
-/**
- * Generic 'make local' function, works for most of data-block types...
- */
-void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
+void BKE_lib_id_make_local_generic_action_define(
+ struct Main *bmain, struct ID *id, int flags, bool *r_force_local, bool *r_force_copy)
{
- if (!ID_IS_LINKED(id)) {
- return;
- }
-
- const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
BLI_assert(force_copy == false || force_copy != force_local);
+ if (force_local || force_copy) {
+ /* Already set by caller code, nothing to do here. */
+ *r_force_local = force_local;
+ *r_force_copy = force_copy;
+ return;
+ }
+
+ const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
bool is_local = false, is_lib = false;
- /* - only lib users: do nothing (unless force_local is set)
- * - only local users: set flag
+ /* - no user (neither lib nor local): make local (happens e.g. with UI-used only data).
+ * - only lib users: do nothing (unless force_local is set)
+ * - only local users: make local
* - mixed: make copy
* In case we make a whole lib's content local,
* we always want to localize, and we skip remapping (done later).
*/
- if (!force_copy && !force_local) {
- BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
- if (lib_local || is_local) {
- if (!is_lib) {
- force_local = true;
- }
- else {
- force_copy = true;
- }
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+ if (!lib_local && !is_local && !is_lib) {
+ force_local = true;
+ }
+ else if (lib_local || is_local) {
+ if (!is_lib) {
+ force_local = true;
+ }
+ else {
+ force_copy = true;
}
}
+ *r_force_local = force_local;
+ *r_force_copy = force_copy;
+}
+
+void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
+{
+ if (!ID_IS_LINKED(id)) {
+ return;
+ }
+
+ bool force_local, force_copy;
+ BKE_lib_id_make_local_generic_action_define(bmain, id, flags, &force_local, &force_copy);
+
if (force_local) {
- BKE_lib_id_clear_library_data(bmain, id);
- BKE_lib_id_expand_local(bmain, id);
+ BKE_lib_id_clear_library_data(bmain, id, flags);
+ BKE_lib_id_expand_local(bmain, id, flags);
}
else if (force_copy) {
ID *id_new = BKE_id_copy(bmain, id);
@@ -488,6 +535,7 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
}
}
+ const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
if (!lib_local) {
BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
@@ -495,15 +543,6 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
}
}
-/**
- * Calls the appropriate make_local method for the block, unless test is set.
- *
- * \note Always set #ID.newid pointer in case it gets duplicated.
- *
- * \param flags: Special flag used when making a whole library's content local,
- * it needs specific handling.
- * \return true is the ID has successfully been made local.
- */
bool BKE_lib_id_make_local(Main *bmain, ID *id, const int flags)
{
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
@@ -578,27 +617,6 @@ bool BKE_id_copy_is_allowed(const ID *id)
#undef LIB_ID_TYPES_NOCOPY
}
-/**
- * Generic entry point for copying a data-block (new API).
- *
- * \note Copy is generally only affecting the given data-block
- * (no ID used by copied one will be affected, besides usercount).
- * There are exceptions though:
- * - Embedded IDs (root node trees and master collections) are always copied with their owner.
- * - If #LIB_ID_COPY_ACTIONS is defined, actions used by animdata will be duplicated.
- * - If #LIB_ID_COPY_SHAPEKEY is defined, shapekeys will be duplicated.
- * - If #LIB_ID_CREATE_LOCAL is defined, root node trees will be deep-duplicated recursively.
- *
- * \note Usercount of new copy is always set to 1.
- *
- * \param bmain: Main database, may be NULL only if LIB_ID_CREATE_NO_MAIN is specified.
- * \param id: Source data-block.
- * \param r_newid: Pointer to new (copied) ID pointer, may be NULL. Used to allow copying into
- * already allocated memory.
- * \param flag: Set of copy options, see DNA_ID.h enum for details (leave to zero for default,
- * full copy).
- * \return NULL when copying that ID type is not supported, the new copy otherwise.
- */
ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
{
ID *newid = (r_newid != NULL) ? *r_newid : NULL;
@@ -648,7 +666,7 @@ ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
* XXX TODO: is this behavior OK, or should we need own flag to control that? */
if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
BLI_assert((flag & LIB_ID_COPY_KEEP_LIB) == 0);
- lib_id_copy_ensure_local(bmain, id, newid);
+ lib_id_copy_ensure_local(bmain, id, newid, 0);
}
else {
newid->lib = id->lib;
@@ -661,20 +679,15 @@ ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
return newid;
}
-/**
- * Invokes the appropriate copy method for the block and returns the result in
- * newid, unless test. Returns true if the block can be copied.
- */
ID *BKE_id_copy(Main *bmain, const ID *id)
{
return BKE_id_copy_ex(bmain, id, NULL, LIB_ID_COPY_DEFAULT);
}
-/**
- * Invokes the appropriate copy method for the block and returns the result in
- * newid, unless test. Returns true if the block can be copied.
- */
-ID *BKE_id_copy_for_duplicate(Main *bmain, ID *id, const eDupli_ID_Flags duplicate_flags)
+ID *BKE_id_copy_for_duplicate(Main *bmain,
+ ID *id,
+ const eDupli_ID_Flags duplicate_flags,
+ const int copy_flags)
{
if (id == NULL) {
return id;
@@ -685,7 +698,7 @@ ID *BKE_id_copy_for_duplicate(Main *bmain, ID *id, const eDupli_ID_Flags duplica
return id;
}
- ID *id_new = BKE_id_copy(bmain, id);
+ ID *id_new = BKE_id_copy_ex(bmain, id, NULL, copy_flags);
/* Copying add one user by default, need to get rid of that one. */
id_us_min(id_new);
ID_NEW_SET(id, id_new);
@@ -751,31 +764,16 @@ static void id_swap(Main *bmain, ID *id_a, ID *id_b, const bool do_full_id)
}
}
-/**
- * Does a mere memory swap over the whole IDs data (including type-specific memory).
- * \note Most internal ID data itself is not swapped (only IDProperties are).
- *
- * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
- * itself.
- */
void BKE_lib_id_swap(Main *bmain, ID *id_a, ID *id_b)
{
id_swap(bmain, id_a, id_b, false);
}
-/**
- * Does a mere memory swap over the whole IDs data (including type-specific memory).
- * \note All internal ID data itself is also swapped.
- *
- * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
- * itself.
- */
void BKE_lib_id_swap_full(Main *bmain, ID *id_a, ID *id_b)
{
id_swap(bmain, id_a, id_b, true);
}
-/** Does *not* set ID->newid pointer. */
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
{
ID *newid = NULL;
@@ -840,7 +838,6 @@ static int libblock_management_us_min(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
-/** Add a 'NO_MAIN' data-block to given main (also sets usercounts of its IDs if needed). */
void BKE_libblock_management_main_add(Main *bmain, void *idv)
{
ID *id = idv;
@@ -874,7 +871,6 @@ void BKE_libblock_management_main_add(Main *bmain, void *idv)
BKE_lib_libblock_session_uuid_ensure(id);
}
-/** Remove a data-block from given main (set it to 'NO_MAIN' status). */
void BKE_libblock_management_main_remove(Main *bmain, void *idv)
{
ID *id = idv;
@@ -919,9 +915,6 @@ void BKE_libblock_management_usercounts_clear(Main *bmain, void *idv)
id->tag |= LIB_TAG_NO_USER_REFCOUNT;
}
-/**
- * Clear or set given tags for all ids in listbase (runtime tags).
- */
void BKE_main_id_tag_listbase(ListBase *lb, const int tag, const bool value)
{
ID *id;
@@ -938,9 +931,6 @@ void BKE_main_id_tag_listbase(ListBase *lb, const int tag, const bool value)
}
}
-/**
- * Clear or set given tags for all ids of given type in bmain (runtime tags).
- */
void BKE_main_id_tag_idcode(struct Main *mainvar,
const short type,
const int tag,
@@ -951,9 +941,6 @@ void BKE_main_id_tag_idcode(struct Main *mainvar,
BKE_main_id_tag_listbase(lb, tag, value);
}
-/**
- * Clear or set given tags for all ids in bmain (runtime tags).
- */
void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value)
{
ListBase *lbarray[INDEX_ID_MAX];
@@ -965,9 +952,6 @@ void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value)
}
}
-/**
- * Clear or set given flags for all ids in listbase (persistent flags).
- */
void BKE_main_id_flag_listbase(ListBase *lb, const int flag, const bool value)
{
ID *id;
@@ -984,9 +968,6 @@ void BKE_main_id_flag_listbase(ListBase *lb, const int flag, const bool value)
}
}
-/**
- * Clear or set given flags for all ids in bmain (persistent flags).
- */
void BKE_main_id_flag_all(Main *bmain, const int flag, const bool value)
{
ListBase *lbarray[INDEX_ID_MAX];
@@ -1052,9 +1033,6 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
*
* **************************** */
-/**
- * Get allocation size of a given data-block type and optionally allocation name.
- */
size_t BKE_libblock_get_alloc_info(short type, const char **name)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(type);
@@ -1072,10 +1050,6 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name)
return id_type->struct_size;
}
-/**
- * Allocates and returns memory of the right size for the specified block type,
- * initialized to zero.
- */
void *BKE_libblock_alloc_notest(short type)
{
const char *name;
@@ -1087,12 +1061,6 @@ void *BKE_libblock_alloc_notest(short type)
return NULL;
}
-/**
- * Allocates and returns a block of the specified type, with the specified name
- * (adjusted as necessary to ensure uniqueness), and appended to the specified list.
- * The user count is set to 1, all other content (apart from name and links) being
- * initialized to zero.
- */
void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int flag)
{
BLI_assert((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
@@ -1118,8 +1086,9 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
id->us = 1;
}
if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- /* Note that 2.8x versioning has tested not to cause conflicts. */
- BLI_assert(bmain->is_locked_for_linking == false || ELEM(type, ID_WS, ID_GR));
+ /* Note that 2.8x versioning has tested not to cause conflicts. Node trees are
+ * skipped in this check to allow adding a geometry node tree for versioning. */
+ BLI_assert(bmain->is_locked_for_linking == false || ELEM(type, ID_WS, ID_GR, ID_NT));
ListBase *lb = which_libbase(bmain, type);
BKE_main_lock(bmain);
@@ -1129,6 +1098,11 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
/* alphabetic insertion: is in new_id */
BKE_main_unlock(bmain);
+ /* This is important in 'readfile doversion after liblink' context mainly, but is a good
+ * consistency change in general: ID created for a Main should get that main's current
+ * library pointer. */
+ id->lib = bmain->curlib;
+
/* TODO: to be removed from here! */
if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0) {
DEG_id_type_tag(bmain, type);
@@ -1149,10 +1123,6 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
return id;
}
-/**
- * Initialize an ID of given type, such that it has valid 'empty' data.
- * ID is assumed to be just calloc'ed.
- */
void BKE_libblock_init_empty(ID *id)
{
const IDTypeInfo *idtype_info = BKE_idtype_get_info_from_id(id);
@@ -1170,12 +1140,6 @@ void BKE_libblock_init_empty(ID *id)
/* ********** ID session-wise UUID management. ********** */
static uint global_session_uuid = 0;
-/**
- * Generate a session-wise uuid for the given \a id.
- *
- * \note "session-wise" here means while editing a given .blend file. Once a new .blend file is
- * loaded or created, undo history is cleared/reset, and so is the uuid counter.
- */
void BKE_lib_libblock_session_uuid_ensure(ID *id)
{
if (id->session_uuid == MAIN_ID_SESSION_UUID_UNSET) {
@@ -1189,25 +1153,12 @@ void BKE_lib_libblock_session_uuid_ensure(ID *id)
}
}
-/**
- * Re-generate a new session-wise uuid for the given \a id.
- *
- * \warning This has a few very specific use-cases, no other usage is expected currently:
- * - To handle UI-related data-blocks that are kept across new file reading, when we do keep
- * existing UI.
- * - For IDs that are made local without needing any copying.
- */
void BKE_lib_libblock_session_uuid_renew(ID *id)
{
id->session_uuid = MAIN_ID_SESSION_UUID_UNSET;
BKE_lib_libblock_session_uuid_ensure(id);
}
-/**
- * Generic helper to create a new empty data-block of given type in given \a bmain database.
- *
- * \param name: can be NULL, in which case we get default name for this ID type.
- */
void *BKE_id_new(Main *bmain, const short type, const char *name)
{
BLI_assert(bmain != NULL);
@@ -1222,11 +1173,6 @@ void *BKE_id_new(Main *bmain, const short type, const char *name)
return id;
}
-/**
- * Generic helper to create a new temporary empty data-block of given type,
- * *outside* of any Main database.
- *
- * \param name: can be NULL, in which case we get default name for this ID type. */
void *BKE_id_new_nomain(const short type, const char *name)
{
if (name == NULL) {
@@ -1340,7 +1286,6 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori
*r_newid = new_id;
}
-/* used everywhere in blenkernel */
void *BKE_libblock_copy(Main *bmain, const ID *id)
{
ID *idn;
@@ -1351,6 +1296,7 @@ void *BKE_libblock_copy(Main *bmain, const ID *id)
}
/* ***************** ID ************************ */
+
ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *name)
{
ListBase *lb = which_libbase(bmain, type);
@@ -1358,14 +1304,20 @@ ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *nam
return BLI_findstring(lb, name, offsetof(ID, name) + 2);
}
-/**
- * Sort given \a id into given \a lb list, using case-insensitive comparison of the id names.
- *
- * \note All other IDs beside given one are assumed already properly sorted in the list.
- *
- * \param id_sorting_hint: Ignored if NULL. Otherwise, used to check if we can insert \a id
- * immediately before or after that pointer. It must always be into given \a lb list.
- */
+struct ID *BKE_libblock_find_session_uuid(Main *bmain,
+ const short type,
+ const uint32_t session_uuid)
+{
+ ListBase *lb = which_libbase(bmain, type);
+ BLI_assert(lb != NULL);
+ LISTBASE_FOREACH (ID *, id, lb) {
+ if (id->session_uuid == session_uuid) {
+ return id;
+ }
+ }
+ return NULL;
+}
+
void id_sort_by_name(ListBase *lb, ID *id, ID *id_sorting_hint)
{
#define ID_SORT_STEP_SIZE 512
@@ -1723,16 +1675,6 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name, ID **r_id_sorting_
#undef MIN_NUMBER
#undef MAX_NUMBER
-/**
- * Ensures given ID has a unique name in given listbase.
- *
- * Only for local IDs (linked ones already have a unique ID in their library).
- *
- * \param do_linked_data: if true, also ensure a unique name in case the given \a id is linked
- * (otherwise, just ensure that it is properly sorted).
- *
- * \return true if a new name had to be created.
- */
bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname, const bool do_linked_data)
{
bool result = false;
@@ -1782,7 +1724,6 @@ bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname, const boo
return result;
}
-/* next to indirect usage in read/writefile also in editobject.c scene.c */
void BKE_main_id_newptr_and_tag_clear(Main *bmain)
{
ID *id;
@@ -1905,30 +1846,20 @@ static void library_make_local_copying_check(ID *id,
BLI_gset_remove(loop_tags, id, NULL);
}
-/**
- * Make linked data-blocks local.
- *
- * \param bmain: Almost certainly global main.
- * \param lib: If not NULL, only make local data-blocks from this library.
- * \param untagged_only: If true, only make local data-blocks not tagged with
- * LIB_TAG_PRE_EXISTING.
- * \param set_fake: If true, set fake user on all localized data-blocks
- * (except group and objects ones).
- */
/* NOTE: Old (2.77) version was simply making (tagging) data-blocks as local,
* without actually making any check whether they were also indirectly used or not...
*
* Current version uses regular id_make_local callback, with advanced pre-processing step to
* detect all cases of IDs currently indirectly used, but which will be used by local data only
* once this function is finished. This allows to avoid any unneeded duplication of IDs, and
- * hence all time lost afterwards to remove orphaned linked data-blocks...
- */
+ * hence all time lost afterwards to remove orphaned linked data-blocks. */
void BKE_library_make_local(Main *bmain,
const Library *lib,
GHash *old_to_new_ids,
const bool untagged_only,
const bool set_fake)
{
+
ListBase *lbarray[INDEX_ID_MAX];
LinkNode *todo_ids = NULL;
@@ -2042,8 +1973,8 @@ void BKE_library_make_local(Main *bmain,
* currently there are some indirect usages. So instead of making a copy that we'll likely
* get rid of later, directly make that data block local.
* Saves a tremendous amount of time with complex scenes... */
- BKE_lib_id_clear_library_data(bmain, id);
- BKE_lib_id_expand_local(bmain, id);
+ BKE_lib_id_clear_library_data(bmain, id, 0);
+ BKE_lib_id_expand_local(bmain, id, 0);
id->tag &= ~LIB_TAG_DOIT;
if (GS(id->name) == ID_OB) {
@@ -2202,10 +2133,6 @@ void BKE_library_make_local(Main *bmain,
#endif
}
-/**
- * Use after setting the ID's name
- * When name exists: call 'new_id'
- */
void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
{
ListBase *lb;
@@ -2225,9 +2152,6 @@ void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
}
}
-/**
- * Sets the name of a block to name, suitably adjusted for uniqueness.
- */
void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
{
BLI_assert(!ID_IS_LINKED(id));
@@ -2237,16 +2161,6 @@ void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
}
}
-/**
- * Generate full name of the data-block (without ID code, but with library if any).
- *
- * \note Result is unique to a given ID type in a given Main database.
- *
- * \param name: An allocated string of minimal length #MAX_ID_FULL_NAME,
- * will be filled with generated string.
- * \param separator_char: Character to use for separating name and library name. Can be 0 to use
- * default (' ').
- */
void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id, char separator_char)
{
strcpy(name, id->name + 2);
@@ -2263,19 +2177,6 @@ void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id, char separa
}
}
-/**
- * Generate full name of the data-block (without ID code, but with library if any),
- * with a 2 to 3 character prefix prepended indicating whether it comes from a library,
- * is overriding, has a fake or no user, etc.
- *
- * \note Result is unique to a given ID type in a given Main database.
- *
- * \param name: An allocated string of minimal length #MAX_ID_FULL_NAME_UI,
- * will be filled with generated string.
- * \param separator_char: Character to use for separating name and library name. Can be 0 to use
- * default (' ').
- * \param r_prefix_len: The length of the prefix added.
- */
void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI],
const ID *id,
const bool add_lib_hint,
@@ -2297,11 +2198,6 @@ void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI],
}
}
-/**
- * Generate a concatenation of ID name (including two-chars type code) and its lib name, if any.
- *
- * \return A unique allocated string key for any ID in the whole Main database.
- */
char *BKE_id_to_unique_string_key(const struct ID *id)
{
if (!ID_IS_LINKED(id)) {
@@ -2325,10 +2221,6 @@ void BKE_id_tag_clear_atomic(ID *id, int tag)
atomic_fetch_and_and_int32(&id->tag, ~tag);
}
-/**
- * Check that given ID pointer actually is in G_MAIN.
- * Main intended use is for debug asserts in places we cannot easily get rid of G_Main...
- */
bool BKE_id_is_in_global_main(ID *id)
{
/* We do not want to fail when id is NULL here, even though this is a bit strange behavior...
@@ -2375,10 +2267,6 @@ static int id_order_compare(const void *a, const void *b)
return strcmp(id_a->name, id_b->name);
}
-/**
- * Returns ordered list of data-blocks for display in the UI.
- * Result is list of LinkData of IDs that must be freed.
- */
void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb)
{
BLI_listbase_clear(ordered_lb);
@@ -2398,9 +2286,6 @@ void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb)
}
}
-/**
- * Reorder ID in the list, before or after the "relative" ID.
- */
void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after)
{
int *id_order = id_order_get(id);
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 502a1197616..f4dd67cac28 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -90,23 +90,6 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
BLI_assert_msg(0, "IDType Missing IDTypeInfo");
}
-/**
- * Complete ID freeing, extended version for corner cases.
- * Can override default (and safe!) freeing process, to gain some speed up.
- *
- * At that point, given id is assumed to not be used by any other data-block already
- * (might not be actually true, in case e.g. several inter-related IDs get freed together...).
- * However, they might still be using (referencing) other IDs, this code takes care of it if
- * #LIB_TAG_NO_USER_REFCOUNT is not defined.
- *
- * \param bmain: #Main database containing the freed #ID,
- * can be NULL in case it's a temp ID outside of any #Main.
- * \param idv: Pointer to ID to be freed.
- * \param flag: Set of \a LIB_ID_FREE_... flags controlling/overriding usual freeing process,
- * 0 to get default safe behavior.
- * \param use_flag_from_idtag: Still use freeing info flags from given #ID datablock,
- * even if some overriding ones are passed in \a flag parameter.
- */
void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_idtag)
{
ID *id = idv;
@@ -171,7 +154,10 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
}
if (remap_editor_id_reference_cb) {
- remap_editor_id_reference_cb(id, NULL);
+ struct IDRemapper *remapper = BKE_id_remapper_create();
+ BKE_id_remapper_add(remapper, id, NULL);
+ remap_editor_id_reference_cb(remapper);
+ BKE_id_remapper_free(remapper);
}
}
@@ -191,24 +177,11 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
}
}
-/**
- * Complete ID freeing, should be usable in most cases (even for out-of-Main IDs).
- *
- * See #BKE_id_free_ex description for full details.
- *
- * \param bmain: Main database containing the freed ID,
- * can be NULL in case it's a temp ID outside of any Main.
- * \param idv: Pointer to ID to be freed.
- */
void BKE_id_free(Main *bmain, void *idv)
{
BKE_id_free_ex(bmain, idv, 0, true);
}
-/**
- * Not really a freeing function by itself,
- * it decrements usercount of given id, and only frees it if it reaches 0.
- */
void BKE_id_free_us(Main *bmain, void *idv) /* test users */
{
ID *id = idv;
@@ -322,32 +295,40 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
* Note that we go forward here, since we want to check dependencies before users
* (e.g. meshes before objects).
* Avoids to have to loop twice. */
+ struct IDRemapper *remapper = BKE_id_remapper_create();
for (i = 0; i < base_count; i++) {
ListBase *lb = lbarray[i];
ID *id, *id_next;
+ BKE_id_remapper_clear(remapper);
for (id = lb->first; id; id = id_next) {
id_next = id->next;
/* NOTE: in case we delete a library, we also delete all its datablocks! */
if ((id->tag & tag) || (id->lib != NULL && (id->lib->id.tag & tag))) {
id->tag |= tag;
-
- /* Will tag 'never NULL' users of this ID too.
- * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect
- * (and proxy!) links, this can lead to nasty crashing here in second,
- * actual deleting loop.
- * Also, this will also flag users of deleted data that cannot be unlinked
- * (object using deleted obdata, etc.), so that they also get deleted. */
- BKE_libblock_remap_locked(bmain,
- id,
- NULL,
- (ID_REMAP_FLAG_NEVER_NULL_USAGE |
- ID_REMAP_FORCE_NEVER_NULL_USAGE |
- ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS));
+ BKE_id_remapper_add(remapper, id, NULL);
}
}
+
+ if (BKE_id_remapper_is_empty(remapper)) {
+ continue;
+ }
+
+ /* Will tag 'never NULL' users of this ID too.
+ * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect
+ * (and proxy!) links, this can lead to nasty crashing here in second,
+ * actual deleting loop.
+ * Also, this will also flag users of deleted data that cannot be unlinked
+ * (object using deleted obdata, etc.), so that they also get deleted. */
+ BKE_libblock_remap_multiple_locked(bmain,
+ remapper,
+ (ID_REMAP_FLAG_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS));
}
+ BKE_id_remapper_free(remapper);
}
+
BKE_main_unlock(bmain);
/* In usual reversed order, such that all usage of a given ID, even 'never NULL' ones,
@@ -378,27 +359,17 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
return num_datablocks_deleted;
}
-/**
- * Properly delete a single ID from given \a bmain database.
- */
void BKE_id_delete(Main *bmain, void *idv)
{
+ BLI_assert_msg((((ID *)idv)->tag & LIB_TAG_NO_MAIN) == 0,
+ "Cannot be used with IDs outside of Main");
+
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
((ID *)idv)->tag |= LIB_TAG_DOIT;
id_delete(bmain, false);
}
-/**
- * Properly delete all IDs tagged with \a LIB_TAG_DOIT, in given \a bmain database.
- *
- * This is more efficient than calling #BKE_id_delete repetitively on a large set of IDs
- * (several times faster when deleting most of the IDs at once)...
- *
- * \warning Considered experimental for now, seems to be working OK but this is
- * risky code in a complicated area.
- * \return Number of deleted datablocks.
- */
size_t BKE_id_multi_tagged_delete(Main *bmain)
{
return id_delete(bmain, true);
@@ -408,12 +379,6 @@ size_t BKE_id_multi_tagged_delete(Main *bmain)
/** \name Python Data Handling
* \{ */
-/**
- * In most cases #BKE_id_free_ex handles this, when lower level functions are called directly
- * this function will need to be called too, if Python has access to the data.
- *
- * ID data-blocks such as #Material.nodetree are not stored in #Main.
- */
void BKE_libblock_free_data_py(ID *id)
{
#ifdef WITH_PYTHON
diff --git a/source/blender/blenkernel/intern/lib_id_eval.c b/source/blender/blenkernel/intern/lib_id_eval.c
index 140fe403ac3..a29d9270d72 100644
--- a/source/blender/blenkernel/intern/lib_id_eval.c
+++ b/source/blender/blenkernel/intern/lib_id_eval.c
@@ -29,11 +29,6 @@
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
-/**
- * Copy relatives parameters, from `id` to `id_cow`.
- * Use handle the #ID_RECALC_PARAMETERS tag.
- * \note Keep in sync with #ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW.
- */
void BKE_id_eval_properties_copy(ID *id_cow, ID *id)
{
const ID_Type id_type = GS(id->name);
diff --git a/source/blender/blenkernel/intern/lib_id_remapper.cc b/source/blender/blenkernel/intern/lib_id_remapper.cc
new file mode 100644
index 00000000000..c1734c9826a
--- /dev/null
+++ b/source/blender/blenkernel/intern/lib_id_remapper.cc
@@ -0,0 +1,175 @@
+/*
+ * 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) 2022 by Blender Foundation.
+ */
+
+#include "DNA_ID.h"
+
+#include "BKE_idtype.h"
+#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_map.hh"
+
+using IDTypeFilter = uint64_t;
+
+namespace blender::bke::id::remapper {
+struct IDRemapper {
+ private:
+ Map<ID *, ID *> mappings;
+ IDTypeFilter source_types = 0;
+
+ public:
+ void clear()
+ {
+ mappings.clear();
+ source_types = 0;
+ }
+
+ bool is_empty() const
+ {
+ return mappings.is_empty();
+ }
+
+ void add(ID *old_id, ID *new_id)
+ {
+ BLI_assert(old_id != nullptr);
+ BLI_assert(new_id == nullptr || (GS(old_id->name) == GS(new_id->name)));
+ mappings.add(old_id, new_id);
+ source_types |= BKE_idtype_idcode_to_idfilter(GS(old_id->name));
+ }
+
+ bool contains_mappings_for_any(IDTypeFilter filter) const
+ {
+ return (source_types & filter) != 0;
+ }
+
+ IDRemapperApplyResult apply(ID **r_id_ptr, IDRemapperApplyOptions options) const
+ {
+ BLI_assert(r_id_ptr != nullptr);
+ if (*r_id_ptr == nullptr) {
+ return ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE;
+ }
+
+ if (!mappings.contains(*r_id_ptr)) {
+ return ID_REMAP_RESULT_SOURCE_UNAVAILABLE;
+ }
+
+ if (options & ID_REMAP_APPLY_UPDATE_REFCOUNT) {
+ id_us_min(*r_id_ptr);
+ }
+
+ *r_id_ptr = mappings.lookup(*r_id_ptr);
+ if (*r_id_ptr == nullptr) {
+ return ID_REMAP_RESULT_SOURCE_UNASSIGNED;
+ }
+
+ if (options & ID_REMAP_APPLY_UPDATE_REFCOUNT) {
+ id_us_plus(*r_id_ptr);
+ }
+
+ if (options & ID_REMAP_APPLY_ENSURE_REAL) {
+ id_us_ensure_real(*r_id_ptr);
+ }
+ return ID_REMAP_RESULT_SOURCE_REMAPPED;
+ }
+
+ void iter(IDRemapperIterFunction func, void *user_data) const
+ {
+ for (auto item : mappings.items()) {
+ func(item.key, item.value, user_data);
+ }
+ }
+};
+
+} // namespace blender::bke::id::remapper
+
+/** \brief wrap CPP IDRemapper to a C handle. */
+static IDRemapper *wrap(blender::bke::id::remapper::IDRemapper *remapper)
+{
+ return static_cast<IDRemapper *>(static_cast<void *>(remapper));
+}
+
+/** \brief wrap C handle to a CPP IDRemapper. */
+static blender::bke::id::remapper::IDRemapper *unwrap(IDRemapper *remapper)
+{
+ return static_cast<blender::bke::id::remapper::IDRemapper *>(static_cast<void *>(remapper));
+}
+
+/** \brief wrap C handle to a CPP IDRemapper. */
+static const blender::bke::id::remapper::IDRemapper *unwrap(const IDRemapper *remapper)
+{
+ return static_cast<const blender::bke::id::remapper::IDRemapper *>(
+ static_cast<const void *>(remapper));
+}
+
+extern "C" {
+
+IDRemapper *BKE_id_remapper_create(void)
+{
+ blender::bke::id::remapper::IDRemapper *remapper =
+ MEM_new<blender::bke::id::remapper::IDRemapper>(__func__);
+ return wrap(remapper);
+}
+
+void BKE_id_remapper_free(IDRemapper *id_remapper)
+{
+ blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ MEM_delete<blender::bke::id::remapper::IDRemapper>(remapper);
+}
+
+void BKE_id_remapper_clear(struct IDRemapper *id_remapper)
+{
+ blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ remapper->clear();
+}
+
+bool BKE_id_remapper_is_empty(const struct IDRemapper *id_remapper)
+{
+ const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ return remapper->is_empty();
+}
+
+void BKE_id_remapper_add(IDRemapper *id_remapper, ID *old_id, ID *new_id)
+{
+ blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ remapper->add(old_id, new_id);
+}
+
+bool BKE_id_remapper_has_mapping_for(const struct IDRemapper *id_remapper, uint64_t type_filter)
+{
+ const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ return remapper->contains_mappings_for_any(type_filter);
+}
+
+IDRemapperApplyResult BKE_id_remapper_apply(const IDRemapper *id_remapper,
+ ID **r_id_ptr,
+ const IDRemapperApplyOptions options)
+{
+ const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ return remapper->apply(r_id_ptr, options);
+}
+
+void BKE_id_remapper_iter(const struct IDRemapper *id_remapper,
+ IDRemapperIterFunction func,
+ void *user_data)
+{
+ const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ remapper->iter(func, user_data);
+}
+}
diff --git a/source/blender/blenkernel/intern/lib_id_remapper_test.cc b/source/blender/blenkernel/intern/lib_id_remapper_test.cc
new file mode 100644
index 00000000000..594f64dac73
--- /dev/null
+++ b/source/blender/blenkernel/intern/lib_id_remapper_test.cc
@@ -0,0 +1,83 @@
+/*
+ * 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) 2022 by Blender Foundation.
+ */
+
+#include "testing/testing.h"
+
+#include "BKE_lib_remap.h"
+
+#include "BLI_string.h"
+
+#include "DNA_ID.h"
+
+namespace blender::bke::id::remapper::tests {
+
+TEST(lib_id_remapper, unavailable)
+{
+ ID id1;
+ ID *idp = &id1;
+
+ IDRemapper *remapper = BKE_id_remapper_create();
+ IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
+ EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_UNAVAILABLE);
+
+ BKE_id_remapper_free(remapper);
+}
+
+TEST(lib_id_remapper, not_mappable)
+{
+ ID *idp = nullptr;
+
+ IDRemapper *remapper = BKE_id_remapper_create();
+ IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
+ EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE);
+
+ BKE_id_remapper_free(remapper);
+}
+
+TEST(lib_id_remapper, mapped)
+{
+ ID id1;
+ ID id2;
+ ID *idp = &id1;
+ BLI_strncpy(id1.name, "OB1", sizeof(id1.name));
+ BLI_strncpy(id2.name, "OB2", sizeof(id2.name));
+
+ IDRemapper *remapper = BKE_id_remapper_create();
+ BKE_id_remapper_add(remapper, &id1, &id2);
+ IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
+ EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_REMAPPED);
+ EXPECT_EQ(idp, &id2);
+
+ BKE_id_remapper_free(remapper);
+}
+
+TEST(lib_id_remapper, unassigned)
+{
+ ID id1;
+ ID *idp = &id1;
+
+ IDRemapper *remapper = BKE_id_remapper_create();
+ BKE_id_remapper_add(remapper, &id1, nullptr);
+ IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
+ EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_UNASSIGNED);
+ EXPECT_EQ(idp, nullptr);
+
+ BKE_id_remapper_free(remapper);
+}
+
+} // namespace blender::bke::id::remapper::tests
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 68675e5fc91..d1375b1e5b5 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -57,6 +57,7 @@
#include "BLI_ghash.h"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
+#include "BLI_memarena.h"
#include "BLI_string.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -99,7 +100,6 @@ BLI_INLINE IDOverrideLibrary *lib_override_get(Main *bmain, ID *id)
return id->override_library;
}
-/** Initialize empty overriding of \a reference_id by \a local_id. */
IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id)
{
/* If reference_id is NULL, we are creating an override template for purely local data.
@@ -134,7 +134,6 @@ IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id)
return local_id->override_library;
}
-/** Shalow or deep copy of a whole override from \a src_id to \a dst_id. */
void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_full_copy)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY(src_id) || ID_IS_OVERRIDE_LIBRARY_TEMPLATE(src_id));
@@ -176,7 +175,6 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f
dst_id->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK;
}
-/** Clear any overriding data from given \a override. */
void BKE_lib_override_library_clear(IDOverrideLibrary *override, const bool do_id_user)
{
BLI_assert(override != NULL);
@@ -196,7 +194,6 @@ void BKE_lib_override_library_clear(IDOverrideLibrary *override, const bool do_i
}
}
-/** Free given \a override. */
void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user)
{
BLI_assert(*override != NULL);
@@ -245,14 +242,11 @@ static ID *lib_override_library_create_from(Main *bmain,
return local_id;
}
-/**
- * Check if given ID has some override rules that actually indicate the user edited it.
- *
- * TODO: This could be simplified by storing a flag in #IDOverrideLibrary during the diffing
- * process?
- */
+/* TODO: This could be simplified by storing a flag in #IDOverrideLibrary
+ * during the diffing process? */
bool BKE_lib_override_library_is_user_edited(struct ID *id)
{
+
if (!ID_IS_OVERRIDE_LIBRARY(id)) {
return false;
}
@@ -280,7 +274,6 @@ bool BKE_lib_override_library_is_user_edited(struct ID *id)
return false;
}
-/** Create an overridden local copy of linked reference. */
ID *BKE_lib_override_library_create_from_id(Main *bmain,
ID *reference_id,
const bool do_tagged_remap)
@@ -289,6 +282,10 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
BLI_assert(ID_IS_LINKED(reference_id));
ID *local_id = lib_override_library_create_from(bmain, reference_id, 0);
+ /* We cannot allow automatic hierarchy resync on this ID, it is highly likely to generate a giant
+ * mess in case there are a lot of hidden, non-instantiated, non-properly organized dependencies.
+ * Ref T94650. */
+ local_id->override_library->flag |= IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY;
if (do_tagged_remap) {
Key *reference_key, *local_key = NULL;
@@ -322,25 +319,6 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
return local_id;
}
-/**
- * Create overridden local copies of all tagged data-blocks in given Main.
- *
- * \note Set `id->newid` of overridden libs with newly created overrides,
- * caller is responsible to clean those pointers before/after usage as needed.
- *
- * \note By default, it will only remap newly created local overriding data-blocks between
- * themselves, to avoid 'enforcing' those overrides into all other usages of the linked data in
- * main. You can add more local IDs to be remapped to use new overriding ones by setting their
- * LIB_TAG_DOIT tag.
- *
- * \param reference_library: the library from which the linked data being overridden come from
- * (i.e. the library of the linked reference ID).
- *
- * \param do_no_main: Create the new override data outside of Main database.
- * Used for resyncing of linked overrides.
- *
- * \return \a true on success, \a false otherwise.
- */
bool BKE_lib_override_library_create_from_tag(Main *bmain,
const Library *reference_library,
const bool do_no_main)
@@ -398,7 +376,6 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
* existing linked IDs usages. */
if (success) {
for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
- ID *other_id;
reference_id = todo_id_iter->data;
ID *local_id = reference_id->newid;
@@ -416,6 +393,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
* remapped to use newly created overriding IDs, if needed. */
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ ID *other_id;
/* In case we created new overrides as 'no main', they are not accessible directly in this
* loop, but we can get to them through their reference's `newid` pointer. */
if (do_no_main && id->lib == reference_id->lib && id->newid != NULL) {
@@ -479,8 +457,60 @@ typedef struct LibOverrideGroupTagData {
bool is_override;
/* Whether we are creating new override, or resyncing existing one. */
bool is_resync;
+
+ /* Mapping linked objects to all their instantiating collections (as a linked list).
+ * Avoids calling #BKE_collection_object_find over and over, this function is very expansive. */
+ GHash *linked_object_to_instantiating_collections;
+ MemArena *mem_arena;
} LibOverrideGroupTagData;
+static void lib_override_group_tag_data_object_to_collection_init_collection_process(
+ LibOverrideGroupTagData *data, Collection *collection)
+{
+ LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
+ Object *ob = collection_object->ob;
+ if (!ID_IS_LINKED(ob)) {
+ continue;
+ }
+
+ LinkNodePair **collections_linkedlist_p;
+ if (!BLI_ghash_ensure_p(data->linked_object_to_instantiating_collections,
+ ob,
+ (void ***)&collections_linkedlist_p)) {
+ *collections_linkedlist_p = BLI_memarena_calloc(data->mem_arena,
+ sizeof(**collections_linkedlist_p));
+ }
+ BLI_linklist_append_arena(*collections_linkedlist_p, collection, data->mem_arena);
+ }
+}
+
+/* Initialize complex data, `data` is expected to be already initialized with basic pointers and
+ * other simple data.
+ *
+ * NOTE: Currently creates a mapping from linked object to all of their instantiating collections
+ * (as returned by #BKE_collection_object_find). */
+static void lib_override_group_tag_data_object_to_collection_init(LibOverrideGroupTagData *data)
+{
+ data->mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ data->linked_object_to_instantiating_collections = BLI_ghash_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ if (data->scene != NULL) {
+ lib_override_group_tag_data_object_to_collection_init_collection_process(
+ data, data->scene->master_collection);
+ }
+ LISTBASE_FOREACH (Collection *, collection, &data->bmain->collections) {
+ lib_override_group_tag_data_object_to_collection_init_collection_process(data, collection);
+ }
+}
+
+static void lib_override_group_tag_data_clear(LibOverrideGroupTagData *data)
+{
+ BLI_ghash_free(data->linked_object_to_instantiating_collections, NULL, NULL);
+ BLI_memarena_free(data->mem_arena);
+ memset(data, 0, sizeof(*data));
+}
+
/* Tag all IDs in dependency relationships within an override hierarchy/group.
*
* Requires existing `Main.relations`.
@@ -586,6 +616,42 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
}
}
+static void lib_override_linked_group_tag_clear_boneshapes_objects(LibOverrideGroupTagData *data)
+{
+ Main *bmain = data->bmain;
+
+ /* Remove (untag) bone shape objects, they shall never need to be to directly/explicitly
+ * overridden. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & data->tag)) {
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ if (pchan->custom != NULL) {
+ pchan->custom->id.tag &= ~data->tag;
+ }
+ }
+ }
+ }
+
+ /* Remove (untag) collections if they do not own any tagged object (either themselves, or in
+ * their children collections). */
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ if ((collection->id.tag & data->tag) == 0) {
+ continue;
+ }
+ bool keep_tagged = false;
+ const ListBase object_bases = BKE_collection_object_cache_get(collection);
+ LISTBASE_FOREACH (Base *, base, &object_bases) {
+ if ((base->object->id.tag & data->tag) != 0) {
+ keep_tagged = true;
+ break;
+ }
+ }
+ if (!keep_tagged) {
+ collection->id.tag &= ~data->tag;
+ }
+ }
+}
+
/* This will tag at least all 'boundary' linked IDs for a potential override group.
*
* Requires existing `Main.relations`.
@@ -599,7 +665,6 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
{
Main *bmain = data->bmain;
- Scene *scene = data->scene;
ID *id_root = data->id_root;
const bool is_resync = data->is_resync;
BLI_assert(!data->is_override);
@@ -611,36 +676,36 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
id_root->tag |= data->tag;
}
- if (ELEM(GS(id_root->name), ID_OB, ID_GR)) {
- /* Tag all collections and objects. */
- lib_override_linked_group_tag_recursive(data);
+ /* Only objects and groups are currently considered as 'keys' in override hierarchies. */
+ if (!ELEM(GS(id_root->name), ID_OB, ID_GR)) {
+ return;
+ }
- /* Then, we remove (untag) bone shape objects, you shall never want to directly/explicitly
- * override those. */
- LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
- if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & data->tag)) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
- if (pchan->custom != NULL) {
- pchan->custom->id.tag &= ~(data->tag | data->missing_tag);
- }
- }
- }
- }
+ /* Tag all collections and objects recursively. */
+ lib_override_linked_group_tag_recursive(data);
- /* For each object tagged for override, ensure we get at least one local or liboverride
- * collection to host it. Avoids getting a bunch of random object in the scene's master
- * collection when all objects' dependencies are not properly 'packed' into a single root
- * collection. */
- LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
- if (ID_IS_LINKED(ob) && (ob->id.tag & data->tag) != 0) {
- Collection *instantiating_collection = NULL;
- Collection *instantiating_collection_override_candidate = NULL;
- /* Loop over all collections instantiating the object, if we already have a 'locale' one we
- * have nothing to do, otherwise try to find a 'linked' one that we can override too. */
- while ((instantiating_collection = BKE_collection_object_find(
- bmain, scene, instantiating_collection, ob)) != NULL) {
- /* In (recursive) resync case, if a collection of a 'parent' lib instantiates the linked
- * object, it is also fine. */
+ /* Do not override objects used as bone shapes, nor their collections if possible. */
+ lib_override_linked_group_tag_clear_boneshapes_objects(data);
+
+ /* For each object tagged for override, ensure we get at least one local or liboverride
+ * collection to host it. Avoids getting a bunch of random object in the scene's master
+ * collection when all objects' dependencies are not properly 'packed' into a single root
+ * collection. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ID_IS_LINKED(ob) && (ob->id.tag & data->tag) != 0) {
+ Collection *instantiating_collection = NULL;
+ Collection *instantiating_collection_override_candidate = NULL;
+ /* Loop over all collections instantiating the object, if we already have a 'locale' one we
+ * have nothing to do, otherwise try to find a 'linked' one that we can override too. */
+ LinkNodePair *instantiating_collection_linklist = BLI_ghash_lookup(
+ data->linked_object_to_instantiating_collections, ob);
+ if (instantiating_collection_linklist != NULL) {
+ for (LinkNode *instantiating_collection_linknode = instantiating_collection_linklist->list;
+ instantiating_collection_linknode != NULL;
+ instantiating_collection_linknode = instantiating_collection_linknode->next) {
+ instantiating_collection = instantiating_collection_linknode->link;
+ /* In (recursive) resync case, if a collection of a 'parent' lib instantiates the
+ * linked object, it is also fine. */
if (!ID_IS_LINKED(instantiating_collection) ||
(is_resync && ID_IS_LINKED(id_root) &&
instantiating_collection->id.lib->temp_index < id_root->lib->temp_index)) {
@@ -650,16 +715,17 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
(!is_resync || instantiating_collection->id.lib == id_root->lib)) {
instantiating_collection_override_candidate = instantiating_collection;
}
+ instantiating_collection = NULL;
}
+ }
- if (instantiating_collection == NULL &&
- instantiating_collection_override_candidate != NULL) {
- if (instantiating_collection_override_candidate->id.tag & LIB_TAG_MISSING) {
- instantiating_collection_override_candidate->id.tag |= data->missing_tag;
- }
- else {
- instantiating_collection_override_candidate->id.tag |= data->tag;
- }
+ if (instantiating_collection == NULL &&
+ instantiating_collection_override_candidate != NULL) {
+ if (instantiating_collection_override_candidate->id.tag & LIB_TAG_MISSING) {
+ instantiating_collection_override_candidate->id.tag |= data->missing_tag;
+ }
+ else {
+ instantiating_collection_override_candidate->id.tag |= data->tag;
}
}
}
@@ -672,6 +738,12 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *
ID *id_owner = data->id_root;
BLI_assert(ID_IS_OVERRIDE_LIBRARY(id_owner));
BLI_assert(data->is_override);
+
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(id_owner) &&
+ (id_owner->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY) != 0) {
+ return;
+ }
+
const uint tag = data->tag;
const uint missing_tag = data->missing_tag;
@@ -751,12 +823,14 @@ static bool lib_override_library_create_do(Main *bmain, Scene *scene, ID *id_roo
.missing_tag = LIB_TAG_MISSING,
.is_override = false,
.is_resync = false};
+ lib_override_group_tag_data_object_to_collection_init(&data);
lib_override_linked_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
lib_override_hierarchy_dependencies_recursive_tag(&data);
BKE_main_relations_free(bmain);
+ lib_override_group_tag_data_clear(&data);
return BKE_lib_override_library_create_from_tag(bmain, id_root->lib, false);
}
@@ -890,24 +964,6 @@ static void lib_override_library_create_post_process(Main *bmain,
BLI_gset_free(all_objects_in_scene, NULL);
}
-/**
- * Advanced 'smart' function to create fully functional overrides.
- *
- * \note Currently it only does special things if given \a id_root is an object or collection, more
- * specific behaviors may be added in the future for other ID types.
- *
- * \note It will override all IDs tagged with \a LIB_TAG_DOIT, and it does not clear that tag at
- * its beginning, so caller code can add extra data-blocks to be overridden as well.
- *
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- * \param id_root: The root ID to create an override from.
- * \param id_reference: Some reference ID used to do some post-processing after overrides have been
- * created, may be NULL. Typically, the Empty object instantiating the linked collection we
- * override, currently.
- * \param r_id_root_override: if not NULL, the override generated for the given \a id_root.
- * \return true if override was successfully created.
- */
bool BKE_lib_override_library_create(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -942,9 +998,6 @@ bool BKE_lib_override_library_create(Main *bmain,
return success;
}
-/**
- * Create a library override template.
- */
bool BKE_lib_override_library_template_create(struct ID *id)
{
if (ID_IS_LINKED(id)) {
@@ -958,16 +1011,6 @@ bool BKE_lib_override_library_template_create(struct ID *id)
return true;
}
-/**
- * Convert a given proxy object into a library override.
- *
- * \note This is a thin wrapper around \a BKE_lib_override_library_create, only extra work is to
- * actually convert the proxy itself into an override first.
- *
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- * \return true if override was successfully created.
- */
bool BKE_lib_override_library_proxy_convert(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1028,7 +1071,7 @@ static void lib_override_library_proxy_convert_do(Main *bmain,
if (success) {
CLOG_INFO(&LOG,
4,
- "Proxy object '%s' successfuly converted to library overrides",
+ "Proxy object '%s' successfully converted to library overrides",
ob_proxy->id.name);
/* Remove the instance empty from this scene, the items now have an overridden collection
* instead. */
@@ -1039,14 +1082,6 @@ static void lib_override_library_proxy_convert_do(Main *bmain,
}
}
-/**
- * Convert all proxy objects into library overrides.
- *
- * \note Only affects local proxies, linked ones are not affected.
- *
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- */
void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadReport *reports)
{
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
@@ -1086,23 +1121,53 @@ void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadRepor
}
}
-/**
- * Advanced 'smart' function to resync, re-create fully functional overrides up-to-date with linked
- * data, from an existing override hierarchy.
- *
- * \param id_root: The root liboverride ID to resync from.
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- * \return true if override was successfully resynced.
- */
-bool BKE_lib_override_library_resync(Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- ID *id_root,
- Collection *override_resync_residual_storage,
- const bool do_hierarchy_enforce,
- const bool do_post_process,
- BlendFileReadReport *reports)
+static void lib_override_library_remap(Main *bmain,
+ const ID *id_root_reference,
+ GHash *linkedref_to_old_override)
+{
+ ID *id;
+ struct IDRemapper *remapper = BKE_id_remapper_create();
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+
+ if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
+ ID *id_override_new = id->newid;
+ ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
+ if (id_override_old == NULL) {
+ continue;
+ }
+
+ BKE_id_remapper_add(remapper, id_override_old, id_override_new);
+ /* Remap no-main override IDs we just created too. */
+ GHashIterator linkedref_to_old_override_iter;
+ GHASH_ITER (linkedref_to_old_override_iter, linkedref_to_old_override) {
+ ID *id_override_old_iter = BLI_ghashIterator_getValue(&linkedref_to_old_override_iter);
+ if ((id_override_old_iter->tag & LIB_TAG_NO_MAIN) == 0) {
+ continue;
+ }
+
+ BKE_libblock_relink_ex(bmain,
+ id_override_old_iter,
+ id_override_old,
+ id_override_new,
+ ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
+
+ /* Remap all IDs to use the new override. */
+ BKE_libblock_remap_multiple(bmain, remapper, 0);
+ BKE_id_remapper_free(remapper);
+}
+
+static bool lib_override_library_resync(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ ID *id_root,
+ Collection *override_resync_residual_storage,
+ const bool do_hierarchy_enforce,
+ const bool do_post_process,
+ BlendFileReadReport *reports)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
@@ -1125,6 +1190,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
.missing_tag = LIB_TAG_MISSING,
.is_override = true,
.is_resync = true};
+ lib_override_group_tag_data_object_to_collection_init(&data);
lib_override_overrides_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
@@ -1215,6 +1281,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
lib_override_hierarchy_dependencies_recursive_tag(&data);
BKE_main_relations_free(bmain);
+ lib_override_group_tag_data_clear(&data);
/* Make new override from linked data. */
/* Note that this call also remaps all pointers of tagged IDs from old override IDs to new
@@ -1284,32 +1351,9 @@ bool BKE_lib_override_library_resync(Main *bmain,
}
FOREACH_MAIN_LISTBASE_END;
- /* We need to remap old to new override usages in a separate loop, after all new overrides have
+ /* We remap old to new override usages in a separate loop, after all new overrides have
* been added to Main. */
- FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
- ID *id_override_new = id->newid;
- ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
-
- if (id_override_old != NULL) {
- /* Remap all IDs to use the new override. */
- BKE_libblock_remap(bmain, id_override_old, id_override_new, 0);
- /* Remap no-main override IDs we just created too. */
- GHashIterator linkedref_to_old_override_iter;
- GHASH_ITER (linkedref_to_old_override_iter, linkedref_to_old_override) {
- ID *id_override_old_iter = BLI_ghashIterator_getValue(&linkedref_to_old_override_iter);
- if (id_override_old_iter->tag & LIB_TAG_NO_MAIN) {
- BKE_libblock_relink_ex(bmain,
- id_override_old_iter,
- id_override_old,
- id_override_new,
- ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
- }
- }
- }
- }
- }
- FOREACH_MAIN_ID_END;
+ lib_override_library_remap(bmain, id_root_reference, linkedref_to_old_override);
BKE_main_collection_sync(bmain);
@@ -1471,6 +1515,26 @@ bool BKE_lib_override_library_resync(Main *bmain,
return success;
}
+bool BKE_lib_override_library_resync(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ ID *id_root,
+ Collection *override_resync_residual_storage,
+ const bool do_hierarchy_enforce,
+ BlendFileReadReport *reports)
+{
+ const bool success = lib_override_library_resync(bmain,
+ scene,
+ view_layer,
+ id_root,
+ override_resync_residual_storage,
+ do_hierarchy_enforce,
+ true,
+ reports);
+
+ return success;
+}
+
/* Also tag ancestors overrides for resync.
*
* WARNING: Expects `bmain` to have valid relation data.
@@ -1489,11 +1553,13 @@ static void lib_override_resync_tagging_finalize_recurse(Main *bmain,
CLOG_ERROR(
&LOG,
"While processing indirect level %d, ID %s from lib %s of indirect level %d detected "
- "as needing resync.",
+ "as needing resync, skipping.",
library_indirect_level,
id->name,
id->lib->filepath,
id->lib->temp_index);
+ id->tag &= ~LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
+ return;
}
MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
@@ -1607,6 +1673,14 @@ static void lib_override_library_main_resync_on_library_indirect_level(
/* Detect all linked data that would need to be overridden if we had to create an override from
* those used by current existing overrides. */
+ LibOverrideGroupTagData data = {.bmain = bmain,
+ .scene = scene,
+ .id_root = NULL,
+ .tag = LIB_TAG_DOIT,
+ .missing_tag = LIB_TAG_MISSING,
+ .is_override = false,
+ .is_resync = true};
+ lib_override_group_tag_data_object_to_collection_init(&data);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
@@ -1617,19 +1691,19 @@ static void lib_override_library_main_resync_on_library_indirect_level(
continue;
}
- LibOverrideGroupTagData data = {.bmain = bmain,
- .scene = scene,
- .id_root = id->override_library->reference,
- .tag = LIB_TAG_DOIT,
- .missing_tag = LIB_TAG_MISSING,
- .is_override = false,
- .is_resync = true};
+ if (id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY) {
+ /* This ID is not part of an override hierarchy. */
+ continue;
+ }
+
+ data.id_root = id->override_library->reference;
lib_override_linked_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
lib_override_hierarchy_dependencies_recursive_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
}
FOREACH_MAIN_ID_END;
+ lib_override_group_tag_data_clear(&data);
/* Now check existing overrides, those needing resync will be the one either already tagged as
* such, or the one using linked data that is now tagged as needing override. */
@@ -1639,6 +1713,12 @@ static void lib_override_library_main_resync_on_library_indirect_level(
continue;
}
+ if (id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY) {
+ /* This ID is not part of an override hierarchy. */
+ BLI_assert((id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0);
+ continue;
+ }
+
if (id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) {
CLOG_INFO(&LOG, 4, "ID %s (%p) was already tagged as needing resync", id->name, id->lib);
lib_override_resync_tagging_finalize_recurse(bmain, id, library_indirect_level);
@@ -1691,6 +1771,10 @@ static void lib_override_library_main_resync_on_library_indirect_level(
continue;
}
+ if (ID_IS_LINKED(id)) {
+ id->lib->tag |= LIBRARY_TAG_RESYNC_REQUIRED;
+ }
+
/* We cannot resync a scene that is currently active. */
if (id == &scene->id) {
id->tag &= ~LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
@@ -1717,7 +1801,7 @@ static void lib_override_library_main_resync_on_library_indirect_level(
do_continue = true;
CLOG_INFO(&LOG, 2, "Resyncing %s (%p)...", id->name, library);
- const bool success = BKE_lib_override_library_resync(
+ const bool success = lib_override_library_resync(
bmain, scene, view_layer, id, override_resync_residual_storage, false, false, reports);
CLOG_INFO(&LOG, 2, "\tSuccess: %d", success);
if (success) {
@@ -1801,23 +1885,6 @@ static int lib_override_libraries_index_define(Main *bmain)
return library_indirect_level_max;
}
-/**
- * Detect and handle required resync of overrides data, when relations between reference linked IDs
- * have changed.
- *
- * This is a fairly complex and costly operation, typically it should be called after
- * #BKE_lib_override_library_main_update, which would already detect and tag a lot of cases.
- *
- * This function will first detect the remaining cases requiring a resync (namely, either when an
- * existing linked ID that did not require to be overridden before now would be, or when new IDs
- * are added to the hierarchy).
- *
- * Then it will handle the resync of necessary IDs (through calls to
- * #BKE_lib_override_library_resync).
- *
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- */
void BKE_lib_override_library_main_resync(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1864,16 +1931,18 @@ void BKE_lib_override_library_main_resync(Main *bmain,
if (BKE_collection_is_empty(override_resync_residual_storage)) {
BKE_collection_delete(bmain, override_resync_residual_storage, true);
}
+
+ LISTBASE_FOREACH (Library *, library, &bmain->libraries) {
+ if (library->tag & LIBRARY_TAG_RESYNC_REQUIRED) {
+ CLOG_INFO(&LOG,
+ 2,
+ "library '%s' contains some linked overrides that required recursive resync, "
+ "consider updating it",
+ library->filepath);
+ }
+ }
}
-/**
- * Advanced 'smart' function to delete library overrides (including their existing override
- * hierarchy) and remap their usages to their linked reference IDs.
- *
- * \note All IDs tagged with `LIB_TAG_DOIT` will be deleted.
- *
- * \param id_root: The root liboverride ID to delete.
- */
void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
@@ -1887,9 +1956,11 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
.missing_tag = LIB_TAG_MISSING,
.is_override = true,
.is_resync = false};
+ lib_override_group_tag_data_object_to_collection_init(&data);
lib_override_overrides_group_tag(&data);
BKE_main_relations_free(bmain);
+ lib_override_group_tag_data_clear(&data);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
@@ -1911,13 +1982,18 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
}
-/** Make given ID fully local.
- *
- * \note Only differs from lower-level `BKE_lib_override_library_free in infamous embedded ID
- * cases.
- */
void BKE_lib_override_library_make_local(ID *id)
{
+ if (!ID_IS_OVERRIDE_LIBRARY(id)) {
+ return;
+ }
+ if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(id)) {
+ /* We should never directly 'make local' virtual overrides (aka shape keys). */
+ BLI_assert_unreachable();
+ id->flag &= ~LIB_EMBEDDED_DATA_LIB_OVERRIDE;
+ return;
+ }
+
BKE_lib_override_library_free(&id->override_library, true);
Key *shape_key = BKE_key_from_id(id);
@@ -1962,9 +2038,6 @@ BLI_INLINE GHash *override_library_rna_path_mapping_ensure(IDOverrideLibrary *ov
return override_runtime->rna_path_to_override_properties;
}
-/**
- * Find override property from given RNA path, if it exists.
- */
IDOverrideLibraryProperty *BKE_lib_override_library_property_find(IDOverrideLibrary *override,
const char *rna_path)
{
@@ -1972,9 +2045,6 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_find(IDOverrideLibr
return BLI_ghash_lookup(override_runtime, rna_path);
}
-/**
- * Find override property from given RNA path, or create it if it does not exist.
- */
IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibrary *override,
const char *rna_path,
bool *r_created)
@@ -2000,13 +2070,6 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibra
return op;
}
-/**
- * Get the RNA-property matching the \a library_prop override property. Used for UI to query
- * additional data about the overridden property (e.g. UI name).
- *
- * \param idpoin: Pointer to the override ID.
- * \param library_prop: The library override property to find the matching RNA property for.
- */
bool BKE_lib_override_rna_property_find(PointerRNA *idpoin,
const IDOverrideLibraryProperty *library_prop,
PointerRNA *r_override_poin,
@@ -2043,9 +2106,6 @@ void lib_override_library_property_clear(IDOverrideLibraryProperty *op)
BLI_freelistN(&op->operations);
}
-/**
- * Remove and free given \a override_property from given ID \a override.
- */
void BKE_lib_override_library_property_delete(IDOverrideLibrary *override,
IDOverrideLibraryProperty *override_property)
{
@@ -2059,9 +2119,6 @@ void BKE_lib_override_library_property_delete(IDOverrideLibrary *override,
BLI_freelinkN(&override->properties, override_property);
}
-/**
- * Find override property operation from given sub-item(s), if it exists.
- */
IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_find(
IDOverrideLibraryProperty *override_property,
const char *subitem_refname,
@@ -2148,9 +2205,6 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_
return NULL;
}
-/**
- * Find override property operation from given sub-item(s), or create it if it does not exist.
- */
IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_get(
IDOverrideLibraryProperty *override_property,
const short operation,
@@ -2217,9 +2271,6 @@ void lib_override_library_property_operation_clear(IDOverrideLibraryPropertyOper
}
}
-/**
- * Remove and free given \a override_property_operation from given ID \a override_property.
- */
void BKE_lib_override_library_property_operation_delete(
IDOverrideLibraryProperty *override_property,
IDOverrideLibraryPropertyOperation *override_property_operation)
@@ -2228,9 +2279,6 @@ void BKE_lib_override_library_property_operation_delete(
BLI_freelinkN(&override_property->operations, override_property_operation);
}
-/**
- * Validate that required data for a given operation are available.
- */
bool BKE_lib_override_library_property_operation_operands_validate(
struct IDOverrideLibraryPropertyOperation *override_property_operation,
struct PointerRNA *ptr_dst,
@@ -2268,7 +2316,6 @@ bool BKE_lib_override_library_property_operation_operands_validate(
return true;
}
-/** Check against potential \a bmain. */
void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *reports)
{
if (id->override_library == NULL) {
@@ -2302,7 +2349,6 @@ void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *
}
}
-/** Check against potential \a bmain. */
void BKE_lib_override_library_main_validate(Main *bmain, ReportList *reports)
{
ID *id;
@@ -2315,16 +2361,6 @@ void BKE_lib_override_library_main_validate(Main *bmain, ReportList *reports)
FOREACH_MAIN_ID_END;
}
-/**
- * Check that status of local data-block is still valid against current reference one.
- *
- * It means that all overridable, but not overridden, properties' local values must be equal to
- * reference ones. Clears #LIB_TAG_OVERRIDE_OK if they do not.
- *
- * This is typically used to detect whether some property has been changed in local and a new
- * #IDOverrideProperty (of #IDOverridePropertyOperation) has to be added.
- *
- * \return true if status is OK, false otherwise. */
bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local));
@@ -2374,16 +2410,6 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
return true;
}
-/**
- * Check that status of reference data-block is still valid against current local one.
- *
- * It means that all non-overridden properties' local values must be equal to reference ones.
- * Clears LIB_TAG_OVERRIDE_OK if they do not.
- *
- * This is typically used to detect whether some reference has changed and local
- * needs to be updated against it.
- *
- * \return true if status is OK, false otherwise. */
bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local));
@@ -2440,20 +2466,6 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
return true;
}
-/**
- * Compare local and reference data-blocks and create new override operations as needed,
- * or reset to reference values if overriding is not allowed.
- *
- * \note Defining override operations is only mandatory before saving a `.blend` file on disk
- * (not for undo!).
- * Knowing that info at runtime is only useful for UI/UX feedback.
- *
- * \note This is by far the biggest operation (the more time-consuming) of the three so far,
- * since it has to go over all properties in depth (all overridable ones at least).
- * Generating differential values and applying overrides are much cheaper.
- *
- * \return true if any library operation was created.
- */
bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
{
BLI_assert(local->override_library != NULL);
@@ -2530,7 +2542,6 @@ static void lib_override_library_operations_create_cb(TaskPool *__restrict pool,
}
}
-/** Check all overrides from given \a bmain and create/update overriding operations as needed. */
bool BKE_lib_override_library_main_operations_create(Main *bmain, const bool force_auto)
{
ID *id;
@@ -2659,7 +2670,6 @@ static bool lib_override_library_id_reset_do(Main *bmain, ID *id_root)
return was_op_deleted;
}
-/** Reset all overrides in given \a id_root, while preserving ID relations. */
void BKE_lib_override_library_id_reset(Main *bmain, ID *id_root)
{
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
@@ -2718,7 +2728,6 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, ID *i
}
}
-/** Reset all overrides in given \a id_root and its dependencies, while preserving ID relations. */
void BKE_lib_override_library_id_hierarchy_reset(Main *bmain, ID *id_root)
{
BKE_main_relations_create(bmain, 0);
@@ -2739,7 +2748,6 @@ void BKE_lib_override_library_id_hierarchy_reset(Main *bmain, ID *id_root)
FOREACH_MAIN_ID_END;
}
-/** Set or clear given tag in all operations in that override property data. */
void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property,
const short tag,
const bool do_set)
@@ -2763,7 +2771,6 @@ void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *o
}
}
-/** Set or clear given tag in all properties and operations in that override data. */
void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
const short tag,
const bool do_set)
@@ -2775,7 +2782,6 @@ void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
}
}
-/** Set or clear given tag in all properties and operations in that Main's ID override data. */
void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, const bool do_set)
{
ID *id;
@@ -2788,7 +2794,6 @@ void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, cons
FOREACH_MAIN_ID_END;
}
-/** Remove all tagged-as-unused properties and operations from that ID override data. */
void BKE_lib_override_library_id_unused_cleanup(struct ID *local)
{
if (ID_IS_OVERRIDE_LIBRARY_REAL(local)) {
@@ -2808,7 +2813,6 @@ void BKE_lib_override_library_id_unused_cleanup(struct ID *local)
}
}
-/** Remove all tagged-as-unused properties and operations from that Main's ID override data. */
void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain)
{
ID *id;
@@ -2829,7 +2833,6 @@ static void lib_override_id_swap(Main *bmain, ID *id_local, ID *id_temp)
id_local->tag |= (id_temp->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC);
}
-/** Update given override from its reference (re-applying overridden properties). */
void BKE_lib_override_library_update(Main *bmain, ID *local)
{
if (!ID_IS_OVERRIDE_LIBRARY_REAL(local)) {
@@ -2864,7 +2867,10 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
* Not impossible to do, but would rather see first if extra useless usual user handling
* is actually a (performances) issue here. */
- ID *tmp_id = BKE_id_copy(bmain, local->override_library->reference);
+ ID *tmp_id = BKE_id_copy_ex(bmain,
+ local->override_library->reference,
+ NULL,
+ LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE_LOCAL_DATA_FLAG);
if (tmp_id == NULL) {
return;
@@ -2951,7 +2957,6 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
DEG_relations_tag_update(bmain);
}
-/** Update all overrides from given \a bmain. */
void BKE_lib_override_library_main_update(Main *bmain)
{
ID *id;
@@ -2972,7 +2977,6 @@ void BKE_lib_override_library_main_update(Main *bmain)
G_MAIN = orig_gmain;
}
-/** In case an ID is used by another liboverride ID, user may not be allowed to delete it. */
bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID *id)
{
if (!(ID_IS_LINKED(id) || ID_IS_OVERRIDE_LIBRARY(id))) {
@@ -3013,17 +3017,11 @@ bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID
* exact same data as "desired" ones (kind of "baked" data-blocks).
*/
-/** Initialize an override storage. */
OverrideLibraryStorage *BKE_lib_override_library_operations_store_init(void)
{
return BKE_main_new();
}
-/**
- * Generate suitable 'write' data (this only affects differential override operations).
- *
- * Note that \a local ID is no more modified by this call,
- * all extra data are stored in its temp \a storage_id copy. */
ID *BKE_lib_override_library_operations_store_start(Main *bmain,
OverrideLibraryStorage *override_storage,
ID *local)
@@ -3088,10 +3086,6 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
return storage_id;
}
-/**
- * Restore given ID modified by #BKE_lib_override_library_operations_store_start, to its
- * original state.
- */
void BKE_lib_override_library_operations_store_end(
OverrideLibraryStorage *UNUSED(override_storage), ID *local)
{
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index 2ac92828cec..1f20a84098c 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -76,48 +76,50 @@ typedef struct LibraryForeachIDData {
BLI_LINKSTACK_DECLARE(ids_todo, ID *);
} LibraryForeachIDData;
-bool BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag)
+bool BKE_lib_query_foreachid_iter_stop(LibraryForeachIDData *data)
{
- if (!(data->status & IDWALK_STOP)) {
- const int flag = data->flag;
- ID *old_id = *id_pp;
-
- /* Update the callback flags with the ones defined (or forbidden) in `data` by the generic
- * caller code. */
- cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear);
-
- /* Update the callback flags with some extra information regarding overrides: all 'loopback',
- * 'internal', 'embedded' etc. ID pointers are never overridable. */
- if (cb_flag &
- (IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
- cb_flag |= IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE;
- }
+ return (data->status & IDWALK_STOP) != 0;
+}
- const int callback_return = data->callback(
- &(struct LibraryIDLinkCallbackData){.user_data = data->user_data,
- .bmain = data->bmain,
- .id_owner = data->owner_id,
- .id_self = data->self_id,
- .id_pointer = id_pp,
- .cb_flag = cb_flag});
- if (flag & IDWALK_READONLY) {
- BLI_assert(*(id_pp) == old_id);
- }
- if (old_id && (flag & IDWALK_RECURSE)) {
- if (BLI_gset_add((data)->ids_handled, old_id)) {
- if (!(callback_return & IDWALK_RET_STOP_RECURSION)) {
- BLI_LINKSTACK_PUSH(data->ids_todo, old_id);
- }
+void BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag)
+{
+ if (BKE_lib_query_foreachid_iter_stop(data)) {
+ return;
+ }
+
+ const int flag = data->flag;
+ ID *old_id = *id_pp;
+
+ /* Update the callback flags with the ones defined (or forbidden) in `data` by the generic
+ * caller code. */
+ cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear);
+
+ /* Update the callback flags with some extra information regarding overrides: all 'loopback',
+ * 'internal', 'embedded' etc. ID pointers are never overridable. */
+ if (cb_flag & (IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
+ cb_flag |= IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE;
+ }
+
+ const int callback_return = data->callback(
+ &(struct LibraryIDLinkCallbackData){.user_data = data->user_data,
+ .bmain = data->bmain,
+ .id_owner = data->owner_id,
+ .id_self = data->self_id,
+ .id_pointer = id_pp,
+ .cb_flag = cb_flag});
+ if (flag & IDWALK_READONLY) {
+ BLI_assert(*(id_pp) == old_id);
+ }
+ if (old_id && (flag & IDWALK_RECURSE)) {
+ if (BLI_gset_add((data)->ids_handled, old_id)) {
+ if (!(callback_return & IDWALK_RET_STOP_RECURSION)) {
+ BLI_LINKSTACK_PUSH(data->ids_todo, old_id);
}
}
- if (callback_return & IDWALK_RET_STOP_ITER) {
- data->status |= IDWALK_STOP;
- return false;
- }
- return true;
}
-
- return false;
+ if (callback_return & IDWALK_RET_STOP_ITER) {
+ data->status |= IDWALK_STOP;
+ }
}
int BKE_lib_query_foreachid_process_flags_get(LibraryForeachIDData *data)
@@ -139,7 +141,7 @@ int BKE_lib_query_foreachid_process_callback_flag_override(LibraryForeachIDData
return cb_flag_backup;
}
-static void library_foreach_ID_link(Main *bmain,
+static bool library_foreach_ID_link(Main *bmain,
ID *id_owner,
ID *id,
LibraryIDLinkCallback callback,
@@ -158,19 +160,20 @@ void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void
BKE_LIB_FOREACHID_PROCESS_ID(data, id_prop->data.pointer, cb_flag);
}
-bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp)
+void BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp)
{
/* Needed e.g. for callbacks handling relationships. This call shall be absolutely read-only. */
ID *id = *id_pp;
const int flag = data->flag;
- if (!BKE_lib_query_foreachid_process(data, id_pp, IDWALK_CB_EMBEDDED)) {
- return false;
+ BKE_lib_query_foreachid_process(data, id_pp, IDWALK_CB_EMBEDDED);
+ if (BKE_lib_query_foreachid_iter_stop(data)) {
+ return;
}
BLI_assert(id == *id_pp);
if (id == NULL) {
- return true;
+ return;
}
if (flag & IDWALK_IGNORE_EMBEDDED_ID) {
@@ -186,14 +189,24 @@ bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp)
}
}
else {
- library_foreach_ID_link(
- data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data);
+ if (!library_foreach_ID_link(
+ data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data)) {
+ data->status |= IDWALK_STOP;
+ return;
+ }
}
+}
- return true;
+static void library_foreach_ID_data_cleanup(LibraryForeachIDData *data)
+{
+ if (data->ids_handled != NULL) {
+ BLI_gset_free(data->ids_handled, NULL);
+ BLI_LINKSTACK_FREE(data->ids_todo);
+ }
}
-static void library_foreach_ID_link(Main *bmain,
+/** \return false in case iteration over ID pointers must be stopped, true otherwise. */
+static bool library_foreach_ID_link(Main *bmain,
ID *id_owner,
ID *id,
LibraryIDLinkCallback callback,
@@ -210,6 +223,10 @@ static void library_foreach_ID_link(Main *bmain,
flag |= IDWALK_READONLY;
flag &= ~IDWALK_DO_INTERNAL_RUNTIME_POINTERS;
+ /* NOTE: This function itself should never be called recursively when IDWALK_RECURSE is set,
+ * see also comments in #BKE_library_foreach_ID_embedded.
+ * This is why we can always create this data here, and do not need to try and re-use it from
+ * `inherit_data`. */
data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
BLI_LINKSTACK_INIT(data.ids_todo);
@@ -224,10 +241,26 @@ static void library_foreach_ID_link(Main *bmain,
data.user_data = user_data;
#define CALLBACK_INVOKE_ID(check_id, cb_flag) \
- BKE_LIB_FOREACHID_PROCESS_ID(&data, check_id, cb_flag)
+ { \
+ CHECK_TYPE_ANY((check_id), ID *, void *); \
+ BKE_lib_query_foreachid_process(&data, (ID **)&(check_id), (cb_flag)); \
+ if (BKE_lib_query_foreachid_iter_stop(&data)) { \
+ library_foreach_ID_data_cleanup(&data); \
+ return false; \
+ } \
+ } \
+ ((void)0)
#define CALLBACK_INVOKE(check_id_super, cb_flag) \
- BKE_LIB_FOREACHID_PROCESS(&data, check_id_super, cb_flag)
+ { \
+ CHECK_TYPE(&((check_id_super)->id), ID *); \
+ BKE_lib_query_foreachid_process(&data, (ID **)&(check_id_super), (cb_flag)); \
+ if (BKE_lib_query_foreachid_iter_stop(&data)) { \
+ library_foreach_ID_data_cleanup(&data); \
+ return false; \
+ } \
+ } \
+ ((void)0)
for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) {
data.self_id = id;
@@ -269,6 +302,10 @@ static void library_foreach_ID_link(Main *bmain,
to_id_entry = to_id_entry->next) {
BKE_lib_query_foreachid_process(
&data, to_id_entry->id_pointer.to, to_id_entry->usage_flag);
+ if (BKE_lib_query_foreachid_iter_stop(&data)) {
+ library_foreach_ID_data_cleanup(&data);
+ return false;
+ }
}
continue;
}
@@ -292,43 +329,44 @@ static void library_foreach_ID_link(Main *bmain,
IDP_TYPE_FILTER_ID,
BKE_lib_query_idpropertiesForeachIDLink_callback,
&data);
+ if (BKE_lib_query_foreachid_iter_stop(&data)) {
+ library_foreach_ID_data_cleanup(&data);
+ return false;
+ }
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
BKE_animdata_foreach_id(adt, &data);
+ if (BKE_lib_query_foreachid_iter_stop(&data)) {
+ library_foreach_ID_data_cleanup(&data);
+ return false;
+ }
}
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
if (id_type->foreach_id != NULL) {
id_type->foreach_id(id, &data);
- if (data.status & IDWALK_STOP) {
- break;
+ if (BKE_lib_query_foreachid_iter_stop(&data)) {
+ library_foreach_ID_data_cleanup(&data);
+ return false;
}
}
}
- if (data.ids_handled) {
- BLI_gset_free(data.ids_handled, NULL);
- BLI_LINKSTACK_FREE(data.ids_todo);
- }
+ library_foreach_ID_data_cleanup(&data);
+ return true;
#undef CALLBACK_INVOKE_ID
#undef CALLBACK_INVOKE
}
-/**
- * Loop over all of the ID's this data-block links to.
- */
void BKE_library_foreach_ID_link(
Main *bmain, ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
{
library_foreach_ID_link(bmain, NULL, id, callback, user_data, flag, NULL);
}
-/**
- * re-usable function, use when replacing ID's
- */
void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
{
if (cb_flag & IDWALK_CB_USER) {
@@ -340,12 +378,6 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
}
}
-/**
- * Say whether given \a id_owner may use (in any way) a data-block of \a id_type_used.
- *
- * This is a 'simplified' abstract version of #BKE_library_foreach_ID_link() above,
- * quite useful to reduce useless iterations in some cases.
- */
bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
{
/* any type of ID can be used in custom props. */
@@ -407,7 +439,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
case ID_LA:
return (ELEM(id_type_used, ID_TE));
case ID_CA:
- return ELEM(id_type_used, ID_OB);
+ return ELEM(id_type_used, ID_OB, ID_IM);
case ID_KE:
/* Warning! key->from, could be more types in future? */
return ELEM(id_type_used, ID_ME, ID_CU, ID_LT);
@@ -517,16 +549,6 @@ static int foreach_libblock_id_users_callback(LibraryIDLinkCallbackData *cb_data
return IDWALK_RET_NOP;
}
-/**
- * Return the number of times given \a id_user uses/references \a id_used.
- *
- * \note This only checks for pointer references of an ID, shallow usages
- * (like e.g. by RNA paths, as done for FCurves) are not detected at all.
- *
- * \param id_user: the ID which is supposed to use (reference) \a id_used.
- * \param id_used: the ID which is supposed to be used (referenced) by \a id_user.
- * \return the number of direct usages/references of \a id_used by \a id_user.
- */
int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
{
IDUsersIter iter;
@@ -575,26 +597,16 @@ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
return is_defined;
}
-/**
- * Check whether given ID is used locally (i.e. by another non-linked ID).
- */
bool BKE_library_ID_is_locally_used(Main *bmain, void *idv)
{
return library_ID_is_used(bmain, idv, false);
}
-/**
- * Check whether given ID is used indirectly (i.e. by another linked ID).
- */
bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
{
return library_ID_is_used(bmain, idv, true);
}
-/**
- * Combine #BKE_library_ID_is_locally_used() and #BKE_library_ID_is_indirectly_used()
- * in a single call.
- */
void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked)
{
IDUsersIter iter;
@@ -709,21 +721,6 @@ static void lib_query_unused_ids_tag_recurse(Main *bmain,
}
}
-/**
- * Tag all unused IDs (a.k.a 'orphaned').
- *
- * By default only tag IDs with `0` user count.
- * If `do_tag_recursive` is set, it will check dependencies to detect all IDs that are not actually
- * used in current file, including 'archipelagos` (i.e. set of IDs referencing each other in
- * loops, but without any 'external' valid usages.
- *
- * Valid usages here are defined as ref-counting usages, which are not towards embedded or
- * loop-back data.
- *
- * \param r_num_tagged: If non-NULL, must be a zero-initialized array of #INDEX_ID_MAX integers.
- * Number of tagged-as-unused IDs is then set for each type, and as total in
- * #INDEX_ID_NULL item.
- */
void BKE_lib_query_unused_ids_tag(Main *bmain,
const int tag,
const bool do_local_ids,
@@ -788,15 +785,6 @@ static int foreach_libblock_used_linked_data_tag_clear_cb(LibraryIDLinkCallbackD
return IDWALK_RET_NOP;
}
-/**
- * Detect orphaned linked data blocks (i.e. linked data not used (directly or indirectly)
- * in any way by any local data), including complex cases like 'linked archipelagoes', i.e.
- * linked data-blocks that use each other in loops,
- * which prevents their deletion by 'basic' usage checks.
- *
- * \param do_init_tag: if \a true, all linked data are checked, if \a false,
- * only linked data-blocks already tagged with #LIB_TAG_DOIT are checked.
- */
void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
{
ID *id;
@@ -826,14 +814,6 @@ void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
}
}
-/**
- * Untag linked data blocks used by other untagged linked data-blocks.
- * Used to detect data-blocks that we can forcefully make local
- * (instead of copying them to later get rid of original):
- * All data-blocks we want to make local are tagged by caller,
- * after this function has ran caller knows data-blocks still tagged can directly be made local,
- * since they are only used by other data-blocks that will also be made fully local.
- */
void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
{
ListBase *lb_array[INDEX_ID_MAX];
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 48396c5e6d9..c3ccedb9608 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -91,6 +91,97 @@ enum {
ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, /* There was some skipped 'user_one' usages of old_id. */
};
+static void foreach_libblock_remap_callback_skip(const ID *id_owner,
+ ID **id_ptr,
+ IDRemap *id_remap_data,
+ const int cb_flag,
+ const bool is_indirect,
+ const bool is_reference,
+ const bool is_never_null,
+ const bool is_obj,
+ const bool is_obj_editmode)
+{
+ if (is_indirect) {
+ id_remap_data->skipped_indirect++;
+ if (is_obj) {
+ Object *ob = (Object *)id_owner;
+ if (ob->data == *id_ptr && ob->proxy != NULL) {
+ /* And another 'Proudly brought to you by Proxy Hell' hack!
+ * This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */
+ id_remap_data->skipped_direct++;
+ }
+ }
+ }
+ else if (is_never_null || is_obj_editmode || is_reference) {
+ id_remap_data->skipped_direct++;
+ }
+ else {
+ BLI_assert(0);
+ }
+ if (cb_flag & IDWALK_CB_USER) {
+ id_remap_data->skipped_refcounted++;
+ }
+ else if (cb_flag & IDWALK_CB_USER_ONE) {
+ /* No need to count number of times this happens, just a flag is enough. */
+ id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED;
+ }
+}
+
+static void foreach_libblock_remap_callback_apply(ID *id_owner,
+ ID *id_self,
+ ID *old_id,
+ ID *new_id,
+ ID **id_ptr,
+ IDRemap *id_remap_data,
+ const int cb_flag,
+ const bool is_indirect,
+ const bool is_never_null,
+ const bool force_user_refcount,
+ const bool is_obj_proxy)
+{
+ if (!is_never_null) {
+ *id_ptr = new_id;
+ DEG_id_tag_update_ex(id_remap_data->bmain,
+ id_self,
+ ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ if (id_self != id_owner) {
+ DEG_id_tag_update_ex(id_remap_data->bmain,
+ id_owner,
+ ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+ }
+ if (cb_flag & IDWALK_CB_USER) {
+ /* NOTE: by default we don't user-count IDs which are not in the main database.
+ * This is because in certain conditions we can have data-blocks in
+ * the main which are referencing data-blocks outside of it.
+ * For example, BKE_mesh_new_from_object() called on an evaluated
+ * object will cause such situation.
+ */
+ if (force_user_refcount || (old_id->tag & LIB_TAG_NO_MAIN) == 0) {
+ id_us_min(old_id);
+ }
+ if (new_id != NULL && (force_user_refcount || (new_id->tag & LIB_TAG_NO_MAIN) == 0)) {
+ /* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */
+ new_id->us++;
+ }
+ }
+ else if (cb_flag & IDWALK_CB_USER_ONE) {
+ id_us_ensure_real(new_id);
+ /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET)
+ * are assumed to be set as needed, that extra user is processed in final handling. */
+ }
+ if (!is_indirect || is_obj_proxy) {
+ id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
+ }
+ /* We need to remap proxy_from pointer of remapped proxy... sigh. */
+ if (is_obj_proxy && new_id != NULL) {
+ Object *ob = (Object *)id_owner;
+ if (ob->proxy == (Object *)new_id) {
+ ob->proxy->proxy_from = ob;
+ }
+ }
+}
+
static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
{
const int cb_flag = cb_data->cb_flag;
@@ -116,124 +207,82 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
old_id = *id_p;
}
- if (*id_p && (*id_p == old_id)) {
- /* Better remap to NULL than not remapping at all,
- * then we can handle it as a regular remap-to-NULL case. */
- if ((cb_flag & IDWALK_CB_NEVER_SELF) && (new_id == id_self)) {
- new_id = NULL;
- }
+ /* Early exit when id pointer isn't set to an expected value. */
+ if (*id_p == NULL || *id_p != old_id) {
+ return IDWALK_RET_NOP;
+ }
+
+ /* Better remap to NULL than not remapping at all,
+ * then we can handle it as a regular remap-to-NULL case. */
+ if ((cb_flag & IDWALK_CB_NEVER_SELF) && (new_id == id_self)) {
+ new_id = NULL;
+ }
- const bool is_reference = (cb_flag & IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE) != 0;
- const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0;
- const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
- /* NOTE: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
- * on the other hand since they get reset to lib data on file open/reload it is indirect too.
- * Edit Mode is also a 'skip direct' case. */
- const bool is_obj = (GS(id_owner->name) == ID_OB);
- const bool is_obj_proxy = (is_obj &&
- (((Object *)id_owner)->proxy || ((Object *)id_owner)->proxy_group));
- const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner));
- const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) &&
- (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
- const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_OVERRIDE_LIBRARY) != 0;
- const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
- const bool force_user_refcount = (id_remap_data->flag & ID_REMAP_FORCE_USER_REFCOUNT) != 0;
+ const bool is_reference = (cb_flag & IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE) != 0;
+ const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0;
+ const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
+ /* NOTE: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
+ * on the other hand since they get reset to lib data on file open/reload it is indirect too.
+ * Edit Mode is also a 'skip direct' case. */
+ const bool is_obj = (GS(id_owner->name) == ID_OB);
+ const bool is_obj_proxy = (is_obj &&
+ (((Object *)id_owner)->proxy || ((Object *)id_owner)->proxy_group));
+ const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner) &&
+ (id_remap_data->flag & ID_REMAP_FORCE_OBDATA_IN_EDITMODE) == 0);
+ const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) &&
+ (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
+ const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_OVERRIDE_LIBRARY) != 0;
+ const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
+ const bool force_user_refcount = (id_remap_data->flag & ID_REMAP_FORCE_USER_REFCOUNT) != 0;
#ifdef DEBUG_PRINT
- printf(
- "In %s (lib %p): Remapping %s (%p) to %s (%p) "
- "(is_indirect: %d, skip_indirect: %d, is_reference: %d, skip_reference: %d)\n",
- id->name,
- id->lib,
- old_id->name,
- old_id,
- new_id ? new_id->name : "<NONE>",
- new_id,
- is_indirect,
- skip_indirect,
- is_reference,
- skip_reference);
+ printf(
+ "In %s (lib %p): Remapping %s (%p) to %s (%p) "
+ "(is_indirect: %d, skip_indirect: %d, is_reference: %d, skip_reference: %d)\n",
+ id->name,
+ id->lib,
+ old_id->name,
+ old_id,
+ new_id ? new_id->name : "<NONE>",
+ new_id,
+ is_indirect,
+ skip_indirect,
+ is_reference,
+ skip_reference);
#endif
- if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) &&
- (cb_flag & IDWALK_CB_NEVER_NULL)) {
- id_owner->tag |= LIB_TAG_DOIT;
- }
+ if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) {
+ id_owner->tag |= LIB_TAG_DOIT;
+ }
- /* Special hack in case it's Object->data and we are in edit mode, and new_id is not NULL
- * (otherwise, we follow common NEVER_NULL flags).
- * (skipped_indirect too). */
- if ((is_never_null && skip_never_null) ||
- (is_obj_editmode && (((Object *)id_owner)->data == *id_p) && new_id != NULL) ||
- (skip_indirect && is_indirect) || (is_reference && skip_reference)) {
- if (is_indirect) {
- id_remap_data->skipped_indirect++;
- if (is_obj) {
- Object *ob = (Object *)id_owner;
- if (ob->data == *id_p && ob->proxy != NULL) {
- /* And another 'Proudly brought to you by Proxy Hell' hack!
- * This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */
- id_remap_data->skipped_direct++;
- }
- }
- }
- else if (is_never_null || is_obj_editmode || is_reference) {
- id_remap_data->skipped_direct++;
- }
- else {
- BLI_assert(0);
- }
- if (cb_flag & IDWALK_CB_USER) {
- id_remap_data->skipped_refcounted++;
- }
- else if (cb_flag & IDWALK_CB_USER_ONE) {
- /* No need to count number of times this happens, just a flag is enough. */
- id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED;
- }
- }
- else {
- if (!is_never_null) {
- *id_p = new_id;
- DEG_id_tag_update_ex(id_remap_data->bmain,
- id_self,
- ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- if (id_self != id_owner) {
- DEG_id_tag_update_ex(id_remap_data->bmain,
- id_owner,
- ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- }
- }
- if (cb_flag & IDWALK_CB_USER) {
- /* NOTE: by default we don't user-count IDs which are not in the main database.
- * This is because in certain conditions we can have data-blocks in
- * the main which are referencing data-blocks outside of it.
- * For example, BKE_mesh_new_from_object() called on an evaluated
- * object will cause such situation.
- */
- if (force_user_refcount || (old_id->tag & LIB_TAG_NO_MAIN) == 0) {
- id_us_min(old_id);
- }
- if (new_id != NULL && (force_user_refcount || (new_id->tag & LIB_TAG_NO_MAIN) == 0)) {
- /* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */
- new_id->us++;
- }
- }
- else if (cb_flag & IDWALK_CB_USER_ONE) {
- id_us_ensure_real(new_id);
- /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET)
- * are assumed to be set as needed, that extra user is processed in final handling. */
- }
- if (!is_indirect || is_obj_proxy) {
- id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
- }
- /* We need to remap proxy_from pointer of remapped proxy... sigh. */
- if (is_obj_proxy && new_id != NULL) {
- Object *ob = (Object *)id_owner;
- if (ob->proxy == (Object *)new_id) {
- ob->proxy->proxy_from = ob;
- }
- }
- }
+ /* Special hack in case it's Object->data and we are in edit mode, and new_id is not NULL
+ * (otherwise, we follow common NEVER_NULL flags).
+ * (skipped_indirect too). */
+ if ((is_never_null && skip_never_null) ||
+ (is_obj_editmode && (((Object *)id_owner)->data == *id_p) && new_id != NULL) ||
+ (skip_indirect && is_indirect) || (is_reference && skip_reference)) {
+ foreach_libblock_remap_callback_skip(id_owner,
+ id_p,
+ id_remap_data,
+ cb_flag,
+ is_indirect,
+ is_reference,
+ is_never_null,
+ is_obj,
+ is_obj_editmode);
+ }
+ else {
+ foreach_libblock_remap_callback_apply(id_owner,
+ id_self,
+ old_id,
+ new_id,
+ id_p,
+ id_remap_data,
+ cb_flag,
+ is_indirect,
+ is_never_null,
+ force_user_refcount,
+ is_obj_proxy);
}
return IDWALK_RET_NOP;
@@ -281,6 +330,11 @@ static void libblock_remap_data_postprocess_object_update(Main *bmain,
* to remove the NULL children from collections not used in any scene. */
BKE_collections_object_remove_nulls(bmain);
}
+ else {
+ /* Remapping may have created duplicates of CollectionObject pointing to the same object within
+ * the same collection. */
+ BKE_collections_object_remove_duplicates(bmain);
+ }
BKE_main_collection_sync_remap(bmain);
@@ -318,6 +372,7 @@ static void libblock_remap_data_postprocess_collection_update(Main *bmain,
else {
/* Temp safe fix, but a "tad" brute force... We should probably be able to use parents from
* old_collection instead? */
+ /* NOTE: Also takes care of duplicated child collections that remapping may have created. */
BKE_main_collections_parent_relations_rebuild(bmain);
}
@@ -345,7 +400,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o
static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id)
{
/* Update all group nodes using a node group. */
- ntreeUpdateAllUsers(bmain, new_id, 0);
+ ntreeUpdateAllUsers(bmain, new_id);
}
/**
@@ -455,15 +510,18 @@ static void libblock_remap_data(
#endif
}
-/**
- * Replace all references in given Main to \a old_id by \a new_id
- * (if \a new_id is NULL, it unlinks \a old_id).
- */
-void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
+typedef struct LibblockRemapMultipleUserData {
+ Main *bmain;
+ short remap_flags;
+} LibBlockRemapMultipleUserData;
+
+static void libblock_remap_foreach_idpair_cb(ID *old_id, ID *new_id, void *user_data)
{
+ LibBlockRemapMultipleUserData *data = user_data;
+ Main *bmain = data->bmain;
+ const short remap_flags = data->remap_flags;
+
IDRemap id_remap_data;
- ID *old_id = old_idv;
- ID *new_id = new_idv;
int skipped_direct, skipped_refcounted;
BLI_assert(old_id != NULL);
@@ -476,13 +534,6 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
free_notifier_reference_cb(old_id);
}
- /* We assume editors do not hold references to their IDs... This is false in some cases
- * (Image is especially tricky here),
- * editors' code is to handle refcount (id->us) itself then. */
- if (remap_editor_id_reference_cb) {
- remap_editor_id_reference_cb(old_id, new_id);
- }
-
skipped_direct = id_remap_data.skipped_direct;
skipped_refcounted = id_remap_data.skipped_refcounted;
@@ -555,6 +606,41 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
DEG_relations_tag_update(bmain);
}
+void BKE_libblock_remap_multiple_locked(Main *bmain,
+ const struct IDRemapper *mappings,
+ const short remap_flags)
+{
+ if (BKE_id_remapper_is_empty(mappings)) {
+ /* Early exit nothing to do. */
+ return;
+ }
+
+ LibBlockRemapMultipleUserData user_data;
+ user_data.bmain = bmain;
+ user_data.remap_flags = remap_flags;
+ BKE_id_remapper_iter(mappings, libblock_remap_foreach_idpair_cb, &user_data);
+
+ /* We assume editors do not hold references to their IDs... This is false in some cases
+ * (Image is especially tricky here),
+ * editors' code is to handle refcount (id->us) itself then. */
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(mappings);
+ }
+
+ /* Full rebuild of DEG! */
+ DEG_relations_tag_update(bmain);
+}
+
+void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
+{
+ struct IDRemapper *remapper = BKE_id_remapper_create();
+ ID *old_id = old_idv;
+ ID *new_id = new_idv;
+ BKE_id_remapper_add(remapper, old_id, new_id);
+ BKE_libblock_remap_multiple_locked(bmain, remapper, remap_flags);
+ BKE_id_remapper_free(remapper);
+}
+
void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
{
BKE_main_lock(bmain);
@@ -564,13 +650,17 @@ void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short r
BKE_main_unlock(bmain);
}
-/**
- * Unlink given \a id from given \a bmain
- * (does not touch to indirect, i.e. library, usages of the ID).
- *
- * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by
- * #LIB_TAG_DOIT flag (quite obviously, 'non-NULL' usages can never be unlinked by this function).
- */
+void BKE_libblock_remap_multiple(Main *bmain,
+ const struct IDRemapper *mappings,
+ const short remap_flags)
+{
+ BKE_main_lock(bmain);
+
+ BKE_libblock_remap_multiple_locked(bmain, mappings, remap_flags);
+
+ BKE_main_unlock(bmain);
+}
+
void BKE_libblock_unlink(Main *bmain,
void *idv,
const bool do_flag_never_null,
@@ -586,16 +676,6 @@ void BKE_libblock_unlink(Main *bmain,
BKE_main_unlock(bmain);
}
-/**
- * Similar to libblock_remap, but only affects IDs used by given \a idv ID.
- *
- * \param old_idv: Unlike BKE_libblock_remap, can be NULL,
- * in which case all ID usages by given \a idv will be cleared.
- * \param us_min_never_null: If \a true and new_id is NULL,
- * 'NEVER_NULL' ID usages keep their old id, but this one still gets its user count decremented
- * (needed when given \a idv is going to be deleted right after being unlinked).
- */
-/* Should be able to replace all _relink() funcs (constraints, rigidbody, etc.) ? */
/* XXX Arg! Naming... :(
* _relink? avoids confusion with _remap, but is confusing with _unlink
* _remap_used_ids?
@@ -603,9 +683,13 @@ void BKE_libblock_unlink(Main *bmain,
* BKE_id_remap maybe?
* ... sigh
*/
+
void BKE_libblock_relink_ex(
Main *bmain, void *idv, void *old_idv, void *new_idv, const short remap_flags)
{
+
+ /* Should be able to replace all _relink() funcs (constraints, rigidbody, etc.) ? */
+
ID *id = idv;
ID *old_id = old_idv;
ID *new_id = new_idv;
@@ -669,88 +753,47 @@ void BKE_libblock_relink_ex(
DEG_relations_tag_update(bmain);
}
+static void libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag);
static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data)
{
const int cb_flag = cb_data->cb_flag;
- if (cb_flag & IDWALK_CB_EMBEDDED) {
+ if (cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
return IDWALK_RET_NOP;
}
+ Main *bmain = cb_data->bmain;
+ ID *id_owner = cb_data->id_owner;
ID **id_pointer = cb_data->id_pointer;
ID *id = *id_pointer;
if (id) {
+ const int remap_flag = POINTER_AS_INT(cb_data->user_data);
/* See: NEW_ID macro */
- if (id->newid) {
- BKE_library_update_ID_link_user(id->newid, id, cb_flag);
+ if (id->newid != NULL) {
+ const int remap_flag_final = remap_flag | ID_REMAP_SKIP_INDIRECT_USAGE |
+ ID_REMAP_SKIP_OVERRIDE_LIBRARY;
+ BKE_libblock_relink_ex(bmain, id_owner, id, id->newid, (short)remap_flag_final);
id = id->newid;
- *id_pointer = id;
}
if (id->tag & LIB_TAG_NEW) {
id->tag &= ~LIB_TAG_NEW;
- BKE_libblock_relink_to_newid(id);
+ libblock_relink_to_newid(bmain, id, remap_flag);
}
}
return IDWALK_RET_NOP;
}
-/**
- * Similar to #libblock_relink_ex,
- * but is remapping IDs to their newid value if non-NULL, in given \a id.
- *
- * Very specific usage, not sure we'll keep it on the long run,
- * currently only used in Object/Collection duplication code...
- *
- * WARNING: This is a deprecated version of this function, should not be used by new code. See
- * #BKE_libblock_relink_to_newid_new below.
- */
-void BKE_libblock_relink_to_newid(ID *id)
+static void libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag)
{
if (ID_IS_LINKED(id)) {
return;
}
- BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0);
-}
-
-/* ************************
- * FIXME: Port all usages of #BKE_libblock_relink_to_newid to this
- * #BKE_libblock_relink_to_newid_new new code and remove old one.
- ************************** */
-static int id_relink_to_newid_looper_new(LibraryIDLinkCallbackData *cb_data)
-{
- const int cb_flag = cb_data->cb_flag;
- if (cb_flag & IDWALK_CB_EMBEDDED) {
- return IDWALK_RET_NOP;
- }
-
- Main *bmain = cb_data->bmain;
- ID *id_owner = cb_data->id_owner;
- ID **id_pointer = cb_data->id_pointer;
- ID *id = *id_pointer;
- if (id) {
- /* See: NEW_ID macro */
- if (id->newid != NULL) {
- BKE_libblock_relink_ex(bmain, id_owner, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE);
- id = id->newid;
- }
- if (id->tag & LIB_TAG_NEW) {
- id->tag &= ~LIB_TAG_NEW;
- BKE_libblock_relink_to_newid_new(bmain, id);
- }
- }
- return IDWALK_RET_NOP;
+ id->tag &= ~LIB_TAG_NEW;
+ BKE_library_foreach_ID_link(
+ bmain, id, id_relink_to_newid_looper, POINTER_FROM_INT(remap_flag), 0);
}
-/**
- * Remaps ID usages of given ID to their `id->newid` pointer if not None, and proceeds recursively
- * in the dependency tree of IDs for all data-blocks tagged with `LIB_TAG_NEW`.
- *
- * NOTE: `LIB_TAG_NEW` is cleared
- *
- * Very specific usage, not sure we'll keep it on the long run,
- * currently only used in Object/Collection duplication code...
- */
-void BKE_libblock_relink_to_newid_new(Main *bmain, ID *id)
+void BKE_libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag)
{
if (ID_IS_LINKED(id)) {
return;
@@ -758,6 +801,8 @@ void BKE_libblock_relink_to_newid_new(Main *bmain, ID *id)
/* We do not want to have those cached relationship data here. */
BLI_assert(bmain->relations == NULL);
- id->tag &= ~LIB_TAG_NEW;
- BKE_library_foreach_ID_link(bmain, id, id_relink_to_newid_looper_new, NULL, 0);
+ BKE_layer_collection_resync_forbid();
+ libblock_relink_to_newid(bmain, id, remap_flag);
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync_remap(bmain);
}
diff --git a/source/blender/blenkernel/intern/lib_remap_test.cc b/source/blender/blenkernel/intern/lib_remap_test.cc
new file mode 100644
index 00000000000..266ada3663d
--- /dev/null
+++ b/source/blender/blenkernel/intern/lib_remap_test.cc
@@ -0,0 +1,369 @@
+/*
+ * 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) 2022 by Blender Foundation.
+ */
+#include "testing/testing.h"
+
+#include "BLI_utildefines.h"
+
+#include "CLG_log.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "RNA_define.h"
+
+#include "BKE_appdir.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_idtype.h"
+#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+
+#include "IMB_imbuf.h"
+
+#include "ED_node.h"
+
+#include "MEM_guardedalloc.h"
+
+namespace blender::bke::tests {
+
+class TestData {
+ public:
+ Main *bmain = nullptr;
+ struct bContext *C = nullptr;
+
+ virtual void setup()
+ {
+ if (bmain == nullptr) {
+ bmain = BKE_main_new();
+ G.main = bmain;
+ }
+
+ if (C == nullptr) {
+ C = CTX_create();
+ CTX_data_main_set(C, bmain);
+ }
+ }
+
+ virtual void teardown()
+ {
+ if (bmain != nullptr) {
+ BKE_main_free(bmain);
+ bmain = nullptr;
+ G.main = nullptr;
+ }
+
+ if (C != nullptr) {
+ CTX_free(C);
+ C = nullptr;
+ }
+ }
+};
+
+class SceneTestData : public TestData {
+ public:
+ Scene *scene = nullptr;
+ void setup() override
+ {
+ TestData::setup();
+ scene = BKE_scene_add(bmain, "IDRemapScene");
+ CTX_data_scene_set(C, scene);
+ }
+};
+
+class CompositorTestData : public SceneTestData {
+ public:
+ bNodeTree *compositor_nodetree = nullptr;
+ void setup() override
+ {
+ SceneTestData::setup();
+ ED_node_composit_default(C, scene);
+ compositor_nodetree = scene->nodetree;
+ }
+};
+
+class MeshTestData : public TestData {
+ public:
+ Mesh *mesh = nullptr;
+
+ void setup() override
+ {
+ TestData::setup();
+ mesh = BKE_mesh_add(bmain, nullptr);
+ }
+};
+
+class TwoMeshesTestData : public MeshTestData {
+ public:
+ Mesh *other_mesh = nullptr;
+
+ void setup() override
+ {
+ MeshTestData::setup();
+ other_mesh = BKE_mesh_add(bmain, nullptr);
+ }
+};
+
+class MeshObjectTestData : public MeshTestData {
+ public:
+ Object *object;
+ void setup() override
+ {
+ MeshTestData::setup();
+
+ object = BKE_object_add_only_object(bmain, OB_MESH, nullptr);
+ object->data = mesh;
+ }
+};
+
+template<typename TestData> class Context {
+ public:
+ TestData test_data;
+
+ Context()
+ {
+ CLG_init();
+ BKE_idtype_init();
+ RNA_init();
+ BKE_node_system_init();
+ BKE_appdir_init();
+ IMB_init();
+
+ test_data.setup();
+ }
+
+ ~Context()
+ {
+ test_data.teardown();
+
+ BKE_node_system_exit();
+ RNA_exit();
+ IMB_exit();
+ BKE_appdir_exit();
+ CLG_exit();
+ }
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Embedded IDs
+ * \{ */
+
+TEST(lib_remap, embedded_ids_can_not_be_remapped)
+{
+ Context<CompositorTestData> context;
+ bNodeTree *other_tree = static_cast<bNodeTree *>(BKE_id_new_nomain(ID_NT, nullptr));
+
+ EXPECT_NE(context.test_data.scene, nullptr);
+ EXPECT_NE(context.test_data.compositor_nodetree, nullptr);
+ EXPECT_EQ(context.test_data.compositor_nodetree, context.test_data.scene->nodetree);
+
+ BKE_libblock_remap(
+ context.test_data.bmain, context.test_data.compositor_nodetree, other_tree, 0);
+
+ EXPECT_EQ(context.test_data.compositor_nodetree, context.test_data.scene->nodetree);
+ EXPECT_NE(context.test_data.scene->nodetree, other_tree);
+
+ BKE_id_free(nullptr, other_tree);
+}
+
+TEST(lib_remap, embedded_ids_can_not_be_deleted)
+{
+ Context<CompositorTestData> context;
+
+ EXPECT_NE(context.test_data.scene, nullptr);
+ EXPECT_NE(context.test_data.compositor_nodetree, nullptr);
+ EXPECT_EQ(context.test_data.compositor_nodetree, context.test_data.scene->nodetree);
+
+ BKE_libblock_remap(context.test_data.bmain,
+ context.test_data.compositor_nodetree,
+ nullptr,
+ ID_REMAP_SKIP_NEVER_NULL_USAGE);
+
+ EXPECT_EQ(context.test_data.compositor_nodetree, context.test_data.scene->nodetree);
+ EXPECT_NE(context.test_data.scene->nodetree, nullptr);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remap to self
+ * \{ */
+
+TEST(lib_remap, delete_when_remap_to_self_not_allowed)
+{
+ Context<TwoMeshesTestData> context;
+
+ EXPECT_NE(context.test_data.mesh, nullptr);
+ EXPECT_NE(context.test_data.other_mesh, nullptr);
+ context.test_data.mesh->texcomesh = context.test_data.other_mesh;
+
+ BKE_libblock_remap(
+ context.test_data.bmain, context.test_data.other_mesh, context.test_data.mesh, 0);
+
+ EXPECT_EQ(context.test_data.mesh->texcomesh, nullptr);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name User Reference Counting
+ * \{ */
+
+TEST(lib_remap, users_are_decreased_when_not_skipping_never_null)
+{
+ Context<MeshObjectTestData> context;
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+ EXPECT_EQ(context.test_data.mesh->id.us, 1);
+
+ /* This is an invalid situation, test case tests this in between value until we have a better
+ * solution. */
+ BKE_libblock_remap(context.test_data.bmain, context.test_data.mesh, nullptr, 0);
+ EXPECT_EQ(context.test_data.mesh->id.us, 0);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_NE(context.test_data.object->data, nullptr);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+}
+
+TEST(lib_remap, users_are_same_when_skipping_never_null)
+{
+ Context<MeshObjectTestData> context;
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+ EXPECT_EQ(context.test_data.mesh->id.us, 1);
+
+ BKE_libblock_remap(
+ context.test_data.bmain, context.test_data.mesh, nullptr, ID_REMAP_SKIP_NEVER_NULL_USAGE);
+ EXPECT_EQ(context.test_data.mesh->id.us, 1);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_NE(context.test_data.object->data, nullptr);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Never Null
+ * \{ */
+
+TEST(lib_remap, do_not_delete_when_cannot_unset)
+{
+ Context<MeshObjectTestData> context;
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+
+ BKE_libblock_remap(
+ context.test_data.bmain, context.test_data.mesh, nullptr, ID_REMAP_SKIP_NEVER_NULL_USAGE);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_NE(context.test_data.object->data, nullptr);
+}
+
+TEST(lib_remap, force_never_null_usage)
+{
+ Context<MeshObjectTestData> context;
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+
+ BKE_libblock_remap(
+ context.test_data.bmain, context.test_data.mesh, nullptr, ID_REMAP_FORCE_NEVER_NULL_USAGE);
+ EXPECT_EQ(context.test_data.object->data, nullptr);
+}
+
+TEST(lib_remap, never_null_usage_flag_not_requested_on_delete)
+{
+ Context<MeshObjectTestData> context;
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+
+ /* Never null usage isn't requested so the flag should not be set. */
+ BKE_libblock_remap(
+ context.test_data.bmain, context.test_data.mesh, nullptr, ID_REMAP_SKIP_NEVER_NULL_USAGE);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_NE(context.test_data.object->data, nullptr);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+}
+
+TEST(lib_remap, never_null_usage_flag_requested_on_delete)
+{
+ Context<MeshObjectTestData> context;
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+
+ /* Never null usage is requested so the flag should be set. */
+ BKE_libblock_remap(context.test_data.bmain,
+ context.test_data.mesh,
+ nullptr,
+ ID_REMAP_SKIP_NEVER_NULL_USAGE | ID_REMAP_FLAG_NEVER_NULL_USAGE);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_NE(context.test_data.object->data, nullptr);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, LIB_TAG_DOIT);
+}
+
+TEST(lib_remap, never_null_usage_flag_not_requested_on_remap)
+{
+ Context<MeshObjectTestData> context;
+ Mesh *other_mesh = BKE_mesh_add(context.test_data.bmain, nullptr);
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+
+ /* Never null usage isn't requested so the flag should not be set. */
+ BKE_libblock_remap(
+ context.test_data.bmain, context.test_data.mesh, other_mesh, ID_REMAP_SKIP_NEVER_NULL_USAGE);
+ EXPECT_EQ(context.test_data.object->data, other_mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+}
+
+TEST(lib_remap, never_null_usage_flag_requested_on_remap)
+{
+ Context<MeshObjectTestData> context;
+ Mesh *other_mesh = BKE_mesh_add(context.test_data.bmain, nullptr);
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+
+ /* Never null usage is requested so the flag should be set. */
+ BKE_libblock_remap(context.test_data.bmain,
+ context.test_data.mesh,
+ other_mesh,
+ ID_REMAP_SKIP_NEVER_NULL_USAGE | ID_REMAP_FLAG_NEVER_NULL_USAGE);
+ EXPECT_EQ(context.test_data.object->data, other_mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, LIB_TAG_DOIT);
+}
+
+/** \} */
+
+} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 36958e36004..c97b003d241 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -36,6 +36,7 @@
#include "BLT_translation.h"
+#include "BKE_bpath.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
@@ -57,7 +58,23 @@ static void library_free_data(ID *id)
static void library_foreach_id(ID *id, LibraryForeachIDData *data)
{
Library *lib = (Library *)id;
- BKE_LIB_FOREACHID_PROCESS(data, lib->parent, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, lib->parent, IDWALK_CB_NEVER_SELF);
+}
+
+static void library_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Library *lib = (Library *)id;
+
+ /* FIXME: Find if we should respect #BKE_BPATH_FOREACH_PATH_SKIP_PACKED here, and if not, explain
+ * why. */
+ if (lib->packedfile !=
+ NULL /*&& (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0 */) {
+ return;
+ }
+
+ if (BKE_bpath_foreach_path_fixed_process(bpath_data, lib->filepath)) {
+ BKE_library_filepath_set(bpath_data->bmain, lib, lib->filepath);
+ }
}
IDTypeInfo IDType_ID_LI = {
@@ -69,6 +86,7 @@ IDTypeInfo IDType_ID_LI = {
.name_plural = "libraries",
.translation_context = BLT_I18NCONTEXT_ID_LIBRARY,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -76,6 +94,7 @@ IDTypeInfo IDType_ID_LI = {
.make_local = NULL,
.foreach_id = library_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = library_foreach_path,
.owner_get = NULL,
.blend_write = NULL,
@@ -108,7 +127,7 @@ void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
*/
/* Never make paths relative to parent lib - reading code (blenloader) always set *all*
* `lib->filepath` relative to current main, not to their parent for indirectly linked ones. */
- const char *basepath = BKE_main_blendfile_path(bmain);
- BLI_path_abs(lib->filepath_abs, basepath);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
+ BLI_path_abs(lib->filepath_abs, blendfile_path);
}
}
diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c
index a6150028f46..e73cda7e24d 100644
--- a/source/blender/blenkernel/intern/light.c
+++ b/source/blender/blenkernel/intern/light.c
@@ -129,7 +129,8 @@ static void light_foreach_id(ID *id, LibraryForeachIDData *data)
Light *lamp = (Light *)id;
if (lamp->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_embedded(data, (ID **)&lamp->nodetree);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&lamp->nodetree));
}
}
@@ -194,6 +195,7 @@ IDTypeInfo IDType_ID_LA = {
.name_plural = "lights",
.translation_context = BLT_I18NCONTEXT_ID_LIGHT,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = light_init_data,
.copy_data = light_copy_data,
@@ -201,6 +203,7 @@ IDTypeInfo IDType_ID_LA = {
.make_local = NULL,
.foreach_id = light_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = light_blend_write,
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
index 1f4abf36426..035e41815e5 100644
--- a/source/blender/blenkernel/intern/lightprobe.c
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -53,8 +53,8 @@ static void lightprobe_foreach_id(ID *id, LibraryForeachIDData *data)
{
LightProbe *probe = (LightProbe *)id;
- BKE_LIB_FOREACHID_PROCESS(data, probe->image, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, probe->visibility_grp, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, probe->image, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, probe->visibility_grp, IDWALK_CB_NOP);
}
static void lightprobe_blend_write(BlendWriter *writer, ID *id, const void *id_address)
@@ -92,6 +92,7 @@ IDTypeInfo IDType_ID_LP = {
.name_plural = "lightprobes",
.translation_context = BLT_I18NCONTEXT_ID_LIGHTPROBE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = lightprobe_init_data,
.copy_data = NULL,
@@ -99,6 +100,7 @@ IDTypeInfo IDType_ID_LP = {
.make_local = NULL,
.foreach_id = lightprobe_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = lightprobe_blend_write,
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index f4e4dd9f1ab..95f41ab4b39 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -50,6 +50,7 @@
#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_texture.h"
#include "BLO_read_write.h"
@@ -155,12 +156,14 @@ static void linestyle_foreach_id(ID *id, LibraryForeachIDData *data)
for (int i = 0; i < MAX_MTEX; i++) {
if (linestyle->mtex[i]) {
- BKE_texture_mtex_foreach_id(data, linestyle->mtex[i]);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_texture_mtex_foreach_id(data, linestyle->mtex[i]));
}
}
if (linestyle->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_embedded(data, (ID **)&linestyle->nodetree);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&linestyle->nodetree));
}
LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->color_modifiers) {
@@ -168,7 +171,7 @@ static void linestyle_foreach_id(ID *id, LibraryForeachIDData *data)
LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)
lsm;
if (p->target) {
- BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, p->target, IDWALK_CB_NOP);
}
}
}
@@ -177,7 +180,7 @@ static void linestyle_foreach_id(ID *id, LibraryForeachIDData *data)
LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)
lsm;
if (p->target) {
- BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, p->target, IDWALK_CB_NOP);
}
}
}
@@ -186,7 +189,7 @@ static void linestyle_foreach_id(ID *id, LibraryForeachIDData *data)
LineStyleThicknessModifier_DistanceFromObject *p =
(LineStyleThicknessModifier_DistanceFromObject *)lsm;
if (p->target) {
- BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, p->target, IDWALK_CB_NOP);
}
}
}
@@ -752,6 +755,7 @@ IDTypeInfo IDType_ID_LS = {
.name_plural = "linestyles",
.translation_context = BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = linestyle_init_data,
.copy_data = linestyle_copy_data,
@@ -759,6 +763,7 @@ IDTypeInfo IDType_ID_LS = {
.make_local = NULL,
.foreach_id = linestyle_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = linestyle_blend_write,
@@ -1908,10 +1913,6 @@ int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle, LineSt
return 0;
}
-/**
- * Reinsert \a modifier in modifier list with an offset of \a direction.
- * \return if position of \a modifier has changed.
- */
bool BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle,
LineStyleModifier *modifier,
int direction)
@@ -2085,5 +2086,5 @@ void BKE_linestyle_default_shader(const bContext *C, FreestyleLineStyle *linesty
tosock = BLI_findlink(&output_linestyle->inputs, 0); /* Color */
nodeAddLink(ntree, input_texure, fromsock, output_linestyle, tosock);
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ BKE_ntree_update_main_tree(CTX_data_main(C), ntree, NULL);
}
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index 9c3291edbcc..64731be57ac 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -205,6 +205,16 @@ void BKE_main_free(Main *mainvar)
MEM_freeN(mainvar);
}
+bool BKE_main_is_empty(struct Main *bmain)
+{
+ ID *id_iter;
+ FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
+ return false;
+ }
+ FOREACH_MAIN_ID_END;
+ return true;
+}
+
void BKE_main_lock(struct Main *bmain)
{
BLI_spin_lock((SpinLock *)bmain->lock);
@@ -267,7 +277,6 @@ static int main_relations_create_idlink_cb(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
-/** Generate the mappings between used IDs and their users, and vice-versa. */
void BKE_main_relations_create(Main *bmain, const short flag)
{
if (bmain->relations != NULL) {
@@ -315,9 +324,8 @@ void BKE_main_relations_free(Main *bmain)
}
}
-/** Set or clear given `tag` in all relation entries of given `bmain`. */
void BKE_main_relations_tag_set(struct Main *bmain,
- const MainIDRelationsEntryTags tag,
+ const eMainIDRelationsEntryTags tag,
const bool value)
{
if (bmain->relations == NULL) {
@@ -339,12 +347,6 @@ void BKE_main_relations_tag_set(struct Main *bmain,
BLI_ghashIterator_free(gh_iter);
}
-/**
- * Create a GSet storing all IDs present in given \a bmain, by their pointers.
- *
- * \param gset: If not NULL, given GSet will be extended with IDs from given \a bmain,
- * instead of creating a new one.
- */
GSet *BKE_main_gset_create(Main *bmain, GSet *gset)
{
if (gset == NULL) {
@@ -393,12 +395,6 @@ static bool lib_weak_key_cmp(const void *a, const void *b)
STREQ(string_pair_a->id_name, string_pair_b->id_name));
}
-/**
- * Generate a mapping between 'library path' of an ID (as a pair (relative blend file path, id
- * name)), and a current local ID, if any.
- *
- * This uses the information stored in `ID.library_weak_reference`.
- */
GHash *BKE_main_library_weak_reference_create(Main *bmain)
{
GHash *library_weak_reference_mapping = BLI_ghash_new(
@@ -431,24 +427,11 @@ GHash *BKE_main_library_weak_reference_create(Main *bmain)
return library_weak_reference_mapping;
}
-/**
- * Destroy the data generated by #BKE_main_library_weak_reference_create.
- */
void BKE_main_library_weak_reference_destroy(GHash *library_weak_reference_mapping)
{
BLI_ghash_free(library_weak_reference_mapping, MEM_freeN, NULL);
}
-/**
- * Search for a local ID matching the given linked ID reference.
- *
- * \param library_weak_reference_mapping: the mapping data generated by
- * #BKE_main_library_weak_reference_create.
- * \param library_relative_path: the path of a blend file library (relative to current working
- * one).
- * \param library_id_name: the full ID name, including the leading two chars encoding the ID
- * type.
- */
ID *BKE_main_library_weak_reference_search_item(GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name)
@@ -458,16 +441,6 @@ ID *BKE_main_library_weak_reference_search_item(GHash *library_weak_reference_ma
return (ID *)BLI_ghash_lookup(library_weak_reference_mapping, &key);
}
-/**
- * Add the given ID weak library reference to given local ID and the runtime mapping.
- *
- * \param library_weak_reference_mapping: the mapping data generated by
- * #BKE_main_library_weak_reference_create.
- * \param library_relative_path: the path of a blend file library (relative to current working
- * one).
- * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
- * \param new_id: New local ID matching given weak reference.
- */
void BKE_main_library_weak_reference_add_item(GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
@@ -496,21 +469,6 @@ void BKE_main_library_weak_reference_add_item(GHash *library_weak_reference_mapp
*id_p = new_id;
}
-/**
- * Update the status of the given ID weak library reference in current local IDs and the runtime
- * mapping.
- *
- * This effectively transfers the 'ownership' of the given weak reference from `old_id` to
- * `new_id`.
- *
- * \param library_weak_reference_mapping: the mapping data generated by
- * #BKE_main_library_weak_reference_create.
- * \param library_relative_path: the path of a blend file library (relative to current working
- * one).
- * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
- * \param old_id: Existing local ID matching given weak reference.
- * \param new_id: New local ID matching given weak reference.
- */
void BKE_main_library_weak_reference_update_item(GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
@@ -534,16 +492,6 @@ void BKE_main_library_weak_reference_update_item(GHash *library_weak_reference_m
*id_p = new_id;
}
-/**
- * Remove the given ID weak library reference from the given local ID and the runtime mapping.
- *
- * \param library_weak_reference_mapping: the mapping data generated by
- * #BKE_main_library_weak_reference_create.
- * \param library_relative_path: the path of a blend file library (relative to current working
- * one).
- * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
- * \param old_id: Existing local ID matching given weak reference.
- */
void BKE_main_library_weak_reference_remove_item(GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
@@ -561,13 +509,6 @@ void BKE_main_library_weak_reference_remove_item(GHash *library_weak_reference_m
MEM_SAFE_FREE(old_id->library_weak_reference);
}
-/**
- * Generates a raw .blend file thumbnail data from given image.
- *
- * \param bmain: If not NULL, also store generated data in this Main.
- * \param img: ImBuf image to generate thumbnail data from.
- * \return The generated .blend file raw thumbnail data.
- */
BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
{
BlendThumbnail *data = NULL;
@@ -592,13 +533,6 @@ BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
return data;
}
-/**
- * Generates an image from raw .blend file thumbnail \a data.
- *
- * \param bmain: Use this bmain->blen_thumb data if given \a data is NULL.
- * \param data: Raw .blend file thumbnail data.
- * \return An ImBuf from given data, or NULL if invalid.
- */
ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
{
ImBuf *img = NULL;
@@ -615,9 +549,6 @@ ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
return img;
}
-/**
- * Generates an empty (black) thumbnail for given Main.
- */
void BKE_main_thumbnail_create(struct Main *bmain)
{
MEM_SAFE_FREE(bmain->blen_thumb);
@@ -627,28 +558,16 @@ void BKE_main_thumbnail_create(struct Main *bmain)
bmain->blen_thumb->height = BLEN_THUMB_SIZE;
}
-/**
- * Return filepath of given \a main.
- */
const char *BKE_main_blendfile_path(const Main *bmain)
{
- return bmain->name;
+ return bmain->filepath;
}
-/**
- * Return filepath of global main #G_MAIN.
- *
- * \warning Usage is not recommended,
- * you should always try to get a valid Main pointer from context...
- */
const char *BKE_main_blendfile_path_from_global(void)
{
return BKE_main_blendfile_path(G_MAIN);
}
-/**
- * \return A pointer to the \a ListBase of given \a bmain for requested \a type ID type.
- */
ListBase *which_libbase(Main *bmain, short type)
{
switch ((ID_Type)type) {
@@ -736,18 +655,6 @@ ListBase *which_libbase(Main *bmain, short type)
return NULL;
}
-/**
- * Put the pointers to all the #ListBase structs in given `bmain` into the `*lb[INDEX_ID_MAX]`
- * array, and return the number of those for convenience.
- *
- * This is useful for generic traversal of all the blocks in a #Main (by traversing all the lists
- * in turn), without worrying about block types.
- *
- * \param lb: Array of lists #INDEX_ID_MAX in length.
- *
- * \note The order of each ID type #ListBase in the array is determined by the `INDEX_ID_<IDTYPE>`
- * enum definitions in `DNA_ID.h`. See also the #FOREACH_MAIN_ID_BEGIN macro in `BKE_main.h`
- */
int set_listbasepointers(Main *bmain, ListBase *lb[/*INDEX_ID_MAX*/])
{
/* Libraries may be accessed from pretty much any other ID. */
diff --git a/source/blender/blenkernel/intern/main_idmap.c b/source/blender/blenkernel/intern/main_idmap.c
index c75365a788d..38523f22aad 100644
--- a/source/blender/blenkernel/intern/main_idmap.c
+++ b/source/blender/blenkernel/intern/main_idmap.c
@@ -88,18 +88,6 @@ static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id
return NULL;
}
-/**
- * Generate mapping from ID type/name to ID pointer for given \a bmain.
- *
- * \note When used during undo/redo, there is no guaranty that ID pointers from UI area
- * are not pointing to freed memory (when some IDs have been deleted). To avoid crashes
- * in those cases, one can provide the 'old' (aka current) Main database as reference.
- * #BKE_main_idmap_lookup_id will then check that given ID does exist in \a old_bmain
- * before trying to use it.
- *
- * \param create_valid_ids_set: If \a true, generate a reference to prevent freed memory accesses.
- * \param old_bmain: If not NULL, its IDs will be added the valid references set.
- */
struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain,
const bool create_valid_ids_set,
struct Main *old_bmain,
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 1d3ebaac303..12bbab57cf2 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -38,6 +38,7 @@
#include "BLT_translation.h"
+#include "DNA_defaults.h"
#include "DNA_mask_types.h"
#include "BKE_animsys.h"
@@ -255,6 +256,7 @@ IDTypeInfo IDType_ID_MSK = {
.name_plural = "masks",
.translation_context = BLT_I18NCONTEXT_ID_MASK,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = mask_copy_data,
@@ -262,6 +264,7 @@ IDTypeInfo IDType_ID_MSK = {
.make_local = NULL,
.foreach_id = mask_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = mask_blend_write,
@@ -371,7 +374,6 @@ MaskLayer *BKE_mask_layer_new(Mask *mask, const char *name)
return masklay;
}
-/* NOTE: may still be hidden, caller needs to check. */
MaskLayer *BKE_mask_layer_active(Mask *mask)
{
return BLI_findlink(&mask->masklayers, mask->masklay_act);
@@ -787,12 +789,11 @@ BLI_INLINE void orthogonal_direction_get(const float vec[2], float result[2])
normalize_v2(result);
}
-/* TODO(sergey): This function will re-calculate loads of stuff again and again
- * when differentiating feather points. This might be easily cached
- * in the callee function for this case.
- */
void BKE_mask_point_normal(MaskSpline *spline, MaskSplinePoint *point, float u, float n[2])
{
+ /* TODO(sergey): This function will re-calculate loads of stuff again and again
+ * when differentiating feather points. This might be easily cached
+ * in the callee function for this case. */
MaskSplinePoint *point_prev, *point_next;
@@ -1132,7 +1133,6 @@ MaskSpline *BKE_mask_spline_copy(const MaskSpline *spline)
return nspline;
}
-/* NOTE: Does NOT add to the list. */
MaskLayerShape *BKE_mask_layer_shape_alloc(MaskLayer *masklay, const int frame)
{
MaskLayerShape *masklay_shape;
@@ -1156,8 +1156,6 @@ void BKE_mask_layer_shape_free(MaskLayerShape *masklay_shape)
MEM_freeN(masklay_shape);
}
-/** \brief Free all animation keys for a mask layer
- */
void BKE_mask_layer_free_shapes(MaskLayer *masklay)
{
MaskLayerShape *masklay_shape;
@@ -1245,7 +1243,6 @@ void BKE_mask_coord_from_image(Image *image, ImageUser *iuser, float r_co[2], co
BKE_mask_coord_from_frame(r_co, co, frame_size);
}
-/* as above but divide */
void BKE_mask_coord_to_frame(float r_co[2], const float co[2], const float frame_size[2])
{
if (frame_size[0] == frame_size[1]) {
@@ -1312,7 +1309,7 @@ void BKE_mask_point_parent_matrix_get(MaskSplinePoint *point,
MovieTrackingObject *ob = BKE_tracking_object_get_named(tracking, parent->parent);
if (ob) {
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
float clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
BKE_movieclip_user_set_frame(&user, ctime);
@@ -1428,8 +1425,6 @@ void BKE_mask_get_handle_point_adjacent(MaskSpline *spline,
*r_point_next = mask_spline_point_next(spline, points_array, point);
}
-/* calculates the tangent of a point by its previous and next
- * (ignoring handles - as if its a poly line) */
void BKE_mask_calc_tangent_polyline(MaskSpline *spline, MaskSplinePoint *point, float t[2])
{
float tvec_a[2], tvec_b[2];
@@ -1513,11 +1508,6 @@ void BKE_mask_calc_handle_adjacent_interp(MaskSpline *spline,
}
}
-/**
- * \brief Resets auto handles even for non-auto bezier points
- *
- * Useful for giving sane defaults.
- */
void BKE_mask_calc_handle_point_auto(MaskSpline *spline,
MaskSplinePoint *point,
const bool do_recalc_length)
@@ -1640,7 +1630,6 @@ static void mask_layer_shape_to_mask_point(BezTriple *bezt,
bezt->radius = fp[7];
}
-/* these functions match. copy is swapped */
void BKE_mask_layer_shape_from_mask(MaskLayer *masklay, MaskLayerShape *masklay_shape)
{
int tot = BKE_mask_layer_shape_totvert(masklay);
@@ -1696,7 +1685,6 @@ BLI_INLINE void interp_v2_v2v2_flfl(
target[1] = s * a[1] + t * b[1];
}
-/* linear interpolation only */
void BKE_mask_layer_shape_to_mask_interp(MaskLayer *masklay,
MaskLayerShape *masklay_shape_a,
MaskLayerShape *masklay_shape_b,
@@ -1757,9 +1745,6 @@ MaskLayerShape *BKE_mask_layer_shape_find_frame(MaskLayer *masklay, const int fr
return NULL;
}
-/**
- * When returning 2 - the frame isn't found but before/after frames are.
- */
int BKE_mask_layer_shape_find_frame_range(MaskLayer *masklay,
const float frame,
MaskLayerShape **r_masklay_shape_a,
@@ -1922,7 +1907,6 @@ static void interp_weights_uv_v2_apply(const float uv[2],
r_pt[1] += dvec[0] * uv[1];
}
-/* When a new points added - resize all shape-key array. */
void BKE_mask_layer_shape_changed_add(MaskLayer *masklay,
int index,
bool do_init,
@@ -2017,7 +2001,6 @@ void BKE_mask_layer_shape_changed_add(MaskLayer *masklay,
}
}
-/* move array to account for removed point */
void BKE_mask_layer_shape_changed_remove(MaskLayer *masklay, int index, int count)
{
MaskLayerShape *masklay_shape;
@@ -2079,13 +2062,11 @@ static void mask_clipboard_free_ex(bool final_free)
}
}
-/* Free the clipboard. */
void BKE_mask_clipboard_free(void)
{
mask_clipboard_free_ex(true);
}
-/* Copy selected visible splines from the given layer to clipboard. */
void BKE_mask_clipboard_copy_from_layer(MaskLayer *mask_layer)
{
MaskSpline *spline;
@@ -2120,13 +2101,11 @@ void BKE_mask_clipboard_copy_from_layer(MaskLayer *mask_layer)
}
}
-/* Check clipboard is empty. */
bool BKE_mask_clipboard_is_empty(void)
{
return BLI_listbase_is_empty(&mask_clipboard.splines);
}
-/* Paste the contents of clipboard to given mask layer */
void BKE_mask_clipboard_paste_to_layer(Main *bmain, MaskLayer *mask_layer)
{
MaskSpline *spline;
diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c
index 4584d9e527e..69fc7554eed 100644
--- a/source/blender/blenkernel/intern/mask_evaluate.c
+++ b/source/blender/blenkernel/intern/mask_evaluate.c
@@ -720,10 +720,6 @@ static float (*mask_spline_feather_differentiated_points_with_resolution__double
return feather;
}
-/**
- * values align with #BKE_mask_spline_differentiate_with_resolution
- * when \a resol arguments match.
- */
float (*BKE_mask_spline_feather_differentiated_points_with_resolution(
MaskSpline *spline,
const unsigned int resol,
@@ -788,7 +784,6 @@ float (*BKE_mask_spline_feather_points(MaskSpline *spline, int *r_tot_feather_po
return feather;
}
-/* *** mask point functions which involve evaluation *** */
float *BKE_mask_point_segment_feather_diff(MaskSpline *spline,
MaskSplinePoint *point,
int width,
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index e04e5fceec6..b0876957620 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -151,7 +151,7 @@ BLI_INLINE unsigned int clampis_uint(const unsigned int v,
}
/* --------------------------------------------------------------------- */
-/* local structs for mask rasterizeing */
+/* local structs for mask rasterizing */
/* --------------------------------------------------------------------- */
/**
@@ -1474,9 +1474,6 @@ static void maskrasterize_buffer_cb(void *__restrict userdata,
}
}
-/**
- * \brief Rasterize a buffer from a single mask (threaded execution).
- */
void BKE_maskrasterize_buffer(MaskRasterHandle *mr_handle,
const unsigned int width,
const unsigned int height,
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index fa3fbd457d1..15469f910b4 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -63,7 +63,6 @@
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_editmesh.h"
-#include "BKE_font.h"
#include "BKE_gpencil.h"
#include "BKE_icons.h"
#include "BKE_idtype.h"
@@ -76,6 +75,7 @@
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_scene.h"
+#include "BKE_vfont.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -166,15 +166,14 @@ static void material_foreach_id(ID *id, LibraryForeachIDData *data)
{
Material *material = (Material *)id;
/* Nodetrees **are owned by IDs**, treat them as mere sub-data and not real ID! */
- if (!BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree)) {
- return;
- }
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree));
if (material->texpaintslot != NULL) {
- BKE_LIB_FOREACHID_PROCESS(data, material->texpaintslot->ima, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->texpaintslot->ima, IDWALK_CB_NOP);
}
if (material->gp_style != NULL) {
- BKE_LIB_FOREACHID_PROCESS(data, material->gp_style->sima, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, material->gp_style->ima, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->gp_style->sima, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->gp_style->ima, IDWALK_CB_USER);
}
}
@@ -262,6 +261,7 @@ IDTypeInfo IDType_ID_MA = {
.name_plural = "materials",
.translation_context = BLT_I18NCONTEXT_ID_MATERIAL,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = material_init_data,
.copy_data = material_copy_data,
@@ -269,6 +269,7 @@ IDTypeInfo IDType_ID_MA = {
.make_local = NULL,
.foreach_id = material_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = material_blend_write,
@@ -388,7 +389,6 @@ short *BKE_object_material_len_p(Object *ob)
return NULL;
}
-/* same as above but for ID's */
Material ***BKE_id_material_array_p(ID *id)
{
/* ensure we don't try get materials from non-obdata */
@@ -720,20 +720,14 @@ static ID *get_evaluated_object_data_with_materials(Object *ob)
/* Meshes in edit mode need special handling. */
if (ob->type == OB_MESH && ob->mode == OB_MODE_EDIT) {
Mesh *mesh = ob->data;
- if (mesh->edit_mesh && mesh->edit_mesh->mesh_eval_final) {
- data = &mesh->edit_mesh->mesh_eval_final->id;
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
+ if (mesh->edit_mesh && editmesh_eval_final) {
+ data = &editmesh_eval_final->id;
}
}
return data;
}
-/**
- * On evaluated objects the number of materials on an object and its data might go out of sync.
- * This is because during evaluation materials can be added/removed on the object data.
- *
- * For rendering or exporting we generally use the materials on the object data. However, some
- * material indices might be overwritten by the object.
- */
Material *BKE_object_material_get_eval(Object *ob, short act)
{
BLI_assert(DEG_is_evaluated_object(ob));
@@ -807,10 +801,6 @@ void BKE_id_material_eval_assign(ID *id, int slot, Material *material)
(*materials_ptr)[slot_index] = material;
}
-/**
- * Add an empty material slot if the id has no material slots. This material slot allows the
- * material to be overwritten by object-linked materials.
- */
void BKE_id_material_eval_ensure_default_slot(ID *id)
{
short *len_ptr = BKE_id_material_len_p(id);
@@ -900,7 +890,17 @@ void BKE_object_materials_test(Main *bmain, Object *ob, ID *id)
return;
}
- BKE_object_material_resize(bmain, ob, *totcol, false);
+ if ((ob->id.tag & LIB_TAG_MISSING) == 0 && (id->tag & LIB_TAG_MISSING) != 0) {
+ /* Exception: In case the object is a valid data, but its obdata is an empty place-holder,
+ * use object's material slots amount as reference.
+ * This avoids losing materials in a local object when its linked obdata goes missing.
+ * See T92780. */
+ BKE_id_material_resize(bmain, id, (short)ob->totcol, false);
+ }
+ else {
+ /* Normal case: the use the obdata amount of materials slots to update the object's one. */
+ BKE_object_material_resize(bmain, ob, *totcol, false);
+ }
}
void BKE_objects_materials_test_all(Main *bmain, ID *id)
@@ -1090,12 +1090,6 @@ void BKE_object_material_remap(Object *ob, const unsigned int *remap)
}
}
-/**
- * Calculate a material remapping from \a ob_src to \a ob_dst.
- *
- * \param remap_src_to_dst: An array the size of `ob_src->totcol`
- * where index values are filled in which map to \a ob_dst materials.
- */
void BKE_object_material_remap_calc(Object *ob_dst, Object *ob_src, short *remap_src_to_dst)
{
if (ob_src->totcol == 0) {
@@ -1144,9 +1138,6 @@ void BKE_object_material_remap_calc(Object *ob_dst, Object *ob_src, short *remap
BLI_ghash_free(gh_mat_map, NULL, NULL);
}
-/**
- * Copy materials from evaluated geometry to the original geometry of an object.
- */
void BKE_object_material_from_eval_data(Main *bmain, Object *ob_orig, ID *data_eval)
{
ID *data_orig = ob_orig->data;
@@ -1181,7 +1172,6 @@ void BKE_object_material_from_eval_data(Main *bmain, Object *ob_orig, ID *data_e
BKE_object_materials_test(bmain, ob_orig, data_orig);
}
-/* XXX: this calls many more update calls per object then are needed, could be optimized. */
void BKE_object_material_array_assign(Main *bmain,
struct Object *ob,
struct Material ***matar,
@@ -1544,7 +1534,6 @@ bNode *BKE_texpaint_slot_material_find_node(Material *ma, short texpaint_slot)
return find_data.r_node;
}
-/* r_col = current value, col = new value, (fac == 0) is no change */
void ramp_blend(int type, float r_col[3], const float fac, const float col[3])
{
float tmp, facm = 1.0f - fac;
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 6c8664aefed..ac6b0a04def 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -112,7 +112,7 @@ static void metaball_foreach_id(ID *id, LibraryForeachIDData *data)
{
MetaBall *metaball = (MetaBall *)id;
for (int i = 0; i < metaball->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, metaball->mat[i], IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, metaball->mat[i], IDWALK_CB_USER);
}
}
@@ -189,6 +189,7 @@ IDTypeInfo IDType_ID_MB = {
.name_plural = "metaballs",
.translation_context = BLT_I18NCONTEXT_ID_METABALL,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = metaball_init_data,
.copy_data = metaball_copy_data,
@@ -196,6 +197,7 @@ IDTypeInfo IDType_ID_MB = {
.make_local = NULL,
.foreach_id = metaball_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = metaball_blend_write,
@@ -219,8 +221,6 @@ MetaBall *BKE_mball_add(Main *bmain, const char *name)
return mb;
}
-/* most simple meta-element adding function
- * don't do context manipulation here (rna uses) */
MetaElem *BKE_mball_element_add(MetaBall *mb, const int type)
{
MetaElem *ml = MEM_callocN(sizeof(MetaElem), "metaelem");
@@ -267,13 +267,6 @@ MetaElem *BKE_mball_element_add(MetaBall *mb, const int type)
return ml;
}
-/**
- * Compute bounding box of all #MetaElem / #MetaBall
- *
- * Bounding box is computed from polygonized surface. \a ob is
- * basic meta-balls (with name `Meta` for example). All other meta-ball objects
- * (with names `Meta.001`, `Meta.002`, etc) are included in this bounding-box.
- */
void BKE_mball_texspace_calc(Object *ob)
{
DispList *dl;
@@ -317,7 +310,6 @@ void BKE_mball_texspace_calc(Object *ob)
bb->flag &= ~BOUNDBOX_DIRTY;
}
-/** Return or compute bbox for given metaball object. */
BoundBox *BKE_mball_boundbox_get(Object *ob)
{
BLI_assert(ob->type == OB_MBALL);
@@ -370,38 +362,29 @@ float *BKE_mball_make_orco(Object *ob, ListBase *dispbase)
return orcodata;
}
-/**
- * \brief Test, if \a ob is a basis meta-ball.
- *
- * It test last character of Object ID name. If last character
- * is digit it return 0, else it return 1.
- *
- *
- * Meta-Ball Basis Notes from Blender-2.5x
- * =======================================
- *
- * This is a can of worms.
- *
- * This really needs a rewrite/refactor its totally broken in anything other than basic cases
- * Multiple Scenes + Set Scenes & mixing meta-ball basis _should_ work but fails to update the
- * depsgraph on rename and linking into scenes or removal of basis meta-ball.
- * So take care when changing this code.
- *
- * Main idiot thing here is that the system returns #BKE_mball_basis_find()
- * objects which fail a #BKE_mball_is_basis() test.
- *
- * Not only that but the depsgraph and their areas depend on this behavior,
- * so making small fixes here isn't worth it.
- * - Campbell
- */
bool BKE_mball_is_basis(Object *ob)
{
- /* just a quick test */
+ /* Meta-Ball Basis Notes from Blender-2.5x
+ * =======================================
+ *
+ * NOTE(@campbellbarton): This is a can of worms.
+ *
+ * This really needs a rewrite/refactor its totally broken in anything other than basic cases
+ * Multiple Scenes + Set Scenes & mixing meta-ball basis _should_ work but fails to update the
+ * depsgraph on rename and linking into scenes or removal of basis meta-ball.
+ * So take care when changing this code.
+ *
+ * Main idiot thing here is that the system returns #BKE_mball_basis_find()
+ * objects which fail a #BKE_mball_is_basis() test.
+ *
+ * Not only that but the depsgraph and their areas depend on this behavior,
+ * so making small fixes here isn't worth it. */
+
+ /* Just a quick test. */
const int len = strlen(ob->id.name);
return (!isdigit(ob->id.name[len - 1]));
}
-/* return nonzero if ob1 is a basis mball for ob */
bool BKE_mball_is_basis_for(Object *ob1, Object *ob2)
{
int basis1nr, basis2nr;
@@ -454,13 +437,6 @@ bool BKE_mball_is_any_unselected(const MetaBall *mb)
return false;
}
-/**
- * \brief copy some properties from object to other meta-ball object with same base name
- *
- * When some properties (wire-size, threshold, update flags) of meta-ball are changed, then this
- * properties are copied to all meta-balls in same "group" (meta-balls with same base name:
- * `MBall`, `MBall.001`, `MBall.002`, etc). The most important is to copy properties to the base
- * meta-ball, because this meta-ball influence polygonization of meta-balls. */
void BKE_mball_properties_copy(Scene *scene, Object *active_object)
{
Scene *sce_iter = scene;
@@ -499,14 +475,6 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object)
}
}
-/** \brief This function finds the basis MetaBall.
- *
- * Basis meta-ball doesn't include any number at the end of
- * its name. All meta-balls with same base of name can be
- * blended. meta-balls with different basic name can't be blended.
- *
- * \warning #BKE_mball_is_basis() can fail on returned object, see function docs for details.
- */
Object *BKE_mball_basis_find(Scene *scene, Object *object)
{
Object *bob = object;
@@ -571,7 +539,6 @@ bool BKE_mball_minmax_ex(
return changed;
}
-/* basic vertex data functions */
bool BKE_mball_minmax(const MetaBall *mb, float min[3], float max[3])
{
INIT_MINMAX(min, max);
@@ -646,7 +613,6 @@ void BKE_mball_translate(MetaBall *mb, const float offset[3])
}
}
-/* *** select funcs *** */
int BKE_mball_select_count(const MetaBall *mb)
{
int sel = 0;
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index a2590171abd..eebe6efad78 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -55,6 +55,8 @@
/* experimental (faster) normal calculation */
// #define USE_ACCUM_NORMAL
+#define MBALL_ARRAY_LEN_INIT 4096
+
/* Data types */
typedef struct corner { /* corner of a cube */
@@ -448,7 +450,7 @@ static void make_face(PROCESS *process, int i1, int i2, int i3, int i4)
#endif
if (UNLIKELY(process->totindex == process->curindex)) {
- process->totindex += 4096;
+ process->totindex = process->totindex ? (process->totindex * 2) : MBALL_ARRAY_LEN_INIT;
process->indices = MEM_reallocN(process->indices, sizeof(int[4]) * process->totindex);
}
@@ -946,8 +948,8 @@ static int getedge(EDGELIST *table[], int i1, int j1, int k1, int i2, int j2, in
*/
static void addtovertices(PROCESS *process, const float v[3], const float no[3])
{
- if (process->curvertex == process->totvertex) {
- process->totvertex += 4096;
+ if (UNLIKELY(process->curvertex == process->totvertex)) {
+ process->totvertex = process->totvertex ? process->totvertex * 2 : MBALL_ARRAY_LEN_INIT;
process->co = MEM_reallocN(process->co, process->totvertex * sizeof(float[3]));
process->no = MEM_reallocN(process->no, process->totvertex * sizeof(float[3]));
}
@@ -1447,6 +1449,16 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa
/* add resulting surface to displist */
if (process.curindex) {
+
+ /* Avoid over-allocation since this is stored in the displist. */
+ if (process.curindex != process.totindex) {
+ process.indices = MEM_reallocN(process.indices, sizeof(int[4]) * process.curindex);
+ }
+ if (process.curvertex != process.totvertex) {
+ process.co = MEM_reallocN(process.co, process.curvertex * sizeof(float[3]));
+ process.no = MEM_reallocN(process.no, process.curvertex * sizeof(float[3]));
+ }
+
dl = MEM_callocN(sizeof(DispList), "mballdisp");
BLI_addtail(dispbase, dl);
dl->type = DL_INDEX4;
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.cc
index ed3766ad6a3..73fe279552d 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -38,16 +38,20 @@
#include "BLI_endian_switch.h"
#include "BLI_ghash.h"
#include "BLI_hash.h"
+#include "BLI_index_range.hh"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_memarena.h"
#include "BLI_string.h"
+#include "BLI_task.hh"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
#include "BKE_anim_data.h"
+#include "BKE_bpath.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
@@ -88,7 +92,11 @@ static void mesh_init_data(ID *id)
CustomData_reset(&mesh->pdata);
CustomData_reset(&mesh->ldata);
- BKE_mesh_runtime_reset(mesh);
+ BKE_mesh_runtime_init_data(mesh);
+
+ /* A newly created mesh does not have normals, so tag them dirty. This will be cleared
+ * by #BKE_mesh_vertex_normals_clear_dirty or #BKE_mesh_poly_normals_ensure. */
+ BKE_mesh_normals_tag_dirty(mesh);
mesh->face_sets_color_seed = BLI_hash_int(PIL_check_seconds_timer_i() & UINT_MAX);
}
@@ -124,7 +132,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
CustomData_MeshMasks_update(&mask, &CD_MASK_DERIVEDMESH);
}
- mesh_dst->mat = MEM_dupallocN(mesh_src->mat);
+ mesh_dst->mat = (Material **)MEM_dupallocN(mesh_src->mat);
BKE_defgroup_copy_list(&mesh_dst->vertex_group_names, &mesh_src->vertex_group_names);
@@ -142,9 +150,18 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
BKE_mesh_update_customdata_pointers(mesh_dst, do_tessface);
- mesh_dst->edit_mesh = NULL;
+ mesh_dst->cd_flag = mesh_src->cd_flag;
+
+ mesh_dst->edit_mesh = nullptr;
- mesh_dst->mselect = MEM_dupallocN(mesh_dst->mselect);
+ mesh_dst->mselect = (MSelect *)MEM_dupallocN(mesh_dst->mselect);
+
+ /* Set normal layers dirty, since they aren't included in CD_MASK_MESH and are therefore not
+ * copied to the destination mesh. Alternatively normal layers could be copied if they aren't
+ * dirty, avoiding recomputation in some cases. However, a copied mesh is often changed anyway,
+ * so that idea is not clearly better. With proper reference counting, all custom data layers
+ * could be copied as the cost would be much lower. */
+ BKE_mesh_normals_tag_dirty(mesh_dst);
/* TODO: Do we want to add flag to prevent this? */
if (mesh_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
@@ -152,6 +169,21 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
/* XXX This is not nice, we need to make BKE_id_copy_ex fully re-entrant... */
mesh_dst->key->from = &mesh_dst->id;
}
+
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh_dst);
+}
+
+void BKE_mesh_free_editmesh(struct Mesh *mesh)
+{
+ if (mesh->edit_mesh == nullptr) {
+ return;
+ }
+
+ if (mesh->edit_mesh->is_shallow_copy == false) {
+ BKE_editmesh_free_data(mesh->edit_mesh);
+ }
+ MEM_freeN(mesh->edit_mesh);
+ mesh->edit_mesh = nullptr;
}
static void mesh_free_data(ID *id)
@@ -160,15 +192,9 @@ static void mesh_free_data(ID *id)
BLI_freelistN(&mesh->vertex_group_names);
- if (mesh->edit_mesh) {
- if (mesh->edit_mesh->is_shallow_copy == false) {
- BKE_editmesh_free_data(mesh->edit_mesh);
- }
- MEM_freeN(mesh->edit_mesh);
- mesh->edit_mesh = NULL;
- }
+ BKE_mesh_free_editmesh(mesh);
- BKE_mesh_runtime_clear_cache(mesh);
+ BKE_mesh_runtime_free_data(mesh);
mesh_clear_geometry(mesh);
MEM_SAFE_FREE(mesh->mat);
}
@@ -176,10 +202,18 @@ static void mesh_free_data(ID *id)
static void mesh_foreach_id(ID *id, LibraryForeachIDData *data)
{
Mesh *mesh = (Mesh *)id;
- BKE_LIB_FOREACHID_PROCESS(data, mesh->texcomesh, IDWALK_CB_NEVER_SELF);
- BKE_LIB_FOREACHID_PROCESS(data, mesh->key, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mesh->texcomesh, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mesh->key, IDWALK_CB_USER);
for (int i = 0; i < mesh->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, mesh->mat[i], IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mesh->mat[i], IDWALK_CB_USER);
+ }
+}
+
+static void mesh_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Mesh *me = (Mesh *)id;
+ if (me->ldata.external) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, me->ldata.external->filename);
}
}
@@ -188,14 +222,14 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
Mesh *mesh = (Mesh *)id;
const bool is_undo = BLO_write_is_undo(writer);
- CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *vlayers = nullptr, vlayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *elayers = nullptr, elayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *flayers = nullptr, flayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *llayers = nullptr, llayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE];
/* cache only - don't write */
- mesh->mface = NULL;
+ mesh->mface = nullptr;
mesh->totface = 0;
memset(&mesh->fdata, 0, sizeof(mesh->fdata));
memset(&mesh->runtime, 0, sizeof(mesh->runtime));
@@ -203,22 +237,22 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
/* Do not store actual geometry data in case this is a library override ID. */
if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) {
- mesh->mvert = NULL;
+ mesh->mvert = nullptr;
mesh->totvert = 0;
memset(&mesh->vdata, 0, sizeof(mesh->vdata));
vlayers = vlayers_buff;
- mesh->medge = NULL;
+ mesh->medge = nullptr;
mesh->totedge = 0;
memset(&mesh->edata, 0, sizeof(mesh->edata));
elayers = elayers_buff;
- mesh->mloop = NULL;
+ mesh->mloop = nullptr;
mesh->totloop = 0;
memset(&mesh->ldata, 0, sizeof(mesh->ldata));
llayers = llayers_buff;
- mesh->mpoly = NULL;
+ mesh->mpoly = nullptr;
mesh->totpoly = 0;
memset(&mesh->pdata, 0, sizeof(mesh->pdata));
players = players_buff;
@@ -307,11 +341,13 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
CustomData_blend_read(reader, &mesh->pdata, mesh->totpoly);
mesh->texflag &= ~ME_AUTOSPACE_EVALUATED;
- mesh->edit_mesh = NULL;
- BKE_mesh_runtime_reset(mesh);
+ mesh->edit_mesh = nullptr;
+
+ memset(&mesh->runtime, 0, sizeof(mesh->runtime));
+ BKE_mesh_runtime_init_data(mesh);
/* happens with old files */
- if (mesh->mselect == NULL) {
+ if (mesh->mselect == nullptr) {
mesh->totselect = 0;
}
@@ -321,6 +357,10 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
BLI_endian_switch_uint32_array(tf->col, 4);
}
}
+
+ /* We don't expect to load normals from files, since they are derived data. */
+ BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
}
static void mesh_blend_read_lib(BlendLibReader *reader, ID *id)
@@ -353,31 +393,33 @@ static void mesh_read_expand(BlendExpander *expander, ID *id)
}
IDTypeInfo IDType_ID_ME = {
- .id_code = ID_ME,
- .id_filter = FILTER_ID_ME,
- .main_listbase_index = INDEX_ID_ME,
- .struct_size = sizeof(Mesh),
- .name = "Mesh",
- .name_plural = "meshes",
- .translation_context = BLT_I18NCONTEXT_ID_MESH,
- .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
-
- .init_data = mesh_init_data,
- .copy_data = mesh_copy_data,
- .free_data = mesh_free_data,
- .make_local = NULL,
- .foreach_id = mesh_foreach_id,
- .foreach_cache = NULL,
- .owner_get = NULL,
-
- .blend_write = mesh_blend_write,
- .blend_read_data = mesh_blend_read_data,
- .blend_read_lib = mesh_blend_read_lib,
- .blend_read_expand = mesh_read_expand,
-
- .blend_read_undo_preserve = NULL,
-
- .lib_override_apply_post = NULL,
+ /* id_code */ ID_ME,
+ /* id_filter */ FILTER_ID_ME,
+ /* main_listbase_index */ INDEX_ID_ME,
+ /* struct_size */ sizeof(Mesh),
+ /* name */ "Mesh",
+ /* name_plural */ "meshes",
+ /* translation_context */ BLT_I18NCONTEXT_ID_MESH,
+ /* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
+
+ /* init_data */ mesh_init_data,
+ /* copy_data */ mesh_copy_data,
+ /* free_data */ mesh_free_data,
+ /* make_local */ nullptr,
+ /* foreach_id */ mesh_foreach_id,
+ /* foreach_cache */ nullptr,
+ /* foreach_path */ mesh_foreach_path,
+ /* owner_get */ nullptr,
+
+ /* blend_write */ mesh_blend_write,
+ /* blend_read_data */ mesh_blend_read_data,
+ /* blend_read_lib */ mesh_blend_read_lib,
+ /* blend_read_expand */ mesh_read_expand,
+
+ /* blend_read_undo_preserve */ nullptr,
+
+ /* lib_override_apply_post */ nullptr,
};
enum {
@@ -439,13 +481,15 @@ static int customdata_compare(
const uint64_t cd_mask_all_attr = CD_MASK_PROP_ALL | cd_mask_non_generic;
for (int i = 0; i < c1->totlayer; i++) {
- if (CD_TYPE_AS_MASK(c1->layers[i].type) & cd_mask_all_attr) {
+ l1 = &c1->layers[i];
+ if ((CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr) && l1->anonymous_id == nullptr) {
layer_count1++;
}
}
for (int i = 0; i < c2->totlayer; i++) {
- if (CD_TYPE_AS_MASK(c2->layers[i].type) & cd_mask_all_attr) {
+ l2 = &c2->layers[i];
+ if ((CD_TYPE_AS_MASK(l2->type) & cd_mask_all_attr) && l2->anonymous_id == nullptr) {
layer_count2++;
}
}
@@ -461,7 +505,8 @@ static int customdata_compare(
l1 = c1->layers + i1;
for (int i2 = 0; i2 < c2->totlayer; i2++) {
l2 = c2->layers + i2;
- if (l1->type != l2->type || !STREQ(l1->name, l2->name)) {
+ if (l1->type != l2->type || !STREQ(l1->name, l2->name) || l1->anonymous_id != nullptr ||
+ l2->anonymous_id != nullptr) {
continue;
}
/* At this point `l1` and `l2` have the same name and type, so they should be compared. */
@@ -469,8 +514,8 @@ static int customdata_compare(
switch (l1->type) {
case CD_MVERT: {
- MVert *v1 = l1->data;
- MVert *v2 = l2->data;
+ MVert *v1 = (MVert *)l1->data;
+ MVert *v2 = (MVert *)l2->data;
int vtot = m1->totvert;
for (j = 0; j < vtot; j++, v1++, v2++) {
@@ -486,8 +531,8 @@ static int customdata_compare(
/* We're order-agnostic for edges here. */
case CD_MEDGE: {
- MEdge *e1 = l1->data;
- MEdge *e2 = l2->data;
+ MEdge *e1 = (MEdge *)l1->data;
+ MEdge *e2 = (MEdge *)l2->data;
int etot = m1->totedge;
EdgeHash *eh = BLI_edgehash_new_ex(__func__, etot);
@@ -500,12 +545,12 @@ static int customdata_compare(
return MESHCMP_EDGEUNKNOWN;
}
}
- BLI_edgehash_free(eh, NULL);
+ BLI_edgehash_free(eh, nullptr);
break;
}
case CD_MPOLY: {
- MPoly *p1 = l1->data;
- MPoly *p2 = l2->data;
+ MPoly *p1 = (MPoly *)l1->data;
+ MPoly *p2 = (MPoly *)l2->data;
int ptot = m1->totpoly;
for (j = 0; j < ptot; j++, p1++, p2++) {
@@ -528,8 +573,8 @@ static int customdata_compare(
break;
}
case CD_MLOOP: {
- MLoop *lp1 = l1->data;
- MLoop *lp2 = l2->data;
+ MLoop *lp1 = (MLoop *)l1->data;
+ MLoop *lp2 = (MLoop *)l2->data;
int ltot = m1->totloop;
for (j = 0; j < ltot; j++, lp1++, lp2++) {
@@ -540,8 +585,8 @@ static int customdata_compare(
break;
}
case CD_MLOOPUV: {
- MLoopUV *lp1 = l1->data;
- MLoopUV *lp2 = l2->data;
+ MLoopUV *lp1 = (MLoopUV *)l1->data;
+ MLoopUV *lp2 = (MLoopUV *)l2->data;
int ltot = m1->totloop;
for (j = 0; j < ltot; j++, lp1++, lp2++) {
@@ -552,8 +597,8 @@ static int customdata_compare(
break;
}
case CD_MLOOPCOL: {
- MLoopCol *lp1 = l1->data;
- MLoopCol *lp2 = l2->data;
+ MLoopCol *lp1 = (MLoopCol *)l1->data;
+ MLoopCol *lp2 = (MLoopCol *)l2->data;
int ltot = m1->totloop;
for (j = 0; j < ltot; j++, lp1++, lp2++) {
@@ -564,8 +609,8 @@ static int customdata_compare(
break;
}
case CD_MDEFORMVERT: {
- MDeformVert *dv1 = l1->data;
- MDeformVert *dv2 = l2->data;
+ MDeformVert *dv1 = (MDeformVert *)l1->data;
+ MDeformVert *dv2 = (MDeformVert *)l2->data;
int dvtot = m1->totvert;
for (j = 0; j < dvtot; j++, dv1++, dv2++) {
@@ -588,8 +633,8 @@ static int customdata_compare(
break;
}
case CD_PROP_FLOAT: {
- const float *l1_data = l1->data;
- const float *l2_data = l2->data;
+ const float *l1_data = (float *)l1->data;
+ const float *l2_data = (float *)l2->data;
for (int i = 0; i < total_length; i++) {
if (compare_threshold_relative(l1_data[i], l2_data[i], thresh)) {
@@ -599,8 +644,8 @@ static int customdata_compare(
break;
}
case CD_PROP_FLOAT2: {
- const float(*l1_data)[2] = l1->data;
- const float(*l2_data)[2] = l2->data;
+ const float(*l1_data)[2] = (float(*)[2])l1->data;
+ const float(*l2_data)[2] = (float(*)[2])l2->data;
for (int i = 0; i < total_length; i++) {
if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) {
@@ -613,8 +658,8 @@ static int customdata_compare(
break;
}
case CD_PROP_FLOAT3: {
- const float(*l1_data)[3] = l1->data;
- const float(*l2_data)[3] = l2->data;
+ const float(*l1_data)[3] = (float(*)[3])l1->data;
+ const float(*l2_data)[3] = (float(*)[3])l2->data;
for (int i = 0; i < total_length; i++) {
if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) {
@@ -630,8 +675,8 @@ static int customdata_compare(
break;
}
case CD_PROP_INT32: {
- const int *l1_data = l1->data;
- const int *l2_data = l2->data;
+ const int *l1_data = (int *)l1->data;
+ const int *l2_data = (int *)l2->data;
for (int i = 0; i < total_length; i++) {
if (l1_data[i] != l2_data[i]) {
@@ -641,8 +686,8 @@ static int customdata_compare(
break;
}
case CD_PROP_BOOL: {
- const bool *l1_data = l1->data;
- const bool *l2_data = l2->data;
+ const bool *l1_data = (bool *)l1->data;
+ const bool *l2_data = (bool *)l2->data;
for (int i = 0; i < total_length; i++) {
if (l1_data[i] != l2_data[i]) {
@@ -652,8 +697,8 @@ static int customdata_compare(
break;
}
case CD_PROP_COLOR: {
- const MPropCol *l1_data = l1->data;
- const MPropCol *l2_data = l2->data;
+ const MPropCol *l1_data = (MPropCol *)l1->data;
+ const MPropCol *l2_data = (MPropCol *)l2->data;
for (int i = 0; i < total_length; i++) {
for (j = 0; j < 4; j++) {
@@ -674,12 +719,6 @@ static int customdata_compare(
return 0;
}
-/**
- * Used for unit testing; compares two meshes, checking only
- * differences we care about. should be usable with leaf's
- * testing framework I get RNA work done, will use hackish
- * testing code for now.
- */
const char *BKE_mesh_cmp(Mesh *me1, Mesh *me2, float thresh)
{
int c;
@@ -720,7 +759,7 @@ const char *BKE_mesh_cmp(Mesh *me1, Mesh *me2, float thresh)
return cmpcode_to_str(c);
}
- return NULL;
+ return nullptr;
}
static void mesh_ensure_tessellation_customdata(Mesh *me)
@@ -765,7 +804,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me)
void BKE_mesh_ensure_skin_customdata(Mesh *me)
{
- BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL;
+ BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr;
MVertSkin *vs;
if (bm) {
@@ -777,7 +816,7 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me)
/* Mark an arbitrary vertex as root */
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- vs = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN);
+ vs = (MVertSkin *)CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN);
vs->flag |= MVERT_SKIN_ROOT;
break;
}
@@ -785,7 +824,8 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me)
}
else {
if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) {
- vs = CustomData_add_layer(&me->vdata, CD_MVERT_SKIN, CD_DEFAULT, NULL, me->totvert);
+ vs = (MVertSkin *)CustomData_add_layer(
+ &me->vdata, CD_MVERT_SKIN, CD_DEFAULT, nullptr, me->totvert);
/* Mark an arbitrary vertex as root */
if (vs) {
@@ -797,7 +837,7 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me)
bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me)
{
- BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL;
+ BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr;
bool changed = false;
if (bm) {
if (!CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
@@ -807,7 +847,7 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me)
}
else {
if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
- CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly);
+ CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, nullptr, me->totpoly);
changed = true;
}
}
@@ -816,7 +856,7 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me)
bool BKE_mesh_clear_facemap_customdata(struct Mesh *me)
{
- BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL;
+ BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr;
bool changed = false;
if (bm) {
if (CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
@@ -834,12 +874,12 @@ bool BKE_mesh_clear_facemap_customdata(struct Mesh *me)
}
/**
- * This ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or
- * mloopcol and mcol) have the same relative active/render/clone/mask indices.
+ * This ensures grouped custom-data (e.g. #CD_MLOOPUV and #CD_MTFACE, or
+ * #CD_MLOOPCOL and #CD_MCOL) have the same relative active/render/clone/mask indices.
*
- * NOTE(campbell): that for undo mesh data we want to skip 'ensure_tess_cd' call since
- * we don't want to store memory for tessface when its only used for older
- * Versions of the mesh.
+ * NOTE(@campbellbarton): that for undo mesh data we want to skip 'ensure_tess_cd' call since
+ * we don't want to store memory for #MFace data when its only used for older
+ * versions of the mesh.
*/
static void mesh_update_linked_customdata(Mesh *me, const bool do_ensure_tess_cd)
{
@@ -854,20 +894,20 @@ void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd)
{
mesh_update_linked_customdata(me, do_ensure_tess_cd);
- me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
- me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
+ me->mvert = (MVert *)CustomData_get_layer(&me->vdata, CD_MVERT);
+ me->dvert = (MDeformVert *)CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
- me->medge = CustomData_get_layer(&me->edata, CD_MEDGE);
+ me->medge = (MEdge *)CustomData_get_layer(&me->edata, CD_MEDGE);
- me->mface = CustomData_get_layer(&me->fdata, CD_MFACE);
- me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL);
- me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE);
+ me->mface = (MFace *)CustomData_get_layer(&me->fdata, CD_MFACE);
+ me->mcol = (MCol *)CustomData_get_layer(&me->fdata, CD_MCOL);
+ me->mtface = (MTFace *)CustomData_get_layer(&me->fdata, CD_MTFACE);
- me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY);
- me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
+ me->mpoly = (MPoly *)CustomData_get_layer(&me->pdata, CD_MPOLY);
+ me->mloop = (MLoop *)CustomData_get_layer(&me->ldata, CD_MLOOP);
- me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
- me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
+ me->mloopcol = (MLoopCol *)CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
+ me->mloopuv = (MLoopUV *)CustomData_get_layer(&me->ldata, CD_MLOOPUV);
}
bool BKE_mesh_has_custom_loop_normals(Mesh *me)
@@ -879,10 +919,6 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me)
return CustomData_has_layer(&me->ldata, CD_CUSTOMLOOPNORMAL);
}
-/**
- * Free (or release) any data used by this mesh (does not free the mesh itself).
- * Only use for undo, in most cases `BKE_id_free(NULL, me)` should be used.
- */
void BKE_mesh_free_data_for_undo(Mesh *me)
{
mesh_free_data(&me->id);
@@ -937,15 +973,15 @@ static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata)
CustomData_reset(&mesh->fdata);
}
- mesh->mface = NULL;
- mesh->mtface = NULL;
- mesh->mcol = NULL;
+ mesh->mface = nullptr;
+ mesh->mtface = nullptr;
+ mesh->mcol = nullptr;
mesh->totface = 0;
}
Mesh *BKE_mesh_add(Main *bmain, const char *name)
{
- Mesh *me = BKE_id_new(bmain, ID_ME, name);
+ Mesh *me = (Mesh *)BKE_id_new(bmain, ID_ME, name);
return me;
}
@@ -954,28 +990,28 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name)
static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface)
{
if (!CustomData_get_layer(&mesh->vdata, CD_MVERT)) {
- CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
+ CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert);
}
if (!CustomData_get_layer(&mesh->edata, CD_MEDGE)) {
- CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
+ CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, nullptr, mesh->totedge);
}
if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP)) {
- CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
+ CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop);
}
if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY)) {
- CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
+ CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly);
}
if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE)) {
- CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, mesh->totface);
+ CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, nullptr, mesh->totface);
}
}
Mesh *BKE_mesh_new_nomain(
int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
{
- Mesh *mesh = BKE_libblock_alloc(
- NULL, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE);
+ Mesh *mesh = (Mesh *)BKE_libblock_alloc(
+ nullptr, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE);
BKE_libblock_init_empty(&mesh->id);
/* Don't use #CustomData_reset because we don't want to touch custom-data. */
@@ -997,10 +1033,6 @@ Mesh *BKE_mesh_new_nomain(
return mesh;
}
-/**
- * Copy user editable settings that we want to preserve
- * when a new mesh is based on an existing mesh.
- */
void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
{
/* Copy general settings. */
@@ -1023,12 +1055,6 @@ void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
me_dst->vertex_group_active_index = me_src->vertex_group_active_index;
}
-/**
- * A version of #BKE_mesh_copy_parameters that is intended for evaluated output
- * (the modifier stack for example).
- *
- * \warning User counts are not handled for ID's.
- */
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
{
/* User counts aren't handled, don't copy into a mesh from #G_MAIN. */
@@ -1036,15 +1062,17 @@ void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
BKE_mesh_copy_parameters(me_dst, me_src);
+ BKE_mesh_assert_normals_dirty_or_calculated(me_dst);
+
/* Copy vertex group names. */
BLI_assert(BLI_listbase_is_empty(&me_dst->vertex_group_names));
BKE_defgroup_copy_list(&me_dst->vertex_group_names, &me_src->vertex_group_names);
/* Copy materials. */
- if (me_dst->mat != NULL) {
+ if (me_dst->mat != nullptr) {
MEM_freeN(me_dst->mat);
}
- me_dst->mat = MEM_dupallocN(me_src->mat);
+ me_dst->mat = (Material **)MEM_dupallocN(me_src->mat);
me_dst->totcol = me_src->totcol;
}
@@ -1059,9 +1087,9 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
/* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */
const bool do_tessface = (tessface_len || ((me_src->totface != 0) && (me_src->totpoly == 0)));
- Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL);
+ Mesh *me_dst = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr);
- me_dst->mselect = MEM_dupallocN(me_src->mselect);
+ me_dst->mselect = (MSelect *)MEM_dupallocN(me_src->mselect);
me_dst->totvert = verts_len;
me_dst->totedge = edges_len;
@@ -1083,6 +1111,18 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
mesh_tessface_clear_intern(me_dst, false);
}
+ me_dst->runtime.cd_dirty_poly = me_src->runtime.cd_dirty_poly;
+ me_dst->runtime.cd_dirty_vert = me_src->runtime.cd_dirty_vert;
+
+ /* Ensure that when no normal layers exist, they are marked dirty, because
+ * normals might not have been included in the mask of copied layers. */
+ if (!CustomData_has_layer(&me_dst->vdata, CD_NORMAL)) {
+ me_dst->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
+ if (!CustomData_has_layer(&me_dst->pdata, CD_NORMAL)) {
+ me_dst->runtime.cd_dirty_poly |= CD_MASK_NORMAL;
+ }
+
/* The destination mesh should at least have valid primary CD layers,
* even in cases where the source mesh does not. */
mesh_ensure_cdlayers_primary(me_dst, do_tessface);
@@ -1105,7 +1145,7 @@ Mesh *BKE_mesh_new_nomain_from_template(const Mesh *me_src,
void BKE_mesh_eval_delete(struct Mesh *mesh_eval)
{
/* Evaluated mesh may point to edit mesh, but never owns it. */
- mesh_eval->edit_mesh = NULL;
+ mesh_eval->edit_mesh = nullptr;
mesh_free_data(&mesh_eval->id);
BKE_libblock_free_data(&mesh_eval->id, false);
MEM_freeN(mesh_eval);
@@ -1119,7 +1159,7 @@ Mesh *BKE_mesh_copy_for_eval(const Mesh *source, bool reference)
flags |= LIB_ID_COPY_CD_REFERENCE;
}
- Mesh *result = (Mesh *)BKE_id_copy_ex(NULL, &source->id, NULL, flags);
+ Mesh *result = (Mesh *)BKE_id_copy_ex(nullptr, &source->id, nullptr, flags);
return result;
}
@@ -1140,14 +1180,12 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me,
const bool add_key_index,
const struct BMeshCreateParams *params)
{
- return BKE_mesh_to_bmesh_ex(me,
- params,
- &(struct BMeshFromMeshParams){
- .calc_face_normal = false,
- .add_key_index = add_key_index,
- .use_shapekey = true,
- .active_shapekey = ob->shapenr,
- });
+ BMeshFromMeshParams bmesh_from_mesh_params{};
+ bmesh_from_mesh_params.calc_face_normal = false;
+ bmesh_from_mesh_params.add_key_index = add_key_index;
+ bmesh_from_mesh_params.use_shapekey = true;
+ bmesh_from_mesh_params.active_shapekey = ob->shapenr;
+ return BKE_mesh_to_bmesh_ex(me, params, &bmesh_from_mesh_params);
}
Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm,
@@ -1155,8 +1193,8 @@ Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm,
const Mesh *me_settings)
{
BLI_assert(params->calc_object_remap == false);
- Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
- BM_mesh_bm_to_me(NULL, bm, mesh, params);
+ Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr);
+ BM_mesh_bm_to_me(nullptr, bm, mesh, params);
BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
return mesh;
}
@@ -1165,7 +1203,7 @@ Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm,
const CustomData_MeshMasks *cd_mask_extra,
const Mesh *me_settings)
{
- Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
+ Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr);
BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra);
BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
return mesh;
@@ -1175,8 +1213,8 @@ BoundBox *BKE_mesh_boundbox_get(Object *ob)
{
/* This is Object-level data access,
* DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
- if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
- Mesh *me = ob->data;
+ if (ob->runtime.bb == nullptr || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
+ Mesh *me = (Mesh *)ob->data;
float min[3], max[3];
INIT_MINMAX(min, max);
@@ -1185,8 +1223,8 @@ BoundBox *BKE_mesh_boundbox_get(Object *ob)
max[0] = max[1] = max[2] = 1.0f;
}
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
+ if (ob->runtime.bb == nullptr) {
+ ob->runtime.bb = (BoundBox *)MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
@@ -1251,17 +1289,17 @@ void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_size[3])
}
}
-void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_size)
+void BKE_mesh_texspace_get_reference(Mesh *me, char **r_texflag, float **r_loc, float **r_size)
{
BKE_mesh_texspace_ensure(me);
- if (r_texflag != NULL) {
+ if (r_texflag != nullptr) {
*r_texflag = &me->texflag;
}
- if (r_loc != NULL) {
+ if (r_loc != nullptr) {
*r_loc = me->loc;
}
- if (r_size != NULL) {
+ if (r_size != nullptr) {
*r_size = me->size;
}
}
@@ -1269,7 +1307,7 @@ void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc,
void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob)
{
float *texloc, *texsize;
- short *texflag;
+ char *texflag;
if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize)) {
me->texflag = *texflag;
@@ -1280,11 +1318,11 @@ void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob)
float (*BKE_mesh_orco_verts_get(Object *ob))[3]
{
- Mesh *me = ob->data;
+ Mesh *me = (Mesh *)ob->data;
Mesh *tme = me->texcomesh ? me->texcomesh : me;
/* Get appropriate vertex coordinates */
- float(*vcos)[3] = MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh");
+ float(*vcos)[3] = (float(*)[3])MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh");
MVert *mvert = tme->mvert;
int totvert = min_ii(tme->totvert, me->totvert);
@@ -1317,10 +1355,18 @@ void BKE_mesh_orco_verts_transform(Mesh *me, float (*orco)[3], int totvert, int
}
}
-/**
- * Rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0.
- * this is necessary to make the if #MFace.v4 check for quads work.
- */
+void BKE_mesh_orco_ensure(Object *ob, Mesh *mesh)
+{
+ if (CustomData_has_layer(&mesh->vdata, CD_ORCO)) {
+ return;
+ }
+
+ /* Orcos are stored in normalized 0..1 range by convention. */
+ float(*orcodata)[3] = BKE_mesh_orco_verts_get(ob);
+ BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false);
+ CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, orcodata, mesh->totvert);
+}
+
int BKE_mesh_mface_index_validate(MFace *mface, CustomData *fdata, int mfindex, int nr)
{
/* first test if the face is legal */
@@ -1391,28 +1437,28 @@ int BKE_mesh_mface_index_validate(MFace *mface, CustomData *fdata, int mfindex,
Mesh *BKE_mesh_from_object(Object *ob)
{
- if (ob == NULL) {
- return NULL;
+ if (ob == nullptr) {
+ return nullptr;
}
if (ob->type == OB_MESH) {
- return ob->data;
+ return (Mesh *)ob->data;
}
- return NULL;
+ return nullptr;
}
void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me)
{
- Mesh *old = NULL;
+ Mesh *old = nullptr;
- if (ob == NULL) {
+ if (ob == nullptr) {
return;
}
multires_force_sculpt_rebuild(ob);
if (ob->type == OB_MESH) {
- old = ob->data;
+ old = (Mesh *)ob->data;
if (old) {
id_us_min(&old->id);
}
@@ -1524,10 +1570,6 @@ void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth)
}
}
-/**
- * Find the index of the loop in 'poly' which references vertex,
- * returns -1 if not found
- */
int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, uint vert)
{
for (int j = 0; j < poly->totloop; j++, loopstart++) {
@@ -1539,11 +1581,6 @@ int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, uint ver
return -1;
}
-/**
- * Fill \a r_adj with the loop indices in \a poly adjacent to the
- * vertex. Returns the index of the loop matching vertex, or -1 if the
- * vertex is not in \a poly
- */
int poly_get_adj_loops_from_vert(const MPoly *poly, const MLoop *mloop, uint vert, uint r_adj[2])
{
int corner = poly_find_loop_from_vert(poly, &mloop[poly->loopstart], vert);
@@ -1557,10 +1594,6 @@ int poly_get_adj_loops_from_vert(const MPoly *poly, const MLoop *mloop, uint ver
return corner;
}
-/**
- * Return the index of the edge vert that is not equal to \a v. If
- * neither edge vertex is equal to \a v, returns -1.
- */
int BKE_mesh_edge_other_vert(const MEdge *e, int v)
{
if (e->v1 == v) {
@@ -1573,9 +1606,6 @@ int BKE_mesh_edge_other_vert(const MEdge *e, int v)
return -1;
}
-/**
- * Sets each output array element to the edge index if it is a real edge, or -1.
- */
void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri, int r_edges[3])
{
for (int i = 2, i_next = 0; i_next < 3; i = i_next++) {
@@ -1588,23 +1618,45 @@ void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri,
}
}
-/* basic vertex data functions */
bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3])
{
- int i = me->totvert;
- MVert *mvert;
- for (mvert = me->mvert; i--; mvert++) {
- minmax_v3v3_v3(r_min, r_max, mvert->co);
+ using namespace blender;
+ if (me->totvert == 0) {
+ return false;
}
- return (me->totvert != 0);
+ struct Result {
+ float3 min;
+ float3 max;
+ };
+
+ const Result minmax = threading::parallel_reduce(
+ IndexRange(me->totvert),
+ 1024,
+ Result{float3(FLT_MAX), float3(-FLT_MAX)},
+ [&](IndexRange range, const Result &init) {
+ Result result = init;
+ for (const int i : range) {
+ math::min_max(float3(me->mvert[i].co), result.min, result.max);
+ }
+ return result;
+ },
+ [](const Result &a, const Result &b) {
+ return Result{math::min(a.min, b.min), math::max(a.max, b.max)};
+ });
+
+ copy_v3_v3(r_min, math::min(minmax.min, float3(r_min)));
+ copy_v3_v3(r_max, math::max(minmax.max, float3(r_max)));
+
+ return true;
}
void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys)
{
int i;
- MVert *mvert = CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert);
- float(*lnors)[3] = CustomData_duplicate_referenced_layer(&me->ldata, CD_NORMAL, me->totloop);
+ MVert *mvert = (MVert *)CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert);
+ float(*lnors)[3] = (float(*)[3])CustomData_duplicate_referenced_layer(
+ &me->ldata, CD_NORMAL, me->totloop);
/* If the referenced layer has been re-allocated need to update pointers stored in the mesh. */
BKE_mesh_update_customdata_pointers(me, false);
@@ -1614,9 +1666,8 @@ void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys)
}
if (do_keys && me->key) {
- KeyBlock *kb;
- for (kb = me->key->block.first; kb; kb = kb->next) {
- float *fp = kb->data;
+ LISTBASE_FOREACH (KeyBlock *, kb, &me->key->block) {
+ float *fp = (float *)kb->data;
for (i = kb->totelem; i--; fp += 3) {
mul_m4_v3(mat, fp);
}
@@ -1649,9 +1700,8 @@ void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys)
}
if (do_keys && me->key) {
- KeyBlock *kb;
- for (kb = me->key->block.first; kb; kb = kb->next) {
- float *fp = kb->data;
+ LISTBASE_FOREACH (KeyBlock *, kb, &me->key->block) {
+ float *fp = (float *)kb->data;
for (i = kb->totelem; i--; fp += 3) {
add_v3_v3(fp, offset);
}
@@ -1723,7 +1773,8 @@ void BKE_mesh_mselect_validate(Mesh *me)
}
mselect_src = me->mselect;
- mselect_dst = MEM_malloc_arrayN((me->totselect), sizeof(MSelect), "Mesh selection history");
+ mselect_dst = (MSelect *)MEM_malloc_arrayN(
+ (me->totselect), sizeof(MSelect), "Mesh selection history");
for (i_src = 0, i_dst = 0; i_src < me->totselect; i_src++) {
int index = mselect_src[i_src].index;
@@ -1760,19 +1811,16 @@ void BKE_mesh_mselect_validate(Mesh *me)
if (i_dst == 0) {
MEM_freeN(mselect_dst);
- mselect_dst = NULL;
+ mselect_dst = nullptr;
}
else if (i_dst != me->totselect) {
- mselect_dst = MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst);
+ mselect_dst = (MSelect *)MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst);
}
me->totselect = i_dst;
me->mselect = mselect_dst;
}
-/**
- * Return the index within me->mselect, or -1
- */
int BKE_mesh_mselect_find(Mesh *me, int index, int type)
{
BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
@@ -1786,9 +1834,6 @@ int BKE_mesh_mselect_find(Mesh *me, int index, int type)
return -1;
}
-/**
- * Return The index of the active element.
- */
int BKE_mesh_mselect_active_get(Mesh *me, int type)
{
BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
@@ -1807,7 +1852,7 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type)
if (msel_index == -1) {
/* add to the end */
- me->mselect = MEM_reallocN(me->mselect, sizeof(MSelect) * (me->totselect + 1));
+ me->mselect = (MSelect *)MEM_reallocN(me->mselect, sizeof(MSelect) * (me->totselect + 1));
me->mselect[me->totselect].index = index;
me->mselect[me->totselect].type = type;
me->totselect++;
@@ -1843,7 +1888,7 @@ void BKE_mesh_vert_coords_get(const Mesh *mesh, float (*vert_coords)[3])
float (*BKE_mesh_vert_coords_alloc(const Mesh *mesh, int *r_vert_len))[3]
{
- float(*vert_coords)[3] = MEM_mallocN(sizeof(float[3]) * mesh->totvert, __func__);
+ float(*vert_coords)[3] = (float(*)[3])MEM_mallocN(sizeof(float[3]) * mesh->totvert, __func__);
BKE_mesh_vert_coords_get(mesh, vert_coords);
if (r_vert_len) {
*r_vert_len = mesh->totvert;
@@ -1854,7 +1899,8 @@ float (*BKE_mesh_vert_coords_alloc(const Mesh *mesh, int *r_vert_len))[3]
void BKE_mesh_vert_coords_apply(Mesh *mesh, const float (*vert_coords)[3])
{
/* This will just return the pointer if it wasn't a referenced layer. */
- MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
+ MVert *mv = (MVert *)CustomData_duplicate_referenced_layer(
+ &mesh->vdata, CD_MVERT, mesh->totvert);
mesh->mvert = mv;
for (int i = 0; i < mesh->totvert; i++, mv++) {
copy_v3_v3(mv->co, vert_coords[i]);
@@ -1867,7 +1913,8 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh,
const float mat[4][4])
{
/* This will just return the pointer if it wasn't a referenced layer. */
- MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
+ MVert *mv = (MVert *)CustomData_duplicate_referenced_layer(
+ &mesh->vdata, CD_MVERT, mesh->totvert);
mesh->mvert = mv;
for (int i = 0; i < mesh->totvert; i++, mv++) {
mul_v3_m4v3(mv->co, mat, vert_coords[i]);
@@ -1875,69 +1922,33 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh,
BKE_mesh_normals_tag_dirty(mesh);
}
-void BKE_mesh_vert_normals_apply(Mesh *mesh, const short (*vert_normals)[3])
-{
- /* This will just return the pointer if it wasn't a referenced layer. */
- MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
- mesh->mvert = mv;
- for (int i = 0; i < mesh->totvert; i++, mv++) {
- copy_v3_v3_short(mv->no, vert_normals[i]);
- }
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
-}
-
-/**
- * Compute 'split' (aka loop, or per face corner's) normals.
- *
- * \param r_lnors_spacearr: Allows to get computed loop normal space array.
- * That data, among other things, contains 'smooth fan' info, useful e.g.
- * to split geometry along sharp edges...
- */
void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr)
{
float(*r_loopnors)[3];
- float(*polynors)[3];
- short(*clnors)[2] = NULL;
- bool free_polynors = false;
+ short(*clnors)[2] = nullptr;
/* Note that we enforce computing clnors when the clnor space array is requested by caller here.
- * However, we obviously only use the autosmooth angle threshold
- * only in case autosmooth is enabled. */
- const bool use_split_normals = (r_lnors_spacearr != NULL) || ((mesh->flag & ME_AUTOSMOOTH) != 0);
+ * However, we obviously only use the auto-smooth angle threshold
+ * only in case auto-smooth is enabled. */
+ const bool use_split_normals = (r_lnors_spacearr != nullptr) ||
+ ((mesh->flag & ME_AUTOSMOOTH) != 0);
const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI;
if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
- r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+ r_loopnors = (float(*)[3])CustomData_get_layer(&mesh->ldata, CD_NORMAL);
memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop);
}
else {
- r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop);
+ r_loopnors = (float(*)[3])CustomData_add_layer(
+ &mesh->ldata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totloop);
CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
}
- /* may be NULL */
- clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
-
- if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
- /* This assume that layer is always up to date, not sure this is the case
- * (esp. in Edit mode?)... */
- polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- free_polynors = false;
- }
- else {
- polynors = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__);
- BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- polynors,
- NULL);
- free_polynors = true;
- }
+ /* may be nullptr */
+ clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
BKE_mesh_normals_loop_split(mesh->mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
mesh->totvert,
mesh->medge,
mesh->totedge,
@@ -1945,48 +1956,44 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
r_loopnors,
mesh->totloop,
mesh->mpoly,
- (const float(*)[3])polynors,
+ BKE_mesh_poly_normals_ensure(mesh),
mesh->totpoly,
use_split_normals,
split_angle,
r_lnors_spacearr,
clnors,
- NULL);
+ nullptr);
- if (free_polynors) {
- MEM_freeN(polynors);
- }
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
- mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL;
mesh->runtime.cd_dirty_loop &= ~CD_MASK_NORMAL;
}
void BKE_mesh_calc_normals_split(Mesh *mesh)
{
- BKE_mesh_calc_normals_split_ex(mesh, NULL);
+ BKE_mesh_calc_normals_split_ex(mesh, nullptr);
}
/* Split faces helper functions. */
-typedef struct SplitFaceNewVert {
+struct SplitFaceNewVert {
struct SplitFaceNewVert *next;
int new_index;
int orig_index;
float *vnor;
-} SplitFaceNewVert;
+};
-typedef struct SplitFaceNewEdge {
+struct SplitFaceNewEdge {
struct SplitFaceNewEdge *next;
int new_index;
int orig_index;
int v1;
int v2;
-} SplitFaceNewEdge;
+};
/* Detect needed new vertices, and update accordingly loops' vertex indices.
* WARNING! Leaves mesh in invalid state. */
-static int split_faces_prepare_new_verts(const Mesh *mesh,
+static int split_faces_prepare_new_verts(Mesh *mesh,
MLoopNorSpaceArray *lnors_spacearr,
SplitFaceNewVert **new_verts,
MemArena *memarena)
@@ -1994,12 +2001,13 @@ static int split_faces_prepare_new_verts(const Mesh *mesh,
/* This is now mandatory, trying to do the job in simple way without that data is doomed to fail,
* even when only dealing with smooth/flat faces one can find cases that no simple algorithm
* can handle properly. */
- BLI_assert(lnors_spacearr != NULL);
+ BLI_assert(lnors_spacearr != nullptr);
const int loops_len = mesh->totloop;
int verts_len = mesh->totvert;
- MVert *mvert = mesh->mvert;
MLoop *mloop = mesh->mloop;
+ BKE_mesh_vertex_normals_ensure(mesh);
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh);
BLI_bitmap *verts_used = BLI_BITMAP_NEW(verts_len, __func__);
BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_len, __func__);
@@ -2043,11 +2051,12 @@ static int split_faces_prepare_new_verts(const Mesh *mesh,
* vnor should always be defined to 'automatic normal' value computed from its polys,
* not some custom normal.
* Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
- normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor);
+ copy_v3_v3(vert_normals[vert_idx], (*lnor_space)->vec_lnor);
}
else {
/* Add new vert to list. */
- SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert));
+ SplitFaceNewVert *new_vert = (SplitFaceNewVert *)BLI_memarena_alloc(memarena,
+ sizeof(*new_vert));
new_vert->orig_index = vert_idx;
new_vert->new_index = new_vert_idx;
new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */
@@ -2094,7 +2103,8 @@ static int split_faces_prepare_new_edges(const Mesh *mesh,
*eval = POINTER_FROM_INT(new_edge_idx);
ml_prev->e = new_edge_idx;
- SplitFaceNewEdge *new_edge = BLI_memarena_alloc(memarena, sizeof(*new_edge));
+ SplitFaceNewEdge *new_edge = (SplitFaceNewEdge *)BLI_memarena_alloc(memarena,
+ sizeof(*new_edge));
new_edge->orig_index = edge_idx;
new_edge->new_index = new_edge_idx;
new_edge->v1 = ml_prev->v;
@@ -2120,7 +2130,7 @@ static int split_faces_prepare_new_edges(const Mesh *mesh,
}
MEM_freeN(edges_used);
- BLI_edgehash_free(edges_hash, NULL);
+ BLI_edgehash_free(edges_hash, nullptr);
return num_edges - mesh->totedge;
}
@@ -2132,6 +2142,7 @@ static void split_faces_split_new_verts(Mesh *mesh,
{
const int verts_len = mesh->totvert - num_new_verts;
MVert *mvert = mesh->mvert;
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh);
/* Remember new_verts is a single linklist, so its items are in reversed order... */
MVert *new_mv = &mvert[mesh->totvert - 1];
@@ -2140,9 +2151,10 @@ static void split_faces_split_new_verts(Mesh *mesh,
BLI_assert(new_verts->new_index != new_verts->orig_index);
CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1);
if (new_verts->vnor) {
- normal_float_to_short_v3(new_mv->no, new_verts->vnor);
+ copy_v3_v3(vert_normals[i], new_verts->vnor);
}
}
+ BKE_mesh_vertex_normals_clear_dirty(mesh);
}
/* Perform actual split of edges. */
@@ -2164,12 +2176,6 @@ static void split_faces_split_new_edges(Mesh *mesh,
}
}
-/* Split faces based on the edge angle and loop normals.
- * Matches behavior of face splitting in render engines.
- *
- * NOTE: Will leave CD_NORMAL loop data layer which is
- * used by render engines to set shading up.
- */
void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
{
const int num_polys = mesh->totpoly;
@@ -2179,14 +2185,14 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
}
BKE_mesh_tessface_clear(mesh);
- MLoopNorSpaceArray lnors_spacearr = {NULL};
+ MLoopNorSpaceArray lnors_spacearr = {nullptr};
/* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */
BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr);
/* Stealing memarena from loop normals space array. */
MemArena *memarena = lnors_spacearr.mem;
- SplitFaceNewVert *new_verts = NULL;
- SplitFaceNewEdge *new_edges = NULL;
+ SplitFaceNewVert *new_verts = nullptr;
+ SplitFaceNewEdge *new_edges = nullptr;
/* Ensure we own the layers, we need to do this before split_faces_prepare_new_verts as it will
* directly assign new indices to existing edges and loops. */
@@ -2236,6 +2242,7 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
/* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */
BKE_lnor_spacearr_free(&lnors_spacearr);
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
#ifdef VALIDATE_MESH
BKE_mesh_validate(mesh, true, true);
#endif
@@ -2250,10 +2257,10 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
/* We are here because something did change in the mesh. This means we can not trust the existing
* evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the
* evaluated mesh and let objects to re-create it with updated settings. */
- if (mesh->runtime.mesh_eval != NULL) {
- mesh->runtime.mesh_eval->edit_mesh = NULL;
- BKE_id_free(NULL, mesh->runtime.mesh_eval);
- mesh->runtime.mesh_eval = NULL;
+ if (mesh->runtime.mesh_eval != nullptr) {
+ mesh->runtime.mesh_eval->edit_mesh = nullptr;
+ BKE_id_free(nullptr, mesh->runtime.mesh_eval);
+ mesh->runtime.mesh_eval = nullptr;
}
if (DEG_is_active(depsgraph)) {
Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id);
diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
index 3086f117707..a4a5fe2be2e 100644
--- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
@@ -32,9 +32,9 @@
#include "BLI_alloca.h"
#include "BLI_array.hh"
-#include "BLI_float2.hh"
#include "BLI_float4x4.hh"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_mesh_boolean.hh"
#include "BLI_mesh_intersect.hh"
#include "BLI_span.hh"
@@ -807,16 +807,6 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
#endif // WITH_GMP
-/**
- * Do a mesh boolean operation directly on meshes (without going back and forth to BMesh).
- * \param meshes: An array of Mesh pointers.
- * \param obmats: An array of pointers to the obmat matrices that transform local
- * coordinates to global ones. It is allowed for the pointers to be null, meaning the
- * transformation is the identity.
- * \param material_remaps: An array of pointers to arrays of maps from material slot numbers in the
- * corresponding mesh to the material slot in the first mesh. It is OK for material_remaps or any
- * of its constituent arrays to be empty.
- */
Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Span<const float4x4 *> obmats,
const float4x4 &target_transform,
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index 59cdb6a2b27..7d5f156040d 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -32,6 +32,7 @@
#include "DNA_scene_types.h"
#include "BLI_edgehash.h"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -65,6 +66,8 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
+using blender::IndexRange;
+
/* Define for cases when you want extra validation of mesh
* after certain modifications.
*/
@@ -85,7 +88,6 @@ void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
MVert *mvert;
MLoop *mloop, *allloop;
MPoly *mpoly;
- const float *nors, *verts;
int a, *index;
dl = (DispList *)lb->first;
@@ -104,15 +106,8 @@ void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
me->totvert = dl->nr;
me->totpoly = dl->parts;
- a = dl->nr;
- nors = dl->nors;
- verts = dl->verts;
- while (a--) {
- copy_v3_v3(mvert->co, verts);
- normal_float_to_short_v3(mvert->no, nors);
- mvert++;
- nors += 3;
- verts += 3;
+ for (const int i : IndexRange(dl->nr)) {
+ copy_v3_v3(me->mvert[i].co, &dl->verts[3 * i]);
}
a = dl->parts;
@@ -139,7 +134,7 @@ void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
BKE_mesh_update_customdata_pointers(me, true);
- BKE_mesh_calc_normals(me);
+ BKE_mesh_normals_tag_dirty(me);
BKE_mesh_calc_edges(me, true, false);
}
@@ -454,10 +449,10 @@ static int mesh_nurbs_displist_to_mdata(const Curve *cu,
mloopuv->uv[1] = (v % dl->nr) / (float)orco_sizeu;
/* cyclic correction */
- if ((i == 1 || i == 2) && mloopuv->uv[0] == 0.0f) {
+ if ((ELEM(i, 1, 2)) && mloopuv->uv[0] == 0.0f) {
mloopuv->uv[0] = 1.0f;
}
- if ((i == 0 || i == 1) && mloopuv->uv[1] == 0.0f) {
+ if ((ELEM(i, 0, 1)) && mloopuv->uv[1] == 0.0f) {
mloopuv->uv[1] = 1.0f;
}
}
@@ -589,14 +584,14 @@ struct VertLink {
static void prependPolyLineVert(ListBase *lb, uint index)
{
- VertLink *vl = (VertLink *)MEM_callocN(sizeof(VertLink), "VertLink");
+ VertLink *vl = MEM_cnew<VertLink>("VertLink");
vl->index = index;
BLI_addhead(lb, vl);
}
static void appendPolyLineVert(ListBase *lb, uint index)
{
- VertLink *vl = (VertLink *)MEM_callocN(sizeof(VertLink), "VertLink");
+ VertLink *vl = MEM_cnew<VertLink>("VertLink");
vl->index = index;
BLI_addtail(lb, vl);
}
@@ -632,7 +627,7 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed
med = medge;
for (i = 0; i < medge_len; i++, med++) {
if (edge_users[i] == edge_users_test) {
- EdgeLink *edl = (EdgeLink *)MEM_callocN(sizeof(EdgeLink), "EdgeLink");
+ EdgeLink *edl = MEM_cnew<EdgeLink>("EdgeLink");
edl->edge = med;
BLI_addtail(&edges, edl);
@@ -719,7 +714,7 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed
VertLink *vl;
/* create new 'nurb' within the curve */
- nu = (Nurb *)MEM_callocN(sizeof(Nurb), "MeshNurb");
+ nu = MEM_cnew<Nurb>("MeshNurb");
nu->pntsu = totpoly;
nu->pntsv = 1;
@@ -901,6 +896,20 @@ static Object *object_for_curve_to_mesh_create(const Object *object)
return temp_object;
}
+static void object_for_curve_to_mesh_free(Object *temp_object)
+{
+ /* Clear edit mode pointers that were explicitly copied to the temporary curve. */
+ ID *final_object_data = static_cast<ID *>(temp_object->data);
+ if (GS(final_object_data->name) == ID_CU) {
+ Curve &curve = *reinterpret_cast<Curve *>(final_object_data);
+ curve.editfont = nullptr;
+ curve.editnurb = nullptr;
+ }
+
+ BKE_id_free(nullptr, temp_object->data);
+ BKE_id_free(nullptr, temp_object);
+}
+
/**
* Populate `object->runtime.curve_cache` which is then used to create the mesh.
*/
@@ -917,7 +926,7 @@ static void curve_to_mesh_eval_ensure(Object &object)
* will have no modifiers. */
Object bevel_object = {{nullptr}};
if (curve.bevobj != nullptr) {
- bevel_object = *curve.bevobj;
+ memcpy(&bevel_object, curve.bevobj, sizeof(bevel_object));
BLI_listbase_clear(&bevel_object.modifiers);
BKE_object_runtime_reset(&bevel_object);
curve.bevobj = &bevel_object;
@@ -926,7 +935,7 @@ static void curve_to_mesh_eval_ensure(Object &object)
/* Same thing for taper. */
Object taper_object = {{nullptr}};
if (curve.taperobj != nullptr) {
- taper_object = *curve.taperobj;
+ memcpy(&taper_object, curve.taperobj, sizeof(taper_object));
BLI_listbase_clear(&taper_object.modifiers);
BKE_object_runtime_reset(&taper_object);
curve.taperobj = &taper_object;
@@ -1003,8 +1012,7 @@ static Mesh *mesh_new_from_curve_type_object(const Object *object)
Mesh *mesh = mesh_new_from_evaluated_curve_type_object(temp_object);
- BKE_id_free(nullptr, temp_object->data);
- BKE_id_free(nullptr, temp_object);
+ object_for_curve_to_mesh_free(temp_object);
return mesh;
}
@@ -1065,7 +1073,8 @@ static Mesh *mesh_new_from_mesh_object_with_layers(Depsgraph *depsgraph,
return nullptr;
}
- Object object_for_eval = *object;
+ Object object_for_eval;
+ memcpy(&object_for_eval, object, sizeof(object_for_eval));
if (object_for_eval.runtime.data_orig != nullptr) {
object_for_eval.data = object_for_eval.runtime.data_orig;
}
@@ -1093,8 +1102,11 @@ static Mesh *mesh_new_from_mesh_object(Depsgraph *depsgraph,
Mesh *mesh_input = (Mesh *)object->data;
/* If we are in edit mode, use evaluated mesh from edit structure, matching to what
* viewport is using for visualization. */
- if (mesh_input->edit_mesh != nullptr && mesh_input->edit_mesh->mesh_eval_final) {
- mesh_input = mesh_input->edit_mesh->mesh_eval_final;
+ if (mesh_input->edit_mesh != nullptr) {
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
+ if (editmesh_eval_final != nullptr) {
+ mesh_input = editmesh_eval_final;
+ }
}
return mesh_new_from_mesh(object, mesh_input);
}
@@ -1281,6 +1293,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob_eval,
ModifierData *md_eval,
+ const bool use_virtual_modifiers,
const bool build_shapekey_layers)
{
Mesh *me = ob_eval->runtime.data_orig ? (Mesh *)ob_eval->runtime.data_orig :
@@ -1303,22 +1316,49 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
BKE_keyblock_convert_to_mesh(kb, me);
}
- if (mti->type == eModifierTypeType_OnlyDeform) {
- int numVerts;
- float(*deformedVerts)[3] = BKE_mesh_vert_coords_alloc(me, &numVerts);
+ Mesh *mesh_temp = (Mesh *)BKE_id_copy_ex(nullptr, &me->id, nullptr, LIB_ID_COPY_LOCALIZE);
+ int numVerts = 0;
+ float(*deformedVerts)[3] = nullptr;
+
+ if (use_virtual_modifiers) {
+ VirtualModifierData virtualModifierData;
+ for (ModifierData *md_eval_virt =
+ BKE_modifiers_get_virtual_modifierlist(ob_eval, &virtualModifierData);
+ md_eval_virt && (md_eval_virt != ob_eval->modifiers.first);
+ md_eval_virt = md_eval_virt->next) {
+ if (!BKE_modifier_is_enabled(scene, md_eval_virt, eModifierMode_Realtime)) {
+ continue;
+ }
+ /* All virtual modifiers are deform modifiers. */
+ const ModifierTypeInfo *mti_virt = BKE_modifier_get_info((ModifierType)md_eval_virt->type);
+ BLI_assert(mti_virt->type == eModifierTypeType_OnlyDeform);
+ if (mti_virt->type != eModifierTypeType_OnlyDeform) {
+ continue;
+ }
+
+ if (deformedVerts == nullptr) {
+ deformedVerts = BKE_mesh_vert_coords_alloc(me, &numVerts);
+ }
+ mti_virt->deformVerts(md_eval_virt, &mectx, mesh_temp, deformedVerts, numVerts);
+ }
+ }
- result = (Mesh *)BKE_id_copy_ex(nullptr, &me->id, nullptr, LIB_ID_COPY_LOCALIZE);
+ if (mti->type == eModifierTypeType_OnlyDeform) {
+ if (deformedVerts == nullptr) {
+ deformedVerts = BKE_mesh_vert_coords_alloc(me, &numVerts);
+ }
+ result = mesh_temp;
mti->deformVerts(md_eval, &mectx, result, deformedVerts, numVerts);
BKE_mesh_vert_coords_apply(result, deformedVerts);
if (build_shapekey_layers) {
add_shapekey_layers(result, me);
}
-
- MEM_freeN(deformedVerts);
}
else {
- Mesh *mesh_temp = (Mesh *)BKE_id_copy_ex(nullptr, &me->id, nullptr, LIB_ID_COPY_LOCALIZE);
+ if (deformedVerts != nullptr) {
+ BKE_mesh_vert_coords_apply(mesh_temp, deformedVerts);
+ }
if (build_shapekey_layers) {
add_shapekey_layers(mesh_temp, me);
@@ -1332,6 +1372,10 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
}
}
+ if (deformedVerts != nullptr) {
+ MEM_freeN(deformedVerts);
+ }
+
return result;
}
@@ -1408,7 +1452,8 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
/* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */
/* TODO(Sybren): the above claim came from 2.7x derived-mesh code (DM_to_mesh);
* check whether it is still true with Mesh */
- Mesh tmp = *mesh_dst;
+ Mesh tmp;
+ memcpy(&tmp, mesh_dst, sizeof(tmp));
int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
bool did_shapekeys = false;
eCDAllocType alloctype = CD_DUPLICATE;
@@ -1429,8 +1474,6 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
CustomData_reset(&tmp.ldata);
CustomData_reset(&tmp.pdata);
- BKE_mesh_ensure_normals(mesh_src);
-
totvert = tmp.totvert = mesh_src->totvert;
totedge = tmp.totedge = mesh_src->totedge;
totloop = tmp.totloop = mesh_src->totloop;
@@ -1444,6 +1487,18 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
tmp.cd_flag = mesh_src->cd_flag;
tmp.runtime.deformed_only = mesh_src->runtime.deformed_only;
+ tmp.runtime.cd_dirty_poly = mesh_src->runtime.cd_dirty_poly;
+ tmp.runtime.cd_dirty_vert = mesh_src->runtime.cd_dirty_vert;
+
+ /* Ensure that when no normal layers exist, they are marked dirty, because
+ * normals might not have been included in the mask of copied layers. */
+ if (!CustomData_has_layer(&tmp.vdata, CD_NORMAL)) {
+ tmp.runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
+ if (!CustomData_has_layer(&tmp.pdata, CD_NORMAL)) {
+ tmp.runtime.cd_dirty_poly |= CD_MASK_NORMAL;
+ }
+
if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) {
KeyBlock *kb;
int uid;
@@ -1567,6 +1622,8 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
}
BKE_id_free(nullptr, mesh_src);
}
+
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh_dst);
}
void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb)
diff --git a/source/blender/blenkernel/intern/mesh_debug.cc b/source/blender/blenkernel/intern/mesh_debug.cc
new file mode 100644
index 00000000000..017f96c2ece
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_debug.cc
@@ -0,0 +1,115 @@
+/*
+ * 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
+ *
+ * Evaluated mesh info printing function, to help track down differences output.
+ *
+ * Output from these functions can be evaluated as Python literals.
+ * See `bmesh_debug.c` for the equivalent #BMesh functionality.
+ */
+
+#ifndef NDEBUG
+
+# include <stdio.h>
+
+# include "MEM_guardedalloc.h"
+
+# include "DNA_mesh_types.h"
+# include "DNA_meshdata_types.h"
+# include "DNA_object_types.h"
+
+# include "BLI_utildefines.h"
+
+# include "BKE_customdata.h"
+
+# include "BKE_mesh.h"
+
+# include "BLI_dynstr.h"
+
+static void mesh_debug_info_from_cd_flag(const Mesh *me, DynStr *dynstr)
+{
+ BLI_dynstr_append(dynstr, "'cd_flag': {");
+ if (me->cd_flag & ME_CDFLAG_VERT_BWEIGHT) {
+ BLI_dynstr_append(dynstr, "'VERT_BWEIGHT', ");
+ }
+ if (me->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
+ BLI_dynstr_append(dynstr, "'EDGE_BWEIGHT', ");
+ }
+ if (me->cd_flag & ME_CDFLAG_EDGE_CREASE) {
+ BLI_dynstr_append(dynstr, "'EDGE_CREASE', ");
+ }
+ BLI_dynstr_append(dynstr, "},\n");
+}
+
+char *BKE_mesh_debug_info(const Mesh *me)
+{
+ DynStr *dynstr = BLI_dynstr_new();
+ char *ret;
+
+ const char *indent4 = " ";
+ const char *indent8 = " ";
+
+ BLI_dynstr_append(dynstr, "{\n");
+ BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)me);
+ BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", me->totvert);
+ BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", me->totedge);
+ BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me->totface);
+ BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me->totpoly);
+
+ BLI_dynstr_appendf(dynstr, " 'runtime.deformed_only': %d,\n", me->runtime.deformed_only);
+ BLI_dynstr_appendf(dynstr, " 'runtime.is_original': %d,\n", me->runtime.is_original);
+
+ BLI_dynstr_append(dynstr, " 'vert_layers': (\n");
+ CustomData_debug_info_from_layers(&me->vdata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'edge_layers': (\n");
+ CustomData_debug_info_from_layers(&me->edata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'loop_layers': (\n");
+ CustomData_debug_info_from_layers(&me->ldata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'poly_layers': (\n");
+ CustomData_debug_info_from_layers(&me->pdata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'tessface_layers': (\n");
+ CustomData_debug_info_from_layers(&me->fdata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, indent4);
+ mesh_debug_info_from_cd_flag(me, dynstr);
+
+ BLI_dynstr_append(dynstr, "}\n");
+
+ ret = BLI_dynstr_get_cstring(dynstr);
+ BLI_dynstr_free(dynstr);
+ return ret;
+}
+
+void BKE_mesh_debug_print(const Mesh *me)
+{
+ char *str = BKE_mesh_debug_info(me);
+ puts(str);
+ fflush(stdout);
+ MEM_freeN(str);
+}
+
+#endif /* NDEBUG */
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc
index 91fd022a316..5cc1b4e4860 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.cc
+++ b/source/blender/blenkernel/intern/mesh_evaluate.cc
@@ -191,7 +191,6 @@ void BKE_mesh_calc_poly_center(const MPoly *mpoly,
}
}
-/* NOTE: passing poly-normal is only a speedup so we can skip calculating it. */
float BKE_mesh_calc_poly_area(const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray)
{
if (mpoly->totloop == 3) {
@@ -249,23 +248,6 @@ float BKE_mesh_calc_poly_uv_area(const MPoly *mpoly, const MLoopUV *uv_array)
return area;
}
-/**
- * Calculate the volume and volume-weighted centroid of the volume
- * formed by the polygon and the origin.
- * Results will be negative if the origin is "outside" the polygon
- * (+ve normal side), but the polygon may be non-planar with no effect.
- *
- * Method from:
- * - http://forums.cgsociety.org/archive/index.php?t-756235.html
- * - http://www.globalspec.com/reference/52702/203279/4-8-the-centroid-of-a-tetrahedron
- *
- * \note
- * - Volume is 6x actual volume, and centroid is 4x actual volume-weighted centroid
- * (so division can be done once at the end).
- * - Results will have bias if polygon is non-planar.
- * - The resulting volume will only be correct if the mesh is manifold and has consistent
- * face winding (non-contiguous face normals or holes in the mesh surface).
- */
static float UNUSED_FUNCTION(mesh_calc_poly_volume_centroid)(const MPoly *mpoly,
const MLoop *loopstart,
const MVert *mvarray,
@@ -445,10 +427,6 @@ bool BKE_mesh_center_median(const Mesh *me, float r_cent[3])
return (me->totvert != 0);
}
-/**
- * Calculate the center from polygons,
- * use when we want to ignore vertex locations that don't have connected faces.
- */
bool BKE_mesh_center_median_from_polys(const Mesh *me, float r_cent[3])
{
int i = me->totpoly;
@@ -514,10 +492,6 @@ bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3])
return (me->totpoly != 0);
}
-/**
- * \note Mesh must be manifold with consistent face-winding,
- * see #mesh_calc_poly_volume_centroid for details.
- */
bool BKE_mesh_center_of_volume(const Mesh *me, float r_cent[3])
{
int i = me->totpoly;
@@ -602,12 +576,6 @@ static bool mesh_calc_center_centroid_ex(const MVert *mverts,
return true;
}
-/**
- * Calculate the volume and center.
- *
- * \param r_volume: Volume (unsigned).
- * \param r_center: Center of mass.
- */
void BKE_mesh_calc_volume(const MVert *mverts,
const int mverts_num,
const MLoopTri *looptri,
@@ -800,19 +768,6 @@ void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh)
BKE_mesh_update_customdata_pointers(mesh, true);
}
-/**
- * The same as #BKE_mesh_convert_mfaces_to_mpolys
- * but oriented to be used in #do_versions from `readfile.c`
- * the difference is how active/render/clone/stencil indices are handled here.
- *
- * normally they're being set from `pdata` which totally makes sense for meshes which are already
- * converted to #BMesh structures, but when loading older files indices shall be updated in other
- * way around, so newly added `pdata` and `ldata` would have this indices set
- * based on `fdata` layer.
- *
- * this is normally only needed when reading older files,
- * in all other cases #BKE_mesh_convert_mfaces_to_mpolys shall be always used.
- */
void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh)
{
BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id,
@@ -957,12 +912,9 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id,
#undef ME_FGON
}
+
/** \} */
-/**
- * Flip a single MLoop's #MDisps structure,
- * low level function to be called from face-flipping code which re-arranged the mdisps themselves.
- */
void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
{
if (UNLIKELY(!md->totdisp || !md->disps)) {
@@ -999,14 +951,6 @@ void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
}
}
-/**
- * Flip (invert winding of) the given \a mpoly, i.e. reverse order of its loops
- * (keeping the same vertex as 'start point').
- *
- * \param mpoly: the polygon to flip.
- * \param mloop: the full loops array.
- * \param ldata: the loops custom data.
- */
void BKE_mesh_polygon_flip_ex(MPoly *mpoly,
MLoop *mloop,
CustomData *ldata,
@@ -1056,11 +1000,6 @@ void BKE_mesh_polygon_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata)
BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, nullptr, mdisp, true);
}
-/**
- * Flip (invert winding of) all polygons (used to inverse their normals).
- *
- * \note Invalidates tessellation, caller must handle that.
- */
void BKE_mesh_polygons_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata, int totpoly)
{
MDisps *mdisp = (MDisps *)CustomData_get_layer(ldata, CD_MDISPS);
@@ -1076,8 +1015,6 @@ void BKE_mesh_polygons_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata, int t
/** \name Mesh Flag Flushing
* \{ */
-/* update the hide flag for edges and faces from the corresponding
- * flag in verts */
void BKE_mesh_flush_hidden_from_verts_ex(const MVert *mvert,
const MLoop *mloop,
MEdge *medge,
@@ -1149,9 +1086,6 @@ void BKE_mesh_flush_hidden_from_polys(Mesh *me)
me->mvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
}
-/**
- * simple poly -> vert/edge selection.
- */
void BKE_mesh_flush_select_from_polys_ex(MVert *mvert,
const int totvert,
const MLoop *mloop,
@@ -1248,23 +1182,13 @@ void BKE_mesh_flush_select_from_verts(Mesh *me)
BKE_mesh_flush_select_from_verts_ex(
me->mvert, me->totvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mesh Spatial Calculation
* \{ */
-/**
- * This function takes the difference between 2 vertex-coord-arrays
- * (\a vert_cos_src, \a vert_cos_dst),
- * and applies the difference to \a vert_cos_new relative to \a vert_cos_org.
- *
- * \param vert_cos_src: reference deform source.
- * \param vert_cos_dst: reference deform destination.
- *
- * \param vert_cos_org: reference for the output location.
- * \param vert_cos_new: resulting coords.
- */
void BKE_mesh_calc_relative_deform(const MPoly *mpoly,
const int totpoly,
const MLoop *mloop,
@@ -1318,4 +1242,5 @@ void BKE_mesh_calc_relative_deform(const MPoly *mpoly,
MEM_freeN(vert_accum);
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_fair.cc b/source/blender/blenkernel/intern/mesh_fair.cc
index 6ac1aa9b2b9..50db1bc1564 100644
--- a/source/blender/blenkernel/intern/mesh_fair.cc
+++ b/source/blender/blenkernel/intern/mesh_fair.cc
@@ -293,8 +293,8 @@ class BMeshFairingContext : public FairingContext {
}
bmloop_.reserve(bm->totloop);
- vlmap_ = (MeshElemMap *)MEM_calloc_arrayN(sizeof(MeshElemMap), bm->totvert, "bmesh loop map");
- vlmap_mem_ = (int *)MEM_malloc_arrayN(sizeof(int), bm->totloop, "bmesh loop map mempool");
+ vlmap_ = (MeshElemMap *)MEM_calloc_arrayN(bm->totvert, sizeof(MeshElemMap), "bmesh loop map");
+ vlmap_mem_ = (int *)MEM_malloc_arrayN(bm->totloop, sizeof(int), "bmesh loop map mempool");
BMVert *v;
BMLoop *l;
diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c
index 7a776b0ecb7..ff2ac8ecee9 100644
--- a/source/blender/blenkernel/intern/mesh_iterators.c
+++ b/source/blender/blenkernel/intern/mesh_iterators.c
@@ -34,15 +34,11 @@
#include "MEM_guardedalloc.h"
-/* Copied from cdDM_foreachMappedVert */
-void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
- void (*func)(void *userData,
- int index,
- const float co[3],
- const float no_f[3],
- const short no_s[3]),
- void *userData,
- MeshForeachFlag flag)
+void BKE_mesh_foreach_mapped_vert(
+ Mesh *mesh,
+ void (*func)(void *userData, int index, const float co[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag)
{
if (mesh->edit_mesh != NULL) {
BMEditMesh *em = mesh->edit_mesh;
@@ -50,7 +46,7 @@ void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
BMIter iter;
BMVert *eve;
int i;
- if (mesh->runtime.edit_data->vertexCos != NULL) {
+ if (mesh->runtime.edit_data != NULL && mesh->runtime.edit_data->vertexCos != NULL) {
const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
const float(*vertexNos)[3];
if (flag & MESH_FOREACH_USE_NORMAL) {
@@ -62,44 +58,42 @@ void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
}
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vertexNos[i] : NULL;
- func(userData, i, vertexCos[i], no, NULL);
+ func(userData, i, vertexCos[i], no);
}
}
else {
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? eve->no : NULL;
- func(userData, i, eve->co, no, NULL);
+ func(userData, i, eve->co, no);
}
}
}
else {
const MVert *mv = mesh->mvert;
const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+ const float(*vert_normals)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
+ BKE_mesh_vertex_normals_ensure(mesh) :
+ NULL;
if (index) {
for (int i = 0; i < mesh->totvert; i++, mv++) {
- const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[i] : NULL;
const int orig = *index++;
if (orig == ORIGINDEX_NONE) {
continue;
}
- func(userData, orig, mv->co, NULL, no);
+ func(userData, orig, mv->co, no);
}
}
else {
for (int i = 0; i < mesh->totvert; i++, mv++) {
- const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
- func(userData, i, mv->co, NULL, no);
+ const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[i] : NULL;
+ func(userData, i, mv->co, no);
}
}
}
}
-/**
- * Copied from #cdDM_foreachMappedEdge.
- * \param tot_edges: Number of original edges. Used to avoid calling the callback with invalid
- * edge indices.
- */
void BKE_mesh_foreach_mapped_edge(
Mesh *mesh,
const int tot_edges,
@@ -112,7 +106,7 @@ void BKE_mesh_foreach_mapped_edge(
BMIter iter;
BMEdge *eed;
int i;
- if (mesh->runtime.edit_data->vertexCos != NULL) {
+ if (mesh->runtime.edit_data != NULL && mesh->runtime.edit_data->vertexCos != NULL) {
const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
BM_mesh_elem_index_ensure(bm, BM_VERT);
@@ -151,7 +145,6 @@ void BKE_mesh_foreach_mapped_edge(
}
}
-/* Copied from cdDM_foreachMappedLoop */
void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
void (*func)(void *userData,
int vertex_index,
@@ -171,7 +164,8 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
BMIter iter;
BMFace *efa;
- const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
+ const float(*vertexCos)[3] = mesh->runtime.edit_data ? mesh->runtime.edit_data->vertexCos :
+ NULL;
/* XXX: investigate using EditMesh data. */
const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
@@ -232,14 +226,13 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
}
}
-/* Copied from cdDM_foreachMappedFaceCenter */
void BKE_mesh_foreach_mapped_face_center(
Mesh *mesh,
void (*func)(void *userData, int index, const float cent[3], const float no[3]),
void *userData,
MeshForeachFlag flag)
{
- if (mesh->edit_mesh != NULL) {
+ if (mesh->edit_mesh != NULL && mesh->runtime.edit_data != NULL) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
const float(*polyCos)[3];
@@ -309,7 +302,6 @@ void BKE_mesh_foreach_mapped_face_center(
}
}
-/* Copied from cdDM_foreachMappedFaceCenter */
void BKE_mesh_foreach_mapped_subdiv_face_center(
Mesh *mesh,
void (*func)(void *userData, int index, const float cent[3], const float no[3]),
@@ -319,8 +311,9 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
const MPoly *mp = mesh->mpoly;
const MLoop *ml;
const MVert *mv;
- float _no_buf[3];
- float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL;
+ const float(*vert_normals)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
+ BKE_mesh_vertex_normals_ensure(mesh) :
+ NULL;
const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
if (index) {
@@ -333,10 +326,11 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
for (int j = 0; j < mp->totloop; j++, ml++) {
mv = &mesh->mvert[ml->v];
if (mv->flag & ME_VERT_FACEDOT) {
- if (flag & MESH_FOREACH_USE_NORMAL) {
- normal_short_to_float_v3(no, mv->no);
- }
- func(userData, orig, mv->co, no);
+
+ func(userData,
+ orig,
+ mv->co,
+ (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[ml->v] : NULL);
}
}
}
@@ -347,10 +341,7 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
for (int j = 0; j < mp->totloop; j++, ml++) {
mv = &mesh->mvert[ml->v];
if (mv->flag & ME_VERT_FACEDOT) {
- if (flag & MESH_FOREACH_USE_NORMAL) {
- normal_short_to_float_v3(no, mv->no);
- }
- func(userData, i, mv->co, no);
+ func(userData, i, mv->co, (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[ml->v] : NULL);
}
}
}
@@ -367,8 +358,7 @@ typedef struct MappedVCosData {
static void get_vertexcos__mapFunc(void *user_data,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
MappedVCosData *mapped_vcos_data = (MappedVCosData *)user_data;
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index d28bb9c0744..415cce95d38 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -42,9 +42,6 @@
* \{ */
/* ngon version wip, based on BM_uv_vert_map_create */
-/* this replaces the non bmesh function (in trunk) which takes MTFace's,
- * if we ever need it back we could but for now this replaces it because its unused. */
-
UvVertMap *BKE_mesh_uv_vert_map_create(const MPoly *mpoly,
const MLoop *mloop,
const MLoopUV *mloopuv,
@@ -250,11 +247,6 @@ static void mesh_vert_poly_or_loop_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * Generates a map where the key is the vertex and the value
- * is a list of polys that use that vertex as a corner.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const MPoly *mpoly,
@@ -266,11 +258,6 @@ void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, false);
}
-/**
- * Generates a map where the key is the vertex and the value
- * is a list of loops that use that vertex as a corner.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const MPoly *mpoly,
@@ -282,11 +269,6 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, true);
}
-/**
- * Generates a map where the key is the edge and the value
- * is a list of looptris that use that edge.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
int **r_mem,
const MVert *UNUSED(mvert),
@@ -331,11 +313,6 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * Generates a map where the key is the vertex and the value
- * is a list of edges that use that vertex as an endpoint.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_vert_edge_map_create(
MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge)
{
@@ -375,10 +352,6 @@ void BKE_mesh_vert_edge_map_create(
*r_mem = indices;
}
-/**
- * A version of #BKE_mesh_vert_edge_map_create that references connected vertices directly
- * (not their edges).
- */
void BKE_mesh_vert_edge_vert_map_create(
MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge)
{
@@ -418,11 +391,6 @@ void BKE_mesh_vert_edge_vert_map_create(
*r_mem = indices;
}
-/**
- * Generates a map where the key is the edge and the value is a list of loops that use that edge.
- * Loops indices of a same poly are contiguous and in winding order.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const MEdge *UNUSED(medge),
@@ -476,11 +444,6 @@ void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * Generates a map where the key is the edge and the value
- * is a list of polygons that use that edge.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const MEdge *UNUSED(medge),
@@ -529,20 +492,6 @@ void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * This function creates a map so the source-data (vert/edge/loop/poly)
- * can loop over the destination data (using the destination arrays origindex).
- *
- * This has the advantage that it can operate on any data-types.
- *
- * \param totsource: The total number of elements that \a final_origindex points to.
- * \param totfinal: The size of \a final_origindex
- * \param final_origindex: The size of the final array.
- *
- * \note `totsource` could be `totpoly`,
- * `totfinal` could be `tottessface` and `final_origindex` its ORIGINDEX custom-data.
- * This would allow an MPoly to loop over its tessfaces.
- */
void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
int **r_mem,
const int totsource,
@@ -584,10 +533,6 @@ void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * A version of #BKE_mesh_origindex_map_create that takes a looptri array.
- * Making a poly -> looptri map.
- */
void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
int **r_mem,
const MPoly *mpoly,
@@ -630,7 +575,7 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
typedef bool (*MeshRemap_CheckIslandBoundary)(const struct MPoly *mpoly,
const struct MLoop *mloop,
const struct MEdge *medge,
- const int nbr_egde_users,
+ const int nbr_edge_users,
const struct MPoly *mpoly_array,
const struct MeshElemMap *edge_poly_map,
void *user_data);
@@ -833,14 +778,14 @@ static void poly_edge_loop_islands_calc(const MEdge *medge,
static bool poly_is_island_boundary_smooth_cb(const MPoly *mp,
const MLoop *UNUSED(ml),
const MEdge *me,
- const int nbr_egde_users,
+ const int nbr_edge_users,
const MPoly *mpoly_array,
const MeshElemMap *edge_poly_map,
void *UNUSED(user_data))
{
/* Edge is sharp if one of its polys is flat, or edge itself is sharp,
* or edge is not used by exactly two polygons. */
- if ((mp->flag & ME_SMOOTH) && !(me->flag & ME_SHARP) && (nbr_egde_users == 2)) {
+ if ((mp->flag & ME_SMOOTH) && !(me->flag & ME_SHARP) && (nbr_edge_users == 2)) {
/* In that case, edge appears to be smooth, but we need to check its other poly too. */
const MPoly *mp_other = (mp == &mpoly_array[edge_poly_map->indices[0]]) ?
&mpoly_array[edge_poly_map->indices[1]] :
@@ -850,14 +795,6 @@ static bool poly_is_island_boundary_smooth_cb(const MPoly *mp,
return true;
}
-/**
- * Calculate smooth groups from sharp edges.
- *
- * \param r_totgroup: The total number of groups, 1 or more.
- * \return Polygon aligned array of group index values (bitflags if use_bitflags is true),
- * starting at 1 (0 being used as 'invalid' flag).
- * Note it's callers's responsibility to MEM_freeN returned array.
- */
int *BKE_mesh_calc_smoothgroups(const MEdge *medge,
const int totedge,
const MPoly *mpoly,
@@ -1012,7 +949,7 @@ typedef struct MeshCheckIslandBoundaryUv {
static bool mesh_check_island_boundary_uv(const MPoly *UNUSED(mp),
const MLoop *ml,
const MEdge *me,
- const int UNUSED(nbr_egde_users),
+ const int UNUSED(nbr_edge_users),
const MPoly *UNUSED(mpoly_array),
const MeshElemMap *UNUSED(edge_poly_map),
void *user_data)
@@ -1202,10 +1139,6 @@ static bool mesh_calc_islands_loop_poly_uv(MVert *UNUSED(verts),
return true;
}
-/**
- * Calculate 'generic' UV islands, i.e. based only on actual geometry data (edge seams),
- * not some UV layers coordinates.
- */
bool BKE_mesh_calc_islands_loop_poly_edgeseam(MVert *verts,
const int totvert,
MEdge *edges,
@@ -1220,19 +1153,6 @@ bool BKE_mesh_calc_islands_loop_poly_edgeseam(MVert *verts,
verts, totvert, edges, totedge, polys, totpoly, loops, totloop, NULL, r_island_store);
}
-/**
- * Calculate UV islands.
- *
- * \note If no MLoopUV layer is passed, we only consider edges tagged as seams as UV boundaries.
- * This has the advantages of simplicity, and being valid/common to all UV maps.
- * However, it means actual UV islands without matching UV seams will not be handled correctly...
- * If a valid UV layer is passed as \a luvs parameter,
- * UV coordinates are also used to detect islands boundaries.
- *
- * \note All this could be optimized...
- * Not sure it would be worth the more complex code, though,
- * those loops are supposed to be really quick to do...
- */
bool BKE_mesh_calc_islands_loop_poly_uvmap(MVert *verts,
const int totvert,
MEdge *edges,
diff --git a/source/blender/blenkernel/intern/mesh_merge.c b/source/blender/blenkernel/intern/mesh_merge.c
index d3d835378ca..134a1344f83 100644
--- a/source/blender/blenkernel/intern/mesh_merge.c
+++ b/source/blender/blenkernel/intern/mesh_merge.c
@@ -204,38 +204,6 @@ static bool poly_gset_compare_fn(const void *k1, const void *k2)
return true;
}
-/**
- * Merge Verts
- *
- * This frees the given mesh and returns a new mesh.
- *
- * \param vtargetmap: The table that maps vertices to target vertices. a value of -1
- * indicates a vertex is a target, and is to be kept.
- * This array is aligned with 'mesh->totvert'
- * \warning \a vtargetmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.),
- * this is not supported and will likely generate corrupted geometry.
- *
- * \param tot_vtargetmap: The number of non '-1' values in vtargetmap. (not the size)
- *
- * \param merge_mode: enum with two modes.
- * - #MESH_MERGE_VERTS_DUMP_IF_MAPPED
- * When called by the Mirror Modifier,
- * In this mode it skips any faces that have all vertices merged (to avoid creating pairs
- * of faces sharing the same set of vertices)
- * - #MESH_MERGE_VERTS_DUMP_IF_EQUAL
- * When called by the Array Modifier,
- * In this mode, faces where all vertices are merged are double-checked,
- * to see whether all target vertices actually make up a poly already.
- * Indeed it could be that all of a poly's vertices are merged,
- * but merged to vertices that do not make up a single poly,
- * in which case the original poly should not be dumped.
- * Actually this later behavior could apply to the Mirror Modifier as well,
- * but the additional checks are costly and not necessary in the case of mirror,
- * because each vertex is only merged to its own mirror.
- *
- * \note #BKE_mesh_tessface_calc_ex has to run on the returned DM
- * if you want to access tessfaces.
- */
Mesh *BKE_mesh_merge_verts(Mesh *mesh,
const int *vtargetmap,
const int tot_vtargetmap,
@@ -647,10 +615,18 @@ Mesh *BKE_mesh_merge_verts(Mesh *mesh,
}
/* Copy over data. #CustomData_add_layer can do this, need to look it up. */
- memcpy(result->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert));
- memcpy(result->medge, medge, sizeof(MEdge) * STACK_SIZE(medge));
- memcpy(result->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop));
- memcpy(result->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly));
+ if (STACK_SIZE(mvert)) {
+ memcpy(result->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert));
+ }
+ if (STACK_SIZE(medge)) {
+ memcpy(result->medge, medge, sizeof(MEdge) * STACK_SIZE(medge));
+ }
+ if (STACK_SIZE(mloop)) {
+ memcpy(result->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop));
+ }
+ if (STACK_SIZE(mpoly)) {
+ memcpy(result->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly));
+ }
MEM_freeN(mvert);
MEM_freeN(medge);
diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c
index b20d81e7b9c..abc0b518d92 100644
--- a/source/blender/blenkernel/intern/mesh_mirror.c
+++ b/source/blender/blenkernel/intern/mesh_mirror.c
@@ -130,14 +130,11 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
BM_mesh_free(bm);
}
-/**
- * \warning This should _not_ be used to modify original meshes since
- * it doesn't handle shape-keys, use #BKE_mesh_mirror_apply_mirror_on_axis instead.
- */
Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
Object *ob,
const Mesh *mesh,
- const int axis)
+ const int axis,
+ const bool use_correct_order_on_merge)
{
const float tolerance_sq = mmd->tolerance * mmd->tolerance;
const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
@@ -239,7 +236,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
}
/* Copy custom-data to new geometry,
- * copy from its self because this data may have been created in the checks above. */
+ * copy from itself because this data may have been created in the checks above. */
CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts);
CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges);
/* loops are copied later */
@@ -260,21 +257,51 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
mul_m4_v3(mtx, mv->co);
if (do_vtargetmap) {
- /* compare location of the original and mirrored vertex, to see if they
- * should be mapped for merging */
- if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
- *vtmap_a = maxVerts + i;
- tot_vtargetmap++;
-
- /* average location */
- mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
- copy_v3_v3(mv_prev->co, mv->co);
- }
- else {
+ /* Compare location of the original and mirrored vertex,
+ * to see if they should be mapped for merging.
+ *
+ * Always merge from the copied into the original vertices so it's possible to
+ * generate a 1:1 mapping by scanning vertices from the beginning of the array
+ * as is done in #BKE_editmesh_vert_coords_when_deformed. Without this,
+ * the coordinates returned will sometimes point to the copied vertex locations, see:
+ * T91444.
+ *
+ * However, such a change also affects non-versionable things like some modifiers binding, so
+ * we cannot enforce that behavior on existing modifiers, in which case we keep using the
+ * old, incorrect behavior of merging the source vertex into its copy.
+ */
+ if (use_correct_order_on_merge) {
+ if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
+ *vtmap_b = i;
+ tot_vtargetmap++;
+
+ /* average location */
+ mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
+ copy_v3_v3(mv_prev->co, mv->co);
+ }
+ else {
+ *vtmap_b = -1;
+ }
+
+ /* Fill here to avoid 2x loops. */
*vtmap_a = -1;
}
+ else {
+ if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
+ *vtmap_a = maxVerts + i;
+ tot_vtargetmap++;
- *vtmap_b = -1; /* fill here to avoid 2x loops */
+ /* average location */
+ mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
+ copy_v3_v3(mv_prev->co, mv->co);
+ }
+ else {
+ *vtmap_a = -1;
+ }
+
+ /* Fill here to avoid 2x loops. */
+ *vtmap_b = -1;
+ }
vtmap_a++;
vtmap_b++;
@@ -383,7 +410,6 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
CustomData *ldata = &result->ldata;
short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
MLoopNorSpaceArray lnors_spacearr = {NULL};
- float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__);
/* The transform matrix of a normal must be
* the transpose of inverse of transform matrix of the geometry... */
@@ -393,16 +419,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
/* calculate custom normals into loop_normals, then mirror first half into second half */
- BKE_mesh_calc_normals_poly_and_vertex(result->mvert,
- result->totvert,
- result->mloop,
- totloop,
- result->mpoly,
- totpoly,
- poly_normals,
- NULL);
-
BKE_mesh_normals_loop_split(result->mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
result->totvert,
result->medge,
result->totedge,
@@ -410,7 +428,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
loop_normals,
totloop,
result->mpoly,
- poly_normals,
+ BKE_mesh_poly_normals_ensure(mesh),
totpoly,
true,
mesh->smoothresh,
@@ -436,7 +454,6 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
}
}
- MEM_freeN(poly_normals);
MEM_freeN(loop_normals);
BKE_lnor_spacearr_free(&lnors_spacearr);
}
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index 9a761c6fa11..08a17060549 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -38,7 +38,9 @@
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_memarena.h"
+#include "BLI_span.hh"
#include "BLI_stack.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -50,6 +52,8 @@
#include "atomic_ops.h"
+using blender::Span;
+
// #define DEBUG_TIME
#ifdef DEBUG_TIME
@@ -109,6 +113,52 @@ void BKE_mesh_normals_tag_dirty(Mesh *mesh)
mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL;
}
+float (*BKE_mesh_vertex_normals_for_write(Mesh *mesh))[3]
+{
+ CustomData_duplicate_referenced_layer(&mesh->vdata, CD_NORMAL, mesh->totvert);
+ return (float(*)[3])CustomData_add_layer(
+ &mesh->vdata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totvert);
+}
+
+float (*BKE_mesh_poly_normals_for_write(Mesh *mesh))[3]
+{
+ CustomData_duplicate_referenced_layer(&mesh->pdata, CD_NORMAL, mesh->totpoly);
+ return (float(*)[3])CustomData_add_layer(
+ &mesh->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totpoly);
+}
+
+void BKE_mesh_vertex_normals_clear_dirty(Mesh *mesh)
+{
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
+}
+
+void BKE_mesh_poly_normals_clear_dirty(Mesh *mesh)
+{
+ mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL;
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
+}
+
+bool BKE_mesh_vertex_normals_are_dirty(const Mesh *mesh)
+{
+ return mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL;
+}
+
+bool BKE_mesh_poly_normals_are_dirty(const Mesh *mesh)
+{
+ return mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL;
+}
+
+void BKE_mesh_assert_normals_dirty_or_calculated(const Mesh *mesh)
+{
+ if (!(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL)) {
+ BLI_assert(CustomData_has_layer(&mesh->vdata, CD_NORMAL) || mesh->totvert == 0);
+ }
+ if (!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL)) {
+ BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL) || mesh->totpoly == 0);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -161,8 +211,6 @@ void BKE_mesh_calc_normals_poly(const MVert *mvert,
/* -------------------------------------------------------------------- */
/** \name Mesh Normal Calculation (Polygons & Vertices)
*
- * Implement #BKE_mesh_calc_normals_poly_and_vertex,
- *
* Take care making optimizations to this function as improvements to low-poly
* meshes can slow down high-poly meshes. For details on performance, see D11993.
* \{ */
@@ -253,18 +301,16 @@ static void mesh_calc_normals_poly_and_vertex_finalize_fn(
/* Following Mesh convention; we use vertex coordinate itself for normal in this case. */
normalize_v3_v3(no, mv->co);
}
-
- normal_float_to_short_v3(mv->no, no);
}
-void BKE_mesh_calc_normals_poly_and_vertex(MVert *mvert,
- const int mvert_len,
- const MLoop *mloop,
- const int UNUSED(mloop_len),
- const MPoly *mpoly,
- const int mpoly_len,
- float (*r_poly_normals)[3],
- float (*r_vert_normals)[3])
+static void mesh_calc_normals_poly_and_vertex(MVert *mvert,
+ const int mvert_len,
+ const MLoop *mloop,
+ const int UNUSED(mloop_len),
+ const MPoly *mpoly,
+ const int mpoly_len,
+ float (*r_poly_normals)[3],
+ float (*r_vert_normals)[3])
{
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -308,22 +354,90 @@ void BKE_mesh_calc_normals_poly_and_vertex(MVert *mvert,
/** \name Mesh Normal Calculation
* \{ */
-void BKE_mesh_ensure_normals(Mesh *mesh)
+const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
{
- if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
- BKE_mesh_calc_normals(mesh);
+ if (!(BKE_mesh_vertex_normals_are_dirty(mesh) || BKE_mesh_poly_normals_are_dirty(mesh))) {
+ BLI_assert(CustomData_has_layer(&mesh->vdata, CD_NORMAL) || mesh->totvert == 0);
+ return (const float(*)[3])CustomData_get_layer(&mesh->vdata, CD_NORMAL);
+ }
+
+ if (mesh->totvert == 0) {
+ return nullptr;
+ }
+
+ ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex;
+ BLI_mutex_lock(normals_mutex);
+ if (!(BKE_mesh_vertex_normals_are_dirty(mesh) || BKE_mesh_poly_normals_are_dirty(mesh))) {
+ BLI_assert(CustomData_has_layer(&mesh->vdata, CD_NORMAL));
+ BLI_mutex_unlock(normals_mutex);
+ return (const float(*)[3])CustomData_get_layer(&mesh->vdata, CD_NORMAL);
}
- BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0);
+
+ Mesh &mesh_mutable = *const_cast<Mesh *>(mesh);
+
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(&mesh_mutable);
+ float(*poly_normals)[3] = BKE_mesh_poly_normals_for_write(&mesh_mutable);
+
+ mesh_calc_normals_poly_and_vertex(mesh_mutable.mvert,
+ mesh_mutable.totvert,
+ mesh_mutable.mloop,
+ mesh_mutable.totloop,
+ mesh_mutable.mpoly,
+ mesh_mutable.totpoly,
+ poly_normals,
+ vert_normals);
+
+ BKE_mesh_vertex_normals_clear_dirty(&mesh_mutable);
+ BKE_mesh_poly_normals_clear_dirty(&mesh_mutable);
+
+ BLI_mutex_unlock(normals_mutex);
+ return vert_normals;
+}
+
+const float (*BKE_mesh_poly_normals_ensure(const Mesh *mesh))[3]
+{
+ if (!BKE_mesh_poly_normals_are_dirty(mesh)) {
+ BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL) || mesh->totpoly == 0);
+ return (const float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ }
+
+ if (mesh->totpoly == 0) {
+ return nullptr;
+ }
+
+ ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex;
+ BLI_mutex_lock(normals_mutex);
+ if (!BKE_mesh_poly_normals_are_dirty(mesh)) {
+ BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL));
+ BLI_mutex_unlock(normals_mutex);
+ return (const float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ }
+
+ Mesh &mesh_mutable = *const_cast<Mesh *>(mesh);
+
+ float(*poly_normals)[3] = BKE_mesh_poly_normals_for_write(&mesh_mutable);
+
+ BKE_mesh_calc_normals_poly(mesh_mutable.mvert,
+ mesh_mutable.totvert,
+ mesh_mutable.mloop,
+ mesh_mutable.totloop,
+ mesh_mutable.mpoly,
+ mesh_mutable.totpoly,
+ poly_normals);
+
+ BKE_mesh_poly_normals_clear_dirty(&mesh_mutable);
+
+ BLI_mutex_unlock(normals_mutex);
+ return poly_normals;
}
-/**
- * Called after calculating all modifiers.
- */
void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
{
switch ((eMeshWrapperType)mesh->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
- /* Run code below. */
+ BKE_mesh_vertex_normals_ensure(mesh);
+ BKE_mesh_poly_normals_ensure(mesh);
break;
case ME_WRAPPER_TYPE_BMESH: {
struct BMEditMesh *em = mesh->edit_mesh;
@@ -335,70 +449,17 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
return;
}
}
-
- float(*poly_nors)[3] = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- const bool do_vert_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) != 0;
- const bool do_poly_normals = (mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL ||
- poly_nors == nullptr);
-
- if (do_vert_normals || do_poly_normals) {
- const bool do_add_poly_nors_cddata = (poly_nors == nullptr);
- if (do_add_poly_nors_cddata) {
- poly_nors = (float(*)[3])MEM_malloc_arrayN(
- (size_t)mesh->totpoly, sizeof(*poly_nors), __func__);
- }
-
- /* Calculate poly/vert normals. */
- if (do_vert_normals) {
- BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- poly_nors,
- nullptr);
- }
- else {
- BKE_mesh_calc_normals_poly(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- poly_nors);
- }
-
- if (do_add_poly_nors_cddata) {
- CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly);
- }
-
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
- mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL;
- }
}
-/**
- * NOTE: this does not update the #CD_NORMAL layer,
- * but does update the normals in the #CD_MVERT layer.
- */
void BKE_mesh_calc_normals(Mesh *mesh)
{
#ifdef DEBUG_TIME
TIMEIT_START_AVERAGED(BKE_mesh_calc_normals);
#endif
- BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- nullptr,
- nullptr);
+ BKE_mesh_vertex_normals_ensure(mesh);
#ifdef DEBUG_TIME
TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
#endif
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
void BKE_mesh_calc_normals_looptri(MVert *mverts,
@@ -445,8 +506,6 @@ void BKE_mesh_calc_normals_looptri(MVert *mverts,
if (UNLIKELY(normalize_v3(no) == 0.0f)) {
normalize_v3_v3(no, mv->co);
}
-
- normal_float_to_short_v3(mv->no, no);
}
cleanup:
@@ -479,13 +538,6 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr,
lnors_spacearr->data_type = data_type;
}
-/**
- * Utility for multi-threaded calculation that ensures
- * `lnors_spacearr_tls` doesn't share memory with `lnors_spacearr`
- * that would cause it not to be thread safe.
- *
- * \note This works as long as threads never operate on the same loops at once.
- */
void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpaceArray *lnors_spacearr_tls)
{
@@ -493,10 +545,6 @@ void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr,
lnors_spacearr_tls->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
}
-/**
- * Utility for multi-threaded calculation
- * that merges `lnors_spacearr_tls` into `lnors_spacearr`.
- */
void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpaceArray *lnors_spacearr_tls)
{
@@ -537,11 +585,6 @@ MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
/* This threshold is a bit touchy (usual float precision issue), this value seems OK. */
#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f)
-/* Should only be called once.
- * Beware, this modifies ref_vec and other_vec in place!
- * In case no valid space can be generated, ref_alpha and ref_beta are set to zero
- * (which means 'use auto lnors').
- */
void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
const float lnor[3],
float vec_ref[3],
@@ -614,14 +657,6 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
}
}
-/**
- * Add a new given loop to given lnor_space.
- * Depending on \a lnor_space->data_type, we expect \a bm_loop to be a pointer to BMLoop struct
- * (in case of BMLOOP_PTR), or nullptr (in case of LOOP_INDEX), loop index is then stored in
- * pointer. If \a is_single is set, the BMLoop or loop index is directly stored in \a
- * lnor_space->loops pointer (since there is only one loop in this fan), else it is added to the
- * linked list of loops in the fan.
- */
void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpace *lnor_space,
const int ml_index,
@@ -783,6 +818,7 @@ struct LoopSplitTaskDataCommon {
int (*edge_to_loops)[2];
int *loop_to_poly;
const float (*polynors)[3];
+ const float (*vert_normals)[3];
int numEdges;
int numLoops;
@@ -799,7 +835,6 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
const float split_angle,
const bool do_sharp_edges_tag)
{
- const MVert *mverts = data->mverts;
const MEdge *medges = data->medges;
const MLoop *mloops = data->mloops;
@@ -838,7 +873,7 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
* this way we don't have to compute those later!
*/
if (loopnors) {
- normal_short_to_float_v3(loopnors[ml_curr_index], mverts[ml_curr->v].no);
+ copy_v3_v3(loopnors[ml_curr_index], data->vert_normals[ml_curr->v]);
}
/* Check whether current edge might be smooth or sharp */
@@ -901,12 +936,6 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
}
}
-/**
- * Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
- *
- * Used when defining an empty custom loop normals data layer,
- * to keep same shading as with auto-smooth!
- */
void BKE_edges_sharp_from_angle_set(const struct MVert *mverts,
const int UNUSED(numVerts),
struct MEdge *medges,
@@ -1568,12 +1597,8 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
#endif
}
-/**
- * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
- * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
- * (splitting edges).
- */
void BKE_mesh_normals_loop_split(const MVert *mverts,
+ const float (*vert_normals)[3],
const int UNUSED(numVerts),
MEdge *medges,
const int numEdges,
@@ -1616,7 +1641,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
copy_v3_v3(r_loopnors[ml_index], polynors[mp_index]);
}
else {
- normal_short_to_float_v3(r_loopnors[ml_index], mverts[mloops[ml_index].v].no);
+ copy_v3_v3(r_loopnors[ml_index], vert_normals[mloops[ml_index].v]);
}
}
}
@@ -1674,6 +1699,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
common_data.edge_to_loops = edge_to_loops;
common_data.loop_to_poly = loop_to_poly;
common_data.polynors = polynors;
+ common_data.vert_normals = vert_normals;
common_data.numEdges = numEdges;
common_data.numLoops = numLoops;
common_data.numPolys = numPolys;
@@ -1725,6 +1751,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
* in which case they will be replaced by default loop/vertex normal.
*/
static void mesh_normals_loop_custom_set(const MVert *mverts,
+ const float (*vert_normals)[3],
const int numVerts,
MEdge *medges,
const int numEdges,
@@ -1756,6 +1783,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
/* Compute current lnor spacearr. */
BKE_mesh_normals_loop_split(mverts,
+ vert_normals,
numVerts,
medges,
numEdges,
@@ -1775,7 +1803,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
if (use_vertices) {
for (int i = 0; i < numVerts; i++) {
if (is_zero_v3(r_custom_loopnors[i])) {
- normal_short_to_float_v3(r_custom_loopnors[i], mverts[i].no);
+ copy_v3_v3(r_custom_loopnors[i], vert_normals[i]);
}
}
}
@@ -1878,6 +1906,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
/* And now, recompute our new auto lnors and lnor spacearr! */
BKE_lnor_spacearr_clear(&lnors_spacearr);
BKE_mesh_normals_loop_split(mverts,
+ vert_normals,
numVerts,
medges,
numEdges,
@@ -1959,6 +1988,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
}
void BKE_mesh_normals_loop_custom_set(const MVert *mverts,
+ const float (*vert_normals)[3],
const int numVerts,
MEdge *medges,
const int numEdges,
@@ -1971,6 +2001,7 @@ void BKE_mesh_normals_loop_custom_set(const MVert *mverts,
short (*r_clnors_data)[2])
{
mesh_normals_loop_custom_set(mverts,
+ vert_normals,
numVerts,
medges,
numEdges,
@@ -1985,6 +2016,7 @@ void BKE_mesh_normals_loop_custom_set(const MVert *mverts,
}
void BKE_mesh_normals_loop_custom_from_vertices_set(const MVert *mverts,
+ const float (*vert_normals)[3],
float (*r_custom_vertnors)[3],
const int numVerts,
MEdge *medges,
@@ -1997,6 +2029,7 @@ void BKE_mesh_normals_loop_custom_from_vertices_set(const MVert *mverts,
short (*r_clnors_data)[2])
{
mesh_normals_loop_custom_set(mverts,
+ vert_normals,
numVerts,
medges,
numEdges,
@@ -2024,22 +2057,8 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
&mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, nullptr, numloops);
}
- float(*polynors)[3] = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- bool free_polynors = false;
- if (polynors == nullptr) {
- polynors = (float(*)[3])MEM_mallocN(sizeof(float[3]) * (size_t)mesh->totpoly, __func__);
- BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- polynors,
- nullptr);
- free_polynors = true;
- }
-
mesh_normals_loop_custom_set(mesh->mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
mesh->totvert,
mesh->medge,
mesh->totedge,
@@ -2047,46 +2066,22 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
r_custom_nors,
mesh->totloop,
mesh->mpoly,
- polynors,
+ BKE_mesh_poly_normals_ensure(mesh),
mesh->totpoly,
clnors,
use_vertices);
-
- if (free_polynors) {
- MEM_freeN(polynors);
- }
}
-/**
- * Higher level functions hiding most of the code needed around call to
- * #BKE_mesh_normals_loop_custom_set().
- *
- * \param r_custom_loopnors: is not const, since code will replace zero_v3 normals there
- * with automatically computed vectors.
- */
void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3])
{
mesh_set_custom_normals(mesh, r_custom_loopnors, false);
}
-/**
- * Higher level functions hiding most of the code needed around call to
- * #BKE_mesh_normals_loop_custom_from_vertices_set().
- *
- * \param r_custom_vertnors: is not const, since code will replace zero_v3 normals there
- * with automatically computed vectors.
- */
void BKE_mesh_set_custom_normals_from_vertices(Mesh *mesh, float (*r_custom_vertnors)[3])
{
mesh_set_custom_normals(mesh, r_custom_vertnors, true);
}
-/**
- * Computes average per-vertex normals from given custom loop normals.
- *
- * \param clnors: The computed custom loop normals.
- * \param r_vert_clnors: The (already allocated) array where to store averaged per-vertex normals.
- */
void BKE_mesh_normals_loop_to_vertex(const int numVerts,
const MLoop *mloops,
const int numLoops,
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index 53a31cbbc7a..a9f61e9827b 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -50,7 +50,7 @@
static CLG_LogRef LOG = {"bke.mesh"};
/* -------------------------------------------------------------------- */
-/** \name Some generic helpers.
+/** \name Some Generic Helpers
* \{ */
static bool mesh_remap_bvhtree_query_nearest(BVHTreeFromMesh *treedata,
@@ -117,22 +117,12 @@ static bool mesh_remap_bvhtree_query_raycast(BVHTreeFromMesh *treedata,
/** \} */
-/**
- * \name Auto-match.
+/* -------------------------------------------------------------------- */
+/** \name Auto-match.
*
* Find transform of a mesh to get best match with another.
* \{ */
-/**
- * Compute a value of the difference between both given meshes.
- * The smaller the result, the better the match.
- *
- * We return the inverse of the average of the inversed
- * shortest distance from each dst vertex to src ones.
- * In other words, beyond a certain (relatively small) distance, all differences have more or less
- * the same weight in final result, which allows to reduce influence of a few high differences,
- * in favor of a global good matching.
- */
float BKE_mesh_remap_calc_difference_from_mesh(const SpaceTransform *space_transform,
const MVert *verts_dst,
const int numverts_dst,
@@ -268,9 +258,6 @@ static void mesh_calc_eigen_matrix(const MVert *verts,
copy_v3_v3(r_mat[3], center);
}
-/**
- * Set r_space_transform so that best bbox of dst matches best bbox of src.
- */
void BKE_mesh_remap_find_best_match_from_mesh(const MVert *verts_dst,
const int numverts_dst,
Mesh *me_src,
@@ -328,7 +315,7 @@ void BKE_mesh_remap_find_best_match_from_mesh(const MVert *verts_dst,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Mesh to mesh mapping
+/** \name Mesh to Mesh Mapping
* \{ */
void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(const int UNUSED(vert_mode),
@@ -607,6 +594,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
MPoly *polys_src = me_src->mpoly;
MLoop *loops_src = me_src->mloop;
float(*vcos_src)[3] = BKE_mesh_vert_coords_alloc(me_src, NULL);
+ const float(*vert_normals_src)[3] = BKE_mesh_vertex_normals_ensure(me_src);
size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE;
float(*vcos)[3] = MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__);
@@ -618,7 +606,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) {
for (i = 0; i < numverts_dst; i++) {
copy_v3_v3(tmp_co, verts_dst[i].co);
- normal_short_to_float_v3(tmp_no, verts_dst[i].no);
+ copy_v3_v3(tmp_no, vert_normals_src[i]);
/* Convert the vertex to tree coordinates, if needed. */
if (space_transform) {
@@ -964,6 +952,8 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
+ const float(*vert_normals_dst)[3] = BKE_mesh_vertex_normals_ensure(me_src);
+
for (i = 0; i < numedges_dst; i++) {
/* For each dst edge, we sample some rays from it (interpolated from its vertices)
* and use their hits to interpolate from source edges. */
@@ -983,8 +973,8 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
copy_v3_v3(v1_co, verts_dst[me->v1].co);
copy_v3_v3(v2_co, verts_dst[me->v2].co);
- normal_short_to_float_v3(v1_no, verts_dst[me->v1].no);
- normal_short_to_float_v3(v2_no, verts_dst[me->v2].no);
+ copy_v3_v3(v1_no, vert_normals_dst[me->v1]);
+ copy_v3_v3(v2_no, vert_normals_dst[me->v2]);
/* We do our transform here, allows to interpolate from normals already in src space. */
if (space_transform) {
@@ -1255,6 +1245,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
const SpaceTransform *space_transform,
const float max_dist,
const float ray_radius,
+ Mesh *mesh_dst,
MVert *verts_dst,
const int numverts_dst,
MEdge *edges_dst,
@@ -1264,7 +1255,6 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
MPoly *polys_dst,
const int numpolys_dst,
CustomData *ldata_dst,
- CustomData *pdata_dst,
const bool use_split_nors_dst,
const float split_angle_dst,
const bool dirty_nors_dst,
@@ -1310,9 +1300,9 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
1) :
0);
- float(*poly_nors_src)[3] = NULL;
- float(*loop_nors_src)[3] = NULL;
- float(*poly_nors_dst)[3] = NULL;
+ const float(*poly_nors_src)[3] = NULL;
+ const float(*loop_nors_src)[3] = NULL;
+ const float(*poly_nors_dst)[3] = NULL;
float(*loop_nors_dst)[3] = NULL;
float(*poly_cents_src)[3] = NULL;
@@ -1369,23 +1359,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
const bool need_pnors_dst = need_lnors_dst || need_pnors_src;
if (need_pnors_dst) {
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- const bool do_poly_nors_dst = (poly_nors_dst == NULL);
- if (!poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(
- pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst || do_poly_nors_dst) {
- BKE_mesh_calc_normals_poly(verts_dst,
- numverts_dst,
- loops_dst,
- numloops_dst,
- polys_dst,
- numpolys_dst,
- poly_nors_dst);
- }
+ poly_nors_dst = BKE_mesh_poly_normals_ensure(mesh_dst);
}
if (need_lnors_dst) {
short(*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
@@ -1400,6 +1374,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
}
if (dirty_nors_dst || do_loop_nors_dst) {
BKE_mesh_normals_loop_split(verts_dst,
+ BKE_mesh_vertex_normals_ensure(mesh_dst),
numverts_dst,
edges_dst,
numedges_dst,
@@ -1407,7 +1382,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
loop_nors_dst,
numloops_dst,
polys_dst,
- (const float(*)[3])poly_nors_dst,
+ poly_nors_dst,
numpolys_dst,
use_split_nors_dst,
split_angle_dst,
@@ -1418,8 +1393,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
}
if (need_pnors_src || need_lnors_src) {
if (need_pnors_src) {
- poly_nors_src = CustomData_get_layer(&me_src->pdata, CD_NORMAL);
- BLI_assert(poly_nors_src != NULL);
+ poly_nors_src = BKE_mesh_poly_normals_ensure(me_src);
}
if (need_lnors_src) {
loop_nors_src = CustomData_get_layer(&me_src->ldata, CD_NORMAL);
@@ -1661,7 +1635,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
if (mesh_remap_bvhtree_query_nearest(
tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
float(*nor_dst)[3];
- float(*nors_src)[3];
+ const float(*nors_src)[3];
float best_nor_dot = -2.0f;
float best_sqdist_fallback = FLT_MAX;
int best_index_src = -1;
@@ -2201,41 +2175,24 @@ void BKE_mesh_remap_calc_polys_from_mesh(const int mode,
const SpaceTransform *space_transform,
const float max_dist,
const float ray_radius,
+ Mesh *mesh_dst,
MVert *verts_dst,
- const int numverts_dst,
MLoop *loops_dst,
- const int numloops_dst,
MPoly *polys_dst,
const int numpolys_dst,
- CustomData *pdata_dst,
- const bool dirty_nors_dst,
Mesh *me_src,
MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
const float max_dist_sq = max_dist * max_dist;
- float(*poly_nors_dst)[3] = NULL;
+ const float(*poly_nors_dst)[3] = NULL;
float tmp_co[3], tmp_no[3];
int i;
BLI_assert(mode & MREMAP_MODE_POLY);
if (mode & (MREMAP_USE_NORMAL | MREMAP_USE_NORPROJ)) {
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- if (!poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst) {
- BKE_mesh_calc_normals_poly(verts_dst,
- numverts_dst,
- loops_dst,
- numloops_dst,
- polys_dst,
- numpolys_dst,
- poly_nors_dst);
- }
+ poly_nors_dst = BKE_mesh_poly_normals_ensure(mesh_dst);
}
BKE_mesh_remap_init(r_map, numpolys_dst);
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
index 9f5703a015d..50464da86e9 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
@@ -31,8 +31,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_array.hh"
-#include "BLI_float3.hh"
#include "BLI_index_range.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "DNA_mesh_types.h"
@@ -410,7 +410,8 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh)
{
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
- const BMeshCreateParams bmesh_create_params = {true};
+ BMeshCreateParams bmesh_create_params{};
+ bmesh_create_params.use_toolflags = true;
BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params);
BMeshFromMeshParams bmesh_from_mesh_params{};
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index 7ac4c29f0ee..e7e5064df7c 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -45,18 +45,53 @@
* \{ */
/**
- * Default values defined at read time.
+ * \brief Initialize the runtime mutexes of the given mesh.
+ *
+ * Any existing mutexes will be overridden.
*/
-void BKE_mesh_runtime_reset(Mesh *mesh)
+static void mesh_runtime_init_mutexes(Mesh *mesh)
{
- memset(&mesh->runtime, 0, sizeof(mesh->runtime));
mesh->runtime.eval_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime eval_mutex");
BLI_mutex_init(mesh->runtime.eval_mutex);
+ mesh->runtime.normals_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime normals_mutex");
+ BLI_mutex_init(mesh->runtime.normals_mutex);
+ mesh->runtime.render_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime render_mutex");
+ BLI_mutex_init(mesh->runtime.render_mutex);
+}
+
+/**
+ * \brief free the mutexes of the given mesh runtime.
+ */
+static void mesh_runtime_free_mutexes(Mesh *mesh)
+{
+ if (mesh->runtime.eval_mutex != NULL) {
+ BLI_mutex_end(mesh->runtime.eval_mutex);
+ MEM_freeN(mesh->runtime.eval_mutex);
+ mesh->runtime.eval_mutex = NULL;
+ }
+ if (mesh->runtime.normals_mutex != NULL) {
+ BLI_mutex_end(mesh->runtime.normals_mutex);
+ MEM_freeN(mesh->runtime.normals_mutex);
+ mesh->runtime.normals_mutex = NULL;
+ }
+ if (mesh->runtime.render_mutex != NULL) {
+ BLI_mutex_end(mesh->runtime.render_mutex);
+ MEM_freeN(mesh->runtime.render_mutex);
+ mesh->runtime.render_mutex = NULL;
+ }
+}
+
+void BKE_mesh_runtime_init_data(Mesh *mesh)
+{
+ mesh_runtime_init_mutexes(mesh);
+}
+
+void BKE_mesh_runtime_free_data(Mesh *mesh)
+{
+ BKE_mesh_runtime_clear_cache(mesh);
+ mesh_runtime_free_mutexes(mesh);
}
-/* Clear all pointers which we don't want to be shared on copying the datablock.
- * However, keep all the flags which defines what the mesh is (for example, that
- * it's deformed only, or that its custom data layers are out of date.) */
void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag))
{
Mesh_Runtime *runtime = &mesh->runtime;
@@ -69,17 +104,11 @@ void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag))
runtime->bvh_cache = NULL;
runtime->shrinkwrap_data = NULL;
- mesh->runtime.eval_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime eval_mutex");
- BLI_mutex_init(mesh->runtime.eval_mutex);
+ mesh_runtime_init_mutexes(mesh);
}
void BKE_mesh_runtime_clear_cache(Mesh *mesh)
{
- if (mesh->runtime.eval_mutex != NULL) {
- BLI_mutex_end(mesh->runtime.eval_mutex);
- MEM_freeN(mesh->runtime.eval_mutex);
- mesh->runtime.eval_mutex = NULL;
- }
if (mesh->runtime.mesh_eval != NULL) {
mesh->runtime.mesh_eval->edit_mesh = NULL;
BKE_id_free(NULL, mesh->runtime.mesh_eval);
@@ -90,7 +119,6 @@ void BKE_mesh_runtime_clear_cache(Mesh *mesh)
BKE_mesh_runtime_clear_edit_data(mesh);
}
-/* This is a ported copy of DM_ensure_looptri_data(dm) */
/**
* Ensure the array is large enough
*
@@ -99,6 +127,7 @@ void BKE_mesh_runtime_clear_cache(Mesh *mesh)
*/
static void mesh_ensure_looptri_data(Mesh *mesh)
{
+ /* This is a ported copy of `DM_ensure_looptri_data(dm)`. */
const uint totpoly = mesh->totpoly;
const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop);
@@ -124,7 +153,6 @@ static void mesh_ensure_looptri_data(Mesh *mesh)
}
}
-/* This is a ported copy of CDDM_recalc_looptri(dm). */
void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
{
mesh_ensure_looptri_data(mesh);
@@ -144,9 +172,9 @@ void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
mesh->runtime.looptris.array_wip = NULL;
}
-/* This is a ported copy of dm_getNumLoopTri(dm). */
int BKE_mesh_runtime_looptri_len(const Mesh *mesh)
{
+ /* This is a ported copy of `dm_getNumLoopTri(dm)`. */
const int looptri_len = poly_to_tri_count(mesh->totpoly, mesh->totloop);
BLI_assert(ELEM(mesh->runtime.looptris.len, 0, looptri_len));
return looptri_len;
@@ -158,11 +186,6 @@ static void mesh_runtime_looptri_recalc_isolated(void *userdata)
BKE_mesh_runtime_looptri_recalc(mesh);
}
-/**
- * \note This function only fills a cache, and therefore the mesh argument can
- * be considered logically const. Concurrent access is protected by a mutex.
- * \note This is a ported copy of dm_getLoopTriArray(dm).
- */
const MLoopTri *BKE_mesh_runtime_looptri_ensure(const Mesh *mesh)
{
ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
@@ -184,7 +207,6 @@ const MLoopTri *BKE_mesh_runtime_looptri_ensure(const Mesh *mesh)
return looptri;
}
-/* This is a copy of DM_verttri_from_looptri(). */
void BKE_mesh_runtime_verttri_from_looptri(MVertTri *r_verttri,
const MLoop *mloop,
const MLoopTri *looptri,
@@ -276,130 +298,10 @@ void BKE_mesh_batch_cache_free(Mesh *me)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Mesh runtime debug helpers.
+/** \name Mesh Runtime Validation
* \{ */
-/* evaluated mesh info printing function,
- * to help track down differences output */
#ifndef NDEBUG
-# include "BLI_dynstr.h"
-
-static void mesh_runtime_debug_info_layers(DynStr *dynstr, CustomData *cd)
-{
- int type;
-
- for (type = 0; type < CD_NUMTYPES; type++) {
- if (CustomData_has_layer(cd, type)) {
- /* NOTE: doesn't account for multiple layers. */
- const char *name = CustomData_layertype_name(type);
- const int size = CustomData_sizeof(type);
- const void *pt = CustomData_get_layer(cd, type);
- const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
- const char *structname;
- int structnum;
- CustomData_file_write_info(type, &structname, &structnum);
- BLI_dynstr_appendf(
- dynstr,
- " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
- name,
- structname,
- type,
- (const void *)pt,
- size,
- pt_size);
- }
- }
-}
-
-char *BKE_mesh_runtime_debug_info(Mesh *me_eval)
-{
- DynStr *dynstr = BLI_dynstr_new();
- char *ret;
-
- BLI_dynstr_append(dynstr, "{\n");
- BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)me_eval);
-# if 0
- const char *tstr;
- switch (me_eval->type) {
- case DM_TYPE_CDDM:
- tstr = "DM_TYPE_CDDM";
- break;
- case DM_TYPE_CCGDM:
- tstr = "DM_TYPE_CCGDM";
- break;
- default:
- tstr = "UNKNOWN";
- break;
- }
- BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr);
-# endif
- BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", me_eval->totvert);
- BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", me_eval->totedge);
- BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me_eval->totface);
- BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me_eval->totpoly);
- BLI_dynstr_appendf(dynstr, " 'deformed_only': %d,\n", me_eval->runtime.deformed_only);
-
- BLI_dynstr_append(dynstr, " 'vertexLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->vdata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'edgeLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->edata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'loopLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->ldata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'polyLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->pdata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'tessFaceLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->fdata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, "}\n");
-
- ret = BLI_dynstr_get_cstring(dynstr);
- BLI_dynstr_free(dynstr);
- return ret;
-}
-
-void BKE_mesh_runtime_debug_print(Mesh *me_eval)
-{
- char *str = BKE_mesh_runtime_debug_info(me_eval);
- puts(str);
- fflush(stdout);
- MEM_freeN(str);
-}
-
-/* XXX Should go in customdata file? */
-void BKE_mesh_runtime_debug_print_cdlayers(CustomData *data)
-{
- int i;
- const CustomDataLayer *layer;
-
- printf("{\n");
-
- for (i = 0, layer = data->layers; i < data->totlayer; i++, layer++) {
-
- const char *name = CustomData_layertype_name(layer->type);
- const int size = CustomData_sizeof(layer->type);
- const char *structname;
- int structnum;
- CustomData_file_write_info(layer->type, &structname, &structnum);
- printf(" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
- name,
- structname,
- layer->type,
- (const void *)layer->data,
- size,
- (int)(MEM_allocN_len(layer->data) / size));
- }
-
- printf("}\n");
-}
bool BKE_mesh_runtime_is_valid(Mesh *me_eval)
{
diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc
index 5388f6e530e..a046cc68bf2 100644
--- a/source/blender/blenkernel/intern/mesh_sample.cc
+++ b/source/blender/blenkernel/intern/mesh_sample.cc
@@ -29,12 +29,13 @@ BLI_NOINLINE static void sample_point_attribute(const Mesh &mesh,
const Span<int> looptri_indices,
const Span<float3> bary_coords,
const VArray<T> &data_in,
+ const IndexMask mask,
const MutableSpan<T> data_out)
{
const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
BKE_mesh_runtime_looptri_len(&mesh)};
- for (const int i : bary_coords.index_range()) {
+ for (const int i : mask) {
const int looptri_index = looptri_indices[i];
const MLoopTri &looptri = looptris[looptri_index];
const float3 &bary_coord = bary_coords[i];
@@ -56,10 +57,9 @@ void sample_point_attribute(const Mesh &mesh,
const Span<int> looptri_indices,
const Span<float3> bary_coords,
const GVArray &data_in,
+ const IndexMask mask,
const GMutableSpan data_out)
{
- BLI_assert(data_out.size() == looptri_indices.size());
- BLI_assert(data_out.size() == bary_coords.size());
BLI_assert(data_in.size() == mesh.totvert);
BLI_assert(data_in.type() == data_out.type());
@@ -67,7 +67,7 @@ void sample_point_attribute(const Mesh &mesh,
attribute_math::convert_to_static_type(type, [&](auto dummy) {
using T = decltype(dummy);
sample_point_attribute<T>(
- mesh, looptri_indices, bary_coords, data_in.typed<T>(), data_out.typed<T>());
+ mesh, looptri_indices, bary_coords, data_in.typed<T>(), mask, data_out.typed<T>());
});
}
@@ -76,12 +76,13 @@ BLI_NOINLINE static void sample_corner_attribute(const Mesh &mesh,
const Span<int> looptri_indices,
const Span<float3> bary_coords,
const VArray<T> &data_in,
+ const IndexMask mask,
const MutableSpan<T> data_out)
{
const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
BKE_mesh_runtime_looptri_len(&mesh)};
- for (const int i : bary_coords.index_range()) {
+ for (const int i : mask) {
const int looptri_index = looptri_indices[i];
const MLoopTri &looptri = looptris[looptri_index];
const float3 &bary_coord = bary_coords[i];
@@ -103,10 +104,9 @@ void sample_corner_attribute(const Mesh &mesh,
const Span<int> looptri_indices,
const Span<float3> bary_coords,
const GVArray &data_in,
+ const IndexMask mask,
const GMutableSpan data_out)
{
- BLI_assert(data_out.size() == looptri_indices.size());
- BLI_assert(data_out.size() == bary_coords.size());
BLI_assert(data_in.size() == mesh.totloop);
BLI_assert(data_in.type() == data_out.type());
@@ -114,7 +114,7 @@ void sample_corner_attribute(const Mesh &mesh,
attribute_math::convert_to_static_type(type, [&](auto dummy) {
using T = decltype(dummy);
sample_corner_attribute<T>(
- mesh, looptri_indices, bary_coords, data_in.typed<T>(), data_out.typed<T>());
+ mesh, looptri_indices, bary_coords, data_in.typed<T>(), mask, data_out.typed<T>());
});
}
@@ -122,12 +122,13 @@ template<typename T>
void sample_face_attribute(const Mesh &mesh,
const Span<int> looptri_indices,
const VArray<T> &data_in,
+ const IndexMask mask,
const MutableSpan<T> data_out)
{
const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
BKE_mesh_runtime_looptri_len(&mesh)};
- for (const int i : data_out.index_range()) {
+ for (const int i : mask) {
const int looptri_index = looptri_indices[i];
const MLoopTri &looptri = looptris[looptri_index];
const int poly_index = looptri.poly;
@@ -138,23 +139,24 @@ void sample_face_attribute(const Mesh &mesh,
void sample_face_attribute(const Mesh &mesh,
const Span<int> looptri_indices,
const GVArray &data_in,
+ const IndexMask mask,
const GMutableSpan data_out)
{
- BLI_assert(data_out.size() == looptri_indices.size());
BLI_assert(data_in.size() == mesh.totpoly);
BLI_assert(data_in.type() == data_out.type());
const CPPType &type = data_in.type();
attribute_math::convert_to_static_type(type, [&](auto dummy) {
using T = decltype(dummy);
- sample_face_attribute<T>(mesh, looptri_indices, data_in.typed<T>(), data_out.typed<T>());
+ sample_face_attribute<T>(mesh, looptri_indices, data_in.typed<T>(), mask, data_out.typed<T>());
});
}
MeshAttributeInterpolator::MeshAttributeInterpolator(const Mesh *mesh,
+ const IndexMask mask,
const Span<float3> positions,
const Span<int> looptri_indices)
- : mesh_(mesh), positions_(positions), looptri_indices_(looptri_indices)
+ : mesh_(mesh), mask_(mask), positions_(positions), looptri_indices_(looptri_indices)
{
BLI_assert(positions.size() == looptri_indices.size());
}
@@ -162,15 +164,15 @@ MeshAttributeInterpolator::MeshAttributeInterpolator(const Mesh *mesh,
Span<float3> MeshAttributeInterpolator::ensure_barycentric_coords()
{
if (!bary_coords_.is_empty()) {
- BLI_assert(bary_coords_.size() == positions_.size());
+ BLI_assert(bary_coords_.size() >= mask_.min_array_size());
return bary_coords_;
}
- bary_coords_.reinitialize(positions_.size());
+ bary_coords_.reinitialize(mask_.min_array_size());
const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(mesh_),
BKE_mesh_runtime_looptri_len(mesh_)};
- for (const int i : bary_coords_.index_range()) {
+ for (const int i : mask_) {
const int looptri_index = looptri_indices_[i];
const MLoopTri &looptri = looptris[looptri_index];
@@ -190,15 +192,15 @@ Span<float3> MeshAttributeInterpolator::ensure_barycentric_coords()
Span<float3> MeshAttributeInterpolator::ensure_nearest_weights()
{
if (!nearest_weights_.is_empty()) {
- BLI_assert(nearest_weights_.size() == positions_.size());
+ BLI_assert(nearest_weights_.size() >= mask_.min_array_size());
return nearest_weights_;
}
- nearest_weights_.reinitialize(positions_.size());
+ nearest_weights_.reinitialize(mask_.min_array_size());
const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(mesh_),
BKE_mesh_runtime_looptri_len(mesh_)};
- for (const int i : nearest_weights_.index_range()) {
+ for (const int i : mask_) {
const int looptri_index = looptri_indices_[i];
const MLoopTri &looptri = looptris[looptri_index];
@@ -215,22 +217,18 @@ Span<float3> MeshAttributeInterpolator::ensure_nearest_weights()
return nearest_weights_;
}
-void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_attribute,
- OutputAttribute &dst_attribute,
- eAttributeMapMode mode)
+void MeshAttributeInterpolator::sample_data(const GVArray &src,
+ const AttributeDomain domain,
+ const eAttributeMapMode mode,
+ const GMutableSpan dst)
{
- if (!src_attribute || !dst_attribute) {
- return;
- }
- const GVArray &src_varray = *src_attribute.varray;
- GMutableSpan dst_span = dst_attribute.as_span();
- if (src_varray.is_empty() || dst_span.is_empty()) {
+ if (src.is_empty() || dst.is_empty()) {
return;
}
/* Compute barycentric coordinates only when they are needed. */
Span<float3> weights;
- if (ELEM(src_attribute.domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
+ if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
switch (mode) {
case eAttributeMapMode::INTERPOLATED:
weights = ensure_barycentric_coords();
@@ -242,17 +240,17 @@ void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_
}
/* Interpolate the source attributes on the surface. */
- switch (src_attribute.domain) {
+ switch (domain) {
case ATTR_DOMAIN_POINT: {
- sample_point_attribute(*mesh_, looptri_indices_, weights, src_varray, dst_span);
+ sample_point_attribute(*mesh_, looptri_indices_, weights, src, mask_, dst);
break;
}
case ATTR_DOMAIN_FACE: {
- sample_face_attribute(*mesh_, looptri_indices_, src_varray, dst_span);
+ sample_face_attribute(*mesh_, looptri_indices_, src, mask_, dst);
break;
}
case ATTR_DOMAIN_CORNER: {
- sample_corner_attribute(*mesh_, looptri_indices_, weights, src_varray, dst_span);
+ sample_corner_attribute(*mesh_, looptri_indices_, weights, src, mask_, dst);
break;
}
case ATTR_DOMAIN_EDGE: {
@@ -266,4 +264,13 @@ void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_
}
}
+void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_attribute,
+ OutputAttribute &dst_attribute,
+ eAttributeMapMode mode)
+{
+ if (src_attribute && dst_attribute) {
+ this->sample_data(src_attribute.varray, src_attribute.domain, mode, dst_attribute.as_span());
+ }
+}
+
} // namespace blender::bke::mesh_surface_sample
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
index e5e971fd574..73cef6b925b 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.c
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -115,12 +115,6 @@ static void set_tspace(const SMikkTSpaceContext *pContext,
p_res[3] = face_sign;
}
-/**
- * Compute simplified tangent space normals, i.e.
- * tangent vector + sign of bi-tangent one, which combined with
- * split normals can be used to recreate the full tangent space.
- * NOTE: * The mesh should be made of only tris and quads!
- */
void BKE_mesh_calc_loop_tangent_single_ex(const MVert *mverts,
const int UNUSED(numVerts),
const MLoop *mloops,
@@ -172,12 +166,6 @@ void BKE_mesh_calc_loop_tangent_single_ex(const MVert *mverts,
}
}
-/**
- * Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code.
- * \note
- * - There must be a valid loop's CD_NORMALS available.
- * - The mesh should be made of only tris and quads!
- */
void BKE_mesh_calc_loop_tangent_single(Mesh *mesh,
const char *uvmap,
float (*r_looptangents)[4],
@@ -236,7 +224,8 @@ typedef struct {
MLoopUV *mloopuv; /* texture coordinates */
const MPoly *mpoly; /* indices */
const MLoop *mloop; /* indices */
- const MVert *mvert; /* vertices & normals */
+ const MVert *mvert; /* vertex coordinates */
+ const float (*vert_normals)[3];
const float (*orco)[3];
float (*tangent)[4]; /* destination */
int numTessFaces;
@@ -410,8 +399,7 @@ finally:
}
}
else {
- const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no;
- normal_short_to_float_v3(r_no, no);
+ copy_v3_v3(r_no, pMesh->vert_normals[pMesh->mloop[loop_index].v]);
}
}
@@ -485,12 +473,6 @@ void BKE_mesh_add_loop_tangent_named_layer_for_uv(CustomData *uv_data,
}
}
-/**
- * Here we get some useful information such as active uv layer name and
- * search if it is already in tangent_names.
- * Also, we calculate tangent_mask that works as a descriptor of tangents state.
- * If tangent_mask has changed, then recalculate tangents.
- */
void BKE_mesh_calc_loop_tangent_step_0(const CustomData *loopData,
bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME],
@@ -564,9 +546,6 @@ void BKE_mesh_calc_loop_tangent_step_0(const CustomData *loopData,
}
}
-/**
- * See: #BKE_editmesh_loop_tangent_calc (matching logic).
- */
void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
const MPoly *mpoly,
const uint mpoly_len,
@@ -578,6 +557,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME],
int tangent_names_len,
+ const float (*vert_normals)[3],
const float (*poly_normals)[3],
const float (*loop_normals)[3],
const float (*vert_orco)[3],
@@ -672,6 +652,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
#endif
mesh2tangent->mvert = mvert;
+ mesh2tangent->vert_normals = vert_normals;
mesh2tangent->mpoly = mpoly;
mesh2tangent->mloop = mloop;
mesh2tangent->looptri = looptri;
@@ -764,7 +745,8 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
calc_active_tangent,
tangent_names,
tangent_names_len,
- CustomData_get_layer(&me_eval->pdata, CD_NORMAL),
+ BKE_mesh_vertex_normals_ensure(me_eval),
+ BKE_mesh_poly_normals_ensure(me_eval),
CustomData_get_layer(&me_eval->ldata, CD_NORMAL),
CustomData_get_layer(&me_eval->vdata, CD_ORCO), /* may be NULL */
/* result */
diff --git a/source/blender/blenkernel/intern/mesh_tessellate.c b/source/blender/blenkernel/intern/mesh_tessellate.c
index 213f2929d63..241aefc418c 100644
--- a/source/blender/blenkernel/intern/mesh_tessellate.c
+++ b/source/blender/blenkernel/intern/mesh_tessellate.c
@@ -154,17 +154,6 @@ static void mesh_loops_to_tessdata(CustomData *fdata,
}
}
-/**
- * Recreate #MFace Tessellation.
- *
- * \param do_face_nor_copy: Controls whether the normals from the poly
- * are copied to the tessellated faces.
- *
- * \return number of tessellation faces.
- *
- * \note This doesn't use multi-threading like #BKE_mesh_recalc_looptri since
- * it's not used in many places and #MFace should be phased out.
- */
int BKE_mesh_tessface_calc_ex(CustomData *fdata,
CustomData *ldata,
CustomData *pdata,
@@ -712,9 +701,6 @@ static void mesh_recalc_looptri__multi_threaded(const MLoop *mloop,
&settings);
}
-/**
- * Calculate tessellation into #MLoopTri which exist only for this purpose.
- */
void BKE_mesh_recalc_looptri(const MLoop *mloop,
const MPoly *mpoly,
const MVert *mvert,
@@ -730,14 +716,6 @@ void BKE_mesh_recalc_looptri(const MLoop *mloop,
}
}
-/**
- * A version of #BKE_mesh_recalc_looptri which takes pre-calculated polygon normals
- * (used to avoid having to calculate the face normal for NGON tessellation).
- *
- * \note Only use this function if normals have already been calculated, there is no need
- * to calculate normals just to use this function as it will cause the normals for triangles
- * to be calculated which aren't needed for tessellation.
- */
void BKE_mesh_recalc_looptri_with_normals(const MLoop *mloop,
const MPoly *mpoly,
const MVert *mvert,
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 08668d55cf4..005c916b4e0 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -193,6 +193,7 @@ static int search_polyloop_cmp(const void *v1, const void *v2)
/* Else, sort on loopstart. */
return sp1->loopstart > sp2->loopstart ? 1 : sp1->loopstart < sp2->loopstart ? -1 : 0;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -213,21 +214,6 @@ static int search_polyloop_cmp(const void *v1, const void *v2)
} \
} while (0)
-/**
- * Validate the mesh, \a do_fixes requires \a mesh to be non-null.
- *
- * \return false if no changes needed to be made.
- *
- * Vertex Normals
- * ==============
- *
- * While zeroed normals are checked, these checks aren't comprehensive.
- * Technically, to detect errors here a normal recalculation and comparison is necessary.
- * However this function is mainly to prevent severe errors in geometry
- * (invalid data that will crash Blender, or cause some features to behave incorrectly),
- * not to detect subtle differences in the resulting normals which could be caused
- * by importers that load normals (for example).
- */
/* NOLINTNEXTLINE: readability-function-size */
bool BKE_mesh_validate_arrays(Mesh *mesh,
MVert *mverts,
@@ -317,6 +303,12 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
recalc_flag.edges = do_fixes;
}
+ const float(*vert_normals)[3] = NULL;
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
+ if (!BKE_mesh_vertex_normals_are_dirty(mesh)) {
+ vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
+ }
+
for (i = 0; i < totvert; i++, mv++) {
bool fix_normal = true;
@@ -331,13 +323,13 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
}
}
- if (mv->no[j] != 0) {
+ if (vert_normals && vert_normals[i][j] != 0.0f) {
fix_normal = false;
break;
}
}
- if (fix_normal) {
+ if (vert_normals && fix_normal) {
/* If the vertex normal accumulates to zero or isn't part of a face, the location is used.
* When the location is also zero, a zero normal warning should not be raised.
* since this is the expected behavior of normal calculation.
@@ -350,7 +342,8 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
if (!is_zero_v3(mv->co)) {
PRINT_ERR("\tVertex %u: has zero normal, assuming Z-up normal", i);
if (do_fixes) {
- mv->no[2] = SHRT_MAX;
+ float *normal = (float *)vert_normals[i];
+ normal[2] = 1.0f;
fix_flag.verts = true;
}
}
@@ -997,9 +990,6 @@ static bool mesh_validate_customdata(CustomData *data,
return is_valid;
}
-/**
- * \returns is_valid.
- */
bool BKE_mesh_validate_all_customdata(CustomData *vdata,
const uint totvert,
CustomData *edata,
@@ -1018,6 +1008,10 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata,
CustomData_MeshMasks mask = {0};
if (check_meshmask) {
mask = CD_MASK_MESH;
+ /* Normal data isn't in the mask since it is derived data,
+ * but it is valid and should not be removed. */
+ mask.vmask |= CD_MASK_NORMAL;
+ mask.pmask |= CD_MASK_NORMAL;
}
is_valid &= mesh_validate_customdata(
@@ -1061,11 +1055,6 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata,
return is_valid;
}
-/**
- * Validates and corrects a Mesh.
- *
- * \returns true if a change is made.
- */
bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_mask)
{
bool is_valid = true;
@@ -1112,13 +1101,6 @@ bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_
return false;
}
-/**
- * Checks if a Mesh is valid without any modification. This is always verbose.
- *
- * \see #DM_is_valid to call on derived meshes
- *
- * \returns is_valid.
- */
bool BKE_mesh_is_valid(Mesh *me)
{
const bool do_verbose = true;
@@ -1127,6 +1109,8 @@ bool BKE_mesh_is_valid(Mesh *me)
bool is_valid = true;
bool changed = true;
+ BKE_mesh_assert_normals_dirty_or_calculated(me);
+
is_valid &= BKE_mesh_validate_all_customdata(
&me->vdata,
me->totvert,
@@ -1162,10 +1146,6 @@ bool BKE_mesh_is_valid(Mesh *me)
return is_valid;
}
-/**
- * Check all material indices of polygons are valid, invalid ones are set to 0.
- * \returns is_valid.
- */
bool BKE_mesh_validate_material_indices(Mesh *me)
{
/* Cast to unsigned to catch negative indices too. */
@@ -1196,9 +1176,9 @@ bool BKE_mesh_validate_material_indices(Mesh *me)
/** \name Mesh Stripping (removing invalid data)
* \{ */
-/* We need to keep this for edge creation (for now?), and some old readfile code... */
void BKE_mesh_strip_loose_faces(Mesh *me)
{
+ /* NOTE: We need to keep this for edge creation (for now?), and some old `readfile.c` code. */
MFace *f;
int a, b;
@@ -1217,13 +1197,6 @@ void BKE_mesh_strip_loose_faces(Mesh *me)
}
}
-/**
- * Works on both loops and polys!
- *
- * \note It won't try to guess which loops of an invalid poly to remove!
- * this is the work of the caller, to mark those loops...
- * See e.g. #BKE_mesh_validate_arrays().
- */
void BKE_mesh_strip_loose_polysloops(Mesh *me)
{
MPoly *p;
@@ -1329,6 +1302,7 @@ void BKE_mesh_strip_loose_edges(Mesh *me)
MEM_freeN(new_idx);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1512,10 +1486,6 @@ static void mesh_calc_edges_mdata(MVert *UNUSED(allvert),
*r_totedge = totedge_final;
}
-/**
- * If the mesh is from a very old blender version,
- * convert mface->edcode to edge drawflags
- */
void BKE_mesh_calc_edges_legacy(Mesh *me, const bool use_old)
{
MEdge *medge;
@@ -1565,12 +1535,6 @@ void BKE_mesh_calc_edges_loose(Mesh *mesh)
}
}
-/**
- * Calculate/create edges from tessface data
- *
- * \param mesh: The mesh to add edges into
- */
-
void BKE_mesh_calc_edges_tessface(Mesh *mesh)
{
const int numFaces = mesh->totface;
diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc
index 574ab785445..c8fae3cf880 100644
--- a/source/blender/blenkernel/intern/mesh_validate.cc
+++ b/source/blender/blenkernel/intern/mesh_validate.cc
@@ -220,9 +220,6 @@ static void clear_hash_tables(MutableSpan<EdgeMap> edge_maps)
} // namespace blender::bke::calc_edges
-/**
- * Calculate edges from polygons.
- */
void BKE_mesh_calc_edges(Mesh *mesh, bool keep_existing_edges, const bool select_new_edges)
{
using namespace blender;
diff --git a/source/blender/blenkernel/intern/mesh_wrapper.c b/source/blender/blenkernel/intern/mesh_wrapper.c
index bc1ffeb8cf4..d1f15cf9007 100644
--- a/source/blender/blenkernel/intern/mesh_wrapper.c
+++ b/source/blender/blenkernel/intern/mesh_wrapper.c
@@ -36,6 +36,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BLI_ghash.h"
@@ -50,8 +51,14 @@
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_wrapper.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_mesh.h"
+#include "BKE_subdiv_modifier.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em,
const CustomData_MeshMasks *cd_mask_extra,
@@ -106,7 +113,8 @@ static void mesh_wrapper_ensure_mdata_isolated(void *userdata)
me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA;
switch (geom_type_orig) {
- case ME_WRAPPER_TYPE_MDATA: {
+ case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD: {
break; /* Quiet warning. */
}
case ME_WRAPPER_TYPE_BMESH: {
@@ -157,6 +165,7 @@ bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3])
case ME_WRAPPER_TYPE_BMESH:
return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime.edit_data, min, max);
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return BKE_mesh_minmax(me, min, max);
}
BLI_assert_unreachable();
@@ -191,7 +200,8 @@ void BKE_mesh_wrapper_vert_coords_copy(const Mesh *me,
}
return;
}
- case ME_WRAPPER_TYPE_MDATA: {
+ case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD: {
BLI_assert(vert_coords_len <= me->totvert);
const MVert *mvert = me->mvert;
for (int i = 0; i < vert_coords_len; i++) {
@@ -228,7 +238,8 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *me,
}
return;
}
- case ME_WRAPPER_TYPE_MDATA: {
+ case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD: {
BLI_assert(vert_coords_len == me->totvert);
const MVert *mvert = me->mvert;
for (int i = 0; i < vert_coords_len; i++) {
@@ -252,6 +263,7 @@ int BKE_mesh_wrapper_vert_len(const Mesh *me)
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totvert;
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return me->totvert;
}
BLI_assert_unreachable();
@@ -264,6 +276,7 @@ int BKE_mesh_wrapper_edge_len(const Mesh *me)
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totedge;
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return me->totedge;
}
BLI_assert_unreachable();
@@ -276,6 +289,7 @@ int BKE_mesh_wrapper_loop_len(const Mesh *me)
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totloop;
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return me->totloop;
}
BLI_assert_unreachable();
@@ -288,6 +302,7 @@ int BKE_mesh_wrapper_poly_len(const Mesh *me)
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totface;
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return me->totpoly;
}
BLI_assert_unreachable();
@@ -295,3 +310,73 @@ int BKE_mesh_wrapper_poly_len(const Mesh *me)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name CPU Subdivision Evaluation
+ * \{ */
+
+Mesh *BKE_mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
+{
+ ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex;
+ BLI_mutex_lock(mesh_eval_mutex);
+
+ if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_SUBD) {
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me->runtime.mesh_eval;
+ }
+
+ SubsurfModifierData *smd = BKE_object_get_last_subsurf_modifier(ob);
+ if (!smd) {
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me;
+ }
+
+ /* Initialize the settings before ensuring the descriptor as this is checked to decide whether
+ * subdivision is needed at all, and checking the descriptor status might involve checking if the
+ * data is out-of-date, which is a very expensive operation. */
+ SubdivToMeshSettings mesh_settings;
+ mesh_settings.resolution = me->runtime.subsurf_resolution;
+ mesh_settings.use_optimal_display = me->runtime.subsurf_use_optimal_display;
+
+ if (mesh_settings.resolution < 3) {
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me;
+ }
+
+ const bool apply_render = me->runtime.subsurf_apply_render;
+
+ SubdivSettings subdiv_settings;
+ BKE_subsurf_modifier_subdiv_settings_init(&subdiv_settings, smd, apply_render);
+ if (subdiv_settings.level == 0) {
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me;
+ }
+
+ SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
+
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &subdiv_settings, me, false);
+ if (subdiv == NULL) {
+ /* Happens on bad topology, but also on empty input mesh. */
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me;
+ }
+
+ Mesh *subdiv_mesh = BKE_subdiv_to_mesh(subdiv, &mesh_settings, me);
+
+ if (subdiv != runtime_data->subdiv) {
+ BKE_subdiv_free(subdiv);
+ }
+
+ if (subdiv_mesh != me) {
+ if (me->runtime.mesh_eval != NULL) {
+ BKE_id_free(NULL, me->runtime.mesh_eval);
+ }
+ me->runtime.mesh_eval = subdiv_mesh;
+ me->runtime.wrapper_type = ME_WRAPPER_TYPE_SUBD;
+ }
+
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me->runtime.mesh_eval;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 6f6cf12f023..e1fd8ff45d1 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -133,9 +133,6 @@ const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type)
return NULL;
}
-/**
- * Get the idname of the modifier type's panel, which was defined in the #panelRegister callback.
- */
void BKE_modifier_type_panel_id(ModifierType type, char *r_idname)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(type);
@@ -213,9 +210,6 @@ void BKE_modifier_free(ModifierData *md)
BKE_modifier_free_ex(md, 0);
}
-/**
- * Use instead of `BLI_remlink` when the object's active modifier should change.
- */
void BKE_modifier_remove_from_list(Object *ob, ModifierData *md)
{
BLI_assert(BLI_findindex(&ob->modifiers, md) != -1);
@@ -328,9 +322,6 @@ void BKE_modifiers_foreach_tex_link(Object *ob, TexWalkFunc walk, void *userData
}
}
-/* callback's can use this
- * to avoid copying every member.
- */
void BKE_modifier_copydata_generic(const ModifierData *md_src,
ModifierData *md_dst,
const int UNUSED(flag))
@@ -457,13 +448,6 @@ void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *_for
CLOG_ERROR(&LOG, "Object: \"%s\", Modifier: \"%s\", %s", ob->id.name + 2, md->name, md->error);
}
-/* used for buttons, to find out if the 'draw deformed in editmode' option is
- * there
- *
- * also used in transform_conversion.c, to detect CrazySpace [tm] (2nd arg
- * then is NULL)
- * also used for some mesh tools to give warnings
- */
int BKE_modifiers_get_cage_index(const Scene *scene,
Object *ob,
int *r_lastPossibleCageIndex,
@@ -547,12 +531,6 @@ bool BKE_modifiers_is_particle_enabled(Object *ob)
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
-/**
- * Check whether is enabled.
- *
- * \param scene: Current scene, may be NULL,
- * in which case isDisabled callback of the modifier is never called.
- */
bool BKE_modifier_is_enabled(const struct Scene *scene, ModifierData *md, int required_mode)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
@@ -575,12 +553,6 @@ bool BKE_modifier_is_enabled(const struct Scene *scene, ModifierData *md, int re
return true;
}
-/**
- * Check whether given modifier is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param md: May be NULL, in which case we consider it as a non-local modifier case.
- */
bool BKE_modifier_is_nonlocal_in_liboverride(const Object *ob, const ModifierData *md)
{
return (ID_IS_OVERRIDE_LIBRARY(ob) &&
@@ -674,8 +646,6 @@ ModifierData *BKE_modifier_get_last_preview(const struct Scene *scene,
return tmp_md;
}
-/* This is to include things that are not modifiers in the evaluation of the modifier stack, for
- * example parenting to an armature. */
ModifierData *BKE_modifiers_get_virtual_modifierlist(const Object *ob,
VirtualModifierData *virtualModifierData)
{
@@ -719,9 +689,6 @@ ModifierData *BKE_modifiers_get_virtual_modifierlist(const Object *ob,
return md;
}
-/* Takes an object and returns its first selected armature, else just its armature
- * This should work for multiple armatures per object
- */
Object *BKE_modifiers_is_deformed_by_armature(Object *ob)
{
if (ob->type == OB_GPENCIL) {
@@ -790,9 +757,6 @@ Object *BKE_modifiers_is_deformed_by_meshdeform(Object *ob)
return NULL;
}
-/* Takes an object and returns its first selected lattice, else just its lattice
- * This should work for multiple lattices per object
- */
Object *BKE_modifiers_is_deformed_by_lattice(Object *ob)
{
VirtualModifierData virtualModifierData;
@@ -816,9 +780,6 @@ Object *BKE_modifiers_is_deformed_by_lattice(Object *ob)
return NULL;
}
-/* Takes an object and returns its first selected curve, else just its curve
- * This should work for multiple curves per object
- */
Object *BKE_modifiers_is_deformed_by_curve(Object *ob)
{
VirtualModifierData virtualModifierData;
@@ -946,7 +907,6 @@ void BKE_modifier_free_temporary_data(ModifierData *md)
}
}
-/* ensure modifier correctness when changing ob->data */
void BKE_modifiers_test_object(Object *ob)
{
ModifierData *md;
@@ -967,45 +927,29 @@ void BKE_modifiers_test_object(Object *ob)
}
}
-/* where should this go?, it doesn't fit well anywhere :S - campbell */
-
-/* elubie: changed this to default to the same dir as the render output
- * to prevent saving to C:\ on Windows */
-
-/* campbell: logic behind this...
- *
- * - if the ID is from a library, return library path
- * - else if the file has been saved return the blend file path.
- * - else if the file isn't saved and the ID isn't from a library, return the temp dir.
- */
const char *BKE_modifier_path_relbase(Main *bmain, Object *ob)
{
- if (G.relbase_valid || ID_IS_LINKED(ob)) {
+ /* - If the ID is from a library, return library path.
+ * - Else if the file has been saved return the blend file path.
+ * - Else if the file isn't saved and the ID isn't from a library, return the temp dir.
+ */
+ if ((bmain->filepath[0] != '\0') || ID_IS_LINKED(ob)) {
return ID_BLEND_PATH(bmain, &ob->id);
}
- /* last resort, better than using "" which resolves to the current
- * working directory */
+ /* Last resort, better than using "" which resolves to the current working directory. */
return BKE_tempdir_session();
}
const char *BKE_modifier_path_relbase_from_global(Object *ob)
{
- if (G.relbase_valid || ID_IS_LINKED(ob)) {
- return ID_BLEND_PATH_FROM_GLOBAL(&ob->id);
- }
-
- /* last resort, better than using "" which resolves to the current
- * working directory */
- return BKE_tempdir_session();
+ return BKE_modifier_path_relbase(G_MAIN, ob);
}
-/* initializes the path with either */
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
{
- /* elubie: changed this to default to the same dir as the render output
- * to prevent saving to C:\ on Windows */
- BLI_join_dirfile(path, path_maxlen, G.relbase_valid ? "//" : BKE_tempdir_session(), name);
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ BLI_join_dirfile(path, path_maxlen, blendfile_path[0] ? "//" : BKE_tempdir_session(), name);
}
/**
@@ -1026,6 +970,7 @@ static void modwrap_dependsOnNormals(Mesh *me)
}
break;
}
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
BKE_mesh_calc_normals(me);
break;
@@ -1039,7 +984,6 @@ struct Mesh *BKE_modifier_modify_mesh(ModifierData *md,
struct Mesh *me)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- BLI_assert(CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
if ((mti->flags & eModifierTypeFlag_AcceptsBMesh) == 0) {
@@ -1060,8 +1004,6 @@ void BKE_modifier_deform_verts(ModifierData *md,
int numVerts)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
-
if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
modwrap_dependsOnNormals(me);
}
@@ -1076,8 +1018,6 @@ void BKE_modifier_deform_vertsEM(ModifierData *md,
int numVerts)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
-
if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
BKE_mesh_calc_normals(me);
}
@@ -1086,15 +1026,6 @@ void BKE_modifier_deform_vertsEM(ModifierData *md,
/* end modifier callback wrappers */
-/**
- * Get evaluated mesh for other evaluated object, which is used as an operand for the modifier,
- * e.g. second operand for boolean modifier.
- * Note that modifiers in stack always get fully evaluated COW ID pointers,
- * never original ones. Makes things simpler.
- *
- * \param get_cage_mesh: Return evaluated mesh with only deforming modifiers applied
- * (i.e. mesh topology remains the same as original one, a.k.a. 'cage' mesh).
- */
Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval,
const bool get_cage_mesh)
{
@@ -1105,8 +1036,11 @@ Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval,
BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
/* 'em' might not exist yet in some cases, just after loading a .blend file, see T57878. */
if (em != NULL) {
- me = (get_cage_mesh && em->mesh_eval_cage != NULL) ? em->mesh_eval_cage :
- em->mesh_eval_final;
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval);
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
+
+ me = (get_cage_mesh && editmesh_eval_cage != NULL) ? editmesh_eval_cage :
+ editmesh_eval_final;
}
}
if (me == NULL) {
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 0c2ac841b87..88da789cdc4 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -60,6 +60,7 @@
#include "BLT_translation.h"
#include "BKE_anim_data.h"
+#include "BKE_bpath.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
@@ -69,6 +70,7 @@
#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
#include "IMB_imbuf.h"
@@ -104,7 +106,7 @@ static void movie_clip_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_s
MovieClip *movie_clip_dst = (MovieClip *)id_dst;
const MovieClip *movie_clip_src = (const MovieClip *)id_src;
- /* We never handle usercount here for own data. */
+ /* We never handle user-count here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
movie_clip_dst->anim = NULL;
@@ -132,19 +134,19 @@ static void movie_clip_foreach_id(ID *id, LibraryForeachIDData *data)
MovieClip *movie_clip = (MovieClip *)id;
MovieTracking *tracking = &movie_clip->tracking;
- BKE_LIB_FOREACHID_PROCESS(data, movie_clip->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, movie_clip->gpd, IDWALK_CB_USER);
LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking->tracks) {
- BKE_LIB_FOREACHID_PROCESS(data, track->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, track->gpd, IDWALK_CB_USER);
}
LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) {
LISTBASE_FOREACH (MovieTrackingTrack *, track, &object->tracks) {
- BKE_LIB_FOREACHID_PROCESS(data, track->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, track->gpd, IDWALK_CB_USER);
}
}
LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking->plane_tracks) {
- BKE_LIB_FOREACHID_PROCESS(data, plane_track->image, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, plane_track->image, IDWALK_CB_USER);
}
}
@@ -165,6 +167,12 @@ static void movie_clip_foreach_cache(ID *id,
function_callback(id, &key, (void **)&movie_clip->tracking.camera.intrinsics, 0, user_data);
}
+static void movie_clip_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ MovieClip *movie_clip = (MovieClip *)id;
+ BKE_bpath_foreach_path_fixed_process(bpath_data, movie_clip->filepath);
+}
+
static void write_movieTracks(BlendWriter *writer, ListBase *tracks)
{
MovieTrackingTrack *track;
@@ -347,6 +355,7 @@ IDTypeInfo IDType_ID_MC = {
.name_plural = "movieclips",
.translation_context = BLT_I18NCONTEXT_ID_MOVIECLIP,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = movie_clip_init_data,
.copy_data = movie_clip_copy_data,
@@ -354,6 +363,7 @@ IDTypeInfo IDType_ID_MC = {
.make_local = NULL,
.foreach_id = movie_clip_foreach_id,
.foreach_cache = movie_clip_foreach_cache,
+ .foreach_path = movie_clip_foreach_path,
.owner_get = NULL,
.blend_write = movieclip_blend_write,
@@ -535,10 +545,6 @@ static void movieclip_convert_multilayer_add_pass(void *UNUSED(layer),
#endif /* WITH_OPENEXR */
-/* Will try to make image buffer usable when originating from the multi-layer
- * source.
- * Internally finds a first combined pass and uses that as a buffer. Not ideal,
- * but is better than a complete empty buffer. */
void BKE_movieclip_convert_multilayer_ibuf(struct ImBuf *ibuf)
{
if (ibuf == NULL) {
@@ -842,7 +848,7 @@ static ImBuf *get_imbuf_cache(MovieClip *clip, const MovieClipUser *user, int fl
key.render_flag = 0;
}
- return IMB_moviecache_get(clip->cache->moviecache, &key);
+ return IMB_moviecache_get(clip->cache->moviecache, &key, NULL);
}
return NULL;
@@ -947,7 +953,7 @@ static MovieClip *movieclip_alloc(Main *bmain, const char *name)
static void movieclip_load_get_size(MovieClip *clip)
{
int width, height;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, 1);
BKE_movieclip_get_size(clip, &user, &width, &height);
@@ -979,10 +985,6 @@ static void detect_clip_source(Main *bmain, MovieClip *clip)
}
}
-/* checks if image was already loaded, then returns same image
- * otherwise creates new.
- * does not load ibuf itself
- * pass on optional frame for #name images */
MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
{
MovieClip *clip;
@@ -1176,7 +1178,7 @@ static ImBuf *get_postprocessed_cached_frame(const MovieClip *clip,
return NULL;
}
- /* postprocessing happened for other frame */
+ /* Postprocessing happened for other frame. */
if (cache->postprocessed.framenr != framenr) {
return NULL;
}
@@ -1612,7 +1614,6 @@ void BKE_movieclip_get_aspect(MovieClip *clip, float *aspx, float *aspy)
*aspy = clip->aspy / clip->aspx / clip->tracking.camera.pixel_aspect;
}
-/* get segments of cached frames. useful for debugging cache policies */
void BKE_movieclip_get_cache_segments(MovieClip *clip,
MovieClipUser *user,
int *r_totseg,
@@ -1695,17 +1696,7 @@ void BKE_movieclip_reload(Main *bmain, MovieClip *clip)
movieclip_calc_length(clip);
- /* same as for image update -- don't use notifiers because they are not 100% sure to succeeded
- * (node trees which are not currently visible wouldn't be refreshed)
- */
- {
- Scene *scene;
- for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
- if (scene->nodetree) {
- nodeUpdateID(scene->nodetree, &clip->id);
- }
- }
- }
+ BKE_ntree_update_tag_id_changed(bmain, &clip->id);
}
void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClipScopes *scopes)
@@ -1848,9 +1839,6 @@ static void movieclip_build_proxy_ibuf(
IMB_freeImBuf(scaleibuf);
}
-/* NOTE: currently used by proxy job for movies, threading happens within single frame
- * (meaning scaling shall be threaded)
- */
void BKE_movieclip_build_proxy_frame(MovieClip *clip,
int clip_flag,
struct MovieDistortion *distortion,
@@ -1892,9 +1880,6 @@ void BKE_movieclip_build_proxy_frame(MovieClip *clip,
}
}
-/* NOTE: currently used by proxy job for sequences, threading happens within sequence
- * (different threads handles different frames, no threading within frame is needed)
- */
void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip,
ImBuf *ibuf,
struct MovieDistortion *distortion,
@@ -1925,6 +1910,11 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip,
}
}
+bool BKE_movieclip_proxy_enabled(MovieClip *clip)
+{
+ return clip->flag & MCLIP_USE_PROXY;
+}
+
float BKE_movieclip_remap_scene_to_clip_frame(const MovieClip *clip, float framenr)
{
return framenr - (float)clip->start_frame + 1.0f;
@@ -2145,4 +2135,5 @@ void BKE_movieclip_free_gputexture(struct MovieClip *clip)
MEM_freeN(tex);
}
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index eaa11a6683a..fbad7d98630 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -330,9 +330,6 @@ MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *
return NULL;
}
-/* used for applying scale on mdisps layer and syncing subdivide levels when joining objects
- * use_first - return first multires modifier if all multires'es are disabled
- */
MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, bool use_first)
{
ModifierData *md;
@@ -519,7 +516,6 @@ static int get_levels_from_disps(Object *ob)
return totlvl;
}
-/* reset the multires levels to match the number of mdisps */
void multiresModifier_set_levels_from_disps(MultiresModifierData *mmd, Object *ob)
{
Mesh *me = ob->data;
@@ -712,7 +708,6 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
multires_set_tot_level(ob, mmd, lvl);
}
-/* (direction = 1) for delete higher, (direction = 0) for lower (not implemented yet) */
void multiresModifier_del_levels(MultiresModifierData *mmd,
Scene *scene,
Object *ob,
@@ -1295,7 +1290,6 @@ DerivedMesh *multires_make_derived_from_derived(
return result;
}
-/* Adapted from sculptmode.c */
void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v)
{
int x, y, x2, y2;
@@ -1349,8 +1343,6 @@ void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u,
add_v3_v3v3(out, d2[0], d2[1]);
}
-/* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them
- * such that 'ob_dst' has the same total number of levels as 'ob_src'. */
void multiresModifier_sync_levels_ex(Object *ob_dst,
MultiresModifierData *mmd_src,
MultiresModifierData *mmd_dst)
@@ -1469,7 +1461,6 @@ void multiresModifier_prepare_join(struct Depsgraph *depsgraph,
multires_apply_smat(depsgraph, scene, ob, mat);
}
-/* update multires data after topology changing */
void multires_topology_changed(Mesh *me)
{
MDisps *mdisp = NULL, *cur = NULL;
@@ -1496,7 +1487,7 @@ void multires_topology_changed(Mesh *me)
if (!mdisp->totdisp || !mdisp->disps) {
if (grid) {
mdisp->totdisp = grid;
- mdisp->disps = MEM_calloc_arrayN(sizeof(float[3]), mdisp->totdisp, "mdisp topology");
+ mdisp->disps = MEM_calloc_arrayN(mdisp->totdisp, sizeof(float[3]), "mdisp topology");
}
continue;
@@ -1504,11 +1495,6 @@ void multires_topology_changed(Mesh *me)
}
}
-/* Makes sure data from an external file is fully read.
- *
- * Since the multires data files only contain displacement vectors without knowledge about
- * subdivision level some extra work is needed. Namely make is to all displacement grids have
- * proper level and number of displacement vectors set. */
void multires_ensure_external_read(struct Mesh *mesh, int top_level)
{
if (!CustomData_external_test(&mesh->ldata, CD_MDISPS)) {
@@ -1544,7 +1530,6 @@ void multiresModifier_ensure_external_read(struct Mesh *mesh, const MultiresModi
/***************** Multires interpolation stuff *****************/
-/* Find per-corner coordinate with given per-face UV coord */
int mdisp_rot_face_to_crn(struct MVert *UNUSED(mvert),
struct MPoly *mpoly,
struct MLoop *UNUSED(mloop),
diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c
index bd52d70b223..e0bb3cf792c 100644
--- a/source/blender/blenkernel/intern/multires_reshape.c
+++ b/source/blender/blenkernel/intern/multires_reshape.c
@@ -69,10 +69,6 @@ bool multiresModifier_reshapeFromVertcos(struct Depsgraph *depsgraph,
return true;
}
-/* Returns truth on success, false otherwise.
- *
- * This function might fail in cases like source and destination not having
- * matched amount of vertices. */
bool multiresModifier_reshapeFromObject(struct Depsgraph *depsgraph,
struct MultiresModifierData *mmd,
struct Object *dst,
diff --git a/source/blender/blenkernel/intern/multires_reshape.h b/source/blender/blenkernel/intern/multires_reshape.h
index 36ecf1a6395..a038ce5f108 100644
--- a/source/blender/blenkernel/intern/multires_reshape.h
+++ b/source/blender/blenkernel/intern/multires_reshape.h
@@ -106,6 +106,9 @@ typedef struct MultiresReshapeContext {
/* Indexed by base face index, returns first ptex face index corresponding
* to that base face. */
int *face_ptex_offset;
+
+ /* Vertex crease custom data layer, null if none is present. */
+ const float *cd_vertex_crease;
} MultiresReshapeContext;
/**
@@ -143,15 +146,19 @@ typedef struct ReshapeConstGridElement {
* Construct/destruct reshape context.
*/
-/* Create subdivision surface descriptor which is configured for surface evaluation at a given
- * multires modifier. */
+/**
+ * Create subdivision surface descriptor which is configured for surface evaluation at a given
+ * multi-res modifier.
+ */
struct Subdiv *multires_reshape_create_subdiv(struct Depsgraph *depsgraph,
struct Object *object,
const struct MultiresModifierData *mmd);
-/* NOTE: Initialized base mesh to object's mesh, the Subdiv is created from the deformed
- * mesh prior to the multires modifier if depsgraph is not NULL. If the depsgraph is NULL
- * then Subdiv is created from base mesh (without any deformation applied). */
+/**
+ * \note Initialized base mesh to object's mesh, the Subdivision is created from the deformed
+ * mesh prior to the multi-res modifier if depsgraph is not NULL. If the depsgraph is NULL
+ * then Subdivision is created from base mesh (without any deformation applied).
+ */
bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context,
struct Depsgraph *depsgraph,
struct Object *object,
@@ -185,44 +192,60 @@ void multires_reshape_context_free(MultiresReshapeContext *reshape_context);
* Helper accessors.
*/
-/* For the given grid index get index of face it was created for. */
+/**
+ * For the given grid index get index of face it was created for.
+ */
int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context,
int grid_index);
-/* For the given grid index get corner of a face it was created for. */
+/**
+ * For the given grid index get corner of a face it was created for.
+ */
int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index);
bool multires_reshape_is_quad_face(const MultiresReshapeContext *reshape_context, int face_index);
-/* For the given grid index get index of corresponding ptex face. */
+/**
+ * For the given grid index get index of corresponding PTEX face.
+ */
int multires_reshape_grid_to_ptex_index(const MultiresReshapeContext *reshape_context,
int grid_index);
-/* Convert normalized coordinate within a grid to a normalized coordinate within a ptex face. */
+/**
+ * Convert normalized coordinate within a grid to a normalized coordinate within a PTEX face.
+ */
PTexCoord multires_reshape_grid_coord_to_ptex(const MultiresReshapeContext *reshape_context,
const GridCoord *grid_coord);
-/* Convert a normalized coordinate within a ptex face to a normalized coordinate within a grid. */
+/**
+ * Convert a normalized coordinate within a PTEX face to a normalized coordinate within a grid.
+ */
GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *reshape_context,
const PTexCoord *ptex_coord);
-/* Calculate tangent matrix which converts displacement to a object vector.
- * Is calculated for the given surface derivatives at a given base face corner. */
+/**
+ * Calculate tangent matrix which converts displacement to a object vector.
+ * Is calculated for the given surface derivatives at a given base face corner.
+ */
void multires_reshape_tangent_matrix_for_corner(const MultiresReshapeContext *reshape_context,
- const int face_index,
- const int corner,
+ int face_index,
+ int corner,
const float dPdu[3],
const float dPdv[3],
float r_tangent_matrix[3][3]);
-/* Get grid elements which are to be reshaped at a given or ptex coordinate.
- * The data is coming from final custom mdata layers. */
+/**
+ * Get grid elements which are to be reshaped at a given or PTEX coordinate.
+ * The data is coming from final custom mdata layers.
+ */
ReshapeGridElement multires_reshape_grid_element_for_grid_coord(
const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord);
ReshapeGridElement multires_reshape_grid_element_for_ptex_coord(
const MultiresReshapeContext *reshape_context, const PTexCoord *ptex_coord);
-/* Get original grid element for the given coordinate. */
+/**
+ * Get original grid element for the given coordinate.
+ */
ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(
const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord);
@@ -230,8 +253,10 @@ ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(
* Sample limit surface of the base mesh.
*/
-/* Evaluate limit surface created from base mesh.
- * This is the limit surface which defines tangent space for MDisps. */
+/**
+ * Evaluate limit surface created from base mesh.
+ * This is the limit surface which defines tangent space for MDisps.
+ */
void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *reshape_context,
const GridCoord *grid_coord,
float r_P[3],
@@ -241,33 +266,41 @@ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *resha
* Custom data preparation.
*/
-/* Make sure custom data is allocated for the given level. */
-void multires_reshape_ensure_grids(struct Mesh *mesh, const int level);
+/**
+ * Make sure custom data is allocated for the given level.
+ */
+void multires_reshape_ensure_grids(struct Mesh *mesh, int level);
/* --------------------------------------------------------------------
* Functions specific to reshaping from a set of vertices in a object position.
*/
-/* Returns truth if all coordinates were assigned.
+/**
+ * Set displacement grids values at a reshape level to a object coordinates of the given source.
+ *
+ * \returns truth if all coordinates were assigned.
*
* False will be returned if the number of vertex coordinates did not match required number of
- * vertices at a reshape level. */
+ * vertices at a reshape level.
+ */
bool multires_reshape_assign_final_coords_from_vertcos(
const MultiresReshapeContext *reshape_context,
const float (*vert_coords)[3],
- const int num_vert_coords);
+ int num_vert_coords);
/* --------------------------------------------------------------------
* Functions specific to reshaping from CCG.
*/
-/* Store final object-space coordinates in the displacement grids.
+/**
+ * Store final object-space coordinates in the displacement grids.
* The reason why displacement grids are used for storage is based on memory
* footprint optimization.
*
- * NOTE: Displacement grids to be at least at a reshape level.
+ * \note Displacement grids to be at least at a reshape level.
*
- * Return truth if all coordinates have been updated. */
+ * \return truth if all coordinates have been updated.
+ */
bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext *reshape_context,
struct SubdivCCG *subdiv_ccg);
@@ -275,11 +308,15 @@ bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext
* Functions specific to reshaping from MDISPS.
*/
-/* Reads and writes to the current mesh CD_MDISPS. */
+/**
+ * Reads and writes to the current mesh #CD_MDISPS.
+ */
void multires_reshape_assign_final_coords_from_mdisps(
const MultiresReshapeContext *reshape_context);
-/* Reads from original CD_MIDTSPS, writes to the current mesh CD_MDISPS. */
+/**
+ * Reads from original #CD_MIDTSPS, writes to the current mesh #CD_MDISPS.
+ */
void multires_reshape_assign_final_elements_from_orig_mdisps(
const MultiresReshapeContext *reshape_context);
@@ -287,28 +324,33 @@ void multires_reshape_assign_final_elements_from_orig_mdisps(
* Displacement smooth.
*/
-/* Operates on a displacement grids (CD_MDISPS) which contains object space coordinates stored for
+/**
+ * Operates on a displacement grids (CD_MDISPS) which contains object space coordinates stored for
* the reshape level.
*
* The result is grids which are defining mesh with a smooth surface and details starting from
- * reshape level up to top level added back from original displacement grids. */
+ * reshape level up to top level added back from original displacement grids.
+ */
void multires_reshape_smooth_object_grids_with_details(
const MultiresReshapeContext *reshape_context);
-/* Operates on a displacement grids (CD_MDISPS) which contains object space-coordinates stored for
+/**
+ * Operates on a displacement grids (CD_MDISPS) which contains object space-coordinates stored for
* the reshape level.
*
* Makes it so surface on top level looks smooth. Details are not preserved
*/
void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context,
- const enum eMultiresSubdivideModeType mode);
+ enum eMultiresSubdivideModeType mode);
/* --------------------------------------------------------------------
* Displacement, space conversion.
*/
-/* Store original grid data, so then it's possible to calculate delta from it and add
- * high-frequency content on top of reshaped grids. */
+/**
+ * Store original grid data, so then it's possible to calculate delta from it and add
+ * high-frequency content on top of reshaped grids.
+ */
void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_context);
void multires_reshape_object_grids_to_tangent_displacement(
@@ -318,21 +360,29 @@ void multires_reshape_object_grids_to_tangent_displacement(
* Apply base.
*/
-/* Update mesh coordinates to the final positions of displacement in object space.
+/**
+ * Update mesh coordinates to the final positions of displacement in object space.
* This is effectively desired position of base mesh vertices after canceling out displacement.
*
- * NOTE: Expects that mesh's CD_MDISPS has been set to object space positions. */
+ * \note Expects that mesh's CD_MDISPS has been set to object space positions.
+ */
void multires_reshape_apply_base_update_mesh_coords(MultiresReshapeContext *reshape_context);
-/* Perform better fitting of the base mesh so its subdivided version brings vertices to their
- * desired locations. */
+/**
+ * Perform better fitting of the base mesh so its subdivided version brings vertices to their
+ * desired locations.
+ */
void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape_context);
-/* Refine subdivision surface to the new positions of the base mesh. */
+/**
+ * Refine subdivision surface to the new positions of the base mesh.
+ */
void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshape_context);
-/* Refine subdivision surface to the new positions of the deformed mesh (base mesh with all
- * modifiers leading the multires applied).
+/**
+ * Refine subdivision surface to the new positions of the deformed mesh (base mesh with all
+ * modifiers leading the multi-res applied).
*
- * NOTE: Will re-evaluate all leading modifiers, so it's not cheap. */
+ * \note Will re-evaluate all leading modifiers, so it's not cheap.
+ */
void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *reshape_context);
diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c
index 9fb158d2f84..839c457dd84 100644
--- a/source/blender/blenkernel/intern/multires_reshape_smooth.c
+++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c
@@ -75,6 +75,7 @@ typedef struct Vertex {
int num_grid_coords;
GridCoord *grid_coords;
+ float sharpness;
bool is_infinite_sharp;
} Vertex;
@@ -271,7 +272,7 @@ static void base_surface_grids_allocate(MultiresReshapeSmoothContext *reshape_sm
for (int grid_index = 0; grid_index < num_grids; ++grid_index) {
surface_grid[grid_index].points = MEM_calloc_arrayN(
- sizeof(SurfacePoint), grid_area, "delta grid displacement");
+ grid_area, sizeof(SurfacePoint), "delta grid displacement");
}
reshape_smooth_context->base_surface_grids = surface_grid;
@@ -489,19 +490,33 @@ static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_co
return (1 << reshape_context->reshape.level) + 1;
}
+static bool is_crease_supported(const MultiresReshapeSmoothContext *reshape_smooth_context)
+{
+ return !ELEM(reshape_smooth_context->smoothing_type,
+ MULTIRES_SUBDIVIDE_LINEAR,
+ MULTIRES_SUBDIVIDE_SIMPLE);
+}
+
/* Get crease which will be used for communication to OpenSubdiv topology.
* Note that simple subdivision treats all base edges as infinitely sharp. */
-static char get_effective_edge_crease_char(
- const MultiresReshapeSmoothContext *reshape_smooth_context, const MEdge *base_edge)
+static char get_effective_crease_char(const MultiresReshapeSmoothContext *reshape_smooth_context,
+ const MEdge *base_edge)
{
- if (ELEM(reshape_smooth_context->smoothing_type,
- MULTIRES_SUBDIVIDE_LINEAR,
- MULTIRES_SUBDIVIDE_SIMPLE)) {
+ if (!is_crease_supported(reshape_smooth_context)) {
return 255;
}
return base_edge->crease;
}
+static float get_effective_crease_float(const MultiresReshapeSmoothContext *reshape_smooth_context,
+ const float crease)
+{
+ if (!is_crease_supported(reshape_smooth_context)) {
+ return 1.0f;
+ }
+ return crease;
+}
+
static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context,
const MultiresReshapeContext *reshape_context,
const eMultiresSubdivideModeType mode)
@@ -566,7 +581,8 @@ static bool foreach_topology_info(const SubdivForeachContext *foreach_context,
const int num_vertices,
const int num_edges,
const int num_loops,
- const int num_polygons)
+ const int num_polygons,
+ const int *UNUSED(subdiv_polygon_offset))
{
MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
const int max_edges = reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR ?
@@ -576,25 +592,26 @@ static bool foreach_topology_info(const SubdivForeachContext *foreach_context,
/* NOTE: Calloc so the counters are re-set to 0 "for free". */
reshape_smooth_context->geometry.num_vertices = num_vertices;
reshape_smooth_context->geometry.vertices = MEM_calloc_arrayN(
- sizeof(Vertex), num_vertices, "smooth vertices");
+ num_vertices, sizeof(Vertex), "smooth vertices");
reshape_smooth_context->geometry.max_edges = max_edges;
reshape_smooth_context->geometry.edges = MEM_malloc_arrayN(
- sizeof(Edge), max_edges, "smooth edges");
+ max_edges, sizeof(Edge), "smooth edges");
reshape_smooth_context->geometry.num_corners = num_loops;
reshape_smooth_context->geometry.corners = MEM_malloc_arrayN(
- sizeof(Corner), num_loops, "smooth corners");
+ num_loops, sizeof(Corner), "smooth corners");
reshape_smooth_context->geometry.num_faces = num_polygons;
reshape_smooth_context->geometry.faces = MEM_malloc_arrayN(
- sizeof(Face), num_polygons, "smooth faces");
+ num_polygons, sizeof(Face), "smooth faces");
return true;
}
static void foreach_single_vertex(const SubdivForeachContext *foreach_context,
const GridCoord *grid_coord,
+ const int coarse_vertex_index,
const int subdiv_vertex_index)
{
const MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
@@ -607,11 +624,32 @@ static void foreach_single_vertex(const SubdivForeachContext *foreach_context,
sizeof(Vertex) * (vertex->num_grid_coords + 1));
vertex->grid_coords[vertex->num_grid_coords] = *grid_coord;
++vertex->num_grid_coords;
+
+ if (coarse_vertex_index == -1) {
+ return;
+ }
+
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+ const float *cd_vertex_crease = reshape_context->cd_vertex_crease;
+
+ if (cd_vertex_crease == NULL) {
+ return;
+ }
+
+ float crease = cd_vertex_crease[coarse_vertex_index];
+
+ if (crease == 0.0f) {
+ return;
+ }
+
+ crease = get_effective_crease_float(reshape_smooth_context, crease);
+ vertex->sharpness = BKE_subdiv_crease_to_sharpness_f(crease);
}
/* TODO(sergey): De-duplicate with similar function in multires_reshape_vertcos.c */
static void foreach_vertex(const SubdivForeachContext *foreach_context,
const PTexCoord *ptex_coord,
+ const int coarse_vertex_index,
const int subdiv_vertex_index)
{
const MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
@@ -631,12 +669,13 @@ static void foreach_vertex(const SubdivForeachContext *foreach_context,
for (int current_corner = 0; current_corner < num_corners; ++current_corner) {
GridCoord corner_grid_coord = grid_coord;
corner_grid_coord.grid_index = start_grid_index + current_corner;
- foreach_single_vertex(foreach_context, &corner_grid_coord, subdiv_vertex_index);
+ foreach_single_vertex(
+ foreach_context, &corner_grid_coord, coarse_vertex_index, subdiv_vertex_index);
}
return;
}
- foreach_single_vertex(foreach_context, &grid_coord, subdiv_vertex_index);
+ foreach_single_vertex(foreach_context, &grid_coord, coarse_vertex_index, subdiv_vertex_index);
if (grid_coord.u == 0.0f) {
GridCoord prev_grid_coord;
@@ -644,7 +683,8 @@ static void foreach_vertex(const SubdivForeachContext *foreach_context,
prev_grid_coord.u = grid_coord.v;
prev_grid_coord.v = 0.0f;
- foreach_single_vertex(foreach_context, &prev_grid_coord, subdiv_vertex_index);
+ foreach_single_vertex(
+ foreach_context, &prev_grid_coord, coarse_vertex_index, subdiv_vertex_index);
}
if (grid_coord.v == 0.0f) {
@@ -653,7 +693,8 @@ static void foreach_vertex(const SubdivForeachContext *foreach_context,
next_grid_coord.u = 0.0f;
next_grid_coord.v = grid_coord.u;
- foreach_single_vertex(foreach_context, &next_grid_coord, subdiv_vertex_index);
+ foreach_single_vertex(
+ foreach_context, &next_grid_coord, coarse_vertex_index, subdiv_vertex_index);
}
}
@@ -671,7 +712,7 @@ static void foreach_vertex_inner(const struct SubdivForeachContext *foreach_cont
.u = ptex_face_u,
.v = ptex_face_v,
};
- foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
+ foreach_vertex(foreach_context, &ptex_coord, -1, subdiv_vertex_index);
}
static void foreach_vertex_every_corner(const struct SubdivForeachContext *foreach_context,
@@ -679,7 +720,7 @@ static void foreach_vertex_every_corner(const struct SubdivForeachContext *forea
const int ptex_face_index,
const float ptex_face_u,
const float ptex_face_v,
- const int UNUSED(coarse_vertex_index),
+ const int coarse_vertex_index,
const int UNUSED(coarse_face_index),
const int UNUSED(coarse_face_corner),
const int subdiv_vertex_index)
@@ -689,7 +730,7 @@ static void foreach_vertex_every_corner(const struct SubdivForeachContext *forea
.u = ptex_face_u,
.v = ptex_face_v,
};
- foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
+ foreach_vertex(foreach_context, &ptex_coord, coarse_vertex_index, subdiv_vertex_index);
}
static void foreach_vertex_every_edge(const struct SubdivForeachContext *foreach_context,
@@ -707,7 +748,7 @@ static void foreach_vertex_every_edge(const struct SubdivForeachContext *foreach
.u = ptex_face_u,
.v = ptex_face_v,
};
- foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
+ foreach_vertex(foreach_context, &ptex_coord, -1, subdiv_vertex_index);
}
static void foreach_loop(const struct SubdivForeachContext *foreach_context,
@@ -777,7 +818,7 @@ static void store_edge(MultiresReshapeSmoothContext *reshape_smooth_context,
Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
edge->v1 = subdiv_v1;
edge->v2 = subdiv_v2;
- edge->sharpness = BKE_subdiv_edge_crease_to_sharpness_char(crease);
+ edge->sharpness = BKE_subdiv_crease_to_sharpness_char(crease);
}
static void foreach_edge(const struct SubdivForeachContext *foreach_context,
@@ -808,7 +849,7 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context,
/* Edges without crease are to be ignored as well. */
const Mesh *base_mesh = reshape_context->base_mesh;
const MEdge *base_edge = &base_mesh->medge[coarse_edge_index];
- const char crease = get_effective_edge_crease_char(reshape_smooth_context, base_edge);
+ const char crease = get_effective_crease_char(reshape_smooth_context, base_edge);
if (crease == 0) {
return;
}
@@ -834,8 +875,7 @@ static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshap
if (!BLI_BITMAP_TEST_BOOL(reshape_smooth_context->non_loose_base_edge_map, loop->e)) {
BLI_BITMAP_ENABLE(reshape_smooth_context->non_loose_base_edge_map, loop->e);
- const char crease = get_effective_edge_crease_char(reshape_smooth_context,
- &base_edge[loop->e]);
+ const char crease = get_effective_crease_char(reshape_smooth_context, &base_edge[loop->e]);
if (crease != 0) {
++num_used_edges;
}
@@ -978,6 +1018,15 @@ static float get_edge_sharpness(const OpenSubdiv_Converter *converter, const int
return edge->sharpness;
}
+static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, const int vertex_index)
+{
+ const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
+ BLI_assert(vertex_index < reshape_smooth_context->geometry.num_vertices);
+
+ const Vertex *vertex = &reshape_smooth_context->geometry.vertices[vertex_index];
+ return vertex->sharpness;
+}
+
static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter, int vertex_index)
{
const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
@@ -1014,7 +1063,7 @@ static void converter_init(const MultiresReshapeSmoothContext *reshape_smooth_co
converter->getNumVertexFaces = NULL;
converter->getVertexFaces = NULL;
converter->isInfiniteSharpVertex = is_infinite_sharp_vertex;
- converter->getVertexSharpness = NULL;
+ converter->getVertexSharpness = get_vertex_sharpness;
converter->getNumUVLayers = NULL;
converter->precalcUVLayer = NULL;
@@ -1037,7 +1086,7 @@ static void reshape_subdiv_create(MultiresReshapeSmoothContext *reshape_smooth_c
converter_init(reshape_smooth_context, &converter);
Subdiv *reshape_subdiv = BKE_subdiv_new_from_converter(settings, &converter);
- BKE_subdiv_eval_begin(reshape_subdiv);
+ BKE_subdiv_eval_begin(reshape_subdiv, SUBDIV_EVALUATOR_TYPE_CPU, NULL);
reshape_smooth_context->reshape_subdiv = reshape_subdiv;
diff --git a/source/blender/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c
index 8fb406e54a5..810cf328531 100644
--- a/source/blender/blenkernel/intern/multires_reshape_util.c
+++ b/source/blender/blenkernel/intern/multires_reshape_util.c
@@ -47,8 +47,6 @@
/** \name Construct/destruct reshape context
* \{ */
-/* Create subdivision surface descriptor which is configured for surface evaluation at a given
- * multires modifier. */
Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph,
/*const*/ Object *object,
const MultiresModifierData *mmd)
@@ -67,7 +65,7 @@ Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph,
SubdivSettings subdiv_settings;
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, base_mesh);
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
BKE_subdiv_free(subdiv);
return NULL;
}
@@ -86,7 +84,7 @@ static void context_init_lookup(MultiresReshapeContext *reshape_context)
const int num_faces = base_mesh->totpoly;
reshape_context->face_start_grid_index = MEM_malloc_arrayN(
- sizeof(int), num_faces, "face_start_grid_index");
+ num_faces, sizeof(int), "face_start_grid_index");
int num_grids = 0;
int num_ptex_faces = 0;
for (int face_index = 0; face_index < num_faces; ++face_index) {
@@ -97,9 +95,9 @@ static void context_init_lookup(MultiresReshapeContext *reshape_context)
}
reshape_context->grid_to_face_index = MEM_malloc_arrayN(
- sizeof(int), num_grids, "grid_to_face_index");
+ num_grids, sizeof(int), "grid_to_face_index");
reshape_context->ptex_start_grid_index = MEM_malloc_arrayN(
- sizeof(int), num_ptex_faces, "ptex_start_grid_index");
+ num_ptex_faces, sizeof(int), "ptex_start_grid_index");
for (int face_index = 0, grid_index = 0, ptex_index = 0; face_index < num_faces; ++face_index) {
const int num_corners = mpoly[face_index].totloop;
const int num_face_ptex_faces = (num_corners == 4) ? 1 : num_corners;
@@ -137,7 +135,7 @@ static void context_init_commoon(MultiresReshapeContext *reshape_context)
static bool context_is_valid(MultiresReshapeContext *reshape_context)
{
if (reshape_context->mdisps == NULL) {
- /* Multires displacement has been removed before current changes were applies. */
+ /* Multi-resolution displacement has been removed before current changes were applies. */
return false;
}
return true;
@@ -213,6 +211,8 @@ bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape
reshape_context->top.level = mmd->totlvl;
reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level);
+ reshape_context->cd_vertex_crease = CustomData_get_layer(&base_mesh->vdata, CD_CREASE);
+
context_init_commoon(reshape_context);
return context_verify_or_free(reshape_context);
@@ -332,7 +332,6 @@ void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
/** \name Helper accessors
* \{ */
-/* For the given grid index get index of face it was created for. */
int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context,
int grid_index)
{
@@ -345,7 +344,6 @@ int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_co
return reshape_context->grid_to_face_index[grid_index];
}
-/* For the given grid index get corner of a face it was created for. */
int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index)
{
BLI_assert(grid_index >= 0);
@@ -364,7 +362,6 @@ bool multires_reshape_is_quad_face(const MultiresReshapeContext *reshape_context
return (base_poly->totloop == 4);
}
-/* For the given grid index get index of corresponding ptex face. */
int multires_reshape_grid_to_ptex_index(const MultiresReshapeContext *reshape_context,
int grid_index)
{
@@ -374,7 +371,6 @@ int multires_reshape_grid_to_ptex_index(const MultiresReshapeContext *reshape_co
return reshape_context->face_ptex_offset[face_index] + (is_quad ? 0 : corner);
}
-/* Convert normalized coordinate within a grid to a normalized coordinate within a ptex face. */
PTexCoord multires_reshape_grid_coord_to_ptex(const MultiresReshapeContext *reshape_context,
const GridCoord *grid_coord)
{
@@ -402,7 +398,6 @@ PTexCoord multires_reshape_grid_coord_to_ptex(const MultiresReshapeContext *resh
return ptex_coord;
}
-/* Convert a normalized coordinate within a ptex face to a normalized coordinate within a grid. */
GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *reshape_context,
const PTexCoord *ptex_coord)
{
diff --git a/source/blender/blenkernel/intern/multires_reshape_vertcos.c b/source/blender/blenkernel/intern/multires_reshape_vertcos.c
index 04df5698cf9..c009349ff1b 100644
--- a/source/blender/blenkernel/intern/multires_reshape_vertcos.c
+++ b/source/blender/blenkernel/intern/multires_reshape_vertcos.c
@@ -114,7 +114,8 @@ static bool multires_reshape_vertcos_foreach_topology_info(
const int num_vertices,
const int UNUSED(num_edges),
const int UNUSED(num_loops),
- const int UNUSED(num_polygons))
+ const int UNUSED(num_polygons),
+ const int *UNUSED(subdiv_polygon_offset))
{
MultiresReshapeAssignVertcosContext *reshape_vertcos_context = foreach_context->user_data;
if (num_vertices != reshape_vertcos_context->num_vert_coords) {
@@ -182,7 +183,6 @@ static void multires_reshape_vertcos_foreach_vertex_every_edge(
multires_reshape_vertcos_foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
}
-/* Set displacement grids values at a reshape level to a object coordinates of the given source. */
bool multires_reshape_assign_final_coords_from_vertcos(
const MultiresReshapeContext *reshape_context,
const float (*vert_coords)[3],
diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c
index 501e3f27389..643e1a50fd5 100644
--- a/source/blender/blenkernel/intern/multires_unsubdivide.c
+++ b/source/blender/blenkernel/intern/multires_unsubdivide.c
@@ -177,7 +177,7 @@ static bool is_vertex_diagonal(BMVert *from_v, BMVert *to_v)
*/
static void unsubdivide_face_center_vertex_tag(BMesh *bm, BMVert *initial_vertex)
{
- bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices");
+ bool *visited_vertices = MEM_calloc_arrayN(bm->totvert, sizeof(bool), "visited vertices");
GSQueue *queue;
queue = BLI_gsqueue_new(sizeof(BMVert *));
@@ -368,7 +368,7 @@ static bool unsubdivide_tag_disconnected_mesh_element(BMesh *bm, int *elem_id, i
*/
static int unsubdivide_init_elem_ids(BMesh *bm, int *elem_id)
{
- bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices");
+ bool *visited_vertices = MEM_calloc_arrayN(bm->totvert, sizeof(bool), "visited vertices");
int current_id = 0;
for (int i = 0; i < bm->totvert; i++) {
if (!visited_vertices[i]) {
@@ -475,7 +475,7 @@ static bool multires_unsubdivide_single_level(BMesh *bm)
BM_mesh_elem_table_ensure(bm, BM_VERT);
/* Build disconnected elements IDs. Each disconnected mesh element is evaluated separately. */
- int *elem_id = MEM_calloc_arrayN(sizeof(int), bm->totvert, " ELEM ID");
+ int *elem_id = MEM_calloc_arrayN(bm->totvert, sizeof(int), " ELEM ID");
const int tot_ids = unsubdivide_init_elem_ids(bm, elem_id);
bool valid_tag_found = true;
@@ -961,7 +961,7 @@ static void multires_unsubdivide_prepare_original_bmesh_for_extract(
}
/* Create a map from loop index to poly index for the original mesh. */
- context->loop_to_face_map = MEM_calloc_arrayN(sizeof(int), original_mesh->totloop, "loop map");
+ context->loop_to_face_map = MEM_calloc_arrayN(original_mesh->totloop, sizeof(int), "loop map");
for (int i = 0; i < original_mesh->totpoly; i++) {
MPoly *poly = &original_mesh->mpoly[i];
@@ -1005,13 +1005,13 @@ static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *conte
context->num_grids = base_mesh->totloop;
context->base_mesh_grids = MEM_calloc_arrayN(
- sizeof(MultiresUnsubdivideGrid), base_mesh->totloop, "grids");
+ base_mesh->totloop, sizeof(MultiresUnsubdivideGrid), "grids");
/* Based on the existing indices in the data-layers, generate two vertex indices maps. */
/* From vertex index in original to vertex index in base and from vertex index in base to vertex
* index in original. */
- int *orig_to_base_vmap = MEM_calloc_arrayN(sizeof(int), bm_original_mesh->totvert, "orig vmap");
- int *base_to_orig_vmap = MEM_calloc_arrayN(sizeof(int), base_mesh->totvert, "base vmap");
+ int *orig_to_base_vmap = MEM_calloc_arrayN(bm_original_mesh->totvert, sizeof(int), "orig vmap");
+ int *base_to_orig_vmap = MEM_calloc_arrayN(base_mesh->totvert, sizeof(int), "base vmap");
context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT32, vname);
for (int i = 0; i < base_mesh->totvert; i++) {
diff --git a/source/blender/blenkernel/intern/multires_versioning.c b/source/blender/blenkernel/intern/multires_versioning.c
index 4c0d7165cd0..18708c43f26 100644
--- a/source/blender/blenkernel/intern/multires_versioning.c
+++ b/source/blender/blenkernel/intern/multires_versioning.c
@@ -61,7 +61,7 @@ static Subdiv *subdiv_for_simple_to_catmull_clark(Object *object, MultiresModifi
Subdiv *subdiv = BKE_subdiv_new_from_converter(&subdiv_settings, &converter);
BKE_subdiv_converter_free(&converter);
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
BKE_subdiv_free(subdiv);
return NULL;
}
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 487e925df79..84484a63291 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -61,14 +61,20 @@
static CLG_LogRef LOG = {"bke.nla"};
+/**
+ * Find the active track and strip.
+ *
+ * The active strip may or may not be on the active track.
+ */
+static void nla_tweakmode_find_active(const ListBase /* NlaTrack */ *nla_tracks,
+ NlaTrack **r_track_of_active_strip,
+ NlaStrip **r_active_strip);
+
/* *************************************************** */
/* Data Management */
/* Freeing ------------------------------------------- */
-/* Remove the given NLA strip from the NLA track it occupies, free the strip's data,
- * and the strip itself.
- */
void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
{
NlaStrip *cs, *csn;
@@ -108,9 +114,6 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
}
}
-/* Remove the given NLA track from the set of NLA tracks, free the track's data,
- * and the track itself.
- */
void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
{
NlaStrip *strip, *stripn;
@@ -135,9 +138,6 @@ void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
}
}
-/* Free the elements of type NLA Tracks provided in the given list, but do not free
- * the list itself since that is not free-standing
- */
void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
{
NlaTrack *nlt, *nltn;
@@ -159,13 +159,6 @@ void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
/* Copying ------------------------------------------- */
-/**
- * Copy NLA strip
- *
- * \param use_same_action: When true, the existing action is used (instead of being duplicated)
- * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
- * flags in BKE_lib_id.h
- */
NlaStrip *BKE_nlastrip_copy(Main *bmain,
NlaStrip *strip,
const bool use_same_action,
@@ -215,11 +208,6 @@ NlaStrip *BKE_nlastrip_copy(Main *bmain,
return strip_d;
}
-/**
- * Copy a single NLA Track.
- * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
- * flags in BKE_lib_id.h
- */
NlaTrack *BKE_nlatrack_copy(Main *bmain,
NlaTrack *nlt,
const bool use_same_actions,
@@ -249,11 +237,6 @@ NlaTrack *BKE_nlatrack_copy(Main *bmain,
return nlt_d;
}
-/**
- * Copy all NLA data.
- * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
- * flags in BKE_lib_id.h
- */
void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, const ListBase *src, const int flag)
{
NlaTrack *nlt, *nlt_d;
@@ -309,6 +292,14 @@ static void update_active_track(AnimData *adt_dest, const AnimData *adt_source)
track_dest = track_dest->next;
}
+
+ /* If the above assumption failed to hold, do a more thorough search for the active strip. */
+ if (adt_source->actstrip != NULL && adt_dest->actstrip == NULL) {
+ nla_tweakmode_find_active(&adt_source->nla_tracks, &track_dest, &adt_dest->actstrip);
+ }
+
+ BLI_assert_msg((adt_source->actstrip == NULL) == (adt_dest->actstrip == NULL),
+ "Active strip did not copy correctly");
}
void BKE_nla_tracks_copy_from_adt(Main *bmain,
@@ -325,9 +316,6 @@ void BKE_nla_tracks_copy_from_adt(Main *bmain,
/* Adding ------------------------------------------- */
-/* Add a NLA Track to the given AnimData
- * - prev: NLA-Track to add the new one after
- */
NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev, const bool is_liboverride)
{
NlaTrack *nlt;
@@ -371,7 +359,6 @@ NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev, const bool is_liboverr
return nlt;
}
-/* Create a NLA Strip referencing the given Action */
NlaStrip *BKE_nlastrip_new(bAction *act)
{
NlaStrip *strip;
@@ -390,6 +377,16 @@ NlaStrip *BKE_nlastrip_new(bAction *act)
*/
strip->flag = NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_SYNC_LENGTH;
+ /* Disable sync for actions with a manual frame range, since it only syncs to range anyway. */
+ if (act->flag & ACT_FRAME_RANGE) {
+ strip->flag &= ~NLASTRIP_FLAG_SYNC_LENGTH;
+ }
+
+ /* Enable cyclic time for known cyclic actions. */
+ if (BKE_action_is_cyclic(act)) {
+ strip->flag |= NLASTRIP_FLAG_USR_TIME_CYCLIC;
+ }
+
/* assign the action reference */
strip->act = act;
id_us_plus(&act->id);
@@ -397,7 +394,7 @@ NlaStrip *BKE_nlastrip_new(bAction *act)
/* determine initial range
* - strip length cannot be 0... ever...
*/
- calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+ BKE_action_get_frame_range(strip->act, &strip->actstart, &strip->actend);
strip->start = strip->actstart;
strip->end = (IS_EQF(strip->actstart, strip->actend)) ? (strip->actstart + 1.0f) :
@@ -411,8 +408,6 @@ NlaStrip *BKE_nlastrip_new(bAction *act)
return strip;
}
-/* Add new NLA-strip to the top of the NLA stack - i.e.
- * into the last track if space, or a new one otherwise. */
NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act, const bool is_liboverride)
{
NlaStrip *strip;
@@ -445,7 +440,6 @@ NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act, const bool is_libo
return strip;
}
-/* Add a NLA Strip referencing the given speaker's sound */
NlaStrip *BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker)
{
NlaStrip *strip = MEM_callocN(sizeof(NlaStrip), "NlaSoundStrip");
@@ -482,20 +476,16 @@ NlaStrip *BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker)
return strip;
}
-/**
- * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
- * `IDTypeInfo` structure).
- */
void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data)
{
- BKE_LIB_FOREACHID_PROCESS(data, strip->act, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, strip->act, IDWALK_CB_USER);
LISTBASE_FOREACH (FCurve *, fcu, &strip->fcurves) {
- BKE_fcurve_foreach_id(fcu, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data));
}
LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) {
- BKE_nla_strip_foreach_id(substrip, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_nla_strip_foreach_id(substrip, data));
}
}
@@ -601,12 +591,6 @@ static float nlastrip_get_frame_transition(NlaStrip *strip, float cframe, short
return (cframe - strip->start) / length;
}
-/* non clipped mapping for strip-time <-> global time
- * mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_*
- *
- * only secure for 'internal' (i.e. within AnimSys evaluation) operations,
- * but should not be directly relied on for stuff which interacts with editors
- */
float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode)
{
switch (strip->type) {
@@ -621,12 +605,6 @@ float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode)
}
}
-/* Non clipped mapping for strip-time <-> global time
- * mode = eNlaTime_ConvertModes -> NLATIME_CONVERT_*
- *
- * Public API method - perform this mapping using the given AnimData block
- * and perform any necessary sanity checks on the value
- */
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
{
NlaStrip *strip;
@@ -675,7 +653,6 @@ float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
/* List of Strips ------------------------------------ */
/* (these functions are used for NLA-Tracks and also for nested/meta-strips) */
-/* Check if there is any space in the given list to add the given strip */
bool BKE_nlastrips_has_space(ListBase *strips, float start, float end)
{
NlaStrip *strip;
@@ -710,9 +687,6 @@ bool BKE_nlastrips_has_space(ListBase *strips, float start, float end)
return true;
}
-/* Rearrange the strips in the track so that they are always in order
- * (usually only needed after a strip has been moved)
- */
void BKE_nlastrips_sort_strips(ListBase *strips)
{
ListBase tmp = {NULL, NULL};
@@ -756,9 +730,6 @@ void BKE_nlastrips_sort_strips(ListBase *strips)
strips->last = tmp.last;
}
-/* Add the given NLA-Strip to the given list of strips, assuming that it
- * isn't currently a member of another list
- */
bool BKE_nlastrips_add_strip(ListBase *strips, NlaStrip *strip)
{
NlaStrip *ns;
@@ -794,10 +765,6 @@ bool BKE_nlastrips_add_strip(ListBase *strips, NlaStrip *strip)
/* Meta-Strips ------------------------------------ */
-/* Convert 'islands' (i.e. continuous string of) selected strips to be
- * contained within 'Meta-Strips' which act as strips which contain strips.
- * temp: are the meta-strips to be created 'temporary' ones used for transforms?
- */
void BKE_nlastrips_make_metas(ListBase *strips, bool is_temp)
{
NlaStrip *mstrip = NULL;
@@ -851,7 +818,6 @@ void BKE_nlastrips_make_metas(ListBase *strips, bool is_temp)
}
}
-/* Split a meta-strip into a set of normal strips */
void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
{
NlaStrip *cs, *csn;
@@ -874,10 +840,6 @@ void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
BKE_nlastrip_free(strips, strip, true);
}
-/* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips
- * sel: only consider selected meta-strips, otherwise all meta-strips are removed
- * onlyTemp: only remove the 'temporary' meta-strips used for transforms
- */
void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp)
{
NlaStrip *strip, *stripn;
@@ -903,9 +865,6 @@ void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp)
}
}
-/* Add the given NLA-Strip to the given Meta-Strip, assuming that the
- * strip isn't attached to any list of strips
- */
bool BKE_nlameta_add_strip(NlaStrip *mstrip, NlaStrip *strip)
{
/* sanity checks */
@@ -954,9 +913,6 @@ bool BKE_nlameta_add_strip(NlaStrip *mstrip, NlaStrip *strip)
return BKE_nlastrips_add_strip(&mstrip->strips, strip);
}
-/* Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively),
- * until the Meta-Strips children all fit within the Meta-Strip's new dimensions
- */
void BKE_nlameta_flush_transforms(NlaStrip *mstrip)
{
NlaStrip *strip;
@@ -1039,7 +995,6 @@ void BKE_nlameta_flush_transforms(NlaStrip *mstrip)
/* NLA-Tracks ---------------------------------------- */
-/* Find the active NLA-track for the given stack */
NlaTrack *BKE_nlatrack_find_active(ListBase *tracks)
{
NlaTrack *nlt;
@@ -1060,11 +1015,6 @@ NlaTrack *BKE_nlatrack_find_active(ListBase *tracks)
return NULL;
}
-/* Get the NLA Track that the active action/action strip comes from,
- * since this info is not stored in AnimData. It also isn't as simple
- * as just using the active track, since multiple tracks may have been
- * entered at the same time.
- */
NlaTrack *BKE_nlatrack_find_tweaked(AnimData *adt)
{
NlaTrack *nlt;
@@ -1096,9 +1046,6 @@ NlaTrack *BKE_nlatrack_find_tweaked(AnimData *adt)
return NULL;
}
-/* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
- * that has this status in its AnimData block.
- */
void BKE_nlatrack_solo_toggle(AnimData *adt, NlaTrack *nlt)
{
NlaTrack *nt;
@@ -1133,9 +1080,6 @@ void BKE_nlatrack_solo_toggle(AnimData *adt, NlaTrack *nlt)
}
}
-/* Make the given NLA-track the active one for the given stack. If no track is provided,
- * this function can be used to simply deactivate all the NLA tracks in the given stack too.
- */
void BKE_nlatrack_set_active(ListBase *tracks, NlaTrack *nlt_a)
{
NlaTrack *nlt;
@@ -1156,7 +1100,6 @@ void BKE_nlatrack_set_active(ListBase *tracks, NlaTrack *nlt_a)
}
}
-/* Check if there is any space in the given track to add a strip of the given length */
bool BKE_nlatrack_has_space(NlaTrack *nlt, float start, float end)
{
/* sanity checks
@@ -1177,9 +1120,6 @@ bool BKE_nlatrack_has_space(NlaTrack *nlt, float start, float end)
return BKE_nlastrips_has_space(&nlt->strips, start, end);
}
-/* Rearrange the strips in the track so that they are always in order
- * (usually only needed after a strip has been moved)
- */
void BKE_nlatrack_sort_strips(NlaTrack *nlt)
{
/* sanity checks */
@@ -1191,9 +1131,6 @@ void BKE_nlatrack_sort_strips(NlaTrack *nlt)
BKE_nlastrips_sort_strips(&nlt->strips);
}
-/* Add the given NLA-Strip to the given NLA-Track, assuming that it
- * isn't currently attached to another one
- */
bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip, const bool is_liboverride)
{
/* sanity checks */
@@ -1211,9 +1148,6 @@ bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip, const bool is_libove
return BKE_nlastrips_add_strip(&nlt->strips, strip);
}
-/* Get the extents of the given NLA-Track including gaps between strips,
- * returning whether this succeeded or not
- */
bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2])
{
NlaStrip *strip;
@@ -1243,12 +1177,6 @@ bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2])
return true;
}
-/**
- * Check whether given NLA track is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param nlt: May be NULL, in which case we consider it as a non-local track case.
- */
bool BKE_nlatrack_is_nonlocal_in_liboverride(const ID *id, const NlaTrack *nlt)
{
return (ID_IS_OVERRIDE_LIBRARY(id) &&
@@ -1257,7 +1185,6 @@ bool BKE_nlatrack_is_nonlocal_in_liboverride(const ID *id, const NlaTrack *nlt)
/* NLA Strips -------------------------------------- */
-/* Find the active NLA-strip within the given track */
NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
{
NlaStrip *strip;
@@ -1278,7 +1205,6 @@ NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
return NULL;
}
-/* Make the given NLA-Strip the active one within the given block */
void BKE_nlastrip_set_active(AnimData *adt, NlaStrip *strip)
{
NlaTrack *nlt;
@@ -1302,7 +1228,6 @@ void BKE_nlastrip_set_active(AnimData *adt, NlaStrip *strip)
}
}
-/* Does the given NLA-strip fall within the given bounds (times)? */
bool BKE_nlastrip_within_bounds(NlaStrip *strip, float min, float max)
{
const float stripLen = (strip) ? strip->end - strip->start : 0.0f;
@@ -1430,10 +1355,6 @@ static void nlastrip_fix_resize_overlaps(NlaStrip *strip)
}
}
-/**
- * Recalculate the start and end frames for the strip to match the bounds of its action such that
- * the overall NLA animation result is unchanged.
- */
void BKE_nlastrip_recalculate_bounds_sync_action(NlaStrip *strip)
{
float prev_actstart;
@@ -1444,16 +1365,13 @@ void BKE_nlastrip_recalculate_bounds_sync_action(NlaStrip *strip)
prev_actstart = strip->actstart;
- calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+ BKE_action_get_frame_range(strip->act, &strip->actstart, &strip->actend);
/* Set start such that key's do not visually move, to preserve the overall animation result. */
strip->start += (strip->actstart - prev_actstart) * strip->scale;
BKE_nlastrip_recalculate_bounds(strip);
}
-/* Recalculate the start and end frames for the current strip, after changing
- * the extents of the action or the mapping (repeats or scale factor) info
- */
void BKE_nlastrip_recalculate_bounds(NlaStrip *strip)
{
float actlen, mapping;
@@ -1518,7 +1436,6 @@ static bool nlastrip_is_first(AnimData *adt, NlaStrip *strip)
/* Animated Strips ------------------------------------------- */
-/* Check if the given NLA-Track has any strips with own F-Curves */
bool BKE_nlatrack_has_animated_strips(NlaTrack *nlt)
{
NlaStrip *strip;
@@ -1539,7 +1456,6 @@ bool BKE_nlatrack_has_animated_strips(NlaTrack *nlt)
return false;
}
-/* Check if given NLA-Tracks have any strips with own F-Curves */
bool BKE_nlatracks_have_animated_strips(ListBase *tracks)
{
NlaTrack *nlt;
@@ -1560,7 +1476,6 @@ bool BKE_nlatracks_have_animated_strips(ListBase *tracks)
return false;
}
-/* Validate the NLA-Strips 'control' F-Curves based on the flags set. */
void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
{
FCurve *fcu;
@@ -1624,9 +1539,6 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
}
}
-/* Check if the given RNA pointer + property combo should be handled by
- * NLA strip curves or not.
- */
bool BKE_nlastrip_has_curves_for_property(const PointerRNA *ptr, const PropertyRNA *prop)
{
/* sanity checks */
@@ -1666,11 +1578,6 @@ static bool nla_editbone_name_check(void *arg, const char *name)
return BLI_ghash_haskey((GHash *)arg, (const void *)name);
}
-/* Find (and set) a unique name for a strip from the whole AnimData block
- * Uses a similar method to the BLI method, but is implemented differently
- * as we need to ensure that the name is unique over several lists of tracks,
- * not just a single track.
- */
void BKE_nlastrip_validate_name(AnimData *adt, NlaStrip *strip)
{
GHash *gh;
@@ -1844,7 +1751,6 @@ static void BKE_nlastrip_validate_autoblends(NlaTrack *nlt, NlaStrip *nls)
}
}
-/* Ensure that auto-blending and other settings are set correctly */
void BKE_nla_validate_state(AnimData *adt)
{
NlaStrip *strip, *fstrip = NULL;
@@ -1901,12 +1807,6 @@ void BKE_nla_validate_state(AnimData *adt)
/* name of stashed tracks - the translation stuff is included here to save extra work */
#define STASH_TRACK_NAME DATA_("[Action Stash]")
-/* Check if an action is "stashed" in the NLA already
- *
- * The criteria for this are:
- * 1) The action in question lives in a "stash" track
- * 2) We only check first-level strips. That is, we will not check inside meta strips.
- */
bool BKE_nla_action_is_stashed(AnimData *adt, bAction *act)
{
NlaTrack *nlt;
@@ -1925,9 +1825,6 @@ bool BKE_nla_action_is_stashed(AnimData *adt, bAction *act)
return false;
}
-/* "Stash" an action (i.e. store it as a track/layer in the NLA, but non-contributing)
- * to retain it in the file for future uses
- */
bool BKE_nla_action_stash(AnimData *adt, const bool is_liboverride)
{
NlaTrack *prev_track = NULL;
@@ -1996,12 +1893,6 @@ bool BKE_nla_action_stash(AnimData *adt, const bool is_liboverride)
/* Core Tools ------------------------------------------- */
-/* For the given AnimData block, add the active action to the NLA
- * stack (i.e. 'push-down' action). The UI should only allow this
- * for normal editing only (i.e. not in editmode for some strip's action),
- * so no checks for this are performed.
- */
-/* TODO: maybe we should have checks for this too... */
void BKE_nla_action_pushdown(AnimData *adt, const bool is_liboverride)
{
NlaStrip *strip;
@@ -2076,29 +1967,17 @@ void BKE_nla_action_pushdown(AnimData *adt, const bool is_liboverride)
BKE_nlastrip_set_active(adt, strip);
}
-/* Find the active strip + track combo, and set them up as the tweaking track,
- * and return if successful or not.
- */
-bool BKE_nla_tweakmode_enter(AnimData *adt)
+static void nla_tweakmode_find_active(const ListBase /* NlaTrack */ *nla_tracks,
+ NlaTrack **r_track_of_active_strip,
+ NlaStrip **r_active_strip)
{
NlaTrack *nlt, *activeTrack = NULL;
NlaStrip *strip, *activeStrip = NULL;
- /* verify that data is valid */
- if (ELEM(NULL, adt, adt->nla_tracks.first)) {
- return false;
- }
-
- /* If block is already in tweak-mode, just leave, but we should report
- * that this block is in tweak-mode (as our returncode). */
- if (adt->flag & ADT_NLA_EDIT_ON) {
- return true;
- }
-
/* go over the tracks, finding the active one, and its active strip
* - if we cannot find both, then there's nothing to do
*/
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (nlt = nla_tracks->first; nlt; nlt = nlt->next) {
/* check if active */
if (nlt->flag & NLATRACK_ACTIVE) {
/* store reference to this active track */
@@ -2117,7 +1996,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
*/
if (activeTrack == NULL) {
/* try last selected track for active strip */
- for (nlt = adt->nla_tracks.last; nlt; nlt = nlt->prev) {
+ for (nlt = nla_tracks->last; nlt; nlt = nlt->prev) {
if (nlt->flag & NLATRACK_SELECTED) {
/* assume this is the active track */
activeTrack = nlt;
@@ -2139,6 +2018,28 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
}
}
+ *r_track_of_active_strip = activeTrack;
+ *r_active_strip = activeStrip;
+}
+
+bool BKE_nla_tweakmode_enter(AnimData *adt)
+{
+ NlaTrack *nlt, *activeTrack = NULL;
+ NlaStrip *strip, *activeStrip = NULL;
+
+ /* verify that data is valid */
+ if (ELEM(NULL, adt, adt->nla_tracks.first)) {
+ return false;
+ }
+
+ /* If block is already in tweak-mode, just leave, but we should report
+ * that this block is in tweak-mode (as our returncode). */
+ if (adt->flag & ADT_NLA_EDIT_ON) {
+ return true;
+ }
+
+ nla_tweakmode_find_active(&adt->nla_tracks, &activeTrack, &activeStrip);
+
if (ELEM(NULL, activeTrack, activeStrip, activeStrip->act)) {
if (G.debug & G_DEBUG) {
printf("NLA tweak-mode enter - neither active requirement found\n");
@@ -2191,7 +2092,6 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
return true;
}
-/* Exit tweak-mode for this AnimData block. */
void BKE_nla_tweakmode_exit(AnimData *adt)
{
NlaStrip *strip;
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index a3a82bee8dc..40d0c24c9af 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -47,34 +47,36 @@
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
+#include "BLI_color.hh"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_map.hh"
-#include "BLI_math.h"
#include "BLI_path_util.h"
#include "BLI_set.hh"
#include "BLI_stack.hh"
#include "BLI_string.h"
#include "BLI_string_utils.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLI_vector_set.hh"
-
#include "BLT_translation.h"
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
+#include "BKE_bpath.h"
#include "BKE_colortools.h"
+#include "BKE_context.h"
#include "BKE_cryptomatte.h"
#include "BKE_global.h"
+#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
-#include "BLI_ghash.h"
-#include "BLI_threads.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -98,10 +100,12 @@
#define NODE_DEFAULT_MAX_WIDTH 700
using blender::Array;
+using blender::Map;
using blender::MutableSpan;
using blender::Set;
using blender::Span;
using blender::Stack;
+using blender::StringRef;
using blender::Vector;
using blender::VectorSet;
using blender::nodes::FieldInferencingInterface;
@@ -129,10 +133,6 @@ static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
static void nodeMuteRerouteOutputLinks(struct bNodeTree *ntree,
struct bNode *node,
const bool mute);
-static FieldInferencingInterface *node_field_inferencing_interface_copy(
- const FieldInferencingInterface &field_inferencing_interface);
-static void node_field_inferencing_interface_free(
- const FieldInferencingInterface *field_inferencing_interface);
static void ntree_init_data(ID *id)
{
@@ -154,62 +154,42 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
BLI_listbase_clear(&ntree_dst->nodes);
BLI_listbase_clear(&ntree_dst->links);
- /* Since source nodes and sockets are unique pointers we can put everything in a single map. */
- GHash *new_pointers = BLI_ghash_ptr_new(__func__);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
- LISTBASE_FOREACH (const bNode *, node_src, &ntree_src->nodes) {
- bNode *new_node = BKE_node_copy_ex(ntree_dst, node_src, flag_subdata, true);
- BLI_ghash_insert(new_pointers, (void *)node_src, new_node);
- /* Store mapping to inputs. */
- bNodeSocket *new_input_sock = (bNodeSocket *)new_node->inputs.first;
- const bNodeSocket *input_sock_src = (const bNodeSocket *)node_src->inputs.first;
- while (new_input_sock != nullptr) {
- BLI_ghash_insert(new_pointers, (void *)input_sock_src, new_input_sock);
- new_input_sock = new_input_sock->next;
- input_sock_src = input_sock_src->next;
- }
- /* Store mapping to outputs. */
- bNodeSocket *new_output_sock = (bNodeSocket *)new_node->outputs.first;
- const bNodeSocket *output_sock_src = (const bNodeSocket *)node_src->outputs.first;
- while (new_output_sock != nullptr) {
- BLI_ghash_insert(new_pointers, (void *)output_sock_src, new_output_sock);
- new_output_sock = new_output_sock->next;
- output_sock_src = output_sock_src->next;
- }
+ BLI_listbase_clear(&ntree_dst->nodes);
+ LISTBASE_FOREACH (const bNode *, src_node, &ntree_src->nodes) {
+ /* Don't find a unique name for every node, since they should have valid names already. */
+ bNode *new_node = blender::bke::node_copy_with_mapping(
+ ntree_dst, *src_node, flag_subdata, false, socket_map);
+ node_map.add(src_node, new_node);
}
/* copy links */
- BLI_duplicatelist(&ntree_dst->links, &ntree_src->links);
- LISTBASE_FOREACH (bNodeLink *, link_dst, &ntree_dst->links) {
- link_dst->fromnode = (bNode *)BLI_ghash_lookup_default(
- new_pointers, link_dst->fromnode, nullptr);
- link_dst->fromsock = (bNodeSocket *)BLI_ghash_lookup_default(
- new_pointers, link_dst->fromsock, nullptr);
- link_dst->tonode = (bNode *)BLI_ghash_lookup_default(new_pointers, link_dst->tonode, nullptr);
- link_dst->tosock = (bNodeSocket *)BLI_ghash_lookup_default(
- new_pointers, link_dst->tosock, nullptr);
- /* update the link socket's pointer */
- if (link_dst->tosock) {
- link_dst->tosock->link = link_dst;
- }
+ BLI_listbase_clear(&ntree_dst->links);
+ LISTBASE_FOREACH (const bNodeLink *, src_link, &ntree_src->links) {
+ bNodeLink *dst_link = (bNodeLink *)MEM_dupallocN(src_link);
+ dst_link->fromnode = node_map.lookup(src_link->fromnode);
+ dst_link->fromsock = socket_map.lookup(src_link->fromsock);
+ dst_link->tonode = node_map.lookup(src_link->tonode);
+ dst_link->tosock = socket_map.lookup(src_link->tosock);
+ BLI_assert(dst_link->tosock);
+ dst_link->tosock->link = dst_link;
+ BLI_addtail(&ntree_dst->links, dst_link);
}
/* copy interface sockets */
- BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs);
- bNodeSocket *sock_dst, *sock_src;
- for (sock_dst = (bNodeSocket *)ntree_dst->inputs.first,
- sock_src = (bNodeSocket *)ntree_src->inputs.first;
- sock_dst != nullptr;
- sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) {
- node_socket_copy(sock_dst, sock_src, flag_subdata);
+ BLI_listbase_clear(&ntree_dst->inputs);
+ LISTBASE_FOREACH (const bNodeSocket *, src_socket, &ntree_src->inputs) {
+ bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket);
+ node_socket_copy(dst_socket, src_socket, flag_subdata);
+ BLI_addtail(&ntree_dst->inputs, dst_socket);
}
-
- BLI_duplicatelist(&ntree_dst->outputs, &ntree_src->outputs);
- for (sock_dst = (bNodeSocket *)ntree_dst->outputs.first,
- sock_src = (bNodeSocket *)ntree_src->outputs.first;
- sock_dst != nullptr;
- sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) {
- node_socket_copy(sock_dst, sock_src, flag_subdata);
+ BLI_listbase_clear(&ntree_dst->outputs);
+ LISTBASE_FOREACH (const bNodeSocket *, src_socket, &ntree_src->outputs) {
+ bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket);
+ node_socket_copy(dst_socket, src_socket, flag_subdata);
+ BLI_addtail(&ntree_dst->outputs, dst_socket);
}
/* copy preview hash */
@@ -229,25 +209,25 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
}
/* update node->parent pointers */
- for (bNode *node_dst = (bNode *)ntree_dst->nodes.first,
- *node_src = (bNode *)ntree_src->nodes.first;
- node_dst;
- node_dst = (bNode *)node_dst->next, node_src = (bNode *)node_src->next) {
- if (node_dst->parent) {
- node_dst->parent = (bNode *)BLI_ghash_lookup_default(
- new_pointers, node_dst->parent, nullptr);
+ LISTBASE_FOREACH (bNode *, new_node, &ntree_dst->nodes) {
+ if (new_node->parent) {
+ new_node->parent = node_map.lookup(new_node->parent);
}
}
-
- BLI_ghash_free(new_pointers, nullptr, nullptr);
-
/* node tree will generate its own interface type */
ntree_dst->interface_type = nullptr;
if (ntree_src->field_inferencing_interface) {
- ntree_dst->field_inferencing_interface = node_field_inferencing_interface_copy(
+ ntree_dst->field_inferencing_interface = new FieldInferencingInterface(
*ntree_src->field_inferencing_interface);
}
+
+ if (flag & LIB_ID_COPY_NO_PREVIEW) {
+ ntree_dst->preview = nullptr;
+ }
+ else {
+ BKE_previewimg_id_copy(&ntree_dst->id, &ntree_src->id);
+ }
}
static void ntree_free_data(ID *id)
@@ -257,8 +237,7 @@ static void ntree_free_data(ID *id)
/* XXX hack! node trees should not store execution graphs at all.
* This should be removed when old tree types no longer require it.
* Currently the execution data for texture nodes remains in the tree
- * after execution, until the node tree is updated or freed.
- */
+ * after execution, until the node tree is updated or freed. */
if (ntree->execdata) {
switch (ntree->type) {
case NTREE_SHADER:
@@ -274,10 +253,10 @@ static void ntree_free_data(ID *id)
/* XXX not nice, but needed to free localized node groups properly */
free_localized_node_groups(ntree);
- /* unregister associated RNA types */
+ /* Unregister associated RNA types. */
ntreeInterfaceTypeFree(ntree);
- BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */
+ BLI_freelistN(&ntree->links);
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
node_free_node(ntree, node);
@@ -293,7 +272,7 @@ static void ntree_free_data(ID *id)
MEM_freeN(sock);
}
- node_field_inferencing_interface_free(ntree->field_inferencing_interface);
+ delete ntree->field_inferencing_interface;
/* free preview hash */
if (ntree->previews) {
@@ -303,38 +282,42 @@ static void ntree_free_data(ID *id)
if (ntree->id.tag & LIB_TAG_LOCALIZED) {
BKE_libblock_free_data(&ntree->id, true);
}
+
+ BKE_previewimg_free(&ntree->preview);
}
static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock)
{
- IDP_foreach_property(
- sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ IDP_foreach_property(
+ sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data));
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_OBJECT: {
bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value;
- BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value;
- BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_COLLECTION: {
bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *)
sock->default_value;
- BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_TEXTURE: {
bNodeSocketValueTexture *default_value = (bNodeSocketValueTexture *)sock->default_value;
- BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_MATERIAL: {
bNodeSocketValueMaterial *default_value = (bNodeSocketValueMaterial *)sock->default_value;
- BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_FLOAT:
@@ -355,26 +338,30 @@ static void node_foreach_id(ID *id, LibraryForeachIDData *data)
{
bNodeTree *ntree = (bNodeTree *)id;
- BKE_LIB_FOREACHID_PROCESS(data, ntree->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, ntree->gpd, IDWALK_CB_USER);
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
BKE_LIB_FOREACHID_PROCESS_ID(data, node->id, IDWALK_CB_USER);
- IDP_foreach_property(
- node->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ IDP_foreach_property(node->prop,
+ IDP_TYPE_FILTER_ID,
+ BKE_lib_query_idpropertiesForeachIDLink_callback,
+ data));
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- library_foreach_node_socket(data, sock);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock));
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
- library_foreach_node_socket(data, sock);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock));
}
}
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) {
- library_foreach_node_socket(data, sock);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock));
}
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) {
- library_foreach_node_socket(data, sock);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock));
}
}
@@ -404,6 +391,29 @@ static void node_foreach_cache(ID *id,
}
}
+static void node_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
+
+ switch (ntree->type) {
+ case NTREE_SHADER: {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_SCRIPT) {
+ NodeShaderScript *nss = reinterpret_cast<NodeShaderScript *>(node->storage);
+ BKE_bpath_foreach_path_fixed_process(bpath_data, nss->filepath);
+ }
+ else if (node->type == SH_NODE_TEX_IES) {
+ NodeShaderTexIES *ies = reinterpret_cast<NodeShaderTexIES *>(node->storage);
+ BKE_bpath_foreach_path_fixed_process(bpath_data, ies->filepath);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
static ID *node_owner_get(Main *bmain, ID *id)
{
if ((id->flag & LIB_EMBEDDED_DATA) == 0) {
@@ -474,8 +484,10 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so
case SOCK_MATERIAL:
BLO_write_struct(writer, bNodeSocketValueMaterial, sock->default_value);
break;
- case __SOCK_MESH:
case SOCK_CUSTOM:
+ /* Custom node sockets where default_value is defined uses custom properties for storage. */
+ break;
+ case __SOCK_MESH:
case SOCK_SHADER:
case SOCK_GEOMETRY:
BLI_assert_unreachable();
@@ -485,7 +497,6 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so
static void write_node_socket(BlendWriter *writer, bNodeSocket *sock)
{
- /* actual socket writing */
BLO_write_struct(writer, bNodeSocket, sock);
if (sock->prop) {
@@ -496,7 +507,6 @@ static void write_node_socket(BlendWriter *writer, bNodeSocket *sock)
}
static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock)
{
- /* actual socket writing */
BLO_write_struct(writer, bNodeSocket, sock);
if (sock->prop) {
@@ -506,13 +516,10 @@ static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock)
write_node_socket_default_value(writer, sock);
}
-/* this is only direct data, tree itself should have been written */
void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
{
BKE_id_blend_write(writer, &ntree->id);
- /* for link_list() speed, we write per list */
-
if (ntree->adt) {
BKE_animdata_blend_write(writer, ntree->adt);
}
@@ -536,9 +543,8 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
}
if (node->storage) {
- /* could be handlerized at some point, now only 1 exception still */
if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) &&
- ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB)) {
+ ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) {
BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage);
}
else if ((ntree->type == NTREE_GEOMETRY) &&
@@ -610,13 +616,13 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
}
if (node->type == CMP_NODE_OUTPUT_FILE) {
- /* inputs have own storage data */
+ /* Inputs have their own storage data. */
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
BLO_write_struct(writer, NodeImageMultiFileSocket, sock->storage);
}
}
if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) {
- /* write extra socket info */
+ /* Write extra socket info. */
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
BLO_write_struct(writer, NodeImageLayer, sock->storage);
}
@@ -633,6 +639,8 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) {
write_node_socket_interface(writer, sock);
}
+
+ BKE_previewimg_blend_write(writer, ntree->preview);
}
static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_address)
@@ -663,9 +671,9 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock)
BLO_read_data_address(reader, &sock->default_value);
sock->total_inputs = 0; /* Clear runtime data set before drawing. */
sock->cache = nullptr;
+ sock->declaration = nullptr;
}
-/* ntree itself has been read! */
void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
{
/* NOTE: writing and reading goes in sync, for speed. */
@@ -678,6 +686,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
ntree->execdata = nullptr;
ntree->field_inferencing_interface = nullptr;
+ BKE_ntree_update_tag_missing_runtime_data(ntree);
BLO_read_data_address(reader, &ntree->adt);
BKE_animdata_blend_read_data(reader, ntree->adt);
@@ -710,10 +719,10 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
}
if (node->storage) {
- /* could be handlerized at some point */
switch (node->type) {
case SH_NODE_CURVE_VEC:
case SH_NODE_CURVE_RGB:
+ case SH_NODE_CURVE_FLOAT:
case CMP_NODE_TIME:
case CMP_NODE_CURVE_VEC:
case CMP_NODE_CURVE_RGB:
@@ -747,13 +756,11 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
}
case SH_NODE_TEX_IMAGE: {
NodeTexImage *tex = (NodeTexImage *)node->storage;
- tex->iuser.ok = 1;
tex->iuser.scene = nullptr;
break;
}
case SH_NODE_TEX_ENVIRONMENT: {
NodeTexEnvironment *tex = (NodeTexEnvironment *)node->storage;
- tex->iuser.ok = 1;
tex->iuser.scene = nullptr;
break;
}
@@ -762,7 +769,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
case CMP_NODE_VIEWER:
case CMP_NODE_SPLITVIEWER: {
ImageUser *iuser = (ImageUser *)node->storage;
- iuser->ok = 1;
iuser->scene = nullptr;
break;
}
@@ -776,7 +782,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
}
case TEX_NODE_IMAGE: {
ImageUser *iuser = (ImageUser *)node->storage;
- iuser->ok = 1;
iuser->scene = nullptr;
break;
}
@@ -824,10 +829,8 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
/* TODO: should be dealt by new generic cache handling of IDs... */
ntree->previews = nullptr;
- if (ntree->type == NTREE_GEOMETRY) {
- /* Update field referencing for the geometry nodes modifier. */
- ntree->update |= NTREE_UPDATE_FIELD_INFERENCING;
- }
+ BLO_read_data_address(reader, &ntree->preview);
+ BKE_previewimg_blend_read(reader, ntree->preview);
/* type verification is in lib-link */
}
@@ -1030,6 +1033,7 @@ IDTypeInfo IDType_ID_NT = {
/* name_plural */ "node_groups",
/* translation_context */ BLT_I18NCONTEXT_ID_NODETREE,
/* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
/* init_data */ ntree_init_data,
/* copy_data */ ntree_copy_data,
@@ -1037,6 +1041,7 @@ IDTypeInfo IDType_ID_NT = {
/* make_local */ nullptr,
/* foreach_id */ node_foreach_id,
/* foreach_cache */ node_foreach_cache,
+ /* foreach_path */ node_foreach_path,
/* owner_get */ node_owner_get,
/* blend_write */ ntree_blend_write,
@@ -1052,26 +1057,22 @@ IDTypeInfo IDType_ID_NT = {
static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
{
if (ntype->declare != nullptr) {
- nodeDeclarationEnsure(ntree, node);
- node->declaration->build(*ntree, *node);
+ node_verify_sockets(ntree, node, true);
return;
}
bNodeSocketTemplate *sockdef;
- /* bNodeSocket *sock; */ /* UNUSED */
if (ntype->inputs) {
sockdef = ntype->inputs;
while (sockdef->type != -1) {
- /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_IN);
-
+ node_add_socket_from_template(ntree, node, sockdef, SOCK_IN);
sockdef++;
}
}
if (ntype->outputs) {
sockdef = ntype->outputs;
while (sockdef->type != -1) {
- /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT);
-
+ node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT);
sockdef++;
}
}
@@ -1129,8 +1130,7 @@ static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr);
/* XXX Warning: context can be nullptr in case nodes are added in do_versions.
- * Delayed init is not supported for nodes with context-based `initfunc_api` at the moment.
- */
+ * Delayed init is not supported for nodes with context-based `initfunc_api` at the moment. */
BLI_assert(C != nullptr);
ntype->initfunc_api(C, &ptr);
}
@@ -1142,15 +1142,16 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo)
{
if (typeinfo) {
ntree->typeinfo = typeinfo;
-
- /* deprecated integer type */
- ntree->type = typeinfo->type;
}
else {
ntree->typeinfo = &NodeTreeTypeUndefined;
ntree->init &= ~NTREE_TYPE_INIT;
}
+
+ /* Deprecated integer type. */
+ ntree->type = ntree->typeinfo->type;
+ BKE_ntree_update_tag_all(ntree);
}
static void node_set_typeinfo(const struct bContext *C,
@@ -1201,6 +1202,7 @@ static void node_socket_set_typeinfo(bNodeTree *ntree,
ntree->init &= ~NTREE_TYPE_INIT;
}
+ BKE_ntree_update_tag_socket_type(ntree, sock);
}
/* Set specific typeinfo pointers in all node trees on register/unregister */
@@ -1256,14 +1258,6 @@ static void update_typeinfo(Main *bmain,
FOREACH_NODETREE_END;
}
-/**
- * Try to initialize all type-info in a node tree.
- *
- * \note In general undefined type-info is a perfectly valid case,
- * the type may just be registered later.
- * In that case the update_typeinfo function will set type-info on registration
- * and do necessary updates.
- */
void ntreeSetTypes(const struct bContext *C, bNodeTree *ntree)
{
ntree->init |= NTREE_TYPE_INIT;
@@ -1335,7 +1329,7 @@ bool ntreeIsRegistered(bNodeTree *ntree)
return (ntree->typeinfo != &NodeTreeTypeUndefined);
}
-GHashIterator *ntreeTypeGetIterator(void)
+GHashIterator *ntreeTypeGetIterator()
{
return BLI_ghashIterator_new(nodetreetypes_hash);
}
@@ -1352,18 +1346,6 @@ bNodeType *nodeTypeFind(const char *idname)
return nullptr;
}
-static void free_dynamic_typeinfo(bNodeType *ntype)
-{
- if (ntype->type == NODE_DYNAMIC) {
- if (ntype->inputs) {
- MEM_freeN(ntype->inputs);
- }
- if (ntype->outputs) {
- MEM_freeN(ntype->outputs);
- }
- }
-}
-
/* callback for hash value free function */
static void node_free_type(void *nodetype_v)
{
@@ -1373,10 +1355,8 @@ static void node_free_type(void *nodetype_v)
* or we'd want to update *all* active Mains, which we cannot do anyway currently. */
update_typeinfo(G_MAIN, nullptr, nullptr, nodetype, nullptr, true);
- /* XXX deprecated */
- if (nodetype->type == NODE_DYNAMIC) {
- free_dynamic_typeinfo(nodetype);
- }
+ delete nodetype->fixed_declaration;
+ nodetype->fixed_declaration = nullptr;
/* Can be null when the type is not dynamically allocated. */
if (nodetype->free_self) {
@@ -1390,6 +1370,14 @@ void nodeRegisterType(bNodeType *nt)
BLI_assert(nt->idname[0] != '\0');
BLI_assert(nt->poll != nullptr);
+ if (nt->declare && !nt->declaration_is_dynamic) {
+ if (nt->fixed_declaration == nullptr) {
+ nt->fixed_declaration = new blender::nodes::NodeDeclaration();
+ blender::nodes::NodeDeclarationBuilder builder{*nt->fixed_declaration};
+ nt->declare(builder);
+ }
+ }
+
BLI_ghash_insert(nodetypes_hash, nt->idname, nt);
/* XXX pass Main to register function? */
/* Probably not. It is pretty much expected we want to update G_MAIN here I think -
@@ -1402,14 +1390,14 @@ void nodeUnregisterType(bNodeType *nt)
BLI_ghash_remove(nodetypes_hash, nt->idname, nullptr, node_free_type);
}
-bool nodeTypeUndefined(bNode *node)
+bool nodeTypeUndefined(const bNode *node)
{
return (node->typeinfo == &NodeTypeUndefined) ||
- ((node->type == NODE_GROUP || node->type == NODE_CUSTOM_GROUP) && node->id &&
+ ((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id &&
ID_IS_LINKED(node->id) && (node->id->tag & LIB_TAG_MISSING));
}
-GHashIterator *nodeTypeGetIterator(void)
+GHashIterator *nodeTypeGetIterator()
{
return BLI_ghashIterator_new(nodetypes_hash);
}
@@ -1457,7 +1445,7 @@ bool nodeSocketIsRegistered(bNodeSocket *sock)
return (sock->typeinfo != &NodeSocketTypeUndefined);
}
-GHashIterator *nodeSocketTypeGetIterator(void)
+GHashIterator *nodeSocketTypeGetIterator()
{
return BLI_ghashIterator_new(nodesockettypes_hash);
}
@@ -1481,6 +1469,33 @@ struct bNodeSocket *nodeFindSocket(const bNode *node,
return nullptr;
}
+namespace blender::bke {
+
+bNodeSocket *node_find_enabled_socket(bNode &node,
+ const eNodeSocketInOut in_out,
+ const StringRef name)
+{
+ ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs;
+ LISTBASE_FOREACH (bNodeSocket *, socket, sockets) {
+ if (!(socket->flag & SOCK_UNAVAIL) && socket->name == name) {
+ return socket;
+ }
+ }
+ return nullptr;
+}
+
+bNodeSocket *node_find_enabled_input_socket(bNode &node, StringRef name)
+{
+ return node_find_enabled_socket(node, SOCK_IN, name);
+}
+
+bNodeSocket *node_find_enabled_output_socket(bNode &node, StringRef name)
+{
+ return node_find_enabled_socket(node, SOCK_OUT, name);
+}
+
+} // namespace blender::bke
+
/* find unique socket identifier */
static bool unique_identifier_check(void *arg, const char *identifier)
{
@@ -1511,11 +1526,11 @@ static bNodeSocket *make_socket(bNodeTree *ntree,
/* if no explicit identifier is given, assign a unique identifier based on the name */
BLI_strncpy(auto_identifier, name, sizeof(auto_identifier));
}
- /* make the identifier unique */
+ /* Make the identifier unique. */
BLI_uniquename_cb(
- unique_identifier_check, lb, "socket", '.', auto_identifier, sizeof(auto_identifier));
+ unique_identifier_check, lb, "socket", '_', auto_identifier, sizeof(auto_identifier));
- bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "sock");
+ bNodeSocket *sock = MEM_cnew<bNodeSocket>("sock");
sock->in_out = in_out;
BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR);
@@ -1680,26 +1695,7 @@ bNodeSocket *nodeAddSocket(bNodeTree *ntree,
BLI_remlink(lb, sock); /* does nothing for new socket */
BLI_addtail(lb, sock);
- node->update |= NODE_UPDATE;
-
- return sock;
-}
-
-bNodeSocket *nodeInsertSocket(bNodeTree *ntree,
- bNode *node,
- eNodeSocketInOut in_out,
- const char *idname,
- bNodeSocket *next_sock,
- const char *identifier,
- const char *name)
-{
- ListBase *lb = (in_out == SOCK_IN ? &node->inputs : &node->outputs);
- bNodeSocket *sock = make_socket(ntree, node, in_out, lb, idname, identifier, name);
-
- BLI_remlink(lb, sock); /* does nothing for new socket */
- BLI_insertlinkbefore(lb, next_sock, sock);
-
- node->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_socket_new(ntree, sock);
return sock;
}
@@ -1920,31 +1916,7 @@ bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree,
return sock;
}
-bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree,
- bNode *node,
- eNodeSocketInOut in_out,
- int type,
- int subtype,
- bNodeSocket *next_sock,
- const char *identifier,
- const char *name)
-{
- const char *idname = nodeStaticSocketType(type, subtype);
-
- if (!idname) {
- CLOG_ERROR(&LOG, "static node socket type %d undefined", type);
- return nullptr;
- }
-
- bNodeSocket *sock = nodeInsertSocket(ntree, node, in_out, idname, next_sock, identifier, name);
- sock->type = type;
- return sock;
-}
-
-static void node_socket_free(bNodeTree *UNUSED(ntree),
- bNodeSocket *sock,
- bNode *UNUSED(node),
- const bool do_id_user)
+static void node_socket_free(bNodeSocket *sock, const bool do_id_user)
{
if (sock->prop) {
IDP_FreePropertyContent_ex(sock->prop, do_id_user);
@@ -1975,14 +1947,22 @@ void nodeRemoveSocketEx(struct bNodeTree *ntree,
}
}
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &node->internal_links) {
+ if (link->fromsock == sock || link->tosock == sock) {
+ BLI_remlink(&node->internal_links, link);
+ MEM_freeN(link);
+ BKE_ntree_update_tag_node_internal_link(ntree, node);
+ }
+ }
+
/* this is fast, this way we don't need an in_out argument */
BLI_remlink(&node->inputs, sock);
BLI_remlink(&node->outputs, sock);
- node_socket_free(ntree, sock, node, do_id_user);
+ node_socket_free(sock, do_id_user);
MEM_freeN(sock);
- node->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_socket_removed(ntree);
}
void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
@@ -1994,27 +1974,25 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
}
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) {
- node_socket_free(ntree, sock, node, true);
+ node_socket_free(sock, true);
MEM_freeN(sock);
}
BLI_listbase_clear(&node->inputs);
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) {
- node_socket_free(ntree, sock, node, true);
+ node_socket_free(sock, true);
MEM_freeN(sock);
}
BLI_listbase_clear(&node->outputs);
- node->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_socket_removed(ntree);
}
-/* finds a node based on its name */
bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name)
{
return (bNode *)BLI_findstring(&ntree->nodes, name, offsetof(bNode, name));
}
-/* Finds a node based on given socket and returns true on success. */
bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex)
{
*r_node = nullptr;
@@ -2038,9 +2016,6 @@ bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_so
return false;
}
-/**
- * \note Recursive
- */
bNode *nodeFindRootParent(bNode *node)
{
if (node->parent) {
@@ -2049,10 +2024,6 @@ bNode *nodeFindRootParent(bNode *node)
return node->type == NODE_FRAME ? node : nullptr;
}
-/**
- * \returns true if \a child has \a parent as a parent/grandparent/...
- * \note Recursive
- */
bool nodeIsChildOf(const bNode *parent, const bNode *child)
{
if (parent == child) {
@@ -2064,13 +2035,6 @@ bool nodeIsChildOf(const bNode *parent, const bNode *child)
return false;
}
-/**
- * Iterate over a chain of nodes, starting with \a node_start, executing
- * \a callback for each node (which can return false to end iterator).
- *
- * \param reversed: for backwards iteration
- * \note Recursive
- */
void nodeChainIter(const bNodeTree *ntree,
const bNode *node_start,
bool (*callback)(bNode *, bNode *, void *, const bool),
@@ -2125,17 +2089,6 @@ static void iter_backwards_ex(const bNodeTree *ntree,
}
}
-/**
- * Iterate over a chain of nodes, starting with \a node_start, executing
- * \a callback for each node (which can return false to end iterator).
- *
- * Faster than nodeChainIter. Iter only once per node.
- * Can be called recursively (using another nodeChainIterBackwards) by
- * setting the recursion_lvl accordingly.
- *
- * \note Needs updated socket links (ntreeUpdateTree).
- * \note Recursive
- */
void nodeChainIterBackwards(const bNodeTree *ntree,
const bNode *node_start,
bool (*callback)(bNode *, bNode *, void *),
@@ -2158,12 +2111,6 @@ void nodeChainIterBackwards(const bNodeTree *ntree,
iter_backwards_ex(ntree, node_start, callback, userdata, recursion_mask);
}
-/**
- * Iterate over all parents of \a node, executing \a callback for each parent
- * (which can return false to end iterator)
- *
- * \note Recursive
- */
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata)
{
if (node->parent) {
@@ -2176,7 +2123,6 @@ void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userd
/* ************** Add stuff ********** */
-/* Find the first available, non-duplicate name for a given node */
void nodeUniqueName(bNodeTree *ntree, bNode *node)
{
BLI_uniquename(
@@ -2185,13 +2131,17 @@ void nodeUniqueName(bNodeTree *ntree, bNode *node)
bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idname)
{
- bNode *node = (bNode *)MEM_callocN(sizeof(bNode), "new node");
+ bNode *node = MEM_cnew<bNode>("new node");
BLI_addtail(&ntree->nodes, node);
BLI_strncpy(node->idname, idname, sizeof(node->idname));
node_set_typeinfo(C, ntree, node, nodeTypeFind(idname));
- ntree->update |= NTREE_UPDATE_NODES;
+ BKE_ntree_update_tag_node_new(ntree, node);
+
+ if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
+ DEG_relations_tag_update(CTX_data_main(C));
+ }
return node;
}
@@ -2201,9 +2151,8 @@ bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type)
const char *idname = nullptr;
NODE_TYPES_BEGIN (ntype) {
- /* do an extra poll here, because some int types are used
- * for multiple node types, this helps find the desired type
- */
+ /* Do an extra poll here, because some int types are used
+ * for multiple node types, this helps find the desired type. */
const char *disabled_hint;
if (ntype->type == type && (!ntype->poll || ntype->poll(ntype, ntree, &disabled_hint))) {
idname = ntype->idname;
@@ -2233,145 +2182,98 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src,
}
sock_dst->stack_index = 0;
- /* XXX some compositor node (e.g. image, render layers) still store
- * some persistent buffer data here, need to clear this to avoid dangling pointers.
- */
+ /* XXX some compositor nodes (e.g. image, render layers) still store
+ * some persistent buffer data here, need to clear this to avoid dangling pointers. */
sock_dst->cache = nullptr;
}
-/* keep socket listorder identical, for copying links */
-/* ntree is the target tree */
-/* unique_name needs to be true. It's only disabled for speed when doing GPUnodetrees. */
-bNode *BKE_node_copy_ex(bNodeTree *ntree,
- const bNode *node_src,
- const int flag,
- const bool unique_name)
-{
- bNode *node_dst = (bNode *)MEM_callocN(sizeof(bNode), "dupli node");
- bNodeSocket *sock_dst, *sock_src;
- bNodeLink *link_dst, *link_src;
-
- *node_dst = *node_src;
+namespace blender::bke {
- /* Reset the declaration of the new node. */
- node_dst->declaration = nullptr;
+bNode *node_copy_with_mapping(bNodeTree *dst_tree,
+ const bNode &node_src,
+ const int flag,
+ const bool unique_name,
+ Map<const bNodeSocket *, bNodeSocket *> &socket_map)
+{
+ bNode *node_dst = (bNode *)MEM_mallocN(sizeof(bNode), __func__);
+ *node_dst = node_src;
- /* can be called for nodes outside a node tree (e.g. clipboard) */
- if (ntree) {
+ /* Can be called for nodes outside a node tree (e.g. clipboard). */
+ if (dst_tree) {
if (unique_name) {
- nodeUniqueName(ntree, node_dst);
+ nodeUniqueName(dst_tree, node_dst);
}
-
- BLI_addtail(&ntree->nodes, node_dst);
+ BLI_addtail(&dst_tree->nodes, node_dst);
}
- BLI_duplicatelist(&node_dst->inputs, &node_src->inputs);
- for (sock_dst = (bNodeSocket *)node_dst->inputs.first,
- sock_src = (bNodeSocket *)node_src->inputs.first;
- sock_dst != nullptr;
- sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) {
- node_socket_copy(sock_dst, sock_src, flag);
+ BLI_listbase_clear(&node_dst->inputs);
+ LISTBASE_FOREACH (const bNodeSocket *, src_socket, &node_src.inputs) {
+ bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket);
+ node_socket_copy(dst_socket, src_socket, flag);
+ BLI_addtail(&node_dst->inputs, dst_socket);
+ socket_map.add_new(src_socket, dst_socket);
}
- BLI_duplicatelist(&node_dst->outputs, &node_src->outputs);
- for (sock_dst = (bNodeSocket *)node_dst->outputs.first,
- sock_src = (bNodeSocket *)node_src->outputs.first;
- sock_dst != nullptr;
- sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) {
- node_socket_copy(sock_dst, sock_src, flag);
+ BLI_listbase_clear(&node_dst->outputs);
+ LISTBASE_FOREACH (const bNodeSocket *, src_socket, &node_src.outputs) {
+ bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket);
+ node_socket_copy(dst_socket, src_socket, flag);
+ BLI_addtail(&node_dst->outputs, dst_socket);
+ socket_map.add_new(src_socket, dst_socket);
}
- if (node_src->prop) {
- node_dst->prop = IDP_CopyProperty_ex(node_src->prop, flag);
+ if (node_src.prop) {
+ node_dst->prop = IDP_CopyProperty_ex(node_src.prop, flag);
}
- BLI_duplicatelist(&node_dst->internal_links, &node_src->internal_links);
- for (link_dst = (bNodeLink *)node_dst->internal_links.first,
- link_src = (bNodeLink *)node_src->internal_links.first;
- link_dst != nullptr;
- link_dst = (bNodeLink *)link_dst->next, link_src = (bNodeLink *)link_src->next) {
- /* This is a bit annoying to do index lookups in a list, but is likely to be faster than
- * trying to create a hash-map. At least for usual nodes, which only have so much sockets
- * and internal links. */
- const int from_sock_index = BLI_findindex(&node_src->inputs, link_src->fromsock);
- const int to_sock_index = BLI_findindex(&node_src->outputs, link_src->tosock);
- BLI_assert(from_sock_index != -1);
- BLI_assert(to_sock_index != -1);
- link_dst->fromnode = node_dst;
- link_dst->tonode = node_dst;
- link_dst->fromsock = (bNodeSocket *)BLI_findlink(&node_dst->inputs, from_sock_index);
- link_dst->tosock = (bNodeSocket *)BLI_findlink(&node_dst->outputs, to_sock_index);
+ BLI_listbase_clear(&node_dst->internal_links);
+ LISTBASE_FOREACH (const bNodeLink *, src_link, &node_src.internal_links) {
+ bNodeLink *dst_link = (bNodeLink *)MEM_dupallocN(src_link);
+ dst_link->fromnode = node_dst;
+ dst_link->tonode = node_dst;
+ dst_link->fromsock = socket_map.lookup(src_link->fromsock);
+ dst_link->tosock = socket_map.lookup(src_link->tosock);
+ BLI_addtail(&node_dst->internal_links, dst_link);
}
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
id_us_plus(node_dst->id);
}
- if (node_src->typeinfo->copyfunc) {
- node_src->typeinfo->copyfunc(ntree, node_dst, node_src);
+ if (node_src.typeinfo->copyfunc) {
+ node_src.typeinfo->copyfunc(dst_tree, node_dst, &node_src);
}
- node_dst->new_node = nullptr;
-
/* Only call copy function when a copy is made for the main database, not
* for cases like the dependency graph and localization. */
if (node_dst->typeinfo->copyfunc_api && !(flag & LIB_ID_CREATE_NO_MAIN)) {
PointerRNA ptr;
- RNA_pointer_create((ID *)ntree, &RNA_Node, node_dst, &ptr);
+ RNA_pointer_create((ID *)dst_tree, &RNA_Node, node_dst, &ptr);
- node_dst->typeinfo->copyfunc_api(&ptr, node_src);
+ node_dst->typeinfo->copyfunc_api(&ptr, &node_src);
}
- if (ntree) {
- ntree->update |= NTREE_UPDATE_NODES;
+ if (dst_tree) {
+ BKE_ntree_update_tag_node_new(dst_tree, node_dst);
}
- return node_dst;
-}
+ /* Reset the declaration of the new node. */
+ node_dst->declaration = nullptr;
+ nodeDeclarationEnsure(dst_tree, node_dst);
-static void node_set_new_pointers(bNode *node_src, bNode *new_node)
-{
- /* Store mapping to the node itself. */
- node_src->new_node = new_node;
- /* Store mapping to inputs. */
- bNodeSocket *new_input_sock = (bNodeSocket *)new_node->inputs.first;
- bNodeSocket *input_sock_src = (bNodeSocket *)node_src->inputs.first;
- while (new_input_sock != nullptr) {
- input_sock_src->new_sock = new_input_sock;
- new_input_sock = new_input_sock->next;
- input_sock_src = input_sock_src->next;
- }
- /* Store mapping to outputs. */
- bNodeSocket *new_output_sock = (bNodeSocket *)new_node->outputs.first;
- bNodeSocket *output_sock_src = (bNodeSocket *)node_src->outputs.first;
- while (new_output_sock != nullptr) {
- output_sock_src->new_sock = new_output_sock;
- new_output_sock = new_output_sock->next;
- output_sock_src = output_sock_src->next;
- }
+ return node_dst;
}
-bNode *BKE_node_copy_store_new_pointers(bNodeTree *ntree, bNode *node_src, const int flag)
+bNode *node_copy(bNodeTree *dst_tree,
+ const bNode &src_node,
+ const int flag,
+ const bool unique_name)
{
- bNode *new_node = BKE_node_copy_ex(ntree, node_src, flag, true);
- node_set_new_pointers(node_src, new_node);
- return new_node;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+ return node_copy_with_mapping(dst_tree, src_node, flag, unique_name, socket_map);
}
-bNodeTree *ntreeCopyTree_ex_new_pointers(const bNodeTree *ntree,
- Main *bmain,
- const bool do_id_user)
-{
- bNodeTree *new_ntree = ntreeCopyTree_ex(ntree, bmain, do_id_user);
- bNode *new_node = (bNode *)new_ntree->nodes.first;
- bNode *node_src = (bNode *)ntree->nodes.first;
- while (new_node != nullptr) {
- node_set_new_pointers(node_src, new_node);
- new_node = new_node->next;
- node_src = node_src->next;
- }
- return new_ntree;
-}
+} // namespace blender::bke
static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
{
@@ -2384,18 +2286,17 @@ static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
return count;
}
-/* also used via rna api, so we check for proper input output direction */
bNodeLink *nodeAddLink(
bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock)
{
bNodeLink *link = nullptr;
- /* test valid input */
+ /* Test valid input. */
BLI_assert(fromnode);
BLI_assert(tonode);
if (fromsock->in_out == SOCK_OUT && tosock->in_out == SOCK_IN) {
- link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "link");
+ link = MEM_cnew<bNodeLink>("link");
if (ntree) {
BLI_addtail(&ntree->links, link);
}
@@ -2406,7 +2307,7 @@ bNodeLink *nodeAddLink(
}
else if (fromsock->in_out == SOCK_IN && tosock->in_out == SOCK_OUT) {
/* OK but flip */
- link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "link");
+ link = MEM_cnew<bNodeLink>("link");
if (ntree) {
BLI_addtail(&ntree->links, link);
}
@@ -2417,7 +2318,7 @@ bNodeLink *nodeAddLink(
}
if (ntree) {
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_added(ntree, link);
}
if (link != nullptr && link->tosock->flag & SOCK_MULTI_INPUT) {
@@ -2429,7 +2330,7 @@ bNodeLink *nodeAddLink(
void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
{
- /* can be called for links outside a node tree (e.g. clipboard) */
+ /* Can be called for links outside a node tree (e.g. clipboard). */
if (ntree) {
BLI_remlink(&ntree->links, link);
}
@@ -2440,7 +2341,7 @@ void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
MEM_freeN(link);
if (ntree) {
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_removed(ntree);
}
}
@@ -2540,7 +2441,7 @@ void nodeMuteLinkToggle(bNodeTree *ntree, bNodeLink *link)
}
if (ntree) {
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_mute(ntree, link);
}
}
@@ -2551,8 +2452,6 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
nodeRemLink(ntree, link);
}
}
-
- ntree->update |= NTREE_UPDATE_LINKS;
}
bool nodeLinkIsHidden(const bNodeLink *link)
@@ -2592,6 +2491,17 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
bNodeLink *fromlink = link->fromsock->link->fromsock->link;
/* skip the node */
if (fromlink) {
+ if (link->tosock->flag & SOCK_MULTI_INPUT) {
+ /* remove the link that would be the same as the relinked one */
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link_to_compare, &ntree->links) {
+ if (link_to_compare->fromsock == fromlink->fromsock &&
+ link_to_compare->tosock == link->tosock) {
+ adjust_multi_input_indices_after_removed_link(
+ ntree, link_to_compare->tosock, link_to_compare->multi_input_socket_index);
+ nodeRemLink(ntree, link_to_compare);
+ }
+ }
+ }
link->fromnode = fromlink->fromnode;
link->fromsock = fromlink->fromsock;
@@ -2606,7 +2516,7 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
link->flag |= NODE_LINK_MUTED;
}
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_changed(ntree);
}
else {
if (link->tosock->flag & SOCK_MULTI_INPUT) {
@@ -2792,21 +2702,24 @@ bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree)
/* XXX this should be removed eventually ...
* Currently BKE functions are modeled closely on previous code,
* using BKE_node_preview_init_tree to set up previews for a whole node tree in advance.
- * This should be left more to the individual node tree implementations.
- */
+ * This should be left more to the individual node tree implementations. */
+
bool BKE_node_preview_used(const bNode *node)
{
/* XXX check for closed nodes? */
return (node->typeinfo->flag & NODE_PREVIEW) != 0;
}
-bNodePreview *BKE_node_preview_verify(
- bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create)
+bNodePreview *BKE_node_preview_verify(bNodeInstanceHash *previews,
+ bNodeInstanceKey key,
+ const int xsize,
+ const int ysize,
+ const bool create)
{
bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key);
if (!preview) {
if (create) {
- preview = (bNodePreview *)MEM_callocN(sizeof(bNodePreview), "node preview");
+ preview = MEM_cnew<bNodePreview>("node preview");
BKE_node_instance_hash_insert(previews, key, preview);
}
else {
@@ -2858,9 +2771,8 @@ void BKE_node_preview_free(bNodePreview *preview)
static void node_preview_init_tree_recursive(bNodeInstanceHash *previews,
bNodeTree *ntree,
bNodeInstanceKey parent_key,
- int xsize,
- int ysize,
- bool create_previews)
+ const int xsize,
+ const int ysize)
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
@@ -2869,17 +2781,16 @@ static void node_preview_init_tree_recursive(bNodeInstanceHash *previews,
node->preview_xsize = xsize;
node->preview_ysize = ysize;
- BKE_node_preview_verify(previews, key, xsize, ysize, create_previews);
+ BKE_node_preview_verify(previews, key, xsize, ysize, false);
}
if (node->type == NODE_GROUP && node->id) {
- node_preview_init_tree_recursive(
- previews, (bNodeTree *)node->id, key, xsize, ysize, create_previews);
+ node_preview_init_tree_recursive(previews, (bNodeTree *)node->id, key, xsize, ysize);
}
}
}
-void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, bool create_previews)
+void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize)
{
if (!ntree) {
return;
@@ -2889,8 +2800,7 @@ void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, bool cre
ntree->previews = BKE_node_instance_hash_new("node previews");
}
- node_preview_init_tree_recursive(
- ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize, create_previews);
+ node_preview_init_tree_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize);
}
static void node_preview_tag_used_recursive(bNodeInstanceHash *previews,
@@ -2924,18 +2834,6 @@ void BKE_node_preview_remove_unused(bNodeTree *ntree)
(bNodeInstanceValueFP)BKE_node_preview_free);
}
-void BKE_node_preview_free_tree(bNodeTree *ntree)
-{
- if (!ntree) {
- return;
- }
-
- if (ntree->previews) {
- BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
- ntree->previews = nullptr;
- }
-}
-
void BKE_node_preview_clear(bNodePreview *preview)
{
if (preview && preview->rect) {
@@ -2956,40 +2854,6 @@ void BKE_node_preview_clear_tree(bNodeTree *ntree)
}
}
-static void node_preview_sync(bNodePreview *to, bNodePreview *from)
-{
- /* sizes should have been initialized by BKE_node_preview_init_tree */
- BLI_assert(to->xsize == from->xsize && to->ysize == from->ysize);
-
- /* copy over contents of previews */
- if (to->rect && from->rect) {
- int xsize = to->xsize;
- int ysize = to->ysize;
- memcpy(to->rect, from->rect, xsize * ysize * sizeof(char[4]));
- }
-}
-
-void BKE_node_preview_sync_tree(bNodeTree *to_ntree, bNodeTree *from_ntree)
-{
- bNodeInstanceHash *from_previews = from_ntree->previews;
- bNodeInstanceHash *to_previews = to_ntree->previews;
-
- if (!from_previews || !to_previews) {
- return;
- }
-
- bNodeInstanceHashIterator iter;
- NODE_INSTANCE_HASH_ITER (iter, from_previews) {
- bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
- bNodePreview *from = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter);
- bNodePreview *to = (bNodePreview *)BKE_node_instance_hash_lookup(to_previews, key);
-
- if (from && to) {
- node_preview_sync(to, from);
- }
- }
-}
-
void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, bool remove_old)
{
if (remove_old || !to_ntree->previews) {
@@ -3026,42 +2890,14 @@ void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, boo
}
}
-/* hack warning! this function is only used for shader previews, and
- * since it gets called multiple times per pixel for Ztransp we only
- * add the color once. Preview gets cleared before it starts render though */
-void BKE_node_preview_set_pixel(
- bNodePreview *preview, const float col[4], int x, int y, bool do_manage)
-{
- if (preview) {
- if (x >= 0 && y >= 0) {
- if (x < preview->xsize && y < preview->ysize) {
- unsigned char *tar = preview->rect + 4 * ((preview->xsize * y) + x);
-
- if (do_manage) {
- linearrgb_to_srgb_uchar4(tar, col);
- }
- else {
- rgba_float_to_uchar(tar, col);
- }
- }
- // else printf("prv out bound x y %d %d\n", x, y);
- }
- // else printf("prv out bound x y %d %d\n", x, y);
- }
-}
-
/* ************** Free stuff ********** */
-/* goes over entire tree */
void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
{
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
ListBase *lb;
if (link->fromnode == node) {
lb = &node->outputs;
- if (link->tonode) {
- link->tonode->update |= NODE_UPDATE;
- }
}
else if (link->tonode == node) {
lb = &node->inputs;
@@ -3103,10 +2939,6 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
/* can be called for nodes outside a node tree (e.g. clipboard) */
if (ntree) {
- /* remove all references to this node */
- nodeUnlinkNode(ntree, node);
- node_unlink_attached(ntree, node);
-
BLI_remlink(&ntree->nodes, node);
if (ntree->typeinfo->free_node_cache) {
@@ -3126,12 +2958,12 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) {
/* Remember, no ID user refcount management here! */
- node_socket_free(ntree, sock, node, false);
+ node_socket_free(sock, false);
MEM_freeN(sock);
}
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) {
/* Remember, no ID user refcount management here! */
- node_socket_free(ntree, sock, node, false);
+ node_socket_free(sock, false);
MEM_freeN(sock);
}
@@ -3143,12 +2975,14 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
MEM_freeN(node->prop);
}
- delete node->declaration;
+ if (node->typeinfo->declaration_is_dynamic) {
+ delete node->declaration;
+ }
MEM_freeN(node);
if (ntree) {
- ntree->update |= NTREE_UPDATE_NODES;
+ BKE_ntree_update_tag_node_removed(ntree);
}
}
@@ -3156,6 +2990,12 @@ void ntreeFreeLocalNode(bNodeTree *ntree, bNode *node)
{
/* For removing nodes while editing localized node trees. */
BLI_assert((ntree->id.tag & LIB_TAG_LOCALIZED) != 0);
+
+ /* These two lines assume the caller might want to free a single node and maintain
+ * a valid state in the node tree. */
+ nodeUnlinkNode(ntree, node);
+ node_unlink_attached(ntree, node);
+
node_free_node(ntree, node);
}
@@ -3200,6 +3040,9 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
}
}
+ nodeUnlinkNode(ntree, node);
+ node_unlink_attached(ntree, node);
+
/* Free node itself. */
node_free_node(ntree, node);
}
@@ -3225,8 +3068,7 @@ static void free_localized_node_groups(bNodeTree *ntree)
/* Only localized node trees store a copy for each node group tree.
* Each node group tree in a localized node tree can be freed,
* since it is a localized copy itself (no risk of accessing free'd
- * data in main, see T37939).
- */
+ * data in main, see T37939). */
if (!(ntree->id.tag & LIB_TAG_LOCALIZED)) {
return;
}
@@ -3240,8 +3082,6 @@ static void free_localized_node_groups(bNodeTree *ntree)
}
}
-/* Free (or release) any data used by this nodetree. Does not free the
- * nodetree itself and does no ID user counting. */
void ntreeFreeTree(bNodeTree *ntree)
{
ntree_free_data(&ntree->id);
@@ -3345,12 +3185,6 @@ void ntreeSetOutput(bNodeTree *ntree)
* might be different for editor or for "real" use... */
}
-/**
- * Get address of potential node-tree pointer of given ID.
- *
- * \warning Using this function directly is potentially dangerous, if you don't know or are not
- * sure, please use `ntreeFromID()` instead.
- */
bNodeTree **BKE_ntree_ptr_from_id(ID *id)
{
switch (GS(id->name)) {
@@ -3373,33 +3207,12 @@ bNodeTree **BKE_ntree_ptr_from_id(ID *id)
}
}
-/* Returns the private NodeTree object of the datablock, if it has one. */
bNodeTree *ntreeFromID(ID *id)
{
bNodeTree **nodetree = BKE_ntree_ptr_from_id(id);
return (nodetree != nullptr) ? *nodetree : nullptr;
}
-bool ntreeNodeExists(const bNodeTree *ntree, const bNode *testnode)
-{
- LISTBASE_FOREACH (const bNode *, node, &ntree->nodes) {
- if (node == testnode) {
- return true;
- }
- }
- return false;
-}
-
-bool ntreeOutputExists(const bNode *node, const bNodeSocket *testsock)
-{
- LISTBASE_FOREACH (const bNodeSocket *, sock, &node->outputs) {
- if (sock == testsock) {
- return true;
- }
- }
- return false;
-}
-
void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable)
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -3412,59 +3225,43 @@ void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable)
}
}
-/* returns localized tree for execution in threads */
bNodeTree *ntreeLocalize(bNodeTree *ntree)
{
- if (ntree) {
- /* Make full copy outside of Main database.
- * NOTE: previews are not copied here.
- */
- bNodeTree *ltree = (bNodeTree *)BKE_id_copy_ex(
- nullptr, &ntree->id, nullptr, (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA));
-
- ltree->id.tag |= LIB_TAG_LOCALIZED;
+ if (ntree == nullptr) {
+ return nullptr;
+ }
- LISTBASE_FOREACH (bNode *, node, &ltree->nodes) {
- if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
- node->id = (ID *)ntreeLocalize((bNodeTree *)node->id);
- }
- }
+ /* Make full copy outside of Main database.
+ * NOTE: previews are not copied here. */
+ bNodeTree *ltree = (bNodeTree *)BKE_id_copy_ex(
+ nullptr, &ntree->id, nullptr, (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA));
- /* ensures only a single output node is enabled */
- ntreeSetOutput(ntree);
+ ltree->id.tag |= LIB_TAG_LOCALIZED;
- bNode *node_src = (bNode *)ntree->nodes.first;
- bNode *node_local = (bNode *)ltree->nodes.first;
- while (node_src != nullptr) {
- node_local->original = node_src;
- node_src = node_src->next;
- node_local = node_local->next;
+ LISTBASE_FOREACH (bNode *, node, &ltree->nodes) {
+ if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
+ node->id = (ID *)ntreeLocalize((bNodeTree *)node->id);
}
+ }
- if (ntree->typeinfo->localize) {
- ntree->typeinfo->localize(ltree, ntree);
- }
+ /* Ensures only a single output node is enabled. */
+ ntreeSetOutput(ntree);
- return ltree;
+ bNode *node_src = (bNode *)ntree->nodes.first;
+ bNode *node_local = (bNode *)ltree->nodes.first;
+ while (node_src != nullptr) {
+ node_local->original = node_src;
+ node_src = node_src->next;
+ node_local = node_local->next;
}
- return nullptr;
-}
-
-/* sync local composite with real tree */
-/* local tree is supposed to be running, be careful moving previews! */
-/* is called by jobs manager, outside threads, so it doesn't happen during draw */
-void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree)
-{
- if (localtree && ntree) {
- if (ntree->typeinfo->local_sync) {
- ntree->typeinfo->local_sync(localtree, ntree);
- }
+ if (ntree->typeinfo->localize) {
+ ntree->typeinfo->localize(ltree, ntree);
}
+
+ return ltree;
}
-/* merge local tree results back, and free local tree */
-/* we have to assume the editor already changed completely */
void ntreeLocalMerge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
{
if (ntree && localtree) {
@@ -3489,7 +3286,7 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree,
return nullptr;
}
- bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "socket template");
+ bNodeSocket *sock = MEM_cnew<bNodeSocket>("socket template");
BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname));
node_socket_set_typeinfo(ntree, sock, stype);
sock->in_out = in_out;
@@ -3535,12 +3332,11 @@ bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree,
bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name);
if (in_out == SOCK_IN) {
BLI_addtail(&ntree->inputs, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_IN;
}
else if (in_out == SOCK_OUT) {
BLI_addtail(&ntree->outputs, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_OUT;
}
+ BKE_ntree_update_tag_interface(ntree);
return iosock;
}
@@ -3553,12 +3349,11 @@ bNodeSocket *ntreeInsertSocketInterface(bNodeTree *ntree,
bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name);
if (in_out == SOCK_IN) {
BLI_insertlinkbefore(&ntree->inputs, next_sock, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_IN;
}
else if (in_out == SOCK_OUT) {
BLI_insertlinkbefore(&ntree->outputs, next_sock, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_OUT;
}
+ BKE_ntree_update_tag_interface(ntree);
return iosock;
}
@@ -3604,7 +3399,7 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
node_socket_interface_free(ntree, sock, true);
MEM_freeN(sock);
- ntree->update |= NTREE_UPDATE_GROUP;
+ BKE_ntree_update_tag_interface(ntree);
}
/* generates a valid RNA identifier from the node tree name */
@@ -3742,11 +3537,6 @@ bNode *ntreeFindType(const bNodeTree *ntree, int type)
return nullptr;
}
-bool ntreeHasType(const bNodeTree *ntree, int type)
-{
- return ntreeFindType(ntree, type) != nullptr;
-}
-
bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup)
{
if (ntree == lookup) {
@@ -3800,95 +3590,6 @@ bNode *nodeGetActive(bNodeTree *ntree)
return nullptr;
}
-static bNode *node_get_active_id_recursive(bNodeInstanceKey active_key,
- bNodeInstanceKey parent_key,
- bNodeTree *ntree,
- short idtype)
-{
- if (parent_key.value == active_key.value || active_key.value == 0) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id && GS(node->id->name) == idtype) {
- if (node->flag & NODE_ACTIVE_ID) {
- return node;
- }
- }
- }
- }
- else {
- /* no node with active ID in this tree, look inside groups */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == NODE_GROUP) {
- bNodeTree *group = (bNodeTree *)node->id;
- if (group) {
- bNodeInstanceKey group_key = BKE_node_instance_key(parent_key, ntree, node);
- bNode *tnode = node_get_active_id_recursive(active_key, group_key, group, idtype);
- if (tnode) {
- return tnode;
- }
- }
- }
- }
- }
- return nullptr;
-}
-
-/* two active flags, ID nodes have special flag for buttons display */
-bNode *nodeGetActiveID(bNodeTree *ntree, short idtype)
-{
- if (ntree) {
- return node_get_active_id_recursive(
- ntree->active_viewer_key, NODE_INSTANCE_KEY_BASE, ntree, idtype);
- }
- return nullptr;
-}
-
-bool nodeSetActiveID(bNodeTree *ntree, short idtype, ID *id)
-{
- bool ok = false;
-
- if (ntree == nullptr) {
- return ok;
- }
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id && GS(node->id->name) == idtype) {
- if (id && ok == false && node->id == id) {
- node->flag |= NODE_ACTIVE_ID;
- ok = true;
- }
- else {
- node->flag &= ~NODE_ACTIVE_ID;
- }
- }
- }
-
- /* update all groups linked from here
- * if active ID node has been found already,
- * just pass null so other matching nodes are deactivated.
- */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == NODE_GROUP) {
- ok |= nodeSetActiveID((bNodeTree *)node->id, idtype, (ok == false ? id : nullptr));
- }
- }
-
- return ok;
-}
-
-/* two active flags, ID nodes have special flag for buttons display */
-void nodeClearActiveID(bNodeTree *ntree, short idtype)
-{
- if (ntree == nullptr) {
- return;
- }
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id && GS(node->id->name) == idtype) {
- node->flag &= ~NODE_ACTIVE_ID;
- }
- }
-}
-
void nodeSetSelected(bNode *node, bool select)
{
if (select) {
@@ -3914,22 +3615,16 @@ void nodeClearActive(bNodeTree *ntree)
}
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_ID);
+ node->flag &= ~NODE_ACTIVE;
}
}
-/* two active flags, ID nodes have special flag for buttons display */
void nodeSetActive(bNodeTree *ntree, bNode *node)
{
/* make sure only one node is active, and only one per ID type */
LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) {
tnode->flag &= ~NODE_ACTIVE;
- if (node->id && tnode->id) {
- if (GS(node->id->name) == GS(tnode->id->name)) {
- tnode->flag &= ~NODE_ACTIVE_ID;
- }
- }
if ((node->typeinfo->nclass == NODE_CLASS_TEXTURE) ||
(node->typeinfo->type == GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE)) {
tnode->flag &= ~NODE_ACTIVE_TEXTURE;
@@ -3937,9 +3632,6 @@ void nodeSetActive(bNodeTree *ntree, bNode *node)
}
node->flag |= NODE_ACTIVE;
- if (node->id) {
- node->flag |= NODE_ACTIVE_ID;
- }
if ((node->typeinfo->nclass == NODE_CLASS_TEXTURE) ||
(node->typeinfo->type == GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE)) {
node->flag |= NODE_ACTIVE_TEXTURE;
@@ -3951,8 +3643,13 @@ int nodeSocketIsHidden(const bNodeSocket *sock)
return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0);
}
-void nodeSetSocketAvailability(bNodeSocket *sock, bool is_available)
+void nodeSetSocketAvailability(bNodeTree *ntree, bNodeSocket *sock, bool is_available)
{
+ const bool was_available = (sock->flag & SOCK_UNAVAIL) == 0;
+ if (is_available != was_available) {
+ BKE_ntree_update_tag_socket_availability(ntree, sock);
+ }
+
if (is_available) {
sock->flag &= ~SOCK_UNAVAIL;
}
@@ -3975,22 +3672,51 @@ int nodeSocketLinkLimit(const bNodeSocket *sock)
return sock->limit;
}
-/**
- * If the node implements a `declare` function, this function makes sure that `node->declaration`
- * is up to date.
- */
-void nodeDeclarationEnsure(bNodeTree *UNUSED(ntree), bNode *node)
+static void update_socket_declarations(ListBase *sockets,
+ Span<blender::nodes::SocketDeclarationPtr> declarations)
{
- if (node->typeinfo->declare == nullptr) {
- return;
+ int index;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) {
+ const SocketDeclaration &socket_decl = *declarations[index];
+ socket->declaration = &socket_decl;
}
+}
+
+void nodeSocketDeclarationsUpdate(bNode *node)
+{
+ BLI_assert(node->declaration != nullptr);
+ update_socket_declarations(&node->inputs, node->declaration->inputs());
+ update_socket_declarations(&node->outputs, node->declaration->outputs());
+}
+
+bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *UNUSED(ntree), bNode *node)
+{
if (node->declaration != nullptr) {
- return;
+ return false;
+ }
+ if (node->typeinfo->declare == nullptr) {
+ return false;
}
+ if (node->typeinfo->declaration_is_dynamic) {
+ node->declaration = new blender::nodes::NodeDeclaration();
+ blender::nodes::NodeDeclarationBuilder builder{*node->declaration};
+ node->typeinfo->declare(builder);
+ }
+ else {
+ /* Declaration should have been created in #nodeRegisterType. */
+ BLI_assert(node->typeinfo->fixed_declaration != nullptr);
+ node->declaration = node->typeinfo->fixed_declaration;
+ }
+ return true;
+}
- node->declaration = new blender::nodes::NodeDeclaration();
- blender::nodes::NodeDeclarationBuilder builder{*node->declaration};
- node->typeinfo->declare(builder);
+bool nodeDeclarationEnsure(bNodeTree *ntree, bNode *node)
+{
+ if (nodeDeclarationEnsureOnOutdatedNode(ntree, node)) {
+ nodeSocketDeclarationsUpdate(node);
+ return true;
+ }
+ return false;
}
/* ************** Node Clipboard *********** */
@@ -4031,7 +3757,7 @@ void BKE_node_clipboard_init(const struct bNodeTree *ntree)
node_clipboard.type = ntree->type;
}
-void BKE_node_clipboard_clear(void)
+void BKE_node_clipboard_clear()
{
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &node_clipboard.links) {
nodeRemLink(nullptr, link);
@@ -4048,8 +3774,7 @@ void BKE_node_clipboard_clear(void)
#endif
}
-/* return false when one or more ID's are lost */
-bool BKE_node_clipboard_validate(void)
+bool BKE_node_clipboard_validate()
{
bool ok = true;
@@ -4127,22 +3852,22 @@ void BKE_node_clipboard_add_link(bNodeLink *link)
BLI_addtail(&node_clipboard.links, link);
}
-const ListBase *BKE_node_clipboard_get_nodes(void)
+const ListBase *BKE_node_clipboard_get_nodes()
{
return &node_clipboard.nodes;
}
-const ListBase *BKE_node_clipboard_get_links(void)
+const ListBase *BKE_node_clipboard_get_links()
{
return &node_clipboard.links;
}
-int BKE_node_clipboard_get_type(void)
+int BKE_node_clipboard_get_type()
{
return node_clipboard.type;
}
-void BKE_node_clipboard_free(void)
+void BKE_node_clipboard_free()
{
BKE_node_clipboard_validate();
BKE_node_clipboard_clear();
@@ -4150,7 +3875,6 @@ void BKE_node_clipboard_free(void)
/* Node Instance Hash */
-/* magic number for initial hash key */
const bNodeInstanceKey NODE_INSTANCE_KEY_BASE = {5381};
const bNodeInstanceKey NODE_INSTANCE_KEY_NONE = {0};
@@ -4377,7 +4101,7 @@ void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***r_deplist,
}
/* only updates node->level for detecting cycles links */
-static void ntree_update_node_level(bNodeTree *ntree)
+void ntreeUpdateNodeLevels(bNodeTree *ntree)
{
/* first clear tag */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -4392,763 +4116,48 @@ static void ntree_update_node_level(bNodeTree *ntree)
}
}
-void ntreeTagUsedSockets(bNodeTree *ntree)
-{
- /* first clear data */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- sock->flag &= ~SOCK_IN_USE;
- }
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
- sock->flag &= ~SOCK_IN_USE;
- }
- }
-
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- link->fromsock->flag |= SOCK_IN_USE;
- if (!(link->flag & NODE_LINK_MUTED)) {
- link->tosock->flag |= SOCK_IN_USE;
- }
- }
-}
-
-static void ntree_update_link_pointers(bNodeTree *ntree)
-{
- /* first clear data */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- sock->link = nullptr;
- }
- }
-
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- link->tosock->link = link;
- }
-
- ntreeTagUsedSockets(ntree);
-}
-
-static void ntree_validate_links(bNodeTree *ntree)
-{
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- link->flag |= NODE_LINK_VALID;
- if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level) {
- link->flag &= ~NODE_LINK_VALID;
- }
- else if (ntree->typeinfo->validate_link) {
- if (!ntree->typeinfo->validate_link(ntree, link)) {
- link->flag &= ~NODE_LINK_VALID;
- }
- }
- }
-}
-
void ntreeUpdateAllNew(Main *main)
{
+ Vector<bNodeTree *> new_ntrees;
+
/* Update all new node trees on file read or append, to add/remove sockets
* in groups nodes if the group changed, and handle any update flags that
* might have been set in file reading or versioning. */
FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
if (owner_id->tag & LIB_TAG_NEW) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->typeinfo->group_update_func) {
- node->typeinfo->group_update_func(ntree, node);
- }
- }
-
- ntreeUpdateTree(nullptr, ntree);
+ BKE_ntree_update_tag_all(ntree);
}
}
FOREACH_NODETREE_END;
+ BKE_ntree_update_main(main, nullptr);
}
-static FieldInferencingInterface *node_field_inferencing_interface_copy(
- const FieldInferencingInterface &field_inferencing_interface)
-{
- return new FieldInferencingInterface(field_inferencing_interface);
-}
-
-static void node_field_inferencing_interface_free(
- const FieldInferencingInterface *field_inferencing_interface)
-{
- delete field_inferencing_interface;
-}
-
-namespace blender::bke::node_field_inferencing {
-
-static bool is_field_socket_type(eNodeSocketDatatype type)
-{
- return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
-}
-
-static bool is_field_socket_type(const SocketRef &socket)
-{
- return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type);
-}
-
-static bool update_field_inferencing(bNodeTree &btree);
-
-static InputSocketFieldType get_interface_input_field_type(const NodeRef &node,
- const InputSocketRef &socket)
-{
- if (!is_field_socket_type(socket)) {
- return InputSocketFieldType::None;
- }
- if (node.is_reroute_node()) {
- return InputSocketFieldType::IsSupported;
- }
- if (node.is_group_output_node()) {
- /* Outputs always support fields when the data type is correct. */
- return InputSocketFieldType::IsSupported;
- }
- if (node.is_undefined()) {
- return InputSocketFieldType::None;
- }
-
- const NodeDeclaration *node_decl = node.declaration();
-
- /* Node declarations should be implemented for nodes involved here. */
- BLI_assert(node_decl != nullptr);
-
- /* Get the field type from the declaration. */
- const SocketDeclaration &socket_decl = *node_decl->inputs()[socket.index()];
- const InputSocketFieldType field_type = socket_decl.input_field_type();
- if (field_type == InputSocketFieldType::Implicit) {
- return field_type;
- }
- if (node_decl->is_function_node()) {
- /* In a function node, every socket supports fields. */
- return InputSocketFieldType::IsSupported;
- }
- return field_type;
-}
-
-static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node,
- const OutputSocketRef &socket)
-{
- if (!is_field_socket_type(socket)) {
- /* Non-field sockets always output data. */
- return OutputFieldDependency::ForDataSource();
- }
- if (node.is_reroute_node()) {
- /* The reroute just forwards what is passed in. */
- return OutputFieldDependency::ForDependentField();
- }
- if (node.is_group_input_node()) {
- /* Input nodes get special treatment in #determine_group_input_states. */
- return OutputFieldDependency::ForDependentField();
- }
- if (node.is_undefined()) {
- return OutputFieldDependency::ForDataSource();
- }
-
- const NodeDeclaration *node_decl = node.declaration();
-
- /* Node declarations should be implemented for nodes involved here. */
- BLI_assert(node_decl != nullptr);
-
- if (node_decl->is_function_node()) {
- /* In a generic function node, all outputs depend on all inputs. */
- return OutputFieldDependency::ForDependentField();
- }
-
- /* Use the socket declaration. */
- const SocketDeclaration &socket_decl = *node_decl->outputs()[socket.index()];
- return socket_decl.output_field_dependency();
-}
-
-/**
- * Retrieves information about how the node interacts with fields.
- * In the future, this information can be stored in the node declaration. This would allow this
- * function to return a reference, making it more efficient.
- */
-static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node)
-{
- /* Node groups already reference all required information, so just return that. */
- if (node.is_group_node()) {
- bNodeTree *group = (bNodeTree *)node.bnode()->id;
- if (group == nullptr) {
- return FieldInferencingInterface();
- }
- if (group->field_inferencing_interface == nullptr) {
- /* Update group recursively. */
- update_field_inferencing(*group);
- }
- return *group->field_inferencing_interface;
- }
-
- FieldInferencingInterface inferencing_interface;
- for (const InputSocketRef *input_socket : node.inputs()) {
- inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket));
- }
-
- for (const OutputSocketRef *output_socket : node.outputs()) {
- inferencing_interface.outputs.append(
- get_interface_output_field_dependency(node, *output_socket));
- }
- return inferencing_interface;
-}
-
-/**
- * This struct contains information for every socket. The values are propagated through the
- * network.
- */
-struct SocketFieldState {
- /* This socket is currently a single value. It could become a field though. */
- bool is_single = true;
- /* This socket is required to be a single value. It must not be a field. */
- bool requires_single = false;
- /* This socket starts a new field. */
- bool is_field_source = false;
-};
-
-static Vector<const InputSocketRef *> gather_input_socket_dependencies(
- const OutputFieldDependency &field_dependency, const NodeRef &node)
-{
- const OutputSocketFieldType type = field_dependency.field_type();
- Vector<const InputSocketRef *> input_sockets;
- switch (type) {
- case OutputSocketFieldType::FieldSource:
- case OutputSocketFieldType::None: {
- break;
- }
- case OutputSocketFieldType::DependentField: {
- /* This output depends on all inputs. */
- input_sockets.extend(node.inputs());
- break;
- }
- case OutputSocketFieldType::PartiallyDependent: {
- /* This output depends only on a few inputs. */
- for (const int i : field_dependency.linked_input_indices()) {
- input_sockets.append(&node.input(i));
- }
- break;
- }
- }
- return input_sockets;
-}
-
-/**
- * Check what the group output socket depends on. Potentially traverses the node tree
- * to figure out if it is always a field or if it depends on any group inputs.
- */
-static OutputFieldDependency find_group_output_dependencies(
- const InputSocketRef &group_output_socket,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- if (!is_field_socket_type(group_output_socket)) {
- return OutputFieldDependency::ForDataSource();
- }
-
- /* Use a Set here instead of an array indexed by socket id, because we my only need to look at
- * very few sockets. */
- Set<const InputSocketRef *> handled_sockets;
- Stack<const InputSocketRef *> sockets_to_check;
-
- handled_sockets.add(&group_output_socket);
- sockets_to_check.push(&group_output_socket);
-
- /* Keeps track of group input indices that are (indirectly) connected to the output. */
- Vector<int> linked_input_indices;
-
- while (!sockets_to_check.is_empty()) {
- const InputSocketRef *input_socket = sockets_to_check.pop();
-
- for (const OutputSocketRef *origin_socket : input_socket->logically_linked_sockets()) {
- const NodeRef &origin_node = origin_socket->node();
- const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()];
-
- if (origin_state.is_field_source) {
- if (origin_node.is_group_input_node()) {
- /* Found a group input that the group output depends on. */
- linked_input_indices.append_non_duplicates(origin_socket->index());
- }
- else {
- /* Found a field source that is not the group input. So the output is always a field. */
- return OutputFieldDependency::ForFieldSource();
- }
- }
- else if (!origin_state.is_single) {
- const FieldInferencingInterface inferencing_interface =
- get_node_field_inferencing_interface(origin_node);
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[origin_socket->index()];
-
- /* Propagate search further to the left. */
- for (const InputSocketRef *origin_input_socket :
- gather_input_socket_dependencies(field_dependency, origin_node)) {
- if (!field_state_by_socket_id[origin_input_socket->id()].is_single) {
- if (handled_sockets.add(origin_input_socket)) {
- sockets_to_check.push(origin_input_socket);
- }
- }
- }
- }
- }
- }
- return OutputFieldDependency::ForPartiallyDependentField(std::move(linked_input_indices));
-}
-
-static void propagate_data_requirements_from_right_to_left(
- const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- const Vector<const NodeRef *> sorted_nodes = tree.toposort(
- NodeTreeRef::ToposortDirection::RightToLeft);
-
- for (const NodeRef *node : sorted_nodes) {
- const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
- *node);
-
- for (const OutputSocketRef *output_socket : node->outputs()) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
-
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[output_socket->index()];
-
- if (field_dependency.field_type() == OutputSocketFieldType::FieldSource) {
- continue;
- }
- if (field_dependency.field_type() == OutputSocketFieldType::None) {
- state.requires_single = true;
- continue;
- }
-
- /* The output is required to be a single value when it is connected to any input that does
- * not support fields. */
- for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) {
- state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
- }
-
- if (state.requires_single) {
- bool any_input_is_field_implicitly = false;
- const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies(
- field_dependency, *node);
- for (const InputSocketRef *input_socket : connected_inputs) {
- if (inferencing_interface.inputs[input_socket->index()] ==
- InputSocketFieldType::Implicit) {
- if (!input_socket->is_logically_linked()) {
- any_input_is_field_implicitly = true;
- break;
- }
- }
- }
- if (any_input_is_field_implicitly) {
- /* This output isn't a single value actually. */
- state.requires_single = false;
- }
- else {
- /* If the output is required to be a single value, the connected inputs in the same node
- * must not be fields as well. */
- for (const InputSocketRef *input_socket : connected_inputs) {
- field_state_by_socket_id[input_socket->id()].requires_single = true;
- }
- }
- }
- }
-
- /* Some inputs do not require fields independent of what the outputs are connected to. */
- for (const InputSocketRef *input_socket : node->inputs()) {
- SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
- if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) {
- state.requires_single = true;
- }
- }
- }
-}
-
-static void determine_group_input_states(
- const NodeTreeRef &tree,
- FieldInferencingInterface &new_inferencing_interface,
- const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- {
- /* Non-field inputs never support fields. */
- int index;
- LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) {
- if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) {
- new_inferencing_interface.inputs[index] = InputSocketFieldType::None;
- }
- }
- }
- /* Check if group inputs are required to be single values, because they are (indirectly)
- * connected to some socket that does not support fields. */
- for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
- for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- if (state.requires_single) {
- new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None;
- }
- }
- }
- /* If an input does not support fields, this should be reflected in all Group Input nodes. */
- for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
- for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] !=
- InputSocketFieldType::None;
- if (supports_field) {
- state.is_single = false;
- state.is_field_source = true;
- }
- else {
- state.requires_single = true;
- }
- }
- SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()];
- dummy_socket_state.requires_single = true;
- }
-}
-
-static void propagate_field_status_from_left_to_right(
- const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- Vector<const NodeRef *> sorted_nodes = tree.toposort(
- NodeTreeRef::ToposortDirection::LeftToRight);
-
- for (const NodeRef *node : sorted_nodes) {
- if (node->is_group_input_node()) {
- continue;
- }
-
- const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
- *node);
-
- /* Update field state of input sockets, also taking into account linked origin sockets. */
- for (const InputSocketRef *input_socket : node->inputs()) {
- SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
- if (state.requires_single) {
- state.is_single = true;
- continue;
- }
- state.is_single = true;
- if (input_socket->logically_linked_sockets().is_empty()) {
- if (inferencing_interface.inputs[input_socket->index()] ==
- InputSocketFieldType::Implicit) {
- state.is_single = false;
- }
- }
- else {
- for (const OutputSocketRef *origin_socket : input_socket->logically_linked_sockets()) {
- if (!field_state_by_socket_id[origin_socket->id()].is_single) {
- state.is_single = false;
- break;
- }
- }
- }
- }
-
- /* Update field state of output sockets, also taking into account input sockets. */
- for (const OutputSocketRef *output_socket : node->outputs()) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[output_socket->index()];
-
- switch (field_dependency.field_type()) {
- case OutputSocketFieldType::None: {
- state.is_single = true;
- break;
- }
- case OutputSocketFieldType::FieldSource: {
- state.is_single = false;
- state.is_field_source = true;
- break;
- }
- case OutputSocketFieldType::PartiallyDependent:
- case OutputSocketFieldType::DependentField: {
- for (const InputSocketRef *input_socket :
- gather_input_socket_dependencies(field_dependency, *node)) {
- if (!field_state_by_socket_id[input_socket->id()].is_single) {
- state.is_single = false;
- break;
- }
- }
- break;
- }
- }
- }
- }
-}
-
-static void determine_group_output_states(const NodeTreeRef &tree,
- FieldInferencingInterface &new_inferencing_interface,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) {
- /* Ignore inactive group output nodes. */
- if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) {
- continue;
- }
- /* Determine dependencies of all group outputs. */
- for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) {
- OutputFieldDependency field_dependency = find_group_output_dependencies(
- *group_output_socket, field_state_by_socket_id);
- new_inferencing_interface.outputs[group_output_socket->index()] = std::move(
- field_dependency);
- }
- break;
- }
-}
-
-static void update_socket_shapes(const NodeTreeRef &tree,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
- const eNodeSocketDisplayShape data_but_can_be_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND_DOT;
- const eNodeSocketDisplayShape is_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND;
-
- for (const InputSocketRef *socket : tree.input_sockets()) {
- bNodeSocket *bsocket = socket->bsocket();
- const SocketFieldState &state = field_state_by_socket_id[socket->id()];
- if (state.requires_single) {
- bsocket->display_shape = requires_data_shape;
- }
- else if (state.is_single) {
- bsocket->display_shape = data_but_can_be_field_shape;
- }
- else {
- bsocket->display_shape = is_field_shape;
- }
- }
- for (const OutputSocketRef *socket : tree.output_sockets()) {
- bNodeSocket *bsocket = socket->bsocket();
- const SocketFieldState &state = field_state_by_socket_id[socket->id()];
- if (state.requires_single) {
- bsocket->display_shape = requires_data_shape;
- }
- else if (state.is_single) {
- bsocket->display_shape = data_but_can_be_field_shape;
- }
- else {
- bsocket->display_shape = is_field_shape;
- }
- }
-}
-
-static bool update_field_inferencing(bNodeTree &btree)
-{
- using namespace blender::nodes;
- if (btree.type != NTREE_GEOMETRY) {
- return false;
- }
-
- /* Create new inferencing interface for this node group. */
- FieldInferencingInterface *new_inferencing_interface = new FieldInferencingInterface();
- new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs),
- InputSocketFieldType::IsSupported);
- new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs),
- OutputFieldDependency::ForDataSource());
-
- /* Create #NodeTreeRef to accelerate various queries on the node tree (e.g. linked sockets). */
- const NodeTreeRef tree{&btree};
-
- /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */
- Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size());
-
- propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id);
- determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id);
- propagate_field_status_from_left_to_right(tree, field_state_by_socket_id);
- determine_group_output_states(tree, *new_inferencing_interface, field_state_by_socket_id);
- update_socket_shapes(tree, field_state_by_socket_id);
-
- /* Update the previous group interface. */
- const bool group_interface_changed = btree.field_inferencing_interface == nullptr ||
- *btree.field_inferencing_interface !=
- *new_inferencing_interface;
- delete btree.field_inferencing_interface;
- btree.field_inferencing_interface = new_inferencing_interface;
-
- return group_interface_changed;
-}
-
-} // namespace blender::bke::node_field_inferencing
-
-/**
- * \param tree_update_flag: #eNodeTreeUpdate enum.
- */
-void ntreeUpdateAllUsers(Main *main, ID *id, const int tree_update_flag)
+void ntreeUpdateAllUsers(Main *main, ID *id)
{
if (id == nullptr) {
return;
}
+ bool need_update = false;
+
/* Update all users of ngroup, to add/remove sockets as needed. */
FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
- bool need_update = false;
-
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->id == id) {
- if (node->typeinfo->group_update_func) {
- node->typeinfo->group_update_func(ntree, node);
- }
-
+ BKE_ntree_update_tag_node_property(ntree, node);
need_update = true;
}
}
-
- if (need_update) {
- ntree->update |= tree_update_flag;
- ntreeUpdateTree(tree_update_flag ? main : nullptr, ntree);
- }
}
FOREACH_NODETREE_END;
-
- if (GS(id->name) == ID_NT) {
- bNodeTree *ngroup = (bNodeTree *)id;
- if (ngroup->type == NTREE_GEOMETRY && (ngroup->update & NTREE_UPDATE_GROUP)) {
- LISTBASE_FOREACH (Object *, object, &main->objects) {
- LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
- if (md->type == eModifierType_Nodes) {
- NodesModifierData *nmd = (NodesModifierData *)md;
- if (nmd->node_group == ngroup) {
- MOD_nodes_update_interface(object, nmd);
- }
- }
- }
- }
- }
- }
-}
-
-void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
-{
- if (!ntree) {
- return;
- }
-
- /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
- if (ntree->is_updating) {
- return;
- }
- ntree->is_updating = true;
-
- if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
- /* set the bNodeSocket->link pointers */
- ntree_update_link_pointers(ntree);
- }
-
- /* update individual nodes */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- /* node tree update tags override individual node update flags */
- if ((node->update & NODE_UPDATE) || (ntree->update & NTREE_UPDATE)) {
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
-
- nodeUpdateInternalLinks(ntree, node);
- }
- }
-
- /* generic tree update callback */
- if (ntree->typeinfo->update) {
- ntree->typeinfo->update(ntree);
- }
- /* XXX this should be moved into the tree type update callback for tree supporting node groups.
- * Currently the node tree interface is still a generic feature of the base NodeTree type.
- */
- if (ntree->update & NTREE_UPDATE_GROUP) {
- ntreeInterfaceTypeUpdate(ntree);
- }
-
- int tree_user_update_flag = 0;
-
- if (ntree->update & NTREE_UPDATE) {
- /* If the field interface of this node tree has changed, all node trees using
- * this group will need to recalculate their interface as well. */
- if (blender::bke::node_field_inferencing::update_field_inferencing(*ntree)) {
- tree_user_update_flag |= NTREE_UPDATE_FIELD_INFERENCING;
- }
- }
-
- if (bmain) {
- ntreeUpdateAllUsers(bmain, &ntree->id, tree_user_update_flag);
- }
-
- if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
- /* node updates can change sockets or links, repeat link pointer update afterward */
- ntree_update_link_pointers(ntree);
-
- /* update the node level from link dependencies */
- ntree_update_node_level(ntree);
-
- /* check link validity */
- ntree_validate_links(ntree);
- }
-
- /* clear update flags */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- node->update = 0;
- }
- ntree->update = 0;
-
- ntree->is_updating = false;
-}
-
-void nodeUpdate(bNodeTree *ntree, bNode *node)
-{
- /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
- if (ntree->is_updating) {
- return;
- }
- ntree->is_updating = true;
-
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
-
- nodeUpdateInternalLinks(ntree, node);
-
- /* clear update flag */
- node->update = 0;
-
- ntree->is_updating = false;
-}
-
-bool nodeUpdateID(bNodeTree *ntree, ID *id)
-{
- bool changed = false;
-
- if (ELEM(nullptr, id, ntree)) {
- return changed;
- }
-
- /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
- if (ntree->is_updating) {
- return changed;
- }
- ntree->is_updating = true;
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id == id) {
- changed = true;
- node->update |= NODE_UPDATE_ID;
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
- /* clear update flag */
- node->update = 0;
- }
- }
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- nodeUpdateInternalLinks(ntree, node);
- }
-
- ntree->is_updating = false;
- return changed;
-}
-
-void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node)
-{
- BLI_freelistN(&node->internal_links);
-
- if (node->typeinfo && node->typeinfo->update_internal_links) {
- node->typeinfo->update_internal_links(ntree, node);
+ if (need_update) {
+ BKE_ntree_update_main(main, nullptr);
}
}
/* ************* node type access ********** */
-void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen)
+void nodeLabel(const bNodeTree *ntree, const bNode *node, char *label, int maxlen)
{
label[0] = '\0';
@@ -5170,7 +4179,6 @@ void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen)
}
}
-/* Get node socket label if it is set */
const char *nodeSocketLabel(const bNodeSocket *sock)
{
return (sock->label[0] != '\0') ? sock->label : sock->name;
@@ -5199,8 +4207,7 @@ static bool node_poll_instance_default(bNode *node, bNodeTree *ntree, const char
return node->typeinfo->poll(node->typeinfo, ntree, disabled_hint);
}
-/* NOLINTNEXTLINE: readability-function-size */
-void node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
/* Use static type info header to map static int type to identifier string and RNA struct type.
* Associate the RNA struct type with the bNodeType.
@@ -5227,7 +4234,6 @@ void node_type_base(bNodeType *ntype, int type, const char *name, short nclass,
ntype->type = type;
BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name));
ntype->nclass = nclass;
- ntype->flag = flag;
node_type_base_defaults(ntype);
@@ -5235,14 +4241,12 @@ void node_type_base(bNodeType *ntype, int type, const char *name, short nclass,
ntype->poll_instance = node_poll_instance_default;
}
-void node_type_base_custom(
- bNodeType *ntype, const char *idname, const char *name, short nclass, short flag)
+void node_type_base_custom(bNodeType *ntype, const char *idname, const char *name, short nclass)
{
BLI_strncpy(ntype->idname, idname, sizeof(ntype->idname));
ntype->type = NODE_CUSTOM;
BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name));
ntype->nclass = nclass;
- ntype->flag = flag;
node_type_base_defaults(ntype);
}
@@ -5352,10 +4356,6 @@ void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size)
}
}
-/**
- * \warning Nodes defining a storage type _must_ allocate this for new nodes.
- * Otherwise nodes will reload as undefined (T46619).
- */
void node_type_storage(bNodeType *ntype,
const char *storagename,
void (*freefunc)(struct bNode *node),
@@ -5373,13 +4373,6 @@ void node_type_storage(bNodeType *ntype,
ntype->freefunc = freefunc;
}
-void node_type_label(
- struct bNodeType *ntype,
- void (*labelfunc)(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen))
-{
- ntype->labelfunc = labelfunc;
-}
-
void node_type_update(struct bNodeType *ntype,
void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
{
@@ -5407,12 +4400,6 @@ void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn)
ntype->gpu_fn = gpu_fn;
}
-void node_type_internal_links(bNodeType *ntype,
- void (*update_internal_links)(bNodeTree *, bNode *))
-{
- ntype->update_internal_links = update_internal_links;
-}
-
/* callbacks for undefined types */
static bool node_undefined_poll(bNodeType *UNUSED(ntype),
@@ -5430,11 +4417,12 @@ static void register_undefined_types()
* they are just used as placeholders in case the actual types are not registered.
*/
+ NodeTreeTypeUndefined.type = NTREE_UNDEFINED;
strcpy(NodeTreeTypeUndefined.idname, "NodeTreeUndefined");
strcpy(NodeTreeTypeUndefined.ui_name, N_("Undefined"));
strcpy(NodeTreeTypeUndefined.ui_description, N_("Undefined Node Tree Type"));
- node_type_base_custom(&NodeTypeUndefined, "NodeUndefined", "Undefined", 0, 0);
+ node_type_base_custom(&NodeTypeUndefined, "NodeUndefined", "Undefined", 0);
NodeTypeUndefined.poll = node_undefined_poll;
BLI_strncpy(NodeSocketTypeUndefined.idname,
@@ -5459,6 +4447,7 @@ static void registerCompositNodes()
register_node_type_cmp_value();
register_node_type_cmp_rgb();
register_node_type_cmp_curve_time();
+ register_node_type_cmp_scene_time();
register_node_type_cmp_movieclip();
register_node_type_cmp_composite();
@@ -5499,6 +4488,7 @@ static void registerCompositNodes()
register_node_type_cmp_denoise();
register_node_type_cmp_antialiasing();
+ register_node_type_cmp_convert_color_space();
register_node_type_cmp_valtorgb();
register_node_type_cmp_rgbtobw();
register_node_type_cmp_setalpha();
@@ -5574,6 +4564,7 @@ static void registerShaderNodes()
register_node_type_sh_shadertorgb();
register_node_type_sh_normal();
register_node_type_sh_mapping();
+ register_node_type_sh_curve_float();
register_node_type_sh_curve_vec();
register_node_type_sh_curve_rgb();
register_node_type_sh_map_range();
@@ -5677,6 +4668,7 @@ static void registerTextureNodes()
register_node_type_sh_tangent();
register_node_type_sh_normal_map();
register_node_type_sh_hair_info();
+ register_node_type_sh_point_info();
register_node_type_sh_volume_info();
register_node_type_tex_checker();
@@ -5709,10 +4701,25 @@ static void registerGeometryNodes()
register_node_type_geo_legacy_attribute_proximity();
register_node_type_geo_legacy_attribute_randomize();
+ register_node_type_geo_legacy_attribute_transfer();
+ register_node_type_geo_legacy_curve_endpoints();
+ register_node_type_geo_legacy_curve_reverse();
+ register_node_type_geo_legacy_curve_set_handles();
+ register_node_type_geo_legacy_curve_spline_type();
+ register_node_type_geo_legacy_curve_subdivide();
+ register_node_type_geo_legacy_curve_to_points();
+ register_node_type_geo_legacy_delete_geometry();
+ register_node_type_geo_legacy_edge_split();
register_node_type_geo_legacy_material_assign();
+ register_node_type_geo_legacy_mesh_to_curve();
+ register_node_type_geo_legacy_points_to_volume();
+ register_node_type_geo_legacy_raycast();
+ register_node_type_geo_legacy_select_by_handle_type();
register_node_type_geo_legacy_select_by_material();
- register_node_type_geo_legacy_curve_reverse();
+ register_node_type_geo_legacy_subdivision_surface();
+ register_node_type_geo_legacy_volume_to_mesh();
+ register_node_type_geo_accumulate_field();
register_node_type_geo_align_rotation_to_vector();
register_node_type_geo_attribute_capture();
register_node_type_geo_attribute_clamp();
@@ -5721,6 +4728,7 @@ static void registerGeometryNodes()
register_node_type_geo_attribute_compare();
register_node_type_geo_attribute_convert();
register_node_type_geo_attribute_curve_map();
+ register_node_type_geo_attribute_domain_size();
register_node_type_geo_attribute_fill();
register_node_type_geo_attribute_map_range();
register_node_type_geo_attribute_math();
@@ -5728,18 +4736,18 @@ static void registerGeometryNodes()
register_node_type_geo_attribute_remove();
register_node_type_geo_attribute_separate_xyz();
register_node_type_geo_attribute_statistic();
- register_node_type_geo_attribute_transfer();
register_node_type_geo_attribute_vector_math();
register_node_type_geo_attribute_vector_rotate();
register_node_type_geo_boolean();
register_node_type_geo_bounding_box();
register_node_type_geo_collection_info();
register_node_type_geo_convex_hull();
- register_node_type_geo_curve_endpoints();
+ register_node_type_geo_curve_endpoint_selection();
register_node_type_geo_curve_fill();
register_node_type_geo_curve_fillet();
+ register_node_type_geo_curve_handle_type_selection();
register_node_type_geo_curve_length();
- register_node_type_geo_curve_parameter();
+ register_node_type_geo_curve_primitive_arc();
register_node_type_geo_curve_primitive_bezier_segment();
register_node_type_geo_curve_primitive_circle();
register_node_type_geo_curve_primitive_line();
@@ -5751,6 +4759,7 @@ static void registerGeometryNodes()
register_node_type_geo_curve_reverse();
register_node_type_geo_curve_sample();
register_node_type_geo_curve_set_handles();
+ register_node_type_geo_curve_spline_parameter();
register_node_type_geo_curve_spline_type();
register_node_type_geo_curve_subdivide();
register_node_type_geo_curve_to_mesh();
@@ -5758,18 +4767,42 @@ static void registerGeometryNodes()
register_node_type_geo_curve_trim();
register_node_type_geo_delete_geometry();
register_node_type_geo_distribute_points_on_faces();
+ register_node_type_geo_dual_mesh();
register_node_type_geo_edge_split();
+ register_node_type_geo_extrude_mesh();
+ register_node_type_geo_field_at_index();
+ register_node_type_geo_flip_faces();
+ register_node_type_geo_geometry_to_instance();
+ register_node_type_geo_image_texture();
+ register_node_type_geo_input_curve_handles();
+ register_node_type_geo_input_curve_tilt();
+ register_node_type_geo_input_id();
register_node_type_geo_input_index();
+ register_node_type_geo_input_material_index();
register_node_type_geo_input_material();
+ register_node_type_geo_input_mesh_edge_angle();
+ register_node_type_geo_input_mesh_edge_neighbors();
+ register_node_type_geo_input_mesh_edge_vertices();
+ register_node_type_geo_input_mesh_face_area();
+ register_node_type_geo_input_mesh_face_neighbors();
+ register_node_type_geo_input_mesh_island();
+ register_node_type_geo_input_mesh_vertex_neighbors();
register_node_type_geo_input_normal();
register_node_type_geo_input_position();
+ register_node_type_geo_input_radius();
+ register_node_type_geo_input_scene_time();
+ register_node_type_geo_input_shade_smooth();
+ register_node_type_geo_input_spline_cyclic();
+ register_node_type_geo_input_spline_length();
+ register_node_type_geo_input_spline_resolution();
register_node_type_geo_input_tangent();
register_node_type_geo_instance_on_points();
+ register_node_type_geo_instances_to_points();
register_node_type_geo_is_viewport();
register_node_type_geo_join_geometry();
- register_node_type_geo_material_assign();
register_node_type_geo_material_replace();
register_node_type_geo_material_selection();
+ register_node_type_geo_merge_by_distance();
register_node_type_geo_mesh_primitive_circle();
register_node_type_geo_mesh_primitive_cone();
register_node_type_geo_mesh_primitive_cube();
@@ -5793,15 +4826,30 @@ static void registerGeometryNodes()
register_node_type_geo_proximity();
register_node_type_geo_raycast();
register_node_type_geo_realize_instances();
+ register_node_type_geo_rotate_instances();
register_node_type_geo_sample_texture();
- register_node_type_geo_select_by_handle_type();
+ register_node_type_geo_scale_elements();
+ register_node_type_geo_scale_instances();
register_node_type_geo_separate_components();
+ register_node_type_geo_separate_geometry();
+ register_node_type_geo_set_curve_handles();
+ register_node_type_geo_set_curve_radius();
+ register_node_type_geo_set_curve_tilt();
+ register_node_type_geo_set_id();
+ register_node_type_geo_set_material_index();
+ register_node_type_geo_set_material();
+ register_node_type_geo_set_point_radius();
register_node_type_geo_set_position();
+ register_node_type_geo_set_shade_smooth();
+ register_node_type_geo_set_spline_cyclic();
+ register_node_type_geo_set_spline_resolution();
register_node_type_geo_string_join();
register_node_type_geo_string_to_curves();
register_node_type_geo_subdivision_surface();
register_node_type_geo_switch();
+ register_node_type_geo_transfer_attribute();
register_node_type_geo_transform();
+ register_node_type_geo_translate_instances();
register_node_type_geo_triangulate();
register_node_type_geo_viewer();
register_node_type_geo_volume_to_mesh();
@@ -5811,19 +4859,25 @@ static void registerFunctionNodes()
{
register_node_type_fn_legacy_random_float();
+ register_node_type_fn_align_euler_to_vector();
register_node_type_fn_boolean_math();
- register_node_type_fn_float_compare();
+ register_node_type_fn_compare();
register_node_type_fn_float_to_int();
+ register_node_type_fn_input_bool();
+ register_node_type_fn_input_color();
+ register_node_type_fn_input_int();
register_node_type_fn_input_special_characters();
register_node_type_fn_input_string();
register_node_type_fn_input_vector();
register_node_type_fn_random_value();
+ register_node_type_fn_replace_string();
+ register_node_type_fn_rotate_euler();
+ register_node_type_fn_slice_string();
register_node_type_fn_string_length();
- register_node_type_fn_string_substring();
register_node_type_fn_value_to_string();
}
-void BKE_node_system_init(void)
+void BKE_node_system_init()
{
nodetreetypes_hash = BLI_ghash_str_new("nodetreetypes_hash gh");
nodetypes_hash = BLI_ghash_str_new("nodetypes_hash gh");
@@ -5850,7 +4904,7 @@ void BKE_node_system_init(void)
registerFunctionNodes();
}
-void BKE_node_system_exit(void)
+void BKE_node_system_exit()
{
if (nodetypes_hash) {
NODE_TYPES_BEGIN (nt) {
diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc
new file mode 100644
index 00000000000..0555707b64c
--- /dev/null
+++ b/source/blender/blenkernel/intern/node_tree_update.cc
@@ -0,0 +1,1670 @@
+/*
+ * 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 "BLI_map.hh"
+#include "BLI_multi_value_map.hh"
+#include "BLI_noise.hh"
+#include "BLI_set.hh"
+#include "BLI_stack.hh"
+#include "BLI_vector_set.hh"
+
+#include "DNA_anim_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
+
+#include "BKE_anim_data.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
+
+#include "MOD_nodes.h"
+
+#include "NOD_node_declaration.hh"
+#include "NOD_node_tree_ref.hh"
+#include "NOD_texture.h"
+
+#include "DEG_depsgraph_query.h"
+
+using namespace blender::nodes;
+
+/**
+ * These flags are used by the `changed_flag` field in #bNodeTree, #bNode and #bNodeSocket.
+ * This enum is not part of the public api. It should be used through the `BKE_ntree_update_tag_*`
+ * api.
+ */
+enum eNodeTreeChangedFlag {
+ NTREE_CHANGED_NOTHING = 0,
+ NTREE_CHANGED_ANY = (1 << 1),
+ NTREE_CHANGED_NODE_PROPERTY = (1 << 2),
+ NTREE_CHANGED_NODE_OUTPUT = (1 << 3),
+ NTREE_CHANGED_INTERFACE = (1 << 4),
+ NTREE_CHANGED_LINK = (1 << 5),
+ NTREE_CHANGED_REMOVED_NODE = (1 << 6),
+ NTREE_CHANGED_REMOVED_SOCKET = (1 << 7),
+ NTREE_CHANGED_SOCKET_PROPERTY = (1 << 8),
+ NTREE_CHANGED_INTERNAL_LINK = (1 << 9),
+ NTREE_CHANGED_ALL = -1,
+};
+
+static void add_tree_tag(bNodeTree *ntree, const eNodeTreeChangedFlag flag)
+{
+ ntree->changed_flag |= flag;
+}
+
+static void add_node_tag(bNodeTree *ntree, bNode *node, const eNodeTreeChangedFlag flag)
+{
+ add_tree_tag(ntree, flag);
+ node->changed_flag |= flag;
+}
+
+static void add_socket_tag(bNodeTree *ntree, bNodeSocket *socket, const eNodeTreeChangedFlag flag)
+{
+ add_tree_tag(ntree, flag);
+ socket->changed_flag |= flag;
+}
+
+namespace blender::bke {
+
+namespace node_field_inferencing {
+
+static bool is_field_socket_type(eNodeSocketDatatype type)
+{
+ return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
+}
+
+static bool is_field_socket_type(const SocketRef &socket)
+{
+ return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type);
+}
+
+static InputSocketFieldType get_interface_input_field_type(const NodeRef &node,
+ const InputSocketRef &socket)
+{
+ if (!is_field_socket_type(socket)) {
+ return InputSocketFieldType::None;
+ }
+ if (node.is_reroute_node()) {
+ return InputSocketFieldType::IsSupported;
+ }
+ if (node.is_group_output_node()) {
+ /* Outputs always support fields when the data type is correct. */
+ return InputSocketFieldType::IsSupported;
+ }
+ if (node.is_undefined()) {
+ return InputSocketFieldType::None;
+ }
+
+ const NodeDeclaration *node_decl = node.declaration();
+
+ /* Node declarations should be implemented for nodes involved here. */
+ BLI_assert(node_decl != nullptr);
+
+ /* Get the field type from the declaration. */
+ const SocketDeclaration &socket_decl = *node_decl->inputs()[socket.index()];
+ const InputSocketFieldType field_type = socket_decl.input_field_type();
+ if (field_type == InputSocketFieldType::Implicit) {
+ return field_type;
+ }
+ if (node_decl->is_function_node()) {
+ /* In a function node, every socket supports fields. */
+ return InputSocketFieldType::IsSupported;
+ }
+ return field_type;
+}
+
+static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node,
+ const OutputSocketRef &socket)
+{
+ if (!is_field_socket_type(socket)) {
+ /* Non-field sockets always output data. */
+ return OutputFieldDependency::ForDataSource();
+ }
+ if (node.is_reroute_node()) {
+ /* The reroute just forwards what is passed in. */
+ return OutputFieldDependency::ForDependentField();
+ }
+ if (node.is_group_input_node()) {
+ /* Input nodes get special treatment in #determine_group_input_states. */
+ return OutputFieldDependency::ForDependentField();
+ }
+ if (node.is_undefined()) {
+ return OutputFieldDependency::ForDataSource();
+ }
+
+ const NodeDeclaration *node_decl = node.declaration();
+
+ /* Node declarations should be implemented for nodes involved here. */
+ BLI_assert(node_decl != nullptr);
+
+ if (node_decl->is_function_node()) {
+ /* In a generic function node, all outputs depend on all inputs. */
+ return OutputFieldDependency::ForDependentField();
+ }
+
+ /* Use the socket declaration. */
+ const SocketDeclaration &socket_decl = *node_decl->outputs()[socket.index()];
+ return socket_decl.output_field_dependency();
+}
+
+static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node)
+{
+ FieldInferencingInterface inferencing_interface;
+ inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size());
+ inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(),
+ node.outputs().size());
+ return inferencing_interface;
+}
+
+/**
+ * Retrieves information about how the node interacts with fields.
+ * In the future, this information can be stored in the node declaration. This would allow this
+ * function to return a reference, making it more efficient.
+ */
+static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node)
+{
+ /* Node groups already reference all required information, so just return that. */
+ if (node.is_group_node()) {
+ bNodeTree *group = (bNodeTree *)node.bnode()->id;
+ if (group == nullptr) {
+ return FieldInferencingInterface();
+ }
+ if (!ntreeIsRegistered(group)) {
+ /* This can happen when there is a linked node group that was not found (see T92799). */
+ return get_dummy_field_inferencing_interface(node);
+ }
+ if (group->field_inferencing_interface == nullptr) {
+ /* This shouldn't happen because referenced node groups should always be updated first. */
+ BLI_assert_unreachable();
+ }
+ return *group->field_inferencing_interface;
+ }
+
+ FieldInferencingInterface inferencing_interface;
+ for (const InputSocketRef *input_socket : node.inputs()) {
+ inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket));
+ }
+
+ for (const OutputSocketRef *output_socket : node.outputs()) {
+ inferencing_interface.outputs.append(
+ get_interface_output_field_dependency(node, *output_socket));
+ }
+ return inferencing_interface;
+}
+
+/**
+ * This struct contains information for every socket. The values are propagated through the
+ * network.
+ */
+struct SocketFieldState {
+ /* This socket starts a new field. */
+ bool is_field_source = false;
+ /* This socket can never become a field, because the node itself does not support it. */
+ bool is_always_single = false;
+ /* This socket is currently a single value. It could become a field though. */
+ bool is_single = true;
+ /* This socket is required to be a single value. This can be because the node itself only
+ * supports this socket to be a single value, or because a node afterwards requires this to be a
+ * single value. */
+ bool requires_single = false;
+};
+
+static Vector<const InputSocketRef *> gather_input_socket_dependencies(
+ const OutputFieldDependency &field_dependency, const NodeRef &node)
+{
+ const OutputSocketFieldType type = field_dependency.field_type();
+ Vector<const InputSocketRef *> input_sockets;
+ switch (type) {
+ case OutputSocketFieldType::FieldSource:
+ case OutputSocketFieldType::None: {
+ break;
+ }
+ case OutputSocketFieldType::DependentField: {
+ /* This output depends on all inputs. */
+ input_sockets.extend(node.inputs());
+ break;
+ }
+ case OutputSocketFieldType::PartiallyDependent: {
+ /* This output depends only on a few inputs. */
+ for (const int i : field_dependency.linked_input_indices()) {
+ input_sockets.append(&node.input(i));
+ }
+ break;
+ }
+ }
+ return input_sockets;
+}
+
+/**
+ * Check what the group output socket depends on. Potentially traverses the node tree
+ * to figure out if it is always a field or if it depends on any group inputs.
+ */
+static OutputFieldDependency find_group_output_dependencies(
+ const InputSocketRef &group_output_socket,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ if (!is_field_socket_type(group_output_socket)) {
+ return OutputFieldDependency::ForDataSource();
+ }
+
+ /* Use a Set here instead of an array indexed by socket id, because we my only need to look at
+ * very few sockets. */
+ Set<const InputSocketRef *> handled_sockets;
+ Stack<const InputSocketRef *> sockets_to_check;
+
+ handled_sockets.add(&group_output_socket);
+ sockets_to_check.push(&group_output_socket);
+
+ /* Keeps track of group input indices that are (indirectly) connected to the output. */
+ Vector<int> linked_input_indices;
+
+ while (!sockets_to_check.is_empty()) {
+ const InputSocketRef *input_socket = sockets_to_check.pop();
+
+ for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
+ const NodeRef &origin_node = origin_socket->node();
+ const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()];
+
+ if (origin_state.is_field_source) {
+ if (origin_node.is_group_input_node()) {
+ /* Found a group input that the group output depends on. */
+ linked_input_indices.append_non_duplicates(origin_socket->index());
+ }
+ else {
+ /* Found a field source that is not the group input. So the output is always a field. */
+ return OutputFieldDependency::ForFieldSource();
+ }
+ }
+ else if (!origin_state.is_single) {
+ const FieldInferencingInterface inferencing_interface =
+ get_node_field_inferencing_interface(origin_node);
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[origin_socket->index()];
+
+ /* Propagate search further to the left. */
+ for (const InputSocketRef *origin_input_socket :
+ gather_input_socket_dependencies(field_dependency, origin_node)) {
+ if (!origin_input_socket->is_available()) {
+ continue;
+ }
+ if (!field_state_by_socket_id[origin_input_socket->id()].is_single) {
+ if (handled_sockets.add(origin_input_socket)) {
+ sockets_to_check.push(origin_input_socket);
+ }
+ }
+ }
+ }
+ }
+ }
+ return OutputFieldDependency::ForPartiallyDependentField(std::move(linked_input_indices));
+}
+
+static void propagate_data_requirements_from_right_to_left(
+ const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
+ NodeTreeRef::ToposortDirection::RightToLeft);
+
+ for (const NodeRef *node : toposort_result.sorted_nodes) {
+ const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
+ *node);
+
+ for (const OutputSocketRef *output_socket : node->outputs()) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[output_socket->index()];
+
+ if (field_dependency.field_type() == OutputSocketFieldType::FieldSource) {
+ continue;
+ }
+ if (field_dependency.field_type() == OutputSocketFieldType::None) {
+ state.requires_single = true;
+ state.is_always_single = true;
+ continue;
+ }
+
+ /* The output is required to be a single value when it is connected to any input that does
+ * not support fields. */
+ for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) {
+ if (target_socket->is_available()) {
+ state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
+ }
+ }
+
+ if (state.requires_single) {
+ bool any_input_is_field_implicitly = false;
+ const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies(
+ field_dependency, *node);
+ for (const InputSocketRef *input_socket : connected_inputs) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ if (inferencing_interface.inputs[input_socket->index()] ==
+ InputSocketFieldType::Implicit) {
+ if (!input_socket->is_logically_linked()) {
+ any_input_is_field_implicitly = true;
+ break;
+ }
+ }
+ }
+ if (any_input_is_field_implicitly) {
+ /* This output isn't a single value actually. */
+ state.requires_single = false;
+ }
+ else {
+ /* If the output is required to be a single value, the connected inputs in the same node
+ * must not be fields as well. */
+ for (const InputSocketRef *input_socket : connected_inputs) {
+ field_state_by_socket_id[input_socket->id()].requires_single = true;
+ }
+ }
+ }
+ }
+
+ /* Some inputs do not require fields independent of what the outputs are connected to. */
+ for (const InputSocketRef *input_socket : node->inputs()) {
+ SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
+ if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) {
+ state.requires_single = true;
+ state.is_always_single = true;
+ }
+ }
+ }
+}
+
+static void determine_group_input_states(
+ const NodeTreeRef &tree,
+ FieldInferencingInterface &new_inferencing_interface,
+ const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ {
+ /* Non-field inputs never support fields. */
+ int index;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) {
+ if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) {
+ new_inferencing_interface.inputs[index] = InputSocketFieldType::None;
+ }
+ }
+ }
+ /* Check if group inputs are required to be single values, because they are (indirectly)
+ * connected to some socket that does not support fields. */
+ for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
+ for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ if (state.requires_single) {
+ new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None;
+ }
+ }
+ }
+ /* If an input does not support fields, this should be reflected in all Group Input nodes. */
+ for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
+ for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] !=
+ InputSocketFieldType::None;
+ if (supports_field) {
+ state.is_single = false;
+ state.is_field_source = true;
+ }
+ else {
+ state.requires_single = true;
+ }
+ }
+ SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()];
+ dummy_socket_state.requires_single = true;
+ }
+}
+
+static void propagate_field_status_from_left_to_right(
+ const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
+ NodeTreeRef::ToposortDirection::LeftToRight);
+
+ for (const NodeRef *node : toposort_result.sorted_nodes) {
+ if (node->is_group_input_node()) {
+ continue;
+ }
+
+ const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
+ *node);
+
+ /* Update field state of input sockets, also taking into account linked origin sockets. */
+ for (const InputSocketRef *input_socket : node->inputs()) {
+ SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
+ if (state.is_always_single) {
+ state.is_single = true;
+ continue;
+ }
+ state.is_single = true;
+ if (input_socket->directly_linked_sockets().is_empty()) {
+ if (inferencing_interface.inputs[input_socket->index()] ==
+ InputSocketFieldType::Implicit) {
+ state.is_single = false;
+ }
+ }
+ else {
+ for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
+ if (!field_state_by_socket_id[origin_socket->id()].is_single) {
+ state.is_single = false;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Update field state of output sockets, also taking into account input sockets. */
+ for (const OutputSocketRef *output_socket : node->outputs()) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[output_socket->index()];
+
+ switch (field_dependency.field_type()) {
+ case OutputSocketFieldType::None: {
+ state.is_single = true;
+ break;
+ }
+ case OutputSocketFieldType::FieldSource: {
+ state.is_single = false;
+ state.is_field_source = true;
+ break;
+ }
+ case OutputSocketFieldType::PartiallyDependent:
+ case OutputSocketFieldType::DependentField: {
+ for (const InputSocketRef *input_socket :
+ gather_input_socket_dependencies(field_dependency, *node)) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ if (!field_state_by_socket_id[input_socket->id()].is_single) {
+ state.is_single = false;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void determine_group_output_states(const NodeTreeRef &tree,
+ FieldInferencingInterface &new_inferencing_interface,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) {
+ /* Ignore inactive group output nodes. */
+ if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) {
+ continue;
+ }
+ /* Determine dependencies of all group outputs. */
+ for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) {
+ OutputFieldDependency field_dependency = find_group_output_dependencies(
+ *group_output_socket, field_state_by_socket_id);
+ new_inferencing_interface.outputs[group_output_socket->index()] = std::move(
+ field_dependency);
+ }
+ break;
+ }
+}
+
+static void update_socket_shapes(const NodeTreeRef &tree,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
+ const eNodeSocketDisplayShape data_but_can_be_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND_DOT;
+ const eNodeSocketDisplayShape is_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND;
+
+ auto get_shape_for_state = [&](const SocketFieldState &state) {
+ if (state.is_always_single) {
+ return requires_data_shape;
+ }
+ if (!state.is_single) {
+ return is_field_shape;
+ }
+ if (state.requires_single) {
+ return requires_data_shape;
+ }
+ return data_but_can_be_field_shape;
+ };
+
+ for (const InputSocketRef *socket : tree.input_sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ const SocketFieldState &state = field_state_by_socket_id[socket->id()];
+ bsocket->display_shape = get_shape_for_state(state);
+ }
+ for (const OutputSocketRef *socket : tree.output_sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ const SocketFieldState &state = field_state_by_socket_id[socket->id()];
+ bsocket->display_shape = get_shape_for_state(state);
+ }
+}
+
+static bool update_field_inferencing(const NodeTreeRef &tree)
+{
+ bNodeTree &btree = *tree.btree();
+
+ /* Create new inferencing interface for this node group. */
+ FieldInferencingInterface *new_inferencing_interface = new FieldInferencingInterface();
+ new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs),
+ InputSocketFieldType::IsSupported);
+ new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs),
+ OutputFieldDependency::ForDataSource());
+
+ /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */
+ Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size());
+
+ propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id);
+ determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id);
+ propagate_field_status_from_left_to_right(tree, field_state_by_socket_id);
+ determine_group_output_states(tree, *new_inferencing_interface, field_state_by_socket_id);
+ update_socket_shapes(tree, field_state_by_socket_id);
+
+ /* Update the previous group interface. */
+ const bool group_interface_changed = btree.field_inferencing_interface == nullptr ||
+ *btree.field_inferencing_interface !=
+ *new_inferencing_interface;
+ delete btree.field_inferencing_interface;
+ btree.field_inferencing_interface = new_inferencing_interface;
+
+ return group_interface_changed;
+}
+
+} // namespace node_field_inferencing
+
+/**
+ * Common datatype priorities, works for compositor, shader and texture nodes alike
+ * defines priority of datatype connection based on output type (to):
+ * `< 0`: never connect these types.
+ * `>= 0`: priority of connection (higher values chosen first).
+ */
+static int get_internal_link_type_priority(const bNodeSocketType *from, const bNodeSocketType *to)
+{
+ switch (to->type) {
+ case SOCK_RGBA:
+ switch (from->type) {
+ case SOCK_RGBA:
+ return 4;
+ case SOCK_FLOAT:
+ return 3;
+ case SOCK_INT:
+ return 2;
+ case SOCK_BOOLEAN:
+ return 1;
+ }
+ return -1;
+ case SOCK_VECTOR:
+ switch (from->type) {
+ case SOCK_VECTOR:
+ return 4;
+ case SOCK_FLOAT:
+ return 3;
+ case SOCK_INT:
+ return 2;
+ case SOCK_BOOLEAN:
+ return 1;
+ }
+ return -1;
+ case SOCK_FLOAT:
+ switch (from->type) {
+ case SOCK_FLOAT:
+ return 5;
+ case SOCK_INT:
+ return 4;
+ case SOCK_BOOLEAN:
+ return 3;
+ case SOCK_RGBA:
+ return 2;
+ case SOCK_VECTOR:
+ return 1;
+ }
+ return -1;
+ case SOCK_INT:
+ switch (from->type) {
+ case SOCK_INT:
+ return 5;
+ case SOCK_FLOAT:
+ return 4;
+ case SOCK_BOOLEAN:
+ return 3;
+ case SOCK_RGBA:
+ return 2;
+ case SOCK_VECTOR:
+ return 1;
+ }
+ return -1;
+ case SOCK_BOOLEAN:
+ switch (from->type) {
+ case SOCK_BOOLEAN:
+ return 5;
+ case SOCK_INT:
+ return 4;
+ case SOCK_FLOAT:
+ return 3;
+ case SOCK_RGBA:
+ return 2;
+ case SOCK_VECTOR:
+ return 1;
+ }
+ return -1;
+ }
+
+ /* The rest of the socket types only allow an internal link if both the input and output socket
+ * have the same type. If the sockets are custom, we check the idname instead. */
+ if (to->type == from->type && (to->type != SOCK_CUSTOM || STREQ(to->idname, from->idname))) {
+ return 1;
+ }
+
+ return -1;
+}
+
+using TreeNodePair = std::pair<bNodeTree *, bNode *>;
+using ObjectModifierPair = std::pair<Object *, ModifierData *>;
+using NodeSocketPair = std::pair<bNode *, bNodeSocket *>;
+
+/**
+ * Cache common data about node trees from the #Main database that is expensive to retrieve on
+ * demand every time.
+ */
+struct NodeTreeRelations {
+ private:
+ Main *bmain_;
+ std::optional<Vector<bNodeTree *>> all_trees_;
+ std::optional<Map<bNodeTree *, ID *>> owner_ids_;
+ std::optional<MultiValueMap<bNodeTree *, TreeNodePair>> group_node_users_;
+ std::optional<MultiValueMap<bNodeTree *, ObjectModifierPair>> modifiers_users_;
+
+ public:
+ NodeTreeRelations(Main *bmain) : bmain_(bmain)
+ {
+ }
+
+ void ensure_all_trees()
+ {
+ if (all_trees_.has_value()) {
+ return;
+ }
+ all_trees_.emplace();
+ owner_ids_.emplace();
+ if (bmain_ == nullptr) {
+ return;
+ }
+
+ FOREACH_NODETREE_BEGIN (bmain_, ntree, id) {
+ all_trees_->append(ntree);
+ if (&ntree->id != id) {
+ owner_ids_->add_new(ntree, id);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ void ensure_owner_ids()
+ {
+ this->ensure_all_trees();
+ }
+
+ void ensure_group_node_users()
+ {
+ if (group_node_users_.has_value()) {
+ return;
+ }
+ group_node_users_.emplace();
+ if (bmain_ == nullptr) {
+ return;
+ }
+
+ this->ensure_all_trees();
+
+ for (bNodeTree *ntree : *all_trees_) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->id == nullptr) {
+ continue;
+ }
+ ID *id = node->id;
+ if (GS(id->name) == ID_NT) {
+ bNodeTree *group = (bNodeTree *)id;
+ group_node_users_->add(group, {ntree, node});
+ }
+ }
+ }
+ }
+
+ void ensure_modifier_users()
+ {
+ if (modifiers_users_.has_value()) {
+ return;
+ }
+ modifiers_users_.emplace();
+ if (bmain_ == nullptr) {
+ return;
+ }
+
+ LISTBASE_FOREACH (Object *, object, &bmain_->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
+ if (md->type == eModifierType_Nodes) {
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ if (nmd->node_group != nullptr) {
+ modifiers_users_->add(nmd->node_group, {object, md});
+ }
+ }
+ }
+ }
+ }
+
+ Span<ObjectModifierPair> get_modifier_users(bNodeTree *ntree)
+ {
+ BLI_assert(modifiers_users_.has_value());
+ return modifiers_users_->lookup(ntree);
+ }
+
+ Span<TreeNodePair> get_group_node_users(bNodeTree *ntree)
+ {
+ BLI_assert(group_node_users_.has_value());
+ return group_node_users_->lookup(ntree);
+ }
+
+ ID *get_owner_id(bNodeTree *ntree)
+ {
+ BLI_assert(owner_ids_.has_value());
+ return owner_ids_->lookup_default(ntree, &ntree->id);
+ }
+};
+
+struct TreeUpdateResult {
+ bool interface_changed = false;
+ bool output_changed = false;
+};
+
+class NodeTreeMainUpdater {
+ private:
+ Main *bmain_;
+ NodeTreeUpdateExtraParams *params_;
+ Map<bNodeTree *, TreeUpdateResult> update_result_by_tree_;
+ NodeTreeRelations relations_;
+
+ public:
+ NodeTreeMainUpdater(Main *bmain, NodeTreeUpdateExtraParams *params)
+ : bmain_(bmain), params_(params), relations_(bmain)
+ {
+ }
+
+ void update()
+ {
+ Vector<bNodeTree *> changed_ntrees;
+ FOREACH_NODETREE_BEGIN (bmain_, ntree, id) {
+ if (ntree->changed_flag != NTREE_CHANGED_NOTHING) {
+ changed_ntrees.append(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ this->update_rooted(changed_ntrees);
+ }
+
+ void update_rooted(Span<bNodeTree *> root_ntrees)
+ {
+ if (root_ntrees.is_empty()) {
+ return;
+ }
+
+ bool is_single_tree_update = false;
+
+ if (root_ntrees.size() == 1) {
+ bNodeTree *ntree = root_ntrees[0];
+ if (ntree->changed_flag == NTREE_CHANGED_NOTHING) {
+ return;
+ }
+ const TreeUpdateResult result = this->update_tree(*ntree);
+ update_result_by_tree_.add_new(ntree, result);
+ if (!result.interface_changed && !result.output_changed) {
+ is_single_tree_update = true;
+ }
+ }
+
+ if (!is_single_tree_update) {
+ Vector<bNodeTree *> ntrees_in_order = this->get_tree_update_order(root_ntrees);
+ for (bNodeTree *ntree : ntrees_in_order) {
+ if (ntree->changed_flag == NTREE_CHANGED_NOTHING) {
+ continue;
+ }
+ if (!update_result_by_tree_.contains(ntree)) {
+ const TreeUpdateResult result = this->update_tree(*ntree);
+ update_result_by_tree_.add_new(ntree, result);
+ }
+ const TreeUpdateResult result = update_result_by_tree_.lookup(ntree);
+ Span<TreeNodePair> dependent_trees = relations_.get_group_node_users(ntree);
+ if (result.output_changed) {
+ for (const TreeNodePair &pair : dependent_trees) {
+ add_node_tag(pair.first, pair.second, NTREE_CHANGED_NODE_OUTPUT);
+ }
+ }
+ if (result.interface_changed) {
+ for (const TreeNodePair &pair : dependent_trees) {
+ add_node_tag(pair.first, pair.second, NTREE_CHANGED_NODE_PROPERTY);
+ }
+ }
+ }
+ }
+
+ for (const auto item : update_result_by_tree_.items()) {
+ bNodeTree *ntree = item.key;
+ const TreeUpdateResult &result = item.value;
+
+ this->reset_changed_flags(*ntree);
+
+ if (result.interface_changed) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ relations_.ensure_modifier_users();
+ for (const ObjectModifierPair &pair : relations_.get_modifier_users(ntree)) {
+ Object *object = pair.first;
+ ModifierData *md = pair.second;
+
+ if (md->type == eModifierType_Nodes) {
+ MOD_nodes_update_interface(object, (NodesModifierData *)md);
+ }
+ }
+ }
+ }
+
+ if (params_) {
+ relations_.ensure_owner_ids();
+ ID *id = relations_.get_owner_id(ntree);
+ if (params_->tree_changed_fn) {
+ params_->tree_changed_fn(id, ntree, params_->user_data);
+ }
+ if (params_->tree_output_changed_fn && result.output_changed) {
+ params_->tree_output_changed_fn(id, ntree, params_->user_data);
+ }
+ }
+ }
+ }
+
+ private:
+ enum class ToposortMark {
+ None,
+ Temporary,
+ Permanent,
+ };
+
+ using ToposortMarkMap = Map<bNodeTree *, ToposortMark>;
+
+ /**
+ * Finds all trees that depend on the given trees (through node groups). Then those trees are
+ * ordered such that all trees used by one tree come before it.
+ */
+ Vector<bNodeTree *> get_tree_update_order(Span<bNodeTree *> root_ntrees)
+ {
+ relations_.ensure_group_node_users();
+
+ Set<bNodeTree *> trees_to_update = get_trees_to_update(root_ntrees);
+
+ Vector<bNodeTree *> sorted_ntrees;
+
+ ToposortMarkMap marks;
+ for (bNodeTree *ntree : trees_to_update) {
+ marks.add_new(ntree, ToposortMark::None);
+ }
+ for (bNodeTree *ntree : trees_to_update) {
+ if (marks.lookup(ntree) == ToposortMark::None) {
+ const bool cycle_detected = !this->get_tree_update_order__visit_recursive(
+ ntree, marks, sorted_ntrees);
+ /* This should be prevented by higher level operators. */
+ BLI_assert(!cycle_detected);
+ UNUSED_VARS_NDEBUG(cycle_detected);
+ }
+ }
+
+ std::reverse(sorted_ntrees.begin(), sorted_ntrees.end());
+
+ return sorted_ntrees;
+ }
+
+ bool get_tree_update_order__visit_recursive(bNodeTree *ntree,
+ ToposortMarkMap &marks,
+ Vector<bNodeTree *> &sorted_ntrees)
+ {
+ ToposortMark &mark = marks.lookup(ntree);
+ if (mark == ToposortMark::Permanent) {
+ return true;
+ }
+ if (mark == ToposortMark::Temporary) {
+ /* There is a dependency cycle. */
+ return false;
+ }
+
+ mark = ToposortMark::Temporary;
+
+ for (const TreeNodePair &pair : relations_.get_group_node_users(ntree)) {
+ this->get_tree_update_order__visit_recursive(pair.first, marks, sorted_ntrees);
+ }
+ sorted_ntrees.append(ntree);
+
+ mark = ToposortMark::Permanent;
+ return true;
+ }
+
+ Set<bNodeTree *> get_trees_to_update(Span<bNodeTree *> root_ntrees)
+ {
+ relations_.ensure_group_node_users();
+
+ Set<bNodeTree *> reachable_trees;
+ VectorSet<bNodeTree *> trees_to_check = root_ntrees;
+
+ while (!trees_to_check.is_empty()) {
+ bNodeTree *ntree = trees_to_check.pop();
+ if (reachable_trees.add(ntree)) {
+ for (const TreeNodePair &pair : relations_.get_group_node_users(ntree)) {
+ trees_to_check.add(pair.first);
+ }
+ }
+ }
+
+ return reachable_trees;
+ }
+
+ TreeUpdateResult update_tree(bNodeTree &ntree)
+ {
+ TreeUpdateResult result;
+
+ /* Use a #NodeTreeRef to speedup certain queries. It is rebuilt whenever the node tree topology
+ * changes, which typically happens zero or one times during the entire update of the node
+ * tree. */
+ std::unique_ptr<NodeTreeRef> tree_ref;
+ this->ensure_tree_ref(ntree, tree_ref);
+
+ this->update_socket_link_and_use(*tree_ref);
+ this->update_individual_nodes(ntree, tree_ref);
+ this->update_internal_links(ntree, tree_ref);
+ this->update_generic_callback(ntree, tree_ref);
+ this->remove_unused_previews_when_necessary(ntree);
+
+ this->ensure_tree_ref(ntree, tree_ref);
+ if (ntree.type == NTREE_GEOMETRY) {
+ if (node_field_inferencing::update_field_inferencing(*tree_ref)) {
+ result.interface_changed = true;
+ }
+ }
+
+ result.output_changed = this->check_if_output_changed(*tree_ref);
+
+ this->update_socket_link_and_use(*tree_ref);
+ this->update_node_levels(ntree);
+ this->update_link_validation(ntree);
+
+ if (ntree.type == NTREE_TEXTURE) {
+ ntreeTexCheckCyclics(&ntree);
+ }
+
+ if (ntree.changed_flag & NTREE_CHANGED_INTERFACE || ntree.changed_flag & NTREE_CHANGED_ANY) {
+ result.interface_changed = true;
+ }
+
+ if (result.interface_changed) {
+ ntreeInterfaceTypeUpdate(&ntree);
+ }
+
+ return result;
+ }
+
+ void ensure_tree_ref(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ if (!tree_ref) {
+ tree_ref = std::make_unique<NodeTreeRef>(&ntree);
+ }
+ }
+
+ void update_socket_link_and_use(const NodeTreeRef &tree)
+ {
+ for (const InputSocketRef *socket : tree.input_sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ if (socket->directly_linked_links().is_empty()) {
+ bsocket->link = nullptr;
+ }
+ else {
+ bsocket->link = socket->directly_linked_links()[0]->blink();
+ }
+ }
+
+ this->update_socket_used_tags(tree);
+ }
+
+ void update_socket_used_tags(const NodeTreeRef &tree)
+ {
+ for (const SocketRef *socket : tree.sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ bsocket->flag &= ~SOCK_IN_USE;
+ for (const LinkRef *link : socket->directly_linked_links()) {
+ if (!link->is_muted()) {
+ bsocket->flag |= SOCK_IN_USE;
+ break;
+ }
+ }
+ }
+ }
+
+ void update_individual_nodes(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ /* Iterate over nodes instead of #NodeTreeRef, because the #tree_ref might be outdated after
+ * some update functions. */
+ LISTBASE_FOREACH (bNode *, bnode, &ntree.nodes) {
+ this->ensure_tree_ref(ntree, tree_ref);
+ const NodeRef &node = *tree_ref->find_node(*bnode);
+ if (this->should_update_individual_node(node)) {
+ const uint32_t old_changed_flag = ntree.changed_flag;
+ ntree.changed_flag = NTREE_CHANGED_NOTHING;
+
+ /* This may set #ntree.changed_flag which is detected below. */
+ this->update_individual_node(node);
+
+ if (ntree.changed_flag != NTREE_CHANGED_NOTHING) {
+ /* The tree ref is outdated and needs to be rebuilt. Generally, only very few update
+ * functions change the node. Typically zero or one nodes change after an update. */
+ tree_ref.reset();
+ }
+ ntree.changed_flag |= old_changed_flag;
+ }
+ }
+ }
+
+ bool should_update_individual_node(const NodeRef &node)
+ {
+ bNodeTree &ntree = *node.btree();
+ bNode &bnode = *node.bnode();
+ if (ntree.changed_flag & NTREE_CHANGED_ANY) {
+ return true;
+ }
+ if (bnode.changed_flag & NTREE_CHANGED_NODE_PROPERTY) {
+ return true;
+ }
+ if (ntree.changed_flag & NTREE_CHANGED_LINK) {
+ /* Node groups currently always rebuilt their sockets when they are updated.
+ * So avoid calling the update method when no new link was added to it. */
+ if (node.is_group_input_node()) {
+ if (node.outputs().last()->is_directly_linked()) {
+ return true;
+ }
+ }
+ else if (node.is_group_output_node()) {
+ if (node.inputs().last()->is_directly_linked()) {
+ return true;
+ }
+ }
+ else {
+ /* Currently we have no way to tell if a node needs to be updated when a link changed. */
+ return true;
+ }
+ }
+ if (ntree.changed_flag & NTREE_CHANGED_INTERFACE) {
+ if (node.is_group_input_node() || node.is_group_output_node()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void update_individual_node(const NodeRef &node)
+ {
+ bNodeTree &ntree = *node.btree();
+ bNode &bnode = *node.bnode();
+ bNodeType &ntype = *bnode.typeinfo;
+ if (ntype.group_update_func) {
+ ntype.group_update_func(&ntree, &bnode);
+ }
+ if (ntype.updatefunc) {
+ ntype.updatefunc(&ntree, &bnode);
+ }
+ }
+
+ void update_internal_links(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ bool any_internal_links_updated = false;
+ this->ensure_tree_ref(ntree, tree_ref);
+ for (const NodeRef *node : tree_ref->nodes()) {
+ if (!this->should_update_individual_node(*node)) {
+ continue;
+ }
+ /* Find all expected internal links. */
+ Vector<std::pair<bNodeSocket *, bNodeSocket *>> expected_internal_links;
+ for (const OutputSocketRef *output_socket : node->outputs()) {
+ if (!output_socket->is_available()) {
+ continue;
+ }
+ if (!output_socket->is_directly_linked()) {
+ continue;
+ }
+ if (output_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) {
+ continue;
+ }
+ const InputSocketRef *input_socket = this->find_internally_linked_input(output_socket);
+ if (input_socket != nullptr) {
+ expected_internal_links.append({input_socket->bsocket(), output_socket->bsocket()});
+ }
+ }
+ /* rebuilt internal links if they have changed. */
+ if (node->internal_links().size() != expected_internal_links.size()) {
+ this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links);
+ any_internal_links_updated = true;
+ }
+ else {
+ for (auto &item : expected_internal_links) {
+ const bNodeSocket *from_socket = item.first;
+ const bNodeSocket *to_socket = item.second;
+ bool found = false;
+ for (const InternalLinkRef *internal_link : node->internal_links()) {
+ if (from_socket == internal_link->from().bsocket() &&
+ to_socket == internal_link->to().bsocket()) {
+ found = true;
+ }
+ }
+ if (!found) {
+ this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links);
+ any_internal_links_updated = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (any_internal_links_updated) {
+ tree_ref.reset();
+ }
+ }
+
+ const InputSocketRef *find_internally_linked_input(const OutputSocketRef *output_socket)
+ {
+ const InputSocketRef *selected_socket = nullptr;
+ int selected_priority = -1;
+ bool selected_is_linked = false;
+ for (const InputSocketRef *input_socket : output_socket->node().inputs()) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ if (input_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) {
+ continue;
+ }
+ const int priority = get_internal_link_type_priority(input_socket->bsocket()->typeinfo,
+ output_socket->bsocket()->typeinfo);
+ if (priority < 0) {
+ continue;
+ }
+ const bool is_linked = input_socket->is_directly_linked();
+ const bool is_preferred = priority > selected_priority || (is_linked && !selected_is_linked);
+ if (!is_preferred) {
+ continue;
+ }
+ selected_socket = input_socket;
+ selected_priority = priority;
+ selected_is_linked = is_linked;
+ }
+ return selected_socket;
+ }
+
+ void update_internal_links_in_node(bNodeTree &ntree,
+ bNode &node,
+ Span<std::pair<bNodeSocket *, bNodeSocket *>> links)
+ {
+ BLI_freelistN(&node.internal_links);
+ for (const auto &item : links) {
+ bNodeSocket *from_socket = item.first;
+ bNodeSocket *to_socket = item.second;
+ bNodeLink *link = MEM_cnew<bNodeLink>(__func__);
+ link->fromnode = &node;
+ link->fromsock = from_socket;
+ link->tonode = &node;
+ link->tosock = to_socket;
+ link->flag |= NODE_LINK_VALID;
+ BLI_addtail(&node.internal_links, link);
+ }
+ BKE_ntree_update_tag_node_internal_link(&ntree, &node);
+ }
+
+ void update_generic_callback(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ if (ntree.typeinfo->update == nullptr) {
+ return;
+ }
+
+ /* Reset the changed_flag to allow detecting when the update callback changed the node tree. */
+ const uint32_t old_changed_flag = ntree.changed_flag;
+ ntree.changed_flag = NTREE_CHANGED_NOTHING;
+
+ ntree.typeinfo->update(&ntree);
+
+ if (ntree.changed_flag != NTREE_CHANGED_NOTHING) {
+ /* The tree ref is outdated and needs to be rebuilt. */
+ tree_ref.reset();
+ }
+ ntree.changed_flag |= old_changed_flag;
+ }
+
+ void remove_unused_previews_when_necessary(bNodeTree &ntree)
+ {
+ /* Don't trigger preview removal when only those flags are set. */
+ const uint32_t allowed_flags = NTREE_CHANGED_LINK | NTREE_CHANGED_SOCKET_PROPERTY |
+ NTREE_CHANGED_NODE_PROPERTY | NTREE_CHANGED_NODE_OUTPUT |
+ NTREE_CHANGED_INTERFACE;
+ if ((ntree.changed_flag & allowed_flags) == ntree.changed_flag) {
+ return;
+ }
+ BKE_node_preview_remove_unused(&ntree);
+ }
+
+ void update_node_levels(bNodeTree &ntree)
+ {
+ ntreeUpdateNodeLevels(&ntree);
+ }
+
+ void update_link_validation(bNodeTree &ntree)
+ {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ link->flag |= NODE_LINK_VALID;
+ if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level) {
+ link->flag &= ~NODE_LINK_VALID;
+ }
+ else if (ntree.typeinfo->validate_link) {
+ const eNodeSocketDatatype from_type = static_cast<eNodeSocketDatatype>(
+ link->fromsock->type);
+ const eNodeSocketDatatype to_type = static_cast<eNodeSocketDatatype>(link->tosock->type);
+ if (!ntree.typeinfo->validate_link(from_type, to_type)) {
+ link->flag &= ~NODE_LINK_VALID;
+ }
+ }
+ }
+ }
+
+ bool check_if_output_changed(const NodeTreeRef &tree)
+ {
+ bNodeTree &btree = *tree.btree();
+
+ /* Compute a hash that represents the node topology connected to the output. This always has to
+ * be updated even if it is not used to detect changes right now. Otherwise
+ * #btree.output_topology_hash will go out of date. */
+ const Vector<const SocketRef *> tree_output_sockets = this->find_output_sockets(tree);
+ const uint32_t old_topology_hash = btree.output_topology_hash;
+ const uint32_t new_topology_hash = this->get_combined_socket_topology_hash(
+ tree, tree_output_sockets);
+ btree.output_topology_hash = new_topology_hash;
+
+ if (const AnimData *adt = BKE_animdata_from_id(&btree.id)) {
+ /* Drivers may copy values in the node tree around arbitrarily and may cause the output to
+ * change even if it wouldn't without drivers. Only some special drivers like `frame/5` can
+ * be used without causing updates all the time currently. In the future we could try to
+ * handle other drivers better as well.
+ * Note that this optimization only works in practice when the depsgraph didn't also get a
+ * copy-on-write tag for the node tree (which happens when changing node properties). It does
+ * work in a few situations like adding reroutes and duplicating nodes though. */
+ LISTBASE_FOREACH (const FCurve *, fcurve, &adt->drivers) {
+ const ChannelDriver *driver = fcurve->driver;
+ const StringRef expression = driver->expression;
+ if (expression.startswith("frame")) {
+ const StringRef remaining_expression = expression.drop_known_prefix("frame");
+ if (remaining_expression.find_first_not_of(" */+-0123456789.") == StringRef::not_found) {
+ continue;
+ }
+ }
+ /* Unrecognized driver, assume that the output always changes. */
+ return true;
+ }
+ }
+
+ if (btree.changed_flag & NTREE_CHANGED_ANY) {
+ return true;
+ }
+
+ if (old_topology_hash != new_topology_hash) {
+ return true;
+ }
+
+ /* The topology hash can only be used when only topology-changing operations have been done. */
+ if (btree.changed_flag ==
+ (btree.changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) {
+ if (old_topology_hash == new_topology_hash) {
+ return false;
+ }
+ }
+
+ if (!this->check_if_socket_outputs_changed_based_on_flags(tree, tree_output_sockets)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ Vector<const SocketRef *> find_output_sockets(const NodeTreeRef &tree)
+ {
+ Vector<const SocketRef *> sockets;
+ for (const NodeRef *node : tree.nodes()) {
+ const bNode *bnode = node->bnode();
+ if (bnode->typeinfo->nclass != NODE_CLASS_OUTPUT && bnode->type != NODE_GROUP_OUTPUT) {
+ continue;
+ }
+ for (const InputSocketRef *socket : node->inputs()) {
+ if (socket->idname() != "NodeSocketVirtual") {
+ sockets.append(socket);
+ }
+ }
+ }
+ return sockets;
+ }
+
+ /**
+ * Computes a hash that changes when the node tree topology connected to an output node changes.
+ * Adding reroutes does not have an effect on the hash.
+ */
+ uint32_t get_combined_socket_topology_hash(const NodeTreeRef &tree,
+ Span<const SocketRef *> sockets)
+ {
+ if (tree.has_link_cycles()) {
+ /* Return dummy value when the link has any cycles. The algorithm below could be improved to
+ * handle cycles more gracefully. */
+ return 0;
+ }
+ Array<uint32_t> hashes = this->get_socket_topology_hashes(tree, sockets);
+ uint32_t combined_hash = 0;
+ for (uint32_t hash : hashes) {
+ combined_hash = noise::hash(combined_hash, hash);
+ }
+ return combined_hash;
+ }
+
+ Array<uint32_t> get_socket_topology_hashes(const NodeTreeRef &tree,
+ Span<const SocketRef *> sockets)
+ {
+ BLI_assert(!tree.has_link_cycles());
+ Array<std::optional<uint32_t>> hash_by_socket_id(tree.sockets().size());
+ Stack<const SocketRef *> sockets_to_check = sockets;
+
+ while (!sockets_to_check.is_empty()) {
+ const SocketRef &in_out_socket = *sockets_to_check.peek();
+ const NodeRef &node = in_out_socket.node();
+
+ if (hash_by_socket_id[in_out_socket.id()].has_value()) {
+ sockets_to_check.pop();
+ /* Socket is handled already. */
+ continue;
+ }
+
+ if (in_out_socket.is_input()) {
+ /* For input sockets, first compute the hashes of all linked sockets. */
+ const InputSocketRef &socket = in_out_socket.as_input();
+ bool all_origins_computed = true;
+ for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) {
+ if (!hash_by_socket_id[origin_socket->id()].has_value()) {
+ sockets_to_check.push(origin_socket);
+ all_origins_computed = false;
+ }
+ }
+ if (!all_origins_computed) {
+ continue;
+ }
+ /* When the hashes for the linked sockets are ready, combine them into a hash for the input
+ * socket. */
+ const uint64_t socket_ptr = (uintptr_t)socket.bsocket();
+ uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32);
+ for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) {
+ const uint32_t origin_socket_hash = *hash_by_socket_id[origin_socket->id()];
+ socket_hash = noise::hash(socket_hash, origin_socket_hash);
+ }
+ hash_by_socket_id[socket.id()] = socket_hash;
+ sockets_to_check.pop();
+ }
+ else {
+ /* For output sockets, first compute the hashes of all available input sockets. */
+ const OutputSocketRef &socket = in_out_socket.as_output();
+ bool all_available_inputs_computed = true;
+ for (const InputSocketRef *input_socket : node.inputs()) {
+ if (input_socket->is_available()) {
+ if (!hash_by_socket_id[input_socket->id()].has_value()) {
+ sockets_to_check.push(input_socket);
+ all_available_inputs_computed = false;
+ }
+ }
+ }
+ if (!all_available_inputs_computed) {
+ continue;
+ }
+ /* When all input socket hashes have been computed, combine them into a hash for the output
+ * socket. */
+ const uint64_t socket_ptr = (uintptr_t)socket.bsocket();
+ uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32);
+ for (const InputSocketRef *input_socket : node.inputs()) {
+ if (input_socket->is_available()) {
+ const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->id()];
+ socket_hash = noise::hash(socket_hash, input_socket_hash);
+ }
+ }
+ hash_by_socket_id[socket.id()] = socket_hash;
+ sockets_to_check.pop();
+ }
+ }
+
+ /* Create output array. */
+ Array<uint32_t> hashes(sockets.size());
+ for (const int i : sockets.index_range()) {
+ hashes[i] = *hash_by_socket_id[sockets[i]->id()];
+ }
+ return hashes;
+ }
+
+ /**
+ * Returns true when any of the provided sockets changed its values. A change is detected by
+ * checking the #changed_flag on connected sockets and nodes.
+ */
+ bool check_if_socket_outputs_changed_based_on_flags(const NodeTreeRef &tree,
+ Span<const SocketRef *> sockets)
+ {
+ /* Avoid visiting the same socket twice when multiple links point to the same socket. */
+ Array<bool> pushed_by_socket_id(tree.sockets().size(), false);
+ Stack<const SocketRef *> sockets_to_check = sockets;
+
+ for (const SocketRef *socket : sockets) {
+ pushed_by_socket_id[socket->id()] = true;
+ }
+
+ while (!sockets_to_check.is_empty()) {
+ const SocketRef &in_out_socket = *sockets_to_check.pop();
+ const bNode &bnode = *in_out_socket.node().bnode();
+ const bNodeSocket &bsocket = *in_out_socket.bsocket();
+ if (bsocket.changed_flag != NTREE_CHANGED_NOTHING) {
+ return true;
+ }
+ if (bnode.changed_flag != NTREE_CHANGED_NOTHING) {
+ const bool only_unused_internal_link_changed = (bnode.flag & NODE_MUTED) == 0 &&
+ bnode.changed_flag ==
+ NTREE_CHANGED_INTERNAL_LINK;
+ if (!only_unused_internal_link_changed) {
+ return true;
+ }
+ }
+ if (in_out_socket.is_input()) {
+ const InputSocketRef &socket = in_out_socket.as_input();
+ for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) {
+ bool &pushed = pushed_by_socket_id[origin_socket->id()];
+ if (!pushed) {
+ sockets_to_check.push(origin_socket);
+ pushed = true;
+ }
+ }
+ }
+ else {
+ const OutputSocketRef &socket = in_out_socket.as_output();
+ for (const InputSocketRef *input_socket : socket.node().inputs()) {
+ if (input_socket->is_available()) {
+ bool &pushed = pushed_by_socket_id[input_socket->id()];
+ if (!pushed) {
+ sockets_to_check.push(input_socket);
+ pushed = true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ void reset_changed_flags(bNodeTree &ntree)
+ {
+ ntree.changed_flag = NTREE_CHANGED_NOTHING;
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
+ node->changed_flag = NTREE_CHANGED_NOTHING;
+ node->update = 0;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ socket->changed_flag = NTREE_CHANGED_NOTHING;
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ socket->changed_flag = NTREE_CHANGED_NOTHING;
+ }
+ }
+ }
+};
+
+} // namespace blender::bke
+
+void BKE_ntree_update_tag_all(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_ANY);
+}
+
+void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+}
+
+void BKE_ntree_update_tag_node_new(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_property(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_new(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_removed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_REMOVED_SOCKET);
+}
+
+void BKE_ntree_update_tag_socket_type(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_availability(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_node_removed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_REMOVED_NODE);
+}
+
+void BKE_ntree_update_tag_node_mute(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+}
+
+void BKE_ntree_update_tag_node_internal_link(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_INTERNAL_LINK);
+}
+
+void BKE_ntree_update_tag_link_changed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_link_removed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_link_added(bNodeTree *ntree, bNodeLink *UNUSED(link))
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_link_mute(bNodeTree *ntree, bNodeLink *UNUSED(link))
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_missing_runtime_data(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_ALL);
+}
+
+void BKE_ntree_update_tag_interface(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_INTERFACE);
+}
+
+void BKE_ntree_update_tag_id_changed(Main *bmain, ID *id)
+{
+ FOREACH_NODETREE_BEGIN (bmain, ntree, ntree_id) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->id == id) {
+ node->update |= NODE_UPDATE_ID;
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+}
+
+/**
+ * Protect from recursive calls into the updating function. Some node update functions might
+ * trigger this from Python or in other cases.
+ *
+ * This could be added to #Main, but given that there is generally only one #Main, that's not
+ * really worth it now.
+ */
+static bool is_updating = false;
+
+void BKE_ntree_update_main(Main *bmain, NodeTreeUpdateExtraParams *params)
+{
+ if (is_updating) {
+ return;
+ }
+
+ is_updating = true;
+ blender::bke::NodeTreeMainUpdater updater{bmain, params};
+ updater.update();
+ is_updating = false;
+}
+
+void BKE_ntree_update_main_tree(Main *bmain, bNodeTree *ntree, NodeTreeUpdateExtraParams *params)
+{
+ if (ntree == nullptr) {
+ BKE_ntree_update_main(bmain, params);
+ return;
+ }
+
+ if (is_updating) {
+ return;
+ }
+
+ is_updating = true;
+ blender::bke::NodeTreeMainUpdater updater{bmain, params};
+ updater.update_rooted({ntree});
+ is_updating = false;
+}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.cc
index fbdf99c91c2..e177b1ce29e 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.cc
@@ -24,9 +24,9 @@
/* Allow using deprecated functionality for .blend file I/O. */
#define DNA_DEPRECATED_ALLOW
-#include <math.h>
-#include <stdio.h>
-#include <string.h>
+#include <cmath>
+#include <cstdio>
+#include <cstring>
#include "CLG_log.h"
@@ -82,9 +82,12 @@
#include "BKE_anim_visualization.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
+#include "BKE_asset.h"
+#include "BKE_bpath.h"
#include "BKE_camera.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
+#include "BKE_crazyspace.h"
#include "BKE_curve.h"
#include "BKE_deform.h"
#include "BKE_displist.h"
@@ -94,8 +97,8 @@
#include "BKE_effect.h"
#include "BKE_fcurve.h"
#include "BKE_fcurve_driver.h"
-#include "BKE_font.h"
#include "BKE_geometry_set.h"
+#include "BKE_geometry_set.hh"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_geom.h"
@@ -136,6 +139,7 @@
#include "BKE_speaker.h"
#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
+#include "BKE_vfont.h"
#include "BKE_volume.h"
#include "DEG_depsgraph.h"
@@ -158,11 +162,10 @@
static CLG_LogRef LOG = {"bke.object"};
/**
- * Vertex parent modifies original BMesh which is not safe for threading.
+ * NOTE(@sergey): Vertex parent modifies original #BMesh which is not safe for threading.
* Ideally such a modification should be handled as a separate DAG update
- * callback for mesh datablock, but for until it is actually supported use
+ * callback for mesh data-block, but for until it is actually supported use
* simpler solution with a mutex lock.
- * - sergey -
*/
#define VPARENT_THREADING_HACK
@@ -200,24 +203,24 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
if (ob_src->totcol) {
- ob_dst->mat = MEM_dupallocN(ob_src->mat);
- ob_dst->matbits = MEM_dupallocN(ob_src->matbits);
+ ob_dst->mat = (Material **)MEM_dupallocN(ob_src->mat);
+ ob_dst->matbits = (char *)MEM_dupallocN(ob_src->matbits);
ob_dst->totcol = ob_src->totcol;
}
- else if (ob_dst->mat != NULL || ob_dst->matbits != NULL) {
+ else if (ob_dst->mat != nullptr || ob_dst->matbits != nullptr) {
/* This shall not be needed, but better be safe than sorry. */
BLI_assert_msg(
- 0, "Object copy: non-NULL material pointers with zero counter, should not happen.");
- ob_dst->mat = NULL;
- ob_dst->matbits = NULL;
+ 0, "Object copy: non-nullptr material pointers with zero counter, should not happen.");
+ ob_dst->mat = nullptr;
+ ob_dst->matbits = nullptr;
}
if (ob_src->iuser) {
- ob_dst->iuser = MEM_dupallocN(ob_src->iuser);
+ ob_dst->iuser = (ImageUser *)MEM_dupallocN(ob_src->iuser);
}
if (ob_src->runtime.bb) {
- ob_dst->runtime.bb = MEM_dupallocN(ob_src->runtime.bb);
+ ob_dst->runtime.bb = (BoundBox *)MEM_dupallocN(ob_src->runtime.bb);
}
BLI_listbase_clear(&ob_dst->shader_fx);
@@ -233,7 +236,7 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
/* backwards compat... non-armatures can get poses in older files? */
if (ob_src->type == OB_ARMATURE) {
const bool do_pose_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
- BKE_pose_rebuild(bmain, ob_dst, ob_dst->data, do_pose_id_user);
+ BKE_pose_rebuild(bmain, ob_dst, (bArmature *)ob_dst->data, do_pose_id_user);
}
}
@@ -241,12 +244,12 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
BKE_constraints_copy_ex(&ob_dst->constraints, &ob_src->constraints, flag_subdata, true);
ob_dst->mode = ob_dst->type != OB_GPENCIL ? OB_MODE_OBJECT : ob_dst->mode;
- ob_dst->sculpt = NULL;
+ ob_dst->sculpt = nullptr;
if (ob_src->pd) {
- ob_dst->pd = MEM_dupallocN(ob_src->pd);
+ ob_dst->pd = (PartDeflect *)MEM_dupallocN(ob_src->pd);
if (ob_dst->pd->rng) {
- ob_dst->pd->rng = MEM_dupallocN(ob_src->pd->rng);
+ ob_dst->pd->rng = (RNG *)MEM_dupallocN(ob_src->pd->rng);
}
}
BKE_rigidbody_object_copy(bmain, ob_dst, ob_src, flag_subdata);
@@ -268,7 +271,7 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
BKE_previewimg_id_copy(&ob_dst->id, &ob_src->id);
}
else {
- ob_dst->preview = NULL;
+ ob_dst->preview = nullptr;
}
}
@@ -290,17 +293,17 @@ static void object_free_data(ID *id)
BLI_freelistN(&ob->fmaps);
if (ob->pose) {
BKE_pose_free_ex(ob->pose, false);
- ob->pose = NULL;
+ ob->pose = nullptr;
}
if (ob->mpath) {
animviz_free_motionpath(ob->mpath);
- ob->mpath = NULL;
+ ob->mpath = nullptr;
}
BKE_constraints_free_ex(&ob->constraints, false);
BKE_partdeflect_free(ob->pd);
- BKE_rigidbody_free_object(ob, NULL);
+ BKE_rigidbody_free_object(ob, nullptr);
BKE_rigidbody_free_constraint(ob);
sbFree(ob);
@@ -316,7 +319,7 @@ static void object_free_data(ID *id)
MEM_freeN((void *)ob->runtime.curve_cache->anim_path_accum_length);
}
MEM_freeN(ob->runtime.curve_cache);
- ob->runtime.curve_cache = NULL;
+ ob->runtime.curve_cache = nullptr;
}
BKE_previewimg_free(&ob->preview);
@@ -331,47 +334,26 @@ static void object_make_local(Main *bmain, ID *id, const int flags)
Object *ob = (Object *)id;
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
const bool clear_proxy = (flags & LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING) == 0;
- bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
- bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
- BLI_assert(force_copy == false || force_copy != force_local);
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing (unless force_local is set)
- * - only local users: set flag
- * - mixed: make copy
- * In case we make a whole lib's content local,
- * we always want to localize, and we skip remapping (done later).
- */
-
- if (!force_local && !force_copy) {
- BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib);
- if (lib_local || is_local) {
- if (!is_lib) {
- force_local = true;
- }
- else {
- force_copy = true;
- }
- }
- }
+ bool force_local, force_copy;
+ BKE_lib_id_make_local_generic_action_define(bmain, id, flags, &force_local, &force_copy);
if (force_local) {
- BKE_lib_id_clear_library_data(bmain, &ob->id);
- BKE_lib_id_expand_local(bmain, &ob->id);
+ BKE_lib_id_clear_library_data(bmain, &ob->id, flags);
+ BKE_lib_id_expand_local(bmain, &ob->id, flags);
if (clear_proxy) {
- if (ob->proxy_from != NULL) {
- ob->proxy_from->proxy = NULL;
- ob->proxy_from->proxy_group = NULL;
+ if (ob->proxy_from != nullptr) {
+ ob->proxy_from->proxy = nullptr;
+ ob->proxy_from->proxy_group = nullptr;
}
- ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
+ ob->proxy = ob->proxy_from = ob->proxy_group = nullptr;
}
}
else if (force_copy) {
Object *ob_new = (Object *)BKE_id_copy(bmain, &ob->id);
id_us_min(&ob_new->id);
- ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL;
+ ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = nullptr;
/* setting newid is mandatory for complex make_lib_local logic... */
ID_NEW_SET(ob, ob_new);
@@ -388,7 +370,8 @@ static void library_foreach_modifiersForeachIDLink(void *user_data,
int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag));
}
static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data,
@@ -397,7 +380,8 @@ static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data,
int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag));
}
static void library_foreach_shaderfxForeachIDLink(void *user_data,
@@ -406,7 +390,8 @@ static void library_foreach_shaderfxForeachIDLink(void *user_data,
int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag));
}
static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con),
@@ -416,7 +401,8 @@ static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con),
{
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP;
- BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag));
}
static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(psys),
@@ -425,7 +411,8 @@ static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(p
int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag));
}
static void object_foreach_id(ID *id, LibraryForeachIDData *data)
@@ -441,22 +428,22 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
/* object data special case */
if (object->type == OB_EMPTY) {
- /* empty can have NULL or Image */
+ /* empty can have nullptr or Image */
BKE_LIB_FOREACHID_PROCESS_ID(data, object->data, proxy_cb_flag | IDWALK_CB_USER);
}
else {
- /* when set, this can't be NULL */
+ /* when set, this can't be nullptr */
if (object->data) {
BKE_LIB_FOREACHID_PROCESS_ID(
data, object->data, proxy_cb_flag | IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
}
}
- BKE_LIB_FOREACHID_PROCESS(data, object->parent, IDWALK_CB_NEVER_SELF);
- BKE_LIB_FOREACHID_PROCESS(data, object->track, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->parent, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->track, IDWALK_CB_NEVER_SELF);
/* object->proxy is refcounted, but not object->proxy_group... *sigh* */
- BKE_LIB_FOREACHID_PROCESS(data, object->proxy, IDWALK_CB_USER | IDWALK_CB_NEVER_SELF);
- BKE_LIB_FOREACHID_PROCESS(data, object->proxy_group, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->proxy, IDWALK_CB_USER | IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->proxy_group, IDWALK_CB_NOP);
/* Special case!
* Since this field is set/owned by 'user' of this ID (and not ID itself),
@@ -464,26 +451,27 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
{
const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override(
data,
- (object->proxy_from != NULL && ID_IS_LINKED(object->proxy_from)) ?
+ (object->proxy_from != nullptr && ID_IS_LINKED(object->proxy_from)) ?
IDWALK_CB_INDIRECT_USAGE :
0,
true);
- BKE_LIB_FOREACHID_PROCESS(data, object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
+ data, object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF);
BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true);
}
- BKE_LIB_FOREACHID_PROCESS(data, object->poselib, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->poselib, IDWALK_CB_USER);
for (int i = 0; i < object->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, object->mat[i], proxy_cb_flag | IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->mat[i], proxy_cb_flag | IDWALK_CB_USER);
}
/* Note that ob->gpd is deprecated, so no need to handle it here. */
- BKE_LIB_FOREACHID_PROCESS(data, object->instance_collection, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->instance_collection, IDWALK_CB_USER);
if (object->pd) {
- BKE_LIB_FOREACHID_PROCESS(data, object->pd->tex, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, object->pd->f_source, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->pd->tex, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->pd->f_source, IDWALK_CB_NOP);
}
/* Note that ob->effect is deprecated, so no need to handle it here. */
@@ -491,38 +479,117 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override(
data, proxy_cb_flag, false);
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
- IDP_foreach_property(
- pchan->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
- BKE_LIB_FOREACHID_PROCESS(data, pchan->custom, IDWALK_CB_USER);
- BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ IDP_foreach_property(pchan->prop,
+ IDP_TYPE_FILTER_ID,
+ BKE_lib_query_idpropertiesForeachIDLink_callback,
+ data));
+
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, pchan->custom, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ BKE_constraints_id_loop(
+ &pchan->constraints, library_foreach_constraintObjectLooper, data));
}
BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true);
}
if (object->rigidbody_constraint) {
- BKE_LIB_FOREACHID_PROCESS(data, object->rigidbody_constraint->ob1, IDWALK_CB_NEVER_SELF);
- BKE_LIB_FOREACHID_PROCESS(data, object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF);
- }
-
- BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, data);
- BKE_gpencil_modifiers_foreach_ID_link(
- object, library_foreach_gpencil_modifiersForeachIDLink, data);
- BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, data);
- BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, data);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
+ data, object->rigidbody_constraint->ob1, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
+ data, object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF);
+ }
+
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, data));
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ BKE_gpencil_modifiers_foreach_ID_link(
+ object, library_foreach_gpencil_modifiersForeachIDLink, data));
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, data));
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, data));
LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
- BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, data));
}
if (object->soft) {
- BKE_LIB_FOREACHID_PROCESS(data, object->soft->collision_group, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->soft->collision_group, IDWALK_CB_NOP);
if (object->soft->effector_weights) {
- BKE_LIB_FOREACHID_PROCESS(data, object->soft->effector_weights->group, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
+ data, object->soft->effector_weights->group, IDWALK_CB_NOP);
}
}
}
+static void object_foreach_path_pointcache(ListBase *ptcache_list,
+ BPathForeachPathData *bpath_data)
+{
+ for (PointCache *cache = (PointCache *)ptcache_list->first; cache != nullptr;
+ cache = cache->next) {
+ if (cache->flag & PTCACHE_DISK_CACHE) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, cache->path);
+ }
+ }
+}
+
+static void object_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Object *ob = reinterpret_cast<Object *>(id);
+
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ /* TODO: Move that to #ModifierTypeInfo. */
+ switch (md->type) {
+ case eModifierType_Fluidsim: {
+ FluidsimModifierData *fluidmd = reinterpret_cast<FluidsimModifierData *>(md);
+ if (fluidmd->fss) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, fluidmd->fss->surfdataPath);
+ }
+ break;
+ }
+ case eModifierType_Fluid: {
+ FluidModifierData *fmd = reinterpret_cast<FluidModifierData *>(md);
+ if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, fmd->domain->cache_directory);
+ }
+ break;
+ }
+ case eModifierType_Cloth: {
+ ClothModifierData *clmd = reinterpret_cast<ClothModifierData *>(md);
+ object_foreach_path_pointcache(&clmd->ptcaches, bpath_data);
+ break;
+ }
+ case eModifierType_Ocean: {
+ OceanModifierData *omd = reinterpret_cast<OceanModifierData *>(md);
+ BKE_bpath_foreach_path_fixed_process(bpath_data, omd->cachepath);
+ break;
+ }
+ case eModifierType_MeshCache: {
+ MeshCacheModifierData *mcmd = reinterpret_cast<MeshCacheModifierData *>(md);
+ BKE_bpath_foreach_path_fixed_process(bpath_data, mcmd->filepath);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (ob->soft != nullptr) {
+ object_foreach_path_pointcache(&ob->soft->shared->ptcaches, bpath_data);
+ }
+
+ LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
+ object_foreach_path_pointcache(&psys->ptcaches, bpath_data);
+ }
+}
+
static void write_fmaps(BlendWriter *writer, ListBase *fbase)
{
LISTBASE_FOREACH (bFaceMap *, fmap, fbase) {
@@ -557,9 +624,9 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre
BLO_write_pointer_array(writer, ob->totcol, ob->mat);
BLO_write_raw(writer, sizeof(char) * ob->totcol, ob->matbits);
- bArmature *arm = NULL;
+ bArmature *arm = nullptr;
if (ob->type == OB_ARMATURE) {
- arm = ob->data;
+ arm = (bArmature *)ob->data;
if (arm && ob->pose && arm->act_bone) {
BLI_strncpy(ob->pose->proxy_act_bone, arm->act_bone->name, sizeof(ob->pose->proxy_act_bone));
}
@@ -621,7 +688,7 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
/* XXX This should not be needed - but seems like it can happen in some cases,
* so for now play safe. */
- ob->proxy_from = NULL;
+ ob->proxy_from = nullptr;
const bool is_undo = BLO_read_data_is_undo(reader);
if (ob->id.tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT)) {
@@ -665,10 +732,10 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
BKE_shaderfx_blend_read_data(reader, &ob->shader_fx);
BLO_read_list(reader, &ob->effect);
- paf = ob->effect.first;
+ paf = (PartEff *)ob->effect.first;
while (paf) {
if (paf->type == EFF_PARTICLE) {
- paf->keys = NULL;
+ paf->keys = nullptr;
}
if (paf->type == EFF_WAVE) {
WaveEff *wav = (WaveEff *)paf;
@@ -721,9 +788,9 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
if (ob->soft) {
SoftBody *sb = ob->soft;
- sb->bpoint = NULL; /* init pointers so it gets rebuilt nicely */
- sb->bspring = NULL;
- sb->scratch = NULL;
+ sb->bpoint = nullptr; /* init pointers so it gets rebuilt nicely */
+ sb->bspring = nullptr;
+ sb->scratch = nullptr;
/* although not used anymore */
/* still have to be loaded to be compatible with old files */
BLO_read_pointer_array(reader, (void **)&sb->keys);
@@ -735,13 +802,13 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_data_address(reader, &sb->effector_weights);
if (!sb->effector_weights) {
- sb->effector_weights = BKE_effector_add_weights(NULL);
+ sb->effector_weights = BKE_effector_add_weights(nullptr);
}
BLO_read_data_address(reader, &sb->shared);
- if (sb->shared == NULL) {
+ if (sb->shared == nullptr) {
/* Link deprecated caches if they exist, so we can use them for versioning.
- * We should only do this when sb->shared == NULL, because those pointers
+ * We should only do this when sb->shared == nullptr, because those pointers
* are always set (for compatibility with older Blenders). We mustn't link
* the same pointcache twice. */
BKE_ptcache_blend_read_data(reader, &sb->ptcaches, &sb->pointcache, false);
@@ -757,11 +824,11 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
if (ob->rigidbody_object) {
RigidBodyOb *rbo = ob->rigidbody_object;
/* Allocate runtime-only struct */
- rbo->shared = MEM_callocN(sizeof(*rbo->shared), "RigidBodyObShared");
+ rbo->shared = (RigidBodyOb_Shared *)MEM_callocN(sizeof(*rbo->shared), "RigidBodyObShared");
}
BLO_read_data_address(reader, &ob->rigidbody_constraint);
if (ob->rigidbody_constraint) {
- ob->rigidbody_constraint->physics_constraint = NULL;
+ ob->rigidbody_constraint->physics_constraint = nullptr;
}
BLO_read_list(reader, &ob->particlesystem);
@@ -771,7 +838,7 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_list(reader, &ob->hooks);
while (ob->hooks.first) {
- ObHook *hook = ob->hooks.first;
+ ObHook *hook = (ObHook *)ob->hooks.first;
HookModifierData *hmd = (HookModifierData *)BKE_modifier_new(eModifierType_Hook);
BLO_read_int32_array(reader, hook->totindex, &hook->indexar);
@@ -808,7 +875,7 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
CLAMP(ob->rotmode, ROT_MODE_MIN, ROT_MODE_MAX);
if (ob->sculpt) {
- ob->sculpt = NULL;
+ ob->sculpt = nullptr;
/* Only create data on undo, otherwise rely on editor mode switching. */
if (BLO_read_data_is_undo(reader) && (ob->mode & OB_MODE_ALL_SCULPT)) {
BKE_object_sculpt_data_create(ob);
@@ -844,6 +911,7 @@ static void object_blend_read_lib(BlendLibReader *reader, ID *id)
{
Object *ob = (Object *)id;
+ Main *bmain = BLO_read_lib_get_main(reader);
BlendFileReadReport *reports = BLO_read_lib_reports(reader);
/* XXX deprecated - old animation system <<< */
@@ -860,7 +928,7 @@ static void object_blend_read_lib(BlendLibReader *reader, ID *id)
BLO_read_id_address(reader, ob->id.lib, &ob->instance_collection);
}
else {
- if (ob->instance_collection != NULL) {
+ if (ob->instance_collection != nullptr) {
ID *new_id = BLO_read_get_new_id_address(reader, ob->id.lib, &ob->instance_collection->id);
BLO_reportf_wrap(reports,
RPT_INFO,
@@ -869,7 +937,7 @@ static void object_blend_read_lib(BlendLibReader *reader, ID *id)
ob->id.name + 2,
new_id->name + 2);
}
- ob->instance_collection = NULL;
+ ob->instance_collection = nullptr;
ob->transflag &= ~OB_DUPLICOLLECTION;
}
@@ -877,8 +945,8 @@ static void object_blend_read_lib(BlendLibReader *reader, ID *id)
if (ob->proxy) {
/* paranoia check, actually a proxy_from pointer should never be written... */
if (!ID_IS_LINKED(ob->proxy)) {
- ob->proxy->proxy_from = NULL;
- ob->proxy = NULL;
+ ob->proxy->proxy_from = nullptr;
+ ob->proxy = nullptr;
if (ob->id.lib) {
BLO_reportf_wrap(reports,
@@ -903,7 +971,7 @@ static void object_blend_read_lib(BlendLibReader *reader, ID *id)
void *poin = ob->data;
BLO_read_id_address(reader, ob->id.lib, &ob->data);
- if (ob->data == NULL && poin != NULL) {
+ if (ob->data == nullptr && poin != nullptr) {
ob->type = OB_EMPTY;
if (ob->pose) {
@@ -917,7 +985,7 @@ static void object_blend_read_lib(BlendLibReader *reader, ID *id)
#else
MEM_freeN(ob->pose);
#endif
- ob->pose = NULL;
+ ob->pose = nullptr;
ob->mode &= ~OB_MODE_POSE;
}
@@ -940,12 +1008,7 @@ static void object_blend_read_lib(BlendLibReader *reader, ID *id)
/* When the object is local and the data is library its possible
* the material list size gets out of sync. T22663. */
if (ob->data && ob->id.lib != ((ID *)ob->data)->lib) {
- const short *totcol_data = BKE_object_material_len_p(ob);
- /* Only expand so as not to lose any object materials that might be set. */
- if (totcol_data && (*totcol_data > ob->totcol)) {
- // printf("'%s' %d -> %d\n", ob->id.name, ob->totcol, *totcol_data);
- BKE_object_material_resize(BLO_read_lib_get_main(reader), ob, *totcol_data, false);
- }
+ BKE_object_materials_test(bmain, ob, (ID *)ob->data);
}
BLO_read_id_address(reader, ob->id.lib, &ob->gpd);
@@ -1028,7 +1091,7 @@ static void expand_object_expandModifiers(void *userData,
ID **idpoin,
int UNUSED(cb_flag))
{
- BlendExpander *expander = userData;
+ BlendExpander *expander = (BlendExpander *)userData;
BLO_expand(expander, *idpoin);
}
@@ -1036,14 +1099,14 @@ PartEff *BKE_object_do_version_give_parteff_245(Object *ob)
{
PartEff *paf;
- paf = ob->effect.first;
+ paf = (PartEff *)ob->effect.first;
while (paf) {
if (paf->type == EFF_PARTICLE) {
return paf;
}
paf = paf->next;
}
- return NULL;
+ return nullptr;
}
static void object_blend_read_expand(BlendExpander *expander, ID *id)
@@ -1131,46 +1194,131 @@ static void object_blend_read_expand(BlendExpander *expander, ID *id)
}
}
-static void object_lib_override_apply_post(ID *id_dst, ID *UNUSED(id_src))
+static void object_lib_override_apply_post(ID *id_dst, ID *id_src)
{
- Object *object = (Object *)id_dst;
+ /* id_dst is the new local override copy of the linked reference data. id_src is the old override
+ * data stored on disk, used as source data for override operations. */
+ Object *object_dst = (Object *)id_dst;
+ Object *object_src = (Object *)id_src;
- ListBase pidlist;
- BKE_ptcache_ids_from_object(&pidlist, object, NULL, 0);
- LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
- LISTBASE_FOREACH (PointCache *, point_cache, pid->ptcaches) {
- point_cache->flag |= PTCACHE_FLAG_INFO_DIRTY;
+ ListBase pidlist_dst, pidlist_src;
+ BKE_ptcache_ids_from_object(&pidlist_dst, object_dst, nullptr, 0);
+ BKE_ptcache_ids_from_object(&pidlist_src, object_src, nullptr, 0);
+
+ /* Problem with point caches is that several status flags (like OUTDATED or BAKED) are read-only
+ * at RNA level, and therefore not overridable per-se.
+ *
+ * This code is a workaround this to check all point-caches from both source and destination
+ * objects in parallel, and transfer those flags when it makes sense.
+ *
+ * This allows to keep baked caches across liboverrides applies.
+ *
+ * NOTE: This is fairly hackish and weak, but so is the point-cache system as its whole. A more
+ * robust solution would be e.g. to have a specific RNA entry point to deal with such cases
+ * (maybe a new flag to allow override code to set values of some read-only properties?).
+ */
+ PTCacheID *pid_src, *pid_dst;
+ for (pid_dst = (PTCacheID *)pidlist_dst.first, pid_src = (PTCacheID *)pidlist_src.first;
+ pid_dst != nullptr;
+ pid_dst = pid_dst->next, pid_src = (pid_src != nullptr) ? pid_src->next : nullptr) {
+ /* If pid's do not match, just tag info of caches in dst as dirty and continue. */
+ if (pid_src == nullptr) {
+ continue;
+ }
+ if (pid_dst->type != pid_src->type || pid_dst->file_type != pid_src->file_type ||
+ pid_dst->default_step != pid_src->default_step || pid_dst->max_step != pid_src->max_step ||
+ pid_dst->data_types != pid_src->data_types || pid_dst->info_types != pid_src->info_types) {
+ LISTBASE_FOREACH (PointCache *, point_cache_src, pid_src->ptcaches) {
+ point_cache_src->flag |= PTCACHE_FLAG_INFO_DIRTY;
+ }
+ continue;
+ }
+
+ PointCache *point_cache_dst, *point_cache_src;
+ for (point_cache_dst = (PointCache *)pid_dst->ptcaches->first,
+ point_cache_src = (PointCache *)pid_src->ptcaches->first;
+ point_cache_dst != nullptr;
+ point_cache_dst = point_cache_dst->next,
+ point_cache_src = (point_cache_src != nullptr) ? point_cache_src->next : nullptr) {
+ /* Always force updating info about caches of applied liboverrides. */
+ point_cache_dst->flag |= PTCACHE_FLAG_INFO_DIRTY;
+ if (point_cache_src == nullptr || !STREQ(point_cache_dst->name, point_cache_src->name)) {
+ continue;
+ }
+ if ((point_cache_src->flag & PTCACHE_BAKED) != 0) {
+ point_cache_dst->flag |= PTCACHE_BAKED;
+ }
+ if ((point_cache_src->flag & PTCACHE_OUTDATED) == 0) {
+ point_cache_dst->flag &= ~PTCACHE_OUTDATED;
+ }
}
}
- BLI_freelistN(&pidlist);
+ BLI_freelistN(&pidlist_dst);
+ BLI_freelistN(&pidlist_src);
}
+static IDProperty *object_asset_dimensions_property(Object *ob)
+{
+ float dimensions[3];
+ BKE_object_dimensions_get(ob, dimensions);
+ if (is_zero_v3(dimensions)) {
+ return nullptr;
+ }
+
+ IDPropertyTemplate idprop{};
+ idprop.array.len = ARRAY_SIZE(dimensions);
+ idprop.array.type = IDP_FLOAT;
+
+ IDProperty *property = IDP_New(IDP_ARRAY, &idprop, "dimensions");
+ memcpy(IDP_Array(property), dimensions, sizeof(dimensions));
+
+ return property;
+}
+
+static void object_asset_pre_save(void *asset_ptr, struct AssetMetaData *asset_data)
+{
+ Object *ob = (Object *)asset_ptr;
+ BLI_assert(GS(ob->id.name) == ID_OB);
+
+ /* Update dimensions hint for the asset. */
+ IDProperty *dimensions_prop = object_asset_dimensions_property(ob);
+ if (dimensions_prop) {
+ BKE_asset_metadata_idprop_ensure(asset_data, dimensions_prop);
+ }
+}
+
+AssetTypeInfo AssetType_OB = {
+ /* pre_save_fn */ object_asset_pre_save,
+};
+
IDTypeInfo IDType_ID_OB = {
- .id_code = ID_OB,
- .id_filter = FILTER_ID_OB,
- .main_listbase_index = INDEX_ID_OB,
- .struct_size = sizeof(Object),
- .name = "Object",
- .name_plural = "objects",
- .translation_context = BLT_I18NCONTEXT_ID_OBJECT,
- .flags = 0,
-
- .init_data = object_init_data,
- .copy_data = object_copy_data,
- .free_data = object_free_data,
- .make_local = object_make_local,
- .foreach_id = object_foreach_id,
- .foreach_cache = NULL,
- .owner_get = NULL,
-
- .blend_write = object_blend_write,
- .blend_read_data = object_blend_read_data,
- .blend_read_lib = object_blend_read_lib,
- .blend_read_expand = object_blend_read_expand,
-
- .blend_read_undo_preserve = NULL,
-
- .lib_override_apply_post = object_lib_override_apply_post,
+ /* id_code */ ID_OB,
+ /* id_filter */ FILTER_ID_OB,
+ /* main_listbase_index */ INDEX_ID_OB,
+ /* struct_size */ sizeof(Object),
+ /* name */ "Object",
+ /* name_plural */ "objects",
+ /* translation_context */ BLT_I18NCONTEXT_ID_OBJECT,
+ /* flags */ 0,
+ /* asset_type_info */ &AssetType_OB,
+
+ /* init_data */ object_init_data,
+ /* copy_data */ object_copy_data,
+ /* free_data */ object_free_data,
+ /* make_local */ object_make_local,
+ /* foreach_id */ object_foreach_id,
+ /* foreach_cache */ nullptr,
+ /* foreach_path */ object_foreach_path,
+ /* owner_get */ nullptr,
+
+ /* blend_write */ object_blend_write,
+ /* blend_read_data */ object_blend_read_data,
+ /* blend_read_lib */ object_blend_read_lib,
+ /* blend_read_expand */ object_blend_read_expand,
+
+ /* blend_read_undo_preserve */ nullptr,
+
+ /* lib_override_apply_post */ object_lib_override_apply_post,
};
void BKE_object_workob_clear(Object *workob)
@@ -1186,7 +1334,7 @@ void BKE_object_free_particlesystems(Object *ob)
{
ParticleSystem *psys;
- while ((psys = BLI_pophead(&ob->particlesystem))) {
+ while ((psys = (ParticleSystem *)BLI_pophead(&ob->particlesystem))) {
psys_free(ob, psys);
}
}
@@ -1206,7 +1354,7 @@ void BKE_object_free_curve_cache(Object *ob)
}
BKE_nurbList_free(&ob->runtime.curve_cache->deformed_nurbs);
MEM_freeN(ob->runtime.curve_cache);
- ob->runtime.curve_cache = NULL;
+ ob->runtime.curve_cache = nullptr;
}
}
@@ -1215,11 +1363,11 @@ void BKE_object_free_modifiers(Object *ob, const int flag)
ModifierData *md;
GpencilModifierData *gp_md;
- while ((md = BLI_pophead(&ob->modifiers))) {
+ while ((md = (ModifierData *)BLI_pophead(&ob->modifiers))) {
BKE_modifier_free_ex(md, flag);
}
- while ((gp_md = BLI_pophead(&ob->greasepencil_modifiers))) {
+ while ((gp_md = (GpencilModifierData *)BLI_pophead(&ob->greasepencil_modifiers))) {
BKE_gpencil_modifier_free_ex(gp_md, flag);
}
/* particle modifiers were freed, so free the particlesystems as well */
@@ -1236,7 +1384,7 @@ void BKE_object_free_shaderfx(Object *ob, const int flag)
{
ShaderFxData *fx;
- while ((fx = BLI_pophead(&ob->shader_fx))) {
+ while ((fx = (ShaderFxData *)BLI_pophead(&ob->shader_fx))) {
BKE_shaderfx_free_ex(fx, flag);
}
}
@@ -1266,7 +1414,7 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData *hmd)
{
- if (hmd->object == NULL) {
+ if (hmd->object == nullptr) {
return;
}
/* reset functionality */
@@ -1288,19 +1436,13 @@ void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData
}
}
-/**
- * Set the object's active modifier.
- *
- * \param md: If NULL, only clear the active modifier, otherwise
- * it must be in the #Object.modifiers list.
- */
void BKE_object_modifier_set_active(Object *ob, ModifierData *md)
{
LISTBASE_FOREACH (ModifierData *, md_iter, &ob->modifiers) {
md_iter->flag &= ~eModifierFlag_Active;
}
- if (md != NULL) {
+ if (md != nullptr) {
BLI_assert(BLI_findindex(&ob->modifiers, md) != -1);
md->flag |= eModifierFlag_Active;
}
@@ -1325,12 +1467,9 @@ ModifierData *BKE_object_active_modifier(const Object *ob)
}
}
- return NULL;
+ return nullptr;
}
-/**
- * \return True if the object's type supports regular modifiers (not grease pencil modifiers).
- */
bool BKE_object_supports_modifiers(const Object *ob)
{
return (
@@ -1339,19 +1478,19 @@ bool BKE_object_supports_modifiers(const Object *ob)
bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
{
- const ModifierTypeInfo *mti = BKE_modifier_get_info(modifier_type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)modifier_type);
/* Surface and lattice objects don't output geometry sets. */
- if (mti->modifyGeometrySet != NULL && ELEM(ob->type, OB_SURF, OB_LATTICE)) {
+ if (mti->modifyGeometrySet != nullptr && ELEM(ob->type, OB_SURF, OB_LATTICE)) {
return false;
}
/* Only geometry objects should be able to get modifiers T25291. */
if (ob->type == OB_HAIR) {
- return (mti->modifyHair != NULL) || (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly);
+ return (mti->modifyHair != nullptr) || (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly);
}
if (ELEM(ob->type, OB_POINTCLOUD, OB_VOLUME)) {
- return (mti->modifyGeometrySet != NULL);
+ return (mti->modifyGeometrySet != nullptr);
}
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly) == 0) {
@@ -1388,7 +1527,7 @@ static ParticleSystem *object_copy_modifier_particle_system_ensure(Main *bmain,
Object *ob_dst,
ParticleSystem *psys_src)
{
- ParticleSystem *psys_dst = NULL;
+ ParticleSystem *psys_dst = nullptr;
/* Check if a particle system with the same particle settings
* already exists on the destination object. */
@@ -1400,7 +1539,7 @@ static ParticleSystem *object_copy_modifier_particle_system_ensure(Main *bmain,
}
/* If it does not exist, copy the particle system to the destination object. */
- if (psys_dst == NULL) {
+ if (psys_dst == nullptr) {
ModifierData *md = object_copy_particle_system(bmain, scene, ob_dst, psys_src);
psys_dst = ((ParticleSystemModifierData *)md)->psys;
}
@@ -1408,24 +1547,13 @@ static ParticleSystem *object_copy_modifier_particle_system_ensure(Main *bmain,
return psys_dst;
}
-/**
- * Copy a single modifier.
- *
- * \note **Do not** use this function to copy a whole modifier stack (see note below too). Use
- * `BKE_object_modifier_stack_copy` instead.
- *
- * \note Complex modifiers relaying on other data (like e.g. dynamic paint or fluid using particle
- * systems) are not always 100% 'correctly' copied here, since we have to use heuristics to decide
- * which particle system to use or add in `ob_dst`, and it's placement in the stack, etc. If used
- * more than once, this function should preferably be called in stack order.
- */
bool BKE_object_copy_modifier(
Main *bmain, Scene *scene, Object *ob_dst, const Object *ob_src, ModifierData *md_src)
{
BLI_assert(ob_dst->type != OB_GPENCIL);
- const ModifierTypeInfo *mti = BKE_modifier_get_info(md_src->type);
- if (!object_modifier_type_copy_check(md_src->type)) {
+ const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md_src->type);
+ if (!object_modifier_type_copy_check((ModifierType)md_src->type)) {
/* We never allow copying those modifiers here. */
return false;
}
@@ -1433,13 +1561,13 @@ bool BKE_object_copy_modifier(
return false;
}
if (mti->flags & eModifierTypeFlag_Single) {
- if (BKE_modifiers_findby_type(ob_dst, md_src->type) != NULL) {
+ if (BKE_modifiers_findby_type(ob_dst, (ModifierType)md_src->type) != nullptr) {
return false;
}
}
- ParticleSystem *psys_src = NULL;
- ParticleSystem *psys_dst = NULL;
+ ParticleSystem *psys_src = nullptr;
+ ParticleSystem *psys_dst = nullptr;
switch (md_src->type) {
case eModifierType_Softbody:
@@ -1447,12 +1575,12 @@ bool BKE_object_copy_modifier(
break;
case eModifierType_Skin:
/* ensure skin-node customdata exists */
- BKE_mesh_ensure_skin_customdata(ob_dst->data);
+ BKE_mesh_ensure_skin_customdata((Mesh *)ob_dst->data);
break;
case eModifierType_Fluid: {
FluidModifierData *fmd = (FluidModifierData *)md_src;
if (fmd->type == MOD_FLUID_TYPE_FLOW) {
- if (fmd->flow != NULL && fmd->flow->psys != NULL) {
+ if (fmd->flow != nullptr && fmd->flow->psys != nullptr) {
psys_src = fmd->flow->psys;
psys_dst = object_copy_modifier_particle_system_ensure(bmain, scene, ob_dst, psys_src);
}
@@ -1461,7 +1589,7 @@ bool BKE_object_copy_modifier(
}
case eModifierType_DynamicPaint: {
DynamicPaintModifierData *dpmd = (DynamicPaintModifierData *)md_src;
- if (dpmd->brush != NULL && dpmd->brush->psys != NULL) {
+ if (dpmd->brush != nullptr && dpmd->brush->psys != nullptr) {
psys_src = dpmd->brush->psys;
psys_dst = object_copy_modifier_particle_system_ensure(bmain, scene, ob_dst, psys_src);
}
@@ -1491,17 +1619,17 @@ bool BKE_object_copy_modifier(
switch (md_dst->type) {
case eModifierType_Fluid:
- if (psys_dst != NULL) {
+ if (psys_dst != nullptr) {
FluidModifierData *fmd_dst = (FluidModifierData *)md_dst;
- BLI_assert(fmd_dst->type == MOD_FLUID_TYPE_FLOW && fmd_dst->flow != NULL &&
- fmd_dst->flow->psys != NULL);
+ BLI_assert(fmd_dst->type == MOD_FLUID_TYPE_FLOW && fmd_dst->flow != nullptr &&
+ fmd_dst->flow->psys != nullptr);
fmd_dst->flow->psys = psys_dst;
}
break;
case eModifierType_DynamicPaint:
- if (psys_dst != NULL) {
+ if (psys_dst != nullptr) {
DynamicPaintModifierData *dpmd_dst = (DynamicPaintModifierData *)md_dst;
- BLI_assert(dpmd_dst->brush != NULL && dpmd_dst->brush->psys != NULL);
+ BLI_assert(dpmd_dst->brush != nullptr && dpmd_dst->brush->psys != nullptr);
dpmd_dst->brush->psys = psys_dst;
}
break;
@@ -1518,12 +1646,6 @@ bool BKE_object_copy_modifier(
return true;
}
-/**
- * Copy a single GPencil modifier.
- *
- * \note **Do not** use this function to copy a whole modifier stack. Use
- * `BKE_object_modifier_stack_copy` instead.
- */
bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData *gmd_src)
{
BLI_assert(ob_dst->type == OB_GPENCIL);
@@ -1531,7 +1653,8 @@ bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData
GpencilModifierData *gmd_dst = BKE_gpencil_modifier_new(gmd_src->type);
BLI_strncpy(gmd_dst->name, gmd_src->name, sizeof(gmd_dst->name));
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(gmd_src->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(
+ (GpencilModifierType)gmd_src->type);
mti->copyData(gmd_src, gmd_dst);
BLI_addtail(&ob_dst->greasepencil_modifiers, gmd_dst);
@@ -1540,15 +1663,6 @@ bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData
return true;
}
-/**
- * Copy the whole stack of modifiers from one object into another.
- *
- * \warning **Does not** clear modifier stack and related data (particle systems, soft-body,
- * etc.) in `ob_dst`, if needed calling code must do it.
- *
- * \param do_copy_all: If true, even modifiers that should not support copying (like Hook one)
- * will be duplicated.
- */
bool BKE_object_modifier_stack_copy(Object *ob_dst,
const Object *ob_src,
const bool do_copy_all,
@@ -1568,7 +1682,7 @@ bool BKE_object_modifier_stack_copy(Object *ob_dst,
}
LISTBASE_FOREACH (ModifierData *, md_src, &ob_src->modifiers) {
- if (!do_copy_all && !object_modifier_type_copy_check(md_src->type)) {
+ if (!do_copy_all && !object_modifier_type_copy_check((ModifierType)md_src->type)) {
continue;
}
if (!BKE_object_support_modifier_type_check(ob_dst, md_src->type)) {
@@ -1621,7 +1735,7 @@ static void copy_ccg_data(Mesh *mesh_destination, Mesh *mesh_source, int layer_t
const int layer_index = CustomData_get_layer_index(data_destination, layer_type);
CustomData_free_layer(data_destination, layer_type, num_elements, layer_index);
BLI_assert(!CustomData_has_layer(data_destination, layer_type));
- CustomData_add_layer(data_destination, layer_type, CD_CALLOC, NULL, num_elements);
+ CustomData_add_layer(data_destination, layer_type, CD_CALLOC, nullptr, num_elements);
BLI_assert(CustomData_has_layer(data_destination, layer_type));
CustomData_copy_layer_type_data(data_source, data_destination, layer_type, 0, 0, num_elements);
}
@@ -1639,13 +1753,14 @@ static void object_update_from_subsurf_ccg(Object *object)
if (!object->runtime.is_data_eval_owned) {
return;
}
- /* Object was never evaluated, so can not have CCG subdivision surface. */
- Mesh *mesh_eval = BKE_object_get_evaluated_mesh(object);
- if (mesh_eval == NULL) {
+ /* Object was never evaluated, so can not have CCG subdivision surface. If it were evaluated, do
+ * not try to compute OpenSubDiv on the CPU as it is not needed here. */
+ Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(object);
+ if (mesh_eval == nullptr) {
return;
}
SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg;
- if (subdiv_ccg == NULL) {
+ if (subdiv_ccg == nullptr) {
return;
}
/* Check whether there is anything to be reshaped. */
@@ -1659,24 +1774,24 @@ static void object_update_from_subsurf_ccg(Object *object)
/* NOTE: we need to reshape into an original mesh from main database,
* allowing:
*
- * - Update copies of that mesh at any moment.
- * - Save the file without doing extra reshape.
- * - All the users of the mesh have updated displacement.
+ * - Update copies of that mesh at any moment.
+ * - Save the file without doing extra reshape.
+ * - All the users of the mesh have updated displacement.
*
* However, the tricky part here is that we only know about sculpted
* state of a mesh on an object level, and object is being updated after
- * mesh datablock is updated. This forces us to:
+ * mesh data-block is updated. This forces us to:
*
- * - Update mesh datablock from object evaluation, which is technically
- * forbidden, but there is no other place for this yet.
- * - Reshape to the original mesh from main database, and then copy updated
- * layer to copy of that mesh (since copy of the mesh has decoupled
- * custom data layers).
+ * - Update mesh data-block from object evaluation, which is technically
+ * forbidden, but there is no other place for this yet.
+ * - Reshape to the original mesh from main database, and then copy updated
+ * layer to copy of that mesh (since copy of the mesh has decoupled
+ * custom data layers).
*
* All this is defeating all the designs we need to follow to allow safe
* threaded evaluation, but this is as good as we can make it within the
* current sculpt/evaluated mesh design. This is also how we've survived
- * with old DerivedMesh based solutions. So, while this is all wrong and
+ * with old #DerivedMesh based solutions. So, while this is all wrong and
* needs reconsideration, doesn't seem to be a big stopper for real
* production artists.
*/
@@ -1687,7 +1802,7 @@ static void object_update_from_subsurf_ccg(Object *object)
* it is orig as in what was in object_eval->data before evaluating
* modifier stack.
*
- * mesh_cow is a copy-on-written version od object_orig->data.
+ * mesh_cow is a copy-on-written version of `object_orig->data`.
*/
Mesh *mesh_cow = (Mesh *)object->runtime.data_orig;
copy_ccg_data(mesh_cow, mesh_orig, CD_MDISPS);
@@ -1697,13 +1812,10 @@ static void object_update_from_subsurf_ccg(Object *object)
subdiv_ccg->dirty.hidden = false;
}
-/**
- * Assign #Object.data after modifier stack evaluation.
- */
void BKE_object_eval_assign_data(Object *object_eval, ID *data_eval, bool is_owned)
{
BLI_assert(object_eval->id.tag & LIB_TAG_COPIED_ON_WRITE);
- BLI_assert(object_eval->runtime.data_eval == NULL);
+ BLI_assert(object_eval->runtime.data_eval == nullptr);
BLI_assert(data_eval->tag & LIB_TAG_NO_MAIN);
if (is_owned) {
@@ -1715,8 +1827,8 @@ void BKE_object_eval_assign_data(Object *object_eval, ID *data_eval, bool is_own
object_eval->runtime.data_eval = data_eval;
object_eval->runtime.is_data_eval_owned = is_owned;
- /* Overwrite data of evaluated object, if the datablock types match. */
- ID *data = object_eval->data;
+ /* Overwrite data of evaluated object, if the data-block types match. */
+ ID *data = (ID *)object_eval->data;
if (GS(data->name) == GS(data_eval->name)) {
/* NOTE: we are not supposed to invoke evaluation for original objects,
* but some areas are still being ported, so we play safe here. */
@@ -1726,19 +1838,22 @@ void BKE_object_eval_assign_data(Object *object_eval, ID *data_eval, bool is_own
}
/* Is set separately currently. */
- object_eval->runtime.geometry_set_eval = NULL;
+ object_eval->runtime.geometry_set_eval = nullptr;
}
-/**
- * Free data derived from mesh, called when mesh changes or is freed.
- */
void BKE_object_free_derived_caches(Object *ob)
{
MEM_SAFE_FREE(ob->runtime.bb);
object_update_from_subsurf_ccg(ob);
- if (ob->runtime.data_eval != NULL) {
+ if (ob->runtime.editmesh_eval_cage &&
+ ob->runtime.editmesh_eval_cage != reinterpret_cast<Mesh *>(ob->runtime.data_eval)) {
+ BKE_mesh_eval_delete(ob->runtime.editmesh_eval_cage);
+ }
+ ob->runtime.editmesh_eval_cage = nullptr;
+
+ if (ob->runtime.data_eval != nullptr) {
if (ob->runtime.is_data_eval_owned) {
ID *data_eval = ob->runtime.data_eval;
if (GS(data_eval->name) == ID_ME) {
@@ -1749,17 +1864,17 @@ void BKE_object_free_derived_caches(Object *ob)
MEM_freeN(data_eval);
}
}
- ob->runtime.data_eval = NULL;
+ ob->runtime.data_eval = nullptr;
}
- if (ob->runtime.mesh_deform_eval != NULL) {
+ if (ob->runtime.mesh_deform_eval != nullptr) {
Mesh *mesh_deform_eval = ob->runtime.mesh_deform_eval;
BKE_mesh_eval_delete(mesh_deform_eval);
- ob->runtime.mesh_deform_eval = NULL;
+ ob->runtime.mesh_deform_eval = nullptr;
}
- /* Restore initial pointer for copy-on-write datablocks, object->data
- * might be pointing to an evaluated datablock data was just freed above. */
- if (ob->runtime.data_orig != NULL) {
+ /* Restore initial pointer for copy-on-write data-blocks, object->data
+ * might be pointing to an evaluated data-block data was just freed above. */
+ if (ob->runtime.data_orig != nullptr) {
ob->data = ob->runtime.data_orig;
}
@@ -1767,16 +1882,20 @@ void BKE_object_free_derived_caches(Object *ob)
BKE_object_to_curve_clear(ob);
BKE_object_free_curve_cache(ob);
+ BKE_crazyspace_api_eval_clear(ob);
+
/* Clear grease pencil data. */
- if (ob->runtime.gpd_eval != NULL) {
+ if (ob->runtime.gpd_eval != nullptr) {
BKE_gpencil_eval_delete(ob->runtime.gpd_eval);
- ob->runtime.gpd_eval = NULL;
+ ob->runtime.gpd_eval = nullptr;
}
- if (ob->runtime.geometry_set_eval != NULL) {
+ if (ob->runtime.geometry_set_eval != nullptr) {
BKE_geometry_set_free(ob->runtime.geometry_set_eval);
- ob->runtime.geometry_set_eval = NULL;
+ ob->runtime.geometry_set_eval = nullptr;
}
+
+ MEM_SAFE_FREE(ob->runtime.editmesh_bb_cage);
}
void BKE_object_free_caches(Object *object)
@@ -1785,8 +1904,7 @@ void BKE_object_free_caches(Object *object)
/* Free particle system caches holding paths. */
if (object->particlesystem.first) {
- ParticleSystem *psys;
- for (psys = object->particlesystem.first; psys != NULL; psys = psys->next) {
+ LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
psys_free_path_cache(psys, psys->edit);
update_flag |= ID_RECALC_PSYS_REDO;
}
@@ -1797,11 +1915,11 @@ void BKE_object_free_caches(Object *object)
if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
if (psmd->mesh_final) {
- BKE_id_free(NULL, psmd->mesh_final);
- psmd->mesh_final = NULL;
+ BKE_id_free(nullptr, psmd->mesh_final);
+ psmd->mesh_final = nullptr;
if (psmd->mesh_original) {
- BKE_id_free(NULL, psmd->mesh_original);
- psmd->mesh_original = NULL;
+ BKE_id_free(nullptr, psmd->mesh_original);
+ psmd->mesh_original = nullptr;
}
psmd->flag |= eParticleSystemFlag_file_loaded;
update_flag |= ID_RECALC_GEOMETRY;
@@ -1827,29 +1945,26 @@ void BKE_object_free_caches(Object *object)
}
}
-/**
- * Actual check for internal data, not context or flags.
- */
bool BKE_object_is_in_editmode(const Object *ob)
{
- if (ob->data == NULL) {
+ if (ob->data == nullptr) {
return false;
}
switch (ob->type) {
case OB_MESH:
- return ((Mesh *)ob->data)->edit_mesh != NULL;
+ return ((Mesh *)ob->data)->edit_mesh != nullptr;
case OB_ARMATURE:
- return ((bArmature *)ob->data)->edbo != NULL;
+ return ((bArmature *)ob->data)->edbo != nullptr;
case OB_FONT:
- return ((Curve *)ob->data)->editfont != NULL;
+ return ((Curve *)ob->data)->editfont != nullptr;
case OB_MBALL:
- return ((MetaBall *)ob->data)->editelems != NULL;
+ return ((MetaBall *)ob->data)->editelems != nullptr;
case OB_LATTICE:
- return ((Lattice *)ob->data)->editlatt != NULL;
+ return ((Lattice *)ob->data)->editlatt != nullptr;
case OB_SURF:
case OB_CURVE:
- return ((Curve *)ob->data)->editnurb != NULL;
+ return ((Curve *)ob->data)->editnurb != nullptr;
case OB_GPENCIL:
/* Grease Pencil object has no edit mode data. */
return GPENCIL_EDIT_MODE((bGPdata *)ob->data);
@@ -1869,15 +1984,16 @@ bool BKE_object_data_is_in_editmode(const ID *id)
BLI_assert(OB_DATA_SUPPORT_EDITMODE(type));
switch (type) {
case ID_ME:
- return ((const Mesh *)id)->edit_mesh != NULL;
+ return ((const Mesh *)id)->edit_mesh != nullptr;
case ID_CU:
- return ((((const Curve *)id)->editnurb != NULL) || (((const Curve *)id)->editfont != NULL));
+ return ((((const Curve *)id)->editnurb != nullptr) ||
+ (((const Curve *)id)->editfont != nullptr));
case ID_MB:
- return ((const MetaBall *)id)->editelems != NULL;
+ return ((const MetaBall *)id)->editelems != nullptr;
case ID_LT:
- return ((const Lattice *)id)->editlatt != NULL;
+ return ((const Lattice *)id)->editlatt != nullptr;
case ID_AR:
- return ((const bArmature *)id)->edbo != NULL;
+ return ((const bArmature *)id)->edbo != nullptr;
default:
BLI_assert_unreachable();
return false;
@@ -1890,15 +2006,15 @@ char *BKE_object_data_editmode_flush_ptr_get(struct ID *id)
switch (type) {
case ID_ME: {
BMEditMesh *em = ((Mesh *)id)->edit_mesh;
- if (em != NULL) {
+ if (em != nullptr) {
return &em->needs_flush_to_id;
}
break;
}
case ID_CU: {
- if (((Curve *)id)->vfont != NULL) {
+ if (((Curve *)id)->vfont != nullptr) {
EditFont *ef = ((Curve *)id)->editfont;
- if (ef != NULL) {
+ if (ef != nullptr) {
return &ef->needs_flush_to_id;
}
}
@@ -1927,16 +2043,16 @@ char *BKE_object_data_editmode_flush_ptr_get(struct ID *id)
}
default:
BLI_assert_unreachable();
- return NULL;
+ return nullptr;
}
- return NULL;
+ return nullptr;
}
bool BKE_object_is_in_wpaint_select_vert(const Object *ob)
{
if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- return ((ob->mode & OB_MODE_WEIGHT_PAINT) && (me->edit_mesh == NULL) &&
+ Mesh *me = (Mesh *)ob->data;
+ return ((ob->mode & OB_MODE_WEIGHT_PAINT) && (me->edit_mesh == nullptr) &&
(ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX));
}
@@ -1966,7 +2082,7 @@ bool BKE_object_has_mode_data(const struct Object *ob, eObjectMode object_mode)
}
}
else if (object_mode & OB_MODE_POSE) {
- if (ob->pose != NULL) {
+ if (ob->pose != nullptr) {
return true;
}
}
@@ -1978,9 +2094,6 @@ bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode)
return ((ob->mode == object_mode) || (ob->mode & object_mode) != 0);
}
-/**
- * Return which parts of the object are visible, as evaluated by depsgraph
- */
int BKE_object_visibility(const Object *ob, const int dag_eval_mode)
{
if ((ob->base_flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
@@ -2021,7 +2134,7 @@ int BKE_object_visibility(const Object *ob, const int dag_eval_mode)
bool BKE_object_exists_check(Main *bmain, const Object *obtest)
{
- if (obtest == NULL) {
+ if (obtest == nullptr) {
return false;
}
@@ -2105,7 +2218,7 @@ static void object_init(Object *ob, const short ob_type)
void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
{
- if (name == NULL) {
+ if (name == nullptr) {
name = get_obdata_defname(type);
}
@@ -2141,16 +2254,13 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
case OB_VOLUME:
return BKE_volume_add(bmain, name);
case OB_EMPTY:
- return NULL;
+ return nullptr;
default:
CLOG_ERROR(&LOG, "Internal error, bad type: %d", type);
- return NULL;
+ return nullptr;
}
}
-/**
- * Return -1 on failure.
- */
int BKE_object_obdata_to_type(const ID *id)
{
/* Keep in sync with #OB_DATA_SUPPORT_ID macro. */
@@ -2186,9 +2296,6 @@ int BKE_object_obdata_to_type(const ID *id)
}
}
-/**
- * More general add: creates minimum required data, but without vertices etc.
- */
Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
{
if (!name) {
@@ -2196,7 +2303,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
}
/* We cannot use #BKE_id_new here as we need some custom initialization code. */
- Object *ob = BKE_libblock_alloc(bmain, ID_OB, name, 0);
+ Object *ob = (Object *)BKE_libblock_alloc(bmain, ID_OB, name, 0);
/* We increase object user count when linking to Collections. */
id_us_min(&ob->id);
@@ -2218,14 +2325,6 @@ static Object *object_add_common(Main *bmain, ViewLayer *view_layer, int type, c
return ob;
}
-/**
- * General add: to scene, with layer from area and default name
- *
- * Object is added to the active #Collection.
- * If there is no linked collection to the active #ViewLayer we create a new one.
- *
- * \note Creates minimum required data, but without vertices etc.
- */
Object *BKE_object_add(Main *bmain, ViewLayer *view_layer, int type, const char *name)
{
Object *ob = object_add_common(bmain, view_layer, type, name);
@@ -2239,11 +2338,6 @@ Object *BKE_object_add(Main *bmain, ViewLayer *view_layer, int type, const char
return ob;
}
-/**
- * Add a new object, using another one as a reference
- *
- * \param ob_src: object to use to determine the collections of the new object.
- */
Object *BKE_object_add_from(
Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name, Object *ob_src)
{
@@ -2256,21 +2350,12 @@ Object *BKE_object_add_from(
return ob;
}
-/**
- * Add a new object, but assign the given datablock as the ob->data
- * for the newly created object.
- *
- * \param data: The datablock to assign as ob->data for the new object.
- * This is assumed to be of the correct type.
- * \param do_id_user: If true, id_us_plus() will be called on data when
- * assigning it to the object.
- */
Object *BKE_object_add_for_data(
Main *bmain, ViewLayer *view_layer, int type, const char *name, ID *data, bool do_id_user)
{
/* same as object_add_common, except we don't create new ob->data */
Object *ob = BKE_object_add_only_object(bmain, type, name);
- ob->data = data;
+ ob->data = (void *)data;
if (do_id_user) {
id_us_plus(data);
}
@@ -2294,17 +2379,17 @@ void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src, const int fl
const bool is_orig = (flag & LIB_ID_COPY_SET_COPIED_ON_WRITE) == 0;
ob_dst->softflag = ob_src->softflag;
- if (sb == NULL) {
- ob_dst->soft = NULL;
+ if (sb == nullptr) {
+ ob_dst->soft = nullptr;
return;
}
- SoftBody *sbn = MEM_dupallocN(sb);
+ SoftBody *sbn = (SoftBody *)MEM_dupallocN(sb);
if ((flag & LIB_ID_COPY_CACHES) == 0) {
sbn->totspring = sbn->totpoint = 0;
- sbn->bpoint = NULL;
- sbn->bspring = NULL;
+ sbn->bpoint = nullptr;
+ sbn->bspring = nullptr;
}
else {
sbn->totspring = sb->totspring;
@@ -2313,33 +2398,33 @@ void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src, const int fl
if (sbn->bpoint) {
int i;
- sbn->bpoint = MEM_dupallocN(sbn->bpoint);
+ sbn->bpoint = (BodyPoint *)MEM_dupallocN(sbn->bpoint);
for (i = 0; i < sbn->totpoint; i++) {
if (sbn->bpoint[i].springs) {
- sbn->bpoint[i].springs = MEM_dupallocN(sbn->bpoint[i].springs);
+ sbn->bpoint[i].springs = (int *)MEM_dupallocN(sbn->bpoint[i].springs);
}
}
}
if (sb->bspring) {
- sbn->bspring = MEM_dupallocN(sb->bspring);
+ sbn->bspring = (struct BodySpring *)MEM_dupallocN(sb->bspring);
}
}
- sbn->keys = NULL;
+ sbn->keys = nullptr;
sbn->totkey = sbn->totpointkey = 0;
- sbn->scratch = NULL;
+ sbn->scratch = nullptr;
if (is_orig) {
- sbn->shared = MEM_dupallocN(sb->shared);
+ sbn->shared = (SoftBody_Shared *)MEM_dupallocN(sb->shared);
sbn->shared->pointcache = BKE_ptcache_copy_list(
&sbn->shared->ptcaches, &sb->shared->ptcaches, flag);
}
if (sb->effector_weights) {
- sbn->effector_weights = MEM_dupallocN(sb->effector_weights);
+ sbn->effector_weights = (EffectorWeights *)MEM_dupallocN(sb->effector_weights);
}
ob_dst->soft = sbn;
@@ -2347,26 +2432,26 @@ void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src, const int fl
ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int flag)
{
- ParticleSystem *psysn = MEM_dupallocN(psys);
+ ParticleSystem *psysn = (ParticleSystem *)MEM_dupallocN(psys);
psys_copy_particles(psysn, psys);
if (psys->clmd) {
psysn->clmd = (ClothModifierData *)BKE_modifier_new(eModifierType_Cloth);
BKE_modifier_copydata_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag);
- psys->hair_in_mesh = psys->hair_out_mesh = NULL;
+ psys->hair_in_mesh = psys->hair_out_mesh = nullptr;
}
BLI_duplicatelist(&psysn->targets, &psys->targets);
- psysn->pathcache = NULL;
- psysn->childcache = NULL;
- psysn->edit = NULL;
- psysn->pdd = NULL;
- psysn->effectors = NULL;
- psysn->tree = NULL;
- psysn->bvhtree = NULL;
- psysn->batch_cache = NULL;
+ psysn->pathcache = nullptr;
+ psysn->childcache = nullptr;
+ psysn->edit = nullptr;
+ psysn->pdd = nullptr;
+ psysn->effectors = nullptr;
+ psysn->tree = nullptr;
+ psysn->bvhtree = nullptr;
+ psysn->batch_cache = nullptr;
BLI_listbase_clear(&psysn->pathcachebufs);
BLI_listbase_clear(&psysn->childcachebufs);
@@ -2376,14 +2461,14 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int f
* creation. */
// BLI_assert((psys->flag & PSYS_SHARED_CACHES) == 0);
psysn->flag |= PSYS_SHARED_CACHES;
- BLI_assert(psysn->pointcache != NULL);
+ BLI_assert(psysn->pointcache != nullptr);
}
else {
psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag);
}
- /* XXX(campbell): from reading existing code this seems correct but intended usage of
- * pointcache should /w cloth should be added in 'ParticleSystem'. */
+ /* XXX(@campbellbarton): from reading existing code this seems correct but intended usage of
+ * point-cache should /w cloth should be added in 'ParticleSystem'. */
if (psysn->clmd) {
psysn->clmd->point_cache = psysn->pointcache;
}
@@ -2443,7 +2528,7 @@ static void copy_object_pose(Object *obn, const Object *ob, const int flag)
{
/* NOTE: need to clear obn->pose pointer first,
* so that BKE_pose_copy_data works (otherwise there's a crash) */
- obn->pose = NULL;
+ obn->pose = nullptr;
BKE_pose_copy_data_ex(&obn->pose, ob->pose, flag, true); /* true = copy constraints */
LISTBASE_FOREACH (bPoseChannel *, chan, &obn->pose->chanbase) {
@@ -2454,20 +2539,19 @@ static void copy_object_pose(Object *obn, const Object *ob, const int flag)
* the flush_constraint_targets callback am not sure about, so will delay that for now. */
LISTBASE_FOREACH (bConstraint *, con, &chan->constraints) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
+ ListBase targets = {nullptr, nullptr};
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
- for (ct = targets.first; ct; ct = ct->next) {
+ LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar == ob) {
ct->tar = obn;
}
}
if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
+ cti->flush_constraint_targets(con, &targets, false);
}
}
}
@@ -2485,8 +2569,8 @@ bool BKE_object_pose_context_check(const Object *ob)
Object *BKE_object_pose_armature_get(Object *ob)
{
- if (ob == NULL) {
- return NULL;
+ if (ob == nullptr) {
+ return nullptr;
}
if (BKE_object_pose_context_check(ob)) {
@@ -2500,7 +2584,7 @@ Object *BKE_object_pose_armature_get(Object *ob)
return ob;
}
- return NULL;
+ return nullptr;
}
Object *BKE_object_pose_armature_get_visible(Object *ob, ViewLayer *view_layer, View3D *v3d)
@@ -2514,12 +2598,9 @@ Object *BKE_object_pose_armature_get_visible(Object *ob, ViewLayer *view_layer,
}
}
}
- return NULL;
+ return nullptr;
}
-/**
- * Access pose array with special check to get pose object when in weight paint mode.
- */
Object **BKE_object_pose_array_get_ex(ViewLayer *view_layer,
View3D *v3d,
uint *r_objects_len,
@@ -2527,24 +2608,23 @@ Object **BKE_object_pose_array_get_ex(ViewLayer *view_layer,
{
Object *ob_active = OBACT(view_layer);
Object *ob_pose = BKE_object_pose_armature_get(ob_active);
- Object **objects = NULL;
+ Object **objects = nullptr;
if (ob_pose == ob_active) {
- objects = BKE_view_layer_array_from_objects_in_mode(view_layer,
- v3d,
- r_objects_len,
- {
- .object_mode = OB_MODE_POSE,
- .no_dup_data = unique,
- });
- }
- else if (ob_pose != NULL) {
+ ObjectsInModeParams ob_params{};
+ ob_params.object_mode = OB_MODE_POSE;
+ ob_params.no_dup_data = unique;
+
+ objects = BKE_view_layer_array_from_objects_in_mode_params(
+ view_layer, v3d, r_objects_len, &ob_params);
+ }
+ else if (ob_pose != nullptr) {
*r_objects_len = 1;
- objects = MEM_mallocN(sizeof(*objects), __func__);
+ objects = (Object **)MEM_mallocN(sizeof(*objects), __func__);
objects[0] = ob_pose;
}
else {
*r_objects_len = 0;
- objects = MEM_mallocN(0, __func__);
+ objects = (Object **)MEM_mallocN(0, __func__);
}
return objects;
}
@@ -2563,9 +2643,9 @@ Base **BKE_object_pose_base_array_get_ex(ViewLayer *view_layer,
bool unique)
{
Base *base_active = BASACT(view_layer);
- Object *ob_pose = base_active ? BKE_object_pose_armature_get(base_active->object) : NULL;
- Base *base_pose = NULL;
- Base **bases = NULL;
+ Object *ob_pose = base_active ? BKE_object_pose_armature_get(base_active->object) : nullptr;
+ Base *base_pose = nullptr;
+ Base **bases = nullptr;
if (base_active) {
if (ob_pose == base_active->object) {
@@ -2577,22 +2657,21 @@ Base **BKE_object_pose_base_array_get_ex(ViewLayer *view_layer,
}
if (base_active && (base_pose == base_active)) {
- bases = BKE_view_layer_array_from_bases_in_mode(view_layer,
- v3d,
- r_bases_len,
- {
- .object_mode = OB_MODE_POSE,
- .no_dup_data = unique,
- });
- }
- else if (base_pose != NULL) {
+ ObjectsInModeParams ob_params{};
+ ob_params.object_mode = OB_MODE_POSE;
+ ob_params.no_dup_data = unique;
+
+ bases = BKE_view_layer_array_from_bases_in_mode_params(
+ view_layer, v3d, r_bases_len, &ob_params);
+ }
+ else if (base_pose != nullptr) {
*r_bases_len = 1;
- bases = MEM_mallocN(sizeof(*bases), __func__);
+ bases = (Base **)MEM_mallocN(sizeof(*bases), __func__);
bases[0] = base_pose;
}
else {
*r_bases_len = 0;
- bases = MEM_mallocN(0, __func__);
+ bases = (Base **)MEM_mallocN(0, __func__);
}
return bases;
}
@@ -2616,28 +2695,20 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
copy_v3_v3(ob_tar->scale, ob_src->scale);
}
-/**
- * Perform deep-copy of object and its 'children' data-blocks (obdata, materials, actions, etc.).
- *
- * \param dupflag: Controls which sub-data are also duplicated
- * (see #eDupli_ID_Flags in DNA_userdef_types.h).
- *
- * \note This function does not do any remapping to new IDs, caller must do it
- * (\a #BKE_libblock_relink_to_newid()).
- * \note Caller MUST free \a newid pointers itself (#BKE_main_id_newptr_and_tag_clear()) and call
- * updates of DEG too (#DAG_relations_tag_update()).
- */
-Object *BKE_object_duplicate(Main *bmain,
- Object *ob,
- eDupli_ID_Flags dupflag,
- eLibIDDuplicateFlags duplicate_options)
+Object *BKE_object_duplicate(Main *bmain, Object *ob, uint dupflag, uint duplicate_options)
{
const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
const bool is_root_id = (duplicate_options & LIB_ID_DUPLICATE_IS_ROOT_ID) != 0;
+ int copy_flags = LIB_ID_COPY_DEFAULT;
if (!is_subprocess) {
BKE_main_id_newptr_and_tag_clear(bmain);
}
+ else {
+ /* In case copying object is a sub-process of collection (or scene) copying, do not try to
+ * re-assign RB objects to existing RBW collections. */
+ copy_flags |= LIB_ID_COPY_RIGID_BODY_NO_COLLECTION_HANDLING;
+ }
if (is_root_id) {
/* In case root duplicated ID is linked, assume we want to get a local copy of it and duplicate
* all expected linked data. */
@@ -2649,7 +2720,7 @@ Object *BKE_object_duplicate(Main *bmain,
Material ***matarar;
- Object *obn = (Object *)BKE_id_copy_for_duplicate(bmain, &ob->id, dupflag);
+ Object *obn = (Object *)BKE_id_copy_for_duplicate(bmain, &ob->id, dupflag, copy_flags);
/* 0 == full linked. */
if (dupflag == 0) {
@@ -2658,105 +2729,104 @@ Object *BKE_object_duplicate(Main *bmain,
if (dupflag & USER_DUP_MAT) {
for (int i = 0; i < obn->totcol; i++) {
- BKE_id_copy_for_duplicate(bmain, (ID *)obn->mat[i], dupflag);
+ BKE_id_copy_for_duplicate(bmain, (ID *)obn->mat[i], dupflag, copy_flags);
}
}
if (dupflag & USER_DUP_PSYS) {
- ParticleSystem *psys;
- for (psys = obn->particlesystem.first; psys; psys = psys->next) {
- BKE_id_copy_for_duplicate(bmain, (ID *)psys->part, dupflag);
+ LISTBASE_FOREACH (ParticleSystem *, psys, &obn->particlesystem) {
+ BKE_id_copy_for_duplicate(bmain, (ID *)psys->part, dupflag, copy_flags);
}
}
- ID *id_old = obn->data;
- ID *id_new = NULL;
- const bool need_to_duplicate_obdata = (id_old != NULL) && (id_old->newid == NULL);
+ ID *id_old = (ID *)obn->data;
+ ID *id_new = nullptr;
+ const bool need_to_duplicate_obdata = (id_old != nullptr) && (id_old->newid == nullptr);
switch (obn->type) {
case OB_MESH:
if (dupflag & USER_DUP_MESH) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_CURVE:
if (dupflag & USER_DUP_CURVE) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_SURF:
if (dupflag & USER_DUP_SURF) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_FONT:
if (dupflag & USER_DUP_FONT) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_MBALL:
if (dupflag & USER_DUP_MBALL) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_LAMP:
if (dupflag & USER_DUP_LAMP) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_ARMATURE:
if (dupflag & USER_DUP_ARM) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_LATTICE:
- if (dupflag != 0) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ if (dupflag & USER_DUP_LATTICE) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_CAMERA:
- if (dupflag != 0) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ if (dupflag & USER_DUP_CAMERA) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_LIGHTPROBE:
if (dupflag & USER_DUP_LIGHTPROBE) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_SPEAKER:
- if (dupflag != 0) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ if (dupflag & USER_DUP_SPEAKER) {
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_GPENCIL:
if (dupflag & USER_DUP_GPENCIL) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_HAIR:
if (dupflag & USER_DUP_HAIR) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_POINTCLOUD:
if (dupflag & USER_DUP_POINTCLOUD) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
case OB_VOLUME:
if (dupflag & USER_DUP_VOLUME) {
- id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag);
+ id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags);
}
break;
}
/* If obdata has been copied, we may also have to duplicate the materials assigned to it. */
- if (need_to_duplicate_obdata && !ELEM(id_new, NULL, id_old)) {
+ if (need_to_duplicate_obdata && !ELEM(id_new, nullptr, id_old)) {
if (dupflag & USER_DUP_MAT) {
matarar = BKE_object_material_array_p(obn);
if (matarar) {
for (int i = 0; i < obn->totcol; i++) {
- BKE_id_copy_for_duplicate(bmain, (ID *)(*matarar)[i], dupflag);
+ BKE_id_copy_for_duplicate(bmain, (ID *)(*matarar)[i], dupflag, copy_flags);
}
}
}
@@ -2764,7 +2834,7 @@ Object *BKE_object_duplicate(Main *bmain,
if (!is_subprocess) {
/* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */
- BKE_libblock_relink_to_newid(&obn->id);
+ BKE_libblock_relink_to_newid(bmain, &obn->id, 0);
#ifndef NDEBUG
/* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */
@@ -2787,24 +2857,18 @@ Object *BKE_object_duplicate(Main *bmain,
// BKE_pose_rebuild(bmain, obn, obn->data, true);
}
- if (obn->data != NULL) {
+ if (obn->data != nullptr) {
DEG_id_tag_update_ex(bmain, (ID *)obn->data, ID_RECALC_EDITORS);
}
return obn;
}
-/**
- * Returns true if the Object is from an external blend file (libdata).
- */
bool BKE_object_is_libdata(const Object *ob)
{
return (ob && ID_IS_LINKED(ob));
}
-/**
- * Returns true if the Object data is from an external blend file (libdata).
- */
bool BKE_object_obdata_is_libdata(const Object *ob)
{
/* Linked objects with local obdata are forbidden! */
@@ -2819,11 +2883,10 @@ bool BKE_object_obdata_is_libdata(const Object *ob)
/* when you make proxy, ensure the exposed layers are extern */
static void armature_set_id_extern(Object *ob)
{
- bArmature *arm = ob->data;
- bPoseChannel *pchan;
+ bArmature *arm = (bArmature *)ob->data;
unsigned int lay = arm->layer_protected;
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
if (!(pchan->bone->layer & lay)) {
id_lib_extern((ID *)pchan->custom);
}
@@ -2833,7 +2896,6 @@ static void armature_set_id_extern(Object *ob)
void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
{
if ((target->adt) && (target->adt->drivers.first)) {
- FCurve *fcu;
/* add new animdata block */
if (!ob->adt) {
@@ -2844,11 +2906,10 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
BKE_fcurves_free(&ob->adt->drivers);
BKE_fcurves_copy(&ob->adt->drivers, &target->adt->drivers);
- for (fcu = ob->adt->drivers.first; fcu; fcu = fcu->next) {
+ LISTBASE_FOREACH (FCurve *, fcu, &ob->adt->drivers) {
ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
/* all drivers */
DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
if (dtar->id) {
@@ -2871,12 +2932,6 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
}
}
-/**
- * Proxy rule:
- * - lib_object->proxy_from == the one we borrow from, set temporally while object_update.
- * - local_object->proxy == pointer to library object, saved in files and read.
- * - local_object->proxy_group == pointer to collection dupli-object, saved in files and read.
- */
void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
{
/* paranoia checks */
@@ -2933,16 +2988,16 @@ void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
if (ob->matbits) {
MEM_freeN(ob->matbits);
}
- ob->mat = NULL;
- ob->matbits = NULL;
+ ob->mat = nullptr;
+ ob->matbits = nullptr;
if ((target->totcol) && (target->mat) && OB_TYPE_SUPPORT_MATERIAL(ob->type)) {
int i;
ob->actcol = target->actcol;
ob->totcol = target->totcol;
- ob->mat = MEM_dupallocN(target->mat);
- ob->matbits = MEM_dupallocN(target->matbits);
+ ob->mat = (Material **)MEM_dupallocN(target->mat);
+ ob->matbits = (char *)MEM_dupallocN(target->matbits);
for (i = 0; i < target->totcol; i++) {
/* don't need to run BKE_object_materials_test
* since we know this object is new and not used elsewhere */
@@ -2952,9 +3007,9 @@ void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
/* type conversions */
if (target->type == OB_ARMATURE) {
- copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */
- BKE_pose_rest(ob->pose, false); /* clear all transforms in channels */
- BKE_pose_rebuild(bmain, ob, ob->data, true); /* set all internal links */
+ copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */
+ BKE_pose_rest(ob->pose, false); /* clear all transforms in channels */
+ BKE_pose_rebuild(bmain, ob, (bArmature *)ob->data, true); /* set all internal links */
armature_set_id_extern(ob);
}
@@ -2966,7 +3021,7 @@ void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
/* copy IDProperties */
if (ob->id.properties) {
IDP_FreeProperty(ob->id.properties);
- ob->id.properties = NULL;
+ ob->id.properties = nullptr;
}
if (target->id.properties) {
ob->id.properties = IDP_CopyProperty(target->id.properties);
@@ -2976,10 +3031,6 @@ void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
ob->dt = target->dt;
}
-/**
- * Use with newly created objects to set their size
- * (used to apply scene-scale).
- */
void BKE_object_obdata_size_init(struct Object *ob, const float size)
{
/* apply radius as a scale to types that support it */
@@ -2989,17 +3040,17 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size)
break;
}
case OB_FONT: {
- Curve *cu = ob->data;
+ Curve *cu = (Curve *)ob->data;
cu->fsize *= size;
break;
}
case OB_CAMERA: {
- Camera *cam = ob->data;
+ Camera *cam = (Camera *)ob->data;
cam->drawsize *= size;
break;
}
case OB_LAMP: {
- Light *lamp = ob->data;
+ Light *lamp = (Light *)ob->data;
lamp->dist *= size;
lamp->area_size *= size;
lamp->area_sizey *= size;
@@ -3009,7 +3060,7 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size)
/* Only lattice (not mesh, curve, mball...),
* because its got data when newly added */
case OB_LATTICE: {
- struct Lattice *lt = ob->data;
+ Lattice *lt = (Lattice *)ob->data;
float mat[4][4];
unit_m4(mat);
@@ -3252,7 +3303,7 @@ void BKE_object_matrix_local_get(struct Object *ob, float r_mat[4][4])
*/
static bool ob_parcurve(Object *ob, Object *par, float r_mat[4][4])
{
- Curve *cu = par->data;
+ Curve *cu = (Curve *)par->data;
float vec[4], dir[3], quat[4], radius, ctime;
/* NOTE: Curve cache is supposed to be evaluated here already, however there
@@ -3263,10 +3314,10 @@ static bool ob_parcurve(Object *ob, Object *par, float r_mat[4][4])
* TODO(sergey): Some of the legit looking cases like T56619 need to be
* looked into, and maybe curve cache (and other dependencies) are to be
* evaluated prior to conversion. */
- if (par->runtime.curve_cache == NULL) {
+ if (par->runtime.curve_cache == nullptr) {
return false;
}
- if (par->runtime.curve_cache->anim_path_accum_length == NULL) {
+ if (par->runtime.curve_cache->anim_path_accum_length == nullptr) {
return false;
}
@@ -3291,7 +3342,7 @@ static bool ob_parcurve(Object *ob, Object *par, float r_mat[4][4])
/* vec: 4 items! */
if (BKE_where_on_path(
- par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : NULL, &radius, NULL)) {
+ par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : nullptr, &radius, nullptr)) {
if (cu->flag & CU_FOLLOW) {
quat_apply_track(quat, ob->trackflag, ob->upflag);
normalize_qt(quat);
@@ -3348,9 +3399,10 @@ static void give_parvert(Object *par, int nr, float vec[3])
zero_v3(vec);
if (par->type == OB_MESH) {
- Mesh *me = par->data;
+ Mesh *me = (Mesh *)par->data;
BMEditMesh *em = me->edit_mesh;
- Mesh *me_eval = (em) ? em->mesh_eval_final : BKE_object_get_evaluated_mesh(par);
+ Mesh *me_eval = (em) ? BKE_object_get_editmesh_eval_final(par) :
+ BKE_object_get_evaluated_mesh(par);
if (me_eval) {
int count = 0;
@@ -3382,7 +3434,7 @@ static void give_parvert(Object *par, int nr, float vec[3])
}
}
else if (CustomData_has_layer(&me_eval->vdata, CD_ORIGINDEX)) {
- const int *index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
+ const int *index = (const int *)CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
/* Get the average of all verts with (original index == nr). */
for (int i = 0; i < numVerts; i++) {
if (index[i] == nr) {
@@ -3421,24 +3473,24 @@ static void give_parvert(Object *par, int nr, float vec[3])
ListBase *nurb;
/* Unless there's some weird depsgraph failure the cache should exist. */
- BLI_assert(par->runtime.curve_cache != NULL);
+ BLI_assert(par->runtime.curve_cache != nullptr);
- if (par->runtime.curve_cache->deformed_nurbs.first != NULL) {
+ if (par->runtime.curve_cache->deformed_nurbs.first != nullptr) {
nurb = &par->runtime.curve_cache->deformed_nurbs;
}
else {
- Curve *cu = par->data;
+ Curve *cu = (Curve *)par->data;
nurb = BKE_curve_nurbs_get(cu);
}
BKE_nurbList_index_get_co(nurb, nr, vec);
}
else if (par->type == OB_LATTICE) {
- Lattice *latt = par->data;
+ Lattice *latt = (Lattice *)par->data;
DispList *dl = par->runtime.curve_cache ?
BKE_displist_find(&par->runtime.curve_cache->disp, DL_VERTS) :
- NULL;
- float(*co)[3] = dl ? (float(*)[3])dl->verts : NULL;
+ nullptr;
+ float(*co)[3] = dl ? (float(*)[3])dl->verts : nullptr;
int tot;
if (latt->editlatt) {
@@ -3448,7 +3500,7 @@ static void give_parvert(Object *par, int nr, float vec[3])
tot = latt->pntsu * latt->pntsv * latt->pntsw;
/* ensure dl is correct size */
- BLI_assert(dl == NULL || dl->nr == tot);
+ BLI_assert(dl == nullptr || dl->nr == tot);
if (nr < tot) {
if (co) {
@@ -3593,7 +3645,7 @@ static void object_where_is_calc_ex(Depsgraph *depsgraph,
/* solve constraints */
if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) {
bConstraintOb *cob;
- cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, nullptr, CONSTRAINT_OBTYPE_OBJECT);
BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime);
BKE_constraints_clear_evalob(cob);
}
@@ -3615,20 +3667,14 @@ void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *o
ctime);
BKE_animsys_evaluate_animdata(
&ob->id, ob->adt, &anim_eval_context, ADT_RECALC_ALL, flush_to_original);
- object_where_is_calc_ex(depsgraph, scene, ob, ctime, NULL, NULL);
+ object_where_is_calc_ex(depsgraph, scene, ob, ctime, nullptr, nullptr);
}
-/**
- * Calculate object transformation matrix without recalculating dependencies and
- * constraints -- assume dependencies are already solved by depsgraph.
- * No changes to object and its parent would be done.
- * Used for bundles orientation in 3d space relative to parented blender camera.
- */
void BKE_object_where_is_calc_mat4(Object *ob, float r_obmat[4][4])
{
if (ob->parent) {
Object *par = ob->parent;
- solve_parenting(ob, par, false, r_obmat, NULL);
+ solve_parenting(ob, par, false, r_obmat, nullptr);
}
else {
BKE_object_to_mat4(ob, r_obmat);
@@ -3644,17 +3690,9 @@ void BKE_object_where_is_calc_ex(
void BKE_object_where_is_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
float ctime = DEG_get_ctime(depsgraph);
- object_where_is_calc_ex(depsgraph, scene, ob, ctime, NULL, NULL);
+ object_where_is_calc_ex(depsgraph, scene, ob, ctime, nullptr, nullptr);
}
-/**
- * For calculation of the inverse parent transform, only used for editor.
- *
- * It assumes the object parent is already in the depsgraph.
- * Otherwise, after changing ob->parent you need to call:
- * - #DEG_relations_tag_update(bmain);
- * - #BKE_scene_graph_update_tagged(depsgraph, bmain);
- */
void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *workob)
{
BKE_object_workob_clear(workob);
@@ -3664,7 +3702,7 @@ void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *o
unit_m4(workob->constinv);
/* Since this is used while calculating parenting,
- * at this moment ob_eval->parent is still NULL. */
+ * at this moment ob_eval->parent is still nullptr. */
workob->parent = DEG_get_evaluated_object(depsgraph, ob->parent);
workob->trackflag = ob->trackflag;
@@ -3686,16 +3724,6 @@ void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *o
BKE_object_where_is_calc(depsgraph, scene, workob);
}
-/**
- * Applies the global transformation \a mat to the \a ob using a relative parent space if
- * supplied.
- *
- * \param mat: the global transformation mat that the object should be set object to.
- * \param parent: the parent space in which this object will be set relative to
- * (should probably always be parent_eval).
- * \param use_compat: true to ensure that rotations are set using the
- * min difference between the old and new orientation.
- */
void BKE_object_apply_mat4_ex(Object *ob,
const float mat[4][4],
Object *parent,
@@ -3706,7 +3734,7 @@ void BKE_object_apply_mat4_ex(Object *ob,
float rot[3][3];
- if (parent != NULL) {
+ if (parent != nullptr) {
float rmat[4][4], diff_mat[4][4], imat[4][4], parent_mat[4][4];
BKE_object_get_parent_matrix(ob, parent, parent_mat);
@@ -3739,15 +3767,12 @@ void BKE_object_apply_mat4_ex(Object *ob,
/* BKE_object_mat3_to_rot handles delta rotations */
}
-/**
- * XXX: should be removed after COW operators port to use BKE_object_apply_mat4_ex directly.
- */
void BKE_object_apply_mat4(Object *ob,
const float mat[4][4],
const bool use_compat,
const bool use_parent)
{
- BKE_object_apply_mat4_ex(ob, mat, use_parent ? ob->parent : NULL, ob->parentinv, use_compat);
+ BKE_object_apply_mat4_ex(ob, mat, use_parent ? ob->parent : nullptr, ob->parentinv, use_compat);
}
/** \} */
@@ -3756,11 +3781,11 @@ void BKE_object_apply_mat4(Object *ob,
/** \name Object Bounding Box API
* \{ */
-BoundBox *BKE_boundbox_alloc_unit(void)
+BoundBox *BKE_boundbox_alloc_unit()
{
const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
- BoundBox *bb = MEM_callocN(sizeof(BoundBox), "OB-BoundBox");
+ BoundBox *bb = MEM_cnew<BoundBox>("OB-BoundBox");
BKE_boundbox_init_from_minmax(bb, min, max);
return bb;
@@ -3807,7 +3832,7 @@ void BKE_boundbox_minmax(const BoundBox *bb,
BoundBox *BKE_object_boundbox_get(Object *ob)
{
- BoundBox *bb = NULL;
+ BoundBox *bb = nullptr;
switch (ob->type) {
case OB_MESH:
@@ -3845,9 +3870,6 @@ BoundBox *BKE_object_boundbox_get(Object *ob)
return bb;
}
-/**
- * Use this to temporally disable/enable bound-box.
- */
void BKE_object_boundbox_flag(Object *ob, int flag, const bool set)
{
BoundBox *bb = BKE_object_boundbox_get(ob);
@@ -3861,7 +3883,7 @@ void BKE_object_boundbox_flag(Object *ob, int flag, const bool set)
}
}
-void BKE_object_boundbox_calc_from_mesh(struct Object *ob, const struct Mesh *me_eval)
+void BKE_object_boundbox_calc_from_mesh(Object *ob, const Mesh *me_eval)
{
float min[3], max[3];
@@ -3872,13 +3894,48 @@ void BKE_object_boundbox_calc_from_mesh(struct Object *ob, const struct Mesh *me
zero_v3(max);
}
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "DM-BoundBox");
+ if (ob->runtime.bb == nullptr) {
+ ob->runtime.bb = MEM_cnew<BoundBox>("DM-BoundBox");
+ }
+
+ BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
+
+ ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
+}
+
+bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob)
+{
+ blender::float3 min, max;
+ INIT_MINMAX(min, max);
+
+ if (ob->runtime.geometry_set_eval) {
+ if (!ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max)) {
+ zero_v3(min);
+ zero_v3(max);
+ }
+ }
+ else if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob)) {
+ if (!BKE_mesh_wrapper_minmax(mesh_eval, min, max)) {
+ zero_v3(min);
+ zero_v3(max);
+ }
+ }
+ else if (ob->runtime.curve_cache) {
+ BKE_displist_minmax(&ob->runtime.curve_cache->disp, min, max);
+ }
+ else {
+ return false;
+ }
+
+ if (ob->runtime.bb == nullptr) {
+ ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
+
+ return true;
}
/** \} */
@@ -3906,14 +3963,6 @@ void BKE_object_dimensions_get(Object *ob, float r_vec[3])
}
}
-/**
- * The original scale and object matrix can be passed in so any difference
- * of the objects matrix and the final matrix can be accounted for,
- * typically this caused by parenting, constraints or delta-scale.
- *
- * Re-using these values from the object causes a feedback loop
- * when multiple values are modified at once in some situations. see: T69536.
- */
void BKE_object_dimensions_set_ex(Object *ob,
const float value[3],
int axis_mask,
@@ -3931,7 +3980,7 @@ void BKE_object_dimensions_set_ex(Object *ob,
for (int i = 0; i < 3; i++) {
if (((1 << i) & axis_mask) == 0) {
- if (ob_scale_orig != NULL) {
+ if (ob_scale_orig != nullptr) {
const float scale_delta = len_v3(ob_obmat_orig[i]) / ob_scale_orig[i];
if (isfinite(scale_delta)) {
len[i] *= scale_delta;
@@ -3949,7 +3998,7 @@ void BKE_object_dimensions_set_ex(Object *ob,
void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
{
- BKE_object_dimensions_set_ex(ob, value, axis_mask, NULL, NULL);
+ BKE_object_dimensions_set_ex(ob, value, axis_mask, nullptr, nullptr);
}
void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool use_hidden)
@@ -3979,7 +4028,7 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
break;
}
case OB_LATTICE: {
- Lattice *lt = ob->data;
+ Lattice *lt = (Lattice *)ob->data;
BPoint *bp = lt->def;
int u, v, w;
@@ -4001,7 +4050,7 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
case OB_MBALL: {
float ob_min[3], ob_max[3];
- changed = BKE_mball_minmax_ex(ob->data, ob_min, ob_max, ob->obmat, 0);
+ changed = BKE_mball_minmax_ex((const MetaBall *)ob->data, ob_min, ob_max, ob->obmat, 0);
if (changed) {
minmax_v3v3_v3(r_min, r_max, ob_min);
minmax_v3v3_v3(r_min, r_max, ob_max);
@@ -4055,8 +4104,7 @@ void BKE_object_empty_draw_type_set(Object *ob, const int value)
if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
if (!ob->iuser) {
- ob->iuser = MEM_callocN(sizeof(ImageUser), "image user");
- ob->iuser->ok = 1;
+ ob->iuser = MEM_cnew<ImageUser>("image user");
ob->iuser->flag |= IMA_ANIM_ALWAYS;
ob->iuser->frames = 100;
ob->iuser->sfra = 1;
@@ -4131,13 +4179,12 @@ bool BKE_object_minmax_dupli(Depsgraph *depsgraph,
const bool use_hidden)
{
bool ok = false;
- if ((ob->transflag & OB_DUPLI) == 0 && ob->runtime.geometry_set_eval == NULL) {
+ if ((ob->transflag & OB_DUPLI) == 0 && ob->runtime.geometry_set_eval == nullptr) {
return ok;
}
- DupliObject *dob;
ListBase *lb = object_duplilist(depsgraph, scene, ob);
- for (dob = lb->first; dob; dob = dob->next) {
+ LISTBASE_FOREACH (DupliObject *, dob, lb) {
if ((use_hidden == false) && (dob->no_draw != 0)) {
/* pass */
}
@@ -4173,7 +4220,7 @@ static void foreach_display_point_gpencil_stroke_fn(bGPDlayer *UNUSED(layer),
bGPDstroke *stroke,
void *thunk)
{
- struct GPencilStrokePointIterData *iter_data = thunk;
+ GPencilStrokePointIterData *iter_data = (GPencilStrokePointIterData *)thunk;
{
bGPDspoint *pt;
int i;
@@ -4194,7 +4241,7 @@ void BKE_object_foreach_display_point(Object *ob,
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
float co[3];
- if (mesh_eval != NULL) {
+ if (mesh_eval != nullptr) {
const MVert *mv = mesh_eval->mvert;
const int totvert = mesh_eval->totvert;
for (int i = 0; i < totvert; i++, mv++) {
@@ -4203,16 +4250,16 @@ void BKE_object_foreach_display_point(Object *ob,
}
}
else if (ob->type == OB_GPENCIL) {
- struct GPencilStrokePointIterData iter_data = {
- .obmat = obmat, .point_func_cb = func_cb, .user_data = user_data};
+ GPencilStrokePointIterData iter_data{};
+ iter_data.obmat = obmat;
+ iter_data.point_func_cb = func_cb;
+ iter_data.user_data = user_data;
BKE_gpencil_visible_stroke_iter(
- ob->data, NULL, foreach_display_point_gpencil_stroke_fn, &iter_data);
+ (bGPdata *)ob->data, nullptr, foreach_display_point_gpencil_stroke_fn, &iter_data);
}
else if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) {
- DispList *dl;
-
- for (dl = ob->runtime.curve_cache->disp.first; dl; dl = dl->next) {
+ LISTBASE_FOREACH (DispList *, dl, &ob->runtime.curve_cache->disp) {
const float *v3 = dl->verts;
int totvert = dl->nr;
int i;
@@ -4240,35 +4287,31 @@ void BKE_scene_foreach_display_point(Depsgraph *depsgraph,
DEG_OBJECT_ITER_END;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Transform Channels (Backup/Restore)
+ * \{ */
+
/**
- * Struct members from DNA_object_types.h
+ * See struct members from #Object in DNA_object_types.h
*/
-typedef struct ObTfmBack {
+struct ObTfmBack {
float loc[3], dloc[3];
- /** scale and delta scale. */
float scale[3], dscale[3];
- /** euler rotation. */
float rot[3], drot[3];
- /** quaternion rotation. */
float quat[4], dquat[4];
- /** axis angle rotation - axis part. */
float rotAxis[3], drotAxis[3];
- /** axis angle rotation - angle part. */
float rotAngle, drotAngle;
- /** final worldspace matrix with constraints & animsys applied. */
float obmat[4][4];
- /** inverse result of parent, so that object doesn't 'stick' to parent. */
float parentinv[4][4];
- /** inverse result of constraints. doesn't include effect of parent or object local transform.
- */
float constinv[4][4];
- /** inverse matrix of 'obmat' for during render, temporally: ipokeys of transform. */
float imat[4][4];
-} ObTfmBack;
+};
void *BKE_object_tfm_backup(Object *ob)
{
- ObTfmBack *obtfm = MEM_mallocN(sizeof(ObTfmBack), "ObTfmBack");
+ ObTfmBack *obtfm = (ObTfmBack *)MEM_mallocN(sizeof(ObTfmBack), "ObTfmBack");
copy_v3_v3(obtfm->loc, ob->loc);
copy_v3_v3(obtfm->dloc, ob->dloc);
copy_v3_v3(obtfm->scale, ob->scale);
@@ -4310,17 +4353,11 @@ void BKE_object_tfm_restore(Object *ob, void *obtfm_pt)
copy_m4_m4(ob->imat, obtfm->imat);
}
-bool BKE_object_parent_loop_check(const Object *par, const Object *ob)
-{
- /* test if 'ob' is a parent somewhere in par's parents */
- if (par == NULL) {
- return false;
- }
- if (ob == par) {
- return true;
- }
- return BKE_object_parent_loop_check(par->parent, ob);
-}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Evaluation/Update API
+ * \{ */
static void object_handle_update_proxy(Depsgraph *depsgraph,
Scene *scene,
@@ -4328,7 +4365,7 @@ static void object_handle_update_proxy(Depsgraph *depsgraph,
const bool do_proxy_update)
{
/* The case when this is a collection proxy, object_update is called in collection.c */
- if (object->proxy == NULL) {
+ if (object->proxy == nullptr) {
return;
}
/* set pointer in library proxy target, for copying, but restore it */
@@ -4336,7 +4373,7 @@ static void object_handle_update_proxy(Depsgraph *depsgraph,
// printf("set proxy pointer for later collection stuff %s\n", ob->id.name);
/* the no-group proxy case, we call update */
- if (object->proxy_group == NULL) {
+ if (object->proxy_group == nullptr) {
if (do_proxy_update) {
// printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name);
BKE_object_handle_update(depsgraph, scene, object->proxy);
@@ -4344,35 +4381,23 @@ static void object_handle_update_proxy(Depsgraph *depsgraph,
}
}
-/**
- * Proxy rule:
- * - lib_object->proxy_from == the one we borrow from, only set temporal and cleared here.
- * - local_object->proxy == pointer to library object, saved in files and read.
- *
- * Function below is polluted with proxy exceptions, cleanup will follow!
- *
- * The main object update call, for object matrix, constraints, keys and displist (modifiers)
- * requires flags to be set!
- *
- * Ideally we shouldn't have to pass the rigid body world,
- * but need bigger restructuring to avoid id.
- */
void BKE_object_handle_update_ex(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
RigidBodyWorld *rbw,
const bool do_proxy_update)
{
- const ID *object_data = ob->data;
+ const ID *object_data = (ID *)ob->data;
const bool recalc_object = (ob->id.recalc & ID_RECALC_ALL) != 0;
- const bool recalc_data = (object_data != NULL) ? ((object_data->recalc & ID_RECALC_ALL) != 0) :
- 0;
+ const bool recalc_data = (object_data != nullptr) ?
+ ((object_data->recalc & ID_RECALC_ALL) != 0) :
+ false;
if (!recalc_object && !recalc_data) {
object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
return;
}
/* Speed optimization for animation lookups. */
- if (ob->pose != NULL) {
+ if (ob->pose != nullptr) {
BKE_pose_channels_hash_ensure(ob->pose);
if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
BKE_pose_update_constraint_flags(ob->pose);
@@ -4384,9 +4409,9 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph,
* with poses we do it ahead of BKE_object_where_is_calc to ensure animation
* is evaluated on the rebuilt pose, otherwise we get incorrect poses
* on file load */
- if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
+ if (ob->pose == nullptr || (ob->pose->flag & POSE_RECALC)) {
/* No need to pass bmain here, we assume we do not need to rebuild DEG from here... */
- BKE_pose_rebuild(NULL, ob, ob->data, true);
+ BKE_pose_rebuild(nullptr, ob, (bArmature *)ob->data, true);
}
}
}
@@ -4399,7 +4424,7 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph,
}
/* Handle proxy copy for target. */
if (!BKE_object_eval_proxy_copy(depsgraph, ob)) {
- BKE_object_where_is_calc_ex(depsgraph, scene, rbw, ob, NULL);
+ BKE_object_where_is_calc_ex(depsgraph, scene, rbw, ob, nullptr);
}
}
@@ -4410,29 +4435,22 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph,
object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
}
-/**
- * \warning "scene" here may not be the scene object actually resides in.
- * When dealing with background-sets, "scene" is actually the active scene.
- * e.g. "scene" <-- set 1 <-- set 2 ("ob" lives here) <-- set 3 <-- ... <-- set n
- * rigid bodies depend on their world so use #BKE_object_handle_update_ex()
- * to also pass along the current rigid body world.
- */
void BKE_object_handle_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- BKE_object_handle_update_ex(depsgraph, scene, ob, NULL, true);
+ BKE_object_handle_update_ex(depsgraph, scene, ob, nullptr, true);
}
void BKE_object_sculpt_data_create(Object *ob)
{
- BLI_assert((ob->sculpt == NULL) && (ob->mode & OB_MODE_ALL_SCULPT));
- ob->sculpt = MEM_callocN(sizeof(SculptSession), __func__);
- ob->sculpt->mode_type = ob->mode;
+ BLI_assert((ob->sculpt == nullptr) && (ob->mode & OB_MODE_ALL_SCULPT));
+ ob->sculpt = MEM_cnew<SculptSession>(__func__);
+ ob->sculpt->mode_type = (eObjectMode)ob->mode;
}
-bool BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc, float **r_size)
+bool BKE_object_obdata_texspace_get(Object *ob, char **r_texflag, float **r_loc, float **r_size)
{
- if (ob->data == NULL) {
+ if (ob->data == nullptr) {
return false;
}
@@ -4442,7 +4460,7 @@ bool BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc
break;
}
case ID_CU: {
- Curve *cu = ob->data;
+ Curve *cu = (Curve *)ob->data;
BKE_curve_texspace_ensure(cu);
if (r_texflag) {
*r_texflag = &cu->texflag;
@@ -4456,7 +4474,7 @@ bool BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc
break;
}
case ID_MB: {
- MetaBall *mb = ob->data;
+ MetaBall *mb = (MetaBall *)ob->data;
if (r_texflag) {
*r_texflag = &mb->texflag;
}
@@ -4474,25 +4492,52 @@ bool BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc
return true;
}
-/** Get evaluated mesh for given object. */
-Mesh *BKE_object_get_evaluated_mesh(const Object *object)
+Mesh *BKE_object_get_evaluated_mesh_no_subsurf(const Object *object)
{
+ /* First attempt to retrieve the evaluated mesh from the evaluated geometry set. Most
+ * object types either store it there or add a reference to it if it's owned elsewhere. */
+ GeometrySet *geometry_set_eval = object->runtime.geometry_set_eval;
+ if (geometry_set_eval) {
+ /* Some areas expect to be able to modify the evaluated mesh in limited ways. Theoretically
+ * this should be avoided, or at least protected with a lock, so a const mesh could be returned
+ * from this function. We use a const_cast instead of #get_mesh_for_write, because that might
+ * result in a copy of the mesh when it is shared. */
+ Mesh *mesh = const_cast<Mesh *>(geometry_set_eval->get_mesh_for_read());
+ if (mesh) {
+ return mesh;
+ }
+ }
+
+ /* Some object types do not yet add the evaluated mesh to an evaluated geometry set, if they do
+ * not support evaluating to multiple data types. Eventually this should be removed, when all
+ * object types use #geometry_set_eval. */
ID *data_eval = object->runtime.data_eval;
- return (data_eval && GS(data_eval->name) == ID_ME) ? (Mesh *)data_eval : NULL;
+ if (data_eval && GS(data_eval->name) == ID_ME) {
+ return reinterpret_cast<Mesh *>(data_eval);
+ }
+
+ return nullptr;
+}
+
+Mesh *BKE_object_get_evaluated_mesh(const Object *object)
+{
+ Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(object);
+ if (!mesh) {
+ return nullptr;
+ }
+
+ if (object->data && GS(((const ID *)object->data)->name) == ID_ME) {
+ mesh = BKE_mesh_wrapper_ensure_subdivision(object, mesh);
+ }
+
+ return mesh;
}
-/**
- * Get mesh which is not affected by modifiers:
- * - For original objects it will be same as `object->data`, and it is a mesh
- * which is in the corresponding #Main.
- * - For copied-on-write objects it will give pointer to a copied-on-write
- * mesh which corresponds to original object's mesh.
- */
Mesh *BKE_object_get_pre_modified_mesh(const Object *object)
{
- if (object->type == OB_MESH && object->runtime.data_orig != NULL) {
+ if (object->type == OB_MESH && object->runtime.data_orig != nullptr) {
BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE);
- BLI_assert(object->id.orig_id != NULL);
+ BLI_assert(object->id.orig_id != nullptr);
BLI_assert(object->runtime.data_orig->orig_id == ((Object *)object->id.orig_id)->data);
Mesh *result = (Mesh *)object->runtime.data_orig;
BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
@@ -4500,37 +4545,58 @@ Mesh *BKE_object_get_pre_modified_mesh(const Object *object)
return result;
}
BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
- return object->data;
+ return (Mesh *)object->data;
}
-/**
- * Get a mesh which corresponds to the very original mesh from #Main.
- * - For original objects it will be object->data.
- * - For evaluated objects it will be same mesh as corresponding original
- * object uses as data.
- */
Mesh *BKE_object_get_original_mesh(const Object *object)
{
- Mesh *result = NULL;
- if (object->id.orig_id == NULL) {
+ Mesh *result = nullptr;
+ if (object->id.orig_id == nullptr) {
BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
- result = object->data;
+ result = (Mesh *)object->data;
}
else {
BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
- result = ((Object *)object->id.orig_id)->data;
+ result = (Mesh *)((Object *)object->id.orig_id)->data;
}
- BLI_assert(result != NULL);
+ BLI_assert(result != nullptr);
BLI_assert((result->id.tag & (LIB_TAG_COPIED_ON_WRITE | LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT)) ==
0);
return result;
}
+Mesh *BKE_object_get_editmesh_eval_final(const Object *object)
+{
+ BLI_assert(!DEG_is_original_id(&object->id));
+ BLI_assert(object->type == OB_MESH);
+
+ const Mesh *mesh = static_cast<const Mesh *>(object->data);
+ if (mesh->edit_mesh == nullptr) {
+ /* Happens when requesting material of evaluated 3d font object: the evaluated object get
+ * converted to mesh, and it does not have edit mesh. */
+ return nullptr;
+ }
+
+ return reinterpret_cast<Mesh *>(object->runtime.data_eval);
+}
+
+Mesh *BKE_object_get_editmesh_eval_cage(const Object *object)
+{
+ BLI_assert(!DEG_is_original_id(&object->id));
+ BLI_assert(object->type == OB_MESH);
+
+ const Mesh *mesh = static_cast<const Mesh *>(object->data);
+ BLI_assert(mesh->edit_mesh != nullptr);
+ UNUSED_VARS_NDEBUG(mesh);
+
+ return object->runtime.editmesh_eval_cage;
+}
+
Lattice *BKE_object_get_lattice(const Object *object)
{
- ID *data = object->data;
- if (data == NULL || GS(data->name) != ID_LT) {
- return NULL;
+ ID *data = (ID *)object->data;
+ if (data == nullptr || GS(data->name) != ID_LT) {
+ return nullptr;
}
Lattice *lt = (Lattice *)data;
@@ -4545,8 +4611,8 @@ Lattice *BKE_object_get_evaluated_lattice(const Object *object)
{
ID *data_eval = object->runtime.data_eval;
- if (data_eval == NULL || GS(data_eval->name) != ID_LT) {
- return NULL;
+ if (data_eval == nullptr || GS(data_eval->name) != ID_LT) {
+ return nullptr;
}
Lattice *lt_eval = (Lattice *)data_eval;
@@ -4557,9 +4623,15 @@ Lattice *BKE_object_get_evaluated_lattice(const Object *object)
return lt_eval;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Point Cache
+ * \{ */
+
static int pc_cmp(const void *a, const void *b)
{
- const LinkData *ad = a, *bd = b;
+ const LinkData *ad = (const LinkData *)a, *bd = (const LinkData *)b;
if (POINTER_AS_INT(ad->data) > POINTER_AS_INT(bd->data)) {
return 1;
}
@@ -4573,12 +4645,12 @@ static int pc_cmp(const void *a, const void *b)
* disk. */
int BKE_object_insert_ptcache(Object *ob)
{
- LinkData *link = NULL;
+ LinkData *link = nullptr;
int i = 0;
BLI_listbase_sort(&ob->pc_ids, pc_cmp);
- for (link = ob->pc_ids.first, i = 0; link; link = link->next, i++) {
+ for (link = (LinkData *)ob->pc_ids.first, i = 0; link; link = link->next, i++) {
int index = POINTER_AS_INT(link->data);
if (i < index) {
@@ -4586,7 +4658,7 @@ int BKE_object_insert_ptcache(Object *ob)
}
}
- link = MEM_callocN(sizeof(LinkData), "PCLink");
+ link = MEM_cnew<LinkData>("PCLink");
link->data = POINTER_FROM_INT(i);
BLI_addtail(&ob->pc_ids, link);
@@ -4597,11 +4669,11 @@ static int pc_findindex(ListBase *listbase, int index)
{
int number = 0;
- if (listbase == NULL) {
+ if (listbase == nullptr) {
return -1;
}
- LinkData *link = listbase->first;
+ LinkData *link = (LinkData *)listbase->first;
while (link) {
if (POINTER_AS_INT(link->data) == index) {
return number;
@@ -4617,10 +4689,12 @@ static int pc_findindex(ListBase *listbase, int index)
void BKE_object_delete_ptcache(Object *ob, int index)
{
int list_index = pc_findindex(&ob->pc_ids, index);
- LinkData *link = BLI_findlink(&ob->pc_ids, list_index);
+ LinkData *link = (LinkData *)BLI_findlink(&ob->pc_ids, list_index);
BLI_freelinkN(&ob->pc_ids, link);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Object Data Shape Key Insert
* \{ */
@@ -4628,12 +4702,12 @@ void BKE_object_delete_ptcache(Object *ob, int index)
/** Mesh */
static KeyBlock *insert_meshkey(Main *bmain, Object *ob, const char *name, const bool from_mix)
{
- Mesh *me = ob->data;
+ Mesh *me = (Mesh *)ob->data;
Key *key = me->key;
KeyBlock *kb;
int newkey = 0;
- if (key == NULL) {
+ if (key == nullptr) {
key = me->key = BKE_key_add(bmain, (ID *)me);
key->type = KEY_RELATIVE;
newkey = 1;
@@ -4660,12 +4734,12 @@ static KeyBlock *insert_meshkey(Main *bmain, Object *ob, const char *name, const
/** Lattice */
static KeyBlock *insert_lattkey(Main *bmain, Object *ob, const char *name, const bool from_mix)
{
- Lattice *lt = ob->data;
+ Lattice *lt = (Lattice *)ob->data;
Key *key = lt->key;
KeyBlock *kb;
int newkey = 0;
- if (key == NULL) {
+ if (key == nullptr) {
key = lt->key = BKE_key_add(bmain, (ID *)lt);
key->type = KEY_RELATIVE;
newkey = 1;
@@ -4698,13 +4772,13 @@ static KeyBlock *insert_lattkey(Main *bmain, Object *ob, const char *name, const
/** Curve */
static KeyBlock *insert_curvekey(Main *bmain, Object *ob, const char *name, const bool from_mix)
{
- Curve *cu = ob->data;
+ Curve *cu = (Curve *)ob->data;
Key *key = cu->key;
KeyBlock *kb;
ListBase *lb = BKE_curve_nurbs_get(cu);
int newkey = 0;
- if (key == NULL) {
+ if (key == nullptr) {
key = cu->key = BKE_key_add(bmain, (ID *)cu);
key->type = KEY_RELATIVE;
newkey = 1;
@@ -4747,7 +4821,7 @@ KeyBlock *BKE_object_shapekey_insert(Main *bmain,
const char *name,
const bool from_mix)
{
- KeyBlock *key = NULL;
+ KeyBlock *key = nullptr;
switch (ob->type) {
case OB_MESH:
@@ -4765,7 +4839,7 @@ KeyBlock *BKE_object_shapekey_insert(Main *bmain,
}
/* Set the first active when none is set when called from RNA. */
- if (key != NULL) {
+ if (key != nullptr) {
if (ob->shapenr <= 0) {
ob->shapenr = 1;
}
@@ -4779,12 +4853,12 @@ bool BKE_object_shapekey_free(Main *bmain, Object *ob)
Key **key_p, *key;
key_p = BKE_key_from_object_p(ob);
- if (ELEM(NULL, key_p, *key_p)) {
+ if (ELEM(nullptr, key_p, *key_p)) {
return false;
}
key = *key_p;
- *key_p = NULL;
+ *key_p = nullptr;
BKE_id_free_us(bmain, key);
@@ -4793,18 +4867,17 @@ bool BKE_object_shapekey_free(Main *bmain, Object *ob)
bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
{
- KeyBlock *rkb;
Key *key = BKE_key_from_object(ob);
short kb_index;
- if (key == NULL) {
+ if (key == nullptr) {
return false;
}
kb_index = BLI_findindex(&key->block, kb);
BLI_assert(kb_index != -1);
- for (rkb = key->block.first; rkb; rkb = rkb->next) {
+ LISTBASE_FOREACH (KeyBlock *, rkb, &key->block) {
if (rkb->relative == kb_index) {
/* remap to the 'Basis' */
rkb->relative = 0;
@@ -4818,20 +4891,21 @@ bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
BLI_remlink(&key->block, kb);
key->totkey--;
if (key->refkey == kb) {
- key->refkey = key->block.first;
+ key->refkey = (KeyBlock *)key->block.first;
if (key->refkey) {
/* apply new basis key on original data */
switch (ob->type) {
case OB_MESH:
- BKE_keyblock_convert_to_mesh(key->refkey, ob->data);
+ BKE_keyblock_convert_to_mesh(key->refkey, (Mesh *)ob->data);
break;
case OB_CURVE:
case OB_SURF:
- BKE_keyblock_convert_to_curve(key->refkey, ob->data, BKE_curve_nurbs_get(ob->data));
+ BKE_keyblock_convert_to_curve(
+ key->refkey, (Curve *)ob->data, BKE_curve_nurbs_get((Curve *)ob->data));
break;
case OB_LATTICE:
- BKE_keyblock_convert_to_lattice(key->refkey, ob->data);
+ BKE_keyblock_convert_to_lattice(key->refkey, (Lattice *)ob->data);
break;
}
}
@@ -4859,6 +4933,22 @@ bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Object Query API
+ * \{ */
+
+bool BKE_object_parent_loop_check(const Object *par, const Object *ob)
+{
+ /* test if 'ob' is a parent somewhere in par's parents */
+ if (par == nullptr) {
+ return false;
+ }
+ if (ob == par) {
+ return true;
+ }
+ return BKE_object_parent_loop_check(par->parent, ob);
+}
+
bool BKE_object_flag_test_recursive(const Object *ob, short flag)
{
if (ob->flag & flag) {
@@ -4881,10 +4971,6 @@ bool BKE_object_is_child_recursive(const Object *ob_parent, const Object *ob_chi
return false;
}
-/**
- * Most important if this is modified it should _always_ return true, in certain
- * cases false positives are hard to avoid (shape keys for example).
- */
int BKE_object_is_modified(Scene *scene, Object *ob)
{
/* Always test on original object since evaluated object may no longer
@@ -4918,21 +5004,6 @@ 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 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 high.
- *
- * \note This function does not consider physics systems.
- */
bool BKE_object_moves_in_time(const Object *object, bool recurse_parent)
{
/* If object has any sort of animation data assume it is moving. */
@@ -4942,7 +5013,7 @@ bool BKE_object_moves_in_time(const Object *object, bool recurse_parent)
if (!BLI_listbase_is_empty(&object->constraints)) {
return true;
}
- if (recurse_parent && object->parent != NULL) {
+ if (recurse_parent && object->parent != nullptr) {
return BKE_object_moves_in_time(object->parent, true);
}
return false;
@@ -4955,7 +5026,7 @@ static bool object_moves_in_time(const Object *object)
static bool object_deforms_in_time(Object *object)
{
- if (BKE_key_from_object(object) != NULL) {
+ if (BKE_key_from_object(object) != nullptr) {
return true;
}
if (!BLI_listbase_is_empty(&object->modifiers)) {
@@ -4972,19 +5043,19 @@ static bool constructive_modifier_is_deform_modified(Object *ob, ModifierData *m
if (md->type == eModifierType_Array) {
ArrayModifierData *amd = (ArrayModifierData *)md;
/* TODO(sergey): Check if curve is deformed. */
- return (amd->start_cap != NULL && object_moves_in_time(amd->start_cap)) ||
- (amd->end_cap != NULL && object_moves_in_time(amd->end_cap)) ||
- (amd->curve_ob != NULL && object_moves_in_time(amd->curve_ob)) ||
- (amd->offset_ob != NULL && object_moves_in_time(amd->offset_ob));
+ return (amd->start_cap != nullptr && object_moves_in_time(amd->start_cap)) ||
+ (amd->end_cap != nullptr && object_moves_in_time(amd->end_cap)) ||
+ (amd->curve_ob != nullptr && object_moves_in_time(amd->curve_ob)) ||
+ (amd->offset_ob != nullptr && object_moves_in_time(amd->offset_ob));
}
if (md->type == eModifierType_Mirror) {
MirrorModifierData *mmd = (MirrorModifierData *)md;
- return mmd->mirror_ob != NULL &&
+ return mmd->mirror_ob != nullptr &&
(object_moves_in_time(mmd->mirror_ob) || object_moves_in_time(ob));
}
if (md->type == eModifierType_Screw) {
ScrewModifierData *smd = (ScrewModifierData *)md;
- return smd->ob_axis != NULL && object_moves_in_time(smd->ob_axis);
+ return smd->ob_axis != nullptr && object_moves_in_time(smd->ob_axis);
}
if (md->type == eModifierType_MeshSequenceCache) {
/* NOTE: Not ideal because it's unknown whether topology changes or not.
@@ -5010,17 +5081,16 @@ static bool modifiers_has_animation_check(const Object *ob)
* would be nicer to solve this as a part of new dependency graph
* work, so we avoid conflicts and so.
*/
- if (ob->adt != NULL) {
+ if (ob->adt != nullptr) {
AnimData *adt = ob->adt;
- FCurve *fcu;
- if (adt->action != NULL) {
- for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) {
+ if (adt->action != nullptr) {
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) {
return true;
}
}
}
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) {
return true;
}
@@ -5029,11 +5099,6 @@ static bool modifiers_has_animation_check(const Object *ob)
return false;
}
-/**
- * Test if object is affected by deforming modifiers (for motion blur). again
- * most important is to avoid false positives, this is to skip computations
- * and we can still if there was actual deformation afterwards.
- */
int BKE_object_is_deform_modified(Scene *scene, Object *ob)
{
/* Always test on original object since evaluated object may no longer
@@ -5051,7 +5116,7 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob)
if (ob->type == OB_CURVE) {
Curve *cu = (Curve *)ob->data;
- if (cu->taperobj != NULL && object_deforms_in_time(cu->taperobj)) {
+ if (cu->taperobj != nullptr && object_deforms_in_time(cu->taperobj)) {
flag |= eModifierMode_Realtime | eModifierMode_Render;
}
}
@@ -5060,7 +5125,7 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob)
for (md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
md = md->next) {
- const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info((const ModifierType)md->type);
bool can_deform = mti->type == eModifierTypeType_OnlyDeform || is_modifier_animated;
if (!can_deform) {
@@ -5083,11 +5148,10 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob)
return flag;
}
-/** Return the number of scenes using (instantiating) that object in their collections. */
int BKE_object_scenes_users_get(Main *bmain, Object *ob)
{
int num_scenes = 0;
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
if (BKE_collection_has_object_recursive(scene->master_collection, ob)) {
num_scenes++;
}
@@ -5097,12 +5161,12 @@ int BKE_object_scenes_users_get(Main *bmain, Object *ob)
MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default)
{
- MovieClip *clip = use_default ? scene->clip : NULL;
- bConstraint *con = ob->constraints.first, *scon = NULL;
+ MovieClip *clip = use_default ? scene->clip : nullptr;
+ bConstraint *con = (bConstraint *)ob->constraints.first, *scon = nullptr;
while (con) {
if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) {
- if (scon == NULL || (scon->flag & CONSTRAINT_OFF)) {
+ if (scon == nullptr || (scon->flag & CONSTRAINT_OFF)) {
scon = con;
}
}
@@ -5111,7 +5175,7 @@ MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default)
}
if (scon) {
- bCameraSolverConstraint *solver = scon->data;
+ bCameraSolverConstraint *solver = (bCameraSolverConstraint *)scon->data;
if ((solver->flag & CAMERASOLVER_ACTIVECLIP) == 0) {
clip = solver->clip;
}
@@ -5123,32 +5187,46 @@ MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default)
return clip;
}
+bool BKE_object_supports_material_slots(struct Object *ob)
+{
+ return ELEM(ob->type,
+ OB_MESH,
+ OB_CURVE,
+ OB_SURF,
+ OB_FONT,
+ OB_MBALL,
+ OB_HAIR,
+ OB_POINTCLOUD,
+ OB_VOLUME,
+ OB_GPENCIL);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Runtime
+ * \{ */
+
void BKE_object_runtime_reset(Object *object)
{
memset(&object->runtime, 0, sizeof(object->runtime));
}
-/**
- * Reset all pointers which we don't want to be shared when copying the object.
- */
void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag))
{
Object_Runtime *runtime = &object->runtime;
- runtime->data_eval = NULL;
- runtime->gpd_eval = NULL;
- runtime->mesh_deform_eval = NULL;
- runtime->curve_cache = NULL;
- runtime->object_as_temp_mesh = NULL;
- runtime->object_as_temp_curve = NULL;
- runtime->geometry_set_eval = NULL;
+ runtime->data_eval = nullptr;
+ runtime->gpd_eval = nullptr;
+ runtime->mesh_deform_eval = nullptr;
+ runtime->curve_cache = nullptr;
+ runtime->object_as_temp_mesh = nullptr;
+ runtime->object_as_temp_curve = nullptr;
+ runtime->geometry_set_eval = nullptr;
+
+ runtime->crazyspace_deform_imats = nullptr;
+ runtime->crazyspace_deform_cos = nullptr;
}
-/**
- * The function frees memory used by the runtime data, but not the runtime field itself.
- *
- * All runtime data is cleared to ensure it's not used again,
- * in keeping with other `_free_data(..)` functions.
- */
void BKE_object_runtime_free_data(Object *object)
{
/* Currently this is all that's needed. */
@@ -5157,12 +5235,18 @@ void BKE_object_runtime_free_data(Object *object)
BKE_object_runtime_reset(object);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Relationships
+ * \{ */
+
/**
* Find an associated armature object.
*/
static Object *obrel_armature_find(Object *ob)
{
- Object *ob_arm = NULL;
+ Object *ob_arm = nullptr;
if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) {
ob_arm = ob->parent;
@@ -5190,36 +5274,27 @@ static void obrel_list_add(LinkNode **links, Object *ob)
ob->id.tag |= LIB_TAG_DOIT;
}
-/**
- * Iterates over all objects of the given scene layer.
- * Depending on the #eObjectSet flag:
- * collect either #OB_SET_ALL, #OB_SET_VISIBLE or #OB_SET_SELECTED objects.
- * If #OB_SET_VISIBLE or#OB_SET_SELECTED are collected,
- * then also add related objects according to the given \a includeFilter.
- */
LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer,
eObjectSet objectSet,
eObRelationTypes includeFilter)
{
- LinkNode *links = NULL;
-
- Base *base;
+ LinkNode *links = nullptr;
/* Remove markers from all objects */
- for (base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
base->object->id.tag &= ~LIB_TAG_DOIT;
}
/* iterate over all selected and visible objects */
- for (base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (objectSet == OB_SET_ALL) {
/* as we get all anyways just add it */
Object *ob = base->object;
obrel_list_add(&links, ob);
}
else {
- if ((objectSet == OB_SET_SELECTED && BASE_SELECTED_EDITABLE(((View3D *)NULL), base)) ||
- (objectSet == OB_SET_VISIBLE && BASE_EDITABLE(((View3D *)NULL), base))) {
+ if ((objectSet == OB_SET_SELECTED && BASE_SELECTED_EDITABLE(((View3D *)nullptr), base)) ||
+ (objectSet == OB_SET_VISIBLE && BASE_EDITABLE(((View3D *)nullptr), base))) {
Object *ob = base->object;
if (obrel_list_test(ob)) {
@@ -5247,10 +5322,8 @@ LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer,
/* child relationship */
if (includeFilter & (OB_REL_CHILDREN | OB_REL_CHILDREN_RECURSIVE)) {
- Base *local_base;
- for (local_base = view_layer->object_bases.first; local_base;
- local_base = local_base->next) {
- if (BASE_EDITABLE(((View3D *)NULL), local_base)) {
+ LISTBASE_FOREACH (Base *, local_base, &view_layer->object_bases) {
+ if (BASE_EDITABLE(((View3D *)nullptr), local_base)) {
Object *child = local_base->object;
if (obrel_list_test(child)) {
@@ -5278,13 +5351,10 @@ LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer,
return links;
}
-/**
- * return all groups this object is a part of, caller must free.
- */
struct LinkNode *BKE_object_groups(Main *bmain, Scene *scene, Object *ob)
{
- LinkNode *collection_linknode = NULL;
- Collection *collection = NULL;
+ LinkNode *collection_linknode = nullptr;
+ Collection *collection = nullptr;
while ((collection = BKE_collection_object_find(bmain, scene, collection, ob))) {
BLI_linklist_prepend(&collection_linknode, collection);
}
@@ -5294,41 +5364,38 @@ struct LinkNode *BKE_object_groups(Main *bmain, Scene *scene, Object *ob)
void BKE_object_groups_clear(Main *bmain, Scene *scene, Object *ob)
{
- Collection *collection = NULL;
+ Collection *collection = nullptr;
while ((collection = BKE_collection_object_find(bmain, scene, collection, ob))) {
BKE_collection_object_remove(bmain, collection, ob, false);
DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE);
}
}
-/**
- * Return a KDTree_3d from the deformed object (in worldspace)
- *
- * \note Only mesh objects currently support deforming, others are TODO.
- *
- * \param ob:
- * \param r_tot:
- * \return The kdtree or NULL if it can't be created.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object KD-Tree
+ * \{ */
+
KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
{
- KDTree_3d *tree = NULL;
+ KDTree_3d *tree = nullptr;
unsigned int tot = 0;
switch (ob->type) {
case OB_MESH: {
- Mesh *me = ob->data;
+ Mesh *me = (Mesh *)ob->data;
unsigned int i;
Mesh *me_eval = ob->runtime.mesh_deform_eval ? ob->runtime.mesh_deform_eval :
BKE_object_get_evaluated_mesh(ob);
const int *index;
- if (me_eval && (index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX))) {
+ if (me_eval && (index = (const int *)CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX))) {
MVert *mvert = me_eval->mvert;
uint totvert = me_eval->totvert;
- /* tree over-allocs in case where some verts have ORIGINDEX_NONE */
+ /* Tree over-allocates in case where some verts have #ORIGINDEX_NONE. */
tot = 0;
tree = BLI_kdtree_3d_new(totvert);
@@ -5361,7 +5428,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
case OB_CURVE:
case OB_SURF: {
/* TODO: take deformation into account */
- Curve *cu = ob->data;
+ Curve *cu = (Curve *)ob->data;
unsigned int i, a;
Nurb *nu;
@@ -5370,7 +5437,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
tree = BLI_kdtree_3d_new(tot);
i = 0;
- nu = cu->nurb.first;
+ nu = (Nurb *)cu->nurb.first;
while (nu) {
if (nu->bezt) {
BezTriple *bezt;
@@ -5404,7 +5471,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
}
case OB_LATTICE: {
/* TODO: take deformation into account */
- Lattice *lt = ob->data;
+ Lattice *lt = (Lattice *)ob->data;
BPoint *bp;
unsigned int i;
@@ -5427,6 +5494,12 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
return tree;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Modifier Utilities
+ * \{ */
+
bool BKE_object_modifier_use_time(Scene *scene,
Object *ob,
ModifierData *md,
@@ -5450,7 +5523,7 @@ bool BKE_object_modifier_use_time(Scene *scene,
/* action - check for F-Curves with paths containing 'modifiers[' */
if (adt->action) {
- for (fcu = (FCurve *)adt->action->curves.first; fcu != NULL; fcu = (FCurve *)fcu->next) {
+ for (fcu = (FCurve *)adt->action->curves.first; fcu != nullptr; fcu = (FCurve *)fcu->next) {
if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
return true;
}
@@ -5463,7 +5536,7 @@ bool BKE_object_modifier_use_time(Scene *scene,
* working, without the updating problems (T28525 T28690 T28774 T28777) caused
* by the RNA updates cache introduced in r.38649
*/
- for (fcu = (FCurve *)adt->drivers.first; fcu != NULL; fcu = (FCurve *)fcu->next) {
+ for (fcu = (FCurve *)adt->drivers.first; fcu != nullptr; fcu = (FCurve *)fcu->next) {
if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
return true;
}
@@ -5486,7 +5559,6 @@ bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
/* TODO(Aligorith): this should be handled as part of build_animdata() */
if (ob->adt) {
AnimData *adt = ob->adt;
- FCurve *fcu;
char md_name_esc[sizeof(md->name) * 2];
BLI_str_escape(md_name_esc, md->name, sizeof(md_name_esc));
@@ -5496,7 +5568,7 @@ bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
/* action - check for F-Curves with paths containing 'grease_pencil_modifiers[' */
if (adt->action) {
- for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
return true;
}
@@ -5504,7 +5576,7 @@ bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
}
/* This here allows modifier properties to get driven and still update properly */
- for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) {
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
return true;
}
@@ -5524,7 +5596,6 @@ bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx)
/* TODO(Aligorith): this should be handled as part of build_animdata() */
if (ob->adt) {
AnimData *adt = ob->adt;
- FCurve *fcu;
char fx_name_esc[sizeof(fx->name) * 2];
BLI_str_escape(fx_name_esc, fx->name, sizeof(fx_name_esc));
@@ -5534,7 +5605,7 @@ bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx)
/* action - check for F-Curves with paths containing string[' */
if (adt->action) {
- for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
return true;
}
@@ -5542,7 +5613,7 @@ bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx)
}
/* This here allows properties to get driven and still update properly */
- for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) {
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
return true;
}
@@ -5558,10 +5629,9 @@ bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx)
static void object_cacheIgnoreClear(Object *ob, int state)
{
ListBase pidlist;
- PTCacheID *pid;
- BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
+ BKE_ptcache_ids_from_object(&pidlist, ob, nullptr, 0);
- for (pid = pidlist.first; pid; pid = pid->next) {
+ LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
if (pid->cache) {
if (state) {
pid->cache->flag |= PTCACHE_IGNORE_CLEAR;
@@ -5575,10 +5645,6 @@ static void object_cacheIgnoreClear(Object *ob, int state)
BLI_freelistN(&pidlist);
}
-/**
- * \note this function should eventually be replaced by depsgraph functionality.
- * Avoid calling this in new code unless there is a very good reason for it!
- */
bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -5589,7 +5655,6 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
{
const bool flush_to_original = DEG_is_active(depsgraph);
ModifierData *md = BKE_modifiers_findby_type(ob, (ModifierType)type);
- bConstraint *con;
if (type == eModifierType_DynamicPaint) {
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
@@ -5613,36 +5678,35 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
bool no_update = false;
if (ob->parent) {
no_update |= BKE_object_modifier_update_subframe(
- depsgraph, scene, ob->parent, 0, recursion, frame, type);
+ depsgraph, scene, ob->parent, false, recursion, frame, type);
}
if (ob->track) {
no_update |= BKE_object_modifier_update_subframe(
- depsgraph, scene, ob->track, 0, recursion, frame, type);
+ depsgraph, scene, ob->track, false, recursion, frame, type);
}
/* skip subframe if object is parented
* to vertex of a dynamic paint canvas */
- if (no_update && (ob->partype == PARVERT1 || ob->partype == PARVERT3)) {
+ if (no_update && (ELEM(ob->partype, PARVERT1, PARVERT3))) {
return false;
}
/* also update constraint targets */
- for (con = ob->constraints.first; con; con = con->next) {
+ LISTBASE_FOREACH (bConstraint *, con, &ob->constraints) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
+ ListBase targets = {nullptr, nullptr};
if (cti && cti->get_constraint_targets) {
- bConstraintTarget *ct;
cti->get_constraint_targets(con, &targets);
- for (ct = targets.first; ct; ct = ct->next) {
+ LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar) {
BKE_object_modifier_update_subframe(
- depsgraph, scene, ct->tar, 0, recursion, frame, type);
+ depsgraph, scene, ct->tar, false, recursion, frame, type);
}
}
/* free temp targets */
if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
+ cti->flush_constraint_targets(con, &targets, false);
}
}
}
@@ -5669,13 +5733,13 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
/* for curve following objects, parented curve has to be updated too */
if (ob->type == OB_CURVE) {
- Curve *cu = ob->data;
+ Curve *cu = (Curve *)ob->data;
BKE_animsys_evaluate_animdata(
&cu->id, cu->adt, &anim_eval_context, ADT_RECALC_ANIM, flush_to_original);
}
/* and armatures... */
if (ob->type == OB_ARMATURE) {
- bArmature *arm = ob->data;
+ bArmature *arm = (bArmature *)ob->data;
BKE_animsys_evaluate_animdata(
&arm->id, arm->adt, &anim_eval_context, ADT_RECALC_ANIM, flush_to_original);
BKE_pose_where_is(depsgraph, scene, ob);
@@ -5684,19 +5748,22 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
return false;
}
-/**
- * Updates select_id of all objects in the given \a bmain.
- */
void BKE_object_update_select_id(struct Main *bmain)
{
- Object *ob = bmain->objects.first;
+ Object *ob = (Object *)bmain->objects.first;
int select_id = 1;
while (ob) {
ob->runtime.select_id = select_id++;
- ob = ob->id.next;
+ ob = (Object *)ob->id.next;
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Conversion
+ * \{ */
+
Mesh *BKE_object_to_mesh(Depsgraph *depsgraph, Object *object, bool preserve_all_data_layers)
{
BKE_object_to_mesh_clear(object);
@@ -5708,11 +5775,11 @@ Mesh *BKE_object_to_mesh(Depsgraph *depsgraph, Object *object, bool preserve_all
void BKE_object_to_mesh_clear(Object *object)
{
- if (object->runtime.object_as_temp_mesh == NULL) {
+ if (object->runtime.object_as_temp_mesh == nullptr) {
return;
}
- BKE_id_free(NULL, object->runtime.object_as_temp_mesh);
- object->runtime.object_as_temp_mesh = NULL;
+ BKE_id_free(nullptr, object->runtime.object_as_temp_mesh);
+ object->runtime.object_as_temp_mesh = nullptr;
}
Curve *BKE_object_to_curve(Object *object, Depsgraph *depsgraph, bool apply_modifiers)
@@ -5726,11 +5793,11 @@ Curve *BKE_object_to_curve(Object *object, Depsgraph *depsgraph, bool apply_modi
void BKE_object_to_curve_clear(Object *object)
{
- if (object->runtime.object_as_temp_curve == NULL) {
+ if (object->runtime.object_as_temp_curve == nullptr) {
return;
}
- BKE_id_free(NULL, object->runtime.object_as_temp_curve);
- object->runtime.object_as_temp_curve = NULL;
+ BKE_id_free(nullptr, object->runtime.object_as_temp_curve);
+ object->runtime.object_as_temp_curve = nullptr;
}
void BKE_object_check_uuids_unique_and_report(const Object *object)
@@ -5744,28 +5811,39 @@ void BKE_object_modifiers_lib_link_common(void *userData,
struct ID **idpoin,
int cb_flag)
{
- BlendLibReader *reader = userData;
+ BlendLibReader *reader = (BlendLibReader *)userData;
BLO_read_id_address(reader, ob->id.lib, idpoin);
- if (*idpoin != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ if (*idpoin != nullptr && (cb_flag & IDWALK_CB_USER) != 0) {
id_us_plus_no_lib(*idpoin);
}
}
+SubsurfModifierData *BKE_object_get_last_subsurf_modifier(const Object *ob)
+{
+ ModifierData *md = (ModifierData *)(ob->modifiers.last);
+
+ while (md) {
+ if (md->type == eModifierType_Subsurf) {
+ break;
+ }
+
+ md = md->prev;
+ }
+
+ return (SubsurfModifierData *)(md);
+}
+
void BKE_object_replace_data_on_shallow_copy(Object *ob, ID *new_data)
{
ob->type = BKE_object_obdata_to_type(new_data);
- ob->data = new_data;
- ob->runtime.geometry_set_eval = NULL;
- ob->runtime.data_eval = NULL;
- if (ob->runtime.bb != NULL) {
+ ob->data = (void *)new_data;
+ ob->runtime.geometry_set_eval = nullptr;
+ ob->runtime.data_eval = new_data;
+ if (ob->runtime.bb != nullptr) {
ob->runtime.bb->flag |= BOUNDBOX_DIRTY;
}
- ob->id.py_instance = NULL;
+ ob->id.py_instance = nullptr;
}
-bool BKE_object_supports_material_slots(struct Object *ob)
-{
- return ELEM(
- ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_HAIR, OB_POINTCLOUD, OB_VOLUME);
-}
+/** \} */
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index 511f5d4ae66..fb4f4a14265 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -63,13 +63,6 @@ static Lattice *object_defgroup_lattice_get(ID *id)
return (lt->editlatt) ? lt->editlatt->latt : lt;
}
-/**
- * Update users of vgroups from this object, according to given map.
- *
- * Use it when you remove or reorder vgroups in the object.
- *
- * \param map: an array mapping old indices to new indices.
- */
void BKE_object_defgroup_remap_update_users(Object *ob, const int *map)
{
ModifierData *md;
@@ -106,15 +99,13 @@ void BKE_object_defgroup_remap_update_users(Object *ob, const int *map)
}
}
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Group creation
* \{ */
-/**
- * Add a vgroup of given name to object. *Does not* handle MDeformVert data at all!
- */
bDeformGroup *BKE_object_defgroup_add_name(Object *ob, const char *name)
{
bDeformGroup *defgroup;
@@ -129,17 +120,11 @@ bDeformGroup *BKE_object_defgroup_add_name(Object *ob, const char *name)
return defgroup;
}
-/**
- * Add a vgroup of default name to object. *Does not* handle MDeformVert data at all!
- */
bDeformGroup *BKE_object_defgroup_add(Object *ob)
{
return BKE_object_defgroup_add_name(ob, DATA_("Group"));
}
-/**
- * Create MDeformVert data for given ID. Work in Object mode only.
- */
MDeformVert *BKE_object_defgroup_data_create(ID *id)
{
if (GS(id->name) == ID_ME) {
@@ -156,18 +141,13 @@ MDeformVert *BKE_object_defgroup_data_create(ID *id)
return NULL;
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Group clearing
* \{ */
-/**
- * Remove all verts (or only selected ones) from given vgroup. Work in Object and Edit modes.
- *
- * \param use_selection: Only operate on selection.
- * \return True if any vertex was removed, false otherwise.
- */
bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_selection)
{
MDeformVert *dv;
@@ -239,12 +219,6 @@ bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_sele
return changed;
}
-/**
- * Remove all verts (or only selected ones) from all vgroups. Work in Object and Edit modes.
- *
- * \param use_selection: Only operate on selection.
- * \return True if any vertex was removed, false otherwise.
- */
bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection)
{
bDeformGroup *dg;
@@ -260,6 +234,7 @@ bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection)
return changed;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -406,9 +381,6 @@ static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg)
object_defgroup_remove_common(ob, dg, def_nr);
}
-/**
- * Remove given vgroup from object. Work in Object and Edit modes.
- */
void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
{
if (ob->type == OB_GPENCIL) {
@@ -426,10 +398,6 @@ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
}
}
-/**
- * Remove all vgroups from object. Work in Object and Edit modes.
- * When only_unlocked=true, locked vertex groups are not removed.
- */
void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
{
ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
@@ -469,19 +437,11 @@ void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
}
}
-/**
- * Remove all vgroups from object. Work in Object and Edit modes.
- */
void BKE_object_defgroup_remove_all(struct Object *ob)
{
BKE_object_defgroup_remove_all_ex(ob, false);
}
-/**
- * Compute mapping for vertex groups with matching name, -1 is used for no remapping.
- * Returns null if no remapping is required.
- * The returned array has to be freed.
- */
int *BKE_object_defgroup_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len)
{
const ListBase *src_defbase = BKE_object_defgroup_list(ob_src);
@@ -549,11 +509,6 @@ void BKE_object_defgroup_index_map_apply(MDeformVert *dvert,
}
}
-/**
- * Get MDeformVert vgroup data from given object. Should only be used in Object mode.
- *
- * \return True if the id type supports weights.
- */
bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_tot)
{
if (id) {
@@ -579,14 +534,11 @@ bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_t
*dvert_tot = 0;
return false;
}
+
/** \} */
/* --- functions for getting vgroup aligned maps --- */
-/**
- * gets the status of "flag" for each bDeformGroup
- * in the object data's vertex group list and returns an array containing them
- */
bool *BKE_object_defgroup_lock_flags_get(Object *ob, const int defbase_tot)
{
bool is_locked = false;
@@ -675,8 +627,6 @@ bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot)
return defgroup_validmap;
}
-/* Returns total selected vgroups,
- * wpi.defbase_sel is assumed malloc'd, all values are set */
bool *BKE_object_defgroup_selected_get(Object *ob, int defbase_tot, int *r_dg_flags_sel_tot)
{
bool *dg_selection = MEM_mallocN(defbase_tot * sizeof(bool), __func__);
@@ -708,11 +658,6 @@ bool *BKE_object_defgroup_selected_get(Object *ob, int defbase_tot, int *r_dg_fl
return dg_selection;
}
-/**
- * Checks if the lock relative mode is applicable.
- *
- * \return true if an unlocked deform group is active.
- */
bool BKE_object_defgroup_check_lock_relative(const bool *lock_flags,
const bool *validmap,
int index)
@@ -720,11 +665,6 @@ bool BKE_object_defgroup_check_lock_relative(const bool *lock_flags,
return validmap && validmap[index] && !(lock_flags && lock_flags[index]);
}
-/**
- * Additional check for whether the lock relative mode is applicable in multi-paint mode.
- *
- * \return true if none of the selected groups are locked.
- */
bool BKE_object_defgroup_check_lock_relative_multi(int defbase_tot,
const bool *lock_flags,
const bool *selected,
@@ -747,11 +687,6 @@ bool BKE_object_defgroup_check_lock_relative_multi(int defbase_tot,
return true;
}
-/**
- * Takes a pair of boolean masks of all locked and all deform groups, and computes
- * a pair of masks for locked deform and unlocked deform groups. Output buffers may
- * reuse the input ones.
- */
void BKE_object_defgroup_split_locked_validmap(
int defbase_tot, const bool *locked, const bool *deform, bool *r_locked, bool *r_unlocked)
{
@@ -774,11 +709,6 @@ void BKE_object_defgroup_split_locked_validmap(
}
}
-/**
- * Marks mirror vgroups in output and counts them.
- * Output and counter assumed to be already initialized.
- * Designed to be usable after BKE_object_defgroup_selected_get to extend selection to mirror.
- */
void BKE_object_defgroup_mirror_selection(struct Object *ob,
int defbase_tot,
const bool *dg_selection,
@@ -808,9 +738,6 @@ void BKE_object_defgroup_mirror_selection(struct Object *ob,
}
}
-/**
- * Return the subset type of the Vertex Group Selection
- */
bool *BKE_object_defgroup_subset_from_select_type(Object *ob,
eVGroupSelect subset_type,
int *r_defgroup_tot,
@@ -873,9 +800,6 @@ bool *BKE_object_defgroup_subset_from_select_type(Object *ob,
return defgroup_validmap;
}
-/**
- * store indices from the defgroup_validmap (faster lookups in some cases)
- */
void BKE_object_defgroup_subset_to_index_array(const bool *defgroup_validmap,
const int defgroup_tot,
int *r_defgroup_subset_map)
diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc
index 04739ec19d3..3082d6f25f3 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -31,9 +31,9 @@
#include "BLI_string_utf8.h"
#include "BLI_array.hh"
-#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_rand.h"
#include "BLI_span.hh"
#include "BLI_vector.hh"
@@ -50,7 +50,6 @@
#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h"
-#include "BKE_font.h"
#include "BKE_geometry_set.h"
#include "BKE_geometry_set.hh"
#include "BKE_global.h"
@@ -63,6 +62,7 @@
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
+#include "BKE_vfont.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -88,7 +88,6 @@ struct DupliContext {
Object *obedit;
Scene *scene;
- ViewLayer *view_layer;
Object *object;
float space_mat[4][4];
@@ -127,7 +126,6 @@ static void init_context(DupliContext *r_ctx,
{
r_ctx->depsgraph = depsgraph;
r_ctx->scene = scene;
- r_ctx->view_layer = DEG_get_evaluated_view_layer(depsgraph);
r_ctx->collection = nullptr;
r_ctx->object = ob;
@@ -149,7 +147,7 @@ static void init_context(DupliContext *r_ctx,
/**
* Create sub-context for recursive duplis.
*/
-static void copy_dupli_context(
+static bool copy_dupli_context(
DupliContext *r_ctx, const DupliContext *ctx, Object *ob, const float mat[4][4], int index)
{
*r_ctx = *ctx;
@@ -168,7 +166,13 @@ static void copy_dupli_context(
r_ctx->persistent_id[r_ctx->level] = index;
++r_ctx->level;
+ if (r_ctx->level == MAX_DUPLI_RECUR - 1) {
+ std::cerr << "Warning: Maximum instance recursion level reached.\n";
+ return false;
+ }
+
r_ctx->gen = get_dupli_generator(r_ctx);
+ return true;
}
/**
@@ -186,7 +190,7 @@ static DupliObject *make_dupli(const DupliContext *ctx,
/* Add a #DupliObject instance to the result container. */
if (ctx->duplilist) {
- dob = (DupliObject *)MEM_callocN(sizeof(DupliObject), "dupli object");
+ dob = MEM_cnew<DupliObject>("dupli object");
BLI_addtail(ctx->duplilist, dob);
}
else {
@@ -256,7 +260,9 @@ static void make_recursive_duplis(const DupliContext *ctx,
/* Simple preventing of too deep nested collections with #MAX_DUPLI_RECUR. */
if (ctx->level < MAX_DUPLI_RECUR) {
DupliContext rctx;
- copy_dupli_context(&rctx, ctx, ob, space_mat, index);
+ if (!copy_dupli_context(&rctx, ctx, ob, space_mat, index)) {
+ return;
+ }
if (rctx.gen) {
ctx->instance_stack->append(ob);
rctx.gen->make_duplis(&rctx);
@@ -299,34 +305,41 @@ static void make_child_duplis(const DupliContext *ctx,
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (ctx->collection, ob, mode) {
if ((ob != ctx->obedit) && is_child(ob, parent)) {
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, nullptr, _base_id);
-
- /* Meta-balls have a different dupli handling. */
- if (ob->type != OB_MBALL) {
- ob->flag |= OB_DONE; /* Doesn't render. */
+ if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, _base_id)) {
+ /* Meta-balls have a different dupli handling. */
+ if (ob->type != OB_MBALL) {
+ ob->flag |= OB_DONE; /* Doesn't render. */
+ }
+ make_child_duplis_cb(&pctx, userdata, ob);
}
- make_child_duplis_cb(&pctx, userdata, ob);
}
}
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
else {
- int baseid;
- ViewLayer *view_layer = ctx->view_layer;
- LISTBASE_FOREACH_INDEX (Base *, base, &view_layer->object_bases, baseid) {
- Object *ob = base->object;
+ /* FIXME: using a mere counter to generate a 'persistent' dupli id is very weak. One possible
+ * better solution could be to use `session_uuid` of ID's instead? */
+ int persistent_dupli_id = 0;
+ /* NOTE: this set of flags ensure we only iterate over objects that have a base in either the
+ * current scene, or the set (background) scene. */
+ int deg_objects_visibility_flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET;
+
+ DEG_OBJECT_ITER_BEGIN (ctx->depsgraph, ob, deg_objects_visibility_flags) {
if ((ob != ctx->obedit) && is_child(ob, parent)) {
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, nullptr, baseid);
+ if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, persistent_dupli_id)) {
+ /* Meta-balls have a different dupli-handling. */
+ if (ob->type != OB_MBALL) {
+ ob->flag |= OB_DONE; /* Doesn't render. */
+ }
- /* Meta-balls have a different dupli-handling. */
- if (ob->type != OB_MBALL) {
- ob->flag |= OB_DONE; /* Doesn't render. */
+ make_child_duplis_cb(&pctx, userdata, ob);
}
-
- make_child_duplis_cb(&pctx, userdata, ob);
}
+ persistent_dupli_id++;
}
+ DEG_OBJECT_ITER_END;
}
}
@@ -358,7 +371,7 @@ static const Mesh *mesh_data_from_duplicator_object(Object *ob,
if (em != nullptr) {
/* Note that this will only show deformation if #eModifierMode_OnCage is enabled.
* We could change this but it matches 2.7x behavior. */
- me_eval = em->mesh_eval_cage;
+ me_eval = BKE_object_get_editmesh_eval_cage(ob);
if ((me_eval == nullptr) || (me_eval->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
EditMeshData *emd = me_eval ? me_eval->runtime.edit_data : nullptr;
@@ -448,6 +461,7 @@ struct VertexDupliData_Mesh {
int totvert;
const MVert *mvert;
+ const float (*vert_normals)[3];
const float (*orco)[3];
};
@@ -545,12 +559,9 @@ static void make_child_duplis_verts_from_mesh(const DupliContext *ctx,
float child_imat[4][4];
mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat);
- const MVert *mv = mvert;
- for (int i = 0; i < totvert; i++, mv++) {
- const float *co = mv->co;
- float no[3];
- normal_short_to_float_v3(no, mv->no);
- DupliObject *dob = vertex_dupli(vdd->params.ctx, inst_ob, child_imat, i, co, no, use_rotation);
+ for (int i = 0; i < totvert; i++) {
+ DupliObject *dob = vertex_dupli(
+ vdd->params.ctx, inst_ob, child_imat, i, mvert[i].co, vdd->vert_normals[i], use_rotation);
if (vdd->orco) {
copy_v3_v3(dob->orco, vdd->orco[i]);
}
@@ -627,6 +638,7 @@ static void make_duplis_verts(const DupliContext *ctx)
vdd.params = vdd_params;
vdd.totvert = me_eval->totvert;
vdd.mvert = me_eval->mvert;
+ vdd.vert_normals = BKE_mesh_vertex_normals_ensure(me_eval);
vdd.orco = (const float(*)[3])CustomData_get_layer(&me_eval->vdata, CD_ORCO);
make_child_duplis(ctx, &vdd, make_child_duplis_verts_from_mesh);
@@ -884,7 +896,9 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
* between the instances component below and the other components above. */
DupliContext new_instances_ctx;
if (creates_duplis_for_components) {
- copy_dupli_context(&new_instances_ctx, ctx, ctx->object, nullptr, component_index);
+ if (!copy_dupli_context(&new_instances_ctx, ctx, ctx->object, nullptr, component_index)) {
+ return;
+ }
instances_ctx = &new_instances_ctx;
}
@@ -919,7 +933,9 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
mul_m4_m4_pre(collection_matrix, parent_transform);
DupliContext sub_ctx;
- copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id);
+ if (!copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) {
+ break;
+ }
eEvaluationMode mode = DEG_get_mode(instances_ctx->depsgraph);
int object_id = 0;
@@ -942,8 +958,9 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
mul_m4_m4m4(new_transform, parent_transform, instance_offset_matrices[i].values);
DupliContext sub_ctx;
- copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id);
- make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true);
+ if (copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) {
+ make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true);
+ }
break;
}
case InstanceReference::Type::None: {
@@ -1008,6 +1025,8 @@ static void get_dupliface_transform_from_coords(Span<float3> coords,
const float scale_fac,
float r_mat[4][4])
{
+ using namespace blender::math;
+
/* Location. */
float3 location(0);
for (const float3 &coord : coords) {
@@ -1018,9 +1037,7 @@ static void get_dupliface_transform_from_coords(Span<float3> coords,
/* Rotation. */
float quat[4];
- float3 f_no;
- cross_poly_v3(f_no, (const float(*)[3])coords.data(), (uint)coords.size());
- f_no.normalize();
+ float3 f_no = normalize(cross_poly(coords));
tri_to_quat_ex(quat, coords[0], coords[1], coords[2], f_no);
/* Scale. */
@@ -1490,7 +1507,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
else {
/* First key. */
state.time = ctime;
- if (psys_get_particle_state(&sim, a, &state, 0) == 0) {
+ if (psys_get_particle_state(&sim, a, &state, false) == 0) {
continue;
}
@@ -1600,8 +1617,9 @@ static void make_duplis_particles(const DupliContext *ctx)
LISTBASE_FOREACH_INDEX (ParticleSystem *, psys, &ctx->object->particlesystem, psysid) {
/* Particles create one more level for persistent `psys` index. */
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, nullptr, psysid);
- make_duplis_particle_system(&pctx, psys);
+ if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, psysid)) {
+ make_duplis_particle_system(&pctx, psys);
+ }
}
}
@@ -1631,6 +1649,14 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
return nullptr;
}
+ /* Give "Object as Font" instances higher priority than geometry set instances, to retain
+ * the behavior from before curve object meshes were processed as instances internally. */
+ if (transflag & OB_DUPLIVERTS) {
+ if (ctx->object->type == OB_FONT) {
+ return &gen_dupli_verts_font;
+ }
+ }
+
if (ctx->object->runtime.geometry_set_eval != nullptr) {
if (BKE_object_has_geometry_set_instances(ctx->object)) {
return &gen_dupli_geometry_set;
@@ -1644,9 +1670,6 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
if (ctx->object->type == OB_MESH) {
return &gen_dupli_verts;
}
- if (ctx->object->type == OB_FONT) {
- return &gen_dupli_verts_font;
- }
if (ctx->object->type == OB_POINTCLOUD) {
return &gen_dupli_verts_pointcloud;
}
@@ -1669,12 +1692,9 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
/** \name Dupli-Container Implementation
* \{ */
-/**
- * \return a #ListBase of #DupliObject.
- */
ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
{
- ListBase *duplilist = (ListBase *)MEM_callocN(sizeof(ListBase), "duplilist");
+ ListBase *duplilist = MEM_cnew<ListBase>("duplilist");
DupliContext ctx;
Vector<Object *> instance_stack;
instance_stack.append(ob);
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 7e15ac5de5d..1a208355870 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -67,14 +67,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-/**
- * Restore the object->data to a non-modifier evaluated state.
- *
- * Some changes done directly in evaluated object require them to be reset
- * before being re-evaluated.
- * For example, we need to call this before #BKE_mesh_new_from_object(),
- * in case we removed/added modifiers in the evaluated object.
- */
void BKE_object_eval_reset(Object *ob_eval)
{
BKE_object_free_derived_caches(ob_eval);
@@ -88,10 +80,10 @@ void BKE_object_eval_local_transform(Depsgraph *depsgraph, Object *ob)
BKE_object_to_mat4(ob, ob->obmat);
}
-/* Evaluate parent */
-/* NOTE: based on solve_parenting(), but with the cruft stripped out */
void BKE_object_eval_parent(Depsgraph *depsgraph, Object *ob)
{
+ /* NOTE: based on `solve_parenting()`, but with the cruft stripped out. */
+
Object *par = ob->parent;
float totmat[4][4];
@@ -168,12 +160,6 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
/* includes all keys and modifiers */
switch (ob->type) {
case OB_MESH: {
-#if 0
- BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? BKE_editmesh_from_object(ob) : NULL;
-#else
- BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? ((Mesh *)ob->data)->edit_mesh : NULL;
-#endif
-
CustomData_MeshMasks cddata_masks = scene->customdata_mask;
CustomData_MeshMasks_update(&cddata_masks, &CD_MASK_BAREMESH);
/* Custom attributes should not be removed automatically. They might be used by the render
@@ -183,6 +169,11 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
cddata_masks.fmask |= CD_MASK_PROP_ALL;
cddata_masks.pmask |= CD_MASK_PROP_ALL;
cddata_masks.lmask |= CD_MASK_PROP_ALL;
+
+ /* Also copy over normal layers to avoid recomputation. */
+ cddata_masks.pmask |= CD_MASK_NORMAL;
+ cddata_masks.vmask |= CD_MASK_NORMAL;
+
/* Make sure Freestyle edge/face marks appear in DM for render (see T40315).
* Due to Line Art implementation, edge marks should also be shown in viewport. */
#ifdef WITH_FREESTYLE
@@ -195,12 +186,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
cddata_masks.lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
cddata_masks.vmask |= CD_MASK_ORCO | CD_MASK_PROP_COLOR;
}
- if (em) {
- makeDerivedMesh(depsgraph, scene, ob, em, &cddata_masks); /* was CD_MASK_BAREMESH */
- }
- else {
- makeDerivedMesh(depsgraph, scene, ob, NULL, &cddata_masks);
- }
+ makeDerivedMesh(depsgraph, scene, ob, &cddata_masks); /* was CD_MASK_BAREMESH */
break;
}
case OB_ARMATURE:
@@ -282,7 +268,12 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
/** Bounding box from evaluated geometry. */
static void object_sync_boundbox_to_original(Object *object_orig, Object *object_eval)
{
- BoundBox *bb = BKE_object_boundbox_get(object_eval);
+ BoundBox *bb = object_eval->runtime.bb;
+ if (!bb || (bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_object_boundbox_calc_from_evaluated_geometry(object_eval);
+ }
+
+ bb = BKE_object_boundbox_get(object_eval);
if (bb != NULL) {
if (object_orig->runtime.bb == NULL) {
object_orig->runtime.bb = MEM_mallocN(sizeof(*object_orig->runtime.bb), __func__);
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index e9683d3b52c..97326c24a61 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -270,7 +270,6 @@ void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float
BLI_rw_mutex_unlock(&oc->oceanmutex);
}
-/* use catmullrom interpolation rather than linear */
void BKE_ocean_eval_uv_catrom(struct Ocean *oc, struct OceanResult *ocr, float u, float v)
{
int i0, i1, i2, i3, j0, j1, j2, j3;
@@ -378,8 +377,6 @@ void BKE_ocean_eval_xz_catrom(struct Ocean *oc, struct OceanResult *ocr, float x
BKE_ocean_eval_uv_catrom(oc, ocr, x / oc->_Lx, z / oc->_Lz);
}
-/* note that this doesn't wrap properly for i, j < 0, but its not really meant for that being
- * just a way to get the raw data out to save in some image format. */
void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j)
{
BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
@@ -650,9 +647,6 @@ static void ocean_compute_normal_z(TaskPool *__restrict pool, void *UNUSED(taskd
fftw_execute(o->_N_z_plan);
}
-/**
- * Return true if the ocean is valid and can be used.
- */
bool BKE_ocean_is_valid(const struct Ocean *o)
{
return o->_k != NULL;
@@ -777,9 +771,6 @@ bool BKE_ocean_ensure(struct OceanModifierData *omd, const int resolution)
return true;
}
-/**
- * Return true if the ocean data is valid and can be used.
- */
bool BKE_ocean_init_from_modifier(struct Ocean *ocean,
struct OceanModifierData const *omd,
const int resolution)
@@ -818,9 +809,6 @@ bool BKE_ocean_init_from_modifier(struct Ocean *ocean,
omd->seed);
}
-/**
- * Return true if the ocean data is valid and can be used.
- */
bool BKE_ocean_init(struct Ocean *o,
int M,
int N,
diff --git a/source/blender/blenkernel/intern/ocean_intern.h b/source/blender/blenkernel/intern/ocean_intern.h
index 4ebd03789af..df9dcd7e2f5 100644
--- a/source/blender/blenkernel/intern/ocean_intern.h
+++ b/source/blender/blenkernel/intern/ocean_intern.h
@@ -17,7 +17,7 @@
#pragma once
/** \file
- * \ingroup bli
+ * \ingroup bke
*/
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/intern/ocean_spectrum.c b/source/blender/blenkernel/intern/ocean_spectrum.c
index c5504b22b43..43e0f399213 100644
--- a/source/blender/blenkernel/intern/ocean_spectrum.c
+++ b/source/blender/blenkernel/intern/ocean_spectrum.c
@@ -128,11 +128,6 @@ static float jonswap(const Ocean *oc, const float k2)
return val;
}
-/**
- * Pierson-Moskowitz model, 1964, assumes waves reach equilibrium with wind.
- * Model is intended for large area 'fully developed' sea, where winds have been steadily blowing
- * for days over an area that includes hundreds of wavelengths on a side.
- */
float BLI_ocean_spectrum_piersonmoskowitz(const Ocean *oc, const float kx, const float kz)
{
const float k2 = kx * kx + kz * kz;
@@ -159,10 +154,6 @@ float BLI_ocean_spectrum_piersonmoskowitz(const Ocean *oc, const float kx, const
return val;
}
-/**
- * TMA extends the JONSWAP spectrum.
- * This spectral model is best suited to shallow water.
- */
float BLI_ocean_spectrum_texelmarsenarsloe(const Ocean *oc, const float kx, const float kz)
{
const float k2 = kx * kx + kz * kz;
@@ -195,14 +186,6 @@ float BLI_ocean_spectrum_texelmarsenarsloe(const Ocean *oc, const float kx, cons
return val;
}
-/**
- * Hasselmann et al, 1973. This model extends the Pierson-Moskowitz model with a peak sharpening
- * function This enhancement is an artificial construct to address the problem that the wave
- * spectrum is never fully developed.
- *
- * The fetch parameter represents the distance from a lee shore,
- * called the fetch, or the distance over which the wind blows with constant velocity.
- */
float BLI_ocean_spectrum_jonswap(const Ocean *oc, const float kx, const float kz)
{
const float k2 = kx * kx + kz * kz;
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index baff1bb47cc..3ddcdb424f9 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -43,12 +43,12 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BKE_font.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
#include "BKE_sound.h"
+#include "BKE_vfont.h"
#include "BKE_volume.h"
#include "IMB_imbuf.h"
@@ -242,7 +242,6 @@ PackedFile *BKE_packedfile_new(ReportList *reports, const char *filename, const
return pf;
}
-/* no libraries for now */
void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose)
{
Image *ima;
@@ -373,14 +372,6 @@ int BKE_packedfile_write_to_file(ReportList *reports,
return ret_value;
}
-/**
- * This function compares a packed file to a 'real' file.
- * It returns an integer indicating if:
- *
- * - PF_EQUAL: the packed file and original file are identical
- * - PF_DIFFERENT: the packed file and original file differ
- * - PF_NOFILE: the original file doesn't exist
- */
enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
const char *filename,
PackedFile *pf)
@@ -434,16 +425,6 @@ enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
return ret_val;
}
-/**
- * #BKE_packedfile_unpack_to_file() looks at the existing files (abs_name, local_name)
- * and a packed file.
- *
- * It returns a char *to the existing file name / new file name or NULL when
- * there was an error or when the user decides to cancel the operation.
- *
- * \warning 'abs_name' may be relative still! (use a "//" prefix)
- * be sure to run #BLI_path_abs on it first.
- */
char *BKE_packedfile_unpack_to_file(ReportList *reports,
const char *ref_file_name,
const char *abs_name,
@@ -753,7 +734,7 @@ void BKE_packedfile_pack_all_libraries(Main *bmain, ReportList *reports)
{
Library *lib;
- /* test for relativenss */
+ /* Test for relativeness. */
for (lib = bmain->libraries.first; lib; lib = lib->id.next) {
if (!BLI_path_is_rel(lib->filepath)) {
break;
@@ -804,28 +785,27 @@ void BKE_packedfile_unpack_all(Main *bmain, ReportList *reports, enum ePF_FileSt
}
}
-/* ID should be not NULL, return 1 if there's a packed file */
-bool BKE_packedfile_id_check(ID *id)
+bool BKE_packedfile_id_check(const ID *id)
{
switch (GS(id->name)) {
case ID_IM: {
- Image *ima = (Image *)id;
+ const Image *ima = (const Image *)id;
return BKE_image_has_packedfile(ima);
}
case ID_VF: {
- VFont *vf = (VFont *)id;
+ const VFont *vf = (const VFont *)id;
return vf->packedfile != NULL;
}
case ID_SO: {
- bSound *snd = (bSound *)id;
+ const bSound *snd = (const bSound *)id;
return snd->packedfile != NULL;
}
case ID_VO: {
- Volume *volume = (Volume *)id;
+ const Volume *volume = (const Volume *)id;
return volume->packedfile != NULL;
}
case ID_LI: {
- Library *li = (Library *)id;
+ const Library *li = (const Library *)id;
return li->packedfile != NULL;
}
default:
@@ -834,7 +814,6 @@ bool BKE_packedfile_id_check(ID *id)
return false;
}
-/* ID should be not NULL */
void BKE_packedfile_id_unpack(Main *bmain, ID *id, ReportList *reports, enum ePF_FileStatus how)
{
switch (GS(id->name)) {
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index d6030941c6d..407375c4d22 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -143,6 +143,7 @@ IDTypeInfo IDType_ID_PAL = {
.name_plural = "palettes",
.translation_context = BLT_I18NCONTEXT_ID_PALETTE,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = palette_init_data,
.copy_data = palette_copy_data,
@@ -150,6 +151,7 @@ IDTypeInfo IDType_ID_PAL = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = palette_blend_write,
@@ -208,6 +210,7 @@ IDTypeInfo IDType_ID_PC = {
.name_plural = "paint_curves",
.translation_context = BLT_I18NCONTEXT_ID_PAINTCURVE,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = paint_curve_copy_data,
@@ -215,6 +218,7 @@ IDTypeInfo IDType_ID_PC = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = paint_curve_blend_write,
@@ -723,7 +727,6 @@ void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, const int add_inde
pc->add_index = (add_index || pc->tot_points == 1) ? (add_index + 1) : 0;
}
-/** Remove color from palette. Must be certain color is inside the palette! */
void BKE_palette_color_remove(Palette *palette, PaletteColor *color)
{
if (BLI_listbase_count_at_most(&palette->colors, palette->active_color) ==
@@ -962,7 +965,6 @@ bool BKE_palette_from_hash(Main *bmain, GHash *color_table, const char *name, co
return done;
}
-/* are we in vertex paint or weight paint face select mode? */
bool BKE_paint_select_face_test(Object *ob)
{
return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) &&
@@ -970,7 +972,6 @@ bool BKE_paint_select_face_test(Object *ob)
(ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)));
}
-/* are we in weight paint vertex select mode? */
bool BKE_paint_select_vert_test(Object *ob)
{
return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) &&
@@ -978,10 +979,6 @@ bool BKE_paint_select_vert_test(Object *ob)
(ob->mode & OB_MODE_WEIGHT_PAINT || ob->mode & OB_MODE_VERTEX_PAINT));
}
-/**
- * used to check if selection is possible
- * (when we don't care if its face or vert)
- */
bool BKE_paint_select_elem_test(Object *ob)
{
return (BKE_paint_select_vert_test(ob) || BKE_paint_select_face_test(ob));
@@ -1024,9 +1021,6 @@ eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode)
}
}
-/**
- * Call when entering each respective paint mode.
- */
bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint)
{
Paint *paint = NULL;
@@ -1147,10 +1141,6 @@ void BKE_paint_free(Paint *paint)
MEM_SAFE_FREE(paint->tool_slots);
}
-/* called when copying scene settings, so even if 'src' and 'tar' are the same
- * still do a id_us_plus(), rather than if we were copying between 2 existing
- * scenes where a matching value should decrease the existing user count as
- * with paint_brush_set() */
void BKE_paint_copy(Paint *src, Paint *tar, const int flag)
{
tar->brush = src->brush;
@@ -1230,8 +1220,6 @@ void BKE_paint_blend_read_lib(BlendLibReader *reader, Scene *sce, Paint *p)
}
}
-/* returns non-zero if any of the face's vertices
- * are hidden, zero otherwise */
bool paint_is_face_hidden(const MLoopTri *lt, const MVert *mvert, const MLoop *mloop)
{
return ((mvert[mloop[lt->tri[0]].v].flag & ME_HIDE) ||
@@ -1239,9 +1227,6 @@ bool paint_is_face_hidden(const MLoopTri *lt, const MVert *mvert, const MLoop *m
(mvert[mloop[lt->tri[2]].v].flag & ME_HIDE));
}
-/* returns non-zero if any of the corners of the grid
- * face whose inner corner is at (x, y) are hidden,
- * zero otherwise */
bool paint_is_grid_face_hidden(const uint *grid_hidden, int gridsize, int x, int y)
{
/* skip face if any of its corners are hidden */
@@ -1251,7 +1236,6 @@ bool paint_is_grid_face_hidden(const uint *grid_hidden, int gridsize, int x, int
BLI_BITMAP_TEST(grid_hidden, (y + 1) * gridsize + x));
}
-/* Return true if all vertices in the face are visible, false otherwise */
bool paint_is_bmesh_face_hidden(BMFace *f)
{
BMLoop *l_iter;
@@ -1520,8 +1504,6 @@ void BKE_sculptsession_free(Object *ob)
}
}
-/* Sculpt mode handles multires differently from regular meshes, but only if
- * it's the last modifier on the stack and it is not on the first level */
MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob)
{
Mesh *me = (Mesh *)ob->data;
@@ -1666,6 +1648,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
ss->totvert = me->totvert;
ss->totpoly = me->totpoly;
ss->totfaces = me->totpoly;
+ ss->vert_normals = BKE_mesh_vertex_normals_ensure(me);
ss->mvert = me->mvert;
ss->mpoly = me->mpoly;
ss->mloop = me->mloop;
@@ -1811,7 +1794,6 @@ void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
DEG_id_tag_update(&orig_me->id, ID_RECALC_GEOMETRY_ALL_MODES);
}
-/** \warning Expects a fully evaluated depsgraph. */
void BKE_sculpt_update_object_for_edit(
Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool need_mask, bool need_colors)
{
@@ -1941,10 +1923,6 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc
return deformed;
}
-/**
- * Ensures that a Face Set data-layers exists. If it does not, it creates one respecting the
- * visibility stored in the vertices of the mesh. If it does, it copies the visibility from the
- * mesh to the Face Sets. */
void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh)
{
const int face_sets_default_visible_id = 1;
@@ -2046,12 +2024,6 @@ void BKE_sculpt_sync_face_set_visibility(struct Mesh *mesh, struct SubdivCCG *su
BKE_sculpt_sync_face_sets_visibility_to_grids(mesh, subdiv_ccg);
}
-/**
- * Ensures we do have expected mesh data in original mesh for the sculpt mode.
- *
- * \note IDs are expected to be original ones here, and calling code should ensure it updates its
- * depsgraph properly after calling this function if it needs up-to-date evaluated data.
- */
void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object)
{
Mesh *mesh = BKE_mesh_from_object(object);
@@ -2223,8 +2195,6 @@ void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg)
subdiv_ccg->grid_hidden);
}
-/* Test if PBVH can be used directly for drawing, which is faster than
- * drawing the mesh and all updates that come with it. */
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d)
{
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/blenkernel/intern/paint_toolslots.c b/source/blender/blenkernel/intern/paint_toolslots.c
index 0ea0173f8a3..bdb7b483997 100644
--- a/source/blender/blenkernel/intern/paint_toolslots.c
+++ b/source/blender/blenkernel/intern/paint_toolslots.c
@@ -140,10 +140,6 @@ void BKE_paint_toolslots_brush_update(Paint *paint)
BKE_paint_toolslots_brush_update_ex(paint, paint->brush);
}
-/**
- * Run this to ensure brush types are set for each slot on entering modes
- * (for new scenes for example).
- */
void BKE_paint_toolslots_brush_validate(Main *bmain, Paint *paint)
{
/* Clear slots with invalid slots or mode (unlikely but possible). */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 50b0fb1c9f5..4dba13ce4c2 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -173,28 +173,29 @@ static void particle_settings_free_data(ID *id)
static void particle_settings_foreach_id(ID *id, LibraryForeachIDData *data)
{
ParticleSettings *psett = (ParticleSettings *)id;
- BKE_LIB_FOREACHID_PROCESS(data, psett->instance_collection, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, psett->instance_object, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, psett->bb_ob, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, psett->collision_group, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->instance_collection, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->instance_object, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->bb_ob, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->collision_group, IDWALK_CB_NOP);
for (int i = 0; i < MAX_MTEX; i++) {
if (psett->mtex[i]) {
- BKE_texture_mtex_foreach_id(data, psett->mtex[i]);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data,
+ BKE_texture_mtex_foreach_id(data, psett->mtex[i]));
}
}
if (psett->effector_weights) {
- BKE_LIB_FOREACHID_PROCESS(data, psett->effector_weights->group, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->effector_weights->group, IDWALK_CB_NOP);
}
if (psett->pd) {
- BKE_LIB_FOREACHID_PROCESS(data, psett->pd->tex, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, psett->pd->f_source, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->pd->tex, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->pd->f_source, IDWALK_CB_NOP);
}
if (psett->pd2) {
- BKE_LIB_FOREACHID_PROCESS(data, psett->pd2->tex, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, psett->pd2->f_source, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->pd2->tex, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, psett->pd2->f_source, IDWALK_CB_NOP);
}
if (psett->boids) {
@@ -202,18 +203,18 @@ static void particle_settings_foreach_id(ID *id, LibraryForeachIDData *data)
LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
if (rule->type == eBoidRuleType_Avoid) {
BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
- BKE_LIB_FOREACHID_PROCESS(data, gabr->ob, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, gabr->ob, IDWALK_CB_NOP);
}
else if (rule->type == eBoidRuleType_FollowLeader) {
BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
- BKE_LIB_FOREACHID_PROCESS(data, flbr->ob, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, flbr->ob, IDWALK_CB_NOP);
}
}
}
}
LISTBASE_FOREACH (ParticleDupliWeight *, dw, &psett->instance_weights) {
- BKE_LIB_FOREACHID_PROCESS(data, dw->ob, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, dw->ob, IDWALK_CB_NOP);
}
}
@@ -499,6 +500,7 @@ IDTypeInfo IDType_ID_PA = {
.name_plural = "particles",
.translation_context = BLT_I18NCONTEXT_ID_PARTICLESETTINGS,
.flags = 0,
+ .asset_type_info = NULL,
.init_data = particle_settings_init,
.copy_data = particle_settings_copy_data,
@@ -506,6 +508,7 @@ IDTypeInfo IDType_ID_PA = {
.make_local = NULL,
.foreach_id = particle_settings_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = particle_settings_blend_write,
@@ -553,7 +556,6 @@ static void get_cpa_texture(Mesh *mesh,
int event,
float cfra);
-/* few helpers for countall etc. */
int count_particles(ParticleSystem *psys)
{
ParticleSettings *part = psys->part;
@@ -643,7 +645,7 @@ static void psys_free_path_cache_buffers(ParticleCacheKey **cache, ListBase *buf
/************************************************/
/* Getting stuff */
/************************************************/
-/* get object's active particle system safely */
+
ParticleSystem *psys_get_current(Object *ob)
{
ParticleSystem *psys;
@@ -911,9 +913,11 @@ int psys_uses_gravity(ParticleSimulationData *sim)
return sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY && sim->psys->part &&
sim->psys->part->effector_weights->global_gravity != 0.0f;
}
+
/************************************************/
/* Freeing stuff */
/************************************************/
+
static void fluid_free_settings(SPHFluidSettings *fluid)
{
if (fluid) {
@@ -1053,7 +1057,6 @@ void psys_free_pdd(ParticleSystem *psys)
psys->pdd->partsize = 0;
}
}
-/* free everything */
void psys_free(Object *ob, ParticleSystem *psys)
{
if (psys) {
@@ -1148,7 +1151,27 @@ void psys_copy_particles(ParticleSystem *psys_dst, ParticleSystem *psys_src)
/* Copy particles and children. */
psys_dst->particles = MEM_dupallocN(psys_src->particles);
psys_dst->child = MEM_dupallocN(psys_src->child);
- if (psys_dst->part->type == PART_HAIR) {
+
+ /* Ideally this should only be performed if `(psys_dst->part->type == PART_HAIR)`.
+ *
+ * But #ParticleData (`psys_dst`) is some sub-data of the #Object ID, while #ParticleSettings
+ * (`psys_dst->part`) is another ID. In case the particle settings is a linked ID that gets
+ * missing, it will be replaced (in readfile code) by a place-holder, which defaults to a
+ * `PART_EMITTER` type of particle settings.
+ *
+ * This leads to a situation where each particle of `psys_dst` still has a valid allocated `hair`
+ * data, which should still be preserved in case the missing particle settings ID becomes valid
+ * again.
+ *
+ * Furthermore, #free_hair() always frees `pa->hair` if it's not NULL, regardless of the
+ * particle type. So *not* copying here would cause a double free (or more), e.g. freeing the
+ * copy-on-write copy and the original data will crash Blender.
+ * In any case, sharing pointers between `psys_src` and `psys_dst` should be forbidden.
+ *
+ * So while we could in theory 'sanitize' the situation by setting `pa->hair` to NULL in the new
+ * copy (in case of non-`PART_HAIR` type), it is probably safer for now to systematically
+ * duplicate the `hair` data if available. */
+ {
ParticleData *pa;
int p;
for (p = 0, pa = psys_dst->particles; p < psys_dst->totpart; p++, pa++) {
@@ -1181,6 +1204,7 @@ void psys_copy_particles(ParticleSystem *psys_dst, ParticleSystem *psys_src)
/************************************************/
/* Interpolation */
/************************************************/
+
static float interpolate_particle_value(
float v1, float v2, float v3, float v4, const float w[4], int four)
{
@@ -1648,8 +1672,9 @@ static void interpolate_pathcache(ParticleCacheKey *first, float t, ParticleCach
/************************************************/
/* Particles on a dm */
/************************************************/
-/* interpolate a location on a face based on face coordinates */
+
void psys_interpolate_face(MVert *mvert,
+ const float (*vert_normals)[3],
MFace *mface,
MTFace *tface,
float (*orcodata)[3],
@@ -1671,13 +1696,13 @@ void psys_interpolate_face(MVert *mvert,
v2 = mvert[mface->v2].co;
v3 = mvert[mface->v3].co;
- normal_short_to_float_v3(n1, mvert[mface->v1].no);
- normal_short_to_float_v3(n2, mvert[mface->v2].no);
- normal_short_to_float_v3(n3, mvert[mface->v3].no);
+ copy_v3_v3(n1, vert_normals[mface->v1]);
+ copy_v3_v3(n2, vert_normals[mface->v2]);
+ copy_v3_v3(n3, vert_normals[mface->v3]);
if (mface->v4) {
v4 = mvert[mface->v4].co;
- normal_short_to_float_v3(n4, mvert[mface->v4].no);
+ copy_v3_v3(n4, vert_normals[mface->v4]);
interp_v3_v3v3v3v3(vec, v1, v2, v3, v4, w);
@@ -1880,18 +1905,6 @@ static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, const float w[4
}
}
-/**
- * Find the final derived mesh tessface for a particle, from its original tessface index.
- * This is slow and can be optimized but only for many lookups.
- *
- * \param mesh_final: Final mesh, it may not have the same topology as original mesh.
- * \param mesh_original: Original mesh, use for accessing #MPoly to #MFace mapping.
- * \param findex_orig: The input tessface index.
- * \param fw: Face weights (position of the particle inside the \a findex_orig tessface).
- * \param poly_nodes: May be NULL, otherwise an array of linked list,
- * one for each final \a mesh_final polygon, containing all its tessfaces indices.
- * \return The \a mesh_final tessface index.
- */
int psys_particle_dm_face_lookup(Mesh *mesh_final,
Mesh *mesh_original,
int findex_orig,
@@ -2073,7 +2086,6 @@ static int psys_map_index_on_dm(Mesh *mesh,
return 1;
}
-/* interprets particle data to get a point on a mesh in object space */
void psys_particle_on_dm(Mesh *mesh_final,
int from,
int index,
@@ -2113,13 +2125,13 @@ void psys_particle_on_dm(Mesh *mesh_final,
}
orcodata = CustomData_get_layer(&mesh_final->vdata, CD_ORCO);
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh_final);
if (from == PART_FROM_VERT) {
copy_v3_v3(vec, mesh_final->mvert[mapindex].co);
if (nor) {
- normal_short_to_float_v3(nor, mesh_final->mvert[mapindex].no);
- normalize_v3(nor);
+ copy_v3_v3(nor, vert_normals[mapindex]);
}
if (orco) {
@@ -2150,7 +2162,8 @@ void psys_particle_on_dm(Mesh *mesh_final,
}
if (from == PART_FROM_VOLUME) {
- psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco);
+ psys_interpolate_face(
+ mvert, vert_normals, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco);
if (nor) {
copy_v3_v3(nor, tmpnor);
}
@@ -2162,7 +2175,8 @@ void psys_particle_on_dm(Mesh *mesh_final,
add_v3_v3(vec, tmpnor);
}
else {
- psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco);
+ psys_interpolate_face(
+ mvert, vert_normals, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco);
}
}
}
@@ -2195,9 +2209,11 @@ ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys)
}
return NULL;
}
+
/************************************************/
/* Particles on a shape */
/************************************************/
+
/* ready for future use */
static void psys_particle_on_shape(int UNUSED(distr),
int UNUSED(index),
@@ -2226,6 +2242,7 @@ static void psys_particle_on_shape(int UNUSED(distr),
copy_v3_v3(orco, zerovec);
}
}
+
/************************************************/
/* Particles on emitter */
/************************************************/
@@ -2300,6 +2317,7 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd,
psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco);
}
}
+
/************************************************/
/* Path Cache */
/************************************************/
@@ -3252,11 +3270,6 @@ static void cache_key_incremental_rotation(ParticleCacheKey *key0,
}
}
-/**
- * Calculates paths ready for drawing/rendering
- * - Useful for making use of opengl vertex arrays for super fast strand drawing.
- * - Makes child strands possible and creates them too into the cache.
- * - Cached path data is also used to determine cut position for the editmode tool. */
void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
PARTICLE_PSMD;
@@ -3739,9 +3752,11 @@ void psys_cache_edit_paths(Depsgraph *depsgraph,
}
}
}
+
/************************************************/
/* Particle Key handling */
/************************************************/
+
void copy_particle_key(ParticleKey *to, ParticleKey *from, int time)
{
if (time) {
@@ -3901,6 +3916,7 @@ void psys_mat_hair_to_global(
/************************************************/
/* ParticleSettings handling */
/************************************************/
+
static ModifierData *object_add_or_copy_particle_system(
Main *bmain, Scene *scene, Object *ob, const char *name, const ParticleSystem *psys_orig)
{
@@ -4437,9 +4453,11 @@ void psys_get_texture(
CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DAMP, ptex->damp);
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length);
}
+
/************************************************/
/* Particle State */
/************************************************/
+
float psys_get_timestep(ParticleSimulationData *sim)
{
return 0.04f * sim->psys->part->timetweak;
@@ -4565,7 +4583,6 @@ static void get_child_modifier_parameters(ParticleSettings *part,
ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist);
}
}
-/* gets hair (or keyed) particles state at the "path time" specified in state->time */
void psys_get_particle_on_path(ParticleSimulationData *sim,
int p,
ParticleKey *state,
@@ -4619,11 +4636,11 @@ void psys_get_particle_on_path(ParticleSimulationData *sim,
pind.cache = cached ? psys->pointcache : NULL;
pind.epoint = NULL;
pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE);
- /* pind.dm disabled in editmode means we don't get effectors taken into
- * account when subdividing for instance */
+ /* `pind.dm` disabled in edit-mode means we don't get effectors taken into
+ * account when subdividing for instance. */
pind.mesh = psys_in_edit_mode(sim->depsgraph, psys) ?
NULL :
- psys->hair_out_mesh; /* XXX Sybren EEK */
+ psys->hair_out_mesh; /* XXX(@sybren) EEK. */
init_particle_interpolation(sim->ob, psys, pa, &pind);
do_particle_interpolation(psys, p, pa, t, &pind, state);
@@ -4834,8 +4851,10 @@ void psys_get_particle_on_path(ParticleSimulationData *sim,
}
}
}
-/* gets particle's state at a time, returns 1 if particle exists and can be seen and 0 if not */
-int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *state, int always)
+bool psys_get_particle_state(ParticleSimulationData *sim,
+ int p,
+ ParticleKey *state,
+ const bool always)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
@@ -4850,12 +4869,12 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
if (p >= totpart) {
if (!psys->totchild) {
- return 0;
+ return false;
}
if (part->childtype == PART_CHILD_FACES) {
if (!(psys->flag & PSYS_KEYED)) {
- return 0;
+ return false;
}
cpa = psys->child + p - totpart;
@@ -4865,7 +4884,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
if (!always) {
if ((state->time < 0.0f && !(part->flag & PART_UNBORN)) ||
(state->time > 1.0f && !(part->flag & PART_DIED))) {
- return 0;
+ return false;
}
}
@@ -4873,7 +4892,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
(part->lifetime * psys_frand(psys, p + 24));
psys_get_particle_on_path(sim, p, state, 1);
- return 1;
+ return true;
}
cpa = sim->psys->child + p - totpart;
@@ -4887,7 +4906,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
if (!always) {
if ((cfra < pa->time && (part->flag & PART_UNBORN) == 0) ||
(cfra >= pa->dietime && (part->flag & PART_DIED) == 0)) {
- return 0;
+ return false;
}
}
@@ -4897,7 +4916,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
if (sim->psys->flag & PSYS_KEYED) {
state->time = -cfra;
psys_get_particle_on_path(sim, p, state, 1);
- return 1;
+ return true;
}
if (cpa) {
@@ -4997,7 +5016,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
}
}
- return 1;
+ return true;
}
void psys_get_dupli_texture(ParticleSystem *psys,
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 863476c6638..ba3f99a2800 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -626,7 +626,8 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
/* experimental */
tot = mesh->totface;
- psys_interpolate_face(mvert, mface, 0, 0, pa->fuv, co, nor, 0, 0, 0);
+ psys_interpolate_face(
+ mvert, BKE_mesh_vertex_normals_ensure(mesh), mface, 0, 0, pa->fuv, co, nor, 0, 0, 0);
normalize_v3(nor);
negate_v3(nor);
@@ -997,12 +998,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx,
BKE_mesh_tessface_ensure(mesh);
/* we need orco for consistent distributions */
- if (!CustomData_has_layer(&mesh->vdata, CD_ORCO)) {
- /* Orcos are stored in normalized 0..1 range by convention. */
- float(*orcodata)[3] = BKE_mesh_orco_verts_get(ob);
- BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false);
- CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, orcodata, mesh->totvert);
- }
+ BKE_mesh_orco_ensure(ob, mesh);
if (from == PART_FROM_VERT) {
MVert *mv = mesh->mvert;
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 8986847a034..e489f9e2bac 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -452,7 +452,6 @@ void psys_calc_dmcache(Object *ob, Mesh *mesh_final, Mesh *mesh_original, Partic
}
}
-/* threaded child particle distribution and path caching */
void psys_thread_context_init(ParticleThreadContext *ctx, ParticleSimulationData *sim)
{
memset(ctx, 0, sizeof(ParticleThreadContext));
@@ -591,7 +590,6 @@ static void init_particle_texture(ParticleSimulationData *sim, ParticleData *pa,
}
}
-/* set particle parameters that don't change during particle's life */
void init_particle(ParticleSimulationData *sim, ParticleData *pa)
{
ParticleSettings *part = sim->psys->part;
@@ -1066,7 +1064,6 @@ static void evaluate_emitter_anim(struct Depsgraph *depsgraph,
BKE_object_where_is_calc_time(depsgraph, scene, ob, cfra);
}
-/* sets particle to the emitter surface with initial velocity & rotation */
void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, float cfra)
{
ParticleSystem *psys = sim->psys;
@@ -1157,9 +1154,11 @@ static void reset_all_particles(ParticleSimulationData *sim, float dtime, float
reset_particle(sim, pa, dtime, cfra);
}
}
+
/************************************************/
/* Particle targets */
/************************************************/
+
ParticleSystem *psys_get_target_system(Object *ob, ParticleTarget *pt)
{
ParticleSystem *psys = NULL;
@@ -1180,10 +1179,11 @@ ParticleSystem *psys_get_target_system(Object *ob, ParticleTarget *pt)
return psys;
}
+
/************************************************/
/* Keyed particles */
/************************************************/
-/* Counts valid keyed targets */
+
void psys_count_keyed_targets(ParticleSimulationData *sim)
{
ParticleSystem *psys = sim->psys, *kpsys;
@@ -1288,6 +1288,7 @@ static void set_keyed_keys(ParticleSimulationData *sim)
/************************************************/
/* Point Cache */
/************************************************/
+
void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys)
{
PointCache *cache = psys->pointcache;
@@ -1325,6 +1326,7 @@ static void bvhtree_balance_isolated(void *userdata)
/************************************************/
/* Effectors */
/************************************************/
+
static void psys_update_particle_bvhtree(ParticleSystem *psys, float cfra)
{
if (psys) {
@@ -2181,7 +2183,6 @@ void psys_sph_finalize(SPHData *sphdata)
}
}
-/* Sample the density field at a point in space. */
void psys_sph_density(BVHTree *tree, SPHData *sphdata, float co[3], float vars[2])
{
ParticleSystem **psys = sphdata->psys;
@@ -2234,6 +2235,7 @@ static void sph_integrate(ParticleSimulationData *sim,
/************************************************/
/* Basic physics */
/************************************************/
+
typedef struct EfData {
ParticleTexture ptex;
ParticleSimulationData *sim;
@@ -2787,7 +2789,6 @@ static int collision_sphere_to_verts(ParticleCollision *col,
return hit != NULL;
}
-/* Callback for BVHTree near test */
void BKE_psys_collision_neartest_cb(void *userdata,
int index,
const BVHTreeRay *ray,
@@ -3179,10 +3180,14 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa
}
}
}
+
/************************************************/
/* Hair */
/************************************************/
-/* check if path cache or children need updating and do it if needed */
+
+/**
+ * Check if path cache or children need updating and do it if needed.
+ */
static void psys_update_path_cache(ParticleSimulationData *sim,
float cfra,
const bool use_render_params)
@@ -4627,7 +4632,6 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
}
}
-/* system type has changed so set sensible defaults and clear non applicable flags */
void psys_changed_type(Object *ob, ParticleSystem *psys)
{
ParticleSettings *part = psys->part;
@@ -4765,8 +4769,6 @@ static void particle_settings_free_local(ParticleSettings *particle_settings)
MEM_freeN(particle_settings);
}
-/* main particle update call, checks that things are ok on the large scale and
- * then advances in to actual particle calculations depending on particle type */
void particle_system_update(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index ca1fada8c76..1926bbcda02 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -15,7 +15,7 @@
*/
/** \file
- * \ingroup bli
+ * \ingroup bke
*/
#include "MEM_guardedalloc.h"
@@ -32,7 +32,7 @@
#include "DNA_meshdata_types.h"
#include "BKE_ccg.h"
-#include "BKE_mesh.h" /* for BKE_mesh_calc_normals */
+#include "BKE_mesh.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_subdiv_ccg.h"
@@ -78,7 +78,6 @@ void BB_reset(BB *bb)
bb->bmax[0] = bb->bmax[1] = bb->bmax[2] = -FLT_MAX;
}
-/* Expand the bounding box to include a new coordinate */
void BB_expand(BB *bb, const float co[3])
{
for (int i = 0; i < 3; i++) {
@@ -87,7 +86,6 @@ void BB_expand(BB *bb, const float co[3])
}
}
-/* Expand the bounding box to include another bounding box */
void BB_expand_with_bb(BB *bb, BB *bb2)
{
for (int i = 0; i < 3; i++) {
@@ -96,7 +94,6 @@ void BB_expand_with_bb(BB *bb, BB *bb2)
}
}
-/* Return 0, 1, or 2 to indicate the widest axis of the bounding box */
int BB_widest_axis(const BB *bb)
{
float dim[3];
@@ -351,7 +348,6 @@ static void update_vb(PBVH *pbvh, PBVHNode *node, BBC *prim_bbc, int offset, int
node->orig_vb = node->vb;
}
-/* Returns the number of visible quads in the nodes' grids. */
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
const int *grid_indices,
int totgrid,
@@ -555,14 +551,8 @@ static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim)
build_sub(pbvh, 0, cb, prim_bbc, 0, totprim);
}
-/**
- * Do a full rebuild with on Mesh data structure.
- *
- * \note Unlike mpoly/mloop/verts, looptri is **totally owned** by PBVH
- * (which means it may rewrite it if needed, see #BKE_pbvh_vert_coords_apply().
- */
void BKE_pbvh_build_mesh(PBVH *pbvh,
- const Mesh *mesh,
+ Mesh *mesh,
const MPoly *mpoly,
const MLoop *mloop,
MVert *verts,
@@ -582,6 +572,8 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
pbvh->mloop = mloop;
pbvh->looptri = looptri;
pbvh->verts = verts;
+ BKE_mesh_vertex_normals_ensure(mesh);
+ pbvh->vert_normals = BKE_mesh_vertex_normals_for_write(mesh);
pbvh->vert_bitmap = BLI_BITMAP_NEW(totvert, "bvh->vert_bitmap");
pbvh->totvert = totvert;
pbvh->leaf_limit = LEAF_LIMIT;
@@ -621,7 +613,6 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
MEM_freeN(pbvh->vert_bitmap);
}
-/* Do a full rebuild with on Grids data structure */
void BKE_pbvh_build_grids(PBVH *pbvh,
CCGElem **grids,
int totgrid,
@@ -1087,7 +1078,6 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
* so we know only this thread will handle this vertex. */
if (mvert->flag & ME_VERT_PBVH_UPDATE) {
normalize_v3(vnors[v]);
- normal_float_to_short_v3(mvert->no, vnors[v]);
mvert->flag &= ~ME_VERT_PBVH_UPDATE;
}
}
@@ -1098,10 +1088,6 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
static void pbvh_faces_update_normals(PBVH *pbvh, PBVHNode **nodes, int totnode)
{
- /* could be per node to save some memory, but also means
- * we have to store for each vertex which node it is in */
- float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * pbvh->totvert, __func__);
-
/* subtle assumptions:
* - We know that for all edited vertices, the nodes with faces
* adjacent to these vertices have been marked with PBVH_UpdateNormals.
@@ -1115,7 +1101,7 @@ static void pbvh_faces_update_normals(PBVH *pbvh, PBVHNode **nodes, int totnode)
PBVHUpdateData data = {
.pbvh = pbvh,
.nodes = nodes,
- .vnors = vnors,
+ .vnors = pbvh->vert_normals,
};
TaskParallelSettings settings;
@@ -1123,8 +1109,6 @@ static void pbvh_faces_update_normals(PBVH *pbvh, PBVHNode **nodes, int totnode)
BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings);
-
- MEM_freeN(vnors);
}
static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata,
@@ -1311,6 +1295,7 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
case PBVH_FACES:
GPU_pbvh_mesh_buffers_update(node->draw_buffers,
pbvh->verts,
+ pbvh->vert_normals,
CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK),
CustomData_get_layer(pbvh->ldata, CD_MLOOPCOL),
CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS),
@@ -1379,7 +1364,7 @@ static int pbvh_flush_bb(PBVH *pbvh, PBVHNode *node, int flag)
{
int update = 0;
- /* difficult to multithread well, we just do single threaded recursive */
+ /* Difficult to multi-thread well, we just do single threaded recursive. */
if (node->flag & PBVH_Leaf) {
if (flag & PBVH_UpdateBB) {
update |= (node->flag & PBVH_UpdateBB);
@@ -1954,11 +1939,6 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
*r_orco_coords = node->bm_orco;
}
-/**
- * \note doing a full search on all vertices here seems expensive,
- * however this is important to avoid having to recalculate bound-box & sync the buffers to the
- * GPU (which is far more expensive!) See: T47232.
- */
bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node)
{
BLI_assert(pbvh->type == PBVH_FACES);
@@ -1977,7 +1957,7 @@ bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node)
return false;
}
-/********************************* Raycast ***********************************/
+/********************************* Ray-cast ***********************************/
typedef struct {
struct IsectRayAABB_Precalc ray;
@@ -2798,7 +2778,7 @@ float (*BKE_pbvh_vert_coords_alloc(PBVH *pbvh))[3]
void BKE_pbvh_vert_coords_apply(PBVH *pbvh, const float (*vertCos)[3], const int totvert)
{
if (totvert != pbvh->totvert) {
- BLI_assert_msg(0, "PBVH: Given deforming vcos number does not natch PBVH vertex number!");
+ BLI_assert_msg(0, "PBVH: Given deforming vcos number does not match PBVH vertex number!");
return;
}
@@ -2980,6 +2960,8 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi->mask = NULL;
if (pbvh->type == PBVH_FACES) {
+ vi->vert_normals = pbvh->vert_normals;
+
vi->vmask = CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK);
vi->vcol = CustomData_get_layer(pbvh->vdata, CD_PROP_COLOR);
}
@@ -3053,6 +3035,12 @@ MVert *BKE_pbvh_get_verts(const PBVH *pbvh)
return pbvh->verts;
}
+const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3]
+{
+ BLI_assert(pbvh->type == PBVH_FACES);
+ return pbvh->vert_normals;
+}
+
void BKE_pbvh_subdiv_cgg_set(PBVH *pbvh, SubdivCCG *subdiv_ccg)
{
pbvh->subdiv_ccg = subdiv_ccg;
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index c30f94a4cf6..6f57448b0ab 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -15,7 +15,7 @@
*/
/** \file
- * \ingroup bli
+ * \ingroup bke
*/
#include "MEM_guardedalloc.h"
@@ -1875,7 +1875,6 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
/***************************** Public API *****************************/
-/* Build a PBVH from a BMesh */
void BKE_pbvh_build_bmesh(PBVH *pbvh,
BMesh *bm,
bool smooth_shading,
@@ -1953,7 +1952,6 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
MEM_freeN(nodeinfo);
}
-/* Collapse short edges, subdivide long edges */
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],
@@ -2031,10 +2029,6 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
return modified;
}
-/* In order to perform operations on the original node coordinates
- * (currently just raycast), store the node's triangles and vertices.
- *
- * Skips triangles that are hidden. */
void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, PBVHNode *node)
{
/* Skip if original coords/triangles are already saved */
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 84c4ae4dead..9562cda5f28 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -17,7 +17,7 @@
#pragma once
/** \file
- * \ingroup bli
+ * \ingroup bke
*/
/* Axis-aligned bounding box */
@@ -130,6 +130,9 @@ struct PBVH {
/* Mesh data */
const struct Mesh *mesh;
+
+ /* Note: Normals are not const because they can be updated for drawing by sculpt code. */
+ float (*vert_normals)[3];
MVert *verts;
const MPoly *mpoly;
const MLoop *mloop;
@@ -180,9 +183,18 @@ struct PBVH {
/* pbvh.c */
void BB_reset(BB *bb);
+/**
+ * Expand the bounding box to include a new coordinate.
+ */
void BB_expand(BB *bb, const float co[3]);
+/**
+ * Expand the bounding box to include another bounding box.
+ */
void BB_expand_with_bb(BB *bb, BB *bb2);
void BBC_update_centroid(BBC *bbc);
+/**
+ * Return 0, 1, or 2 to indicate the widest axis of the bounding box.
+ */
int BB_widest_axis(const BB *bb);
void pbvh_grow_nodes(PBVH *bvh, int totnode);
bool ray_face_intersection_quad(const float ray_start[3],
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 57225872c7e..602546db8df 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -266,7 +266,8 @@ static void ptcache_softbody_error(const ID *UNUSED(owner_id),
/* ignored for now */
}
-/* Particle functions */
+/* Particle functions. */
+
void BKE_ptcache_make_particle_key(ParticleKey *key, int index, void **data, float time)
{
PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, index, key->co);
@@ -830,31 +831,23 @@ static void ptcache_rigidbody_interpolate(int index,
RigidBodyOb *rbo = ob->rigidbody_object;
if (rbo->type == RBO_TYPE_ACTIVE) {
- ParticleKey keys[4];
- ParticleKey result;
- float dfra;
-
- memset(keys, 0, sizeof(keys));
-
- copy_v3_v3(keys[1].co, rbo->pos);
- copy_qt_qt(keys[1].rot, rbo->orn);
+ /* It may be possible to improve results by taking into account velocity
+ * for interpolation using psys_interpolate_particle, however this is
+ * not currently cached. */
+ float pos[3], orn[4];
if (old_data) {
- memcpy(keys[2].co, data, sizeof(float[3]));
- memcpy(keys[2].rot, data + 3, sizeof(float[4]));
+ memcpy(pos, data, sizeof(float[3]));
+ memcpy(orn, data + 3, sizeof(float[4]));
}
else {
- BKE_ptcache_make_particle_key(&keys[2], 0, data, cfra2);
+ PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, index, pos);
+ PTCACHE_DATA_TO(data, BPHYS_DATA_ROTATION, index, orn);
}
- dfra = cfra2 - cfra1;
-
- /* NOTE: keys[0] and keys[3] unused for type < 1 (crappy). */
- psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, &result, true);
- interp_qt_qtqt(result.rot, keys[1].rot, keys[2].rot, (cfra - cfra1) / dfra);
-
- copy_v3_v3(rbo->pos, result.co);
- copy_qt_qt(rbo->orn, result.rot);
+ const float t = (cfra - cfra1) / (cfra2 - cfra1);
+ interp_v3_v3v3(rbo->pos, rbo->pos, pos, t);
+ interp_qt_qtqt(rbo->orn, rbo->orn, orn, t);
}
}
}
@@ -873,6 +866,7 @@ static void ptcache_rigidbody_error(const struct ID *UNUSED(owner_id),
}
/* Creating ID's */
+
void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
{
memset(pid, 0, sizeof(PTCacheID));
@@ -1008,9 +1002,6 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl
pid->file_type = PTCACHE_FILE_PTCACHE;
}
-/* The fluid modifier does not actually use this anymore, but some parts of Blender expect that it
- * still has a point cache currently. For example, the fluid modifier uses
- * #DEG_add_collision_relations, which internally creates relations with the point cache. */
void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct FluidModifierData *fmd)
{
FluidDomainSettings *fds = fmd->domain;
@@ -1104,10 +1095,6 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
pid->file_type = PTCACHE_FILE_PTCACHE;
}
-/**
- * \param ob: Optional, may be NULL.
- * \param scene: Optional may be NULL.
- */
PTCacheID BKE_ptcache_id_find(Object *ob, Scene *scene, PointCache *cache)
{
PTCacheID result = {0};
@@ -1327,10 +1314,11 @@ static int ptcache_frame_from_filename(const char *filename, const char *ext)
static int ptcache_path(PTCacheID *pid, char *filename)
{
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
Library *lib = (pid->owner_id) ? pid->owner_id->lib : NULL;
const char *blendfilename = (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH) == 0) ?
lib->filepath_abs :
- BKE_main_blendfile_path_from_global();
+ blendfile_path;
size_t i;
if (pid->cache->flag & PTCACHE_EXTERNAL) {
@@ -1342,7 +1330,7 @@ static int ptcache_path(PTCacheID *pid, char *filename)
return BLI_path_slash_ensure(filename); /* new strlen() */
}
- if (G.relbase_valid || lib) {
+ if ((blendfile_path[0] != '\0') || lib) {
char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */
BLI_split_file_part(blendfilename, file, sizeof(file));
@@ -1427,8 +1415,11 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p
filename[0] = '\0';
newname = filename;
- if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
- return 0; /* save blend file before using disk pointcache */
+ if ((pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] == '\0') {
+ return 0; /* save blend file before using disk pointcache */
+ }
}
/* start with temp dir */
@@ -1474,8 +1465,11 @@ static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra)
return NULL;
}
#endif
- if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
- return NULL; /* save blend file before using disk pointcache */
+ if ((pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] == '\0') {
+ return NULL; /* save blend file before using disk pointcache */
+ }
}
ptcache_filename(pid, filename, cfra, 1, 1);
@@ -1713,7 +1707,8 @@ static int ptcache_file_header_begin_write(PTCacheFile *pf)
return 1;
}
-/* Data pointer handling */
+/* Data pointer handling. */
+
int BKE_ptcache_data_size(int data_type)
{
return ptcache_data_size[data_type];
@@ -1734,7 +1729,6 @@ static void ptcache_file_pointers_init(PTCacheFile *pf)
pf->cur[BPHYS_DATA_BOIDS] = (data_types & (1 << BPHYS_DATA_BOIDS)) ? &pf->data.boids : NULL;
}
-/* Check to see if point number "index" is in pm, uses binary search for index data. */
int BKE_ptcache_mem_index_find(PTCacheMem *pm, unsigned int index)
{
if (pm->totpoint > 0 && pm->data[BPHYS_DATA_INDEX]) {
@@ -2288,7 +2282,6 @@ static int ptcache_interpolate(PTCacheID *pid, float cfra, int cfra1, int cfra2)
return 1;
}
/* reads cache from disk or memory */
-/* possible to get old or interpolated result */
int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old)
{
int cfrai = (int)floor(cfra), cfra1 = 0, cfra2 = 0;
@@ -2549,7 +2542,6 @@ static int ptcache_write_needed(PTCacheID *pid, int cfra, int *overwrite)
return 0;
}
-/* writes cache to disk or memory */
int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
{
PointCache *cache = pid->cache;
@@ -2600,7 +2592,8 @@ int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
* mode - PTCACHE_CLEAR_ALL,
*/
-/* Clears & resets */
+/* Clears & resets. */
+
void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
{
unsigned int len; /* store the length of the string */
@@ -2632,8 +2625,6 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
}
#endif
- // if (!G.relbase_valid) return; /* Save blend file before using pointcache. */
-
/* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */
switch (mode) {
case PTCACHE_CLEAR_ALL:
@@ -3014,50 +3005,6 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
return reset;
}
-/* Use this when quitting blender, with unsaved files */
-void BKE_ptcache_remove(void)
-{
- char path[MAX_PTCACHE_PATH];
- char path_full[MAX_PTCACHE_PATH];
- int rmdir = 1;
-
- ptcache_path(NULL, path);
-
- if (BLI_exists(path)) {
- /* The pointcache dir exists? - remove all pointcache */
-
- DIR *dir;
- struct dirent *de;
-
- dir = opendir(path);
- if (dir == NULL) {
- return;
- }
-
- while ((de = readdir(dir)) != NULL) {
- if (FILENAME_IS_CURRPAR(de->d_name)) {
- /* do nothing */
- }
- else if (strstr(de->d_name, PTCACHE_EXT)) { /* Do we have the right extension? */
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
- BLI_delete(path_full, false, false);
- }
- else {
- rmdir = 0; /* unknown file, don't remove the dir */
- }
- }
-
- closedir(dir);
- }
- else {
- rmdir = 0; /* Path doesn't exist. */
- }
-
- if (rmdir) {
- BLI_delete(path, true, false);
- }
-}
-
/* Point Cache handling */
PointCache *BKE_ptcache_add(ListBase *ptcaches)
@@ -3150,7 +3097,6 @@ static PointCache *ptcache_copy(PointCache *cache, const bool copy_data)
return ncache;
}
-/* returns first point cache */
PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new,
const ListBase *ptcaches_old,
const int flag)
@@ -3170,6 +3116,7 @@ PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new,
* every user action changing stuff, and then it runs a complete bake??? (ton) */
/* Baking */
+
void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
PTCacheBaker baker;
@@ -3202,7 +3149,6 @@ static void ptcache_dt_to_str(char *str, double dtime)
}
}
-/* if bake is not given run simulations to current frame */
void BKE_ptcache_bake(PTCacheBaker *baker)
{
Scene *scene = baker->scene;
@@ -3439,7 +3385,9 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
/* TODO: call redraw all windows somehow */
}
+
/* Helpers */
+
void BKE_ptcache_disk_to_mem(PTCacheID *pid)
{
PointCache *cache = pid->cache;
@@ -3495,8 +3443,9 @@ void BKE_ptcache_toggle_disk_cache(PTCacheID *pid)
{
PointCache *cache = pid->cache;
int last_exact = cache->last_exact;
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
- if (!G.relbase_valid) {
+ if (blendfile_path[0] == '\0') {
cache->flag &= ~PTCACHE_DISK_CACHE;
if (G.debug & G_DEBUG) {
printf("File must be saved before using disk cache!\n");
@@ -3548,6 +3497,11 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c
char old_path_full[MAX_PTCACHE_FILE];
char ext[MAX_PTCACHE_PATH];
+ /* If both names are the same, there is nothing to do. */
+ if (STREQ(name_src, name_dst)) {
+ return;
+ }
+
/* save old name */
BLI_strncpy(old_name, pid->cache->name, sizeof(old_name));
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index 1db14dc3dc8..b5f016e4d76 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -25,10 +25,13 @@
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_rand.h"
+#include "BLI_span.hh"
#include "BLI_string.h"
+#include "BLI_task.hh"
#include "BLI_utildefines.h"
#include "BKE_anim_data.h"
@@ -51,6 +54,10 @@
#include "BLO_read_write.h"
+using blender::float3;
+using blender::IndexRange;
+using blender::Span;
+
/* PointCloud datablock */
static void pointcloud_random(PointCloud *pointcloud);
@@ -79,7 +86,7 @@ static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_s
{
PointCloud *pointcloud_dst = (PointCloud *)id_dst;
const PointCloud *pointcloud_src = (const PointCloud *)id_src;
- pointcloud_dst->mat = static_cast<Material **>(MEM_dupallocN(pointcloud_dst->mat));
+ pointcloud_dst->mat = static_cast<Material **>(MEM_dupallocN(pointcloud_src->mat));
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
CustomData_copy(&pointcloud_src->pdata,
@@ -105,7 +112,7 @@ static void pointcloud_foreach_id(ID *id, LibraryForeachIDData *data)
{
PointCloud *pointcloud = (PointCloud *)id;
for (int i = 0; i < pointcloud->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, pointcloud->mat[i], IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, pointcloud->mat[i], IDWALK_CB_USER);
}
}
@@ -175,6 +182,7 @@ IDTypeInfo IDType_ID_PT = {
/* name_plural */ "pointclouds",
/* translation_context */ BLT_I18NCONTEXT_ID_POINTCLOUD,
/* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
/* init_data */ pointcloud_init_data,
/* copy_data */ pointcloud_copy_data,
@@ -182,6 +190,7 @@ IDTypeInfo IDType_ID_PT = {
/* make_local */ nullptr,
/* foreach_id */ pointcloud_foreach_id,
/* foreach_cache */ nullptr,
+ /* foreach_path */ nullptr,
/* owner_get */ nullptr,
/* blend_write */ pointcloud_blend_write,
@@ -259,18 +268,70 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
return pointcloud;
}
-void BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3])
+struct MinMaxResult {
+ float3 min;
+ float3 max;
+};
+
+static MinMaxResult min_max_no_radii(Span<float3> positions)
+{
+ using namespace blender::math;
+
+ return blender::threading::parallel_reduce(
+ positions.index_range(),
+ 1024,
+ MinMaxResult{float3(FLT_MAX), float3(-FLT_MAX)},
+ [&](IndexRange range, const MinMaxResult &init) {
+ MinMaxResult result = init;
+ for (const int i : range) {
+ min_max(positions[i], result.min, result.max);
+ }
+ return result;
+ },
+ [](const MinMaxResult &a, const MinMaxResult &b) {
+ return MinMaxResult{min(a.min, b.min), max(a.max, b.max)};
+ });
+}
+
+static MinMaxResult min_max_with_radii(Span<float3> positions, Span<float> radii)
{
- float(*pointcloud_co)[3] = pointcloud->co;
- float *pointcloud_radius = pointcloud->radius;
- for (int a = 0; a < pointcloud->totpoint; a++) {
- float *co = pointcloud_co[a];
- float radius = (pointcloud_radius) ? pointcloud_radius[a] : 0.0f;
- const float co_min[3] = {co[0] - radius, co[1] - radius, co[2] - radius};
- const float co_max[3] = {co[0] + radius, co[1] + radius, co[2] + radius};
- DO_MIN(co_min, r_min);
- DO_MAX(co_max, r_max);
+ using namespace blender::math;
+
+ return blender::threading::parallel_reduce(
+ positions.index_range(),
+ 1024,
+ MinMaxResult{float3(FLT_MAX), float3(-FLT_MAX)},
+ [&](IndexRange range, const MinMaxResult &init) {
+ MinMaxResult result = init;
+ for (const int i : range) {
+ result.min = min(positions[i] - radii[i], result.min);
+ result.max = max(positions[i] + radii[i], result.max);
+ }
+ return result;
+ },
+ [](const MinMaxResult &a, const MinMaxResult &b) {
+ return MinMaxResult{min(a.min, b.min), max(a.max, b.max)};
+ });
+}
+
+bool BKE_pointcloud_minmax(const PointCloud *pointcloud, float r_min[3], float r_max[3])
+{
+ using namespace blender::math;
+
+ if (!pointcloud->totpoint) {
+ return false;
}
+
+ Span<float3> positions{reinterpret_cast<float3 *>(pointcloud->co), pointcloud->totpoint};
+ const MinMaxResult min_max = (pointcloud->radius) ?
+ min_max_with_radii(positions,
+ {pointcloud->radius, pointcloud->totpoint}) :
+ min_max_no_radii(positions);
+
+ copy_v3_v3(r_min, min(min_max.min, float3(r_min)));
+ copy_v3_v3(r_max, max(min_max.max, float3(r_max)));
+
+ return true;
}
BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
@@ -285,7 +346,7 @@ BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
ob->runtime.bb = static_cast<BoundBox *>(MEM_callocN(sizeof(BoundBox), "pointcloud boundbox"));
}
- blender::float3 min, max;
+ float3 min, max;
INIT_MINMAX(min, max);
if (ob->runtime.geometry_set_eval != nullptr) {
ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max);
@@ -417,6 +478,7 @@ void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene
}
/* Draw Cache */
+
void (*BKE_pointcloud_batch_cache_dirty_tag_cb)(PointCloud *pointcloud, int mode) = nullptr;
void (*BKE_pointcloud_batch_cache_free_cb)(PointCloud *pointcloud) = nullptr;
diff --git a/source/blender/blenkernel/intern/preferences.c b/source/blender/blenkernel/intern/preferences.c
index 0b8e8d7c311..4bb2231bbb1 100644
--- a/source/blender/blenkernel/intern/preferences.c
+++ b/source/blender/blenkernel/intern/preferences.c
@@ -24,6 +24,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_fileops.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
@@ -61,10 +62,6 @@ bUserAssetLibrary *BKE_preferences_asset_library_add(UserDef *userdef,
return library;
}
-/**
- * Unlink and free a library preference member.
- * \note Free's \a library itself.
- */
void BKE_preferences_asset_library_remove(UserDef *userdef, bUserAssetLibrary *library)
{
BLI_freelinkN(&userdef->asset_libraries, library);
@@ -83,6 +80,14 @@ void BKE_preferences_asset_library_name_set(UserDef *userdef,
sizeof(library->name));
}
+void BKE_preferences_asset_library_path_set(bUserAssetLibrary *library, const char *path)
+{
+ BLI_strncpy(library->path, path, sizeof(library->path));
+ if (BLI_is_file(library->path)) {
+ BLI_path_parent_dir(library->path);
+ }
+}
+
bUserAssetLibrary *BKE_preferences_asset_library_find_from_index(const UserDef *userdef, int index)
{
return BLI_findlink(&userdef->asset_libraries, index);
@@ -120,7 +125,8 @@ void BKE_preferences_asset_library_default_add(UserDef *userdef)
return;
}
- bUserAssetLibrary *library = BKE_preferences_asset_library_add(userdef, DATA_("Default"), NULL);
+ bUserAssetLibrary *library = BKE_preferences_asset_library_add(
+ userdef, DATA_(BKE_PREFS_ASSET_LIBRARY_DEFAULT_NAME), NULL);
/* Add new "Default" library under '[doc_path]/Blender/Assets'. */
BLI_path_join(
diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c
index c877ec6b6b0..bc11861f2c8 100644
--- a/source/blender/blenkernel/intern/report.c
+++ b/source/blender/blenkernel/intern/report.c
@@ -37,7 +37,7 @@
#include "BKE_global.h" /* G.background only */
#include "BKE_report.h"
-const char *BKE_report_type_str(ReportType type)
+const char *BKE_report_type_str(eReportType type)
{
switch (type) {
case RPT_DEBUG:
@@ -76,11 +76,6 @@ void BKE_reports_init(ReportList *reports, int flag)
reports->flag = flag;
}
-/**
- * Only frees the list \a reports.
- * To make displayed reports disappear, either remove window-manager reports
- * (wmWindowManager.reports, or CTX_wm_reports()), or use #WM_report_banners_cancel().
- */
void BKE_reports_clear(ReportList *reports)
{
Report *report, *report_next;
@@ -101,7 +96,7 @@ void BKE_reports_clear(ReportList *reports)
BLI_listbase_clear(&reports->list);
}
-void BKE_report(ReportList *reports, ReportType type, const char *_message)
+void BKE_report(ReportList *reports, eReportType type, const char *_message)
{
Report *report;
int len;
@@ -129,7 +124,7 @@ void BKE_report(ReportList *reports, ReportType type, const char *_message)
}
}
-void BKE_reportf(ReportList *reports, ReportType type, const char *_format, ...)
+void BKE_reportf(ReportList *reports, eReportType type, const char *_format, ...)
{
DynStr *ds;
Report *report;
@@ -215,7 +210,7 @@ void BKE_reports_prependf(ReportList *reports, const char *_prepend, ...)
}
}
-ReportType BKE_report_print_level(ReportList *reports)
+eReportType BKE_report_print_level(ReportList *reports)
{
if (!reports) {
return RPT_ERROR;
@@ -224,7 +219,7 @@ ReportType BKE_report_print_level(ReportList *reports)
return reports->printlevel;
}
-void BKE_report_print_level_set(ReportList *reports, ReportType level)
+void BKE_report_print_level_set(ReportList *reports, eReportType level)
{
if (!reports) {
return;
@@ -233,7 +228,7 @@ void BKE_report_print_level_set(ReportList *reports, ReportType level)
reports->printlevel = level;
}
-ReportType BKE_report_store_level(ReportList *reports)
+eReportType BKE_report_store_level(ReportList *reports)
{
if (!reports) {
return RPT_ERROR;
@@ -242,7 +237,7 @@ ReportType BKE_report_store_level(ReportList *reports)
return reports->storelevel;
}
-void BKE_report_store_level_set(ReportList *reports, ReportType level)
+void BKE_report_store_level_set(ReportList *reports, eReportType level)
{
if (!reports) {
return;
@@ -251,7 +246,7 @@ void BKE_report_store_level_set(ReportList *reports, ReportType level)
reports->storelevel = level;
}
-char *BKE_reports_string(ReportList *reports, ReportType level)
+char *BKE_reports_string(ReportList *reports, eReportType level)
{
Report *report;
DynStr *ds;
@@ -279,7 +274,7 @@ char *BKE_reports_string(ReportList *reports, ReportType level)
return cstring;
}
-void BKE_reports_print(ReportList *reports, ReportType level)
+void BKE_reports_print(ReportList *reports, eReportType level)
{
char *cstring = BKE_reports_string(reports, level);
@@ -305,7 +300,7 @@ Report *BKE_reports_last_displayable(ReportList *reports)
return NULL;
}
-bool BKE_reports_contain(ReportList *reports, ReportType level)
+bool BKE_reports_contain(ReportList *reports, eReportType level)
{
Report *report;
if (reports != NULL) {
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 328c54fc21b..75e9bc2fbee 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup blenkernel
+ * \ingroup bke
* \brief Blender-side interface and methods for dealing with Rigid Body simulations
*/
@@ -103,7 +103,6 @@ static void RB_constraint_delete(void *UNUSED(con))
#endif
-/* Free rigidbody world */
void BKE_rigidbody_free_world(Scene *scene)
{
bool is_orig = (scene->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0;
@@ -160,7 +159,6 @@ void BKE_rigidbody_free_world(Scene *scene)
MEM_freeN(rbw);
}
-/* Free RigidBody settings and sim instances */
void BKE_rigidbody_free_object(Object *ob, RigidBodyWorld *rbw)
{
bool is_orig = (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0;
@@ -208,7 +206,6 @@ void BKE_rigidbody_free_object(Object *ob, RigidBodyWorld *rbw)
ob->rigidbody_object = NULL;
}
-/* Free RigidBody constraint and sim instance */
void BKE_rigidbody_free_constraint(Object *ob)
{
RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL;
@@ -302,7 +299,7 @@ void BKE_rigidbody_object_copy(Main *bmain, Object *ob_dst, const Object *ob_src
ob_dst->rigidbody_object = rigidbody_copy_object(ob_src, flag);
ob_dst->rigidbody_constraint = rigidbody_copy_constraint(ob_src, flag);
- if (flag & LIB_ID_CREATE_NO_MAIN) {
+ if ((flag & (LIB_ID_CREATE_NO_MAIN | LIB_ID_COPY_RIGID_BODY_NO_COLLECTION_HANDLING)) != 0) {
return;
}
@@ -637,8 +634,6 @@ static void rigidbody_validate_sim_shape(RigidBodyWorld *rbw, Object *ob, bool r
/* --------------------- */
-/* helper function to calculate volume of rigidbody object */
-/* TODO: allow a parameter to specify method used to calculate this? */
void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
{
RigidBodyOb *rbo = ob->rigidbody_object;
@@ -1133,12 +1128,6 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
/* --------------------- */
-/**
- * Create physics sim world given RigidBody world settings
- *
- * \note this does NOT update object references that the scene uses,
- * in case those aren't ready yet!
- */
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
/* sanity checks */
@@ -1161,7 +1150,6 @@ void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool re
/* ************************************** */
/* Setup Utilities - Create Settings Blocks */
-/* Set up RigidBody world */
RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene)
{
/* try to get whatever RigidBody world that might be representing this already */
@@ -1211,8 +1199,8 @@ RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag)
id_us_plus((ID *)rbw_copy->constraints);
}
- if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- /* This is a regular copy, and not a CoW copy for depsgraph evaluation */
+ if ((flag & LIB_ID_COPY_SET_COPIED_ON_WRITE) == 0) {
+ /* This is a regular copy, and not a CoW copy for depsgraph evaluation. */
rbw_copy->shared = MEM_callocN(sizeof(*rbw_copy->shared), "RigidBodyWorld_Shared");
BKE_ptcache_copy_list(&rbw_copy->shared->ptcaches, &rbw->shared->ptcaches, LIB_ID_COPY_CACHES);
rbw_copy->shared->pointcache = rbw_copy->shared->ptcaches.first;
@@ -1246,7 +1234,6 @@ void BKE_rigidbody_world_id_loop(RigidBodyWorld *rbw, RigidbodyWorldIDFunc func,
}
}
-/* Add rigid body settings to the specified object */
RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
{
RigidBodyOb *rbo;
@@ -1309,7 +1296,6 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
return rbo;
}
-/* Add rigid body constraint to the specified object */
RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type)
{
RigidBodyCon *rbc;
@@ -1429,11 +1415,6 @@ void BKE_rigidbody_main_collection_object_add(Main *bmain, Collection *collectio
/* ************************************** */
/* Utilities API */
-/**
- * Get RigidBody world for the given scene, creating one if needed
- *
- * \param scene: Scene to find active Rigid Body world for.
- */
RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene)
{
/* sanity check */
@@ -1473,16 +1454,51 @@ static bool rigidbody_add_object_to_scene(Main *bmain, Scene *scene, Object *ob)
return true;
}
-void BKE_rigidbody_ensure_local_object(Main *bmain, Object *ob)
+static bool rigidbody_add_constraint_to_scene(Main *bmain, Scene *scene, Object *ob)
{
- if (ob->rigidbody_object == NULL) {
- return;
+ /* Add rigid body world and group if they don't exist for convenience */
+ RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
+ if (rbw == NULL) {
+ rbw = BKE_rigidbody_create_world(scene);
+ if (rbw == NULL) {
+ return false;
+ }
+
+ BKE_rigidbody_validate_sim_world(scene, rbw, false);
+ scene->rigidbody_world = rbw;
}
- /* Add newly local object to scene. */
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- if (BKE_scene_object_find(scene, ob)) {
- rigidbody_add_object_to_scene(bmain, scene, ob);
+ if (rbw->constraints == NULL) {
+ rbw->constraints = BKE_collection_add(bmain, NULL, "RigidBodyConstraints");
+ id_fake_user_set(&rbw->constraints->id);
+ }
+
+ /* Add object to rigid body group. */
+ BKE_collection_object_add(bmain, rbw->constraints, ob);
+ BKE_rigidbody_cache_reset(rbw);
+
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&rbw->constraints->id, ID_RECALC_COPY_ON_WRITE);
+
+ return true;
+}
+
+void BKE_rigidbody_ensure_local_object(Main *bmain, Object *ob)
+{
+ if (ob->rigidbody_object != NULL) {
+ /* Add newly local object to scene. */
+ for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ if (BKE_scene_object_find(scene, ob)) {
+ rigidbody_add_object_to_scene(bmain, scene, ob);
+ }
+ }
+ }
+ if (ob->rigidbody_constraint != NULL) {
+ /* Add newly local object to scene. */
+ for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ if (BKE_scene_object_find(scene, ob)) {
+ rigidbody_add_constraint_to_scene(bmain, scene, ob);
+ }
}
}
}
@@ -2023,7 +2039,6 @@ bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime)
return (rbw && (rbw->flag & RBW_FLAG_MUTED) == 0 && ctime > rbw->shared->pointcache->startframe);
}
-/* Sync rigid body and object transformations */
void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime)
{
if (!BKE_rigidbody_is_affected_by_simulation(ob)) {
@@ -2054,7 +2069,6 @@ void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime)
}
}
-/* Used when canceling transforms - return rigidbody and object to initial states */
void BKE_rigidbody_aftertrans_update(
Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle)
{
@@ -2133,8 +2147,6 @@ void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
/* ------------------ */
-/* Rebuild rigid body world */
-/* NOTE: this needs to be called before frame update to work correctly */
void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
@@ -2174,7 +2186,6 @@ void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime
}
}
-/* Run RigidBody simulation for the specified physics world */
void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
@@ -2272,6 +2283,7 @@ void BKE_rigidbody_object_copy(Main *bmain, Object *ob_dst, const Object *ob_src
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
}
+
void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
{
if (r_vol) {
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 03f19cef94e..916a2786a98 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -71,6 +71,7 @@
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
+#include "BKE_bpath.h"
#include "BKE_cachefile.h"
#include "BKE_collection.h"
#include "BKE_colortools.h"
@@ -239,7 +240,7 @@ static void scene_init_data(ID *id)
/* Master Collection */
scene->master_collection = BKE_collection_master_add();
- BKE_view_layer_add(scene, "View Layer", NULL, VIEWLAYER_ADD_NEW);
+ BKE_view_layer_add(scene, "ViewLayer", NULL, VIEWLAYER_ADD_NEW);
}
static void scene_copy_markers(Scene *scene_dst, const Scene *scene_src, const int flag)
@@ -471,7 +472,8 @@ static void scene_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSE
int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag));
}
/**
@@ -522,7 +524,10 @@ static void scene_foreach_toolsettings_id_pointer_process(
}
}
-#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS( \
+/* Special handling is needed here, as `scene_foreach_toolsettings` (and its dependency
+ * `scene_foreach_paint`) are also used by `scene_undo_preserve`, where `LibraryForeachIDData
+ * *data` is NULL. */
+#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER( \
__data, __id, __do_undo_restore, __action, __reader, __id_old, __cb_flag) \
{ \
if (__do_undo_restore) { \
@@ -530,7 +535,21 @@ static void scene_foreach_toolsettings_id_pointer_process(
(ID **)&(__id), __action, __reader, (ID **)&(__id_old), __cb_flag); \
} \
else { \
- BKE_LIB_FOREACHID_PROCESS(__data, __id, __cb_flag); \
+ BLI_assert((__data) != NULL); \
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(__data, __id, __cb_flag); \
+ } \
+ } \
+ (void)0
+
+#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( \
+ __data, __do_undo_restore, __func_call) \
+ { \
+ if (__do_undo_restore) { \
+ __func_call; \
+ } \
+ else { \
+ BLI_assert((__data) != NULL); \
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(__data, __func_call); \
} \
} \
(void)0
@@ -541,13 +560,13 @@ static void scene_foreach_paint(LibraryForeachIDData *data,
BlendLibReader *reader,
Paint *paint_old)
{
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- paint->brush,
- do_undo_restore,
- SCENE_FOREACH_UNDO_RESTORE,
- reader,
- paint_old->brush,
- IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ paint->brush,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_RESTORE,
+ reader,
+ paint_old->brush,
+ IDWALK_CB_USER);
for (int i = 0; i < paint_old->tool_slots_len; i++) {
/* This is a bit tricky.
* - In case we do not do `undo_restore`, `paint` and `paint_old` pointers are the same, so
@@ -559,21 +578,21 @@ static void scene_foreach_paint(LibraryForeachIDData *data,
*/
Brush *brush_tmp = NULL;
Brush **brush_p = i < paint->tool_slots_len ? &paint->tool_slots[i].brush : &brush_tmp;
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- *brush_p,
- do_undo_restore,
- SCENE_FOREACH_UNDO_RESTORE,
- reader,
- paint_old->brush,
- IDWALK_CB_USER);
- }
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- paint->palette,
- do_undo_restore,
- SCENE_FOREACH_UNDO_RESTORE,
- reader,
- paint_old->palette,
- IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ *brush_p,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_RESTORE,
+ reader,
+ paint_old->brush,
+ IDWALK_CB_USER);
+ }
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ paint->palette,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_RESTORE,
+ reader,
+ paint_old->palette,
+ IDWALK_CB_USER);
}
static void scene_foreach_toolsettings(LibraryForeachIDData *data,
@@ -582,110 +601,152 @@ static void scene_foreach_toolsettings(LibraryForeachIDData *data,
BlendLibReader *reader,
ToolSettings *toolsett_old)
{
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->particle.scene,
- do_undo_restore,
- SCENE_FOREACH_UNDO_NO_RESTORE,
- reader,
- toolsett_old->particle.scene,
- IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->particle.object,
- do_undo_restore,
- SCENE_FOREACH_UNDO_NO_RESTORE,
- reader,
- toolsett_old->particle.object,
- IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->particle.shape_object,
- do_undo_restore,
- SCENE_FOREACH_UNDO_NO_RESTORE,
- reader,
- toolsett_old->particle.shape_object,
- IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->particle.scene,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_NO_RESTORE,
+ reader,
+ toolsett_old->particle.scene,
+ IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->particle.object,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_NO_RESTORE,
+ reader,
+ toolsett_old->particle.object,
+ IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->particle.shape_object,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_NO_RESTORE,
+ reader,
+ toolsett_old->particle.shape_object,
+ IDWALK_CB_NOP);
scene_foreach_paint(
data, &toolsett->imapaint.paint, do_undo_restore, reader, &toolsett_old->imapaint.paint);
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->imapaint.stencil,
- do_undo_restore,
- SCENE_FOREACH_UNDO_RESTORE,
- reader,
- toolsett_old->imapaint.stencil,
- IDWALK_CB_USER);
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->imapaint.clone,
- do_undo_restore,
- SCENE_FOREACH_UNDO_RESTORE,
- reader,
- toolsett_old->imapaint.clone,
- IDWALK_CB_USER);
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->imapaint.canvas,
- do_undo_restore,
- SCENE_FOREACH_UNDO_RESTORE,
- reader,
- toolsett_old->imapaint.canvas,
- IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->imapaint.stencil,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_RESTORE,
+ reader,
+ toolsett_old->imapaint.stencil,
+ IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->imapaint.clone,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_RESTORE,
+ reader,
+ toolsett_old->imapaint.clone,
+ IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->imapaint.canvas,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_RESTORE,
+ reader,
+ toolsett_old->imapaint.canvas,
+ IDWALK_CB_USER);
if (toolsett->vpaint) {
- scene_foreach_paint(
- data, &toolsett->vpaint->paint, do_undo_restore, reader, &toolsett_old->vpaint->paint);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->vpaint->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->vpaint->paint));
}
if (toolsett->wpaint) {
- scene_foreach_paint(
- data, &toolsett->wpaint->paint, do_undo_restore, reader, &toolsett_old->wpaint->paint);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->wpaint->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->wpaint->paint));
}
if (toolsett->sculpt) {
- scene_foreach_paint(
- data, &toolsett->sculpt->paint, do_undo_restore, reader, &toolsett_old->sculpt->paint);
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->sculpt->gravity_object,
- do_undo_restore,
- SCENE_FOREACH_UNDO_NO_RESTORE,
- reader,
- toolsett_old->sculpt->gravity_object,
- IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->sculpt->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->sculpt->paint));
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->sculpt->gravity_object,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_NO_RESTORE,
+ reader,
+ toolsett_old->sculpt->gravity_object,
+ IDWALK_CB_NOP);
}
if (toolsett->uvsculpt) {
- scene_foreach_paint(
- data, &toolsett->uvsculpt->paint, do_undo_restore, reader, &toolsett_old->uvsculpt->paint);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->uvsculpt->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->uvsculpt->paint));
}
if (toolsett->gp_paint) {
- scene_foreach_paint(
- data, &toolsett->gp_paint->paint, do_undo_restore, reader, &toolsett_old->gp_paint->paint);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->gp_paint->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->gp_paint->paint));
}
if (toolsett->gp_vertexpaint) {
- scene_foreach_paint(data,
- &toolsett->gp_vertexpaint->paint,
- do_undo_restore,
- reader,
- &toolsett_old->gp_vertexpaint->paint);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->gp_vertexpaint->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->gp_vertexpaint->paint));
}
if (toolsett->gp_sculptpaint) {
- scene_foreach_paint(data,
- &toolsett->gp_sculptpaint->paint,
- do_undo_restore,
- reader,
- &toolsett_old->gp_sculptpaint->paint);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->gp_sculptpaint->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->gp_sculptpaint->paint));
}
if (toolsett->gp_weightpaint) {
- scene_foreach_paint(data,
- &toolsett->gp_weightpaint->paint,
- do_undo_restore,
- reader,
- &toolsett_old->gp_weightpaint->paint);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
+ data,
+ do_undo_restore,
+ scene_foreach_paint(data,
+ &toolsett->gp_weightpaint->paint,
+ do_undo_restore,
+ reader,
+ &toolsett_old->gp_weightpaint->paint));
}
- BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data,
- toolsett->gp_sculpt.guide.reference_object,
- do_undo_restore,
- SCENE_FOREACH_UNDO_NO_RESTORE,
- reader,
- toolsett_old->gp_sculpt.guide.reference_object,
- IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data,
+ toolsett->gp_sculpt.guide.reference_object,
+ do_undo_restore,
+ SCENE_FOREACH_UNDO_NO_RESTORE,
+ reader,
+ toolsett_old->gp_sculpt.guide.reference_object,
+ IDWALK_CB_NOP);
}
+#undef BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER
+#undef BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL
+
static void scene_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb)
{
LISTBASE_FOREACH (LayerCollection *, lc, lb) {
@@ -695,7 +756,7 @@ static void scene_foreach_layer_collection(LibraryForeachIDData *data, ListBase
(lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
IDWALK_CB_EMBEDDED :
IDWALK_CB_NOP;
- BKE_LIB_FOREACHID_PROCESS(data, lc->collection, cb_flag);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, lc->collection, cb_flag);
scene_foreach_layer_collection(data, &lc->layer_collections);
}
}
@@ -704,32 +765,33 @@ static bool seq_foreach_member_id_cb(Sequence *seq, void *user_data)
{
LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
-#define FOREACHID_PROCESS(_data, _id_super, _cb_flag) \
+#define FOREACHID_PROCESS_IDSUPER(_data, _id_super, _cb_flag) \
{ \
CHECK_TYPE(&((_id_super)->id), ID *); \
- if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag))) { \
+ BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag)); \
+ if (BKE_lib_query_foreachid_iter_stop((_data))) { \
return false; \
} \
} \
((void)0)
- FOREACHID_PROCESS(data, seq->scene, IDWALK_CB_NEVER_SELF);
- FOREACHID_PROCESS(data, seq->scene_camera, IDWALK_CB_NOP);
- FOREACHID_PROCESS(data, seq->clip, IDWALK_CB_USER);
- FOREACHID_PROCESS(data, seq->mask, IDWALK_CB_USER);
- FOREACHID_PROCESS(data, seq->sound, IDWALK_CB_USER);
+ FOREACHID_PROCESS_IDSUPER(data, seq->scene, IDWALK_CB_NEVER_SELF);
+ FOREACHID_PROCESS_IDSUPER(data, seq->scene_camera, IDWALK_CB_NOP);
+ FOREACHID_PROCESS_IDSUPER(data, seq->clip, IDWALK_CB_USER);
+ FOREACHID_PROCESS_IDSUPER(data, seq->mask, IDWALK_CB_USER);
+ FOREACHID_PROCESS_IDSUPER(data, seq->sound, IDWALK_CB_USER);
IDP_foreach_property(
seq->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) {
- FOREACHID_PROCESS(data, smd->mask_id, IDWALK_CB_USER);
+ FOREACHID_PROCESS_IDSUPER(data, smd->mask_id, IDWALK_CB_USER);
}
if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) {
TextVars *text_data = seq->effectdata;
- FOREACHID_PROCESS(data, text_data->text_font, IDWALK_CB_USER);
+ FOREACHID_PROCESS_IDSUPER(data, text_data->text_font, IDWALK_CB_USER);
}
-#undef FOREACHID_PROCESS
+#undef FOREACHID_PROCESS_IDSUPER
return true;
}
@@ -738,66 +800,77 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data)
{
Scene *scene = (Scene *)id;
- BKE_LIB_FOREACHID_PROCESS(data, scene->camera, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, scene->world, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, scene->set, IDWALK_CB_NEVER_SELF);
- BKE_LIB_FOREACHID_PROCESS(data, scene->clip, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, scene->gpd, IDWALK_CB_USER);
- BKE_LIB_FOREACHID_PROCESS(data, scene->r.bake.cage_object, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->world, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->set, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->clip, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->r.bake.cage_object, IDWALK_CB_NOP);
if (scene->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_embedded(data, (ID **)&scene->nodetree);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&scene->nodetree));
}
if (scene->ed) {
- SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_member_id_cb, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_member_id_cb, data));
}
/* This pointer can be NULL during old files reading, better be safe than sorry. */
if (scene->master_collection != NULL) {
- BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection));
}
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
- BKE_LIB_FOREACHID_PROCESS(data, view_layer->mat_override, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, view_layer->mat_override, IDWALK_CB_USER);
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
- BKE_LIB_FOREACHID_PROCESS(
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, base->object, IDWALK_CB_NOP | IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE);
}
- scene_foreach_layer_collection(data, &view_layer->layer_collections);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, scene_foreach_layer_collection(data, &view_layer->layer_collections));
LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) {
if (fmc->script) {
- BKE_LIB_FOREACHID_PROCESS(data, fmc->script, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, fmc->script, IDWALK_CB_NOP);
}
}
LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) {
if (fls->group) {
- BKE_LIB_FOREACHID_PROCESS(data, fls->group, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, fls->group, IDWALK_CB_USER);
}
if (fls->linestyle) {
- BKE_LIB_FOREACHID_PROCESS(data, fls->linestyle, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, fls->linestyle, IDWALK_CB_USER);
}
}
}
LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) {
- BKE_LIB_FOREACHID_PROCESS(data, marker->camera, IDWALK_CB_NOP);
- IDP_foreach_property(
- marker->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, marker->camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ IDP_foreach_property(marker->prop,
+ IDP_TYPE_FILTER_ID,
+ BKE_lib_query_idpropertiesForeachIDLink_callback,
+ data));
}
ToolSettings *toolsett = scene->toolsettings;
if (toolsett) {
- scene_foreach_toolsettings(data, toolsett, false, NULL, toolsett);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, scene_foreach_toolsettings(data, toolsett, false, NULL, toolsett));
}
if (scene->rigidbody_world) {
- BKE_rigidbody_world_id_loop(
- scene->rigidbody_world, scene_foreach_rigidbodyworldSceneLooper, data);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data,
+ BKE_rigidbody_world_id_loop(
+ scene->rigidbody_world, scene_foreach_rigidbodyworldSceneLooper, data));
}
}
@@ -819,6 +892,45 @@ static void scene_foreach_cache(ID *id,
user_data);
}
+static bool seq_foreach_path_callback(Sequence *seq, void *user_data)
+{
+ if (SEQ_HAS_PATH(seq)) {
+ StripElem *se = seq->strip->stripdata;
+ BPathForeachPathData *bpath_data = (BPathForeachPathData *)user_data;
+
+ if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM) && se) {
+ BKE_bpath_foreach_path_dirfile_fixed_process(bpath_data, seq->strip->dir, se->name);
+ }
+ else if ((seq->type == SEQ_TYPE_IMAGE) && se) {
+ /* NOTE: An option not to loop over all strips could be useful? */
+ unsigned int len = (unsigned int)MEM_allocN_len(se) / (unsigned int)sizeof(*se);
+ unsigned int i;
+
+ if (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE) {
+ /* only operate on one path */
+ len = MIN2(1u, len);
+ }
+
+ for (i = 0; i < len; i++, se++) {
+ BKE_bpath_foreach_path_dirfile_fixed_process(bpath_data, seq->strip->dir, se->name);
+ }
+ }
+ else {
+ /* simple case */
+ BKE_bpath_foreach_path_fixed_process(bpath_data, seq->strip->dir);
+ }
+ }
+ return true;
+}
+
+static void scene_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Scene *scene = (Scene *)id;
+ if (scene->ed != NULL) {
+ SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_path_callback, bpath_data);
+ }
+}
+
static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Scene *sce = (Scene *)id;
@@ -999,7 +1111,7 @@ static void link_recurs_seq(BlendDataReader *reader, ListBase *lb)
/* Sanity check. */
if (!SEQ_valid_strip_channel(seq)) {
BLI_freelinkN(lb, seq);
- BLO_read_data_reports(reader)->count.vse_strips_skipped++;
+ BLO_read_data_reports(reader)->count.sequence_strips_skipped++;
}
else if (seq->seqbase.first) {
link_recurs_seq(reader, &seq->seqbase);
@@ -1528,6 +1640,7 @@ IDTypeInfo IDType_ID_SCE = {
.name_plural = "scenes",
.translation_context = BLT_I18NCONTEXT_ID_SCENE,
.flags = 0,
+ .asset_type_info = NULL,
.init_data = scene_init_data,
.copy_data = scene_copy_data,
@@ -1537,6 +1650,7 @@ IDTypeInfo IDType_ID_SCE = {
.make_local = NULL,
.foreach_id = scene_foreach_id,
.foreach_cache = scene_foreach_cache,
+ .foreach_path = scene_foreach_path,
.owner_get = NULL,
.blend_write = scene_blend_write,
@@ -1587,7 +1701,6 @@ static void remove_sequencer_fcurves(Scene *sce)
}
}
-/* flag -- copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more). */
ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
{
if (toolsettings == NULL) {
@@ -1801,6 +1914,7 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type)
/* Scene duplication is always root of duplication currently. */
const bool is_subprocess = false;
const bool is_root_id = true;
+ const int copy_flags = LIB_ID_COPY_DEFAULT;
if (!is_subprocess) {
BKE_main_id_newptr_and_tag_clear(bmain);
@@ -1816,24 +1930,43 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type)
/* Copy Freestyle LineStyle datablocks. */
LISTBASE_FOREACH (ViewLayer *, view_layer_dst, &sce_copy->view_layers) {
LISTBASE_FOREACH (FreestyleLineSet *, lineset, &view_layer_dst->freestyle_config.linesets) {
- BKE_id_copy_for_duplicate(bmain, (ID *)lineset->linestyle, duplicate_flags);
+ BKE_id_copy_for_duplicate(bmain, (ID *)lineset->linestyle, duplicate_flags, copy_flags);
}
}
/* Full copy of world (included animations) */
- BKE_id_copy_for_duplicate(bmain, (ID *)sce->world, duplicate_flags);
+ BKE_id_copy_for_duplicate(bmain, (ID *)sce->world, duplicate_flags, copy_flags);
/* Full copy of GreasePencil. */
- BKE_id_copy_for_duplicate(bmain, (ID *)sce->gpd, duplicate_flags);
+ BKE_id_copy_for_duplicate(bmain, (ID *)sce->gpd, duplicate_flags, copy_flags);
/* Deep-duplicate collections and objects (using preferences' settings for which sub-data to
* duplicate along the object itself). */
BKE_collection_duplicate(
bmain, NULL, sce_copy->master_collection, duplicate_flags, LIB_ID_DUPLICATE_IS_SUBPROCESS);
+ /* Rigid body world collections may not be instantiated as scene's collections, ensure they
+ * also get properly duplicated. */
+ if (sce_copy->rigidbody_world != NULL) {
+ if (sce_copy->rigidbody_world->group != NULL) {
+ BKE_collection_duplicate(bmain,
+ NULL,
+ sce_copy->rigidbody_world->group,
+ duplicate_flags,
+ LIB_ID_DUPLICATE_IS_SUBPROCESS);
+ }
+ if (sce_copy->rigidbody_world->constraints != NULL) {
+ BKE_collection_duplicate(bmain,
+ NULL,
+ sce_copy->rigidbody_world->constraints,
+ duplicate_flags,
+ LIB_ID_DUPLICATE_IS_SUBPROCESS);
+ }
+ }
+
if (!is_subprocess) {
/* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */
- BKE_libblock_relink_to_newid(&sce_copy->id);
+ BKE_libblock_relink_to_newid(bmain, &sce_copy->id, 0);
#ifndef NDEBUG
/* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those
@@ -1894,9 +2027,6 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
return sce;
}
-/**
- * Check if there is any instance of the object in the scene
- */
bool BKE_scene_object_find(Scene *scene, Object *ob)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -1919,12 +2049,6 @@ Object *BKE_scene_object_find_by_name(const Scene *scene, const char *name)
return NULL;
}
-/**
- * Sets the active scene, mainly used when running in background mode
- * (`--scene` command line argument).
- * This is also called to set the scene directly, bypassing windowing code.
- * Otherwise #WM_window_set_active_scene is used when changing scenes by the user.
- */
void BKE_scene_set_background(Main *bmain, Scene *scene)
{
Object *ob;
@@ -1949,7 +2073,6 @@ void BKE_scene_set_background(Main *bmain, Scene *scene)
* (render code calls own animation updates). */
}
-/* called from creator_args.c */
Scene *BKE_scene_set_name(Main *bmain, const char *name)
{
Scene *sce = (Scene *)BKE_libblock_find_name(bmain, ID_SCE, name);
@@ -1963,8 +2086,6 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
return NULL;
}
-/* Used by meta-balls, return *all* objects (including duplis)
- * existing in the scene (including scene's sets). */
int BKE_scene_base_iter_next(
Depsgraph *depsgraph, SceneBaseIter *iter, Scene **scene, int val, Base **base, Object **ob)
{
@@ -2189,8 +2310,6 @@ const char *BKE_scene_find_marker_name(const Scene *scene, int frame)
return NULL;
}
-/* return the current marker for this frame,
- * we can have more than 1 marker per frame, this just returns the first :/ */
const char *BKE_scene_find_last_marker_name(const Scene *scene, int frame)
{
const TimeMarker *marker, *best_marker = NULL;
@@ -2234,7 +2353,6 @@ void BKE_scene_remove_rigidbody_object(struct Main *bmain,
}
}
-/* checks for cycle, returns 1 if it's all OK */
bool BKE_scene_validate_setscene(Main *bmain, Scene *sce)
{
Scene *sce_iter;
@@ -2257,16 +2375,11 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce)
return true;
}
-/* Return fractional frame number taking into account subframes and time
- * remapping. This the time value used by animation, modifiers and physics
- * evaluation. */
float BKE_scene_ctime_get(const Scene *scene)
{
return BKE_scene_frame_to_ctime(scene, scene->r.cfra);
}
-/* Convert integer frame number to fractional frame number taking into account
- * subframes and time remapping. */
float BKE_scene_frame_to_ctime(const Scene *scene, const int frame)
{
float ctime = frame;
@@ -2276,13 +2389,11 @@ float BKE_scene_frame_to_ctime(const Scene *scene, const int frame)
return ctime;
}
-/* Get current fractional frame based on frame and subframe. */
float BKE_scene_frame_get(const Scene *scene)
{
return scene->r.cfra + scene->r.subframe;
}
-/* Set current frame and subframe based on a fractional frame. */
void BKE_scene_frame_set(Scene *scene, float frame)
{
double intpart;
@@ -2319,12 +2430,6 @@ TransformOrientationSlot *BKE_scene_orientation_slot_get_from_flag(Scene *scene,
return BKE_scene_orientation_slot_get(scene, slot_index);
}
-/**
- * Activate a transform orientation in a 3D view based on an enum value.
- *
- * \param orientation: If this is #V3D_ORIENT_CUSTOM or greater, the custom transform orientation
- * with index \a orientation - #V3D_ORIENT_CUSTOM gets activated.
- */
void BKE_scene_orientation_slot_set_index(TransformOrientationSlot *orient_slot, int orientation)
{
const bool is_custom = orientation >= V3D_ORIENT_CUSTOM;
@@ -2531,7 +2636,6 @@ void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
scene_graph_update_tagged(depsgraph, bmain, true);
}
-/* applies changes right away, does all sets too */
void BKE_scene_graph_update_for_newframe_ex(Depsgraph *depsgraph, const bool clear_recalc)
{
Scene *scene = DEG_get_input_scene(depsgraph);
@@ -2607,12 +2711,6 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
BKE_scene_graph_update_for_newframe_ex(depsgraph, true);
}
-/**
- * Ensures given scene/view_layer pair has a valid, up-to-date depsgraph.
- *
- * \warning Sets matching depsgraph as active,
- * so should only be called from the active editing context (usually, from operators).
- */
void BKE_scene_view_layer_graph_evaluated_ensure(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
@@ -2620,7 +2718,6 @@ void BKE_scene_view_layer_graph_evaluated_ensure(Main *bmain, Scene *scene, View
BKE_scene_graph_update_tagged(depsgraph, bmain);
}
-/* return default view */
SceneRenderView *BKE_scene_add_render_view(Scene *sce, const char *name)
{
SceneRenderView *srv;
@@ -2690,12 +2787,6 @@ int get_render_child_particle_number(const RenderData *r, int num, bool for_rend
return num;
}
-/**
- * Helper function for the SETLOOPER and SETLOOPER_VIEW_LAYER macros
- *
- * It iterates over the bases of the active layer and then the bases
- * of the active layer of the background (set) scenes recursively.
- */
Base *_setlooper_base_step(Scene **sce_iter, ViewLayer *view_layer, Base *base)
{
if (base && base->next) {
@@ -2760,13 +2851,18 @@ typedef enum eCyclesFeatureSet {
CYCLES_FEATURES_EXPERIMENTAL = 1,
} eCyclesFeatureSet;
-/* We cannot use const as RNA_id_pointer_create is not using a const ID. */
bool BKE_scene_uses_cycles_experimental_features(Scene *scene)
{
BLI_assert(BKE_scene_uses_cycles(scene));
PointerRNA scene_ptr;
RNA_id_pointer_create(&scene->id, &scene_ptr);
PointerRNA cycles_ptr = RNA_pointer_get(&scene_ptr, "cycles");
+
+ if (RNA_pointer_is_null(&cycles_ptr)) {
+ /* The pointer only exists if Cycles is enabled. */
+ return false;
+ }
+
return RNA_enum_get(&cycles_ptr, "feature_set") == CYCLES_FEATURES_EXPERIMENTAL;
}
@@ -2780,16 +2876,6 @@ void BKE_scene_base_flag_to_objects(ViewLayer *view_layer)
}
}
-/**
- * Synchronize object base flags
- *
- * This is usually handled by the depsgraph.
- * However, in rare occasions we need to use the latest object flags
- * before depsgraph is fully updated.
- *
- * It should (ideally) only run for copy-on-written objects since this is
- * runtime data generated per-viewlayer.
- */
void BKE_scene_object_base_flag_sync_from_base(Base *base)
{
Object *ob = base->object;
@@ -2862,10 +2948,6 @@ int BKE_render_preview_pixel_size(const RenderData *r)
return r->preview_pixel_size;
}
-/**
- * Apply the needed correction factor to value, based on unit_type
- * (only length-related are affected currently) and unit->scale_length.
- */
double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, double value)
{
if (unit->system == USER_UNIT_NONE) {
@@ -2940,7 +3022,6 @@ bool BKE_scene_multiview_is_stereo3d(const RenderData *rd)
((srv[1]->viewflag & SCE_VIEW_DISABLE) == 0));
}
-/* return whether to render this SceneRenderView */
bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
{
if (srv == NULL) {
@@ -2967,7 +3048,6 @@ bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const Scene
return false;
}
-/* return true if viewname is the first or if the name is NULL or not found */
bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char *viewname)
{
SceneRenderView *srv;
@@ -2989,7 +3069,6 @@ bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char *
return true;
}
-/* return true if viewname is the last or if the name is NULL or not found */
bool BKE_scene_multiview_is_render_view_last(const RenderData *rd, const char *viewname)
{
SceneRenderView *srv;
@@ -3073,12 +3152,6 @@ void BKE_scene_multiview_filepath_get(SceneRenderView *srv, const char *filepath
BLI_path_suffix(r_filepath, FILE_MAX, srv->suffix, "");
}
-/**
- * When multiview is not used the filepath is as usual (e.g., `Image.jpg`).
- * When multiview is on, even if only one view is enabled the view is incorporated
- * into the file name (e.g., `Image_L.jpg`). That allows for the user to re-render
- * individual views.
- */
void BKE_scene_multiview_view_filepath_get(const RenderData *rd,
const char *filepath,
const char *viewname,
@@ -3466,10 +3539,6 @@ TransformOrientation *BKE_scene_transform_orientation_find(const Scene *scene, c
return BLI_findlink(&scene->transform_spaces, index);
}
-/**
- * \return the index that \a orientation has within \a scene's transform-orientation list
- * or -1 if not found.
- */
int BKE_scene_transform_orientation_get_index(const Scene *scene,
const TransformOrientation *orientation)
{
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 0474c2b81cb..6e352b6ba90 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -45,6 +45,7 @@
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
+#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_mempool.h"
@@ -93,13 +94,13 @@ static void screen_foreach_id_dopesheet(LibraryForeachIDData *data, bDopeSheet *
{
if (ads != NULL) {
BKE_LIB_FOREACHID_PROCESS_ID(data, ads->source, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, ads->filter_grp, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, ads->filter_grp, IDWALK_CB_NOP);
}
}
void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area)
{
- BKE_LIB_FOREACHID_PROCESS(data, area->full, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, area->full, IDWALK_CB_NOP);
/* TODO: this should be moved to a callback in `SpaceType`, defined in each editor's own code.
* Will be for a later round of cleanup though... */
@@ -107,24 +108,21 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
switch (sl->spacetype) {
case SPACE_VIEW3D: {
View3D *v3d = (View3D *)sl;
-
- BKE_LIB_FOREACHID_PROCESS(data, v3d->camera, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, v3d->ob_center, IDWALK_CB_NOP);
-
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->ob_center, IDWALK_CB_NOP);
if (v3d->localvd) {
- BKE_LIB_FOREACHID_PROCESS(data, v3d->localvd->camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->localvd->camera, IDWALK_CB_NOP);
}
break;
}
case SPACE_GRAPH: {
SpaceGraph *sipo = (SpaceGraph *)sl;
-
- screen_foreach_id_dopesheet(data, sipo->ads);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data,
+ screen_foreach_id_dopesheet(data, sipo->ads));
break;
}
case SPACE_PROPERTIES: {
SpaceProperties *sbuts = (SpaceProperties *)sl;
-
BKE_LIB_FOREACHID_PROCESS_ID(data, sbuts->pinid, IDWALK_CB_NOP);
break;
}
@@ -132,48 +130,41 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
break;
case SPACE_ACTION: {
SpaceAction *saction = (SpaceAction *)sl;
-
screen_foreach_id_dopesheet(data, &saction->ads);
- BKE_LIB_FOREACHID_PROCESS(data, saction->action, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, saction->action, IDWALK_CB_NOP);
break;
}
case SPACE_IMAGE: {
SpaceImage *sima = (SpaceImage *)sl;
-
- BKE_LIB_FOREACHID_PROCESS(data, sima->image, IDWALK_CB_USER_ONE);
- BKE_LIB_FOREACHID_PROCESS(data, sima->mask_info.mask, IDWALK_CB_USER_ONE);
- BKE_LIB_FOREACHID_PROCESS(data, sima->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->image, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->mask_info.mask, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->gpd, IDWALK_CB_USER);
break;
}
case SPACE_SEQ: {
SpaceSeq *sseq = (SpaceSeq *)sl;
-
- BKE_LIB_FOREACHID_PROCESS(data, sseq->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sseq->gpd, IDWALK_CB_USER);
break;
}
case SPACE_NLA: {
SpaceNla *snla = (SpaceNla *)sl;
-
- screen_foreach_id_dopesheet(data, snla->ads);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data,
+ screen_foreach_id_dopesheet(data, snla->ads));
break;
}
case SPACE_TEXT: {
SpaceText *st = (SpaceText *)sl;
-
- BKE_LIB_FOREACHID_PROCESS(data, st->text, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, st->text, IDWALK_CB_NOP);
break;
}
case SPACE_SCRIPT: {
SpaceScript *scpt = (SpaceScript *)sl;
-
- BKE_LIB_FOREACHID_PROCESS(data, scpt->script, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scpt->script, IDWALK_CB_NOP);
break;
}
case SPACE_OUTLINER: {
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
-
BKE_LIB_FOREACHID_PROCESS_ID(data, space_outliner->search_tse.id, IDWALK_CB_NOP);
-
if (space_outliner->treestore != NULL) {
TreeStoreElem *tselem;
BLI_mempool_iter iter;
@@ -187,26 +178,24 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
}
case SPACE_NODE: {
SpaceNode *snode = (SpaceNode *)sl;
-
const bool is_private_nodetree = snode->id != NULL &&
ntreeFromID(snode->id) == snode->nodetree;
BKE_LIB_FOREACHID_PROCESS_ID(data, snode->id, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_ID(data, snode->from, IDWALK_CB_NOP);
-
- BKE_LIB_FOREACHID_PROCESS(
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE);
LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) {
if (path == snode->treepath.first) {
/* first nodetree in path is same as snode->nodetree */
- BKE_LIB_FOREACHID_PROCESS(data,
- path->nodetree,
- is_private_nodetree ? IDWALK_CB_EMBEDDED :
- IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data,
+ path->nodetree,
+ is_private_nodetree ? IDWALK_CB_EMBEDDED :
+ IDWALK_CB_USER_ONE);
}
else {
- BKE_LIB_FOREACHID_PROCESS(data, path->nodetree, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, path->nodetree, IDWALK_CB_USER_ONE);
}
if (path->nodetree == NULL) {
@@ -214,22 +203,20 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
}
}
- BKE_LIB_FOREACHID_PROCESS(data, snode->edittree, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, snode->edittree, IDWALK_CB_NOP);
break;
}
case SPACE_CLIP: {
SpaceClip *sclip = (SpaceClip *)sl;
-
- BKE_LIB_FOREACHID_PROCESS(data, sclip->clip, IDWALK_CB_USER_ONE);
- BKE_LIB_FOREACHID_PROCESS(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sclip->clip, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE);
break;
}
case SPACE_SPREADSHEET: {
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
-
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
- BKE_LIB_FOREACHID_PROCESS(
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, ((SpreadsheetContextObject *)context)->object, IDWALK_CB_NOP);
}
}
@@ -243,12 +230,13 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
static void screen_foreach_id(ID *id, LibraryForeachIDData *data)
{
- if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) {
- bScreen *screen = (bScreen *)id;
+ if ((BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) == 0) {
+ return;
+ }
+ bScreen *screen = (bScreen *)id;
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- BKE_screen_foreach_id_screen_area(data, area);
- }
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_screen_foreach_id_screen_area(data, area));
}
}
@@ -267,7 +255,6 @@ static void screen_blend_write(BlendWriter *writer, ID *id, const void *id_addre
BKE_screen_area_map_blend_write(writer, AREAMAP_FROM_SCREEN(screen));
}
-/* Cannot use IDTypeInfo callback yet, because of the return value. */
bool BKE_screen_blend_read_data(BlendDataReader *reader, bScreen *screen)
{
bool success = true;
@@ -313,6 +300,7 @@ IDTypeInfo IDType_ID_SCR = {
.name_plural = "screens",
.translation_context = BLT_I18NCONTEXT_ID_SCREEN,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_ONLY_APPEND | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -320,6 +308,7 @@ IDTypeInfo IDType_ID_SCR = {
.make_local = NULL,
.foreach_id = screen_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = screen_blend_write,
@@ -511,39 +500,35 @@ ARegion *BKE_area_region_copy(const SpaceType *st, const ARegion *region)
return newar;
}
-/* from lb2 to lb1, lb1 is supposed to be freed */
-static void region_copylist(SpaceType *st, ListBase *lb1, ListBase *lb2)
+/* from lb_src to lb_dst, lb_dst is supposed to be freed */
+static void region_copylist(SpaceType *st, ListBase *lb_dst, ListBase *lb_src)
{
/* to be sure */
- BLI_listbase_clear(lb1);
+ BLI_listbase_clear(lb_dst);
- LISTBASE_FOREACH (ARegion *, region, lb2) {
+ LISTBASE_FOREACH (ARegion *, region, lb_src) {
ARegion *region_new = BKE_area_region_copy(st, region);
- BLI_addtail(lb1, region_new);
+ BLI_addtail(lb_dst, region_new);
}
}
-/* lb1 should be empty */
-void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2)
+void BKE_spacedata_copylist(ListBase *lb_dst, ListBase *lb_src)
{
- BLI_listbase_clear(lb1); /* to be sure */
+ BLI_listbase_clear(lb_dst); /* to be sure */
- LISTBASE_FOREACH (SpaceLink *, sl, lb2) {
+ LISTBASE_FOREACH (SpaceLink *, sl, lb_src) {
SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
if (st && st->duplicate) {
SpaceLink *slnew = st->duplicate(sl);
- BLI_addtail(lb1, slnew);
+ BLI_addtail(lb_dst, slnew);
region_copylist(st, &slnew->regionbase, &sl->regionbase);
}
}
}
-/* facility to set locks for drawing to survive (render) threads accessing drawing data */
-/* lock can become bitflag too */
-/* should be replaced in future by better local data handling for threads */
void BKE_spacedata_draw_locks(bool set)
{
LISTBASE_FOREACH (SpaceType *, st, &spacetypes) {
@@ -558,10 +543,6 @@ void BKE_spacedata_draw_locks(bool set)
}
}
-/**
- * Version of #BKE_area_find_region_type that also works if \a slink
- * is not the active space of \a area.
- */
ARegion *BKE_spacedata_find_region_type(const SpaceLink *slink,
const ScrArea *area,
int region_type)
@@ -595,7 +576,6 @@ void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *area, SpaceLink *
spacedata_id_remap_cb = func;
}
-/* UNUSED!!! */
void BKE_spacedata_id_unref(struct ScrArea *area, struct SpaceLink *sl, struct ID *id)
{
if (spacedata_id_remap_cb) {
@@ -659,7 +639,6 @@ void BKE_area_region_panels_free(ListBase *panels)
BLI_listbase_clear(panels);
}
-/* not region itself */
void BKE_area_region_free(SpaceType *st, ARegion *region)
{
if (st) {
@@ -693,13 +672,17 @@ void BKE_area_region_free(SpaceType *st, ARegion *region)
region_free_gizmomap_callback(region->gizmo_map);
}
+ if (region->runtime.block_name_map != NULL) {
+ BLI_ghash_free(region->runtime.block_name_map, NULL, NULL);
+ region->runtime.block_name_map = NULL;
+ }
+
BLI_freelistN(&region->ui_lists);
BLI_freelistN(&region->ui_previews);
BLI_freelistN(&region->panels_category);
BLI_freelistN(&region->panels_category_active);
}
-/* not area itself */
void BKE_screen_area_free(ScrArea *area)
{
SpaceType *st = BKE_spacetype_from_id(area->spacetype);
@@ -727,7 +710,6 @@ void BKE_screen_area_map_free(ScrAreaMap *area_map)
BLI_freelistN(&area_map->areabase);
}
-/** Free (or release) any data used by this screen (does not free the screen itself). */
void BKE_screen_free_data(bScreen *screen)
{
screen_free_data(&screen->id);
@@ -890,12 +872,6 @@ void BKE_screen_remove_unused_scrverts(bScreen *screen)
/* ***************** Utilities ********************** */
-/**
- * Find a region of type \a region_type in the currently active space of \a area.
- *
- * \note This does _not_ work if the region to look up is not in the active
- * space. Use #BKE_spacedata_find_region_type if that may be the case.
- */
ARegion *BKE_area_find_region_type(const ScrArea *area, int region_type)
{
if (area) {
@@ -924,7 +900,7 @@ ARegion *BKE_area_find_region_active_win(ScrArea *area)
return BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
}
-ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int y)
+ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, const int xy[2])
{
if (area == NULL) {
return NULL;
@@ -932,7 +908,7 @@ ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (ELEM(regiontype, RGN_TYPE_ANY, region->regiontype)) {
- if (BLI_rcti_isect_pt(&region->winrct, x, y)) {
+ if (BLI_rcti_isect_pt_v(&region->winrct, xy)) {
return region;
}
}
@@ -940,14 +916,11 @@ ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int
return NULL;
}
-/**
- * \note This is only for screen level regions (typically menus/popups).
- */
-ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, int x, int y)
+ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, const int xy[2])
{
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
if (ELEM(regiontype, RGN_TYPE_ANY, region->regiontype)) {
- if (BLI_rcti_isect_pt(&region->winrct, x, y)) {
+ if (BLI_rcti_isect_pt_v(&region->winrct, xy)) {
return region;
}
}
@@ -955,10 +928,6 @@ ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, int x,
return NULL;
}
-/**
- * \note Ideally we can get the area from the context,
- * there are a few places however where this isn't practical.
- */
ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen, SpaceLink *sl)
{
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
@@ -970,10 +939,6 @@ ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen, SpaceLink *sl)
return NULL;
}
-/**
- * \note Using this function is generally a last resort, you really want to be
- * using the context when you can - campbell
- */
ScrArea *BKE_screen_find_big_area(bScreen *screen, const int spacetype, const short min)
{
ScrArea *big = NULL;
@@ -996,11 +961,10 @@ ScrArea *BKE_screen_find_big_area(bScreen *screen, const int spacetype, const sh
ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap,
const int spacetype,
- int x,
- int y)
+ const int xy[2])
{
LISTBASE_FOREACH (ScrArea *, area, &areamap->areabase) {
- if (BLI_rcti_isect_pt(&area->totrct, x, y)) {
+ if (BLI_rcti_isect_pt_v(&area->totrct, xy)) {
if (ELEM(spacetype, SPACE_TYPE_ANY, area->spacetype)) {
return area;
}
@@ -1009,9 +973,9 @@ ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap,
}
return NULL;
}
-ScrArea *BKE_screen_find_area_xy(bScreen *screen, const int spacetype, int x, int y)
+ScrArea *BKE_screen_find_area_xy(bScreen *screen, const int spacetype, const int xy[2])
{
- return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(screen), spacetype, x, y);
+ return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(screen), spacetype, xy);
}
void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
@@ -1051,26 +1015,20 @@ void BKE_screen_view3d_shading_init(View3DShading *shading)
memcpy(shading, shading_default, sizeof(*shading));
}
-ARegion *BKE_screen_find_main_region_at_xy(bScreen *screen,
- const int space_type,
- const int x,
- const int y)
+ARegion *BKE_screen_find_main_region_at_xy(bScreen *screen, const int space_type, const int xy[2])
{
- ScrArea *area = BKE_screen_find_area_xy(screen, space_type, x, y);
+ ScrArea *area = BKE_screen_find_area_xy(screen, space_type, xy);
if (!area) {
return NULL;
}
- return BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, x, y);
+ return BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, xy);
}
-/* magic zoom calculation, no idea what
- * it signifies, if you find out, tell me! -zr
- */
+/* Magic zoom calculation, no idea what it signifies, if you find out, tell me! -zr
+ *
+ * Simple, its magic dude! Well, to be honest,
+ * this gives a natural feeling zooming with multiple keypad presses (ton). */
-/* simple, its magic dude!
- * well, to be honest, this gives a natural feeling zooming
- * with multiple keypad presses (ton)
- */
float BKE_screen_view3d_zoom_to_fac(float camzoom)
{
return powf(((float)M_SQRT2 + camzoom / 50.0f), 2.0f) / 4.0f;
@@ -1485,7 +1443,6 @@ static void direct_link_region(BlendDataReader *reader, ARegion *region, int spa
}
/* for the saved 2.50 files without regiondata */
-/* and as patch for 2.48 and older */
void BKE_screen_view3d_do_versions_250(View3D *v3d, ListBase *regions)
{
LISTBASE_FOREACH (ARegion *, region, regions) {
@@ -1624,7 +1581,6 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
SpaceImage *sima = (SpaceImage *)sl;
sima->iuser.scene = NULL;
- sima->iuser.ok = 1;
sima->scopes.waveform_1 = NULL;
sima->scopes.waveform_2 = NULL;
sima->scopes.waveform_3 = NULL;
@@ -1793,9 +1749,6 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
BLO_read_data_address(reader, &area->v4);
}
-/**
- * \return false on error.
- */
bool BKE_screen_area_map_blend_read_data(BlendDataReader *reader, ScrAreaMap *area_map)
{
BLO_read_list(reader, &area_map->vertbase);
diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c
index 12017907038..a0d67a78d0f 100644
--- a/source/blender/blenkernel/intern/shader_fx.c
+++ b/source/blender/blenkernel/intern/shader_fx.c
@@ -57,7 +57,6 @@ static ShaderFxTypeInfo *shader_fx_types[NUM_SHADER_FX_TYPES] = {NULL};
/* *************************************************** */
/* Methods - Evaluation Loops, etc. */
-/* check if exist grease pencil effects */
bool BKE_shaderfx_has_gpencil(const Object *ob)
{
const ShaderFxData *fx;
@@ -136,7 +135,6 @@ void BKE_shaderfx_free(ShaderFxData *fx)
BKE_shaderfx_free_ex(fx, 0);
}
-/* check unique name */
bool BKE_shaderfx_unique_name(ListBase *shaders, ShaderFxData *fx)
{
if (shaders && fx) {
@@ -164,24 +162,12 @@ const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type)
return NULL;
}
-/**
- * Check whether given shaderfx is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param shaderfx: May be NULL, in which case we consider it as a non-local shaderfx case.
- */
bool BKE_shaderfx_is_nonlocal_in_liboverride(const Object *ob, const ShaderFxData *shaderfx)
{
return (ID_IS_OVERRIDE_LIBRARY(ob) &&
((shaderfx == NULL) || (shaderfx->flag & eShaderFxFlag_OverrideLibrary_Local) == 0));
}
-/**
- * Get an effect's panel type, which was defined in the #panelRegister callback.
- *
- * \note ShaderFx panel types are assumed to be named with the struct name field concatenated to
- * the defined prefix.
- */
void BKE_shaderfxType_panel_id(ShaderFxType type, char *r_idname)
{
const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(type);
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 7c0c28d664e..d51ed2832f0 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -28,6 +28,7 @@
#include <string.h>
#include <time.h>
+#include "DNA_gpencil_modifier_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
@@ -74,7 +75,8 @@ typedef struct ShrinkwrapCalcData {
struct Object *ob; /* object we are applying shrinkwrap to */
- struct MVert *vert; /* Array of verts being projected (to fetch normals or other data) */
+ struct MVert *vert; /* Array of verts being projected. */
+ const float (*vert_normals)[3];
float (*vertexCos)[3]; /* vertexs being shrinkwraped */
int numVerts;
@@ -101,7 +103,6 @@ typedef struct ShrinkwrapCalcCBData {
SpaceTransform *local2aux;
} ShrinkwrapCalcCBData;
-/* Checks if the modifier needs target normals with these settings. */
bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode)
{
return (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) ||
@@ -109,7 +110,6 @@ bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode)
shrinkMode == MOD_SHRINKWRAP_ABOVE_SURFACE);
}
-/* Initializes the mesh data structure from the given mesh and settings. */
bool BKE_shrinkwrap_init_tree(
ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals)
{
@@ -147,7 +147,7 @@ bool BKE_shrinkwrap_init_tree(
}
if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) {
- data->pnors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ data->pnors = BKE_mesh_poly_normals_ensure(mesh);
if ((mesh->flag & ME_AUTOSMOOTH) != 0) {
data->clnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
}
@@ -160,13 +160,11 @@ bool BKE_shrinkwrap_init_tree(
return true;
}
-/* Frees the tree data if necessary. */
void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData *data)
{
free_bvhtree_from_mesh(&data->treeData);
}
-/* Free boundary data for target project */
void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh)
{
struct ShrinkwrapBoundaryData *data = mesh->runtime.shrinkwrap_data;
@@ -316,18 +314,18 @@ static ShrinkwrapBoundaryData *shrinkwrap_build_boundary_data(struct Mesh *mesh)
MEM_freeN(vert_status);
/* Finalize average direction and compute normal. */
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
for (int i = 0; i < mesh->totvert; i++) {
int bidx = vert_boundary_id[i];
if (bidx >= 0) {
ShrinkwrapBoundaryVertData *vdata = &boundary_verts[bidx];
- float no[3], tmp[3];
+ float tmp[3];
normalize_v3(vdata->direction);
- normal_short_to_float_v3(no, mesh->mvert[i].no);
- cross_v3_v3v3(tmp, no, vdata->direction);
- cross_v3_v3v3(vdata->normal_plane, tmp, no);
+ cross_v3_v3v3(tmp, vert_normals[i], vdata->direction);
+ cross_v3_v3v3(vdata->normal_plane, tmp, vert_normals[i]);
normalize_v3(vdata->normal_plane);
}
}
@@ -434,14 +432,6 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
0, calc->numVerts, &data, shrinkwrap_calc_nearest_vertex_cb_ex, &settings);
}
-/*
- * This function raycast a single vertex and updates the hit if the "hit" is considered valid.
- * Returns true if "hit" was updated.
- * Opts control whether an hit is valid or not
- * Supported options are:
- * - MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored)
- * - MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored)
- */
bool BKE_shrinkwrap_project_normal(char options,
const float vert[3],
const float dir[3],
@@ -551,7 +541,7 @@ static void shrinkwrap_calc_normal_projection_cb_ex(void *__restrict userdata,
* (to get correct normals) for other cases calc->verts contains undeformed coordinates and
* vertexCos should be used */
copy_v3_v3(tmp_co, calc->vert[i].co);
- normal_short_to_float_v3(tmp_no, calc->vert[i].no);
+ copy_v3_v3(tmp_no, calc->vert_normals[i]);
}
else {
copy_v3_v3(tmp_co, co);
@@ -644,7 +634,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
/* Options about projection direction */
float proj_axis[3] = {0.0f, 0.0f, 0.0f};
- /* Raycast and tree stuff */
+ /* Ray-cast and tree stuff. */
/** \note 'hit.dist' is kept in the targets space, this is only used
* for finding the best hit, to get the real dist,
@@ -1019,8 +1009,8 @@ static void target_project_edge(const ShrinkwrapTreeData *tree,
CLAMP(x, 0, 1);
float vedge_no[2][3];
- normal_short_to_float_v3(vedge_no[0], data->vert[edge->v1].no);
- normal_short_to_float_v3(vedge_no[1], data->vert[edge->v2].no);
+ copy_v3_v3(vedge_no[0], data->vert_normals[edge->v1]);
+ copy_v3_v3(vedge_no[1], data->vert_normals[edge->v2]);
interp_v3_v3v3(hit_co, vedge_co[0], vedge_co[1], x);
interp_v3_v3v3(hit_no, vedge_no[0], vedge_no[1], x);
@@ -1066,9 +1056,9 @@ static void mesh_looptri_target_project(void *userdata,
}
/* Decode normals */
- normal_short_to_float_v3(vtri_no[0], vtri[0]->no);
- normal_short_to_float_v3(vtri_no[1], vtri[1]->no);
- normal_short_to_float_v3(vtri_no[2], vtri[2]->no);
+ copy_v3_v3(vtri_no[0], tree->treeData.vert_normals[loop[0]->v]);
+ copy_v3_v3(vtri_no[1], tree->treeData.vert_normals[loop[1]->v]);
+ copy_v3_v3(vtri_no[2], tree->treeData.vert_normals[loop[2]->v]);
/* Solve the equations for the triangle */
if (target_project_solve_point_tri(vtri_co, vtri_no, co, raw_hit_co, dist_sq, hit_co, hit_no)) {
@@ -1089,9 +1079,6 @@ static void mesh_looptri_target_project(void *userdata,
}
}
-/*
- * Maps the point to the nearest surface, either by simple nearest, or by target normal projection.
- */
void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree,
BVHTreeNearest *nearest,
float co[3],
@@ -1196,13 +1183,6 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex(void *__restrict userdat
}
}
-/**
- * Compute a smooth normal of the target (if applicable) at the hit location.
- *
- * \param tree: information about the mesh
- * \param transform: transform from the hit coordinate space to the object space; may be null
- * \param r_no: output in hit coordinate space; may be shared with inputs
- */
void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
const struct SpaceTransform *transform,
int looptri_idx,
@@ -1212,14 +1192,13 @@ void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
{
const BVHTreeFromMesh *treeData = &tree->treeData;
const MLoopTri *tri = &treeData->looptri[looptri_idx];
+ const float(*vert_normals)[3] = tree->treeData.vert_normals;
/* Interpolate smooth normals if enabled. */
if ((tree->mesh->mpoly[tri->poly].flag & ME_SMOOTH) != 0) {
- const MVert *verts[] = {
- &treeData->vert[treeData->loop[tri->tri[0]].v],
- &treeData->vert[treeData->loop[tri->tri[1]].v],
- &treeData->vert[treeData->loop[tri->tri[2]].v],
- };
+ const uint32_t vert_indices[3] = {treeData->loop[tri->tri[0]].v,
+ treeData->loop[tri->tri[1]].v,
+ treeData->loop[tri->tri[2]].v};
float w[3], no[3][3], tmp_co[3];
/* Custom and auto smooth split normals. */
@@ -1230,9 +1209,9 @@ void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
}
/* Ordinary vertex normals. */
else {
- normal_short_to_float_v3(no[0], verts[0]->no);
- normal_short_to_float_v3(no[1], verts[1]->no);
- normal_short_to_float_v3(no[2], verts[2]->no);
+ copy_v3_v3(no[0], vert_normals[vert_indices[0]]);
+ copy_v3_v3(no[1], vert_normals[vert_indices[1]]);
+ copy_v3_v3(no[2], vert_normals[vert_indices[2]]);
}
/* Barycentric weights from hit point. */
@@ -1242,7 +1221,11 @@ void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
BLI_space_transform_apply(transform, tmp_co);
}
- interp_weights_tri_v3(w, verts[0]->co, verts[1]->co, verts[2]->co, tmp_co);
+ interp_weights_tri_v3(w,
+ treeData->vert[vert_indices[0]].co,
+ treeData->vert[vert_indices[1]].co,
+ treeData->vert[vert_indices[2]].co,
+ tmp_co);
/* Interpolate using weights. */
interp_v3_v3v3v3(r_no, no[0], no[1], no[2], w);
@@ -1318,13 +1301,6 @@ static void shrinkwrap_snap_with_side(float r_point_co[3],
}
}
-/**
- * Apply the shrink to surface modes to the given original coordinates and nearest point.
- *
- * \param tree: mesh data for smooth normals
- * \param transform: transform from the hit coordinate space to the object space; may be null
- * \param r_point_co: may be the same memory location as point_co, hit_co, or hit_no.
- */
void BKE_shrinkwrap_snap_point_to_surface(const struct ShrinkwrapTreeData *tree,
const struct SpaceTransform *transform,
int mode,
@@ -1404,7 +1380,6 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
0, calc->numVerts, &data, shrinkwrap_calc_nearest_surface_point_cb_ex, &settings);
}
-/* Main shrinkwrap function */
void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
const ModifierEvalContext *ctx,
struct Scene *scene,
@@ -1453,6 +1428,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
if (mesh != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) {
/* Setup arrays to get vertexs positions, normals and deform weights */
calc.vert = mesh->mvert;
+ calc.vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
/* Using vertexs positions/normals as if a subsurface was applied */
if (smd->subsurfLevels) {
@@ -1513,6 +1489,55 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
}
}
+void shrinkwrapGpencilModifier_deform(ShrinkwrapGpencilModifierData *mmd,
+ Object *ob,
+ MDeformVert *dvert,
+ const int defgrp_index,
+ float (*vertexCos)[3],
+ int numVerts)
+{
+
+ ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
+ /* Convert gpencil struct to use the same struct and function used with meshes. */
+ ShrinkwrapModifierData smd;
+ smd.target = mmd->target;
+ smd.auxTarget = mmd->aux_target;
+ smd.keepDist = mmd->keep_dist;
+ smd.shrinkType = mmd->shrink_type;
+ smd.shrinkOpts = mmd->shrink_opts;
+ smd.shrinkMode = mmd->shrink_mode;
+ smd.projLimit = mmd->proj_limit;
+ smd.projAxis = mmd->proj_axis;
+
+ /* Configure Shrinkwrap calc data. */
+ calc.smd = &smd;
+ calc.ob = ob;
+ calc.numVerts = numVerts;
+ calc.vertexCos = vertexCos;
+ calc.dvert = dvert;
+ calc.vgroup = defgrp_index;
+ calc.invert_vgroup = (mmd->flag & GP_SHRINKWRAP_INVERT_VGROUP) != 0;
+
+ BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob, mmd->target);
+ calc.keepDist = mmd->keep_dist;
+ calc.tree = mmd->cache_data;
+
+ switch (mmd->shrink_type) {
+ case MOD_SHRINKWRAP_NEAREST_SURFACE:
+ case MOD_SHRINKWRAP_TARGET_PROJECT:
+ TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), gpdeform_surface);
+ break;
+
+ case MOD_SHRINKWRAP_PROJECT:
+ TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), gpdeform_project);
+ break;
+
+ case MOD_SHRINKWRAP_NEAREST_VERTEX:
+ TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), gpdeform_vertex);
+ break;
+ }
+}
+
void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
Object *ob_source,
Object *ob_target)
@@ -1561,6 +1586,7 @@ void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object
calc.smd = &ssmd;
calc.numVerts = src_me->totvert;
calc.vertexCos = vertexCos;
+ calc.vert_normals = BKE_mesh_vertex_normals_ensure(src_me);
calc.vgroup = -1;
calc.target = target_me;
calc.keepDist = ssmd.keepDist;
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index 1d297b3ced9..ec4b0e8d51d 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -28,9 +28,9 @@
#include "DNA_simulation_types.h"
#include "BLI_compiler_compat.h"
-#include "BLI_float3.hh"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_rand.h"
#include "BLI_span.hh"
#include "BLI_string.h"
@@ -103,7 +103,8 @@ static void simulation_foreach_id(ID *id, LibraryForeachIDData *data)
Simulation *simulation = (Simulation *)id;
if (simulation->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree));
}
}
@@ -153,6 +154,7 @@ IDTypeInfo IDType_ID_SIM = {
/* name_plural */ "simulations",
/* translation_context */ BLT_I18NCONTEXT_ID_SIMULATION,
/* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
/* init_data */ simulation_init_data,
/* copy_data */ simulation_copy_data,
@@ -160,6 +162,7 @@ IDTypeInfo IDType_ID_SIM = {
/* make_local */ nullptr,
/* foreach_id */ simulation_foreach_id,
/* foreach_cache */ nullptr,
+ /* foreach_path */ nullptr,
/* owner_get */ nullptr,
/* blend_write */ simulation_blend_write,
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index fbc781f5eb9..baabf57f0c3 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -1673,7 +1673,7 @@ static int sb_detect_vertex_collisionCached(float opco[3],
if ((opco[0] < minx) || (opco[1] < miny) || (opco[2] < minz) || (opco[0] > maxx) ||
(opco[1] > maxy) || (opco[2] > maxz)) {
- /* outside the padded boundbox --> collision object is too far away */
+ /* Outside the padded bound-box -> collision object is too far away. */
BLI_ghashIterator_step(ihash);
continue;
}
@@ -2295,7 +2295,7 @@ static void softbody_calc_forces(
sb_sfesf_threads_run(depsgraph, scene, ob, timenow, sb->totspring, NULL);
}
- /* after spring scan because it uses Effoctors too */
+ /* After spring scan because it uses effectors too. */
ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, sb->effector_weights, false);
if (do_deflector) {
@@ -2633,7 +2633,7 @@ static void interpolate_exciter(Object *ob, int timescale, int time)
}
}
-/* ************ convertors ********** */
+/* ************ converters ********** */
/* for each object type we need;
* - xxxx_to_softbody(Object *ob) : a full (new) copy, creates SB geometry
@@ -3112,7 +3112,6 @@ static void sb_new_scratch(SoftBody *sb)
/* ************ Object level, exported functions *************** */
-/* allocates and initializes general main data */
SoftBody *sbNew(void)
{
SoftBody *sb;
@@ -3162,7 +3161,6 @@ SoftBody *sbNew(void)
return sb;
}
-/* frees all */
void sbFree(Object *ob)
{
SoftBody *sb = ob->soft;
@@ -3193,7 +3191,6 @@ void sbFreeSimulation(SoftBody *sb)
free_softbody_intern(sb);
}
-/* makes totally fresh start situation */
void sbObjectToSoftbody(Object *ob)
{
// ob->softflag |= OB_SB_REDO;
@@ -3213,7 +3210,6 @@ static bool object_has_edges(const Object *ob)
return false;
}
-/* SB global visible functions */
void sbSetInterruptCallBack(int (*f)(void))
{
SB_localInterruptCallBack = f;
@@ -3244,20 +3240,6 @@ static void softbody_update_positions(Object *ob,
}
}
-/* void SB_estimate_transform */
-/* input Object *ob out (says any object that can do SB like mesh, lattice, curve )
- * output float lloc[3], float lrot[3][3], float lscale[3][3]
- * that is:
- * a precise position vector denoting the motion of the center of mass
- * give a rotation/scale matrix using averaging method, that's why estimate and not calculate
- * see: this is kind of reverse engineering: having to states of a point cloud and recover what
- * happened our advantage here we know the identity of the vertex there are others methods giving
- * other results. lloc, lrot, lscale are allowed to be NULL, just in case you don't need it.
- * should be pretty useful for pythoneers :)
- * not! velocity .. 2nd order stuff
- * vcloud_estimate_transform_v3 see
- */
-
void SB_estimate_transform(Object *ob, float lloc[3], float lrot[3][3], float lscale[3][3])
{
BodyPoint *bp;
@@ -3523,7 +3505,6 @@ static void sbStoreLastFrame(struct Depsgraph *depsgraph, Object *object, float
object_orig->soft->last_frame = framenr;
}
-/* simulates one step. framenr is in frames */
void sbObjectStep(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 8feda76cc5b..b27231e6a17 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -54,6 +54,7 @@
# include <AUD_Special.h>
#endif
+#include "BKE_bpath.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -133,6 +134,17 @@ static void sound_foreach_cache(ID *id,
function_callback(id, &key, &sound->waveform, 0, user_data);
}
+static void sound_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ bSound *sound = (bSound *)id;
+ if (sound->packedfile != NULL && (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
+ return;
+ }
+
+ /* FIXME: This does not check for empty path... */
+ BKE_bpath_foreach_path_fixed_process(bpath_data, sound->filepath);
+}
+
static void sound_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
bSound *sound = (bSound *)id;
@@ -205,6 +217,7 @@ IDTypeInfo IDType_ID_SO = {
.name_plural = "sounds",
.translation_context = BLT_I18NCONTEXT_ID_SOUND,
.flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
/* A fuzzy case, think NULLified content is OK here... */
.init_data = NULL,
@@ -213,6 +226,7 @@ IDTypeInfo IDType_ID_SO = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = sound_foreach_cache,
+ .foreach_path = sound_foreach_path,
.owner_get = NULL,
.blend_write = sound_blend_write,
@@ -257,14 +271,11 @@ BLI_INLINE void sound_verify_evaluated_id(const ID *id)
bSound *BKE_sound_new_file(Main *bmain, const char *filepath)
{
bSound *sound;
- const char *path;
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
char str[FILE_MAX];
BLI_strncpy(str, filepath, sizeof(str));
-
- path = BKE_main_blendfile_path(bmain);
-
- BLI_path_abs(str, path);
+ BLI_path_abs(str, blendfile_path);
sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath), 0);
BLI_strncpy(sound->filepath, filepath, FILE_MAX);
@@ -702,13 +713,13 @@ void *BKE_sound_scene_add_scene_sound(
Scene *scene, Sequence *sequence, int startframe, int endframe, int frameskip)
{
sound_verify_evaluated_id(&scene->id);
- if (sequence->scene && scene != sequence->scene && sequence->sound) {
+ if (sequence->scene && scene != sequence->scene) {
const double fps = FPS;
return AUD_Sequence_add(scene->sound_scene,
sequence->scene->sound_scene,
startframe / fps,
endframe / fps,
- frameskip / fps + sequence->sound->offset_time);
+ frameskip / fps);
}
return NULL;
}
@@ -774,13 +785,13 @@ void BKE_sound_move_scene_sound(
void BKE_sound_move_scene_sound_defaults(Scene *scene, Sequence *sequence)
{
sound_verify_evaluated_id(&scene->id);
- if (sequence->scene_sound && sequence->sound) {
+ if (sequence->scene_sound) {
BKE_sound_move_scene_sound(scene,
sequence->scene_sound,
sequence->startdisp,
sequence->enddisp,
sequence->startofs + sequence->anim_startofs,
- sequence->sound->offset_time);
+ 0.0);
}
}
@@ -1235,15 +1246,14 @@ bool BKE_sound_stream_info_get(struct Main *main,
int stream,
SoundStreamInfo *sound_info)
{
- const char *path;
+ const char *blendfile_path = BKE_main_blendfile_path(main);
char str[FILE_MAX];
AUD_Sound *sound;
AUD_StreamInfo *stream_infos;
int stream_count;
BLI_strncpy(str, filepath, sizeof(str));
- path = BKE_main_blendfile_path(main);
- BLI_path_abs(str, path);
+ BLI_path_abs(str, blendfile_path);
sound = AUD_Sound_file(str);
if (!sound) {
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index b361f31cc30..b7199dc1e20 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -50,7 +50,7 @@ static void speaker_foreach_id(ID *id, LibraryForeachIDData *data)
{
Speaker *speaker = (Speaker *)id;
- BKE_LIB_FOREACHID_PROCESS(data, speaker->sound, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, speaker->sound, IDWALK_CB_USER);
}
static void speaker_blend_write(BlendWriter *writer, ID *id, const void *id_address)
@@ -99,6 +99,7 @@ IDTypeInfo IDType_ID_SPK = {
.name_plural = "speakers",
.translation_context = BLT_I18NCONTEXT_ID_SPEAKER,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = speaker_init_data,
.copy_data = NULL,
@@ -106,6 +107,7 @@ IDTypeInfo IDType_ID_SPK = {
.make_local = NULL,
.foreach_id = speaker_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = speaker_blend_write,
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
index 663c1951ba3..3262d768b6c 100644
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ b/source/blender/blenkernel/intern/spline_base.cc
@@ -30,14 +30,12 @@ using blender::float3;
using blender::IndexRange;
using blender::MutableSpan;
using blender::Span;
+using blender::VArray;
using blender::attribute_math::convert_to_static_type;
using blender::bke::AttributeIDRef;
using blender::fn::GMutableSpan;
using blender::fn::GSpan;
using blender::fn::GVArray;
-using blender::fn::GVArray_For_GSpan;
-using blender::fn::GVArray_Typed;
-using blender::fn::GVArrayPtr;
Spline::Type Spline::type() const
{
@@ -64,9 +62,6 @@ static SplinePtr create_spline(const Spline::Type type)
return {};
}
-/**
- * Return a new spline with the same data, settings, and attributes.
- */
SplinePtr Spline::copy() const
{
SplinePtr dst = this->copy_without_attributes();
@@ -74,9 +69,6 @@ SplinePtr Spline::copy() const
return dst;
}
-/**
- * Return a new spline with the same type and settings like "cyclic", but without any data.
- */
SplinePtr Spline::copy_only_settings() const
{
SplinePtr dst = create_spline(type_);
@@ -85,9 +77,6 @@ SplinePtr Spline::copy_only_settings() const
return dst;
}
-/**
- * The same as #copy, but skips copying dynamic attributes to the new spline.
- */
SplinePtr Spline::copy_without_attributes() const
{
SplinePtr dst = this->copy_only_settings();
@@ -177,22 +166,18 @@ static void accumulate_lengths(Span<float3> positions,
const bool is_cyclic,
MutableSpan<float> lengths)
{
+ using namespace blender::math;
+
float length = 0.0f;
for (const int i : IndexRange(positions.size() - 1)) {
- length += float3::distance(positions[i], positions[i + 1]);
+ length += distance(positions[i], positions[i + 1]);
lengths[i] = length;
}
if (is_cyclic) {
- lengths.last() = length + float3::distance(positions.last(), positions.first());
+ lengths.last() = length + distance(positions.last(), positions.first());
}
}
-/**
- * Return non-owning access to the cache of accumulated lengths along the spline. Each item is the
- * length of the subsequent segment, i.e. the first value is the length of the first segment rather
- * than 0. This calculation is rather trivial, and only depends on the evaluated positions.
- * However, the results are used often, and it is necessarily single threaded, so it is cached.
- */
Span<float> Spline::evaluated_lengths() const
{
if (!length_cache_dirty_) {
@@ -217,11 +202,13 @@ Span<float> Spline::evaluated_lengths() const
static float3 direction_bisect(const float3 &prev, const float3 &middle, const float3 &next)
{
- const float3 dir_prev = (middle - prev).normalized();
- const float3 dir_next = (next - middle).normalized();
+ using namespace blender::math;
+
+ const float3 dir_prev = normalize(middle - prev);
+ const float3 dir_next = normalize(next - middle);
- const float3 result = (dir_prev + dir_next).normalized();
- if (UNLIKELY(result.is_zero())) {
+ const float3 result = normalize(dir_prev + dir_next);
+ if (UNLIKELY(is_zero(result))) {
return float3(0.0f, 0.0f, 1.0f);
}
return result;
@@ -231,6 +218,8 @@ static void calculate_tangents(Span<float3> positions,
const bool is_cyclic,
MutableSpan<float3> tangents)
{
+ using namespace blender::math;
+
if (positions.size() == 1) {
tangents.first() = float3(0.0f, 0.0f, 1.0f);
return;
@@ -249,14 +238,11 @@ static void calculate_tangents(Span<float3> positions,
tangents.last() = direction_bisect(second_to_last, last, first);
}
else {
- tangents.first() = (positions[1] - positions[0]).normalized();
- tangents.last() = (positions.last() - positions[positions.size() - 2]).normalized();
+ tangents.first() = normalize(positions[1] - positions[0]);
+ tangents.last() = normalize(positions.last() - positions[positions.size() - 2]);
}
}
-/**
- * Return non-owning access to the direction of the curve at each evaluated point.
- */
Span<float3> Spline::evaluated_tangents() const
{
if (!tangent_cache_dirty_) {
@@ -284,18 +270,22 @@ static float3 rotate_direction_around_axis(const float3 &direction,
const float3 &axis,
const float angle)
{
+ using namespace blender::math;
+
BLI_ASSERT_UNIT_V3(direction);
BLI_ASSERT_UNIT_V3(axis);
- const float3 axis_scaled = axis * float3::dot(direction, axis);
+ const float3 axis_scaled = axis * dot(direction, axis);
const float3 diff = direction - axis_scaled;
- const float3 cross = float3::cross(axis, diff);
+ const float3 cross = blender::math::cross(axis, diff);
return axis_scaled + diff * std::cos(angle) + cross * std::sin(angle);
}
static void calculate_normals_z_up(Span<float3> tangents, MutableSpan<float3> r_normals)
{
+ using namespace blender::math;
+
BLI_assert(r_normals.size() == tangents.size());
/* Same as in `vec_to_quat`. */
@@ -306,7 +296,7 @@ static void calculate_normals_z_up(Span<float3> tangents, MutableSpan<float3> r_
r_normals[i] = {1.0f, 0.0f, 0.0f};
}
else {
- r_normals[i] = float3(tangent.y, -tangent.x, 0.0f).normalized();
+ r_normals[i] = normalize(float3(tangent.y, -tangent.x, 0.0f));
}
}
}
@@ -318,12 +308,14 @@ static float3 calculate_next_normal(const float3 &last_normal,
const float3 &last_tangent,
const float3 &current_tangent)
{
- if (last_tangent.is_zero() || current_tangent.is_zero()) {
+ using namespace blender::math;
+
+ if (is_zero(last_tangent) || is_zero(current_tangent)) {
return last_normal;
}
const float angle = angle_normalized_v3v3(last_tangent, current_tangent);
if (angle != 0.0) {
- const float3 axis = float3::cross(last_tangent, current_tangent).normalized();
+ const float3 axis = normalize(cross(last_tangent, current_tangent));
return rotate_direction_around_axis(last_normal, axis, angle);
}
return last_normal;
@@ -333,6 +325,7 @@ static void calculate_normals_minimum(Span<float3> tangents,
const bool cyclic,
MutableSpan<float3> r_normals)
{
+ using namespace blender::math;
BLI_assert(r_normals.size() == tangents.size());
if (r_normals.is_empty()) {
@@ -347,7 +340,7 @@ static void calculate_normals_minimum(Span<float3> tangents,
r_normals[0] = {1.0f, 0.0f, 0.0f};
}
else {
- r_normals[0] = float3(first_tangent.y, -first_tangent.x, 0.0f).normalized();
+ r_normals[0] = normalize(float3(first_tangent.y, -first_tangent.x, 0.0f));
}
/* Forward normal with minimum twist along the entire spline. */
@@ -377,10 +370,6 @@ static void calculate_normals_minimum(Span<float3> tangents,
}
}
-/**
- * Return non-owning access to the direction vectors perpendicular to the tangents at every
- * evaluated point. The method used to generate the normal vectors depends on Spline.normal_mode.
- */
Span<float3> Spline::evaluated_normals() const
{
if (!normal_cache_dirty_) {
@@ -416,7 +405,7 @@ Span<float3> Spline::evaluated_normals() const
}
/* Rotate the generated normals with the interpolated tilt data. */
- GVArray_Typed<float> tilts = this->interpolate_to_evaluated(this->tilts());
+ VArray<float> tilts = this->interpolate_to_evaluated(this->tilts());
for (const int i : normals.index_range()) {
normals[i] = rotate_direction_around_axis(normals[i], tangents[i], tilts[i]);
}
@@ -430,9 +419,6 @@ Spline::LookupResult Spline::lookup_evaluated_factor(const float factor) const
return this->lookup_evaluated_length(this->length() * factor);
}
-/**
- * \note This does not support extrapolation currently.
- */
Spline::LookupResult Spline::lookup_evaluated_length(const float length) const
{
BLI_assert(length >= 0.0f && length <= this->length());
@@ -444,16 +430,13 @@ Spline::LookupResult Spline::lookup_evaluated_length(const float length) const
const int next_index = (index == this->evaluated_points_size() - 1) ? 0 : index + 1;
const float previous_length = (index == 0) ? 0.0f : lengths[index - 1];
- const float factor = (length - previous_length) / (lengths[index] - previous_length);
+ const float length_in_segment = length - previous_length;
+ const float segment_length = lengths[index] - previous_length;
+ const float factor = segment_length == 0.0f ? 0.0f : length_in_segment / segment_length;
return LookupResult{index, next_index, factor};
}
-/**
- * Return an array of evenly spaced samples along the length of the spline. The samples are indices
- * and factors to the next index encoded in floats. The logic for converting from the float values
- * to interpolation data is in #lookup_data_from_index_factor.
- */
Array<float> Spline::sample_uniform_index_factors(const int samples_size) const
{
const Span<float> lengths = this->evaluated_lengths();
@@ -486,6 +469,12 @@ Array<float> Spline::sample_uniform_index_factors(const int samples_size) const
prev_length = length;
}
+ /* Zero lengths or float inaccuracies can cause invalid values, or simply
+ * skip some, so set the values that weren't completed in the main loop. */
+ for (const int i : IndexRange(i_sample, samples_size - i_sample)) {
+ samples[i] = float(samples_size);
+ }
+
if (!is_cyclic_) {
/* In rare cases this can prevent overflow of the stored index. */
samples.last() = lengths.size();
@@ -523,16 +512,11 @@ void Spline::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated)
}
}
-GVArrayPtr Spline::interpolate_to_evaluated(GSpan data) const
+GVArray Spline::interpolate_to_evaluated(GSpan data) const
{
- return this->interpolate_to_evaluated(GVArray_For_GSpan(data));
+ return this->interpolate_to_evaluated(GVArray::ForSpan(data));
}
-/**
- * Sample any input data with a value for each evaluated point (already interpolated to evaluated
- * points) to arbitrary parameters in between the evaluated points. The interpolation is quite
- * simple, but this handles the cyclic and end point special cases.
- */
void Spline::sample_with_index_factors(const GVArray &src,
Span<float> index_factors,
GMutableSpan dst) const
@@ -541,7 +525,7 @@ void Spline::sample_with_index_factors(const GVArray &src,
blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
- const GVArray_Typed<T> src_typed = src.typed<T>();
+ const VArray<T> src_typed = src.typed<T>();
MutableSpan<T> dst_typed = dst.typed<T>();
if (src.size() == 1) {
dst_typed.fill(src_typed[0]);
diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc
index b36d7a21669..980437014b1 100644
--- a/source/blender/blenkernel/intern/spline_bezier.cc
+++ b/source/blender/blenkernel/intern/spline_bezier.cc
@@ -25,9 +25,8 @@ using blender::float3;
using blender::IndexRange;
using blender::MutableSpan;
using blender::Span;
+using blender::VArray;
using blender::fn::GVArray;
-using blender::fn::GVArray_For_ArrayContainer;
-using blender::fn::GVArrayPtr;
void BezierSpline::copy_settings(Spline &dst) const
{
@@ -71,27 +70,6 @@ void BezierSpline::set_resolution(const int value)
this->mark_cache_invalid();
}
-/**
- * \warning Call #reallocate on the spline's attributes after adding all points.
- */
-void BezierSpline::add_point(const float3 position,
- const HandleType handle_type_left,
- const float3 handle_position_left,
- const HandleType handle_type_right,
- const float3 handle_position_right,
- const float radius,
- const float tilt)
-{
- handle_types_left_.append(handle_type_left);
- handle_positions_left_.append(handle_position_left);
- positions_.append(position);
- handle_types_right_.append(handle_type_right);
- handle_positions_right_.append(handle_position_right);
- radii_.append(radius);
- tilts_.append(tilt);
- this->mark_cache_invalid();
-}
-
void BezierSpline::resize(const int size)
{
handle_types_left_.resize(size);
@@ -142,11 +120,14 @@ Span<float3> BezierSpline::handle_positions_left() const
this->ensure_auto_handles();
return handle_positions_left_;
}
-MutableSpan<float3> BezierSpline::handle_positions_left()
+MutableSpan<float3> BezierSpline::handle_positions_left(const bool write_only)
{
- this->ensure_auto_handles();
+ if (!write_only) {
+ this->ensure_auto_handles();
+ }
return handle_positions_left_;
}
+
Span<BezierSpline::HandleType> BezierSpline::handle_types_right() const
{
return handle_types_right_;
@@ -160,9 +141,11 @@ Span<float3> BezierSpline::handle_positions_right() const
this->ensure_auto_handles();
return handle_positions_right_;
}
-MutableSpan<float3> BezierSpline::handle_positions_right()
+MutableSpan<float3> BezierSpline::handle_positions_right(const bool write_only)
{
- this->ensure_auto_handles();
+ if (!write_only) {
+ this->ensure_auto_handles();
+ }
return handle_positions_right_;
}
@@ -199,10 +182,6 @@ static float3 next_position(Span<float3> positions, const bool cyclic, const int
return positions[i + 1];
}
-/**
- * Recalculate all #Auto and #Vector handles with positions automatically
- * derived from the neighboring control points.
- */
void BezierSpline::ensure_auto_handles() const
{
if (!auto_handles_dirty_) {
@@ -220,11 +199,13 @@ void BezierSpline::ensure_auto_handles() const
}
for (const int i : IndexRange(this->size())) {
+ using namespace blender;
+
if (ELEM(HandleType::Auto, handle_types_left_[i], handle_types_right_[i])) {
const float3 prev_diff = positions_[i] - previous_position(positions_, is_cyclic_, i);
const float3 next_diff = next_position(positions_, is_cyclic_, i) - positions_[i];
- float prev_len = prev_diff.length();
- float next_len = next_diff.length();
+ float prev_len = math::length(prev_diff);
+ float next_len = math::length(next_diff);
if (prev_len == 0.0f) {
prev_len = 1.0f;
}
@@ -234,7 +215,7 @@ void BezierSpline::ensure_auto_handles() const
const float3 dir = next_diff / next_len + prev_diff / prev_len;
/* This magic number is unfortunate, but comes from elsewhere in Blender. */
- const float len = dir.length() * 2.5614f;
+ const float len = math::length(dir) * 2.5614f;
if (len != 0.0f) {
if (handle_types_left_[i] == HandleType::Auto) {
const float prev_len_clamped = std::min(prev_len, next_len * 5.0f);
@@ -249,12 +230,12 @@ void BezierSpline::ensure_auto_handles() const
if (handle_types_left_[i] == HandleType::Vector) {
const float3 prev = previous_position(positions_, is_cyclic_, i);
- handle_positions_left_[i] = float3::interpolate(positions_[i], prev, 1.0f / 3.0f);
+ handle_positions_left_[i] = math::interpolate(positions_[i], prev, 1.0f / 3.0f);
}
if (handle_types_right_[i] == HandleType::Vector) {
const float3 next = next_position(positions_, is_cyclic_, i);
- handle_positions_right_[i] = float3::interpolate(positions_[i], next, 1.0f / 3.0f);
+ handle_positions_right_[i] = math::interpolate(positions_[i], next, 1.0f / 3.0f);
}
}
@@ -289,6 +270,50 @@ void BezierSpline::transform(const blender::float4x4 &matrix)
this->mark_cache_invalid();
}
+static void set_handle_position(const float3 &position,
+ const BezierSpline::HandleType type,
+ const BezierSpline::HandleType type_other,
+ const float3 &new_value,
+ float3 &handle,
+ float3 &handle_other)
+{
+ using namespace blender::math;
+
+ /* Don't bother when the handle positions are calculated automatically anyway. */
+ if (ELEM(type, BezierSpline::HandleType::Auto, BezierSpline::HandleType::Vector)) {
+ return;
+ }
+
+ handle = new_value;
+ if (type_other == BezierSpline::HandleType::Align) {
+ /* Keep track of the old length of the opposite handle. */
+ const float length = distance(handle_other, position);
+ /* Set the other handle to directly opposite from the current handle. */
+ const float3 dir = normalize(handle - position);
+ handle_other = position - dir * length;
+ }
+}
+
+void BezierSpline::set_handle_position_right(const int index, const blender::float3 &value)
+{
+ set_handle_position(positions_[index],
+ handle_types_right_[index],
+ handle_types_left_[index],
+ value,
+ handle_positions_right_[index],
+ handle_positions_left_[index]);
+}
+
+void BezierSpline::set_handle_position_left(const int index, const blender::float3 &value)
+{
+ set_handle_position(positions_[index],
+ handle_types_left_[index],
+ handle_types_right_[index],
+ value,
+ handle_positions_left_[index],
+ handle_positions_right_[index]);
+}
+
bool BezierSpline::point_is_sharp(const int index) const
{
return ELEM(handle_types_left_[index], HandleType::Vector, HandleType::Free) ||
@@ -297,6 +322,9 @@ bool BezierSpline::point_is_sharp(const int index) const
bool BezierSpline::segment_is_vector(const int index) const
{
+ /* Two control points are necessary to form a segment, that should be checked by the caller. */
+ BLI_assert(this->size() > 1);
+
if (index == this->size() - 1) {
if (is_cyclic_) {
return handle_types_right_.last() == HandleType::Vector &&
@@ -327,14 +355,9 @@ int BezierSpline::evaluated_points_size() const
return this->control_point_offsets().last();
}
-/**
- * If the spline is not cyclic, the direction for the first and last points is just the
- * direction formed by the corresponding handles and control points. In the unlikely situation
- * that the handles define a zero direction, fallback to using the direction defined by the
- * first and last evaluated segments already calculated in #Spline::evaluated_tangents().
- */
void BezierSpline::correct_end_tangents() const
{
+ using namespace blender::math;
if (is_cyclic_) {
return;
}
@@ -342,50 +365,33 @@ void BezierSpline::correct_end_tangents() const
MutableSpan<float3> tangents(evaluated_tangents_cache_);
if (handle_positions_right_.first() != positions_.first()) {
- tangents.first() = (handle_positions_right_.first() - positions_.first()).normalized();
+ tangents.first() = normalize(handle_positions_right_.first() - positions_.first());
}
if (handle_positions_left_.last() != positions_.last()) {
- tangents.last() = (positions_.last() - handle_positions_left_.last()).normalized();
+ tangents.last() = normalize(positions_.last() - handle_positions_left_.last());
}
}
-/**
- * De Casteljau Bezier subdivision.
- * \param index: The index of the segment's start control point.
- * \param next_index: The index of the control point at the end of the segment. Could be 0,
- * if the spline is cyclic.
- * \param parameter: The factor along the segment, between 0 and 1. Note that this is used
- * directly by the calculation, it doesn't correspond to a portion of the evaluated length.
- *
- * <pre>
- * handle_prev handle_next
- * x----------------x
- * / \
- * / x---O---x \
- * / result \
- * / \
- * O O
- * point_prev point_next
- * </pre>
- */
BezierSpline::InsertResult BezierSpline::calculate_segment_insertion(const int index,
const int next_index,
const float parameter)
{
+ using namespace blender::math;
+
BLI_assert(parameter <= 1.0f && parameter >= 0.0f);
BLI_assert(next_index == 0 || next_index == index + 1);
const float3 &point_prev = positions_[index];
const float3 &handle_prev = handle_positions_right_[index];
const float3 &handle_next = handle_positions_left_[next_index];
const float3 &point_next = positions_[next_index];
- const float3 center_point = float3::interpolate(handle_prev, handle_next, parameter);
+ const float3 center_point = interpolate(handle_prev, handle_next, parameter);
BezierSpline::InsertResult result;
- result.handle_prev = float3::interpolate(point_prev, handle_prev, parameter);
- result.handle_next = float3::interpolate(handle_next, point_next, parameter);
- result.left_handle = float3::interpolate(result.handle_prev, center_point, parameter);
- result.right_handle = float3::interpolate(center_point, result.handle_next, parameter);
- result.position = float3::interpolate(result.left_handle, result.right_handle, parameter);
+ result.handle_prev = interpolate(point_prev, handle_prev, parameter);
+ result.handle_next = interpolate(handle_next, point_next, parameter);
+ result.left_handle = interpolate(result.handle_prev, center_point, parameter);
+ result.right_handle = interpolate(center_point, result.handle_next, parameter);
+ result.position = interpolate(result.left_handle, result.right_handle, parameter);
return result;
}
@@ -433,15 +439,6 @@ void BezierSpline::evaluate_segment(const int index,
}
}
-/**
- * Returns access to a cache of offsets into the evaluated point array for each control point.
- * While most control point edges generate the number of edges specified by the resolution, vector
- * segments only generate one edge.
- *
- * \note The length of the result is one greater than the number of points, so that the last item
- * is the total number of evaluated points. This is useful to avoid recalculating the size of the
- * last segment everywhere.
- */
Span<int> BezierSpline::control_point_offsets() const
{
if (!offset_cache_dirty_) {
@@ -457,13 +454,18 @@ Span<int> BezierSpline::control_point_offsets() const
offset_cache_.resize(size + 1);
MutableSpan<int> offsets = offset_cache_;
-
- int offset = 0;
- for (const int i : IndexRange(size)) {
- offsets[i] = offset;
- offset += this->segment_is_vector(i) ? 1 : resolution_;
+ if (size == 1) {
+ offsets.first() = 0;
+ offsets.last() = 1;
+ }
+ else {
+ int offset = 0;
+ for (const int i : IndexRange(size)) {
+ offsets[i] = offset;
+ offset += this->segment_is_vector(i) ? 1 : resolution_;
+ }
+ offsets.last() = offset;
}
- offsets.last() = offset;
offset_cache_dirty_ = false;
return offsets;
@@ -503,12 +505,6 @@ static void calculate_mappings_linear_resolution(Span<int> offsets,
}
}
-/**
- * Returns non-owning access to an array of values containing the information necessary to
- * interpolate values from the original control points to evaluated points. The control point
- * index is the integer part of each value, and the factor used for interpolating to the next
- * control point is the remaining factional part.
- */
Span<float> BezierSpline::evaluated_mappings() const
{
if (!mapping_cache_dirty_) {
@@ -533,7 +529,10 @@ Span<float> BezierSpline::evaluated_mappings() const
Span<int> offsets = this->control_point_offsets();
- calculate_mappings_linear_resolution(offsets, size, resolution_, is_cyclic_, mappings);
+ blender::threading::isolate_task([&]() {
+ /* Isolate the task, since this is function is multi-threaded and holds a lock. */
+ calculate_mappings_linear_resolution(offsets, size, resolution_, is_cyclic_, mappings);
+ });
mapping_cache_dirty_ = false;
return mappings;
@@ -550,21 +549,32 @@ Span<float3> BezierSpline::evaluated_positions() const
return evaluated_position_cache_;
}
- this->ensure_auto_handles();
-
const int size = this->size();
const int eval_size = this->evaluated_points_size();
evaluated_position_cache_.resize(eval_size);
MutableSpan<float3> positions = evaluated_position_cache_;
+ if (size == 1) {
+ /* Use a special case for single point splines to avoid checking in #evaluate_segment. */
+ BLI_assert(eval_size == 1);
+ positions.first() = positions_.first();
+ position_cache_dirty_ = false;
+ return positions;
+ }
+
+ this->ensure_auto_handles();
+
Span<int> offsets = this->control_point_offsets();
const int grain_size = std::max(512 / resolution_, 1);
- blender::threading::parallel_for(IndexRange(size - 1), grain_size, [&](IndexRange range) {
- for (const int i : range) {
- this->evaluate_segment(i, i + 1, positions.slice(offsets[i], offsets[i + 1] - offsets[i]));
- }
+ blender::threading::isolate_task([&]() {
+ /* Isolate the task, since this is function is multi-threaded and holds a lock. */
+ blender::threading::parallel_for(IndexRange(size - 1), grain_size, [&](IndexRange range) {
+ for (const int i : range) {
+ this->evaluate_segment(i, i + 1, positions.slice(offsets[i], offsets[i + 1] - offsets[i]));
+ }
+ });
});
if (is_cyclic_) {
this->evaluate_segment(
@@ -580,11 +590,6 @@ Span<float3> BezierSpline::evaluated_positions() const
return positions;
}
-/**
- * Convert the data encoded in #evaulated_mappings into its parts-- the information necessary
- * to interpolate data from control points to evaluated points between them. The next control
- * point index result will not overflow the size of the control point vectors.
- */
BezierSpline::InterpolationData BezierSpline::interpolation_data_from_index_factor(
const float index_factor) const
{
@@ -628,26 +633,26 @@ static void interpolate_to_evaluated_impl(const BezierSpline &spline,
}
}
-GVArrayPtr BezierSpline::interpolate_to_evaluated(const GVArray &src) const
+GVArray BezierSpline::interpolate_to_evaluated(const GVArray &src) const
{
BLI_assert(src.size() == this->size());
if (src.is_single()) {
- return src.shallow_copy();
+ return src;
}
const int eval_size = this->evaluated_points_size();
if (eval_size == 1) {
- return src.shallow_copy();
+ return src;
}
- GVArrayPtr new_varray;
+ GVArray new_varray;
blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<blender::attribute_math::DefaultMixer<T>>) {
Array<T> values(eval_size);
interpolate_to_evaluated_impl<T>(*this, src.typed<T>(), values);
- new_varray = std::make_unique<GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ new_varray = VArray<T>::ForContainer(std::move(values));
}
});
diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc
index 6d30d8ba916..5993b9a9a27 100644
--- a/source/blender/blenkernel/intern/spline_nurbs.cc
+++ b/source/blender/blenkernel/intern/spline_nurbs.cc
@@ -26,10 +26,8 @@ using blender::float3;
using blender::IndexRange;
using blender::MutableSpan;
using blender::Span;
+using blender::VArray;
using blender::fn::GVArray;
-using blender::fn::GVArray_For_ArrayContainer;
-using blender::fn::GVArray_Typed;
-using blender::fn::GVArrayPtr;
void NURBSpline::copy_settings(Spline &dst) const
{
@@ -83,22 +81,6 @@ void NURBSpline::set_order(const uint8_t value)
this->mark_cache_invalid();
}
-/**
- * \warning Call #reallocate on the spline's attributes after adding all points.
- */
-void NURBSpline::add_point(const float3 position,
- const float radius,
- const float tilt,
- const float weight)
-{
- positions_.append(position);
- radii_.append(radius);
- tilts_.append(tilt);
- weights_.append(weight);
- knots_dirty_ = true;
- this->mark_cache_invalid();
-}
-
void NURBSpline::resize(const int size)
{
positions_.resize(size);
@@ -197,78 +179,48 @@ int NURBSpline::knots_size() const
void NURBSpline::calculate_knots() const
{
const KnotsMode mode = this->knots_mode;
- const int length = this->size();
const int order = order_;
+ const bool is_bezier = mode == NURBSpline::KnotsMode::Bezier;
+ const bool is_end_point = mode == NURBSpline::KnotsMode::EndPoint;
+ /* Inner knots are always repeated once except on Bezier case. */
+ const int repeat_inner = is_bezier ? order - 1 : 1;
+ /* How many times to repeat 0.0 at the beginning of knot. */
+ const int head = is_end_point && !is_cyclic_ ? order : (is_bezier ? order / 2 : 1);
+ /* Number of knots replicating widths of the starting knots.
+ * Covers both Cyclic and EndPoint cases. */
+ const int tail = is_cyclic_ ? 2 * order - 1 : (is_end_point ? order : 0);
knots_.resize(this->knots_size());
-
MutableSpan<float> knots = knots_;
- if (mode == NURBSpline::KnotsMode::Normal || is_cyclic_) {
- for (const int i : knots.index_range()) {
- knots[i] = static_cast<float>(i);
- }
- }
- else if (mode == NURBSpline::KnotsMode::EndPoint) {
- float k = 0.0f;
- for (const int i : IndexRange(1, knots.size())) {
- knots[i - 1] = k;
- if (i >= order && i <= length) {
- k += 1.0f;
- }
- }
- }
- else if (mode == NURBSpline::KnotsMode::Bezier) {
- BLI_assert(ELEM(order, 3, 4));
- if (order == 3) {
- float k = 0.6f;
- for (const int i : knots.index_range()) {
- if (i >= order && i <= length) {
- k += 0.5f;
- }
- knots[i] = std::floor(k);
- }
- }
- else {
- float k = 0.34f;
- for (const int i : knots.index_range()) {
- knots[i] = std::floor(k);
- k += 1.0f / 3.0f;
- }
- }
- }
+ int r = head;
+ float current = 0.0f;
- if (is_cyclic_) {
- const int b = length + order - 1;
- if (order > 2) {
- for (const int i : IndexRange(1, order - 2)) {
- if (knots[b] != knots[b - i]) {
- if (i == order - 1) {
- knots[length + order - 2] += 1.0f;
- break;
- }
- }
- }
+ for (const int i : IndexRange(knots.size() - tail)) {
+ knots[i] = current;
+ r--;
+ if (r == 0) {
+ current += 1.0;
+ r = repeat_inner;
}
+ }
- int c = order;
- for (int i = b; i < this->knots_size(); i++) {
- knots[i] = knots[i - 1] + (knots[c] - knots[c - 1]);
- c--;
- }
+ const int tail_index = knots.size() - tail;
+ for (const int i : IndexRange(tail)) {
+ knots[tail_index + i] = current + (knots[i] - knots[0]);
}
}
Span<float> NURBSpline::knots() const
{
if (!knots_dirty_) {
- BLI_assert(knots_.size() == this->size() + order_);
+ BLI_assert(knots_.size() == this->knots_size());
return knots_;
}
std::lock_guard lock{knots_mutex_};
if (!knots_dirty_) {
- BLI_assert(knots_.size() == this->size() + order_);
+ BLI_assert(knots_.size() == this->knots_size());
return knots_;
}
@@ -410,23 +362,23 @@ void interpolate_to_evaluated_impl(Span<NURBSpline::BasisCache> weights,
mixer.finalize();
}
-GVArrayPtr NURBSpline::interpolate_to_evaluated(const GVArray &src) const
+GVArray NURBSpline::interpolate_to_evaluated(const GVArray &src) const
{
BLI_assert(src.size() == this->size());
if (src.is_single()) {
- return src.shallow_copy();
+ return src;
}
Span<BasisCache> basis_cache = this->calculate_basis_cache();
- GVArrayPtr new_varray;
+ GVArray new_varray;
blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<blender::attribute_math::DefaultMixer<T>>) {
Array<T> values(this->evaluated_points_size());
interpolate_to_evaluated_impl<T>(basis_cache, src.typed<T>(), values);
- new_varray = std::make_unique<GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
+ new_varray = VArray<T>::ForContainer(std::move(values));
}
});
@@ -448,8 +400,8 @@ Span<float3> NURBSpline::evaluated_positions() const
evaluated_position_cache_.resize(eval_size);
/* TODO: Avoid copying the evaluated data from the temporary array. */
- GVArray_Typed<float3> evaluated = Spline::interpolate_to_evaluated(positions_.as_span());
- evaluated->materialize(evaluated_position_cache_);
+ VArray<float3> evaluated = Spline::interpolate_to_evaluated(positions_.as_span());
+ evaluated.materialize(evaluated_position_cache_);
position_cache_dirty_ = false;
return evaluated_position_cache_;
diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc
index 338b5d0ac9e..480bbd1dfe8 100644
--- a/source/blender/blenkernel/intern/spline_poly.cc
+++ b/source/blender/blenkernel/intern/spline_poly.cc
@@ -23,7 +23,6 @@ using blender::float3;
using blender::MutableSpan;
using blender::Span;
using blender::fn::GVArray;
-using blender::fn::GVArrayPtr;
void PolySpline::copy_settings(Spline &UNUSED(dst)) const
{
@@ -46,17 +45,6 @@ int PolySpline::size() const
return size;
}
-/**
- * \warning Call #reallocate on the spline's attributes after adding all points.
- */
-void PolySpline::add_point(const float3 position, const float radius, const float tilt)
-{
- positions_.append(position);
- radii_.append(radius);
- tilts_.append(tilt);
- this->mark_cache_invalid();
-}
-
void PolySpline::resize(const int size)
{
positions_.resize(size);
@@ -116,15 +104,8 @@ Span<float3> PolySpline::evaluated_positions() const
return this->positions();
}
-/**
- * Poly spline interpolation from control points to evaluated points is a special case, since
- * the result data is the same as the input data. This function returns a GVArray that points to
- * the original data. Therefore the lifetime of the returned virtual array must not be longer than
- * the source data.
- */
-GVArrayPtr PolySpline::interpolate_to_evaluated(const GVArray &src) const
+GVArray PolySpline::interpolate_to_evaluated(const GVArray &src) const
{
BLI_assert(src.size() == this->size());
-
- return src.shallow_copy();
+ return src;
}
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 29f726ece71..b7690e69aa1 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -1402,7 +1402,6 @@ void BKE_studiolight_default(SolidLight lights[4], float light_ambient[3])
lights[3].vec[2] = -0.542269f;
}
-/* API */
void BKE_studiolight_init(void)
{
/* Add default studio light */
@@ -1532,7 +1531,6 @@ void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_typ
}
}
-/* Ensure state of Studiolights */
void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
{
if ((sl->flag & flag) == flag) {
@@ -1570,8 +1568,9 @@ void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
}
/*
- * Python API Functions
+ * Python API Functions.
*/
+
void BKE_studiolight_remove(StudioLight *sl)
{
if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
@@ -1608,7 +1607,6 @@ StudioLight *BKE_studiolight_create(const char *path,
return sl;
}
-/* Only useful for workbench while editing the userprefs. */
StudioLight *BKE_studiolight_studio_edit_get(void)
{
static StudioLight sl = {0};
diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c
index fd32f52351a..45810e29565 100644
--- a/source/blender/blenkernel/intern/subdiv.c
+++ b/source/blender/blenkernel/intern/subdiv.c
@@ -29,6 +29,9 @@
#include "BLI_utildefines.h"
+#include "BKE_modifier.h"
+#include "BKE_subdiv_modifier.h"
+
#include "MEM_guardedalloc.h"
#include "subdiv_converter.h"
@@ -189,6 +192,12 @@ Subdiv *BKE_subdiv_update_from_mesh(Subdiv *subdiv,
void BKE_subdiv_free(Subdiv *subdiv)
{
if (subdiv->evaluator != NULL) {
+ const eOpenSubdivEvaluator evaluator_type = subdiv->evaluator->type;
+ if (evaluator_type != OPENSUBDIV_EVALUATOR_CPU) {
+ /* Let the draw code do the freeing, to ensure that the OpenGL context is valid. */
+ BKE_subsurf_modifier_free_gpu_cache_cb(subdiv);
+ return;
+ }
openSubdiv_deleteEvaluator(subdiv->evaluator);
}
if (subdiv->topology_refiner != NULL) {
@@ -214,12 +223,13 @@ int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv)
}
const int num_coarse_faces = topology_refiner->getNumFaces(topology_refiner);
subdiv->cache_.face_ptex_offset = MEM_malloc_arrayN(
- num_coarse_faces, sizeof(int), "subdiv face_ptex_offset");
+ num_coarse_faces + 1, sizeof(int), "subdiv face_ptex_offset");
int ptex_offset = 0;
for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
const int num_ptex_faces = topology_refiner->getNumFacePtexFaces(topology_refiner, face_index);
subdiv->cache_.face_ptex_offset[face_index] = ptex_offset;
ptex_offset += num_ptex_faces;
}
+ subdiv->cache_.face_ptex_offset[num_coarse_faces] = ptex_offset;
return subdiv->cache_.face_ptex_offset;
}
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
index 95f51a72b70..7d876acf776 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg.c
@@ -359,30 +359,29 @@ static void subdiv_ccg_init_faces(SubdivCCG *subdiv_ccg)
/* TODO(sergey): Consider making it generic enough to be fit into BLI. */
typedef struct StaticOrHeapIntStorage {
int static_storage[64];
- int static_storage_size;
+ int static_storage_len;
int *heap_storage;
- int heap_storage_size;
+ int heap_storage_len;
} StaticOrHeapIntStorage;
static void static_or_heap_storage_init(StaticOrHeapIntStorage *storage)
{
- storage->static_storage_size = sizeof(storage->static_storage) /
- sizeof(*storage->static_storage);
+ storage->static_storage_len = sizeof(storage->static_storage) / sizeof(*storage->static_storage);
storage->heap_storage = NULL;
- storage->heap_storage_size = 0;
+ storage->heap_storage_len = 0;
}
-static int *static_or_heap_storage_get(StaticOrHeapIntStorage *storage, int size)
+static int *static_or_heap_storage_get(StaticOrHeapIntStorage *storage, int heap_len)
{
/* Requested size small enough to be fit into stack allocated memory. */
- if (size <= storage->static_storage_size) {
+ if (heap_len <= storage->static_storage_len) {
return storage->static_storage;
}
/* Make sure heap ius big enough. */
- if (size > storage->heap_storage_size) {
+ if (heap_len > storage->heap_storage_len) {
MEM_SAFE_FREE(storage->heap_storage);
- storage->heap_storage = MEM_malloc_arrayN(size, sizeof(int), "int storage");
- storage->heap_storage_size = size;
+ storage->heap_storage = MEM_malloc_arrayN(heap_len, sizeof(int), "int storage");
+ storage->heap_storage_len = heap_len;
}
return storage->heap_storage;
}
@@ -604,7 +603,8 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv,
{
/* Make sure evaluator is ready. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(
+ subdiv, coarse_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
if (coarse_mesh->totpoly) {
return NULL;
}
@@ -1062,7 +1062,7 @@ static void subdiv_ccg_average_grids_boundary(SubdivCCG *subdiv_ccg,
}
if (tls->accumulators == NULL) {
tls->accumulators = MEM_calloc_arrayN(
- sizeof(GridElementAccumulator), grid_size2, "average accumulators");
+ grid_size2, sizeof(GridElementAccumulator), "average accumulators");
}
else {
for (int i = 1; i < grid_size2 - 1; i++) {
@@ -1797,7 +1797,7 @@ static void neighbor_coords_edge_get(const SubdivCCG *subdiv_ccg,
r_neighbors->coords[i + 2] = coord_step_inside_from_boundary(subdiv_ccg, &grid_coord);
if (grid_coord.grid_index == coord->grid_index) {
- /* Prev and next along the edge for the current grid. */
+ /* Previous and next along the edge for the current grid. */
r_neighbors->coords[0] = boundary_coords[prev_point_index];
r_neighbors->coords[1] = boundary_coords[next_point_index];
}
@@ -1972,7 +1972,7 @@ const int *BKE_subdiv_ccg_start_face_grid_index_ensure(SubdivCCG *subdiv_ccg)
const int num_coarse_faces = topology_refiner->getNumFaces(topology_refiner);
subdiv_ccg->cache_.start_face_grid_index = MEM_malloc_arrayN(
- sizeof(int), num_coarse_faces, "start_face_grid_index");
+ num_coarse_faces, sizeof(int), "start_face_grid_index");
int start_grid_index = 0;
for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
diff --git a/source/blender/blenkernel/intern/subdiv_converter_mesh.c b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
index 41fc28c5d52..fc7ef887879 100644
--- a/source/blender/blenkernel/intern/subdiv_converter_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
@@ -40,6 +40,8 @@
#include "opensubdiv_capi.h"
#include "opensubdiv_converter_capi.h"
+#include "bmesh_class.h"
+
/* Enable work-around for non-working CPU evaluator when using bilinear scheme.
* This forces Catmark scheme with all edges marked as infinitely sharp. */
#define BUGGY_SIMPLE_SCHEME_WORKAROUND 1
@@ -47,6 +49,8 @@
typedef struct ConverterStorage {
SubdivSettings settings;
const Mesh *mesh;
+ /* CustomData layer for vertex sharpnesses. */
+ const float *cd_vertex_crease;
/* Indexed by loop index, value denotes index of face-varying vertex
* which corresponds to the UV coordinate.
*/
@@ -168,7 +172,7 @@ static float get_edge_sharpness(const OpenSubdiv_Converter *converter, int manif
}
const int edge_index = storage->manifold_edge_index_reverse[manifold_edge_index];
const MEdge *medge = storage->mesh->medge;
- return BKE_subdiv_edge_crease_to_sharpness_char(medge[edge_index].crease);
+ return BKE_subdiv_crease_to_sharpness_char(medge[edge_index].crease);
}
static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter,
@@ -184,14 +188,14 @@ static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter,
return BLI_BITMAP_TEST_BOOL(storage->infinite_sharp_vertices_map, vertex_index);
}
-static float get_vertex_sharpness(const OpenSubdiv_Converter *converter,
- int UNUSED(manifold_vertex_index))
+static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, int manifold_vertex_index)
{
ConverterStorage *storage = converter->user_data;
- if (!storage->settings.use_creases) {
+ if (!storage->settings.use_creases || storage->cd_vertex_crease == NULL) {
return 0.0f;
}
- return 0.0f;
+ const int vertex_index = storage->manifold_vertex_index_reverse[manifold_vertex_index];
+ return BKE_subdiv_crease_to_sharpness_f(storage->cd_vertex_crease[vertex_index]);
}
static int get_num_uv_layers(const OpenSubdiv_Converter *converter)
@@ -393,6 +397,7 @@ static void init_user_data(OpenSubdiv_Converter *converter,
ConverterStorage *user_data = MEM_mallocN(sizeof(ConverterStorage), __func__);
user_data->settings = *settings;
user_data->mesh = mesh;
+ user_data->cd_vertex_crease = CustomData_get_layer(&mesh->vdata, CD_CREASE);
user_data->loop_uv_indices = NULL;
initialize_manifold_indices(user_data);
converter->user_data = user_data;
diff --git a/source/blender/blenkernel/intern/subdiv_deform.c b/source/blender/blenkernel/intern/subdiv_deform.c
index 2c900fbd600..c385b1b291d 100644
--- a/source/blender/blenkernel/intern/subdiv_deform.c
+++ b/source/blender/blenkernel/intern/subdiv_deform.c
@@ -69,7 +69,7 @@ static void subdiv_mesh_prepare_accumulator(SubdivDeformContext *ctx, int num_ve
return;
}
ctx->accumulated_counters = MEM_calloc_arrayN(
- sizeof(*ctx->accumulated_counters), num_vertices, "subdiv accumulated counters");
+ num_vertices, sizeof(*ctx->accumulated_counters), "subdiv accumulated counters");
}
static void subdiv_mesh_context_free(SubdivDeformContext *ctx)
@@ -117,7 +117,8 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
const int UNUSED(num_vertices),
const int UNUSED(num_edges),
const int UNUSED(num_loops),
- const int UNUSED(num_polygons))
+ const int UNUSED(num_polygons),
+ const int *UNUSED(subdiv_polygon_offset))
{
SubdivDeformContext *subdiv_context = foreach_context->user_data;
subdiv_mesh_prepare_accumulator(subdiv_context, subdiv_context->coarse_mesh->totvert);
@@ -202,7 +203,8 @@ void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
/* Make sure evaluator is up to date with possible new topology, and that
* is refined for the new positions of coarse vertices. */
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, vertex_cos)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(
+ subdiv, coarse_mesh, vertex_cos, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index 0001eb8a205..c2f7581637b 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -28,6 +28,7 @@
#include "BLI_bitmap.h"
#include "BLI_math_vector.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
@@ -38,7 +39,28 @@
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_topology_refiner_capi.h"
-bool BKE_subdiv_eval_begin(Subdiv *subdiv)
+/* ============================ Helper Function ============================ */
+
+static eOpenSubdivEvaluator opensubdiv_evalutor_from_subdiv_evaluator_type(
+ eSubdivEvaluatorType evaluator_type)
+{
+ switch (evaluator_type) {
+ case SUBDIV_EVALUATOR_TYPE_CPU: {
+ return OPENSUBDIV_EVALUATOR_CPU;
+ }
+ case SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE: {
+ return OPENSUBDIV_EVALUATOR_GLSL_COMPUTE;
+ }
+ }
+ BLI_assert_msg(0, "Unknown evaluator type");
+ return OPENSUBDIV_EVALUATOR_CPU;
+}
+
+/* ====================== Main Subdivision Evaluation ====================== */
+
+bool BKE_subdiv_eval_begin(Subdiv *subdiv,
+ eSubdivEvaluatorType evaluator_type,
+ OpenSubdiv_EvaluatorCache *evaluator_cache)
{
BKE_subdiv_stats_reset(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
if (subdiv->topology_refiner == NULL) {
@@ -47,8 +69,11 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv)
return false;
}
if (subdiv->evaluator == NULL) {
+ eOpenSubdivEvaluator opensubdiv_evaluator_type =
+ opensubdiv_evalutor_from_subdiv_evaluator_type(evaluator_type);
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
- subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(subdiv->topology_refiner);
+ subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(
+ subdiv->topology_refiner, opensubdiv_evaluator_type, evaluator_cache);
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
if (subdiv->evaluator == NULL) {
return false;
@@ -80,6 +105,9 @@ static void set_coarse_positions(Subdiv *subdiv,
BLI_BITMAP_ENABLE(vertex_used_map, loop->v);
}
}
+ /* Use a temporary buffer so we do not upload vertices one at a time to the GPU. */
+ float(*buffer)[3] = MEM_mallocN(sizeof(float[3]) * mesh->totvert, "subdiv tmp coarse positions");
+ int manifold_vertex_count = 0;
for (int vertex_index = 0, manifold_vertex_index = 0; vertex_index < mesh->totvert;
vertex_index++) {
if (!BLI_BITMAP_TEST_BOOL(vertex_used_map, vertex_index)) {
@@ -93,13 +121,49 @@ static void set_coarse_positions(Subdiv *subdiv,
const MVert *vertex = &mvert[vertex_index];
vertex_co = vertex->co;
}
- subdiv->evaluator->setCoarsePositions(subdiv->evaluator, vertex_co, manifold_vertex_index, 1);
+ copy_v3_v3(&buffer[manifold_vertex_index][0], vertex_co);
manifold_vertex_index++;
+ manifold_vertex_count++;
}
+ subdiv->evaluator->setCoarsePositions(
+ subdiv->evaluator, &buffer[0][0], 0, manifold_vertex_count);
MEM_freeN(vertex_used_map);
+ MEM_freeN(buffer);
+}
+
+/* Context which is used to fill face varying data in parallel. */
+typedef struct FaceVaryingDataFromUVContext {
+ OpenSubdiv_TopologyRefiner *topology_refiner;
+ const Mesh *mesh;
+ const MLoopUV *mloopuv;
+ float (*buffer)[2];
+ int layer_index;
+} FaceVaryingDataFromUVContext;
+
+static void set_face_varying_data_from_uv_task(void *__restrict userdata,
+ const int face_index,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ FaceVaryingDataFromUVContext *ctx = userdata;
+ OpenSubdiv_TopologyRefiner *topology_refiner = ctx->topology_refiner;
+ const int layer_index = ctx->layer_index;
+ const Mesh *mesh = ctx->mesh;
+ const MPoly *mpoly = &mesh->mpoly[face_index];
+ const MLoopUV *mluv = &ctx->mloopuv[mpoly->loopstart];
+
+ /* TODO(sergey): OpenSubdiv's C-API converter can change winding of
+ * loops of a face, need to watch for that, to prevent wrong UVs assigned.
+ */
+ const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner, face_index);
+ const int *uv_indices = topology_refiner->getFaceFVarValueIndices(
+ topology_refiner, face_index, layer_index);
+ for (int vertex_index = 0; vertex_index < num_face_vertices; vertex_index++, mluv++) {
+ copy_v2_v2(ctx->buffer[uv_indices[vertex_index]], mluv->uv);
+ }
}
static void set_face_varying_data_from_uv(Subdiv *subdiv,
+ const Mesh *mesh,
const MLoopUV *mloopuv,
const int layer_index)
{
@@ -107,25 +171,37 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv,
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
const int num_faces = topology_refiner->getNumFaces(topology_refiner);
const MLoopUV *mluv = mloopuv;
- /* TODO(sergey): OpenSubdiv's C-API converter can change winding of
- * loops of a face, need to watch for that, to prevent wrong UVs assigned.
- */
- for (int face_index = 0; face_index < num_faces; face_index++) {
- const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner,
- face_index);
- const int *uv_indices = topology_refiner->getFaceFVarValueIndices(
- topology_refiner, face_index, layer_index);
- for (int vertex_index = 0; vertex_index < num_face_vertices; vertex_index++, mluv++) {
- evaluator->setFaceVaryingData(evaluator, layer_index, mluv->uv, uv_indices[vertex_index], 1);
- }
- }
+
+ const int num_fvar_values = topology_refiner->getNumFVarValues(topology_refiner, layer_index);
+ /* Use a temporary buffer so we do not upload UVs one at a time to the GPU. */
+ float(*buffer)[2] = MEM_mallocN(sizeof(float[2]) * num_fvar_values, "temp UV storage");
+
+ FaceVaryingDataFromUVContext ctx;
+ ctx.topology_refiner = topology_refiner;
+ ctx.layer_index = layer_index;
+ ctx.mloopuv = mluv;
+ ctx.mesh = mesh;
+ ctx.buffer = buffer;
+
+ TaskParallelSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ parallel_range_settings.min_iter_per_thread = 1;
+
+ BLI_task_parallel_range(
+ 0, num_faces, &ctx, set_face_varying_data_from_uv_task, &parallel_range_settings);
+
+ evaluator->setFaceVaryingData(evaluator, layer_index, &buffer[0][0], 0, num_fvar_values);
+
+ MEM_freeN(buffer);
}
bool BKE_subdiv_eval_begin_from_mesh(Subdiv *subdiv,
const Mesh *mesh,
- const float (*coarse_vertex_cos)[3])
+ const float (*coarse_vertex_cos)[3],
+ eSubdivEvaluatorType evaluator_type,
+ OpenSubdiv_EvaluatorCache *evaluator_cache)
{
- if (!BKE_subdiv_eval_begin(subdiv)) {
+ if (!BKE_subdiv_eval_begin(subdiv, evaluator_type, evaluator_cache)) {
return false;
}
return BKE_subdiv_eval_refine_from_mesh(subdiv, mesh, coarse_vertex_cos);
@@ -146,7 +222,7 @@ bool BKE_subdiv_eval_refine_from_mesh(Subdiv *subdiv,
const int num_uv_layers = CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) {
const MLoopUV *mloopuv = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPUV, layer_index);
- set_face_varying_data_from_uv(subdiv, mloopuv, layer_index);
+ set_face_varying_data_from_uv(subdiv, mesh, mloopuv, layer_index);
}
/* Update evaluator to the new coarse geometry. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
@@ -188,8 +264,8 @@ void BKE_subdiv_eval_limit_point_and_derivatives(Subdiv *subdiv,
* This happens, for example, in single vertex on Suzannne's nose (where two quads have 2 common
* edges).
*
- * This makes tangent space displacement (such as multires) impossible to be used in those
- * vertices, so those needs to be addressed in one way or another.
+ * This makes tangent space displacement (such as multi-resolution) impossible to be used in
+ * those vertices, so those needs to be addressed in one way or another.
*
* Simplest thing to do: step inside of the face a little bit, where there is known patch at
* which there must be proper derivatives. This might break continuity of normals, but is better
@@ -221,18 +297,6 @@ void BKE_subdiv_eval_limit_point_and_normal(Subdiv *subdiv,
normalize_v3(r_N);
}
-void BKE_subdiv_eval_limit_point_and_short_normal(Subdiv *subdiv,
- const int ptex_face_index,
- const float u,
- const float v,
- float r_P[3],
- short r_N[3])
-{
- float N_float[3];
- BKE_subdiv_eval_limit_point_and_normal(subdiv, ptex_face_index, u, v, r_P, N_float);
- normal_float_to_short_v3(r_N, N_float);
-}
-
void BKE_subdiv_eval_face_varying(Subdiv *subdiv,
const int face_varying_channel,
const int ptex_face_index,
@@ -273,125 +337,3 @@ void BKE_subdiv_eval_final_point(
BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, r_P);
}
}
-
-/* =================== Patch queries at given resolution =================== */
-
-/* Move buffer forward by a given number of bytes. */
-static void buffer_apply_offset(void **buffer, const int offset)
-{
- *buffer = ((unsigned char *)*buffer) + offset;
-}
-
-/* Write given number of floats to the beginning of given buffer. */
-static void buffer_write_float_value(void **buffer, const float *values_buffer, int num_values)
-{
- memcpy(*buffer, values_buffer, sizeof(float) * num_values);
-}
-
-/* Similar to above, just operates with short values. */
-static void buffer_write_short_value(void **buffer, const short *values_buffer, int num_values)
-{
- memcpy(*buffer, values_buffer, sizeof(short) * num_values);
-}
-
-void BKE_subdiv_eval_limit_patch_resolution_point(Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *buffer,
- const int offset,
- const int stride)
-{
- buffer_apply_offset(&buffer, offset);
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- for (int y = 0; y < resolution; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution; x++) {
- const float u = x * inv_resolution_1;
- BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, buffer);
- buffer_apply_offset(&buffer, stride);
- }
- }
-}
-
-void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives(Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer,
- const int point_offset,
- const int point_stride,
- void *du_buffer,
- const int du_offset,
- const int du_stride,
- void *dv_buffer,
- const int dv_offset,
- const int dv_stride)
-{
- buffer_apply_offset(&point_buffer, point_offset);
- buffer_apply_offset(&du_buffer, du_offset);
- buffer_apply_offset(&dv_buffer, dv_offset);
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- for (int y = 0; y < resolution; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution; x++) {
- const float u = x * inv_resolution_1;
- BKE_subdiv_eval_limit_point_and_derivatives(
- subdiv, ptex_face_index, u, v, point_buffer, du_buffer, dv_buffer);
- buffer_apply_offset(&point_buffer, point_stride);
- buffer_apply_offset(&du_buffer, du_stride);
- buffer_apply_offset(&dv_buffer, dv_stride);
- }
- }
-}
-
-void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer,
- const int point_offset,
- const int point_stride,
- void *normal_buffer,
- const int normal_offset,
- const int normal_stride)
-{
- buffer_apply_offset(&point_buffer, point_offset);
- buffer_apply_offset(&normal_buffer, normal_offset);
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- for (int y = 0; y < resolution; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution; x++) {
- const float u = x * inv_resolution_1;
- float normal[3];
- BKE_subdiv_eval_limit_point_and_normal(subdiv, ptex_face_index, u, v, point_buffer, normal);
- buffer_write_float_value(&normal_buffer, normal, 3);
- buffer_apply_offset(&point_buffer, point_stride);
- buffer_apply_offset(&normal_buffer, normal_stride);
- }
- }
-}
-
-void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer,
- const int point_offset,
- const int point_stride,
- void *normal_buffer,
- const int normal_offset,
- const int normal_stride)
-{
- buffer_apply_offset(&point_buffer, point_offset);
- buffer_apply_offset(&normal_buffer, normal_offset);
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- for (int y = 0; y < resolution; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution; x++) {
- const float u = x * inv_resolution_1;
- short normal[3];
- BKE_subdiv_eval_limit_point_and_short_normal(
- subdiv, ptex_face_index, u, v, point_buffer, normal);
- buffer_write_short_value(&normal_buffer, normal, 3);
- buffer_apply_offset(&point_buffer, point_stride);
- buffer_apply_offset(&normal_buffer, normal_stride);
- }
- }
-}
diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c
index 061c196df2a..69bead27fe6 100644
--- a/source/blender/blenkernel/intern/subdiv_foreach.c
+++ b/source/blender/blenkernel/intern/subdiv_foreach.c
@@ -1877,7 +1877,8 @@ bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv,
ctx.num_subdiv_vertices,
ctx.num_subdiv_edges,
ctx.num_subdiv_loops,
- ctx.num_subdiv_polygons)) {
+ ctx.num_subdiv_polygons,
+ ctx.subdiv_polygon_offset)) {
subdiv_foreach_ctx_free(&ctx);
return false;
}
diff --git a/source/blender/blenkernel/intern/subdiv_inline.h b/source/blender/blenkernel/intern/subdiv_inline.h
index ba45d0a4997..d52adff1e61 100644
--- a/source/blender/blenkernel/intern/subdiv_inline.h
+++ b/source/blender/blenkernel/intern/subdiv_inline.h
@@ -103,13 +103,13 @@ BLI_INLINE void BKE_subdiv_rotate_grid_to_quad(
}
}
-BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_f(float edge_crease)
+BLI_INLINE float BKE_subdiv_crease_to_sharpness_f(float edge_crease)
{
return edge_crease * edge_crease * 10.0f;
}
-BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_char(char edge_crease)
+BLI_INLINE float BKE_subdiv_crease_to_sharpness_char(char edge_crease)
{
const float edge_crease_f = edge_crease / 255.0f;
- return BKE_subdiv_edge_crease_to_sharpness_f(edge_crease_f);
+ return BKE_subdiv_crease_to_sharpness_f(edge_crease_f);
}
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index 01bccab1bbd..c334d9a2c33 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -21,6 +21,7 @@
* \ingroup bke
*/
+#include "BKE_mesh.h"
#include "BKE_subdiv_mesh.h"
#include "atomic_ops.h"
@@ -58,23 +59,8 @@ typedef struct SubdivMeshContext {
/* UV layers interpolation. */
int num_uv_layers;
MLoopUV *uv_layers[MAX_MTFACE];
- /* Accumulated values.
- *
- * Averaging is happening for vertices along the coarse edges and corners.
- * This is needed for both displacement and normals.
- *
- * Displacement is being accumulated to a vertices coordinates, since those
- * are not needed during traversal of edge/corner vertices.
- *
- * For normals we are using dedicated array, since we can not use same
- * vertices (normals are `short`, which will cause a lot of precision
- * issues). */
- float (*accumulated_normals)[3];
/* Per-subdivided vertex counter of averaged values. */
int *accumulated_counters;
- /* Denotes whether normals can be evaluated from a limit surface. One case
- * when it's not possible is when displacement is used. */
- bool can_evaluate_normals;
bool have_displacement;
} SubdivMeshContext;
@@ -102,20 +88,12 @@ static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx)
static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vertices)
{
- if (!ctx->can_evaluate_normals && !ctx->have_displacement) {
- return;
- }
- /* TODO(sergey): Technically, this is overallocating, we don't need memory
- * for an inner subdivision vertices. */
- ctx->accumulated_normals = MEM_calloc_arrayN(
- sizeof(*ctx->accumulated_normals), num_vertices, "subdiv accumulated normals");
ctx->accumulated_counters = MEM_calloc_arrayN(
- sizeof(*ctx->accumulated_counters), num_vertices, "subdiv accumulated counters");
+ num_vertices, sizeof(*ctx->accumulated_counters), "subdiv accumulated counters");
}
static void subdiv_mesh_context_free(SubdivMeshContext *ctx)
{
- MEM_SAFE_FREE(ctx->accumulated_normals);
MEM_SAFE_FREE(ctx->accumulated_counters);
}
@@ -450,48 +428,23 @@ static void subdiv_mesh_tls_free(void *tls_v)
/** \} */
-/* -------------------------------------------------------------------- */
-/** \name Evaluation helper functions
- * \{ */
-
-static void eval_final_point_and_vertex_normal(Subdiv *subdiv,
- const int ptex_face_index,
- const float u,
- const float v,
- float r_P[3],
- short r_N[3])
-{
- if (subdiv->displacement_evaluator == NULL) {
- BKE_subdiv_eval_limit_point_and_short_normal(subdiv, ptex_face_index, u, v, r_P, r_N);
- }
- else {
- BKE_subdiv_eval_final_point(subdiv, ptex_face_index, u, v, r_P);
- }
-}
-
/** \} */
/* -------------------------------------------------------------------- */
/** \name Accumulation helpers
* \{ */
-static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext *ctx,
- const int ptex_face_index,
- const float u,
- const float v,
- MVert *subdiv_vert)
+static void subdiv_accumulate_vertex_displacement(SubdivMeshContext *ctx,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ MVert *subdiv_vert)
{
Subdiv *subdiv = ctx->subdiv;
const int subdiv_vertex_index = subdiv_vert - ctx->subdiv_mesh->mvert;
float dummy_P[3], dPdu[3], dPdv[3], D[3];
BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
- /* Accumulate normal. */
- if (ctx->can_evaluate_normals) {
- float N[3];
- cross_v3_v3v3(N, dPdu, dPdv);
- normalize_v3(N);
- add_v3_v3(ctx->accumulated_normals[subdiv_vertex_index], N);
- }
+
/* Accumulate displacement if needed. */
if (ctx->have_displacement) {
/* NOTE: The subdivided mesh is allocated in this module, and its vertices are kept at zero
@@ -514,9 +467,10 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
const int num_vertices,
const int num_edges,
const int num_loops,
- const int num_polygons)
+ const int num_polygons,
+ const int *UNUSED(subdiv_polygon_offset))
{
- /* Multires grid data will be applied or become invalid after subdivision,
+ /* Multi-resolution grid data will be applied or become invalid after subdivision,
* so don't try to preserve it and use memory. */
CustomData_MeshMasks mask = CD_MASK_EVERYTHING;
mask.lmask &= ~CD_MASK_MULTIRES_GRIDS;
@@ -588,13 +542,6 @@ static void evaluate_vertex_and_apply_displacement_copy(const SubdivMeshContext
BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_vert->co);
/* Apply displacement. */
add_v3_v3(subdiv_vert->co, D);
- /* Copy normal from accumulated storage. */
- if (ctx->can_evaluate_normals) {
- float N[3];
- copy_v3_v3(N, ctx->accumulated_normals[subdiv_vertex_index]);
- normalize_v3(N);
- normal_float_to_short_v3(subdiv_vert->no, N);
- }
/* Remove facedot flag. This can happen if there is more than one subsurf modifier. */
subdiv_vert->flag &= ~ME_VERT_FACEDOT;
}
@@ -621,15 +568,6 @@ static void evaluate_vertex_and_apply_displacement_interpolate(
BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_vert->co);
/* Apply displacement. */
add_v3_v3(subdiv_vert->co, D);
- /* Copy normal from accumulated storage. */
- if (ctx->can_evaluate_normals) {
- const float inv_num_accumulated = 1.0f / ctx->accumulated_counters[subdiv_vertex_index];
- float N[3];
- copy_v3_v3(N, ctx->accumulated_normals[subdiv_vertex_index]);
- mul_v3_fl(N, inv_num_accumulated);
- normalize_v3(N);
- normal_float_to_short_v3(subdiv_vert->no, N);
- }
}
static void subdiv_mesh_vertex_every_corner_or_edge(const SubdivForeachContext *foreach_context,
@@ -643,7 +581,7 @@ static void subdiv_mesh_vertex_every_corner_or_edge(const SubdivForeachContext *
Mesh *subdiv_mesh = ctx->subdiv_mesh;
MVert *subdiv_mvert = subdiv_mesh->mvert;
MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
- subdiv_accumulate_vertex_normal_and_displacement(ctx, ptex_face_index, u, v, subdiv_vert);
+ subdiv_accumulate_vertex_displacement(ctx, ptex_face_index, u, v, subdiv_vert);
}
static void subdiv_mesh_vertex_every_corner(const SubdivForeachContext *foreach_context,
@@ -792,8 +730,7 @@ static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context
MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
subdiv_mesh_ensure_vertex_interpolation(ctx, tls, coarse_poly, coarse_corner);
subdiv_vertex_data_interpolate(ctx, subdiv_vert, &tls->vertex_interpolation, u, v);
- eval_final_point_and_vertex_normal(
- subdiv, ptex_face_index, u, v, subdiv_vert->co, subdiv_vert->no);
+ BKE_subdiv_eval_final_point(subdiv, ptex_face_index, u, v, subdiv_vert->co);
subdiv_mesh_tag_center_vertex(coarse_poly, subdiv_vert, u, v);
}
@@ -1083,29 +1020,20 @@ static void subdiv_mesh_vertex_of_loose_edge_interpolate(SubdivMeshContext *ctx,
{
const Mesh *coarse_mesh = ctx->coarse_mesh;
Mesh *subdiv_mesh = ctx->subdiv_mesh;
- if (u == 0.0f) {
- CustomData_copy_data(
- &coarse_mesh->vdata, &subdiv_mesh->vdata, coarse_edge->v1, subdiv_vertex_index, 1);
- }
- else if (u == 1.0f) {
- CustomData_copy_data(
- &coarse_mesh->vdata, &subdiv_mesh->vdata, coarse_edge->v2, subdiv_vertex_index, 1);
- }
- else {
- BLI_assert(u > 0.0f);
- BLI_assert(u < 1.0f);
- const float interpolation_weights[2] = {1.0f - u, u};
- const int coarse_vertex_indices[2] = {coarse_edge->v1, coarse_edge->v2};
- CustomData_interp(&coarse_mesh->vdata,
- &subdiv_mesh->vdata,
- coarse_vertex_indices,
- interpolation_weights,
- NULL,
- 2,
- subdiv_vertex_index);
- if (ctx->vert_origindex != NULL) {
- ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE;
- }
+ /* This is never used for end-points (which are copied from the original). */
+ BLI_assert(u > 0.0f);
+ BLI_assert(u < 1.0f);
+ const float interpolation_weights[2] = {1.0f - u, u};
+ const int coarse_vertex_indices[2] = {coarse_edge->v1, coarse_edge->v2};
+ CustomData_interp(&coarse_mesh->vdata,
+ &subdiv_mesh->vdata,
+ coarse_vertex_indices,
+ interpolation_weights,
+ NULL,
+ 2,
+ subdiv_vertex_index);
+ if (ctx->vert_origindex != NULL) {
+ ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE;
}
}
@@ -1124,8 +1052,11 @@ static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext *
/* Find neighbors of the current loose edge. */
const MEdge *neighbors[2];
find_edge_neighbors(ctx, coarse_edge, neighbors);
- /* Interpolate custom data. */
- subdiv_mesh_vertex_of_loose_edge_interpolate(ctx, coarse_edge, u, subdiv_vertex_index);
+ /* Interpolate custom data when not an end point.
+ * This data has already been copied from the original vertex by #subdiv_mesh_vertex_loose. */
+ if (!ELEM(u, 0.0, 1.0)) {
+ subdiv_mesh_vertex_of_loose_edge_interpolate(ctx, coarse_edge, u, subdiv_vertex_index);
+ }
/* Interpolate coordinate. */
MVert *subdiv_vertex = &subdiv_mvert[subdiv_vertex_index];
if (is_simple) {
@@ -1146,12 +1077,6 @@ static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext *
/* TODO(sergey): This matches old behavior, but we can as well interpolate
* it. Maybe even using vertex varying attributes. */
subdiv_vertex->bweight = 0.0f;
- /* Reset normal, initialize it in a similar way as edit mode does for a
- * vertices adjacent to a loose edges.
- * See `mesh_evaluate#mesh_calc_normals_vert_fallback` */
- float no[3];
- normalize_v3_v3(no, subdiv_vertex->co);
- normal_float_to_short_v3(subdiv_vertex->no, no);
}
/** \} */
@@ -1166,8 +1091,8 @@ static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context,
memset(foreach_context, 0, sizeof(*foreach_context));
/* General information. */
foreach_context->topology_info = subdiv_mesh_topology_info;
- /* Every boundary geometry. Used for displacement and normals averaging. */
- if (subdiv_context->can_evaluate_normals || subdiv_context->have_displacement) {
+ /* Every boundary geometry. Used for displacement averaging. */
+ if (subdiv_context->have_displacement) {
foreach_context->vertex_every_corner = subdiv_mesh_vertex_every_corner;
foreach_context->vertex_every_edge = subdiv_mesh_vertex_every_edge;
}
@@ -1199,7 +1124,8 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
/* Make sure evaluator is up to date with possible new topology, and that
* it is refined for the new positions of coarse vertices. */
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(
+ subdiv, coarse_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
@@ -1216,8 +1142,6 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
subdiv_context.coarse_mesh = coarse_mesh;
subdiv_context.subdiv = subdiv;
subdiv_context.have_displacement = (subdiv->displacement_evaluator != NULL);
- subdiv_context.can_evaluate_normals = !subdiv_context.have_displacement &&
- subdiv_context.subdiv->settings.is_adaptive;
/* Multi-threaded traversal/evaluation. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
SubdivForeachContext foreach_context;
@@ -1231,9 +1155,11 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
Mesh *result = subdiv_context.subdiv_mesh;
// BKE_mesh_validate(result, true, true);
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
- if (!subdiv_context.can_evaluate_normals) {
- BKE_mesh_normals_tag_dirty(result);
- }
+ /* Using normals from the limit surface gives different results than Blender's vertex normal
+ * calculation. Since vertex normals are supposed to be a consistent cache, don't bother
+ * calculating them here. The work may have been pointless anyway if the mesh is deformed or
+ * changed afterwards. */
+ BKE_mesh_normals_tag_dirty(result);
/* Free used memory. */
subdiv_mesh_context_free(&subdiv_context);
return result;
diff --git a/source/blender/blenkernel/intern/subdiv_modifier.c b/source/blender/blenkernel/intern/subdiv_modifier.c
new file mode 100644
index 00000000000..525c4837bc4
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_modifier.c
@@ -0,0 +1,160 @@
+/*
+ * 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) 2021 by Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "BKE_subdiv_modifier.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_modifier.h"
+#include "BKE_subdiv.h"
+
+#include "GPU_capabilities.h"
+#include "GPU_context.h"
+
+#include "opensubdiv_capi.h"
+
+void BKE_subsurf_modifier_subdiv_settings_init(SubdivSettings *settings,
+ const SubsurfModifierData *smd,
+ const bool use_render_params)
+{
+ const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels;
+
+ settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
+ settings->is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision);
+ settings->level = settings->is_simple ?
+ 1 :
+ (settings->is_adaptive ? smd->quality : requested_levels);
+ settings->use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease);
+ settings->vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
+ smd->boundary_smooth);
+ settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
+ smd->uv_smooth);
+}
+
+static ModifierData *modifier_get_last_enabled_for_mode(const Scene *scene,
+ const Object *ob,
+ int required_mode)
+{
+ ModifierData *md = ob->modifiers.last;
+
+ while (md) {
+ if (BKE_modifier_is_enabled(scene, md, required_mode)) {
+ break;
+ }
+
+ md = md->prev;
+ }
+
+ return md;
+}
+
+bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const Scene *scene,
+ const Object *ob,
+ const SubsurfModifierData *smd,
+ int required_mode,
+ bool skip_check_is_last)
+{
+ if ((U.gpu_flag & USER_GPU_FLAG_SUBDIVISION_EVALUATION) == 0) {
+ return false;
+ }
+
+ if (!skip_check_is_last) {
+ ModifierData *md = modifier_get_last_enabled_for_mode(scene, ob, required_mode);
+ if (md != (const ModifierData *)smd) {
+ return false;
+ }
+ }
+
+ /* Only OpenGL is supported for OpenSubdiv evaluation for now. */
+ if (GPU_backend_get_type() != GPU_BACKEND_OPENGL) {
+ return false;
+ }
+
+ if (!(GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support())) {
+ return false;
+ }
+
+ const int available_evaluators = openSubdiv_getAvailableEvaluators();
+ if ((available_evaluators & OPENSUBDIV_EVALUATOR_GLSL_COMPUTE) == 0) {
+ return false;
+ }
+
+ return true;
+}
+
+bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
+ const Object *ob,
+ int required_mode)
+{
+ ModifierData *md = modifier_get_last_enabled_for_mode(scene, ob, required_mode);
+
+ if (!md) {
+ return false;
+ }
+
+ if (md->type != eModifierType_Subsurf) {
+ return false;
+ }
+
+ return BKE_subsurf_modifier_can_do_gpu_subdiv_ex(
+ scene, ob, (SubsurfModifierData *)md, required_mode, true);
+}
+
+void (*BKE_subsurf_modifier_free_gpu_cache_cb)(Subdiv *subdiv) = NULL;
+
+Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(const SubsurfModifierData *smd,
+ const SubdivSettings *subdiv_settings,
+ const Mesh *mesh,
+ const bool for_draw_code)
+{
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ if (runtime_data->subdiv && runtime_data->set_by_draw_code != for_draw_code) {
+ BKE_subdiv_free(runtime_data->subdiv);
+ runtime_data->subdiv = NULL;
+ }
+ Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_settings, mesh);
+ runtime_data->subdiv = subdiv;
+ runtime_data->set_by_draw_code = for_draw_code;
+ return subdiv;
+}
+
+SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(SubsurfModifierData *smd)
+{
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ if (runtime_data == NULL) {
+ runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
+ smd->modifier.runtime = runtime_data;
+ }
+ return runtime_data;
+}
+
+int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode)
+{
+ if (is_final_render) {
+ return eModifierMode_Render;
+ }
+
+ return eModifierMode_Realtime | (is_edit_mode ? eModifierMode_Editmode : 0);
+}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index a1b45c2ac7d..9d66c354b54 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -717,7 +717,6 @@ static void minmax_v3_v3v3(const float vec[3], float min[3], float max[3])
}
}
-/* UNUSED, keep since this functionality may be useful in the future. */
static void UNUSED_FUNCTION(ccgDM_getMinMax)(DerivedMesh *dm, float r_min[3], float r_max[3])
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
@@ -804,17 +803,11 @@ static int ccgDM_getNumLoops(DerivedMesh *dm)
return 4 * ccgSubSurf_getNumFinalFaces(ccgdm->ss);
}
-static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
+static CCGElem *get_vertex_elem(CCGDerivedMesh *ccgdm, int vertNum)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
CCGSubSurf *ss = ccgdm->ss;
- CCGElem *vd;
- CCGKey key;
int i;
- CCG_key_top_level(&key, ss);
- memset(mv, 0, sizeof(*mv));
-
if ((vertNum < ccgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumFaces(ss) > 0)) {
/* this vert comes from face data */
int lastface = ccgSubSurf_getNumFaces(ss) - 1;
@@ -843,30 +836,24 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
offset = vertNum - ccgdm->faceMap[i].startVert;
if (offset < 1) {
- vd = ccgSubSurf_getFaceCenterData(f);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ return ccgSubSurf_getFaceCenterData(f);
}
- else if (offset < gridSideEnd) {
+ if (offset < gridSideEnd) {
offset -= 1;
grid = offset / gridSideVerts;
x = offset % gridSideVerts + 1;
- vd = ccgSubSurf_getFaceGridEdgeData(ss, f, grid, x);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ return ccgSubSurf_getFaceGridEdgeData(ss, f, grid, x);
}
- else if (offset < gridInternalEnd) {
+ if (offset < gridInternalEnd) {
offset -= gridSideEnd;
grid = offset / gridInternalVerts;
offset %= gridInternalVerts;
y = offset / gridSideVerts + 1;
x = offset % gridSideVerts + 1;
- vd = ccgSubSurf_getFaceGridData(ss, f, grid, x, y);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ return ccgSubSurf_getFaceGridData(ss, f, grid, x, y);
}
}
- else if ((vertNum < ccgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
+ if ((vertNum < ccgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
/* this vert comes from edge data */
CCGEdge *e;
int lastedge = ccgSubSurf_getNumEdges(ss) - 1;
@@ -880,175 +867,39 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
e = ccgdm->edgeMap[i].edge;
x = vertNum - ccgdm->edgeMap[i].startVert + 1;
- vd = ccgSubSurf_getEdgeData(ss, e, x);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ return ccgSubSurf_getEdgeData(ss, e, x);
}
- else {
- /* this vert comes from vert data */
- CCGVert *v;
- i = vertNum - ccgdm->vertMap[0].startVert;
- v = ccgdm->vertMap[i].vert;
- vd = ccgSubSurf_getVertData(ss, v);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
- }
-}
+ /* this vert comes from vert data */
+ CCGVert *v;
+ i = vertNum - ccgdm->vertMap[0].startVert;
-static void ccgDM_getFinalVertCo(DerivedMesh *dm, int vertNum, float r_co[3])
-{
- MVert mvert;
-
- ccgDM_getFinalVert(dm, vertNum, &mvert);
- copy_v3_v3(r_co, mvert.co);
-}
-
-static void ccgDM_getFinalVertNo(DerivedMesh *dm, int vertNum, float r_no[3])
-{
- MVert mvert;
-
- ccgDM_getFinalVert(dm, vertNum, &mvert);
- normal_short_to_float_v3(r_no, mvert.no);
+ v = ccgdm->vertMap[i].vert;
+ return ccgSubSurf_getVertData(ss, v);
}
-static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
+static void ccgDM_getFinalVertCo(DerivedMesh *dm, int vertNum, float r_co[3])
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
CCGSubSurf *ss = ccgdm->ss;
- int i;
-
- memset(med, 0, sizeof(*med));
-
- if (edgeNum < ccgdm->edgeMap[0].startEdge) {
- /* this edge comes from face data */
- int lastface = ccgSubSurf_getNumFaces(ss) - 1;
- CCGFace *f;
- int x, y, grid /*, numVerts*/;
- int offset;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int gridSideEdges;
- int gridInternalEdges;
-
- i = 0;
- while (i < lastface && edgeNum >= ccgdm->faceMap[i + 1].startEdge) {
- i++;
- }
-
- f = ccgdm->faceMap[i].face;
- /* numVerts = ccgSubSurf_getFaceNumVerts(f); */ /*UNUSED*/
-
- gridSideEdges = gridSize - 1;
- gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
-
- offset = edgeNum - ccgdm->faceMap[i].startEdge;
- grid = offset / (gridSideEdges + gridInternalEdges);
- offset %= (gridSideEdges + gridInternalEdges);
-
- if (offset < gridSideEdges) {
- x = offset;
- med->v1 = getFaceIndex(ss, f, grid, x, 0, edgeSize, gridSize);
- med->v2 = getFaceIndex(ss, f, grid, x + 1, 0, edgeSize, gridSize);
- }
- else {
- offset -= gridSideEdges;
- x = (offset / 2) / gridSideEdges + 1;
- y = (offset / 2) % gridSideEdges;
- if (offset % 2 == 0) {
- med->v1 = getFaceIndex(ss, f, grid, x, y, edgeSize, gridSize);
- med->v2 = getFaceIndex(ss, f, grid, x, y + 1, edgeSize, gridSize);
- }
- else {
- med->v1 = getFaceIndex(ss, f, grid, y, x, edgeSize, gridSize);
- med->v2 = getFaceIndex(ss, f, grid, y + 1, x, edgeSize, gridSize);
- }
- }
- }
- else {
- /* this vert comes from edge data */
- CCGEdge *e;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int x;
- short *edgeFlag;
- unsigned int flags = 0;
-
- i = (edgeNum - ccgdm->edgeMap[0].startEdge) / (edgeSize - 1);
- e = ccgdm->edgeMap[i].edge;
-
- if (!ccgSubSurf_getEdgeNumFaces(e)) {
- flags |= ME_LOOSEEDGE;
- }
-
- x = edgeNum - ccgdm->edgeMap[i].startEdge;
-
- med->v1 = getEdgeIndex(ss, e, x, edgeSize);
- med->v2 = getEdgeIndex(ss, e, x + 1, edgeSize);
-
- edgeFlag = (ccgdm->edgeFlags) ? &ccgdm->edgeFlags[i] : NULL;
- if (edgeFlag) {
- flags |= (*edgeFlag & (ME_SEAM | ME_SHARP)) | ME_EDGEDRAW | ME_EDGERENDER;
- }
- else {
- flags |= ME_EDGEDRAW | ME_EDGERENDER;
- }
-
- med->flag = flags;
- }
+ CCGElem *vd = get_vertex_elem(ccgdm, vertNum);
+ CCGKey key;
+ CCG_key_top_level(&key, ss);
+ copy_v3_v3(r_co, CCG_elem_co(&key, vd));
}
-static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf)
+static void ccgDM_getFinalVertNo(DerivedMesh *dm, int vertNum, float r_no[3])
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
CCGSubSurf *ss = ccgdm->ss;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int gridSideEdges = gridSize - 1;
- int gridFaces = gridSideEdges * gridSideEdges;
- int i;
- CCGFace *f;
- // int numVerts;
- int offset;
- int grid;
- int x, y;
- // int lastface = ccgSubSurf_getNumFaces(ss) - 1; /* UNUSED */
- DMFlagMat *faceFlags = ccgdm->faceFlags;
-
- memset(mf, 0, sizeof(*mf));
- if (faceNum >= ccgdm->dm.numTessFaceData) {
- return;
- }
-
- i = ccgdm->reverseFaceMap[faceNum];
- f = ccgdm->faceMap[i].face;
- // numVerts = ccgSubSurf_getFaceNumVerts(f); /* UNUSED */
-
- offset = faceNum - ccgdm->faceMap[i].startFace;
- grid = offset / gridFaces;
- offset %= gridFaces;
- y = offset / gridSideEdges;
- x = offset % gridSideEdges;
-
- mf->v1 = getFaceIndex(ss, f, grid, x + 0, y + 0, edgeSize, gridSize);
- mf->v2 = getFaceIndex(ss, f, grid, x + 0, y + 1, edgeSize, gridSize);
- mf->v3 = getFaceIndex(ss, f, grid, x + 1, y + 1, edgeSize, gridSize);
- mf->v4 = getFaceIndex(ss, f, grid, x + 1, y + 0, edgeSize, gridSize);
-
- if (faceFlags) {
- mf->flag = faceFlags[i].flag;
- mf->mat_nr = faceFlags[i].mat_nr;
- }
- else {
- mf->flag = ME_SMOOTH;
- }
-
- mf->edcode = 0;
+ CCGElem *vd = get_vertex_elem(ccgdm, vertNum);
+ CCGKey key;
+ CCG_key_top_level(&key, ss);
+ copy_v3_v3(r_no, CCG_elem_no(&key, vd));
}
-/* Translate GridHidden into the ME_HIDE flag for MVerts. Assumes
- * vertices are in the order output by ccgDM_copyFinalVertArray. */
void subsurf_copy_grid_hidden(DerivedMesh *dm,
const MPoly *mpoly,
MVert *mvert,
@@ -1090,8 +941,6 @@ void subsurf_copy_grid_hidden(DerivedMesh *dm,
}
}
-/* Translate GridPaintMask into vertex paint masks. Assumes vertices
- * are in the order output by ccgDM_copyFinalVertArray. */
void subsurf_copy_grid_paint_mask(DerivedMesh *dm,
const MPoly *mpoly,
float *paint_mask,
@@ -1135,7 +984,6 @@ void subsurf_copy_grid_paint_mask(DerivedMesh *dm,
BLI_INLINE void ccgDM_to_MVert(MVert *mv, const CCGKey *key, CCGElem *elem)
{
copy_v3_v3(mv->co, CCG_elem_co(key, elem));
- normal_float_to_short_v3(mv->no, CCG_elem_no(key, elem));
mv->flag = mv->bweight = 0;
}
@@ -1920,10 +1768,6 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm)
ccgdm->dm.getNumPolys = ccgDM_getNumPolys;
ccgdm->dm.getNumTessFaces = ccgDM_getNumTessFaces;
- ccgdm->dm.getVert = ccgDM_getFinalVert;
- ccgdm->dm.getEdge = ccgDM_getFinalEdge;
- ccgdm->dm.getTessFace = ccgDM_getFinalFace;
-
ccgdm->dm.getVertCo = ccgDM_getFinalVertCo;
ccgdm->dm.getVertNo = ccgDM_getFinalVertNo;
@@ -2032,9 +1876,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
gridSideEdges = gridSize - 1;
gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
- /* mvert = dm->getVertArray(dm); */ /* UNUSED */
medge = dm->getEdgeArray(dm);
- /* mface = dm->getTessFaceArray(dm); */ /* UNUSED */
mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
base_polyOrigIndex = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
@@ -2161,7 +2003,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
&dm->loopData, &ccgdm->dm.loopData, loopidx, w2, NULL, numVerts, loopindex2);
loopindex2++;
- /* Copy over poly data, e.g. mtexpoly. */
+ /* Copy over poly data, e.g. #CD_FACEMAP. */
CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, origIndex, faceNum, 1);
/* Set original index data. */
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 5eb40b6624a..4406647bd2c 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -49,6 +49,7 @@
#include "DNA_text_types.h"
#include "DNA_userdef_types.h"
+#include "BKE_bpath.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -169,6 +170,15 @@ static void text_free_data(ID *id)
#endif
}
+static void text_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Text *text = (Text *)id;
+
+ if (text->filepath != NULL) {
+ BKE_bpath_foreach_path_allocated_process(bpath_data, &text->filepath);
+ }
+}
+
static void text_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Text *text = (Text *)id;
@@ -242,6 +252,7 @@ IDTypeInfo IDType_ID_TXT = {
.name_plural = "texts",
.translation_context = BLT_I18NCONTEXT_ID_TEXT,
.flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = text_init_data,
.copy_data = text_copy_data,
@@ -249,6 +260,7 @@ IDTypeInfo IDType_ID_TXT = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = text_foreach_path,
.owner_get = NULL,
.blend_write = text_blend_write,
@@ -267,9 +279,6 @@ IDTypeInfo IDType_ID_TXT = {
/** \name Text Add, Free, Validation
* \{ */
-/**
- * \note caller must handle `compiled` member.
- */
void BKE_text_free_lines(Text *text)
{
for (TextLine *tmp = text->lines.first, *tmp_next; tmp; tmp = tmp_next) {
@@ -299,8 +308,6 @@ Text *BKE_text_add(Main *bmain, const char *name)
return ta;
}
-/* this function replaces extended ascii characters */
-/* to a valid utf-8 sequences */
int txt_extended_ascii_as_utf8(char **str)
{
ptrdiff_t bad_char, i = 0;
@@ -463,14 +470,6 @@ bool BKE_text_reload(Text *text)
return true;
}
-/**
- * Load a text file.
- *
- * \param is_internal: If \a true, this text data-block only exists in memory,
- * not as a file on disk.
- *
- * \note text data-blocks have no real user but have 'fake user' enabled by default
- */
Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal)
{
unsigned char *buffer;
@@ -480,7 +479,7 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
BLI_stat_t st;
BLI_strncpy(filepath_abs, file, FILE_MAX);
- if (relpath) { /* can be NULL (bg mode) */
+ if (relpath) { /* Can be NULL (background mode). */
BLI_path_abs(filepath_abs, relpath);
}
@@ -523,11 +522,6 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
return ta;
}
-/**
- * Load a text file.
- *
- * \note Text data-blocks have no user by default, only the 'real user' flag.
- */
Text *BKE_text_load(Main *bmain, const char *file, const char *relpath)
{
return BKE_text_load_ex(bmain, file, relpath, false);
@@ -547,11 +541,6 @@ void BKE_text_write(Text *text, const char *str) /* called directly from rna */
txt_make_dirty(text);
}
-/* returns 0 if file on disk is the same or Text is in memory only
- * returns 1 if file has been modified on disk since last local edit
- * returns 2 if file on disk has been deleted
- * -1 is returned if an error occurs */
-
int BKE_text_file_modified_check(Text *text)
{
BLI_stat_t st;
@@ -1131,7 +1120,6 @@ void txt_move_toline(Text *text, unsigned int line, const bool sel)
txt_move_to(text, line, 0, sel);
}
-/* Moves to a certain byte in a line, not a certain utf8-character! */
void txt_move_to(Text *text, unsigned int line, unsigned int ch, const bool sel)
{
TextLine **linep;
@@ -1291,11 +1279,6 @@ void txt_sel_all(Text *text)
text->selc = text->sell->len;
}
-/**
- * Reverse of #txt_pop_sel
- * Clears the selection and ensures the cursor is located
- * at the selection (where the cursor is visually while editing).
- */
void txt_sel_clear(Text *text)
{
if (text->sell) {
@@ -1382,9 +1365,6 @@ void txt_sel_set(Text *text, int startl, int startc, int endl, int endc)
* - Are not null terminated.
* \{ */
-/**
- * Create a buffer, the only requirement is #txt_from_buf_for_undo can decode it.
- */
char *txt_to_buf_for_undo(Text *text, int *r_buf_len)
{
int buf_len = 0;
@@ -1402,9 +1382,6 @@ char *txt_to_buf_for_undo(Text *text, int *r_buf_len)
return buf;
}
-/**
- * Decode a buffer from #txt_to_buf_for_undo.
- */
void txt_from_buf_for_undo(Text *text, const char *buf, int buf_len)
{
const char *buf_end = buf + buf_len;
@@ -1977,7 +1954,7 @@ static char tab_to_spaces[] = " ";
static void txt_convert_tab_to_spaces(Text *text)
{
/* sb aims to pad adjust the tab-width needed so that the right number of spaces
- * is added so that the indention of the line is the right width (i.e. aligned
+ * is added so that the indentation of the line is the right width (i.e. aligned
* to multiples of TXT_TABSIZE)
*/
const char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE];
@@ -2401,10 +2378,11 @@ int text_check_bracket(const char ch)
return 0;
}
-/* TODO: have a function for operators -
- * http://docs.python.org/py3k/reference/lexical_analysis.html#operators */
bool text_check_delim(const char ch)
{
+ /* TODO: have a function for operators:
+ * http://docs.python.org/py3k/reference/lexical_analysis.html#operators */
+
int a;
char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,@";
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index d5f7647f07a..37d5d732a70 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -67,6 +67,8 @@
#include "BKE_scene.h"
#include "BKE_texture.h"
+#include "NOD_texture.h"
+
#include "RE_texture.h"
#include "BLO_read_write.h"
@@ -142,9 +144,10 @@ static void texture_foreach_id(ID *id, LibraryForeachIDData *data)
Tex *texture = (Tex *)id;
if (texture->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_embedded(data, (ID **)&texture->nodetree);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&texture->nodetree));
}
- BKE_LIB_FOREACHID_PROCESS(data, texture->ima, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, texture->ima, IDWALK_CB_USER);
}
static void texture_blend_write(BlendWriter *writer, ID *id, const void *id_address)
@@ -184,7 +187,6 @@ static void texture_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_data_address(reader, &tex->preview);
BKE_previewimg_blend_read(reader, tex->preview);
- tex->iuser.ok = 1;
tex->iuser.scene = NULL;
}
@@ -211,6 +213,7 @@ IDTypeInfo IDType_ID_TE = {
.name_plural = "textures",
.translation_context = BLT_I18NCONTEXT_ID_TEXTURE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = texture_init_data,
.copy_data = texture_copy_data,
@@ -218,6 +221,7 @@ IDTypeInfo IDType_ID_TE = {
.make_local = NULL,
.foreach_id = texture_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = texture_blend_write,
@@ -230,11 +234,10 @@ IDTypeInfo IDType_ID_TE = {
.lib_override_apply_post = NULL,
};
-/* Utils for all IDs using those texture slots. */
void BKE_texture_mtex_foreach_id(LibraryForeachIDData *data, MTex *mtex)
{
- BKE_LIB_FOREACHID_PROCESS(data, mtex->object, IDWALK_CB_NOP);
- BKE_LIB_FOREACHID_PROCESS(data, mtex->tex, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mtex->object, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mtex->tex, IDWALK_CB_USER);
}
/* ****************** Mapping ******************* */
@@ -412,7 +415,6 @@ MTex *BKE_texture_mtex_add(void)
return mtex;
}
-/* slot -1 for first free ID */
MTex *BKE_texture_mtex_add_id(ID *id, int slot)
{
MTex **mtex_ar;
@@ -670,9 +672,6 @@ void BKE_texture_pointdensity_free(PointDensity *pd)
}
/* ------------------------------------------------------------------------- */
-/**
- * \returns true if this texture can use its #Texture.ima (even if its NULL)
- */
bool BKE_texture_is_image_user(const struct Tex *tex)
{
switch (tex->type) {
@@ -684,7 +683,6 @@ bool BKE_texture_is_image_user(const struct Tex *tex)
return false;
}
-/* ------------------------------------------------------------------------- */
bool BKE_texture_dependsOnTime(const struct Tex *texture)
{
if (texture->ima && BKE_image_is_animated(texture->ima)) {
@@ -758,7 +756,6 @@ static void texture_nodes_fetch_images_for_pool(Tex *texture,
}
}
-/* Make sure all images used by texture are loaded into pool. */
void BKE_texture_fetch_images_for_pool(Tex *texture, struct ImagePool *pool)
{
if (texture->nodetree != NULL) {
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 068d048fd08..3878d3b1c98 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -160,11 +160,6 @@ static void tracking_dopesheet_free(MovieTrackingDopesheet *dopesheet)
dopesheet->tot_channel = 0;
}
-/* Free tracking structure, only frees structure contents
- * (if structure is allocated in heap, it shall be handled outside).
- *
- * All the pointers inside structure becomes invalid after this call.
- */
void BKE_tracking_free(MovieTracking *tracking)
{
tracking_tracks_free(&tracking->tracks);
@@ -276,7 +271,6 @@ static void tracking_objects_copy(ListBase *objects_dst,
}
}
-/* Copy tracking structure content. */
void BKE_tracking_copy(MovieTracking *tracking_dst,
const MovieTracking *tracking_src,
const int flag)
@@ -321,9 +315,6 @@ void BKE_tracking_copy(MovieTracking *tracking_dst,
BLI_ghash_free(tracks_mapping, NULL, NULL);
}
-/* Initialize motion tracking settings to default values,
- * used when new movie clip datablock is created.
- */
void BKE_tracking_settings_init(MovieTracking *tracking)
{
tracking->camera.sensor_width = 35.0f;
@@ -361,7 +352,6 @@ void BKE_tracking_settings_init(MovieTracking *tracking)
BKE_tracking_object_add(tracking, "Camera");
}
-/* Get list base of active object's tracks. */
ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking)
{
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
@@ -373,7 +363,6 @@ ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking)
return &tracking->tracks;
}
-/* Get list base of active object's plane tracks. */
ListBase *BKE_tracking_get_active_plane_tracks(MovieTracking *tracking)
{
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
@@ -385,7 +374,6 @@ ListBase *BKE_tracking_get_active_plane_tracks(MovieTracking *tracking)
return &tracking->plane_tracks;
}
-/* Get reconstruction data of active object. */
MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTracking *tracking)
{
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
@@ -393,9 +381,6 @@ MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTrackin
return BKE_tracking_object_get_reconstruction(tracking, object);
}
-/* Get transformation matrix for a given object which is used
- * for parenting motion tracker reconstruction to 3D world.
- */
void BKE_tracking_get_camera_object_matrix(Object *camera_object, float mat[4][4])
{
BLI_assert(camera_object != NULL);
@@ -412,11 +397,6 @@ void BKE_tracking_get_camera_object_matrix(Object *camera_object, float mat[4][4
BKE_object_where_is_calc_mat4(camera_object, mat);
}
-/* Get projection matrix for camera specified by given tracking object
- * and frame number.
- *
- * NOTE: frame number should be in clip space, not scene space
- */
void BKE_tracking_get_projection_matrix(MovieTracking *tracking,
MovieTrackingObject *object,
int framenr,
@@ -472,7 +452,6 @@ void BKE_tracking_get_projection_matrix(MovieTracking *tracking,
/*********************** clipboard *************************/
-/* Free clipboard by freeing memory used by all tracks in it. */
void BKE_tracking_clipboard_free(void)
{
MovieTrackingTrack *track = tracking_clipboard.tracks.first, *next_track;
@@ -489,7 +468,6 @@ void BKE_tracking_clipboard_free(void)
BLI_listbase_clear(&tracking_clipboard.tracks);
}
-/* Copy selected tracks from specified object to the clipboard. */
void BKE_tracking_clipboard_copy_tracks(MovieTracking *tracking, MovieTrackingObject *object)
{
ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
@@ -510,17 +488,11 @@ void BKE_tracking_clipboard_copy_tracks(MovieTracking *tracking, MovieTrackingOb
}
}
-/* Check whether there are any tracks in the clipboard. */
bool BKE_tracking_clipboard_has_tracks(void)
{
return (BLI_listbase_is_empty(&tracking_clipboard.tracks) == false);
}
-/* Paste tracks from clipboard to specified object.
- *
- * Names of new tracks in object are guaranteed to
- * be unique here.
- */
void BKE_tracking_clipboard_paste_tracks(MovieTracking *tracking, MovieTrackingObject *object)
{
ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
@@ -541,10 +513,6 @@ void BKE_tracking_clipboard_paste_tracks(MovieTracking *tracking, MovieTrackingO
/*********************** Tracks *************************/
-/* Add new empty track to the given list of tracks.
- *
- * It is required that caller will append at least one marker to avoid degenerate tracks.
- */
MovieTrackingTrack *BKE_tracking_track_add_empty(MovieTracking *tracking, ListBase *tracks_list)
{
const MovieTrackingSettings *settings = &tracking->settings;
@@ -569,14 +537,6 @@ MovieTrackingTrack *BKE_tracking_track_add_empty(MovieTracking *tracking, ListBa
return track;
}
-/* Add new track to a specified tracks base.
- *
- * Coordinates are expected to be in normalized 0..1 space,
- * frame number is expected to be in clip space.
- *
- * Width and height are clip's dimension used to scale track's
- * pattern and search regions.
- */
MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking,
ListBase *tracksbase,
float x,
@@ -618,7 +578,6 @@ MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking,
return track;
}
-/* Duplicate the specified track, result will no belong to any list. */
MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track)
{
MovieTrackingTrack *new_track;
@@ -639,10 +598,6 @@ MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track)
return new_track;
}
-/* Ensure specified track has got unique name,
- * if it's not name of specified track will be changed
- * keeping names of all other tracks unchanged.
- */
void BKE_tracking_track_unique_name(ListBase *tracksbase, MovieTrackingTrack *track)
{
BLI_uniquename(tracksbase,
@@ -653,11 +608,6 @@ void BKE_tracking_track_unique_name(ListBase *tracksbase, MovieTrackingTrack *tr
sizeof(track->name));
}
-/* Free specified track, only frees contents of a structure
- * (if track is allocated in heap, it shall be handled outside).
- *
- * All the pointers inside track becomes invalid after this call.
- */
void BKE_tracking_track_free(MovieTrackingTrack *track)
{
if (track->markers) {
@@ -665,8 +615,6 @@ void BKE_tracking_track_free(MovieTrackingTrack *track)
}
}
-/* Get frame numbers of the very first and last markers.
- * There is no check on whether the marker is enabled or not. */
void BKE_tracking_track_first_last_frame_get(const MovieTrackingTrack *track,
int *r_first_frame,
int *r_last_frame)
@@ -677,9 +625,6 @@ void BKE_tracking_track_first_last_frame_get(const MovieTrackingTrack *track,
*r_last_frame = track->markers[last_marker_index].framenr;
}
-/* Find the minimum starting frame and maximum ending frame within given set of
- * tracks.
- */
void BKE_tracking_tracks_first_last_frame_minmax(/*const*/ MovieTrackingTrack **tracks,
const int num_tracks,
int *r_first_frame,
@@ -745,11 +690,6 @@ MovieTrackingTrack **BKE_tracking_selected_tracks_in_active_object(MovieTracking
return source_tracks;
}
-/* Set flag for all specified track's areas.
- *
- * area - which part of marker should be selected. see TRACK_AREA_* constants.
- * flag - flag to be set for areas.
- */
void BKE_tracking_track_flag_set(MovieTrackingTrack *track, int area, int flag)
{
if (area == TRACK_AREA_NONE) {
@@ -767,11 +707,6 @@ void BKE_tracking_track_flag_set(MovieTrackingTrack *track, int area, int flag)
}
}
-/* Clear flag from all specified track's areas.
- *
- * area - which part of marker should be selected. see TRACK_AREA_* constants.
- * flag - flag to be cleared for areas.
- */
void BKE_tracking_track_flag_clear(MovieTrackingTrack *track, int area, int flag)
{
if (area == TRACK_AREA_NONE) {
@@ -789,19 +724,11 @@ void BKE_tracking_track_flag_clear(MovieTrackingTrack *track, int area, int flag
}
}
-/* Check whether track has got marker at specified frame.
- *
- * NOTE: frame number should be in clip space, not scene space.
- */
bool BKE_tracking_track_has_marker_at_frame(MovieTrackingTrack *track, int framenr)
{
return BKE_tracking_marker_get_exact(track, framenr) != NULL;
}
-/* Check whether track has got enabled marker at specified frame.
- *
- * NOTE: frame number should be in clip space, not scene space.
- */
bool BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, int framenr)
{
MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
@@ -809,18 +736,6 @@ bool BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, i
return marker && (marker->flag & MARKER_DISABLED) == 0;
}
-/* Clear track's path:
- *
- * - If action is TRACK_CLEAR_REMAINED path from ref_frame+1 up to
- * end will be clear.
- *
- * - If action is TRACK_CLEAR_UPTO path from the beginning up to
- * ref_frame-1 will be clear.
- *
- * - If action is TRACK_CLEAR_ALL only marker at frame ref_frame will remain.
- *
- * NOTE: frame number should be in clip space, not scene space
- */
void BKE_tracking_track_path_clear(MovieTrackingTrack *track, int ref_frame, int action)
{
int a;
@@ -1281,7 +1196,6 @@ static void track_mask_gpencil_layer_rasterize(int frame_width,
}
}
-/* Region is in pixel space, relative to marker's center. */
float *tracking_track_get_mask_for_region(int frame_width,
int frame_height,
const float region_min[2],
@@ -1336,7 +1250,6 @@ float BKE_tracking_track_get_weight_for_marker(MovieClip *clip,
return weight;
}
-/* area - which part of marker should be selected. see TRACK_AREA_* constants */
void BKE_tracking_track_select(ListBase *tracksbase,
MovieTrackingTrack *track,
int area,
@@ -1510,16 +1423,6 @@ void BKE_tracking_marker_clamp(MovieTrackingMarker *marker, int event)
}
}
-/**
- * Get marker closest to the given frame number.
- *
- * If there is maker with exact frame number it returned.
- * Otherwise, marker with highest frame number but lower than the requested
- * frame is returned if such marker exists. Otherwise, the marker with lowest
- * frame number greater than the requested frame number is returned.
- *
- * This function has complexity of `O(log number_of_markers)`.
- */
MovieTrackingMarker *BKE_tracking_marker_get(MovieTrackingTrack *track, int framenr)
{
const int num_markers = track->markersnr;
@@ -1705,7 +1608,6 @@ void BKE_tracking_marker_get_subframe_position(MovieTrackingTrack *track,
/*********************** Plane Track *************************/
-/* Creates new plane track out of selected point tracks */
MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(MovieTracking *tracking,
ListBase *plane_tracks_base,
ListBase *tracks,
@@ -1789,11 +1691,6 @@ void BKE_tracking_plane_track_unique_name(ListBase *plane_tracks_base,
sizeof(plane_track->name));
}
-/* Free specified plane track, only frees contents of a structure
- * (if track is allocated in heap, it shall be handled outside).
- *
- * All the pointers inside track becomes invalid after this call.
- */
void BKE_tracking_plane_track_free(MovieTrackingPlaneTrack *plane_track)
{
if (plane_track->markers) {
@@ -1988,9 +1885,6 @@ void BKE_tracking_plane_marker_delete(MovieTrackingPlaneTrack *plane_track, int
* would be nice to de-duplicate them somehow..
*/
-/* Get a plane marker at given frame,
- * If there's no such marker, closest one from the left side will be returned.
- */
MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(MovieTrackingPlaneTrack *plane_track,
int framenr)
{
@@ -2039,9 +1933,6 @@ MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(MovieTrackingPlaneTrack
return NULL;
}
-/* Get a plane marker at exact given frame, if there's no marker at the frame,
- * NULL will be returned.
- */
MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(MovieTrackingPlaneTrack *plane_track,
int framenr)
{
@@ -2054,7 +1945,6 @@ MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(MovieTrackingPlane
return plane_marker;
}
-/* Ensure there's a marker for the given frame. */
MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(MovieTrackingPlaneTrack *plane_track,
int framenr)
{
@@ -2326,7 +2216,6 @@ static void reconstructed_camera_scale_set(MovieTrackingObject *object, float ma
}
}
-/* converts principal offset from center to offset of blender's camera */
void BKE_tracking_camera_shift_get(
MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty)
{
@@ -2899,10 +2788,6 @@ ImBuf *BKE_tracking_get_search_imbuf(ImBuf *ibuf,
return searchibuf;
}
-/* zap channels from the imbuf that are disabled by the user. this can lead to
- * better tracks sometimes. however, instead of simply zeroing the channels
- * out, do a partial grayscale conversion so the display is better.
- */
void BKE_tracking_disable_channels(
ImBuf *ibuf, bool disable_red, bool disable_green, bool disable_blue, bool grayscale)
{
@@ -3014,6 +2899,61 @@ static int channels_average_error_sort(const void *a, const void *b)
return 0;
}
+static int compare_firstlast_putting_undefined_first(
+ bool inverse, bool a_markerless, int a_value, bool b_markerless, int b_value)
+{
+ if (a_markerless && b_markerless) {
+ /* Neither channel has not-disabled markers, return whatever. */
+ return 0;
+ }
+ if (a_markerless) {
+ /* Put the markerless channel first. */
+ return 0;
+ }
+ if (b_markerless) {
+ /* Put the markerless channel first. */
+ return 1;
+ }
+
+ /* Both channels have markers. */
+
+ if (inverse) {
+ if (a_value < b_value) {
+ return 1;
+ }
+ return 0;
+ }
+
+ if (a_value > b_value) {
+ return 1;
+ }
+ return 0;
+}
+
+static int channels_start_sort(const void *a, const void *b)
+{
+ const MovieTrackingDopesheetChannel *channel_a = a;
+ const MovieTrackingDopesheetChannel *channel_b = b;
+
+ return compare_firstlast_putting_undefined_first(false,
+ channel_a->tot_segment == 0,
+ channel_a->first_not_disabled_marker_framenr,
+ channel_b->tot_segment == 0,
+ channel_b->first_not_disabled_marker_framenr);
+}
+
+static int channels_end_sort(const void *a, const void *b)
+{
+ const MovieTrackingDopesheetChannel *channel_a = a;
+ const MovieTrackingDopesheetChannel *channel_b = b;
+
+ return compare_firstlast_putting_undefined_first(false,
+ channel_a->tot_segment == 0,
+ channel_a->last_not_disabled_marker_framenr,
+ channel_b->tot_segment == 0,
+ channel_b->last_not_disabled_marker_framenr);
+}
+
static int channels_alpha_inverse_sort(const void *a, const void *b)
{
if (channels_alpha_sort(a, b)) {
@@ -3053,22 +2993,51 @@ static int channels_average_error_inverse_sort(const void *a, const void *b)
return 0;
}
+static int channels_start_inverse_sort(const void *a, const void *b)
+{
+ const MovieTrackingDopesheetChannel *channel_a = a;
+ const MovieTrackingDopesheetChannel *channel_b = b;
+
+ return compare_firstlast_putting_undefined_first(true,
+ channel_a->tot_segment == 0,
+ channel_a->first_not_disabled_marker_framenr,
+ channel_b->tot_segment == 0,
+ channel_b->first_not_disabled_marker_framenr);
+}
+
+static int channels_end_inverse_sort(const void *a, const void *b)
+{
+ const MovieTrackingDopesheetChannel *channel_a = a;
+ const MovieTrackingDopesheetChannel *channel_b = b;
+
+ return compare_firstlast_putting_undefined_first(true,
+ channel_a->tot_segment == 0,
+ channel_a->last_not_disabled_marker_framenr,
+ channel_b->tot_segment == 0,
+ channel_b->last_not_disabled_marker_framenr);
+}
+
/* Calculate frames segments at which track is tracked continuously. */
static void tracking_dopesheet_channels_segments_calc(MovieTrackingDopesheetChannel *channel)
{
MovieTrackingTrack *track = channel->track;
int i, segment;
+ bool first_not_disabled_marker_framenr_set;
channel->tot_segment = 0;
channel->max_segment = 0;
channel->total_frames = 0;
+ channel->first_not_disabled_marker_framenr = 0;
+ channel->last_not_disabled_marker_framenr = 0;
+
/* TODO(sergey): looks a bit code-duplicated, need to look into
* logic de-duplication here.
*/
/* count */
i = 0;
+ first_not_disabled_marker_framenr_set = false;
while (i < track->markersnr) {
MovieTrackingMarker *marker = &track->markers[i];
@@ -3086,6 +3055,12 @@ static void tracking_dopesheet_channels_segments_calc(MovieTrackingDopesheetChan
break;
}
+ if (!first_not_disabled_marker_framenr_set) {
+ channel->first_not_disabled_marker_framenr = marker->framenr;
+ first_not_disabled_marker_framenr_set = true;
+ }
+ channel->last_not_disabled_marker_framenr = marker->framenr;
+
prev_fra = marker->framenr;
len++;
i++;
@@ -3203,6 +3178,12 @@ static void tracking_dopesheet_channels_sort(MovieTracking *tracking,
else if (sort_method == TRACKING_DOPE_SORT_AVERAGE_ERROR) {
BLI_listbase_sort(&dopesheet->channels, channels_average_error_inverse_sort);
}
+ else if (sort_method == TRACKING_DOPE_SORT_START) {
+ BLI_listbase_sort(&dopesheet->channels, channels_start_inverse_sort);
+ }
+ else if (sort_method == TRACKING_DOPE_SORT_END) {
+ BLI_listbase_sort(&dopesheet->channels, channels_end_inverse_sort);
+ }
}
else {
if (sort_method == TRACKING_DOPE_SORT_NAME) {
@@ -3217,6 +3198,12 @@ static void tracking_dopesheet_channels_sort(MovieTracking *tracking,
else if (sort_method == TRACKING_DOPE_SORT_AVERAGE_ERROR) {
BLI_listbase_sort(&dopesheet->channels, channels_average_error_sort);
}
+ else if (sort_method == TRACKING_DOPE_SORT_START) {
+ BLI_listbase_sort(&dopesheet->channels, channels_start_sort);
+ }
+ else if (sort_method == TRACKING_DOPE_SORT_END) {
+ BLI_listbase_sort(&dopesheet->channels, channels_end_sort);
+ }
}
}
@@ -3315,9 +3302,6 @@ static void tracking_dopesheet_calc_coverage(MovieTracking *tracking)
MEM_freeN(per_frame_counter);
}
-/* Tag dopesheet for update, actual update will happen later
- * when it'll be actually needed.
- */
void BKE_tracking_dopesheet_tag_update(MovieTracking *tracking)
{
MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
@@ -3325,7 +3309,6 @@ void BKE_tracking_dopesheet_tag_update(MovieTracking *tracking)
dopesheet->ok = false;
}
-/* Do dopesheet update, if update is not needed nothing will happen. */
void BKE_tracking_dopesheet_update(MovieTracking *tracking)
{
MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
@@ -3349,7 +3332,6 @@ void BKE_tracking_dopesheet_update(MovieTracking *tracking)
dopesheet->ok = true;
}
-/* NOTE: Returns NULL if the track comes from camera object, */
MovieTrackingObject *BKE_tracking_find_object_for_track(const MovieTracking *tracking,
const MovieTrackingTrack *track)
{
@@ -3377,7 +3359,6 @@ ListBase *BKE_tracking_find_tracks_list_for_track(MovieTracking *tracking,
return &tracking->tracks;
}
-/* NOTE: Returns NULL if the track comes from camera object, */
MovieTrackingObject *BKE_tracking_find_object_for_plane_track(
const MovieTracking *tracking, const MovieTrackingPlaneTrack *plane_track)
{
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index 92ff0911cf3..c83e595c611 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -475,7 +475,7 @@ static void autotrack_context_init_autotrack(AutoTrackContext *context)
/* Allocate memory for all the markers. */
libmv_Marker *libmv_markers = MEM_malloc_arrayN(
- sizeof(libmv_Marker), num_trackable_markers, "libmv markers array");
+ num_trackable_markers, sizeof(libmv_Marker), "libmv markers array");
/* Fill in markers array. */
int num_filled_libmv_markers = 0;
@@ -516,7 +516,7 @@ static void autotrack_context_init_markers(AutoTrackContext *context)
/* Allocate required memory. */
context->autotrack_markers = MEM_calloc_arrayN(
- sizeof(AutoTrackMarker), context->num_autotrack_markers, "auto track options");
+ context->num_autotrack_markers, sizeof(AutoTrackMarker), "auto track options");
/* Fill in all the markers. */
int autotrack_marker_index = 0;
@@ -775,7 +775,7 @@ void BKE_autotrack_context_sync(AutoTrackContext *context)
}
/* TODO(sergey): Find a way to avoid this, somehow making all needed logic in
- * BKE_autotrack_context_sync(). */
+ * #BKE_autotrack_context_sync(). */
void BKE_autotrack_context_sync_user(AutoTrackContext *context, MovieClipUser *user)
{
user->framenr = context->synchronized_scene_frame;
diff --git a/source/blender/blenkernel/intern/tracking_detect.c b/source/blender/blenkernel/intern/tracking_detect.c
index 08719161e1a..be680ef8a8b 100644
--- a/source/blender/blenkernel/intern/tracking_detect.c
+++ b/source/blender/blenkernel/intern/tracking_detect.c
@@ -148,7 +148,6 @@ static void run_configured_detector(MovieTracking *tracking,
}
}
-/* Detect features using FAST detector */
void BKE_tracking_detect_fast(MovieTracking *tracking,
ListBase *tracksbase,
ImBuf *ibuf,
@@ -170,7 +169,6 @@ void BKE_tracking_detect_fast(MovieTracking *tracking,
tracking, tracksbase, ibuf, framenr, layer, place_outside_layer, &options);
}
-/* Detect features using Harris detector */
void BKE_tracking_detect_harris(MovieTracking *tracking,
ListBase *tracksbase,
ImBuf *ibuf,
diff --git a/source/blender/blenkernel/intern/tracking_plane_tracker.c b/source/blender/blenkernel/intern/tracking_plane_tracker.c
index b787cd366c5..d4a5bb2aa9d 100644
--- a/source/blender/blenkernel/intern/tracking_plane_tracker.c
+++ b/source/blender/blenkernel/intern/tracking_plane_tracker.c
@@ -167,7 +167,6 @@ static void track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_trac
}
}
-/* NOTE: frame number should be in clip space, not scene space */
void BKE_tracking_track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track,
int start_frame)
{
diff --git a/source/blender/blenkernel/intern/tracking_region_tracker.c b/source/blender/blenkernel/intern/tracking_region_tracker.c
index 179def0a6f2..4b23f74bc8f 100644
--- a/source/blender/blenkernel/intern/tracking_region_tracker.c
+++ b/source/blender/blenkernel/intern/tracking_region_tracker.c
@@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_defaults.h"
#include "DNA_movieclip_types.h"
#include "BLI_threads.h"
@@ -42,7 +43,7 @@
/* **** utility functions for tracking **** */
-/* convert from float and byte RGBA to grayscale. Supports different coefficients for RGB. */
+/** Convert from float and byte RGBA to gray-scale. Supports different coefficients for RGB. */
static void float_rgba_to_gray(const float *rgba,
float *gray,
int num_pixels,
@@ -71,7 +72,7 @@ static void uint8_rgba_to_float_gray(const unsigned char *rgba,
}
}
-/* Get grayscale float search buffer for given marker and frame. */
+/** Get gray-scale float search buffer for given marker and frame. */
static float *track_get_search_floatbuf(ImBuf *ibuf,
MovieTrackingTrack *track,
MovieTrackingMarker *marker,
@@ -180,7 +181,6 @@ static ImBuf *tracking_context_get_reference_ibuf(MovieClip *clip,
return ibuf;
}
-/* Fill in libmv tracker options structure with settings need to be used to perform track. */
void tracking_configure_tracker(const MovieTrackingTrack *track,
float *mask,
const bool is_backwards,
@@ -311,11 +311,6 @@ static bool refine_marker_reference_frame_get(MovieTrackingTrack *track,
return (reference->flag & MARKER_DISABLED) == 0;
}
-/* Refine marker's position using previously known keyframe.
- * Direction of searching for a keyframe depends on backwards flag,
- * which means if backwards is false, previous keyframe will be as
- * reference.
- */
void BKE_tracking_refine_marker(MovieClip *clip,
MovieTrackingTrack *track,
MovieTrackingMarker *marker,
@@ -328,7 +323,7 @@ void BKE_tracking_refine_marker(MovieClip *clip,
int search_area_height, search_area_width;
int clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
int reference_framenr;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
double dst_pixel_x[5], dst_pixel_y[5];
bool tracked;
diff --git a/source/blender/blenkernel/intern/tracking_solver.c b/source/blender/blenkernel/intern/tracking_solver.c
index d89d36f85ea..47a955c9d93 100644
--- a/source/blender/blenkernel/intern/tracking_solver.c
+++ b/source/blender/blenkernel/intern/tracking_solver.c
@@ -325,7 +325,6 @@ static int reconstruct_count_tracks_on_both_keyframes(MovieTracking *tracking,
return tot;
}
-/* Perform early check on whether everything is fine to start reconstruction. */
bool BKE_tracking_reconstruction_check(MovieTracking *tracking,
MovieTrackingObject *object,
char *error_msg,
@@ -354,11 +353,6 @@ bool BKE_tracking_reconstruction_check(MovieTracking *tracking,
return true;
}
-/* Create context for camera/object motion reconstruction.
- * Copies all data needed for reconstruction from movie
- * clip datablock, so editing this clip is safe during
- * reconstruction job is in progress.
- */
MovieReconstructContext *BKE_tracking_reconstruction_context_new(MovieClip *clip,
MovieTrackingObject *object,
int keyframe1,
@@ -446,7 +440,6 @@ const char *BKE_tracking_reconstruction_error_message_get(const MovieReconstruct
return context->error_message;
}
-/* Free memory used by a reconstruction process. */
void BKE_tracking_reconstruction_context_free(MovieReconstructContext *context)
{
if (context->reconstruction) {
@@ -486,15 +479,6 @@ static void reconstructionOptionsFromContext(libmv_ReconstructionOptions *recons
reconstruction_options->refine_intrinsics = context->refine_flags;
}
-/* Solve camera/object motion and reconstruct 3D markers position
- * from a prepared reconstruction context.
- *
- * stop is not actually used at this moment, so reconstruction
- * job could not be stopped.
- *
- * do_update, progress and stat_message are set by reconstruction
- * callback in libmv side and passing to an interface.
- */
void BKE_tracking_reconstruction_solve(MovieReconstructContext *context,
short *stop,
short *do_update,
@@ -542,9 +526,6 @@ void BKE_tracking_reconstruction_solve(MovieReconstructContext *context,
context->reprojection_error = error;
}
-/* Finish reconstruction process by copying reconstructed data
- * to an actual movie clip datablock.
- */
bool BKE_tracking_reconstruction_finish(MovieReconstructContext *context, MovieTracking *tracking)
{
MovieTrackingReconstruction *reconstruction;
@@ -608,9 +589,6 @@ static void tracking_scale_reconstruction(ListBase *tracksbase,
}
}
-/* Apply scale on all reconstructed cameras and bundles,
- * used by camera scale apply operator.
- */
void BKE_tracking_reconstruction_scale(MovieTracking *tracking, float scale[3])
{
LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) {
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index d5585116f7e..fe9a2f2268a 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -1252,24 +1252,6 @@ static StabContext *init_stabilizer(MovieClip *clip, int size, float aspect)
/* === public interface functions === */
-/* Get stabilization data (translation, scaling and angle) for a given frame.
- * Returned data describes how to compensate the detected movement, but with any
- * chosen scale factor already applied and any target frame position already
- * compensated. In case stabilization fails or is disabled, neutral values are
- * returned.
- *
- * framenr is a frame number, relative to the clip (not relative to the scene
- * timeline)
- * width is an effective width of the canvas (square pixels), used to scale the
- * determined translation
- *
- * Outputs:
- * - translation of the lateral shift, absolute canvas coordinates
- * (square pixels).
- * - scale of the scaling to apply
- * - angle of the rotation angle, relative to the frame center
- */
-/* TODO(sergey): Use r_ prefix for output parameters here. */
void BKE_tracking_stabilization_data_get(MovieClip *clip,
int framenr,
int width,
@@ -1307,7 +1289,7 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip,
discard_stabilization_working_context(ctx);
}
-typedef void (*interpolation_func)(struct ImBuf *, struct ImBuf *, float, float, int, int);
+typedef void (*interpolation_func)(const struct ImBuf *, struct ImBuf *, float, float, int, int);
typedef struct TrackingStabilizeFrameInterpolationData {
ImBuf *ibuf;
@@ -1336,12 +1318,6 @@ static void tracking_stabilize_frame_interpolation_cb(
}
}
-/* Stabilize given image buffer using stabilization data for a specified
- * frame number.
- *
- * NOTE: frame number should be in clip space, not scene space.
- */
-/* TODO(sergey): Use r_ prefix for output parameters here. */
ImBuf *BKE_tracking_stabilize_frame(
MovieClip *clip, int framenr, ImBuf *ibuf, float translation[2], float *scale, float *angle)
{
@@ -1449,16 +1425,6 @@ ImBuf *BKE_tracking_stabilize_frame(
return tmpibuf;
}
-/* Build a 4x4 transformation matrix based on the given 2D stabilization data.
- * mat is a 4x4 matrix in homogeneous coordinates, adapted to the
- * final image buffer size and compensated for pixel aspect ratio,
- * ready for direct OpenGL drawing.
- *
- * TODO(sergey): The signature of this function should be changed. we actually
- * don't need the dimensions of the image buffer. Instead we
- * should consider to provide the pivot point of the rotation as a
- * further stabilization data parameter.
- */
void BKE_tracking_stabilization_data_to_mat4(int buffer_width,
int buffer_height,
float pixel_aspect,
diff --git a/source/blender/blenkernel/intern/tracking_test.cc b/source/blender/blenkernel/intern/tracking_test.cc
index a3845dcad8f..d85d71b7c86 100644
--- a/source/blender/blenkernel/intern/tracking_test.cc
+++ b/source/blender/blenkernel/intern/tracking_test.cc
@@ -5,7 +5,7 @@
#include "DNA_tracking_types.h"
#include "BKE_tracking.h"
-#include "BLI_float2.hh"
+#include "BLI_math_vec_types.hh"
namespace blender {
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index 16b36e94328..f1fd3a13e0e 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -338,11 +338,6 @@ static void search_pixel_to_marker_unified(int frame_width,
sub_v2_v2v2(marker_unified, frame_unified, marker->pos);
}
-/* Each marker has 5 coordinates associated with it that get warped with
- * tracking: the four corners ("pattern_corners"), and the center ("pos").
- * This function puts those 5 points into the appropriate frame for tracking
- * (the "search" coordinate frame).
- */
void tracking_get_marker_coords_for_tracking(int frame_width,
int frame_height,
const MovieTrackingMarker *marker,
@@ -369,7 +364,6 @@ void tracking_get_marker_coords_for_tracking(int frame_width,
search_pixel_y[4] = pixel_coords[1] - 0.5f;
}
-/* Inverse of above. */
void tracking_set_marker_coords_from_tracking(int frame_width,
int frame_height,
MovieTrackingMarker *marker,
@@ -411,15 +405,6 @@ void tracking_set_marker_coords_from_tracking(int frame_width,
/** \name General Purpose Utility Functions
* \{ */
-/* Place a disabled marker before or after specified ref_marker.
- *
- * If before is truth, disabled marker is placed before reference
- * one, and it's placed after it otherwise.
- *
- * If there's already a marker at the frame where disabled one
- * is expected to be placed, nothing will happen if overwrite
- * is false.
- */
void tracking_marker_insert_disabled(MovieTrackingTrack *track,
const MovieTrackingMarker *ref_marker,
bool before,
@@ -526,7 +511,6 @@ static void distortion_model_parameters_from_options(
BLI_assert_msg(0, "Unknown distortion model");
}
-/* Fill in Libmv C-API camera intrinsics options from tracking structure. */
void tracking_cameraIntrinscisOptionsFromTracking(
MovieTracking *tracking,
int calibration_width,
@@ -563,7 +547,6 @@ void tracking_trackingCameraFromIntrinscisOptions(
distortion_model_parameters_from_options(camera_intrinsics_options, camera);
}
-/* Get previous keyframed marker. */
MovieTrackingMarker *tracking_get_keyframed_marker(MovieTrackingTrack *track,
int current_frame,
bool backwards)
diff --git a/source/blender/nodes/intern/type_conversions.cc b/source/blender/blenkernel/intern/type_conversions.cc
index 1a71a3418a5..cb05337ef2a 100644
--- a/source/blender/nodes/intern/type_conversions.cc
+++ b/source/blender/blenkernel/intern/type_conversions.cc
@@ -14,29 +14,25 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "NOD_type_conversions.hh"
+#include "BKE_type_conversions.hh"
#include "FN_multi_function_builder.hh"
#include "BLI_color.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
-namespace blender::nodes {
+namespace blender::bke {
-using fn::GVArrayPtr;
-using fn::GVMutableArray;
-using fn::GVMutableArrayPtr;
using fn::MFDataType;
template<typename From, typename To, To (*ConversionF)(const From &)>
static void add_implicit_conversion(DataTypeConversions &conversions)
{
- const CPPType &from_type = CPPType::get<From>();
- const CPPType &to_type = CPPType::get<To>();
- const std::string conversion_name = from_type.name() + " to " + to_type.name();
+ static const CPPType &from_type = CPPType::get<From>();
+ static const CPPType &to_type = CPPType::get<To>();
+ static const std::string conversion_name = from_type.name() + " to " + to_type.name();
- static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name, ConversionF};
+ static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name.c_str(), ConversionF};
static auto convert_single_to_initialized = [](const void *src, void *dst) {
*(To *)dst = ConversionF(*(const From *)src);
};
@@ -242,108 +238,126 @@ void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type,
functions->convert_single_to_uninitialized(from_value, to_value);
}
-class GVArray_For_ConvertedGVArray : public GVArray {
+void DataTypeConversions::convert_to_initialized_n(fn::GSpan from_span,
+ fn::GMutableSpan to_span) const
+{
+ const CPPType &from_type = from_span.type();
+ const CPPType &to_type = to_span.type();
+ BLI_assert(from_span.size() == to_span.size());
+ BLI_assert(this->is_convertible(from_type, to_type));
+ const fn::MultiFunction *fn = this->get_conversion_multi_function(
+ MFDataType::ForSingle(from_type), MFDataType::ForSingle(to_type));
+ fn::MFParamsBuilder params{*fn, from_span.size()};
+ params.add_readonly_single_input(from_span);
+ to_type.destruct_n(to_span.data(), to_span.size());
+ params.add_uninitialized_single_output(to_span);
+ fn::MFContextBuilder context;
+ fn->call_auto(IndexRange(from_span.size()), params, context);
+}
+
+class GVArray_For_ConvertedGVArray : public fn::GVArrayImpl {
private:
- GVArrayPtr varray_;
+ fn::GVArray varray_;
const CPPType &from_type_;
ConversionFunctions old_to_new_conversions_;
public:
- GVArray_For_ConvertedGVArray(GVArrayPtr varray,
+ GVArray_For_ConvertedGVArray(fn::GVArray varray,
const CPPType &to_type,
const DataTypeConversions &conversions)
- : GVArray(to_type, varray->size()), varray_(std::move(varray)), from_type_(varray_->type())
+ : fn::GVArrayImpl(to_type, varray.size()),
+ varray_(std::move(varray)),
+ from_type_(varray_.type())
{
old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type);
}
private:
- void get_impl(const int64_t index, void *r_value) const override
+ void get(const int64_t index, void *r_value) const override
{
BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
- varray_->get(index, buffer);
+ varray_.get(index, buffer);
old_to_new_conversions_.convert_single_to_initialized(buffer, r_value);
from_type_.destruct(buffer);
}
- void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
+ void get_to_uninitialized(const int64_t index, void *r_value) const override
{
BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
- varray_->get(index, buffer);
+ varray_.get(index, buffer);
old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value);
from_type_.destruct(buffer);
}
};
-class GVMutableArray_For_ConvertedGVMutableArray : public GVMutableArray {
+class GVMutableArray_For_ConvertedGVMutableArray : public fn::GVMutableArrayImpl {
private:
- GVMutableArrayPtr varray_;
+ fn::GVMutableArray varray_;
const CPPType &from_type_;
ConversionFunctions old_to_new_conversions_;
ConversionFunctions new_to_old_conversions_;
public:
- GVMutableArray_For_ConvertedGVMutableArray(GVMutableArrayPtr varray,
+ GVMutableArray_For_ConvertedGVMutableArray(fn::GVMutableArray varray,
const CPPType &to_type,
const DataTypeConversions &conversions)
- : GVMutableArray(to_type, varray->size()),
+ : fn::GVMutableArrayImpl(to_type, varray.size()),
varray_(std::move(varray)),
- from_type_(varray_->type())
+ from_type_(varray_.type())
{
old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type);
new_to_old_conversions_ = *conversions.get_conversion_functions(to_type, from_type_);
}
private:
- void get_impl(const int64_t index, void *r_value) const override
+ void get(const int64_t index, void *r_value) const override
{
BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
- varray_->get(index, buffer);
+ varray_.get(index, buffer);
old_to_new_conversions_.convert_single_to_initialized(buffer, r_value);
from_type_.destruct(buffer);
}
- void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
+ void get_to_uninitialized(const int64_t index, void *r_value) const override
{
BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
- varray_->get(index, buffer);
+ varray_.get(index, buffer);
old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value);
from_type_.destruct(buffer);
}
- void set_by_move_impl(const int64_t index, void *value) override
+ void set_by_move(const int64_t index, void *value) override
{
BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
new_to_old_conversions_.convert_single_to_uninitialized(value, buffer);
- varray_->set_by_relocate(index, buffer);
+ varray_.set_by_relocate(index, buffer);
}
};
-fn::GVArrayPtr DataTypeConversions::try_convert(fn::GVArrayPtr varray,
- const CPPType &to_type) const
+fn::GVArray DataTypeConversions::try_convert(fn::GVArray varray, const CPPType &to_type) const
{
- const CPPType &from_type = varray->type();
+ const CPPType &from_type = varray.type();
if (from_type == to_type) {
return varray;
}
if (!this->is_convertible(from_type, to_type)) {
return {};
}
- return std::make_unique<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this);
+ return fn::GVArray::For<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this);
}
-fn::GVMutableArrayPtr DataTypeConversions::try_convert(fn::GVMutableArrayPtr varray,
- const CPPType &to_type) const
+fn::GVMutableArray DataTypeConversions::try_convert(fn::GVMutableArray varray,
+ const CPPType &to_type) const
{
- const CPPType &from_type = varray->type();
+ const CPPType &from_type = varray.type();
if (from_type == to_type) {
return varray;
}
if (!this->is_convertible(from_type, to_type)) {
return {};
}
- return std::make_unique<GVMutableArray_For_ConvertedGVMutableArray>(
+ return fn::GVMutableArray::For<GVMutableArray_For_ConvertedGVMutableArray>(
std::move(varray), to_type, *this);
}
-} // namespace blender::nodes
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index db5184edfd2..3e263fafe28 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -61,13 +61,39 @@
static CLG_LogRef LOG = {"bke.undosys"};
/* -------------------------------------------------------------------- */
+/** \name Undo Types
+ * \{ */
+
+const UndoType *BKE_UNDOSYS_TYPE_IMAGE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_MEMFILE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_PARTICLE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_SCULPT = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_TEXT = NULL;
+
+static ListBase g_undo_types = {NULL, NULL};
+
+static const UndoType *BKE_undosys_type_from_context(bContext *C)
+{
+ LISTBASE_FOREACH (const UndoType *, ut, &g_undo_types) {
+ /* No poll means we don't check context. */
+ if (ut->poll && ut->poll(C)) {
+ return ut;
+ }
+ }
+ return NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Internal Nested Undo Checks
*
* Make sure we're not running undo operations from 'step_encode', 'step_decode' callbacks.
* bugs caused by this situation aren't _that_ hard to spot but aren't always so obvious.
* Best we have a check which shows the problem immediately.
- *
* \{ */
+
#define WITH_NESTED_UNDO_CHECK
#ifdef WITH_NESTED_UNDO_CHECK
@@ -90,36 +116,9 @@ static bool g_undo_callback_running = false;
# define UNDO_NESTED_CHECK_BEGIN ((void)0)
# define UNDO_NESTED_CHECK_END ((void)0)
#endif
-/** \} */
-/* -------------------------------------------------------------------- */
-/** \name Public Undo Types
- *
- * Unfortunately we need this for a handful of places.
- * \{ */
-const UndoType *BKE_UNDOSYS_TYPE_IMAGE = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_MEMFILE = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_PARTICLE = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_SCULPT = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_TEXT = NULL;
/** \} */
-/* UndoType */
-
-static ListBase g_undo_types = {NULL, NULL};
-
-static const UndoType *BKE_undosys_type_from_context(bContext *C)
-{
- LISTBASE_FOREACH (const UndoType *, ut, &g_undo_types) {
- /* No poll means we don't check context. */
- if (ut->poll && ut->poll(C)) {
- return ut;
- }
- }
- return NULL;
-}
-
/* -------------------------------------------------------------------- */
/** \name Internal Callback Wrappers
*
@@ -346,7 +345,7 @@ static bool undosys_stack_push_main(UndoStack *ustack, const char *name, struct
CLOG_INFO(&LOG, 1, "'%s'", name);
bContext *C_temp = CTX_create();
CTX_data_main_set(C_temp, bmain);
- UndoPushReturn ret = BKE_undosys_step_push_with_type(
+ eUndoPushReturn ret = BKE_undosys_step_push_with_type(
ustack, C_temp, name, BKE_UNDOSYS_TYPE_MEMFILE);
CTX_free(C_temp);
return (ret & UNDO_PUSH_RET_SUCCESS);
@@ -358,7 +357,6 @@ void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain)
undosys_stack_push_main(ustack, IFACE_("Original"), bmain);
}
-/* called after 'BKE_undosys_stack_init_from_main' */
void BKE_undosys_stack_init_from_context(UndoStack *ustack, bContext *C)
{
const UndoType *ut = BKE_undosys_type_from_context(C);
@@ -367,7 +365,6 @@ void BKE_undosys_stack_init_from_context(UndoStack *ustack, bContext *C)
}
}
-/* name optional */
bool BKE_undosys_stack_has_undo(const UndoStack *ustack, const char *name)
{
if (name) {
@@ -397,10 +394,6 @@ UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const Un
return BKE_undosys_stack_active_with_type(ustack, ut);
}
-/**
- * \param steps: Limit the number of undo steps.
- * \param memory_limit: Limit the amount of memory used by the undo stack.
- */
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit)
{
UNDO_NESTED_ASSERT(false);
@@ -455,6 +448,10 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Undo Step
+ * \{ */
+
UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack,
bContext *C,
const char *name,
@@ -497,20 +494,17 @@ UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, bContext *C, const char
return BKE_undosys_step_push_init_with_type(ustack, C, name, ut);
}
-/**
- * \param C: Can be NULL from some callers if their encoding function doesn't need it
- */
-UndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack,
- bContext *C,
- const char *name,
- const UndoType *ut)
+eUndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack,
+ bContext *C,
+ const char *name,
+ const UndoType *ut)
{
BLI_assert((ut->flags & UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE) == 0 || C != NULL);
UNDO_NESTED_ASSERT(false);
undosys_stack_validate(ustack, false);
bool is_not_empty = ustack->step_active != NULL;
- UndoPushReturn retval = UNDO_PUSH_RET_FAILURE;
+ eUndoPushReturn retval = UNDO_PUSH_RET_FAILURE;
/* Might not be final place for this to be called - probably only want to call it from some
* undo handlers, not all of them? */
@@ -602,7 +596,7 @@ UndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack,
return (retval | UNDO_PUSH_RET_SUCCESS);
}
-UndoPushReturn BKE_undosys_step_push(UndoStack *ustack, bContext *C, const char *name)
+eUndoPushReturn BKE_undosys_step_push(UndoStack *ustack, bContext *C, const char *name)
{
UNDO_NESTED_ASSERT(false);
const UndoType *ut = ustack->step_init ? ustack->step_init->type :
@@ -613,9 +607,6 @@ UndoPushReturn BKE_undosys_step_push(UndoStack *ustack, bContext *C, const char
return BKE_undosys_step_push_with_type(ustack, C, name, ut);
}
-/**
- * Useful when we want to diff against previous undo data but can't be sure the types match.
- */
UndoStep *BKE_undosys_step_same_type_next(UndoStep *us)
{
if (us) {
@@ -629,9 +620,6 @@ UndoStep *BKE_undosys_step_same_type_next(UndoStep *us)
return us;
}
-/**
- * Useful when we want to diff against previous undo data but can't be sure the types match.
- */
UndoStep *BKE_undosys_step_same_type_prev(UndoStep *us)
{
if (us) {
@@ -674,14 +662,6 @@ UndoStep *BKE_undosys_step_find_by_type(UndoStack *ustack, const UndoType *ut)
return NULL;
}
-/**
- * Return direction of the undo/redo from `us_reference` (or `ustack->step_active` if NULL), and
- * `us_target`.
- *
- * \note If `us_reference` and `us_target` are the same, we consider this is an undo.
- *
- * \return -1 for undo, 1 for redo, 0 in case of error.
- */
eUndoStepDir BKE_undosys_step_calc_direction(const UndoStack *ustack,
const UndoStep *us_target,
const UndoStep *us_reference)
@@ -741,19 +721,6 @@ static UndoStep *undosys_step_iter_first(UndoStep *us_reference, const eUndoStep
return (undo_dir == -1) ? us_reference->prev : us_reference->next;
}
-/**
- * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
- *
- * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target`
- * will become the active step.
- *
- * \note In case `use_skip` is true, the final target will always be **beyond** the given one
- * (if the given one has to be skipped).
- *
- * \param us_reference: If NULL, will be set to current active step in the undo stack. Otherwise,
- * it is assumed to match the current state, and will be used as basis for the undo/redo process
- * (i.e. all steps in-between `us_reference` and `us_target` will be processed).
- */
bool BKE_undosys_step_load_data_ex(UndoStack *ustack,
bContext *C,
UndoStep *us_target,
@@ -842,37 +809,22 @@ bool BKE_undosys_step_load_data_ex(UndoStack *ustack,
return false;
}
-/**
- * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
- */
bool BKE_undosys_step_load_data(UndoStack *ustack, bContext *C, UndoStep *us_target)
{
/* Note that here we do not skip 'skipped' steps by default. */
return BKE_undosys_step_load_data_ex(ustack, C, us_target, NULL, false);
}
-/**
- * Undo/Redo until the step matching given `index` in the undo stack becomes the active (currently
- * loaded) one.
- */
void BKE_undosys_step_load_from_index(UndoStack *ustack, bContext *C, const int index)
{
UndoStep *us_target = BLI_findlink(&ustack->steps, index);
BLI_assert(us_target->skip == false);
+ if (us_target == ustack->step_active) {
+ return;
+ }
BKE_undosys_step_load_data(ustack, C, us_target);
}
-/**
- * Undo until `us_target` step becomes the active (currently loaded) one.
- *
- * \warning This function assumes that the given target step is _before_ current active one.
- *
- * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target` will become the
- * active step.
- *
- * \note In case `use_skip` is true, the final target will always be **before** the given one (if
- * the given one has to be skipped).
- */
bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack,
bContext *C,
UndoStep *us_target,
@@ -888,19 +840,11 @@ bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack,
return BKE_undosys_step_load_data_ex(ustack, C, us_target, us_reference, use_skip);
}
-/**
- * Undo until `us_target` step becomes the active (currently loaded) one.
- *
- * \note See #BKE_undosys_step_undo_with_data_ex for details.
- */
bool BKE_undosys_step_undo_with_data(UndoStack *ustack, bContext *C, UndoStep *us_target)
{
return BKE_undosys_step_undo_with_data_ex(ustack, C, us_target, true);
}
-/**
- * Undo one step from current active (currently loaded) one.
- */
bool BKE_undosys_step_undo(UndoStack *ustack, bContext *C)
{
if (ustack->step_active != NULL) {
@@ -909,17 +853,6 @@ bool BKE_undosys_step_undo(UndoStack *ustack, bContext *C)
return false;
}
-/**
- * Redo until `us_target` step becomes the active (currently loaded) one.
- *
- * \warning This function assumes that the given target step is _after_ current active one.
- *
- * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target` will become the
- * active step.
- *
- * \note In case `use_skip` is true, the final target will always be **after** the given one (if
- * the given one has to be skipped).
- */
bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack,
bContext *C,
UndoStep *us_target,
@@ -934,19 +867,11 @@ bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack,
return BKE_undosys_step_load_data_ex(ustack, C, us_target, us_reference, use_skip);
}
-/**
- * Redo until `us_target` step becomes the active (currently loaded) one.
- *
- * \note See #BKE_undosys_step_redo_with_data_ex for details.
- */
bool BKE_undosys_step_redo_with_data(UndoStack *ustack, bContext *C, UndoStep *us_target)
{
return BKE_undosys_step_redo_with_data_ex(ustack, C, us_target, true);
}
-/**
- * Redo one step from current active one.
- */
bool BKE_undosys_step_redo(UndoStack *ustack, bContext *C)
{
if (ustack->step_active != NULL) {
@@ -955,9 +880,6 @@ bool BKE_undosys_step_redo(UndoStack *ustack, bContext *C)
return false;
}
-/**
- * Similar to #WM_operatortype_append
- */
UndoType *BKE_undosys_type_append(void (*undosys_fn)(UndoType *))
{
UndoType *ut;
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 4e9a3c9fb2e..fde3ac13ceb 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -1091,22 +1091,6 @@ double BKE_unit_apply_preferred_unit(const struct UnitSettings *settings, int ty
return value * scalar + bias;
}
-/**
- * Make a copy of the string that replaces the units with numbers.
- *
- * This is only used when evaluating user input and can afford to be a bit slower
- *
- * This is to be used before python evaluation so..
- * 10.1km -> 10.1*1000.0
- * ...will be resolved by python.
- *
- * Values will be split by an add sign.
- * 5'2" -> 5*0.3048 + 2*0.0254
- *
- * \param str_prev: is optional, when valid it is used to get a base unit when none is set.
- *
- * \return True of a change was made.
- */
bool BKE_unit_replace_string(
char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
{
@@ -1196,7 +1180,6 @@ bool BKE_unit_replace_string(
return changed;
}
-/* 45µm --> 45um */
void BKE_unit_name_to_alt(char *str, int len_max, const char *orig_str, int system, int type)
{
const bUnitCollection *usys = unit_get_system(system, type);
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/vfont.c
index 0e159418724..4a598288ee6 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/vfont.c
@@ -40,7 +40,6 @@
#include "BLI_string_utf8.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
-#include "BLI_vfontdata.h"
#include "BLT_translation.h"
@@ -50,13 +49,15 @@
#include "DNA_vfont_types.h"
#include "BKE_anim_path.h"
+#include "BKE_bpath.h"
#include "BKE_curve.h"
-#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
+#include "BKE_vfont.h"
+#include "BKE_vfontdata.h"
#include "BLO_read_write.h"
@@ -77,7 +78,7 @@ static void vfont_init_data(ID *id)
if (pf) {
VFontData *vfd;
- vfd = BLI_vfontdata_from_freetypefont(pf);
+ vfd = BKE_vfontdata_from_freetypefont(pf);
if (vfd) {
vfont->data = vfd;
@@ -107,7 +108,7 @@ static void vfont_copy_data(Main *UNUSED(bmain),
}
if (vfont_dst->data) {
- vfont_dst->data = BLI_vfontdata_copy(vfont_dst->data, flag_subdata);
+ vfont_dst->data = BKE_vfontdata_copy(vfont_dst->data, flag_subdata);
}
}
@@ -123,6 +124,21 @@ static void vfont_free_data(ID *id)
}
}
+static void vfont_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ VFont *vfont = (VFont *)id;
+
+ if (vfont->packedfile != NULL && (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
+ return;
+ }
+
+ if (BKE_vfont_is_builtin(vfont)) {
+ return;
+ }
+
+ BKE_bpath_foreach_path_fixed_process(bpath_data, vfont->filepath);
+}
+
static void vfont_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
VFont *vf = (VFont *)id;
@@ -162,6 +178,7 @@ IDTypeInfo IDType_ID_VF = {
.name_plural = "fonts",
.translation_context = BLT_I18NCONTEXT_ID_VFONT,
.flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = vfont_init_data,
.copy_data = vfont_copy_data,
@@ -169,6 +186,7 @@ IDTypeInfo IDType_ID_VF = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = vfont_foreach_path,
.owner_get = NULL,
.blend_write = vfont_blend_write,
@@ -183,7 +201,6 @@ IDTypeInfo IDType_ID_VF = {
/***************************** VFont *******************************/
-/* The vfont code */
void BKE_vfont_free_data(struct VFont *vfont)
{
if (vfont->data) {
@@ -300,7 +317,7 @@ static VFontData *vfont_get_data(VFont *vfont)
}
if (pf) {
- vfont->data = BLI_vfontdata_from_freetypefont(pf);
+ vfont->data = BKE_vfontdata_from_freetypefont(pf);
if (pf != vfont->packedfile) {
BKE_packedfile_free(pf);
}
@@ -335,19 +352,19 @@ VFont *BKE_vfont_load(Main *bmain, const char *filepath)
if (pf) {
VFontData *vfd;
- vfd = BLI_vfontdata_from_freetypefont(pf);
+ vfd = BKE_vfontdata_from_freetypefont(pf);
if (vfd) {
/* If there's a font name, use it for the ID name. */
vfont = BKE_libblock_alloc(bmain, ID_VF, vfd->name[0] ? vfd->name : filename, 0);
vfont->data = vfd;
BLI_strncpy(vfont->filepath, filepath, sizeof(vfont->filepath));
- /* if autopack is on store the packedfile in de font structure */
+ /* if auto-pack is on store the packed-file in de font structure */
if (!is_builtin && (G.fileflags & G_FILE_AUTOPACK)) {
vfont->packedfile = pf;
}
- /* Do not add FO_BUILTIN_NAME to temporary listbase */
+ /* Do not add #FO_BUILTIN_NAME to temporary list-base. */
if (!STREQ(filename, FO_BUILTIN_NAME)) {
vfont->temp_pf = BKE_packedfile_new(NULL, filepath, BKE_main_blendfile_path(bmain));
}
@@ -694,7 +711,7 @@ struct TempLineInfo {
float x_min; /* left margin */
float x_max; /* right margin */
int char_nr; /* number of characters */
- int wspace_nr; /* number of whitespaces of line */
+ int wspace_nr; /* number of white-spaces of line */
};
/* -------------------------------------------------------------------- */
@@ -803,7 +820,7 @@ static bool vfont_to_curve(Object *ob,
float longest_line_length = 0.0f;
/* Text at the beginning of the last used text-box (use for y-axis alignment).
- * We overallocate by one to simplify logic of getting last char. */
+ * We over-allocate by one to simplify logic of getting last char. */
int *i_textbox_array = MEM_callocN(sizeof(*i_textbox_array) * (cu->totbox + 1),
"TextBox initial char index");
@@ -954,7 +971,7 @@ static bool vfont_to_curve(Object *ob,
* happen often once all the chars are load.
*/
if ((che = find_vfont_char(vfd, ascii)) == NULL) {
- che = BLI_vfontchar_from_freetypefont(vfont, ascii);
+ che = BKE_vfontdata_char_from_freetypefont(vfont, ascii);
}
BLI_rw_mutex_unlock(&vfont_rwlock);
}
@@ -1136,7 +1153,7 @@ static bool vfont_to_curve(Object *ob,
}
}
- /* linedata is now: width of line */
+ /* Line-data is now: width of line. */
if (cu->spacemode != CU_ALIGN_X_LEFT) {
ct = chartransdata;
@@ -1500,7 +1517,7 @@ static bool vfont_to_curve(Object *ob,
chartransdata = NULL;
}
else if (mode == FO_EDIT) {
- /* make nurbdata */
+ /* Make NURBS-data. */
BKE_nurbList_free(r_nubase);
ct = chartransdata;
@@ -1743,10 +1760,6 @@ bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *r_nubase)
return BKE_vfont_to_curve_ex(ob, ob->data, mode, r_nubase, NULL, NULL, NULL, NULL);
}
-/**
- * Warning: expects to have access to evaluated data
- * (i.e. passed object should be evaluated one...).
- */
bool BKE_vfont_to_curve(Object *ob, int mode)
{
Curve *cu = ob->data;
diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenkernel/intern/vfontdata_freetype.c
index 34de8fe7f6d..9b79d5635d1 100644
--- a/source/blender/blenlib/intern/freetypefont.c
+++ b/source/blender/blenkernel/intern/vfontdata_freetype.c
@@ -23,7 +23,7 @@
*/
/** \file
- * \ingroup bli
+ * \ingroup bke
*/
#include <ft2build.h>
@@ -42,7 +42,9 @@
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
-#include "BLI_vfontdata.h"
+
+#include "BKE_curve.h"
+#include "BKE_vfontdata.h"
#include "DNA_curve_types.h"
#include "DNA_packedFile_types.h"
@@ -98,7 +100,7 @@ static VChar *freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *
/* Start converting the FT data */
onpoints = (int *)MEM_callocN((ftoutline.n_contours) * sizeof(int), "onpoints");
- /* get number of on-curve points for beziertriples (including conic virtual on-points) */
+ /* Get number of on-curve points for bezier-triples (including conic virtual on-points). */
for (j = 0, contour_prev = -1; j < ftoutline.n_contours; j++) {
const int n = ftoutline.contours[j] - contour_prev;
contour_prev = ftoutline.contours[j];
@@ -394,15 +396,7 @@ static bool check_freetypefont(PackedFile *pf)
return success;
}
-/**
- * Construct a new VFontData structure from
- * Freetype font data in a PackedFile.
- *
- * \param pf: The font data.
- * \retval A new VFontData structure, or NULL
- * if unable to load.
- */
-VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
+VFontData *BKE_vfontdata_from_freetypefont(PackedFile *pf)
{
VFontData *vfd = NULL;
@@ -425,10 +419,10 @@ VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
static void *vfontdata_copy_characters_value_cb(const void *src)
{
- return BLI_vfontchar_copy(src, 0);
+ return BKE_vfontdata_char_copy(src);
}
-VFontData *BLI_vfontdata_copy(const VFontData *vfont_src, const int UNUSED(flag))
+VFontData *BKE_vfontdata_copy(const VFontData *vfont_src, const int UNUSED(flag))
{
VFontData *vfont_dst = MEM_dupallocN(vfont_src);
@@ -440,7 +434,7 @@ VFontData *BLI_vfontdata_copy(const VFontData *vfont_src, const int UNUSED(flag)
return vfont_dst;
}
-VChar *BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
+VChar *BKE_vfontdata_char_from_freetypefont(VFont *vfont, unsigned long character)
{
VChar *che = NULL;
@@ -464,12 +458,7 @@ VChar *BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
return che;
}
-/* Yeah, this is very bad... But why is this in BLI in the first place, since it uses Nurb data?
- * Anyway, do not feel like duplicating whole Nurb copy code here,
- * so unless someone has a better idea... */
-#include "../../blenkernel/BKE_curve.h"
-
-VChar *BLI_vfontchar_copy(const VChar *vchar_src, const int UNUSED(flag))
+VChar *BKE_vfontdata_char_copy(const VChar *vchar_src)
{
VChar *vchar_dst = MEM_dupallocN(vchar_src);
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 0b9ef5c537d..39a7725bfa3 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -28,18 +28,20 @@
#include "BLI_compiler_compat.h"
#include "BLI_fileops.h"
-#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
#include "BLI_ghash.h"
#include "BLI_index_range.hh"
#include "BLI_map.hh"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_ref.hh"
#include "BLI_task.hh"
#include "BLI_utildefines.h"
#include "BKE_anim_data.h"
+#include "BKE_bpath.h"
#include "BKE_geometry_set.hh"
#include "BKE_global.h"
#include "BKE_idtype.h"
@@ -71,6 +73,7 @@ static CLG_LogRef LOG = {"bke.volume"};
using blender::float3;
using blender::float4x4;
using blender::IndexRange;
+using blender::StringRef;
#ifdef WITH_OPENVDB
# include <atomic>
@@ -135,11 +138,19 @@ static struct VolumeFileCache {
}
std::lock_guard<std::mutex> lock(mutex);
- return simplified_grids.lookup_or_add_cb(simplify_level, [&]() {
- const float resolution_factor = 1.0f / (1 << simplify_level);
- const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(*grid);
- return BKE_volume_grid_create_with_changed_resolution(grid_type, *grid, resolution_factor);
+ openvdb::GridBase::Ptr simple_grid;
+
+ /* Isolate creating grid since that's multithreaded and we are
+ * holding a mutex lock. */
+ blender::threading::isolate_task([&] {
+ simple_grid = simplified_grids.lookup_or_add_cb(simplify_level, [&]() {
+ const float resolution_factor = 1.0f / (1 << simplify_level);
+ const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(*grid);
+ return BKE_volume_grid_create_with_changed_resolution(
+ grid_type, *grid, resolution_factor);
+ });
});
+ return simple_grid;
}
/* Unique key: filename + grid name. */
@@ -244,16 +255,20 @@ static struct VolumeFileCache {
protected:
void update_for_remove_user(Entry &entry)
{
- if (entry.num_metadata_users + entry.num_tree_users == 0) {
- cache.erase(entry);
- }
- else if (entry.num_tree_users == 0) {
- /* Note we replace the grid rather than clearing, so that if there is
- * any other shared pointer to the grid it will keep the tree. */
- entry.grid = entry.grid->copyGridWithNewTree();
- entry.simplified_grids.clear();
- entry.is_loaded = false;
- }
+ /* Isolate file unloading since that's multithreaded and we are
+ * holding a mutex lock. */
+ blender::threading::isolate_task([&] {
+ if (entry.num_metadata_users + entry.num_tree_users == 0) {
+ cache.erase(entry);
+ }
+ else if (entry.num_tree_users == 0) {
+ /* Note we replace the grid rather than clearing, so that if there is
+ * any other shared pointer to the grid it will keep the tree. */
+ entry.grid = entry.grid->copyGridWithNewTree();
+ entry.simplified_grids.clear();
+ entry.is_loaded = false;
+ }
+ });
}
/* Cache contents */
@@ -534,7 +549,7 @@ static void volume_copy_data(Main *UNUSED(bmain),
#ifdef WITH_OPENVDB
if (volume_src->runtime.grids) {
const VolumeGridVector &grids_src = *(volume_src->runtime.grids);
- volume_dst->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector, grids_src);
+ volume_dst->runtime.grids = MEM_new<VolumeGridVector>(__func__, grids_src);
}
#endif
@@ -548,7 +563,8 @@ static void volume_free_data(ID *id)
BKE_volume_batch_cache_free(volume);
MEM_SAFE_FREE(volume->mat);
#ifdef WITH_OPENVDB
- OBJECT_GUARDED_SAFE_DELETE(volume->runtime.grids, VolumeGridVector);
+ MEM_delete(volume->runtime.grids);
+ volume->runtime.grids = nullptr;
#endif
}
@@ -556,7 +572,7 @@ static void volume_foreach_id(ID *id, LibraryForeachIDData *data)
{
Volume *volume = (Volume *)id;
for (int i = 0; i < volume->totcol; i++) {
- BKE_LIB_FOREACHID_PROCESS(data, volume->mat[i], IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, volume->mat[i], IDWALK_CB_USER);
}
}
@@ -574,6 +590,18 @@ static void volume_foreach_cache(ID *id,
function_callback(id, &key, (void **)&volume->runtime.grids, 0, user_data);
}
+static void volume_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Volume *volume = reinterpret_cast<Volume *>(id);
+
+ if (volume->packedfile != nullptr &&
+ (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
+ return;
+ }
+
+ BKE_bpath_foreach_path_fixed_process(bpath_data, volume->filepath);
+}
+
static void volume_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Volume *volume = (Volume *)id;
@@ -643,6 +671,7 @@ IDTypeInfo IDType_ID_VO = {
/* name_plural */ "volumes",
/* translation_context */ BLT_I18NCONTEXT_ID_VOLUME,
/* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
/* init_data */ volume_init_data,
/* copy_data */ volume_copy_data,
@@ -650,6 +679,7 @@ IDTypeInfo IDType_ID_VO = {
/* make_local */ nullptr,
/* foreach_id */ volume_foreach_id,
/* foreach_cache */ volume_foreach_cache,
+ /* foreach_path */ volume_foreach_path,
/* owner_get */ nullptr,
/* blend_write */ volume_blend_write,
@@ -666,7 +696,7 @@ void BKE_volume_init_grids(Volume *volume)
{
#ifdef WITH_OPENVDB
if (volume->runtime.grids == nullptr) {
- volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector);
+ volume->runtime.grids = MEM_new<VolumeGridVector>(__func__);
}
#else
UNUSED_VARS(volume);
@@ -937,7 +967,7 @@ BoundBox *BKE_volume_boundbox_get(Object *ob)
}
if (ob->runtime.bb == nullptr) {
- ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), __func__);
+ ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
}
const Volume *volume = (Volume *)ob->data;
@@ -1112,16 +1142,16 @@ void BKE_volume_grids_backup_restore(Volume *volume, VolumeGridVector *grids, co
if (!grids->is_loaded()) {
/* No grids loaded in CoW datablock, nothing lost by discarding. */
- OBJECT_GUARDED_DELETE(grids, VolumeGridVector);
+ MEM_delete(grids);
}
else if (!STREQ(volume->filepath, filepath)) {
/* Filepath changed, discard grids from CoW datablock. */
- OBJECT_GUARDED_DELETE(grids, VolumeGridVector);
+ MEM_delete(grids);
}
else {
/* Keep grids from CoW datablock. We might still unload them a little
* later in BKE_volume_eval_geometry if the frame changes. */
- OBJECT_GUARDED_DELETE(volume->runtime.grids, VolumeGridVector);
+ MEM_delete(volume->runtime.grids);
volume->runtime.grids = grids;
}
#else
@@ -1223,7 +1253,6 @@ const VolumeGrid *BKE_volume_grid_active_get_for_read(const Volume *volume)
return BKE_volume_grid_get_for_read(volume, index);
}
-/* Tries to find a grid with the given name. Make sure that the volume has been loaded. */
const VolumeGrid *BKE_volume_grid_find_for_read(const Volume *volume, const char *name)
{
int num_grids = BKE_volume_num_grids(volume);
@@ -1363,7 +1392,6 @@ int BKE_volume_grid_channels(const VolumeGrid *grid)
return 0;
}
-/* Transformation from index space to object space. */
void BKE_volume_grid_transform_matrix(const VolumeGrid *volume_grid, float mat[4][4])
{
#ifdef WITH_OPENVDB
@@ -1451,6 +1479,21 @@ VolumeGrid *BKE_volume_grid_add(Volume *volume, const char *name, VolumeGridType
#endif
}
+#ifdef WITH_OPENVDB
+VolumeGrid *BKE_volume_grid_add_vdb(Volume &volume,
+ const StringRef name,
+ openvdb::GridBase::Ptr vdb_grid)
+{
+ VolumeGridVector &grids = *volume.runtime.grids;
+ BLI_assert(BKE_volume_grid_find_for_read(&volume, name.data()) == nullptr);
+ BLI_assert(BKE_volume_grid_type_openvdb(*vdb_grid) != VOLUME_GRID_UNKNOWN);
+
+ vdb_grid->setName(name);
+ grids.emplace_back(vdb_grid);
+ return &grids.back();
+}
+#endif
+
void BKE_volume_grid_remove(Volume *volume, VolumeGrid *grid)
{
#ifdef WITH_OPENVDB
@@ -1513,11 +1556,6 @@ bool BKE_volume_grid_bounds(openvdb::GridBase::ConstPtr grid, float3 &r_min, flo
return true;
}
-/**
- * Return a new grid pointer with only the metadata and transform changed.
- * This is useful for instances, where there is a separate transform on top of the original
- * grid transform that must be applied for some operations that only take a grid argument.
- */
openvdb::GridBase::ConstPtr BKE_volume_grid_shallow_transform(openvdb::GridBase::ConstPtr grid,
const blender::float4x4 &transform)
{
diff --git a/source/blender/blenkernel/intern/volume_render.cc b/source/blender/blenkernel/intern/volume_render.cc
index 6dc497bb616..c0a205b5673 100644
--- a/source/blender/blenkernel/intern/volume_render.cc
+++ b/source/blender/blenkernel/intern/volume_render.cc
@@ -21,8 +21,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_array.hh"
-#include "BLI_float3.hh"
#include "BLI_math_matrix.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.h"
#include "BLI_vector.hh"
diff --git a/source/blender/blenkernel/intern/volume_to_mesh.cc b/source/blender/blenkernel/intern/volume_to_mesh.cc
index e9d6eea4614..336ce724e35 100644
--- a/source/blender/blenkernel/intern/volume_to_mesh.cc
+++ b/source/blender/blenkernel/intern/volume_to_mesh.cc
@@ -16,7 +16,7 @@
#include <vector>
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
@@ -121,46 +121,57 @@ struct VolumeToMeshOp {
}
};
-static Mesh *new_mesh_from_openvdb_data(Span<openvdb::Vec3s> verts,
- Span<openvdb::Vec3I> tris,
- Span<openvdb::Vec4I> quads)
+void fill_mesh_from_openvdb_data(const Span<openvdb::Vec3s> vdb_verts,
+ const Span<openvdb::Vec3I> vdb_tris,
+ const Span<openvdb::Vec4I> vdb_quads,
+ const int vert_offset,
+ const int poly_offset,
+ const int loop_offset,
+ MutableSpan<MVert> verts,
+ MutableSpan<MPoly> polys,
+ MutableSpan<MLoop> loops)
{
- const int tot_loops = 3 * tris.size() + 4 * quads.size();
- const int tot_polys = tris.size() + quads.size();
-
- Mesh *mesh = BKE_mesh_new_nomain(verts.size(), 0, 0, tot_loops, tot_polys);
-
/* Write vertices. */
- for (const int i : verts.index_range()) {
- const blender::float3 co = blender::float3(verts[i].asV());
- copy_v3_v3(mesh->mvert[i].co, co);
+ for (const int i : vdb_verts.index_range()) {
+ const blender::float3 co = blender::float3(vdb_verts[i].asV());
+ copy_v3_v3(verts[vert_offset + i].co, co);
}
/* Write triangles. */
- for (const int i : tris.index_range()) {
- mesh->mpoly[i].loopstart = 3 * i;
- mesh->mpoly[i].totloop = 3;
+ for (const int i : vdb_tris.index_range()) {
+ polys[poly_offset + i].loopstart = loop_offset + 3 * i;
+ polys[poly_offset + i].totloop = 3;
for (int j = 0; j < 3; j++) {
/* Reverse vertex order to get correct normals. */
- mesh->mloop[3 * i + j].v = tris[i][2 - j];
+ loops[loop_offset + 3 * i + j].v = vert_offset + vdb_tris[i][2 - j];
}
}
/* Write quads. */
- const int poly_offset = tris.size();
- const int loop_offset = tris.size() * 3;
- for (const int i : quads.index_range()) {
- mesh->mpoly[poly_offset + i].loopstart = loop_offset + 4 * i;
- mesh->mpoly[poly_offset + i].totloop = 4;
+ const int quad_offset = poly_offset + vdb_tris.size();
+ const int quad_loop_offset = loop_offset + vdb_tris.size() * 3;
+ for (const int i : vdb_quads.index_range()) {
+ polys[quad_offset + i].loopstart = quad_loop_offset + 4 * i;
+ polys[quad_offset + i].totloop = 4;
for (int j = 0; j < 4; j++) {
/* Reverse vertex order to get correct normals. */
- mesh->mloop[loop_offset + 4 * i + j].v = quads[i][3 - j];
+ loops[quad_loop_offset + 4 * i + j].v = vert_offset + vdb_quads[i][3 - j];
}
}
+}
- BKE_mesh_calc_edges(mesh, false, false);
- BKE_mesh_normals_tag_dirty(mesh);
- return mesh;
+bke::OpenVDBMeshData volume_to_mesh_data(const openvdb::GridBase &grid,
+ const VolumeToMeshResolution &resolution,
+ const float threshold,
+ const float adaptivity)
+{
+ const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(grid);
+
+ VolumeToMeshOp to_mesh_op{grid, resolution, threshold, adaptivity};
+ if (!BKE_volume_grid_type_operation(grid_type, to_mesh_op)) {
+ return {};
+ }
+ return {std::move(to_mesh_op.verts), std::move(to_mesh_op.tris), std::move(to_mesh_op.quads)};
}
Mesh *volume_to_mesh(const openvdb::GridBase &grid,
@@ -168,14 +179,27 @@ Mesh *volume_to_mesh(const openvdb::GridBase &grid,
const float threshold,
const float adaptivity)
{
- const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(grid);
+ const bke::OpenVDBMeshData mesh_data = volume_to_mesh_data(
+ grid, resolution, threshold, adaptivity);
+
+ const int tot_loops = 3 * mesh_data.tris.size() + 4 * mesh_data.quads.size();
+ const int tot_polys = mesh_data.tris.size() + mesh_data.quads.size();
+ Mesh *mesh = BKE_mesh_new_nomain(mesh_data.verts.size(), 0, 0, tot_loops, tot_polys);
+
+ fill_mesh_from_openvdb_data(mesh_data.verts,
+ mesh_data.tris,
+ mesh_data.quads,
+ 0,
+ 0,
+ 0,
+ {mesh->mvert, mesh->totvert},
+ {mesh->mpoly, mesh->totpoly},
+ {mesh->mloop, mesh->totloop});
- VolumeToMeshOp to_mesh_op{grid, resolution, threshold, adaptivity};
- if (!BKE_volume_grid_type_operation(grid_type, to_mesh_op)) {
- return nullptr;
- }
+ BKE_mesh_calc_edges(mesh, false, false);
+ BKE_mesh_normals_tag_dirty(mesh);
- return new_mesh_from_openvdb_data(to_mesh_op.verts, to_mesh_op.tris, to_mesh_op.quads);
+ return mesh;
}
#endif /* WITH_OPENVDB */
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index 3c168a6c7b2..e3fe1e04368 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -82,7 +82,7 @@ static void workspace_foreach_id(ID *id, LibraryForeachIDData *data)
WorkSpace *workspace = (WorkSpace *)id;
LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
- BKE_LIB_FOREACHID_PROCESS(data, layout->screen, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, layout->screen, IDWALK_CB_USER);
}
}
@@ -187,6 +187,7 @@ IDTypeInfo IDType_ID_WS = {
.name_plural = "workspaces",
.translation_context = BLT_I18NCONTEXT_ID_WORKSPACE,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_ONLY_APPEND | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = workspace_init_data,
.copy_data = NULL,
@@ -194,6 +195,7 @@ IDTypeInfo IDType_ID_WS = {
.make_local = NULL,
.foreach_id = workspace_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = workspace_blend_write,
@@ -319,13 +321,6 @@ WorkSpace *BKE_workspace_add(Main *bmain, const char *name)
return new_workspace;
}
-/**
- * Remove \a workspace by freeing itself and its data. This is a higher-level wrapper that
- * calls #workspace_free_data (through #BKE_id_free) to free the workspace data, and frees
- * other data-blocks owned by \a workspace and its layouts (currently that is screens only).
- *
- * Always use this to remove (and free) workspaces. Don't free non-ID workspace members here.
- */
void BKE_workspace_remove(Main *bmain, WorkSpace *workspace)
{
for (WorkSpaceLayout *layout = workspace->layouts.first, *layout_next; layout;
@@ -369,9 +364,6 @@ void BKE_workspace_instance_hook_free(const Main *bmain, WorkSpaceInstanceHook *
MEM_freeN(hook);
}
-/**
- * Add a new layout to \a workspace for \a screen.
- */
WorkSpaceLayout *BKE_workspace_layout_add(Main *bmain,
WorkSpace *workspace,
bScreen *screen,
@@ -434,13 +426,6 @@ WorkSpaceLayout *BKE_workspace_layout_find(const WorkSpace *workspace, const bSc
return NULL;
}
-/**
- * Find the layout for \a screen without knowing which workspace to look in.
- * Can also be used to find the workspace that contains \a screen.
- *
- * \param r_workspace: Optionally return the workspace that contains the
- * looked up layout (if found).
- */
WorkSpaceLayout *BKE_workspace_layout_find_global(const Main *bmain,
const bScreen *screen,
WorkSpace **r_workspace)
@@ -464,15 +449,6 @@ WorkSpaceLayout *BKE_workspace_layout_find_global(const Main *bmain,
return NULL;
}
-/**
- * Circular workspace layout iterator.
- *
- * \param callback: Custom function which gets executed for each layout.
- * Can return false to stop iterating.
- * \param arg: Custom data passed to each \a callback call.
- *
- * \return the layout at which \a callback returned false.
- */
WorkSpaceLayout *BKE_workspace_layout_iter_circular(const WorkSpace *workspace,
WorkSpaceLayout *start,
bool (*callback)(const WorkSpaceLayout *layout,
@@ -564,18 +540,11 @@ void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace)
}
}
-/**
- * Get the layout that is active for \a hook (which is the visible layout for the active workspace
- * in \a hook).
- */
WorkSpaceLayout *BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook)
{
return hook->act_layout;
}
-/**
- * Get the layout to be activated should \a workspace become or be the active workspace in \a hook.
- */
WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(const WorkSpaceInstanceHook *hook,
const WorkSpace *workspace)
{
@@ -588,17 +557,6 @@ WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(const WorkSpaceIn
return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
}
-/**
- * \brief Activate a layout
- *
- * Sets \a layout as active for \a workspace when activated through or already active in \a hook.
- * So when the active workspace of \a hook is \a workspace, \a layout becomes the active layout of
- * \a hook too. See #BKE_workspace_active_set().
- *
- * \a workspace does not need to be active for this.
- *
- * WorkSpaceInstanceHook.act_layout should only be modified directly to update the layout pointer.
- */
void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook,
const int winid,
WorkSpace *workspace,
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 02be3bcbf2f..d4f0e016697 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -133,7 +133,8 @@ static void world_foreach_id(ID *id, LibraryForeachIDData *data)
if (world->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_embedded(data, (ID **)&world->nodetree);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
+ data, BKE_library_foreach_ID_embedded(data, (ID **)&world->nodetree));
}
}
@@ -193,6 +194,7 @@ IDTypeInfo IDType_ID_WO = {
.name_plural = "worlds",
.translation_context = BLT_I18NCONTEXT_ID_WORLD,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = world_init_data,
.copy_data = world_copy_data,
@@ -200,6 +202,7 @@ IDTypeInfo IDType_ID_WO = {
.make_local = NULL,
.foreach_id = world_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = world_blend_write,
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index 4635db98514..a4f20f980b4 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -315,7 +315,6 @@ static void context_free_avi(void *context_v)
#endif /* WITH_AVI */
-/* similar to BKE_image_path_from_imformat() */
void BKE_movie_filepath_get(char *string, const RenderData *rd, bool preview, const char *suffix)
{
bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index a20c918c517..4d94132e6fd 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -87,6 +87,7 @@ typedef struct FFMpegContext {
AVStream *video_stream;
AVStream *audio_stream;
AVFrame *current_frame; /* Image frame in output pixel format. */
+ int video_time;
/* Image frame in Blender's own pixel format, may need conversion to the output pixel format. */
AVFrame *img_convert_frame;
@@ -96,6 +97,7 @@ typedef struct FFMpegContext {
uint8_t *audio_deinterleave_buffer;
int audio_input_samples;
double audio_time;
+ double audio_time_total;
bool audio_deinterleave;
int audio_sample_size;
@@ -318,14 +320,15 @@ static const char **get_file_extensions(int format)
}
/* Write a frame to the output file */
-static int write_video_frame(FFMpegContext *context, int cfra, AVFrame *frame, ReportList *reports)
+static int write_video_frame(FFMpegContext *context, AVFrame *frame, ReportList *reports)
{
int ret, success = 1;
AVPacket *packet = av_packet_alloc();
AVCodecContext *c = context->video_codec;
- frame->pts = cfra;
+ frame->pts = context->video_time;
+ context->video_time++;
ret = avcodec_send_frame(c, frame);
if (ret < 0) {
@@ -804,6 +807,8 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
avcodec_parameters_from_context(st->codecpar, c);
+ context->video_time = 0.0f;
+
return st;
}
@@ -1397,9 +1402,10 @@ static void write_audio_frames(FFMpegContext *context, double to_pts)
AVCodecContext *c = context->audio_codec;
while (context->audio_stream) {
- if ((context->audio_time >= to_pts) || !write_audio_frame(context)) {
+ if ((context->audio_time_total >= to_pts) || !write_audio_frame(context)) {
break;
}
+ context->audio_time_total += (double)context->audio_input_samples / (double)c->sample_rate;
context->audio_time += (double)context->audio_input_samples / (double)c->sample_rate;
}
}
@@ -1423,22 +1429,25 @@ int BKE_ffmpeg_append(void *context_v,
if (context->video_stream) {
avframe = generate_video_frame(context, (unsigned char *)pixels);
- success = (avframe && write_video_frame(context, frame - start_frame, avframe, reports));
+ success = (avframe && write_video_frame(context, avframe, reports));
+# ifdef WITH_AUDASPACE
+ /* Add +1 frame because we want to encode audio up until the next video frame. */
+ write_audio_frames(
+ context, (frame - start_frame + 1) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
+# else
+ UNUSED_VARS(start_frame);
+# endif
if (context->ffmpeg_autosplit) {
if (avio_tell(context->outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
end_ffmpeg_impl(context, true);
context->ffmpeg_autosplit_count++;
+
success &= start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
}
}
}
-# ifdef WITH_AUDASPACE
- /* Add +1 frame because we want to encode audio up until the next video frame. */
- write_audio_frames(
- context, (frame - start_frame + 1) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
-# endif
return success;
}
@@ -1881,6 +1890,7 @@ void *BKE_ffmpeg_context_create(void)
context->ffmpeg_autosplit_count = 0;
context->ffmpeg_preview = false;
context->stamp_data = NULL;
+ context->audio_time_total = 0.0;
return context;
}
diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h
index 3e13ba602a4..c338540b5f5 100644
--- a/source/blender/blenkernel/nla_private.h
+++ b/source/blender/blenkernel/nla_private.h
@@ -165,46 +165,77 @@ typedef struct NlaKeyframingContext {
/* --------------- NLA Functions (not to be used as a proper API) ----------------------- */
-/* convert from strip time <-> global time */
+/**
+ * Convert non clipped mapping for strip-time <-> global time:
+ * `mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_*`
+ *
+ * Only secure for 'internal' (i.e. within AnimSys evaluation) operations,
+ * but should not be directly relied on for stuff which interacts with editors.
+ */
float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode);
/* --------------- NLA Evaluation (very-private stuff) ----------------------- */
/* these functions are only defined here to avoid problems with the order
* in which they get defined. */
+/**
+ * Gets the strip active at the current time for a list of strips for evaluation purposes.
+ */
NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list,
ListBase *strips,
short index,
const struct AnimationEvalContext *anim_eval_context,
- const bool flush_to_original);
+ bool flush_to_original);
+/**
+ * Evaluates the given evaluation strip.
+ */
void nlastrip_evaluate(PointerRNA *ptr,
NlaEvalData *channels,
ListBase *modifiers,
NlaEvalStrip *nes,
NlaEvalSnapshot *snapshot,
const struct AnimationEvalContext *anim_eval_context,
- const bool flush_to_original);
+ bool flush_to_original);
+/**
+ * write the accumulated settings to.
+ */
void nladata_flush_channels(PointerRNA *ptr,
NlaEvalData *channels,
NlaEvalSnapshot *snapshot,
- const bool flush_to_original);
+ bool flush_to_original);
void nlasnapshot_enable_all_blend_domain(NlaEvalSnapshot *snapshot);
void nlasnapshot_ensure_channels(NlaEvalData *eval_data, NlaEvalSnapshot *snapshot);
+/**
+ * Blends the \a lower_snapshot with the \a upper_snapshot into \a r_blended_snapshot according
+ * to the given \a upper_blendmode and \a upper_influence.
+ *
+ * For \a upper_snapshot, blending limited to values in the \a blend_domain.
+ * For Replace blend-mode, this allows the upper snapshot to have a location XYZ channel
+ * where only a subset of values are blended.
+ */
void nlasnapshot_blend(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *upper_snapshot,
- const short upper_blendmode,
- const float upper_influence,
+ short upper_blendmode,
+ float upper_influence,
NlaEvalSnapshot *r_blended_snapshot);
+/**
+ * Using \a blended_snapshot and \a lower_snapshot, we can solve for the \a r_upper_snapshot.
+ *
+ * Only channels that exist within \a blended_snapshot are inverted.
+ *
+ * For \a r_upper_snapshot, disables \a NlaEvalChannelSnapshot->remap_domain for failed inversions.
+ * Only values within the \a remap_domain are processed.
+ */
void nlasnapshot_blend_get_inverted_upper_snapshot(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *blended_snapshot,
- const short upper_blendmode,
- const float upper_influence,
+ short upper_blendmode,
+ float upper_influence,
NlaEvalSnapshot *r_upper_snapshot);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/tracking_private.h b/source/blender/blenkernel/tracking_private.h
index 8de6ec93a7c..0c1f73fa4b6 100644
--- a/source/blender/blenkernel/tracking_private.h
+++ b/source/blender/blenkernel/tracking_private.h
@@ -78,12 +78,21 @@ void tracking_get_search_origin_frame_pixel(int frame_width,
const struct MovieTrackingMarker *marker,
float frame_pixel[2]);
+/**
+ * Each marker has 5 coordinates associated with it that get warped with
+ * tracking: the four corners ("pattern_corners"), and the center ("pos").
+ * This function puts those 5 points into the appropriate frame for tracking
+ * (the "search" coordinate frame).
+ */
void tracking_get_marker_coords_for_tracking(int frame_width,
int frame_height,
const struct MovieTrackingMarker *marker,
double search_pixel_x[5],
double search_pixel_y[5]);
+/**
+ * Inverse of #tracking_get_marker_coords_for_tracking.
+ */
void tracking_set_marker_coords_from_tracking(int frame_width,
int frame_height,
struct MovieTrackingMarker *marker,
@@ -92,11 +101,23 @@ void tracking_set_marker_coords_from_tracking(int frame_width,
/*********************** General purpose utility functions *************************/
+/**
+ * Place a disabled marker before or after specified ref_marker.
+ *
+ * If before is truth, disabled marker is placed before reference
+ * one, and it's placed after it otherwise.
+ *
+ * If there's already a marker at the frame where disabled one is expected to be placed,
+ * nothing will happen if overwrite is false.
+ */
void tracking_marker_insert_disabled(struct MovieTrackingTrack *track,
const struct MovieTrackingMarker *ref_marker,
bool before,
bool overwrite);
+/**
+ * Fill in Libmv C-API camera intrinsics options from tracking structure.
+ */
void tracking_cameraIntrinscisOptionsFromTracking(
struct MovieTracking *tracking,
int calibration_width,
@@ -109,17 +130,26 @@ void tracking_trackingCameraFromIntrinscisOptions(
struct libmv_TrackRegionOptions;
+/**
+ * Fill in libmv tracker options structure with settings need to be used to perform track.
+ */
void tracking_configure_tracker(const MovieTrackingTrack *track,
float *mask,
bool is_backwards,
struct libmv_TrackRegionOptions *options);
+/**
+ * Get previous keyframed marker.
+ */
struct MovieTrackingMarker *tracking_get_keyframed_marker(struct MovieTrackingTrack *track,
int current_frame,
bool backwards);
/*********************** Masking *************************/
+/**
+ * Region is in pixel space, relative to marker's center.
+ */
float *tracking_track_get_mask_for_region(int frame_width,
int frame_height,
const float region_min[2],
@@ -145,11 +175,13 @@ typedef struct TrackingImageAccessor {
SpinLock cache_lock;
} TrackingImageAccessor;
-/* Clips are used to access images of an actual footage.
+/**
+ * Clips are used to access images of an actual footage.
* Tracks are used to access masks associated with the tracks.
*
- * NOTE: Both clips and tracks arrays are copied into the image accessor. It means that the caller
- * is allowed to pass temporary arrays which are only valid during initialization. */
+ * \note Both clips and tracks arrays are copied into the image accessor. It means that the caller
+ * is allowed to pass temporary arrays which are only valid during initialization.
+ */
TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR_CLIP],
int num_clips,
MovieTrackingTrack **tracks,
diff --git a/source/blender/blenlib/BLI_any.hh b/source/blender/blenlib/BLI_any.hh
new file mode 100644
index 00000000000..7ffc323adf6
--- /dev/null
+++ b/source/blender/blenlib/BLI_any.hh
@@ -0,0 +1,319 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ *
+ * A #blender::Any is a type-safe container for single values of any copy constructible type.
+ * It is similar to #std::any but provides the following two additional features:
+ * - Adjustable inline buffer capacity and alignment. #std::any has a small inline buffer in most
+ * implementations as well, but its size is not guaranteed.
+ * - Can store additional user-defined type information without increasing the stack size of #Any.
+ */
+
+#include <algorithm>
+#include <utility>
+
+#include "BLI_memory_utils.hh"
+
+namespace blender {
+
+namespace detail {
+
+/**
+ * Contains function pointers that manage the memory in an #Any.
+ * Additional type specific #ExtraInfo can be embedded here as well.
+ */
+template<typename ExtraInfo> struct AnyTypeInfo {
+ void (*copy_construct)(void *dst, const void *src);
+ void (*move_construct)(void *dst, void *src);
+ void (*destruct)(void *src);
+ const void *(*get)(const void *src);
+ ExtraInfo extra_info;
+
+ /**
+ * Used when #T is stored directly in the inline buffer of the #Any.
+ */
+ template<typename T> static const AnyTypeInfo &get_for_inline()
+ {
+ static AnyTypeInfo funcs = {[](void *dst, const void *src) { new (dst) T(*(const T *)src); },
+ [](void *dst, void *src) { new (dst) T(std::move(*(T *)src)); },
+ [](void *src) { ((T *)src)->~T(); },
+ [](const void *src) { return src; },
+ ExtraInfo::template get<T>()};
+ return funcs;
+ }
+
+ /**
+ * Used when #T can't be stored directly in the inline buffer and is stored in a #std::unique_ptr
+ * instead. In this scenario, the #std::unique_ptr is stored in the inline buffer.
+ */
+ template<typename T> static const AnyTypeInfo &get_for_unique_ptr()
+ {
+ using Ptr = std::unique_ptr<T>;
+ static AnyTypeInfo funcs = {
+ [](void *dst, const void *src) { new (dst) Ptr(new T(**(const Ptr *)src)); },
+ [](void *dst, void *src) { new (dst) Ptr(new T(std::move(**(Ptr *)src))); },
+ [](void *src) { ((Ptr *)src)->~Ptr(); },
+ [](const void *src) -> const void * { return &**(const Ptr *)src; },
+ ExtraInfo::template get<T>()};
+ return funcs;
+ }
+
+ /**
+ * Used when the #Any does not contain any type currently.
+ */
+ static const AnyTypeInfo &get_for_empty()
+ {
+ static AnyTypeInfo funcs = {[](void *UNUSED(dst), const void *UNUSED(src)) {},
+ [](void *UNUSED(dst), void *UNUSED(src)) {},
+ [](void *UNUSED(src)) {},
+ [](const void *UNUSED(src)) -> const void * { return nullptr; },
+ ExtraInfo{}};
+ return funcs;
+ }
+};
+
+/**
+ * Dummy extra info that is used when no additional type information should be stored in the #Any.
+ */
+struct NoExtraInfo {
+ template<typename T> static NoExtraInfo get()
+ {
+ return {};
+ }
+};
+
+} // namespace detail
+
+template<
+ /**
+ * Either void or a struct that contains data members for additional type information.
+ * The struct has to have a static `ExtraInfo get<T>()` method that initializes the struct
+ * based on a type.
+ */
+ typename ExtraInfo = void,
+ /**
+ * Size of the inline buffer. This allows types that are small enough to be stored directly
+ * inside the #Any without an additional allocation.
+ */
+ size_t InlineBufferCapacity = 8,
+ /**
+ * Required minimum alignment of the inline buffer. If this is smaller than the alignment
+ * requirement of a used type, a separate allocation is necessary.
+ */
+ size_t Alignment = 8>
+class Any {
+ private:
+ /* Makes it possible to use void in the template parameters. */
+ using RealExtraInfo =
+ std::conditional_t<std::is_void_v<ExtraInfo>, detail::NoExtraInfo, ExtraInfo>;
+ using Info = detail::AnyTypeInfo<RealExtraInfo>;
+
+ /**
+ * Inline buffer that either contains nothing, the stored value directly, or a #std::unique_ptr
+ * to the value.
+ */
+ AlignedBuffer<std::max(InlineBufferCapacity, sizeof(std::unique_ptr<int>)), Alignment> buffer_{};
+
+ /**
+ * Information about the type that is currently stored.
+ */
+ const Info *info_ = &Info::get_for_empty();
+
+ public:
+ /** Only copy constructible types can be stored in #Any. */
+ template<typename T> static constexpr inline bool is_allowed_v = std::is_copy_constructible_v<T>;
+
+ /**
+ * Checks if the type will be stored in the inline buffer or if it requires a separate
+ * allocation.
+ */
+ template<typename T>
+ static constexpr inline bool is_inline_v = std::is_nothrow_move_constructible_v<T> &&
+ sizeof(T) <= InlineBufferCapacity &&
+ alignof(T) <= Alignment;
+
+ /**
+ * Checks if #T is the same type as this #Any, because in this case the behavior of e.g. the
+ * assignment operator is different.
+ */
+ template<typename T>
+ static constexpr inline bool is_same_any_v = std::is_same_v<std::decay_t<T>, Any>;
+
+ private:
+ template<typename T> const Info &get_info() const
+ {
+ using DecayT = std::decay_t<T>;
+ static_assert(is_allowed_v<DecayT>);
+ if constexpr (is_inline_v<DecayT>) {
+ return Info::template get_for_inline<DecayT>();
+ }
+ else {
+ return Info::template get_for_unique_ptr<DecayT>();
+ }
+ }
+
+ public:
+ Any() = default;
+
+ Any(const Any &other) : info_(other.info_)
+ {
+ info_->copy_construct(&buffer_, &other.buffer_);
+ }
+
+ /**
+ * \note The #other #Any will not be empty afterwards if it was not before. Just its value is in
+ * a moved-from state.
+ */
+ Any(Any &&other) noexcept : info_(other.info_)
+ {
+ info_->move_construct(&buffer_, &other.buffer_);
+ }
+
+ /**
+ * Constructs a new #Any that contains the given type #T from #args. The #std::in_place_type_t is
+ * used to disambiguate this and the copy/move constructors.
+ */
+ template<typename T, typename... Args> explicit Any(std::in_place_type_t<T>, Args &&...args)
+ {
+ using DecayT = std::decay_t<T>;
+ static_assert(is_allowed_v<DecayT>);
+ info_ = &this->template get_info<DecayT>();
+ if constexpr (is_inline_v<DecayT>) {
+ /* Construct the value directly in the inline buffer. */
+ new (&buffer_) DecayT(std::forward<Args>(args)...);
+ }
+ else {
+ /* Construct the value in a new allocation and store a #std::unique_ptr to it in the inline
+ * buffer. */
+ new (&buffer_) std::unique_ptr<DecayT>(new DecayT(std::forward<Args>(args)...));
+ }
+ }
+
+ /**
+ * Constructs a new #Any that contains the given value.
+ */
+ template<typename T, BLI_ENABLE_IF((!is_same_any_v<T>))>
+ Any(T &&value) : Any(std::in_place_type<T>, std::forward<T>(value))
+ {
+ }
+
+ ~Any()
+ {
+ info_->destruct(&buffer_);
+ }
+
+ /**
+ * \note: Only needed because the template below does not count as copy assignment operator.
+ */
+ Any &operator=(const Any &other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+ this->~Any();
+ new (this) Any(other);
+ return *this;
+ }
+
+ /** Assign any value to the #Any. */
+ template<typename T> Any &operator=(T &&other)
+ {
+ if constexpr (is_same_any_v<T>) {
+ if (this == &other) {
+ return *this;
+ }
+ }
+ this->~Any();
+ new (this) Any(std::forward<T>(other));
+ return *this;
+ }
+
+ /** Destruct any existing value to make it empty. */
+ void reset()
+ {
+ info_->destruct(&buffer_);
+ info_ = &Info::get_for_empty();
+ }
+
+ operator bool() const
+ {
+ return this->has_value();
+ }
+
+ bool has_value() const
+ {
+ return info_ != &Info::get_for_empty();
+ }
+
+ template<typename T, typename... Args> std::decay_t<T> &emplace(Args &&...args)
+ {
+ this->~Any();
+ new (this) Any(std::in_place_type<T>, std::forward<Args>(args)...);
+ return this->get<T>();
+ }
+
+ /** Return true when the value that is currently stored is a #T. */
+ template<typename T> bool is() const
+ {
+ return info_ == &this->template get_info<T>();
+ }
+
+ /** Get a pointer to the stored value. */
+ void *get()
+ {
+ return const_cast<void *>(info_->get(&buffer_));
+ }
+
+ /** Get a pointer to the stored value. */
+ const void *get() const
+ {
+ return info_->get(&buffer_);
+ }
+
+ /**
+ * Get a reference to the stored value. This invokes undefined behavior when #T does not have the
+ * correct type.
+ */
+ template<typename T> std::decay_t<T> &get()
+ {
+ BLI_assert(this->is<T>());
+ return *static_cast<std::decay_t<T> *>(this->get());
+ }
+
+ /**
+ * Get a reference to the stored value. This invokes undefined behavior when #T does not have the
+ * correct type.
+ */
+ template<typename T> const std::decay_t<T> &get() const
+ {
+ BLI_assert(this->is<T>());
+ return *static_cast<const std::decay_t<T> *>(this->get());
+ }
+
+ /**
+ * Get extra information that has been stored for the contained type.
+ */
+ const RealExtraInfo &extra_info() const
+ {
+ return info_->extra_info;
+ }
+};
+
+} // namespace blender
diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h
index 084f573e8c7..85fa07d8563 100644
--- a/source/blender/blenlib/BLI_array.h
+++ b/source/blender/blenlib/BLI_array.h
@@ -28,7 +28,7 @@
/** \name Internal defines
* \{ */
-/** this returns the entire size of the array, including any buffering. */
+/** This returns the entire size of the array, including any buffering. */
#define _bli_array_totalsize_dynamic(arr) \
(((arr) == NULL) ? 0 : MEM_allocN_len(arr) / sizeof(*(arr)))
@@ -44,14 +44,18 @@
/**
* BLI_array.c
*
- * Doing the realloc in a macro isn't so simple,
+ * Doing the reallocation in a macro isn't so simple,
* so use a function the macros can use.
+ *
+ * This function is only to be called via macros.
+ *
+ * \note The caller must adjust \a arr_len
*/
void _bli_array_grow_func(void **arr_p,
const void *arr_static,
- const int sizeof_arr_p,
- const int arr_len,
- const int num,
+ int sizeof_arr_p,
+ int arr_len,
+ int num,
const char *alloc_str);
/* -------------------------------------------------------------------- */
@@ -64,8 +68,9 @@ void _bli_array_grow_func(void **arr_p,
void *_##arr##_static = NULL
/**
- * this will use stack space, up to maxstatic array elements, before
- * switching to dynamic heap allocation */
+ * This will use stack space, up to `maxstatic` array elements,
+ * before switching to dynamic heap allocation.
+ */
#define BLI_array_staticdeclare(arr, maxstatic) \
int _##arr##_len = 0; \
char _##arr##_static[maxstatic * sizeof(*(arr))]
@@ -77,7 +82,8 @@ void _bli_array_grow_func(void **arr_p,
* Grow the array by a fixed number of items.
*
* Allow for a large 'num' value when the new size is more than double
- * to allocate the exact sized array. */
+ * to allocate the exact sized array.
+ */
#define BLI_array_reserve(arr, num) \
(void)((((void *)(arr) == NULL) && \
((void *)(_##arr##_static) != \
@@ -95,12 +101,16 @@ void _bli_array_grow_func(void **arr_p,
num, \
"BLI_array." #arr)))
-/** returns length of array */
+/**
+ * Returns length of array.
+ */
#define BLI_array_grow_items(arr, num) (BLI_array_reserve(arr, num), (_##arr##_len += num))
#define BLI_array_grow_one(arr) BLI_array_grow_items(arr, 1)
-/** appends an item to the array. */
+/**
+ * Appends an item to the array.
+ */
#define BLI_array_append(arr, item) \
((void)BLI_array_grow_one(arr), (void)(arr[_##arr##_len - 1] = item))
@@ -111,7 +121,9 @@ void _bli_array_grow_func(void **arr_p,
#define BLI_array_append_r(arr, item) \
((void)BLI_array_grow_one(arr), (void)(arr[_##arr##_len - 1] = item), (&arr[_##arr##_len - 1]))
-/** appends (grows) & returns a pointer to the uninitialized memory */
+/**
+ * Appends (grows) & returns a pointer to the uninitialized memory.
+ */
#define BLI_array_append_ret(arr) (BLI_array_reserve(arr, 1), &arr[(_##arr##_len++)])
#define BLI_array_free(arr) \
@@ -127,7 +139,8 @@ void _bli_array_grow_func(void **arr_p,
/**
* Resets the logical size of an array to zero, but doesn't
- * free the memory. */
+ * free the memory.
+ */
#define BLI_array_clear(arr) \
{ \
_##arr##_len = 0; \
@@ -135,30 +148,32 @@ void _bli_array_grow_func(void **arr_p,
((void)0)
/**
- * Set the length of the array, doesn't actually increase the allocated array
- * size. don't use this unless you know what you're doing. */
+ * Set the length of the array, doesn't actually increase the allocated array size.
+ * Don't use this unless you know what you're doing.
+ */
#define BLI_array_len_set(arr, len) \
{ \
_##arr##_len = (len); \
} \
((void)0)
-/** only to prevent unused warnings */
+/**
+ * Only to prevent unused warnings.
+ */
#define BLI_array_fake_user(arr) ((void)_##arr##_len, (void)_##arr##_static)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Generic Array Utils
- * other useful defines
- * (unrelated to the main array macros)
*
+ * Other useful defines (unrelated to the main array macros).
* \{ */
/**
- * Not part of the 'API' but handy functions,
- * same purpose as #BLI_array_staticdeclare()
- * but use when the max size is known ahead of time */
+ * Not part of the 'API' but handy functions, same purpose as #BLI_array_staticdeclare()
+ * but use when the max size is known ahead of time.
+ */
#define BLI_array_fixedstack_declare(arr, maxstatic, realsize, allocstr) \
char _##arr##_static[maxstatic * sizeof(*(arr))]; \
const bool _##arr##_is_static = ((void *)_##arr##_static) != \
diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh
index 352bf379d4d..80464499634 100644
--- a/source/blender/blenlib/BLI_array.hh
+++ b/source/blender/blenlib/BLI_array.hh
@@ -31,7 +31,7 @@
*
* A main benefit of using Array over Vector is that it expresses the intent of the developer
* better. It indicates that the size of the data structure is not expected to change. Furthermore,
- * you can be more certain that an array does not overallocate.
+ * you can be more certain that an array does not over-allocate.
*
* blender::Array supports small object optimization to improve performance when the size turns out
* to be small at run-time.
@@ -100,7 +100,7 @@ class Array {
/**
* Create a new array that contains copies of all values.
*/
- template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
Array(Span<U> values, Allocator allocator = {}) : Array(NoExceptConstructor(), allocator)
{
const int64_t size = values.size();
@@ -112,7 +112,7 @@ class Array {
/**
* Create a new array that contains copies of all values.
*/
- template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
Array(const std::initializer_list<U> &values, Allocator allocator = {})
: Array(Span<U>(values), allocator)
{
@@ -230,13 +230,13 @@ class Array {
return MutableSpan<T>(data_, size_);
}
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
operator Span<U>() const
{
return Span<U>(data_, size_);
}
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
operator MutableSpan<U>()
{
return MutableSpan<U>(data_, size_);
diff --git a/source/blender/blenlib/BLI_array_store.h b/source/blender/blenlib/BLI_array_store.h
index 78d718117ba..68928f53e55 100644
--- a/source/blender/blenlib/BLI_array_store.h
+++ b/source/blender/blenlib/BLI_array_store.h
@@ -28,25 +28,88 @@ extern "C" {
typedef struct BArrayState BArrayState;
typedef struct BArrayStore BArrayStore;
+/**
+ * Create a new array store, which can store any number of arrays
+ * as long as their stride matches.
+ *
+ * \param stride: `sizeof()` each element,
+ *
+ * \note while a stride of `1` will always work,
+ * its less efficient since duplicate chunks of memory will be searched
+ * at positions unaligned with the array data.
+ *
+ * \param chunk_count: Number of elements to split each chunk into.
+ * - A small value increases the ability to de-duplicate chunks,
+ * but adds overhead by increasing the number of chunks to look up when searching for duplicates,
+ * as well as some overhead constructing the original array again, with more calls to `memcpy`.
+ * - Larger values reduce the *book keeping* overhead,
+ * but increase the chance a small,
+ * isolated change will cause a larger amount of data to be duplicated.
+ *
+ * \return A new array store, to be freed with #BLI_array_store_destroy.
+ */
BArrayStore *BLI_array_store_create(unsigned int stride, unsigned int chunk_count);
+/**
+ * Free the #BArrayStore, including all states and chunks.
+ */
void BLI_array_store_destroy(BArrayStore *bs);
+/**
+ * Clear all contents, allowing reuse of \a bs.
+ */
void BLI_array_store_clear(BArrayStore *bs);
-/* find the memory used by all states (expanded & real) */
+/**
+ * Find the memory used by all states (expanded & real).
+ *
+ * \return the total amount of memory that would be used by getting the arrays for all states.
+ */
size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs);
+/**
+ * \return the amount of memory used by all #BChunk.data
+ * (duplicate chunks are only counted once).
+ */
size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs);
+/**
+ *
+ * \param data: Data used to create
+ * \param state_reference: The state to use as a reference when adding the new state,
+ * typically this is the previous state,
+ * however it can be any previously created state from this \a bs.
+ *
+ * \return The new state,
+ * which is used by the caller as a handle to get back the contents of \a data.
+ * This may be removed using #BLI_array_store_state_remove,
+ * otherwise it will be removed with #BLI_array_store_destroy.
+ */
BArrayState *BLI_array_store_state_add(BArrayStore *bs,
const void *data,
- const size_t data_len,
+ size_t data_len,
const BArrayState *state_reference);
+/**
+ * Remove a state and free any unused #BChunk data.
+ *
+ * The states can be freed in any order.
+ */
void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state);
+/**
+ * \return the expanded size of the array,
+ * use this to know how much memory to allocate #BLI_array_store_state_data_get's argument.
+ */
size_t BLI_array_store_state_size_get(BArrayState *state);
+/**
+ * Fill in existing allocated memory with the contents of \a state.
+ */
void BLI_array_store_state_data_get(BArrayState *state, void *data);
+/**
+ * Allocate an array for \a state and return it.
+ */
void *BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len);
-/* only for tests */
+/**
+ * \note Only for tests.
+ */
bool BLI_array_store_is_valid(BArrayStore *bs);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_array_store_utils.h b/source/blender/blenlib/BLI_array_store_utils.h
index 771f4f962a7..01d7f8804ab 100644
--- a/source/blender/blenlib/BLI_array_store_utils.h
+++ b/source/blender/blenlib/BLI_array_store_utils.h
@@ -32,10 +32,10 @@ struct BArrayStore_AtSize {
};
BArrayStore *BLI_array_store_at_size_ensure(struct BArrayStore_AtSize *bs_stride,
- const int stride,
- const int chunk_size);
+ int stride,
+ int chunk_size);
-BArrayStore *BLI_array_store_at_size_get(struct BArrayStore_AtSize *bs_stride, const int stride);
+BArrayStore *BLI_array_store_at_size_get(struct BArrayStore_AtSize *bs_stride, int stride);
void BLI_array_store_at_size_clear(struct BArrayStore_AtSize *bs_stride);
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index 52d41173a0e..202ae9a9786 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -28,26 +28,60 @@
extern "C" {
#endif
+/**
+ * In-place array reverse.
+ *
+ * Access via #BLI_array_reverse
+ */
void _bli_array_reverse(void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_reverse(arr, arr_len) _bli_array_reverse(arr, arr_len, sizeof(*(arr)))
+/**
+ * In-place array wrap.
+ * (rotate the array one step forward or backwards).
+ *
+ * Access via #BLI_array_wrap
+ */
void _bli_array_wrap(void *arr, uint arr_len, size_t arr_stride, int dir);
#define BLI_array_wrap(arr, arr_len, dir) _bli_array_wrap(arr, arr_len, sizeof(*(arr)), dir)
+/**
+ *In-place array permute.
+ * (re-arrange elements based on an array of indices).
+ *
+ * Access via #BLI_array_wrap
+ */
void _bli_array_permute(
- void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp);
+ void *arr, uint arr_len, size_t arr_stride, const uint *order, void *arr_temp);
#define BLI_array_permute(arr, arr_len, order) \
_bli_array_permute(arr, arr_len, sizeof(*(arr)), order, NULL)
#define BLI_array_permute_ex(arr, arr_len, order, arr_temp) \
_bli_array_permute(arr, arr_len, sizeof(*(arr)), order, arr_temp)
+/**
+ * In-place array de-duplication of an ordered array.
+ *
+ * \return The new length of the array.
+ *
+ * Access via #BLI_array_deduplicate_ordered
+ */
uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_deduplicate_ordered(arr, arr_len) \
_bli_array_deduplicate_ordered(arr, arr_len, sizeof(*(arr)))
+/**
+ * Find the first index of an item in an array.
+ *
+ * Access via #BLI_array_findindex
+ *
+ * \note Not efficient, use for error checks/asserts.
+ */
int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p);
#define BLI_array_findindex(arr, arr_len, p) _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p)
+/**
+ * A version of #BLI_array_findindex that searches from the end of the list.
+ */
int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p);
#define BLI_array_rfindindex(arr, arr_len, p) \
_bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p)
@@ -66,6 +100,22 @@ void _bli_array_binary_or(
CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_b)), \
_bli_array_binary_or(arr, arr_a, arr_b, arr_len, sizeof(*(arr))))
+/**
+ * Utility function to iterate over contiguous items in an array.
+ *
+ * \param use_wrap: Detect contiguous ranges across the first/last points.
+ * In this case the second index of \a span_step may be lower than the first,
+ * which indicates the values are wrapped.
+ * \param use_delimit_bounds: When false,
+ * ranges that defined by the start/end indices are excluded.
+ * This option has no effect when \a use_wrap is enabled.
+ * \param test_fn: Function to test if the item should be included in the range.
+ * \param user_data: User data for \a test_fn.
+ * \param span_step: Indices to iterate over,
+ * initialize both values to the array length to initialize iteration.
+ * \param r_span_len: The length of the span, useful when \a use_wrap is enabled,
+ * where calculating the length isn't a simple subtraction.
+ */
bool _bli_array_iter_span(const void *arr,
uint arr_len,
size_t arr_stride,
@@ -87,12 +137,22 @@ bool _bli_array_iter_span(const void *arr,
span_step, \
r_span_len)
+/**
+ * Simple utility to check memory is zeroed.
+ */
bool _bli_array_is_zeroed(const void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_is_zeroed(arr, arr_len) _bli_array_is_zeroed(arr, arr_len, sizeof(*(arr)))
+/**
+ * Smart function to sample a rectangle spiraling outside.
+ * Nice for selection ID.
+ *
+ * \param arr_shape: dimensions [w, h].
+ * \param center: coordinates [x, y] indicating where to start traversing.
+ */
bool _bli_array_iter_spiral_square(const void *arr_v,
const int arr_shape[2],
- const size_t elem_size,
+ size_t elem_size,
const int center[2],
bool (*test_fn)(const void *arr_item, void *user_data),
void *user_data);
diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h
index fbdd3456d6b..71b00b77998 100644
--- a/source/blender/blenlib/BLI_assert.h
+++ b/source/blender/blenlib/BLI_assert.h
@@ -30,11 +30,12 @@ extern "C" {
#endif
/* Utility functions. */
-void _BLI_assert_print_pos(const char *file, const int line, const char *function, const char *id);
+
+void _BLI_assert_print_pos(const char *file, int line, const char *function, const char *id);
void _BLI_assert_print_extra(const char *str);
void _BLI_assert_print_backtrace(void);
void _BLI_assert_abort(void);
-void _BLI_assert_unreachable_print(const char *file, const int line, const char *function);
+void _BLI_assert_unreachable_print(const char *file, int line, const char *function);
#ifdef _MSC_VER
# include <crtdbg.h> /* for _STATIC_ASSERT */
diff --git a/source/blender/blenlib/BLI_astar.h b/source/blender/blenlib/BLI_astar.h
index fe5c4ddad69..26b45f1ebe6 100644
--- a/source/blender/blenlib/BLI_astar.h
+++ b/source/blender/blenlib/BLI_astar.h
@@ -76,18 +76,49 @@ typedef struct BLI_AStarGraph {
struct MemArena *mem; /* Memory arena. */
} BLI_AStarGraph;
-void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data);
-void BLI_astar_node_link_add(BLI_AStarGraph *as_graph,
- const int node1_index,
- const int node2_index,
- const float cost,
- void *custom_data);
-int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, const int idx);
+/**
+ * Initialize a node in A* graph.
+ *
+ * \param custom_data: an opaque pointer attached to this link,
+ * available e.g. to cost callback function.
+ */
+void BLI_astar_node_init(BLI_AStarGraph *as_graph, int node_index, void *custom_data);
+/**
+ * Add a link between two nodes of our A* graph.
+ *
+ * \param cost: The 'length' of the link
+ * (actual distance between two vertices or face centers e.g.).
+ * \param custom_data: An opaque pointer attached to this link,
+ * available e.g. to cost callback function.
+ */
+void BLI_astar_node_link_add(
+ BLI_AStarGraph *as_graph, int node1_index, int node2_index, float cost, void *custom_data);
+/**
+ * \return The index of the other node of given link.
+ */
+int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, int idx);
+/**
+ * Initialize a solution data for given A* graph. Does not compute anything!
+ *
+ * \param custom_data: an opaque pointer attached to this link, available e.g
+ * . to cost callback function.
+ *
+ * \note BLI_AStarSolution stores nearly all data needed during solution compute.
+ */
void BLI_astar_solution_init(BLI_AStarGraph *as_graph,
BLI_AStarSolution *as_solution,
void *custom_data);
+/**
+ * Clear given solution's data, but does not release its memory.
+ * Avoids having to recreate/allocate a memarena in loops, e.g.
+ *
+ * \note This *has to be called* between each path solving.
+ */
void BLI_astar_solution_clear(BLI_AStarSolution *as_solution);
+/**
+ * Release the memory allocated for this solution.
+ */
void BLI_astar_solution_free(BLI_AStarSolution *as_solution);
/**
@@ -104,18 +135,34 @@ void BLI_astar_solution_free(BLI_AStarSolution *as_solution);
typedef float (*astar_f_cost)(BLI_AStarGraph *as_graph,
BLI_AStarSolution *as_solution,
BLI_AStarGNLink *link,
- const int node_idx_curr,
- const int node_idx_next,
- const int node_idx_dst);
+ int node_idx_curr,
+ int node_idx_next,
+ int node_idx_dst);
-void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data);
+/**
+ * Initialize an A* graph. Total number of nodes must be known.
+ *
+ * Nodes might be e.g. vertices, faces, ... etc.
+ *
+ * \param custom_data: an opaque pointer attached to this link,
+ * available e.g. to cost callback function.
+ */
+void BLI_astar_graph_init(BLI_AStarGraph *as_graph, int node_num, void *custom_data);
void BLI_astar_graph_free(BLI_AStarGraph *as_graph);
+/**
+ * Solve a path in given graph, using given 'cost' callback function.
+ *
+ * \param max_steps: maximum number of nodes the found path may have.
+ * Useful in performance-critical usages.
+ * If no path is found within given steps, returns false too.
+ * \return true if a path was found, false otherwise.
+ */
bool BLI_astar_graph_solve(BLI_AStarGraph *as_graph,
- const int node_index_src,
- const int node_index_dst,
+ int node_index_src,
+ int node_index_dst,
astar_f_cost f_cost_cb,
BLI_AStarSolution *r_solution,
- const int max_steps);
+ int max_steps);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_bitmap.h b/source/blender/blenlib/BLI_bitmap.h
index c97be6eed3c..b5ef08e9e60 100644
--- a/source/blender/blenlib/BLI_bitmap.h
+++ b/source/blender/blenlib/BLI_bitmap.h
@@ -40,26 +40,38 @@ typedef unsigned int BLI_bitmap;
/* 0b11111 */
#define _BITMAP_MASK 31
-/* number of blocks needed to hold '_tot' bits */
+/**
+ * Number of blocks needed to hold '_tot' bits.
+ */
#define _BITMAP_NUM_BLOCKS(_tot) (((_tot) >> _BITMAP_POWER) + 1)
-/* size (in bytes) used to hold '_tot' bits */
+/**
+ * Size (in bytes) used to hold '_tot' bits.
+ */
#define BLI_BITMAP_SIZE(_tot) ((size_t)(_BITMAP_NUM_BLOCKS(_tot)) * sizeof(BLI_bitmap))
-/* allocate memory for a bitmap with '_tot' bits; free with MEM_freeN() */
+/**
+ * Allocate memory for a bitmap with '_tot' bits; free with MEM_freeN().
+ */
#define BLI_BITMAP_NEW(_tot, _alloc_string) \
((BLI_bitmap *)MEM_callocN(BLI_BITMAP_SIZE(_tot), _alloc_string))
-/* allocate a bitmap on the stack */
+/**
+ * Allocate a bitmap on the stack.
+ */
#define BLI_BITMAP_NEW_ALLOCA(_tot) \
((BLI_bitmap *)memset(alloca(BLI_BITMAP_SIZE(_tot)), 0, BLI_BITMAP_SIZE(_tot)))
-/* Allocate using given MemArena */
+/**
+ * Allocate using given MemArena.
+ */
#define BLI_BITMAP_NEW_MEMARENA(_mem, _tot) \
(CHECK_TYPE_INLINE(_mem, MemArena *), \
((BLI_bitmap *)BLI_memarena_calloc(_mem, BLI_BITMAP_SIZE(_tot))))
-/* get the value of a single bit at '_index' */
+/**
+ * Get the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_TEST(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] & (1u << ((_index)&_BITMAP_MASK))))
@@ -74,22 +86,30 @@ typedef unsigned int BLI_bitmap;
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
(BLI_BITMAP_TEST(_bitmap, _index) != 0))
-/* set the value of a single bit at '_index' */
+/**
+ * Set the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_ENABLE(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] |= (1u << ((_index)&_BITMAP_MASK))))
-/* clear the value of a single bit at '_index' */
+/**
+ * Clear the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_DISABLE(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] &= ~(1u << ((_index)&_BITMAP_MASK))))
-/* flip the value of a single bit at '_index' */
+/**
+ * Flip the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_FLIP(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] ^= (1u << ((_index)&_BITMAP_MASK))))
-/* set or clear the value of a single bit at '_index' */
+/**
+ * Set or clear the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_SET(_bitmap, _index, _set) \
{ \
CHECK_TYPE(_bitmap, BLI_bitmap *); \
@@ -102,7 +122,9 @@ typedef unsigned int BLI_bitmap;
} \
(void)0
-/* resize bitmap to have space for '_tot' bits */
+/**
+ * Resize bitmap to have space for '_tot' bits.
+ */
#define BLI_BITMAP_RESIZE(_bitmap, _tot) \
{ \
CHECK_TYPE(_bitmap, BLI_bitmap *); \
@@ -110,10 +132,25 @@ typedef unsigned int BLI_bitmap;
} \
(void)0
+/**
+ * Set or clear all bits in the bitmap.
+ */
void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits);
+/**
+ * Invert all bits in the bitmap.
+ */
void BLI_bitmap_flip_all(BLI_bitmap *bitmap, size_t bits);
+/**
+ * Copy all bits from one bitmap to another.
+ */
void BLI_bitmap_copy_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits);
+/**
+ * Combine two bitmaps with boolean AND.
+ */
void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits);
+/**
+ * Combine two bitmaps with boolean OR.
+ */
void BLI_bitmap_or_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_bitmap_draw_2d.h b/source/blender/blenlib/BLI_bitmap_draw_2d.h
index 8331d8fac08..3831ed3c9e7 100644
--- a/source/blender/blenlib/BLI_bitmap_draw_2d.h
+++ b/source/blender/blenlib/BLI_bitmap_draw_2d.h
@@ -24,23 +24,43 @@
extern "C" {
#endif
+/**
+ * Plot a line from \a p1 to \a p2 (inclusive).
+ *
+ * \note For clipped line drawing, see: http://stackoverflow.com/a/40902741/432509
+ */
void BLI_bitmap_draw_2d_line_v2v2i(const int p1[2],
const int p2[2],
bool (*callback)(int, int, void *),
void *user_data);
+/**
+ * \note Unclipped (clipped version can be added if needed).
+ */
void BLI_bitmap_draw_2d_tri_v2i(const int p1[2],
const int p2[2],
const int p3[2],
void (*callback)(int x, int x_end, int y, void *),
void *user_data);
-void BLI_bitmap_draw_2d_poly_v2i_n(const int xmin,
- const int ymin,
- const int xmax,
- const int ymax,
+/**
+ * Draws a filled polygon with support for self intersections.
+ *
+ * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive),
+ * note that \a x_end will always be greater than \a x, so we can use:
+ *
+ * \code{.c}
+ * do {
+ * func(x, y);
+ * } while (++x != x_end);
+ * \endcode
+ */
+void BLI_bitmap_draw_2d_poly_v2i_n(int xmin,
+ int ymin,
+ int xmax,
+ int ymax,
const int verts[][2],
- const int verts_len,
+ int verts_len,
void (*callback)(int x, int x_end, int y, void *),
void *user_data);
diff --git a/source/blender/blenlib/BLI_boxpack_2d.h b/source/blender/blenlib/BLI_boxpack_2d.h
index 7e347d0b0d7..eee1a0d3d41 100644
--- a/source/blender/blenlib/BLI_boxpack_2d.h
+++ b/source/blender/blenlib/BLI_boxpack_2d.h
@@ -44,7 +44,21 @@ typedef struct BoxPack {
int index;
} BoxPack;
-void BLI_box_pack_2d(BoxPack *boxarray, const unsigned int len, float *r_tot_x, float *r_tot_y);
+/**
+ * Main box-packing function accessed from other functions
+ * This sets boxes x,y to positive values, sorting from 0,0 outwards.
+ * There is no limit to the space boxes may take, only that they will be packed
+ * tightly into the lower left hand corner (0,0)
+ *
+ * \param boxarray: a pre-allocated array of boxes.
+ * only the 'box->x' and 'box->y' are set, 'box->w' and 'box->h' are used,
+ * 'box->index' is not used at all, the only reason its there
+ * is that the box array is sorted by area and programs need to be able
+ * to have some way of writing the boxes back to the original data.
+ * \param len: the number of boxes in the array.
+ * \param r_tot_x, r_tot_y: set so you can normalize the data.
+ */
+void BLI_box_pack_2d(BoxPack *boxarray, unsigned int len, float *r_tot_x, float *r_tot_y);
typedef struct FixedSizeBoxPack {
struct FixedSizeBoxPack *next, *prev;
@@ -52,6 +66,21 @@ typedef struct FixedSizeBoxPack {
int w, h;
} FixedSizeBoxPack;
+/**
+ * Packs boxes into a fixed area.
+ *
+ * Boxes and packed are linked lists containing structs that can be cast to
+ * #FixedSizeBoxPack (i.e. contains a #FixedSizeBoxPack as its first element).
+ * Boxes that were packed successfully are placed into *packed and removed from *boxes.
+ *
+ * The algorithm is a simplified version of https://github.com/TeamHypersomnia/rectpack2D.
+ * Better ones could be used, but for the current use case (packing Image tiles into GPU
+ * textures) this is fine.
+ *
+ * Note that packing efficiency depends on the order of the input boxes. Generally speaking,
+ * larger boxes should come first, though how exactly size is best defined (e.g. area, perimeter)
+ * depends on the particular application.
+ */
void BLI_box_pack_2d_fixedarea(struct ListBase *boxes,
int width,
int height,
diff --git a/source/blender/blenlib/BLI_buffer.h b/source/blender/blenlib/BLI_buffer.h
index 9d66fe9a14e..e79d44fd934 100644
--- a/source/blender/blenlib/BLI_buffer.h
+++ b/source/blender/blenlib/BLI_buffer.h
@@ -71,13 +71,25 @@ enum {
} \
(void)0
-/* Never decreases the amount of memory allocated */
-void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count);
+/**
+ * \note Never decreases the amount of memory allocated.
+ */
+void BLI_buffer_resize(BLI_Buffer *buffer, size_t new_count);
-/* Ensure size, throwing away old data, respecting BLI_BUFFER_USE_CALLOC */
-void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count);
+/**
+ * Ensure size, throwing away old data, respecting #BLI_BUFFER_USE_CALLOC.
+ *
+ * Similar to #BLI_buffer_resize, but use when the existing data can be:
+ * - Ignored (malloc'd).
+ * - Cleared (when #BLI_BUFFER_USE_CALLOC is set).
+ */
+void BLI_buffer_reinit(BLI_Buffer *buffer, size_t new_count);
-/* Append an array of elements. */
+/**
+ * Append an array of elements.
+ *
+ * Callers use #BLI_buffer_append_array.
+ */
void _bli_buffer_append_array(BLI_Buffer *buffer, void *data, size_t count);
#define BLI_buffer_append_array(buffer_, type_, data_, count_) \
{ \
@@ -87,7 +99,11 @@ void _bli_buffer_append_array(BLI_Buffer *buffer, void *data, size_t count);
} \
(void)0
-/* Does not free the buffer structure itself */
+/**
+ * Does not free the buffer structure itself.
+ *
+ * Callers use #BLI_buffer_free.
+ */
void _bli_buffer_free(BLI_Buffer *buffer);
#define BLI_buffer_free(name_) \
{ \
@@ -96,7 +112,9 @@ void _bli_buffer_free(BLI_Buffer *buffer);
} \
(void)0
-/* A buffer embedded in a struct. Using memcpy is allowed until first resize. */
+/**
+ * A buffer embedded in a struct. Using #memcpy is allowed until first resize.
+ */
#define BLI_buffer_field_init(name_, type_) \
{ \
memset(name_, 0, sizeof(*name_)); \
diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh
index d93bd7f6f76..deb1774a4c5 100644
--- a/source/blender/blenlib/BLI_color.hh
+++ b/source/blender/blenlib/BLI_color.hh
@@ -73,27 +73,27 @@ namespace blender {
* - Add non RGB spaces/storages ColorXyz.
*/
-/* Enumeration containing the different alpha modes. */
+/** Enumeration containing the different alpha modes. */
enum class eAlpha {
- /* Color and alpha are unassociated. */
+ /** Color and alpha are unassociated. */
Straight,
- /* Color and alpha are associated. */
+ /** Color and alpha are associated. */
Premultiplied,
};
std::ostream &operator<<(std::ostream &stream, const eAlpha &space);
-/* Enumeration containing internal spaces. */
+/** Enumeration containing internal spaces. */
enum class eSpace {
- /* Blender theme color space (sRGB). */
+ /** Blender theme color space (sRGB). */
Theme,
- /* Blender internal scene linear color space (maps to SceneReference role in OCIO). */
+ /** Blender internal scene linear color space (maps to scene_linear role in OCIO). */
SceneLinear,
- /* Blender internal scene linear color space compressed to be stored in 4 uint8_t. */
+ /** Blender internal scene linear color space compressed to be stored in 4 uint8_t. */
SceneLinearByteEncoded,
};
std::ostream &operator<<(std::ostream &stream, const eSpace &space);
-/* Template class to store RGBA values with different precision, space and alpha association. */
+/** Template class to store RGBA values with different precision, space and alpha association. */
template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGBA {
public:
ChannelStorageType r, g, b, a;
@@ -153,11 +153,13 @@ template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGB
};
/* Forward declarations of concrete color classes. */
+
template<eAlpha Alpha> class ColorSceneLinear4f;
template<eAlpha Alpha> class ColorSceneLinearByteEncoded4b;
template<typename ChannelStorageType> class ColorTheme4;
/* Forward declaration of precision conversion methods. */
+
BLI_INLINE ColorTheme4<float> BLI_color_convert_to_theme4f(const ColorTheme4<uint8_t> &srgb4b);
BLI_INLINE ColorTheme4<uint8_t> BLI_color_convert_to_theme4b(const ColorTheme4<float> &srgb4f);
@@ -354,6 +356,7 @@ BLI_color_convert_to_theme4b(const ColorSceneLinear4f<eAlpha::Straight> &scene_l
}
/* Internal roles. For convenience to shorten the type names and hide complexity. */
+
using ColorGeometry4f = ColorSceneLinear4f<eAlpha::Premultiplied>;
using ColorGeometry4b = ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied>;
diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h
index bd8f84cedd6..023fea3853e 100644
--- a/source/blender/blenlib/BLI_compiler_compat.h
+++ b/source/blender/blenlib/BLI_compiler_compat.h
@@ -34,7 +34,7 @@
#if (defined(__GNUC__) || defined(__clang__)) && defined(__cplusplus)
extern "C++" {
-/* Some magic to be sure we don't have reference in the type. */
+/** Some magic to be sure we don't have reference in the type. */
template<typename T> static inline T decltype_helper(T x)
{
return x;
diff --git a/source/blender/blenlib/BLI_convexhull_2d.h b/source/blender/blenlib/BLI_convexhull_2d.h
index e930117822f..77f3eedec95 100644
--- a/source/blender/blenlib/BLI_convexhull_2d.h
+++ b/source/blender/blenlib/BLI_convexhull_2d.h
@@ -24,10 +24,43 @@
extern "C" {
#endif
-int BLI_convexhull_2d_sorted(const float (*points)[2], const int n, int r_points[]);
-int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[]);
+/**
+ * A.M. Andrew's monotone chain 2D convex hull algorithm.
+ *
+ * \param points: An array of 2D points presorted by increasing x and y-coords.
+ * \param n: The number of points in points.
+ * \param r_points: An array of the convex hull vertex indices (max is n).
+ * \returns the number of points in r_points.
+ */
+int BLI_convexhull_2d_sorted(const float (*points)[2], int n, int r_points[]);
+/**
+ * A.M. Andrew's monotone chain 2D convex hull algorithm.
+ *
+ * \param points: An array of 2D points.
+ * \param n: The number of points in points.
+ * \param r_points: An array of the convex hull vertex indices (max is n).
+ * _must_ be allocated as `n * 2` because of how its used internally,
+ * even though the final result will be no more than \a n in size.
+ * \returns the number of points in r_points.
+ */
+int BLI_convexhull_2d(const float (*points)[2], int n, int r_points[]);
+/**
+ * \return The best angle for fitting the convex hull to an axis aligned bounding box.
+ *
+ * Intended to be used with #BLI_convexhull_2d
+ *
+ * \param points_hull: Ordered hull points
+ * (result of #BLI_convexhull_2d mapped to a contiguous array).
+ *
+ * \note we could return the index of the best edge too if its needed.
+ */
float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned int n);
+/**
+ * Wrap #BLI_convexhull_aabb_fit_hull_2d and do the convex hull calculation.
+ *
+ * \param points: arbitrary 2d points.
+ */
float BLI_convexhull_aabb_fit_points_2d(const float (*points)[2], unsigned int n);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_delaunay_2d.h b/source/blender/blenlib/BLI_delaunay_2d.h
index 658dcadadce..1ee0be64cee 100644
--- a/source/blender/blenlib/BLI_delaunay_2d.h
+++ b/source/blender/blenlib/BLI_delaunay_2d.h
@@ -215,14 +215,14 @@ void BLI_delaunay_2d_cdt_free(CDT_result *result);
/* C++ Interface. */
# include "BLI_array.hh"
-# include "BLI_double2.hh"
# include "BLI_math_mpq.hh"
-# include "BLI_mpq2.hh"
+# include "BLI_math_vec_mpq_types.hh"
+# include "BLI_math_vec_types.hh"
# include "BLI_vector.hh"
namespace blender::meshintersect {
-/* vec2<Arith_t> is a 2d vector with Arith_t as the type for coordinates. */
+/** #vec2<Arith_t> is a 2d vector with #Arith_t as the type for coordinates. */
template<typename Arith_t> struct vec2_impl;
template<> struct vec2_impl<double> {
typedef double2 type;
diff --git a/source/blender/blenlib/BLI_dlrbTree.h b/source/blender/blenlib/BLI_dlrbTree.h
index 03aab8d2895..3cf849efaef 100644
--- a/source/blender/blenlib/BLI_dlrbTree.h
+++ b/source/blender/blenlib/BLI_dlrbTree.h
@@ -21,25 +21,26 @@
/** \file
* \ingroup bli
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Double-Linked Red-Black Tree Implementation:
+ *
+ * Double-Linked Red-Black Tree Implementation:
*
* This is simply a Red-Black Tree implementation whose nodes can later
* be arranged + retrieved as elements in a Double-Linked list (i.e. ListBase).
* The Red-Black Tree implementation is based on the methods defined by Wikipedia.
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* ********************************************** */
/* Data Types and Type Defines */
-/* Base Structs --------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Base Structs
+ * \{ */
-/* Basic Layout for a Node */
+/** Basic Layout for a Node. */
typedef struct DLRBT_Node {
/* ListBase capabilities */
struct DLRBT_Node *next, *prev;
@@ -52,7 +53,7 @@ typedef struct DLRBT_Node {
/* ... for nice alignment, next item should usually be a char too... */
} DLRBT_Node;
-/* Red/Black defines for tree_col */
+/** Red/Black defines for tree_col. */
typedef enum eDLRBT_Colors {
DLRBT_BLACK = 0,
DLRBT_RED,
@@ -60,7 +61,7 @@ typedef enum eDLRBT_Colors {
/* -------- */
-/* The Tree Data */
+/** The Tree Data. */
typedef struct DLRBT_Tree {
/* ListBase capabilities */
void *first, *last; /* these should be based on DLRBT_Node-s */
@@ -69,101 +70,150 @@ typedef struct DLRBT_Tree {
void *root; /* this should be based on DLRBT_Node-s */
} DLRBT_Tree;
-/* Callback Types --------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callback Types
+ * \{ */
-/* Return -1, 0, 1 for whether the given data is less than,
+/**
+ * Return -1, 0, 1 for whether the given data is less than,
* equal to, or greater than the given node.
- * - node: <DLRBT_Node> the node to compare to.
- * - data: pointer to the relevant data or values stored in the bit-pattern.
- * dependent on the function.
+ * \param node: <DLRBT_Node> the node to compare to.
+ * \param data: pointer to the relevant data or values stored in the bit-pattern.
+ * Dependent on the function.
*/
typedef short (*DLRBT_Comparator_FP)(void *node, void *data);
-/* Return a new node instance wrapping the given data
- * - data: Pointer to the relevant data to create a subclass of node from
+/**
+ * Return a new node instance wrapping the given data
+ * - data: Pointer to the relevant data to create a subclass of node from.
*/
typedef DLRBT_Node *(*DLRBT_NAlloc_FP)(void *data);
-/* Update an existing node instance accordingly to be in sync with the given data.
- * - node: <DLRBT_Node> the node to update.
- * - data: Pointer to the relevant data or values stored in the bit-pattern.
- * dependent on the function.
+/**
+ * Update an existing node instance accordingly to be in sync with the given data.
+ * \param node: <DLRBT_Node> the node to update.
+ * \param data: Pointer to the relevant data or values stored in the bit-pattern.
+ * Dependent on the function.
*/
typedef void (*DLRBT_NUpdate_FP)(void *node, void *data);
/* ********************************************** */
/* Public API */
-/* ADT Management ------------------------------- */
+/** \} */
-/* Create a new tree, and initialize as necessary */
+/* -------------------------------------------------------------------- */
+/** \name ADT Management
+ * \{ */
+
+/**
+ * Create a new tree, and initialize as necessary.
+ */
DLRBT_Tree *BLI_dlrbTree_new(void);
-/* Initializes some given trees */
+/**
+ * Initializes some given trees.
+ * Just zero out the pointers used.
+ */
void BLI_dlrbTree_init(DLRBT_Tree *tree);
-/* Free some tree */
+/**
+ * Free the given tree's data but not the tree itself.
+ */
void BLI_dlrbTree_free(DLRBT_Tree *tree);
-/* Make sure the tree's Double-Linked list representation is valid */
+/**
+ * Make sure the tree's Double-Linked list representation is valid.
+ */
void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree);
-/* Searching ------------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Tree Searching Utilities
+ * \{ */
-/* Find the node which matches or is the closest to the requested node */
+/**
+ * Find the node which matches or is the closest to the requested node.
+ */
DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
-/* Find the node which exactly matches the required data */
+/**
+ * Find the node which exactly matches the required data.
+ */
DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
-/* Find the node which occurs immediately before the best matching node */
+/**
+ * Find the node which occurs immediately before the best matching node.
+ */
DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
-/* Find the node which occurs immediately after the best matching node */
+/**
+ * Find the node which occurs immediately after the best matching node.
+ */
DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
-/* Check whether there is a node matching the requested node */
+/**
+ * Check whether there is a node matching the requested node.
+ */
short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data);
-/* Node Operations (Managed) --------------------- */
-/* These methods automate the process of adding/removing nodes from the BST,
- * using the supplied data and callbacks
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Operations (Managed)
+ * \{ */
+
+/**
+ * These methods automate the process of adding/removing nodes from the BST,
+ * using the supplied data and callbacks.
*/
-/* Add the given data to the tree, and return the node added */
-/* NOTE: for duplicates, the update_cb is called (if available),
- * and the existing node is returned. */
+/**
+ * Add the given data to the tree, and return the node added.
+ * \note for duplicates, the update_cb is called (if available),
+ * and the existing node is returned.
+ */
DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
DLRBT_NAlloc_FP new_cb,
DLRBT_NUpdate_FP update_cb,
void *data);
-/* Remove the given element from the tree and balance again */
-/* FIXME: this is not implemented yet... */
+/* FIXME: this is not implemented yet. */
+/**
+ * Remove the given element from the tree and balance again.
+ */
// void BLI_dlrbTree_remove(DLRBT_Tree *tree, DLRBT_Node *node);
-/* Node Operations (Manual) --------------------- */
-/* These methods require custom code for creating BST nodes and adding them to the
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Operations (Manual)
+ *
+ * These methods require custom code for creating BST nodes and adding them to the
* tree in special ways, such that the node can then be balanced.
*
- * It is recommended that these methods are only used where the other method is too cumbersome...
- */
+ * It is recommended that these methods are only used where the other method is too cumbersome.
+ * \{ */
-/* Balance the tree after the given node has been added to it
+/**
+ * Balance the tree after the given node has been added to it
* (using custom code, in the Binary Tree way).
*/
void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node);
-/* ********************************************** */
+/** \} */
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_double2.hh b/source/blender/blenlib/BLI_double2.hh
deleted file mode 100644
index 0abff01ab2f..00000000000
--- a/source/blender/blenlib/BLI_double2.hh
+++ /dev/null
@@ -1,143 +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.
- */
-
-#pragma once
-
-/** \file
- * \ingroup bli
- */
-
-#include "BLI_double3.hh"
-
-namespace blender {
-
-struct double2 {
- double x, y;
-
- double2() = default;
-
- double2(const double *ptr) : x{ptr[0]}, y{ptr[1]}
- {
- }
-
- double2(double x, double y) : x(x), y(y)
- {
- }
-
- double2(const double3 &other) : x(other.x), y(other.y)
- {
- }
-
- operator double *()
- {
- return &x;
- }
-
- operator const double *() const
- {
- return &x;
- }
-
- double length() const
- {
- return len_v2_db(*this);
- }
-
- friend double2 operator+(const double2 &a, const double2 &b)
- {
- return {a.x + b.x, a.y + b.y};
- }
-
- friend double2 operator-(const double2 &a, const double2 &b)
- {
- return {a.x - b.x, a.y - b.y};
- }
-
- friend double2 operator*(const double2 &a, double b)
- {
- return {a.x * b, a.y * b};
- }
-
- friend double2 operator/(const double2 &a, double b)
- {
- BLI_assert(b != 0.0);
- return {a.x / b, a.y / b};
- }
-
- friend double2 operator*(double a, const double2 &b)
- {
- return b * a;
- }
-
- friend bool operator==(const double2 &a, const double2 &b)
- {
- return a.x == b.x && a.y == b.y;
- }
-
- friend bool operator!=(const double2 &a, const double2 &b)
- {
- return a.x != b.x || a.y != b.y;
- }
-
- friend std::ostream &operator<<(std::ostream &stream, const double2 &v)
- {
- stream << "(" << v.x << ", " << v.y << ")";
- return stream;
- }
-
- static double dot(const double2 &a, const double2 &b)
- {
- return a.x * b.x + a.y * b.y;
- }
-
- static double2 interpolate(const double2 &a, const double2 &b, double t)
- {
- return a * (1 - t) + b * t;
- }
-
- static double2 abs(const double2 &a)
- {
- return double2(fabs(a.x), fabs(a.y));
- }
-
- static double distance(const double2 &a, const double2 &b)
- {
- return (a - b).length();
- }
-
- static double distance_squared(const double2 &a, const double2 &b)
- {
- double2 diff = a - b;
- return double2::dot(diff, diff);
- }
-
- struct isect_result {
- enum {
- LINE_LINE_COLINEAR = -1,
- LINE_LINE_NONE = 0,
- LINE_LINE_EXACT = 1,
- LINE_LINE_CROSS = 2,
- } kind;
- double lambda;
- };
-
- static isect_result isect_seg_seg(const double2 &v1,
- const double2 &v2,
- const double2 &v3,
- const double2 &v4);
-};
-
-} // namespace blender
diff --git a/source/blender/blenlib/BLI_double3.hh b/source/blender/blenlib/BLI_double3.hh
deleted file mode 100644
index ab258c9121b..00000000000
--- a/source/blender/blenlib/BLI_double3.hh
+++ /dev/null
@@ -1,246 +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.
- */
-
-#pragma once
-
-/** \file
- * \ingroup bli
- */
-
-#include <iostream>
-
-#include "BLI_math_vector.h"
-#include "BLI_span.hh"
-
-namespace blender {
-
-struct double3 {
- double x, y, z;
-
- double3() = default;
-
- double3(const double *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]}
- {
- }
-
- double3(const double (*ptr)[3]) : double3((const double *)ptr)
- {
- }
-
- explicit double3(double value) : x(value), y(value), z(value)
- {
- }
-
- explicit double3(int value) : x(value), y(value), z(value)
- {
- }
-
- double3(double x, double y, double z) : x{x}, y{y}, z{z}
- {
- }
-
- operator const double *() const
- {
- return &x;
- }
-
- operator double *()
- {
- return &x;
- }
-
- double normalize_and_get_length()
- {
- return normalize_v3_db(*this);
- }
-
- double3 normalized() const
- {
- double3 result;
- normalize_v3_v3_db(result, *this);
- return result;
- }
-
- double length() const
- {
- return len_v3_db(*this);
- }
-
- double length_squared() const
- {
- return len_squared_v3_db(*this);
- }
-
- void reflect(const double3 &normal)
- {
- *this = this->reflected(normal);
- }
-
- double3 reflected(const double3 &normal) const
- {
- double3 result;
- reflect_v3_v3v3_db(result, *this, normal);
- return result;
- }
-
- static double3 safe_divide(const double3 &a, const double3 &b)
- {
- double3 result;
- result.x = (b.x == 0.0) ? 0.0 : a.x / b.x;
- result.y = (b.y == 0.0) ? 0.0 : a.y / b.y;
- result.z = (b.z == 0.0) ? 0.0 : a.z / b.z;
- return result;
- }
-
- void invert()
- {
- x = -x;
- y = -y;
- z = -z;
- }
-
- friend double3 operator+(const double3 &a, const double3 &b)
- {
- return {a.x + b.x, a.y + b.y, a.z + b.z};
- }
-
- void operator+=(const double3 &b)
- {
- this->x += b.x;
- this->y += b.y;
- this->z += b.z;
- }
-
- friend double3 operator-(const double3 &a, const double3 &b)
- {
- return {a.x - b.x, a.y - b.y, a.z - b.z};
- }
-
- friend double3 operator-(const double3 &a)
- {
- return {-a.x, -a.y, -a.z};
- }
-
- void operator-=(const double3 &b)
- {
- this->x -= b.x;
- this->y -= b.y;
- this->z -= b.z;
- }
-
- void operator*=(const double &scalar)
- {
- this->x *= scalar;
- this->y *= scalar;
- this->z *= scalar;
- }
-
- void operator*=(const double3 &other)
- {
- this->x *= other.x;
- this->y *= other.y;
- this->z *= other.z;
- }
-
- friend double3 operator*(const double3 &a, const double3 &b)
- {
- return {a.x * b.x, a.y * b.y, a.z * b.z};
- }
-
- friend double3 operator*(const double3 &a, const double &b)
- {
- return {a.x * b, a.y * b, a.z * b};
- }
-
- friend double3 operator*(const double &a, const double3 &b)
- {
- return b * a;
- }
-
- friend double3 operator/(const double3 &a, const double &b)
- {
- BLI_assert(b != 0.0);
- return {a.x / b, a.y / b, a.z / b};
- }
-
- friend bool operator==(const double3 &a, const double3 &b)
- {
- return a.x == b.x && a.y == b.y && a.z == b.z;
- }
-
- friend bool operator!=(const double3 &a, const double3 &b)
- {
- return a.x != b.x || a.y != b.y || a.z != b.z;
- }
-
- friend std::ostream &operator<<(std::ostream &stream, const double3 &v)
- {
- stream << "(" << v.x << ", " << v.y << ", " << v.z << ")";
- return stream;
- }
-
- static double dot(const double3 &a, const double3 &b)
- {
- return a.x * b.x + a.y * b.y + a.z * b.z;
- }
-
- static double3 cross_high_precision(const double3 &a, const double3 &b)
- {
- double3 result;
- cross_v3_v3v3_db(result, a, b);
- return result;
- }
-
- static double3 project(const double3 &a, const double3 &b)
- {
- double3 result;
- project_v3_v3v3_db(result, a, b);
- return result;
- }
-
- static double distance(const double3 &a, const double3 &b)
- {
- return (a - b).length();
- }
-
- static double distance_squared(const double3 &a, const double3 &b)
- {
- double3 diff = a - b;
- return double3::dot(diff, diff);
- }
-
- static double3 interpolate(const double3 &a, const double3 &b, double t)
- {
- return a * (1 - t) + b * t;
- }
-
- static double3 abs(const double3 &a)
- {
- return double3(fabs(a.x), fabs(a.y), fabs(a.z));
- }
-
- static int dominant_axis(const double3 &a)
- {
- double x = (a.x >= 0) ? a.x : -a.x;
- double y = (a.y >= 0) ? a.y : -a.y;
- double z = (a.z >= 0) ? a.z : -a.z;
- return ((x > y) ? ((x > z) ? 0 : 2) : ((y > z) ? 1 : 2));
- }
-
- static double3 cross_poly(Span<double3> poly);
-};
-
-} // namespace blender
diff --git a/source/blender/blenlib/BLI_dynstr.h b/source/blender/blenlib/BLI_dynstr.h
index 4df773c7cc6..90d93f29bcb 100644
--- a/source/blender/blenlib/BLI_dynstr.h
+++ b/source/blender/blenlib/BLI_dynstr.h
@@ -39,25 +39,85 @@ extern "C" {
struct DynStr;
-/** The abstract DynStr type */
+/** The abstract DynStr type. */
typedef struct DynStr DynStr;
+/**
+ * Create a new #DynStr.
+ *
+ * \return Pointer to a new #DynStr.
+ */
DynStr *BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Create a new #DynStr.
+ *
+ * \return Pointer to a new #DynStr.
+ */
DynStr *BLI_dynstr_new_memarena(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Append a c-string to a #DynStr.
+ *
+ * \param ds: The #DynStr to append to.
+ * \param cstr: The c-string to append.
+ */
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL();
+/**
+ * Append a length clamped c-string to a #DynStr.
+ *
+ * \param ds: The #DynStr to append to.
+ * \param cstr: The c-string to append.
+ * \param len: The maximum length of the c-string to copy.
+ */
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATTR_NONNULL();
+/**
+ * Append a c-string to a #DynStr, but with formatting like `printf`.
+ *
+ * \param ds: The #DynStr to append to.
+ * \param format: The `printf` format string to use.
+ */
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...)
ATTR_PRINTF_FORMAT(2, 3) ATTR_NONNULL(1, 2);
void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, va_list args)
ATTR_PRINTF_FORMAT(2, 0) ATTR_NONNULL(1, 2);
+/**
+ * Find the length of a #DynStr.
+ *
+ * \param ds: The #DynStr of interest.
+ * \return The length of \a ds.
+ */
int BLI_dynstr_get_len(const DynStr *ds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Get a #DynStr's contents as a c-string.
+ * \return The c-string which must be freed using #MEM_freeN.
+ *
+ * \param ds: The #DynStr of interest.
+ * \return The contents of \a ds as a c-string.
+ */
char *BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Get a #DynStr's contents as a c-string.
+ * The \a rets argument must be allocated to be at
+ * least the size of `BLI_dynstr_get_len(ds) + 1`.
+ *
+ * \param ds: The DynStr of interest.
+ * \param rets: The string to fill.
+ */
void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict rets) ATTR_NONNULL();
+/**
+ * Clear the #DynStr
+ *
+ * \param ds: The DynStr to clear.
+ */
void BLI_dynstr_clear(DynStr *ds) ATTR_NONNULL();
+/**
+ * Free the #DynStr
+ *
+ * \param ds: The DynStr to free.
+ */
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL();
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_edgehash.h b/source/blender/blenlib/BLI_edgehash.h
index 41f0d41d1e0..26eb8ab7665 100644
--- a/source/blender/blenlib/BLI_edgehash.h
+++ b/source/blender/blenlib/BLI_edgehash.h
@@ -48,42 +48,120 @@ typedef struct EdgeHashIterator {
typedef void (*EdgeHashFreeFP)(void *key);
enum {
- EDGEHASH_FLAG_ALLOW_DUPES = (1 << 0), /* only checked for in debug mode */
+ /**
+ * Only checked for in debug mode.
+ */
+ EDGEHASH_FLAG_ALLOW_DUPES = (1 << 0),
};
-EdgeHash *BLI_edgehash_new_ex(const char *info, const unsigned int nentries_reserve);
+EdgeHash *BLI_edgehash_new_ex(const char *info, unsigned int nentries_reserve);
EdgeHash *BLI_edgehash_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP free_value);
void BLI_edgehash_print(EdgeHash *eh);
+/**
+ * Insert edge (\a v0, \a v1) into hash with given value, does
+ * not check for duplicates.
+ */
void BLI_edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val);
+/**
+ * Assign a new value to a key that may already be in edgehash.
+ */
bool BLI_edgehash_reinsert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val);
+/**
+ * Return value for given edge (\a v0, \a v1), or NULL if
+ * if key does not exist in hash. (If need exists
+ * to differentiate between key-value being NULL and
+ * lack of key then see #BLI_edgehash_lookup_p().
+ */
void *BLI_edgehash_lookup(const EdgeHash *eh,
unsigned int v0,
unsigned int v1) ATTR_WARN_UNUSED_RESULT;
+/**
+ * A version of #BLI_edgehash_lookup which accepts a fallback argument.
+ */
void *BLI_edgehash_lookup_default(const EdgeHash *eh,
unsigned int v0,
unsigned int v1,
void *default_value) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return pointer to value for given edge (\a v0, \a v1),
+ * or NULL if key does not exist in hash.
+ */
void **BLI_edgehash_lookup_p(EdgeHash *eh,
unsigned int v0,
unsigned int v1) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Ensure \a (v0, v1) is exists in \a eh.
+ *
+ * This handles the common situation where the caller needs ensure a key is added to \a eh,
+ * constructing a new value in the case the key isn't found.
+ * Otherwise use the existing value.
+ *
+ * Such situations typically incur multiple lookups, however this function
+ * avoids them by ensuring the key is added,
+ * returning a pointer to the value so it can be used or initialized by the caller.
+ *
+ * \return true when the value didn't need to be added.
+ * (when false, the caller _must_ initialize the value).
+ */
bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val)
ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove \a key (v0, v1) from \a eh, or return false if the key wasn't found.
+ *
+ * \param v0, v1: The key to remove.
+ * \param free_value: Optional callback to free the value.
+ * \return true if \a key was removed from \a eh.
+ */
bool BLI_edgehash_remove(EdgeHash *eh,
unsigned int v0,
unsigned int v1,
EdgeHashFreeFP free_value);
+/**
+ * Remove \a key (v0, v1) from \a eh, returning the value or NULL if the key wasn't found.
+ *
+ * \param v0, v1: The key to remove.
+ * \return the value of \a key int \a eh or NULL.
+ */
void *BLI_edgehash_popkey(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return boolean true/false if edge (v0,v1) in hash.
+ */
bool BLI_edgehash_haskey(const EdgeHash *eh,
unsigned int v0,
unsigned int v1) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return number of keys in hash.
+ */
int BLI_edgehash_len(const EdgeHash *eh) ATTR_WARN_UNUSED_RESULT;
-void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint reserve);
+/**
+ * Remove all edges from hash.
+ */
+void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, uint reserve);
+/**
+ * Wraps #BLI_edgehash_clear_ex with zero entries reserved.
+ */
void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value);
+/**
+ * Create a new #EdgeHashIterator. The hash table must not be mutated
+ * while the iterator is in use, and the iterator will step exactly
+ * #BLI_edgehash_len(eh) times before becoming done.
+ */
EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Initialize an already allocated #EdgeHashIterator. The hash table must not
+ * be mutated while the iterator is in use, and the iterator will
+ * step exactly BLI_edgehash_len(eh) times before becoming done.
+ *
+ * \param ehi: The #EdgeHashIterator to initialize.
+ * \param eh: The #EdgeHash to iterate over.
+ */
void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh);
+/**
+ * Free an #EdgeHashIterator.
+ */
void BLI_edgehashIterator_free(EdgeHashIterator *ehi);
BLI_INLINE void BLI_edgehashIterator_step(EdgeHashIterator *ehi)
@@ -129,11 +207,21 @@ typedef struct EdgeSetIterator {
uint index;
} EdgeSetIterator;
-EdgeSet *BLI_edgeset_new_ex(const char *info, const unsigned int nentries_reserve)
- ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+EdgeSet *BLI_edgeset_new_ex(const char *info,
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
EdgeSet *BLI_edgeset_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
int BLI_edgeset_len(const EdgeSet *es) ATTR_WARN_UNUSED_RESULT;
+/**
+ * A version of BLI_edgeset_insert which checks first if the key is in the set.
+ * \returns true if a new key has been added.
+ *
+ * \note #EdgeHash has no equivalent to this because typically the value would be different.
+ */
bool BLI_edgeset_add(EdgeSet *es, unsigned int v0, unsigned int v1);
+/**
+ * Adds the key to the set (no checks for unique keys!).
+ * Matching #BLI_edgehash_insert
+ */
void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1);
bool BLI_edgeset_haskey(const EdgeSet *es,
unsigned int v0,
@@ -141,6 +229,7 @@ bool BLI_edgeset_haskey(const EdgeSet *es,
void BLI_edgeset_free(EdgeSet *es);
/* rely on inline api for now */
+
EdgeSetIterator *BLI_edgesetIterator_new(EdgeSet *es);
void BLI_edgesetIterator_free(EdgeSetIterator *esi);
diff --git a/source/blender/blenlib/BLI_endian_switch.h b/source/blender/blenlib/BLI_endian_switch.h
index b512133b34c..c8257483616 100644
--- a/source/blender/blenlib/BLI_endian_switch.h
+++ b/source/blender/blenlib/BLI_endian_switch.h
@@ -30,6 +30,7 @@ extern "C" {
#endif
/* BLI_endian_switch_inline.h */
+
BLI_INLINE void BLI_endian_switch_int16(short *val) ATTR_NONNULL(1);
BLI_INLINE void BLI_endian_switch_uint16(unsigned short *val) ATTR_NONNULL(1);
BLI_INLINE void BLI_endian_switch_int32(int *val) ATTR_NONNULL(1);
@@ -40,14 +41,15 @@ BLI_INLINE void BLI_endian_switch_uint64(uint64_t *val) ATTR_NONNULL(1);
BLI_INLINE void BLI_endian_switch_double(double *val) ATTR_NONNULL(1);
/* endian_switch.c */
-void BLI_endian_switch_int16_array(short *val, const int size) ATTR_NONNULL(1);
-void BLI_endian_switch_uint16_array(unsigned short *val, const int size) ATTR_NONNULL(1);
-void BLI_endian_switch_int32_array(int *val, const int size) ATTR_NONNULL(1);
-void BLI_endian_switch_uint32_array(unsigned int *val, const int size) ATTR_NONNULL(1);
-void BLI_endian_switch_float_array(float *val, const int size) ATTR_NONNULL(1);
-void BLI_endian_switch_int64_array(int64_t *val, const int size) ATTR_NONNULL(1);
-void BLI_endian_switch_uint64_array(uint64_t *val, const int size) ATTR_NONNULL(1);
-void BLI_endian_switch_double_array(double *val, const int size) ATTR_NONNULL(1);
+
+void BLI_endian_switch_int16_array(short *val, int size) ATTR_NONNULL(1);
+void BLI_endian_switch_uint16_array(unsigned short *val, int size) ATTR_NONNULL(1);
+void BLI_endian_switch_int32_array(int *val, int size) ATTR_NONNULL(1);
+void BLI_endian_switch_uint32_array(unsigned int *val, int size) ATTR_NONNULL(1);
+void BLI_endian_switch_float_array(float *val, int size) ATTR_NONNULL(1);
+void BLI_endian_switch_int64_array(int64_t *val, int size) ATTR_NONNULL(1);
+void BLI_endian_switch_uint64_array(uint64_t *val, int size) ATTR_NONNULL(1);
+void BLI_endian_switch_double_array(double *val, int size) ATTR_NONNULL(1);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_endian_switch_inline.h b/source/blender/blenlib/BLI_endian_switch_inline.h
index ec4cfe4801a..31be7fd47e4 100644
--- a/source/blender/blenlib/BLI_endian_switch_inline.h
+++ b/source/blender/blenlib/BLI_endian_switch_inline.h
@@ -33,6 +33,7 @@ extern "C" {
* use bit shifting instead. */
/* *** 16 *** */
+
BLI_INLINE void BLI_endian_switch_int16(short *val)
{
BLI_endian_switch_uint16((unsigned short *)val);
@@ -48,6 +49,7 @@ BLI_INLINE void BLI_endian_switch_uint16(unsigned short *val)
}
/* *** 32 *** */
+
BLI_INLINE void BLI_endian_switch_int32(int *val)
{
BLI_endian_switch_uint32((unsigned int *)val);
@@ -67,6 +69,7 @@ BLI_INLINE void BLI_endian_switch_float(float *val)
}
/* *** 64 *** */
+
BLI_INLINE void BLI_endian_switch_int64(int64_t *val)
{
BLI_endian_switch_uint64((uint64_t *)val);
diff --git a/source/blender/blenlib/BLI_expr_pylike_eval.h b/source/blender/blenlib/BLI_expr_pylike_eval.h
index c074b5d8130..dccb1863b4b 100644
--- a/source/blender/blenlib/BLI_expr_pylike_eval.h
+++ b/source/blender/blenlib/BLI_expr_pylike_eval.h
@@ -41,13 +41,35 @@ typedef enum eExprPyLike_EvalStatus {
EXPR_PYLIKE_FATAL_ERROR,
} eExprPyLike_EvalStatus;
+/**
+ * Free the parsed data; NULL argument is ok.
+ */
void BLI_expr_pylike_free(struct ExprPyLike_Parsed *expr);
+/**
+ * Check if the parsing result is valid for evaluation.
+ */
bool BLI_expr_pylike_is_valid(struct ExprPyLike_Parsed *expr);
+/**
+ * Check if the parsed expression always evaluates to the same value.
+ */
bool BLI_expr_pylike_is_constant(struct ExprPyLike_Parsed *expr);
+/**
+ * Check if the parsed expression uses the parameter with the given index.
+ */
bool BLI_expr_pylike_is_using_param(struct ExprPyLike_Parsed *expr, int index);
+/**
+ * Compile the expression and return the result.
+ *
+ * Parse the expression for evaluation later.
+ * Returns non-NULL even on failure; use is_valid to check.
+ */
ExprPyLike_Parsed *BLI_expr_pylike_parse(const char *expression,
const char **param_names,
int param_names_len);
+/**
+ * Evaluate the expression with the given parameters.
+ * The order and number of parameters must match the names given to parse.
+ */
eExprPyLike_EvalStatus BLI_expr_pylike_eval(struct ExprPyLike_Parsed *expr,
const double *param_values,
int param_values_len,
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index 906a56ce909..28cb5f6d84b 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -45,19 +45,40 @@ extern "C" {
# define PATH_MAX 4096
#endif
-/* Common */
+/* -------------------------------------------------------------------- */
+/** \name Common
+ * \{ */
+/**
+ * Returns the st_mode from stat-ing the specified path name, or 0 if stat fails
+ * (most likely doesn't exist or no access).
+ */
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_copy(const char *file, const char *to) ATTR_NONNULL();
+/**
+ * \return zero on success (matching 'rename' behavior).
+ */
int BLI_rename(const char *from, const char *to) ATTR_NONNULL();
+/**
+ * Deletes the specified file or directory (depending on dir), optionally
+ * doing recursive delete of directory contents.
+ *
+ * \return zero on success (matching 'remove' behavior).
+ */
int BLI_delete(const char *file, bool dir, bool recursive) ATTR_NONNULL();
+/**
+ * Soft deletes the specified file or directory (depending on dir) by moving the files to the
+ * recycling bin, optionally doing recursive delete of directory contents.
+ *
+ * \return zero on success (matching 'remove' behavior).
+ */
int BLI_delete_soft(const char *file, const char **error_message) ATTR_NONNULL();
#if 0 /* Unused */
int BLI_move(const char *path, const char *to) ATTR_NONNULL();
int BLI_create_symlink(const char *path, const char *to) ATTR_NONNULL();
#endif
-/* keep in sync with the definition of struct direntry in BLI_fileops_types.h */
+/* Keep in sync with the definition of struct `direntry` in `BLI_fileops_types.h`. */
#ifdef WIN32
# if defined(_MSC_VER)
typedef struct _stat64 BLI_stat_t;
@@ -101,56 +122,131 @@ typedef enum eFileAttributes {
(FILE_ATTR_ALIAS | FILE_ATTR_REPARSE_POINT | FILE_ATTR_SYMLINK | FILE_ATTR_JUNCTION_POINT | \
FILE_ATTR_MOUNT_POINT | FILE_ATTR_HARDLINK)
-/* Directories */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Directories
+ * \{ */
struct direntry;
+/**
+ * Does the specified path point to a directory?
+ * \note Would be better in `fileops.c` except that it needs `stat.h` so add here.
+ */
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Does the specified path point to a non-directory?
+ */
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \return true on success (i.e. given path now exists on FS), false otherwise.
+ */
bool BLI_dir_create_recursive(const char *dir) ATTR_NONNULL();
+/**
+ * Returns the number of free bytes on the volume containing the specified pathname.
+ *
+ * \note Not actually used anywhere.
+ */
double BLI_dir_free_space(const char *dir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-char *BLI_current_working_dir(char *dir, const size_t maxncpy) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+/**
+ * Copies the current working directory into *dir (max size maxncpy), and
+ * returns a pointer to same.
+ *
+ * \note can return NULL when the size is not big enough
+ */
+char *BLI_current_working_dir(char *dir, size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
eFileAttributes BLI_file_attributes(const char *path);
-/* Filelist */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name File-List
+ * \{ */
+/**
+ * Scans the contents of the directory named *dirname, and allocates and fills in an
+ * array of entries describing them in *filelist.
+ *
+ * \return The length of filelist array.
+ */
unsigned int BLI_filelist_dir_contents(const char *dir, struct direntry **r_filelist);
+/**
+ * Deep-duplicate of a single direntry.
+ */
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src);
+/**
+ * Deep-duplicate of a #direntry array including the array itself.
+ */
void BLI_filelist_duplicate(struct direntry **dest_filelist,
struct direntry *const src_filelist,
- const unsigned int nrentries);
+ unsigned int nrentries);
+/**
+ * Frees storage for a single direntry, not the direntry itself.
+ */
void BLI_filelist_entry_free(struct direntry *entry);
-void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries);
+/**
+ * Frees storage for an array of #direntry, including the array itself.
+ */
+void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries);
+/**
+ * Convert given entry's size into human-readable strings.
+ */
void BLI_filelist_entry_size_to_string(const struct stat *st,
- const uint64_t sz,
- const bool compact,
+ uint64_t sz,
+ bool compact,
char r_size[FILELIST_DIRENTRY_SIZE_LEN]);
+/**
+ * Convert given entry's modes into human-readable strings.
+ */
void BLI_filelist_entry_mode_to_string(const struct stat *st,
- const bool compact,
+ bool compact,
char r_mode1[FILELIST_DIRENTRY_MODE_LEN],
char r_mode2[FILELIST_DIRENTRY_MODE_LEN],
char r_mode3[FILELIST_DIRENTRY_MODE_LEN]);
+/**
+ * Convert given entry's owner into human-readable strings.
+ */
void BLI_filelist_entry_owner_to_string(const struct stat *st,
- const bool compact,
+ bool compact,
char r_owner[FILELIST_DIRENTRY_OWNER_LEN]);
+/**
+ * Convert given entry's time into human-readable strings.
+ *
+ * \param r_is_today: optional, returns true if the date matches today's.
+ * \param r_is_yesterday: optional, returns true if the date matches yesterday's.
+ */
void BLI_filelist_entry_datetime_to_string(const struct stat *st,
- const int64_t ts,
- const bool compact,
+ int64_t ts,
+ bool compact,
char r_time[FILELIST_DIRENTRY_TIME_LEN],
char r_date[FILELIST_DIRENTRY_DATE_LEN],
bool *r_is_today,
bool *r_is_yesterday);
-/* Files */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Files
+ * \{ */
FILE *BLI_fopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void *BLI_gzopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_open(const char *filename, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_access(const char *filename, int mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true if the file with the specified name can be written.
+ * This implementation uses access(2), which makes the check according
+ * to the real UID and GID of the process, not its effective UID and GID.
+ * This shouldn't matter for Blender, which is not going to run privileged anyway.
+ */
bool BLI_file_is_writable(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Creates the file with nothing in it, or updates its last-modified date if it already exists.
+ * Returns true if successful (like the unix touch command).
+ */
bool BLI_file_touch(const char *file) ATTR_NONNULL();
bool BLI_file_alias_target(const char *filepath, char *r_targetpath) ATTR_WARN_UNUSED_RESULT;
@@ -165,23 +261,75 @@ size_t BLI_file_unzstd_to_mem_at_pos(void *buf, size_t len, FILE *file, size_t f
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BLI_file_magic_is_zstd(const char header[4]);
+/**
+ * Returns the file size of an opened file descriptor.
+ */
size_t BLI_file_descriptor_size(int file) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Returns the size of a file.
+ */
size_t BLI_file_size(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* compare if one was last modified before the other */
+/**
+ * Compare if one was last modified before the other.
+ *
+ * \return true when is `file1` older than `file2`.
+ */
bool BLI_file_older(const char *file1, const char *file2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* read ascii file as lines, empty list if reading fails */
+/**
+ * Reads the contents of a text file.
+ *
+ * \return the lines in a linked list (an empty list when file reading fails).
+ */
struct LinkNode *BLI_file_read_as_lines(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void *BLI_file_read_text_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size);
+/**
+ * Return the text file data with:
+
+ * - Newlines replaced with '\0'.
+ * - Optionally trim white-space, replacing trailing <space> & <tab> with '\0'.
+ *
+ * This is an alternative to using #BLI_file_read_as_lines,
+ * allowing us to loop over lines without converting it into a linked list
+ * with individual allocations.
+ *
+ * \param trim_trailing_space: Replace trailing spaces & tabs with nil.
+ * This arguments prevents the caller from counting blank lines (if that's important).
+ * \param pad_bytes: When this is non-zero, the first byte is set to nil,
+ * to simplify parsing the file.
+ * It's recommended to pass in 1, so all text is nil terminated.
+ *
+ * Example looping over lines:
+ *
+ * \code{.c}
+ * size_t data_len;
+ * char *data = BLI_file_read_text_as_mem_with_newline_as_nil(filepath, true, 1, &data_len);
+ * char *data_end = data + data_len;
+ * for (char *line = data; line != data_end; line = strlen(line) + 1) {
+ * printf("line='%s'\n", line);
+ * }
+ * \endcode
+ */
void *BLI_file_read_text_as_mem_with_newline_as_nil(const char *filepath,
bool trim_trailing_space,
size_t pad_bytes,
size_t *r_size);
void *BLI_file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size);
+/**
+ * Frees memory from a previous call to #BLI_file_read_as_lines.
+ */
void BLI_file_free_lines(struct LinkNode *lines);
-/* this weirdo pops up in two places ... */
+#ifdef __APPLE__
+/**
+ * Expand the leading `~` in the given path to `/Users/$USER`.
+ * This doesn't preserve the trailing path separator.
+ * Giving a path without leading `~` is not an error.
+ */
+const char *BLI_expand_tilde(const char *path_with_tilde);
+#endif
+/* This weirdo pops up in two places. */
#if !defined(WIN32)
# ifndef O_BINARY
# define O_BINARY 0
@@ -190,6 +338,8 @@ void BLI_file_free_lines(struct LinkNode *lines);
void BLI_get_short_name(char short_name[256], const char *filename);
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_fileops.hh b/source/blender/blenlib/BLI_fileops.hh
new file mode 100644
index 00000000000..c69b1983c59
--- /dev/null
+++ b/source/blender/blenlib/BLI_fileops.hh
@@ -0,0 +1,52 @@
+/*
+ * 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 bli
+ * \brief File and directory operations.
+ */
+
+#pragma once
+
+#ifndef __cplusplus
+# error This is a C++ header
+#endif
+
+#include "BLI_fileops.h"
+#include "BLI_string_ref.hh"
+
+#include <fstream>
+#include <string>
+
+namespace blender {
+
+/**
+ * std::fstream subclass that handles UTF-16 encoding on Windows.
+ *
+ * For documentation, see https://en.cppreference.com/w/cpp/io/basic_fstream
+ */
+class fstream : public std::fstream {
+ public:
+ fstream() = default;
+ explicit fstream(const char *filepath,
+ std::ios_base::openmode mode = ios_base::in | ios_base::out);
+ explicit fstream(const std::string &filepath,
+ std::ios_base::openmode mode = ios_base::in | ios_base::out);
+
+ void open(StringRefNull filepath, ios_base::openmode mode = ios_base::in | ios_base::out);
+};
+
+} // namespace blender
diff --git a/source/blender/blenlib/BLI_filereader.h b/source/blender/blenlib/BLI_filereader.h
index 8d1fa3d1596..f232ad72cc4 100644
--- a/source/blender/blenlib/BLI_filereader.h
+++ b/source/blender/blenlib/BLI_filereader.h
@@ -47,7 +47,7 @@ typedef ssize_t (*FileReaderReadFn)(struct FileReader *reader, void *buffer, siz
typedef off64_t (*FileReaderSeekFn)(struct FileReader *reader, off64_t offset, int whence);
typedef void (*FileReaderCloseFn)(struct FileReader *reader);
-/* General structure for all FileReaders, implementations add custom fields at the end. */
+/** General structure for all #FileReaders, implementations add custom fields at the end. */
typedef struct FileReader {
FileReaderReadFn read;
FileReaderSeekFn seek;
@@ -59,21 +59,21 @@ typedef struct FileReader {
/* Functions for opening the various types of FileReader.
* They either succeed and return a valid FileReader, or fail and return NULL.
*
- * If a FileReader is created, it has to be cleaned up and freed by calling
- * its close() function unless another FileReader has taken ownership - for example,
- * Zstd and Gzip take over the base FileReader and will clean it up when their clean() is called.
+ * If a FileReader is created, it has to be cleaned up and freed by calling its close()
+ * function unless another FileReader has taken ownership - for example, `Zstd` & `Gzip`
+ * take over the base FileReader and will clean it up when their clean() is called.
*/
-/* Create FileReader from raw file descriptor. */
+/** Create #FileReader from raw file descriptor. */
FileReader *BLI_filereader_new_file(int filedes) ATTR_WARN_UNUSED_RESULT;
-/* Create FileReader from raw file descriptor using memory-mapped IO. */
+/** Create #FileReader from raw file descriptor using memory-mapped IO. */
FileReader *BLI_filereader_new_mmap(int filedes) ATTR_WARN_UNUSED_RESULT;
-/* Create FileReader from a region of memory. */
+/** Create #FileReader from a region of memory. */
FileReader *BLI_filereader_new_memory(const void *data, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-/* Create FileReader from applying Zstd decompression on an underlying file. */
+/** Create #FileReader from applying `Zstd` decompression on an underlying file. */
FileReader *BLI_filereader_new_zstd(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* Create FileReader from applying Gzip decompression on an underlying file. */
+/** Create #FileReader from applying `Gzip` decompression on an underlying file. */
FileReader *BLI_filereader_new_gzip(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_float2.hh b/source/blender/blenlib/BLI_float2.hh
deleted file mode 100644
index 0ff0e50c54e..00000000000
--- a/source/blender/blenlib/BLI_float2.hh
+++ /dev/null
@@ -1,244 +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.
- */
-
-#pragma once
-
-#include "BLI_float3.hh"
-
-namespace blender {
-
-struct float2 {
- float x, y;
-
- float2() = default;
-
- float2(const float *ptr) : x{ptr[0]}, y{ptr[1]}
- {
- }
-
- explicit float2(float value) : x(value), y(value)
- {
- }
-
- explicit float2(int value) : x(value), y(value)
- {
- }
-
- float2(float x, float y) : x(x), y(y)
- {
- }
-
- float2(const float3 &other) : x(other.x), y(other.y)
- {
- }
-
- operator float *()
- {
- return &x;
- }
-
- operator const float *() const
- {
- return &x;
- }
-
- float length() const
- {
- return len_v2(*this);
- }
-
- float length_squared() const
- {
- return len_squared_v2(*this);
- }
-
- bool is_zero() const
- {
- return this->x == 0.0f && this->y == 0.0f;
- }
-
- float2 &operator+=(const float2 &other)
- {
- x += other.x;
- y += other.y;
- return *this;
- }
-
- float2 &operator-=(const float2 &other)
- {
- x -= other.x;
- y -= other.y;
- return *this;
- }
-
- float2 &operator*=(const float2 &other)
- {
- x *= other.x;
- y *= other.y;
- return *this;
- }
-
- float2 &operator/=(const float2 &other)
- {
- x *= other.x;
- y *= other.y;
- return *this;
- }
-
- float2 &operator*=(float factor)
- {
- x *= factor;
- y *= factor;
- return *this;
- }
-
- float2 &operator/=(float divisor)
- {
- x /= divisor;
- y /= divisor;
- return *this;
- }
-
- uint64_t hash() const
- {
- uint64_t x1 = *reinterpret_cast<const uint32_t *>(&x);
- uint64_t x2 = *reinterpret_cast<const uint32_t *>(&y);
- return (x1 * 812519) ^ (x2 * 707951);
- }
-
- friend float2 operator+(const float2 &a, const float2 &b)
- {
- return {a.x + b.x, a.y + b.y};
- }
-
- friend float2 operator-(const float2 &a, const float2 &b)
- {
- return {a.x - b.x, a.y - b.y};
- }
-
- friend float2 operator*(const float2 &a, const float2 &b)
- {
- return {a.x * b.x, a.y * b.y};
- }
-
- friend float2 operator/(const float2 &a, const float2 &b)
- {
- BLI_assert(b.x != 0.0f && b.y != 0.0f);
- return {a.x / b.x, a.y / b.y};
- }
-
- friend float2 operator+(const float2 &a, float b)
- {
- return {a.x + b, a.y + b};
- }
-
- friend float2 operator-(const float2 &a, float b)
- {
- return {a.x - b, a.y - b};
- }
-
- friend float2 operator*(const float2 &a, float b)
- {
- return {a.x * b, a.y * b};
- }
-
- friend float2 operator/(const float2 &a, float b)
- {
- BLI_assert(b != 0.0f);
- return {a.x / b, a.y / b};
- }
-
- friend float2 operator+(float a, const float2 &b)
- {
- return {a + b.x, a + b.y};
- }
-
- friend float2 operator-(float a, const float2 &b)
- {
- return {a - b.x, a - b.y};
- }
-
- friend float2 operator*(float a, const float2 &b)
- {
- return b * a;
- }
-
- friend float2 operator/(float a, const float2 &b)
- {
- BLI_assert(b.x != 0.0f && b.y != 0.0f);
- return {a / b.x, a / b.y};
- }
-
- friend std::ostream &operator<<(std::ostream &stream, const float2 &v)
- {
- stream << "(" << v.x << ", " << v.y << ")";
- return stream;
- }
-
- static float dot(const float2 &a, const float2 &b)
- {
- return a.x * b.x + a.y * b.y;
- }
-
- static float2 interpolate(const float2 &a, const float2 &b, float t)
- {
- return a * (1 - t) + b * t;
- }
-
- static float2 abs(const float2 &a)
- {
- return float2(fabsf(a.x), fabsf(a.y));
- }
-
- static float distance(const float2 &a, const float2 &b)
- {
- return (a - b).length();
- }
-
- static float distance_squared(const float2 &a, const float2 &b)
- {
- float2 diff = a - b;
- return float2::dot(diff, diff);
- }
-
- struct isect_result {
- enum {
- LINE_LINE_COLINEAR = -1,
- LINE_LINE_NONE = 0,
- LINE_LINE_EXACT = 1,
- LINE_LINE_CROSS = 2,
- } kind;
- float lambda;
- float mu;
- };
-
- static isect_result isect_seg_seg(const float2 &v1,
- const float2 &v2,
- const float2 &v3,
- const float2 &v4);
-
- friend bool operator==(const float2 &a, const float2 &b)
- {
- return a.x == b.x && a.y == b.y;
- }
-
- friend bool operator!=(const float2 &a, const float2 &b)
- {
- return !(a == b);
- }
-};
-
-} // namespace blender
diff --git a/source/blender/blenlib/BLI_float3.hh b/source/blender/blenlib/BLI_float3.hh
deleted file mode 100644
index 3254c813307..00000000000
--- a/source/blender/blenlib/BLI_float3.hh
+++ /dev/null
@@ -1,295 +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.
- */
-
-#pragma once
-
-#include <iostream>
-
-#include "BLI_math_vector.h"
-
-namespace blender {
-
-struct float3 {
- float x, y, z;
-
- float3() = default;
-
- float3(const float *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]}
- {
- }
-
- float3(const float (*ptr)[3]) : float3(static_cast<const float *>(ptr[0]))
- {
- }
-
- explicit float3(float value) : x(value), y(value), z(value)
- {
- }
-
- explicit float3(int value) : x(value), y(value), z(value)
- {
- }
-
- float3(float x, float y, float z) : x{x}, y{y}, z{z}
- {
- }
-
- operator const float *() const
- {
- return &x;
- }
-
- operator float *()
- {
- return &x;
- }
-
- friend float3 operator+(const float3 &a, const float3 &b)
- {
- return {a.x + b.x, a.y + b.y, a.z + b.z};
- }
-
- float3 &operator+=(const float3 &b)
- {
- this->x += b.x;
- this->y += b.y;
- this->z += b.z;
- return *this;
- }
-
- friend float3 operator-(const float3 &a, const float3 &b)
- {
- return {a.x - b.x, a.y - b.y, a.z - b.z};
- }
-
- friend float3 operator-(const float3 &a, float b)
- {
- return {a.x - b, a.y - b, a.z - b};
- }
-
- friend float3 operator-(const float3 &a)
- {
- return {-a.x, -a.y, -a.z};
- }
-
- float3 &operator-=(const float3 &b)
- {
- this->x -= b.x;
- this->y -= b.y;
- this->z -= b.z;
- return *this;
- }
-
- float3 &operator*=(float scalar)
- {
- this->x *= scalar;
- this->y *= scalar;
- this->z *= scalar;
- return *this;
- }
-
- float3 &operator*=(const float3 &other)
- {
- this->x *= other.x;
- this->y *= other.y;
- this->z *= other.z;
- return *this;
- }
-
- friend float3 operator*(const float3 &a, const float3 &b)
- {
- return {a.x * b.x, a.y * b.y, a.z * b.z};
- }
-
- friend float3 operator*(const float3 &a, float b)
- {
- return {a.x * b, a.y * b, a.z * b};
- }
-
- friend float3 operator*(float a, const float3 &b)
- {
- return b * a;
- }
-
- friend float3 operator/(const float3 &a, float b)
- {
- BLI_assert(b != 0.0f);
- return {a.x / b, a.y / b, a.z / b};
- }
-
- friend float3 operator/(const float3 &a, const float3 &b)
- {
- BLI_assert(b.x != 0.0f && b.y != 0.0f && b.z != 0.0f);
- return {a.x / b.x, a.y / b.y, a.z / b.z};
- }
-
- friend std::ostream &operator<<(std::ostream &stream, const float3 &v)
- {
- stream << "(" << v.x << ", " << v.y << ", " << v.z << ")";
- return stream;
- }
-
- friend bool operator==(const float3 &a, const float3 &b)
- {
- return a.x == b.x && a.y == b.y && a.z == b.z;
- }
-
- friend bool operator!=(const float3 &a, const float3 &b)
- {
- return !(a == b);
- }
-
- float normalize_and_get_length()
- {
- 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;
- normalize_v3_v3(result, *this);
- return result;
- }
-
- float length() const
- {
- return len_v3(*this);
- }
-
- float length_squared() const
- {
- return len_squared_v3(*this);
- }
-
- bool is_zero() const
- {
- return this->x == 0.0f && this->y == 0.0f && this->z == 0.0f;
- }
-
- void reflect(const float3 &normal)
- {
- *this = this->reflected(normal);
- }
-
- float3 reflected(const float3 &normal) const
- {
- float3 result;
- reflect_v3_v3v3(result, *this, normal);
- return result;
- }
-
- static float3 refract(const float3 &incident, const float3 &normal, const float eta)
- {
- float3 result;
- float k = 1.0f - eta * eta * (1.0f - dot(normal, incident) * dot(normal, incident));
- if (k < 0.0f) {
- result = float3(0.0f);
- }
- else {
- result = eta * incident - (eta * dot(normal, incident) + sqrt(k)) * normal;
- }
- return result;
- }
-
- static float3 faceforward(const float3 &vector, const float3 &incident, const float3 &reference)
- {
- return dot(reference, incident) < 0.0f ? vector : -vector;
- }
-
- static float3 safe_divide(const float3 &a, const float3 &b)
- {
- float3 result;
- result.x = (b.x == 0.0f) ? 0.0f : a.x / b.x;
- result.y = (b.y == 0.0f) ? 0.0f : a.y / b.y;
- result.z = (b.z == 0.0f) ? 0.0f : a.z / b.z;
- return result;
- }
-
- void invert()
- {
- x = -x;
- y = -y;
- z = -z;
- }
-
- uint64_t hash() const
- {
- uint64_t x1 = *reinterpret_cast<const uint32_t *>(&x);
- uint64_t x2 = *reinterpret_cast<const uint32_t *>(&y);
- uint64_t x3 = *reinterpret_cast<const uint32_t *>(&z);
- return (x1 * 435109) ^ (x2 * 380867) ^ (x3 * 1059217);
- }
-
- static float dot(const float3 &a, const float3 &b)
- {
- return a.x * b.x + a.y * b.y + a.z * b.z;
- }
-
- static float3 cross_high_precision(const float3 &a, const float3 &b)
- {
- float3 result;
- cross_v3_v3v3_hi_prec(result, a, b);
- return result;
- }
-
- static float3 cross(const float3 &a, const float3 &b)
- {
- float3 result;
- cross_v3_v3v3(result, a, b);
- return result;
- }
-
- static float3 project(const float3 &a, const float3 &b)
- {
- float3 result;
- project_v3_v3v3(result, a, b);
- return result;
- }
-
- static float distance(const float3 &a, const float3 &b)
- {
- return (a - b).length();
- }
-
- static float distance_squared(const float3 &a, const float3 &b)
- {
- float3 diff = a - b;
- return float3::dot(diff, diff);
- }
-
- static float3 interpolate(const float3 &a, const float3 &b, float t)
- {
- return a * (1 - t) + b * t;
- }
-
- static float3 abs(const float3 &a)
- {
- return float3(fabsf(a.x), fabsf(a.y), fabsf(a.z));
- }
-};
-
-} // namespace blender
diff --git a/source/blender/blenlib/BLI_float4.hh b/source/blender/blenlib/BLI_float4.hh
deleted file mode 100644
index 6392ca038f2..00000000000
--- a/source/blender/blenlib/BLI_float4.hh
+++ /dev/null
@@ -1,129 +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.
- */
-
-#pragma once
-
-namespace blender {
-
-struct float4 {
- float x, y, z, w;
-
- float4() = default;
-
- float4(const float *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]}, w{ptr[3]}
- {
- }
-
- explicit float4(float value) : x(value), y(value), z(value), w(value)
- {
- }
-
- explicit float4(int value) : x(value), y(value), z(value), w(value)
- {
- }
-
- float4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w)
- {
- }
-
- operator float *()
- {
- return &x;
- }
-
- operator const float *() const
- {
- return &x;
- }
-
- float4 &operator+=(const float4 &other)
- {
- x += other.x;
- y += other.y;
- z += other.z;
- w += other.w;
- return *this;
- }
-
- friend float4 operator+(const float4 &a, const float4 &b)
- {
- return {a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w};
- }
-
- float4 &operator-=(const float4 &other)
- {
- x -= other.x;
- y -= other.y;
- z -= other.z;
- w -= other.w;
- return *this;
- }
-
- friend float4 operator-(const float4 &a, const float4 &b)
- {
- return {a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w};
- }
-
- float4 &operator*=(float factor)
- {
- x *= factor;
- y *= factor;
- z *= factor;
- w *= factor;
- return *this;
- }
-
- friend float4 operator*(float4 &a, const float4 &b)
- {
- return {a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w};
- }
-
- friend float4 operator*(const float4 &a, float b)
- {
- return {a.x * b, a.y * b, a.z * b, a.w * b};
- }
-
- friend float4 operator*(float a, const float4 &b)
- {
- return b * a;
- }
-
- float4 &operator/=(const float4 &other)
- {
- x /= other.x;
- y /= other.y;
- z /= other.z;
- w /= other.w;
- return *this;
- }
-
- friend float4 operator/(const float4 &a, const float4 &b)
- {
- return {a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w};
- }
-
- friend float4 operator/(const float4 &a, float b)
- {
- return {a.x / b, a.y / b, a.z / b, a.w / b};
- }
-
- friend float4 operator/(float a, const float4 &b)
- {
- return {a / b.x, a / b.y, a / b.z, a / b.w};
- }
-};
-
-} // namespace blender
diff --git a/source/blender/blenlib/BLI_float4x4.hh b/source/blender/blenlib/BLI_float4x4.hh
index 14e61d53845..81c969d02d0 100644
--- a/source/blender/blenlib/BLI_float4x4.hh
+++ b/source/blender/blenlib/BLI_float4x4.hh
@@ -16,8 +16,9 @@
#pragma once
-#include "BLI_float3.hh"
#include "BLI_math_matrix.h"
+#include "BLI_math_vec_types.hh"
+#include "BLI_math_vector.h"
namespace blender {
@@ -63,7 +64,7 @@ struct float4x4 {
* Without the negation, the result would be a so called improper rotation. That means it
* contains a reflection. Such an improper rotation matrix could not be converted to another
* representation of a rotation such as euler angles. */
- const float3 cross = -float3::cross(forward, up);
+ const float3 cross = -math::cross(forward, up);
float4x4 matrix;
matrix.values[0][0] = forward.x;
@@ -124,6 +125,11 @@ struct float4x4 {
return result;
}
+ void operator*=(const float4x4 &other)
+ {
+ mul_m4_m4_post(values, other.values);
+ }
+
/**
* This also applies the translation on the vector. Use `m.ref_3x3() * v` if that is not
* intended.
diff --git a/source/blender/blenlib/BLI_function_ref.hh b/source/blender/blenlib/BLI_function_ref.hh
index 71be7d7f029..c762756b474 100644
--- a/source/blender/blenlib/BLI_function_ref.hh
+++ b/source/blender/blenlib/BLI_function_ref.hh
@@ -80,6 +80,8 @@
*
*/
+#include "BLI_memory_utils.hh"
+
namespace blender {
template<typename Function> class FunctionRef;
@@ -125,8 +127,8 @@ template<typename Ret, typename... Params> class FunctionRef<Ret(Params...)> {
* another lambda.
*/
template<typename Callable,
- std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Callable>>,
- FunctionRef>> * = nullptr>
+ BLI_ENABLE_IF((
+ !std::is_same_v<std::remove_cv_t<std::remove_reference_t<Callable>>, FunctionRef>))>
FunctionRef(Callable &&callable)
: callback_(callback_fn<typename std::remove_reference_t<Callable>>),
callable_(reinterpret_cast<intptr_t>(&callable))
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index a2c5c6349a5..1c5adb8ee82 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -43,6 +43,10 @@ extern "C" {
# endif
#endif
+/* -------------------------------------------------------------------- */
+/** \name GHash Types
+ * \{ */
+
typedef unsigned int (*GHashHashFP)(const void *key);
/** returns false when equal */
typedef bool (*GHashCmpFP)(const void *a, const void *b);
@@ -74,53 +78,191 @@ enum {
#endif
};
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name GHash API
*
* Defined in `BLI_ghash.c`
* \{ */
+/**
+ * Creates a new, empty GHash.
+ *
+ * \param hashfp: Hash callback.
+ * \param cmpfp: Comparison callback.
+ * \param info: Identifier string for the GHash.
+ * \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
+ * Use this to avoid resizing buckets if the size is known or can be closely approximated.
+ * \return An empty GHash.
+ */
GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
GHashCmpFP cmpfp,
const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Wraps #BLI_ghash_new_ex with zero entries reserved.
+ */
GHash *BLI_ghash_new(GHashHashFP hashfp,
GHashCmpFP cmpfp,
const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Copy given GHash. Keys and values are also copied if relevant callback is provided,
+ * else pointers remain the same.
+ */
GHash *BLI_ghash_copy(const GHash *gh,
GHashKeyCopyFP keycopyfp,
GHashValCopyFP valcopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Frees the GHash and its members.
+ *
+ * \param gh: The GHash to free.
+ * \param keyfreefp: Optional callback to free the key.
+ * \param valfreefp: Optional callback to free the value.
+ */
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
-void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve);
+/**
+ * Reserve given amount of entries (resize \a gh accordingly if needed).
+ */
+void BLI_ghash_reserve(GHash *gh, unsigned int nentries_reserve);
+/**
+ * Insert a key/value pair into the \a gh.
+ *
+ * \note Duplicates are not checked,
+ * the caller is expected to ensure elements are unique unless
+ * GHASH_FLAG_ALLOW_DUPES flag is set.
+ */
void BLI_ghash_insert(GHash *gh, void *key, void *val);
+/**
+ * Inserts a new value to a key that may already be in ghash.
+ *
+ * Avoids #BLI_ghash_remove, #BLI_ghash_insert calls (double lookups)
+ *
+ * \returns true if a new key has been added.
+ */
bool BLI_ghash_reinsert(
GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+/**
+ * Replaces the key of an item in the \a gh.
+ *
+ * Use when a key is re-allocated or its memory location is changed.
+ *
+ * \returns The previous key or NULL if not found, the caller may free if it's needed.
+ */
void *BLI_ghash_replace_key(GHash *gh, void *key);
+/**
+ * Lookup the value of \a key in \a gh.
+ *
+ * \param key: The key to lookup.
+ * \returns the value for \a key or NULL.
+ *
+ * \note When NULL is a valid value, use #BLI_ghash_lookup_p to differentiate a missing key
+ * from a key with a NULL value. (Avoids calling #BLI_ghash_haskey before #BLI_ghash_lookup)
+ */
void *BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * A version of #BLI_ghash_lookup which accepts a fallback argument.
+ */
void *BLI_ghash_lookup_default(const GHash *gh,
const void *key,
void *val_default) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Lookup a pointer to the value of \a key in \a gh.
+ *
+ * \param key: The key to lookup.
+ * \returns the pointer to value for \a key or NULL.
+ *
+ * \note This has 2 main benefits over #BLI_ghash_lookup.
+ * - A NULL return always means that \a key isn't in \a gh.
+ * - The value can be modified in-place without further function calls (faster).
+ */
void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Ensure \a key is exists in \a gh.
+ *
+ * This handles the common situation where the caller needs ensure a key is added to \a gh,
+ * constructing a new value in the case the key isn't found.
+ * Otherwise use the existing value.
+ *
+ * Such situations typically incur multiple lookups, however this function
+ * avoids them by ensuring the key is added,
+ * returning a pointer to the value so it can be used or initialized by the caller.
+ *
+ * \returns true when the value didn't need to be added.
+ * (when false, the caller _must_ initialize the value).
+ */
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT;
+/**
+ * A version of #BLI_ghash_ensure_p that allows caller to re-assign the key.
+ * Typically used when the key is to be duplicated.
+ *
+ * \warning Caller _must_ write to \a r_key when returning false.
+ */
bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val)
ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove \a key from \a gh, or return false if the key wasn't found.
+ *
+ * \param key: The key to remove.
+ * \param keyfreefp: Optional callback to free the key.
+ * \param valfreefp: Optional callback to free the value.
+ * \return true if \a key was removed from \a gh.
+ */
bool BLI_ghash_remove(GHash *gh,
const void *key,
GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp);
+/**
+ * Wraps #BLI_ghash_clear_ex with zero entries reserved.
+ */
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+/**
+ * Reset \a gh clearing all entries.
+ *
+ * \param keyfreefp: Optional callback to free the key.
+ * \param valfreefp: Optional callback to free the value.
+ * \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
+ */
void BLI_ghash_clear_ex(GHash *gh,
GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp,
- const unsigned int nentries_reserve);
+ unsigned int nentries_reserve);
+/**
+ * Remove \a key from \a gh, returning the value or NULL if the key wasn't found.
+ *
+ * \param key: The key to remove.
+ * \param keyfreefp: Optional callback to free the key.
+ * \return the value of \a key int \a gh or NULL.
+ */
void *BLI_ghash_popkey(GHash *gh,
const void *key,
GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \return true if the \a key is in \a gh.
+ */
bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove a random entry from \a gh, returning true
+ * if a key/value pair could be removed, false otherwise.
+ *
+ * \param r_key: The removed key.
+ * \param r_val: The removed value.
+ * \param state: Used for efficient removal.
+ * \return true if there was something to pop, false if ghash was already empty.
+ */
bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \return size of the GHash.
+ */
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Sets a GHash flag.
+ */
void BLI_ghash_flag_set(GHash *gh, unsigned int flag);
+/**
+ * Clear a GHash flag.
+ */
void BLI_ghash_flag_clear(GHash *gh, unsigned int flag);
/** \} */
@@ -129,10 +271,36 @@ void BLI_ghash_flag_clear(GHash *gh, unsigned int flag);
/** \name GHash Iterator
* \{ */
+/**
+ * Create a new GHashIterator. The hash table must not be mutated
+ * while the iterator is in use, and the iterator will step exactly
+ * #BLI_ghash_len(gh) times before becoming done.
+ *
+ * \param gh: The GHash to iterate over.
+ * \return Pointer to a new iterator.
+ */
GHashIterator *BLI_ghashIterator_new(GHash *gh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Init an already allocated GHashIterator. The hash table must not
+ * be mutated while the iterator is in use, and the iterator will
+ * step exactly #BLI_ghash_len(gh) times before becoming done.
+ *
+ * \param ghi: The GHashIterator to initialize.
+ * \param gh: The GHash to iterate over.
+ */
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh);
+/**
+ * Free a GHashIterator.
+ *
+ * \param ghi: The iterator to free.
+ */
void BLI_ghashIterator_free(GHashIterator *ghi);
+/**
+ * Steps the iterator to the next index.
+ *
+ * \param ghi: The iterator.
+ */
void BLI_ghashIterator_step(GHashIterator *ghi);
BLI_INLINE void *BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT;
@@ -178,12 +346,11 @@ BLI_INLINE bool BLI_ghashIterator_done(const GHashIterator *ghi)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name GSet API
+/** \name GSet Types
* A 'set' implementation (unordered collection of unique elements).
*
* Internally this is a 'GHash' without any keys,
* which is why this API's are in the same header & source file.
- *
* \{ */
typedef struct GSet GSet;
@@ -195,32 +362,84 @@ typedef GHashKeyCopyFP GSetKeyCopyFP;
typedef GHashIterState GSetIterState;
+/** \} */
+
+/** \name GSet Public API
+ *
+ * Use ghash API to give 'set' functionality
+ * \{ */
+
GSet *BLI_gset_new_ex(GSetHashFP hashfp,
GSetCmpFP cmpfp,
const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_new(GSetHashFP hashfp,
GSetCmpFP cmpfp,
const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Copy given GSet. Keys are also copied if callback is provided, else pointers remain the same.
+ */
GSet *BLI_gset_copy(const GSet *gs, GSetKeyCopyFP keycopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
unsigned int BLI_gset_len(const GSet *gs) ATTR_WARN_UNUSED_RESULT;
void BLI_gset_flag_set(GSet *gs, unsigned int flag);
void BLI_gset_flag_clear(GSet *gs, unsigned int flag);
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp);
+/**
+ * Adds the key to the set (no checks for unique keys!).
+ * Matching #BLI_ghash_insert
+ */
void BLI_gset_insert(GSet *gs, void *key);
+/**
+ * A version of BLI_gset_insert which checks first if the key is in the set.
+ * \returns true if a new key has been added.
+ *
+ * \note GHash has no equivalent to this because typically the value would be different.
+ */
bool BLI_gset_add(GSet *gs, void *key);
+/**
+ * Set counterpart to #BLI_ghash_ensure_p_ex.
+ * similar to BLI_gset_add, except it returns the key pointer.
+ *
+ * \warning Caller _must_ write to \a r_key when returning false.
+ */
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key);
+/**
+ * Adds the key to the set (duplicates are managed).
+ * Matching #BLI_ghash_reinsert
+ *
+ * \returns true if a new key has been added.
+ */
bool BLI_gset_reinsert(GSet *gh, void *key, GSetKeyFreeFP keyfreefp);
+/**
+ * Replaces the key to the set if it's found.
+ * Matching #BLI_ghash_replace_key
+ *
+ * \returns The old key or NULL if not found.
+ */
void *BLI_gset_replace_key(GSet *gs, void *key);
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove a random entry from \a gs, returning true if a key could be removed, false otherwise.
+ *
+ * \param r_key: The removed key.
+ * \param state: Used for efficient removal.
+ * \return true if there was something to pop, false if gset was already empty.
+ */
bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp);
-void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp, const unsigned int nentries_reserve);
+void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp, unsigned int nentries_reserve);
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp);
/* When set's are used for key & value. */
+/**
+ * Returns the pointer to the key if it's found.
+ */
void *BLI_gset_lookup(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Returns the pointer to the key if it's found, removing it from the GSet.
+ * \note Caller must handle freeing.
+ */
void *BLI_gset_pop_key(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
/** \} */
@@ -231,7 +450,7 @@ void *BLI_gset_pop_key(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
/* rely on inline api for now */
-/* so we can cast but compiler sees as different */
+/** Use a GSet specific type so we can cast but compiler sees as different */
typedef struct GSetIterator {
GHashIterator _ghi
#if defined(__GNUC__) && !defined(__clang__)
@@ -282,9 +501,19 @@ BLI_INLINE bool BLI_gsetIterator_done(const GSetIterator *gsi)
/* For testing, debugging only */
#ifdef GHASH_INTERNAL_API
+/**
+ * \return number of buckets in the GHash.
+ */
int BLI_ghash_buckets_len(const GHash *gh);
int BLI_gset_buckets_len(const GSet *gs);
+/**
+ * Measure how well the hash function performs (1.0 is approx as good as random distribution),
+ * and return a few other stats like load,
+ * variance of the distribution of the entries in the buckets, etc.
+ *
+ * Smaller is better!
+ */
double BLI_ghash_calc_quality_ex(GHash *gh,
double *r_load,
double *r_variance,
@@ -300,6 +529,7 @@ double BLI_gset_calc_quality_ex(GSet *gs,
double BLI_ghash_calc_quality(GHash *gh);
double BLI_gset_calc_quality(GSet *gs);
#endif /* GHASH_INTERNAL_API */
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -346,6 +576,15 @@ double BLI_gset_calc_quality(GSet *gs);
unsigned int BLI_ghashutil_ptrhash(const void *key);
bool BLI_ghashutil_ptrcmp(const void *a, const void *b);
+/**
+ * This function implements the widely used `djb` hash apparently posted
+ * by Daniel Bernstein to `comp.lang.c` some time ago. The 32 bit
+ * unsigned hash value starts at 5381 and for each byte 'c' in the
+ * string, is updated: `hash = hash * 33 + c`.
+ * This function uses the signed value of each byte.
+ *
+ * NOTE: this is the same hash method that glib 2.34.0 uses.
+ */
unsigned int BLI_ghashutil_strhash_n(const char *key, size_t n);
#define BLI_ghashutil_strhash(key) \
(CHECK_TYPE_ANY(key, char *, const char *, const char *const), BLI_ghashutil_strhash_p(key))
@@ -391,30 +630,30 @@ void BLI_ghashutil_pairfree(void *ptr);
* Wrapper GHash Creation Functions
*/
-GHash *BLI_ghash_ptr_new_ex(const char *info, const unsigned int nentries_reserve)
- ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_ptr_new_ex(const char *info,
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GHash *BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_str_new_ex(const char *info, const unsigned int nentries_reserve)
- ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_str_new_ex(const char *info,
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GHash *BLI_ghash_str_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_int_new_ex(const char *info, const unsigned int nentries_reserve)
- ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_int_new_ex(const char *info,
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GHash *BLI_ghash_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_pair_new_ex(const char *info, const unsigned int nentries_reserve)
- ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_pair_new_ex(const char *info,
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GHash *BLI_ghash_pair_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_ptr_new_ex(const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_ptr_new(const char *info);
GSet *BLI_gset_str_new_ex(const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_str_new(const char *info);
-GSet *BLI_gset_pair_new_ex(const char *info, const unsigned int nentries_reserve)
- ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GSet *BLI_gset_pair_new_ex(const char *info,
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_pair_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_int_new_ex(const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
/** \} */
diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h
index 9cc61bc8059..a35c743c80b 100644
--- a/source/blender/blenlib/BLI_gsqueue.h
+++ b/source/blender/blenlib/BLI_gsqueue.h
@@ -31,11 +31,31 @@ extern "C" {
typedef struct _GSQueue GSQueue;
-GSQueue *BLI_gsqueue_new(const size_t elem_size);
+GSQueue *BLI_gsqueue_new(size_t elem_size);
+/**
+ * Returns true if the queue is empty, false otherwise.
+ */
bool BLI_gsqueue_is_empty(const GSQueue *queue);
size_t BLI_gsqueue_len(const GSQueue *queue);
+/**
+ * Retrieves and removes the first element from the queue.
+ * The value is copies to \a r_item, which must be at least \a elem_size bytes.
+ *
+ * Does not reduce amount of allocated memory.
+ */
void BLI_gsqueue_pop(GSQueue *queue, void *r_item);
+/**
+ * Copies the source value onto the end of the queue
+ *
+ * \note This copies #GSQueue.elem_size bytes from \a item,
+ * (the pointer itself is not stored).
+ *
+ * \param item: source data to be copied to the queue.
+ */
void BLI_gsqueue_push(GSQueue *queue, const void *item);
+/**
+ * Free the queue's data and the queue itself.
+ */
void BLI_gsqueue_free(GSQueue *queue);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_hash.hh b/source/blender/blenlib/BLI_hash.hh
index 11ff7d040aa..9132aacf7b9 100644
--- a/source/blender/blenlib/BLI_hash.hh
+++ b/source/blender/blenlib/BLI_hash.hh
@@ -243,6 +243,16 @@ uint64_t get_default_hash_3(const T1 &v1, const T2 &v2, const T3 &v3)
return h1 ^ (h2 * 19349669) ^ (h3 * 83492791);
}
+template<typename T1, typename T2, typename T3, typename T4>
+uint64_t get_default_hash_4(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4)
+{
+ const uint64_t h1 = get_default_hash(v1);
+ const uint64_t h2 = get_default_hash(v2);
+ const uint64_t h3 = get_default_hash(v3);
+ const uint64_t h4 = get_default_hash(v4);
+ return h1 ^ (h2 * 19349669) ^ (h3 * 83492791) ^ (h4 * 3632623);
+}
+
template<typename T> struct DefaultHash<std::unique_ptr<T>> {
uint64_t operator()(const std::unique_ptr<T> &value) const
{
diff --git a/source/blender/blenlib/BLI_hash_md5.h b/source/blender/blenlib/BLI_hash_md5.h
index 227cfcc8876..7b5868d7ffc 100644
--- a/source/blender/blenlib/BLI_hash_md5.h
+++ b/source/blender/blenlib/BLI_hash_md5.h
@@ -24,17 +24,18 @@
extern "C" {
#endif
-/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
- * result is always in little endian byte order, so that a byte-wise
- * output yields to the wanted ASCII representation of the message
- * digest. */
-
+/**
+ * Compute MD5 message digest for 'len' bytes beginning at 'buffer'.
+ * The result is always in little endian byte order,
+ * so that a byte-wise output yields to the wanted ASCII representation of the message digest.
+ */
void *BLI_hash_md5_buffer(const char *buffer, size_t len, void *resblock);
-/* Compute MD5 message digest for bytes read from STREAM. The
- * resulting message digest number will be written into the 16 bytes
- * beginning at RESBLOCK. */
-
+/**
+ * Compute MD5 message digest for bytes read from 'stream'.
+ * The resulting message digest number will be written into the 16 bytes beginning at 'resblock'.
+ * \return Non-zero if an error occurred.
+ */
int BLI_hash_md5_stream(FILE *stream, void *resblock);
char *BLI_hash_md5_to_hexdigest(void *resblock, char r_hex_digest[33]);
diff --git a/source/blender/blenlib/BLI_hash_mm2a.h b/source/blender/blenlib/BLI_hash_mm2a.h
index 193a78e6293..2619e516861 100644
--- a/source/blender/blenlib/BLI_hash_mm2a.h
+++ b/source/blender/blenlib/BLI_hash_mm2a.h
@@ -41,6 +41,9 @@ void BLI_hash_mm2a_add_int(BLI_HashMurmur2A *mm2, int data);
uint32_t BLI_hash_mm2a_end(BLI_HashMurmur2A *mm2);
+/**
+ * Non-incremental version, quicker for small keys.
+ */
uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_heap.h b/source/blender/blenlib/BLI_heap.h
index 4cfb7945303..b6a12521fff 100644
--- a/source/blender/blenlib/BLI_heap.h
+++ b/source/blender/blenlib/BLI_heap.h
@@ -34,27 +34,59 @@ typedef struct HeapNode HeapNode;
typedef void (*HeapFreeFP)(void *ptr);
+/**
+ * Creates a new heap. Removed nodes are recycled, so memory usage will not shrink.
+ *
+ * \note Use when the size of the heap is known in advance.
+ */
Heap *BLI_heap_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT;
Heap *BLI_heap_new(void) ATTR_WARN_UNUSED_RESULT;
void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1);
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1);
+/**
+ * Insert heap node with a value (often a 'cost') and pointer into the heap,
+ * duplicate values are allowed.
+ */
HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1);
+/**
+ * Convenience function since this is a common pattern.
+ */
void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr)
ATTR_NONNULL(1, 2);
void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1, 2);
bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1);
unsigned int BLI_heap_len(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Return the top node of the heap.
+ * This is the node with the lowest value.
+ */
HeapNode *BLI_heap_top(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Return the value of top node of the heap.
+ * This is the node with the lowest value.
+ */
float BLI_heap_top_value(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Pop the top node off the heap and return its pointer.
+ */
void *BLI_heap_pop_min(Heap *heap) ATTR_NONNULL(1);
+/**
+ * Can be used to avoid #BLI_heap_remove, #BLI_heap_insert calls,
+ * balancing the tree still has a performance cost,
+ * but is often much less than remove/insert, difference is most noticeable with large heaps.
+ */
void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value) ATTR_NONNULL(1, 2);
void BLI_heap_node_value_update_ptr(Heap *heap, HeapNode *node, float value, void *ptr)
ATTR_NONNULL(1, 2);
-/* Return the value or pointer of a heap node. */
+/**
+ * Return the value or pointer of a heap node.
+ */
float BLI_heap_node_value(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void *BLI_heap_node_ptr(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* only for gtest */
+/**
+ * Only for checking internal errors (gtest).
+ */
bool BLI_heap_is_valid(const Heap *heap);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_heap_simple.h b/source/blender/blenlib/BLI_heap_simple.h
index b2a1b5582e5..5583f209de0 100644
--- a/source/blender/blenlib/BLI_heap_simple.h
+++ b/source/blender/blenlib/BLI_heap_simple.h
@@ -30,14 +30,29 @@ typedef struct HeapSimple HeapSimple;
typedef void (*HeapSimpleFreeFP)(void *ptr);
+/**
+ * Creates a new simple heap, which only supports insertion and removal from top.
+ *
+ * \note Use when the size of the heap is known in advance.
+ */
HeapSimple *BLI_heapsimple_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT;
HeapSimple *BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT;
void BLI_heapsimple_clear(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1);
void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1);
+/**
+ * Insert heap node with a value (often a 'cost') and pointer into the heap,
+ * duplicate values are allowed.
+ */
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) ATTR_NONNULL(1);
bool BLI_heapsimple_is_empty(const HeapSimple *heap) ATTR_NONNULL(1);
uint BLI_heapsimple_len(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Return the lowest value of the heap.
+ */
float BLI_heapsimple_top_value(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Pop the top node off the heap and return its pointer.
+ */
void *BLI_heapsimple_pop_min(HeapSimple *heap) ATTR_NONNULL(1);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_index_mask.hh b/source/blender/blenlib/BLI_index_mask.hh
index ad030e127fe..2dca3689cb1 100644
--- a/source/blender/blenlib/BLI_index_mask.hh
+++ b/source/blender/blenlib/BLI_index_mask.hh
@@ -45,11 +45,11 @@ namespace blender {
class IndexMask {
private:
- /* The underlying reference to sorted integers. */
+ /** The underlying reference to sorted integers. */
Span<int64_t> indices_;
public:
- /* Creates an IndexMask that contains no indices. */
+ /** Creates an IndexMask that contains no indices. */
IndexMask() = default;
/**
@@ -223,6 +223,25 @@ class IndexMask {
return indices_.is_empty();
}
+ IndexMask slice(IndexRange slice) const;
+ /**
+ * Create a sub-mask that is also shifted to the beginning.
+ * The shifting to the beginning allows code to work with smaller indices,
+ * which is more memory efficient.
+ *
+ * \return New index mask with the size of #slice. It is either empty or starts with 0.
+ * It might reference indices that have been appended to #r_new_indices.
+ *
+ * Example:
+ * \code{.unparsed}
+ * this: [2, 3, 5, 7, 8, 9, 10]
+ * slice: ^--------^
+ * output: [0, 2, 4, 5]
+ * \endcode
+ *
+ * All the indices in the sub-mask are shifted by 3 towards zero,
+ * so that the first index in the output is zero.
+ */
IndexMask slice_and_offset(IndexRange slice, Vector<int64_t> &r_new_indices) const;
};
diff --git a/source/blender/blenlib/BLI_index_range.hh b/source/blender/blenlib/BLI_index_range.hh
index 665f44468db..cc6040d49db 100644
--- a/source/blender/blenlib/BLI_index_range.hh
+++ b/source/blender/blenlib/BLI_index_range.hh
@@ -48,7 +48,7 @@
* Ideally this could be could be even closer to Python's enumerate(). We might get that in the
* future with newer C++ versions.
*
- * One other important feature is the as_span method. This method returns an Span<int64_t>
+ * One other important feature is the as_span method. This method returns a Span<int64_t>
* that contains the interval as individual numbers.
*/
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index 5e0ea4f2a99..cee9ec4c0a8 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -104,69 +104,104 @@ enum {
#define BVH_RAYCAST_DEFAULT (BVH_RAYCAST_WATERTIGHT)
#define BVH_RAYCAST_DIST_MAX (FLT_MAX / 2.0f)
-/* callback must update nearest in case it finds a nearest result */
+/**
+ * Callback must update nearest in case it finds a nearest result.
+ */
typedef void (*BVHTree_NearestPointCallback)(void *userdata,
int index,
const float co[3],
BVHTreeNearest *nearest);
-/* callback must update hit in case it finds a nearest successful hit */
+/**
+ * Callback must update hit in case it finds a nearest successful hit.
+ */
typedef void (*BVHTree_RayCastCallback)(void *userdata,
int index,
const BVHTreeRay *ray,
BVHTreeRayHit *hit);
-/* callback to check if 2 nodes overlap (use thread if intersection results need to be stored) */
+/**
+ * Callback to check if 2 nodes overlap (use thread if intersection results need to be stored).
+ */
typedef bool (*BVHTree_OverlapCallback)(void *userdata, int index_a, int index_b, int thread);
-/* callback to range search query */
+/**
+ * Callback to range search query.
+ */
typedef void (*BVHTree_RangeQuery)(void *userdata, int index, const float co[3], float dist_sq);
-/* callback to find nearest projected */
+/**
+ * Callback to find nearest projected.
+ */
typedef void (*BVHTree_NearestProjectedCallback)(void *userdata,
int index,
const struct DistProjectedAABBPrecalc *precalc,
const float (*clip_plane)[4],
- const int clip_plane_len,
+ int clip_plane_len,
BVHTreeNearest *nearest);
/* callbacks to BLI_bvhtree_walk_dfs */
-/* return true to traverse into this nodes children, else skip. */
+
+/**
+ * Return true to traverse into this nodes children, else skip.
+ */
typedef bool (*BVHTree_WalkParentCallback)(const BVHTreeAxisRange *bounds, void *userdata);
-/* return true to keep walking, else early-exit the search. */
+/**
+ * Return true to keep walking, else early-exit the search.
+ */
typedef bool (*BVHTree_WalkLeafCallback)(const BVHTreeAxisRange *bounds,
int index,
void *userdata);
-/* return true to search (min, max) else (max, min). */
+/**
+ * Return true to search (min, max) else (max, min).
+ */
typedef bool (*BVHTree_WalkOrderCallback)(const BVHTreeAxisRange *bounds,
char axis,
void *userdata);
+/**
+ * \note many callers don't check for `NULL` return.
+ */
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis);
void BLI_bvhtree_free(BVHTree *tree);
-/* construct: first insert points, then call balance */
+/**
+ * Construct: first insert points, then call balance.
+ */
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints);
void BLI_bvhtree_balance(BVHTree *tree);
-/* update: first update points/nodes, then call update_tree to refit the bounding volumes */
+/**
+ * Update: first update points/nodes, then call update_tree to refit the bounding volumes.
+ * \note call before #BLI_bvhtree_update_tree().
+ */
bool BLI_bvhtree_update_node(
BVHTree *tree, int index, const float co[3], const float co_moving[3], int numpoints);
+/**
+ * Call #BLI_bvhtree_update_node() first for every node/point/triangle.
+ */
void BLI_bvhtree_update_tree(BVHTree *tree);
+/**
+ * Use to check the total number of threads #BLI_bvhtree_overlap will use.
+ *
+ * \warning Must be the first tree passed to #BLI_bvhtree_overlap!
+ */
int BLI_bvhtree_overlap_thread_num(const BVHTree *tree);
-/* collision/overlap: check two trees if they overlap,
- * alloc's *overlap with length of the int return value */
-BVHTreeOverlap *BLI_bvhtree_overlap_ex(
- const BVHTree *tree1,
- const BVHTree *tree2,
- uint *r_overlap_tot,
- /* optional callback to test the overlap before adding (must be thread-safe!) */
- BVHTree_OverlapCallback callback,
- void *userdata,
- const uint max_interactions,
- const int flag);
+/**
+ * Collision/overlap: check two trees if they overlap,
+ * alloc's *overlap with length of the int return value.
+ *
+ * \param callback: optional, to test the overlap before adding (must be thread-safe!).
+ */
+BVHTreeOverlap *BLI_bvhtree_overlap_ex(const BVHTree *tree1,
+ const BVHTree *tree2,
+ uint *r_overlap_tot,
+ BVHTree_OverlapCallback callback,
+ void *userdata,
+ uint max_interactions,
+ int flag);
BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1,
const BVHTree *tree2,
unsigned int *r_overlap_tot,
@@ -175,14 +210,26 @@ BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1,
int *BLI_bvhtree_intersect_plane(BVHTree *tree, float plane[4], uint *r_intersect_tot);
+/**
+ * Number of times #BLI_bvhtree_insert has been called.
+ * mainly useful for asserts functions to check we added the correct number.
+ */
int BLI_bvhtree_get_len(const BVHTree *tree);
+/**
+ * Maximum number of children that a node can have.
+ */
int BLI_bvhtree_get_tree_type(const BVHTree *tree);
float BLI_bvhtree_get_epsilon(const BVHTree *tree);
+/**
+ * This function returns the bounding box of the BVH tree.
+ */
void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3]);
-/* find nearest node to the given coordinates
+/**
+ * Find nearest node to the given coordinates
* (if nearest is given it will only search nodes where
- * square distance is smaller than nearest->dist) */
+ * square distance is smaller than nearest->dist).
+ */
int BLI_bvhtree_find_nearest_ex(BVHTree *tree,
const float co[3],
BVHTreeNearest *nearest,
@@ -195,9 +242,13 @@ int BLI_bvhtree_find_nearest(BVHTree *tree,
BVHTree_NearestPointCallback callback,
void *userdata);
+/**
+ * Find the first node nearby.
+ * Favors speed over quality since it doesn't find the best target node.
+ */
int BLI_bvhtree_find_nearest_first(BVHTree *tree,
const float co[3],
- const float dist_sq,
+ float dist_sq,
BVHTree_NearestPointCallback callback,
void *userdata);
@@ -217,6 +268,15 @@ int BLI_bvhtree_ray_cast(BVHTree *tree,
BVHTree_RayCastCallback callback,
void *userdata);
+/**
+ * Calls the callback for every ray intersection
+ *
+ * \note Using a \a callback which resets or never sets the #BVHTreeRayHit index & dist works too,
+ * however using this function means existing generic callbacks can be used from custom callbacks
+ * without having to handle resetting the hit beforehand.
+ * It also avoid redundant argument and return value which aren't meaningful
+ * when collecting multiple hits.
+ */
void BLI_bvhtree_ray_cast_all_ex(BVHTree *tree,
const float co[3],
const float dir[3],
@@ -238,7 +298,9 @@ float BLI_bvhtree_bb_raycast(const float bv[6],
const float light_end[3],
float pos[3]);
-/* range query */
+/**
+ * Range query.
+ */
int BLI_bvhtree_range_query(
BVHTree *tree, const float co[3], float radius, BVHTree_RangeQuery callback, void *userdata);
@@ -252,13 +314,27 @@ int BLI_bvhtree_find_nearest_projected(BVHTree *tree,
BVHTree_NearestProjectedCallback callback,
void *userdata);
+/**
+ * This is a generic function to perform a depth first search on the #BVHTree
+ * where the search order and nodes traversed depend on callbacks passed in.
+ *
+ * \param tree: Tree to walk.
+ * \param walk_parent_cb: Callback on a parents bound-box to test if it should be traversed.
+ * \param walk_leaf_cb: Callback to test leaf nodes, callback must store its own result,
+ * returning false exits early.
+ * \param walk_order_cb: Callback that indicates which direction to search,
+ * either from the node with the lower or higher K-DOP axis value.
+ * \param userdata: Argument passed to all callbacks.
+ */
void BLI_bvhtree_walk_dfs(BVHTree *tree,
BVHTree_WalkParentCallback walk_parent_cb,
BVHTree_WalkLeafCallback walk_leaf_cb,
BVHTree_WalkOrderCallback walk_order_cb,
void *userdata);
-/* expose for bvh callbacks to use */
+/**
+ * Expose for BVH callbacks to use.
+ */
extern const float bvhtree_kdop_axes[13][3];
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_kdtree.h b/source/blender/blenlib/BLI_kdtree.h
index 76f39dfbacb..bb61ba17d99 100644
--- a/source/blender/blenlib/BLI_kdtree.h
+++ b/source/blender/blenlib/BLI_kdtree.h
@@ -22,7 +22,7 @@ extern "C" {
/** \file
* \ingroup bli
- * \brief A kd-tree for nearest neighbor search.
+ * \brief A KD-tree for nearest neighbor search.
*/
/* 1D version */
diff --git a/source/blender/blenlib/BLI_kdtree_impl.h b/source/blender/blenlib/BLI_kdtree_impl.h
index 4b2a37830ae..b15ae4a8a24 100644
--- a/source/blender/blenlib/BLI_kdtree_impl.h
+++ b/source/blender/blenlib/BLI_kdtree_impl.h
@@ -16,7 +16,7 @@
/** \file
* \ingroup bli
- * \brief A kd-tree for nearest neighbor search.
+ * \brief A KD-tree for nearest neighbor search.
*/
#include "BLI_compiler_attrs.h"
@@ -47,12 +47,12 @@ int BLI_kdtree_nd_(find_nearest)(const KDTree *tree,
int BLI_kdtree_nd_(find_nearest_n)(const KDTree *tree,
const float co[KD_DIMS],
KDTreeNearest *r_nearest,
- const uint nearest_len_capacity) ATTR_NONNULL(1, 2, 3);
+ uint nearest_len_capacity) ATTR_NONNULL(1, 2, 3);
int BLI_kdtree_nd_(range_search)(const KDTree *tree,
const float co[KD_DIMS],
KDTreeNearest **r_nearest,
- const float range) ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
+ float range) ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
int BLI_kdtree_nd_(find_nearest_cb)(
const KDTree *tree,
@@ -68,18 +68,18 @@ void BLI_kdtree_nd_(range_search_cb)(
void *user_data);
int BLI_kdtree_nd_(calc_duplicates_fast)(const KDTree *tree,
- const float range,
+ float range,
bool use_index_order,
int *doubles);
int BLI_kdtree_nd_(deduplicate)(KDTree *tree);
-/* Versions of find/range search that take a squared distance callback to support bias. */
+/** Versions of find/range search that take a squared distance callback to support bias. */
int BLI_kdtree_nd_(find_nearest_n_with_len_squared_cb)(
const KDTree *tree,
const float co[KD_DIMS],
KDTreeNearest *r_nearest,
- const uint nearest_len_capacity,
+ uint nearest_len_capacity,
float (*len_sq_fn)(const float co_search[KD_DIMS],
const float co_test[KD_DIMS],
const void *user_data),
@@ -88,7 +88,7 @@ int BLI_kdtree_nd_(range_search_with_len_squared_cb)(
const KDTree *tree,
const float co[KD_DIMS],
KDTreeNearest **r_nearest,
- const float range,
+ float range,
float (*len_sq_fn)(const float co_search[KD_DIMS],
const float co_test[KD_DIMS],
const void *user_data),
diff --git a/source/blender/blenlib/BLI_lasso_2d.h b/source/blender/blenlib/BLI_lasso_2d.h
index e920d1189a2..2e4a2ed22b4 100644
--- a/source/blender/blenlib/BLI_lasso_2d.h
+++ b/source/blender/blenlib/BLI_lasso_2d.h
@@ -29,19 +29,19 @@ extern "C" {
struct rcti;
-void BLI_lasso_boundbox(struct rcti *rect, const int mcoords[][2], const unsigned int mcoords_len);
-bool BLI_lasso_is_point_inside(const int mcoords[][2],
- const unsigned int mcoords_len,
- const int sx,
- const int sy,
- const int error_value);
+void BLI_lasso_boundbox(struct rcti *rect, const int mcoords[][2], unsigned int mcoords_len);
+bool BLI_lasso_is_point_inside(
+ const int mcoords[][2], unsigned int mcoords_len, int sx, int sy, int error_value);
+/**
+ * Edge version for lasso select. We assume bound-box check was done.
+ */
bool BLI_lasso_is_edge_inside(const int mcoords[][2],
- const unsigned int mcoords_len,
+ unsigned int mcoords_len,
int x0,
int y0,
int x1,
int y1,
- const int error_value);
+ int error_value);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_linklist.h b/source/blender/blenlib/BLI_linklist.h
index 25d58a3050c..d872921defc 100644
--- a/source/blender/blenlib/BLI_linklist.h
+++ b/source/blender/blenlib/BLI_linklist.h
@@ -58,8 +58,15 @@ LinkNode *BLI_linklist_find_last(LinkNode *list) ATTR_WARN_UNUSED_RESULT;
void BLI_linklist_reverse(LinkNode **listp) ATTR_NONNULL(1);
+/**
+ * Move an item from its current position to a new one inside a single-linked list.
+ * \note `*listp` may be modified.
+ */
void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index) ATTR_NONNULL(1);
+/**
+ * A version of #BLI_linklist_prepend that takes the allocated link.
+ */
void BLI_linklist_prepend_nlink(LinkNode **listp, void *ptr, LinkNode *nlink) ATTR_NONNULL(1, 3);
void BLI_linklist_prepend(LinkNode **listp, void *ptr) ATTR_NONNULL(1);
void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, struct MemArena *ma)
@@ -67,7 +74,11 @@ void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, struct MemArena *ma
void BLI_linklist_prepend_pool(LinkNode **listp, void *ptr, struct BLI_mempool *mempool)
ATTR_NONNULL(1, 3);
-/* use LinkNodePair to avoid full search */
+/* Use #LinkNodePair to avoid full search. */
+
+/**
+ * A version of append that takes the allocated link.
+ */
void BLI_linklist_append_nlink(LinkNodePair *list_pair, void *ptr, LinkNode *nlink)
ATTR_NONNULL(1, 3);
void BLI_linklist_append(LinkNodePair *list_pair, void *ptr) ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_linklist_lockfree.h b/source/blender/blenlib/BLI_linklist_lockfree.h
index 142fa1cf243..d2083bdd44e 100644
--- a/source/blender/blenlib/BLI_linklist_lockfree.h
+++ b/source/blender/blenlib/BLI_linklist_lockfree.h
@@ -48,18 +48,19 @@ typedef void (*LockfreeeLinkNodeFreeFP)(void *link);
/* NOTE: These functions are NOT safe for use from threads. */
/* NOTE: !!! I REPEAT: DO NOT USE THEM WITHOUT EXTERNAL LOCK !!! */
-/* Make list ready for lock-free access. */
+/** Make list ready for lock-free access. */
void BLI_linklist_lockfree_init(LockfreeLinkList *list);
-/* Completely free the whole list, it is NOT re-usable after this. */
+/** Completely free the whole list, it is NOT re-usable after this. */
void BLI_linklist_lockfree_free(LockfreeLinkList *list, LockfreeeLinkNodeFreeFP free_func);
-/* Remove all the elements from the list, keep it usable for further
- * inserts.
+/**
+ * Remove all the elements from the list, keep it usable for further inserts.
*/
void BLI_linklist_lockfree_clear(LockfreeLinkList *list, LockfreeeLinkNodeFreeFP free_func);
-/* Begin iteration of lock-free linked list, starting with a
+/**
+ * Begin iteration of lock-free linked list, starting with a
* first user=defined node. Will ignore the dummy node.
*/
LockfreeLinkNode *BLI_linklist_lockfree_begin(LockfreeLinkList *list);
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index 345d9d93d03..f73d1f22502 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -33,85 +33,238 @@
extern "C" {
#endif
+/**
+ * Returns the position of \a vlink within \a listbase, numbering from 0, or -1 if not found.
+ */
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Returns the 0-based index of the first element of listbase which contains the specified
+ * null-terminated string at the specified offset, or -1 if not found.
+ */
int BLI_findstringindex(const struct ListBase *listbase,
const char *id,
- const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+
+/**
+ * Return a ListBase representing the entire list the given Link is in.
+ */
+ListBase BLI_listbase_from_link(struct Link *some_link);
-/* find forwards */
+/* Find forwards. */
+
+/**
+ * Returns the nth element of \a listbase, numbering from 0.
+ */
void *BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Finds the first element of \a listbase which contains the null-terminated
+ * string \a id at the specified offset, returning NULL if not found.
+ */
void *BLI_findstring(const struct ListBase *listbase,
const char *id,
- const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the first element of \a listbase which contains a pointer to the
+ * null-terminated string \a id at the specified offset, returning NULL if not found.
+ */
void *BLI_findstring_ptr(const struct ListBase *listbase,
const char *id,
- const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the first element of listbase which contains the specified pointer value
+ * at the specified offset, returning NULL if not found.
+ */
void *BLI_findptr(const struct ListBase *listbase,
const void *ptr,
- const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the first element of listbase which contains the specified bytes
+ * at the specified offset, returning NULL if not found.
+ */
void *BLI_listbase_bytes_find(const ListBase *listbase,
const void *bytes,
- const size_t bytes_size,
- const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+ size_t bytes_size,
+ int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+/**
+ * Find the first item in the list that matches the given string, or the given index as fallback.
+ *
+ * \note The string is only used is non-NULL and non-empty.
+ *
+ * \return The found item, or NULL.
+ */
+void *BLI_listbase_string_or_index_find(const struct ListBase *listbase,
+ const char *string,
+ size_t string_offset,
+ int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+
+/* Find backwards. */
-/* find backwards */
+/**
+ * Returns the nth-last element of \a listbase, numbering from 0.
+ */
void *BLI_rfindlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Finds the last element of \a listbase which contains the
+ * null-terminated string \a id at the specified offset, returning NULL if not found.
+ */
void *BLI_rfindstring(const struct ListBase *listbase,
const char *id,
- const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the last element of \a listbase which contains a pointer to the
+ * null-terminated string \a id at the specified offset, returning NULL if not found.
+ */
void *BLI_rfindstring_ptr(const struct ListBase *listbase,
const char *id,
- const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the last element of listbase which contains the specified pointer value
+ * at the specified offset, returning NULL if not found.
+ */
void *BLI_rfindptr(const struct ListBase *listbase,
const void *ptr,
- const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the last element of listbase which contains the specified bytes
+ * at the specified offset, returning NULL if not found.
+ */
void *BLI_listbase_bytes_rfind(const ListBase *listbase,
const void *bytes,
- const size_t bytes_size,
- const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+ size_t bytes_size,
+ int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+/**
+ * Removes and disposes of the entire contents of \a listbase using guardedalloc.
+ */
void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1);
+/**
+ * Appends \a vlink (assumed to begin with a Link) onto listbase.
+ */
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Removes \a vlink from \a listbase. Assumes it is linked into there!
+ */
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Checks that \a vlink is linked into listbase, removing it from there if so.
+ */
bool BLI_remlink_safe(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Removes the head from \a listbase and returns it.
+ */
void *BLI_pophead(ListBase *listbase) ATTR_NONNULL(1);
+/**
+ * Removes the tail from \a listbase and returns it.
+ */
void *BLI_poptail(ListBase *listbase) ATTR_NONNULL(1);
+/**
+ * Prepends \a vlink (assumed to begin with a Link) onto listbase.
+ */
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Inserts \a vnewlink immediately preceding \a vnextlink in listbase.
+ * Or, if \a vnextlink is NULL, puts \a vnewlink at the end of the list.
+ */
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink)
ATTR_NONNULL(1);
+/**
+ * Inserts \a vnewlink immediately following \a vprevlink in \a listbase.
+ * Or, if \a vprevlink is NULL, puts \a vnewlink at the front of the list.
+ */
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink)
ATTR_NONNULL(1);
+/**
+ * Insert a link in place of another, without changing its position in the list.
+ *
+ * Puts `vnewlink` in the position of `vreplacelink`, removing `vreplacelink`.
+ * - `vreplacelink` *must* be in the list.
+ * - `vnewlink` *must not* be in the list.
+ */
void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
ATTR_NONNULL(1, 2, 3);
+/**
+ * Sorts the elements of listbase into the order defined by cmp
+ * (which should return 1 if its first arg should come after its second arg).
+ * This uses insertion sort, so NOT ok for large list.
+ */
void BLI_listbase_sort(struct ListBase *listbase, int (*cmp)(const void *, const void *))
ATTR_NONNULL(1, 2);
void BLI_listbase_sort_r(ListBase *listbase,
int (*cmp)(void *, const void *, const void *),
void *thunk) ATTR_NONNULL(1, 2);
+/**
+ * Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move
+ * item if new position would exceed list (could optionally move to head/tail).
+ *
+ * \param step: Absolute value defines step size, sign defines direction. E.g pass -1
+ * to move \a vlink before previous, or 1 to move behind next.
+ * \return If position of \a vlink has changed.
+ */
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL();
+/**
+ * Move the link at the index \a from to the position at index \a to.
+ *
+ * \return If the move was successful.
+ */
bool BLI_listbase_move_index(ListBase *listbase, int from, int to) ATTR_NONNULL();
+/**
+ * Removes and disposes of the entire contents of listbase using direct free(3).
+ */
void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1);
+/**
+ * Returns the number of elements in \a listbase, up until (and including count_max)
+ *
+ * \note Use to avoid redundant looping.
+ */
int BLI_listbase_count_at_most(const struct ListBase *listbase,
- const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Returns the number of elements in \a listbase.
+ */
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Removes \a vlink from listbase and disposes of it. Assumes it is linked into there!
+ */
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Swaps \a vlinka and \a vlinkb in the list. Assumes they are both already in the list!
+ */
void BLI_listbase_swaplinks(struct ListBase *listbase, void *vlinka, void *vlinkb)
ATTR_NONNULL(1, 2);
+/**
+ * Swaps \a vlinka and \a vlinkb from their respective lists.
+ * Assumes they are both already in their \a listbasea!
+ */
void BLI_listbases_swaplinks(struct ListBase *listbasea,
struct ListBase *listbaseb,
void *vlinka,
void *vlinkb) ATTR_NONNULL(2, 3);
+/**
+ * Moves the entire contents of \a src onto the end of \a dst.
+ */
void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2);
+/**
+ * Moves the entire contents of \a src at the beginning of \a dst.
+ */
void BLI_movelisttolist_reverse(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2);
+/**
+ * Sets dst to a duplicate of the entire contents of src. dst may be the same as src.
+ */
void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1, 2);
void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1);
+/**
+ * \param vlink: Link to make first.
+ */
void BLI_listbase_rotate_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
+/**
+ * \param vlink: Link to make last.
+ */
void BLI_listbase_rotate_last(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
/**
@@ -130,7 +283,26 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
lb->first = lb->last = (void *)0;
}
-/* create a generic list node containing link to provided data */
+/**
+ * Equality check for ListBase.
+ *
+ * This only shallowly compares the ListBase itself (so the first/last
+ * pointers), and does not do any equality checks on the list items.
+ */
+BLI_INLINE bool BLI_listbase_equal(const struct ListBase *a, const struct ListBase *b)
+{
+ if (a == NULL) {
+ return b == NULL;
+ }
+ if (b == NULL) {
+ return false;
+ }
+ return a->first == b->first && a->last == b->last;
+}
+
+/**
+ * Create a generic list node containing link to provided data.
+ */
struct LinkData *BLI_genericNodeN(void *data);
/**
@@ -184,13 +356,17 @@ struct LinkData *BLI_genericNodeN(void *data);
#define LISTBASE_FOREACH_BACKWARD(type, var, list) \
for (type var = (type)((list)->last); var != NULL; var = (type)(((Link *)(var))->prev))
-/** A version of #LISTBASE_FOREACH that supports removing the item we're looping over. */
+/**
+ * A version of #LISTBASE_FOREACH that supports removing the item we're looping over.
+ */
#define LISTBASE_FOREACH_MUTABLE(type, var, list) \
for (type var = (type)((list)->first), *var##_iter_next; \
((var != NULL) ? ((void)(var##_iter_next = (type)(((Link *)(var))->next)), 1) : 0); \
var = var##_iter_next)
-/** A version of #LISTBASE_FOREACH_BACKWARD that supports removing the item we're looping over. */
+/**
+ * A version of #LISTBASE_FOREACH_BACKWARD that supports removing the item we're looping over.
+ */
#define LISTBASE_FOREACH_BACKWARD_MUTABLE(type, var, list) \
for (type var = (type)((list)->last), *var##_iter_prev; \
((var != NULL) ? ((void)(var##_iter_prev = (type)(((Link *)(var))->prev)), 1) : 0); \
@@ -199,3 +375,10 @@ struct LinkData *BLI_genericNodeN(void *data);
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+BLI_INLINE bool operator==(const ListBase &a, const ListBase &b)
+{
+ return BLI_listbase_equal(&a, &b);
+}
+#endif
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 9b54f780296..f6462233106 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -76,8 +76,7 @@
#if defined(__GNUC__)
# define NAN_FLT __builtin_nanf("")
-#else
-/* evil quiet NaN definition */
+#else /* evil quiet NaN definition */
static const int NAN_INT = 0x7FC00000;
# define NAN_FLT (*((float *)(&NAN_INT)))
#endif
@@ -97,6 +96,8 @@ extern "C" {
/******************************* Float ******************************/
+/* `powf` is really slow for raising to integer powers. */
+
MINLINE float pow2f(float x);
MINLINE float pow3f(float x);
MINLINE float pow4f(float x);
@@ -120,11 +121,18 @@ MINLINE double interpd(double a, double b, double t);
MINLINE float ratiof(float min, float max, float pos);
MINLINE double ratiod(double min, double max, double pos);
+/**
+ * Map a normalized value, i.e. from interval [0, 1] to interval [a, b].
+ */
MINLINE float scalenorm(float a, float b, float x);
+/**
+ * Map a normalized value, i.e. from interval [0, 1] to interval [a, b].
+ */
MINLINE double scalenormd(double a, double b, double x);
/* NOTE: Compilers will upcast all types smaller than int to int when performing arithmetic
* operation. */
+
MINLINE int square_s(short a);
MINLINE int square_uchar(unsigned char a);
MINLINE int cube_s(short a);
@@ -170,23 +178,49 @@ MINLINE int clamp_i(int value, int min, int max);
MINLINE float clamp_f(float value, float min, float max);
MINLINE size_t clamp_z(size_t value, size_t min, size_t max);
-MINLINE int compare_ff(float a, float b, const float max_diff);
-MINLINE int compare_ff_relative(float a, float b, const float max_diff, const int max_ulps);
-MINLINE bool compare_threshold_relative(const float value1,
- const float value2,
- const float thresh);
+/**
+ * Almost-equal for IEEE floats, using absolute difference method.
+ *
+ * \param max_diff: the maximum absolute difference.
+ */
+MINLINE int compare_ff(float a, float b, float max_diff);
+/**
+ * Almost-equal for IEEE floats, using their integer representation
+ * (mixing ULP and absolute difference methods).
+ *
+ * \param max_diff: is the maximum absolute difference (allows to take care of the near-zero area,
+ * where relative difference methods cannot really work).
+ * \param max_ulps: is the 'maximum number of floats + 1'
+ * allowed between \a a and \a b to consider them equal.
+ *
+ * \see https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
+ */
+MINLINE int compare_ff_relative(float a, float b, float max_diff, int max_ulps);
+MINLINE bool compare_threshold_relative(float value1, float value2, float thresh);
MINLINE float signf(float f);
MINLINE int signum_i_ex(float a, float eps);
MINLINE int signum_i(float a);
+/**
+ * Used for zoom values.
+ */
MINLINE float power_of_2(float f);
-MINLINE int integer_digits_f(const float f);
-MINLINE int integer_digits_d(const double d);
-MINLINE int integer_digits_i(const int i);
+/**
+ * Returns number of (base ten) *significant* digits of integer part of given float
+ * (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
+ */
+MINLINE int integer_digits_f(float f);
+/**
+ * Returns number of (base ten) *significant* digits of integer part of given double
+ * (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
+ */
+MINLINE int integer_digits_d(double d);
+MINLINE int integer_digits_i(int i);
+
+/* These don't really fit anywhere but were being copied about a lot. */
-/* these don't really fit anywhere but were being copied about a lot */
MINLINE int is_power_of_2_i(int n);
MINLINE int power_of_2_max_i(int n);
MINLINE int power_of_2_min_i(int n);
@@ -196,9 +230,19 @@ MINLINE unsigned int power_of_2_min_u(unsigned int x);
MINLINE unsigned int log2_floor_u(unsigned int x);
MINLINE unsigned int log2_ceil_u(unsigned int x);
+/**
+ * Integer division that rounds 0.5 up, particularly useful for color blending
+ * with integers, to avoid gradual darkening when rounding down.
+ */
MINLINE int divide_round_i(int a, int b);
+/**
+ * modulo that handles negative numbers, works the same as Python's.
+ */
MINLINE int mod_i(int i, int n);
+/**
+ * Round to closest even number, halfway cases are rounded away from zero.
+ */
MINLINE float round_to_even(float f);
MINLINE signed char round_fl_to_char(float a);
@@ -230,18 +274,40 @@ MINLINE int round_db_to_int_clamp(double a);
MINLINE unsigned int round_db_to_uint_clamp(double a);
int pow_i(int base, int exp);
+
+/**
+ * \param ndigits: must be between 0 and 21.
+ */
double double_round(double x, int ndigits);
+/**
+ * Floor to the nearest power of 10, e.g.:
+ * - 15.0 -> 10.0
+ * - 0.015 -> 0.01
+ * - 1.0 -> 1.0
+ *
+ * \param f: Value to floor, must be over 0.0.
+ * \note If we wanted to support signed values we could if this becomes necessary.
+ */
float floor_power_of_10(float f);
+/**
+ * Ceiling to the nearest power of 10, e.g.:
+ * - 15.0 -> 100.0
+ * - 0.015 -> 0.1
+ * - 1.0 -> 1.0
+ *
+ * \param f: Value to ceiling, must be over 0.0.
+ * \note If we wanted to support signed values we could if this becomes necessary.
+ */
float ceil_power_of_10(float f);
#ifdef BLI_MATH_GCC_WARN_PRAGMA
# pragma GCC diagnostic pop
#endif
-/* asserts, some math functions expect normalized inputs
- * check the vector is unit length, or zero length (which can't be helped in some cases).
- */
+/* Asserts, some math functions expect normalized inputs
+ * check the vector is unit length, or zero length (which can't be helped in some cases). */
+
#ifndef NDEBUG
/** \note 0.0001 is too small because normals may be converted from short's: see T34322. */
# define BLI_ASSERT_UNIT_EPSILON 0.0002f
diff --git a/source/blender/blenlib/BLI_math_bits.h b/source/blender/blenlib/BLI_math_bits.h
index e881f1a0e4e..70a54879446 100644
--- a/source/blender/blenlib/BLI_math_bits.h
+++ b/source/blender/blenlib/BLI_math_bits.h
@@ -28,24 +28,29 @@ extern "C" {
#endif
/* Search the value from LSB to MSB for a set bit. Returns index of this bit. */
+
MINLINE int bitscan_forward_i(int a);
MINLINE unsigned int bitscan_forward_uint(unsigned int a);
MINLINE unsigned int bitscan_forward_uint64(unsigned long long a);
/* Similar to above, but also clears the bit. */
+
MINLINE int bitscan_forward_clear_i(int *a);
MINLINE unsigned int bitscan_forward_clear_uint(unsigned int *a);
/* Search the value from MSB to LSB for a set bit. Returns index of this bit. */
+
MINLINE int bitscan_reverse_i(int a);
MINLINE unsigned int bitscan_reverse_uint(unsigned int a);
MINLINE unsigned int bitscan_reverse_uint64(unsigned long long a);
/* Similar to above, but also clears the bit. */
+
MINLINE int bitscan_reverse_clear_i(int *a);
MINLINE unsigned int bitscan_reverse_clear_uint(unsigned int *a);
/* NOTE: Those functions returns 2 to the power of index of highest order bit. */
+
MINLINE unsigned int highest_order_bit_uint(unsigned int n);
MINLINE unsigned short highest_order_bit_s(unsigned short n);
diff --git a/source/blender/blenlib/BLI_math_boolean.hh b/source/blender/blenlib/BLI_math_boolean.hh
index 79b1483bfb8..8cf93c82dec 100644
--- a/source/blender/blenlib/BLI_math_boolean.hh
+++ b/source/blender/blenlib/BLI_math_boolean.hh
@@ -21,31 +21,33 @@
* \brief Math vector functions needed specifically for mesh intersect and boolean.
*/
-#include "BLI_double2.hh"
-#include "BLI_double3.hh"
+#include "BLI_math_vec_types.hh"
#ifdef WITH_GMP
# include "BLI_math_mpq.hh"
-# include "BLI_mpq2.hh"
-# include "BLI_mpq3.hh"
+# include "BLI_math_vec_mpq_types.hh"
#endif
namespace blender {
-/* #orient2d gives the exact result, using multi-precision arithmetic when result
+/**
+ * #orient2d gives the exact result, using multi-precision arithmetic when result
* is close to zero. orient3d_fast just uses double arithmetic, so may be
* wrong if the answer is very close to zero.
- * Similarly, for #incircle and #incircle_fast. */
+ * Similarly, for #incircle and #incircle_fast.
+ */
int orient2d(const double2 &a, const double2 &b, const double2 &c);
int orient2d_fast(const double2 &a, const double2 &b, const double2 &c);
int incircle(const double2 &a, const double2 &b, const double2 &c, const double2 &d);
int incircle_fast(const double2 &a, const double2 &b, const double2 &c, const double2 &d);
-/* #orient3d gives the exact result, using multi-precision arithmetic when result
+/**
+ * #orient3d gives the exact result, using multi-precision arithmetic when result
* is close to zero. orient3d_fast just uses double arithmetic, so may be
* wrong if the answer is very close to zero.
- * Similarly, for #insphere and #insphere_fast. */
+ * Similarly, for #insphere and #insphere_fast.
+ */
int orient3d(const double3 &a, const double3 &b, const double3 &c, const double3 &d);
int orient3d_fast(const double3 &a, const double3 &b, const double3 &c, const double3 &d);
@@ -55,8 +57,23 @@ int insphere_fast(
const double3 &a, const double3 &b, const double3 &c, const double3 &d, const double3 &e);
#ifdef WITH_GMP
+/**
+ * Return +1 if a, b, c are in CCW order around a circle in the plane.
+ * Return -1 if they are in CW order, and 0 if they are in line.
+ */
int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c);
+/**
+ * Return +1 if d is in the oriented circle through a, b, and c.
+ * The oriented circle goes CCW through a, b, and c.
+ * Return -1 if d is outside, and 0 if it is on the circle.
+ */
int incircle(const mpq2 &a, const mpq2 &b, const mpq2 &c, const mpq2 &d);
+/**
+ * Return +1 if d is below the plane containing a, b, c (which appear
+ * CCW when viewed from above the plane).
+ * Return -1 if d is above the plane.
+ * Return 0 if it is on the plane.
+ */
int orient3d(const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &d);
#endif
} // namespace blender
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index 28257ba418a..0798acbb790 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -31,6 +31,10 @@
extern "C" {
#endif
+/* -------------------------------------------------------------------- */
+/** \name Defines
+ * \{ */
+
/* YCbCr */
#define BLI_YCC_ITU_BT601 0
#define BLI_YCC_ITU_BT709 1
@@ -40,7 +44,11 @@ extern "C" {
#define BLI_YUV_ITU_BT601 0
#define BLI_YUV_ITU_BT709 1
-/******************* Conversion to RGB ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Conversion to RGB
+ * \{ */
void hsv_to_rgb(float h, float s, float v, float *r_r, float *r_g, float *r_b);
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3]);
@@ -51,9 +59,18 @@ void yuv_to_rgb(float y, float u, float v, float *r_r, float *r_g, float *r_b, i
void ycc_to_rgb(float y, float cb, float cr, float *r_r, float *r_g, float *r_b, int colorspace);
void cpack_to_rgb(unsigned int col, float *r_r, float *r_g, float *r_b);
-/***************** Conversion from RGB ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Conversion from RGB
+ * \{ */
void rgb_to_yuv(float r, float g, float b, float *r_y, float *r_u, float *r_v, int colorspace);
+/**
+ * The RGB inputs are supposed gamma corrected and in the range 0 - 1.0f
+ *
+ * Output YCC have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255.
+ */
void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr, int colorspace);
void rgb_to_hsv(float r, float g, float b, float *r_h, float *r_s, float *r_v);
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3]);
@@ -64,9 +81,19 @@ void rgb_to_hsl_compat_v(const float rgb[3], float r_hsl[3]);
void rgb_to_hsv_compat(float r, float g, float b, float *r_h, float *r_s, float *r_v);
void rgb_to_hsv_compat_v(const float rgb[3], float r_hsv[3]);
unsigned int rgb_to_cpack(float r, float g, float b);
+/**
+ * We define a 'cpack' here as a (3 byte color code)
+ * number that can be expressed like 0xFFAA66 or so.
+ * For that reason it is sensitive for endianness... with this function it works correctly.
+ * \see #imm_cpack
+ */
unsigned int hsv_to_cpack(float h, float s, float v);
-/**************** Profile Transformations *****************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Profile Transformations
+ * \{ */
float srgb_to_linearrgb(float c);
float linearrgb_to_srgb(float c);
@@ -80,7 +107,7 @@ MINLINE void linearrgb_to_srgb_v4(float srgb[4], const float linear[4]);
MINLINE void srgb_to_linearrgb_predivide_v4(float linear[4], const float srgb[4]);
MINLINE void linearrgb_to_srgb_predivide_v4(float srgb[4], const float linear[4]);
-MINLINE unsigned short to_srgb_table_lookup(const float f);
+MINLINE unsigned short to_srgb_table_lookup(float f);
MINLINE void linearrgb_to_srgb_ushort4(unsigned short srgb[4], const float linear[4]);
MINLINE void srgb_to_linearrgb_uchar4(float linear[4], const unsigned char srgb[4]);
MINLINE void srgb_to_linearrgb_uchar4_predivide(float linear[4], const unsigned char srgb[4]);
@@ -90,7 +117,11 @@ MINLINE void linearrgb_to_srgb_uchar4(unsigned char srgb[4], const float linear[
void BLI_init_srgb_conversion(void);
-/**************** Alpha Transformations *****************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Alpha Transformations
+ * \{ */
MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4]);
MINLINE void premul_to_straight_v4(float color[4]);
@@ -99,13 +130,34 @@ MINLINE void straight_to_premul_v4(float color[4]);
MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4]);
MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4]);
-/************************** Other *************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Other
+ * \{ */
+
+/**
+ * If the requested RGB shade contains a negative weight for
+ * one of the primaries, it lies outside the color gamut
+ * accessible from the given triple of primaries. Desaturate
+ * it by adding white, equal quantities of R, G, and B, enough
+ * to make RGB all positive. The function returns 1 if the
+ * components were modified, zero otherwise.
+ */
int constrain_rgb(float *r, float *g, float *b);
void minmax_rgb(short c[3]);
+/**
+ * Clamp `hsv` to usable values.
+ */
void hsv_clamp_v(float hsv[3], float v_max);
+/**
+ * Applies an HUE offset to a float RGB color.
+ */
void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset);
+/**
+ * Applies an HUE offset to a byte RGB color.
+ */
void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset);
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3]);
@@ -113,11 +165,28 @@ void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4]);
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3]);
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4]);
+/**
+ * ITU-R BT.709 primaries
+ * https://en.wikipedia.org/wiki/Relative_luminance
+ *
+ * Real values are:
+ * `Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)`
+ * according to: "Derivation of Basic Television Color Equations", RP 177-1993
+ *
+ * As this sums slightly above 1.0, the document recommends to use:
+ * `0.2126(R) + 0.7152(G) + 0.0722(B)`, as used here.
+ *
+ * The high precision values are used to calculate the rounded byte weights so they add up to 255:
+ * `54(R) + 182(G) + 19(B)`
+ */
MINLINE float rgb_to_grayscale(const float rgb[3]);
MINLINE unsigned char rgb_to_grayscale_byte(const unsigned char rgb[3]);
-MINLINE int compare_rgb_uchar(const unsigned char a[3], const unsigned char b[3], const int limit);
+MINLINE int compare_rgb_uchar(const unsigned char a[3], const unsigned char b[3], int limit);
+/**
+ * Return triangle noise in [-0.5..1.5] range.
+ */
MINLINE float dither_random_value(float s, float t);
MINLINE void float_to_byte_dither_v3(
unsigned char b[3], const float f[3], float dither, float s, float t);
@@ -128,24 +197,21 @@ MINLINE void float_to_byte_dither_v3(
#define rgba_float_args_set_ch(col, r, g, b, a) \
rgba_float_args_set(col, (r) / 255.0f, (g) / 255.0f, (b) / 255.0f, (a) / 255.0f)
-MINLINE void rgba_uchar_args_set(unsigned char col[4],
- const unsigned char r,
- const unsigned char g,
- const unsigned char b,
- const unsigned char a);
-MINLINE void rgba_float_args_set(
- float col[4], const float r, const float g, const float b, const float a);
-MINLINE void rgba_uchar_args_test_set(unsigned char col[4],
- const unsigned char r,
- const unsigned char g,
- const unsigned char b,
- const unsigned char a);
-MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack);
+MINLINE void rgba_uchar_args_set(
+ unsigned char col[4], unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+MINLINE void rgba_float_args_set(float col[4], float r, float g, float b, float a);
+MINLINE void rgba_uchar_args_test_set(
+ unsigned char col[4], unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+MINLINE void cpack_cpy_3ub(unsigned char r_col[3], unsigned int pack);
void blackbody_temperature_to_rgb_table(float *r_table, int width, float min, float max);
void wavelength_to_xyz_table(float *r_table, int width);
-/********* lift/gamma/gain / ASC-CDL conversion ***********/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name lift/gamma/gain / ASC-CDL conversion
+ * \{ */
void lift_gamma_gain_to_asc_cdl(const float *lift,
const float *gamma,
@@ -158,6 +224,8 @@ void lift_gamma_gain_to_asc_cdl(const float *lift,
# include "intern/math_color_inline.c"
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 3cef82eb995..6d7159f73c6 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -37,16 +37,24 @@
extern "C" {
#endif
-/********************************** Polygons *********************************/
+/* -------------------------------------------------------------------- */
+/** \name Polygons
+ * \{ */
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3]);
float normal_quad_v3(
float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
+/**
+ * Computes the normal of a planar polygon See Graphics Gems for computing newell normal.
+ */
float normal_poly_v3(float n[3], const float verts[][3], unsigned int nr);
MINLINE float area_tri_v2(const float v1[2], const float v2[2], const float v3[2]);
MINLINE float area_squared_tri_v2(const float v1[2], const float v2[2], const float v3[2]);
MINLINE float area_tri_signed_v2(const float v1[2], const float v2[2], const float v3[2]);
+
+/* Triangles */
+
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3]);
float area_squared_tri_v3(const float v1[3], const float v2[3], const float v3[3]);
float area_tri_signed_v3(const float v1[3],
@@ -68,38 +76,88 @@ float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float
void cross_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3]);
MINLINE float cross_tri_v2(const float v1[2], const float v2[2], const float v3[2]);
void cross_poly_v3(float n[3], const float verts[][3], unsigned int nr);
+/**
+ * Scalar cross product of a 2d polygon.
+ *
+ * - equivalent to `area * 2`
+ * - useful for checking polygon winding (a positive value is clockwise).
+ */
float cross_poly_v2(const float verts[][2], unsigned int nr);
-/********************************* Planes **********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Planes
+ * \{ */
+/**
+ * Calculate a plane from a point and a direction,
+ * \note \a point_no isn't required to be normalized.
+ */
void plane_from_point_normal_v3(float r_plane[4],
const float plane_co[3],
const float plane_no[3]);
+/**
+ * Get a point and a direction from a plane.
+ */
void plane_to_point_vector_v3(const float plane[4], float r_plane_co[3], float r_plane_no[3]);
+/**
+ * Version of #plane_to_point_vector_v3 that gets a unit length vector.
+ */
void plane_to_point_vector_v3_normalized(const float plane[4],
float r_plane_co[3],
float r_plane_no[3]);
MINLINE float plane_point_side_v3(const float plane[4], const float co[3]);
-/********************************* Volume **********************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Volume
+ * \{ */
+
+/**
+ * The volume from a tetrahedron, points can be in any order
+ */
float volume_tetrahedron_v3(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3]);
+/**
+ * The volume from a tetrahedron, normal pointing inside gives negative volume
+ */
float volume_tetrahedron_signed_v3(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3]);
+/**
+ * The volume from a triangle that is made into a tetrahedron.
+ * This uses a simplified formula where the tip of the tetrahedron is in the world origin.
+ * Using this method, the total volume of a closed triangle mesh can be calculated.
+ * Note that you need to divide the result by 6 to get the actual volume.
+ */
float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3]);
float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3]);
+/**
+ * Check if the edge is convex or concave
+ * (depends on face winding)
+ * Copied from BM_edge_is_convex().
+ */
bool is_edge_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
+/**
+ * Evaluate if entire quad is a proper convex quad
+ */
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
bool is_poly_convex_v2(const float verts[][2], unsigned int nr);
+/**
+ * Check if either of the diagonals along this quad create flipped triangles
+ * (normals pointing away from eachother).
+ * - (1 << 0): (v1-v3) is flipped.
+ * - (1 << 1): (v2-v4) is flipped.
+ */
int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_flip_v3_first_third_fast(const float v1[3],
const float v2[3],
@@ -111,36 +169,88 @@ bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
const float v4[3],
const float normal[3]);
-/********************************* Distance **********************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Distance
+ * \{ */
+
+/**
+ * Distance p to line v1-v2 using Hesse formula (NO LINE PIECE!)
+ */
float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l2[2]);
float dist_to_line_v2(const float p[2], const float l1[2], const float l2[2]);
+/**
+ * Distance p to line-piece v1-v2.
+ */
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2]);
float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2]);
float dist_signed_squared_to_plane_v3(const float p[3], const float plane[4]);
float dist_squared_to_plane_v3(const float p[3], const float plane[4]);
+/**
+ * Return the signed distance from the point to the plane.
+ */
float dist_signed_to_plane_v3(const float p[3], const float plane[4]);
float dist_to_plane_v3(const float p[3], const float plane[4]);
-/* plane3 versions */
+/* Plane3 versions. */
+
float dist_signed_squared_to_plane3_v3(const float p[3], const float plane[3]);
float dist_squared_to_plane3_v3(const float p[3], const float plane[3]);
float dist_signed_to_plane3_v3(const float p[3], const float plane[3]);
float dist_to_plane3_v3(const float p[3], const float plane[3]);
+/**
+ * Distance v1 to line-piece l1-l2 in 3D.
+ */
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3]);
float dist_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3]);
float dist_squared_to_line_v3(const float p[3], const float l1[3], const float l2[3]);
float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3]);
+/**
+ * Check if \a p is inside the 2x planes defined by `(v1, v2, v3)`
+ * where the 3x points define 2x planes.
+ *
+ * \param axis_ref: used when v1,v2,v3 form a line and to check if the corner is concave/convex.
+ *
+ * \note the distance from \a v1 & \a v3 to \a v2 doesn't matter
+ * (it just defines the planes).
+ *
+ * \return the lowest squared distance to either of the planes.
+ * where `(return < 0.0)` is outside.
+ *
+ * <pre>
+ * v1
+ * +
+ * /
+ * x - out / x - inside
+ * /
+ * +----+
+ * v2 v3
+ * x - also outside
+ * </pre>
+ */
float dist_signed_squared_to_corner_v3v3v3(const float p[3],
const float v1[3],
const float v2[3],
const float v3[3],
const float axis_ref[3]);
+/**
+ * Compute the squared distance of a point to a line (defined as ray).
+ * \param ray_origin: A point on the line.
+ * \param ray_direction: Normalized direction of the line.
+ * \param co: Point to which the distance is to be calculated.
+ */
float dist_squared_to_ray_v3_normalized(const float ray_origin[3],
const float ray_direction[3],
const float co[3]);
+/**
+ * Find the closest point in a seg to a ray and return the distance squared.
+ * \param r_point: Is the point on segment closest to ray
+ * (or to ray_origin if the ray and the segment are parallel).
+ * \param r_depth: the distance of r_point projection on ray to the ray_origin.
+ */
float dist_squared_ray_to_seg_v3(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -148,6 +258,9 @@ float dist_squared_ray_to_seg_v3(const float ray_origin[3],
float r_point[3],
float *r_depth);
+/**
+ * Returns the coordinates of the nearest vertex and the farthest vertex from a plane (or normal).
+ */
void aabb_get_near_far_from_plane(const float plane_no[3],
const float bbmin[3],
const float bbmax[3],
@@ -162,12 +275,17 @@ struct DistRayAABB_Precalc {
void dist_squared_ray_to_aabb_v3_precalc(struct DistRayAABB_Precalc *neasrest_precalc,
const float ray_origin[3],
const float ray_direction[3]);
+/**
+ * Returns the distance from a ray to a bound-box (projected on ray)
+ */
float dist_squared_ray_to_aabb_v3(const struct DistRayAABB_Precalc *data,
const float bb_min[3],
const float bb_max[3],
float r_point[3],
float *r_depth);
-/* when there is no advantage to precalc. */
+/**
+ * Use when there is no advantage to pre-calculation.
+ */
float dist_squared_ray_to_aabb_v3_simple(const float ray_origin[3],
const float ray_direction[3],
const float bb_min[3],
@@ -182,10 +300,17 @@ struct DistProjectedAABBPrecalc {
float pmat[4][4];
float mval[2];
};
+/**
+ * \param projmat: Projection Matrix (usually perspective
+ * matrix multiplied by object matrix).
+ */
void dist_squared_to_projected_aabb_precalc(struct DistProjectedAABBPrecalc *precalc,
const float projmat[4][4],
const float winsize[2],
const float mval[2]);
+/**
+ * Returns the distance from a 2D coordinate to a bound-box (projected).
+ */
float dist_squared_to_projected_aabb(struct DistProjectedAABBPrecalc *data,
const float bbmin[3],
const float bbmax[3],
@@ -205,55 +330,88 @@ double closest_to_line_v2_db(double r_close[2],
const double p[2],
const double l1[2],
const double l2[2]);
+/**
+ * Find closest point to p on line through (`l1`, `l2`) and return lambda,
+ * where (0 <= lambda <= 1) when `p` is in the line segment (`l1`, `l2`).
+ */
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]);
+/**
+ * Point closest to v1 on line v2-v3 in 2D.
+ */
void closest_to_line_segment_v2(float r_close[2],
const float p[2],
const float l1[2],
const float l2[2]);
+/**
+ * Point closest to v1 on line v2-v3 in 3D.
+ */
void closest_to_line_segment_v3(float r_close[3],
const float p[3],
const float l1[3],
const float l2[3]);
void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3]);
+/**
+ * Find the closest point on a plane.
+ *
+ * \param r_close: Return coordinate
+ * \param plane: The plane to test against.
+ * \param pt: The point to find the nearest of
+ *
+ * \note non-unit-length planes are supported.
+ */
void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3]);
void closest_to_plane3_normalized_v3(float r_close[3], const float plane[3], const float pt[3]);
void closest_to_plane3_v3(float r_close[3], const float plane[3], const float pt[3]);
-/* Set 'r' to the point in triangle (v1, v2, v3) closest to point 'p' */
+/**
+ * Set 'r' to the point in triangle (v1, v2, v3) closest to point 'p'.
+ */
void closest_on_tri_to_point_v3(
float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3]);
float ray_point_factor_v3_ex(const float p[3],
const float ray_origin[3],
const float ray_direction[3],
- const float epsilon,
- const float fallback);
+ float epsilon,
+ float fallback);
float ray_point_factor_v3(const float p[3],
const float ray_origin[3],
const float ray_direction[3]);
-float line_point_factor_v3_ex(const float p[3],
- const float l1[3],
- const float l2[3],
- const float epsilon,
- const float fallback);
+/**
+ * A simplified version of #closest_to_line_v3
+ * we only need to return the `lambda`
+ *
+ * \param epsilon: avoid approaching divide-by-zero.
+ * Passing a zero will just check for nonzero division.
+ */
+float line_point_factor_v3_ex(
+ const float p[3], const float l1[3], const float l2[3], float epsilon, float fallback);
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3]);
-float line_point_factor_v2_ex(const float p[2],
- const float l1[2],
- const float l2[2],
- const float epsilon,
- const float fallback);
+float line_point_factor_v2_ex(
+ const float p[2], const float l1[2], const float l2[2], float epsilon, float fallback);
float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2]);
+/**
+ * \note #isect_line_plane_v3() shares logic.
+ */
float line_plane_factor_v3(const float plane_co[3],
const float plane_no[3],
const float l1[3],
const float l2[3]);
-void limit_dist_v3(float v1[3], float v2[3], const float dist);
+/**
+ * Ensure the distance between these points is no greater than 'dist'.
+ * If it is, scale them both into the center.
+ */
+void limit_dist_v3(float v1[3], float v2[3], float dist);
+
+/** \} */
-/******************************* Intersection ********************************/
+/* -------------------------------------------------------------------- */
+/** \name Intersection
+ * \{ */
/* TODO: int return value consistency. */
@@ -263,7 +421,13 @@ void limit_dist_v3(float v1[3], float v2[3], const float dist);
#define ISECT_LINE_LINE_EXACT 1
#define ISECT_LINE_LINE_CROSS 2
+/**
+ * Intersect Line-Line, floats.
+ */
int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
+/**
+ * Returns a point on each segment that is closest to the other.
+ */
void isect_seg_seg_v3(const float a0[3],
const float a1[3],
const float b0[3],
@@ -271,12 +435,28 @@ void isect_seg_seg_v3(const float a0[3],
float r_a[3],
float r_b[3]);
+/**
+ * Intersect Line-Line, integer.
+ */
int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2]);
+/**
+ * Get intersection point of two 2D segments.
+ *
+ * \param endpoint_bias: Bias to use when testing for end-point overlap.
+ * A positive value considers intersections that extend past the endpoints,
+ * negative values contract the endpoints.
+ * Note the bias is applied to a 0-1 factor, not scaled to the length of segments.
+ *
+ * \returns intersection type:
+ * - -1: collinear.
+ * - 1: intersection.
+ * - 0: no intersection.
+ */
int isect_seg_seg_v2_point_ex(const float v0[2],
const float v1[2],
const float v2[2],
const float v3[2],
- const float endpoint_bias,
+ float endpoint_bias,
float vi[2]);
int isect_seg_seg_v2_point(
const float v0[2], const float v1[2], const float v2[2], const float v3[2], float vi[2]);
@@ -284,51 +464,95 @@ bool isect_seg_seg_v2_simple(const float v1[2],
const float v2[2],
const float v3[2],
const float v4[2]);
+/**
+ * If intersection == ISECT_LINE_LINE_CROSS or ISECT_LINE_LINE_NONE:
+ * <pre>
+ * pt = v1 + lambda * (v2 - v1) = v3 + mu * (v4 - v3)
+ * </pre>
+ * \returns intersection type:
+ * - ISECT_LINE_LINE_COLINEAR: collinear.
+ * - ISECT_LINE_LINE_EXACT: intersection at an endpoint of either.
+ * - ISECT_LINE_LINE_CROSS: interaction, not at an endpoint.
+ * - ISECT_LINE_LINE_NONE: no intersection.
+ * Also returns lambda and mu in r_lambda and r_mu.
+ */
int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
const double v2[2],
const double v3[2],
const double v4[2],
double *r_lambda,
double *r_mu);
+/**
+ * \param l1, l2: Coordinates (point of line).
+ * \param sp, r: Coordinate and radius (sphere).
+ * \return r_p1, r_p2: Intersection coordinates.
+ *
+ * \note The order of assignment for intersection points (\a r_p1, \a r_p2) is predictable,
+ * based on the direction defined by `l2 - l1`,
+ * this direction compared with the normal of each point on the sphere:
+ * \a r_p1 always has a >= 0.0 dot product.
+ * \a r_p2 always has a <= 0.0 dot product.
+ * For example, when \a l1 is inside the sphere and \a l2 is outside,
+ * \a r_p1 will always be between \a l1 and \a l2.
+ */
int isect_line_sphere_v3(const float l1[3],
const float l2[3],
const float sp[3],
- const float r,
+ float r,
float r_p1[3],
float r_p2[3]);
int isect_line_sphere_v2(const float l1[2],
const float l2[2],
const float sp[2],
- const float r,
+ float r,
float r_p1[2],
float r_p2[2]);
+/**
+ * Intersect Line-Line, floats - gives intersection point.
+ */
int isect_line_line_v2_point(
const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2]);
+/**
+ * \return The number of point of interests
+ * 0 - lines are collinear
+ * 1 - lines are coplanar, i1 is set to intersection
+ * 2 - i1 and i2 are the nearest points on line 1 (v1, v2) and line 2 (v3, v4) respectively
+ */
int isect_line_line_epsilon_v3(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3],
float i1[3],
float i2[3],
- const float epsilon);
+ float epsilon);
int isect_line_line_v3(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3],
float r_i1[3],
float r_i2[3]);
+/**
+ * Intersection point strictly between the two lines
+ * \return false when no intersection is found.
+ */
bool isect_line_line_strict_v3(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3],
float vi[3],
float *r_lambda);
+/**
+ * Check if two rays are not parallel and returns a factor that indicates
+ * the distance from \a ray_origin_b to the closest point on ray-a to ray-b.
+ *
+ * \note Neither directions need to be normalized.
+ */
bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3],
const float ray_direction_a[3],
const float ray_origin_b[3],
const float ray_direction_b[3],
- const float epsilon,
+ float epsilon,
float *r_lambda_a,
float *r_lambda_b);
bool isect_ray_ray_v3(const float ray_origin_a[3],
@@ -338,39 +562,99 @@ bool isect_ray_ray_v3(const float ray_origin_a[3],
float *r_lambda_a,
float *r_lambda_b);
+/**
+ * if clip is nonzero, will only return true if lambda is >= 0.0
+ * (i.e. intersection point is along positive \a ray_direction)
+ *
+ * \note #line_plane_factor_v3() shares logic.
+ */
bool isect_ray_plane_v3(const float ray_origin[3],
const float ray_direction[3],
const float plane[4],
float *r_lambda,
- const bool clip);
+ bool clip);
+/**
+ * Check if a point is behind all planes.
+ */
bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3]);
-bool isect_point_planes_v3_negated(const float (*planes)[4], const int totplane, const float p[3]);
+/**
+ * Check if a point is in front all planes.
+ * Same as isect_point_planes_v3 but with planes facing the opposite direction.
+ */
+bool isect_point_planes_v3_negated(const float (*planes)[4], int totplane, const float p[3]);
+/**
+ * Intersect line/plane.
+ *
+ * \param r_isect_co: The intersection point.
+ * \param l1: The first point of the line.
+ * \param l2: The second point of the line.
+ * \param plane_co: A point on the plane to intersect with.
+ * \param plane_no: The direction of the plane (does not need to be normalized).
+ *
+ * \note #line_plane_factor_v3() shares logic.
+ */
bool isect_line_plane_v3(float r_isect_co[3],
const float l1[3],
const float l2[3],
const float plane_co[3],
const float plane_no[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Intersect three planes, return the point where all 3 meet.
+ * See Graphics Gems 1 pg 305
+ *
+ * \param plane_a, plane_b, plane_c: Planes.
+ * \param r_isect_co: The resulting intersection point.
+ */
bool isect_plane_plane_plane_v3(const float plane_a[4],
const float plane_b[4],
const float plane_c[4],
float r_isect_co[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Intersect two planes, return a point on the intersection and a vector
+ * that runs on the direction of the intersection.
+ * \note this is a slightly reduced version of #isect_plane_plane_plane_v3
+ *
+ * \param plane_a, plane_b: Planes.
+ * \param r_isect_co: The resulting intersection point.
+ * \param r_isect_no: The resulting vector of the intersection.
+ *
+ * \note \a r_isect_no isn't unit length.
+ */
bool isect_plane_plane_v3(const float plane_a[4],
const float plane_b[4],
float r_isect_co[3],
float r_isect_no[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Intersect all planes, calling `callback_fn` for each point that intersects
+ * 3 of the planes that isn't outside any of the other planes.
+ *
+ * This can be thought of as calculating a convex-hull from an array of planes.
+ *
+ * \param eps_coplanar: Epsilon for testing if two planes are aligned (co-planar).
+ * \param eps_isect: Epsilon for testing of a point is behind any of the planes.
+ *
+ * \warning As complexity is a little under `O(N^3)`, this is only suitable for small arrays.
+ *
+ * \note This function could be optimized by some spatial structure.
+ */
bool isect_planes_v3_fn(
const float planes[][4],
- const int planes_len,
- const float eps_coplanar,
- const float eps_isect,
+ int planes_len,
+ float eps_coplanar,
+ float eps_isect,
void (*callback_fn)(const float co[3], int i, int j, int k, void *user_data),
void *user_data);
/* line/ray triangle */
+
+/**
+ * Test if the line starting at p1 ending at p2 intersects the triangle v0..v2
+ * return non zero if it does.
+ */
bool isect_line_segment_tri_v3(const float p1[3],
const float p2[3],
const float v0[3],
@@ -378,6 +662,9 @@ bool isect_line_segment_tri_v3(const float p1[3],
const float v2[3],
float *r_lambda,
float r_uv[2]);
+/**
+ * Like #isect_line_segment_tri_v3, but allows epsilon tolerance around triangle.
+ */
bool isect_line_segment_tri_epsilon_v3(const float p1[3],
const float p2[3],
const float v0[3],
@@ -385,8 +672,8 @@ bool isect_line_segment_tri_epsilon_v3(const float p1[3],
const float v2[3],
float *r_lambda,
float r_uv[2],
- const float epsilon);
-bool isect_axial_line_segment_tri_v3(const int axis,
+ float epsilon);
+bool isect_axial_line_segment_tri_v3(int axis,
const float p1[3],
const float p2[3],
const float v0[3],
@@ -394,6 +681,10 @@ bool isect_axial_line_segment_tri_v3(const int axis,
const float v2[3],
float *r_lambda);
+/**
+ * Test if the ray starting at p1 going in d direction intersects the triangle v0..v2
+ * return non zero if it does.
+ */
bool isect_ray_tri_v3(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -408,7 +699,7 @@ bool isect_ray_tri_threshold_v3(const float ray_origin[3],
const float v2[3],
float *r_lambda,
float r_uv[2],
- const float threshold);
+ float threshold);
bool isect_ray_tri_epsilon_v3(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -416,7 +707,17 @@ bool isect_ray_tri_epsilon_v3(const float ray_origin[3],
const float v2[3],
float *r_lambda,
float r_uv[2],
- const float epsilon);
+ float epsilon);
+/**
+ * Intersect two triangles.
+ *
+ * \param r_i1, r_i2: Retrieve the overlapping edge between the 2 triangles.
+ * \param r_tri_a_edge_isect_count: Indicates how many edges in the first triangle are intersected.
+ * \return true when the triangles intersect.
+ *
+ * \note If it exists, \a r_i1 will be a point on the edge of the 1st triangle.
+ * \note intersections between coplanar triangles are currently undetected.
+ */
bool isect_tri_tri_v3_ex(const float tri_a[3][3],
const float tri_b[3][3],
float r_i1[3],
@@ -438,9 +739,11 @@ bool isect_tri_tri_v2(const float p1[2],
const float q2[2],
const float r2[2]);
-/* water-tight raycast (requires pre-calculation) */
+/**
+ * Water-tight ray-cast (requires pre-calculation).
+ */
struct IsectRayPrecalc {
- /* Maximal dimension kz, and orthogonal dimensions. */
+ /* Maximal dimension `kz`, and orthogonal dimensions. */
int kx, ky, kz;
/* Shear constants. */
@@ -456,7 +759,9 @@ bool isect_ray_tri_watertight_v3(const float ray_origin[3],
const float v2[3],
float *r_dist,
float r_uv[2]);
-/* slower version which calculates IsectRayPrecalc each time */
+/**
+ * Slower version which calculates #IsectRayPrecalc each time.
+ */
bool isect_ray_tri_watertight_v3_simple(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -478,37 +783,60 @@ bool isect_ray_line_v3(const float ray_origin[3],
const float v1[3],
float *r_lambda);
-/* point in polygon */
+/* Point in polygon. */
+
bool isect_point_poly_v2(const float pt[2],
const float verts[][2],
- const unsigned int nr,
- const bool use_holes);
+ unsigned int nr,
+ bool use_holes);
bool isect_point_poly_v2_int(const int pt[2],
const int verts[][2],
- const unsigned int nr,
- const bool use_holes);
+ unsigned int nr,
+ bool use_holes);
+/**
+ * Point in quad - only convex quads.
+ */
int isect_point_quad_v2(
const float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2], const float v3[2]);
+/**
+ * Only single direction.
+ */
bool isect_point_tri_v2_cw(const float pt[2],
const float v1[2],
const float v2[2],
const float v3[2]);
-int isect_point_tri_v2_int(
- const int x1, const int y1, const int x2, const int y2, const int a, const int b);
+/**
+ * \code{.unparsed}
+ * x1,y2
+ * | \
+ * | \ .(a,b)
+ * | \
+ * x1,y1-- x2,y1
+ * \endcode
+ */
+int isect_point_tri_v2_int(int x1, int y1, int x2, int y2, int a, int b);
bool isect_point_tri_prism_v3(const float p[3],
const float v1[3],
const float v2[3],
const float v3[3]);
+/**
+ * \param r_isect_co: The point \a p projected onto the triangle.
+ * \return True when \a p is inside the triangle.
+ * \note Its up to the caller to check the distance between \a p and \a r_vi
+ * against an error margin.
+ */
bool isect_point_tri_v3(const float p[3],
const float v1[3],
const float v2[3],
const float v3[3],
float r_isect_co[3]);
-/* axis-aligned bounding box */
+/**
+ * Axis-aligned bounding box.
+ */
bool isect_aabb_aabb_v3(const float min1[3],
const float max1[3],
const float min2[3],
@@ -527,6 +855,13 @@ bool isect_ray_aabb_v3(const struct IsectRayAABB_Precalc *data,
const float bb_min[3],
const float bb_max[3],
float *tmin);
+/**
+ * Test a bounding box (AABB) for ray intersection.
+ * Assumes the ray is already local to the boundbox space.
+ *
+ * \note \a direction should be normalized
+ * if you intend to use the \a tmin or \a tmax distance results!
+ */
bool isect_ray_aabb_v3_simple(const float orig[3],
const float dir[3],
const float bb_min[3],
@@ -539,14 +874,22 @@ bool isect_ray_aabb_v3_simple(const float orig[3],
#define ISECT_AABB_PLANE_CROSS_ANY 1
#define ISECT_AABB_PLANE_IN_FRONT_ALL 2
+/**
+ * Checks status of an AABB in relation to a list of planes.
+ *
+ * \returns intersection type:
+ * - ISECT_AABB_PLANE_BEHIND_ONE (0): AABB is completely behind at least 1 plane;
+ * - ISECT_AABB_PLANE_CROSS_ANY (1): AABB intersects at least 1 plane;
+ * - ISECT_AABB_PLANE_IN_FRONT_ALL (2): AABB is completely in front of all planes;
+ */
int isect_aabb_planes_v3(const float (*planes)[4],
- const int totplane,
+ int totplane,
const float bbmin[3],
const float bbmax[3]);
bool isect_sweeping_sphere_tri_v3(const float p1[3],
const float p2[3],
- const float radius,
+ float radius,
const float v0[3],
const float v1[3],
const float v2[3],
@@ -558,13 +901,18 @@ bool clip_segment_v3_plane(
bool clip_segment_v3_plane_n(const float p1[3],
const float p2[3],
const float plane_array[][4],
- const int plane_tot,
+ int plane_tot,
float r_p1[3],
float r_p2[3]);
bool point_in_slice_seg(float p[3], float l1[3], float l2[3]);
-/****************************** Interpolation ********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Interpolation
+ * \{ */
+
void interp_weights_tri_v3(
float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3]);
void interp_weights_quad_v3(float w[4],
@@ -573,19 +921,29 @@ void interp_weights_quad_v3(float w[4],
const float v3[3],
const float v4[3],
const float co[3]);
-void interp_weights_poly_v3(float w[], float v[][3], const int n, const float co[3]);
-void interp_weights_poly_v2(float w[], float v[][2], const int n, const float co[2]);
+void interp_weights_poly_v3(float w[], float v[][3], int n, const float co[3]);
+void interp_weights_poly_v2(float w[], float v[][2], int n, const float co[2]);
+/** `(x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t)`. */
void interp_cubic_v3(float x[3],
float v[3],
const float x1[3],
const float v1[3],
const float x2[3],
const float v2[3],
- const float t);
+ float t);
-int interp_sparse_array(float *array, const int list_size, const float skipval);
+/**
+ * Given an array with some invalid values this function interpolates valid values
+ * replacing the invalid ones.
+ */
+int interp_sparse_array(float *array, int list_size, float skipval);
+/**
+ * Given 2 triangles in 3D space, and a point in relation to the first triangle.
+ * calculate the location of a point in relation to the second triangle.
+ * Useful for finding relative positions with geometry.
+ */
void transform_point_by_tri_v3(float pt_tar[3],
float const pt_src[3],
const float tri_tar_p1[3],
@@ -594,6 +952,10 @@ void transform_point_by_tri_v3(float pt_tar[3],
const float tri_src_p1[3],
const float tri_src_p2[3],
const float tri_src_p3[3]);
+/**
+ * Simply re-interpolates,
+ * assumes p_src is between \a l_src_p1-l_src_p2
+ */
void transform_point_by_seg_v3(float p_dst[3],
const float p_src[3],
const float l_dst_p1[3],
@@ -601,12 +963,32 @@ void transform_point_by_seg_v3(float p_dst[3],
const float l_src_p1[3],
const float l_src_p2[3]);
+/**
+ * \note Using #cross_tri_v2 means locations outside the triangle are correctly weighted.
+ *
+ * \note This is *exactly* the same calculation as #resolve_tri_uv_v2,
+ * although it has double precision and is used for texture baking, so keep both.
+ */
void barycentric_weights_v2(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]);
+/**
+ * A version of #barycentric_weights_v2 that doesn't allow negative weights.
+ * Useful when negative values cause problems and points are only
+ * ever slightly outside of the triangle.
+ */
void barycentric_weights_v2_clamped(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]);
+/**
+ * still use 2D X,Y space but this works for verts transformed by a perspective matrix,
+ * using their 4th component as a weight
+ */
void barycentric_weights_v2_persp(
const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3]);
+/**
+ * same as #barycentric_weights_v2 but works with a quad,
+ * NOTE: untested for values outside the quad's bounds
+ * this is #interp_weights_poly_v2 expanded for quads only
+ */
void barycentric_weights_v2_quad(const float v1[2],
const float v2[2],
const float v3[2],
@@ -614,20 +996,47 @@ void barycentric_weights_v2_quad(const float v1[2],
const float co[2],
float w[4]);
+/**
+ * \return false for degenerated triangles.
+ */
bool barycentric_coords_v2(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]);
+/**
+ * \return
+ * - 0 if the point is outside of triangle.
+ * - 1 if the point is inside triangle.
+ * - 2 if it's on the edge.
+ */
int barycentric_inside_triangle_v2(const float w[3]);
+/**
+ * Barycentric reverse
+ *
+ * Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
+ *
+ * \note same basic result as #barycentric_weights_v2, see its comment for details.
+ */
void resolve_tri_uv_v2(
float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2]);
+/**
+ * Barycentric reverse 3d
+ *
+ * Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
+ */
void resolve_tri_uv_v3(
float r_uv[2], const float st[3], const float st0[3], const float st1[3], const float st2[3]);
+/**
+ * Bilinear reverse.
+ */
void resolve_quad_uv_v2(float r_uv[2],
const float st[2],
const float st0[2],
const float st1[2],
const float st2[2],
const float st3[2]);
+/**
+ * Bilinear reverse with derivatives.
+ */
void resolve_quad_uv_v2_deriv(float r_uv[2],
float r_deriv[2][2],
const float st[2],
@@ -635,48 +1044,71 @@ void resolve_quad_uv_v2_deriv(float r_uv[2],
const float st1[2],
const float st2[2],
const float st3[2]);
+/**
+ * A version of resolve_quad_uv_v2 that only calculates the 'u'.
+ */
float resolve_quad_u_v2(const float st[2],
const float st0[2],
const float st1[2],
const float st2[2],
const float st3[2]);
-/* use to find the point of a UV on a face */
+/**
+ * Use to find the point of a UV on a face.
+ * Reverse of `resolve_*` functions.
+ */
void interp_bilinear_quad_v3(float data[4][3], float u, float v, float res[3]);
void interp_barycentric_tri_v3(float data[3][3], float u, float v, float res[3]);
-/***************************** View & Projection *****************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View & Projection
+ * \{ */
void lookat_m4(
float mat[4][4], float vx, float vy, float vz, float px, float py, float pz, float twist);
void polarview_m4(float mat[4][4], float dist, float azimuth, float incidence, float twist);
+/**
+ * Matches `glFrustum` result.
+ */
void perspective_m4(float mat[4][4],
- const float left,
- const float right,
- const float bottom,
- const float top,
- const float nearClip,
- const float farClip);
+ float left,
+ float right,
+ float bottom,
+ float top,
+ float nearClip,
+ float farClip);
void perspective_m4_fov(float mat[4][4],
- const float angle_left,
- const float angle_right,
- const float angle_up,
- const float angle_down,
- const float nearClip,
- const float farClip);
+ float angle_left,
+ float angle_right,
+ float angle_up,
+ float angle_down,
+ float nearClip,
+ float farClip);
+/**
+ * Matches `glOrtho` result.
+ */
void orthographic_m4(float mat[4][4],
- const float left,
- const float right,
- const float bottom,
- const float top,
- const float nearClip,
- const float farClip);
-void window_translate_m4(float winmat[4][4],
- const float perspmat[4][4],
- const float x,
- const float y);
+ float left,
+ float right,
+ float bottom,
+ float top,
+ float nearClip,
+ float farClip);
+/**
+ * Translate a matrix created by orthographic_m4 or perspective_m4 in XY coords
+ * (used to jitter the view).
+ */
+void window_translate_m4(float winmat[4][4], float perspmat[4][4], float x, float y);
+/**
+ * Frustum planes extraction from a projection matrix
+ * (homogeneous 4d vector representations of planes).
+ *
+ * plane parameters can be NULL if you do not need them.
+ */
void planes_from_projmat(const float mat[4][4],
float left[4],
float right[4],
@@ -700,28 +1132,44 @@ void projmat_dimensions_db(const float winmat[4][4],
double *r_near,
double *r_far);
+/**
+ * Creates a projection matrix for a small region of the viewport.
+ *
+ * \param projmat: Projection Matrix.
+ * \param win_size: Viewport Size.
+ * \param x_min, x_max, y_min, y_max: Coordinates of the subregion.
+ * \return r_projmat: Resulting Projection Matrix.
+ */
void projmat_from_subregion(const float projmat[4][4],
const int win_size[2],
- const int x_min,
- const int x_max,
- const int y_min,
- const int y_max,
+ int x_min,
+ int x_max,
+ int y_min,
+ int y_max,
float r_projmat[4][4]);
int box_clip_bounds_m4(float boundbox[2][3], const float bounds[4], float winmat[4][4]);
void box_minmax_bounds_m4(float min[3], float max[3], float boundbox[2][3], float mat[4][4]);
-/********************************** Mapping **********************************/
+/** \} */
-void map_to_tube(float *r_u, float *r_v, const float x, const float y, const float z);
-void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const float z);
+/* -------------------------------------------------------------------- */
+/** \name Mapping
+ * \{ */
+
+void map_to_tube(float *r_u, float *r_v, float x, float y, float z);
+void map_to_sphere(float *r_u, float *r_v, float x, float y, float z);
void map_to_plane_v2_v3v3(float r_co[2], const float co[3], const float no[3]);
void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2],
const float co[3],
const float axis[3],
- const float angle);
+ float angle);
+
+/** \} */
-/********************************** Normals **********************************/
+/* -------------------------------------------------------------------- */
+/** \name Normals
+ * \{ */
void accumulate_vertex_normals_tri_v3(float n1[3],
float n2[3],
@@ -741,13 +1189,18 @@ void accumulate_vertex_normals_v3(float n1[3],
const float co3[3],
const float co4[3]);
-void accumulate_vertex_normals_poly_v3(float **vertnos,
- const float polyno[3],
- const float **vertcos,
- float vdiffs[][3],
- const int nverts);
+/**
+ * Add weighted face normal component into normals of the face vertices.
+ * Caller must pass pre-allocated vdiffs of nverts length.
+ */
+void accumulate_vertex_normals_poly_v3(
+ float **vertnos, const float polyno[3], const float **vertcos, float vdiffs[][3], int nverts);
+
+/** \} */
-/********************************* Tangents **********************************/
+/* -------------------------------------------------------------------- */
+/** \name Tangents
+ * \{ */
void tangent_from_uv_v3(const float uv1[2],
const float uv2[2],
@@ -758,9 +1211,32 @@ void tangent_from_uv_v3(const float uv1[2],
const float n[3],
float r_tang[3]);
-/******************************** Vector Clouds ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Clouds
+ * \{ */
-void vcloud_estimate_transform_v3(const int list_size,
+/**
+ * Input:
+ *
+ * \param list_size: 4 lists as pointer to array[list_size]
+ * \param pos: current pos array of 'new' positions
+ * \param weight: current weight array of 'new'weights (may be NULL pointer if you have no weights)
+ * \param rpos: Reference rpos array of 'old' positions
+ * \param rweight: Reference rweight array of 'old'weights
+ * (may be NULL pointer if you have no weights).
+ *
+ * Output:
+ *
+ * \param lloc: Center of mass pos.
+ * \param rloc: Center of mass rpos.
+ * \param lrot: Rotation matrix.
+ * \param lscale: Scale matrix.
+ *
+ * pointers may be NULL if not needed
+ */
+void vcloud_estimate_transform_v3(int list_size,
const float (*pos)[3],
const float *weight,
const float (*rpos)[3],
@@ -770,25 +1246,33 @@ void vcloud_estimate_transform_v3(const int list_size,
float lrot[3][3],
float lscale[3][3]);
-/****************************** Spherical Harmonics *************************/
+/** \} */
-/* Uses 2nd order SH => 9 coefficients, stored in this order:
- * 0 = (0, 0),
- * 1 = (1, -1), 2 = (1, 0), 3 = (1, 1),
- * 4 = (2, -2), 5 = (2, -1), 6 = (2, 0), 7 = (2, 1), 8 = (2, 2) */
+/* -------------------------------------------------------------------- */
+/** \name Spherical Harmonics
+ *
+ * Uses 2nd order SH => 9 coefficients, stored in this order:
+ * - 0 = `(0, 0)`
+ * - 1 = `(1, -1), 2 = (1, 0), 3 = (1, 1)`
+ * - 4 = `(2, -2), 5 = (2, -1), 6 = (2, 0), 7 = (2, 1), 8 = (2, 2)`
+ * \{ */
MINLINE void zero_sh(float r[9]);
MINLINE void copy_sh_sh(float r[9], const float a[9]);
-MINLINE void mul_sh_fl(float r[9], const float f);
+MINLINE void mul_sh_fl(float r[9], float f);
MINLINE void add_sh_shsh(float r[9], const float a[9], const float b[9]);
MINLINE float dot_shsh(const float a[9], const float b[9]);
MINLINE float eval_shv3(float r[9], const float v[3]);
-MINLINE float diffuse_shv3(float r[9], const float v[3]);
-MINLINE void vec_fac_to_sh(float r[9], const float v[3], const float f);
-MINLINE void madd_sh_shfl(float r[9], const float sh[9], const float f);
+MINLINE float diffuse_shv3(const float r[9], const float v[3]);
+MINLINE void vec_fac_to_sh(float r[9], const float v[3], float f);
+MINLINE void madd_sh_shfl(float r[9], const float sh[9], float f);
+
+/** \} */
-/********************************* Form Factor *******************************/
+/* -------------------------------------------------------------------- */
+/** \name Form Factor
+ * \{ */
float form_factor_quad(const float p[3],
const float n[3],
@@ -808,37 +1292,117 @@ bool form_factor_visible_quad(const float p[3],
float form_factor_hemi_poly(
float p[3], float n[3], float v1[3], float v2[3], float v3[3], float v4[3]);
+/**
+ * Same as axis_dominant_v3_to_m3, but flips the normal
+ */
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3]);
+/**
+ * \brief Normal to x,y matrix
+ *
+ * Creates a 3x3 matrix from a normal.
+ * This matrix can be applied to vectors so their 'z' axis runs along \a normal.
+ * In practice it means you can use x,y as 2d coords. \see
+ *
+ * \param r_mat: The matrix to return.
+ * \param normal: A unit length vector.
+ */
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3]);
+/**
+ * Get the 2 dominant axis values, 0==X, 1==Y, 2==Z.
+ */
MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3]);
+/**
+ * Same as #axis_dominant_v3 but return the max value.
+ */
MINLINE float axis_dominant_v3_max(int *r_axis_a,
int *r_axis_b,
const float axis[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Get the single dominant axis value, 0==X, 1==Y, 2==Z.
+ */
MINLINE int axis_dominant_v3_single(const float vec[3]);
+/**
+ * The dominant axis of an orthogonal vector.
+ */
MINLINE int axis_dominant_v3_ortho_single(const float vec[3]);
MINLINE int max_axis_v3(const float vec[3]);
MINLINE int min_axis_v3(const float vec[3]);
-MINLINE int poly_to_tri_count(const int poly_count, const int corner_count);
+/**
+ * Simple function to either:
+ * - Calculate how many triangles needed from the total number of polygons + loops.
+ * - Calculate the first triangle index from the polygon index & that polygons loop-start.
+ *
+ * \param poly_count: The number of polygons or polygon-index
+ * (3+ sided faces, 1-2 sided give incorrect results).
+ * \param corner_count: The number of corners (also called loop-index).
+ */
+MINLINE int poly_to_tri_count(int poly_count, int corner_count);
-MINLINE float shell_angle_to_dist(const float angle);
+/**
+ * Useful to calculate an even width shell, by taking the angle between 2 planes.
+ * The return value is a scale on the offset.
+ * no angle between planes is 1.0, as the angle between the 2 planes approaches 180d
+ * the distance gets very high, 180d would be inf, but this case isn't valid.
+ */
+MINLINE float shell_angle_to_dist(float angle);
+/**
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b))`.
+ */
MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3]);
+/**
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b))`.
+ */
MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2]);
+/**
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b) / 2)`.
+ */
MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3]);
+/**
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b) / 2)`.
+ */
MINLINE float shell_v2v2_mid_normalized_to_dist(const float a[2], const float b[2]);
-/********************************* Cubic (Bezier) *******************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Cubic (Bezier)
+ * \{ */
+
+/**
+ * Return the value which the distance between points will need to be scaled by,
+ * to define a handle, given both points are on a perfect circle.
+ *
+ * Use when we want a bezier curve to match a circle as closely as possible.
+ *
+ * \note the return value will need to be divided by 0.75 for correct results.
+ */
float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3]);
-/********************************** Geodesics *********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Geodesics
+ * \{ */
+/**
+ * Utility for computing approximate geodesic distances on triangle meshes.
+ *
+ * Given triangle with vertex coordinates v0, v1, v2, and known geodesic distances
+ * dist1 and dist2 at v1 and v2, estimate a geodesic distance at vertex v0.
+ *
+ * From "Dart Throwing on Surfaces", EGSR 2009. Section 7, Geodesic Dart Throwing.
+ */
float geodesic_distance_propagate_across_triangle(
- const float v0[3], const float v1[3], const float v2[3], const float dist1, const float dist2);
+ const float v0[3], const float v1[3], const float v2[3], float dist1, float dist2);
-/**************************** Inline Definitions ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline Definitions
+ * \{ */
#if BLI_MATH_DO_INLINE
# include "intern/math_geom_inline.c"
@@ -848,6 +1412,8 @@ float geodesic_distance_propagate_across_triangle(
# pragma GCC diagnostic pop
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_interp.h b/source/blender/blenlib/BLI_math_interp.h
index cc025b469e3..0af250064f6 100644
--- a/source/blender/blenlib/BLI_math_interp.h
+++ b/source/blender/blenlib/BLI_math_interp.h
@@ -77,13 +77,14 @@ typedef void (*ewa_filter_read_pixel_cb)(void *userdata, int x, int y, float res
void BLI_ewa_imp2radangle(
float A, float B, float C, float F, float *a, float *b, float *th, float *ecc);
-/* TODO(sergey): Consider making this function inlined, so the pixel read callback
+/**
+ * TODO(sergey): Consider making this function inlined, so the pixel read callback
* could also be inlined in order to avoid per-pixel function calls.
*/
-void BLI_ewa_filter(const int width,
- const int height,
- const bool intpol,
- const bool use_alpha,
+void BLI_ewa_filter(int width,
+ int height,
+ bool intpol,
+ bool use_alpha,
const float uv[2],
const float du[2],
const float dv[2],
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index e38df58c1ca..65d654bc930 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -32,7 +32,9 @@
extern "C" {
#endif
-/********************************* Init **************************************/
+/* -------------------------------------------------------------------- */
+/** \name Init
+ * \{ */
void zero_m2(float m[2][2]);
void zero_m3(float m[3][3]);
@@ -54,24 +56,31 @@ void copy_m4_m2(float m1[4][4], const float m2[2][2]);
void copy_m4_m4_db(double m1[4][4], const double m2[4][4]);
/* double->float */
+
void copy_m3_m3d(float m1[3][3], const double m2[3][3]);
/* float->double */
+
+void copy_m3d_m3(double m1[3][3], const float m2[3][3]);
void copy_m4d_m4(double m1[4][4], const float m2[4][4]);
void swap_m3m3(float m1[3][3], float m2[3][3]);
void swap_m4m4(float m1[4][4], float m2[4][4]);
-/* Build index shuffle matrix */
+/** Build index shuffle matrix. */
void shuffle_m4(float R[4][4], const int index[4]);
-/******************************** Arithmetic *********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Arithmetic
+ * \{ */
void add_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]);
void add_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]);
-void madd_m3_m3m3fl(float R[3][3], const float A[3][3], const float B[3][3], const float f);
-void madd_m4_m4m4fl(float R[4][4], const float A[4][4], const float B[4][4], const float f);
+void madd_m3_m3m3fl(float R[3][3], const float A[3][3], const float B[3][3], float f);
+void madd_m4_m4m4fl(float R[4][4], const float A[4][4], const float B[4][4], float f);
void sub_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]);
void sub_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]);
@@ -80,14 +89,21 @@ void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]);
void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4]);
void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3]);
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]);
+/**
+ * `R = A * B`, ignore the elements on the 4th row/column of A.
+ */
void mul_m3_m3m4(float R[3][3], const float A[3][3], const float B[4][4]);
+/**
+ * `R = A * B`, ignore the elements on the 4th row/column of B.
+ */
void mul_m3_m4m3(float R[3][3], const float A[4][4], const float B[3][3]);
void mul_m3_m4m4(float R[3][3], const float A[4][4], const float B[4][4]);
-/* special matrix multiplies
- * uniq: R <-- AB, R is neither A nor B
- * pre: R <-- AR
- * post: R <-- RB
+/**
+ * Special matrix multiplies
+ * - uniq: `R <-- AB`, R is neither A nor B
+ * - pre: `R <-- AR`
+ * - post: `R <-- RB`.
*/
void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3]);
void mul_m3_m3_pre(float R[3][3], const float A[3][3]);
@@ -98,7 +114,8 @@ void mul_m4db_m4db_m4fl_uniq(double R[4][4], const double A[4][4], const float B
void mul_m4_m4_pre(float R[4][4], const float A[4][4]);
void mul_m4_m4_post(float R[4][4], const float B[4][4]);
-/* mul_m3_series */
+/* Implement #mul_m3_series macro. */
+
void _va_mul_m3_series_3(float R[3][3], const float M1[3][3], const float M2[3][3]) ATTR_NONNULL();
void _va_mul_m3_series_4(float R[3][3],
const float M1[3][3],
@@ -139,7 +156,9 @@ void _va_mul_m3_series_9(float R[3][3],
const float M6[3][3],
const float M7[3][3],
const float M8[3][3]) ATTR_NONNULL();
-/* mul_m4_series */
+
+/* Implement #mul_m4_series macro. */
+
void _va_mul_m4_series_3(float R[4][4], const float M1[4][4], const float M2[4][4]) ATTR_NONNULL();
void _va_mul_m4_series_4(float R[4][4],
const float M1[4][4],
@@ -191,6 +210,7 @@ void mul_v4_m4v3_db(double r[4], const double mat[4][4], const double vec[3]);
void mul_v2_m4v3(float r[2], const float M[4][4], const float v[3]);
void mul_v2_m2v2(float r[2], const float M[2][2], const float v[2]);
void mul_m2_v2(const float M[2][2], float v[2]);
+/** Same as #mul_m4_v3() but doesn't apply translation component. */
void mul_mat3_m4_v3(const float M[4][4], float r[3]);
void mul_v3_mat3_m4v3(float r[3], const float M[4][4], const float v[3]);
void mul_v3_mat3_m4v3_db(double r[3], const double M[4][4], const double v[3]);
@@ -210,7 +230,18 @@ void mul_transposed_m3_v3(const float M[3][3], float r[3]);
void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3]);
void mul_m3_v3_double(const float M[3][3], double r[3]);
+/**
+ * Combines transformations, handling scale separately in a manner equivalent
+ * to the Aligned Inherit Scale mode, in order to avoid creating shear.
+ * If A scale is uniform, the result is equivalent to ordinary multiplication.
+ *
+ * NOTE: this effectively takes output location from simple multiplication,
+ * and uses mul_m4_m4m4_split_channels for rotation and scale.
+ */
void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4]);
+/**
+ * Separately combines location, rotation and scale of the input matrices.
+ */
void mul_m4_m4m4_split_channels(float R[4][4], const float A[4][4], const float B[4][4]);
void mul_m3_fl(float R[3][3], float f);
@@ -221,27 +252,46 @@ void negate_m3(float R[3][3]);
void negate_mat3_m4(float R[4][4]);
void negate_m4(float R[4][4]);
-bool invert_m3_ex(float m[3][3], const float epsilon);
-bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], const float epsilon);
+bool invert_m3_ex(float m[3][3], float epsilon);
+bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], float epsilon);
bool invert_m3(float R[3][3]);
bool invert_m3_m3(float R[3][3], const float A[3][3]);
bool invert_m4(float R[4][4]);
bool invert_m4_m4(float R[4][4], const float A[4][4]);
+/**
+ * Computes the inverse of mat and puts it in inverse.
+ * Uses Gaussian Elimination with partial (maximal column) pivoting.
+ * \return true on success (i.e. can always find a pivot) and false on failure.
+ * Mark Segal - 1992.
+ *
+ * \note this has worse performance than #EIG_invert_m4_m4 (Eigen), but e.g.
+ * for non-invertible scale matrices, finding a partial solution can
+ * be useful to have a valid local transform center, see T57767.
+ */
bool invert_m4_m4_fallback(float R[4][4], const float A[4][4]);
-/* double arithmetic (mixed float/double) */
+/* Double arithmetic (mixed float/double). */
+
void mul_m4_v4d(const float M[4][4], double r[4]);
void mul_v4d_m4v4d(double r[4], const float M[4][4], const double v[4]);
-/* double matrix functions (no mixing types) */
+/* Double matrix functions (no mixing types). */
+
void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3]);
void mul_m3_v3_db(const double M[3][3], double r[3]);
-/****************************** Linear Algebra *******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Linear Algebra
+ * \{ */
void transpose_m3(float R[3][3]);
void transpose_m3_m3(float R[3][3], const float M[3][3]);
+/**
+ * \note Seems obscure but in-fact a common operation.
+ */
void transpose_m3_m4(float R[3][3], const float M[4][4]);
void transpose_m4(float R[4][4]);
void transpose_m4_m4(float R[4][4], const float M[4][4]);
@@ -261,14 +311,40 @@ void normalize_m4(float R[4][4]) ATTR_NONNULL();
void normalize_m4_m4_ex(float R[4][4], const float M[4][4], float r_scale[3]) ATTR_NONNULL();
void normalize_m4_m4(float R[4][4], const float M[4][4]) ATTR_NONNULL();
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ */
void orthogonalize_m3(float R[3][3], int axis);
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ */
void orthogonalize_m4(float R[4][4], int axis);
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix,
+ * in a way that is symmetric and stable to variations in the input, and
+ * preserving the value of the determinant, i.e. the overall volume change.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ * \param normalize: Normalize the matrix instead of preserving volume.
+ */
void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize);
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix,
+ * in a way that is symmetric and stable to variations in the input, and
+ * preserving the value of the determinant, i.e. the overall volume change.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ * \param normalize: Normalize the matrix instead of preserving volume.
+ */
void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize);
-bool orthogonalize_m3_zero_axes(float R[3][3], const float unit_length);
-bool orthogonalize_m4_zero_axes(float R[4][4], const float unit_length);
+bool orthogonalize_m3_zero_axes(float R[3][3], float unit_length);
+bool orthogonalize_m4_zero_axes(float R[4][4], float unit_length);
bool is_orthogonal_m3(const float mat[3][3]);
bool is_orthogonal_m4(const float mat[4][4]);
@@ -280,8 +356,8 @@ bool is_uniform_scaled_m4(const float m[4][4]);
/* NOTE: 'adjoint' here means the adjugate (adjunct, "classical adjoint") matrix!
* Nowadays 'adjoint' usually refers to the conjugate transpose,
- * which for real-valued matrices is simply the transpose.
- */
+ * which for real-valued matrices is simply the transpose. */
+
void adjoint_m2_m2(float R[2][2], const float M[2][2]);
void adjoint_m3_m3(float R[3][3], const float M[3][3]);
void adjoint_m4_m4(float R[4][4], const float M[4][4]);
@@ -291,10 +367,18 @@ float determinant_m3(
float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3);
float determinant_m3_array(const float m[3][3]);
float determinant_m4_mat3_array(const float m[4][4]);
+double determinant_m3_array_db(const double m[3][3]);
float determinant_m4(const float m[4][4]);
#define PSEUDOINVERSE_EPSILON 1e-8f
+/**
+ * Compute the Single Value Decomposition of an arbitrary matrix A
+ * That is compute the 3 matrices U,W,V with U column orthogonal (m,n)
+ * ,W a diagonal matrix and V an orthogonal square matrix `s.t.A = U.W.Vt`.
+ * From this decomposition it is trivial to compute the (pseudo-inverse)
+ * of `A` as `Ainv = V.Winv.transpose(U)`.
+ */
void svd_m4(float U[4][4], float s[4], float V[4][4], float A[4][4]);
void pseudoinverse_m4_m4(float Ainv[4][4], const float A[4][4], float epsilon);
void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon);
@@ -304,18 +388,39 @@ bool has_zero_axis_m4(const float matrix[4][4]);
void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]);
void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3]);
+/**
+ * A safe version of invert that uses valid axes, calculating the zero'd axis
+ * based on the non-zero ones.
+ *
+ * This works well for transformation matrices, when a single axis is zerod.
+ */
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4]);
-/****************************** Transformations ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transformations
+ * \{ */
void scale_m3_fl(float R[3][3], float scale);
void scale_m4_fl(float R[4][4], float scale);
+/**
+ * This computes the overall volume scale factor of a transformation matrix.
+ * For an orthogonal matrix, it is the product of all three scale values.
+ * Returns a negative value if the transform is flipped by negative scale.
+ */
float mat3_to_volume_scale(const float M[3][3]);
float mat4_to_volume_scale(const float M[4][4]);
+/**
+ * This gets the average scale of a matrix, only use when your scaling
+ * data that has no idea of scale axis, examples are bone-envelope-radius
+ * and curve radius.
+ */
float mat3_to_scale(const float M[3][3]);
float mat4_to_scale(const float M[4][4]);
+/** Return 2D scale (in XY plane) of given mat4. */
float mat4_to_xy_scale(const float M[4][4]);
void size_to_mat3(float R[3][3], const float size[3]);
@@ -324,15 +429,31 @@ void size_to_mat4(float R[4][4], const float size[3]);
void mat3_to_size(float size[3], const float M[3][3]);
void mat4_to_size(float size[3], const float M[4][4]);
+/**
+ * Extract scale factors from the matrix, with correction to ensure
+ * exact volume in case of a sheared matrix.
+ */
void mat4_to_size_fix_shear(float size[3], const float M[4][4]);
-void translate_m3(float mat[3][3], float tx, float ty);
void translate_m4(float mat[4][4], float tx, float ty, float tz);
-void rotate_m3(float mat[3][3], const float angle);
-void rotate_m4(float mat[4][4], const char axis, const float angle);
-void rescale_m3(float mat[3][3], const float scale[2]);
+/**
+ * Rotate a matrix in-place.
+ *
+ * \note To create a new rotation matrix see:
+ * #axis_angle_to_mat4_single, #axis_angle_to_mat3_single, #angle_to_mat2
+ * (axis & angle args are compatible).
+ */
+void rotate_m4(float mat[4][4], char axis, float angle);
+/** Scale a matrix in-place. */
void rescale_m4(float mat[4][4], const float scale[3]);
-void transform_pivot_set_m3(float mat[3][3], const float pivot[2]);
+/**
+ * Scale or rotate around a pivot point,
+ * a convenience function to avoid having to do inline.
+ *
+ * Since its common to make a scale/rotation matrix that pivots around an arbitrary point.
+ *
+ * Typical use case is to make 3x3 matrix, copy to 4x4, then pass to this function.
+ */
void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
void mat4_to_rot(float rot[3][3], const float wmat[4][4]);
@@ -343,41 +464,71 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat
void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]);
-void loc_rot_size_to_mat3(float R[3][3],
- const float loc[2],
- const float angle,
- const float size[2]);
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
+ */
void loc_rot_size_to_mat4(float R[4][4],
const float loc[3],
const float rot[3][3],
const float size[3]);
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
+ *
+ * TODO: need to have a version that allows for rotation order.
+ */
void loc_eul_size_to_mat4(float R[4][4],
const float loc[3],
const float eul[3],
const float size[3]);
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
+ */
void loc_eulO_size_to_mat4(
- float R[4][4], const float loc[3], const float eul[3], const float size[3], const short order);
+ float R[4][4], const float loc[3], const float eul[3], const float size[3], short order);
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
+ */
void loc_quat_size_to_mat4(float R[4][4],
const float loc[3],
const float quat[4],
const float size[3]);
-void loc_axisangle_size_to_mat4(float R[4][4],
- const float loc[3],
- const float axis[3],
- const float angle,
- const float size[3]);
-
-void blend_m3_m3m3(float out[3][3],
- const float dst[3][3],
- const float src[3][3],
- const float srcweight);
-void blend_m4_m4m4(float out[4][4],
- const float dst[4][4],
- const float src[4][4],
- const float srcweight);
-
-void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t);
-void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t);
+void loc_axisangle_size_to_mat4(
+ float R[4][4], const float loc[3], const float axis[3], float angle, const float size[3]);
+
+void blend_m3_m3m3(float out[3][3], const float dst[3][3], const float src[3][3], float srcweight);
+void blend_m4_m4m4(float out[4][4], const float dst[4][4], const float src[4][4], float srcweight);
+
+/**
+ * A polar-decomposition-based interpolation between matrix A and matrix B.
+ *
+ * \note This code is about five times slower as the 'naive' interpolation done by #blend_m3_m3m3
+ * (it typically remains below 2 usec on an average i74700,
+ * while #blend_m3_m3m3 remains below 0.4 usec).
+ * However, it gives expected results even with non-uniformly scaled matrices,
+ * see T46418 for an example.
+ *
+ * Based on "Matrix Animation and Polar Decomposition", by Ken Shoemake & Tom Duff
+ *
+ * \param R: Resulting interpolated matrix.
+ * \param A: Input matrix which is totally effective with `t = 0.0`.
+ * \param B: Input matrix which is totally effective with `t = 1.0`.
+ * \param t: Interpolation factor.
+ */
+void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], float t);
+/**
+ * Complete transform matrix interpolation,
+ * based on polar-decomposition-based interpolation from #interp_m3_m3m3.
+ *
+ * \param R: Resulting interpolated matrix.
+ * \param A: Input matrix which is totally effective with `t = 0.0`.
+ * \param B: Input matrix which is totally effective with `t = 1.0`.
+ * \param t: Interpolation factor.
+ */
+void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], float t);
bool is_negative_m3(const float mat[3][3]);
bool is_negative_m4(const float mat[4][4]);
@@ -388,16 +539,57 @@ bool is_zero_m4(const float mat[4][4]);
bool equals_m3m3(const float mat1[3][3], const float mat2[3][3]);
bool equals_m4m4(const float mat1[4][4], const float mat2[4][4]);
-/* SpaceTransform helper */
+/**
+ * #SpaceTransform struct encapsulates all needed data to convert between two coordinate spaces
+ * (where conversion can be represented by a matrix multiplication).
+ *
+ * A #SpaceTransform is initialized using:
+ * - #BLI_SPACE_TRANSFORM_SETUP(&data, ob1, ob2)
+ *
+ * After that the following calls can be used:
+ * - Converts a coordinate in ob1 space to the corresponding ob2 space:
+ * #BLI_space_transform_apply(&data, co);
+ * - Converts a coordinate in ob2 space to the corresponding ob1 space:
+ * #BLI_space_transform_invert(&data, co);
+ *
+ * Same concept as #BLI_space_transform_apply and #BLI_space_transform_invert,
+ * but no is normalized after conversion (and not translated at all!):
+ * - #BLI_space_transform_apply_normal(&data, no);
+ * - #BLI_space_transform_invert_normal(&data, no);
+ */
typedef struct SpaceTransform {
float local2target[4][4];
float target2local[4][4];
} SpaceTransform;
+/**
+ * Global-invariant transform.
+ *
+ * This defines a matrix transforming a point in local space to a point in target space
+ * such that its global coordinates remain unchanged.
+ *
+ * In other words, if we have a global point P with local coordinates (x, y, z)
+ * and global coordinates (X, Y, Z),
+ * this defines a transform matrix TM such that (x', y', z') = TM * (x, y, z)
+ * where (x', y', z') are the coordinates of P' in target space
+ * such that it keeps (X, Y, Z) coordinates in global space.
+ */
void BLI_space_transform_from_matrices(struct SpaceTransform *data,
const float local[4][4],
const float target[4][4]);
+/**
+ * Local-invariant transform.
+ *
+ * This defines a matrix transforming a point in global space
+ * such that its local coordinates (from local space to target space) remain unchanged.
+ *
+ * In other words, if we have a local point p with local coordinates (x, y, z)
+ * and global coordinates (X, Y, Z),
+ * this defines a transform matrix TM such that (X', Y', Z') = TM * (X, Y, Z)
+ * where (X', Y', Z') are the coordinates of p' in global space
+ * such that it keeps (x, y, z) coordinates in target space.
+ */
void BLI_space_transform_global_from_matrices(struct SpaceTransform *data,
const float local[4][4],
const float target[4][4]);
@@ -409,7 +601,11 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float
#define BLI_SPACE_TRANSFORM_SETUP(data, local, target) \
BLI_space_transform_from_matrices((data), (local)->obmat, (target)->obmat)
-/*********************************** Other ***********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Other
+ * \{ */
void print_m3(const char *str, const float M[3][3]);
void print_m4(const char *str, const float M[4][4]);
@@ -417,6 +613,8 @@ void print_m4(const char *str, const float M[4][4]);
#define print_m3_id(M) print_m3(STRINGIFY(M), M)
#define print_m4_id(M) print_m4(STRINGIFY(M), M)
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index 461b5a60c9d..c27cf71ce5f 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -32,31 +32,73 @@
extern "C" {
#endif
+/* -------------------------------------------------------------------- */
+/** \name Conversion Defines
+ * \{ */
+
#define RAD2DEG(_rad) ((_rad) * (180.0 / M_PI))
#define DEG2RAD(_deg) ((_deg) * (M_PI / 180.0))
#define RAD2DEGF(_rad) ((_rad) * (float)(180.0 / M_PI))
#define DEG2RADF(_deg) ((_deg) * (float)(M_PI / 180.0))
-/******************************** Quaternions ********************************/
-/* stored in (w, x, y, z) order */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternions
+ * Stored in (w, x, y, z) order.
+ * \{ */
+
+/* Initialize */
+
+/* Convenience, avoids setting Y axis everywhere. */
-/* init */
void unit_axis_angle(float axis[3], float *angle);
void unit_qt(float q[4]);
void copy_qt_qt(float q[4], const float a[4]);
-/* arithmetic */
+/* Arithmetic. */
+
void mul_qt_qtqt(float q[4], const float a[4], const float b[4]);
+/**
+ * \note
+ * Assumes a unit quaternion?
+ *
+ * in fact not, but you may want to use a unit quaternion read on...
+ *
+ * Shortcut for 'q v q*' when \a v is actually a quaternion.
+ * This removes the need for converting a vector to a quaternion,
+ * calculating q's conjugate and converting back to a vector.
+ * It also happens to be faster (17+,24* vs * 24+,32*).
+ * If \a q is not a unit quaternion, then \a v will be both rotated by
+ * the same amount as if q was a unit quaternion, and scaled by the square of
+ * the length of q.
+ *
+ * For people used to python mathutils, its like:
+ * def mul_qt_v3(q, v): (q * Quaternion((0.0, v[0], v[1], v[2])) * q.conjugated())[1:]
+ *
+ * \note Multiplying by 3x3 matrix is ~25% faster.
+ */
void mul_qt_v3(const float q[4], float r[3]);
-void mul_qt_fl(float q[4], const float f);
+/**
+ * Simple multiply.
+ */
+void mul_qt_fl(float q[4], float f);
-void pow_qt_fl_normalized(float q[4], const float f);
+/**
+ * Raise a unit quaternion to the specified power.
+ */
+void pow_qt_fl_normalized(float q[4], float f);
void sub_qt_qtqt(float q[4], const float a[4], const float b[4]);
void invert_qt(float q[4]);
void invert_qt_qt(float q1[4], const float q2[4]);
+/**
+ * This is just conjugate_qt for cases we know \a q is unit-length.
+ * we could use #conjugate_qt directly, but use this function to show intent,
+ * and assert if its ever becomes non-unit-length.
+ */
void invert_qt_normalized(float q[4]);
void invert_qt_qt_normalized(float q1[4], const float q2[4]);
void conjugate_qt(float q[4]);
@@ -65,36 +107,73 @@ float dot_qtqt(const float a[4], const float b[4]);
float normalize_qt(float q[4]);
float normalize_qt_qt(float r[4], const float q[4]);
-/* comparison */
+/* Comparison. */
+
bool is_zero_qt(const float q[4]);
/* interpolation */
-void interp_dot_slerp(const float t, const float cosom, float w[2]);
-void interp_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
-void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
+/**
+ * Generic function for implementing slerp
+ * (quaternions and spherical vector coords).
+ *
+ * \param t: factor in [0..1]
+ * \param cosom: dot product from normalized vectors/quats.
+ * \param r_w: calculated weights.
+ */
+void interp_dot_slerp(float t, float cosom, float r_w[2]);
+void interp_qt_qtqt(float q[4], const float a[4], const float b[4], float t);
+void add_qt_qtqt(float q[4], const float a[4], const float b[4], float t);
+
+/* Conversion. */
-/* conversion */
void quat_to_mat3(float mat[3][3], const float q[4]);
void quat_to_mat4(float mat[4][4], const float q[4]);
+/**
+ * Apply the rotation of \a a to \a q keeping the values compatible with \a old.
+ * Avoid axis flipping for animated f-curves for eg.
+ */
void quat_to_compatible_quat(float q[4], const float a[4], const float old[4]);
void mat3_normalized_to_quat(float q[4], const float mat[3][3]);
void mat4_normalized_to_quat(float q[4], const float mat[4][4]);
void mat3_to_quat(float q[4], const float mat[3][3]);
void mat4_to_quat(float q[4], const float mat[4][4]);
+/**
+ * Same as tri_to_quat() but takes pre-computed normal from the triangle
+ * used for ngons when we know their normal.
+ */
void tri_to_quat_ex(float quat[4],
const float v1[3],
const float v2[3],
const float v3[3],
const float no_orig[3]);
+/**
+ * \return the length of the normal, use to test for degenerate triangles.
+ */
float tri_to_quat(float q[4], const float a[3], const float b[3], const float c[3]);
-void vec_to_quat(float q[4], const float vec[3], short axis, const short upflag);
-/* NOTE: v1 and v2 must be normalized. */
+void vec_to_quat(float q[4], const float vec[3], short axis, short upflag);
+/**
+ * Calculate a rotation matrix from 2 normalized vectors.
+ * \note `v1` and `v2` must be normalized.
+ */
void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float v2[3]);
+/**
+ * \note Expects vectors to be normalized.
+ */
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3]);
void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q2[4]);
+/**
+ * Decompose a quaternion into a swing rotation (quaternion with the selected
+ * axis component locked at zero), followed by a twist rotation around the axis.
+ *
+ * \param q: input quaternion.
+ * \param axis: twist axis in [0,1,2]
+ * \param r_swing: if not NULL, receives the swing quaternion.
+ * \param r_twist: if not NULL, receives the twist quaternion.
+ * \returns twist angle.
+ */
float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4]);
float angle_normalized_qt(const float q[4]);
@@ -107,45 +186,95 @@ float angle_signed_normalized_qtqt(const float q1[4], const float q2[4]);
float angle_signed_qt(const float q[4]);
float angle_signed_qtqt(const float q1[4], const float q2[4]);
-/* TODO: don't what this is, but it's not the same as mat3_to_quat */
+/**
+ * TODO: don't what this is, but it's not the same as #mat3_to_quat.
+ */
void mat3_to_quat_is_ok(float q[4], const float mat[3][3]);
-/* other */
+/* Other. */
+
void print_qt(const char *str, const float q[4]);
#define print_qt_id(q) print_qt(STRINGIFY(q), q)
-/******************************** Axis Angle *********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Axis Angle
+ * \{ */
+
+/* Conversion. */
-/* conversion */
-void axis_angle_normalized_to_quat(float r[4], const float axis[3], const float angle);
-void axis_angle_to_quat(float r[4], const float axis[3], const float angle);
-void axis_angle_to_mat3(float R[3][3], const float axis[3], const float angle);
+void axis_angle_normalized_to_quat(float r[4], const float axis[3], float angle);
+void axis_angle_to_quat(float r[4], const float axis[3], float angle);
+/**
+ * Axis angle to 3x3 matrix - safer version (normalization of axis performed).
+ */
+void axis_angle_to_mat3(float R[3][3], const float axis[3], float angle);
+/**
+ * axis angle to 3x3 matrix
+ *
+ * This takes the angle with sin/cos applied so we can avoid calculating it in some cases.
+ *
+ * \param axis: rotation axis (must be normalized).
+ * \param angle_sin: sin(angle)
+ * \param angle_cos: cos(angle)
+ */
void axis_angle_normalized_to_mat3_ex(float mat[3][3],
const float axis[3],
- const float angle_sin,
- const float angle_cos);
-void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], const float angle);
-void axis_angle_to_mat4(float R[4][4], const float axis[3], const float angle);
+ float angle_sin,
+ float angle_cos);
+void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], float angle);
+/**
+ * Axis angle to 4x4 matrix - safer version (normalization of axis performed).
+ */
+void axis_angle_to_mat4(float R[4][4], const float axis[3], float angle);
+/**
+ * 3x3 matrix to axis angle.
+ */
void mat3_normalized_to_axis_angle(float axis[3], float *angle, const float M[3][3]);
+/**
+ * 4x4 matrix to axis angle.
+ */
void mat4_normalized_to_axis_angle(float axis[3], float *angle, const float M[4][4]);
void mat3_to_axis_angle(float axis[3], float *angle, const float M[3][3]);
+/**
+ * 4x4 matrix to axis angle.
+ */
void mat4_to_axis_angle(float axis[3], float *angle, const float M[4][4]);
+/**
+ * Quaternions to Axis Angle.
+ */
void quat_to_axis_angle(float axis[3], float *angle, const float q[4]);
-void angle_to_mat2(float R[2][2], const float angle);
-void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle);
-void axis_angle_to_mat4_single(float R[4][4], const char axis, const float angle);
+void angle_to_mat2(float R[2][2], float angle);
+/**
+ * Create a 3x3 rotation matrix from a single axis.
+ */
+void axis_angle_to_mat3_single(float R[3][3], char axis, float angle);
+/**
+ * Create a 4x4 rotation matrix from a single axis.
+ */
+void axis_angle_to_mat4_single(float R[4][4], char axis, float angle);
+
+void axis_angle_to_quat_single(float q[4], char axis, float angle);
-void axis_angle_to_quat_single(float q[4], const char axis, const float angle);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Exponential Map
+ * \{ */
-/****************************** Exponential Map ******************************/
void quat_to_expmap(float expmap[3], const float q[4]);
void quat_normalized_to_expmap(float expmap[3], const float q[4]);
void expmap_to_quat(float r[4], const float expmap[3]);
-/******************************** XYZ Eulers *********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XYZ Eulers
+ * \{ */
void eul_to_quat(float quat[4], const float eul[3]);
void eul_to_mat3(float mat[3][3], const float eul[3]);
@@ -160,16 +289,22 @@ void quat_to_eul(float eul[3], const float quat[4]);
void mat3_normalized_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void mat3_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float quat[4]);
+void rotate_eul(float eul[3], char axis, float angle);
+
+/* Order independent. */
+
void compatible_eul(float eul[3], const float old[3]);
-void rotate_eul(float eul[3], const char axis, const float angle);
+void add_eul_euleul(float r_eul[3], float a[3], float b[3], short order);
+void sub_eul_euleul(float r_eul[3], float a[3], float b[3], short order);
-void add_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
-void sub_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
+/** \} */
-/************************** Arbitrary Order Eulers ***************************/
+/* -------------------------------------------------------------------- */
+/** \name Arbitrary Order Eulers
+ * \{ */
-/* warning: must match the eRotationModes in DNA_action_types.h
+/* WARNING: must match the #eRotationModes in `DNA_action_types.h`
* order matters - types are saved to file. */
typedef enum eEulerRotationOrders {
@@ -183,43 +318,67 @@ typedef enum eEulerRotationOrders {
/* There are 6 more entries with duplicate entries included. */
} eEulerRotationOrders;
-void eulO_to_quat(float quat[4], const float eul[3], const short order);
-void eulO_to_mat3(float mat[3][3], const float eul[3], const short order);
-void eulO_to_mat4(float mat[4][4], const float eul[3], const short order);
-void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const short order);
-void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], const short order);
+/**
+ * Construct quaternion from Euler angles (in radians).
+ */
+void eulO_to_quat(float quat[4], const float eul[3], short order);
+/**
+ * Construct 3x3 matrix from Euler angles (in radians).
+ */
+void eulO_to_mat3(float mat[3][3], const float eul[3], short order);
+/**
+ * Construct 4x4 matrix from Euler angles (in radians).
+ */
+void eulO_to_mat4(float mat[4][4], const float eul[3], short order);
+/**
+ * Euler Rotation to Axis Angle.
+ */
+void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], short order);
+/**
+ * The matrix is written to as 3 axis vectors.
+ */
+void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], short order);
+
+/**
+ * Convert 3x3 matrix to Euler angles (in radians).
+ */
+void mat3_normalized_to_eulO(float eul[3], short order, const float mat[3][3]);
+/**
+ * Convert 4x4 matrix to Euler angles (in radians).
+ */
+void mat4_normalized_to_eulO(float eul[3], short order, const float mat[4][4]);
+void mat3_to_eulO(float eul[3], short order, const float mat[3][3]);
+void mat4_to_eulO(float eul[3], short order, const float mat[4][4]);
+/**
+ * Convert quaternion to Euler angles (in radians).
+ */
+void quat_to_eulO(float eul[3], short order, const float quat[4]);
+/**
+ * Axis Angle to Euler Rotation.
+ */
+void axis_angle_to_eulO(float eul[3], short order, const float axis[3], float angle);
-void mat3_normalized_to_eulO(float eul[3], const short order, const float mat[3][3]);
-void mat4_normalized_to_eulO(float eul[3], const short order, const float mat[4][4]);
-void mat3_to_eulO(float eul[3], const short order, const float mat[3][3]);
-void mat4_to_eulO(float eul[3], const short order, const float mat[4][4]);
-void quat_to_eulO(float eul[3], const short order, const float quat[4]);
-void axis_angle_to_eulO(float eul[3], const short order, const float axis[3], const float angle);
+/* Uses 2 methods to retrieve eulers, and picks the closest. */
void mat3_normalized_to_compatible_eulO(float eul[3],
const float old[3],
- const short order,
+ short order,
const float mat[3][3]);
void mat4_normalized_to_compatible_eulO(float eul[3],
const float old[3],
- const short order,
+ short order,
const float mat[4][4]);
-void mat3_to_compatible_eulO(float eul[3],
- const float old[3],
- const short order,
- const float mat[3][3]);
-void mat4_to_compatible_eulO(float eul[3],
- const float old[3],
- const short order,
- const float mat[4][4]);
-void quat_to_compatible_eulO(float eul[3],
- const float old[3],
- const short order,
- const float quat[4]);
-
-void rotate_eulO(float eul[3], const short order, char axis, float angle);
-
-/******************************* Dual Quaternions ****************************/
+void mat3_to_compatible_eulO(float eul[3], const float old[3], short order, const float mat[3][3]);
+void mat4_to_compatible_eulO(float eul[3], const float old[3], short order, const float mat[4][4]);
+void quat_to_compatible_eulO(float eul[3], const float old[3], short order, const float quat[4]);
+
+void rotate_eulO(float eul[3], short order, char axis, float angle);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dual Quaternions
+ * \{ */
void copy_dq_dq(DualQuat *r, const DualQuat *dq);
void normalize_dq(DualQuat *dq, float totw);
@@ -229,21 +388,39 @@ void mul_v3m3_dq(float r[3], float R[3][3], DualQuat *dq);
void mat4_to_dquat(DualQuat *dq, const float basemat[4][4], const float mat[4][4]);
void dquat_to_mat4(float R[4][4], const DualQuat *dq);
+/**
+ * Axis matches #eTrackToAxis_Modes.
+ */
void quat_apply_track(float quat[4], short axis, short upflag);
void vec_apply_track(float vec[3], short axis);
+/**
+ * Lens/angle conversion (radians).
+ */
float focallength_to_fov(float focal_length, float sensor);
float fov_to_focallength(float fov, float sensor);
float angle_wrap_rad(float angle);
float angle_wrap_deg(float angle);
+/**
+ * Returns an angle compatible with angle_compat.
+ */
float angle_compat_rad(float angle, float angle_compat);
+/**
+ * Each argument us an axis in ['X', 'Y', 'Z', '-X', '-Y', '-Z']
+ * where the first 2 are a source and the second 2 are the target.
+ */
bool mat3_from_axis_conversion(
int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3]);
+/**
+ * Use when the second axis can be guessed.
+ */
bool mat3_from_axis_conversion_single(int src_axis, int dst_axis, float r_mat[3][3]);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_solvers.h b/source/blender/blenlib/BLI_math_solvers.h
index 39a79efc7e2..ca413d2b49c 100644
--- a/source/blender/blenlib/BLI_math_solvers.h
+++ b/source/blender/blenlib/BLI_math_solvers.h
@@ -35,22 +35,61 @@ extern "C" {
# pragma GCC diagnostic ignored "-Wredundant-decls"
#endif
-/********************************** Eigen Solvers *********************************/
+/* -------------------------------------------------------------------- */
+/** \name Eigen Solvers
+ * \{ */
+/**
+ * \brief Compute the eigen values and/or vectors of given 3D symmetric (aka adjoint) matrix.
+ *
+ * \param m3: the 3D symmetric matrix.
+ * \return r_eigen_values the computed eigen values (NULL if not needed).
+ * \return r_eigen_vectors the computed eigen vectors (NULL if not needed).
+ */
bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3],
float r_eigen_values[3],
float r_eigen_vectors[3][3]);
+/**
+ * \brief Compute the SVD (Singular Values Decomposition) of given 3D matrix (m3 = USV*).
+ *
+ * \param m3: the matrix to decompose.
+ * \return r_U the computed left singular vector of \a m3 (NULL if not needed).
+ * \return r_S the computed singular values of \a m3 (NULL if not needed).
+ * \return r_V the computed right singular vector of \a m3 (NULL if not needed).
+ */
void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3][3]);
-/***************************** Simple Solvers ************************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Simple Solvers
+ * \{ */
+
+/**
+ * \brief Solve a tridiagonal system of equations:
+ *
+ * a[i] * r_x[i-1] + b[i] * r_x[i] + c[i] * r_x[i+1] = d[i]
+ *
+ * Ignores a[0] and c[count-1]. Uses the Thomas algorithm, e.g. see wiki.
+ *
+ * \param r_x: output vector, may be shared with any of the input ones
+ * \return true if success
+ */
bool BLI_tridiagonal_solve(
- const float *a, const float *b, const float *c, const float *d, float *r_x, const int count);
+ const float *a, const float *b, const float *c, const float *d, float *r_x, int count);
+/**
+ * \brief Solve a possibly cyclic tridiagonal system using the Sherman-Morrison formula.
+ *
+ * \param r_x: output vector, may be shared with any of the input ones
+ * \return true if success
+ */
bool BLI_tridiagonal_solve_cyclic(
- const float *a, const float *b, const float *c, const float *d, float *r_x, const int count);
+ const float *a, const float *b, const float *c, const float *d, float *r_x, int count);
-/* Generic 3 variable Newton's method solver. */
+/**
+ * Generic 3 variable Newton's method solver.
+ */
typedef void (*Newton3D_DeltaFunc)(void *userdata, const float x[3], float r_delta[3]);
typedef void (*Newton3D_JacobianFunc)(void *userdata, const float x[3], float r_jacobian[3][3]);
typedef bool (*Newton3D_CorrectionFunc)(void *userdata,
@@ -58,6 +97,21 @@ typedef bool (*Newton3D_CorrectionFunc)(void *userdata,
float step[3],
float x_next[3]);
+/**
+ * \brief Solve a generic f(x) = 0 equation using Newton's method.
+ *
+ * \param func_delta: Callback computing the value of f(x).
+ * \param func_jacobian: Callback computing the Jacobian matrix of the function at x.
+ * \param func_correction: Callback for forcing the search into an arbitrary custom domain.
+ * May be NULL.
+ * \param userdata: Data for the callbacks.
+ * \param epsilon: Desired precision.
+ * \param max_iterations: Limit on the iterations.
+ * \param trace: Enables logging to console.
+ * \param x_init: Initial solution vector.
+ * \param result: Final result.
+ * \return true if success
+ */
bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta,
Newton3D_JacobianFunc func_jacobian,
Newton3D_CorrectionFunc func_correction,
@@ -72,6 +126,8 @@ bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta,
# pragma GCC diagnostic pop
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_statistics.h b/source/blender/blenlib/BLI_math_statistics.h
index 6e818f5c8df..586c82a8844 100644
--- a/source/blender/blenlib/BLI_math_statistics.h
+++ b/source/blender/blenlib/BLI_math_statistics.h
@@ -35,17 +35,39 @@ extern "C" {
# pragma GCC diagnostic ignored "-Wredundant-decls"
#endif
-/********************************** Covariance Matrices *********************************/
+/* -------------------------------------------------------------------- */
+/** \name Covariance Matrices
+ * \{ */
-void BLI_covariance_m_vn_ex(const int n,
+/**
+ * \brief Compute the covariance matrix of given set of nD coordinates.
+ *
+ * \param n: the dimension of the vectors (and hence, of the covariance matrix to compute).
+ * \param cos_vn: the nD points to compute covariance from.
+ * \param nbr_cos_vn: the number of nD coordinates in cos_vn.
+ * \param center: the center (or mean point) of cos_vn. If NULL,
+ * it is assumed cos_vn is already centered.
+ * \param use_sample_correction: whether to apply sample correction
+ * (i.e. get 'sample variance' instead of 'population variance').
+ * \return r_covmat the computed covariance matrix.
+ */
+void BLI_covariance_m_vn_ex(int n,
const float *cos_vn,
- const int nbr_cos_vn,
+ int nbr_cos_vn,
const float *center,
- const bool use_sample_correction,
+ bool use_sample_correction,
float *r_covmat);
+/**
+ * \brief Compute the covariance matrix of given set of 3D coordinates.
+ *
+ * \param cos_v3: the 3D points to compute covariance from.
+ * \param nbr_cos_v3: the number of 3D coordinates in cos_v3.
+ * \return r_covmat the computed covariance matrix.
+ * \return r_center the computed center (mean) of 3D points (may be NULL).
+ */
void BLI_covariance_m3_v3n(const float (*cos_v3)[3],
- const int nbr_cos_v3,
- const bool use_sample_correction,
+ int nbr_cos_v3,
+ bool use_sample_correction,
float r_covmat[3][3],
float r_center[3]);
@@ -53,6 +75,8 @@ void BLI_covariance_m3_v3n(const float (*cos_v3)[3],
# pragma GCC diagnostic pop
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_time.h b/source/blender/blenlib/BLI_math_time.h
index 671ec6f857f..52857773797 100644
--- a/source/blender/blenlib/BLI_math_time.h
+++ b/source/blender/blenlib/BLI_math_time.h
@@ -27,7 +27,10 @@
extern "C" {
#endif
-/************************ Time constants definitions***************************/
+/* -------------------------------------------------------------------- */
+/** \name Time Constants Definitions
+ * \{ */
+
#define SECONDS_IN_MILLISECONDS 0.001
#define SECONDS_IN_MINUTE 60.0
#define MINUTES_IN_HOUR 60.0
@@ -37,6 +40,20 @@ extern "C" {
#define SECONDS_IN_DAY (MINUTES_IN_DAY * SECONDS_IN_MINUTE)
#define SECONDS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Time API
+ * \{ */
+
+/**
+ * Explode given time value expressed in seconds, into a set of days, hours, minutes, seconds
+ * and/or milliseconds (depending on which return parameters are not NULL).
+ *
+ * \note The smallest given return parameter will get the potential fractional remaining time
+ * value. E.g. if you give `seconds=90.0` and do not pass `r_seconds` and `r_milliseconds`,
+ * `r_minutes` will be set to `1.5`.
+ */
void BLI_math_time_seconds_decompose(double seconds,
double *r_days,
double *r_hours,
@@ -44,7 +61,15 @@ void BLI_math_time_seconds_decompose(double seconds,
double *r_seconds,
double *r_milliseconds);
-/**************************** Inline Definitions ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline Definitions
+ * \{ */
+
+/* None. */
+
+/** \} */
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_math_vec_mpq_types.hh b/source/blender/blenlib/BLI_math_vec_mpq_types.hh
new file mode 100644
index 00000000000..392c647fe0d
--- /dev/null
+++ b/source/blender/blenlib/BLI_math_vec_mpq_types.hh
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ */
+
+#include "BLI_math_vec_types.hh"
+
+#ifdef WITH_GMP
+
+# include "BLI_math_mpq.hh"
+
+namespace blender {
+
+using mpq2 = vec_base<mpq_class, 2>;
+using mpq3 = vec_base<mpq_class, 3>;
+
+namespace math {
+
+uint64_t hash_mpq_class(const mpq_class &value);
+
+template<> inline uint64_t vector_hash(const mpq2 &vec)
+{
+ return hash_mpq_class(vec.x) ^ (hash_mpq_class(vec.y) * 33);
+}
+
+template<> inline uint64_t vector_hash(const mpq3 &vec)
+{
+ return hash_mpq_class(vec.x) ^ (hash_mpq_class(vec.y) * 33) ^ (hash_mpq_class(vec.z) * 33 * 37);
+}
+
+/**
+ * Cannot do this exactly in rational arithmetic!
+ * Approximate by going in and out of doubles.
+ */
+template<> inline mpq_class length(const mpq2 &a)
+{
+ return mpq_class(sqrt(length_squared(a).get_d()));
+}
+
+/**
+ * Cannot do this exactly in rational arithmetic!
+ * Approximate by going in and out of doubles.
+ */
+template<> inline mpq_class length(const mpq3 &a)
+{
+ return mpq_class(sqrt(length_squared(a).get_d()));
+}
+
+/**
+ * The buffer avoids allocating a temporary variable.
+ */
+inline mpq_class distance_squared_with_buffer(const mpq3 &a, const mpq3 &b, mpq3 &buffer)
+{
+ buffer = a;
+ buffer -= b;
+ return dot(buffer, buffer);
+}
+
+/**
+ * The buffer avoids allocating a temporary variable.
+ */
+inline mpq_class dot_with_buffer(const mpq3 &a, const mpq3 &b, mpq3 &buffer)
+{
+ buffer = a;
+ buffer *= b;
+ buffer.x += buffer.y;
+ buffer.x += buffer.z;
+ return buffer.x;
+}
+
+} // namespace math
+
+} // namespace blender
+
+#endif /* WITH_GMP */
diff --git a/source/blender/blenlib/BLI_math_vec_types.hh b/source/blender/blenlib/BLI_math_vec_types.hh
new file mode 100644
index 00000000000..52aacd294e4
--- /dev/null
+++ b/source/blender/blenlib/BLI_math_vec_types.hh
@@ -0,0 +1,566 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2022, Blender Foundation.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ */
+
+#include <array>
+#include <cmath>
+#include <iostream>
+#include <type_traits>
+
+#include "BLI_math_vector.hh"
+#include "BLI_utildefines.h"
+
+namespace blender {
+
+/* clang-format off */
+template<typename T>
+using as_uint_type = std::conditional_t<sizeof(T) == sizeof(uint8_t), uint8_t,
+ std::conditional_t<sizeof(T) == sizeof(uint16_t), uint16_t,
+ std::conditional_t<sizeof(T) == sizeof(uint32_t), uint32_t,
+ std::conditional_t<sizeof(T) == sizeof(uint64_t), uint64_t, void>>>>;
+/* clang-format on */
+
+template<typename T, int Size> struct vec_struct_base {
+ std::array<T, Size> values;
+};
+
+template<typename T> struct vec_struct_base<T, 2> {
+ T x, y;
+};
+
+template<typename T> struct vec_struct_base<T, 3> {
+ T x, y, z;
+};
+
+template<typename T> struct vec_struct_base<T, 4> {
+ T x, y, z, w;
+};
+
+template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> {
+
+ static constexpr int type_length = Size;
+
+ using base_type = T;
+ using uint_type = vec_base<as_uint_type<T>, Size>;
+
+ vec_base() = default;
+
+ explicit vec_base(uint value)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = static_cast<T>(value);
+ }
+ }
+
+ explicit vec_base(int value)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = static_cast<T>(value);
+ }
+ }
+
+ explicit vec_base(float value)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = static_cast<T>(value);
+ }
+ }
+
+ explicit vec_base(double value)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = static_cast<T>(value);
+ }
+ }
+
+/* Workaround issue with template BLI_ENABLE_IF((Size == 2)) not working. */
+#define BLI_ENABLE_IF_VEC(_size, _test) int S = _size, BLI_ENABLE_IF((S _test))
+
+ template<BLI_ENABLE_IF_VEC(Size, == 2)> vec_base(T _x, T _y)
+ {
+ (*this)[0] = _x;
+ (*this)[1] = _y;
+ }
+
+ template<BLI_ENABLE_IF_VEC(Size, == 3)> vec_base(T _x, T _y, T _z)
+ {
+ (*this)[0] = _x;
+ (*this)[1] = _y;
+ (*this)[2] = _z;
+ }
+
+ template<BLI_ENABLE_IF_VEC(Size, == 4)> vec_base(T _x, T _y, T _z, T _w)
+ {
+ (*this)[0] = _x;
+ (*this)[1] = _y;
+ (*this)[2] = _z;
+ (*this)[3] = _w;
+ }
+
+ /** Mixed scalar-vector constructors. */
+
+ template<typename U, BLI_ENABLE_IF_VEC(Size, == 3)>
+ constexpr vec_base(const vec_base<U, 2> &xy, T z)
+ : vec_base(static_cast<T>(xy.x), static_cast<T>(xy.y), z)
+ {
+ }
+
+ template<typename U, BLI_ENABLE_IF_VEC(Size, == 3)>
+ constexpr vec_base(T x, const vec_base<U, 2> &yz)
+ : vec_base(x, static_cast<T>(yz.x), static_cast<T>(yz.y))
+ {
+ }
+
+ template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)>
+ vec_base(vec_base<U, 3> xyz, T w)
+ : vec_base(
+ static_cast<T>(xyz.x), static_cast<T>(xyz.y), static_cast<T>(xyz.z), static_cast<T>(w))
+ {
+ }
+
+ template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)>
+ vec_base(T x, vec_base<U, 3> yzw)
+ : vec_base(
+ static_cast<T>(x), static_cast<T>(yzw.x), static_cast<T>(yzw.y), static_cast<T>(yzw.z))
+ {
+ }
+
+ template<typename U, typename V, BLI_ENABLE_IF_VEC(Size, == 4)>
+ vec_base(vec_base<U, 2> xy, vec_base<V, 2> zw)
+ : vec_base(
+ static_cast<T>(xy.x), static_cast<T>(xy.y), static_cast<T>(zw.x), static_cast<T>(zw.y))
+ {
+ }
+
+ template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)>
+ vec_base(vec_base<U, 2> xy, T z, T w)
+ : vec_base(static_cast<T>(xy.x), static_cast<T>(xy.y), static_cast<T>(z), static_cast<T>(w))
+ {
+ }
+
+ template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)>
+ vec_base(T x, vec_base<U, 2> yz, T w)
+ : vec_base(static_cast<T>(x), static_cast<T>(yz.x), static_cast<T>(yz.y), static_cast<T>(w))
+ {
+ }
+
+ template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)>
+ vec_base(T x, T y, vec_base<U, 2> zw)
+ : vec_base(static_cast<T>(x), static_cast<T>(y), static_cast<T>(zw.x), static_cast<T>(zw.y))
+ {
+ }
+
+ /** Masking. */
+
+ template<typename U, int OtherSize, BLI_ENABLE_IF(OtherSize > Size)>
+ explicit vec_base(const vec_base<U, OtherSize> &other)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = static_cast<T>(other[i]);
+ }
+ }
+
+#undef BLI_ENABLE_IF_VEC
+
+ /** Conversion from pointers (from C-style vectors). */
+
+ vec_base(const T *ptr)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = ptr[i];
+ }
+ }
+
+ vec_base(const T (*ptr)[Size]) : vec_base(static_cast<const T *>(ptr[0]))
+ {
+ }
+
+ /** Conversion from other vector types. */
+
+ template<typename U> explicit vec_base(const vec_base<U, Size> &vec)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = static_cast<T>(vec[i]);
+ }
+ }
+
+ /** C-style pointer dereference. */
+
+ operator const T *() const
+ {
+ return reinterpret_cast<const T *>(this);
+ }
+
+ operator T *()
+ {
+ return reinterpret_cast<T *>(this);
+ }
+
+ /** Array access. */
+
+ const T &operator[](int index) const
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < Size);
+ return reinterpret_cast<const T *>(this)[index];
+ }
+
+ T &operator[](int index)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < Size);
+ return reinterpret_cast<T *>(this)[index];
+ }
+
+ /** Internal Operators Macro. */
+
+#define BLI_INT_OP(_T) template<typename U = _T, BLI_ENABLE_IF((std::is_integral_v<U>))>
+
+#define BLI_VEC_OP_IMPL(_result, _i, _op) \
+ vec_base _result; \
+ for (int _i = 0; _i < Size; _i++) { \
+ _op; \
+ } \
+ return _result;
+
+#define BLI_VEC_OP_IMPL_SELF(_i, _op) \
+ for (int _i = 0; _i < Size; _i++) { \
+ _op; \
+ } \
+ return *this;
+
+ /** Arithmetic operators. */
+
+ friend vec_base operator+(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] + b[i]);
+ }
+
+ friend vec_base operator+(const vec_base &a, const T &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] + b);
+ }
+
+ friend vec_base operator+(const T &a, const vec_base &b)
+ {
+ return b + a;
+ }
+
+ vec_base &operator+=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] += b[i]);
+ }
+
+ vec_base &operator+=(const T &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] += b);
+ }
+
+ friend vec_base operator-(const vec_base &a)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = -a[i]);
+ }
+
+ friend vec_base operator-(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] - b[i]);
+ }
+
+ friend vec_base operator-(const vec_base &a, const T &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] - b);
+ }
+
+ friend vec_base operator-(const T &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a - b[i]);
+ }
+
+ vec_base &operator-=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] -= b[i]);
+ }
+
+ vec_base &operator-=(const T &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] -= b);
+ }
+
+ friend vec_base operator*(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] * b[i]);
+ }
+
+ friend vec_base operator*(const vec_base &a, T b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] * b);
+ }
+
+ friend vec_base operator*(T a, const vec_base &b)
+ {
+ return b * a;
+ }
+
+ vec_base &operator*=(T b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] *= b);
+ }
+
+ vec_base &operator*=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] *= b[i]);
+ }
+
+ friend vec_base operator/(const vec_base &a, const vec_base &b)
+ {
+ BLI_assert(!math::is_any_zero(b));
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] / b[i]);
+ }
+
+ friend vec_base operator/(const vec_base &a, T b)
+ {
+ BLI_assert(b != T(0));
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] / b);
+ }
+
+ friend vec_base operator/(T a, const vec_base &b)
+ {
+ BLI_assert(!math::is_any_zero(b));
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a / b[i]);
+ }
+
+ vec_base &operator/=(T b)
+ {
+ BLI_assert(b != T(0));
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] /= b);
+ }
+
+ vec_base &operator/=(const vec_base &b)
+ {
+ BLI_assert(!math::is_any_zero(b));
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] /= b[i]);
+ }
+
+ /** Binary operators. */
+
+ BLI_INT_OP(T) friend vec_base operator&(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] & b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator&(const vec_base &a, T b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] & b);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator&(T a, const vec_base &b)
+ {
+ return b & a;
+ }
+
+ BLI_INT_OP(T) vec_base &operator&=(T b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] &= b);
+ }
+
+ BLI_INT_OP(T) vec_base &operator&=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] &= b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator|(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] | b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator|(const vec_base &a, T b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] | b);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator|(T a, const vec_base &b)
+ {
+ return b | a;
+ }
+
+ BLI_INT_OP(T) vec_base &operator|=(T b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] |= b);
+ }
+
+ BLI_INT_OP(T) vec_base &operator|=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] |= b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator^(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] ^ b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator^(const vec_base &a, T b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] ^ b);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator^(T a, const vec_base &b)
+ {
+ return b ^ a;
+ }
+
+ BLI_INT_OP(T) vec_base &operator^=(T b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] ^= b);
+ }
+
+ BLI_INT_OP(T) vec_base &operator^=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] ^= b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator~(const vec_base &a)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = ~a[i]);
+ }
+
+ /** Bit-shift operators. */
+
+ BLI_INT_OP(T) friend vec_base operator<<(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] << b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator<<(const vec_base &a, T b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] << b);
+ }
+
+ BLI_INT_OP(T) vec_base &operator<<=(T b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] <<= b);
+ }
+
+ BLI_INT_OP(T) vec_base &operator<<=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] <<= b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator>>(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] >> b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator>>(const vec_base &a, T b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] >> b);
+ }
+
+ BLI_INT_OP(T) vec_base &operator>>=(T b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] >>= b);
+ }
+
+ BLI_INT_OP(T) vec_base &operator>>=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] >>= b[i]);
+ }
+
+ /** Modulo operators. */
+
+ BLI_INT_OP(T) friend vec_base operator%(const vec_base &a, const vec_base &b)
+ {
+ BLI_assert(!math::is_any_zero(b));
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] % b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator%(const vec_base &a, T b)
+ {
+ BLI_assert(b != 0);
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] % b);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator%(T a, const vec_base &b)
+ {
+ BLI_assert(!math::is_any_zero(b));
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a % b[i]);
+ }
+
+#undef BLI_INT_OP
+#undef BLI_VEC_OP_IMPL
+#undef BLI_VEC_OP_IMPL_SELF
+
+ /** Compare. */
+
+ friend bool operator==(const vec_base &a, const vec_base &b)
+ {
+ for (int i = 0; i < Size; i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ friend bool operator!=(const vec_base &a, const vec_base &b)
+ {
+ return !(a == b);
+ }
+
+ /** Misc. */
+
+ uint64_t hash() const
+ {
+ return math::vector_hash(*this);
+ }
+
+ friend std::ostream &operator<<(std::ostream &stream, const vec_base &v)
+ {
+ stream << "(";
+ for (int i = 0; i < Size; i++) {
+ stream << v[i];
+ if (i != Size - 1) {
+ stream << ", ";
+ }
+ }
+ stream << ")";
+ return stream;
+ }
+};
+
+using int2 = vec_base<int32_t, 2>;
+using int3 = vec_base<int32_t, 3>;
+using int4 = vec_base<int32_t, 4>;
+
+using uint2 = vec_base<uint32_t, 2>;
+using uint3 = vec_base<uint32_t, 3>;
+using uint4 = vec_base<uint32_t, 4>;
+
+using float2 = vec_base<float, 2>;
+using float3 = vec_base<float, 3>;
+using float4 = vec_base<float, 4>;
+
+using double2 = vec_base<double, 2>;
+using double3 = vec_base<double, 3>;
+using double4 = vec_base<double, 4>;
+
+} // namespace blender
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 860ba14a3ed..1ed8d4fc005 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -33,7 +33,9 @@
extern "C" {
#endif
-/************************************* Init ***********************************/
+/* -------------------------------------------------------------------- */
+/** \name Init
+ * \{ */
#ifdef BLI_MATH_GCC_WARN_PRAGMA
# pragma GCC diagnostic push
@@ -57,51 +59,76 @@ MINLINE void swap_v3_v3(float a[3], float b[3]);
MINLINE void swap_v4_v4(float a[4], float b[4]);
/* unsigned char */
+
MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2]);
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3]);
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4]);
-MINLINE void copy_v2_uchar(unsigned char r[2], const unsigned char a);
-MINLINE void copy_v3_uchar(unsigned char r[3], const unsigned char a);
-MINLINE void copy_v4_uchar(unsigned char r[4], const unsigned char a);
+MINLINE void copy_v2_uchar(unsigned char r[2], unsigned char a);
+MINLINE void copy_v3_uchar(unsigned char r[3], unsigned char a);
+MINLINE void copy_v4_uchar(unsigned char r[4], unsigned char a);
/* char */
+
MINLINE void copy_v2_v2_char(char r[2], const char a[2]);
MINLINE void copy_v3_v3_char(char r[3], const char a[3]);
MINLINE void copy_v4_v4_char(char r[4], const char a[4]);
+
/* short */
+
MINLINE void copy_v2_v2_short(short r[2], const short a[2]);
MINLINE void copy_v3_v3_short(short r[3], const short a[3]);
MINLINE void copy_v4_v4_short(short r[4], const short a[4]);
+
/* int */
+
MINLINE void zero_v3_int(int r[3]);
MINLINE void copy_v2_v2_int(int r[2], const int a[2]);
MINLINE void copy_v3_v3_int(int r[3], const int a[3]);
MINLINE void copy_v4_v4_int(int r[4], const int a[4]);
+
/* double */
+
MINLINE void zero_v3_db(double r[3]);
MINLINE void copy_v2_v2_db(double r[2], const double a[2]);
MINLINE void copy_v3_v3_db(double r[3], const double a[3]);
MINLINE void copy_v4_v4_db(double r[4], const double a[4]);
+
/* short -> float */
+
MINLINE void copy_v3fl_v3s(float r[3], const short a[3]);
+
/* int <-> float */
+
MINLINE void copy_v2fl_v2i(float r[2], const int a[2]);
+
+/* int <-> float */
+
MINLINE void round_v2i_v2fl(int r[2], const float a[2]);
+
/* double -> float */
+
MINLINE void copy_v2fl_v2db(float r[2], const double a[2]);
MINLINE void copy_v3fl_v3db(float r[3], const double a[3]);
MINLINE void copy_v4fl_v4db(float r[4], const double a[4]);
+
/* float -> double */
+
MINLINE void copy_v2db_v2fl(double r[2], const float a[2]);
MINLINE void copy_v3db_v3fl(double r[3], const float a[3]);
MINLINE void copy_v4db_v4fl(double r[4], const float a[4]);
+
/* float args -> vec */
+
MINLINE void copy_v2_fl2(float v[2], float x, float y);
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z);
MINLINE void copy_v4_fl4(float v[4], float x, float y, float z, float w);
-/********************************* Arithmetic ********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Arithmetic
+ * \{ */
MINLINE void add_v2_fl(float r[2], float f);
MINLINE void add_v3_fl(float r[3], float f);
@@ -118,7 +145,6 @@ MINLINE void add_v4_v4(float r[4], const float a[4]);
MINLINE void add_v4_v4v4(float r[4], const float a[4], const float b[4]);
MINLINE void add_v3fl_v3fl_v3i(float r[3], const float a[3], const int b[3]);
-MINLINE void add_v3fl_v3fl_v3s(float r[3], const float a[3], const short b[3]);
MINLINE void sub_v2_v2(float r[2], const float a[2]);
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2]);
@@ -149,11 +175,30 @@ MINLINE void mul_v4_v4(float r[4], const float a[4]);
MINLINE void mul_v4_v4fl(float r[4], const float a[4], float f);
MINLINE void mul_v2_v2_cw(float r[2], const float mat[2], const float vec[2]);
MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2]);
+/**
+ * Convenience function to get the projected depth of a position.
+ * This avoids creating a temporary 4D vector and multiplying it - only for the 4th component.
+ *
+ * Matches logic for:
+ *
+ * \code{.c}
+ * float co_4d[4] = {co[0], co[1], co[2], 1.0};
+ * mul_m4_v4(mat, co_4d);
+ * return co_4d[3];
+ * \endcode
+ */
MINLINE float mul_project_m4_v3_zfac(const float mat[4][4],
const float co[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Has the effect of #mul_m3_v3(), on a single axis.
+ */
MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m3_v3_row_y(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Has the effect of #mul_mat3_m4_v3(), on a single axis.
+ * (no adding translation)
+ */
MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m4_v3_row_y(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m4_v3_row_z(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
@@ -180,12 +225,17 @@ MINLINE void negate_v3_v3(float r[3], const float a[3]);
MINLINE void negate_v4(float r[4]);
MINLINE void negate_v4_v4(float r[4], const float a[4]);
+/* could add more... */
+
MINLINE void negate_v3_short(short r[3]);
MINLINE void negate_v3_db(double r[3]);
MINLINE void invert_v2(float r[2]);
MINLINE void invert_v3(float r[3]);
-MINLINE void invert_v3_safe(float r[3]); /* Invert the vector, but leaves zero values as zero. */
+/**
+ * Invert the vector, but leaves zero values as zero.
+ */
+MINLINE void invert_v3_safe(float r[3]);
MINLINE void abs_v2(float r[2]);
MINLINE void abs_v2_v2(float r[2], const float a[2]);
@@ -209,14 +259,26 @@ MINLINE double dot_v3v3_db(const double a[3], const double b[3]) ATTR_WARN_UNUSE
MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE double cross_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3]);
+/**
+ * Cross product suffers from severe precision loss when vectors are
+ * nearly parallel or opposite; doing the computation in double helps a lot.
+ */
MINLINE void cross_v3_v3v3_hi_prec(float r[3], const float a[3], const float b[3]);
MINLINE void cross_v3_v3v3_db(double r[3], const double a[3], const double b[3]);
+/**
+ * Excuse this fairly specific function, its used for polygon normals all over the place
+ * (could use a better name).
+ */
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3]);
-MINLINE void star_m3_v3(float rmat[3][3], float a[3]);
+MINLINE void star_m3_v3(float rmat[3][3], const float a[3]);
+
+/** \} */
-/*********************************** Length **********************************/
+/* -------------------------------------------------------------------- */
+/** \name Length
+ * \{ */
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT;
@@ -240,12 +302,18 @@ MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESU
MINLINE double len_v3_db(const double a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE double len_squared_v3_db(const double v[3]) ATTR_WARN_UNUSED_RESULT;
-MINLINE float normalize_v2_length(float r[2], const float unit_scale);
-MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_scale);
-MINLINE float normalize_v3_length(float r[3], const float unit_scale);
-MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_scale);
-MINLINE double normalize_v3_length_db(double n[3], const double unit_scale);
-MINLINE double normalize_v3_v3_length_db(double r[3], const double a[3], const double unit_scale);
+MINLINE float normalize_v2_length(float r[2], float unit_scale);
+/**
+ * \note any vectors containing `nan` will be zeroed out.
+ */
+MINLINE float normalize_v2_v2_length(float r[2], const float a[2], float unit_scale);
+MINLINE float normalize_v3_length(float r[3], float unit_scale);
+/**
+ * \note any vectors containing `nan` will be zeroed out.
+ */
+MINLINE float normalize_v3_v3_length(float r[3], const float a[3], float unit_scale);
+MINLINE double normalize_v3_length_db(double n[3], double unit_scale);
+MINLINE double normalize_v3_v3_length_db(double r[3], const double a[3], double unit_scale);
MINLINE float normalize_v2(float r[2]);
MINLINE float normalize_v2_v2(float r[2], const float a[2]);
@@ -254,23 +322,39 @@ MINLINE float normalize_v3_v3(float r[3], const float a[3]);
MINLINE double normalize_v3_v3_db(double r[3], const double a[3]);
MINLINE double normalize_v3_db(double n[3]);
-/******************************* Interpolation *******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Interpolation
+ * \{ */
-void interp_v2_v2v2(float r[2], const float a[2], const float b[2], const float t);
-void interp_v2_v2v2_db(double target[2], const double a[2], const double b[2], const double t);
+void interp_v2_v2v2(float r[2], const float a[2], const float b[2], float t);
+void interp_v2_v2v2_db(double target[2], const double a[2], const double b[2], double t);
+/**
+ * Weight 3 2D vectors,
+ * 'w' must be unit length but is not a vector, just 3 weights.
+ */
void interp_v2_v2v2v2(
float r[2], const float a[2], const float b[2], const float c[2], const float t[3]);
-void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t);
-void interp_v3_v3v3_db(double target[3], const double a[3], const double b[3], const double t);
+void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t);
+void interp_v3_v3v3_db(double target[3], const double a[3], const double b[3], double t);
+/**
+ * Weight 3 vectors,
+ * 'w' must be unit length but is not a vector, just 3 weights.
+ */
void interp_v3_v3v3v3(
float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3]);
+/**
+ * Weight 3 vectors,
+ * 'w' must be unit length but is not a vector, just 4 weights.
+ */
void interp_v3_v3v3v3v3(float p[3],
const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3],
const float w[4]);
-void interp_v4_v4v4(float r[4], const float a[4], const float b[4], const float t);
+void interp_v4_v4v4(float r[4], const float a[4], const float b[4], float t);
void interp_v4_v4v4v4(
float p[4], const float v1[4], const float v2[4], const float v3[4], const float w[3]);
void interp_v4_v4v4v4v4(float p[4],
@@ -282,31 +366,40 @@ void interp_v4_v4v4v4v4(float p[4],
void interp_v3_v3v3v3_uv(
float p[3], const float v1[3], const float v2[3], const float v3[3], const float uv[2]);
-bool interp_v3_v3v3_slerp(float target[3], const float a[3], const float b[3], const float t)
+/**
+ * slerp, treat vectors as spherical coordinates
+ * \see #interp_qt_qtqt
+ *
+ * \return success
+ */
+bool interp_v3_v3v3_slerp(float target[3], const float a[3], const float b[3], float t)
ATTR_WARN_UNUSED_RESULT;
-bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], const float t)
+bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], float t)
ATTR_WARN_UNUSED_RESULT;
-void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t);
-void interp_v2_v2v2_slerp_safe(float target[2], const float a[2], const float b[2], const float t);
+/**
+ * Same as #interp_v3_v3v3_slerp but uses fallback values for opposite vectors.
+ */
+void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], float t);
+void interp_v2_v2v2_slerp_safe(float target[2], const float a[2], const float b[2], float t);
void interp_v2_v2v2v2v2_cubic(float p[2],
const float v1[2],
const float v2[2],
const float v3[2],
const float v4[2],
- const float u);
+ float u);
-void interp_v3_v3v3_char(char target[3], const char a[3], const char b[3], const float t);
+void interp_v3_v3v3_char(char target[3], const char a[3], const char b[3], float t);
void interp_v3_v3v3_uchar(unsigned char target[3],
const unsigned char a[3],
const unsigned char b[3],
- const float t);
-void interp_v4_v4v4_char(char target[4], const char a[4], const char b[4], const float t);
+ float t);
+void interp_v4_v4v4_char(char target[4], const char a[4], const char b[4], float t);
void interp_v4_v4v4_uchar(unsigned char target[4],
const unsigned char a[4],
const unsigned char b[4],
- const float t);
+ float t);
void mid_v3_v3v3(float r[3], const float a[3], const float b[3]);
void mid_v2_v2v2(float r[2], const float a[2], const float b[2]);
@@ -314,16 +407,36 @@ void mid_v3_v3v3v3(float v[3], const float v1[3], const float v2[3], const float
void mid_v2_v2v2v2(float v[2], const float v1[2], const float v2[2], const float v3[2]);
void mid_v3_v3v3v3v3(
float v[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
-void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const unsigned int nbr);
+void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], unsigned int nbr);
+/**
+ * Specialized function for calculating normals.
+ * Fast-path for:
+ *
+ * \code{.c}
+ * add_v3_v3v3(r, a, b);
+ * normalize_v3(r)
+ * mul_v3_fl(r, angle_normalized_v3v3(a, b) / M_PI_2);
+ * \endcode
+ *
+ * We can use the length of (a + b) to calculate the angle.
+ */
void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3]);
+/**
+ * Same as mid_v3_v3v3_angle_weighted
+ * but \a r is assumed to be accumulated normals, divided by their total.
+ */
void mid_v3_angle_weighted(float r[3]);
void flip_v4_v4v4(float v[4], const float v1[4], const float v2[4]);
void flip_v3_v3v3(float v[3], const float v1[3], const float v2[3]);
void flip_v2_v2v2(float v[2], const float v1[2], const float v2[2]);
-/********************************* Comparison ********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Comparison
+ * \{ */
MINLINE bool is_zero_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
@@ -347,55 +460,83 @@ MINLINE bool equals_v2v2_int(const int v1[2], const int v2[2]) ATTR_WARN_UNUSED_
MINLINE bool equals_v3v3_int(const int v1[3], const int v2[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool equals_v4v4_int(const int v1[4], const int v2[4]) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool compare_v2v2(const float a[2],
- const float b[2],
- const float limit) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool compare_v3v3(const float a[3],
- const float b[3],
- const float limit) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool compare_v4v4(const float a[4],
- const float b[4],
- const float limit) ATTR_WARN_UNUSED_RESULT;
-
-MINLINE bool compare_v2v2_relative(const float a[2],
- const float b[2],
- const float limit,
- const int max_ulps) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool compare_v3v3_relative(const float a[3],
- const float b[3],
- const float limit,
- const int max_ulps) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool compare_v4v4_relative(const float a[4],
- const float b[4],
- const float limit,
- const int max_ulps) ATTR_WARN_UNUSED_RESULT;
+MINLINE bool compare_v2v2(const float a[2], const float b[2], float limit) ATTR_WARN_UNUSED_RESULT;
+MINLINE bool compare_v3v3(const float a[3], const float b[3], float limit) ATTR_WARN_UNUSED_RESULT;
+MINLINE bool compare_v4v4(const float a[4], const float b[4], float limit) ATTR_WARN_UNUSED_RESULT;
+
+MINLINE bool compare_v2v2_relative(const float a[2], const float b[2], float limit, int max_ulps)
+ ATTR_WARN_UNUSED_RESULT;
+MINLINE bool compare_v3v3_relative(const float a[3], const float b[3], float limit, int max_ulps)
+ ATTR_WARN_UNUSED_RESULT;
+MINLINE bool compare_v4v4_relative(const float a[4], const float b[4], float limit, int max_ulps)
+ ATTR_WARN_UNUSED_RESULT;
MINLINE bool compare_len_v3v3(const float a[3],
const float b[3],
- const float limit) ATTR_WARN_UNUSED_RESULT;
+ float limit) ATTR_WARN_UNUSED_RESULT;
MINLINE bool compare_size_v3v3(const float a[3],
const float b[3],
- const float limit) ATTR_WARN_UNUSED_RESULT;
-
+ float limit) ATTR_WARN_UNUSED_RESULT;
+
+/**
+ * <pre>
+ * + l1
+ * |
+ * neg <- | -> pos
+ * |
+ * + l2
+ * </pre>
+ *
+ * \return Positive value when 'pt' is left-of-line
+ * (looking from 'l1' -> 'l2').
+ */
MINLINE float line_point_side_v2(const float l1[2],
const float l2[2],
const float pt[2]) ATTR_WARN_UNUSED_RESULT;
-/********************************** Angles ***********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Angles
+ * \{ */
/* - angle with 2 arguments is angle between vector.
* - angle with 3 arguments is angle between 3 points at the middle point.
* - angle_normalized_* is faster equivalent if vectors are normalized.
*/
+
+/**
+ * Return the shortest angle in radians between the 2 vectors.
+ */
float angle_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
float angle_signed_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT;
float angle_v2v2v2(const float a[2], const float b[2], const float c[2]) ATTR_WARN_UNUSED_RESULT;
float angle_normalized_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return the shortest angle in radians between the 2 vectors.
+ */
float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return the angle in radians between vecs 1-2 and 2-3 in radians
+ * If v1 is a shoulder, v2 is the elbow and v3 is the hand,
+ * this would return the angle at the elbow.
+ *
+ * note that when v1/v2/v3 represent 3 points along a straight line
+ * that the angle returned will be pi (180deg), rather than 0.0.
+ */
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Quicker than full angle computation.
+ */
float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Quicker than full angle computation.
+ */
float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Angle between 2 vectors, about an axis (axis can be considered a plane).
+ */
float angle_on_axis_v3v3_v3(const float v1[3],
const float v2[3],
const float axis[3]) ATTR_WARN_UNUSED_RESULT;
@@ -403,6 +544,9 @@ float angle_signed_on_axis_v3v3_v3(const float v1[3],
const float v2[3],
const float axis[3]) ATTR_WARN_UNUSED_RESULT;
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Angle between 2 vectors defined by 3 coords, about an axis (axis can be considered a plane).
+ */
float angle_on_axis_v3v3v3_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -416,37 +560,109 @@ void angle_quad_v3(
float angles[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
void angle_poly_v3(float *angles, const float *verts[3], int len);
-/********************************* Geometry **********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry
+ * \{ */
+/**
+ * Project \a p onto \a v_proj
+ */
void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2]);
+/**
+ * Project \a p onto \a v_proj
+ */
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3]);
void project_v3_v3v3_db(double out[3], const double p[3], const double v_proj[3]);
+/**
+ * Project \a p onto a unit length \a v_proj
+ */
void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2]);
+/**
+ * Project \a p onto a unit length \a v_proj
+ */
void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3]);
+/**
+ * In this case plane is a 3D vector only (no 4th component).
+ *
+ * Projecting will make \a out a copy of \a p orthogonal to \a v_plane.
+ *
+ * \note If \a p is exactly perpendicular to \a v_plane, \a out will just be a copy of \a p.
+ *
+ * \note This function is a convenience to call:
+ * \code{.c}
+ * project_v3_v3v3(out, p, v_plane);
+ * sub_v3_v3v3(out, p, out);
+ * \endcode
+ */
void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3]);
void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2]);
void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3]);
void project_plane_normalized_v2_v2v2(float out[2], const float p[2], const float v_plane[2]);
+/**
+ * Project a vector on a plane defined by normal and a plane point p.
+ */
void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3]);
+/**
+ * Returns a reflection vector from a vector and a normal vector
+ * reflect = vec - ((2 * dot(vec, mirror)) * mirror).
+ *
+ * <pre>
+ * v
+ * + ^
+ * \ |
+ * \|
+ * + normal: axis of reflection
+ * /
+ * /
+ * +
+ * out: result (negate for a 'bounce').
+ * </pre>
+ */
void reflect_v3_v3v3(float out[3], const float vec[3], const float normal[3]);
void reflect_v3_v3v3_db(double out[3], const double vec[3], const double normal[3]);
+/**
+ * Takes a vector and computes 2 orthogonal directions.
+ *
+ * \note if \a n is n unit length, computed values will be too.
+ */
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]);
+/**
+ * Calculates \a p - a perpendicular vector to \a v
+ *
+ * \note return vector won't maintain same length.
+ */
void ortho_v3_v3(float out[3], const float v[3]);
+/**
+ * no brainer compared to v3, just have for consistency.
+ */
void ortho_v2_v2(float out[2], const float v[2]);
+/**
+ * Returns a vector bisecting the angle at b formed by a, b and c.
+ */
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]);
-void rotate_v2_v2fl(float r[2], const float p[2], const float angle);
-void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], const float angle);
-void rotate_normalized_v3_v3v3fl(float out[3],
- const float p[3],
- const float axis[3],
- const float angle);
+/**
+ * Rotate a point \a p by \a angle around origin (0, 0)
+ */
+void rotate_v2_v2fl(float r[2], const float p[2], float angle);
+void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], float angle);
+/**
+ * Rotate a point \a p by \a angle around an arbitrary unit length \a axis.
+ * http://local.wasp.uwa.edu.au/~pbourke/geometry/
+ */
+void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], float angle);
+
+/** \} */
-/*********************************** Other ***********************************/
+/* -------------------------------------------------------------------- */
+/** \name Other
+ * \{ */
void print_v2(const char *str, const float v[2]);
void print_v3(const char *str, const float v[3]);
void print_v4(const char *str, const float v[4]);
-void print_vn(const char *str, const float v[], const int n);
+void print_vn(const char *str, const float v[], int n);
#define print_v2_id(v) print_v2(STRINGIFY(v), v)
#define print_v3_id(v) print_v3(STRINGIFY(v), v)
@@ -464,75 +680,73 @@ void minmax_v2v2_v2(float min[2], float max[2], const float vec[2]);
void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float (*vec_arr)[3], int nbr);
-void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist);
-void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist);
+/** ensure \a v1 is \a dist from \a v2 */
+void dist_ensure_v3_v3fl(float v1[3], const float v2[3], float dist);
+void dist_ensure_v2_v2fl(float v1[2], const float v2[2], float dist);
void axis_sort_v3(const float axis_values[3], int r_axis_order[3]);
-MINLINE void clamp_v2(float vec[2], const float min, const float max);
-MINLINE void clamp_v3(float vec[3], const float min, const float max);
-MINLINE void clamp_v4(float vec[4], const float min, const float max);
+MINLINE void clamp_v2(float vec[2], float min, float max);
+MINLINE void clamp_v3(float vec[3], float min, float max);
+MINLINE void clamp_v4(float vec[4], float min, float max);
MINLINE void clamp_v2_v2v2(float vec[2], const float min[2], const float max[2]);
MINLINE void clamp_v3_v3v3(float vec[3], const float min[3], const float max[3]);
MINLINE void clamp_v4_v4v4(float vec[4], const float min[4], const float max[4]);
-/***************************** Array Functions *******************************/
-/* follow fixed length vector function conventions. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Array Functions
+ * \{ */
+
+/**
+ * Follow fixed length vector function conventions.
+ */
+
double dot_vn_vn(const float *array_src_a,
const float *array_src_b,
- const int size) ATTR_WARN_UNUSED_RESULT;
-double len_squared_vn(const float *array, const int size) ATTR_WARN_UNUSED_RESULT;
-float normalize_vn_vn(float *array_tar, const float *array_src, const int size);
-float normalize_vn(float *array_tar, const int size);
-void range_vn_i(int *array_tar, const int size, const int start);
-void range_vn_u(unsigned int *array_tar, const int size, const unsigned int start);
-void range_vn_fl(float *array_tar, const int size, const float start, const float step);
-void negate_vn(float *array_tar, const int size);
-void negate_vn_vn(float *array_tar, const float *array_src, const int size);
-void mul_vn_vn(float *array_tar, const float *array_src, const int size);
-void mul_vn_vnvn(float *array_tar,
- const float *array_src_a,
- const float *array_src_b,
- const int size);
-void mul_vn_fl(float *array_tar, const int size, const float f);
-void mul_vn_vn_fl(float *array_tar, const float *array_src, const int size, const float f);
-void add_vn_vn(float *array_tar, const float *array_src, const int size);
-void add_vn_vnvn(float *array_tar,
- const float *array_src_a,
- const float *array_src_b,
- const int size);
-void madd_vn_vn(float *array_tar, const float *array_src, const float f, const int size);
-void madd_vn_vnvn(float *array_tar,
- const float *array_src_a,
- const float *array_src_b,
- const float f,
- const int size);
-void sub_vn_vn(float *array_tar, const float *array_src, const int size);
-void sub_vn_vnvn(float *array_tar,
- const float *array_src_a,
- const float *array_src_b,
- const int size);
-void msub_vn_vn(float *array_tar, const float *array_src, const float f, const int size);
-void msub_vn_vnvn(float *array_tar,
- const float *array_src_a,
- const float *array_src_b,
- const float f,
- const int size);
-void interp_vn_vn(float *array_tar, const float *array_src, const float t, const int size);
-void copy_vn_i(int *array_tar, const int size, const int val);
-void copy_vn_short(short *array_tar, const int size, const short val);
-void copy_vn_ushort(unsigned short *array_tar, const int size, const unsigned short val);
-void copy_vn_uchar(unsigned char *array_tar, const int size, const unsigned char val);
-void copy_vn_fl(float *array_tar, const int size, const float val);
-
-void add_vn_vn_d(double *array_tar, const double *array_src, const int size);
+ int size) ATTR_WARN_UNUSED_RESULT;
+double len_squared_vn(const float *array, int size) ATTR_WARN_UNUSED_RESULT;
+float normalize_vn_vn(float *array_tar, const float *array_src, int size);
+float normalize_vn(float *array_tar, int size);
+void range_vn_i(int *array_tar, int size, int start);
+void range_vn_u(unsigned int *array_tar, int size, unsigned int start);
+void range_vn_fl(float *array_tar, int size, float start, float step);
+void negate_vn(float *array_tar, int size);
+void negate_vn_vn(float *array_tar, const float *array_src, int size);
+void mul_vn_vn(float *array_tar, const float *array_src, int size);
+void mul_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size);
+void mul_vn_fl(float *array_tar, int size, float f);
+void mul_vn_vn_fl(float *array_tar, const float *array_src, int size, float f);
+void add_vn_vn(float *array_tar, const float *array_src, int size);
+void add_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size);
+void madd_vn_vn(float *array_tar, const float *array_src, float f, int size);
+void madd_vn_vnvn(
+ float *array_tar, const float *array_src_a, const float *array_src_b, float f, int size);
+void sub_vn_vn(float *array_tar, const float *array_src, int size);
+void sub_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size);
+void msub_vn_vn(float *array_tar, const float *array_src, float f, int size);
+void msub_vn_vnvn(
+ float *array_tar, const float *array_src_a, const float *array_src_b, float f, int size);
+void interp_vn_vn(float *array_tar, const float *array_src, float t, int size);
+void copy_vn_i(int *array_tar, int size, int val);
+void copy_vn_short(short *array_tar, int size, short val);
+void copy_vn_ushort(unsigned short *array_tar, int size, unsigned short val);
+void copy_vn_uchar(unsigned char *array_tar, int size, unsigned char val);
+void copy_vn_fl(float *array_tar, int size, float val);
+
+void add_vn_vn_d(double *array_tar, const double *array_src, int size);
void add_vn_vnvn_d(double *array_tar,
const double *array_src_a,
const double *array_src_b,
- const int size);
-void mul_vn_db(double *array_tar, const int size, const double f);
+ int size);
+void mul_vn_db(double *array_tar, int size, double f);
-/**************************** Inline Definitions ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline Definitions
+ * \{ */
#if BLI_MATH_DO_INLINE
# include "intern/math_vector_inline.c"
@@ -542,6 +756,8 @@ void mul_vn_db(double *array_tar, const int size, const double f);
# pragma GCC diagnostic pop
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_vector.hh b/source/blender/blenlib/BLI_math_vector.hh
new file mode 100644
index 00000000000..1d60447445e
--- /dev/null
+++ b/source/blender/blenlib/BLI_math_vector.hh
@@ -0,0 +1,404 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2022, Blender Foundation.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ */
+
+#include <cmath>
+#include <type_traits>
+
+#include "BLI_math_base_safe.h"
+#include "BLI_math_vector.h"
+#include "BLI_span.hh"
+#include "BLI_utildefines.h"
+
+#ifdef WITH_GMP
+# include "BLI_math_mpq.hh"
+#endif
+
+namespace blender::math {
+
+#ifndef NDEBUG
+# define BLI_ASSERT_UNIT(v) \
+ { \
+ const float _test_unit = length_squared(v); \
+ BLI_assert(!(std::abs(_test_unit - 1.0f) >= BLI_ASSERT_UNIT_EPSILON) || \
+ !(std::abs(_test_unit) >= BLI_ASSERT_UNIT_EPSILON)); \
+ } \
+ (void)0
+#else
+# define BLI_ASSERT_UNIT(v) (void)(v)
+#endif
+
+#define bT typename T::base_type
+
+#ifdef WITH_GMP
+# define BLI_ENABLE_IF_FLT_VEC(T) \
+ BLI_ENABLE_IF((std::is_floating_point_v<typename T::base_type> || \
+ std::is_same_v<typename T::base_type, mpq_class>))
+#else
+# define BLI_ENABLE_IF_FLT_VEC(T) BLI_ENABLE_IF((std::is_floating_point_v<typename T::base_type>))
+#endif
+
+#define BLI_ENABLE_IF_INT_VEC(T) BLI_ENABLE_IF((std::is_integral_v<typename T::base_type>))
+
+template<typename T> inline bool is_zero(const T &a)
+{
+ for (int i = 0; i < T::type_length; i++) {
+ if (a[i] != bT(0)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+template<typename T> inline bool is_any_zero(const T &a)
+{
+ for (int i = 0; i < T::type_length; i++) {
+ if (a[i] == bT(0)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+template<typename T> inline T abs(const T &a)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = a[i] >= 0 ? a[i] : -a[i];
+ }
+ return result;
+}
+
+template<typename T> inline T min(const T &a, const T &b)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = a[i] < b[i] ? a[i] : b[i];
+ }
+ return result;
+}
+
+template<typename T> inline T max(const T &a, const T &b)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = a[i] > b[i] ? a[i] : b[i];
+ }
+ return result;
+}
+
+template<typename T> inline T clamp(const T &a, const T &min_v, const T &max_v)
+{
+ T result = a;
+ for (int i = 0; i < T::type_length; i++) {
+ CLAMP(result[i], min_v[i], max_v[i]);
+ }
+ return result;
+}
+
+template<typename T> inline T clamp(const T &a, const bT &min_v, const bT &max_v)
+{
+ T result = a;
+ for (int i = 0; i < T::type_length; i++) {
+ CLAMP(result[i], min_v, max_v);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T mod(const T &a, const T &b)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ BLI_assert(b[i] != 0);
+ result[i] = std::fmod(a[i], b[i]);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T mod(const T &a, bT b)
+{
+ BLI_assert(b != 0);
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = std::fmod(a[i], b);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_mod(const T &a, const T &b)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = (b[i] != 0) ? std::fmod(a[i], b[i]) : 0;
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_mod(const T &a, bT b)
+{
+ if (b == 0) {
+ return T(0.0f);
+ }
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = std::fmod(a[i], b);
+ }
+ return result;
+}
+
+template<typename T> inline void min_max(const T &vector, T &min_vec, T &max_vec)
+{
+ min_vec = min(vector, min_vec);
+ max_vec = max(vector, max_vec);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_divide(const T &a, const T &b)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = (b[i] == 0) ? 0 : a[i] / b[i];
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_divide(const T &a, const bT b)
+{
+ return (b != 0) ? a / b : T(0.0f);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T floor(const T &a)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = std::floor(a[i]);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T ceil(const T &a)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = std::ceil(a[i]);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T fract(const T &a)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = a[i] - std::floor(a[i]);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT dot(const T &a, const T &b)
+{
+ bT result = a[0] * b[0];
+ for (int i = 1; i < T::type_length; i++) {
+ result += a[i] * b[i];
+ }
+ return result;
+}
+
+template<typename T> inline bT length_manhattan(const T &a)
+{
+ bT result = std::abs(a[0]);
+ for (int i = 1; i < T::type_length; i++) {
+ result += std::abs(a[i]);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT length_squared(const T &a)
+{
+ return dot(a, a);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT length(const T &a)
+{
+ return std::sqrt(length_squared(a));
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT distance_manhattan(const T &a, const T &b)
+{
+ return length_manhattan(a - b);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT distance_squared(const T &a, const T &b)
+{
+ return length_squared(a - b);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT distance(const T &a, const T &b)
+{
+ return length(a - b);
+}
+
+template<typename T> uint64_t vector_hash(const T &vec)
+{
+ BLI_STATIC_ASSERT(T::type_length <= 4, "Longer types need to implement vector_hash themself.");
+ const typename T::uint_type &uvec = *reinterpret_cast<const typename T::uint_type *>(&vec);
+ uint64_t result;
+ result = uvec[0] * uint64_t(435109);
+ if constexpr (T::type_length > 1) {
+ result ^= uvec[1] * uint64_t(380867);
+ }
+ if constexpr (T::type_length > 2) {
+ result ^= uvec[2] * uint64_t(1059217);
+ }
+ if constexpr (T::type_length > 3) {
+ result ^= uvec[3] * uint64_t(2002613);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T reflect(const T &incident, const T &normal)
+{
+ BLI_ASSERT_UNIT(normal);
+ return incident - 2.0 * dot(normal, incident) * normal;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)>
+inline T refract(const T &incident, const T &normal, const bT eta)
+{
+ float dot_ni = dot(normal, incident);
+ float k = 1.0f - eta * eta * (1.0f - dot_ni * dot_ni);
+ if (k < 0.0f) {
+ return T(0.0f);
+ }
+ return eta * incident - (eta * dot_ni + sqrt(k)) * normal;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T project(const T &p, const T &v_proj)
+{
+ if (UNLIKELY(is_zero(v_proj))) {
+ return T(0.0f);
+ }
+ return v_proj * (dot(p, v_proj) / dot(v_proj, v_proj));
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)>
+inline T normalize_and_get_length(const T &v, bT &out_length)
+{
+ out_length = length_squared(v);
+ /* A larger value causes normalize errors in a scaled down models with camera extreme close. */
+ constexpr bT threshold = std::is_same_v<bT, double> ? 1.0e-70 : 1.0e-35f;
+ if (out_length > threshold) {
+ out_length = sqrt(out_length);
+ return v / out_length;
+ }
+ /* Either the vector is small or one of it's values contained `nan`. */
+ out_length = 0.0;
+ return T(0.0);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T normalize(const T &v)
+{
+ bT len;
+ return normalize_and_get_length(v, len);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T), BLI_ENABLE_IF((T::type_length == 3))>
+inline T cross(const T &a, const T &b)
+{
+ return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
+}
+
+template<typename T,
+ BLI_ENABLE_IF((std::is_same_v<bT, float>)),
+ BLI_ENABLE_IF((T::type_length == 3))>
+inline T cross_high_precision(const T &a, const T &b)
+{
+ return {(float)((double)a.y * b.z - (double)a.z * b.y),
+ (float)((double)a.z * b.x - (double)a.x * b.z),
+ (float)((double)a.x * b.y - (double)a.y * b.x)};
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T), BLI_ENABLE_IF((T::type_length == 3))>
+inline T cross_poly(Span<T> poly)
+{
+ /* Newell's Method. */
+ int nv = static_cast<int>(poly.size());
+ if (nv < 3) {
+ return T(0, 0, 0);
+ }
+ const T *v_prev = &poly[nv - 1];
+ const T *v_curr = &poly[0];
+ T n(0, 0, 0);
+ for (int i = 0; i < nv;) {
+ n[0] = n[0] + ((*v_prev)[1] - (*v_curr)[1]) * ((*v_prev)[2] + (*v_curr)[2]);
+ n[1] = n[1] + ((*v_prev)[2] - (*v_curr)[2]) * ((*v_prev)[0] + (*v_curr)[0]);
+ n[2] = n[2] + ((*v_prev)[0] - (*v_curr)[0]) * ((*v_prev)[1] + (*v_curr)[1]);
+ v_prev = v_curr;
+ ++i;
+ if (i < nv) {
+ v_curr = &poly[i];
+ }
+ }
+ return n;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T interpolate(const T &a, const T &b, bT t)
+{
+ return a * (1 - t) + b * t;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T midpoint(const T &a, const T &b)
+{
+ return (a + b) * 0.5;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)>
+inline T faceforward(const T &vector, const T &incident, const T &reference)
+{
+ return (dot(reference, incident) < 0) ? vector : -vector;
+}
+
+template<typename T> inline int dominant_axis(const T &a)
+{
+ T b = abs(a);
+ return ((b.x > b.y) ? ((b.x > b.z) ? 0 : 2) : ((b.y > b.z) ? 1 : 2));
+}
+
+/** Intersections. */
+
+template<typename T> struct isect_result {
+ enum {
+ LINE_LINE_COLINEAR = -1,
+ LINE_LINE_NONE = 0,
+ LINE_LINE_EXACT = 1,
+ LINE_LINE_CROSS = 2,
+ } kind;
+ bT lambda;
+};
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)>
+isect_result<T> isect_seg_seg(const T &v1, const T &v2, const T &v3, const T &v4);
+
+#undef BLI_ENABLE_IF_FLT_VEC
+#undef BLI_ENABLE_IF_INT_VEC
+#undef bT
+
+} // namespace blender::math
diff --git a/source/blender/blenlib/BLI_memarena.h b/source/blender/blenlib/BLI_memarena.h
index b2e05b00735..bcfe2efc5e5 100644
--- a/source/blender/blenlib/BLI_memarena.h
+++ b/source/blender/blenlib/BLI_memarena.h
@@ -29,8 +29,8 @@
extern "C" {
#endif
-/* A reasonable standard buffer size, big
- * enough to not cause much internal fragmentation,
+/**
+ * A reasonable standard buffer size, big enough to not cause much internal fragmentation,
* small enough not to waste resources
*/
#define BLI_MEMARENA_STD_BUFSIZE MEM_SIZE_OPTIMAL(1 << 14)
@@ -38,20 +38,34 @@ extern "C" {
struct MemArena;
typedef struct MemArena MemArena;
-struct MemArena *BLI_memarena_new(const size_t bufsize,
+struct MemArena *BLI_memarena_new(size_t bufsize,
const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
ATTR_NONNULL(2) ATTR_MALLOC;
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1);
void BLI_memarena_use_malloc(struct MemArena *ma) ATTR_NONNULL(1);
void BLI_memarena_use_calloc(struct MemArena *ma) ATTR_NONNULL(1);
-void BLI_memarena_use_align(struct MemArena *ma, const size_t align) ATTR_NONNULL(1);
+void BLI_memarena_use_align(struct MemArena *ma, size_t align) ATTR_NONNULL(1);
void *BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2);
void *BLI_memarena_calloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2);
+/**
+ * Transfer ownership of allocated blocks from `ma_src` into `ma_dst`,
+ * cleaning the contents of `ma_src`.
+ *
+ * \note Useful for multi-threaded tasks that need a thread-local #MemArena
+ * that is kept after the multi-threaded operation is completed.
+ *
+ * \note Avoid accumulating memory pools where possible
+ * as any unused memory in `ma_src` is wasted every merge.
+ */
void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src) ATTR_NONNULL(1, 2);
+/**
+ * Clear for reuse, avoids re-allocation when an arena may
+ * otherwise be free'd and recreated.
+ */
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_memblock.h b/source/blender/blenlib/BLI_memblock.h
index a9a3928394d..827ecc49739 100644
--- a/source/blender/blenlib/BLI_memblock.h
+++ b/source/blender/blenlib/BLI_memblock.h
@@ -38,6 +38,10 @@ typedef void (*MemblockValFreeFP)(void *val);
BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size) ATTR_WARN_UNUSED_RESULT;
void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Reset elem count to 0 but keep as much memory allocated needed
+ * for at least the previous elem count.
+ */
void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1);
void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1);
@@ -56,6 +60,11 @@ typedef struct BLI_memblock_iter {
void BLI_memblock_iternew(BLI_memblock *mblk, BLI_memblock_iter *iter) ATTR_NONNULL();
void *BLI_memblock_iterstep(BLI_memblock_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Direct access. elem is element index inside the chosen chunk.
+ * Double usage: You can set chunk to 0 and set the absolute elem index.
+ * The correct chunk will be retrieve.
+ */
void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_memiter.h b/source/blender/blenlib/BLI_memiter.h
index abb1bec809d..231aa31fad9 100644
--- a/source/blender/blenlib/BLI_memiter.h
+++ b/source/blender/blenlib/BLI_memiter.h
@@ -35,10 +35,19 @@ struct BLI_memiter;
typedef struct BLI_memiter BLI_memiter;
-/* warning, ATTR_MALLOC flag on BLI_memiter_alloc causes crash, see: D2756 */
-BLI_memiter *BLI_memiter_create(unsigned int chunk_size)
+/**
+ * \param chunk_size_min: Should be a power of two and
+ * significantly larger than the average element size used.
+ *
+ * While allocations of any size are supported, they won't be efficient
+ * (effectively becoming a single-linked list).
+ *
+ * Its intended that many elements can be stored per chunk.
+ */
+BLI_memiter *BLI_memiter_create(unsigned int chunk_size_min)
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
void *BLI_memiter_alloc(BLI_memiter *mi, unsigned int size)
+ /* WARNING: `ATTR_MALLOC` attribute on #BLI_memiter_alloc causes crash, see: D2756. */
ATTR_RETURNS_NONNULL ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1);
void BLI_memiter_alloc_from(BLI_memiter *mi, uint elem_size, const void *data_from)
ATTR_NONNULL(1, 3);
@@ -48,11 +57,15 @@ void BLI_memiter_destroy(BLI_memiter *mi) ATTR_NONNULL(1);
void BLI_memiter_clear(BLI_memiter *mi) ATTR_NONNULL(1);
unsigned int BLI_memiter_count(const BLI_memiter *mi) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* utils */
+/* Utilities. */
+
+/**
+ * Support direct lookup for the first item.
+ */
void *BLI_memiter_elem_first(BLI_memiter *mi);
void *BLI_memiter_elem_first_size(BLI_memiter *mi, unsigned int *r_size);
-/* private structure */
+/** Private structure. */
typedef struct BLI_memiter_handle {
struct BLI_memiter_elem *elem;
uint elem_left;
diff --git a/source/blender/blenlib/BLI_memory_utils.h b/source/blender/blenlib/BLI_memory_utils.h
index 79e25e26040..09d8f646905 100644
--- a/source/blender/blenlib/BLI_memory_utils.h
+++ b/source/blender/blenlib/BLI_memory_utils.h
@@ -29,7 +29,7 @@ extern "C" {
/* it may be defined already */
#ifndef __BLI_UTILDEFINES_H__
-bool BLI_memory_is_zero(const void *arr, const size_t size);
+bool BLI_memory_is_zero(const void *arr, size_t size);
#endif
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh
index 14eca49d126..9a5be79b61e 100644
--- a/source/blender/blenlib/BLI_memory_utils.hh
+++ b/source/blender/blenlib/BLI_memory_utils.hh
@@ -498,6 +498,12 @@ inline constexpr bool is_span_convertible_pointer_v =
std::is_same_v<To, const void *>);
/**
+ * Same as #std::is_same_v but allows for checking multiple types at the same time.
+ */
+template<typename T, typename... Args>
+inline constexpr bool is_same_any_v = (std::is_same_v<T, Args> || ...);
+
+/**
* Inline buffers for small-object-optimization should be disable by default. Otherwise we might
* get large unexpected allocations on the stack.
*/
diff --git a/source/blender/blenlib/BLI_mempool.h b/source/blender/blenlib/BLI_mempool.h
index 61b572a4943..caf946cabe3 100644
--- a/source/blender/blenlib/BLI_mempool.h
+++ b/source/blender/blenlib/BLI_mempool.h
@@ -44,19 +44,52 @@ void *BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT A
ATTR_NONNULL(1);
void *BLI_mempool_calloc(BLI_mempool *pool)
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1);
+/**
+ * Free an element from the mempool.
+ *
+ * \note doesn't protect against double frees, take care!
+ */
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1, 2);
-void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve) ATTR_NONNULL(1);
+/**
+ * Empty the pool, as if it were just created.
+ *
+ * \param pool: The pool to clear.
+ * \param totelem_reserve: Optionally reserve how many items should be kept from clearing.
+ */
+void BLI_mempool_clear_ex(BLI_mempool *pool, int totelem_reserve) ATTR_NONNULL(1);
+/**
+ * Wrap #BLI_mempool_clear_ex with no reserve set.
+ */
void BLI_mempool_clear(BLI_mempool *pool) ATTR_NONNULL(1);
+/**
+ * Free the mempool itself (and all elements).
+ */
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1);
int BLI_mempool_len(const BLI_mempool *pool) ATTR_NONNULL(1);
void *BLI_mempool_findelem(BLI_mempool *pool, unsigned int index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Fill in \a data with pointers to each element of the mempool,
+ * to create lookup table.
+ *
+ * \param pool: Pool to create a table from.
+ * \param data: array of pointers at least the size of 'pool->totused'
+ */
void BLI_mempool_as_table(BLI_mempool *pool, void **data) ATTR_NONNULL(1, 2);
+/**
+ * A version of #BLI_mempool_as_table that allocates and returns the data.
+ */
void **BLI_mempool_as_tableN(BLI_mempool *pool,
const char *allocstr) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
+/**
+ * Fill in \a data with the contents of the mempool.
+ */
void BLI_mempool_as_array(BLI_mempool *pool, void *data) ATTR_NONNULL(1, 2);
+/**
+ * A version of #BLI_mempool_as_array that allocates and returns the data.
+ */
void *BLI_mempool_as_arrayN(BLI_mempool *pool,
const char *allocstr) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
@@ -67,16 +100,17 @@ void BLI_mempool_set_memory_debug(void);
/**
* Iteration stuff.
- * NOTE: this may easy to produce bugs with.
+ * \note this may easy to produce bugs with.
*/
-/* private structure */
+
+/** \note Private structure. */
typedef struct BLI_mempool_iter {
BLI_mempool *pool;
struct BLI_mempool_chunk *curchunk;
unsigned int curindex;
} BLI_mempool_iter;
-/* flag */
+/** #BLI_mempool.flag */
enum {
BLI_MEMPOOL_NOP = 0,
/** allow iterating on this mempool.
@@ -89,7 +123,13 @@ enum {
BLI_MEMPOOL_ALLOW_ITER = (1 << 0),
};
+/**
+ * Initialize a new mempool iterator, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
+ */
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL();
+/**
+ * Step over the iterator, returning the mempool item or NULL.
+ */
void *BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_mesh_intersect.hh b/source/blender/blenlib/BLI_mesh_intersect.hh
index f28be9bf59b..0ebee6f16a8 100644
--- a/source/blender/blenlib/BLI_mesh_intersect.hh
+++ b/source/blender/blenlib/BLI_mesh_intersect.hh
@@ -28,12 +28,11 @@
# include <iostream>
# include "BLI_array.hh"
-# include "BLI_double3.hh"
-# include "BLI_float3.hh"
# include "BLI_index_range.hh"
# include "BLI_map.hh"
# include "BLI_math_mpq.hh"
-# include "BLI_mpq3.hh"
+# include "BLI_math_vec_mpq_types.hh"
+# include "BLI_math_vec_types.hh"
# include "BLI_span.hh"
# include "BLI_utility_mixins.hh"
# include "BLI_vector.hh"
@@ -91,15 +90,18 @@ struct Plane {
Plane() = default;
Plane(const mpq3 &norm_exact, const mpq_class &d_exact);
- Plane(const double3 &norm, const double d);
+ Plane(const double3 &norm, double d);
- /* Test equality on the exact fields. */
+ /** Test equality on the exact fields. */
bool operator==(const Plane &other) const;
- /* Hash on the exact fields. */
+ /** Hash on the exact fields. */
uint64_t hash() const;
void make_canonical();
+ /**
+ * This is wrong for degenerate planes, but we don't expect to call it on those.
+ */
bool exact_populated() const;
void populate_exact();
};
@@ -395,10 +397,16 @@ struct BoundingBox {
}
};
-/** Assume bounding boxes have been expanded by a sufficient epsilon. */
+/**
+ * Assume bounding boxes have been expanded by a sufficient epsilon on all sides
+ * so that the comparisons against the bb bounds are sufficient to guarantee that
+ * if an overlap or even touching could happen, this will return true.
+ */
bool bbs_might_intersect(const BoundingBox &bb_a, const BoundingBox &bb_b);
/**
+ * This is the main routine for calculating the self_intersection of a triangle mesh.
+ *
* The output will have duplicate vertices merged and degenerate triangles ignored.
* If the input has overlapping co-planar triangles, then there will be
* as many duplicates as there are overlaps in each overlapping triangular region.
@@ -406,7 +414,7 @@ bool bbs_might_intersect(const BoundingBox &bb_a, const BoundingBox &bb_b);
* that the output triangle was a part of (input can have -1 for that field and then
* the index in `tri[]` will be used as the original index).
* The orig structure of the output #IMesh gives the originals for vertices and edges.
- * NOTE: if the input tm_in has a non-empty orig structure, then it is ignored.
+ * \note if the input tm_in has a non-empty orig structure, then it is ignored.
*/
IMesh trimesh_self_intersect(const IMesh &tm_in, IMeshArena *arena);
@@ -416,10 +424,17 @@ IMesh trimesh_nary_intersect(const IMesh &tm_in,
bool use_self,
IMeshArena *arena);
-/** Return an IMesh that is a triangulation of a mesh with general polygonal faces. */
+/**
+ * Return an #IMesh that is a triangulation of a mesh with general
+ * polygonal faces, #IMesh.
+ * Added diagonals will be distinguishable by having edge original
+ * indices of #NO_INDEX.
+ */
IMesh triangulate_polymesh(IMesh &imesh, IMeshArena *arena);
-/** This has the side effect of populating verts in the #IMesh. */
+/**
+ * Writing the obj_mesh has the side effect of populating verts in the #IMesh.
+ */
void write_obj_mesh(IMesh &m, const std::string &objname);
} /* namespace blender::meshintersect */
diff --git a/source/blender/blenlib/BLI_mpq2.hh b/source/blender/blenlib/BLI_mpq2.hh
deleted file mode 100644
index 18bc8821d9c..00000000000
--- a/source/blender/blenlib/BLI_mpq2.hh
+++ /dev/null
@@ -1,184 +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.
- */
-
-#pragma once
-
-/** \file
- * \ingroup bli
- */
-
-#ifdef WITH_GMP
-
-# include "BLI_math_mpq.hh"
-# include "BLI_mpq3.hh"
-
-namespace blender {
-
-struct mpq2 {
- mpq_class x, y;
-
- mpq2() = default;
-
- mpq2(const mpq_class *ptr) : x{ptr[0]}, y{ptr[1]}
- {
- }
-
- mpq2(mpq_class x, mpq_class y) : x(x), y(y)
- {
- }
-
- mpq2(const mpq2 &other) : x(other.x), y(other.y)
- {
- }
-
- mpq2(mpq2 &&other) noexcept : x(std::move(other.x)), y(std::move(other.y))
- {
- }
-
- ~mpq2() = default;
-
- mpq2 &operator=(const mpq2 &other)
- {
- if (this != &other) {
- x = other.x;
- y = other.y;
- }
- return *this;
- }
-
- mpq2 &operator=(mpq2 &&other) noexcept
- {
- x = std::move(other.x);
- y = std::move(other.y);
- return *this;
- }
-
- mpq2(const mpq3 &other) : x(other.x), y(other.y)
- {
- }
-
- operator mpq_class *()
- {
- return &x;
- }
-
- operator const mpq_class *() const
- {
- return &x;
- }
-
- /**
- * Cannot do this exactly in rational arithmetic!
- * Approximate by going in and out of doubles.
- */
- mpq_class length() const
- {
- mpq_class lsquared = dot(*this, *this);
- return mpq_class(sqrt(lsquared.get_d()));
- }
-
- friend mpq2 operator+(const mpq2 &a, const mpq2 &b)
- {
- return {a.x + b.x, a.y + b.y};
- }
-
- friend mpq2 operator-(const mpq2 &a, const mpq2 &b)
- {
- return {a.x - b.x, a.y - b.y};
- }
-
- friend mpq2 operator*(const mpq2 &a, mpq_class b)
- {
- return {a.x * b, a.y * b};
- }
-
- friend mpq2 operator/(const mpq2 &a, mpq_class b)
- {
- BLI_assert(b != 0);
- return {a.x / b, a.y / b};
- }
-
- friend mpq2 operator*(mpq_class a, const mpq2 &b)
- {
- return b * a;
- }
-
- friend bool operator==(const mpq2 &a, const mpq2 &b)
- {
- return a.x == b.x && a.y == b.y;
- }
-
- friend bool operator!=(const mpq2 &a, const mpq2 &b)
- {
- return a.x != b.x || a.y != b.y;
- }
-
- friend std::ostream &operator<<(std::ostream &stream, const mpq2 &v)
- {
- stream << "(" << v.x << ", " << v.y << ")";
- return stream;
- }
-
- static mpq_class dot(const mpq2 &a, const mpq2 &b)
- {
- return a.x * b.x + a.y * b.y;
- }
-
- static mpq2 interpolate(const mpq2 &a, const mpq2 &b, mpq_class t)
- {
- return a * (1 - t) + b * t;
- }
-
- static mpq2 abs(const mpq2 &a)
- {
- mpq_class abs_x = (a.x >= 0) ? a.x : -a.x;
- mpq_class abs_y = (a.y >= 0) ? a.y : -a.y;
- return mpq2(abs_x, abs_y);
- }
-
- static mpq_class distance(const mpq2 &a, const mpq2 &b)
- {
- return (a - b).length();
- }
-
- static mpq_class distance_squared(const mpq2 &a, const mpq2 &b)
- {
- mpq2 diff = a - b;
- return dot(diff, diff);
- }
-
- struct isect_result {
- enum {
- LINE_LINE_COLINEAR = -1,
- LINE_LINE_NONE = 0,
- LINE_LINE_EXACT = 1,
- LINE_LINE_CROSS = 2,
- } kind;
- mpq_class lambda;
- };
-
- static isect_result isect_seg_seg(const mpq2 &v1,
- const mpq2 &v2,
- const mpq2 &v3,
- const mpq2 &v4);
-
- /** There is a sensible use for hashing on exact arithmetic types. */
- uint64_t hash() const;
-};
-
-} // namespace blender
-
-#endif /* WITH_GMP */
diff --git a/source/blender/blenlib/BLI_mpq3.hh b/source/blender/blenlib/BLI_mpq3.hh
deleted file mode 100644
index b9eda2ad7e1..00000000000
--- a/source/blender/blenlib/BLI_mpq3.hh
+++ /dev/null
@@ -1,297 +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.
- */
-
-#pragma once
-
-/** \file
- * \ingroup bli
- */
-
-#ifdef WITH_GMP
-
-# include <iostream>
-
-# include "BLI_math.h"
-# include "BLI_math_mpq.hh"
-# include "BLI_span.hh"
-
-namespace blender {
-
-struct mpq3 {
- mpq_class x, y, z;
-
- mpq3() = default;
-
- mpq3(const mpq_class *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]}
- {
- }
-
- mpq3(const mpq_class (*ptr)[3]) : mpq3((const mpq_class *)ptr)
- {
- }
-
- explicit mpq3(mpq_class value) : x(value), y(value), z(value)
- {
- }
-
- explicit mpq3(int value) : x(value), y(value), z(value)
- {
- }
-
- mpq3(mpq_class x, mpq_class y, mpq_class z) : x{x}, y{y}, z{z}
- {
- }
-
- operator const mpq_class *() const
- {
- return &x;
- }
-
- operator mpq_class *()
- {
- return &x;
- }
-
- /* Cannot do this exactly in rational arithmetic!
- * Approximate by going in and out of doubles.
- */
- mpq_class normalize_and_get_length()
- {
- double dv[3] = {x.get_d(), y.get_d(), z.get_d()};
- double len = normalize_v3_db(dv);
- this->x = mpq_class(dv[0]);
- this->y = mpq_class(dv[1]);
- this->z = mpq_class(dv[2]);
- return len;
- }
-
- mpq3 normalized() const
- {
- double dv[3] = {x.get_d(), y.get_d(), z.get_d()};
- double dr[3];
- normalize_v3_v3_db(dr, dv);
- return mpq3(mpq_class(dr[0]), mpq_class(dr[1]), mpq_class(dr[2]));
- }
-
- /* Cannot do this exactly in rational arithmetic!
- * Approximate by going in and out of double.
- */
- mpq_class length() const
- {
- mpq_class lsquared = this->length_squared();
- double dsquared = lsquared.get_d();
- double d = sqrt(dsquared);
- return mpq_class(d);
- }
-
- mpq_class length_squared() const
- {
- return x * x + y * y + z * z;
- }
-
- void reflect(const mpq3 &normal)
- {
- *this = this->reflected(normal);
- }
-
- mpq3 reflected(const mpq3 &normal) const
- {
- mpq3 result;
- const mpq_class dot2 = 2 * dot(*this, normal);
- result.x = this->x - (dot2 * normal.x);
- result.y = this->y - (dot2 * normal.y);
- result.z = this->z - (dot2 * normal.z);
- return result;
- }
-
- static mpq3 safe_divide(const mpq3 &a, const mpq3 &b)
- {
- mpq3 result;
- result.x = (b.x == 0) ? mpq_class(0) : a.x / b.x;
- result.y = (b.y == 0) ? mpq_class(0) : a.y / b.y;
- result.z = (b.z == 0) ? mpq_class(0) : a.z / b.z;
- return result;
- }
-
- void invert()
- {
- x = -x;
- y = -y;
- z = -z;
- }
-
- friend mpq3 operator+(const mpq3 &a, const mpq3 &b)
- {
- return mpq3(a.x + b.x, a.y + b.y, a.z + b.z);
- }
-
- void operator+=(const mpq3 &b)
- {
- this->x += b.x;
- this->y += b.y;
- this->z += b.z;
- }
-
- friend mpq3 operator-(const mpq3 &a, const mpq3 &b)
- {
- return mpq3(a.x - b.x, a.y - b.y, a.z - b.z);
- }
-
- friend mpq3 operator-(const mpq3 &a)
- {
- return mpq3(-a.x, -a.y, -a.z);
- }
-
- void operator-=(const mpq3 &b)
- {
- this->x -= b.x;
- this->y -= b.y;
- this->z -= b.z;
- }
-
- void operator*=(mpq_class scalar)
- {
- this->x *= scalar;
- this->y *= scalar;
- this->z *= scalar;
- }
-
- void operator*=(const mpq3 &other)
- {
- this->x *= other.x;
- this->y *= other.y;
- this->z *= other.z;
- }
-
- friend mpq3 operator*(const mpq3 &a, const mpq3 &b)
- {
- return {a.x * b.x, a.y * b.y, a.z * b.z};
- }
-
- friend mpq3 operator*(const mpq3 &a, const mpq_class &b)
- {
- return mpq3(a.x * b, a.y * b, a.z * b);
- }
-
- friend mpq3 operator*(const mpq_class &a, const mpq3 &b)
- {
- return mpq3(a * b.x, a * b.y, a * b.z);
- }
-
- friend mpq3 operator/(const mpq3 &a, const mpq_class &b)
- {
- BLI_assert(b != 0);
- return mpq3(a.x / b, a.y / b, a.z / b);
- }
-
- friend bool operator==(const mpq3 &a, const mpq3 &b)
- {
- return a.x == b.x && a.y == b.y && a.z == b.z;
- }
-
- friend bool operator!=(const mpq3 &a, const mpq3 &b)
- {
- return a.x != b.x || a.y != b.y || a.z != b.z;
- }
-
- friend std::ostream &operator<<(std::ostream &stream, const mpq3 &v)
- {
- stream << "(" << v.x << ", " << v.y << ", " << v.z << ")";
- return stream;
- }
-
- static mpq_class dot(const mpq3 &a, const mpq3 &b)
- {
- return a.x * b.x + a.y * b.y + a.z * b.z;
- }
-
- static mpq_class dot_with_buffer(const mpq3 &a, const mpq3 &b, mpq3 &buffer)
- {
- buffer = a;
- buffer *= b;
- buffer.x += buffer.y;
- buffer.x += buffer.z;
- return buffer.x;
- }
-
- static mpq3 cross(const mpq3 &a, const mpq3 &b)
- {
- return mpq3(a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]);
- }
-
- static mpq3 cross_high_precision(const mpq3 &a, const mpq3 &b)
- {
- return cross(a, b);
- }
-
- static mpq3 project(const mpq3 &a, const mpq3 &b)
- {
- const mpq_class mul = mpq3::dot(a, b) / mpq3::dot(b, b);
- return mpq3(mul * b[0], mul * b[1], mul * b[2]);
- }
-
- static mpq_class distance(const mpq3 &a, const mpq3 &b)
- {
- mpq3 diff(a.x - b.x, a.y - b.y, a.z - b.z);
- return diff.length();
- }
-
- static mpq_class distance_squared(const mpq3 &a, const mpq3 &b)
- {
- mpq3 diff(a.x - b.x, a.y - b.y, a.z - b.z);
- return mpq3::dot(diff, diff);
- }
-
- static mpq_class distance_squared_with_buffer(const mpq3 &a, const mpq3 &b, mpq3 &buffer)
- {
- buffer = a;
- buffer -= b;
- return mpq3::dot(buffer, buffer);
- }
-
- static mpq3 interpolate(const mpq3 &a, const mpq3 &b, mpq_class t)
- {
- mpq_class s = 1 - t;
- return mpq3(a.x * s + b.x * t, a.y * s + b.y * t, a.z * s + b.z * t);
- }
-
- static mpq3 abs(const mpq3 &a)
- {
- mpq_class abs_x = (a.x >= 0) ? a.x : -a.x;
- mpq_class abs_y = (a.y >= 0) ? a.y : -a.y;
- mpq_class abs_z = (a.z >= 0) ? a.z : -a.z;
- return mpq3(abs_x, abs_y, abs_z);
- }
-
- static int dominant_axis(const mpq3 &a)
- {
- mpq_class x = (a.x >= 0) ? a.x : -a.x;
- mpq_class y = (a.y >= 0) ? a.y : -a.y;
- mpq_class z = (a.z >= 0) ? a.z : -a.z;
- return ((x > y) ? ((x > z) ? 0 : 2) : ((y > z) ? 1 : 2));
- }
-
- static mpq3 cross_poly(Span<mpq3> poly);
-
- /** There is a sensible use for hashing on exact arithmetic types. */
- uint64_t hash() const;
-};
-
-uint64_t hash_mpq_class(const mpq_class &value);
-
-} // namespace blender
-
-#endif /* WITH_GMP */
diff --git a/source/blender/blenlib/BLI_noise.h b/source/blender/blenlib/BLI_noise.h
index 37afd8ee031..51aee9dc2ba 100644
--- a/source/blender/blenlib/BLI_noise.h
+++ b/source/blender/blenlib/BLI_noise.h
@@ -29,21 +29,65 @@ extern "C" {
float BLI_noise_hnoise(float noisesize, float x, float y, float z);
float BLI_noise_hnoisep(float noisesize, float x, float y, float z);
+/**
+ * Original turbulence functions.
+ */
float BLI_noise_turbulence(float noisesize, float x, float y, float z, int nr);
-/* newnoise: generic noise & turbulence functions
+/**
+ * newnoise: generic noise & turbulence functions
* to replace the above BLI_noise_hnoise/p & BLI_noise_turbulence/1.
- * This is done so different noise basis functions can be used */
+ * This is done so different noise basis functions can be used.
+ */
+/**
+ * newnoise: generic noise function for use with different `noisebasis`.
+ */
float BLI_noise_generic_noise(
float noisesize, float x, float y, float z, bool hard, int noisebasis);
+/**
+ * newnoise: generic turbulence function for use with different `noisebasis`.
+ */
float BLI_noise_generic_turbulence(
float noisesize, float x, float y, float z, int oct, bool hard, int noisebasis);
+
/* newnoise: musgrave functions */
+
+/**
+ * Procedural `fBm` evaluated at "point"; returns value stored in "value".
+ *
+ * \param H: is the fractal increment parameter.
+ * \param lacunarity: is the gap between successive frequencies.
+ * \param octaves: is the number of frequencies in the `fBm`.
+ */
float BLI_noise_mg_fbm(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis);
+/**
+ * Procedural multi-fractal evaluated at "point";
+ * returns value stored in "value".
+ *
+ * \param H: determines the highest fractal dimension.
+ * \param lacunarity: is gap between successive frequencies.
+ * \param octaves: is the number of frequencies in the `fBm`.
+ *
+ * \note There used to be a parameter called `offset`, old docs read:
+ * is the zero offset, which determines multi-fractality.
+ */
float BLI_noise_mg_multi_fractal(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis);
+/**
+ * "Variable Lacunarity Noise"
+ * A distorted variety of Perlin noise.
+ */
float BLI_noise_mg_variable_lacunarity(
float x, float y, float z, float distortion, int nbas1, int nbas2);
+/**
+ * Heterogeneous procedural terrain function: stats by altitude method.
+ * Evaluated at "point"; returns value stored in "value".
+ *
+ * \param H: Determines the fractal dimension of the roughest areas.
+ * \param lacunarity: Is the gap between successive frequencies.
+ * \param octaves: Is the number of frequencies in the `fBm`.
+ * \param offset: Raises the terrain from `sea level`.
+ */
float BLI_noise_mg_hetero_terrain(float x,
float y,
float z,
@@ -52,6 +96,14 @@ float BLI_noise_mg_hetero_terrain(float x,
float octaves,
float offset,
int noisebasis);
+/**
+ * Hybrid additive/multiplicative multi-fractal terrain model.
+ *
+ * Some good parameter values to start with:
+ *
+ * \param H: 0.25
+ * \param offset: 0.7
+ */
float BLI_noise_mg_hybrid_multi_fractal(float x,
float y,
float z,
@@ -61,6 +113,15 @@ float BLI_noise_mg_hybrid_multi_fractal(float x,
float offset,
float gain,
int noisebasis);
+/**
+ * Ridged multi-fractal terrain model.
+ *
+ * Some good parameter values to start with:
+ *
+ * \param H: 1.0
+ * \param offset: 1.0
+ * \param gain: 2.0
+ */
float BLI_noise_mg_ridged_multi_fractal(float x,
float y,
float z,
@@ -71,9 +132,20 @@ float BLI_noise_mg_ridged_multi_fractal(float x,
float gain,
int noisebasis);
/* newnoise: voronoi */
+
+/**
+ * Not 'pure' Worley, but the results are virtually the same.
+ * Returns distances in da and point coords in `pa`.
+ */
void BLI_noise_voronoi(float x, float y, float z, float *da, float *pa, float me, int dtype);
-/* newnoise: BLI_noise_cell & BLI_noise_cell_v3 (for vector/point/color) */
+/**
+ * newnoise: BLI_noise_cell & BLI_noise_cell_v3 (for vector/point/color).
+ * idem, signed.
+ */
float BLI_noise_cell(float x, float y, float z);
+/**
+ * Returns a vector/point/color in `r_ca`, using point hash-array directly.
+ */
void BLI_noise_cell_v3(float x, float y, float z, float r_ca[3]);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_noise.hh b/source/blender/blenlib/BLI_noise.hh
index 7e1655f7864..297c65c250a 100644
--- a/source/blender/blenlib/BLI_noise.hh
+++ b/source/blender/blenlib/BLI_noise.hh
@@ -16,72 +16,90 @@
#pragma once
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
-#include "BLI_float4.hh"
+#include "BLI_math_vec_types.hh"
namespace blender::noise {
-/* --------------------------------------------------------------------
- * Hash functions.
-
+/* -------------------------------------------------------------------- */
+/** \name Hash Functions
+ *
* Create a randomized hash from the given inputs. Contrary to hash functions in `BLI_hash.hh`
* these functions produce better randomness but are more expensive to compute.
- */
+ * \{ */
/* Hash integers to `uint32_t`. */
+
uint32_t hash(uint32_t kx);
uint32_t hash(uint32_t kx, uint32_t ky);
uint32_t hash(uint32_t kx, uint32_t ky, uint32_t kz);
uint32_t hash(uint32_t kx, uint32_t ky, uint32_t kz, uint32_t kw);
/* Hash floats to `uint32_t`. */
+
uint32_t hash_float(float kx);
uint32_t hash_float(float2 k);
uint32_t hash_float(float3 k);
uint32_t hash_float(float4 k);
/* Hash integers to `float` between 0 and 1. */
+
float hash_to_float(uint32_t kx);
float hash_to_float(uint32_t kx, uint32_t ky);
float hash_to_float(uint32_t kx, uint32_t ky, uint32_t kz);
float hash_to_float(uint32_t kx, uint32_t ky, uint32_t kz, uint32_t kw);
/* Hash floats to `float` between 0 and 1. */
+
float hash_float_to_float(float k);
float hash_float_to_float(float2 k);
float hash_float_to_float(float3 k);
float hash_float_to_float(float4 k);
-/* --------------------------------------------------------------------
- * Perlin noise.
- */
+float2 hash_float_to_float2(float2 k);
+
+float3 hash_float_to_float3(float k);
+float3 hash_float_to_float3(float2 k);
+float3 hash_float_to_float3(float3 k);
+float3 hash_float_to_float3(float4 k);
+
+float4 hash_float_to_float4(float4 k);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Perlin Noise
+ * \{ */
/* Perlin noise in the range [-1, 1]. */
+
float perlin_signed(float position);
float perlin_signed(float2 position);
float perlin_signed(float3 position);
float perlin_signed(float4 position);
/* Perlin noise in the range [0, 1]. */
+
float perlin(float position);
float perlin(float2 position);
float perlin(float3 position);
float perlin(float4 position);
/* Fractal perlin noise in the range [0, 1]. */
+
float perlin_fractal(float position, float octaves, float roughness);
float perlin_fractal(float2 position, float octaves, float roughness);
float perlin_fractal(float3 position, float octaves, float roughness);
float perlin_fractal(float4 position, float octaves, float roughness);
/* Positive distorted fractal perlin noise. */
+
float perlin_fractal_distorted(float position, float octaves, float roughness, float distortion);
float perlin_fractal_distorted(float2 position, float octaves, float roughness, float distortion);
float perlin_fractal_distorted(float3 position, float octaves, float roughness, float distortion);
float perlin_fractal_distorted(float4 position, float octaves, float roughness, float distortion);
/* Positive distorted fractal perlin noise that outputs a float3. */
+
float3 perlin_float3_fractal_distorted(float position,
float octaves,
float roughness,
@@ -99,4 +117,289 @@ float3 perlin_float3_fractal_distorted(float4 position,
float roughness,
float distortion);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Musgrave Multi Fractal
+ * \{ */
+
+/**
+ * 1D Ridged Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
+float musgrave_ridged_multi_fractal(
+ float co, float H, float lacunarity, float octaves, float offset, float gain);
+/**
+ * 2D Ridged Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
+float musgrave_ridged_multi_fractal(
+ const float2 co, float H, float lacunarity, float octaves, float offset, float gain);
+/**
+ * 3D Ridged Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
+float musgrave_ridged_multi_fractal(
+ const float3 co, float H, float lacunarity, float octaves, float offset, float gain);
+/**
+ * 4D Ridged Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
+float musgrave_ridged_multi_fractal(
+ const float4 co, float H, float lacunarity, float octaves, float offset, float gain);
+
+/**
+ * 1D Hybrid Additive/Multiplicative Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
+float musgrave_hybrid_multi_fractal(
+ float co, float H, float lacunarity, float octaves, float offset, float gain);
+/**
+ * 2D Hybrid Additive/Multiplicative Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
+float musgrave_hybrid_multi_fractal(
+ const float2 co, float H, float lacunarity, float octaves, float offset, float gain);
+/**
+ * 3D Hybrid Additive/Multiplicative Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
+float musgrave_hybrid_multi_fractal(
+ const float3 co, float H, float lacunarity, float octaves, float offset, float gain);
+/**
+ * 4D Hybrid Additive/Multiplicative Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
+float musgrave_hybrid_multi_fractal(
+ const float4 co, float H, float lacunarity, float octaves, float offset, float gain);
+
+/**
+ * 1D Musgrave fBm
+ *
+ * \param H: fractal increment parameter.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
+float musgrave_fBm(float co, float H, float lacunarity, float octaves);
+
+/**
+ * 2D Musgrave fBm
+ *
+ * \param H: fractal increment parameter.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
+float musgrave_fBm(const float2 co, float H, float lacunarity, float octaves);
+/**
+ * 3D Musgrave fBm
+ *
+ * \param H: fractal increment parameter.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
+float musgrave_fBm(const float3 co, float H, float lacunarity, float octaves);
+/**
+ * 4D Musgrave fBm
+ *
+ * \param H: fractal increment parameter.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
+float musgrave_fBm(const float4 co, float H, float lacunarity, float octaves);
+
+/**
+ * 1D Musgrave Multi-fractal
+ *
+ * \param H: highest fractal dimension.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
+float musgrave_multi_fractal(float co, float H, float lacunarity, float octaves);
+/**
+ * 2D Musgrave Multi-fractal
+ *
+ * \param H: highest fractal dimension.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
+float musgrave_multi_fractal(const float2 co, float H, float lacunarity, float octaves);
+/**
+ * 3D Musgrave Multi-fractal
+ *
+ * \param H: highest fractal dimension.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
+float musgrave_multi_fractal(const float3 co, float H, float lacunarity, float octaves);
+/**
+ * 4D Musgrave Multi-fractal
+ *
+ * \param H: highest fractal dimension.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
+float musgrave_multi_fractal(const float4 co, float H, float lacunarity, float octaves);
+
+/**
+ * 1D Musgrave Heterogeneous Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
+float musgrave_hetero_terrain(float co, float H, float lacunarity, float octaves, float offset);
+/**
+ * 2D Musgrave Heterogeneous Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
+float musgrave_hetero_terrain(
+ const float2 co, float H, float lacunarity, float octaves, float offset);
+/**
+ * 3D Musgrave Heterogeneous Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
+float musgrave_hetero_terrain(
+ const float3 co, float H, float lacunarity, float octaves, float offset);
+/**
+ * 4D Musgrave Heterogeneous Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
+float musgrave_hetero_terrain(
+ const float4 co, float H, float lacunarity, float octaves, float offset);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Voronoi Noise
+ * \{ */
+
+void voronoi_f1(float w, float randomness, float *r_distance, float3 *r_color, float *r_w);
+void voronoi_smooth_f1(
+ float w, float smoothness, float randomness, float *r_distance, float3 *r_color, float *r_w);
+void voronoi_f2(float w, float randomness, float *r_distance, float3 *r_color, float *r_w);
+void voronoi_distance_to_edge(float w, float randomness, float *r_distance);
+void voronoi_n_sphere_radius(float w, float randomness, float *r_radius);
+
+void voronoi_f1(const float2 coord,
+ float exponent,
+ float randomness,
+ int metric,
+ float *r_distance,
+ float3 *r_color,
+ float2 *r_position);
+void voronoi_smooth_f1(const float2 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ int metric,
+ float *r_distance,
+ float3 *r_color,
+ float2 *r_position);
+void voronoi_f2(const float2 coord,
+ float exponent,
+ float randomness,
+ int metric,
+ float *r_distance,
+ float3 *r_color,
+ float2 *r_position);
+void voronoi_distance_to_edge(const float2 coord, float randomness, float *r_distance);
+void voronoi_n_sphere_radius(const float2 coord, float randomness, float *r_radius);
+
+void voronoi_f1(const float3 coord,
+ float exponent,
+ float randomness,
+ int metric,
+ float *r_distance,
+ float3 *r_color,
+ float3 *r_position);
+void voronoi_smooth_f1(const float3 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ int metric,
+ float *r_distance,
+ float3 *r_color,
+ float3 *r_position);
+void voronoi_f2(const float3 coord,
+ float exponent,
+ float randomness,
+ int metric,
+ float *r_distance,
+ float3 *r_color,
+ float3 *r_position);
+void voronoi_distance_to_edge(const float3 coord, float randomness, float *r_distance);
+void voronoi_n_sphere_radius(const float3 coord, float randomness, float *r_radius);
+
+void voronoi_f1(const float4 coord,
+ float exponent,
+ float randomness,
+ int metric,
+ float *r_distance,
+ float3 *r_color,
+ float4 *r_position);
+void voronoi_smooth_f1(const float4 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ int metric,
+ float *r_distance,
+ float3 *r_color,
+ float4 *r_position);
+void voronoi_f2(const float4 coord,
+ float exponent,
+ float randomness,
+ int metric,
+ float *r_distance,
+ float3 *r_color,
+ float4 *r_position);
+void voronoi_distance_to_edge(const float4 coord, float randomness, float *r_distance);
+void voronoi_n_sphere_radius(const float4 coord, float randomness, float *r_radius);
+
+/** \} */
+
} // namespace blender::noise
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index e4774c58e84..658cc0c3825 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -29,29 +29,110 @@
extern "C" {
#endif
+/**
+ * Sets the specified environment variable to the specified value,
+ * and clears it if `val == NULL`.
+ */
void BLI_setenv(const char *env, const char *val) ATTR_NONNULL(1);
+/**
+ * Only set an environment variable if already not there.
+ * Like Unix `setenv(env, val, 0);`
+ *
+ * (not used anywhere).
+ */
void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1);
+/**
+ * Get an environment variable, result has to be used immediately.
+ *
+ * On windows #getenv gets its variables from a static copy of the environment variables taken at
+ * process start-up, causing it to not pick up on environment variables created during runtime.
+ * This function uses an alternative method to get environment variables that does pick up on
+ * runtime environment variables. The result will be UTF-8 encoded.
+ */
const char *BLI_getenv(const char *env) ATTR_NONNULL(1);
+/**
+ * Returns in `string` the concatenation of `dir` and `file` (also with `relabase` on the
+ * front if specified and `dir` begins with "//"). Normalizes all occurrences of path
+ * separators, including ensuring there is exactly one between the copies of `dir` and `file`,
+ * and between the copies of `relabase` and `dir`.
+ *
+ * \param relabase: Optional prefix to substitute for "//" on front of `dir`.
+ * \param string: Area to return result.
+ */
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file);
+/**
+ * Ensures that the parent directory of `name` exists.
+ *
+ * \return true on success (i.e. given path now exists on file-system), false otherwise.
+ */
bool BLI_make_existing_file(const char *name);
-void BLI_split_dirfile(
- const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen);
-void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen);
-void BLI_split_file_part(const char *string, char *file, const size_t filelen);
+/**
+ * Converts `/foo/bar.txt` to `/foo/` and `bar.txt`
+ *
+ * - Won't change \a string.
+ * - Won't create any directories.
+ * - Doesn't use CWD, or deal with relative paths.
+ * - Only fill's in \a dir and \a file when they are non NULL.
+ */
+void BLI_split_dirfile(const char *string, char *dir, char *file, size_t dirlen, size_t filelen);
+/**
+ * Copies the parent directory part of string into `dir`, max length `dirlen`.
+ */
+void BLI_split_dir_part(const char *string, char *dir, size_t dirlen);
+/**
+ * Copies the leaf filename part of string into `file`, max length `filelen`.
+ */
+void BLI_split_file_part(const char *string, char *file, size_t filelen);
+/**
+ * Returns a pointer to the last extension (e.g. the position of the last period).
+ * Returns NULL if there is no extension.
+ */
const char *BLI_path_extension(const char *filepath) ATTR_NONNULL();
-void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file)
+/**
+ * Append a filename to a dir, ensuring slash separates.
+ */
+void BLI_path_append(char *__restrict dst, size_t maxlen, const char *__restrict file)
ATTR_NONNULL();
+/**
+ * Simple appending of filename to dir, does not check for valid path!
+ * Puts result into `dst`, which may be same area as `dir`.
+ *
+ * \note Consider using #BLI_path_join for more general path joining
+ * that de-duplicates separators and can handle an arbitrary number of paths.
+ */
void BLI_join_dirfile(char *__restrict dst,
- const size_t maxlen,
+ size_t maxlen,
const char *__restrict dir,
const char *__restrict file) ATTR_NONNULL();
-size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path_first, ...)
+/**
+ * Join multiple strings into a path, ensuring only a single path separator between each,
+ * and trailing slash is kept.
+ *
+ * \note If you want a trailing slash, add `SEP_STR` as the last path argument,
+ * duplicate slashes will be cleaned up.
+ */
+size_t BLI_path_join(char *__restrict dst, size_t dst_len, const char *path_first, ...)
ATTR_NONNULL(1, 3) ATTR_SENTINEL(0);
+/**
+ * Like Python's `os.path.basename()`
+ *
+ * \return The pointer into \a path string immediately after last slash,
+ * or start of \a path if none found.
+ */
const char *BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Get an element of the path at an index, eg:
+ * "/some/path/file.txt" where an index of:
+ * - 0 or -3: "some"
+ * - 1 or -2: "path"
+ * - 2 or -1: "file.txt"
+ *
+ * Ignores multiple slashes at any point in the path (including start/end).
+ */
bool BLI_path_name_at_index(const char *__restrict path,
- const int index,
+ int index,
int *__restrict r_offset,
int *__restrict r_len) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
@@ -59,59 +140,239 @@ bool BLI_path_name_at_index(const char *__restrict path,
bool BLI_path_contains(const char *container_path,
const char *containee_path) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \return pointer to the leftmost path separator in string (or NULL when not found).
+ */
+const char *BLI_path_slash_find(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * \return pointer to the rightmost path separator in string (or NULL when not found).
+ */
const char *BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Appends a slash to string if there isn't one there already.
+ * Returns the new length of the string.
+ */
int BLI_path_slash_ensure(char *string) ATTR_NONNULL();
+/**
+ * Removes the last slash and everything after it to the end of string, if there is one.
+ */
void BLI_path_slash_rstrip(char *string) ATTR_NONNULL();
-const char *BLI_path_slash_find(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Changes to the path separators to the native ones for this OS.
+ */
void BLI_path_slash_native(char *path) ATTR_NONNULL();
#ifdef _WIN32
-bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen);
+bool BLI_path_program_extensions_add_win32(char *name, size_t maxlen);
#endif
-bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *name);
+/**
+ * Search for a binary (executable)
+ */
+bool BLI_path_program_search(char *fullname, size_t maxlen, const char *name);
+/**
+ * \return true when `str` end with `ext` (case insensitive).
+ */
bool BLI_path_extension_check(const char *str, const char *ext)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
bool BLI_path_extension_check_n(const char *str, ...) ATTR_NONNULL(1) ATTR_SENTINEL(0);
+/**
+ * \return true when `str` ends with any of the suffixes in `ext_array`.
+ */
bool BLI_path_extension_check_array(const char *str, const char **ext_array)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Semicolon separated wildcards, eg: `*.zip;*.py;*.exe`
+ * does `str` match any of the semicolon-separated glob patterns in #fnmatch.
+ */
bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Does basic validation of the given glob string, to prevent common issues from string
+ * truncation.
+ *
+ * For now, only forbids last group to be a wildcard-only one, if there are more than one group
+ * (i.e. things like `*.txt;*.cpp;*` are changed to `*.txt;*.cpp;`)
+ *
+ * \returns true if it had to modify given \a ext_fnmatch pattern.
+ */
bool BLI_path_extension_glob_validate(char *ext_fnmatch) ATTR_NONNULL();
+/**
+ * Removes any existing extension on the end of \a path and appends \a ext.
+ * \return false if there was no room.
+ */
bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
+/**
+ * Strip's trailing '.'s and adds the extension only when needed
+ */
bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
+/**
+ * Ensure `filepath` has a file component, adding `filename` when it's empty or ends with a slash.
+ * \return true if the `filename` was appended to `filepath`.
+ */
bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL();
+/**
+ * Looks for a sequence of decimal digits in string, preceding any filename extension,
+ * returning the integer value if found, or 0 if not.
+ *
+ * \param string: String to scan.
+ * \param head: Optional area to return copy of part of string prior to digits,
+ * or before dot if no digits.
+ * \param tail: Optional area to return copy of part of string following digits,
+ * or from dot if no digits.
+ * \param r_num_len: Optional to return number of digits found.
+ */
int BLI_path_sequence_decode(const char *string,
char *head,
char *tail,
unsigned short *r_num_len);
+/**
+ * Returns in area pointed to by string a string of the form `<head><pic><tail>`,
+ * where pic is formatted as `numlen` digits with leading zeroes.
+ */
void BLI_path_sequence_encode(
char *string, const char *head, const char *tail, unsigned short numlen, int pic);
+/**
+ * Remove redundant characters from \a path and optionally make absolute.
+ *
+ * \param relabase: The path this is relative to, or ignored when NULL.
+ * \param path: Can be any input, and this function converts it to a regular full path.
+ * Also removes garbage from directory paths, like `/../` or double slashes etc.
+ *
+ * \note \a path isn't protected for max string names.
+ */
void BLI_path_normalize(const char *relabase, char *path) ATTR_NONNULL(2);
-/* Same as above but adds a trailing slash. */
+/**
+ * Cleanup file-path ensuring a trailing slash.
+ *
+ * \note Same as #BLI_path_normalize but adds a trailing slash.
+ */
void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2);
+/**
+ * Make given name safe to be used in paths.
+ *
+ * \param allow_tokens: Permit the usage of '<' and '>' characters. This can be
+ * leveraged by higher layers to support "virtual filenames" which contain
+ * substitution markers delineated between the two characters.
+ *
+ * \return true if \a fname was changed, false otherwise.
+ *
+ * For now, simply replaces reserved chars (as listed in
+ * https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
+ * by underscores ('_').
+ *
+ * \note Space case ' ' is a bit of an edge case here - in theory it is allowed,
+ * but again can be an issue in some cases, so we simply replace it by an underscore too
+ * (good practice anyway).
+ * REMOVED based on popular demand (see T45900).
+ * Percent '%' char is a bit same case - not recommended to use it,
+ * but supported by all decent file-systems/operating-systems around.
+ *
+ * \note On Windows, it also ensures there is no '.' (dot char) at the end of the file,
+ * this can lead to issues.
+ *
+ * \note On Windows, it also checks for forbidden names
+ * (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
+ */
+bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens) ATTR_NONNULL(1);
bool BLI_filename_make_safe(char *fname) ATTR_NONNULL(1);
+
+/**
+ * Make given path OS-safe.
+ *
+ * \return true if \a path was changed, false otherwise.
+ */
bool BLI_path_make_safe(char *path) ATTR_NONNULL(1);
-/* Go back one directory. */
+/**
+ * Go back one directory.
+ *
+ * Replaces path with the path of its parent directory, returning true if
+ * it was able to find a parent directory within the path.
+ */
bool BLI_path_parent_dir(char *path) ATTR_NONNULL();
-/* Go back until the directory is found. */
+/**
+ * Go back until the directory is found.
+ *
+ * Strips off nonexistent (or non-accessible) sub-directories from the end of `dir`,
+ * leaving the path of the lowest-level directory that does exist and we can read.
+ */
bool BLI_path_parent_dir_until_exists(char *path) ATTR_NONNULL();
+/**
+ * If path begins with "//", strips that and replaces it with `basepath` directory.
+ *
+ * \note Also converts drive-letter prefix to something more sensible
+ * if this is a non-drive-letter-based system.
+ *
+ * \param path: The path to convert.
+ * \param basepath: The directory to base relative paths with.
+ * \return true if the path was relative (started with "//").
+ */
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL();
+/**
+ * Replaces "#" character sequence in last slash-separated component of `path`
+ * with frame as decimal integer, with leading zeroes as necessary, to make digits digits.
+ */
bool BLI_path_frame(char *path, int frame, int digits) ATTR_NONNULL();
+/**
+ * Replaces "#" character sequence in last slash-separated component of `path`
+ * with sta and end as decimal integers, with leading zeroes as necessary, to make digits
+ * digits each, with a hyphen in-between.
+ */
bool BLI_path_frame_range(char *path, int sta, int end, int digits) ATTR_NONNULL();
+/**
+ * Get the frame from a filename formatted by blender's frame scheme
+ */
bool BLI_path_frame_get(char *path, int *r_frame, int *numdigits) ATTR_NONNULL();
-void BLI_path_frame_strip(char *path, char *ext) ATTR_NONNULL();
+/**
+ * Given a `path` with digits representing frame numbers, replace the digits with the '#'
+ * character and extract the extension.
+ * So: `/some/path_123.jpeg`
+ * Becomes: `/some/path_###` with `r_ext` set to `.jpeg`.
+ */
+void BLI_path_frame_strip(char *path, char *r_ext) ATTR_NONNULL();
+/**
+ * Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
+ */
bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL();
-bool BLI_path_abs_from_cwd(char *path, const size_t maxlen) ATTR_NONNULL();
+/**
+ * Checks for a relative path (ignoring Blender's "//") prefix
+ * (unlike `!BLI_path_is_rel(path)`).
+ * When false, #BLI_path_abs_from_cwd would expand the absolute path.
+ */
+bool BLI_path_is_abs_from_cwd(const char *path) ATTR_NONNULL();
+/**
+ * Checks for relative path, expanding them relative to the current working directory.
+ * \returns true if the expansion was performed.
+ *
+ * \note Should only be called with command line paths.
+ * This is _not_ something Blender's internal paths support, instead they use the "//" prefix.
+ * In most cases #BLI_path_abs should be used instead.
+ */
+bool BLI_path_abs_from_cwd(char *path, size_t maxlen) ATTR_NONNULL();
+/**
+ * Replaces `file` with a relative version (prefixed by "//") such that #BLI_path_abs, given
+ * the same `relfile`, will convert it back to its original value.
+ */
void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL();
+/**
+ * Does path begin with the special "//" prefix that Blender uses to indicate
+ * a path relative to the .blend file.
+ */
bool BLI_path_is_rel(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return true if the path is a UNC share.
+ */
bool BLI_path_is_unc(const char *path);
+/**
+ * Creates a display string from path to be used menus and the user interface.
+ * Like `bpy.path.display_name()`.
+ */
void BLI_path_to_display_name(char *display_name, int maxlen, const char *name) ATTR_NONNULL();
#if defined(WIN32)
@@ -119,10 +380,22 @@ void BLI_path_normalize_unc_16(wchar_t *path_16);
void BLI_path_normalize_unc(char *path_16, int maxlen);
#endif
+/**
+ * Appends a suffix to the string, fitting it before the extension
+ *
+ * string = Foo.png, suffix = 123, separator = _
+ * Foo.png -> Foo_123.png
+ *
+ * \param string: original (and final) string
+ * \param maxlen: Maximum length of string
+ * \param suffix: String to append to the original string
+ * \param sep: Optional separator character
+ * \return true if succeeded
+ */
bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep)
ATTR_NONNULL();
-/* path string comparisons: case-insensitive for Windows, case-sensitive otherwise */
+/* Path string comparisons: case-insensitive for Windows, case-sensitive otherwise. */
#if defined(WIN32)
# define BLI_path_cmp BLI_strcasecmp
# define BLI_path_ncmp BLI_strncasecmp
@@ -131,8 +404,8 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
# define BLI_path_ncmp strncmp
#endif
-/* these values need to be hardcoded in structs, dna does not recognize defines */
-/* also defined in DNA_space_types.h */
+/* These values need to be hard-coded in structs, dna does not recognize defines */
+/* also defined in `DNA_space_types.h`. */
#ifndef FILE_MAXDIR
# define FILE_MAXDIR 768
# define FILE_MAXFILE 256
@@ -155,7 +428,7 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
#define FILENAME_PARENT ".."
#define FILENAME_CURRENT "."
-/* Avoid calling strcmp on one or two chars! */
+/* Avoid calling `strcmp` on one or two chars! */
#define FILENAME_IS_PARENT(_n) (((_n)[0] == '.') && ((_n)[1] == '.') && ((_n)[2] == '\0'))
#define FILENAME_IS_CURRENT(_n) (((_n)[0] == '.') && ((_n)[1] == '\0'))
#define FILENAME_IS_CURRPAR(_n) \
diff --git a/source/blender/blenlib/BLI_polyfill_2d.h b/source/blender/blenlib/BLI_polyfill_2d.h
index ca63ea5af87..25a624ba005 100644
--- a/source/blender/blenlib/BLI_polyfill_2d.h
+++ b/source/blender/blenlib/BLI_polyfill_2d.h
@@ -26,16 +26,32 @@ extern "C" {
struct MemArena;
+/**
+ * A version of #BLI_polyfill_calc that uses a memory arena to avoid re-allocations.
+ */
void BLI_polyfill_calc_arena(const float (*coords)[2],
- const unsigned int coords_tot,
- const int coords_sign,
+ unsigned int coords_tot,
+ int coords_sign,
unsigned int (*r_tris)[3],
struct MemArena *arena);
+/**
+ * Triangulates the given (convex or concave) simple polygon to a list of triangle vertices.
+ *
+ * \param coords: 2D coordinates describing vertices of the polygon,
+ * in either clockwise or counterclockwise order.
+ * \param coords_tot: Total points in the array.
+ * \param coords_sign: Pass this when we know the sign in advance to avoid extra calculations.
+ *
+ * \param r_tris: This array is filled in with triangle indices in clockwise order.
+ * The length of the array must be `coords_tot - 2`.
+ * Indices are guaranteed to be assigned to unique triangles, with valid indices,
+ * even in the case of degenerate input (self intersecting polygons, zero area ears... etc).
+ */
void BLI_polyfill_calc(const float (*coords)[2],
- const unsigned int coords_tot,
- const int coords_sign,
+ unsigned int coords_tot,
+ int coords_sign,
unsigned int (*r_tris)[3]);
/* default size of polyfill arena */
diff --git a/source/blender/blenlib/BLI_polyfill_2d_beautify.h b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
index 2c5296269ae..3a94ef46aca 100644
--- a/source/blender/blenlib/BLI_polyfill_2d_beautify.h
+++ b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
@@ -27,19 +27,40 @@ extern "C" {
struct Heap;
struct MemArena;
+/**
+ * The intention is that this calculates the output of #BLI_polyfill_calc
+ * \note assumes the \a coords form a boundary,
+ * so any edges running along contiguous (wrapped) indices,
+ * are ignored since the edges won't share 2 faces.
+ */
void BLI_polyfill_beautify(const float (*coords)[2],
- const unsigned int coords_tot,
+ unsigned int coords_tot,
unsigned int (*tris)[3],
/* structs for reuse */
struct MemArena *arena,
struct Heap *eheap);
+/**
+ * Assuming we have 2 triangles sharing an edge (2 - 4),
+ * check if the edge running from (1 - 3) gives better results.
+ *
+ * \param lock_degenerate: Use to avoid rotating out of a degenerate state:
+ * - When true, an existing zero area face on either side of the (2 - 4
+ * split will return a positive value.
+ * - When false, the check must be non-biased towards either split direction.
+ * \param r_area: Return the area of the quad,
+ * This can be useful when comparing the return value with near zero epsilons.
+ * In this case the epsilon can be scaled by the area to avoid the return value
+ * of very large faces not having a reliable way to detect near-zero output.
+ *
+ * \return (negative number means the edge can be rotated, lager == better).
+ */
float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
const float v2[2],
const float v3[2],
const float v4[2],
- const bool lock_degenerate,
+ bool lock_degenerate,
float *r_area);
#define BLI_polyfill_beautify_quad_rotate_calc(v1, v2, v3, v4) \
BLI_polyfill_beautify_quad_rotate_calc_ex(v1, v2, v3, v4, false, NULL)
diff --git a/source/blender/blenlib/BLI_quadric.h b/source/blender/blenlib/BLI_quadric.h
index fdb7d1e67ac..03642023986 100644
--- a/source/blender/blenlib/BLI_quadric.h
+++ b/source/blender/blenlib/BLI_quadric.h
@@ -31,20 +31,23 @@ typedef struct Quadric {
double a2, ab, ac, ad, b2, bc, bd, c2, cd, d2;
} Quadric;
-/* conversion */
+/* Conversion. */
+
void BLI_quadric_from_plane(Quadric *q, const double v[4]);
void BLI_quadric_to_vector_v3(const Quadric *q, double v[3]);
void BLI_quadric_clear(Quadric *q);
-/* math */
+/* Math operations. */
+
void BLI_quadric_add_qu_qu(Quadric *a, const Quadric *b);
void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b);
-void BLI_quadric_mul(Quadric *a, const double scalar);
+void BLI_quadric_mul(Quadric *a, double scalar);
+
+/* Solve. */
-/* solve */
double BLI_quadric_evaluate(const Quadric *q, const double v[3]);
-bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon);
+bool BLI_quadric_optimize(const Quadric *q, double v[3], double epsilon);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h
index f8627952628..a1df6e1263e 100644
--- a/source/blender/blenlib/BLI_rand.h
+++ b/source/blender/blenlib/BLI_rand.h
@@ -31,7 +31,8 @@
extern "C" {
#endif
-/* RNG is an abstract random number generator type that avoids using globals.
+/**
+ * RNG is an abstract random number generator type that avoids using globals.
* Always use this instead of the global RNG unless you have a good reason,
* the global RNG is not thread safe and will not give repeatable results.
*/
@@ -42,19 +43,34 @@ struct RNG_THREAD_ARRAY;
typedef struct RNG_THREAD_ARRAY RNG_THREAD_ARRAY;
struct RNG *BLI_rng_new(unsigned int seed);
+/**
+ * A version of #BLI_rng_new that hashes the seed.
+ */
struct RNG *BLI_rng_new_srandom(unsigned int seed);
struct RNG *BLI_rng_copy(struct RNG *rng) ATTR_NONNULL(1);
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1);
void BLI_rng_seed(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1);
+/**
+ * Use a hash table to create better seed.
+ */
void BLI_rng_srandom(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1);
void BLI_rng_get_char_n(RNG *rng, char *bytes, size_t bytes_len) ATTR_NONNULL(1, 2);
int BLI_rng_get_int(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
unsigned int BLI_rng_get_uint(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * \return Random value (0..1), but never 1.0.
+ */
double BLI_rng_get_double(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * \return Random value (0..1), but never 1.0.
+ */
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void BLI_rng_get_float_unit_v2(struct RNG *rng, float v[2]) ATTR_NONNULL(1, 2);
void BLI_rng_get_float_unit_v3(struct RNG *rng, float v[3]) ATTR_NONNULL(1, 2);
+/**
+ * Generate a random point inside given tri.
+ */
void BLI_rng_get_tri_sample_float_v2(struct RNG *rng,
const float v1[2],
const float v2[2],
@@ -75,9 +91,16 @@ void BLI_rng_shuffle_bitmap(struct RNG *rng, unsigned int *bitmap, unsigned int
ATTR_NONNULL(1, 2);
/** Note that skipping is as slow as generating n numbers! */
+/**
+ * Simulate getting \a n random values.
+ *
+ * \note Useful when threaded code needs consistent values, independent of task division.
+ */
void BLI_rng_skip(struct RNG *rng, int n) ATTR_NONNULL(1);
-/* fill an array with random numbers */
+/**
+ * Fill an array with random numbers.
+ */
void BLI_array_frand(float *ar, int count, unsigned int seed);
/** Return a pseudo-random (hash) float from an integer value */
diff --git a/source/blender/blenlib/BLI_rand.hh b/source/blender/blenlib/BLI_rand.hh
index 0c0dd464d4d..667d6df8996 100644
--- a/source/blender/blenlib/BLI_rand.hh
+++ b/source/blender/blenlib/BLI_rand.hh
@@ -20,9 +20,8 @@
#pragma once
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
@@ -47,6 +46,9 @@ class RandomNumberGenerator {
x_ = (static_cast<uint64_t>(seed) << 16) | lowseed;
}
+ /**
+ * Set a randomized hash of the value as seed.
+ */
void seed_random(uint32_t seed);
uint32_t get_uint32()
@@ -117,6 +119,9 @@ class RandomNumberGenerator {
float2 get_unit_float2();
float3 get_unit_float3();
+ /**
+ * Generate a random point inside the given triangle.
+ */
float2 get_triangle_sample(float2 v1, float2 v2, float2 v3);
float3 get_triangle_sample_3d(float3 v1, float3 v2, float3 v3);
void get_bytes(MutableSpan<char> r_bytes);
diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h
index fb52436587f..b8906a97977 100644
--- a/source/blender/blenlib/BLI_rect.h
+++ b/source/blender/blenlib/BLI_rect.h
@@ -34,12 +34,28 @@ struct rcti;
extern "C" {
#endif
+/**
+ * Determine if a `rect` is empty.
+ * An empty `rect` is one with a zero (or negative) width or height.
+ *
+ * \return True if \a rect is empty.
+ */
bool BLI_rcti_is_empty(const struct rcti *rect);
bool BLI_rctf_is_empty(const struct rctf *rect);
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax);
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax);
+/**
+ * Check if X-min and Y-min are less than or equal to X-max and Y-max, respectively.
+ * If this returns false, #BLI_rctf_sanitize() can be called to address this.
+ *
+ * This is not a hard constraint or invariant for rectangles, in some cases it may be useful to
+ * have max < min. Usually this is what you'd want though.
+ */
bool BLI_rctf_is_valid(const struct rctf *rect);
bool BLI_rcti_is_valid(const struct rcti *rect);
+/**
+ * Ensure X-min and Y-min are less than or equal to X-max and Y-max, respectively.
+ */
void BLI_rctf_sanitize(struct rctf *rect);
void BLI_rcti_sanitize(struct rcti *rect);
void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size);
@@ -48,11 +64,21 @@ void BLI_rcti_init_minmax(struct rcti *rect);
void BLI_rctf_init_minmax(struct rctf *rect);
void BLI_rcti_do_minmax_v(struct rcti *rect, const int xy[2]);
void BLI_rctf_do_minmax_v(struct rctf *rect, const float xy[2]);
+void BLI_rcti_do_minmax_rcti(struct rcti *rect, const struct rcti *other);
+/**
+ * Given 2 rectangles, transform a point from one to another.
+ */
void BLI_rctf_transform_pt_v(const rctf *dst,
const rctf *src,
float xy_dst[2],
const float xy_src[2]);
+/**
+ * Calculate a 4x4 matrix representing the transformation between two rectangles.
+ *
+ * \note Multiplying a vector by this matrix does *not*
+ * give the same value as #BLI_rctf_transform_pt_v.
+ */
void BLI_rctf_transform_calc_m4_pivot_min_ex(
const rctf *dst, const rctf *src, float matrix[4][4], uint x, uint y);
void BLI_rctf_transform_calc_m4_pivot_min(const rctf *dst, const rctf *src, float matrix[4][4]);
@@ -62,29 +88,40 @@ void BLI_rcti_translate(struct rcti *rect, int x, int y);
void BLI_rcti_recenter(struct rcti *rect, int x, int y);
void BLI_rctf_recenter(struct rctf *rect, float x, float y);
void BLI_rcti_resize(struct rcti *rect, int x, int y);
+/**
+ * Change width & height around the central X location.
+ */
void BLI_rcti_resize_x(struct rcti *rect, int x);
+/**
+ * Change width & height around the central Y location.
+ */
void BLI_rcti_resize_y(struct rcti *rect, int y);
void BLI_rcti_pad(struct rcti *rect, int pad_x, int pad_y);
void BLI_rctf_pad(struct rctf *rect, float pad_x, float pad_y);
void BLI_rctf_resize(struct rctf *rect, float x, float y);
void BLI_rctf_resize_x(struct rctf *rect, float x);
void BLI_rctf_resize_y(struct rctf *rect, float y);
-void BLI_rcti_scale(rcti *rect, const float scale);
-void BLI_rctf_scale(rctf *rect, const float scale);
-void BLI_rctf_pad_y(struct rctf *rect,
- const float boundary_size,
- const float pad_min,
- const float pad_max);
+void BLI_rcti_scale(rcti *rect, float scale);
+void BLI_rctf_scale(rctf *rect, float scale);
+void BLI_rctf_pad_y(struct rctf *rect, float boundary_size, float pad_min, float pad_max);
void BLI_rctf_interp(struct rctf *rect,
const struct rctf *rect_a,
const struct rctf *rect_b,
- const float fac);
+ float fac);
// void BLI_rcti_interp(struct rctf *rect, struct rctf *rect_a, struct rctf *rect_b, float fac);
bool BLI_rctf_clamp_pt_v(const struct rctf *rect, float xy[2]);
bool BLI_rcti_clamp_pt_v(const struct rcti *rect, int xy[2]);
+/**
+ * Clamp \a rect within \a rect_bounds, setting \a r_xy to the offset.
+ *
+ * Keeps the top left corner within the bounds, which for user interface
+ * elements is typically where the most important information is.
+ *
+ * \return true if a change is made.
+ */
bool BLI_rctf_clamp(struct rctf *rect, const struct rctf *rect_bounds, float r_xy[2]);
bool BLI_rcti_clamp(struct rcti *rect, const struct rcti *rect_bounds, int r_xy[2]);
-bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, const float limit);
+bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, float limit);
bool BLI_rcti_compare(const struct rcti *rect_a, const struct rcti *rect_b);
bool BLI_rctf_isect(const struct rctf *src1, const struct rctf *src2, struct rctf *dest);
bool BLI_rcti_isect(const struct rcti *src1, const struct rcti *src2, struct rcti *dest);
@@ -92,32 +129,44 @@ bool BLI_rctf_isect_rect_x(const struct rctf *src1, const struct rctf *src2, flo
bool BLI_rctf_isect_rect_y(const struct rctf *src1, const struct rctf *src2, float range_y[2]);
bool BLI_rcti_isect_rect_x(const struct rcti *src1, const struct rcti *src2, int range_x[2]);
bool BLI_rcti_isect_rect_y(const struct rcti *src1, const struct rcti *src2, int range_y[2]);
-bool BLI_rcti_isect_x(const rcti *rect, const int x);
-bool BLI_rcti_isect_y(const rcti *rect, const int y);
-bool BLI_rcti_isect_pt(const struct rcti *rect, const int x, const int y);
+bool BLI_rcti_isect_x(const rcti *rect, int x);
+bool BLI_rcti_isect_y(const rcti *rect, int y);
+bool BLI_rcti_isect_pt(const struct rcti *rect, int x, int y);
bool BLI_rcti_isect_pt_v(const struct rcti *rect, const int xy[2]);
-bool BLI_rctf_isect_x(const rctf *rect, const float x);
-bool BLI_rctf_isect_y(const rctf *rect, const float y);
-bool BLI_rctf_isect_pt(const struct rctf *rect, const float x, const float y);
+bool BLI_rctf_isect_x(const rctf *rect, float x);
+bool BLI_rctf_isect_y(const rctf *rect, float y);
+bool BLI_rctf_isect_pt(const struct rctf *rect, float x, float y);
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2]);
-int BLI_rcti_length_x(const rcti *rect, const int x);
-int BLI_rcti_length_y(const rcti *rect, const int y);
-float BLI_rctf_length_x(const rctf *rect, const float x);
-float BLI_rctf_length_y(const rctf *rect, const float y);
+/**
+ * \returns shortest distance from \a rect to x (0 if inside)
+ */
+int BLI_rcti_length_x(const rcti *rect, int x);
+/**
+ * \returns shortest distance from \a rect to y (0 if inside)
+ */
+int BLI_rcti_length_y(const rcti *rect, int y);
+float BLI_rctf_length_x(const rctf *rect, float x);
+float BLI_rctf_length_y(const rctf *rect, float y);
bool BLI_rcti_isect_segment(const struct rcti *rect, const int s1[2], const int s2[2]);
bool BLI_rctf_isect_segment(const struct rctf *rect, const float s1[2], const float s2[2]);
-bool BLI_rcti_isect_circle(const struct rcti *rect, const float xy[2], const float radius);
-bool BLI_rctf_isect_circle(const struct rctf *rect, const float xy[2], const float radius);
+bool BLI_rcti_isect_circle(const struct rcti *rect, const float xy[2], float radius);
+bool BLI_rctf_isect_circle(const struct rctf *rect, const float xy[2], float radius);
bool BLI_rcti_inside_rcti(const rcti *rct_a, const rcti *rct_b);
+/**
+ * is \a rct_b inside \a rct_a
+ */
bool BLI_rctf_inside_rctf(const rctf *rct_a, const rctf *rct_b);
-void BLI_rcti_union(struct rcti *rct1, const struct rcti *rct2);
-void BLI_rctf_union(struct rctf *rct1, const struct rctf *rct2);
+void BLI_rcti_union(struct rcti *rct_a, const struct rcti *rct_b);
+void BLI_rctf_union(struct rctf *rct_a, const struct rctf *rct_b);
void BLI_rcti_rctf_copy(struct rcti *dst, const struct rctf *src);
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src);
void BLI_rcti_rctf_copy_floor(struct rcti *dst, const struct rctf *src);
void BLI_rcti_rctf_copy_round(struct rcti *dst, const struct rctf *src);
-void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle);
+/**
+ * Expand the rectangle to fit a rotated \a src.
+ */
+void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, float angle);
void print_rctf(const char *str, const struct rctf *rect);
void print_rcti(const char *str, const struct rcti *rect);
diff --git a/source/blender/blenlib/BLI_resource_scope.hh b/source/blender/blenlib/BLI_resource_scope.hh
index 761e1ef834c..f0d8e71478e 100644
--- a/source/blender/blenlib/BLI_resource_scope.hh
+++ b/source/blender/blenlib/BLI_resource_scope.hh
@@ -56,106 +56,115 @@ class ResourceScope : NonCopyable, NonMovable {
Vector<ResourceData> resources_;
public:
- ResourceScope() = default;
-
- ~ResourceScope()
- {
- /* Free in reversed order. */
- for (int64_t i = resources_.size(); i--;) {
- ResourceData &data = resources_[i];
- data.free(data.data);
- }
- }
+ ResourceScope();
+ ~ResourceScope();
- /**
- * Pass ownership of the resource to the ResourceScope. It will be destructed and freed when
- * the collector is destructed.
- */
- template<typename T> T *add(std::unique_ptr<T> resource)
- {
- T *ptr = resource.release();
- if (ptr == nullptr) {
- return nullptr;
- }
- this->add(ptr, [](void *data) {
- T *typed_data = reinterpret_cast<T *>(data);
- delete typed_data;
- });
- return ptr;
- }
+ template<typename T> T *add(std::unique_ptr<T> resource);
+ template<typename T> T *add(destruct_ptr<T> resource);
+ void add(void *userdata, void (*free)(void *));
- /**
- * Pass ownership of the resource to the ResourceScope. It will be destructed when the
- * collector is destructed.
- */
- template<typename T> T *add(destruct_ptr<T> resource)
- {
- T *ptr = resource.release();
- if (ptr == nullptr) {
- return nullptr;
- }
- /* There is no need to keep track of such types. */
- if (std::is_trivially_destructible_v<T>) {
- return ptr;
- }
-
- this->add(ptr, [](void *data) {
- T *typed_data = reinterpret_cast<T *>(data);
- typed_data->~T();
- });
- return ptr;
- }
+ template<typename T> T &add_value(T &&value);
+ template<typename Func> void add_destruct_call(Func func);
- /**
- * Pass ownership of some resource to the ResourceScope. The given free function will be
- * called when the collector is destructed.
- */
- void add(void *userdata, void (*free)(void *))
- {
- ResourceData data;
- data.data = userdata;
- data.free = free;
- resources_.append(data);
- }
+ template<typename T, typename... Args> T &construct(Args &&...args);
- /**
- * Construct an object with the same value in the ResourceScope and return a reference to the
- * new value.
- */
- template<typename T> T &add_value(T &&value)
- {
- return this->construct<T>(std::forward<T>(value));
- }
+ LinearAllocator<> &linear_allocator();
+};
- /**
- * The passed in function will be called when the scope is destructed.
- */
- template<typename Func> void add_destruct_call(Func func)
- {
- void *buffer = allocator_.allocate(sizeof(Func), alignof(Func));
- new (buffer) Func(std::move(func));
- this->add(buffer, [](void *data) { (*(Func *)data)(); });
- }
+/* -------------------------------------------------------------------- */
+/** \name #ResourceScope Inline Methods
+ * \{ */
- /**
- * Returns a reference to a linear allocator that is owned by the ResourcesCollector. Memory
- * allocated through this allocator will be freed when the collector is destructed.
- */
- LinearAllocator<> &linear_allocator()
- {
- return allocator_;
+/**
+ * Pass ownership of the resource to the ResourceScope. It will be destructed and freed when
+ * the collector is destructed.
+ */
+template<typename T> inline T *ResourceScope::add(std::unique_ptr<T> resource)
+{
+ T *ptr = resource.release();
+ if (ptr == nullptr) {
+ return nullptr;
}
-
- /**
- * Utility method to construct an instance of type T that will be owned by the ResourceScope.
- */
- template<typename T, typename... Args> T &construct(Args &&...args)
- {
- destruct_ptr<T> value_ptr = allocator_.construct<T>(std::forward<Args>(args)...);
- T &value_ref = *value_ptr;
- this->add(std::move(value_ptr));
- return value_ref;
+ this->add(ptr, [](void *data) {
+ T *typed_data = reinterpret_cast<T *>(data);
+ delete typed_data;
+ });
+ return ptr;
+}
+
+/**
+ * Pass ownership of the resource to the ResourceScope. It will be destructed when the
+ * collector is destructed.
+ */
+template<typename T> inline T *ResourceScope::add(destruct_ptr<T> resource)
+{
+ T *ptr = resource.release();
+ if (ptr == nullptr) {
+ return nullptr;
}
-};
+ /* There is no need to keep track of such types. */
+ if constexpr (std::is_trivially_destructible_v<T>) {
+ return ptr;
+ }
+
+ this->add(ptr, [](void *data) {
+ T *typed_data = reinterpret_cast<T *>(data);
+ typed_data->~T();
+ });
+ return ptr;
+}
+
+/**
+ * Pass ownership of some resource to the ResourceScope. The given free function will be
+ * called when the collector is destructed.
+ */
+inline void ResourceScope::add(void *userdata, void (*free)(void *))
+{
+ ResourceData data;
+ data.data = userdata;
+ data.free = free;
+ resources_.append(data);
+}
+
+/**
+ * Construct an object with the same value in the ResourceScope and return a reference to the
+ * new value.
+ */
+template<typename T> inline T &ResourceScope::add_value(T &&value)
+{
+ return this->construct<T>(std::forward<T>(value));
+}
+
+/**
+ * The passed in function will be called when the scope is destructed.
+ */
+template<typename Func> inline void ResourceScope::add_destruct_call(Func func)
+{
+ void *buffer = allocator_.allocate(sizeof(Func), alignof(Func));
+ new (buffer) Func(std::move(func));
+ this->add(buffer, [](void *data) { (*(Func *)data)(); });
+}
+
+/**
+ * Utility method to construct an instance of type T that will be owned by the ResourceScope.
+ */
+template<typename T, typename... Args> inline T &ResourceScope::construct(Args &&...args)
+{
+ destruct_ptr<T> value_ptr = allocator_.construct<T>(std::forward<Args>(args)...);
+ T &value_ref = *value_ptr;
+ this->add(std::move(value_ptr));
+ return value_ref;
+}
+
+/**
+ * Returns a reference to a linear allocator that is owned by the ResourcesCollector. Memory
+ * allocated through this allocator will be freed when the collector is destructed.
+ */
+inline LinearAllocator<> &ResourceScope::linear_allocator()
+{
+ return allocator_;
+}
+
+/** \} */
} // namespace blender
diff --git a/source/blender/blenlib/BLI_scanfill.h b/source/blender/blenlib/BLI_scanfill.h
index 8f281023177..eca3c00017c 100644
--- a/source/blender/blenlib/BLI_scanfill.h
+++ b/source/blender/blenlib/BLI_scanfill.h
@@ -91,6 +91,7 @@ typedef struct ScanFillFace {
} ScanFillFace;
/* scanfill.c */
+
struct ScanFillVert *BLI_scanfill_vert_add(ScanFillContext *sf_ctx, const float vec[3]);
struct ScanFillEdge *BLI_scanfill_edge_add(ScanFillContext *sf_ctx,
struct ScanFillVert *v1,
@@ -113,16 +114,20 @@ enum {
BLI_SCANFILL_CALC_LOOSE = (1 << 4),
};
void BLI_scanfill_begin(ScanFillContext *sf_ctx);
-unsigned int BLI_scanfill_calc(ScanFillContext *sf_ctx, const int flag);
-unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx,
- const int flag,
- const float nor_proj[3]);
+unsigned int BLI_scanfill_calc(ScanFillContext *sf_ctx, int flag);
+unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, int flag, const float nor_proj[3]);
void BLI_scanfill_end(ScanFillContext *sf_ctx);
void BLI_scanfill_begin_arena(ScanFillContext *sf_ctx, struct MemArena *arena);
void BLI_scanfill_end_arena(ScanFillContext *sf_ctx, struct MemArena *arena);
/* scanfill_utils.c */
+
+/**
+ * Call before scan-fill to remove self intersections.
+ *
+ * \return false if no changes were made.
+ */
bool BLI_scanfill_calc_self_isect(ScanFillContext *sf_ctx,
ListBase *fillvertbase,
ListBase *filledgebase);
diff --git a/source/blender/blenlib/BLI_serialize.hh b/source/blender/blenlib/BLI_serialize.hh
new file mode 100644
index 00000000000..05606794994
--- /dev/null
+++ b/source/blender/blenlib/BLI_serialize.hh
@@ -0,0 +1,329 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ *
+ * An abstraction layer for serialization formats.
+ *
+ * Allowing to read/write data to a serialization format like JSON.
+ *
+ *
+ *
+ * # Supported data types
+ *
+ * The abstraction layer has a limited set of data types it supports.
+ * There are specific classes that builds up the data structure that
+ * can be (de)serialized.
+ *
+ * - StringValue: for strings
+ * - IntValue: for integer values
+ * - DoubleValue: for double precision floating point numbers
+ * - BooleanValue: for boolean values
+ * - ArrayValue: An array of any supported value.
+ * - DictionaryValue: A key value pair where keys are std::string.
+ * - NullValue: for null values.
+ *
+ * # Basic usage
+ *
+ * ## Serializing
+ *
+ * - Construct a structure that needs to be serialized using the `*Value` classes.
+ * - Construct the formatter you want to use
+ * - Invoke the formatter.serialize method passing an output stream and the value.
+ *
+ * The next example would format an integer value (42) as JSON the result will
+ * be stored inside `out`.
+ *
+ * \code{.cc}
+ * JsonFormatter json;
+ * std::stringstream out;
+ * IntValue test_value(42);
+ * json.serialize(out, test_value);
+ * \endcode
+ *
+ * ## Deserializing
+ *
+ * \code{.cc}
+ * std::stringstream is("42");
+ * JsonFormatter json;
+ * std::unique_ptr<Value> value = json.deserialize(is);
+ * \endcode
+ *
+ * # Adding a new formatter
+ *
+ * To add a new formatter a new sub-class of `Formatter` must be created and the
+ * `serialize`/`deserialize` methods should be implemented.
+ *
+ */
+
+#include <ostream>
+
+#include "BLI_map.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+namespace blender::io::serialize {
+
+/**
+ * Enumeration containing all sub-classes of Value. It is used as for type checking.
+ *
+ * \see #Value::type()
+ */
+enum class eValueType {
+ String,
+ Int,
+ Array,
+ Null,
+ Boolean,
+ Double,
+ Dictionary,
+};
+
+class Value;
+class StringValue;
+class DictionaryValue;
+template<typename T, eValueType V> class PrimitiveValue;
+using IntValue = PrimitiveValue<int64_t, eValueType::Int>;
+using DoubleValue = PrimitiveValue<double, eValueType::Double>;
+using BooleanValue = PrimitiveValue<bool, eValueType::Boolean>;
+
+template<typename Container, eValueType V, typename ContainerItem = typename Container::value_type>
+class ContainerValue;
+/* ArrayValue stores its items as shared pointer as it shares data with a lookup table that can
+ * be created by calling `create_lookup`. */
+using ArrayValue = ContainerValue<Vector<std::shared_ptr<Value>>, eValueType::Array>;
+
+/**
+ * Class containing a (de)serializable value.
+ *
+ * To serialize from or to a specific format the Value will be used as an intermediate container
+ * holding the values. Value class is abstract. There are concrete classes to for different data
+ * types.
+ *
+ * - `StringValue`: contains a string.
+ * - `IntValue`: contains an integer.
+ * - `ArrayValue`: contains an array of elements. Elements don't need to be the same type.
+ * - `NullValue`: represents nothing (null pointer or optional).
+ * - `BooleanValue`: contains a boolean (true/false).
+ * - `DoubleValue`: contains a double precision floating point number.
+ * - `DictionaryValue`: represents an object (key value pairs where keys are strings and values can
+ * be of different types.
+ *
+ */
+class Value {
+ private:
+ eValueType type_;
+
+ protected:
+ Value() = delete;
+ explicit Value(eValueType type) : type_(type)
+ {
+ }
+
+ public:
+ virtual ~Value() = default;
+ eValueType type() const
+ {
+ return type_;
+ }
+
+ /**
+ * Casts to a StringValue.
+ * Will return nullptr when it is a different type.
+ */
+ const StringValue *as_string_value() const;
+
+ /**
+ * Casts to an IntValue.
+ * Will return nullptr when it is a different type.
+ */
+ const IntValue *as_int_value() const;
+
+ /**
+ * Casts to a DoubleValue.
+ * Will return nullptr when it is a different type.
+ */
+ const DoubleValue *as_double_value() const;
+
+ /**
+ * Casts to a BooleanValue.
+ * Will return nullptr when it is a different type.
+ */
+ const BooleanValue *as_boolean_value() const;
+
+ /**
+ * Casts to an ArrayValue.
+ * Will return nullptr when it is a different type.
+ */
+ const ArrayValue *as_array_value() const;
+
+ /**
+ * Casts to an DictionaryValue.
+ * Will return nullptr when it is a different type.
+ */
+ const DictionaryValue *as_dictionary_value() const;
+};
+
+/**
+ * For generating value types that represent types that are typically known processor data types.
+ */
+template<
+ /** Wrapped c/cpp data type that is used to store the value. */
+ typename T,
+ /** Value type of the class. */
+ eValueType V>
+class PrimitiveValue : public Value {
+ private:
+ T inner_value_{};
+
+ public:
+ explicit PrimitiveValue(const T value) : Value(V), inner_value_(value)
+ {
+ }
+
+ const T value() const
+ {
+ return inner_value_;
+ }
+};
+
+class NullValue : public Value {
+ public:
+ NullValue() : Value(eValueType::Null)
+ {
+ }
+};
+
+class StringValue : public Value {
+ private:
+ std::string string_;
+
+ public:
+ StringValue(const StringRef string) : Value(eValueType::String), string_(string)
+ {
+ }
+
+ const std::string &value() const
+ {
+ return string_;
+ }
+};
+
+/**
+ * Template for arrays and objects.
+ *
+ * Both ArrayValue and DictionaryValue store their values in an array.
+ */
+template<
+ /** The container type where the elements are stored in. */
+ typename Container,
+
+ /** ValueType representing the value (object/array). */
+ eValueType V,
+
+ /** Type of the data inside the container. */
+ typename ContainerItem>
+class ContainerValue : public Value {
+ public:
+ using Items = Container;
+ using Item = ContainerItem;
+
+ private:
+ Container inner_value_;
+
+ public:
+ ContainerValue() : Value(V)
+ {
+ }
+
+ const Container &elements() const
+ {
+ return inner_value_;
+ }
+
+ Container &elements()
+ {
+ return inner_value_;
+ }
+};
+
+/**
+ * Internal storage type for DictionaryValue.
+ *
+ * The elements are stored as an key value pair. The value is a shared pointer so it can be shared
+ * when using `DictionaryValue::create_lookup`.
+ */
+using DictionaryElementType = std::pair<std::string, std::shared_ptr<Value>>;
+
+/**
+ * Object is a key-value container where the key must be a std::string.
+ * Internally it is stored in a blender::Vector to ensure the order of keys.
+ */
+class DictionaryValue
+ : public ContainerValue<Vector<DictionaryElementType>, eValueType::Dictionary> {
+ public:
+ using LookupValue = std::shared_ptr<Value>;
+ using Lookup = Map<std::string, LookupValue>;
+
+ /**
+ * Return a lookup map to quickly lookup by key.
+ *
+ * The lookup is owned by the caller.
+ */
+ const Lookup create_lookup() const
+ {
+ Lookup result;
+ for (const Item &item : elements()) {
+ result.add_as(item.first, item.second);
+ }
+ return result;
+ }
+};
+
+/**
+ * Interface for any provided Formatter.
+ */
+class Formatter {
+ public:
+ virtual ~Formatter() = default;
+
+ /** Serialize the value to the given stream. */
+ virtual void serialize(std::ostream &os, const Value &value) = 0;
+
+ /** Deserialize the stream. */
+ virtual std::unique_ptr<Value> deserialize(std::istream &is) = 0;
+};
+
+/**
+ * Formatter to (de)serialize a JSON formatted stream.
+ */
+class JsonFormatter : public Formatter {
+ public:
+ /**
+ * The indentation level to use.
+ * Typically number of chars. Set to 0 to not use indentation.
+ */
+ int8_t indentation_len = 0;
+
+ public:
+ void serialize(std::ostream &os, const Value &value) override;
+ std::unique_ptr<Value> deserialize(std::istream &is) override;
+};
+
+} // namespace blender::io::serialize
diff --git a/source/blender/blenlib/BLI_session_uuid.h b/source/blender/blenlib/BLI_session_uuid.h
index 887044e9b54..29e291add5a 100644
--- a/source/blender/blenlib/BLI_session_uuid.h
+++ b/source/blender/blenlib/BLI_session_uuid.h
@@ -33,18 +33,19 @@ extern "C" {
#include "DNA_session_uuid_types.h"
-/* Generate new UUID which is unique throughout the Blender session. */
+/** Generate new UUID which is unique throughout the Blender session. */
SessionUUID BLI_session_uuid_generate(void);
-/* Check whether the UUID is properly generated. */
+/** Check whether the UUID is properly generated. */
bool BLI_session_uuid_is_generated(const SessionUUID *uuid);
-/* Check whether two UUIDs are identical. */
+/** Check whether two UUIDs are identical. */
bool BLI_session_uuid_is_equal(const SessionUUID *lhs, const SessionUUID *rhs);
uint64_t BLI_session_uuid_hash_uint64(const SessionUUID *uuid);
/* Utility functions to make it possible to create GHash/GSet with UUID as a key. */
+
uint BLI_session_uuid_ghash_hash(const void *uuid_v);
bool BLI_session_uuid_ghash_compare(const void *lhs_v, const void *rhs_v);
diff --git a/source/blender/blenlib/BLI_set.hh b/source/blender/blenlib/BLI_set.hh
index a8ccf957f6c..2e0dfea70e9 100644
--- a/source/blender/blenlib/BLI_set.hh
+++ b/source/blender/blenlib/BLI_set.hh
@@ -423,6 +423,8 @@ class Set {
int64_t total_slots_;
int64_t current_slot_;
+ friend Set;
+
public:
Iterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
: slots_(slots), total_slots_(total_slots), current_slot_(current_slot)
@@ -467,6 +469,12 @@ class Set {
{
return !(a != b);
}
+
+ protected:
+ const Slot &current_slot() const
+ {
+ return slots_[current_slot_];
+ }
};
Iterator begin() const
@@ -485,6 +493,20 @@ class Set {
}
/**
+ * Remove the key that the iterator is currently pointing at. It is valid to call this method
+ * while iterating over the set. However, after this method has been called, the removed element
+ * must not be accessed anymore.
+ */
+ void remove(const Iterator &iterator)
+ {
+ /* The const cast is valid because this method itself is not const. */
+ Slot &slot = const_cast<Slot &>(iterator.current_slot());
+ BLI_assert(slot.is_occupied());
+ slot.remove();
+ removed_slots_++;
+ }
+
+ /**
* Print common statistics like size and collision count. This is useful for debugging purposes.
*/
void print_stats(StringRef name = "") const
diff --git a/source/blender/blenlib/BLI_smallhash.h b/source/blender/blenlib/BLI_smallhash.h
index f7aec716e9e..9c274d25fba 100644
--- a/source/blender/blenlib/BLI_smallhash.h
+++ b/source/blender/blenlib/BLI_smallhash.h
@@ -34,8 +34,10 @@ typedef struct {
void *val;
} SmallHashEntry;
-/* How much stack space to use before dynamically allocating memory.
- * set to match one of the values in 'hashsizes' to avoid too many mallocs. */
+/**
+ * How much stack space to use before dynamically allocating memory.
+ * set to match one of the values in 'hashsizes' to avoid too many mallocs.
+ */
#define SMSTACKSIZE 131
typedef struct SmallHash {
unsigned int nbuckets;
@@ -51,10 +53,20 @@ typedef struct {
unsigned int i;
} SmallHashIter;
-void BLI_smallhash_init_ex(SmallHash *sh, const unsigned int nentries_reserve) ATTR_NONNULL(1);
+void BLI_smallhash_init_ex(SmallHash *sh, unsigned int nentries_reserve) ATTR_NONNULL(1);
void BLI_smallhash_init(SmallHash *sh) ATTR_NONNULL(1);
+/**
+ * \note does *not* free *sh itself! only the direct data!
+ */
void BLI_smallhash_release(SmallHash *sh) ATTR_NONNULL(1);
void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1);
+/**
+ * Inserts a new value to a key that may already be in #GHash.
+ *
+ * Avoids #BLI_smallhash_remove, #BLI_smallhash_insert calls (double lookups)
+ *
+ * \returns true if a new key has been added.
+ */
bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1);
bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1);
void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key)
@@ -74,6 +86,12 @@ void **BLI_smallhash_iternew_p(const SmallHash *sh, SmallHashIter *iter, uintptr
/* void BLI_smallhash_print(SmallHash *sh); */ /* UNUSED */
#ifdef DEBUG
+/**
+ * Measure how well the hash function performs
+ * (1.0 is perfect - no stepping needed).
+ *
+ * Smaller is better!
+ */
double BLI_smallhash_calc_quality(SmallHash *sh);
#endif
diff --git a/source/blender/blenlib/BLI_sort.h b/source/blender/blenlib/BLI_sort.h
index 969816086e2..31a052eb79d 100644
--- a/source/blender/blenlib/BLI_sort.h
+++ b/source/blender/blenlib/BLI_sort.h
@@ -30,7 +30,7 @@
# define BLI_qsort_r qsort_r
#endif
-/* Quick sort re-entrant */
+/** Quick sort (re-entrant). */
typedef int (*BLI_sort_cmp_t)(const void *a, const void *b, void *ctx);
void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh
index 29098fd79ce..b4497977815 100644
--- a/source/blender/blenlib/BLI_span.hh
+++ b/source/blender/blenlib/BLI_span.hh
@@ -62,7 +62,7 @@
* then the function has to specify whether the referenced array is expected to be initialized or
* not.
*
- * Since the arrays are only referenced, it is generally unsafe to store an Span. When you
+ * Since the arrays are only referenced, it is generally unsafe to store a Span. When you
* store one, you should know who owns the memory.
*
* Instances of Span and MutableSpan are small and should be passed by value.
@@ -109,7 +109,7 @@ template<typename T> class Span {
BLI_assert(size >= 0);
}
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<U, T>))>
constexpr Span(const U *start, int64_t size) : data_(static_cast<const T *>(start)), size_(size)
{
BLI_assert(size >= 0);
@@ -144,7 +144,7 @@ template<typename T> class Span {
* Support implicit conversions like the one below:
* Span<T *> -> Span<const T *>
*/
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<U, T>))>
constexpr Span(Span<U> span) : data_(static_cast<const T *>(span.data())), size_(span.size())
{
}
@@ -501,7 +501,7 @@ template<typename T> class MutableSpan {
* Support implicit conversions like the one below:
* MutableSpan<T *> -> MutableSpan<const T *>
*/
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<U, T>))>
constexpr MutableSpan(MutableSpan<U> span)
: data_(static_cast<T *>(span.data())), size_(span.size())
{
@@ -512,7 +512,7 @@ template<typename T> class MutableSpan {
return Span<T>(data_, size_);
}
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
constexpr operator Span<U>() const
{
return Span<U>(static_cast<const U *>(data_), size_);
@@ -599,6 +599,11 @@ template<typename T> class MutableSpan {
return MutableSpan(data_ + start, new_size);
}
+ constexpr MutableSpan slice(IndexRange range) const
+ {
+ return this->slice(range.start(), range.size());
+ }
+
/**
* Returns a new MutableSpan with n elements removed from the beginning. This invokes
* undefined behavior when n is negative.
@@ -729,29 +734,4 @@ template<typename T> class MutableSpan {
}
};
-/**
- * Utilities to check that arrays have the same size in debug builds.
- */
-template<typename T1, typename T2> constexpr void assert_same_size(const T1 &v1, const T2 &v2)
-{
- UNUSED_VARS_NDEBUG(v1, v2);
-#ifdef DEBUG
- int64_t size = v1.size();
- BLI_assert(size == v1.size());
- BLI_assert(size == v2.size());
-#endif
-}
-
-template<typename T1, typename T2, typename T3>
-constexpr void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3)
-{
- UNUSED_VARS_NDEBUG(v1, v2, v3);
-#ifdef DEBUG
- int64_t size = v1.size();
- BLI_assert(size == v1.size());
- BLI_assert(size == v2.size());
- BLI_assert(size == v3.size());
-#endif
-}
-
} /* namespace blender */
diff --git a/source/blender/blenlib/BLI_stack.h b/source/blender/blenlib/BLI_stack.h
index b00bc0a2e57..eb4e69a42d4 100644
--- a/source/blender/blenlib/BLI_stack.h
+++ b/source/blender/blenlib/BLI_stack.h
@@ -28,27 +28,76 @@ extern "C" {
typedef struct BLI_Stack BLI_Stack;
-BLI_Stack *BLI_stack_new_ex(const size_t elem_size,
+BLI_Stack *BLI_stack_new_ex(size_t elem_size,
const char *description,
- const size_t chunk_size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-BLI_Stack *BLI_stack_new(const size_t elem_size, const char *description) ATTR_WARN_UNUSED_RESULT
+ size_t chunk_size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Create a new homogeneous stack with elements of 'elem_size' bytes.
+ */
+BLI_Stack *BLI_stack_new(size_t elem_size, const char *description) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Free the stack's data and the stack itself
+ */
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL();
+/**
+ * Push a new item onto the stack.
+ *
+ * \return a pointer #BLI_Stack.elem_size
+ * bytes of uninitialized memory (caller must fill in).
+ */
void *BLI_stack_push_r(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Copies the source value onto the stack
+ *
+ * \note This copies #BLI_Stack.elem_size bytes from \a src,
+ * (the pointer itself is not stored).
+ *
+ * \param src: source data to be copied to the stack.
+ */
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL();
+/**
+ * A version of #BLI_stack_pop which fills in an array.
+ *
+ * \param dst: The destination array,
+ * must be at least (#BLI_Stack.elem_size * \a n) bytes long.
+ * \param n: The number of items to pop.
+ *
+ * \note The first item in the array will be last item added to the stack.
+ */
void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL();
+/**
+ * A version of #BLI_stack_pop_n which fills in an array (in the reverse order).
+ *
+ * \note The first item in the array will be first item added to the stack.
+ */
void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL();
+/**
+ * Retrieves and removes the top element from the stack.
+ * The value is copies to \a dst, which must be at least \a elem_size bytes.
+ *
+ * Does not reduce amount of allocated memory.
+ */
void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL();
void *BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Removes the top element from the stack.
+ */
void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL();
+/**
+ * Discards all elements without freeing.
+ */
void BLI_stack_clear(BLI_Stack *stack) ATTR_NONNULL();
size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true if the stack is empty, false otherwise
+ */
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index d3dc05edd9e..8177545911c 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -33,30 +33,95 @@
extern "C" {
#endif
-char *BLI_strdupn(const char *str, const size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+/**
+ * Duplicates the first \a len bytes of cstring \a str
+ * into a newly mallocN'd string and returns it. \a str
+ * is assumed to be at least len bytes long.
+ *
+ * \param str: The string to be duplicated
+ * \param len: The number of bytes to duplicate
+ * \retval Returns the duplicated string
+ */
+char *BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Duplicates the cstring \a str into a newly mallocN'd
+ * string and returns it.
+ *
+ * \param str: The string to be duplicated
+ * \retval Returns the duplicated string
+ */
char *BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC;
+/**
+ * Appends the two strings, and returns new mallocN'ed string
+ * \param str1: first string for copy
+ * \param str2: second string for append
+ * \retval Returns dst
+ */
char *BLI_strdupcat(const char *__restrict str1,
const char *__restrict str2) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL() ATTR_MALLOC;
-char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
- ATTR_NONNULL();
+/**
+ * Like strncpy but ensures dst is always
+ * '\0' terminated.
+ *
+ * \param dst: Destination for copy
+ * \param src: Source string to copy
+ * \param maxncpy: Maximum number of characters to copy (generally
+ * the size of dst)
+ * \retval Returns dst
+ */
+char *BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL();
+/**
+ * Like BLI_strncpy but ensures dst is always padded by given char,
+ * on both sides (unless src is empty).
+ *
+ * \param dst: Destination for copy
+ * \param src: Source string to copy
+ * \param pad: the char to use for padding
+ * \param maxncpy: Maximum number of characters to copy (generally the size of dst)
+ * \retval Returns dst
+ */
char *BLI_strncpy_ensure_pad(char *__restrict dst,
const char *__restrict src,
- const char pad,
+ char pad,
size_t maxncpy) ATTR_NONNULL();
+/**
+ * Like strncpy but ensures dst is always
+ * '\0' terminated.
+ *
+ * \note This is a duplicate of #BLI_strncpy that returns bytes copied.
+ * And is a drop in replacement for 'snprintf(str, sizeof(str), "%s", arg);'
+ *
+ * \param dst: Destination for copy
+ * \param src: Source string to copy
+ * \param maxncpy: Maximum number of characters to copy (generally
+ * the size of dst)
+ * \retval The number of bytes copied (The only difference from BLI_strncpy).
+ */
size_t BLI_strncpy_rlen(char *__restrict dst,
const char *__restrict src,
- const size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+ size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Return the range of the quoted string (excluding quotes) `str` after `prefix`.
+ *
+ * A version of #BLI_str_quoted_substrN that calculates the range
+ * instead of un-escaping and allocating the result.
+ *
+ * \param str: String potentially including `prefix`.
+ * \param prefix: Quoted string prefix.
+ * \param r_start: The start of the quoted string (after the first quote).
+ * \param r_end: The end of the quoted string (before the last quote).
+ * \return True when a quoted string range could be found after `prefix`.
+ */
bool BLI_str_quoted_substr_range(const char *__restrict str,
const char *__restrict prefix,
int *__restrict r_start,
@@ -67,108 +132,353 @@ char *BLI_str_quoted_substrN(const char *__restrict str,
const char *__restrict prefix) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL() ATTR_MALLOC;
#endif
+/**
+ * Fills \a result with text within "" that appear after some the contents of \a prefix.
+ * i.e. for string `pose["apples"]` with prefix `pose[`, it will return `apples`.
+ *
+ * \param str: is the entire string to chop.
+ * \param prefix: is the part of the string to step over.
+ * \param result: The buffer to fill.
+ * \param result_maxlen: The maximum size of the buffer (including nil terminator).
+ * \return True if the prefix was found and the entire quoted string was copied into result.
+ *
+ * Assume that the strings returned must be freed afterwards,
+ * and that the inputs will contain data we want.
+ */
bool BLI_str_quoted_substr(const char *__restrict str,
const char *__restrict prefix,
char *result,
size_t result_maxlen);
+/**
+ * string with all instances of substr_old replaced with substr_new,
+ * Returns a copy of the c-string \a str into a newly #MEM_mallocN'd
+ * and returns it.
+ *
+ * \note A rather wasteful string-replacement utility, though this shall do for now.
+ * Feel free to replace this with an even safe + nicer alternative
+ *
+ * \param str: The string to replace occurrences of substr_old in
+ * \param substr_old: The text in the string to find and replace
+ * \param substr_new: The text in the string to find and replace
+ * \retval Returns the duplicated string
+ */
char *BLI_str_replaceN(const char *__restrict str,
const char *__restrict substr_old,
const char *__restrict substr_new) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL() ATTR_MALLOC;
-void BLI_str_replace_char(char *string, char src, char dst) ATTR_NONNULL();
+/**
+ * In-place replace every \a src to \a dst in \a str.
+ *
+ * \param str: The string to operate on.
+ * \param src: The character to replace.
+ * \param dst: The character to replace with.
+ */
+void BLI_str_replace_char(char *str, char src, char dst) ATTR_NONNULL();
+/**
+ * Simple exact-match string replacement.
+ *
+ * \param replace_table: Array of source, destination pairs.
+ *
+ * \note Larger tables should use a hash table.
+ */
bool BLI_str_replace_table_exact(char *string,
- const size_t string_len,
+ size_t string_len,
const char *replace_table[][2],
int replace_table_len);
+/**
+ * Portable replacement for #snprintf
+ */
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
+/**
+ * A version of #BLI_snprintf that returns `strlen(dst)`
+ */
size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
+/**
+ * Portable replacement for `vsnprintf`.
+ */
size_t BLI_vsnprintf(char *__restrict buffer,
size_t maxncpy,
const char *__restrict format,
va_list arg) ATTR_PRINTF_FORMAT(3, 0);
+/**
+ * A version of #BLI_vsnprintf that returns `strlen(buffer)`
+ */
size_t BLI_vsnprintf_rlen(char *__restrict buffer,
size_t maxncpy,
const char *__restrict format,
va_list arg) ATTR_PRINTF_FORMAT(3, 0);
+/**
+ * Print formatted string into a newly #MEM_mallocN'd string
+ * and return it.
+ */
char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1, 2);
-size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
+/**
+ * This roughly matches C and Python's string escaping with double quotes - `"`.
+ *
+ * Since every character may need escaping,
+ * it's common to create a buffer twice as large as the input.
+ *
+ * \param dst: The destination string, at least \a dst_maxncpy, typically `(strlen(src) * 2) + 1`.
+ * \param src: The un-escaped source string.
+ * \param dst_maxncpy: The maximum number of bytes allowable to copy.
+ *
+ * \note This is used for creating animation paths in blend files.
+ */
+size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy)
ATTR_NONNULL();
+/**
+ * This roughly matches C and Python's string escaping with double quotes - `"`.
+ *
+ * The destination will never be larger than the source, it will either be the same
+ * or up to half when all characters are escaped.
+ *
+ * \param dst: The destination string, at least the size of `strlen(src) + 1`.
+ * \param src: The escaped source string.
+ * \param src_maxncpy: The maximum number of bytes allowable to copy from `src`.
+ * \param dst_maxncpy: The maximum number of bytes allowable to copy into `dst`.
+ * \param r_is_complete: Set to true when
+ */
size_t BLI_str_unescape_ex(char *__restrict dst,
const char *__restrict src,
- const size_t src_maxncpy,
+ size_t src_maxncpy,
/* Additional arguments. */
- const size_t dst_maxncpy,
+ size_t dst_maxncpy,
bool *r_is_complete) ATTR_NONNULL();
-size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy)
+/**
+ * See #BLI_str_unescape_ex doc-string.
+ *
+ * This function makes the assumption that `dst` always has
+ * at least `src_maxncpy` bytes available.
+ *
+ * Use #BLI_str_unescape_ex if `dst` has a smaller fixed size.
+ *
+ * \note This is used for parsing animation paths in blend files (runs often).
+ */
+size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, size_t src_maxncpy)
ATTR_NONNULL();
+/**
+ * Find the first un-escaped quote in the string (to find the end of the string).
+ *
+ * \param str: Typically this is the first character in a quoted string.
+ * Where the character before `*str` would be `"`.
+
+ * \return The pointer to the first un-escaped quote.
+ */
const char *BLI_str_escape_find_quote(const char *str) ATTR_NONNULL();
+/**
+ * Format ints with decimal grouping.
+ * 1000 -> 1,000
+ *
+ * \param dst: The resulting string
+ * \param num: Number to format
+ * \return The length of \a dst
+ */
size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL();
+/**
+ * Format uint64_t with decimal grouping.
+ * 1000 -> 1,000
+ *
+ * \param dst: The resulting string
+ * \param num: Number to format
+ * \return The length of \a dst
+ */
size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num) ATTR_NONNULL();
-void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base_10)
- ATTR_NONNULL();
+/**
+ * Format a size in bytes using binary units.
+ * 1000 -> 1 KB
+ * Number of decimal places grows with the used unit (e.g. 1.5 MB, 1.55 GB, 1.545 TB).
+ *
+ * \param dst: The resulting string.
+ * Dimension of 14 to support largest possible value for \a bytes (#LLONG_MAX).
+ * \param bytes: Number to format.
+ * \param base_10: Calculate using base 10 (GB, MB, ...) or 2 (GiB, MiB, ...).
+ */
+void BLI_str_format_byte_unit(char dst[15], long long int bytes, bool base_10) ATTR_NONNULL();
+/**
+ * Format a count to up to 6 places (plus '\0' terminator) string using long number
+ * names abbreviations. Used to produce a compact representation of large numbers.
+ *
+ * 1 -> 1
+ * 15 -> 15
+ * 155 -> 155
+ * 1555 -> 1.6K
+ * 15555 -> 15.6K
+ * 155555 -> 156K
+ * 1555555 -> 1.6M
+ * 15555555 -> 15.6M
+ * 155555555 -> 156M
+ * 1000000000 -> 1B
+ * ...
+ *
+ * Length of 7 is the maximum of the resulting string, for example, `-15.5K\0`.
+ */
void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format) ATTR_NONNULL();
+/**
+ * Compare two strings without regard to case.
+ *
+ * \retval True if the strings are equal, false otherwise.
+ */
int BLI_strcaseeq(const char *a, const char *b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Portable replacement for `strcasestr` (not available in MSVC)
+ */
char *BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Variation of #BLI_strcasestr with string length limited to \a len
+ */
char *BLI_strncasestr(const char *s, const char *find, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_strncasecmp(const char *s1, const char *s2, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Case insensitive, *natural* string comparison,
+ * keeping numbers in order.
+ */
int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-int BLI_strcmp_ignore_pad(const char *str1,
- const char *str2,
- const char pad) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Like strcmp, but will ignore any heading/trailing pad char for comparison.
+ * So e.g. if pad is '*', '*world' and 'world*' will compare equal.
+ */
+int BLI_strcmp_ignore_pad(const char *str1, const char *str2, char pad) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL();
-size_t BLI_strnlen(const char *str, const size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Determine the length of a fixed-size string.
+ */
+size_t BLI_strnlen(const char *str, size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void BLI_str_tolower_ascii(char *str, const size_t len) ATTR_NONNULL();
-void BLI_str_toupper_ascii(char *str, const size_t len) ATTR_NONNULL();
+void BLI_str_tolower_ascii(char *str, size_t len) ATTR_NONNULL();
+void BLI_str_toupper_ascii(char *str, size_t len) ATTR_NONNULL();
+/**
+ * Strip white-space from end of the string.
+ */
void BLI_str_rstrip(char *str) ATTR_NONNULL();
-int BLI_str_rstrip_float_zero(char *str, const char pad) ATTR_NONNULL();
+/**
+ * Strip trailing zeros from a float, eg:
+ * 0.0000 -> 0.0
+ * 2.0010 -> 2.001
+ *
+ * \param str:
+ * \param pad:
+ * \return The number of zeros stripped.
+ */
+int BLI_str_rstrip_float_zero(char *str, char pad) ATTR_NONNULL();
+/**
+ * Return index of a string in a string array.
+ *
+ * \param str: The string to find.
+ * \param str_array: Array of strings.
+ * \param str_array_len: The length of the array, or -1 for a NULL-terminated array.
+ * \return The index of str in str_array or -1.
+ */
int BLI_str_index_in_array_n(const char *__restrict str,
const char **__restrict str_array,
- const int str_array_len) ATTR_NONNULL();
+ int str_array_len) ATTR_NONNULL();
+/**
+ * Return index of a string in a string array.
+ *
+ * \param str: The string to find.
+ * \param str_array: Array of strings, (must be NULL-terminated).
+ * \return The index of str in str_array or -1.
+ */
int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
ATTR_NONNULL();
+/**
+ * Find if a string starts with another string.
+ *
+ * \param str: The string to search within.
+ * \param start: The string we look for at the start.
+ * \return If str starts with start.
+ */
bool BLI_str_startswith(const char *__restrict str, const char *__restrict start) ATTR_NONNULL();
+/**
+ * Find if a string ends with another string.
+ *
+ * \param str: The string to search within.
+ * \param end: The string we look for at the end.
+ * \return If str ends with end.
+ */
bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL();
bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t length)
ATTR_NONNULL();
+/**
+ * Find the first char matching one of the chars in \a delim, from left.
+ *
+ * \param str: The string to search within.
+ * \param delim: The set of delimiters to search for, as unicode values.
+ * \param sep: Return value, set to the first delimiter found (or NULL if none found).
+ * \param suf: Return value, set to next char after the first delimiter found
+ * (or NULL if none found).
+ * \return The length of the prefix (i.e. *sep - str).
+ */
size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf)
ATTR_NONNULL();
+/**
+ * Find the first char matching one of the chars in \a delim, from right.
+ *
+ * \param str: The string to search within.
+ * \param delim: The set of delimiters to search for, as unicode values.
+ * \param sep: Return value, set to the first delimiter found (or NULL if none found).
+ * \param suf: Return value, set to next char after the first delimiter found
+ * (or NULL if none found).
+ * \return The length of the prefix (i.e. *sep - str).
+ */
size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf)
ATTR_NONNULL();
+/**
+ * Find the first char matching one of the chars in \a delim, either from left or right.
+ *
+ * \param str: The string to search within.
+ * \param end: If non-NULL, the right delimiter of the string.
+ * \param delim: The set of delimiters to search for, as unicode values.
+ * \param sep: Return value, set to the first delimiter found (or NULL if none found).
+ * \param suf: Return value, set to next char after the first delimiter found
+ * (or NULL if none found).
+ * \param from_right: If %true, search from the right of \a str, else, search from its left.
+ * \return The length of the prefix (i.e. *sep - str).
+ */
size_t BLI_str_partition_ex(const char *str,
const char *end,
const char delim[],
const char **sep,
const char **suf,
- const bool from_right) ATTR_NONNULL(1, 3, 4, 5);
+ bool from_right) ATTR_NONNULL(1, 3, 4, 5);
-int BLI_string_max_possible_word_count(const int str_len);
+int BLI_string_max_possible_word_count(int str_len);
bool BLI_string_has_word_prefix(const char *haystack, const char *needle, size_t needle_len);
bool BLI_string_all_words_matched(const char *name,
const char *str,
int (*words)[2],
- const int words_len);
+ int words_len);
+/**
+ * Find the ranges needed to split \a str into its individual words.
+ *
+ * \param str: The string to search for words.
+ * \param len: Size of the string to search.
+ * \param delim: Character to use as a delimiter.
+ * \param r_words: Info about the words found. Set to [index, len] pairs.
+ * \param words_max: Max number of words to find
+ * \return The number of words found in \a str
+ */
int BLI_string_find_split_words(const char *str,
- const size_t len,
- const char delim,
+ size_t len,
+ char delim,
int r_words[][2],
int words_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -177,6 +487,7 @@ int BLI_string_find_split_words(const char *str,
* Avoid repeating destination with `sizeof(..)`.
* \note `ARRAY_SIZE` allows pointers on some platforms.
* \{ */
+
#define STRNCPY(dst, src) BLI_strncpy(dst, src, ARRAY_SIZE(dst))
#define STRNCPY_RLEN(dst, src) BLI_strncpy_rlen(dst, src, ARRAY_SIZE(dst))
#define SNPRINTF(dst, format, ...) BLI_snprintf(dst, ARRAY_SIZE(dst), format, __VA_ARGS__)
@@ -186,6 +497,7 @@ int BLI_string_find_split_words(const char *str,
len += BLI_strncpy_rlen(dst + len, suffix, ARRAY_SIZE(dst) - len)
#define STR_CONCATF(dst, len, format, ...) \
len += BLI_snprintf_rlen(dst + len, ARRAY_SIZE(dst) - len, format, __VA_ARGS__)
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenlib/BLI_string_ref.hh b/source/blender/blenlib/BLI_string_ref.hh
index dcf66bbf5ad..e3dd8afd588 100644
--- a/source/blender/blenlib/BLI_string_ref.hh
+++ b/source/blender/blenlib/BLI_string_ref.hh
@@ -64,135 +64,35 @@ class StringRefBase {
const char *data_;
int64_t size_;
- constexpr StringRefBase(const char *data, const int64_t size) : data_(data), size_(size)
- {
- }
+ constexpr StringRefBase(const char *data, int64_t size);
public:
/* Similar to string_view::npos, but signed. */
static constexpr int64_t not_found = -1;
- /**
- * Return the (byte-)length of the referenced string, without any null-terminator.
- */
- constexpr int64_t size() const
- {
- return size_;
- }
-
- constexpr bool is_empty() const
- {
- return size_ == 0;
- }
-
- /**
- * Return a pointer to the start of the string.
- */
- constexpr const char *data() const
- {
- return data_;
- }
-
- constexpr operator Span<char>() const
- {
- return Span<char>(data_, size_);
- }
-
- /**
- * Implicitly convert to std::string. This is convenient in most cases, but you have to be a bit
- * careful not to convert to std::string accidentally.
- */
- operator std::string() const
- {
- return std::string(data_, static_cast<size_t>(size_));
- }
+ constexpr int64_t size() const;
+ constexpr bool is_empty() const;
+ constexpr const char *data() const;
+ constexpr operator Span<char>() const;
- constexpr operator std::string_view() const
- {
- return std::string_view(data_, static_cast<size_t>(size_));
- }
+ operator std::string() const;
+ constexpr operator std::string_view() const;
- constexpr const char *begin() const
- {
- return data_;
- }
+ constexpr const char *begin() const;
+ constexpr const char *end() const;
- constexpr const char *end() const
- {
- return data_ + size_;
- }
+ constexpr IndexRange index_range() const;
- constexpr IndexRange index_range() const
- {
- return IndexRange(size_);
- }
+ void unsafe_copy(char *dst) const;
+ void copy(char *dst, int64_t dst_size) const;
+ template<size_t N> void copy(char (&dst)[N]) const;
- /**
- * Copy the string into a buffer. The buffer has to be one byte larger than the size of the
- * string, because the copied string will be null-terminated. Only use this when you are
- * absolutely sure that the buffer is large enough.
- */
- void unsafe_copy(char *dst) const
- {
- if (size_ > 0) {
- memcpy(dst, data_, static_cast<size_t>(size_));
- }
- dst[size_] = '\0';
- }
-
- /**
- * Copy the string into a buffer. The copied string will be null-terminated. This invokes
- * undefined behavior when dst_size is too small. (Should we define the behavior?)
- */
- void copy(char *dst, const int64_t dst_size) const
- {
- if (size_ < dst_size) {
- this->unsafe_copy(dst);
- }
- else {
- BLI_assert(false);
- dst[0] = '\0';
- }
- }
-
- /**
- * Copy the string into a char array. The copied string will be null-terminated. This invokes
- * undefined behavior when dst is too small.
- */
- template<size_t N> void copy(char (&dst)[N]) const
- {
- this->copy(dst, N);
- }
-
- /**
- * Returns true when the string begins with the given prefix. Otherwise false.
- */
constexpr bool startswith(StringRef prefix) const;
-
- /**
- * Returns true when the string ends with the given suffix. Otherwise false.
- */
constexpr bool endswith(StringRef suffix) const;
+ constexpr StringRef substr(int64_t start, int64_t size) const;
- constexpr StringRef substr(int64_t start, const int64_t size) const;
-
- /**
- * Get the first char in the string. This invokes undefined behavior when the string is empty.
- */
- constexpr const char &front() const
- {
- BLI_assert(size_ >= 1);
- return data_[0];
- }
-
- /**
- * Get the last char in the string. This invokes undefined behavior when the string is empty.
- */
- constexpr const char &back() const
- {
- BLI_assert(size_ >= 1);
- return data_[size_ - 1];
- }
+ constexpr const char &front() const;
+ constexpr const char &back() const;
/**
* The behavior of those functions matches the standard library implementation of
@@ -211,15 +111,7 @@ class StringRefBase {
constexpr int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const;
constexpr int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const;
- /**
- * Return a new StringRef that does not contain leading and trailing whitespace.
- */
constexpr StringRef trim() const;
-
- /**
- * Return a new StringRef that removes all the leading and trailing characters
- * that occur in `characters_to_remove`.
- */
constexpr StringRef trim(StringRef characters_to_remove) const;
constexpr StringRef trim(char character_to_remove) const;
};
@@ -230,57 +122,13 @@ class StringRefBase {
class StringRefNull : public StringRefBase {
public:
- constexpr StringRefNull() : StringRefBase("", 0)
- {
- }
+ constexpr StringRefNull();
+ constexpr StringRefNull(const char *str, int64_t size);
+ StringRefNull(const char *str);
+ StringRefNull(const std::string &str);
- /**
- * Construct a StringRefNull from a null terminated c-string. The pointer must not point to
- * NULL.
- */
- StringRefNull(const char *str) : StringRefBase(str, static_cast<int64_t>(strlen(str)))
- {
- BLI_assert(str != nullptr);
- BLI_assert(data_[size_] == '\0');
- }
-
- /**
- * Construct a StringRefNull from a null terminated c-string. This invokes undefined behavior
- * when the given size is not the correct size of the string.
- */
- constexpr StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size)
- {
- BLI_assert(static_cast<int64_t>(strlen(str)) == size);
- }
-
- /**
- * Reference a std::string. Remember that when the std::string is destructed, the StringRefNull
- * will point to uninitialized memory.
- */
- StringRefNull(const std::string &str) : StringRefNull(str.c_str())
- {
- }
-
- /**
- * Get the char at the given index.
- */
- constexpr char operator[](const int64_t index) const
- {
- BLI_assert(index >= 0);
- /* Use '<=' instead of just '<', so that the null character can be accessed as well. */
- BLI_assert(index <= size_);
- return data_[index];
- }
-
- /**
- * Returns the beginning of a null-terminated char array.
- *
- * This is like ->data(), but can only be called on a StringRefNull.
- */
- constexpr const char *c_str() const
- {
- return data_;
- }
+ constexpr char operator[](int64_t index) const;
+ constexpr const char *c_str() const;
};
/**
@@ -288,161 +136,126 @@ class StringRefNull : public StringRefBase {
*/
class StringRef : public StringRefBase {
public:
- constexpr StringRef() : StringRefBase(nullptr, 0)
- {
- }
-
- /**
- * StringRefNull can be converted into StringRef, but not the other way around.
- */
- constexpr StringRef(StringRefNull other) : StringRefBase(other.data(), other.size())
- {
- }
-
- /**
- * Create a StringRef from a null-terminated c-string.
- */
- constexpr StringRef(const char *str)
- : StringRefBase(str, str ? static_cast<int64_t>(std::char_traits<char>::length(str)) : 0)
- {
- }
-
- constexpr StringRef(const char *str, const int64_t length) : StringRefBase(str, length)
- {
- }
-
- /**
- * Create a StringRef from a start and end pointer. This invokes undefined behavior when the
- * second point points to a smaller address than the first one.
- */
- constexpr StringRef(const char *begin, const char *one_after_end)
- : StringRefBase(begin, static_cast<int64_t>(one_after_end - begin))
- {
- BLI_assert(begin <= one_after_end);
- }
-
- /**
- * Reference a std::string. Remember that when the std::string is destructed, the StringRef
- * will point to uninitialized memory.
- */
- StringRef(const std::string &str) : StringRefBase(str.data(), static_cast<int64_t>(str.size()))
- {
- }
-
- constexpr StringRef(std::string_view view)
- : StringRefBase(view.data(), static_cast<int64_t>(view.size()))
- {
- }
-
- /**
- * Returns a new StringRef that does not contain the first n chars. This invokes undefined
- * behavior when n is negative.
- */
- constexpr StringRef drop_prefix(const int64_t n) const
- {
- BLI_assert(n >= 0);
- const int64_t clamped_n = std::min(n, size_);
- const int64_t new_size = size_ - clamped_n;
- return StringRef(data_ + clamped_n, new_size);
- }
+ constexpr StringRef();
+ constexpr StringRef(StringRefNull other);
+ constexpr StringRef(const char *str);
+ constexpr StringRef(const char *str, int64_t length);
+ constexpr StringRef(const char *begin, const char *one_after_end);
+ constexpr StringRef(std::string_view view);
+ StringRef(const std::string &str);
+
+ constexpr StringRef drop_prefix(int64_t n) const;
+ constexpr StringRef drop_known_prefix(StringRef prefix) const;
+ constexpr StringRef drop_suffix(int64_t n) const;
+
+ constexpr char operator[](int64_t index) const;
+};
- /**
- * Return a new StringRef with the given prefix being skipped. This invokes undefined behavior if
- * the string does not begin with the given prefix.
- */
- constexpr StringRef drop_known_prefix(StringRef prefix) const
- {
- BLI_assert(this->startswith(prefix));
- return this->drop_prefix(prefix.size());
- }
+/* -------------------------------------------------------------------- */
+/** \name #StringRefBase Inline Methods
+ * \{ */
- /**
- * Return a new StringRef that does not contain the last n chars. This invokes undefined behavior
- * when n is negative.
- */
- constexpr StringRef drop_suffix(const int64_t n) const
- {
- BLI_assert(n >= 0);
- const int64_t new_size = std::max<int64_t>(0, size_ - n);
- return StringRef(data_, new_size);
- }
+constexpr StringRefBase::StringRefBase(const char *data, const int64_t size)
+ : data_(data), size_(size)
+{
+}
- /**
- * Get the char at the given index.
- */
- constexpr char operator[](int64_t index) const
- {
- BLI_assert(index >= 0);
- BLI_assert(index < size_);
- return data_[index];
- }
-};
+/**
+ * Return the (byte-)length of the referenced string, without any null-terminator.
+ */
+constexpr int64_t StringRefBase::size() const
+{
+ return size_;
+}
-/* More inline functions
- ***************************************/
+constexpr bool StringRefBase::is_empty() const
+{
+ return size_ == 0;
+}
-inline std::ostream &operator<<(std::ostream &stream, StringRef ref)
+/**
+ * Return a pointer to the start of the string.
+ */
+constexpr const char *StringRefBase::data() const
{
- stream << std::string(ref);
- return stream;
+ return data_;
}
-inline std::ostream &operator<<(std::ostream &stream, StringRefNull ref)
+constexpr StringRefBase::operator Span<char>() const
{
- stream << std::string(ref.data(), (size_t)ref.size());
- return stream;
+ return Span<char>(data_, size_);
}
/**
- * Adding two #StringRefs will allocate an std::string.
- * This is not efficient, but convenient in most cases.
+ * Implicitly convert to std::string. This is convenient in most cases, but you have to be a bit
+ * careful not to convert to std::string accidentally.
*/
-inline std::string operator+(StringRef a, StringRef b)
+inline StringRefBase::operator std::string() const
{
- return std::string(a) + std::string(b);
+ return std::string(data_, static_cast<size_t>(size_));
}
-/* This does not compare StringRef and std::string_view, because of ambiguous overloads. This is
- * not a problem when std::string_view is only used at api boundaries. To compare a StringRef and a
- * std::string_view, one should convert the std::string_view to StringRef (which is very cheap).
- * Ideally, we only use StringRef in our code to avoid this problem altogether. */
-constexpr inline bool operator==(StringRef a, StringRef b)
+constexpr StringRefBase::operator std::string_view() const
{
- if (a.size() != b.size()) {
- return false;
- }
- return STREQLEN(a.data(), b.data(), (size_t)a.size());
+ return std::string_view(data_, static_cast<size_t>(size_));
}
-constexpr inline bool operator!=(StringRef a, StringRef b)
+constexpr const char *StringRefBase::begin() const
{
- return !(a == b);
+ return data_;
}
-constexpr inline bool operator<(StringRef a, StringRef b)
+constexpr const char *StringRefBase::end() const
{
- return std::string_view(a) < std::string_view(b);
+ return data_ + size_;
}
-constexpr inline bool operator>(StringRef a, StringRef b)
+constexpr IndexRange StringRefBase::index_range() const
{
- return std::string_view(a) > std::string_view(b);
+ return IndexRange(size_);
}
-constexpr inline bool operator<=(StringRef a, StringRef b)
+/**
+ * Copy the string into a buffer. The buffer has to be one byte larger than the size of the
+ * string, because the copied string will be null-terminated. Only use this when you are
+ * absolutely sure that the buffer is large enough.
+ */
+inline void StringRefBase::unsafe_copy(char *dst) const
{
- return std::string_view(a) <= std::string_view(b);
+ if (size_ > 0) {
+ memcpy(dst, data_, static_cast<size_t>(size_));
+ }
+ dst[size_] = '\0';
}
-constexpr inline bool operator>=(StringRef a, StringRef b)
+/**
+ * Copy the string into a buffer. The copied string will be null-terminated. This invokes
+ * undefined behavior when dst_size is too small. (Should we define the behavior?)
+ */
+inline void StringRefBase::copy(char *dst, const int64_t dst_size) const
{
- return std::string_view(a) >= std::string_view(b);
+ if (size_ < dst_size) {
+ this->unsafe_copy(dst);
+ }
+ else {
+ BLI_assert(false);
+ dst[0] = '\0';
+ }
+}
+
+/**
+ * Copy the string into a char array. The copied string will be null-terminated. This invokes
+ * undefined behavior when dst is too small.
+ */
+template<size_t N> inline void StringRefBase::copy(char (&dst)[N]) const
+{
+ this->copy(dst, N);
}
/**
* Return true when the string starts with the given prefix.
*/
-constexpr inline bool StringRefBase::startswith(StringRef prefix) const
+constexpr bool StringRefBase::startswith(StringRef prefix) const
{
if (size_ < prefix.size_) {
return false;
@@ -458,7 +271,7 @@ constexpr inline bool StringRefBase::startswith(StringRef prefix) const
/**
* Return true when the string ends with the given suffix.
*/
-constexpr inline bool StringRefBase::endswith(StringRef suffix) const
+constexpr bool StringRefBase::endswith(StringRef suffix) const
{
if (size_ < suffix.size_) {
return false;
@@ -476,8 +289,8 @@ constexpr inline bool StringRefBase::endswith(StringRef suffix) const
* Return a new #StringRef containing only a sub-string of the original string. This invokes
* undefined if the start or max_size is negative.
*/
-constexpr inline StringRef StringRefBase::substr(const int64_t start,
- const int64_t max_size = INT64_MAX) const
+constexpr StringRef StringRefBase::substr(const int64_t start,
+ const int64_t max_size = INT64_MAX) const
{
BLI_assert(max_size >= 0);
BLI_assert(start >= 0);
@@ -485,7 +298,25 @@ constexpr inline StringRef StringRefBase::substr(const int64_t start,
return StringRef(data_ + start, substr_size);
}
-constexpr inline int64_t index_or_npos_to_int64(size_t index)
+/**
+ * Get the first char in the string. This invokes undefined behavior when the string is empty.
+ */
+constexpr const char &StringRefBase::front() const
+{
+ BLI_assert(size_ >= 1);
+ return data_[0];
+}
+
+/**
+ * Get the last char in the string. This invokes undefined behavior when the string is empty.
+ */
+constexpr const char &StringRefBase::back() const
+{
+ BLI_assert(size_ >= 1);
+ return data_[size_ - 1];
+}
+
+constexpr int64_t index_or_npos_to_int64(size_t index)
{
/* The compiler will probably optimize this check away. */
if (index == std::string_view::npos) {
@@ -494,62 +325,74 @@ constexpr inline int64_t index_or_npos_to_int64(size_t index)
return static_cast<int64_t>(index);
}
-constexpr inline int64_t StringRefBase::find(char c, int64_t pos) const
+constexpr int64_t StringRefBase::find(char c, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(std::string_view(*this).find(c, static_cast<size_t>(pos)));
}
-constexpr inline int64_t StringRefBase::find(StringRef str, int64_t pos) const
+constexpr int64_t StringRefBase::find(StringRef str, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(std::string_view(*this).find(str, static_cast<size_t>(pos)));
}
-constexpr inline int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const
+constexpr int64_t StringRefBase::rfind(char c, int64_t pos) const
+{
+ BLI_assert(pos >= 0);
+ return index_or_npos_to_int64(std::string_view(*this).rfind(c, static_cast<size_t>(pos)));
+}
+
+constexpr int64_t StringRefBase::rfind(StringRef str, int64_t pos) const
+{
+ BLI_assert(pos >= 0);
+ return index_or_npos_to_int64(std::string_view(*this).rfind(str, static_cast<size_t>(pos)));
+}
+
+constexpr int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_first_of(chars, static_cast<size_t>(pos)));
}
-constexpr inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const
+constexpr int64_t StringRefBase::find_first_of(char c, int64_t pos) const
{
return this->find_first_of(StringRef(&c, 1), pos);
}
-constexpr inline int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const
+constexpr int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_last_of(chars, static_cast<size_t>(pos)));
}
-constexpr inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const
+constexpr int64_t StringRefBase::find_last_of(char c, int64_t pos) const
{
return this->find_last_of(StringRef(&c, 1), pos);
}
-constexpr inline int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const
+constexpr int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_first_not_of(chars, static_cast<size_t>(pos)));
}
-constexpr inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const
+constexpr int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const
{
return this->find_first_not_of(StringRef(&c, 1), pos);
}
-constexpr inline int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const
+constexpr int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_last_not_of(chars, static_cast<size_t>(pos)));
}
-constexpr inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const
+constexpr int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const
{
return this->find_last_not_of(StringRef(&c, 1), pos);
}
@@ -559,6 +402,9 @@ constexpr StringRef StringRefBase::trim() const
return this->trim(" \t\r\n");
}
+/**
+ * Return a new StringRef that does not contain leading and trailing white-space.
+ */
constexpr StringRef StringRefBase::trim(const char character_to_remove) const
{
return this->trim(StringRef(&character_to_remove, 1));
@@ -584,4 +430,230 @@ constexpr StringRef StringRefBase::trim(StringRef characters_to_remove) const
return this->substr(find_front, substr_len);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #StringRefNull Inline Methods
+ * \{ */
+
+constexpr StringRefNull::StringRefNull() : StringRefBase("", 0)
+{
+}
+
+/**
+ * Construct a StringRefNull from a null terminated c-string. This invokes undefined behavior
+ * when the given size is not the correct size of the string.
+ */
+constexpr StringRefNull::StringRefNull(const char *str, const int64_t size)
+ : StringRefBase(str, size)
+{
+ BLI_assert(static_cast<int64_t>(strlen(str)) == size);
+}
+
+/**
+ * Construct a StringRefNull from a null terminated c-string. The pointer must not point to
+ * NULL.
+ */
+inline StringRefNull::StringRefNull(const char *str)
+ : StringRefBase(str, static_cast<int64_t>(strlen(str)))
+{
+ BLI_assert(str != nullptr);
+ BLI_assert(data_[size_] == '\0');
+}
+
+/**
+ * Reference a std::string. Remember that when the std::string is destructed, the StringRefNull
+ * will point to uninitialized memory.
+ */
+inline StringRefNull::StringRefNull(const std::string &str) : StringRefNull(str.c_str())
+{
+}
+
+/**
+ * Get the char at the given index.
+ */
+constexpr char StringRefNull::operator[](const int64_t index) const
+{
+ BLI_assert(index >= 0);
+ /* Use '<=' instead of just '<', so that the null character can be accessed as well. */
+ BLI_assert(index <= size_);
+ return data_[index];
+}
+
+/**
+ * Returns the beginning of a null-terminated char array.
+ *
+ * This is like ->data(), but can only be called on a StringRefNull.
+ */
+constexpr const char *StringRefNull::c_str() const
+{
+ return data_;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #StringRef Inline Methods
+ * \{ */
+
+constexpr StringRef::StringRef() : StringRefBase(nullptr, 0)
+{
+}
+
+/**
+ * StringRefNull can be converted into StringRef, but not the other way around.
+ */
+constexpr StringRef::StringRef(StringRefNull other) : StringRefBase(other.data(), other.size())
+{
+}
+
+/**
+ * Create a StringRef from a null-terminated c-string.
+ */
+constexpr StringRef::StringRef(const char *str)
+ : StringRefBase(str, str ? static_cast<int64_t>(std::char_traits<char>::length(str)) : 0)
+{
+}
+
+constexpr StringRef::StringRef(const char *str, const int64_t length) : StringRefBase(str, length)
+{
+}
+
+/**
+ * Returns a new StringRef that does not contain the first n chars. This invokes undefined
+ * behavior when n is negative.
+ */
+constexpr StringRef StringRef::drop_prefix(const int64_t n) const
+{
+ BLI_assert(n >= 0);
+ const int64_t clamped_n = std::min(n, size_);
+ const int64_t new_size = size_ - clamped_n;
+ return StringRef(data_ + clamped_n, new_size);
+}
+
+/**
+ * Return a new StringRef with the given prefix being skipped. This invokes undefined behavior if
+ * the string does not begin with the given prefix.
+ */
+constexpr StringRef StringRef::drop_known_prefix(StringRef prefix) const
+{
+ BLI_assert(this->startswith(prefix));
+ return this->drop_prefix(prefix.size());
+}
+
+/**
+ * Return a new StringRef that does not contain the last n chars. This invokes undefined behavior
+ * when n is negative.
+ */
+constexpr StringRef StringRef::drop_suffix(const int64_t n) const
+{
+ BLI_assert(n >= 0);
+ const int64_t new_size = std::max<int64_t>(0, size_ - n);
+ return StringRef(data_, new_size);
+}
+
+/**
+ * Get the char at the given index.
+ */
+constexpr char StringRef::operator[](int64_t index) const
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ return data_[index];
+}
+
+/**
+ * Create a StringRef from a start and end pointer. This invokes undefined behavior when the
+ * second point points to a smaller address than the first one.
+ */
+constexpr StringRef::StringRef(const char *begin, const char *one_after_end)
+ : StringRefBase(begin, static_cast<int64_t>(one_after_end - begin))
+{
+ BLI_assert(begin <= one_after_end);
+}
+
+/**
+ * Reference a std::string. Remember that when the std::string is destructed, the StringRef
+ * will point to uninitialized memory.
+ */
+inline StringRef::StringRef(const std::string &str)
+ : StringRefBase(str.data(), static_cast<int64_t>(str.size()))
+{
+}
+
+constexpr StringRef::StringRef(std::string_view view)
+ : StringRefBase(view.data(), static_cast<int64_t>(view.size()))
+{
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Overloads
+ * \{ */
+
+inline std::ostream &operator<<(std::ostream &stream, StringRef ref)
+{
+ stream << std::string(ref);
+ return stream;
+}
+
+inline std::ostream &operator<<(std::ostream &stream, StringRefNull ref)
+{
+ stream << std::string(ref.data(), (size_t)ref.size());
+ return stream;
+}
+
+/**
+ * Adding two #StringRefs will allocate an std::string.
+ * This is not efficient, but convenient in most cases.
+ */
+inline std::string operator+(StringRef a, StringRef b)
+{
+ return std::string(a) + std::string(b);
+}
+
+/* This does not compare StringRef and std::string_view, because of ambiguous overloads. This is
+ * not a problem when std::string_view is only used at api boundaries. To compare a StringRef and a
+ * std::string_view, one should convert the std::string_view to StringRef (which is very cheap).
+ * Ideally, we only use StringRef in our code to avoid this problem altogether. */
+constexpr bool operator==(StringRef a, StringRef b)
+{
+ if (a.size() != b.size()) {
+ return false;
+ }
+ if (a.data() == b.data()) {
+ /* This also avoids passing null to the call below, which would results in an ASAN warning. */
+ return true;
+ }
+ return STREQLEN(a.data(), b.data(), (size_t)a.size());
+}
+
+constexpr bool operator!=(StringRef a, StringRef b)
+{
+ return !(a == b);
+}
+
+constexpr bool operator<(StringRef a, StringRef b)
+{
+ return std::string_view(a) < std::string_view(b);
+}
+
+constexpr bool operator>(StringRef a, StringRef b)
+{
+ return std::string_view(a) > std::string_view(b);
+}
+
+constexpr bool operator<=(StringRef a, StringRef b)
+{
+ return std::string_view(a) <= std::string_view(b);
+}
+
+constexpr bool operator>=(StringRef a, StringRef b)
+{
+ return std::string_view(a) >= std::string_view(b);
+}
+
+/** \} */
+
} // namespace blender
diff --git a/source/blender/blenlib/BLI_string_search.h b/source/blender/blenlib/BLI_string_search.h
index 8057e5b75cb..f0bf259d213 100644
--- a/source/blender/blenlib/BLI_string_search.h
+++ b/source/blender/blenlib/BLI_string_search.h
@@ -23,7 +23,19 @@ extern "C" {
typedef struct StringSearch StringSearch;
StringSearch *BLI_string_search_new(void);
-void BLI_string_search_add(StringSearch *search, const char *str, void *user_data);
+/**
+ * Add a new possible result to the search.
+ * The caller keeps ownership of all parameters.
+ *
+ * \param weight: Can be used to customize the order when multiple items have the same match score.
+ */
+void BLI_string_search_add(StringSearch *search, const char *str, void *user_data, int weight);
+
+/**
+ * Filter and sort all previously added search items.
+ * Returns an array containing the filtered user data.
+ * The caller has to free the returned array.
+ */
int BLI_string_search_query(StringSearch *search, const char *query, void ***r_data);
void BLI_string_search_free(StringSearch *search);
@@ -40,8 +52,24 @@ void BLI_string_search_free(StringSearch *search);
namespace blender::string_search {
+/**
+ * Computes the cost of transforming string a into b. The cost/distance is the minimal number of
+ * operations that need to be executed. Valid operations are deletion, insertion, substitution and
+ * transposition.
+ *
+ * This function is utf8 aware in the sense that it works at the level of individual code points
+ * (1-4 bytes long) instead of on individual bytes.
+ */
int damerau_levenshtein_distance(StringRef a, StringRef b);
+/**
+ * Returns -1 when this is no reasonably good match.
+ * Otherwise returns the number of errors in the match.
+ */
int get_fuzzy_match_errors(StringRef query, StringRef full);
+/**
+ * Splits a string into words and normalizes them (currently that just means converting to lower
+ * case). The returned strings are allocated in the given allocator.
+ */
void extract_normalized_words(StringRef str,
LinearAllocator<> &allocator,
Vector<StringRef, 64> &r_words);
diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h
index 3b7463affc0..108a2f5fc7d 100644
--- a/source/blender/blenlib/BLI_string_utf8.h
+++ b/source/blender/blenlib/BLI_string_utf8.h
@@ -32,58 +32,157 @@ char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t
size_t BLI_strncpy_utf8_rlen(char *__restrict dst,
const char *__restrict src,
size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+/**
+ * Find first UTF-8 invalid byte in given \a str, of \a length bytes.
+ *
+ * \return the offset of the first invalid byte.
+ */
ptrdiff_t BLI_str_utf8_invalid_byte(const char *str, size_t length) ATTR_NONNULL(1);
+/**
+ * Remove any invalid UTF-8 byte (taking into account multi-bytes sequence of course).
+ *
+ * \return number of stripped bytes.
+ */
int BLI_str_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL(1);
-/* warning, can return -1 on bad chars */
+/**
+ * \return The size (in bytes) of a single UTF-8 char.
+ * \warning Can return -1 on bad chars.
+ */
int BLI_str_utf8_size(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Use when we want to skip errors.
+ */
int BLI_str_utf8_size_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* copied from glib */
+/**
+ * \param p: a pointer to Unicode character encoded as UTF-8
+ *
+ * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
+ * If \a p does not point to a valid UTF-8 encoded character, results are
+ * undefined. If you are not sure that the bytes are complete
+ * valid Unicode characters, you should use g_utf8_get_char_validated()
+ * instead.
+ *
+ * Return value: the resulting character
+ */
unsigned int BLI_str_utf8_as_unicode(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * UTF8 decoding that steps over the index (unless an error is encountered).
+ *
+ * \param p: The text to step over.
+ * \param p_len: The length of `p`.
+ * \param index: Index of `p` to step over.
+ * \return the code-point `(p + *index)` if there is a decoding error.
+ *
+ * \note Falls back to `LATIN1` for text drawing.
+ */
unsigned int BLI_str_utf8_as_unicode_step(const char *__restrict p,
size_t p_len,
size_t *__restrict index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 3);
+/**
+ * UTF8 decoding that steps over the index (unless an error is encountered).
+ *
+ * \param p: The text to step over.
+ * \param p_len: The length of `p`.
+ * \param index: Index of `p` to step over.
+ * \return the code-point or #BLI_UTF8_ERR if there is a decoding error.
+ *
+ * \note The behavior for clipped text (where `p_len` limits decoding trailing bytes)
+ * must have the same behavior is encountering a nil byte,
+ * so functions that only use the first part of a string has matching behavior to functions
+ * that null terminate the text.
+ */
unsigned int BLI_str_utf8_as_unicode_step_or_error(
const char *__restrict p, size_t p_len, size_t *__restrict index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 3);
size_t BLI_str_utf8_from_unicode_len(unsigned int c) ATTR_WARN_UNUSED_RESULT;
-size_t BLI_str_utf8_from_unicode(unsigned int c, char *outbuf, const size_t outbuf_len)
- ATTR_NONNULL(2);
+/**
+ * BLI_str_utf8_from_unicode:
+ *
+ * \param c: a Unicode character code
+ * \param outbuf: output buffer, must have at least `outbuf_len` bytes of space.
+ * If the length required by `c` exceeds `outbuf_len`,
+ * the bytes available bytes will be zeroed and `outbuf_len` returned.
+ *
+ * Converts a single character to UTF-8.
+ *
+ * \return number of bytes written.
+ */
+size_t BLI_str_utf8_from_unicode(unsigned int c, char *outbuf, size_t outbuf_len) ATTR_NONNULL(2);
size_t BLI_str_utf8_as_utf32(char32_t *__restrict dst_w,
const char *__restrict src_c,
- const size_t maxncpy) ATTR_NONNULL(1, 2);
-size_t BLI_str_utf32_as_utf8(char *__restrict dst,
- const char32_t *__restrict src,
- const size_t maxncpy) ATTR_NONNULL(1, 2);
+ size_t maxncpy) ATTR_NONNULL(1, 2);
+size_t BLI_str_utf32_as_utf8(char *__restrict dst, const char32_t *__restrict src, size_t maxncpy)
+ ATTR_NONNULL(1, 2);
+/**
+ * \return The UTF-32 len in UTF-8.
+ */
size_t BLI_str_utf32_as_utf8_len(const char32_t *src) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * BLI_str_find_prev_char_utf8:
+ * \param p: pointer to some position within \a str
+ * \param str_start: pointer to the beginning of a UTF-8 encoded string
+ *
+ * Given a position \a p with a UTF-8 encoded string \a str, find the start
+ * of the previous UTF-8 character starting before. \a p Returns \a str_start if no
+ * UTF-8 characters are present in \a str_start before \a p.
+ *
+ * \a p does not have to be at the beginning of a UTF-8 character. No check
+ * is made to see if the character found is actually valid other than
+ * it starts with an appropriate byte.
+ *
+ * \return A pointer to the found character.
+ */
const char *BLI_str_find_prev_char_utf8(const char *p, const char *str_start)
ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1, 2);
+/**
+ * \param p: a pointer to a position within a UTF-8 encoded string
+ * \param str_end: a pointer to the byte following the end of the string.
+ *
+ * Finds the start of the next UTF-8 character in the string after \a p
+ *
+ * \a p does not have to be at the beginning of a UTF-8 character. No check
+ * is made to see if the character found is actually valid other than
+ * it starts with an appropriate byte.
+ *
+ * \return a pointer to the found character or a pointer to the null terminating character '\0'.
+ */
const char *BLI_str_find_next_char_utf8(const char *p, const char *str_end)
ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1, 2);
-/* wchar_t functions, copied from blenders own font.c originally */
+/**
+ * \return the `wchar_t` length in UTF-8.
+ */
size_t BLI_wstrlen_utf8(const wchar_t *src) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strlen_utf8_ex(const char *strc, size_t *r_len_bytes)
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strlen_utf8(const char *strc) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
-size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, size_t *r_len_bytes)
+size_t BLI_strnlen_utf8_ex(const char *strc, size_t maxlen, size_t *r_len_bytes)
ATTR_NONNULL(1, 3);
-size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen)
- ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \param strc: the string to measure the length.
+ * \param maxlen: the string length (in bytes)
+ * \return the unicode length (not in bytes!)
+ */
+size_t BLI_strnlen_utf8(const char *strc, size_t maxlen) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst,
const wchar_t *__restrict src,
- const size_t maxncpy) ATTR_NONNULL(1, 2);
+ size_t maxncpy) ATTR_NONNULL(1, 2);
size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst,
const char *__restrict src,
- const size_t maxncpy) ATTR_NONNULL(1, 2);
+ size_t maxncpy) ATTR_NONNULL(1, 2);
-/* count columns that character/string occupies, based on wcwidth.c */
+/**
+ * Count columns that character/string occupies (based on `wcwidth.co`).
+ */
int BLI_wcwidth(char32_t ucs) ATTR_WARN_UNUSED_RESULT;
int BLI_wcswidth(const char32_t *pwcs, size_t n) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* warning, can return -1 on bad chars */
+/**
+ * \warning can return -1 on bad chars.
+ */
int BLI_str_utf8_char_width(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
int BLI_str_utf8_char_width_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
@@ -100,8 +199,7 @@ size_t BLI_str_partition_ex_utf8(const char *str,
const unsigned int delim[],
const char **sep,
const char **suf,
- const bool from_right) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL(1, 3, 4, 5);
+ bool from_right) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 3, 4, 5);
int BLI_str_utf8_offset_to_index(const char *str, int offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
@@ -112,7 +210,8 @@ int BLI_str_utf8_offset_to_column(const char *str, int offset) ATTR_WARN_UNUSED_
int BLI_str_utf8_offset_from_column(const char *str, int column) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
-#define BLI_UTF8_MAX 6 /* mem */
+/** Size in bytes. */
+#define BLI_UTF8_MAX 6
#define BLI_UTF8_WIDTH_MAX 2 /* columns */
#define BLI_UTF8_ERR ((unsigned int)-1)
@@ -121,8 +220,10 @@ int BLI_str_utf8_offset_from_column(const char *str, int column) ATTR_WARN_UNUSE
* Avoid repeating destination with `sizeof(..)`.
* \note `ARRAY_SIZE` allows pointers on some platforms.
* \{ */
+
#define STRNCPY_UTF8(dst, src) BLI_strncpy_utf8(dst, src, ARRAY_SIZE(dst))
#define STRNCPY_UTF8_RLEN(dst, src) BLI_strncpy_utf8_rlen(dst, src, ARRAY_SIZE(dst))
+
/** \} */
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h
index 277bb6fac05..818bfe8182b 100644
--- a/source/blender/blenlib/BLI_string_utils.h
+++ b/source/blender/blenlib/BLI_string_utils.h
@@ -36,33 +36,71 @@ struct ListBase;
typedef bool (*UniquenameCheckCallback)(void *arg, const char *name);
-size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim);
+/**
+ * Looks for a numeric suffix preceded by `delim` character on the end of
+ * name, puts preceding part into *left and value of suffix into *nr.
+ * Returns the length of *left.
+ *
+ * Foo.001 -> "Foo", 1
+ * Returning the length of "Foo"
+ *
+ * \param left: Where to return copy of part preceding `delim`.
+ * \param nr: Where to return value of numeric suffix`.
+ * \param name: String to split`.
+ * \param delim: Delimiter character`.
+ * \return Length of \a left.
+ */
+size_t BLI_split_name_num(char *left, int *nr, const char *name, char delim);
bool BLI_string_is_decimal(const char *string) ATTR_NONNULL();
-void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len);
-void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len);
+/**
+ * Based on `BLI_split_dirfile()` / `os.path.splitext()`,
+ * `"a.b.c"` -> (`"a.b"`, `".c"`).
+ */
+void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, size_t str_len);
+/**
+ * `"a.b.c"` -> (`"a."`, `"b.c"`).
+ */
+void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, size_t str_len);
-/* Join strings, return newly allocated string. */
+/**
+ * Join strings, return newly allocated string.
+ */
char *BLI_string_join_array(char *result,
size_t result_len,
const char *strings[],
uint strings_len) ATTR_NONNULL();
+/**
+ * A version of #BLI_string_join that takes a separator which can be any character including '\0'.
+ */
char *BLI_string_join_array_by_sep_char(char *result,
size_t result_len,
char sep,
const char *strings[],
uint strings_len) ATTR_NONNULL();
+/**
+ * Join an array of strings into a newly allocated, null terminated string.
+ */
char *BLI_string_join_arrayN(const char *strings[], uint strings_len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * A version of #BLI_string_joinN that takes a separator which can be any character including '\0'.
+ */
char *BLI_string_join_array_by_sep_charN(char sep,
const char *strings[],
uint strings_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * A version of #BLI_string_join_array_by_sep_charN that takes a table array.
+ * The new location of each string is written into this array.
+ */
char *BLI_string_join_array_by_sep_char_with_tableN(char sep,
char *table[],
const char *strings[],
uint strings_len) ATTR_NONNULL();
-/* Take multiple arguments, pass as (array, length). */
+/**
+ * Take multiple arguments, pass as (array, length).
+ */
#define BLI_string_join(result, result_len, ...) \
BLI_string_join_array( \
result, result_len, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
@@ -75,23 +113,57 @@ char *BLI_string_join_array_by_sep_char_with_tableN(char sep,
BLI_string_join_array_by_sep_char_with_tableN( \
sep, table, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+/**
+ * Finds the best possible flipped (left/right) name.
+ * For renaming; check for unique names afterwards.
+ *
+ * \param r_name: flipped name,
+ * assumed to be a pointer to a string of at least \a name_len size.
+ * \param from_name: original name,
+ * assumed to be a pointer to a string of at least \a name_len size.
+ * \param strip_number: If set, remove number extensions.
+ * \return The number of bytes written into \a r_name.
+ */
size_t BLI_string_flip_side_name(char *r_name,
const char *from_name,
- const bool strip_number,
- const size_t name_len);
+ bool strip_number,
+ size_t name_len);
+/**
+ * Ensures name is unique (according to criteria specified by caller in unique_check callback),
+ * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
+ *
+ * \param unique_check: Return true if name is not unique
+ * \param arg: Additional arg to unique_check--meaning is up to caller
+ * \param defname: To initialize name if latter is empty
+ * \param delim: Delimits numeric suffix in name
+ * \param name: Name to be ensured unique
+ * \param name_len: Maximum length of name area
+ * \return true if there if the name was changed
+ */
bool BLI_uniquename_cb(UniquenameCheckCallback unique_check,
void *arg,
const char *defname,
char delim,
char *name,
size_t name_len);
+/**
+ * Ensures that the specified block has a unique name within the containing list,
+ * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
+ *
+ * \param list: List containing the block
+ * \param vlink: The block to check the name for
+ * \param defname: To initialize block name if latter is empty
+ * \param delim: Delimits numeric suffix in name
+ * \param name_offset: Offset of name within block structure
+ * \param name_len: Maximum length of name area
+ */
bool BLI_uniquename(struct ListBase *list,
void *vlink,
const char *defname,
char delim,
int name_offset,
- size_t len);
+ size_t name_len);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h
index 2740e3740f2..95327ff33b8 100644
--- a/source/blender/blenlib/BLI_sys_types.h
+++ b/source/blender/blenlib/BLI_sys_types.h
@@ -72,8 +72,8 @@ typedef uint64_t u_int64_t;
#include <stddef.h> /* size_t define */
#ifndef __cplusplus
+/* The <uchar.h> standard header is missing on some systems. */
# if defined(__APPLE__) || defined(__NetBSD__)
-/* The <uchar.h> standard header is missing on macOS. */
typedef unsigned int char32_t;
# else
# include <uchar.h>
diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h
index 0d5b2e6e2df..2e5e07d8407 100644
--- a/source/blender/blenlib/BLI_system.h
+++ b/source/blender/blenlib/BLI_system.h
@@ -30,7 +30,7 @@ int BLI_cpu_support_sse2(void);
int BLI_cpu_support_sse41(void);
void BLI_system_backtrace(FILE *fp);
-/* Get CPU brand, result is to be MEM_freeN()-ed. */
+/** Get CPU brand, result is to be MEM_freeN()-ed. */
char *BLI_cpu_brand_string(void);
/**
@@ -45,15 +45,19 @@ char *BLI_cpu_brand_string(void);
*/
void BLI_hostname_get(char *buffer, size_t bufsize);
-/* Get maximum addressable memory in megabytes. */
+/** Get maximum addressable memory in megabytes. */
size_t BLI_system_memory_max_in_megabytes(void);
+/** Get maximum addressable memory in megabytes (clamped to #INT_MAX). */
int BLI_system_memory_max_in_megabytes_int(void);
/* For `getpid`. */
#ifdef WIN32
# define BLI_SYSTEM_PID_H <process.h>
-/* void* since we really do not want to drag Windows.h in to get the proper typedef. */
+/**
+ * \note Use `void *` for `exception` since we really do not want to drag Windows.h
+ * in to get the proper `typedef`.
+ */
void BLI_windows_handle_exception(void *exception);
#else
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 418db14e2f3..e487f8acd98 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -35,20 +35,24 @@ extern "C" {
struct BLI_mempool;
-/* Task Scheduler
+/* -------------------------------------------------------------------- */
+/** \name Task Scheduler
*
- * Central scheduler that holds running threads ready to execute tasks. A single
- * queue holds the task from all pools.
+ * Central scheduler that holds running threads ready to execute tasks.
+ * A single queue holds the task from all pools.
*
- * Init/exit must be called before/after any task pools are created/freed, and
- * must be called from the main threads. All other scheduler and pool functions
- * are thread-safe. */
+ * Initialize/exit must be called before/after any task pools are created/freed, and must
+ * be called from the main threads. All other scheduler and pool functions are thread-safe.
+ * \{ */
void BLI_task_scheduler_init(void);
void BLI_task_scheduler_exit(void);
int BLI_task_scheduler_num_threads(void);
-/* Task Pool
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Task Pool
*
* Pool of tasks that will be executed by the central task scheduler. For each
* pool, we can wait for all tasks to be done, or cancel them before they are
@@ -60,36 +64,45 @@ int BLI_task_scheduler_num_threads(void);
* pool with smaller tasks. When other threads are busy they will continue
* working on their own tasks, if not they will join in, no new threads will
* be launched.
- */
+ * \{ */
-typedef enum TaskPriority {
+typedef enum eTaskPriority {
TASK_PRIORITY_LOW,
TASK_PRIORITY_HIGH,
-} TaskPriority;
+} eTaskPriority;
typedef struct TaskPool TaskPool;
typedef void (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata);
typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata);
-/* Regular task pool that immediately starts executing tasks as soon as they
- * are pushed, either on the current or another thread. */
-TaskPool *BLI_task_pool_create(void *userdata, TaskPriority priority);
+/**
+ * Regular task pool that immediately starts executing tasks as soon as they
+ * are pushed, either on the current or another thread.
+ */
+TaskPool *BLI_task_pool_create(void *userdata, eTaskPriority priority);
-/* Background: always run tasks in a background thread, never immediately
- * execute them. For running background jobs. */
-TaskPool *BLI_task_pool_create_background(void *userdata, TaskPriority priority);
+/**
+ * Background: always run tasks in a background thread, never immediately
+ * execute them. For running background jobs.
+ */
+TaskPool *BLI_task_pool_create_background(void *userdata, eTaskPriority priority);
-/* Background Serial: run tasks one after the other in the background,
- * without parallelization between the tasks. */
-TaskPool *BLI_task_pool_create_background_serial(void *userdata, TaskPriority priority);
+/**
+ * Background Serial: run tasks one after the other in the background,
+ * without parallelization between the tasks.
+ */
+TaskPool *BLI_task_pool_create_background_serial(void *userdata, eTaskPriority priority);
-/* Suspended: don't execute tasks until work_and_wait is called. This is slower
+/**
+ * Suspended: don't execute tasks until work_and_wait is called. This is slower
* as threads can't immediately start working. But it can be used if the data
- * structures the threads operate on are not fully initialized until all tasks
- * are created. */
-TaskPool *BLI_task_pool_create_suspended(void *userdata, TaskPriority priority);
+ * structures the threads operate on are not fully initialized until all tasks are created.
+ */
+TaskPool *BLI_task_pool_create_suspended(void *userdata, eTaskPriority priority);
-/* No threads: immediately executes tasks on the same thread. For debugging. */
+/**
+ * No threads: immediately executes tasks on the same thread. For debugging.
+ */
TaskPool *BLI_task_pool_create_no_threads(void *userdata);
void BLI_task_pool_free(TaskPool *pool);
@@ -100,34 +113,51 @@ void BLI_task_pool_push(TaskPool *pool,
bool free_taskdata,
TaskFreeFunction freedata);
-/* work and wait until all tasks are done */
+/**
+ * Work and wait until all tasks are done.
+ */
void BLI_task_pool_work_and_wait(TaskPool *pool);
-/* cancel all tasks, keep worker threads running */
+/**
+ * Cancel all tasks, keep worker threads running.
+ */
void BLI_task_pool_cancel(TaskPool *pool);
-/* for worker threads, test if current task pool canceled. this function may
+/**
+ * For worker threads, test if current task pool canceled. this function may
* only be called from worker threads and pool must be the task pool that the
- * thread is currently executing a task from. */
+ * thread is currently executing a task from.
+ */
bool BLI_task_pool_current_canceled(TaskPool *pool);
-/* optional userdata pointer to pass along to run function */
+/**
+ * Optional `userdata` pointer to pass along to run function.
+ */
void *BLI_task_pool_user_data(TaskPool *pool);
-/* optional mutex to use from run function */
+/**
+ * Optional mutex to use from run function.
+ */
ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool);
-/* Parallel for routines */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Parallel for Routines
+ * \{ */
-/* Per-thread specific data passed to the callback. */
+/**
+ * Per-thread specific data passed to the callback.
+ */
typedef struct TaskParallelTLS {
- /* Copy of user-specifier chunk, which is copied from original chunk to all
- * worker threads. This is similar to OpenMP's firstprivate.
+ /**
+ * Copy of user-specifier chunk, which is copied from original chunk to all worker threads.
+ * This is similar to OpenMP's `firstprivate`.
*/
void *userdata_chunk;
} TaskParallelTLS;
typedef void (*TaskParallelRangeFunc)(void *__restrict userdata,
- const int iter,
+ int iter,
const TaskParallelTLS *__restrict tls);
typedef void (*TaskParallelInitFunc)(const void *__restrict userdata, void *__restrict chunk);
@@ -180,13 +210,14 @@ typedef struct TaskParallelSettings {
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings);
-void BLI_task_parallel_range(const int start,
- const int stop,
+void BLI_task_parallel_range(int start,
+ int stop,
void *userdata,
TaskParallelRangeFunc func,
const TaskParallelSettings *settings);
-/* This data is shared between all tasks, its access needs thread lock or similar protection.
+/**
+ * This data is shared between all tasks, its access needs thread lock or similar protection.
*/
typedef struct TaskParallelIteratorStateShared {
/* Maximum amount of items to acquire at once. */
@@ -214,14 +245,39 @@ typedef void (*TaskParallelIteratorFunc)(void *__restrict userdata,
int index,
const TaskParallelTLS *__restrict tls);
+/**
+ * This function allows to parallelize for loops using a generic iterator.
+ *
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param iter_func: Callback function used to generate chunks of items.
+ * \param init_item: The initial item, if necessary (may be NULL if unused).
+ * \param init_index: The initial index.
+ * \param tot_items: The total amount of items to iterate over
+ * (if unknown, set it to a negative number).
+ * \param func: Callback function.
+ * \param settings: See public API doc of TaskParallelSettings for description of all settings.
+ *
+ * \note Static scheduling is only available when \a tot_items is >= 0.
+ */
void BLI_task_parallel_iterator(void *userdata,
TaskParallelIteratorIterFunc iter_func,
void *init_item,
- const int init_index,
- const int tot_items,
+ int init_index,
+ int tot_items,
TaskParallelIteratorFunc func,
const TaskParallelSettings *settings);
+/**
+ * This function allows to parallelize for loops over ListBase items.
+ *
+ * \param listbase: The double linked list to loop over.
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param func: Callback function.
+ * \param settings: See public API doc of ParallelRangeSettings for description of all settings.
+ *
+ * \note There is no static scheduling here,
+ * since it would need another full loop over items to count them.
+ */
void BLI_task_parallel_listbase(struct ListBase *listbase,
void *userdata,
TaskParallelIteratorFunc func,
@@ -232,12 +288,22 @@ typedef struct MempoolIterData MempoolIterData;
typedef void (*TaskParallelMempoolFunc)(void *userdata,
MempoolIterData *iter,
const TaskParallelTLS *__restrict tls);
+/**
+ * This function allows to parallelize for loops over Mempool items.
+ *
+ * \param mempool: The iterable BLI_mempool to loop over.
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param func: Callback function.
+ * \param settings: See public API doc of TaskParallelSettings for description of all settings.
+ *
+ * \note There is no static scheduling here.
+ */
void BLI_task_parallel_mempool(struct BLI_mempool *mempool,
void *userdata,
TaskParallelMempoolFunc func,
const TaskParallelSettings *settings);
-/* TODO(sergey): Think of a better place for this. */
+/** TODO(sergey): Think of a better place for this. */
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
{
memset(settings, 0, sizeof(*settings));
@@ -252,14 +318,21 @@ BLI_INLINE void BLI_parallel_mempool_settings_defaults(TaskParallelSettings *set
settings->use_threading = true;
}
-/* Don't use this, store any thread specific data in tls->userdata_chunk instead.
- * Only here for code to be removed. */
+/**
+ * Don't use this, store any thread specific data in `tls->userdata_chunk` instead.
+ * Only here for code to be removed.
+ */
int BLI_task_parallel_thread_id(const TaskParallelTLS *tls);
-/* Task Graph Scheduling */
-/* Task Graphs can be used to create a forest of directional trees and schedule work to any tree.
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Task Graph Scheduling
+ *
+ * Task Graphs can be used to create a forest of directional trees and schedule work to any tree.
* The nodes in the graph can be run in separate threads.
*
+ * \code{.unparsed}
* +---- [root] ----+
* | |
* v v
@@ -267,55 +340,61 @@ int BLI_task_parallel_thread_id(const TaskParallelTLS *tls);
* | |
* v v
* [node_3] [node_4]
+ * \endcode
*
- * TaskGraph *task_graph = BLI_task_graph_create();
- * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, NULL, NULL);
- * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
- * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
- * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
- * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * \code{.c}
+ * TaskGraph *task_graph = BLI_task_graph_create();
+ * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, NULL, NULL);
+ * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
*
- * BLI_task_graph_edge_create(root, node_1);
- * BLI_task_graph_edge_create(root, node_2);
- * BLI_task_graph_edge_create(node_2, node_3);
- * BLI_task_graph_edge_create(node_2, node_4);
+ * BLI_task_graph_edge_create(root, node_1);
+ * BLI_task_graph_edge_create(root, node_2);
+ * BLI_task_graph_edge_create(node_2, node_3);
+ * BLI_task_graph_edge_create(node_2, node_4);
+ * \endcode
*
* Any node can be triggered to start a chain of tasks. Normally you would trigger a root node but
* it is supported to start the chain of tasks anywhere in the forest or tree. When a node
* completes, the execution flow is forwarded via the created edges.
* When a child node has multiple parents the child node will be triggered once for each parent.
*
- * BLI_task_graph_node_push_work(root);
+ * `BLI_task_graph_node_push_work(root);`
*
* In this example After `root` is finished, `node_1` and `node_2` will be started.
* Only after `node_2` is finished `node_3` and `node_4` will be started.
*
* After scheduling work we need to wait until all the tasks have been finished.
*
- * BLI_task_graph_work_and_wait();
+ * `BLI_task_graph_work_and_wait();`
*
* When finished you can clean up all the resources by freeing the task_graph. Nodes are owned by
* the graph and are freed task_data will only be freed if a free_func was given.
*
- * BLI_task_graph_free(task_graph);
+ * `BLI_task_graph_free(task_graph);`
*
* Work can enter a tree on any node. Normally this would be the root_node.
* A `task_graph` can be reused, but the caller needs to make sure the task_data is reset.
*
- * ** Task-Data **
+ * Task-Data
+ * ---------
*
* Typically you want give a task data to work on.
* Task data can be shared with other nodes, but be careful not to free the data multiple times.
- * Task data is freed when calling `BLI_task_graph_free`.
- *
- * MyData *task_data = MEM_callocN(sizeof(MyData), __func__);
- * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, task_data, MEM_freeN);
- * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
- * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
- * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
- * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * Task data is freed when calling #BLI_task_graph_free.
*
- */
+ * \code{.c}
+ * MyData *task_data = MEM_callocN(sizeof(MyData), __func__);
+ * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, task_data, MEM_freeN);
+ * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * \endcode
+ * \{ */
+
struct TaskGraph;
struct TaskNode;
@@ -332,7 +411,10 @@ struct TaskNode *BLI_task_graph_node_create(struct TaskGraph *task_graph,
bool BLI_task_graph_node_push_work(struct TaskNode *task_node);
void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node);
-/* Task Isolation
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Task Isolation
*
* Task isolation helps avoid unexpected task scheduling decisions that can lead to bugs if wrong
* assumptions were made. Typically that happens when doing "nested threading", i.e. one thread
@@ -359,9 +441,12 @@ void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_
* multiple threads, another thread will typically run the task and avoid the deadlock. However, if
* this situation happens on all threads at the same time, all threads will deadlock. This happened
* in T88598.
- */
+ * \{ */
+
void BLI_task_isolate(void (*func)(void *userdata), void *userdata);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_task.hh b/source/blender/blenlib/BLI_task.hh
index e2446ad143e..84d5cd39bb4 100644
--- a/source/blender/blenlib/BLI_task.hh
+++ b/source/blender/blenlib/BLI_task.hh
@@ -28,10 +28,10 @@
# define NOMINMAX
# define TBB_MIN_MAX_CLEANUP
# endif
-# include "tbb/parallel_reduce.h"
# include <tbb/blocked_range.h>
# include <tbb/parallel_for.h>
# include <tbb/parallel_for_each.h>
+# include <tbb/parallel_reduce.h>
# include <tbb/task_arena.h>
# ifdef WIN32
/* We cannot keep this defined, since other parts of the code deal with this on their own, leading
@@ -67,14 +67,19 @@ void parallel_for(IndexRange range, int64_t grain_size, const Function &function
return;
}
#ifdef WITH_TBB
- tbb::parallel_for(tbb::blocked_range<int64_t>(range.first(), range.one_after_last(), grain_size),
- [&](const tbb::blocked_range<int64_t> &subrange) {
- function(IndexRange(subrange.begin(), subrange.size()));
- });
+ /* Invoking tbb for small workloads has a large overhead. */
+ if (range.size() >= grain_size) {
+ tbb::parallel_for(
+ tbb::blocked_range<int64_t>(range.first(), range.one_after_last(), grain_size),
+ [&](const tbb::blocked_range<int64_t> &subrange) {
+ function(IndexRange(subrange.begin(), subrange.size()));
+ });
+ return;
+ }
#else
UNUSED_VARS(grain_size);
- function(range);
#endif
+ function(range);
}
template<typename Value, typename Function, typename Reduction>
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index 4f71e3aa6e4..60ed5f0544a 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -31,19 +31,31 @@
extern "C" {
#endif
-/* for tables, button in UI, etc */
+/** For tables, button in UI, etc. */
#define BLENDER_MAX_THREADS 1024
struct ListBase;
/* Threading API */
-/* This is run once at startup. */
+/**
+ * This is run once at startup.
+ */
void BLI_threadapi_init(void);
void BLI_threadapi_exit(void);
+/**
+ * \param tot: When 0 only initializes malloc mutex in a safe way (see sequence.c)
+ * problem otherwise: scene render will kill of the mutex!
+ */
void BLI_threadpool_init(struct ListBase *threadbase, void *(*do_thread)(void *), int tot);
+/**
+ * Amount of available threads.
+ */
int BLI_available_threads(struct ListBase *threadbase);
+/**
+ * Returns thread number, for sample patterns or threadsafe tables.
+ */
int BLI_threadpool_available_thread_index(struct ListBase *threadbase);
void BLI_threadpool_insert(struct ListBase *threadbase, void *callerdata);
void BLI_threadpool_remove(struct ListBase *threadbase, void *callerdata);
@@ -54,7 +66,10 @@ int BLI_thread_is_main(void);
/* System Information */
-int BLI_system_thread_count(void); /* gets the number of threads the system can make use of */
+/**
+ * \return the number of threads the system can make use of.
+ */
+int BLI_system_thread_count(void);
void BLI_system_num_threads_override_set(int num);
int BLI_system_num_threads_override_get(void);
@@ -152,7 +167,7 @@ typedef pthread_cond_t ThreadCondition;
void BLI_condition_init(ThreadCondition *cond);
void BLI_condition_wait(ThreadCondition *cond, ThreadMutex *mutex);
-void BLI_condition_wait_global_mutex(ThreadCondition *cond, const int type);
+void BLI_condition_wait_global_mutex(ThreadCondition *cond, int type);
void BLI_condition_notify_one(ThreadCondition *cond);
void BLI_condition_notify_all(ThreadCondition *cond);
void BLI_condition_end(ThreadCondition *cond);
@@ -195,12 +210,6 @@ void BLI_thread_queue_nowait(ThreadQueue *queue);
# define BLI_thread_local_set(name, value) name = value
#endif /* defined(__APPLE__) */
-/* **** Special functions to help performance on crazy NUMA setups. **** */
-
-/* Make sure process/thread is using NUMA node with fast memory access. */
-void BLI_thread_put_process_on_fast_node(void);
-void BLI_thread_put_thread_on_fast_node(void);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_timecode.h b/source/blender/blenlib/BLI_timecode.h
index 12f4f93f700..1cd18dc86ab 100644
--- a/source/blender/blenlib/BLI_timecode.h
+++ b/source/blender/blenlib/BLI_timecode.h
@@ -20,7 +20,7 @@
#pragma once
/** \file
- * \ingroup BLI
+ * \ingroup bli
*/
#include "BLI_compiler_attrs.h"
@@ -29,21 +29,52 @@
extern "C" {
#endif
+/**
+ * Generate time-code/frame number string and store in \a str
+ *
+ * \param str: destination string
+ * \param maxncpy: maximum number of characters to copy `sizeof(str)`
+ * \param brevity_level: special setting for #View2D grid drawing,
+ * used to specify how detailed we need to be
+ * \param time_seconds: time total time in seconds
+ * \param fps: frames per second, typically from the #FPS macro
+ * \param timecode_style: enum from #eTimecodeStyles
+ * \return length of \a str
+ */
size_t BLI_timecode_string_from_time(char *str,
- const size_t maxncpy,
- const int brevity_level,
- const float time_seconds,
- const double scene_fps,
- const short timecode_style) ATTR_NONNULL();
+ size_t maxncpy,
+ int brevity_level,
+ float time_seconds,
+ double fps,
+ short timecode_style) ATTR_NONNULL();
-size_t BLI_timecode_string_from_time_simple(char *str,
- const size_t maxncpy,
- const double time_seconds) ATTR_NONNULL();
+/**
+ * Generate time string and store in \a str
+ *
+ * \param str: destination string
+ * \param maxncpy: maximum number of characters to copy `sizeof(str)`
+ * \param time_seconds: time total time in seconds
+ * \return length of \a str
+ */
+size_t BLI_timecode_string_from_time_simple(char *str, size_t maxncpy, double time_seconds)
+ ATTR_NONNULL();
+/**
+ * Generate time string and store in \a str
+ *
+ * \param str: destination string
+ * \param maxncpy: maximum number of characters to copy `sizeof(str)`
+ * \param brevity_level: special setting for #View2D grid drawing,
+ * used to specify how detailed we need to be
+ * \param time_seconds: time total time in seconds
+ * \return length of \a str
+ *
+ * \note in some cases this is used to print non-seconds values.
+ */
size_t BLI_timecode_string_from_time_seconds(char *str,
- const size_t maxncpy,
- const int brevity_level,
- const float time_seconds) ATTR_NONNULL();
+ size_t maxncpy,
+ int brevity_level,
+ float time_seconds) ATTR_NONNULL();
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_timer.h b/source/blender/blenlib/BLI_timer.h
index 19275ff5b9a..b1cc8d5514f 100644
--- a/source/blender/blenlib/BLI_timer.h
+++ b/source/blender/blenlib/BLI_timer.h
@@ -22,15 +22,18 @@
#include "BLI_sys_types.h"
/** \file
- * \ingroup BLI
+ * \ingroup bli
*/
#ifdef __cplusplus
extern "C" {
#endif
-/* ret < 0: the timer will be removed.
- * ret >= 0: the timer will be called again in ret seconds */
+/**
+ * \return A value of:
+ * - < 0: the timer will be removed.
+ * - >= 0: the timer will be called again in this number of seconds.
+ */
typedef double (*BLI_timer_func)(uintptr_t uuid, void *user_data);
typedef void (*BLI_timer_data_free)(uintptr_t uuid, void *user_data);
@@ -45,10 +48,10 @@ void BLI_timer_register(uintptr_t uuid,
bool BLI_timer_is_registered(uintptr_t uuid);
-/* Returns False when the timer does not exist (anymore). */
+/** Returns False when the timer does not exist (anymore). */
bool BLI_timer_unregister(uintptr_t uuid);
-/* Execute all registered functions that are due. */
+/** Execute all registered functions that are due. */
void BLI_timer_execute(void);
void BLI_timer_free(void);
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index dec8acd7549..c4b31810669 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -635,7 +635,10 @@ extern "C" {
/* defined
* in memory_utils.c for now. I do not know where we should put it actually... */
#ifndef __BLI_MEMORY_UTILS_H__
-extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
+/**
+ * Check if memory is zeroed, as with `memset(arr, 0, arr_size)`.
+ */
+extern bool BLI_memory_is_zero(const void *arr, size_t arr_size);
#endif
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member) \
@@ -648,11 +651,12 @@ extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
/** \name String Macros
* \{ */
-/* Macro to convert a value to string in the pre-processor:
+/* Macro to convert a value to string in the preprocessor:
* - `STRINGIFY_ARG`: gives the argument as a string
* - `STRINGIFY_APPEND`: appends any argument 'b' onto the string argument 'a',
- * used by `STRINGIFY` because some preprocessors warn about zero arguments
+ * used by `STRINGIFY` because some preprocessors warn about zero arguments.
* - `STRINGIFY`: gives the argument's value as a string. */
+
#define STRINGIFY_ARG(x) "" #x
#define STRINGIFY_APPEND(a, b) "" a #b
#define STRINGIFY(x) STRINGIFY_APPEND("", x)
@@ -836,6 +840,15 @@ extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
/** No-op for expressions we don't want to instantiate, but must remain valid. */
#define EXPR_NOP(expr) (void)(0 ? ((void)(expr), 1) : 0)
+/**
+ * Utility macro that wraps `std::enable_if` to make it a bit easier to use and less verbose for
+ * SFINAE in common cases.
+ *
+ * \note Often one has to invoke this macro with double parenthesis. That's because the condition
+ * often contains a comma and angle brackets are not recognized as parenthesis by the preprocessor.
+ */
+#define BLI_ENABLE_IF(condition) typename std::enable_if_t<(condition)> * = nullptr
+
/** \} */
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_uvproject.h b/source/blender/blenlib/BLI_uvproject.h
index 6028d95bda0..c1cc1cdbb51 100644
--- a/source/blender/blenlib/BLI_uvproject.h
+++ b/source/blender/blenlib/BLI_uvproject.h
@@ -26,16 +26,26 @@ extern "C" {
struct Object;
struct ProjCameraInfo;
-/* create uv info from the camera, needs to be freed */
+/**
+ * Create UV info from the camera, needs to be freed.
+ *
+ * \param rotmat: can be `obedit->obmat` when uv project is used.
+ * \param winx, winy: can be from `scene->r.xsch / ysch`.
+ */
struct ProjCameraInfo *BLI_uvproject_camera_info(struct Object *ob,
float rotmat[4][4],
float winx,
float winy);
-/* apply uv from uvinfo (camera) */
+/**
+ * Apply UV from uvinfo (camera).
+ */
void BLI_uvproject_from_camera(float target[2], float source[3], struct ProjCameraInfo *uci);
-/* apply uv from perspective matrix */
+/**
+ * Apply uv from perspective matrix.
+ * \param persmat: Can be `rv3d->persmat`.
+ */
void BLI_uvproject_from_view(float target[2],
float source[3],
float persmat[4][4],
@@ -43,10 +53,14 @@ void BLI_uvproject_from_view(float target[2],
float winx,
float winy);
-/* apply ortho uv's */
+/**
+ * Apply orthographic UV's.
+ */
void BLI_uvproject_from_view_ortho(float target[2], float source[3], const float rotmat[4][4]);
-/* so we can adjust scale with keeping the struct private */
+/**
+ * So we can adjust scale with keeping the struct private.
+ */
void BLI_uvproject_camera_info_scale(struct ProjCameraInfo *uci, float scale_x, float scale_y);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index d2b94a6d8ef..1b10a4c0897 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -163,7 +163,7 @@ class Vector {
/**
* Create a vector from a span. The values in the vector are copy constructed.
*/
- template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
Vector(Span<U> values, Allocator allocator = {}) : Vector(NoExceptConstructor(), allocator)
{
const int64_t size = values.size();
@@ -178,7 +178,7 @@ class Vector {
* This allows you to write code like:
* Vector<int> vec = {3, 4, 5};
*/
- template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
Vector(const std::initializer_list<U> &values) : Vector(Span<U>(values))
{
}
@@ -187,9 +187,7 @@ class Vector {
{
}
- template<typename U,
- size_t N,
- typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ template<typename U, size_t N, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
Vector(const std::array<U, N> &values) : Vector(Span(values))
{
}
@@ -197,7 +195,7 @@ class Vector {
template<typename InputIt,
/* This constructor should not be called with e.g. Vector(3, 10), because that is
* expected to produce the vector (10, 10, 10). */
- typename std::enable_if_t<!std::is_convertible_v<InputIt, int>> * = nullptr>
+ BLI_ENABLE_IF((!std::is_convertible_v<InputIt, int>))>
Vector(InputIt first, InputIt last, Allocator allocator = {})
: Vector(NoExceptConstructor(), allocator)
{
@@ -326,13 +324,13 @@ class Vector {
return MutableSpan<T>(begin_, this->size());
}
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
operator Span<U>() const
{
return Span<U>(begin_, this->size());
}
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
operator MutableSpan<U>()
{
return MutableSpan<U>(begin_, this->size());
@@ -637,7 +635,7 @@ class Vector {
* Insert values at the beginning of the vector. The has to move all the other elements, so it
* has a linear running time.
*/
- void prepend(const T &&value)
+ void prepend(const T &value)
{
this->insert(0, value);
}
diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh
index 567e4fd8128..0aac96f93bc 100644
--- a/source/blender/blenlib/BLI_vector_set.hh
+++ b/source/blender/blenlib/BLI_vector_set.hh
@@ -263,7 +263,7 @@ class VectorSet {
}
/**
- * Get an Span referencing the keys vector. The referenced memory buffer is only valid as
+ * Get a Span referencing the keys vector. The referenced memory buffer is only valid as
* long as the vector set is not changed.
*
* The keys must not be changed, because this would change their hash value.
@@ -465,6 +465,14 @@ class VectorSet {
}
/**
+ * Get an index range containing all valid indices for this array.
+ */
+ IndexRange index_range() const
+ {
+ return IndexRange(this->size());
+ }
+
+ /**
* Print common statistics like size and collision count. This is useful for debugging purposes.
*/
void print_stats(StringRef name = "") const
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index 1c02bce8411..231ce1bdd67 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -37,148 +37,98 @@
* see of the increased compile time and binary size is worth it.
*/
+#include "BLI_any.hh"
#include "BLI_array.hh"
#include "BLI_index_mask.hh"
#include "BLI_span.hh"
namespace blender {
-/* An immutable virtual array. */
-template<typename T> class VArray {
+/** Forward declarations for generic virtual arrays. */
+namespace fn {
+class GVArray;
+class GVMutableArray;
+}; // namespace fn
+
+/**
+ * Implements the specifics of how the elements of a virtual array are accessed. It contains a
+ * bunch of virtual methods that are wrapped by #VArray.
+ */
+template<typename T> class VArrayImpl {
protected:
+ /**
+ * Number of elements in the virtual array. All virtual arrays have a size, but in some cases it
+ * may make sense to set it to the max value.
+ */
int64_t size_;
public:
- VArray(const int64_t size) : size_(size)
+ VArrayImpl(const int64_t size) : size_(size)
{
BLI_assert(size_ >= 0);
}
- virtual ~VArray() = default;
-
- T get(const int64_t index) const
- {
- BLI_assert(index >= 0);
- BLI_assert(index < size_);
- return this->get_impl(index);
- }
+ virtual ~VArrayImpl() = default;
int64_t size() const
{
return size_;
}
- bool is_empty() const
- {
- return size_ == 0;
- }
-
- IndexRange index_range() const
- {
- return IndexRange(size_);
- }
-
- /* Returns true when the virtual array is stored as a span internally. */
- bool is_span() const
- {
- if (size_ == 0) {
- return true;
- }
- return this->is_span_impl();
- }
-
- /* Returns the internally used span of the virtual array. This invokes undefined behavior is the
- * virtual array is not stored as a span internally. */
- Span<T> get_internal_span() const
- {
- BLI_assert(this->is_span());
- if (size_ == 0) {
- return {};
- }
- return this->get_internal_span_impl();
- }
-
- /* Returns true when the virtual array returns the same value for every index. */
- bool is_single() const
- {
- if (size_ == 1) {
- return true;
- }
- return this->is_single_impl();
- }
-
- /* Returns the value that is returned for every index. This invokes undefined behavior if the
- * virtual array would not return the same value for every index. */
- T get_internal_single() const
- {
- BLI_assert(this->is_single());
- if (size_ == 1) {
- return this->get(0);
- }
- return this->get_internal_single_impl();
- }
-
- /* Get the element at a specific index. Note that this operator cannot be used to assign values
- * to an index, because the return value is not a reference. */
- T operator[](const int64_t index) const
- {
- return this->get(index);
- }
-
- /* Copy the entire virtual array into a span. */
- void materialize(MutableSpan<T> r_span) const
- {
- this->materialize(IndexMask(size_), r_span);
- }
-
- /* Copy some indices of the virtual array into a span. */
- void materialize(IndexMask mask, MutableSpan<T> r_span) const
- {
- BLI_assert(mask.min_array_size() <= size_);
- this->materialize_impl(mask, r_span);
- }
-
- void materialize_to_uninitialized(MutableSpan<T> r_span) const
- {
- this->materialize_to_uninitialized(IndexMask(size_), r_span);
- }
-
- void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const
- {
- BLI_assert(mask.min_array_size() <= size_);
- this->materialize_to_uninitialized_impl(mask, r_span);
- }
-
- protected:
- virtual T get_impl(const int64_t index) const = 0;
+ /**
+ * Get the element at #index. This does not return a reference, because the value may be computed
+ * on the fly.
+ */
+ virtual T get(int64_t index) const = 0;
- virtual bool is_span_impl() const
+ /**
+ * Return true when the virtual array is a plain array internally.
+ */
+ virtual bool is_span() const
{
return false;
}
- virtual Span<T> get_internal_span_impl() const
+ /**
+ * Return the span of the virtual array.
+ * This invokes undefined behavior when #is_span returned false.
+ */
+ virtual Span<T> get_internal_span() const
{
+ /* Provide a default implementation, so that subclasses don't have to provide it. This method
+ * should never be called because #is_span returns false by default. */
BLI_assert_unreachable();
return {};
}
- virtual bool is_single_impl() const
+ /**
+ * Return true when the virtual array has the same value at every index.
+ */
+ virtual bool is_single() const
{
return false;
}
- virtual T get_internal_single_impl() const
+ /**
+ * Return the value that is used at every index.
+ * This invokes undefined behavior when #is_single returned false.
+ */
+ virtual T get_internal_single() const
{
/* Provide a default implementation, so that subclasses don't have to provide it. This method
- * should never be called because `is_single_impl` returns false by default. */
+ * should never be called because #is_single returns false by default. */
BLI_assert_unreachable();
return T();
}
- virtual void materialize_impl(IndexMask mask, MutableSpan<T> r_span) const
+ /**
+ * Copy values from the virtual array into the provided span. The index of the value in the
+ * virtual is the same as the index in the span.
+ */
+ virtual void materialize(IndexMask mask, MutableSpan<T> r_span) const
{
T *dst = r_span.data();
+ /* Optimize for a few different common cases. */
if (this->is_span()) {
const T *src = this->get_internal_span().data();
mask.foreach_index([&](const int64_t i) { dst[i] = src[i]; });
@@ -192,9 +142,13 @@ template<typename T> class VArray {
}
}
- virtual void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<T> r_span) const
+ /**
+ * Same as #materialize but #r_span is expected to be uninitialized.
+ */
+ virtual void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const
{
T *dst = r_span.data();
+ /* Optimize for a few different common cases. */
if (this->is_span()) {
const T *src = this->get_internal_span().data();
mask.foreach_index([&](const int64_t i) { new (dst + i) T(src[i]); });
@@ -207,43 +161,57 @@ template<typename T> class VArray {
mask.foreach_index([&](const int64_t i) { new (dst + i) T(this->get(i)); });
}
}
-};
-/* Similar to VArray, but the elements are mutable. */
-template<typename T> class VMutableArray : public VArray<T> {
- public:
- VMutableArray(const int64_t size) : VArray<T>(size)
+ /**
+ * If this virtual wraps another #GVArray, this method should assign the wrapped array to the
+ * provided reference. This allows losslessly converting between generic and typed virtual
+ * arrays in all cases.
+ * Return true when the virtual array was assigned and false when nothing was done.
+ */
+ virtual bool try_assign_GVArray(fn::GVArray &UNUSED(varray)) const
{
+ return false;
}
- void set(const int64_t index, T value)
+ /**
+ * Return true when this virtual array may own any of the memory it references. This can be used
+ * for optimization purposes when converting or copying the virtual array.
+ */
+ virtual bool may_have_ownership() const
{
- BLI_assert(index >= 0);
- BLI_assert(index < this->size_);
- this->set_impl(index, std::move(value));
+ /* Use true by default to be on the safe side. Subclasses that know for sure that they don't
+ * own anything can overwrite this with false. */
+ return true;
}
- /* Copy the values from the source span to all elements in the virtual array. */
- void set_all(Span<T> src)
+ /**
+ * Return true when the other virtual array should be considered to be the same, e.g. because it
+ * shares the same underlying memory.
+ */
+ virtual bool is_same(const VArrayImpl<T> &UNUSED(other)) const
{
- BLI_assert(src.size() == this->size_);
- this->set_all_impl(src);
+ return false;
}
+};
- MutableSpan<T> get_internal_span()
- {
- BLI_assert(this->is_span());
- Span<T> span = static_cast<const VArray<T> *>(this)->get_internal_span();
- return MutableSpan<T>(const_cast<T *>(span.data()), span.size());
- }
+/** Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */
+template<typename T> class VMutableArrayImpl : public VArrayImpl<T> {
+ public:
+ using VArrayImpl<T>::VArrayImpl;
- protected:
- virtual void set_impl(const int64_t index, T value) = 0;
+ /**
+ * Assign the provided #value to the #index.
+ */
+ virtual void set(int64_t index, T value) = 0;
- virtual void set_all_impl(Span<T> src)
+ /**
+ * Copy all elements from the provided span into the virtual array.
+ */
+ virtual void set_all(Span<T> src)
{
if (this->is_span()) {
- const MutableSpan<T> span = this->get_internal_span();
+ const Span<T> const_span = this->get_internal_span();
+ const MutableSpan<T> span{(T *)const_span.data(), const_span.size()};
initialized_copy_n(src.data(), this->size_, span.data());
}
else {
@@ -253,138 +221,771 @@ template<typename T> class VMutableArray : public VArray<T> {
}
}
}
-};
-template<typename T> using VArrayPtr = std::unique_ptr<VArray<T>>;
-template<typename T> using VMutableArrayPtr = std::unique_ptr<VMutableArray<T>>;
+ /**
+ * Similar to #VArrayImpl::try_assign_GVArray but for mutable virtual arrays.
+ */
+ virtual bool try_assign_GVMutableArray(fn::GVMutableArray &UNUSED(varray)) const
+ {
+ return false;
+ }
+};
/**
- * A virtual array implementation for a span. Methods in this class are final so that it can be
- * devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is used).
+ * A virtual array implementation that references that wraps a span. This implementation is used by
+ * mutable and immutable spans to avoid code duplication.
*/
-template<typename T> class VArray_For_Span : public VArray<T> {
+template<typename T> class VArrayImpl_For_Span : public VMutableArrayImpl<T> {
protected:
- const T *data_ = nullptr;
+ T *data_ = nullptr;
public:
- VArray_For_Span(const Span<T> data) : VArray<T>(data.size()), data_(data.data())
+ VArrayImpl_For_Span(const MutableSpan<T> data)
+ : VMutableArrayImpl<T>(data.size()), data_(data.data())
{
}
protected:
- VArray_For_Span(const int64_t size) : VArray<T>(size)
+ VArrayImpl_For_Span(const int64_t size) : VMutableArrayImpl<T>(size)
{
}
- T get_impl(const int64_t index) const final
+ T get(const int64_t index) const final
{
return data_[index];
}
- bool is_span_impl() const final
+ void set(const int64_t index, T value) final
+ {
+ data_[index] = value;
+ }
+
+ bool is_span() const override
{
return true;
}
- Span<T> get_internal_span_impl() const final
+ Span<T> get_internal_span() const override
{
return Span<T>(data_, this->size_);
}
+
+ bool is_same(const VArrayImpl<T> &other) const final
+ {
+ if (other.size() != this->size_) {
+ return false;
+ }
+ if (!other.is_span()) {
+ return false;
+ }
+ const Span<T> other_span = other.get_internal_span();
+ return data_ == other_span.data();
+ }
};
-template<typename T> class VMutableArray_For_MutableSpan : public VMutableArray<T> {
- protected:
- T *data_ = nullptr;
+/**
+ * A version of #VArrayImpl_For_Span that can not be subclassed. This allows safely overwriting the
+ * #may_have_ownership method.
+ */
+template<typename T> class VArrayImpl_For_Span_final final : public VArrayImpl_For_Span<T> {
+ public:
+ using VArrayImpl_For_Span<T>::VArrayImpl_For_Span;
+
+ private:
+ bool may_have_ownership() const override
+ {
+ return false;
+ }
+};
+
+/**
+ * A variant of `VArrayImpl_For_Span` that owns the underlying data.
+ * The `Container` type has to implement a `size()` and `data()` method.
+ * The `data()` method has to return a pointer to the first element in the continuous array of
+ * elements.
+ */
+template<typename Container, typename T = typename Container::value_type>
+class VArrayImpl_For_ArrayContainer : public VArrayImpl_For_Span<T> {
+ private:
+ Container container_;
public:
- VMutableArray_For_MutableSpan(const MutableSpan<T> data)
- : VMutableArray<T>(data.size()), data_(data.data())
+ VArrayImpl_For_ArrayContainer(Container container)
+ : VArrayImpl_For_Span<T>((int64_t)container.size()), container_(std::move(container))
+ {
+ this->data_ = const_cast<T *>(container_.data());
+ }
+};
+
+/**
+ * A virtual array implementation that returns the same value for every index. This class is final
+ * so that it can be devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is
+ * used).
+ */
+template<typename T> class VArrayImpl_For_Single final : public VArrayImpl<T> {
+ private:
+ T value_;
+
+ public:
+ VArrayImpl_For_Single(T value, const int64_t size)
+ : VArrayImpl<T>(size), value_(std::move(value))
{
}
protected:
- VMutableArray_For_MutableSpan(const int64_t size) : VMutableArray<T>(size)
+ T get(const int64_t UNUSED(index)) const override
{
+ return value_;
}
- T get_impl(const int64_t index) const final
+ bool is_span() const override
{
- return data_[index];
+ return this->size_ == 1;
}
- void set_impl(const int64_t index, T value) final
+ Span<T> get_internal_span() const override
{
- data_[index] = value;
+ return Span<T>(&value_, 1);
}
- bool is_span_impl() const override
+ bool is_single() const override
{
return true;
}
- Span<T> get_internal_span_impl() const override
+ T get_internal_single() const override
{
- return Span<T>(data_, this->size_);
+ return value_;
}
};
/**
- * A variant of `VArray_For_Span` that owns the underlying data.
- * The `Container` type has to implement a `size()` and `data()` method.
- * The `data()` method has to return a pointer to the first element in the continuous array of
- * elements.
+ * This class makes it easy to create a virtual array for an existing function or lambda. The
+ * `GetFunc` should take a single `index` argument and return the value at that index.
*/
-template<typename Container, typename T = typename Container::value_type>
-class VArray_For_ArrayContainer : public VArray_For_Span<T> {
+template<typename T, typename GetFunc> class VArrayImpl_For_Func final : public VArrayImpl<T> {
private:
- Container container_;
+ GetFunc get_func_;
public:
- VArray_For_ArrayContainer(Container container)
- : VArray_For_Span<T>((int64_t)container.size()), container_(std::move(container))
+ VArrayImpl_For_Func(const int64_t size, GetFunc get_func)
+ : VArrayImpl<T>(size), get_func_(std::move(get_func))
+ {
+ }
+
+ private:
+ T get(const int64_t index) const override
+ {
+ return get_func_(index);
+ }
+
+ void materialize(IndexMask mask, MutableSpan<T> r_span) const override
{
- this->data_ = container_.data();
+ T *dst = r_span.data();
+ mask.foreach_index([&](const int64_t i) { dst[i] = get_func_(i); });
+ }
+
+ void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const override
+ {
+ T *dst = r_span.data();
+ mask.foreach_index([&](const int64_t i) { new (dst + i) T(get_func_(i)); });
}
};
/**
- * A virtual array implementation that returns the same value for every index. This class is final
- * so that it can be devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is
- * used).
+ * \note: This is `final` so that #may_have_ownership can be implemented reliably.
*/
-template<typename T> class VArray_For_Single final : public VArray<T> {
+template<typename StructT,
+ typename ElemT,
+ ElemT (*GetFunc)(const StructT &),
+ void (*SetFunc)(StructT &, ElemT) = nullptr>
+class VArrayImpl_For_DerivedSpan final : public VMutableArrayImpl<ElemT> {
private:
- T value_;
+ StructT *data_;
public:
- VArray_For_Single(T value, const int64_t size) : VArray<T>(size), value_(std::move(value))
+ VArrayImpl_For_DerivedSpan(const MutableSpan<StructT> data)
+ : VMutableArrayImpl<ElemT>(data.size()), data_(data.data())
{
}
+ template<typename OtherStructT,
+ typename OtherElemT,
+ OtherElemT (*OtherGetFunc)(const OtherStructT &),
+ void (*OtherSetFunc)(OtherStructT &, OtherElemT)>
+ friend class VArrayImpl_For_DerivedSpan;
+
+ private:
+ ElemT get(const int64_t index) const override
+ {
+ return GetFunc(data_[index]);
+ }
+
+ void set(const int64_t index, ElemT value) override
+ {
+ SetFunc(data_[index], std::move(value));
+ }
+
+ void materialize(IndexMask mask, MutableSpan<ElemT> r_span) const override
+ {
+ ElemT *dst = r_span.data();
+ mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); });
+ }
+
+ void materialize_to_uninitialized(IndexMask mask, MutableSpan<ElemT> r_span) const override
+ {
+ ElemT *dst = r_span.data();
+ mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); });
+ }
+
+ bool may_have_ownership() const override
+ {
+ return false;
+ }
+
+ bool is_same(const VArrayImpl<ElemT> &other) const override
+ {
+ if (other.size() != this->size_) {
+ return false;
+ }
+ if (const VArrayImpl_For_DerivedSpan<StructT, ElemT, GetFunc> *other_typed =
+ dynamic_cast<const VArrayImpl_For_DerivedSpan<StructT, ElemT, GetFunc> *>(&other)) {
+ return other_typed->data_ == data_;
+ }
+ if (const VArrayImpl_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc> *other_typed =
+ dynamic_cast<const VArrayImpl_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc> *>(
+ &other)) {
+ return other_typed->data_ == data_;
+ }
+ return false;
+ }
+};
+
+namespace detail {
+
+/**
+ * Struct that can be passed as `ExtraInfo` into an #Any.
+ * This struct is only intended to be used by #VArrayCommon.
+ */
+template<typename T> struct VArrayAnyExtraInfo {
+ /**
+ * Gets the virtual array that is stored at the given pointer.
+ */
+ const VArrayImpl<T> *(*get_varray)(const void *buffer) =
+ [](const void *UNUSED(buffer)) -> const VArrayImpl<T> * { return nullptr; };
+
+ template<typename StorageT> static VArrayAnyExtraInfo get()
+ {
+ /* These are the only allowed types in the #Any. */
+ static_assert(
+ std::is_base_of_v<VArrayImpl<T>, StorageT> ||
+ is_same_any_v<StorageT, const VArrayImpl<T> *, std::shared_ptr<const VArrayImpl<T>>>);
+
+ /* Depending on how the virtual array implementation is stored in the #Any, a different
+ * #get_varray function is required. */
+ if constexpr (std::is_base_of_v<VArrayImpl<T>, StorageT>) {
+ return {[](const void *buffer) {
+ return static_cast<const VArrayImpl<T> *>((const StorageT *)buffer);
+ }};
+ }
+ else if constexpr (std::is_same_v<StorageT, const VArrayImpl<T> *>) {
+ return {[](const void *buffer) { return *(const StorageT *)buffer; }};
+ }
+ else if constexpr (std::is_same_v<StorageT, std::shared_ptr<const VArrayImpl<T>>>) {
+ return {[](const void *buffer) { return ((const StorageT *)buffer)->get(); }};
+ }
+ else {
+ BLI_assert_unreachable();
+ return {};
+ }
+ }
+};
+
+} // namespace detail
+
+/**
+ * Utility class to reduce code duplication for methods available on #VArray and #VMutableArray.
+ * Deriving #VMutableArray from #VArray would have some issues:
+ * - Static methods on #VArray would also be available on #VMutableArray.
+ * - It would allow assigning a #VArray to a #VMutableArray under some circumstances which is not
+ * allowed and could result in hard to find bugs.
+ */
+template<typename T> class VArrayCommon {
+ protected:
+ /**
+ * Store the virtual array implementation in an #Any. This makes it easy to avoid a memory
+ * allocation if the implementation is small enough and is copyable. This is the case for the
+ * most common virtual arrays.
+ * Other virtual array implementations are typically stored as #std::shared_ptr. That works even
+ * when the implementation itself is not copyable and makes copying #VArrayCommon cheaper.
+ */
+ using Storage = Any<detail::VArrayAnyExtraInfo<T>, 24, 8>;
+
+ /**
+ * Pointer to the currently contained virtual array implementation. This is allowed to be null.
+ */
+ const VArrayImpl<T> *impl_ = nullptr;
+ /**
+ * Does the memory management for the virtual array implementation. It contains one of the
+ * following:
+ * - Inlined subclass of #VArrayImpl.
+ * - Non-owning pointer to a #VArrayImpl.
+ * - Shared pointer to a #VArrayImpl.
+ */
+ Storage storage_;
+
protected:
- T get_impl(const int64_t UNUSED(index)) const override
+ VArrayCommon() = default;
+
+ /** Copy constructor. */
+ VArrayCommon(const VArrayCommon &other) : storage_(other.storage_)
{
- return value_;
+ impl_ = this->impl_from_storage();
}
- bool is_span_impl() const override
+ /** Move constructor. */
+ VArrayCommon(VArrayCommon &&other) noexcept : storage_(std::move(other.storage_))
{
- return this->size_ == 1;
+ impl_ = this->impl_from_storage();
+ other.storage_.reset();
+ other.impl_ = nullptr;
}
- Span<T> get_internal_span_impl() const override
+ /**
+ * Wrap an existing #VArrayImpl and don't take ownership of it. This should rarely be used in
+ * practice.
+ */
+ VArrayCommon(const VArrayImpl<T> *impl) : impl_(impl)
{
- return Span<T>(&value_, 1);
+ storage_ = impl_;
}
- bool is_single_impl() const override
+ /**
+ * Wrap an existing #VArrayImpl that is contained in a #std::shared_ptr. This takes ownership.
+ */
+ VArrayCommon(std::shared_ptr<const VArrayImpl<T>> impl) : impl_(impl.get())
{
- return true;
+ if (impl) {
+ storage_ = std::move(impl);
+ }
}
- T get_internal_single_impl() const override
+ /**
+ * Replace the contained #VArrayImpl.
+ */
+ template<typename ImplT, typename... Args> void emplace(Args &&...args)
+ {
+ /* Make sure we are actually constructing a #VArrayImpl. */
+ static_assert(std::is_base_of_v<VArrayImpl<T>, ImplT>);
+ if constexpr (std::is_copy_constructible_v<ImplT> && Storage::template is_inline_v<ImplT>) {
+ /* Only inline the implementation when it is copyable and when it fits into the inline
+ * buffer of the storage. */
+ impl_ = &storage_.template emplace<ImplT>(std::forward<Args>(args)...);
+ }
+ else {
+ /* If it can't be inlined, create a new #std::shared_ptr instead and store that in the
+ * storage. */
+ std::shared_ptr<const VArrayImpl<T>> ptr = std::make_shared<ImplT>(
+ std::forward<Args>(args)...);
+ impl_ = &*ptr;
+ storage_ = std::move(ptr);
+ }
+ }
+
+ /** Utility to implement a copy assignment operator in a subclass. */
+ void copy_from(const VArrayCommon &other)
+ {
+ if (this == &other) {
+ return;
+ }
+ storage_ = other.storage_;
+ impl_ = this->impl_from_storage();
+ }
+
+ /** Utility to implement a move assignment operator in a subclass. */
+ void move_from(VArrayCommon &&other) noexcept
+ {
+ if (this == &other) {
+ return;
+ }
+ storage_ = std::move(other.storage_);
+ impl_ = this->impl_from_storage();
+ other.storage_.reset();
+ other.impl_ = nullptr;
+ }
+
+ /** Get a pointer to the virtual array implementation that is currently stored in #storage_, or
+ * null. */
+ const VArrayImpl<T> *impl_from_storage() const
+ {
+ return storage_.extra_info().get_varray(storage_.get());
+ }
+
+ public:
+ /** Return false when there is no virtual array implementation currently. */
+ operator bool() const
+ {
+ return impl_ != nullptr;
+ }
+
+ /**
+ * Get the element at a specific index.
+ * \note: This can't return a reference because the value may be computed on the fly. This also
+ * implies that one can not use this method for assignments.
+ */
+ T operator[](const int64_t index) const
+ {
+ BLI_assert(*this);
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ return impl_->get(index);
+ }
+
+ /**
+ * Same as the #operator[] but is sometimes easier to use when one has a pointer to a virtual
+ * array.
+ */
+ T get(const int64_t index) const
+ {
+ return (*this)[index];
+ }
+
+ /**
+ * Return the size of the virtual array. It's allowed to call this method even when there is no
+ * virtual array. In this case 0 is returned.
+ */
+ int64_t size() const
+ {
+ if (impl_ == nullptr) {
+ return 0;
+ }
+ return impl_->size();
+ }
+
+ /** True when the size is zero or when there is no virtual array. */
+ bool is_empty() const
+ {
+ return this->size() == 0;
+ }
+
+ IndexRange index_range() const
+ {
+ return IndexRange(this->size());
+ }
+
+ /** Return true when the virtual array is stored as a span internally. */
+ bool is_span() const
+ {
+ BLI_assert(*this);
+ return impl_->is_span();
+ }
+
+ /**
+ * Returns the internally used span of the virtual array. This invokes undefined behavior is the
+ * virtual array is not stored as a span internally.
+ */
+ Span<T> get_internal_span() const
+ {
+ BLI_assert(this->is_span());
+ if (this->is_empty()) {
+ return {};
+ }
+ return impl_->get_internal_span();
+ }
+
+ /** Return true when the virtual array returns the same value for every index. */
+ bool is_single() const
+ {
+ BLI_assert(*this);
+ return impl_->is_single();
+ }
+
+ /**
+ * Return the value that is returned for every index. This invokes undefined behavior if the
+ * virtual array would not return the same value for every index.
+ */
+ T get_internal_single() const
+ {
+ BLI_assert(this->is_single());
+ if (impl_->size() == 1) {
+ return impl_->get(0);
+ }
+ return impl_->get_internal_single();
+ }
+
+ /**
+ * Return true when the other virtual references the same underlying memory.
+ */
+ bool is_same(const VArrayCommon<T> &other) const
+ {
+ if (!*this || !other) {
+ return false;
+ }
+ /* Check in both directions in case one does not know how to compare to the other
+ * implementation. */
+ if (impl_->is_same(*other.impl_)) {
+ return true;
+ }
+ if (other.impl_->is_same(*impl_)) {
+ return true;
+ }
+ return false;
+ }
+
+ /** Copy the entire virtual array into a span. */
+ void materialize(MutableSpan<T> r_span) const
+ {
+ this->materialize(IndexMask(this->size()), r_span);
+ }
+
+ /** Copy some indices of the virtual array into a span. */
+ void materialize(IndexMask mask, MutableSpan<T> r_span) const
+ {
+ BLI_assert(mask.min_array_size() <= this->size());
+ impl_->materialize(mask, r_span);
+ }
+
+ void materialize_to_uninitialized(MutableSpan<T> r_span) const
+ {
+ this->materialize_to_uninitialized(IndexMask(this->size()), r_span);
+ }
+
+ void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const
+ {
+ BLI_assert(mask.min_array_size() <= this->size());
+ impl_->materialize_to_uninitialized(mask, r_span);
+ }
+
+ /** See #GVArrayImpl::try_assign_GVArray. */
+ bool try_assign_GVArray(fn::GVArray &varray) const
+ {
+ return impl_->try_assign_GVArray(varray);
+ }
+
+ /** See #GVArrayImpl::may_have_ownership. */
+ bool may_have_ownership() const
+ {
+ return impl_->may_have_ownership();
+ }
+};
+
+template<typename T> class VMutableArray;
+
+/**
+ * A #VArray wraps a virtual array implementation and provides easy access to its elements. It can
+ * be copied and moved. While it is relatively small, it should still be passed by reference if
+ * possible (other than e.g. #Span).
+ */
+template<typename T> class VArray : public VArrayCommon<T> {
+ friend VMutableArray<T>;
+
+ public:
+ VArray() = default;
+ VArray(const VArray &other) = default;
+ VArray(VArray &&other) noexcept = default;
+
+ VArray(const VArrayImpl<T> *impl) : VArrayCommon<T>(impl)
+ {
+ }
+
+ VArray(std::shared_ptr<const VArrayImpl<T>> impl) : VArrayCommon<T>(std::move(impl))
{
- return value_;
+ }
+
+ /**
+ * Construct a new virtual array for a custom #VArrayImpl.
+ */
+ template<typename ImplT, typename... Args> static VArray For(Args &&...args)
+ {
+ static_assert(std::is_base_of_v<VArrayImpl<T>, ImplT>);
+ VArray varray;
+ varray.template emplace<ImplT>(std::forward<Args>(args)...);
+ return varray;
+ }
+
+ /**
+ * Construct a new virtual array that has the same value at every index.
+ */
+ static VArray ForSingle(T value, const int64_t size)
+ {
+ return VArray::For<VArrayImpl_For_Single<T>>(std::move(value), size);
+ }
+
+ /**
+ * Construct a new virtual array for an existing span. This does not take ownership of the
+ * underlying memory.
+ */
+ static VArray ForSpan(Span<T> values)
+ {
+ /* Cast const away, because the virtual array implementation for const and non const spans is
+ * shared. */
+ MutableSpan<T> span{const_cast<T *>(values.data()), values.size()};
+ return VArray::For<VArrayImpl_For_Span_final<T>>(span);
+ }
+
+ /**
+ * Construct a new virtual that will invoke the provided function whenever an element is
+ * accessed.
+ */
+ template<typename GetFunc> static VArray ForFunc(const int64_t size, GetFunc get_func)
+ {
+ return VArray::For<VArrayImpl_For_Func<T, decltype(get_func)>>(size, std::move(get_func));
+ }
+
+ /**
+ * Construct a new virtual array for an existing span with a mapping function. This does not take
+ * ownership of the span.
+ */
+ template<typename StructT, T (*GetFunc)(const StructT &)>
+ static VArray ForDerivedSpan(Span<StructT> values)
+ {
+ /* Cast const away, because the virtual array implementation for const and non const derived
+ * spans is shared. */
+ MutableSpan<StructT> span{const_cast<StructT *>(values.data()), values.size()};
+ return VArray::For<VArrayImpl_For_DerivedSpan<StructT, T, GetFunc>>(span);
+ }
+
+ /**
+ * Construct a new virtual array for an existing container. Every container that lays out the
+ * elements in a plain array works. This takes ownership of the passed in container. If that is
+ * not desired, use #ForSpan instead.
+ */
+ template<typename ContainerT> static VArray ForContainer(ContainerT container)
+ {
+ return VArray::For<VArrayImpl_For_ArrayContainer<ContainerT>>(std::move(container));
+ }
+
+ VArray &operator=(const VArray &other)
+ {
+ this->copy_from(other);
+ return *this;
+ }
+
+ VArray &operator=(VArray &&other) noexcept
+ {
+ this->move_from(std::move(other));
+ return *this;
+ }
+};
+
+/**
+ * Similar to #VArray but references a virtual array that can be modified.
+ */
+template<typename T> class VMutableArray : public VArrayCommon<T> {
+ public:
+ VMutableArray() = default;
+ VMutableArray(const VMutableArray &other) = default;
+ VMutableArray(VMutableArray &&other) noexcept = default;
+
+ VMutableArray(const VMutableArrayImpl<T> *impl) : VArrayCommon<T>(impl)
+ {
+ }
+
+ VMutableArray(std::shared_ptr<const VMutableArrayImpl<T>> impl)
+ : VArrayCommon<T>(std::move(impl))
+ {
+ }
+
+ /**
+ * Construct a new virtual array for a custom #VMutableArrayImpl.
+ */
+ template<typename ImplT, typename... Args> static VMutableArray For(Args &&...args)
+ {
+ static_assert(std::is_base_of_v<VMutableArrayImpl<T>, ImplT>);
+ VMutableArray varray;
+ varray.template emplace<ImplT>(std::forward<Args>(args)...);
+ return varray;
+ }
+
+ /**
+ * Construct a new virtual array for an existing span. This does not take ownership of the span.
+ */
+ static VMutableArray ForSpan(MutableSpan<T> values)
+ {
+ return VMutableArray::For<VArrayImpl_For_Span_final<T>>(values);
+ }
+
+ /**
+ * Construct a new virtual array for an existing span with a mapping function. This does not take
+ * ownership of the span.
+ */
+ template<typename StructT, T (*GetFunc)(const StructT &), void (*SetFunc)(StructT &, T)>
+ static VMutableArray ForDerivedSpan(MutableSpan<StructT> values)
+ {
+ return VMutableArray::For<VArrayImpl_For_DerivedSpan<StructT, T, GetFunc, SetFunc>>(values);
+ }
+
+ /** Convert to a #VArray by copying. */
+ operator VArray<T>() const &
+ {
+ VArray<T> varray;
+ varray.copy_from(*this);
+ return varray;
+ }
+
+ /** Convert to a #VArray by moving. */
+ operator VArray<T>() &&noexcept
+ {
+ VArray<T> varray;
+ varray.move_from(std::move(*this));
+ return varray;
+ }
+
+ VMutableArray &operator=(const VMutableArray &other)
+ {
+ this->copy_from(other);
+ return *this;
+ }
+
+ VMutableArray &operator=(VMutableArray &&other) noexcept
+ {
+ this->move_from(std::move(other));
+ return *this;
+ }
+
+ /**
+ * Get access to the internal span. This invokes undefined behavior if the #is_span returned
+ * false.
+ */
+ MutableSpan<T> get_internal_span() const
+ {
+ BLI_assert(this->is_span());
+ const Span<T> span = this->impl_->get_internal_span();
+ return MutableSpan<T>(const_cast<T *>(span.data()), span.size());
+ }
+
+ /**
+ * Set the value at the given index.
+ */
+ void set(const int64_t index, T value)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ this->get_impl()->set(index, std::move(value));
+ }
+
+ /**
+ * Copy the values from the source span to all elements in the virtual array.
+ */
+ void set_all(Span<T> src)
+ {
+ BLI_assert(src.size() == this->size());
+ this->get_impl()->set_all(src);
+ }
+
+ /** See #GVMutableArrayImpl::try_assign_GVMutableArray. */
+ bool try_assign_GVMutableArray(fn::GVMutableArray &varray) const
+ {
+ return this->get_impl()->try_assign_GVMutableArray(varray);
+ }
+
+ private:
+ /** Utility to get the pointer to the wrapped #VMutableArrayImpl. */
+ VMutableArrayImpl<T> *get_impl() const
+ {
+ /* This cast is valid by the invariant that a #VMutableArray->impl_ is always a
+ * #VMutableArrayImpl. */
+ return (VMutableArrayImpl<T> *)this->impl_;
}
};
@@ -401,11 +1002,11 @@ template<typename T> class VArray_For_Single final : public VArray<T> {
*/
template<typename T> class VArray_Span final : public Span<T> {
private:
- const VArray<T> &varray_;
+ VArray<T> varray_;
Array<T> owned_data_;
public:
- VArray_Span(const VArray<T> &varray) : Span<T>(), varray_(varray)
+ VArray_Span(VArray<T> varray) : Span<T>(), varray_(std::move(varray))
{
this->size_ = varray_.size();
if (varray_.is_span()) {
@@ -421,7 +1022,7 @@ template<typename T> class VArray_Span final : public Span<T> {
};
/**
- * Same as VArray_Span, but for a mutable span.
+ * Same as #VArray_Span, but for a mutable span.
* The important thing to note is that when changing this span, the results might not be
* immediately reflected in the underlying virtual array (only when the virtual array is a span
* internally). The #save method can be used to write all changes to the underlying virtual array,
@@ -429,7 +1030,7 @@ template<typename T> class VArray_Span final : public Span<T> {
*/
template<typename T> class VMutableArray_Span final : public MutableSpan<T> {
private:
- VMutableArray<T> &varray_;
+ VMutableArray<T> varray_;
Array<T> owned_data_;
bool save_has_been_called_ = false;
bool show_not_saved_warning_ = true;
@@ -437,8 +1038,8 @@ template<typename T> class VMutableArray_Span final : public MutableSpan<T> {
public:
/* Create a span for any virtual array. This is cheap when the virtual array is a span itself. If
* not, a new array has to be allocated as a wrapper for the underlying virtual array. */
- VMutableArray_Span(VMutableArray<T> &varray, const bool copy_values_to_span = true)
- : MutableSpan<T>(), varray_(varray)
+ VMutableArray_Span(VMutableArray<T> varray, const bool copy_values_to_span = true)
+ : MutableSpan<T>(), varray_(std::move(varray))
{
this->size_ = varray_.size();
if (varray_.is_span()) {
@@ -482,103 +1083,27 @@ template<typename T> class VMutableArray_Span final : public MutableSpan<T> {
}
};
-/**
- * This class makes it easy to create a virtual array for an existing function or lambda. The
- * `GetFunc` should take a single `index` argument and return the value at that index.
- */
-template<typename T, typename GetFunc> class VArray_For_Func final : public VArray<T> {
+template<typename T> class SingleAsSpan {
private:
- GetFunc get_func_;
-
- public:
- VArray_For_Func(const int64_t size, GetFunc get_func)
- : VArray<T>(size), get_func_(std::move(get_func))
- {
- }
-
- private:
- T get_impl(const int64_t index) const override
- {
- return get_func_(index);
- }
-
- void materialize_impl(IndexMask mask, MutableSpan<T> r_span) const override
- {
- T *dst = r_span.data();
- mask.foreach_index([&](const int64_t i) { dst[i] = get_func_(i); });
- }
-
- void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<T> r_span) const override
- {
- T *dst = r_span.data();
- mask.foreach_index([&](const int64_t i) { new (dst + i) T(get_func_(i)); });
- }
-};
-
-template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
-class VArray_For_DerivedSpan : public VArray<ElemT> {
- private:
- const StructT *data_;
-
- public:
- VArray_For_DerivedSpan(const Span<StructT> data) : VArray<ElemT>(data.size()), data_(data.data())
- {
- }
-
- private:
- ElemT get_impl(const int64_t index) const override
- {
- return GetFunc(data_[index]);
- }
-
- void materialize_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override
- {
- ElemT *dst = r_span.data();
- mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); });
- }
-
- void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override
- {
- ElemT *dst = r_span.data();
- mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); });
- }
-};
-
-template<typename StructT,
- typename ElemT,
- ElemT (*GetFunc)(const StructT &),
- void (*SetFunc)(StructT &, ElemT)>
-class VMutableArray_For_DerivedSpan : public VMutableArray<ElemT> {
- private:
- StructT *data_;
+ T value_;
+ int64_t size_;
public:
- VMutableArray_For_DerivedSpan(const MutableSpan<StructT> data)
- : VMutableArray<ElemT>(data.size()), data_(data.data())
+ SingleAsSpan(T value, int64_t size) : value_(std::move(value)), size_(size)
{
+ BLI_assert(size_ >= 0);
}
- private:
- ElemT get_impl(const int64_t index) const override
- {
- return GetFunc(data_[index]);
- }
-
- void set_impl(const int64_t index, ElemT value) override
- {
- SetFunc(data_[index], std::move(value));
- }
-
- void materialize_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override
+ SingleAsSpan(const VArray<T> &varray) : SingleAsSpan(varray.get_internal_single(), varray.size())
{
- ElemT *dst = r_span.data();
- mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); });
}
- void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override
+ const T &operator[](const int64_t index) const
{
- ElemT *dst = r_span.data();
- mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); });
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ UNUSED_VARS_NDEBUG(index);
+ return value_;
}
};
@@ -596,15 +1121,11 @@ inline void devirtualize_varray(const VArray<T> &varray, const Func &func, bool
/* Support disabling the devirtualization to simplify benchmarking. */
if (enable) {
if (varray.is_single()) {
- /* `VArray_For_Single` can be used for devirtualization, because it is declared `final`. */
- const VArray_For_Single<T> varray_single{varray.get_internal_single(), varray.size()};
- func(varray_single);
+ func(SingleAsSpan<T>(varray));
return;
}
if (varray.is_span()) {
- /* `VArray_For_Span` can be used for devirtualization, because it is declared `final`. */
- const VArray_For_Span<T> varray_span{varray.get_internal_span()};
- func(varray_span);
+ func(varray.get_internal_span());
return;
}
}
@@ -629,27 +1150,19 @@ inline void devirtualize_varray2(const VArray<T1> &varray1,
const bool is_single1 = varray1.is_single();
const bool is_single2 = varray2.is_single();
if (is_span1 && is_span2) {
- const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()};
- const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()};
- func(varray1_span, varray2_span);
+ func(varray1.get_internal_span(), varray2.get_internal_span());
return;
}
if (is_span1 && is_single2) {
- const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()};
- const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()};
- func(varray1_span, varray2_single);
+ func(varray1.get_internal_span(), SingleAsSpan(varray2));
return;
}
if (is_single1 && is_span2) {
- const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()};
- const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()};
- func(varray1_single, varray2_span);
+ func(SingleAsSpan(varray1), varray2.get_internal_span());
return;
}
if (is_single1 && is_single2) {
- const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()};
- const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()};
- func(varray1_single, varray2_single);
+ func(SingleAsSpan(varray1), SingleAsSpan(varray2));
return;
}
}
diff --git a/source/blender/blenlib/BLI_virtual_vector_array.hh b/source/blender/blenlib/BLI_virtual_vector_array.hh
index ab5afd2d80a..7960c6b1420 100644
--- a/source/blender/blenlib/BLI_virtual_vector_array.hh
+++ b/source/blender/blenlib/BLI_virtual_vector_array.hh
@@ -29,7 +29,7 @@
namespace blender {
-/* A readonly virtual array of vectors. */
+/** A read-only virtual array of vectors. */
template<typename T> class VVectorArray {
protected:
int64_t size_;
@@ -82,9 +82,9 @@ template<typename T> class VVectorArray {
}
protected:
- virtual int64_t get_vector_size_impl(const int64_t index) const = 0;
+ virtual int64_t get_vector_size_impl(int64_t index) const = 0;
- virtual T get_vector_element_impl(const int64_t index, const int64_t index_in_vetor) const = 0;
+ virtual T get_vector_element_impl(int64_t index, int64_t index_in_vetor) const = 0;
virtual bool is_single_vector_impl() const
{
diff --git a/source/blender/blenlib/BLI_voxel.h b/source/blender/blenlib/BLI_voxel.h
index eb84f0a27ee..83e4bdbdc10 100644
--- a/source/blender/blenlib/BLI_voxel.h
+++ b/source/blender/blenlib/BLI_voxel.h
@@ -27,13 +27,13 @@
extern "C" {
#endif
-/** Find the index number of a voxel, given x/y/z integer coords and resolution vector. */
-
+/** Calculate the index number of a voxel, given x/y/z integer coords and resolution vector. */
#define BLI_VOXEL_INDEX(x, y, z, res) \
((int64_t)(x) + (int64_t)(y) * (int64_t)(res)[0] + \
(int64_t)(z) * (int64_t)(res)[0] * (int64_t)(res)[1])
-/* all input coordinates must be in bounding box 0.0 - 1.0 */
+/* All input coordinates must be in bounding box 0.0 - 1.0. */
+
float BLI_voxel_sample_nearest(const float *data, const int res[3], const float co[3]);
float BLI_voxel_sample_trilinear(const float *data, const int res[3], const float co[3]);
float BLI_voxel_sample_triquadratic(const float *data, const int res[3], const float co[3]);
diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h
index bf09b56c779..2ea557e971a 100644
--- a/source/blender/blenlib/BLI_winstuff.h
+++ b/source/blender/blenlib/BLI_winstuff.h
@@ -88,7 +88,7 @@ typedef SSIZE_T ssize_t;
# endif
#endif
-/* Directory reading compatibility with UNIX. */
+/** Directory reading compatibility with UNIX. */
struct dirent {
int d_ino;
int d_off;
@@ -96,7 +96,7 @@ struct dirent {
char *d_name;
};
-/* intentionally opaque to users */
+/** Intentionally opaque to users. */
typedef struct __dirstream DIR;
DIR *opendir(const char *path);
@@ -105,8 +105,9 @@ int closedir(DIR *dp);
const char *dirname(char *path);
/* Windows utility functions. */
-bool BLI_windows_register_blend_extension(const bool background);
-void BLI_windows_get_default_root_dir(char *root_dir);
+
+bool BLI_windows_register_blend_extension(bool background);
+void BLI_windows_get_default_root_dir(char root_dir[4]);
int BLI_windows_get_executable_dir(char *str);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 1eaf007e01b..e9446f36c83 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -25,14 +25,13 @@ set(INC
../../../intern/atomic
../../../intern/eigen
../../../intern/guardedalloc
- ../../../intern/numaapi/include
../../../extern/wcwidth
+ ../../../extern/json/include
)
set(INC_SYS
${ZLIB_INCLUDE_DIRS}
${ZSTD_INCLUDE_DIRS}
- ${FREETYPE_INCLUDE_DIRS}
${GMP_INCLUDE_DIRS}
)
@@ -76,12 +75,12 @@ set(SRC
intern/endian_switch.c
intern/expr_pylike_eval.c
intern/fileops.c
+ intern/fileops.cc
intern/filereader_file.c
intern/filereader_gzip.c
intern/filereader_memory.c
intern/filereader_zstd.c
intern/fnmatch.c
- intern/freetypefont.c
intern/gsqueue.c
intern/hash_md5.c
intern/hash_mm2a.c
@@ -124,8 +123,10 @@ set(SRC
intern/quadric.c
intern/rand.cc
intern/rct.c
+ intern/resource_scope.cc
intern/scanfill.c
intern/scanfill_utils.c
+ intern/serialize.cc
intern/session_uuid.c
intern/smallhash.c
intern/sort.c
@@ -164,6 +165,7 @@ set(SRC
BLI_alloca.h
BLI_allocator.hh
+ BLI_any.hh
BLI_args.h
BLI_array.h
BLI_array.hh
@@ -190,8 +192,6 @@ set(SRC
BLI_dlrbTree.h
BLI_dot_export.hh
BLI_dot_export_attribute_enums.hh
- BLI_double2.hh
- BLI_double3.hh
BLI_dynlib.h
BLI_dynstr.h
BLI_easing.h
@@ -202,11 +202,9 @@ set(SRC
BLI_enumerable_thread_specific.hh
BLI_expr_pylike_eval.h
BLI_fileops.h
+ BLI_fileops.hh
BLI_fileops_types.h
BLI_filereader.h
- BLI_float2.hh
- BLI_float3.hh
- BLI_float4.hh
BLI_float4x4.hh
BLI_fnmatch.h
BLI_function_ref.hh
@@ -254,6 +252,8 @@ set(SRC
BLI_math_solvers.h
BLI_math_statistics.h
BLI_math_time.h
+ BLI_math_vec_mpq_types.hh
+ BLI_math_vec_types.hh
BLI_math_vector.h
BLI_memarena.h
BLI_memblock.h
@@ -264,8 +264,6 @@ set(SRC
BLI_mesh_boolean.hh
BLI_mesh_intersect.hh
BLI_mmap.h
- BLI_mpq2.hh
- BLI_mpq3.hh
BLI_multi_value_map.hh
BLI_noise.h
BLI_noise.hh
@@ -280,6 +278,7 @@ set(SRC
BLI_rect.h
BLI_resource_scope.hh
BLI_scanfill.h
+ BLI_serialize.hh
BLI_session_uuid.h
BLI_set.hh
BLI_set_slots.hh
@@ -317,7 +316,6 @@ set(SRC
BLI_vector_adaptor.hh
BLI_vector_set.hh
BLI_vector_set_slots.hh
- BLI_vfontdata.h
BLI_virtual_array.hh
BLI_virtual_vector_array.hh
BLI_voronoi_2d.h
@@ -330,10 +328,8 @@ set(SRC
set(LIB
bf_intern_eigen
bf_intern_guardedalloc
- bf_intern_numaapi
extern_wcwidth
- ${FREETYPE_LIBRARY}
${ZLIB_LIBRARIES}
${ZSTD_LIBRARIES}
)
@@ -367,6 +363,10 @@ if(WITH_GMP)
endif()
if(WIN32)
+ if (WITH_BLENDER_THUMBNAILER)
+ # Needed for querying the thumbnailer .dll in winstuff.c
+ add_definitions(-DWITH_BLENDER_THUMBNAILER)
+ endif()
list(APPEND INC
../../../intern/utfconv
)
@@ -407,6 +407,7 @@ blender_add_lib(bf_blenlib "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
if(WITH_GTESTS)
set(TEST_SRC
+ tests/BLI_any_test.cc
tests/BLI_array_store_test.cc
tests/BLI_array_test.cc
tests/BLI_array_utils_test.cc
@@ -415,6 +416,7 @@ if(WITH_GTESTS)
tests/BLI_disjoint_set_test.cc
tests/BLI_edgehash_test.cc
tests/BLI_expr_pylike_eval_test.cc
+ tests/BLI_fileops_test.cc
tests/BLI_function_ref_test.cc
tests/BLI_ghash_test.cc
tests/BLI_hash_mm2a_test.cc
@@ -437,6 +439,7 @@ if(WITH_GTESTS)
tests/BLI_math_rotation_test.cc
tests/BLI_math_solvers_test.cc
tests/BLI_math_time_test.cc
+ tests/BLI_math_vec_types_test.cc
tests/BLI_math_vector_test.cc
tests/BLI_memiter_test.cc
tests/BLI_memory_utils_test.cc
@@ -446,6 +449,7 @@ if(WITH_GTESTS)
tests/BLI_path_util_test.cc
tests/BLI_polyfill_2d_test.cc
tests/BLI_ressource_strings.h
+ tests/BLI_serialize_test.cc
tests/BLI_session_uuid_test.cc
tests/BLI_set_test.cc
tests/BLI_span_test.cc
diff --git a/source/blender/blenlib/intern/BLI_array.c b/source/blender/blenlib/intern/BLI_array.c
index 7a9cf416d91..f4d60a9e047 100644
--- a/source/blender/blenlib/intern/BLI_array.c
+++ b/source/blender/blenlib/intern/BLI_array.c
@@ -54,11 +54,6 @@
#include "MEM_guardedalloc.h"
-/**
- * This function is only to be called via macros.
- *
- * \note The caller must adjust \a arr_len
- */
void _bli_array_grow_func(void **arr_p,
const void *arr_static,
const int sizeof_arr_p,
diff --git a/source/blender/blenlib/intern/BLI_assert.c b/source/blender/blenlib/intern/BLI_assert.c
index cebc6f8957f..e089ef149a0 100644
--- a/source/blender/blenlib/intern/BLI_assert.c
+++ b/source/blender/blenlib/intern/BLI_assert.c
@@ -49,14 +49,13 @@ void _BLI_assert_print_backtrace(void)
#endif
}
-/**
- * Wrap to remove 'noreturn' attribute since this suppresses missing return statements,
- * allowing changes to debug builds to accidentally to break release builds.
- *
- * For example `BLI_assert(0);` at the end of a function that returns a value,
- * will hide that it's missing a return.
- */
void _BLI_assert_abort(void)
{
+ /* Wrap to remove 'noreturn' attribute since this suppresses missing return statements,
+ * allowing changes to debug builds to accidentally to break release builds.
+ *
+ * For example `BLI_assert(0);` at the end of a function that returns a value,
+ * will hide that it's missing a return. */
+
abort();
}
diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c
index 8f7f722c71b..262d112d914 100644
--- a/source/blender/blenlib/intern/BLI_dynstr.c
+++ b/source/blender/blenlib/intern/BLI_dynstr.c
@@ -63,11 +63,6 @@ struct DynStr {
/***/
-/**
- * Create a new DynStr.
- *
- * \return Pointer to a new DynStr.
- */
DynStr *BLI_dynstr_new(void)
{
DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
@@ -78,11 +73,6 @@ DynStr *BLI_dynstr_new(void)
return ds;
}
-/**
- * Create a new DynStr.
- *
- * \return Pointer to a new DynStr.
- */
DynStr *BLI_dynstr_new_memarena(void)
{
DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
@@ -98,12 +88,6 @@ BLI_INLINE void *dynstr_alloc(DynStr *__restrict ds, size_t size)
return ds->memarena ? BLI_memarena_alloc(ds->memarena, size) : malloc(size);
}
-/**
- * Append a c-string to a DynStr.
- *
- * \param ds: The DynStr to append to.
- * \param cstr: The c-string to append.
- */
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
{
DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse));
@@ -123,13 +107,6 @@ void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
ds->curlen += cstrlen;
}
-/**
- * Append a length clamped c-string to a DynStr.
- *
- * \param ds: The DynStr to append to.
- * \param cstr: The c-string to append.
- * \param len: The maximum length of the c-string to copy.
- */
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len)
{
DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse));
@@ -209,12 +186,6 @@ void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, v
}
}
-/**
- * Append a c-string to a DynStr, but with formatting like printf.
- *
- * \param ds: The DynStr to append to.
- * \param format: The printf format string to use.
- */
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...)
{
va_list args;
@@ -277,25 +248,11 @@ void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ..
}
}
-/**
- * Find the length of a DynStr.
- *
- * \param ds: The DynStr of interest.
- * \return The length of \a ds.
- */
int BLI_dynstr_get_len(const DynStr *ds)
{
return ds->curlen;
}
-/**
- * Get a DynStr's contents as a c-string.
- * The \a rets argument must be allocated to be at
- * least the size of `BLI_dynstr_get_len(ds) + 1`.
- *
- * \param ds: The DynStr of interest.
- * \param rets: The string to fill.
- */
void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict rets)
{
char *s;
@@ -312,14 +269,6 @@ void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict ret
rets[ds->curlen] = '\0';
}
-/**
- * Get a DynStr's contents as a c-string.
- * <i> The returned c-string should be freed
- * using MEM_freeN. </i>
- *
- * \param ds: The DynStr of interest.
- * \return The contents of \a ds as a c-string.
- */
char *BLI_dynstr_get_cstring(const DynStr *ds)
{
char *rets = MEM_mallocN(ds->curlen + 1, "dynstr_cstring");
@@ -327,11 +276,6 @@ char *BLI_dynstr_get_cstring(const DynStr *ds)
return rets;
}
-/**
- * Clear the DynStr
- *
- * \param ds: The DynStr to clear.
- */
void BLI_dynstr_clear(DynStr *ds)
{
if (ds->memarena) {
@@ -350,11 +294,6 @@ void BLI_dynstr_clear(DynStr *ds)
ds->curlen = 0;
}
-/**
- * Free the DynStr
- *
- * \param ds: The DynStr to free.
- */
void BLI_dynstr_free(DynStr *ds)
{
if (ds->memarena) {
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
index f05dea46dc8..169f34f52c3 100644
--- a/source/blender/blenlib/intern/BLI_filelist.c
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -229,12 +229,6 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
}
}
-/**
- * Scans the contents of the directory named *dirname, and allocates and fills in an
- * array of entries describing them in *filelist.
- *
- * \return The length of filelist array.
- */
unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist)
{
struct BuildDirCtx dir_ctx;
@@ -256,9 +250,6 @@ unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_
return dir_ctx.nrfiles;
}
-/**
- * Convert given entry's size into human-readable strings.
- */
void BLI_filelist_entry_size_to_string(const struct stat *st,
const uint64_t sz,
/* Used to change MB -> M, etc. - is that really useful? */
@@ -278,9 +269,6 @@ void BLI_filelist_entry_size_to_string(const struct stat *st,
#endif
}
-/**
- * Convert given entry's modes into human-readable strings.
- */
void BLI_filelist_entry_mode_to_string(const struct stat *st,
const bool UNUSED(compact),
char r_mode1[FILELIST_DIRENTRY_MODE_LEN],
@@ -328,9 +316,6 @@ void BLI_filelist_entry_mode_to_string(const struct stat *st,
#endif
}
-/**
- * Convert given entry's owner into human-readable strings.
- */
void BLI_filelist_entry_owner_to_string(const struct stat *st,
const bool UNUSED(compact),
char r_owner[FILELIST_DIRENTRY_OWNER_LEN])
@@ -349,12 +334,6 @@ void BLI_filelist_entry_owner_to_string(const struct stat *st,
#endif
}
-/**
- * Convert given entry's time into human-readable strings.
- *
- * \param r_is_today: optional, returns true if the date matches today's.
- * \param r_is_yesterday: optional, returns true if the date matches yesterday's.
- */
void BLI_filelist_entry_datetime_to_string(const struct stat *st,
const int64_t ts,
const bool compact,
@@ -417,9 +396,6 @@ void BLI_filelist_entry_datetime_to_string(const struct stat *st,
}
}
-/**
- * Deep-duplicate of a single direntry.
- */
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src)
{
*dst = *src;
@@ -431,9 +407,6 @@ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *s
}
}
-/**
- * Deep-duplicate of a #direntry array including the array itself.
- */
void BLI_filelist_duplicate(struct direntry **dest_filelist,
struct direntry *const src_filelist,
const unsigned int nrentries)
@@ -448,9 +421,6 @@ void BLI_filelist_duplicate(struct direntry **dest_filelist,
}
}
-/**
- * frees storage for a single direntry, not the direntry itself.
- */
void BLI_filelist_entry_free(struct direntry *entry)
{
if (entry->relname) {
@@ -461,9 +431,6 @@ void BLI_filelist_entry_free(struct direntry *entry)
}
}
-/**
- * Frees storage for an array of #direntry, including the array itself.
- */
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries)
{
unsigned int i;
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 2c9285e418a..8e2a8ab7639 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -694,16 +694,6 @@ static GHash *ghash_copy(const GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopy
/** \name GHash Public API
* \{ */
-/**
- * Creates a new, empty GHash.
- *
- * \param hashfp: Hash callback.
- * \param cmpfp: Comparison callback.
- * \param info: Identifier string for the GHash.
- * \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
- * Use this to avoid resizing buckets if the size is known or can be closely approximated.
- * \return An empty GHash.
- */
GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
GHashCmpFP cmpfp,
const char *info,
@@ -712,72 +702,38 @@ GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
return ghash_new(hashfp, cmpfp, info, nentries_reserve, 0);
}
-/**
- * Wraps #BLI_ghash_new_ex with zero entries reserved.
- */
GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info)
{
return BLI_ghash_new_ex(hashfp, cmpfp, info, 0);
}
-/**
- * Copy given GHash. Keys and values are also copied if relevant callback is provided,
- * else pointers remain the same.
- */
GHash *BLI_ghash_copy(const GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
{
return ghash_copy(gh, keycopyfp, valcopyfp);
}
-/**
- * Reserve given amount of entries (resize \a gh accordingly if needed).
- */
void BLI_ghash_reserve(GHash *gh, const uint nentries_reserve)
{
ghash_buckets_expand(gh, nentries_reserve, true);
ghash_buckets_contract(gh, nentries_reserve, true, false);
}
-/**
- * \return size of the GHash.
- */
uint BLI_ghash_len(const GHash *gh)
{
return gh->nentries;
}
-/**
- * Insert a key/value pair into the \a gh.
- *
- * \note Duplicates are not checked,
- * the caller is expected to ensure elements are unique unless
- * GHASH_FLAG_ALLOW_DUPES flag is set.
- */
void BLI_ghash_insert(GHash *gh, void *key, void *val)
{
ghash_insert(gh, key, val);
}
-/**
- * Inserts a new value to a key that may already be in ghash.
- *
- * Avoids #BLI_ghash_remove, #BLI_ghash_insert calls (double lookups)
- *
- * \returns true if a new key has been added.
- */
bool BLI_ghash_reinsert(
GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
return ghash_insert_safe(gh, key, val, true, keyfreefp, valfreefp);
}
-/**
- * Replaces the key of an item in the \a gh.
- *
- * Use when a key is re-allocated or its memory location is changed.
- *
- * \returns The previous key or NULL if not found, the caller may free if it's needed.
- */
void *BLI_ghash_replace_key(GHash *gh, void *key)
{
const uint hash = ghash_keyhash(gh, key);
@@ -791,15 +747,6 @@ void *BLI_ghash_replace_key(GHash *gh, void *key)
return NULL;
}
-/**
- * Lookup the value of \a key in \a gh.
- *
- * \param key: The key to lookup.
- * \returns the value for \a key or NULL.
- *
- * \note When NULL is a valid value, use #BLI_ghash_lookup_p to differentiate a missing key
- * from a key with a NULL value. (Avoids calling #BLI_ghash_haskey before #BLI_ghash_lookup)
- */
void *BLI_ghash_lookup(const GHash *gh, const void *key)
{
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
@@ -807,9 +754,6 @@ void *BLI_ghash_lookup(const GHash *gh, const void *key)
return e ? e->val : NULL;
}
-/**
- * A version of #BLI_ghash_lookup which accepts a fallback argument.
- */
void *BLI_ghash_lookup_default(const GHash *gh, const void *key, void *val_default)
{
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
@@ -817,16 +761,6 @@ void *BLI_ghash_lookup_default(const GHash *gh, const void *key, void *val_defau
return e ? e->val : val_default;
}
-/**
- * Lookup a pointer to the value of \a key in \a gh.
- *
- * \param key: The key to lookup.
- * \returns the pointer to value for \a key or NULL.
- *
- * \note This has 2 main benefits over #BLI_ghash_lookup.
- * - A NULL return always means that \a key isn't in \a gh.
- * - The value can be modified in-place without further function calls (faster).
- */
void **BLI_ghash_lookup_p(GHash *gh, const void *key)
{
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
@@ -834,20 +768,6 @@ void **BLI_ghash_lookup_p(GHash *gh, const void *key)
return e ? &e->val : NULL;
}
-/**
- * Ensure \a key is exists in \a gh.
- *
- * This handles the common situation where the caller needs ensure a key is added to \a gh,
- * constructing a new value in the case the key isn't found.
- * Otherwise use the existing value.
- *
- * Such situations typically incur multiple lookups, however this function
- * avoids them by ensuring the key is added,
- * returning a pointer to the value so it can be used or initialized by the caller.
- *
- * \returns true when the value didn't need to be added.
- * (when false, the caller _must_ initialize the value).
- */
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val)
{
const uint hash = ghash_keyhash(gh, key);
@@ -864,12 +784,6 @@ bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val)
return haskey;
}
-/**
- * A version of #BLI_ghash_ensure_p that allows caller to re-assign the key.
- * Typically used when the key is to be duplicated.
- *
- * \warning Caller _must_ write to \a r_key when returning false.
- */
bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val)
{
const uint hash = ghash_keyhash(gh, key);
@@ -889,14 +803,6 @@ bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_
return haskey;
}
-/**
- * Remove \a key from \a gh, or return false if the key wasn't found.
- *
- * \param key: The key to remove.
- * \param keyfreefp: Optional callback to free the key.
- * \param valfreefp: Optional callback to free the value.
- * \return true if \a key was removed from \a gh.
- */
bool BLI_ghash_remove(GHash *gh,
const void *key,
GHashKeyFreeFP keyfreefp,
@@ -912,17 +818,11 @@ bool BLI_ghash_remove(GHash *gh,
return false;
}
-/* same as above but return the value,
- * no free value argument since it will be returned */
-/**
- * Remove \a key from \a gh, returning the value or NULL if the key wasn't found.
- *
- * \param key: The key to remove.
- * \param keyfreefp: Optional callback to free the key.
- * \return the value of \a key int \a gh or NULL.
- */
void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp)
{
+ /* Same as above but return the value,
+ * no free value argument since it will be returned. */
+
const uint hash = ghash_keyhash(gh, key);
const uint bucket_index = ghash_bucket_index(gh, hash);
GHashEntry *e = (GHashEntry *)ghash_remove_ex(gh, key, keyfreefp, NULL, bucket_index);
@@ -935,23 +835,11 @@ void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp)
return NULL;
}
-/**
- * \return true if the \a key is in \a gh.
- */
bool BLI_ghash_haskey(const GHash *gh, const void *key)
{
return (ghash_lookup_entry(gh, key) != NULL);
}
-/**
- * Remove a random entry from \a gh, returning true
- * if a key/value pair could be removed, false otherwise.
- *
- * \param r_key: The removed key.
- * \param r_val: The removed value.
- * \param state: Used for efficient removal.
- * \return true if there was something to pop, false if ghash was already empty.
- */
bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
{
GHashEntry *e = (GHashEntry *)ghash_pop(gh, state);
@@ -970,13 +858,6 @@ bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
return false;
}
-/**
- * Reset \a gh clearing all entries.
- *
- * \param keyfreefp: Optional callback to free the key.
- * \param valfreefp: Optional callback to free the value.
- * \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
- */
void BLI_ghash_clear_ex(GHash *gh,
GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp,
@@ -990,21 +871,11 @@ void BLI_ghash_clear_ex(GHash *gh,
BLI_mempool_clear_ex(gh->entrypool, nentries_reserve ? (int)nentries_reserve : -1);
}
-/**
- * Wraps #BLI_ghash_clear_ex with zero entries reserved.
- */
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
BLI_ghash_clear_ex(gh, keyfreefp, valfreefp, 0);
}
-/**
- * Frees the GHash and its members.
- *
- * \param gh: The GHash to free.
- * \param keyfreefp: Optional callback to free the key.
- * \param valfreefp: Optional callback to free the value.
- */
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
BLI_assert((int)gh->nentries == BLI_mempool_len(gh->entrypool));
@@ -1017,17 +888,11 @@ void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreef
MEM_freeN(gh);
}
-/**
- * Sets a GHash flag.
- */
void BLI_ghash_flag_set(GHash *gh, uint flag)
{
gh->flag |= flag;
}
-/**
- * Clear a GHash flag.
- */
void BLI_ghash_flag_clear(GHash *gh, uint flag)
{
gh->flag &= ~flag;
@@ -1039,14 +904,6 @@ void BLI_ghash_flag_clear(GHash *gh, uint flag)
/** \name GHash Iterator API
* \{ */
-/**
- * Create a new GHashIterator. The hash table must not be mutated
- * while the iterator is in use, and the iterator will step exactly
- * #BLI_ghash_len(gh) times before becoming done.
- *
- * \param gh: The GHash to iterate over.
- * \return Pointer to a new iterator.
- */
GHashIterator *BLI_ghashIterator_new(GHash *gh)
{
GHashIterator *ghi = MEM_mallocN(sizeof(*ghi), "ghash iterator");
@@ -1054,14 +911,6 @@ GHashIterator *BLI_ghashIterator_new(GHash *gh)
return ghi;
}
-/**
- * Init an already allocated GHashIterator. The hash table must not
- * be mutated while the iterator is in use, and the iterator will
- * step exactly #BLI_ghash_len(gh) times before becoming done.
- *
- * \param ghi: The GHashIterator to initialize.
- * \param gh: The GHash to iterate over.
- */
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
{
ghi->gh = gh;
@@ -1078,11 +927,6 @@ void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
}
}
-/**
- * Steps the iterator to the next index.
- *
- * \param ghi: The iterator.
- */
void BLI_ghashIterator_step(GHashIterator *ghi)
{
if (ghi->curEntry) {
@@ -1097,11 +941,6 @@ void BLI_ghashIterator_step(GHashIterator *ghi)
}
}
-/**
- * Free a GHashIterator.
- *
- * \param ghi: The iterator to free.
- */
void BLI_ghashIterator_free(GHashIterator *ghi)
{
MEM_freeN(ghi);
@@ -1111,9 +950,8 @@ void BLI_ghashIterator_free(GHashIterator *ghi)
/* -------------------------------------------------------------------- */
/** \name GSet Public API
- *
- * Use ghash API to give 'set' functionality
* \{ */
+
GSet *BLI_gset_new_ex(GSetHashFP hashfp,
GSetCmpFP cmpfp,
const char *info,
@@ -1127,9 +965,6 @@ GSet *BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info)
return BLI_gset_new_ex(hashfp, cmpfp, info, 0);
}
-/**
- * Copy given GSet. Keys are also copied if callback is provided, else pointers remain the same.
- */
GSet *BLI_gset_copy(const GSet *gs, GHashKeyCopyFP keycopyfp)
{
return (GSet *)ghash_copy((const GHash *)gs, keycopyfp, NULL);
@@ -1140,10 +975,6 @@ uint BLI_gset_len(const GSet *gs)
return ((GHash *)gs)->nentries;
}
-/**
- * Adds the key to the set (no checks for unique keys!).
- * Matching #BLI_ghash_insert
- */
void BLI_gset_insert(GSet *gs, void *key)
{
const uint hash = ghash_keyhash((GHash *)gs, key);
@@ -1151,23 +982,11 @@ void BLI_gset_insert(GSet *gs, void *key)
ghash_insert_ex_keyonly((GHash *)gs, key, bucket_index);
}
-/**
- * A version of BLI_gset_insert which checks first if the key is in the set.
- * \returns true if a new key has been added.
- *
- * \note GHash has no equivalent to this because typically the value would be different.
- */
bool BLI_gset_add(GSet *gs, void *key)
{
return ghash_insert_safe_keyonly((GHash *)gs, key, false, NULL);
}
-/**
- * Set counterpart to #BLI_ghash_ensure_p_ex.
- * similar to BLI_gset_add, except it returns the key pointer.
- *
- * \warning Caller _must_ write to \a r_key when returning false.
- */
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
{
const uint hash = ghash_keyhash((GHash *)gs, key);
@@ -1186,23 +1005,11 @@ bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
return haskey;
}
-/**
- * Adds the key to the set (duplicates are managed).
- * Matching #BLI_ghash_reinsert
- *
- * \returns true if a new key has been added.
- */
bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp)
{
return ghash_insert_safe_keyonly((GHash *)gs, key, true, keyfreefp);
}
-/**
- * Replaces the key to the set if it's found.
- * Matching #BLI_ghash_replace_key
- *
- * \returns The old key or NULL if not found.
- */
void *BLI_gset_replace_key(GSet *gs, void *key)
{
return BLI_ghash_replace_key((GHash *)gs, key);
@@ -1218,13 +1025,6 @@ bool BLI_gset_haskey(const GSet *gs, const void *key)
return (ghash_lookup_entry((const GHash *)gs, key) != NULL);
}
-/**
- * Remove a random entry from \a gs, returning true if a key could be removed, false otherwise.
- *
- * \param r_key: The removed key.
- * \param state: Used for efficient removal.
- * \return true if there was something to pop, false if gset was already empty.
- */
bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key)
{
GSetEntry *e = (GSetEntry *)ghash_pop((GHash *)gs, (GHashIterState *)state);
@@ -1274,19 +1074,12 @@ void BLI_gset_flag_clear(GSet *gs, uint flag)
* This can be useful when the key references data stored outside the GSet.
* \{ */
-/**
- * Returns the pointer to the key if it's found.
- */
void *BLI_gset_lookup(const GSet *gs, const void *key)
{
Entry *e = ghash_lookup_entry((const GHash *)gs, key);
return e ? e->key : NULL;
}
-/**
- * Returns the pointer to the key if it's found, removing it from the GSet.
- * \note Caller must handle freeing.
- */
void *BLI_gset_pop_key(GSet *gs, const void *key)
{
const uint hash = ghash_keyhash((GHash *)gs, key);
@@ -1308,9 +1101,6 @@ void *BLI_gset_pop_key(GSet *gs, const void *key)
#include "BLI_math.h"
-/**
- * \return number of buckets in the GHash.
- */
int BLI_ghash_buckets_len(const GHash *gh)
{
return (int)gh->nbuckets;
@@ -1320,13 +1110,6 @@ int BLI_gset_buckets_len(const GSet *gs)
return BLI_ghash_buckets_len((const GHash *)gs);
}
-/**
- * Measure how well the hash function performs (1.0 is approx as good as random distribution),
- * and return a few other stats like load,
- * variance of the distribution of the entries in the buckets, etc.
- *
- * Smaller is better!
- */
double BLI_ghash_calc_quality_ex(GHash *gh,
double *r_load,
double *r_variance,
diff --git a/source/blender/blenlib/intern/BLI_ghash_utils.c b/source/blender/blenlib/intern/BLI_ghash_utils.c
index b9144009304..f8e621e406c 100644
--- a/source/blender/blenlib/intern/BLI_ghash_utils.c
+++ b/source/blender/blenlib/intern/BLI_ghash_utils.c
@@ -46,9 +46,10 @@ uint BLI_ghashutil_ptrhash(const void *key)
return (uint)(intptr_t)key;
}
#else
-/* Based Python3.7's pointer hashing function. */
uint BLI_ghashutil_ptrhash(const void *key)
{
+ /* Based Python3.7's pointer hashing function. */
+
size_t y = (size_t)key;
/* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid
* excessive hash collisions for dicts and sets */
@@ -134,15 +135,6 @@ size_t BLI_ghashutil_combine_hash(size_t hash_a, size_t hash_b)
return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
}
-/**
- * This function implements the widely used "djb" hash apparently posted
- * by Daniel Bernstein to comp.lang.c some time ago. The 32 bit
- * unsigned hash value starts at 5381 and for each byte 'c' in the
- * string, is updated: `hash = hash * 33 + c`.
- * This function uses the signed value of each byte.
- *
- * NOTE: this is the same hash method that glib 2.34.0 uses.
- */
uint BLI_ghashutil_strhash_n(const char *key, size_t n)
{
const signed char *p;
diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c
index a221820d4c4..efa0110ed53 100644
--- a/source/blender/blenlib/intern/BLI_heap.c
+++ b/source/blender/blenlib/intern/BLI_heap.c
@@ -193,11 +193,6 @@ static void heap_node_free(Heap *heap, HeapNode *node)
/** \name Public Heap API
* \{ */
-/**
- * Creates a new heap. Removed nodes are recycled, so memory usage will not shrink.
- *
- * \note Use when the size of the heap is known in advance.
- */
Heap *BLI_heap_new_ex(uint tot_reserve)
{
Heap *heap = MEM_mallocN(sizeof(Heap), __func__);
@@ -261,10 +256,6 @@ void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp)
heap->nodes.free = NULL;
}
-/**
- * Insert heap node with a value (often a 'cost') and pointer into the heap,
- * duplicate values are allowed.
- */
HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
{
HeapNode *node;
@@ -289,9 +280,6 @@ HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
return node;
}
-/**
- * Convenience function since this is a common pattern.
- */
void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr)
{
if (*node_p == NULL) {
@@ -312,19 +300,11 @@ uint BLI_heap_len(const Heap *heap)
return heap->size;
}
-/**
- * Return the top node of the heap.
- * This is the node with the lowest value.
- */
HeapNode *BLI_heap_top(const Heap *heap)
{
return heap->tree[0];
}
-/**
- * Return the value of top node of the heap.
- * This is the node with the lowest value.
- */
float BLI_heap_top_value(const Heap *heap)
{
BLI_assert(heap->size != 0);
@@ -332,9 +312,6 @@ float BLI_heap_top_value(const Heap *heap)
return heap->tree[0]->value;
}
-/**
- * Pop the top node off the heap and return its pointer.
- */
void *BLI_heap_pop_min(Heap *heap)
{
BLI_assert(heap->size != 0);
@@ -366,11 +343,6 @@ void BLI_heap_remove(Heap *heap, HeapNode *node)
BLI_heap_pop_min(heap);
}
-/**
- * Can be used to avoid #BLI_heap_remove, #BLI_heap_insert calls,
- * balancing the tree still has a performance cost,
- * but is often much less than remove/insert, difference is most noticeable with large heaps.
- */
void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value)
{
if (value < node->value) {
@@ -427,9 +399,6 @@ static bool heap_is_minheap(const Heap *heap, uint root)
}
return true;
}
-/**
- * Only for checking internal errors (gtest).
- */
bool BLI_heap_is_valid(const Heap *heap)
{
return heap_is_minheap(heap, 0);
diff --git a/source/blender/blenlib/intern/BLI_heap_simple.c b/source/blender/blenlib/intern/BLI_heap_simple.c
index c075a2f8643..f285dd074c3 100644
--- a/source/blender/blenlib/intern/BLI_heap_simple.c
+++ b/source/blender/blenlib/intern/BLI_heap_simple.c
@@ -147,11 +147,6 @@ static void heapsimple_up(HeapSimple *heap, uint i, float active_val, void *acti
/** \name Public HeapSimple API
* \{ */
-/**
- * Creates a new simple heap, which only supports insertion and removal from top.
- *
- * \note Use when the size of the heap is known in advance.
- */
HeapSimple *BLI_heapsimple_new_ex(uint tot_reserve)
{
HeapSimple *heap = MEM_mallocN(sizeof(HeapSimple), __func__);
@@ -190,10 +185,6 @@ void BLI_heapsimple_clear(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp)
heap->size = 0;
}
-/**
- * Insert heap node with a value (often a 'cost') and pointer into the heap,
- * duplicate values are allowed.
- */
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr)
{
if (UNLIKELY(heap->size >= heap->bufsize)) {
@@ -214,9 +205,6 @@ uint BLI_heapsimple_len(const HeapSimple *heap)
return heap->size;
}
-/**
- * Return the lowest value of the heap.
- */
float BLI_heapsimple_top_value(const HeapSimple *heap)
{
BLI_assert(heap->size != 0);
@@ -224,9 +212,6 @@ float BLI_heapsimple_top_value(const HeapSimple *heap)
return heap->tree[0].value;
}
-/**
- * Pop the top node off the heap and return its pointer.
- */
void *BLI_heapsimple_pop_min(HeapSimple *heap)
{
BLI_assert(heap->size != 0);
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 674654c99a8..64c2ce2a4a3 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -867,9 +867,6 @@ static void non_recursive_bvh_div_nodes(const BVHTree *tree,
/** \name BLI_bvhtree API
* \{ */
-/**
- * \note many callers don't check for `NULL` return.
- */
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
{
BVHTree *tree;
@@ -1013,7 +1010,6 @@ void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoin
bvhtree_node_inflate(tree, node, tree->epsilon);
}
-/* call before BLI_bvhtree_update_tree() */
bool BLI_bvhtree_update_node(
BVHTree *tree, int index, const float co[3], const float co_moving[3], int numpoints)
{
@@ -1038,9 +1034,6 @@ bool BLI_bvhtree_update_node(
return true;
}
-/**
- * Call #BLI_bvhtree_update_node() first for every node/point/triangle.
- */
void BLI_bvhtree_update_tree(BVHTree *tree)
{
/* Update bottom=>top
@@ -1054,18 +1047,11 @@ void BLI_bvhtree_update_tree(BVHTree *tree)
node_join(tree, *index);
}
}
-/**
- * Number of times #BLI_bvhtree_insert has been called.
- * mainly useful for asserts functions to check we added the correct number.
- */
int BLI_bvhtree_get_len(const BVHTree *tree)
{
return tree->totleaf;
}
-/**
- * Maximum number of children that a node can have.
- */
int BLI_bvhtree_get_tree_type(const BVHTree *tree)
{
return tree->tree_type;
@@ -1076,9 +1062,6 @@ float BLI_bvhtree_get_epsilon(const BVHTree *tree)
return tree->epsilon;
}
-/**
- * This function returns the bounding box of the BVH tree.
- */
void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3])
{
BVHNode *root = tree->nodes[tree->totleaf];
@@ -1264,11 +1247,6 @@ static bool tree_overlap_traverse_num(BVHOverlapData_Thread *data_thread,
return false;
}
-/**
- * Use to check the total number of threads #BLI_bvhtree_overlap will use.
- *
- * \warning Must be the first tree passed to #BLI_bvhtree_overlap!
- */
int BLI_bvhtree_overlap_thread_num(const BVHTree *tree)
{
return (int)MIN2(tree->tree_type, tree->nodes[tree->totleaf]->totnode);
@@ -1717,10 +1695,6 @@ static bool dfs_find_duplicate_fast_dfs(BVHNearestData *data, BVHNode *node)
return false;
}
-/**
- * Find the first node nearby.
- * Favors speed over quality since it doesn't find the best target node.
- */
int BLI_bvhtree_find_nearest_first(BVHTree *tree,
const float co[3],
const float dist_sq,
@@ -2020,15 +1994,6 @@ float BLI_bvhtree_bb_raycast(const float bv[6],
return dist;
}
-/**
- * Calls the callback for every ray intersection
- *
- * \note Using a \a callback which resets or never sets the #BVHTreeRayHit index & dist works too,
- * however using this function means existing generic callbacks can be used from custom callbacks
- * without having to handle resetting the hit beforehand.
- * It also avoid redundant argument and return value which aren't meaningful
- * when collecting multiple hits.
- */
void BLI_bvhtree_ray_cast_all_ex(BVHTree *tree,
const float co[3],
const float dir[3],
@@ -2395,18 +2360,6 @@ static bool bvhtree_walk_dfs_recursive(BVHTree_WalkData *walk_data, const BVHNod
return true;
}
-/**
- * This is a generic function to perform a depth first search on the #BVHTree
- * where the search order and nodes traversed depend on callbacks passed in.
- *
- * \param tree: Tree to walk.
- * \param walk_parent_cb: Callback on a parents bound-box to test if it should be traversed.
- * \param walk_leaf_cb: Callback to test leaf nodes, callback must store its own result,
- * returning false exits early.
- * \param walk_order_cb: Callback that indicates which direction to search,
- * either from the node with the lower or higher K-DOP axis value.
- * \param userdata: Argument passed to all callbacks.
- */
void BLI_bvhtree_walk_dfs(BVHTree *tree,
BVHTree_WalkParentCallback walk_parent_cb,
BVHTree_WalkLeafCallback walk_leaf_cb,
diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c
index 4cac526088b..765d2f0be55 100644
--- a/source/blender/blenlib/intern/BLI_linklist.c
+++ b/source/blender/blenlib/intern/BLI_linklist.c
@@ -100,10 +100,6 @@ void BLI_linklist_reverse(LinkNode **listp)
*listp = rhead;
}
-/**
- * Move an item from its current position to a new one inside a single-linked list.
- * Note *listp may be modified.
- */
void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index)
{
LinkNode *lnk, *lnk_psrc = NULL, *lnk_pdst = NULL;
@@ -171,9 +167,6 @@ void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index)
}
}
-/**
- * A version of prepend that takes the allocated link.
- */
void BLI_linklist_prepend_nlink(LinkNode **listp, void *ptr, LinkNode *nlink)
{
nlink->link = ptr;
@@ -199,9 +192,6 @@ void BLI_linklist_prepend_pool(LinkNode **listp, void *ptr, BLI_mempool *mempool
BLI_linklist_prepend_nlink(listp, ptr, nlink);
}
-/**
- * A version of append that takes the allocated link.
- */
void BLI_linklist_append_nlink(LinkNodePair *list_pair, void *ptr, LinkNode *nlink)
{
nlink->link = ptr;
diff --git a/source/blender/blenlib/intern/BLI_memarena.c b/source/blender/blenlib/intern/BLI_memarena.c
index 0ab27a5adad..f1fc3bba4ea 100644
--- a/source/blender/blenlib/intern/BLI_memarena.c
+++ b/source/blender/blenlib/intern/BLI_memarena.c
@@ -179,16 +179,6 @@ void *BLI_memarena_calloc(MemArena *ma, size_t size)
return ptr;
}
-/**
- * Transfer ownership of allocated blocks from `ma_src` into `ma_dst`,
- * cleaning the contents of `ma_src`.
- *
- * \note Useful for multi-threaded tasks that need a thread-local #MemArena
- * that is kept after the multi-threaded operation is completed.
- *
- * \note Avoid accumulating memory pools where possible
- * as any unused memory in `ma_src` is wasted every merge.
- */
void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src)
{
/* Memory arenas must be compatible. */
@@ -231,10 +221,6 @@ void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src)
VALGRIND_CREATE_MEMPOOL(ma_src, 0, false);
}
-/**
- * Clear for reuse, avoids re-allocation when an arena may
- * otherwise be free'd and recreated.
- */
void BLI_memarena_clear(MemArena *ma)
{
if (ma->bufs) {
diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c
index 2fbdfbe8a95..4e9d68d92e4 100644
--- a/source/blender/blenlib/intern/BLI_memblock.c
+++ b/source/blender/blenlib/intern/BLI_memblock.c
@@ -99,8 +99,6 @@ void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback)
MEM_freeN(mblk);
}
-/* Reset elem count to 0 but keep as much memory allocated needed for at least the previous elem
- * count. */
void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP free_callback)
{
int elem_per_chunk = mblk->chunk_size / mblk->elem_size;
@@ -191,9 +189,6 @@ void *BLI_memblock_iterstep(BLI_memblock_iter *iter)
return ptr;
}
-/* Direct access. elem is element index inside the chosen chunk.
- * Double usage: You can set chunk to 0 and set the absolute elem index.
- * The correct chunk will be retrieve. */
void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem)
{
BLI_assert(chunk < mblk->chunk_len);
diff --git a/source/blender/blenlib/intern/BLI_memiter.c b/source/blender/blenlib/intern/BLI_memiter.c
index effbe5da5c4..98348fe2938 100644
--- a/source/blender/blenlib/intern/BLI_memiter.c
+++ b/source/blender/blenlib/intern/BLI_memiter.c
@@ -125,15 +125,6 @@ static void memiter_init(BLI_memiter *mi)
/** \name Public API's
* \{ */
-/**
- * \param chunk_size_min: Should be a power of two and
- * significantly larger than the average element size used.
- *
- * While allocations of any size are supported, they won't be efficient
- * (effectively becoming a single-linked list).
- *
- * Its intended that many elements can be stored per chunk.
- */
BLI_memiter *BLI_memiter_create(uint chunk_size_min)
{
BLI_memiter *mi = MEM_mallocN(sizeof(BLI_memiter), "BLI_memiter");
@@ -261,7 +252,6 @@ uint BLI_memiter_count(const BLI_memiter *mi)
/** \name Helper API's
* \{ */
-/* Support direct lookup for first. */
void *BLI_memiter_elem_first(BLI_memiter *mi)
{
if (mi->head != NULL) {
diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c
index f968799326a..df85d3e7553 100644
--- a/source/blender/blenlib/intern/BLI_mempool.c
+++ b/source/blender/blenlib/intern/BLI_mempool.c
@@ -126,7 +126,7 @@ struct BLI_mempool {
uint flag;
/* keeps aligned to 16 bits */
- /** Free element list. Interleaved into chunk datas. */
+ /** Free element list. Interleaved into chunk data. */
BLI_freenode *free;
/** Use to know how many chunks to keep for #BLI_mempool_clear. */
uint maxchunks;
@@ -367,11 +367,6 @@ void *BLI_mempool_calloc(BLI_mempool *pool)
return retval;
}
-/**
- * Free an element from the mempool.
- *
- * \note doesn't protect against double frees, take care!
- */
void BLI_mempool_free(BLI_mempool *pool, void *addr)
{
BLI_freenode *newhead = addr;
@@ -475,13 +470,6 @@ void *BLI_mempool_findelem(BLI_mempool *pool, uint index)
return NULL;
}
-/**
- * Fill in \a data with pointers to each element of the mempool,
- * to create lookup table.
- *
- * \param pool: Pool to create a table from.
- * \param data: array of pointers at least the size of 'pool->totused'
- */
void BLI_mempool_as_table(BLI_mempool *pool, void **data)
{
BLI_mempool_iter iter;
@@ -495,9 +483,6 @@ void BLI_mempool_as_table(BLI_mempool *pool, void **data)
BLI_assert((uint)(p - data) == pool->totused);
}
-/**
- * A version of #BLI_mempool_as_table that allocates and returns the data.
- */
void **BLI_mempool_as_tableN(BLI_mempool *pool, const char *allocstr)
{
void **data = MEM_mallocN((size_t)pool->totused * sizeof(void *), allocstr);
@@ -505,9 +490,6 @@ void **BLI_mempool_as_tableN(BLI_mempool *pool, const char *allocstr)
return data;
}
-/**
- * Fill in \a data with the contents of the mempool.
- */
void BLI_mempool_as_array(BLI_mempool *pool, void *data)
{
const uint esize = pool->esize;
@@ -522,9 +504,6 @@ void BLI_mempool_as_array(BLI_mempool *pool, void *data)
BLI_assert((uint)(p - (char *)data) == pool->totused * esize);
}
-/**
- * A version of #BLI_mempool_as_array that allocates and returns the data.
- */
void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr)
{
char *data = MEM_malloc_arrayN(pool->totused, pool->esize, allocstr);
@@ -532,9 +511,6 @@ void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr)
return data;
}
-/**
- * Initialize a new mempool iterator, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
- */
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter)
{
BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER);
@@ -550,19 +526,6 @@ static void mempool_threadsafe_iternew(BLI_mempool *pool, BLI_mempool_threadsafe
ts_iter->curchunk_threaded_shared = NULL;
}
-/**
- * Initialize an array of mempool iterators, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
- *
- * This is used in threaded code, to generate as much iterators as needed
- * (each task should have its own),
- * such that each iterator goes over its own single chunk,
- * and only getting the next chunk to iterate over has to be
- * protected against concurrency (which can be done in a lockless way).
- *
- * To be used when creating a task for each single item in the pool is totally overkill.
- *
- * See BLI_task_parallel_mempool implementation for detailed usage example.
- */
ParallelMempoolTaskData *mempool_iter_threadsafe_create(BLI_mempool *pool, const size_t num_iter)
{
BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER);
@@ -625,13 +588,8 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
return ret;
}
-#else
-
-/* optimized version of code above */
+#else /* Optimized version of code above. */
-/**
- * Step over the iterator, returning the mempool item or NULL.
- */
void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
{
if (UNLIKELY(iter->curchunk == NULL)) {
@@ -660,11 +618,6 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
return ret;
}
-/**
- * A version of #BLI_mempool_iterstep that uses
- * #BLI_mempool_threadsafe_iter.curchunk_threaded_shared for threaded iteration support.
- * (threaded section noted in comments).
- */
void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *ts_iter)
{
BLI_mempool_iter *iter = &ts_iter->iter;
@@ -710,12 +663,6 @@ void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *ts_iter)
#endif
-/**
- * Empty the pool, as if it were just created.
- *
- * \param pool: The pool to clear.
- * \param totelem_reserve: Optionally reserve how many items should be kept from clearing.
- */
void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve)
{
BLI_mempool_chunk *mpchunk;
@@ -768,17 +715,11 @@ void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve)
}
}
-/**
- * Wrap #BLI_mempool_clear_ex with no reserve set.
- */
void BLI_mempool_clear(BLI_mempool *pool)
{
BLI_mempool_clear_ex(pool, -1);
}
-/**
- * Free the mempool its self (and all elements).
- */
void BLI_mempool_destroy(BLI_mempool *pool)
{
mempool_chunk_free_all(pool->chunks);
diff --git a/source/blender/blenlib/intern/BLI_mempool_private.h b/source/blender/blenlib/intern/BLI_mempool_private.h
index e1c8205c80c..03b0b11297b 100644
--- a/source/blender/blenlib/intern/BLI_mempool_private.h
+++ b/source/blender/blenlib/intern/BLI_mempool_private.h
@@ -41,10 +41,29 @@ typedef struct ParallelMempoolTaskData {
TaskParallelTLS tls;
} ParallelMempoolTaskData;
-ParallelMempoolTaskData *mempool_iter_threadsafe_create(BLI_mempool *pool, const size_t num_iter)
- ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Initialize an array of mempool iterators, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
+ *
+ * This is used in threaded code, to generate as much iterators as needed
+ * (each task should have its own),
+ * such that each iterator goes over its own single chunk,
+ * and only getting the next chunk to iterate over has to be
+ * protected against concurrency (which can be done in a lock-less way).
+ *
+ * To be used when creating a task for each single item in the pool is totally overkill.
+ *
+ * See #BLI_task_parallel_mempool implementation for detailed usage example.
+ */
+ParallelMempoolTaskData *mempool_iter_threadsafe_create(BLI_mempool *pool,
+ size_t num_iter) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL();
void mempool_iter_threadsafe_destroy(ParallelMempoolTaskData *iter_arr) ATTR_NONNULL();
+/**
+ * A version of #BLI_mempool_iterstep that uses
+ * #BLI_mempool_threadsafe_iter.curchunk_threaded_shared for threaded iteration support.
+ * (threaded section noted in comments).
+ */
void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *iter);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/intern/DLRB_tree.c b/source/blender/blenlib/intern/DLRB_tree.c
index 436b9b8d782..66c394f5eb2 100644
--- a/source/blender/blenlib/intern/DLRB_tree.c
+++ b/source/blender/blenlib/intern/DLRB_tree.c
@@ -29,14 +29,12 @@
/* *********************************************** */
/* Tree API */
-/* Create a new tree, and initialize as necessary */
DLRBT_Tree *BLI_dlrbTree_new(void)
{
/* just allocate for now */
return MEM_callocN(sizeof(DLRBT_Tree), "DLRBT_Tree");
}
-/* Just zero out the pointers used */
void BLI_dlrbTree_init(DLRBT_Tree *tree)
{
if (tree == NULL) {
@@ -62,7 +60,6 @@ static void recursive_tree_free_nodes(DLRBT_Node *node)
MEM_freeN(node);
}
-/* Free the given tree's data but not the tree itself */
void BLI_dlrbTree_free(DLRBT_Tree *tree)
{
if (tree == NULL) {
@@ -109,7 +106,6 @@ static void linkedlist_sync_add_node(DLRBT_Tree *tree, DLRBT_Node *node)
linkedlist_sync_add_node(tree, node->right);
}
-/* Make sure the tree's Double-Linked list representation is valid */
void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree)
{
/* sanity checks */
@@ -127,7 +123,6 @@ void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree)
/* *********************************************** */
/* Tree Search Utilities */
-/* Find the node which matches or is the closest to the requested node */
DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
@@ -175,7 +170,6 @@ DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree,
return node;
}
-/* Find the node which exactly matches the required data */
DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
@@ -223,7 +217,6 @@ DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree,
return (found == 1) ? (node) : (NULL);
}
-/* Find the node which occurs immediately before the best matching node */
DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
@@ -254,7 +247,6 @@ DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree,
return NULL;
}
-/* Find the node which occurs immediately after the best matching node */
DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
@@ -285,7 +277,6 @@ DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree,
return NULL;
}
-/* Check whether there is a node matching the requested node */
short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data)
{
/* check if an exact search throws up anything... */
@@ -522,9 +513,6 @@ static void insert_check_3(DLRBT_Tree *tree, DLRBT_Node *node)
/* ----- */
-/* Balance the tree after the given element has been added to it
- * (using custom code, in the Binary Tree way).
- */
void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node)
{
/* sanity checks */
@@ -541,9 +529,6 @@ void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node)
/* ----- */
-/* Add the given data to the tree, and return the node added */
-/* NOTE: for duplicates, the update_cb is called (if available),
- * and the existing node is returned */
DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
DLRBT_NAlloc_FP new_cb,
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
index ee06d8b6347..825682736e8 100644
--- a/source/blender/blenlib/intern/array_store.c
+++ b/source/blender/blenlib/intern/array_store.c
@@ -439,7 +439,7 @@ static void bchunk_list_ensure_min_size_last(const BArrayInfo *info,
if (data_merge_len <= info->chunk_byte_size_max) {
/* we have enough space to merge */
- /* remove last from linklist */
+ /* Remove last from the linked-list. */
BLI_assert(chunk_list->chunk_refs.last != chunk_list->chunk_refs.first);
cref->prev->next = NULL;
chunk_list->chunk_refs.last = cref->prev;
@@ -1399,26 +1399,6 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info,
/** \name Main Array Storage API
* \{ */
-/**
- * Create a new array store, which can store any number of arrays
- * as long as their stride matches.
- *
- * \param stride: `sizeof()` each element,
- *
- * \note while a stride of `1` will always work,
- * its less efficient since duplicate chunks of memory will be searched
- * at positions unaligned with the array data.
- *
- * \param chunk_count: Number of elements to split each chunk into.
- * - A small value increases the ability to de-duplicate chunks,
- * but adds overhead by increasing the number of chunks to look up when searching for duplicates,
- * as well as some overhead constructing the original array again, with more calls to `memcpy`.
- * - Larger values reduce the *book keeping* overhead,
- * but increase the chance a small,
- * isolated change will cause a larger amount of data to be duplicated.
- *
- * \return A new array store, to be freed with #BLI_array_store_destroy.
- */
BArrayStore *BLI_array_store_create(uint stride, uint chunk_count)
{
BArrayStore *bs = MEM_callocN(sizeof(BArrayStore), __func__);
@@ -1472,9 +1452,6 @@ static void array_store_free_data(BArrayStore *bs)
}
}
-/**
- * Free the #BArrayStore, including all states and chunks.
- */
void BLI_array_store_destroy(BArrayStore *bs)
{
array_store_free_data(bs);
@@ -1486,9 +1463,6 @@ void BLI_array_store_destroy(BArrayStore *bs)
MEM_freeN(bs);
}
-/**
- * Clear all contents, allowing reuse of \a bs.
- */
void BLI_array_store_clear(BArrayStore *bs)
{
array_store_free_data(bs);
@@ -1506,9 +1480,6 @@ void BLI_array_store_clear(BArrayStore *bs)
/** \name BArrayStore Statistics
* \{ */
-/**
- * \return the total amount of memory that would be used by getting the arrays for all states.
- */
size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs)
{
size_t size_accum = 0;
@@ -1518,10 +1489,6 @@ size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs)
return size_accum;
}
-/**
- * \return the amount of memory used by all #BChunk.data
- * (duplicate chunks are only counted once).
- */
size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs)
{
size_t size_total = 0;
@@ -1541,18 +1508,6 @@ size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs)
/** \name BArrayState Access
* \{ */
-/**
- *
- * \param data: Data used to create
- * \param state_reference: The state to use as a reference when adding the new state,
- * typically this is the previous state,
- * however it can be any previously created state from this \a bs.
- *
- * \return The new state,
- * which is used by the caller as a handle to get back the contents of \a data.
- * This may be removed using #BLI_array_store_state_remove,
- * otherwise it will be removed with #BLI_array_store_destroy.
- */
BArrayState *BLI_array_store_state_add(BArrayStore *bs,
const void *data,
const size_t data_len,
@@ -1601,11 +1556,6 @@ BArrayState *BLI_array_store_state_add(BArrayStore *bs,
return state;
}
-/**
- * Remove a state and free any unused #BChunk data.
- *
- * The states can be freed in any order.
- */
void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state)
{
#ifdef USE_PARANOID_CHECKS
@@ -1618,18 +1568,11 @@ void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state)
MEM_freeN(state);
}
-/**
- * \return the expanded size of the array,
- * use this to know how much memory to allocate #BLI_array_store_state_data_get's argument.
- */
size_t BLI_array_store_state_size_get(BArrayState *state)
{
return state->chunk_list->total_size;
}
-/**
- * Fill in existing allocated memory with the contents of \a state.
- */
void BLI_array_store_state_data_get(BArrayState *state, void *data)
{
#ifdef USE_PARANOID_CHECKS
@@ -1648,9 +1591,6 @@ void BLI_array_store_state_data_get(BArrayState *state, void *data)
}
}
-/**
- * Allocate an array for \a state and return it.
- */
void *BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len)
{
void *data = MEM_mallocN(state->chunk_list->total_size, __func__);
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index 9a12a7442b7..36bd193810e 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -35,11 +35,6 @@
#include "BLI_array_utils.h"
-/**
- *In-place array reverse.
- *
- * Access via #BLI_array_reverse
- */
void _bli_array_reverse(void *arr_v, uint arr_len, size_t arr_stride)
{
const uint arr_stride_uint = (uint)arr_stride;
@@ -56,12 +51,6 @@ void _bli_array_reverse(void *arr_v, uint arr_len, size_t arr_stride)
}
}
-/**
- * In-place array wrap.
- * (rotate the array one step forward or backwards).
- *
- * Access via #BLI_array_wrap
- */
void _bli_array_wrap(void *arr_v, uint arr_len, size_t arr_stride, int dir)
{
char *arr = arr_v;
@@ -82,12 +71,6 @@ void _bli_array_wrap(void *arr_v, uint arr_len, size_t arr_stride, int dir)
}
}
-/**
- *In-place array permute.
- * (re-arrange elements based on an array of indices).
- *
- * Access via #BLI_array_wrap
- */
void _bli_array_permute(
void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp)
{
@@ -117,13 +100,6 @@ void _bli_array_permute(
}
}
-/**
- * In-place array de-duplication of an ordered array.
- *
- * \return The new length of the array.
- *
- * Access via #BLI_array_deduplicate_ordered
- */
uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride)
{
if (UNLIKELY(arr_len <= 1)) {
@@ -146,13 +122,6 @@ uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride)
return j + 1;
}
-/**
- * Find the first index of an item in an array.
- *
- * Access via #BLI_array_findindex
- *
- * \note Not efficient, use for error checks/asserts.
- */
int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p)
{
const char *arr_step = (const char *)arr;
@@ -164,9 +133,6 @@ int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const
return -1;
}
-/**
- * A version of #BLI_array_findindex that searches from the end of the list.
- */
int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p)
{
const char *arr_step = (const char *)arr + (arr_stride * arr_len);
@@ -205,22 +171,6 @@ void _bli_array_binary_or(
}
}
-/**
- * Utility function to iterate over contiguous items in an array.
- *
- * \param use_wrap: Detect contiguous ranges across the first/last points.
- * In this case the second index of \a span_step may be lower than the first,
- * which indicates the values are wrapped.
- * \param use_delimit_bounds: When false,
- * ranges that defined by the start/end indices are excluded.
- * This option has no effect when \a use_wrap is enabled.
- * \param test_fn: Function to test if the item should be included in the range.
- * \param user_data: User data for \a test_fn.
- * \param span_step: Indices to iterate over,
- * initialize both values to the array length to initialize iteration.
- * \param r_span_len: The length of the span, useful when \a use_wrap is enabled,
- * where calculating the length isn't a simple subtraction.
- */
bool _bli_array_iter_span(const void *arr,
uint arr_len,
size_t arr_stride,
@@ -330,9 +280,6 @@ bool _bli_array_iter_span(const void *arr,
return false;
}
-/**
- * Simple utility to check memory is zeroed.
- */
bool _bli_array_is_zeroed(const void *arr_v, uint arr_len, size_t arr_stride)
{
const char *arr_step = (const char *)arr_v;
@@ -345,13 +292,6 @@ bool _bli_array_is_zeroed(const void *arr_v, uint arr_len, size_t arr_stride)
return true;
}
-/**
- * Smart function to sample a rect spiraling outside.
- * Nice for selection ID.
- *
- * \param arr_shape: dimensions [w, h].
- * \param center: coordinates [x, y] indicating where to start traversing.
- */
bool _bli_array_iter_spiral_square(const void *arr_v,
const int arr_shape[2],
size_t elem_size,
diff --git a/source/blender/blenlib/intern/astar.c b/source/blender/blenlib/intern/astar.c
index 1f71a62d191..8347e00adc8 100644
--- a/source/blender/blenlib/intern/astar.c
+++ b/source/blender/blenlib/intern/astar.c
@@ -53,25 +53,11 @@
#include "BLI_astar.h"
-/**
- * Init a node in A* graph.
- *
- * \param custom_data: an opaque pointer attached to this link,
- * available e.g. to cost callback function.
- */
void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data)
{
as_graph->nodes[node_index].custom_data = custom_data;
}
-/**
- * Add a link between two nodes of our A* graph.
- *
- * \param cost: the 'length' of the link
- * (actual distance between two vertices or face centers e.g.).
- * \param custom_data: an opaque pointer attached to this link,
- * available e.g. to cost callback function.
- */
void BLI_astar_node_link_add(BLI_AStarGraph *as_graph,
const int node1_index,
const int node2_index,
@@ -93,22 +79,11 @@ void BLI_astar_node_link_add(BLI_AStarGraph *as_graph,
BLI_addtail(&(as_graph->nodes[node2_index].neighbor_links), &ld[1]);
}
-/**
- * \return The index of the other node of given link.
- */
int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, const int idx)
{
return (lnk->nodes[0] == idx) ? lnk->nodes[1] : lnk->nodes[0];
}
-/**
- * Initialize a solution data for given A* graph. Does not compute anything!
- *
- * \param custom_data: an opaque pointer attached to this link, available e.g
- * . to cost callback function.
- *
- * \note BLI_AStarSolution stores nearly all data needed during solution compute.
- */
void BLI_astar_solution_init(BLI_AStarGraph *as_graph,
BLI_AStarSolution *as_solution,
void *custom_data)
@@ -133,12 +108,6 @@ void BLI_astar_solution_init(BLI_AStarGraph *as_graph,
as_solution->g_steps = BLI_memarena_alloc(mem, sizeof(*as_solution->g_steps) * node_num);
}
-/**
- * Clear given solution's data, but does not release its memory. Avoids having to recreate/allocate
- * a memarena in loops, e.g.
- *
- * \note This *has to be called* between each path solving.
- */
void BLI_astar_solution_clear(BLI_AStarSolution *as_solution)
{
if (as_solution->mem) {
@@ -156,9 +125,6 @@ void BLI_astar_solution_clear(BLI_AStarSolution *as_solution)
as_solution->g_steps = NULL;
}
-/**
- * Release the memory allocated for this solution.
- */
void BLI_astar_solution_free(BLI_AStarSolution *as_solution)
{
if (as_solution->mem) {
@@ -167,14 +133,6 @@ void BLI_astar_solution_free(BLI_AStarSolution *as_solution)
}
}
-/**
- * Init an A* graph. Total number of nodes must be known.
- *
- * Nodes might be e.g. vertices, faces, ...
- *
- * \param custom_data: an opaque pointer attached to this link,
- * available e.g. to cost callback function.
- */
void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data)
{
MemArena *mem = as_graph->mem;
@@ -199,14 +157,6 @@ void BLI_astar_graph_free(BLI_AStarGraph *as_graph)
}
}
-/**
- * Solve a path in given graph, using given 'cost' callback function.
- *
- * \param max_steps: maximum number of nodes the found path may have.
- * Useful in performance-critical usages.
- * If no path is found within given steps, returns false too.
- * \return true if a path was found, false otherwise.
- */
bool BLI_astar_graph_solve(BLI_AStarGraph *as_graph,
const int node_index_src,
const int node_index_dst,
diff --git a/source/blender/blenlib/intern/bitmap.c b/source/blender/blenlib/intern/bitmap.c
index 54edcaec2c8..681736b7927 100644
--- a/source/blender/blenlib/intern/bitmap.c
+++ b/source/blender/blenlib/intern/bitmap.c
@@ -29,13 +29,11 @@
#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
-/** Set or clear all bits in the bitmap. */
void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits)
{
memset(bitmap, set ? UCHAR_MAX : 0, BLI_BITMAP_SIZE(bits));
}
-/** Invert all bits in the bitmap. */
void BLI_bitmap_flip_all(BLI_bitmap *bitmap, size_t bits)
{
size_t num_blocks = _BITMAP_NUM_BLOCKS(bits);
@@ -44,13 +42,11 @@ void BLI_bitmap_flip_all(BLI_bitmap *bitmap, size_t bits)
}
}
-/** Copy all bits from one bitmap to another. */
void BLI_bitmap_copy_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
{
memcpy(dst, src, BLI_BITMAP_SIZE(bits));
}
-/** Combine two bitmaps with boolean AND. */
void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
{
size_t num_blocks = _BITMAP_NUM_BLOCKS(bits);
@@ -59,7 +55,6 @@ void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
}
}
-/** Combine two bitmaps with boolean OR. */
void BLI_bitmap_or_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
{
size_t num_blocks = _BITMAP_NUM_BLOCKS(bits);
diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c
index b0afe1349ad..670ea75e9ea 100644
--- a/source/blender/blenlib/intern/bitmap_draw_2d.c
+++ b/source/blender/blenlib/intern/bitmap_draw_2d.c
@@ -41,11 +41,6 @@
/** \name Draw Line
* \{ */
-/**
- * Plot a line from \a p1 to \a p2 (inclusive).
- *
- * \note For clipped line drawing, see: http://stackoverflow.com/a/40902741/432509
- */
void BLI_bitmap_draw_2d_line_v2v2i(const int p1[2],
const int p2[2],
bool (*callback)(int, int, void *),
@@ -223,9 +218,6 @@ static void draw_tri_flat_min(const int p[2],
}
}
-/**
- * \note Unclipped (clipped version can be added if needed).
- */
void BLI_bitmap_draw_2d_tri_v2i(
/* all 2d */
const int p1[2],
@@ -338,18 +330,6 @@ static int draw_poly_v2i_n__span_y_sort(const void *a_p, const void *b_p, void *
return 0;
}
-/**
- * Draws a filled polygon with support for self intersections.
- *
- * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive),
- * note that \a x_end will always be greater than \a x, so we can use:
- *
- * \code{.c}
- * do {
- * func(x, y);
- * } while (++x != x_end);
- * \endcode
- */
void BLI_bitmap_draw_2d_poly_v2i_n(const int xmin,
const int ymin,
const int xmax,
diff --git a/source/blender/blenlib/intern/boxpack_2d.c b/source/blender/blenlib/intern/boxpack_2d.c
index 4a07f1134d0..5d35feee699 100644
--- a/source/blender/blenlib/intern/boxpack_2d.c
+++ b/source/blender/blenlib/intern/boxpack_2d.c
@@ -120,6 +120,7 @@ static float box_ymax_get(const BoxPack *box)
{
return box->v[TR]->y;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -165,6 +166,7 @@ static void box_ymax_set(BoxPack *box, const float f)
box->v[TR]->y = f;
box_v34y_update(box);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -275,22 +277,9 @@ static int vertex_sort(const void *p1, const void *p2, void *vs_ctx_p)
}
return 0;
}
+
/** \} */
-/**
- * Main box-packing function accessed from other functions
- * This sets boxes x,y to positive values, sorting from 0,0 outwards.
- * There is no limit to the space boxes may take, only that they will be packed
- * tightly into the lower left hand corner (0,0)
- *
- * \param boxarray: a pre-allocated array of boxes.
- * only the 'box->x' and 'box->y' are set, 'box->w' and 'box->h' are used,
- * 'box->index' is not used at all, the only reason its there
- * is that the box array is sorted by area and programs need to be able
- * to have some way of writing the boxes back to the original data.
- * \param len: the number of boxes in the array.
- * \param r_tot_x, r_tot_y: set so you can normalize the data.
- */
void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r_tot_y)
{
uint box_index, verts_pack_len, i, j, k;
@@ -516,7 +505,7 @@ void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r
* flag verts on one or both of the boxes
* as being used by checking the width or
* height of both boxes */
- if (vert->tlb && vert->trb && (box == vert->tlb || box == vert->trb)) {
+ if (vert->tlb && vert->trb && (ELEM(box, vert->tlb, vert->trb))) {
if (UNLIKELY(fabsf(vert->tlb->h - vert->trb->h) < EPSILON_MERGE)) {
#ifdef USE_MERGE
# define A (vert->trb->v[TL])
@@ -547,7 +536,7 @@ void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r
vert->tlb->v[TR]->free &= ~(TRF | BRF);
}
}
- else if (vert->blb && vert->brb && (box == vert->blb || box == vert->brb)) {
+ else if (vert->blb && vert->brb && (ELEM(box, vert->blb, vert->brb))) {
if (UNLIKELY(fabsf(vert->blb->h - vert->brb->h) < EPSILON_MERGE)) {
#ifdef USE_MERGE
# define A (vert->blb->v[BR])
@@ -579,7 +568,7 @@ void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r
}
}
/* Horizontal */
- if (vert->tlb && vert->blb && (box == vert->tlb || box == vert->blb)) {
+ if (vert->tlb && vert->blb && (ELEM(box, vert->tlb, vert->blb))) {
if (UNLIKELY(fabsf(vert->tlb->w - vert->blb->w) < EPSILON_MERGE)) {
#ifdef USE_MERGE
# define A (vert->blb->v[TL])
@@ -610,7 +599,7 @@ void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r
vert->tlb->v[BL]->free &= ~(BLF | BRF);
}
}
- else if (vert->trb && vert->brb && (box == vert->trb || box == vert->brb)) {
+ else if (vert->trb && vert->brb && (ELEM(box, vert->trb, vert->brb))) {
if (UNLIKELY(fabsf(vert->trb->w - vert->brb->w) < EPSILON_MERGE)) {
#ifdef USE_MERGE
@@ -678,18 +667,6 @@ void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r
MEM_freeN(vs_ctx.vertarray);
}
-/* Packs boxes into a fixed area.
- * boxes and packed are linked lists containing structs that can be cast to
- * FixedSizeBoxPack (i.e. contains a FixedSizeBoxPack as its first element).
- * Boxes that were packed successfully are placed into *packed and removed from *boxes.
- *
- * The algorithm is a simplified version of https://github.com/TeamHypersomnia/rectpack2D.
- * Better ones could be used, but for the current use case (packing Image tiles into GPU
- * textures) this is fine.
- *
- * Note that packing efficiency depends on the order of the input boxes. Generally speaking,
- * larger boxes should come first, though how exactly size is best defined (e.g. area,
- * perimeter) depends on the particular application. */
void BLI_box_pack_2d_fixedarea(ListBase *boxes, int width, int height, ListBase *packed)
{
ListBase spaces = {NULL};
diff --git a/source/blender/blenlib/intern/buffer.c b/source/blender/blenlib/intern/buffer.c
index 74e97d89430..9df32051281 100644
--- a/source/blender/blenlib/intern/buffer.c
+++ b/source/blender/blenlib/intern/buffer.c
@@ -86,11 +86,6 @@ void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count)
buffer->count = new_count;
}
-/**
- * Similar to #BLI_buffer_resize, but use when the existing data can be:
- * - Ignored (malloc'd)
- * - Cleared (when BLI_BUFFER_USE_CALLOC is set)
- */
void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count)
{
if (UNLIKELY(new_count > buffer->alloc_count)) {
@@ -114,7 +109,6 @@ void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count)
buffer->count = new_count;
}
-/* Callers use BLI_buffer_append_array. */
void _bli_buffer_append_array(BLI_Buffer *buffer, void *new_data, size_t count)
{
size_t size = buffer->count;
@@ -124,7 +118,6 @@ void _bli_buffer_append_array(BLI_Buffer *buffer, void *new_data, size_t count)
memcpy(bytes + size * buffer->elem_size, new_data, count * buffer->elem_size);
}
-/* callers use BLI_buffer_free */
void _bli_buffer_free(BLI_Buffer *buffer)
{
if ((buffer->flag & BLI_BUFFER_USE_STATIC) == 0) {
diff --git a/source/blender/blenlib/intern/convexhull_2d.c b/source/blender/blenlib/intern/convexhull_2d.c
index 233a1430fe7..df675b512d9 100644
--- a/source/blender/blenlib/intern/convexhull_2d.c
+++ b/source/blender/blenlib/intern/convexhull_2d.c
@@ -53,14 +53,6 @@ static float is_left(const float p0[2], const float p1[2], const float p2[2])
return (p1[0] - p0[0]) * (p2[1] - p0[1]) - (p2[0] - p0[0]) * (p1[1] - p0[1]);
}
-/**
- * A.M. Andrew's monotone chain 2D convex hull algorithm
- *
- * \param points: An array of 2D points presorted by increasing x and y-coords.
- * \param n: The number of points in points.
- * \param r_points: An array of the convex hull vertex indices (max is n).
- * \returns the number of points in r_points.
- */
int BLI_convexhull_2d_sorted(const float (*points)[2], const int n, int r_points[])
{
/* the output array r_points[] will be used as the stack */
@@ -182,16 +174,6 @@ static int pointref_cmp_yx(const void *a_, const void *b_)
return 0;
}
-/**
- * A.M. Andrew's monotone chain 2D convex hull algorithm
- *
- * \param points: An array of 2D points.
- * \param n: The number of points in points.
- * \param r_points: An array of the convex hull vertex indices (max is n).
- * _must_ be allocated as `n * 2` because of how its used internally,
- * even though the final result will be no more than \a n in size.
- * \returns the number of points in r_points.
- */
int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[])
{
struct PointRef *points_ref = MEM_mallocN(sizeof(*points_ref) * (size_t)n, __func__);
@@ -234,16 +216,6 @@ int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[])
/** \name Utility Convex-Hull Functions
* \{ */
-/**
- * \return The best angle for fitting the convex hull to an axis aligned bounding box.
- *
- * Intended to be used with #BLI_convexhull_2d
- *
- * \param points_hull: Ordered hull points
- * (result of #BLI_convexhull_2d mapped to a contiguous array).
- *
- * \note we could return the index of the best edge too if its needed.
- */
float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned int n)
{
unsigned int i, i_prev;
@@ -291,11 +263,6 @@ float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned in
return (area_best != FLT_MAX) ? atan2f(dvec_best[0], dvec_best[1]) : 0.0f;
}
-/**
- * Wrap #BLI_convexhull_aabb_fit_hull_2d and do the convex hull calculation.
- *
- * \param points: arbitrary 2d points.
- */
float BLI_convexhull_aabb_fit_points_2d(const float (*points)[2], unsigned int n)
{
int *index_map;
diff --git a/source/blender/blenlib/intern/delaunay_2d.cc b/source/blender/blenlib/intern/delaunay_2d.cc
index 4582ea69d9b..842e6cb6135 100644
--- a/source/blender/blenlib/intern/delaunay_2d.cc
+++ b/source/blender/blenlib/intern/delaunay_2d.cc
@@ -25,11 +25,10 @@
#include <sstream>
#include "BLI_array.hh"
-#include "BLI_double2.hh"
#include "BLI_linklist.h"
#include "BLI_math_boolean.hh"
#include "BLI_math_mpq.hh"
-#include "BLI_mpq2.hh"
+#include "BLI_math_vec_mpq_types.hh"
#include "BLI_set.hh"
#include "BLI_task.hh"
#include "BLI_vector.hh"
@@ -38,6 +37,8 @@
namespace blender::meshintersect {
+using namespace blender::math;
+
/* Throughout this file, template argument T will be an
* arithmetic-like type, like float, double, or mpq_class. */
@@ -788,11 +789,11 @@ bool in_line<mpq_class>(const FatCo<mpq_class> &a,
}
vec2<mpq_class> exact_ab = b.exact - a.exact;
vec2<mpq_class> exact_ac = c.exact - a.exact;
- if (vec2<mpq_class>::dot(exact_ab, exact_ac) < 0) {
+ if (dot(exact_ab, exact_ac) < 0) {
return false;
}
vec2<mpq_class> exact_bc = c.exact - b.exact;
- return vec2<mpq_class>::dot(exact_bc, exact_ac) >= 0;
+ return dot(exact_bc, exact_ac) >= 0;
}
#endif
@@ -801,11 +802,11 @@ bool in_line<double>(const FatCo<double> &a, const FatCo<double> &b, const FatCo
{
vec2<double> ab = b.approx - a.approx;
vec2<double> ac = c.approx - a.approx;
- if (vec2<double>::dot(ab, ac) < 0) {
+ if (dot(ab, ac) < 0) {
return false;
}
vec2<double> bc = c.approx - b.approx;
- return vec2<double>::dot(bc, ac) >= 0;
+ return dot(bc, ac) >= 0;
}
template<> CDTVert<double>::CDTVert(const vec2<double> &pt)
@@ -1081,7 +1082,7 @@ template<typename T> CDTEdge<T> *CDTArrangement<T>::split_edge(SymEdge<T> *se, T
SymEdge<T> *sesymprev = prev(sesym);
SymEdge<T> *sesymprevsym = sym(sesymprev);
SymEdge<T> *senext = se->next;
- CDTVert<T> *v = this->add_vert(vec2<T>::interpolate(*a, *b, lambda));
+ CDTVert<T> *v = this->add_vert(interpolate(*a, *b, lambda));
CDTEdge<T> *e = this->add_edge(v, se->next->vert, se->face, sesym->face);
sesym->vert = v;
SymEdge<T> *newse = &e->symedges[0];
@@ -1704,16 +1705,16 @@ void fill_crossdata_for_intersect(const FatCo<T> &curco,
BLI_assert(se_vcva->vert == vc && se_vcva->next->vert == va);
BLI_assert(se_vcvb->vert == vc && se_vcvb->next->vert == vb);
UNUSED_VARS_NDEBUG(vc);
- auto isect = vec2<T>::isect_seg_seg(va->co.exact, vb->co.exact, curco.exact, v2->co.exact);
+ auto isect = isect_seg_seg<vec2<T>>(va->co.exact, vb->co.exact, curco.exact, v2->co.exact);
T &lambda = isect.lambda;
switch (isect.kind) {
- case vec2<T>::isect_result::LINE_LINE_CROSS: {
+ case isect_result<vec2<T>>::LINE_LINE_CROSS: {
#ifdef WITH_GMP
if (!std::is_same<T, mpq_class>::value) {
#else
if (true) {
#endif
- double len_ab = vec2<double>::distance(va->co.approx, vb->co.approx);
+ double len_ab = distance(va->co.approx, vb->co.approx);
if (lambda * len_ab <= epsilon) {
fill_crossdata_for_through_vert(va, se_vcva, cd, cd_next);
}
@@ -1735,7 +1736,7 @@ void fill_crossdata_for_intersect(const FatCo<T> &curco,
}
break;
}
- case vec2<T>::isect_result::LINE_LINE_EXACT: {
+ case isect_result<vec2<T>>::LINE_LINE_EXACT: {
if (lambda == 0) {
fill_crossdata_for_through_vert(va, se_vcva, cd, cd_next);
}
@@ -1750,7 +1751,7 @@ void fill_crossdata_for_intersect(const FatCo<T> &curco,
}
break;
}
- case vec2<T>::isect_result::LINE_LINE_NONE: {
+ case isect_result<vec2<T>>::LINE_LINE_NONE: {
#ifdef WITH_GMP
if (std::is_same<T, mpq_class>::value) {
BLI_assert(false);
@@ -1766,9 +1767,9 @@ void fill_crossdata_for_intersect(const FatCo<T> &curco,
}
break;
}
- case vec2<T>::isect_result::LINE_LINE_COLINEAR: {
- if (vec2<double>::distance_squared(va->co.approx, v2->co.approx) <=
- vec2<double>::distance_squared(vb->co.approx, v2->co.approx)) {
+ case isect_result<vec2<T>>::LINE_LINE_COLINEAR: {
+ if (distance_squared(va->co.approx, v2->co.approx) <=
+ distance_squared(vb->co.approx, v2->co.approx)) {
fill_crossdata_for_through_vert(va, se_vcva, cd, cd_next);
}
else {
@@ -1845,7 +1846,7 @@ void get_next_crossing_from_edge(CrossData<T> *cd,
{
CDTVert<T> *va = cd->in->vert;
CDTVert<T> *vb = cd->in->next->vert;
- vec2<T> curco = vec2<T>::interpolate(va->co.exact, vb->co.exact, cd->lambda);
+ vec2<T> curco = interpolate(va->co.exact, vb->co.exact, cd->lambda);
FatCo<T> fat_curco(curco);
SymEdge<T> *se_ac = sym(cd->in)->next;
CDTVert<T> *vc = se_ac->next->vert;
@@ -2274,8 +2275,8 @@ void add_face_constraints(CDT_state<T> *cdt_state,
* making valid BMesh faces. */
int id = cdt_state->need_ids ? f : 0;
add_face_ids(cdt_state, face_symedge0, id, fedge_start, fedge_end);
- if (cdt_state->need_ids || (output_type == CDT_CONSTRAINTS_VALID_BMESH ||
- output_type == CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES)) {
+ if (cdt_state->need_ids ||
+ ELEM(output_type, CDT_CONSTRAINTS_VALID_BMESH, CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES)) {
add_face_ids(cdt_state, face_symedge0, f, fedge_start, fedge_end);
}
}
@@ -2386,7 +2387,7 @@ template<typename T> void remove_non_constraint_edges_leave_valid_bmesh(CDT_stat
dissolvable_edges[i].e = e;
const vec2<double> &co1 = e->symedges[0].vert->co.approx;
const vec2<double> &co2 = e->symedges[1].vert->co.approx;
- dissolvable_edges[i].len_squared = vec2<double>::distance_squared(co1, co2);
+ dissolvable_edges[i].len_squared = distance_squared(co1, co2);
i++;
}
}
@@ -2569,18 +2570,18 @@ template<typename T> void detect_holes(CDT_state<T> *cdt_state)
if (e->symedges[0].face->visit_index == e->symedges[1].face->visit_index) {
continue; /* Don't count hits on edges between faces in same region. */
}
- auto isect = vec2<T>::isect_seg_seg(ray_end.exact,
+ auto isect = isect_seg_seg<vec2<T>>(ray_end.exact,
mid.exact,
e->symedges[0].vert->co.exact,
e->symedges[1].vert->co.exact);
switch (isect.kind) {
- case vec2<T>::isect_result::LINE_LINE_CROSS: {
+ case isect_result<vec2<T>>::LINE_LINE_CROSS: {
hits++;
break;
}
- case vec2<T>::isect_result::LINE_LINE_EXACT:
- case vec2<T>::isect_result::LINE_LINE_NONE:
- case vec2<T>::isect_result::LINE_LINE_COLINEAR:
+ case isect_result<vec2<T>>::LINE_LINE_EXACT:
+ case isect_result<vec2<T>>::LINE_LINE_NONE:
+ case isect_result<vec2<T>>::LINE_LINE_COLINEAR:
break;
}
}
diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c
index f95619803bf..d8e59b6f6ee 100644
--- a/source/blender/blenlib/intern/edgehash.c
+++ b/source/blender/blenlib/intern/edgehash.c
@@ -230,8 +230,8 @@ EdgeHash *BLI_edgehash_new_ex(const char *info, const uint reserve)
UPDATE_SLOT_MASK(eh);
eh->length = 0;
eh->dummy_count = 0;
- eh->entries = MEM_calloc_arrayN(sizeof(EdgeHashEntry), ENTRIES_CAPACITY(eh), "eh entries");
- eh->map = MEM_malloc_arrayN(sizeof(int32_t), MAP_CAPACITY(eh), "eh map");
+ eh->entries = MEM_calloc_arrayN(ENTRIES_CAPACITY(eh), sizeof(EdgeHashEntry), "eh entries");
+ eh->map = MEM_malloc_arrayN(MAP_CAPACITY(eh), sizeof(int32_t), "eh map");
CLEAR_MAP(eh);
return eh;
}
@@ -272,10 +272,6 @@ void BLI_edgehash_print(EdgeHash *eh)
}
}
-/**
- * Insert edge (\a v0, \a v1) into hash with given value, does
- * not check for duplicates.
- */
void BLI_edgehash_insert(EdgeHash *eh, uint v0, uint v1, void *value)
{
edgehash_ensure_can_insert(eh);
@@ -283,9 +279,6 @@ void BLI_edgehash_insert(EdgeHash *eh, uint v0, uint v1, void *value)
edgehash_insert(eh, edge, value);
}
-/**
- * Assign a new value to a key that may already be in edgehash.
- */
bool BLI_edgehash_reinsert(EdgeHash *eh, uint v0, uint v1, void *value)
{
Edge edge = init_edge(v0, v1);
@@ -307,51 +300,24 @@ bool BLI_edgehash_reinsert(EdgeHash *eh, uint v0, uint v1, void *value)
}
}
-/**
- * A version of #BLI_edgehash_lookup which accepts a fallback argument.
- */
void *BLI_edgehash_lookup_default(const EdgeHash *eh, uint v0, uint v1, void *default_value)
{
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
return entry ? entry->value : default_value;
}
-/**
- * Return value for given edge (\a v0, \a v1), or NULL if
- * if key does not exist in hash. (If need exists
- * to differentiate between key-value being NULL and
- * lack of key then see #BLI_edgehash_lookup_p().
- */
void *BLI_edgehash_lookup(const EdgeHash *eh, uint v0, uint v1)
{
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
return entry ? entry->value : NULL;
}
-/**
- * Return pointer to value for given edge (\a v0, \a v1),
- * or NULL if key does not exist in hash.
- */
void **BLI_edgehash_lookup_p(EdgeHash *eh, uint v0, uint v1)
{
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
return entry ? &entry->value : NULL;
}
-/**
- * Ensure \a (v0, v1) is exists in \a eh.
- *
- * This handles the common situation where the caller needs ensure a key is added to \a eh,
- * constructing a new value in the case the key isn't found.
- * Otherwise use the existing value.
- *
- * Such situations typically incur multiple lookups, however this function
- * avoids them by ensuring the key is added,
- * returning a pointer to the value so it can be used or initialized by the caller.
- *
- * \returns true when the value didn't need to be added.
- * (when false, the caller _must_ initialize the value).
- */
bool BLI_edgehash_ensure_p(EdgeHash *eh, uint v0, uint v1, void ***r_value)
{
Edge edge = init_edge(v0, v1);
@@ -373,13 +339,6 @@ bool BLI_edgehash_ensure_p(EdgeHash *eh, uint v0, uint v1, void ***r_value)
}
}
-/**
- * Remove \a key (v0, v1) from \a eh, or return false if the key wasn't found.
- *
- * \param v0, v1: The key to remove.
- * \param free_value: Optional callback to free the value.
- * \return true if \a key was removed from \a eh.
- */
bool BLI_edgehash_remove(EdgeHash *eh, uint v0, uint v1, EdgeHashFreeFP free_value)
{
uint old_length = eh->length;
@@ -390,16 +349,11 @@ bool BLI_edgehash_remove(EdgeHash *eh, uint v0, uint v1, EdgeHashFreeFP free_val
return old_length > eh->length;
}
-/* same as above but return the value,
- * no free value argument since it will be returned */
-/**
- * Remove \a key (v0, v1) from \a eh, returning the value or NULL if the key wasn't found.
- *
- * \param v0, v1: The key to remove.
- * \return the value of \a key int \a eh or NULL.
- */
void *BLI_edgehash_popkey(EdgeHash *eh, uint v0, uint v1)
{
+ /* Same as #BLI_edgehash_remove but return the value,
+ * no free value argument since it will be returned */
+
Edge edge = init_edge(v0, v1);
ITER_SLOTS (eh, edge, slot, index) {
@@ -420,25 +374,16 @@ void *BLI_edgehash_popkey(EdgeHash *eh, uint v0, uint v1)
}
}
-/**
- * Return boolean true/false if edge (v0,v1) in hash.
- */
bool BLI_edgehash_haskey(const EdgeHash *eh, uint v0, uint v1)
{
return edgehash_lookup_entry(eh, v0, v1) != NULL;
}
-/**
- * Return number of keys in hash.
- */
int BLI_edgehash_len(const EdgeHash *eh)
{
return (int)eh->length;
}
-/**
- * Remove all edges from hash.
- */
void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint UNUSED(reserve))
{
/* TODO: handle reserve */
@@ -449,9 +394,6 @@ void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint U
CLEAR_MAP(eh);
}
-/**
- * Wraps #BLI_edgehash_clear_ex with zero entries reserved.
- */
void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value)
{
BLI_edgehash_clear_ex(eh, free_value, 0);
@@ -463,11 +405,6 @@ void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value)
/** \name Edge Hash Iterator API
* \{ */
-/**
- * Create a new EdgeHashIterator. The hash table must not be mutated
- * while the iterator is in use, and the iterator will step exactly
- * BLI_edgehash_len(eh) times before becoming done.
- */
EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh)
{
EdgeHashIterator *ehi = MEM_mallocN(sizeof(EdgeHashIterator), __func__);
@@ -475,14 +412,6 @@ EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh)
return ehi;
}
-/**
- * Init an already allocated EdgeHashIterator. The hash table must not
- * be mutated while the iterator is in use, and the iterator will
- * step exactly BLI_edgehash_len(eh) times before becoming done.
- *
- * \param ehi: The EdgeHashIterator to initialize.
- * \param eh: The EdgeHash to iterate over.
- */
void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh)
{
ehi->entries = eh->entries;
@@ -490,9 +419,6 @@ void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh)
ehi->index = 0;
}
-/**
- * Free an EdgeHashIterator.
- */
void BLI_edgehashIterator_free(EdgeHashIterator *ehi)
{
MEM_freeN(ehi);
@@ -515,8 +441,8 @@ EdgeSet *BLI_edgeset_new_ex(const char *info, const uint reserve)
es->capacity_exp = calc_capacity_exp_for_reserve(reserve);
UPDATE_SLOT_MASK(es);
es->length = 0;
- es->entries = MEM_malloc_arrayN(sizeof(Edge), ENTRIES_CAPACITY(es), "es entries");
- es->map = MEM_malloc_arrayN(sizeof(int32_t), MAP_CAPACITY(es), "es map");
+ es->entries = MEM_malloc_arrayN(ENTRIES_CAPACITY(es), sizeof(Edge), "es entries");
+ es->map = MEM_malloc_arrayN(MAP_CAPACITY(es), sizeof(int32_t), "es map");
CLEAR_MAP(es);
return es;
}
@@ -569,12 +495,6 @@ BLI_INLINE void edgeset_insert_at_slot(EdgeSet *es, uint slot, Edge edge)
es->length++;
}
-/**
- * A version of BLI_edgeset_insert which checks first if the key is in the set.
- * \returns true if a new key has been added.
- *
- * \note EdgeHash has no equivalent to this because typically the value would be different.
- */
bool BLI_edgeset_add(EdgeSet *es, uint v0, uint v1)
{
edgeset_ensure_can_insert(es);
@@ -591,10 +511,6 @@ bool BLI_edgeset_add(EdgeSet *es, uint v0, uint v1)
}
}
-/**
- * Adds the key to the set (no checks for unique keys!).
- * Matching #BLI_edgehash_insert
- */
void BLI_edgeset_insert(EdgeSet *es, uint v0, uint v1)
{
edgeset_ensure_can_insert(es);
diff --git a/source/blender/blenlib/intern/expr_pylike_eval.c b/source/blender/blenlib/intern/expr_pylike_eval.c
index 4d1ba190c14..c6be8836229 100644
--- a/source/blender/blenlib/intern/expr_pylike_eval.c
+++ b/source/blender/blenlib/intern/expr_pylike_eval.c
@@ -124,7 +124,6 @@ struct ExprPyLike_Parsed {
/** \name Public API
* \{ */
-/** Free the parsed data; NULL argument is ok. */
void BLI_expr_pylike_free(ExprPyLike_Parsed *expr)
{
if (expr != NULL) {
@@ -132,19 +131,16 @@ void BLI_expr_pylike_free(ExprPyLike_Parsed *expr)
}
}
-/** Check if the parsing result is valid for evaluation. */
bool BLI_expr_pylike_is_valid(ExprPyLike_Parsed *expr)
{
return expr != NULL && expr->ops_count > 0;
}
-/** Check if the parsed expression always evaluates to the same value. */
bool BLI_expr_pylike_is_constant(ExprPyLike_Parsed *expr)
{
return expr != NULL && expr->ops_count == 1 && expr->ops[0].opcode == OPCODE_CONST;
}
-/** Check if the parsed expression uses the parameter with the given index. */
bool BLI_expr_pylike_is_using_param(ExprPyLike_Parsed *expr, int index)
{
int i;
@@ -168,10 +164,6 @@ bool BLI_expr_pylike_is_using_param(ExprPyLike_Parsed *expr, int index)
/** \name Stack Machine Evaluation
* \{ */
-/**
- * Evaluate the expression with the given parameters.
- * The order and number of parameters must match the names given to parse.
- */
eExprPyLike_EvalStatus BLI_expr_pylike_eval(ExprPyLike_Parsed *expr,
const double *param_values,
int param_values_len,
@@ -653,7 +645,7 @@ static bool parse_add_func(ExprParseState *state, eOpCode code, int args, void *
/* Extract the next token from raw characters. */
static bool parse_next_token(ExprParseState *state)
{
- /* Skip whitespace. */
+ /* Skip white-space. */
while (isspace(*state->cur)) {
state->cur++;
}
@@ -1073,12 +1065,6 @@ static bool parse_expr(ExprParseState *state)
/** \name Main Parsing Function
* \{ */
-/**
- * Compile the expression and return the result.
- *
- * Parse the expression for evaluation later.
- * Returns non-NULL even on failure; use is_valid to check.
- */
ExprPyLike_Parsed *BLI_expr_pylike_parse(const char *expression,
const char **param_names,
int param_names_len)
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index 88fb67c5502..838644054af 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -30,8 +30,8 @@
#include <errno.h>
-#include "zlib.h"
-#include "zstd.h"
+#include <zlib.h>
+#include <zstd.h>
#ifdef WIN32
# include "BLI_fileops_types.h"
@@ -89,7 +89,7 @@ size_t BLI_file_zstd_from_mem_at_pos(
total_written += output.pos;
}
- /* Finalize the Zstd frame. */
+ /* Finalize the `Zstd` frame. */
size_t ret = 1;
while (ret != 0) {
ZSTD_outBuffer output = {out_buf, out_len, 0};
@@ -180,13 +180,6 @@ bool BLI_file_magic_is_zstd(const char header[4])
return false;
}
-/**
- * Returns true if the file with the specified name can be written.
- * This implementation uses access(2), which makes the check according
- * to the real UID and GID of the process, not its effective UID and GID.
- * This shouldn't matter for Blender, which is not going to run privileged
- * anyway.
- */
bool BLI_file_is_writable(const char *filename)
{
bool writable;
@@ -212,10 +205,6 @@ bool BLI_file_is_writable(const char *filename)
return writable;
}
-/**
- * Creates the file with nothing in it, or updates its last-modified date if it already exists.
- * Returns true if successful (like the unix touch command).
- */
bool BLI_file_touch(const char *file)
{
FILE *f = BLI_fopen(file, "r+b");
@@ -761,7 +750,7 @@ static int recursive_operation(const char *startfrom,
# endif
if (is_dir) {
- /* recursively dig into a subfolder */
+ /* Recurse into sub-directories. */
ret = recursive_operation(
from_path, to_path, callback_dir_pre, callback_file, callback_dir_post);
}
@@ -954,12 +943,6 @@ int BLI_access(const char *filename, int mode)
return access(filename, mode);
}
-/**
- * Deletes the specified file or directory (depending on dir), optionally
- * doing recursive delete of directory contents.
- *
- * \return zero on success (matching 'remove' behavior).
- */
int BLI_delete(const char *file, bool dir, bool recursive)
{
BLI_assert(!BLI_path_is_rel(file));
@@ -973,12 +956,6 @@ int BLI_delete(const char *file, bool dir, bool recursive)
return remove(file);
}
-/**
- * Soft deletes the specified file or directory (depending on dir) by moving the files to the
- * recycling bin, optionally doing recursive delete of directory contents.
- *
- * \return zero on success (matching 'remove' behavior).
- */
int BLI_delete_soft(const char *file, const char **error_message)
{
BLI_assert(!BLI_path_is_rel(file));
@@ -1251,7 +1228,6 @@ int BLI_create_symlink(const char *file, const char *to)
}
# endif
-/** \return true on success (i.e. given path now exists on FS), false otherwise. */
bool BLI_dir_create_recursive(const char *dirname)
{
char *lslash;
@@ -1301,9 +1277,6 @@ bool BLI_dir_create_recursive(const char *dirname)
return ret;
}
-/**
- * \return zero on success (matching 'rename' behavior).
- */
int BLI_rename(const char *from, const char *to)
{
if (!BLI_exists(from)) {
diff --git a/source/blender/blenlib/intern/fileops.cc b/source/blender/blenlib/intern/fileops.cc
new file mode 100644
index 00000000000..5ceedbd8cb5
--- /dev/null
+++ b/source/blender/blenlib/intern/fileops.cc
@@ -0,0 +1,51 @@
+/*
+ * 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 bli
+ */
+
+#include "BLI_fileops.hh"
+
+#ifdef WIN32
+# include "utfconv.h"
+#endif
+
+namespace blender {
+fstream::fstream(const char *filepath, std::ios_base::openmode mode)
+{
+ this->open(filepath, mode);
+}
+
+fstream::fstream(const std::string &filepath, std::ios_base::openmode mode)
+{
+ this->open(filepath, mode);
+}
+
+void fstream::open(StringRefNull filepath, ios_base::openmode mode)
+{
+#ifdef WIN32
+ const char *filepath_cstr = filepath.c_str();
+ UTF16_ENCODE(filepath_cstr);
+ std::wstring filepath_wstr(filepath_cstr_16);
+ std::fstream::open(filepath_wstr.c_str(), mode);
+ UTF16_UN_ENCODE(filepath_cstr);
+#else
+ std::fstream::open(filepath, mode);
+#endif
+}
+
+} // namespace blender
diff --git a/source/blender/blenlib/intern/filereader_gzip.c b/source/blender/blenlib/intern/filereader_gzip.c
index 72eb153a8b9..fe766e5da41 100644
--- a/source/blender/blenlib/intern/filereader_gzip.c
+++ b/source/blender/blenlib/intern/filereader_gzip.c
@@ -64,7 +64,7 @@ static ssize_t gzip_read(FileReader *reader, void *buffer, size_t size)
int ret = inflate(&gzip->strm, Z_NO_FLUSH);
- if (ret != Z_OK && ret != Z_BUF_ERROR) {
+ if (!ELEM(ret, Z_OK, Z_BUF_ERROR)) {
break;
}
}
diff --git a/source/blender/blenlib/intern/filereader_zstd.c b/source/blender/blenlib/intern/filereader_zstd.c
index 55ce32713d9..5a04f5b11f3 100644
--- a/source/blender/blenlib/intern/filereader_zstd.c
+++ b/source/blender/blenlib/intern/filereader_zstd.c
@@ -331,5 +331,8 @@ FileReader *BLI_filereader_new_zstd(FileReader *base)
}
zstd->reader.close = zstd_close;
+ /* Rewind after the seek table check so that zstd_read starts at the file's start. */
+ zstd->base->seek(zstd->base, 0, SEEK_SET);
+
return (FileReader *)zstd;
}
diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c
index ae34074e804..1bd99497432 100644
--- a/source/blender/blenlib/intern/gsqueue.c
+++ b/source/blender/blenlib/intern/gsqueue.c
@@ -101,9 +101,6 @@ static void queue_free_chunk(struct QueueChunk *data)
}
}
-/**
- * Free the queue's data and the queue itself
- */
void BLI_gsqueue_free(GSQueue *queue)
{
queue_free_chunk(queue->chunk_first);
@@ -111,14 +108,6 @@ void BLI_gsqueue_free(GSQueue *queue)
MEM_freeN(queue);
}
-/**
- * Copies the source value onto the end of the queue
- *
- * \note This copies #GSQueue.elem_size bytes from \a item,
- * (the pointer itself is not stored).
- *
- * \param item: source data to be copied to the queue.
- */
void BLI_gsqueue_push(GSQueue *queue, const void *item)
{
queue->chunk_last_index++;
@@ -153,12 +142,6 @@ void BLI_gsqueue_push(GSQueue *queue, const void *item)
memcpy(queue_get_last_elem(queue), item, queue->elem_size);
}
-/**
- * Retrieves and removes the first element from the queue.
- * The value is copies to \a r_item, which must be at least \a elem_size bytes.
- *
- * Does not reduce amount of allocated memory.
- */
void BLI_gsqueue_pop(GSQueue *queue, void *r_item)
{
BLI_assert(BLI_gsqueue_is_empty(queue) == false);
@@ -187,9 +170,6 @@ size_t BLI_gsqueue_len(const GSQueue *queue)
return queue->totelem;
}
-/**
- * Returns true if the queue is empty, false otherwise
- */
bool BLI_gsqueue_is_empty(const GSQueue *queue)
{
return (queue->chunk_first == NULL);
diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c
index 3db1b7df0fa..6a0ca8bb33f 100644
--- a/source/blender/blenlib/intern/hash_md5.c
+++ b/source/blender/blenlib/intern/hash_md5.c
@@ -284,11 +284,6 @@ static void *md5_read_ctx(const struct md5_ctx *ctx, void *resbuf)
/* Top level public functions. */
-/**
- * Compute MD5 message digest for bytes read from 'stream'.
- * The resulting message digest number will be written into the 16 bytes beginning at 'resblock'.
- * \return Non-zero if an error occurred.
- */
int BLI_hash_md5_stream(FILE *stream, void *resblock)
{
#define BLOCKSIZE 4096 /* Important: must be a multiple of 64. */
@@ -362,11 +357,6 @@ int BLI_hash_md5_stream(FILE *stream, void *resblock)
return 0;
}
-/**
- * Compute MD5 message digest for 'len' bytes beginning at 'buffer'.
- * The result is always in little endian byte order,
- * so that a byte-wise output yields to the wanted ASCII representation of the message digest.
- */
void *BLI_hash_md5_buffer(const char *buffer, size_t len, void *resblock)
{
struct md5_ctx ctx;
diff --git a/source/blender/blenlib/intern/hash_mm2a.c b/source/blender/blenlib/intern/hash_mm2a.c
index 0899491cd0d..a98ae083fc8 100644
--- a/source/blender/blenlib/intern/hash_mm2a.c
+++ b/source/blender/blenlib/intern/hash_mm2a.c
@@ -110,7 +110,6 @@ uint32_t BLI_hash_mm2a_end(BLI_HashMurmur2A *mm2)
return mm2->hash;
}
-/* Non-incremental version, quicker for small keys. */
uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed)
{
/* Initialize the hash to a 'random' value */
diff --git a/source/blender/blenlib/intern/index_mask.cc b/source/blender/blenlib/intern/index_mask.cc
index cba985b8a44..a73e6caf313 100644
--- a/source/blender/blenlib/intern/index_mask.cc
+++ b/source/blender/blenlib/intern/index_mask.cc
@@ -18,21 +18,11 @@
namespace blender {
-/**
- * Create a sub-mask that is also shifted to the beginning. The shifting to the beginning allows
- * code to work with smaller indices, which is more memory efficient.
- *
- * \return New index mask with the size of #slice. It is either empty or starts with 0. It might
- * reference indices that have been appended to #r_new_indices.
- *
- * Example:
- * this: [2, 3, 5, 7, 8, 9, 10]
- * slice: ^--------^
- * output: [0, 2, 4, 5]
- *
- * All the indices in the sub-mask are shifted by 3 towards zero, so that the first index in the
- * output is zero.
- */
+IndexMask IndexMask::slice(IndexRange slice) const
+{
+ return IndexMask(indices_.slice(slice));
+}
+
IndexMask IndexMask::slice_and_offset(const IndexRange slice, Vector<int64_t> &r_new_indices) const
{
const int slice_size = slice.size();
diff --git a/source/blender/blenlib/intern/kdtree_impl.h b/source/blender/blenlib/intern/kdtree_impl.h
index 0c9de0aa128..c0e740b39b3 100644
--- a/source/blender/blenlib/intern/kdtree_impl.h
+++ b/source/blender/blenlib/intern/kdtree_impl.h
@@ -190,7 +190,7 @@ static uint kdtree_balance(KDTreeNode *nodes, uint nodes_len, uint axis, const u
}
}
- /* set node and sort subnodes */
+ /* Set node and sort sub-nodes. */
node = &nodes[median];
node->d = axis;
axis = (axis + 1) % KD_DIMS;
@@ -594,7 +594,7 @@ int BLI_kdtree_nd_(find_nearest_n_with_len_squared_cb)(
int BLI_kdtree_nd_(find_nearest_n)(const KDTree *tree,
const float co[KD_DIMS],
KDTreeNearest r_nearest[],
- const uint nearest_len_capacity)
+ uint nearest_len_capacity)
{
return BLI_kdtree_nd_(find_nearest_n_with_len_squared_cb)(
tree, co, r_nearest, nearest_len_capacity, NULL, NULL);
@@ -726,7 +726,7 @@ int BLI_kdtree_nd_(range_search_with_len_squared_cb)(
int BLI_kdtree_nd_(range_search)(const KDTree *tree,
const float co[KD_DIMS],
KDTreeNearest **r_nearest,
- const float range)
+ float range)
{
return BLI_kdtree_nd_(range_search_with_len_squared_cb)(tree, co, r_nearest, range, NULL, NULL);
}
diff --git a/source/blender/blenlib/intern/lasso_2d.c b/source/blender/blenlib/intern/lasso_2d.c
index a3b111cf0f2..ee10a233d39 100644
--- a/source/blender/blenlib/intern/lasso_2d.c
+++ b/source/blender/blenlib/intern/lasso_2d.c
@@ -65,7 +65,6 @@ bool BLI_lasso_is_point_inside(const int mcoords[][2],
return isect_point_poly_v2_int(pt, mcoords, mcoords_len, true);
}
-/* edge version for lasso select. we assume boundbox check was done */
bool BLI_lasso_is_edge_inside(const int mcoords[][2],
const unsigned int mcoords_len,
int x0,
diff --git a/source/blender/blenlib/intern/list_sort_impl.h b/source/blender/blenlib/intern/list_sort_impl.h
index 680044f9ccb..626956e2fb6 100644
--- a/source/blender/blenlib/intern/list_sort_impl.h
+++ b/source/blender/blenlib/intern/list_sort_impl.h
@@ -34,7 +34,7 @@
* - `SORT_IMPL_LINKTYPE`:
* Struct type for sorting.
* - `SORT_IMPL_LINKTYPE_DATA`:
- * Data pointer or leave undefined to pass the link its self.
+ * Data pointer or leave undefined to pass the link itself.
* - `SORT_IMPL_FUNC`:
* Function name of the sort function.
*
@@ -202,7 +202,7 @@ BLI_INLINE list_node *sweep_up(struct SortInfo *si, list_node *list, unsigned in
}
/**
- * The 'ranks' array essentially captures the recursion stack of a mergesort.
+ * The 'ranks' array essentially captures the recursion stack of a merge-sort.
* The merge tree is built in a bottom-up manner. The control loop for
* updating the 'ranks' array is analogous to incrementing a binary integer,
* and the `O(n)` time for counting `upto` n translates to `O(n)` merges when
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index 1b16f6b0aee..513b08a589d 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -36,11 +36,6 @@
#include "BLI_strict_flags.h"
-/* implementation */
-
-/**
- * moves the entire contents of \a src onto the end of \a dst.
- */
void BLI_movelisttolist(ListBase *dst, ListBase *src)
{
if (src->first == NULL) {
@@ -59,9 +54,6 @@ void BLI_movelisttolist(ListBase *dst, ListBase *src)
src->first = src->last = NULL;
}
-/**
- * moves the entire contents of \a src at the beginning of \a dst.
- */
void BLI_movelisttolist_reverse(ListBase *dst, ListBase *src)
{
if (src->first == NULL) {
@@ -81,9 +73,6 @@ void BLI_movelisttolist_reverse(ListBase *dst, ListBase *src)
src->first = src->last = NULL;
}
-/**
- * Prepends \a vlink (assumed to begin with a Link) onto listbase.
- */
void BLI_addhead(ListBase *listbase, void *vlink)
{
Link *link = vlink;
@@ -104,9 +93,6 @@ void BLI_addhead(ListBase *listbase, void *vlink)
listbase->first = link;
}
-/**
- * Appends \a vlink (assumed to begin with a Link) onto listbase.
- */
void BLI_addtail(ListBase *listbase, void *vlink)
{
Link *link = vlink;
@@ -127,9 +113,6 @@ void BLI_addtail(ListBase *listbase, void *vlink)
listbase->last = link;
}
-/**
- * Removes \a vlink from \a listbase. Assumes it is linked into there!
- */
void BLI_remlink(ListBase *listbase, void *vlink)
{
Link *link = vlink;
@@ -153,9 +136,6 @@ void BLI_remlink(ListBase *listbase, void *vlink)
}
}
-/**
- * Checks that \a vlink is linked into listbase, removing it from there if so.
- */
bool BLI_remlink_safe(ListBase *listbase, void *vlink)
{
if (BLI_findindex(listbase, vlink) != -1) {
@@ -166,9 +146,6 @@ bool BLI_remlink_safe(ListBase *listbase, void *vlink)
return false;
}
-/**
- * Swaps \a vlinka and \a vlinkb in the list. Assumes they are both already in the list!
- */
void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
{
Link *linka = vlinka;
@@ -222,10 +199,6 @@ void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
}
}
-/**
- * Swaps \a vlinka and \a vlinkb from their respective lists.
- * Assumes they are both already in their \a listbasea!
- */
void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vlinka, void *vlinkb)
{
Link *linka = vlinka;
@@ -251,9 +224,6 @@ void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vli
BLI_remlink(listbasea, &linkc);
}
-/**
- * Removes the head from \a listbase and returns it.
- */
void *BLI_pophead(ListBase *listbase)
{
Link *link;
@@ -263,9 +233,6 @@ void *BLI_pophead(ListBase *listbase)
return link;
}
-/**
- * Removes the tail from \a listbase and returns it.
- */
void *BLI_poptail(ListBase *listbase)
{
Link *link;
@@ -275,9 +242,6 @@ void *BLI_poptail(ListBase *listbase)
return link;
}
-/**
- * Removes \a vlink from listbase and disposes of it. Assumes it is linked into there!
- */
void BLI_freelinkN(ListBase *listbase, void *vlink)
{
Link *link = vlink;
@@ -320,11 +284,6 @@ static void listbase_double_from_single(Link *iter, ListBase *listbase)
#undef SORT_IMPL_LINKTYPE
-/**
- * Sorts the elements of listbase into the order defined by cmp
- * (which should return 1 if its first arg should come after its second arg).
- * This uses insertion sort, so NOT ok for large list.
- */
void BLI_listbase_sort(ListBase *listbase, int (*cmp)(const void *, const void *))
{
if (listbase->first != listbase->last) {
@@ -345,10 +304,6 @@ void BLI_listbase_sort_r(ListBase *listbase,
}
}
-/**
- * Inserts \a vnewlink immediately following \a vprevlink in \a listbase.
- * Or, if \a vprevlink is NULL, puts \a vnewlink at the front of the list.
- */
void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
{
Link *prevlink = vprevlink;
@@ -388,10 +343,6 @@ void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
}
}
-/**
- * Inserts \a vnewlink immediately preceding \a vnextlink in listbase.
- * Or, if \a vnextlink is NULL, puts \a vnewlink at the end of the list.
- */
void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
{
Link *nextlink = vnextlink;
@@ -431,13 +382,6 @@ void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
}
}
-/**
- * Insert a link in place of another, without changing its position in the list.
- *
- * Puts `vnewlink` in the position of `vreplacelink`, removing `vreplacelink`.
- * - `vreplacelink` *must* be in the list.
- * - `vnewlink` *must not* be in the list.
- */
void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
{
Link *l_old = vreplacelink;
@@ -464,14 +408,6 @@ void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlin
}
}
-/**
- * Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move
- * item if new position would exceed list (could optionally move to head/tail).
- *
- * \param step: Absolute value defines step size, sign defines direction. E.g pass -1
- * to move \a vlink before previous, or 1 to move behind next.
- * \return If position of \a vlink has changed.
- */
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
{
Link *link = vlink;
@@ -503,11 +439,6 @@ bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
return true;
}
-/**
- * Move the link at the index \a from to the position at index \a to.
- *
- * \return If the move was successful.
- */
bool BLI_listbase_move_index(ListBase *listbase, int from, int to)
{
if (from == to) {
@@ -524,9 +455,6 @@ bool BLI_listbase_move_index(ListBase *listbase, int from, int to)
return BLI_listbase_link_move(listbase, link, to - from);
}
-/**
- * Removes and disposes of the entire contents of listbase using direct free(3).
- */
void BLI_freelist(ListBase *listbase)
{
Link *link, *next;
@@ -541,9 +469,6 @@ void BLI_freelist(ListBase *listbase)
BLI_listbase_clear(listbase);
}
-/**
- * Removes and disposes of the entire contents of \a listbase using guardedalloc.
- */
void BLI_freelistN(ListBase *listbase)
{
Link *link, *next;
@@ -558,11 +483,6 @@ void BLI_freelistN(ListBase *listbase)
BLI_listbase_clear(listbase);
}
-/**
- * Returns the number of elements in \a listbase, up until (and including count_max)
- *
- * \note Use to avoid redundant looping.
- */
int BLI_listbase_count_at_most(const ListBase *listbase, const int count_max)
{
Link *link;
@@ -575,9 +495,6 @@ int BLI_listbase_count_at_most(const ListBase *listbase, const int count_max)
return count;
}
-/**
- * Returns the number of elements in \a listbase.
- */
int BLI_listbase_count(const ListBase *listbase)
{
Link *link;
@@ -590,9 +507,6 @@ int BLI_listbase_count(const ListBase *listbase)
return count;
}
-/**
- * Returns the nth element of \a listbase, numbering from 0.
- */
void *BLI_findlink(const ListBase *listbase, int number)
{
Link *link = NULL;
@@ -608,9 +522,6 @@ void *BLI_findlink(const ListBase *listbase, int number)
return link;
}
-/**
- * Returns the nth-last element of \a listbase, numbering from 0.
- */
void *BLI_rfindlink(const ListBase *listbase, int number)
{
Link *link = NULL;
@@ -626,9 +537,6 @@ void *BLI_rfindlink(const ListBase *listbase, int number)
return link;
}
-/**
- * Returns the position of \a vlink within \a listbase, numbering from 0, or -1 if not found.
- */
int BLI_findindex(const ListBase *listbase, const void *vlink)
{
Link *link = NULL;
@@ -651,10 +559,6 @@ int BLI_findindex(const ListBase *listbase, const void *vlink)
return -1;
}
-/**
- * Finds the first element of \a listbase which contains the null-terminated
- * string \a id at the specified offset, returning NULL if not found.
- */
void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
{
Link *link = NULL;
@@ -674,13 +578,10 @@ void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
return NULL;
}
-/* same as above but find reverse */
-/**
- * Finds the last element of \a listbase which contains the
- * null-terminated string \a id at the specified offset, returning NULL if not found.
- */
void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset)
{
+ /* Same as #BLI_findstring but find reverse. */
+
Link *link = NULL;
const char *id_iter;
@@ -695,10 +596,6 @@ void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset
return NULL;
}
-/**
- * Finds the first element of \a listbase which contains a pointer to the
- * null-terminated string \a id at the specified offset, returning NULL if not found.
- */
void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int offset)
{
Link *link = NULL;
@@ -715,13 +612,10 @@ void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int off
return NULL;
}
-/* same as above but find reverse */
-/**
- * Finds the last element of \a listbase which contains a pointer to the
- * null-terminated string \a id at the specified offset, returning NULL if not found.
- */
void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int offset)
{
+ /* Same as #BLI_findstring_ptr but find reverse. */
+
Link *link = NULL;
const char *id_iter;
@@ -737,10 +631,6 @@ void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int of
return NULL;
}
-/**
- * Finds the first element of listbase which contains the specified pointer value
- * at the specified offset, returning NULL if not found.
- */
void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
{
Link *link = NULL;
@@ -757,13 +647,10 @@ void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
return NULL;
}
-/* same as above but find reverse */
-/**
- * Finds the last element of listbase which contains the specified pointer value
- * at the specified offset, returning NULL if not found.
- */
void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
{
+ /* Same as #BLI_findptr but find reverse. */
+
Link *link = NULL;
const void *ptr_iter;
@@ -779,10 +666,6 @@ void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
return NULL;
}
-/**
- * Finds the first element of listbase which contains the specified bytes
- * at the specified offset, returning NULL if not found.
- */
void *BLI_listbase_bytes_find(const ListBase *listbase,
const void *bytes,
const size_t bytes_size,
@@ -801,16 +684,13 @@ void *BLI_listbase_bytes_find(const ListBase *listbase,
return NULL;
}
-/* same as above but find reverse */
-/**
- * Finds the last element of listbase which contains the specified bytes
- * at the specified offset, returning NULL if not found.
- */
void *BLI_listbase_bytes_rfind(const ListBase *listbase,
const void *bytes,
const size_t bytes_size,
const int offset)
{
+ /* Same as #BLI_listbase_bytes_find but find reverse. */
+
Link *link = NULL;
const void *ptr_iter;
@@ -825,10 +705,30 @@ void *BLI_listbase_bytes_rfind(const ListBase *listbase,
return NULL;
}
-/**
- * Returns the 0-based index of the first element of listbase which contains the specified
- * null-terminated string at the specified offset, or -1 if not found.
- */
+void *BLI_listbase_string_or_index_find(const ListBase *listbase,
+ const char *string,
+ const size_t string_offset,
+ const int index)
+{
+ Link *link = NULL;
+ Link *link_at_index = NULL;
+
+ int index_iter;
+ for (link = listbase->first, index_iter = 0; link; link = link->next, index_iter++) {
+ if (string != NULL && string[0] != '\0') {
+ const char *string_iter = ((const char *)link) + string_offset;
+
+ if (string[0] == string_iter[0] && STREQ(string, string_iter)) {
+ return link;
+ }
+ }
+ if (index_iter == index) {
+ link_at_index = link;
+ }
+ }
+ return link_at_index;
+}
+
int BLI_findstringindex(const ListBase *listbase, const char *id, const int offset)
{
Link *link = NULL;
@@ -849,9 +749,26 @@ int BLI_findstringindex(const ListBase *listbase, const char *id, const int offs
return -1;
}
-/**
- * Sets dst to a duplicate of the entire contents of src. dst may be the same as src.
- */
+ListBase BLI_listbase_from_link(Link *some_link)
+{
+ ListBase list = {some_link, some_link};
+ if (some_link == NULL) {
+ return list;
+ }
+
+ /* Find the first element. */
+ while (((Link *)list.first)->prev != NULL) {
+ list.first = ((Link *)list.first)->prev;
+ }
+
+ /* Find the last element. */
+ while (((Link *)list.last)->next != NULL) {
+ list.last = ((Link *)list.last)->next;
+ }
+
+ return list;
+}
+
void BLI_duplicatelist(ListBase *dst, const ListBase *src)
{
struct Link *dst_link, *src_link;
@@ -887,9 +804,6 @@ void BLI_listbase_reverse(ListBase *lb)
lb->last = curr;
}
-/**
- * \param vlink: Link to make first.
- */
void BLI_listbase_rotate_first(ListBase *lb, void *vlink)
{
/* make circular */
@@ -903,9 +817,6 @@ void BLI_listbase_rotate_first(ListBase *lb, void *vlink)
((Link *)lb->last)->next = NULL;
}
-/**
- * \param vlink: Link to make last.
- */
void BLI_listbase_rotate_last(ListBase *lb, void *vlink)
{
/* make circular */
@@ -919,7 +830,6 @@ void BLI_listbase_rotate_last(ListBase *lb, void *vlink)
((Link *)lb->last)->next = NULL;
}
-/* create a generic list node containing link to provided data */
LinkData *BLI_genericNodeN(void *data)
{
LinkData *ld;
diff --git a/source/blender/blenlib/intern/math_base.c b/source/blender/blenlib/intern/math_base.c
index 1137c4114a5..be70acf622a 100644
--- a/source/blender/blenlib/intern/math_base.c
+++ b/source/blender/blenlib/intern/math_base.c
@@ -42,10 +42,10 @@ int pow_i(int base, int exp)
return result;
}
-/* from python 3.1 floatobject.c
- * ndigits must be between 0 and 21 */
double double_round(double x, int ndigits)
{
+ /* From Python 3.1 `floatobject.c`. */
+
double pow1, pow2, y, z;
if (ndigits >= 0) {
pow1 = pow(10.0, (double)ndigits);
@@ -79,15 +79,6 @@ double double_round(double x, int ndigits)
return z;
}
-/**
- * Floor to the nearest power of 10, e.g.:
- * - 15.0 -> 10.0
- * - 0.015 -> 0.01
- * - 1.0 -> 1.0
- *
- * \param f: Value to floor, must be over 0.0.
- * \note If we wanted to support signed values we could if this becomes necessary.
- */
float floor_power_of_10(float f)
{
BLI_assert(!(f < 0.0f));
@@ -97,15 +88,6 @@ float floor_power_of_10(float f)
return 0.0f;
}
-/**
- * Ceiling to the nearest power of 10, e.g.:
- * - 15.0 -> 100.0
- * - 0.015 -> 0.1
- * - 1.0 -> 1.0
- *
- * \param f: Value to ceiling, must be over 0.0.
- * \note If we wanted to support signed values we could if this becomes necessary.
- */
float ceil_power_of_10(float f)
{
BLI_assert(!(f < 0.0f));
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index 49f9faf1704..cfcc54b1136 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -45,7 +45,6 @@ extern "C" {
# define UNLIKELY(x) (x)
#endif
-/* powf is really slow for raising to integer powers. */
MINLINE float pow2f(float x)
{
return x * x;
@@ -192,21 +191,18 @@ MINLINE double ratiod(double min, double max, double pos)
return range == 0 ? 0 : ((pos - min) / range);
}
-/* Map a normalized value, i.e. from interval [0, 1] to interval [a, b]. */
MINLINE float scalenorm(float a, float b, float x)
{
BLI_assert(x <= 1 && x >= 0);
return (x * (b - a)) + a;
}
-/* Map a normalized value, i.e. from interval [0, 1] to interval [a, b]. */
MINLINE double scalenormd(double a, double b, double x)
{
BLI_assert(x <= 1 && x >= 0);
return (x * (b - a)) + a;
}
-/* Used for zoom values. */
MINLINE float power_of_2(float val)
{
return (float)pow(2.0, ceil(log((double)val) / M_LN2));
@@ -363,16 +359,11 @@ MINLINE signed char round_db_to_char_clamp(double a){
#undef _round_clamp_fl_impl
#undef _round_clamp_db_impl
-/**
- * Round to closest even number, halfway cases are rounded away from zero.
- */
MINLINE float round_to_even(float f)
{
return roundf(f * 0.5f) * 2.0f;
}
-/* integer division that rounds 0.5 up, particularly useful for color blending
- * with integers, to avoid gradual darkening when rounding down */
MINLINE int divide_round_i(int a, int b)
{
return (2 * a + b) / (2 * b);
@@ -397,9 +388,6 @@ MINLINE uint divide_ceil_u(uint a, uint b)
return (a + b - 1) / b;
}
-/**
- * modulo that handles negative numbers, works the same as Python's.
- */
MINLINE int mod_i(int i, int n)
{
return (i % n + n) % n;
@@ -410,7 +398,7 @@ MINLINE float fractf(float a)
return a - floorf(a);
}
-/* Adapted from godot-engine math_funcs.h. */
+/* Adapted from `godot-engine` math_funcs.h. */
MINLINE float wrapf(float value, float max, float min)
{
float range = max - min;
@@ -511,6 +499,22 @@ MINLINE float smoothminf(float a, float b, float c)
}
}
+MINLINE float smoothstep(float edge0, float edge1, float x)
+{
+ float result;
+ if (x < edge0) {
+ result = 0.0f;
+ }
+ else if (x >= edge1) {
+ result = 1.0f;
+ }
+ else {
+ float t = (x - edge0) / (edge1 - edge0);
+ result = (3.0f - 2.0f * t) * (t * t);
+ }
+ return result;
+}
+
MINLINE double min_dd(double a, double b)
{
return (a < b) ? a : b;
@@ -613,27 +617,11 @@ MINLINE size_t clamp_z(size_t value, size_t min, size_t max)
return min_zz(max_zz(value, min), max);
}
-/**
- * Almost-equal for IEEE floats, using absolute difference method.
- *
- * \param max_diff: the maximum absolute difference.
- */
MINLINE int compare_ff(float a, float b, const float max_diff)
{
return fabsf(a - b) <= max_diff;
}
-/**
- * Almost-equal for IEEE floats, using their integer representation
- * (mixing ULP and absolute difference methods).
- *
- * \param max_diff: is the maximum absolute difference (allows to take care of the near-zero area,
- * where relative difference methods cannot really work).
- * \param max_ulps: is the 'maximum number of floats + 1'
- * allowed between \a a and \a b to consider them equal.
- *
- * \see https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
- */
MINLINE int compare_ff_relative(float a, float b, const float max_diff, const int max_ulps)
{
union {
@@ -712,19 +700,11 @@ MINLINE int signum_i(float a)
}
}
-/**
- * Returns number of (base ten) *significant* digits of integer part of given float
- * (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
- */
MINLINE int integer_digits_f(const float f)
{
return (f == 0.0f) ? 0 : (int)floor(log10(fabs(f))) + 1;
}
-/**
- * Returns number of (base ten) *significant* digits of integer part of given double
- * (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
- */
MINLINE int integer_digits_d(const double d)
{
return (d == 0.0) ? 0 : (int)floor(log10(fabs(d))) + 1;
@@ -742,15 +722,15 @@ MINLINE int integer_digits_i(const int i)
#ifdef BLI_HAVE_SSE2
-/* Calculate initial guess for arg^exp based on float representation
+/**
+ * Calculate initial guess for `arg^exp` based on float representation
* This method gives a constant bias, which can be easily compensated by
* multiplying with bias_coeff.
- * Gives better results for exponents near 1 (e. g. 4/5).
+ * Gives better results for exponents near 1 (e.g. `4/5`).
* exp = exponent, encoded as uint32_t
- * e2coeff = 2^(127/exponent - 127) * bias_coeff^(1/exponent), encoded as
- * uint32_t
+ * `e2coeff = 2^(127/exponent - 127) * bias_coeff^(1/exponent)`, encoded as `uint32_t`.
*
- * We hope that exp and e2coeff gets properly inlined
+ * We hope that exp and e2coeff gets properly inlined.
*/
MALWAYS_INLINE __m128 _bli_math_fastpow(const int exp, const int e2coeff, const __m128 arg)
{
@@ -762,7 +742,7 @@ MALWAYS_INLINE __m128 _bli_math_fastpow(const int exp, const int e2coeff, const
return ret;
}
-/* Improve x ^ 1.0f/5.0f solution with Newton-Raphson method */
+/** Improve `x ^ 1.0f/5.0f` solution with Newton-Raphson method */
MALWAYS_INLINE __m128 _bli_math_improve_5throot_solution(const __m128 old_result, const __m128 x)
{
__m128 approx2 = _mm_mul_ps(old_result, old_result);
@@ -772,7 +752,7 @@ MALWAYS_INLINE __m128 _bli_math_improve_5throot_solution(const __m128 old_result
return _mm_mul_ps(summ, _mm_set1_ps(1.0f / 5.0f));
}
-/* Calculate powf(x, 2.4). Working domain: 1e-10 < x < 1e+10 */
+/** Calculate `powf(x, 2.4)`. Working domain: `1e-10 < x < 1e+10`. */
MALWAYS_INLINE __m128 _bli_math_fastpow24(const __m128 arg)
{
/* max, avg and |avg| errors were calculated in gcc without FMA instructions
diff --git a/source/blender/blenlib/intern/math_boolean.cc b/source/blender/blenlib/intern/math_boolean.cc
index 6d4806a3fbc..0bae3c23f79 100644
--- a/source/blender/blenlib/intern/math_boolean.cc
+++ b/source/blender/blenlib/intern/math_boolean.cc
@@ -18,25 +18,16 @@
* \ingroup bli
*/
-#include "BLI_double2.hh"
-#include "BLI_double3.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
#include "BLI_hash.hh"
#include "BLI_math_boolean.hh"
#include "BLI_math_mpq.hh"
-#include "BLI_mpq2.hh"
-#include "BLI_mpq3.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
namespace blender {
#ifdef WITH_GMP
-/**
- * Return +1 if a, b, c are in CCW order around a circle in the plane.
- * Return -1 if they are in CW order, and 0 if they are in line.
- */
int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c)
{
mpq_class detleft = (a[0] - c[0]) * (b[1] - c[1]);
@@ -45,11 +36,6 @@ int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c)
return sgn(det);
}
-/**
- Return +1 if d is in the oriented circle through a, b, and c.
- * The oriented circle goes CCW through a, b, and c.
- * Return -1 if d is outside, and 0 if it is on the circle.
- */
int incircle(const mpq2 &a, const mpq2 &b, const mpq2 &c, const mpq2 &d)
{
mpq_class adx = a[0] - d[0];
@@ -76,12 +62,6 @@ int incircle(const mpq2 &a, const mpq2 &b, const mpq2 &c, const mpq2 &d)
return sgn(det);
}
-/**
- * Return +1 if d is below the plane containing a, b, c (which appear
- * CCW when viewed from above the plane).
- * Return -1 if d is above the plane.
- * Return 0 if it is on the plane.
- */
int orient3d(const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &d)
{
mpq_class adx = a[0] - d[0];
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index 14eb78648e0..5e52873649e 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -64,13 +64,11 @@ void hsl_to_rgb(float h, float s, float l, float *r_r, float *r_g, float *r_b)
*r_b = (nb - 0.5f) * chroma + l;
}
-/* convenience function for now */
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
{
hsv_to_rgb(hsv[0], hsv[1], hsv[2], &r_rgb[0], &r_rgb[1], &r_rgb[2]);
}
-/* convenience function for now */
void hsl_to_rgb_v(const float hsl[3], float r_rgb[3])
{
hsl_to_rgb(hsl[0], hsl[1], hsl[2], &r_rgb[0], &r_rgb[1], &r_rgb[2]);
@@ -124,9 +122,6 @@ void yuv_to_rgb(float y, float u, float v, float *r_r, float *r_g, float *r_b, i
*r_b = b;
}
-/* The RGB inputs are supposed gamma corrected and in the range 0 - 1.0f
- *
- * Output YCC have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255 */
void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr, int colorspace)
{
float sr, sg, sb;
@@ -162,12 +157,14 @@ void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr,
*r_cr = cr;
}
-/* YCC input have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255 */
-/* RGB outputs are in the range 0 - 1.0f */
-
-/* FIXME comment above must be wrong because BLI_YCC_ITU_BT601 y 16.0 cr 16.0 -> r -0.7009 */
void ycc_to_rgb(float y, float cb, float cr, float *r_r, float *r_g, float *r_b, int colorspace)
{
+ /* FIXME the following comment must be wrong because:
+ * BLI_YCC_ITU_BT601 y 16.0 cr 16.0 -> r -0.7009. */
+
+ /* YCC input have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255
+ * RGB outputs are in the range 0 - 1.0f. */
+
float r = 128.0f, g = 128.0f, b = 128.0f;
switch (colorspace) {
@@ -250,7 +247,6 @@ void rgb_to_hsv(float r, float g, float b, float *r_h, float *r_s, float *r_v)
*r_v = r;
}
-/* convenience function for now */
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
{
rgb_to_hsv(rgb[0], rgb[1], rgb[2], &r_hsv[0], &r_hsv[1], &r_hsv[2]);
@@ -311,7 +307,6 @@ void rgb_to_hsl_compat_v(const float rgb[3], float r_hsl[3])
rgb_to_hsl_compat(rgb[0], rgb[1], rgb[2], &r_hsl[0], &r_hsl[1], &r_hsl[2]);
}
-/* convenience function for now */
void rgb_to_hsl_v(const float rgb[3], float r_hsl[3])
{
rgb_to_hsl(rgb[0], rgb[1], rgb[2], &r_hsl[0], &r_hsl[1], &r_hsl[2]);
@@ -338,13 +333,11 @@ void rgb_to_hsv_compat(float r, float g, float b, float *r_h, float *r_s, float
}
}
-/* convenience function for now */
void rgb_to_hsv_compat_v(const float rgb[3], float r_hsv[3])
{
rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], &r_hsv[0], &r_hsv[1], &r_hsv[2]);
}
-/* clamp hsv to usable values */
void hsv_clamp_v(float hsv[3], float v_max)
{
if (UNLIKELY(hsv[0] < 0.0f || hsv[0] > 1.0f)) {
@@ -354,12 +347,6 @@ void hsv_clamp_v(float hsv[3], float v_max)
CLAMP(hsv[2], 0.0f, v_max);
}
-/**
- * We define a 'cpack' here as a (3 byte color code)
- * number that can be expressed like 0xFFAA66 or so.
- * For that reason it is sensitive for endianness... with this function it works correctly.
- * \see #imm_cpack
- */
unsigned int hsv_to_cpack(float h, float s, float v)
{
unsigned int r, g, b;
@@ -473,12 +460,6 @@ void minmax_rgb(short c[3])
}
}
-/* If the requested RGB shade contains a negative weight for
- * one of the primaries, it lies outside the color gamut
- * accessible from the given triple of primaries. Desaturate
- * it by adding white, equal quantities of R, G, and B, enough
- * to make RGB all positive. The function returns 1 if the
- * components were modified, zero otherwise. */
int constrain_rgb(float *r, float *g, float *b)
{
/* Amount of white needed */
@@ -520,7 +501,6 @@ void lift_gamma_gain_to_asc_cdl(const float *lift,
/* ************************************* other ************************************************* */
-/* Applies an hue offset to a float rgb color */
void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset)
{
float hsv[3];
@@ -538,7 +518,6 @@ void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset)
hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb + 1, rgb + 2);
}
-/* Applies an hue offset to a byte rgb color */
void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset)
{
float rgb_float[3];
diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c
index 53257cc9285..73ecb2cf798 100644
--- a/source/blender/blenlib/intern/math_color_blend_inline.c
+++ b/source/blender/blenlib/intern/math_color_blend_inline.c
@@ -382,7 +382,7 @@ MINLINE void blend_color_pinlight_byte(uchar dst[4], const uchar src1[4], const
else {
temp = min_ii(2 * src2[i], src1[i]);
}
- dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
+ dst[i] = (uchar)((min_ii(temp, 255) * fac + src1[i] * mfac) / 255);
}
}
else {
@@ -473,7 +473,7 @@ MINLINE void blend_color_exclusion_byte(uchar dst[4], const uchar src1[4], const
int i = 3;
while (i--) {
- const int temp = 127 - ((2 * (src1[i] - 127) * (src2[i] - 127)) / 255);
+ const int temp = 127 - min_ii(((2 * (src1[i] - 127) * (src2[i] - 127)) / 255), 127);
dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
}
}
@@ -896,15 +896,9 @@ MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], cons
int i = 3;
while (i--) {
- float temp;
-
- if (src1[i] < 0.5f) {
- temp = (src2[i] + 0.5f) * src1[i];
- }
- else {
- temp = 1.0f - ((1.0f - (src2[i] + 0.5f)) * (1.0f - src1[i]));
- }
- dst[i] = (temp * fac + src1[i] * mfac);
+ float screen = 1.0f - (1.0f - src1[i]) * (1.0f - src2[i]);
+ float soft_light = ((1.0f - src1[i]) * src2[i] + screen) * src1[i];
+ dst[i] = src1[i] * mfac + soft_light * fac;
}
}
else {
diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c
index ad4b844175f..a7f229e7147 100644
--- a/source/blender/blenlib/intern/math_color_inline.c
+++ b/source/blender/blenlib/intern/math_color_inline.c
@@ -27,7 +27,7 @@
#include "BLI_math_color.h"
#include "BLI_utildefines.h"
-#include "math.h"
+#include <math.h>
#ifndef __MATH_COLOR_INLINE_C__
# define __MATH_COLOR_INLINE_C__
@@ -261,7 +261,7 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack)
}
/* -------------------------------------------------------------------- */
-/** \name RGB/Grayscale Functions
+/** \name RGB/Gray-Scale Functions
*
* \warning
* These are only an approximation,
@@ -271,20 +271,6 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack)
*
* \{ */
-/**
- * ITU-R BT.709 primaries
- * https://en.wikipedia.org/wiki/Relative_luminance
- *
- * Real values are:
- * `Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)`
- * according to: "Derivation of Basic Television Color Equations", RP 177-1993
- *
- * As this sums slightly above 1.0, the document recommends to use:
- * `0.2126(R) + 0.7152(G) + 0.0722(B)`, as used here.
- *
- * The high precision values are used to calculate the rounded byte weights so they add up to 255:
- * `54(R) + 182(G) + 19(B)`
- */
MINLINE float rgb_to_grayscale(const float rgb[3])
{
return (0.2126f * rgb[0]) + (0.7152f * rgb[1]) + (0.0722f * rgb[2]);
@@ -317,11 +303,11 @@ MINLINE int compare_rgb_uchar(const unsigned char col_a[3],
return 0;
}
-/* Using a triangle distribution which gives a more final uniform noise.
- * See Banding in Games:A Noisy Rant(revision 5) Mikkel Gjøl, Playdead (slide 27) */
-/* Return triangle noise in [-0.5..1.5[ range */
MINLINE float dither_random_value(float s, float t)
{
+ /* Using a triangle distribution which gives a more final uniform noise.
+ * See Banding in Games:A Noisy Rant(revision 5) Mikkel Gjøl, Playdead (slide 27) */
+
/* Uniform noise in [0..1[ range, using common GLSL hash function.
* https://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner. */
float hash0 = sinf(s * 12.9898f + t * 78.233f) * 43758.5453f;
@@ -329,7 +315,7 @@ MINLINE float dither_random_value(float s, float t)
hash0 -= floorf(hash0);
hash1 -= floorf(hash1);
/* Convert uniform distribution into triangle-shaped distribution. */
- return hash0 + hash0 - 0.5f;
+ return hash0 + hash1 - 0.5f;
}
MINLINE void float_to_byte_dither_v3(
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 56d93a2d8be..3800fc58a5b 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -86,11 +86,6 @@ float normal_quad_v3(
return normalize_v3(n);
}
-/**
- * Computes the normal of a planar
- * polygon See Graphics Gems for
- * computing newell normal.
- */
float normal_poly_v3(float n[3], const float verts[][3], unsigned int nr)
{
cross_poly_v3(n, verts, nr);
@@ -112,7 +107,6 @@ float area_squared_quad_v3(const float v1[3],
return area_squared_poly_v3(verts, 4);
}
-/* Triangles */
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
{
float n[3];
@@ -162,12 +156,6 @@ float area_squared_poly_v3(const float verts[][3], unsigned int nr)
return len_squared_v3(n);
}
-/**
- * Scalar cross product of a 2d polygon.
- *
- * - equivalent to `area * 2`
- * - useful for checking polygon winding (a positive value is clockwise).
- */
float cross_poly_v2(const float verts[][2], unsigned int nr)
{
unsigned int a;
@@ -236,28 +224,18 @@ float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float
/********************************* Planes **********************************/
-/**
- * Calculate a plane from a point and a direction,
- * \note \a point_no isn't required to be normalized.
- */
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
{
copy_v3_v3(r_plane, plane_no);
r_plane[3] = -dot_v3v3(r_plane, plane_co);
}
-/**
- * Get a point and a direction from a plane.
- */
void plane_to_point_vector_v3(const float plane[4], float r_plane_co[3], float r_plane_no[3])
{
mul_v3_v3fl(r_plane_co, plane, (-plane[3] / len_squared_v3(plane)));
copy_v3_v3(r_plane_no, plane);
}
-/**
- * version of #plane_to_point_vector_v3 that gets a unit length vector.
- */
void plane_to_point_vector_v3_normalized(const float plane[4],
float r_plane_co[3],
float r_plane_no[3])
@@ -268,9 +246,6 @@ void plane_to_point_vector_v3_normalized(const float plane[4],
/********************************* Volume **********************************/
-/**
- * The volume from a tetrahedron, points can be in any order
- */
float volume_tetrahedron_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -283,9 +258,6 @@ float volume_tetrahedron_v3(const float v1[3],
return fabsf(determinant_m3_array(m)) / 6.0f;
}
-/**
- * The volume from a tetrahedron, normal pointing inside gives negative volume
- */
float volume_tetrahedron_signed_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -298,12 +270,6 @@ float volume_tetrahedron_signed_v3(const float v1[3],
return determinant_m3_array(m) / 6.0f;
}
-/**
- * The volume from a triangle that is made into a tetrahedron.
- * This uses a simplified formula where the tip of the tetrahedron is in the world origin.
- * Using this method, the total volume of a closed triangle mesh can be calculated.
- * Note that you need to divide the result by 6 to get the actual volume.
- */
float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3])
{
float v_cross[3];
@@ -319,8 +285,6 @@ float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], con
/********************************* Distance **********************************/
-/* distance p to line v1-v2
- * using Hesse formula, NO LINE PIECE! */
float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l2[2])
{
float closest[2];
@@ -334,7 +298,6 @@ float dist_to_line_v2(const float p[2], const float l1[2], const float l2[2])
return sqrtf(dist_squared_to_line_v2(p, l1, l2));
}
-/* distance p to line-piece v1-v2 */
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
{
float closest[2];
@@ -349,7 +312,6 @@ float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l
return sqrtf(dist_squared_to_line_segment_v2(p, l1, l2));
}
-/* point closest to v1 on line v2-v3 in 2D */
void closest_to_line_segment_v2(float r_close[2],
const float p[2],
const float l1[2],
@@ -371,7 +333,6 @@ void closest_to_line_segment_v2(float r_close[2],
}
}
-/* point closest to v1 on line v2-v3 in 3D */
void closest_to_line_segment_v3(float r_close[3],
const float p[3],
const float l1[3],
@@ -393,15 +354,6 @@ void closest_to_line_segment_v3(float r_close[3],
}
}
-/**
- * Find the closest point on a plane.
- *
- * \param r_close: Return coordinate
- * \param plane: The plane to test against.
- * \param pt: The point to find the nearest of
- *
- * \note non-unit-length planes are supported.
- */
void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3])
{
const float len_sq = len_squared_v3(plane);
@@ -462,9 +414,6 @@ float dist_squared_to_plane3_v3(const float pt[3], const float plane[3])
return len_sq * (fac * fac);
}
-/**
- * Return the signed distance from the point to the plane.
- */
float dist_signed_to_plane_v3(const float pt[3], const float plane[4])
{
const float len_sq = len_squared_v3(plane);
@@ -489,7 +438,6 @@ float dist_to_plane3_v3(const float pt[3], const float plane[3])
return fabsf(dist_signed_to_plane3_v3(pt, plane));
}
-/* distance v1 to line-piece l1-l2 in 3D */
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
{
float closest[3];
@@ -517,29 +465,6 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3])
return sqrtf(dist_squared_to_line_v3(p, l1, l2));
}
-/**
- * Check if \a p is inside the 2x planes defined by `(v1, v2, v3)`
- * where the 3x points define 2x planes.
- *
- * \param axis_ref: used when v1,v2,v3 form a line and to check if the corner is concave/convex.
- *
- * \note the distance from \a v1 & \a v3 to \a v2 doesn't matter
- * (it just defines the planes).
- *
- * \return the lowest squared distance to either of the planes.
- * where `(return < 0.0)` is outside.
- *
- * <pre>
- * v1
- * +
- * /
- * x - out / x - inside
- * /
- * +----+
- * v2 v3
- * x - also outside
- * </pre>
- */
float dist_signed_squared_to_corner_v3v3v3(const float p[3],
const float v1[3],
const float v2[3],
@@ -591,12 +516,6 @@ float dist_signed_squared_to_corner_v3v3v3(const float p[3],
return max_ff(dist_a, dist_b);
}
-/**
- * Compute the squared distance of a point to a line (defined as ray).
- * \param ray_origin: A point on the line.
- * \param ray_direction: Normalized direction of the line.
- * \param co: Point to which the distance is to be calculated.
- */
float dist_squared_to_ray_v3_normalized(const float ray_origin[3],
const float ray_direction[3],
const float co[3])
@@ -613,12 +532,6 @@ float dist_squared_to_ray_v3_normalized(const float ray_origin[3],
return len_squared_v3v3(co, co_projected_on_ray);
}
-/**
- * Find the closest point in a seg to a ray and return the distance squared.
- * \param r_point: Is the point on segment closest to ray
- * (or to ray_origin if the ray and the segment are parallel).
- * \param r_depth: the distance of r_point projection on ray to the ray_origin.
- */
float dist_squared_ray_to_seg_v3(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -655,8 +568,6 @@ float dist_squared_ray_to_seg_v3(const float ray_origin[3],
return len_squared_v3(dvec) - square_f(depth);
}
-/* Returns the coordinates of the nearest vertex and
- * the farthest vertex from a plane (or normal). */
void aabb_get_near_far_from_plane(const float plane_no[3],
const float bbmin[3],
const float bbmax[3],
@@ -707,9 +618,6 @@ void dist_squared_ray_to_aabb_v3_precalc(struct DistRayAABB_Precalc *neasrest_pr
}
}
-/**
- * Returns the distance from a ray to a bound-box (projected on ray)
- */
float dist_squared_ray_to_aabb_v3(const struct DistRayAABB_Precalc *data,
const float bb_min[3],
const float bb_max[3],
@@ -810,16 +718,13 @@ float dist_squared_ray_to_aabb_v3_simple(const float ray_origin[3],
dist_squared_ray_to_aabb_v3_precalc(&data, ray_origin, ray_direction);
return dist_squared_ray_to_aabb_v3(&data, bb_min, bb_max, r_point, r_depth);
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name dist_squared_to_projected_aabb and helpers
* \{ */
-/**
- * \param projmat: Projection Matrix (usually perspective
- * matrix multiplied by object matrix).
- */
void dist_squared_to_projected_aabb_precalc(struct DistProjectedAABBPrecalc *precalc,
const float projmat[4][4],
const float winsize[2],
@@ -871,7 +776,6 @@ void dist_squared_to_projected_aabb_precalc(struct DistProjectedAABBPrecalc *pre
}
}
-/* Returns the distance from a 2d coordinate to a BoundBox (Projected) */
float dist_squared_to_projected_aabb(struct DistProjectedAABBPrecalc *data,
const float bbmin[3],
const float bbmax[3],
@@ -1014,15 +918,15 @@ float dist_squared_to_projected_aabb_simple(const float projmat[4][4],
bool dummy[3] = {true, true, true};
return dist_squared_to_projected_aabb(&data, bbmin, bbmax, dummy);
}
+
/** \} */
-/* Adapted from "Real-Time Collision Detection" by Christer Ericson,
- * published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc.
- *
- * Set 'r' to the point in triangle (a, b, c) closest to point 'p' */
void closest_on_tri_to_point_v3(
float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
{
+ /* Adapted from "Real-Time Collision Detection" by Christer Ericson,
+ * published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc. */
+
float ab[3], ac[3], ap[3], d1, d2;
float bp[3], d3, d4, vc, cp[3], d5, d6, vb, va;
float denom, v, w;
@@ -1100,7 +1004,6 @@ void closest_on_tri_to_point_v3(
/******************************* Intersection ********************************/
-/* intersect Line-Line, shorts */
int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2])
{
float div, lambda, mu;
@@ -1123,7 +1026,6 @@ int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], cons
return ISECT_LINE_LINE_NONE;
}
-/* intersect Line-Line, floats - gives intersection point */
int isect_line_line_v2_point(
const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2])
{
@@ -1147,7 +1049,6 @@ int isect_line_line_v2_point(
return ISECT_LINE_LINE_COLINEAR;
}
-/* intersect Line-Line, floats */
int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
{
float div, lambda, mu;
@@ -1170,7 +1071,6 @@ int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], co
return ISECT_LINE_LINE_NONE;
}
-/* Returns a point on each segment that is closest to the other. */
void isect_seg_seg_v3(const float a0[3],
const float a1[3],
const float b0[3],
@@ -1236,19 +1136,6 @@ void isect_seg_seg_v3(const float a0[3],
madd_v3_v3v3fl(r_b, b0, b_dir, fac_b);
}
-/**
- * Get intersection point of two 2D segments.
- *
- * \param endpoint_bias: Bias to use when testing for end-point overlap.
- * A positive value considers intersections that extend past the endpoints,
- * negative values contract the endpoints.
- * Note the bias is applied to a 0-1 factor, not scaled to the length of segments.
- *
- * \returns intersection type:
- * - -1: collinear.
- * - 1: intersection.
- * - 0: no intersection.
- */
int isect_seg_seg_v2_point_ex(const float v0[2],
const float v1[2],
const float v2[2],
@@ -1369,18 +1256,6 @@ bool isect_seg_seg_v2_simple(const float v1[2],
#undef CCW
}
-/**
- * If intersection == ISECT_LINE_LINE_CROSS or ISECT_LINE_LINE_NONE:
- * <pre>
- * pt = v1 + lambda * (v2 - v1) = v3 + mu * (v4 - v3)
- * </pre>
- * \returns intersection type:
- * - ISECT_LINE_LINE_COLINEAR: collinear.
- * - ISECT_LINE_LINE_EXACT: intersection at an endpoint of either.
- * - ISECT_LINE_LINE_CROSS: interaction, not at an endpoint.
- * - ISECT_LINE_LINE_NONE: no intersection.
- * Also returns lambda and mu in r_lambda and r_mu.
- */
int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
const double v2[2],
const double v3[2],
@@ -1415,19 +1290,6 @@ int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
return ISECT_LINE_LINE_NONE;
}
-/**
- * \param l1, l2: Coordinates (point of line).
- * \param sp, r: Coordinate and radius (sphere).
- * \return r_p1, r_p2: Intersection coordinates.
- *
- * \note The order of assignment for intersection points (\a r_p1, \a r_p2) is predictable,
- * based on the direction defined by `l2 - l1`,
- * this direction compared with the normal of each point on the sphere:
- * \a r_p1 always has a >= 0.0 dot product.
- * \a r_p2 always has a <= 0.0 dot product.
- * For example, when \a l1 is inside the sphere and \a l2 is outside,
- * \a r_p1 will always be between \a l1 and \a l2.
- */
int isect_line_sphere_v3(const float l1[3],
const float l2[3],
const float sp[3],
@@ -1490,7 +1352,6 @@ int isect_line_sphere_v3(const float l1[3],
return -1;
}
-/* keep in sync with isect_line_sphere_v3 */
int isect_line_sphere_v2(const float l1[2],
const float l2[2],
const float sp[2],
@@ -1498,6 +1359,8 @@ int isect_line_sphere_v2(const float l1[2],
float r_p1[2],
float r_p2[2])
{
+ /* Keep in sync with #isect_line_sphere_v3. */
+
const float ldir[2] = {l2[0] - l1[0], l2[1] - l1[1]};
const float a = dot_v2v2(ldir, ldir);
@@ -1537,12 +1400,13 @@ int isect_line_sphere_v2(const float l1[2],
return -1;
}
-/* point in polygon (keep float and int versions in sync) */
bool isect_point_poly_v2(const float pt[2],
const float verts[][2],
const unsigned int nr,
const bool UNUSED(use_holes))
{
+ /* Keep in sync with #isect_point_poly_v2_int. */
+
unsigned int i, j;
bool isect = false;
for (i = 0, j = nr - 1; i < nr; j = i++) {
@@ -1560,6 +1424,8 @@ bool isect_point_poly_v2_int(const int pt[2],
const unsigned int nr,
const bool UNUSED(use_holes))
{
+ /* Keep in sync with #isect_point_poly_v2. */
+
unsigned int i, j;
bool isect = false;
for (i = 0, j = nr - 1; i < nr; j = i++) {
@@ -1575,7 +1441,6 @@ bool isect_point_poly_v2_int(const int pt[2],
/* point in tri */
-/* only single direction */
bool isect_point_tri_v2_cw(const float pt[2],
const float v1[2],
const float v2[2],
@@ -1612,7 +1477,6 @@ int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2],
return 0;
}
-/* point in quad - only convex quads */
int isect_point_quad_v2(
const float pt[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2])
{
@@ -1638,10 +1502,6 @@ int isect_point_quad_v2(
return 0;
}
-/* moved from effect.c
- * test if the line starting at p1 ending at p2 intersects the triangle v0..v2
- * return non zero if it does
- */
bool isect_line_segment_tri_v3(const float p1[3],
const float p2[3],
const float v0[3],
@@ -1692,7 +1552,6 @@ bool isect_line_segment_tri_v3(const float p1[3],
return true;
}
-/* like isect_line_segment_tri_v3, but allows epsilon tolerance around triangle */
bool isect_line_segment_tri_epsilon_v3(const float p1[3],
const float p2[3],
const float v0[3],
@@ -1744,10 +1603,6 @@ bool isect_line_segment_tri_epsilon_v3(const float p1[3],
return true;
}
-/* moved from effect.c
- * test if the ray starting at p1 going in d direction intersects the triangle v0..v2
- * return non zero if it does
- */
bool isect_ray_tri_v3(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -1799,12 +1654,6 @@ bool isect_ray_tri_v3(const float ray_origin[3],
return true;
}
-/**
- * if clip is nonzero, will only return true if lambda is >= 0.0
- * (i.e. intersection point is along positive \a ray_direction)
- *
- * \note #line_plane_factor_v3() shares logic.
- */
bool isect_ray_plane_v3(const float ray_origin[3],
const float ray_direction[3],
const float plane[4],
@@ -2146,9 +1995,6 @@ bool isect_ray_line_v3(const float ray_origin[3],
return true;
}
-/**
- * Check if a point is behind all planes.
- */
bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3])
{
int i;
@@ -2162,10 +2008,6 @@ bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3])
return true;
}
-/**
- * Check if a point is in front all planes.
- * Same as isect_point_planes_v3 but with planes facing the opposite direction.
- */
bool isect_point_planes_v3_negated(const float (*planes)[4], const int totplane, const float p[3])
{
for (int i = 0; i < totplane; i++) {
@@ -2177,17 +2019,6 @@ bool isect_point_planes_v3_negated(const float (*planes)[4], const int totplane,
return true;
}
-/**
- * Intersect line/plane.
- *
- * \param r_isect_co: The intersection point.
- * \param l1: The first point of the line.
- * \param l2: The second point of the line.
- * \param plane_co: A point on the plane to intersect with.
- * \param plane_no: The direction of the plane (does not need to be normalized).
- *
- * \note #line_plane_factor_v3() shares logic.
- */
bool isect_line_plane_v3(float r_isect_co[3],
const float l1[3],
const float l2[3],
@@ -2211,13 +2042,6 @@ bool isect_line_plane_v3(float r_isect_co[3],
return false;
}
-/**
- * Intersect three planes, return the point where all 3 meet.
- * See Graphics Gems 1 pg 305
- *
- * \param plane_a, plane_b, plane_c: Planes.
- * \param r_isect_co: The resulting intersection point.
- */
bool isect_plane_plane_plane_v3(const float plane_a[4],
const float plane_b[4],
const float plane_c[4],
@@ -2251,17 +2075,6 @@ bool isect_plane_plane_plane_v3(const float plane_a[4],
return false;
}
-/**
- * Intersect two planes, return a point on the intersection and a vector
- * that runs on the direction of the intersection.
- * \note this is a slightly reduced version of #isect_plane_plane_plane_v3
- *
- * \param plane_a, plane_b: Planes.
- * \param r_isect_co: The resulting intersection point.
- * \param r_isect_no: The resulting vector of the intersection.
- *
- * \note \a r_isect_no isn't unit length.
- */
bool isect_plane_plane_v3(const float plane_a[4],
const float plane_b[4],
float r_isect_co[3],
@@ -2296,19 +2109,6 @@ bool isect_plane_plane_v3(const float plane_a[4],
return false;
}
-/**
- * Intersect all planes, calling `callback_fn` for each point that intersects
- * 3 of the planes that isn't outside any of the other planes.
- *
- * This can be thought of as calculating a convex-hull from an array of planes.
- *
- * \param eps_coplanar: Epsilon for testing if two planes are aligned (co-planar).
- * \param eps_isect: Epsilon for testing of a point is behind any of the planes.
- *
- * \warning As complexity is a little under `O(N^3)`, this is only suitable for small arrays.
- *
- * \note This function could be optimized by some spatial structure.
- */
bool isect_planes_v3_fn(
const float planes[][4],
const int planes_len,
@@ -2371,16 +2171,6 @@ bool isect_planes_v3_fn(
return found;
}
-/**
- * Intersect two triangles.
- *
- * \param r_i1, r_i2: Retrieve the overlapping edge between the 2 triangles.
- * \param r_tri_a_edge_isect_count: Indicates how many edges in the first triangle are intersected.
- * \return true when the triangles intersect.
- *
- * \note If it exists, \a r_i1 will be a point on the edge of the 1st triangle.
- * \note intersections between coplanar triangles are currently undetected.
- */
bool isect_tri_tri_v3_ex(const float tri_a[3][3],
const float tri_b[3][3],
float r_i1[3],
@@ -2755,14 +2545,6 @@ static bool getLowestRoot(
return false;
}
-/**
- * Checks status of an AABB in relation to a list of planes.
- *
- * \returns intersection type:
- * - ISECT_AABB_PLANE_BEHIND_ONE (0): AABB is completely behind at least 1 plane;
- * - ISECT_AABB_PLANE_CROSS_ANY (1): AABB intersects at least 1 plane;
- * - ISECT_AABB_PLANE_IN_FRONT_ALL (2): AABB is completely in front of all planes;
- */
int isect_aabb_planes_v3(const float (*planes)[4],
const int totplane,
const float bbmin[3],
@@ -3030,12 +2812,6 @@ bool isect_axial_line_segment_tri_v3(const int axis,
return true;
}
-/**
- * \return The number of point of interests
- * 0 - lines are collinear
- * 1 - lines are coplanar, i1 is set to intersection
- * 2 - i1 and i2 are the nearest points on line 1 (v1, v2) and line 2 (v3, v4) respectively
- */
int isect_line_line_epsilon_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -3111,10 +2887,6 @@ int isect_line_line_v3(const float v1[3],
return isect_line_line_epsilon_v3(v1, v2, v3, v4, r_i1, r_i2, epsilon);
}
-/**
- * Intersection point strictly between the two lines
- * \return false when no intersection is found.
- */
bool isect_line_line_strict_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -3165,12 +2937,6 @@ bool isect_line_line_strict_v3(const float v1[3],
return false;
}
-/**
- * Check if two rays are not parallel and returns a factor that indicates
- * the distance from \a ray_origin_b to the closest point on ray-a to ray-b.
- *
- * \note Neither directions need to be normalized.
- */
bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3],
const float ray_direction_a[3],
const float ray_origin_b[3],
@@ -3247,12 +3013,13 @@ void isect_ray_aabb_v3_precalc(struct IsectRayAABB_Precalc *data,
data->sign[2] = data->ray_inv_dir[2] < 0.0f;
}
-/* Adapted from http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */
bool isect_ray_aabb_v3(const struct IsectRayAABB_Precalc *data,
const float bb_min[3],
const float bb_max[3],
float *tmin_out)
{
+ /* Adapted from http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */
+
float bbox[2][3];
copy_v3_v3(bbox[0], bb_min);
@@ -3298,13 +3065,6 @@ bool isect_ray_aabb_v3(const struct IsectRayAABB_Precalc *data,
return true;
}
-/**
- * Test a bounding box (AABB) for ray intersection.
- * Assumes the ray is already local to the boundbox space.
- *
- * \note \a direction should be normalized
- * if you intend to use the \a tmin or \a tmax distance results!
- */
bool isect_ray_aabb_v3_simple(const float orig[3],
const float dir[3],
const float bb_min[3],
@@ -3357,10 +3117,6 @@ float closest_to_ray_v3(float r_close[3],
return lambda;
}
-/**
- * Find closest point to p on line through (l1, l2) and return lambda,
- * where (0 <= lambda <= 1) when cp is in the line segment (l1, l2).
- */
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3])
{
float u[3];
@@ -3424,13 +3180,6 @@ float ray_point_factor_v3(const float p[3],
return ray_point_factor_v3_ex(p, ray_origin, ray_direction, 0.0f, 0.0f);
}
-/**
- * A simplified version of #closest_to_line_v3
- * we only need to return the `lambda`
- *
- * \param epsilon: avoid approaching divide-by-zero.
- * Passing a zero will just check for nonzero division.
- */
float line_point_factor_v3_ex(const float p[3],
const float l1[3],
const float l2[3],
@@ -3471,9 +3220,6 @@ float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2
return line_point_factor_v2_ex(p, l1, l2, 0.0f, 0.0f);
}
-/**
- * \note #isect_line_plane_v3() shares logic
- */
float line_plane_factor_v3(const float plane_co[3],
const float plane_no[3],
const float l1[3],
@@ -3487,10 +3233,6 @@ float line_plane_factor_v3(const float plane_co[3],
return (dot != 0.0f) ? -dot_v3v3(plane_no, h) / dot : 0.0f;
}
-/**
- * Ensure the distance between these points is no greater than 'dist'.
- * If it is, scale them both into the center.
- */
void limit_dist_v3(float v1[3], float v2[3], const float dist)
{
const float dist_old = len_v3v3(v1, v2);
@@ -3508,13 +3250,6 @@ void limit_dist_v3(float v1[3], float v2[3], const float dist)
}
}
-/*
- * x1,y2
- * | \
- * | \ .(a,b)
- * | \
- * x1,y1-- x2,y1
- */
int isect_point_tri_v2_int(
const int x1, const int y1, const int x2, const int y2, const int a, const int b)
{
@@ -3603,12 +3338,6 @@ bool isect_point_tri_prism_v3(const float p[3],
return true;
}
-/**
- * \param r_isect_co: The point \a p projected onto the triangle.
- * \return True when \a p is inside the triangle.
- * \note Its up to the caller to check the distance between \a p and \a r_vi
- * against an error margin.
- */
bool isect_point_tri_v3(
const float p[3], const float v1[3], const float v2[3], const float v3[3], float r_isect_co[3])
{
@@ -3739,16 +3468,6 @@ bool clip_segment_v3_plane_n(const float p1[3],
/****************************** Axis Utils ********************************/
-/**
- * \brief Normal to x,y matrix
- *
- * Creates a 3x3 matrix from a normal.
- * This matrix can be applied to vectors so their 'z' axis runs along \a normal.
- * In practice it means you can use x,y as 2d coords. \see
- *
- * \param r_mat: The matrix to return.
- * \param normal: A unit length vector.
- */
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
{
BLI_ASSERT_UNIT_V3(normal);
@@ -3766,9 +3485,6 @@ void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
is_zero_v3(normal));
}
-/**
- * Same as axis_dominant_v3_to_m3, but flips the normal
- */
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3])
{
BLI_ASSERT_UNIT_V3(normal);
@@ -3888,12 +3604,6 @@ void interp_weights_quad_v3(float w[4],
}
}
-/**
- * \return
- * - 0 if the point is outside of triangle.
- * - 1 if the point is inside triangle.
- * - 2 if it's on the edge.
- */
int barycentric_inside_triangle_v2(const float w[3])
{
if (IN_RANGE(w[0], 0.0f, 1.0f) && IN_RANGE(w[1], 0.0f, 1.0f) && IN_RANGE(w[2], 0.0f, 1.0f)) {
@@ -3907,9 +3617,6 @@ int barycentric_inside_triangle_v2(const float w[3])
return 0;
}
-/**
- * \return false for degenerated triangles.
- */
bool barycentric_coords_v2(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{
@@ -3934,12 +3641,6 @@ bool barycentric_coords_v2(
return false;
}
-/**
- * \note Using #cross_tri_v2 means locations outside the triangle are correctly weighted.
- *
- * \note This is *exactly* the same calculation as #resolve_tri_uv_v2,
- * although it has double precision and is used for texture baking, so keep both.
- */
void barycentric_weights_v2(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{
@@ -3963,11 +3664,6 @@ void barycentric_weights_v2(
copy_v3_fl(w, 1.0f / 3.0f);
}
-/**
- * A version of #barycentric_weights_v2 that doesn't allow negative weights.
- * Useful when negative values cause problems and points are only
- * ever slightly outside of the triangle.
- */
void barycentric_weights_v2_clamped(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{
@@ -3991,10 +3687,6 @@ void barycentric_weights_v2_clamped(
copy_v3_fl(w, 1.0f / 3.0f);
}
-/**
- * still use 2D X,Y space but this works for verts transformed by a perspective matrix,
- * using their 4th component as a weight
- */
void barycentric_weights_v2_persp(
const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3])
{
@@ -4018,11 +3710,6 @@ void barycentric_weights_v2_persp(
copy_v3_fl(w, 1.0f / 3.0f);
}
-/**
- * same as #barycentric_weights_v2 but works with a quad,
- * NOTE: untested for values outside the quad's bounds
- * this is #interp_weights_poly_v2 expanded for quads only
- */
void barycentric_weights_v2_quad(const float v1[2],
const float v2[2],
const float v3[2],
@@ -4033,7 +3720,7 @@ void barycentric_weights_v2_quad(const float v1[2],
/* NOTE(campbell): fabsf() here is not needed for convex quads
* (and not used in #interp_weights_poly_v2).
* But in the case of concave/bow-tie quads for the mask rasterizer it
- * gives unreliable results without adding absf(). If this becomes an issue for more general
+ * gives unreliable results without adding `absf()`. If this becomes an issue for more general
* usage we could have this optional or use a different function. */
#define MEAN_VALUE_HALF_TAN_V2(_area, i1, i2) \
((_area = cross_v2v2(dirs[i1], dirs[i2])) != 0.0f ? \
@@ -4116,9 +3803,6 @@ void barycentric_weights_v2_quad(const float v1[2],
}
}
-/* given 2 triangles in 3D space, and a point in relation to the first triangle.
- * calculate the location of a point in relation to the second triangle.
- * Useful for finding relative positions with geometry */
void transform_point_by_tri_v3(float pt_tar[3],
float const pt_src[3],
const float tri_tar_p1[3],
@@ -4163,10 +3847,6 @@ void transform_point_by_tri_v3(float pt_tar[3],
madd_v3_v3v3fl(pt_tar, pt_tar, no_tar, (z_ofs_src / area_src) * area_tar);
}
-/**
- * Simply re-interpolates,
- * assumes p_src is between \a l_src_p1-l_src_p2
- */
void transform_point_by_seg_v3(float p_dst[3],
const float p_src[3],
const float l_dst_p1[3],
@@ -4178,8 +3858,6 @@ void transform_point_by_seg_v3(float p_dst[3],
interp_v3_v3v3(p_dst, l_dst_p1, l_dst_p2, t);
}
-/* given an array with some invalid values this function interpolates valid values
- * replacing the invalid ones */
int interp_sparse_array(float *array, const int list_size, const float skipval)
{
int found_invalid = 0;
@@ -4516,7 +4194,6 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[
/** \} */
-/* (x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t) */
void interp_cubic_v3(float x[3],
float v[3],
const float x1[3],
@@ -4552,13 +4229,6 @@ void interp_cubic_v3(float x[3],
#define IS_ZERO(x) ((x > (-DBL_EPSILON) && x < DBL_EPSILON) ? 1 : 0)
-/**
- * Barycentric reverse
- *
- * Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
- *
- * \note same basic result as #barycentric_weights_v2, see its comment for details.
- */
void resolve_tri_uv_v2(
float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2])
{
@@ -4581,11 +4251,6 @@ void resolve_tri_uv_v2(
}
}
-/**
- * Barycentric reverse 3d
- *
- * Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
- */
void resolve_tri_uv_v3(
float r_uv[2], const float st[3], const float st0[3], const float st1[3], const float st2[3])
{
@@ -4617,7 +4282,6 @@ void resolve_tri_uv_v3(
}
}
-/* bilinear reverse */
void resolve_quad_uv_v2(float r_uv[2],
const float st[2],
const float st0[2],
@@ -4628,7 +4292,6 @@ void resolve_quad_uv_v2(float r_uv[2],
resolve_quad_uv_v2_deriv(r_uv, NULL, st, st0, st1, st2, st3);
}
-/* bilinear reverse with derivatives */
void resolve_quad_uv_v2_deriv(float r_uv[2],
float r_deriv[2][2],
const float st[2],
@@ -4719,7 +4382,6 @@ void resolve_quad_uv_v2_deriv(float r_uv[2],
}
}
-/* a version of resolve_quad_uv_v2 that only calculates the 'u' */
float resolve_quad_u_v2(const float st[2],
const float st0[2],
const float st1[2],
@@ -4763,7 +4425,6 @@ float resolve_quad_u_v2(const float st[2],
#undef IS_ZERO
-/* reverse of the functions above */
void interp_bilinear_quad_v3(float data[4][3], float u, float v, float res[3])
{
float vec[3];
@@ -4797,9 +4458,6 @@ void interp_barycentric_tri_v3(float data[3][3], float u, float v, float res[3])
/***************************** View & Projection *****************************/
-/**
- * Matches `glOrtho` result.
- */
void orthographic_m4(float matrix[4][4],
const float left,
const float right,
@@ -4825,9 +4483,6 @@ void orthographic_m4(float matrix[4][4],
matrix[3][2] = -(farClip + nearClip) / Zdelta;
}
-/**
- * Matches `glFrustum` result.
- */
void perspective_m4(float mat[4][4],
const float left,
const float right,
@@ -4873,9 +4528,7 @@ void perspective_m4_fov(float mat[4][4],
mat[1][1] /= nearClip;
}
-/* translate a matrix created by orthographic_m4 or perspective_m4 in XY coords
- * (used to jitter the view) */
-void window_translate_m4(float winmat[4][4], const float perspmat[4][4], const float x, const float y)
+void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x, const float y)
{
if (winmat[2][3] == -1.0f) {
/* in the case of a win-matrix, this means perspective always */
@@ -4903,12 +4556,6 @@ void window_translate_m4(float winmat[4][4], const float perspmat[4][4], const f
}
}
-/**
- * Frustum planes extraction from a projection matrix
- * (homogeneous 4d vector representations of planes).
- *
- * plane parameters can be NULL if you do not need them.
- */
void planes_from_projmat(const float mat[4][4],
float left[4],
float right[4],
@@ -5021,14 +4668,6 @@ void projmat_dimensions_db(const float winmat_fl[4][4],
}
}
-/**
- * Creates a projection matrix for a small region of the viewport.
- *
- * \param projmat: Projection Matrix.
- * \param win_size: Viewport Size.
- * \param x_min, x_max, y_min, y_max: Coordinates of the subregion.
- * \return r_projmat: Resulting Projection Matrix.
- */
void projmat_from_subregion(const float projmat[4][4],
const int win_size[2],
const int x_min,
@@ -5363,8 +5002,6 @@ void accumulate_vertex_normals_v3(float n1[3],
}
}
-/* Add weighted face normal component into normals of the face vertices.
- * Caller must pass pre-allocated vdiffs of nverts length. */
void accumulate_vertex_normals_poly_v3(float **vertnos,
const float polyno[3],
const float **vertcos,
@@ -5444,25 +5081,6 @@ void tangent_from_uv_v3(const float uv1[2],
/****************************** Vector Clouds ********************************/
/* vector clouds */
-/**
- * input
- *
- * \param list_size: 4 lists as pointer to array[list_size]
- * \param pos: current pos array of 'new' positions
- * \param weight: current weight array of 'new'weights (may be NULL pointer if you have no weights)
- * \param rpos: Reference rpos array of 'old' positions
- * \param rweight: Reference rweight array of 'old'weights
- * (may be NULL pointer if you have no weights).
- *
- * output
- *
- * \param lloc: Center of mass pos.
- * \param rloc: Center of mass rpos.
- * \param lrot: Rotation matrix.
- * \param lscale: Scale matrix.
- *
- * pointers may be NULL if not needed
- */
void vcloud_estimate_transform_v3(const int list_size,
const float (*pos)[3],
@@ -6057,11 +5675,6 @@ float form_factor_hemi_poly(
return contrib;
}
-/**
- * Check if the edge is convex or concave
- * (depends on face winding)
- * Copied from BM_edge_is_convex().
- */
bool is_edge_convex_v3(const float v1[3],
const float v2[3],
const float f1_no[3],
@@ -6078,9 +5691,6 @@ bool is_edge_convex_v3(const float v1[3],
return false;
}
-/**
- * Evaluate if entire quad is a proper convex quad
- */
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{
/**
@@ -6176,12 +5786,6 @@ bool is_poly_convex_v2(const float verts[][2], unsigned int nr)
return true;
}
-/**
- * Check if either of the diagonals along this quad create flipped triangles
- * (normals pointing away from eachother).
- * - (1 << 0): (v1-v3) is flipped.
- * - (1 << 1): (v2-v4) is flipped.
- */
int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{
float d_12[3], d_23[3], d_34[3], d_41[3];
@@ -6232,14 +5836,6 @@ bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
return (dot_v3v3(v4, tangent) >= dot) || (dot_v3v3(v2, tangent) <= dot);
}
-/**
- * Return the value which the distance between points will need to be scaled by,
- * to define a handle, given both points are on a perfect circle.
- *
- * Use when we want a bezier curve to match a circle as closely as possible.
- *
- * \note the return value will need to be divided by 0.75 for correct results.
- */
float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
{
BLI_ASSERT_UNIT_V3(tan_l);
@@ -6267,14 +5863,6 @@ float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
return ((1.0f - angle_cos) / (angle_sin * 2.0f)) / angle_sin;
}
-/**
- * Utility for computing approximate geodesic distances on triangle meshes.
- *
- * Given triangle with vertex coordinates v0, v1, v2, and known geodesic distances
- * dist1 and dist2 at v1 and v2, estimate a geodesic distance at vertex v0.
- *
- * From "Dart Throwing on Surfaces", EGSR 2009. Section 7, Geodesic Dart Throwing.
- */
float geodesic_distance_propagate_across_triangle(
const float v0[3], const float v1[3], const float v2[3], const float dist1, const float dist2)
{
diff --git a/source/blender/blenlib/intern/math_geom_inline.c b/source/blender/blenlib/intern/math_geom_inline.c
index 1757b0dd525..09028a1eb9a 100644
--- a/source/blender/blenlib/intern/math_geom_inline.c
+++ b/source/blender/blenlib/intern/math_geom_inline.c
@@ -99,7 +99,7 @@ MINLINE float dot_shsh(const float a[9], const float b[9])
return r;
}
-MINLINE float diffuse_shv3(float sh[9], const float v[3])
+MINLINE float diffuse_shv3(const float sh[9], const float v[3])
{
/* See formula (13) in:
* "An Efficient Representation for Irradiance Environment Maps" */
@@ -164,7 +164,6 @@ MINLINE void madd_sh_shfl(float r[9], const float sh[9], const float f)
add_sh_shsh(r, r, tmp);
}
-/* get the 2 dominant axis values, 0==X, 1==Y, 2==Z */
MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3])
{
const float xn = fabsf(axis[0]);
@@ -185,7 +184,6 @@ MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3])
}
}
-/* same as axis_dominant_v3 but return the max value */
MINLINE float axis_dominant_v3_max(int *r_axis_a, int *r_axis_b, const float axis[3])
{
const float xn = fabsf(axis[0]);
@@ -209,7 +207,6 @@ MINLINE float axis_dominant_v3_max(int *r_axis_a, int *r_axis_b, const float axi
}
}
-/* get the single dominant axis value, 0==X, 1==Y, 2==Z */
MINLINE int axis_dominant_v3_single(const float vec[3])
{
const float x = fabsf(vec[0]);
@@ -218,7 +215,6 @@ MINLINE int axis_dominant_v3_single(const float vec[3])
return ((x > y) ? ((x > z) ? 0 : 2) : ((y > z) ? 1 : 2));
}
-/* the dominant axis of an orthogonal vector */
MINLINE int axis_dominant_v3_ortho_single(const float vec[3])
{
const float x = fabsf(vec[0]);
@@ -243,15 +239,6 @@ MINLINE int min_axis_v3(const float vec[3])
return ((x < y) ? ((x < z) ? 0 : 2) : ((y < z) ? 1 : 2));
}
-/**
- * Simple function to either:
- * - Calculate how many triangles needed from the total number of polygons + loops.
- * - Calculate the first triangle index from the polygon index & that polygons loop-start.
- *
- * \param poly_count: The number of polygons or polygon-index
- * (3+ sided faces, 1-2 sided give incorrect results).
- * \param corner_count: The number of corners (also called loop-index).
- */
MINLINE int poly_to_tri_count(const int poly_count, const int corner_count)
{
BLI_assert(!poly_count || corner_count > poly_count * 2);
@@ -263,17 +250,10 @@ MINLINE float plane_point_side_v3(const float plane[4], const float co[3])
return dot_v3v3(co, plane) + plane[3];
}
-/* useful to calculate an even width shell, by taking the angle between 2 planes.
- * The return value is a scale on the offset.
- * no angle between planes is 1.0, as the angle between the 2 planes approaches 180d
- * the distance gets very high, 180d would be inf, but this case isn't valid */
MINLINE float shell_angle_to_dist(const float angle)
{
return (UNLIKELY(angle < SMALL_NUMBER)) ? 1.0f : fabsf(1.0f / cosf(angle));
}
-/**
- * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b))`.
- */
MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
{
const float angle_cos = fabsf(dot_v3v3(a, b));
@@ -281,9 +261,6 @@ MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
BLI_ASSERT_UNIT_V3(b);
return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
}
-/**
- * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b))`.
- */
MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2])
{
const float angle_cos = fabsf(dot_v2v2(a, b));
@@ -292,9 +269,6 @@ MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2])
return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
}
-/**
- * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b) / 2)`.
- */
MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3])
{
float angle_cos;
@@ -306,9 +280,6 @@ MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[
return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
}
-/**
- * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b) / 2)`.
- */
MINLINE float shell_v2v2_mid_normalized_to_dist(const float a[2], const float b[2])
{
float angle_cos;
diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c
index bd48edf70c0..54beb74abca 100644
--- a/source/blender/blenlib/intern/math_interp.c
+++ b/source/blender/blenlib/intern/math_interp.c
@@ -567,10 +567,11 @@ static void radangle2imp(float a2, float b2, float th, float *A, float *B, float
*F = a2 * b2;
}
-/* all tests here are done to make sure possible overflows are hopefully minimized */
void BLI_ewa_imp2radangle(
float A, float B, float C, float F, float *a, float *b, float *th, float *ecc)
{
+ /* NOTE: all tests here are done to make sure possible overflows are hopefully minimized. */
+
if (F <= 1e-5f) { /* use arbitrary major radius, zero minor, infinite eccentricity */
*a = sqrtf(A > C ? A : C);
*b = 0.0f;
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index b605c3eeead..eaf76696a0a 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -180,6 +180,21 @@ void copy_m4_m2(float m1[4][4], const float m2[2][2])
m1[3][3] = 1.0f;
}
+void copy_m3d_m3(double m1[3][3], const float m2[3][3])
+{
+ m1[0][0] = m2[0][0];
+ m1[0][1] = m2[0][1];
+ m1[0][2] = m2[0][2];
+
+ m1[1][0] = m2[1][0];
+ m1[1][1] = m2[1][1];
+ m1[1][2] = m2[1][2];
+
+ m1[2][0] = m2[2][0];
+ m1[2][1] = m2[2][1];
+ m1[2][2] = m2[2][2];
+}
+
void copy_m4d_m4(double m1[4][4], const float m2[4][4])
{
m1[0][0] = m2[0][0];
@@ -454,7 +469,6 @@ void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3])
R[2][2] = B_[2][0] * A_[0][2] + B_[2][1] * A_[1][2] + B_[2][2] * A_[2][2];
}
-/* R = A * B, ignore the elements on the 4th row/column of A */
void mul_m3_m3m4(float R[3][3], const float A[3][3], const float B[4][4])
{
float B_[4][4], A_[3][3];
@@ -478,7 +492,6 @@ void mul_m3_m3m4(float R[3][3], const float A[3][3], const float B[4][4])
R[2][2] = B_[2][0] * A_[0][2] + B_[2][1] * A_[1][2] + B_[2][2] * A_[2][2];
}
-/* R = A * B, ignore the elements on the 4th row/column of B */
void mul_m3_m4m3(float R[3][3], const float A[4][4], const float B[3][3])
{
float B_[3][3], A_[4][4];
@@ -621,6 +634,7 @@ void _va_mul_m3_series_9(float r[3][3],
mul_m3_m3m3(r, r, m7);
mul_m3_m3m3(r, r, m8);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -709,6 +723,7 @@ void _va_mul_m4_series_9(float r[4][4],
mul_m4_m4m4(r, r, m7);
mul_m4_m4m4(r, r, m8);
}
+
/** \} */
void mul_v2_m3v2(float r[2], const float m[3][3], const float v[2])
@@ -790,7 +805,6 @@ void mul_m2_v2(const float mat[2][2], float vec[2])
mul_v2_m2v2(vec, mat, vec);
}
-/** Same as #mul_m4_v3() but doesn't apply translation component. */
void mul_mat3_m4_v3(const float M[4][4], float r[3])
{
const float x = r[0];
@@ -1113,6 +1127,13 @@ float determinant_m4_mat3_array(const float m[4][4])
m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1]));
}
+double determinant_m3_array_db(const double m[3][3])
+{
+ return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) -
+ m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) +
+ m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1]));
+}
+
bool invert_m3_ex(float m[3][3], const float epsilon)
{
float tmp[3][3];
@@ -1193,16 +1214,6 @@ bool invert_m4(float m[4][4])
return success;
}
-/**
- * Computes the inverse of mat and puts it in inverse.
- * Uses Gaussian Elimination with partial (maximal column) pivoting.
- * \return true on success (i.e. can always find a pivot) and false on failure.
- * Mark Segal - 1992.
- *
- * \note this has worse performance than #EIG_invert_m4_m4 (Eigen), but e.g.
- * for non-invertible scale matrices, finding a partial solution can
- * be useful to have a valid local transform center, see T57767.
- */
bool invert_m4_m4_fallback(float inverse[4][4], const float mat[4][4])
{
#ifndef MATH_STANDALONE
@@ -1286,14 +1297,6 @@ bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
#endif
}
-/**
- * Combines transformations, handling scale separately in a manner equivalent
- * to the Aligned Inherit Scale mode, in order to avoid creating shear.
- * If A scale is uniform, the result is equivalent to ordinary multiplication.
- *
- * NOTE: this effectively takes output location from simple multiplication,
- * and uses mul_m4_m4m4_split_channels for rotation and scale.
- */
void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4])
{
float loc_a[3], rot_a[3][3], size_a[3];
@@ -1310,9 +1313,6 @@ void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B
loc_rot_size_to_mat4(R, loc_r, rot_r, size_r);
}
-/**
- * Separately combines location, rotation and scale of the input matrices.
- */
void mul_m4_m4m4_split_channels(float R[4][4], const float A[4][4], const float B[4][4])
{
float loc_a[3], rot_a[3][3], size_a[3];
@@ -1361,7 +1361,6 @@ void transpose_m3_m3(float R[3][3], const float M[3][3])
R[2][2] = M[2][2];
}
-/* seems obscure but in-fact a common operation */
void transpose_m3_m4(float R[3][3], const float M[4][4])
{
BLI_assert(&R[0][0] != &M[0][0]);
@@ -1439,11 +1438,6 @@ bool compare_m4m4(const float mat1[4][4], const float mat2[4][4], float limit)
return false;
}
-/**
- * Make an orthonormal matrix around the selected axis of the given matrix.
- *
- * \param axis: Axis to build the orthonormal basis around.
- */
void orthogonalize_m3(float R[3][3], int axis)
{
float size[3];
@@ -1528,11 +1522,6 @@ void orthogonalize_m3(float R[3][3], int axis)
mul_v3_fl(R[2], size[2]);
}
-/**
- * Make an orthonormal matrix around the selected axis of the given matrix.
- *
- * \param axis: Axis to build the orthonormal basis around.
- */
void orthogonalize_m4(float R[4][4], int axis)
{
float size[3];
@@ -1670,14 +1659,6 @@ static void orthogonalize_stable(float v1[3], float v2[3], float v3[3], bool nor
}
}
-/**
- * Make an orthonormal matrix around the selected axis of the given matrix,
- * in a way that is symmetric and stable to variations in the input, and
- * preserving the value of the determinant, i.e. the overall volume change.
- *
- * \param axis: Axis to build the orthonormal basis around.
- * \param normalize: Normalize the matrix instead of preserving volume.
- */
void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize)
{
switch (axis) {
@@ -1696,14 +1677,6 @@ void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize)
}
}
-/**
- * Make an orthonormal matrix around the selected axis of the given matrix,
- * in a way that is symmetric and stable to variations in the input, and
- * preserving the value of the determinant, i.e. the overall volume change.
- *
- * \param axis: Axis to build the orthonormal basis around.
- * \param normalize: Normalize the matrix instead of preserving volume.
- */
void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize)
{
switch (axis) {
@@ -2171,10 +2144,6 @@ void mat4_to_size(float size[3], const float M[4][4])
size[2] = len_v3(M[2]);
}
-/**
- * Extract scale factors from the matrix, with correction to ensure
- * exact volume in case of a sheared matrix.
- */
void mat4_to_size_fix_shear(float size[3], const float M[4][4])
{
mat4_to_size(size, M);
@@ -2186,11 +2155,6 @@ void mat4_to_size_fix_shear(float size[3], const float M[4][4])
}
}
-/**
- * This computes the overall volume scale factor of a transformation matrix.
- * For an orthogonal matrix, it is the product of all three scale values.
- * Returns a negative value if the transform is flipped by negative scale.
- */
float mat3_to_volume_scale(const float mat[3][3])
{
return determinant_m3_array(mat);
@@ -2201,11 +2165,6 @@ float mat4_to_volume_scale(const float mat[4][4])
return determinant_m4_mat3_array(mat);
}
-/**
- * This gets the average scale of a matrix, only use when your scaling
- * data that has no idea of scale axis, examples are bone-envelope-radius
- * and curve radius.
- */
float mat3_to_scale(const float mat[3][3])
{
/* unit length vector */
@@ -2224,7 +2183,6 @@ float mat4_to_scale(const float mat[4][4])
return len_v3(unit_vec);
}
-/** Return 2D scale (in XY plane) of given mat4. */
float mat4_to_xy_scale(const float M[4][4])
{
/* unit length vector in xy plane */
@@ -2338,12 +2296,6 @@ void scale_m4_fl(float R[4][4], float scale)
R[3][0] = R[3][1] = R[3][2] = 0.0;
}
-void translate_m3(float mat[3][3], float tx, float ty)
-{
- mat[2][0] += (tx * mat[0][0] + ty * mat[1][0]);
- mat[2][1] += (tx * mat[0][1] + ty * mat[1][1]);
-}
-
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
{
mat[3][0] += (Tx * mat[0][0] + Ty * mat[1][0] + Tz * mat[2][0]);
@@ -2351,26 +2303,6 @@ void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
mat[3][2] += (Tx * mat[0][2] + Ty * mat[1][2] + Tz * mat[2][2]);
}
-void rotate_m3(float mat[3][3], const float angle)
-{
- const float angle_cos = cosf(angle);
- const float angle_sin = sinf(angle);
-
- for (int col = 0; col < 3; col++) {
- float temp = angle_cos * mat[0][col] + angle_sin * mat[1][col];
- mat[1][col] = -angle_sin * mat[0][col] + angle_cos * mat[1][col];
- mat[0][col] = temp;
- }
-}
-
-/* TODO: enum for axis? */
-/**
- * Rotate a matrix in-place.
- *
- * \note To create a new rotation matrix see:
- * #axis_angle_to_mat4_single, #axis_angle_to_mat3_single, #angle_to_mat2
- * (axis & angle args are compatible).
- */
void rotate_m4(float mat[4][4], const char axis, const float angle)
{
const float angle_cos = cosf(angle);
@@ -2408,13 +2340,6 @@ void rotate_m4(float mat[4][4], const char axis, const float angle)
}
}
-void rescale_m3(float mat[3][3], const float scale[2])
-{
- mul_v3_fl(mat[0], scale[0]);
- mul_v3_fl(mat[1], scale[1]);
-}
-
-/** Scale a matrix in-place. */
void rescale_m4(float mat[4][4], const float scale[3])
{
mul_v3_fl(mat[0], scale[0]);
@@ -2422,14 +2347,6 @@ void rescale_m4(float mat[4][4], const float scale[3])
mul_v3_fl(mat[2], scale[2]);
}
-/**
- * Scale or rotate around a pivot point,
- * a convenience function to avoid having to do inline.
- *
- * Since its common to make a scale/rotation matrix that pivots around an arbitrary point.
- *
- * Typical use case is to make 3x3 matrix, copy to 4x4, then pass to this function.
- */
void transform_pivot_set_m4(float mat[4][4], const float pivot[3])
{
float tmat[4][4];
@@ -2444,20 +2361,6 @@ void transform_pivot_set_m4(float mat[4][4], const float pivot[3])
mul_m4_m4m4(mat, mat, tmat);
}
-void transform_pivot_set_m3(float mat[3][3], const float pivot[2])
-{
- float tmat[3][3];
-
- unit_m3(tmat);
-
- copy_v2_v2(tmat[2], pivot);
- mul_m3_m3m3(mat, tmat, mat);
-
- /* invert the matrix */
- negate_v2(tmat[2]);
- mul_m3_m3m3(mat, mat, tmat);
-}
-
void blend_m3_m3m3(float out[3][3],
const float dst[3][3],
const float src[3][3],
@@ -2511,22 +2414,6 @@ void blend_m4_m4m4(float out[4][4],
/* for builds without Eigen */
#ifndef MATH_STANDALONE
-/**
- * A polar-decomposition-based interpolation between matrix A and matrix B.
- *
- * \note This code is about five times slower as the 'naive' interpolation done by #blend_m3_m3m3
- * (it typically remains below 2 usec on an average i74700,
- * while #blend_m3_m3m3 remains below 0.4 usec).
- * However, it gives expected results even with non-uniformly scaled matrices,
- * see T46418 for an example.
- *
- * Based on "Matrix Animation and Polar Decomposition", by Ken Shoemake & Tom Duff
- *
- * \param R: Resulting interpolated matrix.
- * \param A: Input matrix which is totally effective with `t = 0.0`.
- * \param B: Input matrix which is totally effective with `t = 1.0`.
- * \param t: Interpolation factor.
- */
void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t)
{
/* 'Rotation' component ('U' part of polar decomposition,
@@ -2572,15 +2459,6 @@ void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], con
mul_m3_m3m3(R, U, P);
}
-/**
- * Complete transform matrix interpolation,
- * based on polar-decomposition-based interpolation from #interp_m3_m3m3.
- *
- * \param R: Resulting interpolated matrix.
- * \param A: Input matrix which is totally effective with `t = 0.0`.
- * \param B: Input matrix which is totally effective with `t = 1.0`.
- * \param t: Interpolation factor.
- */
void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t)
{
float A3[3][3], B3[3][3], R3[3][3];
@@ -2637,25 +2515,6 @@ bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
equals_v4v4(mat1[2], mat2[2]) && equals_v4v4(mat1[3], mat2[3]));
}
-/**
- * Make a 3x3 matrix out of 3 transform components.
- * Matrices are made in the order: `loc * rot * scale`
- */
-void loc_rot_size_to_mat3(float R[3][3],
- const float loc[2],
- const float angle,
- const float size[2])
-{
- unit_m3(R);
- translate_m3(R, loc[0], loc[1]);
- rotate_m3(R, angle);
- rescale_m3(R, size);
-}
-
-/**
- * Make a 4x4 matrix out of 3 transform components.
- * Matrices are made in the order: `scale * rot * loc`
- */
void loc_rot_size_to_mat4(float R[4][4],
const float loc[3],
const float rot[3][3],
@@ -2666,12 +2525,6 @@ void loc_rot_size_to_mat4(float R[4][4],
copy_v3_v3(R[3], loc);
}
-/**
- * Make a 4x4 matrix out of 3 transform components.
- * Matrices are made in the order: `scale * rot * loc`
- *
- * TODO: need to have a version that allows for rotation order...
- */
void loc_eul_size_to_mat4(float R[4][4],
const float loc[3],
const float eul[3],
@@ -2696,10 +2549,6 @@ void loc_eul_size_to_mat4(float R[4][4],
R[3][2] = loc[2];
}
-/**
- * Make a 4x4 matrix out of 3 transform components.
- * Matrices are made in the order: `scale * rot * loc`
- */
void loc_eulO_size_to_mat4(float R[4][4],
const float loc[3],
const float eul[3],
@@ -2725,10 +2574,6 @@ void loc_eulO_size_to_mat4(float R[4][4],
R[3][2] = loc[2];
}
-/**
- * Make a 4x4 matrix out of 3 transform components.
- * Matrices are made in the order: `scale * rot * loc`
- */
void loc_quat_size_to_mat4(float R[4][4],
const float loc[3],
const float quat[4],
@@ -2782,18 +2627,11 @@ void print_m4(const char *str, const float m[4][4])
printf("\n");
}
-/*********************************** SVD ************************************
- * from TNT matrix library
- *
- * Compute the Single Value Decomposition of an arbitrary matrix A
- * That is compute the 3 matrices U,W,V with U column orthogonal (m,n)
- * ,W a diagonal matrix and V an orthogonal square matrix `s.t.A = U.W.Vt`.
- * From this decomposition it is trivial to compute the (pseudo-inverse)
- * of `A` as `Ainv = V.Winv.transpose(U)`.
- */
-
void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
{
+ /* NOTE: originally from TNT (template numeric toolkit) matrix library.
+ * https://math.nist.gov/tnt */
+
float A[4][4];
float work1[4], work2[4];
int m = 4;
@@ -3300,12 +3138,6 @@ void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4])
* where we want to specify the length of the degenerate axes.
* \{ */
-/**
- * A safe version of invert that uses valid axes, calculating the zero'd axis
- * based on the non-zero ones.
- *
- * This works well for transformation matrices, when a single axis is zerod.
- */
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4])
{
if (UNLIKELY(!invert_m4_m4(Ainv, A))) {
@@ -3330,37 +3162,6 @@ void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3])
/** \} */
-/**
- * #SpaceTransform struct encapsulates all needed data to convert between two coordinate spaces
- * (where conversion can be represented by a matrix multiplication).
- *
- * A SpaceTransform is initialized using:
- * - #BLI_SPACE_TRANSFORM_SETUP(&data, ob1, ob2)
- *
- * After that the following calls can be used:
- * - Converts a coordinate in ob1 space to the corresponding ob2 space:
- * #BLI_space_transform_apply(&data, co);
- * - Converts a coordinate in ob2 space to the corresponding ob1 space:
- * #BLI_space_transform_invert(&data, co);
- *
- * Same concept as #BLI_space_transform_apply and #BLI_space_transform_invert,
- * but no is normalized after conversion (and not translated at all!):
- * - #BLI_space_transform_apply_normal(&data, no);
- * - #BLI_space_transform_invert_normal(&data, no);
- */
-
-/**
- * Global-invariant transform.
- *
- * This defines a matrix transforming a point in local space to a point in target space
- * such that its global coordinates remain unchanged.
- *
- * In other words, if we have a global point P with local coordinates (x, y, z)
- * and global coordinates (X, Y, Z),
- * this defines a transform matrix TM such that (x', y', z') = TM * (x, y, z)
- * where (x', y', z') are the coordinates of P' in target space
- * such that it keeps (X, Y, Z) coordinates in global space.
- */
void BLI_space_transform_from_matrices(SpaceTransform *data,
const float local[4][4],
const float target[4][4])
@@ -3371,18 +3172,6 @@ void BLI_space_transform_from_matrices(SpaceTransform *data,
invert_m4_m4(data->target2local, data->local2target);
}
-/**
- * Local-invariant transform.
- *
- * This defines a matrix transforming a point in global space
- * such that its local coordinates (from local space to target space) remain unchanged.
- *
- * In other words, if we have a local point p with local coordinates (x, y, z)
- * and global coordinates (X, Y, Z),
- * this defines a transform matrix TM such that (X', Y', Z') = TM * (X, Y, Z)
- * where (X', Y', Z') are the coordinates of p' in global space
- * such that it keeps (x, y, z) coordinates in target space.
- */
void BLI_space_transform_global_from_matrices(SpaceTransform *data,
const float local[4][4],
const float target[4][4])
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index 34baac6f2a4..dbcf3a6500c 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -34,7 +34,6 @@
# define QUAT_EPSILON 0.0001
#endif
-/* convenience, avoids setting Y axis everywhere */
void unit_axis_angle(float axis[3], float *angle)
{
axis[0] = 0.0f;
@@ -75,25 +74,6 @@ void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
q[2] = t2;
}
-/**
- * \note
- * Assumes a unit quaternion?
- *
- * in fact not, but you may want to use a unit quat, read on...
- *
- * Shortcut for 'q v q*' when \a v is actually a quaternion.
- * This removes the need for converting a vector to a quaternion,
- * calculating q's conjugate and converting back to a vector.
- * It also happens to be faster (17+,24* vs * 24+,32*).
- * If \a q is not a unit quaternion, then \a v will be both rotated by
- * the same amount as if q was a unit quaternion, and scaled by the square of
- * the length of q.
- *
- * For people used to python mathutils, its like:
- * def mul_qt_v3(q, v): (q * Quaternion((0.0, v[0], v[1], v[2])) * q.conjugated())[1:]
- *
- * \note Multiplying by 3x3 matrix is ~25% faster.
- */
void mul_qt_v3(const float q[4], float r[3])
{
float t0, t1, t2;
@@ -150,11 +130,6 @@ void invert_qt_qt(float q1[4], const float q2[4])
invert_qt(q1);
}
-/**
- * This is just conjugate_qt for cases we know \a q is unit-length.
- * we could use #conjugate_qt directly, but use this function to show intent,
- * and assert if its ever becomes non-unit-length.
- */
void invert_qt_normalized(float q[4])
{
BLI_ASSERT_UNIT_QUAT(q);
@@ -167,7 +142,6 @@ void invert_qt_qt_normalized(float q1[4], const float q2[4])
invert_qt_normalized(q1);
}
-/* Simple multiply. */
void mul_qt_fl(float q[4], const float f)
{
q[0] *= f;
@@ -188,7 +162,6 @@ void sub_qt_qtqt(float q[4], const float a[4], const float b[4])
mul_qt_qtqt(q, a, n_b);
}
-/* raise a unit quaternion to the specified power */
void pow_qt_fl_normalized(float q[4], const float fac)
{
BLI_ASSERT_UNIT_QUAT(q);
@@ -200,10 +173,6 @@ void pow_qt_fl_normalized(float q[4], const float fac)
normalize_v3_length(q + 1, si);
}
-/**
- * Apply the rotation of \a a to \a q keeping the values compatible with \a old.
- * Avoid axis flipping for animated f-curves for eg.
- */
void quat_to_compatible_quat(float q[4], const float a[4], const float old[4])
{
const float eps = 1e-4f;
@@ -471,9 +440,6 @@ float normalize_qt_qt(float r[4], const float q[4])
return normalize_qt(r);
}
-/**
- * Calculate a rotation matrix from 2 normalized vectors.
- */
void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float v2[3])
{
float axis[3];
@@ -511,7 +477,6 @@ void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float
}
}
-/* NOTE: expects vectors to be normalized. */
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3])
{
float axis[3];
@@ -551,16 +516,6 @@ void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q
mul_qt_qtqt(q, tquat, q2);
}
-/**
- * Decompose a quaternion into a swing rotation (quaternion with the selected
- * axis component locked at zero), followed by a twist rotation around the axis.
- *
- * \param q: input quaternion.
- * \param axis: twist axis in [0,1,2]
- * \param r_swing: if not NULL, receives the swing quaternion.
- * \param r_twist: if not NULL, receives the twist quaternion.
- * \returns twist angle.
- */
float quat_split_swing_and_twist(const float q_in[4], int axis, float r_swing[4], float r_twist[4])
{
BLI_assert(axis >= 0 && axis <= 2);
@@ -861,14 +816,6 @@ void QuatInterpolW(float *result, float quat1[4], float quat2[4], float t)
}
#endif
-/**
- * Generic function for implementing slerp
- * (quaternions and spherical vector coords).
- *
- * \param t: factor in [0..1]
- * \param cosom: dot product from normalized vectors/quats.
- * \param r_w: calculated weights.
- */
void interp_dot_slerp(const float t, const float cosom, float r_w[2])
{
const float eps = 1e-4f;
@@ -925,8 +872,6 @@ void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t)
q[3] = a[3] + t * b[3];
}
-/* same as tri_to_quat() but takes pre-computed normal from the triangle
- * used for ngons when we know their normal */
void tri_to_quat_ex(
float quat[4], const float v1[3], const float v2[3], const float v3[3], const float no_orig[3])
{
@@ -979,9 +924,6 @@ void tri_to_quat_ex(
mul_qt_qtqt(quat, q1, q2);
}
-/**
- * \return the length of the normal, use to test for degenerate triangles.
- */
float tri_to_quat(float q[4], const float a[3], const float b[3], const float c[3])
{
float vec[3];
@@ -1020,7 +962,6 @@ void axis_angle_to_quat(float r[4], const float axis[3], const float angle)
}
}
-/* Quaternions to Axis Angle */
void quat_to_axis_angle(float axis[3], float *angle, const float q[4])
{
float ha, si;
@@ -1054,7 +995,6 @@ void quat_to_axis_angle(float axis[3], float *angle, const float q[4])
}
}
-/* Axis Angle to Euler Rotation */
void axis_angle_to_eulO(float eul[3], const short order, const float axis[3], const float angle)
{
float q[4];
@@ -1064,7 +1004,6 @@ void axis_angle_to_eulO(float eul[3], const short order, const float axis[3], co
quat_to_eulO(eul, order, q);
}
-/* Euler Rotation to Axis Angle */
void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const short order)
{
float q[4];
@@ -1074,15 +1013,6 @@ void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const s
quat_to_axis_angle(axis, angle, q);
}
-/**
- * axis angle to 3x3 matrix
- *
- * This takes the angle with sin/cos applied so we can avoid calculating it in some cases.
- *
- * \param axis: rotation axis (must be normalized).
- * \param angle_sin: sin(angle)
- * \param angle_cos: cos(angle)
- */
void axis_angle_normalized_to_mat3_ex(float mat[3][3],
const float axis[3],
const float angle_sin,
@@ -1123,7 +1053,6 @@ void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], const flo
axis_angle_normalized_to_mat3_ex(R, axis, sinf(angle), cosf(angle));
}
-/* axis angle to 3x3 matrix - safer version (normalization of axis performed) */
void axis_angle_to_mat3(float R[3][3], const float axis[3], const float angle)
{
float nor[3];
@@ -1137,7 +1066,6 @@ void axis_angle_to_mat3(float R[3][3], const float axis[3], const float angle)
axis_angle_normalized_to_mat3(R, nor, angle);
}
-/* axis angle to 4x4 matrix - safer version (normalization of axis performed) */
void axis_angle_to_mat4(float R[4][4], const float axis[3], const float angle)
{
float tmat[3][3];
@@ -1147,7 +1075,6 @@ void axis_angle_to_mat4(float R[4][4], const float axis[3], const float angle)
copy_m4_m3(R, tmat);
}
-/* 3x3 matrix to axis angle */
void mat3_normalized_to_axis_angle(float axis[3], float *angle, const float mat[3][3])
{
float q[4];
@@ -1167,7 +1094,6 @@ void mat3_to_axis_angle(float axis[3], float *angle, const float mat[3][3])
quat_to_axis_angle(axis, angle, q);
}
-/* 4x4 matrix to axis angle */
void mat4_normalized_to_axis_angle(float axis[3], float *angle, const float mat[4][4])
{
float q[4];
@@ -1178,7 +1104,6 @@ void mat4_normalized_to_axis_angle(float axis[3], float *angle, const float mat[
quat_to_axis_angle(axis, angle, q);
}
-/* 4x4 matrix to axis angle */
void mat4_to_axis_angle(float axis[3], float *angle, const float mat[4][4])
{
float q[4];
@@ -1196,7 +1121,6 @@ void axis_angle_to_mat4_single(float R[4][4], const char axis, const float angle
copy_m4_m3(R, mat3);
}
-/* rotation matrix from a single axis */
void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle)
{
const float angle_cos = cosf(angle);
@@ -1305,7 +1229,6 @@ void expmap_to_quat(float r[4], const float expmap[3])
/******************************** XYZ Eulers *********************************/
-/* XYZ order */
void eul_to_mat3(float mat[3][3], const float eul[3])
{
double ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
@@ -1332,7 +1255,6 @@ void eul_to_mat3(float mat[3][3], const float eul[3])
mat[2][2] = (float)(cj * ci);
}
-/* XYZ order */
void eul_to_mat4(float mat[4][4], const float eul[3])
{
double ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
@@ -1390,7 +1312,6 @@ static void mat3_normalized_to_eul2(const float mat[3][3], float eul1[3], float
}
}
-/* XYZ order */
void mat3_normalized_to_eul(float eul[3], const float mat[3][3])
{
float eul1[3], eul2[3];
@@ -1413,7 +1334,6 @@ void mat3_to_eul(float eul[3], const float mat[3][3])
mat3_normalized_to_eul(eul, unit_mat);
}
-/* XYZ order */
void mat4_normalized_to_eul(float eul[3], const float m[4][4])
{
float mat3[3][3];
@@ -1427,7 +1347,6 @@ void mat4_to_eul(float eul[3], const float m[4][4])
mat3_to_eul(eul, mat3);
}
-/* XYZ order */
void quat_to_eul(float eul[3], const float quat[4])
{
float unit_mat[3][3];
@@ -1435,7 +1354,6 @@ void quat_to_eul(float eul[3], const float quat[4])
mat3_normalized_to_eul(eul, unit_mat);
}
-/* XYZ order */
void eul_to_quat(float quat[4], const float eul[3])
{
float ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
@@ -1460,7 +1378,6 @@ void eul_to_quat(float quat[4], const float eul[3])
quat[3] = cj * cs - sj * sc;
}
-/* XYZ order */
void rotate_eul(float beul[3], const char axis, const float ang)
{
float eul[3], mat1[3][3], mat2[3][3], totmat[3][3];
@@ -1486,7 +1403,6 @@ void rotate_eul(float beul[3], const char axis, const float ang)
mat3_to_eul(beul, totmat);
}
-/* order independent! */
void compatible_eul(float eul[3], const float oldrot[3])
{
/* we could use M_PI as pi_thresh: which is correct but 5.1 gives better results.
@@ -1539,7 +1455,6 @@ void compatible_eul(float eul[3], const float oldrot[3])
/* uses 2 methods to retrieve eulers, and picks the closest */
-/* XYZ order */
void mat3_normalized_to_compatible_eul(float eul[3], const float oldrot[3], float mat[3][3])
{
float eul1[3], eul2[3];
@@ -1622,7 +1537,6 @@ static const RotOrderInfo *get_rotation_order_info(const short order)
return &rotOrders[5];
}
-/* Construct quaternion from Euler angles (in radians). */
void eulO_to_quat(float q[4], const float e[3], const short order)
{
const RotOrderInfo *R = get_rotation_order_info(order);
@@ -1660,7 +1574,6 @@ void eulO_to_quat(float q[4], const float e[3], const short order)
}
}
-/* Convert quaternion to Euler angles (in radians). */
void quat_to_eulO(float e[3], short const order, const float q[4])
{
float unit_mat[3][3];
@@ -1669,7 +1582,6 @@ void quat_to_eulO(float e[3], short const order, const float q[4])
mat3_normalized_to_eulO(e, order, unit_mat);
}
-/* Construct 3x3 matrix from Euler angles (in radians). */
void eulO_to_mat3(float M[3][3], const float e[3], const short order)
{
const RotOrderInfo *R = get_rotation_order_info(order);
@@ -1747,7 +1659,6 @@ static void mat3_normalized_to_eulo2(const float mat[3][3],
}
}
-/* Construct 4x4 matrix from Euler angles (in radians). */
void eulO_to_mat4(float mat[4][4], const float e[3], const short order)
{
float unit_mat[3][3];
@@ -1757,7 +1668,6 @@ void eulO_to_mat4(float mat[4][4], const float e[3], const short order)
copy_m4_m3(mat, unit_mat);
}
-/* Convert 3x3 matrix to Euler angles (in radians). */
void mat3_normalized_to_eulO(float eul[3], const short order, const float m[3][3])
{
float eul1[3], eul2[3];
@@ -1783,7 +1693,6 @@ void mat3_to_eulO(float eul[3], const short order, const float m[3][3])
mat3_normalized_to_eulO(eul, order, unit_mat);
}
-/* Convert 4x4 matrix to Euler angles (in radians). */
void mat4_normalized_to_eulO(float eul[3], const short order, const float m[4][4])
{
float mat3[3][3];
@@ -1801,7 +1710,6 @@ void mat4_to_eulO(float eul[3], const short order, const float m[4][4])
mat3_normalized_to_eulO(eul, order, mat3);
}
-/* uses 2 methods to retrieve eulers, and picks the closest */
void mat3_normalized_to_compatible_eulO(float eul[3],
const float oldrot[3],
const short order,
@@ -1901,7 +1809,6 @@ void rotate_eulO(float beul[3], const short order, char axis, float ang)
mat3_to_eulO(beul, order, totmat);
}
-/* the matrix is written to as 3 axis vectors */
void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], const short order)
{
const RotOrderInfo *R = get_rotation_order_info(order);
@@ -2190,7 +2097,6 @@ void copy_dq_dq(DualQuat *r, const DualQuat *dq)
memcpy(r, dq, sizeof(DualQuat));
}
-/* axis matches eTrackToAxis_Modes */
void quat_apply_track(float quat[4], short axis, short upflag)
{
/* rotations are hard coded to match vec_to_quat */
@@ -2271,7 +2177,6 @@ void vec_apply_track(float vec[3], short axis)
}
}
-/* lens/angle conversion (radians) */
float focallength_to_fov(float focal_length, float sensor)
{
return 2.0f * atanf((sensor / 2.0f) / focal_length);
@@ -2298,7 +2203,6 @@ float angle_wrap_deg(float angle)
return mod_inline(angle + 180.0f, 360.0f) - 180.0f;
}
-/* returns an angle compatible with angle_compat */
float angle_compat_rad(float angle, float angle_compat)
{
return angle_compat + angle_wrap_rad(angle - angle_compat);
@@ -2387,10 +2291,6 @@ BLI_INLINE int _axis_signed(const int axis)
return (axis < 3) ? axis : axis - 3;
}
-/**
- * Each argument us an axis in ['X', 'Y', 'Z', '-X', '-Y', '-Z']
- * where the first 2 are a source and the second 2 are the target.
- */
bool mat3_from_axis_conversion(
int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3])
{
@@ -2423,9 +2323,6 @@ bool mat3_from_axis_conversion(
return false;
}
-/**
- * Use when the second axis can be guessed.
- */
bool mat3_from_axis_conversion_single(int src_axis, int dst_axis, float r_mat[3][3])
{
if (src_axis == dst_axis) {
diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c
index 131afc19f28..f7630efd203 100644
--- a/source/blender/blenlib/intern/math_solvers.c
+++ b/source/blender/blenlib/intern/math_solvers.c
@@ -32,13 +32,6 @@
/********************************** Eigen Solvers *********************************/
-/**
- * \brief Compute the eigen values and/or vectors of given 3D symmetric (aka adjoint) matrix.
- *
- * \param m3: the 3D symmetric matrix.
- * \return r_eigen_values the computed eigen values (NULL if not needed).
- * \return r_eigen_vectors the computed eigen vectors (NULL if not needed).
- */
bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3],
float r_eigen_values[3],
float r_eigen_vectors[3][3])
@@ -54,14 +47,6 @@ bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3],
3, (const float *)m3, r_eigen_values, (float *)r_eigen_vectors);
}
-/**
- * \brief Compute the SVD (Singular Values Decomposition) of given 3D matrix (m3 = USV*).
- *
- * \param m3: the matrix to decompose.
- * \return r_U the computed left singular vector of \a m3 (NULL if not needed).
- * \return r_S the computed singular values of \a m3 (NULL if not needed).
- * \return r_V the computed right singular vector of \a m3 (NULL if not needed).
- */
void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3][3])
{
EIG_svd_square_matrix(3, (const float *)m3, (float *)r_U, (float *)r_S, (float *)r_V);
@@ -69,16 +54,6 @@ void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3
/***************************** Simple Solvers ************************************/
-/**
- * \brief Solve a tridiagonal system of equations:
- *
- * a[i] * r_x[i-1] + b[i] * r_x[i] + c[i] * r_x[i+1] = d[i]
- *
- * Ignores a[0] and c[count-1]. Uses the Thomas algorithm, e.g. see wiki.
- *
- * \param r_x: output vector, may be shared with any of the input ones
- * \return true if success
- */
bool BLI_tridiagonal_solve(
const float *a, const float *b, const float *c, const float *d, float *r_x, const int count)
{
@@ -124,12 +99,6 @@ bool BLI_tridiagonal_solve(
return isfinite(x_prev);
}
-/**
- * \brief Solve a possibly cyclic tridiagonal system using the Sherman-Morrison formula.
- *
- * \param r_x: output vector, may be shared with any of the input ones
- * \return true if success
- */
bool BLI_tridiagonal_solve_cyclic(
const float *a, const float *b, const float *c, const float *d, float *r_x, const int count)
{
@@ -194,21 +163,6 @@ bool BLI_tridiagonal_solve_cyclic(
return success;
}
-/**
- * \brief Solve a generic f(x) = 0 equation using Newton's method.
- *
- * \param func_delta: Callback computing the value of f(x).
- * \param func_jacobian: Callback computing the Jacobian matrix of the function at x.
- * \param func_correction: Callback for forcing the search into an arbitrary custom domain.
- * May be NULL.
- * \param userdata: Data for the callbacks.
- * \param epsilon: Desired precision.
- * \param max_iterations: Limit on the iterations.
- * \param trace: Enables logging to console.
- * \param x_init: Initial solution vector.
- * \param result: Final result.
- * \return true if success
- */
bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta,
Newton3D_JacobianFunc func_jacobian,
Newton3D_CorrectionFunc func_correction,
diff --git a/source/blender/blenlib/intern/math_statistics.c b/source/blender/blenlib/intern/math_statistics.c
index b90ac99dbfe..8087e7a962a 100644
--- a/source/blender/blenlib/intern/math_statistics.c
+++ b/source/blender/blenlib/intern/math_statistics.c
@@ -87,18 +87,6 @@ static void covariance_m_vn_ex_task_cb(void *__restrict userdata,
}
}
-/**
- * \brief Compute the covariance matrix of given set of nD coordinates.
- *
- * \param n: the dimension of the vectors (and hence, of the covariance matrix to compute).
- * \param cos_vn: the nD points to compute covariance from.
- * \param nbr_cos_vn: the number of nD coordinates in cos_vn.
- * \param center: the center (or mean point) of cos_vn. If NULL,
- * it is assumed cos_vn is already centered.
- * \param use_sample_correction: whether to apply sample correction
- * (i.e. get 'sample variance' instead of 'population variance').
- * \return r_covmat the computed covariance matrix.
- */
void BLI_covariance_m_vn_ex(const int n,
const float *cos_vn,
const int nbr_cos_vn,
@@ -128,14 +116,6 @@ void BLI_covariance_m_vn_ex(const int n,
BLI_task_parallel_range(0, n * n, &data, covariance_m_vn_ex_task_cb, &settings);
}
-/**
- * \brief Compute the covariance matrix of given set of 3D coordinates.
- *
- * \param cos_v3: the 3D points to compute covariance from.
- * \param nbr_cos_v3: the number of 3D coordinates in cos_v3.
- * \return r_covmat the computed covariance matrix.
- * \return r_center the computed center (mean) of 3D points (may be NULL).
- */
void BLI_covariance_m3_v3n(const float (*cos_v3)[3],
const int nbr_cos_v3,
const bool use_sample_correction,
diff --git a/source/blender/blenlib/intern/math_time.c b/source/blender/blenlib/intern/math_time.c
index b85de7817dd..4484144a81e 100644
--- a/source/blender/blenlib/intern/math_time.c
+++ b/source/blender/blenlib/intern/math_time.c
@@ -23,13 +23,6 @@
#include "BLI_math.h"
-/** Explode given time value expressed in seconds, into a set of days, hours, minutes, seconds
- * and/or milliseconds (depending on which return parameters are not NULL).
- *
- * \note The smallest given return parameter will get the potential fractional remaining time
- * value. E.g. if you give `seconds=90.0` and do not pass `r_seconds` and `r_milliseconds`,
- * `r_minutes` will be set to `1.5`.
- */
void BLI_math_time_seconds_decompose(double seconds,
double *r_days,
double *r_hours,
diff --git a/source/blender/blenlib/intern/math_vec.cc b/source/blender/blenlib/intern/math_vec.cc
index 223c0e273f0..6fab6c9a383 100644
--- a/source/blender/blenlib/intern/math_vec.cc
+++ b/source/blender/blenlib/intern/math_vec.cc
@@ -18,89 +18,83 @@
* \ingroup bli
*/
-#include "BLI_double2.hh"
-#include "BLI_double3.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
#include "BLI_hash.hh"
-#include "BLI_math_mpq.hh"
-#include "BLI_mpq2.hh"
-#include "BLI_mpq3.hh"
+#include "BLI_math_vec_mpq_types.hh"
+#include "BLI_math_vector.hh"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
-namespace blender {
+namespace blender::math {
-float2::isect_result float2::isect_seg_seg(const float2 &v1,
- const float2 &v2,
- const float2 &v3,
- const float2 &v4)
+template<>
+isect_result<float2> isect_seg_seg(const float2 &v1,
+ const float2 &v2,
+ const float2 &v3,
+ const float2 &v4)
{
- float2::isect_result ans;
+ isect_result<float2> ans;
float div = (v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]);
if (div == 0.0f) {
ans.lambda = 0.0f;
- ans.mu = 0.0f;
- ans.kind = float2::isect_result::LINE_LINE_COLINEAR;
+ ans.kind = isect_result<float2>::LINE_LINE_COLINEAR;
}
else {
ans.lambda = ((v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div;
- ans.mu = ((v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div;
- if (ans.lambda >= 0.0f && ans.lambda <= 1.0f && ans.mu >= 0.0f && ans.mu <= 1.0f) {
- if (ans.lambda == 0.0f || ans.lambda == 1.0f || ans.mu == 0.0f || ans.mu == 1.0f) {
- ans.kind = float2::isect_result::LINE_LINE_EXACT;
+ float mu = ((v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div;
+ if (ans.lambda >= 0.0f && ans.lambda <= 1.0f && mu >= 0.0f && mu <= 1.0f) {
+ if (ans.lambda == 0.0f || ans.lambda == 1.0f || mu == 0.0f || mu == 1.0f) {
+ ans.kind = isect_result<float2>::LINE_LINE_EXACT;
}
else {
- ans.kind = float2::isect_result::LINE_LINE_CROSS;
+ ans.kind = isect_result<float2>::LINE_LINE_CROSS;
}
}
else {
- ans.kind = float2::isect_result::LINE_LINE_NONE;
+ ans.kind = isect_result<float2>::LINE_LINE_NONE;
}
}
return ans;
}
-double2::isect_result double2::isect_seg_seg(const double2 &v1,
- const double2 &v2,
- const double2 &v3,
- const double2 &v4)
+template<>
+isect_result<double2> isect_seg_seg(const double2 &v1,
+ const double2 &v2,
+ const double2 &v3,
+ const double2 &v4)
{
- double2::isect_result ans;
+ isect_result<double2> ans;
double div = (v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]);
if (div == 0.0) {
ans.lambda = 0.0;
- ans.kind = double2::isect_result::LINE_LINE_COLINEAR;
+ ans.kind = isect_result<double2>::LINE_LINE_COLINEAR;
}
else {
ans.lambda = ((v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div;
double mu = ((v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div;
if (ans.lambda >= 0.0 && ans.lambda <= 1.0 && mu >= 0.0 && mu <= 1.0) {
if (ans.lambda == 0.0 || ans.lambda == 1.0 || mu == 0.0 || mu == 1.0) {
- ans.kind = double2::isect_result::LINE_LINE_EXACT;
+ ans.kind = isect_result<double2>::LINE_LINE_EXACT;
}
else {
- ans.kind = double2::isect_result::LINE_LINE_CROSS;
+ ans.kind = isect_result<double2>::LINE_LINE_CROSS;
}
}
else {
- ans.kind = double2::isect_result::LINE_LINE_NONE;
+ ans.kind = isect_result<double2>::LINE_LINE_NONE;
}
}
return ans;
}
#ifdef WITH_GMP
-mpq2::isect_result mpq2::isect_seg_seg(const mpq2 &v1,
- const mpq2 &v2,
- const mpq2 &v3,
- const mpq2 &v4)
+template<>
+isect_result<mpq2> isect_seg_seg(const mpq2 &v1, const mpq2 &v2, const mpq2 &v3, const mpq2 &v4)
{
- mpq2::isect_result ans;
+ isect_result<mpq2> ans;
mpq_class div = (v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]);
if (div == 0.0) {
ans.lambda = 0.0;
- ans.kind = mpq2::isect_result::LINE_LINE_COLINEAR;
+ ans.kind = isect_result<mpq2>::LINE_LINE_COLINEAR;
}
else {
ans.lambda = ((v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div;
@@ -109,66 +103,21 @@ mpq2::isect_result mpq2::isect_seg_seg(const mpq2 &v1,
if (ans.lambda >= 0 && ans.lambda <= 1 &&
((div > 0 && mudiv >= 0 && mudiv <= div) || (div < 0 && mudiv <= 0 && mudiv >= div))) {
if (ans.lambda == 0 || ans.lambda == 1 || mudiv == 0 || mudiv == div) {
- ans.kind = mpq2::isect_result::LINE_LINE_EXACT;
+ ans.kind = isect_result<mpq2>::LINE_LINE_EXACT;
}
else {
- ans.kind = mpq2::isect_result::LINE_LINE_CROSS;
+ ans.kind = isect_result<mpq2>::LINE_LINE_CROSS;
}
}
else {
- ans.kind = mpq2::isect_result::LINE_LINE_NONE;
+ ans.kind = isect_result<mpq2>::LINE_LINE_NONE;
}
}
return ans;
}
#endif
-double3 double3::cross_poly(Span<double3> poly)
-{
- /* Newell's Method. */
- int nv = static_cast<int>(poly.size());
- if (nv < 3) {
- return double3(0, 0, 0);
- }
- const double3 *v_prev = &poly[nv - 1];
- const double3 *v_curr = &poly[0];
- double3 n(0, 0, 0);
- for (int i = 0; i < nv;) {
- n[0] = n[0] + ((*v_prev)[1] - (*v_curr)[1]) * ((*v_prev)[2] + (*v_curr)[2]);
- n[1] = n[1] + ((*v_prev)[2] - (*v_curr)[2]) * ((*v_prev)[0] + (*v_curr)[0]);
- n[2] = n[2] + ((*v_prev)[0] - (*v_curr)[0]) * ((*v_prev)[1] + (*v_curr)[1]);
- v_prev = v_curr;
- ++i;
- if (i < nv) {
- v_curr = &poly[i];
- }
- }
- return n;
-}
-
#ifdef WITH_GMP
-mpq3 mpq3::cross_poly(Span<mpq3> poly)
-{
- /* Newell's Method. */
- int nv = static_cast<int>(poly.size());
- if (nv < 3) {
- return mpq3(0);
- }
- const mpq3 *v_prev = &poly[nv - 1];
- const mpq3 *v_curr = &poly[0];
- mpq3 n(0);
- for (int i = 0; i < nv;) {
- n[0] = n[0] + ((*v_prev)[1] - (*v_curr)[1]) * ((*v_prev)[2] + (*v_curr)[2]);
- n[1] = n[1] + ((*v_prev)[2] - (*v_curr)[2]) * ((*v_prev)[0] + (*v_curr)[0]);
- n[2] = n[2] + ((*v_prev)[0] - (*v_curr)[0]) * ((*v_prev)[1] + (*v_curr)[1]);
- v_prev = v_curr;
- ++i;
- if (i < nv) {
- v_curr = &poly[i];
- }
- }
- return n;
-}
uint64_t hash_mpq_class(const mpq_class &value)
{
@@ -176,20 +125,6 @@ uint64_t hash_mpq_class(const mpq_class &value)
return get_default_hash(static_cast<float>(value.get_d()));
}
-uint64_t mpq2::hash() const
-{
- uint64_t hashx = hash_mpq_class(this->x);
- uint64_t hashy = hash_mpq_class(this->y);
- return hashx ^ (hashy * 33);
-}
-
-uint64_t mpq3::hash() const
-{
- uint64_t hashx = hash_mpq_class(this->x);
- uint64_t hashy = hash_mpq_class(this->y);
- uint64_t hashz = hash_mpq_class(this->z);
- return hashx ^ (hashy * 33) ^ (hashz * 33 * 37);
-}
#endif
-} // namespace blender
+} // namespace blender::math
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 35dfe421cf0..a0afab8a179 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -37,8 +37,6 @@ void interp_v2_v2v2(float r[2], const float a[2], const float b[2], const float
r[1] = s * a[1] + t * b[1];
}
-/* weight 3 2D vectors,
- * 'w' must be unit length but is not a vector, just 3 weights */
void interp_v2_v2v2v2(
float r[2], const float a[2], const float b[2], const float c[2], const float t[3])
{
@@ -65,12 +63,6 @@ void interp_v4_v4v4(float r[4], const float a[4], const float b[4], const float
r[3] = s * a[3] + t * b[3];
}
-/**
- * slerp, treat vectors as spherical coordinates
- * \see #interp_qt_qtqt
- *
- * \return success
- */
bool interp_v3_v3v3_slerp(float target[3], const float a[3], const float b[3], const float t)
{
float cosom, w[2];
@@ -115,9 +107,6 @@ bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], c
return true;
}
-/**
- * Same as #interp_v3_v3v3_slerp but uses fallback values for opposite vectors.
- */
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t)
{
if (UNLIKELY(!interp_v3_v3v3_slerp(target, a, b, t))) {
@@ -186,8 +175,6 @@ void interp_v2_v2v2v2v2_cubic(float p[2],
/** \} */
-/* weight 3 vectors,
- * 'w' must be unit length but is not a vector, just 3 weights */
void interp_v3_v3v3v3(
float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3])
{
@@ -196,8 +183,6 @@ void interp_v3_v3v3v3(
p[2] = v1[2] * w[0] + v2[2] * w[1] + v3[2] * w[2];
}
-/* weight 3 vectors,
- * 'w' must be unit length but is not a vector, just 4 weights */
void interp_v3_v3v3v3v3(float p[3],
const float v1[3],
const float v2[3],
@@ -311,18 +296,6 @@ void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const uint nbr)
}
}
-/**
- * Specialized function for calculating normals.
- * Fast-path for:
- *
- * \code{.c}
- * add_v3_v3v3(r, a, b);
- * normalize_v3(r)
- * mul_v3_fl(r, angle_normalized_v3v3(a, b) / M_PI_2);
- * \endcode
- *
- * We can use the length of (a + b) to calculate the angle.
- */
void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3])
{
/* trick, we want the middle of 2 normals as well as the angle between them
@@ -341,10 +314,6 @@ void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3])
acosf(normalize_v3(r) / 2.0f);
mul_v3_fl(r, angle);
}
-/**
- * Same as mid_v3_v3v3_angle_weighted
- * but \a r is assumed to be accumulated normals, divided by their total.
- */
void mid_v3_angle_weighted(float r[3])
{
/* trick, we want the middle of 2 normals as well as the angle between them
@@ -407,13 +376,6 @@ bool is_finite_v4(const float v[4])
/********************************** Angles ***********************************/
-/* Return the angle in radians between vecs 1-2 and 2-3 in radians
- * If v1 is a shoulder, v2 is the elbow and v3 is the hand,
- * this would return the angle at the elbow.
- *
- * note that when v1/v2/v3 represent 3 points along a straight line
- * that the angle returned will be pi (180deg), rather than 0.0
- */
float angle_v3v3v3(const float a[3], const float b[3], const float c[3])
{
float vec1[3], vec2[3];
@@ -426,7 +388,6 @@ float angle_v3v3v3(const float a[3], const float b[3], const float c[3])
return angle_normalized_v3v3(vec1, vec2);
}
-/* Quicker than full angle computation */
float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3])
{
float vec1[3], vec2[3];
@@ -439,7 +400,6 @@ float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3])
return dot_v3v3(vec1, vec2);
}
-/* Return the shortest angle in radians between the 2 vectors */
float angle_v3v3(const float a[3], const float b[3])
{
float vec1[3], vec2[3];
@@ -466,7 +426,6 @@ float angle_v2v2v2(const float a[2], const float b[2], const float c[2])
return angle_normalized_v2v2(vec1, vec2);
}
-/* Quicker than full angle computation */
float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2])
{
float vec1[2], vec2[2];
@@ -479,7 +438,6 @@ float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2])
return dot_v2v2(vec1, vec2);
}
-/* Return the shortest angle in radians between the 2 vectors */
float angle_v2v2(const float a[2], const float b[2])
{
float vec1[2], vec2[2];
@@ -534,9 +492,6 @@ float angle_normalized_v2v2(const float a[2], const float b[2])
return (float)M_PI - 2.0f * saasin(len_v2v2(a, v2_n) / 2.0f);
}
-/**
- * Angle between 2 vectors, about an axis (axis can be considered a plane).
- */
float angle_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3])
{
float v1_proj[3], v2_proj[3];
@@ -568,9 +523,6 @@ float angle_signed_on_axis_v3v3_v3(const float v1[3], const float v2[3], const f
return angle;
}
-/**
- * Angle between 2 vectors defined by 3 coords, about an axis (axis can be considered a plane).
- */
float angle_on_axis_v3v3v3_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -652,9 +604,6 @@ void angle_poly_v3(float *angles, const float *verts[3], int len)
/********************************* Geometry **********************************/
-/**
- * Project \a p onto \a v_proj
- */
void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2])
{
if (UNLIKELY(is_zero_v2(v_proj))) {
@@ -666,9 +615,6 @@ void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2])
mul_v2_v2fl(out, v_proj, mul);
}
-/**
- * Project \a p onto \a v_proj
- */
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3])
{
if (UNLIKELY(is_zero_v3(v_proj))) {
@@ -691,9 +637,6 @@ void project_v3_v3v3_db(double out[3], const double p[3], const double v_proj[3]
mul_v3_v3db_db(out, v_proj, mul);
}
-/**
- * Project \a p onto a unit length \a v_proj
- */
void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2])
{
BLI_ASSERT_UNIT_V2(v_proj);
@@ -702,9 +645,6 @@ void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_pr
mul_v2_v2fl(out, v_proj, mul);
}
-/**
- * Project \a p onto a unit length \a v_proj
- */
void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3])
{
BLI_ASSERT_UNIT_V3(v_proj);
@@ -713,19 +653,6 @@ void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_pr
mul_v3_v3fl(out, v_proj, mul);
}
-/**
- * In this case plane is a 3D vector only (no 4th component).
- *
- * Projecting will make \a out a copy of \a p orthogonal to \a v_plane.
- *
- * \note If \a p is exactly perpendicular to \a v_plane, \a out will just be a copy of \a p.
- *
- * \note This function is a convenience to call:
- * \code{.c}
- * project_v3_v3v3(out, p, v_plane);
- * sub_v3_v3v3(out, p, out);
- * \endcode
- */
void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
{
const float mul = dot_v3v3(p, v_plane) / dot_v3v3(v_plane, v_plane);
@@ -756,7 +683,6 @@ void project_plane_normalized_v2_v2v2(float out[2], const float p[2], const floa
madd_v2_v2v2fl(out, p, v_plane, -mul);
}
-/* project a vector on a plane defined by normal and a plane point p */
void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3])
{
float vector[3];
@@ -769,7 +695,6 @@ void project_v3_plane(float out[3], const float plane_no[3], const float plane_c
madd_v3_v3fl(out, plane_no, -mul);
}
-/* Returns a vector bisecting the angle at b formed by a, b and c */
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3])
{
float d_12[3], d_23[3];
@@ -781,22 +706,6 @@ void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const floa
normalize_v3(r);
}
-/**
- * Returns a reflection vector from a vector and a normal vector
- * reflect = vec - ((2 * dot(vec, mirror)) * mirror).
- *
- * <pre>
- * v
- * + ^
- * \ |
- * \|
- * + normal: axis of reflection
- * /
- * /
- * +
- * out: result (negate for a 'bounce').
- * </pre>
- */
void reflect_v3_v3v3(float out[3], const float v[3], const float normal[3])
{
BLI_ASSERT_UNIT_V3(normal);
@@ -813,11 +722,6 @@ void reflect_v3_v3v3_db(double out[3], const double v[3], const double normal[3]
madd_v3_v3v3db_db(out, v, normal, -dot2);
}
-/**
- * Takes a vector and computes 2 orthogonal directions.
- *
- * \note if \a n is n unit length, computed values will be too.
- */
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
{
const float eps = FLT_EPSILON;
@@ -843,11 +747,6 @@ void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
}
}
-/**
- * Calculates \a p - a perpendicular vector to \a v
- *
- * \note return vector won't maintain same length.
- */
void ortho_v3_v3(float out[3], const float v[3])
{
const int axis = axis_dominant_v3_single(v);
@@ -873,9 +772,6 @@ void ortho_v3_v3(float out[3], const float v[3])
}
}
-/**
- * no brainer compared to v3, just have for consistency.
- */
void ortho_v2_v2(float out[2], const float v[2])
{
BLI_assert(out != v);
@@ -884,9 +780,6 @@ void ortho_v2_v2(float out[2], const float v[2])
out[1] = v[0];
}
-/**
- * Rotate a point \a p by \a angle around origin (0, 0)
- */
void rotate_v2_v2fl(float r[2], const float p[2], const float angle)
{
const float co = cosf(angle);
@@ -898,10 +791,6 @@ void rotate_v2_v2fl(float r[2], const float p[2], const float angle)
r[1] = si * p[0] + co * p[1];
}
-/**
- * Rotate a point \a p by \a angle around an arbitrary unit length \a axis.
- * http://local.wasp.uwa.edu.au/~pbourke/geometry/
- */
void rotate_normalized_v3_v3v3fl(float out[3],
const float p[3],
const float axis[3],
@@ -1040,7 +929,6 @@ void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float (*vec_arr)
}
}
-/** ensure \a v1 is \a dist from \a v2 */
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist)
{
if (!equals_v3v3(v2, v1)) {
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index d68cd414e71..5893f909183 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -101,6 +101,7 @@ MINLINE void copy_v4_fl(float r[4], float f)
}
/* unsigned char */
+
MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2])
{
r[0] = a[0];
@@ -144,6 +145,7 @@ MINLINE void copy_v4_uchar(unsigned char r[4], const unsigned char a)
}
/* char */
+
MINLINE void copy_v2_v2_char(char r[2], const char a[2])
{
r[0] = a[0];
@@ -224,6 +226,7 @@ MINLINE void copy_v4_v4_int(int r[4], const int a[4])
}
/* double */
+
MINLINE void zero_v3_db(double r[3])
{
r[0] = 0.0;
@@ -252,7 +255,6 @@ MINLINE void copy_v4_v4_db(double r[4], const double a[4])
r[3] = a[3];
}
-/* int <-> float */
MINLINE void round_v2i_v2fl(int r[2], const float a[2])
{
r[0] = (int)roundf(a[0]);
@@ -266,6 +268,7 @@ MINLINE void copy_v2fl_v2i(float r[2], const int a[2])
}
/* double -> float */
+
MINLINE void copy_v2fl_v2db(float r[2], const double a[2])
{
r[0] = (float)a[0];
@@ -288,6 +291,7 @@ MINLINE void copy_v4fl_v4db(float r[4], const double a[4])
}
/* float -> double */
+
MINLINE void copy_v2db_v2fl(double r[2], const float a[2])
{
r[0] = (double)a[0];
@@ -331,6 +335,7 @@ MINLINE void swap_v4_v4(float a[4], float b[4])
}
/* float args -> vec */
+
MINLINE void copy_v2_fl2(float v[2], float x, float y)
{
v[0] = x;
@@ -433,13 +438,6 @@ MINLINE void add_v3fl_v3fl_v3i(float r[3], const float a[3], const int b[3])
r[2] = a[2] + (float)b[2];
}
-MINLINE void add_v3fl_v3fl_v3s(float r[3], const float a[3], const short b[3])
-{
- r[0] = a[0] + (float)b[0];
- r[1] = a[1] + (float)b[1];
- r[2] = a[2] + (float)b[2];
-}
-
MINLINE void add_v4_v4(float r[4], const float a[4])
{
r[0] += a[0];
@@ -639,26 +637,11 @@ MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2])
r[1] = mat[1] * vec[0] + (+mat[0]) * vec[1];
}
-/**
- * Convenience function to get the projected depth of a position.
- * This avoids creating a temporary 4D vector and multiplying it - only for the 4th component.
- *
- * Matches logic for:
- *
- * \code{.c}
- * float co_4d[4] = {co[0], co[1], co[2], 1.0};
- * mul_m4_v4(mat, co_4d);
- * return co_4d[3];
- * \endcode
- */
MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], const float co[3])
{
return (mat[0][3] * co[0]) + (mat[1][3] * co[1]) + (mat[2][3] * co[2]) + mat[3][3];
}
-/**
- * Has the effect of #mul_m3_v3(), on a single axis.
- */
MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3])
{
return M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2];
@@ -672,10 +655,6 @@ MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3])
return M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2];
}
-/**
- * Has the effect of #mul_mat3_m4_v3(), on a single axis.
- * (no adding translation)
- */
MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3])
{
return M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2];
@@ -823,7 +802,6 @@ MINLINE void negate_v4_v4(float r[4], const float a[4])
r[3] = -a[3];
}
-/* could add more... */
MINLINE void negate_v3_short(short r[3])
{
r[0] = (short)-r[0];
@@ -968,8 +946,6 @@ MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
r[2] = a[0] * b[1] - a[1] * b[0];
}
-/* cross product suffers from severe precision loss when vectors are
- * nearly parallel or opposite; doing the computation in double helps a lot */
MINLINE void cross_v3_v3v3_hi_prec(float r[3], const float a[3], const float b[3])
{
BLI_assert(r != a && r != b);
@@ -986,10 +962,6 @@ MINLINE void cross_v3_v3v3_db(double r[3], const double a[3], const double b[3])
r[2] = a[0] * b[1] - a[1] * b[0];
}
-/* Newell's Method */
-/* excuse this fairly specific function,
- * its used for polygon normals all over the place
- * could use a better name */
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3])
{
n[0] += (v_prev[1] - v_curr[1]) * (v_prev[2] + v_curr[2]);
@@ -997,7 +969,7 @@ MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const f
n[2] += (v_prev[0] - v_curr[0]) * (v_prev[1] + v_curr[1]);
}
-MINLINE void star_m3_v3(float rmat[3][3], float a[3])
+MINLINE void star_m3_v3(float rmat[3][3], const float a[3])
{
rmat[0][0] = rmat[1][1] = rmat[2][2] = 0.0;
rmat[0][1] = -a[2];
@@ -1151,9 +1123,19 @@ MINLINE float len_v3v3(const float a[3], const float b[3])
return len_v3(d);
}
-/**
- * \note any vectors containing `nan` will be zeroed out.
- */
+MINLINE float len_v4(const float a[4])
+{
+ return sqrtf(dot_v4v4(a, a));
+}
+
+MINLINE float len_v4v4(const float a[4], const float b[4])
+{
+ float d[4];
+
+ sub_v4_v4v4(d, b, a);
+ return len_v4(d);
+}
+
MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_length)
{
float d = dot_v2v2(a, a);
@@ -1185,9 +1167,6 @@ MINLINE float normalize_v2_length(float n[2], const float unit_length)
return normalize_v2_v2_length(n, n, unit_length);
}
-/**
- * \note any vectors containing `nan` will be zeroed out.
- */
MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_length)
{
float d = dot_v3v3(a, a);
@@ -1491,18 +1470,6 @@ MINLINE void clamp_v4_v4v4(float vec[4], const float min[4], const float max[4])
/** \} */
-/**
- * <pre>
- * + l1
- * |
- * neg <- | -> pos
- * |
- * + l2
- * </pre>
- *
- * \return Positive value when 'pt' is left-of-line
- * (looking from 'l1' -> 'l2').
- */
MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2])
{
return (((l1[0] - pt[0]) * (l2[1] - pt[1])) - ((l2[0] - pt[0]) * (l1[1] - pt[1])));
diff --git a/source/blender/blenlib/intern/memory_utils.c b/source/blender/blenlib/intern/memory_utils.c
index 4bb93877401..2befcb1bb19 100644
--- a/source/blender/blenlib/intern/memory_utils.c
+++ b/source/blender/blenlib/intern/memory_utils.c
@@ -30,9 +30,6 @@
#include "BLI_strict_flags.h"
-/**
- * Check if memory is zeroed, as with `memset(arr, 0, arr_size)`.
- */
bool BLI_memory_is_zero(const void *arr, const size_t arr_size)
{
const char *arr_byte = arr;
diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc
index 90ffebdb422..a3eae1896d3 100644
--- a/source/blender/blenlib/intern/mesh_boolean.cc
+++ b/source/blender/blenlib/intern/mesh_boolean.cc
@@ -28,8 +28,6 @@
# include "BLI_array.hh"
# include "BLI_assert.h"
# include "BLI_delaunay_2d.h"
-# include "BLI_double3.hh"
-# include "BLI_float3.hh"
# include "BLI_hash.hh"
# include "BLI_kdopbvh.h"
# include "BLI_map.hh"
@@ -37,8 +35,9 @@
# include "BLI_math_boolean.hh"
# include "BLI_math_geom.h"
# include "BLI_math_mpq.hh"
+# include "BLI_math_vec_mpq_types.hh"
+# include "BLI_math_vec_types.hh"
# include "BLI_mesh_intersect.hh"
-# include "BLI_mpq3.hh"
# include "BLI_set.hh"
# include "BLI_span.hh"
# include "BLI_stack.hh"
@@ -51,8 +50,8 @@
# include "BLI_mesh_boolean.hh"
# ifdef WITH_TBB
-# include "tbb/parallel_reduce.h"
-# include "tbb/spin_mutex.h"
+# include <tbb/parallel_reduce.h>
+# include <tbb/spin_mutex.h>
# endif
// # define PERFDEBUG
@@ -1370,6 +1369,11 @@ static bool is_pwn(const IMesh &tm, const TriMeshTopology &tmtopo)
}
threading::parallel_for(tris.index_range(), 2048, [&](IndexRange range) {
+ if (!is_pwn.load()) {
+ /* Early out if mesh is already determined to be non-pwn. */
+ return;
+ }
+
for (int j : range) {
const Edge &edge = tris[j].first;
int tot_orient = 0;
@@ -1395,9 +1399,7 @@ static bool is_pwn(const IMesh &tm, const TriMeshTopology &tmtopo)
std::cout << "edge causing non-pwn: " << edge << "\n";
}
is_pwn = false;
-# ifdef WITH_TBB
- tbb::task::self().cancel_group_execution();
-# endif
+ break;
}
}
});
@@ -1630,13 +1632,13 @@ static Edge find_good_sorting_edge(const Vert *testp,
ordinate[axis_next] = -abscissa[axis];
ordinate[axis_next_next] = 0;
/* By construction, dot(abscissa, ordinate) == 0, so they are perpendicular. */
- mpq3 normal = mpq3::cross(abscissa, ordinate);
+ mpq3 normal = math::cross(abscissa, ordinate);
if (dbg_level > 0) {
std::cout << "abscissa = " << abscissa << "\n";
std::cout << "ordinate = " << ordinate << "\n";
std::cout << "normal = " << normal << "\n";
}
- mpq_class nlen2 = normal.length_squared();
+ mpq_class nlen2 = math::length_squared(normal);
mpq_class max_abs_slope = -1;
Edge esort;
const Vector<Edge> &edges = tmtopo.vert_edges(closestp);
@@ -1645,12 +1647,12 @@ static Edge find_good_sorting_edge(const Vert *testp,
const mpq3 &co_other = v_other->co_exact;
mpq3 evec = co_other - co_closest;
/* Get projection of evec onto plane of abscissa and ordinate. */
- mpq3 proj_evec = evec - (mpq3::dot(evec, normal) / nlen2) * normal;
+ mpq3 proj_evec = evec - (math::dot(evec, normal) / nlen2) * normal;
/* The projection calculations along the abscissa and ordinate should
* be scaled by 1/abscissa and 1/ordinate respectively,
* but we can skip: it won't affect which `evec` has the maximum slope. */
- mpq_class evec_a = mpq3::dot(proj_evec, abscissa);
- mpq_class evec_o = mpq3::dot(proj_evec, ordinate);
+ mpq_class evec_a = math::dot(proj_evec, abscissa);
+ mpq_class evec_o = math::dot(proj_evec, ordinate);
if (dbg_level > 0) {
std::cout << "e = " << e << "\n";
std::cout << "v_other = " << v_other << "\n";
@@ -1788,8 +1790,8 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
ap = p;
ap -= a;
- mpq_class d1 = mpq3::dot_with_buffer(ab, ap, m);
- mpq_class d2 = mpq3::dot_with_buffer(ac, ap, m);
+ mpq_class d1 = math::dot_with_buffer(ab, ap, m);
+ mpq_class d2 = math::dot_with_buffer(ac, ap, m);
if (d1 <= 0 && d2 <= 0) {
/* Barycentric coordinates (1,0,0). */
*r_edge = -1;
@@ -1797,13 +1799,13 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
if (dbg_level > 0) {
std::cout << " answer = a\n";
}
- return mpq3::distance_squared_with_buffer(p, a, m);
+ return math::distance_squared_with_buffer(p, a, m);
}
/* Check if p in vertex region outside b. */
bp = p;
bp -= b;
- mpq_class d3 = mpq3::dot_with_buffer(ab, bp, m);
- mpq_class d4 = mpq3::dot_with_buffer(ac, bp, m);
+ mpq_class d3 = math::dot_with_buffer(ab, bp, m);
+ mpq_class d4 = math::dot_with_buffer(ac, bp, m);
if (d3 >= 0 && d4 <= d3) {
/* Barycentric coordinates (0,1,0). */
*r_edge = -1;
@@ -1811,7 +1813,7 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
if (dbg_level > 0) {
std::cout << " answer = b\n";
}
- return mpq3::distance_squared_with_buffer(p, b, m);
+ return math::distance_squared_with_buffer(p, b, m);
}
/* Check if p in region of ab. */
mpq_class vc = d1 * d4 - d3 * d2;
@@ -1826,13 +1828,13 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
if (dbg_level > 0) {
std::cout << " answer = on ab at " << r << "\n";
}
- return mpq3::distance_squared_with_buffer(p, r, m);
+ return math::distance_squared_with_buffer(p, r, m);
}
/* Check if p in vertex region outside c. */
cp = p;
cp -= c;
- mpq_class d5 = mpq3::dot_with_buffer(ab, cp, m);
- mpq_class d6 = mpq3::dot_with_buffer(ac, cp, m);
+ mpq_class d5 = math::dot_with_buffer(ab, cp, m);
+ mpq_class d6 = math::dot_with_buffer(ac, cp, m);
if (d6 >= 0 && d5 <= d6) {
/* Barycentric coordinates (0,0,1). */
*r_edge = -1;
@@ -1840,7 +1842,7 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
if (dbg_level > 0) {
std::cout << " answer = c\n";
}
- return mpq3::distance_squared_with_buffer(p, c, m);
+ return math::distance_squared_with_buffer(p, c, m);
}
/* Check if p in edge region of ac. */
mpq_class vb = d5 * d2 - d1 * d6;
@@ -1855,7 +1857,7 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
if (dbg_level > 0) {
std::cout << " answer = on ac at " << r << "\n";
}
- return mpq3::distance_squared_with_buffer(p, r, m);
+ return math::distance_squared_with_buffer(p, r, m);
}
/* Check if p in edge region of bc. */
mpq_class va = d3 * d6 - d5 * d4;
@@ -1871,7 +1873,7 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
if (dbg_level > 0) {
std::cout << " answer = on bc at " << r << "\n";
}
- return mpq3::distance_squared_with_buffer(p, r, m);
+ return math::distance_squared_with_buffer(p, r, m);
}
/* p inside face region. Compute barycentric coordinates (u,v,w). */
mpq_class denom = 1 / (va + vb + vc);
@@ -1887,7 +1889,7 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
if (dbg_level > 0) {
std::cout << " answer = inside at " << r << "\n";
}
- return mpq3::distance_squared_with_buffer(p, r, m);
+ return math::distance_squared_with_buffer(p, r, m);
}
static float closest_on_tri_to_point_float_dist_squared(const float3 &p,
@@ -2607,7 +2609,7 @@ static void test_tri_inside_shapes(const IMesh &tm,
double3 test_point = calc_point_inside_tri_db(tri_test);
/* Offset the test point a tiny bit in the tri_test normal direction. */
tri_test.populate_plane(false);
- double3 norm = tri_test.plane->norm.normalized();
+ double3 norm = math::normalize(tri_test.plane->norm);
const double offset_amount = 1e-5;
double3 offset_test_point = test_point + offset_amount * norm;
if (dbg_level > 0) {
@@ -2999,7 +3001,7 @@ static void init_face_merge_state(FaceMergeState *fms,
std::cout << "process tri = " << &tri << "\n";
}
BLI_assert(tri.plane_populated());
- if (double3::dot(norm, tri.plane->norm) <= 0.0) {
+ if (math::dot(norm, tri.plane->norm) <= 0.0) {
if (dbg_level > 0) {
std::cout << "triangle has wrong orientation, skipping\n";
}
@@ -3024,7 +3026,7 @@ static void init_face_merge_state(FaceMergeState *fms,
}
if (me_index == -1) {
double3 vec = new_me.v2->co - new_me.v1->co;
- new_me.len_squared = vec.length_squared();
+ new_me.len_squared = math::length_squared(vec);
new_me.orig = tri.edge_orig[i];
new_me.is_intersect = tri.is_intersect[i];
new_me.dissolvable = (new_me.orig == NO_INDEX && !new_me.is_intersect);
@@ -3264,7 +3266,7 @@ static Vector<Face *> merge_tris_for_face(Vector<int> tris,
bool done = false;
double3 first_tri_normal = tm.face(tris[0])->plane->norm;
double3 second_tri_normal = tm.face(tris[1])->plane->norm;
- if (tris.size() == 2 && double3::dot(first_tri_normal, second_tri_normal) > 0.0) {
+ if (tris.size() == 2 && math::dot(first_tri_normal, second_tri_normal) > 0.0) {
/* Is this a case where quad with one diagonal remained unchanged?
* Worth special handling because this case will be very common. */
Face &tri1 = *tm.face(tris[0]);
@@ -3329,7 +3331,7 @@ static bool approx_in_line(const double3 &a, const double3 &b, const double3 &c)
{
double3 vec1 = b - a;
double3 vec2 = c - b;
- double cos_ang = double3::dot(vec1.normalized(), vec2.normalized());
+ double cos_ang = math::dot(math::normalize(vec1), math::normalize(vec2));
return fabs(cos_ang - 1.0) < 1e-4;
}
@@ -3673,10 +3675,6 @@ static void dump_test_spec(IMesh &imesh)
}
}
-/**
- * Do the boolean operation op on the polygon mesh imesh_in.
- * See the header file for a complete description.
- */
IMesh boolean_mesh(IMesh &imesh,
BoolOpType op,
int nshapes,
diff --git a/source/blender/blenlib/intern/mesh_intersect.cc b/source/blender/blenlib/intern/mesh_intersect.cc
index 5651e52799e..982759ffcff 100644
--- a/source/blender/blenlib/intern/mesh_intersect.cc
+++ b/source/blender/blenlib/intern/mesh_intersect.cc
@@ -30,15 +30,13 @@
# include "BLI_array.hh"
# include "BLI_assert.h"
# include "BLI_delaunay_2d.h"
-# include "BLI_double3.hh"
-# include "BLI_float3.hh"
# include "BLI_hash.hh"
# include "BLI_kdopbvh.h"
# include "BLI_map.hh"
# include "BLI_math_boolean.hh"
# include "BLI_math_mpq.hh"
-# include "BLI_mpq2.hh"
-# include "BLI_mpq3.hh"
+# include "BLI_math_vec_mpq_types.hh"
+# include "BLI_math_vec_types.hh"
# include "BLI_polyfill_2d.h"
# include "BLI_set.hh"
# include "BLI_span.hh"
@@ -53,7 +51,7 @@
# include "BLI_mesh_intersect.hh"
# ifdef WITH_TBB
-# include "tbb/parallel_sort.h"
+# include <tbb/parallel_sort.h>
# endif
// # define PERFDEBUG
@@ -61,11 +59,11 @@
namespace blender::meshintersect {
# ifdef PERFDEBUG
-static void perfdata_init(void);
+static void perfdata_init();
static void incperfcount(int countnum);
static void bumpperfcount(int countnum, int amt);
static void doperfmax(int maxnum, int val);
-static void dump_perfdata(void);
+static void dump_perfdata();
# endif
/** For debugging, can disable threading in intersect code with this static constant. */
@@ -150,7 +148,6 @@ Plane::Plane(const double3 &norm, const double d) : norm(norm), d(d)
norm_exact = mpq3(0, 0, 0); /* Marks as "exact not yet populated". */
}
-/** This is wrong for degenerate planes, but we don't expect to call it on those. */
bool Plane::exact_populated() const
{
return norm_exact[0] != 0 || norm_exact[1] != 0 || norm_exact[2] != 0;
@@ -199,14 +196,14 @@ void Face::populate_plane(bool need_exact)
for (int i : index_range()) {
co[i] = vert[i]->co_exact;
}
- normal_exact = mpq3::cross_poly(co);
+ normal_exact = math::cross_poly(co.as_span());
}
else {
mpq3 tr02 = vert[0]->co_exact - vert[2]->co_exact;
mpq3 tr12 = vert[1]->co_exact - vert[2]->co_exact;
- normal_exact = mpq3::cross(tr02, tr12);
+ normal_exact = math::cross(tr02, tr12);
}
- mpq_class d_exact = -mpq3::dot(normal_exact, vert[0]->co_exact);
+ mpq_class d_exact = -math::dot(normal_exact, vert[0]->co_exact);
plane = new Plane(normal_exact, d_exact);
}
else {
@@ -216,14 +213,14 @@ void Face::populate_plane(bool need_exact)
for (int i : index_range()) {
co[i] = vert[i]->co;
}
- normal = double3::cross_poly(co);
+ normal = math::cross_poly(co.as_span());
}
else {
double3 tr02 = vert[0]->co - vert[2]->co;
double3 tr12 = vert[1]->co - vert[2]->co;
- normal = double3::cross_high_precision(tr02, tr12);
+ normal = math::cross(tr02, tr12);
}
- double d = -double3::dot(normal, vert[0]->co);
+ double d = -math::dot(normal, vert[0]->co);
plane = new Plane(normal, d);
}
}
@@ -803,11 +800,6 @@ std::ostream &operator<<(std::ostream &os, const IMesh &mesh)
return os;
}
-/**
- * Assume bounding boxes have been expanded by a sufficient epsilon on all sides
- * so that the comparisons against the bb bounds are sufficient to guarantee that
- * if an overlap or even touching could happen, this will return true.
- */
bool bbs_might_intersect(const BoundingBox &bb_a, const BoundingBox &bb_b)
{
return isect_aabb_aabb_v3(bb_a.min, bb_a.max, bb_b.min, bb_b.max);
@@ -1104,15 +1096,15 @@ static mpq2 project_3d_to_2d(const mpq3 &p3d, int proj_axis)
*/
static double supremum_dot_cross(const double3 &a, const double3 &b)
{
- double3 abs_a = double3::abs(a);
- double3 abs_b = double3::abs(b);
+ double3 abs_a = math::abs(a);
+ double3 abs_b = math::abs(b);
double3 c;
/* This is dot(cross(a, b), cross(a,b)) but using absolute values for a and b
* and always using + when operation is + or -. */
c[0] = abs_a[1] * abs_b[2] + abs_a[2] * abs_b[1];
c[1] = abs_a[2] * abs_b[0] + abs_a[0] * abs_b[2];
c[2] = abs_a[0] * abs_b[1] + abs_a[1] * abs_b[0];
- return double3::dot(c, c);
+ return math::dot(c, c);
}
/* The index of dot when inputs are plane_coords with index 1 is much higher.
@@ -1149,11 +1141,11 @@ static int filter_plane_side(const double3 &p,
const double3 &abs_plane_p,
const double3 &abs_plane_no)
{
- double d = double3::dot(p - plane_p, plane_no);
+ double d = math::dot(p - plane_p, plane_no);
if (d == 0.0) {
return 0;
}
- double supremum = double3::dot(abs_p + abs_plane_p, abs_plane_no);
+ double supremum = math::dot(abs_p + abs_plane_p, abs_plane_no);
double err_bound = supremum * index_plane_side * DBL_EPSILON;
if (fabs(d) > err_bound) {
return d > 0 ? 1 : -1;
@@ -1162,7 +1154,7 @@ static int filter_plane_side(const double3 &p,
}
/*
- * interesect_tri_tri and helper functions.
+ * #intersect_tri_tri and helper functions.
* This code uses the algorithm of Guigue and Devillers, as described
* in "Faster Triangle-Triangle Intersection Tests".
* Adapted from code by Eric Haines:
@@ -1184,9 +1176,9 @@ static inline mpq3 tti_interp(
ab -= b;
ac = a;
ac -= c;
- mpq_class den = mpq3::dot_with_buffer(ab, n, dotbuf);
+ mpq_class den = math::dot_with_buffer(ab, n, dotbuf);
BLI_assert(den != 0);
- mpq_class alpha = mpq3::dot_with_buffer(ac, n, dotbuf) / den;
+ mpq_class alpha = math::dot_with_buffer(ac, n, dotbuf) / den;
return a - alpha * ab;
}
@@ -1215,7 +1207,7 @@ static inline int tti_above(const mpq3 &a,
n.y = ba.z * ca.x - ba.x * ca.z;
n.z = ba.x * ca.y - ba.y * ca.x;
- return sgn(mpq3::dot_with_buffer(ad, n, dotbuf));
+ return sgn(math::dot_with_buffer(ad, n, dotbuf));
}
/**
@@ -1434,11 +1426,11 @@ static ITT_value intersect_tri_tri(const IMesh &tm, int t1, int t2)
const double3 &d_r2 = vr2->co;
const double3 &d_n2 = tri2.plane->norm;
- const double3 &abs_d_p1 = double3::abs(d_p1);
- const double3 &abs_d_q1 = double3::abs(d_q1);
- const double3 &abs_d_r1 = double3::abs(d_r1);
- const double3 &abs_d_r2 = double3::abs(d_r2);
- const double3 &abs_d_n2 = double3::abs(d_n2);
+ const double3 &abs_d_p1 = math::abs(d_p1);
+ const double3 &abs_d_q1 = math::abs(d_q1);
+ const double3 &abs_d_r1 = math::abs(d_r1);
+ const double3 &abs_d_r2 = math::abs(d_r2);
+ const double3 &abs_d_n2 = math::abs(d_n2);
int sp1 = filter_plane_side(d_p1, d_r2, d_n2, abs_d_p1, abs_d_r2, abs_d_n2);
int sq1 = filter_plane_side(d_q1, d_r2, d_n2, abs_d_q1, abs_d_r2, abs_d_n2);
@@ -1454,9 +1446,9 @@ static ITT_value intersect_tri_tri(const IMesh &tm, int t1, int t2)
}
const double3 &d_n1 = tri1.plane->norm;
- const double3 &abs_d_p2 = double3::abs(d_p2);
- const double3 &abs_d_q2 = double3::abs(d_q2);
- const double3 &abs_d_n1 = double3::abs(d_n1);
+ const double3 &abs_d_p2 = math::abs(d_p2);
+ const double3 &abs_d_q2 = math::abs(d_q2);
+ const double3 &abs_d_n1 = math::abs(d_n1);
int sp2 = filter_plane_side(d_p2, d_r1, d_n1, abs_d_p2, abs_d_r1, abs_d_n1);
int sq2 = filter_plane_side(d_q2, d_r1, d_n1, abs_d_q2, abs_d_r1, abs_d_n1);
@@ -1483,17 +1475,17 @@ static ITT_value intersect_tri_tri(const IMesh &tm, int t1, int t2)
if (sp1 == 0) {
buf[0] = p1;
buf[0] -= r2;
- sp1 = sgn(mpq3::dot_with_buffer(buf[0], n2, buf[1]));
+ sp1 = sgn(math::dot_with_buffer(buf[0], n2, buf[1]));
}
if (sq1 == 0) {
buf[0] = q1;
buf[0] -= r2;
- sq1 = sgn(mpq3::dot_with_buffer(buf[0], n2, buf[1]));
+ sq1 = sgn(math::dot_with_buffer(buf[0], n2, buf[1]));
}
if (sr1 == 0) {
buf[0] = r1;
buf[0] -= r2;
- sr1 = sgn(mpq3::dot_with_buffer(buf[0], n2, buf[1]));
+ sr1 = sgn(math::dot_with_buffer(buf[0], n2, buf[1]));
}
if (dbg_level > 1) {
@@ -1515,17 +1507,17 @@ static ITT_value intersect_tri_tri(const IMesh &tm, int t1, int t2)
if (sp2 == 0) {
buf[0] = p2;
buf[0] -= r1;
- sp2 = sgn(mpq3::dot_with_buffer(buf[0], n1, buf[1]));
+ sp2 = sgn(math::dot_with_buffer(buf[0], n1, buf[1]));
}
if (sq2 == 0) {
buf[0] = q2;
buf[0] -= r1;
- sq2 = sgn(mpq3::dot_with_buffer(buf[0], n1, buf[1]));
+ sq2 = sgn(math::dot_with_buffer(buf[0], n1, buf[1]));
}
if (sr2 == 0) {
buf[0] = r2;
buf[0] -= r1;
- sr2 = sgn(mpq3::dot_with_buffer(buf[0], n1, buf[1]));
+ sr2 = sgn(math::dot_with_buffer(buf[0], n1, buf[1]));
}
if (dbg_level > 1) {
@@ -1727,7 +1719,7 @@ static CDT_data prepare_cdt_input(const IMesh &tm, int t, const Vector<ITT_value
BLI_assert(tm.face(t)->plane_populated());
ans.t_plane = tm.face(t)->plane;
BLI_assert(ans.t_plane->exact_populated());
- ans.proj_axis = mpq3::dominant_axis(ans.t_plane->norm_exact);
+ ans.proj_axis = math::dominant_axis(ans.t_plane->norm_exact);
prepare_need_tri(ans, tm, t);
for (const ITT_value &itt : itts) {
switch (itt.kind) {
@@ -1763,7 +1755,7 @@ static CDT_data prepare_cdt_input_for_cluster(const IMesh &tm,
BLI_assert(tm.face(t0)->plane_populated());
ans.t_plane = tm.face(t0)->plane;
BLI_assert(ans.t_plane->exact_populated());
- ans.proj_axis = mpq3::dominant_axis(ans.t_plane->norm_exact);
+ ans.proj_axis = math::dominant_axis(ans.t_plane->norm_exact);
for (const int t : cl) {
prepare_need_tri(ans, tm, t);
}
@@ -2010,9 +2002,9 @@ static bool is_quad_flip_first_third(const double3 &v1,
const double3 &normal)
{
double3 dir_v3v1 = v3 - v1;
- double3 tangent = double3::cross_high_precision(dir_v3v1, normal);
- double dot = double3::dot(v1, tangent);
- return (double3::dot(v4, tangent) >= dot) || (double3::dot(v2, tangent) <= dot);
+ double3 tangent = math::cross(dir_v3v1, normal);
+ double dot = math::dot(v1, tangent);
+ return (math::dot(v4, tangent) >= dot) || (math::dot(v2, tangent) <= dot);
}
/**
@@ -2130,7 +2122,7 @@ static Array<Face *> exact_triangulate_poly(Face *f, IMeshArena *arena)
f->populate_plane(false);
}
const double3 &poly_normal = f->plane->norm;
- int axis = double3::dominant_axis(poly_normal);
+ int axis = math::dominant_axis(poly_normal);
/* If project down y axis as opposed to x or z, the orientation
* of the polygon will be reversed.
* Yet another reversal happens if the poly normal in the dominant
@@ -2209,15 +2201,15 @@ static bool face_is_degenerate(const Face *f)
}
double3 da = v2->co - v0->co;
double3 db = v2->co - v1->co;
- double3 dab = double3::cross_high_precision(da, db);
- double dab_length_squared = dab.length_squared();
+ double3 dab = math::cross(da, db);
+ double dab_length_squared = math::length_squared(dab);
double err_bound = supremum_dot_cross(dab, dab) * index_dot_cross * DBL_EPSILON;
if (dab_length_squared > err_bound) {
return false;
}
mpq3 a = v2->co_exact - v0->co_exact;
mpq3 b = v2->co_exact - v1->co_exact;
- mpq3 ab = mpq3::cross(a, b);
+ mpq3 ab = math::cross(a, b);
if (ab.x == 0 && ab.y == 0 && ab.z == 0) {
return true;
}
@@ -2225,8 +2217,7 @@ static bool face_is_degenerate(const Face *f)
return false;
}
-/** Fast check for degenerate tris. Only tests for when verts are identical,
- * not cases where there are zero-length edges. */
+/** Fast check for degenerate tris. It is OK if it returns true for nearly degenerate triangles. */
static bool any_degenerate_tris_fast(const Array<Face *> triangulation)
{
for (const Face *f : triangulation) {
@@ -2236,6 +2227,23 @@ static bool any_degenerate_tris_fast(const Array<Face *> triangulation)
if (v0 == v1 || v0 == v2 || v1 == v2) {
return true;
}
+ double3 da = v2->co - v0->co;
+ double3 db = v2->co - v1->co;
+ double da_length_squared = math::length_squared(da);
+ double db_length_squared = math::length_squared(db);
+ if (da_length_squared == 0.0 || db_length_squared == 0.0) {
+ return true;
+ }
+ /* |da x db| = |da| |db| sin t, where t is angle between them.
+ * The triangle is almost degenerate if sin t is almost 0.
+ * sin^2 t = |da x db|^2 / (|da|^2 |db|^2)
+ */
+ double3 dab = math::cross(da, db);
+ double dab_length_squared = math::length_squared(dab);
+ double sin_squared_t = dab_length_squared / (da_length_squared * db_length_squared);
+ if (sin_squared_t < 1e-8) {
+ return true;
+ }
}
return false;
}
@@ -2260,12 +2268,6 @@ static Array<Face *> triangulate_poly(Face *f, IMeshArena *arena)
return ans;
}
-/**
- * Return an #IMesh that is a triangulation of a mesh with general
- * polygonal faces, #IMesh.
- * Added diagonals will be distinguishable by having edge original
- * indices of #NO_INDEX.
- */
IMesh triangulate_polymesh(IMesh &imesh, IMeshArena *arena)
{
Vector<Face *> face_tris;
@@ -2552,79 +2554,6 @@ static void calc_overlap_itts(Map<std::pair<int, int>, ITT_value> &itt_map,
}
/**
- * Data needed for parallelization of calc_subdivided_non_cluster_tris.
- */
-struct OverlapTriRange {
- int tri_index;
- int overlap_start;
- int len;
-};
-struct SubdivideTrisData {
- Array<IMesh> &r_tri_subdivided;
- const IMesh &tm;
- const Map<std::pair<int, int>, ITT_value> &itt_map;
- Span<BVHTreeOverlap> overlap;
- IMeshArena *arena;
-
- /* This vector gives, for each triangle in tm that has an intersection
- * we want to calculate: what the index of that triangle in tm is,
- * where it starts in the ov structure as indexA, and how many
- * overlap pairs have that same indexA (they will be continuous). */
- Vector<OverlapTriRange> overlap_tri_range;
-
- SubdivideTrisData(Array<IMesh> &r_tri_subdivided,
- const IMesh &tm,
- const Map<std::pair<int, int>, ITT_value> &itt_map,
- Span<BVHTreeOverlap> overlap,
- IMeshArena *arena)
- : r_tri_subdivided(r_tri_subdivided),
- tm(tm),
- itt_map(itt_map),
- overlap(overlap),
- arena(arena)
- {
- }
-};
-
-static void calc_subdivided_tri_range_func(void *__restrict userdata,
- const int iter,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- constexpr int dbg_level = 0;
- SubdivideTrisData *data = static_cast<SubdivideTrisData *>(userdata);
- OverlapTriRange &otr = data->overlap_tri_range[iter];
- int t = otr.tri_index;
- if (dbg_level > 0) {
- std::cout << "calc_subdivided_tri_range_func\nt=" << t << " start=" << otr.overlap_start
- << " len=" << otr.len << "\n";
- }
- constexpr int inline_capacity = 100;
- Vector<ITT_value, inline_capacity> itts(otr.len);
- for (int j = otr.overlap_start; j < otr.overlap_start + otr.len; ++j) {
- int t_other = data->overlap[j].indexB;
- std::pair<int, int> key = canon_int_pair(t, t_other);
- ITT_value itt;
- if (data->itt_map.contains(key)) {
- itt = data->itt_map.lookup(key);
- }
- if (itt.kind != INONE) {
- itts.append(itt);
- }
- if (dbg_level > 0) {
- std::cout << " tri t" << t_other << "; result = " << itt << "\n";
- }
- }
- if (itts.size() > 0) {
- CDT_data cd_data = prepare_cdt_input(data->tm, t, itts);
- do_cdt(cd_data);
- data->r_tri_subdivided[t] = extract_subdivided_tri(cd_data, data->tm, t, data->arena);
- if (dbg_level > 0) {
- std::cout << "subdivide output\n" << data->r_tri_subdivided[t];
- }
- }
-}
-
-/**
* For each triangle in tm, fill in the corresponding slot in
* r_tri_subdivided with the result of intersecting it with
* all the other triangles in the mesh, if it intersects any others.
@@ -2642,10 +2571,14 @@ static void calc_subdivided_non_cluster_tris(Array<IMesh> &r_tri_subdivided,
std::cout << "\nCALC_SUBDIVIDED_TRIS\n\n";
}
Span<BVHTreeOverlap> overlap = ov.overlap();
- SubdivideTrisData data(r_tri_subdivided, tm, itt_map, overlap, arena);
+ struct OverlapTriRange {
+ int tri_index;
+ int overlap_start;
+ int len;
+ };
+ Vector<OverlapTriRange> overlap_tri_range;
int overlap_tot = overlap.size();
- data.overlap_tri_range = Vector<OverlapTriRange>();
- data.overlap_tri_range.reserve(overlap_tot);
+ overlap_tri_range.reserve(overlap_tot);
int overlap_index = 0;
while (overlap_index < overlap_tot) {
int t = overlap[overlap_index].indexA;
@@ -2660,7 +2593,7 @@ static void calc_subdivided_non_cluster_tris(Array<IMesh> &r_tri_subdivided,
int len = i - overlap_index + 1;
if (!(len == 1 && overlap[overlap_index].indexB == t)) {
OverlapTriRange range = {t, overlap_index, len};
- data.overlap_tri_range.append(range);
+ overlap_tri_range.append(range);
# ifdef PERFDEBUG
bumpperfcount(0, len); /* Non-cluster overlaps. */
# endif
@@ -2668,13 +2601,50 @@ static void calc_subdivided_non_cluster_tris(Array<IMesh> &r_tri_subdivided,
}
overlap_index = i + 1;
}
- int overlap_tri_range_tot = data.overlap_tri_range.size();
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = 50;
- settings.use_threading = intersect_use_threading;
- BLI_task_parallel_range(
- 0, overlap_tri_range_tot, &data, calc_subdivided_tri_range_func, &settings);
+ int overlap_tri_range_tot = overlap_tri_range.size();
+ Array<CDT_data> cd_data(overlap_tri_range_tot);
+ int grain_size = 64;
+ threading::parallel_for(overlap_tri_range.index_range(), grain_size, [&](IndexRange range) {
+ for (int otr_index : range) {
+ OverlapTriRange &otr = overlap_tri_range[otr_index];
+ int t = otr.tri_index;
+ if (dbg_level > 0) {
+ std::cout << "handling overlap range\nt=" << t << " start=" << otr.overlap_start
+ << " len=" << otr.len << "\n";
+ }
+ constexpr int inline_capacity = 100;
+ Vector<ITT_value, inline_capacity> itts(otr.len);
+ for (int j = otr.overlap_start; j < otr.overlap_start + otr.len; ++j) {
+ int t_other = overlap[j].indexB;
+ std::pair<int, int> key = canon_int_pair(t, t_other);
+ ITT_value itt;
+ if (itt_map.contains(key)) {
+ itt = itt_map.lookup(key);
+ }
+ if (itt.kind != INONE) {
+ itts.append(itt);
+ }
+ if (dbg_level > 0) {
+ std::cout << " tri t" << t_other << "; result = " << itt << "\n";
+ }
+ }
+ if (itts.size() > 0) {
+ cd_data[otr_index] = prepare_cdt_input(tm, t, itts);
+ do_cdt(cd_data[otr_index]);
+ }
+ }
+ });
+ /* Extract the new faces serially, so that Boolean is repeatable regardless of parallelism. */
+ for (int otr_index : overlap_tri_range.index_range()) {
+ CDT_data &cdd = cd_data[otr_index];
+ if (cdd.vert.size() > 0) {
+ int t = overlap_tri_range[otr_index].tri_index;
+ r_tri_subdivided[t] = extract_subdivided_tri(cdd, tm, t, arena);
+ if (dbg_level > 1) {
+ std::cout << "subdivide output for tri " << t << " = " << r_tri_subdivided[t];
+ }
+ }
+ }
/* Now have to put in the triangles that are the same as the input ones, and not in clusters.
*/
threading::parallel_for(tm.face_index_range(), 2048, [&](IndexRange range) {
@@ -2978,7 +2948,6 @@ static IMesh remove_degenerate_tris(const IMesh &tm_in)
return ans;
}
-/* This is the main routine for calculating the self_intersection of a triangle mesh. */
IMesh trimesh_self_intersect(const IMesh &tm_in, IMeshArena *arena)
{
return trimesh_nary_intersect(
@@ -3153,9 +3122,6 @@ static std::ostream &operator<<(std::ostream &os, const ITT_value &itt)
return os;
}
-/**
- * Writing the obj_mesh has the side effect of populating verts.
- */
void write_obj_mesh(IMesh &m, const std::string &objname)
{
/* Would like to use #BKE_tempdir_base() here, but that brings in dependence on kernel library.
@@ -3211,7 +3177,7 @@ struct PerfCounts {
static PerfCounts *perfdata = nullptr;
-static void perfdata_init(void)
+static void perfdata_init()
{
perfdata = new PerfCounts;
@@ -3263,7 +3229,7 @@ static void doperfmax(int maxnum, int val)
perfdata->max[maxnum] = max_ii(perfdata->max[maxnum], val);
}
-static void dump_perfdata(void)
+static void dump_perfdata()
{
std::cout << "\nPERFDATA\n";
for (int i : perfdata->count.index_range()) {
diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c
index 9850de69b5a..ce4dee16d32 100644
--- a/source/blender/blenlib/intern/noise.c
+++ b/source/blender/blenlib/intern/noise.c
@@ -429,15 +429,17 @@ static float orgBlenderNoise(float x, float y, float z)
return n;
}
-/* as orgBlenderNoise(), returning signed noise */
static float orgBlenderNoiseS(float x, float y, float z)
{
+ /* NOTE: As #orgBlenderNoise(), returning signed noise. */
+
return (2.0f * orgBlenderNoise(x, y, z) - 1.0f);
}
-/* separated from orgBlenderNoise above, with scaling */
float BLI_noise_hnoise(float noisesize, float x, float y, float z)
{
+ /* NOTE: Separated from orgBlenderNoise, with scaling. */
+
if (noisesize == 0.0f) {
return 0.0f;
}
@@ -447,7 +449,6 @@ float BLI_noise_hnoise(float noisesize, float x, float y, float z)
return orgBlenderNoise(x, y, z);
}
-/* original turbulence functions */
float BLI_noise_turbulence(float noisesize, float x, float y, float z, int nr)
{
float s, d = 0.5, div = 1.0;
@@ -926,8 +927,6 @@ static float dist_Minkovsky(float x, float y, float z, float e)
return powf(powf(fabsf(x), e) + powf(fabsf(y), e) + powf(fabsf(z), e), 1.0f / e);
}
-/* Not 'pure' Worley, but the results are virtually the same.
- * Returns distances in da and point coords in pa */
void BLI_noise_voronoi(float x, float y, float z, float *da, float *pa, float me, int dtype)
{
float (*distfunc)(float, float, float, float);
@@ -1137,13 +1136,11 @@ static float BLI_cellNoiseU(float x, float y, float z)
return ((float)(n * (n * n * 15731 + 789221) + 1376312589) / 4294967296.0f);
}
-/* idem, signed */
float BLI_noise_cell(float x, float y, float z)
{
return (2.0f * BLI_cellNoiseU(x, y, z) - 1.0f);
}
-/* returns a vector/point/color in ca, using point hasharray directly */
void BLI_noise_cell_v3(float x, float y, float z, float ca[3])
{
/* avoid precision issues on unit coordinates */
@@ -1166,9 +1163,6 @@ void BLI_noise_cell_v3(float x, float y, float z, float ca[3])
/** \name Public API's
* \{ */
-/**
- * newnoise: generic noise function for use with different `noisebasis`.
- */
float BLI_noise_generic_noise(
float noisesize, float x, float y, float z, bool hard, int noisebasis)
{
@@ -1226,7 +1220,6 @@ float BLI_noise_generic_noise(
return noisefunc(x, y, z);
}
-/* newnoise: generic turbulence function for use with different noisebasis */
float BLI_noise_generic_turbulence(
float noisesize, float x, float y, float z, int oct, bool hard, int noisebasis)
{
@@ -1289,21 +1282,12 @@ float BLI_noise_generic_turbulence(
return sum;
}
-/*
- * The following code is based on Ken Musgrave's explanations and sample
- * source code in the book "Texturing and Modeling: A procedural approach"
- */
-
-/**
- * Procedural `fBm` evaluated at "point"; returns value stored in "value".
- *
- * \param H: is the fractal increment parameter.
- * \param lacunarity: is the gap between successive frequencies.
- * \param octaves: is the number of frequencies in the `fBm`.
- */
float BLI_noise_mg_fbm(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis)
{
+ /* The following code is based on Ken Musgrave's explanations and sample
+ * source code in the book "Texturing and Modeling: A procedural approach". */
+
float (*noisefunc)(float, float, float);
switch (noisebasis) {
case 1:
@@ -1358,24 +1342,13 @@ float BLI_noise_mg_fbm(
} /* fBm() */
-/**
- * Procedural multi-fractal evaluated at "point";
- * returns value stored in "value".
- *
- * \param H: determines the highest fractal dimension.
- * \param lacunarity: is gap between successive frequencies.
- * \param octaves: is the number of frequencies in the `fBm`.
- *
- * \note There used to be a parameter called `offset`, old docs read:
- * is the zero offset, which determines multi-fractality.
- */
-
-/* this one is in fact rather confusing,
- * there seem to be errors in the original source code (in all three versions of proc.text&mod),
- * I modified it to something that made sense to me, so it might be wrong... */
float BLI_noise_mg_multi_fractal(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis)
{
+ /* This one is in fact rather confusing,
+ * there seem to be errors in the original source code (in all three versions of proc.text&mod),
+ * I modified it to something that made sense to me, so it might be wrong. */
+
float (*noisefunc)(float, float, float);
switch (noisebasis) {
case 1:
@@ -1426,18 +1399,8 @@ float BLI_noise_mg_multi_fractal(
}
return value;
+}
-} /* multifractal() */
-
-/**
- * Heterogeneous procedural terrain function: stats by altitude method.
- * Evaluated at "point"; returns value stored in "value".
- *
- * \param H: Determines the fractal dimension of the roughest areas.
- * \param lacunarity: Is the gap between successive frequencies.
- * \param octaves: Is the number of frequencies in the `fBm`.
- * \param offset: Raises the terrain from `sea level`.
- */
float BLI_noise_mg_hetero_terrain(float x,
float y,
float z,
@@ -1508,13 +1471,6 @@ float BLI_noise_mg_hetero_terrain(float x,
return value;
}
-/* Hybrid additive/multiplicative multifractal terrain model.
- *
- * Some good parameter values to start with:
- *
- * H: 0.25
- * offset: 0.7
- */
float BLI_noise_mg_hybrid_multi_fractal(float x,
float y,
float z,
@@ -1591,14 +1547,6 @@ float BLI_noise_mg_hybrid_multi_fractal(float x,
} /* HybridMultifractal() */
-/* Ridged multifractal terrain model.
- *
- * Some good parameter values to start with:
- *
- * H: 1.0
- * offset: 1.0
- * gain: 2.0
- */
float BLI_noise_mg_ridged_multi_fractal(float x,
float y,
float z,
@@ -1670,9 +1618,6 @@ float BLI_noise_mg_ridged_multi_fractal(float x,
return result;
} /* RidgedMultifractal() */
-/* "Variable Lacunarity Noise"
- * A distorted variety of Perlin noise.
- */
float BLI_noise_mg_variable_lacunarity(
float x, float y, float z, float distortion, int nbas1, int nbas2)
{
diff --git a/source/blender/blenlib/intern/noise.cc b/source/blender/blenlib/intern/noise.cc
index e80975f618c..21816fcd595 100644
--- a/source/blender/blenlib/intern/noise.cc
+++ b/source/blender/blenlib/intern/noise.cc
@@ -46,23 +46,22 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <algorithm>
#include <cmath>
#include <cstdint>
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
-#include "BLI_float4.hh"
+#include "BLI_math_base_safe.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_noise.hh"
#include "BLI_utildefines.h"
namespace blender::noise {
-/* ------------------------------
- * Jenkins Lookup3 Hash Functions
- * ------------------------------
+
+/* -------------------------------------------------------------------- */
+/** \name Jenkins Lookup3 Hash Functions
*
* https://burtleburtle.net/bob/c/lookup3.c
- *
- */
+ * \{ */
BLI_INLINE uint32_t hash_bit_rotate(uint32_t x, uint32_t k)
{
@@ -222,34 +221,76 @@ float hash_to_float(uint32_t kx, uint32_t ky, uint32_t kz, uint32_t kw)
float hash_float_to_float(float k)
{
- return hash_to_float(hash_float(k));
+ return uint_to_float_01(hash_float(k));
}
float hash_float_to_float(float2 k)
{
- return hash_to_float(hash_float(k));
+ return uint_to_float_01(hash_float(k));
}
float hash_float_to_float(float3 k)
{
- return hash_to_float(hash_float(k));
+ return uint_to_float_01(hash_float(k));
}
float hash_float_to_float(float4 k)
{
- return hash_to_float(hash_float(k));
+ return uint_to_float_01(hash_float(k));
+}
+
+float2 hash_float_to_float2(float2 k)
+{
+ return float2(hash_float_to_float(k), hash_float_to_float(float3(k.x, k.y, 1.0)));
+}
+
+float3 hash_float_to_float3(float k)
+{
+ return float3(hash_float_to_float(k),
+ hash_float_to_float(float2(k, 1.0)),
+ hash_float_to_float(float2(k, 2.0)));
+}
+
+float3 hash_float_to_float3(float2 k)
+{
+ return float3(hash_float_to_float(k),
+ hash_float_to_float(float3(k.x, k.y, 1.0)),
+ hash_float_to_float(float3(k.x, k.y, 2.0)));
+}
+
+float3 hash_float_to_float3(float3 k)
+{
+ return float3(hash_float_to_float(k),
+ hash_float_to_float(float4(k.x, k.y, k.z, 1.0)),
+ hash_float_to_float(float4(k.x, k.y, k.z, 2.0)));
+}
+
+float3 hash_float_to_float3(float4 k)
+{
+ return float3(hash_float_to_float(k),
+ hash_float_to_float(float4(k.z, k.x, k.w, k.y)),
+ hash_float_to_float(float4(k.w, k.z, k.y, k.x)));
+}
+
+float4 hash_float_to_float4(float4 k)
+{
+ return float4(hash_float_to_float(k),
+ hash_float_to_float(float4(k.w, k.x, k.y, k.z)),
+ hash_float_to_float(float4(k.z, k.w, k.x, k.y)),
+ hash_float_to_float(float4(k.y, k.z, k.w, k.x)));
}
-/* ------------
- * Perlin Noise
- * ------------
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Perlin Noise
*
* Perlin, Ken. "Improving noise." Proceedings of the 29th annual conference on Computer graphics
* and interactive techniques. 2002.
*
* This implementation is functionally identical to the implementations in EEVEE, OSL, and SVM. So
* any changes should be applied in all relevant implementations.
- */
+ * \{ */
/* Linear Interpolation. */
BLI_INLINE float mix(float v0, float v1, float x)
@@ -367,7 +408,7 @@ BLI_INLINE float noise_grad(uint32_t hash, float x, float y, float z)
{
uint32_t h = hash & 15u;
float u = h < 8u ? x : y;
- float vt = ((h == 12u) || (h == 14u)) ? x : z;
+ float vt = ELEM(h, 12u, 14u) ? x : z;
float v = h < 4u ? y : vt;
return negate_if(u, h & 1u) + negate_if(v, h & 2u);
}
@@ -539,7 +580,7 @@ template<typename T> float perlin_fractal_template(T position, float octaves, fl
float amp = 1.0f;
float maxamp = 0.0f;
float sum = 0.0f;
- octaves = CLAMPIS(octaves, 0.0f, 16.0f);
+ octaves = CLAMPIS(octaves, 0.0f, 15.0f);
int n = static_cast<int>(octaves);
for (int i = 0; i <= n; i++) {
float t = perlin(fscale * position);
@@ -714,4 +755,1617 @@ float3 perlin_float3_fractal_distorted(float4 position,
perlin_fractal(position + random_float4_offset(5.0f), octaves, roughness));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Musgrave Noise
+ * \{ */
+
+float musgrave_fBm(const float co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped)
+{
+ /* From "Texturing and Modelling: A procedural approach". */
+
+ float p = co;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ const float pwHL = powf(lacunarity, -H);
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value += perlin_signed(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * perlin_signed(p) * pwr;
+ }
+
+ return value;
+}
+
+float musgrave_multi_fractal(const float co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped)
+{
+ float p = co;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ const float pwHL = powf(lacunarity, -H);
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * perlin_signed(p) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * perlin_signed(p) + 1.0f); /* correct? */
+ }
+
+ return value;
+}
+
+float musgrave_hetero_terrain(const float co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped,
+ const float offset)
+{
+ float p = co;
+ const float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + perlin_signed(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ float increment = (perlin_signed(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float increment = (perlin_signed(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+float musgrave_hybrid_multi_fractal(const float co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped,
+ const float offset,
+ const float gain)
+{
+ float p = co;
+ const float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = perlin_signed(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 1; (weight > 0.001f) && (i < (int)octaves); i++) {
+ if (weight > 1.0f) {
+ weight = 1.0f;
+ }
+
+ float signal = (perlin_signed(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * ((perlin_signed(p) + offset) * pwr);
+ }
+
+ return value;
+}
+
+float musgrave_ridged_multi_fractal(const float co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped,
+ const float offset,
+ const float gain)
+{
+ float p = co;
+ const float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabsf(perlin_signed(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0f;
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = CLAMPIS(signal * gain, 0.0f, 1.0f);
+ signal = offset - fabsf(perlin_signed(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+float musgrave_fBm(const float2 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped)
+{
+ /* From "Texturing and Modelling: A procedural approach". */
+
+ float2 p = co;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ const float pwHL = powf(lacunarity, -H);
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value += perlin_signed(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * perlin_signed(p) * pwr;
+ }
+
+ return value;
+}
+
+float musgrave_multi_fractal(const float2 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped)
+{
+ float2 p = co;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ const float pwHL = powf(lacunarity, -H);
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * perlin_signed(p) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * perlin_signed(p) + 1.0f); /* correct? */
+ }
+
+ return value;
+}
+
+float musgrave_hetero_terrain(const float2 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped,
+ const float offset)
+{
+ float2 p = co;
+ const float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + perlin_signed(p);
+ p *= lacunarity;
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 1; i < (int)octaves; i++) {
+ float increment = (perlin_signed(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float increment = (perlin_signed(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+float musgrave_hybrid_multi_fractal(const float2 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped,
+ const float offset,
+ const float gain)
+{
+ float2 p = co;
+ const float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = perlin_signed(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 1; (weight > 0.001f) && (i < (int)octaves); i++) {
+ if (weight > 1.0f) {
+ weight = 1.0f;
+ }
+
+ float signal = (perlin_signed(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * ((perlin_signed(p) + offset) * pwr);
+ }
+
+ return value;
+}
+
+float musgrave_ridged_multi_fractal(const float2 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped,
+ const float offset,
+ const float gain)
+{
+ float2 p = co;
+ const float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabsf(perlin_signed(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0f;
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = CLAMPIS(signal * gain, 0.0f, 1.0f);
+ signal = offset - fabsf(perlin_signed(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+float musgrave_fBm(const float3 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped)
+{
+ /* From "Texturing and Modelling: A procedural approach". */
+
+ float3 p = co;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ const float pwHL = powf(lacunarity, -H);
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value += perlin_signed(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * perlin_signed(p) * pwr;
+ }
+
+ return value;
+}
+
+float musgrave_multi_fractal(const float3 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped)
+{
+ float3 p = co;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ const float pwHL = powf(lacunarity, -H);
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * perlin_signed(p) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * perlin_signed(p) + 1.0f); /* correct? */
+ }
+
+ return value;
+}
+
+float musgrave_hetero_terrain(const float3 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped,
+ const float offset)
+{
+ float3 p = co;
+ const float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + perlin_signed(p);
+ p *= lacunarity;
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 1; i < (int)octaves; i++) {
+ float increment = (perlin_signed(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float increment = (perlin_signed(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+float musgrave_hybrid_multi_fractal(const float3 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped,
+ const float offset,
+ const float gain)
+{
+ float3 p = co;
+ const float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = perlin_signed(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 1; (weight > 0.001f) && (i < (int)octaves); i++) {
+ if (weight > 1.0f) {
+ weight = 1.0f;
+ }
+
+ float signal = (perlin_signed(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * ((perlin_signed(p) + offset) * pwr);
+ }
+
+ return value;
+}
+
+float musgrave_ridged_multi_fractal(const float3 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped,
+ const float offset,
+ const float gain)
+{
+ float3 p = co;
+ const float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabsf(perlin_signed(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0f;
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = CLAMPIS(signal * gain, 0.0f, 1.0f);
+ signal = offset - fabsf(perlin_signed(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+float musgrave_fBm(const float4 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped)
+{
+ /* From "Texturing and Modelling: A procedural approach". */
+
+ float4 p = co;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ const float pwHL = powf(lacunarity, -H);
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value += perlin_signed(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * perlin_signed(p) * pwr;
+ }
+
+ return value;
+}
+
+float musgrave_multi_fractal(const float4 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped)
+{
+ float4 p = co;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ const float pwHL = powf(lacunarity, -H);
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * perlin_signed(p) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * perlin_signed(p) + 1.0f); /* correct? */
+ }
+
+ return value;
+}
+
+float musgrave_hetero_terrain(const float4 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped,
+ const float offset)
+{
+ float4 p = co;
+ const float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + perlin_signed(p);
+ p *= lacunarity;
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 1; i < (int)octaves; i++) {
+ float increment = (perlin_signed(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ float increment = (perlin_signed(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+float musgrave_hybrid_multi_fractal(const float4 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped,
+ const float offset,
+ const float gain)
+{
+ float4 p = co;
+ const float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = perlin_signed(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 1; (weight > 0.001f) && (i < (int)octaves); i++) {
+ if (weight > 1.0f) {
+ weight = 1.0f;
+ }
+
+ float signal = (perlin_signed(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ const float rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * ((perlin_signed(p) + offset) * pwr);
+ }
+
+ return value;
+}
+
+float musgrave_ridged_multi_fractal(const float4 co,
+ const float H,
+ const float lacunarity,
+ const float octaves_unclamped,
+ const float offset,
+ const float gain)
+{
+ float4 p = co;
+ const float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabsf(perlin_signed(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0f;
+
+ const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
+
+ for (int i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = CLAMPIS(signal * gain, 0.0f, 1.0f);
+ signal = offset - fabsf(perlin_signed(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Voronoi Noise
+ *
+ * \note Ported from Cycles code.
+ *
+ * Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez.
+ *
+ * Smooth Voronoi:
+ *
+ * - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
+ *
+ * Distance To Edge based on:
+ *
+ * - https://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm
+ * - https://www.shadertoy.com/view/ldl3W8
+ *
+ * With optimization to change -2..2 scan window to -1..1 for better performance,
+ * as explained in https://www.shadertoy.com/view/llG3zy.
+ * \{ */
+
+/* **** 1D Voronoi **** */
+
+/* Ensure to align with DNA. */
+enum {
+ NOISE_SHD_VORONOI_EUCLIDEAN = 0,
+ NOISE_SHD_VORONOI_MANHATTAN = 1,
+ NOISE_SHD_VORONOI_CHEBYCHEV = 2,
+ NOISE_SHD_VORONOI_MINKOWSKI = 3,
+};
+
+BLI_INLINE float voronoi_distance(const float a, const float b)
+{
+ return fabsf(b - a);
+}
+
+void voronoi_f1(
+ const float w, const float randomness, float *r_distance, float3 *r_color, float *r_w)
+{
+ const float cellPosition = floorf(w);
+ const float localPosition = w - cellPosition;
+
+ float minDistance = 8.0f;
+ float targetOffset = 0.0f;
+ float targetPosition = 0.0f;
+ for (int i = -1; i <= 1; i++) {
+ const float cellOffset = i;
+ const float pointPosition = cellOffset +
+ hash_float_to_float(cellPosition + cellOffset) * randomness;
+ const float distanceToPoint = voronoi_distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ if (r_distance != nullptr) {
+ *r_distance = minDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + targetOffset);
+ }
+ if (r_w != nullptr) {
+ *r_w = targetPosition + cellPosition;
+ }
+}
+
+void voronoi_smooth_f1(const float w,
+ const float smoothness,
+ const float randomness,
+ float *r_distance,
+ float3 *r_color,
+ float *r_w)
+{
+ const float cellPosition = floorf(w);
+ const float localPosition = w - cellPosition;
+ const float smoothness_clamped = max_ff(smoothness, FLT_MIN);
+
+ float smoothDistance = 8.0f;
+ float smoothPosition = 0.0f;
+ float3 smoothColor = float3(0.0f, 0.0f, 0.0f);
+ for (int i = -2; i <= 2; i++) {
+ const float cellOffset = i;
+ const float pointPosition = cellOffset +
+ hash_float_to_float(cellPosition + cellOffset) * randomness;
+ const float distanceToPoint = voronoi_distance(pointPosition, localPosition);
+ const float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness_clamped);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ if (r_color != nullptr || r_w != nullptr) {
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ if (r_color != nullptr) {
+ const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
+ smoothColor = math::interpolate(smoothColor, cellColor, h) - correctionFactor;
+ }
+ if (r_w != nullptr) {
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ if (r_distance != nullptr) {
+ *r_distance = smoothDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = smoothColor;
+ }
+ if (r_w != nullptr) {
+ *r_w = cellPosition + smoothPosition;
+ }
+}
+
+void voronoi_f2(
+ const float w, const float randomness, float *r_distance, float3 *r_color, float *r_w)
+{
+ const float cellPosition = floorf(w);
+ const float localPosition = w - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float offsetF1 = 0.0f;
+ float positionF1 = 0.0f;
+ float offsetF2 = 0.0f;
+ float positionF2 = 0.0f;
+ for (int i = -1; i <= 1; i++) {
+ const float cellOffset = i;
+ const float pointPosition = cellOffset +
+ hash_float_to_float(cellPosition + cellOffset) * randomness;
+ const float distanceToPoint = voronoi_distance(pointPosition, localPosition);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ if (r_distance != nullptr) {
+ *r_distance = distanceF2;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + offsetF2);
+ }
+ if (r_w != nullptr) {
+ *r_w = positionF2 + cellPosition;
+ }
+}
+
+void voronoi_distance_to_edge(const float w, const float randomness, float *r_distance)
+{
+ const float cellPosition = floorf(w);
+ const float localPosition = w - cellPosition;
+
+ const float midPointPosition = hash_float_to_float(cellPosition) * randomness;
+ const float leftPointPosition = -1.0f + hash_float_to_float(cellPosition - 1.0f) * randomness;
+ const float rightPointPosition = 1.0f + hash_float_to_float(cellPosition + 1.0f) * randomness;
+ const float distanceToMidLeft = fabsf((midPointPosition + leftPointPosition) / 2.0f -
+ localPosition);
+ const float distanceToMidRight = fabsf((midPointPosition + rightPointPosition) / 2.0f -
+ localPosition);
+
+ *r_distance = std::min(distanceToMidLeft, distanceToMidRight);
+}
+
+void voronoi_n_sphere_radius(const float w, const float randomness, float *r_radius)
+{
+ const float cellPosition = floorf(w);
+ const float localPosition = w - cellPosition;
+
+ float closestPoint = 0.0f;
+ float closestPointOffset = 0.0f;
+ float minDistance = 8.0f;
+ for (int i = -1; i <= 1; i++) {
+ const float cellOffset = i;
+ const float pointPosition = cellOffset +
+ hash_float_to_float(cellPosition + cellOffset) * randomness;
+ const float distanceToPoint = fabsf(pointPosition - localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+
+ minDistance = 8.0f;
+ float closestPointToClosestPoint = 0.0f;
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0) {
+ continue;
+ }
+ const float cellOffset = i + closestPointOffset;
+ const float pointPosition = cellOffset +
+ hash_float_to_float(cellPosition + cellOffset) * randomness;
+ const float distanceToPoint = fabsf(closestPoint - pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ *r_radius = fabsf(closestPointToClosestPoint - closestPoint) / 2.0f;
+}
+
+/* **** 2D Voronoi **** */
+
+static float voronoi_distance(const float2 a,
+ const float2 b,
+ const int metric,
+ const float exponent)
+{
+ switch (metric) {
+ case NOISE_SHD_VORONOI_EUCLIDEAN:
+ return math::distance(a, b);
+ case NOISE_SHD_VORONOI_MANHATTAN:
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y);
+ case NOISE_SHD_VORONOI_CHEBYCHEV:
+ return std::max(fabsf(a.x - b.x), fabsf(a.y - b.y));
+ case NOISE_SHD_VORONOI_MINKOWSKI:
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent),
+ 1.0f / exponent);
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ return 0.0f;
+}
+
+void voronoi_f1(const float2 coord,
+ const float exponent,
+ const float randomness,
+ const int metric,
+ float *r_distance,
+ float3 *r_color,
+ float2 *r_position)
+{
+ const float2 cellPosition = math::floor(coord);
+ const float2 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0f;
+ float2 targetOffset = float2(0.0f, 0.0f);
+ float2 targetPosition = float2(0.0f, 0.0f);
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float2 cellOffset = float2(i, j);
+ const float2 pointPosition = cellOffset +
+ hash_float_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ if (r_distance != nullptr) {
+ *r_distance = minDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + targetOffset);
+ }
+ if (r_position != nullptr) {
+ *r_position = targetPosition + cellPosition;
+ }
+}
+
+void voronoi_smooth_f1(const float2 coord,
+ const float smoothness,
+ const float exponent,
+ const float randomness,
+ const int metric,
+ float *r_distance,
+ float3 *r_color,
+ float2 *r_position)
+{
+ const float2 cellPosition = math::floor(coord);
+ const float2 localPosition = coord - cellPosition;
+ const float smoothness_clamped = max_ff(smoothness, FLT_MIN);
+
+ float smoothDistance = 8.0f;
+ float3 smoothColor = float3(0.0f, 0.0f, 0.0f);
+ float2 smoothPosition = float2(0.0f, 0.0f);
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ const float2 cellOffset = float2(i, j);
+ const float2 pointPosition = cellOffset +
+ hash_float_to_float2(cellPosition + cellOffset) * randomness;
+ const float distanceToPoint = voronoi_distance(
+ pointPosition, localPosition, metric, exponent);
+ const float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness_clamped);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ if (r_color != nullptr || r_position != nullptr) {
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ if (r_color != nullptr) {
+ const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
+ smoothColor = math::interpolate(smoothColor, cellColor, h) - correctionFactor;
+ }
+ if (r_position != nullptr) {
+ smoothPosition = math::interpolate(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ }
+ if (r_distance != nullptr) {
+ *r_distance = smoothDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = smoothColor;
+ }
+ if (r_position != nullptr) {
+ *r_position = cellPosition + smoothPosition;
+ }
+}
+
+void voronoi_f2(const float2 coord,
+ const float exponent,
+ const float randomness,
+ const int metric,
+ float *r_distance,
+ float3 *r_color,
+ float2 *r_position)
+{
+ const float2 cellPosition = math::floor(coord);
+ const float2 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float2 offsetF1 = float2(0.0f, 0.0f);
+ float2 positionF1 = float2(0.0f, 0.0f);
+ float2 offsetF2 = float2(0.0f, 0.0f);
+ float2 positionF2 = float2(0.0f, 0.0f);
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float2 cellOffset = float2(i, j);
+ const float2 pointPosition = cellOffset +
+ hash_float_to_float2(cellPosition + cellOffset) * randomness;
+ const float distanceToPoint = voronoi_distance(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ if (r_distance != nullptr) {
+ *r_distance = distanceF2;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + offsetF2);
+ }
+ if (r_position != nullptr) {
+ *r_position = positionF2 + cellPosition;
+ }
+}
+
+void voronoi_distance_to_edge(const float2 coord, const float randomness, float *r_distance)
+{
+ const float2 cellPosition = math::floor(coord);
+ const float2 localPosition = coord - cellPosition;
+
+ float2 vectorToClosest = float2(0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float2 cellOffset = float2(i, j);
+ const float2 vectorToPoint = cellOffset +
+ hash_float_to_float2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ const float distanceToPoint = dot_v2v2(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float2 cellOffset = float2(i, j);
+ const float2 vectorToPoint = cellOffset +
+ hash_float_to_float2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ const float2 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot_v2v2(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ const float distanceToEdge = dot_v2v2((vectorToClosest + vectorToPoint) / 2.0f,
+ math::normalize(perpendicularToEdge));
+ minDistance = std::min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ *r_distance = minDistance;
+}
+
+void voronoi_n_sphere_radius(const float2 coord, const float randomness, float *r_radius)
+{
+ const float2 cellPosition = math::floor(coord);
+ const float2 localPosition = coord - cellPosition;
+
+ float2 closestPoint = float2(0.0f, 0.0f);
+ float2 closestPointOffset = float2(0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float2 cellOffset = float2(i, j);
+ const float2 pointPosition = cellOffset +
+ hash_float_to_float2(cellPosition + cellOffset) * randomness;
+ const float distanceToPoint = math::distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ float2 closestPointToClosestPoint = float2(0.0f, 0.0f);
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0) {
+ continue;
+ }
+ const float2 cellOffset = float2(i, j) + closestPointOffset;
+ const float2 pointPosition = cellOffset +
+ hash_float_to_float2(cellPosition + cellOffset) * randomness;
+ const float distanceToPoint = math::distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ *r_radius = math::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+}
+
+/* **** 3D Voronoi **** */
+
+static float voronoi_distance(const float3 a,
+ const float3 b,
+ const int metric,
+ const float exponent)
+{
+ switch (metric) {
+ case NOISE_SHD_VORONOI_EUCLIDEAN:
+ return math::distance(a, b);
+ case NOISE_SHD_VORONOI_MANHATTAN:
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z);
+ case NOISE_SHD_VORONOI_CHEBYCHEV:
+ return std::max(fabsf(a.x - b.x), std::max(fabsf(a.y - b.y), fabsf(a.z - b.z)));
+ case NOISE_SHD_VORONOI_MINKOWSKI:
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
+ powf(fabsf(a.z - b.z), exponent),
+ 1.0f / exponent);
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ return 0.0f;
+}
+
+void voronoi_f1(const float3 coord,
+ const float exponent,
+ const float randomness,
+ const int metric,
+ float *r_distance,
+ float3 *r_color,
+ float3 *r_position)
+{
+ const float3 cellPosition = math::floor(coord);
+ const float3 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0f;
+ float3 targetOffset = float3(0.0f, 0.0f, 0.0f);
+ float3 targetPosition = float3(0.0f, 0.0f, 0.0f);
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float3 cellOffset = float3(i, j, k);
+ const float3 pointPosition = cellOffset +
+ hash_float_to_float3(cellPosition + cellOffset) * randomness;
+ const float distanceToPoint = voronoi_distance(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ }
+ if (r_distance != nullptr) {
+ *r_distance = minDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + targetOffset);
+ }
+ if (r_position != nullptr) {
+ *r_position = targetPosition + cellPosition;
+ }
+}
+
+void voronoi_smooth_f1(const float3 coord,
+ const float smoothness,
+ const float exponent,
+ const float randomness,
+ const int metric,
+ float *r_distance,
+ float3 *r_color,
+ float3 *r_position)
+{
+ const float3 cellPosition = math::floor(coord);
+ const float3 localPosition = coord - cellPosition;
+ const float smoothness_clamped = max_ff(smoothness, FLT_MIN);
+
+ float smoothDistance = 8.0f;
+ float3 smoothColor = float3(0.0f, 0.0f, 0.0f);
+ float3 smoothPosition = float3(0.0f, 0.0f, 0.0f);
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ const float3 cellOffset = float3(i, j, k);
+ const float3 pointPosition = cellOffset +
+ hash_float_to_float3(cellPosition + cellOffset) * randomness;
+ const float distanceToPoint = voronoi_distance(
+ pointPosition, localPosition, metric, exponent);
+ const float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness_clamped);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ if (r_color != nullptr || r_position != nullptr) {
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ if (r_color != nullptr) {
+ const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
+ smoothColor = math::interpolate(smoothColor, cellColor, h) - correctionFactor;
+ }
+ if (r_position != nullptr) {
+ smoothPosition = math::interpolate(smoothPosition, pointPosition, h) -
+ correctionFactor;
+ }
+ }
+ }
+ }
+ }
+ if (r_distance != nullptr) {
+ *r_distance = smoothDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = smoothColor;
+ }
+ if (r_position != nullptr) {
+ *r_position = cellPosition + smoothPosition;
+ }
+}
+
+void voronoi_f2(const float3 coord,
+ const float exponent,
+ const float randomness,
+ const int metric,
+ float *r_distance,
+ float3 *r_color,
+ float3 *r_position)
+{
+ const float3 cellPosition = math::floor(coord);
+ const float3 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float3 offsetF1 = float3(0.0f, 0.0f, 0.0f);
+ float3 positionF1 = float3(0.0f, 0.0f, 0.0f);
+ float3 offsetF2 = float3(0.0f, 0.0f, 0.0f);
+ float3 positionF2 = float3(0.0f, 0.0f, 0.0f);
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float3 cellOffset = float3(i, j, k);
+ const float3 pointPosition = cellOffset +
+ hash_float_to_float3(cellPosition + cellOffset) * randomness;
+ const float distanceToPoint = voronoi_distance(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ }
+ if (r_distance != nullptr) {
+ *r_distance = distanceF2;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + offsetF2);
+ }
+ if (r_position != nullptr) {
+ *r_position = positionF2 + cellPosition;
+ }
+}
+
+void voronoi_distance_to_edge(const float3 coord, const float randomness, float *r_distance)
+{
+ const float3 cellPosition = math::floor(coord);
+ const float3 localPosition = coord - cellPosition;
+
+ float3 vectorToClosest = float3(0.0f, 0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float3 cellOffset = float3(i, j, k);
+ const float3 vectorToPoint = cellOffset +
+ hash_float_to_float3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ const float distanceToPoint = dot_v3v3(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float3 cellOffset = float3(i, j, k);
+ const float3 vectorToPoint = cellOffset +
+ hash_float_to_float3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ const float3 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot_v3v3(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ const float distanceToEdge = dot_v3v3((vectorToClosest + vectorToPoint) / 2.0f,
+ math::normalize(perpendicularToEdge));
+ minDistance = std::min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ *r_distance = minDistance;
+}
+
+void voronoi_n_sphere_radius(const float3 coord, const float randomness, float *r_radius)
+{
+ const float3 cellPosition = math::floor(coord);
+ const float3 localPosition = coord - cellPosition;
+
+ float3 closestPoint = float3(0.0f, 0.0f, 0.0f);
+ float3 closestPointOffset = float3(0.0f, 0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float3 cellOffset = float3(i, j, k);
+ const float3 pointPosition = cellOffset +
+ hash_float_to_float3(cellPosition + cellOffset) * randomness;
+ const float distanceToPoint = math::distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ float3 closestPointToClosestPoint = float3(0.0f, 0.0f, 0.0f);
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0) {
+ continue;
+ }
+ const float3 cellOffset = float3(i, j, k) + closestPointOffset;
+ const float3 pointPosition = cellOffset +
+ hash_float_to_float3(cellPosition + cellOffset) * randomness;
+ const float distanceToPoint = math::distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ *r_radius = math::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+}
+
+/* **** 4D Voronoi **** */
+
+static float voronoi_distance(const float4 a,
+ const float4 b,
+ const int metric,
+ const float exponent)
+{
+ switch (metric) {
+ case NOISE_SHD_VORONOI_EUCLIDEAN:
+ return math::distance(a, b);
+ case NOISE_SHD_VORONOI_MANHATTAN:
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z) + fabsf(a.w - b.w);
+ case NOISE_SHD_VORONOI_CHEBYCHEV:
+ return std::max(fabsf(a.x - b.x),
+ std::max(fabsf(a.y - b.y), std::max(fabsf(a.z - b.z), fabsf(a.w - b.w))));
+ case NOISE_SHD_VORONOI_MINKOWSKI:
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
+ powf(fabsf(a.z - b.z), exponent) + powf(fabsf(a.w - b.w), exponent),
+ 1.0f / exponent);
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ return 0.0f;
+}
+
+void voronoi_f1(const float4 coord,
+ const float exponent,
+ const float randomness,
+ const int metric,
+ float *r_distance,
+ float3 *r_color,
+ float4 *r_position)
+{
+ const float4 cellPosition = math::floor(coord);
+ const float4 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0f;
+ float4 targetOffset = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 targetPosition = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float4 cellOffset = float4(i, j, k, u);
+ const float4 pointPosition = cellOffset +
+ hash_float_to_float4(cellPosition + cellOffset) *
+ randomness;
+ const float distanceToPoint = voronoi_distance(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ if (r_distance != nullptr) {
+ *r_distance = minDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + targetOffset);
+ }
+ if (r_position != nullptr) {
+ *r_position = targetPosition + cellPosition;
+ }
+}
+
+void voronoi_smooth_f1(const float4 coord,
+ const float smoothness,
+ const float exponent,
+ const float randomness,
+ const int metric,
+ float *r_distance,
+ float3 *r_color,
+ float4 *r_position)
+{
+ const float4 cellPosition = math::floor(coord);
+ const float4 localPosition = coord - cellPosition;
+ const float smoothness_clamped = max_ff(smoothness, FLT_MIN);
+
+ float smoothDistance = 8.0f;
+ float3 smoothColor = float3(0.0f, 0.0f, 0.0f);
+ float4 smoothPosition = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ for (int u = -2; u <= 2; u++) {
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ const float4 cellOffset = float4(i, j, k, u);
+ const float4 pointPosition = cellOffset +
+ hash_float_to_float4(cellPosition + cellOffset) *
+ randomness;
+ const float distanceToPoint = voronoi_distance(
+ pointPosition, localPosition, metric, exponent);
+ const float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness_clamped);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ if (r_color != nullptr || r_position != nullptr) {
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ if (r_color != nullptr) {
+ const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
+ smoothColor = math::interpolate(smoothColor, cellColor, h) - correctionFactor;
+ }
+ if (r_position != nullptr) {
+ smoothPosition = math::interpolate(smoothPosition, pointPosition, h) -
+ correctionFactor;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (r_distance != nullptr) {
+ *r_distance = smoothDistance;
+ }
+ if (r_color != nullptr) {
+ *r_color = smoothColor;
+ }
+ if (r_position != nullptr) {
+ *r_position = cellPosition + smoothPosition;
+ }
+}
+
+void voronoi_f2(const float4 coord,
+ const float exponent,
+ const float randomness,
+ const int metric,
+ float *r_distance,
+ float3 *r_color,
+ float4 *r_position)
+{
+ const float4 cellPosition = math::floor(coord);
+ const float4 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float4 offsetF1 = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 positionF1 = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 offsetF2 = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 positionF2 = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float4 cellOffset = float4(i, j, k, u);
+ const float4 pointPosition = cellOffset +
+ hash_float_to_float4(cellPosition + cellOffset) *
+ randomness;
+ const float distanceToPoint = voronoi_distance(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ if (r_distance != nullptr) {
+ *r_distance = distanceF2;
+ }
+ if (r_color != nullptr) {
+ *r_color = hash_float_to_float3(cellPosition + offsetF2);
+ }
+ if (r_position != nullptr) {
+ *r_position = positionF2 + cellPosition;
+ }
+}
+
+void voronoi_distance_to_edge(const float4 coord, const float randomness, float *r_distance)
+{
+ const float4 cellPosition = math::floor(coord);
+ const float4 localPosition = coord - cellPosition;
+
+ float4 vectorToClosest = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float4 cellOffset = float4(i, j, k, u);
+ const float4 vectorToPoint = cellOffset +
+ hash_float_to_float4(cellPosition + cellOffset) *
+ randomness -
+ localPosition;
+ const float distanceToPoint = dot_v4v4(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float4 cellOffset = float4(i, j, k, u);
+ const float4 vectorToPoint = cellOffset +
+ hash_float_to_float4(cellPosition + cellOffset) *
+ randomness -
+ localPosition;
+ const float4 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot_v4v4(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ const float distanceToEdge = dot_v4v4((vectorToClosest + vectorToPoint) / 2.0f,
+ math::normalize(perpendicularToEdge));
+ minDistance = std::min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ }
+ *r_distance = minDistance;
+}
+
+void voronoi_n_sphere_radius(const float4 coord, const float randomness, float *r_radius)
+{
+ const float4 cellPosition = math::floor(coord);
+ const float4 localPosition = coord - cellPosition;
+
+ float4 closestPoint = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 closestPointOffset = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float minDistance = 8.0f;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ const float4 cellOffset = float4(i, j, k, u);
+ const float4 pointPosition = cellOffset +
+ hash_float_to_float4(cellPosition + cellOffset) *
+ randomness;
+ const float distanceToPoint = math::distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ float4 closestPointToClosestPoint = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0 && u == 0) {
+ continue;
+ }
+ const float4 cellOffset = float4(i, j, k, u) + closestPointOffset;
+ const float4 pointPosition = cellOffset +
+ hash_float_to_float4(cellPosition + cellOffset) *
+ randomness;
+ const float distanceToPoint = math::distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ *r_radius = math::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+}
+
+/** \} */
+
} // namespace blender::noise
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 066749f3a94..64bde1193a6 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -48,7 +48,7 @@
# include <shlobj.h>
# include <windows.h>
#else
-# include "unistd.h"
+# include <unistd.h>
#endif /* WIN32 */
#include "MEM_guardedalloc.h"
@@ -69,17 +69,6 @@ static bool BLI_path_is_abs(const char *name);
/* implementation */
-/**
- * Looks for a sequence of decimal digits in string, preceding any filename extension,
- * returning the integer value if found, or 0 if not.
- *
- * \param string: String to scan.
- * \param head: Optional area to return copy of part of string prior to digits,
- * or before dot if no digits.
- * \param tail: Optional area to return copy of part of string following digits,
- * or from dot if no digits.
- * \param r_num_len: Optional to return number of digits found.
- */
int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort *r_num_len)
{
uint nums = 0, nume = 0;
@@ -147,10 +136,6 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort
return 0;
}
-/**
- * Returns in area pointed to by string a string of the form "<head><pic><tail>", where pic
- * is formatted as numlen digits with leading zeroes.
- */
void BLI_path_sequence_encode(
char *string, const char *head, const char *tail, unsigned short numlen, int pic)
{
@@ -159,17 +144,6 @@ void BLI_path_sequence_encode(
static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
-/* ******************** string encoding ***************** */
-
-/**
- * Remove redundant characters from \a path and optionally make absolute.
- *
- * \param relabase: The path this is relative to, or ignored when NULL.
- * \param path: Can be any input, and this function converts it to a regular full path.
- * Also removes garbage from directory paths, like `/../` or double slashes etc.
- *
- * \note \a path isn't protected for max string names...
- */
void BLI_path_normalize(const char *relabase, char *path)
{
ptrdiff_t a;
@@ -260,9 +234,6 @@ void BLI_path_normalize(const char *relabase, char *path)
#endif
}
-/**
- * Cleanup filepath ensuring a trailing slash.
- */
void BLI_path_normalize_dir(const char *relabase, char *dir)
{
/* Would just create an unexpected "/" path, just early exit entirely. */
@@ -274,34 +245,19 @@ void BLI_path_normalize_dir(const char *relabase, char *dir)
BLI_path_slash_ensure(dir);
}
-/**
- * Make given name safe to be used in paths.
- *
- * \return true if \a fname was changed, false otherwise.
- *
- * For now, simply replaces reserved chars (as listed in
- * https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
- * by underscores ('_').
- *
- * \note Space case ' ' is a bit of an edge case here - in theory it is allowed,
- * but again can be an issue in some cases, so we simply replace it by an underscore too
- * (good practice anyway).
- * REMOVED based on popular demand (see T45900).
- * Percent '%' char is a bit same case - not recommended to use it,
- * but supported by all decent file-systems/operating-systems around.
- *
- * \note On Windows, it also ensures there is no '.' (dot char) at the end of the file,
- * this can lead to issues.
- *
- * \note On Windows, it also checks for forbidden names
- * (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
- */
-bool BLI_filename_make_safe(char *fname)
+bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens)
{
- const char *invalid =
- "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
- "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
- "/\\?*:|\"<>";
+#define INVALID_CHARS \
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
+ "/\\?*:|\""
+#define INVALID_TOKENS "<>"
+
+ const char *invalid = allow_tokens ? INVALID_CHARS : INVALID_CHARS INVALID_TOKENS;
+
+#undef INVALID_CHARS
+#undef INVALID_TOKENS
+
char *fn;
bool changed = false;
@@ -366,11 +322,11 @@ bool BLI_filename_make_safe(char *fname)
return changed;
}
-/**
- * Make given path OS-safe.
- *
- * \return true if \a path was changed, false otherwise.
- */
+bool BLI_filename_make_safe(char *fname)
+{
+ return BLI_filename_make_safe_ex(fname, false);
+}
+
bool BLI_path_make_safe(char *path)
{
/* Simply apply BLI_filename_make_safe() over each component of the path.
@@ -404,16 +360,11 @@ bool BLI_path_make_safe(char *path)
return changed;
}
-/**
- * Does path begin with the special "//" prefix that Blender uses to indicate
- * a path relative to the .blend file.
- */
bool BLI_path_is_rel(const char *path)
{
return path[0] == '/' && path[1] == '/';
}
-/* return true if the path is a UNC share */
bool BLI_path_is_unc(const char *name)
{
return name[0] == '\\' && name[1] == '\\';
@@ -512,10 +463,6 @@ void BLI_path_normalize_unc_16(wchar_t *path_16)
}
#endif
-/**
- * Replaces `file` with a relative version (prefixed by "//") such that #BLI_path_abs, given
- * the same `relfile`, will convert it back to its original value.
- */
void BLI_path_rel(char *file, const char *relfile)
{
const char *lslash;
@@ -654,18 +601,6 @@ void BLI_path_rel(char *file, const char *relfile)
}
}
-/**
- * Appends a suffix to the string, fitting it before the extension
- *
- * string = Foo.png, suffix = 123, separator = _
- * Foo.png -> Foo_123.png
- *
- * \param string: original (and final) string
- * \param maxlen: Maximum length of string
- * \param suffix: String to append to the original string
- * \param sep: Optional separator character
- * \return true if succeeded
- */
bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep)
{
#ifdef DEBUG_STRSIZE
@@ -701,10 +636,6 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
return true;
}
-/**
- * Replaces path with the path of its parent directory, returning true if
- * it was able to find a parent directory within the path.
- */
bool BLI_path_parent_dir(char *path)
{
const char parent_dir[] = {'.', '.', SEP, '\0'}; /* "../" or "..\\" */
@@ -721,10 +652,6 @@ bool BLI_path_parent_dir(char *path)
return false;
}
-/**
- * Strips off nonexistent (or non-accessible) sub-directories from the end of `dir`,
- * leaving the path of the lowest-level directory that does exist and we can read.
- */
bool BLI_path_parent_dir_until_exists(char *dir)
{
bool valid_path = true;
@@ -795,10 +722,6 @@ static void ensure_digits(char *path, int digits)
}
}
-/**
- * Replaces "#" character sequence in last slash-separated component of `path`
- * with frame as decimal integer, with leading zeroes as necessary, to make digits digits.
- */
bool BLI_path_frame(char *path, int frame, int digits)
{
int ch_sta, ch_end;
@@ -817,11 +740,6 @@ bool BLI_path_frame(char *path, int frame, int digits)
return false;
}
-/**
- * Replaces "#" character sequence in last slash-separated component of `path`
- * with sta and end as decimal integers, with leading zeroes as necessary, to make digits
- * digits each, with a hyphen in-between.
- */
bool BLI_path_frame_range(char *path, int sta, int end, int digits)
{
int ch_sta, ch_end;
@@ -848,9 +766,6 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits)
return false;
}
-/**
- * Get the frame from a filename formatted by blender's frame scheme
- */
bool BLI_path_frame_get(char *path, int *r_frame, int *r_numdigits)
{
if (*path) {
@@ -952,19 +867,12 @@ void BLI_path_frame_strip(char *path, char *r_ext)
*c = '\0';
}
-/**
- * Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
- */
bool BLI_path_frame_check_chars(const char *path)
{
int ch_sta, ch_end; /* dummy args */
return stringframe_chars(path, &ch_sta, &ch_end);
}
-/**
- * Creates a display string from path to be used menus and the user interface.
- * Like `bpy.path.display_name()`.
- */
void BLI_path_to_display_name(char *display_name, int maxlen, const char *name)
{
/* Strip leading underscores and spaces. */
@@ -1003,16 +911,6 @@ void BLI_path_to_display_name(char *display_name, int maxlen, const char *name)
}
}
-/**
- * If path begins with "//", strips that and replaces it with `basepath` directory.
- *
- * \note Also converts drive-letter prefix to something more sensible
- * if this is a non-drive-letter-based system.
- *
- * \param path: The path to convert.
- * \param basepath: The directory to base relative paths with.
- * \return true if the path was relative (started with "//").
- */
bool BLI_path_abs(char *path, const char *basepath)
{
const bool wasrelative = BLI_path_is_rel(path);
@@ -1059,15 +957,15 @@ bool BLI_path_abs(char *path, const char *basepath)
#endif
- /* push slashes into unix mode - strings entering this part are
+ /* NOTE(@jesterKing): push slashes into unix mode - strings entering this part are
* potentially messed up: having both back- and forward slashes.
* Here we push into one conform direction, and at the end we
* push them into the system specific dir. This ensures uniformity
- * of paths and solving some problems (and prevent potential future
- * ones) -jesterKing.
- * For UNC paths the first characters containing the UNC prefix
+ * of paths and solving some problems (and prevent potential future ones).
+ *
+ * NOTE(@elubie): For UNC paths the first characters containing the UNC prefix
* shouldn't be switched as we need to distinguish them from
- * paths relative to the .blend file -elubie */
+ * paths relative to the `.blend` file. */
BLI_str_replace_char(tmp + BLI_path_unc_prefix_len(tmp), '\\', '/');
/* Paths starting with `//` will get the blend file as their base,
@@ -1114,33 +1012,30 @@ bool BLI_path_abs(char *path, const char *basepath)
return wasrelative;
}
-/**
- * Checks for relative path, expanding them relative to the current working directory.
- * Returns true if the expansion was performed.
- *
- * \note Should only be called with command line paths.
- * This is _not_ something Blender's internal paths support, instead they use the "//" prefix.
- * In most cases #BLI_path_abs should be used instead.
- */
-bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
+bool BLI_path_is_abs_from_cwd(const char *path)
{
-#ifdef DEBUG_STRSIZE
- memset(path, 0xff, sizeof(*path) * maxlen);
-#endif
- bool wasrelative = true;
- const int filelen = strlen(path);
+ bool is_abs = false;
+ const int path_len_clamp = BLI_strnlen(path, 3);
#ifdef WIN32
- if ((filelen >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path)) {
- wasrelative = false;
+ if ((path_len_clamp >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path)) {
+ is_abs = true;
}
#else
- if (filelen >= 2 && path[0] == '/') {
- wasrelative = false;
+ if (path_len_clamp >= 2 && path[0] == '/') {
+ is_abs = true;
}
#endif
+ return is_abs;
+}
- if (wasrelative) {
+bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
+{
+#ifdef DEBUG_STRSIZE
+ memset(path, 0xff, sizeof(*path) * maxlen);
+#endif
+
+ if (!BLI_path_is_abs_from_cwd(path)) {
char cwd[FILE_MAX];
/* in case the full path to the blend isn't used */
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
@@ -1151,9 +1046,10 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
else {
printf("Could not get the current working directory - $PWD for an unknown reason.\n");
}
+ return true;
}
- return wasrelative;
+ return false;
}
#ifdef _WIN32
@@ -1209,9 +1105,6 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
}
#endif /* WIN32 */
-/**
- * Search for a binary (executable)
- */
bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *name)
{
#ifdef DEBUG_STRSIZE
@@ -1264,10 +1157,6 @@ bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *na
return retval;
}
-/**
- * Sets the specified environment variable to the specified value,
- * and clears it if `val == NULL`.
- */
void BLI_setenv(const char *env, const char *val)
{
/* free windows */
@@ -1286,12 +1175,6 @@ void BLI_setenv(const char *env, const char *val)
#endif
}
-/**
- * Only set an env var if already not there.
- * Like Unix setenv(env, val, 0);
- *
- * (not used anywhere).
- */
void BLI_setenv_if_new(const char *env, const char *val)
{
if (BLI_getenv(env) == NULL) {
@@ -1299,14 +1182,6 @@ void BLI_setenv_if_new(const char *env, const char *val)
}
}
-/**
- * Get an env var, result has to be used immediately.
- *
- * On windows #getenv gets its variables from a static copy of the environment variables taken at
- * process start-up, causing it to not pick up on environment variables created during runtime.
- * This function uses an alternative method to get environment variables that does pick up on
- * runtime environment variables. The result will be UTF-8 encoded.
- */
const char *BLI_getenv(const char *env)
{
#ifdef _MSC_VER
@@ -1336,11 +1211,6 @@ const char *BLI_getenv(const char *env)
#endif
}
-/**
- * Ensures that the parent directory of `name` exists.
- *
- * \return true on success (i.e. given path now exists on file-system), false otherwise.
- */
bool BLI_make_existing_file(const char *name)
{
char di[FILE_MAX];
@@ -1350,15 +1220,6 @@ bool BLI_make_existing_file(const char *name)
return BLI_dir_create_recursive(di);
}
-/**
- * Returns in `string` the concatenation of `dir` and `file` (also with `relabase` on the
- * front if specified and `dir` begins with "//"). Normalizes all occurrences of path
- * separators, including ensuring there is exactly one between the copies of `dir` and `file`,
- * and between the copies of `relabase` and `dir`.
- *
- * \param relabase: Optional prefix to substitute for "//" on front of `dir`.
- * \param string: Area to return result.
- */
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file)
{
int sl;
@@ -1452,7 +1313,6 @@ static bool path_extension_check_ex(const char *str,
(BLI_strcasecmp(ext, str + str_len - ext_len) == 0));
}
-/* does str end with ext. */
bool BLI_path_extension_check(const char *str, const char *ext)
{
return path_extension_check_ex(str, strlen(str), ext, strlen(ext));
@@ -1480,7 +1340,6 @@ bool BLI_path_extension_check_n(const char *str, ...)
return ret;
}
-/* does str end with any of the suffixes in *ext_array. */
bool BLI_path_extension_check_array(const char *str, const char **ext_array)
{
const size_t str_len = strlen(str);
@@ -1496,10 +1355,6 @@ bool BLI_path_extension_check_array(const char *str, const char **ext_array)
return false;
}
-/**
- * Semicolon separated wildcards, eg: `*.zip;*.py;*.exe`
- * does str match any of the semicolon-separated glob patterns in #fnmatch.
- */
bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch)
{
const char *ext_step = ext_fnmatch;
@@ -1526,15 +1381,6 @@ bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch)
return false;
}
-/**
- * Does basic validation of the given glob string, to prevent common issues from string
- * truncation.
- *
- * For now, only forbids last group to be a wildcard-only one, if there are more than one group
- * (i.e. things like `*.txt;*.cpp;*` are changed to `*.txt;*.cpp;`)
- *
- * \returns true if it had to modify given \a ext_fnmatch pattern.
- */
bool BLI_path_extension_glob_validate(char *ext_fnmatch)
{
bool only_wildcards = false;
@@ -1561,10 +1407,6 @@ bool BLI_path_extension_glob_validate(char *ext_fnmatch)
return false;
}
-/**
- * Removes any existing extension on the end of \a path and appends \a ext.
- * \return false if there was no room.
- */
bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext)
{
#ifdef DEBUG_STRSIZE
@@ -1592,9 +1434,6 @@ bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext)
return true;
}
-/**
- * Strip's trailing '.'s and adds the extension only when needed
- */
bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext)
{
#ifdef DEBUG_STRSIZE
@@ -1640,14 +1479,6 @@ bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filenam
return false;
}
-/**
- * Converts `/foo/bar.txt` to `/foo/` and `bar.txt`
- *
- * - Won't change \a string.
- * - Won't create any directories.
- * - Doesn't use CWD, or deal with relative paths.
- * - Only fill's in \a dir and \a file when they are non NULL.
- */
void BLI_split_dirfile(
const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen)
{
@@ -1673,26 +1504,16 @@ void BLI_split_dirfile(
}
}
-/**
- * Copies the parent directory part of string into `dir`, max length `dirlen`.
- */
void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen)
{
BLI_split_dirfile(string, dir, NULL, dirlen, 0);
}
-/**
- * Copies the leaf filename part of string into `file`, max length `filelen`.
- */
void BLI_split_file_part(const char *string, char *file, const size_t filelen)
{
BLI_split_dirfile(string, NULL, file, 0, filelen);
}
-/**
- * Returns a pointer to the last extension (e.g. the position of the last period).
- * Returns NULL if there is no extension.
- */
const char *BLI_path_extension(const char *filepath)
{
const char *extension = strrchr(filepath, '.');
@@ -1707,9 +1528,6 @@ const char *BLI_path_extension(const char *filepath)
return extension;
}
-/**
- * Append a filename to a dir, ensuring slash separates.
- */
void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file)
{
size_t dirlen = BLI_strnlen(dst, maxlen);
@@ -1727,10 +1545,6 @@ void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__re
BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
}
-/**
- * Simple appending of filename to dir, does not check for valid path!
- * Puts result into `dst`, which may be same area as `dir`.
- */
void BLI_join_dirfile(char *__restrict dst,
const size_t maxlen,
const char *__restrict dir,
@@ -1741,9 +1555,13 @@ void BLI_join_dirfile(char *__restrict dst,
#endif
size_t dirlen = BLI_strnlen(dir, maxlen);
- /* args can't match */
+ /* Arguments can't match. */
BLI_assert(!ELEM(dst, dir, file));
+ /* Files starting with a separator cause a double-slash which could later be interpreted
+ * as a relative path where: `dir == "/"` and `file == "/file"` would result in "//file". */
+ BLI_assert(file[0] != SEP);
+
if (dirlen == maxlen) {
memcpy(dst, dir, dirlen);
dst[dirlen - 1] = '\0';
@@ -1769,13 +1587,6 @@ void BLI_join_dirfile(char *__restrict dst,
BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
}
-/**
- * Join multiple strings into a path, ensuring only a single path separator between each,
- * and trailing slash is kept.
- *
- * \note If you want a trailing slash, add `SEP_STR` as the last path argument,
- * duplicate slashes will be cleaned up.
- */
size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path, ...)
{
#ifdef DEBUG_STRSIZE
@@ -1856,27 +1667,12 @@ size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *pat
return ofs;
}
-/**
- * like Python's `os.path.basename()`
- *
- * \return The pointer into \a path string immediately after last slash,
- * or start of \a path if none found.
- */
const char *BLI_path_basename(const char *path)
{
const char *const filename = BLI_path_slash_rfind(path);
return filename ? filename + 1 : path;
}
-/**
- * Get an element of the path at an index, eg:
- * "/some/path/file.txt" where an index of...
- * - 0 or -3: "some"
- * - 1 or -2: "path"
- * - 2 or -1: "file.txt"
- *
- * Ignores multiple slashes at any point in the path (including start/end).
- */
bool BLI_path_name_at_index(const char *__restrict path,
const int index,
int *__restrict r_offset,
@@ -1941,7 +1737,7 @@ bool BLI_path_contains(const char *container_path, const char *containee_path)
char containee_native[PATH_MAX];
/* Keep space for a trailing slash. If the path is truncated by this, the containee path is
- * longer than PATH_MAX and the result is ill-defined. */
+ * longer than PATH_MAX and the result is ill-defined. */
BLI_strncpy(container_native, container_path, PATH_MAX - 1);
BLI_strncpy(containee_native, containee_path, PATH_MAX);
@@ -1968,9 +1764,6 @@ bool BLI_path_contains(const char *container_path, const char *containee_path)
return BLI_str_startswith(containee_native, container_native);
}
-/**
- * Returns pointer to the leftmost path separator in string. Not actually used anywhere.
- */
const char *BLI_path_slash_find(const char *string)
{
const char *const ffslash = strchr(string, '/');
@@ -1986,9 +1779,6 @@ const char *BLI_path_slash_find(const char *string)
return (ffslash < fbslash) ? ffslash : fbslash;
}
-/**
- * Returns pointer to the rightmost path separator in string.
- */
const char *BLI_path_slash_rfind(const char *string)
{
const char *const lfslash = strrchr(string, '/');
@@ -2004,10 +1794,6 @@ const char *BLI_path_slash_rfind(const char *string)
return (lfslash > lbslash) ? lfslash : lbslash;
}
-/**
- * Appends a slash to string if there isn't one there already.
- * Returns the new length of the string.
- */
int BLI_path_slash_ensure(char *string)
{
int len = strlen(string);
@@ -2019,9 +1805,6 @@ int BLI_path_slash_ensure(char *string)
return len;
}
-/**
- * Removes the last slash and everything after it to the end of string, if there is one.
- */
void BLI_path_slash_rstrip(char *string)
{
int len = strlen(string);
@@ -2036,9 +1819,6 @@ void BLI_path_slash_rstrip(char *string)
}
}
-/**
- * Changes to the path separators to the native ones for this OS.
- */
void BLI_path_slash_native(char *path)
{
#ifdef WIN32
diff --git a/source/blender/blenlib/intern/polyfill_2d.c b/source/blender/blenlib/intern/polyfill_2d.c
index 9af98359199..aec34659884 100644
--- a/source/blender/blenlib/intern/polyfill_2d.c
+++ b/source/blender/blenlib/intern/polyfill_2d.c
@@ -25,7 +25,7 @@
* and that triangles will have non-overlapping indices (even for degenerate geometry).
* - Self-intersections are considered degenerate (resulting triangles will overlap).
* - While multiple polygons aren't supported, holes can still be defined using *key-holes*
- * (where the polygon doubles back on its self with *exactly* matching coordinates).
+ * (where the polygon doubles back on itself with *exactly* matching coordinates).
*
* \note
*
@@ -147,7 +147,7 @@ typedef struct PolyFill {
#endif
} PolyFill;
-/* circular linklist */
+/** Circular double linked-list. */
typedef struct PolyIndex {
struct PolyIndex *next, *prev;
uint index;
@@ -841,9 +841,6 @@ static void polyfill_calc(PolyFill *pf)
pf_triangulate(pf);
}
-/**
- * A version of #BLI_polyfill_calc that uses a memory arena to avoid re-allocations.
- */
void BLI_polyfill_calc_arena(const float (*coords)[2],
const uint coords_tot,
const int coords_sign,
@@ -889,19 +886,6 @@ void BLI_polyfill_calc_arena(const float (*coords)[2],
#endif
}
-/**
- * Triangulates the given (convex or concave) simple polygon to a list of triangle vertices.
- *
- * \param coords: 2D coordinates describing vertices of the polygon,
- * in either clockwise or counterclockwise order.
- * \param coords_tot: Total points in the array.
- * \param coords_sign: Pass this when we know the sign in advance to avoid extra calculations.
- *
- * \param r_tris: This array is filled in with triangle indices in clockwise order.
- * The length of the array must be `coords_tot - 2`.
- * Indices are guaranteed to be assigned to unique triangles, with valid indices,
- * even in the case of degenerate input (self intersecting polygons, zero area ears... etc).
- */
void BLI_polyfill_calc(const float (*coords)[2],
const uint coords_tot,
const int coords_sign,
diff --git a/source/blender/blenlib/intern/polyfill_2d_beautify.c b/source/blender/blenlib/intern/polyfill_2d_beautify.c
index ed07b002e32..aab33cb163b 100644
--- a/source/blender/blenlib/intern/polyfill_2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill_2d_beautify.c
@@ -92,21 +92,6 @@ BLI_INLINE bool is_boundary_edge(uint i_a, uint i_b, const uint coord_last)
BLI_assert(i_a < i_b);
return ((i_a + 1 == i_b) || UNLIKELY((i_a == 0) && (i_b == coord_last)));
}
-/**
- * Assuming we have 2 triangles sharing an edge (2 - 4),
- * check if the edge running from (1 - 3) gives better results.
- *
- * \param lock_degenerate: Use to avoid rotating out of a degenerate state:
- * - When true, an existing zero area face on either side of the (2 - 4
- * split will return a positive value.
- * - When false, the check must be non-biased towards either split direction.
- * \param r_area: Return the area of the quad,
- * This can be useful when comparing the return value with near zero epsilons.
- * In this case the epsilon can be scaled by the area to avoid the return value
- * of very large faces not having a reliable way to detect near-zero output.
- *
- * \return (negative number means the edge can be rotated, lager == better).
- */
float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
const float v2[2],
const float v3[2],
@@ -316,12 +301,6 @@ static void polyedge_rotate(struct HalfEdge *edges, struct HalfEdge *e)
ed[3]->v = ed[2]->v;
}
-/**
- * The intention is that this calculates the output of #BLI_polyfill_calc
- * \note assumes the \a coords form a boundary,
- * so any edges running along contiguous (wrapped) indices,
- * are ignored since the edges won't share 2 faces.
- */
void BLI_polyfill_beautify(const float (*coords)[2],
const uint coords_tot,
uint (*tris)[3],
@@ -421,7 +400,7 @@ void BLI_polyfill_beautify(const float (*coords)[2],
BLI_heap_clear(eheap, NULL);
- /* MEM_freeN(eheap_table); */ /* arena */
+ // MEM_freeN(eheap_table); /* arena */
/* get tris from half edge. */
uint tri_index = 0;
diff --git a/source/blender/blenlib/intern/rand.cc b/source/blender/blenlib/intern/rand.cc
index db5e08d37ce..1d2274ede37 100644
--- a/source/blender/blenlib/intern/rand.cc
+++ b/source/blender/blenlib/intern/rand.cc
@@ -59,9 +59,6 @@ RNG *BLI_rng_new(unsigned int seed)
return rng;
}
-/**
- * A version of #BLI_rng_new that hashes the seed.
- */
RNG *BLI_rng_new_srandom(unsigned int seed)
{
RNG *rng = new RNG();
@@ -84,9 +81,6 @@ void BLI_rng_seed(RNG *rng, unsigned int seed)
rng->rng.seed(seed);
}
-/**
- * Use a hash table to create better seed.
- */
void BLI_rng_srandom(RNG *rng, unsigned int seed)
{
rng->rng.seed_random(seed);
@@ -107,17 +101,11 @@ unsigned int BLI_rng_get_uint(RNG *rng)
return rng->rng.get_uint32();
}
-/**
- * \return Random value (0..1), but never 1.0.
- */
double BLI_rng_get_double(RNG *rng)
{
return rng->rng.get_double();
}
-/**
- * \return Random value (0..1), but never 1.0.
- */
float BLI_rng_get_float(RNG *rng)
{
return rng->rng.get_float();
@@ -133,9 +121,6 @@ void BLI_rng_get_float_unit_v3(RNG *rng, float v[3])
copy_v3_v3(v, rng->rng.get_unit_float3());
}
-/**
- * Generate a random point inside given tri.
- */
void BLI_rng_get_tri_sample_float_v2(
RNG *rng, const float v1[2], const float v2[2], const float v3[2], float r_pt[2])
{
@@ -190,11 +175,6 @@ void BLI_rng_shuffle_bitmap(struct RNG *rng, BLI_bitmap *bitmap, unsigned int bi
}
}
-/**
- * Simulate getting \a n random values.
- *
- * \note Useful when threaded code needs consistent values, independent of task division.
- */
void BLI_rng_skip(RNG *rng, int n)
{
rng->rng.skip((uint)n);
@@ -202,7 +182,6 @@ void BLI_rng_skip(RNG *rng, int n)
/***/
-/* fill an array with random numbers */
void BLI_array_frand(float *ar, int count, unsigned int seed)
{
RNG rng;
@@ -272,7 +251,7 @@ struct RNG_THREAD_ARRAY {
RNG rng_tab[BLENDER_MAX_THREADS];
};
-RNG_THREAD_ARRAY *BLI_rng_threaded_new(void)
+RNG_THREAD_ARRAY *BLI_rng_threaded_new()
{
unsigned int i;
RNG_THREAD_ARRAY *rngarr = (RNG_THREAD_ARRAY *)MEM_mallocN(sizeof(RNG_THREAD_ARRAY),
@@ -402,9 +381,6 @@ void BLI_hammersley_2d_sequence(unsigned int n, double *r)
namespace blender {
-/**
- * Set a randomized hash of the value as seed.
- */
void RandomNumberGenerator::seed_random(uint32_t seed)
{
this->seed(seed + hash[seed & 255]);
@@ -434,9 +410,6 @@ float3 RandomNumberGenerator::get_unit_float3()
return {0.0f, 0.0f, 1.0f};
}
-/**
- * Generate a random point inside the given triangle.
- */
float2 RandomNumberGenerator::get_triangle_sample(float2 v1, float2 v2, float2 v3)
{
float u = this->get_float();
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
index 35e24ecc785..091945c9b12 100644
--- a/source/blender/blenlib/intern/rct.c
+++ b/source/blender/blenlib/intern/rct.c
@@ -30,6 +30,7 @@
#include <float.h>
#include <limits.h>
+#include "BLI_math_base.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
@@ -38,13 +39,6 @@
/* avoid including BLI_math */
static void unit_m4(float m[4][4]);
-/**
- * Determine if a rect is empty. An empty
- * rect is one with a zero (or negative)
- * width or height.
- *
- * \return True if \a rect is empty.
- */
bool BLI_rcti_is_empty(const rcti *rect)
{
return ((rect->xmax <= rect->xmin) || (rect->ymax <= rect->ymin));
@@ -167,10 +161,6 @@ bool BLI_rctf_isect_pt_v(const rctf *rect, const float xy[2])
return true;
}
-/**
- * \returns shortest distance from \a rect to x/y (0 if inside)
- */
-
int BLI_rcti_length_x(const rcti *rect, const int x)
{
if (x < rect->xmin) {
@@ -215,9 +205,6 @@ float BLI_rctf_length_y(const rctf *rect, const float y)
return 0.0f;
}
-/**
- * is \a rct_b inside \a rct_a
- */
bool BLI_rctf_inside_rctf(const rctf *rct_a, const rctf *rct_b)
{
return ((rct_a->xmin <= rct_b->xmin) && (rct_a->xmax >= rct_b->xmax) &&
@@ -401,35 +388,35 @@ bool BLI_rctf_isect_circle(const rctf *rect, const float xy[2], const float radi
return dx * dx + dy * dy <= radius * radius;
}
-void BLI_rctf_union(rctf *rct1, const rctf *rct2)
+void BLI_rctf_union(rctf *rct_a, const rctf *rct_b)
{
- if (rct1->xmin > rct2->xmin) {
- rct1->xmin = rct2->xmin;
+ if (rct_a->xmin > rct_b->xmin) {
+ rct_a->xmin = rct_b->xmin;
}
- if (rct1->xmax < rct2->xmax) {
- rct1->xmax = rct2->xmax;
+ if (rct_a->xmax < rct_b->xmax) {
+ rct_a->xmax = rct_b->xmax;
}
- if (rct1->ymin > rct2->ymin) {
- rct1->ymin = rct2->ymin;
+ if (rct_a->ymin > rct_b->ymin) {
+ rct_a->ymin = rct_b->ymin;
}
- if (rct1->ymax < rct2->ymax) {
- rct1->ymax = rct2->ymax;
+ if (rct_a->ymax < rct_b->ymax) {
+ rct_a->ymax = rct_b->ymax;
}
}
-void BLI_rcti_union(rcti *rct1, const rcti *rct2)
+void BLI_rcti_union(rcti *rct_a, const rcti *rct_b)
{
- if (rct1->xmin > rct2->xmin) {
- rct1->xmin = rct2->xmin;
+ if (rct_a->xmin > rct_b->xmin) {
+ rct_a->xmin = rct_b->xmin;
}
- if (rct1->xmax < rct2->xmax) {
- rct1->xmax = rct2->xmax;
+ if (rct_a->xmax < rct_b->xmax) {
+ rct_a->xmax = rct_b->xmax;
}
- if (rct1->ymin > rct2->ymin) {
- rct1->ymin = rct2->ymin;
+ if (rct_a->ymin > rct_b->ymin) {
+ rct_a->ymin = rct_b->ymin;
}
- if (rct1->ymax < rct2->ymax) {
- rct1->ymax = rct2->ymax;
+ if (rct_a->ymax < rct_b->ymax) {
+ rct_a->ymax = rct_b->ymax;
}
}
@@ -453,13 +440,6 @@ void BLI_rcti_init(rcti *rect, int xmin, int xmax, int ymin, int ymax)
BLI_rcti_sanitize(rect);
}
-/**
- * Check if X-min and Y-min are less than or equal to X-max and Y-max, respectively.
- * If this returns false, #BLI_rctf_sanitize() can be called to address this.
- *
- * This is not a hard constraint or invariant for rectangles, in some cases it may be useful to
- * have max < min. Usually this is what you'd want though.
- */
bool BLI_rctf_is_valid(const rctf *rect)
{
return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax);
@@ -470,9 +450,6 @@ bool BLI_rcti_is_valid(const rcti *rect)
return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax);
}
-/**
- * Ensure X-min and Y-min are less than or equal to X-max and Y-max, respectively.
- */
void BLI_rctf_sanitize(rctf *rect)
{
if (rect->xmin > rect->xmax) {
@@ -541,6 +518,14 @@ void BLI_rcti_do_minmax_v(rcti *rect, const int xy[2])
}
}
+void BLI_rcti_do_minmax_rcti(rcti *rect, const rcti *other)
+{
+ rect->xmin = min_ii(rect->xmin, other->xmin);
+ rect->xmax = max_ii(rect->xmax, other->xmax);
+ rect->ymin = min_ii(rect->ymin, other->ymin);
+ rect->ymax = max_ii(rect->ymax, other->ymax);
+}
+
void BLI_rctf_do_minmax_v(rctf *rect, const float xy[2])
{
if (xy[0] < rect->xmin) {
@@ -557,7 +542,6 @@ void BLI_rctf_do_minmax_v(rctf *rect, const float xy[2])
}
}
-/* given 2 rectangles - transform a point from one to another */
void BLI_rctf_transform_pt_v(const rctf *dst,
const rctf *src,
float xy_dst[2],
@@ -570,12 +554,6 @@ void BLI_rctf_transform_pt_v(const rctf *dst,
xy_dst[1] = dst->ymin + ((dst->ymax - dst->ymin) * xy_dst[1]);
}
-/**
- * Calculate a 4x4 matrix representing the transformation between two rectangles.
- *
- * \note Multiplying a vector by this matrix does *not*
- * give the same value as #BLI_rctf_transform_pt_v.
- */
void BLI_rctf_transform_calc_m4_pivot_min_ex(
const rctf *dst, const rctf *src, float matrix[4][4], uint x, uint y)
{
@@ -622,7 +600,6 @@ void BLI_rctf_recenter(rctf *rect, float x, float y)
BLI_rctf_translate(rect, dx, dy);
}
-/* change width & height around the central location */
void BLI_rcti_resize_x(rcti *rect, int x)
{
rect->xmin = BLI_rcti_cent_x(rect) - (x / 2);
@@ -777,14 +754,6 @@ bool BLI_rcti_clamp_pt_v(const rcti *rect, int xy[2])
return changed;
}
-/**
- * Clamp \a rect within \a rect_bounds, setting \a r_xy to the offset.
- *
- * Keeps the top left corner within the bounds, which for user interface
- * elements is typically where the most important information is.
- *
- * \return true if a change is made.
- */
bool BLI_rctf_clamp(rctf *rect, const rctf *rect_bounds, float r_xy[2])
{
bool changed = false;
@@ -1106,9 +1075,6 @@ void print_rcti(const char *str, const rcti *rect)
} \
((void)0)
-/**
- * Expand the rectangle to fit a rotated \a src.
- */
void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle)
{
const float mat2[2] = {sinf(angle), cosf(angle)};
diff --git a/source/blender/blenlib/intern/resource_scope.cc b/source/blender/blenlib/intern/resource_scope.cc
new file mode 100644
index 00000000000..8c8a03b8ce5
--- /dev/null
+++ b/source/blender/blenlib/intern/resource_scope.cc
@@ -0,0 +1,32 @@
+/*
+ * 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 "BLI_resource_scope.hh"
+
+namespace blender {
+
+ResourceScope::ResourceScope() = default;
+
+ResourceScope::~ResourceScope()
+{
+ /* Free in reversed order. */
+ for (int64_t i = resources_.size(); i--;) {
+ ResourceData &data = resources_[i];
+ data.free(data.data);
+ }
+}
+
+} // namespace blender
diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c
index f0cf19bf508..9fe82069d2c 100644
--- a/source/blender/blenlib/intern/scanfill.c
+++ b/source/blender/blenlib/intern/scanfill.c
@@ -357,8 +357,10 @@ static ScanFillVertLink *addedgetoscanlist(ScanFillVertLink *scdata,
return NULL;
}
+/**
+ * Return true if `eve` inside the bound-box of `eed`.
+ */
static bool boundinsideEV(ScanFillEdge *eed, ScanFillVert *eve)
-/* is eve inside boundbox eed */
{
float minx, maxx, miny, maxy;
@@ -448,7 +450,7 @@ static void splitlist(ScanFillContext *sf_ctx,
ListBase *temped,
unsigned short nr)
{
- /* everything is in templist, write only poly nr to fillist */
+ /* Everything is in temp-list, write only poly nr to fill-list. */
ScanFillVert *eve, *eve_next;
ScanFillEdge *eed, *eed_next;
@@ -1040,13 +1042,13 @@ unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const
}
/* CURRENT STATUS:
- * - eve->f :1 = available in edges
- * - eve->poly_nr :polynumber
- * - eve->edge_tot :amount of edges connected to vertex
- * - eve->tmp.v :store! original vertex number
+ * - `eve->f`: 1 = available in edges.
+ * - `eve->poly_nr`: poly-number.
+ * - `eve->edge_tot`: amount of edges connected to vertex.
+ * - `eve->tmp.v`: store! original vertex number.
*
- * - eed->f :1 = boundary edge (optionally set by caller)
- * - eed->poly_nr :poly number
+ * - `eed->f`: 1 = boundary edge (optionally set by caller).
+ * - `eed->poly_nr`: poly number.
*/
/* STEP 3: MAKE POLYFILL STRUCT */
diff --git a/source/blender/blenlib/intern/scanfill_utils.c b/source/blender/blenlib/intern/scanfill_utils.c
index ec0f8659395..89c2a695829 100644
--- a/source/blender/blenlib/intern/scanfill_utils.c
+++ b/source/blender/blenlib/intern/scanfill_utils.c
@@ -156,15 +156,13 @@ static ScanFillEdge *edge_step(PolyInfo *poly_info,
eed = (e_curr->next && e_curr != poly_info[poly_nr].edge_last) ? e_curr->next :
poly_info[poly_nr].edge_first;
- if ((v_curr == eed->v1 || v_curr == eed->v2) == true &&
- (ELEM(v_prev, eed->v1, eed->v2)) == false) {
+ if (ELEM(v_curr, eed->v1, eed->v2) == true && ELEM(v_prev, eed->v1, eed->v2) == false) {
return eed;
}
eed = (e_curr->prev && e_curr != poly_info[poly_nr].edge_first) ? e_curr->prev :
poly_info[poly_nr].edge_last;
- if ((v_curr == eed->v1 || v_curr == eed->v2) == true &&
- (ELEM(v_prev, eed->v1, eed->v2)) == false) {
+ if (ELEM(v_curr, eed->v1, eed->v2) == true && ELEM(v_prev, eed->v1, eed->v2) == false) {
return eed;
}
@@ -371,11 +369,6 @@ static bool scanfill_preprocess_self_isect(ScanFillContext *sf_ctx,
return true;
}
-/**
- * Call before scanfill to remove self intersections.
- *
- * \return false if no changes were made.
- */
bool BLI_scanfill_calc_self_isect(ScanFillContext *sf_ctx,
ListBase *remvertbase,
ListBase *remedgebase)
diff --git a/source/blender/blenlib/intern/serialize.cc b/source/blender/blenlib/intern/serialize.cc
new file mode 100644
index 00000000000..4e7203efe9b
--- /dev/null
+++ b/source/blender/blenlib/intern/serialize.cc
@@ -0,0 +1,217 @@
+#include "BLI_serialize.hh"
+
+#include "json.hpp"
+
+namespace blender::io::serialize {
+
+const StringValue *Value::as_string_value() const
+{
+ if (type_ != eValueType::String) {
+ return nullptr;
+ }
+ return static_cast<const StringValue *>(this);
+}
+
+const IntValue *Value::as_int_value() const
+{
+ if (type_ != eValueType::Int) {
+ return nullptr;
+ }
+ return static_cast<const IntValue *>(this);
+}
+
+const DoubleValue *Value::as_double_value() const
+{
+ if (type_ != eValueType::Double) {
+ return nullptr;
+ }
+ return static_cast<const DoubleValue *>(this);
+}
+
+const BooleanValue *Value::as_boolean_value() const
+{
+ if (type_ != eValueType::Boolean) {
+ return nullptr;
+ }
+ return static_cast<const BooleanValue *>(this);
+}
+
+const ArrayValue *Value::as_array_value() const
+{
+ if (type_ != eValueType::Array) {
+ return nullptr;
+ }
+ return static_cast<const ArrayValue *>(this);
+}
+
+const DictionaryValue *Value::as_dictionary_value() const
+{
+ if (type_ != eValueType::Dictionary) {
+ return nullptr;
+ }
+ return static_cast<const DictionaryValue *>(this);
+}
+
+static void convert_to_json(nlohmann::ordered_json &j, const Value &value);
+static void convert_to_json(nlohmann::ordered_json &j, const ArrayValue &value)
+{
+ const ArrayValue::Items &items = value.elements();
+ /* Create a json array to store the elements. If this isn't done and items is empty it would
+ * return use a null value, in stead of an empty array. */
+ j = "[]"_json;
+ for (const ArrayValue::Item &item_value : items) {
+ nlohmann::ordered_json json_item;
+ convert_to_json(json_item, *item_value);
+ j.push_back(json_item);
+ }
+}
+
+static void convert_to_json(nlohmann::ordered_json &j, const DictionaryValue &value)
+{
+ const DictionaryValue::Items &attributes = value.elements();
+ /* Create a json object to store the attributes. If this isn't done and attributes is empty it
+ * would return use a null value, in stead of an empty object. */
+ j = "{}"_json;
+ for (const DictionaryValue::Item &attribute : attributes) {
+ nlohmann::ordered_json json_item;
+ convert_to_json(json_item, *attribute.second);
+ j[attribute.first] = json_item;
+ }
+}
+
+static void convert_to_json(nlohmann::ordered_json &j, const Value &value)
+{
+ switch (value.type()) {
+ case eValueType::String: {
+ j = value.as_string_value()->value();
+ break;
+ }
+
+ case eValueType::Int: {
+ j = value.as_int_value()->value();
+ break;
+ }
+
+ case eValueType::Array: {
+ const ArrayValue &array = *value.as_array_value();
+ convert_to_json(j, array);
+ break;
+ }
+
+ case eValueType::Dictionary: {
+ const DictionaryValue &object = *value.as_dictionary_value();
+ convert_to_json(j, object);
+ break;
+ }
+
+ case eValueType::Null: {
+ j = nullptr;
+ break;
+ }
+
+ case eValueType::Boolean: {
+ j = value.as_boolean_value()->value();
+ break;
+ }
+
+ case eValueType::Double: {
+ j = value.as_double_value()->value();
+ }
+ }
+}
+
+static std::unique_ptr<Value> convert_from_json(const nlohmann::ordered_json &j);
+static std::unique_ptr<ArrayValue> convert_from_json_to_array(const nlohmann::ordered_json &j)
+{
+ std::unique_ptr<ArrayValue> array = std::make_unique<ArrayValue>();
+ ArrayValue::Items &elements = array->elements();
+ for (auto element : j.items()) {
+ nlohmann::ordered_json element_json = element.value();
+ std::unique_ptr<Value> value = convert_from_json(element_json);
+ elements.append_as(value.release());
+ }
+ return array;
+}
+
+static std::unique_ptr<DictionaryValue> convert_from_json_to_object(
+ const nlohmann::ordered_json &j)
+{
+ std::unique_ptr<DictionaryValue> object = std::make_unique<DictionaryValue>();
+ DictionaryValue::Items &elements = object->elements();
+ for (auto element : j.items()) {
+ std::string key = element.key();
+ nlohmann::ordered_json element_json = element.value();
+ std::unique_ptr<Value> value = convert_from_json(element_json);
+ elements.append_as(std::pair(key, value.release()));
+ }
+ return object;
+}
+
+static std::unique_ptr<Value> convert_from_json(const nlohmann::ordered_json &j)
+{
+ switch (j.type()) {
+ case nlohmann::json::value_t::array: {
+ return convert_from_json_to_array(j);
+ }
+
+ case nlohmann::json::value_t::object: {
+ return convert_from_json_to_object(j);
+ }
+
+ case nlohmann::json::value_t::string: {
+ std::string value = j;
+ return std::make_unique<StringValue>(value);
+ }
+
+ case nlohmann::json::value_t::null: {
+ return std::make_unique<NullValue>();
+ }
+
+ case nlohmann::json::value_t::boolean: {
+ return std::make_unique<BooleanValue>(j);
+ }
+ case nlohmann::json::value_t::number_integer:
+ case nlohmann::json::value_t::number_unsigned: {
+ return std::make_unique<IntValue>(j);
+ }
+
+ case nlohmann::json::value_t::number_float: {
+ return std::make_unique<DoubleValue>(j);
+ }
+
+ case nlohmann::json::value_t::binary:
+ case nlohmann::json::value_t::discarded:
+ /*
+ * Binary data isn't supported.
+ * Discarded is an internal type of nlohmann.
+ *
+ * Assert in case we need to parse them.
+ */
+ BLI_assert_unreachable();
+ return std::make_unique<NullValue>();
+ }
+
+ BLI_assert_unreachable();
+ return std::make_unique<NullValue>();
+}
+
+void JsonFormatter::serialize(std::ostream &os, const Value &value)
+{
+ nlohmann::ordered_json j;
+ convert_to_json(j, value);
+ if (indentation_len) {
+ os << j.dump(indentation_len);
+ }
+ else {
+ os << j.dump();
+ }
+}
+
+std::unique_ptr<Value> JsonFormatter::deserialize(std::istream &is)
+{
+ nlohmann::ordered_json j;
+ is >> j;
+ return convert_from_json(j);
+}
+
+} // namespace blender::io::serialize
diff --git a/source/blender/blenlib/intern/session_uuid.c b/source/blender/blenlib/intern/session_uuid.c
index 8ed96f02149..ac15a400a92 100644
--- a/source/blender/blenlib/intern/session_uuid.c
+++ b/source/blender/blenlib/intern/session_uuid.c
@@ -74,5 +74,5 @@ bool BLI_session_uuid_ghash_compare(const void *lhs_v, const void *rhs_v)
{
const SessionUUID *lhs = (const SessionUUID *)lhs_v;
const SessionUUID *rhs = (const SessionUUID *)rhs_v;
- return BLI_session_uuid_is_equal(lhs, rhs);
+ return !BLI_session_uuid_is_equal(lhs, rhs);
}
diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c
index 006a3798dcd..2278daf5516 100644
--- a/source/blender/blenlib/intern/smallhash.c
+++ b/source/blender/blenlib/intern/smallhash.c
@@ -214,7 +214,6 @@ void BLI_smallhash_init(SmallHash *sh)
BLI_smallhash_init_ex(sh, 0);
}
-/* NOTE: does *not* free *sh itself! only the direct data! */
void BLI_smallhash_release(SmallHash *sh)
{
if (sh->buckets != sh->buckets_stack) {
@@ -239,13 +238,6 @@ void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item)
e->val = item;
}
-/**
- * Inserts a new value to a key that may already be in ghash.
- *
- * Avoids #BLI_smallhash_remove, #BLI_smallhash_insert calls (double lookups)
- *
- * \returns true if a new key has been added.
- */
bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item)
{
SmallHashEntry *e = smallhash_lookup(sh, key);
@@ -389,12 +381,6 @@ void BLI_smallhash_print(SmallHash *sh)
#endif
#ifdef DEBUG
-/**
- * Measure how well the hash function performs
- * (1.0 is perfect - no stepping needed).
- *
- * Smaller is better!
- */
double BLI_smallhash_calc_quality(SmallHash *sh)
{
uint64_t sum = 0;
diff --git a/source/blender/blenlib/intern/stack.c b/source/blender/blenlib/intern/stack.c
index 4a9bdd48a0a..629a6eaa78c 100644
--- a/source/blender/blenlib/intern/stack.c
+++ b/source/blender/blenlib/intern/stack.c
@@ -91,9 +91,6 @@ BLI_Stack *BLI_stack_new_ex(const size_t elem_size,
return stack;
}
-/**
- * Create a new homogeneous stack with elements of 'elem_size' bytes.
- */
BLI_Stack *BLI_stack_new(const size_t elem_size, const char *description)
{
return BLI_stack_new_ex(elem_size, description, CHUNK_SIZE_DEFAULT);
@@ -108,9 +105,6 @@ static void stack_free_chunks(struct StackChunk *data)
}
}
-/**
- * Free the stack's data and the stack itself
- */
void BLI_stack_free(BLI_Stack *stack)
{
stack_free_chunks(stack->chunk_curr);
@@ -118,12 +112,6 @@ void BLI_stack_free(BLI_Stack *stack)
MEM_freeN(stack);
}
-/**
- * Push a new item onto the stack.
- *
- * \return a pointer #BLI_Stack.elem_size
- * bytes of uninitialized memory (caller must fill in).
- */
void *BLI_stack_push_r(BLI_Stack *stack)
{
stack->chunk_index++;
@@ -152,26 +140,12 @@ void *BLI_stack_push_r(BLI_Stack *stack)
return stack_get_last_elem(stack);
}
-/**
- * Copies the source value onto the stack
- *
- * \note This copies #BLI_Stack.elem_size bytes from \a src,
- * (the pointer itself is not stored).
- *
- * \param src: source data to be copied to the stack.
- */
void BLI_stack_push(BLI_Stack *stack, const void *src)
{
void *dst = BLI_stack_push_r(stack);
memcpy(dst, src, stack->elem_size);
}
-/**
- * Retrieves and removes the top element from the stack.
- * The value is copies to \a dst, which must be at least \a elem_size bytes.
- *
- * Does not reduce amount of allocated memory.
- */
void BLI_stack_pop(BLI_Stack *stack, void *dst)
{
BLI_assert(BLI_stack_is_empty(stack) == false);
@@ -181,15 +155,6 @@ void BLI_stack_pop(BLI_Stack *stack, void *dst)
BLI_stack_discard(stack);
}
-/**
- * A version of #BLI_stack_pop which fills in an array.
- *
- * \param dst: The destination array,
- * must be at least (#BLI_Stack.elem_size * \a n) bytes long.
- * \param n: The number of items to pop.
- *
- * \note The first item in the array will be last item added to the stack.
- */
void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n)
{
BLI_assert(n <= BLI_stack_count(stack));
@@ -200,11 +165,6 @@ void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n)
}
}
-/**
- * A version of #BLI_stack_pop_n which fills in an array (in the reverse order).
- *
- * \note The first item in the array will be first item added to the stack.
- */
void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, unsigned int n)
{
BLI_assert(n <= BLI_stack_count(stack));
@@ -224,9 +184,6 @@ void *BLI_stack_peek(BLI_Stack *stack)
return stack_get_last_elem(stack);
}
-/**
- * Removes the top element from the stack.
- */
void BLI_stack_discard(BLI_Stack *stack)
{
BLI_assert(BLI_stack_is_empty(stack) == false);
@@ -247,9 +204,6 @@ void BLI_stack_discard(BLI_Stack *stack)
}
}
-/**
- * Discards all elements without freeing.
- */
void BLI_stack_clear(BLI_Stack *stack)
{
#ifdef USE_TOTELEM
@@ -304,9 +258,6 @@ size_t BLI_stack_count(const BLI_Stack *stack)
#endif
}
-/**
- * Returns true if the stack is empty, false otherwise
- */
bool BLI_stack_is_empty(const BLI_Stack *stack)
{
#ifdef USE_TOTELEM
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index 47bb2f0e8dd..c5e30ac6a6b 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -72,12 +72,6 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-/**
- * Copies the current working directory into *dir (max size maxncpy), and
- * returns a pointer to same.
- *
- * \note can return NULL when the size is not big enough
- */
char *BLI_current_working_dir(char *dir, const size_t maxncpy)
{
#if defined(WIN32)
@@ -102,10 +96,6 @@ char *BLI_current_working_dir(char *dir, const size_t maxncpy)
#endif
}
-/**
- * Returns the number of free bytes on the volume containing the specified pathname. */
-/* Not actually used anywhere.
- */
double BLI_dir_free_space(const char *dir)
{
#ifdef WIN32
@@ -201,9 +191,6 @@ int64_t BLI_lseek(int fd, int64_t offset, int whence)
#endif
}
-/**
- * Returns the file size of an opened file descriptor.
- */
size_t BLI_file_descriptor_size(int file)
{
BLI_stat_t st;
@@ -213,9 +200,6 @@ size_t BLI_file_descriptor_size(int file)
return st.st_size;
}
-/**
- * Returns the size of a file.
- */
size_t BLI_file_size(const char *path)
{
BLI_stat_t stats;
@@ -343,10 +327,6 @@ bool BLI_file_alias_target(const char *filepath,
}
#endif
-/**
- * Returns the st_mode from stat-ing the specified path name, or 0 if stat fails
- * (most likely doesn't exist or no access).
- */
int BLI_exists(const char *path)
{
#if defined(WIN32)
@@ -430,18 +410,11 @@ int BLI_stat(const char *path, struct stat *buffer)
}
#endif
-/**
- * Does the specified path point to a directory?
- * \note Would be better in fileops.c except that it needs stat.h so add here
- */
bool BLI_is_dir(const char *file)
{
return S_ISDIR(BLI_exists(file));
}
-/**
- * Does the specified path point to a non-directory?
- */
bool BLI_is_file(const char *path)
{
const int mode = BLI_exists(path);
@@ -528,33 +501,6 @@ void *BLI_file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t
return mem;
}
-/**
- * Return the text file data with:
-
- * - Newlines replaced with '\0'.
- * - Optionally trim white-space, replacing trailing <space> & <tab> with '\0'.
- *
- * This is an alternative to using #BLI_file_read_as_lines,
- * allowing us to loop over lines without converting it into a linked list
- * with individual allocations.
- *
- * \param trim_trailing_space: Replace trailing spaces & tabs with nil.
- * This arguments prevents the caller from counting blank lines (if that's important).
- * \param pad_bytes: When this is non-zero, the first byte is set to nil,
- * to simplify parsing the file.
- * It's recommended to pass in 1, so all text is nil terminated.
- *
- * Example looping over lines:
- *
- * \code{.c}
- * size_t data_len;
- * char *data = BLI_file_read_text_as_mem_with_newline_as_nil(filepath, true, 1, &data_len);
- * char *data_end = data + data_len;
- * for (char *line = data; line != data_end; line = strlen(line) + 1) {
- * printf("line='%s'\n", line);
- * }
- * \endcode
- */
void *BLI_file_read_text_as_mem_with_newline_as_nil(const char *filepath,
bool trim_trailing_space,
size_t pad_bytes,
@@ -585,9 +531,6 @@ void *BLI_file_read_text_as_mem_with_newline_as_nil(const char *filepath,
return mem;
}
-/**
- * Reads the contents of a text file and returns the lines in a linked list.
- */
LinkNode *BLI_file_read_as_lines(const char *filepath)
{
FILE *fp = BLI_fopen(filepath, "r");
@@ -634,15 +577,11 @@ LinkNode *BLI_file_read_as_lines(const char *filepath)
return lines.list;
}
-/*
- * Frees memory from a previous call to BLI_file_read_as_lines.
- */
void BLI_file_free_lines(LinkNode *lines)
{
BLI_linklist_freeN(lines);
}
-/** is file1 older than file2 */
bool BLI_file_older(const char *file1, const char *file2)
{
#ifdef WIN32
diff --git a/source/blender/blenlib/intern/storage_apple.mm b/source/blender/blenlib/intern/storage_apple.mm
index 8af98d61ecb..b0234b9a093 100644
--- a/source/blender/blenlib/intern/storage_apple.mm
+++ b/source/blender/blenlib/intern/storage_apple.mm
@@ -99,7 +99,7 @@ static bool find_attribute(const std::string &attributes, const char *search_att
*/
static bool test_onedrive_file_is_placeholder(const char *path)
{
- /* Note: Currently only checking for the "com.microsoft.OneDrive.RecallOnOpen" extended file
+ /* NOTE: Currently only checking for the "com.microsoft.OneDrive.RecallOnOpen" extended file
* attribute. In theory this attribute can also be set on files that aren't located inside a
* OneDrive folder. Maybe additional checks are required? */
@@ -184,3 +184,20 @@ eFileAttributes BLI_file_attributes(const char *path)
return (eFileAttributes)ret;
}
+
+const char *BLI_expand_tilde(const char *path_with_tilde)
+{
+ static char path_expanded[FILE_MAX];
+ @autoreleasepool {
+ const NSString *const str_with_tilde = [[NSString alloc] initWithCString:path_with_tilde
+ encoding:NSUTF8StringEncoding];
+ if (!str_with_tilde) {
+ return nullptr;
+ }
+ const NSString *const str_expanded = [str_with_tilde stringByExpandingTildeInPath];
+ [str_expanded getCString:path_expanded
+ maxLength:sizeof(path_expanded)
+ encoding:NSUTF8StringEncoding];
+ }
+ return path_expanded;
+}
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index 0ea784c95b0..2c626773871 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -42,15 +42,10 @@
// #define DEBUG_STRSIZE
-/**
- * Duplicates the first \a len bytes of cstring \a str
- * into a newly mallocN'd string and returns it. \a str
- * is assumed to be at least len bytes long.
- *
- * \param str: The string to be duplicated
- * \param len: The number of bytes to duplicate
- * \retval Returns the duplicated string
- */
+/* -------------------------------------------------------------------- */
+/** \name String Duplicate/Copy
+ * \{ */
+
char *BLI_strdupn(const char *str, const size_t len)
{
char *n = MEM_mallocN(len + 1, "strdup");
@@ -60,24 +55,11 @@ char *BLI_strdupn(const char *str, const size_t len)
return n;
}
-/**
- * Duplicates the cstring \a str into a newly mallocN'd
- * string and returns it.
- *
- * \param str: The string to be duplicated
- * \retval Returns the duplicated string
- */
char *BLI_strdup(const char *str)
{
return BLI_strdupn(str, strlen(str));
}
-/**
- * Appends the two strings, and returns new mallocN'ed string
- * \param str1: first string for copy
- * \param str2: second string for append
- * \retval Returns dst
- */
char *BLI_strdupcat(const char *__restrict str1, const char *__restrict str2)
{
/* include the NULL terminator of str2 only */
@@ -95,16 +77,6 @@ char *BLI_strdupcat(const char *__restrict str1, const char *__restrict str2)
return str;
}
-/**
- * Like strncpy but ensures dst is always
- * '\0' terminated.
- *
- * \param dst: Destination for copy
- * \param src: Source string to copy
- * \param maxncpy: Maximum number of characters to copy (generally
- * the size of dst)
- * \retval Returns dst
- */
char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
{
size_t srclen = BLI_strnlen(src, maxncpy - 1);
@@ -119,16 +91,6 @@ char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t
return dst;
}
-/**
- * Like BLI_strncpy but ensures dst is always padded by given char,
- * on both sides (unless src is empty).
- *
- * \param dst: Destination for copy
- * \param src: Source string to copy
- * \param pad: the char to use for padding
- * \param maxncpy: Maximum number of characters to copy (generally the size of dst)
- * \retval Returns dst
- */
char *BLI_strncpy_ensure_pad(char *__restrict dst,
const char *__restrict src,
const char pad,
@@ -171,19 +133,6 @@ char *BLI_strncpy_ensure_pad(char *__restrict dst,
return dst;
}
-/**
- * Like strncpy but ensures dst is always
- * '\0' terminated.
- *
- * \note This is a duplicate of #BLI_strncpy that returns bytes copied.
- * And is a drop in replacement for 'snprintf(str, sizeof(str), "%s", arg);'
- *
- * \param dst: Destination for copy
- * \param src: Source string to copy
- * \param maxncpy: Maximum number of characters to copy (generally
- * the size of dst)
- * \retval The number of bytes copied (The only difference from BLI_strncpy).
- */
size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
{
size_t srclen = BLI_strnlen(src, maxncpy - 1);
@@ -205,9 +154,12 @@ size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src)
return srclen;
}
-/**
- * Portable replacement for `vsnprintf`.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Printing
+ * \{ */
+
size_t BLI_vsnprintf(char *__restrict buffer,
size_t maxncpy,
const char *__restrict format,
@@ -231,9 +183,6 @@ size_t BLI_vsnprintf(char *__restrict buffer,
return n;
}
-/**
- * A version of #BLI_vsnprintf that returns `strlen(buffer)`
- */
size_t BLI_vsnprintf_rlen(char *__restrict buffer,
size_t maxncpy,
const char *__restrict format,
@@ -258,9 +207,6 @@ size_t BLI_vsnprintf_rlen(char *__restrict buffer,
return n;
}
-/**
- * Portable replacement for #snprintf
- */
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
{
size_t n;
@@ -277,9 +223,6 @@ size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict
return n;
}
-/**
- * A version of #BLI_snprintf that returns `strlen(dst)`
- */
size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
{
size_t n;
@@ -296,10 +239,6 @@ size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__res
return n;
}
-/**
- * Print formatted string into a newly #MEM_mallocN'd string
- * and return it.
- */
char *BLI_sprintfN(const char *__restrict format, ...)
{
DynStr *ds;
@@ -318,18 +257,12 @@ char *BLI_sprintfN(const char *__restrict format, ...)
return n;
}
-/**
- * This roughly matches C and Python's string escaping with double quotes - `"`.
- *
- * Since every character may need escaping,
- * it's common to create a buffer twice as large as the input.
- *
- * \param dst: The destination string, at least \a dst_maxncpy, typically `(strlen(src) * 2) + 1`.
- * \param src: The un-escaped source string.
- * \param dst_maxncpy: The maximum number of bytes allowable to copy.
- *
- * \note This is used for creating animation paths in blend files.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Escape/Un-Escape
+ * \{ */
+
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
{
@@ -381,18 +314,6 @@ BLI_INLINE bool str_unescape_pair(char c_next, char *r_out)
return false;
}
-/**
- * This roughly matches C and Python's string escaping with double quotes - `"`.
- *
- * The destination will never be larger than the source, it will either be the same
- * or up to half when all characters are escaped.
- *
- * \param dst: The destination string, at least the size of `strlen(src) + 1`.
- * \param src: The escaped source string.
- * \param src_maxncpy: The maximum number of bytes allowable to copy from `src`.
- * \param dst_maxncpy: The maximum number of bytes allowable to copy into `dst`.
- * \param r_is_complete: Set to true when
- */
size_t BLI_str_unescape_ex(char *__restrict dst,
const char *__restrict src,
const size_t src_maxncpy,
@@ -418,16 +339,6 @@ size_t BLI_str_unescape_ex(char *__restrict dst,
return len;
}
-/**
- * See #BLI_str_unescape_ex doc-string.
- *
- * This function makes the assumption that `dst` always has
- * at least `src_maxncpy` bytes available.
- *
- * Use #BLI_str_unescape_ex if `dst` has a smaller fixed size.
- *
- * \note This is used for parsing animation paths in blend files (runs often).
- */
size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy)
{
size_t len = 0;
@@ -442,14 +353,6 @@ size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const
return len;
}
-/**
- * Find the first un-escaped quote in the string (to find the end of the string).
- *
- * \param str: Typically this is the first character in a quoted string.
- * Where the character before `*str` would be `"`.
-
- * \return The pointer to the first un-escaped quote.
- */
const char *BLI_str_escape_find_quote(const char *str)
{
bool escape = false;
@@ -462,18 +365,12 @@ const char *BLI_str_escape_find_quote(const char *str)
return (*str == '"') ? str : NULL;
}
-/**
- * Return the range of the quoted string (excluding quotes) `str` after `prefix`.
- *
- * A version of #BLI_str_quoted_substrN that calculates the range
- * instead of un-escaping and allocating the result.
- *
- * \param str: String potentially including `prefix`.
- * \param prefix: Quoted string prefix.
- * \param r_start: The start of the quoted string (after the first quote).
- * \param r_end: The end of the quoted string (before the last quote).
- * \return True when a quoted string range could be found after `prefix`.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Quote/Un-Quote
+ * \{ */
+
bool BLI_str_quoted_substr_range(const char *__restrict str,
const char *__restrict prefix,
int *__restrict r_start,
@@ -539,19 +436,6 @@ char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict
}
#endif
-/**
- * Fills \a result with text within "" that appear after some the contents of \a prefix.
- * i.e. for string `pose["apples"]` with prefix `pose[`, it will return `apples`.
- *
- * \param str: is the entire string to chop.
- * \param prefix: is the part of the string to step over.
- * \param result: The buffer to fill.
- * \param result_maxlen: The maximum size of the buffer (including nil terminator).
- * \return True if the prefix was found and the entire quoted string was copied into result.
- *
- * Assume that the strings returned must be freed afterwards,
- * and that the inputs will contain data we want.
- */
bool BLI_str_quoted_substr(const char *__restrict str,
const char *__restrict prefix,
char *result,
@@ -570,19 +454,12 @@ bool BLI_str_quoted_substr(const char *__restrict str,
return is_complete;
}
-/**
- * string with all instances of substr_old replaced with substr_new,
- * Returns a copy of the c-string \a str into a newly #MEM_mallocN'd
- * and returns it.
- *
- * \note A rather wasteful string-replacement utility, though this shall do for now...
- * Feel free to replace this with an even safe + nicer alternative
- *
- * \param str: The string to replace occurrences of substr_old in
- * \param substr_old: The text in the string to find and replace
- * \param substr_new: The text in the string to find and replace
- * \retval Returns the duplicated string
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Replace
+ * \{ */
+
char *BLI_str_replaceN(const char *__restrict str,
const char *__restrict substr_old,
const char *__restrict substr_new)
@@ -638,13 +515,6 @@ char *BLI_str_replaceN(const char *__restrict str,
return BLI_strdup(str);
}
-/**
- * In-place replace every \a src to \a dst in \a str.
- *
- * \param str: The string to operate on.
- * \param src: The character to replace.
- * \param dst: The character to replace with.
- */
void BLI_str_replace_char(char *str, char src, char dst)
{
while (*str) {
@@ -655,13 +525,6 @@ void BLI_str_replace_char(char *str, char src, char dst)
}
}
-/**
- * Simple exact-match string replacement.
- *
- * \param replace_table: Array of source, destination pairs.
- *
- * \note Larger tables should use a hash table.
- */
bool BLI_str_replace_table_exact(char *string,
const size_t string_len,
const char *replace_table[][2],
@@ -678,19 +541,15 @@ bool BLI_str_replace_table_exact(char *string,
/** \} */
-/**
- * Compare two strings without regard to case.
- *
- * \retval True if the strings are equal, false otherwise.
- */
+/* -------------------------------------------------------------------- */
+/** \name String Comparison/Matching
+ * \{ */
+
int BLI_strcaseeq(const char *a, const char *b)
{
return (BLI_strcasecmp(a, b) == 0);
}
-/**
- * Portable replacement for `strcasestr` (not available in MSVC)
- */
char *BLI_strcasestr(const char *s, const char *find)
{
char c, sc;
@@ -745,9 +604,6 @@ bool BLI_string_all_words_matched(const char *name,
return all_words_matched;
}
-/**
- * Variation of #BLI_strcasestr with string length limited to \a len
- */
char *BLI_strncasestr(const char *s, const char *find, size_t len)
{
char c, sc;
@@ -875,10 +731,6 @@ static int left_number_strcmp(const char *s1, const char *s2, int *tiebreaker)
return 0;
}
-/**
- * Case insensitive, *natural* string comparison,
- * keeping numbers in order.
- */
int BLI_strcasecmp_natural(const char *s1, const char *s2)
{
int d1 = 0, d2 = 0;
@@ -946,10 +798,6 @@ int BLI_strcasecmp_natural(const char *s1, const char *s2)
return strcmp(s1, s2);
}
-/**
- * Like strcmp, but will ignore any heading/trailing pad char for comparison.
- * So e.g. if pad is '*', '*world' and 'world*' will compare equal.
- */
int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad)
{
size_t str1_len, str2_len;
@@ -990,7 +838,79 @@ int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad)
}
}
-/* determine the length of a fixed-size string */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Comparison at Start/End
+ * \{ */
+
+int BLI_str_index_in_array_n(const char *__restrict str,
+ const char **__restrict str_array,
+ const int str_array_len)
+{
+ int index;
+ const char **str_iter = str_array;
+
+ for (index = 0; index < str_array_len; str_iter++, index++) {
+ if (STREQ(str, *str_iter)) {
+ return index;
+ }
+ }
+ return -1;
+}
+
+int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
+{
+ int index;
+ const char **str_iter = str_array;
+
+ for (index = 0; *str_iter; str_iter++, index++) {
+ if (STREQ(str, *str_iter)) {
+ return index;
+ }
+ }
+ return -1;
+}
+
+bool BLI_str_startswith(const char *__restrict str, const char *__restrict start)
+{
+ for (; *str && *start; str++, start++) {
+ if (*str != *start) {
+ return false;
+ }
+ }
+
+ return (*start == '\0');
+}
+
+bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t slength)
+{
+ size_t elength = strlen(end);
+
+ if (elength < slength) {
+ const char *iter = &str[slength - elength];
+ while (*iter) {
+ if (*iter++ != *end++) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool BLI_str_endswith(const char *__restrict str, const char *__restrict end)
+{
+ const size_t slength = strlen(str);
+ return BLI_strn_endswith(str, end, slength);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Length
+ * \{ */
+
size_t BLI_strnlen(const char *s, const size_t maxlen)
{
size_t len;
@@ -1003,6 +923,12 @@ size_t BLI_strnlen(const char *s, const size_t maxlen)
return len;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Case Conversion
+ * \{ */
+
void BLI_str_tolower_ascii(char *str, const size_t len)
{
size_t i;
@@ -1025,9 +951,12 @@ void BLI_str_toupper_ascii(char *str, const size_t len)
}
}
-/**
- * Strip whitespace from end of the string.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Stripping
+ * \{ */
+
void BLI_str_rstrip(char *str)
{
for (int i = (int)strlen(str) - 1; i >= 0; i--) {
@@ -1040,15 +969,6 @@ void BLI_str_rstrip(char *str)
}
}
-/**
- * Strip trailing zeros from a float, eg:
- * 0.0000 -> 0.0
- * 2.0010 -> 2.001
- *
- * \param str:
- * \param pad:
- * \return The number of zeros stripped.
- */
int BLI_str_rstrip_float_zero(char *str, const char pad)
{
char *p = strchr(str, '.');
@@ -1069,138 +989,22 @@ int BLI_str_rstrip_float_zero(char *str, const char pad)
return totstrip;
}
-/**
- * Return index of a string in a string array.
- *
- * \param str: The string to find.
- * \param str_array: Array of strings.
- * \param str_array_len: The length of the array, or -1 for a NULL-terminated array.
- * \return The index of str in str_array or -1.
- */
-int BLI_str_index_in_array_n(const char *__restrict str,
- const char **__restrict str_array,
- const int str_array_len)
-{
- int index;
- const char **str_iter = str_array;
-
- for (index = 0; index < str_array_len; str_iter++, index++) {
- if (STREQ(str, *str_iter)) {
- return index;
- }
- }
- return -1;
-}
-
-/**
- * Return index of a string in a string array.
- *
- * \param str: The string to find.
- * \param str_array: Array of strings, (must be NULL-terminated).
- * \return The index of str in str_array or -1.
- */
-int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
-{
- int index;
- const char **str_iter = str_array;
-
- for (index = 0; *str_iter; str_iter++, index++) {
- if (STREQ(str, *str_iter)) {
- return index;
- }
- }
- return -1;
-}
-
-/**
- * Find if a string starts with another string.
- *
- * \param str: The string to search within.
- * \param start: The string we look for at the start.
- * \return If str starts with start.
- */
-bool BLI_str_startswith(const char *__restrict str, const char *__restrict start)
-{
- for (; *str && *start; str++, start++) {
- if (*str != *start) {
- return false;
- }
- }
-
- return (*start == '\0');
-}
-
-bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t slength)
-{
- size_t elength = strlen(end);
+/** \} */
- if (elength < slength) {
- const char *iter = &str[slength - elength];
- while (*iter) {
- if (*iter++ != *end++) {
- return false;
- }
- }
- return true;
- }
- return false;
-}
+/* -------------------------------------------------------------------- */
+/** \name String Split (Partition)
+ * \{ */
-/**
- * Find if a string ends with another string.
- *
- * \param str: The string to search within.
- * \param end: The string we look for at the end.
- * \return If str ends with end.
- */
-bool BLI_str_endswith(const char *__restrict str, const char *__restrict end)
-{
- const size_t slength = strlen(str);
- return BLI_strn_endswith(str, end, slength);
-}
-
-/**
- * Find the first char matching one of the chars in \a delim, from left.
- *
- * \param str: The string to search within.
- * \param delim: The set of delimiters to search for, as unicode values.
- * \param sep: Return value, set to the first delimiter found (or NULL if none found).
- * \param suf: Return value, set to next char after the first delimiter found
- * (or NULL if none found).
- * \return The length of the prefix (i.e. *sep - str).
- */
size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf)
{
return BLI_str_partition_ex(str, NULL, delim, sep, suf, false);
}
-/**
- * Find the first char matching one of the chars in \a delim, from right.
- *
- * \param str: The string to search within.
- * \param delim: The set of delimiters to search for, as unicode values.
- * \param sep: Return value, set to the first delimiter found (or NULL if none found).
- * \param suf: Return value, set to next char after the first delimiter found
- * (or NULL if none found).
- * \return The length of the prefix (i.e. *sep - str).
- */
size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf)
{
return BLI_str_partition_ex(str, NULL, delim, sep, suf, true);
}
-/**
- * Find the first char matching one of the chars in \a delim, either from left or right.
- *
- * \param str: The string to search within.
- * \param end: If non-NULL, the right delimiter of the string.
- * \param delim: The set of delimiters to search for, as unicode values.
- * \param sep: Return value, set to the first delimiter found (or NULL if none found).
- * \param suf: Return value, set to next char after the first delimiter found
- * (or NULL if none found).
- * \param from_right: If %true, search from the right of \a str, else, search from its left.
- * \return The length of the prefix (i.e. *sep - str).
- */
size_t BLI_str_partition_ex(const char *str,
const char *end,
const char delim[],
@@ -1251,6 +1055,47 @@ size_t BLI_str_partition_ex(const char *str,
return end ? (size_t)(end - str) : strlen(str);
}
+int BLI_string_find_split_words(
+ const char *str, const size_t len, const char delim, int r_words[][2], int words_max)
+{
+ int n = 0, i;
+ bool charsearch = true;
+
+ /* Skip leading spaces */
+ for (i = 0; (i < len) && (str[i] != '\0'); i++) {
+ if (str[i] != delim) {
+ break;
+ }
+ }
+
+ for (; (i < len) && (str[i] != '\0') && (n < words_max); i++) {
+ if ((str[i] != delim) && (charsearch == true)) {
+ r_words[n][0] = i;
+ charsearch = false;
+ }
+ else {
+ if ((str[i] == delim) && (charsearch == false)) {
+ r_words[n][1] = i - r_words[n][0];
+ n++;
+ charsearch = true;
+ }
+ }
+ }
+
+ if (charsearch == false) {
+ r_words[n][1] = i - r_words[n][0];
+ n++;
+ }
+
+ return n;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Formatting (Numeric)
+ * \{ */
+
static size_t BLI_str_format_int_grouped_ex(char src[16], char dst[16], int num_len)
{
char *p_src = src;
@@ -1275,14 +1120,6 @@ static size_t BLI_str_format_int_grouped_ex(char src[16], char dst[16], int num_
return (size_t)(p_dst - dst);
}
-/**
- * Format ints with decimal grouping.
- * 1000 -> 1,000
- *
- * \param dst: The resulting string
- * \param num: Number to format
- * \return The length of \a dst
- */
size_t BLI_str_format_int_grouped(char dst[16], int num)
{
char src[16];
@@ -1291,14 +1128,6 @@ size_t BLI_str_format_int_grouped(char dst[16], int num)
return BLI_str_format_int_grouped_ex(src, dst, num_len);
}
-/**
- * Format uint64_t with decimal grouping.
- * 1000 -> 1,000
- *
- * \param dst: The resulting string
- * \param num: Number to format
- * \return The length of \a dst
- */
size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num)
{
/* NOTE: Buffer to hold maximum unsigned int64, which is 1.8e+19. but
@@ -1309,16 +1138,6 @@ size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num)
return BLI_str_format_int_grouped_ex(src, dst, num_len);
}
-/**
- * Format a size in bytes using binary units.
- * 1000 -> 1 KB
- * Number of decimal places grows with the used unit (e.g. 1.5 MB, 1.55 GB, 1.545 TB).
- *
- * \param dst: The resulting string.
- * Dimension of 14 to support largest possible value for \a bytes (#LLONG_MAX).
- * \param bytes: Number to format.
- * \param base_10: Calculate using base 10 (GB, MB, ...) or 2 (GiB, MiB, ...).
- */
void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base_10)
{
double bytes_converted = bytes;
@@ -1345,26 +1164,6 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base
BLI_strncpy(dst + len, base_10 ? units_base_10[order] : units_base_2[order], dst_len - len);
}
-/**
- * Format a attribute domain to a up to 6 places (plus '\0' terminator) string using long number
- * names abbreviations. This function is designed to produce a compact representation of large
- * numbers.
- *
- * 1 -> 1
- * 15 -> 15
- * 155 -> 155
- * 1555 -> 1.6K
- * 15555 -> 15.6K
- * 155555 -> 156K
- * 1555555 -> 1.6M
- * 15555555 -> 15.6M
- * 155555555 -> 156M
- * 1000000000 -> 1B
- * ...
- *
- * Dimension of 7 is the maximum length of the resulting string
- * A combination with 7 places would be -15.5K\0
- */
void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format)
{
float number_to_format_converted = number_to_format;
@@ -1386,47 +1185,4 @@ void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format)
BLI_snprintf(dst, dst_len, "%.*f%s", decimals, number_to_format_converted, units[order]);
}
-/**
- * Find the ranges needed to split \a str into its individual words.
- *
- * \param str: The string to search for words.
- * \param len: Size of the string to search.
- * \param delim: Character to use as a delimiter.
- * \param r_words: Info about the words found. Set to [index, len] pairs.
- * \param words_max: Max number of words to find
- * \return The number of words found in \a str
- */
-int BLI_string_find_split_words(
- const char *str, const size_t len, const char delim, int r_words[][2], int words_max)
-{
- int n = 0, i;
- bool charsearch = true;
-
- /* Skip leading spaces */
- for (i = 0; (i < len) && (str[i] != '\0'); i++) {
- if (str[i] != delim) {
- break;
- }
- }
-
- for (; (i < len) && (str[i] != '\0') && (n < words_max); i++) {
- if ((str[i] != delim) && (charsearch == true)) {
- r_words[n][0] = i;
- charsearch = false;
- }
- else {
- if ((str[i] == delim) && (charsearch == false)) {
- r_words[n][1] = i - r_words[n][0];
- n++;
- charsearch = true;
- }
- }
- }
-
- if (charsearch == false) {
- r_words[n][1] = i - r_words[n][0];
- n++;
- }
-
- return n;
-}
+/** \} */
diff --git a/source/blender/blenlib/intern/string_cursor_utf8.c b/source/blender/blenlib/intern/string_cursor_utf8.c
index eb49572f06c..5e2a0b85814 100644
--- a/source/blender/blenlib/intern/string_cursor_utf8.c
+++ b/source/blender/blenlib/intern/string_cursor_utf8.c
@@ -199,7 +199,7 @@ void BLI_str_cursor_step_utf8(const char *str,
const int pos_prev = *pos;
if (BLI_str_cursor_step_prev_utf8(str, maxlen, pos)) {
if ((jump != STRCUR_JUMP_ALL) &&
- (delim_type != cursor_delim_type_utf8(str, maxlen, (size_t)*pos))) {
+ (delim_type != cursor_delim_type_utf8(str, maxlen, *pos))) {
/* left only: compensate for index/change in direction */
if ((pos_orig - (*pos)) >= 1) {
*pos = pos_prev;
diff --git a/source/blender/blenlib/intern/string_search.cc b/source/blender/blenlib/intern/string_search.cc
index a466c124073..c5528dce2f2 100644
--- a/source/blender/blenlib/intern/string_search.cc
+++ b/source/blender/blenlib/intern/string_search.cc
@@ -24,6 +24,10 @@
#include "BLI_string_utf8.h"
#include "BLI_timeit.hh"
+/* Right arrow, keep in sync with #UI_MENU_ARROW_SEP in `UI_interface.h`. */
+#define UI_MENU_ARROW_SEP "\xe2\x96\xb6"
+#define UI_MENU_ARROW_SEP_UNICODE 0x25b6
+
namespace blender::string_search {
static int64_t count_utf8_code_points(StringRef str)
@@ -31,14 +35,6 @@ static int64_t count_utf8_code_points(StringRef str)
return static_cast<int64_t>(BLI_strnlen_utf8(str.data(), static_cast<size_t>(str.size())));
}
-/**
- * Computes the cost of transforming string a into b. The cost/distance is the minimal number of
- * operations that need to be executed. Valid operations are deletion, insertion, substitution and
- * transposition.
- *
- * This function is utf8 aware in the sense that it works at the level of individual code points
- * (1-4 bytes long) instead of on individual bytes.
- */
int damerau_levenshtein_distance(StringRef a, StringRef b)
{
constexpr int deletion_cost = 1;
@@ -102,10 +98,6 @@ int damerau_levenshtein_distance(StringRef a, StringRef b)
return v1.last();
}
-/**
- * Returns -1 when this is no reasonably good match.
- * Otherwise returns the number of errors in the match.
- */
int get_fuzzy_match_errors(StringRef query, StringRef full)
{
/* If it is a perfect partial match, return immediately. */
@@ -342,16 +334,15 @@ static int score_query_against_words(Span<StringRef> query_words, Span<StringRef
return total_match_score;
}
-/**
- * Splits a string into words and normalizes them (currently that just means converting to lower
- * case). The returned strings are allocated in the given allocator.
- */
void extract_normalized_words(StringRef str,
LinearAllocator<> &allocator,
Vector<StringRef, 64> &r_words)
{
- const uint32_t unicode_space = BLI_str_utf8_as_unicode(" ");
- const uint32_t unicode_right_triangle = BLI_str_utf8_as_unicode("▶");
+ const uint32_t unicode_space = (uint32_t)' ';
+ const uint32_t unicode_right_triangle = UI_MENU_ARROW_SEP_UNICODE;
+
+ BLI_assert(unicode_space == BLI_str_utf8_as_unicode(" "));
+ BLI_assert(unicode_right_triangle == BLI_str_utf8_as_unicode(UI_MENU_ARROW_SEP));
auto is_separator = [&](uint32_t unicode) {
return ELEM(unicode, unicode_space, unicode_right_triangle);
@@ -398,6 +389,7 @@ struct SearchItem {
blender::Span<blender::StringRef> normalized_words;
int length;
void *user_data;
+ int weight;
};
struct StringSearch {
@@ -410,25 +402,21 @@ StringSearch *BLI_string_search_new()
return new StringSearch();
}
-/**
- * Add a new possible result to the search.
- * The caller keeps ownership of all parameters.
- */
-void BLI_string_search_add(StringSearch *search, const char *str, void *user_data)
+void BLI_string_search_add(StringSearch *search,
+ const char *str,
+ void *user_data,
+ const int weight)
{
using namespace blender;
Vector<StringRef, 64> words;
StringRef str_ref{str};
string_search::extract_normalized_words(str_ref, search->allocator, words);
- search->items.append(
- {search->allocator.construct_array_copy(words.as_span()), (int)str_ref.size(), user_data});
+ search->items.append({search->allocator.construct_array_copy(words.as_span()),
+ (int)str_ref.size(),
+ user_data,
+ weight});
}
-/**
- * Filter and sort all previously added search items.
- * Returns an array containing the filtered user data.
- * The caller has to free the returned array.
- */
int BLI_string_search_query(StringSearch *search, const char *query, void ***r_data)
{
using namespace blender;
@@ -467,6 +455,11 @@ int BLI_string_search_query(StringSearch *search, const char *query, void ***r_d
std::sort(indices.begin(), indices.end(), [&](int a, int b) {
return search->items[a].length < search->items[b].length;
});
+ /* Prefer items with larger weights. Use `stable_sort` so that if the weights are the same,
+ * the order won't be changed. */
+ std::stable_sort(indices.begin(), indices.end(), [&](int a, int b) {
+ return search->items[a].weight > search->items[b].weight;
+ });
}
sorted_result_indices.extend(indices);
}
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index b9ea538ff24..807344a912c 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -42,9 +42,11 @@
// #define DEBUG_STRSIZE
-/* array copied from glib's gutf8.c, */
-/* NOTE: last two values (0xfe and 0xff) are forbidden in utf-8,
- * so they are considered 1 byte length too. */
+/**
+ * Array copied from GLIB's `gutf8.c`.
+ * \note last two values (0xfe and 0xff) are forbidden in UTF-8,
+ * so they are considered 1 byte length too.
+ */
static const size_t utf8_skip_data[256] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -56,22 +58,18 @@ static const size_t utf8_skip_data[256] = {
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1,
};
-/* from libswish3, originally called u8_isvalid(),
- * modified to return the index of the bad character (byte index not utf).
- * http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044 - campbell */
-
-/* based on the valid_utf8 routine from the PCRE library by Philip Hazel
- *
- * length is in bytes, since without knowing whether the string is valid
- * it's hard to know how many characters there are! */
-
-/**
- * Find first utf-8 invalid byte in given \a str, of \a length bytes.
- *
- * \return the offset of the first invalid byte.
- */
ptrdiff_t BLI_str_utf8_invalid_byte(const char *str, size_t length)
{
+ /* NOTE(@campbellbarton): from libswish3, originally called u8_isvalid(),
+ * modified to return the index of the bad character (byte index not UTF).
+ * http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044.
+ *
+ * Comment from code in: `libswish3`.
+ * Based on the `valid_utf8` routine from the PCRE library by Philip Hazel
+ *
+ * length is in bytes, since without knowing whether the string is valid
+ * it's hard to know how many characters there are! */
+
const unsigned char *p, *perr, *pend = (const unsigned char *)str + length;
unsigned char c;
int ab;
@@ -195,11 +193,6 @@ utf8_error:
return ((const char *)perr - (const char *)str);
}
-/**
- * Remove any invalid utf-8 byte (taking into account multi-bytes sequence of course).
- *
- * \return number of stripped bytes.
- */
int BLI_str_utf8_invalid_strip(char *str, size_t length)
{
ptrdiff_t bad_char;
@@ -312,7 +305,6 @@ size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst,
return len;
}
-/* wchar len in utf8 */
size_t BLI_wstrlen_utf8(const wchar_t *src)
{
size_t len = 0;
@@ -362,11 +354,6 @@ size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, size_t *r_len_
return len;
}
-/**
- * \param strc: the string to measure the length.
- * \param maxlen: the string length (in bytes)
- * \return the unicode length (not in bytes!)
- */
size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen)
{
size_t len_bytes;
@@ -389,8 +376,6 @@ size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst_w,
/* end wchar_t / utf8 functions */
/* --------------------------------------------------------------------------*/
-/* count columns that character/string occupies, based on wcwidth.c */
-
int BLI_wcwidth(char32_t ucs)
{
return mk_wcwidth(ucs);
@@ -475,10 +460,10 @@ int BLI_str_utf8_char_width_safe(const char *p)
} \
(void)0
-/* uses glib functions but not from glib */
-/* gets the size of a single utf8 char */
int BLI_str_utf8_size(const char *p)
{
+ /* NOTE: uses glib functions but not from GLIB. */
+
int mask = 0, len;
const unsigned char c = (unsigned char)*p;
@@ -489,7 +474,6 @@ int BLI_str_utf8_size(const char *p)
return len;
}
-/* use when we want to skip errors */
int BLI_str_utf8_size_safe(const char *p)
{
int mask = 0, len;
@@ -502,21 +486,10 @@ int BLI_str_utf8_size_safe(const char *p)
return len;
}
-/* was g_utf8_get_char */
-/**
- * BLI_str_utf8_as_unicode:
- * \param p: a pointer to Unicode character encoded as UTF-8
- *
- * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
- * If \a p does not point to a valid UTF-8 encoded character, results are
- * undefined. If you are not sure that the bytes are complete
- * valid Unicode characters, you should use g_utf8_get_char_validated()
- * instead.
- *
- * Return value: the resulting character
- */
uint BLI_str_utf8_as_unicode(const char *p)
{
+ /* Originally `g_utf8_get_char` in GLIB. */
+
int i, len;
uint mask = 0;
uint result;
@@ -531,19 +504,6 @@ uint BLI_str_utf8_as_unicode(const char *p)
return result;
}
-/**
- * UTF8 decoding that steps over the index (unless an error is encountered).
- *
- * \param p: The text to step over.
- * \param p_len: The length of `p`.
- * \param index: Index of `p` to step over.
- * \return the code-point or #BLI_UTF8_ERR if there is a decoding error.
- *
- * \note The behavior for clipped text (where `p_len` limits decoding trailing bytes)
- * must have the same behavior is encountering a nil byte,
- * so functions that only use the first part of a string has matching behavior to functions
- * that null terminate the text.
- */
uint BLI_str_utf8_as_unicode_step_or_error(const char *__restrict p,
const size_t p_len,
size_t *__restrict index)
@@ -569,16 +529,6 @@ uint BLI_str_utf8_as_unicode_step_or_error(const char *__restrict p,
return result;
}
-/**
- * UTF8 decoding that steps over the index (unless an error is encountered).
- *
- * \param p: The text to step over.
- * \param p_len: The length of `p`.
- * \param index: Index of `p` to step over.
- * \return the code-point `(p + *index)` if there is a decoding error.
- *
- * \note Falls back to `LATIN1` for text drawing.
- */
uint BLI_str_utf8_as_unicode_step(const char *__restrict p,
const size_t p_len,
size_t *__restrict index)
@@ -633,18 +583,6 @@ size_t BLI_str_utf8_from_unicode_len(const uint c)
return len;
}
-/**
- * BLI_str_utf8_from_unicode:
- *
- * \param c: a Unicode character code
- * \param outbuf: output buffer, must have at least `outbuf_len` bytes of space.
- * If the length required by `c` exceeds `outbuf_len`,
- * the bytes available bytes will be zeroed and `outbuf_len` returned.
- *
- * Converts a single character to UTF-8.
- *
- * \return number of bytes written.
- */
size_t BLI_str_utf8_from_unicode(uint c, char *outbuf, const size_t outbuf_len)
{
@@ -724,7 +662,6 @@ size_t BLI_str_utf32_as_utf8(char *__restrict dst,
return len;
}
-/* utf32 len in utf8 */
size_t BLI_str_utf32_as_utf8_len(const char32_t *src)
{
size_t len = 0;
@@ -736,24 +673,10 @@ size_t BLI_str_utf32_as_utf8_len(const char32_t *src)
return len;
}
-/* was g_utf8_find_prev_char */
-/**
- * BLI_str_find_prev_char_utf8:
- * \param str: pointer to the beginning of a UTF-8 encoded string
- * \param p: pointer to some position within \a str
- *
- * Given a position \a p with a UTF-8 encoded string \a str, find the start
- * of the previous UTF-8 character starting before. \a p Returns \a str_start if no
- * UTF-8 characters are present in \a str_start before \a p.
- *
- * \a p does not have to be at the beginning of a UTF-8 character. No check
- * is made to see if the character found is actually valid other than
- * it starts with an appropriate byte.
- *
- * \return A pointer to the found character.
- */
const char *BLI_str_find_prev_char_utf8(const char *p, const char *str_start)
{
+ /* Originally `g_utf8_find_prev_char` in GLIB. */
+
BLI_assert(p >= str_start);
if (str_start < p) {
for (--p; p >= str_start; p--) {
@@ -765,22 +688,10 @@ const char *BLI_str_find_prev_char_utf8(const char *p, const char *str_start)
return p;
}
-/* was g_utf8_find_next_char */
-/**
- * BLI_str_find_next_char_utf8:
- * \param p: a pointer to a position within a UTF-8 encoded string
- * \param end: a pointer to the byte following the end of the string.
- *
- * Finds the start of the next UTF-8 character in the string after \a p
- *
- * \a p does not have to be at the beginning of a UTF-8 character. No check
- * is made to see if the character found is actually valid other than
- * it starts with an appropriate byte.
- *
- * \return a pointer to the found character or a pointer to the null terminating character '\0'.
- */
const char *BLI_str_find_next_char_utf8(const char *p, const char *str_end)
{
+ /* Originally `g_utf8_find_next_char` in GLIB. */
+
BLI_assert(p <= str_end);
if ((p < str_end) && (*p != '\0')) {
for (++p; p < str_end && (*p & 0xc0) == 0x80; p++) {
diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c
index bd733aca4f1..21162904dbd 100644
--- a/source/blender/blenlib/intern/string_utils.c
+++ b/source/blender/blenlib/intern/string_utils.c
@@ -38,20 +38,6 @@
# pragma GCC diagnostic error "-Wsign-conversion"
#endif
-/**
- * Looks for a numeric suffix preceded by delim character on the end of
- * name, puts preceding part into *left and value of suffix into *nr.
- * Returns the length of *left.
- *
- * Foo.001 -> "Foo", 1
- * Returning the length of "Foo"
- *
- * \param left: Where to return copy of part preceding delim
- * \param nr: Where to return value of numeric suffix
- * \param name: String to split
- * \param delim: Delimiter character
- * \return Length of \a left
- */
size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
{
const size_t name_len = strlen(name);
@@ -102,10 +88,6 @@ static bool is_char_sep(const char c)
return ELEM(c, '.', ' ', '-', '_');
}
-/**
- * based on `BLI_split_dirfile()` / `os.path.splitext()`,
- * `"a.b.c"` -> (`"a.b"`, `".c"`).
- */
void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len)
{
size_t len = BLI_strnlen(string, str_len);
@@ -124,9 +106,6 @@ void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, cons
memcpy(r_body, string, len + 1);
}
-/**
- * `"a.b.c"` -> (`"a."`, `"b.c"`)
- */
void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len)
{
size_t len = BLI_strnlen(string, str_len);
@@ -146,17 +125,6 @@ void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, cons
BLI_strncpy(r_body, string, len);
}
-/**
- * Finds the best possible flipped (left/right) name.
- * For renaming; check for unique names afterwards.
- *
- * \param r_name: flipped name,
- * assumed to be a pointer to a string of at least \a name_len size.
- * \param from_name: original name,
- * assumed to be a pointer to a string of at least \a name_len size.
- * \param strip_number: If set, remove number extensions.
- * \return The number of bytes written into \a r_name.
- */
size_t BLI_string_flip_side_name(char *r_name,
const char *from_name,
const bool strip_number,
@@ -278,18 +246,6 @@ size_t BLI_string_flip_side_name(char *r_name,
/* Unique name utils. */
-/**
- * Ensures name is unique (according to criteria specified by caller in unique_check callback),
- * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
- *
- * \param unique_check: Return true if name is not unique
- * \param arg: Additional arg to unique_check--meaning is up to caller
- * \param defname: To initialize name if latter is empty
- * \param delim: Delimits numeric suffix in name
- * \param name: Name to be ensured unique
- * \param name_len: Maximum length of name area
- * \return true if there if the name was changed
- */
bool BLI_uniquename_cb(UniquenameCheckCallback unique_check,
void *arg,
const char *defname,
@@ -366,17 +322,6 @@ static bool uniquename_unique_check(void *arg, const char *name)
return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offset);
}
-/**
- * Ensures that the specified block has a unique name within the containing list,
- * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
- *
- * \param list: List containing the block
- * \param vlink: The block to check the name for
- * \param defname: To initialize block name if latter is empty
- * \param delim: Delimits numeric suffix in name
- * \param name_offset: Offset of name within block structure
- * \param name_len: Maximum length of name area
- */
bool BLI_uniquename(
ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_len)
{
@@ -432,9 +377,6 @@ char *BLI_string_join_array(char *result,
return c;
}
-/**
- * A version of #BLI_string_join that takes a separator which can be any character including '\0'.
- */
char *BLI_string_join_array_by_sep_char(
char *result, size_t result_len, char sep, const char *strings[], uint strings_len)
{
@@ -455,9 +397,6 @@ char *BLI_string_join_array_by_sep_char(
return c;
}
-/**
- * Join an array of strings into a newly allocated, null terminated string.
- */
char *BLI_string_join_arrayN(const char *strings[], uint strings_len)
{
uint total_len = 1;
@@ -469,12 +408,11 @@ char *BLI_string_join_arrayN(const char *strings[], uint strings_len)
for (uint i = 0; i < strings_len; i++) {
c += BLI_strcpy_rlen(c, strings[i]);
}
+ /* Only needed when `strings_len == 0`. */
+ *c = '\0';
return result;
}
-/**
- * A version of #BLI_string_joinN that takes a separator which can be any character including '\0'.
- */
char *BLI_string_join_array_by_sep_charN(char sep, const char *strings[], uint strings_len)
{
uint total_len = 0;
@@ -499,10 +437,6 @@ char *BLI_string_join_array_by_sep_charN(char sep, const char *strings[], uint s
return result;
}
-/**
- * A version of #BLI_string_join_array_by_sep_charN that takes a table array.
- * The new location of each string is written into this array.
- */
char *BLI_string_join_array_by_sep_char_with_tableN(char sep,
char *table[],
const char *strings[],
diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c
index 66d0b44cfb3..e64d53467e4 100644
--- a/source/blender/blenlib/intern/system.c
+++ b/source/blender/blenlib/intern/system.c
@@ -73,9 +73,6 @@ int BLI_cpu_support_sse2(void)
/* Windows stack-walk lives in system_win32.c */
#if !defined(_MSC_VER)
-/**
- * Write a backtrace into a file for systems which support it.
- */
void BLI_system_backtrace(FILE *fp)
{
/* ------------- */
diff --git a/source/blender/blenlib/intern/system_win32.c b/source/blender/blenlib/intern/system_win32.c
index f65234b656b..b2360cf743f 100644
--- a/source/blender/blenlib/intern/system_win32.c
+++ b/source/blender/blenlib/intern/system_win32.c
@@ -373,6 +373,9 @@ static void bli_load_symbols()
}
}
+/**
+ * Write a backtrace into a file for systems which support it.
+ */
void BLI_system_backtrace(FILE *fp)
{
SymInitialize(GetCurrentProcess(), NULL, TRUE);
diff --git a/source/blender/blenlib/intern/task_graph.cc b/source/blender/blenlib/intern/task_graph.cc
index ff7d0ecb4c4..d84857caeea 100644
--- a/source/blender/blenlib/intern/task_graph.cc
+++ b/source/blender/blenlib/intern/task_graph.cc
@@ -109,7 +109,7 @@ struct TaskNode {
#endif
};
-TaskGraph *BLI_task_graph_create(void)
+TaskGraph *BLI_task_graph_create()
{
return new TaskGraph();
}
diff --git a/source/blender/blenlib/intern/task_iterator.c b/source/blender/blenlib/intern/task_iterator.c
index 6378d88e2b1..49666eb3082 100644
--- a/source/blender/blenlib/intern/task_iterator.c
+++ b/source/blender/blenlib/intern/task_iterator.c
@@ -274,21 +274,6 @@ static void task_parallel_iterator_do(const TaskParallelSettings *settings,
state->iter_shared.spin_lock = NULL;
}
-/**
- * This function allows to parallelize for loops using a generic iterator.
- *
- * \param userdata: Common userdata passed to all instances of \a func.
- * \param iter_func: Callback function used to generate chunks of items.
- * \param init_item: The initial item, if necessary (may be NULL if unused).
- * \param init_index: The initial index.
- * \param tot_items: The total amount of items to iterate over
- * (if unknown, set it to a negative number).
- * \param func: Callback function.
- * \param settings: See public API doc of TaskParallelSettings for description of all settings.
- *
- * \note Static scheduling is only available when \a tot_items is >= 0.
- */
-
void BLI_task_parallel_iterator(void *userdata,
TaskParallelIteratorIterFunc iter_func,
void *init_item,
@@ -332,17 +317,6 @@ static void task_parallel_listbase_get(void *__restrict UNUSED(userdata),
(*r_next_index)++;
}
-/**
- * This function allows to parallelize for loops over ListBase items.
- *
- * \param listbase: The double linked list to loop over.
- * \param userdata: Common userdata passed to all instances of \a func.
- * \param func: Callback function.
- * \param settings: See public API doc of ParallelRangeSettings for description of all settings.
- *
- * \note There is no static scheduling here,
- * since it would need another full loop over items to count them.
- */
void BLI_task_parallel_listbase(ListBase *listbase,
void *userdata,
TaskParallelIteratorFunc func,
@@ -388,16 +362,6 @@ static void parallel_mempool_func(TaskPool *__restrict pool, void *taskdata)
}
}
-/**
- * This function allows to parallelize for loops over Mempool items.
- *
- * \param mempool: The iterable BLI_mempool to loop over.
- * \param userdata: Common userdata passed to all instances of \a func.
- * \param func: Callback function.
- * \param settings: See public API doc of TaskParallelSettings for description of all settings.
- *
- * \note There is no static scheduling here.
- */
void BLI_task_parallel_mempool(BLI_mempool *mempool,
void *userdata,
TaskParallelMempoolFunc func,
diff --git a/source/blender/blenlib/intern/task_pool.cc b/source/blender/blenlib/intern/task_pool.cc
index cbb5bf34477..1651d4c2205 100644
--- a/source/blender/blenlib/intern/task_pool.cc
+++ b/source/blender/blenlib/intern/task_pool.cc
@@ -121,7 +121,7 @@ class Task {
#ifdef WITH_TBB
class TBBTaskGroup : public tbb::task_group {
public:
- TBBTaskGroup(TaskPriority priority)
+ TBBTaskGroup(eTaskPriority priority)
{
# if TBB_INTERFACE_VERSION_MAJOR >= 12
/* TODO: support priorities in TBB 2021, where they are only available as
@@ -186,7 +186,7 @@ void Task::operator()() const
* Tasks may be suspended until in all are created, to make it possible to
* initialize data structures and create tasks in a single pass. */
-static void tbb_task_pool_create(TaskPool *pool, TaskPriority priority)
+static void tbb_task_pool_create(TaskPool *pool, eTaskPriority priority)
{
if (pool->type == TASK_POOL_TBB_SUSPENDED) {
pool->is_suspended = true;
@@ -363,7 +363,7 @@ static void background_task_pool_free(TaskPool *pool)
/* Task Pool */
-static TaskPool *task_pool_create_ex(void *userdata, TaskPoolType type, TaskPriority priority)
+static TaskPool *task_pool_create_ex(void *userdata, TaskPoolType type, eTaskPriority priority)
{
const bool use_threads = BLI_task_scheduler_num_threads() > 1 && type != TASK_POOL_NO_THREADS;
@@ -401,7 +401,7 @@ static TaskPool *task_pool_create_ex(void *userdata, TaskPoolType type, TaskPrio
/**
* Create a normal task pool. Tasks will be executed as soon as they are added.
*/
-TaskPool *BLI_task_pool_create(void *userdata, TaskPriority priority)
+TaskPool *BLI_task_pool_create(void *userdata, eTaskPriority priority)
{
return task_pool_create_ex(userdata, TASK_POOL_TBB, priority);
}
@@ -418,7 +418,7 @@ TaskPool *BLI_task_pool_create(void *userdata, TaskPriority priority)
* they could end never being executed, since the 'fallback' background thread is already
* busy with parent task in single-threaded context).
*/
-TaskPool *BLI_task_pool_create_background(void *userdata, TaskPriority priority)
+TaskPool *BLI_task_pool_create_background(void *userdata, eTaskPriority priority)
{
return task_pool_create_ex(userdata, TASK_POOL_BACKGROUND, priority);
}
@@ -428,7 +428,7 @@ TaskPool *BLI_task_pool_create_background(void *userdata, TaskPriority priority)
* for until BLI_task_pool_work_and_wait() is called. This helps reducing threading
* overhead when pushing huge amount of small initial tasks from the main thread.
*/
-TaskPool *BLI_task_pool_create_suspended(void *userdata, TaskPriority priority)
+TaskPool *BLI_task_pool_create_suspended(void *userdata, eTaskPriority priority)
{
return task_pool_create_ex(userdata, TASK_POOL_TBB_SUSPENDED, priority);
}
@@ -446,7 +446,7 @@ TaskPool *BLI_task_pool_create_no_threads(void *userdata)
* Task pool that executes one task after the other, possibly on different threads
* but never in parallel.
*/
-TaskPool *BLI_task_pool_create_background_serial(void *userdata, TaskPriority priority)
+TaskPool *BLI_task_pool_create_background_serial(void *userdata, eTaskPriority priority)
{
return task_pool_create_ex(userdata, TASK_POOL_BACKGROUND_SERIAL, priority);
}
diff --git a/source/blender/blenlib/intern/task_scheduler.cc b/source/blender/blenlib/intern/task_scheduler.cc
index 69117e9dc7e..5992e092f4d 100644
--- a/source/blender/blenlib/intern/task_scheduler.cc
+++ b/source/blender/blenlib/intern/task_scheduler.cc
@@ -50,8 +50,8 @@ void BLI_task_scheduler_init()
if (num_threads_override > 0) {
/* Override number of threads. This settings is used within the lifetime
* of tbb::global_control, so we allocate it on the heap. */
- task_scheduler_global_control = OBJECT_GUARDED_NEW(
- tbb::global_control, tbb::global_control::max_allowed_parallelism, num_threads_override);
+ task_scheduler_global_control = MEM_new<tbb::global_control>(
+ __func__, tbb::global_control::max_allowed_parallelism, num_threads_override);
task_scheduler_num_threads = num_threads_override;
}
else {
@@ -69,7 +69,7 @@ void BLI_task_scheduler_init()
void BLI_task_scheduler_exit()
{
#ifdef WITH_TBB_GLOBAL_CONTROL
- OBJECT_GUARDED_DELETE(task_scheduler_global_control, tbb::global_control);
+ MEM_delete(task_scheduler_global_control);
#endif
}
diff --git a/source/blender/blenlib/intern/threads.cc b/source/blender/blenlib/intern/threads.cc
index 35097013439..f131a464650 100644
--- a/source/blender/blenlib/intern/threads.cc
+++ b/source/blender/blenlib/intern/threads.cc
@@ -52,7 +52,6 @@
#endif
#include "atomic_ops.h"
-#include "numaapi.h"
#if defined(__APPLE__) && defined(_OPENMP) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2) && \
!defined(__clang__)
@@ -125,7 +124,6 @@ static pthread_mutex_t _colormanage_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _fftw_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _view3d_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_t mainid;
-static bool is_numa_available = false;
static unsigned int thread_levels = 0; /* threads can be invoked inside threads */
static int num_threads_override = 0;
@@ -140,22 +138,15 @@ struct ThreadSlot {
int avail;
};
-void BLI_threadapi_init(void)
+void BLI_threadapi_init()
{
mainid = pthread_self();
- if (numaAPI_Initialize() == NUMAAPI_SUCCESS) {
- is_numa_available = true;
- }
}
-void BLI_threadapi_exit(void)
+void BLI_threadapi_exit()
{
}
-/* tot = 0 only initializes malloc mutex in a safe way (see sequence.c)
- * problem otherwise: scene render will kill of the mutex!
- */
-
void BLI_threadpool_init(ListBase *threadbase, void *(*do_thread)(void *), int tot)
{
int a;
@@ -189,7 +180,6 @@ void BLI_threadpool_init(ListBase *threadbase, void *(*do_thread)(void *), int t
}
}
-/* amount of available threads */
int BLI_available_threads(ListBase *threadbase)
{
int counter = 0;
@@ -203,7 +193,6 @@ int BLI_available_threads(ListBase *threadbase)
return counter;
}
-/* returns thread number, for sample patterns or threadsafe tables */
int BLI_threadpool_available_thread_index(ListBase *threadbase)
{
int counter = 0;
@@ -231,7 +220,7 @@ static void *tslot_thread_start(void *tslot_p)
return tslot->do_thread(tslot->callerdata);
}
-int BLI_thread_is_main(void)
+int BLI_thread_is_main()
{
return pthread_equal(pthread_self(), mainid);
}
@@ -305,8 +294,7 @@ void BLI_threadpool_end(ListBase *threadbase)
/* System Information */
-/* how many threads are native on this system? */
-int BLI_system_thread_count(void)
+int BLI_system_thread_count()
{
static int t = -1;
@@ -347,7 +335,7 @@ void BLI_system_num_threads_override_set(int num)
num_threads_override = num;
}
-int BLI_system_num_threads_override_get(void)
+int BLI_system_num_threads_override_get()
{
return num_threads_override;
}
@@ -418,7 +406,7 @@ void BLI_mutex_end(ThreadMutex *mutex)
pthread_mutex_destroy(mutex);
}
-ThreadMutex *BLI_mutex_alloc(void)
+ThreadMutex *BLI_mutex_alloc()
{
ThreadMutex *mutex = static_cast<ThreadMutex *>(MEM_callocN(sizeof(ThreadMutex), "ThreadMutex"));
BLI_mutex_init(mutex);
@@ -533,7 +521,7 @@ void BLI_rw_mutex_end(ThreadRWMutex *mutex)
pthread_rwlock_destroy(mutex);
}
-ThreadRWMutex *BLI_rw_mutex_alloc(void)
+ThreadRWMutex *BLI_rw_mutex_alloc()
{
ThreadRWMutex *mutex = static_cast<ThreadRWMutex *>(
MEM_callocN(sizeof(ThreadRWMutex), "ThreadRWMutex"));
@@ -555,7 +543,7 @@ struct TicketMutex {
unsigned int queue_head, queue_tail;
};
-TicketMutex *BLI_ticket_mutex_alloc(void)
+TicketMutex *BLI_ticket_mutex_alloc()
{
TicketMutex *ticket = static_cast<TicketMutex *>(
MEM_callocN(sizeof(TicketMutex), "TicketMutex"));
@@ -640,7 +628,7 @@ struct ThreadQueue {
volatile int canceled;
};
-ThreadQueue *BLI_thread_queue_init(void)
+ThreadQueue *BLI_thread_queue_init()
{
ThreadQueue *queue;
@@ -814,113 +802,3 @@ void BLI_thread_queue_wait_finish(ThreadQueue *queue)
pthread_mutex_unlock(&queue->mutex);
}
-
-/* **** Special functions to help performance on crazy NUMA setups. **** */
-
-#if 0 /* UNUSED */
-static bool check_is_threadripper2_alike_topology(void)
-{
- /* NOTE: We hope operating system does not support CPU hot-swap to
- * a different brand. And that SMP of different types is also not
- * encouraged by the system. */
- static bool is_initialized = false;
- static bool is_threadripper2 = false;
- if (is_initialized) {
- return is_threadripper2;
- }
- is_initialized = true;
- char *cpu_brand = BLI_cpu_brand_string();
- if (cpu_brand == nullptr) {
- return false;
- }
- if (strstr(cpu_brand, "Threadripper")) {
- /* NOTE: We consider all Thread-rippers having similar topology to
- * the second one. This is because we are trying to utilize NUMA node
- * 0 as much as possible. This node does exist on earlier versions of
- * thread-ripper and setting affinity to it should not have negative
- * effect.
- * This allows us to avoid per-model check, making the code more
- * reliable for the CPUs which are not yet released.
- */
- if (strstr(cpu_brand, "2990WX") || strstr(cpu_brand, "2950X")) {
- is_threadripper2 = true;
- }
- }
- /* NOTE: While all dies of EPYC has memory controller, only two f them
- * has access to a lower-indexed DDR slots. Those dies are same as on
- * Threadripper2 with the memory controller.
- * Now, it is rather likely that reasonable amount of users don't max
- * up their DR slots, making it only two dies connected to a DDR slot
- * with actual memory in it. */
- if (strstr(cpu_brand, "EPYC")) {
- /* NOTE: Similarly to Thread-ripper we do not do model check. */
- is_threadripper2 = true;
- }
- MEM_freeN(cpu_brand);
- return is_threadripper2;
-}
-
-static void threadripper_put_process_on_fast_node(void)
-{
- if (!is_numa_available) {
- return;
- }
- /* NOTE: Technically, we can use NUMA nodes 0 and 2 and using both of
- * them in the affinity mask will allow OS to schedule threads more
- * flexible,possibly increasing overall performance when multiple apps
- * are crunching numbers.
- *
- * However, if scene fits into memory adjacent to a single die we don't
- * want OS to re-schedule the process to another die since that will make
- * it further away from memory allocated for .blend file. */
- /* NOTE: Even if NUMA is available in the API but is disabled in BIOS on
- * this workstation we still process here. If NUMA is disabled it will be a
- * single node, so our action is no-visible-changes, but allows to keep
- * things simple and unified. */
- numaAPI_RunProcessOnNode(0);
-}
-
-static void threadripper_put_thread_on_fast_node(void)
-{
- if (!is_numa_available) {
- return;
- }
- /* NOTE: This is where things becomes more interesting. On the one hand
- * we can use nodes 0 and 2 and allow operating system to do balancing
- * of processes/threads for the maximum performance when multiple apps
- * are running.
- * On another hand, however, we probably want to use same node as the
- * main thread since that's where the memory of .blend file is likely
- * to be allocated.
- * Since the main thread is currently on node 0, we also put thread on
- * same node. */
- /* See additional note about NUMA disabled in BIOS above. */
- numaAPI_RunThreadOnNode(0);
-}
-#endif /* UNUSED */
-
-void BLI_thread_put_process_on_fast_node(void)
-{
- /* Disabled for now since this causes only 16 threads to be used on a
- * thread-ripper for computations like sculpting and fluid sim. The problem
- * is that all threads created as children from this thread will inherit
- * the NUMA node and so will end up on the same node. This can be fixed
- * case-by-case by assigning the NUMA node for every child thread, however
- * this is difficult for external libraries and OpenMP, and out of our
- * control for plugins like external renderers. */
-#if 0
- if (check_is_threadripper2_alike_topology()) {
- threadripper_put_process_on_fast_node();
- }
-#endif
-}
-
-void BLI_thread_put_thread_on_fast_node(void)
-{
- /* Disabled for now, see comment above. */
-#if 0
- if (check_is_threadripper2_alike_topology()) {
- threadripper_put_thread_on_fast_node();
- }
-#endif
-}
diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c
index 69c383061fc..14adab8648b 100644
--- a/source/blender/blenlib/intern/timecode.c
+++ b/source/blender/blenlib/intern/timecode.c
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup blendlib
+ * \ingroup bli
*
* Time-Code string formatting
*/
@@ -35,19 +35,6 @@
#include "BLI_strict_flags.h"
-/**
- * Generate time-code/frame number string and store in \a str
- *
- * \param str: destination string
- * \param maxncpy: maximum number of characters to copy `sizeof(str)`
- * \param brevity_level: special setting for #View2D grid drawing,
- * used to specify how detailed we need to be
- * \param time_seconds: time total time in seconds
- * \param fps: frames per second, typically from the #FPS macro
- * \param timecode_style: enum from #eTimecodeStyles
- * \return length of \a str
- */
-
size_t BLI_timecode_string_from_time(char *str,
const size_t maxncpy,
const int brevity_level,
@@ -62,7 +49,7 @@ size_t BLI_timecode_string_from_time(char *str,
/* get cframes */
if (time < 0) {
- /* correction for negative cfraues */
+ /* Correction for negative cframes. */
neg[0] = '-';
time = -time;
}
@@ -195,14 +182,6 @@ size_t BLI_timecode_string_from_time(char *str,
return rlen;
}
-/**
- * Generate time string and store in \a str
- *
- * \param str: destination string
- * \param maxncpy: maximum number of characters to copy `sizeof(str)`
- * \param time_seconds: time total time in seconds
- * \return length of \a str
- */
size_t BLI_timecode_string_from_time_simple(char *str,
const size_t maxncpy,
const double time_seconds)
@@ -225,18 +204,6 @@ size_t BLI_timecode_string_from_time_simple(char *str,
return rlen;
}
-/**
- * Generate time string and store in \a str
- *
- * \param str: destination string
- * \param maxncpy: maximum number of characters to copy `sizeof(str)`
- * \param brevity_level: special setting for #View2D grid drawing,
- * used to specify how detailed we need to be
- * \param time_seconds: time total time in seconds
- * \return length of \a str
- *
- * \note in some cases this is used to print non-seconds values.
- */
size_t BLI_timecode_string_from_time_seconds(char *str,
const size_t maxncpy,
const int brevity_level,
diff --git a/source/blender/blenlib/intern/uuid.cc b/source/blender/blenlib/intern/uuid.cc
index 3c86238036c..e2578ffa7c7 100644
--- a/source/blender/blenlib/intern/uuid.cc
+++ b/source/blender/blenlib/intern/uuid.cc
@@ -81,9 +81,9 @@ bUUID BLI_uuid_generate_random()
return uuid;
}
-bUUID BLI_uuid_nil(void)
+bUUID BLI_uuid_nil()
{
- const bUUID nil = {0, 0, 0, 0, 0, 0};
+ const bUUID nil = {0, 0, 0, 0, 0, {0}};
return nil;
}
diff --git a/source/blender/blenlib/intern/uvproject.c b/source/blender/blenlib/intern/uvproject.c
index 093d08e643d..dbab0162eba 100644
--- a/source/blender/blenlib/intern/uvproject.c
+++ b/source/blender/blenlib/intern/uvproject.c
@@ -90,7 +90,6 @@ void BLI_uvproject_from_camera(float target[2], float source[3], ProjCameraInfo
target[1] += uci->shifty;
}
-/* could rv3d->persmat */
void BLI_uvproject_from_view(float target[2],
float source[3],
float persmat[4][4],
@@ -132,8 +131,6 @@ void BLI_uvproject_from_view(float target[2],
target[1] = (y + target[1]) / winy;
}
-/* 'rotmat' can be `obedit->obmat` when uv project is used.
- * 'winx' and 'winy' can be from `scene->r.xsch/ysch` */
ProjCameraInfo *BLI_uvproject_camera_info(Object *ob, float rotmat[4][4], float winx, float winy)
{
ProjCameraInfo uci;
diff --git a/source/blender/blenlib/intern/voxel.c b/source/blender/blenlib/intern/voxel.c
index c0c895654e3..a2b29ce1185 100644
--- a/source/blender/blenlib/intern/voxel.c
+++ b/source/blender/blenlib/intern/voxel.c
@@ -35,7 +35,7 @@ BLI_INLINE float D(const float *data, const int res[3], int x, int y, int z)
}
/* *** nearest neighbor *** */
-/* input coordinates must be in bounding box 0.0 - 1.0 */
+
float BLI_voxel_sample_nearest(const float *data, const int res[3], const float co[3])
{
int xi, yi, zi;
diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c
index d5c9c5cd5e6..11345fc7242 100644
--- a/source/blender/blenlib/intern/winstuff.c
+++ b/source/blender/blenlib/intern/winstuff.c
@@ -172,12 +172,14 @@ bool BLI_windows_register_blend_extension(const bool background)
return false;
}
+# ifdef WITH_BLENDER_THUMBNAILER
BLI_windows_get_executable_dir(InstallDir);
GetSystemDirectory(SysDir, FILE_MAXDIR);
ThumbHandlerDLL = "BlendThumb.dll";
snprintf(
RegCmd, MAX_PATH * 2, "%s\\regsvr32 /s \"%s\\%s\"", SysDir, InstallDir, ThumbHandlerDLL);
system(RegCmd);
+# endif
RegCloseKey(root);
printf("success (%s)\n", usr_mode ? "user" : "system");
@@ -191,7 +193,7 @@ bool BLI_windows_register_blend_extension(const bool background)
return true;
}
-void BLI_windows_get_default_root_dir(char *root)
+void BLI_windows_get_default_root_dir(char root[4])
{
char str[MAX_PATH + 1];
diff --git a/source/blender/blenlib/tests/BLI_any_test.cc b/source/blender/blenlib/tests/BLI_any_test.cc
new file mode 100644
index 00000000000..dc72affd610
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_any_test.cc
@@ -0,0 +1,110 @@
+/* Apache License, Version 2.0 */
+
+#include "BLI_any.hh"
+#include "BLI_map.hh"
+
+#include "testing/testing.h"
+
+namespace blender::tests {
+
+TEST(any, DefaultConstructor)
+{
+ Any<> a;
+ EXPECT_FALSE(a.has_value());
+}
+
+TEST(any, AssignInt)
+{
+ Any<> a = 5;
+ EXPECT_TRUE(a.has_value());
+ EXPECT_TRUE(a.is<int>());
+ EXPECT_FALSE(a.is<float>());
+ const int &value = a.get<int>();
+ EXPECT_EQ(value, 5);
+ a = 10;
+ EXPECT_EQ(value, 10);
+
+ Any<> b = a;
+ EXPECT_TRUE(b.has_value());
+ EXPECT_EQ(b.get<int>(), 10);
+
+ Any<> c = std::move(a);
+ EXPECT_TRUE(c);
+ EXPECT_EQ(c.get<int>(), 10);
+
+ EXPECT_EQ(a.get<int>(), 10); /* NOLINT: bugprone-use-after-move */
+
+ a.reset();
+ EXPECT_FALSE(a);
+}
+
+TEST(any, AssignMap)
+{
+ Any<> a = Map<int, int>();
+ EXPECT_TRUE(a.has_value());
+ EXPECT_TRUE((a.is<Map<int, int>>()));
+ EXPECT_FALSE((a.is<Map<int, float>>()));
+ Map<int, int> &map = a.get<Map<int, int>>();
+ map.add(4, 2);
+ EXPECT_EQ((a.get<Map<int, int>>().lookup(4)), 2);
+
+ Any<> b = a;
+ EXPECT_TRUE(b);
+ EXPECT_EQ((b.get<Map<int, int>>().lookup(4)), 2);
+
+ Any<> c = std::move(a);
+ /* Test valid state after self assignment. Clang emits `-Wself-assign-overloaded` with `c=c;`.
+ * And `pragma` suppression creates warnings on other compilers. */
+ c = static_cast<decltype(a) &>(c);
+ EXPECT_TRUE(c);
+ EXPECT_EQ((c.get<Map<int, int>>().lookup(4)), 2);
+
+ EXPECT_TRUE((a.get<Map<int, int>>().is_empty())); /* NOLINT: bugprone-use-after-move */
+}
+
+TEST(any, AssignAny)
+{
+ Any<> a = 5;
+ Any<> b = std::string("hello");
+ Any<> c;
+
+ Any<> z;
+ EXPECT_FALSE(z.has_value());
+
+ z = a;
+ EXPECT_TRUE(z.has_value());
+ EXPECT_EQ(z.get<int>(), 5);
+
+ z = b;
+ EXPECT_EQ(z.get<std::string>(), "hello");
+
+ z = c;
+ EXPECT_FALSE(z.has_value());
+
+ z = Any(std::in_place_type<Any<>>, a);
+ EXPECT_FALSE(z.is<int>());
+ EXPECT_TRUE(z.is<Any<>>());
+ EXPECT_EQ(z.get<Any<>>().get<int>(), 5);
+}
+
+struct ExtraSizeInfo {
+ size_t size;
+
+ template<typename T> static ExtraSizeInfo get()
+ {
+ return {sizeof(T)};
+ }
+};
+
+TEST(any, ExtraInfo)
+{
+ using MyAny = Any<ExtraSizeInfo>;
+
+ MyAny a = 5;
+ EXPECT_EQ(a.extra_info().size, sizeof(int));
+
+ a = std::string("hello");
+ EXPECT_EQ(a.extra_info().size, sizeof(std::string));
+}
+
+} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_color_test.cc b/source/blender/blenlib/tests/BLI_color_test.cc
index a91c743b133..5194d8048bf 100644
--- a/source/blender/blenlib/tests/BLI_color_test.cc
+++ b/source/blender/blenlib/tests/BLI_color_test.cc
@@ -6,8 +6,8 @@
namespace blender::tests {
-/**
- * \name Conversions
+/* -------------------------------------------------------------------- */
+/** \name Conversions
* \{ */
TEST(color, ThemeByteToFloat)
diff --git a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc
index 70e3a99e57a..eac3faa6d15 100644
--- a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc
+++ b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc
@@ -21,10 +21,9 @@ extern "C" {
#define DO_RANDOM_TESTS 0
#include "BLI_array.hh"
-#include "BLI_double2.hh"
#include "BLI_math_boolean.hh"
#include "BLI_math_mpq.hh"
-#include "BLI_mpq2.hh"
+#include "BLI_math_vec_mpq_types.hh"
#include "BLI_vector.hh"
#include "BLI_delaunay_2d.h"
diff --git a/source/blender/blenlib/tests/BLI_fileops_test.cc b/source/blender/blenlib/tests/BLI_fileops_test.cc
new file mode 100644
index 00000000000..e2a792647dc
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_fileops_test.cc
@@ -0,0 +1,40 @@
+/* Apache License, Version 2.0 */
+
+#include "BLI_fileops.hh"
+
+#include "testing/testing.h"
+
+namespace blender::tests {
+
+TEST(fileops, fstream_open_string_filename)
+{
+ const std::string test_files_dir = blender::tests::flags_test_asset_dir();
+ if (test_files_dir.empty()) {
+ FAIL();
+ }
+
+ const std::string filepath = test_files_dir + "/asset_library/новый/blender_assets.cats.txt";
+ fstream in(filepath, std::ios_base::in);
+ ASSERT_TRUE(in.is_open()) << "could not open " << filepath;
+ in.close(); /* This should not crash. */
+
+ /* Reading the file not tested here. That's deferred to `std::fstream` anyway. */
+}
+
+TEST(fileops, fstream_open_charptr_filename)
+{
+ const std::string test_files_dir = blender::tests::flags_test_asset_dir();
+ if (test_files_dir.empty()) {
+ FAIL();
+ }
+
+ const std::string filepath_str = test_files_dir + "/asset_library/новый/blender_assets.cats.txt";
+ const char *filepath = filepath_str.c_str();
+ fstream in(filepath, std::ios_base::in);
+ ASSERT_TRUE(in.is_open()) << "could not open " << filepath;
+ in.close(); /* This should not crash. */
+
+ /* Reading the file not tested here. That's deferred to `std::fstream` anyway. */
+}
+
+} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_listbase_test.cc b/source/blender/blenlib/tests/BLI_listbase_test.cc
index 0ba08a0cd48..9e4d7c7dd36 100644
--- a/source/blender/blenlib/tests/BLI_listbase_test.cc
+++ b/source/blender/blenlib/tests/BLI_listbase_test.cc
@@ -96,6 +96,89 @@ TEST(listbase, FindLinkOrIndex)
BLI_freelistN(&lb);
}
+TEST(listbase, FindLinkFromStringOrPointer)
+{
+ struct TestLink {
+ struct TestLink *prev, *next;
+ char name[64];
+ const void *ptr;
+ };
+
+ const char *const link1_name = "Link1";
+ const char *const link2_name = "Link2";
+ const void *const link1_ptr = nullptr;
+ const void *const link2_ptr = link2_name;
+
+ const size_t name_offset = offsetof(struct TestLink, name);
+ const size_t ptr_offset = offsetof(struct TestLink, ptr);
+
+ ListBase lb;
+ struct TestLink *link1 = (struct TestLink *)MEM_callocN(sizeof(TestLink), "link1");
+ BLI_strncpy(link1->name, link1_name, sizeof(link1->name));
+ link1->ptr = link1_ptr;
+ struct TestLink *link2 = (struct TestLink *)MEM_callocN(sizeof(TestLink), "link2");
+ BLI_strncpy(link2->name, link2_name, sizeof(link2->name));
+ link2->ptr = link2_ptr;
+
+ /* Empty list */
+ BLI_listbase_clear(&lb);
+ EXPECT_EQ(BLI_findptr(&lb, link1_ptr, ptr_offset), (void *)nullptr);
+ EXPECT_EQ(BLI_findstring(&lb, link1_name, name_offset), (void *)nullptr);
+ EXPECT_EQ(BLI_rfindptr(&lb, link1_ptr, ptr_offset), (void *)nullptr);
+ EXPECT_EQ(BLI_rfindstring(&lb, link1_name, name_offset), (void *)nullptr);
+ EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link1_name, name_offset, 0), (void *)nullptr);
+
+ /* One link */
+ BLI_addtail(&lb, link1);
+ EXPECT_EQ(BLI_findptr(&lb, link1_ptr, ptr_offset), (void *)link1);
+ EXPECT_EQ(BLI_findstring(&lb, link1_name, name_offset), (void *)link1);
+ EXPECT_EQ(BLI_rfindptr(&lb, link1_ptr, ptr_offset), (void *)link1);
+ EXPECT_EQ(BLI_rfindstring(&lb, link1_name, name_offset), (void *)link1);
+ EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link1_name, name_offset, 0), (void *)link1);
+ EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, "", name_offset, 0), (void *)link1);
+ EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 0), (void *)link1);
+ EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 1), (void *)nullptr);
+
+ /* Two links */
+ BLI_addtail(&lb, link2);
+ EXPECT_EQ(BLI_findptr(&lb, link1_ptr, ptr_offset), (void *)link1);
+ EXPECT_EQ(BLI_findstring(&lb, link1_name, name_offset), (void *)link1);
+ EXPECT_EQ(BLI_rfindptr(&lb, link1_ptr, ptr_offset), (void *)link1);
+ EXPECT_EQ(BLI_rfindstring(&lb, link1_name, name_offset), (void *)link1);
+ EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link1_name, name_offset, 0), (void *)link1);
+ EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link2_name, name_offset, 0), (void *)link2);
+ EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 0), (void *)link1);
+ EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 1), (void *)link2);
+ EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, -1), (void *)nullptr);
+
+ BLI_freelistN(&lb);
+}
+
+TEST(listbase, FromLink)
+{
+ ListBase lb = {nullptr, nullptr};
+ Link *link1 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link1"));
+ Link *link2 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link2"));
+ Link *link3 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link3"));
+
+ /* NULL safety. */
+ EXPECT_EQ(lb, BLI_listbase_from_link(nullptr));
+
+ /* One link. */
+ BLI_addtail(&lb, link1);
+ EXPECT_EQ(lb, BLI_listbase_from_link(link1));
+
+ /* Two links. */
+ BLI_addtail(&lb, link2);
+ EXPECT_EQ(lb, BLI_listbase_from_link(link2));
+
+ /* Three links, search from middle. */
+ BLI_addtail(&lb, link3);
+ EXPECT_EQ(lb, BLI_listbase_from_link(link2));
+
+ BLI_freelistN(&lb);
+}
+
/* -------------------------------------------------------------------- */
/* Sort utilities & test */
diff --git a/source/blender/blenlib/tests/BLI_math_vec_types_test.cc b/source/blender/blenlib/tests/BLI_math_vec_types_test.cc
new file mode 100644
index 00000000000..c9be404139e
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_math_vec_types_test.cc
@@ -0,0 +1,149 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "BLI_math_vec_types.hh"
+
+namespace blender::tests {
+
+using namespace blender::math;
+
+TEST(math_vec_types, ScalarConstructorUnsigned)
+{
+ float2 u(5u);
+ EXPECT_EQ(u[0], 5.0f);
+ EXPECT_EQ(u[1], 5.0f);
+}
+
+TEST(math_vec_types, ScalarConstructorInt)
+{
+ float2 i(-5);
+ EXPECT_EQ(i[0], -5.0f);
+ EXPECT_EQ(i[1], -5.0f);
+}
+
+TEST(math_vec_types, ScalarConstructorFloat)
+{
+ float2 f(5.2f);
+ EXPECT_FLOAT_EQ(f[0], 5.2f);
+ EXPECT_FLOAT_EQ(f[1], 5.2f);
+}
+
+TEST(math_vec_types, ScalarConstructorDouble)
+{
+ float2 d(5.2);
+ EXPECT_FLOAT_EQ(d[0], 5.2f);
+ EXPECT_FLOAT_EQ(d[1], 5.2f);
+}
+
+TEST(math_vec_types, MultiScalarConstructorVec2)
+{
+ int2 i(5, -1);
+ EXPECT_EQ(i[0], 5);
+ EXPECT_EQ(i[1], -1);
+}
+
+TEST(math_vec_types, MultiScalarConstructorVec3)
+{
+ int3 i(5, -1, 6u);
+ EXPECT_EQ(i[0], 5);
+ EXPECT_EQ(i[1], -1);
+ EXPECT_EQ(i[2], 6);
+}
+
+TEST(math_vec_types, MultiScalarConstructorVec4)
+{
+ int4 i(5, -1, 6u, 0);
+ EXPECT_EQ(i[0], 5);
+ EXPECT_EQ(i[1], -1);
+ EXPECT_EQ(i[2], 6);
+ EXPECT_EQ(i[3], 0);
+}
+
+TEST(math_vec_types, MixedScalarVectorConstructorVec3)
+{
+ float3 fl_v2(float2(5.5f), 1.8f);
+ EXPECT_FLOAT_EQ(fl_v2[0], 5.5f);
+ EXPECT_FLOAT_EQ(fl_v2[1], 5.5f);
+ EXPECT_FLOAT_EQ(fl_v2[2], 1.8f);
+
+ float3 v2_fl(1.8f, float2(5.5f));
+ EXPECT_FLOAT_EQ(v2_fl[0], 1.8f);
+ EXPECT_FLOAT_EQ(v2_fl[1], 5.5f);
+ EXPECT_FLOAT_EQ(v2_fl[2], 5.5f);
+}
+
+TEST(math_vec_types, MixedScalarVectorConstructorVec4)
+{
+ int4 v2_fl_fl(float2(1), 2, 3);
+ EXPECT_EQ(v2_fl_fl[0], 1);
+ EXPECT_EQ(v2_fl_fl[1], 1);
+ EXPECT_EQ(v2_fl_fl[2], 2);
+ EXPECT_EQ(v2_fl_fl[3], 3);
+
+ float4 fl_v2_fl(1, int2(2), 3);
+ EXPECT_EQ(fl_v2_fl[0], 1);
+ EXPECT_EQ(fl_v2_fl[1], 2);
+ EXPECT_EQ(fl_v2_fl[2], 2);
+ EXPECT_EQ(fl_v2_fl[3], 3);
+
+ double4 fl_fl_v2(1, 2, double2(3));
+ EXPECT_EQ(fl_fl_v2[0], 1);
+ EXPECT_EQ(fl_fl_v2[1], 2);
+ EXPECT_EQ(fl_fl_v2[2], 3);
+ EXPECT_EQ(fl_fl_v2[3], 3);
+
+ int4 v2_v2(float2(1), uint2(2));
+ EXPECT_EQ(v2_v2[0], 1);
+ EXPECT_EQ(v2_v2[1], 1);
+ EXPECT_EQ(v2_v2[2], 2);
+ EXPECT_EQ(v2_v2[3], 2);
+
+ float4 v3_fl(uint3(1), 2);
+ EXPECT_EQ(v3_fl[0], 1);
+ EXPECT_EQ(v3_fl[1], 1);
+ EXPECT_EQ(v3_fl[2], 1);
+ EXPECT_EQ(v3_fl[3], 2);
+
+ uint4 fl_v3(1, float3(2));
+ EXPECT_EQ(fl_v3[0], 1);
+ EXPECT_EQ(fl_v3[1], 2);
+ EXPECT_EQ(fl_v3[2], 2);
+ EXPECT_EQ(fl_v3[3], 2);
+}
+
+TEST(math_vec_types, ComponentMasking)
+{
+ int4 i(0, 1, 2, 3);
+ float2 f2 = float2(i);
+ EXPECT_EQ(f2[0], 0.0f);
+ EXPECT_EQ(f2[1], 1.0f);
+}
+
+TEST(math_vec_types, PointerConversion)
+{
+ float array[3] = {1.0f, 2.0f, 3.0f};
+ float3 farray(array);
+ EXPECT_EQ(farray[0], 1.0f);
+ EXPECT_EQ(farray[1], 2.0f);
+ EXPECT_EQ(farray[2], 3.0f);
+}
+
+TEST(math_vec_types, PointerArrayConversion)
+{
+ float array[1][3] = {{1.0f, 2.0f, 3.0f}};
+ float(*ptr)[3] = array;
+ float3 fptr(ptr);
+ EXPECT_EQ(fptr[0], 1.0f);
+ EXPECT_EQ(fptr[1], 2.0f);
+ EXPECT_EQ(fptr[2], 3.0f);
+}
+
+TEST(math_vec_types, VectorTypeConversion)
+{
+ double2 d(int2(float2(5.75f, -1.57f)));
+ EXPECT_EQ(d[0], 5.0);
+ EXPECT_EQ(d[1], -1.0);
+}
+
+} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_memory_utils_test.cc b/source/blender/blenlib/tests/BLI_memory_utils_test.cc
index 23415e69b04..74e54151a06 100644
--- a/source/blender/blenlib/tests/BLI_memory_utils_test.cc
+++ b/source/blender/blenlib/tests/BLI_memory_utils_test.cc
@@ -1,6 +1,6 @@
/* Apache License, Version 2.0 */
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_memory_utils.hh"
#include "BLI_strict_flags.h"
#include "testing/testing.h"
@@ -169,4 +169,11 @@ static_assert(is_span_convertible_pointer_v<int *, const void *>);
static_assert(!is_span_convertible_pointer_v<TestBaseClass *, TestChildClass *>);
static_assert(!is_span_convertible_pointer_v<TestChildClass *, TestBaseClass *>);
+static_assert(is_same_any_v<int, float, bool, int>);
+static_assert(is_same_any_v<int, int, float>);
+static_assert(is_same_any_v<int, int>);
+static_assert(!is_same_any_v<int, float, bool>);
+static_assert(!is_same_any_v<int, float>);
+static_assert(!is_same_any_v<int>);
+
} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
index d759f0c3be4..2b8fb3dbea4 100644
--- a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
+++ b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
@@ -11,8 +11,8 @@
#include "BLI_array.hh"
#include "BLI_map.hh"
#include "BLI_math_mpq.hh"
+#include "BLI_math_vec_mpq_types.hh"
#include "BLI_mesh_boolean.hh"
-#include "BLI_mpq3.hh"
#include "BLI_vector.hh"
#ifdef WITH_GMP
diff --git a/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc b/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc
index 68111fb8eb1..d2d76593129 100644
--- a/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc
+++ b/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc
@@ -10,8 +10,8 @@
#include "BLI_array.hh"
#include "BLI_math_mpq.hh"
+#include "BLI_math_vec_mpq_types.hh"
#include "BLI_mesh_intersect.hh"
-#include "BLI_mpq3.hh"
#include "BLI_task.h"
#include "BLI_vector.hh"
diff --git a/source/blender/blenlib/tests/BLI_serialize_test.cc b/source/blender/blenlib/tests/BLI_serialize_test.cc
new file mode 100644
index 00000000000..120fcdc3e81
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_serialize_test.cc
@@ -0,0 +1,207 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "BLI_serialize.hh"
+
+/* -------------------------------------------------------------------- */
+/* tests */
+
+namespace blender::io::serialize::json::testing {
+
+TEST(serialize, string_to_json)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ StringValue test_value("Hello JSON");
+ json.serialize(out, test_value);
+ EXPECT_EQ(out.str(), "\"Hello JSON\"");
+}
+
+static void test_int_to_json(int64_t value, StringRef expected)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ IntValue test_value(value);
+ json.serialize(out, test_value);
+ EXPECT_EQ(out.str(), expected);
+}
+
+TEST(serialize, int_to_json)
+{
+ test_int_to_json(42, "42");
+ test_int_to_json(-42, "-42");
+ test_int_to_json(std::numeric_limits<int32_t>::max(), "2147483647");
+ test_int_to_json(std::numeric_limits<int32_t>::min(), "-2147483648");
+ test_int_to_json(std::numeric_limits<int64_t>::max(), "9223372036854775807");
+ test_int_to_json(std::numeric_limits<int64_t>::min(), "-9223372036854775808");
+}
+
+TEST(serialize, double_to_json)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ DoubleValue test_value(42.31);
+ json.serialize(out, test_value);
+ EXPECT_EQ(out.str(), "42.31");
+}
+
+TEST(serialize, null_to_json)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ NullValue test_value;
+ json.serialize(out, test_value);
+ EXPECT_EQ(out.str(), "null");
+}
+
+TEST(serialize, false_to_json)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ BooleanValue value(false);
+ json.serialize(out, value);
+ EXPECT_EQ(out.str(), "false");
+}
+
+TEST(serialize, true_to_json)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ BooleanValue value(true);
+ json.serialize(out, value);
+ EXPECT_EQ(out.str(), "true");
+}
+
+TEST(serialize, array_to_json)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ ArrayValue value_array;
+ ArrayValue::Items &array = value_array.elements();
+ array.append_as(new IntValue(42));
+ array.append_as(new StringValue("Hello JSON"));
+ array.append_as(new NullValue);
+ array.append_as(new BooleanValue(false));
+ array.append_as(new BooleanValue(true));
+
+ json.serialize(out, value_array);
+ EXPECT_EQ(out.str(), "[42,\"Hello JSON\",null,false,true]");
+}
+
+TEST(serialize, object_to_json)
+{
+ JsonFormatter json;
+ std::stringstream out;
+ DictionaryValue value_object;
+ DictionaryValue::Items &attributes = value_object.elements();
+ attributes.append_as(std::pair(std::string("best_number"), new IntValue(42)));
+
+ json.serialize(out, value_object);
+ EXPECT_EQ(out.str(), "{\"best_number\":42}");
+}
+
+TEST(serialize, json_roundtrip_ordering)
+{
+ const std::string input =
+ "[{\"_id\":\"614ada7c476c472ecbd0ecbb\",\"index\":0,\"guid\":\"d5b81381-cef8-4327-923d-"
+ "41e57ff79326\",\"isActive\":false,\"balance\":\"$2,062.25\",\"picture\":\"http://"
+ "placehold.it/32x32\",\"age\":26,\"eyeColor\":\"brown\",\"name\":\"Geneva "
+ "Vega\",\"gender\":\"female\",\"company\":\"SLOGANAUT\",\"email\":\"genevavega@sloganaut."
+ "com\",\"phone\":\"+1 (993) 432-2805\",\"address\":\"943 Christopher Avenue, Northchase, "
+ "Alabama, 5769\",\"about\":\"Eu cillum qui eu fugiat sit nulla eu duis. Aliqua nulla aliqua "
+ "ea tempor dolor fugiat sint consectetur exercitation ipsum magna ex. Aute laborum esse "
+ "magna nostrud in cillum et mollit proident. Deserunt ex minim adipisicing incididunt "
+ "incididunt dolore velit aliqua.\\r\\n\",\"registered\":\"2014-06-02T06:29:33 "
+ "-02:00\",\"latitude\":-66.003108,\"longitude\":44.038986,\"tags\":[\"exercitation\","
+ "\"laborum\",\"velit\",\"magna\",\"officia\",\"aliqua\",\"laboris\"],\"friends\":[{\"id\":0,"
+ "\"name\":\"Daniel Stuart\"},{\"id\":1,\"name\":\"Jackson "
+ "Velez\"},{\"id\":2,\"name\":\"Browning Boyd\"}],\"greeting\":\"Hello, Geneva Vega! You "
+ "have 8 unread "
+ "messages.\",\"favoriteFruit\":\"strawberry\"},{\"_id\":\"614ada7cf28685063c6722af\","
+ "\"index\":1,\"guid\":\"e157edf3-a86d-4984-b18d-e2fe568a9915\",\"isActive\":false,"
+ "\"balance\":\"$3,550.44\",\"picture\":\"http://placehold.it/"
+ "32x32\",\"age\":40,\"eyeColor\":\"blue\",\"name\":\"Lamb "
+ "Lowe\",\"gender\":\"male\",\"company\":\"PROXSOFT\",\"email\":\"lamblowe@proxsoft.com\","
+ "\"phone\":\"+1 (999) 573-2855\",\"address\":\"632 Rockwell Place, Diaperville, "
+ "Pennsylvania, 5050\",\"about\":\"Anim dolor deserunt esse quis velit adipisicing aute "
+ "nostrud velit minim culpa aute et tempor. Dolor aliqua reprehenderit anim voluptate. "
+ "Consequat proident ut culpa reprehenderit qui. Nisi proident velit cillum voluptate. "
+ "Ullamco id sunt quis aute adipisicing cupidatat consequat "
+ "aliquip.\\r\\n\",\"registered\":\"2014-09-06T06:13:36 "
+ "-02:00\",\"latitude\":-44.550228,\"longitude\":-80.893356,\"tags\":[\"anim\",\"id\","
+ "\"irure\",\"do\",\"officia\",\"irure\",\"Lorem\"],\"friends\":[{\"id\":0,\"name\":"
+ "\"Faulkner Watkins\"},{\"id\":1,\"name\":\"Cecile Schneider\"},{\"id\":2,\"name\":\"Burt "
+ "Lester\"}],\"greeting\":\"Hello, Lamb Lowe! You have 1 unread "
+ "messages.\",\"favoriteFruit\":\"strawberry\"},{\"_id\":\"614ada7c235335fc56bc2f78\","
+ "\"index\":2,\"guid\":\"8206bad1-8274-49fd-9223-d727589f22ca\",\"isActive\":false,"
+ "\"balance\":\"$2,548.34\",\"picture\":\"http://placehold.it/"
+ "32x32\",\"age\":37,\"eyeColor\":\"blue\",\"name\":\"Sallie "
+ "Chase\",\"gender\":\"female\",\"company\":\"FLEETMIX\",\"email\":\"salliechase@fleetmix."
+ "com\",\"phone\":\"+1 (953) 453-3388\",\"address\":\"865 Irving Place, Chelsea, Utah, "
+ "9777\",\"about\":\"In magna exercitation incididunt exercitation dolor anim. Consectetur "
+ "dolore commodo elit cillum dolor reprehenderit magna minim et ex labore pariatur. Nulla "
+ "ullamco officia velit in aute proident nostrud. Duis deserunt et labore Lorem aliqua "
+ "eiusmod commodo sunt.\\r\\n\",\"registered\":\"2017-03-16T08:54:53 "
+ "-01:00\",\"latitude\":-78.481939,\"longitude\":-149.820215,\"tags\":[\"Lorem\",\"ipsum\","
+ "\"in\",\"tempor\",\"consectetur\",\"voluptate\",\"elit\"],\"friends\":[{\"id\":0,\"name\":"
+ "\"Gibson Garner\"},{\"id\":1,\"name\":\"Anna Frank\"},{\"id\":2,\"name\":\"Roberson "
+ "Daugherty\"}],\"greeting\":\"Hello, Sallie Chase! You have 7 unread "
+ "messages.\",\"favoriteFruit\":\"apple\"},{\"_id\":\"614ada7c93b63ecad5f9ba5e\",\"index\":3,"
+ "\"guid\":\"924b02fc-7c27-481a-9941-db3b9403dfe1\",\"isActive\":true,\"balance\":\"$1,633."
+ "60\",\"picture\":\"http://placehold.it/"
+ "32x32\",\"age\":29,\"eyeColor\":\"brown\",\"name\":\"Grace "
+ "Mccall\",\"gender\":\"female\",\"company\":\"PIVITOL\",\"email\":\"gracemccall@pivitol."
+ "com\",\"phone\":\"+1 (964) 541-2514\",\"address\":\"734 Schaefer Street, Topaz, Virginia, "
+ "9137\",\"about\":\"Amet officia magna fugiat ut pariatur fugiat elit culpa voluptate elit "
+ "do proident culpa minim. Commodo do minim reprehenderit ut voluptate ut velit id esse "
+ "consequat. Labore ullamco deserunt irure eiusmod cillum tempor incididunt qui adipisicing "
+ "nostrud pariatur enim aliquip. Excepteur nostrud commodo consectetur esse duis irure "
+ "qui.\\r\\n\",\"registered\":\"2015-04-24T03:55:17 "
+ "-02:00\",\"latitude\":58.801446,\"longitude\":-157.413865,\"tags\":[\"do\",\"ea\",\"eu\","
+ "\"eu\",\"qui\",\"duis\",\"sint\"],\"friends\":[{\"id\":0,\"name\":\"Carrie "
+ "Short\"},{\"id\":1,\"name\":\"Dickerson Barnes\"},{\"id\":2,\"name\":\"Rae "
+ "Rios\"}],\"greeting\":\"Hello, Grace Mccall! You have 5 unread "
+ "messages.\",\"favoriteFruit\":\"apple\"},{\"_id\":\"614ada7c9caf1353b0e22bbf\",\"index\":4,"
+ "\"guid\":\"e5981ae1-90e4-41c4-9905-161522db700b\",\"isActive\":false,\"balance\":\"$3,660."
+ "34\",\"picture\":\"http://placehold.it/"
+ "32x32\",\"age\":31,\"eyeColor\":\"blue\",\"name\":\"Herring "
+ "Powers\",\"gender\":\"male\",\"company\":\"PYRAMIA\",\"email\":\"herringpowers@pyramia."
+ "com\",\"phone\":\"+1 (981) 541-2829\",\"address\":\"409 Furman Avenue, Waterloo, South "
+ "Carolina, 380\",\"about\":\"In officia culpa aliqua culpa pariatur aliqua mollit ex. Velit "
+ "est Lorem enim magna cillum sunt elit consectetur deserunt ea est consectetur fugiat "
+ "mollit. Aute Lorem excepteur minim esse qui. Id Lorem in tempor et. Nisi aliquip laborum "
+ "magna eu aute.\\r\\n\",\"registered\":\"2018-07-05T07:28:54 "
+ "-02:00\",\"latitude\":51.497405,\"longitude\":-129.422711,\"tags\":[\"eiusmod\",\"et\","
+ "\"nostrud\",\"reprehenderit\",\"Lorem\",\"cillum\",\"nulla\"],\"friends\":[{\"id\":0,"
+ "\"name\":\"Tonia Keith\"},{\"id\":1,\"name\":\"Leanne Rice\"},{\"id\":2,\"name\":\"Craig "
+ "Gregory\"}],\"greeting\":\"Hello, Herring Powers! You have 6 unread "
+ "messages.\",\"favoriteFruit\":\"strawberry\"},{\"_id\":\"614ada7c53a3d6da77468f25\","
+ "\"index\":5,\"guid\":\"abb2eec9-c4f0-4a0d-b20a-5c8e50fe88a1\",\"isActive\":true,"
+ "\"balance\":\"$1,481.08\",\"picture\":\"http://placehold.it/"
+ "32x32\",\"age\":31,\"eyeColor\":\"green\",\"name\":\"Lela "
+ "Dillard\",\"gender\":\"female\",\"company\":\"CEMENTION\",\"email\":\"leladillard@"
+ "cemention.com\",\"phone\":\"+1 (856) 456-3657\",\"address\":\"391 Diamond Street, Madaket, "
+ "Ohio, 9337\",\"about\":\"Tempor dolor ullamco esse cillum excepteur. Excepteur aliqua non "
+ "enim anim esse amet cupidatat non. Cillum excepteur occaecat cupidatat elit labore. "
+ "Pariatur ut esse sint elit. Velit sint magna et commodo sit velit labore consectetur irure "
+ "officia proident aliquip. Aliqua dolore ipsum voluptate veniam deserunt amet irure. Cillum "
+ "consequat veniam proident Lorem in anim enim veniam ea "
+ "nulla.\\r\\n\",\"registered\":\"2017-01-11T11:07:22 "
+ "-01:00\",\"latitude\":86.349081,\"longitude\":-179.983754,\"tags\":[\"consequat\","
+ "\"labore\",\"consectetur\",\"dolor\",\"laborum\",\"eiusmod\",\"in\"],\"friends\":[{\"id\":"
+ "0,\"name\":\"Hancock Rivera\"},{\"id\":1,\"name\":\"Chasity "
+ "Oneil\"},{\"id\":2,\"name\":\"Whitaker Barr\"}],\"greeting\":\"Hello, Lela Dillard! You "
+ "have 3 unread messages.\",\"favoriteFruit\":\"strawberry\"}]";
+ std::stringstream is(input);
+
+ JsonFormatter json;
+ std::unique_ptr<Value> value = json.deserialize(is);
+ EXPECT_EQ(value->type(), eValueType::Array);
+
+ std::stringstream out;
+ json.serialize(out, *value);
+ EXPECT_EQ(out.str(), input);
+}
+
+} // namespace blender::io::serialize::json::testing
diff --git a/source/blender/blenlib/tests/BLI_set_test.cc b/source/blender/blenlib/tests/BLI_set_test.cc
index 3a4733a218f..28eb4df2ca6 100644
--- a/source/blender/blenlib/tests/BLI_set_test.cc
+++ b/source/blender/blenlib/tests/BLI_set_test.cc
@@ -544,6 +544,32 @@ TEST(set, GenericAlgorithms)
EXPECT_EQ(std::count(set.begin(), set.end(), 20), 1);
}
+TEST(set, RemoveDuringIteration)
+{
+ Set<int> set;
+ set.add(6);
+ set.add(5);
+ set.add(2);
+ set.add(3);
+
+ EXPECT_EQ(set.size(), 4);
+
+ using Iter = Set<int>::Iterator;
+ Iter begin = set.begin();
+ Iter end = set.end();
+ for (Iter iter = begin; iter != end; ++iter) {
+ int item = *iter;
+ if (item == 2) {
+ set.remove(iter);
+ }
+ }
+
+ EXPECT_EQ(set.size(), 3);
+ EXPECT_TRUE(set.contains(5));
+ EXPECT_TRUE(set.contains(6));
+ EXPECT_TRUE(set.contains(3));
+}
+
/**
* Set this to 1 to activate the benchmark. It is disabled by default, because it prints a lot.
*/
diff --git a/source/blender/blenlib/tests/BLI_string_search_test.cc b/source/blender/blenlib/tests/BLI_string_search_test.cc
index 0d1fd2cab96..aa1c0b41c44 100644
--- a/source/blender/blenlib/tests/BLI_string_search_test.cc
+++ b/source/blender/blenlib/tests/BLI_string_search_test.cc
@@ -8,6 +8,9 @@
namespace blender::string_search::tests {
+/* Right arrow, keep in sync with #UI_MENU_ARROW_SEP in `UI_interface.h`. */
+#define UI_MENU_ARROW_SEP "\xe2\x96\xb6"
+
TEST(string_search, damerau_levenshtein_distance)
{
EXPECT_EQ(damerau_levenshtein_distance("test", "test"), 0);
@@ -30,14 +33,17 @@ TEST(string_search, get_fuzzy_match_errors)
EXPECT_EQ(get_fuzzy_match_errors("", "abc"), 0);
EXPECT_EQ(get_fuzzy_match_errors("hello", "hallo"), 1);
EXPECT_EQ(get_fuzzy_match_errors("hap", "hello"), -1);
- EXPECT_EQ(get_fuzzy_match_errors("armature", "▶restore"), -1);
+ EXPECT_EQ(get_fuzzy_match_errors("armature", UI_MENU_ARROW_SEP "restore"), -1);
}
TEST(string_search, extract_normalized_words)
{
LinearAllocator<> allocator;
Vector<StringRef, 64> words;
- extract_normalized_words("hello world▶test another test▶ 3", allocator, words);
+ extract_normalized_words("hello world" UI_MENU_ARROW_SEP "test another test" UI_MENU_ARROW_SEP
+ " 3",
+ allocator,
+ words);
EXPECT_EQ(words.size(), 6);
EXPECT_EQ(words[0], "hello");
EXPECT_EQ(words[1], "world");
diff --git a/source/blender/blenlib/tests/BLI_task_test.cc b/source/blender/blenlib/tests/BLI_task_test.cc
index dd4441517a9..3bb6f6f753c 100644
--- a/source/blender/blenlib/tests/BLI_task_test.cc
+++ b/source/blender/blenlib/tests/BLI_task_test.cc
@@ -154,7 +154,7 @@ static void task_mempool_iter_tls_func(void *UNUSED(userdata),
EXPECT_TRUE(data != nullptr);
if (task_data->accumulate_items == nullptr) {
- task_data->accumulate_items = (ListBase *)MEM_callocN(sizeof(ListBase), __func__);
+ task_data->accumulate_items = MEM_cnew<ListBase>(__func__);
}
/* Flip to prove this has been touched. */
@@ -172,7 +172,7 @@ static void task_mempool_iter_tls_reduce(const void *__restrict UNUSED(userdata)
if (data_chunk->accumulate_items != nullptr) {
if (join_chunk->accumulate_items == nullptr) {
- join_chunk->accumulate_items = (ListBase *)MEM_callocN(sizeof(ListBase), __func__);
+ join_chunk->accumulate_items = MEM_cnew<ListBase>(__func__);
}
BLI_movelisttolist(join_chunk->accumulate_items, data_chunk->accumulate_items);
}
diff --git a/source/blender/blenlib/tests/BLI_uuid_test.cc b/source/blender/blenlib/tests/BLI_uuid_test.cc
index b406a0521a1..111c21cb7d1 100644
--- a/source/blender/blenlib/tests/BLI_uuid_test.cc
+++ b/source/blender/blenlib/tests/BLI_uuid_test.cc
@@ -24,11 +24,11 @@ TEST(BLI_uuid, generate_random)
{
const bUUID uuid = BLI_uuid_generate_random();
- // The 4 MSbits represent the "version" of the UUID.
+ /* The 4 MSbits represent the "version" of the UUID. */
const uint16_t version = uuid.time_hi_and_version >> 12;
EXPECT_EQ(version, 4);
- // The 2 MSbits should be 0b10, indicating compliance with RFC4122.
+ /* The 2 MSbits should be 0b10, indicating compliance with RFC4122. */
const uint8_t reserved = uuid.clock_seq_hi_and_reserved >> 6;
EXPECT_EQ(reserved, 0b10);
}
@@ -42,7 +42,7 @@ TEST(BLI_uuid, generate_many_random)
const bUUID uuid = BLI_uuid_generate_random();
EXPECT_NE(first_uuid, uuid);
- // Check that the non-random bits are set according to RFC4122.
+ /* Check that the non-random bits are set according to RFC4122. */
const uint16_t version = uuid.time_hi_and_version >> 12;
EXPECT_EQ(version, 4);
const uint8_t reserved = uuid.clock_seq_hi_and_reserved >> 6;
diff --git a/source/blender/blenlib/tests/BLI_vector_test.cc b/source/blender/blenlib/tests/BLI_vector_test.cc
index e8636168308..e9393a2b1e5 100644
--- a/source/blender/blenlib/tests/BLI_vector_test.cc
+++ b/source/blender/blenlib/tests/BLI_vector_test.cc
@@ -708,6 +708,17 @@ TEST(vector, Prepend)
EXPECT_EQ_ARRAY(vec.data(), Span({7, 8, 1, 2, 3}).data(), 5);
}
+TEST(vector, PrependString)
+{
+ std::string s = "test";
+ Vector<std::string> vec;
+ vec.prepend(s);
+ vec.prepend(std::move(s));
+ EXPECT_EQ(vec.size(), 2);
+ EXPECT_EQ(vec[0], "test");
+ EXPECT_EQ(vec[1], "test");
+}
+
TEST(vector, ReverseIterator)
{
Vector<int> vec = {4, 5, 6, 7};
diff --git a/source/blender/blenlib/tests/BLI_virtual_array_test.cc b/source/blender/blenlib/tests/BLI_virtual_array_test.cc
index a6d2ca10315..62b7b383831 100644
--- a/source/blender/blenlib/tests/BLI_virtual_array_test.cc
+++ b/source/blender/blenlib/tests/BLI_virtual_array_test.cc
@@ -12,7 +12,7 @@ namespace blender::tests {
TEST(virtual_array, Span)
{
std::array<int, 5> data = {3, 4, 5, 6, 7};
- VArray_For_Span<int> varray{data};
+ VArray<int> varray = VArray<int>::ForSpan(data);
EXPECT_EQ(varray.size(), 5);
EXPECT_EQ(varray.get(0), 3);
EXPECT_EQ(varray.get(4), 7);
@@ -23,7 +23,7 @@ TEST(virtual_array, Span)
TEST(virtual_array, Single)
{
- VArray_For_Single<int> varray{10, 4};
+ VArray<int> varray = VArray<int>::ForSingle(10, 4);
EXPECT_EQ(varray.size(), 4);
EXPECT_EQ(varray.get(0), 10);
EXPECT_EQ(varray.get(3), 10);
@@ -35,7 +35,7 @@ TEST(virtual_array, Array)
{
Array<int> array = {1, 2, 3, 5, 8};
{
- VArray_For_ArrayContainer varray{array};
+ VArray<int> varray = VArray<int>::ForContainer(array);
EXPECT_EQ(varray.size(), 5);
EXPECT_EQ(varray[0], 1);
EXPECT_EQ(varray[2], 3);
@@ -43,7 +43,7 @@ TEST(virtual_array, Array)
EXPECT_TRUE(varray.is_span());
}
{
- VArray_For_ArrayContainer varray{std::move(array)};
+ VArray<int> varray = VArray<int>::ForContainer(std::move(array));
EXPECT_EQ(varray.size(), 5);
EXPECT_EQ(varray[0], 1);
EXPECT_EQ(varray[2], 3);
@@ -51,7 +51,7 @@ TEST(virtual_array, Array)
EXPECT_TRUE(varray.is_span());
}
{
- VArray_For_ArrayContainer varray{array}; /* NOLINT: bugprone-use-after-move */
+ VArray<int> varray = VArray<int>::ForContainer(array); /* NOLINT: bugprone-use-after-move */
EXPECT_TRUE(varray.is_empty());
}
}
@@ -59,7 +59,7 @@ TEST(virtual_array, Array)
TEST(virtual_array, Vector)
{
Vector<int> vector = {9, 8, 7, 6};
- VArray_For_ArrayContainer varray{std::move(vector)};
+ VArray<int> varray = VArray<int>::ForContainer(std::move(vector));
EXPECT_EQ(varray.size(), 4);
EXPECT_EQ(varray[0], 9);
EXPECT_EQ(varray[3], 6);
@@ -68,7 +68,7 @@ TEST(virtual_array, Vector)
TEST(virtual_array, StdVector)
{
std::vector<int> vector = {5, 6, 7, 8};
- VArray_For_ArrayContainer varray{std::move(vector)};
+ VArray<int> varray = VArray<int>::ForContainer(std::move(vector));
EXPECT_EQ(varray.size(), 4);
EXPECT_EQ(varray[0], 5);
EXPECT_EQ(varray[1], 6);
@@ -77,7 +77,7 @@ TEST(virtual_array, StdVector)
TEST(virtual_array, StdArray)
{
std::array<int, 4> array = {2, 3, 4, 5};
- VArray_For_ArrayContainer varray{array};
+ VArray<int> varray = VArray<int>::ForContainer(std::move(array));
EXPECT_EQ(varray.size(), 4);
EXPECT_EQ(varray[0], 2);
EXPECT_EQ(varray[1], 3);
@@ -86,7 +86,7 @@ TEST(virtual_array, StdArray)
TEST(virtual_array, VectorSet)
{
VectorSet<int> vector_set = {5, 3, 7, 3, 3, 5, 1};
- VArray_For_ArrayContainer varray{std::move(vector_set)};
+ VArray<int> varray = VArray<int>::ForContainer(std::move(vector_set));
EXPECT_TRUE(vector_set.is_empty()); /* NOLINT: bugprone-use-after-move. */
EXPECT_EQ(varray.size(), 4);
EXPECT_EQ(varray[0], 5);
@@ -98,7 +98,7 @@ TEST(virtual_array, VectorSet)
TEST(virtual_array, Func)
{
auto func = [](int64_t index) { return (int)(index * index); };
- VArray_For_Func<int, decltype(func)> varray{10, func};
+ VArray<int> varray = VArray<int>::ForFunc(10, func);
EXPECT_EQ(varray.size(), 10);
EXPECT_EQ(varray[0], 0);
EXPECT_EQ(varray[3], 9);
@@ -108,7 +108,7 @@ TEST(virtual_array, Func)
TEST(virtual_array, AsSpan)
{
auto func = [](int64_t index) { return (int)(10 * index); };
- VArray_For_Func<int, decltype(func)> func_varray{10, func};
+ VArray<int> func_varray = VArray<int>::ForFunc(10, func);
VArray_Span span_varray{func_varray};
EXPECT_EQ(span_varray.size(), 10);
Span<int> span = span_varray;
@@ -134,13 +134,14 @@ TEST(virtual_array, DerivedSpan)
vector.append({3, 4, 5});
vector.append({1, 1, 1});
{
- VArray_For_DerivedSpan<std::array<int, 3>, int, get_x> varray{vector};
+ VArray<int> varray = VArray<int>::ForDerivedSpan<std::array<int, 3>, get_x>(vector);
EXPECT_EQ(varray.size(), 2);
EXPECT_EQ(varray[0], 3);
EXPECT_EQ(varray[1], 1);
}
{
- VMutableArray_For_DerivedSpan<std::array<int, 3>, int, get_x, set_x> varray{vector};
+ VMutableArray<int> varray =
+ VMutableArray<int>::ForDerivedSpan<std::array<int, 3>, get_x, set_x>(vector);
EXPECT_EQ(varray.size(), 2);
EXPECT_EQ(varray[0], 3);
EXPECT_EQ(varray[1], 1);
@@ -151,4 +152,32 @@ TEST(virtual_array, DerivedSpan)
}
}
+TEST(virtual_array, MutableToImmutable)
+{
+ std::array<int, 4> array = {4, 2, 6, 4};
+ {
+ VMutableArray<int> mutable_varray = VMutableArray<int>::ForSpan(array);
+ VArray<int> varray = mutable_varray;
+ EXPECT_TRUE(varray.is_span());
+ EXPECT_EQ(varray.size(), 4);
+ EXPECT_EQ(varray[1], 2);
+ EXPECT_EQ(mutable_varray.size(), 4);
+ }
+ {
+ VMutableArray<int> mutable_varray = VMutableArray<int>::ForSpan(array);
+ EXPECT_EQ(mutable_varray.size(), 4);
+ VArray<int> varray = std::move(mutable_varray);
+ EXPECT_TRUE(varray.is_span());
+ EXPECT_EQ(varray.size(), 4);
+ EXPECT_EQ(varray[1], 2);
+ EXPECT_EQ(mutable_varray.size(), 0); /* NOLINT: bugprone-use-after-move */
+ }
+ {
+ VArray<int> varray = VMutableArray<int>::ForSpan(array);
+ EXPECT_TRUE(varray.is_span());
+ EXPECT_EQ(varray.size(), 4);
+ EXPECT_EQ(varray[1], 2);
+ }
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/performance/CMakeLists.txt b/source/blender/blenlib/tests/performance/CMakeLists.txt
index 5342dbe286c..036955a4b43 100644
--- a/source/blender/blenlib/tests/performance/CMakeLists.txt
+++ b/source/blender/blenlib/tests/performance/CMakeLists.txt
@@ -23,7 +23,6 @@ set(INC
..
)
-setup_libdirs()
include_directories(${INC})
BLENDER_TEST_PERFORMANCE(BLI_ghash_performance "bf_blenlib")
diff --git a/source/blender/blenloader/BLO_blend_validate.h b/source/blender/blenloader/BLO_blend_validate.h
index 78aa481d4b1..3a192284661 100644
--- a/source/blender/blenloader/BLO_blend_validate.h
+++ b/source/blender/blenloader/BLO_blend_validate.h
@@ -21,12 +21,19 @@
/** \file
* \ingroup blenloader
- * \brief Utils ensuring .blend file (i.e. Main)
+ * \brief Utilities ensuring `.blend` file (i.e. Main)
* is in valid state during write and/or read process.
*/
struct Main;
struct ReportList;
+/**
+ * Check (but do *not* fix) that all linked data-blocks are still valid
+ * (i.e. pointing to the right library).
+ */
bool BLO_main_validate_libraries(struct Main *bmain, struct ReportList *reports);
+/**
+ * * Check (and fix if needed) that shape key's 'from' pointer is valid.
+ */
bool BLO_main_validate_shapekeys(struct Main *bmain, struct ReportList *reports);
diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h
index 86c7c367816..fe8173e335a 100644
--- a/source/blender/blenloader/BLO_read_write.h
+++ b/source/blender/blenloader/BLO_read_write.h
@@ -43,7 +43,7 @@
/* for SDNA_TYPE_FROM_STRUCT() macro */
#include "dna_type_offsets.h"
-#include "DNA_windowmanager_types.h" /* for ReportType */
+#include "DNA_windowmanager_types.h" /* for eReportType */
#ifdef __cplusplus
extern "C" {
@@ -58,8 +58,8 @@ struct BlendFileReadReport;
struct Main;
struct ReportList;
-/* Blend Write API
- * ===============
+/* -------------------------------------------------------------------- */
+/** \name Blend Write API
*
* Most functions fall into one of two categories. Either they write a DNA struct or a raw memory
* buffer to the .blend file.
@@ -69,41 +69,47 @@ struct ReportList;
* DNA Struct Writing
* ------------------
*
- * Functions dealing with DNA structs begin with BLO_write_struct_*.
+ * Functions dealing with DNA structs begin with `BLO_write_struct_*`.
*
* DNA struct types can be identified in different ways:
- * - Run-time Name: The name is provided as const char *.
- * - Compile-time Name: The name is provided at compile time. This is more efficient.
- * - Struct ID: Every DNA struct type has an integer ID that can be queried with
- * BLO_get_struct_id_by_name. Providing this ID can be a useful optimization when many structs
- * of the same type are stored AND if those structs are not in a continuous array.
+ * - Run-time Name: The name is provided as `const char *`.
+ * - Compile-time Name: The name is provided at compile time. This is more efficient.
+ * - Struct ID: Every DNA struct type has an integer ID that can be queried with
+ * #BLO_get_struct_id_by_name. Providing this ID can be a useful optimization when many
+ * structs of the same type are stored AND if those structs are not in a continuous array.
*
* Often only a single instance of a struct is written at once. However, sometimes it is necessary
* to write arrays or linked lists. Separate functions for that are provided as well.
*
- * There is a special macro for writing id structs: BLO_write_id_struct. Those are handled
- * differently from other structs.
+ * There is a special macro for writing id structs: #BLO_write_id_struct.
+ * Those are handled differently from other structs.
*
* Raw Data Writing
* ----------------
*
- * At the core there is BLO_write_raw, which can write arbitrary memory buffers to the file. The
- * code that reads this data might have to correct its byte-order. For the common cases there are
- * convenience functions that write and read arrays of simple types such as int32. Those will
- * correct endianness automatically.
+ * At the core there is #BLO_write_raw, which can write arbitrary memory buffers to the file.
+ * The code that reads this data might have to correct its byte-order. For the common cases
+ * there are convenience functions that write and read arrays of simple types such as `int32`.
+ * Those will correct endianness automatically.
+ * \{ */
+
+/**
+ * Mapping between names and ids.
*/
-
-/* Mapping between names and ids. */
int BLO_get_struct_id_by_name(BlendWriter *writer, const char *struct_name);
#define BLO_get_struct_id(writer, struct_name) SDNA_TYPE_FROM_STRUCT(struct_name)
-/* Write single struct. */
+/**
+ * Write single struct.
+ */
void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr);
void BLO_write_struct_by_id(BlendWriter *writer, int struct_id, const void *data_ptr);
#define BLO_write_struct(writer, struct_name, data_ptr) \
BLO_write_struct_by_id(writer, BLO_get_struct_id(writer, struct_name), data_ptr)
-/* Write single struct at address. */
+/**
+ * Write single struct at address.
+ */
void BLO_write_struct_at_address_by_id(BlendWriter *writer,
int struct_id,
const void *address,
@@ -112,7 +118,9 @@ void BLO_write_struct_at_address_by_id(BlendWriter *writer,
BLO_write_struct_at_address_by_id( \
writer, BLO_get_struct_id(writer, struct_name), address, data_ptr)
-/* Write single struct at address and specify a filecode. */
+/**
+ * Write single struct at address and specify a file-code.
+ */
void BLO_write_struct_at_address_by_id_with_filecode(
BlendWriter *writer, int filecode, int struct_id, const void *address, const void *data_ptr);
#define BLO_write_struct_at_address_with_filecode( \
@@ -120,7 +128,9 @@ void BLO_write_struct_at_address_by_id_with_filecode(
BLO_write_struct_at_address_by_id_with_filecode( \
writer, filecode, BLO_get_struct_id(writer, struct_name), address, data_ptr)
-/* Write struct array. */
+/**
+ * Write struct array.
+ */
void BLO_write_struct_array_by_name(BlendWriter *writer,
const char *struct_name,
int array_size,
@@ -133,14 +143,18 @@ void BLO_write_struct_array_by_id(BlendWriter *writer,
BLO_write_struct_array_by_id( \
writer, BLO_get_struct_id(writer, struct_name), array_size, data_ptr)
-/* Write struct array at address. */
+/**
+ * Write struct array at address.
+ */
void BLO_write_struct_array_at_address_by_id(
BlendWriter *writer, int struct_id, int array_size, const void *address, const void *data_ptr);
#define BLO_write_struct_array_at_address(writer, struct_name, array_size, address, data_ptr) \
BLO_write_struct_array_at_address_by_id( \
writer, BLO_get_struct_id(writer, struct_name), array_size, address, data_ptr)
-/* Write struct list. */
+/**
+ * Write struct list.
+ */
void BLO_write_struct_list_by_name(BlendWriter *writer,
const char *struct_name,
struct ListBase *list);
@@ -148,7 +162,9 @@ void BLO_write_struct_list_by_id(BlendWriter *writer, int struct_id, struct List
#define BLO_write_struct_list(writer, struct_name, list_ptr) \
BLO_write_struct_list_by_id(writer, BLO_get_struct_id(writer, struct_name), list_ptr)
-/* Write id struct. */
+/**
+ * Write id struct.
+ */
void blo_write_id_struct(BlendWriter *writer,
int struct_id,
const void *id_address,
@@ -156,7 +172,9 @@ void blo_write_id_struct(BlendWriter *writer,
#define BLO_write_id_struct(writer, struct_name, id_address, id) \
blo_write_id_struct(writer, BLO_get_struct_id(writer, struct_name), id_address, id)
-/* Write raw data. */
+/**
+ * Write raw data.
+ */
void BLO_write_raw(BlendWriter *writer, size_t size_in_bytes, const void *data_ptr);
void BLO_write_int32_array(BlendWriter *writer, uint num, const int32_t *data_ptr);
void BLO_write_uint32_array(BlendWriter *writer, uint num, const uint32_t *data_ptr);
@@ -164,13 +182,23 @@ void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr)
void BLO_write_double_array(BlendWriter *writer, uint num, const double *data_ptr);
void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr);
void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr);
+/**
+ * Write a null terminated string.
+ */
void BLO_write_string(BlendWriter *writer, const char *data_ptr);
/* Misc. */
+
+/**
+ * Sometimes different data is written depending on whether the file is saved to disk or used for
+ * undo. This function returns true when the current file-writing is done for undo.
+ */
bool BLO_write_is_undo(BlendWriter *writer);
-/* Blend Read Data API
- * ===================
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend Read Data API
*
* Generally, for every BLO_write_* call there should be a corresponding BLO_read_* call.
*
@@ -181,15 +209,18 @@ bool BLO_write_is_undo(BlendWriter *writer);
* updated to be NULL. When it was pointing to NULL before, it will stay that way.
*
* Examples of matching calls:
- * BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms);
- * BLO_read_data_address(reader, &clmd->sim_parms);
*
- * BLO_write_struct_list(writer, TimeMarker, &action->markers);
- * BLO_read_list(reader, &action->markers);
+ * \code{.c}
+ * BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms);
+ * BLO_read_data_address(reader, &clmd->sim_parms);
*
- * BLO_write_int32_array(writer, hmd->totindex, hmd->indexar);
- * BLO_read_int32_array(reader, hmd->totindex, &hmd->indexar);
- */
+ * BLO_write_struct_list(writer, TimeMarker, &action->markers);
+ * BLO_read_list(reader, &action->markers);
+ *
+ * BLO_write_int32_array(writer, hmd->totindex, hmd->indexar);
+ * BLO_read_int32_array(reader, hmd->totindex, &hmd->indexar);
+ * \endcode
+ * \{ */
void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address);
void *BLO_read_get_new_data_address_no_us(BlendDataReader *reader, const void *old_address);
@@ -201,10 +232,16 @@ void *BLO_read_get_new_packed_address(BlendDataReader *reader, const void *old_a
*((void **)ptr_p) = BLO_read_get_new_packed_address((reader), *(ptr_p))
typedef void (*BlendReadListFn)(BlendDataReader *reader, void *data);
+/**
+ * Updates all ->prev and ->next pointers of the list elements.
+ * Updates the list->first and list->last pointers.
+ * When not NULL, calls the callback on every element.
+ */
void BLO_read_list_cb(BlendDataReader *reader, struct ListBase *list, BlendReadListFn callback);
void BLO_read_list(BlendDataReader *reader, struct ListBase *list);
/* Update data pointers and correct byte-order if necessary. */
+
void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p);
void BLO_read_uint32_array(BlendDataReader *reader, int array_size, uint32_t **ptr_p);
void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p);
@@ -213,18 +250,21 @@ void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr
void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p);
/* Misc. */
+
bool BLO_read_requires_endian_switch(BlendDataReader *reader);
bool BLO_read_data_is_undo(BlendDataReader *reader);
void BLO_read_data_globmap_add(BlendDataReader *reader, void *oldaddr, void *newaddr);
void BLO_read_glob_list(BlendDataReader *reader, struct ListBase *list);
struct BlendFileReadReport *BLO_read_data_reports(BlendDataReader *reader);
-/* Blend Read Lib API
- * ===================
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend Read Lib API
*
- * This API does almost the same as the Blend Read Data API. However, now only pointers to ID data
- * blocks are updated.
- */
+ * This API does almost the same as the Blend Read Data API.
+ * However, now only pointers to ID data blocks are updated.
+ * \{ */
ID *BLO_read_get_new_id_address(BlendLibReader *reader, struct Library *lib, struct ID *id);
@@ -232,30 +272,44 @@ ID *BLO_read_get_new_id_address(BlendLibReader *reader, struct Library *lib, str
*((void **)id_ptr_p) = (void *)BLO_read_get_new_id_address((reader), (lib), (ID *)*(id_ptr_p))
/* Misc. */
+
bool BLO_read_lib_is_undo(BlendLibReader *reader);
struct Main *BLO_read_lib_get_main(BlendLibReader *reader);
struct BlendFileReadReport *BLO_read_lib_reports(BlendLibReader *reader);
-/* Blend Expand API
- * ===================
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend Expand API
*
* BLO_expand has to be called for every data block that should be loaded. If the data block is in
- * a separate .blend file, it will be pulled from there.
- */
+ * a separate `.blend` file, it will be pulled from there.
+ * \{ */
void BLO_expand_id(BlendExpander *expander, struct ID *id);
#define BLO_expand(expander, id) BLO_expand_id(expander, (struct ID *)id)
-/* Report API
- * ===================
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Report API
+ * \{ */
+/**
+ * This function ensures that reports are printed,
+ * in the case of library linking errors this is important!
+ *
+ * bit kludge but better than doubling up on prints,
+ * we could alternatively have a versions of a report function which forces printing - campbell
+ */
void BLO_reportf_wrap(struct BlendFileReadReport *reports,
- ReportType type,
+ eReportType type,
const char *format,
...) ATTR_PRINTF_FORMAT(3, 4);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index c6637b17d47..c4c3b42cb63 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -32,11 +32,13 @@ extern "C" {
struct BHead;
struct BlendThumbnail;
+struct Collection;
struct FileData;
struct LinkNode;
struct ListBase;
struct Main;
struct MemFile;
+struct Object;
struct ReportList;
struct Scene;
struct UserDef;
@@ -72,7 +74,7 @@ typedef struct BlendFileData {
int fileflags;
int globalf;
- char filename[1024]; /* 1024 = FILE_MAX */
+ char filepath[1024]; /* 1024 = FILE_MAX */
struct bScreen *curscreen; /* TODO: think this isn't needed anymore? */
struct Scene *curscene;
@@ -121,8 +123,8 @@ typedef struct BlendFileReadReport {
int proxies_to_lib_overrides_success;
/* Number of proxies that failed to convert to library overrides. */
int proxies_to_lib_overrides_failures;
- /* Number of VSE strips that were not read because were in non-supported channels. */
- int vse_strips_skipped;
+ /* Number of sequencer strips that were not read because were in non-supported channels. */
+ int sequence_strips_skipped;
} count;
/* Number of libraries which had overrides that needed to be resynced, and a single linked list
@@ -142,19 +144,50 @@ typedef enum eBLOReadSkip {
} eBLOReadSkip;
#define BLO_READ_SKIP_ALL (BLO_READ_SKIP_USERDEF | BLO_READ_SKIP_DATA)
+/**
+ * Open a blender file from a pathname. The function returns NULL
+ * and sets a report in the list if it cannot open the file.
+ *
+ * \param filepath: The path of the file to open.
+ * \param reports: If the return value is NULL, errors indicating the cause of the failure.
+ * \return The data of the file.
+ */
BlendFileData *BLO_read_from_file(const char *filepath,
eBLOReadSkip skip_flags,
struct BlendFileReadReport *reports);
+/**
+ * Open a blender file from memory. The function returns NULL
+ * and sets a report in the list if it cannot open the file.
+ *
+ * \param mem: The file data.
+ * \param memsize: The length of \a mem.
+ * \param reports: If the return value is NULL, errors indicating the cause of the failure.
+ * \return The data of the file.
+ */
BlendFileData *BLO_read_from_memory(const void *mem,
int memsize,
eBLOReadSkip skip_flags,
struct ReportList *reports);
+/**
+ * Used for undo/redo, skips part of libraries reading
+ * (assuming their data are already loaded & valid).
+ *
+ * \param oldmain: old main,
+ * from which we will keep libraries and other data-blocks that should not have changed.
+ * \param filename: current file, only for retrieving library data.
+ */
BlendFileData *BLO_read_from_memfile(struct Main *oldmain,
const char *filename,
struct MemFile *memfile,
const struct BlendFileReadParams *params,
struct ReportList *reports);
+/**
+ * Frees a BlendFileData structure and *all* the data associated with it
+ * (the userdef data, and the main libblock data).
+ *
+ * \param bfd: The structure to free.
+ */
void BLO_blendfiledata_free(BlendFileData *bfd);
/** \} */
@@ -163,29 +196,96 @@ void BLO_blendfiledata_free(BlendFileData *bfd);
/** \name BLO Blend File Handle API
* \{ */
-struct BLODataBlockInfo {
+typedef struct BLODataBlockInfo {
char name[64]; /* MAX_NAME */
struct AssetMetaData *asset_data;
-};
+} BLODataBlockInfo;
+/**
+ * Open a blendhandle from a file path.
+ *
+ * \param filepath: The file path to open.
+ * \param reports: Report errors in opening the file (can be NULL).
+ * \return A handle on success, or NULL on failure.
+ */
BlendHandle *BLO_blendhandle_from_file(const char *filepath, struct BlendFileReadReport *reports);
+/**
+ * Open a blendhandle from memory.
+ *
+ * \param mem: The data to load from.
+ * \param memsize: The size of the data.
+ * \return A handle on success, or NULL on failure.
+ */
BlendHandle *BLO_blendhandle_from_memory(const void *mem,
int memsize,
struct BlendFileReadReport *reports);
+/**
+ * Gets the names of all the data-blocks in a file of a certain type
+ * (e.g. all the scene names in a file).
+ *
+ * \param bh: The blendhandle to access.
+ * \param ofblocktype: The type of names to get.
+ * \param use_assets_only: Only list IDs marked as assets.
+ * \param r_tot_names: The length of the returned list.
+ * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN().
+ */
struct LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh,
int ofblocktype,
- const bool use_assets_only,
+ bool use_assets_only,
int *r_tot_names);
-struct LinkNode * /*BLODataBlockInfo */ BLO_blendhandle_get_datablock_info(
- BlendHandle *bh, int ofblocktype, const bool use_assets_only, int *r_tot_info_items);
+/**
+ * Gets the names and asset-data (if ID is an asset) of data-blocks in a file of a certain type.
+ * The data-blocks can be limited to assets.
+ *
+ * \param bh: The blendhandle to access.
+ * \param ofblocktype: The type of names to get.
+ * \param use_assets_only: Limit the result to assets only.
+ * \param r_tot_info_items: The length of the returned list.
+ * \return A BLI_linklist of `BLODataBlockInfo *`.
+ * The links and #BLODataBlockInfo.asset_data should be freed with MEM_freeN.
+ */
+struct LinkNode * /*BLODataBlockInfo */ BLO_blendhandle_get_datablock_info(BlendHandle *bh,
+ int ofblocktype,
+ bool use_assets_only,
+ int *r_tot_info_items);
+/**
+ * Gets the previews of all the data-blocks in a file of a certain type
+ * (e.g. all the scene previews in a file).
+ *
+ * \param bh: The blendhandle to access.
+ * \param ofblocktype: The type of names to get.
+ * \param r_tot_prev: The length of the returned list.
+ * \return A BLI_linklist of #PreviewImage. The #PreviewImage links should be freed with malloc.
+ */
struct LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_tot_prev);
+/**
+ * Get the PreviewImage of a single data block in a file.
+ * (e.g. all the scene previews in a file).
+ *
+ * \param bh: The blendhandle to access.
+ * \param ofblocktype: The type of names to get.
+ * \param name: Name of the block without the ID_ prefix, to read the preview image from.
+ * \return PreviewImage or NULL when no preview Images have been found. Caller owns the returned
+ */
struct PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh,
int ofblocktype,
const char *name);
+/**
+ * Gets the names of all the linkable data-block types available in a file.
+ * (e.g. "Scene", "Mesh", "Light", etc.).
+ *
+ * \param bh: The blendhandle to access.
+ * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN().
+ */
struct LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh);
+/**
+ * Close and free a blendhandle. The handle becomes invalid after this call.
+ *
+ * \param bh: The handle to close.
+ */
void BLO_blendhandle_close(BlendHandle *bh);
/** \} */
@@ -193,7 +293,25 @@ void BLO_blendhandle_close(BlendHandle *bh);
#define BLO_GROUP_MAX 32
#define BLO_EMBEDDED_STARTUP_BLEND "<startup.blend>"
+/**
+ * Check whether given path ends with a blend file compatible extension
+ * (`.blend`, `.ble` or `.blend.gz`).
+ *
+ * \param str: The path to check.
+ * \return true is this path ends with a blender file extension.
+ */
bool BLO_has_bfile_extension(const char *str);
+/**
+ * Try to explode given path into its 'library components'
+ * (i.e. a .blend file, id type/group, and data-block itself).
+ *
+ * \param path: the full path to explode.
+ * \param r_dir: the string that'll contain path up to blend file itself ('library' path).
+ * WARNING! Must be #FILE_MAX_LIBEXTRA long (it also stores group and name strings)!
+ * \param r_group: the string that'll contain 'group' part of the path, if any. May be NULL.
+ * \param r_name: the string that'll contain data's name part of the path, if any. May be NULL.
+ * \return true if path contains a blend file.
+ */
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name);
/* -------------------------------------------------------------------- */
@@ -210,20 +328,16 @@ typedef enum eBLOLibLinkFlags {
BLO_LIBLINK_USE_PLACEHOLDERS = 1 << 16,
/** Force loaded ID to be tagged as #LIB_TAG_INDIRECT (used in reload context only). */
BLO_LIBLINK_FORCE_INDIRECT = 1 << 17,
- /**
- * When set, tag ID types that pass the internal check #library_link_idcode_needs_tag_check
- *
- * Currently this is only used to instantiate objects in the scene.
- * Set this from #BLO_library_link_params_init_with_context so callers
- * don't need to remember to set this flag.
- */
- BLO_LIBLINK_NEEDS_ID_TAG_DOIT = 1 << 18,
/** Set fake user on appended IDs. */
BLO_LIBLINK_APPEND_SET_FAKEUSER = 1 << 19,
- /** Append (make local) also indirect dependencies of appended IDs. */
+ /** Append (make local) also indirect dependencies of appended IDs coming from other libraries.
+ * NOTE: All IDs (including indirectly linked ones) coming from the same initial library are
+ * always made local. */
BLO_LIBLINK_APPEND_RECURSIVE = 1 << 20,
/** Try to re-use previously appended matching ID on new append. */
BLO_LIBLINK_APPEND_LOCAL_ID_REUSE = 1 << 21,
+ /** Clear the asset data. */
+ BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR = 1 << 22,
/** Instantiate object data IDs (i.e. create objects for them if needed). */
BLO_LIBLINK_OBDATA_INSTANCE = 1 << 24,
/** Instantiate collections as empties, instead of linking them into current view layer. */
@@ -235,7 +349,7 @@ typedef enum eBLOLibLinkFlags {
* #BLO_library_link_begin, #BLO_library_link_named_part & #BLO_library_link_end.
* Wrap these in parameters since it's important both functions receive matching values.
*/
-struct LibraryLink_Params {
+typedef struct LibraryLink_Params {
/** The current main database, e.g. #G_MAIN or `CTX_data_main(C)`. */
struct Main *bmain;
/** Options for linking, used for instantiating. */
@@ -251,34 +365,59 @@ struct LibraryLink_Params {
/** The active 3D viewport (only used to define local-view). */
const struct View3D *v3d;
} context;
-};
+} LibraryLink_Params;
void BLO_library_link_params_init(struct LibraryLink_Params *params,
struct Main *bmain,
- const int flag,
- const int id_tag_extra);
+ int flag,
+ int id_tag_extra);
void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params,
struct Main *bmain,
- const int flag,
- const int id_tag_extra,
+ int flag,
+ int id_tag_extra,
struct Scene *scene,
struct ViewLayer *view_layer,
const struct View3D *v3d);
+/**
+ * Initialize the #BlendHandle for linking library data.
+ *
+ * \param bh: A blender file handle as returned by
+ * #BLO_blendhandle_from_file or #BLO_blendhandle_from_memory.
+ * \param filepath: Used for relative linking, copied to the `lib->filepath`.
+ * \param params: Settings for linking that don't change from beginning to end of linking.
+ * \return the library #Main, to be passed to #BLO_library_link_named_part as \a mainl.
+ */
struct Main *BLO_library_link_begin(BlendHandle **bh,
const char *filepath,
const struct LibraryLink_Params *params);
+/**
+ * Link a named data-block from an external blend file.
+ *
+ * \param mainl: The main database to link from (not the active one).
+ * \param bh: The blender file handle.
+ * \param idcode: The kind of data-block to link.
+ * \param name: The name of the data-block (without the 2 char ID prefix).
+ * \return the linked ID when found.
+ */
struct ID *BLO_library_link_named_part(struct Main *mainl,
BlendHandle **bh,
- const short idcode,
+ short idcode,
const char *name,
const struct LibraryLink_Params *params);
+/**
+ * Finalize linking from a given .blend file (library).
+ * Optionally instance the indirect object/collection in the scene when the flags are set.
+ * \note Do not use \a bh after calling this function, it may frees it.
+ *
+ * \param mainl: The main database to link from (not the active one).
+ * \param bh: The blender file handle (WARNING! may be freed by this function!).
+ * \param params: Settings for linking that don't change from beginning to end of linking.
+ */
void BLO_library_link_end(struct Main *mainl,
BlendHandle **bh,
const struct LibraryLink_Params *params);
-int BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh, const uint64_t id_types_mask);
-
/**
* Struct for temporarily loading datablocks from a blend file.
*/
@@ -298,7 +437,7 @@ typedef struct TempLibraryContext {
TempLibraryContext *BLO_library_temp_load_id(struct Main *real_main,
const char *blend_file_path,
- const short idcode,
+ short idcode,
const char *idname,
struct ReportList *reports);
void BLO_library_temp_free(TempLibraryContext *temp_lib_ctx);
@@ -308,6 +447,10 @@ void BLO_library_temp_free(TempLibraryContext *temp_lib_ctx);
void *BLO_library_read_struct(struct FileData *fd, struct BHead *bh, const char *blockname);
/* internal function but we need to expose it */
+/**
+ * Used to link a file (without UI) to the current UI.
+ * Note that it assumes the old pointers in UI are still valid, so old Main is not freed.
+ */
void blo_lib_link_restore(struct Main *oldmain,
struct Main *newmain,
struct wmWindowManager *curwm,
@@ -316,19 +459,48 @@ void blo_lib_link_restore(struct Main *oldmain,
typedef void (*BLOExpandDoitCallback)(void *fdhandle, struct Main *mainvar, void *idv);
+/**
+ * Set the callback func used over all ID data found by \a BLO_expand_main func.
+ *
+ * \param expand_doit_func: Called for each ID block it finds.
+ */
void BLO_main_expander(BLOExpandDoitCallback expand_doit_func);
+/**
+ * Loop over all ID data in Main to mark relations.
+ * Set (id->tag & LIB_TAG_NEED_EXPAND) to mark expanding. Flags get cleared after expanding.
+ *
+ * \param fdhandle: usually filedata, or own handle.
+ * \param mainvar: the Main database to expand.
+ */
void BLO_expand_main(void *fdhandle, struct Main *mainvar);
/**
* Update defaults in startup.blend, without having to save and embed it.
* \note defaults for preferences are stored in `userdef_default.c` and can be updated there.
*/
+/**
+ * Update defaults in startup.blend, without having to save and embed the file.
+ * This function can be emptied each time the startup.blend is updated.
+ *
+ * \note Screen data may be cleared at this point, this will happen in the case
+ * an app-template's data needs to be versioned when read-file is called with "Load UI" disabled.
+ * Versioning the screen data can be safely skipped without "Load UI" since the screen data
+ * will have been versioned when it was first loaded.
+ */
void BLO_update_defaults_startup_blend(struct Main *bmain, const char *app_template);
void BLO_update_defaults_workspace(struct WorkSpace *workspace, const char *app_template);
/* Disable unwanted experimental feature settings on startup. */
void BLO_sanitize_experimental_features_userpref_blend(struct UserDef *userdef);
+/**
+ * Does a very light reading of given .blend file to extract its stored thumbnail.
+ *
+ * \param filepath: The path of the file to extract thumbnail from.
+ * \return The raw thumbnail
+ * (MEM-allocated, as stored in file, use #BKE_main_thumbnail_to_imbuf()
+ * to convert it to ImBuf image).
+ */
struct BlendThumbnail *BLO_thumbnail_from_file(const char *filepath);
/* datafiles (generated theme) */
diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h
index 4e240e2462b..0e2c22d7e4d 100644
--- a/source/blender/blenloader/BLO_undofile.h
+++ b/source/blender/blenloader/BLO_undofile.h
@@ -77,7 +77,7 @@ typedef struct {
bool memchunk_identical;
} UndoReader;
-/* actually only used writefile.c */
+/* Actually only used `writefile.c`. */
void BLO_memfile_write_init(MemFileWriteData *mem_data,
MemFile *written_memfile,
@@ -87,14 +87,31 @@ void BLO_memfile_write_finalize(MemFileWriteData *mem_data);
void BLO_memfile_chunk_add(MemFileWriteData *mem_data, const char *buf, size_t size);
/* exports */
+
+/**
+ * Not memfile itself.
+ */
extern void BLO_memfile_free(MemFile *memfile);
+/**
+ * Result is that 'first' is being freed.
+ * to keep list of memfiles consistent, 'first' is always first in list.
+ */
extern void BLO_memfile_merge(MemFile *first, MemFile *second);
+/**
+ * Clear is_identical_future before adding next memfile.
+ */
extern void BLO_memfile_clear_future(MemFile *memfile);
-/* utilities */
+/* Utilities. */
+
extern struct Main *BLO_memfile_main_get(struct MemFile *memfile,
struct Main *bmain,
struct Scene **r_scene);
+/**
+ * Saves .blend using undo buffer.
+ *
+ * \return success.
+ */
extern bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename);
FileReader *BLO_memfile_new_filereader(MemFile *memfile, int undo_direction);
diff --git a/source/blender/blenloader/BLO_writefile.h b/source/blender/blenloader/BLO_writefile.h
index 746c663926d..072f86b48d6 100644
--- a/source/blender/blenloader/BLO_writefile.h
+++ b/source/blender/blenloader/BLO_writefile.h
@@ -21,9 +21,13 @@
/** \file
* \ingroup blenloader
- * \brief external writefile function prototypes.
+ * \brief external `writefile.c` function prototypes.
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct BlendThumbnail;
struct Main;
struct MemFile;
@@ -60,15 +64,25 @@ struct BlendFileWriteParams {
const struct BlendThumbnail *thumb;
};
+/**
+ * \return Success.
+ */
extern bool BLO_write_file(struct Main *mainvar,
const char *filepath,
- const int write_flags,
+ int write_flags,
const struct BlendFileWriteParams *params,
struct ReportList *reports);
+/**
+ * \return Success.
+ */
extern bool BLO_write_file_mem(struct Main *mainvar,
struct MemFile *compare,
struct MemFile *current,
int write_flags);
/** \} */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 89631588ed0..245514d4977 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -26,6 +26,7 @@ set(INC
../blentranslation
../depsgraph
../draw
+ ../editors/include
../imbuf
../makesdna
../makesrna
@@ -113,6 +114,7 @@ if(WITH_GTESTS)
tests/blendfile_loading_base_test.h
)
set(TEST_INC
+ ../../../intern/ghost
)
set(TEST_LIB
bf_blenloader
diff --git a/source/blender/blenloader/intern/blend_validate.c b/source/blender/blenloader/intern/blend_validate.c
index 7d641d976e3..333f6e341c6 100644
--- a/source/blender/blenloader/intern/blend_validate.c
+++ b/source/blender/blenloader/intern/blend_validate.c
@@ -47,10 +47,6 @@
#include "readfile.h"
-/**
- * Check (but do *not* fix) that all linked data-blocks are still valid
- * (i.e. pointing to the right library).
- */
bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
{
ListBase mainlist;
@@ -165,7 +161,6 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
return is_valid;
}
-/** Check (and fix if needed) that shape key's 'from' pointer is valid. */
bool BLO_main_validate_shapekeys(Main *bmain, ReportList *reports)
{
ListBase *lb;
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index 3306eb9e454..f3c92aec338 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -61,13 +61,6 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp);
/* Access routines used by filesel. */
-/**
- * Open a blendhandle from a file path.
- *
- * \param filepath: The file path to open.
- * \param reports: Report errors in opening the file (can be NULL).
- * \return A handle on success, or NULL on failure.
- */
BlendHandle *BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport *reports)
{
BlendHandle *bh;
@@ -77,13 +70,6 @@ BlendHandle *BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport
return bh;
}
-/**
- * Open a blendhandle from memory.
- *
- * \param mem: The data to load from.
- * \param memsize: The size of the data.
- * \return A handle on success, or NULL on failure.
- */
BlendHandle *BLO_blendhandle_from_memory(const void *mem,
int memsize,
BlendFileReadReport *reports)
@@ -130,16 +116,6 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp)
fprintf(fp, "]\n");
}
-/**
- * Gets the names of all the data-blocks in a file of a certain type
- * (e.g. all the scene names in a file).
- *
- * \param bh: The blendhandle to access.
- * \param ofblocktype: The type of names to get.
- * \param tot_names: The length of the returned list.
- * \param use_assets_only: Only list IDs marked as assets.
- * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN().
- */
LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh,
int ofblocktype,
const bool use_assets_only,
@@ -169,17 +145,6 @@ LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh,
return names;
}
-/**
- * Gets the names and asset-data (if ID is an asset) of data-blocks in a file of a certain type.
- * The data-blocks can be limited to assets.
- *
- * \param bh: The blendhandle to access.
- * \param ofblocktype: The type of names to get.
- * \param use_assets_only: Limit the result to assets only.
- * \param tot_info_items: The length of the returned list.
- * \return A BLI_linklist of BLODataBlockInfo *. The links and #BLODataBlockInfo.asset_data should
- * be freed with MEM_freeN.
- */
LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh,
int ofblocktype,
const bool use_assets_only,
@@ -267,15 +232,6 @@ static BHead *blo_blendhandle_read_preview_rects(FileData *fd,
return bhead;
}
-/**
- * Get the PreviewImage of a single data block in a file.
- * (e.g. all the scene previews in a file).
- *
- * \param bh: The blendhandle to access.
- * \param ofblocktype: The type of names to get.
- * \param name: Name of the block without the ID_ prefix, to read the preview image from.
- * \return PreviewImage or NULL when no preview Images have been found. Caller owns the returned
- */
PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh,
int ofblocktype,
const char *name)
@@ -315,15 +271,6 @@ PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh,
return NULL;
}
-/**
- * Gets the previews of all the data-blocks in a file of a certain type
- * (e.g. all the scene previews in a file).
- *
- * \param bh: The blendhandle to access.
- * \param ofblocktype: The type of names to get.
- * \param r_tot_prev: The length of the returned list.
- * \return A BLI_linklist of PreviewImage. The PreviewImage links should be freed with malloc.
- */
LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_tot_prev)
{
FileData *fd = (FileData *)bh;
@@ -347,6 +294,7 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_
case ID_GR: /* fall through */
case ID_SCE: /* fall through */
case ID_AC: /* fall through */
+ case ID_NT: /* fall through */
new_prv = MEM_callocN(sizeof(PreviewImage), "newpreview");
BLI_linklist_prepend(&previews, new_prv);
tot++;
@@ -383,13 +331,6 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_
return previews;
}
-/**
- * Gets the names of all the linkable data-block types available in a file.
- * (e.g. "Scene", "Mesh", "Light", etc.).
- *
- * \param bh: The blendhandle to access.
- * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN().
- */
LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
{
FileData *fd = (FileData *)bh;
@@ -417,11 +358,6 @@ LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
return names;
}
-/**
- * Close and free a blendhandle. The handle becomes invalid after this call.
- *
- * \param bh: The handle to close.
- */
void BLO_blendhandle_close(BlendHandle *bh)
{
FileData *fd = (FileData *)bh;
@@ -431,14 +367,6 @@ void BLO_blendhandle_close(BlendHandle *bh)
/**********/
-/**
- * Open a blender file from a pathname. The function returns NULL
- * and sets a report in the list if it cannot open the file.
- *
- * \param filepath: The path of the file to open.
- * \param reports: If the return value is NULL, errors indicating the cause of the failure.
- * \return The data of the file.
- */
BlendFileData *BLO_read_from_file(const char *filepath,
eBLOReadSkip skip_flags,
BlendFileReadReport *reports)
@@ -456,15 +384,6 @@ BlendFileData *BLO_read_from_file(const char *filepath,
return bfd;
}
-/**
- * Open a blender file from memory. The function returns NULL
- * and sets a report in the list if it cannot open the file.
- *
- * \param mem: The file data.
- * \param memsize: The length of \a mem.
- * \param reports: If the return value is NULL, errors indicating the cause of the failure.
- * \return The data of the file.
- */
BlendFileData *BLO_read_from_memory(const void *mem,
int memsize,
eBLOReadSkip skip_flags,
@@ -484,14 +403,6 @@ BlendFileData *BLO_read_from_memory(const void *mem,
return bfd;
}
-/**
- * Used for undo/redo, skips part of libraries reading
- * (assuming their data are already loaded & valid).
- *
- * \param oldmain: old main,
- * from which we will keep libraries and other data-blocks that should not have changed.
- * \param filename: current file, only for retrieving library data.
- */
BlendFileData *BLO_read_from_memfile(Main *oldmain,
const char *filename,
MemFile *memfile,
@@ -547,12 +458,6 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain,
return bfd;
}
-/**
- * Frees a BlendFileData structure and *all* the data associated with it
- * (the userdef data, and the main libblock data).
- *
- * \param bfd: The structure to free.
- */
void BLO_blendfiledata_free(BlendFileData *bfd)
{
if (bfd->main) {
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index cdae043d01c..38f2d8bb22c 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -195,7 +195,6 @@ static void read_libraries(FileData *basefd, ListBase *mainlist);
static void *read_struct(FileData *fd, BHead *bh, const char *blockname);
static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name);
static BHead *find_bhead_from_idname(FileData *fd, const char *idname);
-static bool library_link_idcode_needs_tag_check(const short idcode, const int flag);
typedef struct BHeadN {
struct BHeadN *next, *prev;
@@ -215,14 +214,7 @@ typedef struct BHeadN {
* because ID names are used in lookup tables. */
#define BHEAD_USE_READ_ON_DEMAND(bhead) ((bhead)->code == DATA)
-/**
- * This function ensures that reports are printed,
- * in the case of library linking errors this is important!
- *
- * bit kludge but better than doubling up on prints,
- * we could alternatively have a versions of a report function which forces printing - campbell
- */
-void BLO_reportf_wrap(BlendFileReadReport *reports, ReportType type, const char *format, ...)
+void BLO_reportf_wrap(BlendFileReadReport *reports, eReportType type, const char *format, ...)
{
char fixed_buf[1024]; /* should be long enough */
@@ -262,7 +254,7 @@ typedef struct OldNewMap {
/* Array that stores the actual entries. */
OldNew *entries;
int nentries;
- /* Hashmap that stores indices into the `entries` array. */
+ /* Hash-map that stores indices into the `entries` array. */
int32_t *map;
int capacity_exp;
@@ -639,7 +631,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab
// printf("blo_find_main: converted to %s\n", name1);
for (m = mainlist->first; m; m = m->next) {
- const char *libname = (m->curlib) ? m->curlib->filepath_abs : m->name;
+ const char *libname = (m->curlib) ? m->curlib->filepath_abs : m->filepath;
if (BLI_path_cmp(name1, libname) == 0) {
if (G.debug & G_DEBUG) {
@@ -998,13 +990,11 @@ static BHead *blo_bhead_read_full(FileData *fd, BHead *thisblock)
}
#endif /* USE_BHEAD_READ_ON_DEMAND */
-/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */
const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead)
{
return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offset);
}
-/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */
AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead)
{
BLI_assert(blo_bhead_is_id_valid_type(bhead));
@@ -1149,6 +1139,10 @@ static int *read_file_thumbnail(FileData *fd)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name File Data API
+ * \{ */
+
static FileData *filedata_new(BlendFileReadReport *reports)
{
BLI_assert(reports != NULL);
@@ -1230,13 +1224,13 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
else if (BLI_file_magic_is_gzip(header)) {
file = BLI_filereader_new_gzip(rawfile);
if (file != NULL) {
- rawfile = NULL; /* The Gzip FileReader takes ownership of `rawfile`. */
+ rawfile = NULL; /* The `Gzip` #FileReader takes ownership of `rawfile`. */
}
}
else if (BLI_file_magic_is_zstd(header)) {
file = BLI_filereader_new_zstd(rawfile);
if (file != NULL) {
- rawfile = NULL; /* The Zstd FileReader takes ownership of `rawfile`. */
+ rawfile = NULL; /* The `Zstd` #FileReader takes ownership of `rawfile`. */
}
}
@@ -1270,8 +1264,6 @@ static FileData *blo_filedata_from_file_open(const char *filepath, BlendFileRead
return blo_filedata_from_file_descriptor(filepath, reports, file);
}
-/* cannot be called with relative paths anymore! */
-/* on each new library added, it now checks for the current FileData and expands relativeness */
FileData *blo_filedata_from_file(const char *filepath, BlendFileReadReport *reports)
{
FileData *fd = blo_filedata_from_file_open(filepath, reports);
@@ -1351,7 +1343,6 @@ FileData *blo_filedata_from_memfile(MemFile *memfile,
void blo_filedata_free(FileData *fd)
{
if (fd) {
- fd->file->close(fd->file);
/* Free all BHeadN data blocks */
#ifndef NDEBUG
@@ -1365,6 +1356,7 @@ void blo_filedata_free(FileData *fd)
MEM_freeN(new_bhead);
}
#endif
+ fd->file->close(fd->file);
if (fd->filesdna) {
DNA_sdna_free(fd->filesdna);
@@ -1412,30 +1404,12 @@ void blo_filedata_free(FileData *fd)
/** \name Public Utilities
* \{ */
-/**
- * Check whether given path ends with a blend file compatible extension
- * (`.blend`, `.ble` or `.blend.gz`).
- *
- * \param str: The path to check.
- * \return true is this path ends with a blender file extension.
- */
bool BLO_has_bfile_extension(const char *str)
{
const char *ext_test[4] = {".blend", ".ble", ".blend.gz", NULL};
return BLI_path_extension_check_array(str, ext_test);
}
-/**
- * Try to explode given path into its 'library components'
- * (i.e. a .blend file, id type/group, and data-block itself).
- *
- * \param path: the full path to explode.
- * \param r_dir: the string that'll contain path up to blend file itself ('library' path).
- * WARNING! Must be #FILE_MAX_LIBEXTRA long (it also stores group and name strings)!
- * \param r_group: the string that'll contain 'group' part of the path, if any. May be NULL.
- * \param r_name: the string that'll contain data's name part of the path, if any. May be NULL.
- * \return true if path contains a blend file.
- */
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
{
/* We might get some data names with slashes,
@@ -1496,14 +1470,6 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha
return true;
}
-/**
- * Does a very light reading of given .blend file to extract its stored thumbnail.
- *
- * \param filepath: The path of the file to extract thumbnail from.
- * \return The raw thumbnail
- * (MEM-allocated, as stored in file, use #BKE_main_thumbnail_to_imbuf()
- * to convert it to ImBuf image).
- */
BlendThumbnail *BLO_thumbnail_from_file(const char *filepath)
{
FileData *fd;
@@ -1552,7 +1518,6 @@ static void *newdataadr_no_us(FileData *fd, const void *adr)
return oldnewmap_lookup_and_inc(fd->datamap, adr, false);
}
-/* Direct datablocks with global linking. */
void *blo_read_get_new_globaldata_address(FileData *fd, const void *adr)
{
return oldnewmap_lookup_and_inc(fd->globmap, adr, true);
@@ -1574,7 +1539,6 @@ static void *newlibadr(FileData *fd, const void *lib, const void *adr)
return oldnewmap_liblookup(fd->libmap, adr, lib);
}
-/* only lib data */
void *blo_do_versions_newlibadr(FileData *fd, const void *lib, const void *adr)
{
return newlibadr(fd, lib, adr);
@@ -1616,12 +1580,6 @@ static void change_link_placeholder_to_real_ID_pointer(ListBase *mainlist,
}
}
-/* lib linked proxy objects point to our local data, we need
- * to clear that pointer before reading the undo memfile since
- * the object might be removed, it is set again in reading
- * if the local object still exists.
- * This is only valid for local proxy objects though, linked ones should not be affected here.
- */
void blo_clear_proxy_pointers_from_lib(Main *oldmain)
{
LISTBASE_FOREACH (Object *, ob, &oldmain->objects) {
@@ -1681,8 +1639,6 @@ void blo_make_packed_pointer_map(FileData *fd, Main *oldmain)
}
}
-/* set old main packed data to zero if it has been restored */
-/* this works because freeing old main only happens after this call */
void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
{
OldNew *entry = fd->packedmap->entries;
@@ -1719,7 +1675,6 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
}
}
-/* undo file support: add all library pointers in lookup */
void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
{
ListBase *lbarray[INDEX_ID_MAX];
@@ -1736,8 +1691,6 @@ void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
fd->old_mainlist = old_mainlist;
}
-/* Build a GSet of old main (we only care about local data here, so we can do that after
- * split_main() call. */
void blo_make_old_idmap_from_main(FileData *fd, Main *bmain)
{
if (fd->old_idmap != NULL) {
@@ -2211,6 +2164,9 @@ static void direct_link_id_common(
if (id->asset_data) {
BLO_read_data_address(reader, &id->asset_data);
BKE_asset_metadata_read(reader, id->asset_data);
+ /* Restore runtime asset type info. */
+ const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
+ id->asset_data->local_type_info = id_type->asset_type_info;
}
/* Link direct data of ID properties. */
@@ -2588,7 +2544,6 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
else if (sl->spacetype == SPACE_FILE) {
SpaceFile *sfile = (SpaceFile *)sl;
sfile->op = NULL;
- sfile->previews_timer = NULL;
sfile->tags = FILE_TAG_REBUILD_MAIN_FILES;
}
else if (sl->spacetype == SPACE_ACTION) {
@@ -2768,10 +2723,6 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
}
}
-/**
- * Used to link a file (without UI) to the current UI.
- * Note that it assumes the old pointers in UI are still valid, so old Main is not freed.
- */
void blo_lib_link_restore(Main *oldmain,
Main *newmain,
wmWindowManager *curwm,
@@ -2900,7 +2851,7 @@ static void lib_link_library(BlendLibReader *UNUSED(reader), Library *UNUSED(lib
* in relation to the blend file. */
static void fix_relpaths_library(const char *basepath, Main *main)
{
- /* BLO_read_from_memory uses a blank filename */
+ /* #BLO_read_from_memory uses a blank file-path. */
if (basepath == NULL || basepath[0] == '\0') {
LISTBASE_FOREACH (Library *, lib, &main->libraries) {
/* when loading a linked lib into a file which has not been saved,
@@ -3554,25 +3505,25 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
bfd->fileflags = fg->fileflags;
bfd->globalf = fg->globalf;
- BLI_strncpy(bfd->filename, fg->filename, sizeof(bfd->filename));
+ STRNCPY(bfd->filepath, fg->filepath);
- /* Error in 2.65 and older: main->name was not set if you save from startup
+ /* Error in 2.65 and older: `main->filepath` was not set if you save from startup
* (not after loading file). */
- if (bfd->filename[0] == 0) {
+ if (bfd->filepath[0] == 0) {
if (fd->fileversion < 265 || (fd->fileversion == 265 && fg->subversion < 1)) {
if ((G.fileflags & G_FILE_RECOVER_READ) == 0) {
- BLI_strncpy(bfd->filename, BKE_main_blendfile_path(bfd->main), sizeof(bfd->filename));
+ STRNCPY(bfd->filepath, BKE_main_blendfile_path(bfd->main));
}
}
- /* early 2.50 version patch - filename not in FileGlobal struct at all */
+ /* early 2.50 version patch - filepath not in FileGlobal struct at all */
if (fd->fileversion <= 250) {
- BLI_strncpy(bfd->filename, BKE_main_blendfile_path(bfd->main), sizeof(bfd->filename));
+ STRNCPY(bfd->filepath, BKE_main_blendfile_path(bfd->main));
}
}
if (G.fileflags & G_FILE_RECOVER_READ) {
- BLI_strncpy(fd->relabase, fg->filename, sizeof(fd->relabase));
+ BLI_strncpy(fd->relabase, fg->filepath, sizeof(fd->relabase));
}
bfd->curscreen = fg->curscreen;
@@ -3668,7 +3619,7 @@ static void do_versions_after_linking(Main *main, ReportList *reports)
CLOG_INFO(&LOG,
2,
"Processing %s (%s), %d.%d",
- main->curlib ? main->curlib->filepath : main->name,
+ main->curlib ? main->curlib->filepath : main->filepath,
main->curlib ? "LIB" : "MAIN",
main->versionfile,
main->subversionfile);
@@ -3906,7 +3857,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) {
BLI_addtail(&mainlist, bfd->main);
fd->mainlist = &mainlist;
- BLI_strncpy(bfd->main->name, filepath, sizeof(bfd->main->name));
+ STRNCPY(bfd->main->filepath, filepath);
}
if (G.background) {
@@ -4027,11 +3978,13 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
* does not always properly handle user counts, and/or that function does not take into
* account old, deprecated data. */
BKE_main_id_refcount_recompute(bfd->main, false);
-
- /* After all data has been read and versioned, uses LIB_TAG_NEW. */
- ntreeUpdateAllNew(bfd->main);
}
+ /* After all data has been read and versioned, uses LIB_TAG_NEW. Theoretically this should
+ * not be calculated in the undo case, but it is currently needed even on undo to recalculate
+ * a cache. */
+ ntreeUpdateAllNew(bfd->main);
+
placeholders_ensure_valid(bfd->main);
BKE_main_id_tag_all(bfd->main, LIB_TAG_NEW, false);
@@ -4379,23 +4332,11 @@ static void expand_id(BlendExpander *expander, ID *id)
expand_id_embedded_id(expander, id);
}
-/**
- * Set the callback func used over all ID data found by \a BLO_expand_main func.
- *
- * \param expand_doit_func: Called for each ID block it finds.
- */
void BLO_main_expander(BLOExpandDoitCallback expand_doit_func)
{
expand_doit = expand_doit_func;
}
-/**
- * Loop over all ID data in Main to mark relations.
- * Set (id->tag & LIB_TAG_NEED_EXPAND) to mark expanding. Flags get cleared after expanding.
- *
- * \param fdhandle: usually filedata, or own handle.
- * \param mainvar: the Main database to expand.
- */
void BLO_expand_main(void *fdhandle, Main *mainvar)
{
ListBase *lbarray[INDEX_ID_MAX];
@@ -4436,267 +4377,6 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
/** \name Library Linking (helper functions)
* \{ */
-static bool object_in_any_scene(Main *bmain, Object *ob)
-{
- LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
- if (BKE_scene_object_find(sce, ob)) {
- return true;
- }
- }
-
- return false;
-}
-
-static bool object_in_any_collection(Main *bmain, Object *ob)
-{
- LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
- if (BKE_collection_has_object(collection, ob)) {
- return true;
- }
- }
-
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- if (scene->master_collection != NULL &&
- BKE_collection_has_object(scene->master_collection, ob)) {
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * Shared operations to perform on the object's base after adding it to the scene.
- */
-static void object_base_instance_init(
- Object *ob, bool set_selected, bool set_active, ViewLayer *view_layer, const View3D *v3d)
-{
- Base *base = BKE_view_layer_base_find(view_layer, ob);
-
- if (v3d != NULL) {
- base->local_view_bits |= v3d->local_view_uuid;
- }
-
- if (set_selected) {
- if (base->flag & BASE_SELECTABLE) {
- base->flag |= BASE_SELECTED;
- }
- }
-
- if (set_active) {
- view_layer->basact = base;
- }
-
- BKE_scene_object_base_flag_sync_from_base(base);
-}
-
-static void add_loose_objects_to_scene(Main *mainvar,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d,
- Library *lib,
- const int flag)
-{
- Collection *active_collection = NULL;
- const bool do_append = (flag & FILE_LINK) == 0;
-
- BLI_assert(scene);
-
- /* Give all objects which are LIB_TAG_INDIRECT a base,
- * or for a collection when *lib has been set. */
- LISTBASE_FOREACH (Object *, ob, &mainvar->objects) {
- bool do_it = (ob->id.tag & LIB_TAG_DOIT) != 0;
- if (do_it ||
- ((ob->id.tag & LIB_TAG_INDIRECT) != 0 && (ob->id.tag & LIB_TAG_PRE_EXISTING) == 0)) {
- if (do_append) {
- if (ob->id.us == 0) {
- do_it = true;
- }
- else if ((ob->id.lib == lib) && !object_in_any_collection(bmain, ob)) {
- /* When appending, make sure any indirectly loaded object gets a base,
- * when they are not part of any collection yet. */
- do_it = true;
- }
- }
-
- if (do_it) {
- /* Find or add collection as needed. */
- if (active_collection == NULL) {
- if (flag & FILE_ACTIVE_COLLECTION) {
- LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
- active_collection = lc->collection;
- }
- else {
- active_collection = BKE_collection_add(bmain, scene->master_collection, NULL);
- }
- }
-
- CLAMP_MIN(ob->id.us, 0);
- ob->mode = OB_MODE_OBJECT;
-
- BKE_collection_object_add(bmain, active_collection, ob);
-
- const bool set_selected = (flag & FILE_AUTOSELECT) != 0;
- /* Do NOT make base active here! screws up GUI stuff,
- * if you want it do it at the editor level. */
- const bool set_active = false;
- object_base_instance_init(ob, set_selected, set_active, view_layer, v3d);
-
- ob->id.tag &= ~LIB_TAG_INDIRECT;
- ob->id.flag &= ~LIB_INDIRECT_WEAK_LINK;
- ob->id.tag |= LIB_TAG_EXTERN;
- }
- }
- }
-}
-
-static void add_loose_object_data_to_scene(Main *mainvar,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d,
- const int flag)
-{
- if ((flag & BLO_LIBLINK_OBDATA_INSTANCE) == 0) {
- return;
- }
-
- Collection *active_collection = scene->master_collection;
- if (flag & FILE_ACTIVE_COLLECTION) {
- LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
- active_collection = lc->collection;
- }
-
- /* Do not re-instantiate obdata IDs that are already instantiated by an object. */
- LISTBASE_FOREACH (Object *, ob, &mainvar->objects) {
- if ((ob->id.tag & LIB_TAG_PRE_EXISTING) == 0 && ob->data != NULL) {
- ID *obdata = ob->data;
- BLI_assert(ID_REAL_USERS(obdata) > 0);
- if ((obdata->tag & LIB_TAG_PRE_EXISTING) == 0) {
- obdata->tag &= ~LIB_TAG_DOIT;
- }
- }
- }
-
- /* Loop over all ID types, instancing object-data for ID types that have support for it. */
- ListBase *lbarray[INDEX_ID_MAX];
- int i = set_listbasepointers(mainvar, lbarray);
- while (i--) {
- const short idcode = BKE_idtype_idcode_from_index(i);
- if (!OB_DATA_SUPPORT_ID(idcode)) {
- continue;
- }
-
- LISTBASE_FOREACH (ID *, id, lbarray[i]) {
- if (id->tag & LIB_TAG_DOIT) {
- const int type = BKE_object_obdata_to_type(id);
- BLI_assert(type != -1);
- Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2);
- ob->data = id;
- id_us_plus(id);
- BKE_object_materials_test(bmain, ob, ob->data);
-
- BKE_collection_object_add(bmain, active_collection, ob);
-
- const bool set_selected = (flag & FILE_AUTOSELECT) != 0;
- /* Do NOT make base active here! screws up GUI stuff,
- * if you want it do it at the editor level. */
- bool set_active = false;
- object_base_instance_init(ob, set_selected, set_active, view_layer, v3d);
-
- copy_v3_v3(ob->loc, scene->cursor.location);
- }
- }
- }
-}
-
-static void add_collections_to_scene(Main *mainvar,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d,
- Library *lib,
- const int flag)
-{
- Collection *active_collection = scene->master_collection;
- if (flag & FILE_ACTIVE_COLLECTION) {
- LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
- active_collection = lc->collection;
- }
-
- /* Give all objects which are tagged a base. */
- LISTBASE_FOREACH (Collection *, collection, &mainvar->collections) {
- if ((flag & BLO_LIBLINK_COLLECTION_INSTANCE) && (collection->id.tag & LIB_TAG_DOIT)) {
- /* Any indirect collection should not have been tagged. */
- BLI_assert((collection->id.tag & LIB_TAG_INDIRECT) == 0);
-
- /* BKE_object_add(...) messes with the selection. */
- Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2);
- ob->type = OB_EMPTY;
- ob->empty_drawsize = U.collection_instance_empty_size;
-
- BKE_collection_object_add(bmain, active_collection, ob);
-
- const bool set_selected = (flag & FILE_AUTOSELECT) != 0;
- /* TODO: why is it OK to make this active here but not in other situations?
- * See other callers of #object_base_instance_init */
- const bool set_active = set_selected;
- object_base_instance_init(ob, set_selected, set_active, view_layer, v3d);
-
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
-
- /* Assign the collection. */
- ob->instance_collection = collection;
- id_us_plus(&collection->id);
- ob->transflag |= OB_DUPLICOLLECTION;
- copy_v3_v3(ob->loc, scene->cursor.location);
- }
- /* We do not want to force instantiation of indirectly linked collections,
- * not even when appending. Users can now easily instantiate collections (and their objects)
- * as needed by themselves. See T67032. */
- else if ((collection->id.tag & LIB_TAG_INDIRECT) == 0) {
- bool do_add_collection = (collection->id.tag & LIB_TAG_DOIT) != 0;
- if (!do_add_collection) {
- /* We need to check that objects in that collections are already instantiated in a scene.
- * Otherwise, it's better to add the collection to the scene's active collection, than to
- * instantiate its objects in active scene's collection directly. See T61141.
- * Note that we only check object directly into that collection,
- * not recursively into its children.
- */
- LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
- Object *ob = coll_ob->ob;
- if ((ob->id.tag & (LIB_TAG_PRE_EXISTING | LIB_TAG_DOIT | LIB_TAG_INDIRECT)) == 0 &&
- (ob->id.lib == lib) && (object_in_any_scene(bmain, ob) == false)) {
- do_add_collection = true;
- break;
- }
- }
- }
- if (do_add_collection) {
- /* Add collection as child of active collection. */
- BKE_collection_child_add(bmain, active_collection, collection);
-
- if (flag & FILE_AUTOSELECT) {
- LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
- Object *ob = coll_ob->ob;
- Base *base = BKE_view_layer_base_find(view_layer, ob);
- if (base) {
- base->flag |= BASE_SELECTED;
- BKE_scene_object_base_flag_sync_from_base(base);
- }
- }
- }
-
- /* Those are kept for safety and consistency, but should not be needed anymore? */
- collection->id.tag &= ~LIB_TAG_INDIRECT;
- collection->id.flag &= ~LIB_INDIRECT_WEAK_LINK;
- collection->id.tag |= LIB_TAG_EXTERN;
- }
- }
- }
-}
-
/* returns true if the item was found
* but it may already have already been appended/linked */
static ID *link_named_part(
@@ -4746,68 +4426,9 @@ static ID *link_named_part(
/* if we found the id but the id is NULL, this is really bad */
BLI_assert(!((bhead != NULL) && (id == NULL)));
- /* Tag as loose object (or data associated with objects)
- * needing to be instantiated in #LibraryLink_Params.scene. */
- if ((id != NULL) && (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT)) {
- if (library_link_idcode_needs_tag_check(idcode, flag)) {
- id->tag |= LIB_TAG_DOIT;
- }
- }
-
return id;
}
-/**
- * Simple reader for copy/paste buffers.
- */
-int BLO_library_link_copypaste(Main *mainl, BlendHandle *bh, const uint64_t id_types_mask)
-{
- FileData *fd = (FileData *)(bh);
- BHead *bhead;
- int num_directly_linked = 0;
-
- for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
- ID *id = NULL;
-
- if (bhead->code == ENDB) {
- break;
- }
-
- if (blo_bhead_is_id_valid_type(bhead) && BKE_idtype_idcode_is_linkable((short)bhead->code) &&
- (id_types_mask == 0 ||
- (BKE_idtype_idcode_to_idfilter((short)bhead->code) & id_types_mask) != 0)) {
- read_libblock(fd, mainl, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, &id);
- num_directly_linked++;
- }
-
- if (id) {
- /* sort by name in list */
- ListBase *lb = which_libbase(mainl, GS(id->name));
- id_sort_by_name(lb, id, NULL);
-
- if (bhead->code == ID_OB) {
- /* Instead of instancing Base's directly, postpone until after collections are loaded
- * otherwise the base's flag is set incorrectly when collections are used */
- Object *ob = (Object *)id;
- ob->mode = OB_MODE_OBJECT;
- /* ensure add_loose_objects_to_scene runs on this object */
- BLI_assert(id->us == 0);
- }
- }
- }
-
- return num_directly_linked;
-}
-
-/**
- * Link a named data-block from an external blend file.
- *
- * \param mainl: The main database to link from (not the active one).
- * \param bh: The blender file handle.
- * \param idcode: The kind of data-block to link.
- * \param name: The name of the data-block (without the 2 char ID prefix).
- * \return the linked ID when found.
- */
ID *BLO_library_link_named_part(Main *mainl,
BlendHandle **bh,
const short idcode,
@@ -4820,41 +4441,10 @@ ID *BLO_library_link_named_part(Main *mainl,
/* common routine to append/link something from a library */
-/**
- * Checks if the \a idcode needs to be tagged with #LIB_TAG_DOIT when linking/appending.
- */
-static bool library_link_idcode_needs_tag_check(const short idcode, const int flag)
-{
- if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
- /* Always true because of #add_loose_objects_to_scene & #add_collections_to_scene. */
- if (ELEM(idcode, ID_OB, ID_GR)) {
- return true;
- }
- if (flag & BLO_LIBLINK_OBDATA_INSTANCE) {
- if (OB_DATA_SUPPORT_ID(idcode)) {
- return true;
- }
- }
- }
- return false;
-}
-
-/**
- * Clears #LIB_TAG_DOIT based on the result of #library_link_idcode_needs_tag_check.
- */
-static void library_link_clear_tag(Main *mainvar, const int flag)
-{
- for (int i = 0; i < INDEX_ID_MAX; i++) {
- const short idcode = BKE_idtype_idcode_from_index(i);
- BLI_assert(idcode != -1);
- if (library_link_idcode_needs_tag_check(idcode, flag)) {
- BKE_main_id_tag_idcode(mainvar, idcode, LIB_TAG_DOIT, false);
- }
- }
-}
-
-static Main *library_link_begin(
- Main *mainvar, FileData **fd, const char *filepath, const int flag, const int id_tag_extra)
+static Main *library_link_begin(Main *mainvar,
+ FileData **fd,
+ const char *filepath,
+ const int id_tag_extra)
{
Main *mainl;
@@ -4867,11 +4457,6 @@ static Main *library_link_begin(
(*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist");
- if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
- /* Clear for objects and collections instantiating tag. */
- library_link_clear_tag(mainvar, flag);
- }
-
/* make mains */
blo_split_main((*fd)->mainlist, mainvar);
@@ -4910,30 +4495,18 @@ void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params
{
BLO_library_link_params_init(params, bmain, flag, id_tag_extra);
if (scene != NULL) {
- /* Tagging is needed for instancing. */
- params->flag |= BLO_LIBLINK_NEEDS_ID_TAG_DOIT;
-
params->context.scene = scene;
params->context.view_layer = view_layer;
params->context.v3d = v3d;
}
}
-/**
- * Initialize the #BlendHandle for linking library data.
- *
- * \param bh: A blender file handle as returned by
- * #BLO_blendhandle_from_file or #BLO_blendhandle_from_memory.
- * \param filepath: Used for relative linking, copied to the `lib->filepath`.
- * \param params: Settings for linking that don't change from beginning to end of linking.
- * \return the library #Main, to be passed to #BLO_library_link_named_part as \a mainl.
- */
Main *BLO_library_link_begin(BlendHandle **bh,
const char *filepath,
const struct LibraryLink_Params *params)
{
FileData *fd = (FileData *)(*bh);
- return library_link_begin(params->bmain, &fd, filepath, params->flag, params->id_tag_extra);
+ return library_link_begin(params->bmain, &fd, filepath, params->id_tag_extra);
}
static void split_main_newid(Main *mainptr, Main *main_newid)
@@ -4941,7 +4514,7 @@ static void split_main_newid(Main *mainptr, Main *main_newid)
/* We only copy the necessary subset of data in this temp main. */
main_newid->versionfile = mainptr->versionfile;
main_newid->subversionfile = mainptr->subversionfile;
- BLI_strncpy(main_newid->name, mainptr->name, sizeof(main_newid->name));
+ STRNCPY(main_newid->filepath, mainptr->filepath);
main_newid->curlib = mainptr->curlib;
ListBase *lbarray[INDEX_ID_MAX];
@@ -4960,19 +4533,7 @@ static void split_main_newid(Main *mainptr, Main *main_newid)
}
}
-/**
- * \param scene: The scene in which to instantiate objects/collections
- * (if NULL, no instantiation is done).
- * \param v3d: The active 3D viewport.
- * (only to define active layers for instantiated objects & collections, can be NULL).
- */
-static void library_link_end(Main *mainl,
- FileData **fd,
- Main *bmain,
- const int flag,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d)
+static void library_link_end(Main *mainl, FileData **fd, const int flag)
{
Main *mainvar;
Library *curlib;
@@ -5030,7 +4591,6 @@ static void library_link_end(Main *mainl,
add_main_to_main(mainvar, main_newid);
}
- BKE_main_free(main_newid);
blo_join_main((*fd)->mainlist);
mainvar = (*fd)->mainlist->first;
MEM_freeN((*fd)->mainlist);
@@ -5044,27 +4604,20 @@ static void library_link_end(Main *mainl,
placeholders_ensure_valid(mainvar);
+ /* Apply overrides of newly linked data if needed. Already existing IDs need to split out, to
+ * avoid re-applying their own overrides. */
+ BLI_assert(BKE_main_is_empty(main_newid));
+ split_main_newid(mainvar, main_newid);
+ BKE_lib_override_library_main_validate(main_newid, (*fd)->reports->reports);
+ BKE_lib_override_library_main_update(main_newid);
+ add_main_to_main(mainvar, main_newid);
+ BKE_main_free(main_newid);
+
BKE_main_id_tag_all(mainvar, LIB_TAG_NEW, false);
/* Make all relative paths, relative to the open blend file. */
fix_relpaths_library(BKE_main_blendfile_path(mainvar), mainvar);
- /* Give a base to loose objects and collections.
- * Only directly linked objects & collections are instantiated by
- * #BLO_library_link_named_part & co,
- * here we handle indirect ones and other possible edge-cases. */
- if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
- /* Should always be true. */
- if (scene != NULL) {
- add_collections_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag);
- add_loose_objects_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag);
- add_loose_object_data_to_scene(mainvar, bmain, scene, view_layer, v3d, flag);
- }
-
- /* Clear objects and collections instantiating tag. */
- library_link_clear_tag(mainvar, flag);
- }
-
/* patch to prevent switch_endian happens twice */
if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) {
blo_filedata_free(*fd);
@@ -5072,25 +4625,10 @@ static void library_link_end(Main *mainl,
}
}
-/**
- * Finalize linking from a given .blend file (library).
- * Optionally instance the indirect object/collection in the scene when the flags are set.
- * \note Do not use \a bh after calling this function, it may frees it.
- *
- * \param mainl: The main database to link from (not the active one).
- * \param bh: The blender file handle (WARNING! may be freed by this function!).
- * \param params: Settings for linking that don't change from beginning to end of linking.
- */
void BLO_library_link_end(Main *mainl, BlendHandle **bh, const struct LibraryLink_Params *params)
{
FileData *fd = (FileData *)(*bh);
- library_link_end(mainl,
- &fd,
- params->bmain,
- params->flag,
- params->context.scene,
- params->context.view_layer,
- params->context.v3d);
+ library_link_end(mainl, &fd, params->flag);
*bh = (BlendHandle *)fd;
}
@@ -5442,11 +4980,6 @@ bool BLO_read_requires_endian_switch(BlendDataReader *reader)
return (reader->fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
}
-/**
- * Updates all ->prev and ->next pointers of the list elements.
- * Updates the list->first and list->last pointers.
- * When not NULL, calls the callback on every element.
- */
void BLO_read_list_cb(BlendDataReader *reader, ListBase *list, BlendReadListFn callback)
{
if (BLI_listbase_is_empty(list)) {
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index beeed8e45ae..21b0354b097 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -31,7 +31,7 @@
#include "BLI_filereader.h"
#include "DNA_sdna_types.h"
#include "DNA_space_types.h"
-#include "DNA_windowmanager_types.h" /* for ReportType */
+#include "DNA_windowmanager_types.h" /* for eReportType */
struct BLI_mmap_file;
struct BLOCacheStorage;
@@ -131,6 +131,11 @@ void blo_split_main(ListBase *mainlist, struct Main *main);
BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath);
+/**
+ * On each new library added, it now checks for the current #FileData and expands relativeness
+ *
+ * cannot be called with relative paths anymore!
+ */
FileData *blo_filedata_from_file(const char *filepath, struct BlendFileReadReport *reports);
FileData *blo_filedata_from_memory(const void *mem,
int memsize,
@@ -139,10 +144,28 @@ FileData *blo_filedata_from_memfile(struct MemFile *memfile,
const struct BlendFileReadParams *params,
struct BlendFileReadReport *reports);
+/**
+ * Lib linked proxy objects point to our local data, we need
+ * to clear that pointer before reading the undo memfile since
+ * the object might be removed, it is set again in reading
+ * if the local object still exists.
+ * This is only valid for local proxy objects though, linked ones should not be affected here.
+ */
void blo_clear_proxy_pointers_from_lib(struct Main *oldmain);
void blo_make_packed_pointer_map(FileData *fd, struct Main *oldmain);
+/**
+ * Set old main packed data to zero if it has been restored
+ * this works because freeing old main only happens after this call.
+ */
void blo_end_packed_pointer_map(FileData *fd, struct Main *oldmain);
+/**
+ * Undo file support: add all library pointers in lookup.
+ */
void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd);
+/**
+ * Build a #GSet of old main (we only care about local data here,
+ * so we can do that after #blo_split_main() call.
+ */
void blo_make_old_idmap_from_main(FileData *fd, struct Main *bmain);
BHead *blo_read_asset_data_block(FileData *fd, BHead *bhead, struct AssetMetaData **r_asset_data);
@@ -157,23 +180,48 @@ BHead *blo_bhead_first(FileData *fd);
BHead *blo_bhead_next(FileData *fd, BHead *thisblock);
BHead *blo_bhead_prev(FileData *fd, BHead *thisblock);
+/**
+ * Warning! Caller's responsibility to ensure given bhead **is** an ID one!
+ */
const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead);
+/**
+ * Warning! Caller's responsibility to ensure given bhead **is** an ID one!
+ */
struct AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead);
/* do versions stuff */
-void blo_do_versions_dna(struct SDNA *sdna, const int versionfile, const int subversionfile);
+/**
+ * Manipulates SDNA before calling #DNA_struct_get_compareflags,
+ * allowing us to rename structs and struct members.
+ *
+ * - This means older versions of Blender won't have access to this data **USE WITH CARE**.
+ * - These changes are applied on file load (run-time), similar to versioning for compatibility.
+ *
+ * \attention ONLY USE THIS KIND OF VERSIONING WHEN `dna_rename_defs.h` ISN'T SUFFICIENT.
+ */
+void blo_do_versions_dna(struct SDNA *sdna, int versionfile, int subversionfile);
void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm,
const void *oldaddr,
void *newaddr,
int nr);
+/**
+ * Only library data.
+ */
void *blo_do_versions_newlibadr(struct FileData *fd, const void *lib, const void *adr);
void *blo_do_versions_newlibadr_us(struct FileData *fd, const void *lib, const void *adr);
+/**
+ * \note this version patch is intended for versions < 2.52.2,
+ * but was initially introduced in 2.27 already.
+ */
void blo_do_version_old_trackto_to_constraints(struct Object *ob);
void blo_do_versions_key_uidgen(struct Key *key);
+/**
+ * Patching #UserDef struct and Themes.
+ */
void blo_do_versions_userdef(struct UserDef *userdef);
void blo_do_versions_pre250(struct FileData *fd, struct Library *lib, struct Main *bmain);
@@ -193,6 +241,10 @@ void do_versions_after_linking_290(struct Main *bmain, struct ReportList *report
void do_versions_after_linking_300(struct Main *bmain, struct ReportList *reports);
void do_versions_after_linking_cycles(struct Main *bmain);
-/* This is rather unfortunate to have to expose this here, but better use that nasty hack in
- * do_version than readfile itself. */
+/**
+ * Direct data-blocks with global linking.
+ *
+ * \note This is rather unfortunate to have to expose this here,
+ * but better use that nasty hack in do_version than readfile itself.
+ */
void *blo_read_get_new_globaldata_address(struct FileData *fd, const void *adr);
diff --git a/source/blender/blenloader/intern/readfile_tempload.c b/source/blender/blenloader/intern/readfile_tempload.c
index 1b1cbb29ef5..311732adf99 100644
--- a/source/blender/blenloader/intern/readfile_tempload.c
+++ b/source/blender/blenloader/intern/readfile_tempload.c
@@ -39,7 +39,7 @@ TempLibraryContext *BLO_library_temp_load_id(struct Main *real_main,
temp_lib_ctx->bf_reports.reports = reports;
/* Copy the file path so any path remapping is performed properly. */
- STRNCPY(temp_lib_ctx->bmain_base->name, real_main->name);
+ STRNCPY(temp_lib_ctx->bmain_base->filepath, real_main->filepath);
temp_lib_ctx->blendhandle = BLO_blendhandle_from_file(blend_file_path,
&temp_lib_ctx->bf_reports);
diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c
index 62072cf7df5..dfa6135dac9 100644
--- a/source/blender/blenloader/intern/undofile.c
+++ b/source/blender/blenloader/intern/undofile.c
@@ -55,7 +55,6 @@
/* **************** support for memory-write, for undo buffers *************** */
-/* not memfile itself */
void BLO_memfile_free(MemFile *memfile)
{
MemFileChunk *chunk;
@@ -69,8 +68,6 @@ void BLO_memfile_free(MemFile *memfile)
memfile->size = 0;
}
-/* to keep list of memfiles consistent, 'first' is always first in list */
-/* result is that 'first' is being freed */
void BLO_memfile_merge(MemFile *first, MemFile *second)
{
/* We use this mapping to store the memory buffers from second memfile chunks which are not owned
@@ -106,7 +103,6 @@ void BLO_memfile_merge(MemFile *first, MemFile *second)
BLO_memfile_free(first);
}
-/* Clear is_identical_future before adding next memfile. */
void BLO_memfile_clear_future(MemFile *memfile)
{
LISTBASE_FOREACH (MemFileChunk *, chunk, &memfile->chunks) {
@@ -216,11 +212,6 @@ struct Main *BLO_memfile_main_get(struct MemFile *memfile,
return bmain_undo;
}
-/**
- * Saves .blend using undo buffer.
- *
- * \return success.
- */
bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename)
{
MemFileChunk *chunk;
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 54e673b51eb..52737950ea3 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -70,6 +70,7 @@
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
+#include "BKE_node_tree_update.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_screen.h"
@@ -579,7 +580,6 @@ static bNodeSocket *do_versions_node_group_add_socket_2_56_2(bNodeTree *ngroup,
gsock->type = type;
gsock->next = gsock->prev = NULL;
- gsock->new_sock = NULL;
gsock->link = NULL;
/* assign new unique index */
gsock->own_index = ngroup->cur_index++;
@@ -590,7 +590,7 @@ static bNodeSocket *do_versions_node_group_add_socket_2_56_2(bNodeTree *ngroup,
BLI_addtail(in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs, gsock);
- ngroup->update |= (in_out == SOCK_IN ? NTREE_UPDATE_GROUP_IN : NTREE_UPDATE_GROUP_OUT);
+ BKE_ntree_update_tag_interface(ngroup);
return gsock;
}
@@ -856,10 +856,9 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
if (!ts->uv_selectmode || ts->vgroup_weight == 0.0f) {
ts->selectmode = SCE_SELECT_VERTEX;
- /* autokeying - setting should be taken from the user-prefs
- * but the userprefs version may not have correct flags set
- * (i.e. will result in blank box when enabled)
- */
+ /* The auto-keying setting should be taken from the user-preferences
+ * but the user-preferences version may not have correct flags set
+ * (i.e. will result in blank box when enabled). */
ts->autokey_mode = U.autokey_mode;
if (ts->autokey_mode == 0) {
ts->autokey_mode = 2; /* 'add/replace' but not on */
@@ -1004,7 +1003,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
int a, tot;
/* shape keys are no longer applied to the mesh itself, but rather
- * to the derivedmesh/displist, so here we ensure that the basis
+ * to the evaluated #Mesh / #DispList, so here we ensure that the basis
* shape key is always set in the mesh coordinates. */
for (me = bmain->meshes.first; me; me = me->id.next) {
if ((key = blo_do_versions_newlibadr(fd, lib, me->key)) && key->refkey) {
@@ -2019,7 +2018,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
link->fromsock = gsock;
link->tonode = node;
link->tosock = sock;
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_added(ntree, link);
sock->link = link;
}
@@ -2042,7 +2041,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
link->fromsock = sock;
link->tonode = NULL;
link->tosock = gsock;
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_added(ntree, link);
gsock->link = link;
}
@@ -2282,7 +2281,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
do_versions_socket_default_value_259(sock);
}
- ntree->update |= NTREE_UPDATE;
+ BKE_ntree_update_tag_all(ntree);
}
FOREACH_NODETREE_END;
}
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 55252210a78..c34b8f735e5 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -78,6 +78,7 @@
#include "IMB_imbuf.h" /* for proxy / time-code versioning stuff. */
#include "NOD_common.h"
+#include "NOD_composite.h"
#include "NOD_texture.h"
#include "BLO_readfile.h"
@@ -1384,7 +1385,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
tex->iuser.frames = 1;
tex->iuser.sfra = 1;
- tex->iuser.ok = 1;
}
}
}
@@ -1893,7 +1893,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->flag & (CU_FRONT | CU_BACK)) {
- if (cu->ext1 != 0.0f || cu->ext2 != 0.0f) {
+ if (cu->extrude != 0.0f || cu->bevel_radius != 0.0f) {
Nurb *nu;
for (nu = cu->nurb.first; nu; nu = nu->next) {
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index d226e942d61..8d478b1e1c1 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -88,6 +88,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_paint.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
@@ -401,6 +402,8 @@ static void do_version_scene_collection_to_collection(Main *bmain, Scene *scene)
do_version_layer_collection_pre(
view_layer, &view_layer->layer_collections, enabled_set, selectable_set);
+ BKE_layer_collection_doversion_2_80(scene, view_layer);
+
BKE_layer_collection_sync(scene, view_layer);
do_version_layer_collection_post(
@@ -896,7 +899,7 @@ static void do_versions_material_convert_legacy_blend_mode(bNodeTree *ntree, cha
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1717,18 +1720,8 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
}
}
- /**
- * Versioning code until next subversion bump goes here.
- *
- * \note Be sure to check when bumping the version:
- * - #blo_do_versions_280 in this file.
- * - "versioning_userdef.c", #blo_do_versions_userdef
- * - "versioning_userdef.c", #do_versions_theme
- *
- * \note Keep this message at the bottom of the function.
- */
- {
- /* Keep this block, even when empty. */
+ /* Old forgotten versioning code. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 39)) {
/* Paint Brush. This ensure that the brush paints by default. Used during the development and
* patch review of the initial Sculpt Vertex Colors implementation (D5975) */
LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
@@ -1748,6 +1741,20 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
}
}
}
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - #blo_do_versions_280 in this file.
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
+ }
}
/* NOTE: This version patch is intended for versions < 2.52.2,
@@ -3717,7 +3724,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
STRNCPY(node->idname, "ShaderNodeOutputLight");
}
if (node->type == SH_NODE_BSDF_PRINCIPLED && node->custom2 == 0) {
- node->custom2 = SHD_SUBSURFACE_DIFFUSION;
+ node->custom2 = SHD_SUBSURFACE_BURLEY;
}
}
}
@@ -4512,7 +4519,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "Image", "ListBase", "tiles")) {
for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
ImageTile *tile = MEM_callocN(sizeof(ImageTile), "Image Tile");
- tile->ok = 1;
tile->tile_number = 1001;
BLI_addtail(&ima->tiles, tile);
}
@@ -5065,17 +5071,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /**
- * Versioning code until next subversion bump goes here.
- *
- * \note Be sure to check when bumping the version:
- * - #do_versions_after_linking_280 in this file.
- * - "versioning_userdef.c", #blo_do_versions_userdef
- * - "versioning_userdef.c", #do_versions_theme
- *
- * \note Keep this message at the bottom of the function.
- */
- {
+ /* Old forgotten versioning code. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 39)) {
/* Set the cloth wind factor to 1 for old forces. */
if (!DNA_struct_elem_find(fd->filesdna, "PartDeflect", "float", "f_wind_factor")) {
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
@@ -5095,10 +5092,22 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
/* Don't rotate light with the viewer by default, make it fixed. Shading settings can't be
- * edited and this flag should always be set. So we can always execute this. */
+ * edited and this flag should always be set. */
wm->xr.session_settings.shading.flag |= V3D_SHADING_WORLD_ORIENTATION;
}
+ }
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - #do_versions_after_linking_280 in this file.
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
/* Keep this block, even when empty. */
}
}
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 9f790d262ec..e158838008b 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -606,34 +606,8 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports))
*
* To play safe we move all the inputs beyond 18 to their rightful new place.
* In case users are doing unexpected things with not-really supported keyframeable channels.
- *
- * The for loop for the input ids is at the top level otherwise we lose the animation
- * keyframe data.
*/
- for (int input_id = 21; input_id >= 18; input_id--) {
- FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- if (ntree->type == NTREE_SHADER) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type != SH_NODE_BSDF_PRINCIPLED) {
- continue;
- }
-
- const size_t node_name_length = strlen(node->name);
- const size_t node_name_escaped_max_length = (node_name_length * 2);
- char *node_name_escaped = MEM_mallocN(node_name_escaped_max_length + 1,
- "escaped name");
- BLI_str_escape(node_name_escaped, node->name, node_name_escaped_max_length);
- char *rna_path_prefix = BLI_sprintfN("nodes[\"%s\"].inputs", node_name_escaped);
-
- BKE_animdata_fix_paths_rename_all_ex(
- bmain, id, rna_path_prefix, NULL, NULL, input_id, input_id + 1, false);
- MEM_freeN(rna_path_prefix);
- MEM_freeN(node_name_escaped);
- }
- }
- }
- FOREACH_NODETREE_END;
- }
+ version_node_socket_index_animdata(bmain, NTREE_SHADER, SH_NODE_BSDF_PRINCIPLED, 18, 1, 22);
}
/* Convert all Multires displacement to Catmull-Clark subdivision limit surface. */
@@ -1462,6 +1436,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
view_layer->cryptomatte_levels = 6;
+ view_layer->cryptomatte_flag = VIEW_LAYER_CRYPTOMATTE_ACCURATE;
}
}
}
@@ -1651,8 +1626,8 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 293, 1)) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_GEOMETRY) {
- version_node_socket_name(ntree, GEO_NODE_BOOLEAN, "Geometry A", "Geometry 1");
- version_node_socket_name(ntree, GEO_NODE_BOOLEAN, "Geometry B", "Geometry 2");
+ version_node_socket_name(ntree, GEO_NODE_MESH_BOOLEAN, "Geometry A", "Geometry 1");
+ version_node_socket_name(ntree, GEO_NODE_MESH_BOOLEAN, "Geometry B", "Geometry 2");
}
}
FOREACH_NODETREE_END;
@@ -1986,7 +1961,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 293, 18)) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_GEOMETRY) {
- version_node_socket_name(ntree, GEO_NODE_VOLUME_TO_MESH, "Grid", "Density");
+ version_node_socket_name(ntree, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Grid", "Density");
}
}
FOREACH_NODETREE_END;
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index e65fd3e6754..81fc6086951 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -22,12 +22,15 @@
#include <string.h>
+#include "CLG_log.h"
+
#include "MEM_guardedalloc.h"
#include "BLI_listbase.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 "DNA_anim_types.h"
@@ -42,19 +45,26 @@
#include "DNA_listBase.h"
#include "DNA_material_types.h"
#include "DNA_modifier_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "DNA_text_types.h"
#include "DNA_workspace_types.h"
#include "BKE_action.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
+#include "BKE_armature.h"
#include "BKE_asset.h"
#include "BKE_collection.h"
#include "BKE_deform.h"
#include "BKE_fcurve.h"
#include "BKE_fcurve_driver.h"
#include "BKE_idprop.h"
+#include "BKE_image.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_override.h"
#include "BKE_main.h"
+#include "BKE_modifier.h"
#include "BKE_node.h"
#include "RNA_access.h"
@@ -66,11 +76,14 @@
#include "SEQ_iterator.h"
#include "SEQ_sequencer.h"
+#include "SEQ_time.h"
#include "RNA_access.h"
#include "versioning_common.h"
+static CLG_LogRef LOG = {"blo.readfile.doversion"};
+
static IDProperty *idproperty_find_ui_container(IDProperty *idprop_group)
{
LISTBASE_FOREACH (IDProperty *, prop, &idprop_group->data.group) {
@@ -153,18 +166,18 @@ static void version_idproperty_move_data_float(IDPropertyUIDataFloat *ui_data,
IDProperty *default_value = IDP_GetPropertyFromGroup(prop_ui_data, "default");
if (default_value != NULL) {
if (default_value->type == IDP_ARRAY) {
- const int size = default_value->len;
- ui_data->default_array_len = size;
+ const int array_len = default_value->len;
+ ui_data->default_array_len = array_len;
if (default_value->subtype == IDP_FLOAT) {
- ui_data->default_array = MEM_malloc_arrayN(size, sizeof(double), __func__);
+ ui_data->default_array = MEM_malloc_arrayN(array_len, sizeof(double), __func__);
const float *old_default_array = IDP_Array(default_value);
for (int i = 0; i < ui_data->default_array_len; i++) {
ui_data->default_array[i] = (double)old_default_array[i];
}
}
else if (default_value->subtype == IDP_DOUBLE) {
- ui_data->default_array = MEM_malloc_arrayN(size, sizeof(double), __func__);
- memcpy(ui_data->default_array, IDP_Array(default_value), sizeof(double) * size);
+ ui_data->default_array = MEM_malloc_arrayN(array_len, sizeof(double), __func__);
+ memcpy(ui_data->default_array, IDP_Array(default_value), sizeof(double) * array_len);
}
}
else if (ELEM(default_value->type, IDP_DOUBLE, IDP_FLOAT)) {
@@ -376,6 +389,7 @@ static void move_vertex_group_names_to_object_data(Main *bmain)
/* Clear the list in case the it was already assigned from another object. */
BLI_freelistN(new_defbase);
*new_defbase = object->defbase;
+ BKE_object_defgroup_active_index_set(object, object->actdef);
}
}
}
@@ -455,6 +469,22 @@ static bool do_versions_sequencer_color_tags(Sequence *seq, void *UNUSED(user_da
return true;
}
+static bool do_versions_sequencer_color_balance_sop(Sequence *seq, void *UNUSED(user_data))
+{
+ LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) {
+ if (smd->type == seqModifierType_ColorBalance) {
+ StripColorBalance *cb = &((ColorBalanceModifierData *)smd)->color_balance;
+ cb->method = SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN;
+ for (int i = 0; i < 3; i++) {
+ copy_v3_fl(cb->slope, 1.0f);
+ copy_v3_fl(cb->offset, 1.0f);
+ copy_v3_fl(cb->power, 1.0f);
+ }
+ }
+ }
+ return true;
+}
+
static bNodeLink *find_connected_link(bNodeTree *ntree, bNodeSocket *in_socket)
{
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
@@ -498,17 +528,17 @@ static void version_geometry_nodes_add_realize_instance_nodes(bNodeTree *ntree)
{
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
if (ELEM(node->type,
- GEO_NODE_ATTRIBUTE_CAPTURE,
+ GEO_NODE_CAPTURE_ATTRIBUTE,
GEO_NODE_SEPARATE_COMPONENTS,
GEO_NODE_CONVEX_HULL,
GEO_NODE_CURVE_LENGTH,
- GEO_NODE_BOOLEAN,
- GEO_NODE_CURVE_FILLET,
- GEO_NODE_CURVE_RESAMPLE,
+ GEO_NODE_MESH_BOOLEAN,
+ GEO_NODE_FILLET_CURVE,
+ GEO_NODE_RESAMPLE_CURVE,
GEO_NODE_CURVE_TO_MESH,
- GEO_NODE_CURVE_TRIM,
- GEO_NODE_MATERIAL_REPLACE,
- GEO_NODE_MESH_SUBDIVIDE,
+ GEO_NODE_TRIM_CURVE,
+ GEO_NODE_REPLACE_MATERIAL,
+ GEO_NODE_SUBDIVIDE_MESH,
GEO_NODE_ATTRIBUTE_REMOVE,
GEO_NODE_TRIANGULATE)) {
bNodeSocket *geometry_socket = node->inputs.first;
@@ -516,12 +546,60 @@ static void version_geometry_nodes_add_realize_instance_nodes(bNodeTree *ntree)
}
/* Also realize instances for the profile input of the curve to mesh node. */
if (node->type == GEO_NODE_CURVE_TO_MESH) {
- bNodeSocket *profile_socket = node->inputs.last;
+ bNodeSocket *profile_socket = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
add_realize_instances_before_socket(ntree, node, profile_socket);
}
}
}
+/**
+ * The geometry nodes modifier used to realize instances for the next modifier implicitly. Now it
+ * is done with the realize instances node. It also used to convert meshes to point clouds
+ * automatically, which is also now done with a specific node.
+ */
+static bNodeTree *add_realize_node_tree(Main *bmain)
+{
+ bNodeTree *node_tree = ntreeAddTree(bmain, "Realize Instances 2.93 Legacy", "GeometryNodeTree");
+
+ ntreeAddSocketInterface(node_tree, SOCK_IN, "NodeSocketGeometry", "Geometry");
+ ntreeAddSocketInterface(node_tree, SOCK_OUT, "NodeSocketGeometry", "Geometry");
+
+ bNode *group_input = nodeAddStaticNode(NULL, node_tree, NODE_GROUP_INPUT);
+ group_input->locx = -400.0f;
+ bNode *group_output = nodeAddStaticNode(NULL, node_tree, NODE_GROUP_OUTPUT);
+ group_output->locx = 500.0f;
+ group_output->flag |= NODE_DO_OUTPUT;
+
+ bNode *join = nodeAddStaticNode(NULL, node_tree, GEO_NODE_JOIN_GEOMETRY);
+ join->locx = group_output->locx - 175.0f;
+ join->locy = group_output->locy;
+ bNode *conv = nodeAddStaticNode(NULL, node_tree, GEO_NODE_POINTS_TO_VERTICES);
+ conv->locx = join->locx - 175.0f;
+ conv->locy = join->locy - 70.0;
+ bNode *separate = nodeAddStaticNode(NULL, node_tree, GEO_NODE_SEPARATE_COMPONENTS);
+ separate->locx = join->locx - 350.0f;
+ separate->locy = join->locy + 50.0f;
+ bNode *realize = nodeAddStaticNode(NULL, node_tree, GEO_NODE_REALIZE_INSTANCES);
+ realize->locx = separate->locx - 200.0f;
+ realize->locy = join->locy;
+
+ nodeAddLink(node_tree, group_input, group_input->outputs.first, realize, realize->inputs.first);
+ nodeAddLink(node_tree, realize, realize->outputs.first, separate, separate->inputs.first);
+ nodeAddLink(node_tree, conv, conv->outputs.first, join, join->inputs.first);
+ nodeAddLink(node_tree, separate, BLI_findlink(&separate->outputs, 3), join, join->inputs.first);
+ nodeAddLink(node_tree, separate, BLI_findlink(&separate->outputs, 1), conv, conv->inputs.first);
+ nodeAddLink(node_tree, separate, BLI_findlink(&separate->outputs, 2), join, join->inputs.first);
+ nodeAddLink(node_tree, separate, separate->outputs.first, join, join->inputs.first);
+ nodeAddLink(node_tree, join, join->outputs.first, group_output, group_output->inputs.first);
+
+ LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
+ nodeSetSelected(node, false);
+ }
+
+ version_socket_update_is_used(node_tree);
+ return node_tree;
+}
+
void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
{
if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) {
@@ -578,6 +656,10 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 25)) {
+ version_node_socket_index_animdata(bmain, NTREE_SHADER, SH_NODE_BSDF_PRINCIPLED, 4, 2, 25);
+ }
+
if (!MAIN_VERSION_ATLEAST(bmain, 300, 26)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
ToolSettings *tool_settings = scene->toolsettings;
@@ -616,6 +698,90 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
do_versions_idproperty_ui_data(bmain);
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 32)) {
+ /* Update Switch Node Non-Fields switch input to Switch_001. */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (link->tonode->type == GEO_NODE_SWITCH) {
+ if (STREQ(link->tosock->identifier, "Switch")) {
+ bNode *to_node = link->tonode;
+
+ uint8_t mode = ((NodeSwitch *)to_node->storage)->input_type;
+ if (ELEM(mode,
+ SOCK_GEOMETRY,
+ SOCK_OBJECT,
+ SOCK_COLLECTION,
+ SOCK_TEXTURE,
+ SOCK_MATERIAL)) {
+ link->tosock = link->tosock->next;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 33)) {
+ /* This was missing from #move_vertex_group_names_to_object_data. */
+ LISTBASE_FOREACH (Object *, object, &bmain->objects) {
+ if (ELEM(object->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
+ /* This uses the fact that the active vertex group index starts counting at 1. */
+ if (BKE_object_defgroup_active_index_get(object) == 0) {
+ BKE_object_defgroup_active_index_set(object, object->actdef);
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 35)) {
+ /* Add a new modifier to realize instances from previous modifiers.
+ * Previously that was done automatically by geometry nodes. */
+ bNodeTree *realize_instances_node_tree = NULL;
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH_MUTABLE (ModifierData *, md, &ob->modifiers) {
+ if (md->type != eModifierType_Nodes) {
+ continue;
+ }
+ if (md->next == NULL) {
+ break;
+ }
+ if (md->next->type == eModifierType_Nodes) {
+ continue;
+ }
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ if (nmd->node_group == NULL) {
+ continue;
+ }
+
+ NodesModifierData *new_nmd = (NodesModifierData *)BKE_modifier_new(eModifierType_Nodes);
+ STRNCPY(new_nmd->modifier.name, "Realize Instances 2.93 Legacy");
+ BKE_modifier_unique_name(&ob->modifiers, &new_nmd->modifier);
+ BLI_insertlinkafter(&ob->modifiers, md, new_nmd);
+ if (realize_instances_node_tree == NULL) {
+ realize_instances_node_tree = add_realize_node_tree(bmain);
+ }
+ new_nmd->node_group = realize_instances_node_tree;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 37)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_BOUNDING_BOX) {
+ bNodeSocket *geometry_socket = node->inputs.first;
+ add_realize_instances_before_socket(ntree, node, geometry_socket);
+ }
+ }
+ }
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -628,6 +794,40 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
*/
{
/* Keep this block, even when empty. */
+
+ { /* Ensure driver variable names are unique within the driver. */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt == NULL) {
+ continue;
+ }
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
+ ChannelDriver *driver = fcu->driver;
+ /* Ensure the uniqueness front to back. Given a list of identically
+ * named variables, the last one gets to keep its original name. This
+ * matches the evaluation order, and thus shouldn't change the evaluated
+ * value of the driver expression. */
+ LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
+ BLI_uniquename(&driver->variables,
+ dvar,
+ dvar->name,
+ '_',
+ offsetof(DriverVar, name),
+ sizeof(dvar->name));
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
+
+ /* Ensure tiled image sources contain a UDIM token. */
+ LISTBASE_FOREACH (Image *, ima, &bmain->images) {
+ if (ima->source == IMA_SRC_TILED) {
+ char *filename = (char *)BLI_path_basename(ima->filepath);
+ BKE_image_ensure_tile_token(filename);
+ }
+ }
}
}
@@ -767,9 +967,9 @@ static bool geometry_node_is_293_legacy(const short node_type)
/* Not legacy: No attribute inputs or outputs. */
case GEO_NODE_TRIANGULATE:
case GEO_NODE_TRANSFORM:
- case GEO_NODE_BOOLEAN:
+ case GEO_NODE_MESH_BOOLEAN:
case GEO_NODE_IS_VIEWPORT:
- case GEO_NODE_MESH_SUBDIVIDE:
+ case GEO_NODE_SUBDIVIDE_MESH:
case GEO_NODE_MESH_PRIMITIVE_CUBE:
case GEO_NODE_MESH_PRIMITIVE_CIRCLE:
case GEO_NODE_MESH_PRIMITIVE_UV_SPHERE:
@@ -779,9 +979,9 @@ static bool geometry_node_is_293_legacy(const short node_type)
case GEO_NODE_MESH_PRIMITIVE_LINE:
case GEO_NODE_MESH_PRIMITIVE_GRID:
case GEO_NODE_BOUNDING_BOX:
- case GEO_NODE_CURVE_RESAMPLE:
+ case GEO_NODE_RESAMPLE_CURVE:
case GEO_NODE_INPUT_MATERIAL:
- case GEO_NODE_MATERIAL_REPLACE:
+ case GEO_NODE_REPLACE_MATERIAL:
case GEO_NODE_CURVE_LENGTH:
case GEO_NODE_CONVEX_HULL:
case GEO_NODE_SEPARATE_COMPONENTS:
@@ -793,8 +993,8 @@ static bool geometry_node_is_293_legacy(const short node_type)
case GEO_NODE_VIEWER:
case GEO_NODE_CURVE_PRIMITIVE_LINE:
case GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL:
- case GEO_NODE_CURVE_FILL:
- case GEO_NODE_CURVE_TRIM:
+ case GEO_NODE_FILL_CURVE:
+ case GEO_NODE_TRIM_CURVE:
case GEO_NODE_CURVE_TO_MESH:
return false;
@@ -803,7 +1003,7 @@ static bool geometry_node_is_293_legacy(const short node_type)
case GEO_NODE_SET_POSITION:
case GEO_NODE_INPUT_INDEX:
case GEO_NODE_INPUT_NORMAL:
- case GEO_NODE_ATTRIBUTE_CAPTURE:
+ case GEO_NODE_CAPTURE_ATTRIBUTE:
return false;
/* Maybe legacy: Might need special attribute handling, depending on design. */
@@ -816,7 +1016,7 @@ static bool geometry_node_is_293_legacy(const short node_type)
/* Maybe legacy: Special case for grid names? Or finish patch from level set branch to
* generate a mesh for all grids in the volume. */
- case GEO_NODE_VOLUME_TO_MESH:
+ case GEO_NODE_LEGACY_VOLUME_TO_MESH:
return false;
/* Legacy: Transferred *all* attributes before, will not transfer all built-ins now. */
@@ -908,12 +1108,12 @@ static bool seq_transform_origin_set(Sequence *seq, void *UNUSED(user_data))
static void do_version_subsurface_methods(bNode *node)
{
if (node->type == SH_NODE_SUBSURFACE_SCATTERING) {
- if (node->custom1 != SHD_SUBSURFACE_RANDOM_WALK) {
+ if (!ELEM(node->custom1, SHD_SUBSURFACE_BURLEY, SHD_SUBSURFACE_RANDOM_WALK)) {
node->custom1 = SHD_SUBSURFACE_RANDOM_WALK_FIXED_RADIUS;
}
}
else if (node->type == SH_NODE_BSDF_PRINCIPLED) {
- if (node->custom2 != SHD_SUBSURFACE_RANDOM_WALK) {
+ if (!ELEM(node->custom2, SHD_SUBSURFACE_BURLEY, SHD_SUBSURFACE_RANDOM_WALK)) {
node->custom2 = SHD_SUBSURFACE_RANDOM_WALK_FIXED_RADIUS;
}
}
@@ -960,6 +1160,327 @@ static void version_geometry_nodes_add_attribute_input_settings(NodesModifierDat
}
}
+/* Copy of the function before the fixes. */
+static void legacy_vec_roll_to_mat3_normalized(const float nor[3],
+ const float roll,
+ float r_mat[3][3])
+{
+ const float SAFE_THRESHOLD = 1.0e-5f; /* theta above this value has good enough precision. */
+ const float CRITICAL_THRESHOLD = 1.0e-9f; /* above this is safe under certain conditions. */
+ const float THRESHOLD_SQUARED = CRITICAL_THRESHOLD * CRITICAL_THRESHOLD;
+
+ const float x = nor[0];
+ const float y = nor[1];
+ const float z = nor[2];
+
+ const float theta = 1.0f + y; /* remapping Y from [-1,+1] to [0,2]. */
+ const float theta_alt = x * x + z * z; /* Helper value for matrix calculations. */
+ float rMatrix[3][3], bMatrix[3][3];
+
+ BLI_ASSERT_UNIT_V3(nor);
+
+ /* When theta is close to zero (nor is aligned close to negative Y Axis),
+ * we have to check we do have non-null X/Z components as well.
+ * Also, due to float precision errors, nor can be (0.0, -0.99999994, 0.0) which results
+ * in theta being close to zero. This will cause problems when theta is used as divisor.
+ */
+ if (theta > SAFE_THRESHOLD || (theta > CRITICAL_THRESHOLD && theta_alt > THRESHOLD_SQUARED)) {
+ /* nor is *not* aligned to negative Y-axis (0,-1,0). */
+
+ bMatrix[0][1] = -x;
+ bMatrix[1][0] = x;
+ bMatrix[1][1] = y;
+ bMatrix[1][2] = z;
+ bMatrix[2][1] = -z;
+
+ if (theta > SAFE_THRESHOLD) {
+ /* nor differs significantly from negative Y axis (0,-1,0): apply the general case. */
+ bMatrix[0][0] = 1 - x * x / theta;
+ bMatrix[2][2] = 1 - z * z / theta;
+ bMatrix[2][0] = bMatrix[0][2] = -x * z / theta;
+ }
+ else {
+ /* nor is close to negative Y axis (0,-1,0): apply the special case. */
+ bMatrix[0][0] = (x + z) * (x - z) / -theta_alt;
+ bMatrix[2][2] = -bMatrix[0][0];
+ bMatrix[2][0] = bMatrix[0][2] = 2.0f * x * z / theta_alt;
+ }
+ }
+ else {
+ /* nor is very close to negative Y axis (0,-1,0): use simple symmetry by Z axis. */
+ unit_m3(bMatrix);
+ bMatrix[0][0] = bMatrix[1][1] = -1.0;
+ }
+
+ /* Make Roll matrix */
+ axis_angle_normalized_to_mat3(rMatrix, nor, roll);
+
+ /* Combine and output result */
+ mul_m3_m3m3(r_mat, rMatrix, bMatrix);
+}
+
+static void correct_bone_roll_value(const float head[3],
+ const float tail[3],
+ const float check_x_axis[3],
+ const float check_y_axis[3],
+ float *r_roll)
+{
+ const float SAFE_THRESHOLD = 1.0e-5f;
+ float vec[3], bone_mat[3][3], vec2[3];
+
+ /* Compute the Y axis vector. */
+ sub_v3_v3v3(vec, tail, head);
+ normalize_v3(vec);
+
+ /* Only correct when in the danger zone. */
+ if (1.0f + vec[1] < SAFE_THRESHOLD * 2 && (vec[0] || vec[2])) {
+ /* Use the armature matrix to double-check if adjustment is needed.
+ * This should minimize issues if the file is bounced back and forth between
+ * 2.92 and 2.91, provided Edit Mode isn't entered on the armature in 2.91. */
+ vec_roll_to_mat3(vec, *r_roll, bone_mat);
+
+ UNUSED_VARS_NDEBUG(check_y_axis);
+ BLI_assert(dot_v3v3(bone_mat[1], check_y_axis) > 0.999f);
+
+ if (dot_v3v3(bone_mat[0], check_x_axis) < 0.999f) {
+ /* Recompute roll using legacy code to interpret the old value. */
+ legacy_vec_roll_to_mat3_normalized(vec, *r_roll, bone_mat);
+ mat3_to_vec_roll(bone_mat, vec2, r_roll);
+ BLI_assert(compare_v3v3(vec, vec2, 0.001f));
+ }
+ }
+}
+
+/* Update the armature Bone roll fields for bones very close to -Y direction. */
+static void do_version_bones_roll(ListBase *lb)
+{
+ LISTBASE_FOREACH (Bone *, bone, lb) {
+ /* Parent-relative orientation (used for posing). */
+ correct_bone_roll_value(
+ bone->head, bone->tail, bone->bone_mat[0], bone->bone_mat[1], &bone->roll);
+
+ /* Absolute orientation (used for Edit mode). */
+ correct_bone_roll_value(
+ bone->arm_head, bone->arm_tail, bone->arm_mat[0], bone->arm_mat[1], &bone->arm_roll);
+
+ do_version_bones_roll(&bone->childbase);
+ }
+}
+
+static void version_geometry_nodes_set_position_node_offset(bNodeTree *ntree)
+{
+ /* Add the new Offset socket. */
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type != GEO_NODE_SET_POSITION) {
+ continue;
+ }
+ if (BLI_listbase_count(&node->inputs) < 4) {
+ /* The offset socket didn't exist in the file yet. */
+ return;
+ }
+ bNodeSocket *old_offset_socket = BLI_findlink(&node->inputs, 3);
+ if (old_offset_socket->type == SOCK_VECTOR) {
+ /* Versioning happened already. */
+ return;
+ }
+ /* Change identifier of old socket, so that the there is no name collision. */
+ STRNCPY(old_offset_socket->identifier, "Offset_old");
+ nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_VECTOR, PROP_TRANSLATION, "Offset", "Offset");
+ }
+
+ /* Relink links that were connected to Position while Offset was enabled. */
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (link->tonode->type != GEO_NODE_SET_POSITION) {
+ continue;
+ }
+ if (!STREQ(link->tosock->identifier, "Position")) {
+ continue;
+ }
+ bNodeSocket *old_offset_socket = BLI_findlink(&link->tonode->inputs, 3);
+ /* This assumes that the offset is not linked to something else. That seems to be a reasonable
+ * assumption, because the node is probably only ever used in one or the other mode. */
+ const bool offset_enabled =
+ ((bNodeSocketValueBoolean *)old_offset_socket->default_value)->value;
+ if (offset_enabled) {
+ /* Relink to new offset socket. */
+ link->tosock = old_offset_socket->next;
+ }
+ }
+
+ /* Remove old Offset socket. */
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type != GEO_NODE_SET_POSITION) {
+ continue;
+ }
+ bNodeSocket *old_offset_socket = BLI_findlink(&node->inputs, 3);
+ nodeRemoveSocket(ntree, node, old_offset_socket);
+ }
+}
+
+static void version_node_tree_socket_id_delim(bNodeTree *ntree)
+{
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ version_node_socket_id_delim(socket);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ version_node_socket_id_delim(socket);
+ }
+ }
+}
+
+static bool version_fix_seq_meta_range(Sequence *seq, void *user_data)
+{
+ Scene *scene = (Scene *)user_data;
+ if (seq->type == SEQ_TYPE_META) {
+ SEQ_time_update_meta_strip_range(scene, seq);
+ }
+ return true;
+}
+
+/* Those `version_liboverride_rnacollections_*` functions mimic the old, pre-3.0 code to find
+ * anchor and source items in the given list of modifiers, constraints etc., using only the
+ * `subitem_local` data of the override property operation.
+ *
+ * Then they convert it into the new, proper `subitem_reference` data for the anchor, and
+ * `subitem_local` for the source.
+ *
+ * NOTE: Here only the stored override ID is available, unlike in the `override_apply` functions.
+ */
+
+static void version_liboverride_rnacollections_insertion_object_constraints(
+ ListBase *constraints, IDOverrideLibraryProperty *op)
+{
+ LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) {
+ continue;
+ }
+ bConstraint *constraint_anchor = BLI_listbase_string_or_index_find(constraints,
+ opop->subitem_local_name,
+ offsetof(bConstraint, name),
+ opop->subitem_local_index);
+ bConstraint *constraint_src = constraint_anchor != NULL ? constraint_anchor->next :
+ constraints->first;
+
+ if (constraint_src == NULL) {
+ /* Invalid case, just remove that override property operation. */
+ CLOG_ERROR(&LOG, "Could not find source constraint in stored override data");
+ BKE_lib_override_library_property_operation_delete(op, opop);
+ continue;
+ }
+
+ opop->subitem_reference_name = opop->subitem_local_name;
+ opop->subitem_local_name = BLI_strdup(constraint_src->name);
+ opop->subitem_reference_index = opop->subitem_local_index;
+ opop->subitem_local_index++;
+ }
+}
+
+static void version_liboverride_rnacollections_insertion_object(Object *object)
+{
+ IDOverrideLibrary *liboverride = object->id.override_library;
+ IDOverrideLibraryProperty *op;
+
+ op = BKE_lib_override_library_property_find(liboverride, "modifiers");
+ if (op != NULL) {
+ LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) {
+ continue;
+ }
+ ModifierData *mod_anchor = BLI_listbase_string_or_index_find(&object->modifiers,
+ opop->subitem_local_name,
+ offsetof(ModifierData, name),
+ opop->subitem_local_index);
+ ModifierData *mod_src = mod_anchor != NULL ? mod_anchor->next : object->modifiers.first;
+
+ if (mod_src == NULL) {
+ /* Invalid case, just remove that override property operation. */
+ CLOG_ERROR(&LOG, "Could not find source modifier in stored override data");
+ BKE_lib_override_library_property_operation_delete(op, opop);
+ continue;
+ }
+
+ opop->subitem_reference_name = opop->subitem_local_name;
+ opop->subitem_local_name = BLI_strdup(mod_src->name);
+ opop->subitem_reference_index = opop->subitem_local_index;
+ opop->subitem_local_index++;
+ }
+ }
+
+ op = BKE_lib_override_library_property_find(liboverride, "grease_pencil_modifiers");
+ if (op != NULL) {
+ LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) {
+ continue;
+ }
+ GpencilModifierData *gp_mod_anchor = BLI_listbase_string_or_index_find(
+ &object->greasepencil_modifiers,
+ opop->subitem_local_name,
+ offsetof(GpencilModifierData, name),
+ opop->subitem_local_index);
+ GpencilModifierData *gp_mod_src = gp_mod_anchor != NULL ?
+ gp_mod_anchor->next :
+ object->greasepencil_modifiers.first;
+
+ if (gp_mod_src == NULL) {
+ /* Invalid case, just remove that override property operation. */
+ CLOG_ERROR(&LOG, "Could not find source GP modifier in stored override data");
+ BKE_lib_override_library_property_operation_delete(op, opop);
+ continue;
+ }
+
+ opop->subitem_reference_name = opop->subitem_local_name;
+ opop->subitem_local_name = BLI_strdup(gp_mod_src->name);
+ opop->subitem_reference_index = opop->subitem_local_index;
+ opop->subitem_local_index++;
+ }
+ }
+
+ op = BKE_lib_override_library_property_find(liboverride, "constraints");
+ if (op != NULL) {
+ version_liboverride_rnacollections_insertion_object_constraints(&object->constraints, op);
+ }
+
+ if (object->pose != NULL) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ char rna_path[FILE_MAXFILE];
+ BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].constraints", pchan->name);
+ op = BKE_lib_override_library_property_find(liboverride, rna_path);
+ if (op != NULL) {
+ version_liboverride_rnacollections_insertion_object_constraints(&pchan->constraints, op);
+ }
+ }
+ }
+}
+
+static void version_liboverride_rnacollections_insertion_animdata(ID *id)
+{
+ AnimData *anim_data = BKE_animdata_from_id(id);
+ if (anim_data == NULL) {
+ return;
+ }
+
+ IDOverrideLibrary *liboverride = id->override_library;
+ IDOverrideLibraryProperty *op;
+
+ op = BKE_lib_override_library_property_find(liboverride, "animation_data.nla_tracks");
+ if (op != NULL) {
+ LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) {
+ continue;
+ }
+ /* NLA tracks are only referenced by index, which limits possibilities, basically they are
+ * always added at the end of the list, see #rna_NLA_tracks_override_apply.
+ *
+ * This makes things simple here. */
+ opop->subitem_reference_name = opop->subitem_local_name;
+ opop->subitem_local_name = NULL;
+ opop->subitem_reference_index = opop->subitem_local_index;
+ opop->subitem_local_index++;
+ }
+ }
+}
+
/* NOLINTNEXTLINE: readability-function-size */
void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
@@ -1039,7 +1560,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
FOREACH_NODETREE_END;
- if (!DNA_struct_elem_find(fd->filesdna, "FileAssetSelectParams", "int", "import_type")) {
+ if (!DNA_struct_elem_find(fd->filesdna, "FileAssetSelectParams", "short", "import_type")) {
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
@@ -1173,7 +1694,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_GEOMETRY) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == GEO_NODE_MESH_SUBDIVIDE) {
+ if (node->type == GEO_NODE_SUBDIVIDE_MESH) {
strcpy(node->idname, "GeometryNodeMeshSubdivide");
}
}
@@ -1552,7 +2073,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
SpaceFile *sfile = (SpaceFile *)sl;
if (sfile->params) {
sfile->params->flag &= ~(FILE_PARAMS_FLAG_UNUSED_1 | FILE_PARAMS_FLAG_UNUSED_2 |
- FILE_PARAMS_FLAG_UNUSED_3 | FILE_PARAMS_FLAG_UNUSED_4);
+ FILE_PARAMS_FLAG_UNUSED_3 | FILE_PATH_TOKENS_ALLOW);
}
/* New default import type: Append with reuse. */
@@ -1658,7 +2179,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /* Show vse color tags by default. */
+ /* Show sequencer color tags by default. */
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
@@ -1669,6 +2190,299 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
+
+ /* Set defaults for new color balance modifier parameters. */
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->ed != NULL) {
+ SEQ_for_each_callback(&scene->ed->seqbase, do_versions_sequencer_color_balance_sop, NULL);
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 33)) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ switch (sl->spacetype) {
+ case SPACE_SEQ: {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ enum { SEQ_DRAW_SEQUENCE = 0 };
+ if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
+ sseq->mainb = SEQ_DRAW_IMG_IMBUF;
+ }
+ break;
+ }
+ case SPACE_TEXT: {
+ SpaceText *st = (SpaceText *)sl;
+ st->flags &= ~ST_FLAG_UNUSED_4;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 36)) {
+ /* Update the `idnames` for renamed geometry and function nodes. */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ version_node_id(ntree, FN_NODE_COMPARE, "FunctionNodeCompareFloats");
+ version_node_id(ntree, GEO_NODE_CAPTURE_ATTRIBUTE, "GeometryNodeCaptureAttribute");
+ version_node_id(ntree, GEO_NODE_MESH_BOOLEAN, "GeometryNodeMeshBoolean");
+ version_node_id(ntree, GEO_NODE_FILL_CURVE, "GeometryNodeFillCurve");
+ version_node_id(ntree, GEO_NODE_FILLET_CURVE, "GeometryNodeFilletCurve");
+ version_node_id(ntree, GEO_NODE_REVERSE_CURVE, "GeometryNodeReverseCurve");
+ version_node_id(ntree, GEO_NODE_SAMPLE_CURVE, "GeometryNodeSampleCurve");
+ version_node_id(ntree, GEO_NODE_RESAMPLE_CURVE, "GeometryNodeResampleCurve");
+ version_node_id(ntree, GEO_NODE_SUBDIVIDE_CURVE, "GeometryNodeSubdivideCurve");
+ version_node_id(ntree, GEO_NODE_TRIM_CURVE, "GeometryNodeTrimCurve");
+ version_node_id(ntree, GEO_NODE_REPLACE_MATERIAL, "GeometryNodeReplaceMaterial");
+ version_node_id(ntree, GEO_NODE_SUBDIVIDE_MESH, "GeometryNodeSubdivideMesh");
+ version_node_id(ntree, GEO_NODE_SET_MATERIAL, "GeometryNodeSetMaterial");
+ version_node_id(ntree, GEO_NODE_SPLIT_EDGES, "GeometryNodeSplitEdges");
+ }
+
+ /* Update bone roll after a fix to vec_roll_to_mat3_normalized. */
+ LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) {
+ do_version_bones_roll(&arm->bonebase);
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 37)) {
+ /* Node Editor: toggle overlays on. */
+ if (!DNA_struct_find(fd->filesdna, "SpaceNodeOverlay")) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ if (space->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)space;
+ snode->overlay.flag |= SN_OVERLAY_SHOW_OVERLAYS;
+ snode->overlay.flag |= SN_OVERLAY_SHOW_WIRE_COLORS;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 38)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ if (space->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)space;
+ FileAssetSelectParams *asset_params = sfile->asset_params;
+ if (asset_params) {
+ asset_params->base_params.filter_id = FILTER_ID_ALL;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 39)) {
+ LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
+ wm->xr.session_settings.base_scale = 1.0f;
+ wm->xr.session_settings.draw_flags |= (V3D_OFSDRAW_SHOW_SELECTION |
+ V3D_OFSDRAW_XR_SHOW_CONTROLLERS |
+ V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS);
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 40)) {
+ /* Update the `idnames` for renamed geometry and function nodes. */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ version_node_id(ntree, FN_NODE_SLICE_STRING, "FunctionNodeSliceString");
+ version_geometry_nodes_set_position_node_offset(ntree);
+ version_node_id(ntree, GEO_NODE_LEGACY_VOLUME_TO_MESH, "GeometryNodeLegacyVolumeToMesh");
+ }
+
+ /* Add storage to viewer node. */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_VIEWER) {
+ if (node->storage == NULL) {
+ NodeGeometryViewer *data = (NodeGeometryViewer *)MEM_callocN(
+ sizeof(NodeGeometryViewer), __func__);
+ data->data_type = CD_PROP_FLOAT;
+ node->storage = data;
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_input_socket_name(
+ ntree, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, "Geometry", "Mesh");
+ version_node_input_socket_name(ntree, GEO_NODE_POINTS_TO_VOLUME, "Geometry", "Points");
+ version_node_output_socket_name(ntree, GEO_NODE_POINTS_TO_VOLUME, "Geometry", "Volume");
+ version_node_socket_name(ntree, GEO_NODE_SUBDIVISION_SURFACE, "Geometry", "Mesh");
+ version_node_socket_name(ntree, GEO_NODE_RESAMPLE_CURVE, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_SUBDIVIDE_CURVE, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_SET_CURVE_RADIUS, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_SET_CURVE_TILT, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_SET_CURVE_HANDLES, "Geometry", "Curve");
+ version_node_socket_name(ntree, GEO_NODE_TRANSLATE_INSTANCES, "Geometry", "Instances");
+ version_node_socket_name(ntree, GEO_NODE_ROTATE_INSTANCES, "Geometry", "Instances");
+ version_node_socket_name(ntree, GEO_NODE_SCALE_INSTANCES, "Geometry", "Instances");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_BOOLEAN, "Geometry", "Mesh");
+ version_node_input_socket_name(ntree, GEO_NODE_MESH_BOOLEAN, "Geometry 1", "Mesh 1");
+ version_node_input_socket_name(ntree, GEO_NODE_MESH_BOOLEAN, "Geometry 2", "Mesh 2");
+ version_node_socket_name(ntree, GEO_NODE_SUBDIVIDE_MESH, "Geometry", "Mesh");
+ version_node_socket_name(ntree, GEO_NODE_TRIANGULATE, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_CONE, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_CUBE, "Geometry", "Mesh");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_GRID, "Geometry", "Mesh");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Geometry", "Mesh");
+ version_node_output_socket_name(ntree, GEO_NODE_MESH_PRIMITIVE_LINE, "Geometry", "Mesh");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "Geometry", "Mesh");
+ version_node_socket_name(ntree, GEO_NODE_SET_POINT_RADIUS, "Geometry", "Points");
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 42)) {
+ /* Use consistent socket identifiers for the math node.
+ * The code to make unique identifiers from the names was inconsistent. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type != NTREE_CUSTOM) {
+ version_node_tree_socket_id_delim(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SEQ) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ region->v2d.min[1] = 1.0f;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Change minimum zoom to 0.05f in the node editor. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_NODE) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ if (region->v2d.minzoom > 0.05f) {
+ region->v2d.minzoom = 0.05f;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ Editing *ed = SEQ_editing_get(scene);
+ /* Make sure range of meta strips is correct.
+ * It was possible to save .blend file with incorrect state of meta strip
+ * range. The root cause is expected to be fixed, but need to ensure files
+ * with invalid meta strip range are corrected. */
+ if (ed != NULL) {
+ SEQ_for_each_callback(&ed->seqbase, version_fix_seq_meta_range, scene);
+ }
+ }
+ }
+
+ /* Special case to handle older in-development 3.1 files, before change from 3.0 branch gets
+ * merged in master. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 42) ||
+ (bmain->versionfile == 301 && !MAIN_VERSION_ATLEAST(bmain, 301, 3))) {
+ /* Update LibOverride operations regarding insertions in RNA collections (i.e. modifiers,
+ * constraints and NLA tracks). */
+ ID *id_iter;
+ FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) {
+ version_liboverride_rnacollections_insertion_animdata(id_iter);
+ if (GS(id_iter->name) == ID_OB) {
+ version_liboverride_rnacollections_insertion_object((Object *)id_iter);
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 301, 4)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ version_node_id(ntree, GEO_NODE_CURVE_SPLINE_PARAMETER, "GeometryNodeSplineParameter");
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_CURVE_SPLINE_PARAMETER) {
+ version_node_add_socket_if_not_exist(
+ ntree, node, SOCK_OUT, SOCK_INT, PROP_NONE, "Index", "Index");
+ }
+
+ /* Convert float compare into a more general compare node. */
+ if (node->type == FN_NODE_COMPARE) {
+ if (node->storage == NULL) {
+ NodeFunctionCompare *data = (NodeFunctionCompare *)MEM_callocN(
+ sizeof(NodeFunctionCompare), __func__);
+ data->data_type = SOCK_FLOAT;
+ data->operation = node->custom1;
+ strcpy(node->idname, "FunctionNodeCompare");
+ node->storage = data;
+ }
+ }
+ }
+ }
+
+ /* Add a toggle for the breadcrumbs overlay in the node editor. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ if (space->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)space;
+ snode->overlay.flag |= SN_OVERLAY_SHOW_PATH;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 301, 5)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type != GEO_NODE_REALIZE_INSTANCES) {
+ continue;
+ }
+ node->custom1 |= GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR;
+ }
+ }
}
/**
@@ -1682,5 +2496,65 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ /* Add node storage for map range node. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_MAP_RANGE) {
+ if (node->storage == NULL) {
+ NodeMapRange *data = MEM_callocN(sizeof(NodeMapRange), __func__);
+ data->clamp = node->custom1;
+ data->data_type = CD_PROP_FLOAT;
+ data->interpolation_type = node->custom2;
+ node->storage = data;
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ /* Update spreadsheet data set region type. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == RGN_TYPE_CHANNELS) {
+ region->regiontype = RGN_TYPE_TOOLS;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Initialize the bone wireframe opacity setting. */
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "bone_wire_alpha")) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.bone_wire_alpha = 1.0f;
+ }
+ }
+ }
+ }
+ }
+
+ /* Rename sockets on multiple nodes */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_output_socket_name(
+ ntree, GEO_NODE_STRING_TO_CURVES, "Curves", "Curve Instances");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_INPUT_MESH_EDGE_ANGLE, "Angle", "Unsigned Angle");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_INPUT_MESH_ISLAND, "Index", "Island Index");
+ version_node_input_socket_name(ntree, GEO_NODE_TRANSFER_ATTRIBUTE, "Target", "Source");
+ }
+ }
}
}
diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc
index 3f13d1ec12e..575bfd565e6 100644
--- a/source/blender/blenloader/intern/versioning_common.cc
+++ b/source/blender/blenloader/intern/versioning_common.cc
@@ -27,14 +27,19 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
+#include "BLI_string_ref.hh"
+#include "BKE_animsys.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_node.h"
#include "MEM_guardedalloc.h"
#include "versioning_common.h"
+using blender::StringRef;
+
ARegion *do_versions_add_region_if_not_found(ListBase *regionbase,
int region_type,
const char *name,
@@ -56,11 +61,6 @@ ARegion *do_versions_add_region_if_not_found(ListBase *regionbase,
return new_region;
}
-/**
- * Rename if the ID doesn't exist.
- *
- * \return the ID (if found).
- */
ID *do_versions_rename_id(Main *bmain,
const short id_type,
const char *name_src,
@@ -87,6 +87,39 @@ ID *do_versions_rename_id(Main *bmain,
return id;
}
+static void change_node_socket_name(ListBase *sockets, const char *old_name, const char *new_name)
+{
+ LISTBASE_FOREACH (bNodeSocket *, socket, sockets) {
+ if (STREQ(socket->name, old_name)) {
+ BLI_strncpy(socket->name, new_name, sizeof(socket->name));
+ }
+ if (STREQ(socket->identifier, old_name)) {
+ BLI_strncpy(socket->identifier, new_name, sizeof(socket->name));
+ }
+ }
+}
+
+void version_node_socket_id_delim(bNodeSocket *socket)
+{
+ StringRef name = socket->name;
+ StringRef id = socket->identifier;
+
+ if (!id.startswith(name)) {
+ /* We only need to affect the case where the identifier starts with the name. */
+ return;
+ }
+
+ StringRef id_number = id.drop_known_prefix(name);
+ if (id_number.is_empty()) {
+ /* The name was already unique, and didn't need numbers at the end for the id. */
+ return;
+ }
+
+ if (id_number.startswith(".")) {
+ socket->identifier[name.size()] = '_';
+ }
+}
+
void version_node_socket_name(bNodeTree *ntree,
const int node_type,
const char *old_name,
@@ -94,22 +127,115 @@ void version_node_socket_name(bNodeTree *ntree,
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == node_type) {
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- if (STREQ(socket->name, old_name)) {
- BLI_strncpy(socket->name, new_name, sizeof(socket->name));
- }
- if (STREQ(socket->identifier, old_name)) {
- BLI_strncpy(socket->identifier, new_name, sizeof(socket->name));
- }
+ change_node_socket_name(&node->inputs, old_name, new_name);
+ change_node_socket_name(&node->outputs, old_name, new_name);
+ }
+ }
+}
+
+void version_node_input_socket_name(bNodeTree *ntree,
+ const int node_type,
+ const char *old_name,
+ const char *new_name)
+{
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == node_type) {
+ change_node_socket_name(&node->inputs, old_name, new_name);
+ }
+ }
+}
+
+void version_node_output_socket_name(bNodeTree *ntree,
+ const int node_type,
+ const char *old_name,
+ const char *new_name)
+{
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == node_type) {
+ change_node_socket_name(&node->outputs, old_name, new_name);
+ }
+ }
+}
+
+bNodeSocket *version_node_add_socket_if_not_exist(bNodeTree *ntree,
+ bNode *node,
+ eNodeSocketInOut in_out,
+ int type,
+ int subtype,
+ const char *identifier,
+ const char *name)
+{
+ bNodeSocket *sock = nodeFindSocket(node, in_out, identifier);
+ if (sock != nullptr) {
+ return sock;
+ }
+ return nodeAddStaticSocket(ntree, node, in_out, type, subtype, identifier, name);
+}
+
+void version_node_id(bNodeTree *ntree, const int node_type, const char *new_name)
+{
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == node_type) {
+ if (!STREQ(node->idname, new_name)) {
+ strcpy(node->idname, new_name);
}
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
- if (STREQ(socket->name, old_name)) {
- BLI_strncpy(socket->name, new_name, sizeof(socket->name));
- }
- if (STREQ(socket->identifier, old_name)) {
- BLI_strncpy(socket->identifier, new_name, sizeof(socket->name));
+ }
+ }
+}
+
+void version_node_socket_index_animdata(Main *bmain,
+ const int node_tree_type,
+ const int node_type,
+ const int socket_index_orig,
+ const int socket_index_offset,
+ const int total_number_of_sockets)
+{
+
+ /* The for loop for the input ids is at the top level otherwise we lose the animation
+ * keyframe data. Not sure what causes that, so I (Sybren) moved the code here from
+ * versioning_290.c as-is (structure-wise). */
+ for (int input_index = total_number_of_sockets - 1; input_index >= socket_index_orig;
+ input_index--) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, owner_id) {
+ if (ntree->type != node_tree_type) {
+ continue;
+ }
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type != node_type) {
+ continue;
}
+
+ const size_t node_name_length = strlen(node->name);
+ const size_t node_name_escaped_max_length = (node_name_length * 2);
+ char *node_name_escaped = (char *)MEM_mallocN(node_name_escaped_max_length + 1,
+ "escaped name");
+ BLI_str_escape(node_name_escaped, node->name, node_name_escaped_max_length);
+ char *rna_path_prefix = BLI_sprintfN("nodes[\"%s\"].inputs", node_name_escaped);
+
+ const int new_index = input_index + socket_index_offset;
+ BKE_animdata_fix_paths_rename_all_ex(
+ bmain, owner_id, rna_path_prefix, nullptr, nullptr, input_index, new_index, false);
+ MEM_freeN(rna_path_prefix);
+ MEM_freeN(node_name_escaped);
}
}
+ FOREACH_NODETREE_END;
+ }
+}
+
+void version_socket_update_is_used(bNodeTree *ntree)
+{
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ socket->flag &= ~SOCK_IN_USE;
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ socket->flag &= ~SOCK_IN_USE;
+ }
+ }
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ link->fromsock->flag |= SOCK_IN_USE;
+ link->tosock->flag |= SOCK_IN_USE;
}
}
diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h
index c1fe2b591cd..ea850a052ae 100644
--- a/source/blender/blenloader/intern/versioning_common.h
+++ b/source/blender/blenloader/intern/versioning_common.h
@@ -34,15 +34,74 @@ struct ARegion *do_versions_add_region_if_not_found(struct ListBase *regionbase,
const char *name,
int link_after_region_type);
-ID *do_versions_rename_id(Main *bmain,
- const short id_type,
- const char *name_src,
- const char *name_dst);
+/**
+ * Rename if the ID doesn't exist.
+ *
+ * \return the ID (if found).
+ */
+ID *do_versions_rename_id(Main *bmain, short id_type, const char *name_src, const char *name_dst);
void version_node_socket_name(struct bNodeTree *ntree,
- const int node_type,
+ int node_type,
const char *old_name,
const char *new_name);
+void version_node_input_socket_name(struct bNodeTree *ntree,
+ int node_type,
+ const char *old_name,
+ const char *new_name);
+void version_node_output_socket_name(struct bNodeTree *ntree,
+ int node_type,
+ const char *old_name,
+ const char *new_name);
+
+/**
+ * Adjust animation data for newly added node sockets.
+ *
+ * Node sockets are addressed by their index (in their RNA path, and thus FCurves/drivers), and
+ * thus when a new node is added in the middle of the list, existing animation data needs to be
+ * adjusted.
+ *
+ * Since this is about animation data, it only concerns input sockets.
+ *
+ * \param node_tree_type: Node tree type that has these nodes, for example #NTREE_SHADER.
+ * \param node_type: Node type to adjust, for example #SH_NODE_BSDF_PRINCIPLED.
+ * \param socket_index_orig: The original index of the moved socket; when socket 4 moved to 6,
+ * pass 4 here.
+ * \param socket_index_offset: The offset of the nodes, so when socket 4 moved to 6,
+ * pass 2 here.
+ * \param total_number_of_sockets: The total number of sockets in the node.
+ */
+void version_node_socket_index_animdata(
+ Main *bmain,
+ int node_tree_type, /* NTREE_....., e.g. NTREE_SHADER */
+ int node_type, /* SH_NODE_..., e.g. SH_NODE_BSDF_PRINCIPLED */
+ int socket_index_orig,
+ int socket_index_offset,
+ int total_number_of_sockets);
+
+/**
+ * Replace the ID name of all nodes in the tree with the given type with the new name.
+ */
+void version_node_id(struct bNodeTree *ntree, int node_type, const char *new_name);
+
+/**
+ * Convert `SocketName.001` unique name format to `SocketName_001`. Previously both were used.
+ */
+void version_node_socket_id_delim(bNodeSocket *socket);
+
+struct bNodeSocket *version_node_add_socket_if_not_exist(struct bNodeTree *ntree,
+ struct bNode *node,
+ eNodeSocketInOut in_out,
+ int type,
+ int subtype,
+ const char *identifier,
+ const char *name);
+
+/**
+ * The versioning code generally expects `SOCK_IN_USE` to be set correctly. This function updates
+ * the flag on all sockets after changes to the node tree.
+ */
+void version_socket_update_is_used(bNodeTree *ntree);
#ifdef __cplusplus
}
diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c
index da57f27af4e..1f18405cdf9 100644
--- a/source/blender/blenloader/intern/versioning_cycles.c
+++ b/source/blender/blenloader/intern/versioning_cycles.c
@@ -42,12 +42,15 @@
#include "BKE_main.h"
#include "BKE_node.h"
+#include "NOD_shader.h"
+
#include "MEM_guardedalloc.h"
#include "IMB_colormanagement.h"
#include "BLO_readfile.h"
#include "readfile.h"
+#include "versioning_common.h"
static bool socket_is_used(bNodeSocket *sock)
{
@@ -170,7 +173,7 @@ static void displacement_node_insert(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -182,8 +185,8 @@ static void displacement_principled_nodes(bNode *node)
}
}
else if (node->type == SH_NODE_BSDF_PRINCIPLED) {
- if (node->custom2 != SHD_SUBSURFACE_RANDOM_WALK_FIXED_RADIUS) {
- node->custom2 = SHD_SUBSURFACE_DIFFUSION;
+ if (node->custom2 != SHD_SUBSURFACE_RANDOM_WALK) {
+ node->custom2 = SHD_SUBSURFACE_BURLEY;
}
}
}
@@ -243,7 +246,7 @@ static void square_roughness_node_insert(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -318,7 +321,7 @@ static void ambient_occlusion_node_relink(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -466,7 +469,7 @@ static void update_math_node_single_operand_operators(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -528,7 +531,7 @@ static void update_vector_math_node_add_and_subtract_operators(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -566,7 +569,7 @@ static void update_vector_math_node_dot_product_operator(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -631,7 +634,7 @@ static void update_vector_math_node_cross_product_operator(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -683,7 +686,7 @@ static void update_vector_math_node_normalize_operator(bNodeTree *ntree)
}
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -785,7 +788,7 @@ static void update_vector_math_node_average_operator(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -974,7 +977,7 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1149,7 +1152,7 @@ static void update_voronoi_node_crackle(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1191,7 +1194,7 @@ static void update_voronoi_node_coloring(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1234,7 +1237,7 @@ static void update_voronoi_node_square_distance(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1279,7 +1282,7 @@ static void update_noise_and_wave_distortion(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1635,6 +1638,8 @@ void do_versions_after_linking_cycles(Main *bmain)
flag |= OB_HIDE_CAMERA | OB_SHADOW_CATCHER;
}
+ /* Clear unused bits from old version, and add new flags. */
+ object->visibility_flag &= (OB_HIDE_VIEWPORT | OB_HIDE_SELECT | OB_HIDE_RENDER);
object->visibility_flag |= flag;
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index c383c1cc4e5..234951eac9a 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -61,6 +61,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_paint.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
@@ -208,7 +209,8 @@ static void blo_update_defaults_screen(bScreen *screen,
LISTBASE_FOREACH (ARegion *, region, regionbase) {
if (region->regiontype == RGN_TYPE_TOOL_HEADER) {
- if ((sl->spacetype == SPACE_IMAGE) && hide_image_tool_header) {
+ if (((sl->spacetype == SPACE_IMAGE) && hide_image_tool_header) ||
+ sl->spacetype == SPACE_SEQ) {
region->flag |= RGN_FLAG_HIDDEN;
}
else {
@@ -293,7 +295,7 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
}
/* Rename render layers. */
- BKE_view_layer_rename(bmain, scene, scene->view_layers.first, "View Layer");
+ BKE_view_layer_rename(bmain, scene, scene->view_layers.first, "ViewLayer");
/* Disable Z pass by default. */
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -366,15 +368,6 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
}
}
-/**
- * Update defaults in startup.blend, without having to save and embed the file.
- * This function can be emptied each time the startup.blend is updated.
- *
- * \note Screen data may be cleared at this point, this will happen in the case
- * an app-template's data needs to be versioned when read-file is called with "Load UI" disabled.
- * Versioning the screen data can be safely skipped without "Load UI" since the screen data
- * will have been versioned when it was first loaded.
- */
void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
{
/* For all app templates. */
@@ -591,9 +584,11 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
bNodeSocketValueFloat *roughness_data = roughness_socket->default_value;
roughness_data->value = 0.4f;
node->custom2 = SHD_SUBSURFACE_RANDOM_WALK;
+ BKE_ntree_update_tag_node_property(ma->nodetree, node);
}
else if (node->type == SH_NODE_SUBSURFACE_SCATTERING) {
node->custom1 = SHD_SUBSURFACE_RANDOM_WALK;
+ BKE_ntree_update_tag_node_property(ma->nodetree, node);
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_dna.c b/source/blender/blenloader/intern/versioning_dna.c
index aee54b94833..0a97eedb993 100644
--- a/source/blender/blenloader/intern/versioning_dna.c
+++ b/source/blender/blenloader/intern/versioning_dna.c
@@ -29,16 +29,6 @@
#include "BLO_readfile.h"
#include "readfile.h"
-/**
- * Manipulates SDNA before calling #DNA_struct_get_compareflags,
- * allowing us to rename structs and struct members.
- *
- * - This means older versions of Blender won't have access to this data **USE WITH CARE**.
- *
- * - These changes are applied on file load (run-time), similar to versioning for compatibility.
- *
- * \attention ONLY USE THIS KIND OF VERSIONING WHEN `dna_rename_defs.h` ISN'T SUFFICIENT.
- */
void blo_do_versions_dna(SDNA *sdna, const int versionfile, const int subversionfile)
{
#define DNA_VERSION_ATLEAST(ver, subver) \
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 62cc2aa3662..94720ad0b0a 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -391,7 +391,6 @@ static void do_version_ntree_242_2(bNodeTree *ntree)
iuser->sfra = nia->sfra;
iuser->offset = nia->nr - 1;
iuser->cycl = nia->cyclic;
- iuser->ok = 1;
node->storage = iuser;
MEM_freeN(nia);
@@ -399,7 +398,6 @@ static void do_version_ntree_242_2(bNodeTree *ntree)
else {
ImageUser *iuser = node->storage = MEM_callocN(sizeof(ImageUser), "node image user");
iuser->sfra = 1;
- iuser->ok = 1;
}
}
}
@@ -463,8 +461,6 @@ static void do_version_constraints_245(ListBase *lb)
}
}
-/* NOTE: this version patch is intended for versions < 2.52.2,
- * but was initially introduced in 2.27 already. */
void blo_do_version_old_trackto_to_constraints(Object *ob)
{
/* create new trackto constraint from the relationship */
@@ -1863,7 +1859,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (bmain->subversionfile < 4) {
for (sce = bmain->scenes.first; sce; sce = sce->id.next) {
sce->r.bake_mode = 1; /* prevent to include render stuff here */
- sce->r.bake_filter = 16;
+ sce->r.bake_margin = 16;
+ sce->r.bake_margin_type = R_BAKE_ADJACENT_FACES;
sce->r.bake_flag = R_BAKE_CLEAR;
}
}
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index cd365b6be78..064d7977c68 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -27,10 +27,6 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#ifdef WITH_INTERNATIONAL
-# include "BLT_translation.h"
-#endif
-
#include "DNA_anim_types.h"
#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
@@ -53,6 +49,16 @@
#include "wm_event_types.h"
+/* Don't use translation strings in versioning!
+ * These depend on the preferences already being read.
+ * If this is important we can set the translations as part of versioning preferences,
+ * however that should only be done if there are important use-cases. */
+#if 0
+# include "BLT_translation.h"
+#else
+# define N_(msgid) msgid
+#endif
+
/* For versioning we only ever want to manipulate preferences passed in. */
#define U BLI_STATIC_ASSERT(false, "Global 'U' not allowed, only use arguments passed in!")
@@ -60,10 +66,6 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
{
#define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST(userdef, ver, subver)
- if (!USER_VERSION_ATLEAST(280, 20)) {
- memcpy(btheme, &U_theme_default, sizeof(*btheme));
- }
-
#define FROM_DEFAULT_V4_UCHAR(member) copy_v4_v4_uchar(btheme->member, U_theme_default.member)
if (!USER_VERSION_ATLEAST(280, 25)) {
@@ -301,6 +303,40 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
}
}
+ if (!USER_VERSION_ATLEAST(300, 33)) {
+ /* Adjust the frame node alpha now that it is used differently. */
+ btheme->space_node.movie[3] = U_theme_default.space_node.movie[3];
+ }
+
+ if (!USER_VERSION_ATLEAST(300, 34)) {
+ btheme->tui.panel_roundness = 0.4f;
+ }
+
+ if (!USER_VERSION_ATLEAST(300, 37)) {
+ btheme->space_node.dash_alpha = 0.5f;
+ }
+
+ if (!USER_VERSION_ATLEAST(300, 39)) {
+ FROM_DEFAULT_V4_UCHAR(space_node.grid);
+ btheme->space_node.grid_levels = 7;
+ }
+
+ if (!USER_VERSION_ATLEAST(300, 41)) {
+ memcpy(btheme, &U_theme_default, sizeof(*btheme));
+ }
+
+ /* Again reset the theme, but only if stored with an early 3.1 alpha version. Some changes were
+ * done in the release branch and then merged into the 3.1 branch (master). So the previous reset
+ * wouldn't work for people who saved their preferences with a 3.1 build meanwhile. But we still
+ * don't want to reset theme changes stored in the eventual 3.0 release once opened in a 3.1
+ * build. */
+ if (userdef->versionfile > 300 && !USER_VERSION_ATLEAST(301, 1)) {
+ memcpy(btheme, &U_theme_default, sizeof(*btheme));
+ }
+
+ if (!USER_VERSION_ATLEAST(301, 2)) {
+ FROM_DEFAULT_V4_UCHAR(space_sequencer.mask);
+ }
/**
* Versioning code until next subversion bump goes here.
*
@@ -363,7 +399,6 @@ static bool keymap_item_has_invalid_wm_context_data_path(wmKeyMapItem *kmi,
return false;
}
-/* patching UserDef struct and Themes */
void blo_do_versions_userdef(UserDef *userdef)
{
/* #UserDef & #Main happen to have the same struct member. */
@@ -534,8 +569,8 @@ void blo_do_versions_userdef(UserDef *userdef)
}
if (!USER_VERSION_ATLEAST(257, 0)) {
- /* clear "AUTOKEY_FLAG_ONLYKEYINGSET" flag from userprefs,
- * so that it doesn't linger around from old configs like a ghost */
+ /* Clear #AUTOKEY_FLAG_ONLYKEYINGSET flag from user-preferences,
+ * so that it doesn't linger around from old configurations like a ghost. */
userdef->autokey_flag &= ~AUTOKEY_FLAG_ONLYKEYINGSET;
}
@@ -676,8 +711,6 @@ void blo_do_versions_userdef(UserDef *userdef)
}
if (!USER_VERSION_ATLEAST(280, 38)) {
-
- /* (keep this block even if it becomes empty). */
copy_v4_fl4(userdef->light_param[0].vec, -0.580952, 0.228571, 0.781185, 0.0);
copy_v4_fl4(userdef->light_param[0].col, 0.900000, 0.900000, 0.900000, 1.000000);
copy_v4_fl4(userdef->light_param[0].spec, 0.318547, 0.318547, 0.318547, 1.000000);
@@ -710,8 +743,6 @@ void blo_do_versions_userdef(UserDef *userdef)
}
if (!USER_VERSION_ATLEAST(280, 41)) {
- /* (keep this block even if it becomes empty). */
-
if (userdef->pie_tap_timeout == 0) {
userdef->pie_tap_timeout = 20;
}
@@ -768,7 +799,6 @@ void blo_do_versions_userdef(UserDef *userdef)
}
if (!USER_VERSION_ATLEAST(280, 62)) {
- /* (keep this block even if it becomes empty). */
if (userdef->vbotimeout == 0) {
userdef->vbocollectrate = 60;
userdef->vbotimeout = 120;
@@ -903,6 +933,35 @@ void blo_do_versions_userdef(UserDef *userdef)
userdef->flag &= ~USER_FLAG_UNUSED_5;
}
+ if (!USER_VERSION_ATLEAST(300, 38)) {
+ /* Patch to set Dupli Lattice/Camera/Speaker. */
+ userdef->dupflag |= USER_DUP_LATTICE;
+ userdef->dupflag |= USER_DUP_CAMERA;
+ userdef->dupflag |= USER_DUP_SPEAKER;
+ }
+
+ if (!USER_VERSION_ATLEAST(300, 40)) {
+ /* Rename the default asset library from "Default" to "User Library". This isn't bullet proof
+ * since it doesn't handle translations and ignores user changes. But this was an alpha build
+ * (experimental) feature and the name is just for display in the UI anyway. So it doesn't have
+ * to work perfectly at all. */
+ LISTBASE_FOREACH (bUserAssetLibrary *, asset_library, &userdef->asset_libraries) {
+ /* Ignores translations, since that would depend on the current preferences (global `U`). */
+ if (STREQ(asset_library->name, "Default")) {
+ BKE_preferences_asset_library_name_set(
+ userdef, asset_library, BKE_PREFS_ASSET_LIBRARY_DEFAULT_NAME);
+ }
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(300, 40)) {
+ LISTBASE_FOREACH (uiStyle *, style, &userdef->uistyles) {
+ const int default_title_points = 11; /* UI_DEFAULT_TITLE_POINTS */
+ style->paneltitle.points = default_title_points;
+ style->grouplabel.points = default_title_points;
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 56ff7151cb1..aa3eef4b475 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -50,7 +50,7 @@
* Almost all data in Blender are structures. Each struct saved
* gets a BHead header. With BHead the struct can be linked again
* and compared with #StructDNA.
-
+ *
* WRITE
* =====
*
@@ -1028,7 +1028,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
/* prevent mem checkers from complaining */
memset(fg._pad, 0, sizeof(fg._pad));
- memset(fg.filename, 0, sizeof(fg.filename));
+ memset(fg.filepath, 0, sizeof(fg.filepath));
memset(fg.build_hash, 0, sizeof(fg.build_hash));
fg._pad1 = NULL;
@@ -1045,7 +1045,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
fg.globalf = G.f;
/* Write information needed for recovery. */
if (fileflags & G_FILE_RECOVER_WRITE) {
- BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename));
+ STRNCPY(fg.filepath, mainvar->filepath);
}
sprintf(subvstr, "%4d", BLENDER_FILE_SUBVERSION);
memcpy(fg.subvstr, subvstr, 4);
@@ -1312,15 +1312,15 @@ static bool do_history(const char *name, ReportList *reports)
/** \name File Writing (Public)
* \{ */
-/**
- * \return Success.
- */
bool BLO_write_file(Main *mainvar,
const char *filepath,
const int write_flags,
const struct BlendFileWriteParams *params,
ReportList *reports)
{
+ BLI_assert(!BLI_path_is_rel(filepath));
+ BLI_assert(BLI_path_is_abs_from_cwd(filepath));
+
char tempname[FILE_MAX + 1];
WriteWrap ww;
@@ -1329,10 +1329,12 @@ bool BLO_write_file(Main *mainvar,
const bool use_save_as_copy = params->use_save_as_copy;
const bool use_userdef = params->use_userdef;
const BlendThumbnail *thumb = params->thumb;
+ const bool relbase_valid = (mainvar->filepath[0] != '\0');
/* path backup/restore */
void *path_list_backup = NULL;
- const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
+ const eBPathForeachFlag path_list_flag = (BKE_BPATH_FOREACH_PATH_SKIP_LINKED |
+ BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE);
if (G.debug & G_DEBUG_IO && mainvar->lock != NULL) {
BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* save to disk");
@@ -1351,35 +1353,47 @@ bool BLO_write_file(Main *mainvar,
return 0;
}
+ if (remap_mode == BLO_WRITE_PATH_REMAP_ABSOLUTE) {
+ /* Paths will already be absolute, no remapping to do. */
+ if (relbase_valid == false) {
+ remap_mode = BLO_WRITE_PATH_REMAP_NONE;
+ }
+ }
+
/* Remapping of relative paths to new file location. */
if (remap_mode != BLO_WRITE_PATH_REMAP_NONE) {
if (remap_mode == BLO_WRITE_PATH_REMAP_RELATIVE) {
- /* Make all relative as none of the existing paths can be relative in an unsaved document.
- */
- if (G.relbase_valid == false) {
+ /* Make all relative as none of the existing paths can be relative in an unsaved document. */
+ if (relbase_valid == false) {
remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE_ALL;
}
}
+ /* The source path only makes sense to set if the file was saved (`relbase_valid`). */
char dir_src[FILE_MAX];
char dir_dst[FILE_MAX];
- BLI_split_dir_part(mainvar->name, dir_src, sizeof(dir_src));
- BLI_split_dir_part(filepath, dir_dst, sizeof(dir_dst));
- /* Just in case there is some subtle difference. */
- BLI_path_normalize(mainvar->name, dir_dst);
- BLI_path_normalize(mainvar->name, dir_src);
+ /* Normalize the paths in case there is some subtle difference (so they can be compared). */
+ if (relbase_valid) {
+ BLI_split_dir_part(mainvar->filepath, dir_src, sizeof(dir_src));
+ BLI_path_normalize(NULL, dir_src);
+ }
+ else {
+ dir_src[0] = '\0';
+ }
+ BLI_split_dir_part(filepath, dir_dst, sizeof(dir_dst));
+ BLI_path_normalize(NULL, dir_dst);
/* Only for relative, not relative-all, as this means making existing paths relative. */
if (remap_mode == BLO_WRITE_PATH_REMAP_RELATIVE) {
- if (G.relbase_valid && (BLI_path_cmp(dir_dst, dir_src) == 0)) {
+ if (relbase_valid && (BLI_path_cmp(dir_dst, dir_src) == 0)) {
/* Saved to same path. Nothing to do. */
remap_mode = BLO_WRITE_PATH_REMAP_NONE;
}
}
else if (remap_mode == BLO_WRITE_PATH_REMAP_ABSOLUTE) {
- if (G.relbase_valid == false) {
+ if (relbase_valid == false) {
/* Unsaved, all paths are absolute.Even if the user manages to set a relative path,
* there is no base-path that can be used to make it absolute. */
remap_mode = BLO_WRITE_PATH_REMAP_NONE;
@@ -1395,6 +1409,7 @@ bool BLO_write_file(Main *mainvar,
switch (remap_mode) {
case BLO_WRITE_PATH_REMAP_RELATIVE:
/* Saved, make relative paths relative to new location (if possible). */
+ BLI_assert(relbase_valid);
BKE_bpath_relative_rebase(mainvar, dir_src, dir_dst, NULL);
break;
case BLO_WRITE_PATH_REMAP_RELATIVE_ALL:
@@ -1403,6 +1418,7 @@ bool BLO_write_file(Main *mainvar,
break;
case BLO_WRITE_PATH_REMAP_ABSOLUTE:
/* Make all absolute (when requested or unsaved). */
+ BLI_assert(relbase_valid);
BKE_bpath_absolute_convert(mainvar, dir_src, NULL);
break;
case BLO_WRITE_PATH_REMAP_NONE:
@@ -1452,9 +1468,6 @@ bool BLO_write_file(Main *mainvar,
return 1;
}
-/**
- * \return Success.
- */
bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags)
{
bool use_userdef = false;
@@ -1577,9 +1590,6 @@ void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr
BLO_write_raw(writer, sizeof(float[3]) * (size_t)num, data_ptr);
}
-/**
- * Write a null terminated string.
- */
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
{
if (data_ptr != NULL) {
@@ -1587,10 +1597,6 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr)
}
}
-/**
- * Sometimes different data is written depending on whether the file is saved to disk or used for
- * undo. This function returns true when the current file-writing is done for undo.
- */
bool BLO_write_is_undo(BlendWriter *writer)
{
return writer->wd->use_memfile;
diff --git a/source/blender/blenloader/tests/blendfile_loading_base_test.cc b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
index 8afa631ffc5..7a8afbcb227 100644
--- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc
+++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
@@ -21,14 +21,17 @@
#include "BKE_appdir.h"
#include "BKE_blender.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_mball_tessellate.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_scene.h"
+#include "BKE_vfont.h"
#include "BLI_path_util.h"
#include "BLI_threads.h"
@@ -43,11 +46,15 @@
#include "IMB_imbuf.h"
+#include "ED_datafiles.h"
+
#include "RNA_define.h"
#include "WM_api.h"
#include "wm.h"
+#include "GHOST_Path-api.h"
+
#include "CLG_log.h"
void BlendfileLoadingBaseTest::SetUpTestCase()
@@ -65,11 +72,12 @@ void BlendfileLoadingBaseTest::SetUpTestCase()
BKE_idtype_init();
BKE_appdir_init();
IMB_init();
- BKE_images_init();
BKE_modifier_init();
DEG_register_node_types();
RNA_init();
BKE_node_system_init();
+ BKE_callback_global_init();
+ BKE_vfont_builtin_register(datatoc_bfont_pfb, datatoc_bfont_pfb_size);
G.background = true;
G.factory_startup = true;
@@ -93,6 +101,7 @@ void BlendfileLoadingBaseTest::TearDownTestCase()
RNA_exit();
DEG_free_node_types();
+ GHOST_DisposeSystemPaths();
DNA_sdna_current_free();
BLI_threadapi_exit();
@@ -107,6 +116,7 @@ void BlendfileLoadingBaseTest::TearDownTestCase()
void BlendfileLoadingBaseTest::TearDown()
{
+ BKE_mball_cubeTable_free();
depsgraph_free();
blendfile_free();
diff --git a/source/blender/blentranslation/BLT_lang.h b/source/blender/blentranslation/BLT_lang.h
index dcd4de10416..1a0981613a1 100644
--- a/source/blender/blentranslation/BLT_lang.h
+++ b/source/blender/blentranslation/BLT_lang.h
@@ -46,6 +46,15 @@ const char *BLT_lang_get(void);
* Non-null elements are always MEM_mallocN'ed, it's the caller's responsibility to free them.
* NOTE: Always available, even in non-WITH_INTERNATIONAL builds.
*/
+/**
+ * Get locale's elements (if relevant pointer is not NULL and element actually exists, e.g.
+ * if there is no variant,
+ * *variant and *language_variant will always be NULL).
+ * Non-null elements are always MEM_mallocN'ed, it's the caller's responsibility to free them.
+ *
+ * \note Keep that one always available, you never know,
+ * may become useful even in no #WITH_INTERNATIONAL context.
+ */
void BLT_lang_locale_explode(const char *locale,
char **language,
char **country,
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index 341e648443e..21296143226 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -44,6 +44,11 @@ const char *BLT_translate_do_iface(const char *msgctxt, const char *msgid);
const char *BLT_translate_do_tooltip(const char *msgctxt, const char *msgid);
const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid);
+/**
+ * Note that "lang" here is the _output_ display language. We used to restrict
+ * IME for keyboard _input_ language because our multilingual font was only used
+ * when some output languages were selected. That font is used all the time now.
+ */
bool BLT_lang_is_ime_supported(void);
/* The "translation-marker" macro. */
diff --git a/source/blender/blentranslation/intern/blt_lang.c b/source/blender/blentranslation/intern/blt_lang.c
index 91e8a81aec0..01f7574bd34 100644
--- a/source/blender/blentranslation/intern/blt_lang.c
+++ b/source/blender/blentranslation/intern/blt_lang.c
@@ -282,7 +282,6 @@ void BLT_lang_set(const char *str)
IMB_thumb_clear_translations();
}
-/* Get the current locale (short code, e.g. es_ES). */
const char *BLT_lang_get(void)
{
#ifdef WITH_INTERNATIONAL
@@ -303,15 +302,6 @@ const char *BLT_lang_get(void)
#undef LOCALE
#undef ULANGUAGE
-/**
- * Get locale's elements (if relevant pointer is not NULL and element actually exists, e.g.
- * if there is no variant,
- * *variant and *language_variant will always be NULL).
- * Non-null elements are always MEM_mallocN'ed, it's the caller's responsibility to free them.
- *
- * \note Keep that one always available, you never know,
- * may become useful even in no #WITH_INTERNATIONAL context.
- */
void BLT_lang_locale_explode(const char *locale,
char **language,
char **country,
@@ -372,9 +362,6 @@ void BLT_lang_locale_explode(const char *locale,
}
}
-/* Note that "lang" here is the _output_ display language. We used to restrict
- * IME for keyboard _input_ language because our multilingual font was only used
- * when some output languages were selected. That font is used all the time now. */
bool BLT_lang_is_ime_supported(void)
{
#ifdef WITH_INPUT_IME
diff --git a/source/blender/blentranslation/msgfmt/CMakeLists.txt b/source/blender/blentranslation/msgfmt/CMakeLists.txt
index 4b8f0878c75..a535d5b8e2d 100644
--- a/source/blender/blentranslation/msgfmt/CMakeLists.txt
+++ b/source/blender/blentranslation/msgfmt/CMakeLists.txt
@@ -30,7 +30,6 @@ set(SRC
msgfmt.c
)
-setup_libdirs()
add_cc_flags_custom_test(msgfmt)
if(WIN32)
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index ec282888ffa..e2ed005cf9e 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -98,8 +98,10 @@ set(SRC
intern/bmesh_marking.h
intern/bmesh_mesh.c
intern/bmesh_mesh.h
- intern/bmesh_mesh_convert.c
+ intern/bmesh_mesh_convert.cc
intern/bmesh_mesh_convert.h
+ intern/bmesh_mesh_debug.c
+ intern/bmesh_mesh_debug.h
intern/bmesh_mesh_duplicate.c
intern/bmesh_mesh_duplicate.h
intern/bmesh_mesh_normals.c
@@ -191,7 +193,7 @@ set(LIB
if(WITH_BULLET)
list(APPEND INC_SYS
${BULLET_INCLUDE_DIRS}
- "../../../intern/rigidbody/"
+ ../../../intern/rigidbody
)
if(NOT WITH_SYSTEM_BULLET)
list(APPEND LIB
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index 40db423ba2f..fc97c55091a 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -214,6 +214,7 @@ extern "C" {
#include "intern/bmesh_marking.h"
#include "intern/bmesh_mesh.h"
#include "intern/bmesh_mesh_convert.h"
+#include "intern/bmesh_mesh_debug.h"
#include "intern/bmesh_mesh_duplicate.h"
#include "intern/bmesh_mesh_normals.h"
#include "intern/bmesh_mesh_partial_update.h"
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index 6f7b2cbc79f..a127089ad2c 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -31,6 +31,7 @@
#include "BKE_customdata.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "bmesh.h"
@@ -38,11 +39,6 @@
#define SELECT 1
-/**
- * Fill in a vertex array from an edge array.
- *
- * \returns false if any verts aren't found.
- */
bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len)
{
int i, i_prev = len - 1;
@@ -56,11 +52,6 @@ bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len)
return true;
}
-/**
- * Fill in an edge array from a vertex array (connected polygon loop).
- *
- * \returns false if any edges aren't found.
- */
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
{
int i, i_prev = len - 1;
@@ -74,10 +65,6 @@ bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
return true;
}
-/**
- * Fill in an edge array from a vertex array (connected polygon loop).
- * Creating edges as-needed.
- */
void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len)
{
int i, i_prev = len - 1;
@@ -92,20 +79,6 @@ void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr,
static void bm_loop_attrs_copy(
BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, CustomDataMask mask_exclude);
-/**
- * \brief Make Quad/Triangle
- *
- * Creates a new quad or triangle from a list of 3 or 4 vertices.
- * If \a no_double is true, then a check is done to see if a face
- * with these vertices already exists and returns it instead.
- *
- * If a pointer to an example face is provided, its custom data
- * and properties will be copied to the new face.
- *
- * \note The winding of the face is determined by the order
- * of the vertices in the vertex array.
- */
-
BMFace *BM_face_create_quad_tri(BMesh *bm,
BMVert *v1,
BMVert *v2,
@@ -118,16 +91,6 @@ BMFace *BM_face_create_quad_tri(BMesh *bm,
return BM_face_create_verts(bm, vtar, v4 ? 4 : 3, f_example, create_flag, true);
}
-/**
- * \brief copies face loop data from shared adjacent faces.
- *
- * \param filter_fn: A function that filters the source loops before copying
- * (don't always want to copy all).
- *
- * \note when a matching edge is found, both loops of that edge are copied
- * this is done since the face may not be completely surrounded by faces,
- * this way: a quad with 2 connected quads on either side will still get all 4 loops updated
- */
void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data)
{
BMLoop *l_first;
@@ -259,20 +222,6 @@ error:
return false;
}
-/**
- * \brief Make NGon
- *
- * Makes an ngon from an unordered list of edges.
- * Verts \a v1 and \a v2 define the winding of the new face.
- *
- * \a edges are not required to be ordered, simply to form
- * a single closed loop as a whole.
- *
- * \note While this function will work fine when the edges
- * are already sorted, if the edges are always going to be sorted,
- * #BM_face_create should be considered over this function as it
- * avoids some unnecessary work.
- */
BMFace *BM_face_create_ngon(BMesh *bm,
BMVert *v1,
BMVert *v2,
@@ -293,14 +242,6 @@ BMFace *BM_face_create_ngon(BMesh *bm,
return NULL;
}
-/**
- * Create an ngon from an array of sorted verts
- *
- * Special features this has over other functions.
- * - Optionally calculate winding based on surrounding edges.
- * - Optionally create edges between vertices.
- * - Uses verts so no need to find edges (handy when you only have verts)
- */
BMFace *BM_face_create_ngon_verts(BMesh *bm,
BMVert **vert_arr,
const int len,
@@ -366,22 +307,6 @@ BMFace *BM_face_create_ngon_verts(BMesh *bm,
bm, v_winding[winding[0]], v_winding[winding[1]], edge_arr, len, f_example, create_flag);
}
-/**
- * Makes an NGon from an un-ordered set of verts
- *
- * assumes...
- * - that verts are only once in the list.
- * - that the verts have roughly planer bounds
- * - that the verts are roughly circular
- * there can be concave areas but overlapping folds from the center point will fail.
- *
- * a brief explanation of the method used
- * - find the center point
- * - find the normal of the vcloud
- * - order the verts around the face based on their angle to the normal vector at the center point.
- *
- * \note Since this is a vcloud there is no direction.
- */
void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
{
struct SortIntByFloat *vang = BLI_array_alloca(vang, len);
@@ -466,13 +391,6 @@ static void bm_face_attrs_copy(
f_dst->mat_nr = f_src->mat_nr;
}
-/* BMESH_TODO: Special handling for hide flags? */
-/* BMESH_TODO: swap src/dst args, everywhere else in bmesh does other way round */
-
-/**
- * Copies attributes, e.g. customdata, header flags, etc, from one element
- * to another of the same type.
- */
void BM_elem_attrs_copy_ex(BMesh *bm_src,
BMesh *bm_dst,
const void *ele_src_v,
@@ -480,6 +398,9 @@ void BM_elem_attrs_copy_ex(BMesh *bm_src,
const char hflag_mask,
const uint64_t cd_mask_exclude)
{
+ /* TODO: Special handling for hide flags? */
+ /* TODO: swap src/dst args, everywhere else in bmesh does other way round. */
+
const BMHeader *ele_src = ele_src_v;
BMHeader *ele_dst = ele_dst_v;
@@ -589,6 +510,53 @@ static BMFace *bm_mesh_copy_new_face(
return f_new;
}
+void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst,
+ const Mesh *me_src_array[],
+ const int me_src_array_len,
+ const BMAllocTemplate *allocsize)
+
+{
+ if (allocsize == NULL) {
+ allocsize = &bm_mesh_allocsize_default;
+ }
+
+ char cd_flag = 0;
+
+ for (int i = 0; i < me_src_array_len; i++) {
+ const Mesh *me_src = me_src_array[i];
+ if (i == 0) {
+ CustomData_copy(&me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0);
+ CustomData_copy(&me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0);
+ CustomData_copy(&me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0);
+ CustomData_copy(&me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0);
+ }
+ else {
+ CustomData_merge(&me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0);
+ CustomData_merge(&me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0);
+ CustomData_merge(&me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0);
+ CustomData_merge(&me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0);
+ }
+
+ cd_flag |= me_src->cd_flag;
+ }
+
+ cd_flag |= BM_mesh_cd_flag_from_bmesh(bm_dst);
+
+ CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT);
+ CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE);
+ CustomData_bmesh_init_pool(&bm_dst->ldata, allocsize->totloop, BM_LOOP);
+ CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE);
+
+ BM_mesh_cd_flag_apply(bm_dst, cd_flag);
+}
+
+void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst,
+ const Mesh *me_src,
+ const BMAllocTemplate *allocsize)
+{
+ BM_mesh_copy_init_customdata_from_mesh_array(bm_dst, &me_src, 1, allocsize);
+}
+
void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTemplate *allocsize)
{
if (allocsize == NULL) {
@@ -606,15 +574,6 @@ void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTem
CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE);
}
-/**
- * Similar to #BM_mesh_copy_init_customdata but copies all layers ignoring
- * flags like #CD_FLAG_NOCOPY.
- *
- * \param bm_dst: BMesh whose custom-data layers will be added.
- * \param bm_src: BMesh whose custom-data layers will be copied.
- * \param htype: Specifies which custom-data layers will be initiated.
- * \param allocsize: Initialize the memory-pool before use (may be an estimate).
- */
void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst,
BMesh *bm_src,
const char htype,
@@ -766,7 +725,6 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
return bm_new;
}
-/* ME -> BM */
char BM_vert_flag_from_mflag(const char mflag)
{
return (((mflag & SELECT) ? BM_ELEM_SELECT : 0) | ((mflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0));
@@ -784,7 +742,6 @@ char BM_face_flag_from_mflag(const char mflag)
((mflag & ME_SMOOTH) ? BM_ELEM_SMOOTH : 0) | ((mflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0));
}
-/* BM -> ME */
char BM_vert_flag_to_mflag(BMVert *v)
{
const char hflag = v->head.hflag;
diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h
index f5102283ede..008219165a8 100644
--- a/source/blender/bmesh/intern/bmesh_construct.h
+++ b/source/blender/bmesh/intern/bmesh_construct.h
@@ -23,61 +23,168 @@
#include "bmesh_core.h"
struct BMAllocTemplate;
+struct Mesh;
-bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len);
+/**
+ * Fill in a vertex array from an edge array.
+ *
+ * \returns false if any verts aren't found.
+ */
+bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, int len);
-bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len);
-void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len);
+/**
+ * Fill in an edge array from a vertex array (connected polygon loop).
+ *
+ * \returns false if any edges aren't found.
+ */
+bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, int len);
+/**
+ * Fill in an edge array from a vertex array (connected polygon loop).
+ * Creating edges as-needed.
+ */
+void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, int len);
-/* sort before creation */
+/**
+ * Makes an NGon from an un-ordered set of verts.
+ *
+ * Assumes:
+ * - that verts are only once in the list.
+ * - that the verts have roughly planer bounds
+ * - that the verts are roughly circular
+ *
+ * There can be concave areas but overlapping folds from the center point will fail.
+ *
+ * A brief explanation of the method used
+ * - find the center point
+ * - find the normal of the vertex-cloud
+ * - order the verts around the face based on their angle to the normal vector at the center point.
+ *
+ * \note Since this is a vertex-cloud there is no direction.
+ */
void BM_verts_sort_radial_plane(BMVert **vert_arr, int len);
+/**
+ * \brief Make Quad/Triangle
+ *
+ * Creates a new quad or triangle from a list of 3 or 4 vertices.
+ * If \a no_double is true, then a check is done to see if a face
+ * with these vertices already exists and returns it instead.
+ *
+ * If a pointer to an example face is provided, its custom data
+ * and properties will be copied to the new face.
+ *
+ * \note The winding of the face is determined by the order
+ * of the vertices in the vertex array.
+ */
BMFace *BM_face_create_quad_tri(BMesh *bm,
BMVert *v1,
BMVert *v2,
BMVert *v3,
BMVert *v4,
const BMFace *f_example,
- const eBMCreateFlag create_flag);
+ eBMCreateFlag create_flag);
+/**
+ * \brief copies face loop data from shared adjacent faces.
+ *
+ * \param filter_fn: A function that filters the source loops before copying
+ * (don't always want to copy all).
+ *
+ * \note when a matching edge is found, both loops of that edge are copied
+ * this is done since the face may not be completely surrounded by faces,
+ * this way: a quad with 2 connected quads on either side will still get all 4 loops updated
+ */
void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data);
+/**
+ * \brief Make NGon
+ *
+ * Makes an ngon from an unordered list of edges.
+ * Verts \a v1 and \a v2 define the winding of the new face.
+ *
+ * \a edges are not required to be ordered, simply to form
+ * a single closed loop as a whole.
+ *
+ * \note While this function will work fine when the edges
+ * are already sorted, if the edges are always going to be sorted,
+ * #BM_face_create should be considered over this function as it
+ * avoids some unnecessary work.
+ */
BMFace *BM_face_create_ngon(BMesh *bm,
BMVert *v1,
BMVert *v2,
BMEdge **edges,
- const int len,
+ int len,
const BMFace *f_example,
- const eBMCreateFlag create_flag);
+ eBMCreateFlag create_flag);
+/**
+ * Create an ngon from an array of sorted verts
+ *
+ * Special features this has over other functions.
+ * - Optionally calculate winding based on surrounding edges.
+ * - Optionally create edges between vertices.
+ * - Uses verts so no need to find edges (handy when you only have verts)
+ */
BMFace *BM_face_create_ngon_verts(BMesh *bm,
BMVert **vert_arr,
- const int len,
+ int len,
const BMFace *f_example,
- const eBMCreateFlag create_flag,
- const bool calc_winding,
- const bool create_edges);
+ eBMCreateFlag create_flag,
+ bool calc_winding,
+ bool create_edges);
+/**
+ * Copies attributes, e.g. customdata, header flags, etc, from one element
+ * to another of the same type.
+ */
void BM_elem_attrs_copy_ex(BMesh *bm_src,
BMesh *bm_dst,
const void *ele_src_v,
void *ele_dst_v,
- const char hflag_mask,
- const uint64_t cd_mask_exclude);
+ char hflag_mask,
+ uint64_t cd_mask_exclude);
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v);
void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v);
+/**
+ * Initialize the `bm_dst` layers in preparation for populating it's contents with multiple meshes.
+ * Typically done using multiple calls to #BM_mesh_bm_from_me with the same `bm` argument).
+ *
+ * \note While the custom-data layers of all meshes are created, the active layers are set
+ * by the first instance mesh containing that layer type.
+ * This means the first mesh should always be the main mesh (from the user perspective),
+ * as this is the mesh they have control over (active UV layer for rendering for example).
+ */
+void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst,
+ const struct Mesh *me_src_array[],
+ int me_src_array_len,
+ const struct BMAllocTemplate *allocsize);
+void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst,
+ const struct Mesh *me_src,
+ const struct BMAllocTemplate *allocsize);
void BM_mesh_copy_init_customdata(BMesh *bm_dst,
BMesh *bm_src,
const struct BMAllocTemplate *allocsize);
+/**
+ * Similar to #BM_mesh_copy_init_customdata but copies all layers ignoring
+ * flags like #CD_FLAG_NOCOPY.
+ *
+ * \param bm_dst: BMesh whose custom-data layers will be added.
+ * \param bm_src: BMesh whose custom-data layers will be copied.
+ * \param htype: Specifies which custom-data layers will be initiated.
+ * \param allocsize: Initialize the memory-pool before use (may be an estimate).
+ */
void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst,
BMesh *bm_src,
- const char htype,
+ char htype,
const struct BMAllocTemplate *allocsize);
BMesh *BM_mesh_copy(BMesh *bm_old);
-char BM_face_flag_from_mflag(const char mflag);
-char BM_edge_flag_from_mflag(const short mflag);
-char BM_vert_flag_from_mflag(const char mflag);
+char BM_face_flag_from_mflag(char mflag);
+char BM_edge_flag_from_mflag(short mflag);
+/* ME -> BM */
+char BM_vert_flag_from_mflag(char mflag);
char BM_face_flag_to_mflag(BMFace *f);
short BM_edge_flag_to_mflag(BMEdge *e);
+/* BM -> ME */
char BM_vert_flag_to_mflag(BMVert *v);
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index e72c689ddfb..1d7d10de96f 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -52,9 +52,6 @@
#endif
-/**
- * \brief Main function for creating a new vertex.
- */
BMVert *BM_vert_create(BMesh *bm,
const float co[3],
const BMVert *v_example,
@@ -137,13 +134,6 @@ BMVert *BM_vert_create(BMesh *bm,
return v;
}
-/**
- * \brief Main function for creating a new edge.
- *
- * \note Duplicate edges are supported by the API however users should _never_ see them.
- * so unless you need a unique edge or know the edge won't exist,
- * you should call with \a no_double = true.
- */
BMEdge *BM_edge_create(
BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
{
@@ -416,15 +406,6 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm)
return f;
}
-/**
- * Main face creation function
- *
- * \param bm: The mesh
- * \param verts: A sorted array of verts size of len
- * \param edges: A sorted array of edges size of len
- * \param len: Length of the face
- * \param create_flag: Options for creating the face
- */
BMFace *BM_face_create(BMesh *bm,
BMVert **verts,
BMEdge **edges,
@@ -494,9 +475,6 @@ BMFace *BM_face_create(BMesh *bm,
return f;
}
-/**
- * Wrapper for #BM_face_create when you don't have an edge array
- */
BMFace *BM_face_create_verts(BMesh *bm,
BMVert **vert_arr,
const int len,
@@ -520,12 +498,6 @@ BMFace *BM_face_create_verts(BMesh *bm,
#ifndef NDEBUG
-/**
- * Check the element is valid.
- *
- * BMESH_TODO, when this raises an error the output is incredibly confusing.
- * need to have some nice way to print/debug what the heck's going on.
- */
int bmesh_elem_check(void *element, const char htype)
{
BMHeader *head = element;
@@ -833,10 +805,6 @@ static void bm_kill_only_loop(BMesh *bm, BMLoop *l)
BLI_mempool_free(bm->lpool, l);
}
-/**
- * kills all edges associated with \a f, along with any other faces containing
- * those edges
- */
void BM_face_edges_kill(BMesh *bm, BMFace *f)
{
BMEdge **edges = BLI_array_alloca(edges, f->len);
@@ -854,10 +822,6 @@ void BM_face_edges_kill(BMesh *bm, BMFace *f)
}
}
-/**
- * kills all verts associated with \a f, along with any other faces containing
- * those vertices
- */
void BM_face_verts_kill(BMesh *bm, BMFace *f)
{
BMVert **verts = BLI_array_alloca(verts, f->len);
@@ -875,9 +839,6 @@ void BM_face_verts_kill(BMesh *bm, BMFace *f)
}
}
-/**
- * Kills \a f and its loops.
- */
void BM_face_kill(BMesh *bm, BMFace *f)
{
#ifdef USE_BMESH_HOLES
@@ -922,10 +883,6 @@ void BM_face_kill(BMesh *bm, BMFace *f)
bm_kill_only_face(bm, f);
}
-/**
- * A version of #BM_face_kill which removes edges and verts
- * which have no remaining connected geometry.
- */
void BM_face_kill_loose(BMesh *bm, BMFace *f)
{
#ifdef USE_BMESH_HOLES
@@ -981,9 +938,6 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f)
bm_kill_only_face(bm, f);
}
-/**
- * kills \a e and all faces that use it.
- */
void BM_edge_kill(BMesh *bm, BMEdge *e)
{
while (e->l) {
@@ -996,9 +950,6 @@ void BM_edge_kill(BMesh *bm, BMEdge *e)
bm_kill_only_edge(bm, e);
}
-/**
- * kills \a v and all edges that use it.
- */
void BM_vert_kill(BMesh *bm, BMVert *v)
{
while (v->e) {
@@ -1025,15 +976,6 @@ static int UNUSED_FUNCTION(bm_loop_length)(BMLoop *l)
return i;
}
-/**
- * \brief Loop Reverse
- *
- * Changes the winding order of a face from CW to CCW or vice versa.
- *
- * \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`.
- * \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp,
- * (use when flipping normals, disable when mirroring, eg: symmetrize).
- */
void bmesh_kernel_loop_reverse(BMesh *bm,
BMFace *f,
const int cd_loop_mdisp_offset,
@@ -1192,20 +1134,6 @@ static bool bm_vert_is_manifold_flagged(BMVert *v, const char api_flag)
/* Mid-level Topology Manipulation Functions */
-/**
- * \brief Join Connected Faces
- *
- * Joins a collected group of faces into one. Only restriction on
- * the input data is that the faces must be connected to each other.
- *
- * \return The newly created combine BMFace.
- *
- * \note If a pair of faces share multiple edges,
- * the pair of faces will be joined at every edge.
- *
- * \note this is a generic, flexible join faces function,
- * almost everything uses this, including #BM_faces_join_pair
- */
BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
{
BMFace *f, *f_new;
@@ -1422,44 +1350,6 @@ static BMFace *bm_face_create__sfme(BMesh *bm, BMFace *f_example)
return f;
}
-/**
- * \brief Split Face Make Edge (SFME)
- *
- * \warning this is a low level function, most likely you want to use #BM_face_split()
- *
- * Takes as input two vertices in a single face.
- * An edge is created which divides the original face into two distinct regions.
- * One of the regions is assigned to the original face and it is closed off.
- * The second region has a new face assigned to it.
- *
- * \par Examples:
- * <pre>
- * Before: After:
- * +--------+ +--------+
- * | | | |
- * | | | f1 |
- * v1 f1 v2 v1======v2
- * | | | f2 |
- * | | | |
- * +--------+ +--------+
- * </pre>
- *
- * \note the input vertices can be part of the same edge. This will
- * result in a two edged face. This is desirable for advanced construction
- * tools and particularly essential for edge bevel. Because of this it is
- * up to the caller to decide what to do with the extra edge.
- *
- * \note If \a holes is NULL, then both faces will lose
- * all holes from the original face. Also, you cannot split between
- * a hole vert and a boundary vert; that case is handled by higher-
- * level wrapping functions (when holes are fully implemented, anyway).
- *
- * \note that holes represents which holes goes to the new face, and of
- * course this requires removing them from the existing face first, since
- * you cannot have linked list links inside multiple lists.
- *
- * \return A BMFace pointer
- */
BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
BMFace *f,
BMLoop *l_v1,
@@ -1599,24 +1489,6 @@ BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
return f2;
}
-/**
- * \brief Split Edge Make Vert (SEMV)
- *
- * Takes \a e edge and splits it into two, creating a new vert.
- * \a tv should be one end of \a e : the newly created edge
- * will be attached to that end and is returned in \a r_e.
- *
- * \par Examples:
- *
- * <pre>
- * E
- * Before: OV-------------TV
- * E RE
- * After: OV------NV-----TV
- * </pre>
- *
- * \return The newly created BMVert pointer.
- */
BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
{
BMLoop *l_next;
@@ -1770,36 +1642,6 @@ BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEd
return v_new;
}
-/**
- * \brief Join Edge Kill Vert (JEKV)
- *
- * Takes an edge \a e_kill and pointer to one of its vertices \a v_kill
- * and collapses the edge on that vertex.
- *
- * \par Examples:
- *
- * <pre>
- * Before: e_old e_kill
- * +-------+-------+
- * | | |
- * v_old v_kill v_target
- *
- * After: e_old
- * +---------------+
- * | |
- * v_old v_target
- * </pre>
- *
- * \par Restrictions:
- * KV is a vertex that must have a valance of exactly two. Furthermore
- * both edges in KV's disk cycle (OE and KE) must be unique (no double edges).
- *
- * \return The resulting edge, NULL for failure.
- *
- * \note This euler has the possibility of creating
- * faces with just 2 edges. It is up to the caller to decide what to do with
- * these faces.
- */
BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -1967,24 +1809,6 @@ BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
return NULL;
}
-/**
- * \brief Join Vert Kill Edge (JVKE)
- *
- * Collapse an edge, merging surrounding data.
- *
- * Unlike #BM_vert_collapse_edge & #bmesh_kernel_join_edge_kill_vert
- * which only handle 2 valence verts,
- * this can handle any number of connected edges/faces.
- *
- * <pre>
- * Before: -> After:
- * +-+-+-+ +-+-+-+
- * | | | | | \ / |
- * +-+-+-+ +--+--+
- * | | | | | / \ |
- * +-+-+-+ +-+-+-+
- * </pre>
- */
BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -2068,37 +1892,6 @@ BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
return v_target;
}
-/**
- * \brief Join Face Kill Edge (JFKE)
- *
- * Takes two faces joined by a single 2-manifold edge and fuses them together.
- * The edge shared by the faces must not be connected to any other edges which have
- * Both faces in its radial cycle
- *
- * \par Examples:
- * <pre>
- * A B
- * +--------+ +--------+
- * | | | |
- * | f1 | | f1 |
- * v1========v2 = Ok! v1==V2==v3 == Wrong!
- * | f2 | | f2 |
- * | | | |
- * +--------+ +--------+
- * </pre>
- *
- * In the example A, faces \a f1 and \a f2 are joined by a single edge,
- * and the euler can safely be used.
- * In example B however, \a f1 and \a f2 are joined by multiple edges and will produce an error.
- * The caller in this case should call #bmesh_kernel_join_edge_kill_vert on the extra edges
- * before attempting to fuse \a f1 and \a f2.
- *
- * \note The order of arguments decides whether or not certain per-face attributes are present
- * in the resultant face. For instance vertex winding, material index, smooth flags,
- * etc are inherited from \a f1, not \a f2.
- *
- * \return A BMFace pointer
- */
BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
{
BMLoop *l_iter, *l_f1 = NULL, *l_f2 = NULL;
@@ -2221,11 +2014,6 @@ BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEd
return f1;
}
-/**
- * Check if splicing vertices would create any double edges.
- *
- * \note assume caller will handle case where verts share an edge.
- */
bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
{
bool is_double = false;
@@ -2269,18 +2057,6 @@ bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
return is_double;
}
-/**
- * \brief Splice Vert
- *
- * Merges two verts into one
- * (\a v_src into \a v_dst, removing \a v_src).
- *
- * \return Success
- *
- * \warning This doesn't work for collapsing edges,
- * where \a v and \a vtarget are connected by an edge
- * (assert checks for this case).
- */
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
{
BMEdge *e;
@@ -2317,17 +2093,6 @@ BLI_INLINE bool bm_edge_supports_separate(const BMEdge *e)
return (e->l && e->l->radial_next != e->l);
}
-/**
- * \brief Separate Vert
- *
- * Separates all disjoint fans that meet at a vertex, making a unique
- * vertex for each region. returns an array of all resulting vertices.
- *
- * \note this is a low level function, bm_edge_separate needs to run on edges first
- * or, the faces sharing verts must not be sharing edges for them to split at least.
- *
- * \return Success
- */
void bmesh_kernel_vert_separate(
BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select)
{
@@ -2480,9 +2245,6 @@ static void bmesh_kernel_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separ
} while ((edges_separate = edges_separate->next));
}
-/**
- * High level function which wraps both #bmesh_kernel_vert_separate and #bmesh_kernel_edge_separate
- */
void BM_vert_separate(BMesh *bm,
BMVert *v,
BMEdge **e_in,
@@ -2516,9 +2278,6 @@ void BM_vert_separate(BMesh *bm,
}
}
-/**
- * A version of #BM_vert_separate which takes a flag.
- */
void BM_vert_separate_hflag(BMesh *bm,
BMVert *v,
const char hflag,
@@ -2584,16 +2343,6 @@ void BM_vert_separate_tested_edges(BMesh *UNUSED(bm),
/** \} */
-/**
- * \brief Splice Edge
- *
- * Splice two unique edges which share the same two vertices into one edge.
- * (\a e_src into \a e_dst, removing e_src).
- *
- * \return Success
- *
- * \note Edges must already have the same vertices.
- */
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
{
BMLoop *l;
@@ -2627,17 +2376,6 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
return true;
}
-/**
- * \brief Separate Edge
- *
- * Separates a single edge into two edge: the original edge and
- * a new edge that has only \a l_sep in its radial.
- *
- * \return Success
- *
- * \note Does nothing if \a l_sep is already the only loop in the
- * edge radial.
- */
void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select)
{
BMEdge *e_new;
@@ -2673,15 +2411,6 @@ void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool
BM_CHECK_ELEMENT(e);
}
-/**
- * \brief Un-glue Region Make Vert (URMV)
- *
- * Disconnects a face from its vertex fan at loop \a l_sep
- *
- * \return The newly created BMVert
- *
- * \note Will be a no-op and return original vertex if only two edges at that vertex.
- */
BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep)
{
BMVert *v_new = NULL;
@@ -2744,13 +2473,6 @@ BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep)
return v_new;
}
-/**
- * A version of #bmesh_kernel_unglue_region_make_vert that disconnects multiple loops at once.
- * The loops must all share the same vertex, can be in any order
- * and are all moved to use a single new vertex - which is returned.
- *
- * This function handles the details of finding fans boundaries.
- */
BMVert *bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len)
{
BMVert *v_sep = larr[0]->v;
@@ -2931,10 +2653,6 @@ static void bmesh_edge_vert_swap__recursive(BMEdge *e, BMVert *v_dst, BMVert *v_
} while ((l_iter = l_iter->radial_next) != l_first);
}
-/**
- * This function assumes l_sep is a part of a larger fan which has already been
- * isolated by calling #bmesh_kernel_edge_separate to segregate it radially.
- */
BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep)
{
BMVert *v_new = BM_vert_create(bm, l_sep->v->co, l_sep->v, BM_CREATE_NOP);
@@ -2944,11 +2662,6 @@ BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l
return v_new;
}
-/**
- * Avoid calling this where possible,
- * low level function so both face pointers remain intact but point to swapped data.
- * \note must be from the same bmesh.
- */
void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b)
{
BMLoop *l_iter, *l_first;
diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h
index 8f7580714ae..a885df51bd3 100644
--- a/source/blender/bmesh/intern/bmesh_core.h
+++ b/source/blender/bmesh/intern/bmesh_core.h
@@ -20,72 +20,172 @@
* \ingroup bmesh
*/
-BMFace *BM_face_copy(
- BMesh *bm_dst, BMesh *bm_src, BMFace *f, const bool copy_verts, const bool copy_edges);
+BMFace *BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f, bool copy_verts, bool copy_edges);
typedef enum eBMCreateFlag {
BM_CREATE_NOP = 0,
- /* faces and edges only */
+ /** Faces and edges only. */
BM_CREATE_NO_DOUBLE = (1 << 1),
- /* Skip CustomData - for all element types data,
- * use if we immediately write customdata into the element so this skips copying from 'example'
- * args or setting defaults, speeds up conversion when data is converted all at once. */
+ /**
+ * Skip custom-data - for all element types data,
+ * use if we immediately write custom-data into the element so this skips copying from 'example'
+ * arguments or setting defaults, speeds up conversion when data is converted all at once.
+ */
BM_CREATE_SKIP_CD = (1 << 2),
} eBMCreateFlag;
+/**
+ * \brief Main function for creating a new vertex.
+ */
BMVert *BM_vert_create(BMesh *bm,
const float co[3],
const BMVert *v_example,
- const eBMCreateFlag create_flag);
+ eBMCreateFlag create_flag);
+/**
+ * \brief Main function for creating a new edge.
+ *
+ * \note Duplicate edges are supported by the API however users should _never_ see them.
+ * so unless you need a unique edge or know the edge won't exist,
+ * you should call with \a no_double = true.
+ */
BMEdge *BM_edge_create(
- BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag);
+ BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, eBMCreateFlag create_flag);
+/**
+ * Main face creation function
+ *
+ * \param bm: The mesh
+ * \param verts: A sorted array of verts size of len
+ * \param edges: A sorted array of edges size of len
+ * \param len: Length of the face
+ * \param create_flag: Options for creating the face
+ */
BMFace *BM_face_create(BMesh *bm,
BMVert **verts,
BMEdge **edges,
- const int len,
+ int len,
const BMFace *f_example,
- const eBMCreateFlag create_flag);
+ eBMCreateFlag create_flag);
+/**
+ * Wrapper for #BM_face_create when you don't have an edge array
+ */
BMFace *BM_face_create_verts(BMesh *bm,
BMVert **vert_arr,
- const int len,
+ int len,
const BMFace *f_example,
- const eBMCreateFlag create_flag,
- const bool create_edges);
+ eBMCreateFlag create_flag,
+ bool create_edges);
+/**
+ * Kills all edges associated with \a f, along with any other faces containing those edges.
+ */
void BM_face_edges_kill(BMesh *bm, BMFace *f);
+/**
+ * kills all verts associated with \a f, along with any other faces containing
+ * those vertices
+ */
void BM_face_verts_kill(BMesh *bm, BMFace *f);
+/**
+ * A version of #BM_face_kill which removes edges and verts
+ * which have no remaining connected geometry.
+ */
void BM_face_kill_loose(BMesh *bm, BMFace *f);
+/**
+ * Kills \a f and its loops.
+ */
void BM_face_kill(BMesh *bm, BMFace *f);
+/**
+ * Kills \a e and all faces that use it.
+ */
void BM_edge_kill(BMesh *bm, BMEdge *e);
+/**
+ * Kills \a v and all edges that use it.
+ */
void BM_vert_kill(BMesh *bm, BMVert *v);
+/**
+ * \brief Splice Edge
+ *
+ * Splice two unique edges which share the same two vertices into one edge.
+ * (\a e_src into \a e_dst, removing e_src).
+ *
+ * \return Success
+ *
+ * \note Edges must already have the same vertices.
+ */
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src);
+/**
+ * \brief Splice Vert
+ *
+ * Merges two verts into one
+ * (\a v_src into \a v_dst, removing \a v_src).
+ *
+ * \return Success
+ *
+ * \warning This doesn't work for collapsing edges,
+ * where \a v and \a vtarget are connected by an edge
+ * (assert checks for this case).
+ */
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src);
+/**
+ * Check if splicing vertices would create any double edges.
+ *
+ * \note assume caller will handle case where verts share an edge.
+ */
bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b);
+/**
+ * \brief Loop Reverse
+ *
+ * Changes the winding order of a face from CW to CCW or vice versa.
+ *
+ * \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`.
+ * \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp,
+ * (use when flipping normals, disable when mirroring, eg: symmetrize).
+ */
void bmesh_kernel_loop_reverse(BMesh *bm,
BMFace *f,
- const int cd_loop_mdisp_offset,
- const bool use_loop_mdisp_flip);
+ int cd_loop_mdisp_offset,
+ bool use_loop_mdisp_flip);
+/**
+ * Avoid calling this where possible,
+ * low level function so both face pointers remain intact but point to swapped data.
+ * \note must be from the same bmesh.
+ */
void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b);
-BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del);
+/**
+ * \brief Join Connected Faces
+ *
+ * Joins a collected group of faces into one. Only restriction on
+ * the input data is that the faces must be connected to each other.
+ *
+ * \return The newly created combine BMFace.
+ *
+ * \note If a pair of faces share multiple edges,
+ * the pair of faces will be joined at every edge.
+ *
+ * \note this is a generic, flexible join faces function,
+ * almost everything uses this, including #BM_faces_join_pair
+ */
+BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, bool do_del);
+/**
+ * High level function which wraps both #bmesh_kernel_vert_separate and #bmesh_kernel_edge_separate
+ */
void BM_vert_separate(BMesh *bm,
BMVert *v,
BMEdge **e_in,
int e_in_len,
- const bool copy_select,
+ bool copy_select,
BMVert ***r_vout,
int *r_vout_len);
-void BM_vert_separate_hflag(BMesh *bm,
- BMVert *v,
- const char hflag,
- const bool copy_select,
- BMVert ***r_vout,
- int *r_vout_len);
+/**
+ * A version of #BM_vert_separate which takes a flag.
+ */
+void BM_vert_separate_hflag(
+ BMesh *bm, BMVert *v, char hflag, bool copy_select, BMVert ***r_vout, int *r_vout_len);
void BM_vert_separate_tested_edges(
BMesh *bm, BMVert *v_dst, BMVert *v_src, bool (*testfn)(BMEdge *, void *arg), void *arg);
@@ -94,10 +194,70 @@ void BM_vert_separate_tested_edges(
*
* Names are on the verbose side but these are only for low-level access.
*/
+/**
+ * \brief Separate Vert
+ *
+ * Separates all disjoint fans that meet at a vertex, making a unique
+ * vertex for each region. returns an array of all resulting vertices.
+ *
+ * \note this is a low level function, bm_edge_separate needs to run on edges first
+ * or, the faces sharing verts must not be sharing edges for them to split at least.
+ *
+ * \return Success
+ */
void bmesh_kernel_vert_separate(
- BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select);
-void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select);
+ BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, bool copy_select);
+/**
+ * \brief Separate Edge
+ *
+ * Separates a single edge into two edge: the original edge and
+ * a new edge that has only \a l_sep in its radial.
+ *
+ * \return Success
+ *
+ * \note Does nothing if \a l_sep is already the only loop in the
+ * edge radial.
+ */
+void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, bool copy_select);
+/**
+ * \brief Split Face Make Edge (SFME)
+ *
+ * \warning this is a low level function, most likely you want to use #BM_face_split()
+ *
+ * Takes as input two vertices in a single face.
+ * An edge is created which divides the original face into two distinct regions.
+ * One of the regions is assigned to the original face and it is closed off.
+ * The second region has a new face assigned to it.
+ *
+ * \par Examples:
+ * <pre>
+ * Before: After:
+ * +--------+ +--------+
+ * | | | |
+ * | | | f1 |
+ * v1 f1 v2 v1======v2
+ * | | | f2 |
+ * | | | |
+ * +--------+ +--------+
+ * </pre>
+ *
+ * \note the input vertices can be part of the same edge. This will
+ * result in a two edged face. This is desirable for advanced construction
+ * tools and particularly essential for edge bevel. Because of this it is
+ * up to the caller to decide what to do with the extra edge.
+ *
+ * \note If \a holes is NULL, then both faces will lose
+ * all holes from the original face. Also, you cannot split between
+ * a hole vert and a boundary vert; that case is handled by higher-
+ * level wrapping functions (when holes are fully implemented, anyway).
+ *
+ * \note that holes represents which holes goes to the new face, and of
+ * course this requires removing them from the existing face first, since
+ * you cannot have linked list links inside multiple lists.
+ *
+ * \return A BMFace pointer
+ */
BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
BMFace *f,
BMLoop *l_v1,
@@ -107,24 +267,141 @@ BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
ListBase *holes,
#endif
BMEdge *example,
- const bool no_double);
+ bool no_double);
+/**
+ * \brief Split Edge Make Vert (SEMV)
+ *
+ * Takes \a e edge and splits it into two, creating a new vert.
+ * \a tv should be one end of \a e : the newly created edge
+ * will be attached to that end and is returned in \a r_e.
+ *
+ * \par Examples:
+ *
+ * <pre>
+ * E
+ * Before: OV-------------TV
+ * E RE
+ * After: OV------NV-----TV
+ * </pre>
+ *
+ * \return The newly created BMVert pointer.
+ */
BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e);
+/**
+ * \brief Join Edge Kill Vert (JEKV)
+ *
+ * Takes an edge \a e_kill and pointer to one of its vertices \a v_kill
+ * and collapses the edge on that vertex.
+ *
+ * \par Examples:
+ *
+ * <pre>
+ * Before: e_old e_kill
+ * +-------+-------+
+ * | | |
+ * v_old v_kill v_target
+ *
+ * After: e_old
+ * +---------------+
+ * | |
+ * v_old v_target
+ * </pre>
+ *
+ * \par Restrictions:
+ * KV is a vertex that must have a valance of exactly two. Furthermore
+ * both edges in KV's disk cycle (OE and KE) must be unique (no double edges).
+ *
+ * \return The resulting edge, NULL for failure.
+ *
+ * \note This euler has the possibility of creating
+ * faces with just 2 edges. It is up to the caller to decide what to do with
+ * these faces.
+ */
BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
- const bool do_del,
- const bool check_edge_exists,
- const bool kill_degenerate_faces,
- const bool kill_duplicate_faces);
+ bool do_del,
+ bool check_edge_exists,
+ bool kill_degenerate_faces,
+ bool kill_duplicate_faces);
+/**
+ * \brief Join Vert Kill Edge (JVKE)
+ *
+ * Collapse an edge, merging surrounding data.
+ *
+ * Unlike #BM_vert_collapse_edge & #bmesh_kernel_join_edge_kill_vert
+ * which only handle 2 valence verts,
+ * this can handle any number of connected edges/faces.
+ *
+ * <pre>
+ * Before: -> After:
+ * +-+-+-+ +-+-+-+
+ * | | | | | \ / |
+ * +-+-+-+ +--+--+
+ * | | | | | / \ |
+ * +-+-+-+ +-+-+-+
+ * </pre>
+ */
BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
- const bool do_del,
- const bool check_edge_exists,
- const bool kill_degenerate_faces);
+ bool do_del,
+ bool check_edge_exists,
+ bool kill_degenerate_faces);
+/**
+ * \brief Join Face Kill Edge (JFKE)
+ *
+ * Takes two faces joined by a single 2-manifold edge and fuses them together.
+ * The edge shared by the faces must not be connected to any other edges which have
+ * Both faces in its radial cycle
+ *
+ * \par Examples:
+ * <pre>
+ * A B
+ * +--------+ +--------+
+ * | | | |
+ * | f1 | | f1 |
+ * v1========v2 = Ok! v1==V2==v3 == Wrong!
+ * | f2 | | f2 |
+ * | | | |
+ * +--------+ +--------+
+ * </pre>
+ *
+ * In the example A, faces \a f1 and \a f2 are joined by a single edge,
+ * and the euler can safely be used.
+ * In example B however, \a f1 and \a f2 are joined by multiple edges and will produce an error.
+ * The caller in this case should call #bmesh_kernel_join_edge_kill_vert on the extra edges
+ * before attempting to fuse \a f1 and \a f2.
+ *
+ * \note The order of arguments decides whether or not certain per-face attributes are present
+ * in the resultant face. For instance vertex winding, material index, smooth flags,
+ * etc are inherited from \a f1, not \a f2.
+ *
+ * \return A BMFace pointer
+ */
BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
+/**
+ * \brief Un-glue Region Make Vert (URMV)
+ *
+ * Disconnects a face from its vertex fan at loop \a l_sep
+ *
+ * \return The newly created BMVert
+ *
+ * \note Will be a no-op and return original vertex if only two edges at that vertex.
+ */
BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep);
+/**
+ * A version of #bmesh_kernel_unglue_region_make_vert that disconnects multiple loops at once.
+ * The loops must all share the same vertex, can be in any order
+ * and are all moved to use a single new vertex - which is returned.
+ *
+ * This function handles the details of finding fans boundaries.
+ */
BMVert *bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len);
+/**
+ * This function assumes l_sep is a part of a larger fan which has already been
+ * isolated by calling #bmesh_kernel_edge_separate to segregate it radially.
+ */
BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep);
diff --git a/source/blender/bmesh/intern/bmesh_delete.c b/source/blender/bmesh/intern/bmesh_delete.c
index 9f2fb1370bb..ae93795d51c 100644
--- a/source/blender/bmesh/intern/bmesh_delete.c
+++ b/source/blender/bmesh/intern/bmesh_delete.c
@@ -99,10 +99,6 @@ void BMO_mesh_delete_oflag_tagged(BMesh *bm, const short oflag, const char htype
}
}
-/**
- * \warning oflag applies to different types in some contexts,
- * not just the type being removed.
- */
void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type)
{
BMEdge *e;
@@ -275,10 +271,6 @@ void BM_mesh_delete_hflag_tagged(BMesh *bm, const char hflag, const char htype)
}
}
-/**
- * \warning oflag applies to different types in some contexts,
- * not just the type being removed.
- */
void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type)
{
BMEdge *e;
diff --git a/source/blender/bmesh/intern/bmesh_delete.h b/source/blender/bmesh/intern/bmesh_delete.h
index fcbcb8a90fc..068c35f6dc7 100644
--- a/source/blender/bmesh/intern/bmesh_delete.h
+++ b/source/blender/bmesh/intern/bmesh_delete.h
@@ -20,8 +20,16 @@
* \ingroup bmesh
*/
-void BMO_mesh_delete_oflag_tagged(BMesh *bm, const short oflag, const char htype);
-void BM_mesh_delete_hflag_tagged(BMesh *bm, const char hflag, const char htype);
+void BMO_mesh_delete_oflag_tagged(BMesh *bm, short oflag, char htype);
+void BM_mesh_delete_hflag_tagged(BMesh *bm, char hflag, char htype);
-void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type);
-void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type);
+/**
+ * \warning oflag applies to different types in some contexts,
+ * not just the type being removed.
+ */
+void BMO_mesh_delete_oflag_context(BMesh *bm, short oflag, int type);
+/**
+ * \warning oflag applies to different types in some contexts,
+ * not just the type being removed.
+ */
+void BM_mesh_delete_hflag_context(BMesh *bm, char hflag, int type);
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c
index ab14ec23fad..3c79d2bce04 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.c
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.c
@@ -121,9 +121,6 @@ static bool bm_loop_build(BMEdgeLoopStore *el_store, BMVert *v_prev, BMVert *v,
return true;
}
-/**
- * \return listbase of listbases, each linking to a vertex.
- */
int BM_mesh_edgeloops_find(BMesh *bm,
ListBase *r_eloops,
bool (*test_fn)(BMEdge *, void *user_data),
@@ -506,7 +503,6 @@ void BM_mesh_edgeloops_calc_order(BMesh *UNUSED(bm), ListBase *eloops, const boo
/* -------------------------------------------------------------------- */
/* BM_edgeloop_*** functions */
-/* return new edgeloops */
BMEdgeLoopStore *BM_edgeloop_copy(BMEdgeLoopStore *el_store)
{
BMEdgeLoopStore *el_store_copy = MEM_mallocN(sizeof(*el_store), __func__);
@@ -565,9 +561,6 @@ const float *BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store)
#define NODE_AS_V(n) ((BMVert *)((LinkData *)n)->data)
#define NODE_AS_CO(n) ((BMVert *)((LinkData *)n)->data)->co
-/**
- * edges are assigned to one vert -> the next.
- */
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr)
{
LinkData *node;
@@ -653,12 +646,6 @@ bool BM_edgeloop_calc_normal(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
return true;
}
-/**
- * For open loops that are straight lines,
- * calculating the normal as if it were a polygon is meaningless.
- *
- * Instead use an alignment vector and calculate the normal based on that.
- */
bool BM_edgeloop_calc_normal_aligned(BMesh *UNUSED(bm),
BMEdgeLoopStore *el_store,
const float no_align[3])
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.h b/source/blender/bmesh/intern/bmesh_edgeloop.h
index 34fc4c0ccc1..9dc1e64dd46 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.h
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.h
@@ -28,6 +28,9 @@ struct GSet;
struct ListBase;
/* multiple edgeloops (ListBase) */
+/**
+ * \return listbase of listbases, each linking to a vertex.
+ */
int BM_mesh_edgeloops_find(BMesh *bm,
struct ListBase *r_eloops,
bool (*test_fn)(BMEdge *, void *user_data),
@@ -45,13 +48,14 @@ void BM_mesh_edgeloops_calc_normal(BMesh *bm, struct ListBase *eloops);
void BM_mesh_edgeloops_calc_normal_aligned(BMesh *bm,
struct ListBase *eloops,
const float no_align[3]);
-void BM_mesh_edgeloops_calc_order(BMesh *bm, ListBase *eloops, const bool use_normals);
+void BM_mesh_edgeloops_calc_order(BMesh *bm, ListBase *eloops, bool use_normals);
-/* single edgeloop */
+/**
+ * Copy a single edge-loop.
+ * \return new edge-loops.
+ */
struct BMEdgeLoopStore *BM_edgeloop_copy(struct BMEdgeLoopStore *el_store);
-struct BMEdgeLoopStore *BM_edgeloop_from_verts(BMVert **v_arr,
- const int v_arr_tot,
- bool is_closed);
+struct BMEdgeLoopStore *BM_edgeloop_from_verts(BMVert **v_arr, int v_arr_tot, bool is_closed);
void BM_edgeloop_free(struct BMEdgeLoopStore *el_store);
bool BM_edgeloop_is_closed(struct BMEdgeLoopStore *el_store);
@@ -59,9 +63,18 @@ int BM_edgeloop_length_get(struct BMEdgeLoopStore *el_store);
struct ListBase *BM_edgeloop_verts_get(struct BMEdgeLoopStore *el_store);
const float *BM_edgeloop_normal_get(struct BMEdgeLoopStore *el_store);
const float *BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store);
+/**
+ * Edges are assigned to one vert -> the next.
+ */
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr);
void BM_edgeloop_calc_center(BMesh *bm, struct BMEdgeLoopStore *el_store);
bool BM_edgeloop_calc_normal(BMesh *bm, struct BMEdgeLoopStore *el_store);
+/**
+ * For open loops that are straight lines,
+ * calculating the normal as if it were a polygon is meaningless.
+ *
+ * Instead use an alignment vector and calculate the normal based on that.
+ */
bool BM_edgeloop_calc_normal_aligned(BMesh *bm,
struct BMEdgeLoopStore *el_store,
const float no_align[3]);
diff --git a/source/blender/bmesh/intern/bmesh_error.h b/source/blender/bmesh/intern/bmesh_error.h
index 7694d4dbfb6..68ec3fe3ee8 100644
--- a/source/blender/bmesh/intern/bmesh_error.h
+++ b/source/blender/bmesh/intern/bmesh_error.h
@@ -48,13 +48,17 @@ typedef enum eBMOpErrorLevel {
BMO_ERROR_FATAL = 2,
} eBMOpErrorLevel;
-/* Pushes an error onto the bmesh error stack.
- * if msg is null, then the default message for the `errcode` is used. */
+/**
+ * Pushes an error onto the bmesh error stack.
+ * if msg is null, then the default message for the `errcode` is used.
+ */
void BMO_error_raise(BMesh *bm, BMOperator *owner, eBMOpErrorLevel level, const char *msg)
ATTR_NONNULL(1, 2, 4);
-/* Gets the topmost error from the stack.
- * returns error code or 0 if no error. */
+/**
+ * Gets the topmost error from the stack.
+ * returns error code or 0 if no error.
+ */
bool BMO_error_get(BMesh *bm, const char **r_msg, BMOperator **r_op, eBMOpErrorLevel *r_level);
bool BMO_error_get_at_level(BMesh *bm,
eBMOpErrorLevel level,
@@ -83,8 +87,10 @@ void BMO_error_clear(BMesh *bm);
# define _BMESH_DUMMY_ABORT() (void)0
#endif
-/* This is meant to be higher level than BLI_assert(),
- * its enabled even when in Release mode. */
+/**
+ * This is meant to be higher level than BLI_assert(),
+ * its enabled even when in Release mode.
+ */
#define BMESH_ASSERT(a) \
(void)((!(a)) ? ((fprintf(stderr, \
"BMESH_ASSERT failed: %s, %s(), %d at \'%s\'\n", \
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index 288c5fa8158..a1bcd8e6258 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -81,13 +81,6 @@ static void bm_data_interp_from_elem(CustomData *data_layer,
}
}
-/**
- * \brief Data, Interp From Verts
- *
- * Interpolates per-vertex data from two sources to \a v_dst
- *
- * \note This is an exact match to #BM_data_interp_from_edges
- */
void BM_data_interp_from_verts(
BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac)
{
@@ -95,13 +88,6 @@ void BM_data_interp_from_verts(
&bm->vdata, (const BMElem *)v_src_1, (const BMElem *)v_src_2, (BMElem *)v_dst, fac);
}
-/**
- * \brief Data, Interp From Edges
- *
- * Interpolates per-edge data from two sources to \a e_dst.
- *
- * \note This is an exact match to #BM_data_interp_from_verts
- */
void BM_data_interp_from_edges(
BMesh *bm, const BMEdge *e_src_1, const BMEdge *e_src_2, BMEdge *e_dst, const float fac)
{
@@ -120,12 +106,6 @@ static void UNUSED_FUNCTION(BM_Data_Vert_Average)(BMesh *UNUSED(bm), BMFace *UNU
// BMIter iter;
}
-/**
- * \brief Data Face-Vert Edge Interp
- *
- * Walks around the faces of \a e and interpolates
- * the loop data between two sources.
- */
void BM_data_interp_face_vert_edge(BMesh *bm,
const BMVert *v_src_1,
const BMVert *UNUSED(v_src_2),
@@ -169,14 +149,6 @@ void BM_data_interp_face_vert_edge(BMesh *bm,
} while ((l_iter = l_iter->radial_next) != e->l);
}
-/**
- * \brief Data Interp From Face
- *
- * projects target onto source, and pulls interpolated customdata from
- * source.
- *
- * \note Only handles loop customdata. multires is handled.
- */
void BM_face_interp_from_face_ex(BMesh *bm,
BMFace *f_dst,
const BMFace *f_src,
@@ -570,9 +542,6 @@ void BM_loop_interp_multires_ex(BMesh *UNUSED(bm),
BLI_task_parallel_range(0, res, &data, loop_interp_multires_cb, &settings);
}
-/**
- * project the multires grid in target onto f_src's set of multires grids
- */
void BM_loop_interp_multires(BMesh *bm, BMLoop *l_dst, const BMFace *f_src)
{
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
@@ -618,10 +587,6 @@ void BM_face_interp_multires(BMesh *bm, BMFace *f_dst, const BMFace *f_src)
}
}
-/**
- * smooths boundaries between multires grids,
- * including some borders in adjacent faces
- */
void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
{
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
@@ -730,10 +695,6 @@ void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
}
}
-/**
- * projects a single loop, target, onto f_src for customdata interpolation. multires is handled.
- * if do_vertex is true, target's vert data will also get interpolated.
- */
void BM_loop_interp_from_face(
BMesh *bm, BMLoop *l_dst, const BMFace *f_src, const bool do_vertex, const bool do_multires)
{
@@ -1246,9 +1207,6 @@ static void bm_vert_loop_groups_data_layer_merge_weights__single(
}
}
-/**
- * Take existing custom data and merge each fan's data.
- */
void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, const int layer_n)
{
const int type = bm->ldata.layers[layer_n].type;
@@ -1260,10 +1218,6 @@ void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, const int
} while ((groups = groups->next));
}
-/**
- * A version of #BM_vert_loop_groups_data_layer_merge
- * that takes an array of loop-weights (aligned with #BM_LOOPS_OF_VERT iterator)
- */
void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm,
LinkNode *groups,
const int layer_n,
diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h
index c77281bd798..bf5b5bd09f4 100644
--- a/source/blender/bmesh/intern/bmesh_interp.h
+++ b/source/blender/bmesh/intern/bmesh_interp.h
@@ -28,7 +28,10 @@ void BM_loop_interp_multires_ex(BMesh *bm,
const BMFace *f_src,
const float f_dst_center[3],
const float f_src_center[3],
- const int cd_loop_mdisp_offset);
+ int cd_loop_mdisp_offset);
+/**
+ * Project the multi-resolution grid in target onto f_src's set of multi-resolution grids.
+ */
void BM_loop_interp_multires(BMesh *bm, BMLoop *l_dst, const BMFace *f_src);
void BM_face_interp_multires_ex(BMesh *bm,
@@ -36,21 +39,37 @@ void BM_face_interp_multires_ex(BMesh *bm,
const BMFace *f_src,
const float f_dst_center[3],
const float f_src_center[3],
- const int cd_loop_mdisp_offset);
+ int cd_loop_mdisp_offset);
void BM_face_interp_multires(BMesh *bm, BMFace *f_dst, const BMFace *f_src);
void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src);
+/**
+ * \brief Data, Interpolate From Verts
+ *
+ * Interpolates per-vertex data from two sources to \a v_dst
+ *
+ * \note This is an exact match to #BM_data_interp_from_edges.
+ */
void BM_data_interp_from_verts(
- BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac);
+ BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, float fac);
+/**
+ * \brief Data, Interpolate From Edges
+ *
+ * Interpolates per-edge data from two sources to \a e_dst.
+ *
+ * \note This is an exact match to #BM_data_interp_from_verts.
+ */
void BM_data_interp_from_edges(
- BMesh *bm, const BMEdge *e_src_1, const BMEdge *e_src_2, BMEdge *e_dst, const float fac);
-void BM_data_interp_face_vert_edge(BMesh *bm,
- const BMVert *v_src_1,
- const BMVert *v_src_2,
- BMVert *v,
- BMEdge *e,
- const float fac);
+ BMesh *bm, const BMEdge *e_src_1, const BMEdge *e_src_2, BMEdge *e_dst, float fac);
+/**
+ * \brief Data Face-Vert Edge Interpolate
+ *
+ * Walks around the faces of \a e and interpolates
+ * the loop data between two sources.
+ */
+void BM_data_interp_face_vert_edge(
+ BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v, BMEdge *e, float fac);
void BM_data_layer_add(BMesh *bm, CustomData *data, int type);
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name);
void BM_data_layer_free(BMesh *bm, CustomData *data, int type);
@@ -58,26 +77,49 @@ void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n);
void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int dst_n);
float BM_elem_float_data_get(CustomData *cd, void *element, int type);
-void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float val);
+void BM_elem_float_data_set(CustomData *cd, void *element, int type, float val);
+/**
+ * \brief Data Interpolate From Face
+ *
+ * Projects target onto source, and pulls interpolated custom-data from source.
+ *
+ * \note Only handles loop custom-data. multi-res is handled.
+ */
void BM_face_interp_from_face_ex(BMesh *bm,
BMFace *f_dst,
const BMFace *f_src,
- const bool do_vertex,
+ bool do_vertex,
const void **blocks,
const void **blocks_v,
float (*cos_2d)[2],
float axis_mat[3][3]);
-void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, const bool do_vertex);
+void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, bool do_vertex);
+/**
+ * Projects a single loop, target, onto f_src for custom-data interpolation.
+ * multi-resolution is handled.
+ * \param do_vertex: When true the target's vert data will also get interpolated.
+ */
void BM_loop_interp_from_face(
- BMesh *bm, BMLoop *l_dst, const BMFace *f_src, const bool do_vertex, const bool do_multires);
+ BMesh *bm, BMLoop *l_dst, const BMFace *f_src, bool do_vertex, bool do_multires);
+/**
+ * Smooths boundaries between multi-res grids,
+ * including some borders in adjacent faces.
+ */
void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f);
struct LinkNode *BM_vert_loop_groups_data_layer_create(
- BMesh *bm, BMVert *v, const int layer_n, const float *loop_weights, struct MemArena *arena);
-void BM_vert_loop_groups_data_layer_merge(BMesh *bm, struct LinkNode *groups, const int layer_n);
+ BMesh *bm, BMVert *v, int layer_n, const float *loop_weights, struct MemArena *arena);
+/**
+ * Take existing custom data and merge each fan's data.
+ */
+void BM_vert_loop_groups_data_layer_merge(BMesh *bm, struct LinkNode *groups, int layer_n);
+/**
+ * A version of #BM_vert_loop_groups_data_layer_merge
+ * that takes an array of loop-weights (aligned with #BM_LOOPS_OF_VERT iterator).
+ */
void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm,
struct LinkNode *groups,
- const int layer_n,
+ int layer_n,
const float *loop_weights);
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
index bd28022de4b..6a27e54c6a6 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.c
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -47,9 +47,6 @@ const char bm_iter_itype_htype_map[BM_ITYPE_MAX] = {
BM_LOOP, /* BM_LOOPS_OF_EDGE */
};
-/**
- * Utility function.
- */
int BM_iter_mesh_count(const char itype, BMesh *bm)
{
int count;
@@ -73,9 +70,6 @@ int BM_iter_mesh_count(const char itype, BMesh *bm)
return count;
}
-/**
- * \note Use #BM_vert_at_index / #BM_edge_at_index / #BM_face_at_index for mesh arrays.
- */
void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
{
BMIter iter;
@@ -98,12 +92,6 @@ void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
return val;
}
-/**
- * \brief Iterator as Array
- *
- * Sometimes its convenient to get the iterator as an array
- * to avoid multiple calls to #BM_iter_at_index.
- */
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len)
{
int i = 0;
@@ -124,11 +112,6 @@ int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, cons
return i;
}
-/**
- * \brief Operator Iterator as Array
- *
- * Sometimes its convenient to get the iterator as an array.
- */
int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char restrictmask,
@@ -155,16 +138,6 @@ int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
return i;
}
-/**
- * \brief Iterator as Array
- *
- * Allocates a new array, has the advantage that you don't need to know the size ahead of time.
- *
- * Takes advantage of less common iterator usage to avoid counting twice,
- * which you might end up doing when #BM_iter_as_array is used.
- *
- * Caller needs to free the array.
- */
void *BM_iter_as_arrayN(BMesh *bm,
const char itype,
void *data,
@@ -272,9 +245,6 @@ int BM_iter_mesh_bitmap_from_filter(const char itype,
return bitmap_enabled;
}
-/**
- * Needed when we want to check faces, but return a loop aligned array.
- */
int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
BLI_bitmap *bitmap,
bool (*test_fn)(BMFace *, void *user_data),
@@ -305,11 +275,6 @@ int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
return bitmap_enabled;
}
-/**
- * \brief Elem Iter Flag Count
- *
- * Counts how many flagged / unflagged items are found in this element.
- */
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value)
{
BMIter iter;
@@ -325,11 +290,6 @@ int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, cons
return count;
}
-/**
- * \brief Elem Iter Tool Flag Count
- *
- * Counts how many flagged / unflagged items are found in this element.
- */
int BMO_iter_elem_count_flag(
BMesh *bm, const char itype, void *data, const short oflag, const bool value)
{
@@ -371,11 +331,6 @@ int BMO_iter_elem_count_flag(
return count;
}
-/**
- * \brief Mesh Iter Flag Count
- *
- * Counts how many flagged / unflagged items are found in this mesh.
- */
int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value)
{
BMIter iter;
diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h
index ab4427e6968..1c9b322ef75 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.h
+++ b/source/blender/bmesh/intern/bmesh_iterators.h
@@ -34,13 +34,6 @@
#include "BLI_compiler_attrs.h"
#include "BLI_mempool.h"
-/* Defines for passing to BM_iter_new.
- *
- * "OF" can be substituted for "around"
- * so BM_VERTS_OF_FACE means "vertices
- * around a face."
- */
-
/* these iterator over all elements of a specific
* type in the mesh.
*
@@ -75,6 +68,12 @@ typedef enum BMIterType {
/* the iterator htype for each iterator */
extern const char bm_iter_itype_htype_map[BM_ITYPE_MAX];
+/* -------------------------------------------------------------------- */
+/** \name Defines for passing to #BM_iter_new.
+ *
+ * "OF" can be substituted for "around" so #BM_VERTS_OF_FACE means "vertices* around a face."
+ * \{ */
+
#define BM_ITER_MESH(ele, iter, bm, itype) \
for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new(iter, bm, itype, NULL); ele; \
BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter))
@@ -108,6 +107,8 @@ extern const char bm_iter_itype_htype_map[BM_ITYPE_MAX];
for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new(iter, NULL, itype, data), indexvar = 0; ele; \
BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter), (indexvar)++)
+/** \} */
+
/* iterator type structs */
struct BMIter__elem_of_mesh {
BLI_mempool_iter pooliter;
@@ -184,42 +185,86 @@ typedef struct BMIter {
char itype;
} BMIter;
-void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index) ATTR_WARN_UNUSED_RESULT;
-int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len);
+/**
+ * \note Use #BM_vert_at_index / #BM_edge_at_index / #BM_face_at_index for mesh arrays.
+ */
+void *BM_iter_at_index(BMesh *bm, char itype, void *data, int index) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \brief Iterator as Array
+ *
+ * Sometimes its convenient to get the iterator as an array
+ * to avoid multiple calls to #BM_iter_at_index.
+ */
+int BM_iter_as_array(BMesh *bm, char itype, void *data, void **array, int len);
+/**
+ * \brief Iterator as Array
+ *
+ * Allocates a new array, has the advantage that you don't need to know the size ahead of time.
+ *
+ * Takes advantage of less common iterator usage to avoid counting twice,
+ * which you might end up doing when #BM_iter_as_array is used.
+ *
+ * Caller needs to free the array.
+ */
void *BM_iter_as_arrayN(BMesh *bm,
- const char itype,
+ char itype,
void *data,
int *r_len,
void **stack_array,
int stack_array_size) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \brief Operator Iterator as Array
+ *
+ * Sometimes its convenient to get the iterator as an array.
+ */
int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char restrictmask,
+ char restrictmask,
void **array,
- const int len);
+ int len);
void *BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char restrictmask,
+ char restrictmask,
int *r_len,
/* optional args to avoid an alloc (normally stack array) */
void **stack_array,
int stack_array_size);
-int BM_iter_mesh_bitmap_from_filter(const char itype,
+int BM_iter_mesh_bitmap_from_filter(char itype,
BMesh *bm,
uint *bitmap,
bool (*test_fn)(BMElem *, void *user_data),
void *user_data);
+/**
+ * Needed when we want to check faces, but return a loop aligned array.
+ */
int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
uint *bitmap,
bool (*test_fn)(BMFace *, void *user_data),
void *user_data);
-int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value);
-int BMO_iter_elem_count_flag(
- BMesh *bm, const char itype, void *data, const short oflag, const bool value);
-int BM_iter_mesh_count(const char itype, BMesh *bm);
-int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value);
+/**
+ * \brief Elem Iter Flag Count
+ *
+ * Counts how many flagged / unflagged items are found in this element.
+ */
+int BM_iter_elem_count_flag(char itype, void *data, char hflag, bool value);
+/**
+ * \brief Elem Iter Tool Flag Count
+ *
+ * Counts how many flagged / unflagged items are found in this element.
+ */
+int BMO_iter_elem_count_flag(BMesh *bm, char itype, void *data, short oflag, bool value);
+/**
+ * Utility function.
+ */
+int BM_iter_mesh_count(char itype, BMesh *bm);
+/**
+ * \brief Mesh Iter Flag Count
+ *
+ * Counts how many flagged / unflagged items are found in this mesh.
+ */
+int BM_iter_mesh_count_flag(char itype, BMesh *bm, char hflag, bool value);
/* private for bmesh_iterators_inline.c */
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index 9033e43374b..edcd9159520 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -109,7 +109,7 @@ struct BMLog {
typedef struct {
float co[3];
- short no[3];
+ float no[3];
char hflag;
float mask;
} BMLogVert;
@@ -200,7 +200,7 @@ static void vert_mask_set(BMVert *v, const float new_mask, const int cd_vert_mas
static void bm_log_vert_bmvert_copy(BMLogVert *lv, BMVert *v, const int cd_vert_mask_offset)
{
copy_v3_v3(lv->co, v->co);
- normal_float_to_short_v3(lv->no, v->no);
+ copy_v3_v3(lv->no, v->no);
lv->mask = vert_mask_get(v, cd_vert_mask_offset);
lv->hflag = v->head.hflag;
}
@@ -294,7 +294,7 @@ static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts)
BMVert *v = BM_vert_create(bm, lv->co, NULL, BM_CREATE_NOP);
vert_mask_set(v, lv->mask, cd_vert_mask_offset);
v->head.hflag = lv->hflag;
- normal_short_to_float_v3(v->no, lv->no);
+ copy_v3_v3(v->no, lv->no);
bm_log_vert_id_set(log, v, POINTER_AS_UINT(key));
}
}
@@ -329,12 +329,9 @@ static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts)
uint id = POINTER_AS_UINT(key);
BMVert *v = bm_log_vert_from_id(log, id);
float mask;
- short normal[3];
swap_v3_v3(v->co, lv->co);
- copy_v3_v3_short(normal, lv->no);
- normal_float_to_short_v3(lv->no, v->no);
- normal_short_to_float_v3(v->no, normal);
+ swap_v3_v3(v->no, lv->no);
SWAP(char, v->head.hflag, lv->hflag);
mask = lv->mask;
lv->mask = vert_mask_get(v, cd_vert_mask_offset);
@@ -468,7 +465,6 @@ static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash)
/***************************** Public API *****************************/
-/* Allocate, initialize, and assign a new BMLog */
BMLog *BM_log_create(BMesh *bm)
{
BMLog *log = MEM_callocN(sizeof(*log), __func__);
@@ -506,14 +502,6 @@ void BM_log_cleanup_entry(BMLogEntry *entry)
}
}
-/* Allocate and initialize a new BMLog using existing BMLogEntries
- *
- * The 'entry' should be the last entry in the BMLog. Its prev pointer
- * will be followed back to find the first entry.
- *
- * The unused IDs field of the log will be initialized by taking all
- * keys from all GHashes in the log entry.
- */
BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
{
BMLog *log = BM_log_create(bm);
@@ -555,7 +543,6 @@ BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
return log;
}
-/* Free all the data in a BMLog including the log itself */
void BM_log_free(BMLog *log)
{
BMLogEntry *entry;
@@ -581,13 +568,11 @@ void BM_log_free(BMLog *log)
MEM_freeN(log);
}
-/* Get the number of log entries */
int BM_log_length(const BMLog *log)
{
return BLI_listbase_count(&log->entries);
}
-/* Apply a consistent ordering to BMesh vertices */
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
{
uint *varr;
@@ -639,16 +624,6 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
MEM_freeN(farr);
}
-/* Start a new log entry and update the log entry list
- *
- * If the log entry list is empty, or if the current log entry is the
- * last entry, the new entry is simply appended to the end.
- *
- * Otherwise, the new entry is added after the current entry and all
- * following entries are deleted.
- *
- * In either case, the new entry is set as the current log entry.
- */
BMLogEntry *BM_log_entry_add(BMLog *log)
{
/* WARNING: this is now handled by the UndoSystem: BKE_UNDOSYS_TYPE_SCULPT
@@ -676,15 +651,6 @@ BMLogEntry *BM_log_entry_add(BMLog *log)
return entry;
}
-/* Remove an entry from the log
- *
- * Uses entry->log as the log. If the log is NULL, the entry will be
- * free'd but not removed from any list, nor shall its IDs be
- * released.
- *
- * This operation is only valid on the first and last entries in the
- * log. Deleting from the middle will assert.
- */
void BM_log_entry_drop(BMLogEntry *entry)
{
BMLog *log = entry->log;
@@ -751,9 +717,6 @@ void BM_log_entry_drop(BMLogEntry *entry)
BLI_freelinkN(&log->entries, entry);
}
-/* Undo one BMLogEntry
- *
- * Has no effect if there's nothing left to undo */
void BM_log_undo(BMesh *bm, BMLog *log)
{
BMLogEntry *entry = log->current_entry;
@@ -775,9 +738,6 @@ void BM_log_undo(BMesh *bm, BMLog *log)
}
}
-/* Redo one BMLogEntry
- *
- * Has no effect if there's nothing left to redo */
void BM_log_redo(BMesh *bm, BMLog *log)
{
BMLogEntry *entry = log->current_entry;
@@ -812,29 +772,6 @@ void BM_log_redo(BMesh *bm, BMLog *log)
}
}
-/* Log a vertex before it is modified
- *
- * Before modifying vertex coordinates, masks, or hflags, call this
- * function to log its current values. This is better than logging
- * after the coordinates have been modified, because only those
- * vertices that are modified need to have their original values
- * stored.
- *
- * Handles two separate cases:
- *
- * If the vertex was added in the current log entry, update the
- * vertex in the map of added vertices.
- *
- * If the vertex already existed prior to the current log entry, a
- * separate key/value map of modified vertices is used (using the
- * vertex's ID as the key). The values stored in that case are
- * the vertex's original state so that an undo can restore the
- * previous state.
- *
- * On undo, the current vertex state will be swapped with the stored
- * state so that a subsequent redo operation will restore the newer
- * vertex state.
- */
void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
{
BMLogEntry *entry = log->current_entry;
@@ -853,12 +790,6 @@ void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_o
}
}
-/* Log a new vertex as added to the BMesh
- *
- * The new vertex gets a unique ID assigned. It is then added to a map
- * of added vertices, with the key being its ID and the value
- * containing everything needed to reconstruct that vertex.
- */
void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
{
BMLogVert *lv;
@@ -870,11 +801,6 @@ void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
BLI_ghash_insert(log->current_entry->added_verts, key, lv);
}
-/* Log a face before it is modified
- *
- * This is intended to handle only header flags and we always
- * assume face has been added before
- */
void BM_log_face_modified(BMLog *log, BMFace *f)
{
BMLogFace *lf;
@@ -885,12 +811,6 @@ void BM_log_face_modified(BMLog *log, BMFace *f)
BLI_ghash_insert(log->current_entry->modified_faces, key, lf);
}
-/* Log a new face as added to the BMesh
- *
- * The new face gets a unique ID assigned. It is then added to a map
- * of added faces, with the key being its ID and the value containing
- * everything needed to reconstruct that face.
- */
void BM_log_face_added(BMLog *log, BMFace *f)
{
BMLogFace *lf;
@@ -905,22 +825,6 @@ void BM_log_face_added(BMLog *log, BMFace *f)
BLI_ghash_insert(log->current_entry->added_faces, key, lf);
}
-/* Log a vertex as removed from the BMesh
- *
- * A couple things can happen here:
- *
- * If the vertex was added as part of the current log entry, then it's
- * deleted and forgotten about entirely. Its unique ID is returned to
- * the unused pool.
- *
- * If the vertex was already part of the BMesh before the current log
- * entry, it is added to a map of deleted vertices, with the key being
- * its ID and the value containing everything needed to reconstruct
- * that vertex.
- *
- * If there's a move record for the vertex, that's used as the
- * vertices original location, then the move record is deleted.
- */
void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
{
BMLogEntry *entry = log->current_entry;
@@ -949,19 +853,6 @@ void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
}
}
-/* Log a face as removed from the BMesh
- *
- * A couple things can happen here:
- *
- * If the face was added as part of the current log entry, then it's
- * deleted and forgotten about entirely. Its unique ID is returned to
- * the unused pool.
- *
- * If the face was already part of the BMesh before the current log
- * entry, it is added to a map of deleted faces, with the key being
- * its ID and the value containing everything needed to reconstruct
- * that face.
- */
void BM_log_face_removed(BMLog *log, BMFace *f)
{
BMLogEntry *entry = log->current_entry;
@@ -983,7 +874,6 @@ void BM_log_face_removed(BMLog *log, BMFace *f)
}
}
-/* Log all vertices/faces in the BMesh as added */
void BM_log_all_added(BMesh *bm, BMLog *log)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
@@ -1011,7 +901,6 @@ void BM_log_all_added(BMesh *bm, BMLog *log)
}
}
-/* Log all vertices/faces in the BMesh as removed */
void BM_log_before_all_removed(BMesh *bm, BMLog *log)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
@@ -1030,9 +919,6 @@ void BM_log_before_all_removed(BMesh *bm, BMLog *log)
}
}
-/* Get the logged coordinates of a vertex
- *
- * Does not modify the log or the vertex */
const float *BM_log_original_vert_co(BMLog *log, BMVert *v)
{
BMLogEntry *entry = log->current_entry;
@@ -1048,10 +934,7 @@ const float *BM_log_original_vert_co(BMLog *log, BMVert *v)
return lv->co;
}
-/* Get the logged normal of a vertex
- *
- * Does not modify the log or the vertex */
-const short *BM_log_original_vert_no(BMLog *log, BMVert *v)
+const float *BM_log_original_vert_no(BMLog *log, BMVert *v)
{
BMLogEntry *entry = log->current_entry;
const BMLogVert *lv;
@@ -1066,9 +949,6 @@ const short *BM_log_original_vert_no(BMLog *log, BMVert *v)
return lv->no;
}
-/* Get the logged mask of a vertex
- *
- * Does not modify the log or the vertex */
float BM_log_original_mask(BMLog *log, BMVert *v)
{
BMLogEntry *entry = log->current_entry;
@@ -1084,7 +964,7 @@ float BM_log_original_mask(BMLog *log, BMVert *v)
return lv->mask;
}
-void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const short **r_no)
+void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const float **r_no)
{
BMLogEntry *entry = log->current_entry;
const BMLogVert *lv;
@@ -1102,13 +982,11 @@ void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const
/************************ Debugging and Testing ***********************/
-/* For internal use only (unit testing) */
BMLogEntry *BM_log_current_entry(BMLog *log)
{
return log->current_entry;
}
-/* For internal use only (unit testing) */
RangeTreeUInt *BM_log_unused_ids(BMLog *log)
{
return log->unused_ids;
diff --git a/source/blender/bmesh/intern/bmesh_log.h b/source/blender/bmesh/intern/bmesh_log.h
index 5c0ca78bddf..935cb5aba28 100644
--- a/source/blender/bmesh/intern/bmesh_log.h
+++ b/source/blender/bmesh/intern/bmesh_log.h
@@ -29,71 +29,189 @@ typedef struct BMLog BMLog;
typedef struct BMLogEntry BMLogEntry;
/* Allocate and initialize a new BMLog */
+/* Allocate, initialize, and assign a new BMLog */
BMLog *BM_log_create(BMesh *bm);
/* Allocate and initialize a new BMLog using existing BMLogEntries */
+/* Allocate and initialize a new BMLog using existing BMLogEntries
+ *
+ * The 'entry' should be the last entry in the BMLog. Its prev pointer
+ * will be followed back to find the first entry.
+ *
+ * The unused IDs field of the log will be initialized by taking all
+ * keys from all GHashes in the log entry.
+ */
BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry);
/* Free all the data in a BMLog including the log itself */
+/* Free all the data in a BMLog including the log itself */
void BM_log_free(BMLog *log);
/* Get the number of log entries */
+/* Get the number of log entries */
int BM_log_length(const BMLog *log);
/* Apply a consistent ordering to BMesh vertices and faces */
+/* Apply a consistent ordering to BMesh vertices */
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log);
/* Start a new log entry and update the log entry list */
+/* Start a new log entry and update the log entry list
+ *
+ * If the log entry list is empty, or if the current log entry is the
+ * last entry, the new entry is simply appended to the end.
+ *
+ * Otherwise, the new entry is added after the current entry and all
+ * following entries are deleted.
+ *
+ * In either case, the new entry is set as the current log entry.
+ */
BMLogEntry *BM_log_entry_add(BMLog *log);
/* Mark all used ids as unused for this node */
void BM_log_cleanup_entry(BMLogEntry *entry);
/* Remove an entry from the log */
+/* Remove an entry from the log
+ *
+ * Uses entry->log as the log. If the log is NULL, the entry will be
+ * free'd but not removed from any list, nor shall its IDs be
+ * released.
+ *
+ * This operation is only valid on the first and last entries in the
+ * log. Deleting from the middle will assert.
+ */
void BM_log_entry_drop(BMLogEntry *entry);
/* Undo one BMLogEntry */
+/* Undo one BMLogEntry
+ *
+ * Has no effect if there's nothing left to undo */
void BM_log_undo(BMesh *bm, BMLog *log);
/* Redo one BMLogEntry */
+/* Redo one BMLogEntry
+ *
+ * Has no effect if there's nothing left to redo */
void BM_log_redo(BMesh *bm, BMLog *log);
/* Log a vertex before it is modified */
-void BM_log_vert_before_modified(BMLog *log, struct BMVert *v, const int cd_vert_mask_offset);
+/* Log a vertex before it is modified
+ *
+ * Before modifying vertex coordinates, masks, or hflags, call this
+ * function to log its current values. This is better than logging
+ * after the coordinates have been modified, because only those
+ * vertices that are modified need to have their original values
+ * stored.
+ *
+ * Handles two separate cases:
+ *
+ * If the vertex was added in the current log entry, update the
+ * vertex in the map of added vertices.
+ *
+ * If the vertex already existed prior to the current log entry, a
+ * separate key/value map of modified vertices is used (using the
+ * vertex's ID as the key). The values stored in that case are
+ * the vertex's original state so that an undo can restore the
+ * previous state.
+ *
+ * On undo, the current vertex state will be swapped with the stored
+ * state so that a subsequent redo operation will restore the newer
+ * vertex state.
+ */
+void BM_log_vert_before_modified(BMLog *log, struct BMVert *v, int cd_vert_mask_offset);
/* Log a new vertex as added to the BMesh */
-void BM_log_vert_added(BMLog *log, struct BMVert *v, const int cd_vert_mask_offset);
+/* Log a new vertex as added to the BMesh
+ *
+ * The new vertex gets a unique ID assigned. It is then added to a map
+ * of added vertices, with the key being its ID and the value
+ * containing everything needed to reconstruct that vertex.
+ */
+void BM_log_vert_added(BMLog *log, struct BMVert *v, int cd_vert_mask_offset);
/* Log a face before it is modified */
+/* Log a face before it is modified
+ *
+ * This is intended to handle only header flags and we always
+ * assume face has been added before
+ */
void BM_log_face_modified(BMLog *log, struct BMFace *f);
/* Log a new face as added to the BMesh */
+/* Log a new face as added to the BMesh
+ *
+ * The new face gets a unique ID assigned. It is then added to a map
+ * of added faces, with the key being its ID and the value containing
+ * everything needed to reconstruct that face.
+ */
void BM_log_face_added(BMLog *log, struct BMFace *f);
/* Log a vertex as removed from the BMesh */
-void BM_log_vert_removed(BMLog *log, struct BMVert *v, const int cd_vert_mask_offset);
+/* Log a vertex as removed from the BMesh
+ *
+ * A couple things can happen here:
+ *
+ * If the vertex was added as part of the current log entry, then it's
+ * deleted and forgotten about entirely. Its unique ID is returned to
+ * the unused pool.
+ *
+ * If the vertex was already part of the BMesh before the current log
+ * entry, it is added to a map of deleted vertices, with the key being
+ * its ID and the value containing everything needed to reconstruct
+ * that vertex.
+ *
+ * If there's a move record for the vertex, that's used as the
+ * vertices original location, then the move record is deleted.
+ */
+void BM_log_vert_removed(BMLog *log, struct BMVert *v, int cd_vert_mask_offset);
/* Log a face as removed from the BMesh */
+/* Log a face as removed from the BMesh
+ *
+ * A couple things can happen here:
+ *
+ * If the face was added as part of the current log entry, then it's
+ * deleted and forgotten about entirely. Its unique ID is returned to
+ * the unused pool.
+ *
+ * If the face was already part of the BMesh before the current log
+ * entry, it is added to a map of deleted faces, with the key being
+ * its ID and the value containing everything needed to reconstruct
+ * that face.
+ */
void BM_log_face_removed(BMLog *log, struct BMFace *f);
/* Log all vertices/faces in the BMesh as added */
+/* Log all vertices/faces in the BMesh as added */
void BM_log_all_added(BMesh *bm, BMLog *log);
/* Log all vertices/faces in the BMesh as removed */
+/* Log all vertices/faces in the BMesh as removed */
void BM_log_before_all_removed(BMesh *bm, BMLog *log);
/* Get the logged coordinates of a vertex */
+/* Get the logged coordinates of a vertex
+ *
+ * Does not modify the log or the vertex */
const float *BM_log_original_vert_co(BMLog *log, BMVert *v);
-/* Get the logged normal of a vertex */
-const short *BM_log_original_vert_no(BMLog *log, BMVert *v);
+/* Get the logged normal of a vertex
+ *
+ * Does not modify the log or the vertex */
+const float *BM_log_original_vert_no(BMLog *log, BMVert *v);
/* Get the logged mask of a vertex */
+/* Get the logged mask of a vertex
+ *
+ * Does not modify the log or the vertex */
float BM_log_original_mask(BMLog *log, BMVert *v);
/* Get the logged data of a vertex (avoid multiple lookups) */
-void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const short **r_no);
+void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const float **r_no);
/* For internal use only (unit testing) */
+/* For internal use only (unit testing) */
BMLogEntry *BM_log_current_entry(BMLog *log);
+/* For internal use only (unit testing) */
struct RangeTreeUInt *BM_log_unused_ids(BMLog *log);
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index b70e26f51ea..b756aa25edd 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -251,14 +251,6 @@ static bool bm_edge_is_face_visible_any(const BMEdge *e)
/** \} */
-/**
- * \brief Select Mode Clean
- *
- * Remove isolated selected elements when in a mode doesn't support them.
- * eg: in edge-mode a selected vertex must be connected to a selected edge.
- *
- * \note this could be made a part of #BM_mesh_select_mode_flush_ex
- */
void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode)
{
if (selectmode & SCE_SELECT_VERTEX) {
@@ -424,13 +416,6 @@ static void bm_mesh_select_mode_flush_edge_to_face(BMesh *bm)
bm->totfacesel += chunk_data.delta_selection_len;
}
-/**
- * \brief Select Mode Flush
- *
- * Makes sure to flush selections 'upwards'
- * (ie: all verts of an edge selects the edge and so on).
- * This should only be called by system and not tool authors.
- */
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags)
{
if (selectmode & SCE_SELECT_VERTEX) {
@@ -463,9 +448,6 @@ void BM_mesh_select_mode_flush(BMesh *bm)
/** \} */
-/**
- * mode independent flushing up/down
- */
void BM_mesh_deselect_flush(BMesh *bm)
{
BMIter eiter;
@@ -498,9 +480,6 @@ void BM_mesh_deselect_flush(BMesh *bm)
recount_totsels(bm);
}
-/**
- * mode independent flushing up/down
- */
void BM_mesh_select_flush(BMesh *bm)
{
BMEdge *e;
@@ -542,12 +521,6 @@ void BM_mesh_select_flush(BMesh *bm)
recount_totsels(bm);
}
-/**
- * \brief Select Vert
- *
- * Changes selection state of a single vertex
- * in a mesh
- */
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
{
BLI_assert(v->head.htype == BM_VERT);
@@ -570,11 +543,6 @@ void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
}
}
-/**
- * \brief Select Edge
- *
- * Changes selection state of a single edge in a mesh.
- */
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
{
BLI_assert(e->head.htype == BM_EDGE);
@@ -615,12 +583,6 @@ void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
}
}
-/**
- * \brief Select Face
- *
- * Changes selection state of a single
- * face in a mesh.
- */
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
{
BMLoop *l_iter;
@@ -746,12 +708,6 @@ void BM_face_select_set_noflush(BMesh *bm, BMFace *f, const bool select)
/** \} */
-/**
- * Select Mode Set
- *
- * Sets the selection mode for the bmesh,
- * updating the selection state.
- */
void BM_mesh_select_mode_set(BMesh *bm, int selectmode)
{
BMIter iter;
@@ -867,10 +823,6 @@ int BM_mesh_elem_hflag_count_disabled(BMesh *bm,
return bm_mesh_flag_count(bm, htype, hflag, respecthide, false);
}
-/**
- * \note use BM_elem_flag_test(ele, BM_ELEM_SELECT) to test selection
- * \note by design, this will not touch the editselection history stuff
- */
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
{
switch (ele->head.htype) {
@@ -889,7 +841,6 @@ void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
}
}
-/* this replaces the active flag used in uv/face mode */
void BM_mesh_active_face_set(BMesh *bm, BMFace *f)
{
bm->act_face = f;
@@ -974,15 +925,6 @@ BMElem *BM_mesh_active_elem_get(BMesh *bm)
return NULL;
}
-/**
- * Generic way to get data from an EditSelection type
- * These functions were written to be used by the Modifier widget
- * when in Rotate about active mode, but can be used anywhere.
- *
- * - #BM_editselection_center
- * - #BM_editselection_normal
- * - #BM_editselection_plane
- */
void BM_editselection_center(BMEditSelection *ese, float r_center[3])
{
if (ese->htype == BM_VERT) {
@@ -1027,11 +969,6 @@ void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
}
}
-/**
- * Calculate a plane that is right angles to the edge/vert/faces normal
- * also make the plane run along an axis that is related to the geometry,
- * because this is used for the gizmos Y axis.
- */
void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
{
if (ese->htype == BM_VERT) {
@@ -1098,6 +1035,7 @@ static BMEditSelection *bm_select_history_create(BMHeader *ele)
}
/* --- macro wrapped funcs --- */
+
bool _bm_select_history_check(BMesh *bm, const BMHeader *ele)
{
return (BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele)) != NULL);
@@ -1170,9 +1108,6 @@ void BM_select_history_validate(BMesh *bm)
}
}
-/**
- * Get the active mesh element (with active-face fallback).
- */
bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
{
BMEditSelection *ese_last = bm->selected.last;
@@ -1209,9 +1144,6 @@ bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
return true;
}
-/**
- * Return a map from BMVert/Edge/Face -> BMEditSelection
- */
GHash *BM_select_history_map_create(BMesh *bm)
{
BMEditSelection *ese;
@@ -1230,9 +1162,6 @@ GHash *BM_select_history_map_create(BMesh *bm)
return map;
}
-/**
- * Map arguments may all be the same pointer.
- */
void BM_select_history_merge_from_targetmap(
BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain)
{
diff --git a/source/blender/bmesh/intern/bmesh_marking.h b/source/blender/bmesh/intern/bmesh_marking.h
index 99feae1d66c..01c3291b525 100644
--- a/source/blender/bmesh/intern/bmesh_marking.h
+++ b/source/blender/bmesh/intern/bmesh_marking.h
@@ -36,76 +36,123 @@ typedef enum eBMSelectionFlushFLags {
BM_SELECT_LEN_FLUSH_RECALC_FACE),
} eBMSelectionFlushFLags;
-/* geometry hiding code */
+/* Geometry hiding code. */
+
#define BM_elem_hide_set(bm, ele, hide) _bm_elem_hide_set(bm, &(ele)->head, hide)
-void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide);
-void BM_vert_hide_set(BMVert *v, const bool hide);
-void BM_edge_hide_set(BMEdge *e, const bool hide);
-void BM_face_hide_set(BMFace *f, const bool hide);
-
-/* Selection code */
-void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select);
-
-void BM_mesh_elem_hflag_enable_test(BMesh *bm,
- const char htype,
- const char hflag,
- const bool respecthide,
- const bool overwrite,
- const char hflag_test);
-void BM_mesh_elem_hflag_disable_test(BMesh *bm,
- const char htype,
- const char hflag,
- const bool respecthide,
- const bool overwrite,
- const char hflag_test);
-
-void BM_mesh_elem_hflag_enable_all(BMesh *bm,
- const char htype,
- const char hflag,
- const bool respecthide);
-void BM_mesh_elem_hflag_disable_all(BMesh *bm,
- const char htype,
- const char hflag,
- const bool respecthide);
-
-/* Individual element select functions, BM_elem_select_set is a shortcut for these
+void _bm_elem_hide_set(BMesh *bm, BMHeader *head, bool hide);
+void BM_vert_hide_set(BMVert *v, bool hide);
+void BM_edge_hide_set(BMEdge *e, bool hide);
+void BM_face_hide_set(BMFace *f, bool hide);
+
+/* Selection code. */
+
+/**
+ * \note use BM_elem_flag_test(ele, BM_ELEM_SELECT) to test selection
+ * \note by design, this will not touch the editselection history stuff
+ */
+void BM_elem_select_set(BMesh *bm, BMElem *ele, bool select);
+
+void BM_mesh_elem_hflag_enable_test(
+ BMesh *bm, char htype, char hflag, bool respecthide, bool overwrite, char hflag_test);
+void BM_mesh_elem_hflag_disable_test(
+ BMesh *bm, char htype, char hflag, bool respecthide, bool overwrite, char hflag_test);
+
+void BM_mesh_elem_hflag_enable_all(BMesh *bm, char htype, char hflag, bool respecthide);
+void BM_mesh_elem_hflag_disable_all(BMesh *bm, char htype, char hflag, bool respecthide);
+
+/* Individual element select functions, #BM_elem_select_set is a shortcut for these
* that automatically detects which one to use. */
-void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select);
-void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select);
-void BM_face_select_set(BMesh *bm, BMFace *f, const bool select);
-/* lower level functions which don't do flushing */
-void BM_edge_select_set_noflush(BMesh *bm, BMEdge *e, const bool select);
-void BM_face_select_set_noflush(BMesh *bm, BMFace *f, const bool select);
+/**
+ * \brief Select Vert
+ *
+ * Changes selection state of a single vertex
+ * in a mesh
+ */
+void BM_vert_select_set(BMesh *bm, BMVert *v, bool select);
+/**
+ * \brief Select Edge
+ *
+ * Changes selection state of a single edge in a mesh.
+ */
+void BM_edge_select_set(BMesh *bm, BMEdge *e, bool select);
+/**
+ * \brief Select Face
+ *
+ * Changes selection state of a single
+ * face in a mesh.
+ */
+void BM_face_select_set(BMesh *bm, BMFace *f, bool select);
+
+/* Lower level functions which don't do flushing. */
-void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode);
+void BM_edge_select_set_noflush(BMesh *bm, BMEdge *e, bool select);
+void BM_face_select_set_noflush(BMesh *bm, BMFace *f, bool select);
+
+/**
+ * \brief Select Mode Clean
+ *
+ * Remove isolated selected elements when in a mode doesn't support them.
+ * eg: in edge-mode a selected vertex must be connected to a selected edge.
+ *
+ * \note this could be made a part of #BM_mesh_select_mode_flush_ex
+ */
+void BM_mesh_select_mode_clean_ex(BMesh *bm, short selectmode);
void BM_mesh_select_mode_clean(BMesh *bm);
+/**
+ * Select Mode Set
+ *
+ * Sets the selection mode for the bmesh,
+ * updating the selection state.
+ */
void BM_mesh_select_mode_set(BMesh *bm, int selectmode);
-void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags);
+/**
+ * \brief Select Mode Flush
+ *
+ * Makes sure to flush selections 'upwards'
+ * (ie: all verts of an edge selects the edge and so on).
+ * This should only be called by system and not tool authors.
+ */
+void BM_mesh_select_mode_flush_ex(BMesh *bm, short selectmode, eBMSelectionFlushFLags flags);
void BM_mesh_select_mode_flush(BMesh *bm);
+/**
+ * Mode independent de-selection flush (up/down).
+ */
void BM_mesh_deselect_flush(BMesh *bm);
+/**
+ * Mode independent selection flush (up/down).
+ */
void BM_mesh_select_flush(BMesh *bm);
-int BM_mesh_elem_hflag_count_enabled(BMesh *bm,
- const char htype,
- const char hflag,
- const bool respecthide);
-int BM_mesh_elem_hflag_count_disabled(BMesh *bm,
- const char htype,
- const char hflag,
- const bool respecthide);
+int BM_mesh_elem_hflag_count_enabled(BMesh *bm, char htype, char hflag, bool respecthide);
+int BM_mesh_elem_hflag_count_disabled(BMesh *bm, char htype, char hflag, bool respecthide);
+
+/* Edit selection stuff. */
-/* edit selection stuff */
void BM_mesh_active_face_set(BMesh *bm, BMFace *f);
-BMFace *BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected);
+BMFace *BM_mesh_active_face_get(BMesh *bm, bool is_sloppy, bool is_selected);
BMEdge *BM_mesh_active_edge_get(BMesh *bm);
BMVert *BM_mesh_active_vert_get(BMesh *bm);
BMElem *BM_mesh_active_elem_get(BMesh *bm);
+/**
+ * Generic way to get data from an #BMEditSelection type
+ * These functions were written to be used by the Modifier widget
+ * when in Rotate about active mode, but can be used anywhere.
+ *
+ * - #BM_editselection_center
+ * - #BM_editselection_normal
+ * - #BM_editselection_plane
+ */
void BM_editselection_center(BMEditSelection *ese, float r_center[3]);
void BM_editselection_normal(BMEditSelection *ese, float r_normal[3]);
+/**
+ * Calculate a plane that is right angles to the edge/vert/faces normal
+ * also make the plane run along an axis that is related to the geometry,
+ * because this is used for the gizmos Y axis.
+ */
void BM_editselection_plane(BMEditSelection *ese, float r_plane[3]);
#define BM_select_history_check(bm, ele) _bm_select_history_check(bm, &(ele)->head)
@@ -131,11 +178,20 @@ void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref,
void BM_select_history_validate(BMesh *bm);
void BM_select_history_clear(BMesh *bm);
+/**
+ * Get the active mesh element (with active-face fallback).
+ */
bool BM_select_history_active_get(BMesh *bm, struct BMEditSelection *ese);
+/**
+ * Return a map from #BMVert/#BMEdge/#BMFace -> #BMEditSelection.
+ */
struct GHash *BM_select_history_map_create(BMesh *bm);
+/**
+ * Map arguments may all be the same pointer.
+ */
void BM_select_history_merge_from_targetmap(
- BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain);
+ BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, bool use_chain);
#define BM_SELECT_HISTORY_BACKUP(bm) \
{ \
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index b2958a9e744..b65f6e4c872 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -34,7 +34,6 @@
#include "bmesh.h"
-/* used as an extern, defined in bmesh.h */
const BMAllocTemplate bm_mesh_allocsize_default = {512, 1024, 2048, 512};
const BMAllocTemplate bm_mesh_chunksize_default = {512, 1024, 2048, 512};
@@ -137,15 +136,6 @@ void BM_mesh_elem_toolflags_clear(BMesh *bm)
}
}
-/**
- * \brief BMesh Make Mesh
- *
- * Allocates a new BMesh structure.
- *
- * \return The New bmesh
- *
- * \note ob is needed by multires
- */
BMesh *BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreateParams *params)
{
/* allocate the structure */
@@ -167,13 +157,6 @@ BMesh *BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreate
return bm;
}
-/**
- * \brief BMesh Free Mesh Data
- *
- * Frees a BMesh structure.
- *
- * \note frees mesh, but not actual BMesh struct
- */
void BM_mesh_data_free(BMesh *bm)
{
BMVert *v;
@@ -265,11 +248,6 @@ void BM_mesh_data_free(BMesh *bm)
BMO_error_clear(bm);
}
-/**
- * \brief BMesh Clear Mesh
- *
- * Clear all data in bm
- */
void BM_mesh_clear(BMesh *bm)
{
const bool use_toolflags = bm->use_toolflags;
@@ -291,11 +269,6 @@ void BM_mesh_clear(BMesh *bm)
CustomData_reset(&bm->pdata);
}
-/**
- * \brief BMesh Free Mesh
- *
- * Frees a BMesh data and its structure.
- */
void BM_mesh_free(BMesh *bm)
{
BM_mesh_data_free(bm);
@@ -310,13 +283,6 @@ void BM_mesh_free(BMesh *bm)
MEM_freeN(bm);
}
-/**
- * \brief BMesh Begin Edit
- *
- * Functions for setting up a mesh for editing and cleaning up after
- * the editing operations are done. These are called by the tools/operator
- * API for each time a tool is executed.
- */
void bmesh_edit_begin(BMesh *UNUSED(bm), BMOpTypeFlag UNUSED(type_flag))
{
/* Most operators seem to be using BMO_OPTYPE_FLAG_UNTAN_MULTIRES to change the MDisps to
@@ -337,9 +303,6 @@ void bmesh_edit_begin(BMesh *UNUSED(bm), BMOpTypeFlag UNUSED(type_flag))
#endif
}
-/**
- * \brief BMesh End Edit
- */
void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
{
ListBase select_history;
@@ -499,18 +462,6 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
BM_mesh_elem_index_ensure_ex(bm, htype, NULL);
}
-/**
- * Array checking/setting macros
- *
- * Currently vert/edge/loop/face index data is being abused, in a few areas of the code.
- *
- * To avoid correcting them afterwards, set 'bm->elem_index_dirty' however its possible
- * this flag is set incorrectly which could crash blender.
- *
- * Code that calls this functions may depend on dirty indices on being set.
- * Keep this function read-only.
- */
-
void BM_mesh_elem_index_validate(
BMesh *bm, const char *location, const char *func, const char *msg_a, const char *msg_b)
{
@@ -693,7 +644,6 @@ finally:
bm->elem_table_dirty &= ~htype_needed;
}
-/* use BM_mesh_elem_table_ensure where possible to avoid full rebuild */
void BM_mesh_elem_table_init(BMesh *bm, const char htype)
{
BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
@@ -754,11 +704,6 @@ BMLoop *BM_loop_at_index_find(BMesh *bm, const int index)
return NULL;
}
-/**
- * Use lookup table when available, else use slower find functions.
- *
- * \note Try to use #BM_mesh_elem_table_ensure instead.
- */
BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index)
{
if ((bm->elem_table_dirty & BM_VERT) == 0) {
@@ -783,9 +728,6 @@ BMFace *BM_face_at_index_find_or_table(BMesh *bm, const int index)
return BM_face_at_index_find(bm, index);
}
-/**
- * Return the amount of element of type 'type' in a given bmesh.
- */
int BM_mesh_elem_count(BMesh *bm, const char htype)
{
BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
@@ -804,20 +746,6 @@ int BM_mesh_elem_count(BMesh *bm, const char htype)
}
}
-/**
- * Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays
- * (xxx_idx[org_index] = new_index).
- *
- * A NULL array means no changes.
- *
- * \note
- * - Does not mess with indices, just sets elem_index_dirty flag.
- * - For verts/edges/faces only (as loops must remain "ordered" and "aligned"
- * on a per-face basis...).
- *
- * \warning Be careful if you keep pointers to affected BM elements,
- * or arrays, when using this func!
- */
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx)
{
/* Mapping old to new pointers. */
@@ -1000,7 +928,7 @@ void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const
/* Edges' pointers, only vert pointers (as we don't mess with loops!),
* and - ack! - edge pointers,
- * as we have to handle disklinks... */
+ * as we have to handle disk-links. */
if (vptr_map || eptr_map) {
BM_ITER_MESH (ed, &iter, bm, BM_EDGES_OF_MESH) {
if (vptr_map) {
@@ -1106,12 +1034,6 @@ void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const
}
}
-/**
- * Use new memory pools for this mesh.
- *
- * \note needed for re-sizing elements (adding/removing tool flags)
- * but could also be used for packing fragmented bmeshes.
- */
void BM_mesh_rebuild(BMesh *bm,
const struct BMeshCreateParams *params,
BLI_mempool *vpool_dst,
@@ -1363,9 +1285,6 @@ void BM_mesh_rebuild(BMesh *bm,
}
}
-/**
- * Re-allocates mesh data with/without toolflags.
- */
void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags)
{
if (bm->use_toolflags == use_toolflags) {
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index bd0504b038a..94615d558fa 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -34,30 +34,85 @@ struct BMeshCreateParams {
uint use_toolflags : 1;
};
+/**
+ * \brief BMesh Make Mesh
+ *
+ * Allocates a new BMesh structure.
+ *
+ * \return The New bmesh
+ *
+ * \note ob is needed by multires
+ */
BMesh *BM_mesh_create(const struct BMAllocTemplate *allocsize,
const struct BMeshCreateParams *params);
+/**
+ * \brief BMesh Free Mesh
+ *
+ * Frees a BMesh data and its structure.
+ */
void BM_mesh_free(BMesh *bm);
+/**
+ * \brief BMesh Free Mesh Data
+ *
+ * Frees a BMesh structure.
+ *
+ * \note frees mesh, but not actual BMesh struct
+ */
void BM_mesh_data_free(BMesh *bm);
+/**
+ * \brief BMesh Clear Mesh
+ *
+ * Clear all data in bm
+ */
void BM_mesh_clear(BMesh *bm);
-void bmesh_edit_begin(BMesh *bm, const BMOpTypeFlag type_flag);
-void bmesh_edit_end(BMesh *bm, const BMOpTypeFlag type_flag);
+/**
+ * \brief BMesh Begin Edit
+ *
+ * Functions for setting up a mesh for editing and cleaning up after
+ * the editing operations are done. These are called by the tools/operator
+ * API for each time a tool is executed.
+ */
+void bmesh_edit_begin(BMesh *bm, BMOpTypeFlag type_flag);
+/**
+ * \brief BMesh End Edit
+ */
+void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag);
-void BM_mesh_elem_index_ensure_ex(BMesh *bm, const char htype, int elem_offset[4]);
-void BM_mesh_elem_index_ensure(BMesh *bm, const char htype);
+void BM_mesh_elem_index_ensure_ex(BMesh *bm, char htype, int elem_offset[4]);
+void BM_mesh_elem_index_ensure(BMesh *bm, char htype);
+/**
+ * Array checking/setting macros.
+ *
+ * Currently vert/edge/loop/face index data is being abused, in a few areas of the code.
+ *
+ * To avoid correcting them afterwards, set 'bm->elem_index_dirty' however its possible
+ * this flag is set incorrectly which could crash blender.
+ *
+ * Functions that calls this function may depend on dirty indices on being set.
+ *
+ * This is read-only, so it can be used for assertions that don't impact behavior.
+ */
void BM_mesh_elem_index_validate(
BMesh *bm, const char *location, const char *func, const char *msg_a, const char *msg_b);
-void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags);
-
#ifndef NDEBUG
+/**
+ * \see #BM_mesh_elem_index_validate the same rationale applies to this function.
+ */
bool BM_mesh_elem_table_check(BMesh *bm);
#endif
-void BM_mesh_elem_table_ensure(BMesh *bm, const char htype);
-void BM_mesh_elem_table_init(BMesh *bm, const char htype);
-void BM_mesh_elem_table_free(BMesh *bm, const char htype);
+/**
+ * Re-allocates mesh data with/without toolflags.
+ */
+void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags);
+
+void BM_mesh_elem_table_ensure(BMesh *bm, char htype);
+/* use BM_mesh_elem_table_ensure where possible to avoid full rebuild */
+void BM_mesh_elem_table_init(BMesh *bm, char htype);
+void BM_mesh_elem_table_free(BMesh *bm, char htype);
BLI_INLINE BMVert *BM_vert_at_index(BMesh *bm, const int index)
{
@@ -78,21 +133,49 @@ BLI_INLINE BMFace *BM_face_at_index(BMesh *bm, const int index)
return bm->ftable[index];
}
-BMVert *BM_vert_at_index_find(BMesh *bm, const int index);
-BMEdge *BM_edge_at_index_find(BMesh *bm, const int index);
-BMFace *BM_face_at_index_find(BMesh *bm, const int index);
-BMLoop *BM_loop_at_index_find(BMesh *bm, const int index);
+BMVert *BM_vert_at_index_find(BMesh *bm, int index);
+BMEdge *BM_edge_at_index_find(BMesh *bm, int index);
+BMFace *BM_face_at_index_find(BMesh *bm, int index);
+BMLoop *BM_loop_at_index_find(BMesh *bm, int index);
-BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index);
-BMEdge *BM_edge_at_index_find_or_table(BMesh *bm, const int index);
-BMFace *BM_face_at_index_find_or_table(BMesh *bm, const int index);
+/**
+ * Use lookup table when available, else use slower find functions.
+ *
+ * \note Try to use #BM_mesh_elem_table_ensure instead.
+ */
+BMVert *BM_vert_at_index_find_or_table(BMesh *bm, int index);
+BMEdge *BM_edge_at_index_find_or_table(BMesh *bm, int index);
+BMFace *BM_face_at_index_find_or_table(BMesh *bm, int index);
// XXX
-int BM_mesh_elem_count(BMesh *bm, const char htype);
+/**
+ * Return the amount of element of type 'type' in a given bmesh.
+ */
+int BM_mesh_elem_count(BMesh *bm, char htype);
+/**
+ * Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays
+ * (xxx_idx[org_index] = new_index).
+ *
+ * A NULL array means no changes.
+ *
+ * \note
+ * - Does not mess with indices, just sets elem_index_dirty flag.
+ * - For verts/edges/faces only (as loops must remain "ordered" and "aligned"
+ * on a per-face basis...).
+ *
+ * \warning Be careful if you keep pointers to affected BM elements,
+ * or arrays, when using this func!
+ */
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx);
+/**
+ * Use new memory pools for this mesh.
+ *
+ * \note needed for re-sizing elements (adding/removing tool flags)
+ * but could also be used for packing fragmented bmeshes.
+ */
void BM_mesh_rebuild(BMesh *bm,
const struct BMeshCreateParams *params,
struct BLI_mempool *vpool,
@@ -104,6 +187,7 @@ typedef struct BMAllocTemplate {
int totvert, totedge, totloop, totface;
} BMAllocTemplate;
+/* used as an extern, defined in bmesh.h */
extern const BMAllocTemplate bm_mesh_allocsize_default;
extern const BMAllocTemplate bm_mesh_chunksize_default;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.c b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
index 9d29a90a7a4..d6c642ff80b 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
@@ -40,7 +40,7 @@
*
* - The active key-block is used for BMesh vertex locations on entering edit-mode.
* So obviously the meshes vertex locations remain unchanged and the shape key
- * its self is not being edited directly.
+ * itself is not being edited directly.
* Simply the #BMVert.co is a initialized from active shape key (when its set).
* - All key-blocks are added as CustomData layers (read code for details).
*
@@ -79,8 +79,11 @@
#include "MEM_guardedalloc.h"
#include "BLI_alloca.h"
+#include "BLI_array.hh"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
+#include "BLI_span.hh"
#include "BKE_customdata.h"
#include "BKE_mesh.h"
@@ -95,6 +98,10 @@
#include "bmesh.h"
#include "intern/bmesh_private.h" /* For element checking. */
+using blender::Array;
+using blender::IndexRange;
+using blender::Span;
+
void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag)
{
const char cd_flag_all = BM_mesh_cd_flag_from_bmesh(bm) | cd_flag;
@@ -107,9 +114,9 @@ void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag)
void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag)
{
/* CustomData_bmesh_init_pool() must run first */
- BLI_assert(bm->vdata.totlayer == 0 || bm->vdata.pool != NULL);
- BLI_assert(bm->edata.totlayer == 0 || bm->edata.pool != NULL);
- BLI_assert(bm->pdata.totlayer == 0 || bm->pdata.pool != NULL);
+ BLI_assert(bm->vdata.totlayer == 0 || bm->vdata.pool != nullptr);
+ BLI_assert(bm->edata.totlayer == 0 || bm->edata.pool != nullptr);
+ BLI_assert(bm->pdata.totlayer == 0 || bm->pdata.pool != nullptr);
if (cd_flag & ME_CDFLAG_VERT_BWEIGHT) {
if (!CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
@@ -122,6 +129,17 @@ void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag)
}
}
+ if (cd_flag & ME_CDFLAG_VERT_CREASE) {
+ if (!CustomData_has_layer(&bm->vdata, CD_CREASE)) {
+ BM_data_layer_add(bm, &bm->vdata, CD_CREASE);
+ }
+ }
+ else {
+ if (CustomData_has_layer(&bm->vdata, CD_CREASE)) {
+ BM_data_layer_free(bm, &bm->vdata, CD_CREASE);
+ }
+ }
+
if (cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
if (!CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
BM_data_layer_add(bm, &bm->edata, CD_BWEIGHT);
@@ -151,6 +169,9 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm)
if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
}
+ if (CustomData_has_layer(&bm->vdata, CD_CREASE)) {
+ cd_flag |= ME_CDFLAG_VERT_CREASE;
+ }
if (CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
}
@@ -161,45 +182,28 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm)
}
/* Static function for alloc (duplicate in modifiers_bmesh.c) */
-static BMFace *bm_face_create_from_mpoly(
- MPoly *mp, MLoop *ml, BMesh *bm, BMVert **vtable, BMEdge **etable)
+static BMFace *bm_face_create_from_mpoly(BMesh &bm,
+ Span<MLoop> loops,
+ Span<BMVert *> vtable,
+ Span<BMEdge *> etable)
{
- BMVert **verts = BLI_array_alloca(verts, mp->totloop);
- BMEdge **edges = BLI_array_alloca(edges, mp->totloop);
- int j;
+ Array<BMVert *, BM_DEFAULT_NGON_STACK_SIZE> verts(loops.size());
+ Array<BMEdge *, BM_DEFAULT_NGON_STACK_SIZE> edges(loops.size());
- for (j = 0; j < mp->totloop; j++, ml++) {
- verts[j] = vtable[ml->v];
- edges[j] = etable[ml->e];
+ for (const int i : loops.index_range()) {
+ verts[i] = vtable[loops[i].v];
+ edges[i] = etable[loops[i].e];
}
- return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD);
+ return BM_face_create(&bm, verts.data(), edges.data(), loops.size(), nullptr, BM_CREATE_SKIP_CD);
}
-/**
- * \brief Mesh -> BMesh
- * \param bm: The mesh to write into, while this is typically a newly created BMesh,
- * merging into existing data is supported.
- * Note the custom-data layout isn't used.
- * If more comprehensive merging is needed we should move this into a separate function
- * since this should be kept fast for edit-mode switching and storing undo steps.
- *
- * \warning This function doesn't calculate face normals.
- */
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
{
const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer ||
bm->pdata.totlayer || bm->ldata.totlayer));
- MVert *mvert;
- MEdge *medge;
- MLoop *mloop;
- MPoly *mp;
- KeyBlock *actkey, *block;
- BMVert *v, **vtable = NULL;
- BMEdge *e, **etable = NULL;
- BMFace *f, **ftable = NULL;
- float(*keyco)[3] = NULL;
- int totloops, i;
+ KeyBlock *actkey;
+ float(*keyco)[3] = nullptr;
CustomData_MeshMasks mask = CD_MASK_BMESH;
CustomData_MeshMasks_update(&mask, &params->cd_mask_extra);
@@ -218,6 +222,14 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
return; /* Sanity check. */
}
+ /* Only copy normals to the new BMesh if they are not already dirty. This avoids unnecessary
+ * work, but also accessing normals on an incomplete mesh, for example when restoring undo steps
+ * in edit mode. */
+ const float(*vert_normals)[3] = nullptr;
+ if (!BKE_mesh_vertex_normals_are_dirty(me)) {
+ vert_normals = BKE_mesh_vertex_normals_ensure(me);
+ }
+
if (is_new) {
CustomData_copy(&me->vdata, &bm->vdata, mask.vmask, CD_CALLOC, 0);
CustomData_copy(&me->edata, &bm->edata, mask.emask, CD_CALLOC, 0);
@@ -234,7 +246,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
/* -------------------------------------------------------------------- */
/* Shape Key */
int tot_shape_keys = 0;
- if (me->key != NULL && DEG_is_original_id(&me->id)) {
+ if (me->key != nullptr && DEG_is_original_id(&me->id)) {
/* Evaluated meshes can be topologically inconsistent with their shape keys.
* Shape keys are also already integrated into the state of the evaluated
* mesh, so considering them here would kind of apply them twice. */
@@ -261,20 +273,20 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
if (is_new == false) {
tot_shape_keys = min_ii(tot_shape_keys, CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY));
}
- const float(**shape_key_table)[3] = tot_shape_keys ?
- BLI_array_alloca(shape_key_table, tot_shape_keys) :
- NULL;
+ const float(**shape_key_table)[3] = tot_shape_keys ? (const float(**)[3])BLI_array_alloca(
+ shape_key_table, tot_shape_keys) :
+ nullptr;
if ((params->active_shapekey != 0) && tot_shape_keys > 0) {
- actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1);
+ actkey = static_cast<KeyBlock *>(BLI_findlink(&me->key->block, params->active_shapekey - 1));
}
else {
- actkey = NULL;
+ actkey = nullptr;
}
if (is_new) {
if (tot_shape_keys || params->add_key_index) {
- CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);
+ CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, nullptr, 0);
}
}
@@ -289,26 +301,29 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
__func__);
me->key->uidgen = 1;
- for (block = me->key->block.first; block; block = block->next) {
+ LISTBASE_FOREACH (KeyBlock *, block, &me->key->block) {
block->uid = me->key->uidgen++;
}
}
}
if (actkey && actkey->totelem == me->totvert) {
- keyco = params->use_shapekey ? actkey->data : NULL;
+ keyco = params->use_shapekey ? static_cast<float(*)[3]>(actkey->data) : nullptr;
if (is_new) {
bm->shapenr = params->active_shapekey;
}
}
- for (i = 0, block = me->key->block.first; i < tot_shape_keys; block = block->next, i++) {
+ int i;
+ KeyBlock *block;
+ for (i = 0, block = static_cast<KeyBlock *>(me->key->block.first); i < tot_shape_keys;
+ block = block->next, i++) {
if (is_new) {
- CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, CD_ASSIGN, NULL, 0, block->name);
+ CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, CD_ASSIGN, nullptr, 0, block->name);
int j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i);
bm->vdata.layers[j].uid = block->uid;
}
- shape_key_table[i] = (const float(*)[3])block->data;
+ shape_key_table[i] = static_cast<const float(*)[3]>(block->data);
}
}
@@ -317,40 +332,50 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP);
CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE);
-
- BM_mesh_cd_flag_apply(bm, me->cd_flag);
}
-
- const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
- const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
- const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
+ BM_mesh_cd_flag_apply(bm, me->cd_flag | (is_new ? 0 : BM_mesh_cd_flag_from_bmesh(bm)));
+
+ /* Only copy these values over if the source mesh is flagged to be using them.
+ * Even if `bm` has these layers, they may have been added from another mesh, when `!is_new`. */
+ const int cd_vert_bweight_offset = (me->cd_flag & ME_CDFLAG_VERT_BWEIGHT) ?
+ CustomData_get_offset(&bm->vdata, CD_BWEIGHT) :
+ -1;
+ const int cd_edge_bweight_offset = (me->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) ?
+ CustomData_get_offset(&bm->edata, CD_BWEIGHT) :
+ -1;
+ const int cd_edge_crease_offset = (me->cd_flag & ME_CDFLAG_EDGE_CREASE) ?
+ CustomData_get_offset(&bm->edata, CD_CREASE) :
+ -1;
const int cd_shape_key_offset = tot_shape_keys ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) :
-1;
const int cd_shape_keyindex_offset = is_new && (tot_shape_keys || params->add_key_index) ?
CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) :
-1;
- vtable = MEM_mallocN(sizeof(BMVert **) * me->totvert, __func__);
-
- for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
- v = vtable[i] = BM_vert_create(bm, keyco ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD);
+ Span<MVert> mvert{me->mvert, me->totvert};
+ Array<BMVert *> vtable(me->totvert);
+ for (const int i : mvert.index_range()) {
+ BMVert *v = vtable[i] = BM_vert_create(
+ bm, keyco ? keyco[i] : mvert[i].co, nullptr, BM_CREATE_SKIP_CD);
BM_elem_index_set(v, i); /* set_ok */
/* Transfer flag. */
- v->head.hflag = BM_vert_flag_from_mflag(mvert->flag & ~SELECT);
+ v->head.hflag = BM_vert_flag_from_mflag(mvert[i].flag & ~SELECT);
/* This is necessary for selection counts to work properly. */
- if (mvert->flag & SELECT) {
+ if (mvert[i].flag & SELECT) {
BM_vert_select_set(bm, v, true);
}
- normal_short_to_float_v3(v->no, mvert->no);
+ if (vert_normals) {
+ copy_v3_v3(v->no, vert_normals[i]);
+ }
/* Copy Custom Data */
CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data, true);
if (cd_vert_bweight_offset != -1) {
- BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert->bweight / 255.0f);
+ BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert[i].bweight / 255.0f);
}
/* Set shape key original index. */
@@ -360,7 +385,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
/* Set shape-key data. */
if (tot_shape_keys) {
- float(*co_dst)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset);
+ float(*co_dst)[3] = (float(*)[3])BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset);
for (int j = 0; j < tot_shape_keys; j++, co_dst++) {
copy_v3_v3(*co_dst, shape_key_table[j][i]);
}
@@ -370,19 +395,18 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
bm->elem_index_dirty &= ~BM_VERT; /* Added in order, clear dirty flag. */
}
- etable = MEM_mallocN(sizeof(BMEdge **) * me->totedge, __func__);
-
- medge = me->medge;
- for (i = 0; i < me->totedge; i++, medge++) {
- e = etable[i] = BM_edge_create(
- bm, vtable[medge->v1], vtable[medge->v2], NULL, BM_CREATE_SKIP_CD);
+ Span<MEdge> medge{me->medge, me->totedge};
+ Array<BMEdge *> etable(me->totedge);
+ for (const int i : medge.index_range()) {
+ BMEdge *e = etable[i] = BM_edge_create(
+ bm, vtable[medge[i].v1], vtable[medge[i].v2], nullptr, BM_CREATE_SKIP_CD);
BM_elem_index_set(e, i); /* set_ok */
/* Transfer flags. */
- e->head.hflag = BM_edge_flag_from_mflag(medge->flag & ~SELECT);
+ e->head.hflag = BM_edge_flag_from_mflag(medge[i].flag & ~SELECT);
/* This is necessary for selection counts to work properly. */
- if (medge->flag & SELECT) {
+ if (medge[i].flag & SELECT) {
BM_edge_select_set(bm, e, true);
}
@@ -390,33 +414,35 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data, true);
if (cd_edge_bweight_offset != -1) {
- BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)medge->bweight / 255.0f);
+ BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)medge[i].bweight / 255.0f);
}
if (cd_edge_crease_offset != -1) {
- BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)medge->crease / 255.0f);
+ BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)medge[i].crease / 255.0f);
}
}
if (is_new) {
bm->elem_index_dirty &= ~BM_EDGE; /* Added in order, clear dirty flag. */
}
+ Span<MPoly> mpoly{me->mpoly, me->totpoly};
+ Span<MLoop> mloop{me->mloop, me->totloop};
+
/* Only needed for selection. */
+
+ Array<BMFace *> ftable;
if (me->mselect && me->totselect != 0) {
- ftable = MEM_mallocN(sizeof(BMFace **) * me->totpoly, __func__);
+ ftable.reinitialize(me->totpoly);
}
- mloop = me->mloop;
- mp = me->mpoly;
- for (i = 0, totloops = 0; i < me->totpoly; i++, mp++) {
- BMLoop *l_iter;
- BMLoop *l_first;
-
- f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart, bm, vtable, etable);
- if (ftable != NULL) {
+ int totloops = 0;
+ for (const int i : mpoly.index_range()) {
+ BMFace *f = bm_face_create_from_mpoly(
+ *bm, mloop.slice(mpoly[i].loopstart, mpoly[i].totloop), vtable, etable);
+ if (!ftable.is_empty()) {
ftable[i] = f;
}
- if (UNLIKELY(f == NULL)) {
+ if (UNLIKELY(f == nullptr)) {
printf(
"%s: Warning! Bad face in mesh"
" \"%s\" at index %d!, skipping\n",
@@ -430,20 +456,21 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
BM_elem_index_set(f, bm->totface - 1); /* set_ok */
/* Transfer flag. */
- f->head.hflag = BM_face_flag_from_mflag(mp->flag & ~ME_FACE_SEL);
+ f->head.hflag = BM_face_flag_from_mflag(mpoly[i].flag & ~ME_FACE_SEL);
/* This is necessary for selection counts to work properly. */
- if (mp->flag & ME_FACE_SEL) {
+ if (mpoly[i].flag & ME_FACE_SEL) {
BM_face_select_set(bm, f, true);
}
- f->mat_nr = mp->mat_nr;
+ f->mat_nr = mpoly[i].mat_nr;
if (i == me->act_face) {
bm->act_face = f;
}
- int j = mp->loopstart;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ int j = mpoly[i].loopstart;
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
do {
/* Don't use 'j' since we may have skipped some faces, hence some loops. */
BM_elem_index_set(l_iter, totloops++); /* set_ok */
@@ -464,44 +491,39 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
}
/* -------------------------------------------------------------------- */
- /* MSelect clears the array elements (avoid adding multiple times).
+ /* MSelect clears the array elements (to avoid adding multiple times).
*
* Take care to keep this last and not use (v/e/ftable) after this.
*/
if (me->mselect && me->totselect != 0) {
- MSelect *msel;
- for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) {
+ for (const int i : IndexRange(me->totselect)) {
+ const MSelect &msel = me->mselect[i];
+
BMElem **ele_p;
- switch (msel->type) {
+ switch (msel.type) {
case ME_VSEL:
- ele_p = (BMElem **)&vtable[msel->index];
+ ele_p = (BMElem **)&vtable[msel.index];
break;
case ME_ESEL:
- ele_p = (BMElem **)&etable[msel->index];
+ ele_p = (BMElem **)&etable[msel.index];
break;
case ME_FSEL:
- ele_p = (BMElem **)&ftable[msel->index];
+ ele_p = (BMElem **)&ftable[msel.index];
break;
default:
continue;
}
- if (*ele_p != NULL) {
+ if (*ele_p != nullptr) {
BM_select_history_store_notest(bm, *ele_p);
- *ele_p = NULL;
+ *ele_p = nullptr;
}
}
}
else {
BM_select_history_clear(bm);
}
-
- MEM_freeN(vtable);
- MEM_freeN(etable);
- if (ftable) {
- MEM_freeN(ftable);
- }
}
/**
@@ -510,7 +532,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
{
const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
- BMVert **vertMap = NULL;
+ BMVert **vertMap = nullptr;
BMVert *eve;
int i = 0;
BMIter iter;
@@ -518,7 +540,7 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
/* Caller needs to ensure this. */
BLI_assert(ototvert > 0);
- vertMap = MEM_callocN(sizeof(*vertMap) * ototvert, "vertMap");
+ vertMap = static_cast<BMVert **>(MEM_callocN(sizeof(*vertMap) * ototvert, "vertMap"));
if (cd_shape_keyindex_offset != -1) {
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
@@ -526,7 +548,7 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
/* Not fool-proof, but chances are if we have many verts with the same index,
* we will want to use the first one,
* since the second is more likely to be a duplicate. */
- (vertMap[keyi] == NULL)) {
+ (vertMap[keyi] == nullptr)) {
vertMap[keyi] = eve;
}
}
@@ -569,8 +591,8 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
{
/* This is a cheap way to set the edge draw, its not precise and will
* pick the first 2 faces an edge uses.
- * The dot comparison is a little arbitrary, but set so that a 5 subd
- * IcoSphere won't vanish but subd 6 will (as with pre-bmesh Blender). */
+ * The dot comparison is a little arbitrary, but set so that a 5 subdivisions
+ * ico-sphere won't vanish but 6 subdivisions will (as with pre-bmesh Blender). */
if (/* (med->flag & ME_EDGEDRAW) && */ /* Assume to be true. */
(e->l && (e->l != e->l->radial_next)) &&
@@ -582,10 +604,6 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
}
}
-/**
- *
- * \param bmain: May be NULL in case \a calc_object_remap parameter option is not set.
- */
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
{
MEdge *med;
@@ -600,7 +618,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
- MVert *oldverts = NULL;
+ MVert *oldverts = nullptr;
const int ototvert = me->totvert;
if (me->key && (cd_shape_keyindex_offset != -1)) {
@@ -611,9 +629,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
oldverts = MEM_dupallocN(me->mvert);
#else
oldverts = me->mvert;
- me->mvert = NULL;
+ me->mvert = nullptr;
CustomData_update_typemap(&me->vdata);
- CustomData_set_layer(&me->vdata, CD_MVERT, NULL);
+ CustomData_set_layer(&me->vdata, CD_MVERT, nullptr);
#endif
}
@@ -630,7 +648,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
me->totloop = bm->totloop;
me->totpoly = bm->totface;
/* Will be overwritten with a valid value if 'dotess' is set, otherwise we
- * end up with 'me->totface' and me->mface == NULL which can crash T28625. */
+ * end up with 'me->totface' and me->mface == nullptr which can crash T28625. */
me->totface = 0;
me->act_face = -1;
@@ -643,25 +661,32 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_CALLOC, me->totpoly);
}
- MVert *mvert = bm->totvert ? MEM_callocN(sizeof(MVert) * bm->totvert, "bm_to_me.vert") : NULL;
- MEdge *medge = bm->totedge ? MEM_callocN(sizeof(MEdge) * bm->totedge, "bm_to_me.edge") : NULL;
- MLoop *mloop = bm->totloop ? MEM_callocN(sizeof(MLoop) * bm->totloop, "bm_to_me.loop") : NULL;
- MPoly *mpoly = bm->totface ? MEM_callocN(sizeof(MPoly) * bm->totface, "bm_to_me.poly") : NULL;
+ MVert *mvert = bm->totvert ? (MVert *)MEM_callocN(sizeof(MVert) * bm->totvert, "bm_to_me.vert") :
+ nullptr;
+ MEdge *medge = bm->totedge ? (MEdge *)MEM_callocN(sizeof(MEdge) * bm->totedge, "bm_to_me.edge") :
+ nullptr;
+ MLoop *mloop = bm->totloop ? (MLoop *)MEM_callocN(sizeof(MLoop) * bm->totloop, "bm_to_me.loop") :
+ nullptr;
+ MPoly *mpoly = bm->totface ? (MPoly *)MEM_callocN(sizeof(MPoly) * bm->totface, "bm_to_me.poly") :
+ nullptr;
CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, mloop, me->totloop);
CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, mpoly, me->totpoly);
+ /* There is no way to tell if BMesh normals are dirty or not. Instead of calculating the normals
+ * on the BMesh possibly unnecessarily, just tag them dirty on the resulting mesh. */
+ BKE_mesh_normals_tag_dirty(me);
+
me->cd_flag = BM_mesh_cd_flag_from_bmesh(bm);
/* This is called again, 'dotess' arg is used there. */
- BKE_mesh_update_customdata_pointers(me, 0);
+ BKE_mesh_update_customdata_pointers(me, false);
i = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
copy_v3_v3(mvert->co, v->co);
- normal_float_to_short_v3(mvert->no, v->no);
mvert->flag = BM_vert_flag_to_mflag(v);
@@ -747,15 +772,13 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
/* Patch hook indices and vertex parents. */
if (params->calc_object_remap && (ototvert > 0)) {
- BLI_assert(bmain != NULL);
- Object *ob;
- ModifierData *md;
- BMVert **vertMap = NULL;
+ BLI_assert(bmain != nullptr);
+ BMVert **vertMap = nullptr;
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
if ((ob->parent) && (ob->parent->data == me) && ELEM(ob->partype, PARVERT1, PARVERT3)) {
- if (vertMap == NULL) {
+ if (vertMap == nullptr) {
vertMap = bm_to_mesh_vertex_map(bm, ototvert);
}
@@ -779,11 +802,11 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
}
if (ob->data == me) {
- for (md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_Hook) {
HookModifierData *hmd = (HookModifierData *)md;
- if (vertMap == NULL) {
+ if (vertMap == nullptr) {
vertMap = bm_to_mesh_vertex_map(bm, ototvert);
}
@@ -814,15 +837,15 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BKE_mesh_update_customdata_pointers(me, false);
{
- BMEditSelection *selected;
me->totselect = BLI_listbase_count(&(bm->selected));
MEM_SAFE_FREE(me->mselect);
if (me->totselect != 0) {
- me->mselect = MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history");
+ me->mselect = static_cast<MSelect *>(
+ MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history"));
}
- for (i = 0, selected = bm->selected.first; selected; i++, selected = selected->next) {
+ LISTBASE_FOREACH_INDEX (BMEditSelection *, selected, &bm->selected, i) {
if (selected->htype == BM_VERT) {
me->mselect[i].type = ME_VSEL;
}
@@ -841,9 +864,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
if (me->key) {
KeyBlock *currkey;
- KeyBlock *actkey = BLI_findlink(&me->key->block, bm->shapenr - 1);
+ KeyBlock *actkey = static_cast<KeyBlock *>(BLI_findlink(&me->key->block, bm->shapenr - 1));
- float(*ofs)[3] = NULL;
+ float(*ofs)[3] = nullptr;
/* Go through and find any shape-key custom-data layers
* that might not have corresponding KeyBlocks, and add them if necessary. */
@@ -852,7 +875,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
continue;
}
- for (currkey = me->key->block.first; currkey; currkey = currkey->next) {
+ for (currkey = (KeyBlock *)me->key->block.first; currkey; currkey = currkey->next) {
if (currkey->uid == bm->vdata.layers[i].uid) {
break;
}
@@ -870,10 +893,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
/* Unlikely, but the active key may not be valid if the
* BMesh and the mesh are out of sync. */
- (actkey != NULL) &&
+ (actkey != nullptr) &&
/* Not used here, but 'oldverts' is used later for applying 'ofs'. */
- (oldverts != NULL) &&
+ (oldverts != nullptr) &&
/* Needed for referencing oldverts. */
(cd_shape_keyindex_offset != -1)) {
@@ -882,9 +905,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
/* Active key is a base. */
if (act_is_basis) {
- const float(*fp)[3] = actkey->data;
+ const float(*fp)[3] = static_cast<const float(*)[3]>(actkey->data);
- ofs = MEM_callocN(sizeof(float[3]) * bm->totvert, "currkey->data");
+ ofs = static_cast<float(*)[3]>(
+ MEM_callocN(sizeof(float[3]) * bm->totvert, "currkey->data"));
mvert = me->mvert;
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
@@ -898,7 +922,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
* because it will only work for the existing vertices and not the new
* ones, creating a mess when doing e.g. subdivide + translate. */
MEM_freeN(ofs);
- ofs = NULL;
+ ofs = nullptr;
break;
}
@@ -907,7 +931,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
}
- for (currkey = me->key->block.first; currkey; currkey = currkey->next) {
+ LISTBASE_FOREACH (KeyBlock *, currkey, &me->key->block) {
int keyi;
const float(*ofs_pt)[3] = ofs;
float *newkey, (*oldkey)[3], *fp;
@@ -917,11 +941,12 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
CustomData_get_n_offset(&bm->vdata,
CD_SHAPEKEY,
currkey_uuid);
- const bool apply_offset = (cd_shape_offset != -1) && (ofs != NULL) && (currkey != actkey) &&
- (bm->shapenr - 1 == currkey->relative);
+ const bool apply_offset = (cd_shape_offset != -1) && (ofs != nullptr) &&
+ (currkey != actkey) && (bm->shapenr - 1 == currkey->relative);
- fp = newkey = MEM_callocN(me->key->elemsize * bm->totvert, "currkey->data");
- oldkey = currkey->data;
+ fp = newkey = static_cast<float *>(
+ MEM_callocN(me->key->elemsize * bm->totvert, "currkey->data"));
+ oldkey = static_cast<float(*)[3]>(currkey->data);
mvert = me->mvert;
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
@@ -942,9 +967,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
else if (cd_shape_offset != -1) {
/* In most cases this runs. */
- copy_v3_v3(fp, BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset));
+ copy_v3_v3(fp, (const float *)BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset));
}
- else if ((oldkey != NULL) && (cd_shape_keyindex_offset != -1) &&
+ else if ((oldkey != nullptr) && (cd_shape_keyindex_offset != -1) &&
((keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset)) != ORIGINDEX_NONE) &&
(keyi < currkey->totelem)) {
/* Old method of reconstructing keys via vertices original key indices,
@@ -964,7 +989,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
* Otherwise, in case we call again #BM_mesh_bm_to_me on same BMesh,
* we'll apply diff from previous call to #BM_mesh_bm_to_me,
* to shape-key values from *original creation of the BMesh*. See T50524. */
- copy_v3_v3(BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset), fp);
+ copy_v3_v3((float *)BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset), fp);
}
fp += 3;
@@ -994,7 +1019,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
}
- if (oldverts != NULL) {
+ if (oldverts != nullptr) {
MEM_freeN(oldverts);
}
@@ -1005,28 +1030,11 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BKE_mesh_runtime_clear_geometry(me);
}
-/**
- * A version of #BM_mesh_bm_to_me intended for getting the mesh
- * to pass to the modifier stack for evaluation,
- * instead of mode switching (where we make sure all data is kept
- * and do expensive lookups to maintain shape keys).
- *
- * Key differences:
- *
- * - Don't support merging with existing mesh.
- * - Ignore shape-keys.
- * - Ignore vertex-parents.
- * - Ignore selection history.
- * - Uses simpler method to calculate #ME_EDGEDRAW
- * - Uses #CD_MASK_DERIVEDMESH instead of #CD_MASK_MESH.
- *
- * \note Was `cddm_from_bmesh_ex` in 2.7x, removed `MFace` support.
- */
void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *cd_mask_extra)
{
/* Must be an empty mesh. */
BLI_assert(me->totvert == 0);
- BLI_assert(cd_mask_extra == NULL || (cd_mask_extra->vmask & CD_MASK_SHAPEKEY) == 0);
+ BLI_assert(cd_mask_extra == nullptr || (cd_mask_extra->vmask & CD_MASK_SHAPEKEY) == 0);
me->totvert = bm->totvert;
me->totedge = bm->totedge;
@@ -1034,19 +1042,19 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
me->totloop = bm->totloop;
me->totpoly = bm->totface;
- CustomData_add_layer(&me->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totvert);
- CustomData_add_layer(&me->edata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totedge);
- CustomData_add_layer(&me->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totface);
+ CustomData_add_layer(&me->vdata, CD_ORIGINDEX, CD_CALLOC, nullptr, bm->totvert);
+ CustomData_add_layer(&me->edata, CD_ORIGINDEX, CD_CALLOC, nullptr, bm->totedge);
+ CustomData_add_layer(&me->pdata, CD_ORIGINDEX, CD_CALLOC, nullptr, bm->totface);
- CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, bm->totvert);
- CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, bm->totedge);
- CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, bm->totloop);
- CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, bm->totface);
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, bm->totvert);
+ CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, nullptr, bm->totedge);
+ CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, nullptr, bm->totloop);
+ CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, nullptr, bm->totface);
/* Don't process shape-keys, we only feed them through the modifier stack as needed,
* e.g. for applying modifiers or the like. */
CustomData_MeshMasks mask = CD_MASK_DERIVEDMESH;
- if (cd_mask_extra != NULL) {
+ if (cd_mask_extra != nullptr) {
CustomData_MeshMasks_update(&mask, cd_mask_extra);
}
mask.vmask &= ~CD_MASK_SHAPEKEY;
@@ -1072,12 +1080,14 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
+ BKE_mesh_normals_tag_dirty(me);
+
me->runtime.deformed_only = true;
/* Don't add origindex layer if one already exists. */
add_orig = !CustomData_has_layer(&bm->pdata, CD_ORIGINDEX);
- index = CustomData_get_layer(&me->vdata, CD_ORIGINDEX);
+ index = (int *)CustomData_get_layer(&me->vdata, CD_ORIGINDEX);
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
MVert *mv = &mvert[i];
@@ -1086,8 +1096,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
BM_elem_index_set(eve, i); /* set_inline */
- normal_float_to_short_v3(mv->no, eve->no);
-
mv->flag = BM_vert_flag_to_mflag(eve);
if (cd_vert_bweight_offset != -1) {
@@ -1102,7 +1110,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
}
bm->elem_index_dirty &= ~BM_VERT;
- index = CustomData_get_layer(&me->edata, CD_ORIGINDEX);
+ index = (int *)CustomData_get_layer(&me->edata, CD_ORIGINDEX);
BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
MEdge *med = &medge[i];
@@ -1135,7 +1143,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
}
bm->elem_index_dirty &= ~BM_EDGE;
- index = CustomData_get_layer(&me->pdata, CD_ORIGINDEX);
+ index = (int *)CustomData_get_layer(&me->pdata, CD_ORIGINDEX);
j = 0;
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
BMLoop *l_iter;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.h b/source/blender/bmesh/intern/bmesh_mesh_convert.h
index 1b5d001d35d..07ffc8b43df 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.h
@@ -29,8 +29,8 @@ struct CustomData_MeshMasks;
struct Main;
struct Mesh;
-void BM_mesh_cd_flag_ensure(BMesh *bm, struct Mesh *mesh, const char cd_flag);
-void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag);
+void BM_mesh_cd_flag_ensure(BMesh *bm, struct Mesh *mesh, char cd_flag);
+void BM_mesh_cd_flag_apply(BMesh *bm, char cd_flag);
char BM_mesh_cd_flag_from_bmesh(BMesh *bm);
struct BMeshFromMeshParams {
@@ -43,6 +43,16 @@ struct BMeshFromMeshParams {
int active_shapekey;
struct CustomData_MeshMasks cd_mask_extra;
};
+/**
+ * \brief Mesh -> BMesh
+ * \param bm: The mesh to write into, while this is typically a newly created BMesh,
+ * merging into existing data is supported.
+ * Note the custom-data layout isn't used.
+ * If more comprehensive merging is needed we should move this into a separate function
+ * since this should be kept fast for edit-mode switching and storing undo steps.
+ *
+ * \warning This function doesn't calculate face normals.
+ */
void BM_mesh_bm_from_me(BMesh *bm, const struct Mesh *me, const struct BMeshFromMeshParams *params)
ATTR_NONNULL(1, 3);
@@ -61,11 +71,32 @@ struct BMeshToMeshParams {
uint update_shapekey_indices : 1;
struct CustomData_MeshMasks cd_mask_extra;
};
+/**
+ *
+ * \param bmain: May be NULL in case \a calc_object_remap parameter option is not set.
+ */
void BM_mesh_bm_to_me(struct Main *bmain,
BMesh *bm,
struct Mesh *me,
const struct BMeshToMeshParams *params) ATTR_NONNULL(2, 3, 4);
+/**
+ * A version of #BM_mesh_bm_to_me intended for getting the mesh
+ * to pass to the modifier stack for evaluation,
+ * instead of mode switching (where we make sure all data is kept
+ * and do expensive lookups to maintain shape keys).
+ *
+ * Key differences:
+ *
+ * - Don't support merging with existing mesh.
+ * - Ignore shape-keys.
+ * - Ignore vertex-parents.
+ * - Ignore selection history.
+ * - Uses simpler method to calculate #ME_EDGEDRAW
+ * - Uses #CD_MASK_DERIVEDMESH instead of #CD_MASK_MESH.
+ *
+ * \note Was `cddm_from_bmesh_ex` in 2.7x, removed `MFace` support.
+ */
void BM_mesh_bm_to_me_for_eval(BMesh *bm,
struct Mesh *me,
const struct CustomData_MeshMasks *cd_mask_extra)
diff --git a/source/blender/bmesh/intern/bmesh_mesh_debug.c b/source/blender/bmesh/intern/bmesh_mesh_debug.c
new file mode 100644
index 00000000000..81a11df13f2
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_mesh_debug.c
@@ -0,0 +1,86 @@
+/*
+ * 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
+ *
+ * Evaluated mesh info printing function, to help track down differences output.
+ *
+ * Output from these functions can be evaluated as Python literals.
+ * See `mesh_debug.cc` for the equivalent #Mesh functionality.
+ */
+
+#ifndef NDEBUG
+
+# include <stdio.h>
+
+# include "MEM_guardedalloc.h"
+
+# include "BLI_utildefines.h"
+
+# include "BKE_customdata.h"
+
+# include "bmesh.h"
+
+# include "bmesh_mesh_debug.h"
+
+# include "BLI_dynstr.h"
+
+char *BM_mesh_debug_info(BMesh *bm)
+{
+ DynStr *dynstr = BLI_dynstr_new();
+ char *ret;
+
+ const char *indent8 = " ";
+
+ BLI_dynstr_append(dynstr, "{\n");
+ BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)bm);
+ BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", bm->totvert);
+ BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", bm->totedge);
+ BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", bm->totface);
+
+ BLI_dynstr_append(dynstr, " 'vert_layers': (\n");
+ CustomData_debug_info_from_layers(&bm->vdata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'edge_layers': (\n");
+ CustomData_debug_info_from_layers(&bm->edata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'loop_layers': (\n");
+ CustomData_debug_info_from_layers(&bm->ldata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'poly_layers': (\n");
+ CustomData_debug_info_from_layers(&bm->pdata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, "}\n");
+
+ ret = BLI_dynstr_get_cstring(dynstr);
+ BLI_dynstr_free(dynstr);
+ return ret;
+}
+
+void BM_mesh_debug_print(BMesh *bm)
+{
+ char *str = BM_mesh_debug_info(bm);
+ puts(str);
+ fflush(stdout);
+ MEM_freeN(str);
+}
+
+#endif /* NDEBUG */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_debug.h b/source/blender/bmesh/intern/bmesh_mesh_debug.h
new file mode 100644
index 00000000000..e903b627419
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_mesh_debug.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bmesh
+ */
+
+#include "BLI_compiler_attrs.h"
+
+#include "bmesh.h"
+
+#ifndef NDEBUG
+char *BM_mesh_debug_info(BMesh *bm) ATTR_NONNULL(1) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+void BM_mesh_debug_print(BMesh *bm) ATTR_NONNULL(1);
+#endif /* NDEBUG */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_duplicate.c b/source/blender/bmesh/intern/bmesh_mesh_duplicate.c
index 1d393abcd56..db21e50bb71 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_duplicate.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_duplicate.c
@@ -85,9 +85,6 @@ static BMFace *bm_face_copy_with_arrays(
return f_dst;
}
-/**
- * Geometry must be completely isolated.
- */
void BM_mesh_copy_arrays(BMesh *bm_src,
BMesh *bm_dst,
BMVert **verts_src,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_duplicate.h b/source/blender/bmesh/intern/bmesh_mesh_duplicate.h
index 8ace555d61f..d15ef8f4ab2 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_duplicate.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_duplicate.h
@@ -20,6 +20,9 @@
* \ingroup bmesh
*/
+/**
+ * Geometry must be completely isolated.
+ */
void BM_mesh_copy_arrays(BMesh *bm_src,
BMesh *bm_dst,
BMVert **verts_src,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.c b/source/blender/bmesh/intern/bmesh_mesh_normals.c
index 186c85abe58..34c07b4f310 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_normals.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_normals.c
@@ -247,11 +247,6 @@ static void bm_face_calc_normals_cb(void *UNUSED(userdata),
BM_face_calc_normal(f, f->no);
}
-/**
- * \brief BMesh Compute Normals
- *
- * Updates the normals of a mesh.
- */
void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *params)
{
if (params->face_normals) {
@@ -295,10 +290,6 @@ static void bm_partial_verts_parallel_range_calc_normal_cb(
bm_vert_calc_normals_impl(v);
}
-/**
- * A version of #BM_mesh_normals_update that updates a subset of geometry,
- * used to avoid the overhead of updating everything.
- */
void BM_mesh_normals_update_with_partial_ex(BMesh *UNUSED(bm),
const BMPartialUpdate *bmpinfo,
const struct BMeshNormalsUpdate_Params *params)
@@ -343,12 +334,6 @@ void BM_mesh_normals_update_with_partial(BMesh *bm, const BMPartialUpdate *bmpin
/** \name Update Vertex & Face Normals (Custom Coords)
* \{ */
-/**
- * \brief BMesh Compute Normals from/to external data.
- *
- * Computes the vertex normals of a mesh into vnos,
- * using given vertex coordinates (vcos) and polygon normals (fnos).
- */
void BM_verts_calc_normal_vcos(BMesh *bm,
const float (*fnos)[3],
const float (*vcos)[3],
@@ -404,16 +389,13 @@ void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges)
*/
static void bm_mesh_edges_sharp_tag(BMesh *bm,
const float (*fnos)[3],
- const float split_angle,
+ float split_angle_cos,
const bool do_sharp_edges_tag)
{
BMIter eiter;
BMEdge *e;
int i;
- const bool check_angle = (split_angle < (float)M_PI);
- const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
-
if (fnos) {
BM_mesh_elem_index_ensure(bm, BM_FACE);
}
@@ -438,12 +420,6 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm,
bm->elem_index_dirty &= ~BM_EDGE;
}
-/**
- * Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
- *
- * Used when defining an empty custom loop normals data layer,
- * to keep same shading as with auto-smooth!
- */
void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
{
if (split_angle >= (float)M_PI) {
@@ -451,7 +427,7 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
return;
}
- bm_mesh_edges_sharp_tag(bm, NULL, split_angle, true);
+ bm_mesh_edges_sharp_tag(bm, NULL, cosf(split_angle), true);
}
/** \} */
@@ -460,11 +436,6 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
/** \name Loop Normals Calculation API
* \{ */
-/**
- * Check whether given loop is part of an unknown-so-far cyclic smooth fan, or not.
- * Needed because cyclic smooth fans have no obvious 'entry point',
- * and yet we need to walk them once, and only once.
- */
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
{
BMLoop *lfan_pivot_next = l_curr;
@@ -523,7 +494,8 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
float (*r_lnos)[3],
MLoopNorSpaceArray *r_lnors_spacearr)
{
- BLI_assert((bm->elem_index_dirty & (BM_FACE | BM_LOOP)) == 0);
+ BLI_assert((bm->elem_index_dirty & BM_LOOP) == 0);
+ BLI_assert((fnos == NULL) || ((bm->elem_index_dirty & BM_FACE) == 0));
BLI_assert((vcos == NULL) || ((bm->elem_index_dirty & BM_VERT) == 0));
UNUSED_VARS_NDEBUG(bm);
@@ -1110,11 +1082,13 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
const short (*clnors_data)[2],
const int cd_loop_clnors_offset,
const bool do_rebuild,
- const float split_angle)
+ const float split_angle_cos)
{
BMIter fiter;
BMFace *f_curr;
const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
+ /* When false the caller must have already tagged the edges. */
+ const bool do_edge_tag = (split_angle_cos != EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS);
MLoopNorSpaceArray _lnors_spacearr = {NULL};
@@ -1155,7 +1129,9 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
/* Always tag edges based on winding & sharp edge flag
* (even when the auto-smooth angle doesn't need to be calculated). */
- bm_mesh_edges_sharp_tag(bm, fnos, has_clnors ? (float)M_PI : split_angle, false);
+ if (do_edge_tag) {
+ bm_mesh_edges_sharp_tag(bm, fnos, has_clnors ? -1.0f : split_angle_cos, false);
+ }
/* We now know edges that can be smoothed (they are tagged),
* and edges that will be hard (they aren't).
@@ -1308,12 +1284,9 @@ static void bm_mesh_loops_calc_normals__multi_threaded(BMesh *bm,
const short (*clnors_data)[2],
const int cd_loop_clnors_offset,
const bool do_rebuild,
- const float split_angle)
+ const float split_angle_cos)
{
const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
- const bool check_angle = (split_angle < (float)M_PI);
- const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
-
MLoopNorSpaceArray _lnors_spacearr = {NULL};
{
@@ -1387,7 +1360,7 @@ static void bm_mesh_loops_calc_normals(BMesh *bm,
const short (*clnors_data)[2],
const int cd_loop_clnors_offset,
const bool do_rebuild,
- const float split_angle)
+ const float split_angle_cos)
{
if (bm->totloop < BM_OMP_LIMIT) {
bm_mesh_loops_calc_normals__single_threaded(bm,
@@ -1398,7 +1371,7 @@ static void bm_mesh_loops_calc_normals(BMesh *bm,
clnors_data,
cd_loop_clnors_offset,
do_rebuild,
- split_angle);
+ split_angle_cos);
}
else {
bm_mesh_loops_calc_normals__multi_threaded(bm,
@@ -1409,7 +1382,7 @@ static void bm_mesh_loops_calc_normals(BMesh *bm,
clnors_data,
cd_loop_clnors_offset,
do_rebuild,
- split_angle);
+ split_angle_cos);
}
}
@@ -1620,7 +1593,7 @@ static void bm_mesh_loops_custom_normals_set(BMesh *bm,
/* Tag smooth edges and set lnos from vnos when they might be completely smooth...
* When using custom loop normals, disable the angle feature! */
- bm_mesh_edges_sharp_tag(bm, fnos, (float)M_PI, false);
+ bm_mesh_edges_sharp_tag(bm, fnos, -1.0f, false);
/* Finish computing lnos by accumulating face normals
* in each fan of faces defined by sharp edges. */
@@ -1721,13 +1694,6 @@ static void bm_mesh_loops_calc_normals_no_autosmooth(BMesh *bm,
}
}
-/**
- * \brief BMesh Compute Loop Normals from/to external data.
- *
- * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
- * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
- * (splitting edges).
- */
void BM_loops_calc_normal_vcos(BMesh *bm,
const float (*vcos)[3],
const float (*vnos)[3],
@@ -1751,7 +1717,7 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
clnors_data,
cd_loop_clnors_offset,
do_rebuild,
- has_clnors ? (float)M_PI : split_angle);
+ has_clnors ? -1.0f : cosf(split_angle));
}
else {
BLI_assert(!r_lnors_spacearr);
@@ -1934,10 +1900,6 @@ void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor)
#endif
}
-/**
- * \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
- * take care to run this before setting up tags.
- */
void BM_lnorspace_update(BMesh *bm)
{
if (bm->lnor_spacearr == NULL) {
@@ -2251,10 +2213,6 @@ void BM_loop_normal_editdata_array_free(BMLoopNorEditDataArray *lnors_ed_arr)
/** \name Custom Normals / Vector Layer Conversion
* \{ */
-/**
- * \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
- * take care to run this before setting up tags.
- */
bool BM_custom_loop_normals_to_vector_layer(BMesh *bm)
{
BMFace *f;
@@ -2266,7 +2224,6 @@ bool BM_custom_loop_normals_to_vector_layer(BMesh *bm)
}
BM_lnorspace_update(bm);
- BM_mesh_elem_index_ensure(bm, BM_LOOP);
/* Create a loop normal layer. */
if (!CustomData_has_layer(&bm->ldata, CD_NORMAL)) {
@@ -2278,14 +2235,15 @@ bool BM_custom_loop_normals_to_vector_layer(BMesh *bm)
const int cd_custom_normal_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
const int cd_normal_offset = CustomData_get_offset(&bm->ldata, CD_NORMAL);
+ int l_index = 0;
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- const int l_index = BM_elem_index_get(l);
const short *clnors_data = BM_ELEM_CD_GET_VOID_P(l, cd_custom_normal_offset);
float *normal = BM_ELEM_CD_GET_VOID_P(l, cd_normal_offset);
BKE_lnor_space_custom_data_to_normal(
bm->lnor_spacearr->lspacearr[l_index], clnors_data, normal);
+ l_index += 1;
}
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.h b/source/blender/bmesh/intern/bmesh_mesh_normals.h
index ecd627d4bfe..d9b9a88b10d 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_normals.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_normals.h
@@ -30,45 +30,86 @@ struct BMeshNormalsUpdate_Params {
bool face_normals;
};
+/**
+ * \brief BMesh Compute Normals
+ *
+ * Updates the normals of a mesh.
+ */
void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *param);
void BM_mesh_normals_update(BMesh *bm);
+/**
+ * A version of #BM_mesh_normals_update that updates a subset of geometry,
+ * used to avoid the overhead of updating everything.
+ */
void BM_mesh_normals_update_with_partial_ex(BMesh *bm,
const struct BMPartialUpdate *bmpinfo,
const struct BMeshNormalsUpdate_Params *param);
void BM_mesh_normals_update_with_partial(BMesh *bm, const struct BMPartialUpdate *bmpinfo);
+/**
+ * \brief BMesh Compute Normals from/to external data.
+ *
+ * Computes the vertex normals of a mesh into vnos,
+ * using given vertex coordinates (vcos) and polygon normals (fnos).
+ */
void BM_verts_calc_normal_vcos(BMesh *bm,
const float (*fnos)[3],
const float (*vcos)[3],
float (*vnos)[3]);
+/**
+ * \brief BMesh Compute Loop Normals from/to external data.
+ *
+ * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
+ * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
+ * (splitting edges).
+ */
void BM_loops_calc_normal_vcos(BMesh *bm,
const float (*vcos)[3],
const float (*vnos)[3],
const float (*fnos)[3],
- const bool use_split_normals,
- const float split_angle,
+ bool use_split_normals,
+ float split_angle,
float (*r_lnos)[3],
struct MLoopNorSpaceArray *r_lnors_spacearr,
short (*clnors_data)[2],
- const int cd_loop_clnors_offset,
- const bool do_rebuild);
+ int cd_loop_clnors_offset,
+ bool do_rebuild);
+/**
+ * Check whether given loop is part of an unknown-so-far cyclic smooth fan, or not.
+ * Needed because cyclic smooth fans have no obvious 'entry point',
+ * and yet we need to walk them once, and only once.
+ */
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr);
void BM_lnorspacearr_store(BMesh *bm, float (*r_lnors)[3]);
-void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all);
+void BM_lnorspace_invalidate(BMesh *bm, bool do_invalidate_all);
void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor);
+/**
+ * \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
+ * take care to run this before setting up tags.
+ */
void BM_lnorspace_update(BMesh *bm);
-void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges);
+void BM_normals_loops_edges_tag(BMesh *bm, bool do_edges);
#ifndef NDEBUG
void BM_lnorspace_err(BMesh *bm);
#endif
/* Loop Generics */
struct BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm,
- const bool do_all_loops_of_vert);
+ bool do_all_loops_of_vert);
void BM_loop_normal_editdata_array_free(struct BMLoopNorEditDataArray *lnors_ed_arr);
+/**
+ * \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
+ * take care to run this before setting up tags.
+ */
bool BM_custom_loop_normals_to_vector_layer(struct BMesh *bm);
void BM_custom_loop_normals_from_vector_layer(struct BMesh *bm, bool add_sharp_edges);
-void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle);
+/**
+ * Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
+ *
+ * Used when defining an empty custom loop normals data layer,
+ * to keep same shading as with auto-smooth!
+ */
+void BM_edges_sharp_from_angle_set(BMesh *bm, float split_angle);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_partial_update.c b/source/blender/bmesh/intern/bmesh_mesh_partial_update.c
index 46fd2ad9a31..ad9b8414525 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_partial_update.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_partial_update.c
@@ -103,10 +103,6 @@ BLI_INLINE bool partial_elem_face_ensure(BMPartialUpdate *bmpinfo,
return false;
}
-/**
- * All Tagged & Connected, see: #BM_mesh_partial_create_from_verts
- * Operate on everything that's tagged as well as connected geometry.
- */
BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
const BMPartialUpdate_Params *params,
const BLI_bitmap *verts_mask,
@@ -216,11 +212,6 @@ BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
return bmpinfo;
}
-/**
- * All Connected, operate on all faces that have both tagged and un-tagged vertices.
- *
- * Reduces computations when transforming isolated regions.
- */
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_single(
BMesh *bm,
const BMPartialUpdate_Params *params,
@@ -314,25 +305,6 @@ BMPartialUpdate *BM_mesh_partial_create_from_verts_group_single(
return bmpinfo;
}
-/**
- * All Connected, operate on all faces that have vertices in the same group.
- *
- * Reduces computations when transforming isolated regions.
- *
- * This is a version of #BM_mesh_partial_create_from_verts_group_single
- * that handles multiple groups instead of a bitmap mask.
- *
- * This is needed for example when transform has mirror enabled,
- * since one side needs to have a different group to the other since a face that has vertices
- * attached to both won't have an affine transformation.
- *
- * \param verts_groups: Vertex aligned array of groups.
- * Values are used as follows:
- * - >0: Each face is grouped with other faces of the same group.
- * - 0: Not in a group (don't handle these).
- * - -1: Don't use grouping logic (include any face that contains a vertex with this group).
- * \param verts_groups_count: The number of non-zero values in `verts_groups`.
- */
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_multi(
BMesh *bm,
const BMPartialUpdate_Params *params,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_partial_update.h b/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
index cf4eab22836..a280acb4624 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
@@ -52,22 +52,48 @@ typedef struct BMPartialUpdate {
BMPartialUpdate_Params params;
} BMPartialUpdate;
+/**
+ * All Tagged & Connected, see: #BM_mesh_partial_create_from_verts
+ * Operate on everything that's tagged as well as connected geometry.
+ */
BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
const BMPartialUpdate_Params *params,
const unsigned int *verts_mask,
- const int verts_mask_count)
+ int verts_mask_count)
ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
+/**
+ * All Connected, operate on all faces that have both tagged and un-tagged vertices.
+ *
+ * Reduces computations when transforming isolated regions.
+ */
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_single(
BMesh *bm,
const BMPartialUpdate_Params *params,
const unsigned int *verts_mask,
- const int verts_mask_count) ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
+ int verts_mask_count) ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
+/**
+ * All Connected, operate on all faces that have vertices in the same group.
+ *
+ * Reduces computations when transforming isolated regions.
+ *
+ * This is a version of #BM_mesh_partial_create_from_verts_group_single
+ * that handles multiple groups instead of a bitmap mask.
+ *
+ * This is needed for example when transform has mirror enabled,
+ * since one side needs to have a different group to the other since a face that has vertices
+ * attached to both won't have an affine transformation.
+ *
+ * \param verts_group: Vertex aligned array of groups.
+ * Values are used as follows:
+ * - >0: Each face is grouped with other faces of the same group.
+ * - 0: Not in a group (don't handle these).
+ * - -1: Don't use grouping logic (include any face that contains a vertex with this group).
+ * \param verts_group_count: The number of non-zero values in `verts_groups`.
+ */
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_multi(
- BMesh *bm,
- const BMPartialUpdate_Params *params,
- const int *verts_group,
- const int verts_group_count) ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
+ BMesh *bm, const BMPartialUpdate_Params *params, const int *verts_group, int verts_group_count)
+ ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
void BM_mesh_partial_destroy(BMPartialUpdate *bmpinfo) ATTR_NONNULL(1);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_tessellate.c b/source/blender/bmesh/intern/bmesh_mesh_tessellate.c
index 9f477bc8a9c..94d8901edf8 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_tessellate.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_tessellate.c
@@ -549,9 +549,6 @@ static int bmesh_calc_tessellation_for_face_beauty(BMLoop *(*looptris)[3],
}
}
-/**
- * A version of #BM_mesh_calc_tessellation that avoids degenerate triangles.
- */
void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3])
{
#ifndef NDEBUG
diff --git a/source/blender/bmesh/intern/bmesh_mesh_tessellate.h b/source/blender/bmesh/intern/bmesh_mesh_tessellate.h
index 9a6a20d7568..91eac6bc6fc 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_tessellate.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_tessellate.h
@@ -35,6 +35,9 @@ void BM_mesh_calc_tessellation_ex(BMesh *bm,
const struct BMeshCalcTessellation_Params *params);
void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3]);
+/**
+ * A version of #BM_mesh_calc_tessellation that avoids degenerate triangles.
+ */
void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3]);
void BM_mesh_calc_tessellation_with_partial_ex(BMesh *bm,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.c b/source/blender/bmesh/intern/bmesh_mesh_validate.c
index f8830e1557b..3145ceceafd 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_validate.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_validate.c
@@ -50,12 +50,6 @@
(void)0
# endif
-/**
- * Check of this BMesh is valid,
- * this function can be slow since its intended to help with debugging.
- *
- * \return true when the mesh is valid.
- */
bool BM_mesh_validate(BMesh *bm)
{
EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, bm->totedge);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.h b/source/blender/bmesh/intern/bmesh_mesh_validate.h
index 2112e1f3200..203c8a89c55 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_validate.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_validate.h
@@ -23,4 +23,10 @@
* \ingroup bmesh
*/
+/**
+ * Check of this #BMesh is valid,
+ * this function can be slow since its intended to help with debugging.
+ *
+ * \return true when the mesh is valid.
+ */
bool BM_mesh_validate(BMesh *bm);
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index 5fa12397a07..0a3857a6e0a 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -31,31 +31,6 @@
#include "bmesh.h"
#include "intern/bmesh_private.h"
-/**
- * \brief Dissolve Vert
- *
- * Turns the face region surrounding a manifold vertex into a single polygon.
- *
- * \par Example:
- * <pre>
- * +---------+ +---------+
- * | \ / | | |
- * Before: | v | After: | |
- * | / \ | | |
- * +---------+ +---------+
- * </pre>
- *
- * This function can also collapse edges too
- * in cases when it can't merge into faces.
- *
- * \par Example:
- * <pre>
- * Before: +----v----+ After: +---------+
- * </pre>
- *
- * \note dissolves vert, in more situations than BM_disk_dissolve
- * (e.g. if the vert is part of a wire edge, etc).
- */
bool BM_vert_dissolve(BMesh *bm, BMVert *v)
{
/* logic for 3 or more is identical */
@@ -87,9 +62,6 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v)
return BM_disk_dissolve(bm, v);
}
-/**
- * dissolves all faces around a vert, and removes it.
- */
bool BM_disk_dissolve(BMesh *bm, BMVert *v)
{
BMEdge *e, *keepedge = NULL, *baseedge = NULL;
@@ -205,19 +177,6 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
return true;
}
-/**
- * \brief Faces Join Pair
- *
- * Joins two adjacent faces together.
- *
- * \note This method calls to #BM_faces_join to do its work.
- * This means connected edges which also share the two faces will be joined.
- *
- * If the windings do not match the winding of the new face will follow
- * \a l_a's winding (i.e. \a l_b will be reversed before the join).
- *
- * \return The combined face or NULL on failure.
- */
BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
{
BLI_assert((l_a != l_b) && (l_a->e == l_b->e));
@@ -231,24 +190,6 @@ BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_de
return BM_faces_join(bm, faces, 2, do_del);
}
-/**
- * \brief Face Split
- *
- * Split a face along two vertices. returns the newly made face, and sets
- * the \a r_l member to a loop in the newly created edge.
- *
- * \param bm: The bmesh
- * \param f: the original face
- * \param l_a, l_b: Loops of this face, their vertices define
- * the split edge to be created (must be differ and not can't be adjacent in the face).
- * \param r_l: pointer which will receive the BMLoop for the split edge in the new face
- * \param example: Edge used for attributes of splitting edge, if non-NULL
- * \param no_double: Use an existing edge if found
- *
- * \return Pointer to the newly created face representing one side of the split
- * if the split is successful (and the original face will be the other side).
- * NULL if the split fails.
- */
BMFace *BM_face_split(BMesh *bm,
BMFace *f,
BMLoop *l_a,
@@ -313,24 +254,6 @@ BMFace *BM_face_split(BMesh *bm,
return f_new;
}
-/**
- * \brief Face Split with intermediate points
- *
- * Like BM_face_split, but with an edge split by \a n intermediate points with given coordinates.
- *
- * \param bm: The bmesh.
- * \param f: the original face.
- * \param l_a, l_b: Vertices which define the split edge, must be different.
- * \param cos: Array of coordinates for intermediate points.
- * \param n: Length of \a cos (must be > 0).
- * \param r_l: pointer which will receive the BMLoop.
- * for the first split edge (from \a l_a) in the new face.
- * \param example: Edge used for attributes of splitting edge, if non-NULL.
- *
- * \return Pointer to the newly created face representing one side of the split
- * if the split is successful (and the original face will be the other side).
- * NULL if the split fails.
- */
BMFace *BM_face_split_n(BMesh *bm,
BMFace *f,
BMLoop *l_a,
@@ -404,29 +327,6 @@ BMFace *BM_face_split_n(BMesh *bm,
return f_new;
}
-/**
- * \brief Vert Collapse Faces
- *
- * Collapses vertex \a v_kill that has only two manifold edges
- * onto a vertex it shares an edge with.
- * \a fac defines the amount of interpolation for Custom Data.
- *
- * \note that this is not a general edge collapse function.
- *
- * \note this function is very close to #BM_vert_collapse_edge,
- * both collapse a vertex and return a new edge.
- * Except this takes a factor and merges custom data.
- *
- * \param bm: The bmesh
- * \param e_kill: The edge to collapse
- * \param v_kill: The vertex to collapse into the edge
- * \param fac: The factor along the edge
- * \param join_faces: When true the faces around the vertex will be joined
- * otherwise collapse the vertex by merging the 2 edges this vert touches into one.
- * \param kill_degenerate_faces: Removes faces with less than 3 verts after collapsing.
- *
- * \returns The New Edge
- */
BMEdge *BM_vert_collapse_faces(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -513,13 +413,6 @@ BMEdge *BM_vert_collapse_faces(BMesh *bm,
return e_new;
}
-/**
- * \brief Vert Collapse Faces
- *
- * Collapses a vertex onto another vertex it shares an edge with.
- *
- * \return The New Edge
- */
BMEdge *BM_vert_collapse_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -560,34 +453,12 @@ BMEdge *BM_vert_collapse_edge(BMesh *bm,
#undef DO_V_INTERP
-/**
- * Collapse and edge into a single vertex.
- */
BMVert *BM_edge_collapse(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces)
{
return bmesh_kernel_join_vert_kill_edge(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
}
-/**
- * \brief Edge Split
- *
- * <pre>
- * Before: v
- * +-----------------------------------+
- * e
- *
- * After: v v_new (returned)
- * +-----------------+-----------------+
- * r_e e
- * </pre>
- *
- * \param e: The edge to split.
- * \param v: One of the vertices in \a e and defines the "from" end of the splitting operation,
- * the new vertex will be \a fac of the way from \a v to the other end.
- * \param r_e: The newly created edge.
- * \return The new vertex.
- */
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
{
BMVert *v_new, *v_other;
@@ -703,11 +574,6 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
return v_new;
}
-/**
- * \brief Split an edge multiple times evenly
- *
- * \param r_varr: Optional array, verts in between (v1 -> v2)
- */
BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr)
{
int i;
@@ -725,11 +591,6 @@ BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr)
return v_new;
}
-/**
- * Swap v1 & v2
- *
- * \note Typically we shouldn't care about this, however it's used when extruding wire edges.
- */
void BM_edge_verts_swap(BMEdge *e)
{
SWAP(BMVert *, e->v1, e->v2);
@@ -785,20 +646,6 @@ bool BM_face_validate(BMFace *face, FILE *err)
}
#endif
-/**
- * Calculate the 2 loops which _would_ make up the newly rotated Edge
- * but don't actually change anything.
- *
- * Use this to further inspect if the loops to be connected have issues:
- *
- * Examples:
- * - the newly formed edge already exists
- * - the new face would be degenerate (zero area / concave / bow-tie)
- * - may want to measure if the new edge gives improved results topology.
- * over the old one, as with beauty fill.
- *
- * \note #BM_edge_rotate_check must have already run.
- */
void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2)
{
BMVert *v1, *v2;
@@ -825,12 +672,6 @@ void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2
*r_l2 = BM_face_other_vert_loop(fa, v1, v2);
}
-/**
- * \brief Check if Rotate Edge is OK
- *
- * Quick check to see if we could rotate the edge,
- * use this to avoid calling exceptions on common cases.
- */
bool BM_edge_rotate_check(BMEdge *e)
{
BMFace *fa, *fb;
@@ -860,17 +701,6 @@ bool BM_edge_rotate_check(BMEdge *e)
return false;
}
-/**
- * \brief Check if Edge Rotate Gives Degenerate Faces
- *
- * Check 2 cases
- * 1) does the newly forms edge form a flipped face (compare with previous cross product)
- * 2) does the newly formed edge cause a zero area corner (or close enough to be almost zero)
- *
- * \param e: The edge to test rotation.
- * \param l1, l2: are the loops of the proposed verts to rotate too and should
- * be the result of calling #BM_edge_calc_rotate
- */
bool BM_edge_rotate_check_degenerate(BMEdge *e, BMLoop *l1, BMLoop *l2)
{
/* NOTE: for these vars 'old' just means initial edge state. */
@@ -966,20 +796,6 @@ bool BM_edge_rotate_check_beauty(BMEdge *e, BMLoop *l1, BMLoop *l2)
return (len_squared_v3v3(e->v1->co, e->v2->co) > len_squared_v3v3(l1->v->co, l2->v->co));
}
-/**
- * \brief Rotate Edge
- *
- * Spins an edge topologically,
- * either counter-clockwise or clockwise depending on \a ccw.
- *
- * \return The spun edge, NULL on error
- * (e.g., if the edge isn't surrounded by exactly two faces).
- *
- * \note This works by dissolving the edge then re-creating it,
- * so the returned edge won't have the same pointer address as the original one.
- *
- * \see header definition for \a check_flag enum.
- */
BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag)
{
BMVert *v1, *v2;
@@ -1091,9 +907,6 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
return e_new;
}
-/**
- * \brief Rip a single face from a vertex fan
- */
BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *l_sep)
{
return bmesh_kernel_unglue_region_make_vert(bm, l_sep);
diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h
index 4328187b95e..4e8a8a14a6a 100644
--- a/source/blender/bmesh/intern/bmesh_mods.h
+++ b/source/blender/bmesh/intern/bmesh_mods.h
@@ -20,22 +20,94 @@
* \ingroup bmesh
*/
+/**
+ * \brief Dissolve Vert
+ *
+ * Turns the face region surrounding a manifold vertex into a single polygon.
+ *
+ * \par Example:
+ * <pre>
+ * +---------+ +---------+
+ * | \ / | | |
+ * Before: | v | After: | |
+ * | / \ | | |
+ * +---------+ +---------+
+ * </pre>
+ *
+ * This function can also collapse edges too
+ * in cases when it can't merge into faces.
+ *
+ * \par Example:
+ * <pre>
+ * Before: +----v----+ After: +---------+
+ * </pre>
+ *
+ * \note dissolves vert, in more situations than BM_disk_dissolve
+ * (e.g. if the vert is part of a wire edge, etc).
+ */
bool BM_vert_dissolve(BMesh *bm, BMVert *v);
+/**
+ * dissolves all faces around a vert, and removes it.
+ */
bool BM_disk_dissolve(BMesh *bm, BMVert *v);
-BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del);
+/**
+ * \brief Faces Join Pair
+ *
+ * Joins two adjacent faces together.
+ *
+ * \note This method calls to #BM_faces_join to do its work.
+ * This means connected edges which also share the two faces will be joined.
+ *
+ * If the windings do not match the winding of the new face will follow
+ * \a l_a's winding (i.e. \a l_b will be reversed before the join).
+ *
+ * \return The combined face or NULL on failure.
+ */
+BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, bool do_del);
/** see: bmesh_polygon_edgenet.h for #BM_face_split_edgenet */
-BMFace *BM_face_split(BMesh *bm,
- BMFace *f,
- BMLoop *l_a,
- BMLoop *l_b,
- BMLoop **r_l,
- BMEdge *example,
- const bool no_double);
+/**
+ * \brief Face Split
+ *
+ * Split a face along two vertices. returns the newly made face, and sets
+ * the \a r_l member to a loop in the newly created edge.
+ *
+ * \param bm: The bmesh
+ * \param f: the original face
+ * \param l_a, l_b: Loops of this face, their vertices define
+ * the split edge to be created (must be differ and not can't be adjacent in the face).
+ * \param r_l: pointer which will receive the BMLoop for the split edge in the new face
+ * \param example: Edge used for attributes of splitting edge, if non-NULL
+ * \param no_double: Use an existing edge if found
+ *
+ * \return Pointer to the newly created face representing one side of the split
+ * if the split is successful (and the original face will be the other side).
+ * NULL if the split fails.
+ */
+BMFace *BM_face_split(
+ BMesh *bm, BMFace *f, BMLoop *l_a, BMLoop *l_b, BMLoop **r_l, BMEdge *example, bool no_double);
+/**
+ * \brief Face Split with intermediate points
+ *
+ * Like BM_face_split, but with an edge split by \a n intermediate points with given coordinates.
+ *
+ * \param bm: The bmesh.
+ * \param f: the original face.
+ * \param l_a, l_b: Vertices which define the split edge, must be different.
+ * \param cos: Array of coordinates for intermediate points.
+ * \param n: Length of \a cos (must be > 0).
+ * \param r_l: pointer which will receive the BMLoop.
+ * for the first split edge (from \a l_a) in the new face.
+ * \param example: Edge used for attributes of splitting edge, if non-NULL.
+ *
+ * \return Pointer to the newly created face representing one side of the split
+ * if the split is successful (and the original face will be the other side).
+ * NULL if the split fails.
+ */
BMFace *BM_face_split_n(BMesh *bm,
BMFace *f,
BMLoop *l_a,
@@ -45,40 +117,144 @@ BMFace *BM_face_split_n(BMesh *bm,
BMLoop **r_l,
BMEdge *example);
+/**
+ * \brief Vert Collapse Faces
+ *
+ * Collapses vertex \a v_kill that has only two manifold edges
+ * onto a vertex it shares an edge with.
+ * \a fac defines the amount of interpolation for Custom Data.
+ *
+ * \note that this is not a general edge collapse function.
+ *
+ * \note this function is very close to #BM_vert_collapse_edge,
+ * both collapse a vertex and return a new edge.
+ * Except this takes a factor and merges custom data.
+ *
+ * \param bm: The bmesh
+ * \param e_kill: The edge to collapse
+ * \param v_kill: The vertex to collapse into the edge
+ * \param fac: The factor along the edge
+ * \param join_faces: When true the faces around the vertex will be joined
+ * otherwise collapse the vertex by merging the 2 edges this vert touches into one.
+ * \param kill_degenerate_faces: Removes faces with less than 3 verts after collapsing.
+ *
+ * \returns The New Edge
+ */
BMEdge *BM_vert_collapse_faces(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
float fac,
- const bool do_del,
- const bool join_faces,
- const bool kill_degenerate_faces,
- const bool kill_duplicate_faces);
+ bool do_del,
+ bool join_faces,
+ bool kill_degenerate_faces,
+ bool kill_duplicate_faces);
+/**
+ * \brief Vert Collapse Faces
+ *
+ * Collapses a vertex onto another vertex it shares an edge with.
+ *
+ * \return The New Edge
+ */
BMEdge *BM_vert_collapse_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
- const bool do_del,
- const bool kill_degenerate_faces,
- const bool kill_duplicate_faces);
+ bool do_del,
+ bool kill_degenerate_faces,
+ bool kill_duplicate_faces);
-BMVert *BM_edge_collapse(BMesh *bm,
- BMEdge *e_kill,
- BMVert *v_kill,
- const bool do_del,
- const bool kill_degenerate_faces);
+/**
+ * Collapse and edge into a single vertex.
+ */
+BMVert *BM_edge_collapse(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill, bool do_del, bool kill_degenerate_faces);
+/**
+ * \brief Edge Split
+ *
+ * <pre>
+ * Before: v
+ * +-----------------------------------+
+ * e
+ *
+ * After: v v_new (returned)
+ * +-----------------+-----------------+
+ * r_e e
+ * </pre>
+ *
+ * \param e: The edge to split.
+ * \param v: One of the vertices in \a e and defines the "from" end of the splitting operation,
+ * the new vertex will be \a fac of the way from \a v to the other end.
+ * \param r_e: The newly created edge.
+ * \return The new vertex.
+ */
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac);
+/**
+ * \brief Split an edge multiple times evenly
+ *
+ * \param r_varr: Optional array, verts in between (v1 -> v2)
+ */
BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr);
+/**
+ * Swap v1 & v2
+ *
+ * \note Typically we shouldn't care about this, however it's used when extruding wire edges.
+ */
void BM_edge_verts_swap(BMEdge *e);
bool BM_face_validate(BMFace *face, FILE *err);
-void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2);
+/**
+ * Calculate the 2 loops which _would_ make up the newly rotated Edge
+ * but don't actually change anything.
+ *
+ * Use this to further inspect if the loops to be connected have issues:
+ *
+ * Examples:
+ * - the newly formed edge already exists
+ * - the new face would be degenerate (zero area / concave / bow-tie)
+ * - may want to measure if the new edge gives improved results topology.
+ * over the old one, as with beauty fill.
+ *
+ * \note #BM_edge_rotate_check must have already run.
+ */
+void BM_edge_calc_rotate(BMEdge *e, bool ccw, BMLoop **r_l1, BMLoop **r_l2);
+/**
+ * \brief Check if Rotate Edge is OK
+ *
+ * Quick check to see if we could rotate the edge,
+ * use this to avoid calling exceptions on common cases.
+ */
bool BM_edge_rotate_check(BMEdge *e);
+/**
+ * \brief Check if Edge Rotate Gives Degenerate Faces
+ *
+ * Check 2 cases
+ * 1) does the newly forms edge form a flipped face (compare with previous cross product)
+ * 2) does the newly formed edge cause a zero area corner (or close enough to be almost zero)
+ *
+ * \param e: The edge to test rotation.
+ * \param l1, l2: are the loops of the proposed verts to rotate too and should
+ * be the result of calling #BM_edge_calc_rotate
+ */
bool BM_edge_rotate_check_degenerate(BMEdge *e, BMLoop *l1, BMLoop *l2);
bool BM_edge_rotate_check_beauty(BMEdge *e, BMLoop *l1, BMLoop *l2);
-BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag);
+/**
+ * \brief Rotate Edge
+ *
+ * Spins an edge topologically,
+ * either counter-clockwise or clockwise depending on \a ccw.
+ *
+ * \return The spun edge, NULL on error
+ * (e.g., if the edge isn't surrounded by exactly two faces).
+ *
+ * \note This works by dissolving the edge then re-creating it,
+ * so the returned edge won't have the same pointer address as the original one.
+ *
+ * \see header definition for \a check_flag enum.
+ */
+BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, bool ccw, short check_flag);
/** Flags for #BM_edge_rotate */
enum {
@@ -92,6 +268,9 @@ enum {
BM_EDGEROT_CHECK_BEAUTY = (1 << 3),
};
+/**
+ * \brief Rip a single face from a vertex fan
+ */
BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *l_sep);
BMVert *BM_face_loop_separate_multi_isolated(BMesh *bm, BMLoop *l_sep);
BMVert *BM_face_loop_separate_multi(BMesh *bm, BMLoop **larr, int larr_len);
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 7865c79323d..85ea27b0f4e 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1186,6 +1186,7 @@ static BMO_FlagSet bmo_enum_triangulate_quad_method[] = {
{MOD_TRIANGULATE_QUAD_FIXED, "FIXED"},
{MOD_TRIANGULATE_QUAD_ALTERNATE, "ALTERNATE"},
{MOD_TRIANGULATE_QUAD_SHORTEDGE, "SHORT_EDGE"},
+ {MOD_TRIANGULATE_QUAD_LONGEDGE, "LONG_EDGE"},
{0, NULL},
};
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index 0f9488bd091..ef3c2cf8f17 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -185,12 +185,12 @@ BLI_INLINE BMFlagLayer *BMO_elem_flag_from_header(BMHeader *ele_head)
_bmo_elem_flag_set(bm, _BMO_CAST_F(e)->oflags, oflag, val)
#define BMO_face_flag_toggle(bm, e, oflag) _bmo_elem_flag_toggle(bm, _BMO_CAST_F(e)->oflags, oflag)
-BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, const BMFlagLayer *oflags, const short oflag);
-BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, const BMFlagLayer *oflags, const short oflag);
-BLI_INLINE void _bmo_elem_flag_enable(BMesh *bm, BMFlagLayer *oflags, const short oflag);
-BLI_INLINE void _bmo_elem_flag_disable(BMesh *bm, BMFlagLayer *oflags, const short oflag);
-BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, const short oflag, int val);
-BLI_INLINE void _bmo_elem_flag_toggle(BMesh *bm, BMFlagLayer *oflags, const short oflag);
+BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, const BMFlagLayer *oflags, short oflag);
+BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, const BMFlagLayer *oflags, short oflag);
+BLI_INLINE void _bmo_elem_flag_enable(BMesh *bm, BMFlagLayer *oflags, short oflag);
+BLI_INLINE void _bmo_elem_flag_disable(BMesh *bm, BMFlagLayer *oflags, short oflag);
+BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, short oflag, int val);
+BLI_INLINE void _bmo_elem_flag_toggle(BMesh *bm, BMFlagLayer *oflags, short oflag);
/* slot type arrays are terminated by the last member
* having a slot type of 0 */
@@ -341,50 +341,161 @@ typedef struct BMOpDefine {
BMOpTypeFlag type_flag;
} BMOpDefine;
-/*------------- Operator API --------------*/
-
-/* data types that use pointers (arrays, etc) should never
- * have it set directly. and never use BMO_slot_ptr_set to
- * pass in a list of edges or any arrays, really. */
+/* -------------------------------------------------------------------- */
+/** \name BMesh Operator API
+ *
+ * \note data types that use pointers (arrays, etc) must _never_ have it set directly.
+ * Don't #BMO_slot_ptr_set to pass in a list of edges or any arrays.
+ * \{ */
-void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname);
+/**
+ * \brief BMESH OPSTACK INIT OP
+ *
+ * Initializes an operator structure to a certain type
+ */
+void BMO_op_init(BMesh *bm, BMOperator *op, int flag, const char *opname);
-/* executes an operator, pushing and popping a new tool flag
- * layer as appropriate. */
+/**
+ * \brief BMESH OPSTACK EXEC OP
+ *
+ * Executes a passed in operator.
+ *
+ * This handles the allocation and freeing of temporary tool flag
+ * layers and starting/stopping the modeling loop.
+ * Can be called from other operators exec callbacks as well.
+ */
void BMO_op_exec(BMesh *bm, BMOperator *op);
-/* finishes an operator (though note the operator's tool flag is removed
- * after it finishes executing in BMO_op_exec). */
+/**
+ * \brief BMESH OPSTACK FINISH OP
+ *
+ * Does housekeeping chores related to finishing up an operator.
+ *
+ * \note the operator's tool flag is removed after it finishes executing in #BMO_op_exec.
+ */
void BMO_op_finish(BMesh *bm, BMOperator *op);
-/* count the number of elements with the specified flag enabled.
- * type can be a bitmask of BM_FACE, BM_EDGE, or BM_FACE. */
-int BMO_mesh_enabled_flag_count(BMesh *bm, const char htype, const short oflag);
+/**
+ * Count the number of elements with the specified flag enabled.
+ * type can be a bit-mask of #BM_FACE, #BM_EDGE, or #BM_FACE.
+ */
+int BMO_mesh_enabled_flag_count(BMesh *bm, char htype, short oflag);
-/* count the number of elements with the specified flag disabled.
- * type can be a bitmask of BM_FACE, BM_EDGE, or BM_FACE. */
-int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag);
+/**
+ * Count the number of elements with the specified flag disabled.
+ * type can be a bit-mask of #BM_FACE, #BM_EDGE, or #BM_FACE.
+ */
+int BMO_mesh_disabled_flag_count(BMesh *bm, char htype, short oflag);
-/*---------formatted operator initialization/execution-----------*/
+/**
+ * \brief BMESH OPSTACK PUSH
+ *
+ * Pushes the operator-stack down one level and allocates a new flag layer if appropriate.
+ */
void BMO_push(BMesh *bm, BMOperator *op);
+/**
+ * \brief BMESH OPSTACK POP
+ *
+ * Pops the operator-stack one level and frees a flag layer if appropriate
+ *
+ * BMESH_TODO: investigate NOT freeing flag layers.
+ */
void BMO_pop(BMesh *bm);
-/* Executes an operator. */
-bool BMO_op_callf(BMesh *bm, const int flag, const char *fmt, ...);
+/** \} */
-/* initializes, but doesn't execute an operator. this is so you can
+/* -------------------------------------------------------------------- */
+/** \name Formatted Operator Initialization/Execution
+ *
+ * Format Strings for #BMOperator Initialization.
+ *
+ * This system is used to execute or initialize an operator,
+ * using a formatted-string system.
+ *
+ * The basic format for the format string is:
+ * `[operatorname] [slot_name]=%[code] [slot_name]=%[code]`
+ *
+ * Example:
+ *
+ * \code{.c}
+ * BMO_op_callf(bm, BMO_FLAG_DEFAULTS,
+ * "delete context=%i geom=%hv",
+ * DEL_ONLYFACES, BM_ELEM_SELECT);
+ * \endcode
+ * **Primitive Types**
+ * - `b` - boolean (same as int but 1/0 only). #BMO_OP_SLOT_BOOL
+ * - `i` - int. #BMO_OP_SLOT_INT
+ * - `f` - float. #BMO_OP_SLOT_FLT
+ * - `p` - pointer (normally to a Scene/Mesh/Object/BMesh). #BMO_OP_SLOT_PTR
+ * - `m3` - 3x3 matrix of floats. #BMO_OP_SLOT_MAT
+ * - `m4` - 4x4 matrix of floats. #BMO_OP_SLOT_MAT
+ * - `v` - 3D vector of floats. #BMO_OP_SLOT_VEC
+ * **Utility**
+ *
+ * Pass an existing slot which is copied to either an input or output slot.
+ * Taking the operator and slot-name pair of args (BMOperator *, const char *).
+ * - `s` - slot_in (lower case)
+ * - `S` - slot_out (upper case)
+ * **Element Buffer** (#BMO_OP_SLOT_ELEMENT_BUF)
+ * - `e` - single element vert/edge/face (use with #BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE).
+ * - `eb` - elem buffer, take an array and a length.
+ * - `av` - all verts
+ * - `ae` - all edges
+ * - `af` - all faces
+ * - `hv` - header flagged verts (hflag)
+ * - `he` - header flagged edges (hflag)
+ * - `hf` - header flagged faces (hflag)
+ * - `Hv` - header flagged verts (hflag off)
+ * - `He` - header flagged edges (hflag off)
+ * - `Hf` - header flagged faces (hflag off)
+ * - `fv` - flagged verts (oflag)
+ * - `fe` - flagged edges (oflag)
+ * - `ff` - flagged faces (oflag)
+ * - `Fv` - flagged verts (oflag off)
+ * - `Fe` - flagged edges (oflag off)
+ * - `Ff` - flagged faces (oflag off)
+ *
+ * \note The common v/e/f suffix can be mixed,
+ * so `avef` is can be used for all verts, edges and faces.
+ * Order is not important so `Hfev` is also valid (all un-flagged verts, edges and faces).
+ *
+ * \{ */
+
+/** Executes an operator. */
+bool BMO_op_callf(BMesh *bm, int flag, const char *fmt, ...);
+
+/**
+ * Initializes, but doesn't execute an operator. this is so you can
* gain access to the outputs of the operator. note that you have
- * to execute/finish (BMO_op_exec and BMO_op_finish) yourself. */
-bool BMO_op_initf(BMesh *bm, BMOperator *op, const int flag, const char *fmt, ...);
+ * to execute/finish (BMO_op_exec and BMO_op_finish) yourself.
+ */
+bool BMO_op_initf(BMesh *bm, BMOperator *op, int flag, const char *fmt, ...);
+
+/**
+ * A `va_list` version, used to implement the above two functions,
+ * plus #EDBM_op_callf in editmesh_utils.c.
+ */
+bool BMO_op_vinitf(BMesh *bm, BMOperator *op, int flag, const char *fmt, va_list vlist);
+
+/** \} */
-/* va_list version, used to implement the above two functions,
- * plus EDBM_op_callf in editmesh_utils.c. */
-bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *fmt, va_list vlist);
+/* -------------------------------------------------------------------- */
+/** \name BMesh Operator Slot Access
+ * \{ */
-/* test whether a named slot exists */
+/**
+ * \brief BMESH OPSTACK HAS SLOT
+ *
+ * \return Success if the slot if found.
+ */
bool BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier);
/* get a pointer to a slot. this may be removed layer on from the public API. */
+/**
+ * \brief BMESH OPSTACK GET SLOT
+ *
+ * Returns a pointer to the slot of type 'slot_code'
+ */
BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier);
/* copies the data of a slot from one operator to another. src and dst are the
@@ -393,12 +504,20 @@ BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identif
_bmo_slot_copy( \
(op_src)->slots_src, slot_name_src, (op_dst)->slots_dst, slot_name_dst, (op_dst)->arena)
+/**
+ * \brief BMESH OPSTACK COPY SLOT
+ *
+ * define used.
+ * Copies data from one slot to another.
+ */
void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
const char *slot_name_src,
BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],
const char *slot_name_dst,
struct MemArena *arena_dst);
+/** \} */
+
/* del "context" slot values, used for operator too */
enum {
DEL_VERTS = 1,
@@ -430,24 +549,30 @@ typedef enum {
BMO_DELIM_UV = 1 << 4,
} BMO_Delimit;
-void BMO_op_flag_enable(BMesh *bm, BMOperator *op, const int op_flag);
-void BMO_op_flag_disable(BMesh *bm, BMOperator *op, const int op_flag);
+void BMO_op_flag_enable(BMesh *bm, BMOperator *op, int op_flag);
+void BMO_op_flag_disable(BMesh *bm, BMOperator *op, int op_flag);
-void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
- const char *slot_name,
- const float f);
+/* -------------------------------------------------------------------- */
+/** \name BMesh Operator Slot Get/Set
+ * \{ */
+
+void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float f);
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
-void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int i);
+void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int i);
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
-void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const bool i);
+void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, bool i);
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
+/**
+ * Return a copy of the element buffer.
+ */
void *BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int *len);
-/* don't pass in arrays that are supposed to map to elements this way.
+/**
+ * Don't pass in arrays that are supposed to map to elements this way.
*
* so, e.g. passing in list of floats per element in another slot is bad.
- * passing in, e.g. pointer to an editmesh for the conversion operator is fine
- * though. */
+ * passing in, e.g. pointer to an edit-mesh for the conversion operator is fine though.
+ */
void BMO_slot_ptr_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, void *p);
void *BMO_slot_ptr_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -455,10 +580,12 @@ void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const float vec[3]);
void BMO_slot_vec_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_vec[3]);
-/* only supports square mats */
-/* size must be 3 or 4; this api is meant only for transformation matrices.
- * note that internally the matrix is stored in 4x4 form, and it's safe to
- * call whichever BMO_Get_MatXXX function you want. */
+/**
+ * Only supports square matrices.
+ * size must be 3 or 4; this api is meant only for transformation matrices.
+ *
+ * \note the matrix is stored in 4x4 form, and it's safe to call whichever function you want.
+ */
void BMO_slot_mat_set(BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -471,90 +598,118 @@ void BMO_slot_mat3_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
float r_mat[3][3]);
-void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *op, const char htype, const short oflag);
+/** \} */
+
+void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *op, char htype, short oflag);
void BMO_mesh_selected_remap(BMesh *bm,
BMOpSlot *slot_vert_map,
BMOpSlot *slot_edge_map,
BMOpSlot *slot_face_map,
- const bool check_select);
+ bool check_select);
-/* copies the values from another slot to the end of the output slot */
+/**
+ * Copies the values from another slot to the end of the output slot.
+ */
#define BMO_slot_buffer_append( \
op_src, slots_src, slot_name_src, op_dst, slots_dst, slot_name_dst) \
_bmo_slot_buffer_append( \
(op_src)->slots_src, slot_name_src, (op_dst)->slots_dst, slot_name_dst, (op_dst)->arena)
+/**
+ * Copies the values from another slot to the end of the output slot.
+ */
void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],
const char *slot_name_dst,
BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
const char *slot_name_src,
struct MemArena *arena_dst);
-/* puts every element of type 'type' (which is a bitmask) with tool
- * flag 'flag', into a slot. */
+/**
+ * Puts every element of type 'type' (which is a bit-mask) with tool flag 'flag', into a slot.
+ */
void BMO_slot_buffer_from_enabled_flag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype,
- const short oflag);
+ char htype,
+ short oflag);
-/* puts every element of type 'type' (which is a bitmask) without tool
- * flag 'flag', into a slot. */
+/**
+ * Puts every element of type 'type' (which is a bit-mask) without tool flag 'flag', into a slot.
+ */
void BMO_slot_buffer_from_disabled_flag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype,
- const short oflag);
+ char htype,
+ short oflag);
-/* tool-flags all elements inside an element slot array with flag flag. */
+/**
+ * \brief BMO_FLAG_BUFFER
+ *
+ * Flags elements in a slots buffer
+ */
void BMO_slot_buffer_flag_enable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype,
- const short oflag);
-/* clears tool-flag flag from all elements inside a slot array. */
+ char htype,
+ short oflag);
+/**
+ * \brief BMO_FLAG_BUFFER
+ *
+ * Removes flags from elements in a slots buffer
+ */
void BMO_slot_buffer_flag_disable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype,
- const short oflag);
+ char htype,
+ short oflag);
-/* tool-flags all elements inside an element slot array with flag flag. */
+/**
+ * \brief BMO_FLAG_BUFFER
+ *
+ * Header Flags elements in a slots buffer, automatically
+ * using the selection API where appropriate.
+ */
void BMO_slot_buffer_hflag_enable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype,
- const char hflag,
- const bool do_flush);
-/* clears tool-flag flag from all elements inside a slot array. */
+ char htype,
+ char hflag,
+ bool do_flush);
+/**
+ * \brief BMO_FLAG_BUFFER
+ *
+ * Removes flags from elements in a slots buffer, automatically
+ * using the selection API where appropriate.
+ */
void BMO_slot_buffer_hflag_disable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype,
- const char hflag,
- const bool do_flush);
+ char htype,
+ char hflag,
+ bool do_flush);
-/* puts every element of type 'type' (which is a bitmask) with header
- * flag 'flag', into a slot. NOTE: ignores hidden elements
- * (e.g. elements with header flag BM_ELEM_HIDDEN set). */
+/**
+ * Puts every element of type 'type' (which is a bit-mask) with header flag 'flag', into a slot.
+ * \note ignores hidden elements (e.g. elements with header flag BM_ELEM_HIDDEN set).
+ */
void BMO_slot_buffer_from_enabled_hflag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype,
- const char hflag);
-
-/* puts every element of type 'type' (which is a bitmask) without
- * header flag 'flag', into a slot. NOTE: ignores hidden elements
- * (e.g. elements with header flag BM_ELEM_HIDDEN set). */
+ char htype,
+ char hflag);
+/**
+ * Puts every element of type 'type' (which is a bit-mask) without header flag 'flag', into a slot.
+ * \note ignores hidden elements (e.g. elements with header flag BM_ELEM_HIDDEN set).
+ */
void BMO_slot_buffer_from_disabled_hflag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype,
- const char hflag);
+ char htype,
+ char hflag);
void BMO_slot_buffer_from_array(BMOperator *op,
BMOpSlot *slot,
@@ -564,30 +719,42 @@ void BMO_slot_buffer_from_array(BMOperator *op,
void BMO_slot_buffer_from_single(BMOperator *op, BMOpSlot *slot, BMHeader *ele);
void *BMO_slot_buffer_get_single(BMOpSlot *slot);
-/* counts number of elements inside a slot array. */
+/** Return the number of elements inside a slot array. */
int BMO_slot_buffer_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
+/** Return the number of elements inside a slot map. */
int BMO_slot_map_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
+/**
+ * Inserts a key/value mapping into a mapping slot. note that it copies the
+ * value, it doesn't store a reference to it.
+ */
void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot, const void *element, const void *data);
-/* flags all elements in a mapping. note that the mapping must only have
- * bmesh elements in it. */
+/**
+ * Flags all elements in a mapping.
+ * \note that the mapping must only have #BMesh elements in it.
+ */
void BMO_slot_map_to_flag(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype,
- const short oflag);
+ char htype,
+ short oflag);
void *BMO_slot_buffer_alloc(BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const int len);
+ int len);
+/**
+ * \brief BMO_ALL_TO_SLOT
+ *
+ * Copies all elements of a certain type into an operator slot.
+ */
void BMO_slot_buffer_from_all(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype);
+ char htype);
/**
* This part of the API is used to iterate over element buffer or
@@ -631,17 +798,28 @@ typedef struct BMOIter {
int cur; // for arrays
GHashIterator giter;
void **val;
- char restrictmask; /* bitwise '&' with BMHeader.htype */
+ /** Bit-wise '&' with #BMHeader.htype */
+ char restrictmask;
} BMOIter;
void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
+/**
+ * \brief New Iterator
+ *
+ * \param restrictmask: restricts the iteration to certain element types
+ * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
+ * over an element buffer (not a mapping). */
void *BMO_iter_new(BMOIter *iter,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char restrictmask);
+ char restrictmask);
void *BMO_iter_step(BMOIter *iter);
+/**
+ * Returns a pointer to the key-value when iterating over mappings.
+ * remember for pointer maps this will be a pointer to a pointer.
+ */
void **BMO_iter_map_value_p(BMOIter *iter);
void *BMO_iter_map_value_ptr(BMOIter *iter);
@@ -660,6 +838,7 @@ bool BMO_iter_map_value_bool(BMOIter *iter);
ele; \
BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMO_iter_step(iter), i_++)
+/* operator slot type information - size of one element of the type given. */
extern const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES];
int BMO_opcode_from_opname(const char *opname);
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
index cf7697ad35f..dd35f0feee7 100644
--- a/source/blender/bmesh/intern/bmesh_operators.c
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -42,7 +42,6 @@ static int bmo_name_to_slotcode(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char
static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *identifier);
-/* operator slot type information - size of one element of the type given. */
const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES] = {
0, /* 0: BMO_OP_SLOT_SENTINEL */
sizeof(int), /* 1: BMO_OP_SLOT_BOOL */
@@ -70,11 +69,6 @@ void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
op->flag &= ~op_flag;
}
-/**
- * \brief BMESH OPSTACK PUSH
- *
- * Pushes the opstack down one level and allocates a new flag layer if appropriate.
- */
void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
{
bm->toolflag_index++;
@@ -90,13 +84,6 @@ void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
}
}
-/**
- * \brief BMESH OPSTACK POP
- *
- * Pops the opstack one level and frees a flag layer if appropriate
- *
- * BMESH_TODO: investigate NOT freeing flag layers.
- */
void BMO_pop(BMesh *bm)
{
if (bm->toolflag_index > 0) {
@@ -152,11 +139,6 @@ static void bmo_op_slots_free(const BMOSlotType *slot_types, BMOpSlot *slot_args
}
}
-/**
- * \brief BMESH OPSTACK INIT OP
- *
- * Initializes an operator structure to a certain type
- */
void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname)
{
int opcode = BMO_opcode_from_opname(opname);
@@ -188,15 +170,6 @@ void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname)
BLI_memarena_use_calloc(op->arena);
}
-/**
- * \brief BMESH OPSTACK EXEC OP
- *
- * Executes a passed in operator.
- *
- * This handles the allocation and freeing of temporary flag
- * layers and starting/stopping the modeling loop.
- * Can be called from other operators exec callbacks as well.
- */
void BMO_op_exec(BMesh *bm, BMOperator *op)
{
/* allocate tool flags on demand */
@@ -216,11 +189,6 @@ void BMO_op_exec(BMesh *bm, BMOperator *op)
BMO_pop(bm);
}
-/**
- * \brief BMESH OPSTACK FINISH OP
- *
- * Does housekeeping chores related to finishing up an operator.
- */
void BMO_op_finish(BMesh *bm, BMOperator *op)
{
bmo_op_slots_free(bmo_opdefines[op->type]->slot_types_in, op->slots_in);
@@ -238,22 +206,12 @@ void BMO_op_finish(BMesh *bm, BMOperator *op)
#endif
}
-/**
- * \brief BMESH OPSTACK HAS SLOT
- *
- * \return Success if the slot if found.
- */
bool BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
{
int slot_code = bmo_name_to_slotcode(slot_args, identifier);
return (slot_code >= 0);
}
-/**
- * \brief BMESH OPSTACK GET SLOT
- *
- * Returns a pointer to the slot of type 'slot_code'
- */
BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
{
int slot_code = bmo_name_to_slotcode_check(slot_args, identifier);
@@ -267,12 +225,6 @@ BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identif
return &slot_args[slot_code];
}
-/**
- * \brief BMESH OPSTACK COPY SLOT
- *
- * define used.
- * Copies data from one slot to another.
- */
void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
const char *slot_name_src,
BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],
@@ -393,7 +345,6 @@ void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
slot->data.i = i;
}
-/* only supports square mats */
void BMO_slot_mat_set(BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -515,7 +466,6 @@ bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
return slot->data.i;
}
-/* if you want a copy of the elem buffer */
void *BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int *len)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
@@ -698,9 +648,6 @@ int BMO_slot_map_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name
return BLI_ghash_len(slot->data.ghash);
}
-/* inserts a key/value mapping into a mapping slot. note that it copies the
- * value, it doesn't store a reference to it. */
-
void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot, const void *element, const void *data)
{
(void)op; /* Ignored in release builds. */
@@ -796,11 +743,6 @@ void *BMO_slot_buffer_alloc(BMOperator *op,
return slot->data.buf;
}
-/**
- * \brief BMO_ALL_TO_SLOT
- *
- * Copies all elements of a certain type into an operator slot.
- */
void BMO_slot_buffer_from_all(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -987,9 +929,6 @@ void *BMO_slot_buffer_get_single(BMOpSlot *slot)
return slot->len ? (BMHeader *)slot->data.buf[0] : NULL;
}
-/**
- * Copies the values from another slot to the end of the output slot.
- */
void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],
const char *slot_name_dst,
BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
@@ -1115,12 +1054,6 @@ void BMO_slot_buffer_from_disabled_flag(BMesh *bm,
bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, false);
}
-/**
- * \brief BMO_FLAG_BUFFER
- *
- * Header Flags elements in a slots buffer, automatically
- * using the selection API where appropriate.
- */
void BMO_slot_buffer_hflag_enable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1155,12 +1088,6 @@ void BMO_slot_buffer_hflag_enable(BMesh *bm,
}
}
-/**
- * \brief BMO_FLAG_BUFFER
- *
- * Removes flags from elements in a slots buffer, automatically
- * using the selection API where appropriate.
- */
void BMO_slot_buffer_hflag_disable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1194,11 +1121,6 @@ void BMO_slot_buffer_hflag_disable(BMesh *bm,
}
}
-/**
- * \brief BMO_FLAG_BUFFER
- *
- * Flags elements in a slots buffer
- */
void BMO_slot_buffer_flag_enable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1221,11 +1143,6 @@ void BMO_slot_buffer_flag_enable(BMesh *bm,
}
}
-/**
- * \brief BMO_FLAG_BUFFER
- *
- * Removes flags from elements in a slots buffer
- */
void BMO_slot_buffer_flag_disable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1434,12 +1351,6 @@ void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char
return slot->data.buf ? *slot->data.buf : NULL;
}
-/**
- * \brief New Iterator
- *
- * \param restrictmask: restricts the iteration to certain element types
- * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
- * over an element buffer (not a mapping). */
void *BMO_iter_new(BMOIter *iter,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1513,10 +1424,6 @@ void *BMO_iter_step(BMOIter *iter)
/* used for iterating over mappings */
-/**
- * Returns a pointer to the key-value when iterating over mappings.
- * remember for pointer maps this will be a pointer to a pointer.
- */
void **BMO_iter_map_value_p(BMOIter *iter)
{
return iter->val;
@@ -1584,7 +1491,6 @@ bool BMO_error_occurred_at_level(BMesh *bm, eBMOpErrorLevel level)
return false;
}
-/* returns error code or 0 if no error */
bool BMO_error_get(BMesh *bm, const char **r_msg, BMOperator **r_op, eBMOpErrorLevel *r_level)
{
BMOpError *err = bm->errorstack.first;
@@ -1694,60 +1600,6 @@ static int BMO_opcode_from_opname_check(const char *opname)
return i;
}
-/**
- * \brief Format Strings for #BMOperator Initialization.
- *
- * This system is used to execute or initialize an operator,
- * using a formatted-string system.
- *
- * The basic format for the format string is:
- * `[operatorname] [slot_name]=%[code] [slot_name]=%[code]`
- *
- * Example:
- *
- * \code{.c}
- * BMO_op_callf(bm, BMO_FLAG_DEFAULTS,
- * "delete context=%i geom=%hv",
- * DEL_ONLYFACES, BM_ELEM_SELECT);
- * \endcode
- * **Primitive Types**
- * - `b` - boolean (same as int but 1/0 only). #BMO_OP_SLOT_BOOL
- * - `i` - int. #BMO_OP_SLOT_INT
- * - `f` - float. #BMO_OP_SLOT_FLT
- * - `p` - pointer (normally to a Scene/Mesh/Object/BMesh). #BMO_OP_SLOT_PTR
- * - `m3` - 3x3 matrix of floats. #BMO_OP_SLOT_MAT
- * - `m4` - 4x4 matrix of floats. #BMO_OP_SLOT_MAT
- * - `v` - 3D vector of floats. #BMO_OP_SLOT_VEC
- * **Utility**
- *
- * Pass an existing slot which is copied to either an input or output slot.
- * Taking the operator and slot-name pair of args (BMOperator *, const char *).
- * - `s` - slot_in (lower case)
- * - `S` - slot_out (upper case)
- * **Element Buffer** (#BMO_OP_SLOT_ELEMENT_BUF)
- * - `e` - single element vert/edge/face (use with #BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE).
- * - `eb` - elem buffer, take an array and a length.
- * - `av` - all verts
- * - `ae` - all edges
- * - `af` - all faces
- * - `hv` - header flagged verts (hflag)
- * - `he` - header flagged edges (hflag)
- * - `hf` - header flagged faces (hflag)
- * - `Hv` - header flagged verts (hflag off)
- * - `He` - header flagged edges (hflag off)
- * - `Hf` - header flagged faces (hflag off)
- * - `fv` - flagged verts (oflag)
- * - `fe` - flagged edges (oflag)
- * - `ff` - flagged faces (oflag)
- * - `Fv` - flagged verts (oflag off)
- * - `Fe` - flagged edges (oflag off)
- * - `Ff` - flagged faces (oflag off)
- *
- * \note The common v/e/f suffix can be mixed,
- * so `avef` is can be used for all verts, edges and faces.
- * Order is not important so `Hfev` is also valid (all un-flagged verts, edges and faces).
- */
-
bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, va_list vlist)
{
// BMOpDefine *def;
@@ -1796,11 +1648,11 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt,
while (*fmt) {
if (state) {
- /* jump past leading whitespace */
+ /* Jump past leading white-space. */
i = strspn(fmt, " ");
fmt += i;
- /* ignore trailing whitespace */
+ /* Ignore trailing white-space. */
if (!fmt[i]) {
break;
}
diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h
index a701fe3eb85..e5ede75f737 100644
--- a/source/blender/bmesh/intern/bmesh_operators.h
+++ b/source/blender/bmesh/intern/bmesh_operators.h
@@ -156,39 +156,75 @@ extern const int bmo_opdefines_total;
/*------specific operator helper functions-------*/
void BM_mesh_esubdivide(BMesh *bm,
- const char edge_hflag,
- const float smooth,
- const short smooth_falloff,
- const bool use_smooth_even,
- const float fractal,
- const float along_normal,
- const int numcuts,
- const int seltype,
- const int cornertype,
- const short use_single_edge,
- const short use_grid_fill,
- const short use_only_quads,
- const int seed);
-
-void BM_mesh_calc_uvs_grid(BMesh *bm,
- const uint x_segments,
- const uint y_segments,
- const short oflag,
- const int cd_loop_uv_offset);
-void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag, const int cd_loop_uv_offset);
-void BM_mesh_calc_uvs_circle(BMesh *bm,
- float mat[4][4],
- const float radius,
- const short oflag,
- const int cd_loop_uv_offset);
+ char edge_hflag,
+ float smooth,
+ short smooth_falloff,
+ bool use_smooth_even,
+ float fractal,
+ float along_normal,
+ int numcuts,
+ int seltype,
+ int cornertype,
+ short use_single_edge,
+ short use_grid_fill,
+ short use_only_quads,
+ int seed);
+
+/**
+ * Fills first available UV-map with grid-like UV's for all faces with `oflag` set.
+ *
+ * \param bm: The BMesh to operate on
+ * \param x_segments: The x-resolution of the grid
+ * \param y_segments: The y-resolution of the grid
+ * \param oflag: The flag to check faces with.
+ */
+void BM_mesh_calc_uvs_grid(
+ BMesh *bm, uint x_segments, uint y_segments, short oflag, int cd_loop_uv_offset);
+/**
+ * Fills first available UV-map with spherical projected UVs for all faces with `oflag` set.
+ *
+ * \param bm: The BMesh to operate on
+ * \param oflag: The flag to check faces with.
+ */
+void BM_mesh_calc_uvs_sphere(BMesh *bm, short oflag, int cd_loop_uv_offset);
+/**
+ * Fills first available UV-map with 2D projected UVs for all faces with `oflag` set.
+ *
+ * \param bm: The BMesh to operate on.
+ * \param mat: The transform matrix applied to the created circle.
+ * \param radius: The size of the circle.
+ * \param oflag: The flag to check faces with.
+ */
+void BM_mesh_calc_uvs_circle(
+ BMesh *bm, float mat[4][4], float radius, short oflag, int cd_loop_uv_offset);
+/**
+ * Fills first available UV-map with cylinder/cone-like UVs for all faces with `oflag` set.
+ *
+ * \param bm: The BMesh to operate on.
+ * \param mat: The transform matrix applied to the created cone/cylinder.
+ * \param radius_top: The size of the top end of the cone/cylinder.
+ * \param radius_bottom: The size of the bottom end of the cone/cylinder.
+ * \param segments: The number of subdivisions in the sides of the cone/cylinder.
+ * \param cap_ends: Whether the ends of the cone/cylinder are filled or not.
+ * \param oflag: The flag to check faces with.
+ */
void BM_mesh_calc_uvs_cone(BMesh *bm,
float mat[4][4],
- const float radius_top,
- const float radius_bottom,
- const int segments,
- const bool cap_ends,
- const short oflag,
- const int cd_loop_uv_offset);
-void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag);
+ float radius_top,
+ float radius_bottom,
+ int segments,
+ bool cap_ends,
+ short oflag,
+ int cd_loop_uv_offset);
+/**
+ * Fills first available UV-map with cube-like UVs for all faces with `oflag` set.
+ *
+ * \note Expects tagged faces to be six quads.
+ * \note Caller must order faces for correct alignment.
+ *
+ * \param bm: The BMesh to operate on.
+ * \param oflag: The flag to check faces with.
+ */
+void BM_mesh_calc_uvs_cube(BMesh *bm, short oflag);
#include "intern/bmesh_operator_api_inline.h"
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 51ae47adacc..e7280303c26 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -117,15 +117,6 @@ static void bm_face_calc_poly_center_median_vertex_cos(const BMFace *f,
mul_v3_fl(r_cent, 1.0f / f->len);
}
-/**
- * For tools that insist on using triangles, ideally we would cache this data.
- *
- * \param use_fixed_quad: When true,
- * always split quad along (0 -> 2) regardless of concave corners,
- * (as done in #BM_mesh_calc_tessellation).
- * \param r_loops: Store face loop pointers, (f->len)
- * \param r_index: Store triangle triples, indices into \a r_loops, `((f->len - 2) * 3)`
- */
void BM_face_calc_tessellation(const BMFace *f,
const bool use_fixed_quad,
BMLoop **r_loops,
@@ -177,9 +168,6 @@ void BM_face_calc_tessellation(const BMFace *f,
}
}
-/**
- * Return a point inside the face.
- */
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
{
const BMLoop *l_tri[3];
@@ -218,9 +206,6 @@ void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
mid_v3_v3v3v3(r_co, l_tri[0]->v->co, l_tri[1]->v->co, l_tri[2]->v->co);
}
-/**
- * get the area of the face
- */
float BM_face_calc_area(const BMFace *f)
{
/* inline 'area_poly_v3' logic, avoid creating a temp array */
@@ -235,9 +220,6 @@ float BM_face_calc_area(const BMFace *f)
return len_v3(n) * 0.5f;
}
-/**
- * Get the area of the face in world space.
- */
float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3])
{
/* inline 'area_poly_v3' logic, avoid creating a temp array */
@@ -257,9 +239,6 @@ float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3])
return len_v3(n) * 0.5f;
}
-/**
- * get the area of UV face
- */
float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset)
{
/* inline 'area_poly_v2' logic, avoid creating a temp array */
@@ -276,9 +255,6 @@ float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset)
return fabsf(cross * 0.5f);
}
-/**
- * compute the perimeter of an ngon
- */
float BM_face_calc_perimeter(const BMFace *f)
{
const BMLoop *l_iter, *l_first;
@@ -292,9 +268,6 @@ float BM_face_calc_perimeter(const BMFace *f)
return perimeter;
}
-/**
- * Calculate the perimeter of a ngon in world space.
- */
float BM_face_calc_perimeter_with_mat3(const BMFace *f, const float mat3[3][3])
{
const BMLoop *l_iter, *l_first;
@@ -355,14 +328,6 @@ static int bm_vert_tri_find_unique_edge(BMVert *verts[3])
return order[0];
}
-/**
- * Calculate a tangent from any 3 vertices.
- *
- * The tangent aligns to the most *unique* edge
- * (the edge most unlike the other two).
- *
- * \param r_tangent: Calculated unit length tangent (return value).
- */
void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3])
{
const int index = bm_vert_tri_find_unique_edge(verts);
@@ -372,14 +337,6 @@ void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Calculate a tangent from any 3 vertices,
- *
- * The tangent follows the center-line formed by the most unique edges center
- * and the opposite vertex.
- *
- * \param r_tangent: Calculated unit length tangent (return value).
- */
void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3])
{
const int index = bm_vert_tri_find_unique_edge(verts);
@@ -394,9 +351,6 @@ void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Compute the tangent of the face, using the longest edge.
- */
void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3])
{
const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f);
@@ -406,11 +360,6 @@ void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Compute the tangent of the face, using the two longest disconnected edges.
- *
- * \param r_tangent: Calculated unit length tangent (return value).
- */
void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3])
{
if (f->len == 3) {
@@ -471,11 +420,6 @@ void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3])
}
}
-/**
- * Compute the tangent of the face, using the edge farthest away from any vertex in the face.
- *
- * \param r_tangent: Calculated unit length tangent (return value).
- */
void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3])
{
BMLoop *l_iter, *l_first;
@@ -508,11 +452,6 @@ void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Compute the tangent of the face, using longest distance between vertices on the face.
- *
- * \note The logic is almost identical to #BM_face_calc_tangent_edge_diagonal
- */
void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3])
{
BMLoop *l_iter, *l_first;
@@ -541,11 +480,6 @@ void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Compute a meaningful direction along the face (use for gizmo axis).
- *
- * \note Callers shouldn't depend on the *exact* method used here.
- */
void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3])
{
if (f->len == 3) {
@@ -564,9 +498,6 @@ void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3])
}
}
-/**
- * expands bounds (min/max must be initialized).
- */
void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3])
{
const BMLoop *l_iter, *l_first;
@@ -576,9 +507,6 @@ void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3])
} while ((l_iter = l_iter->next) != l_first);
}
-/**
- * computes center of face in 3d. uses center of bounding box.
- */
void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
{
const BMLoop *l_iter, *l_first;
@@ -594,9 +522,6 @@ void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
mid_v3_v3v3(r_cent, min, max);
}
-/**
- * computes center of face in 3d. uses center of bounding box.
- */
void BM_face_calc_center_bounds_vcos(const BMesh *bm,
const BMFace *f,
float r_cent[3],
@@ -619,9 +544,6 @@ void BM_face_calc_center_bounds_vcos(const BMesh *bm,
mid_v3_v3v3(r_cent, min, max);
}
-/**
- * computes the center of a face, using the mean average
- */
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
{
const BMLoop *l_iter, *l_first;
@@ -635,10 +557,6 @@ void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
mul_v3_fl(r_cent, 1.0f / (float)f->len);
}
-/**
- * computes the center of a face, using the mean average
- * weighted by edge length
- */
void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3])
{
const BMLoop *l_iter;
@@ -663,12 +581,6 @@ void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3])
}
}
-/**
- * \brief POLY ROTATE PLANE
- *
- * Rotates a polygon so that its
- * normal is pointing towards the mesh Z axis
- */
void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nverts)
{
float mat[3][3];
@@ -684,9 +596,6 @@ void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nver
}
}
-/**
- * updates face and vertex normals incident on an edge
- */
void BM_edge_normals_update(BMEdge *e)
{
BMIter iter;
@@ -800,24 +709,11 @@ void BM_vert_normal_update_all(BMVert *v)
}
}
-/**
- * update a vert normal (but not the faces incident on it)
- */
void BM_vert_normal_update(BMVert *v)
{
BM_vert_calc_normal(v, v->no);
}
-/**
- * \brief BMESH UPDATE FACE NORMAL
- *
- * Updates the stored normal for the
- * given face. Requires that a buffer
- * of sufficient length to store projected
- * coordinates for all of the face's vertices
- * is passed in as well.
- */
-
float BM_face_calc_normal(const BMFace *f, float r_no[3])
{
BMLoop *l;
@@ -849,7 +745,6 @@ void BM_face_normal_update(BMFace *f)
BM_face_calc_normal(f, f->no);
}
-/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
float BM_face_calc_normal_vcos(const BMesh *bm,
const BMFace *f,
float r_no[3],
@@ -884,12 +779,6 @@ float BM_face_calc_normal_vcos(const BMesh *bm,
}
}
-/**
- * Calculate a normal from a vertex cloud.
- *
- * \note We could make a higher quality version that takes all vertices into account.
- * Currently it finds 4 outer most points returning its normal.
- */
void BM_verts_calc_normal_from_cloud_ex(
BMVert **varr, int varr_len, float r_normal[3], float r_center[3], int *r_index_tangent)
{
@@ -991,9 +880,6 @@ void BM_verts_calc_normal_from_cloud(BMVert **varr, int varr_len, float r_normal
BM_verts_calc_normal_from_cloud_ex(varr, varr_len, r_normal, NULL, NULL);
}
-/**
- * Calculates the face subset normal.
- */
float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3])
{
const float *v_prev, *v_curr;
@@ -1014,7 +900,6 @@ float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, fl
return normalize_v3(r_no);
}
-/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
void BM_face_calc_center_median_vcos(const BMesh *bm,
const BMFace *f,
float r_cent[3],
@@ -1027,12 +912,6 @@ void BM_face_calc_center_median_vcos(const BMesh *bm,
bm_face_calc_poly_center_median_vertex_cos(f, r_cent, vertexCos);
}
-/**
- * \brief Face Flip Normal
- *
- * Reverses the winding of a face.
- * \note This updates the calculated normal.
- */
void BM_face_normal_flip_ex(BMesh *bm,
BMFace *f,
const int cd_loop_mdisp_offset,
@@ -1048,16 +927,6 @@ void BM_face_normal_flip(BMesh *bm, BMFace *f)
BM_face_normal_flip_ex(bm, f, cd_loop_mdisp_offset, true);
}
-/**
- * BM POINT IN FACE
- *
- * Projects co onto face f, and returns true if it is inside
- * the face bounds.
- *
- * \note this uses a best-axis projection test,
- * instead of projecting co directly into f's orientation space,
- * so there might be accuracy issues.
- */
bool BM_face_point_inside_test(const BMFace *f, const float co[3])
{
float axis_mat[3][3];
@@ -1080,29 +949,6 @@ bool BM_face_point_inside_test(const BMFace *f, const float co[3])
return isect_point_poly_v2(co_2d, projverts, f->len, false);
}
-/**
- * \brief BMESH TRIANGULATE FACE
- *
- * Breaks all quads and ngons down to triangles.
- * It uses polyfill for the ngons splitting, and
- * the beautify operator when use_beauty is true.
- *
- * \param r_faces_new: if non-null, must be an array of BMFace pointers,
- * with a length equal to (f->len - 3). It will be filled with the new
- * triangles (not including the original triangle).
- *
- * \param r_faces_double: When newly created faces are duplicates of existing faces,
- * they're added to this list. Caller must handle de-duplication.
- * This is done because its possible _all_ faces exist already,
- * and in that case we would have to remove all faces including the one passed,
- * which causes complications adding/removing faces while looking over them.
- *
- * \note The number of faces is _almost_ always (f->len - 3),
- * However there may be faces that already occupying the
- * triangles we would make, so the caller must check \a r_faces_new_tot.
- *
- * \note use_tag tags new flags and edges.
- */
void BM_face_triangulate(BMesh *bm,
BMFace *f,
BMFace **r_faces_new,
@@ -1161,6 +1007,7 @@ void BM_face_triangulate(BMesh *bm,
break;
}
case MOD_TRIANGULATE_QUAD_SHORTEDGE:
+ case MOD_TRIANGULATE_QUAD_LONGEDGE:
case MOD_TRIANGULATE_QUAD_BEAUTY:
default: {
BMLoop *l_v3, *l_v4;
@@ -1177,6 +1024,12 @@ void BM_face_triangulate(BMesh *bm,
d2 = len_squared_v3v3(l_v1->v->co, l_v3->v->co);
split_24 = ((d2 - d1) > 0.0f);
}
+ else if (quad_method == MOD_TRIANGULATE_QUAD_LONGEDGE) {
+ float d1, d2;
+ d1 = len_squared_v3v3(l_v4->v->co, l_v2->v->co);
+ d2 = len_squared_v3v3(l_v1->v->co, l_v3->v->co);
+ split_24 = ((d2 - d1) < 0.0f);
+ }
else {
/* first check if the quad is concave on either diagonal */
const int flip_flag = is_quad_flip_v3(
@@ -1325,14 +1178,6 @@ void BM_face_triangulate(BMesh *bm,
}
}
-/**
- * each pair of loops defines a new edge, a split. this function goes
- * through and sets pairs that are geometrically invalid to null. a
- * split is invalid, if it forms a concave angle or it intersects other
- * edges in the face, or it intersects another split. in the case of
- * intersecting splits, only the first of the set of intersecting
- * splits survives
- */
void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len)
{
float out[2] = {-FLT_MAX, -FLT_MAX};
@@ -1430,10 +1275,6 @@ void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int l
#undef EDGE_SHARE_VERT
}
-/**
- * This simply checks that the verts don't connect faces which would have more optimal splits.
- * but _not_ check for correctness.
- */
void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len)
{
int i;
@@ -1447,12 +1288,6 @@ void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len)
}
}
-/**
- * Small utility functions for fast access
- *
- * faster alternative to:
- * BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 3);
- */
void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3])
{
BMLoop *l = BM_FACE_FIRST_LOOP(f);
@@ -1466,10 +1301,6 @@ void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3])
r_verts[2] = l->v;
}
-/**
- * faster alternative to:
- * BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 4);
- */
void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4])
{
BMLoop *l = BM_FACE_FIRST_LOOP(f);
@@ -1485,12 +1316,6 @@ void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4])
r_verts[3] = l->v;
}
-/**
- * Small utility functions for fast access
- *
- * faster alternative to:
- * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 3);
- */
void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3])
{
BMLoop *l = BM_FACE_FIRST_LOOP(f);
@@ -1504,10 +1329,6 @@ void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3])
r_loops[2] = l;
}
-/**
- * faster alternative to:
- * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 4);
- */
void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4])
{
BMLoop *l = BM_FACE_FIRST_LOOP(f);
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index 5be7f4a5f3b..2123410c738 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -25,68 +25,200 @@ struct Heap;
#include "BLI_compiler_attrs.h"
+/**
+ * For tools that insist on using triangles, ideally we would cache this data.
+ *
+ * \param use_fixed_quad: When true,
+ * always split quad along (0 -> 2) regardless of concave corners,
+ * (as done in #BM_mesh_calc_tessellation).
+ * \param r_loops: Store face loop pointers, (f->len)
+ * \param r_index: Store triangle triples, indices into \a r_loops, `((f->len - 2) * 3)`
+ */
void BM_face_calc_tessellation(const BMFace *f,
- const bool use_fixed_quad,
+ bool use_fixed_quad,
BMLoop **r_loops,
uint (*r_index)[3]);
+/**
+ * Return a point inside the face.
+ */
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]);
+
+/**
+ * \brief BMESH UPDATE FACE NORMAL
+ *
+ * Updates the stored normal for the
+ * given face. Requires that a buffer
+ * of sufficient length to store projected
+ * coordinates for all of the face's vertices
+ * is passed in as well.
+ */
float BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL();
+/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
float BM_face_calc_normal_vcos(const BMesh *bm,
const BMFace *f,
float r_no[3],
float const (*vertexCos)[3]) ATTR_NONNULL();
+/**
+ * Calculate a normal from a vertex cloud.
+ *
+ * \note We could make a higher quality version that takes all vertices into account.
+ * Currently it finds 4 outer most points returning its normal.
+ */
void BM_verts_calc_normal_from_cloud_ex(
BMVert **varr, int varr_len, float r_normal[3], float r_center[3], int *r_index_tangent);
void BM_verts_calc_normal_from_cloud(BMVert **varr, int varr_len, float r_normal[3]);
+/**
+ * Calculates the face subset normal.
+ */
float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3])
ATTR_NONNULL();
+/**
+ * get the area of the face
+ */
float BM_face_calc_area(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Get the area of the face in world space.
+ */
float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * get the area of UV face
+ */
float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * compute the perimeter of an ngon
+ */
float BM_face_calc_perimeter(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Calculate the perimeter of a ngon in world space.
+ */
float BM_face_calc_perimeter_with_mat3(const BMFace *f,
const float mat3[3][3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Compute the tangent of the face, using the longest edge.
+ */
void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * Compute the tangent of the face, using the two longest disconnected edges.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * Compute the tangent of the face, using the edge farthest away from any vertex in the face.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * Compute the tangent of the face, using longest distance between vertices on the face.
+ *
+ * \note The logic is almost identical to #BM_face_calc_tangent_edge_diagonal
+ */
void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * Compute a meaningful direction along the face (use for gizmo axis).
+ *
+ * \note Callers shouldn't depend on the *exact* method used here.
+ */
void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * computes center of face in 3d. uses center of bounding box.
+ */
void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3]) ATTR_NONNULL();
+/**
+ * computes center of face in 3d. uses center of bounding box.
+ */
void BM_face_calc_center_bounds_vcos(const BMesh *bm,
const BMFace *f,
float r_center[3],
float const (*vertexCos)[3]) ATTR_NONNULL();
+/**
+ * computes the center of a face, using the mean average
+ */
void BM_face_calc_center_median(const BMFace *f, float r_center[3]) ATTR_NONNULL();
+/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
void BM_face_calc_center_median_vcos(const BMesh *bm,
const BMFace *f,
float r_center[3],
float const (*vertexCos)[3]) ATTR_NONNULL();
+/**
+ * computes the center of a face, using the mean average
+ * weighted by edge length
+ */
void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3]) ATTR_NONNULL();
+/**
+ * expands bounds (min/max must be initialized).
+ */
void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3]);
void BM_face_normal_update(BMFace *f) ATTR_NONNULL();
+/**
+ * updates face and vertex normals incident on an edge
+ */
void BM_edge_normals_update(BMEdge *e) ATTR_NONNULL();
-bool BM_vert_calc_normal_ex(const BMVert *v, const char hflag, float r_no[3]);
+bool BM_vert_calc_normal_ex(const BMVert *v, char hflag, float r_no[3]);
bool BM_vert_calc_normal(const BMVert *v, float r_no[3]);
+/**
+ * update a vert normal (but not the faces incident on it)
+ */
void BM_vert_normal_update(BMVert *v) ATTR_NONNULL();
void BM_vert_normal_update_all(BMVert *v) ATTR_NONNULL();
+/**
+ * \brief Face Flip Normal
+ *
+ * Reverses the winding of a face.
+ * \note This updates the calculated normal.
+ */
void BM_face_normal_flip_ex(BMesh *bm,
BMFace *f,
- const int cd_loop_mdisp_offset,
- const bool use_loop_mdisp_flip) ATTR_NONNULL();
+ int cd_loop_mdisp_offset,
+ bool use_loop_mdisp_flip) ATTR_NONNULL();
void BM_face_normal_flip(BMesh *bm, BMFace *f) ATTR_NONNULL();
+/**
+ * BM POINT IN FACE
+ *
+ * Projects co onto face f, and returns true if it is inside
+ * the face bounds.
+ *
+ * \note this uses a best-axis projection test,
+ * instead of projecting co directly into f's orientation space,
+ * so there might be accuracy issues.
+ */
bool BM_face_point_inside_test(const BMFace *f, const float co[3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief BMESH TRIANGULATE FACE
+ *
+ * Breaks all quads and ngons down to triangles.
+ * It uses poly-fill for the ngons splitting, and
+ * the beautify operator when use_beauty is true.
+ *
+ * \param r_faces_new: if non-null, must be an array of BMFace pointers,
+ * with a length equal to (f->len - 3). It will be filled with the new
+ * triangles (not including the original triangle).
+ *
+ * \param r_faces_double: When newly created faces are duplicates of existing faces,
+ * they're added to this list. Caller must handle de-duplication.
+ * This is done because its possible _all_ faces exist already,
+ * and in that case we would have to remove all faces including the one passed,
+ * which causes complications adding/removing faces while looking over them.
+ *
+ * \note The number of faces is _almost_ always (f->len - 3),
+ * However there may be faces that already occupying the
+ * triangles we would make, so the caller must check \a r_faces_new_tot.
+ *
+ * \note use_tag tags new flags and edges.
+ */
void BM_face_triangulate(BMesh *bm,
BMFace *f,
BMFace **r_faces_new,
@@ -94,20 +226,68 @@ void BM_face_triangulate(BMesh *bm,
BMEdge **r_edges_new,
int *r_edges_new_tot,
struct LinkNode **r_faces_double,
- const int quad_method,
- const int ngon_method,
- const bool use_tag,
+ int quad_method,
+ int ngon_method,
+ bool use_tag,
struct MemArena *pf_arena,
struct Heap *pf_heap) ATTR_NONNULL(1, 2);
+/**
+ * each pair of loops defines a new edge, a split. this function goes
+ * through and sets pairs that are geometrically invalid to null. a
+ * split is invalid, if it forms a concave angle or it intersects other
+ * edges in the face, or it intersects another split. in the case of
+ * intersecting splits, only the first of the set of intersecting
+ * splits survives
+ */
void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL();
+/**
+ * This simply checks that the verts don't connect faces which would have more optimal splits.
+ * but _not_ check for correctness.
+ */
void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL();
+/**
+ * Small utility functions for fast access
+ *
+ * faster alternative to:
+ * BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 3);
+ */
void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3]) ATTR_NONNULL();
+/**
+ * faster alternative to:
+ * BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 4);
+ */
void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]) ATTR_NONNULL();
+/**
+ * Small utility functions for fast access
+ *
+ * faster alternative to:
+ * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 3);
+ */
void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3]) ATTR_NONNULL();
+/**
+ * faster alternative to:
+ * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 4);
+ */
void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4]) ATTR_NONNULL();
+/**
+ * Calculate a tangent from any 3 vertices.
+ *
+ * The tangent aligns to the most *unique* edge
+ * (the edge most unlike the other two).
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3]);
+/**
+ * Calculate a tangent from any 3 vertices,
+ *
+ * The tangent follows the center-line formed by the most unique edges center
+ * and the opposite vertex.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3]);
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
index 103d7621f87..24d9c194054 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
@@ -452,14 +452,6 @@ static bool bm_face_split_edgenet_find_loop(BMVert *v_init,
return false;
}
-/**
- * Splits a face into many smaller faces defined by an edge-net.
- * handle customdata and degenerate cases.
- *
- * - Isolated holes or unsupported face configurations, will be ignored.
- * - Customdata calculations aren't efficient
- * (need to calculate weights for each vert).
- */
bool BM_face_split_edgenet(BMesh *bm,
BMFace *f,
BMEdge **edge_net,
@@ -1223,14 +1215,6 @@ static bool bm_vert_partial_connect_check_overlap(const int *remap,
#endif /* USE_PARTIAL_CONNECT */
-/**
- * For when the edge-net has holes in it-this connects them.
- *
- * \param use_partial_connect: Support for handling islands connected by only a single edge,
- * \note that this is quite slow so avoid using where possible.
- * \param mem_arena: Avoids many small allocs & should be cleared after each use.
- * take care since \a edge_net_new is stored in \a r_edge_net_new.
- */
bool BM_face_split_edgenet_connect_islands(BMesh *bm,
BMFace *f,
BMEdge **edge_net_init,
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
index 6833f067421..626df9fb46a 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
@@ -20,19 +20,35 @@
* \ingroup bmesh
*/
+/**
+ * Splits a face into many smaller faces defined by an edge-net.
+ * handle customdata and degenerate cases.
+ *
+ * - Isolated holes or unsupported face configurations, will be ignored.
+ * - Customdata calculations aren't efficient
+ * (need to calculate weights for each vert).
+ */
bool BM_face_split_edgenet(BMesh *bm,
BMFace *f,
BMEdge **edge_net,
- const int edge_net_len,
+ int edge_net_len,
BMFace ***r_face_arr,
int *r_face_arr_len);
+/**
+ * For when the edge-net has holes in it-this connects them.
+ *
+ * \param use_partial_connect: Support for handling islands connected by only a single edge,
+ * \note that this is quite slow so avoid using where possible.
+ * \param mem_arena: Avoids many small allocs & should be cleared after each use.
+ * take care since \a edge_net_new is stored in \a r_edge_net_new.
+ */
bool BM_face_split_edgenet_connect_islands(BMesh *bm,
BMFace *f,
BMEdge **edge_net_init,
- const uint edge_net_init_len,
+ uint edge_net_init_len,
bool use_partial_connect,
- struct MemArena *arena,
+ struct MemArena *mem_arena,
BMEdge ***r_edge_net_new,
uint *r_edge_net_new_len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2, 3, 6, 7, 8);
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
index e1df7744e41..4b3c4cbff82 100644
--- a/source/blender/bmesh/intern/bmesh_private.h
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -27,6 +27,10 @@
* parts of the bmesh internals.
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* returns positive nonzero on error */
#ifdef NDEBUG
@@ -34,7 +38,13 @@
* it can take most of the CPU time when running some tools. */
# define BM_CHECK_ELEMENT(el) (void)(el)
#else
-int bmesh_elem_check(void *element, const char htype);
+/**
+ * Check the element is valid.
+ *
+ * BMESH_TODO, when this raises an error the output is incredibly confusing.
+ * need to have some nice way to print/debug what the heck's going on.
+ */
+int bmesh_elem_check(void *element, char htype);
# define BM_CHECK_ELEMENT(el) \
{ \
if (bmesh_elem_check(el, ((BMHeader *)el)->htype)) { \
@@ -50,7 +60,7 @@ int bmesh_elem_check(void *element, const char htype);
#endif
int bmesh_radial_length(const BMLoop *l);
-int bmesh_disk_count_at_most(const BMVert *v, const int count_max);
+int bmesh_disk_count_at_most(const BMVert *v, int count_max);
int bmesh_disk_count(const BMVert *v);
/**
@@ -86,7 +96,17 @@ enum {
} \
(void)0
-void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nverts);
+/**
+ * \brief POLY ROTATE PLANE
+ *
+ * Rotates a polygon so that its
+ * normal is pointing towards the mesh Z axis
+ */
+void poly_rotate_plane(const float normal[3], float (*verts)[3], uint nverts);
/* include the rest of our private declarations */
#include "bmesh_structure.h"
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index 795d8829ee7..fe2142670a2 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -37,24 +37,6 @@
#include "bmesh.h"
#include "intern/bmesh_private.h"
-/**
- * \brief Other Loop in Face Sharing an Edge
- *
- * Finds the other loop that shares \a v with \a e loop in \a f.
- * <pre>
- * +----------+
- * | |
- * | f |
- * | |
- * +----------+ <-- return the face loop of this vertex.
- * v --> e
- * ^ ^ <------- These vert args define direction
- * in the face to check.
- * The faces loop direction is ignored.
- * </pre>
- *
- * \note caller must ensure \a e is used in \a f
- */
BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v)
{
BMLoop *l = BM_face_edge_share_loop(f, e);
@@ -62,38 +44,12 @@ BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v)
return BM_loop_other_edge_loop(l, v);
}
-/**
- * See #BM_face_other_edge_loop This is the same functionality
- * to be used when the edges loop is already known.
- */
BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v)
{
BLI_assert(BM_vert_in_edge(l->e, v));
return l->v == v ? l->prev : l->next;
}
-/**
- * \brief Other Loop in Face Sharing a Vertex
- *
- * Finds the other loop in a face.
- *
- * This function returns a loop in \a f that shares an edge with \a v
- * The direction is defined by \a v_prev, where the return value is
- * the loop of what would be 'v_next'
- * <pre>
- * +----------+ <-- return the face loop of this vertex.
- * | |
- * | f |
- * | |
- * +----------+
- * v_prev --> v
- * ^^^^^^ ^ <-- These vert args define direction
- * in the face to check.
- * The faces loop direction is ignored.
- * </pre>
- *
- * \note \a v_prev and \a v _implicitly_ define an edge.
- */
BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
{
BMLoop *l_iter = BM_face_vert_share_loop(f, v);
@@ -116,22 +72,6 @@ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
return NULL;
}
-/**
- * \brief Other Loop in Face Sharing a Vert
- *
- * Finds the other loop that shares \a v with \a e loop in \a f.
- * <pre>
- * +----------+ <-- return the face loop of this vertex.
- * | |
- * | |
- * | |
- * +----------+ <-- This vertex defines the direction.
- * l v
- * ^ <------- This loop defines both the face to search
- * and the edge, in combination with 'v'
- * The faces loop direction is ignored.
- * </pre>
- */
BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
{
#if 0 /* works but slow */
@@ -157,22 +97,6 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
#endif
}
-/**
- * Return the other loop that uses this edge.
- *
- * In this case the loop defines the vertex,
- * the edge passed in defines the direction to step.
- *
- * <pre>
- * +----------+ <-- Return the face-loop of this vertex.
- * | |
- * | e | <-- This edge defines the direction.
- * | |
- * +----------+ <-- This loop defines the face and vertex..
- * l
- * </pre>
- *
- */
BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e)
{
BLI_assert(BM_vert_in_edge(e, l->v));
@@ -187,9 +111,6 @@ BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e)
return NULL;
}
-/**
- * Check if verts share a face.
- */
bool BM_vert_pair_share_face_check(BMVert *v_a, BMVert *v_b)
{
if (v_a->e && v_b->e) {
@@ -255,9 +176,6 @@ BMFace *BM_vert_pair_shared_face_cb(BMVert *v_a,
return NULL;
}
-/**
- * Given 2 verts, find the smallest face they share and give back both loops.
- */
BMFace *BM_vert_pair_share_face_by_len(
BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
{
@@ -325,24 +243,12 @@ static float bm_face_calc_split_dot(BMLoop *l_a, BMLoop *l_b)
return -1.0f;
}
-/**
- * Check if a point is inside the corner defined by a loop
- * (within the 2 planes defined by the loops corner & face normal).
- *
- * \return signed, squared distance to the loops planes, less than 0.0 when outside.
- */
float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3])
{
const float *axis = l->f->no;
return dist_signed_squared_to_corner_v3v3v3(co, l->prev->v->co, l->v->co, l->next->v->co, axis);
}
-/**
- * Check if a point is inside the edge defined by a loop
- * (within the plane defined by the loops edge & face normal).
- *
- * \return signed, squared distance to the edge plane, less than 0.0 when outside.
- */
float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3])
{
const float *axis = l->f->no;
@@ -356,13 +262,6 @@ float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3])
return dist_signed_squared_to_plane_v3(co, plane);
}
-/**
- * Given 2 verts,
- * find a face they share that has the lowest angle across these verts and give back both loops.
- *
- * This can be better than #BM_vert_pair_share_face_by_len
- * because concave splits are ranked lowest.
- */
BMFace *BM_vert_pair_share_face_by_angle(
BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
{
@@ -409,25 +308,15 @@ BMFace *BM_vert_pair_share_face_by_angle(
return f_cur;
}
-/**
- * Get the first loop of a vert. Uses the same initialization code for the first loop of the
- * iterator API
- */
BMLoop *BM_vert_find_first_loop(BMVert *v)
{
return v->e ? bmesh_disk_faceloop_find_first(v->e, v) : NULL;
}
-/**
- * A version of #BM_vert_find_first_loop that ignores hidden loops.
- */
BMLoop *BM_vert_find_first_loop_visible(BMVert *v)
{
return v->e ? bmesh_disk_faceloop_find_first_visible(v->e, v) : NULL;
}
-/**
- * Returns true if the vertex is used in a given face.
- */
bool BM_vert_in_face(BMVert *v, BMFace *f)
{
BMLoop *l_iter, *l_first;
@@ -452,10 +341,6 @@ bool BM_vert_in_face(BMVert *v, BMFace *f)
return false;
}
-/**
- * Compares the number of vertices in an array
- * that appear in a given face
- */
int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f)
{
BMLoop *l_iter, *l_first;
@@ -496,9 +381,6 @@ int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f)
return count;
}
-/**
- * Return true if all verts are in the face.
- */
bool BM_verts_in_face(BMVert **varr, int len, BMFace *f)
{
BMLoop *l_iter, *l_first;
@@ -549,9 +431,6 @@ bool BM_verts_in_face(BMVert **varr, int len, BMFace *f)
return ok;
}
-/**
- * Returns whether or not a given edge is part of a given face.
- */
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
{
if (e->l) {
@@ -568,22 +447,6 @@ bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
return false;
}
-/**
- * Given a edge and a loop (assumes the edge is manifold). returns
- * the other faces loop, sharing the same vertex.
- *
- * <pre>
- * +-------------------+
- * | |
- * | |
- * |l_other <-- return |
- * +-------------------+ <-- A manifold edge between 2 faces
- * |l e <-- edge |
- * |^ <-------- loop |
- * | |
- * +-------------------+
- * </pre>
- */
BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l)
{
BMLoop *l_other;
@@ -609,31 +472,6 @@ BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l)
return l_other;
}
-/**
- * Utility function to step around a fan of loops,
- * using an edge to mark the previous side.
- *
- * \note all edges must be manifold,
- * once a non manifold edge is hit, return NULL.
- *
- * <pre>
- * ,.,-->|
- * _,-' |
- * ,' | (notice how 'e_step'
- * / | and 'l' define the
- * / | direction the arrow
- * | return | points).
- * | loop --> |
- * ---------------------+---------------------
- * ^ l --> |
- * | |
- * assign e_step |
- * |
- * begin e_step ----> |
- * |
- * </pre>
- */
-
BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step)
{
BMEdge *e_prev = *e_step;
@@ -655,12 +493,6 @@ BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step)
return NULL;
}
-/**
- * The function takes a vertex at the center of a fan and returns the opposite edge in the fan.
- * All edges in the fan must be manifold, otherwise return NULL.
- *
- * \note This could (probably) be done more efficiently.
- */
BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first)
{
BMLoop *l_a;
@@ -707,28 +539,16 @@ BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first)
return NULL;
}
-/**
- * Returns edge length
- */
float BM_edge_calc_length(const BMEdge *e)
{
return len_v3v3(e->v1->co, e->v2->co);
}
-/**
- * Returns edge length squared (for comparisons)
- */
float BM_edge_calc_length_squared(const BMEdge *e)
{
return len_squared_v3v3(e->v1->co, e->v2->co);
}
-/**
- * Utility function, since enough times we have an edge
- * and want to access 2 connected faces.
- *
- * \return true when only 2 faces are found.
- */
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
{
BMLoop *la, *lb;
@@ -744,12 +564,6 @@ bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
return false;
}
-/**
- * Utility function, since enough times we have an edge
- * and want to access 2 connected loops.
- *
- * \return true when only 2 faces are found.
- */
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
{
BMLoop *la, *lb;
@@ -765,9 +579,6 @@ bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
return false;
}
-/**
- * Fast alternative to `(BM_vert_edge_count(v) == 2)`.
- */
bool BM_vert_is_edge_pair(const BMVert *v)
{
const BMEdge *e = v->e;
@@ -778,10 +589,6 @@ bool BM_vert_is_edge_pair(const BMVert *v)
return false;
}
-/**
- * Fast alternative to `(BM_vert_edge_count(v) == 2)`
- * that checks both edges connect to the same faces.
- */
bool BM_vert_is_edge_pair_manifold(const BMVert *v)
{
const BMEdge *e = v->e;
@@ -794,11 +601,6 @@ bool BM_vert_is_edge_pair_manifold(const BMVert *v)
return false;
}
-/**
- * Access a verts 2 connected edges.
- *
- * \return true when only 2 verts are found.
- */
bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b)
{
BMEdge *e_a = v->e;
@@ -816,9 +618,6 @@ bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b)
return false;
}
-/**
- * Returns the number of edges around this vertex.
- */
int BM_vert_edge_count(const BMVert *v)
{
return bmesh_disk_count(v);
@@ -841,9 +640,6 @@ int BM_vert_edge_count_nonwire(const BMVert *v)
}
return count;
}
-/**
- * Returns the number of faces around this edge
- */
int BM_edge_face_count(const BMEdge *e)
{
int count = 0;
@@ -879,10 +675,6 @@ int BM_edge_face_count_at_most(const BMEdge *e, const int count_max)
return count;
}
-/**
- * Returns the number of faces around this vert
- * length matches #BM_LOOPS_OF_VERT iterator
- */
int BM_vert_face_count(const BMVert *v)
{
return bmesh_disk_facevert_count(v);
@@ -893,11 +685,6 @@ int BM_vert_face_count_at_most(const BMVert *v, int count_max)
return bmesh_disk_facevert_count_at_most(v, count_max);
}
-/**
- * Return true if the vertex is connected to _any_ faces.
- *
- * same as `BM_vert_face_count(v) != 0` or `BM_vert_find_first_loop(v) == NULL`.
- */
bool BM_vert_face_check(const BMVert *v)
{
if (v->e != NULL) {
@@ -912,10 +699,6 @@ bool BM_vert_face_check(const BMVert *v)
return false;
}
-/**
- * Tests whether or not the vertex is part of a wire edge.
- * (ie: has no faces attached to it)
- */
bool BM_vert_is_wire(const BMVert *v)
{
if (v->e) {
@@ -933,13 +716,6 @@ bool BM_vert_is_wire(const BMVert *v)
return false;
}
-/**
- * A vertex is non-manifold if it meets the following conditions:
- * 1: Loose - (has no edges/faces incident upon it).
- * 2: Joins two distinct regions - (two pyramids joined at the tip).
- * 3: Is part of an edge with more than 2 faces.
- * 4: Is part of a wire edge.
- */
bool BM_vert_is_manifold(const BMVert *v)
{
BMEdge *e_iter, *e_first, *e_prev;
@@ -1064,9 +840,6 @@ static int bm_loop_region_count__clear(BMLoop *l)
return count;
}
-/**
- * The number of loops connected to this loop (not including disconnected regions).
- */
int BM_loop_region_loops_count_at_most(BMLoop *l, int *r_loop_total)
{
const int count = bm_loop_region_count__recursive(l->e, l->v);
@@ -1085,10 +858,6 @@ int BM_loop_region_loops_count(BMLoop *l)
return BM_loop_region_loops_count_at_most(l, NULL);
}
-/**
- * A version of #BM_vert_is_manifold
- * which only checks if we're connected to multiple isolated regions.
- */
bool BM_vert_is_manifold_region(const BMVert *v)
{
BMLoop *l_first = BM_vert_find_first_loop((BMVert *)v);
@@ -1100,10 +869,6 @@ bool BM_vert_is_manifold_region(const BMVert *v)
return true;
}
-/**
- * Check if the edge is convex or concave
- * (depends on face winding)
- */
bool BM_edge_is_convex(const BMEdge *e)
{
if (BM_edge_is_manifold(e)) {
@@ -1121,9 +886,6 @@ bool BM_edge_is_convex(const BMEdge *e)
return true;
}
-/**
- * \return true when loop customdata is contiguous.
- */
bool BM_edge_is_contiguous_loop_cd(const BMEdge *e,
const int cd_loop_type,
const int cd_loop_offset)
@@ -1182,11 +944,6 @@ bool BM_vert_is_boundary(const BMVert *v)
return false;
}
-/**
- * Returns the number of faces that are adjacent to both f1 and f2,
- * \note Could be sped up a bit by not using iterators and by tagging
- * faces on either side, then count the tags rather then searching.
- */
int BM_face_share_face_count(BMFace *f_a, BMFace *f_b)
{
BMIter iter1, iter2;
@@ -1205,9 +962,6 @@ int BM_face_share_face_count(BMFace *f_a, BMFace *f_b)
return count;
}
-/**
- * same as #BM_face_share_face_count but returns a bool
- */
bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b)
{
BMIter iter1, iter2;
@@ -1225,9 +979,6 @@ bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b)
return false;
}
-/**
- * Counts the number of edges two faces share (if any)
- */
int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b)
{
BMLoop *l_iter;
@@ -1244,9 +995,6 @@ int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b)
return count;
}
-/**
- * Returns true if the faces share an edge
- */
bool BM_face_share_edge_check(BMFace *f1, BMFace *f2)
{
BMLoop *l_iter;
@@ -1262,9 +1010,6 @@ bool BM_face_share_edge_check(BMFace *f1, BMFace *f2)
return false;
}
-/**
- * Counts the number of verts two faces share (if any).
- */
int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b)
{
BMLoop *l_iter;
@@ -1281,9 +1026,6 @@ int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b)
return count;
}
-/**
- * Returns true if the faces share a vert.
- */
bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b)
{
BMLoop *l_iter;
@@ -1299,18 +1041,12 @@ bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b)
return false;
}
-/**
- * Returns true when 2 loops share an edge (are adjacent in the face-fan)
- */
bool BM_loop_share_edge_check(BMLoop *l_a, BMLoop *l_b)
{
BLI_assert(l_a->v == l_b->v);
return (ELEM(l_a->e, l_b->e, l_b->prev->e) || ELEM(l_b->e, l_a->e, l_a->prev->e));
}
-/**
- * Test if e1 shares any faces with e2
- */
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
{
BMLoop *l;
@@ -1329,9 +1065,6 @@ bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
return false;
}
-/**
- * Test if e1 shares any quad faces with e2
- */
bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2)
{
BMLoop *l;
@@ -1352,17 +1085,11 @@ bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2)
return false;
}
-/**
- * Tests to see if e1 shares a vertex with e2
- */
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2)
{
return (e1->v1 == e2->v1 || e1->v1 == e2->v2 || e1->v2 == e2->v1 || e1->v2 == e2->v2);
}
-/**
- * Return the shared vertex between the two edges or NULL
- */
BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
{
BLI_assert(e1 != e2);
@@ -1375,14 +1102,6 @@ BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
return NULL;
}
-/**
- * \brief Return the Loop Shared by Edge and Vert
- *
- * Finds the loop used which uses \a in face loop \a l
- *
- * \note this function takes a loop rather than an edge
- * so we can select the face that the loop should be from.
- */
BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v)
{
BLI_assert(BM_vert_in_edge(l->e, v));
@@ -1392,14 +1111,6 @@ BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v)
return l->next;
}
-/**
- * \brief Return the Loop Shared by Face and Vertex
- *
- * Finds the loop used which uses \a v in face loop \a l
- *
- * \note currently this just uses simple loop in future may be sped up
- * using radial vars
- */
BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v)
{
BMLoop *l_first;
@@ -1415,14 +1126,6 @@ BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v)
return NULL;
}
-/**
- * \brief Return the Loop Shared by Face and Edge
- *
- * Finds the loop used which uses \a e in face loop \a l
- *
- * \note currently this just uses simple loop in future may be sped up
- * using radial vars
- */
BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e)
{
BMLoop *l_first;
@@ -1438,18 +1141,6 @@ BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e)
return NULL;
}
-/**
- * Returns the verts of an edge as used in a face
- * if used in a face at all, otherwise just assign as used in the edge.
- *
- * Useful to get a deterministic winding order when calling
- * BM_face_create_ngon() on an arbitrary array of verts,
- * though be sure to pick an edge which has a face.
- *
- * \note This is in fact quite a simple check,
- * mainly include this function so the intent is more obvious.
- * We know these 2 verts will _always_ make up the loops edge
- */
void BM_edge_ordered_verts_ex(const BMEdge *edge,
BMVert **r_v1,
BMVert **r_v2,
@@ -1466,9 +1157,6 @@ void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2)
BM_edge_ordered_verts_ex(edge, r_v1, r_v2, edge->l);
}
-/**
- * \return The previous loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
- */
BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
{
BMLoop *l_step = l->prev;
@@ -1486,9 +1174,6 @@ BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq
return l_step;
}
-/**
- * \return The next loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
- */
BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
{
BMLoop *l_step = l->next;
@@ -1506,10 +1191,6 @@ BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq
return l_step;
}
-/**
- * Check if the loop is convex or concave
- * (depends on face normal)
- */
bool BM_loop_is_convex(const BMLoop *l)
{
float e_dir_prev[3];
@@ -1522,26 +1203,11 @@ bool BM_loop_is_convex(const BMLoop *l)
return dot_v3v3(l_no, l->f->no) > 0.0f;
}
-/**
- * Calculates the angle between the previous and next loops
- * (angle at this loops face corner).
- *
- * \return angle in radians
- */
float BM_loop_calc_face_angle(const BMLoop *l)
{
return angle_v3v3v3(l->prev->v->co, l->v->co, l->next->v->co);
}
-/**
- * \brief BM_loop_calc_face_normal
- *
- * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
- *
- * \param l: The loop to calculate the normal at.
- * \param epsilon_sq: Value to avoid numeric errors (1e-5f works well).
- * \param r_normal: Resulting normal.
- */
float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, float r_normal[3])
{
/* NOTE: we cannot use result of normal_tri_v3 here to detect colinear vectors
@@ -1571,9 +1237,6 @@ float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq,
return 0.0f;
}
-/**
- * A version of BM_loop_calc_face_normal_safe_ex which takes vertex coordinates.
- */
float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
const float normal_fallback[3],
float const (*vertexCos)[3],
@@ -1604,11 +1267,6 @@ float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
return 0.0f;
}
-/**
- * #BM_loop_calc_face_normal_safe_ex with predefined sane epsilon.
- *
- * Since this doesn't scale based on triangle size, fixed value works well.
- */
float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3])
{
return BM_loop_calc_face_normal_safe_ex(l, 1e-5f, r_normal);
@@ -1623,15 +1281,6 @@ float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
return BM_loop_calc_face_normal_safe_vcos_ex(l, normal_fallback, vertexCos, 1e-5f, r_normal);
}
-/**
- * \brief BM_loop_calc_face_normal
- *
- * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
- *
- * \param l: The loop to calculate the normal at
- * \param r_normal: Resulting normal
- * \return The length of the cross product (double the area).
- */
float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
{
float v1[3], v2[3];
@@ -1646,14 +1295,6 @@ float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
return len;
}
-/**
- * \brief BM_loop_calc_face_direction
- *
- * Calculate the direction a loop is pointing.
- *
- * \param l: The loop to calculate the direction at
- * \param r_dir: Resulting direction
- */
void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3])
{
float v_prev[3];
@@ -1669,15 +1310,6 @@ void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3])
normalize_v3(r_dir);
}
-/**
- * \brief BM_loop_calc_face_tangent
- *
- * Calculate the tangent at this loop corner or fallback to the face normal on straight lines.
- * This vector always points inward into the face.
- *
- * \param l: The loop to calculate the tangent at
- * \param r_tangent: Resulting tangent
- */
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
{
float v_prev[3];
@@ -1708,14 +1340,6 @@ void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * \brief BMESH EDGE/FACE ANGLE
- *
- * Calculates the angle between two faces.
- * Assumes the face normals are correct.
- *
- * \return angle in radians
- */
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback)
{
if (BM_edge_is_manifold(e)) {
@@ -1730,14 +1354,6 @@ float BM_edge_calc_face_angle(const BMEdge *e)
return BM_edge_calc_face_angle_ex(e, DEG2RADF(90.0f));
}
-/**
- * \brief BMESH EDGE/FACE ANGLE
- *
- * Calculates the angle between two faces in world space.
- * Assumes the face normals are correct.
- *
- * \return angle in radians
- */
float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e,
const float imat3[3][3],
const float fallback)
@@ -1764,14 +1380,6 @@ float BM_edge_calc_face_angle_with_imat3(const BMEdge *e, const float imat3[3][3
return BM_edge_calc_face_angle_with_imat3_ex(e, imat3, DEG2RADF(90.0f));
}
-/**
- * \brief BMESH EDGE/FACE ANGLE
- *
- * Calculates the angle between two faces.
- * Assumes the face normals are correct.
- *
- * \return angle in radians
- */
float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback)
{
if (BM_edge_is_manifold(e)) {
@@ -1787,19 +1395,6 @@ float BM_edge_calc_face_angle_signed(const BMEdge *e)
return BM_edge_calc_face_angle_signed_ex(e, DEG2RADF(90.0f));
}
-/**
- * \brief BMESH EDGE/FACE TANGENT
- *
- * Calculate the tangent at this loop corner or fallback to the face normal on straight lines.
- * This vector always points inward into the face.
- *
- * \brief BM_edge_calc_face_tangent
- * \param e:
- * \param e_loop: The loop to calculate the tangent at,
- * used to get the face and winding direction.
- * \param r_tangent: The loop corner tangent to set
- */
-
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
{
float tvec[3];
@@ -1813,13 +1408,6 @@ void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_ta
normalize_v3(r_tangent);
}
-/**
- * \brief BMESH VERT/EDGE ANGLE
- *
- * Calculates the angle a verts 2 edges.
- *
- * \returns the angle in radians
- */
float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback)
{
BMEdge *e1, *e2;
@@ -1843,10 +1431,6 @@ float BM_vert_calc_edge_angle(const BMVert *v)
return BM_vert_calc_edge_angle_ex(v, DEG2RADF(90.0f));
}
-/**
- * \note this isn't optimal to run on an array of verts,
- * see 'solidify_add_thickness' for a function which runs on an array.
- */
float BM_vert_calc_shell_factor(const BMVert *v)
{
BMIter iter;
@@ -1865,8 +1449,6 @@ float BM_vert_calc_shell_factor(const BMVert *v)
}
return 1.0f;
}
-/* alternate version of #BM_vert_calc_shell_factor which only
- * uses 'hflag' faces, but falls back to all if none found. */
float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const char hflag)
{
BMIter iter;
@@ -1896,10 +1478,6 @@ float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const cha
return 1.0f;
}
-/**
- * \note quite an obscure function.
- * used in bmesh operators that have a relative scale options,
- */
float BM_vert_calc_median_tagged_edge_length(const BMVert *v)
{
BMIter iter;
@@ -1920,9 +1498,6 @@ float BM_vert_calc_median_tagged_edge_length(const BMVert *v)
return 0.0f;
}
-/**
- * Returns the loop of the shortest edge in f.
- */
BMLoop *BM_face_find_shortest_loop(BMFace *f)
{
BMLoop *shortest_loop = NULL;
@@ -1944,9 +1519,6 @@ BMLoop *BM_face_find_shortest_loop(BMFace *f)
return shortest_loop;
}
-/**
- * Returns the loop of the longest edge in f.
- */
BMLoop *BM_face_find_longest_loop(BMFace *f)
{
BMLoop *longest_loop = NULL;
@@ -2020,11 +1592,6 @@ BMEdge *BM_edge_exists(BMVert *v_a, BMVert *v_b)
}
#endif
-/**
- * Returns an edge sharing the same vertices as this one.
- * This isn't an invalid state but tools should clean up these cases before
- * returning the mesh to the user.
- */
BMEdge *BM_edge_find_double(BMEdge *e)
{
BMVert *v = e->v1;
@@ -2042,10 +1609,6 @@ BMEdge *BM_edge_find_double(BMEdge *e)
return NULL;
}
-/**
- * Only #BMEdge.l access us needed, however when we want the first visible loop,
- * a utility function is needed.
- */
BMLoop *BM_edge_find_first_loop_visible(BMEdge *e)
{
if (e->l != NULL) {
@@ -2060,13 +1623,6 @@ BMLoop *BM_edge_find_first_loop_visible(BMEdge *e)
return NULL;
}
-/**
- * Given a set of vertices (varr), find out if
- * there is a face with exactly those vertices
- * (and only those vertices).
- *
- * \note there used to be a BM_face_exists_overlap function that checks for partial overlap.
- */
BMFace *BM_face_exists(BMVert **varr, int len)
{
if (varr[0]->e) {
@@ -2115,9 +1671,6 @@ BMFace *BM_face_exists(BMVert **varr, int len)
return NULL;
}
-/**
- * Check if the face has an exact duplicate (both winding directions).
- */
BMFace *BM_face_find_double(BMFace *f)
{
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
@@ -2150,18 +1703,6 @@ BMFace *BM_face_find_double(BMFace *f)
return NULL;
}
-/**
- * Given a set of vertices and edges (\a varr, \a earr), find out if
- * all those vertices are filled in by existing faces that _only_ use those vertices.
- *
- * This is for use in cases where creating a face is possible but would result in
- * many overlapping faces.
- *
- * An example of how this is used: when 2 tri's are selected that share an edge,
- * pressing Fkey would make a new overlapping quad (without a check like this)
- *
- * \a earr and \a varr can be in any order, however they _must_ form a closed loop.
- */
bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len)
{
BMFace *f;
@@ -2270,7 +1811,6 @@ finally:
return ok;
}
-/* same as 'BM_face_exists_multi' but built vert array from edges */
bool BM_face_exists_multi_edge(BMEdge **earr, int len)
{
BMVert **varr = BLI_array_alloca(varr, len);
@@ -2284,20 +1824,6 @@ bool BM_face_exists_multi_edge(BMEdge **earr, int len)
return BM_face_exists_multi(varr, earr, len);
}
-/**
- * Given a set of vertices (varr), find out if
- * all those vertices overlap an existing face.
- *
- * \note The face may contain other verts \b not in \a varr.
- *
- * \note Its possible there are more than one overlapping faces,
- * in this case the first one found will be returned.
- *
- * \param varr: Array of unordered verts.
- * \param len: \a varr array length.
- * \return The face or NULL.
- */
-
BMFace *BM_face_exists_overlap(BMVert **varr, const int len)
{
BMIter viter;
@@ -2336,14 +1862,6 @@ BMFace *BM_face_exists_overlap(BMVert **varr, const int len)
return f_overlap;
}
-/**
- * Given a set of vertices (varr), find out if
- * there is a face that uses vertices only from this list
- * (that the face is a subset or made from the vertices given).
- *
- * \param varr: Array of unordered verts.
- * \param len: varr array length.
- */
bool BM_face_exists_overlap_subset(BMVert **varr, const int len)
{
BMIter viter;
@@ -2477,7 +1995,6 @@ bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag)
return false;
}
-/* convenience functions for checking flags */
bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag)
{
return (BM_elem_flag_test(e->v1, hflag) || BM_elem_flag_test(e->v2, hflag));
@@ -2527,9 +2044,6 @@ bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len)
return false;
}
-/**
- * Use within assert's to check normals are valid.
- */
bool BM_face_is_normal_valid(const BMFace *f)
{
const float eps = 0.0001f;
@@ -2591,23 +2105,6 @@ double BM_mesh_calc_volume(BMesh *bm, bool is_signed)
return vol;
}
-/* NOTE: almost duplicate of #BM_mesh_calc_edge_groups, keep in sync. */
-/**
- * Calculate isolated groups of faces with optional filtering.
- *
- * \param bm: the BMesh.
- * \param r_groups_array: Array of ints to fill in, length of bm->totface
- * (or when hflag_test is set, the number of flagged faces).
- * \param r_group_index: index, length pairs into \a r_groups_array, size of return value
- * int pairs: (array_start, array_length).
- * \param filter_fn: Filter the edge-loops or vert-loops we step over (depends on \a htype_step).
- * \param user_data: Optional user data for \a filter_fn, can be NULL.
- * \param hflag_test: Optional flag to test faces,
- * use to exclude faces from the calculation, 0 for all faces.
- * \param htype_step: BM_VERT to walk over face-verts, BM_EDGE to walk over faces edges
- * (having both set is supported too).
- * \return The number of groups found.
- */
int BM_mesh_calc_face_groups(BMesh *bm,
int *r_groups_array,
int (**r_group_index)[2],
@@ -2617,6 +2114,8 @@ int BM_mesh_calc_face_groups(BMesh *bm,
const char hflag_test,
const char htype_step)
{
+ /* NOTE: almost duplicate of #BM_mesh_calc_edge_groups, keep in sync. */
+
#ifdef DEBUG
int group_index_len = 1;
#else
@@ -2755,25 +2254,6 @@ int BM_mesh_calc_face_groups(BMesh *bm,
return group_curr;
}
-/* NOTE: almost duplicate of #BM_mesh_calc_face_groups, keep in sync. */
-/**
- * Calculate isolated groups of edges with optional filtering.
- *
- * \param bm: the BMesh.
- * \param r_groups_array: Array of ints to fill in, length of bm->totedge
- * (or when hflag_test is set, the number of flagged edges).
- * \param r_group_index: index, length pairs into \a r_groups_array, size of return value
- * int pairs: (array_start, array_length).
- * \param filter_fn: Filter the edges or verts we step over (depends on \a htype_step)
- * as to which types we deal with.
- * \param user_data: Optional user data for \a filter_fn, can be NULL.
- * \param hflag_test: Optional flag to test edges,
- * use to exclude edges from the calculation, 0 for all edges.
- * \return The number of groups found.
- *
- * \note Unlike #BM_mesh_calc_face_groups there is no 'htype_step' argument,
- * since we always walk over verts.
- */
int BM_mesh_calc_edge_groups(BMesh *bm,
int *r_groups_array,
int (**r_group_index)[2],
@@ -2781,6 +2261,8 @@ int BM_mesh_calc_edge_groups(BMesh *bm,
void *user_data,
const char hflag_test)
{
+ /* NOTE: almost duplicate of #BM_mesh_calc_face_groups, keep in sync. */
+
#ifdef DEBUG
int group_index_len = 1;
#else
@@ -2892,13 +2374,6 @@ int BM_mesh_calc_edge_groups(BMesh *bm,
return group_curr;
}
-/**
- * This is an alternative to #BM_mesh_calc_edge_groups.
- *
- * While we could call this, then create vertex & face arrays,
- * it requires looping over geometry connectivity twice,
- * this slows down edit-mesh separate by loose parts, see: T70864.
- */
int BM_mesh_calc_edge_groups_as_arrays(
BMesh *bm, BMVert **verts, BMEdge **edges, BMFace **faces, int (**r_groups)[3])
{
diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h
index 021358f81ad..841549945ca 100644
--- a/source/blender/bmesh/intern/bmesh_query.h
+++ b/source/blender/bmesh/intern/bmesh_query.h
@@ -20,11 +20,24 @@
* \ingroup bmesh
*/
+/**
+ * Returns true if the vertex is used in a given face.
+ */
bool BM_vert_in_face(BMVert *v, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Compares the number of vertices in an array
+ * that appear in a given face
+ */
int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Return true if all verts are in the face.
+ */
bool BM_verts_in_face(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns whether or not a given edge is part of a given face.
+ */
bool BM_edge_in_face(const BMEdge *e, const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -35,27 +48,175 @@ BLI_INLINE bool BM_verts_in_edge(const BMVert *v1,
const BMVert *v2,
const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns edge length
+ */
float BM_edge_calc_length(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns edge length squared (for comparisons)
+ */
float BM_edge_calc_length_squared(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Utility function, since enough times we have an edge
+ * and want to access 2 connected faces.
+ *
+ * \return true when only 2 faces are found.
+ */
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb) ATTR_NONNULL();
+/**
+ * Utility function, since enough times we have an edge
+ * and want to access 2 connected loops.
+ *
+ * \return true when only 2 faces are found.
+ */
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb) ATTR_NONNULL();
BLI_INLINE BMVert *BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Given a edge and a loop (assumes the edge is manifold). returns
+ * the other faces loop, sharing the same vertex.
+ *
+ * <pre>
+ * +-------------------+
+ * | |
+ * | |
+ * |l_other <-- return |
+ * +-------------------+ <-- A manifold edge between 2 faces
+ * |l e <-- edge |
+ * |^ <-------- loop |
+ * | |
+ * +-------------------+
+ * </pre>
+ */
BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Other Loop in Face Sharing an Edge
+ *
+ * Finds the other loop that shares \a v with \a e loop in \a f.
+ * <pre>
+ * +----------+
+ * | |
+ * | f |
+ * | |
+ * +----------+ <-- return the face loop of this vertex.
+ * v --> e
+ * ^ ^ <------- These vert args define direction
+ * in the face to check.
+ * The faces loop direction is ignored.
+ * </pre>
+ *
+ * \note caller must ensure \a e is used in \a f
+ */
BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * See #BM_face_other_edge_loop This is the same functionality
+ * to be used when the edges loop is already known.
+ */
BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Other Loop in Face Sharing a Vertex
+ *
+ * Finds the other loop in a face.
+ *
+ * This function returns a loop in \a f that shares an edge with \a v
+ * The direction is defined by \a v_prev, where the return value is
+ * the loop of what would be 'v_next'
+ * <pre>
+ * +----------+ <-- return the face loop of this vertex.
+ * | |
+ * | f |
+ * | |
+ * +----------+
+ * v_prev --> v
+ * ^^^^^^ ^ <-- These vert args define direction
+ * in the face to check.
+ * The faces loop direction is ignored.
+ * </pre>
+ *
+ * \note \a v_prev and \a v _implicitly_ define an edge.
+ */
BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Return the other loop that uses this edge.
+ *
+ * In this case the loop defines the vertex,
+ * the edge passed in defines the direction to step.
+ *
+ * <pre>
+ * +----------+ <-- Return the face-loop of this vertex.
+ * | |
+ * | e | <-- This edge defines the direction.
+ * | |
+ * +----------+ <-- This loop defines the face and vertex..
+ * l
+ * </pre>
+ *
+ */
BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief Other Loop in Face Sharing a Vert
+ *
+ * Finds the other loop that shares \a v with \a e loop in \a f.
+ * <pre>
+ * +----------+ <-- return the face loop of this vertex.
+ * | |
+ * | |
+ * | |
+ * +----------+ <-- This vertex defines the direction.
+ * l v
+ * ^ <------- This loop defines both the face to search
+ * and the edge, in combination with 'v'
+ * The faces loop direction is ignored.
+ * </pre>
+ */
BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Utility function to step around a fan of loops,
+ * using an edge to mark the previous side.
+ *
+ * \note all edges must be manifold,
+ * once a non manifold edge is hit, return NULL.
+ *
+ * \code{.unparsed}
+ * ,.,-->|
+ * _,-' |
+ * ,' | (notice how 'e_step'
+ * / | and 'l' define the
+ * / | direction the arrow
+ * | return | points).
+ * | loop --> |
+ * ---------------------+---------------------
+ * ^ l --> |
+ * | |
+ * assign e_step |
+ * |
+ * begin e_step ----> |
+ * |
+ * \endcode
+ */
BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Get the first loop of a vert. Uses the same initialization code for the first loop of the
+ * iterator API
+ */
BMLoop *BM_vert_find_first_loop(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * A version of #BM_vert_find_first_loop that ignores hidden loops.
+ */
BMLoop *BM_vert_find_first_loop_visible(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Only #BMEdge.l access us needed, however when we want the first visible loop,
+ * a utility function is needed.
+ */
BMLoop *BM_edge_find_first_loop_visible(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Check if verts share a face.
+ */
bool BM_vert_pair_share_face_check(BMVert *v_a, BMVert *v_b) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
bool BM_vert_pair_share_face_check_cb(BMVert *v_a,
@@ -65,206 +226,555 @@ bool BM_vert_pair_share_face_check_cb(BMVert *v_a,
ATTR_NONNULL(1, 2, 3);
BMFace *BM_vert_pair_shared_face_cb(BMVert *v_a,
BMVert *v_b,
- const bool allow_adjacent,
+ bool allow_adjacent,
bool (*callback)(BMFace *, BMLoop *, BMLoop *, void *userdata),
void *user_data,
BMLoop **r_l_a,
BMLoop **r_l_b) ATTR_NONNULL(1, 2, 4, 6, 7);
-BMFace *BM_vert_pair_share_face_by_len(BMVert *v_a,
- BMVert *v_b,
- BMLoop **r_l_a,
- BMLoop **r_l_b,
- const bool allow_adjacent) ATTR_NONNULL();
-BMFace *BM_vert_pair_share_face_by_angle(BMVert *v_a,
- BMVert *v_b,
- BMLoop **r_l_a,
- BMLoop **r_l_b,
- const bool allow_adjacent) ATTR_NONNULL();
-
-BMFace *BM_edge_pair_share_face_by_len(BMEdge *e_a,
- BMEdge *e_b,
- BMLoop **r_l_a,
- BMLoop **r_l_b,
- const bool allow_adjacent) ATTR_NONNULL();
+/**
+ * Given 2 verts, find the smallest face they share and give back both loops.
+ */
+BMFace *BM_vert_pair_share_face_by_len(
+ BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, bool allow_adjacent) ATTR_NONNULL();
+/**
+ * Given 2 verts,
+ * find a face they share that has the lowest angle across these verts and give back both loops.
+ *
+ * This can be better than #BM_vert_pair_share_face_by_len
+ * because concave splits are ranked lowest.
+ */
+BMFace *BM_vert_pair_share_face_by_angle(
+ BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, bool allow_adjacent) ATTR_NONNULL();
+
+BMFace *BM_edge_pair_share_face_by_len(
+ BMEdge *e_a, BMEdge *e_b, BMLoop **r_l_a, BMLoop **r_l_b, bool allow_adjacent) ATTR_NONNULL();
int BM_vert_edge_count_nonwire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#define BM_vert_edge_count_is_equal(v, n) (BM_vert_edge_count_at_most(v, (n) + 1) == n)
#define BM_vert_edge_count_is_over(v, n) (BM_vert_edge_count_at_most(v, (n) + 1) == (n) + 1)
-int BM_vert_edge_count_at_most(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT
+int BM_vert_edge_count_at_most(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Returns the number of edges around this vertex.
+ */
int BM_vert_edge_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#define BM_edge_face_count_is_equal(e, n) (BM_edge_face_count_at_most(e, (n) + 1) == n)
#define BM_edge_face_count_is_over(e, n) (BM_edge_face_count_at_most(e, (n) + 1) == (n) + 1)
-int BM_edge_face_count_at_most(const BMEdge *e, const int count_max) ATTR_WARN_UNUSED_RESULT
+int BM_edge_face_count_at_most(const BMEdge *e, int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Returns the number of faces around this edge
+ */
int BM_edge_face_count(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#define BM_vert_face_count_is_equal(v, n) (BM_vert_face_count_at_most(v, (n) + 1) == n)
#define BM_vert_face_count_is_over(v, n) (BM_vert_face_count_at_most(v, (n) + 1) == (n) + 1)
int BM_vert_face_count_at_most(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Returns the number of faces around this vert
+ * length matches #BM_LOOPS_OF_VERT iterator
+ */
int BM_vert_face_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * The function takes a vertex at the center of a fan and returns the opposite edge in the fan.
+ * All edges in the fan must be manifold, otherwise return NULL.
+ *
+ * \note This could (probably) be done more efficiently.
+ */
BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Fast alternative to `(BM_vert_edge_count(v) == 2)`.
+ */
bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Fast alternative to `(BM_vert_edge_count(v) == 2)`
+ * that checks both edges connect to the same faces.
+ */
bool BM_vert_is_edge_pair_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Access a verts 2 connected edges.
+ *
+ * \return true when only 2 verts are found.
+ */
bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b);
+/**
+ * Return true if the vertex is connected to _any_ faces.
+ *
+ * same as `BM_vert_face_count(v) != 0` or `BM_vert_find_first_loop(v) == NULL`.
+ */
bool BM_vert_face_check(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Tests whether or not the vertex is part of a wire edge.
+ * (ie: has no faces attached to it)
+ */
bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * A vertex is non-manifold if it meets the following conditions:
+ * 1: Loose - (has no edges/faces incident upon it).
+ * 2: Joins two distinct regions - (two pyramids joined at the tip).
+ * 3: Is part of an edge with more than 2 faces.
+ * 4: Is part of a wire edge.
+ */
bool BM_vert_is_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * A version of #BM_vert_is_manifold
+ * which only checks if we're connected to multiple isolated regions.
+ */
bool BM_vert_is_manifold_region(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_boundary(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Check if the edge is convex or concave
+ * (depends on face winding)
+ */
bool BM_edge_is_convex(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \return true when loop customdata is contiguous.
+ */
bool BM_edge_is_contiguous_loop_cd(const BMEdge *e,
- const int cd_loop_type,
- const int cd_loop_offset) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+ int cd_loop_type,
+ int cd_loop_offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * The number of loops connected to this loop (not including disconnected regions).
+ */
int BM_loop_region_loops_count_at_most(BMLoop *l, int *r_loop_total) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
int BM_loop_region_loops_count(BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Check if the loop is convex or concave
+ * (depends on face normal)
+ */
bool BM_loop_is_convex(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Check if a point is inside the corner defined by a loop
+ * (within the 2 planes defined by the loops corner & face normal).
+ *
+ * \return signed, squared distance to the loops planes, less than 0.0 when outside.
+ */
float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Check if a point is inside the edge defined by a loop
+ * (within the plane defined by the loops edge & face normal).
+ *
+ * \return signed, squared distance to the edge plane, less than 0.0 when outside.
+ */
float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq);
-BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq);
+/**
+ * \return The previous loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
+ */
+BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, float eps_sq);
+/**
+ * \return The next loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
+ */
+BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, float eps_sq);
+/**
+ * Calculates the angle between the previous and next loops
+ * (angle at this loops face corner).
+ *
+ * \return angle in radians
+ */
float BM_loop_calc_face_angle(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief BM_loop_calc_face_normal
+ *
+ * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
+ *
+ * \param l: The loop to calculate the normal at
+ * \param r_normal: Resulting normal
+ * \return The length of the cross product (double the area).
+ */
float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
+/**
+ * #BM_loop_calc_face_normal_safe_ex with predefined sane epsilon.
+ *
+ * Since this doesn't scale based on triangle size, fixed value works well.
+ */
float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
-float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon, float r_normal[3])
+/**
+ * \brief BM_loop_calc_face_normal
+ *
+ * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
+ *
+ * \param l: The loop to calculate the normal at.
+ * \param epsilon_sq: Value to avoid numeric errors (1e-5f works well).
+ * \param r_normal: Resulting normal.
+ */
+float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, float epsilon_sq, float r_normal[3])
ATTR_NONNULL();
+/**
+ * A version of BM_loop_calc_face_normal_safe_ex which takes vertex coordinates.
+ */
float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
const float normal_fallback[3],
float const (*vertexCos)[3],
- const float epsilon_sq,
+ float epsilon_sq,
float r_normal[3]) ATTR_NONNULL();
float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
const float normal_fallback[3],
float const (*vertexCos)[3],
float r_normal[3]) ATTR_NONNULL();
+/**
+ * \brief BM_loop_calc_face_direction
+ *
+ * Calculate the direction a loop is pointing.
+ *
+ * \param l: The loop to calculate the direction at
+ * \param r_dir: Resulting direction
+ */
void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3]);
+/**
+ * \brief BM_loop_calc_face_tangent
+ *
+ * Calculate the tangent at this loop corner or fallback to the face normal on straight lines.
+ * This vector always points inward into the face.
+ *
+ * \param l: The loop to calculate the tangent at
+ * \param r_tangent: Resulting tangent
+ */
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]);
-float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT
+/**
+ * \brief BMESH EDGE/FACE ANGLE
+ *
+ * Calculates the angle between two faces.
+ * Assumes the face normals are correct.
+ *
+ * \return angle in radians
+ */
+float BM_edge_calc_face_angle_ex(const BMEdge *e, float fallback) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
float BM_edge_calc_face_angle(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_edge_calc_face_angle_signed_ex(const BMEdge *e,
- const float fallback) ATTR_WARN_UNUSED_RESULT
+/**
+ * \brief BMESH EDGE/FACE ANGLE
+ *
+ * Calculates the angle between two faces.
+ * Assumes the face normals are correct.
+ *
+ * \return angle in radians
+ */
+float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, float fallback) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief BMESH EDGE/FACE ANGLE
+ *
+ * Calculates the angle between two faces in world space.
+ * Assumes the face normals are correct.
+ *
+ * \return angle in radians
+ */
float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e,
const float imat3[3][3],
- const float fallback) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+ float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_edge_calc_face_angle_with_imat3(const BMEdge *e,
const float imat3[3][3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
float BM_edge_calc_face_angle_signed(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief BMESH EDGE/FACE TANGENT
+ *
+ * Calculate the tangent at this loop corner or fallback to the face normal on straight lines.
+ * This vector always points inward into the face.
+ *
+ * \brief BM_edge_calc_face_tangent
+ * \param e:
+ * \param e_loop: The loop to calculate the tangent at,
+ * used to get the face and winding direction.
+ * \param r_tangent: The loop corner tangent to set
+ */
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
ATTR_NONNULL();
float BM_vert_calc_edge_angle(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback) ATTR_WARN_UNUSED_RESULT
+/**
+ * \brief BMESH VERT/EDGE ANGLE
+ *
+ * Calculates the angle a verts 2 edges.
+ *
+ * \returns the angle in radians
+ */
+float BM_vert_calc_edge_angle_ex(const BMVert *v, float fallback) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \note this isn't optimal to run on an array of verts,
+ * see 'solidify_add_thickness' for a function which runs on an array.
+ */
float BM_vert_calc_shell_factor(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/* alternate version of #BM_vert_calc_shell_factor which only
+ * uses 'hflag' faces, but falls back to all if none found. */
float BM_vert_calc_shell_factor_ex(const BMVert *v,
const float no[3],
- const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+ char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \note quite an obscure function.
+ * used in bmesh operators that have a relative scale options,
+ */
float BM_vert_calc_median_tagged_edge_length(const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Returns the loop of the shortest edge in f.
+ */
BMLoop *BM_face_find_shortest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns the loop of the longest edge in f.
+ */
BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *BM_edge_exists(BMVert *v_a, BMVert *v_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns an edge sharing the same vertices as this one.
+ * This isn't an invalid state but tools should clean up these cases before
+ * returning the mesh to the user.
+ */
BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Given a set of vertices (varr), find out if
+ * there is a face with exactly those vertices
+ * (and only those vertices).
+ *
+ * \note there used to be a BM_face_exists_overlap function that checks for partial overlap.
+ */
BMFace *BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1);
+/**
+ * Check if the face has an exact duplicate (both winding directions).
+ */
BMFace *BM_face_find_double(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Given a set of vertices and edges (\a varr, \a earr), find out if
+ * all those vertices are filled in by existing faces that _only_ use those vertices.
+ *
+ * This is for use in cases where creating a face is possible but would result in
+ * many overlapping faces.
+ *
+ * An example of how this is used: when 2 tri's are selected that share an edge,
+ * pressing F-key would make a new overlapping quad (without a check like this)
+ *
+ * \a earr and \a varr can be in any order, however they _must_ form a closed loop.
+ */
bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/* same as 'BM_face_exists_multi' but built vert array from edges */
bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-BMFace *BM_face_exists_overlap(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT;
-bool BM_face_exists_overlap_subset(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+/**
+ * Given a set of vertices (varr), find out if
+ * all those vertices overlap an existing face.
+ *
+ * \note The face may contain other verts \b not in \a varr.
+ *
+ * \note Its possible there are more than one overlapping faces,
+ * in this case the first one found will be returned.
+ *
+ * \param varr: Array of unordered verts.
+ * \param len: \a varr array length.
+ * \return The face or NULL.
+ */
+BMFace *BM_face_exists_overlap(BMVert **varr, int len) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Given a set of vertices (varr), find out if
+ * there is a face that uses vertices only from this list
+ * (that the face is a subset or made from the vertices given).
+ *
+ * \param varr: Array of unordered verts.
+ * \param len: varr array length.
+ */
+bool BM_face_exists_overlap_subset(BMVert **varr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns the number of faces that are adjacent to both f1 and f2,
+ * \note Could be sped up a bit by not using iterators and by tagging
+ * faces on either side, then count the tags rather then searching.
+ */
int BM_face_share_face_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Counts the number of edges two faces share (if any)
+ */
int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Counts the number of verts two faces share (if any).
+ */
int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * same as #BM_face_share_face_count but returns a bool
+ */
bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true if the faces share an edge
+ */
bool BM_face_share_edge_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true if the faces share a vert.
+ */
bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true when 2 loops share an edge (are adjacent in the face-fan)
+ */
bool BM_loop_share_edge_check(BMLoop *l_a, BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Test if e1 shares any faces with e2
+ */
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Test if e1 shares any quad faces with e2
+ */
bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Tests to see if e1 shares a vertex with e2
+ */
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Return the shared vertex between the two edges or NULL
+ */
BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Return the Loop Shared by Edge and Vert
+ *
+ * Finds the loop used which uses \a in face loop \a l
+ *
+ * \note this function takes a loop rather than an edge
+ * so we can select the face that the loop should be from.
+ */
BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Return the Loop Shared by Face and Vertex
+ *
+ * Finds the loop used which uses \a v in face loop \a l
+ *
+ * \note currently this just uses simple loop in future may be sped up
+ * using radial vars
+ */
BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Return the Loop Shared by Face and Edge
+ *
+ * Finds the loop used which uses \a e in face loop \a l
+ *
+ * \note currently this just uses simple loop in future may be sped up
+ * using radial vars
+ */
BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2) ATTR_NONNULL();
+/**
+ * Returns the verts of an edge as used in a face
+ * if used in a face at all, otherwise just assign as used in the edge.
+ *
+ * Useful to get a deterministic winding order when calling
+ * BM_face_create_ngon() on an arbitrary array of verts,
+ * though be sure to pick an edge which has a face.
+ *
+ * \note This is in fact quite a simple check,
+ * mainly include this function so the intent is more obvious.
+ * We know these 2 verts will _always_ make up the loops edge
+ */
void BM_edge_ordered_verts_ex(const BMEdge *edge,
BMVert **r_v1,
BMVert **r_v2,
const BMLoop *edge_loop) ATTR_NONNULL();
bool BM_vert_is_all_edge_flag_test(const BMVert *v,
- const char hflag,
- const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+ char hflag,
+ bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_all_face_flag_test(const BMVert *v,
- const char hflag,
- const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+ char hflag,
+ bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_edge_is_all_face_flag_test(const BMEdge *e,
- const char hflag,
- const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+ char hflag,
+ bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag) ATTR_WARN_UNUSED_RESULT
+/* convenience functions for checking flags */
+bool BM_edge_is_any_vert_flag_test(const BMEdge *e, char hflag) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag) ATTR_WARN_UNUSED_RESULT
+bool BM_edge_is_any_face_flag_test(const BMEdge *e, char hflag) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-bool BM_face_is_any_vert_flag_test(const BMFace *f, const char hflag) ATTR_WARN_UNUSED_RESULT
+bool BM_face_is_any_vert_flag_test(const BMFace *f, char hflag) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag) ATTR_WARN_UNUSED_RESULT
+bool BM_face_is_any_edge_flag_test(const BMFace *f, char hflag) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+bool BM_edge_is_any_face_len_test(const BMEdge *e, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Use within assert's to check normals are valid.
+ */
bool BM_face_is_normal_valid(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
double BM_mesh_calc_volume(BMesh *bm, bool is_signed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Calculate isolated groups of faces with optional filtering.
+ *
+ * \param bm: the BMesh.
+ * \param r_groups_array: Array of ints to fill in, length of bm->totface
+ * (or when hflag_test is set, the number of flagged faces).
+ * \param r_group_index: index, length pairs into \a r_groups_array, size of return value
+ * int pairs: (array_start, array_length).
+ * \param filter_fn: Filter the edge-loops or vert-loops we step over (depends on \a htype_step).
+ * \param user_data: Optional user data for \a filter_fn, can be NULL.
+ * \param hflag_test: Optional flag to test faces,
+ * use to exclude faces from the calculation, 0 for all faces.
+ * \param htype_step: BM_VERT to walk over face-verts, BM_EDGE to walk over faces edges
+ * (having both set is supported too).
+ * \return The number of groups found.
+ */
int BM_mesh_calc_face_groups(BMesh *bm,
int *r_groups_array,
int (**r_group_index)[2],
BMLoopFilterFunc filter_fn,
BMLoopPairFilterFunc filter_pair_fn,
void *user_data,
- const char hflag_test,
- const char htype_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+ char hflag_test,
+ char htype_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+/**
+ * Calculate isolated groups of edges with optional filtering.
+ *
+ * \param bm: the BMesh.
+ * \param r_groups_array: Array of ints to fill in, length of `bm->totedge`
+ * (or when hflag_test is set, the number of flagged edges).
+ * \param r_group_index: index, length pairs into \a r_groups_array, size of return value
+ * int pairs: (array_start, array_length).
+ * \param filter_fn: Filter the edges or verts we step over (depends on \a htype_step)
+ * as to which types we deal with.
+ * \param user_data: Optional user data for \a filter_fn, can be NULL.
+ * \param hflag_test: Optional flag to test edges,
+ * use to exclude edges from the calculation, 0 for all edges.
+ * \return The number of groups found.
+ *
+ * \note Unlike #BM_mesh_calc_face_groups there is no 'htype_step' argument,
+ * since we always walk over verts.
+ */
int BM_mesh_calc_edge_groups(BMesh *bm,
int *r_groups_array,
int (**r_group_index)[2],
BMVertFilterFunc filter_fn,
void *user_data,
- const char hflag_test) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+ char hflag_test) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+/**
+ * This is an alternative to #BM_mesh_calc_edge_groups.
+ *
+ * While we could call this, then create vertex & face arrays,
+ * it requires looping over geometry connectivity twice,
+ * this slows down edit-mesh separate by loose parts, see: T70864.
+ */
int BM_mesh_calc_edge_groups_as_arrays(BMesh *bm,
BMVert **verts,
BMEdge **edges,
@@ -273,6 +783,6 @@ int BM_mesh_calc_edge_groups_as_arrays(BMesh *bm,
ATTR_NONNULL(1, 2, 3, 4, 5);
/* Not really any good place to put this. */
-float bmesh_subd_falloff_calc(const int falloff, float val) ATTR_WARN_UNUSED_RESULT;
+float bmesh_subd_falloff_calc(int falloff, float val) ATTR_WARN_UNUSED_RESULT;
#include "bmesh_query_inline.h"
diff --git a/source/blender/bmesh/intern/bmesh_query_uv.c b/source/blender/bmesh/intern/bmesh_query_uv.c
index f9b87e4e71c..f069613f5b3 100644
--- a/source/blender/bmesh/intern/bmesh_query_uv.c
+++ b/source/blender/bmesh/intern/bmesh_query_uv.c
@@ -48,14 +48,6 @@ static void uv_aspect(const BMLoop *l,
*/
#define UV_ASPECT(l, r_uv) uv_aspect(l, aspect, cd_loop_uv_offset, r_uv)
-/**
- * Computes the UV center of a face, using the mean average weighted by edge length.
- *
- * See #BM_face_calc_center_median_weighted for matching spatial functionality.
- *
- * \param aspect: Calculate the center scaling by these values, and finally dividing.
- * Since correct weighting depends on having the correct aspect.
- */
void BM_face_uv_calc_center_median_weighted(const BMFace *f,
const float aspect[2],
const int cd_loop_uv_offset,
@@ -109,9 +101,6 @@ void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset,
mul_v2_fl(r_cent, 1.0f / (float)f->len);
}
-/**
- * Calculate the UV cross product (use the sign to check the winding).
- */
float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset)
{
float(*uvs)[2] = BLI_array_alloca(uvs, f->len);
@@ -148,9 +137,6 @@ void BM_face_uv_transform(BMFace *f, const float matrix[2][2], const int cd_loop
} while ((l_iter = l_iter->next) != l_first);
}
-/**
- * Check if two loops that share an edge also have the same UV coordinates.
- */
bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
{
BLI_assert(l_a->e == l_b->e);
@@ -165,9 +151,6 @@ bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_
equals_v2v2(luv_a_next->uv, luv_b_next->uv));
}
-/**
- * Check if two loops that share a vertex also have the same UV coordinates.
- */
bool BM_loop_uv_share_vert_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
{
BLI_assert(l_a->v == l_b->v);
@@ -179,9 +162,6 @@ bool BM_loop_uv_share_vert_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_
return true;
}
-/**
- * Check if two loops that share a vertex also have the same UV coordinates.
- */
bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
{
BLI_assert(l_a->v == l_b->v);
@@ -204,9 +184,6 @@ bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int
return true;
}
-/**
- * Check if the point is inside the UV face.
- */
bool BM_face_uv_point_inside_test(const BMFace *f, const float co[2], const int cd_loop_uv_offset)
{
float(*projverts)[2] = BLI_array_alloca(projverts, f->len);
diff --git a/source/blender/bmesh/intern/bmesh_query_uv.h b/source/blender/bmesh/intern/bmesh_query_uv.h
index 850b27d3894..4399f8b4c4d 100644
--- a/source/blender/bmesh/intern/bmesh_query_uv.h
+++ b/source/blender/bmesh/intern/bmesh_query_uv.h
@@ -21,45 +21,64 @@
*/
float BM_loop_uv_calc_edge_length_squared(const BMLoop *l,
- const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
+ int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-float BM_loop_uv_calc_edge_length(const BMLoop *l,
- const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
+float BM_loop_uv_calc_edge_length(const BMLoop *l, int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Computes the UV center of a face, using the mean average weighted by edge length.
+ *
+ * See #BM_face_calc_center_median_weighted for matching spatial functionality.
+ *
+ * \param aspect: Calculate the center scaling by these values, and finally dividing.
+ * Since correct weighting depends on having the correct aspect.
+ */
void BM_face_uv_calc_center_median_weighted(const BMFace *f,
const float aspect[2],
- const int cd_loop_uv_offset,
+ int cd_loop_uv_offset,
float r_cent[2]) ATTR_NONNULL();
-void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset, float r_cent[2])
+void BM_face_uv_calc_center_median(const BMFace *f, int cd_loop_uv_offset, float r_cent[2])
ATTR_NONNULL();
-float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
+/**
+ * Calculate the UV cross product (use the sign to check the winding).
+ */
+float BM_face_uv_calc_cross(const BMFace *f, int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-void BM_face_uv_minmax(const BMFace *f, float min[2], float max[2], const int cd_loop_uv_offset);
-void BM_face_uv_transform(BMFace *f, const float matrix[2][2], const int cd_loop_uv_offset);
+void BM_face_uv_minmax(const BMFace *f, float min[2], float max[2], int cd_loop_uv_offset);
+void BM_face_uv_transform(BMFace *f, const float matrix[2][2], int cd_loop_uv_offset);
bool BM_loop_uv_share_edge_check_with_limit(BMLoop *l_a,
BMLoop *l_b,
const float limit[2],
- const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
+ int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Check if two loops that share an edge also have the same UV coordinates.
+ */
bool BM_loop_uv_share_edge_check(BMLoop *l_a,
BMLoop *l_b,
- const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+ int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
+/**
+ * Check if two loops that share a vertex also have the same UV coordinates.
+ */
+bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, int cd_loop_uv_offset)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Check if two loops that share a vertex also have the same UV coordinates.
+ */
bool BM_loop_uv_share_vert_check(BMLoop *l_a,
BMLoop *l_b,
- const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+ int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Check if the point is inside the UV face.
+ */
bool BM_face_uv_point_inside_test(const BMFace *f,
const float co[2],
- const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+ int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c
index d5d72cd4ba3..08b0920c115 100644
--- a/source/blender/bmesh/intern/bmesh_structure.c
+++ b/source/blender/bmesh/intern/bmesh_structure.c
@@ -47,11 +47,6 @@ void bmesh_disk_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
}
}
-/**
- * Handles all connected data, use with care.
- *
- * Assumes caller has setup correct state before the swap is done.
- */
void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
{
/* swap out loops */
@@ -86,7 +81,8 @@ void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src)
/**
* \section bm_cycles BMesh Cycles
- * (this is somewhat outdate, though bits of its API are still used) - joeedh
+ *
+ * NOTE(@joeedh): this is somewhat outdated, though bits of its API are still used.
*
* Cycles are circular doubly linked lists that form the basis of adjacency
* information in the BME modeler. Full adjacency relations can be derived
@@ -267,14 +263,6 @@ bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
return true;
}
-/**
- * \brief DISK COUNT FACE VERT
- *
- * Counts the number of loop users
- * for this vertex. Note that this is
- * equivalent to counting the number of
- * faces incident upon this vertex
- */
int bmesh_disk_facevert_count(const BMVert *v)
{
/* is there an edge on this vert at all */
@@ -314,14 +302,6 @@ int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max)
return count;
}
-/**
- * \brief FIND FIRST FACE EDGE
- *
- * Finds the first edge in a vertices
- * Disk cycle that has one of this
- * vert's loops attached
- * to it.
- */
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v)
{
const BMEdge *e_iter = e;
@@ -333,11 +313,6 @@ BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v)
return NULL;
}
-/**
- * Special case for BM_LOOPS_OF_VERT & BM_FACES_OF_VERT, avoids 2x calls.
- *
- * The returned BMLoop.e matches the result of #bmesh_disk_faceedge_find_first
- */
BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
{
const BMEdge *e_iter = e;
@@ -349,9 +324,6 @@ BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
return NULL;
}
-/**
- * A version of #bmesh_disk_faceloop_find_first that ignores hidden faces.
- */
BMLoop *bmesh_disk_faceloop_find_first_visible(const BMEdge *e, const BMVert *v)
{
const BMEdge *e_iter = e;
@@ -383,7 +355,6 @@ BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v)
return (BMEdge *)e;
}
-/*****radial cycle functions, e.g. loops surrounding edges**** */
bool bmesh_radial_validate(int radlen, BMLoop *l)
{
BMLoop *l_iter = l;
@@ -441,14 +412,6 @@ void bmesh_radial_loop_append(BMEdge *e, BMLoop *l)
l->e = e;
}
-/**
- * \brief BMESH RADIAL REMOVE LOOP
- *
- * Removes a loop from an radial cycle. If edge e is non-NULL
- * it should contain the radial cycle, and it will also get
- * updated (in the case that the edge's link into the radial
- * cycle was the loop which is being removed from the cycle).
- */
void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l)
{
/* if e is non-NULL, l must be in the radial cycle of e */
@@ -479,10 +442,6 @@ void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l)
l->e = NULL;
}
-/**
- * A version of #bmesh_radial_loop_remove which only performs the radial unlink,
- * leaving the edge untouched.
- */
void bmesh_radial_loop_unlink(BMLoop *l)
{
if (l->radial_next != l) {
@@ -496,12 +455,6 @@ void bmesh_radial_loop_unlink(BMLoop *l)
l->e = NULL;
}
-/**
- * \brief BME RADIAL FIND FIRST FACE VERT
- *
- * Finds the first loop of v around radial
- * cycle
- */
BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v)
{
const BMLoop *l_iter;
@@ -552,12 +505,6 @@ int bmesh_radial_length(const BMLoop *l)
return i;
}
-/**
- * \brief RADIAL COUNT FACE VERT
- *
- * Returns the number of times a vertex appears
- * in a radial cycle
- */
int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v)
{
const BMLoop *l_iter;
@@ -589,11 +536,6 @@ int bmesh_radial_facevert_count_at_most(const BMLoop *l, const BMVert *v, const
return count;
}
-/**
- * \brief RADIAL CHECK FACE VERT
- *
- * Quicker check for `bmesh_radial_facevert_count(...) != 0`.
- */
bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v)
{
const BMLoop *l_iter;
@@ -607,7 +549,6 @@ bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v)
return false;
}
-/*****loop cycle functions, e.g. loops surrounding a face**** */
bool bmesh_loop_validate(BMFace *f)
{
int i;
diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h
index ca51a9c39de..8a9c1f114f9 100644
--- a/source/blender/bmesh/intern/bmesh_structure.h
+++ b/source/blender/bmesh/intern/bmesh_structure.h
@@ -31,6 +31,7 @@
*/
/* LOOP CYCLE MANAGEMENT */
+/*****loop cycle functions, e.g. loops surrounding a face**** */
bool bmesh_loop_validate(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* DISK CYCLE MANAGEMENT */
@@ -46,13 +47,37 @@ BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_W
ATTR_NONNULL();
BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT
+int bmesh_disk_facevert_count_at_most(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief DISK COUNT FACE VERT
+ *
+ * Counts the number of loop users
+ * for this vertex. Note that this is
+ * equivalent to counting the number of
+ * faces incident upon this vertex
+ */
int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief FIND FIRST FACE EDGE
+ *
+ * Finds the first edge in a vertices
+ * Disk cycle that has one of this
+ * vert's loops attached
+ * to it.
+ */
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Special case for BM_LOOPS_OF_VERT & BM_FACES_OF_VERT, avoids 2x calls.
+ *
+ * The returned BMLoop.e matches the result of #bmesh_disk_faceedge_find_first
+ */
BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * A version of #bmesh_disk_faceloop_find_first that ignores hidden faces.
+ */
BMLoop *bmesh_disk_faceloop_find_first_visible(const BMEdge *e,
const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -61,7 +86,19 @@ BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WAR
/* RADIAL CYCLE MANAGEMENT */
void bmesh_radial_loop_append(BMEdge *e, BMLoop *l) ATTR_NONNULL();
+/**
+ * \brief BMESH RADIAL REMOVE LOOP
+ *
+ * Removes a loop from an radial cycle. If edge e is non-NULL
+ * it should contain the radial cycle, and it will also get
+ * updated (in the case that the edge's link into the radial
+ * cycle was the loop which is being removed from the cycle).
+ */
void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l) ATTR_NONNULL();
+/**
+ * A version of #bmesh_radial_loop_remove which only performs the radial unlink,
+ * leaving the edge untouched.
+ */
void bmesh_radial_loop_unlink(BMLoop *l) ATTR_NONNULL();
/* NOTE:
* bmesh_radial_loop_next(BMLoop *l) / prev.
@@ -69,22 +106,44 @@ void bmesh_radial_loop_unlink(BMLoop *l) ATTR_NONNULL();
int bmesh_radial_facevert_count_at_most(const BMLoop *l,
const BMVert *v,
- const int count_max) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+ int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief RADIAL COUNT FACE VERT
+ *
+ * Returns the number of times a vertex appears
+ * in a radial cycle
+ */
int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief RADIAL CHECK FACE VERT
+ *
+ * Quicker check for `bmesh_radial_facevert_count(...) != 0`.
+ */
bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief BME RADIAL FIND FIRST FACE VERT
+ *
+ * Finds the first loop of v around radial
+ * cycle
+ */
BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
BMLoop *bmesh_radial_faceloop_find_next(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
BMLoop *bmesh_radial_faceloop_find_vert(const BMFace *f, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/*****radial cycle functions, e.g. loops surrounding edges**** */
bool bmesh_radial_validate(int radlen, BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* EDGE UTILITIES */
void bmesh_disk_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
+/**
+ * Handles all connected data, use with care.
+ *
+ * Assumes caller has setup correct state before the swap is done.
+ */
void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
BMEdge *bmesh_disk_edge_exists(const BMVert *v1, const BMVert *v2) ATTR_WARN_UNUSED_RESULT
diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c
index 8bdf205babd..0e13c4c8128 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.c
+++ b/source/blender/bmesh/intern/bmesh_walkers.c
@@ -31,22 +31,21 @@
#include "bmesh_walkers_private.h"
/**
- * - joeedh -
- * design notes:
+ * NOTE(@joeedh): Details on design.
*
- * original design: walkers directly emulation recursive functions.
- * functions save their state onto a worklist, and also add new states
- * to implement recursive or looping behavior. generally only one
- * state push per call with a specific state is desired.
+ * Original design: walkers directly emulation recursive functions.
+ * functions save their state onto a #BMWalker.worklist, and also add new states
+ * to implement recursive or looping behavior.
+ * Generally only one state push per call with a specific state is desired.
*
* basic design pattern: the walker step function goes through its
* list of possible choices for recursion, and recurses (by pushing a new state)
- * using the first non-visited one. This choice is the flagged as visited using
- * the ghash. each step may push multiple new states onto the worklist at once.
+ * using the first non-visited one. This choice is the flagged as visited using the #GHash.
+ * Each step may push multiple new states onto the #BMWalker.worklist at once.
*
* - Walkers use tool flags, not header flags.
- * - Walkers now use ghash for storing visited elements,
- * rather than stealing flags. ghash can be rewritten
+ * - Walkers now use #GHash for storing visited elements,
+ * rather than stealing flags. #GHash can be rewritten
* to be faster if necessary, in the far future :) .
* - tools should ALWAYS have necessary error handling
* for if walkers fail.
@@ -61,12 +60,6 @@ void *BMW_begin(BMWalker *walker, void *start)
return BMW_current_state(walker) ? walker->step(walker) : NULL;
}
-/**
- * \brief Init Walker
- *
- * Allocates and returns a new mesh walker of a given type.
- * The elements visited are filtered by the bitmask 'searchmask'.
- */
void BMW_init(BMWalker *walker,
BMesh *bm,
int type,
@@ -125,11 +118,6 @@ void BMW_init(BMWalker *walker,
BLI_listbase_clear(&walker->states);
}
-/**
- * \brief End Walker
- *
- * Frees a walker's worklist.
- */
void BMW_end(BMWalker *walker)
{
BLI_mempool_destroy(walker->worklist);
@@ -137,9 +125,6 @@ void BMW_end(BMWalker *walker)
BLI_gset_free(walker->visit_set_alt, NULL);
}
-/**
- * \brief Step Walker
- */
void *BMW_step(BMWalker *walker)
{
BMHeader *head;
@@ -149,22 +134,11 @@ void *BMW_step(BMWalker *walker)
return head;
}
-/**
- * \brief Walker Current Depth
- *
- * Returns the current depth of the walker.
- */
-
int BMW_current_depth(BMWalker *walker)
{
return walker->depth;
}
-/**
- * \brief Main Walking Function
- *
- * Steps a mesh walker forward by one element
- */
void *BMW_walk(BMWalker *walker)
{
void *current = NULL;
@@ -178,13 +152,6 @@ void *BMW_walk(BMWalker *walker)
return NULL;
}
-/**
- * \brief Current Walker State
- *
- * Returns the first state from the walker state
- * worklist. This state is the next in the
- * worklist for processing.
- */
void *BMW_current_state(BMWalker *walker)
{
BMwGenericWalker *currentstate = walker->states.first;
@@ -204,12 +171,6 @@ void *BMW_current_state(BMWalker *walker)
return currentstate;
}
-/**
- * \brief Remove Current Walker State
- *
- * Remove and free an item from the end of the walker state
- * worklist.
- */
void BMW_state_remove(BMWalker *walker)
{
void *oldstate;
@@ -218,15 +179,6 @@ void BMW_state_remove(BMWalker *walker)
BLI_mempool_free(walker->worklist, oldstate);
}
-/**
- * \brief Add a new Walker State
- *
- * Allocate a new empty state and put it on the worklist.
- * A pointer to the new state is returned so that the caller
- * can fill in the state data. The new state will be inserted
- * at the front for depth-first walks, and at the end for
- * breadth-first walks.
- */
void *BMW_state_add(BMWalker *walker)
{
BMwGenericWalker *newstate;
@@ -246,12 +198,6 @@ void *BMW_state_add(BMWalker *walker)
return newstate;
}
-/**
- * \brief Reset Walker
- *
- * Frees all states from the worklist, resetting the walker
- * for reuse in a new walk.
- */
void BMW_reset(BMWalker *walker)
{
while (BMW_current_state(walker)) {
diff --git a/source/blender/bmesh/intern/bmesh_walkers.h b/source/blender/bmesh/intern/bmesh_walkers.h
index d0348aa11dc..f36f77ce009 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.h
+++ b/source/blender/bmesh/intern/bmesh_walkers.h
@@ -67,6 +67,12 @@ typedef struct BMWalker {
/* define to make BMW_init more clear */
#define BMW_MASK_NOP 0
+/**
+ * \brief Init Walker
+ *
+ * Allocates and returns a new mesh walker of a given type.
+ * The elements visited are filtered by the bitmask 'searchmask'.
+ */
void BMW_init(struct BMWalker *walker,
BMesh *bm,
int type,
@@ -76,15 +82,61 @@ void BMW_init(struct BMWalker *walker,
BMWFlag flag,
int layer);
void *BMW_begin(BMWalker *walker, void *start);
+/**
+ * \brief Step Walker
+ */
void *BMW_step(struct BMWalker *walker);
+/**
+ * \brief End Walker
+ *
+ * Frees a walker's worklist.
+ */
void BMW_end(struct BMWalker *walker);
+/**
+ * \brief Walker Current Depth
+ *
+ * Returns the current depth of the walker.
+ */
int BMW_current_depth(BMWalker *walker);
/* These are used by custom walkers. */
+/**
+ * \brief Current Walker State
+ *
+ * Returns the first state from the walker state
+ * worklist. This state is the next in the
+ * worklist for processing.
+ */
void *BMW_current_state(BMWalker *walker);
+/**
+ * \brief Add a new Walker State
+ *
+ * Allocate a new empty state and put it on the worklist.
+ * A pointer to the new state is returned so that the caller
+ * can fill in the state data. The new state will be inserted
+ * at the front for depth-first walks, and at the end for
+ * breadth-first walks.
+ */
void *BMW_state_add(BMWalker *walker);
+/**
+ * \brief Remove Current Walker State
+ *
+ * Remove and free an item from the end of the walker state
+ * worklist.
+ */
void BMW_state_remove(BMWalker *walker);
+/**
+ * \brief Main Walking Function
+ *
+ * Steps a mesh walker forward by one element
+ */
void *BMW_walk(BMWalker *walker);
+/**
+ * \brief Reset Walker
+ *
+ * Frees all states from the worklist, resetting the walker
+ * for reuse in a new walk.
+ */
void BMW_reset(BMWalker *walker);
#define BMW_ITER(ele, walker, data) \
diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c
index 7931e953295..15d3a6a6a53 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_impl.c
+++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c
@@ -94,6 +94,7 @@ static bool bmw_edge_is_wire(const BMWalker *walker, const BMEdge *e)
}
return BM_edge_is_wire(e);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -107,6 +108,7 @@ static bool bmw_edge_is_wire(const BMWalker *walker, const BMEdge *e)
*
* \todo Add restriction flag/callback for wire edges.
* \{ */
+
static void bmw_VertShellWalker_visitEdge(BMWalker *walker, BMEdge *e)
{
BMwShellWalker *shellWalk = NULL;
@@ -236,6 +238,7 @@ static void *bmw_VertShellWalker_step(BMWalker *walker)
*
* \note this is mainly useful to loop over a shell delimited by edges.
* \{ */
+
static void bmw_LoopShellWalker_visitLoop(BMWalker *walker, BMLoop *l)
{
BMwLoopShellWalker *shellWalk = NULL;
@@ -509,6 +512,7 @@ static void *bmw_LoopShellWireWalker_step(BMWalker *walker)
* Starts at an edge on the mesh and walks over the 'shell' it belongs
* to via visiting connected faces.
* \{ */
+
static void bmw_FaceShellWalker_visitEdge(BMWalker *walker, BMEdge *e)
{
BMwShellWalker *shellWalk = NULL;
@@ -564,6 +568,7 @@ static void *bmw_FaceShellWalker_step(BMWalker *walker)
return e;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -573,6 +578,7 @@ static void *bmw_FaceShellWalker_step(BMWalker *walker)
*
* Walk from a vertex to all connected vertices.
* \{ */
+
static void bmw_ConnectedVertexWalker_visitVertex(BMWalker *walker, BMVert *v)
{
BMwConnectedVertexWalker *vwalk;
@@ -640,6 +646,7 @@ static void *bmw_ConnectedVertexWalker_step(BMWalker *walker)
*
* \todo Add restriction flag/callback for wire edges.
* \{ */
+
static void bmw_IslandboundWalker_begin(BMWalker *walker, void *data)
{
BMLoop *l = data;
@@ -735,6 +742,7 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
*
* \todo Add restriction flag/callback for wire edges.
* \{ */
+
static void bmw_IslandWalker_begin(BMWalker *walker, void *data)
{
BMwIslandWalker *iwalk = NULL;
@@ -1299,6 +1307,7 @@ static void *bmw_FaceLoopWalker_step(BMWalker *walker)
* Conditions for starting and stepping the edge ring have been
* tuned to match behavior users expect (dating back to v2.4x).
* \{ */
+
static void bmw_EdgeringWalker_begin(BMWalker *walker, void *data)
{
BMwEdgeringWalker *lwalk, owalk, *owalk_pt;
@@ -1850,6 +1859,12 @@ static BMWalker bmw_ConnectedVertexWalker_Type = {
BM_VERT, /* Valid restrict masks. */
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name All Walker Types
+ * \{ */
+
BMWalker *bm_walker_types[] = {
&bmw_VertShellWalker_Type, /* #BMW_VERT_SHELL */
&bmw_LoopShellWalker_Type, /* #BMW_LOOP_SHELL */
@@ -1868,3 +1883,5 @@ BMWalker *bm_walker_types[] = {
};
const int bm_totwalkers = ARRAY_SIZE(bm_walker_types);
+
+/** \} */
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index 660633e8a0f..29fd8d9094b 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -120,19 +120,18 @@ typedef struct PathLinkState {
float co_prev[3];
} PathLinkState;
-/**
- * \name Min Dist Dir Util
+/* -------------------------------------------------------------------- */
+/** \name Min Dist Dir Util
*
* Simply getting the closest intersecting vert/edge is _not_ good enough. see T43792
* we need to get the closest in both directions since the absolute closest may be a dead-end.
*
* Logic is simple:
*
- * - first intersection, store the direction.
- * - successive intersections will update the first distance if its aligned with the first hit.
+ * - First intersection, store the direction.
+ * - Successive intersections will update the first distance if its aligned with the first hit.
* otherwise update the opposite distance.
- * - caller stores best outcome in both directions.
- *
+ * - Caller stores best outcome in both directions.
* \{ */
typedef struct MinDistDir {
diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c
index a740e4d66e8..6bb2830c71b 100644
--- a/source/blender/bmesh/operators/bmo_create.c
+++ b/source/blender/bmesh/operators/bmo_create.c
@@ -17,7 +17,7 @@
/** \file
* \ingroup bmesh
*
- * Create faces or edges (Fkey by default).
+ * Create faces or edges (F-key by default).
*/
#include "MEM_guardedalloc.h"
@@ -31,12 +31,11 @@
#define ELE_NEW 1
#define ELE_OUT 2
-/* This is what runs when pressing the F key
- * doing the best thing here isn't always easy create vs dissolve, its nice to support
- * but it _really_ gives issues we might have to not call dissolve. - campbell
- */
void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
{
+ /* NOTE(@campbellbarton): doing the best thing here isn't always easy create vs dissolve,
+ * its nice to support but it _really_ gives issues we might have to not call dissolve. */
+
BMOIter oiter;
BMHeader *h;
int totv = 0, tote = 0, totf = 0;
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index efba0ec99ec..82d277ec3af 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -233,8 +233,8 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
* This could optionally do a partial merge, where some faces are joined. */
/* Prevent these faces from being removed. */
- for (i = 0; i < faces_len; i++) {
- BMO_face_flag_disable(bm, faces[i], FACE_ORIG);
+ for (int j = 0; j < faces_len; j++) {
+ BMO_face_flag_disable(bm, faces[j], FACE_ORIG);
}
}
}
@@ -488,7 +488,6 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
/* done with cleanup */
}
-/* Limited Dissolve */
void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op)
{
BMOpSlot *einput = BMO_slot_get(op->slots_in, "edges");
diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c
index da4567d947b..f366aede2ab 100644
--- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c
+++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c
@@ -85,7 +85,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op)
}
if (ok) {
- /* NOTE: in the case of multiple loops, this over-allocs (which is fine). */
+ /* NOTE: in the case of multiple loops, this over-allocates (which is fine). */
BMVert **f_verts = MEM_mallocN(sizeof(*verts) * totv, __func__);
BMIter eiter;
diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c
index 740815691cc..f6cdb18f982 100644
--- a/source/blender/bmesh/operators/bmo_hull.c
+++ b/source/blender/bmesh/operators/bmo_hull.c
@@ -30,7 +30,7 @@
# include "RBI_hull_api.h"
-/* XXX: using 128 for totelem and pchunk of mempool, no idea what good
+/* XXX: using 128 for totelem and `pchunk` of `mempool`, no idea what good
* values would be though */
# include "bmesh.h"
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index d8047499780..69404c8ba0e 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -787,14 +787,6 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
}
}
-/**
- * Fills first available UV-map with grid-like UV's for all faces with `oflag` set.
- *
- * \param bm: The BMesh to operate on
- * \param x_segments: The x-resolution of the grid
- * \param y_segments: The y-resolution of the grid
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_grid(BMesh *bm,
const uint x_segments,
const uint y_segments,
@@ -1130,12 +1122,6 @@ static void bm_mesh_calc_uvs_sphere_face(BMFace *f, const int cd_loop_uv_offset)
}
}
-/**
- * Fills first available UV-map with spherical projected UVs for all faces with `oflag` set.
- *
- * \param bm: The BMesh to operate on
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag, const int cd_loop_uv_offset)
{
BMFace *f;
@@ -1343,14 +1329,6 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
-/**
- * Fills first available UV-map with 2D projected UVs for all faces with `oflag` set.
- *
- * \param bm: The BMesh to operate on.
- * \param mat: The transform matrix applied to the created circle.
- * \param radius: The size of the circle.
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_circle(
BMesh *bm, float mat[4][4], const float radius, const short oflag, const int cd_loop_uv_offset)
{
@@ -1534,17 +1512,6 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
-/**
- * Fills first available UV-map with cylinder/cone-like UVs for all faces with `oflag` set.
- *
- * \param bm: The BMesh to operate on.
- * \param mat: The transform matrix applied to the created cone/cylinder.
- * \param radius_top: The size of the top end of the cone/cylinder.
- * \param radius_bottom: The size of the bottom end of the cone/cylinder.
- * \param segments: The number of subdivisions in the sides of the cone/cylinder.
- * \param cap_ends: Whether the ends of the cone/cylinder are filled or not.
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_cone(BMesh *bm,
float mat[4][4],
const float radius_top,
@@ -1710,15 +1677,6 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
-/**
- * Fills first available UV-map with cube-like UVs for all faces with `oflag` set.
- *
- * \note Expects tagged faces to be six quads.
- * \note Caller must order faces for correct alignment.
- *
- * \param bm: The BMesh to operate on.
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag)
{
BMFace *f;
diff --git a/source/blender/bmesh/operators/bmo_split_edges.c b/source/blender/bmesh/operators/bmo_split_edges.c
index d030a6e11b0..5a00094ef45 100644
--- a/source/blender/bmesh/operators/bmo_split_edges.c
+++ b/source/blender/bmesh/operators/bmo_split_edges.c
@@ -27,7 +27,6 @@
#include "intern/bmesh_operators_private.h" /* own include */
-/* keep this operator fast, its used in a modifier */
void bmo_split_edges_exec(BMesh *bm, BMOperator *op)
{
const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts");
diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c
index 7311c94a0d8..05837ae2a0e 100644
--- a/source/blender/bmesh/operators/bmo_subdivide.c
+++ b/source/blender/bmesh/operators/bmo_subdivide.c
@@ -1187,12 +1187,14 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
vlen = BLI_array_len(loops);
/* find the boundary of one of the split edges */
- for (a = 1; a < vlen; a++) {
- if (!BMO_vert_flag_test(bm, loops[a - 1]->v, ELE_INNER) &&
+ for (a = 0; a < vlen; a++) {
+ if (!BMO_vert_flag_test(bm, loops[a ? (a - 1) : (vlen - 1)]->v, ELE_INNER) &&
BMO_vert_flag_test(bm, loops[a]->v, ELE_INNER)) {
break;
}
}
+ /* Failure to break means there is an internal error. */
+ BLI_assert(a < vlen);
if (BMO_vert_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) {
b = (a + numcuts + 1) % vlen;
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
index 6a80f360f59..7f0bfc5e2c9 100644
--- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c
+++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
@@ -1061,9 +1061,10 @@ static bool bm_edge_rim_test_cb(BMEdge *e, void *bm_v)
return BMO_edge_flag_test_bool(bm, e, EDGE_RIM);
}
-/* keep this operator fast, its used in a modifier */
void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op)
{
+ /* NOTE: keep this operator fast, its used in a modifier. */
+
ListBase eloops_rim = {NULL};
BMOIter siter;
BMEdge *e;
diff --git a/source/blender/bmesh/operators/bmo_unsubdivide.c b/source/blender/bmesh/operators/bmo_unsubdivide.c
index c5de6df34a7..f11e359e962 100644
--- a/source/blender/bmesh/operators/bmo_unsubdivide.c
+++ b/source/blender/bmesh/operators/bmo_unsubdivide.c
@@ -29,11 +29,10 @@
#include "intern/bmesh_operators_private.h" /* own include */
-/* - BMVert.flag & BM_ELEM_TAG: shows we touched this vert
- * - BMVert.index == -1: shows we will remove this vert
- */
void bmo_unsubdivide_exec(BMesh *bm, BMOperator *op)
{
+ /* - `BMVert.flag & BM_ELEM_TAG`: Shows we touched this vert.
+ * - `BMVert.index == -1`: Shows we will remove this vert. */
BMVert *v;
BMIter iter;
diff --git a/source/blender/bmesh/tests/bmesh_core_test.cc b/source/blender/bmesh/tests/bmesh_core_test.cc
index 202d16b09e3..3d6fabcbc2f 100644
--- a/source/blender/bmesh/tests/bmesh_core_test.cc
+++ b/source/blender/bmesh/tests/bmesh_core_test.cc
@@ -10,9 +10,9 @@ TEST(bmesh_core, BMVertCreate)
BMVert *bv1, *bv2, *bv3;
const float co1[3] = {1.0f, 2.0f, 0.0f};
- BMeshCreateParams bm_params;
- bm_params.use_toolflags = true;
- bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_params);
+ BMeshCreateParams bmesh_create_params{};
+ bmesh_create_params.use_toolflags = true;
+ bm = BM_mesh_create(&bm_mesh_allocsize_default, &bmesh_create_params);
EXPECT_EQ(bm->totvert, 0);
/* make a custom layer so we can see if it is copied properly */
BM_data_layer_add(bm, &bm->vdata, CD_PROP_FLOAT);
diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c
index d5c5063f2cb..266b1c0cea8 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.c
+++ b/source/blender/bmesh/tools/bmesh_beautify.c
@@ -49,8 +49,17 @@
/* GSet for edge rotation */
typedef struct EdRotState {
- int v1, v2; /* edge vert, small -> large */
- int f1, f2; /* face vert, small -> large */
+ /**
+ * Edge vert indices (ordered small -> large).
+ */
+ int v_pair[2];
+ /**
+ * Face vert indices (small -> large).
+ *
+ * Each face-vertex points to a connected triangles vertex
+ * that's isn't part of the edge defined by `v_pair`.
+ */
+ int f_pair[2];
} EdRotState;
#if 0
@@ -58,7 +67,7 @@ typedef struct EdRotState {
static uint erot_gsetutil_hash(const void *ptr)
{
const EdRotState *e_state = (const EdRotState *)ptr;
- return BLI_ghashutil_inthash_v4(&e_state->v1);
+ return BLI_ghashutil_inthash_v4(&e_state->v_pair[0]);
}
#endif
#if 0
@@ -66,33 +75,31 @@ static int erot_gsetutil_cmp(const void *a, const void *b)
{
const EdRotState *e_state_a = (const EdRotState *)a;
const EdRotState *e_state_b = (const EdRotState *)b;
- if (e_state_a->v1 < e_state_b->v1) {
+ if (e_state_a->v_pair[0] < e_state_b->v_pair[0]) {
return -1;
}
- else if (e_state_a->v1 > e_state_b->v1) {
+ if (e_state_a->v_pair[0] > e_state_b->v_pair[0]) {
return 1;
}
- else if (e_state_a->v2 < e_state_b->v2) {
+ if (e_state_a->v_pair[1] < e_state_b->v_pair[1]) {
return -1;
}
- else if (e_state_a->v2 > e_state_b->v2) {
+ if (e_state_a->v_pair[1] > e_state_b->v_pair[1]) {
return 1;
}
- else if (e_state_a->f1 < e_state_b->f1) {
+ if (e_state_a->f_pair[0] < e_state_b->f_pair[0]) {
return -1;
}
- else if (e_state_a->f1 > e_state_b->f1) {
+ if (e_state_a->f_pair[0] > e_state_b->f_pair[0]) {
return 1;
}
- else if (e_state_a->f2 < e_state_b->f2) {
+ if (e_state_a->f_pair[1] < e_state_b->f_pair[1]) {
return -1;
}
- else if (e_state_a->f2 > e_state_b->f2) {
+ if (e_state_a->f_pair[1] > e_state_b->f_pair[1]) {
return 1;
}
- else {
- return 0;
- }
+ return 0;
}
#endif
static GSet *erot_gset_new(void)
@@ -127,12 +134,12 @@ static void erot_state_ex(const BMEdge *e, int v_index[2], int f_index[2])
static void erot_state_current(const BMEdge *e, EdRotState *e_state)
{
- erot_state_ex(e, &e_state->v1, &e_state->f1);
+ erot_state_ex(e, e_state->v_pair, e_state->f_pair);
}
static void erot_state_alternate(const BMEdge *e, EdRotState *e_state)
{
- erot_state_ex(e, &e_state->f1, &e_state->v1);
+ erot_state_ex(e, e_state->f_pair, e_state->v_pair);
}
/* -------------------------------------------------------------------- */
@@ -235,12 +242,6 @@ static float bm_edge_calc_rotate_beauty__angle(const float v1[3],
return FLT_MAX;
}
-/**
- * Assuming we have 2 triangles sharing an edge (2 - 4),
- * check if the edge running from (1 - 3) gives better results.
- *
- * \return (negative number means the edge can be rotated, lager == better).
- */
float BM_verts_calc_rotate_beauty(const BMVert *v1,
const BMVert *v2,
const BMVert *v3,
@@ -374,9 +375,6 @@ static void bm_edge_update_beauty_cost(BMEdge *e,
/* -------------------------------------------------------------------- */
/* Beautify Fill */
-/**
- * \note This function sets the edge indices to invalid values.
- */
void BM_mesh_beautify_fill(BMesh *bm,
BMEdge **edge_array,
const int edge_array_len,
diff --git a/source/blender/bmesh/tools/bmesh_beautify.h b/source/blender/bmesh/tools/bmesh_beautify.h
index d0fef828e7c..a61ae55c3b0 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.h
+++ b/source/blender/bmesh/tools/bmesh_beautify.h
@@ -27,17 +27,26 @@ enum {
EDGE_RESTRICT_DEGENERATE = (1 << 1),
};
+/**
+ * \note This function sets the edge indices to invalid values.
+ */
void BM_mesh_beautify_fill(BMesh *bm,
BMEdge **edge_array,
- const int edge_array_len,
- const short flag,
- const short method,
- const short oflag_edge,
- const short oflag_face);
+ int edge_array_len,
+ short flag,
+ short method,
+ short oflag_edge,
+ short oflag_face);
+/**
+ * Assuming we have 2 triangles sharing an edge (2 - 4),
+ * check if the edge running from (1 - 3) gives better results.
+ *
+ * \return (negative number means the edge can be rotated, lager == better).
+ */
float BM_verts_calc_rotate_beauty(const BMVert *v1,
const BMVert *v2,
const BMVert *v3,
const BMVert *v4,
- const short flag,
- const short method);
+ short flag,
+ short method);
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 0fe687da44e..2f471bf0b81 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -111,7 +111,7 @@ typedef struct EdgeHalf {
bool is_bev;
/** Is e->v2 the vertex at this end? */
bool is_rev;
- /** Is e a seam for custom loopdata (e.g., UVs)? */
+ /** Is e a seam for custom loop-data (e.g., UV's). */
bool is_seam;
/** Used during the custom profile orientation pass. */
bool visited_rpo;
@@ -3048,7 +3048,9 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
}
}
else {
- offset_meet(bp, e, e2, bv->v, e->fnext, true, co, eip);
+ /* Since all edges between e and e2 are in the same plane, it is OK
+ * to treat this like the case where there are no edges between. */
+ offset_meet(bp, e, e2, bv->v, e->fnext, false, co, NULL);
}
}
@@ -4689,7 +4691,7 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe)
* vertices to snap to the midline on the pipe, not just to one plane or the other. */
bool even = (ns % 2) == 0;
bool midline = even && k == half_ns &&
- ((i == 0 && j == half_ns) || (i == ipipe1 || i == ipipe2));
+ ((i == 0 && j == half_ns) || (ELEM(i, ipipe1, ipipe2)));
snap_to_pipe_profile(vpipe, midline, mesh_vert(vm, i, j, k)->co);
}
}
@@ -5215,7 +5217,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert
for (int i = 0; i < n_bndv; i++) {
for (int j = 0; j <= ns2; j++) {
for (int k = 0; k <= ns; k++) {
- if (j == 0 && (k == 0 || k == ns)) {
+ if (j == 0 && (ELEM(k, 0, ns))) {
continue; /* Boundary corners already made. */
}
if (!is_canon(vm, i, j, k)) {
@@ -5792,7 +5794,7 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
/* Make sure the pipe case ADJ mesh is used for both the "Grid Fill" (ADJ) and cutoff options. */
BoundVert *vpipe = NULL;
- if ((vm->count == 3 || vm->count == 4) && bp->seg > 1) {
+ if (ELEM(vm->count, 3, 4) && bp->seg > 1) {
/* Result is passed to bevel_build_rings to avoid overhead. */
vpipe = pipe_test(bv);
if (vpipe) {
@@ -7441,18 +7443,6 @@ static void bevel_limit_offset(BevelParams *bp, BMesh *bm)
}
}
-/**
- * - Currently only bevels BM_ELEM_TAG'd verts and edges.
- *
- * - Newly created faces, edges, and verts are BM_ELEM_TAG'd too,
- * the caller needs to ensure these are cleared before calling
- * if its going to use this tag.
- *
- * - If limit_offset is set, adjusts offset down if necessary
- * to avoid geometry collisions.
- *
- * \warning all tagged edges _must_ be manifold.
- */
void BM_mesh_bevel(BMesh *bm,
const float offset,
const int offset_type,
diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h
index de57e1c62a9..56533e83c39 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.h
+++ b/source/blender/bmesh/tools/bmesh_bevel.h
@@ -23,26 +23,38 @@
struct CurveProfile;
struct MDeformVert;
+/**
+ * - Currently only bevels BM_ELEM_TAG'd verts and edges.
+ *
+ * - Newly created faces, edges, and verts are BM_ELEM_TAG'd too,
+ * the caller needs to ensure these are cleared before calling
+ * if its going to use this tag.
+ *
+ * - If limit_offset is set, adjusts offset down if necessary
+ * to avoid geometry collisions.
+ *
+ * \warning all tagged edges _must_ be manifold.
+ */
void BM_mesh_bevel(BMesh *bm,
- const float offset,
- const int offset_type,
- const int profile_type,
- const int segments,
- const float profile,
- const bool affect_type,
- const bool use_weights,
- const bool limit_offset,
+ float offset,
+ int offset_type,
+ int profile_type,
+ int segments,
+ float profile,
+ bool affect_type,
+ bool use_weights,
+ bool limit_offset,
const struct MDeformVert *dvert,
- const int vertex_group,
- const int mat,
- const bool loop_slide,
- const bool mark_seam,
- const bool mark_sharp,
- const bool harden_normals,
- const int face_strength_mode,
- const int miter_outer,
- const int miter_inner,
- const float spread,
- const float smoothresh,
+ int vertex_group,
+ int mat,
+ bool loop_slide,
+ bool mark_seam,
+ bool mark_sharp,
+ bool harden_normals,
+ int face_strength_mode,
+ int miter_outer,
+ int miter_inner,
+ float spread,
+ float smoothresh,
const struct CurveProfile *custom_profile,
- const int vmesh_method);
+ int vmesh_method);
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c
index 8f03b86b859..d220b183b8d 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.c
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c
@@ -88,7 +88,7 @@ static short plane_point_test_v3(const float plane[4],
*
* Hide flag access
* (for more readable code since same flag is used differently for vert/edge-face).
- */
+ * \{ */
/** Enable when vertex is in the center and its faces have been added to the stack. */
BLI_INLINE void vert_is_center_enable(BMVert *v)
@@ -411,11 +411,6 @@ finally:
/** \name Public BMesh Bisect Function
* \{ */
-/**
- * \param use_snap_center: Snap verts onto the plane.
- * \param use_tag: Only bisect tagged edges and faces.
- * \param oflag_center: Operator flag, enabled for geometry on the axis (existing and created)
- */
void BM_mesh_bisect_plane(BMesh *bm,
const float plane[4],
const bool use_snap_center,
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.h b/source/blender/bmesh/tools/bmesh_bisect_plane.h
index f64b5d8097c..d3c1c6f4c62 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.h
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.h
@@ -20,10 +20,15 @@
* \ingroup bmesh
*/
+/**
+ * \param use_snap_center: Snap verts onto the plane.
+ * \param use_tag: Only bisect tagged edges and faces.
+ * \param oflag_center: Operator flag, enabled for geometry on the axis (existing and created)
+ */
void BM_mesh_bisect_plane(BMesh *bm,
const float plane[4],
- const bool use_snap_center,
- const bool use_tag,
- const short oflag_center,
- const short oflag_new,
- const float eps);
+ bool use_snap_center,
+ bool use_tag,
+ short oflag_center,
+ short oflag_new,
+ float eps);
diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc
index 487ef6427af..e244bc377db 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.cc
+++ b/source/blender/bmesh/tools/bmesh_boolean.cc
@@ -456,14 +456,6 @@ bool BM_mesh_boolean(BMesh *bm,
static_cast<blender::meshintersect::BoolOpType>(boolean_mode));
}
-/**
- * Perform a Knife Intersection operation on the mesh bm.
- * There are either one or two operands, the same as described above for BM_mesh_boolean().
- * If use_separate_all is true, each edge that is created from the intersection should
- * be used to separate all its incident faces. TODO: implement that.
- * TODO: need to ensure that "selected/non-selected" flag of original faces gets propagated
- * to the intersection result faces.
- */
bool BM_mesh_boolean_knife(BMesh *bm,
struct BMLoop *(*looptris)[3],
const int looptris_tot,
diff --git a/source/blender/bmesh/tools/bmesh_boolean.h b/source/blender/bmesh/tools/bmesh_boolean.h
index ed77242e14c..f97f49a7470 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.h
+++ b/source/blender/bmesh/tools/bmesh_boolean.h
@@ -26,25 +26,35 @@ extern "C" {
bool BM_mesh_boolean(BMesh *bm,
struct BMLoop *(*looptris)[3],
- const int looptris_tot,
+ int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data),
void *user_data,
- const int nshapes,
- const bool use_self,
- const bool keep_hidden,
- const bool hole_tolerant,
- const int boolean_mode);
+ int nshapes,
+ bool use_self,
+ bool keep_hidden,
+ bool hole_tolerant,
+ int boolean_mode);
+/**
+ * Perform a Knife Intersection operation on the mesh `bm`.
+ * There are either one or two operands, the same as described above for #BM_mesh_boolean().
+ *
+ * \param use_separate_all: When true, each edge that is created from the intersection should
+ * be used to separate all its incident faces. TODO: implement that.
+ *
+ * TODO: need to ensure that "selected/non-selected" flag of original faces gets propagated
+ * to the intersection result faces.
+ */
bool BM_mesh_boolean_knife(BMesh *bm,
struct BMLoop *(*looptris)[3],
- const int looptris_tot,
+ int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data),
void *user_data,
- const int nshapes,
- const bool use_self,
- const bool use_separate_all,
- const bool hole_tolerant,
- const bool keep_hidden);
+ int nshapes,
+ bool use_self,
+ bool use_separate_all,
+ bool hole_tolerant,
+ bool keep_hidden);
#ifdef __cplusplus
}
diff --git a/source/blender/bmesh/tools/bmesh_decimate.h b/source/blender/bmesh/tools/bmesh_decimate.h
index c62288c269a..336b653d462 100644
--- a/source/blender/bmesh/tools/bmesh_decimate.h
+++ b/source/blender/bmesh/tools/bmesh_decimate.h
@@ -20,27 +20,43 @@
* \ingroup bmesh
*/
+/**
+ * \brief BM_mesh_decimate
+ * \param bm: The mesh
+ * \param factor: face count multiplier [0 - 1]
+ * \param vweights: Optional array of vertex aligned weights [0 - 1],
+ * a vertex group is the usual source for this.
+ * \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate.
+ * \param symmetry_eps: Threshold when matching mirror verts.
+ *
+ * \note The caller is responsible for recalculating face and vertex normals.
+ * - Vertex normals are maintained while decimating,
+ * although they won't necessarily match the final recalculated normals.
+ * - Face normals are not maintained at all.
+ */
void BM_mesh_decimate_collapse(BMesh *bm,
- const float factor,
+ float factor,
float *vweights,
float vweight_factor,
- const bool do_triangulate,
- const int symmetry_axis,
- const float symmetry_eps);
+ bool do_triangulate,
+ int symmetry_axis,
+ float symmetry_eps);
-void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool tag_only);
-void BM_mesh_decimate_unsubdivide(BMesh *bm, const int iterations);
+/**
+ * \param tag_only: so we can call this from an operator */
+void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, int iterations, bool tag_only);
+void BM_mesh_decimate_unsubdivide(BMesh *bm, int iterations);
void BM_mesh_decimate_dissolve_ex(BMesh *bm,
- const float angle_limit,
- const bool do_dissolve_boundaries,
+ float angle_limit,
+ bool do_dissolve_boundaries,
BMO_Delimit delimit,
BMVert **vinput_arr,
- const int vinput_len,
+ int vinput_len,
BMEdge **einput_arr,
- const int einput_len,
- const short oflag_out);
+ int einput_len,
+ short oflag_out);
void BM_mesh_decimate_dissolve(BMesh *bm,
- const float angle_limit,
- const bool do_dissolve_boundaries,
+ float angle_limit,
+ bool do_dissolve_boundaries,
const BMO_Delimit delimit);
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index 97fccbe01fd..c653b2b8007 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -847,7 +847,7 @@ BLI_INLINE int bm_edge_is_manifold_or_boundary(BMLoop *l)
/* less optimized version of check below */
return (BM_edge_is_manifold(l->e) || BM_edge_is_boundary(l->e);
#else
- /* if the edge is a boundary it points to its self, else this must be a manifold */
+ /* if the edge is a boundary it points to itself, else this must be a manifold */
return LIKELY(l) && LIKELY(l->radial_next->radial_next == l);
#endif
}
@@ -855,7 +855,7 @@ BLI_INLINE int bm_edge_is_manifold_or_boundary(BMLoop *l)
static bool bm_edge_collapse_is_degenerate_topology(BMEdge *e_first)
{
/* simply check that there is no overlap between faces and edges of each vert,
- * (excluding the 2 faces attached to 'e' and 'e' its self) */
+ * (excluding the 2 faces attached to 'e' and 'e' itself) */
BMEdge *e_iter;
@@ -1277,20 +1277,6 @@ static bool bm_decim_edge_collapse(BMesh *bm,
/* Main Decimate Function
* ********************** */
-/**
- * \brief BM_mesh_decimate
- * \param bm: The mesh
- * \param factor: face count multiplier [0 - 1]
- * \param vweights: Optional array of vertex aligned weights [0 - 1],
- * a vertex group is the usual source for this.
- * \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate.
- * \param symmetry_eps: Threshold when matching mirror verts.
- *
- * \note The caller is responsible for recalculating face and vertex normals.
- * - Vertex normals are maintained while decimating,
- * although they won't necessarily match the final recalculated normals.
- * - Face normals are not maintained at all.
- */
void BM_mesh_decimate_collapse(BMesh *bm,
const float factor,
float *vweights,
diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
index c96a7be1adf..ca0f31fdf75 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
@@ -168,8 +168,6 @@ enum {
* - BMVert.index == -1: shows we will remove this vert
*/
-/**
- * \param tag_only: so we can call this from an operator */
void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool tag_only)
{
#ifdef USE_WALKER
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c
index 242b269ed47..4cad1d3cb3c 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.c
+++ b/source/blender/bmesh/tools/bmesh_edgenet.c
@@ -422,15 +422,6 @@ static LinkNode *bm_edgenet_path_calc_best(BMEdge *e,
return path;
}
-/**
- * Fill in faces from an edgenet made up of boundary and wire edges.
- *
- * \note New faces currently don't have their normals calculated and are flipped randomly.
- * The caller needs to flip faces correctly.
- *
- * \param bm: The mesh to operate on.
- * \param use_edge_tag: Only fill tagged edges.
- */
void BM_mesh_edgenet(BMesh *bm, const bool use_edge_tag, const bool use_new_face_tag)
{
VertNetInfo *vnet_info = MEM_callocN(sizeof(*vnet_info) * (size_t)bm->totvert, __func__);
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.h b/source/blender/bmesh/tools/bmesh_edgenet.h
index 7855b2e2886..60e9d9acff1 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.h
+++ b/source/blender/bmesh/tools/bmesh_edgenet.h
@@ -20,4 +20,13 @@
* \ingroup bmesh
*/
-void BM_mesh_edgenet(BMesh *bm, const bool use_edge_tag, const bool use_new_face_tag);
+/**
+ * Fill in faces from an edgenet made up of boundary and wire edges.
+ *
+ * \note New faces currently don't have their normals calculated and are flipped randomly.
+ * The caller needs to flip faces correctly.
+ *
+ * \param bm: The mesh to operate on.
+ * \param use_edge_tag: Only fill tagged edges.
+ */
+void BM_mesh_edgenet(BMesh *bm, bool use_edge_tag, bool use_new_face_tag);
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.c b/source/blender/bmesh/tools/bmesh_edgesplit.c
index 388e7f41aba..cd5200a660d 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.c
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.c
@@ -28,11 +28,6 @@
#include "bmesh_edgesplit.h" /* own include */
-/**
- * \param use_verts: Use flagged verts instead of edges.
- * \param tag_only: Only split tagged edges.
- * \param copy_select: Copy selection history.
- */
void BM_mesh_edgesplit(BMesh *bm,
const bool use_verts,
const bool tag_only,
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.h b/source/blender/bmesh/tools/bmesh_edgesplit.h
index 4d3db67ef5f..dd835ba335c 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.h
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.h
@@ -24,10 +24,12 @@
extern "C" {
#endif
-void BM_mesh_edgesplit(BMesh *bm,
- const bool use_verts,
- const bool tag_only,
- const bool copy_select);
+/**
+ * \param use_verts: Use flagged verts instead of edges.
+ * \param tag_only: Only split tagged edges.
+ * \param copy_select: Copy selection history.
+ */
+void BM_mesh_edgesplit(BMesh *bm, bool use_verts, bool tag_only, bool copy_select);
#ifdef __cplusplus
}
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index d51661a08bb..6824dd5008a 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -901,7 +901,7 @@ static int isect_bvhtree_point_v3(BVHTree *tree, const float **looptris, const f
const float dir[3] = {1.0f, 0.0f, 0.0f};
/* Need to initialize hit even tho it's not used.
- * This is to make it so kd-tree believes we didn't intersect anything and
+ * This is to make it so KD-tree believes we didn't intersect anything and
* keeps calling the intersect callback.
*/
hit.index = -1;
@@ -947,14 +947,6 @@ static int isect_bvhtree_point_v3(BVHTree *tree, const float **looptris, const f
#endif /* USE_BVH */
-/**
- * Intersect tessellated faces
- * leaving the resulting edges tagged.
- *
- * \param test_fn: Return value: -1: skip, 0: tree_a, 1: tree_b (use_self == false)
- * \param boolean_mode: -1: no-boolean, 0: intersection... see #BMESH_ISECT_BOOLEAN_ISECT.
- * \return true if the mesh is changed (intersections cut or faces removed from boolean).
- */
bool BM_mesh_intersect(BMesh *bm,
struct BMLoop *(*looptris)[3],
const int looptris_tot,
diff --git a/source/blender/bmesh/tools/bmesh_intersect.h b/source/blender/bmesh/tools/bmesh_intersect.h
index d09ea67a3bb..4fc6460a35f 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.h
+++ b/source/blender/bmesh/tools/bmesh_intersect.h
@@ -24,19 +24,27 @@
extern "C" {
#endif
+/**
+ * Intersect tessellated faces
+ * leaving the resulting edges tagged.
+ *
+ * \param test_fn: Return value: -1: skip, 0: tree_a, 1: tree_b (use_self == false)
+ * \param boolean_mode: -1: no-boolean, 0: intersection... see #BMESH_ISECT_BOOLEAN_ISECT.
+ * \return true if the mesh is changed (intersections cut or faces removed from boolean).
+ */
bool BM_mesh_intersect(BMesh *bm,
struct BMLoop *(*looptris)[3],
- const int looptris_tot,
+ int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data),
void *user_data,
- const bool use_self,
- const bool use_separate,
- const bool use_dissolve,
- const bool use_island_connect,
- const bool use_partial_connect,
- const bool use_edge_tag,
- const int boolean_mode,
- const float eps);
+ bool use_self,
+ bool use_separate,
+ bool use_dissolve,
+ bool use_island_connect,
+ bool use_partial_connect,
+ bool use_edge_tag,
+ int boolean_mode,
+ float eps);
enum {
BMESH_ISECT_BOOLEAN_NONE = -1,
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.h b/source/blender/bmesh/tools/bmesh_intersect_edges.h
index 2736b7a52f9..cd7293c4a0b 100644
--- a/source/blender/bmesh/tools/bmesh_intersect_edges.h
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.h
@@ -21,4 +21,4 @@
#pragma once
bool BM_mesh_intersect_edges(
- BMesh *bm, const char hflag, const float dist, const bool split_faces, GHash *r_targetmap);
+ BMesh *bm, char hflag, float dist, bool split_faces, GHash *r_targetmap);
diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c
index ea1e7eb1e43..52bb92a6221 100644
--- a/source/blender/bmesh/tools/bmesh_path.c
+++ b/source/blender/bmesh/tools/bmesh_path.c
@@ -580,4 +580,5 @@ LinkNode *BM_mesh_calc_path_face(BMesh *bm,
return path;
}
+
/** \} */
diff --git a/source/blender/bmesh/tools/bmesh_path_region_uv.h b/source/blender/bmesh/tools/bmesh_path_region_uv.h
index 5767c5384e5..2f29ef2a36e 100644
--- a/source/blender/bmesh/tools/bmesh_path_region_uv.h
+++ b/source/blender/bmesh/tools/bmesh_path_region_uv.h
@@ -23,7 +23,7 @@
struct LinkNode *BM_mesh_calc_path_uv_region_vert(BMesh *bm,
BMElem *ele_src,
BMElem *ele_dst,
- const uint cd_loop_uv_offset,
+ uint cd_loop_uv_offset,
bool (*filter_fn)(BMLoop *, void *user_data),
void *user_data) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2, 3);
@@ -31,7 +31,7 @@ struct LinkNode *BM_mesh_calc_path_uv_region_vert(BMesh *bm,
struct LinkNode *BM_mesh_calc_path_uv_region_edge(BMesh *bm,
BMElem *ele_src,
BMElem *ele_dst,
- const uint cd_loop_uv_offset,
+ uint cd_loop_uv_offset,
bool (*filter_fn)(BMLoop *, void *user_data),
void *user_data) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2, 3);
@@ -39,7 +39,7 @@ struct LinkNode *BM_mesh_calc_path_uv_region_edge(BMesh *bm,
struct LinkNode *BM_mesh_calc_path_uv_region_face(BMesh *bm,
BMElem *ele_src,
BMElem *ele_dst,
- const uint cd_loop_uv_offset,
+ uint cd_loop_uv_offset,
bool (*filter_fn)(BMFace *, void *user_data),
void *user_data) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2, 3);
diff --git a/source/blender/bmesh/tools/bmesh_path_uv.c b/source/blender/bmesh/tools/bmesh_path_uv.c
index 30b109d4731..131a8aa0085 100644
--- a/source/blender/bmesh/tools/bmesh_path_uv.c
+++ b/source/blender/bmesh/tools/bmesh_path_uv.c
@@ -198,6 +198,7 @@ struct LinkNode *BM_mesh_calc_path_uv_vert(BMesh *bm,
/* -------------------------------------------------------------------- */
/** \name BM_mesh_calc_path_uv_edge
* \{ */
+
/* TODO(campbell): not very urgent, since the operator fakes this using vertex path. */
/** \} */
diff --git a/source/blender/bmesh/tools/bmesh_region_match.c b/source/blender/bmesh/tools/bmesh_region_match.c
index 924538490ad..2ada18f51e7 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.c
+++ b/source/blender/bmesh/tools/bmesh_region_match.c
@@ -1223,6 +1223,7 @@ static BMEdge *bm_face_region_pivot_edge_find(BMFace **faces_region,
return e_pivot;
}
+
/** \} */
#endif /* USE_PIVOT_SEARCH */
@@ -1332,12 +1333,6 @@ static void bm_vert_fasthash_destroy(UUIDFashMatch *fm)
#endif /* USE_PIVOT_FASTMATCH */
-/**
- * Take a face-region and return a list of matching face-regions.
- *
- * \param faces_region: A single, contiguous face-region.
- * \return A list of matching null-terminated face-region arrays.
- */
int BM_mesh_region_match(BMesh *bm,
BMFace **faces_region,
uint faces_region_len,
diff --git a/source/blender/bmesh/tools/bmesh_region_match.h b/source/blender/bmesh/tools/bmesh_region_match.h
index 799af938c31..7b7233783ce 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.h
+++ b/source/blender/bmesh/tools/bmesh_region_match.h
@@ -20,6 +20,12 @@
* \ingroup bmesh
*/
+/**
+ * Take a face-region and return a list of matching face-regions.
+ *
+ * \param faces_region: A single, contiguous face-region.
+ * \return A list of matching null-terminated face-region arrays.
+ */
int BM_mesh_region_match(BMesh *bm,
BMFace **faces_region,
uint faces_region_len,
diff --git a/source/blender/bmesh/tools/bmesh_separate.c b/source/blender/bmesh/tools/bmesh_separate.c
index 3c69ea111bf..e00829604d5 100644
--- a/source/blender/bmesh/tools/bmesh_separate.c
+++ b/source/blender/bmesh/tools/bmesh_separate.c
@@ -32,10 +32,6 @@
#include "bmesh_separate.h" /* own include */
#include "intern/bmesh_private.h"
-/**
- * Split all faces that match `filter_fn`.
- * \note
- */
void BM_mesh_separate_faces(BMesh *bm, BMFaceFilterFunc filter_fn, void *user_data)
{
BMFace **faces_array_all = MEM_mallocN(bm->totface * sizeof(BMFace *), __func__);
diff --git a/source/blender/bmesh/tools/bmesh_separate.h b/source/blender/bmesh/tools/bmesh_separate.h
index 9260903a8fa..8c599eef2b0 100644
--- a/source/blender/bmesh/tools/bmesh_separate.h
+++ b/source/blender/bmesh/tools/bmesh_separate.h
@@ -20,4 +20,8 @@
* \ingroup bmesh
*/
+/**
+ * Split all faces that match `filter_fn`.
+ * \note
+ */
void BM_mesh_separate_faces(BMesh *bm, BMFaceFilterFunc filter_fn, void *user_data);
diff --git a/source/blender/bmesh/tools/bmesh_triangulate.h b/source/blender/bmesh/tools/bmesh_triangulate.h
index f45f94f15d8..0d78b6a74b4 100644
--- a/source/blender/bmesh/tools/bmesh_triangulate.h
+++ b/source/blender/bmesh/tools/bmesh_triangulate.h
@@ -23,10 +23,10 @@
#pragma once
void BM_mesh_triangulate(BMesh *bm,
- const int quad_method,
- const int ngon_method,
- const int min_vertices,
- const bool tag_only,
+ int quad_method,
+ int ngon_method,
+ int min_vertices,
+ bool tag_only,
BMOperator *op,
BMOpSlot *slot_facemap_out,
BMOpSlot *slot_facemap_double_out);
diff --git a/source/blender/bmesh/tools/bmesh_wireframe.c b/source/blender/bmesh/tools/bmesh_wireframe.c
index af4a4424103..67010fc89c7 100644
--- a/source/blender/bmesh/tools/bmesh_wireframe.c
+++ b/source/blender/bmesh/tools/bmesh_wireframe.c
@@ -152,12 +152,6 @@ static bool bm_loop_is_radial_boundary(BMLoop *l_first)
return true;
}
-/**
- * \param defgrp_index: Vertex group index, -1 for no vertex groups.
- *
- * \note All edge tags must be cleared.
- * \note Behavior matches MOD_solidify.c
- */
void BM_mesh_wireframe(BMesh *bm,
const float offset,
const float offset_fac,
diff --git a/source/blender/bmesh/tools/bmesh_wireframe.h b/source/blender/bmesh/tools/bmesh_wireframe.h
index b2c2f5f5523..8e523780a67 100644
--- a/source/blender/bmesh/tools/bmesh_wireframe.h
+++ b/source/blender/bmesh/tools/bmesh_wireframe.h
@@ -22,18 +22,24 @@
#pragma once
+/**
+ * \param defgrp_index: Vertex group index, -1 for no vertex groups.
+ *
+ * \note All edge tags must be cleared.
+ * \note Behavior matches MOD_solidify.c
+ */
void BM_mesh_wireframe(BMesh *bm,
- const float offset,
- const float offset_fac,
- const float offset_fac_vg,
- const bool use_replace,
- const bool use_boundary,
- const bool use_even_offset,
- const bool use_relative_offset,
- const bool use_crease,
- const float crease_weight,
- const int defgrp_index,
- const bool defgrp_invert,
- const short mat_offset,
- const short mat_max,
- const bool use_tag);
+ float offset,
+ float offset_fac,
+ float offset_fac_vg,
+ bool use_replace,
+ bool use_boundary,
+ bool use_even_offset,
+ bool use_relative_offset,
+ bool use_crease,
+ float crease_weight,
+ int defgrp_index,
+ bool defgrp_invert,
+ short mat_offset,
+ short mat_max,
+ bool use_tag);
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 10e385e0187..b9b365a3175 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -38,7 +38,11 @@ set(INC
../render/intern
../../../extern/clew/include
../../../intern/atomic
+ ../../../intern/clog
../../../intern/guardedalloc
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../makesdna/intern
)
set(INC_SYS
@@ -136,6 +140,8 @@ set(SRC
nodes/COM_OutputFileNode.h
nodes/COM_RenderLayersNode.cc
nodes/COM_RenderLayersNode.h
+ nodes/COM_SceneTimeNode.cc
+ nodes/COM_SceneTimeNode.h
nodes/COM_SwitchNode.cc
nodes/COM_SwitchNode.h
nodes/COM_SwitchViewNode.cc
@@ -242,6 +248,8 @@ set(SRC
nodes/COM_ColorToBWNode.h
nodes/COM_ConvertAlphaNode.cc
nodes/COM_ConvertAlphaNode.h
+ nodes/COM_ConvertColorSpaceNode.cc
+ nodes/COM_ConvertColorSpaceNode.h
nodes/COM_GammaNode.cc
nodes/COM_GammaNode.h
nodes/COM_HueSaturationValueCorrectNode.cc
@@ -565,6 +573,8 @@ set(SRC
operations/COM_IDMaskOperation.cc
operations/COM_IDMaskOperation.h
+ operations/COM_ConvertColorSpaceOperation.cc
+ operations/COM_ConvertColorSpaceOperation.h
operations/COM_DotproductOperation.cc
operations/COM_DotproductOperation.h
@@ -640,6 +650,15 @@ endif()
blender_add_lib(bf_compositor "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+if(WITH_UNITY_BUILD)
+ set_target_properties(bf_compositor PROPERTIES UNITY_BUILD ON)
+ set_target_properties(bf_compositor PROPERTIES UNITY_BUILD_BATCH_SIZE 10)
+endif()
+
+if(COMMAND target_precompile_headers)
+ target_precompile_headers(bf_compositor PRIVATE COM_precomp.h)
+endif()
+
if(CXX_WARN_NO_SUGGEST_OVERRIDE)
target_compile_options(bf_compositor PRIVATE "-Wsuggest-override")
endif()
@@ -661,3 +680,6 @@ if(WITH_GTESTS)
include(GTestTesting)
blender_add_test_lib(bf_compositor_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
endif()
+
+# Needed so we can use dna_type_offsets.h for defaults initialization.
+add_dependencies(bf_compositor bf_dna)
diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h
index a7f9081f3fc..67d189fe5f8 100644
--- a/source/blender/compositor/COM_compositor.h
+++ b/source/blender/compositor/COM_compositor.h
@@ -28,12 +28,19 @@ extern "C" {
/* Keep ascii art. */
/* clang-format off */
/**
+ *
* \defgroup Model The data model of the compositor
+ * \ingroup compositor
* \defgroup Memory The memory management stuff
+ * \ingroup compositor
* \defgroup Execution The execution logic
+ * \ingroup compositor
* \defgroup Conversion Conversion logic
+ * \ingroup compositor
* \defgroup Node All nodes of the compositor
+ * \ingroup compositor
* \defgroup Operation All operations of the compositor
+ * \ingroup compositor
*
* \page Introduction of the Blender Compositor
*
@@ -74,8 +81,8 @@ extern "C" {
*
* during the preparation of the execution All ReadBufferOperation will receive an offset.
* This offset is used during execution as an optimization trick
- * Next all operations will be initialized for execution \see NodeOperation.initExecution
- * Next all ExecutionGroup's will be initialized for execution \see ExecutionGroup.initExecution
+ * Next all operations will be initialized for execution \see NodeOperation.init_execution
+ * Next all ExecutionGroup's will be initialized for execution \see ExecutionGroup.init_execution
* this all is controlled from \see ExecutionSystem.execute
*
* \section priority Render priority
@@ -92,7 +99,7 @@ extern "C" {
* When match the ExecutionGroup will be executed (this happens in serial)
*
* \see ExecutionSystem.execute control of the Render priority
- * \see NodeOperation.getRenderPriority receive the render priority
+ * \see NodeOperation.get_render_priority receive the render priority
* \see ExecutionGroup.execute the main loop to execute a whole ExecutionGroup
*
* \section order Chunk order
@@ -121,7 +128,7 @@ extern "C" {
* Chunk is finished.
*
* \see ExecutionGroup.execute
- * \see ViewerOperation.getChunkOrder
+ * \see ViewerOperation.get_chunk_order
* \see ChunkOrdering
*
* \section interest Area of interest
@@ -152,13 +159,13 @@ extern "C" {
*
* In the above example ExecutionGroup B has an outputoperation (ViewerOperation)
* and is being executed.
- * The first chunk is evaluated [@ref ExecutionGroup.scheduleChunkWhenPossible],
+ * The first chunk is evaluated [@ref ExecutionGroup.schedule_chunk_when_possible],
* but not all input chunks are available.
* The relevant ExecutionGroup (that can calculate the missing chunks; ExecutionGroup A)
* is asked to calculate the area ExecutionGroup B is missing.
- * [@ref ExecutionGroup.scheduleAreaWhenPossible]
+ * [@ref ExecutionGroup.schedule_area_when_possible]
* ExecutionGroup B checks what chunks the area spans, and tries to schedule these chunks.
- * If all input data is available these chunks are scheduled [@ref ExecutionGroup.scheduleChunk]
+ * If all input data is available these chunks are scheduled [@ref ExecutionGroup.schedule_chunk]
*
* <pre>
*
@@ -171,18 +178,18 @@ extern "C" {
* O------------------------------->O |
* . O |
* . O-------\ |
- * . . | ExecutionGroup.scheduleChunkWhenPossible
+ * . . | ExecutionGroup.schedule_chunk_when_possible
* . . O----/ (*) |
* . . O |
* . . O |
- * . . O ExecutionGroup.scheduleAreaWhenPossible|
+ * . . O ExecutionGroup.schedule_area_when_possible|
* . . O---------------------------------------->O
- * . . . O----------\ ExecutionGroup.scheduleChunkWhenPossible
+ * . . . O----------\ ExecutionGroup.schedule_chunk_when_possible
* . . . . | (*)
* . . . . O-------/
* . . . . O
* . . . . O
- * . . . . O-------\ ExecutionGroup.scheduleChunk
+ * . . . . O-------\ ExecutionGroup.schedule_chunk
* . . . . . |
* . . . . . O----/
* . . . . O<=O
@@ -198,7 +205,7 @@ extern "C" {
* This happens until all chunks of (ExecutionGroup B) are finished executing or the user break's the process.
*
* NodeOperation like the ScaleOperation can influence the area of interest by reimplementing the
- * [@ref NodeOperation.determineAreaOfInterest] method
+ * [@ref NodeOperation.determine_area_of_interest] method
*
* <pre>
*
@@ -221,13 +228,13 @@ extern "C" {
*
* \see ExecutionGroup.execute Execute a complete ExecutionGroup.
* Halts until finished or breaked by user
- * \see ExecutionGroup.scheduleChunkWhenPossible Tries to schedule a single chunk,
+ * \see ExecutionGroup.schedule_chunk_when_possible Tries to schedule a single chunk,
* checks if all input data is available. Can trigger dependent chunks to be calculated
- * \see ExecutionGroup.scheduleAreaWhenPossible
+ * \see ExecutionGroup.schedule_area_when_possible
* Tries to schedule an area. This can be multiple chunks
- * (is called from [@ref ExecutionGroup.scheduleChunkWhenPossible])
- * \see ExecutionGroup.scheduleChunk Schedule a chunk on the WorkScheduler
- * \see NodeOperation.determineDependingAreaOfInterest Influence the area of interest of a chunk.
+ * (is called from [@ref ExecutionGroup.schedule_chunk_when_possible])
+ * \see ExecutionGroup.schedule_chunk Schedule a chunk on the WorkScheduler
+ * \see NodeOperation.determine_depending_area_of_interest Influence the area of interest of a chunk.
* \see WriteBufferOperation Operation to write to a MemoryProxy/MemoryBuffer
* \see ReadBufferOperation Operation to read from a MemoryProxy/MemoryBuffer
* \see MemoryProxy proxy for information about memory image
@@ -283,16 +290,16 @@ extern "C" {
* The OutputOperation of the ExecutionGroup is called to execute the area of the outputbuffer.
*
* \see ExecutionGroup
- * \see NodeOperation.executeRegion executes a single chunk of a NodeOperation
+ * \see NodeOperation.execute_region executes a single chunk of a NodeOperation
* \see CPUDevice.execute
*
* \subsection GPUDevice OpenCLDevice
*
* To be completed!
- * \see NodeOperation.executeOpenCLRegion
+ * \see NodeOperation.execute_opencl_region
* \see OpenCLDevice.execute
*
- * \section executePixel executing a pixel
+ * \section execute_pixel executing a pixel
* Finally the last step, the node functionality :)
*/
@@ -301,10 +308,10 @@ extern "C" {
* It can be executed during editing (blenkernel/node.cc) or rendering
* (renderer/pipeline.c)
*
- * \param rd: [struct RenderData]
+ * \param render_data: [struct RenderData]
* Render data for this composite, this won't always belong to a scene.
*
- * \param editingtree: [struct bNodeTree]
+ * \param node_tree: [struct bNodeTree]
* reference to the compositor editing tree
*
* \param rendering: [true false]
@@ -312,10 +319,10 @@ extern "C" {
* (true) or editing (false).
* based on this setting the system will work differently:
* - during rendering only Composite & the File output node will be calculated
- * \see NodeOperation.isOutputProgram(int rendering) of the specific operations
+ * \see NodeOperation.is_output_program(int rendering) of the specific operations
*
* - during editing all output nodes will be calculated
- * \see NodeOperation.isOutputProgram(int rendering) of the specific operations
+ * \see NodeOperation.is_output_program(int rendering) of the specific operations
*
* - another quality setting can be used bNodeTree.
* The quality is determined by the bNodeTree fields.
@@ -326,10 +333,10 @@ extern "C" {
* - output nodes can have different priorities in the WorkScheduler.
* This is implemented in the COM_execute function.
*
- * \param viewSettings:
+ * \param view_settings:
* reference to view settings used for color management
*
- * \param displaySettings:
+ * \param display_settings:
* reference to display settings used for color management
*
* OCIO_TODO: this options only used in rare cases, namely in output file node,
@@ -343,13 +350,13 @@ void COM_execute(RenderData *render_data,
Scene *scene,
bNodeTree *node_tree,
int rendering,
- const ColorManagedViewSettings *viewSettings,
- const ColorManagedDisplaySettings *displaySettings,
- const char *viewName);
+ const ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ const char *view_name);
/**
* \brief Deinitialize the compositor caches and allocated memory.
- * Use COM_clearCaches to only free the caches.
+ * Use COM_clear_caches to only free the caches.
*/
void COM_deinitialize(void);
@@ -357,7 +364,7 @@ void COM_deinitialize(void);
* \brief Clear all compositor caches. (Compositor system will still remain available).
* To deinitialize the compositor use the COM_deinitialize method.
*/
-// void COM_clearCaches(void); // NOT YET WRITTEN
+// void COM_clear_caches(void); // NOT YET WRITTEN
#ifdef __cplusplus
}
diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h
index 9991414aba4..794bf1b23bc 100644
--- a/source/blender/compositor/COM_defines.h
+++ b/source/blender/compositor/COM_defines.h
@@ -18,9 +18,9 @@
#pragma once
-#include "BLI_float2.hh"
-#include "BLI_index_range.hh"
-#include "BLI_rect.h"
+#include "BLI_math_vec_types.hh"
+
+#include "DNA_vec_types.h"
namespace blender::compositor {
diff --git a/source/blender/compositor/COM_precomp.h b/source/blender/compositor/COM_precomp.h
new file mode 100644
index 00000000000..4d2681ea0cd
--- /dev/null
+++ b/source/blender/compositor/COM_precomp.h
@@ -0,0 +1,33 @@
+/* Pre-compiled headers, see: D13797. */
+
+#include <cfloat>
+#include <climits>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <iostream>
+#include <iterator>
+#include <list>
+#include <map>
+#include <ostream>
+#include <set>
+#include <string>
+
+#include "COM_ConstantOperation.h"
+#include "COM_ConvertOperation.h"
+#include "COM_Debug.h"
+#include "COM_Enums.h"
+#include "COM_ExecutionGroup.h"
+#include "COM_ExecutionSystem.h"
+#include "COM_MultiThreadedOperation.h"
+#include "COM_Node.h"
+#include "COM_NodeOperation.h"
+#include "COM_OpenCLDevice.h"
+#include "COM_SetAlphaMultiplyOperation.h"
+#include "COM_SetColorOperation.h"
+#include "COM_SetSamplerOperation.h"
+#include "COM_SetValueOperation.h"
+#include "COM_SetVectorOperation.h"
+#include "COM_defines.h"
diff --git a/source/blender/compositor/intern/COM_BufferOperation.cc b/source/blender/compositor/intern/COM_BufferOperation.cc
index c6530cf6bd1..81ea645e482 100644
--- a/source/blender/compositor/intern/COM_BufferOperation.cc
+++ b/source/blender/compositor/intern/COM_BufferOperation.cc
@@ -25,47 +25,50 @@ BufferOperation::BufferOperation(MemoryBuffer *buffer, DataType data_type)
buffer_ = buffer;
inflated_buffer_ = nullptr;
set_canvas(buffer->get_rect());
- addOutputSocket(data_type);
- flags.is_constant_operation = buffer_->is_a_single_elem();
- flags.is_fullframe_operation = false;
+ add_output_socket(data_type);
+ flags_.is_constant_operation = buffer_->is_a_single_elem();
+ flags_.is_fullframe_operation = false;
}
const float *BufferOperation::get_constant_elem()
{
BLI_assert(buffer_->is_a_single_elem());
- return buffer_->getBuffer();
+ return buffer_->get_buffer();
}
-void BufferOperation::initExecution()
+void BufferOperation::init_execution()
{
if (buffer_->is_a_single_elem()) {
- initMutex();
+ init_mutex();
}
}
-void *BufferOperation::initializeTileData(rcti * /*rect*/)
+void *BufferOperation::initialize_tile_data(rcti * /*rect*/)
{
if (buffer_->is_a_single_elem() == false) {
return buffer_;
}
- lockMutex();
+ lock_mutex();
if (!inflated_buffer_) {
inflated_buffer_ = buffer_->inflate();
}
- unlockMutex();
+ unlock_mutex();
return inflated_buffer_;
}
-void BufferOperation::deinitExecution()
+void BufferOperation::deinit_execution()
{
if (buffer_->is_a_single_elem()) {
- deinitMutex();
+ deinit_mutex();
}
delete inflated_buffer_;
}
-void BufferOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void BufferOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
switch (sampler) {
case PixelSampler::Nearest:
@@ -73,16 +76,16 @@ void BufferOperation::executePixelSampled(float output[4], float x, float y, Pix
break;
case PixelSampler::Bilinear:
default:
- buffer_->readBilinear(output, x, y);
+ buffer_->read_bilinear(output, x, y);
break;
case PixelSampler::Bicubic:
/* No bicubic. Same implementation as ReadBufferOperation. */
- buffer_->readBilinear(output, x, y);
+ buffer_->read_bilinear(output, x, y);
break;
}
}
-void BufferOperation::executePixelFiltered(
+void BufferOperation::execute_pixel_filtered(
float output[4], float x, float y, float dx[2], float dy[2])
{
const float uv[2] = {x, y};
diff --git a/source/blender/compositor/intern/COM_BufferOperation.h b/source/blender/compositor/intern/COM_BufferOperation.h
index b4cbc0a56b6..4aba3a705dd 100644
--- a/source/blender/compositor/intern/COM_BufferOperation.h
+++ b/source/blender/compositor/intern/COM_BufferOperation.h
@@ -31,11 +31,12 @@ class BufferOperation : public ConstantOperation {
BufferOperation(MemoryBuffer *buffer, DataType data_type);
const float *get_constant_elem() override;
- void *initializeTileData(rcti *rect) override;
- void initExecution() override;
- void deinitExecution() override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
- void executePixelFiltered(float output[4], float x, float y, float dx[2], float dy[2]) override;
+ void *initialize_tile_data(rcti *rect) override;
+ void init_execution() override;
+ void deinit_execution() override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_filtered(
+ float output[4], float x, float y, float dx[2], float dy[2]) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_BufferRange.h b/source/blender/compositor/intern/COM_BufferRange.h
index ffdf1f2f1e5..7684ae52fab 100644
--- a/source/blender/compositor/intern/COM_BufferRange.h
+++ b/source/blender/compositor/intern/COM_BufferRange.h
@@ -19,7 +19,6 @@
#pragma once
#include "BLI_assert.h"
-#include "BLI_rect.h"
#include <iterator>
diff --git a/source/blender/compositor/intern/COM_CPUDevice.cc b/source/blender/compositor/intern/COM_CPUDevice.cc
index 2ca5557e278..ad7a807b8fd 100644
--- a/source/blender/compositor/intern/COM_CPUDevice.cc
+++ b/source/blender/compositor/intern/COM_CPUDevice.cc
@@ -19,12 +19,11 @@
#include "COM_CPUDevice.h"
#include "COM_ExecutionGroup.h"
-
-#include "BLI_rect.h"
+#include "COM_NodeOperation.h"
namespace blender::compositor {
-CPUDevice::CPUDevice(int thread_id) : m_thread_id(thread_id)
+CPUDevice::CPUDevice(int thread_id) : thread_id_(thread_id)
{
}
@@ -32,11 +31,11 @@ void CPUDevice::execute(WorkPackage *work_package)
{
switch (work_package->type) {
case eWorkPackageType::Tile: {
- const unsigned int chunkNumber = work_package->chunk_number;
- ExecutionGroup *executionGroup = work_package->execution_group;
+ const unsigned int chunk_number = work_package->chunk_number;
+ ExecutionGroup *execution_group = work_package->execution_group;
- executionGroup->getOutputOperation()->executeRegion(&work_package->rect, chunkNumber);
- executionGroup->finalizeChunkExecution(chunkNumber, nullptr);
+ execution_group->get_output_operation()->execute_region(&work_package->rect, chunk_number);
+ execution_group->finalize_chunk_execution(chunk_number, nullptr);
break;
}
case eWorkPackageType::CustomFunction: {
diff --git a/source/blender/compositor/intern/COM_CPUDevice.h b/source/blender/compositor/intern/COM_CPUDevice.h
index 99629890b30..b5d1fd1fff1 100644
--- a/source/blender/compositor/intern/COM_CPUDevice.h
+++ b/source/blender/compositor/intern/COM_CPUDevice.h
@@ -39,11 +39,11 @@ class CPUDevice : public Device {
int thread_id()
{
- return m_thread_id;
+ return thread_id_;
}
protected:
- int m_thread_id;
+ int thread_id_;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_ChunkOrder.cc b/source/blender/compositor/intern/COM_ChunkOrder.cc
index a03718d720d..3e0246ce893 100644
--- a/source/blender/compositor/intern/COM_ChunkOrder.cc
+++ b/source/blender/compositor/intern/COM_ChunkOrder.cc
@@ -16,9 +16,9 @@
* Copyright 2011, Blender Foundation.
*/
-#include "COM_ChunkOrder.h"
+#include <cfloat>
-#include "BLI_math.h"
+#include "COM_ChunkOrder.h"
namespace blender::compositor {
diff --git a/source/blender/compositor/intern/COM_CompositorContext.cc b/source/blender/compositor/intern/COM_CompositorContext.cc
index f5f490b0bf6..7b0f7b0f8fb 100644
--- a/source/blender/compositor/intern/COM_CompositorContext.cc
+++ b/source/blender/compositor/intern/COM_CompositorContext.cc
@@ -17,43 +17,38 @@
*/
#include "COM_CompositorContext.h"
-#include "COM_defines.h"
-#include <cstdio>
-
-#include "BLI_assert.h"
-#include "DNA_userdef_types.h"
namespace blender::compositor {
CompositorContext::CompositorContext()
{
- this->m_scene = nullptr;
- this->m_rd = nullptr;
- this->m_quality = eCompositorQuality::High;
- this->m_hasActiveOpenCLDevices = false;
- this->m_fastCalculation = false;
- this->m_viewSettings = nullptr;
- this->m_displaySettings = nullptr;
- this->m_bnodetree = nullptr;
+ scene_ = nullptr;
+ rd_ = nullptr;
+ quality_ = eCompositorQuality::High;
+ hasActiveOpenCLDevices_ = false;
+ fast_calculation_ = false;
+ view_settings_ = nullptr;
+ display_settings_ = nullptr;
+ bnodetree_ = nullptr;
}
-int CompositorContext::getFramenumber() const
+int CompositorContext::get_framenumber() const
{
- BLI_assert(m_rd);
- return m_rd->cfra;
+ BLI_assert(rd_);
+ return rd_->cfra;
}
Size2f CompositorContext::get_render_size() const
{
- return {getRenderData()->xsch * getRenderPercentageAsFactor(),
- getRenderData()->ysch * getRenderPercentageAsFactor()};
+ return {get_render_data()->xsch * get_render_percentage_as_factor(),
+ get_render_data()->ysch * get_render_percentage_as_factor()};
}
eExecutionModel CompositorContext::get_execution_model() const
{
if (U.experimental.use_full_frame_compositor) {
- BLI_assert(m_bnodetree != nullptr);
- switch (m_bnodetree->execution_mode) {
+ BLI_assert(bnodetree_ != nullptr);
+ switch (bnodetree_->execution_mode) {
case 1:
return eExecutionModel::FullFrame;
case 0:
diff --git a/source/blender/compositor/intern/COM_CompositorContext.h b/source/blender/compositor/intern/COM_CompositorContext.h
index ae298c5a65a..e41576b6f69 100644
--- a/source/blender/compositor/intern/COM_CompositorContext.h
+++ b/source/blender/compositor/intern/COM_CompositorContext.h
@@ -18,16 +18,13 @@
#pragma once
-#include "BLI_rect.h"
-
#include "COM_Enums.h"
#include "DNA_color_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
-#include <string>
-#include <vector>
+struct bNodeInstanceHash;
namespace blender::compositor {
@@ -41,55 +38,55 @@ class CompositorContext {
* editor) This field is initialized in ExecutionSystem and must only be read from that point
* on. \see ExecutionSystem
*/
- bool m_rendering;
+ bool rendering_;
/**
* \brief The quality of the composite.
* This field is initialized in ExecutionSystem and must only be read from that point on.
* \see ExecutionSystem
*/
- eCompositorQuality m_quality;
+ eCompositorQuality quality_;
- Scene *m_scene;
+ Scene *scene_;
/**
* \brief Reference to the render data that is being composited.
* This field is initialized in ExecutionSystem and must only be read from that point on.
* \see ExecutionSystem
*/
- RenderData *m_rd;
+ RenderData *rd_;
/**
* \brief reference to the bNodeTree
* This field is initialized in ExecutionSystem and must only be read from that point on.
* \see ExecutionSystem
*/
- bNodeTree *m_bnodetree;
+ bNodeTree *bnodetree_;
/**
* \brief Preview image hash table
* This field is initialized in ExecutionSystem and must only be read from that point on.
*/
- bNodeInstanceHash *m_previews;
+ bNodeInstanceHash *previews_;
/**
* \brief does this system have active opencl devices?
*/
- bool m_hasActiveOpenCLDevices;
+ bool hasActiveOpenCLDevices_;
/**
* \brief Skip slow nodes
*/
- bool m_fastCalculation;
+ bool fast_calculation_;
/* \brief color management settings */
- const ColorManagedViewSettings *m_viewSettings;
- const ColorManagedDisplaySettings *m_displaySettings;
+ const ColorManagedViewSettings *view_settings_;
+ const ColorManagedDisplaySettings *display_settings_;
/**
* \brief active rendering view name
*/
- const char *m_viewName;
+ const char *view_name_;
public:
/**
@@ -100,192 +97,192 @@ class CompositorContext {
/**
* \brief set the rendering field of the context
*/
- void setRendering(bool rendering)
+ void set_rendering(bool rendering)
{
- this->m_rendering = rendering;
+ rendering_ = rendering;
}
/**
* \brief get the rendering field of the context
*/
- bool isRendering() const
+ bool is_rendering() const
{
- return this->m_rendering;
+ return rendering_;
}
/**
* \brief set the scene of the context
*/
- void setRenderData(RenderData *rd)
+ void set_render_data(RenderData *rd)
{
- this->m_rd = rd;
+ rd_ = rd;
}
/**
* \brief set the bnodetree of the context
*/
- void setbNodeTree(bNodeTree *bnodetree)
+ void set_bnodetree(bNodeTree *bnodetree)
{
- this->m_bnodetree = bnodetree;
+ bnodetree_ = bnodetree;
}
/**
* \brief get the bnodetree of the context
*/
- const bNodeTree *getbNodeTree() const
+ const bNodeTree *get_bnodetree() const
{
- return this->m_bnodetree;
+ return bnodetree_;
}
/**
* \brief get the scene of the context
*/
- const RenderData *getRenderData() const
+ const RenderData *get_render_data() const
{
- return this->m_rd;
+ return rd_;
}
- void setScene(Scene *scene)
+ void set_scene(Scene *scene)
{
- m_scene = scene;
+ scene_ = scene;
}
- Scene *getScene() const
+ Scene *get_scene() const
{
- return m_scene;
+ return scene_;
}
/**
* \brief set the preview image hash table
*/
- void setPreviewHash(bNodeInstanceHash *previews)
+ void set_preview_hash(bNodeInstanceHash *previews)
{
- this->m_previews = previews;
+ previews_ = previews;
}
/**
* \brief get the preview image hash table
*/
- bNodeInstanceHash *getPreviewHash() const
+ bNodeInstanceHash *get_preview_hash() const
{
- return this->m_previews;
+ return previews_;
}
/**
* \brief set view settings of color management
*/
- void setViewSettings(const ColorManagedViewSettings *viewSettings)
+ void set_view_settings(const ColorManagedViewSettings *view_settings)
{
- this->m_viewSettings = viewSettings;
+ view_settings_ = view_settings;
}
/**
* \brief get view settings of color management
*/
- const ColorManagedViewSettings *getViewSettings() const
+ const ColorManagedViewSettings *get_view_settings() const
{
- return this->m_viewSettings;
+ return view_settings_;
}
/**
* \brief set display settings of color management
*/
- void setDisplaySettings(const ColorManagedDisplaySettings *displaySettings)
+ void set_display_settings(const ColorManagedDisplaySettings *display_settings)
{
- this->m_displaySettings = displaySettings;
+ display_settings_ = display_settings;
}
/**
* \brief get display settings of color management
*/
- const ColorManagedDisplaySettings *getDisplaySettings() const
+ const ColorManagedDisplaySettings *get_display_settings() const
{
- return this->m_displaySettings;
+ return display_settings_;
}
/**
* \brief set the quality
*/
- void setQuality(eCompositorQuality quality)
+ void set_quality(eCompositorQuality quality)
{
- this->m_quality = quality;
+ quality_ = quality;
}
/**
* \brief get the quality
*/
- eCompositorQuality getQuality() const
+ eCompositorQuality get_quality() const
{
- return this->m_quality;
+ return quality_;
}
/**
* \brief get the current frame-number of the scene in this context
*/
- int getFramenumber() const;
+ int get_framenumber() const;
/**
- * \brief has this system active openclDevices?
+ * \brief has this system active opencl_devices?
*/
- bool getHasActiveOpenCLDevices() const
+ bool get_has_active_opencl_devices() const
{
- return this->m_hasActiveOpenCLDevices;
+ return hasActiveOpenCLDevices_;
}
/**
- * \brief set has this system active openclDevices?
+ * \brief set has this system active opencl_devices?
*/
void setHasActiveOpenCLDevices(bool hasAvtiveOpenCLDevices)
{
- this->m_hasActiveOpenCLDevices = hasAvtiveOpenCLDevices;
+ hasActiveOpenCLDevices_ = hasAvtiveOpenCLDevices;
}
/** Whether it has a view with a specific name and not the default one. */
bool has_explicit_view() const
{
- return m_viewName && m_viewName[0] != '\0';
+ return view_name_ && view_name_[0] != '\0';
}
/**
* \brief get the active rendering view
*/
- const char *getViewName() const
+ const char *get_view_name() const
{
- return this->m_viewName;
+ return view_name_;
}
/**
* \brief set the active rendering view
*/
- void setViewName(const char *viewName)
+ void set_view_name(const char *view_name)
{
- this->m_viewName = viewName;
+ view_name_ = view_name;
}
- int getChunksize() const
+ int get_chunksize() const
{
- return this->getbNodeTree()->chunksize;
+ return this->get_bnodetree()->chunksize;
}
- void setFastCalculation(bool fastCalculation)
+ void set_fast_calculation(bool fast_calculation)
{
- this->m_fastCalculation = fastCalculation;
+ fast_calculation_ = fast_calculation;
}
- bool isFastCalculation() const
+ bool is_fast_calculation() const
{
- return this->m_fastCalculation;
+ return fast_calculation_;
}
- bool isGroupnodeBufferEnabled() const
+ bool is_groupnode_buffer_enabled() const
{
- return (this->getbNodeTree()->flag & NTREE_COM_GROUPNODE_BUFFER) != 0;
+ return (this->get_bnodetree()->flag & NTREE_COM_GROUPNODE_BUFFER) != 0;
}
/**
* \brief Get the render percentage as a factor.
* The compositor uses a factor i.o. a percentage.
*/
- float getRenderPercentageAsFactor() const
+ float get_render_percentage_as_factor() const
{
- return m_rd->size * 0.01f;
+ return rd_->size * 0.01f;
}
Size2f get_render_size() const;
diff --git a/source/blender/compositor/intern/COM_ConstantFolder.cc b/source/blender/compositor/intern/COM_ConstantFolder.cc
index 445a9ce7433..f10bee38a6e 100644
--- a/source/blender/compositor/intern/COM_ConstantFolder.cc
+++ b/source/blender/compositor/intern/COM_ConstantFolder.cc
@@ -16,10 +16,11 @@
* Copyright 2021, Blender Foundation.
*/
-#include "BLI_rect.h"
+#include "BLI_map.hh"
+#include "BLI_set.hh"
#include "COM_ConstantFolder.h"
-#include "COM_ConstantOperation.h"
+#include "COM_NodeOperationBuilder.h"
#include "COM_SetColorOperation.h"
#include "COM_SetValueOperation.h"
#include "COM_SetVectorOperation.h"
@@ -27,12 +28,6 @@
namespace blender::compositor {
-using Link = NodeOperationBuilder::Link;
-
-/**
- * \param operations_builder: Contains all operations to fold.
- * \param exec_system: Execution system.
- */
ConstantFolder::ConstantFolder(NodeOperationBuilder &operations_builder)
: operations_builder_(operations_builder)
{
@@ -43,7 +38,7 @@ ConstantFolder::ConstantFolder(NodeOperationBuilder &operations_builder)
static bool is_constant_foldable(NodeOperation *operation)
{
if (operation->get_flags().can_be_constant && !operation->get_flags().is_constant_operation) {
- for (int i = 0; i < operation->getNumberOfInputSockets(); i++) {
+ for (int i = 0; i < operation->get_number_of_input_sockets(); i++) {
NodeOperation *input = operation->get_input_operation(i);
if (!input->get_flags().is_constant_operation ||
!static_cast<ConstantOperation *>(input)->can_get_constant_elem()) {
@@ -71,17 +66,17 @@ static ConstantOperation *create_constant_operation(DataType data_type, const fl
switch (data_type) {
case DataType::Color: {
SetColorOperation *color_op = new SetColorOperation();
- color_op->setChannels(constant_elem);
+ color_op->set_channels(constant_elem);
return color_op;
}
case DataType::Vector: {
SetVectorOperation *vector_op = new SetVectorOperation();
- vector_op->setVector(constant_elem);
+ vector_op->set_vector(constant_elem);
return vector_op;
}
case DataType::Value: {
SetValueOperation *value_op = new SetValueOperation();
- value_op->setValue(*constant_elem);
+ value_op->set_value(*constant_elem);
return value_op;
}
default: {
@@ -93,7 +88,7 @@ static ConstantOperation *create_constant_operation(DataType data_type, const fl
ConstantOperation *ConstantFolder::fold_operation(NodeOperation *operation)
{
- const DataType data_type = operation->getOutputSocket()->getDataType();
+ const DataType data_type = operation->get_output_socket()->get_data_type();
MemoryBuffer fold_buf(data_type, first_elem_area_);
Vector<MemoryBuffer *> input_bufs = get_constant_input_buffers(operation);
operation->init_data();
@@ -101,7 +96,8 @@ ConstantOperation *ConstantFolder::fold_operation(NodeOperation *operation)
MemoryBuffer *constant_buf = create_constant_buffer(data_type);
constant_buf->copy_from(&fold_buf, first_elem_area_);
- ConstantOperation *constant_op = create_constant_operation(data_type, constant_buf->getBuffer());
+ ConstantOperation *constant_op = create_constant_operation(data_type,
+ constant_buf->get_buffer());
operations_builder_.replace_operation_with_constant(operation, constant_op);
constant_buffers_.add_new(constant_op, constant_buf);
return constant_op;
@@ -116,14 +112,15 @@ MemoryBuffer *ConstantFolder::create_constant_buffer(const DataType data_type)
Vector<MemoryBuffer *> ConstantFolder::get_constant_input_buffers(NodeOperation *operation)
{
- const int num_inputs = operation->getNumberOfInputSockets();
+ const int num_inputs = operation->get_number_of_input_sockets();
Vector<MemoryBuffer *> inputs_bufs(num_inputs);
for (int i = 0; i < num_inputs; i++) {
BLI_assert(operation->get_input_operation(i)->get_flags().is_constant_operation);
ConstantOperation *constant_op = static_cast<ConstantOperation *>(
operation->get_input_operation(i));
MemoryBuffer *constant_buf = constant_buffers_.lookup_or_add_cb(constant_op, [=] {
- MemoryBuffer *buf = create_constant_buffer(constant_op->getOutputSocket()->getDataType());
+ MemoryBuffer *buf = create_constant_buffer(
+ constant_op->get_output_socket()->get_data_type());
constant_op->render(buf, {first_elem_area_}, {});
return buf;
});
@@ -132,7 +129,6 @@ Vector<MemoryBuffer *> ConstantFolder::get_constant_input_buffers(NodeOperation
return inputs_bufs;
}
-/** Returns constant operations resulted from folded operations. */
Vector<ConstantOperation *> ConstantFolder::try_fold_operations(Span<NodeOperation *> operations)
{
Set<NodeOperation *> foldable_ops = find_constant_foldable_operations(operations);
@@ -148,9 +144,6 @@ Vector<ConstantOperation *> ConstantFolder::try_fold_operations(Span<NodeOperati
return new_folds;
}
-/**
- * Evaluate operations with constant elements into primitive constant operations.
- */
int ConstantFolder::fold_operations()
{
WorkScheduler::start(operations_builder_.context());
@@ -183,10 +176,10 @@ void ConstantFolder::delete_constant_buffers()
void ConstantFolder::get_operation_output_operations(NodeOperation *operation,
Vector<NodeOperation *> &r_outputs)
{
- const Vector<Link> &links = operations_builder_.get_links();
- for (const Link &link : links) {
- if (&link.from()->getOperation() == operation) {
- r_outputs.append(&link.to()->getOperation());
+ const Vector<NodeOperationBuilder::Link> &links = operations_builder_.get_links();
+ for (const NodeOperationBuilder::Link &link : links) {
+ if (&link.from()->get_operation() == operation) {
+ r_outputs.append(&link.to()->get_operation());
}
}
}
diff --git a/source/blender/compositor/intern/COM_ConstantFolder.h b/source/blender/compositor/intern/COM_ConstantFolder.h
index 2432e859a5a..972dbf0e125 100644
--- a/source/blender/compositor/intern/COM_ConstantFolder.h
+++ b/source/blender/compositor/intern/COM_ConstantFolder.h
@@ -18,16 +18,12 @@
#pragma once
-#include "BLI_map.hh"
-#include "BLI_set.hh"
-#include "BLI_vector.hh"
-
-#include "COM_NodeOperationBuilder.h"
#include "COM_defines.h"
namespace blender::compositor {
class NodeOperation;
+class NodeOperationBuilder;
class ConstantOperation;
class MemoryBuffer;
@@ -46,10 +42,18 @@ class ConstantFolder {
rcti first_elem_area_;
public:
+ /**
+ * \param operations_builder: Contains all operations to fold.
+ * \param exec_system: Execution system.
+ */
ConstantFolder(NodeOperationBuilder &operations_builder);
+ /**
+ * Evaluate operations with constant elements into primitive constant operations.
+ */
int fold_operations();
private:
+ /** Returns constant operations resulted from folded operations. */
Vector<ConstantOperation *> try_fold_operations(Span<NodeOperation *> operations);
ConstantOperation *fold_operation(NodeOperation *operation);
diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc
index ee77beb8a82..6cf6c698a2f 100644
--- a/source/blender/compositor/intern/COM_Converter.cc
+++ b/source/blender/compositor/intern/COM_Converter.cc
@@ -22,7 +22,6 @@
#include "BKE_node.h"
-#include "COM_NodeOperation.h"
#include "COM_NodeOperationBuilder.h"
#include "COM_AlphaOverNode.h"
@@ -47,6 +46,7 @@
#include "COM_CombineColorNode.h"
#include "COM_CompositorNode.h"
#include "COM_ConvertAlphaNode.h"
+#include "COM_ConvertColorSpaceNode.h"
#include "COM_ConvertOperation.h"
#include "COM_Converter.h"
#include "COM_CornerPinNode.h"
@@ -62,7 +62,6 @@
#include "COM_DistanceMatteNode.h"
#include "COM_DoubleEdgeMaskNode.h"
#include "COM_EllipseMaskNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_FilterNode.h"
#include "COM_FlipNode.h"
#include "COM_GammaNode.h"
@@ -95,6 +94,7 @@
#include "COM_RotateNode.h"
#include "COM_ScaleNode.h"
#include "COM_ScaleOperation.h"
+#include "COM_SceneTimeNode.h"
#include "COM_SeparateColorNode.h"
#include "COM_SetAlphaNode.h"
#include "COM_SetValueOperation.h"
@@ -361,6 +361,9 @@ Node *COM_convert_bnode(bNode *b_node)
case CMP_NODE_TRANSFORM:
node = new TransformNode(b_node);
break;
+ case CMP_NODE_SCENE_TIME:
+ node = new SceneTimeNode(b_node);
+ break;
case CMP_NODE_STABILIZE2D:
node = new Stabilize2dNode(b_node);
break;
@@ -428,6 +431,9 @@ Node *COM_convert_bnode(bNode *b_node)
case CMP_NODE_POSTERIZE:
node = new PosterizeNode(b_node);
break;
+ case CMP_NODE_CONVERT_COLOR_SPACE:
+ node = new ConvertColorSpaceNode(b_node);
+ break;
}
return node;
}
@@ -435,8 +441,8 @@ Node *COM_convert_bnode(bNode *b_node)
/* TODO(jbakker): make this an std::optional<NodeOperation>. */
NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, const NodeOperationInput &to)
{
- const DataType src_data_type = from.getDataType();
- const DataType dst_data_type = to.getDataType();
+ const DataType src_data_type = from.get_data_type();
+ const DataType dst_data_type = to.get_data_type();
if (src_data_type == DataType::Value && dst_data_type == DataType::Color) {
return new ConvertValueToColorOperation();
@@ -461,24 +467,24 @@ NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, const Node
}
void COM_convert_canvas(NodeOperationBuilder &builder,
- NodeOperationOutput *fromSocket,
- NodeOperationInput *toSocket)
+ NodeOperationOutput *from_socket,
+ NodeOperationInput *to_socket)
{
/* Data type conversions are executed before resolutions to ensure convert operations have
* resolution. This method have to ensure same datatypes are linked for new operations. */
- BLI_assert(fromSocket->getDataType() == toSocket->getDataType());
+ BLI_assert(from_socket->get_data_type() == to_socket->get_data_type());
- ResizeMode mode = toSocket->getResizeMode();
+ ResizeMode mode = to_socket->get_resize_mode();
BLI_assert(mode != ResizeMode::None);
- NodeOperation *toOperation = &toSocket->getOperation();
- const float toWidth = toOperation->getWidth();
- const float toHeight = toOperation->getHeight();
- NodeOperation *fromOperation = &fromSocket->getOperation();
- const float fromWidth = fromOperation->getWidth();
- const float fromHeight = fromOperation->getHeight();
- bool doCenter = false;
- bool doScale = false;
+ NodeOperation *to_operation = &to_socket->get_operation();
+ const float to_width = to_operation->get_width();
+ const float to_height = to_operation->get_height();
+ NodeOperation *from_operation = &from_socket->get_operation();
+ const float from_width = from_operation->get_width();
+ const float from_height = from_operation->get_height();
+ bool do_center = false;
+ bool do_scale = false;
float scaleX = 0;
float scaleY = 0;
@@ -487,23 +493,23 @@ void COM_convert_canvas(NodeOperationBuilder &builder,
case ResizeMode::Align:
break;
case ResizeMode::Center:
- doCenter = true;
+ do_center = true;
break;
case ResizeMode::FitWidth:
- doCenter = true;
- doScale = true;
- scaleX = scaleY = toWidth / fromWidth;
+ do_center = true;
+ do_scale = true;
+ scaleX = scaleY = to_width / from_width;
break;
case ResizeMode::FitHeight:
- doCenter = true;
- doScale = true;
- scaleX = scaleY = toHeight / fromHeight;
+ do_center = true;
+ do_scale = true;
+ scaleX = scaleY = to_height / from_height;
break;
case ResizeMode::FitAny:
- doCenter = true;
- doScale = true;
- scaleX = toWidth / fromWidth;
- scaleY = toHeight / fromHeight;
+ do_center = true;
+ do_scale = true;
+ scaleX = to_width / from_width;
+ scaleY = to_height / from_height;
if (scaleX < scaleY) {
scaleX = scaleY;
}
@@ -512,81 +518,82 @@ void COM_convert_canvas(NodeOperationBuilder &builder,
}
break;
case ResizeMode::Stretch:
- doCenter = true;
- doScale = true;
- scaleX = toWidth / fromWidth;
- scaleY = toHeight / fromHeight;
+ do_center = true;
+ do_scale = true;
+ scaleX = to_width / from_width;
+ scaleY = to_height / from_height;
break;
}
- float addX = doCenter ? (toWidth - fromWidth) / 2.0f : 0.0f;
- float addY = doCenter ? (toHeight - fromHeight) / 2.0f : 0.0f;
+ float addX = do_center ? (to_width - from_width) / 2.0f : 0.0f;
+ float addY = do_center ? (to_height - from_height) / 2.0f : 0.0f;
NodeOperation *first = nullptr;
- ScaleOperation *scaleOperation = nullptr;
- if (doScale) {
- scaleOperation = new ScaleRelativeOperation(fromSocket->getDataType());
- scaleOperation->getInputSocket(1)->setResizeMode(ResizeMode::None);
- scaleOperation->getInputSocket(2)->setResizeMode(ResizeMode::None);
- first = scaleOperation;
+ ScaleOperation *scale_operation = nullptr;
+ if (do_scale) {
+ scale_operation = new ScaleRelativeOperation(from_socket->get_data_type());
+ scale_operation->get_input_socket(1)->set_resize_mode(ResizeMode::None);
+ scale_operation->get_input_socket(2)->set_resize_mode(ResizeMode::None);
+ first = scale_operation;
SetValueOperation *sxop = new SetValueOperation();
- sxop->setValue(scaleX);
- builder.addLink(sxop->getOutputSocket(), scaleOperation->getInputSocket(1));
+ sxop->set_value(scaleX);
+ builder.add_link(sxop->get_output_socket(), scale_operation->get_input_socket(1));
SetValueOperation *syop = new SetValueOperation();
- syop->setValue(scaleY);
- builder.addLink(syop->getOutputSocket(), scaleOperation->getInputSocket(2));
- builder.addOperation(sxop);
- builder.addOperation(syop);
+ syop->set_value(scaleY);
+ builder.add_link(syop->get_output_socket(), scale_operation->get_input_socket(2));
+ builder.add_operation(sxop);
+ builder.add_operation(syop);
- rcti scale_canvas = fromOperation->get_canvas();
+ rcti scale_canvas = from_operation->get_canvas();
if (builder.context().get_execution_model() == eExecutionModel::FullFrame) {
ScaleOperation::scale_area(scale_canvas, scaleX, scaleY);
- scale_canvas.xmax = scale_canvas.xmin + toOperation->getWidth();
- scale_canvas.ymax = scale_canvas.ymin + toOperation->getHeight();
+ scale_canvas.xmax = scale_canvas.xmin + to_operation->get_width();
+ scale_canvas.ymax = scale_canvas.ymin + to_operation->get_height();
addX = 0;
addY = 0;
}
- scaleOperation->set_canvas(scale_canvas);
+ scale_operation->set_canvas(scale_canvas);
sxop->set_canvas(scale_canvas);
syop->set_canvas(scale_canvas);
- builder.addOperation(scaleOperation);
+ builder.add_operation(scale_operation);
}
- TranslateOperation *translateOperation = new TranslateOperation(toSocket->getDataType());
- translateOperation->getInputSocket(1)->setResizeMode(ResizeMode::None);
- translateOperation->getInputSocket(2)->setResizeMode(ResizeMode::None);
+ TranslateOperation *translate_operation = new TranslateOperation(to_socket->get_data_type());
+ translate_operation->get_input_socket(1)->set_resize_mode(ResizeMode::None);
+ translate_operation->get_input_socket(2)->set_resize_mode(ResizeMode::None);
if (!first) {
- first = translateOperation;
+ first = translate_operation;
}
SetValueOperation *xop = new SetValueOperation();
- xop->setValue(addX);
- builder.addLink(xop->getOutputSocket(), translateOperation->getInputSocket(1));
+ xop->set_value(addX);
+ builder.add_link(xop->get_output_socket(), translate_operation->get_input_socket(1));
SetValueOperation *yop = new SetValueOperation();
- yop->setValue(addY);
- builder.addLink(yop->getOutputSocket(), translateOperation->getInputSocket(2));
- builder.addOperation(xop);
- builder.addOperation(yop);
+ yop->set_value(addY);
+ builder.add_link(yop->get_output_socket(), translate_operation->get_input_socket(2));
+ builder.add_operation(xop);
+ builder.add_operation(yop);
- rcti translate_canvas = toOperation->get_canvas();
+ rcti translate_canvas = to_operation->get_canvas();
if (mode == ResizeMode::Align) {
- translate_canvas.xmax = translate_canvas.xmin + fromWidth;
- translate_canvas.ymax = translate_canvas.ymin + fromHeight;
+ translate_canvas.xmax = translate_canvas.xmin + from_width;
+ translate_canvas.ymax = translate_canvas.ymin + from_height;
}
- translateOperation->set_canvas(translate_canvas);
+ translate_operation->set_canvas(translate_canvas);
xop->set_canvas(translate_canvas);
yop->set_canvas(translate_canvas);
- builder.addOperation(translateOperation);
+ builder.add_operation(translate_operation);
- if (doScale) {
- translateOperation->getInputSocket(0)->setResizeMode(ResizeMode::None);
- builder.addLink(scaleOperation->getOutputSocket(), translateOperation->getInputSocket(0));
+ if (do_scale) {
+ translate_operation->get_input_socket(0)->set_resize_mode(ResizeMode::None);
+ builder.add_link(scale_operation->get_output_socket(),
+ translate_operation->get_input_socket(0));
}
/* remove previous link and replace */
- builder.removeInputLink(toSocket);
- first->getInputSocket(0)->setResizeMode(ResizeMode::None);
- toSocket->setResizeMode(ResizeMode::None);
- builder.addLink(fromSocket, first->getInputSocket(0));
- builder.addLink(translateOperation->getOutputSocket(), toSocket);
+ builder.remove_input_link(to_socket);
+ first->get_input_socket(0)->set_resize_mode(ResizeMode::None);
+ to_socket->set_resize_mode(ResizeMode::None);
+ builder.add_link(from_socket, first->get_input_socket(0));
+ builder.add_link(translate_operation->get_output_socket(), to_socket);
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_Converter.h b/source/blender/compositor/intern/COM_Converter.h
index 7f0402d4e70..39bd44e8a9f 100644
--- a/source/blender/compositor/intern/COM_Converter.h
+++ b/source/blender/compositor/intern/COM_Converter.h
@@ -18,8 +18,6 @@
#pragma once
-#include "COM_NodeOperation.h"
-
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
@@ -29,6 +27,7 @@ struct bNode;
namespace blender::compositor {
class Node;
+class NodeOperation;
class NodeOperationInput;
class NodeOperationOutput;
class NodeOperationBuilder;
@@ -66,7 +65,7 @@ NodeOperation *COM_convert_data_type(const NodeOperationOutput &from,
* \see InputSocketResizeMode for the possible conversions.
*/
void COM_convert_canvas(NodeOperationBuilder &builder,
- NodeOperationOutput *fromSocket,
- NodeOperationInput *toSocket);
+ NodeOperationOutput *from_socket,
+ NodeOperationInput *to_socket);
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc
index 9e47aa9fcb5..8525e2fde50 100644
--- a/source/blender/compositor/intern/COM_Debug.cc
+++ b/source/blender/compositor/intern/COM_Debug.cc
@@ -18,26 +18,16 @@
#include "COM_Debug.h"
-#include <map>
-#include <typeinfo>
-#include <vector>
-
extern "C" {
#include "BLI_fileops.h"
#include "BLI_path_util.h"
-#include "BLI_string.h"
-#include "BLI_sys_types.h"
#include "BKE_appdir.h"
-#include "BKE_node.h"
-#include "DNA_node_types.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
}
-#include "COM_ExecutionSystem.h"
-#include "COM_Node.h"
-
+#include "COM_ExecutionGroup.h"
#include "COM_ReadBufferOperation.h"
#include "COM_SetValueOperation.h"
#include "COM_ViewerOperation.h"
@@ -45,12 +35,12 @@ extern "C" {
namespace blender::compositor {
-int DebugInfo::m_file_index = 0;
-DebugInfo::NodeNameMap DebugInfo::m_node_names;
-DebugInfo::OpNameMap DebugInfo::m_op_names;
-std::string DebugInfo::m_current_node_name;
-std::string DebugInfo::m_current_op_name;
-DebugInfo::GroupStateMap DebugInfo::m_group_states;
+int DebugInfo::file_index_ = 0;
+DebugInfo::NodeNameMap DebugInfo::node_names_;
+DebugInfo::OpNameMap DebugInfo::op_names_;
+std::string DebugInfo::current_node_name_;
+std::string DebugInfo::current_op_name_;
+DebugInfo::GroupStateMap DebugInfo::group_states_;
static std::string operation_class_name(const NodeOperation *op)
{
@@ -63,8 +53,8 @@ static std::string operation_class_name(const NodeOperation *op)
std::string DebugInfo::node_name(const Node *node)
{
- NodeNameMap::const_iterator it = m_node_names.find(node);
- if (it != m_node_names.end()) {
+ NodeNameMap::const_iterator it = node_names_.find(node);
+ if (it != node_names_.end()) {
return it->second;
}
return "";
@@ -72,8 +62,8 @@ std::string DebugInfo::node_name(const Node *node)
std::string DebugInfo::operation_name(const NodeOperation *op)
{
- OpNameMap::const_iterator it = m_op_names.find(op);
- if (it != m_op_names.end()) {
+ OpNameMap::const_iterator it = op_names_.find(op);
+ if (it != op_names_.end()) {
return it->second;
}
return "";
@@ -90,14 +80,14 @@ int DebugInfo::graphviz_operation(const ExecutionSystem *system,
std::string fillcolor = "gainsboro";
if (operation->get_flags().is_viewer_operation) {
const ViewerOperation *viewer = (const ViewerOperation *)operation;
- if (viewer->isActiveViewerOutput()) {
+ if (viewer->is_active_viewer_output()) {
fillcolor = "lightskyblue1";
}
else {
fillcolor = "lightskyblue3";
}
}
- else if (operation->isOutputOperation(system->getContext().isRendering())) {
+ else if (operation->is_output_operation(system->get_context().is_rendering())) {
fillcolor = "dodgerblue1";
}
else if (operation->get_flags().is_set_operation) {
@@ -122,16 +112,16 @@ int DebugInfo::graphviz_operation(const ExecutionSystem *system,
" [fillcolor=%s,style=filled,shape=record,label=\"{",
fillcolor.c_str());
- int totinputs = operation->getNumberOfInputSockets();
+ int totinputs = operation->get_number_of_input_sockets();
if (totinputs != 0) {
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "{");
for (int k = 0; k < totinputs; k++) {
- NodeOperationInput *socket = operation->getInputSocket(k);
+ NodeOperationInput *socket = operation->get_input_socket(k);
if (k != 0) {
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|");
}
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<IN_%p>", socket);
- switch (socket->getDataType()) {
+ switch (socket->get_data_type()) {
case DataType::Value:
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Value");
break;
@@ -166,20 +156,20 @@ int DebugInfo::graphviz_operation(const ExecutionSystem *system,
operation->get_id(),
operation->get_canvas().xmin,
operation->get_canvas().ymin,
- operation->getWidth(),
- operation->getHeight());
+ operation->get_width(),
+ operation->get_height());
- int totoutputs = operation->getNumberOfOutputSockets();
+ int totoutputs = operation->get_number_of_output_sockets();
if (totoutputs != 0) {
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|");
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "{");
for (int k = 0; k < totoutputs; k++) {
- NodeOperationOutput *socket = operation->getOutputSocket(k);
+ NodeOperationOutput *socket = operation->get_output_socket(k);
if (k != 0) {
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|");
}
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<OUT_%p>", socket);
- switch (socket->getDataType()) {
+ switch (socket->get_data_type()) {
case DataType::Value: {
ConstantOperation *constant = operation->get_flags().is_constant_operation ?
static_cast<ConstantOperation *>(operation) :
@@ -310,25 +300,25 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
std::map<NodeOperation *, std::vector<std::string>> op_groups;
int index = 0;
- for (const ExecutionGroup *group : system->m_groups) {
+ for (const ExecutionGroup *group : system->groups_) {
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "// GROUP: %d\r\n", index);
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "subgraph cluster_%d{\r\n", index);
/* used as a check for executing group */
- if (m_group_states[group] == EG_WAIT) {
+ if (group_states_[group] == EG_WAIT) {
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "style=dashed\r\n");
}
- else if (m_group_states[group] == EG_RUNNING) {
+ else if (group_states_[group] == EG_RUNNING) {
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "style=filled\r\n");
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "color=black\r\n");
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "fillcolor=firebrick1\r\n");
}
- else if (m_group_states[group] == EG_FINISHED) {
+ else if (group_states_[group] == EG_FINISHED) {
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "style=filled\r\n");
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "color=black\r\n");
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "fillcolor=chartreuse4\r\n");
}
- for (NodeOperation *operation : group->m_operations) {
+ for (NodeOperation *operation : group->operations_) {
sprintf(strbuf, "_%p", group);
op_groups[operation].push_back(std::string(strbuf));
@@ -342,7 +332,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
}
/* operations not included in any group */
- for (NodeOperation *operation : system->m_operations) {
+ for (NodeOperation *operation : system->operations_) {
if (op_groups.find(operation) != op_groups.end()) {
continue;
}
@@ -353,10 +343,10 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
system, operation, nullptr, str + len, maxlen > len ? maxlen - len : 0);
}
- for (NodeOperation *operation : system->m_operations) {
+ for (NodeOperation *operation : system->operations_) {
if (operation->get_flags().is_read_buffer_operation) {
ReadBufferOperation *read = (ReadBufferOperation *)operation;
- WriteBufferOperation *write = read->getMemoryProxy()->getWriteBufferOperation();
+ WriteBufferOperation *write = read->get_memory_proxy()->get_write_buffer_operation();
std::vector<std::string> &read_groups = op_groups[read];
std::vector<std::string> &write_groups = op_groups[write];
@@ -374,16 +364,16 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
}
}
- for (NodeOperation *op : system->m_operations) {
- for (NodeOperationInput &to : op->m_inputs) {
- NodeOperationOutput *from = to.getLink();
+ for (NodeOperation *op : system->operations_) {
+ for (NodeOperationInput &to : op->inputs_) {
+ NodeOperationOutput *from = to.get_link();
if (!from) {
continue;
}
std::string color;
- switch (from->getDataType()) {
+ switch (from->get_data_type()) {
case DataType::Value:
color = "gray";
break;
@@ -395,8 +385,8 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
break;
}
- NodeOperation *to_op = &to.getOperation();
- NodeOperation *from_op = &from->getOperation();
+ NodeOperation *to_op = &to.get_operation();
+ NodeOperation *from_op = &from->get_operation();
std::vector<std::string> &from_groups = op_groups[from_op];
std::vector<std::string> &to_groups = op_groups[to_op];
@@ -426,9 +416,9 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
}
}
- const bool has_execution_groups = system->getContext().get_execution_model() ==
+ const bool has_execution_groups = system->get_context().get_execution_model() ==
eExecutionModel::Tiled &&
- system->m_groups.size() > 0;
+ system->groups_.size() > 0;
len += graphviz_legend(str + len, maxlen > len ? maxlen - len : 0, has_execution_groups);
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\r\n");
@@ -441,19 +431,20 @@ void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name)
if (!COM_EXPORT_GRAPHVIZ) {
return;
}
- char str[1000000];
- if (graphviz_system(system, str, sizeof(str) - 1)) {
+ const int max_textlength = 1000000;
+ char *str = (char *)MEM_mallocN(max_textlength, __func__);
+ if (graphviz_system(system, str, max_textlength - 1)) {
char basename[FILE_MAX];
char filename[FILE_MAX];
if (name.is_empty()) {
- BLI_snprintf(basename, sizeof(basename), "compositor_%d.dot", m_file_index);
+ BLI_snprintf(basename, sizeof(basename), "compositor_%d.dot", file_index_);
}
else {
BLI_strncpy(basename, (name + ".dot").c_str(), sizeof(basename));
}
BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_session(), basename);
- m_file_index++;
+ file_index_++;
std::cout << "Writing compositor debug to: " << filename << "\n";
@@ -461,6 +452,7 @@ void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name)
fputs(str, fp);
fclose(fp);
}
+ MEM_freeN(str);
}
static std::string get_operations_export_dir()
@@ -470,8 +462,8 @@ static std::string get_operations_export_dir()
void DebugInfo::export_operation(const NodeOperation *op, MemoryBuffer *render)
{
- const int width = render->getWidth();
- const int height = render->getHeight();
+ const int width = render->get_width();
+ const int height = render->get_height();
const int num_channels = render->get_num_channels();
ImBuf *ibuf = IMB_allocImBuf(width, height, 8 * num_channels, IB_rectfloat);
diff --git a/source/blender/compositor/intern/COM_Debug.h b/source/blender/compositor/intern/COM_Debug.h
index 23d99c7e529..021d6e744fb 100644
--- a/source/blender/compositor/intern/COM_Debug.h
+++ b/source/blender/compositor/intern/COM_Debug.h
@@ -21,9 +21,11 @@
#include <map>
#include <string>
+#include "BLI_vector.hh"
+
#include "COM_ExecutionSystem.h"
-#include "COM_NodeOperation.h"
-#include "COM_defines.h"
+#include "COM_MemoryBuffer.h"
+#include "COM_Node.h"
namespace blender::compositor {
@@ -34,6 +36,7 @@ static constexpr bool COM_GRAPHVIZ_SHOW_NODE_NAME = false;
static constexpr bool COM_EXPORT_OPERATION_BUFFERS = false;
class Node;
+class NodeOperation;
class ExecutionSystem;
class ExecutionGroup;
@@ -49,33 +52,33 @@ class DebugInfo {
static std::string operation_name(const NodeOperation *op);
private:
- static int m_file_index;
+ static int file_index_;
/** Map nodes to usable names for debug output. */
- static NodeNameMap m_node_names;
+ static NodeNameMap node_names_;
/** Map operations to usable names for debug output. */
- static OpNameMap m_op_names;
+ static OpNameMap op_names_;
/** Base name for all operations added by a node. */
- static std::string m_current_node_name;
+ static std::string current_node_name_;
/** Base name for automatic sub-operations. */
- static std::string m_current_op_name;
+ static std::string current_op_name_;
/** For visualizing group states. */
- static GroupStateMap m_group_states;
+ static GroupStateMap group_states_;
public:
static void convert_started()
{
if (COM_EXPORT_GRAPHVIZ) {
- m_op_names.clear();
+ op_names_.clear();
}
}
static void execute_started(const ExecutionSystem *system)
{
if (COM_EXPORT_GRAPHVIZ) {
- m_file_index = 1;
- m_group_states.clear();
- for (ExecutionGroup *execution_group : system->m_groups) {
- m_group_states[execution_group] = EG_WAIT;
+ file_index_ = 1;
+ group_states_.clear();
+ for (ExecutionGroup *execution_group : system->groups_) {
+ group_states_[execution_group] = EG_WAIT;
}
}
if (COM_EXPORT_OPERATION_BUFFERS) {
@@ -86,41 +89,41 @@ class DebugInfo {
static void node_added(const Node *node)
{
if (COM_EXPORT_GRAPHVIZ) {
- m_node_names[node] = std::string(node->getbNode() ? node->getbNode()->name : "");
+ node_names_[node] = std::string(node->get_bnode() ? node->get_bnode()->name : "");
}
}
static void node_to_operations(const Node *node)
{
if (COM_EXPORT_GRAPHVIZ) {
- m_current_node_name = m_node_names[node];
+ current_node_name_ = node_names_[node];
}
}
static void operation_added(const NodeOperation *operation)
{
if (COM_EXPORT_GRAPHVIZ) {
- m_op_names[operation] = m_current_node_name;
+ op_names_[operation] = current_node_name_;
}
};
static void operation_read_write_buffer(const NodeOperation *operation)
{
if (COM_EXPORT_GRAPHVIZ) {
- m_current_op_name = m_op_names[operation];
+ current_op_name_ = op_names_[operation];
}
};
static void execution_group_started(const ExecutionGroup *group)
{
if (COM_EXPORT_GRAPHVIZ) {
- m_group_states[group] = EG_RUNNING;
+ group_states_[group] = EG_RUNNING;
}
};
static void execution_group_finished(const ExecutionGroup *group)
{
if (COM_EXPORT_GRAPHVIZ) {
- m_group_states[group] = EG_FINISHED;
+ group_states_[group] = EG_FINISHED;
}
};
diff --git a/source/blender/compositor/intern/COM_Device.h b/source/blender/compositor/intern/COM_Device.h
index c848672a405..a409ddf97a5 100644
--- a/source/blender/compositor/intern/COM_Device.h
+++ b/source/blender/compositor/intern/COM_Device.h
@@ -18,10 +18,14 @@
#pragma once
-#include "COM_WorkPackage.h"
+#ifdef WITH_CXX_GUARDEDALLOC
+# include "MEM_guardedalloc.h"
+#endif
namespace blender::compositor {
+struct WorkPackage;
+
/**
* \brief Abstract class for device implementations to be used by the Compositor.
* devices are queried, initialized and used by the WorkScheduler.
diff --git a/source/blender/compositor/intern/COM_Enums.cc b/source/blender/compositor/intern/COM_Enums.cc
index 2f20d2652ba..63a5a78436b 100644
--- a/source/blender/compositor/intern/COM_Enums.cc
+++ b/source/blender/compositor/intern/COM_Enums.cc
@@ -17,7 +17,6 @@
*/
#include "COM_Enums.h"
-#include "BLI_rect.h"
namespace blender::compositor {
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cc b/source/blender/compositor/intern/COM_ExecutionGroup.cc
index 505a4066a25..63ca642d52d 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.cc
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.cc
@@ -16,36 +16,21 @@
* Copyright 2011, Blender Foundation.
*/
-#include <algorithm>
-#include <cmath>
-#include <cstdlib>
-#include <sstream>
-
-#include "atomic_ops.h"
-
+#include "COM_ExecutionGroup.h"
#include "COM_ChunkOrder.h"
#include "COM_Debug.h"
-#include "COM_ExecutionGroup.h"
-#include "COM_ExecutionSystem.h"
#include "COM_ReadBufferOperation.h"
#include "COM_ViewerOperation.h"
#include "COM_WorkScheduler.h"
#include "COM_WriteBufferOperation.h"
#include "COM_defines.h"
-#include "BLI_math.h"
#include "BLI_rand.hh"
-#include "BLI_string.h"
#include "BLT_translation.h"
-#include "MEM_guardedalloc.h"
-
#include "PIL_time.h"
-#include "WM_api.h"
-#include "WM_types.h"
-
namespace blender::compositor {
std::ostream &operator<<(std::ostream &os, const ExecutionGroupFlags &flags)
@@ -70,36 +55,36 @@ std::ostream &operator<<(std::ostream &os, const ExecutionGroupFlags &flags)
ExecutionGroup::ExecutionGroup(int id)
{
- m_id = id;
- this->m_bTree = nullptr;
- this->m_height = 0;
- this->m_width = 0;
- this->m_max_read_buffer_offset = 0;
- this->m_x_chunks_len = 0;
- this->m_y_chunks_len = 0;
- this->m_chunks_len = 0;
- this->m_chunks_finished = 0;
- BLI_rcti_init(&this->m_viewerBorder, 0, 0, 0, 0);
- this->m_executionStartTime = 0;
+ id_ = id;
+ bTree_ = nullptr;
+ height_ = 0;
+ width_ = 0;
+ max_read_buffer_offset_ = 0;
+ x_chunks_len_ = 0;
+ y_chunks_len_ = 0;
+ chunks_len_ = 0;
+ chunks_finished_ = 0;
+ BLI_rcti_init(&viewer_border_, 0, 0, 0, 0);
+ execution_start_time_ = 0;
}
std::ostream &operator<<(std::ostream &os, const ExecutionGroup &execution_group)
{
os << "ExecutionGroup(id=" << execution_group.get_id();
os << ",flags={" << execution_group.get_flags() << "}";
- os << ",operation=" << *execution_group.getOutputOperation() << "";
+ os << ",operation=" << *execution_group.get_output_operation() << "";
os << ")";
return os;
}
-eCompositorPriority ExecutionGroup::getRenderPriority()
+eCompositorPriority ExecutionGroup::get_render_priority()
{
- return this->getOutputOperation()->getRenderPriority();
+ return this->get_output_operation()->get_render_priority();
}
bool ExecutionGroup::can_contain(NodeOperation &operation)
{
- if (!m_flags.initialized) {
+ if (!flags_.initialized) {
return true;
}
@@ -114,7 +99,7 @@ bool ExecutionGroup::can_contain(NodeOperation &operation)
}
/* complex groups don't allow further ops (except read buffer and values, see above) */
- if (m_flags.complex) {
+ if (flags_.complex) {
return false;
}
/* complex ops can't be added to other groups (except their own, which they initialize, see
@@ -126,7 +111,7 @@ bool ExecutionGroup::can_contain(NodeOperation &operation)
return true;
}
-bool ExecutionGroup::addOperation(NodeOperation *operation)
+bool ExecutionGroup::add_operation(NodeOperation *operation)
{
if (!can_contain(*operation)) {
return false;
@@ -134,34 +119,34 @@ bool ExecutionGroup::addOperation(NodeOperation *operation)
if (!operation->get_flags().is_read_buffer_operation &&
!operation->get_flags().is_write_buffer_operation) {
- m_flags.complex = operation->get_flags().complex;
- m_flags.open_cl = operation->get_flags().open_cl;
- m_flags.single_threaded = operation->get_flags().single_threaded;
- m_flags.initialized = true;
+ flags_.complex = operation->get_flags().complex;
+ flags_.open_cl = operation->get_flags().open_cl;
+ flags_.single_threaded = operation->get_flags().single_threaded;
+ flags_.initialized = true;
}
- m_operations.append(operation);
+ operations_.append(operation);
return true;
}
-NodeOperation *ExecutionGroup::getOutputOperation() const
+NodeOperation *ExecutionGroup::get_output_operation() const
{
return this
- ->m_operations[0]; /* the first operation of the group is always the output operation. */
+ ->operations_[0]; /* the first operation of the group is always the output operation. */
}
void ExecutionGroup::init_work_packages()
{
- m_work_packages.clear();
- if (this->m_chunks_len != 0) {
- m_work_packages.resize(this->m_chunks_len);
- for (unsigned int index = 0; index < m_chunks_len; index++) {
- m_work_packages[index].type = eWorkPackageType::Tile;
- m_work_packages[index].state = eWorkPackageState::NotScheduled;
- m_work_packages[index].execution_group = this;
- m_work_packages[index].chunk_number = index;
- determineChunkRect(&m_work_packages[index].rect, index);
+ work_packages_.clear();
+ if (chunks_len_ != 0) {
+ work_packages_.resize(chunks_len_);
+ for (unsigned int index = 0; index < chunks_len_; index++) {
+ work_packages_[index].type = eWorkPackageType::Tile;
+ work_packages_[index].state = eWorkPackageState::NotScheduled;
+ work_packages_[index].execution_group = this;
+ work_packages_[index].chunk_number = index;
+ determine_chunk_rect(&work_packages_[index].rect, index);
}
}
}
@@ -169,68 +154,68 @@ void ExecutionGroup::init_work_packages()
void ExecutionGroup::init_read_buffer_operations()
{
unsigned int max_offset = 0;
- for (NodeOperation *operation : m_operations) {
+ for (NodeOperation *operation : operations_) {
if (operation->get_flags().is_read_buffer_operation) {
- ReadBufferOperation *readOperation = static_cast<ReadBufferOperation *>(operation);
- this->m_read_operations.append(readOperation);
- max_offset = MAX2(max_offset, readOperation->getOffset());
+ ReadBufferOperation *read_operation = static_cast<ReadBufferOperation *>(operation);
+ read_operations_.append(read_operation);
+ max_offset = MAX2(max_offset, read_operation->get_offset());
}
}
max_offset++;
- this->m_max_read_buffer_offset = max_offset;
+ max_read_buffer_offset_ = max_offset;
}
-void ExecutionGroup::initExecution()
+void ExecutionGroup::init_execution()
{
init_number_of_chunks();
init_work_packages();
init_read_buffer_operations();
}
-void ExecutionGroup::deinitExecution()
+void ExecutionGroup::deinit_execution()
{
- m_work_packages.clear();
- this->m_chunks_len = 0;
- this->m_x_chunks_len = 0;
- this->m_y_chunks_len = 0;
- this->m_read_operations.clear();
- this->m_bTree = nullptr;
+ work_packages_.clear();
+ chunks_len_ = 0;
+ x_chunks_len_ = 0;
+ y_chunks_len_ = 0;
+ read_operations_.clear();
+ bTree_ = nullptr;
}
-void ExecutionGroup::determineResolution(unsigned int resolution[2])
+void ExecutionGroup::determine_resolution(unsigned int resolution[2])
{
- NodeOperation *operation = this->getOutputOperation();
- resolution[0] = operation->getWidth();
- resolution[1] = operation->getHeight();
- this->setResolution(resolution);
- BLI_rcti_init(&this->m_viewerBorder, 0, this->m_width, 0, this->m_height);
+ NodeOperation *operation = this->get_output_operation();
+ resolution[0] = operation->get_width();
+ resolution[1] = operation->get_height();
+ this->set_resolution(resolution);
+ BLI_rcti_init(&viewer_border_, 0, width_, 0, height_);
}
void ExecutionGroup::init_number_of_chunks()
{
- if (this->m_flags.single_threaded) {
- this->m_x_chunks_len = 1;
- this->m_y_chunks_len = 1;
- this->m_chunks_len = 1;
+ if (flags_.single_threaded) {
+ x_chunks_len_ = 1;
+ y_chunks_len_ = 1;
+ chunks_len_ = 1;
}
else {
- const float chunkSizef = this->m_chunkSize;
- const int border_width = BLI_rcti_size_x(&this->m_viewerBorder);
- const int border_height = BLI_rcti_size_y(&this->m_viewerBorder);
- this->m_x_chunks_len = ceil(border_width / chunkSizef);
- this->m_y_chunks_len = ceil(border_height / chunkSizef);
- this->m_chunks_len = this->m_x_chunks_len * this->m_y_chunks_len;
+ const float chunk_sizef = chunk_size_;
+ const int border_width = BLI_rcti_size_x(&viewer_border_);
+ const int border_height = BLI_rcti_size_y(&viewer_border_);
+ x_chunks_len_ = ceil(border_width / chunk_sizef);
+ y_chunks_len_ = ceil(border_height / chunk_sizef);
+ chunks_len_ = x_chunks_len_ * y_chunks_len_;
}
}
blender::Array<unsigned int> ExecutionGroup::get_execution_order() const
{
- blender::Array<unsigned int> chunk_order(m_chunks_len);
- for (int chunk_index = 0; chunk_index < this->m_chunks_len; chunk_index++) {
+ blender::Array<unsigned int> chunk_order(chunks_len_);
+ for (int chunk_index = 0; chunk_index < chunks_len_; chunk_index++) {
chunk_order[chunk_index] = chunk_index;
}
- NodeOperation *operation = this->getOutputOperation();
+ NodeOperation *operation = this->get_output_operation();
float centerX = 0.5f;
float centerY = 0.5f;
ChunkOrdering order_type = ChunkOrdering::Default;
@@ -239,11 +224,11 @@ blender::Array<unsigned int> ExecutionGroup::get_execution_order() const
ViewerOperation *viewer = (ViewerOperation *)operation;
centerX = viewer->getCenterX();
centerY = viewer->getCenterY();
- order_type = viewer->getChunkOrder();
+ order_type = viewer->get_chunk_order();
}
- const int border_width = BLI_rcti_size_x(&this->m_viewerBorder);
- const int border_height = BLI_rcti_size_y(&this->m_viewerBorder);
+ const int border_width = BLI_rcti_size_x(&viewer_border_);
+ const int border_height = BLI_rcti_size_y(&viewer_border_);
int index;
switch (order_type) {
case ChunkOrdering::Random: {
@@ -256,17 +241,17 @@ blender::Array<unsigned int> ExecutionGroup::get_execution_order() const
}
case ChunkOrdering::CenterOut: {
ChunkOrderHotspot hotspot(border_width * centerX, border_height * centerY, 0.0f);
- blender::Array<ChunkOrder> chunk_orders(m_chunks_len);
- for (index = 0; index < this->m_chunks_len; index++) {
- const WorkPackage &work_package = m_work_packages[index];
+ blender::Array<ChunkOrder> chunk_orders(chunks_len_);
+ for (index = 0; index < chunks_len_; index++) {
+ const WorkPackage &work_package = work_packages_[index];
chunk_orders[index].index = index;
- chunk_orders[index].x = work_package.rect.xmin - this->m_viewerBorder.xmin;
- chunk_orders[index].y = work_package.rect.ymin - this->m_viewerBorder.ymin;
+ chunk_orders[index].x = work_package.rect.xmin - viewer_border_.xmin;
+ chunk_orders[index].y = work_package.rect.ymin - viewer_border_.ymin;
chunk_orders[index].update_distance(&hotspot, 1);
}
- std::sort(&chunk_orders[0], &chunk_orders[this->m_chunks_len - 1]);
- for (index = 0; index < this->m_chunks_len; index++) {
+ std::sort(&chunk_orders[0], &chunk_orders[chunks_len_ - 1]);
+ for (index = 0; index < chunks_len_; index++) {
chunk_order[index] = chunk_orders[index].index;
}
@@ -279,7 +264,7 @@ blender::Array<unsigned int> ExecutionGroup::get_execution_order() const
unsigned int my = border_height / 2;
unsigned int bx = mx + 2 * tx;
unsigned int by = my + 2 * ty;
- float addition = this->m_chunks_len / COM_RULE_OF_THIRDS_DIVIDER;
+ float addition = chunks_len_ / COM_RULE_OF_THIRDS_DIVIDER;
ChunkOrderHotspot hotspots[9]{
ChunkOrderHotspot(mx, my, addition * 0),
@@ -293,18 +278,18 @@ blender::Array<unsigned int> ExecutionGroup::get_execution_order() const
ChunkOrderHotspot(mx, by, addition * 8),
};
- blender::Array<ChunkOrder> chunk_orders(m_chunks_len);
- for (index = 0; index < this->m_chunks_len; index++) {
- const WorkPackage &work_package = m_work_packages[index];
+ blender::Array<ChunkOrder> chunk_orders(chunks_len_);
+ for (index = 0; index < chunks_len_; index++) {
+ const WorkPackage &work_package = work_packages_[index];
chunk_orders[index].index = index;
- chunk_orders[index].x = work_package.rect.xmin - this->m_viewerBorder.xmin;
- chunk_orders[index].y = work_package.rect.ymin - this->m_viewerBorder.ymin;
+ chunk_orders[index].x = work_package.rect.xmin - viewer_border_.xmin;
+ chunk_orders[index].y = work_package.rect.ymin - viewer_border_.ymin;
chunk_orders[index].update_distance(hotspots, 9);
}
- std::sort(&chunk_orders[0], &chunk_orders[this->m_chunks_len]);
+ std::sort(&chunk_orders[0], &chunk_orders[chunks_len_]);
- for (index = 0; index < this->m_chunks_len; index++) {
+ for (index = 0; index < chunks_len_; index++) {
chunk_order[index] = chunk_orders[index].index;
}
@@ -317,29 +302,25 @@ blender::Array<unsigned int> ExecutionGroup::get_execution_order() const
return chunk_order;
}
-/**
- * this method is called for the top execution groups. containing the compositor node or the
- * preview node or the viewer node)
- */
void ExecutionGroup::execute(ExecutionSystem *graph)
{
- const CompositorContext &context = graph->getContext();
- const bNodeTree *bTree = context.getbNodeTree();
- if (this->m_width == 0 || this->m_height == 0) {
+ const CompositorContext &context = graph->get_context();
+ const bNodeTree *bTree = context.get_bnodetree();
+ if (width_ == 0 || height_ == 0) {
return;
} /** \note Break out... no pixels to calculate. */
if (bTree->test_break && bTree->test_break(bTree->tbh)) {
return;
} /** \note Early break out for blur and preview nodes. */
- if (this->m_chunks_len == 0) {
+ if (chunks_len_ == 0) {
return;
} /** \note Early break out. */
unsigned int chunk_index;
- this->m_executionStartTime = PIL_check_seconds_timer();
+ execution_start_time_ = PIL_check_seconds_timer();
- this->m_chunks_finished = 0;
- this->m_bTree = bTree;
+ chunks_finished_ = 0;
+ bTree_ = bTree;
blender::Array<unsigned int> chunk_order = get_execution_order();
@@ -348,27 +329,26 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
bool breaked = false;
bool finished = false;
- unsigned int startIndex = 0;
- const int maxNumberEvaluated = BLI_system_thread_count() * 2;
+ unsigned int start_index = 0;
+ const int max_number_evaluated = BLI_system_thread_count() * 2;
while (!finished && !breaked) {
- bool startEvaluated = false;
+ bool start_evaluated = false;
finished = true;
- int numberEvaluated = 0;
+ int number_evaluated = 0;
- for (int index = startIndex;
- index < this->m_chunks_len && numberEvaluated < maxNumberEvaluated;
+ for (int index = start_index; index < chunks_len_ && number_evaluated < max_number_evaluated;
index++) {
chunk_index = chunk_order[index];
- int yChunk = chunk_index / this->m_x_chunks_len;
- int xChunk = chunk_index - (yChunk * this->m_x_chunks_len);
- const WorkPackage &work_package = m_work_packages[chunk_index];
+ int y_chunk = chunk_index / x_chunks_len_;
+ int x_chunk = chunk_index - (y_chunk * x_chunks_len_);
+ const WorkPackage &work_package = work_packages_[chunk_index];
switch (work_package.state) {
case eWorkPackageState::NotScheduled: {
- scheduleChunkWhenPossible(graph, xChunk, yChunk);
+ schedule_chunk_when_possible(graph, x_chunk, y_chunk);
finished = false;
- startEvaluated = true;
- numberEvaluated++;
+ start_evaluated = true;
+ number_evaluated++;
if (bTree->update_draw) {
bTree->update_draw(bTree->udh);
@@ -377,13 +357,13 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
}
case eWorkPackageState::Scheduled: {
finished = false;
- startEvaluated = true;
- numberEvaluated++;
+ start_evaluated = true;
+ number_evaluated++;
break;
}
case eWorkPackageState::Executed: {
- if (!startEvaluated) {
- startIndex = index + 1;
+ if (!start_evaluated) {
+ start_index = index + 1;
}
}
};
@@ -399,139 +379,135 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
DebugInfo::graphviz(graph);
}
-MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber)
+MemoryBuffer **ExecutionGroup::get_input_buffers_opencl(int chunk_number)
{
- WorkPackage &work_package = m_work_packages[chunkNumber];
+ WorkPackage &work_package = work_packages_[chunk_number];
- MemoryBuffer **memoryBuffers = (MemoryBuffer **)MEM_callocN(
- sizeof(MemoryBuffer *) * this->m_max_read_buffer_offset, __func__);
+ MemoryBuffer **memory_buffers = (MemoryBuffer **)MEM_callocN(
+ sizeof(MemoryBuffer *) * max_read_buffer_offset_, __func__);
rcti output;
- for (ReadBufferOperation *readOperation : m_read_operations) {
- MemoryProxy *memoryProxy = readOperation->getMemoryProxy();
- this->determineDependingAreaOfInterest(&work_package.rect, readOperation, &output);
- MemoryBuffer *memoryBuffer = memoryProxy->getExecutor()->constructConsolidatedMemoryBuffer(
- *memoryProxy, output);
- memoryBuffers[readOperation->getOffset()] = memoryBuffer;
- }
- return memoryBuffers;
+ for (ReadBufferOperation *read_operation : read_operations_) {
+ MemoryProxy *memory_proxy = read_operation->get_memory_proxy();
+ this->determine_depending_area_of_interest(&work_package.rect, read_operation, &output);
+ MemoryBuffer *memory_buffer =
+ memory_proxy->get_executor()->construct_consolidated_memory_buffer(*memory_proxy, output);
+ memory_buffers[read_operation->get_offset()] = memory_buffer;
+ }
+ return memory_buffers;
}
-MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy &memoryProxy,
- rcti &rect)
+MemoryBuffer *ExecutionGroup::construct_consolidated_memory_buffer(MemoryProxy &memory_proxy,
+ rcti &rect)
{
- MemoryBuffer *imageBuffer = memoryProxy.getBuffer();
- MemoryBuffer *result = new MemoryBuffer(&memoryProxy, rect, MemoryBufferState::Temporary);
- result->fill_from(*imageBuffer);
+ MemoryBuffer *image_buffer = memory_proxy.get_buffer();
+ MemoryBuffer *result = new MemoryBuffer(&memory_proxy, rect, MemoryBufferState::Temporary);
+ result->fill_from(*image_buffer);
return result;
}
-void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers)
+void ExecutionGroup::finalize_chunk_execution(int chunk_number, MemoryBuffer **memory_buffers)
{
- WorkPackage &work_package = m_work_packages[chunkNumber];
+ WorkPackage &work_package = work_packages_[chunk_number];
if (work_package.state == eWorkPackageState::Scheduled) {
work_package.state = eWorkPackageState::Executed;
}
- atomic_add_and_fetch_u(&this->m_chunks_finished, 1);
- if (memoryBuffers) {
- for (unsigned int index = 0; index < this->m_max_read_buffer_offset; index++) {
- MemoryBuffer *buffer = memoryBuffers[index];
+ atomic_add_and_fetch_u(&chunks_finished_, 1);
+ if (memory_buffers) {
+ for (unsigned int index = 0; index < max_read_buffer_offset_; index++) {
+ MemoryBuffer *buffer = memory_buffers[index];
if (buffer) {
- if (buffer->isTemporarily()) {
- memoryBuffers[index] = nullptr;
+ if (buffer->is_temporarily()) {
+ memory_buffers[index] = nullptr;
delete buffer;
}
}
}
- MEM_freeN(memoryBuffers);
+ MEM_freeN(memory_buffers);
}
- if (this->m_bTree) {
+ if (bTree_) {
/* Status report is only performed for top level Execution Groups. */
- float progress = this->m_chunks_finished;
- progress /= this->m_chunks_len;
- this->m_bTree->progress(this->m_bTree->prh, progress);
+ float progress = chunks_finished_;
+ progress /= chunks_len_;
+ bTree_->progress(bTree_->prh, progress);
char buf[128];
- BLI_snprintf(buf,
- sizeof(buf),
- TIP_("Compositing | Tile %u-%u"),
- this->m_chunks_finished,
- this->m_chunks_len);
- this->m_bTree->stats_draw(this->m_bTree->sdh, buf);
+ BLI_snprintf(
+ buf, sizeof(buf), TIP_("Compositing | Tile %u-%u"), chunks_finished_, chunks_len_);
+ bTree_->stats_draw(bTree_->sdh, buf);
}
}
-inline void ExecutionGroup::determineChunkRect(rcti *r_rect,
- const unsigned int xChunk,
- const unsigned int yChunk) const
+inline void ExecutionGroup::determine_chunk_rect(rcti *r_rect,
+ const unsigned int x_chunk,
+ const unsigned int y_chunk) const
{
- const int border_width = BLI_rcti_size_x(&this->m_viewerBorder);
- const int border_height = BLI_rcti_size_y(&this->m_viewerBorder);
+ const int border_width = BLI_rcti_size_x(&viewer_border_);
+ const int border_height = BLI_rcti_size_y(&viewer_border_);
- if (this->m_flags.single_threaded) {
- BLI_rcti_init(
- r_rect, this->m_viewerBorder.xmin, border_width, this->m_viewerBorder.ymin, border_height);
+ if (flags_.single_threaded) {
+ BLI_rcti_init(r_rect, viewer_border_.xmin, border_width, viewer_border_.ymin, border_height);
}
else {
- const unsigned int minx = xChunk * this->m_chunkSize + this->m_viewerBorder.xmin;
- const unsigned int miny = yChunk * this->m_chunkSize + this->m_viewerBorder.ymin;
- const unsigned int width = MIN2((unsigned int)this->m_viewerBorder.xmax, this->m_width);
- const unsigned int height = MIN2((unsigned int)this->m_viewerBorder.ymax, this->m_height);
+ const unsigned int minx = x_chunk * chunk_size_ + viewer_border_.xmin;
+ const unsigned int miny = y_chunk * chunk_size_ + viewer_border_.ymin;
+ const unsigned int width = MIN2((unsigned int)viewer_border_.xmax, width_);
+ const unsigned int height = MIN2((unsigned int)viewer_border_.ymax, height_);
BLI_rcti_init(r_rect,
- MIN2(minx, this->m_width),
- MIN2(minx + this->m_chunkSize, width),
- MIN2(miny, this->m_height),
- MIN2(miny + this->m_chunkSize, height));
+ MIN2(minx, width_),
+ MIN2(minx + chunk_size_, width),
+ MIN2(miny, height_),
+ MIN2(miny + chunk_size_, height));
}
}
-void ExecutionGroup::determineChunkRect(rcti *r_rect, const unsigned int chunkNumber) const
+void ExecutionGroup::determine_chunk_rect(rcti *r_rect, const unsigned int chunk_number) const
{
- const unsigned int yChunk = chunkNumber / this->m_x_chunks_len;
- const unsigned int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len);
- determineChunkRect(r_rect, xChunk, yChunk);
+ const unsigned int y_chunk = chunk_number / x_chunks_len_;
+ const unsigned int x_chunk = chunk_number - (y_chunk * x_chunks_len_);
+ determine_chunk_rect(r_rect, x_chunk, y_chunk);
}
-MemoryBuffer *ExecutionGroup::allocateOutputBuffer(rcti &rect)
+MemoryBuffer *ExecutionGroup::allocate_output_buffer(rcti &rect)
{
/* We assume that this method is only called from complex execution groups. */
- NodeOperation *operation = this->getOutputOperation();
+ NodeOperation *operation = this->get_output_operation();
if (operation->get_flags().is_write_buffer_operation) {
- WriteBufferOperation *writeOperation = (WriteBufferOperation *)operation;
+ WriteBufferOperation *write_operation = (WriteBufferOperation *)operation;
MemoryBuffer *buffer = new MemoryBuffer(
- writeOperation->getMemoryProxy(), rect, MemoryBufferState::Temporary);
+ write_operation->get_memory_proxy(), rect, MemoryBufferState::Temporary);
return buffer;
}
return nullptr;
}
-bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area)
+bool ExecutionGroup::schedule_area_when_possible(ExecutionSystem *graph, rcti *area)
{
- if (this->m_flags.single_threaded) {
- return scheduleChunkWhenPossible(graph, 0, 0);
+ if (flags_.single_threaded) {
+ return schedule_chunk_when_possible(graph, 0, 0);
}
/* Find all chunks inside the rect
* determine `minxchunk`, `minychunk`, `maxxchunk`, `maxychunk`
* where x and y are chunk-numbers. */
int indexx, indexy;
- int minx = max_ii(area->xmin - m_viewerBorder.xmin, 0);
- int maxx = min_ii(area->xmax - m_viewerBorder.xmin, m_viewerBorder.xmax - m_viewerBorder.xmin);
- int miny = max_ii(area->ymin - m_viewerBorder.ymin, 0);
- int maxy = min_ii(area->ymax - m_viewerBorder.ymin, m_viewerBorder.ymax - m_viewerBorder.ymin);
- int minxchunk = minx / (int)m_chunkSize;
- int maxxchunk = (maxx + (int)m_chunkSize - 1) / (int)m_chunkSize;
- int minychunk = miny / (int)m_chunkSize;
- int maxychunk = (maxy + (int)m_chunkSize - 1) / (int)m_chunkSize;
+ int minx = max_ii(area->xmin - viewer_border_.xmin, 0);
+ int maxx = min_ii(area->xmax - viewer_border_.xmin, viewer_border_.xmax - viewer_border_.xmin);
+ int miny = max_ii(area->ymin - viewer_border_.ymin, 0);
+ int maxy = min_ii(area->ymax - viewer_border_.ymin, viewer_border_.ymax - viewer_border_.ymin);
+ int minxchunk = minx / (int)chunk_size_;
+ int maxxchunk = (maxx + (int)chunk_size_ - 1) / (int)chunk_size_;
+ int minychunk = miny / (int)chunk_size_;
+ int maxychunk = (maxy + (int)chunk_size_ - 1) / (int)chunk_size_;
minxchunk = max_ii(minxchunk, 0);
minychunk = max_ii(minychunk, 0);
- maxxchunk = min_ii(maxxchunk, (int)m_x_chunks_len);
- maxychunk = min_ii(maxychunk, (int)m_y_chunks_len);
+ maxxchunk = min_ii(maxxchunk, (int)x_chunks_len_);
+ maxychunk = min_ii(maxychunk, (int)y_chunks_len_);
bool result = true;
for (indexx = minxchunk; indexx < maxxchunk; indexx++) {
for (indexy = minychunk; indexy < maxychunk; indexy++) {
- if (!scheduleChunkWhenPossible(graph, indexx, indexy)) {
+ if (!schedule_chunk_when_possible(graph, indexx, indexy)) {
result = false;
}
}
@@ -540,9 +516,9 @@ bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area
return result;
}
-bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber)
+bool ExecutionGroup::schedule_chunk(unsigned int chunk_number)
{
- WorkPackage &work_package = m_work_packages[chunkNumber];
+ WorkPackage &work_package = work_packages_[chunk_number];
if (work_package.state == eWorkPackageState::NotScheduled) {
work_package.state = eWorkPackageState::Scheduled;
WorkScheduler::schedule(&work_package);
@@ -551,20 +527,20 @@ bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber)
return false;
}
-bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph,
- const int chunk_x,
- const int chunk_y)
+bool ExecutionGroup::schedule_chunk_when_possible(ExecutionSystem *graph,
+ const int chunk_x,
+ const int chunk_y)
{
- if (chunk_x < 0 || chunk_x >= (int)this->m_x_chunks_len) {
+ if (chunk_x < 0 || chunk_x >= (int)x_chunks_len_) {
return true;
}
- if (chunk_y < 0 || chunk_y >= (int)this->m_y_chunks_len) {
+ if (chunk_y < 0 || chunk_y >= (int)y_chunks_len_) {
return true;
}
/* Check if chunk is already executed or scheduled and not yet executed. */
- const int chunk_index = chunk_y * this->m_x_chunks_len + chunk_x;
- WorkPackage &work_package = m_work_packages[chunk_index];
+ const int chunk_index = chunk_y * x_chunks_len_ + chunk_x;
+ WorkPackage &work_package = work_packages_[chunk_index];
if (work_package.state == eWorkPackageState::Executed) {
return true;
}
@@ -575,52 +551,45 @@ bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph,
bool can_be_executed = true;
rcti area;
- for (ReadBufferOperation *read_operation : m_read_operations) {
+ for (ReadBufferOperation *read_operation : read_operations_) {
BLI_rcti_init(&area, 0, 0, 0, 0);
- MemoryProxy *memory_proxy = read_operation->getMemoryProxy();
- determineDependingAreaOfInterest(&work_package.rect, read_operation, &area);
- ExecutionGroup *group = memory_proxy->getExecutor();
+ MemoryProxy *memory_proxy = read_operation->get_memory_proxy();
+ determine_depending_area_of_interest(&work_package.rect, read_operation, &area);
+ ExecutionGroup *group = memory_proxy->get_executor();
- if (!group->scheduleAreaWhenPossible(graph, &area)) {
+ if (!group->schedule_area_when_possible(graph, &area)) {
can_be_executed = false;
}
}
if (can_be_executed) {
- scheduleChunk(chunk_index);
+ schedule_chunk(chunk_index);
}
return false;
}
-void ExecutionGroup::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+void ExecutionGroup::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- this->getOutputOperation()->determineDependingAreaOfInterest(input, readOperation, output);
+ this->get_output_operation()->determine_depending_area_of_interest(
+ input, read_operation, output);
}
-void ExecutionGroup::setViewerBorder(float xmin, float xmax, float ymin, float ymax)
+void ExecutionGroup::set_viewer_border(float xmin, float xmax, float ymin, float ymax)
{
- const NodeOperation &operation = *this->getOutputOperation();
+ const NodeOperation &operation = *this->get_output_operation();
if (operation.get_flags().use_viewer_border) {
- BLI_rcti_init(&this->m_viewerBorder,
- xmin * this->m_width,
- xmax * this->m_width,
- ymin * this->m_height,
- ymax * this->m_height);
+ BLI_rcti_init(&viewer_border_, xmin * width_, xmax * width_, ymin * height_, ymax * height_);
}
}
-void ExecutionGroup::setRenderBorder(float xmin, float xmax, float ymin, float ymax)
+void ExecutionGroup::set_render_border(float xmin, float xmax, float ymin, float ymax)
{
- const NodeOperation &operation = *this->getOutputOperation();
- if (operation.isOutputOperation(true) && operation.get_flags().use_render_border) {
- BLI_rcti_init(&this->m_viewerBorder,
- xmin * this->m_width,
- xmax * this->m_width,
- ymin * this->m_height,
- ymax * this->m_height);
+ const NodeOperation &operation = *this->get_output_operation();
+ if (operation.is_output_operation(true) && operation.get_flags().use_render_border) {
+ BLI_rcti_init(&viewer_border_, xmin * width_, xmax * width_, ymin * height_, ymax * height_);
}
}
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h
index cb593feabb0..d37bfe29306 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.h
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.h
@@ -22,25 +22,24 @@
# include "MEM_guardedalloc.h"
#endif
+#include <iostream>
+
#include "BLI_array.hh"
-#include "BLI_rect.h"
#include "BLI_vector.hh"
-#include "COM_CompositorContext.h"
-#include "COM_Device.h"
-#include "COM_MemoryProxy.h"
-#include "COM_Node.h"
-#include "COM_NodeOperation.h"
+#include "COM_Enums.h"
#include "COM_WorkPackage.h"
-#include <vector>
+
+#include "DNA_node_types.h"
+#include "DNA_vec_types.h"
namespace blender::compositor {
class ExecutionSystem;
+class NodeOperation;
class MemoryProxy;
class MemoryBuffer;
class ReadBufferOperation;
-class Device;
struct ExecutionGroupFlags {
bool initialized : 1;
@@ -87,84 +86,84 @@ class ExecutionGroup {
/**
* Id of the execution group. For debugging purposes.
*/
- int m_id;
+ int id_;
/**
* \brief list of operations in this ExecutionGroup
*/
- Vector<NodeOperation *> m_operations;
+ Vector<NodeOperation *> operations_;
- ExecutionGroupFlags m_flags;
+ ExecutionGroupFlags flags_;
/**
* \brief Width of the output
*/
- unsigned int m_width;
+ unsigned int width_;
/**
* \brief Height of the output
*/
- unsigned int m_height;
+ unsigned int height_;
/**
* \brief size of a single chunk, being Width or of height
* a chunk is always a square, except at the edges of the MemoryBuffer
*/
- unsigned int m_chunkSize;
+ unsigned int chunk_size_;
/**
* \brief number of chunks in the x-axis
*/
- unsigned int m_x_chunks_len;
+ unsigned int x_chunks_len_;
/**
* \brief number of chunks in the y-axis
*/
- unsigned int m_y_chunks_len;
+ unsigned int y_chunks_len_;
/**
* \brief total number of chunks
*/
- unsigned int m_chunks_len;
+ unsigned int chunks_len_;
/**
* \brief what is the maximum number field of all ReadBufferOperation in this ExecutionGroup.
* \note this is used to construct the MemoryBuffers that will be passed during execution.
*/
- unsigned int m_max_read_buffer_offset;
+ unsigned int max_read_buffer_offset_;
/**
* \brief All read operations of this execution group.
*/
- Vector<ReadBufferOperation *> m_read_operations;
+ Vector<ReadBufferOperation *> read_operations_;
/**
* \brief reference to the original bNodeTree,
* this field is only set for the 'top' execution group.
* \note can only be used to call the callbacks for progress, status and break.
*/
- const bNodeTree *m_bTree;
+ const bNodeTree *bTree_;
/**
* \brief total number of chunks that have been calculated for this ExecutionGroup
*/
- unsigned int m_chunks_finished;
+ unsigned int chunks_finished_;
/**
- * \brief m_work_packages holds all unit of work.
+ * \brief work_packages_ holds all unit of work.
*/
- Vector<WorkPackage> m_work_packages;
+ Vector<WorkPackage> work_packages_;
/**
* \brief denotes boundary for border compositing
* \note measured in pixel space
*/
- rcti m_viewerBorder;
+ rcti viewer_border_;
/**
* \brief start time of execution
*/
- double m_executionStartTime;
+ double execution_start_time_;
// methods
/**
@@ -176,13 +175,12 @@ class ExecutionGroup {
/**
* \brief Determine the rect (minx, maxx, miny, maxy) of a chunk at a position.
*/
- void determineChunkRect(rcti *r_rect,
- const unsigned int xChunk,
- const unsigned int yChunk) const;
+ void determine_chunk_rect(rcti *r_rect, unsigned int x_chunk, unsigned int y_chunk) const;
/**
- * \brief determine the number of chunks, based on the chunkSize, width and height.
- * \note The result are stored in the fields numberOfChunks, numberOfXChunks, numberOfYChunks
+ * \brief determine the number of chunks, based on the chunk_size, width and height.
+ * \note The result are stored in the fields number_of_chunks, number_of_xchunks,
+ * number_of_ychunks
*/
void init_number_of_chunks();
@@ -191,13 +189,13 @@ class ExecutionGroup {
* \note scheduling succeeds when all input requirements are met and the chunks hasn't been
* scheduled yet.
* \param graph:
- * \param xChunk:
- * \param yChunk:
+ * \param x_chunk:
+ * \param y_chunk:
* \return [true:false]
* true: package(s) are scheduled
* false: scheduling is deferred (depending workpackages are scheduled)
*/
- bool scheduleChunkWhenPossible(ExecutionSystem *graph, const int chunk_x, const int chunk_y);
+ bool schedule_chunk_when_possible(ExecutionSystem *graph, int chunk_x, int chunk_y);
/**
* \brief try to schedule a specific area.
@@ -209,24 +207,24 @@ class ExecutionGroup {
* true: package(s) are scheduled
* false: scheduling is deferred (depending workpackages are scheduled)
*/
- bool scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area);
+ bool schedule_area_when_possible(ExecutionSystem *graph, rcti *area);
/**
* \brief add a chunk to the WorkScheduler.
* \param chunknumber:
*/
- bool scheduleChunk(unsigned int chunkNumber);
+ bool schedule_chunk(unsigned int chunk_number);
/**
* \brief determine the area of interest of a certain input area
* \note This method only evaluates a single ReadBufferOperation
* \param input: the input area
- * \param readOperation: The ReadBufferOperation where the area needs to be evaluated
+ * \param read_operation: The ReadBufferOperation where the area needs to be evaluated
* \param output: the area needed of the ReadBufferOperation. Result
*/
- void determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output);
+ void determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output);
/**
* Return the execution order of the user visible chunks.
@@ -242,12 +240,12 @@ class ExecutionGroup {
int get_id() const
{
- return m_id;
+ return id_;
}
const ExecutionGroupFlags get_flags() const
{
- return m_flags;
+ return flags_;
}
// methods
@@ -259,103 +257,95 @@ class ExecutionGroup {
* \param operation:
* \return True if the operation was successfully added
*/
- bool addOperation(NodeOperation *operation);
+ bool add_operation(NodeOperation *operation);
/**
* \brief set whether this ExecutionGroup is an output
- * \param isOutput:
+ * \param is_output:
*/
- void setOutputExecutionGroup(bool is_output)
+ void set_output_execution_group(bool is_output)
{
- this->m_flags.is_output = is_output;
+ flags_.is_output = is_output;
}
/**
* \brief determine the resolution of this ExecutionGroup
* \param resolution:
*/
- void determineResolution(unsigned int resolution[2]);
+ void determine_resolution(unsigned int resolution[2]);
/**
* \brief set the resolution of this executiongroup
* \param resolution:
*/
- void setResolution(unsigned int resolution[2])
+ void set_resolution(unsigned int resolution[2])
{
- this->m_width = resolution[0];
- this->m_height = resolution[1];
+ width_ = resolution[0];
+ height_ = resolution[1];
}
/**
* \brief get the width of this execution group
*/
- unsigned int getWidth() const
+ unsigned int get_width() const
{
- return m_width;
+ return width_;
}
/**
* \brief get the height of this execution group
*/
- unsigned int getHeight() const
+ unsigned int get_height() const
{
- return m_height;
+ return height_;
}
/**
* \brief get the output operation of this ExecutionGroup
* \return NodeOperation *output operation
*/
- NodeOperation *getOutputOperation() const;
+ NodeOperation *get_output_operation() const;
/**
* \brief compose multiple chunks into a single chunk
* \return Memorybuffer *consolidated chunk
*/
- MemoryBuffer *constructConsolidatedMemoryBuffer(MemoryProxy &memoryProxy, rcti &rect);
-
- /**
- * \brief initExecution is called just before the execution of the whole graph will be done.
- * \note The implementation will calculate the chunkSize of this execution group.
- */
- void initExecution();
+ MemoryBuffer *construct_consolidated_memory_buffer(MemoryProxy &memory_proxy, rcti &rect);
/**
- * \brief get all inputbuffers needed to calculate an chunk
- * \note all inputbuffers must be executed
- * \param chunkNumber: the chunk to be calculated
- * \return (MemoryBuffer **) the inputbuffers
+ * \brief init_execution is called just before the execution of the whole graph will be done.
+ * \note The implementation will calculate the chunk_size of this execution group.
*/
- MemoryBuffer **getInputBuffersCPU();
+ void init_execution();
/**
* \brief get all inputbuffers needed to calculate an chunk
* \note all inputbuffers must be executed
- * \param chunkNumber: the chunk to be calculated
+ * \param chunk_number: the chunk to be calculated
* \return (MemoryBuffer **) the inputbuffers
*/
- MemoryBuffer **getInputBuffersOpenCL(int chunkNumber);
+ MemoryBuffer **get_input_buffers_opencl(int chunk_number);
/**
* \brief allocate the outputbuffer of a chunk
- * \param chunkNumber: the number of the chunk in the ExecutionGroup
+ * \param chunk_number: the number of the chunk in the ExecutionGroup
* \param rect: the rect of that chunk
- * \see determineChunkRect
+ * \see determine_chunk_rect
*/
- MemoryBuffer *allocateOutputBuffer(rcti &rect);
+ MemoryBuffer *allocate_output_buffer(rcti &rect);
/**
* \brief after a chunk is executed the needed resources can be freed or unlocked.
* \param chunknumber:
* \param memorybuffers:
*/
- void finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers);
+ void finalize_chunk_execution(int chunk_number, MemoryBuffer **memory_buffers);
/**
- * \brief deinitExecution is called just after execution the whole graph.
+ * \brief deinit_execution is called just after execution the whole graph.
* \note It will release all needed resources
*/
- void deinitExecution();
+ void deinit_execution();
/**
* \brief schedule an ExecutionGroup
@@ -373,31 +363,35 @@ class ExecutionGroup {
* \see ViewerOperation
* \param graph:
*/
+ /**
+ * This method is called for the top execution groups. containing the compositor node or the
+ * preview node or the viewer node).
+ */
void execute(ExecutionSystem *graph);
/**
* \brief Determine the rect (minx, maxx, miny, maxy) of a chunk.
*/
- void determineChunkRect(rcti *r_rect, const unsigned int chunkNumber) const;
+ void determine_chunk_rect(rcti *r_rect, unsigned int chunk_number) const;
- void setChunksize(int chunksize)
+ void set_chunksize(int chunksize)
{
- this->m_chunkSize = chunksize;
+ chunk_size_ = chunksize;
}
/**
* \brief get the Render priority of this ExecutionGroup
* \see ExecutionSystem.execute
*/
- eCompositorPriority getRenderPriority();
+ eCompositorPriority get_render_priority();
/**
* \brief set border for viewer operation
* \note all the coordinates are assumed to be in normalized space
*/
- void setViewerBorder(float xmin, float xmax, float ymin, float ymax);
+ void set_viewer_border(float xmin, float xmax, float ymin, float ymax);
- void setRenderBorder(float xmin, float xmax, float ymin, float ymax);
+ void set_render_border(float xmin, float xmax, float ymin, float ymax);
/* allow the DebugInfo class to look at internals */
friend class DebugInfo;
diff --git a/source/blender/compositor/intern/COM_ExecutionModel.cc b/source/blender/compositor/intern/COM_ExecutionModel.cc
index b75b277e92c..b319aaa4b21 100644
--- a/source/blender/compositor/intern/COM_ExecutionModel.cc
+++ b/source/blender/compositor/intern/COM_ExecutionModel.cc
@@ -17,13 +17,14 @@
*/
#include "COM_ExecutionModel.h"
+#include "COM_CompositorContext.h"
namespace blender::compositor {
ExecutionModel::ExecutionModel(CompositorContext &context, Span<NodeOperation *> operations)
: context_(context), operations_(operations)
{
- const bNodeTree *node_tree = context_.getbNodeTree();
+ const bNodeTree *node_tree = context_.get_bnodetree();
const rctf *viewer_border = &node_tree->viewer_border;
border_.use_viewer_border = (node_tree->flag & NTREE_VIEWER_BORDER) &&
@@ -31,10 +32,10 @@ ExecutionModel::ExecutionModel(CompositorContext &context, Span<NodeOperation *>
viewer_border->ymin < viewer_border->ymax;
border_.viewer_border = viewer_border;
- const RenderData *rd = context_.getRenderData();
+ const RenderData *rd = context_.get_render_data();
/* Case when cropping to render border happens is handled in
* compositor output and render layer nodes. */
- border_.use_render_border = context.isRendering() && (rd->mode & R_BORDER) &&
+ border_.use_render_border = context.is_rendering() && (rd->mode & R_BORDER) &&
!(rd->mode & R_CROP);
border_.render_border = &rd->border;
}
diff --git a/source/blender/compositor/intern/COM_ExecutionModel.h b/source/blender/compositor/intern/COM_ExecutionModel.h
index 452861ae4be..f0adc7d3e54 100644
--- a/source/blender/compositor/intern/COM_ExecutionModel.h
+++ b/source/blender/compositor/intern/COM_ExecutionModel.h
@@ -18,12 +18,9 @@
#pragma once
-#include "BLI_rect.h"
-#include "BLI_vector.hh"
+#include "BLI_span.hh"
-#include "COM_ExecutionSystem.h"
-
-#include <functional>
+#include "DNA_vec_types.h"
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
@@ -31,6 +28,8 @@
namespace blender::compositor {
+class CompositorContext;
+class ExecutionSystem;
class NodeOperation;
/**
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cc b/source/blender/compositor/intern/COM_ExecutionSystem.cc
index c92e292c74f..038df6ed9df 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.cc
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.cc
@@ -18,14 +18,13 @@
#include "COM_ExecutionSystem.h"
-#include "BLI_utildefines.h"
-#include "PIL_time.h"
-
#include "COM_Debug.h"
+#include "COM_ExecutionGroup.h"
#include "COM_FullFrameExecutionModel.h"
#include "COM_NodeOperation.h"
#include "COM_NodeOperationBuilder.h"
#include "COM_TiledExecutionModel.h"
+#include "COM_WorkPackage.h"
#include "COM_WorkScheduler.h"
#ifdef WITH_CXX_GUARDEDALLOC
@@ -39,45 +38,45 @@ ExecutionSystem::ExecutionSystem(RenderData *rd,
bNodeTree *editingtree,
bool rendering,
bool fastcalculation,
- const ColorManagedViewSettings *viewSettings,
- const ColorManagedDisplaySettings *displaySettings,
- const char *viewName)
+ const ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ const char *view_name)
{
num_work_threads_ = WorkScheduler::get_num_cpu_threads();
- this->m_context.setViewName(viewName);
- this->m_context.setScene(scene);
- this->m_context.setbNodeTree(editingtree);
- this->m_context.setPreviewHash(editingtree->previews);
- this->m_context.setFastCalculation(fastcalculation);
+ context_.set_view_name(view_name);
+ context_.set_scene(scene);
+ context_.set_bnodetree(editingtree);
+ context_.set_preview_hash(editingtree->previews);
+ context_.set_fast_calculation(fastcalculation);
/* initialize the CompositorContext */
if (rendering) {
- this->m_context.setQuality((eCompositorQuality)editingtree->render_quality);
+ context_.set_quality((eCompositorQuality)editingtree->render_quality);
}
else {
- this->m_context.setQuality((eCompositorQuality)editingtree->edit_quality);
+ context_.set_quality((eCompositorQuality)editingtree->edit_quality);
}
- this->m_context.setRendering(rendering);
- this->m_context.setHasActiveOpenCLDevices(WorkScheduler::has_gpu_devices() &&
- (editingtree->flag & NTREE_COM_OPENCL));
+ context_.set_rendering(rendering);
+ context_.setHasActiveOpenCLDevices(WorkScheduler::has_gpu_devices() &&
+ (editingtree->flag & NTREE_COM_OPENCL));
- this->m_context.setRenderData(rd);
- this->m_context.setViewSettings(viewSettings);
- this->m_context.setDisplaySettings(displaySettings);
+ context_.set_render_data(rd);
+ context_.set_view_settings(view_settings);
+ context_.set_display_settings(display_settings);
BLI_mutex_init(&work_mutex_);
BLI_condition_init(&work_finished_cond_);
{
- NodeOperationBuilder builder(&m_context, editingtree, this);
- builder.convertToOperations(this);
+ NodeOperationBuilder builder(&context_, editingtree, this);
+ builder.convert_to_operations(this);
}
- switch (m_context.get_execution_model()) {
+ switch (context_.get_execution_model()) {
case eExecutionModel::Tiled:
- execution_model_ = new TiledExecutionModel(m_context, m_operations, m_groups);
+ execution_model_ = new TiledExecutionModel(context_, operations_, groups_);
break;
case eExecutionModel::FullFrame:
- execution_model_ = new FullFrameExecutionModel(m_context, active_buffers_, m_operations);
+ execution_model_ = new FullFrameExecutionModel(context_, active_buffers_, operations_);
break;
default:
BLI_assert_msg(0, "Non implemented execution model");
@@ -92,36 +91,33 @@ ExecutionSystem::~ExecutionSystem()
delete execution_model_;
- for (NodeOperation *operation : m_operations) {
+ for (NodeOperation *operation : operations_) {
delete operation;
}
- this->m_operations.clear();
+ operations_.clear();
- for (ExecutionGroup *group : m_groups) {
+ for (ExecutionGroup *group : groups_) {
delete group;
}
- this->m_groups.clear();
+ groups_.clear();
}
void ExecutionSystem::set_operations(const Vector<NodeOperation *> &operations,
const Vector<ExecutionGroup *> &groups)
{
- m_operations = operations;
- m_groups = groups;
+ operations_ = operations;
+ groups_ = groups;
}
void ExecutionSystem::execute()
{
DebugInfo::execute_started(this);
- for (NodeOperation *op : m_operations) {
+ for (NodeOperation *op : operations_) {
op->init_data();
}
execution_model_->execute(*this);
}
-/**
- * Multi-threadedly execute given work function passing work_rect splits as argument.
- */
void ExecutionSystem::execute_work(const rcti &work_rect,
std::function<void(const rcti &split_rect)> work_func)
{
@@ -185,7 +181,7 @@ void ExecutionSystem::execute_work(const rcti &work_rect,
bool ExecutionSystem::is_breaked() const
{
- const bNodeTree *btree = m_context.getbNodeTree();
+ const bNodeTree *btree = context_.get_bnodetree();
return btree->test_break(btree->tbh);
}
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h
index bce96db52c7..4456ec107fa 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.h
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.h
@@ -16,22 +16,23 @@
* Copyright 2011, Blender Foundation.
*/
-class ExecutionGroup;
-
#pragma once
-#include "BKE_text.h"
+#include <functional>
+
+#include "atomic_ops.h"
+
+#include "BLI_index_range.hh"
+#include "BLI_threads.h"
+#include "BLI_vector.hh"
-#include "COM_ExecutionGroup.h"
-#include "COM_Node.h"
-#include "COM_NodeOperation.h"
+#include "COM_CompositorContext.h"
#include "COM_SharedOperationBuffers.h"
#include "DNA_color_types.h"
#include "DNA_node_types.h"
-
-#include "BLI_vector.hh"
-#include "atomic_ops.h"
+#include "DNA_scene_types.h"
+#include "DNA_vec_types.h"
namespace blender::compositor {
@@ -63,8 +64,8 @@ namespace blender::compositor {
* based on settings; like MixNode. based on the selected Mixtype a different operation will be
* used. for more information see the page about creating new Nodes. [@subpage newnode]
*
- * \see ExecutionSystem.convertToOperations
- * \see Node.convertToOperations
+ * \see ExecutionSystem.convert_to_operations
+ * \see Node.convert_to_operations
* \see NodeOperation base class for all operations in the system
*
* \section EM_Step3 Step3: add additional conversions to the operation system
@@ -88,7 +89,7 @@ namespace blender::compositor {
* Bottom left of the images are aligned.
*
* \see COM_convert_data_type Datatype conversions
- * \see Converter.convertResolution Image size conversions
+ * \see Converter.convert_resolution Image size conversions
*
* \section EM_Step4 Step4: group operations in executions groups
* ExecutionGroup are groups of operations that are calculated as being one bigger operation.
@@ -111,14 +112,16 @@ namespace blender::compositor {
* |cFAA | |cFAA | |cFAA | |cFAA |
* +------+ +------+ +-------+ +-------+
* </pre>
- * \see ExecutionSystem.groupOperations method doing this step
- * \see ExecutionSystem.addReadWriteBufferOperations
- * \see NodeOperation.isComplex
+ * \see ExecutionSystem.group_operations method doing this step
+ * \see ExecutionSystem.add_read_write_buffer_operations
+ * \see NodeOperation.is_complex
* \see ExecutionGroup class representing the ExecutionGroup
*/
/* Forward declarations. */
+class ExecutionGroup;
class ExecutionModel;
+class NodeOperation;
/**
* \brief the ExecutionSystem contains the whole compositor tree.
@@ -134,17 +137,17 @@ class ExecutionSystem {
/**
* \brief the context used during execution
*/
- CompositorContext m_context;
+ CompositorContext context_;
/**
* \brief vector of operations
*/
- Vector<NodeOperation *> m_operations;
+ Vector<NodeOperation *> operations_;
/**
* \brief vector of groups
*/
- Vector<ExecutionGroup *> m_groups;
+ Vector<ExecutionGroup *> groups_;
/**
* Active execution model implementation.
@@ -172,9 +175,9 @@ class ExecutionSystem {
bNodeTree *editingtree,
bool rendering,
bool fastcalculation,
- const ColorManagedViewSettings *viewSettings,
- const ColorManagedDisplaySettings *displaySettings,
- const char *viewName);
+ const ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ const char *view_name);
/**
* Destructor
@@ -195,9 +198,9 @@ class ExecutionSystem {
/**
* \brief get the reference to the compositor context
*/
- const CompositorContext &getContext() const
+ const CompositorContext &get_context() const
{
- return this->m_context;
+ return context_;
}
SharedOperationBuffers &get_active_buffers()
@@ -205,6 +208,9 @@ class ExecutionSystem {
return active_buffers_;
}
+ /**
+ * Multi-threadedly execute given work function passing work_rect splits as argument.
+ */
void execute_work(const rcti &work_rect, std::function<void(const rcti &split_rect)> work_func);
/**
diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
index c44a168390b..15dbbfde7ed 100644
--- a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
+++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
@@ -17,14 +17,13 @@
*/
#include "COM_FullFrameExecutionModel.h"
+
+#include "BLT_translation.h"
+
#include "COM_Debug.h"
-#include "COM_ExecutionGroup.h"
-#include "COM_ReadBufferOperation.h"
#include "COM_ViewerOperation.h"
#include "COM_WorkScheduler.h"
-#include "BLT_translation.h"
-
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
@@ -39,7 +38,7 @@ FullFrameExecutionModel::FullFrameExecutionModel(CompositorContext &context,
num_operations_finished_(0)
{
priorities_.append(eCompositorPriority::High);
- if (!context.isFastCalculation()) {
+ if (!context.is_fast_calculation()) {
priorities_.append(eCompositorPriority::Medium);
priorities_.append(eCompositorPriority::Low);
}
@@ -47,7 +46,7 @@ FullFrameExecutionModel::FullFrameExecutionModel(CompositorContext &context,
void FullFrameExecutionModel::execute(ExecutionSystem &exec_system)
{
- const bNodeTree *node_tree = this->context_.getbNodeTree();
+ const bNodeTree *node_tree = this->context_.get_bnodetree();
node_tree->stats_draw(node_tree->sdh, TIP_("Compositing | Initializing execution"));
DebugInfo::graphviz(&exec_system, "compositor_prior_rendering");
@@ -58,14 +57,14 @@ void FullFrameExecutionModel::execute(ExecutionSystem &exec_system)
void FullFrameExecutionModel::determine_areas_to_render_and_reads()
{
- const bool is_rendering = context_.isRendering();
- const bNodeTree *node_tree = context_.getbNodeTree();
+ const bool is_rendering = context_.is_rendering();
+ const bNodeTree *node_tree = context_.get_bnodetree();
rcti area;
for (eCompositorPriority priority : priorities_) {
for (NodeOperation *op : operations_) {
- op->setbNodeTree(node_tree);
- if (op->isOutputOperation(is_rendering) && op->getRenderPriority() == priority) {
+ op->set_bnodetree(node_tree);
+ if (op->is_output_operation(is_rendering) && op->get_render_priority() == priority) {
get_output_render_area(op, area);
determine_areas_to_render(op, area);
determine_reads(op);
@@ -74,15 +73,11 @@ void FullFrameExecutionModel::determine_areas_to_render_and_reads()
}
}
-/**
- * Returns input buffers with an offset relative to given output coordinates. Returned memory
- * buffers must be deleted.
- */
Vector<MemoryBuffer *> FullFrameExecutionModel::get_input_buffers(NodeOperation *op,
const int output_x,
const int output_y)
{
- const int num_inputs = op->getNumberOfInputSockets();
+ const int num_inputs = op->get_number_of_input_sockets();
Vector<MemoryBuffer *> inputs_buffers(num_inputs);
for (int i = 0; i < num_inputs; i++) {
NodeOperation *input = op->get_input_operation(i);
@@ -93,7 +88,7 @@ Vector<MemoryBuffer *> FullFrameExecutionModel::get_input_buffers(NodeOperation
rcti rect = buf->get_rect();
BLI_rcti_translate(&rect, offset_x, offset_y);
inputs_buffers[i] = new MemoryBuffer(
- buf->getBuffer(), buf->get_num_channels(), rect, buf->is_a_single_elem());
+ buf->get_buffer(), buf->get_num_channels(), rect, buf->is_a_single_elem());
}
return inputs_buffers;
}
@@ -103,9 +98,10 @@ MemoryBuffer *FullFrameExecutionModel::create_operation_buffer(NodeOperation *op
const int output_y)
{
rcti rect;
- BLI_rcti_init(&rect, output_x, output_x + op->getWidth(), output_y, output_y + op->getHeight());
+ BLI_rcti_init(
+ &rect, output_x, output_x + op->get_width(), output_y, output_y + op->get_height());
- const DataType data_type = op->getOutputSocket(0)->getDataType();
+ const DataType data_type = op->get_output_socket(0)->get_data_type();
const bool is_a_single_elem = op->get_flags().is_constant_operation;
return new MemoryBuffer(data_type, rect, is_a_single_elem);
}
@@ -116,13 +112,13 @@ void FullFrameExecutionModel::render_operation(NodeOperation *op)
constexpr int output_x = 0;
constexpr int output_y = 0;
- const bool has_outputs = op->getNumberOfOutputSockets() > 0;
+ const bool has_outputs = op->get_number_of_output_sockets() > 0;
MemoryBuffer *op_buf = has_outputs ? create_operation_buffer(op, output_x, output_y) : nullptr;
- if (op->getWidth() > 0 && op->getHeight() > 0) {
+ if (op->get_width() > 0 && op->get_height() > 0) {
Vector<MemoryBuffer *> input_bufs = get_input_buffers(op, output_x, output_y);
const int op_offset_x = output_x - op->get_canvas().xmin;
const int op_offset_y = output_y - op->get_canvas().ymin;
- Span<rcti> areas = active_buffers_.get_areas_to_render(op, op_offset_x, op_offset_y);
+ Vector<rcti> areas = active_buffers_.get_areas_to_render(op, op_offset_x, op_offset_y);
op->render(op_buf, areas, input_bufs);
DebugInfo::operation_rendered(op, op_buf);
@@ -137,24 +133,21 @@ void FullFrameExecutionModel::render_operation(NodeOperation *op)
operation_finished(op);
}
-/**
- * Render output operations in order of priority.
- */
void FullFrameExecutionModel::render_operations()
{
- const bool is_rendering = context_.isRendering();
+ const bool is_rendering = context_.is_rendering();
WorkScheduler::start(this->context_);
for (eCompositorPriority priority : priorities_) {
for (NodeOperation *op : operations_) {
- const bool has_size = op->getWidth() > 0 && op->getHeight() > 0;
- const bool is_priority_output = op->isOutputOperation(is_rendering) &&
- op->getRenderPriority() == priority;
+ const bool has_size = op->get_width() > 0 && op->get_height() > 0;
+ const bool is_priority_output = op->is_output_operation(is_rendering) &&
+ op->get_render_priority() == priority;
if (is_priority_output && has_size) {
render_output_dependencies(op);
render_operation(op);
}
- else if (is_priority_output && !has_size && op->isActiveViewerOutput()) {
+ else if (is_priority_output && !has_size && op->is_active_viewer_output()) {
static_cast<ViewerOperation *>(op)->clear_display_buffer();
}
}
@@ -176,7 +169,7 @@ static Vector<NodeOperation *> get_operation_dependencies(NodeOperation *operati
Vector<NodeOperation *> outputs(next_outputs);
next_outputs.clear();
for (NodeOperation *output : outputs) {
- for (int i = 0; i < output->getNumberOfInputSockets(); i++) {
+ for (int i = 0; i < output->get_number_of_input_sockets(); i++) {
next_outputs.append(output->get_input_operation(i));
}
}
@@ -191,7 +184,7 @@ static Vector<NodeOperation *> get_operation_dependencies(NodeOperation *operati
void FullFrameExecutionModel::render_output_dependencies(NodeOperation *output_op)
{
- BLI_assert(output_op->isOutputOperation(context_.isRendering()));
+ BLI_assert(output_op->is_output_operation(context_.is_rendering()));
Vector<NodeOperation *> dependencies = get_operation_dependencies(output_op);
for (NodeOperation *op : dependencies) {
if (!active_buffers_.is_operation_rendered(op)) {
@@ -200,13 +193,10 @@ void FullFrameExecutionModel::render_output_dependencies(NodeOperation *output_o
}
}
-/**
- * Determines all operations areas needed to render given output area.
- */
void FullFrameExecutionModel::determine_areas_to_render(NodeOperation *output_op,
const rcti &output_area)
{
- BLI_assert(output_op->isOutputOperation(context_.isRendering()));
+ BLI_assert(output_op->is_output_operation(context_.is_rendering()));
Vector<std::pair<NodeOperation *, const rcti>> stack;
stack.append({output_op, output_area});
@@ -221,7 +211,7 @@ void FullFrameExecutionModel::determine_areas_to_render(NodeOperation *output_op
active_buffers_.register_area(operation, render_area);
- const int num_inputs = operation->getNumberOfInputSockets();
+ const int num_inputs = operation->get_number_of_input_sockets();
for (int i = 0; i < num_inputs; i++) {
NodeOperation *input_op = operation->get_input_operation(i);
rcti input_area;
@@ -235,19 +225,15 @@ void FullFrameExecutionModel::determine_areas_to_render(NodeOperation *output_op
}
}
-/**
- * Determines reads to receive by operations in output operation tree (i.e: Number of dependent
- * operations each operation has).
- */
void FullFrameExecutionModel::determine_reads(NodeOperation *output_op)
{
- BLI_assert(output_op->isOutputOperation(context_.isRendering()));
+ BLI_assert(output_op->is_output_operation(context_.is_rendering()));
Vector<NodeOperation *> stack;
stack.append(output_op);
while (stack.size() > 0) {
NodeOperation *operation = stack.pop_last();
- const int num_inputs = operation->getNumberOfInputSockets();
+ const int num_inputs = operation->get_number_of_input_sockets();
for (int i = 0; i < num_inputs; i++) {
NodeOperation *input_op = operation->get_input_operation(i);
if (!active_buffers_.has_registered_reads(input_op)) {
@@ -258,13 +244,9 @@ void FullFrameExecutionModel::determine_reads(NodeOperation *output_op)
}
}
-/**
- * Calculates given output operation area to be rendered taking into account viewer and render
- * borders.
- */
void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, rcti &r_area)
{
- BLI_assert(output_op->isOutputOperation(context_.isRendering()));
+ BLI_assert(output_op->is_output_operation(context_.is_rendering()));
/* By default return operation bounds (no border). */
rcti canvas = output_op->get_canvas();
@@ -279,8 +261,8 @@ void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, r
const rctf *norm_border = has_viewer_border ? border_.viewer_border : border_.render_border;
/* Return de-normalized border within canvas. */
- const int w = output_op->getWidth();
- const int h = output_op->getHeight();
+ const int w = output_op->get_width();
+ const int h = output_op->get_height();
r_area.xmin = canvas.xmin + norm_border->xmin * w;
r_area.xmax = canvas.xmin + norm_border->xmax * w;
r_area.ymin = canvas.ymin + norm_border->ymin * h;
@@ -291,7 +273,7 @@ void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, r
void FullFrameExecutionModel::operation_finished(NodeOperation *operation)
{
/* Report inputs reads so that buffers may be freed/reused. */
- const int num_inputs = operation->getNumberOfInputSockets();
+ const int num_inputs = operation->get_number_of_input_sockets();
for (int i = 0; i < num_inputs; i++) {
active_buffers_.read_finished(operation->get_input_operation(i));
}
@@ -302,7 +284,7 @@ void FullFrameExecutionModel::operation_finished(NodeOperation *operation)
void FullFrameExecutionModel::update_progress_bar()
{
- const bNodeTree *tree = context_.getbNodeTree();
+ const bNodeTree *tree = context_.get_bnodetree();
if (tree) {
const float progress = num_operations_finished_ / static_cast<float>(operations_.size());
tree->progress(tree->prh, progress);
diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.h b/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
index 66dfb8f052c..6d3a5fba53a 100644
--- a/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
+++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
@@ -18,6 +18,9 @@
#pragma once
+#include "BLI_vector.hh"
+
+#include "COM_Enums.h"
#include "COM_ExecutionModel.h"
#ifdef WITH_CXX_GUARDEDALLOC
@@ -27,7 +30,11 @@
namespace blender::compositor {
/* Forward declarations. */
-class ExecutionGroup;
+class CompositorContext;
+class ExecutionSystem;
+class MemoryBuffer;
+class NodeOperation;
+class SharedOperationBuffers;
/**
* Fully renders operations in order from inputs to outputs.
@@ -35,8 +42,8 @@ class ExecutionGroup;
class FullFrameExecutionModel : public ExecutionModel {
private:
/**
- * Contains operations active buffers data. Buffers will be disposed once reader operations are
- * finished.
+ * Contains operations active buffers data.
+ * Buffers will be disposed once reader operations are finished.
*/
SharedOperationBuffers &active_buffers_;
@@ -59,18 +66,34 @@ class FullFrameExecutionModel : public ExecutionModel {
private:
void determine_areas_to_render_and_reads();
+ /**
+ * Render output operations in order of priority.
+ */
void render_operations();
void render_output_dependencies(NodeOperation *output_op);
- Vector<MemoryBuffer *> get_input_buffers(NodeOperation *op,
- const int output_x,
- const int output_y);
- MemoryBuffer *create_operation_buffer(NodeOperation *op, const int output_x, const int output_y);
+ /**
+ * Returns input buffers with an offset relative to given output coordinates.
+ * Returned memory buffers must be deleted.
+ */
+ Vector<MemoryBuffer *> get_input_buffers(NodeOperation *op, int output_x, int output_y);
+ MemoryBuffer *create_operation_buffer(NodeOperation *op, int output_x, int output_y);
void render_operation(NodeOperation *op);
void operation_finished(NodeOperation *operation);
+ /**
+ * Calculates given output operation area to be rendered taking into account viewer and render
+ * borders.
+ */
void get_output_render_area(NodeOperation *output_op, rcti &r_area);
+ /**
+ * Determines all operations areas needed to render given output area.
+ */
void determine_areas_to_render(NodeOperation *output_op, const rcti &output_area);
+ /**
+ * Determines reads to receive by operations in output operation tree (i.e: Number of dependent
+ * operations each operation has).
+ */
void determine_reads(NodeOperation *output_op);
void update_progress_bar();
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cc b/source/blender/compositor/intern/COM_MemoryBuffer.cc
index f57f0f055bf..dcc279e3b88 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.cc
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc
@@ -18,9 +18,10 @@
#include "COM_MemoryBuffer.h"
+#include "COM_MemoryProxy.h"
+
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
-#include "MEM_guardedalloc.h"
#define ASSERT_BUFFER_CONTAINS_AREA(buf, area) \
BLI_assert(BLI_rcti_inside_rcti(&(buf)->get_rect(), &(area)))
@@ -43,129 +44,116 @@ static rcti create_rect(const int width, const int height)
return rect;
}
-MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, const rcti &rect, MemoryBufferState state)
+MemoryBuffer::MemoryBuffer(MemoryProxy *memory_proxy, const rcti &rect, MemoryBufferState state)
{
- m_rect = rect;
- this->m_is_a_single_elem = false;
- this->m_memoryProxy = memoryProxy;
- this->m_num_channels = COM_data_type_num_channels(memoryProxy->getDataType());
- this->m_buffer = (float *)MEM_mallocN_aligned(
- sizeof(float) * buffer_len() * this->m_num_channels, 16, "COM_MemoryBuffer");
+ rect_ = rect;
+ is_a_single_elem_ = false;
+ memory_proxy_ = memory_proxy;
+ num_channels_ = COM_data_type_num_channels(memory_proxy->get_data_type());
+ buffer_ = (float *)MEM_mallocN_aligned(
+ sizeof(float) * buffer_len() * num_channels_, 16, "COM_MemoryBuffer");
owns_data_ = true;
- this->m_state = state;
- this->m_datatype = memoryProxy->getDataType();
+ state_ = state;
+ datatype_ = memory_proxy->get_data_type();
set_strides();
}
-MemoryBuffer::MemoryBuffer(DataType dataType, const rcti &rect, bool is_a_single_elem)
+MemoryBuffer::MemoryBuffer(DataType data_type, const rcti &rect, bool is_a_single_elem)
{
- m_rect = rect;
- this->m_is_a_single_elem = is_a_single_elem;
- this->m_memoryProxy = nullptr;
- this->m_num_channels = COM_data_type_num_channels(dataType);
- this->m_buffer = (float *)MEM_mallocN_aligned(
- sizeof(float) * buffer_len() * this->m_num_channels, 16, "COM_MemoryBuffer");
+ rect_ = rect;
+ is_a_single_elem_ = is_a_single_elem;
+ memory_proxy_ = nullptr;
+ num_channels_ = COM_data_type_num_channels(data_type);
+ buffer_ = (float *)MEM_mallocN_aligned(
+ sizeof(float) * buffer_len() * num_channels_, 16, "COM_MemoryBuffer");
owns_data_ = true;
- this->m_state = MemoryBufferState::Temporary;
- this->m_datatype = dataType;
+ state_ = MemoryBufferState::Temporary;
+ datatype_ = data_type;
set_strides();
}
-/**
- * Construct MemoryBuffer from a float buffer. MemoryBuffer is not responsible for
- * freeing it.
- */
MemoryBuffer::MemoryBuffer(
float *buffer, int num_channels, int width, int height, bool is_a_single_elem)
: MemoryBuffer(buffer, num_channels, create_rect(width, height), is_a_single_elem)
{
}
-/**
- * Construct MemoryBuffer from a float buffer area. MemoryBuffer is not responsible for
- * freeing given buffer.
- */
MemoryBuffer::MemoryBuffer(float *buffer,
const int num_channels,
const rcti &rect,
const bool is_a_single_elem)
{
- m_rect = rect;
- m_is_a_single_elem = is_a_single_elem;
- m_memoryProxy = nullptr;
- m_num_channels = num_channels;
- m_datatype = COM_num_channels_data_type(num_channels);
- m_buffer = buffer;
+ rect_ = rect;
+ is_a_single_elem_ = is_a_single_elem;
+ memory_proxy_ = nullptr;
+ num_channels_ = num_channels;
+ datatype_ = COM_num_channels_data_type(num_channels);
+ buffer_ = buffer;
owns_data_ = false;
- m_state = MemoryBufferState::Temporary;
+ state_ = MemoryBufferState::Temporary;
set_strides();
}
-MemoryBuffer::MemoryBuffer(const MemoryBuffer &src)
- : MemoryBuffer(src.m_datatype, src.m_rect, false)
+MemoryBuffer::MemoryBuffer(const MemoryBuffer &src) : MemoryBuffer(src.datatype_, src.rect_, false)
{
- m_memoryProxy = src.m_memoryProxy;
+ memory_proxy_ = src.memory_proxy_;
/* src may be single elem buffer */
fill_from(src);
}
void MemoryBuffer::set_strides()
{
- if (m_is_a_single_elem) {
+ if (is_a_single_elem_) {
this->elem_stride = 0;
this->row_stride = 0;
}
else {
- this->elem_stride = m_num_channels;
- this->row_stride = getWidth() * m_num_channels;
+ this->elem_stride = num_channels_;
+ this->row_stride = get_width() * num_channels_;
}
- to_positive_x_stride_ = m_rect.xmin < 0 ? -m_rect.xmin + 1 : (m_rect.xmin == 0 ? 1 : 0);
- to_positive_y_stride_ = m_rect.ymin < 0 ? -m_rect.ymin + 1 : (m_rect.ymin == 0 ? 1 : 0);
+ to_positive_x_stride_ = rect_.xmin < 0 ? -rect_.xmin + 1 : (rect_.xmin == 0 ? 1 : 0);
+ to_positive_y_stride_ = rect_.ymin < 0 ? -rect_.ymin + 1 : (rect_.ymin == 0 ? 1 : 0);
}
void MemoryBuffer::clear()
{
- memset(m_buffer, 0, buffer_len() * m_num_channels * sizeof(float));
+ memset(buffer_, 0, buffer_len() * num_channels_ * sizeof(float));
}
BuffersIterator<float> MemoryBuffer::iterate_with(Span<MemoryBuffer *> inputs)
{
- return iterate_with(inputs, m_rect);
+ return iterate_with(inputs, rect_);
}
BuffersIterator<float> MemoryBuffer::iterate_with(Span<MemoryBuffer *> inputs, const rcti &area)
{
- BuffersIteratorBuilder<float> builder(m_buffer, m_rect, area, elem_stride);
+ BuffersIteratorBuilder<float> builder(buffer_, rect_, area, elem_stride);
for (MemoryBuffer *input : inputs) {
- builder.add_input(input->getBuffer(), input->get_rect(), input->elem_stride);
+ builder.add_input(input->get_buffer(), input->get_rect(), input->elem_stride);
}
return builder.build();
}
-/**
- * Converts a single elem buffer to a full size buffer (allocates memory for all
- * elements in resolution).
- */
MemoryBuffer *MemoryBuffer::inflate() const
{
BLI_assert(is_a_single_elem());
- MemoryBuffer *inflated = new MemoryBuffer(this->m_datatype, this->m_rect, false);
- inflated->copy_from(this, this->m_rect);
+ MemoryBuffer *inflated = new MemoryBuffer(datatype_, rect_, false);
+ inflated->copy_from(this, rect_);
return inflated;
}
float MemoryBuffer::get_max_value() const
{
- float result = this->m_buffer[0];
+ float result = buffer_[0];
const unsigned int size = this->buffer_len();
unsigned int i;
- const float *fp_src = this->m_buffer;
+ const float *fp_src = buffer_;
- for (i = 0; i < size; i++, fp_src += this->m_num_channels) {
+ for (i = 0; i < size; i++, fp_src += num_channels_) {
float value = *fp_src;
if (value > result) {
result = value;
@@ -180,10 +168,10 @@ float MemoryBuffer::get_max_value(const rcti &rect) const
rcti rect_clamp;
/* first clamp the rect by the bounds or we get un-initialized values */
- BLI_rcti_isect(&rect, &this->m_rect, &rect_clamp);
+ BLI_rcti_isect(&rect, &rect_, &rect_clamp);
if (!BLI_rcti_is_empty(&rect_clamp)) {
- MemoryBuffer temp_buffer(this->m_datatype, rect_clamp);
+ MemoryBuffer temp_buffer(datatype_, rect_clamp);
temp_buffer.fill_from(*this);
return temp_buffer.get_max_value();
}
@@ -194,9 +182,9 @@ float MemoryBuffer::get_max_value(const rcti &rect) const
MemoryBuffer::~MemoryBuffer()
{
- if (this->m_buffer && owns_data_) {
- MEM_freeN(this->m_buffer);
- this->m_buffer = nullptr;
+ if (buffer_ && owns_data_) {
+ MEM_freeN(buffer_);
+ buffer_ = nullptr;
}
}
@@ -248,7 +236,7 @@ void MemoryBuffer::copy_from(const MemoryBuffer *src,
void MemoryBuffer::copy_from(const uchar *src, const rcti &area)
{
const int elem_stride = this->get_num_channels();
- const int row_stride = elem_stride * getWidth();
+ const int row_stride = elem_stride * get_width();
copy_from(src, area, 0, this->get_num_channels(), elem_stride, row_stride, 0);
}
@@ -301,13 +289,30 @@ void MemoryBuffer::copy_from(const uchar *src,
}
}
+void MemoryBuffer::apply_processor(ColormanageProcessor &processor, const rcti area)
+{
+ const int width = BLI_rcti_size_x(&area);
+ const int height = BLI_rcti_size_y(&area);
+ float *out = get_elem(area.xmin, area.ymin);
+ /* If area allows continuous memory do conversion in one step. Otherwise per row. */
+ if (get_width() == width) {
+ IMB_colormanagement_processor_apply(&processor, out, width, height, get_num_channels(), false);
+ }
+ else {
+ for (int y = 0; y < height; y++) {
+ IMB_colormanagement_processor_apply(&processor, out, width, 1, get_num_channels(), false);
+ out += row_stride;
+ }
+ }
+}
+
static void colorspace_to_scene_linear(MemoryBuffer *buf, const rcti &area, ColorSpace *colorspace)
{
const int width = BLI_rcti_size_x(&area);
const int height = BLI_rcti_size_y(&area);
float *out = buf->get_elem(area.xmin, area.ymin);
/* If area allows continuous memory do conversion in one step. Otherwise per row. */
- if (buf->getWidth() == width) {
+ if (buf->get_width() == width) {
IMB_colormanagement_colorspace_to_scene_linear(
out, width, height, buf->get_num_channels(), colorspace, false);
}
@@ -397,30 +402,28 @@ void MemoryBuffer::fill(const rcti &area,
void MemoryBuffer::fill_from(const MemoryBuffer &src)
{
rcti overlap;
- overlap.xmin = MAX2(this->m_rect.xmin, src.m_rect.xmin);
- overlap.xmax = MIN2(this->m_rect.xmax, src.m_rect.xmax);
- overlap.ymin = MAX2(this->m_rect.ymin, src.m_rect.ymin);
- overlap.ymax = MIN2(this->m_rect.ymax, src.m_rect.ymax);
+ overlap.xmin = MAX2(rect_.xmin, src.rect_.xmin);
+ overlap.xmax = MIN2(rect_.xmax, src.rect_.xmax);
+ overlap.ymin = MAX2(rect_.ymin, src.rect_.ymin);
+ overlap.ymax = MIN2(rect_.ymax, src.rect_.ymax);
copy_from(&src, overlap);
}
-void MemoryBuffer::writePixel(int x, int y, const float color[4])
+void MemoryBuffer::write_pixel(int x, int y, const float color[4])
{
- if (x >= this->m_rect.xmin && x < this->m_rect.xmax && y >= this->m_rect.ymin &&
- y < this->m_rect.ymax) {
+ if (x >= rect_.xmin && x < rect_.xmax && y >= rect_.ymin && y < rect_.ymax) {
const int offset = get_coords_offset(x, y);
- memcpy(&this->m_buffer[offset], color, sizeof(float) * this->m_num_channels);
+ memcpy(&buffer_[offset], color, sizeof(float) * num_channels_);
}
}
-void MemoryBuffer::addPixel(int x, int y, const float color[4])
+void MemoryBuffer::add_pixel(int x, int y, const float color[4])
{
- if (x >= this->m_rect.xmin && x < this->m_rect.xmax && y >= this->m_rect.ymin &&
- y < this->m_rect.ymax) {
+ if (x >= rect_.xmin && x < rect_.xmax && y >= rect_.ymin && y < rect_.ymax) {
const int offset = get_coords_offset(x, y);
- float *dst = &this->m_buffer[offset];
+ float *dst = &buffer_[offset];
const float *src = color;
- for (int i = 0; i < this->m_num_channels; i++, dst++, src++) {
+ for (int i = 0; i < num_channels_; i++, dst++, src++) {
*dst += *src;
}
}
@@ -435,11 +438,11 @@ static void read_ewa_elem(void *userdata, int x, int y, float result[4])
void MemoryBuffer::read_elem_filtered(
const float x, const float y, float dx[2], float dy[2], float *out) const
{
- BLI_assert(this->m_datatype == DataType::Color);
+ BLI_assert(datatype_ == DataType::Color);
const float deriv[2][2] = {{dx[0], dx[1]}, {dy[0], dy[1]}};
- float inv_width = 1.0f / (float)this->getWidth(), inv_height = 1.0f / (float)this->getHeight();
+ float inv_width = 1.0f / (float)this->get_width(), inv_height = 1.0f / (float)this->get_height();
/* TODO(sergey): Render pipeline uses normalized coordinates and derivatives,
* but compositor uses pixel space. For now let's just divide the values and
* switch compositor to normalized space for EWA later.
@@ -448,8 +451,8 @@ void MemoryBuffer::read_elem_filtered(
float du_normal[2] = {deriv[0][0] * inv_width, deriv[0][1] * inv_height};
float dv_normal[2] = {deriv[1][0] * inv_width, deriv[1][1] * inv_height};
- BLI_ewa_filter(this->getWidth(),
- this->getHeight(),
+ BLI_ewa_filter(this->get_width(),
+ this->get_height(),
false,
true,
uv_normal,
@@ -470,12 +473,13 @@ static void read_ewa_pixel_sampled(void *userdata, int x, int y, float result[4]
/* TODO(manzanilla): to be removed with tiled implementation. */
void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivatives[2][2])
{
- if (m_is_a_single_elem) {
- memcpy(result, m_buffer, sizeof(float) * this->m_num_channels);
+ if (is_a_single_elem_) {
+ memcpy(result, buffer_, sizeof(float) * num_channels_);
}
else {
- BLI_assert(this->m_datatype == DataType::Color);
- float inv_width = 1.0f / (float)this->getWidth(), inv_height = 1.0f / (float)this->getHeight();
+ BLI_assert(datatype_ == DataType::Color);
+ float inv_width = 1.0f / (float)this->get_width(),
+ inv_height = 1.0f / (float)this->get_height();
/* TODO(sergey): Render pipeline uses normalized coordinates and derivatives,
* but compositor uses pixel space. For now let's just divide the values and
* switch compositor to normalized space for EWA later.
@@ -484,8 +488,8 @@ void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivat
float du_normal[2] = {derivatives[0][0] * inv_width, derivatives[0][1] * inv_height};
float dv_normal[2] = {derivatives[1][0] * inv_width, derivatives[1][1] * inv_height};
- BLI_ewa_filter(this->getWidth(),
- this->getHeight(),
+ BLI_ewa_filter(this->get_width(),
+ this->get_height(),
false,
true,
uv_normal,
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index 9e173f73f63..1765fb93035 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -21,12 +21,15 @@
#include "COM_BufferArea.h"
#include "COM_BufferRange.h"
#include "COM_BuffersIterator.h"
-#include "COM_ExecutionGroup.h"
-#include "COM_MemoryProxy.h"
+#include "COM_Enums.h"
-#include "BLI_math.h"
+#include "BLI_math_interp.h"
#include "BLI_rect.h"
+#include "IMB_colormanagement.h"
+
+struct ImBuf;
+
namespace blender::compositor {
/**
@@ -76,38 +79,38 @@ class MemoryBuffer {
/**
* \brief proxy of the memory (same for all chunks in the same buffer)
*/
- MemoryProxy *m_memoryProxy;
+ MemoryProxy *memory_proxy_;
/**
* \brief the type of buffer DataType::Value, DataType::Vector, DataType::Color
*/
- DataType m_datatype;
+ DataType datatype_;
/**
* \brief region of this buffer inside relative to the MemoryProxy
*/
- rcti m_rect;
+ rcti rect_;
/**
* \brief state of the buffer
*/
- MemoryBufferState m_state;
+ MemoryBufferState state_;
/**
* \brief the actual float buffer/data
*/
- float *m_buffer;
+ float *buffer_;
/**
* \brief the number of channels of a single value in the buffer.
* For value buffers this is 1, vector 3 and color 4
*/
- uint8_t m_num_channels;
+ uint8_t num_channels_;
/**
* Whether buffer is a single element in memory.
*/
- bool m_is_a_single_elem;
+ bool is_a_single_elem_;
/**
* Whether MemoryBuffer owns buffer data.
@@ -124,16 +127,24 @@ class MemoryBuffer {
/**
* \brief construct new temporarily MemoryBuffer for an area
*/
- MemoryBuffer(MemoryProxy *memoryProxy, const rcti &rect, MemoryBufferState state);
+ MemoryBuffer(MemoryProxy *memory_proxy, const rcti &rect, MemoryBufferState state);
/**
* \brief construct new temporarily MemoryBuffer for an area
*/
- MemoryBuffer(DataType datatype, const rcti &rect, bool is_a_single_elem = false);
+ MemoryBuffer(DataType data_type, const rcti &rect, bool is_a_single_elem = false);
+ /**
+ * Construct MemoryBuffer from a float buffer. MemoryBuffer is not responsible for
+ * freeing it.
+ */
MemoryBuffer(
float *buffer, int num_channels, int width, int height, bool is_a_single_elem = false);
+ /**
+ * Construct MemoryBuffer from a float buffer area. MemoryBuffer is not responsible for
+ * freeing given buffer.
+ */
MemoryBuffer(float *buffer, int num_channels, const rcti &rect, bool is_a_single_elem = false);
/**
@@ -152,21 +163,21 @@ class MemoryBuffer {
*/
bool is_a_single_elem() const
{
- return m_is_a_single_elem;
+ return is_a_single_elem_;
}
float &operator[](int index)
{
- BLI_assert(m_is_a_single_elem ? index < m_num_channels :
- index < get_coords_offset(getWidth(), getHeight()));
- return m_buffer[index];
+ BLI_assert(is_a_single_elem_ ? index < num_channels_ :
+ index < get_coords_offset(get_width(), get_height()));
+ return buffer_[index];
}
const float &operator[](int index) const
{
- BLI_assert(m_is_a_single_elem ? index < m_num_channels :
- index < get_coords_offset(getWidth(), getHeight()));
- return m_buffer[index];
+ BLI_assert(is_a_single_elem_ ? index < num_channels_ :
+ index < get_coords_offset(get_width(), get_height()));
+ return buffer_[index];
}
/**
@@ -174,7 +185,7 @@ class MemoryBuffer {
*/
intptr_t get_coords_offset(int x, int y) const
{
- return ((intptr_t)y - m_rect.ymin) * row_stride + ((intptr_t)x - m_rect.xmin) * elem_stride;
+ return ((intptr_t)y - rect_.ymin) * row_stride + ((intptr_t)x - rect_.xmin) * elem_stride;
}
/**
@@ -183,7 +194,7 @@ class MemoryBuffer {
float *get_elem(int x, int y)
{
BLI_assert(has_coords(x, y));
- return m_buffer + get_coords_offset(x, y);
+ return buffer_ + get_coords_offset(x, y);
}
/**
@@ -192,7 +203,7 @@ class MemoryBuffer {
const float *get_elem(int x, int y) const
{
BLI_assert(has_coords(x, y));
- return m_buffer + get_coords_offset(x, y);
+ return buffer_ + get_coords_offset(x, y);
}
void read_elem(int x, int y, float *out) const
@@ -218,21 +229,19 @@ class MemoryBuffer {
void read_elem_bilinear(float x, float y, float *out) const
{
/* Only clear past +/-1 borders to be able to smooth edges. */
- if (x <= m_rect.xmin - 1.0f || x >= m_rect.xmax || y <= m_rect.ymin - 1.0f ||
- y >= m_rect.ymax) {
+ if (x <= rect_.xmin - 1.0f || x >= rect_.xmax || y <= rect_.ymin - 1.0f || y >= rect_.ymax) {
clear_elem(out);
return;
}
- if (m_is_a_single_elem) {
- if (x >= m_rect.xmin && x < m_rect.xmax - 1.0f && y >= m_rect.ymin &&
- y < m_rect.ymax - 1.0f) {
- memcpy(out, m_buffer, get_elem_bytes_len());
+ if (is_a_single_elem_) {
+ if (x >= rect_.xmin && x < rect_.xmax - 1.0f && y >= rect_.ymin && y < rect_.ymax - 1.0f) {
+ memcpy(out, buffer_, get_elem_bytes_len());
return;
}
/* Do sampling at borders to smooth edges. */
- const float last_x = getWidth() - 1.0f;
+ const float last_x = get_width() - 1.0f;
const float rel_x = get_relative_x(x);
float single_x = 0.0f;
if (rel_x < 0.0f) {
@@ -242,7 +251,7 @@ class MemoryBuffer {
single_x = rel_x - last_x;
}
- const float last_y = getHeight() - 1.0f;
+ const float last_y = get_height() - 1.0f;
const float rel_y = get_relative_y(y);
float single_y = 0.0f;
if (rel_y < 0.0f) {
@@ -252,15 +261,15 @@ class MemoryBuffer {
single_y = rel_y - last_y;
}
- BLI_bilinear_interpolation_fl(m_buffer, out, 1, 1, m_num_channels, single_x, single_y);
+ BLI_bilinear_interpolation_fl(buffer_, out, 1, 1, num_channels_, single_x, single_y);
return;
}
- BLI_bilinear_interpolation_fl(m_buffer,
+ BLI_bilinear_interpolation_fl(buffer_,
out,
- getWidth(),
- getHeight(),
- m_num_channels,
+ get_width(),
+ get_height(),
+ num_channels_,
get_relative_x(x),
get_relative_y(y));
}
@@ -279,16 +288,15 @@ class MemoryBuffer {
}
}
- void read_elem_filtered(
- const float x, const float y, float dx[2], float dy[2], float *out) const;
+ void read_elem_filtered(float x, float y, float dx[2], float dy[2], float *out) const;
/**
* Get channel value at given coordinates.
*/
float &get_value(int x, int y, int channel)
{
- BLI_assert(has_coords(x, y) && channel >= 0 && channel < m_num_channels);
- return m_buffer[get_coords_offset(x, y) + channel];
+ BLI_assert(has_coords(x, y) && channel >= 0 && channel < num_channels_);
+ return buffer_[get_coords_offset(x, y) + channel];
}
/**
@@ -296,8 +304,8 @@ class MemoryBuffer {
*/
const float &get_value(int x, int y, int channel) const
{
- BLI_assert(has_coords(x, y) && channel >= 0 && channel < m_num_channels);
- return m_buffer[get_coords_offset(x, y) + channel];
+ BLI_assert(has_coords(x, y) && channel >= 0 && channel < num_channels_);
+ return buffer_[get_coords_offset(x, y) + channel];
}
/**
@@ -306,7 +314,7 @@ class MemoryBuffer {
const float *get_row_end(int y) const
{
BLI_assert(has_y(y));
- return m_buffer + (is_a_single_elem() ? m_num_channels : get_coords_offset(getWidth(), y));
+ return buffer_ + (is_a_single_elem() ? num_channels_ : get_coords_offset(get_width(), y));
}
/**
@@ -315,7 +323,7 @@ class MemoryBuffer {
*/
int get_memory_width() const
{
- return is_a_single_elem() ? 1 : getWidth();
+ return is_a_single_elem() ? 1 : get_width();
}
/**
@@ -324,17 +332,17 @@ class MemoryBuffer {
*/
int get_memory_height() const
{
- return is_a_single_elem() ? 1 : getHeight();
+ return is_a_single_elem() ? 1 : get_height();
}
uint8_t get_num_channels() const
{
- return this->m_num_channels;
+ return num_channels_;
}
uint8_t get_elem_bytes_len() const
{
- return this->m_num_channels * sizeof(float);
+ return num_channels_ * sizeof(float);
}
/**
@@ -342,22 +350,22 @@ class MemoryBuffer {
*/
BufferRange<float> as_range()
{
- return BufferRange<float>(m_buffer, 0, buffer_len(), elem_stride);
+ return BufferRange<float>(buffer_, 0, buffer_len(), elem_stride);
}
BufferRange<const float> as_range() const
{
- return BufferRange<const float>(m_buffer, 0, buffer_len(), elem_stride);
+ return BufferRange<const float>(buffer_, 0, buffer_len(), elem_stride);
}
BufferArea<float> get_buffer_area(const rcti &area)
{
- return BufferArea<float>(m_buffer, getWidth(), area, elem_stride);
+ return BufferArea<float>(buffer_, get_width(), area, elem_stride);
}
BufferArea<const float> get_buffer_area(const rcti &area) const
{
- return BufferArea<const float>(m_buffer, getWidth(), area, elem_stride);
+ return BufferArea<const float>(buffer_, get_width(), area, elem_stride);
}
BuffersIterator<float> iterate_with(Span<MemoryBuffer *> inputs);
@@ -367,25 +375,29 @@ class MemoryBuffer {
* \brief get the data of this MemoryBuffer
* \note buffer should already be available in memory
*/
- float *getBuffer()
+ float *get_buffer()
{
- return this->m_buffer;
+ return buffer_;
}
float *release_ownership_buffer()
{
owns_data_ = false;
- return this->m_buffer;
+ return buffer_;
}
+ /**
+ * Converts a single elem buffer to a full size buffer (allocates memory for all
+ * elements in resolution).
+ */
MemoryBuffer *inflate() const;
inline void wrap_pixel(int &x, int &y, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y)
{
- const int w = getWidth();
- const int h = getHeight();
- x = x - m_rect.xmin;
- y = y - m_rect.ymin;
+ const int w = get_width();
+ const int h = get_height();
+ x = x - rect_.xmin;
+ y = y - rect_.ymin;
switch (extend_x) {
case MemoryBufferExtend::Clip:
@@ -425,8 +437,8 @@ class MemoryBuffer {
break;
}
- x = x + m_rect.xmin;
- y = y + m_rect.ymin;
+ x = x + rect_.xmin;
+ y = y + rect_.ymin;
}
inline void wrap_pixel(float &x,
@@ -434,10 +446,10 @@ class MemoryBuffer {
MemoryBufferExtend extend_x,
MemoryBufferExtend extend_y) const
{
- const float w = (float)getWidth();
- const float h = (float)getHeight();
- x = x - m_rect.xmin;
- y = y - m_rect.ymin;
+ const float w = (float)get_width();
+ const float h = (float)get_height();
+ x = x - rect_.xmin;
+ y = y - rect_.ymin;
switch (extend_x) {
case MemoryBufferExtend::Clip:
@@ -477,8 +489,8 @@ class MemoryBuffer {
break;
}
- x = x + m_rect.xmin;
- y = y + m_rect.ymin;
+ x = x + rect_.xmin;
+ y = y + rect_.ymin;
}
/* TODO(manzanilla): to be removed with tiled implementation. For applying #MemoryBufferExtend
@@ -489,28 +501,28 @@ class MemoryBuffer {
MemoryBufferExtend extend_x = MemoryBufferExtend::Clip,
MemoryBufferExtend extend_y = MemoryBufferExtend::Clip)
{
- bool clip_x = (extend_x == MemoryBufferExtend::Clip && (x < m_rect.xmin || x >= m_rect.xmax));
- bool clip_y = (extend_y == MemoryBufferExtend::Clip && (y < m_rect.ymin || y >= m_rect.ymax));
+ bool clip_x = (extend_x == MemoryBufferExtend::Clip && (x < rect_.xmin || x >= rect_.xmax));
+ bool clip_y = (extend_y == MemoryBufferExtend::Clip && (y < rect_.ymin || y >= rect_.ymax));
if (clip_x || clip_y) {
/* clip result outside rect is zero */
- memset(result, 0, this->m_num_channels * sizeof(float));
+ memset(result, 0, num_channels_ * sizeof(float));
}
else {
int u = x;
int v = y;
this->wrap_pixel(u, v, extend_x, extend_y);
const int offset = get_coords_offset(u, v);
- float *buffer = &this->m_buffer[offset];
- memcpy(result, buffer, sizeof(float) * this->m_num_channels);
+ float *buffer = &buffer_[offset];
+ memcpy(result, buffer, sizeof(float) * num_channels_);
}
}
/* TODO(manzanilla): to be removed with tiled implementation. */
- inline void readNoCheck(float *result,
- int x,
- int y,
- MemoryBufferExtend extend_x = MemoryBufferExtend::Clip,
- MemoryBufferExtend extend_y = MemoryBufferExtend::Clip)
+ inline void read_no_check(float *result,
+ int x,
+ int y,
+ MemoryBufferExtend extend_x = MemoryBufferExtend::Clip,
+ MemoryBufferExtend extend_y = MemoryBufferExtend::Clip)
{
int u = x;
int v = y;
@@ -519,38 +531,38 @@ class MemoryBuffer {
const int offset = get_coords_offset(u, v);
BLI_assert(offset >= 0);
- BLI_assert(offset < this->buffer_len() * this->m_num_channels);
- BLI_assert(!(extend_x == MemoryBufferExtend::Clip && (u < m_rect.xmin || u >= m_rect.xmax)) &&
- !(extend_y == MemoryBufferExtend::Clip && (v < m_rect.ymin || v >= m_rect.ymax)));
- float *buffer = &this->m_buffer[offset];
- memcpy(result, buffer, sizeof(float) * this->m_num_channels);
+ BLI_assert(offset < this->buffer_len() * num_channels_);
+ BLI_assert(!(extend_x == MemoryBufferExtend::Clip && (u < rect_.xmin || u >= rect_.xmax)) &&
+ !(extend_y == MemoryBufferExtend::Clip && (v < rect_.ymin || v >= rect_.ymax)));
+ float *buffer = &buffer_[offset];
+ memcpy(result, buffer, sizeof(float) * num_channels_);
}
- void writePixel(int x, int y, const float color[4]);
- void addPixel(int x, int y, const float color[4]);
- inline void readBilinear(float *result,
- float x,
- float y,
- MemoryBufferExtend extend_x = MemoryBufferExtend::Clip,
- MemoryBufferExtend extend_y = MemoryBufferExtend::Clip) const
+ void write_pixel(int x, int y, const float color[4]);
+ void add_pixel(int x, int y, const float color[4]);
+ inline void read_bilinear(float *result,
+ float x,
+ float y,
+ MemoryBufferExtend extend_x = MemoryBufferExtend::Clip,
+ MemoryBufferExtend extend_y = MemoryBufferExtend::Clip) const
{
float u = x;
float v = y;
this->wrap_pixel(u, v, extend_x, extend_y);
- if ((extend_x != MemoryBufferExtend::Repeat && (u < 0.0f || u >= getWidth())) ||
- (extend_y != MemoryBufferExtend::Repeat && (v < 0.0f || v >= getHeight()))) {
- copy_vn_fl(result, this->m_num_channels, 0.0f);
+ if ((extend_x != MemoryBufferExtend::Repeat && (u < 0.0f || u >= get_width())) ||
+ (extend_y != MemoryBufferExtend::Repeat && (v < 0.0f || v >= get_height()))) {
+ copy_vn_fl(result, num_channels_, 0.0f);
return;
}
- if (m_is_a_single_elem) {
- memcpy(result, m_buffer, sizeof(float) * this->m_num_channels);
+ if (is_a_single_elem_) {
+ memcpy(result, buffer_, sizeof(float) * num_channels_);
}
else {
- BLI_bilinear_interpolation_wrap_fl(this->m_buffer,
+ BLI_bilinear_interpolation_wrap_fl(buffer_,
result,
- getWidth(),
- getHeight(),
- this->m_num_channels,
+ get_width(),
+ get_height(),
+ num_channels_,
u,
v,
extend_x == MemoryBufferExtend::Repeat,
@@ -563,11 +575,16 @@ class MemoryBuffer {
/**
* \brief is this MemoryBuffer a temporarily buffer (based on an area, not on a chunk)
*/
- inline bool isTemporarily() const
+ inline bool is_temporarily() const
{
- return this->m_state == MemoryBufferState::Temporary;
+ return state_ == MemoryBufferState::Temporary;
}
+ /**
+ * \brief Apply a color processor on the given area.
+ */
+ void apply_processor(ColormanageProcessor &processor, const rcti area);
+
void copy_from(const MemoryBuffer *src, const rcti &area);
void copy_from(const MemoryBuffer *src, const rcti &area, int to_x, int to_y);
void copy_from(const MemoryBuffer *src,
@@ -618,8 +635,8 @@ class MemoryBuffer {
void fill(const rcti &area, const float *value);
void fill(const rcti &area, int channel_offset, const float *value, int value_size);
/**
- * \brief add the content from otherBuffer to this MemoryBuffer
- * \param otherBuffer: source buffer
+ * \brief add the content from other_buffer to this MemoryBuffer
+ * \param other_buffer: source buffer
*
* \note take care when running this on a new buffer since it won't fill in
* uninitialized values in areas where the buffers don't overlap.
@@ -631,23 +648,23 @@ class MemoryBuffer {
*/
const rcti &get_rect() const
{
- return this->m_rect;
+ return rect_;
}
/**
* \brief get the width of this MemoryBuffer
*/
- const int getWidth() const
+ const int get_width() const
{
- return BLI_rcti_size_x(&m_rect);
+ return BLI_rcti_size_x(&rect_);
}
/**
* \brief get the height of this MemoryBuffer
*/
- const int getHeight() const
+ const int get_height() const
{
- return BLI_rcti_size_y(&m_rect);
+ return BLI_rcti_size_y(&rect_);
}
/**
@@ -667,17 +684,17 @@ class MemoryBuffer {
void clear_elem(float *out) const
{
- memset(out, 0, this->m_num_channels * sizeof(float));
+ memset(out, 0, num_channels_ * sizeof(float));
}
template<typename T> T get_relative_x(T x) const
{
- return x - m_rect.xmin;
+ return x - rect_.xmin;
}
template<typename T> T get_relative_y(T y) const
{
- return y - m_rect.ymin;
+ return y - rect_.ymin;
}
template<typename T> bool has_coords(T x, T y) const
@@ -687,12 +704,12 @@ class MemoryBuffer {
template<typename T> bool has_x(T x) const
{
- return x >= m_rect.xmin && x < m_rect.xmax;
+ return x >= rect_.xmin && x < rect_.xmax;
}
template<typename T> bool has_y(T y) const
{
- return y >= m_rect.ymin && y < m_rect.ymax;
+ return y >= rect_.ymin && y < rect_.ymax;
}
/* Fast `floor(..)` functions. The caller should check result is within buffer bounds.
@@ -711,18 +728,15 @@ class MemoryBuffer {
void copy_single_elem_from(const MemoryBuffer *src,
int channel_offset,
int elem_size,
- const int to_channel_offset);
- void copy_rows_from(const MemoryBuffer *src,
- const rcti &src_area,
- const int to_x,
- const int to_y);
+ int to_channel_offset);
+ void copy_rows_from(const MemoryBuffer *src, const rcti &src_area, int to_x, int to_y);
void copy_elems_from(const MemoryBuffer *src,
const rcti &area,
- const int channel_offset,
- const int elem_size,
- const int to_x,
- const int to_y,
- const int to_channel_offset);
+ int channel_offset,
+ int elem_size,
+ int to_x,
+ int to_y,
+ int to_channel_offset);
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:MemoryBuffer")
diff --git a/source/blender/compositor/intern/COM_MemoryProxy.cc b/source/blender/compositor/intern/COM_MemoryProxy.cc
index 6023850c944..6263c47fc9e 100644
--- a/source/blender/compositor/intern/COM_MemoryProxy.cc
+++ b/source/blender/compositor/intern/COM_MemoryProxy.cc
@@ -17,18 +17,16 @@
*/
#include "COM_MemoryProxy.h"
-
#include "COM_MemoryBuffer.h"
-#include "BLI_rect.h"
-
namespace blender::compositor {
MemoryProxy::MemoryProxy(DataType datatype)
{
- this->m_writeBufferOperation = nullptr;
- this->m_executor = nullptr;
- this->m_datatype = datatype;
+ write_buffer_operation_ = nullptr;
+ executor_ = nullptr;
+ buffer_ = nullptr;
+ datatype_ = datatype;
}
void MemoryProxy::allocate(unsigned int width, unsigned int height)
@@ -39,14 +37,14 @@ void MemoryProxy::allocate(unsigned int width, unsigned int height)
result.ymin = 0;
result.ymax = height;
- this->m_buffer = new MemoryBuffer(this, result, MemoryBufferState::Default);
+ buffer_ = new MemoryBuffer(this, result, MemoryBufferState::Default);
}
void MemoryProxy::free()
{
- if (this->m_buffer) {
- delete this->m_buffer;
- this->m_buffer = nullptr;
+ if (buffer_) {
+ delete buffer_;
+ buffer_ = nullptr;
}
}
diff --git a/source/blender/compositor/intern/COM_MemoryProxy.h b/source/blender/compositor/intern/COM_MemoryProxy.h
index 6814afada74..89149a47976 100644
--- a/source/blender/compositor/intern/COM_MemoryProxy.h
+++ b/source/blender/compositor/intern/COM_MemoryProxy.h
@@ -42,22 +42,22 @@ class MemoryProxy {
/**
* \brief reference to the output operation of the executiongroup
*/
- WriteBufferOperation *m_writeBufferOperation;
+ WriteBufferOperation *write_buffer_operation_;
/**
* \brief reference to the executor. the Execution group that can fill a chunk
*/
- ExecutionGroup *m_executor;
+ ExecutionGroup *executor_;
/**
* \brief the allocated memory
*/
- MemoryBuffer *m_buffer;
+ MemoryBuffer *buffer_;
/**
* \brief datatype of this MemoryProxy
*/
- DataType m_datatype;
+ DataType datatype_;
public:
MemoryProxy(DataType type);
@@ -66,35 +66,35 @@ class MemoryProxy {
* \brief set the ExecutionGroup that can be scheduled to calculate a certain chunk.
* \param group: the ExecutionGroup to set
*/
- void setExecutor(ExecutionGroup *executor)
+ void set_executor(ExecutionGroup *executor)
{
- this->m_executor = executor;
+ executor_ = executor;
}
/**
* \brief get the ExecutionGroup that can be scheduled to calculate a certain chunk.
*/
- ExecutionGroup *getExecutor() const
+ ExecutionGroup *get_executor() const
{
- return this->m_executor;
+ return executor_;
}
/**
* \brief set the WriteBufferOperation that is responsible for writing to this MemoryProxy
* \param operation:
*/
- void setWriteBufferOperation(WriteBufferOperation *operation)
+ void set_write_buffer_operation(WriteBufferOperation *operation)
{
- this->m_writeBufferOperation = operation;
+ write_buffer_operation_ = operation;
}
/**
* \brief get the WriteBufferOperation that is responsible for writing to this MemoryProxy
* \return WriteBufferOperation
*/
- WriteBufferOperation *getWriteBufferOperation() const
+ WriteBufferOperation *get_write_buffer_operation() const
{
- return this->m_writeBufferOperation;
+ return write_buffer_operation_;
}
/**
@@ -110,14 +110,14 @@ class MemoryProxy {
/**
* \brief get the allocated memory
*/
- inline MemoryBuffer *getBuffer()
+ inline MemoryBuffer *get_buffer()
{
- return this->m_buffer;
+ return buffer_;
}
- inline DataType getDataType()
+ inline DataType get_data_type()
{
- return this->m_datatype;
+ return datatype_;
}
#ifdef WITH_CXX_GUARDEDALLOC
diff --git a/source/blender/compositor/intern/COM_MetaData.cc b/source/blender/compositor/intern/COM_MetaData.cc
index a6fb84dfb87..50561975ae4 100644
--- a/source/blender/compositor/intern/COM_MetaData.cc
+++ b/source/blender/compositor/intern/COM_MetaData.cc
@@ -22,8 +22,6 @@
#include "RE_pipeline.h"
-#include <string_view>
-
namespace blender::compositor {
void MetaData::add(const blender::StringRef key, const blender::StringRef value)
@@ -31,18 +29,14 @@ void MetaData::add(const blender::StringRef key, const blender::StringRef value)
entries_.add(key, value);
}
-void MetaData::addCryptomatteEntry(const blender::StringRef layer_name,
- const blender::StringRefNull key,
- const blender::StringRef value)
+void MetaData::add_cryptomatte_entry(const blender::StringRef layer_name,
+ const blender::StringRefNull key,
+ const blender::StringRef value)
{
add(blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(layer_name, key), value);
}
-/* Replace the hash neutral cryptomatte keys with hashed versions.
- *
- * When a conversion happens it will also add the cryptomatte name key with the given
- * `layer_name`. */
-void MetaData::replaceHashNeutralCryptomatteKeys(const blender::StringRef layer_name)
+void MetaData::replace_hash_neutral_cryptomatte_keys(const blender::StringRef layer_name)
{
std::string cryptomatte_hash = entries_.pop_default(META_DATA_KEY_CRYPTOMATTE_HASH, "");
std::string cryptomatte_conversion = entries_.pop_default(META_DATA_KEY_CRYPTOMATTE_CONVERSION,
@@ -51,27 +45,28 @@ void MetaData::replaceHashNeutralCryptomatteKeys(const blender::StringRef layer_
if (cryptomatte_hash.length() || cryptomatte_conversion.length() ||
cryptomatte_manifest.length()) {
- addCryptomatteEntry(layer_name, "name", layer_name);
+ add_cryptomatte_entry(layer_name, "name", layer_name);
}
if (cryptomatte_hash.length()) {
- addCryptomatteEntry(layer_name, "hash", cryptomatte_hash);
+ add_cryptomatte_entry(layer_name, "hash", cryptomatte_hash);
}
if (cryptomatte_conversion.length()) {
- addCryptomatteEntry(layer_name, "conversion", cryptomatte_conversion);
+ add_cryptomatte_entry(layer_name, "conversion", cryptomatte_conversion);
}
if (cryptomatte_manifest.length()) {
- addCryptomatteEntry(layer_name, "manifest", cryptomatte_manifest);
+ add_cryptomatte_entry(layer_name, "manifest", cryptomatte_manifest);
}
}
-void MetaData::addToRenderResult(RenderResult *render_result) const
+void MetaData::add_to_render_result(RenderResult *render_result) const
{
for (Map<std::string, std::string>::Item entry : entries_.items()) {
BKE_render_result_stamp_data(render_result, entry.key.c_str(), entry.value.c_str());
}
}
-void MetaDataExtractCallbackData::addMetaData(blender::StringRef key, blender::StringRefNull value)
+void MetaDataExtractCallbackData::add_meta_data(blender::StringRef key,
+ blender::StringRefNull value)
{
if (!meta_data) {
meta_data = std::make_unique<MetaData>();
@@ -79,7 +74,7 @@ void MetaDataExtractCallbackData::addMetaData(blender::StringRef key, blender::S
meta_data->add(key, value);
}
-void MetaDataExtractCallbackData::setCryptomatteKeys(blender::StringRef cryptomatte_layer_name)
+void MetaDataExtractCallbackData::set_cryptomatte_keys(blender::StringRef cryptomatte_layer_name)
{
manifest_key = blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name,
"manifest");
@@ -97,13 +92,13 @@ void MetaDataExtractCallbackData::extract_cryptomatte_meta_data(void *_data,
MetaDataExtractCallbackData *data = static_cast<MetaDataExtractCallbackData *>(_data);
blender::StringRefNull key(propname);
if (key == data->hash_key) {
- data->addMetaData(META_DATA_KEY_CRYPTOMATTE_HASH, propvalue);
+ data->add_meta_data(META_DATA_KEY_CRYPTOMATTE_HASH, propvalue);
}
else if (key == data->conversion_key) {
- data->addMetaData(META_DATA_KEY_CRYPTOMATTE_CONVERSION, propvalue);
+ data->add_meta_data(META_DATA_KEY_CRYPTOMATTE_CONVERSION, propvalue);
}
else if (key == data->manifest_key) {
- data->addMetaData(META_DATA_KEY_CRYPTOMATTE_MANIFEST, propvalue);
+ data->add_meta_data(META_DATA_KEY_CRYPTOMATTE_MANIFEST, propvalue);
}
}
diff --git a/source/blender/compositor/intern/COM_MetaData.h b/source/blender/compositor/intern/COM_MetaData.h
index a76540dc3af..be47d7c281e 100644
--- a/source/blender/compositor/intern/COM_MetaData.h
+++ b/source/blender/compositor/intern/COM_MetaData.h
@@ -44,14 +44,20 @@ constexpr blender::StringRef META_DATA_KEY_CRYPTOMATTE_NAME("cryptomatte/{hash}/
class MetaData {
private:
Map<std::string, std::string> entries_;
- void addCryptomatteEntry(const blender::StringRef layer_name,
- const blender::StringRefNull key,
- const blender::StringRef value);
+ void add_cryptomatte_entry(const blender::StringRef layer_name,
+ const blender::StringRefNull key,
+ const blender::StringRef value);
public:
void add(const blender::StringRef key, const blender::StringRef value);
- void replaceHashNeutralCryptomatteKeys(const blender::StringRef layer_name);
- void addToRenderResult(RenderResult *render_result) const;
+ /**
+ * Replace the hash neutral cryptomatte keys with hashed versions.
+ *
+ * When a conversion happens it will also add the cryptomatte name key with the given
+ * `layer_name`.
+ */
+ void replace_hash_neutral_cryptomatte_keys(const blender::StringRef layer_name);
+ void add_to_render_result(RenderResult *render_result) const;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:MetaData")
#endif
@@ -63,8 +69,8 @@ struct MetaDataExtractCallbackData {
std::string conversion_key;
std::string manifest_key;
- void addMetaData(blender::StringRef key, blender::StringRefNull value);
- void setCryptomatteKeys(blender::StringRef cryptomatte_layer_name);
+ void add_meta_data(blender::StringRef key, blender::StringRefNull value);
+ void set_cryptomatte_keys(blender::StringRef cryptomatte_layer_name);
/* C type callback function (StampCallback). */
static void extract_cryptomatte_meta_data(void *_data,
const char *propname,
diff --git a/source/blender/compositor/intern/COM_MultiThreadedOperation.cc b/source/blender/compositor/intern/COM_MultiThreadedOperation.cc
index 7ccf6f76d9f..d118027202a 100644
--- a/source/blender/compositor/intern/COM_MultiThreadedOperation.cc
+++ b/source/blender/compositor/intern/COM_MultiThreadedOperation.cc
@@ -7,7 +7,7 @@ MultiThreadedOperation::MultiThreadedOperation()
{
num_passes_ = 1;
current_pass_ = 0;
- flags.is_fullframe_operation = true;
+ flags_.is_fullframe_operation = true;
}
void MultiThreadedOperation::update_memory_buffer(MemoryBuffer *output,
diff --git a/source/blender/compositor/intern/COM_MultiThreadedRowOperation.h b/source/blender/compositor/intern/COM_MultiThreadedRowOperation.h
index 3daa9eec474..c1835e85949 100644
--- a/source/blender/compositor/intern/COM_MultiThreadedRowOperation.h
+++ b/source/blender/compositor/intern/COM_MultiThreadedRowOperation.h
@@ -18,6 +18,8 @@
#pragma once
+#include "BLI_array.h"
+
#include "COM_MultiThreadedOperation.h"
namespace blender::compositor {
diff --git a/source/blender/compositor/intern/COM_Node.cc b/source/blender/compositor/intern/COM_Node.cc
index 6ac48e3646c..67af9496ca4 100644
--- a/source/blender/compositor/intern/COM_Node.cc
+++ b/source/blender/compositor/intern/COM_Node.cc
@@ -16,20 +16,10 @@
* Copyright 2011, Blender Foundation.
*/
-#include <cstring>
-
#include "BKE_node.h"
#include "RNA_access.h"
-#include "COM_ExecutionSystem.h"
-#include "COM_NodeOperation.h"
-#include "COM_TranslateOperation.h"
-
-#include "COM_SocketProxyNode.h"
-
-#include "COM_defines.h"
-
#include "COM_Node.h" /* own include */
namespace blender::compositor {
@@ -38,14 +28,14 @@ namespace blender::compositor {
**** Node ****
**************/
-Node::Node(bNode *editorNode, bool create_sockets)
- : m_editorNodeTree(nullptr),
- m_editorNode(editorNode),
- m_inActiveGroup(false),
- m_instanceKey(NODE_INSTANCE_KEY_NONE)
+Node::Node(bNode *editor_node, bool create_sockets)
+ : editor_node_tree_(nullptr),
+ editor_node_(editor_node),
+ in_active_group_(false),
+ instance_key_(NODE_INSTANCE_KEY_NONE)
{
if (create_sockets) {
- bNodeSocket *input = (bNodeSocket *)editorNode->inputs.first;
+ bNodeSocket *input = (bNodeSocket *)editor_node->inputs.first;
while (input != nullptr) {
DataType dt = DataType::Value;
if (input->type == SOCK_RGBA) {
@@ -55,10 +45,10 @@ Node::Node(bNode *editorNode, bool create_sockets)
dt = DataType::Vector;
}
- this->addInputSocket(dt, input);
+ this->add_input_socket(dt, input);
input = input->next;
}
- bNodeSocket *output = (bNodeSocket *)editorNode->outputs.first;
+ bNodeSocket *output = (bNodeSocket *)editor_node->outputs.first;
while (output != nullptr) {
DataType dt = DataType::Value;
if (output->type == SOCK_RGBA) {
@@ -68,7 +58,7 @@ Node::Node(bNode *editorNode, bool create_sockets)
dt = DataType::Vector;
}
- this->addOutputSocket(dt, output);
+ this->add_output_socket(dt, output);
output = output->next;
}
}
@@ -76,51 +66,51 @@ Node::Node(bNode *editorNode, bool create_sockets)
Node::~Node()
{
- while (!this->outputs.is_empty()) {
- delete (this->outputs.pop_last());
+ while (!outputs_.is_empty()) {
+ delete (outputs_.pop_last());
}
- while (!this->inputs.is_empty()) {
- delete (this->inputs.pop_last());
+ while (!inputs_.is_empty()) {
+ delete (inputs_.pop_last());
}
}
-void Node::addInputSocket(DataType datatype)
+void Node::add_input_socket(DataType datatype)
{
- this->addInputSocket(datatype, nullptr);
+ this->add_input_socket(datatype, nullptr);
}
-void Node::addInputSocket(DataType datatype, bNodeSocket *bSocket)
+void Node::add_input_socket(DataType datatype, bNodeSocket *bSocket)
{
NodeInput *socket = new NodeInput(this, bSocket, datatype);
- this->inputs.append(socket);
+ inputs_.append(socket);
}
-void Node::addOutputSocket(DataType datatype)
+void Node::add_output_socket(DataType datatype)
{
- this->addOutputSocket(datatype, nullptr);
+ this->add_output_socket(datatype, nullptr);
}
-void Node::addOutputSocket(DataType datatype, bNodeSocket *bSocket)
+void Node::add_output_socket(DataType datatype, bNodeSocket *bSocket)
{
NodeOutput *socket = new NodeOutput(this, bSocket, datatype);
- outputs.append(socket);
+ outputs_.append(socket);
}
-NodeOutput *Node::getOutputSocket(unsigned int index) const
+NodeOutput *Node::get_output_socket(unsigned int index) const
{
- return outputs[index];
+ return outputs_[index];
}
-NodeInput *Node::getInputSocket(unsigned int index) const
+NodeInput *Node::get_input_socket(unsigned int index) const
{
- return inputs[index];
+ return inputs_[index];
}
-bNodeSocket *Node::getEditorInputSocket(int editorNodeInputSocketIndex)
+bNodeSocket *Node::get_editor_input_socket(int editor_node_input_socket_index)
{
- bNodeSocket *bSock = (bNodeSocket *)this->getbNode()->inputs.first;
+ bNodeSocket *bSock = (bNodeSocket *)this->get_bnode()->inputs.first;
int index = 0;
while (bSock != nullptr) {
- if (index == editorNodeInputSocketIndex) {
+ if (index == editor_node_input_socket_index) {
return bSock;
}
index++;
@@ -128,12 +118,12 @@ bNodeSocket *Node::getEditorInputSocket(int editorNodeInputSocketIndex)
}
return nullptr;
}
-bNodeSocket *Node::getEditorOutputSocket(int editorNodeOutputSocketIndex)
+bNodeSocket *Node::get_editor_output_socket(int editor_node_output_socket_index)
{
- bNodeSocket *bSock = (bNodeSocket *)this->getbNode()->outputs.first;
+ bNodeSocket *bSock = (bNodeSocket *)this->get_bnode()->outputs.first;
int index = 0;
while (bSock != nullptr) {
- if (index == editorNodeOutputSocketIndex) {
+ if (index == editor_node_output_socket_index) {
return bSock;
}
index++;
@@ -147,33 +137,33 @@ bNodeSocket *Node::getEditorOutputSocket(int editorNodeOutputSocketIndex)
*******************/
NodeInput::NodeInput(Node *node, bNodeSocket *b_socket, DataType datatype)
- : m_node(node), m_editorSocket(b_socket), m_datatype(datatype), m_link(nullptr)
+ : node_(node), editor_socket_(b_socket), datatype_(datatype), link_(nullptr)
{
}
-void NodeInput::setLink(NodeOutput *link)
+void NodeInput::set_link(NodeOutput *link)
{
- m_link = link;
+ link_ = link;
}
-float NodeInput::getEditorValueFloat() const
+float NodeInput::get_editor_value_float() const
{
PointerRNA ptr;
- RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr);
+ RNA_pointer_create((ID *)get_node()->get_bnodetree(), &RNA_NodeSocket, get_bnode_socket(), &ptr);
return RNA_float_get(&ptr, "default_value");
}
-void NodeInput::getEditorValueColor(float *value) const
+void NodeInput::get_editor_value_color(float *value) const
{
PointerRNA ptr;
- RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr);
+ RNA_pointer_create((ID *)get_node()->get_bnodetree(), &RNA_NodeSocket, get_bnode_socket(), &ptr);
return RNA_float_get_array(&ptr, "default_value", value);
}
-void NodeInput::getEditorValueVector(float *value) const
+void NodeInput::get_editor_value_vector(float *value) const
{
PointerRNA ptr;
- RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr);
+ RNA_pointer_create((ID *)get_node()->get_bnodetree(), &RNA_NodeSocket, get_bnode_socket(), &ptr);
return RNA_float_get_array(&ptr, "default_value", value);
}
@@ -182,28 +172,28 @@ void NodeInput::getEditorValueVector(float *value) const
********************/
NodeOutput::NodeOutput(Node *node, bNodeSocket *b_socket, DataType datatype)
- : m_node(node), m_editorSocket(b_socket), m_datatype(datatype)
+ : node_(node), editor_socket_(b_socket), datatype_(datatype)
{
}
-float NodeOutput::getEditorValueFloat()
+float NodeOutput::get_editor_value_float()
{
PointerRNA ptr;
- RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr);
+ RNA_pointer_create((ID *)get_node()->get_bnodetree(), &RNA_NodeSocket, get_bnode_socket(), &ptr);
return RNA_float_get(&ptr, "default_value");
}
-void NodeOutput::getEditorValueColor(float *value)
+void NodeOutput::get_editor_value_color(float *value)
{
PointerRNA ptr;
- RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr);
+ RNA_pointer_create((ID *)get_node()->get_bnodetree(), &RNA_NodeSocket, get_bnode_socket(), &ptr);
return RNA_float_get_array(&ptr, "default_value", value);
}
-void NodeOutput::getEditorValueVector(float *value)
+void NodeOutput::get_editor_value_vector(float *value)
{
PointerRNA ptr;
- RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr);
+ RNA_pointer_create((ID *)get_node()->get_bnodetree(), &RNA_NodeSocket, get_bnode_socket(), &ptr);
return RNA_float_get_array(&ptr, "default_value", value);
}
diff --git a/source/blender/compositor/intern/COM_Node.h b/source/blender/compositor/intern/COM_Node.h
index 28b59397af9..37fa71f9b97 100644
--- a/source/blender/compositor/intern/COM_Node.h
+++ b/source/blender/compositor/intern/COM_Node.h
@@ -22,9 +22,6 @@
#include "DNA_node_types.h"
-#include <algorithm>
-#include <string>
-
/* common node includes
* added here so node files don't have to include themselves
*/
@@ -44,52 +41,52 @@ class Node {
/**
* \brief stores the reference to the SDNA bNode struct
*/
- bNodeTree *m_editorNodeTree;
+ bNodeTree *editor_node_tree_;
/**
* \brief stores the reference to the SDNA bNode struct
*/
- bNode *m_editorNode;
+ bNode *editor_node_;
/**
* \brief Is this node part of the active group
*/
- bool m_inActiveGroup;
+ bool in_active_group_;
/**
* \brief Instance key to identify the node in an instance hash table
*/
- bNodeInstanceKey m_instanceKey;
+ bNodeInstanceKey instance_key_;
protected:
/**
* \brief the list of actual input-sockets \see NodeInput
*/
- Vector<NodeInput *> inputs;
+ Vector<NodeInput *> inputs_;
/**
* \brief the list of actual output-sockets \see NodeOutput
*/
- Vector<NodeOutput *> outputs;
+ Vector<NodeOutput *> outputs_;
public:
- Node(bNode *editorNode, bool create_sockets = true);
+ Node(bNode *editor_node, bool create_sockets = true);
virtual ~Node();
/**
* \brief get the reference to the SDNA bNode struct
*/
- bNode *getbNode() const
+ bNode *get_bnode() const
{
- return m_editorNode;
+ return editor_node_;
}
/**
* \brief get the reference to the SDNA bNodeTree struct
*/
- bNodeTree *getbNodeTree() const
+ bNodeTree *get_bnodetree() const
{
- return m_editorNodeTree;
+ return editor_node_tree_;
}
/**
@@ -98,57 +95,55 @@ class Node {
* node for highlight during execution.
* \param bNode:
*/
- void setbNode(bNode *node)
+ void set_bnode(bNode *node)
{
- this->m_editorNode = node;
+ editor_node_ = node;
}
/**
* \brief set the reference to the bNodeTree
* \param bNodeTree:
*/
- void setbNodeTree(bNodeTree *nodetree)
+ void set_bnodetree(bNodeTree *nodetree)
{
- this->m_editorNodeTree = nodetree;
+ editor_node_tree_ = nodetree;
}
/**
* \brief get access to the vector of input sockets
*/
- const Vector<NodeInput *> &getInputSockets() const
+ const Vector<NodeInput *> &get_input_sockets() const
{
- return this->inputs;
+ return inputs_;
}
/**
* \brief get access to the vector of input sockets
*/
- const Vector<NodeOutput *> &getOutputSockets() const
+ const Vector<NodeOutput *> &get_output_sockets() const
{
- return this->outputs;
+ return outputs_;
}
/**
- * get the reference to a certain outputsocket
- * \param index:
- * the index of the needed outputsocket
+ * Get the reference to a certain output-socket.
+ * \param index: The index of the needed output-socket.
*/
- NodeOutput *getOutputSocket(const unsigned int index = 0) const;
+ NodeOutput *get_output_socket(unsigned int index = 0) const;
/**
- * get the reference to a certain inputsocket
- * \param index:
- * the index of the needed inputsocket
+ * get the reference to a certain input-socket.
+ * \param index: The index of the needed input-socket.
*/
- NodeInput *getInputSocket(const unsigned int index) const;
+ NodeInput *get_input_socket(unsigned int index) const;
/**
* \brief Is this node in the active group (the group that is being edited)
- * \param isInActiveGroup:
+ * \param is_in_active_group:
*/
- void setIsInActiveGroup(bool value)
+ void set_is_in_active_group(bool value)
{
- this->m_inActiveGroup = value;
+ in_active_group_ = value;
}
/**
@@ -157,9 +152,9 @@ class Node {
* the active group will be the main tree (all nodes that are not part of a group will be active)
* \return bool [false:true]
*/
- inline bool isInActiveGroup() const
+ inline bool is_in_active_group() const
{
- return this->m_inActiveGroup;
+ return in_active_group_;
}
/**
@@ -170,16 +165,16 @@ class Node {
* \param system: the ExecutionSystem where the operations need to be added
* \param context: reference to the CompositorContext
*/
- virtual void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const = 0;
+ virtual void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const = 0;
- void setInstanceKey(bNodeInstanceKey instance_key)
+ void set_instance_key(bNodeInstanceKey instance_key)
{
- m_instanceKey = instance_key;
+ instance_key_ = instance_key;
}
- bNodeInstanceKey getInstanceKey() const
+ bNodeInstanceKey get_instance_key() const
{
- return m_instanceKey;
+ return instance_key_;
}
protected:
@@ -188,19 +183,19 @@ class Node {
* \note may only be called in an constructor
* \param socket: the NodeInput to add
*/
- void addInputSocket(DataType datatype);
- void addInputSocket(DataType datatype, bNodeSocket *socket);
+ void add_input_socket(DataType datatype);
+ void add_input_socket(DataType datatype, bNodeSocket *socket);
/**
* \brief add an NodeOutput to the collection of output-sockets
* \note may only be called in an constructor
* \param socket: the NodeOutput to add
*/
- void addOutputSocket(DataType datatype);
- void addOutputSocket(DataType datatype, bNodeSocket *socket);
+ void add_output_socket(DataType datatype);
+ void add_output_socket(DataType datatype, bNodeSocket *socket);
- bNodeSocket *getEditorInputSocket(int editorNodeInputSocketIndex);
- bNodeSocket *getEditorOutputSocket(int editorNodeOutputSocketIndex);
+ bNodeSocket *get_editor_input_socket(int editor_node_input_socket_index);
+ bNodeSocket *get_editor_output_socket(int editor_node_output_socket_index);
};
/**
@@ -209,46 +204,46 @@ class Node {
*/
class NodeInput {
private:
- Node *m_node;
- bNodeSocket *m_editorSocket;
+ Node *node_;
+ bNodeSocket *editor_socket_;
- DataType m_datatype;
+ DataType datatype_;
/**
* \brief link connected to this NodeInput.
* An input socket can only have a single link
*/
- NodeOutput *m_link;
+ NodeOutput *link_;
public:
NodeInput(Node *node, bNodeSocket *b_socket, DataType datatype);
- Node *getNode() const
+ Node *get_node() const
{
- return this->m_node;
+ return node_;
}
- DataType getDataType() const
+ DataType get_data_type() const
{
- return m_datatype;
+ return datatype_;
}
- bNodeSocket *getbNodeSocket() const
+ bNodeSocket *get_bnode_socket() const
{
- return this->m_editorSocket;
+ return editor_socket_;
}
- void setLink(NodeOutput *link);
- bool isLinked() const
+ void set_link(NodeOutput *link);
+ bool is_linked() const
{
- return m_link;
+ return link_;
}
- NodeOutput *getLink()
+ NodeOutput *get_link()
{
- return m_link;
+ return link_;
}
- float getEditorValueFloat() const;
- void getEditorValueColor(float *value) const;
- void getEditorValueVector(float *value) const;
+ float get_editor_value_float() const;
+ void get_editor_value_color(float *value) const;
+ void get_editor_value_vector(float *value) const;
};
/**
@@ -257,30 +252,30 @@ class NodeInput {
*/
class NodeOutput {
private:
- Node *m_node;
- bNodeSocket *m_editorSocket;
+ Node *node_;
+ bNodeSocket *editor_socket_;
- DataType m_datatype;
+ DataType datatype_;
public:
NodeOutput(Node *node, bNodeSocket *b_socket, DataType datatype);
- Node *getNode() const
+ Node *get_node() const
{
- return this->m_node;
+ return node_;
}
- DataType getDataType() const
+ DataType get_data_type() const
{
- return m_datatype;
+ return datatype_;
}
- bNodeSocket *getbNodeSocket() const
+ bNodeSocket *get_bnode_socket() const
{
- return this->m_editorSocket;
+ return editor_socket_;
}
- float getEditorValueFloat();
- void getEditorValueColor(float *value);
- void getEditorValueVector(float *value);
+ float get_editor_value_float();
+ void get_editor_value_color(float *value);
+ void get_editor_value_vector(float *value);
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_NodeConverter.cc b/source/blender/compositor/intern/COM_NodeConverter.cc
index 49a2e7988c4..93ec559533b 100644
--- a/source/blender/compositor/intern/COM_NodeConverter.cc
+++ b/source/blender/compositor/intern/COM_NodeConverter.cc
@@ -18,9 +18,7 @@
#include "BLI_utildefines.h"
-#include "COM_Debug.h"
-
-#include "COM_NodeOperation.h"
+#include "COM_Node.h"
#include "COM_NodeOperationBuilder.h"
#include "COM_SetColorOperation.h"
#include "COM_SetValueOperation.h"
@@ -31,136 +29,137 @@
namespace blender::compositor {
-NodeConverter::NodeConverter(NodeOperationBuilder *builder) : m_builder(builder)
+NodeConverter::NodeConverter(NodeOperationBuilder *builder) : builder_(builder)
{
}
-void NodeConverter::addOperation(NodeOperation *operation)
+void NodeConverter::add_operation(NodeOperation *operation)
{
- m_builder->addOperation(operation);
+ builder_->add_operation(operation);
}
-void NodeConverter::mapInputSocket(NodeInput *node_socket, NodeOperationInput *operation_socket)
+void NodeConverter::map_input_socket(NodeInput *node_socket, NodeOperationInput *operation_socket)
{
- m_builder->mapInputSocket(node_socket, operation_socket);
+ builder_->map_input_socket(node_socket, operation_socket);
}
-void NodeConverter::mapOutputSocket(NodeOutput *node_socket, NodeOperationOutput *operation_socket)
+void NodeConverter::map_output_socket(NodeOutput *node_socket,
+ NodeOperationOutput *operation_socket)
{
- m_builder->mapOutputSocket(node_socket, operation_socket);
+ builder_->map_output_socket(node_socket, operation_socket);
}
-void NodeConverter::addLink(NodeOperationOutput *from, NodeOperationInput *to)
+void NodeConverter::add_link(NodeOperationOutput *from, NodeOperationInput *to)
{
- m_builder->addLink(from, to);
+ builder_->add_link(from, to);
}
-void NodeConverter::addPreview(NodeOperationOutput *output)
+void NodeConverter::add_preview(NodeOperationOutput *output)
{
- m_builder->addPreview(output);
+ builder_->add_preview(output);
}
-void NodeConverter::addNodeInputPreview(NodeInput *input)
+void NodeConverter::add_node_input_preview(NodeInput *input)
{
- m_builder->addNodeInputPreview(input);
+ builder_->add_node_input_preview(input);
}
-NodeOperation *NodeConverter::setInvalidOutput(NodeOutput *output)
+NodeOperation *NodeConverter::set_invalid_output(NodeOutput *output)
{
/* this is a really bad situation - bring on the pink! - so artists know this is bad */
const float warning_color[4] = {1.0f, 0.0f, 1.0f, 1.0f};
SetColorOperation *operation = new SetColorOperation();
- operation->setChannels(warning_color);
+ operation->set_channels(warning_color);
- m_builder->addOperation(operation);
- m_builder->mapOutputSocket(output, operation->getOutputSocket());
+ builder_->add_operation(operation);
+ builder_->map_output_socket(output, operation->get_output_socket());
return operation;
}
-NodeOperationOutput *NodeConverter::addInputProxy(NodeInput *input, bool use_conversion)
+NodeOperationOutput *NodeConverter::add_input_proxy(NodeInput *input, bool use_conversion)
{
- SocketProxyOperation *proxy = new SocketProxyOperation(input->getDataType(), use_conversion);
- m_builder->addOperation(proxy);
+ SocketProxyOperation *proxy = new SocketProxyOperation(input->get_data_type(), use_conversion);
+ builder_->add_operation(proxy);
- m_builder->mapInputSocket(input, proxy->getInputSocket(0));
+ builder_->map_input_socket(input, proxy->get_input_socket(0));
- return proxy->getOutputSocket();
+ return proxy->get_output_socket();
}
-NodeOperationInput *NodeConverter::addOutputProxy(NodeOutput *output, bool use_conversion)
+NodeOperationInput *NodeConverter::add_output_proxy(NodeOutput *output, bool use_conversion)
{
- SocketProxyOperation *proxy = new SocketProxyOperation(output->getDataType(), use_conversion);
- m_builder->addOperation(proxy);
+ SocketProxyOperation *proxy = new SocketProxyOperation(output->get_data_type(), use_conversion);
+ builder_->add_operation(proxy);
- m_builder->mapOutputSocket(output, proxy->getOutputSocket());
+ builder_->map_output_socket(output, proxy->get_output_socket());
- return proxy->getInputSocket(0);
+ return proxy->get_input_socket(0);
}
-void NodeConverter::addInputValue(NodeOperationInput *input, float value)
+void NodeConverter::add_input_value(NodeOperationInput *input, float value)
{
SetValueOperation *operation = new SetValueOperation();
- operation->setValue(value);
+ operation->set_value(value);
- m_builder->addOperation(operation);
- m_builder->addLink(operation->getOutputSocket(), input);
+ builder_->add_operation(operation);
+ builder_->add_link(operation->get_output_socket(), input);
}
-void NodeConverter::addInputColor(NodeOperationInput *input, const float value[4])
+void NodeConverter::add_input_color(NodeOperationInput *input, const float value[4])
{
SetColorOperation *operation = new SetColorOperation();
- operation->setChannels(value);
+ operation->set_channels(value);
- m_builder->addOperation(operation);
- m_builder->addLink(operation->getOutputSocket(), input);
+ builder_->add_operation(operation);
+ builder_->add_link(operation->get_output_socket(), input);
}
-void NodeConverter::addInputVector(NodeOperationInput *input, const float value[3])
+void NodeConverter::add_input_vector(NodeOperationInput *input, const float value[3])
{
SetVectorOperation *operation = new SetVectorOperation();
- operation->setVector(value);
+ operation->set_vector(value);
- m_builder->addOperation(operation);
- m_builder->addLink(operation->getOutputSocket(), input);
+ builder_->add_operation(operation);
+ builder_->add_link(operation->get_output_socket(), input);
}
-void NodeConverter::addOutputValue(NodeOutput *output, float value)
+void NodeConverter::add_output_value(NodeOutput *output, float value)
{
SetValueOperation *operation = new SetValueOperation();
- operation->setValue(value);
+ operation->set_value(value);
- m_builder->addOperation(operation);
- m_builder->mapOutputSocket(output, operation->getOutputSocket());
+ builder_->add_operation(operation);
+ builder_->map_output_socket(output, operation->get_output_socket());
}
-void NodeConverter::addOutputColor(NodeOutput *output, const float value[4])
+void NodeConverter::add_output_color(NodeOutput *output, const float value[4])
{
SetColorOperation *operation = new SetColorOperation();
- operation->setChannels(value);
+ operation->set_channels(value);
- m_builder->addOperation(operation);
- m_builder->mapOutputSocket(output, operation->getOutputSocket());
+ builder_->add_operation(operation);
+ builder_->map_output_socket(output, operation->get_output_socket());
}
-void NodeConverter::addOutputVector(NodeOutput *output, const float value[3])
+void NodeConverter::add_output_vector(NodeOutput *output, const float value[3])
{
SetVectorOperation *operation = new SetVectorOperation();
- operation->setVector(value);
+ operation->set_vector(value);
- m_builder->addOperation(operation);
- m_builder->mapOutputSocket(output, operation->getOutputSocket());
+ builder_->add_operation(operation);
+ builder_->map_output_socket(output, operation->get_output_socket());
}
-void NodeConverter::registerViewer(ViewerOperation *viewer)
+void NodeConverter::register_viewer(ViewerOperation *viewer)
{
- m_builder->registerViewer(viewer);
+ builder_->register_viewer(viewer);
}
ViewerOperation *NodeConverter::active_viewer() const
{
- return m_builder->active_viewer();
+ return builder_->active_viewer();
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_NodeConverter.h b/source/blender/compositor/intern/COM_NodeConverter.h
index b3f03485249..9193a28a77f 100644
--- a/source/blender/compositor/intern/COM_NodeConverter.h
+++ b/source/blender/compositor/intern/COM_NodeConverter.h
@@ -36,7 +36,7 @@ class ViewerOperation;
/**
* Interface type for converting a \a Node into \a NodeOperation.
- * This is passed to \a Node::convertToOperation methods and allows them
+ * This is passed to \a Node::convert_to_operation methods and allows them
* to register any number of operations, create links between them,
* and map original node sockets to their inputs or outputs.
*/
@@ -48,7 +48,7 @@ class NodeConverter {
* Insert a new operation into the operations graph.
* The operation must be created by the node.
*/
- void addOperation(NodeOperation *operation);
+ void add_operation(NodeOperation *operation);
/**
* Map input socket of the node to an operation socket.
@@ -57,7 +57,7 @@ class NodeConverter {
*
* \note A \a Node input can be mapped to multiple \a NodeOperation inputs.
*/
- void mapInputSocket(NodeInput *node_socket, NodeOperationInput *operation_socket);
+ void map_input_socket(NodeInput *node_socket, NodeOperationInput *operation_socket);
/**
* Map output socket of the node to an operation socket.
* Links between nodes will then generate equivalent links between
@@ -66,57 +66,57 @@ class NodeConverter {
* \note A \a Node output can only be mapped to one \a NodeOperation output.
* Any existing operation output mapping will be replaced.
*/
- void mapOutputSocket(NodeOutput *node_socket, NodeOperationOutput *operation_socket);
+ void map_output_socket(NodeOutput *node_socket, NodeOperationOutput *operation_socket);
/**
* Create a proxy operation for a node input.
* This operation will be removed later and replaced
* by direct links between the connected operations.
*/
- NodeOperationOutput *addInputProxy(NodeInput *input, bool use_conversion);
+ NodeOperationOutput *add_input_proxy(NodeInput *input, bool use_conversion);
/**
* Create a proxy operation for a node output.
* This operation will be removed later and replaced
* by direct links between the connected operations.
*/
- NodeOperationInput *addOutputProxy(NodeOutput *output, bool use_conversion);
+ NodeOperationInput *add_output_proxy(NodeOutput *output, bool use_conversion);
/** Define a constant input value. */
- void addInputValue(NodeOperationInput *input, float value);
+ void add_input_value(NodeOperationInput *input, float value);
/** Define a constant input color. */
- void addInputColor(NodeOperationInput *input, const float value[4]);
+ void add_input_color(NodeOperationInput *input, const float value[4]);
/** Define a constant input vector. */
- void addInputVector(NodeOperationInput *input, const float value[3]);
+ void add_input_vector(NodeOperationInput *input, const float value[3]);
/** Define a constant output value. */
- void addOutputValue(NodeOutput *output, float value);
+ void add_output_value(NodeOutput *output, float value);
/** Define a constant output color. */
- void addOutputColor(NodeOutput *output, const float value[4]);
+ void add_output_color(NodeOutput *output, const float value[4]);
/** Define a constant output vector. */
- void addOutputVector(NodeOutput *output, const float value[3]);
+ void add_output_vector(NodeOutput *output, const float value[3]);
/** Add an explicit link between two operations. */
- void addLink(NodeOperationOutput *from, NodeOperationInput *to);
+ void add_link(NodeOperationOutput *from, NodeOperationInput *to);
/** Add a preview operation for a operation output. */
- void addPreview(NodeOperationOutput *output);
+ void add_preview(NodeOperationOutput *output);
/** Add a preview operation for a node input. */
- void addNodeInputPreview(NodeInput *input);
+ void add_node_input_preview(NodeInput *input);
/**
* When a node has no valid data
* \note missing image / group pointer, or missing renderlayer from EXR
*/
- NodeOperation *setInvalidOutput(NodeOutput *output);
+ NodeOperation *set_invalid_output(NodeOutput *output);
/** Define a viewer operation as the active output, if possible */
- void registerViewer(ViewerOperation *viewer);
+ void register_viewer(ViewerOperation *viewer);
/** The currently active viewer output operation */
ViewerOperation *active_viewer() const;
private:
/** The internal builder for storing the results of the graph construction. */
- NodeOperationBuilder *m_builder;
+ NodeOperationBuilder *builder_;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeCompiler")
diff --git a/source/blender/compositor/intern/COM_NodeGraph.cc b/source/blender/compositor/intern/COM_NodeGraph.cc
index 1872fbcf656..64684b772d9 100644
--- a/source/blender/compositor/intern/COM_NodeGraph.cc
+++ b/source/blender/compositor/intern/COM_NodeGraph.cc
@@ -18,17 +18,12 @@
#include <cstring>
-#include "BLI_listbase.h"
-#include "BLI_utildefines.h"
-
#include "DNA_node_types.h"
#include "BKE_node.h"
-#include "COM_CompositorContext.h"
#include "COM_Converter.h"
#include "COM_Debug.h"
-#include "COM_Node.h"
#include "COM_SocketProxyNode.h"
#include "COM_NodeGraph.h" /* own include */
@@ -41,8 +36,8 @@ namespace blender::compositor {
NodeGraph::~NodeGraph()
{
- while (m_nodes.size()) {
- delete m_nodes.pop_last();
+ while (nodes_.size()) {
+ delete nodes_.pop_last();
}
}
@@ -76,21 +71,21 @@ void NodeGraph::add_node(Node *node,
bNodeInstanceKey key,
bool is_active_group)
{
- node->setbNodeTree(b_ntree);
- node->setInstanceKey(key);
- node->setIsInActiveGroup(is_active_group);
+ node->set_bnodetree(b_ntree);
+ node->set_instance_key(key);
+ node->set_is_in_active_group(is_active_group);
- m_nodes.append(node);
+ nodes_.append(node);
DebugInfo::node_added(node);
}
-void NodeGraph::add_link(NodeOutput *fromSocket, NodeInput *toSocket)
+void NodeGraph::add_link(NodeOutput *from_socket, NodeInput *to_socket)
{
- m_links.append(Link(fromSocket, toSocket));
+ links_.append(Link(from_socket, to_socket));
/* register with the input */
- toSocket->setLink(fromSocket);
+ to_socket->set_link(from_socket);
}
void NodeGraph::add_bNodeTree(const CompositorContext &context,
@@ -98,7 +93,7 @@ void NodeGraph::add_bNodeTree(const CompositorContext &context,
bNodeTree *tree,
bNodeInstanceKey parent_key)
{
- const bNodeTree *basetree = context.getbNodeTree();
+ const bNodeTree *basetree = context.get_bnodetree();
/* Update viewers in the active edit-tree as well the base tree (for backdrop). */
bool is_active_group = (parent_key.value == basetree->active_viewer_key.value);
@@ -109,7 +104,7 @@ void NodeGraph::add_bNodeTree(const CompositorContext &context,
add_bNode(context, tree, node, key, is_active_group);
}
- NodeRange node_range(m_nodes.begin() + nodes_start, m_nodes.end());
+ NodeRange node_range(nodes_.begin() + nodes_start, nodes_.end());
/* Add all node-links of the tree to the link list. */
for (bNodeLink *nodelink = (bNodeLink *)tree->links.first; nodelink; nodelink = nodelink->next) {
add_bNodeLink(node_range, nodelink);
@@ -129,7 +124,7 @@ void NodeGraph::add_bNode(const CompositorContext &context,
}
/* replace slow nodes with proxies for fast execution */
- if (context.isFastCalculation() && !COM_bnode_is_fast_node(*b_node)) {
+ if (context.is_fast_calculation() && !COM_bnode_is_fast_node(*b_node)) {
add_proxies_skip(b_ntree, b_node, key, is_active_group);
return;
}
@@ -154,8 +149,8 @@ NodeOutput *NodeGraph::find_output(const NodeRange &node_range, bNodeSocket *b_s
{
for (Vector<Node *>::iterator it = node_range.first; it != node_range.second; ++it) {
Node *node = *it;
- for (NodeOutput *output : node->getOutputSockets()) {
- if (output->getbNodeSocket() == b_socket) {
+ for (NodeOutput *output : node->get_output_sockets()) {
+ if (output->get_bnode_socket() == b_socket) {
return output;
}
}
@@ -185,8 +180,8 @@ void NodeGraph::add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink
for (Vector<Node *>::iterator it = node_range.first; it != node_range.second; ++it) {
Node *node = *it;
- for (NodeInput *input : node->getInputSockets()) {
- if (input->getbNodeSocket() == b_nodelink->tosock && !input->isLinked()) {
+ for (NodeInput *input : node->get_input_sockets()) {
+ if (input->get_bnode_socket() == b_nodelink->tosock && !input->is_linked()) {
add_link(output, input);
}
}
@@ -263,7 +258,7 @@ void NodeGraph::add_proxies_group_outputs(const CompositorContext &context,
b_sock_io = b_sock_io->next) {
bNodeSocket *b_sock_group = find_b_node_output(b_node, b_sock_io->identifier);
if (b_sock_group) {
- if (context.isGroupnodeBufferEnabled() &&
+ if (context.is_groupnode_buffer_enabled() &&
context.get_execution_model() == eExecutionModel::Tiled) {
SocketBufferNode *buffer = new SocketBufferNode(b_node_io, b_sock_io, b_sock_group);
add_node(buffer, b_group_tree, key, is_active_group);
@@ -284,13 +279,13 @@ void NodeGraph::add_proxies_group(const CompositorContext &context,
/* missing node group datablock can happen with library linking */
if (!b_group_tree) {
- /* This error case its handled in convertToOperations()
+ /* This error case its handled in convert_to_operations()
* so we don't get un-converted sockets. */
return;
}
/* use node list size before adding proxies, so they can be connected in add_bNodeTree */
- int nodes_start = m_nodes.size();
+ int nodes_start = nodes_.size();
/* create proxy nodes for group input/output nodes */
for (bNode *b_node_io = (bNode *)b_group_tree->nodes.first; b_node_io;
diff --git a/source/blender/compositor/intern/COM_NodeGraph.h b/source/blender/compositor/intern/COM_NodeGraph.h
index dfcc6c2fcf9..476b99033c9 100644
--- a/source/blender/compositor/intern/COM_NodeGraph.h
+++ b/source/blender/compositor/intern/COM_NodeGraph.h
@@ -18,11 +18,6 @@
#pragma once
-#include "BLI_vector.hh"
-
-#include <map>
-#include <set>
-
#include "DNA_node_types.h"
#ifdef WITH_CXX_GUARDEDALLOC
@@ -52,19 +47,19 @@ class NodeGraph {
};
private:
- Vector<Node *> m_nodes;
- Vector<Link> m_links;
+ Vector<Node *> nodes_;
+ Vector<Link> links_;
public:
~NodeGraph();
const Vector<Node *> &nodes() const
{
- return m_nodes;
+ return nodes_;
}
const Vector<Link> &links() const
{
- return m_links;
+ return links_;
}
void from_bNodeTree(const CompositorContext &context, bNodeTree *tree);
@@ -76,7 +71,7 @@ class NodeGraph {
static bNodeSocket *find_b_node_output(bNode *b_node, const char *identifier);
void add_node(Node *node, bNodeTree *b_ntree, bNodeInstanceKey key, bool is_active_group);
- void add_link(NodeOutput *fromSocket, NodeInput *toSocket);
+ void add_link(NodeOutput *from_socket, NodeInput *to_socket);
void add_bNodeTree(const CompositorContext &context,
int nodes_start,
diff --git a/source/blender/compositor/intern/COM_NodeOperation.cc b/source/blender/compositor/intern/COM_NodeOperation.cc
index a6a395261f2..1f8bc542843 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.cc
+++ b/source/blender/compositor/intern/COM_NodeOperation.cc
@@ -17,13 +17,10 @@
*/
#include <cstdio>
-#include <memory>
-#include <typeinfo>
#include "COM_BufferOperation.h"
#include "COM_ExecutionSystem.h"
#include "COM_ReadBufferOperation.h"
-#include "COM_defines.h"
#include "COM_NodeOperation.h" /* own include */
@@ -37,20 +34,18 @@ NodeOperation::NodeOperation()
{
canvas_input_index_ = 0;
canvas_ = COM_AREA_NONE;
- this->m_btree = nullptr;
+ btree_ = nullptr;
}
-/** Get constant value when operation is constant, otherwise return default_value. */
float NodeOperation::get_constant_value_default(float default_value)
{
- BLI_assert(m_outputs.size() > 0 && getOutputSocket()->getDataType() == DataType::Value);
+ BLI_assert(outputs_.size() > 0 && get_output_socket()->get_data_type() == DataType::Value);
return *get_constant_elem_default(&default_value);
}
-/** Get constant elem when operation is constant, otherwise return default_elem. */
const float *NodeOperation::get_constant_elem_default(const float *default_elem)
{
- BLI_assert(m_outputs.size() > 0);
+ BLI_assert(outputs_.size() > 0);
if (get_flags().is_constant_operation) {
return static_cast<ConstantOperation *>(this)->get_constant_elem();
}
@@ -58,11 +53,6 @@ const float *NodeOperation::get_constant_elem_default(const float *default_elem)
return default_elem;
}
-/**
- * Generate a hash that identifies the operation result in the current execution.
- * Requires `hash_output_params` to be implemented, otherwise `std::nullopt` is returned.
- * If the operation parameters or its linked inputs change, the hash must be re-generated.
- */
std::optional<NodeOperationHash> NodeOperation::generate_hash()
{
params_hash_ = get_default_hash_2(canvas_.xmin, canvas_.xmax);
@@ -75,25 +65,25 @@ std::optional<NodeOperationHash> NodeOperation::generate_hash()
}
hash_params(canvas_.ymin, canvas_.ymax);
- if (m_outputs.size() > 0) {
- BLI_assert(m_outputs.size() == 1);
- hash_param(this->getOutputSocket()->getDataType());
+ if (outputs_.size() > 0) {
+ BLI_assert(outputs_.size() == 1);
+ hash_param(this->get_output_socket()->get_data_type());
}
NodeOperationHash hash;
hash.params_hash_ = params_hash_;
hash.parents_hash_ = 0;
- for (NodeOperationInput &socket : m_inputs) {
- if (!socket.isConnected()) {
+ for (NodeOperationInput &socket : inputs_) {
+ if (!socket.is_connected()) {
continue;
}
- NodeOperation &input = socket.getLink()->getOperation();
+ NodeOperation &input = socket.get_link()->get_operation();
const bool is_constant = input.get_flags().is_constant_operation;
combine_hashes(hash.parents_hash_, get_default_hash(is_constant));
if (is_constant) {
const float *elem = ((ConstantOperation *)&input)->get_constant_elem();
- const int num_channels = COM_data_type_num_channels(socket.getDataType());
+ const int num_channels = COM_data_type_num_channels(socket.get_data_type());
for (const int i : IndexRange(num_channels)) {
combine_hashes(hash.parents_hash_, get_default_hash(elem[i]));
}
@@ -109,31 +99,31 @@ std::optional<NodeOperationHash> NodeOperation::generate_hash()
return hash;
}
-NodeOperationOutput *NodeOperation::getOutputSocket(unsigned int index)
+NodeOperationOutput *NodeOperation::get_output_socket(unsigned int index)
{
- return &m_outputs[index];
+ return &outputs_[index];
}
-NodeOperationInput *NodeOperation::getInputSocket(unsigned int index)
+NodeOperationInput *NodeOperation::get_input_socket(unsigned int index)
{
- return &m_inputs[index];
+ return &inputs_[index];
}
-void NodeOperation::addInputSocket(DataType datatype, ResizeMode resize_mode)
+void NodeOperation::add_input_socket(DataType datatype, ResizeMode resize_mode)
{
- m_inputs.append(NodeOperationInput(this, datatype, resize_mode));
+ inputs_.append(NodeOperationInput(this, datatype, resize_mode));
}
-void NodeOperation::addOutputSocket(DataType datatype)
+void NodeOperation::add_output_socket(DataType datatype)
{
- m_outputs.append(NodeOperationOutput(this, datatype));
+ outputs_.append(NodeOperationOutput(this, datatype));
}
void NodeOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
unsigned int used_canvas_index = 0;
if (canvas_input_index_ == RESOLUTION_INPUT_ANY) {
- for (NodeOperationInput &input : m_inputs) {
+ for (NodeOperationInput &input : inputs_) {
rcti any_area = COM_AREA_NONE;
const bool determined = input.determine_canvas(preferred_area, any_area);
if (determined) {
@@ -143,8 +133,8 @@ void NodeOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
used_canvas_index += 1;
}
}
- else if (canvas_input_index_ < m_inputs.size()) {
- NodeOperationInput &input = m_inputs[canvas_input_index_];
+ else if (canvas_input_index_ < inputs_.size()) {
+ NodeOperationInput &input = inputs_[canvas_input_index_];
input.determine_canvas(preferred_area, r_area);
used_canvas_index = canvas_input_index_;
}
@@ -153,14 +143,14 @@ void NodeOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
modify_determined_canvas_fn_(r_area);
}
- rcti unused_area;
+ rcti unused_area = COM_AREA_NONE;
const rcti &local_preferred_area = r_area;
- for (unsigned int index = 0; index < m_inputs.size(); index++) {
+ for (unsigned int index = 0; index < inputs_.size(); index++) {
if (index == used_canvas_index) {
continue;
}
- NodeOperationInput &input = m_inputs[index];
- if (input.isConnected()) {
+ NodeOperationInput &input = inputs_[index];
+ if (input.is_connected()) {
input.determine_canvas(local_preferred_area, unused_area);
}
}
@@ -175,32 +165,32 @@ void NodeOperation::init_data()
{
/* Pass. */
}
-void NodeOperation::initExecution()
+void NodeOperation::init_execution()
{
/* pass */
}
-void NodeOperation::initMutex()
+void NodeOperation::init_mutex()
{
- BLI_mutex_init(&this->m_mutex);
+ BLI_mutex_init(&mutex_);
}
-void NodeOperation::lockMutex()
+void NodeOperation::lock_mutex()
{
- BLI_mutex_lock(&this->m_mutex);
+ BLI_mutex_lock(&mutex_);
}
-void NodeOperation::unlockMutex()
+void NodeOperation::unlock_mutex()
{
- BLI_mutex_unlock(&this->m_mutex);
+ BLI_mutex_unlock(&mutex_);
}
-void NodeOperation::deinitMutex()
+void NodeOperation::deinit_mutex()
{
- BLI_mutex_end(&this->m_mutex);
+ BLI_mutex_end(&mutex_);
}
-void NodeOperation::deinitExecution()
+void NodeOperation::deinit_execution()
{
/* pass */
}
@@ -208,7 +198,7 @@ void NodeOperation::deinitExecution()
void NodeOperation::set_canvas(const rcti &canvas_area)
{
canvas_ = canvas_area;
- flags.is_canvas_set = true;
+ flags_.is_canvas_set = true;
}
const rcti &NodeOperation::get_canvas() const
@@ -216,58 +206,54 @@ const rcti &NodeOperation::get_canvas() const
return canvas_;
}
-/**
- * Mainly used for re-determining canvas of constant operations in cases where preferred canvas
- * depends on the constant element.
- */
void NodeOperation::unset_canvas()
{
- BLI_assert(m_inputs.size() == 0);
- flags.is_canvas_set = false;
+ BLI_assert(inputs_.size() == 0);
+ flags_.is_canvas_set = false;
}
-SocketReader *NodeOperation::getInputSocketReader(unsigned int inputSocketIndex)
+SocketReader *NodeOperation::get_input_socket_reader(unsigned int index)
{
- return this->getInputSocket(inputSocketIndex)->getReader();
+ return this->get_input_socket(index)->get_reader();
}
-NodeOperation *NodeOperation::getInputOperation(unsigned int inputSocketIndex)
+NodeOperation *NodeOperation::get_input_operation(int index)
{
- NodeOperationInput *input = getInputSocket(inputSocketIndex);
- if (input && input->isConnected()) {
- return &input->getLink()->getOperation();
+ NodeOperationInput *input = get_input_socket(index);
+ if (input && input->is_connected()) {
+ return &input->get_link()->get_operation();
}
return nullptr;
}
-bool NodeOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool NodeOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- if (m_inputs.size() == 0) {
+ if (inputs_.size() == 0) {
BLI_rcti_init(output, input->xmin, input->xmax, input->ymin, input->ymax);
return false;
}
- rcti tempOutput;
+ rcti temp_output;
bool first = true;
- for (int i = 0; i < getNumberOfInputSockets(); i++) {
- NodeOperation *inputOperation = this->getInputOperation(i);
- if (inputOperation &&
- inputOperation->determineDependingAreaOfInterest(input, readOperation, &tempOutput)) {
+ for (int i = 0; i < get_number_of_input_sockets(); i++) {
+ NodeOperation *input_operation = this->get_input_operation(i);
+ if (input_operation && input_operation->determine_depending_area_of_interest(
+ input, read_operation, &temp_output)) {
if (first) {
- output->xmin = tempOutput.xmin;
- output->ymin = tempOutput.ymin;
- output->xmax = tempOutput.xmax;
- output->ymax = tempOutput.ymax;
+ output->xmin = temp_output.xmin;
+ output->ymin = temp_output.ymin;
+ output->xmax = temp_output.xmax;
+ output->ymax = temp_output.ymax;
first = false;
}
else {
- output->xmin = MIN2(output->xmin, tempOutput.xmin);
- output->ymin = MIN2(output->ymin, tempOutput.ymin);
- output->xmax = MAX2(output->xmax, tempOutput.xmax);
- output->ymax = MAX2(output->ymax, tempOutput.ymax);
+ output->xmin = MIN2(output->xmin, temp_output.xmin);
+ output->ymin = MIN2(output->ymin, temp_output.ymin);
+ output->xmax = MAX2(output->xmax, temp_output.xmax);
+ output->ymax = MAX2(output->ymax, temp_output.ymax);
}
}
}
@@ -278,18 +264,6 @@ bool NodeOperation::determineDependingAreaOfInterest(rcti *input,
/** \name Full Frame Methods
* \{ */
-/**
- * \brief Get input operation area being read by this operation on rendering given output area.
- *
- * Implementation don't need to ensure r_input_area is within input operation bounds. The
- * caller must clamp it.
- * TODO: See if it's possible to use parameter overloading (input_id for example).
- *
- * \param input_idx: Input operation index for which we want to calculate the area being read.
- * \param output_area: Area being rendered by this operation.
- * \param r_input_area: Returned input operation area that needs to be read in order to render
- * given output area.
- */
void NodeOperation::get_area_of_interest(const int input_idx,
const rcti &output_area,
rcti &r_input_area)
@@ -300,7 +274,7 @@ void NodeOperation::get_area_of_interest(const int input_idx,
else {
/* Non full-frame operations never implement this method. To ensure correctness assume
* whole area is used. */
- NodeOperation *input_op = getInputOperation(input_idx);
+ NodeOperation *input_op = get_input_operation(input_idx);
r_input_area = input_op->get_canvas();
}
}
@@ -309,8 +283,8 @@ void NodeOperation::get_area_of_interest(NodeOperation *input_op,
const rcti &output_area,
rcti &r_input_area)
{
- for (int i = 0; i < getNumberOfInputSockets(); i++) {
- if (input_op == getInputOperation(i)) {
+ for (int i = 0; i < get_number_of_input_sockets(); i++) {
+ if (input_op == get_input_operation(i)) {
get_area_of_interest(i, output_area, r_input_area);
return;
}
@@ -318,12 +292,6 @@ void NodeOperation::get_area_of_interest(NodeOperation *input_op,
BLI_assert_msg(0, "input_op is not an input operation.");
}
-/**
- * Executes operation image manipulation algorithm rendering given areas.
- * \param output_buf: Buffer to write result to.
- * \param areas: Areas within this operation bounds to render.
- * \param inputs_bufs: Inputs operations buffers.
- */
void NodeOperation::render(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs_bufs)
@@ -336,41 +304,35 @@ void NodeOperation::render(MemoryBuffer *output_buf,
}
}
-/**
- * Renders given areas using operations full frame implementation.
- */
void NodeOperation::render_full_frame(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs_bufs)
{
- initExecution();
+ init_execution();
for (const rcti &area : areas) {
update_memory_buffer(output_buf, area, inputs_bufs);
}
- deinitExecution();
+ deinit_execution();
}
-/**
- * Renders given areas using operations tiled implementation.
- */
void NodeOperation::render_full_frame_fallback(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs_bufs)
{
Vector<NodeOperationOutput *> orig_input_links = replace_inputs_with_buffers(inputs_bufs);
- initExecution();
- const bool is_output_operation = getNumberOfOutputSockets() == 0;
+ init_execution();
+ const bool is_output_operation = get_number_of_output_sockets() == 0;
if (!is_output_operation && output_buf->is_a_single_elem()) {
float *output_elem = output_buf->get_elem(0, 0);
- readSampled(output_elem, 0, 0, PixelSampler::Nearest);
+ read_sampled(output_elem, 0, 0, PixelSampler::Nearest);
}
else {
for (const rcti &rect : areas) {
exec_system_->execute_work(rect, [=](const rcti &split_rect) {
rcti tile_rect = split_rect;
if (is_output_operation) {
- executeRegion(&tile_rect, 0);
+ execute_region(&tile_rect, 0);
}
else {
render_tile(output_buf, &tile_rect);
@@ -378,7 +340,7 @@ void NodeOperation::render_full_frame_fallback(MemoryBuffer *output_buf,
});
}
}
- deinitExecution();
+ deinit_execution();
remove_buffers_and_restore_original_inputs(orig_input_links);
}
@@ -386,7 +348,7 @@ void NodeOperation::render_full_frame_fallback(MemoryBuffer *output_buf,
void NodeOperation::render_tile(MemoryBuffer *output_buf, rcti *tile_rect)
{
const bool is_complex = get_flags().complex;
- void *tile_data = is_complex ? initializeTileData(tile_rect) : nullptr;
+ void *tile_data = is_complex ? initialize_tile_data(tile_rect) : nullptr;
const int elem_stride = output_buf->elem_stride;
for (int y = tile_rect->ymin; y < tile_rect->ymax; y++) {
float *output_elem = output_buf->get_elem(tile_rect->xmin, y);
@@ -398,30 +360,28 @@ void NodeOperation::render_tile(MemoryBuffer *output_buf, rcti *tile_rect)
}
else {
for (int x = tile_rect->xmin; x < tile_rect->xmax; x++) {
- readSampled(output_elem, x, y, PixelSampler::Nearest);
+ read_sampled(output_elem, x, y, PixelSampler::Nearest);
output_elem += elem_stride;
}
}
}
if (tile_data) {
- deinitializeTileData(tile_rect, tile_data);
+ deinitialize_tile_data(tile_rect, tile_data);
}
}
-/**
- * \return Replaced inputs links.
- */
Vector<NodeOperationOutput *> NodeOperation::replace_inputs_with_buffers(
Span<MemoryBuffer *> inputs_bufs)
{
- BLI_assert(inputs_bufs.size() == getNumberOfInputSockets());
+ BLI_assert(inputs_bufs.size() == get_number_of_input_sockets());
Vector<NodeOperationOutput *> orig_links(inputs_bufs.size());
for (int i = 0; i < inputs_bufs.size(); i++) {
- NodeOperationInput *input_socket = getInputSocket(i);
- BufferOperation *buffer_op = new BufferOperation(inputs_bufs[i], input_socket->getDataType());
- orig_links[i] = input_socket->getLink();
- input_socket->setLink(buffer_op->getOutputSocket());
- buffer_op->initExecution();
+ NodeOperationInput *input_socket = get_input_socket(i);
+ BufferOperation *buffer_op = new BufferOperation(inputs_bufs[i],
+ input_socket->get_data_type());
+ orig_links[i] = input_socket->get_link();
+ input_socket->set_link(buffer_op->get_output_socket());
+ buffer_op->init_execution();
}
return orig_links;
}
@@ -429,14 +389,14 @@ Vector<NodeOperationOutput *> NodeOperation::replace_inputs_with_buffers(
void NodeOperation::remove_buffers_and_restore_original_inputs(
Span<NodeOperationOutput *> original_inputs_links)
{
- BLI_assert(original_inputs_links.size() == getNumberOfInputSockets());
+ BLI_assert(original_inputs_links.size() == get_number_of_input_sockets());
for (int i = 0; i < original_inputs_links.size(); i++) {
NodeOperation *buffer_op = get_input_operation(i);
BLI_assert(buffer_op != nullptr);
BLI_assert(typeid(*buffer_op) == typeid(BufferOperation));
- buffer_op->deinitExecution();
- NodeOperationInput *input_socket = getInputSocket(i);
- input_socket->setLink(original_inputs_links[i]);
+ buffer_op->deinit_execution();
+ NodeOperationInput *input_socket = get_input_socket(i);
+ input_socket->set_link(original_inputs_links[i]);
delete buffer_op;
}
}
@@ -447,27 +407,26 @@ void NodeOperation::remove_buffers_and_restore_original_inputs(
**** OpInput ****
*****************/
-NodeOperationInput::NodeOperationInput(NodeOperation *op, DataType datatype, ResizeMode resizeMode)
- : m_operation(op), m_datatype(datatype), m_resizeMode(resizeMode), m_link(nullptr)
+NodeOperationInput::NodeOperationInput(NodeOperation *op,
+ DataType datatype,
+ ResizeMode resize_mode)
+ : operation_(op), datatype_(datatype), resize_mode_(resize_mode), link_(nullptr)
{
}
-SocketReader *NodeOperationInput::getReader()
+SocketReader *NodeOperationInput::get_reader()
{
- if (isConnected()) {
- return &m_link->getOperation();
+ if (is_connected()) {
+ return &link_->get_operation();
}
return nullptr;
}
-/**
- * \return Whether canvas area could be determined.
- */
bool NodeOperationInput::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
- if (m_link) {
- m_link->determine_canvas(preferred_area, r_area);
+ if (link_) {
+ link_->determine_canvas(preferred_area, r_area);
return !BLI_rcti_is_empty(&r_area);
}
return false;
@@ -478,13 +437,13 @@ bool NodeOperationInput::determine_canvas(const rcti &preferred_area, rcti &r_ar
******************/
NodeOperationOutput::NodeOperationOutput(NodeOperation *op, DataType datatype)
- : m_operation(op), m_datatype(datatype)
+ : operation_(op), datatype_(datatype)
{
}
void NodeOperationOutput::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
- NodeOperation &operation = getOperation();
+ NodeOperation &operation = get_operation();
if (operation.get_flags().is_canvas_set) {
r_area = operation.get_canvas();
}
@@ -561,9 +520,9 @@ std::ostream &operator<<(std::ostream &os, const NodeOperation &node_operation)
os << ",flags={" << flags << "}";
if (flags.is_read_buffer_operation) {
const ReadBufferOperation *read_operation = (const ReadBufferOperation *)&node_operation;
- const MemoryProxy *proxy = read_operation->getMemoryProxy();
+ const MemoryProxy *proxy = read_operation->get_memory_proxy();
if (proxy) {
- const WriteBufferOperation *write_operation = proxy->getWriteBufferOperation();
+ const WriteBufferOperation *write_operation = proxy->get_write_buffer_operation();
if (write_operation) {
os << ",write=" << (NodeOperation &)*write_operation;
}
diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h
index f507665bee3..4412c021517 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.h
+++ b/source/blender/compositor/intern/COM_NodeOperation.h
@@ -18,32 +18,32 @@
#pragma once
+#include <functional>
#include <list>
-#include <sstream>
-#include <string>
#include "BLI_ghash.h"
#include "BLI_hash.hh"
-#include "BLI_math_color.h"
-#include "BLI_math_vector.h"
+#include "BLI_rect.h"
+#include "BLI_span.hh"
#include "BLI_threads.h"
+#include "BLI_utildefines.h"
#include "COM_Enums.h"
#include "COM_MemoryBuffer.h"
-#include "COM_MemoryProxy.h"
#include "COM_MetaData.h"
-#include "COM_Node.h"
#include "clew.h"
+#include "DNA_node_types.h"
+
namespace blender::compositor {
class OpenCLDevice;
class ReadBufferOperation;
-class WriteBufferOperation;
class ExecutionSystem;
-
class NodeOperation;
+class NodeOperationOutput;
+
typedef NodeOperation SocketReader;
/**
@@ -83,57 +83,60 @@ enum class ResizeMode {
class NodeOperationInput {
private:
- NodeOperation *m_operation;
+ NodeOperation *operation_;
/** Datatype of this socket. Is used for automatically data transformation.
* \section data-conversion
*/
- DataType m_datatype;
+ DataType datatype_;
/** Resize mode of this socket */
- ResizeMode m_resizeMode;
+ ResizeMode resize_mode_;
/** Connected output */
- NodeOperationOutput *m_link;
+ NodeOperationOutput *link_;
public:
NodeOperationInput(NodeOperation *op,
DataType datatype,
- ResizeMode resizeMode = ResizeMode::Center);
+ ResizeMode resize_mode = ResizeMode::Center);
- NodeOperation &getOperation() const
+ NodeOperation &get_operation() const
{
- return *m_operation;
+ return *operation_;
}
- DataType getDataType() const
+ DataType get_data_type() const
{
- return m_datatype;
+ return datatype_;
}
- void setLink(NodeOperationOutput *link)
+ void set_link(NodeOperationOutput *link)
{
- m_link = link;
+ link_ = link;
}
- NodeOperationOutput *getLink() const
+ NodeOperationOutput *get_link() const
{
- return m_link;
+ return link_;
}
- bool isConnected() const
+ bool is_connected() const
{
- return m_link;
+ return link_;
}
- void setResizeMode(ResizeMode resizeMode)
+ void set_resize_mode(ResizeMode resize_mode)
{
- this->m_resizeMode = resizeMode;
+ resize_mode_ = resize_mode;
}
- ResizeMode getResizeMode() const
+ ResizeMode get_resize_mode() const
{
- return this->m_resizeMode;
+ return resize_mode_;
}
- SocketReader *getReader();
+ SocketReader *get_reader();
+ /**
+ * \return Whether canvas area could be determined.
+ */
bool determine_canvas(const rcti &preferred_area, rcti &r_area);
#ifdef WITH_CXX_GUARDEDALLOC
@@ -143,23 +146,23 @@ class NodeOperationInput {
class NodeOperationOutput {
private:
- NodeOperation *m_operation;
+ NodeOperation *operation_;
/** Datatype of this socket. Is used for automatically data transformation.
* \section data-conversion
*/
- DataType m_datatype;
+ DataType datatype_;
public:
NodeOperationOutput(NodeOperation *op, DataType datatype);
- NodeOperation &getOperation() const
+ NodeOperation &get_operation() const
{
- return *m_operation;
+ return *operation_;
}
- DataType getDataType() const
+ DataType get_data_type() const
{
- return m_datatype;
+ return datatype_;
}
void determine_canvas(const rcti &preferred_area, rcti &r_area);
@@ -314,10 +317,10 @@ struct NodeOperationHash {
*/
class NodeOperation {
private:
- int m_id;
- std::string m_name;
- Vector<NodeOperationInput> m_inputs;
- Vector<NodeOperationOutput> m_outputs;
+ int id_;
+ std::string name_;
+ Vector<NodeOperationInput> inputs_;
+ Vector<NodeOperationOutput> outputs_;
size_t params_hash_;
bool is_hash_output_params_implemented_;
@@ -334,16 +337,16 @@ class NodeOperation {
* \note only use when you really know what you are doing.
* this mutex is used to share data among chunks in the same operation
* \see TonemapOperation for an example of usage
- * \see NodeOperation.initMutex initializes this mutex
- * \see NodeOperation.deinitMutex deinitializes this mutex
- * \see NodeOperation.getMutex retrieve a pointer to this mutex.
+ * \see NodeOperation.init_mutex initializes this mutex
+ * \see NodeOperation.deinit_mutex deinitializes this mutex
+ * \see NodeOperation.get_mutex retrieve a pointer to this mutex.
*/
- ThreadMutex m_mutex;
+ ThreadMutex mutex_;
/**
* \brief reference to the editing bNodeTree, used for break and update callback
*/
- const bNodeTree *m_btree;
+ const bNodeTree *btree_;
protected:
/**
@@ -351,12 +354,12 @@ class NodeOperation {
*/
eExecutionModel execution_model_;
- rcti canvas_;
+ rcti canvas_ = COM_AREA_NONE;
/**
* Flags how to evaluate this operation.
*/
- NodeOperationFlags flags;
+ NodeOperationFlags flags_;
ExecutionSystem *exec_system_;
@@ -367,56 +370,58 @@ class NodeOperation {
void set_name(const std::string name)
{
- m_name = name;
+ name_ = name;
}
const std::string get_name() const
{
- return m_name;
+ return name_;
}
void set_id(const int id)
{
- m_id = id;
+ id_ = id;
}
const int get_id() const
{
- return m_id;
+ return id_;
}
+ /** Get constant value when operation is constant, otherwise return default_value. */
float get_constant_value_default(float default_value);
+ /** Get constant elem when operation is constant, otherwise return default_elem. */
const float *get_constant_elem_default(const float *default_elem);
const NodeOperationFlags get_flags() const
{
- return flags;
+ return flags_;
}
+ /**
+ * Generate a hash that identifies the operation result in the current execution.
+ * Requires `hash_output_params` to be implemented, otherwise `std::nullopt` is returned.
+ * If the operation parameters or its linked inputs change, the hash must be re-generated.
+ */
std::optional<NodeOperationHash> generate_hash();
- unsigned int getNumberOfInputSockets() const
+ unsigned int get_number_of_input_sockets() const
{
- return m_inputs.size();
+ return inputs_.size();
}
- unsigned int getNumberOfOutputSockets() const
+ unsigned int get_number_of_output_sockets() const
{
- return m_outputs.size();
+ return outputs_.size();
}
- NodeOperationOutput *getOutputSocket(unsigned int index = 0);
- NodeOperationInput *getInputSocket(unsigned int index);
+ NodeOperationOutput *get_output_socket(unsigned int index = 0);
+ NodeOperationInput *get_input_socket(unsigned int index);
- NodeOperation *get_input_operation(int index)
- {
- /* TODO: Rename protected getInputOperation to get_input_operation and make it public replacing
- * this method. */
- return getInputOperation(index);
- }
+ NodeOperation *get_input_operation(int index);
virtual void determine_canvas(const rcti &preferred_area, rcti &r_area);
/**
- * \brief isOutputOperation determines whether this operation is an output of the
+ * \brief is_output_operation determines whether this operation is an output of the
* ExecutionSystem during rendering or editing.
*
* Default behavior if not overridden, this operation will not be evaluated as being an output
@@ -430,7 +435,7 @@ class NodeOperation {
*
* \return bool the result of this method
*/
- virtual bool isOutputOperation(bool /*rendering*/) const
+ virtual bool is_output_operation(bool /*rendering*/) const
{
return false;
}
@@ -440,9 +445,9 @@ class NodeOperation {
execution_model_ = model;
}
- void setbNodeTree(const bNodeTree *tree)
+ void set_bnodetree(const bNodeTree *tree)
{
- this->m_btree = tree;
+ btree_ = tree;
}
void set_execution_system(ExecutionSystem *system)
@@ -452,20 +457,20 @@ class NodeOperation {
/**
* Initializes operation data needed after operations are linked and resolutions determined. For
- * rendering heap memory data use initExecution().
+ * rendering heap memory data use init_execution().
*/
virtual void init_data();
- virtual void initExecution();
+ virtual void init_execution();
/**
* \brief when a chunk is executed by a CPUDevice, this method is called
* \ingroup execution
* \param rect: the rectangle of the chunk (location and size)
- * \param chunkNumber: the chunkNumber to be calculated
- * \param memoryBuffers: all input MemoryBuffer's needed
+ * \param chunk_number: the chunk_number to be calculated
+ * \param memory_buffers: all input MemoryBuffer's needed
*/
- virtual void executeRegion(rcti * /*rect*/, unsigned int /*chunkNumber*/)
+ virtual void execute_region(rcti * /*rect*/, unsigned int /*chunk_number*/)
{
}
@@ -477,15 +482,15 @@ class NodeOperation {
* \param program: the OpenCL program containing all compositor kernels
* \param queue: the OpenCL command queue of the device the chunk is executed on
* \param rect: the rectangle of the chunk (location and size)
- * \param chunkNumber: the chunkNumber to be calculated
- * \param memoryBuffers: all input MemoryBuffer's needed
- * \param outputBuffer: the outputbuffer to write to
+ * \param chunk_number: the chunk_number to be calculated
+ * \param memory_buffers: all input MemoryBuffer's needed
+ * \param output_buffer: the outputbuffer to write to
*/
- virtual void executeOpenCLRegion(OpenCLDevice * /*device*/,
- rcti * /*rect*/,
- unsigned int /*chunkNumber*/,
- MemoryBuffer ** /*memoryBuffers*/,
- MemoryBuffer * /*outputBuffer*/)
+ virtual void execute_opencl_region(OpenCLDevice * /*device*/,
+ rcti * /*rect*/,
+ unsigned int /*chunk_number*/,
+ MemoryBuffer ** /*memory_buffers*/,
+ MemoryBuffer * /*output_buffer*/)
{
}
@@ -496,26 +501,30 @@ class NodeOperation {
* \param context: the OpenCL context
* \param program: the OpenCL program containing all compositor kernels
* \param queue: the OpenCL command queue of the device the chunk is executed on
- * \param outputMemoryBuffer: the allocated memory buffer in main CPU memory
- * \param clOutputBuffer: the allocated memory buffer in OpenCLDevice memory
- * \param inputMemoryBuffers: all input MemoryBuffer's needed
- * \param clMemToCleanUp: all created cl_mem references must be added to this list.
+ * \param output_memory_buffer: the allocated memory buffer in main CPU memory
+ * \param cl_output_buffer: the allocated memory buffer in OpenCLDevice memory
+ * \param input_memory_buffers: all input MemoryBuffer's needed
+ * \param cl_mem_to_clean_up: all created cl_mem references must be added to this list.
* Framework will clean this after execution
- * \param clKernelsToCleanUp: all created cl_kernel references must be added to this list.
+ * \param cl_kernels_to_clean_up: all created cl_kernel references must be added to this list.
* Framework will clean this after execution
*/
- virtual void executeOpenCL(OpenCLDevice * /*device*/,
- MemoryBuffer * /*outputMemoryBuffer*/,
- cl_mem /*clOutputBuffer*/,
- MemoryBuffer ** /*inputMemoryBuffers*/,
- std::list<cl_mem> * /*clMemToCleanUp*/,
- std::list<cl_kernel> * /*clKernelsToCleanUp*/)
+ virtual void execute_opencl(OpenCLDevice * /*device*/,
+ MemoryBuffer * /*output_memory_buffer*/,
+ cl_mem /*cl_output_buffer*/,
+ MemoryBuffer ** /*input_memory_buffers*/,
+ std::list<cl_mem> * /*cl_mem_to_clean_up*/,
+ std::list<cl_kernel> * /*cl_kernels_to_clean_up*/)
{
}
- virtual void deinitExecution();
+ virtual void deinit_execution();
void set_canvas(const rcti &canvas_area);
const rcti &get_canvas() const;
+ /**
+ * Mainly used for re-determining canvas of constant operations in cases where preferred canvas
+ * depends on the constant element.
+ */
void unset_canvas();
/**
@@ -525,14 +534,14 @@ class NodeOperation {
* \return [true:false]
* \see BaseViewerOperation
*/
- virtual bool isActiveViewerOutput() const
+ virtual bool is_active_viewer_output() const
{
return false;
}
- virtual bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output);
+ virtual bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output);
/**
* \brief set the index of the input socket that will determine the canvas of this
@@ -554,58 +563,58 @@ class NodeOperation {
* \note only applicable for output operations like ViewerOperation
* \return eCompositorPriority
*/
- virtual eCompositorPriority getRenderPriority() const
+ virtual eCompositorPriority get_render_priority() const
{
return eCompositorPriority::Low;
}
- inline bool isBraked() const
+ inline bool is_braked() const
{
- return this->m_btree->test_break(this->m_btree->tbh);
+ return btree_->test_break(btree_->tbh);
}
- inline void updateDraw()
+ inline void update_draw()
{
- if (this->m_btree->update_draw) {
- this->m_btree->update_draw(this->m_btree->udh);
+ if (btree_->update_draw) {
+ btree_->update_draw(btree_->udh);
}
}
- unsigned int getWidth() const
+ unsigned int get_width() const
{
return BLI_rcti_size_x(&get_canvas());
}
- unsigned int getHeight() const
+ unsigned int get_height() const
{
return BLI_rcti_size_y(&get_canvas());
}
- inline void readSampled(float result[4], float x, float y, PixelSampler sampler)
+ inline void read_sampled(float result[4], float x, float y, PixelSampler sampler)
{
- executePixelSampled(result, x, y, sampler);
+ execute_pixel_sampled(result, x, y, sampler);
}
- inline void readFiltered(float result[4], float x, float y, float dx[2], float dy[2])
+ inline void read_filtered(float result[4], float x, float y, float dx[2], float dy[2])
{
- executePixelFiltered(result, x, y, dx, dy);
+ execute_pixel_filtered(result, x, y, dx, dy);
}
- inline void read(float result[4], int x, int y, void *chunkData)
+ inline void read(float result[4], int x, int y, void *chunk_data)
{
- executePixel(result, x, y, chunkData);
+ execute_pixel(result, x, y, chunk_data);
}
- virtual void *initializeTileData(rcti * /*rect*/)
+ virtual void *initialize_tile_data(rcti * /*rect*/)
{
return 0;
}
- virtual void deinitializeTileData(rcti * /*rect*/, void * /*data*/)
+ virtual void deinitialize_tile_data(rcti * /*rect*/, void * /*data*/)
{
}
- virtual MemoryBuffer *getInputMemoryBuffer(MemoryBuffer ** /*memoryBuffers*/)
+ virtual MemoryBuffer *get_input_memory_buffer(MemoryBuffer ** /*memory_buffers*/)
{
return 0;
}
@@ -614,7 +623,7 @@ class NodeOperation {
* Return the meta data associated with this branch.
*
* The return parameter holds an instance or is an nullptr. */
- virtual std::unique_ptr<MetaData> getMetaData()
+ virtual std::unique_ptr<MetaData> get_meta_data()
{
return std::unique_ptr<MetaData>();
}
@@ -623,6 +632,12 @@ class NodeOperation {
/** \name Full Frame Methods
* \{ */
+ /**
+ * Executes operation image manipulation algorithm rendering given areas.
+ * \param output_buf: Buffer to write result to.
+ * \param areas: Areas within this operation bounds to render.
+ * \param inputs_bufs: Inputs operations buffers.
+ */
void render(MemoryBuffer *output_buf, Span<rcti> areas, Span<MemoryBuffer *> inputs_bufs);
/**
@@ -635,7 +650,16 @@ class NodeOperation {
}
/**
- * Get input operation area being read by this operation on rendering given output area.
+ * \brief Get input operation area being read by this operation on rendering given output area.
+ *
+ * Implementation don't need to ensure r_input_area is within input operation bounds.
+ * The caller must clamp it.
+ * TODO: See if it's possible to use parameter overloading (input_id for example).
+ *
+ * \param input_idx: Input operation index for which we want to calculate the area being read.
+ * \param output_area: Area being rendered by this operation.
+ * \param r_input_area: Returned input operation area that needs to be read in order to render
+ * given output area.
*/
virtual void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area);
void get_area_of_interest(NodeOperation *input_op, const rcti &output_area, rcti &r_input_area);
@@ -672,28 +696,27 @@ class NodeOperation {
combine_hashes(params_hash_, get_default_hash_3(param1, param2, param3));
}
- void addInputSocket(DataType datatype, ResizeMode resize_mode = ResizeMode::Center);
- void addOutputSocket(DataType datatype);
+ void add_input_socket(DataType datatype, ResizeMode resize_mode = ResizeMode::Center);
+ void add_output_socket(DataType datatype);
/* TODO(manzanilla): to be removed with tiled implementation. */
- void setWidth(unsigned int width)
+ void set_width(unsigned int width)
{
canvas_.xmax = canvas_.xmin + width;
- this->flags.is_canvas_set = true;
+ flags_.is_canvas_set = true;
}
- void setHeight(unsigned int height)
+ void set_height(unsigned int height)
{
canvas_.ymax = canvas_.ymin + height;
- this->flags.is_canvas_set = true;
+ flags_.is_canvas_set = true;
}
- SocketReader *getInputSocketReader(unsigned int inputSocketindex);
- NodeOperation *getInputOperation(unsigned int inputSocketindex);
+ SocketReader *get_input_socket_reader(unsigned int index);
- void deinitMutex();
- void initMutex();
- void lockMutex();
- void unlockMutex();
+ void deinit_mutex();
+ void init_mutex();
+ void lock_mutex();
+ void unlock_mutex();
/**
* \brief set whether this operation is complex
@@ -701,9 +724,9 @@ class NodeOperation {
* Complex operations are typically doing many reads to calculate the output of a single pixel.
* Mostly Filter types (Blurs, Convolution, Defocus etc) need this to be set to true.
*/
- void setComplex(bool complex)
+ void set_complex(bool complex)
{
- this->flags.complex = complex;
+ flags_.complex = complex;
}
/**
@@ -712,12 +735,12 @@ class NodeOperation {
* \param result: is a float[4] array to store the result
* \param x: the x-coordinate of the pixel to calculate in image space
* \param y: the y-coordinate of the pixel to calculate in image space
- * \param inputBuffers: chunks that can be read by their ReadBufferOperation.
+ * \param input_buffers: chunks that can be read by their ReadBufferOperation.
*/
- virtual void executePixelSampled(float /*output*/[4],
- float /*x*/,
- float /*y*/,
- PixelSampler /*sampler*/)
+ virtual void execute_pixel_sampled(float /*output*/[4],
+ float /*x*/,
+ float /*y*/,
+ PixelSampler /*sampler*/)
{
}
@@ -727,12 +750,12 @@ class NodeOperation {
* \param result: is a float[4] array to store the result
* \param x: the x-coordinate of the pixel to calculate in image space
* \param y: the y-coordinate of the pixel to calculate in image space
- * \param inputBuffers: chunks that can be read by their ReadBufferOperation.
- * \param chunkData: chunk specific data a during execution time.
+ * \param input_buffers: chunks that can be read by their ReadBufferOperation.
+ * \param chunk_data: chunk specific data a during execution time.
*/
- virtual void executePixel(float output[4], int x, int y, void * /*chunkData*/)
+ virtual void execute_pixel(float output[4], int x, int y, void * /*chunk_data*/)
{
- executePixelSampled(output, x, y, PixelSampler::Nearest);
+ execute_pixel_sampled(output, x, y, PixelSampler::Nearest);
}
/**
@@ -743,9 +766,9 @@ class NodeOperation {
* \param y: the y-coordinate of the pixel to calculate in image space
* \param dx:
* \param dy:
- * \param inputBuffers: chunks that can be read by their ReadBufferOperation.
+ * \param input_buffers: chunks that can be read by their ReadBufferOperation.
*/
- virtual void executePixelFiltered(
+ virtual void execute_pixel_filtered(
float /*output*/[4], float /*x*/, float /*y*/, float /*dx*/[2], float /*dy*/[2])
{
}
@@ -755,14 +778,23 @@ class NodeOperation {
/** \name Full Frame Methods
* \{ */
+ /**
+ * Renders given areas using operations full frame implementation.
+ */
void render_full_frame(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs_bufs);
+ /**
+ * Renders given areas using operations tiled implementation.
+ */
void render_full_frame_fallback(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs);
void render_tile(MemoryBuffer *output_buf, rcti *tile_rect);
+ /**
+ * \return Replaced inputs links.
+ */
Vector<NodeOperationOutput *> replace_inputs_with_buffers(Span<MemoryBuffer *> inputs_bufs);
void remove_buffers_and_restore_original_inputs(
Span<NodeOperationOutput *> original_inputs_links);
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
index acb7f61f6dd..2109dd9c582 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
@@ -16,24 +16,19 @@
* Copyright 2013, Blender Foundation.
*/
+#include <set>
+
#include "BLI_multi_value_map.hh"
-#include "BLI_utildefines.h"
#include "COM_Converter.h"
#include "COM_Debug.h"
-#include "COM_ExecutionSystem.h"
-#include "COM_Node.h"
-#include "COM_NodeConverter.h"
-#include "COM_SocketProxyNode.h"
-#include "COM_NodeOperation.h"
+#include "COM_ExecutionGroup.h"
#include "COM_PreviewOperation.h"
#include "COM_ReadBufferOperation.h"
#include "COM_SetColorOperation.h"
#include "COM_SetValueOperation.h"
#include "COM_SetVectorOperation.h"
-#include "COM_SocketProxyOperation.h"
-#include "COM_TranslateOperation.h"
#include "COM_ViewerOperation.h"
#include "COM_WriteBufferOperation.h"
@@ -45,39 +40,39 @@ namespace blender::compositor {
NodeOperationBuilder::NodeOperationBuilder(const CompositorContext *context,
bNodeTree *b_nodetree,
ExecutionSystem *system)
- : m_context(context), exec_system_(system), m_current_node(nullptr), m_active_viewer(nullptr)
+ : context_(context), exec_system_(system), current_node_(nullptr), active_viewer_(nullptr)
{
- m_graph.from_bNodeTree(*context, b_nodetree);
+ graph_.from_bNodeTree(*context, b_nodetree);
}
-void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
+void NodeOperationBuilder::convert_to_operations(ExecutionSystem *system)
{
/* interface handle for nodes */
NodeConverter converter(this);
- for (Node *node : m_graph.nodes()) {
- m_current_node = node;
+ for (Node *node : graph_.nodes()) {
+ current_node_ = node;
DebugInfo::node_to_operations(node);
- node->convertToOperations(converter, *m_context);
+ node->convert_to_operations(converter, *context_);
}
- m_current_node = nullptr;
+ current_node_ = nullptr;
/* The input map constructed by nodes maps operation inputs to node inputs.
* Inverting yields a map of node inputs to all connected operation inputs,
* so multiple operations can use the same node input.
*/
blender::MultiValueMap<NodeInput *, NodeOperationInput *> inverse_input_map;
- for (Map<NodeOperationInput *, NodeInput *>::MutableItem item : m_input_map.items()) {
+ for (Map<NodeOperationInput *, NodeInput *>::MutableItem item : input_map_.items()) {
inverse_input_map.add(item.value, item.key);
}
- for (const NodeGraph::Link &link : m_graph.links()) {
+ for (const NodeGraph::Link &link : graph_.links()) {
NodeOutput *from = link.from;
NodeInput *to = link.to;
- NodeOperationOutput *op_from = m_output_map.lookup_default(from, nullptr);
+ NodeOperationOutput *op_from = output_map_.lookup_default(from, nullptr);
const blender::Span<NodeOperationInput *> op_to_list = inverse_input_map.lookup(to);
if (!op_from || op_to_list.is_empty()) {
@@ -91,7 +86,7 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
}
for (NodeOperationInput *op_to : op_to_list) {
- addLink(op_from, op_to);
+ add_link(op_from, op_to);
}
}
@@ -101,7 +96,7 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
add_datatype_conversions();
- if (m_context->get_execution_model() == eExecutionModel::FullFrame) {
+ if (context_->get_execution_model() == eExecutionModel::FullFrame) {
save_graphviz("compositor_prior_folding");
ConstantFolder folder(*this);
folder.fold_operations();
@@ -112,111 +107,111 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
save_graphviz("compositor_prior_merging");
merge_equal_operations();
- if (m_context->get_execution_model() == eExecutionModel::Tiled) {
+ if (context_->get_execution_model() == eExecutionModel::Tiled) {
/* surround complex ops with read/write buffer */
add_complex_operation_buffers();
}
/* links not available from here on */
- /* XXX make m_links a local variable to avoid confusion! */
- m_links.clear();
+ /* XXX make links_ a local variable to avoid confusion! */
+ links_.clear();
prune_operations();
/* ensure topological (link-based) order of nodes */
/*sort_operations();*/ /* not needed yet */
- if (m_context->get_execution_model() == eExecutionModel::Tiled) {
+ if (context_->get_execution_model() == eExecutionModel::Tiled) {
/* create execution groups */
group_operations();
}
/* transfer resulting operations to the system */
- system->set_operations(m_operations, m_groups);
+ system->set_operations(operations_, groups_);
}
-void NodeOperationBuilder::addOperation(NodeOperation *operation)
+void NodeOperationBuilder::add_operation(NodeOperation *operation)
{
- operation->set_id(m_operations.size());
- m_operations.append(operation);
- if (m_current_node) {
- operation->set_name(m_current_node->getbNode()->name);
+ operation->set_id(operations_.size());
+ operations_.append(operation);
+ if (current_node_) {
+ operation->set_name(current_node_->get_bnode()->name);
}
- operation->set_execution_model(m_context->get_execution_model());
+ operation->set_execution_model(context_->get_execution_model());
operation->set_execution_system(exec_system_);
}
void NodeOperationBuilder::replace_operation_with_constant(NodeOperation *operation,
ConstantOperation *constant_operation)
{
- BLI_assert(constant_operation->getNumberOfInputSockets() == 0);
+ BLI_assert(constant_operation->get_number_of_input_sockets() == 0);
unlink_inputs_and_relink_outputs(operation, constant_operation);
- addOperation(constant_operation);
+ add_operation(constant_operation);
}
void NodeOperationBuilder::unlink_inputs_and_relink_outputs(NodeOperation *unlinked_op,
NodeOperation *linked_op)
{
int i = 0;
- while (i < m_links.size()) {
- Link &link = m_links[i];
- if (&link.to()->getOperation() == unlinked_op) {
- link.to()->setLink(nullptr);
- m_links.remove(i);
+ while (i < links_.size()) {
+ Link &link = links_[i];
+ if (&link.to()->get_operation() == unlinked_op) {
+ link.to()->set_link(nullptr);
+ links_.remove(i);
continue;
}
- if (&link.from()->getOperation() == unlinked_op) {
- link.to()->setLink(linked_op->getOutputSocket());
- m_links[i] = Link(linked_op->getOutputSocket(), link.to());
+ if (&link.from()->get_operation() == unlinked_op) {
+ link.to()->set_link(linked_op->get_output_socket());
+ links_[i] = Link(linked_op->get_output_socket(), link.to());
}
i++;
}
}
-void NodeOperationBuilder::mapInputSocket(NodeInput *node_socket,
- NodeOperationInput *operation_socket)
+void NodeOperationBuilder::map_input_socket(NodeInput *node_socket,
+ NodeOperationInput *operation_socket)
{
- BLI_assert(m_current_node);
- BLI_assert(node_socket->getNode() == m_current_node);
+ BLI_assert(current_node_);
+ BLI_assert(node_socket->get_node() == current_node_);
/* NOTE: this maps operation sockets to node sockets.
- * for resolving links the map will be inverted first in convertToOperations,
+ * for resolving links the map will be inverted first in convert_to_operations,
* to get a list of links for each node input socket.
*/
- m_input_map.add_new(operation_socket, node_socket);
+ input_map_.add_new(operation_socket, node_socket);
}
-void NodeOperationBuilder::mapOutputSocket(NodeOutput *node_socket,
- NodeOperationOutput *operation_socket)
+void NodeOperationBuilder::map_output_socket(NodeOutput *node_socket,
+ NodeOperationOutput *operation_socket)
{
- BLI_assert(m_current_node);
- BLI_assert(node_socket->getNode() == m_current_node);
+ BLI_assert(current_node_);
+ BLI_assert(node_socket->get_node() == current_node_);
- m_output_map.add_new(node_socket, operation_socket);
+ output_map_.add_new(node_socket, operation_socket);
}
-void NodeOperationBuilder::addLink(NodeOperationOutput *from, NodeOperationInput *to)
+void NodeOperationBuilder::add_link(NodeOperationOutput *from, NodeOperationInput *to)
{
- if (to->isConnected()) {
+ if (to->is_connected()) {
return;
}
- m_links.append(Link(from, to));
+ links_.append(Link(from, to));
/* register with the input */
- to->setLink(from);
+ to->set_link(from);
}
-void NodeOperationBuilder::removeInputLink(NodeOperationInput *to)
+void NodeOperationBuilder::remove_input_link(NodeOperationInput *to)
{
int index = 0;
- for (Link &link : m_links) {
+ for (Link &link : links_) {
if (link.to() == to) {
/* unregister with the input */
- to->setLink(nullptr);
+ to->set_link(nullptr);
- m_links.remove(index);
+ links_.remove(index);
return;
}
index++;
@@ -225,69 +220,69 @@ void NodeOperationBuilder::removeInputLink(NodeOperationInput *to)
PreviewOperation *NodeOperationBuilder::make_preview_operation() const
{
- BLI_assert(m_current_node);
+ BLI_assert(current_node_);
- if (!(m_current_node->getbNode()->flag & NODE_PREVIEW)) {
+ if (!(current_node_->get_bnode()->flag & NODE_PREVIEW)) {
return nullptr;
}
/* previews only in the active group */
- if (!m_current_node->isInActiveGroup()) {
+ if (!current_node_->is_in_active_group()) {
return nullptr;
}
/* do not calculate previews of hidden nodes */
- if (m_current_node->getbNode()->flag & NODE_HIDDEN) {
+ if (current_node_->get_bnode()->flag & NODE_HIDDEN) {
return nullptr;
}
- bNodeInstanceHash *previews = m_context->getPreviewHash();
+ bNodeInstanceHash *previews = context_->get_preview_hash();
if (previews) {
- PreviewOperation *operation = new PreviewOperation(m_context->getViewSettings(),
- m_context->getDisplaySettings(),
- m_current_node->getbNode()->preview_xsize,
- m_current_node->getbNode()->preview_ysize);
- operation->setbNodeTree(m_context->getbNodeTree());
- operation->verifyPreview(previews, m_current_node->getInstanceKey());
+ PreviewOperation *operation = new PreviewOperation(context_->get_view_settings(),
+ context_->get_display_settings(),
+ current_node_->get_bnode()->preview_xsize,
+ current_node_->get_bnode()->preview_ysize);
+ operation->set_bnodetree(context_->get_bnodetree());
+ operation->verify_preview(previews, current_node_->get_instance_key());
return operation;
}
return nullptr;
}
-void NodeOperationBuilder::addPreview(NodeOperationOutput *output)
+void NodeOperationBuilder::add_preview(NodeOperationOutput *output)
{
PreviewOperation *operation = make_preview_operation();
if (operation) {
- addOperation(operation);
+ add_operation(operation);
- addLink(output, operation->getInputSocket(0));
+ add_link(output, operation->get_input_socket(0));
}
}
-void NodeOperationBuilder::addNodeInputPreview(NodeInput *input)
+void NodeOperationBuilder::add_node_input_preview(NodeInput *input)
{
PreviewOperation *operation = make_preview_operation();
if (operation) {
- addOperation(operation);
+ add_operation(operation);
- mapInputSocket(input, operation->getInputSocket(0));
+ map_input_socket(input, operation->get_input_socket(0));
}
}
-void NodeOperationBuilder::registerViewer(ViewerOperation *viewer)
+void NodeOperationBuilder::register_viewer(ViewerOperation *viewer)
{
- if (m_active_viewer) {
- if (m_current_node->isInActiveGroup()) {
+ if (active_viewer_) {
+ if (current_node_->is_in_active_group()) {
/* deactivate previous viewer */
- m_active_viewer->setActive(false);
+ active_viewer_->set_active(false);
- m_active_viewer = viewer;
- viewer->setActive(true);
+ active_viewer_ = viewer;
+ viewer->set_active(true);
}
}
else {
- if (m_current_node->getbNodeTree() == m_context->getbNodeTree()) {
- m_active_viewer = viewer;
- viewer->setActive(true);
+ if (current_node_->get_bnodetree() == context_->get_bnodetree()) {
+ active_viewer_ = viewer;
+ viewer->set_active(true);
}
}
}
@@ -299,27 +294,27 @@ void NodeOperationBuilder::registerViewer(ViewerOperation *viewer)
void NodeOperationBuilder::add_datatype_conversions()
{
Vector<Link> convert_links;
- for (const Link &link : m_links) {
+ for (const Link &link : links_) {
/* proxy operations can skip data type conversion */
- NodeOperation *from_op = &link.from()->getOperation();
- NodeOperation *to_op = &link.to()->getOperation();
+ NodeOperation *from_op = &link.from()->get_operation();
+ NodeOperation *to_op = &link.to()->get_operation();
if (!(from_op->get_flags().use_datatype_conversion ||
to_op->get_flags().use_datatype_conversion)) {
continue;
}
- if (link.from()->getDataType() != link.to()->getDataType()) {
+ if (link.from()->get_data_type() != link.to()->get_data_type()) {
convert_links.append(link);
}
}
for (const Link &link : convert_links) {
NodeOperation *converter = COM_convert_data_type(*link.from(), *link.to());
if (converter) {
- addOperation(converter);
+ add_operation(converter);
- removeInputLink(link.to());
- addLink(link.from(), converter->getInputSocket(0));
- addLink(converter->getOutputSocket(0), link.to());
+ remove_input_link(link.to());
+ add_link(link.from(), converter->get_input_socket(0));
+ add_link(converter->get_output_socket(0), link.to());
}
}
}
@@ -327,69 +322,69 @@ void NodeOperationBuilder::add_datatype_conversions()
void NodeOperationBuilder::add_operation_input_constants()
{
/* NOTE: unconnected inputs cached first to avoid modifying
- * m_operations while iterating over it
+ * operations_ while iterating over it
*/
Vector<NodeOperationInput *> pending_inputs;
- for (NodeOperation *op : m_operations) {
- for (int k = 0; k < op->getNumberOfInputSockets(); ++k) {
- NodeOperationInput *input = op->getInputSocket(k);
- if (!input->isConnected()) {
+ for (NodeOperation *op : operations_) {
+ for (int k = 0; k < op->get_number_of_input_sockets(); ++k) {
+ NodeOperationInput *input = op->get_input_socket(k);
+ if (!input->is_connected()) {
pending_inputs.append(input);
}
}
}
for (NodeOperationInput *input : pending_inputs) {
- add_input_constant_value(input, m_input_map.lookup_default(input, nullptr));
+ add_input_constant_value(input, input_map_.lookup_default(input, nullptr));
}
}
void NodeOperationBuilder::add_input_constant_value(NodeOperationInput *input,
const NodeInput *node_input)
{
- switch (input->getDataType()) {
+ switch (input->get_data_type()) {
case DataType::Value: {
float value;
- if (node_input && node_input->getbNodeSocket()) {
- value = node_input->getEditorValueFloat();
+ if (node_input && node_input->get_bnode_socket()) {
+ value = node_input->get_editor_value_float();
}
else {
value = 0.0f;
}
SetValueOperation *op = new SetValueOperation();
- op->setValue(value);
- addOperation(op);
- addLink(op->getOutputSocket(), input);
+ op->set_value(value);
+ add_operation(op);
+ add_link(op->get_output_socket(), input);
break;
}
case DataType::Color: {
float value[4];
- if (node_input && node_input->getbNodeSocket()) {
- node_input->getEditorValueColor(value);
+ if (node_input && node_input->get_bnode_socket()) {
+ node_input->get_editor_value_color(value);
}
else {
zero_v4(value);
}
SetColorOperation *op = new SetColorOperation();
- op->setChannels(value);
- addOperation(op);
- addLink(op->getOutputSocket(), input);
+ op->set_channels(value);
+ add_operation(op);
+ add_link(op->get_output_socket(), input);
break;
}
case DataType::Vector: {
float value[3];
- if (node_input && node_input->getbNodeSocket()) {
- node_input->getEditorValueVector(value);
+ if (node_input && node_input->get_bnode_socket()) {
+ node_input->get_editor_value_vector(value);
}
else {
zero_v3(value);
}
SetVectorOperation *op = new SetVectorOperation();
- op->setVector(value);
- addOperation(op);
- addLink(op->getOutputSocket(), input);
+ op->set_vector(value);
+ add_operation(op);
+ add_link(op->get_output_socket(), input);
break;
}
}
@@ -398,10 +393,10 @@ void NodeOperationBuilder::add_input_constant_value(NodeOperationInput *input,
void NodeOperationBuilder::resolve_proxies()
{
Vector<Link> proxy_links;
- for (const Link &link : m_links) {
+ for (const Link &link : links_) {
/* don't replace links from proxy to proxy, since we may need them for replacing others! */
- if (link.from()->getOperation().get_flags().is_proxy_operation &&
- !link.to()->getOperation().get_flags().is_proxy_operation) {
+ if (link.from()->get_operation().get_flags().is_proxy_operation &&
+ !link.to()->get_operation().get_flags().is_proxy_operation) {
proxy_links.append(link);
}
}
@@ -411,15 +406,15 @@ void NodeOperationBuilder::resolve_proxies()
NodeOperationOutput *from = link.from();
do {
/* walk upstream bypassing the proxy operation */
- from = from->getOperation().getInputSocket(0)->getLink();
- } while (from && from->getOperation().get_flags().is_proxy_operation);
+ from = from->get_operation().get_input_socket(0)->get_link();
+ } while (from && from->get_operation().get_flags().is_proxy_operation);
- removeInputLink(to);
+ remove_input_link(to);
/* we may not have a final proxy input link,
* in that case it just gets dropped
*/
if (from) {
- addLink(from, to);
+ add_link(from, to);
}
}
}
@@ -428,16 +423,18 @@ void NodeOperationBuilder::determine_canvases()
{
/* Determine all canvas areas of the operations. */
const rcti &preferred_area = COM_AREA_NONE;
- for (NodeOperation *op : m_operations) {
- if (op->isOutputOperation(m_context->isRendering()) && !op->get_flags().is_preview_operation) {
+ for (NodeOperation *op : operations_) {
+ if (op->is_output_operation(context_->is_rendering()) &&
+ !op->get_flags().is_preview_operation) {
rcti canvas = COM_AREA_NONE;
op->determine_canvas(preferred_area, canvas);
op->set_canvas(canvas);
}
}
- for (NodeOperation *op : m_operations) {
- if (op->isOutputOperation(m_context->isRendering()) && op->get_flags().is_preview_operation) {
+ for (NodeOperation *op : operations_) {
+ if (op->is_output_operation(context_->is_rendering()) &&
+ op->get_flags().is_preview_operation) {
rcti canvas = COM_AREA_NONE;
op->determine_canvas(preferred_area, canvas);
op->set_canvas(canvas);
@@ -447,13 +444,13 @@ void NodeOperationBuilder::determine_canvases()
/* Convert operation canvases when needed. */
{
Vector<Link> convert_links;
- for (const Link &link : m_links) {
- if (link.to()->getResizeMode() != ResizeMode::None) {
- const rcti &from_canvas = link.from()->getOperation().get_canvas();
- const rcti &to_canvas = link.to()->getOperation().get_canvas();
+ for (const Link &link : links_) {
+ if (link.to()->get_resize_mode() != ResizeMode::None) {
+ const rcti &from_canvas = link.from()->get_operation().get_canvas();
+ const rcti &to_canvas = link.to()->get_operation().get_canvas();
bool needs_conversion;
- if (link.to()->getResizeMode() == ResizeMode::Align) {
+ if (link.to()->get_resize_mode() == ResizeMode::Align) {
needs_conversion = from_canvas.xmin != to_canvas.xmin ||
from_canvas.ymin != to_canvas.ymin;
}
@@ -484,13 +481,12 @@ static Vector<NodeOperationHash> generate_hashes(Span<NodeOperation *> operation
return hashes;
}
-/** Merge operations with same type, inputs and parameters that produce the same result. */
void NodeOperationBuilder::merge_equal_operations()
{
bool check_for_next_merge = true;
while (check_for_next_merge) {
/* Re-generate hashes with any change. */
- Vector<NodeOperationHash> hashes = generate_hashes(m_operations);
+ Vector<NodeOperationHash> hashes = generate_hashes(operations_);
/* Make hashes be consecutive when they are equal. */
std::sort(hashes.begin(), hashes.end());
@@ -512,7 +508,7 @@ void NodeOperationBuilder::merge_equal_operations()
void NodeOperationBuilder::merge_equal_operations(NodeOperation *from, NodeOperation *into)
{
unlink_inputs_and_relink_outputs(from, into);
- m_operations.remove_first_occurrence_and_reorder(from);
+ operations_.remove_first_occurrence_and_reorder(from);
delete from;
}
@@ -520,7 +516,7 @@ Vector<NodeOperationInput *> NodeOperationBuilder::cache_output_links(
NodeOperationOutput *output) const
{
Vector<NodeOperationInput *> inputs;
- for (const Link &link : m_links) {
+ for (const Link &link : links_) {
if (link.from() == output) {
inputs.append(link.to());
}
@@ -531,9 +527,9 @@ Vector<NodeOperationInput *> NodeOperationBuilder::cache_output_links(
WriteBufferOperation *NodeOperationBuilder::find_attached_write_buffer_operation(
NodeOperationOutput *output) const
{
- for (const Link &link : m_links) {
+ for (const Link &link : links_) {
if (link.from() == output) {
- NodeOperation &op = link.to()->getOperation();
+ NodeOperation &op = link.to()->get_operation();
if (op.get_flags().is_write_buffer_operation) {
return (WriteBufferOperation *)(&op);
}
@@ -545,39 +541,39 @@ WriteBufferOperation *NodeOperationBuilder::find_attached_write_buffer_operation
void NodeOperationBuilder::add_input_buffers(NodeOperation * /*operation*/,
NodeOperationInput *input)
{
- if (!input->isConnected()) {
+ if (!input->is_connected()) {
return;
}
- NodeOperationOutput *output = input->getLink();
- if (output->getOperation().get_flags().is_read_buffer_operation) {
+ NodeOperationOutput *output = input->get_link();
+ if (output->get_operation().get_flags().is_read_buffer_operation) {
/* input is already buffered, no need to add another */
return;
}
/* this link will be replaced below */
- removeInputLink(input);
+ remove_input_link(input);
/* check of other end already has write operation, otherwise add a new one */
WriteBufferOperation *writeoperation = find_attached_write_buffer_operation(output);
if (!writeoperation) {
- writeoperation = new WriteBufferOperation(output->getDataType());
- writeoperation->setbNodeTree(m_context->getbNodeTree());
- addOperation(writeoperation);
+ writeoperation = new WriteBufferOperation(output->get_data_type());
+ writeoperation->set_bnodetree(context_->get_bnodetree());
+ add_operation(writeoperation);
- addLink(output, writeoperation->getInputSocket(0));
+ add_link(output, writeoperation->get_input_socket(0));
- writeoperation->readResolutionFromInputSocket();
+ writeoperation->read_resolution_from_input_socket();
}
/* add readbuffer op for the input */
- ReadBufferOperation *readoperation = new ReadBufferOperation(output->getDataType());
- readoperation->setMemoryProxy(writeoperation->getMemoryProxy());
- this->addOperation(readoperation);
+ ReadBufferOperation *readoperation = new ReadBufferOperation(output->get_data_type());
+ readoperation->set_memory_proxy(writeoperation->get_memory_proxy());
+ this->add_operation(readoperation);
- addLink(readoperation->getOutputSocket(), input);
+ add_link(readoperation->get_output_socket(), input);
- readoperation->readResolutionFromWriteBuffer();
+ readoperation->read_resolution_from_write_buffer();
}
void NodeOperationBuilder::add_output_buffers(NodeOperation *operation,
@@ -589,54 +585,54 @@ void NodeOperationBuilder::add_output_buffers(NodeOperation *operation,
return;
}
- WriteBufferOperation *writeOperation = nullptr;
+ WriteBufferOperation *write_operation = nullptr;
for (NodeOperationInput *target : targets) {
/* try to find existing write buffer operation */
- if (target->getOperation().get_flags().is_write_buffer_operation) {
- BLI_assert(writeOperation == nullptr); /* there should only be one write op connected */
- writeOperation = (WriteBufferOperation *)(&target->getOperation());
+ if (target->get_operation().get_flags().is_write_buffer_operation) {
+ BLI_assert(write_operation == nullptr); /* there should only be one write op connected */
+ write_operation = (WriteBufferOperation *)(&target->get_operation());
}
else {
/* remove all links to other nodes */
- removeInputLink(target);
+ remove_input_link(target);
}
}
/* if no write buffer operation exists yet, create a new one */
- if (!writeOperation) {
- writeOperation = new WriteBufferOperation(operation->getOutputSocket()->getDataType());
- writeOperation->setbNodeTree(m_context->getbNodeTree());
- addOperation(writeOperation);
+ if (!write_operation) {
+ write_operation = new WriteBufferOperation(operation->get_output_socket()->get_data_type());
+ write_operation->set_bnodetree(context_->get_bnodetree());
+ add_operation(write_operation);
- addLink(output, writeOperation->getInputSocket(0));
+ add_link(output, write_operation->get_input_socket(0));
}
- writeOperation->readResolutionFromInputSocket();
+ write_operation->read_resolution_from_input_socket();
/* add readbuffer op for every former connected input */
for (NodeOperationInput *target : targets) {
- if (&target->getOperation() == writeOperation) {
+ if (&target->get_operation() == write_operation) {
continue; /* skip existing write op links */
}
ReadBufferOperation *readoperation = new ReadBufferOperation(
- operation->getOutputSocket()->getDataType());
- readoperation->setMemoryProxy(writeOperation->getMemoryProxy());
- addOperation(readoperation);
+ operation->get_output_socket()->get_data_type());
+ readoperation->set_memory_proxy(write_operation->get_memory_proxy());
+ add_operation(readoperation);
- addLink(readoperation->getOutputSocket(), target);
+ add_link(readoperation->get_output_socket(), target);
- readoperation->readResolutionFromWriteBuffer();
+ readoperation->read_resolution_from_write_buffer();
}
}
void NodeOperationBuilder::add_complex_operation_buffers()
{
/* NOTE: complex ops and get cached here first, since adding operations
- * will invalidate iterators over the main m_operations
+ * will invalidate iterators over the main operations_
*/
Vector<NodeOperation *> complex_ops;
- for (NodeOperation *operation : m_operations) {
+ for (NodeOperation *operation : operations_) {
if (operation->get_flags().complex) {
complex_ops.append(operation);
}
@@ -645,12 +641,12 @@ void NodeOperationBuilder::add_complex_operation_buffers()
for (NodeOperation *op : complex_ops) {
DebugInfo::operation_read_write_buffer(op);
- for (int index = 0; index < op->getNumberOfInputSockets(); index++) {
- add_input_buffers(op, op->getInputSocket(index));
+ for (int index = 0; index < op->get_number_of_input_sockets(); index++) {
+ add_input_buffers(op, op->get_input_socket(index));
}
- for (int index = 0; index < op->getNumberOfOutputSockets(); index++) {
- add_output_buffers(op, op->getOutputSocket(index));
+ for (int index = 0; index < op->get_number_of_output_sockets(); index++) {
+ add_output_buffers(op, op->get_output_socket(index));
}
}
}
@@ -664,34 +660,34 @@ static void find_reachable_operations_recursive(Tags &reachable, NodeOperation *
}
reachable.insert(op);
- for (int i = 0; i < op->getNumberOfInputSockets(); i++) {
- NodeOperationInput *input = op->getInputSocket(i);
- if (input->isConnected()) {
- find_reachable_operations_recursive(reachable, &input->getLink()->getOperation());
+ for (int i = 0; i < op->get_number_of_input_sockets(); i++) {
+ NodeOperationInput *input = op->get_input_socket(i);
+ if (input->is_connected()) {
+ find_reachable_operations_recursive(reachable, &input->get_link()->get_operation());
}
}
/* associated write-buffer operations are executed as well */
if (op->get_flags().is_read_buffer_operation) {
ReadBufferOperation *read_op = (ReadBufferOperation *)op;
- MemoryProxy *memproxy = read_op->getMemoryProxy();
- find_reachable_operations_recursive(reachable, memproxy->getWriteBufferOperation());
+ MemoryProxy *memproxy = read_op->get_memory_proxy();
+ find_reachable_operations_recursive(reachable, memproxy->get_write_buffer_operation());
}
}
void NodeOperationBuilder::prune_operations()
{
Tags reachable;
- for (NodeOperation *op : m_operations) {
+ for (NodeOperation *op : operations_) {
/* output operations are primary executed operations */
- if (op->isOutputOperation(m_context->isRendering())) {
+ if (op->is_output_operation(context_->is_rendering())) {
find_reachable_operations_recursive(reachable, op);
}
}
/* delete unreachable operations */
Vector<NodeOperation *> reachable_ops;
- for (NodeOperation *op : m_operations) {
+ for (NodeOperation *op : operations_) {
if (reachable.find(op) != reachable.end()) {
reachable_ops.append(op);
}
@@ -700,7 +696,7 @@ void NodeOperationBuilder::prune_operations()
}
}
/* finally replace the operations list with the pruned list */
- m_operations = reachable_ops;
+ operations_ = reachable_ops;
}
/* topological (depth-first) sorting of operations */
@@ -713,10 +709,10 @@ static void sort_operations_recursive(Vector<NodeOperation *> &sorted,
}
visited.insert(op);
- for (int i = 0; i < op->getNumberOfInputSockets(); i++) {
- NodeOperationInput *input = op->getInputSocket(i);
- if (input->isConnected()) {
- sort_operations_recursive(sorted, visited, &input->getLink()->getOperation());
+ for (int i = 0; i < op->get_number_of_input_sockets(); i++) {
+ NodeOperationInput *input = op->get_input_socket(i);
+ if (input->is_connected()) {
+ sort_operations_recursive(sorted, visited, &input->get_link()->get_operation());
}
}
@@ -726,14 +722,14 @@ static void sort_operations_recursive(Vector<NodeOperation *> &sorted,
void NodeOperationBuilder::sort_operations()
{
Vector<NodeOperation *> sorted;
- sorted.reserve(m_operations.size());
+ sorted.reserve(operations_.size());
Tags visited;
- for (NodeOperation *operation : m_operations) {
+ for (NodeOperation *operation : operations_) {
sort_operations_recursive(sorted, visited, operation);
}
- m_operations = sorted;
+ operations_ = sorted;
}
static void add_group_operations_recursive(Tags &visited, NodeOperation *op, ExecutionGroup *group)
@@ -743,23 +739,23 @@ static void add_group_operations_recursive(Tags &visited, NodeOperation *op, Exe
}
visited.insert(op);
- if (!group->addOperation(op)) {
+ if (!group->add_operation(op)) {
return;
}
/* add all eligible input ops to the group */
- for (int i = 0; i < op->getNumberOfInputSockets(); i++) {
- NodeOperationInput *input = op->getInputSocket(i);
- if (input->isConnected()) {
- add_group_operations_recursive(visited, &input->getLink()->getOperation(), group);
+ for (int i = 0; i < op->get_number_of_input_sockets(); i++) {
+ NodeOperationInput *input = op->get_input_socket(i);
+ if (input->is_connected()) {
+ add_group_operations_recursive(visited, &input->get_link()->get_operation(), group);
}
}
}
ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op)
{
- ExecutionGroup *group = new ExecutionGroup(this->m_groups.size());
- m_groups.append(group);
+ ExecutionGroup *group = new ExecutionGroup(groups_.size());
+ groups_.append(group);
Tags visited;
add_group_operations_recursive(visited, op, group);
@@ -769,20 +765,20 @@ ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op)
void NodeOperationBuilder::group_operations()
{
- for (NodeOperation *op : m_operations) {
- if (op->isOutputOperation(m_context->isRendering())) {
+ for (NodeOperation *op : operations_) {
+ if (op->is_output_operation(context_->is_rendering())) {
ExecutionGroup *group = make_group(op);
- group->setOutputExecutionGroup(true);
+ group->set_output_execution_group(true);
}
/* add new groups for associated memory proxies where needed */
if (op->get_flags().is_read_buffer_operation) {
ReadBufferOperation *read_op = (ReadBufferOperation *)op;
- MemoryProxy *memproxy = read_op->getMemoryProxy();
+ MemoryProxy *memproxy = read_op->get_memory_proxy();
- if (memproxy->getExecutor() == nullptr) {
- ExecutionGroup *group = make_group(memproxy->getWriteBufferOperation());
- memproxy->setExecutor(group);
+ if (memproxy->get_executor() == nullptr) {
+ ExecutionGroup *group = make_group(memproxy->get_write_buffer_operation());
+ memproxy->set_executor(group);
}
}
}
@@ -791,12 +787,11 @@ void NodeOperationBuilder::group_operations()
void NodeOperationBuilder::save_graphviz(StringRefNull name)
{
if (COM_EXPORT_GRAPHVIZ) {
- exec_system_->set_operations(m_operations, m_groups);
+ exec_system_->set_operations(operations_, groups_);
DebugInfo::graphviz(exec_system_, name);
}
}
-/** Create a graphviz representation of the NodeOperationBuilder. */
std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder &builder)
{
os << "# Builder start\n";
@@ -809,15 +804,15 @@ std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder &builder)
os << "\n";
for (const NodeOperationBuilder::Link &link : builder.get_links()) {
- os << " op" << link.from()->getOperation().get_id() << " -> op"
- << link.to()->getOperation().get_id() << ";\n";
+ os << " op" << link.from()->get_operation().get_id() << " -> op"
+ << link.to()->get_operation().get_id() << ";\n";
}
for (const NodeOperation *operation : builder.get_operations()) {
if (operation->get_flags().is_read_buffer_operation) {
const ReadBufferOperation &read_operation = static_cast<const ReadBufferOperation &>(
*operation);
const WriteBufferOperation &write_operation =
- *read_operation.getMemoryProxy()->getWriteBufferOperation();
+ *read_operation.get_memory_proxy()->get_write_buffer_operation();
os << " op" << write_operation.get_id() << " -> op" << read_operation.get_id() << ";\n";
}
}
@@ -829,7 +824,7 @@ std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder &builder)
std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder::Link &link)
{
- os << link.from()->getOperation().get_id() << " -> " << link.to()->getOperation().get_id();
+ os << link.from()->get_operation().get_id() << " -> " << link.to()->get_operation().get_id();
return os;
}
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.h b/source/blender/compositor/intern/COM_NodeOperationBuilder.h
index 1f9c86b51cd..efc927e7c9e 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.h
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.h
@@ -18,9 +18,8 @@
#pragma once
-#include <map>
-#include <set>
-#include <vector>
+#include "BLI_map.hh"
+#include "BLI_vector.hh"
#include "COM_NodeGraph.h"
@@ -47,45 +46,45 @@ class NodeOperationBuilder {
public:
class Link {
private:
- NodeOperationOutput *m_from;
- NodeOperationInput *m_to;
+ NodeOperationOutput *from_;
+ NodeOperationInput *to_;
public:
- Link(NodeOperationOutput *from, NodeOperationInput *to) : m_from(from), m_to(to)
+ Link(NodeOperationOutput *from, NodeOperationInput *to) : from_(from), to_(to)
{
}
NodeOperationOutput *from() const
{
- return m_from;
+ return from_;
}
NodeOperationInput *to() const
{
- return m_to;
+ return to_;
}
};
private:
- const CompositorContext *m_context;
- NodeGraph m_graph;
+ const CompositorContext *context_;
+ NodeGraph graph_;
ExecutionSystem *exec_system_;
- Vector<NodeOperation *> m_operations;
- Vector<Link> m_links;
- Vector<ExecutionGroup *> m_groups;
+ Vector<NodeOperation *> operations_;
+ Vector<Link> links_;
+ Vector<ExecutionGroup *> groups_;
/** Maps operation inputs to node inputs */
- Map<NodeOperationInput *, NodeInput *> m_input_map;
+ Map<NodeOperationInput *, NodeInput *> input_map_;
/** Maps node outputs to operation outputs */
- Map<NodeOutput *, NodeOperationOutput *> m_output_map;
+ Map<NodeOutput *, NodeOperationOutput *> output_map_;
- Node *m_current_node;
+ Node *current_node_;
/** Operation that will be writing to the viewer image
* Only one operation can occupy this place at a time,
* to avoid race conditions
*/
- ViewerOperation *m_active_viewer;
+ ViewerOperation *active_viewer_;
public:
NodeOperationBuilder(const CompositorContext *context,
@@ -94,44 +93,44 @@ class NodeOperationBuilder {
const CompositorContext &context() const
{
- return *m_context;
+ return *context_;
}
- void convertToOperations(ExecutionSystem *system);
+ void convert_to_operations(ExecutionSystem *system);
- void addOperation(NodeOperation *operation);
+ void add_operation(NodeOperation *operation);
void replace_operation_with_constant(NodeOperation *operation,
ConstantOperation *constant_operation);
/** Map input socket of the current node to an operation socket */
- void mapInputSocket(NodeInput *node_socket, NodeOperationInput *operation_socket);
+ void map_input_socket(NodeInput *node_socket, NodeOperationInput *operation_socket);
/** Map output socket of the current node to an operation socket */
- void mapOutputSocket(NodeOutput *node_socket, NodeOperationOutput *operation_socket);
+ void map_output_socket(NodeOutput *node_socket, NodeOperationOutput *operation_socket);
- void addLink(NodeOperationOutput *from, NodeOperationInput *to);
- void removeInputLink(NodeOperationInput *to);
+ void add_link(NodeOperationOutput *from, NodeOperationInput *to);
+ void remove_input_link(NodeOperationInput *to);
/** Add a preview operation for a operation output */
- void addPreview(NodeOperationOutput *output);
+ void add_preview(NodeOperationOutput *output);
/** Add a preview operation for a node input */
- void addNodeInputPreview(NodeInput *input);
+ void add_node_input_preview(NodeInput *input);
/** Define a viewer operation as the active output, if possible */
- void registerViewer(ViewerOperation *viewer);
+ void register_viewer(ViewerOperation *viewer);
/** The currently active viewer output operation */
ViewerOperation *active_viewer() const
{
- return m_active_viewer;
+ return active_viewer_;
}
const Vector<NodeOperation *> &get_operations() const
{
- return m_operations;
+ return operations_;
}
const Vector<Link> &get_links() const
{
- return m_links;
+ return links_;
}
protected:
@@ -170,6 +169,7 @@ class NodeOperationBuilder {
private:
PreviewOperation *make_preview_operation() const;
void unlink_inputs_and_relink_outputs(NodeOperation *unlinked_op, NodeOperation *linked_op);
+ /** Merge operations with same type, inputs and parameters that produce the same result. */
void merge_equal_operations();
void merge_equal_operations(NodeOperation *from, NodeOperation *into);
void save_graphviz(StringRefNull name = "");
@@ -178,6 +178,7 @@ class NodeOperationBuilder {
#endif
};
+/** Create a graphviz representation of the NodeOperationBuilder. */
std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder &builder);
std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder::Link &link);
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cc b/source/blender/compositor/intern/COM_OpenCLDevice.cc
index 3409c8fa3bc..9a274abf806 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.cc
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.cc
@@ -17,7 +17,9 @@
*/
#include "COM_OpenCLDevice.h"
-#include "COM_WorkScheduler.h"
+
+#include "COM_ExecutionGroup.h"
+#include "COM_ReadBufferOperation.h"
namespace blender::compositor {
@@ -38,68 +40,69 @@ const cl_image_format IMAGE_FORMAT_VALUE = {
OpenCLDevice::OpenCLDevice(cl_context context,
cl_device_id device,
cl_program program,
- cl_int vendorId)
+ cl_int vendor_id)
{
- this->m_device = device;
- this->m_context = context;
- this->m_program = program;
- this->m_queue = nullptr;
- this->m_vendorID = vendorId;
+ device_ = device;
+ context_ = context;
+ program_ = program;
+ queue_ = nullptr;
+ vendor_id_ = vendor_id;
cl_int error;
- this->m_queue = clCreateCommandQueue(this->m_context, this->m_device, 0, &error);
+ queue_ = clCreateCommandQueue(context_, device_, 0, &error);
}
OpenCLDevice::OpenCLDevice(OpenCLDevice &&other) noexcept
- : m_context(other.m_context),
- m_device(other.m_device),
- m_program(other.m_program),
- m_queue(other.m_queue),
- m_vendorID(other.m_vendorID)
+ : context_(other.context_),
+ device_(other.device_),
+ program_(other.program_),
+ queue_(other.queue_),
+ vendor_id_(other.vendor_id_)
{
- other.m_queue = nullptr;
+ other.queue_ = nullptr;
}
OpenCLDevice::~OpenCLDevice()
{
- if (this->m_queue) {
- clReleaseCommandQueue(this->m_queue);
+ if (queue_) {
+ clReleaseCommandQueue(queue_);
}
}
void OpenCLDevice::execute(WorkPackage *work_package)
{
- const unsigned int chunkNumber = work_package->chunk_number;
- ExecutionGroup *executionGroup = work_package->execution_group;
+ const unsigned int chunk_number = work_package->chunk_number;
+ ExecutionGroup *execution_group = work_package->execution_group;
- MemoryBuffer **inputBuffers = executionGroup->getInputBuffersOpenCL(chunkNumber);
- MemoryBuffer *outputBuffer = executionGroup->allocateOutputBuffer(work_package->rect);
+ MemoryBuffer **input_buffers = execution_group->get_input_buffers_opencl(chunk_number);
+ MemoryBuffer *output_buffer = execution_group->allocate_output_buffer(work_package->rect);
- executionGroup->getOutputOperation()->executeOpenCLRegion(
- this, &work_package->rect, chunkNumber, inputBuffers, outputBuffer);
+ execution_group->get_output_operation()->execute_opencl_region(
+ this, &work_package->rect, chunk_number, input_buffers, output_buffer);
- delete outputBuffer;
+ delete output_buffer;
- executionGroup->finalizeChunkExecution(chunkNumber, inputBuffers);
+ execution_group->finalize_chunk_execution(chunk_number, input_buffers);
}
-cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel,
- int parameterIndex,
- int offsetIndex,
- std::list<cl_mem> *cleanup,
- MemoryBuffer **inputMemoryBuffers,
- SocketReader *reader)
+cl_mem OpenCLDevice::COM_cl_attach_memory_buffer_to_kernel_parameter(
+ cl_kernel kernel,
+ int parameter_index,
+ int offset_index,
+ std::list<cl_mem> *cleanup,
+ MemoryBuffer **input_memory_buffers,
+ SocketReader *reader)
{
- return COM_clAttachMemoryBufferToKernelParameter(kernel,
- parameterIndex,
- offsetIndex,
- cleanup,
- inputMemoryBuffers,
- (ReadBufferOperation *)reader);
+ return COM_cl_attach_memory_buffer_to_kernel_parameter(kernel,
+ parameter_index,
+ offset_index,
+ cleanup,
+ input_memory_buffers,
+ (ReadBufferOperation *)reader);
}
-const cl_image_format *OpenCLDevice::determineImageFormat(MemoryBuffer *memoryBuffer)
+const cl_image_format *OpenCLDevice::determine_image_format(MemoryBuffer *memory_buffer)
{
- switch (memoryBuffer->get_num_channels()) {
+ switch (memory_buffer->get_num_channels()) {
case 1:
return &IMAGE_FORMAT_VALUE;
break;
@@ -116,166 +119,164 @@ const cl_image_format *OpenCLDevice::determineImageFormat(MemoryBuffer *memoryBu
return &IMAGE_FORMAT_COLOR;
}
-cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel,
- int parameterIndex,
- int offsetIndex,
- std::list<cl_mem> *cleanup,
- MemoryBuffer **inputMemoryBuffers,
- ReadBufferOperation *reader)
+cl_mem OpenCLDevice::COM_cl_attach_memory_buffer_to_kernel_parameter(
+ cl_kernel kernel,
+ int parameter_index,
+ int offset_index,
+ std::list<cl_mem> *cleanup,
+ MemoryBuffer **input_memory_buffers,
+ ReadBufferOperation *reader)
{
cl_int error;
- MemoryBuffer *result = reader->getInputMemoryBuffer(inputMemoryBuffers);
+ MemoryBuffer *result = reader->get_input_memory_buffer(input_memory_buffers);
- const cl_image_format *imageFormat = determineImageFormat(result);
+ const cl_image_format *image_format = determine_image_format(result);
- cl_mem clBuffer = clCreateImage2D(this->m_context,
- CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
- imageFormat,
- result->getWidth(),
- result->getHeight(),
- 0,
- result->getBuffer(),
- &error);
+ cl_mem cl_buffer = clCreateImage2D(context_,
+ CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
+ image_format,
+ result->get_width(),
+ result->get_height(),
+ 0,
+ result->get_buffer(),
+ &error);
if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
if (error == CL_SUCCESS) {
- cleanup->push_back(clBuffer);
+ cleanup->push_back(cl_buffer);
}
- error = clSetKernelArg(kernel, parameterIndex, sizeof(cl_mem), &clBuffer);
+ error = clSetKernelArg(kernel, parameter_index, sizeof(cl_mem), &cl_buffer);
if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
- COM_clAttachMemoryBufferOffsetToKernelParameter(kernel, offsetIndex, result);
- return clBuffer;
+ COM_cl_attach_memory_buffer_offset_to_kernel_parameter(kernel, offset_index, result);
+ return cl_buffer;
}
-void OpenCLDevice::COM_clAttachMemoryBufferOffsetToKernelParameter(cl_kernel kernel,
- int offsetIndex,
- MemoryBuffer *memoryBuffer)
+void OpenCLDevice::COM_cl_attach_memory_buffer_offset_to_kernel_parameter(
+ cl_kernel kernel, int offset_index, MemoryBuffer *memory_buffer)
{
- if (offsetIndex != -1) {
+ if (offset_index != -1) {
cl_int error;
- const rcti &rect = memoryBuffer->get_rect();
+ const rcti &rect = memory_buffer->get_rect();
cl_int2 offset = {{rect.xmin, rect.ymin}};
- error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset);
+ error = clSetKernelArg(kernel, offset_index, sizeof(cl_int2), &offset);
if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
}
}
-void OpenCLDevice::COM_clAttachSizeToKernelParameter(cl_kernel kernel,
- int offsetIndex,
- NodeOperation *operation)
+void OpenCLDevice::COM_cl_attach_size_to_kernel_parameter(cl_kernel kernel,
+ int offset_index,
+ NodeOperation *operation)
{
- if (offsetIndex != -1) {
+ if (offset_index != -1) {
cl_int error;
- cl_int2 offset = {{(cl_int)operation->getWidth(), (cl_int)operation->getHeight()}};
+ cl_int2 offset = {{(cl_int)operation->get_width(), (cl_int)operation->get_height()}};
- error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset);
+ error = clSetKernelArg(kernel, offset_index, sizeof(cl_int2), &offset);
if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
}
}
-void OpenCLDevice::COM_clAttachOutputMemoryBufferToKernelParameter(cl_kernel kernel,
- int parameterIndex,
- cl_mem clOutputMemoryBuffer)
+void OpenCLDevice::COM_cl_attach_output_memory_buffer_to_kernel_parameter(
+ cl_kernel kernel, int parameter_index, cl_mem cl_output_memory_buffer)
{
cl_int error;
- error = clSetKernelArg(kernel, parameterIndex, sizeof(cl_mem), &clOutputMemoryBuffer);
+ error = clSetKernelArg(kernel, parameter_index, sizeof(cl_mem), &cl_output_memory_buffer);
if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
}
-void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, MemoryBuffer *outputMemoryBuffer)
+void OpenCLDevice::COM_cl_enqueue_range(cl_kernel kernel, MemoryBuffer *output_memory_buffer)
{
cl_int error;
const size_t size[] = {
- (size_t)outputMemoryBuffer->getWidth(),
- (size_t)outputMemoryBuffer->getHeight(),
+ (size_t)output_memory_buffer->get_width(),
+ (size_t)output_memory_buffer->get_height(),
};
- error = clEnqueueNDRangeKernel(
- this->m_queue, kernel, 2, nullptr, size, nullptr, 0, nullptr, nullptr);
+ error = clEnqueueNDRangeKernel(queue_, kernel, 2, nullptr, size, nullptr, 0, nullptr, nullptr);
if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
}
-void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel,
- MemoryBuffer *outputMemoryBuffer,
- int offsetIndex,
- NodeOperation *operation)
+void OpenCLDevice::COM_cl_enqueue_range(cl_kernel kernel,
+ MemoryBuffer *output_memory_buffer,
+ int offset_index,
+ NodeOperation *operation)
{
cl_int error;
- const int width = outputMemoryBuffer->getWidth();
- const int height = outputMemoryBuffer->getHeight();
+ const int width = output_memory_buffer->get_width();
+ const int height = output_memory_buffer->get_height();
int offsetx;
int offsety;
- int localSize = 1024;
+ int local_size = 1024;
size_t size[2];
cl_int2 offset;
- if (this->m_vendorID == NVIDIA) {
- localSize = 32;
+ if (vendor_id_ == NVIDIA) {
+ local_size = 32;
}
bool breaked = false;
- for (offsety = 0; offsety < height && (!breaked); offsety += localSize) {
+ for (offsety = 0; offsety < height && (!breaked); offsety += local_size) {
offset.s[1] = offsety;
- if (offsety + localSize < height) {
- size[1] = localSize;
+ if (offsety + local_size < height) {
+ size[1] = local_size;
}
else {
size[1] = height - offsety;
}
- for (offsetx = 0; offsetx < width && (!breaked); offsetx += localSize) {
- if (offsetx + localSize < width) {
- size[0] = localSize;
+ for (offsetx = 0; offsetx < width && (!breaked); offsetx += local_size) {
+ if (offsetx + local_size < width) {
+ size[0] = local_size;
}
else {
size[0] = width - offsetx;
}
offset.s[0] = offsetx;
- error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset);
+ error = clSetKernelArg(kernel, offset_index, sizeof(cl_int2), &offset);
if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
error = clEnqueueNDRangeKernel(
- this->m_queue, kernel, 2, nullptr, size, nullptr, 0, nullptr, nullptr);
+ queue_, kernel, 2, nullptr, size, nullptr, 0, nullptr, nullptr);
if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
- clFlush(this->m_queue);
- if (operation->isBraked()) {
+ clFlush(queue_);
+ if (operation->is_braked()) {
breaked = false;
}
}
}
}
-cl_kernel OpenCLDevice::COM_clCreateKernel(const char *kernelname,
- std::list<cl_kernel> *clKernelsToCleanUp)
+cl_kernel OpenCLDevice::COM_cl_create_kernel(const char *kernelname,
+ std::list<cl_kernel> *cl_kernels_to_clean_up)
{
cl_int error;
- cl_kernel kernel = clCreateKernel(this->m_program, kernelname, &error);
+ cl_kernel kernel = clCreateKernel(program_, kernelname, &error);
if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
else {
- if (clKernelsToCleanUp) {
- clKernelsToCleanUp->push_back(kernel);
+ if (cl_kernels_to_clean_up) {
+ cl_kernels_to_clean_up->push_back(kernel);
}
}
return kernel;
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h
index 826b0457a49..44a25747407 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.h
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.h
@@ -20,13 +20,20 @@ class OpenCLDevice;
#pragma once
+#include <list>
+
#include "COM_Device.h"
-#include "COM_ReadBufferOperation.h"
-#include "COM_WorkScheduler.h"
+
#include "clew.h"
namespace blender::compositor {
+class NodeOperation;
+class MemoryBuffer;
+class ReadBufferOperation;
+
+typedef NodeOperation SocketReader;
+
/**
* \brief device representing an GPU OpenCL device.
* an instance of this class represents a single cl_device
@@ -36,27 +43,27 @@ class OpenCLDevice : public Device {
/**
* \brief opencl context
*/
- cl_context m_context;
+ cl_context context_;
/**
* \brief opencl device
*/
- cl_device_id m_device;
+ cl_device_id device_;
/**
* \brief opencl program
*/
- cl_program m_program;
+ cl_program program_;
/**
* \brief opencl command queue
*/
- cl_command_queue m_queue;
+ cl_command_queue queue_;
/**
* \brief opencl vendor ID
*/
- cl_int m_vendorID;
+ cl_int vendor_id_;
public:
/**
@@ -66,7 +73,7 @@ class OpenCLDevice : public Device {
* \param program:
* \param vendorID:
*/
- OpenCLDevice(cl_context context, cl_device_id device, cl_program program, cl_int vendorId);
+ OpenCLDevice(cl_context context, cl_device_id device, cl_program program, cl_int vendor_id);
OpenCLDevice(OpenCLDevice &&other) noexcept;
@@ -82,45 +89,46 @@ class OpenCLDevice : public Device {
* \brief determine an image format
* \param memorybuffer:
*/
- static const cl_image_format *determineImageFormat(MemoryBuffer *memoryBuffer);
+ static const cl_image_format *determine_image_format(MemoryBuffer *memory_buffer);
- cl_context getContext()
+ cl_context get_context()
{
- return this->m_context;
+ return context_;
}
- cl_command_queue getQueue()
+ cl_command_queue get_queue()
{
- return this->m_queue;
+ return queue_;
}
- cl_mem COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel,
- int parameterIndex,
- int offsetIndex,
- std::list<cl_mem> *cleanup,
- MemoryBuffer **inputMemoryBuffers,
- SocketReader *reader);
- cl_mem COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel,
- int parameterIndex,
- int offsetIndex,
- std::list<cl_mem> *cleanup,
- MemoryBuffer **inputMemoryBuffers,
- ReadBufferOperation *reader);
- void COM_clAttachMemoryBufferOffsetToKernelParameter(cl_kernel kernel,
- int offsetIndex,
- MemoryBuffer *memoryBuffers);
- void COM_clAttachOutputMemoryBufferToKernelParameter(cl_kernel kernel,
- int parameterIndex,
- cl_mem clOutputMemoryBuffer);
- void COM_clAttachSizeToKernelParameter(cl_kernel kernel,
- int offsetIndex,
- NodeOperation *operation);
- void COM_clEnqueueRange(cl_kernel kernel, MemoryBuffer *outputMemoryBuffer);
- void COM_clEnqueueRange(cl_kernel kernel,
- MemoryBuffer *outputMemoryBuffer,
- int offsetIndex,
- NodeOperation *operation);
- cl_kernel COM_clCreateKernel(const char *kernelname, std::list<cl_kernel> *clKernelsToCleanUp);
+ cl_mem COM_cl_attach_memory_buffer_to_kernel_parameter(cl_kernel kernel,
+ int parameter_index,
+ int offset_index,
+ std::list<cl_mem> *cleanup,
+ MemoryBuffer **input_memory_buffers,
+ SocketReader *reader);
+ cl_mem COM_cl_attach_memory_buffer_to_kernel_parameter(cl_kernel kernel,
+ int parameter_index,
+ int offset_index,
+ std::list<cl_mem> *cleanup,
+ MemoryBuffer **input_memory_buffers,
+ ReadBufferOperation *reader);
+ void COM_cl_attach_memory_buffer_offset_to_kernel_parameter(cl_kernel kernel,
+ int offset_index,
+ MemoryBuffer *memory_buffers);
+ void COM_cl_attach_output_memory_buffer_to_kernel_parameter(cl_kernel kernel,
+ int parameter_index,
+ cl_mem cl_output_memory_buffer);
+ void COM_cl_attach_size_to_kernel_parameter(cl_kernel kernel,
+ int offset_index,
+ NodeOperation *operation);
+ void COM_cl_enqueue_range(cl_kernel kernel, MemoryBuffer *output_memory_buffer);
+ void COM_cl_enqueue_range(cl_kernel kernel,
+ MemoryBuffer *output_memory_buffer,
+ int offset_index,
+ NodeOperation *operation);
+ cl_kernel COM_cl_create_kernel(const char *kernelname,
+ std::list<cl_kernel> *cl_kernels_to_clean_up);
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_SharedOperationBuffers.cc b/source/blender/compositor/intern/COM_SharedOperationBuffers.cc
index 55153bd4f0a..567b5e0ee53 100644
--- a/source/blender/compositor/intern/COM_SharedOperationBuffers.cc
+++ b/source/blender/compositor/intern/COM_SharedOperationBuffers.cc
@@ -17,7 +17,6 @@
*/
#include "COM_SharedOperationBuffers.h"
-#include "BLI_rect.h"
#include "COM_NodeOperation.h"
namespace blender::compositor {
@@ -32,13 +31,11 @@ SharedOperationBuffers::BufferData &SharedOperationBuffers::get_buffer_data(Node
return buffers_.lookup_or_add_cb(op, []() { return BufferData(); });
}
-/**
- * Whether given operation area to render is already registered.
- * TODO: Possibly refactor to "request_area". Current implementation is incomplete: partial
- * overlapping, etc. Leading to more rendering than necessary.
- */
bool SharedOperationBuffers::is_area_registered(NodeOperation *op, const rcti &area_to_render)
{
+ /* TODO: Possibly refactor to "request_area". Current implementation is incomplete:
+ * partial overlapping, etc. Leading to more rendering than necessary. */
+
BufferData &buf_data = get_buffer_data(op);
for (rcti &reg_rect : buf_data.render_areas) {
if (BLI_rcti_inside_rcti(&reg_rect, &area_to_render)) {
@@ -48,34 +45,21 @@ bool SharedOperationBuffers::is_area_registered(NodeOperation *op, const rcti &a
return false;
}
-/**
- * Registers an operation area to render.
- */
void SharedOperationBuffers::register_area(NodeOperation *op, const rcti &area_to_render)
{
get_buffer_data(op).render_areas.append(area_to_render);
}
-/**
- * Whether given operation has any registered reads (other operation registered it depends on given
- * operation).
- */
bool SharedOperationBuffers::has_registered_reads(NodeOperation *op)
{
return get_buffer_data(op).registered_reads > 0;
}
-/**
- * Registers an operation read (other operation depends on given operation).
- */
void SharedOperationBuffers::register_read(NodeOperation *read_op)
{
get_buffer_data(read_op).registered_reads++;
}
-/**
- * Get registered areas given operation needs to render.
- */
Vector<rcti> SharedOperationBuffers::get_areas_to_render(NodeOperation *op,
const int offset_x,
const int offset_y)
@@ -89,17 +73,11 @@ Vector<rcti> SharedOperationBuffers::get_areas_to_render(NodeOperation *op,
return dst_areas;
}
-/**
- * Whether this operation buffer has already been rendered.
- */
bool SharedOperationBuffers::is_operation_rendered(NodeOperation *op)
{
return get_buffer_data(op).is_rendered;
}
-/**
- * Stores given operation rendered buffer.
- */
void SharedOperationBuffers::set_rendered_buffer(NodeOperation *op,
std::unique_ptr<MemoryBuffer> buffer)
{
@@ -110,19 +88,12 @@ void SharedOperationBuffers::set_rendered_buffer(NodeOperation *op,
buf_data.is_rendered = true;
}
-/**
- * Get given operation rendered buffer.
- */
MemoryBuffer *SharedOperationBuffers::get_rendered_buffer(NodeOperation *op)
{
BLI_assert(is_operation_rendered(op));
return get_buffer_data(op).buffer.get();
}
-/**
- * Reports an operation has finished reading given operation. If all given operation dependencies
- * have finished its buffer will be disposed.
- */
void SharedOperationBuffers::read_finished(NodeOperation *read_op)
{
BufferData &buf_data = get_buffer_data(read_op);
diff --git a/source/blender/compositor/intern/COM_SharedOperationBuffers.h b/source/blender/compositor/intern/COM_SharedOperationBuffers.h
index 4461ba75cbe..fd053fce02f 100644
--- a/source/blender/compositor/intern/COM_SharedOperationBuffers.h
+++ b/source/blender/compositor/intern/COM_SharedOperationBuffers.h
@@ -19,16 +19,19 @@
#pragma once
#include "BLI_map.hh"
-#include "BLI_span.hh"
#include "BLI_vector.hh"
-#include "COM_MemoryBuffer.h"
+
+#include "DNA_vec_types.h"
+
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
-#include <memory>
namespace blender::compositor {
+class MemoryBuffer;
+class NodeOperation;
+
/**
* Stores and shares operations rendered buffers including render data. Buffers are
* disposed once all dependent operations have finished reading them.
@@ -47,17 +50,46 @@ class SharedOperationBuffers {
blender::Map<NodeOperation *, BufferData> buffers_;
public:
+ /**
+ * Whether given operation area to render is already registered.
+ */
bool is_area_registered(NodeOperation *op, const rcti &area_to_render);
+ /**
+ * Registers an operation area to render.
+ */
void register_area(NodeOperation *op, const rcti &area_to_render);
+ /**
+ * Whether given operation has any registered reads (other operation registered it depends on
+ * given operation).
+ */
bool has_registered_reads(NodeOperation *op);
+ /**
+ * Registers an operation read (other operation depends on given operation).
+ */
void register_read(NodeOperation *read_op);
+ /**
+ * Get registered areas given operation needs to render.
+ */
Vector<rcti> get_areas_to_render(NodeOperation *op, int offset_x, int offset_y);
+ /**
+ * Whether this operation buffer has already been rendered.
+ */
bool is_operation_rendered(NodeOperation *op);
+ /**
+ * Stores given operation rendered buffer.
+ */
void set_rendered_buffer(NodeOperation *op, std::unique_ptr<MemoryBuffer> buffer);
+ /**
+ * Get given operation rendered buffer.
+ */
MemoryBuffer *get_rendered_buffer(NodeOperation *op);
+ /**
+ * Reports an operation has finished reading given operation. If all given operation dependencies
+ * have finished its buffer will be disposed.
+ */
void read_finished(NodeOperation *read_op);
private:
diff --git a/source/blender/compositor/intern/COM_SingleThreadedOperation.cc b/source/blender/compositor/intern/COM_SingleThreadedOperation.cc
index 01be6e1afed..5ad324459fd 100644
--- a/source/blender/compositor/intern/COM_SingleThreadedOperation.cc
+++ b/source/blender/compositor/intern/COM_SingleThreadedOperation.cc
@@ -22,42 +22,42 @@ namespace blender::compositor {
SingleThreadedOperation::SingleThreadedOperation()
{
- this->m_cachedInstance = nullptr;
- flags.complex = true;
- flags.single_threaded = true;
+ cached_instance_ = nullptr;
+ flags_.complex = true;
+ flags_.single_threaded = true;
}
-void SingleThreadedOperation::initExecution()
+void SingleThreadedOperation::init_execution()
{
- initMutex();
+ init_mutex();
}
-void SingleThreadedOperation::executePixel(float output[4], int x, int y, void * /*data*/)
+void SingleThreadedOperation::execute_pixel(float output[4], int x, int y, void * /*data*/)
{
- this->m_cachedInstance->readNoCheck(output, x, y);
+ cached_instance_->read_no_check(output, x, y);
}
-void SingleThreadedOperation::deinitExecution()
+void SingleThreadedOperation::deinit_execution()
{
- deinitMutex();
- if (this->m_cachedInstance) {
- delete this->m_cachedInstance;
- this->m_cachedInstance = nullptr;
+ deinit_mutex();
+ if (cached_instance_) {
+ delete cached_instance_;
+ cached_instance_ = nullptr;
}
}
-void *SingleThreadedOperation::initializeTileData(rcti *rect)
+void *SingleThreadedOperation::initialize_tile_data(rcti *rect)
{
- if (this->m_cachedInstance) {
- return this->m_cachedInstance;
+ if (cached_instance_) {
+ return cached_instance_;
}
- lockMutex();
- if (this->m_cachedInstance == nullptr) {
+ lock_mutex();
+ if (cached_instance_ == nullptr) {
//
- this->m_cachedInstance = createMemoryBuffer(rect);
+ cached_instance_ = create_memory_buffer(rect);
}
- unlockMutex();
- return this->m_cachedInstance;
+ unlock_mutex();
+ return cached_instance_;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_SingleThreadedOperation.h b/source/blender/compositor/intern/COM_SingleThreadedOperation.h
index 9945f938ff9..7588e654f75 100644
--- a/source/blender/compositor/intern/COM_SingleThreadedOperation.h
+++ b/source/blender/compositor/intern/COM_SingleThreadedOperation.h
@@ -24,12 +24,12 @@ namespace blender::compositor {
class SingleThreadedOperation : public NodeOperation {
private:
- MemoryBuffer *m_cachedInstance;
+ MemoryBuffer *cached_instance_;
protected:
- inline bool isCached()
+ inline bool is_cached()
{
- return this->m_cachedInstance != nullptr;
+ return cached_instance_ != nullptr;
}
public:
@@ -38,21 +38,21 @@ class SingleThreadedOperation : public NodeOperation {
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
- virtual MemoryBuffer *createMemoryBuffer(rcti *rect) = 0;
+ virtual MemoryBuffer *create_memory_buffer(rcti *rect) = 0;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_TiledExecutionModel.cc b/source/blender/compositor/intern/COM_TiledExecutionModel.cc
index a081b80349d..e9f7310cead 100644
--- a/source/blender/compositor/intern/COM_TiledExecutionModel.cc
+++ b/source/blender/compositor/intern/COM_TiledExecutionModel.cc
@@ -35,24 +35,24 @@ TiledExecutionModel::TiledExecutionModel(CompositorContext &context,
Span<ExecutionGroup *> groups)
: ExecutionModel(context, operations), groups_(groups)
{
- const bNodeTree *node_tree = context.getbNodeTree();
+ const bNodeTree *node_tree = context.get_bnodetree();
node_tree->stats_draw(node_tree->sdh, TIP_("Compositing | Determining resolution"));
unsigned int resolution[2];
for (ExecutionGroup *group : groups_) {
resolution[0] = 0;
resolution[1] = 0;
- group->determineResolution(resolution);
+ group->determine_resolution(resolution);
if (border_.use_render_border) {
const rctf *render_border = border_.render_border;
- group->setRenderBorder(
+ group->set_render_border(
render_border->xmin, render_border->xmax, render_border->ymin, render_border->ymax);
}
if (border_.use_viewer_border) {
const rctf *viewer_border = border_.viewer_border;
- group->setViewerBorder(
+ group->set_viewer_border(
viewer_border->xmin, viewer_border->xmax, viewer_border->ymin, viewer_border->ymax);
}
}
@@ -63,8 +63,8 @@ static void update_read_buffer_offset(Span<NodeOperation *> operations)
unsigned int order = 0;
for (NodeOperation *operation : operations) {
if (operation->get_flags().is_read_buffer_operation) {
- ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
- readOperation->setOffset(order);
+ ReadBufferOperation *read_operation = (ReadBufferOperation *)operation;
+ read_operation->set_offset(order);
order++;
}
}
@@ -75,8 +75,8 @@ static void init_write_operations_for_execution(Span<NodeOperation *> operations
{
for (NodeOperation *operation : operations) {
if (operation->get_flags().is_write_buffer_operation) {
- operation->setbNodeTree(bTree);
- operation->initExecution();
+ operation->set_bnodetree(bTree);
+ operation->init_execution();
}
}
}
@@ -85,8 +85,8 @@ static void link_write_buffers(Span<NodeOperation *> operations)
{
for (NodeOperation *operation : operations) {
if (operation->get_flags().is_read_buffer_operation) {
- ReadBufferOperation *readOperation = static_cast<ReadBufferOperation *>(operation);
- readOperation->updateMemoryBuffer();
+ ReadBufferOperation *read_operation = static_cast<ReadBufferOperation *>(operation);
+ read_operation->update_memory_buffer();
}
}
}
@@ -96,8 +96,8 @@ static void init_non_write_operations_for_execution(Span<NodeOperation *> operat
{
for (NodeOperation *operation : operations) {
if (!operation->get_flags().is_write_buffer_operation) {
- operation->setbNodeTree(bTree);
- operation->initExecution();
+ operation->set_bnodetree(bTree);
+ operation->init_execution();
}
}
}
@@ -106,27 +106,27 @@ static void init_execution_groups_for_execution(Span<ExecutionGroup *> groups,
const int chunk_size)
{
for (ExecutionGroup *execution_group : groups) {
- execution_group->setChunksize(chunk_size);
- execution_group->initExecution();
+ execution_group->set_chunksize(chunk_size);
+ execution_group->init_execution();
}
}
void TiledExecutionModel::execute(ExecutionSystem &exec_system)
{
- const bNodeTree *editingtree = this->context_.getbNodeTree();
+ const bNodeTree *editingtree = this->context_.get_bnodetree();
editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | Initializing execution"));
update_read_buffer_offset(operations_);
- init_write_operations_for_execution(operations_, context_.getbNodeTree());
+ init_write_operations_for_execution(operations_, context_.get_bnodetree());
link_write_buffers(operations_);
- init_non_write_operations_for_execution(operations_, context_.getbNodeTree());
- init_execution_groups_for_execution(groups_, context_.getChunksize());
+ init_non_write_operations_for_execution(operations_, context_.get_bnodetree());
+ init_execution_groups_for_execution(groups_, context_.get_chunksize());
WorkScheduler::start(context_);
execute_groups(eCompositorPriority::High, exec_system);
- if (!context_.isFastCalculation()) {
+ if (!context_.is_fast_calculation()) {
execute_groups(eCompositorPriority::Medium, exec_system);
execute_groups(eCompositorPriority::Low, exec_system);
}
@@ -136,11 +136,11 @@ void TiledExecutionModel::execute(ExecutionSystem &exec_system)
editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | De-initializing execution"));
for (NodeOperation *operation : operations_) {
- operation->deinitExecution();
+ operation->deinit_execution();
}
for (ExecutionGroup *execution_group : groups_) {
- execution_group->deinitExecution();
+ execution_group->deinit_execution();
}
}
@@ -149,7 +149,7 @@ void TiledExecutionModel::execute_groups(eCompositorPriority priority,
{
for (ExecutionGroup *execution_group : groups_) {
if (execution_group->get_flags().is_output &&
- execution_group->getRenderPriority() == priority) {
+ execution_group->get_render_priority() == priority) {
execution_group->execute(&exec_system);
}
}
diff --git a/source/blender/compositor/intern/COM_TiledExecutionModel.h b/source/blender/compositor/intern/COM_TiledExecutionModel.h
index 05a795b9f07..1f5345241e2 100644
--- a/source/blender/compositor/intern/COM_TiledExecutionModel.h
+++ b/source/blender/compositor/intern/COM_TiledExecutionModel.h
@@ -18,6 +18,7 @@
#pragma once
+#include "COM_Enums.h"
#include "COM_ExecutionModel.h"
#ifdef WITH_CXX_GUARDEDALLOC
diff --git a/source/blender/compositor/intern/COM_WorkPackage.cc b/source/blender/compositor/intern/COM_WorkPackage.cc
index ea78c0d6333..7db44226574 100644
--- a/source/blender/compositor/intern/COM_WorkPackage.cc
+++ b/source/blender/compositor/intern/COM_WorkPackage.cc
@@ -18,7 +18,6 @@
#include "COM_WorkPackage.h"
-#include "COM_Enums.h"
#include "COM_ExecutionGroup.h"
namespace blender::compositor {
diff --git a/source/blender/compositor/intern/COM_WorkPackage.h b/source/blender/compositor/intern/COM_WorkPackage.h
index 20fca89aa4c..1fe50b9ecf3 100644
--- a/source/blender/compositor/intern/COM_WorkPackage.h
+++ b/source/blender/compositor/intern/COM_WorkPackage.h
@@ -24,7 +24,7 @@
#include "COM_Enums.h"
-#include "BLI_rect.h"
+#include "DNA_vec_types.h"
#include <functional>
#include <ostream>
@@ -43,7 +43,7 @@ struct WorkPackage {
eWorkPackageState state = eWorkPackageState::NotScheduled;
/**
- * \brief executionGroup with the operations-setup to be evaluated
+ * \brief execution_group with the operations-setup to be evaluated
*/
ExecutionGroup *execution_group;
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cc b/source/blender/compositor/intern/COM_WorkScheduler.cc
index a08f9dd284c..c88cc556e72 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cc
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cc
@@ -16,15 +16,14 @@
* Copyright 2011, Blender Foundation.
*/
-#include <cstdio>
-#include <list>
+#include "COM_WorkScheduler.h"
#include "COM_CPUDevice.h"
+#include "COM_CompositorContext.h"
+#include "COM_ExecutionGroup.h"
#include "COM_OpenCLDevice.h"
#include "COM_OpenCLKernels.cl.h"
-#include "COM_WorkScheduler.h"
#include "COM_WriteBufferOperation.h"
-#include "COM_compositor.h"
#include "clew.h"
@@ -33,7 +32,6 @@
#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_vector.hh"
-#include "PIL_time.h"
#include "BKE_global.h"
@@ -106,10 +104,10 @@ static struct {
/** \name OpenCL Scheduling
* \{ */
-static void CL_CALLBACK clContextError(const char *errinfo,
- const void * /*private_info*/,
- size_t /*cb*/,
- void * /*user_data*/)
+static void CL_CALLBACK cl_context_error(const char *errinfo,
+ const void * /*private_info*/,
+ size_t /*cb*/,
+ void * /*user_data*/)
{
printf("OPENCL error: %s\n", errinfo);
}
@@ -128,7 +126,7 @@ static void *thread_execute_gpu(void *data)
static void opencl_start(const CompositorContext &context)
{
- if (context.getHasActiveOpenCLDevices()) {
+ if (context.get_has_active_opencl_devices()) {
g_work_scheduler.opencl.queue = BLI_thread_queue_init();
BLI_threadpool_init(&g_work_scheduler.opencl.threads,
thread_execute_gpu,
@@ -188,35 +186,35 @@ static void opencl_initialize(const bool use_opencl)
}
if (clCreateContextFromType) {
- cl_uint numberOfPlatforms = 0;
+ cl_uint number_of_platforms = 0;
cl_int error;
- error = clGetPlatformIDs(0, nullptr, &numberOfPlatforms);
+ error = clGetPlatformIDs(0, nullptr, &number_of_platforms);
if (error == -1001) {
} /* GPU not supported */
else if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
if (G.f & G_DEBUG) {
- printf("%u number of platforms\n", numberOfPlatforms);
+ printf("%u number of platforms\n", number_of_platforms);
}
cl_platform_id *platforms = (cl_platform_id *)MEM_mallocN(
- sizeof(cl_platform_id) * numberOfPlatforms, __func__);
- error = clGetPlatformIDs(numberOfPlatforms, platforms, nullptr);
- unsigned int indexPlatform;
- for (indexPlatform = 0; indexPlatform < numberOfPlatforms; indexPlatform++) {
- cl_platform_id platform = platforms[indexPlatform];
- cl_uint numberOfDevices = 0;
- clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, nullptr, &numberOfDevices);
- if (numberOfDevices <= 0) {
+ sizeof(cl_platform_id) * number_of_platforms, __func__);
+ error = clGetPlatformIDs(number_of_platforms, platforms, nullptr);
+ unsigned int index_platform;
+ for (index_platform = 0; index_platform < number_of_platforms; index_platform++) {
+ cl_platform_id platform = platforms[index_platform];
+ cl_uint number_of_devices = 0;
+ clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, nullptr, &number_of_devices);
+ if (number_of_devices <= 0) {
continue;
}
cl_device_id *cldevices = (cl_device_id *)MEM_mallocN(
- sizeof(cl_device_id) * numberOfDevices, __func__);
- clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, numberOfDevices, cldevices, nullptr);
+ sizeof(cl_device_id) * number_of_devices, __func__);
+ clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, number_of_devices, cldevices, nullptr);
g_work_scheduler.opencl.context = clCreateContext(
- nullptr, numberOfDevices, cldevices, clContextError, nullptr, &error);
+ nullptr, number_of_devices, cldevices, cl_context_error, nullptr, &error);
if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
@@ -224,7 +222,7 @@ static void opencl_initialize(const bool use_opencl)
g_work_scheduler.opencl.program = clCreateProgramWithSource(
g_work_scheduler.opencl.context, 1, cl_str, nullptr, &error);
error = clBuildProgram(g_work_scheduler.opencl.program,
- numberOfDevices,
+ number_of_devices,
cldevices,
nullptr,
nullptr,
@@ -257,9 +255,9 @@ static void opencl_initialize(const bool use_opencl)
MEM_freeN(build_log);
}
else {
- unsigned int indexDevices;
- for (indexDevices = 0; indexDevices < numberOfDevices; indexDevices++) {
- cl_device_id device = cldevices[indexDevices];
+ unsigned int index_devices;
+ for (index_devices = 0; index_devices < number_of_devices; index_devices++) {
+ cl_device_id device = cldevices[index_devices];
cl_int vendorID = 0;
cl_int error2 = clGetDeviceInfo(
device, CL_DEVICE_VENDOR_ID, sizeof(cl_int), &vendorID, nullptr);
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.h b/source/blender/compositor/intern/COM_WorkScheduler.h
index 297943aa63b..dfba5a03256 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.h
+++ b/source/blender/compositor/intern/COM_WorkScheduler.h
@@ -18,14 +18,16 @@
#pragma once
-#include "COM_ExecutionGroup.h"
-
-#include "COM_Device.h"
-#include "COM_WorkPackage.h"
-#include "COM_defines.h"
+#ifdef WITH_CXX_GUARDEDALLOC
+# include "MEM_guardedalloc.h"
+#endif
namespace blender::compositor {
+struct WorkPackage;
+
+class CompositorContext;
+
/** \brief the workscheduler
* \ingroup execution
*/
@@ -83,7 +85,7 @@ struct WorkScheduler {
* \brief Are there OpenCL capable GPU devices initialized?
* the result of this method is stored in the CompositorContext
* A node can generate a different operation tree when OpenCLDevices exists.
- * \see CompositorContext.getHasActiveOpenCLDevices
+ * \see CompositorContext.get_has_active_opencl_devices
*/
static bool has_gpu_devices();
diff --git a/source/blender/compositor/intern/COM_compositor.cc b/source/blender/compositor/intern/COM_compositor.cc
index c05234f3bd0..5c9b34c4772 100644
--- a/source/blender/compositor/intern/COM_compositor.cc
+++ b/source/blender/compositor/intern/COM_compositor.cc
@@ -24,10 +24,8 @@
#include "BKE_scene.h"
#include "COM_ExecutionSystem.h"
-#include "COM_MovieDistortionOperation.h"
#include "COM_WorkScheduler.h"
#include "COM_compositor.h"
-#include "clew.h"
static struct {
bool is_initialized = false;
@@ -53,7 +51,7 @@ static void compositor_init_node_previews(const RenderData *render_data, bNodeTr
preview_width = (int)(blender::compositor::COM_PREVIEW_SIZE / aspect);
preview_height = blender::compositor::COM_PREVIEW_SIZE;
}
- BKE_node_preview_init_tree(node_tree, preview_width, preview_height, false);
+ BKE_node_preview_init_tree(node_tree, preview_width, preview_height);
}
static void compositor_reset_node_tree_status(bNodeTree *node_tree)
@@ -66,9 +64,9 @@ void COM_execute(RenderData *render_data,
Scene *scene,
bNodeTree *node_tree,
int rendering,
- const ColorManagedViewSettings *viewSettings,
- const ColorManagedDisplaySettings *displaySettings,
- const char *viewName)
+ const ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ const char *view_name)
{
/* Initialize mutex, TODO: this mutex init is actually not thread safe and
* should be done somewhere as part of blender startup, all the other
@@ -97,8 +95,14 @@ void COM_execute(RenderData *render_data,
/* Execute. */
const bool twopass = (node_tree->flag & NTREE_TWO_PASS) && !rendering;
if (twopass) {
- blender::compositor::ExecutionSystem fast_pass(
- render_data, scene, node_tree, rendering, true, viewSettings, displaySettings, viewName);
+ blender::compositor::ExecutionSystem fast_pass(render_data,
+ scene,
+ node_tree,
+ rendering,
+ true,
+ view_settings,
+ display_settings,
+ view_name);
fast_pass.execute();
if (node_tree->test_break(node_tree->tbh)) {
@@ -108,7 +112,7 @@ void COM_execute(RenderData *render_data,
}
blender::compositor::ExecutionSystem system(
- render_data, scene, node_tree, rendering, false, viewSettings, displaySettings, viewName);
+ render_data, scene, node_tree, rendering, false, view_settings, display_settings, view_name);
system.execute();
BLI_mutex_unlock(&g_compositor.mutex);
diff --git a/source/blender/compositor/nodes/COM_AlphaOverNode.cc b/source/blender/compositor/nodes/COM_AlphaOverNode.cc
index c9038886b0d..42836d0a575 100644
--- a/source/blender/compositor/nodes/COM_AlphaOverNode.cc
+++ b/source/blender/compositor/nodes/COM_AlphaOverNode.cc
@@ -21,50 +21,46 @@
#include "COM_AlphaOverKeyOperation.h"
#include "COM_AlphaOverMixedOperation.h"
#include "COM_AlphaOverPremultiplyOperation.h"
-#include "COM_MixOperation.h"
-
-#include "COM_SetValueOperation.h"
-#include "DNA_material_types.h" /* the ramp types */
namespace blender::compositor {
-void AlphaOverNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void AlphaOverNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeInput *color1Socket = this->getInputSocket(1);
- NodeInput *color2Socket = this->getInputSocket(2);
- bNode *editorNode = this->getbNode();
+ NodeInput *color1Socket = this->get_input_socket(1);
+ NodeInput *color2Socket = this->get_input_socket(2);
+ bNode *editor_node = this->get_bnode();
- MixBaseOperation *convertProg;
- NodeTwoFloats *ntf = (NodeTwoFloats *)editorNode->storage;
+ MixBaseOperation *convert_prog;
+ NodeTwoFloats *ntf = (NodeTwoFloats *)editor_node->storage;
if (ntf->x != 0.0f) {
- AlphaOverMixedOperation *mixOperation = new AlphaOverMixedOperation();
- mixOperation->setX(ntf->x);
- convertProg = mixOperation;
+ AlphaOverMixedOperation *mix_operation = new AlphaOverMixedOperation();
+ mix_operation->setX(ntf->x);
+ convert_prog = mix_operation;
}
- else if (editorNode->custom1) {
- convertProg = new AlphaOverKeyOperation();
+ else if (editor_node->custom1) {
+ convert_prog = new AlphaOverKeyOperation();
}
else {
- convertProg = new AlphaOverPremultiplyOperation();
+ convert_prog = new AlphaOverPremultiplyOperation();
}
- convertProg->setUseValueAlphaMultiply(false);
- if (color1Socket->isLinked()) {
- convertProg->set_canvas_input_index(1);
+ convert_prog->set_use_value_alpha_multiply(false);
+ if (color1Socket->is_linked()) {
+ convert_prog->set_canvas_input_index(1);
}
- else if (color2Socket->isLinked()) {
- convertProg->set_canvas_input_index(2);
+ else if (color2Socket->is_linked()) {
+ convert_prog->set_canvas_input_index(2);
}
else {
- convertProg->set_canvas_input_index(0);
+ convert_prog->set_canvas_input_index(0);
}
- converter.addOperation(convertProg);
- converter.mapInputSocket(getInputSocket(0), convertProg->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), convertProg->getInputSocket(1));
- converter.mapInputSocket(getInputSocket(2), convertProg->getInputSocket(2));
- converter.mapOutputSocket(getOutputSocket(0), convertProg->getOutputSocket(0));
+ converter.add_operation(convert_prog);
+ converter.map_input_socket(get_input_socket(0), convert_prog->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), convert_prog->get_input_socket(1));
+ converter.map_input_socket(get_input_socket(2), convert_prog->get_input_socket(2));
+ converter.map_output_socket(get_output_socket(0), convert_prog->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_AlphaOverNode.h b/source/blender/compositor/nodes/COM_AlphaOverNode.h
index 201c8ed5b6e..447570fe604 100644
--- a/source/blender/compositor/nodes/COM_AlphaOverNode.h
+++ b/source/blender/compositor/nodes/COM_AlphaOverNode.h
@@ -28,11 +28,11 @@ namespace blender::compositor {
*/
class AlphaOverNode : public Node {
public:
- AlphaOverNode(bNode *editorNode) : Node(editorNode)
+ AlphaOverNode(bNode *editor_node) : Node(editor_node)
{
}
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_AntiAliasingNode.cc b/source/blender/compositor/nodes/COM_AntiAliasingNode.cc
index af4832665df..b11c57041d9 100644
--- a/source/blender/compositor/nodes/COM_AntiAliasingNode.cc
+++ b/source/blender/compositor/nodes/COM_AntiAliasingNode.cc
@@ -20,41 +20,40 @@
#include "COM_AntiAliasingNode.h"
#include "COM_SMAAOperation.h"
-#include "DNA_node_types.h"
namespace blender::compositor {
-void AntiAliasingNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void AntiAliasingNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *node = this->getbNode();
+ bNode *node = this->get_bnode();
NodeAntiAliasingData *data = (NodeAntiAliasingData *)node->storage;
/* Edge Detection (First Pass) */
SMAAEdgeDetectionOperation *operation1 = nullptr;
operation1 = new SMAAEdgeDetectionOperation();
- operation1->setThreshold(data->threshold);
- operation1->setLocalContrastAdaptationFactor(data->contrast_limit);
- converter.addOperation(operation1);
+ operation1->set_threshold(data->threshold);
+ operation1->set_local_contrast_adaptation_factor(data->contrast_limit);
+ converter.add_operation(operation1);
- converter.mapInputSocket(getInputSocket(0), operation1->getInputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation1->get_input_socket(0));
/* Blending Weight Calculation Pixel Shader (Second Pass) */
SMAABlendingWeightCalculationOperation *operation2 =
new SMAABlendingWeightCalculationOperation();
- operation2->setCornerRounding(data->corner_rounding);
- converter.addOperation(operation2);
+ operation2->set_corner_rounding(data->corner_rounding);
+ converter.add_operation(operation2);
- converter.addLink(operation1->getOutputSocket(), operation2->getInputSocket(0));
+ converter.add_link(operation1->get_output_socket(), operation2->get_input_socket(0));
/* Neighborhood Blending Pixel Shader (Third Pass) */
SMAANeighborhoodBlendingOperation *operation3 = new SMAANeighborhoodBlendingOperation();
- converter.addOperation(operation3);
+ converter.add_operation(operation3);
- converter.mapInputSocket(getInputSocket(0), operation3->getInputSocket(0));
- converter.addLink(operation2->getOutputSocket(), operation3->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(0), operation3->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), operation3->get_input_socket(0));
+ converter.add_link(operation2->get_output_socket(), operation3->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(0), operation3->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_AntiAliasingNode.h b/source/blender/compositor/nodes/COM_AntiAliasingNode.h
index 7d3dd750864..05c51d5856a 100644
--- a/source/blender/compositor/nodes/COM_AntiAliasingNode.h
+++ b/source/blender/compositor/nodes/COM_AntiAliasingNode.h
@@ -30,11 +30,11 @@ namespace blender::compositor {
*/
class AntiAliasingNode : public Node {
public:
- AntiAliasingNode(bNode *editorNode) : Node(editorNode)
+ AntiAliasingNode(bNode *editor_node) : Node(editor_node)
{
}
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_BilateralBlurNode.cc b/source/blender/compositor/nodes/COM_BilateralBlurNode.cc
index 1b9da789d3c..2390f6305b2 100644
--- a/source/blender/compositor/nodes/COM_BilateralBlurNode.cc
+++ b/source/blender/compositor/nodes/COM_BilateralBlurNode.cc
@@ -18,28 +18,26 @@
#include "COM_BilateralBlurNode.h"
#include "COM_BilateralBlurOperation.h"
-#include "COM_ExecutionSystem.h"
-#include "DNA_node_types.h"
namespace blender::compositor {
-BilateralBlurNode::BilateralBlurNode(bNode *editorNode) : Node(editorNode)
+BilateralBlurNode::BilateralBlurNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void BilateralBlurNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void BilateralBlurNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- NodeBilateralBlurData *data = (NodeBilateralBlurData *)this->getbNode()->storage;
+ NodeBilateralBlurData *data = (NodeBilateralBlurData *)this->get_bnode()->storage;
BilateralBlurOperation *operation = new BilateralBlurOperation();
- operation->setQuality(context.getQuality());
- operation->setData(data);
+ operation->set_quality(context.get_quality());
+ operation->set_data(data);
- converter.addOperation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.add_operation(operation);
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_BilateralBlurNode.h b/source/blender/compositor/nodes/COM_BilateralBlurNode.h
index fed2612ac02..6bef897f2ef 100644
--- a/source/blender/compositor/nodes/COM_BilateralBlurNode.h
+++ b/source/blender/compositor/nodes/COM_BilateralBlurNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class BilateralBlurNode : public Node {
public:
- BilateralBlurNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ BilateralBlurNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_BlurNode.cc b/source/blender/compositor/nodes/COM_BlurNode.cc
index c10bc2a05f0..97a7159de67 100644
--- a/source/blender/compositor/nodes/COM_BlurNode.cc
+++ b/source/blender/compositor/nodes/COM_BlurNode.cc
@@ -17,7 +17,6 @@
*/
#include "COM_BlurNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_FastGaussianBlurOperation.h"
#include "COM_GammaCorrectOperation.h"
#include "COM_GaussianAlphaXBlurOperation.h"
@@ -27,107 +26,106 @@
#include "COM_GaussianYBlurOperation.h"
#include "COM_MathBaseOperation.h"
#include "COM_SetValueOperation.h"
-#include "DNA_node_types.h"
namespace blender::compositor {
-BlurNode::BlurNode(bNode *editorNode) : Node(editorNode)
+BlurNode::BlurNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void BlurNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void BlurNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *editorNode = this->getbNode();
- NodeBlurData *data = (NodeBlurData *)editorNode->storage;
- NodeInput *inputSizeSocket = this->getInputSocket(1);
- bool connectedSizeSocket = inputSizeSocket->isLinked();
+ bNode *editor_node = this->get_bnode();
+ NodeBlurData *data = (NodeBlurData *)editor_node->storage;
+ NodeInput *input_size_socket = this->get_input_socket(1);
+ bool connected_size_socket = input_size_socket->is_linked();
- const float size = this->getInputSocket(1)->getEditorValueFloat();
- const bool extend_bounds = (editorNode->custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS) != 0;
+ const float size = this->get_input_socket(1)->get_editor_value_float();
+ const bool extend_bounds = (editor_node->custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS) != 0;
- eCompositorQuality quality = context.getQuality();
+ eCompositorQuality quality = context.get_quality();
NodeOperation *input_operation = nullptr, *output_operation = nullptr;
if (data->filtertype == R_FILTER_FAST_GAUSS) {
FastGaussianBlurOperation *operationfgb = new FastGaussianBlurOperation();
- operationfgb->setData(data);
- operationfgb->setExtendBounds(extend_bounds);
- converter.addOperation(operationfgb);
+ operationfgb->set_data(data);
+ operationfgb->set_extend_bounds(extend_bounds);
+ converter.add_operation(operationfgb);
- converter.mapInputSocket(getInputSocket(1), operationfgb->getInputSocket(1));
+ converter.map_input_socket(get_input_socket(1), operationfgb->get_input_socket(1));
input_operation = operationfgb;
output_operation = operationfgb;
}
- else if (editorNode->custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE) {
+ else if (editor_node->custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE) {
MathAddOperation *clamp = new MathAddOperation();
SetValueOperation *zero = new SetValueOperation();
- zero->setValue(0.0f);
- clamp->setUseClamp(true);
+ zero->set_value(0.0f);
+ clamp->set_use_clamp(true);
- converter.addOperation(clamp);
- converter.addOperation(zero);
- converter.mapInputSocket(getInputSocket(1), clamp->getInputSocket(0));
- converter.addLink(zero->getOutputSocket(), clamp->getInputSocket(1));
+ converter.add_operation(clamp);
+ converter.add_operation(zero);
+ converter.map_input_socket(get_input_socket(1), clamp->get_input_socket(0));
+ converter.add_link(zero->get_output_socket(), clamp->get_input_socket(1));
GaussianAlphaXBlurOperation *operationx = new GaussianAlphaXBlurOperation();
- operationx->setData(data);
- operationx->setQuality(quality);
- operationx->setSize(1.0f);
- operationx->setFalloff(PROP_SMOOTH);
- operationx->setSubtract(false);
- operationx->setExtendBounds(extend_bounds);
+ operationx->set_data(data);
+ operationx->set_quality(quality);
+ operationx->set_size(1.0f);
+ operationx->set_falloff(PROP_SMOOTH);
+ operationx->set_subtract(false);
+ operationx->set_extend_bounds(extend_bounds);
- converter.addOperation(operationx);
- converter.addLink(clamp->getOutputSocket(), operationx->getInputSocket(0));
+ converter.add_operation(operationx);
+ converter.add_link(clamp->get_output_socket(), operationx->get_input_socket(0));
GaussianAlphaYBlurOperation *operationy = new GaussianAlphaYBlurOperation();
- operationy->setData(data);
- operationy->setQuality(quality);
- operationy->setSize(1.0f);
- operationy->setFalloff(PROP_SMOOTH);
- operationy->setSubtract(false);
- operationy->setExtendBounds(extend_bounds);
+ operationy->set_data(data);
+ operationy->set_quality(quality);
+ operationy->set_size(1.0f);
+ operationy->set_falloff(PROP_SMOOTH);
+ operationy->set_subtract(false);
+ operationy->set_extend_bounds(extend_bounds);
- converter.addOperation(operationy);
- converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0));
+ converter.add_operation(operationy);
+ converter.add_link(operationx->get_output_socket(), operationy->get_input_socket(0));
GaussianBlurReferenceOperation *operation = new GaussianBlurReferenceOperation();
- operation->setData(data);
- operation->setQuality(quality);
- operation->setExtendBounds(extend_bounds);
+ operation->set_data(data);
+ operation->set_quality(quality);
+ operation->set_extend_bounds(extend_bounds);
- converter.addOperation(operation);
- converter.addLink(operationy->getOutputSocket(), operation->getInputSocket(1));
+ converter.add_operation(operation);
+ converter.add_link(operationy->get_output_socket(), operation->get_input_socket(1));
output_operation = operation;
input_operation = operation;
}
else if (!data->bokeh) {
GaussianXBlurOperation *operationx = new GaussianXBlurOperation();
- operationx->setData(data);
- operationx->setQuality(quality);
- operationx->checkOpenCL();
- operationx->setExtendBounds(extend_bounds);
+ operationx->set_data(data);
+ operationx->set_quality(quality);
+ operationx->check_opencl();
+ operationx->set_extend_bounds(extend_bounds);
- converter.addOperation(operationx);
- converter.mapInputSocket(getInputSocket(1), operationx->getInputSocket(1));
+ converter.add_operation(operationx);
+ converter.map_input_socket(get_input_socket(1), operationx->get_input_socket(1));
GaussianYBlurOperation *operationy = new GaussianYBlurOperation();
- operationy->setData(data);
- operationy->setQuality(quality);
- operationy->checkOpenCL();
- operationy->setExtendBounds(extend_bounds);
-
- converter.addOperation(operationy);
- converter.mapInputSocket(getInputSocket(1), operationy->getInputSocket(1));
- converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0));
-
- if (!connectedSizeSocket) {
- operationx->setSize(size);
- operationy->setSize(size);
+ operationy->set_data(data);
+ operationy->set_quality(quality);
+ operationy->check_opencl();
+ operationy->set_extend_bounds(extend_bounds);
+
+ converter.add_operation(operationy);
+ converter.map_input_socket(get_input_socket(1), operationy->get_input_socket(1));
+ converter.add_link(operationx->get_output_socket(), operationy->get_input_socket(0));
+
+ if (!connected_size_socket) {
+ operationx->set_size(size);
+ operationy->set_size(size);
}
input_operation = operationx;
@@ -135,15 +133,15 @@ void BlurNode::convertToOperations(NodeConverter &converter,
}
else {
GaussianBokehBlurOperation *operation = new GaussianBokehBlurOperation();
- operation->setData(data);
- operation->setQuality(quality);
- operation->setExtendBounds(extend_bounds);
+ operation->set_data(data);
+ operation->set_quality(quality);
+ operation->set_extend_bounds(extend_bounds);
- converter.addOperation(operation);
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
+ converter.add_operation(operation);
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
- if (!connectedSizeSocket) {
- operation->setSize(size);
+ if (!connected_size_socket) {
+ operation->set_size(size);
}
input_operation = operation;
@@ -153,21 +151,21 @@ void BlurNode::convertToOperations(NodeConverter &converter,
if (data->gamma) {
GammaCorrectOperation *correct = new GammaCorrectOperation();
GammaUncorrectOperation *inverse = new GammaUncorrectOperation();
- converter.addOperation(correct);
- converter.addOperation(inverse);
+ converter.add_operation(correct);
+ converter.add_operation(inverse);
- converter.mapInputSocket(getInputSocket(0), correct->getInputSocket(0));
- converter.addLink(correct->getOutputSocket(), input_operation->getInputSocket(0));
- converter.addLink(output_operation->getOutputSocket(), inverse->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(), inverse->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), correct->get_input_socket(0));
+ converter.add_link(correct->get_output_socket(), input_operation->get_input_socket(0));
+ converter.add_link(output_operation->get_output_socket(), inverse->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(), inverse->get_output_socket());
- converter.addPreview(inverse->getOutputSocket());
+ converter.add_preview(inverse->get_output_socket());
}
else {
- converter.mapInputSocket(getInputSocket(0), input_operation->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(), output_operation->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), input_operation->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(), output_operation->get_output_socket());
- converter.addPreview(output_operation->getOutputSocket());
+ converter.add_preview(output_operation->get_output_socket());
}
}
diff --git a/source/blender/compositor/nodes/COM_BlurNode.h b/source/blender/compositor/nodes/COM_BlurNode.h
index 61cdc17f3a9..816f359cab1 100644
--- a/source/blender/compositor/nodes/COM_BlurNode.h
+++ b/source/blender/compositor/nodes/COM_BlurNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class BlurNode : public Node {
public:
- BlurNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ BlurNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_BokehBlurNode.cc b/source/blender/compositor/nodes/COM_BokehBlurNode.cc
index c51a98c0f82..8f71621c435 100644
--- a/source/blender/compositor/nodes/COM_BokehBlurNode.cc
+++ b/source/blender/compositor/nodes/COM_BokehBlurNode.cc
@@ -18,61 +18,56 @@
#include "COM_BokehBlurNode.h"
#include "COM_BokehBlurOperation.h"
-#include "COM_ConvertDepthToRadiusOperation.h"
-#include "COM_ExecutionSystem.h"
#include "COM_VariableSizeBokehBlurOperation.h"
-#include "DNA_camera_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_types.h"
namespace blender::compositor {
-BokehBlurNode::BokehBlurNode(bNode *editorNode) : Node(editorNode)
+BokehBlurNode::BokehBlurNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void BokehBlurNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void BokehBlurNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *b_node = this->getbNode();
+ bNode *b_node = this->get_bnode();
- NodeInput *inputSizeSocket = this->getInputSocket(2);
+ NodeInput *input_size_socket = this->get_input_socket(2);
- bool connectedSizeSocket = inputSizeSocket->isLinked();
+ bool connected_size_socket = input_size_socket->is_linked();
const bool extend_bounds = (b_node->custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS) != 0;
- if ((b_node->custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE) && connectedSizeSocket) {
+ if ((b_node->custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE) && connected_size_socket) {
VariableSizeBokehBlurOperation *operation = new VariableSizeBokehBlurOperation();
- operation->setQuality(context.getQuality());
- operation->setThreshold(0.0f);
- operation->setMaxBlur(b_node->custom4);
- operation->setDoScaleSize(true);
+ operation->set_quality(context.get_quality());
+ operation->set_threshold(0.0f);
+ operation->set_max_blur(b_node->custom4);
+ operation->set_do_scale_size(true);
- converter.addOperation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
+ converter.add_operation(operation);
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_input_socket(get_input_socket(2), operation->get_input_socket(2));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
}
else {
BokehBlurOperation *operation = new BokehBlurOperation();
- operation->setQuality(context.getQuality());
- operation->setExtendBounds(extend_bounds);
+ operation->set_quality(context.get_quality());
+ operation->set_extend_bounds(extend_bounds);
- converter.addOperation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
+ converter.add_operation(operation);
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
/* NOTE: on the bokeh blur operation the sockets are switched.
* for this reason the next two lines are correct. Fix for T43771. */
- converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(3));
- converter.mapInputSocket(getInputSocket(3), operation->getInputSocket(2));
+ converter.map_input_socket(get_input_socket(2), operation->get_input_socket(3));
+ converter.map_input_socket(get_input_socket(3), operation->get_input_socket(2));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
- if (!connectedSizeSocket) {
- operation->setSize(this->getInputSocket(2)->getEditorValueFloat());
+ if (!connected_size_socket) {
+ operation->set_size(this->get_input_socket(2)->get_editor_value_float());
}
}
}
diff --git a/source/blender/compositor/nodes/COM_BokehBlurNode.h b/source/blender/compositor/nodes/COM_BokehBlurNode.h
index 2c060936025..869eee44a6f 100644
--- a/source/blender/compositor/nodes/COM_BokehBlurNode.h
+++ b/source/blender/compositor/nodes/COM_BokehBlurNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class BokehBlurNode : public Node {
public:
- BokehBlurNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ BokehBlurNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_BokehImageNode.cc b/source/blender/compositor/nodes/COM_BokehImageNode.cc
index 2b0a47c76bc..c860ef7a1c9 100644
--- a/source/blender/compositor/nodes/COM_BokehImageNode.cc
+++ b/source/blender/compositor/nodes/COM_BokehImageNode.cc
@@ -18,25 +18,24 @@
#include "COM_BokehImageNode.h"
#include "COM_BokehImageOperation.h"
-#include "COM_ExecutionSystem.h"
namespace blender::compositor {
-BokehImageNode::BokehImageNode(bNode *editorNode) : Node(editorNode)
+BokehImageNode::BokehImageNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void BokehImageNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void BokehImageNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
BokehImageOperation *operation = new BokehImageOperation();
- operation->setData((NodeBokehImage *)this->getbNode()->storage);
+ operation->set_data((NodeBokehImage *)this->get_bnode()->storage);
- converter.addOperation(operation);
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.add_operation(operation);
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
- converter.addPreview(operation->getOutputSocket(0));
+ converter.add_preview(operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_BokehImageNode.h b/source/blender/compositor/nodes/COM_BokehImageNode.h
index 323561a7e4f..cb685c93237 100644
--- a/source/blender/compositor/nodes/COM_BokehImageNode.h
+++ b/source/blender/compositor/nodes/COM_BokehImageNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class BokehImageNode : public Node {
public:
- BokehImageNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ BokehImageNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_BoxMaskNode.cc b/source/blender/compositor/nodes/COM_BoxMaskNode.cc
index 8017e063a69..1cf05727a0a 100644
--- a/source/blender/compositor/nodes/COM_BoxMaskNode.cc
+++ b/source/blender/compositor/nodes/COM_BoxMaskNode.cc
@@ -18,59 +18,59 @@
#include "COM_BoxMaskNode.h"
#include "COM_BoxMaskOperation.h"
-#include "COM_ExecutionSystem.h"
#include "COM_ScaleOperation.h"
#include "COM_SetValueOperation.h"
namespace blender::compositor {
-BoxMaskNode::BoxMaskNode(bNode *editorNode) : Node(editorNode)
+BoxMaskNode::BoxMaskNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void BoxMaskNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void BoxMaskNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeOutput *outputSocket = this->getOutputSocket(0);
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeOutput *output_socket = this->get_output_socket(0);
BoxMaskOperation *operation;
operation = new BoxMaskOperation();
- operation->setData((NodeBoxMask *)this->getbNode()->storage);
- operation->setMaskType(this->getbNode()->custom1);
- converter.addOperation(operation);
+ operation->set_data((NodeBoxMask *)this->get_bnode()->storage);
+ operation->set_mask_type(this->get_bnode()->custom1);
+ converter.add_operation(operation);
- if (inputSocket->isLinked()) {
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket());
+ if (input_socket->is_linked()) {
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.map_output_socket(output_socket, operation->get_output_socket());
}
else {
/* Value operation to produce original transparent image */
- SetValueOperation *valueOperation = new SetValueOperation();
- valueOperation->setValue(0.0f);
- converter.addOperation(valueOperation);
+ SetValueOperation *value_operation = new SetValueOperation();
+ value_operation->set_value(0.0f);
+ converter.add_operation(value_operation);
/* Scale that image up to render resolution */
- const RenderData *rd = context.getRenderData();
- const float render_size_factor = context.getRenderPercentageAsFactor();
- ScaleFixedSizeOperation *scaleOperation = new ScaleFixedSizeOperation();
+ const RenderData *rd = context.get_render_data();
+ const float render_size_factor = context.get_render_percentage_as_factor();
+ ScaleFixedSizeOperation *scale_operation = new ScaleFixedSizeOperation();
- scaleOperation->setIsAspect(false);
- scaleOperation->setIsCrop(false);
- scaleOperation->setOffset(0.0f, 0.0f);
- scaleOperation->setNewWidth(rd->xsch * render_size_factor);
- scaleOperation->setNewHeight(rd->ysch * render_size_factor);
- scaleOperation->getInputSocket(0)->setResizeMode(ResizeMode::Align);
- converter.addOperation(scaleOperation);
+ scale_operation->set_is_aspect(false);
+ scale_operation->set_is_crop(false);
+ scale_operation->set_offset(0.0f, 0.0f);
+ scale_operation->set_new_width(rd->xsch * render_size_factor);
+ scale_operation->set_new_height(rd->ysch * render_size_factor);
+ scale_operation->get_input_socket(0)->set_resize_mode(ResizeMode::Align);
+ converter.add_operation(scale_operation);
- converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0));
- converter.addLink(scaleOperation->getOutputSocket(0), operation->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ converter.add_link(value_operation->get_output_socket(0),
+ scale_operation->get_input_socket(0));
+ converter.add_link(scale_operation->get_output_socket(0), operation->get_input_socket(0));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
}
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_BoxMaskNode.h b/source/blender/compositor/nodes/COM_BoxMaskNode.h
index 46cedf7af75..68d98f6c0ea 100644
--- a/source/blender/compositor/nodes/COM_BoxMaskNode.h
+++ b/source/blender/compositor/nodes/COM_BoxMaskNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class BoxMaskNode : public Node {
public:
- BoxMaskNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ BoxMaskNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_BrightnessNode.cc b/source/blender/compositor/nodes/COM_BrightnessNode.cc
index b64f1fea99f..0b87d5d3d49 100644
--- a/source/blender/compositor/nodes/COM_BrightnessNode.cc
+++ b/source/blender/compositor/nodes/COM_BrightnessNode.cc
@@ -18,27 +18,26 @@
#include "COM_BrightnessNode.h"
#include "COM_BrightnessOperation.h"
-#include "COM_ExecutionSystem.h"
namespace blender::compositor {
-BrightnessNode::BrightnessNode(bNode *editorNode) : Node(editorNode)
+BrightnessNode::BrightnessNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void BrightnessNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void BrightnessNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *bnode = this->getbNode();
+ bNode *bnode = this->get_bnode();
BrightnessOperation *operation = new BrightnessOperation();
- operation->setUsePremultiply((bnode->custom1 & 1) != 0);
- converter.addOperation(operation);
+ operation->set_use_premultiply((bnode->custom1 & 1) != 0);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_input_socket(get_input_socket(2), operation->get_input_socket(2));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_BrightnessNode.h b/source/blender/compositor/nodes/COM_BrightnessNode.h
index 1084108b1c3..82a383557ba 100644
--- a/source/blender/compositor/nodes/COM_BrightnessNode.h
+++ b/source/blender/compositor/nodes/COM_BrightnessNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class BrightnessNode : public Node {
public:
- BrightnessNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ BrightnessNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ChannelMatteNode.cc b/source/blender/compositor/nodes/COM_ChannelMatteNode.cc
index d0f72274aea..cf8e8a7392d 100644
--- a/source/blender/compositor/nodes/COM_ChannelMatteNode.cc
+++ b/source/blender/compositor/nodes/COM_ChannelMatteNode.cc
@@ -17,26 +17,25 @@
*/
#include "COM_ChannelMatteNode.h"
-#include "BKE_node.h"
#include "COM_ChannelMatteOperation.h"
#include "COM_ConvertOperation.h"
#include "COM_SetAlphaMultiplyOperation.h"
namespace blender::compositor {
-ChannelMatteNode::ChannelMatteNode(bNode *editorNode) : Node(editorNode)
+ChannelMatteNode::ChannelMatteNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ChannelMatteNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ChannelMatteNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *node = this->getbNode();
+ bNode *node = this->get_bnode();
- NodeInput *inputSocketImage = this->getInputSocket(0);
- NodeOutput *outputSocketImage = this->getOutputSocket(0);
- NodeOutput *outputSocketMatte = this->getOutputSocket(1);
+ NodeInput *input_socket_image = this->get_input_socket(0);
+ NodeOutput *output_socket_image = this->get_output_socket(0);
+ NodeOutput *output_socket_matte = this->get_output_socket(1);
NodeOperation *convert = nullptr, *inv_convert = nullptr;
/* colorspace */
@@ -53,9 +52,9 @@ void ChannelMatteNode::convertToOperations(NodeConverter &converter,
break;
case CMP_NODE_CHANNEL_MATTE_CS_YCC: /* YCC */
convert = new ConvertRGBToYCCOperation();
- ((ConvertRGBToYCCOperation *)convert)->setMode(BLI_YCC_ITU_BT709);
+ ((ConvertRGBToYCCOperation *)convert)->set_mode(BLI_YCC_ITU_BT709);
inv_convert = new ConvertYCCToRGBOperation();
- ((ConvertYCCToRGBOperation *)inv_convert)->setMode(BLI_YCC_ITU_BT709);
+ ((ConvertYCCToRGBOperation *)inv_convert)->set_mode(BLI_YCC_ITU_BT709);
break;
default:
break;
@@ -63,36 +62,36 @@ void ChannelMatteNode::convertToOperations(NodeConverter &converter,
ChannelMatteOperation *operation = new ChannelMatteOperation();
/* pass the ui properties to the operation */
- operation->setSettings((NodeChroma *)node->storage, node->custom2);
- converter.addOperation(operation);
+ operation->set_settings((NodeChroma *)node->storage, node->custom2);
+ converter.add_operation(operation);
- SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation();
- converter.addOperation(operationAlpha);
+ SetAlphaMultiplyOperation *operation_alpha = new SetAlphaMultiplyOperation();
+ converter.add_operation(operation_alpha);
if (convert != nullptr) {
- converter.addOperation(convert);
+ converter.add_operation(convert);
- converter.mapInputSocket(inputSocketImage, convert->getInputSocket(0));
- converter.addLink(convert->getOutputSocket(), operation->getInputSocket(0));
- converter.addLink(convert->getOutputSocket(), operationAlpha->getInputSocket(0));
+ converter.map_input_socket(input_socket_image, convert->get_input_socket(0));
+ converter.add_link(convert->get_output_socket(), operation->get_input_socket(0));
+ converter.add_link(convert->get_output_socket(), operation_alpha->get_input_socket(0));
}
else {
- converter.mapInputSocket(inputSocketImage, operation->getInputSocket(0));
- converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0));
+ converter.map_input_socket(input_socket_image, operation->get_input_socket(0));
+ converter.map_input_socket(input_socket_image, operation_alpha->get_input_socket(0));
}
- converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket(0));
- converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1));
+ converter.map_output_socket(output_socket_matte, operation->get_output_socket(0));
+ converter.add_link(operation->get_output_socket(), operation_alpha->get_input_socket(1));
if (inv_convert != nullptr) {
- converter.addOperation(inv_convert);
- converter.addLink(operationAlpha->getOutputSocket(0), inv_convert->getInputSocket(0));
- converter.mapOutputSocket(outputSocketImage, inv_convert->getOutputSocket());
- converter.addPreview(inv_convert->getOutputSocket());
+ converter.add_operation(inv_convert);
+ converter.add_link(operation_alpha->get_output_socket(0), inv_convert->get_input_socket(0));
+ converter.map_output_socket(output_socket_image, inv_convert->get_output_socket());
+ converter.add_preview(inv_convert->get_output_socket());
}
else {
- converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket());
- converter.addPreview(operationAlpha->getOutputSocket());
+ converter.map_output_socket(output_socket_image, operation_alpha->get_output_socket());
+ converter.add_preview(operation_alpha->get_output_socket());
}
}
diff --git a/source/blender/compositor/nodes/COM_ChannelMatteNode.h b/source/blender/compositor/nodes/COM_ChannelMatteNode.h
index 46100b3f7ea..c071c516e6d 100644
--- a/source/blender/compositor/nodes/COM_ChannelMatteNode.h
+++ b/source/blender/compositor/nodes/COM_ChannelMatteNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ChannelMatteNode : public Node {
public:
- ChannelMatteNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ChannelMatteNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ChromaMatteNode.cc b/source/blender/compositor/nodes/COM_ChromaMatteNode.cc
index 9abf183a843..8db96e0308d 100644
--- a/source/blender/compositor/nodes/COM_ChromaMatteNode.cc
+++ b/source/blender/compositor/nodes/COM_ChromaMatteNode.cc
@@ -17,53 +17,52 @@
*/
#include "COM_ChromaMatteNode.h"
-#include "BKE_node.h"
#include "COM_ChromaMatteOperation.h"
#include "COM_ConvertOperation.h"
#include "COM_SetAlphaMultiplyOperation.h"
namespace blender::compositor {
-ChromaMatteNode::ChromaMatteNode(bNode *editorNode) : Node(editorNode)
+ChromaMatteNode::ChromaMatteNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ChromaMatteNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ChromaMatteNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *editorsnode = getbNode();
+ bNode *editorsnode = get_bnode();
- NodeInput *inputSocketImage = this->getInputSocket(0);
- NodeInput *inputSocketKey = this->getInputSocket(1);
- NodeOutput *outputSocketImage = this->getOutputSocket(0);
- NodeOutput *outputSocketMatte = this->getOutputSocket(1);
+ NodeInput *input_socket_image = this->get_input_socket(0);
+ NodeInput *input_socket_key = this->get_input_socket(1);
+ NodeOutput *output_socket_image = this->get_output_socket(0);
+ NodeOutput *output_socket_matte = this->get_output_socket(1);
ConvertRGBToYCCOperation *operationRGBToYCC_Image = new ConvertRGBToYCCOperation();
ConvertRGBToYCCOperation *operationRGBToYCC_Key = new ConvertRGBToYCCOperation();
- operationRGBToYCC_Image->setMode(BLI_YCC_ITU_BT709);
- operationRGBToYCC_Key->setMode(BLI_YCC_ITU_BT709);
- converter.addOperation(operationRGBToYCC_Image);
- converter.addOperation(operationRGBToYCC_Key);
+ operationRGBToYCC_Image->set_mode(BLI_YCC_ITU_BT709);
+ operationRGBToYCC_Key->set_mode(BLI_YCC_ITU_BT709);
+ converter.add_operation(operationRGBToYCC_Image);
+ converter.add_operation(operationRGBToYCC_Key);
ChromaMatteOperation *operation = new ChromaMatteOperation();
- operation->setSettings((NodeChroma *)editorsnode->storage);
- converter.addOperation(operation);
+ operation->set_settings((NodeChroma *)editorsnode->storage);
+ converter.add_operation(operation);
- SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation();
- converter.addOperation(operationAlpha);
+ SetAlphaMultiplyOperation *operation_alpha = new SetAlphaMultiplyOperation();
+ converter.add_operation(operation_alpha);
- converter.mapInputSocket(inputSocketImage, operationRGBToYCC_Image->getInputSocket(0));
- converter.mapInputSocket(inputSocketKey, operationRGBToYCC_Key->getInputSocket(0));
- converter.addLink(operationRGBToYCC_Image->getOutputSocket(), operation->getInputSocket(0));
- converter.addLink(operationRGBToYCC_Key->getOutputSocket(), operation->getInputSocket(1));
- converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket());
+ converter.map_input_socket(input_socket_image, operationRGBToYCC_Image->get_input_socket(0));
+ converter.map_input_socket(input_socket_key, operationRGBToYCC_Key->get_input_socket(0));
+ converter.add_link(operationRGBToYCC_Image->get_output_socket(), operation->get_input_socket(0));
+ converter.add_link(operationRGBToYCC_Key->get_output_socket(), operation->get_input_socket(1));
+ converter.map_output_socket(output_socket_matte, operation->get_output_socket());
- converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0));
- converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1));
- converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket());
+ converter.map_input_socket(input_socket_image, operation_alpha->get_input_socket(0));
+ converter.add_link(operation->get_output_socket(), operation_alpha->get_input_socket(1));
+ converter.map_output_socket(output_socket_image, operation_alpha->get_output_socket());
- converter.addPreview(operationAlpha->getOutputSocket());
+ converter.add_preview(operation_alpha->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ChromaMatteNode.h b/source/blender/compositor/nodes/COM_ChromaMatteNode.h
index f3ddd013fa4..854c07c104b 100644
--- a/source/blender/compositor/nodes/COM_ChromaMatteNode.h
+++ b/source/blender/compositor/nodes/COM_ChromaMatteNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ChromaMatteNode : public Node {
public:
- ChromaMatteNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ChromaMatteNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorBalanceNode.cc b/source/blender/compositor/nodes/COM_ColorBalanceNode.cc
index 03e4e143061..e7c43161a00 100644
--- a/source/blender/compositor/nodes/COM_ColorBalanceNode.cc
+++ b/source/blender/compositor/nodes/COM_ColorBalanceNode.cc
@@ -17,28 +17,25 @@
*/
#include "COM_ColorBalanceNode.h"
-#include "BKE_node.h"
#include "COM_ColorBalanceASCCDLOperation.h"
#include "COM_ColorBalanceLGGOperation.h"
-#include "COM_ExecutionSystem.h"
-#include "COM_MixOperation.h"
namespace blender::compositor {
-ColorBalanceNode::ColorBalanceNode(bNode *editorNode) : Node(editorNode)
+ColorBalanceNode::ColorBalanceNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ColorBalanceNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ColorBalanceNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *node = this->getbNode();
+ bNode *node = this->get_bnode();
NodeColorBalance *n = (NodeColorBalance *)node->storage;
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeInput *inputImageSocket = this->getInputSocket(1);
- NodeOutput *outputSocket = this->getOutputSocket(0);
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeInput *input_image_socket = this->get_input_socket(1);
+ NodeOutput *output_socket = this->get_output_socket(0);
NodeOperation *operation;
if (node->custom1 == 0) {
@@ -50,9 +47,9 @@ void ColorBalanceNode::convertToOperations(NodeConverter &converter,
gamma_inv[c] = (n->gamma[c] != 0.0f) ? 1.0f / n->gamma[c] : 1000000.0f;
}
- operationLGG->setGain(n->gain);
- operationLGG->setLift(lift_lgg);
- operationLGG->setGammaInv(gamma_inv);
+ operationLGG->set_gain(n->gain);
+ operationLGG->set_lift(lift_lgg);
+ operationLGG->set_gamma_inv(gamma_inv);
operation = operationLGG;
}
else {
@@ -62,16 +59,16 @@ void ColorBalanceNode::convertToOperations(NodeConverter &converter,
copy_v3_fl(offset, n->offset_basis);
add_v3_v3(offset, n->offset);
- operationCDL->setOffset(offset);
- operationCDL->setPower(n->power);
- operationCDL->setSlope(n->slope);
+ operationCDL->set_offset(offset);
+ operationCDL->set_power(n->power);
+ operationCDL->set_slope(n->slope);
operation = operationCDL;
}
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.mapInputSocket(inputImageSocket, operation->getInputSocket(1));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.map_input_socket(input_image_socket, operation->get_input_socket(1));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorBalanceNode.h b/source/blender/compositor/nodes/COM_ColorBalanceNode.h
index 243713b4912..3ac0b7cdee1 100644
--- a/source/blender/compositor/nodes/COM_ColorBalanceNode.h
+++ b/source/blender/compositor/nodes/COM_ColorBalanceNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ColorBalanceNode : public Node {
public:
- ColorBalanceNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ColorBalanceNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc
index 6397b1d8e4b..49d8a7fec98 100644
--- a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc
+++ b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc
@@ -18,30 +18,29 @@
#include "COM_ColorCorrectionNode.h"
#include "COM_ColorCorrectionOperation.h"
-#include "COM_ExecutionSystem.h"
namespace blender::compositor {
-ColorCorrectionNode::ColorCorrectionNode(bNode *editorNode) : Node(editorNode)
+ColorCorrectionNode::ColorCorrectionNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ColorCorrectionNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ColorCorrectionNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *editorNode = getbNode();
+ bNode *editor_node = get_bnode();
ColorCorrectionOperation *operation = new ColorCorrectionOperation();
- operation->setData((NodeColorCorrection *)editorNode->storage);
- operation->setRedChannelEnabled((editorNode->custom1 & 1) != 0);
- operation->setGreenChannelEnabled((editorNode->custom1 & 2) != 0);
- operation->setBlueChannelEnabled((editorNode->custom1 & 4) != 0);
- converter.addOperation(operation);
+ operation->set_data((NodeColorCorrection *)editor_node->storage);
+ operation->set_red_channel_enabled((editor_node->custom1 & 1) != 0);
+ operation->set_green_channel_enabled((editor_node->custom1 & 2) != 0);
+ operation->set_blue_channel_enabled((editor_node->custom1 & 4) != 0);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorCorrectionNode.h b/source/blender/compositor/nodes/COM_ColorCorrectionNode.h
index aee07ee07a3..6fe4212e428 100644
--- a/source/blender/compositor/nodes/COM_ColorCorrectionNode.h
+++ b/source/blender/compositor/nodes/COM_ColorCorrectionNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ColorCorrectionNode : public Node {
public:
- ColorCorrectionNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ColorCorrectionNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorCurveNode.cc b/source/blender/compositor/nodes/COM_ColorCurveNode.cc
index 774dd689a46..5b59b2bee14 100644
--- a/source/blender/compositor/nodes/COM_ColorCurveNode.cc
+++ b/source/blender/compositor/nodes/COM_ColorCurveNode.cc
@@ -18,43 +18,42 @@
#include "COM_ColorCurveNode.h"
#include "COM_ColorCurveOperation.h"
-#include "COM_ExecutionSystem.h"
namespace blender::compositor {
-ColorCurveNode::ColorCurveNode(bNode *editorNode) : Node(editorNode)
+ColorCurveNode::ColorCurveNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ColorCurveNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ColorCurveNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- if (this->getInputSocket(2)->isLinked() || this->getInputSocket(3)->isLinked()) {
+ if (this->get_input_socket(2)->is_linked() || this->get_input_socket(3)->is_linked()) {
ColorCurveOperation *operation = new ColorCurveOperation();
- operation->setCurveMapping((CurveMapping *)this->getbNode()->storage);
- converter.addOperation(operation);
+ operation->set_curve_mapping((CurveMapping *)this->get_bnode()->storage);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2));
- converter.mapInputSocket(getInputSocket(3), operation->getInputSocket(3));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_input_socket(get_input_socket(2), operation->get_input_socket(2));
+ converter.map_input_socket(get_input_socket(3), operation->get_input_socket(3));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
}
else {
ConstantLevelColorCurveOperation *operation = new ConstantLevelColorCurveOperation();
float col[4];
- this->getInputSocket(2)->getEditorValueColor(col);
- operation->setBlackLevel(col);
- this->getInputSocket(3)->getEditorValueColor(col);
- operation->setWhiteLevel(col);
- operation->setCurveMapping((CurveMapping *)this->getbNode()->storage);
- converter.addOperation(operation);
-
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
+ this->get_input_socket(2)->get_editor_value_color(col);
+ operation->set_black_level(col);
+ this->get_input_socket(3)->get_editor_value_color(col);
+ operation->set_white_level(col);
+ operation->set_curve_mapping((CurveMapping *)this->get_bnode()->storage);
+ converter.add_operation(operation);
+
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
}
}
diff --git a/source/blender/compositor/nodes/COM_ColorCurveNode.h b/source/blender/compositor/nodes/COM_ColorCurveNode.h
index 89786b47cf5..852f755bf95 100644
--- a/source/blender/compositor/nodes/COM_ColorCurveNode.h
+++ b/source/blender/compositor/nodes/COM_ColorCurveNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ColorCurveNode : public Node {
public:
- ColorCurveNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ColorCurveNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorExposureNode.cc b/source/blender/compositor/nodes/COM_ColorExposureNode.cc
index a8f164e6b66..2f5e6b0a7bf 100644
--- a/source/blender/compositor/nodes/COM_ColorExposureNode.cc
+++ b/source/blender/compositor/nodes/COM_ColorExposureNode.cc
@@ -18,24 +18,23 @@
#include "COM_ColorExposureNode.h"
#include "COM_ColorExposureOperation.h"
-#include "COM_ExecutionSystem.h"
namespace blender::compositor {
-ExposureNode::ExposureNode(bNode *editorNode) : Node(editorNode)
+ExposureNode::ExposureNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ExposureNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ExposureNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
ExposureOperation *operation = new ExposureOperation();
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorExposureNode.h b/source/blender/compositor/nodes/COM_ColorExposureNode.h
index df9bfc65f81..33b143e0676 100644
--- a/source/blender/compositor/nodes/COM_ColorExposureNode.h
+++ b/source/blender/compositor/nodes/COM_ColorExposureNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ExposureNode : public Node {
public:
- ExposureNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ExposureNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorMatteNode.cc b/source/blender/compositor/nodes/COM_ColorMatteNode.cc
index eadb8ce4f96..629ae932eb7 100644
--- a/source/blender/compositor/nodes/COM_ColorMatteNode.cc
+++ b/source/blender/compositor/nodes/COM_ColorMatteNode.cc
@@ -17,51 +17,50 @@
*/
#include "COM_ColorMatteNode.h"
-#include "BKE_node.h"
#include "COM_ColorMatteOperation.h"
#include "COM_ConvertOperation.h"
#include "COM_SetAlphaMultiplyOperation.h"
namespace blender::compositor {
-ColorMatteNode::ColorMatteNode(bNode *editorNode) : Node(editorNode)
+ColorMatteNode::ColorMatteNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ColorMatteNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ColorMatteNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *editorsnode = getbNode();
+ bNode *editorsnode = get_bnode();
- NodeInput *inputSocketImage = this->getInputSocket(0);
- NodeInput *inputSocketKey = this->getInputSocket(1);
- NodeOutput *outputSocketImage = this->getOutputSocket(0);
- NodeOutput *outputSocketMatte = this->getOutputSocket(1);
+ NodeInput *input_socket_image = this->get_input_socket(0);
+ NodeInput *input_socket_key = this->get_input_socket(1);
+ NodeOutput *output_socket_image = this->get_output_socket(0);
+ NodeOutput *output_socket_matte = this->get_output_socket(1);
ConvertRGBToHSVOperation *operationRGBToHSV_Image = new ConvertRGBToHSVOperation();
ConvertRGBToHSVOperation *operationRGBToHSV_Key = new ConvertRGBToHSVOperation();
- converter.addOperation(operationRGBToHSV_Image);
- converter.addOperation(operationRGBToHSV_Key);
+ converter.add_operation(operationRGBToHSV_Image);
+ converter.add_operation(operationRGBToHSV_Key);
ColorMatteOperation *operation = new ColorMatteOperation();
- operation->setSettings((NodeChroma *)editorsnode->storage);
- converter.addOperation(operation);
+ operation->set_settings((NodeChroma *)editorsnode->storage);
+ converter.add_operation(operation);
- SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation();
- converter.addOperation(operationAlpha);
+ SetAlphaMultiplyOperation *operation_alpha = new SetAlphaMultiplyOperation();
+ converter.add_operation(operation_alpha);
- converter.mapInputSocket(inputSocketImage, operationRGBToHSV_Image->getInputSocket(0));
- converter.mapInputSocket(inputSocketKey, operationRGBToHSV_Key->getInputSocket(0));
- converter.addLink(operationRGBToHSV_Image->getOutputSocket(), operation->getInputSocket(0));
- converter.addLink(operationRGBToHSV_Key->getOutputSocket(), operation->getInputSocket(1));
- converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket(0));
+ converter.map_input_socket(input_socket_image, operationRGBToHSV_Image->get_input_socket(0));
+ converter.map_input_socket(input_socket_key, operationRGBToHSV_Key->get_input_socket(0));
+ converter.add_link(operationRGBToHSV_Image->get_output_socket(), operation->get_input_socket(0));
+ converter.add_link(operationRGBToHSV_Key->get_output_socket(), operation->get_input_socket(1));
+ converter.map_output_socket(output_socket_matte, operation->get_output_socket(0));
- converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0));
- converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1));
- converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket());
+ converter.map_input_socket(input_socket_image, operation_alpha->get_input_socket(0));
+ converter.add_link(operation->get_output_socket(), operation_alpha->get_input_socket(1));
+ converter.map_output_socket(output_socket_image, operation_alpha->get_output_socket());
- converter.addPreview(operationAlpha->getOutputSocket());
+ converter.add_preview(operation_alpha->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorMatteNode.h b/source/blender/compositor/nodes/COM_ColorMatteNode.h
index 9d70b6d8416..3e1bfd607e8 100644
--- a/source/blender/compositor/nodes/COM_ColorMatteNode.h
+++ b/source/blender/compositor/nodes/COM_ColorMatteNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ColorMatteNode : public Node {
public:
- ColorMatteNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ColorMatteNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorNode.cc b/source/blender/compositor/nodes/COM_ColorNode.cc
index f8277645a4b..2d875d703c7 100644
--- a/source/blender/compositor/nodes/COM_ColorNode.cc
+++ b/source/blender/compositor/nodes/COM_ColorNode.cc
@@ -17,27 +17,26 @@
*/
#include "COM_ColorNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_SetColorOperation.h"
namespace blender::compositor {
-ColorNode::ColorNode(bNode *editorNode) : Node(editorNode)
+ColorNode::ColorNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ColorNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ColorNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
SetColorOperation *operation = new SetColorOperation();
- NodeOutput *output = this->getOutputSocket(0);
+ NodeOutput *output = this->get_output_socket(0);
float col[4];
- output->getEditorValueColor(col);
- operation->setChannels(col);
- converter.addOperation(operation);
+ output->get_editor_value_color(col);
+ operation->set_channels(col);
+ converter.add_operation(operation);
- converter.mapOutputSocket(output, operation->getOutputSocket());
+ converter.map_output_socket(output, operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorNode.h b/source/blender/compositor/nodes/COM_ColorNode.h
index ae3bf575bb4..f5b932f6321 100644
--- a/source/blender/compositor/nodes/COM_ColorNode.h
+++ b/source/blender/compositor/nodes/COM_ColorNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ColorNode : public Node {
public:
- ColorNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ColorNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorRampNode.cc b/source/blender/compositor/nodes/COM_ColorRampNode.cc
index 6b44ef3057e..7ae83be65c2 100644
--- a/source/blender/compositor/nodes/COM_ColorRampNode.cc
+++ b/source/blender/compositor/nodes/COM_ColorRampNode.cc
@@ -17,40 +17,37 @@
*/
#include "COM_ColorRampNode.h"
-#include "BKE_node.h"
#include "COM_ColorRampOperation.h"
#include "COM_ConvertOperation.h"
-#include "COM_ExecutionSystem.h"
-#include "DNA_texture_types.h"
namespace blender::compositor {
-ColorRampNode::ColorRampNode(bNode *editorNode) : Node(editorNode)
+ColorRampNode::ColorRampNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ColorRampNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ColorRampNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeOutput *outputSocket = this->getOutputSocket(0);
- NodeOutput *outputSocketAlpha = this->getOutputSocket(1);
- bNode *editorNode = this->getbNode();
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeOutput *output_socket = this->get_output_socket(0);
+ NodeOutput *output_socket_alpha = this->get_output_socket(1);
+ bNode *editor_node = this->get_bnode();
ColorRampOperation *operation = new ColorRampOperation();
- operation->setColorBand((ColorBand *)editorNode->storage);
- converter.addOperation(operation);
+ operation->set_color_band((ColorBand *)editor_node->storage);
+ converter.add_operation(operation);
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
SeparateChannelOperation *operation2 = new SeparateChannelOperation();
- operation2->setChannel(3);
- converter.addOperation(operation2);
+ operation2->set_channel(3);
+ converter.add_operation(operation2);
- converter.addLink(operation->getOutputSocket(), operation2->getInputSocket(0));
- converter.mapOutputSocket(outputSocketAlpha, operation2->getOutputSocket());
+ converter.add_link(operation->get_output_socket(), operation2->get_input_socket(0));
+ converter.map_output_socket(output_socket_alpha, operation2->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorRampNode.h b/source/blender/compositor/nodes/COM_ColorRampNode.h
index d0c0e43d56c..70e10311b2a 100644
--- a/source/blender/compositor/nodes/COM_ColorRampNode.h
+++ b/source/blender/compositor/nodes/COM_ColorRampNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ColorRampNode : public Node {
public:
- ColorRampNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ColorRampNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorSpillNode.cc b/source/blender/compositor/nodes/COM_ColorSpillNode.cc
index 6119e635e59..063c515b460 100644
--- a/source/blender/compositor/nodes/COM_ColorSpillNode.cc
+++ b/source/blender/compositor/nodes/COM_ColorSpillNode.cc
@@ -17,35 +17,34 @@
*/
#include "COM_ColorSpillNode.h"
-#include "BKE_node.h"
#include "COM_ColorSpillOperation.h"
namespace blender::compositor {
-ColorSpillNode::ColorSpillNode(bNode *editorNode) : Node(editorNode)
+ColorSpillNode::ColorSpillNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ColorSpillNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ColorSpillNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *editorsnode = getbNode();
+ bNode *editorsnode = get_bnode();
- NodeInput *inputSocketImage = this->getInputSocket(0);
- NodeInput *inputSocketFac = this->getInputSocket(1);
- NodeOutput *outputSocketImage = this->getOutputSocket(0);
+ NodeInput *input_socket_image = this->get_input_socket(0);
+ NodeInput *input_socket_fac = this->get_input_socket(1);
+ NodeOutput *output_socket_image = this->get_output_socket(0);
ColorSpillOperation *operation;
operation = new ColorSpillOperation();
- operation->setSettings((NodeColorspill *)editorsnode->storage);
- operation->setSpillChannel(editorsnode->custom1 - 1); /* Channel for spilling */
- operation->setSpillMethod(editorsnode->custom2); /* Channel method */
- converter.addOperation(operation);
-
- converter.mapInputSocket(inputSocketImage, operation->getInputSocket(0));
- converter.mapInputSocket(inputSocketFac, operation->getInputSocket(1));
- converter.mapOutputSocket(outputSocketImage, operation->getOutputSocket());
+ operation->set_settings((NodeColorspill *)editorsnode->storage);
+ operation->set_spill_channel(editorsnode->custom1 - 1); /* Channel for spilling */
+ operation->set_spill_method(editorsnode->custom2); /* Channel method */
+ converter.add_operation(operation);
+
+ converter.map_input_socket(input_socket_image, operation->get_input_socket(0));
+ converter.map_input_socket(input_socket_fac, operation->get_input_socket(1));
+ converter.map_output_socket(output_socket_image, operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorSpillNode.h b/source/blender/compositor/nodes/COM_ColorSpillNode.h
index 731a76e8811..3a9b0e665e8 100644
--- a/source/blender/compositor/nodes/COM_ColorSpillNode.h
+++ b/source/blender/compositor/nodes/COM_ColorSpillNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ColorSpillNode : public Node {
public:
- ColorSpillNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ColorSpillNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorToBWNode.cc b/source/blender/compositor/nodes/COM_ColorToBWNode.cc
index dcedfc19e4d..c021ee59b9e 100644
--- a/source/blender/compositor/nodes/COM_ColorToBWNode.cc
+++ b/source/blender/compositor/nodes/COM_ColorToBWNode.cc
@@ -19,26 +19,25 @@
#include "COM_ColorToBWNode.h"
#include "COM_ConvertOperation.h"
-#include "COM_ExecutionSystem.h"
namespace blender::compositor {
-ColorToBWNode::ColorToBWNode(bNode *editorNode) : Node(editorNode)
+ColorToBWNode::ColorToBWNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ColorToBWNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ColorToBWNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeInput *colorSocket = this->getInputSocket(0);
- NodeOutput *valueSocket = this->getOutputSocket(0);
+ NodeInput *color_socket = this->get_input_socket(0);
+ NodeOutput *value_socket = this->get_output_socket(0);
- ConvertColorToBWOperation *convertProg = new ConvertColorToBWOperation();
- converter.addOperation(convertProg);
+ ConvertColorToBWOperation *convert_prog = new ConvertColorToBWOperation();
+ converter.add_operation(convert_prog);
- converter.mapInputSocket(colorSocket, convertProg->getInputSocket(0));
- converter.mapOutputSocket(valueSocket, convertProg->getOutputSocket(0));
+ converter.map_input_socket(color_socket, convert_prog->get_input_socket(0));
+ converter.map_output_socket(value_socket, convert_prog->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ColorToBWNode.h b/source/blender/compositor/nodes/COM_ColorToBWNode.h
index 60c08a3c886..7018f30f559 100644
--- a/source/blender/compositor/nodes/COM_ColorToBWNode.h
+++ b/source/blender/compositor/nodes/COM_ColorToBWNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class ColorToBWNode : public Node {
public:
- ColorToBWNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ColorToBWNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.cc b/source/blender/compositor/nodes/COM_CombineColorNode.cc
index dd68780dc19..a37fc6ad5fa 100644
--- a/source/blender/compositor/nodes/COM_CombineColorNode.cc
+++ b/source/blender/compositor/nodes/COM_CombineColorNode.cc
@@ -22,70 +22,70 @@
namespace blender::compositor {
-CombineColorNode::CombineColorNode(bNode *editorNode) : Node(editorNode)
+CombineColorNode::CombineColorNode(bNode *editor_node) : Node(editor_node)
{
}
-void CombineColorNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void CombineColorNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- NodeInput *inputRSocket = this->getInputSocket(0);
- NodeInput *inputGSocket = this->getInputSocket(1);
- NodeInput *inputBSocket = this->getInputSocket(2);
- NodeInput *inputASocket = this->getInputSocket(3);
- NodeOutput *outputSocket = this->getOutputSocket(0);
+ NodeInput *input_rsocket = this->get_input_socket(0);
+ NodeInput *input_gsocket = this->get_input_socket(1);
+ NodeInput *input_bsocket = this->get_input_socket(2);
+ NodeInput *input_asocket = this->get_input_socket(3);
+ NodeOutput *output_socket = this->get_output_socket(0);
CombineChannelsOperation *operation = new CombineChannelsOperation();
- if (inputRSocket->isLinked()) {
+ if (input_rsocket->is_linked()) {
operation->set_canvas_input_index(0);
}
- else if (inputGSocket->isLinked()) {
+ else if (input_gsocket->is_linked()) {
operation->set_canvas_input_index(1);
}
- else if (inputBSocket->isLinked()) {
+ else if (input_bsocket->is_linked()) {
operation->set_canvas_input_index(2);
}
else {
operation->set_canvas_input_index(3);
}
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(inputRSocket, operation->getInputSocket(0));
- converter.mapInputSocket(inputGSocket, operation->getInputSocket(1));
- converter.mapInputSocket(inputBSocket, operation->getInputSocket(2));
- converter.mapInputSocket(inputASocket, operation->getInputSocket(3));
+ converter.map_input_socket(input_rsocket, operation->get_input_socket(0));
+ converter.map_input_socket(input_gsocket, operation->get_input_socket(1));
+ converter.map_input_socket(input_bsocket, operation->get_input_socket(2));
+ converter.map_input_socket(input_asocket, operation->get_input_socket(3));
- NodeOperation *color_conv = getColorConverter(context);
+ NodeOperation *color_conv = get_color_converter(context);
if (color_conv) {
- converter.addOperation(color_conv);
+ converter.add_operation(color_conv);
- converter.addLink(operation->getOutputSocket(), color_conv->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, color_conv->getOutputSocket());
+ converter.add_link(operation->get_output_socket(), color_conv->get_input_socket(0));
+ converter.map_output_socket(output_socket, color_conv->get_output_socket());
}
else {
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket());
+ converter.map_output_socket(output_socket, operation->get_output_socket());
}
}
-NodeOperation *CombineRGBANode::getColorConverter(const CompositorContext & /*context*/) const
+NodeOperation *CombineRGBANode::get_color_converter(const CompositorContext & /*context*/) const
{
return nullptr; /* no conversion needed */
}
-NodeOperation *CombineHSVANode::getColorConverter(const CompositorContext & /*context*/) const
+NodeOperation *CombineHSVANode::get_color_converter(const CompositorContext & /*context*/) const
{
return new ConvertHSVToRGBOperation();
}
-NodeOperation *CombineYCCANode::getColorConverter(const CompositorContext & /*context*/) const
+NodeOperation *CombineYCCANode::get_color_converter(const CompositorContext & /*context*/) const
{
ConvertYCCToRGBOperation *operation = new ConvertYCCToRGBOperation();
- bNode *editorNode = this->getbNode();
- operation->setMode(editorNode->custom1);
+ bNode *editor_node = this->get_bnode();
+ operation->set_mode(editor_node->custom1);
return operation;
}
-NodeOperation *CombineYUVANode::getColorConverter(const CompositorContext & /*context*/) const
+NodeOperation *CombineYUVANode::get_color_converter(const CompositorContext & /*context*/) const
{
return new ConvertYUVToRGBOperation();
}
diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.h b/source/blender/compositor/nodes/COM_CombineColorNode.h
index 29d3fa37817..3252fc779f4 100644
--- a/source/blender/compositor/nodes/COM_CombineColorNode.h
+++ b/source/blender/compositor/nodes/COM_CombineColorNode.h
@@ -24,48 +24,48 @@ namespace blender::compositor {
class CombineColorNode : public Node {
public:
- CombineColorNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ CombineColorNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
protected:
- virtual NodeOperation *getColorConverter(const CompositorContext &context) const = 0;
+ virtual NodeOperation *get_color_converter(const CompositorContext &context) const = 0;
};
class CombineRGBANode : public CombineColorNode {
public:
- CombineRGBANode(bNode *editorNode) : CombineColorNode(editorNode)
+ CombineRGBANode(bNode *editor_node) : CombineColorNode(editor_node)
{
}
- NodeOperation *getColorConverter(const CompositorContext &context) const override;
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
};
class CombineHSVANode : public CombineColorNode {
public:
- CombineHSVANode(bNode *editorNode) : CombineColorNode(editorNode)
+ CombineHSVANode(bNode *editor_node) : CombineColorNode(editor_node)
{
}
- NodeOperation *getColorConverter(const CompositorContext &context) const override;
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
};
class CombineYCCANode : public CombineColorNode {
public:
- CombineYCCANode(bNode *editorNode) : CombineColorNode(editorNode)
+ CombineYCCANode(bNode *editor_node) : CombineColorNode(editor_node)
{
}
- NodeOperation *getColorConverter(const CompositorContext &context) const override;
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
};
class CombineYUVANode : public CombineColorNode {
public:
- CombineYUVANode(bNode *editorNode) : CombineColorNode(editorNode)
+ CombineYUVANode(bNode *editor_node) : CombineColorNode(editor_node)
{
}
- NodeOperation *getColorConverter(const CompositorContext &context) const override;
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cc b/source/blender/compositor/nodes/COM_CompositorNode.cc
index 262fa550915..5121a7cc123 100644
--- a/source/blender/compositor/nodes/COM_CompositorNode.cc
+++ b/source/blender/compositor/nodes/COM_CompositorNode.cc
@@ -18,48 +18,47 @@
#include "COM_CompositorNode.h"
#include "COM_CompositorOperation.h"
-#include "COM_ExecutionSystem.h"
namespace blender::compositor {
-CompositorNode::CompositorNode(bNode *editorNode) : Node(editorNode)
+CompositorNode::CompositorNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void CompositorNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void CompositorNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *editorNode = this->getbNode();
- bool is_active = (editorNode->flag & NODE_DO_OUTPUT_RECALC) || context.isRendering();
- bool ignore_alpha = (editorNode->custom2 & CMP_NODE_OUTPUT_IGNORE_ALPHA) != 0;
+ bNode *editor_node = this->get_bnode();
+ bool is_active = (editor_node->flag & NODE_DO_OUTPUT_RECALC) || context.is_rendering();
+ bool ignore_alpha = (editor_node->custom2 & CMP_NODE_OUTPUT_IGNORE_ALPHA) != 0;
- NodeInput *imageSocket = this->getInputSocket(0);
- NodeInput *alphaSocket = this->getInputSocket(1);
- NodeInput *depthSocket = this->getInputSocket(2);
+ NodeInput *image_socket = this->get_input_socket(0);
+ NodeInput *alpha_socket = this->get_input_socket(1);
+ NodeInput *depth_socket = this->get_input_socket(2);
- CompositorOperation *compositorOperation = new CompositorOperation();
- compositorOperation->setScene(context.getScene());
- compositorOperation->setSceneName(context.getScene()->id.name);
- compositorOperation->setRenderData(context.getRenderData());
- compositorOperation->setViewName(context.getViewName());
- compositorOperation->setbNodeTree(context.getbNodeTree());
+ CompositorOperation *compositor_operation = new CompositorOperation();
+ compositor_operation->set_scene(context.get_scene());
+ compositor_operation->set_scene_name(context.get_scene()->id.name);
+ compositor_operation->set_render_data(context.get_render_data());
+ compositor_operation->set_view_name(context.get_view_name());
+ compositor_operation->set_bnodetree(context.get_bnodetree());
/* alpha socket gives either 1 or a custom alpha value if "use alpha" is enabled */
- compositorOperation->setUseAlphaInput(ignore_alpha || alphaSocket->isLinked());
- compositorOperation->setActive(is_active);
+ compositor_operation->set_use_alpha_input(ignore_alpha || alpha_socket->is_linked());
+ compositor_operation->set_active(is_active);
- converter.addOperation(compositorOperation);
- converter.mapInputSocket(imageSocket, compositorOperation->getInputSocket(0));
+ converter.add_operation(compositor_operation);
+ converter.map_input_socket(image_socket, compositor_operation->get_input_socket(0));
/* only use alpha link if "use alpha" is enabled */
if (ignore_alpha) {
- converter.addInputValue(compositorOperation->getInputSocket(1), 1.0f);
+ converter.add_input_value(compositor_operation->get_input_socket(1), 1.0f);
}
else {
- converter.mapInputSocket(alphaSocket, compositorOperation->getInputSocket(1));
+ converter.map_input_socket(alpha_socket, compositor_operation->get_input_socket(1));
}
- converter.mapInputSocket(depthSocket, compositorOperation->getInputSocket(2));
+ converter.map_input_socket(depth_socket, compositor_operation->get_input_socket(2));
- converter.addNodeInputPreview(imageSocket);
+ converter.add_node_input_preview(image_socket);
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CompositorNode.h b/source/blender/compositor/nodes/COM_CompositorNode.h
index 4da9f9a766f..68005230ba2 100644
--- a/source/blender/compositor/nodes/COM_CompositorNode.h
+++ b/source/blender/compositor/nodes/COM_CompositorNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class CompositorNode : public Node {
public:
- CompositorNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ CompositorNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc
index ac4e45357dc..c2c4b989007 100644
--- a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc
+++ b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc
@@ -18,15 +18,14 @@
#include "COM_ConvertAlphaNode.h"
#include "COM_ConvertOperation.h"
-#include "COM_ExecutionSystem.h"
namespace blender::compositor {
-void ConvertAlphaNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ConvertAlphaNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
NodeOperation *operation = nullptr;
- bNode *node = this->getbNode();
+ bNode *node = this->get_bnode();
/* value hardcoded in rna_nodetree.c */
if (node->custom1 == 1) {
@@ -36,10 +35,10 @@ void ConvertAlphaNode::convertToOperations(NodeConverter &converter,
operation = new ConvertStraightToPremulOperation();
}
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ConvertAlphaNode.h b/source/blender/compositor/nodes/COM_ConvertAlphaNode.h
index f3d0ef2cd5b..8f26c82c110 100644
--- a/source/blender/compositor/nodes/COM_ConvertAlphaNode.h
+++ b/source/blender/compositor/nodes/COM_ConvertAlphaNode.h
@@ -28,11 +28,11 @@ namespace blender::compositor {
*/
class ConvertAlphaNode : public Node {
public:
- ConvertAlphaNode(bNode *editorNode) : Node(editorNode)
+ ConvertAlphaNode(bNode *editor_node) : Node(editor_node)
{
}
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ConvertColorSpaceNode.cc b/source/blender/compositor/nodes/COM_ConvertColorSpaceNode.cc
new file mode 100644
index 00000000000..4e7bbefc22d
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_ConvertColorSpaceNode.cc
@@ -0,0 +1,100 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "COM_ConvertColorSpaceNode.h"
+
+#include "BKE_node.h"
+
+#include "BLI_utildefines.h"
+
+#include "COM_ConvertColorSpaceOperation.h"
+#include "COM_ConvertOperation.h"
+#include "COM_ExecutionSystem.h"
+#include "COM_ImageOperation.h"
+#include "COM_MultilayerImageOperation.h"
+
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"compositor"};
+
+namespace blender::compositor {
+
+ConvertColorSpaceNode::ConvertColorSpaceNode(bNode *editorNode) : Node(editorNode)
+{
+ /* pass */
+}
+
+void ConvertColorSpaceNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &UNUSED(context)) const
+{
+ bNode *b_node = get_bnode();
+
+ NodeInput *inputSocketImage = this->get_input_socket(0);
+ NodeOutput *outputSocketImage = this->get_output_socket(0);
+
+ NodeConvertColorSpace *settings = static_cast<NodeConvertColorSpace *>(b_node->storage);
+
+ if (!performs_conversion(*settings)) {
+ converter.map_output_socket(get_output_socket(0),
+ converter.add_input_proxy(get_input_socket(0), false));
+ return;
+ }
+
+ ConvertColorSpaceOperation *operation = new ConvertColorSpaceOperation();
+ operation->set_settings((NodeConvertColorSpace *)b_node->storage);
+ converter.add_operation(operation);
+
+ converter.map_input_socket(inputSocketImage, operation->get_input_socket(0));
+ converter.map_output_socket(outputSocketImage, operation->get_output_socket());
+}
+
+bool ConvertColorSpaceNode::performs_conversion(NodeConvertColorSpace &settings) const
+{
+ bNode *b_node = get_bnode();
+
+ if (IMB_colormanagement_space_name_is_data(settings.from_color_space)) {
+ CLOG_INFO(&LOG,
+ 2,
+ "Color space conversion bypassed for node: %s. From color space is data: %s.",
+ b_node->name,
+ settings.from_color_space);
+ return false;
+ }
+
+ if (IMB_colormanagement_space_name_is_data(settings.to_color_space)) {
+ CLOG_INFO(&LOG,
+ 2,
+ "Color space conversion bypassed for node: %s. To color space is data: %s.",
+ b_node->name,
+ settings.to_color_space);
+ return false;
+ }
+
+ if (STREQLEN(
+ settings.from_color_space, settings.to_color_space, sizeof(settings.from_color_space))) {
+ CLOG_INFO(&LOG,
+ 2,
+ "Color space conversion bypassed for node: %s. To and from are the same: %s.",
+ b_node->name,
+ settings.from_color_space);
+ return false;
+ }
+ return true;
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ConvertColorSpaceNode.h b/source/blender/compositor/nodes/COM_ConvertColorSpaceNode.h
new file mode 100644
index 00000000000..b3460abea27
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_ConvertColorSpaceNode.h
@@ -0,0 +1,46 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "COM_Node.h"
+#include "COM_defines.h"
+#include "DNA_image_types.h"
+#include "DNA_node_types.h"
+
+#include "RE_engine.h"
+#include "RE_pipeline.h"
+
+namespace blender::compositor {
+
+/**
+ * \brief ImageNode
+ * \ingroup Node
+ */
+class ConvertColorSpaceNode : public Node {
+ public:
+ ConvertColorSpaceNode(bNode *editorNode);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
+
+ private:
+ /** \brief check if the given settings changes color space. */
+ bool performs_conversion(NodeConvertColorSpace &settings) const;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.cc b/source/blender/compositor/nodes/COM_CornerPinNode.cc
index 3cfa20f4e05..0f7b58db89d 100644
--- a/source/blender/compositor/nodes/COM_CornerPinNode.cc
+++ b/source/blender/compositor/nodes/COM_CornerPinNode.cc
@@ -16,20 +16,19 @@
*/
#include "COM_CornerPinNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_PlaneCornerPinOperation.h"
namespace blender::compositor {
-CornerPinNode::CornerPinNode(bNode *editorNode) : Node(editorNode)
+CornerPinNode::CornerPinNode(bNode *editor_node) : Node(editor_node)
{
}
-void CornerPinNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void CornerPinNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeInput *input_image = this->getInputSocket(0);
+ NodeInput *input_image = this->get_input_socket(0);
/* NOTE: socket order differs between UI node and operations:
* bNode uses intuitive order following top-down layout:
* upper-left, upper-right, lower-left, lower-right
@@ -38,22 +37,22 @@ void CornerPinNode::convertToOperations(NodeConverter &converter,
*/
const int node_corner_index[4] = {3, 4, 2, 1};
- NodeOutput *output_warped_image = this->getOutputSocket(0);
- NodeOutput *output_plane = this->getOutputSocket(1);
+ NodeOutput *output_warped_image = this->get_output_socket(0);
+ NodeOutput *output_plane = this->get_output_socket(1);
PlaneCornerPinWarpImageOperation *warp_image_operation = new PlaneCornerPinWarpImageOperation();
- converter.addOperation(warp_image_operation);
+ converter.add_operation(warp_image_operation);
PlaneCornerPinMaskOperation *plane_mask_operation = new PlaneCornerPinMaskOperation();
- converter.addOperation(plane_mask_operation);
+ converter.add_operation(plane_mask_operation);
- converter.mapInputSocket(input_image, warp_image_operation->getInputSocket(0));
+ converter.map_input_socket(input_image, warp_image_operation->get_input_socket(0));
for (int i = 0; i < 4; i++) {
- NodeInput *corner_input = getInputSocket(node_corner_index[i]);
- converter.mapInputSocket(corner_input, warp_image_operation->getInputSocket(i + 1));
- converter.mapInputSocket(corner_input, plane_mask_operation->getInputSocket(i));
+ NodeInput *corner_input = get_input_socket(node_corner_index[i]);
+ converter.map_input_socket(corner_input, warp_image_operation->get_input_socket(i + 1));
+ converter.map_input_socket(corner_input, plane_mask_operation->get_input_socket(i));
}
- converter.mapOutputSocket(output_warped_image, warp_image_operation->getOutputSocket());
- converter.mapOutputSocket(output_plane, plane_mask_operation->getOutputSocket());
+ converter.map_output_socket(output_warped_image, warp_image_operation->get_output_socket());
+ converter.map_output_socket(output_plane, plane_mask_operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.h b/source/blender/compositor/nodes/COM_CornerPinNode.h
index 779e057ebb5..a1b4d107126 100644
--- a/source/blender/compositor/nodes/COM_CornerPinNode.h
+++ b/source/blender/compositor/nodes/COM_CornerPinNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class CornerPinNode : public Node {
public:
- CornerPinNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ CornerPinNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CropNode.cc b/source/blender/compositor/nodes/COM_CropNode.cc
index 3f01062c789..e33af232f17 100644
--- a/source/blender/compositor/nodes/COM_CropNode.cc
+++ b/source/blender/compositor/nodes/COM_CropNode.cc
@@ -21,31 +21,31 @@
namespace blender::compositor {
-CropNode::CropNode(bNode *editorNode) : Node(editorNode)
+CropNode::CropNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void CropNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void CropNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *node = getbNode();
- NodeTwoXYs *cropSettings = (NodeTwoXYs *)node->storage;
+ bNode *node = get_bnode();
+ NodeTwoXYs *crop_settings = (NodeTwoXYs *)node->storage;
bool relative = (bool)node->custom2;
- bool cropImage = (bool)node->custom1;
+ bool crop_image = (bool)node->custom1;
CropBaseOperation *operation;
- if (cropImage) {
+ if (crop_image) {
operation = new CropImageOperation();
}
else {
operation = new CropOperation();
}
- operation->setCropSettings(cropSettings);
- operation->setRelative(relative);
- converter.addOperation(operation);
+ operation->set_crop_settings(crop_settings);
+ operation->set_relative(relative);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(), operation->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(), operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CropNode.h b/source/blender/compositor/nodes/COM_CropNode.h
index be3c9a268f9..55324bb37df 100644
--- a/source/blender/compositor/nodes/COM_CropNode.h
+++ b/source/blender/compositor/nodes/COM_CropNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class CropNode : public Node {
public:
- CropNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ CropNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cc b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
index c04d98d6a2b..c360e519cf8 100644
--- a/source/blender/compositor/nodes/COM_CryptomatteNode.cc
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
@@ -16,20 +16,16 @@
* Copyright 2018, Blender Foundation.
*/
-#include "COM_CryptomatteNode.h"
#include "BKE_node.h"
-#include "BLI_assert.h"
-#include "BLI_hash_mm3.h"
-#include "BLI_listbase.h"
-#include "BLI_string.h"
+
+#include "NOD_composite.h"
+
#include "COM_ConvertOperation.h"
-#include "COM_CryptomatteOperation.h"
+#include "COM_CryptomatteNode.h"
#include "COM_MultilayerImageOperation.h"
#include "COM_RenderLayersProg.h"
#include "COM_SetAlphaMultiplyOperation.h"
#include "COM_SetColorOperation.h"
-#include <iterator>
-#include <string>
namespace blender::compositor {
@@ -37,41 +33,41 @@ namespace blender::compositor {
/** \name Cryptomatte Base
* \{ */
-void CryptomatteBaseNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void CryptomatteBaseNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- NodeOutput *output_image_socket = this->getOutputSocket(0);
+ NodeOutput *output_image_socket = this->get_output_socket(0);
- bNode *node = this->getbNode();
+ bNode *node = this->get_bnode();
NodeCryptomatte *cryptomatte_settings = static_cast<NodeCryptomatte *>(node->storage);
CryptomatteOperation *cryptomatte_operation = create_cryptomatte_operation(
converter, context, *node, cryptomatte_settings);
- converter.addOperation(cryptomatte_operation);
+ converter.add_operation(cryptomatte_operation);
- NodeOutput *output_matte_socket = this->getOutputSocket(1);
+ NodeOutput *output_matte_socket = this->get_output_socket(1);
SeparateChannelOperation *extract_mask_operation = new SeparateChannelOperation;
- extract_mask_operation->setChannel(3);
- converter.addOperation(extract_mask_operation);
- converter.addLink(cryptomatte_operation->getOutputSocket(0),
- extract_mask_operation->getInputSocket(0));
- converter.mapOutputSocket(output_matte_socket, extract_mask_operation->getOutputSocket(0));
+ extract_mask_operation->set_channel(3);
+ converter.add_operation(extract_mask_operation);
+ converter.add_link(cryptomatte_operation->get_output_socket(0),
+ extract_mask_operation->get_input_socket(0));
+ converter.map_output_socket(output_matte_socket, extract_mask_operation->get_output_socket(0));
- NodeInput *input_image_socket = this->getInputSocket(0);
+ NodeInput *input_image_socket = this->get_input_socket(0);
SetAlphaMultiplyOperation *apply_mask_operation = new SetAlphaMultiplyOperation();
- converter.mapInputSocket(input_image_socket, apply_mask_operation->getInputSocket(0));
- converter.addOperation(apply_mask_operation);
- converter.addLink(extract_mask_operation->getOutputSocket(0),
- apply_mask_operation->getInputSocket(1));
- converter.mapOutputSocket(output_image_socket, apply_mask_operation->getOutputSocket(0));
+ converter.map_input_socket(input_image_socket, apply_mask_operation->get_input_socket(0));
+ converter.add_operation(apply_mask_operation);
+ converter.add_link(extract_mask_operation->get_output_socket(0),
+ apply_mask_operation->get_input_socket(1));
+ converter.map_output_socket(output_image_socket, apply_mask_operation->get_output_socket(0));
- NodeOutput *output_pick_socket = this->getOutputSocket(2);
+ NodeOutput *output_pick_socket = this->get_output_socket(2);
SetAlphaMultiplyOperation *extract_pick_operation = new SetAlphaMultiplyOperation();
- converter.addOperation(extract_pick_operation);
- converter.addInputValue(extract_pick_operation->getInputSocket(1), 1.0f);
- converter.addLink(cryptomatte_operation->getOutputSocket(0),
- extract_pick_operation->getInputSocket(0));
- converter.mapOutputSocket(output_pick_socket, extract_pick_operation->getOutputSocket(0));
+ converter.add_operation(extract_pick_operation);
+ converter.add_input_value(extract_pick_operation->get_input_socket(1), 1.0f);
+ converter.add_link(cryptomatte_operation->get_output_socket(0),
+ extract_pick_operation->get_input_socket(0));
+ converter.map_output_socket(output_pick_socket, extract_pick_operation->get_output_socket(0));
}
/** \} */
@@ -83,7 +79,7 @@ void CryptomatteBaseNode::convertToOperations(NodeConverter &converter,
static std::string prefix_from_node(const CompositorContext &context, const bNode &node)
{
char prefix[MAX_NAME];
- ntreeCompositCryptomatteLayerPrefix(context.getScene(), &node, prefix, sizeof(prefix));
+ ntreeCompositCryptomatteLayerPrefix(context.get_scene(), &node, prefix, sizeof(prefix));
return std::string(prefix, BLI_strnlen(prefix, sizeof(prefix)));
}
@@ -127,7 +123,7 @@ void CryptomatteNode::input_operations_from_render_source(
RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name);
if (render_layer) {
LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) {
- if (context.has_explicit_view() && !STREQ(render_pass->view, context.getViewName())) {
+ if (context.has_explicit_view() && !STREQ(render_pass->view, context.get_view_name())) {
continue;
}
@@ -135,10 +131,10 @@ void CryptomatteNode::input_operations_from_render_source(
if (blender::StringRef(combined_name).startswith(prefix)) {
RenderLayersProg *op = new RenderLayersProg(
render_pass->name, DataType::Color, render_pass->channels);
- op->setScene(scene);
- op->setLayerId(view_layer_id);
- op->setRenderData(context.getRenderData());
- op->setViewName(context.getViewName());
+ op->set_scene(scene);
+ op->set_layer_id(view_layer_id);
+ op->set_render_data(context.get_render_data());
+ op->set_view_name(context.get_view_name());
r_input_operations.append(op);
}
}
@@ -164,7 +160,7 @@ void CryptomatteNode::input_operations_from_image_source(
}
ImageUser *iuser = &cryptomatte_settings->iuser;
- BKE_image_user_frame_calc(image, iuser, context.getFramenumber());
+ BKE_image_user_frame_calc(image, iuser, context.get_framenumber());
ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, nullptr);
if (image->rr) {
@@ -174,7 +170,7 @@ void CryptomatteNode::input_operations_from_image_source(
/* Heuristic to match image name with scene names, check if the view name exists in the
* image. */
view = BLI_findstringindex(
- &image->rr->views, context.getViewName(), offsetof(RenderView, name));
+ &image->rr->views, context.get_view_name(), offsetof(RenderView, name));
if (view == -1) {
view = 0;
}
@@ -196,10 +192,10 @@ void CryptomatteNode::input_operations_from_image_source(
if (blender::StringRef(combined_name).startswith(prefix)) {
MultilayerColorOperation *op = new MultilayerColorOperation(
render_layer, render_pass, view);
- op->setImage(image);
- op->setImageUser(iuser);
+ op->set_image(image);
+ op->set_image_user(iuser);
iuser->layer = layer_index;
- op->setFramenumber(context.getFramenumber());
+ op->set_framenumber(context.get_framenumber());
r_input_operations.append(op);
}
}
@@ -224,10 +220,10 @@ Vector<NodeOperation *> CryptomatteNode::create_input_operations(const Composito
if (input_operations.is_empty()) {
SetColorOperation *op = new SetColorOperation();
- op->setChannel1(0.0f);
- op->setChannel2(1.0f);
- op->setChannel3(0.0f);
- op->setChannel4(0.0f);
+ op->set_channel1(0.0f);
+ op->set_channel2(1.0f);
+ op->set_channel3(0.0f);
+ op->set_channel4(0.0f);
input_operations.append(op);
}
return input_operations;
@@ -241,11 +237,11 @@ CryptomatteOperation *CryptomatteNode::create_cryptomatte_operation(
Vector<NodeOperation *> input_operations = create_input_operations(context, node);
CryptomatteOperation *operation = new CryptomatteOperation(input_operations.size());
LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptomatte_settings->entries) {
- operation->addObjectIndex(cryptomatte_entry->encoded_hash);
+ operation->add_object_index(cryptomatte_entry->encoded_hash);
}
for (int i = 0; i < input_operations.size(); ++i) {
- converter.addOperation(input_operations[i]);
- converter.addLink(input_operations[i]->getOutputSocket(), operation->getInputSocket(i));
+ converter.add_operation(input_operations[i]);
+ converter.add_link(input_operations[i]->get_output_socket(), operation->get_input_socket(i));
}
return operation;
}
@@ -262,16 +258,16 @@ CryptomatteOperation *CryptomatteLegacyNode::create_cryptomatte_operation(
const bNode &UNUSED(node),
const NodeCryptomatte *cryptomatte_settings) const
{
- const int num_inputs = inputs.size() - 1;
+ const int num_inputs = inputs_.size() - 1;
CryptomatteOperation *operation = new CryptomatteOperation(num_inputs);
if (cryptomatte_settings) {
LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptomatte_settings->entries) {
- operation->addObjectIndex(cryptomatte_entry->encoded_hash);
+ operation->add_object_index(cryptomatte_entry->encoded_hash);
}
}
for (int i = 0; i < num_inputs; i++) {
- converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i));
+ converter.map_input_socket(this->get_input_socket(i + 1), operation->get_input_socket(i));
}
return operation;
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.h b/source/blender/compositor/nodes/COM_CryptomatteNode.h
index eacb49e2033..7ca1084886b 100644
--- a/source/blender/compositor/nodes/COM_CryptomatteNode.h
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.h
@@ -38,8 +38,8 @@ class CryptomatteBaseNode : public Node {
}
public:
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
protected:
virtual CryptomatteOperation *create_cryptomatte_operation(
diff --git a/source/blender/compositor/nodes/COM_DefocusNode.cc b/source/blender/compositor/nodes/COM_DefocusNode.cc
index 2023e4f7118..684f9014c3c 100644
--- a/source/blender/compositor/nodes/COM_DefocusNode.cc
+++ b/source/blender/compositor/nodes/COM_DefocusNode.cc
@@ -19,71 +19,65 @@
#include "COM_DefocusNode.h"
#include "COM_BokehImageOperation.h"
#include "COM_ConvertDepthToRadiusOperation.h"
-#include "COM_ExecutionSystem.h"
-#include "COM_FastGaussianBlurOperation.h"
#include "COM_GammaCorrectOperation.h"
#include "COM_MathBaseOperation.h"
#include "COM_SetValueOperation.h"
#include "COM_VariableSizeBokehBlurOperation.h"
-#include "DNA_camera_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
namespace blender::compositor {
-DefocusNode::DefocusNode(bNode *editorNode) : Node(editorNode)
+DefocusNode::DefocusNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void DefocusNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void DefocusNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *node = this->getbNode();
+ bNode *node = this->get_bnode();
NodeDefocus *data = (NodeDefocus *)node->storage;
- Scene *scene = node->id ? (Scene *)node->id : context.getScene();
+ Scene *scene = node->id ? (Scene *)node->id : context.get_scene();
Object *camob = scene ? scene->camera : nullptr;
- NodeOperation *radiusOperation;
+ NodeOperation *radius_operation;
if (data->no_zbuf) {
MathMultiplyOperation *multiply = new MathMultiplyOperation();
SetValueOperation *multiplier = new SetValueOperation();
- multiplier->setValue(data->scale);
- SetValueOperation *maxRadius = new SetValueOperation();
- maxRadius->setValue(data->maxblur);
+ multiplier->set_value(data->scale);
+ SetValueOperation *max_radius = new SetValueOperation();
+ max_radius->set_value(data->maxblur);
MathMinimumOperation *minimize = new MathMinimumOperation();
- converter.addOperation(multiply);
- converter.addOperation(multiplier);
- converter.addOperation(maxRadius);
- converter.addOperation(minimize);
+ converter.add_operation(multiply);
+ converter.add_operation(multiplier);
+ converter.add_operation(max_radius);
+ converter.add_operation(minimize);
- converter.mapInputSocket(getInputSocket(1), multiply->getInputSocket(0));
- converter.addLink(multiplier->getOutputSocket(), multiply->getInputSocket(1));
- converter.addLink(multiply->getOutputSocket(), minimize->getInputSocket(0));
- converter.addLink(maxRadius->getOutputSocket(), minimize->getInputSocket(1));
+ converter.map_input_socket(get_input_socket(1), multiply->get_input_socket(0));
+ converter.add_link(multiplier->get_output_socket(), multiply->get_input_socket(1));
+ converter.add_link(multiply->get_output_socket(), minimize->get_input_socket(0));
+ converter.add_link(max_radius->get_output_socket(), minimize->get_input_socket(1));
- radiusOperation = minimize;
+ radius_operation = minimize;
}
else {
ConvertDepthToRadiusOperation *radius_op = new ConvertDepthToRadiusOperation();
- radius_op->setCameraObject(camob);
- radius_op->setfStop(data->fstop);
- radius_op->setMaxRadius(data->maxblur);
- converter.addOperation(radius_op);
+ radius_op->set_camera_object(camob);
+ radius_op->setf_stop(data->fstop);
+ radius_op->set_max_radius(data->maxblur);
+ converter.add_operation(radius_op);
- converter.mapInputSocket(getInputSocket(1), radius_op->getInputSocket(0));
+ converter.map_input_socket(get_input_socket(1), radius_op->get_input_socket(0));
FastGaussianBlurValueOperation *blur = new FastGaussianBlurValueOperation();
/* maintain close pixels so far Z values don't bleed into the foreground */
- blur->setOverlay(FAST_GAUSS_OVERLAY_MIN);
- converter.addOperation(blur);
+ blur->set_overlay(FAST_GAUSS_OVERLAY_MIN);
+ converter.add_operation(blur);
- converter.addLink(radius_op->getOutputSocket(0), blur->getInputSocket(0));
- radius_op->setPostBlur(blur);
+ converter.add_link(radius_op->get_output_socket(0), blur->get_input_socket(0));
+ radius_op->set_post_blur(blur);
- radiusOperation = blur;
+ radius_operation = blur;
}
NodeBokehImage *bokehdata = new NodeBokehImage();
@@ -98,49 +92,49 @@ void DefocusNode::convertToOperations(NodeConverter &converter,
bokehdata->lensshift = 0.0f;
BokehImageOperation *bokeh = new BokehImageOperation();
- bokeh->setData(bokehdata);
- bokeh->deleteDataOnFinish();
- converter.addOperation(bokeh);
+ bokeh->set_data(bokehdata);
+ bokeh->delete_data_on_finish();
+ converter.add_operation(bokeh);
#ifdef COM_DEFOCUS_SEARCH
InverseSearchRadiusOperation *search = new InverseSearchRadiusOperation();
- search->setMaxBlur(data->maxblur);
- converter.addOperation(search);
+ search->set_max_blur(data->maxblur);
+ converter.add_operation(search);
- converter.addLink(radiusOperation->getOutputSocket(0), search->getInputSocket(0));
+ converter.add_link(radius_operation->get_output_socket(0), search->get_input_socket(0));
#endif
VariableSizeBokehBlurOperation *operation = new VariableSizeBokehBlurOperation();
if (data->preview) {
- operation->setQuality(eCompositorQuality::Low);
+ operation->set_quality(eCompositorQuality::Low);
}
else {
- operation->setQuality(context.getQuality());
+ operation->set_quality(context.get_quality());
}
- operation->setMaxBlur(data->maxblur);
- operation->setThreshold(data->bthresh);
- converter.addOperation(operation);
+ operation->set_max_blur(data->maxblur);
+ operation->set_threshold(data->bthresh);
+ converter.add_operation(operation);
- converter.addLink(bokeh->getOutputSocket(), operation->getInputSocket(1));
- converter.addLink(radiusOperation->getOutputSocket(), operation->getInputSocket(2));
+ converter.add_link(bokeh->get_output_socket(), operation->get_input_socket(1));
+ converter.add_link(radius_operation->get_output_socket(), operation->get_input_socket(2));
#ifdef COM_DEFOCUS_SEARCH
- converter.addLink(search->getOutputSocket(), operation->getInputSocket(3));
+ converter.add_link(search->get_output_socket(), operation->get_input_socket(3));
#endif
if (data->gamco) {
GammaCorrectOperation *correct = new GammaCorrectOperation();
- converter.addOperation(correct);
+ converter.add_operation(correct);
GammaUncorrectOperation *inverse = new GammaUncorrectOperation();
- converter.addOperation(inverse);
+ converter.add_operation(inverse);
- converter.mapInputSocket(getInputSocket(0), correct->getInputSocket(0));
- converter.addLink(correct->getOutputSocket(), operation->getInputSocket(0));
- converter.addLink(operation->getOutputSocket(), inverse->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(), inverse->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), correct->get_input_socket(0));
+ converter.add_link(correct->get_output_socket(), operation->get_input_socket(0));
+ converter.add_link(operation->get_output_socket(), inverse->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(), inverse->get_output_socket());
}
else {
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(), operation->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(), operation->get_output_socket());
}
}
diff --git a/source/blender/compositor/nodes/COM_DefocusNode.h b/source/blender/compositor/nodes/COM_DefocusNode.h
index 5e51a0ccd52..58993495bee 100644
--- a/source/blender/compositor/nodes/COM_DefocusNode.h
+++ b/source/blender/compositor/nodes/COM_DefocusNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class DefocusNode : public Node {
public:
- DefocusNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ DefocusNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.cc b/source/blender/compositor/nodes/COM_DenoiseNode.cc
index cc9328414ef..2ff8870f716 100644
--- a/source/blender/compositor/nodes/COM_DenoiseNode.cc
+++ b/source/blender/compositor/nodes/COM_DenoiseNode.cc
@@ -17,57 +17,54 @@
*/
#include "COM_DenoiseNode.h"
#include "COM_DenoiseOperation.h"
-#include "COM_MixOperation.h"
-#include "COM_SetValueOperation.h"
-#include "DNA_node_types.h"
namespace blender::compositor {
-DenoiseNode::DenoiseNode(bNode *editorNode) : Node(editorNode)
+DenoiseNode::DenoiseNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void DenoiseNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void DenoiseNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
if (!COM_is_denoise_supported()) {
- converter.mapOutputSocket(getOutputSocket(0),
- converter.addInputProxy(getInputSocket(0), false));
+ converter.map_output_socket(get_output_socket(0),
+ converter.add_input_proxy(get_input_socket(0), false));
return;
}
- bNode *node = this->getbNode();
+ bNode *node = this->get_bnode();
NodeDenoise *denoise = (NodeDenoise *)node->storage;
DenoiseOperation *operation = new DenoiseOperation();
- converter.addOperation(operation);
- operation->setDenoiseSettings(denoise);
+ converter.add_operation(operation);
+ operation->set_denoise_settings(denoise);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
if (denoise && denoise->prefilter == CMP_NODE_DENOISE_PREFILTER_ACCURATE) {
{
DenoisePrefilterOperation *normal_prefilter = new DenoisePrefilterOperation(
DataType::Vector);
normal_prefilter->set_image_name("normal");
- converter.addOperation(normal_prefilter);
- converter.mapInputSocket(getInputSocket(1), normal_prefilter->getInputSocket(0));
- converter.addLink(normal_prefilter->getOutputSocket(), operation->getInputSocket(1));
+ converter.add_operation(normal_prefilter);
+ converter.map_input_socket(get_input_socket(1), normal_prefilter->get_input_socket(0));
+ converter.add_link(normal_prefilter->get_output_socket(), operation->get_input_socket(1));
}
{
DenoisePrefilterOperation *albedo_prefilter = new DenoisePrefilterOperation(DataType::Color);
albedo_prefilter->set_image_name("albedo");
- converter.addOperation(albedo_prefilter);
- converter.mapInputSocket(getInputSocket(2), albedo_prefilter->getInputSocket(0));
- converter.addLink(albedo_prefilter->getOutputSocket(), operation->getInputSocket(2));
+ converter.add_operation(albedo_prefilter);
+ converter.map_input_socket(get_input_socket(2), albedo_prefilter->get_input_socket(0));
+ converter.add_link(albedo_prefilter->get_output_socket(), operation->get_input_socket(2));
}
}
else {
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_input_socket(get_input_socket(2), operation->get_input_socket(2));
}
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.h b/source/blender/compositor/nodes/COM_DenoiseNode.h
index 91be8e3e3ad..7e18c22c1e9 100644
--- a/source/blender/compositor/nodes/COM_DenoiseNode.h
+++ b/source/blender/compositor/nodes/COM_DenoiseNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class DenoiseNode : public Node {
public:
- DenoiseNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ DenoiseNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_DespeckleNode.cc b/source/blender/compositor/nodes/COM_DespeckleNode.cc
index beda479025d..12c9d50f214 100644
--- a/source/blender/compositor/nodes/COM_DespeckleNode.cc
+++ b/source/blender/compositor/nodes/COM_DespeckleNode.cc
@@ -17,36 +17,33 @@
*/
#include "COM_DespeckleNode.h"
-#include "BLI_math.h"
#include "COM_DespeckleOperation.h"
-#include "COM_ExecutionSystem.h"
-#include "DNA_scene_types.h"
namespace blender::compositor {
-DespeckleNode::DespeckleNode(bNode *editorNode) : Node(editorNode)
+DespeckleNode::DespeckleNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void DespeckleNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void DespeckleNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *editorNode = this->getbNode();
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeInput *inputImageSocket = this->getInputSocket(1);
- NodeOutput *outputSocket = this->getOutputSocket(0);
+ bNode *editor_node = this->get_bnode();
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeInput *input_image_socket = this->get_input_socket(1);
+ NodeOutput *output_socket = this->get_output_socket(0);
DespeckleOperation *operation = new DespeckleOperation();
- operation->setThreshold(editorNode->custom3);
- operation->setThresholdNeighbor(editorNode->custom4);
- converter.addOperation(operation);
+ operation->set_threshold(editor_node->custom3);
+ operation->set_threshold_neighbor(editor_node->custom4);
+ converter.add_operation(operation);
- converter.mapInputSocket(inputImageSocket, operation->getInputSocket(0));
- converter.mapInputSocket(inputSocket, operation->getInputSocket(1));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket());
+ converter.map_input_socket(input_image_socket, operation->get_input_socket(0));
+ converter.map_input_socket(input_socket, operation->get_input_socket(1));
+ converter.map_output_socket(output_socket, operation->get_output_socket());
- converter.addPreview(operation->getOutputSocket(0));
+ converter.add_preview(operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_DespeckleNode.h b/source/blender/compositor/nodes/COM_DespeckleNode.h
index 2f268e99e1b..2c3af600aed 100644
--- a/source/blender/compositor/nodes/COM_DespeckleNode.h
+++ b/source/blender/compositor/nodes/COM_DespeckleNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class DespeckleNode : public Node {
public:
- DespeckleNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ DespeckleNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc
index 8c989bfc04e..ceb5be7bd08 100644
--- a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc
+++ b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc
@@ -17,42 +17,41 @@
*/
#include "COM_DifferenceMatteNode.h"
-#include "BKE_node.h"
#include "COM_DifferenceMatteOperation.h"
#include "COM_SetAlphaMultiplyOperation.h"
namespace blender::compositor {
-DifferenceMatteNode::DifferenceMatteNode(bNode *editorNode) : Node(editorNode)
+DifferenceMatteNode::DifferenceMatteNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void DifferenceMatteNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void DifferenceMatteNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeInput *inputSocket2 = this->getInputSocket(1);
- NodeOutput *outputSocketImage = this->getOutputSocket(0);
- NodeOutput *outputSocketMatte = this->getOutputSocket(1);
- bNode *editorNode = this->getbNode();
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeInput *input_socket2 = this->get_input_socket(1);
+ NodeOutput *output_socket_image = this->get_output_socket(0);
+ NodeOutput *output_socket_matte = this->get_output_socket(1);
+ bNode *editor_node = this->get_bnode();
- DifferenceMatteOperation *operationSet = new DifferenceMatteOperation();
- operationSet->setSettings((NodeChroma *)editorNode->storage);
- converter.addOperation(operationSet);
+ DifferenceMatteOperation *operation_set = new DifferenceMatteOperation();
+ operation_set->set_settings((NodeChroma *)editor_node->storage);
+ converter.add_operation(operation_set);
- converter.mapInputSocket(inputSocket, operationSet->getInputSocket(0));
- converter.mapInputSocket(inputSocket2, operationSet->getInputSocket(1));
- converter.mapOutputSocket(outputSocketMatte, operationSet->getOutputSocket(0));
+ converter.map_input_socket(input_socket, operation_set->get_input_socket(0));
+ converter.map_input_socket(input_socket2, operation_set->get_input_socket(1));
+ converter.map_output_socket(output_socket_matte, operation_set->get_output_socket(0));
SetAlphaMultiplyOperation *operation = new SetAlphaMultiplyOperation();
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.addLink(operationSet->getOutputSocket(), operation->getInputSocket(1));
- converter.mapOutputSocket(outputSocketImage, operation->getOutputSocket());
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.add_link(operation_set->get_output_socket(), operation->get_input_socket(1));
+ converter.map_output_socket(output_socket_image, operation->get_output_socket());
- converter.addPreview(operation->getOutputSocket());
+ converter.add_preview(operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_DifferenceMatteNode.h b/source/blender/compositor/nodes/COM_DifferenceMatteNode.h
index a173c723192..f99d4022507 100644
--- a/source/blender/compositor/nodes/COM_DifferenceMatteNode.h
+++ b/source/blender/compositor/nodes/COM_DifferenceMatteNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class DifferenceMatteNode : public Node {
public:
- DifferenceMatteNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ DifferenceMatteNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_DilateErodeNode.cc b/source/blender/compositor/nodes/COM_DilateErodeNode.cc
index 1867014f64b..b121fcb3724 100644
--- a/source/blender/compositor/nodes/COM_DilateErodeNode.cc
+++ b/source/blender/compositor/nodes/COM_DilateErodeNode.cc
@@ -17,135 +17,133 @@
*/
#include "COM_DilateErodeNode.h"
-#include "BLI_math.h"
#include "COM_AntiAliasOperation.h"
#include "COM_DilateErodeOperation.h"
-#include "COM_ExecutionSystem.h"
#include "COM_GaussianAlphaXBlurOperation.h"
#include "COM_GaussianAlphaYBlurOperation.h"
namespace blender::compositor {
-DilateErodeNode::DilateErodeNode(bNode *editorNode) : Node(editorNode)
+DilateErodeNode::DilateErodeNode(bNode *editor_node) : Node(editor_node)
{
/* initialize node data */
- NodeBlurData *data = &m_alpha_blur;
+ NodeBlurData *data = &alpha_blur_;
memset(data, 0, sizeof(NodeBlurData));
data->filtertype = R_FILTER_GAUSS;
- if (editorNode->custom2 > 0) {
- data->sizex = data->sizey = editorNode->custom2;
+ if (editor_node->custom2 > 0) {
+ data->sizex = data->sizey = editor_node->custom2;
}
else {
- data->sizex = data->sizey = -editorNode->custom2;
+ data->sizex = data->sizey = -editor_node->custom2;
}
}
-void DilateErodeNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void DilateErodeNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *editorNode = this->getbNode();
- if (editorNode->custom1 == CMP_NODE_DILATEERODE_DISTANCE_THRESH) {
+ bNode *editor_node = this->get_bnode();
+ if (editor_node->custom1 == CMP_NODE_DILATEERODE_DISTANCE_THRESH) {
DilateErodeThresholdOperation *operation = new DilateErodeThresholdOperation();
- operation->setDistance(editorNode->custom2);
- operation->setInset(editorNode->custom3);
- converter.addOperation(operation);
+ operation->set_distance(editor_node->custom2);
+ operation->set_inset(editor_node->custom3);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
- if (editorNode->custom3 < 2.0f) {
- AntiAliasOperation *antiAlias = new AntiAliasOperation();
- converter.addOperation(antiAlias);
+ if (editor_node->custom3 < 2.0f) {
+ AntiAliasOperation *anti_alias = new AntiAliasOperation();
+ converter.add_operation(anti_alias);
- converter.addLink(operation->getOutputSocket(), antiAlias->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(0), antiAlias->getOutputSocket(0));
+ converter.add_link(operation->get_output_socket(), anti_alias->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(0), anti_alias->get_output_socket(0));
}
else {
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
}
- else if (editorNode->custom1 == CMP_NODE_DILATEERODE_DISTANCE) {
- if (editorNode->custom2 > 0) {
+ else if (editor_node->custom1 == CMP_NODE_DILATEERODE_DISTANCE) {
+ if (editor_node->custom2 > 0) {
DilateDistanceOperation *operation = new DilateDistanceOperation();
- operation->setDistance(editorNode->custom2);
- converter.addOperation(operation);
+ operation->set_distance(editor_node->custom2);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
else {
ErodeDistanceOperation *operation = new ErodeDistanceOperation();
- operation->setDistance(-editorNode->custom2);
- converter.addOperation(operation);
+ operation->set_distance(-editor_node->custom2);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
}
- else if (editorNode->custom1 == CMP_NODE_DILATEERODE_DISTANCE_FEATHER) {
+ else if (editor_node->custom1 == CMP_NODE_DILATEERODE_DISTANCE_FEATHER) {
/* this uses a modified gaussian blur function otherwise its far too slow */
- eCompositorQuality quality = context.getQuality();
+ eCompositorQuality quality = context.get_quality();
GaussianAlphaXBlurOperation *operationx = new GaussianAlphaXBlurOperation();
- operationx->setData(&m_alpha_blur);
- operationx->setQuality(quality);
- operationx->setFalloff(PROP_SMOOTH);
- converter.addOperation(operationx);
+ operationx->set_data(&alpha_blur_);
+ operationx->set_quality(quality);
+ operationx->set_falloff(PROP_SMOOTH);
+ converter.add_operation(operationx);
- converter.mapInputSocket(getInputSocket(0), operationx->getInputSocket(0));
- // converter.mapInputSocket(getInputSocket(1), operationx->getInputSocket(1)); // no size input
- // yet
+ converter.map_input_socket(get_input_socket(0), operationx->get_input_socket(0));
+ // converter.map_input_socket(get_input_socket(1), operationx->get_input_socket(1)); // no size
+ // input yet
GaussianAlphaYBlurOperation *operationy = new GaussianAlphaYBlurOperation();
- operationy->setData(&m_alpha_blur);
- operationy->setQuality(quality);
- operationy->setFalloff(PROP_SMOOTH);
- converter.addOperation(operationy);
+ operationy->set_data(&alpha_blur_);
+ operationy->set_quality(quality);
+ operationy->set_falloff(PROP_SMOOTH);
+ converter.add_operation(operationy);
- converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0));
- // converter.mapInputSocket(getInputSocket(1), operationy->getInputSocket(1)); // no size input
- // yet
- converter.mapOutputSocket(getOutputSocket(0), operationy->getOutputSocket());
+ converter.add_link(operationx->get_output_socket(), operationy->get_input_socket(0));
+ // converter.map_input_socket(get_input_socket(1), operationy->get_input_socket(1)); // no size
+ // input yet
+ converter.map_output_socket(get_output_socket(0), operationy->get_output_socket());
- converter.addPreview(operationy->getOutputSocket());
+ converter.add_preview(operationy->get_output_socket());
/* TODO? */
/* see gaussian blue node for original usage */
#if 0
- if (!connectedSizeSocket) {
- operationx->setSize(size);
- operationy->setSize(size);
+ if (!connected_size_socket) {
+ operationx->set_size(size);
+ operationy->set_size(size);
}
#else
- operationx->setSize(1.0f);
- operationy->setSize(1.0f);
+ operationx->set_size(1.0f);
+ operationy->set_size(1.0f);
#endif
- operationx->setSubtract(editorNode->custom2 < 0);
- operationy->setSubtract(editorNode->custom2 < 0);
+ operationx->set_subtract(editor_node->custom2 < 0);
+ operationy->set_subtract(editor_node->custom2 < 0);
- if (editorNode->storage) {
- NodeDilateErode *data_storage = (NodeDilateErode *)editorNode->storage;
- operationx->setFalloff(data_storage->falloff);
- operationy->setFalloff(data_storage->falloff);
+ if (editor_node->storage) {
+ NodeDilateErode *data_storage = (NodeDilateErode *)editor_node->storage;
+ operationx->set_falloff(data_storage->falloff);
+ operationy->set_falloff(data_storage->falloff);
}
}
else {
- if (editorNode->custom2 > 0) {
+ if (editor_node->custom2 > 0) {
DilateStepOperation *operation = new DilateStepOperation();
- operation->setIterations(editorNode->custom2);
- converter.addOperation(operation);
+ operation->set_iterations(editor_node->custom2);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
else {
ErodeStepOperation *operation = new ErodeStepOperation();
- operation->setIterations(-editorNode->custom2);
- converter.addOperation(operation);
+ operation->set_iterations(-editor_node->custom2);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
}
}
diff --git a/source/blender/compositor/nodes/COM_DilateErodeNode.h b/source/blender/compositor/nodes/COM_DilateErodeNode.h
index 7684d7e3834..df6abe7a6b6 100644
--- a/source/blender/compositor/nodes/COM_DilateErodeNode.h
+++ b/source/blender/compositor/nodes/COM_DilateErodeNode.h
@@ -28,12 +28,12 @@ namespace blender::compositor {
*/
class DilateErodeNode : public Node {
/** only used for blurring alpha, since the dilate/erode node doesn't have this. */
- NodeBlurData m_alpha_blur;
+ NodeBlurData alpha_blur_;
public:
- DilateErodeNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ DilateErodeNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc b/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc
index 90c4236bce8..b8e3e44f41f 100644
--- a/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc
+++ b/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc
@@ -18,27 +18,25 @@
#include "COM_DirectionalBlurNode.h"
#include "COM_DirectionalBlurOperation.h"
-#include "COM_ExecutionSystem.h"
-#include "DNA_node_types.h"
namespace blender::compositor {
-DirectionalBlurNode::DirectionalBlurNode(bNode *editorNode) : Node(editorNode)
+DirectionalBlurNode::DirectionalBlurNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void DirectionalBlurNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void DirectionalBlurNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- NodeDBlurData *data = (NodeDBlurData *)this->getbNode()->storage;
+ NodeDBlurData *data = (NodeDBlurData *)this->get_bnode()->storage;
DirectionalBlurOperation *operation = new DirectionalBlurOperation();
- operation->setQuality(context.getQuality());
- operation->setData(data);
- converter.addOperation(operation);
+ operation->set_quality(context.get_quality());
+ operation->set_data(data);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_DirectionalBlurNode.h b/source/blender/compositor/nodes/COM_DirectionalBlurNode.h
index ce3ef378aaf..96a5122d134 100644
--- a/source/blender/compositor/nodes/COM_DirectionalBlurNode.h
+++ b/source/blender/compositor/nodes/COM_DirectionalBlurNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class DirectionalBlurNode : public Node {
public:
- DirectionalBlurNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ DirectionalBlurNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_DisplaceNode.cc b/source/blender/compositor/nodes/COM_DisplaceNode.cc
index f2ec750c595..06208fb7d89 100644
--- a/source/blender/compositor/nodes/COM_DisplaceNode.cc
+++ b/source/blender/compositor/nodes/COM_DisplaceNode.cc
@@ -19,32 +19,31 @@
#include "COM_DisplaceNode.h"
#include "COM_DisplaceOperation.h"
#include "COM_DisplaceSimpleOperation.h"
-#include "COM_ExecutionSystem.h"
namespace blender::compositor {
-DisplaceNode::DisplaceNode(bNode *editorNode) : Node(editorNode)
+DisplaceNode::DisplaceNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void DisplaceNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void DisplaceNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
NodeOperation *operation;
- if (context.getQuality() == eCompositorQuality::Low) {
+ if (context.get_quality() == eCompositorQuality::Low) {
operation = new DisplaceSimpleOperation();
}
else {
operation = new DisplaceOperation();
}
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2));
- converter.mapInputSocket(getInputSocket(3), operation->getInputSocket(3));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_input_socket(get_input_socket(2), operation->get_input_socket(2));
+ converter.map_input_socket(get_input_socket(3), operation->get_input_socket(3));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_DisplaceNode.h b/source/blender/compositor/nodes/COM_DisplaceNode.h
index b2495839da3..394624e8f60 100644
--- a/source/blender/compositor/nodes/COM_DisplaceNode.h
+++ b/source/blender/compositor/nodes/COM_DisplaceNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class DisplaceNode : public Node {
public:
- DisplaceNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ DisplaceNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_DistanceMatteNode.cc b/source/blender/compositor/nodes/COM_DistanceMatteNode.cc
index 4450c4a2f4a..db78e60fbbe 100644
--- a/source/blender/compositor/nodes/COM_DistanceMatteNode.cc
+++ b/source/blender/compositor/nodes/COM_DistanceMatteNode.cc
@@ -17,85 +17,84 @@
*/
#include "COM_DistanceMatteNode.h"
-#include "BKE_node.h"
#include "COM_ConvertOperation.h"
-#include "COM_DistanceRGBMatteOperation.h"
#include "COM_DistanceYCCMatteOperation.h"
#include "COM_SetAlphaMultiplyOperation.h"
namespace blender::compositor {
-DistanceMatteNode::DistanceMatteNode(bNode *editorNode) : Node(editorNode)
+DistanceMatteNode::DistanceMatteNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void DistanceMatteNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void DistanceMatteNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *editorsnode = getbNode();
+ bNode *editorsnode = get_bnode();
NodeChroma *storage = (NodeChroma *)editorsnode->storage;
- NodeInput *inputSocketImage = this->getInputSocket(0);
- NodeInput *inputSocketKey = this->getInputSocket(1);
- NodeOutput *outputSocketImage = this->getOutputSocket(0);
- NodeOutput *outputSocketMatte = this->getOutputSocket(1);
+ NodeInput *input_socket_image = this->get_input_socket(0);
+ NodeInput *input_socket_key = this->get_input_socket(1);
+ NodeOutput *output_socket_image = this->get_output_socket(0);
+ NodeOutput *output_socket_matte = this->get_output_socket(1);
- SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation();
- converter.addOperation(operationAlpha);
+ SetAlphaMultiplyOperation *operation_alpha = new SetAlphaMultiplyOperation();
+ converter.add_operation(operation_alpha);
/* work in RGB color space */
NodeOperation *operation;
if (storage->channel == 1) {
DistanceRGBMatteOperation *matte = new DistanceRGBMatteOperation();
- matte->setSettings(storage);
- converter.addOperation(matte);
+ matte->set_settings(storage);
+ converter.add_operation(matte);
- converter.mapInputSocket(inputSocketImage, matte->getInputSocket(0));
- converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0));
+ converter.map_input_socket(input_socket_image, matte->get_input_socket(0));
+ converter.map_input_socket(input_socket_image, operation_alpha->get_input_socket(0));
- converter.mapInputSocket(inputSocketKey, matte->getInputSocket(1));
+ converter.map_input_socket(input_socket_key, matte->get_input_socket(1));
operation = matte;
}
/* work in YCbCr color space */
else {
DistanceYCCMatteOperation *matte = new DistanceYCCMatteOperation();
- matte->setSettings(storage);
- converter.addOperation(matte);
+ matte->set_settings(storage);
+ converter.add_operation(matte);
- ConvertRGBToYCCOperation *operationYCCImage = new ConvertRGBToYCCOperation();
- ConvertRGBToYCCOperation *operationYCCMatte = new ConvertRGBToYCCOperation();
- operationYCCImage->setMode(BLI_YCC_ITU_BT709);
- operationYCCMatte->setMode(BLI_YCC_ITU_BT709);
- converter.addOperation(operationYCCImage);
- converter.addOperation(operationYCCMatte);
+ ConvertRGBToYCCOperation *operation_yccimage = new ConvertRGBToYCCOperation();
+ ConvertRGBToYCCOperation *operation_yccmatte = new ConvertRGBToYCCOperation();
+ operation_yccimage->set_mode(BLI_YCC_ITU_BT709);
+ operation_yccmatte->set_mode(BLI_YCC_ITU_BT709);
+ converter.add_operation(operation_yccimage);
+ converter.add_operation(operation_yccmatte);
- converter.mapInputSocket(inputSocketImage, operationYCCImage->getInputSocket(0));
- converter.addLink(operationYCCImage->getOutputSocket(), matte->getInputSocket(0));
- converter.addLink(operationYCCImage->getOutputSocket(), operationAlpha->getInputSocket(0));
+ converter.map_input_socket(input_socket_image, operation_yccimage->get_input_socket(0));
+ converter.add_link(operation_yccimage->get_output_socket(), matte->get_input_socket(0));
+ converter.add_link(operation_yccimage->get_output_socket(),
+ operation_alpha->get_input_socket(0));
- converter.mapInputSocket(inputSocketKey, operationYCCMatte->getInputSocket(0));
- converter.addLink(operationYCCMatte->getOutputSocket(), matte->getInputSocket(1));
+ converter.map_input_socket(input_socket_key, operation_yccmatte->get_input_socket(0));
+ converter.add_link(operation_yccmatte->get_output_socket(), matte->get_input_socket(1));
operation = matte;
}
- converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket(0));
- converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1));
+ converter.map_output_socket(output_socket_matte, operation->get_output_socket(0));
+ converter.add_link(operation->get_output_socket(), operation_alpha->get_input_socket(1));
if (storage->channel != 1) {
ConvertYCCToRGBOperation *inv_convert = new ConvertYCCToRGBOperation();
- inv_convert->setMode(BLI_YCC_ITU_BT709);
+ inv_convert->set_mode(BLI_YCC_ITU_BT709);
- converter.addOperation(inv_convert);
- converter.addLink(operationAlpha->getOutputSocket(0), inv_convert->getInputSocket(0));
- converter.mapOutputSocket(outputSocketImage, inv_convert->getOutputSocket());
- converter.addPreview(inv_convert->getOutputSocket());
+ converter.add_operation(inv_convert);
+ converter.add_link(operation_alpha->get_output_socket(0), inv_convert->get_input_socket(0));
+ converter.map_output_socket(output_socket_image, inv_convert->get_output_socket());
+ converter.add_preview(inv_convert->get_output_socket());
}
else {
- converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket());
- converter.addPreview(operationAlpha->getOutputSocket());
+ converter.map_output_socket(output_socket_image, operation_alpha->get_output_socket());
+ converter.add_preview(operation_alpha->get_output_socket());
}
}
diff --git a/source/blender/compositor/nodes/COM_DistanceMatteNode.h b/source/blender/compositor/nodes/COM_DistanceMatteNode.h
index 0baa531b4d2..d12e69d8065 100644
--- a/source/blender/compositor/nodes/COM_DistanceMatteNode.h
+++ b/source/blender/compositor/nodes/COM_DistanceMatteNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class DistanceMatteNode : public Node {
public:
- DistanceMatteNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ DistanceMatteNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc
index 847dcc2f8f1..b88348ccc60 100644
--- a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc
+++ b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc
@@ -18,29 +18,28 @@
#include "COM_DoubleEdgeMaskNode.h"
#include "COM_DoubleEdgeMaskOperation.h"
-#include "COM_ExecutionSystem.h"
namespace blender::compositor {
-DoubleEdgeMaskNode::DoubleEdgeMaskNode(bNode *editorNode) : Node(editorNode)
+DoubleEdgeMaskNode::DoubleEdgeMaskNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void DoubleEdgeMaskNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void DoubleEdgeMaskNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
DoubleEdgeMaskOperation *operation;
- bNode *bnode = this->getbNode();
+ bNode *bnode = this->get_bnode();
operation = new DoubleEdgeMaskOperation();
- operation->setAdjecentOnly(bnode->custom1);
- operation->setKeepInside(bnode->custom2);
- converter.addOperation(operation);
+ operation->set_adjecent_only(bnode->custom1);
+ operation->set_keep_inside(bnode->custom2);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.h b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.h
index 90e009747c1..99b3b1d0546 100644
--- a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.h
+++ b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class DoubleEdgeMaskNode : public Node {
public:
- DoubleEdgeMaskNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ DoubleEdgeMaskNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_EllipseMaskNode.cc b/source/blender/compositor/nodes/COM_EllipseMaskNode.cc
index 752597ef937..1f6e2ab2a6c 100644
--- a/source/blender/compositor/nodes/COM_EllipseMaskNode.cc
+++ b/source/blender/compositor/nodes/COM_EllipseMaskNode.cc
@@ -18,59 +18,59 @@
#include "COM_EllipseMaskNode.h"
#include "COM_EllipseMaskOperation.h"
-#include "COM_ExecutionSystem.h"
#include "COM_ScaleOperation.h"
#include "COM_SetValueOperation.h"
namespace blender::compositor {
-EllipseMaskNode::EllipseMaskNode(bNode *editorNode) : Node(editorNode)
+EllipseMaskNode::EllipseMaskNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void EllipseMaskNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void EllipseMaskNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeOutput *outputSocket = this->getOutputSocket(0);
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeOutput *output_socket = this->get_output_socket(0);
EllipseMaskOperation *operation;
operation = new EllipseMaskOperation();
- operation->setData((NodeEllipseMask *)this->getbNode()->storage);
- operation->setMaskType(this->getbNode()->custom1);
- converter.addOperation(operation);
+ operation->set_data((NodeEllipseMask *)this->get_bnode()->storage);
+ operation->set_mask_type(this->get_bnode()->custom1);
+ converter.add_operation(operation);
- if (inputSocket->isLinked()) {
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket());
+ if (input_socket->is_linked()) {
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.map_output_socket(output_socket, operation->get_output_socket());
}
else {
/* Value operation to produce original transparent image */
- SetValueOperation *valueOperation = new SetValueOperation();
- valueOperation->setValue(0.0f);
- converter.addOperation(valueOperation);
+ SetValueOperation *value_operation = new SetValueOperation();
+ value_operation->set_value(0.0f);
+ converter.add_operation(value_operation);
/* Scale that image up to render resolution */
- const RenderData *rd = context.getRenderData();
- const float render_size_factor = context.getRenderPercentageAsFactor();
- ScaleFixedSizeOperation *scaleOperation = new ScaleFixedSizeOperation();
+ const RenderData *rd = context.get_render_data();
+ const float render_size_factor = context.get_render_percentage_as_factor();
+ ScaleFixedSizeOperation *scale_operation = new ScaleFixedSizeOperation();
- scaleOperation->setIsAspect(false);
- scaleOperation->setIsCrop(false);
- scaleOperation->setOffset(0.0f, 0.0f);
- scaleOperation->setNewWidth(rd->xsch * render_size_factor);
- scaleOperation->setNewHeight(rd->ysch * render_size_factor);
- scaleOperation->getInputSocket(0)->setResizeMode(ResizeMode::Align);
- converter.addOperation(scaleOperation);
+ scale_operation->set_is_aspect(false);
+ scale_operation->set_is_crop(false);
+ scale_operation->set_offset(0.0f, 0.0f);
+ scale_operation->set_new_width(rd->xsch * render_size_factor);
+ scale_operation->set_new_height(rd->ysch * render_size_factor);
+ scale_operation->get_input_socket(0)->set_resize_mode(ResizeMode::Align);
+ converter.add_operation(scale_operation);
- converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0));
- converter.addLink(scaleOperation->getOutputSocket(0), operation->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ converter.add_link(value_operation->get_output_socket(0),
+ scale_operation->get_input_socket(0));
+ converter.add_link(scale_operation->get_output_socket(0), operation->get_input_socket(0));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
}
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_EllipseMaskNode.h b/source/blender/compositor/nodes/COM_EllipseMaskNode.h
index cbe189be9f6..4a582b63d91 100644
--- a/source/blender/compositor/nodes/COM_EllipseMaskNode.h
+++ b/source/blender/compositor/nodes/COM_EllipseMaskNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class EllipseMaskNode : public Node {
public:
- EllipseMaskNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ EllipseMaskNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_FilterNode.cc b/source/blender/compositor/nodes/COM_FilterNode.cc
index 351219155c2..2108e68cbec 100644
--- a/source/blender/compositor/nodes/COM_FilterNode.cc
+++ b/source/blender/compositor/nodes/COM_FilterNode.cc
@@ -19,26 +19,23 @@
#include "COM_FilterNode.h"
#include "BKE_node.h"
#include "COM_ConvolutionEdgeFilterOperation.h"
-#include "COM_ConvolutionFilterOperation.h"
-#include "COM_ExecutionSystem.h"
-#include "COM_MixOperation.h"
namespace blender::compositor {
-FilterNode::FilterNode(bNode *editorNode) : Node(editorNode)
+FilterNode::FilterNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void FilterNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void FilterNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeInput *inputImageSocket = this->getInputSocket(1);
- NodeOutput *outputSocket = this->getOutputSocket(0);
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeInput *input_image_socket = this->get_input_socket(1);
+ NodeOutput *output_socket = this->get_output_socket(0);
ConvolutionFilterOperation *operation = nullptr;
- switch (this->getbNode()->custom1) {
+ switch (this->get_bnode()->custom1) {
case CMP_FILT_SOFT:
operation = new ConvolutionFilterOperation();
operation->set3x3Filter(1 / 16.0f,
@@ -88,13 +85,13 @@ void FilterNode::convertToOperations(NodeConverter &converter,
operation->set3x3Filter(0, 0, 0, 0, 1, 0, 0, 0, 0);
break;
}
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(inputImageSocket, operation->getInputSocket(0));
- converter.mapInputSocket(inputSocket, operation->getInputSocket(1));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket());
+ converter.map_input_socket(input_image_socket, operation->get_input_socket(0));
+ converter.map_input_socket(input_socket, operation->get_input_socket(1));
+ converter.map_output_socket(output_socket, operation->get_output_socket());
- converter.addPreview(operation->getOutputSocket(0));
+ converter.add_preview(operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_FilterNode.h b/source/blender/compositor/nodes/COM_FilterNode.h
index f7f4176cea5..c160e11fd9f 100644
--- a/source/blender/compositor/nodes/COM_FilterNode.h
+++ b/source/blender/compositor/nodes/COM_FilterNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class FilterNode : public Node {
public:
- FilterNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ FilterNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_FlipNode.cc b/source/blender/compositor/nodes/COM_FlipNode.cc
index bca6cd3c4f7..ec9a4f9419b 100644
--- a/source/blender/compositor/nodes/COM_FlipNode.cc
+++ b/source/blender/compositor/nodes/COM_FlipNode.cc
@@ -18,23 +18,22 @@
#include "COM_FlipNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_FlipOperation.h"
namespace blender::compositor {
-FlipNode::FlipNode(bNode *editorNode) : Node(editorNode)
+FlipNode::FlipNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void FlipNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void FlipNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeOutput *outputSocket = this->getOutputSocket(0);
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeOutput *output_socket = this->get_output_socket(0);
FlipOperation *operation = new FlipOperation();
- switch (this->getbNode()->custom1) {
+ switch (this->get_bnode()->custom1) {
case 0: /* TODO: I didn't find any constants in the old implementation,
* should I introduce them. */
operation->setFlipX(true);
@@ -50,9 +49,9 @@ void FlipNode::convertToOperations(NodeConverter &converter,
break;
}
- converter.addOperation(operation);
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ converter.add_operation(operation);
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_FlipNode.h b/source/blender/compositor/nodes/COM_FlipNode.h
index ee61d09fbba..40dc44edbbe 100644
--- a/source/blender/compositor/nodes/COM_FlipNode.h
+++ b/source/blender/compositor/nodes/COM_FlipNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class FlipNode : public Node {
public:
- FlipNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ FlipNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_GammaNode.cc b/source/blender/compositor/nodes/COM_GammaNode.cc
index 52148a80a8f..3c4e885ff76 100644
--- a/source/blender/compositor/nodes/COM_GammaNode.cc
+++ b/source/blender/compositor/nodes/COM_GammaNode.cc
@@ -17,25 +17,24 @@
*/
#include "COM_GammaNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_GammaOperation.h"
namespace blender::compositor {
-GammaNode::GammaNode(bNode *editorNode) : Node(editorNode)
+GammaNode::GammaNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void GammaNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void GammaNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
GammaOperation *operation = new GammaOperation();
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_GammaNode.h b/source/blender/compositor/nodes/COM_GammaNode.h
index 29c9ed170fa..3c7a8ee4983 100644
--- a/source/blender/compositor/nodes/COM_GammaNode.h
+++ b/source/blender/compositor/nodes/COM_GammaNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class GammaNode : public Node {
public:
- GammaNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ GammaNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_GlareNode.cc b/source/blender/compositor/nodes/COM_GlareNode.cc
index 9c26d7c86a9..77b1162f7cc 100644
--- a/source/blender/compositor/nodes/COM_GlareNode.cc
+++ b/source/blender/compositor/nodes/COM_GlareNode.cc
@@ -17,7 +17,6 @@
*/
#include "COM_GlareNode.h"
-#include "COM_FastGaussianBlurOperation.h"
#include "COM_GlareFogGlowOperation.h"
#include "COM_GlareGhostOperation.h"
#include "COM_GlareSimpleStarOperation.h"
@@ -25,19 +24,18 @@
#include "COM_GlareThresholdOperation.h"
#include "COM_MixOperation.h"
#include "COM_SetValueOperation.h"
-#include "DNA_node_types.h"
namespace blender::compositor {
-GlareNode::GlareNode(bNode *editorNode) : Node(editorNode)
+GlareNode::GlareNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void GlareNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void GlareNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *node = this->getbNode();
+ bNode *node = this->get_bnode();
NodeGlare *glare = (NodeGlare *)node->storage;
GlareBaseOperation *glareoperation = nullptr;
@@ -57,30 +55,31 @@ void GlareNode::convertToOperations(NodeConverter &converter,
break;
}
BLI_assert(glareoperation);
- glareoperation->setGlareSettings(glare);
+ glareoperation->set_glare_settings(glare);
- GlareThresholdOperation *thresholdOperation = new GlareThresholdOperation();
- thresholdOperation->setGlareSettings(glare);
+ GlareThresholdOperation *threshold_operation = new GlareThresholdOperation();
+ threshold_operation->set_glare_settings(glare);
SetValueOperation *mixvalueoperation = new SetValueOperation();
- mixvalueoperation->setValue(glare->mix);
+ mixvalueoperation->set_value(glare->mix);
MixGlareOperation *mixoperation = new MixGlareOperation();
mixoperation->set_canvas_input_index(1);
- mixoperation->getInputSocket(2)->setResizeMode(ResizeMode::FitAny);
+ mixoperation->get_input_socket(2)->set_resize_mode(ResizeMode::FitAny);
- converter.addOperation(glareoperation);
- converter.addOperation(thresholdOperation);
- converter.addOperation(mixvalueoperation);
- converter.addOperation(mixoperation);
+ converter.add_operation(glareoperation);
+ converter.add_operation(threshold_operation);
+ converter.add_operation(mixvalueoperation);
+ converter.add_operation(mixoperation);
- converter.mapInputSocket(getInputSocket(0), thresholdOperation->getInputSocket(0));
- converter.addLink(thresholdOperation->getOutputSocket(), glareoperation->getInputSocket(0));
+ converter.map_input_socket(get_input_socket(0), threshold_operation->get_input_socket(0));
+ converter.add_link(threshold_operation->get_output_socket(),
+ glareoperation->get_input_socket(0));
- converter.addLink(mixvalueoperation->getOutputSocket(), mixoperation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(0), mixoperation->getInputSocket(1));
- converter.addLink(glareoperation->getOutputSocket(), mixoperation->getInputSocket(2));
- converter.mapOutputSocket(getOutputSocket(), mixoperation->getOutputSocket());
+ converter.add_link(mixvalueoperation->get_output_socket(), mixoperation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(0), mixoperation->get_input_socket(1));
+ converter.add_link(glareoperation->get_output_socket(), mixoperation->get_input_socket(2));
+ converter.map_output_socket(get_output_socket(), mixoperation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_GlareNode.h b/source/blender/compositor/nodes/COM_GlareNode.h
index 7db5fa85e04..85e657984cd 100644
--- a/source/blender/compositor/nodes/COM_GlareNode.h
+++ b/source/blender/compositor/nodes/COM_GlareNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class GlareNode : public Node {
public:
- GlareNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ GlareNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc
index e7b1664c354..6cf9a5356c4 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc
@@ -19,50 +19,47 @@
#include "COM_HueSaturationValueCorrectNode.h"
#include "COM_ConvertOperation.h"
-#include "COM_ExecutionSystem.h"
#include "COM_HueSaturationValueCorrectOperation.h"
#include "COM_MixOperation.h"
-#include "COM_SetColorOperation.h"
-#include "COM_SetValueOperation.h"
-#include "DNA_node_types.h"
namespace blender::compositor {
-HueSaturationValueCorrectNode::HueSaturationValueCorrectNode(bNode *editorNode) : Node(editorNode)
+HueSaturationValueCorrectNode::HueSaturationValueCorrectNode(bNode *editor_node)
+ : Node(editor_node)
{
/* pass */
}
-void HueSaturationValueCorrectNode::convertToOperations(
+void HueSaturationValueCorrectNode::convert_to_operations(
NodeConverter &converter, const CompositorContext & /*context*/) const
{
- NodeInput *valueSocket = this->getInputSocket(0);
- NodeInput *colorSocket = this->getInputSocket(1);
- NodeOutput *outputSocket = this->getOutputSocket(0);
- bNode *editorsnode = getbNode();
+ NodeInput *value_socket = this->get_input_socket(0);
+ NodeInput *color_socket = this->get_input_socket(1);
+ NodeOutput *output_socket = this->get_output_socket(0);
+ bNode *editorsnode = get_bnode();
CurveMapping *storage = (CurveMapping *)editorsnode->storage;
ConvertRGBToHSVOperation *rgbToHSV = new ConvertRGBToHSVOperation();
- converter.addOperation(rgbToHSV);
+ converter.add_operation(rgbToHSV);
ConvertHSVToRGBOperation *hsvToRGB = new ConvertHSVToRGBOperation();
- converter.addOperation(hsvToRGB);
+ converter.add_operation(hsvToRGB);
HueSaturationValueCorrectOperation *changeHSV = new HueSaturationValueCorrectOperation();
- changeHSV->setCurveMapping(storage);
- converter.addOperation(changeHSV);
+ changeHSV->set_curve_mapping(storage);
+ converter.add_operation(changeHSV);
MixBlendOperation *blend = new MixBlendOperation();
blend->set_canvas_input_index(1);
- converter.addOperation(blend);
+ converter.add_operation(blend);
- converter.mapInputSocket(colorSocket, rgbToHSV->getInputSocket(0));
- converter.addLink(rgbToHSV->getOutputSocket(), changeHSV->getInputSocket(0));
- converter.addLink(changeHSV->getOutputSocket(), hsvToRGB->getInputSocket(0));
- converter.addLink(hsvToRGB->getOutputSocket(), blend->getInputSocket(2));
- converter.mapInputSocket(colorSocket, blend->getInputSocket(1));
- converter.mapInputSocket(valueSocket, blend->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, blend->getOutputSocket());
+ converter.map_input_socket(color_socket, rgbToHSV->get_input_socket(0));
+ converter.add_link(rgbToHSV->get_output_socket(), changeHSV->get_input_socket(0));
+ converter.add_link(changeHSV->get_output_socket(), hsvToRGB->get_input_socket(0));
+ converter.add_link(hsvToRGB->get_output_socket(), blend->get_input_socket(2));
+ converter.map_input_socket(color_socket, blend->get_input_socket(1));
+ converter.map_input_socket(value_socket, blend->get_input_socket(0));
+ converter.map_output_socket(output_socket, blend->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.h b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.h
index d75b2ba51ca..1f59c06cb9f 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.h
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class HueSaturationValueCorrectNode : public Node {
public:
- HueSaturationValueCorrectNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ HueSaturationValueCorrectNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc
index 29e5f39a144..fa296f54d8f 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc
@@ -20,52 +20,48 @@
#include "COM_ChangeHSVOperation.h"
#include "COM_ConvertOperation.h"
-#include "COM_ExecutionSystem.h"
#include "COM_MixOperation.h"
-#include "COM_SetColorOperation.h"
-#include "COM_SetValueOperation.h"
-#include "DNA_node_types.h"
namespace blender::compositor {
-HueSaturationValueNode::HueSaturationValueNode(bNode *editorNode) : Node(editorNode)
+HueSaturationValueNode::HueSaturationValueNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void HueSaturationValueNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void HueSaturationValueNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeInput *colorSocket = this->getInputSocket(0);
- NodeInput *hueSocket = this->getInputSocket(1);
- NodeInput *saturationSocket = this->getInputSocket(2);
- NodeInput *valueSocket = this->getInputSocket(3);
- NodeInput *facSocket = this->getInputSocket(4);
- NodeOutput *outputSocket = this->getOutputSocket(0);
+ NodeInput *color_socket = this->get_input_socket(0);
+ NodeInput *hue_socket = this->get_input_socket(1);
+ NodeInput *saturation_socket = this->get_input_socket(2);
+ NodeInput *value_socket = this->get_input_socket(3);
+ NodeInput *fac_socket = this->get_input_socket(4);
+ NodeOutput *output_socket = this->get_output_socket(0);
ConvertRGBToHSVOperation *rgbToHSV = new ConvertRGBToHSVOperation();
- converter.addOperation(rgbToHSV);
+ converter.add_operation(rgbToHSV);
ConvertHSVToRGBOperation *hsvToRGB = new ConvertHSVToRGBOperation();
- converter.addOperation(hsvToRGB);
+ converter.add_operation(hsvToRGB);
ChangeHSVOperation *changeHSV = new ChangeHSVOperation();
- converter.mapInputSocket(hueSocket, changeHSV->getInputSocket(1));
- converter.mapInputSocket(saturationSocket, changeHSV->getInputSocket(2));
- converter.mapInputSocket(valueSocket, changeHSV->getInputSocket(3));
- converter.addOperation(changeHSV);
+ converter.map_input_socket(hue_socket, changeHSV->get_input_socket(1));
+ converter.map_input_socket(saturation_socket, changeHSV->get_input_socket(2));
+ converter.map_input_socket(value_socket, changeHSV->get_input_socket(3));
+ converter.add_operation(changeHSV);
MixBlendOperation *blend = new MixBlendOperation();
blend->set_canvas_input_index(1);
- converter.addOperation(blend);
+ converter.add_operation(blend);
- converter.mapInputSocket(colorSocket, rgbToHSV->getInputSocket(0));
- converter.addLink(rgbToHSV->getOutputSocket(), changeHSV->getInputSocket(0));
- converter.addLink(changeHSV->getOutputSocket(), hsvToRGB->getInputSocket(0));
- converter.addLink(hsvToRGB->getOutputSocket(), blend->getInputSocket(2));
- converter.mapInputSocket(colorSocket, blend->getInputSocket(1));
- converter.mapInputSocket(facSocket, blend->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, blend->getOutputSocket());
+ converter.map_input_socket(color_socket, rgbToHSV->get_input_socket(0));
+ converter.add_link(rgbToHSV->get_output_socket(), changeHSV->get_input_socket(0));
+ converter.add_link(changeHSV->get_output_socket(), hsvToRGB->get_input_socket(0));
+ converter.add_link(hsvToRGB->get_output_socket(), blend->get_input_socket(2));
+ converter.map_input_socket(color_socket, blend->get_input_socket(1));
+ converter.map_input_socket(fac_socket, blend->get_input_socket(0));
+ converter.map_output_socket(output_socket, blend->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.h b/source/blender/compositor/nodes/COM_HueSaturationValueNode.h
index 0b295158cc7..abb7d0afebe 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueNode.h
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class HueSaturationValueNode : public Node {
public:
- HueSaturationValueNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ HueSaturationValueNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_IDMaskNode.cc b/source/blender/compositor/nodes/COM_IDMaskNode.cc
index 761cb8b98cf..4d761f25fd3 100644
--- a/source/blender/compositor/nodes/COM_IDMaskNode.cc
+++ b/source/blender/compositor/nodes/COM_IDMaskNode.cc
@@ -17,52 +17,51 @@
*/
#include "COM_IDMaskNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_IDMaskOperation.h"
#include "COM_SMAAOperation.h"
namespace blender::compositor {
-IDMaskNode::IDMaskNode(bNode *editorNode) : Node(editorNode)
+IDMaskNode::IDMaskNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void IDMaskNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void IDMaskNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *bnode = this->getbNode();
+ bNode *bnode = this->get_bnode();
IDMaskOperation *operation;
operation = new IDMaskOperation();
- operation->setObjectIndex(bnode->custom1);
- converter.addOperation(operation);
+ operation->set_object_index(bnode->custom1);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
if (bnode->custom2 == 0) {
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
else {
SMAAEdgeDetectionOperation *operation1 = nullptr;
operation1 = new SMAAEdgeDetectionOperation();
- converter.addOperation(operation1);
+ converter.add_operation(operation1);
- converter.addLink(operation->getOutputSocket(0), operation1->getInputSocket(0));
+ converter.add_link(operation->get_output_socket(0), operation1->get_input_socket(0));
/* Blending Weight Calculation Pixel Shader (Second Pass). */
SMAABlendingWeightCalculationOperation *operation2 =
new SMAABlendingWeightCalculationOperation();
- converter.addOperation(operation2);
+ converter.add_operation(operation2);
- converter.addLink(operation1->getOutputSocket(), operation2->getInputSocket(0));
+ converter.add_link(operation1->get_output_socket(), operation2->get_input_socket(0));
/* Neighborhood Blending Pixel Shader (Third Pass). */
SMAANeighborhoodBlendingOperation *operation3 = new SMAANeighborhoodBlendingOperation();
- converter.addOperation(operation3);
+ converter.add_operation(operation3);
- converter.addLink(operation->getOutputSocket(0), operation3->getInputSocket(0));
- converter.addLink(operation2->getOutputSocket(), operation3->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(0), operation3->getOutputSocket());
+ converter.add_link(operation->get_output_socket(0), operation3->get_input_socket(0));
+ converter.add_link(operation2->get_output_socket(), operation3->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(0), operation3->get_output_socket());
}
}
diff --git a/source/blender/compositor/nodes/COM_IDMaskNode.h b/source/blender/compositor/nodes/COM_IDMaskNode.h
index f702732a8ed..8eba2af715f 100644
--- a/source/blender/compositor/nodes/COM_IDMaskNode.h
+++ b/source/blender/compositor/nodes/COM_IDMaskNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class IDMaskNode : public Node {
public:
- IDMaskNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ IDMaskNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cc b/source/blender/compositor/nodes/COM_ImageNode.cc
index 20476144efa..cc1c4109d9e 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cc
+++ b/source/blender/compositor/nodes/COM_ImageNode.cc
@@ -17,35 +17,30 @@
*/
#include "COM_ImageNode.h"
-#include "BKE_node.h"
-#include "BLI_utildefines.h"
#include "COM_ConvertOperation.h"
-#include "COM_ExecutionSystem.h"
-#include "COM_ImageOperation.h"
#include "COM_MultilayerImageOperation.h"
-#include "COM_SeparateColorNode.h"
#include "COM_SetColorOperation.h"
#include "COM_SetValueOperation.h"
#include "COM_SetVectorOperation.h"
namespace blender::compositor {
-ImageNode::ImageNode(bNode *editorNode) : Node(editorNode)
+ImageNode::ImageNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-NodeOperation *ImageNode::doMultilayerCheck(NodeConverter &converter,
- RenderLayer *render_layer,
- RenderPass *render_pass,
- Image *image,
- ImageUser *user,
- int framenumber,
- int outputsocketIndex,
- int view,
- DataType datatype) const
+NodeOperation *ImageNode::do_multilayer_check(NodeConverter &converter,
+ RenderLayer *render_layer,
+ RenderPass *render_pass,
+ Image *image,
+ ImageUser *user,
+ int framenumber,
+ int outputsocket_index,
+ int view,
+ DataType datatype) const
{
- NodeOutput *outputSocket = this->getOutputSocket(outputsocketIndex);
+ NodeOutput *output_socket = this->get_output_socket(outputsocket_index);
MultilayerBaseOperation *operation = nullptr;
switch (datatype) {
case DataType::Value:
@@ -60,27 +55,27 @@ NodeOperation *ImageNode::doMultilayerCheck(NodeConverter &converter,
default:
break;
}
- operation->setImage(image);
- operation->setImageUser(user);
- operation->setFramenumber(framenumber);
+ operation->set_image(image);
+ operation->set_image_user(user);
+ operation->set_framenumber(framenumber);
- converter.addOperation(operation);
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket());
+ converter.add_operation(operation);
+ converter.map_output_socket(output_socket, operation->get_output_socket());
return operation;
}
-void ImageNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void ImageNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
/** Image output */
- NodeOutput *outputImage = this->getOutputSocket(0);
- bNode *editorNode = this->getbNode();
- Image *image = (Image *)editorNode->id;
- ImageUser *imageuser = (ImageUser *)editorNode->storage;
- int framenumber = context.getFramenumber();
- bool outputStraightAlpha = (editorNode->custom1 & CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT) != 0;
- BKE_image_user_frame_calc(image, imageuser, context.getFramenumber());
+ NodeOutput *output_image = this->get_output_socket(0);
+ bNode *editor_node = this->get_bnode();
+ Image *image = (Image *)editor_node->id;
+ ImageUser *imageuser = (ImageUser *)editor_node->storage;
+ int framenumber = context.get_framenumber();
+ bool output_straight_alpha = (editor_node->custom1 & CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT) != 0;
+ BKE_image_user_frame_calc(image, imageuser, context.get_framenumber());
/* force a load, we assume iuser index will be set OK anyway */
if (image && image->type == IMA_TYPE_MULTILAYER) {
bool is_multilayer_ok = false;
@@ -90,17 +85,17 @@ void ImageNode::convertToOperations(NodeConverter &converter,
if (rl) {
is_multilayer_ok = true;
- for (int64_t index = 0; index < outputs.size(); index++) {
- NodeOutput *socket = outputs[index];
+ for (int64_t index = 0; index < outputs_.size(); index++) {
+ NodeOutput *socket = outputs_[index];
NodeOperation *operation = nullptr;
- bNodeSocket *bnodeSocket = socket->getbNodeSocket();
- NodeImageLayer *storage = (NodeImageLayer *)bnodeSocket->storage;
+ bNodeSocket *bnode_socket = socket->get_bnode_socket();
+ NodeImageLayer *storage = (NodeImageLayer *)bnode_socket->storage;
RenderPass *rpass = (RenderPass *)BLI_findstring(
&rl->passes, storage->pass_name, offsetof(RenderPass, name));
int view = 0;
if (STREQ(storage->pass_name, RE_PASSNAME_COMBINED) &&
- STREQ(bnodeSocket->name, "Alpha")) {
+ STREQ(bnode_socket->name, "Alpha")) {
/* Alpha output is already handled with the associated combined output. */
continue;
}
@@ -114,7 +109,7 @@ void ImageNode::convertToOperations(NodeConverter &converter,
/* heuristic to match image name with scene names
* check if the view name exists in the image */
view = BLI_findstringindex(
- &image->rr->views, context.getViewName(), offsetof(RenderView, name));
+ &image->rr->views, context.get_view_name(), offsetof(RenderView, name));
if (view == -1) {
view = 0;
}
@@ -127,64 +122,64 @@ void ImageNode::convertToOperations(NodeConverter &converter,
if (rpass) {
switch (rpass->channels) {
case 1:
- operation = doMultilayerCheck(converter,
- rl,
- rpass,
- image,
- imageuser,
- framenumber,
- index,
- view,
- DataType::Value);
+ operation = do_multilayer_check(converter,
+ rl,
+ rpass,
+ image,
+ imageuser,
+ framenumber,
+ index,
+ view,
+ DataType::Value);
break;
/* using image operations for both 3 and 4 channels (RGB and RGBA respectively) */
/* XXX any way to detect actual vector images? */
case 3:
- operation = doMultilayerCheck(converter,
- rl,
- rpass,
- image,
- imageuser,
- framenumber,
- index,
- view,
- DataType::Vector);
+ operation = do_multilayer_check(converter,
+ rl,
+ rpass,
+ image,
+ imageuser,
+ framenumber,
+ index,
+ view,
+ DataType::Vector);
break;
case 4:
- operation = doMultilayerCheck(converter,
- rl,
- rpass,
- image,
- imageuser,
- framenumber,
- index,
- view,
- DataType::Color);
+ operation = do_multilayer_check(converter,
+ rl,
+ rpass,
+ image,
+ imageuser,
+ framenumber,
+ index,
+ view,
+ DataType::Color);
break;
default:
/* dummy operation is added below */
break;
}
if (index == 0 && operation) {
- converter.addPreview(operation->getOutputSocket());
+ converter.add_preview(operation->get_output_socket());
}
- if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && !(bnodeSocket->flag & SOCK_UNAVAIL)) {
- for (NodeOutput *alphaSocket : getOutputSockets()) {
- bNodeSocket *bnodeAlphaSocket = alphaSocket->getbNodeSocket();
- if (!STREQ(bnodeAlphaSocket->name, "Alpha")) {
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && !(bnode_socket->flag & SOCK_UNAVAIL)) {
+ for (NodeOutput *alpha_socket : get_output_sockets()) {
+ bNodeSocket *bnode_alpha_socket = alpha_socket->get_bnode_socket();
+ if (!STREQ(bnode_alpha_socket->name, "Alpha")) {
continue;
}
- NodeImageLayer *alphaStorage = (NodeImageLayer *)bnodeSocket->storage;
- if (!STREQ(alphaStorage->pass_name, RE_PASSNAME_COMBINED)) {
+ NodeImageLayer *alpha_storage = (NodeImageLayer *)bnode_socket->storage;
+ if (!STREQ(alpha_storage->pass_name, RE_PASSNAME_COMBINED)) {
continue;
}
SeparateChannelOperation *separate_operation;
separate_operation = new SeparateChannelOperation();
- separate_operation->setChannel(3);
- converter.addOperation(separate_operation);
- converter.addLink(operation->getOutputSocket(),
- separate_operation->getInputSocket(0));
- converter.mapOutputSocket(alphaSocket, separate_operation->getOutputSocket());
+ separate_operation->set_channel(3);
+ converter.add_operation(separate_operation);
+ converter.add_link(operation->get_output_socket(),
+ separate_operation->get_input_socket(0));
+ converter.map_output_socket(alpha_socket, separate_operation->get_output_socket());
break;
}
}
@@ -192,7 +187,7 @@ void ImageNode::convertToOperations(NodeConverter &converter,
/* In case we can't load the layer. */
if (operation == nullptr) {
- converter.setInvalidOutput(getOutputSocket(index));
+ converter.set_invalid_output(get_output_socket(index));
}
}
}
@@ -201,69 +196,70 @@ void ImageNode::convertToOperations(NodeConverter &converter,
/* without this, multilayer that fail to load will crash blender T32490. */
if (is_multilayer_ok == false) {
- for (NodeOutput *output : getOutputSockets()) {
- converter.setInvalidOutput(output);
+ for (NodeOutput *output : get_output_sockets()) {
+ converter.set_invalid_output(output);
}
}
}
else {
- const int64_t numberOfOutputs = getOutputSockets().size();
- if (numberOfOutputs > 0) {
+ const int64_t number_of_outputs = get_output_sockets().size();
+ if (number_of_outputs > 0) {
ImageOperation *operation = new ImageOperation();
- operation->setImage(image);
- operation->setImageUser(imageuser);
- operation->setFramenumber(framenumber);
- operation->setRenderData(context.getRenderData());
- operation->setViewName(context.getViewName());
- converter.addOperation(operation);
+ operation->set_image(image);
+ operation->set_image_user(imageuser);
+ operation->set_framenumber(framenumber);
+ operation->set_render_data(context.get_render_data());
+ operation->set_view_name(context.get_view_name());
+ converter.add_operation(operation);
- if (outputStraightAlpha) {
- NodeOperation *alphaConvertOperation = new ConvertPremulToStraightOperation();
+ if (output_straight_alpha) {
+ NodeOperation *alpha_convert_operation = new ConvertPremulToStraightOperation();
- converter.addOperation(alphaConvertOperation);
- converter.mapOutputSocket(outputImage, alphaConvertOperation->getOutputSocket());
- converter.addLink(operation->getOutputSocket(0), alphaConvertOperation->getInputSocket(0));
+ converter.add_operation(alpha_convert_operation);
+ converter.map_output_socket(output_image, alpha_convert_operation->get_output_socket());
+ converter.add_link(operation->get_output_socket(0),
+ alpha_convert_operation->get_input_socket(0));
}
else {
- converter.mapOutputSocket(outputImage, operation->getOutputSocket());
+ converter.map_output_socket(output_image, operation->get_output_socket());
}
- converter.addPreview(operation->getOutputSocket());
+ converter.add_preview(operation->get_output_socket());
}
- if (numberOfOutputs > 1) {
- NodeOutput *alphaImage = this->getOutputSocket(1);
- ImageAlphaOperation *alphaOperation = new ImageAlphaOperation();
- alphaOperation->setImage(image);
- alphaOperation->setImageUser(imageuser);
- alphaOperation->setFramenumber(framenumber);
- alphaOperation->setRenderData(context.getRenderData());
- alphaOperation->setViewName(context.getViewName());
- converter.addOperation(alphaOperation);
+ if (number_of_outputs > 1) {
+ NodeOutput *alpha_image = this->get_output_socket(1);
+ ImageAlphaOperation *alpha_operation = new ImageAlphaOperation();
+ alpha_operation->set_image(image);
+ alpha_operation->set_image_user(imageuser);
+ alpha_operation->set_framenumber(framenumber);
+ alpha_operation->set_render_data(context.get_render_data());
+ alpha_operation->set_view_name(context.get_view_name());
+ converter.add_operation(alpha_operation);
- converter.mapOutputSocket(alphaImage, alphaOperation->getOutputSocket());
+ converter.map_output_socket(alpha_image, alpha_operation->get_output_socket());
}
- if (numberOfOutputs > 2) {
- NodeOutput *depthImage = this->getOutputSocket(2);
- ImageDepthOperation *depthOperation = new ImageDepthOperation();
- depthOperation->setImage(image);
- depthOperation->setImageUser(imageuser);
- depthOperation->setFramenumber(framenumber);
- depthOperation->setRenderData(context.getRenderData());
- depthOperation->setViewName(context.getViewName());
- converter.addOperation(depthOperation);
+ if (number_of_outputs > 2) {
+ NodeOutput *depth_image = this->get_output_socket(2);
+ ImageDepthOperation *depth_operation = new ImageDepthOperation();
+ depth_operation->set_image(image);
+ depth_operation->set_image_user(imageuser);
+ depth_operation->set_framenumber(framenumber);
+ depth_operation->set_render_data(context.get_render_data());
+ depth_operation->set_view_name(context.get_view_name());
+ converter.add_operation(depth_operation);
- converter.mapOutputSocket(depthImage, depthOperation->getOutputSocket());
+ converter.map_output_socket(depth_image, depth_operation->get_output_socket());
}
- if (numberOfOutputs > 3) {
+ if (number_of_outputs > 3) {
/* happens when unlinking image datablock from multilayer node */
- for (int i = 3; i < numberOfOutputs; i++) {
- NodeOutput *output = this->getOutputSocket(i);
+ for (int i = 3; i < number_of_outputs; i++) {
+ NodeOutput *output = this->get_output_socket(i);
NodeOperation *operation = nullptr;
- switch (output->getDataType()) {
+ switch (output->get_data_type()) {
case DataType::Value: {
SetValueOperation *valueoperation = new SetValueOperation();
- valueoperation->setValue(0.0f);
+ valueoperation->set_value(0.0f);
operation = valueoperation;
break;
}
@@ -277,10 +273,10 @@ void ImageNode::convertToOperations(NodeConverter &converter,
}
case DataType::Color: {
SetColorOperation *coloroperation = new SetColorOperation();
- coloroperation->setChannel1(0.0f);
- coloroperation->setChannel2(0.0f);
- coloroperation->setChannel3(0.0f);
- coloroperation->setChannel4(0.0f);
+ coloroperation->set_channel1(0.0f);
+ coloroperation->set_channel2(0.0f);
+ coloroperation->set_channel3(0.0f);
+ coloroperation->set_channel4(0.0f);
operation = coloroperation;
break;
}
@@ -288,8 +284,8 @@ void ImageNode::convertToOperations(NodeConverter &converter,
if (operation) {
/* not supporting multiview for this generic case */
- converter.addOperation(operation);
- converter.mapOutputSocket(output, operation->getOutputSocket());
+ converter.add_operation(operation);
+ converter.map_output_socket(output, operation->get_output_socket());
}
}
}
diff --git a/source/blender/compositor/nodes/COM_ImageNode.h b/source/blender/compositor/nodes/COM_ImageNode.h
index 047cc496f83..7dd948be946 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.h
+++ b/source/blender/compositor/nodes/COM_ImageNode.h
@@ -34,20 +34,20 @@ namespace blender::compositor {
*/
class ImageNode : public Node {
private:
- NodeOperation *doMultilayerCheck(NodeConverter &converter,
- RenderLayer *render_layer,
- RenderPass *render_pass,
- Image *image,
- ImageUser *user,
- int framenumber,
- int outputsocketIndex,
- int view,
- DataType datatype) const;
+ NodeOperation *do_multilayer_check(NodeConverter &converter,
+ RenderLayer *render_layer,
+ RenderPass *render_pass,
+ Image *image,
+ ImageUser *user,
+ int framenumber,
+ int outputsocket_index,
+ int view,
+ DataType datatype) const;
public:
- ImageNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ImageNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_InpaintNode.cc b/source/blender/compositor/nodes/COM_InpaintNode.cc
index 01ec5523939..1feb618d47a 100644
--- a/source/blender/compositor/nodes/COM_InpaintNode.cc
+++ b/source/blender/compositor/nodes/COM_InpaintNode.cc
@@ -17,32 +17,29 @@
*/
#include "COM_InpaintNode.h"
-#include "BLI_math.h"
-#include "COM_ExecutionSystem.h"
#include "COM_InpaintOperation.h"
-#include "DNA_scene_types.h"
namespace blender::compositor {
-InpaintNode::InpaintNode(bNode *editorNode) : Node(editorNode)
+InpaintNode::InpaintNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void InpaintNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void InpaintNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *editorNode = this->getbNode();
+ bNode *editor_node = this->get_bnode();
- /* if (editorNode->custom1 == CMP_NODE_INPAINT_SIMPLE) { */
+ /* if (editor_node->custom1 == CMP_NODE_INPAINT_SIMPLE) { */
if (true) {
InpaintSimpleOperation *operation = new InpaintSimpleOperation();
- operation->setIterations(editorNode->custom2);
- converter.addOperation(operation);
+ operation->set_iterations(editor_node->custom2);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
}
diff --git a/source/blender/compositor/nodes/COM_InpaintNode.h b/source/blender/compositor/nodes/COM_InpaintNode.h
index 3a10c11bf61..389ca1d56f4 100644
--- a/source/blender/compositor/nodes/COM_InpaintNode.h
+++ b/source/blender/compositor/nodes/COM_InpaintNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class InpaintNode : public Node {
public:
- InpaintNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ InpaintNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_InvertNode.cc b/source/blender/compositor/nodes/COM_InvertNode.cc
index 5fe2033227f..ffde5b1e12e 100644
--- a/source/blender/compositor/nodes/COM_InvertNode.cc
+++ b/source/blender/compositor/nodes/COM_InvertNode.cc
@@ -18,28 +18,27 @@
#include "COM_InvertNode.h"
#include "BKE_node.h"
-#include "COM_ExecutionSystem.h"
#include "COM_InvertOperation.h"
namespace blender::compositor {
-InvertNode::InvertNode(bNode *editorNode) : Node(editorNode)
+InvertNode::InvertNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void InvertNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void InvertNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
InvertOperation *operation = new InvertOperation();
- bNode *node = this->getbNode();
- operation->setColor(node->custom1 & CMP_CHAN_RGB);
- operation->setAlpha(node->custom1 & CMP_CHAN_A);
- converter.addOperation(operation);
+ bNode *node = this->get_bnode();
+ operation->set_color(node->custom1 & CMP_CHAN_RGB);
+ operation->set_alpha(node->custom1 & CMP_CHAN_A);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_InvertNode.h b/source/blender/compositor/nodes/COM_InvertNode.h
index 1cc975b8236..8f2eb258ab5 100644
--- a/source/blender/compositor/nodes/COM_InvertNode.h
+++ b/source/blender/compositor/nodes/COM_InvertNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class InvertNode : public Node {
public:
- InvertNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ InvertNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_KeyingNode.cc b/source/blender/compositor/nodes/COM_KeyingNode.cc
index 0af328a3601..d3130fdd2eb 100644
--- a/source/blender/compositor/nodes/COM_KeyingNode.cc
+++ b/source/blender/compositor/nodes/COM_KeyingNode.cc
@@ -18,8 +18,6 @@
#include "COM_KeyingNode.h"
-#include "COM_ExecutionSystem.h"
-
#include "COM_KeyingBlurOperation.h"
#include "COM_KeyingClipOperation.h"
#include "COM_KeyingDespillOperation.h"
@@ -39,112 +37,114 @@
namespace blender::compositor {
-KeyingNode::KeyingNode(bNode *editorNode) : Node(editorNode)
+KeyingNode::KeyingNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-NodeOperationOutput *KeyingNode::setupPreBlur(NodeConverter &converter,
- NodeInput *inputImage,
- int size) const
+NodeOperationOutput *KeyingNode::setup_pre_blur(NodeConverter &converter,
+ NodeInput *input_image,
+ int size) const
{
ConvertRGBToYCCOperation *convertRGBToYCCOperation = new ConvertRGBToYCCOperation();
- convertRGBToYCCOperation->setMode(BLI_YCC_ITU_BT709);
- converter.addOperation(convertRGBToYCCOperation);
+ convertRGBToYCCOperation->set_mode(BLI_YCC_ITU_BT709);
+ converter.add_operation(convertRGBToYCCOperation);
- converter.mapInputSocket(inputImage, convertRGBToYCCOperation->getInputSocket(0));
+ converter.map_input_socket(input_image, convertRGBToYCCOperation->get_input_socket(0));
- CombineChannelsOperation *combineOperation = new CombineChannelsOperation();
- converter.addOperation(combineOperation);
+ CombineChannelsOperation *combine_operation = new CombineChannelsOperation();
+ converter.add_operation(combine_operation);
for (int channel = 0; channel < 4; channel++) {
- SeparateChannelOperation *separateOperation = new SeparateChannelOperation();
- separateOperation->setChannel(channel);
- converter.addOperation(separateOperation);
+ SeparateChannelOperation *separate_operation = new SeparateChannelOperation();
+ separate_operation->set_channel(channel);
+ converter.add_operation(separate_operation);
- converter.addLink(convertRGBToYCCOperation->getOutputSocket(0),
- separateOperation->getInputSocket(0));
+ converter.add_link(convertRGBToYCCOperation->get_output_socket(0),
+ separate_operation->get_input_socket(0));
if (ELEM(channel, 0, 3)) {
- converter.addLink(separateOperation->getOutputSocket(0),
- combineOperation->getInputSocket(channel));
+ converter.add_link(separate_operation->get_output_socket(0),
+ combine_operation->get_input_socket(channel));
}
else {
- KeyingBlurOperation *blurXOperation = new KeyingBlurOperation();
- blurXOperation->setSize(size);
- blurXOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_X);
- converter.addOperation(blurXOperation);
-
- KeyingBlurOperation *blurYOperation = new KeyingBlurOperation();
- blurYOperation->setSize(size);
- blurYOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_Y);
- converter.addOperation(blurYOperation);
-
- converter.addLink(separateOperation->getOutputSocket(), blurXOperation->getInputSocket(0));
- converter.addLink(blurXOperation->getOutputSocket(), blurYOperation->getInputSocket(0));
- converter.addLink(blurYOperation->getOutputSocket(0),
- combineOperation->getInputSocket(channel));
+ KeyingBlurOperation *blur_xoperation = new KeyingBlurOperation();
+ blur_xoperation->set_size(size);
+ blur_xoperation->set_axis(KeyingBlurOperation::BLUR_AXIS_X);
+ converter.add_operation(blur_xoperation);
+
+ KeyingBlurOperation *blur_yoperation = new KeyingBlurOperation();
+ blur_yoperation->set_size(size);
+ blur_yoperation->set_axis(KeyingBlurOperation::BLUR_AXIS_Y);
+ converter.add_operation(blur_yoperation);
+
+ converter.add_link(separate_operation->get_output_socket(),
+ blur_xoperation->get_input_socket(0));
+ converter.add_link(blur_xoperation->get_output_socket(),
+ blur_yoperation->get_input_socket(0));
+ converter.add_link(blur_yoperation->get_output_socket(0),
+ combine_operation->get_input_socket(channel));
}
}
ConvertYCCToRGBOperation *convertYCCToRGBOperation = new ConvertYCCToRGBOperation();
- convertYCCToRGBOperation->setMode(BLI_YCC_ITU_BT709);
- converter.addOperation(convertYCCToRGBOperation);
+ convertYCCToRGBOperation->set_mode(BLI_YCC_ITU_BT709);
+ converter.add_operation(convertYCCToRGBOperation);
- converter.addLink(combineOperation->getOutputSocket(0),
- convertYCCToRGBOperation->getInputSocket(0));
+ converter.add_link(combine_operation->get_output_socket(0),
+ convertYCCToRGBOperation->get_input_socket(0));
- return convertYCCToRGBOperation->getOutputSocket(0);
+ return convertYCCToRGBOperation->get_output_socket(0);
}
-NodeOperationOutput *KeyingNode::setupPostBlur(NodeConverter &converter,
- NodeOperationOutput *postBlurInput,
- int size) const
+NodeOperationOutput *KeyingNode::setup_post_blur(NodeConverter &converter,
+ NodeOperationOutput *post_blur_input,
+ int size) const
{
- KeyingBlurOperation *blurXOperation = new KeyingBlurOperation();
- blurXOperation->setSize(size);
- blurXOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_X);
- converter.addOperation(blurXOperation);
+ KeyingBlurOperation *blur_xoperation = new KeyingBlurOperation();
+ blur_xoperation->set_size(size);
+ blur_xoperation->set_axis(KeyingBlurOperation::BLUR_AXIS_X);
+ converter.add_operation(blur_xoperation);
- KeyingBlurOperation *blurYOperation = new KeyingBlurOperation();
- blurYOperation->setSize(size);
- blurYOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_Y);
- converter.addOperation(blurYOperation);
+ KeyingBlurOperation *blur_yoperation = new KeyingBlurOperation();
+ blur_yoperation->set_size(size);
+ blur_yoperation->set_axis(KeyingBlurOperation::BLUR_AXIS_Y);
+ converter.add_operation(blur_yoperation);
- converter.addLink(postBlurInput, blurXOperation->getInputSocket(0));
- converter.addLink(blurXOperation->getOutputSocket(), blurYOperation->getInputSocket(0));
+ converter.add_link(post_blur_input, blur_xoperation->get_input_socket(0));
+ converter.add_link(blur_xoperation->get_output_socket(), blur_yoperation->get_input_socket(0));
- return blurYOperation->getOutputSocket();
+ return blur_yoperation->get_output_socket();
}
-NodeOperationOutput *KeyingNode::setupDilateErode(NodeConverter &converter,
- NodeOperationOutput *dilateErodeInput,
- int distance) const
+NodeOperationOutput *KeyingNode::setup_dilate_erode(NodeConverter &converter,
+ NodeOperationOutput *dilate_erode_input,
+ int distance) const
{
- DilateDistanceOperation *dilateErodeOperation;
+ DilateDistanceOperation *dilate_erode_operation;
if (distance > 0) {
- dilateErodeOperation = new DilateDistanceOperation();
- dilateErodeOperation->setDistance(distance);
+ dilate_erode_operation = new DilateDistanceOperation();
+ dilate_erode_operation->set_distance(distance);
}
else {
- dilateErodeOperation = new ErodeDistanceOperation();
- dilateErodeOperation->setDistance(-distance);
+ dilate_erode_operation = new ErodeDistanceOperation();
+ dilate_erode_operation->set_distance(-distance);
}
- converter.addOperation(dilateErodeOperation);
+ converter.add_operation(dilate_erode_operation);
- converter.addLink(dilateErodeInput, dilateErodeOperation->getInputSocket(0));
+ converter.add_link(dilate_erode_input, dilate_erode_operation->get_input_socket(0));
- return dilateErodeOperation->getOutputSocket(0);
+ return dilate_erode_operation->get_output_socket(0);
}
-NodeOperationOutput *KeyingNode::setupFeather(NodeConverter &converter,
- const CompositorContext &context,
- NodeOperationOutput *featherInput,
- int falloff,
- int distance) const
+NodeOperationOutput *KeyingNode::setup_feather(NodeConverter &converter,
+ const CompositorContext &context,
+ NodeOperationOutput *feather_input,
+ int falloff,
+ int distance) const
{
/* this uses a modified gaussian blur function otherwise its far too slow */
- eCompositorQuality quality = context.getQuality();
+ eCompositorQuality quality = context.get_quality();
/* initialize node data */
NodeBlurData data;
@@ -158,196 +158,198 @@ NodeOperationOutput *KeyingNode::setupFeather(NodeConverter &converter,
}
GaussianAlphaXBlurOperation *operationx = new GaussianAlphaXBlurOperation();
- operationx->setData(&data);
- operationx->setQuality(quality);
- operationx->setSize(1.0f);
- operationx->setSubtract(distance < 0);
- operationx->setFalloff(falloff);
- converter.addOperation(operationx);
+ operationx->set_data(&data);
+ operationx->set_quality(quality);
+ operationx->set_size(1.0f);
+ operationx->set_subtract(distance < 0);
+ operationx->set_falloff(falloff);
+ converter.add_operation(operationx);
GaussianAlphaYBlurOperation *operationy = new GaussianAlphaYBlurOperation();
- operationy->setData(&data);
- operationy->setQuality(quality);
- operationy->setSize(1.0f);
- operationy->setSubtract(distance < 0);
- operationy->setFalloff(falloff);
- converter.addOperation(operationy);
+ operationy->set_data(&data);
+ operationy->set_quality(quality);
+ operationy->set_size(1.0f);
+ operationy->set_subtract(distance < 0);
+ operationy->set_falloff(falloff);
+ converter.add_operation(operationy);
- converter.addLink(featherInput, operationx->getInputSocket(0));
- converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0));
+ converter.add_link(feather_input, operationx->get_input_socket(0));
+ converter.add_link(operationx->get_output_socket(), operationy->get_input_socket(0));
- return operationy->getOutputSocket();
+ return operationy->get_output_socket();
}
-NodeOperationOutput *KeyingNode::setupDespill(NodeConverter &converter,
- NodeOperationOutput *despillInput,
- NodeInput *inputScreen,
- float factor,
- float colorBalance) const
+NodeOperationOutput *KeyingNode::setup_despill(NodeConverter &converter,
+ NodeOperationOutput *despill_input,
+ NodeInput *input_screen,
+ float factor,
+ float color_balance) const
{
- KeyingDespillOperation *despillOperation = new KeyingDespillOperation();
- despillOperation->setDespillFactor(factor);
- despillOperation->setColorBalance(colorBalance);
- converter.addOperation(despillOperation);
+ KeyingDespillOperation *despill_operation = new KeyingDespillOperation();
+ despill_operation->set_despill_factor(factor);
+ despill_operation->set_color_balance(color_balance);
+ converter.add_operation(despill_operation);
- converter.addLink(despillInput, despillOperation->getInputSocket(0));
- converter.mapInputSocket(inputScreen, despillOperation->getInputSocket(1));
+ converter.add_link(despill_input, despill_operation->get_input_socket(0));
+ converter.map_input_socket(input_screen, despill_operation->get_input_socket(1));
- return despillOperation->getOutputSocket(0);
+ return despill_operation->get_output_socket(0);
}
-NodeOperationOutput *KeyingNode::setupClip(NodeConverter &converter,
- NodeOperationOutput *clipInput,
- int kernelRadius,
- float kernelTolerance,
- float clipBlack,
- float clipWhite,
- bool edgeMatte) const
+NodeOperationOutput *KeyingNode::setup_clip(NodeConverter &converter,
+ NodeOperationOutput *clip_input,
+ int kernel_radius,
+ float kernel_tolerance,
+ float clip_black,
+ float clip_white,
+ bool edge_matte) const
{
- KeyingClipOperation *clipOperation = new KeyingClipOperation();
- clipOperation->setKernelRadius(kernelRadius);
- clipOperation->setKernelTolerance(kernelTolerance);
- clipOperation->setClipBlack(clipBlack);
- clipOperation->setClipWhite(clipWhite);
- clipOperation->setIsEdgeMatte(edgeMatte);
- converter.addOperation(clipOperation);
+ KeyingClipOperation *clip_operation = new KeyingClipOperation();
+ clip_operation->set_kernel_radius(kernel_radius);
+ clip_operation->set_kernel_tolerance(kernel_tolerance);
+ clip_operation->set_clip_black(clip_black);
+ clip_operation->set_clip_white(clip_white);
+ clip_operation->set_is_edge_matte(edge_matte);
+ converter.add_operation(clip_operation);
- converter.addLink(clipInput, clipOperation->getInputSocket(0));
+ converter.add_link(clip_input, clip_operation->get_input_socket(0));
- return clipOperation->getOutputSocket(0);
+ return clip_operation->get_output_socket(0);
}
-void KeyingNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void KeyingNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *editorNode = this->getbNode();
- NodeKeyingData *keying_data = (NodeKeyingData *)editorNode->storage;
-
- NodeInput *inputImage = this->getInputSocket(0);
- NodeInput *inputScreen = this->getInputSocket(1);
- NodeInput *inputGarbageMatte = this->getInputSocket(2);
- NodeInput *inputCoreMatte = this->getInputSocket(3);
- NodeOutput *outputImage = this->getOutputSocket(0);
- NodeOutput *outputMatte = this->getOutputSocket(1);
- NodeOutput *outputEdges = this->getOutputSocket(2);
- NodeOperationOutput *postprocessedMatte = nullptr, *postprocessedImage = nullptr,
- *edgesMatte = nullptr;
+ bNode *editor_node = this->get_bnode();
+ NodeKeyingData *keying_data = (NodeKeyingData *)editor_node->storage;
+
+ NodeInput *input_image = this->get_input_socket(0);
+ NodeInput *input_screen = this->get_input_socket(1);
+ NodeInput *input_garbage_matte = this->get_input_socket(2);
+ NodeInput *input_core_matte = this->get_input_socket(3);
+ NodeOutput *output_image = this->get_output_socket(0);
+ NodeOutput *output_matte = this->get_output_socket(1);
+ NodeOutput *output_edges = this->get_output_socket(2);
+ NodeOperationOutput *postprocessed_matte = nullptr, *postprocessed_image = nullptr,
+ *edges_matte = nullptr;
/* keying operation */
- KeyingOperation *keyingOperation = new KeyingOperation();
- keyingOperation->setScreenBalance(keying_data->screen_balance);
- converter.addOperation(keyingOperation);
+ KeyingOperation *keying_operation = new KeyingOperation();
+ keying_operation->set_screen_balance(keying_data->screen_balance);
+ converter.add_operation(keying_operation);
- converter.mapInputSocket(inputScreen, keyingOperation->getInputSocket(1));
+ converter.map_input_socket(input_screen, keying_operation->get_input_socket(1));
if (keying_data->blur_pre) {
/* Chroma pre-blur operation for input of keying operation. */
- NodeOperationOutput *preBlurredImage = setupPreBlur(
- converter, inputImage, keying_data->blur_pre);
- converter.addLink(preBlurredImage, keyingOperation->getInputSocket(0));
+ NodeOperationOutput *pre_blurred_image = setup_pre_blur(
+ converter, input_image, keying_data->blur_pre);
+ converter.add_link(pre_blurred_image, keying_operation->get_input_socket(0));
}
else {
- converter.mapInputSocket(inputImage, keyingOperation->getInputSocket(0));
+ converter.map_input_socket(input_image, keying_operation->get_input_socket(0));
}
- postprocessedMatte = keyingOperation->getOutputSocket();
+ postprocessed_matte = keying_operation->get_output_socket();
/* black / white clipping */
if (keying_data->clip_black > 0.0f || keying_data->clip_white < 1.0f) {
- postprocessedMatte = setupClip(converter,
- postprocessedMatte,
- keying_data->edge_kernel_radius,
- keying_data->edge_kernel_tolerance,
- keying_data->clip_black,
- keying_data->clip_white,
- false);
+ postprocessed_matte = setup_clip(converter,
+ postprocessed_matte,
+ keying_data->edge_kernel_radius,
+ keying_data->edge_kernel_tolerance,
+ keying_data->clip_black,
+ keying_data->clip_white,
+ false);
}
/* output edge matte */
- edgesMatte = setupClip(converter,
- postprocessedMatte,
- keying_data->edge_kernel_radius,
- keying_data->edge_kernel_tolerance,
- keying_data->clip_black,
- keying_data->clip_white,
- true);
+ edges_matte = setup_clip(converter,
+ postprocessed_matte,
+ keying_data->edge_kernel_radius,
+ keying_data->edge_kernel_tolerance,
+ keying_data->clip_black,
+ keying_data->clip_white,
+ true);
/* apply garbage matte */
- if (inputGarbageMatte->isLinked()) {
- SetValueOperation *valueOperation = new SetValueOperation();
- valueOperation->setValue(1.0f);
- converter.addOperation(valueOperation);
+ if (input_garbage_matte->is_linked()) {
+ SetValueOperation *value_operation = new SetValueOperation();
+ value_operation->set_value(1.0f);
+ converter.add_operation(value_operation);
- MathSubtractOperation *subtractOperation = new MathSubtractOperation();
- converter.addOperation(subtractOperation);
+ MathSubtractOperation *subtract_operation = new MathSubtractOperation();
+ converter.add_operation(subtract_operation);
- MathMinimumOperation *minOperation = new MathMinimumOperation();
- converter.addOperation(minOperation);
+ MathMinimumOperation *min_operation = new MathMinimumOperation();
+ converter.add_operation(min_operation);
- converter.addLink(valueOperation->getOutputSocket(), subtractOperation->getInputSocket(0));
- converter.mapInputSocket(inputGarbageMatte, subtractOperation->getInputSocket(1));
+ converter.add_link(value_operation->get_output_socket(),
+ subtract_operation->get_input_socket(0));
+ converter.map_input_socket(input_garbage_matte, subtract_operation->get_input_socket(1));
- converter.addLink(subtractOperation->getOutputSocket(), minOperation->getInputSocket(0));
- converter.addLink(postprocessedMatte, minOperation->getInputSocket(1));
+ converter.add_link(subtract_operation->get_output_socket(),
+ min_operation->get_input_socket(0));
+ converter.add_link(postprocessed_matte, min_operation->get_input_socket(1));
- postprocessedMatte = minOperation->getOutputSocket();
+ postprocessed_matte = min_operation->get_output_socket();
}
/* apply core matte */
- if (inputCoreMatte->isLinked()) {
- MathMaximumOperation *maxOperation = new MathMaximumOperation();
- converter.addOperation(maxOperation);
+ if (input_core_matte->is_linked()) {
+ MathMaximumOperation *max_operation = new MathMaximumOperation();
+ converter.add_operation(max_operation);
- converter.mapInputSocket(inputCoreMatte, maxOperation->getInputSocket(0));
- converter.addLink(postprocessedMatte, maxOperation->getInputSocket(1));
+ converter.map_input_socket(input_core_matte, max_operation->get_input_socket(0));
+ converter.add_link(postprocessed_matte, max_operation->get_input_socket(1));
- postprocessedMatte = maxOperation->getOutputSocket();
+ postprocessed_matte = max_operation->get_output_socket();
}
/* apply blur on matte if needed */
if (keying_data->blur_post) {
- postprocessedMatte = setupPostBlur(converter, postprocessedMatte, keying_data->blur_post);
+ postprocessed_matte = setup_post_blur(converter, postprocessed_matte, keying_data->blur_post);
}
/* matte dilate/erode */
if (keying_data->dilate_distance != 0) {
- postprocessedMatte = setupDilateErode(
- converter, postprocessedMatte, keying_data->dilate_distance);
+ postprocessed_matte = setup_dilate_erode(
+ converter, postprocessed_matte, keying_data->dilate_distance);
}
/* matte feather */
if (keying_data->feather_distance != 0) {
- postprocessedMatte = setupFeather(converter,
- context,
- postprocessedMatte,
- keying_data->feather_falloff,
- keying_data->feather_distance);
+ postprocessed_matte = setup_feather(converter,
+ context,
+ postprocessed_matte,
+ keying_data->feather_falloff,
+ keying_data->feather_distance);
}
/* set alpha channel to output image */
- SetAlphaMultiplyOperation *alphaOperation = new SetAlphaMultiplyOperation();
- converter.addOperation(alphaOperation);
+ SetAlphaMultiplyOperation *alpha_operation = new SetAlphaMultiplyOperation();
+ converter.add_operation(alpha_operation);
- converter.mapInputSocket(inputImage, alphaOperation->getInputSocket(0));
- converter.addLink(postprocessedMatte, alphaOperation->getInputSocket(1));
+ converter.map_input_socket(input_image, alpha_operation->get_input_socket(0));
+ converter.add_link(postprocessed_matte, alpha_operation->get_input_socket(1));
- postprocessedImage = alphaOperation->getOutputSocket();
+ postprocessed_image = alpha_operation->get_output_socket();
/* despill output image */
if (keying_data->despill_factor > 0.0f) {
- postprocessedImage = setupDespill(converter,
- postprocessedImage,
- inputScreen,
- keying_data->despill_factor,
- keying_data->despill_balance);
+ postprocessed_image = setup_despill(converter,
+ postprocessed_image,
+ input_screen,
+ keying_data->despill_factor,
+ keying_data->despill_balance);
}
/* connect result to output sockets */
- converter.mapOutputSocket(outputImage, postprocessedImage);
- converter.mapOutputSocket(outputMatte, postprocessedMatte);
+ converter.map_output_socket(output_image, postprocessed_image);
+ converter.map_output_socket(output_matte, postprocessed_matte);
- if (edgesMatte) {
- converter.mapOutputSocket(outputEdges, edgesMatte);
+ if (edges_matte) {
+ converter.map_output_socket(output_edges, edges_matte);
}
}
diff --git a/source/blender/compositor/nodes/COM_KeyingNode.h b/source/blender/compositor/nodes/COM_KeyingNode.h
index 6d5e3ca1883..ed70433fea3 100644
--- a/source/blender/compositor/nodes/COM_KeyingNode.h
+++ b/source/blender/compositor/nodes/COM_KeyingNode.h
@@ -28,37 +28,37 @@ namespace blender::compositor {
*/
class KeyingNode : public Node {
protected:
- NodeOperationOutput *setupPreBlur(NodeConverter &converter,
- NodeInput *inputImage,
- int size) const;
- NodeOperationOutput *setupPostBlur(NodeConverter &converter,
- NodeOperationOutput *postBlurInput,
- int size) const;
- NodeOperationOutput *setupDilateErode(NodeConverter &converter,
- NodeOperationOutput *dilateErodeInput,
- int distance) const;
- NodeOperationOutput *setupFeather(NodeConverter &converter,
- const CompositorContext &context,
- NodeOperationOutput *featherInput,
- int falloff,
- int distance) const;
- NodeOperationOutput *setupDespill(NodeConverter &converter,
- NodeOperationOutput *despillInput,
- NodeInput *inputScreen,
- float factor,
- float colorBalance) const;
- NodeOperationOutput *setupClip(NodeConverter &converter,
- NodeOperationOutput *clipInput,
- int kernelRadius,
- float kernelTolerance,
- float clipBlack,
- float clipWhite,
- bool edgeMatte) const;
+ NodeOperationOutput *setup_pre_blur(NodeConverter &converter,
+ NodeInput *input_image,
+ int size) const;
+ NodeOperationOutput *setup_post_blur(NodeConverter &converter,
+ NodeOperationOutput *post_blur_input,
+ int size) const;
+ NodeOperationOutput *setup_dilate_erode(NodeConverter &converter,
+ NodeOperationOutput *dilate_erode_input,
+ int distance) const;
+ NodeOperationOutput *setup_feather(NodeConverter &converter,
+ const CompositorContext &context,
+ NodeOperationOutput *feather_input,
+ int falloff,
+ int distance) const;
+ NodeOperationOutput *setup_despill(NodeConverter &converter,
+ NodeOperationOutput *despill_input,
+ NodeInput *input_screen,
+ float factor,
+ float color_balance) const;
+ NodeOperationOutput *setup_clip(NodeConverter &converter,
+ NodeOperationOutput *clip_input,
+ int kernel_radius,
+ float kernel_tolerance,
+ float clip_black,
+ float clip_white,
+ bool edge_matte) const;
public:
- KeyingNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ KeyingNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_KeyingScreenNode.cc b/source/blender/compositor/nodes/COM_KeyingScreenNode.cc
index 43574d02d80..bf5d7bb237a 100644
--- a/source/blender/compositor/nodes/COM_KeyingScreenNode.cc
+++ b/source/blender/compositor/nodes/COM_KeyingScreenNode.cc
@@ -17,35 +17,32 @@
*/
#include "COM_KeyingScreenNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_KeyingScreenOperation.h"
-#include "DNA_movieclip_types.h"
-
namespace blender::compositor {
-KeyingScreenNode::KeyingScreenNode(bNode *editorNode) : Node(editorNode)
+KeyingScreenNode::KeyingScreenNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void KeyingScreenNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void KeyingScreenNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *editorNode = this->getbNode();
- MovieClip *clip = (MovieClip *)editorNode->id;
- NodeKeyingScreenData *keyingscreen_data = (NodeKeyingScreenData *)editorNode->storage;
+ bNode *editor_node = this->get_bnode();
+ MovieClip *clip = (MovieClip *)editor_node->id;
+ NodeKeyingScreenData *keyingscreen_data = (NodeKeyingScreenData *)editor_node->storage;
- NodeOutput *outputScreen = this->getOutputSocket(0);
+ NodeOutput *output_screen = this->get_output_socket(0);
/* Always connect the output image. */
KeyingScreenOperation *operation = new KeyingScreenOperation();
- operation->setMovieClip(clip);
- operation->setTrackingObject(keyingscreen_data->tracking_object);
- operation->setFramenumber(context.getFramenumber());
- converter.addOperation(operation);
+ operation->set_movie_clip(clip);
+ operation->set_tracking_object(keyingscreen_data->tracking_object);
+ operation->set_framenumber(context.get_framenumber());
+ converter.add_operation(operation);
- converter.mapOutputSocket(outputScreen, operation->getOutputSocket());
+ converter.map_output_socket(output_screen, operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_KeyingScreenNode.h b/source/blender/compositor/nodes/COM_KeyingScreenNode.h
index f2ad3b344f1..3704081041f 100644
--- a/source/blender/compositor/nodes/COM_KeyingScreenNode.h
+++ b/source/blender/compositor/nodes/COM_KeyingScreenNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class KeyingScreenNode : public Node {
public:
- KeyingScreenNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ KeyingScreenNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_LensDistortionNode.cc b/source/blender/compositor/nodes/COM_LensDistortionNode.cc
index f5226d31989..7cef21487df 100644
--- a/source/blender/compositor/nodes/COM_LensDistortionNode.cc
+++ b/source/blender/compositor/nodes/COM_LensDistortionNode.cc
@@ -17,48 +17,47 @@
*/
#include "COM_LensDistortionNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_ProjectorLensDistortionOperation.h"
#include "COM_ScreenLensDistortionOperation.h"
namespace blender::compositor {
-LensDistortionNode::LensDistortionNode(bNode *editorNode) : Node(editorNode)
+LensDistortionNode::LensDistortionNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void LensDistortionNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void LensDistortionNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *editorNode = this->getbNode();
- NodeLensDist *data = (NodeLensDist *)editorNode->storage;
+ bNode *editor_node = this->get_bnode();
+ NodeLensDist *data = (NodeLensDist *)editor_node->storage;
if (data->proj) {
ProjectorLensDistortionOperation *operation = new ProjectorLensDistortionOperation();
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(2), operation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
else {
ScreenLensDistortionOperation *operation = new ScreenLensDistortionOperation();
- operation->setFit(data->fit);
- operation->setJitter(data->jit);
+ operation->set_fit(data->fit);
+ operation->set_jitter(data->jit);
- if (!getInputSocket(1)->isLinked()) {
- operation->setDistortion(getInputSocket(1)->getEditorValueFloat());
+ if (!get_input_socket(1)->is_linked()) {
+ operation->set_distortion(get_input_socket(1)->get_editor_value_float());
}
- if (!getInputSocket(2)->isLinked()) {
- operation->setDispersion(getInputSocket(2)->getEditorValueFloat());
+ if (!get_input_socket(2)->is_linked()) {
+ operation->set_dispersion(get_input_socket(2)->get_editor_value_float());
}
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_input_socket(get_input_socket(2), operation->get_input_socket(2));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
}
diff --git a/source/blender/compositor/nodes/COM_LensDistortionNode.h b/source/blender/compositor/nodes/COM_LensDistortionNode.h
index 4de1b0fe4da..154b8c20b86 100644
--- a/source/blender/compositor/nodes/COM_LensDistortionNode.h
+++ b/source/blender/compositor/nodes/COM_LensDistortionNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class LensDistortionNode : public Node {
public:
- LensDistortionNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ LensDistortionNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc
index 920da53231f..645cbe91fd2 100644
--- a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc
+++ b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc
@@ -17,41 +17,39 @@
*/
#include "COM_LuminanceMatteNode.h"
-#include "BKE_node.h"
-#include "COM_ConvertOperation.h"
#include "COM_LuminanceMatteOperation.h"
#include "COM_SetAlphaMultiplyOperation.h"
namespace blender::compositor {
-LuminanceMatteNode::LuminanceMatteNode(bNode *editorNode) : Node(editorNode)
+LuminanceMatteNode::LuminanceMatteNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void LuminanceMatteNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void LuminanceMatteNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *editorsnode = getbNode();
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeOutput *outputSocketImage = this->getOutputSocket(0);
- NodeOutput *outputSocketMatte = this->getOutputSocket(1);
+ bNode *editorsnode = get_bnode();
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeOutput *output_socket_image = this->get_output_socket(0);
+ NodeOutput *output_socket_matte = this->get_output_socket(1);
- LuminanceMatteOperation *operationSet = new LuminanceMatteOperation();
- operationSet->setSettings((NodeChroma *)editorsnode->storage);
- converter.addOperation(operationSet);
+ LuminanceMatteOperation *operation_set = new LuminanceMatteOperation();
+ operation_set->set_settings((NodeChroma *)editorsnode->storage);
+ converter.add_operation(operation_set);
- converter.mapInputSocket(inputSocket, operationSet->getInputSocket(0));
- converter.mapOutputSocket(outputSocketMatte, operationSet->getOutputSocket(0));
+ converter.map_input_socket(input_socket, operation_set->get_input_socket(0));
+ converter.map_output_socket(output_socket_matte, operation_set->get_output_socket(0));
SetAlphaMultiplyOperation *operation = new SetAlphaMultiplyOperation();
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.addLink(operationSet->getOutputSocket(), operation->getInputSocket(1));
- converter.mapOutputSocket(outputSocketImage, operation->getOutputSocket());
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.add_link(operation_set->get_output_socket(), operation->get_input_socket(1));
+ converter.map_output_socket(output_socket_image, operation->get_output_socket());
- converter.addPreview(operation->getOutputSocket());
+ converter.add_preview(operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_LuminanceMatteNode.h b/source/blender/compositor/nodes/COM_LuminanceMatteNode.h
index ef4ebc8ad92..1f934c73d1e 100644
--- a/source/blender/compositor/nodes/COM_LuminanceMatteNode.h
+++ b/source/blender/compositor/nodes/COM_LuminanceMatteNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class LuminanceMatteNode : public Node {
public:
- LuminanceMatteNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ LuminanceMatteNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_MapRangeNode.cc b/source/blender/compositor/nodes/COM_MapRangeNode.cc
index 718a6d9e47b..45f3113ca9e 100644
--- a/source/blender/compositor/nodes/COM_MapRangeNode.cc
+++ b/source/blender/compositor/nodes/COM_MapRangeNode.cc
@@ -18,36 +18,35 @@
#include "COM_MapRangeNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_MapRangeOperation.h"
namespace blender::compositor {
-MapRangeNode::MapRangeNode(bNode *editorNode) : Node(editorNode)
+MapRangeNode::MapRangeNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void MapRangeNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void MapRangeNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeInput *valueSocket = this->getInputSocket(0);
- NodeInput *sourceMinSocket = this->getInputSocket(1);
- NodeInput *sourceMaxSocket = this->getInputSocket(2);
- NodeInput *destMinSocket = this->getInputSocket(3);
- NodeInput *destMaxSocket = this->getInputSocket(4);
- NodeOutput *outputSocket = this->getOutputSocket(0);
+ NodeInput *value_socket = this->get_input_socket(0);
+ NodeInput *source_min_socket = this->get_input_socket(1);
+ NodeInput *source_max_socket = this->get_input_socket(2);
+ NodeInput *dest_min_socket = this->get_input_socket(3);
+ NodeInput *dest_max_socket = this->get_input_socket(4);
+ NodeOutput *output_socket = this->get_output_socket(0);
MapRangeOperation *operation = new MapRangeOperation();
- operation->setUseClamp(this->getbNode()->custom1);
- converter.addOperation(operation);
-
- converter.mapInputSocket(valueSocket, operation->getInputSocket(0));
- converter.mapInputSocket(sourceMinSocket, operation->getInputSocket(1));
- converter.mapInputSocket(sourceMaxSocket, operation->getInputSocket(2));
- converter.mapInputSocket(destMinSocket, operation->getInputSocket(3));
- converter.mapInputSocket(destMaxSocket, operation->getInputSocket(4));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ operation->set_use_clamp(this->get_bnode()->custom1);
+ converter.add_operation(operation);
+
+ converter.map_input_socket(value_socket, operation->get_input_socket(0));
+ converter.map_input_socket(source_min_socket, operation->get_input_socket(1));
+ converter.map_input_socket(source_max_socket, operation->get_input_socket(2));
+ converter.map_input_socket(dest_min_socket, operation->get_input_socket(3));
+ converter.map_input_socket(dest_max_socket, operation->get_input_socket(4));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_MapRangeNode.h b/source/blender/compositor/nodes/COM_MapRangeNode.h
index ad6fd78a7d5..c9323ac00c2 100644
--- a/source/blender/compositor/nodes/COM_MapRangeNode.h
+++ b/source/blender/compositor/nodes/COM_MapRangeNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class MapRangeNode : public Node {
public:
- MapRangeNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ MapRangeNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_MapUVNode.cc b/source/blender/compositor/nodes/COM_MapUVNode.cc
index bbf9e8f3aeb..9c794165e0b 100644
--- a/source/blender/compositor/nodes/COM_MapUVNode.cc
+++ b/source/blender/compositor/nodes/COM_MapUVNode.cc
@@ -17,29 +17,28 @@
*/
#include "COM_MapUVNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_MapUVOperation.h"
namespace blender::compositor {
-MapUVNode::MapUVNode(bNode *editorNode) : Node(editorNode)
+MapUVNode::MapUVNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void MapUVNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void MapUVNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bNode *node = this->getbNode();
+ bNode *node = this->get_bnode();
MapUVOperation *operation = new MapUVOperation();
- operation->setAlpha((float)node->custom1);
+ operation->set_alpha((float)node->custom1);
operation->set_canvas_input_index(1);
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_MapUVNode.h b/source/blender/compositor/nodes/COM_MapUVNode.h
index f7f4db167ea..eebfd0e66fa 100644
--- a/source/blender/compositor/nodes/COM_MapUVNode.h
+++ b/source/blender/compositor/nodes/COM_MapUVNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class MapUVNode : public Node {
public:
- MapUVNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ MapUVNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_MapValueNode.cc b/source/blender/compositor/nodes/COM_MapValueNode.cc
index ae48bda6cb8..8c81a902863 100644
--- a/source/blender/compositor/nodes/COM_MapValueNode.cc
+++ b/source/blender/compositor/nodes/COM_MapValueNode.cc
@@ -18,30 +18,29 @@
#include "COM_MapValueNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_MapValueOperation.h"
namespace blender::compositor {
-MapValueNode::MapValueNode(bNode *editorNode) : Node(editorNode)
+MapValueNode::MapValueNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void MapValueNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void MapValueNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- TexMapping *storage = (TexMapping *)this->getbNode()->storage;
+ TexMapping *storage = (TexMapping *)this->get_bnode()->storage;
- NodeInput *colorSocket = this->getInputSocket(0);
- NodeOutput *valueSocket = this->getOutputSocket(0);
+ NodeInput *color_socket = this->get_input_socket(0);
+ NodeOutput *value_socket = this->get_output_socket(0);
- MapValueOperation *convertProg = new MapValueOperation();
- convertProg->setSettings(storage);
- converter.addOperation(convertProg);
+ MapValueOperation *convert_prog = new MapValueOperation();
+ convert_prog->set_settings(storage);
+ converter.add_operation(convert_prog);
- converter.mapInputSocket(colorSocket, convertProg->getInputSocket(0));
- converter.mapOutputSocket(valueSocket, convertProg->getOutputSocket(0));
+ converter.map_input_socket(color_socket, convert_prog->get_input_socket(0));
+ converter.map_output_socket(value_socket, convert_prog->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_MapValueNode.h b/source/blender/compositor/nodes/COM_MapValueNode.h
index dcac1d6e3c5..4516d7eb016 100644
--- a/source/blender/compositor/nodes/COM_MapValueNode.h
+++ b/source/blender/compositor/nodes/COM_MapValueNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class MapValueNode : public Node {
public:
- MapValueNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ MapValueNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_MaskNode.cc b/source/blender/compositor/nodes/COM_MaskNode.cc
index b5b23798160..b1e0506089e 100644
--- a/source/blender/compositor/nodes/COM_MaskNode.cc
+++ b/source/blender/compositor/nodes/COM_MaskNode.cc
@@ -17,58 +17,55 @@
*/
#include "COM_MaskNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_MaskOperation.h"
-#include "DNA_mask_types.h"
-
namespace blender::compositor {
-MaskNode::MaskNode(bNode *editorNode) : Node(editorNode)
+MaskNode::MaskNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void MaskNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void MaskNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- const RenderData *rd = context.getRenderData();
- const float render_size_factor = context.getRenderPercentageAsFactor();
+ const RenderData *rd = context.get_render_data();
+ const float render_size_factor = context.get_render_percentage_as_factor();
- NodeOutput *outputMask = this->getOutputSocket(0);
+ NodeOutput *output_mask = this->get_output_socket(0);
- bNode *editorNode = this->getbNode();
- NodeMask *data = (NodeMask *)editorNode->storage;
- Mask *mask = (Mask *)editorNode->id;
+ bNode *editor_node = this->get_bnode();
+ NodeMask *data = (NodeMask *)editor_node->storage;
+ Mask *mask = (Mask *)editor_node->id;
/* Always connect the output image. */
MaskOperation *operation = new MaskOperation();
- if (editorNode->custom1 & CMP_NODEFLAG_MASK_FIXED) {
- operation->setMaskWidth(data->size_x);
- operation->setMaskHeight(data->size_y);
+ if (editor_node->custom1 & CMP_NODEFLAG_MASK_FIXED) {
+ operation->set_mask_width(data->size_x);
+ operation->set_mask_height(data->size_y);
}
- else if (editorNode->custom1 & CMP_NODEFLAG_MASK_FIXED_SCENE) {
- operation->setMaskWidth(data->size_x * render_size_factor);
- operation->setMaskHeight(data->size_y * render_size_factor);
+ else if (editor_node->custom1 & CMP_NODEFLAG_MASK_FIXED_SCENE) {
+ operation->set_mask_width(data->size_x * render_size_factor);
+ operation->set_mask_height(data->size_y * render_size_factor);
}
else {
- operation->setMaskWidth(rd->xsch * render_size_factor);
- operation->setMaskHeight(rd->ysch * render_size_factor);
+ operation->set_mask_width(rd->xsch * render_size_factor);
+ operation->set_mask_height(rd->ysch * render_size_factor);
}
- operation->setMask(mask);
- operation->setFramenumber(context.getFramenumber());
- operation->setFeather((bool)(editorNode->custom1 & CMP_NODEFLAG_MASK_NO_FEATHER) == 0);
+ operation->set_mask(mask);
+ operation->set_framenumber(context.get_framenumber());
+ operation->set_feather((bool)(editor_node->custom1 & CMP_NODEFLAG_MASK_NO_FEATHER) == 0);
- if ((editorNode->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) && (editorNode->custom2 > 1) &&
- (editorNode->custom3 > FLT_EPSILON)) {
- operation->setMotionBlurSamples(editorNode->custom2);
- operation->setMotionBlurShutter(editorNode->custom3);
+ if ((editor_node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) && (editor_node->custom2 > 1) &&
+ (editor_node->custom3 > FLT_EPSILON)) {
+ operation->set_motion_blur_samples(editor_node->custom2);
+ operation->set_motion_blur_shutter(editor_node->custom3);
}
- converter.addOperation(operation);
- converter.mapOutputSocket(outputMask, operation->getOutputSocket());
+ converter.add_operation(operation);
+ converter.map_output_socket(output_mask, operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_MaskNode.h b/source/blender/compositor/nodes/COM_MaskNode.h
index 5890cf5957a..0d9d4284b27 100644
--- a/source/blender/compositor/nodes/COM_MaskNode.h
+++ b/source/blender/compositor/nodes/COM_MaskNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class MaskNode : public Node {
public:
- MaskNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ MaskNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_MathNode.cc b/source/blender/compositor/nodes/COM_MathNode.cc
index dd0d8931d58..6102aed0f88 100644
--- a/source/blender/compositor/nodes/COM_MathNode.cc
+++ b/source/blender/compositor/nodes/COM_MathNode.cc
@@ -17,17 +17,16 @@
*/
#include "COM_MathNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_MathBaseOperation.h"
namespace blender::compositor {
-void MathNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void MathNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
MathBaseOperation *operation = nullptr;
- switch (this->getbNode()->custom1) {
+ switch (this->get_bnode()->custom1) {
case NODE_MATH_ADD:
operation = new MathAddOperation();
break;
@@ -151,14 +150,14 @@ void MathNode::convertToOperations(NodeConverter &converter,
}
if (operation) {
- bool useClamp = getbNode()->custom2;
- operation->setUseClamp(useClamp);
- converter.addOperation(operation);
+ bool use_clamp = get_bnode()->custom2;
+ operation->set_use_clamp(use_clamp);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_input_socket(get_input_socket(2), operation->get_input_socket(2));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
}
}
diff --git a/source/blender/compositor/nodes/COM_MathNode.h b/source/blender/compositor/nodes/COM_MathNode.h
index 5db59e62bab..7f60fc03fcd 100644
--- a/source/blender/compositor/nodes/COM_MathNode.h
+++ b/source/blender/compositor/nodes/COM_MathNode.h
@@ -28,11 +28,11 @@ namespace blender::compositor {
*/
class MathNode : public Node {
public:
- MathNode(bNode *editorNode) : Node(editorNode)
+ MathNode(bNode *editor_node) : Node(editor_node)
{
}
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_MixNode.cc b/source/blender/compositor/nodes/COM_MixNode.cc
index cfa8d0ee6a6..ae7736b4b67 100644
--- a/source/blender/compositor/nodes/COM_MixNode.cc
+++ b/source/blender/compositor/nodes/COM_MixNode.cc
@@ -20,97 +20,95 @@
#include "COM_MixOperation.h"
-#include "COM_ExecutionSystem.h"
-#include "COM_SetValueOperation.h"
#include "DNA_material_types.h" /* the ramp types */
namespace blender::compositor {
-MixNode::MixNode(bNode *editorNode) : Node(editorNode)
+MixNode::MixNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void MixNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void MixNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeInput *valueSocket = this->getInputSocket(0);
- NodeInput *color1Socket = this->getInputSocket(1);
- NodeInput *color2Socket = this->getInputSocket(2);
- NodeOutput *outputSocket = this->getOutputSocket(0);
- bNode *editorNode = this->getbNode();
- bool useAlphaPremultiply = (this->getbNode()->custom2 & 1) != 0;
- bool useClamp = (this->getbNode()->custom2 & 2) != 0;
+ NodeInput *value_socket = this->get_input_socket(0);
+ NodeInput *color1Socket = this->get_input_socket(1);
+ NodeInput *color2Socket = this->get_input_socket(2);
+ NodeOutput *output_socket = this->get_output_socket(0);
+ bNode *editor_node = this->get_bnode();
+ bool use_alpha_premultiply = (this->get_bnode()->custom2 & 1) != 0;
+ bool use_clamp = (this->get_bnode()->custom2 & 2) != 0;
- MixBaseOperation *convertProg;
- switch (editorNode->custom1) {
+ MixBaseOperation *convert_prog;
+ switch (editor_node->custom1) {
case MA_RAMP_ADD:
- convertProg = new MixAddOperation();
+ convert_prog = new MixAddOperation();
break;
case MA_RAMP_MULT:
- convertProg = new MixMultiplyOperation();
+ convert_prog = new MixMultiplyOperation();
break;
case MA_RAMP_LIGHT:
- convertProg = new MixLightenOperation();
+ convert_prog = new MixLightenOperation();
break;
case MA_RAMP_BURN:
- convertProg = new MixColorBurnOperation();
+ convert_prog = new MixColorBurnOperation();
break;
case MA_RAMP_HUE:
- convertProg = new MixHueOperation();
+ convert_prog = new MixHueOperation();
break;
case MA_RAMP_COLOR:
- convertProg = new MixColorOperation();
+ convert_prog = new MixColorOperation();
break;
case MA_RAMP_SOFT:
- convertProg = new MixSoftLightOperation();
+ convert_prog = new MixSoftLightOperation();
break;
case MA_RAMP_SCREEN:
- convertProg = new MixScreenOperation();
+ convert_prog = new MixScreenOperation();
break;
case MA_RAMP_LINEAR:
- convertProg = new MixLinearLightOperation();
+ convert_prog = new MixLinearLightOperation();
break;
case MA_RAMP_DIFF:
- convertProg = new MixDifferenceOperation();
+ convert_prog = new MixDifferenceOperation();
break;
case MA_RAMP_SAT:
- convertProg = new MixSaturationOperation();
+ convert_prog = new MixSaturationOperation();
break;
case MA_RAMP_DIV:
- convertProg = new MixDivideOperation();
+ convert_prog = new MixDivideOperation();
break;
case MA_RAMP_SUB:
- convertProg = new MixSubtractOperation();
+ convert_prog = new MixSubtractOperation();
break;
case MA_RAMP_DARK:
- convertProg = new MixDarkenOperation();
+ convert_prog = new MixDarkenOperation();
break;
case MA_RAMP_OVERLAY:
- convertProg = new MixOverlayOperation();
+ convert_prog = new MixOverlayOperation();
break;
case MA_RAMP_VAL:
- convertProg = new MixValueOperation();
+ convert_prog = new MixValueOperation();
break;
case MA_RAMP_DODGE:
- convertProg = new MixDodgeOperation();
+ convert_prog = new MixDodgeOperation();
break;
case MA_RAMP_BLEND:
default:
- convertProg = new MixBlendOperation();
+ convert_prog = new MixBlendOperation();
break;
}
- convertProg->setUseValueAlphaMultiply(useAlphaPremultiply);
- convertProg->setUseClamp(useClamp);
- converter.addOperation(convertProg);
+ convert_prog->set_use_value_alpha_multiply(use_alpha_premultiply);
+ convert_prog->set_use_clamp(use_clamp);
+ converter.add_operation(convert_prog);
- converter.mapInputSocket(valueSocket, convertProg->getInputSocket(0));
- converter.mapInputSocket(color1Socket, convertProg->getInputSocket(1));
- converter.mapInputSocket(color2Socket, convertProg->getInputSocket(2));
- converter.mapOutputSocket(outputSocket, convertProg->getOutputSocket(0));
+ converter.map_input_socket(value_socket, convert_prog->get_input_socket(0));
+ converter.map_input_socket(color1Socket, convert_prog->get_input_socket(1));
+ converter.map_input_socket(color2Socket, convert_prog->get_input_socket(2));
+ converter.map_output_socket(output_socket, convert_prog->get_output_socket(0));
- converter.addPreview(convertProg->getOutputSocket(0));
+ converter.add_preview(convert_prog->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_MixNode.h b/source/blender/compositor/nodes/COM_MixNode.h
index 81f9c41871e..1a6bdf1cf57 100644
--- a/source/blender/compositor/nodes/COM_MixNode.h
+++ b/source/blender/compositor/nodes/COM_MixNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class MixNode : public Node {
public:
- MixNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ MixNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_MovieClipNode.cc b/source/blender/compositor/nodes/COM_MovieClipNode.cc
index b80071d27c7..b71e379304e 100644
--- a/source/blender/compositor/nodes/COM_MovieClipNode.cc
+++ b/source/blender/compositor/nodes/COM_MovieClipNode.cc
@@ -17,10 +17,8 @@
*/
#include "COM_MovieClipNode.h"
-#include "COM_ConvertColorProfileOperation.h"
-#include "COM_ExecutionSystem.h"
+
#include "COM_MovieClipOperation.h"
-#include "COM_SetValueOperation.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
@@ -31,58 +29,58 @@
namespace blender::compositor {
-MovieClipNode::MovieClipNode(bNode *editorNode) : Node(editorNode)
+MovieClipNode::MovieClipNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void MovieClipNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void MovieClipNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- NodeOutput *outputMovieClip = this->getOutputSocket(0);
- NodeOutput *alphaMovieClip = this->getOutputSocket(1);
- NodeOutput *offsetXMovieClip = this->getOutputSocket(2);
- NodeOutput *offsetYMovieClip = this->getOutputSocket(3);
- NodeOutput *scaleMovieClip = this->getOutputSocket(4);
- NodeOutput *angleMovieClip = this->getOutputSocket(5);
-
- bNode *editorNode = this->getbNode();
- MovieClip *movieClip = (MovieClip *)editorNode->id;
- MovieClipUser *movieClipUser = (MovieClipUser *)editorNode->storage;
- bool cacheFrame = !context.isRendering();
+ NodeOutput *output_movie_clip = this->get_output_socket(0);
+ NodeOutput *alpha_movie_clip = this->get_output_socket(1);
+ NodeOutput *offset_xmovie_clip = this->get_output_socket(2);
+ NodeOutput *offset_ymovie_clip = this->get_output_socket(3);
+ NodeOutput *scale_movie_clip = this->get_output_socket(4);
+ NodeOutput *angle_movie_clip = this->get_output_socket(5);
+
+ bNode *editor_node = this->get_bnode();
+ MovieClip *movie_clip = (MovieClip *)editor_node->id;
+ MovieClipUser *movie_clip_user = (MovieClipUser *)editor_node->storage;
+ bool cache_frame = !context.is_rendering();
ImBuf *ibuf = nullptr;
- if (movieClip) {
- if (cacheFrame) {
- ibuf = BKE_movieclip_get_ibuf(movieClip, movieClipUser);
+ if (movie_clip) {
+ if (cache_frame) {
+ ibuf = BKE_movieclip_get_ibuf(movie_clip, movie_clip_user);
}
else {
ibuf = BKE_movieclip_get_ibuf_flag(
- movieClip, movieClipUser, movieClip->flag, MOVIECLIP_CACHE_SKIP);
+ movie_clip, movie_clip_user, movie_clip->flag, MOVIECLIP_CACHE_SKIP);
}
}
/* Always connect the output image. */
MovieClipOperation *operation = new MovieClipOperation();
- operation->setMovieClip(movieClip);
- operation->setMovieClipUser(movieClipUser);
- operation->setFramenumber(context.getFramenumber());
- operation->setCacheFrame(cacheFrame);
+ operation->set_movie_clip(movie_clip);
+ operation->set_movie_clip_user(movie_clip_user);
+ operation->set_framenumber(context.get_framenumber());
+ operation->set_cache_frame(cache_frame);
- converter.addOperation(operation);
- converter.mapOutputSocket(outputMovieClip, operation->getOutputSocket());
- converter.addPreview(operation->getOutputSocket());
+ converter.add_operation(operation);
+ converter.map_output_socket(output_movie_clip, operation->get_output_socket());
+ converter.add_preview(operation->get_output_socket());
- MovieClipAlphaOperation *alphaOperation = new MovieClipAlphaOperation();
- alphaOperation->setMovieClip(movieClip);
- alphaOperation->setMovieClipUser(movieClipUser);
- alphaOperation->setFramenumber(context.getFramenumber());
- alphaOperation->setCacheFrame(cacheFrame);
+ MovieClipAlphaOperation *alpha_operation = new MovieClipAlphaOperation();
+ alpha_operation->set_movie_clip(movie_clip);
+ alpha_operation->set_movie_clip_user(movie_clip_user);
+ alpha_operation->set_framenumber(context.get_framenumber());
+ alpha_operation->set_cache_frame(cache_frame);
- converter.addOperation(alphaOperation);
- converter.mapOutputSocket(alphaMovieClip, alphaOperation->getOutputSocket());
+ converter.add_operation(alpha_operation);
+ converter.map_output_socket(alpha_movie_clip, alpha_operation->get_output_socket());
- MovieTrackingStabilization *stab = &movieClip->tracking.stabilization;
+ MovieTrackingStabilization *stab = &movie_clip->tracking.stabilization;
float loc[2], scale, angle;
loc[0] = 0.0f;
loc[1] = 0.0f;
@@ -91,18 +89,18 @@ void MovieClipNode::convertToOperations(NodeConverter &converter,
if (ibuf) {
if (stab->flag & TRACKING_2D_STABILIZATION) {
- int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(movieClip,
- context.getFramenumber());
+ int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(movie_clip,
+ context.get_framenumber());
BKE_tracking_stabilization_data_get(
- movieClip, clip_framenr, ibuf->x, ibuf->y, loc, &scale, &angle);
+ movie_clip, clip_framenr, ibuf->x, ibuf->y, loc, &scale, &angle);
}
}
- converter.addOutputValue(offsetXMovieClip, loc[0]);
- converter.addOutputValue(offsetYMovieClip, loc[1]);
- converter.addOutputValue(scaleMovieClip, scale);
- converter.addOutputValue(angleMovieClip, angle);
+ converter.add_output_value(offset_xmovie_clip, loc[0]);
+ converter.add_output_value(offset_ymovie_clip, loc[1]);
+ converter.add_output_value(scale_movie_clip, scale);
+ converter.add_output_value(angle_movie_clip, angle);
if (ibuf) {
IMB_freeImBuf(ibuf);
diff --git a/source/blender/compositor/nodes/COM_MovieClipNode.h b/source/blender/compositor/nodes/COM_MovieClipNode.h
index a469ce9e2a4..cf9e7a3e01e 100644
--- a/source/blender/compositor/nodes/COM_MovieClipNode.h
+++ b/source/blender/compositor/nodes/COM_MovieClipNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class MovieClipNode : public Node {
public:
- MovieClipNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ MovieClipNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_MovieDistortionNode.cc b/source/blender/compositor/nodes/COM_MovieDistortionNode.cc
index 8f17ef8bb98..03b780198cd 100644
--- a/source/blender/compositor/nodes/COM_MovieDistortionNode.cc
+++ b/source/blender/compositor/nodes/COM_MovieDistortionNode.cc
@@ -18,33 +18,31 @@
#include "COM_MovieDistortionNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_MovieDistortionOperation.h"
-#include "DNA_movieclip_types.h"
namespace blender::compositor {
-MovieDistortionNode::MovieDistortionNode(bNode *editorNode) : Node(editorNode)
+MovieDistortionNode::MovieDistortionNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void MovieDistortionNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void MovieDistortionNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *bnode = this->getbNode();
+ bNode *bnode = this->get_bnode();
MovieClip *clip = (MovieClip *)bnode->id;
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeOutput *outputSocket = this->getOutputSocket(0);
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeOutput *output_socket = this->get_output_socket(0);
MovieDistortionOperation *operation = new MovieDistortionOperation(bnode->custom1 == 1);
- operation->setMovieClip(clip);
- operation->setFramenumber(context.getFramenumber());
- converter.addOperation(operation);
+ operation->set_movie_clip(clip);
+ operation->set_framenumber(context.get_framenumber());
+ converter.add_operation(operation);
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_MovieDistortionNode.h b/source/blender/compositor/nodes/COM_MovieDistortionNode.h
index 0c1610aa3d3..530b0dd6f97 100644
--- a/source/blender/compositor/nodes/COM_MovieDistortionNode.h
+++ b/source/blender/compositor/nodes/COM_MovieDistortionNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class MovieDistortionNode : public Node {
public:
- MovieDistortionNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ MovieDistortionNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_NormalNode.cc b/source/blender/compositor/nodes/COM_NormalNode.cc
index 5a97b0932ef..f9875c6015c 100644
--- a/source/blender/compositor/nodes/COM_NormalNode.cc
+++ b/source/blender/compositor/nodes/COM_NormalNode.cc
@@ -17,44 +17,42 @@
*/
#include "COM_NormalNode.h"
-#include "BKE_node.h"
#include "COM_DotproductOperation.h"
-#include "COM_ExecutionSystem.h"
#include "COM_SetVectorOperation.h"
namespace blender::compositor {
-NormalNode::NormalNode(bNode *editorNode) : Node(editorNode)
+NormalNode::NormalNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void NormalNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void NormalNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeOutput *outputSocket = this->getOutputSocket(0);
- NodeOutput *outputSocketDotproduct = this->getOutputSocket(1);
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeOutput *output_socket = this->get_output_socket(0);
+ NodeOutput *output_socket_dotproduct = this->get_output_socket(1);
- SetVectorOperation *operationSet = new SetVectorOperation();
+ SetVectorOperation *operation_set = new SetVectorOperation();
float normal[3];
- outputSocket->getEditorValueVector(normal);
+ output_socket->get_editor_value_vector(normal);
/* animation can break normalization, this restores it */
normalize_v3(normal);
- operationSet->setX(normal[0]);
- operationSet->setY(normal[1]);
- operationSet->setZ(normal[2]);
- operationSet->setW(0.0f);
- converter.addOperation(operationSet);
+ operation_set->setX(normal[0]);
+ operation_set->setY(normal[1]);
+ operation_set->setZ(normal[2]);
+ operation_set->setW(0.0f);
+ converter.add_operation(operation_set);
- converter.mapOutputSocket(outputSocket, operationSet->getOutputSocket(0));
+ converter.map_output_socket(output_socket, operation_set->get_output_socket(0));
DotproductOperation *operation = new DotproductOperation();
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.addLink(operationSet->getOutputSocket(0), operation->getInputSocket(1));
- converter.mapOutputSocket(outputSocketDotproduct, operation->getOutputSocket(0));
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.add_link(operation_set->get_output_socket(0), operation->get_input_socket(1));
+ converter.map_output_socket(output_socket_dotproduct, operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_NormalNode.h b/source/blender/compositor/nodes/COM_NormalNode.h
index 6d5cbb394a0..2fcbb280c20 100644
--- a/source/blender/compositor/nodes/COM_NormalNode.h
+++ b/source/blender/compositor/nodes/COM_NormalNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class NormalNode : public Node {
public:
- NormalNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ NormalNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_NormalizeNode.cc b/source/blender/compositor/nodes/COM_NormalizeNode.cc
index 639dd8e5a51..0dbd9e1837c 100644
--- a/source/blender/compositor/nodes/COM_NormalizeNode.cc
+++ b/source/blender/compositor/nodes/COM_NormalizeNode.cc
@@ -17,24 +17,23 @@
*/
#include "COM_NormalizeNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_NormalizeOperation.h"
namespace blender::compositor {
-NormalizeNode::NormalizeNode(bNode *editorNode) : Node(editorNode)
+NormalizeNode::NormalizeNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void NormalizeNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void NormalizeNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
NormalizeOperation *operation = new NormalizeOperation();
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_NormalizeNode.h b/source/blender/compositor/nodes/COM_NormalizeNode.h
index 7770fc49b61..50d3b939b30 100644
--- a/source/blender/compositor/nodes/COM_NormalizeNode.h
+++ b/source/blender/compositor/nodes/COM_NormalizeNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class NormalizeNode : public Node {
public:
- NormalizeNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ NormalizeNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cc b/source/blender/compositor/nodes/COM_OutputFileNode.cc
index 25ec7331849..1a9908d4a93 100644
--- a/source/blender/compositor/nodes/COM_OutputFileNode.cc
+++ b/source/blender/compositor/nodes/COM_OutputFileNode.cc
@@ -17,52 +17,46 @@
*/
#include "COM_OutputFileNode.h"
-#include "COM_ExecutionSystem.h"
-#include "COM_OutputFileOperation.h"
-
-#include "BKE_scene.h"
-
-#include "BLI_path_util.h"
namespace blender::compositor {
-OutputFileNode::OutputFileNode(bNode *editorNode) : Node(editorNode)
+OutputFileNode::OutputFileNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
void OutputFileNode::add_input_sockets(OutputOpenExrMultiLayerOperation &operation) const
{
- for (NodeInput *input : inputs) {
+ for (NodeInput *input : inputs_) {
NodeImageMultiFileSocket *sockdata =
- (NodeImageMultiFileSocket *)input->getbNodeSocket()->storage;
+ (NodeImageMultiFileSocket *)input->get_bnode_socket()->storage;
/* NOTE: layer becomes an empty placeholder if the input is not linked. */
- operation.add_layer(sockdata->layer, input->getDataType(), input->isLinked());
+ operation.add_layer(sockdata->layer, input->get_data_type(), input->is_linked());
}
}
void OutputFileNode::map_input_sockets(NodeConverter &converter,
OutputOpenExrMultiLayerOperation &operation) const
{
- bool previewAdded = false;
+ bool preview_added = false;
int index = 0;
- for (NodeInput *input : inputs) {
- converter.mapInputSocket(input, operation.getInputSocket(index++));
+ for (NodeInput *input : inputs_) {
+ converter.map_input_socket(input, operation.get_input_socket(index++));
- if (!previewAdded) {
- converter.addNodeInputPreview(input);
- previewAdded = true;
+ if (!preview_added) {
+ converter.add_node_input_preview(input);
+ preview_added = true;
}
}
}
-void OutputFileNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void OutputFileNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- NodeImageMultiFile *storage = (NodeImageMultiFile *)this->getbNode()->storage;
- const bool is_multiview = (context.getRenderData()->scemode & R_MULTIVIEW) != 0;
+ NodeImageMultiFile *storage = (NodeImageMultiFile *)this->get_bnode()->storage;
+ const bool is_multiview = (context.get_render_data()->scemode & R_MULTIVIEW) != 0;
- if (!context.isRendering()) {
+ if (!context.is_rendering()) {
/* only output files when rendering a sequence -
* otherwise, it overwrites the output files just
* scrubbing through the timeline when the compositor updates.
@@ -73,40 +67,40 @@ void OutputFileNode::convertToOperations(NodeConverter &converter,
if (storage->format.imtype == R_IMF_IMTYPE_MULTILAYER) {
const bool use_half_float = (storage->format.depth == R_IMF_CHAN_DEPTH_16);
/* single output operation for the multilayer file */
- OutputOpenExrMultiLayerOperation *outputOperation;
+ OutputOpenExrMultiLayerOperation *output_operation;
if (is_multiview && storage->format.views_format == R_IMF_VIEWS_MULTIVIEW) {
- outputOperation = new OutputOpenExrMultiLayerMultiViewOperation(context.getScene(),
- context.getRenderData(),
- context.getbNodeTree(),
- storage->base_path,
- storage->format.exr_codec,
- use_half_float,
- context.getViewName());
+ output_operation = new OutputOpenExrMultiLayerMultiViewOperation(context.get_scene(),
+ context.get_render_data(),
+ context.get_bnodetree(),
+ storage->base_path,
+ storage->format.exr_codec,
+ use_half_float,
+ context.get_view_name());
}
else {
- outputOperation = new OutputOpenExrMultiLayerOperation(context.getScene(),
- context.getRenderData(),
- context.getbNodeTree(),
- storage->base_path,
- storage->format.exr_codec,
- use_half_float,
- context.getViewName());
+ output_operation = new OutputOpenExrMultiLayerOperation(context.get_scene(),
+ context.get_render_data(),
+ context.get_bnodetree(),
+ storage->base_path,
+ storage->format.exr_codec,
+ use_half_float,
+ context.get_view_name());
}
- converter.addOperation(outputOperation);
+ converter.add_operation(output_operation);
/* First add all inputs. Inputs are stored in a Vector and can be moved to a different
* memory address during this time. */
- add_input_sockets(*outputOperation);
+ add_input_sockets(*output_operation);
/* After adding the sockets the memory addresses will stick. */
- map_input_sockets(converter, *outputOperation);
+ map_input_sockets(converter, *output_operation);
}
else { /* single layer format */
- bool previewAdded = false;
- for (NodeInput *input : inputs) {
- if (input->isLinked()) {
+ bool preview_added = false;
+ for (NodeInput *input : inputs_) {
+ if (input->is_linked()) {
NodeImageMultiFileSocket *sockdata =
- (NodeImageMultiFileSocket *)input->getbNodeSocket()->storage;
+ (NodeImageMultiFileSocket *)input->get_bnode_socket()->storage;
ImageFormatData *format = (sockdata->use_node_format ? &storage->format :
&sockdata->format);
char path[FILE_MAX];
@@ -114,50 +108,50 @@ void OutputFileNode::convertToOperations(NodeConverter &converter,
/* combine file path for the input */
BLI_join_dirfile(path, FILE_MAX, storage->base_path, sockdata->path);
- NodeOperation *outputOperation = nullptr;
+ NodeOperation *output_operation = nullptr;
if (is_multiview && format->views_format == R_IMF_VIEWS_MULTIVIEW) {
- outputOperation = new OutputOpenExrSingleLayerMultiViewOperation(
- context.getRenderData(),
- context.getbNodeTree(),
- input->getDataType(),
+ output_operation = new OutputOpenExrSingleLayerMultiViewOperation(
+ context.get_render_data(),
+ context.get_bnodetree(),
+ input->get_data_type(),
format,
path,
- context.getViewSettings(),
- context.getDisplaySettings(),
- context.getViewName(),
+ context.get_view_settings(),
+ context.get_display_settings(),
+ context.get_view_name(),
sockdata->save_as_render);
}
else if ((!is_multiview) || (format->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
- outputOperation = new OutputSingleLayerOperation(context.getRenderData(),
- context.getbNodeTree(),
- input->getDataType(),
- format,
- path,
- context.getViewSettings(),
- context.getDisplaySettings(),
- context.getViewName(),
- sockdata->save_as_render);
+ output_operation = new OutputSingleLayerOperation(context.get_render_data(),
+ context.get_bnodetree(),
+ input->get_data_type(),
+ format,
+ path,
+ context.get_view_settings(),
+ context.get_display_settings(),
+ context.get_view_name(),
+ sockdata->save_as_render);
}
else { /* R_IMF_VIEWS_STEREO_3D */
- outputOperation = new OutputStereoOperation(context.getRenderData(),
- context.getbNodeTree(),
- input->getDataType(),
- format,
- path,
- sockdata->layer,
- context.getViewSettings(),
- context.getDisplaySettings(),
- context.getViewName(),
- sockdata->save_as_render);
+ output_operation = new OutputStereoOperation(context.get_render_data(),
+ context.get_bnodetree(),
+ input->get_data_type(),
+ format,
+ path,
+ sockdata->layer,
+ context.get_view_settings(),
+ context.get_display_settings(),
+ context.get_view_name(),
+ sockdata->save_as_render);
}
- converter.addOperation(outputOperation);
- converter.mapInputSocket(input, outputOperation->getInputSocket(0));
+ converter.add_operation(output_operation);
+ converter.map_input_socket(input, output_operation->get_input_socket(0));
- if (!previewAdded) {
- converter.addNodeInputPreview(input);
- previewAdded = true;
+ if (!preview_added) {
+ converter.add_node_input_preview(input);
+ preview_added = true;
}
}
}
diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.h b/source/blender/compositor/nodes/COM_OutputFileNode.h
index c64128a708f..4c5575cc6b9 100644
--- a/source/blender/compositor/nodes/COM_OutputFileNode.h
+++ b/source/blender/compositor/nodes/COM_OutputFileNode.h
@@ -32,9 +32,9 @@ namespace blender::compositor {
*/
class OutputFileNode : public Node {
public:
- OutputFileNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ OutputFileNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
private:
void add_input_sockets(OutputOpenExrMultiLayerOperation &operation) const;
diff --git a/source/blender/compositor/nodes/COM_PixelateNode.cc b/source/blender/compositor/nodes/COM_PixelateNode.cc
index 396f339e5a2..251ef7b192a 100644
--- a/source/blender/compositor/nodes/COM_PixelateNode.cc
+++ b/source/blender/compositor/nodes/COM_PixelateNode.cc
@@ -18,33 +18,32 @@
#include "COM_PixelateNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_PixelateOperation.h"
namespace blender::compositor {
-PixelateNode::PixelateNode(bNode *editorNode) : Node(editorNode)
+PixelateNode::PixelateNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void PixelateNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void PixelateNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeOutput *outputSocket = this->getOutputSocket(0);
- DataType datatype = inputSocket->getDataType();
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeOutput *output_socket = this->get_output_socket(0);
+ DataType datatype = input_socket->get_data_type();
- if (inputSocket->isLinked()) {
- NodeOutput *link = inputSocket->getLink();
- datatype = link->getDataType();
+ if (input_socket->is_linked()) {
+ NodeOutput *link = input_socket->get_link();
+ datatype = link->get_data_type();
}
PixelateOperation *operation = new PixelateOperation(datatype);
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_PixelateNode.h b/source/blender/compositor/nodes/COM_PixelateNode.h
index 1a6555550cf..c52a73cafa6 100644
--- a/source/blender/compositor/nodes/COM_PixelateNode.h
+++ b/source/blender/compositor/nodes/COM_PixelateNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class PixelateNode : public Node {
public:
- PixelateNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ PixelateNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc
index 54a0f4d0452..0d2623f6e8b 100644
--- a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc
+++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc
@@ -17,60 +17,55 @@
*/
#include "COM_PlaneTrackDeformNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_PlaneTrackOperation.h"
-#include "BKE_movieclip.h"
-#include "BKE_node.h"
-#include "BKE_tracking.h"
-
namespace blender::compositor {
-PlaneTrackDeformNode::PlaneTrackDeformNode(bNode *editorNode) : Node(editorNode)
+PlaneTrackDeformNode::PlaneTrackDeformNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void PlaneTrackDeformNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void PlaneTrackDeformNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *editorNode = this->getbNode();
- MovieClip *clip = (MovieClip *)editorNode->id;
- NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)editorNode->storage;
+ bNode *editor_node = this->get_bnode();
+ MovieClip *clip = (MovieClip *)editor_node->id;
+ NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)editor_node->storage;
- int frame_number = context.getFramenumber();
+ int frame_number = context.get_framenumber();
- NodeInput *input_image = this->getInputSocket(0);
- NodeOutput *output_warped_image = this->getOutputSocket(0);
- NodeOutput *output_plane = this->getOutputSocket(1);
+ NodeInput *input_image = this->get_input_socket(0);
+ NodeOutput *output_warped_image = this->get_output_socket(0);
+ NodeOutput *output_plane = this->get_output_socket(1);
PlaneTrackWarpImageOperation *warp_image_operation = new PlaneTrackWarpImageOperation();
- warp_image_operation->setMovieClip(clip);
- warp_image_operation->setTrackingObject(data->tracking_object);
- warp_image_operation->setPlaneTrackName(data->plane_track_name);
- warp_image_operation->setFramenumber(frame_number);
+ warp_image_operation->set_movie_clip(clip);
+ warp_image_operation->set_tracking_object(data->tracking_object);
+ warp_image_operation->set_plane_track_name(data->plane_track_name);
+ warp_image_operation->set_framenumber(frame_number);
if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
- warp_image_operation->setMotionBlurSamples(data->motion_blur_samples);
- warp_image_operation->setMotionBlurShutter(data->motion_blur_shutter);
+ warp_image_operation->set_motion_blur_samples(data->motion_blur_samples);
+ warp_image_operation->set_motion_blur_shutter(data->motion_blur_shutter);
}
- converter.addOperation(warp_image_operation);
+ converter.add_operation(warp_image_operation);
- converter.mapInputSocket(input_image, warp_image_operation->getInputSocket(0));
- converter.mapOutputSocket(output_warped_image, warp_image_operation->getOutputSocket());
+ converter.map_input_socket(input_image, warp_image_operation->get_input_socket(0));
+ converter.map_output_socket(output_warped_image, warp_image_operation->get_output_socket());
PlaneTrackMaskOperation *plane_mask_operation = new PlaneTrackMaskOperation();
- plane_mask_operation->setMovieClip(clip);
- plane_mask_operation->setTrackingObject(data->tracking_object);
- plane_mask_operation->setPlaneTrackName(data->plane_track_name);
- plane_mask_operation->setFramenumber(frame_number);
+ plane_mask_operation->set_movie_clip(clip);
+ plane_mask_operation->set_tracking_object(data->tracking_object);
+ plane_mask_operation->set_plane_track_name(data->plane_track_name);
+ plane_mask_operation->set_framenumber(frame_number);
if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
- plane_mask_operation->setMotionBlurSamples(data->motion_blur_samples);
- plane_mask_operation->setMotionBlurShutter(data->motion_blur_shutter);
+ plane_mask_operation->set_motion_blur_samples(data->motion_blur_samples);
+ plane_mask_operation->set_motion_blur_shutter(data->motion_blur_shutter);
}
- converter.addOperation(plane_mask_operation);
+ converter.add_operation(plane_mask_operation);
- converter.mapOutputSocket(output_plane, plane_mask_operation->getOutputSocket());
+ converter.map_output_socket(output_plane, plane_mask_operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
index 307738fcaf0..16367423454 100644
--- a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
+++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
@@ -31,9 +31,9 @@ namespace blender::compositor {
*/
class PlaneTrackDeformNode : public Node {
public:
- PlaneTrackDeformNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ PlaneTrackDeformNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_PosterizeNode.cc b/source/blender/compositor/nodes/COM_PosterizeNode.cc
index 9f5a69961a4..c055a954c01 100644
--- a/source/blender/compositor/nodes/COM_PosterizeNode.cc
+++ b/source/blender/compositor/nodes/COM_PosterizeNode.cc
@@ -17,25 +17,24 @@
*/
#include "COM_PosterizeNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_PosterizeOperation.h"
namespace blender::compositor {
-PosterizeNode::PosterizeNode(bNode *editorNode) : Node(editorNode)
+PosterizeNode::PosterizeNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void PosterizeNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void PosterizeNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
PosterizeOperation *operation = new PosterizeOperation();
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_PosterizeNode.h b/source/blender/compositor/nodes/COM_PosterizeNode.h
index bb9bef2bdd0..d19e598632a 100644
--- a/source/blender/compositor/nodes/COM_PosterizeNode.h
+++ b/source/blender/compositor/nodes/COM_PosterizeNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class PosterizeNode : public Node {
public:
- PosterizeNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ PosterizeNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cc b/source/blender/compositor/nodes/COM_RenderLayersNode.cc
index 6744e98ecdb..4b82c5cbc21 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.cc
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cc
@@ -17,76 +17,72 @@
*/
#include "COM_RenderLayersNode.h"
-#include "COM_RenderLayersProg.h"
-#include "COM_RotateOperation.h"
-#include "COM_ScaleOperation.h"
#include "COM_SetColorOperation.h"
#include "COM_SetValueOperation.h"
#include "COM_SetVectorOperation.h"
-#include "COM_TranslateOperation.h"
namespace blender::compositor {
-RenderLayersNode::RenderLayersNode(bNode *editorNode) : Node(editorNode)
+RenderLayersNode::RenderLayersNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void RenderLayersNode::testSocketLink(NodeConverter &converter,
- const CompositorContext &context,
- NodeOutput *output,
- RenderLayersProg *operation,
- Scene *scene,
- int layerId,
- bool is_preview) const
+void RenderLayersNode::test_socket_link(NodeConverter &converter,
+ const CompositorContext &context,
+ NodeOutput *output,
+ RenderLayersProg *operation,
+ Scene *scene,
+ int layer_id,
+ bool is_preview) const
{
- operation->setScene(scene);
- operation->setLayerId(layerId);
- operation->setRenderData(context.getRenderData());
- operation->setViewName(context.getViewName());
+ operation->set_scene(scene);
+ operation->set_layer_id(layer_id);
+ operation->set_render_data(context.get_render_data());
+ operation->set_view_name(context.get_view_name());
- converter.mapOutputSocket(output, operation->getOutputSocket());
- converter.addOperation(operation);
+ converter.map_output_socket(output, operation->get_output_socket());
+ converter.add_operation(operation);
if (is_preview) { /* only for image socket */
- converter.addPreview(operation->getOutputSocket());
+ converter.add_preview(operation->get_output_socket());
}
}
-void RenderLayersNode::testRenderLink(NodeConverter &converter,
- const CompositorContext &context,
- Render *re) const
+void RenderLayersNode::test_render_link(NodeConverter &converter,
+ const CompositorContext &context,
+ Render *re) const
{
- Scene *scene = (Scene *)this->getbNode()->id;
- const short layerId = this->getbNode()->custom1;
+ Scene *scene = (Scene *)this->get_bnode()->id;
+ const short layer_id = this->get_bnode()->custom1;
RenderResult *rr = RE_AcquireResultRead(re);
if (rr == nullptr) {
- missingRenderLink(converter);
+ missing_render_link(converter);
return;
}
- ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, layerId);
+ ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, layer_id);
if (view_layer == nullptr) {
- missingRenderLink(converter);
+ missing_render_link(converter);
return;
}
RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name);
if (rl == nullptr) {
- missingRenderLink(converter);
+ missing_render_link(converter);
return;
}
- for (NodeOutput *output : getOutputSockets()) {
- NodeImageLayer *storage = (NodeImageLayer *)output->getbNodeSocket()->storage;
+ for (NodeOutput *output : get_output_sockets()) {
+ NodeImageLayer *storage = (NodeImageLayer *)output->get_bnode_socket()->storage;
RenderPass *rpass = (RenderPass *)BLI_findstring(
&rl->passes, storage->pass_name, offsetof(RenderPass, name));
if (rpass == nullptr) {
- missingSocketLink(converter, output);
+ missing_socket_link(converter, output);
continue;
}
RenderLayersProg *operation;
bool is_preview;
if (STREQ(rpass->name, RE_PASSNAME_COMBINED) &&
- STREQ(output->getbNodeSocket()->name, "Alpha")) {
+ STREQ(output->get_bnode_socket()->name, "Alpha")) {
operation = new RenderLayersAlphaProg(rpass->name, DataType::Value, rpass->channels);
is_preview = false;
}
@@ -112,33 +108,33 @@ void RenderLayersNode::testRenderLink(NodeConverter &converter,
break;
}
operation = new RenderLayersProg(rpass->name, type, rpass->channels);
- is_preview = STREQ(output->getbNodeSocket()->name, "Image");
+ is_preview = STREQ(output->get_bnode_socket()->name, "Image");
}
- testSocketLink(converter, context, output, operation, scene, layerId, is_preview);
+ test_socket_link(converter, context, output, operation, scene, layer_id, is_preview);
}
}
-void RenderLayersNode::missingSocketLink(NodeConverter &converter, NodeOutput *output) const
+void RenderLayersNode::missing_socket_link(NodeConverter &converter, NodeOutput *output) const
{
NodeOperation *operation;
- switch (output->getDataType()) {
+ switch (output->get_data_type()) {
case DataType::Color: {
const float color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
SetColorOperation *color_operation = new SetColorOperation();
- color_operation->setChannels(color);
+ color_operation->set_channels(color);
operation = color_operation;
break;
}
case DataType::Vector: {
const float vector[3] = {0.0f, 0.0f, 0.0f};
SetVectorOperation *vector_operation = new SetVectorOperation();
- vector_operation->setVector(vector);
+ vector_operation->set_vector(vector);
operation = vector_operation;
break;
}
case DataType::Value: {
SetValueOperation *value_operation = new SetValueOperation();
- value_operation->setValue(0.0f);
+ value_operation->set_value(0.0f);
operation = value_operation;
break;
}
@@ -148,29 +144,29 @@ void RenderLayersNode::missingSocketLink(NodeConverter &converter, NodeOutput *o
}
}
- converter.mapOutputSocket(output, operation->getOutputSocket());
- converter.addOperation(operation);
+ converter.map_output_socket(output, operation->get_output_socket());
+ converter.add_operation(operation);
}
-void RenderLayersNode::missingRenderLink(NodeConverter &converter) const
+void RenderLayersNode::missing_render_link(NodeConverter &converter) const
{
- for (NodeOutput *output : outputs) {
- missingSocketLink(converter, output);
+ for (NodeOutput *output : outputs_) {
+ missing_socket_link(converter, output);
}
}
-void RenderLayersNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void RenderLayersNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- Scene *scene = (Scene *)this->getbNode()->id;
+ Scene *scene = (Scene *)this->get_bnode()->id;
Render *re = (scene) ? RE_GetSceneRender(scene) : nullptr;
if (re != nullptr) {
- testRenderLink(converter, context, re);
+ test_render_link(converter, context, re);
RE_ReleaseResult(re);
}
else {
- missingRenderLink(converter);
+ missing_render_link(converter);
}
}
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.h b/source/blender/compositor/nodes/COM_RenderLayersNode.h
index 4eb2427c8e0..33e61c58336 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.h
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.h
@@ -31,24 +31,24 @@ namespace blender::compositor {
*/
class RenderLayersNode : public Node {
public:
- RenderLayersNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ RenderLayersNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
private:
- void testSocketLink(NodeConverter &converter,
- const CompositorContext &context,
- NodeOutput *output,
- RenderLayersProg *operation,
- Scene *scene,
- int layerId,
- bool is_preview) const;
- void testRenderLink(NodeConverter &converter,
- const CompositorContext &context,
- Render *re) const;
+ void test_socket_link(NodeConverter &converter,
+ const CompositorContext &context,
+ NodeOutput *output,
+ RenderLayersProg *operation,
+ Scene *scene,
+ int layer_id,
+ bool is_preview) const;
+ void test_render_link(NodeConverter &converter,
+ const CompositorContext &context,
+ Render *re) const;
- void missingSocketLink(NodeConverter &converter, NodeOutput *output) const;
- void missingRenderLink(NodeConverter &converter) const;
+ void missing_socket_link(NodeConverter &converter, NodeOutput *output) const;
+ void missing_render_link(NodeConverter &converter) const;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_RotateNode.cc b/source/blender/compositor/nodes/COM_RotateNode.cc
index c2fd8ed5594..64f49893335 100644
--- a/source/blender/compositor/nodes/COM_RotateNode.cc
+++ b/source/blender/compositor/nodes/COM_RotateNode.cc
@@ -18,45 +18,44 @@
#include "COM_RotateNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_RotateOperation.h"
#include "COM_SetSamplerOperation.h"
namespace blender::compositor {
-RotateNode::RotateNode(bNode *editorNode) : Node(editorNode)
+RotateNode::RotateNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void RotateNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void RotateNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeInput *inputDegreeSocket = this->getInputSocket(1);
- NodeOutput *outputSocket = this->getOutputSocket(0);
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeInput *input_degree_socket = this->get_input_socket(1);
+ NodeOutput *output_socket = this->get_output_socket(0);
RotateOperation *operation = new RotateOperation();
- converter.addOperation(operation);
+ converter.add_operation(operation);
- PixelSampler sampler = (PixelSampler)this->getbNode()->custom1;
+ PixelSampler sampler = (PixelSampler)this->get_bnode()->custom1;
switch (context.get_execution_model()) {
case eExecutionModel::Tiled: {
SetSamplerOperation *sampler_op = new SetSamplerOperation();
- sampler_op->setSampler(sampler);
- converter.addOperation(sampler_op);
- converter.addLink(sampler_op->getOutputSocket(), operation->getInputSocket(0));
- converter.mapInputSocket(inputSocket, sampler_op->getInputSocket(0));
+ sampler_op->set_sampler(sampler);
+ converter.add_operation(sampler_op);
+ converter.add_link(sampler_op->get_output_socket(), operation->get_input_socket(0));
+ converter.map_input_socket(input_socket, sampler_op->get_input_socket(0));
break;
}
case eExecutionModel::FullFrame: {
operation->set_sampler(sampler);
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
break;
}
}
- converter.mapInputSocket(inputDegreeSocket, operation->getInputSocket(1));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ converter.map_input_socket(input_degree_socket, operation->get_input_socket(1));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_RotateNode.h b/source/blender/compositor/nodes/COM_RotateNode.h
index 5d8bcb2e3e4..fa50cd1f689 100644
--- a/source/blender/compositor/nodes/COM_RotateNode.h
+++ b/source/blender/compositor/nodes/COM_RotateNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class RotateNode : public Node {
public:
- RotateNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ RotateNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ScaleNode.cc b/source/blender/compositor/nodes/COM_ScaleNode.cc
index f1f41375eba..56f1d998db8 100644
--- a/source/blender/compositor/nodes/COM_ScaleNode.cc
+++ b/source/blender/compositor/nodes/COM_ScaleNode.cc
@@ -19,77 +19,77 @@
#include "COM_ScaleNode.h"
#include "BKE_node.h"
-#include "COM_ExecutionSystem.h"
#include "COM_ScaleOperation.h"
-#include "COM_SetSamplerOperation.h"
#include "COM_SetValueOperation.h"
namespace blender::compositor {
-ScaleNode::ScaleNode(bNode *editorNode) : Node(editorNode)
+ScaleNode::ScaleNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ScaleNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void ScaleNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *bnode = this->getbNode();
+ bNode *bnode = this->get_bnode();
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeInput *inputXSocket = this->getInputSocket(1);
- NodeInput *inputYSocket = this->getInputSocket(2);
- NodeOutput *outputSocket = this->getOutputSocket(0);
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeInput *input_xsocket = this->get_input_socket(1);
+ NodeInput *input_ysocket = this->get_input_socket(2);
+ NodeOutput *output_socket = this->get_output_socket(0);
switch (bnode->custom1) {
case CMP_SCALE_RELATIVE: {
ScaleRelativeOperation *operation = new ScaleRelativeOperation();
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.mapInputSocket(inputXSocket, operation->getInputSocket(1));
- converter.mapInputSocket(inputYSocket, operation->getInputSocket(2));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.map_input_socket(input_xsocket, operation->get_input_socket(1));
+ converter.map_input_socket(input_ysocket, operation->get_input_socket(2));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
- operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked());
+ operation->set_variable_size(input_xsocket->is_linked() || input_ysocket->is_linked());
operation->set_scale_canvas_max_size(context.get_render_size() * 1.5f);
break;
}
case CMP_SCALE_SCENEPERCENT: {
- SetValueOperation *scaleFactorOperation = new SetValueOperation();
- scaleFactorOperation->setValue(context.getRenderPercentageAsFactor());
- converter.addOperation(scaleFactorOperation);
+ SetValueOperation *scale_factor_operation = new SetValueOperation();
+ scale_factor_operation->set_value(context.get_render_percentage_as_factor());
+ converter.add_operation(scale_factor_operation);
ScaleRelativeOperation *operation = new ScaleRelativeOperation();
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.addLink(scaleFactorOperation->getOutputSocket(), operation->getInputSocket(1));
- converter.addLink(scaleFactorOperation->getOutputSocket(), operation->getInputSocket(2));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.add_link(scale_factor_operation->get_output_socket(),
+ operation->get_input_socket(1));
+ converter.add_link(scale_factor_operation->get_output_socket(),
+ operation->get_input_socket(2));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
- operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked());
+ operation->set_variable_size(input_xsocket->is_linked() || input_ysocket->is_linked());
operation->set_scale_canvas_max_size(context.get_render_size() * 1.5f);
break;
}
case CMP_SCALE_RENDERPERCENT: {
- const RenderData *rd = context.getRenderData();
- const float render_size_factor = context.getRenderPercentageAsFactor();
+ const RenderData *rd = context.get_render_data();
+ const float render_size_factor = context.get_render_percentage_as_factor();
ScaleFixedSizeOperation *operation = new ScaleFixedSizeOperation();
/* framing options */
- operation->setIsAspect((bnode->custom2 & CMP_SCALE_RENDERSIZE_FRAME_ASPECT) != 0);
- operation->setIsCrop((bnode->custom2 & CMP_SCALE_RENDERSIZE_FRAME_CROP) != 0);
- operation->setOffset(bnode->custom3, bnode->custom4);
- operation->setNewWidth(rd->xsch * render_size_factor);
- operation->setNewHeight(rd->ysch * render_size_factor);
- converter.addOperation(operation);
+ operation->set_is_aspect((bnode->custom2 & CMP_SCALE_RENDERSIZE_FRAME_ASPECT) != 0);
+ operation->set_is_crop((bnode->custom2 & CMP_SCALE_RENDERSIZE_FRAME_CROP) != 0);
+ operation->set_offset(bnode->custom3, bnode->custom4);
+ operation->set_new_width(rd->xsch * render_size_factor);
+ operation->set_new_height(rd->ysch * render_size_factor);
+ converter.add_operation(operation);
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
- operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked());
+ operation->set_variable_size(input_xsocket->is_linked() || input_ysocket->is_linked());
operation->set_scale_canvas_max_size(context.get_render_size() * 3.0f);
break;
@@ -97,14 +97,14 @@ void ScaleNode::convertToOperations(NodeConverter &converter,
case CMP_SCALE_ABSOLUTE: {
/* TODO: what is the use of this one.... perhaps some issues when the ui was updated... */
ScaleAbsoluteOperation *operation = new ScaleAbsoluteOperation();
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.mapInputSocket(inputXSocket, operation->getInputSocket(1));
- converter.mapInputSocket(inputYSocket, operation->getInputSocket(2));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.map_input_socket(input_xsocket, operation->get_input_socket(1));
+ converter.map_input_socket(input_ysocket, operation->get_input_socket(2));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
- operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked());
+ operation->set_variable_size(input_xsocket->is_linked() || input_ysocket->is_linked());
operation->set_scale_canvas_max_size(context.get_render_size() * 1.5f);
break;
diff --git a/source/blender/compositor/nodes/COM_ScaleNode.h b/source/blender/compositor/nodes/COM_ScaleNode.h
index 186ffa8bdce..7800a7acb8b 100644
--- a/source/blender/compositor/nodes/COM_ScaleNode.h
+++ b/source/blender/compositor/nodes/COM_ScaleNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ScaleNode : public Node {
public:
- ScaleNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ScaleNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SceneTimeNode.cc b/source/blender/compositor/nodes/COM_SceneTimeNode.cc
new file mode 100644
index 00000000000..533f30918ca
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SceneTimeNode.cc
@@ -0,0 +1,50 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2022, Blender Foundation.
+ */
+
+#include "COM_SceneTimeNode.h"
+
+#include "COM_SetValueOperation.h"
+
+namespace blender::compositor {
+
+SceneTimeNode::SceneTimeNode(bNode *editor_node) : Node(editor_node)
+{
+ /* pass */
+}
+
+void SceneTimeNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
+{
+ SetValueOperation *SecondOperation = new SetValueOperation();
+ SetValueOperation *frameOperation = new SetValueOperation();
+
+ const int frameNumber = context.get_framenumber();
+ const Scene *scene = context.get_scene();
+ const double frameRate = (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base);
+
+ SecondOperation->set_value(float(frameNumber / frameRate));
+ converter.add_operation(SecondOperation);
+
+ frameOperation->set_value(frameNumber);
+ converter.add_operation(frameOperation);
+
+ converter.map_output_socket(get_output_socket(0), SecondOperation->get_output_socket());
+ converter.map_output_socket(get_output_socket(1), frameOperation->get_output_socket());
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/functions/FN_multi_function_parallel.hh b/source/blender/compositor/nodes/COM_SceneTimeNode.h
index 84c57efd434..62c502d26d2 100644
--- a/source/blender/functions/FN_multi_function_parallel.hh
+++ b/source/blender/compositor/nodes/COM_SceneTimeNode.h
@@ -12,28 +12,25 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2022, Blender Foundation.
*/
#pragma once
-/** \file
- * \ingroup fn
- */
-
-#include "FN_multi_function.hh"
+#include "COM_Node.h"
-namespace blender::fn {
-
-class ParallelMultiFunction : public MultiFunction {
- private:
- const MultiFunction &fn_;
- const int64_t grain_size_;
- bool threading_supported_;
+namespace blender::compositor {
+/**
+ * \brief SceneTimeNode
+ * \ingroup Node
+ */
+class SceneTimeNode : public Node {
public:
- ParallelMultiFunction(const MultiFunction &fn, const int64_t grain_size);
-
- void call(IndexMask mask, MFParams params, MFContext context) const override;
+ SceneTimeNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
-} // namespace blender::fn
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.cc b/source/blender/compositor/nodes/COM_SeparateColorNode.cc
index fcaf52c701d..046a813895e 100644
--- a/source/blender/compositor/nodes/COM_SeparateColorNode.cc
+++ b/source/blender/compositor/nodes/COM_SeparateColorNode.cc
@@ -22,102 +22,102 @@
namespace blender::compositor {
-SeparateColorNode::SeparateColorNode(bNode *editorNode) : Node(editorNode)
+SeparateColorNode::SeparateColorNode(bNode *editor_node) : Node(editor_node)
{
}
-void SeparateColorNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void SeparateColorNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- NodeInput *imageSocket = this->getInputSocket(0);
- NodeOutput *outputRSocket = this->getOutputSocket(0);
- NodeOutput *outputGSocket = this->getOutputSocket(1);
- NodeOutput *outputBSocket = this->getOutputSocket(2);
- NodeOutput *outputASocket = this->getOutputSocket(3);
+ NodeInput *image_socket = this->get_input_socket(0);
+ NodeOutput *output_rsocket = this->get_output_socket(0);
+ NodeOutput *output_gsocket = this->get_output_socket(1);
+ NodeOutput *output_bsocket = this->get_output_socket(2);
+ NodeOutput *output_asocket = this->get_output_socket(3);
- NodeOperation *color_conv = getColorConverter(context);
+ NodeOperation *color_conv = get_color_converter(context);
if (color_conv) {
- converter.addOperation(color_conv);
+ converter.add_operation(color_conv);
- converter.mapInputSocket(imageSocket, color_conv->getInputSocket(0));
+ converter.map_input_socket(image_socket, color_conv->get_input_socket(0));
}
{
SeparateChannelOperation *operation = new SeparateChannelOperation();
- operation->setChannel(0);
- converter.addOperation(operation);
+ operation->set_channel(0);
+ converter.add_operation(operation);
if (color_conv) {
- converter.addLink(color_conv->getOutputSocket(), operation->getInputSocket(0));
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
}
else {
- converter.mapInputSocket(imageSocket, operation->getInputSocket(0));
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
}
- converter.mapOutputSocket(outputRSocket, operation->getOutputSocket(0));
+ converter.map_output_socket(output_rsocket, operation->get_output_socket(0));
}
{
SeparateChannelOperation *operation = new SeparateChannelOperation();
- operation->setChannel(1);
- converter.addOperation(operation);
+ operation->set_channel(1);
+ converter.add_operation(operation);
if (color_conv) {
- converter.addLink(color_conv->getOutputSocket(), operation->getInputSocket(0));
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
}
else {
- converter.mapInputSocket(imageSocket, operation->getInputSocket(0));
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
}
- converter.mapOutputSocket(outputGSocket, operation->getOutputSocket(0));
+ converter.map_output_socket(output_gsocket, operation->get_output_socket(0));
}
{
SeparateChannelOperation *operation = new SeparateChannelOperation();
- operation->setChannel(2);
- converter.addOperation(operation);
+ operation->set_channel(2);
+ converter.add_operation(operation);
if (color_conv) {
- converter.addLink(color_conv->getOutputSocket(), operation->getInputSocket(0));
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
}
else {
- converter.mapInputSocket(imageSocket, operation->getInputSocket(0));
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
}
- converter.mapOutputSocket(outputBSocket, operation->getOutputSocket(0));
+ converter.map_output_socket(output_bsocket, operation->get_output_socket(0));
}
{
SeparateChannelOperation *operation = new SeparateChannelOperation();
- operation->setChannel(3);
- converter.addOperation(operation);
+ operation->set_channel(3);
+ converter.add_operation(operation);
if (color_conv) {
- converter.addLink(color_conv->getOutputSocket(), operation->getInputSocket(0));
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
}
else {
- converter.mapInputSocket(imageSocket, operation->getInputSocket(0));
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
}
- converter.mapOutputSocket(outputASocket, operation->getOutputSocket(0));
+ converter.map_output_socket(output_asocket, operation->get_output_socket(0));
}
}
-NodeOperation *SeparateRGBANode::getColorConverter(const CompositorContext & /*context*/) const
+NodeOperation *SeparateRGBANode::get_color_converter(const CompositorContext & /*context*/) const
{
return nullptr; /* no conversion needed */
}
-NodeOperation *SeparateHSVANode::getColorConverter(const CompositorContext & /*context*/) const
+NodeOperation *SeparateHSVANode::get_color_converter(const CompositorContext & /*context*/) const
{
return new ConvertRGBToHSVOperation();
}
-NodeOperation *SeparateYCCANode::getColorConverter(const CompositorContext & /*context*/) const
+NodeOperation *SeparateYCCANode::get_color_converter(const CompositorContext & /*context*/) const
{
ConvertRGBToYCCOperation *operation = new ConvertRGBToYCCOperation();
- bNode *editorNode = this->getbNode();
- operation->setMode(editorNode->custom1);
+ bNode *editor_node = this->get_bnode();
+ operation->set_mode(editor_node->custom1);
return operation;
}
-NodeOperation *SeparateYUVANode::getColorConverter(const CompositorContext & /*context*/) const
+NodeOperation *SeparateYUVANode::get_color_converter(const CompositorContext & /*context*/) const
{
return new ConvertRGBToYUVOperation();
}
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.h b/source/blender/compositor/nodes/COM_SeparateColorNode.h
index eaf543df51f..0dfcd676772 100644
--- a/source/blender/compositor/nodes/COM_SeparateColorNode.h
+++ b/source/blender/compositor/nodes/COM_SeparateColorNode.h
@@ -24,48 +24,48 @@ namespace blender::compositor {
class SeparateColorNode : public Node {
public:
- SeparateColorNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ SeparateColorNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
protected:
- virtual NodeOperation *getColorConverter(const CompositorContext &context) const = 0;
+ virtual NodeOperation *get_color_converter(const CompositorContext &context) const = 0;
};
class SeparateRGBANode : public SeparateColorNode {
public:
- SeparateRGBANode(bNode *editorNode) : SeparateColorNode(editorNode)
+ SeparateRGBANode(bNode *editor_node) : SeparateColorNode(editor_node)
{
}
- NodeOperation *getColorConverter(const CompositorContext &context) const override;
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
};
class SeparateHSVANode : public SeparateColorNode {
public:
- SeparateHSVANode(bNode *editorNode) : SeparateColorNode(editorNode)
+ SeparateHSVANode(bNode *editor_node) : SeparateColorNode(editor_node)
{
}
- NodeOperation *getColorConverter(const CompositorContext &context) const override;
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
};
class SeparateYCCANode : public SeparateColorNode {
public:
- SeparateYCCANode(bNode *editorNode) : SeparateColorNode(editorNode)
+ SeparateYCCANode(bNode *editor_node) : SeparateColorNode(editor_node)
{
}
- NodeOperation *getColorConverter(const CompositorContext &context) const override;
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
};
class SeparateYUVANode : public SeparateColorNode {
public:
- SeparateYUVANode(bNode *editorNode) : SeparateColorNode(editorNode)
+ SeparateYUVANode(bNode *editor_node) : SeparateColorNode(editor_node)
{
}
- NodeOperation *getColorConverter(const CompositorContext &context) const override;
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SetAlphaNode.cc b/source/blender/compositor/nodes/COM_SetAlphaNode.cc
index c7365b09f71..58b8df98bc8 100644
--- a/source/blender/compositor/nodes/COM_SetAlphaNode.cc
+++ b/source/blender/compositor/nodes/COM_SetAlphaNode.cc
@@ -17,17 +17,16 @@
*/
#include "COM_SetAlphaNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_SetAlphaMultiplyOperation.h"
#include "COM_SetAlphaReplaceOperation.h"
namespace blender::compositor {
-void SetAlphaNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void SetAlphaNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- const bNode *editorNode = this->getbNode();
- const NodeSetAlpha *storage = static_cast<const NodeSetAlpha *>(editorNode->storage);
+ const bNode *editor_node = this->get_bnode();
+ const NodeSetAlpha *storage = static_cast<const NodeSetAlpha *>(editor_node->storage);
NodeOperation *operation = nullptr;
switch (storage->mode) {
case CMP_NODE_SETALPHA_MODE_APPLY:
@@ -38,15 +37,15 @@ void SetAlphaNode::convertToOperations(NodeConverter &converter,
break;
}
- if (!this->getInputSocket(0)->isLinked() && this->getInputSocket(1)->isLinked()) {
+ if (!this->get_input_socket(0)->is_linked() && this->get_input_socket(1)->is_linked()) {
operation->set_canvas_input_index(1);
}
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SetAlphaNode.h b/source/blender/compositor/nodes/COM_SetAlphaNode.h
index c8d340eb64b..9e369838bbe 100644
--- a/source/blender/compositor/nodes/COM_SetAlphaNode.h
+++ b/source/blender/compositor/nodes/COM_SetAlphaNode.h
@@ -28,11 +28,11 @@ namespace blender::compositor {
*/
class SetAlphaNode : public Node {
public:
- SetAlphaNode(bNode *editorNode) : Node(editorNode)
+ SetAlphaNode(bNode *editor_node) : Node(editor_node)
{
}
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.cc b/source/blender/compositor/nodes/COM_SocketProxyNode.cc
index b3aa1770551..e7c8a90a48b 100644
--- a/source/blender/compositor/nodes/COM_SocketProxyNode.cc
+++ b/source/blender/compositor/nodes/COM_SocketProxyNode.cc
@@ -17,91 +17,87 @@
*/
#include "COM_SocketProxyNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_ReadBufferOperation.h"
-#include "COM_SetColorOperation.h"
-#include "COM_SetValueOperation.h"
-#include "COM_SetVectorOperation.h"
-#include "COM_SocketProxyOperation.h"
#include "COM_WriteBufferOperation.h"
namespace blender::compositor {
-SocketProxyNode::SocketProxyNode(bNode *editorNode,
- bNodeSocket *editorInput,
- bNodeSocket *editorOutput,
+SocketProxyNode::SocketProxyNode(bNode *editor_node,
+ bNodeSocket *editor_input,
+ bNodeSocket *editor_output,
bool use_conversion)
- : Node(editorNode, false), m_use_conversion(use_conversion)
+ : Node(editor_node, false), use_conversion_(use_conversion)
{
DataType dt;
dt = DataType::Value;
- if (editorInput->type == SOCK_RGBA) {
+ if (editor_input->type == SOCK_RGBA) {
dt = DataType::Color;
}
- if (editorInput->type == SOCK_VECTOR) {
+ if (editor_input->type == SOCK_VECTOR) {
dt = DataType::Vector;
}
- this->addInputSocket(dt, editorInput);
+ this->add_input_socket(dt, editor_input);
dt = DataType::Value;
- if (editorOutput->type == SOCK_RGBA) {
+ if (editor_output->type == SOCK_RGBA) {
dt = DataType::Color;
}
- if (editorOutput->type == SOCK_VECTOR) {
+ if (editor_output->type == SOCK_VECTOR) {
dt = DataType::Vector;
}
- this->addOutputSocket(dt, editorOutput);
+ this->add_output_socket(dt, editor_output);
}
-void SocketProxyNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void SocketProxyNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeOperationOutput *proxy_output = converter.addInputProxy(getInputSocket(0), m_use_conversion);
- converter.mapOutputSocket(getOutputSocket(), proxy_output);
+ NodeOperationOutput *proxy_output = converter.add_input_proxy(get_input_socket(0),
+ use_conversion_);
+ converter.map_output_socket(get_output_socket(), proxy_output);
}
-SocketBufferNode::SocketBufferNode(bNode *editorNode,
- bNodeSocket *editorInput,
- bNodeSocket *editorOutput)
- : Node(editorNode, false)
+SocketBufferNode::SocketBufferNode(bNode *editor_node,
+ bNodeSocket *editor_input,
+ bNodeSocket *editor_output)
+ : Node(editor_node, false)
{
DataType dt;
dt = DataType::Value;
- if (editorInput->type == SOCK_RGBA) {
+ if (editor_input->type == SOCK_RGBA) {
dt = DataType::Color;
}
- if (editorInput->type == SOCK_VECTOR) {
+ if (editor_input->type == SOCK_VECTOR) {
dt = DataType::Vector;
}
- this->addInputSocket(dt, editorInput);
+ this->add_input_socket(dt, editor_input);
dt = DataType::Value;
- if (editorOutput->type == SOCK_RGBA) {
+ if (editor_output->type == SOCK_RGBA) {
dt = DataType::Color;
}
- if (editorOutput->type == SOCK_VECTOR) {
+ if (editor_output->type == SOCK_VECTOR) {
dt = DataType::Vector;
}
- this->addOutputSocket(dt, editorOutput);
+ this->add_output_socket(dt, editor_output);
}
-void SocketBufferNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void SocketBufferNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeOutput *output = this->getOutputSocket(0);
- NodeInput *input = this->getInputSocket(0);
+ NodeOutput *output = this->get_output_socket(0);
+ NodeInput *input = this->get_input_socket(0);
- DataType datatype = output->getDataType();
- WriteBufferOperation *writeOperation = new WriteBufferOperation(datatype);
- ReadBufferOperation *readOperation = new ReadBufferOperation(datatype);
- readOperation->setMemoryProxy(writeOperation->getMemoryProxy());
- converter.addOperation(writeOperation);
- converter.addOperation(readOperation);
+ DataType datatype = output->get_data_type();
+ WriteBufferOperation *write_operation = new WriteBufferOperation(datatype);
+ ReadBufferOperation *read_operation = new ReadBufferOperation(datatype);
+ read_operation->set_memory_proxy(write_operation->get_memory_proxy());
+ converter.add_operation(write_operation);
+ converter.add_operation(read_operation);
- converter.mapInputSocket(input, writeOperation->getInputSocket(0));
- converter.mapOutputSocket(output, readOperation->getOutputSocket());
+ converter.map_input_socket(input, write_operation->get_input_socket(0));
+ converter.map_output_socket(output, read_operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.h b/source/blender/compositor/nodes/COM_SocketProxyNode.h
index d19fb802767..50079ed4718 100644
--- a/source/blender/compositor/nodes/COM_SocketProxyNode.h
+++ b/source/blender/compositor/nodes/COM_SocketProxyNode.h
@@ -28,32 +28,32 @@ namespace blender::compositor {
*/
class SocketProxyNode : public Node {
public:
- SocketProxyNode(bNode *editorNode,
- bNodeSocket *editorInput,
- bNodeSocket *editorOutput,
+ SocketProxyNode(bNode *editor_node,
+ bNodeSocket *editor_input,
+ bNodeSocket *editor_output,
bool use_conversion);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
- bool getUseConversion() const
+ bool get_use_conversion() const
{
- return m_use_conversion;
+ return use_conversion_;
}
- void setUseConversion(bool use_conversion)
+ void set_use_conversion(bool use_conversion)
{
- m_use_conversion = use_conversion;
+ use_conversion_ = use_conversion;
}
private:
/** If true, the proxy will convert input and output data to/from the proxy socket types. */
- bool m_use_conversion;
+ bool use_conversion_;
};
class SocketBufferNode : public Node {
public:
- SocketBufferNode(bNode *editorNode, bNodeSocket *editorInput, bNodeSocket *editorOutput);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ SocketBufferNode(bNode *editor_node, bNodeSocket *editor_input, bNodeSocket *editor_output);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cc b/source/blender/compositor/nodes/COM_SplitViewerNode.cc
index 582c650f205..c3234fad0fb 100644
--- a/source/blender/compositor/nodes/COM_SplitViewerNode.cc
+++ b/source/blender/compositor/nodes/COM_SplitViewerNode.cc
@@ -17,62 +17,59 @@
*/
#include "COM_SplitViewerNode.h"
-#include "BKE_global.h"
-#include "BKE_image.h"
-#include "BKE_scene.h"
-#include "COM_ExecutionSystem.h"
#include "COM_SplitOperation.h"
#include "COM_ViewerOperation.h"
namespace blender::compositor {
-SplitViewerNode::SplitViewerNode(bNode *editorNode) : Node(editorNode)
+SplitViewerNode::SplitViewerNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void SplitViewerNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void SplitViewerNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *editorNode = this->getbNode();
- bool do_output = (editorNode->flag & NODE_DO_OUTPUT_RECALC || context.isRendering()) &&
- (editorNode->flag & NODE_DO_OUTPUT);
+ bNode *editor_node = this->get_bnode();
+ bool do_output = (editor_node->flag & NODE_DO_OUTPUT_RECALC || context.is_rendering()) &&
+ (editor_node->flag & NODE_DO_OUTPUT);
- NodeInput *image1Socket = this->getInputSocket(0);
- NodeInput *image2Socket = this->getInputSocket(1);
- Image *image = (Image *)this->getbNode()->id;
- ImageUser *imageUser = (ImageUser *)this->getbNode()->storage;
+ NodeInput *image1Socket = this->get_input_socket(0);
+ NodeInput *image2Socket = this->get_input_socket(1);
+ Image *image = (Image *)this->get_bnode()->id;
+ ImageUser *image_user = (ImageUser *)this->get_bnode()->storage;
- SplitOperation *splitViewerOperation = new SplitOperation();
- splitViewerOperation->setSplitPercentage(this->getbNode()->custom1);
- splitViewerOperation->setXSplit(!this->getbNode()->custom2);
+ SplitOperation *split_viewer_operation = new SplitOperation();
+ split_viewer_operation->set_split_percentage(this->get_bnode()->custom1);
+ split_viewer_operation->set_xsplit(!this->get_bnode()->custom2);
- converter.addOperation(splitViewerOperation);
- converter.mapInputSocket(image1Socket, splitViewerOperation->getInputSocket(0));
- converter.mapInputSocket(image2Socket, splitViewerOperation->getInputSocket(1));
+ converter.add_operation(split_viewer_operation);
+ converter.map_input_socket(image1Socket, split_viewer_operation->get_input_socket(0));
+ converter.map_input_socket(image2Socket, split_viewer_operation->get_input_socket(1));
- ViewerOperation *viewerOperation = new ViewerOperation();
- viewerOperation->setImage(image);
- viewerOperation->setImageUser(imageUser);
- viewerOperation->setViewSettings(context.getViewSettings());
- viewerOperation->setDisplaySettings(context.getDisplaySettings());
- viewerOperation->setRenderData(context.getRenderData());
- viewerOperation->setViewName(context.getViewName());
+ ViewerOperation *viewer_operation = new ViewerOperation();
+ viewer_operation->set_image(image);
+ viewer_operation->set_image_user(image_user);
+ viewer_operation->set_view_settings(context.get_view_settings());
+ viewer_operation->set_display_settings(context.get_display_settings());
+ viewer_operation->set_render_data(context.get_render_data());
+ viewer_operation->set_view_name(context.get_view_name());
/* defaults - the viewer node has these options but not exposed for split view
* we could use the split to define an area of interest on one axis at least */
- viewerOperation->setChunkOrder(ChunkOrdering::Default);
- viewerOperation->setCenterX(0.5f);
- viewerOperation->setCenterY(0.5f);
+ viewer_operation->set_chunk_order(ChunkOrdering::Default);
+ viewer_operation->setCenterX(0.5f);
+ viewer_operation->setCenterY(0.5f);
- converter.addOperation(viewerOperation);
- converter.addLink(splitViewerOperation->getOutputSocket(), viewerOperation->getInputSocket(0));
+ converter.add_operation(viewer_operation);
+ converter.add_link(split_viewer_operation->get_output_socket(),
+ viewer_operation->get_input_socket(0));
- converter.addPreview(splitViewerOperation->getOutputSocket());
+ converter.add_preview(split_viewer_operation->get_output_socket());
if (do_output) {
- converter.registerViewer(viewerOperation);
+ converter.register_viewer(viewer_operation);
}
}
diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.h b/source/blender/compositor/nodes/COM_SplitViewerNode.h
index 8a42775eb0d..579eca9d8e1 100644
--- a/source/blender/compositor/nodes/COM_SplitViewerNode.h
+++ b/source/blender/compositor/nodes/COM_SplitViewerNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class SplitViewerNode : public Node {
public:
- SplitViewerNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ SplitViewerNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.cc b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc
index 3d8f0bbda7e..9892c4f5c05 100644
--- a/source/blender/compositor/nodes/COM_Stabilize2dNode.cc
+++ b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc
@@ -17,159 +17,168 @@
*/
#include "COM_Stabilize2dNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_MovieClipAttributeOperation.h"
#include "COM_RotateOperation.h"
#include "COM_ScaleOperation.h"
#include "COM_SetSamplerOperation.h"
-#include "COM_TransformOperation.h"
#include "COM_TranslateOperation.h"
-#include "BKE_tracking.h"
-
-#include "DNA_movieclip_types.h"
-
namespace blender::compositor {
-Stabilize2dNode::Stabilize2dNode(bNode *editorNode) : Node(editorNode)
+Stabilize2dNode::Stabilize2dNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void Stabilize2dNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void Stabilize2dNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *editorNode = this->getbNode();
- NodeInput *imageInput = this->getInputSocket(0);
- MovieClip *clip = (MovieClip *)editorNode->id;
- bool invert = (editorNode->custom2 & CMP_NODEFLAG_STABILIZE_INVERSE) != 0;
- const PixelSampler sampler = (PixelSampler)editorNode->custom1;
-
- MovieClipAttributeOperation *scaleAttribute = new MovieClipAttributeOperation();
- MovieClipAttributeOperation *angleAttribute = new MovieClipAttributeOperation();
- MovieClipAttributeOperation *xAttribute = new MovieClipAttributeOperation();
- MovieClipAttributeOperation *yAttribute = new MovieClipAttributeOperation();
-
- scaleAttribute->setAttribute(MCA_SCALE);
- scaleAttribute->setFramenumber(context.getFramenumber());
- scaleAttribute->setMovieClip(clip);
- scaleAttribute->setInvert(invert);
-
- angleAttribute->setAttribute(MCA_ANGLE);
- angleAttribute->setFramenumber(context.getFramenumber());
- angleAttribute->setMovieClip(clip);
- angleAttribute->setInvert(invert);
-
- xAttribute->setAttribute(MCA_X);
- xAttribute->setFramenumber(context.getFramenumber());
- xAttribute->setMovieClip(clip);
- xAttribute->setInvert(invert);
-
- yAttribute->setAttribute(MCA_Y);
- yAttribute->setFramenumber(context.getFramenumber());
- yAttribute->setMovieClip(clip);
- yAttribute->setInvert(invert);
-
- converter.addOperation(scaleAttribute);
- converter.addOperation(angleAttribute);
- converter.addOperation(xAttribute);
- converter.addOperation(yAttribute);
+ bNode *editor_node = this->get_bnode();
+ NodeInput *image_input = this->get_input_socket(0);
+ MovieClip *clip = (MovieClip *)editor_node->id;
+ bool invert = (editor_node->custom2 & CMP_NODEFLAG_STABILIZE_INVERSE) != 0;
+ const PixelSampler sampler = (PixelSampler)editor_node->custom1;
+
+ MovieClipAttributeOperation *scale_attribute = new MovieClipAttributeOperation();
+ MovieClipAttributeOperation *angle_attribute = new MovieClipAttributeOperation();
+ MovieClipAttributeOperation *x_attribute = new MovieClipAttributeOperation();
+ MovieClipAttributeOperation *y_attribute = new MovieClipAttributeOperation();
+
+ scale_attribute->set_attribute(MCA_SCALE);
+ scale_attribute->set_framenumber(context.get_framenumber());
+ scale_attribute->set_movie_clip(clip);
+ scale_attribute->set_invert(invert);
+
+ angle_attribute->set_attribute(MCA_ANGLE);
+ angle_attribute->set_framenumber(context.get_framenumber());
+ angle_attribute->set_movie_clip(clip);
+ angle_attribute->set_invert(invert);
+
+ x_attribute->set_attribute(MCA_X);
+ x_attribute->set_framenumber(context.get_framenumber());
+ x_attribute->set_movie_clip(clip);
+ x_attribute->set_invert(invert);
+
+ y_attribute->set_attribute(MCA_Y);
+ y_attribute->set_framenumber(context.get_framenumber());
+ y_attribute->set_movie_clip(clip);
+ y_attribute->set_invert(invert);
+
+ converter.add_operation(scale_attribute);
+ converter.add_operation(angle_attribute);
+ converter.add_operation(x_attribute);
+ converter.add_operation(y_attribute);
switch (context.get_execution_model()) {
case eExecutionModel::Tiled: {
- ScaleRelativeOperation *scaleOperation = new ScaleRelativeOperation();
- scaleOperation->setSampler(sampler);
- RotateOperation *rotateOperation = new RotateOperation();
- rotateOperation->setDoDegree2RadConversion(false);
- TranslateOperation *translateOperation = new TranslateOperation();
+ ScaleRelativeOperation *scale_operation = new ScaleRelativeOperation();
+ scale_operation->set_sampler(sampler);
+ RotateOperation *rotate_operation = new RotateOperation();
+ rotate_operation->set_do_degree2_rad_conversion(false);
+ TranslateOperation *translate_operation = new TranslateOperation();
SetSamplerOperation *psoperation = new SetSamplerOperation();
- psoperation->setSampler(sampler);
+ psoperation->set_sampler(sampler);
- converter.addOperation(scaleOperation);
- converter.addOperation(translateOperation);
- converter.addOperation(rotateOperation);
- converter.addOperation(psoperation);
+ converter.add_operation(scale_operation);
+ converter.add_operation(translate_operation);
+ converter.add_operation(rotate_operation);
+ converter.add_operation(psoperation);
- converter.addLink(scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(1));
- converter.addLink(scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(2));
+ converter.add_link(scale_attribute->get_output_socket(),
+ scale_operation->get_input_socket(1));
+ converter.add_link(scale_attribute->get_output_socket(),
+ scale_operation->get_input_socket(2));
- converter.addLink(angleAttribute->getOutputSocket(), rotateOperation->getInputSocket(1));
+ converter.add_link(angle_attribute->get_output_socket(),
+ rotate_operation->get_input_socket(1));
- converter.addLink(xAttribute->getOutputSocket(), translateOperation->getInputSocket(1));
- converter.addLink(yAttribute->getOutputSocket(), translateOperation->getInputSocket(2));
+ converter.add_link(x_attribute->get_output_socket(),
+ translate_operation->get_input_socket(1));
+ converter.add_link(y_attribute->get_output_socket(),
+ translate_operation->get_input_socket(2));
- converter.mapOutputSocket(getOutputSocket(), psoperation->getOutputSocket());
+ converter.map_output_socket(get_output_socket(), psoperation->get_output_socket());
if (invert) {
/* Translate -> Rotate -> Scale. */
- converter.mapInputSocket(imageInput, translateOperation->getInputSocket(0));
+ converter.map_input_socket(image_input, translate_operation->get_input_socket(0));
- converter.addLink(translateOperation->getOutputSocket(),
- rotateOperation->getInputSocket(0));
- converter.addLink(rotateOperation->getOutputSocket(), scaleOperation->getInputSocket(0));
+ converter.add_link(translate_operation->get_output_socket(),
+ rotate_operation->get_input_socket(0));
+ converter.add_link(rotate_operation->get_output_socket(),
+ scale_operation->get_input_socket(0));
- converter.addLink(scaleOperation->getOutputSocket(), psoperation->getInputSocket(0));
+ converter.add_link(scale_operation->get_output_socket(), psoperation->get_input_socket(0));
}
else {
/* Scale -> Rotate -> Translate. */
- converter.mapInputSocket(imageInput, scaleOperation->getInputSocket(0));
+ converter.map_input_socket(image_input, scale_operation->get_input_socket(0));
- converter.addLink(scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0));
- converter.addLink(rotateOperation->getOutputSocket(),
- translateOperation->getInputSocket(0));
+ converter.add_link(scale_operation->get_output_socket(),
+ rotate_operation->get_input_socket(0));
+ converter.add_link(rotate_operation->get_output_socket(),
+ translate_operation->get_input_socket(0));
- converter.addLink(translateOperation->getOutputSocket(), psoperation->getInputSocket(0));
+ converter.add_link(translate_operation->get_output_socket(),
+ psoperation->get_input_socket(0));
}
break;
}
case eExecutionModel::FullFrame: {
- ScaleRelativeOperation *scaleOperation = new ScaleRelativeOperation();
- scaleOperation->setSampler(sampler);
- RotateOperation *rotateOperation = new RotateOperation();
- rotateOperation->setDoDegree2RadConversion(false);
- rotateOperation->set_sampler(sampler);
- TranslateOperation *translateOperation = new TranslateCanvasOperation();
-
- converter.addOperation(scaleOperation);
- converter.addOperation(translateOperation);
- converter.addOperation(rotateOperation);
-
- converter.addLink(scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(1));
- converter.addLink(scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(2));
-
- converter.addLink(angleAttribute->getOutputSocket(), rotateOperation->getInputSocket(1));
-
- converter.addLink(xAttribute->getOutputSocket(), translateOperation->getInputSocket(1));
- converter.addLink(yAttribute->getOutputSocket(), translateOperation->getInputSocket(2));
+ ScaleRelativeOperation *scale_operation = new ScaleRelativeOperation();
+ scale_operation->set_sampler(sampler);
+ RotateOperation *rotate_operation = new RotateOperation();
+ rotate_operation->set_do_degree2_rad_conversion(false);
+ rotate_operation->set_sampler(sampler);
+ TranslateOperation *translate_operation = new TranslateCanvasOperation();
+
+ converter.add_operation(scale_operation);
+ converter.add_operation(translate_operation);
+ converter.add_operation(rotate_operation);
+
+ converter.add_link(scale_attribute->get_output_socket(),
+ scale_operation->get_input_socket(1));
+ converter.add_link(scale_attribute->get_output_socket(),
+ scale_operation->get_input_socket(2));
+
+ converter.add_link(angle_attribute->get_output_socket(),
+ rotate_operation->get_input_socket(1));
+
+ converter.add_link(x_attribute->get_output_socket(),
+ translate_operation->get_input_socket(1));
+ converter.add_link(y_attribute->get_output_socket(),
+ translate_operation->get_input_socket(2));
NodeOperationInput *stabilization_socket = nullptr;
if (invert) {
/* Translate -> Rotate -> Scale. */
- stabilization_socket = translateOperation->getInputSocket(0);
- converter.mapInputSocket(imageInput, translateOperation->getInputSocket(0));
+ stabilization_socket = translate_operation->get_input_socket(0);
+ converter.map_input_socket(image_input, translate_operation->get_input_socket(0));
- converter.addLink(translateOperation->getOutputSocket(),
- rotateOperation->getInputSocket(0));
- converter.addLink(rotateOperation->getOutputSocket(), scaleOperation->getInputSocket(0));
+ converter.add_link(translate_operation->get_output_socket(),
+ rotate_operation->get_input_socket(0));
+ converter.add_link(rotate_operation->get_output_socket(),
+ scale_operation->get_input_socket(0));
- converter.mapOutputSocket(getOutputSocket(), scaleOperation->getOutputSocket());
+ converter.map_output_socket(get_output_socket(), scale_operation->get_output_socket());
}
else {
/* Scale -> Rotate -> Translate. */
- stabilization_socket = scaleOperation->getInputSocket(0);
- converter.mapInputSocket(imageInput, scaleOperation->getInputSocket(0));
+ stabilization_socket = scale_operation->get_input_socket(0);
+ converter.map_input_socket(image_input, scale_operation->get_input_socket(0));
- converter.addLink(scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0));
- converter.addLink(rotateOperation->getOutputSocket(),
- translateOperation->getInputSocket(0));
+ converter.add_link(scale_operation->get_output_socket(),
+ rotate_operation->get_input_socket(0));
+ converter.add_link(rotate_operation->get_output_socket(),
+ translate_operation->get_input_socket(0));
- converter.mapOutputSocket(getOutputSocket(), translateOperation->getOutputSocket());
+ converter.map_output_socket(get_output_socket(), translate_operation->get_output_socket());
}
- xAttribute->set_socket_input_resolution_for_stabilization(stabilization_socket);
- yAttribute->set_socket_input_resolution_for_stabilization(stabilization_socket);
- scaleAttribute->set_socket_input_resolution_for_stabilization(stabilization_socket);
- angleAttribute->set_socket_input_resolution_for_stabilization(stabilization_socket);
+ x_attribute->set_socket_input_resolution_for_stabilization(stabilization_socket);
+ y_attribute->set_socket_input_resolution_for_stabilization(stabilization_socket);
+ scale_attribute->set_socket_input_resolution_for_stabilization(stabilization_socket);
+ angle_attribute->set_socket_input_resolution_for_stabilization(stabilization_socket);
break;
}
}
diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.h b/source/blender/compositor/nodes/COM_Stabilize2dNode.h
index 34ed8871e33..0c6afb272e9 100644
--- a/source/blender/compositor/nodes/COM_Stabilize2dNode.h
+++ b/source/blender/compositor/nodes/COM_Stabilize2dNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class Stabilize2dNode : public Node {
public:
- Stabilize2dNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ Stabilize2dNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.cc b/source/blender/compositor/nodes/COM_SunBeamsNode.cc
index 1e5aa0b8020..ba42b79f307 100644
--- a/source/blender/compositor/nodes/COM_SunBeamsNode.cc
+++ b/source/blender/compositor/nodes/COM_SunBeamsNode.cc
@@ -20,24 +20,24 @@
namespace blender::compositor {
-SunBeamsNode::SunBeamsNode(bNode *editorNode) : Node(editorNode)
+SunBeamsNode::SunBeamsNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void SunBeamsNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void SunBeamsNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeOutput *outputSocket = this->getOutputSocket(0);
- NodeSunBeams *data = (NodeSunBeams *)getbNode()->storage;
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeOutput *output_socket = this->get_output_socket(0);
+ NodeSunBeams *data = (NodeSunBeams *)get_bnode()->storage;
SunBeamsOperation *operation = new SunBeamsOperation();
- operation->setData(*data);
- converter.addOperation(operation);
+ operation->set_data(*data);
+ converter.add_operation(operation);
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.h b/source/blender/compositor/nodes/COM_SunBeamsNode.h
index 8b68d3f4cb5..478b5ce39f8 100644
--- a/source/blender/compositor/nodes/COM_SunBeamsNode.h
+++ b/source/blender/compositor/nodes/COM_SunBeamsNode.h
@@ -27,9 +27,9 @@ namespace blender::compositor {
*/
class SunBeamsNode : public Node {
public:
- SunBeamsNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ SunBeamsNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SwitchNode.cc b/source/blender/compositor/nodes/COM_SwitchNode.cc
index 4006d10dafb..d0bc0f6dea2 100644
--- a/source/blender/compositor/nodes/COM_SwitchNode.cc
+++ b/source/blender/compositor/nodes/COM_SwitchNode.cc
@@ -20,25 +20,25 @@
namespace blender::compositor {
-SwitchNode::SwitchNode(bNode *editorNode) : Node(editorNode)
+SwitchNode::SwitchNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void SwitchNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void SwitchNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- bool condition = this->getbNode()->custom1;
+ bool condition = this->get_bnode()->custom1;
NodeOperationOutput *result;
if (!condition) {
- result = converter.addInputProxy(getInputSocket(0), false);
+ result = converter.add_input_proxy(get_input_socket(0), false);
}
else {
- result = converter.addInputProxy(getInputSocket(1), false);
+ result = converter.add_input_proxy(get_input_socket(1), false);
}
- converter.mapOutputSocket(getOutputSocket(0), result);
+ converter.map_output_socket(get_output_socket(0), result);
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SwitchNode.h b/source/blender/compositor/nodes/COM_SwitchNode.h
index aa6caa2e59f..eafdeb4ac74 100644
--- a/source/blender/compositor/nodes/COM_SwitchNode.h
+++ b/source/blender/compositor/nodes/COM_SwitchNode.h
@@ -30,9 +30,9 @@ namespace blender::compositor {
*/
class SwitchNode : public Node {
public:
- SwitchNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ SwitchNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.cc b/source/blender/compositor/nodes/COM_SwitchViewNode.cc
index 395122dd11b..735ccaf3513 100644
--- a/source/blender/compositor/nodes/COM_SwitchViewNode.cc
+++ b/source/blender/compositor/nodes/COM_SwitchViewNode.cc
@@ -17,28 +17,27 @@
*/
#include "COM_SwitchViewNode.h"
-#include "BLI_listbase.h"
namespace blender::compositor {
-SwitchViewNode::SwitchViewNode(bNode *editorNode) : Node(editorNode)
+SwitchViewNode::SwitchViewNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void SwitchViewNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void SwitchViewNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
NodeOperationOutput *result;
- const char *viewName = context.getViewName();
- bNode *bnode = this->getbNode();
+ const char *view_name = context.get_view_name();
+ bNode *bnode = this->get_bnode();
/* get the internal index of the socket with a matching name */
- int nr = BLI_findstringindex(&bnode->inputs, viewName, offsetof(bNodeSocket, name));
+ int nr = BLI_findstringindex(&bnode->inputs, view_name, offsetof(bNodeSocket, name));
nr = MAX2(nr, 0);
- result = converter.addInputProxy(getInputSocket(nr), false);
- converter.mapOutputSocket(getOutputSocket(0), result);
+ result = converter.add_input_proxy(get_input_socket(nr), false);
+ converter.map_output_socket(get_output_socket(0), result);
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.h b/source/blender/compositor/nodes/COM_SwitchViewNode.h
index ce6de52182c..227c076f181 100644
--- a/source/blender/compositor/nodes/COM_SwitchViewNode.h
+++ b/source/blender/compositor/nodes/COM_SwitchViewNode.h
@@ -30,9 +30,9 @@ namespace blender::compositor {
*/
class SwitchViewNode : public Node {
public:
- SwitchViewNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ SwitchViewNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_TextureNode.cc b/source/blender/compositor/nodes/COM_TextureNode.cc
index 317355b8c9a..ca57680781f 100644
--- a/source/blender/compositor/nodes/COM_TextureNode.cc
+++ b/source/blender/compositor/nodes/COM_TextureNode.cc
@@ -17,44 +17,43 @@
*/
#include "COM_TextureNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_TextureOperation.h"
namespace blender::compositor {
-TextureNode::TextureNode(bNode *editorNode) : Node(editorNode)
+TextureNode::TextureNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void TextureNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void TextureNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *editorNode = this->getbNode();
- Tex *texture = (Tex *)editorNode->id;
+ bNode *editor_node = this->get_bnode();
+ Tex *texture = (Tex *)editor_node->id;
TextureOperation *operation = new TextureOperation();
- const ColorManagedDisplaySettings *displaySettings = context.getDisplaySettings();
- bool sceneColorManage = !STREQ(displaySettings->display_device, "None");
- operation->setTexture(texture);
- operation->setRenderData(context.getRenderData());
- operation->setSceneColorManage(sceneColorManage);
- converter.addOperation(operation);
-
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(1), operation->getOutputSocket());
-
- converter.addPreview(operation->getOutputSocket());
-
- TextureAlphaOperation *alphaOperation = new TextureAlphaOperation();
- alphaOperation->setTexture(texture);
- alphaOperation->setRenderData(context.getRenderData());
- alphaOperation->setSceneColorManage(sceneColorManage);
- converter.addOperation(alphaOperation);
-
- converter.mapInputSocket(getInputSocket(0), alphaOperation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), alphaOperation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(0), alphaOperation->getOutputSocket());
+ const ColorManagedDisplaySettings *display_settings = context.get_display_settings();
+ bool scene_color_manage = !STREQ(display_settings->display_device, "None");
+ operation->set_texture(texture);
+ operation->set_render_data(context.get_render_data());
+ operation->set_scene_color_manage(scene_color_manage);
+ converter.add_operation(operation);
+
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(1), operation->get_output_socket());
+
+ converter.add_preview(operation->get_output_socket());
+
+ TextureAlphaOperation *alpha_operation = new TextureAlphaOperation();
+ alpha_operation->set_texture(texture);
+ alpha_operation->set_render_data(context.get_render_data());
+ alpha_operation->set_scene_color_manage(scene_color_manage);
+ converter.add_operation(alpha_operation);
+
+ converter.map_input_socket(get_input_socket(0), alpha_operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), alpha_operation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(0), alpha_operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_TextureNode.h b/source/blender/compositor/nodes/COM_TextureNode.h
index b886e3b74e1..bd477e6c6e6 100644
--- a/source/blender/compositor/nodes/COM_TextureNode.h
+++ b/source/blender/compositor/nodes/COM_TextureNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class TextureNode : public Node {
public:
- TextureNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ TextureNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_TimeNode.cc b/source/blender/compositor/nodes/COM_TimeNode.cc
index c14c5344eee..0d1532f62f9 100644
--- a/source/blender/compositor/nodes/COM_TimeNode.cc
+++ b/source/blender/compositor/nodes/COM_TimeNode.cc
@@ -17,29 +17,27 @@
*/
#include "COM_TimeNode.h"
-#include "COM_ExecutionSystem.h"
+
#include "COM_SetValueOperation.h"
#include "BKE_colortools.h"
-#include "BLI_utildefines.h"
-
namespace blender::compositor {
-TimeNode::TimeNode(bNode *editorNode) : Node(editorNode)
+TimeNode::TimeNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void TimeNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void TimeNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
SetValueOperation *operation = new SetValueOperation();
- bNode *node = this->getbNode();
+ bNode *node = this->get_bnode();
/* stack order output: fac */
float fac = 0.0f;
- const int framenumber = context.getFramenumber();
+ const int framenumber = context.get_framenumber();
if (framenumber < node->custom1) {
fac = 0.0f;
@@ -48,15 +46,15 @@ void TimeNode::convertToOperations(NodeConverter &converter,
fac = 1.0f;
}
else if (node->custom1 < node->custom2) {
- fac = (context.getFramenumber() - node->custom1) / (float)(node->custom2 - node->custom1);
+ fac = (context.get_framenumber() - node->custom1) / (float)(node->custom2 - node->custom1);
}
BKE_curvemapping_init((CurveMapping *)node->storage);
fac = BKE_curvemapping_evaluateF((CurveMapping *)node->storage, 0, fac);
- operation->setValue(clamp_f(fac, 0.0f, 1.0f));
- converter.addOperation(operation);
+ operation->set_value(clamp_f(fac, 0.0f, 1.0f));
+ converter.add_operation(operation);
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_TimeNode.h b/source/blender/compositor/nodes/COM_TimeNode.h
index 5688e2cff03..5c5a0c98058 100644
--- a/source/blender/compositor/nodes/COM_TimeNode.h
+++ b/source/blender/compositor/nodes/COM_TimeNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class TimeNode : public Node {
public:
- TimeNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ TimeNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_TonemapNode.cc b/source/blender/compositor/nodes/COM_TonemapNode.cc
index 844fe3e8cb6..54ba84d46bd 100644
--- a/source/blender/compositor/nodes/COM_TonemapNode.cc
+++ b/source/blender/compositor/nodes/COM_TonemapNode.cc
@@ -17,28 +17,27 @@
*/
#include "COM_TonemapNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_TonemapOperation.h"
namespace blender::compositor {
-TonemapNode::TonemapNode(bNode *editorNode) : Node(editorNode)
+TonemapNode::TonemapNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void TonemapNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void TonemapNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeTonemap *data = (NodeTonemap *)this->getbNode()->storage;
+ NodeTonemap *data = (NodeTonemap *)this->get_bnode()->storage;
TonemapOperation *operation = data->type == 1 ? new PhotoreceptorTonemapOperation() :
new TonemapOperation();
- operation->setData(data);
- converter.addOperation(operation);
+ operation->set_data(data);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0));
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_TonemapNode.h b/source/blender/compositor/nodes/COM_TonemapNode.h
index cac9004c32a..3c67472bf98 100644
--- a/source/blender/compositor/nodes/COM_TonemapNode.h
+++ b/source/blender/compositor/nodes/COM_TonemapNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class TonemapNode : public Node {
public:
- TonemapNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ TonemapNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_TrackPositionNode.cc b/source/blender/compositor/nodes/COM_TrackPositionNode.cc
index 3fb5fc02f20..ced09d8535f 100644
--- a/source/blender/compositor/nodes/COM_TrackPositionNode.cc
+++ b/source/blender/compositor/nodes/COM_TrackPositionNode.cc
@@ -19,7 +19,6 @@
#include "COM_TrackPositionNode.h"
#include "COM_ConvertOperation.h"
-#include "COM_ExecutionSystem.h"
#include "COM_TrackPositionOperation.h"
#include "DNA_movieclip_types.h"
@@ -28,7 +27,7 @@
namespace blender::compositor {
-TrackPositionNode::TrackPositionNode(bNode *editorNode) : Node(editorNode)
+TrackPositionNode::TrackPositionNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
@@ -41,58 +40,58 @@ static TrackPositionOperation *create_motion_operation(NodeConverter &converter,
int delta)
{
TrackPositionOperation *operation = new TrackPositionOperation();
- operation->setMovieClip(clip);
- operation->setTrackingObject(trackpos_data->tracking_object);
- operation->setTrackName(trackpos_data->track_name);
- operation->setFramenumber(frame_number);
- operation->setAxis(axis);
- operation->setPosition(CMP_TRACKPOS_ABSOLUTE);
- operation->setRelativeFrame(frame_number + delta);
- operation->setSpeedOutput(true);
- converter.addOperation(operation);
+ operation->set_movie_clip(clip);
+ operation->set_tracking_object(trackpos_data->tracking_object);
+ operation->set_track_name(trackpos_data->track_name);
+ operation->set_framenumber(frame_number);
+ operation->set_axis(axis);
+ operation->set_position(CMP_TRACKPOS_ABSOLUTE);
+ operation->set_relative_frame(frame_number + delta);
+ operation->set_speed_output(true);
+ converter.add_operation(operation);
return operation;
}
-void TrackPositionNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void TrackPositionNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *editorNode = this->getbNode();
- MovieClip *clip = (MovieClip *)editorNode->id;
- NodeTrackPosData *trackpos_data = (NodeTrackPosData *)editorNode->storage;
+ bNode *editor_node = this->get_bnode();
+ MovieClip *clip = (MovieClip *)editor_node->id;
+ NodeTrackPosData *trackpos_data = (NodeTrackPosData *)editor_node->storage;
- NodeOutput *outputX = this->getOutputSocket(0);
- NodeOutput *outputY = this->getOutputSocket(1);
- NodeOutput *outputSpeed = this->getOutputSocket(2);
+ NodeOutput *outputX = this->get_output_socket(0);
+ NodeOutput *outputY = this->get_output_socket(1);
+ NodeOutput *output_speed = this->get_output_socket(2);
int frame_number;
- if (editorNode->custom1 == CMP_TRACKPOS_ABSOLUTE_FRAME) {
- frame_number = editorNode->custom2;
+ if (editor_node->custom1 == CMP_TRACKPOS_ABSOLUTE_FRAME) {
+ frame_number = editor_node->custom2;
}
else {
- frame_number = context.getFramenumber();
+ frame_number = context.get_framenumber();
}
TrackPositionOperation *operationX = new TrackPositionOperation();
- operationX->setMovieClip(clip);
- operationX->setTrackingObject(trackpos_data->tracking_object);
- operationX->setTrackName(trackpos_data->track_name);
- operationX->setFramenumber(frame_number);
- operationX->setAxis(0);
- operationX->setPosition(editorNode->custom1);
- operationX->setRelativeFrame(editorNode->custom2);
- converter.addOperation(operationX);
- converter.mapOutputSocket(outputX, operationX->getOutputSocket());
+ operationX->set_movie_clip(clip);
+ operationX->set_tracking_object(trackpos_data->tracking_object);
+ operationX->set_track_name(trackpos_data->track_name);
+ operationX->set_framenumber(frame_number);
+ operationX->set_axis(0);
+ operationX->set_position(editor_node->custom1);
+ operationX->set_relative_frame(editor_node->custom2);
+ converter.add_operation(operationX);
+ converter.map_output_socket(outputX, operationX->get_output_socket());
TrackPositionOperation *operationY = new TrackPositionOperation();
- operationY->setMovieClip(clip);
- operationY->setTrackingObject(trackpos_data->tracking_object);
- operationY->setTrackName(trackpos_data->track_name);
- operationY->setFramenumber(frame_number);
- operationY->setAxis(1);
- operationY->setPosition(editorNode->custom1);
- operationY->setRelativeFrame(editorNode->custom2);
- converter.addOperation(operationY);
- converter.mapOutputSocket(outputY, operationY->getOutputSocket());
+ operationY->set_movie_clip(clip);
+ operationY->set_tracking_object(trackpos_data->tracking_object);
+ operationY->set_track_name(trackpos_data->track_name);
+ operationY->set_framenumber(frame_number);
+ operationY->set_axis(1);
+ operationY->set_position(editor_node->custom1);
+ operationY->set_relative_frame(editor_node->custom2);
+ converter.add_operation(operationY);
+ converter.map_output_socket(outputY, operationY->get_output_socket());
TrackPositionOperation *operationMotionPreX = create_motion_operation(
converter, clip, trackpos_data, 0, frame_number, -1);
@@ -104,12 +103,16 @@ void TrackPositionNode::convertToOperations(NodeConverter &converter,
converter, clip, trackpos_data, 1, frame_number, 1);
CombineChannelsOperation *combine_operation = new CombineChannelsOperation();
- converter.addOperation(combine_operation);
- converter.addLink(operationMotionPreX->getOutputSocket(), combine_operation->getInputSocket(0));
- converter.addLink(operationMotionPreY->getOutputSocket(), combine_operation->getInputSocket(1));
- converter.addLink(operationMotionPostX->getOutputSocket(), combine_operation->getInputSocket(2));
- converter.addLink(operationMotionPostY->getOutputSocket(), combine_operation->getInputSocket(3));
- converter.mapOutputSocket(outputSpeed, combine_operation->getOutputSocket());
+ converter.add_operation(combine_operation);
+ converter.add_link(operationMotionPreX->get_output_socket(),
+ combine_operation->get_input_socket(0));
+ converter.add_link(operationMotionPreY->get_output_socket(),
+ combine_operation->get_input_socket(1));
+ converter.add_link(operationMotionPostX->get_output_socket(),
+ combine_operation->get_input_socket(2));
+ converter.add_link(operationMotionPostY->get_output_socket(),
+ combine_operation->get_input_socket(3));
+ converter.map_output_socket(output_speed, combine_operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_TrackPositionNode.h b/source/blender/compositor/nodes/COM_TrackPositionNode.h
index 665ba36fe09..d0b1648b0c9 100644
--- a/source/blender/compositor/nodes/COM_TrackPositionNode.h
+++ b/source/blender/compositor/nodes/COM_TrackPositionNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class TrackPositionNode : public Node {
public:
- TrackPositionNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ TrackPositionNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_TransformNode.cc b/source/blender/compositor/nodes/COM_TransformNode.cc
index b38aad78d90..cd60e8c17db 100644
--- a/source/blender/compositor/nodes/COM_TransformNode.cc
+++ b/source/blender/compositor/nodes/COM_TransformNode.cc
@@ -17,89 +17,92 @@
*/
#include "COM_TransformNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_RotateOperation.h"
#include "COM_ScaleOperation.h"
#include "COM_SetSamplerOperation.h"
-#include "COM_SetValueOperation.h"
-#include "COM_TransformOperation.h"
#include "COM_TranslateOperation.h"
namespace blender::compositor {
-TransformNode::TransformNode(bNode *editorNode) : Node(editorNode)
+TransformNode::TransformNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void TransformNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void TransformNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- NodeInput *imageInput = this->getInputSocket(0);
- NodeInput *xInput = this->getInputSocket(1);
- NodeInput *yInput = this->getInputSocket(2);
- NodeInput *angleInput = this->getInputSocket(3);
- NodeInput *scaleInput = this->getInputSocket(4);
+ NodeInput *image_input = this->get_input_socket(0);
+ NodeInput *x_input = this->get_input_socket(1);
+ NodeInput *y_input = this->get_input_socket(2);
+ NodeInput *angle_input = this->get_input_socket(3);
+ NodeInput *scale_input = this->get_input_socket(4);
switch (context.get_execution_model()) {
case eExecutionModel::Tiled: {
- ScaleRelativeOperation *scaleOperation = new ScaleRelativeOperation();
- converter.addOperation(scaleOperation);
+ ScaleRelativeOperation *scale_operation = new ScaleRelativeOperation();
+ converter.add_operation(scale_operation);
- RotateOperation *rotateOperation = new RotateOperation();
- rotateOperation->setDoDegree2RadConversion(false);
- converter.addOperation(rotateOperation);
+ RotateOperation *rotate_operation = new RotateOperation();
+ rotate_operation->set_do_degree2_rad_conversion(false);
+ converter.add_operation(rotate_operation);
- TranslateOperation *translateOperation = new TranslateOperation();
- converter.addOperation(translateOperation);
+ TranslateOperation *translate_operation = new TranslateOperation();
+ converter.add_operation(translate_operation);
SetSamplerOperation *sampler = new SetSamplerOperation();
- sampler->setSampler((PixelSampler)this->getbNode()->custom1);
- converter.addOperation(sampler);
+ sampler->set_sampler((PixelSampler)this->get_bnode()->custom1);
+ converter.add_operation(sampler);
- converter.mapInputSocket(imageInput, sampler->getInputSocket(0));
- converter.addLink(sampler->getOutputSocket(), scaleOperation->getInputSocket(0));
- converter.mapInputSocket(scaleInput, scaleOperation->getInputSocket(1));
- converter.mapInputSocket(scaleInput, scaleOperation->getInputSocket(2)); // xscale = yscale
+ converter.map_input_socket(image_input, sampler->get_input_socket(0));
+ converter.add_link(sampler->get_output_socket(), scale_operation->get_input_socket(0));
+ converter.map_input_socket(scale_input, scale_operation->get_input_socket(1));
+ converter.map_input_socket(scale_input,
+ scale_operation->get_input_socket(2)); // xscale = yscale
- converter.addLink(scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0));
- converter.mapInputSocket(angleInput, rotateOperation->getInputSocket(1));
+ converter.add_link(scale_operation->get_output_socket(),
+ rotate_operation->get_input_socket(0));
+ converter.map_input_socket(angle_input, rotate_operation->get_input_socket(1));
- converter.addLink(rotateOperation->getOutputSocket(), translateOperation->getInputSocket(0));
- converter.mapInputSocket(xInput, translateOperation->getInputSocket(1));
- converter.mapInputSocket(yInput, translateOperation->getInputSocket(2));
+ converter.add_link(rotate_operation->get_output_socket(),
+ translate_operation->get_input_socket(0));
+ converter.map_input_socket(x_input, translate_operation->get_input_socket(1));
+ converter.map_input_socket(y_input, translate_operation->get_input_socket(2));
- converter.mapOutputSocket(getOutputSocket(), translateOperation->getOutputSocket());
+ converter.map_output_socket(get_output_socket(), translate_operation->get_output_socket());
break;
}
case eExecutionModel::FullFrame: {
- ScaleRelativeOperation *scaleOperation = new ScaleRelativeOperation();
- converter.addOperation(scaleOperation);
+ ScaleRelativeOperation *scale_operation = new ScaleRelativeOperation();
+ converter.add_operation(scale_operation);
- RotateOperation *rotateOperation = new RotateOperation();
- rotateOperation->setDoDegree2RadConversion(false);
- converter.addOperation(rotateOperation);
+ RotateOperation *rotate_operation = new RotateOperation();
+ rotate_operation->set_do_degree2_rad_conversion(false);
+ converter.add_operation(rotate_operation);
- TranslateOperation *translateOperation = new TranslateCanvasOperation();
- converter.addOperation(translateOperation);
+ TranslateOperation *translate_operation = new TranslateCanvasOperation();
+ converter.add_operation(translate_operation);
- PixelSampler sampler = (PixelSampler)this->getbNode()->custom1;
- scaleOperation->setSampler(sampler);
- rotateOperation->set_sampler(sampler);
- scaleOperation->set_scale_canvas_max_size(context.get_render_size());
+ PixelSampler sampler = (PixelSampler)this->get_bnode()->custom1;
+ scale_operation->set_sampler(sampler);
+ rotate_operation->set_sampler(sampler);
+ scale_operation->set_scale_canvas_max_size(context.get_render_size());
- converter.mapInputSocket(imageInput, scaleOperation->getInputSocket(0));
- converter.mapInputSocket(scaleInput, scaleOperation->getInputSocket(1));
- converter.mapInputSocket(scaleInput, scaleOperation->getInputSocket(2)); // xscale = yscale
+ converter.map_input_socket(image_input, scale_operation->get_input_socket(0));
+ converter.map_input_socket(scale_input, scale_operation->get_input_socket(1));
+ converter.map_input_socket(scale_input,
+ scale_operation->get_input_socket(2)); // xscale = yscale
- converter.addLink(scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0));
- converter.mapInputSocket(angleInput, rotateOperation->getInputSocket(1));
+ converter.add_link(scale_operation->get_output_socket(),
+ rotate_operation->get_input_socket(0));
+ converter.map_input_socket(angle_input, rotate_operation->get_input_socket(1));
- converter.addLink(rotateOperation->getOutputSocket(), translateOperation->getInputSocket(0));
- converter.mapInputSocket(xInput, translateOperation->getInputSocket(1));
- converter.mapInputSocket(yInput, translateOperation->getInputSocket(2));
+ converter.add_link(rotate_operation->get_output_socket(),
+ translate_operation->get_input_socket(0));
+ converter.map_input_socket(x_input, translate_operation->get_input_socket(1));
+ converter.map_input_socket(y_input, translate_operation->get_input_socket(2));
- converter.mapOutputSocket(getOutputSocket(), translateOperation->getOutputSocket());
+ converter.map_output_socket(get_output_socket(), translate_operation->get_output_socket());
break;
}
}
diff --git a/source/blender/compositor/nodes/COM_TransformNode.h b/source/blender/compositor/nodes/COM_TransformNode.h
index 137e162256d..66255d63813 100644
--- a/source/blender/compositor/nodes/COM_TransformNode.h
+++ b/source/blender/compositor/nodes/COM_TransformNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class TransformNode : public Node {
public:
- TransformNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ TransformNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_TranslateNode.cc b/source/blender/compositor/nodes/COM_TranslateNode.cc
index 165a03baf41..b9f96d92942 100644
--- a/source/blender/compositor/nodes/COM_TranslateNode.cc
+++ b/source/blender/compositor/nodes/COM_TranslateNode.cc
@@ -18,60 +18,59 @@
#include "COM_TranslateNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_TranslateOperation.h"
#include "COM_WrapOperation.h"
#include "COM_WriteBufferOperation.h"
namespace blender::compositor {
-TranslateNode::TranslateNode(bNode *editorNode) : Node(editorNode)
+TranslateNode::TranslateNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void TranslateNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void TranslateNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *bnode = this->getbNode();
+ bNode *bnode = this->get_bnode();
NodeTranslateData *data = (NodeTranslateData *)bnode->storage;
- NodeInput *inputSocket = this->getInputSocket(0);
- NodeInput *inputXSocket = this->getInputSocket(1);
- NodeInput *inputYSocket = this->getInputSocket(2);
- NodeOutput *outputSocket = this->getOutputSocket(0);
+ NodeInput *input_socket = this->get_input_socket(0);
+ NodeInput *input_xsocket = this->get_input_socket(1);
+ NodeInput *input_ysocket = this->get_input_socket(2);
+ NodeOutput *output_socket = this->get_output_socket(0);
TranslateOperation *operation = context.get_execution_model() == eExecutionModel::Tiled ?
new TranslateOperation() :
new TranslateCanvasOperation();
operation->set_wrapping(data->wrap_axis);
if (data->relative) {
- const RenderData *rd = context.getRenderData();
- const float render_size_factor = context.getRenderPercentageAsFactor();
+ const RenderData *rd = context.get_render_data();
+ const float render_size_factor = context.get_render_percentage_as_factor();
float fx = rd->xsch * render_size_factor;
float fy = rd->ysch * render_size_factor;
operation->setFactorXY(fx, fy);
}
- converter.addOperation(operation);
- converter.mapInputSocket(inputXSocket, operation->getInputSocket(1));
- converter.mapInputSocket(inputYSocket, operation->getInputSocket(2));
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+ converter.add_operation(operation);
+ converter.map_input_socket(input_xsocket, operation->get_input_socket(1));
+ converter.map_input_socket(input_ysocket, operation->get_input_socket(2));
+ converter.map_output_socket(output_socket, operation->get_output_socket(0));
if (data->wrap_axis && context.get_execution_model() != eExecutionModel::FullFrame) {
/* TODO: To be removed with tiled implementation. */
- WriteBufferOperation *writeOperation = new WriteBufferOperation(DataType::Color);
- WrapOperation *wrapOperation = new WrapOperation(DataType::Color);
- wrapOperation->setMemoryProxy(writeOperation->getMemoryProxy());
- wrapOperation->setWrapping(data->wrap_axis);
+ WriteBufferOperation *write_operation = new WriteBufferOperation(DataType::Color);
+ WrapOperation *wrap_operation = new WrapOperation(DataType::Color);
+ wrap_operation->set_memory_proxy(write_operation->get_memory_proxy());
+ wrap_operation->set_wrapping(data->wrap_axis);
- converter.addOperation(writeOperation);
- converter.addOperation(wrapOperation);
- converter.mapInputSocket(inputSocket, writeOperation->getInputSocket(0));
- converter.addLink(wrapOperation->getOutputSocket(), operation->getInputSocket(0));
+ converter.add_operation(write_operation);
+ converter.add_operation(wrap_operation);
+ converter.map_input_socket(input_socket, write_operation->get_input_socket(0));
+ converter.add_link(wrap_operation->get_output_socket(), operation->get_input_socket(0));
}
else {
- converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
+ converter.map_input_socket(input_socket, operation->get_input_socket(0));
}
}
diff --git a/source/blender/compositor/nodes/COM_TranslateNode.h b/source/blender/compositor/nodes/COM_TranslateNode.h
index 0cea234bff8..5ccbb01f3f0 100644
--- a/source/blender/compositor/nodes/COM_TranslateNode.h
+++ b/source/blender/compositor/nodes/COM_TranslateNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class TranslateNode : public Node {
public:
- TranslateNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ TranslateNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ValueNode.cc b/source/blender/compositor/nodes/COM_ValueNode.cc
index 6b640fa2a3a..892a68dabcc 100644
--- a/source/blender/compositor/nodes/COM_ValueNode.cc
+++ b/source/blender/compositor/nodes/COM_ValueNode.cc
@@ -17,25 +17,24 @@
*/
#include "COM_ValueNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_SetValueOperation.h"
namespace blender::compositor {
-ValueNode::ValueNode(bNode *editorNode) : Node(editorNode)
+ValueNode::ValueNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ValueNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ValueNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
SetValueOperation *operation = new SetValueOperation();
- NodeOutput *output = this->getOutputSocket(0);
- operation->setValue(output->getEditorValueFloat());
- converter.addOperation(operation);
+ NodeOutput *output = this->get_output_socket(0);
+ operation->set_value(output->get_editor_value_float());
+ converter.add_operation(operation);
- converter.mapOutputSocket(output, operation->getOutputSocket());
+ converter.map_output_socket(output, operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ValueNode.h b/source/blender/compositor/nodes/COM_ValueNode.h
index 1401b2c7e0a..d70013c48af 100644
--- a/source/blender/compositor/nodes/COM_ValueNode.h
+++ b/source/blender/compositor/nodes/COM_ValueNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ValueNode : public Node {
public:
- ValueNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ValueNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_VectorBlurNode.cc b/source/blender/compositor/nodes/COM_VectorBlurNode.cc
index 7aa5f5668c9..b3f32465a34 100644
--- a/source/blender/compositor/nodes/COM_VectorBlurNode.cc
+++ b/source/blender/compositor/nodes/COM_VectorBlurNode.cc
@@ -18,30 +18,29 @@
#include "COM_VectorBlurNode.h"
#include "COM_VectorBlurOperation.h"
-#include "DNA_node_types.h"
namespace blender::compositor {
-VectorBlurNode::VectorBlurNode(bNode *editorNode) : Node(editorNode)
+VectorBlurNode::VectorBlurNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void VectorBlurNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void VectorBlurNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *node = this->getbNode();
- NodeBlurData *vectorBlurSettings = (NodeBlurData *)node->storage;
+ bNode *node = this->get_bnode();
+ NodeBlurData *vector_blur_settings = (NodeBlurData *)node->storage;
VectorBlurOperation *operation = new VectorBlurOperation();
- operation->setVectorBlurSettings(vectorBlurSettings);
- operation->setQuality(context.getQuality());
- converter.addOperation(operation);
+ operation->set_vector_blur_settings(vector_blur_settings);
+ operation->set_quality(context.get_quality());
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2));
- converter.mapOutputSocket(getOutputSocket(), operation->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_input_socket(get_input_socket(2), operation->get_input_socket(2));
+ converter.map_output_socket(get_output_socket(), operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_VectorBlurNode.h b/source/blender/compositor/nodes/COM_VectorBlurNode.h
index 8c98a0b81a1..fb8a70ab2ec 100644
--- a/source/blender/compositor/nodes/COM_VectorBlurNode.h
+++ b/source/blender/compositor/nodes/COM_VectorBlurNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class VectorBlurNode : public Node {
public:
- VectorBlurNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ VectorBlurNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_VectorCurveNode.cc b/source/blender/compositor/nodes/COM_VectorCurveNode.cc
index f2fd80cd93e..d064c5787fd 100644
--- a/source/blender/compositor/nodes/COM_VectorCurveNode.cc
+++ b/source/blender/compositor/nodes/COM_VectorCurveNode.cc
@@ -17,25 +17,24 @@
*/
#include "COM_VectorCurveNode.h"
-#include "COM_ExecutionSystem.h"
#include "COM_VectorCurveOperation.h"
namespace blender::compositor {
-VectorCurveNode::VectorCurveNode(bNode *editorNode) : Node(editorNode)
+VectorCurveNode::VectorCurveNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void VectorCurveNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void VectorCurveNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
VectorCurveOperation *operation = new VectorCurveOperation();
- operation->setCurveMapping((CurveMapping *)this->getbNode()->storage);
- converter.addOperation(operation);
+ operation->set_curve_mapping((CurveMapping *)this->get_bnode()->storage);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_VectorCurveNode.h b/source/blender/compositor/nodes/COM_VectorCurveNode.h
index ee4df5d3a42..901bd6f64b9 100644
--- a/source/blender/compositor/nodes/COM_VectorCurveNode.h
+++ b/source/blender/compositor/nodes/COM_VectorCurveNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class VectorCurveNode : public Node {
public:
- VectorCurveNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ VectorCurveNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ViewLevelsNode.cc b/source/blender/compositor/nodes/COM_ViewLevelsNode.cc
index 5a03972c89d..79d535fc58a 100644
--- a/source/blender/compositor/nodes/COM_ViewLevelsNode.cc
+++ b/source/blender/compositor/nodes/COM_ViewLevelsNode.cc
@@ -17,48 +17,45 @@
*/
#include "COM_ViewLevelsNode.h"
-#include "COM_CalculateMeanOperation.h"
#include "COM_CalculateStandardDeviationOperation.h"
-#include "COM_ExecutionSystem.h"
-#include "COM_SetValueOperation.h"
namespace blender::compositor {
-ViewLevelsNode::ViewLevelsNode(bNode *editorNode) : Node(editorNode)
+ViewLevelsNode::ViewLevelsNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ViewLevelsNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ViewLevelsNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- NodeInput *input = this->getInputSocket(0);
- if (input->isLinked()) {
+ NodeInput *input = this->get_input_socket(0);
+ if (input->is_linked()) {
/* Add preview to input-socket. */
/* calculate mean operation */
{
CalculateMeanOperation *operation = new CalculateMeanOperation();
- operation->setSetting(this->getbNode()->custom1);
+ operation->set_setting(this->get_bnode()->custom1);
- converter.addOperation(operation);
- converter.mapInputSocket(input, operation->getInputSocket(0));
- converter.mapOutputSocket(this->getOutputSocket(0), operation->getOutputSocket());
+ converter.add_operation(operation);
+ converter.map_input_socket(input, operation->get_input_socket(0));
+ converter.map_output_socket(this->get_output_socket(0), operation->get_output_socket());
}
/* calculate standard deviation operation */
{
CalculateStandardDeviationOperation *operation = new CalculateStandardDeviationOperation();
- operation->setSetting(this->getbNode()->custom1);
+ operation->set_setting(this->get_bnode()->custom1);
- converter.addOperation(operation);
- converter.mapInputSocket(input, operation->getInputSocket(0));
- converter.mapOutputSocket(this->getOutputSocket(1), operation->getOutputSocket());
+ converter.add_operation(operation);
+ converter.map_input_socket(input, operation->get_input_socket(0));
+ converter.map_output_socket(this->get_output_socket(1), operation->get_output_socket());
}
}
else {
- converter.addOutputValue(getOutputSocket(0), 0.0f);
- converter.addOutputValue(getOutputSocket(1), 0.0f);
+ converter.add_output_value(get_output_socket(0), 0.0f);
+ converter.add_output_value(get_output_socket(1), 0.0f);
}
}
diff --git a/source/blender/compositor/nodes/COM_ViewLevelsNode.h b/source/blender/compositor/nodes/COM_ViewLevelsNode.h
index 055d871498e..5415bbb2ee9 100644
--- a/source/blender/compositor/nodes/COM_ViewLevelsNode.h
+++ b/source/blender/compositor/nodes/COM_ViewLevelsNode.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ViewLevelsNode : public Node {
public:
- ViewLevelsNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ViewLevelsNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cc b/source/blender/compositor/nodes/COM_ViewerNode.cc
index 4dbcdbe9e40..7efb23b849d 100644
--- a/source/blender/compositor/nodes/COM_ViewerNode.cc
+++ b/source/blender/compositor/nodes/COM_ViewerNode.cc
@@ -17,71 +17,66 @@
*/
#include "COM_ViewerNode.h"
-#include "BKE_global.h"
-#include "BKE_image.h"
-#include "BKE_scene.h"
-#include "BLI_listbase.h"
-#include "COM_ExecutionSystem.h"
#include "COM_ViewerOperation.h"
namespace blender::compositor {
-ViewerNode::ViewerNode(bNode *editorNode) : Node(editorNode)
+ViewerNode::ViewerNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
-void ViewerNode::convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const
+void ViewerNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- bNode *editorNode = this->getbNode();
- bool do_output = (editorNode->flag & NODE_DO_OUTPUT_RECALC || context.isRendering()) &&
- (editorNode->flag & NODE_DO_OUTPUT);
- bool ignore_alpha = (editorNode->custom2 & CMP_NODE_OUTPUT_IGNORE_ALPHA) != 0;
+ bNode *editor_node = this->get_bnode();
+ bool do_output = (editor_node->flag & NODE_DO_OUTPUT_RECALC || context.is_rendering()) &&
+ (editor_node->flag & NODE_DO_OUTPUT);
+ bool ignore_alpha = (editor_node->custom2 & CMP_NODE_OUTPUT_IGNORE_ALPHA) != 0;
- NodeInput *imageSocket = this->getInputSocket(0);
- NodeInput *alphaSocket = this->getInputSocket(1);
- NodeInput *depthSocket = this->getInputSocket(2);
- Image *image = (Image *)this->getbNode()->id;
- ImageUser *imageUser = (ImageUser *)this->getbNode()->storage;
- ViewerOperation *viewerOperation = new ViewerOperation();
- viewerOperation->setbNodeTree(context.getbNodeTree());
- viewerOperation->setImage(image);
- viewerOperation->setImageUser(imageUser);
- viewerOperation->setChunkOrder((ChunkOrdering)editorNode->custom1);
- viewerOperation->setCenterX(editorNode->custom3);
- viewerOperation->setCenterY(editorNode->custom4);
+ NodeInput *image_socket = this->get_input_socket(0);
+ NodeInput *alpha_socket = this->get_input_socket(1);
+ NodeInput *depth_socket = this->get_input_socket(2);
+ Image *image = (Image *)this->get_bnode()->id;
+ ImageUser *image_user = (ImageUser *)this->get_bnode()->storage;
+ ViewerOperation *viewer_operation = new ViewerOperation();
+ viewer_operation->set_bnodetree(context.get_bnodetree());
+ viewer_operation->set_image(image);
+ viewer_operation->set_image_user(image_user);
+ viewer_operation->set_chunk_order((ChunkOrdering)editor_node->custom1);
+ viewer_operation->setCenterX(editor_node->custom3);
+ viewer_operation->setCenterY(editor_node->custom4);
/* alpha socket gives either 1 or a custom alpha value if "use alpha" is enabled */
- viewerOperation->setUseAlphaInput(ignore_alpha || alphaSocket->isLinked());
- viewerOperation->setRenderData(context.getRenderData());
- viewerOperation->setViewName(context.getViewName());
+ viewer_operation->set_use_alpha_input(ignore_alpha || alpha_socket->is_linked());
+ viewer_operation->set_render_data(context.get_render_data());
+ viewer_operation->set_view_name(context.get_view_name());
- viewerOperation->setViewSettings(context.getViewSettings());
- viewerOperation->setDisplaySettings(context.getDisplaySettings());
+ viewer_operation->set_view_settings(context.get_view_settings());
+ viewer_operation->set_display_settings(context.get_display_settings());
- viewerOperation->set_canvas_input_index(0);
- if (!imageSocket->isLinked()) {
- if (alphaSocket->isLinked()) {
- viewerOperation->set_canvas_input_index(1);
+ viewer_operation->set_canvas_input_index(0);
+ if (!image_socket->is_linked()) {
+ if (alpha_socket->is_linked()) {
+ viewer_operation->set_canvas_input_index(1);
}
}
- converter.addOperation(viewerOperation);
- converter.mapInputSocket(imageSocket, viewerOperation->getInputSocket(0));
+ converter.add_operation(viewer_operation);
+ converter.map_input_socket(image_socket, viewer_operation->get_input_socket(0));
/* only use alpha link if "use alpha" is enabled */
if (ignore_alpha) {
- converter.addInputValue(viewerOperation->getInputSocket(1), 1.0f);
+ converter.add_input_value(viewer_operation->get_input_socket(1), 1.0f);
}
else {
- converter.mapInputSocket(alphaSocket, viewerOperation->getInputSocket(1));
+ converter.map_input_socket(alpha_socket, viewer_operation->get_input_socket(1));
}
- converter.mapInputSocket(depthSocket, viewerOperation->getInputSocket(2));
+ converter.map_input_socket(depth_socket, viewer_operation->get_input_socket(2));
- converter.addNodeInputPreview(imageSocket);
+ converter.add_node_input_preview(image_socket);
if (do_output) {
- converter.registerViewer(viewerOperation);
+ converter.register_viewer(viewer_operation);
}
}
diff --git a/source/blender/compositor/nodes/COM_ViewerNode.h b/source/blender/compositor/nodes/COM_ViewerNode.h
index 544a5e6a504..ce9076666bc 100644
--- a/source/blender/compositor/nodes/COM_ViewerNode.h
+++ b/source/blender/compositor/nodes/COM_ViewerNode.h
@@ -29,9 +29,9 @@ namespace blender::compositor {
*/
class ViewerNode : public Node {
public:
- ViewerNode(bNode *editorNode);
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ ViewerNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ZCombineNode.cc b/source/blender/compositor/nodes/COM_ZCombineNode.cc
index 9753e812a8b..52cb1451ba1 100644
--- a/source/blender/compositor/nodes/COM_ZCombineNode.cc
+++ b/source/blender/compositor/nodes/COM_ZCombineNode.cc
@@ -18,43 +18,37 @@
#include "COM_ZCombineNode.h"
-#include "COM_ZCombineOperation.h"
-
#include "COM_AntiAliasOperation.h"
-#include "COM_ExecutionSystem.h"
#include "COM_MathBaseOperation.h"
-#include "COM_MixOperation.h"
-#include "COM_SetValueOperation.h"
-
-#include "DNA_material_types.h" /* the ramp types */
+#include "COM_ZCombineOperation.h"
namespace blender::compositor {
-void ZCombineNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+void ZCombineNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext & /*context*/) const
{
- if (this->getbNode()->custom2) {
+ if (this->get_bnode()->custom2) {
ZCombineOperation *operation = nullptr;
- if (this->getbNode()->custom1) {
+ if (this->get_bnode()->custom1) {
operation = new ZCombineAlphaOperation();
}
else {
operation = new ZCombineOperation();
}
- converter.addOperation(operation);
+ converter.add_operation(operation);
- converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
- converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2));
- converter.mapInputSocket(getInputSocket(3), operation->getInputSocket(3));
- converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
+ converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
+ converter.map_input_socket(get_input_socket(2), operation->get_input_socket(2));
+ converter.map_input_socket(get_input_socket(3), operation->get_input_socket(3));
+ converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
MathMinimumOperation *zoperation = new MathMinimumOperation();
- converter.addOperation(zoperation);
+ converter.add_operation(zoperation);
- converter.mapInputSocket(getInputSocket(1), zoperation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(3), zoperation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(1), zoperation->getOutputSocket());
+ converter.map_input_socket(get_input_socket(1), zoperation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(3), zoperation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(1), zoperation->get_output_socket());
}
else {
/* XXX custom1 is "use_alpha", what on earth is this supposed to do here?!? */
@@ -62,40 +56,42 @@ void ZCombineNode::convertToOperations(NodeConverter &converter,
/* Step 1 create mask. */
NodeOperation *maskoperation;
- if (this->getbNode()->custom1) {
+ if (this->get_bnode()->custom1) {
maskoperation = new MathGreaterThanOperation();
}
else {
maskoperation = new MathLessThanOperation();
}
- converter.addOperation(maskoperation);
+ converter.add_operation(maskoperation);
- converter.mapInputSocket(getInputSocket(1), maskoperation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(3), maskoperation->getInputSocket(1));
+ converter.map_input_socket(get_input_socket(1), maskoperation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(3), maskoperation->get_input_socket(1));
/* Step 2 anti alias mask bit of an expensive operation, but does the trick. */
AntiAliasOperation *antialiasoperation = new AntiAliasOperation();
- converter.addOperation(antialiasoperation);
+ converter.add_operation(antialiasoperation);
- converter.addLink(maskoperation->getOutputSocket(), antialiasoperation->getInputSocket(0));
+ converter.add_link(maskoperation->get_output_socket(),
+ antialiasoperation->get_input_socket(0));
/* use mask to blend between the input colors. */
- ZCombineMaskOperation *zcombineoperation = this->getbNode()->custom1 ?
+ ZCombineMaskOperation *zcombineoperation = this->get_bnode()->custom1 ?
new ZCombineMaskAlphaOperation() :
new ZCombineMaskOperation();
- converter.addOperation(zcombineoperation);
+ converter.add_operation(zcombineoperation);
- converter.addLink(antialiasoperation->getOutputSocket(), zcombineoperation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(0), zcombineoperation->getInputSocket(1));
- converter.mapInputSocket(getInputSocket(2), zcombineoperation->getInputSocket(2));
- converter.mapOutputSocket(getOutputSocket(0), zcombineoperation->getOutputSocket());
+ converter.add_link(antialiasoperation->get_output_socket(),
+ zcombineoperation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(0), zcombineoperation->get_input_socket(1));
+ converter.map_input_socket(get_input_socket(2), zcombineoperation->get_input_socket(2));
+ converter.map_output_socket(get_output_socket(0), zcombineoperation->get_output_socket());
MathMinimumOperation *zoperation = new MathMinimumOperation();
- converter.addOperation(zoperation);
+ converter.add_operation(zoperation);
- converter.mapInputSocket(getInputSocket(1), zoperation->getInputSocket(0));
- converter.mapInputSocket(getInputSocket(3), zoperation->getInputSocket(1));
- converter.mapOutputSocket(getOutputSocket(1), zoperation->getOutputSocket());
+ converter.map_input_socket(get_input_socket(1), zoperation->get_input_socket(0));
+ converter.map_input_socket(get_input_socket(3), zoperation->get_input_socket(1));
+ converter.map_output_socket(get_output_socket(1), zoperation->get_output_socket());
}
}
diff --git a/source/blender/compositor/nodes/COM_ZCombineNode.h b/source/blender/compositor/nodes/COM_ZCombineNode.h
index 82f2f30fb3c..4761b336fc1 100644
--- a/source/blender/compositor/nodes/COM_ZCombineNode.h
+++ b/source/blender/compositor/nodes/COM_ZCombineNode.h
@@ -28,11 +28,11 @@ namespace blender::compositor {
*/
class ZCombineNode : public Node {
public:
- ZCombineNode(bNode *editorNode) : Node(editorNode)
+ ZCombineNode(bNode *editor_node) : Node(editor_node)
{
}
- void convertToOperations(NodeConverter &converter,
- const CompositorContext &context) const override;
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc
index 30e7fab4027..5b8d376cf79 100644
--- a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc
+++ b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc
@@ -22,36 +22,36 @@ namespace blender::compositor {
AlphaOverKeyOperation::AlphaOverKeyOperation()
{
- this->flags.can_be_constant = true;
+ flags_.can_be_constant = true;
}
-void AlphaOverKeyOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void AlphaOverKeyOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputOverColor[4];
+ float input_color1[4];
+ float input_over_color[4];
float value[4];
- this->m_inputValueOperation->readSampled(value, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputOverColor, x, y, sampler);
+ input_value_operation_->read_sampled(value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_over_color, x, y, sampler);
- if (inputOverColor[3] <= 0.0f) {
- copy_v4_v4(output, inputColor1);
+ if (input_over_color[3] <= 0.0f) {
+ copy_v4_v4(output, input_color1);
}
- else if (value[0] == 1.0f && inputOverColor[3] >= 1.0f) {
- copy_v4_v4(output, inputOverColor);
+ else if (value[0] == 1.0f && input_over_color[3] >= 1.0f) {
+ copy_v4_v4(output, input_over_color);
}
else {
- float premul = value[0] * inputOverColor[3];
+ float premul = value[0] * input_over_color[3];
float mul = 1.0f - premul;
- output[0] = (mul * inputColor1[0]) + premul * inputOverColor[0];
- output[1] = (mul * inputColor1[1]) + premul * inputOverColor[1];
- output[2] = (mul * inputColor1[2]) + premul * inputOverColor[2];
- output[3] = (mul * inputColor1[3]) + value[0] * inputOverColor[3];
+ output[0] = (mul * input_color1[0]) + premul * input_over_color[0];
+ output[1] = (mul * input_color1[1]) + premul * input_over_color[1];
+ output[2] = (mul * input_color1[2]) + premul * input_over_color[2];
+ output[3] = (mul * input_color1[3]) + value[0] * input_over_color[3];
}
}
diff --git a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h
index 960fbc98fe9..cfcb655ceca 100644
--- a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h
+++ b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h
@@ -33,7 +33,7 @@ class AlphaOverKeyOperation : public MixBaseOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_row(PixelCursor &p) override;
};
diff --git a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc
index 0cc179ea209..42efca996ab 100644
--- a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc
+++ b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc
@@ -22,38 +22,38 @@ namespace blender::compositor {
AlphaOverMixedOperation::AlphaOverMixedOperation()
{
- this->m_x = 0.0f;
- this->flags.can_be_constant = true;
+ x_ = 0.0f;
+ flags_.can_be_constant = true;
}
-void AlphaOverMixedOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void AlphaOverMixedOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputOverColor[4];
+ float input_color1[4];
+ float input_over_color[4];
float value[4];
- this->m_inputValueOperation->readSampled(value, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputOverColor, x, y, sampler);
+ input_value_operation_->read_sampled(value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_over_color, x, y, sampler);
- if (inputOverColor[3] <= 0.0f) {
- copy_v4_v4(output, inputColor1);
+ if (input_over_color[3] <= 0.0f) {
+ copy_v4_v4(output, input_color1);
}
- else if (value[0] == 1.0f && inputOverColor[3] >= 1.0f) {
- copy_v4_v4(output, inputOverColor);
+ else if (value[0] == 1.0f && input_over_color[3] >= 1.0f) {
+ copy_v4_v4(output, input_over_color);
}
else {
- float addfac = 1.0f - this->m_x + inputOverColor[3] * this->m_x;
+ float addfac = 1.0f - x_ + input_over_color[3] * x_;
float premul = value[0] * addfac;
- float mul = 1.0f - value[0] * inputOverColor[3];
+ float mul = 1.0f - value[0] * input_over_color[3];
- output[0] = (mul * inputColor1[0]) + premul * inputOverColor[0];
- output[1] = (mul * inputColor1[1]) + premul * inputOverColor[1];
- output[2] = (mul * inputColor1[2]) + premul * inputOverColor[2];
- output[3] = (mul * inputColor1[3]) + value[0] * inputOverColor[3];
+ output[0] = (mul * input_color1[0]) + premul * input_over_color[0];
+ output[1] = (mul * input_color1[1]) + premul * input_over_color[1];
+ output[2] = (mul * input_color1[2]) + premul * input_over_color[2];
+ output[3] = (mul * input_color1[3]) + value[0] * input_over_color[3];
}
}
@@ -71,7 +71,7 @@ void AlphaOverMixedOperation::update_memory_buffer_row(PixelCursor &p)
copy_v4_v4(p.out, over_color);
}
else {
- const float addfac = 1.0f - this->m_x + over_color[3] * this->m_x;
+ const float addfac = 1.0f - x_ + over_color[3] * x_;
const float premul = value * addfac;
const float mul = 1.0f - value * over_color[3];
diff --git a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h
index 2b88cd5f421..32ff77fdecd 100644
--- a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h
+++ b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h
@@ -28,7 +28,7 @@ namespace blender::compositor {
*/
class AlphaOverMixedOperation : public MixBaseOperation {
private:
- float m_x;
+ float x_;
public:
/**
@@ -39,11 +39,11 @@ class AlphaOverMixedOperation : public MixBaseOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void setX(float x)
{
- this->m_x = x;
+ x_ = x;
}
void update_memory_buffer_row(PixelCursor &p) override;
diff --git a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc
index 911e8d2df92..a627705fab5 100644
--- a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc
+++ b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc
@@ -22,36 +22,36 @@ namespace blender::compositor {
AlphaOverPremultiplyOperation::AlphaOverPremultiplyOperation()
{
- this->flags.can_be_constant = true;
+ flags_.can_be_constant = true;
}
-void AlphaOverPremultiplyOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void AlphaOverPremultiplyOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputOverColor[4];
+ float input_color1[4];
+ float input_over_color[4];
float value[4];
- this->m_inputValueOperation->readSampled(value, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputOverColor, x, y, sampler);
+ input_value_operation_->read_sampled(value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_over_color, x, y, sampler);
/* Zero alpha values should still permit an add of RGB data */
- if (inputOverColor[3] < 0.0f) {
- copy_v4_v4(output, inputColor1);
+ if (input_over_color[3] < 0.0f) {
+ copy_v4_v4(output, input_color1);
}
- else if (value[0] == 1.0f && inputOverColor[3] >= 1.0f) {
- copy_v4_v4(output, inputOverColor);
+ else if (value[0] == 1.0f && input_over_color[3] >= 1.0f) {
+ copy_v4_v4(output, input_over_color);
}
else {
- float mul = 1.0f - value[0] * inputOverColor[3];
+ float mul = 1.0f - value[0] * input_over_color[3];
- output[0] = (mul * inputColor1[0]) + value[0] * inputOverColor[0];
- output[1] = (mul * inputColor1[1]) + value[0] * inputOverColor[1];
- output[2] = (mul * inputColor1[2]) + value[0] * inputOverColor[2];
- output[3] = (mul * inputColor1[3]) + value[0] * inputOverColor[3];
+ output[0] = (mul * input_color1[0]) + value[0] * input_over_color[0];
+ output[1] = (mul * input_color1[1]) + value[0] * input_over_color[1];
+ output[2] = (mul * input_color1[2]) + value[0] * input_over_color[2];
+ output[3] = (mul * input_color1[3]) + value[0] * input_over_color[3];
}
}
diff --git a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h
index 701bc07cc27..cc4cb615de8 100644
--- a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h
+++ b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h
@@ -33,7 +33,7 @@ class AlphaOverPremultiplyOperation : public MixBaseOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_row(PixelCursor &p) override;
};
diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cc b/source/blender/compositor/operations/COM_AntiAliasOperation.cc
index deccbb28f49..2695e47aa60 100644
--- a/source/blender/compositor/operations/COM_AntiAliasOperation.cc
+++ b/source/blender/compositor/operations/COM_AntiAliasOperation.cc
@@ -17,12 +17,6 @@
*/
#include "COM_AntiAliasOperation.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "RE_texture.h"
namespace blender::compositor {
@@ -116,26 +110,26 @@ static int extrapolate9(float *E0,
AntiAliasOperation::AntiAliasOperation()
{
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
- this->m_valueReader = nullptr;
- this->flags.complex = true;
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
+ value_reader_ = nullptr;
+ flags_.complex = true;
}
-void AntiAliasOperation::initExecution()
+void AntiAliasOperation::init_execution()
{
- this->m_valueReader = this->getInputSocketReader(0);
+ value_reader_ = this->get_input_socket_reader(0);
}
-void AntiAliasOperation::executePixel(float output[4], int x, int y, void *data)
+void AntiAliasOperation::execute_pixel(float output[4], int x, int y, void *data)
{
MemoryBuffer *input_buffer = (MemoryBuffer *)data;
- const int buffer_width = input_buffer->getWidth(), buffer_height = input_buffer->getHeight();
+ const int buffer_width = input_buffer->get_width(), buffer_height = input_buffer->get_height();
if (y < 0 || y >= buffer_height || x < 0 || x >= buffer_width) {
output[0] = 0.0f;
}
else {
- const float *buffer = input_buffer->getBuffer();
+ const float *buffer = input_buffer->get_buffer();
const float *row_curr = &buffer[y * buffer_width];
if (x == 0 || x == buffer_width - 1 || y == 0 || y == buffer_height - 1) {
output[0] = row_curr[x];
@@ -179,27 +173,27 @@ void AntiAliasOperation::executePixel(float output[4], int x, int y, void *data)
}
}
-void AntiAliasOperation::deinitExecution()
+void AntiAliasOperation::deinit_execution()
{
- this->m_valueReader = nullptr;
+ value_reader_ = nullptr;
}
-bool AntiAliasOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool AntiAliasOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti imageInput;
- NodeOperation *operation = getInputOperation(0);
- imageInput.xmax = input->xmax + 1;
- imageInput.xmin = input->xmin - 1;
- imageInput.ymax = input->ymax + 1;
- imageInput.ymin = input->ymin - 1;
- return operation->determineDependingAreaOfInterest(&imageInput, readOperation, output);
+ rcti image_input;
+ NodeOperation *operation = get_input_operation(0);
+ image_input.xmax = input->xmax + 1;
+ image_input.xmin = input->xmin - 1;
+ image_input.ymax = input->ymax + 1;
+ image_input.ymin = input->ymin - 1;
+ return operation->determine_depending_area_of_interest(&image_input, read_operation, output);
}
-void *AntiAliasOperation::initializeTileData(rcti *rect)
+void *AntiAliasOperation::initialize_tile_data(rcti *rect)
{
- return getInputOperation(0)->initializeTileData(rect);
+ return get_input_operation(0)->initialize_tile_data(rect);
}
void AntiAliasOperation::get_area_of_interest(const int input_idx,
diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.h b/source/blender/compositor/operations/COM_AntiAliasOperation.h
index b5048248425..0a6a63bf57e 100644
--- a/source/blender/compositor/operations/COM_AntiAliasOperation.h
+++ b/source/blender/compositor/operations/COM_AntiAliasOperation.h
@@ -33,7 +33,7 @@ class AntiAliasOperation : public MultiThreadedOperation {
/**
* \brief Cached reference to the reader
*/
- SocketReader *m_valueReader;
+ SocketReader *value_reader_;
public:
AntiAliasOperation();
@@ -41,22 +41,22 @@ class AntiAliasOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ void deinit_execution() override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.cc b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc
index 44680c3acd1..32780ad4ea8 100644
--- a/source/blender/compositor/operations/COM_BilateralBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc
@@ -17,73 +17,70 @@
*/
#include "COM_BilateralBlurOperation.h"
-#include "BLI_math.h"
-
-#include "RE_pipeline.h"
namespace blender::compositor {
BilateralBlurOperation::BilateralBlurOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
- this->flags.complex = true;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ flags_.complex = true;
- this->m_inputColorProgram = nullptr;
- this->m_inputDeterminatorProgram = nullptr;
+ input_color_program_ = nullptr;
+ input_determinator_program_ = nullptr;
}
-void BilateralBlurOperation::initExecution()
+void BilateralBlurOperation::init_execution()
{
- this->m_inputColorProgram = getInputSocketReader(0);
- this->m_inputDeterminatorProgram = getInputSocketReader(1);
- QualityStepHelper::initExecution(COM_QH_INCREASE);
+ input_color_program_ = get_input_socket_reader(0);
+ input_determinator_program_ = get_input_socket_reader(1);
+ QualityStepHelper::init_execution(COM_QH_INCREASE);
}
-void BilateralBlurOperation::executePixel(float output[4], int x, int y, void *data)
+void BilateralBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
{
/* Read the determinator color at x, y,
* this will be used as the reference color for the determinator. */
- float determinatorReferenceColor[4];
+ float determinator_reference_color[4];
float determinator[4];
- float tempColor[4];
- float blurColor[4];
- float blurDivider;
- float space = this->m_space;
- float sigmacolor = this->m_data->sigma_color;
+ float temp_color[4];
+ float blur_color[4];
+ float blur_divider;
+ float space = space_;
+ float sigmacolor = data_->sigma_color;
int minx = floor(x - space);
int maxx = ceil(x + space);
int miny = floor(y - space);
int maxy = ceil(y + space);
- float deltaColor;
- this->m_inputDeterminatorProgram->read(determinatorReferenceColor, x, y, data);
+ float delta_color;
+ input_determinator_program_->read(determinator_reference_color, x, y, data);
- zero_v4(blurColor);
- blurDivider = 0.0f;
+ zero_v4(blur_color);
+ blur_divider = 0.0f;
/* TODO(sergey): This isn't really good bilateral filter, it should be
* using gaussian bell for weights. Also sigma_color doesn't seem to be
* used correct at all.
*/
- for (int yi = miny; yi < maxy; yi += QualityStepHelper::getStep()) {
- for (int xi = minx; xi < maxx; xi += QualityStepHelper::getStep()) {
+ for (int yi = miny; yi < maxy; yi += QualityStepHelper::get_step()) {
+ for (int xi = minx; xi < maxx; xi += QualityStepHelper::get_step()) {
/* Read determinator. */
- this->m_inputDeterminatorProgram->read(determinator, xi, yi, data);
- deltaColor = (fabsf(determinatorReferenceColor[0] - determinator[0]) +
- fabsf(determinatorReferenceColor[1] - determinator[1]) +
- /* Do not take the alpha channel into account. */
- fabsf(determinatorReferenceColor[2] - determinator[2]));
- if (deltaColor < sigmacolor) {
+ input_determinator_program_->read(determinator, xi, yi, data);
+ delta_color = (fabsf(determinator_reference_color[0] - determinator[0]) +
+ fabsf(determinator_reference_color[1] - determinator[1]) +
+ /* Do not take the alpha channel into account. */
+ fabsf(determinator_reference_color[2] - determinator[2]));
+ if (delta_color < sigmacolor) {
/* Add this to the blur. */
- this->m_inputColorProgram->read(tempColor, xi, yi, data);
- add_v4_v4(blurColor, tempColor);
- blurDivider += 1.0f;
+ input_color_program_->read(temp_color, xi, yi, data);
+ add_v4_v4(blur_color, temp_color);
+ blur_divider += 1.0f;
}
}
}
- if (blurDivider > 0.0f) {
- mul_v4_v4fl(output, blurColor, 1.0f / blurDivider);
+ if (blur_divider > 0.0f) {
+ mul_v4_v4fl(output, blur_color, 1.0f / blur_divider);
}
else {
output[0] = 0.0f;
@@ -93,32 +90,31 @@ void BilateralBlurOperation::executePixel(float output[4], int x, int y, void *d
}
}
-void BilateralBlurOperation::deinitExecution()
+void BilateralBlurOperation::deinit_execution()
{
- this->m_inputColorProgram = nullptr;
- this->m_inputDeterminatorProgram = nullptr;
+ input_color_program_ = nullptr;
+ input_determinator_program_ = nullptr;
}
-bool BilateralBlurOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool BilateralBlurOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
- int add = ceil(this->m_space) + 1;
+ rcti new_input;
+ int add = ceil(space_) + 1;
- newInput.xmax = input->xmax + (add);
- newInput.xmin = input->xmin - (add);
- newInput.ymax = input->ymax + (add);
- newInput.ymin = input->ymin - (add);
+ new_input.xmax = input->xmax + (add);
+ new_input.xmin = input->xmin - (add);
+ new_input.ymax = input->ymax + (add);
+ new_input.ymin = input->ymin - (add);
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void BilateralBlurOperation::get_area_of_interest(const int UNUSED(input_idx),
const rcti &output_area,
rcti &r_input_area)
{
- const int add = ceil(this->m_space) + 1;
+ const int add = ceil(space_) + 1;
r_input_area.xmax = output_area.xmax + (add);
r_input_area.xmin = output_area.xmin - (add);
@@ -176,11 +172,11 @@ void BilateralBlurOperation::update_memory_buffer_partial(MemoryBuffer *output,
Span<MemoryBuffer *> inputs)
{
PixelCursor p = {};
- p.step = QualityStepHelper::getStep();
- p.sigma_color = this->m_data->sigma_color;
+ p.step = QualityStepHelper::get_step();
+ p.sigma_color = data_->sigma_color;
p.input_color = inputs[0];
p.input_determinator = inputs[1];
- const float space = this->m_space;
+ const float space = space_;
for (int y = area.ymin; y < area.ymax; y++) {
p.out = output->get_elem(area.xmin, y);
/* This will be used as the reference color for the determinator. */
diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.h b/source/blender/compositor/operations/COM_BilateralBlurOperation.h
index 517c5292827..42df82a5296 100644
--- a/source/blender/compositor/operations/COM_BilateralBlurOperation.h
+++ b/source/blender/compositor/operations/COM_BilateralBlurOperation.h
@@ -25,10 +25,10 @@ namespace blender::compositor {
class BilateralBlurOperation : public MultiThreadedOperation, public QualityStepHelper {
private:
- SocketReader *m_inputColorProgram;
- SocketReader *m_inputDeterminatorProgram;
- NodeBilateralBlurData *m_data;
- float m_space;
+ SocketReader *input_color_program_;
+ SocketReader *input_determinator_program_;
+ NodeBilateralBlurData *data_;
+ float space_;
public:
BilateralBlurOperation();
@@ -36,26 +36,26 @@ class BilateralBlurOperation : public MultiThreadedOperation, public QualityStep
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void setData(NodeBilateralBlurData *data)
+ void set_data(NodeBilateralBlurData *data)
{
- this->m_data = data;
- this->m_space = data->sigma_space + data->iter;
+ data_ = data;
+ space_ = data->sigma_space + data->iter;
}
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cc b/source/blender/compositor/operations/COM_BlurBaseOperation.cc
index 412632e2e22..702733498c8 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.cc
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cc
@@ -19,9 +19,6 @@
#include "COM_BlurBaseOperation.h"
#include "COM_ConstantOperation.h"
-#include "BLI_math.h"
-#include "MEM_guardedalloc.h"
-
#include "RE_pipeline.h"
namespace blender::compositor {
@@ -29,52 +26,52 @@ namespace blender::compositor {
BlurBaseOperation::BlurBaseOperation(DataType data_type)
{
/* data_type is almost always DataType::Color except for alpha-blur */
- this->addInputSocket(data_type);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(data_type);
- this->flags.complex = true;
- this->m_inputProgram = nullptr;
- memset(&m_data, 0, sizeof(NodeBlurData));
- this->m_size = 1.0f;
- this->m_sizeavailable = false;
- this->m_extend_bounds = false;
+ this->add_input_socket(data_type);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(data_type);
+ flags_.complex = true;
+ input_program_ = nullptr;
+ memset(&data_, 0, sizeof(NodeBlurData));
+ size_ = 1.0f;
+ sizeavailable_ = false;
+ extend_bounds_ = false;
use_variable_size_ = false;
}
void BlurBaseOperation::init_data()
{
if (execution_model_ == eExecutionModel::FullFrame) {
- updateSize();
+ update_size();
}
- this->m_data.image_in_width = this->getWidth();
- this->m_data.image_in_height = this->getHeight();
- if (this->m_data.relative) {
+ data_.image_in_width = this->get_width();
+ data_.image_in_height = this->get_height();
+ if (data_.relative) {
int sizex, sizey;
- switch (this->m_data.aspect) {
+ switch (data_.aspect) {
case CMP_NODE_BLUR_ASPECT_Y:
- sizex = sizey = this->m_data.image_in_width;
+ sizex = sizey = data_.image_in_width;
break;
case CMP_NODE_BLUR_ASPECT_X:
- sizex = sizey = this->m_data.image_in_height;
+ sizex = sizey = data_.image_in_height;
break;
default:
- BLI_assert(this->m_data.aspect == CMP_NODE_BLUR_ASPECT_NONE);
- sizex = this->m_data.image_in_width;
- sizey = this->m_data.image_in_height;
+ BLI_assert(data_.aspect == CMP_NODE_BLUR_ASPECT_NONE);
+ sizex = data_.image_in_width;
+ sizey = data_.image_in_height;
break;
}
- this->m_data.sizex = round_fl_to_int(this->m_data.percentx * 0.01f * sizex);
- this->m_data.sizey = round_fl_to_int(this->m_data.percenty * 0.01f * sizey);
+ data_.sizex = round_fl_to_int(data_.percentx * 0.01f * sizex);
+ data_.sizey = round_fl_to_int(data_.percenty * 0.01f * sizey);
}
}
-void BlurBaseOperation::initExecution()
+void BlurBaseOperation::init_execution()
{
- this->m_inputProgram = this->getInputSocketReader(0);
- this->m_inputSize = this->getInputSocketReader(1);
+ input_program_ = this->get_input_socket_reader(0);
+ input_size_ = this->get_input_socket_reader(1);
- QualityStepHelper::initExecution(COM_QH_MULTIPLY);
+ QualityStepHelper::init_execution(COM_QH_MULTIPLY);
}
float *BlurBaseOperation::make_gausstab(float rad, int size)
@@ -89,7 +86,7 @@ float *BlurBaseOperation::make_gausstab(float rad, int size)
sum = 0.0f;
float fac = (rad > 0.0f ? 1.0f / rad : 0.0f);
for (i = -size; i <= size; i++) {
- val = RE_filter_value(this->m_data.filtertype, (float)i * fac);
+ val = RE_filter_value(data_.filtertype, (float)i * fac);
sum += val;
gausstab[i + size] = val;
}
@@ -114,8 +111,6 @@ __m128 *BlurBaseOperation::convert_gausstab_sse(const float *gausstab, int size)
}
#endif
-/* normalized distance from the current (inverted so 1.0 is close and 0.0 is far)
- * 'ease' is applied after, looks nicer */
float *BlurBaseOperation::make_dist_fac_inverse(float rad, int size, int falloff)
{
float *dist_fac_invert, val;
@@ -166,55 +161,55 @@ float *BlurBaseOperation::make_dist_fac_inverse(float rad, int size, int falloff
return dist_fac_invert;
}
-void BlurBaseOperation::deinitExecution()
+void BlurBaseOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
- this->m_inputSize = nullptr;
+ input_program_ = nullptr;
+ input_size_ = nullptr;
}
-void BlurBaseOperation::setData(const NodeBlurData *data)
+void BlurBaseOperation::set_data(const NodeBlurData *data)
{
- memcpy(&m_data, data, sizeof(NodeBlurData));
+ memcpy(&data_, data, sizeof(NodeBlurData));
}
int BlurBaseOperation::get_blur_size(eDimension dim) const
{
switch (dim) {
case eDimension::X:
- return m_data.sizex;
+ return data_.sizex;
case eDimension::Y:
- return m_data.sizey;
+ return data_.sizey;
}
return -1;
}
-void BlurBaseOperation::updateSize()
+void BlurBaseOperation::update_size()
{
- if (this->m_sizeavailable || use_variable_size_) {
+ if (sizeavailable_ || use_variable_size_) {
return;
}
switch (execution_model_) {
case eExecutionModel::Tiled: {
float result[4];
- this->getInputSocketReader(1)->readSampled(result, 0, 0, PixelSampler::Nearest);
- this->m_size = result[0];
+ this->get_input_socket_reader(1)->read_sampled(result, 0, 0, PixelSampler::Nearest);
+ size_ = result[0];
break;
}
case eExecutionModel::FullFrame: {
NodeOperation *size_input = get_input_operation(SIZE_INPUT_INDEX);
if (size_input->get_flags().is_constant_operation) {
- m_size = *static_cast<ConstantOperation *>(size_input)->get_constant_elem();
+ size_ = *static_cast<ConstantOperation *>(size_input)->get_constant_elem();
} /* Else use default. */
break;
}
}
- this->m_sizeavailable = true;
+ sizeavailable_ = true;
}
void BlurBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
- if (!m_extend_bounds) {
+ if (!extend_bounds_) {
NodeOperation::determine_canvas(preferred_area, r_area);
return;
}
@@ -222,8 +217,8 @@ void BlurBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_are
switch (execution_model_) {
case eExecutionModel::Tiled: {
NodeOperation::determine_canvas(preferred_area, r_area);
- r_area.xmax += 2 * m_size * m_data.sizex;
- r_area.ymax += 2 * m_size * m_data.sizey;
+ r_area.xmax += 2 * size_ * data_.sizex;
+ r_area.ymax += 2 * size_ * data_.sizey;
break;
}
case eExecutionModel::FullFrame: {
@@ -232,8 +227,8 @@ void BlurBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_are
* operations. */
set_determined_canvas_modifier([=](rcti &canvas) {
/* Rounding to even prevents jiggling in backdrop while switching size values. */
- canvas.xmax += round_to_even(2 * m_size * m_data.sizex);
- canvas.ymax += round_to_even(2 * m_size * m_data.sizey);
+ canvas.xmax += round_to_even(2 * size_ * data_.sizex);
+ canvas.ymax += round_to_even(2 * size_ * data_.sizey);
});
NodeOperation::determine_canvas(preferred_area, r_area);
break;
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.h b/source/blender/compositor/operations/COM_BlurBaseOperation.h
index 9ab9bf5a173..e12c5427082 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.h
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.h
@@ -29,7 +29,7 @@ namespace blender::compositor {
class BlurBaseOperation : public MultiThreadedOperation, public QualityStepHelper {
private:
- bool m_extend_bounds;
+ bool extend_bounds_;
protected:
static constexpr int IMAGE_INPUT_INDEX = 0;
@@ -41,19 +41,23 @@ class BlurBaseOperation : public MultiThreadedOperation, public QualityStepHelpe
#ifdef BLI_HAVE_SSE2
__m128 *convert_gausstab_sse(const float *gausstab, int size);
#endif
+ /**
+ * Normalized distance from the current (inverted so 1.0 is close and 0.0 is far)
+ * 'ease' is applied after, looks nicer.
+ */
float *make_dist_fac_inverse(float rad, int size, int falloff);
- void updateSize();
+ void update_size();
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
- SocketReader *m_inputSize;
- NodeBlurData m_data;
+ SocketReader *input_program_;
+ SocketReader *input_size_;
+ NodeBlurData data_;
- float m_size;
- bool m_sizeavailable;
+ float size_;
+ bool sizeavailable_;
/* Flags for inheriting classes. */
bool use_variable_size_;
@@ -63,24 +67,24 @@ class BlurBaseOperation : public MultiThreadedOperation, public QualityStepHelpe
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setData(const NodeBlurData *data);
+ void set_data(const NodeBlurData *data);
- void setSize(float size)
+ void set_size(float size)
{
- this->m_size = size;
- this->m_sizeavailable = true;
+ size_ = size;
+ sizeavailable_ = true;
}
- void setExtendBounds(bool extend_bounds)
+ void set_extend_bounds(bool extend_bounds)
{
- this->m_extend_bounds = extend_bounds;
+ extend_bounds_ = extend_bounds;
}
int get_blur_size(eDimension dim) const;
diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cc b/source/blender/compositor/operations/COM_BokehBlurOperation.cc
index 93482dd2a54..3c8dd94c094 100644
--- a/source/blender/compositor/operations/COM_BokehBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cc
@@ -19,11 +19,8 @@
#include "COM_BokehBlurOperation.h"
#include "COM_ConstantOperation.h"
-#include "BLI_math.h"
#include "COM_OpenCLDevice.h"
-#include "RE_pipeline.h"
-
namespace blender::compositor {
constexpr int IMAGE_INPUT_INDEX = 0;
@@ -33,109 +30,109 @@ constexpr int SIZE_INPUT_INDEX = 3;
BokehBlurOperation::BokehBlurOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Color, ResizeMode::Align);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
-
- flags.complex = true;
- flags.open_cl = true;
-
- this->m_size = 1.0f;
- this->m_sizeavailable = false;
- this->m_inputProgram = nullptr;
- this->m_inputBokehProgram = nullptr;
- this->m_inputBoundingBoxReader = nullptr;
-
- this->m_extend_bounds = false;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Color, ResizeMode::Align);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
+
+ flags_.complex = true;
+ flags_.open_cl = true;
+
+ size_ = 1.0f;
+ sizeavailable_ = false;
+ input_program_ = nullptr;
+ input_bokeh_program_ = nullptr;
+ input_bounding_box_reader_ = nullptr;
+
+ extend_bounds_ = false;
}
void BokehBlurOperation::init_data()
{
if (execution_model_ == eExecutionModel::FullFrame) {
- updateSize();
+ update_size();
}
NodeOperation *bokeh = get_input_operation(BOKEH_INPUT_INDEX);
- const int width = bokeh->getWidth();
- const int height = bokeh->getHeight();
+ const int width = bokeh->get_width();
+ const int height = bokeh->get_height();
const float dimension = MIN2(width, height);
- m_bokehMidX = width / 2.0f;
- m_bokehMidY = height / 2.0f;
- m_bokehDimension = dimension / 2.0f;
+ bokeh_mid_x_ = width / 2.0f;
+ bokeh_mid_y_ = height / 2.0f;
+ bokehDimension_ = dimension / 2.0f;
}
-void *BokehBlurOperation::initializeTileData(rcti * /*rect*/)
+void *BokehBlurOperation::initialize_tile_data(rcti * /*rect*/)
{
- lockMutex();
- if (!this->m_sizeavailable) {
- updateSize();
+ lock_mutex();
+ if (!sizeavailable_) {
+ update_size();
}
- void *buffer = getInputOperation(0)->initializeTileData(nullptr);
- unlockMutex();
+ void *buffer = get_input_operation(0)->initialize_tile_data(nullptr);
+ unlock_mutex();
return buffer;
}
-void BokehBlurOperation::initExecution()
+void BokehBlurOperation::init_execution()
{
- initMutex();
+ init_mutex();
- this->m_inputProgram = getInputSocketReader(0);
- this->m_inputBokehProgram = getInputSocketReader(1);
- this->m_inputBoundingBoxReader = getInputSocketReader(2);
+ input_program_ = get_input_socket_reader(0);
+ input_bokeh_program_ = get_input_socket_reader(1);
+ input_bounding_box_reader_ = get_input_socket_reader(2);
- QualityStepHelper::initExecution(COM_QH_INCREASE);
+ QualityStepHelper::init_execution(COM_QH_INCREASE);
}
-void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
+void BokehBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
{
float color_accum[4];
- float tempBoundingBox[4];
+ float temp_bounding_box[4];
float bokeh[4];
- this->m_inputBoundingBoxReader->readSampled(tempBoundingBox, x, y, PixelSampler::Nearest);
- if (tempBoundingBox[0] > 0.0f) {
+ input_bounding_box_reader_->read_sampled(temp_bounding_box, x, y, PixelSampler::Nearest);
+ if (temp_bounding_box[0] > 0.0f) {
float multiplier_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
- const rcti &input_rect = inputBuffer->get_rect();
- float *buffer = inputBuffer->getBuffer();
- int bufferwidth = inputBuffer->getWidth();
+ MemoryBuffer *input_buffer = (MemoryBuffer *)data;
+ const rcti &input_rect = input_buffer->get_rect();
+ float *buffer = input_buffer->get_buffer();
+ int bufferwidth = input_buffer->get_width();
int bufferstartx = input_rect.xmin;
int bufferstarty = input_rect.ymin;
- const float max_dim = MAX2(this->getWidth(), this->getHeight());
- int pixelSize = this->m_size * max_dim / 100.0f;
+ const float max_dim = MAX2(this->get_width(), this->get_height());
+ int pixel_size = size_ * max_dim / 100.0f;
zero_v4(color_accum);
- if (pixelSize < 2) {
- this->m_inputProgram->readSampled(color_accum, x, y, PixelSampler::Nearest);
+ if (pixel_size < 2) {
+ input_program_->read_sampled(color_accum, x, y, PixelSampler::Nearest);
multiplier_accum[0] = 1.0f;
multiplier_accum[1] = 1.0f;
multiplier_accum[2] = 1.0f;
multiplier_accum[3] = 1.0f;
}
- int miny = y - pixelSize;
- int maxy = y + pixelSize;
- int minx = x - pixelSize;
- int maxx = x + pixelSize;
+ int miny = y - pixel_size;
+ int maxy = y + pixel_size;
+ int minx = x - pixel_size;
+ int maxx = x + pixel_size;
miny = MAX2(miny, input_rect.ymin);
minx = MAX2(minx, input_rect.xmin);
maxy = MIN2(maxy, input_rect.ymax);
maxx = MIN2(maxx, input_rect.xmax);
- int step = getStep();
- int offsetadd = getOffsetAdd() * COM_DATA_TYPE_COLOR_CHANNELS;
+ int step = get_step();
+ int offsetadd = get_offset_add() * COM_DATA_TYPE_COLOR_CHANNELS;
- float m = this->m_bokehDimension / pixelSize;
+ float m = bokehDimension_ / pixel_size;
for (int ny = miny; ny < maxy; ny += step) {
int bufferindex = ((minx - bufferstartx) * COM_DATA_TYPE_COLOR_CHANNELS) +
((ny - bufferstarty) * COM_DATA_TYPE_COLOR_CHANNELS * bufferwidth);
for (int nx = minx; nx < maxx; nx += step) {
- float u = this->m_bokehMidX - (nx - x) * m;
- float v = this->m_bokehMidY - (ny - y) * m;
- this->m_inputBokehProgram->readSampled(bokeh, u, v, PixelSampler::Nearest);
+ float u = bokeh_mid_x_ - (nx - x) * m;
+ float v = bokeh_mid_y_ - (ny - y) * m;
+ input_bokeh_program_->read_sampled(bokeh, u, v, PixelSampler::Nearest);
madd_v4_v4v4(color_accum, bokeh, &buffer[bufferindex]);
add_v4_v4(multiplier_accum, bokeh);
bufferindex += offsetadd;
@@ -147,128 +144,128 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
output[3] = color_accum[3] * (1.0f / multiplier_accum[3]);
}
else {
- this->m_inputProgram->readSampled(output, x, y, PixelSampler::Nearest);
+ input_program_->read_sampled(output, x, y, PixelSampler::Nearest);
}
}
-void BokehBlurOperation::deinitExecution()
+void BokehBlurOperation::deinit_execution()
{
- deinitMutex();
- this->m_inputProgram = nullptr;
- this->m_inputBokehProgram = nullptr;
- this->m_inputBoundingBoxReader = nullptr;
+ deinit_mutex();
+ input_program_ = nullptr;
+ input_bokeh_program_ = nullptr;
+ input_bounding_box_reader_ = nullptr;
}
-bool BokehBlurOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool BokehBlurOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti newInput;
- rcti bokehInput;
- const float max_dim = MAX2(this->getWidth(), this->getHeight());
-
- if (this->m_sizeavailable) {
- newInput.xmax = input->xmax + (this->m_size * max_dim / 100.0f);
- newInput.xmin = input->xmin - (this->m_size * max_dim / 100.0f);
- newInput.ymax = input->ymax + (this->m_size * max_dim / 100.0f);
- newInput.ymin = input->ymin - (this->m_size * max_dim / 100.0f);
+ rcti new_input;
+ rcti bokeh_input;
+ const float max_dim = MAX2(this->get_width(), this->get_height());
+
+ if (sizeavailable_) {
+ new_input.xmax = input->xmax + (size_ * max_dim / 100.0f);
+ new_input.xmin = input->xmin - (size_ * max_dim / 100.0f);
+ new_input.ymax = input->ymax + (size_ * max_dim / 100.0f);
+ new_input.ymin = input->ymin - (size_ * max_dim / 100.0f);
}
else {
- newInput.xmax = input->xmax + (10.0f * max_dim / 100.0f);
- newInput.xmin = input->xmin - (10.0f * max_dim / 100.0f);
- newInput.ymax = input->ymax + (10.0f * max_dim / 100.0f);
- newInput.ymin = input->ymin - (10.0f * max_dim / 100.0f);
+ new_input.xmax = input->xmax + (10.0f * max_dim / 100.0f);
+ new_input.xmin = input->xmin - (10.0f * max_dim / 100.0f);
+ new_input.ymax = input->ymax + (10.0f * max_dim / 100.0f);
+ new_input.ymin = input->ymin - (10.0f * max_dim / 100.0f);
}
- NodeOperation *operation = getInputOperation(1);
- bokehInput.xmax = operation->getWidth();
- bokehInput.xmin = 0;
- bokehInput.ymax = operation->getHeight();
- bokehInput.ymin = 0;
- if (operation->determineDependingAreaOfInterest(&bokehInput, readOperation, output)) {
+ NodeOperation *operation = get_input_operation(1);
+ bokeh_input.xmax = operation->get_width();
+ bokeh_input.xmin = 0;
+ bokeh_input.ymax = operation->get_height();
+ bokeh_input.ymin = 0;
+ if (operation->determine_depending_area_of_interest(&bokeh_input, read_operation, output)) {
return true;
}
- operation = getInputOperation(0);
- if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) {
+ operation = get_input_operation(0);
+ if (operation->determine_depending_area_of_interest(&new_input, read_operation, output)) {
return true;
}
- operation = getInputOperation(2);
- if (operation->determineDependingAreaOfInterest(input, readOperation, output)) {
+ operation = get_input_operation(2);
+ if (operation->determine_depending_area_of_interest(input, read_operation, output)) {
return true;
}
- if (!this->m_sizeavailable) {
- rcti sizeInput;
- sizeInput.xmin = 0;
- sizeInput.ymin = 0;
- sizeInput.xmax = 5;
- sizeInput.ymax = 5;
- operation = getInputOperation(3);
- if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
+ if (!sizeavailable_) {
+ rcti size_input;
+ size_input.xmin = 0;
+ size_input.ymin = 0;
+ size_input.xmax = 5;
+ size_input.ymax = 5;
+ operation = get_input_operation(3);
+ if (operation->determine_depending_area_of_interest(&size_input, read_operation, output)) {
return true;
}
}
return false;
}
-void BokehBlurOperation::executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer,
- cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers,
- std::list<cl_mem> *clMemToCleanUp,
- std::list<cl_kernel> * /*clKernelsToCleanUp*/)
+void BokehBlurOperation::execute_opencl(OpenCLDevice *device,
+ MemoryBuffer *output_memory_buffer,
+ cl_mem cl_output_buffer,
+ MemoryBuffer **input_memory_buffers,
+ std::list<cl_mem> *cl_mem_to_clean_up,
+ std::list<cl_kernel> * /*cl_kernels_to_clean_up*/)
{
- cl_kernel kernel = device->COM_clCreateKernel("bokehBlurKernel", nullptr);
- if (!this->m_sizeavailable) {
- updateSize();
+ cl_kernel kernel = device->COM_cl_create_kernel("bokeh_blur_kernel", nullptr);
+ if (!sizeavailable_) {
+ update_size();
}
- const float max_dim = MAX2(this->getWidth(), this->getHeight());
- cl_int radius = this->m_size * max_dim / 100.0f;
- cl_int step = this->getStep();
-
- device->COM_clAttachMemoryBufferToKernelParameter(
- kernel, 0, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputBoundingBoxReader);
- device->COM_clAttachMemoryBufferToKernelParameter(
- kernel, 1, 4, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram);
- device->COM_clAttachMemoryBufferToKernelParameter(
- kernel, 2, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputBokehProgram);
- device->COM_clAttachOutputMemoryBufferToKernelParameter(kernel, 3, clOutputBuffer);
- device->COM_clAttachMemoryBufferOffsetToKernelParameter(kernel, 5, outputMemoryBuffer);
+ const float max_dim = MAX2(this->get_width(), this->get_height());
+ cl_int radius = size_ * max_dim / 100.0f;
+ cl_int step = this->get_step();
+
+ device->COM_cl_attach_memory_buffer_to_kernel_parameter(
+ kernel, 0, -1, cl_mem_to_clean_up, input_memory_buffers, input_bounding_box_reader_);
+ device->COM_cl_attach_memory_buffer_to_kernel_parameter(
+ kernel, 1, 4, cl_mem_to_clean_up, input_memory_buffers, input_program_);
+ device->COM_cl_attach_memory_buffer_to_kernel_parameter(
+ kernel, 2, -1, cl_mem_to_clean_up, input_memory_buffers, input_bokeh_program_);
+ device->COM_cl_attach_output_memory_buffer_to_kernel_parameter(kernel, 3, cl_output_buffer);
+ device->COM_cl_attach_memory_buffer_offset_to_kernel_parameter(kernel, 5, output_memory_buffer);
clSetKernelArg(kernel, 6, sizeof(cl_int), &radius);
clSetKernelArg(kernel, 7, sizeof(cl_int), &step);
- device->COM_clAttachSizeToKernelParameter(kernel, 8, this);
+ device->COM_cl_attach_size_to_kernel_parameter(kernel, 8, this);
- device->COM_clEnqueueRange(kernel, outputMemoryBuffer, 9, this);
+ device->COM_cl_enqueue_range(kernel, output_memory_buffer, 9, this);
}
-void BokehBlurOperation::updateSize()
+void BokehBlurOperation::update_size()
{
- if (this->m_sizeavailable) {
+ if (sizeavailable_) {
return;
}
switch (execution_model_) {
case eExecutionModel::Tiled: {
float result[4];
- this->getInputSocketReader(3)->readSampled(result, 0, 0, PixelSampler::Nearest);
- this->m_size = result[0];
- CLAMP(this->m_size, 0.0f, 10.0f);
+ this->get_input_socket_reader(3)->read_sampled(result, 0, 0, PixelSampler::Nearest);
+ size_ = result[0];
+ CLAMP(size_, 0.0f, 10.0f);
break;
}
case eExecutionModel::FullFrame: {
NodeOperation *size_input = get_input_operation(SIZE_INPUT_INDEX);
if (size_input->get_flags().is_constant_operation) {
- m_size = *static_cast<ConstantOperation *>(size_input)->get_constant_elem();
- CLAMP(m_size, 0.0f, 10.0f);
+ size_ = *static_cast<ConstantOperation *>(size_input)->get_constant_elem();
+ CLAMP(size_, 0.0f, 10.0f);
} /* Else use default. */
break;
}
}
- this->m_sizeavailable = true;
+ sizeavailable_ = true;
}
void BokehBlurOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
- if (!m_extend_bounds) {
+ if (!extend_bounds_) {
NodeOperation::determine_canvas(preferred_area, r_area);
return;
}
@@ -277,15 +274,15 @@ void BokehBlurOperation::determine_canvas(const rcti &preferred_area, rcti &r_ar
case eExecutionModel::Tiled: {
NodeOperation::determine_canvas(preferred_area, r_area);
const float max_dim = MAX2(BLI_rcti_size_x(&r_area), BLI_rcti_size_y(&r_area));
- r_area.xmax += 2 * this->m_size * max_dim / 100.0f;
- r_area.ymax += 2 * this->m_size * max_dim / 100.0f;
+ r_area.xmax += 2 * size_ * max_dim / 100.0f;
+ r_area.ymax += 2 * size_ * max_dim / 100.0f;
break;
}
case eExecutionModel::FullFrame: {
set_determined_canvas_modifier([=](rcti &canvas) {
const float max_dim = MAX2(BLI_rcti_size_x(&canvas), BLI_rcti_size_y(&canvas));
/* Rounding to even prevents image jiggling in backdrop while switching size values. */
- float add_size = round_to_even(2 * this->m_size * max_dim / 100.0f);
+ float add_size = round_to_even(2 * size_ * max_dim / 100.0f);
canvas.xmax += add_size;
canvas.ymax += add_size;
});
@@ -301,8 +298,8 @@ void BokehBlurOperation::get_area_of_interest(const int input_idx,
{
switch (input_idx) {
case IMAGE_INPUT_INDEX: {
- const float max_dim = MAX2(this->getWidth(), this->getHeight());
- const float add_size = m_size * max_dim / 100.0f;
+ const float max_dim = MAX2(this->get_width(), this->get_height());
+ const float add_size = size_ * max_dim / 100.0f;
r_input_area.xmin = output_area.xmin - add_size;
r_input_area.xmax = output_area.xmax + add_size;
r_input_area.ymin = output_area.ymin - add_size;
@@ -310,7 +307,7 @@ void BokehBlurOperation::get_area_of_interest(const int input_idx,
break;
}
case BOKEH_INPUT_INDEX: {
- NodeOperation *bokeh_input = getInputOperation(BOKEH_INPUT_INDEX);
+ NodeOperation *bokeh_input = get_input_operation(BOKEH_INPUT_INDEX);
r_input_area = bokeh_input->get_canvas();
break;
}
@@ -328,9 +325,9 @@ void BokehBlurOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- const float max_dim = MAX2(this->getWidth(), this->getHeight());
- const int pixel_size = m_size * max_dim / 100.0f;
- const float m = m_bokehDimension / pixel_size;
+ const float max_dim = MAX2(this->get_width(), this->get_height());
+ const int pixel_size = size_ * max_dim / 100.0f;
+ const float m = bokehDimension_ / pixel_size;
const MemoryBuffer *image_input = inputs[IMAGE_INPUT_INDEX];
const MemoryBuffer *bokeh_input = inputs[BOKEH_INPUT_INDEX];
@@ -359,15 +356,15 @@ void BokehBlurOperation::update_memory_buffer_partial(MemoryBuffer *output,
const int maxy = MIN2(y + pixel_size, image_rect.ymax);
const int minx = MAX2(x - pixel_size, image_rect.xmin);
const int maxx = MIN2(x + pixel_size, image_rect.xmax);
- const int step = getStep();
+ const int step = get_step();
const int elem_stride = image_input->elem_stride * step;
const int row_stride = image_input->row_stride * step;
const float *row_color = image_input->get_elem(minx, miny);
for (int ny = miny; ny < maxy; ny += step, row_color += row_stride) {
const float *color = row_color;
- const float v = m_bokehMidY - (ny - y) * m;
+ const float v = bokeh_mid_y_ - (ny - y) * m;
for (int nx = minx; nx < maxx; nx += step, color += elem_stride) {
- const float u = m_bokehMidX - (nx - x) * m;
+ const float u = bokeh_mid_x_ - (nx - x) * m;
float bokeh[4];
bokeh_input->read_elem_checked(u, v, bokeh);
madd_v4_v4v4(color_accum, bokeh, color);
diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.h b/source/blender/compositor/operations/COM_BokehBlurOperation.h
index 84f5a8293ba..5f6a880f890 100644
--- a/source/blender/compositor/operations/COM_BokehBlurOperation.h
+++ b/source/blender/compositor/operations/COM_BokehBlurOperation.h
@@ -25,59 +25,59 @@ namespace blender::compositor {
class BokehBlurOperation : public MultiThreadedOperation, public QualityStepHelper {
private:
- SocketReader *m_inputProgram;
- SocketReader *m_inputBokehProgram;
- SocketReader *m_inputBoundingBoxReader;
- void updateSize();
- float m_size;
- bool m_sizeavailable;
-
- float m_bokehMidX;
- float m_bokehMidY;
- float m_bokehDimension;
- bool m_extend_bounds;
+ SocketReader *input_program_;
+ SocketReader *input_bokeh_program_;
+ SocketReader *input_bounding_box_reader_;
+ void update_size();
+ float size_;
+ bool sizeavailable_;
+
+ float bokeh_mid_x_;
+ float bokeh_mid_y_;
+ float bokehDimension_;
+ bool extend_bounds_;
public:
BokehBlurOperation();
void init_data() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void setSize(float size)
+ void set_size(float size)
{
- this->m_size = size;
- this->m_sizeavailable = true;
+ size_ = size;
+ sizeavailable_ = true;
}
- void executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer,
- cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers,
- std::list<cl_mem> *clMemToCleanUp,
- std::list<cl_kernel> *clKernelsToCleanUp) override;
+ void execute_opencl(OpenCLDevice *device,
+ MemoryBuffer *output_memory_buffer,
+ cl_mem cl_output_buffer,
+ MemoryBuffer **input_memory_buffers,
+ std::list<cl_mem> *cl_mem_to_clean_up,
+ std::list<cl_kernel> *cl_kernels_to_clean_up) override;
- void setExtendBounds(bool extend_bounds)
+ void set_extend_bounds(bool extend_bounds)
{
- this->m_extend_bounds = extend_bounds;
+ extend_bounds_ = extend_bounds;
}
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.cc b/source/blender/compositor/operations/COM_BokehImageOperation.cc
index 5c9c8b36ee0..9e7c1162052 100644
--- a/source/blender/compositor/operations/COM_BokehImageOperation.cc
+++ b/source/blender/compositor/operations/COM_BokehImageOperation.cc
@@ -17,130 +17,130 @@
*/
#include "COM_BokehImageOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
BokehImageOperation::BokehImageOperation()
{
- this->addOutputSocket(DataType::Color);
- this->m_deleteData = false;
+ this->add_output_socket(DataType::Color);
+ delete_data_ = false;
}
-void BokehImageOperation::initExecution()
+void BokehImageOperation::init_execution()
{
- this->m_center[0] = getWidth() / 2;
- this->m_center[1] = getHeight() / 2;
- this->m_inverseRounding = 1.0f - this->m_data->rounding;
- this->m_circularDistance = getWidth() / 2;
- this->m_flapRad = (float)(M_PI * 2) / this->m_data->flaps;
- this->m_flapRadAdd = this->m_data->angle;
- while (this->m_flapRadAdd < 0.0f) {
- this->m_flapRadAdd += (float)(M_PI * 2.0);
+ center_[0] = get_width() / 2;
+ center_[1] = get_height() / 2;
+ inverse_rounding_ = 1.0f - data_->rounding;
+ circular_distance_ = get_width() / 2;
+ flap_rad_ = (float)(M_PI * 2) / data_->flaps;
+ flap_rad_add_ = data_->angle;
+ while (flap_rad_add_ < 0.0f) {
+ flap_rad_add_ += (float)(M_PI * 2.0);
}
- while (this->m_flapRadAdd > (float)M_PI) {
- this->m_flapRadAdd -= (float)(M_PI * 2.0);
+ while (flap_rad_add_ > (float)M_PI) {
+ flap_rad_add_ -= (float)(M_PI * 2.0);
}
}
-void BokehImageOperation::detemineStartPointOfFlap(float r[2], int flapNumber, float distance)
+void BokehImageOperation::detemine_start_point_of_flap(float r[2], int flap_number, float distance)
{
- r[0] = sinf(this->m_flapRad * flapNumber + this->m_flapRadAdd) * distance + this->m_center[0];
- r[1] = cosf(this->m_flapRad * flapNumber + this->m_flapRadAdd) * distance + this->m_center[1];
+ r[0] = sinf(flap_rad_ * flap_number + flap_rad_add_) * distance + center_[0];
+ r[1] = cosf(flap_rad_ * flap_number + flap_rad_add_) * distance + center_[1];
}
-float BokehImageOperation::isInsideBokeh(float distance, float x, float y)
+float BokehImageOperation::is_inside_bokeh(float distance, float x, float y)
{
- float insideBokeh = 0.0f;
- const float deltaX = x - this->m_center[0];
- const float deltaY = y - this->m_center[1];
- float closestPoint[2];
- float lineP1[2];
- float lineP2[2];
+ float inside_bokeh = 0.0f;
+ const float deltaX = x - center_[0];
+ const float deltaY = y - center_[1];
+ float closest_point[2];
+ float line_p1[2];
+ float line_p2[2];
float point[2];
point[0] = x;
point[1] = y;
- const float distanceToCenter = len_v2v2(point, this->m_center);
+ const float distance_to_center = len_v2v2(point, center_);
const float bearing = (atan2f(deltaX, deltaY) + (float)(M_PI * 2.0));
- int flapNumber = (int)((bearing - this->m_flapRadAdd) / this->m_flapRad);
+ int flap_number = (int)((bearing - flap_rad_add_) / flap_rad_);
- detemineStartPointOfFlap(lineP1, flapNumber, distance);
- detemineStartPointOfFlap(lineP2, flapNumber + 1, distance);
- closest_to_line_v2(closestPoint, point, lineP1, lineP2);
+ detemine_start_point_of_flap(line_p1, flap_number, distance);
+ detemine_start_point_of_flap(line_p2, flap_number + 1, distance);
+ closest_to_line_v2(closest_point, point, line_p1, line_p2);
- const float distanceLineToCenter = len_v2v2(this->m_center, closestPoint);
- const float distanceRoundingToCenter = this->m_inverseRounding * distanceLineToCenter +
- this->m_data->rounding * distance;
+ const float distance_line_to_center = len_v2v2(center_, closest_point);
+ const float distance_rounding_to_center = inverse_rounding_ * distance_line_to_center +
+ data_->rounding * distance;
- const float catadioptricDistanceToCenter = distanceRoundingToCenter * this->m_data->catadioptric;
- if (distanceRoundingToCenter >= distanceToCenter &&
- catadioptricDistanceToCenter <= distanceToCenter) {
- if (distanceRoundingToCenter - distanceToCenter < 1.0f) {
- insideBokeh = (distanceRoundingToCenter - distanceToCenter);
+ const float catadioptric_distance_to_center = distance_rounding_to_center * data_->catadioptric;
+ if (distance_rounding_to_center >= distance_to_center &&
+ catadioptric_distance_to_center <= distance_to_center) {
+ if (distance_rounding_to_center - distance_to_center < 1.0f) {
+ inside_bokeh = (distance_rounding_to_center - distance_to_center);
}
- else if (this->m_data->catadioptric != 0.0f &&
- distanceToCenter - catadioptricDistanceToCenter < 1.0f) {
- insideBokeh = (distanceToCenter - catadioptricDistanceToCenter);
+ else if (data_->catadioptric != 0.0f &&
+ distance_to_center - catadioptric_distance_to_center < 1.0f) {
+ inside_bokeh = (distance_to_center - catadioptric_distance_to_center);
}
else {
- insideBokeh = 1.0f;
+ inside_bokeh = 1.0f;
}
}
- return insideBokeh;
+ return inside_bokeh;
}
-void BokehImageOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler /*sampler*/)
+void BokehImageOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
- float shift = this->m_data->lensshift;
+ float shift = data_->lensshift;
float shift2 = shift / 2.0f;
- float distance = this->m_circularDistance;
- float insideBokehMax = isInsideBokeh(distance, x, y);
- float insideBokehMed = isInsideBokeh(distance - fabsf(shift2 * distance), x, y);
- float insideBokehMin = isInsideBokeh(distance - fabsf(shift * distance), x, y);
+ float distance = circular_distance_;
+ float inside_bokeh_max = is_inside_bokeh(distance, x, y);
+ float inside_bokeh_med = is_inside_bokeh(distance - fabsf(shift2 * distance), x, y);
+ float inside_bokeh_min = is_inside_bokeh(distance - fabsf(shift * distance), x, y);
if (shift < 0) {
- output[0] = insideBokehMax;
- output[1] = insideBokehMed;
- output[2] = insideBokehMin;
+ output[0] = inside_bokeh_max;
+ output[1] = inside_bokeh_med;
+ output[2] = inside_bokeh_min;
}
else {
- output[0] = insideBokehMin;
- output[1] = insideBokehMed;
- output[2] = insideBokehMax;
+ output[0] = inside_bokeh_min;
+ output[1] = inside_bokeh_med;
+ output[2] = inside_bokeh_max;
}
- output[3] = (insideBokehMax + insideBokehMed + insideBokehMin) / 3.0f;
+ output[3] = (inside_bokeh_max + inside_bokeh_med + inside_bokeh_min) / 3.0f;
}
void BokehImageOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> UNUSED(inputs))
{
- const float shift = this->m_data->lensshift;
+ const float shift = data_->lensshift;
const float shift2 = shift / 2.0f;
- const float distance = this->m_circularDistance;
+ const float distance = circular_distance_;
for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
- const float insideBokehMax = isInsideBokeh(distance, it.x, it.y);
- const float insideBokehMed = isInsideBokeh(distance - fabsf(shift2 * distance), it.x, it.y);
- const float insideBokehMin = isInsideBokeh(distance - fabsf(shift * distance), it.x, it.y);
+ const float inside_bokeh_max = is_inside_bokeh(distance, it.x, it.y);
+ const float inside_bokeh_med = is_inside_bokeh(
+ distance - fabsf(shift2 * distance), it.x, it.y);
+ const float inside_bokeh_min = is_inside_bokeh(distance - fabsf(shift * distance), it.x, it.y);
if (shift < 0) {
- it.out[0] = insideBokehMax;
- it.out[1] = insideBokehMed;
- it.out[2] = insideBokehMin;
+ it.out[0] = inside_bokeh_max;
+ it.out[1] = inside_bokeh_med;
+ it.out[2] = inside_bokeh_min;
}
else {
- it.out[0] = insideBokehMin;
- it.out[1] = insideBokehMed;
- it.out[2] = insideBokehMax;
+ it.out[0] = inside_bokeh_min;
+ it.out[1] = inside_bokeh_med;
+ it.out[2] = inside_bokeh_max;
}
- it.out[3] = (insideBokehMax + insideBokehMed + insideBokehMin) / 3.0f;
+ it.out[3] = (inside_bokeh_max + inside_bokeh_med + inside_bokeh_min) / 3.0f;
}
}
-void BokehImageOperation::deinitExecution()
+void BokehImageOperation::deinit_execution()
{
- if (this->m_deleteData) {
- if (this->m_data) {
- delete this->m_data;
- this->m_data = nullptr;
+ if (delete_data_) {
+ if (data_) {
+ delete data_;
+ data_ = nullptr;
}
}
}
diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.h b/source/blender/compositor/operations/COM_BokehImageOperation.h
index f7fec5d71a5..6c7818724b3 100644
--- a/source/blender/compositor/operations/COM_BokehImageOperation.h
+++ b/source/blender/compositor/operations/COM_BokehImageOperation.h
@@ -54,46 +54,46 @@ class BokehImageOperation : public MultiThreadedOperation {
/**
* \brief Settings of the bokeh image
*/
- NodeBokehImage *m_data;
+ NodeBokehImage *data_;
/**
* \brief precalculate center of the image
*/
- float m_center[2];
+ float center_[2];
/**
* \brief 1.0-rounding
*/
- float m_inverseRounding;
+ float inverse_rounding_;
/**
* \brief distance of a full circle lens
*/
- float m_circularDistance;
+ float circular_distance_;
/**
* \brief radius when the first flap starts
*/
- float m_flapRad;
+ float flap_rad_;
/**
* \brief radians of a single flap
*/
- float m_flapRadAdd;
+ float flap_rad_add_;
/**
- * \brief should the m_data field by deleted when this operation is finished
+ * \brief should the data_ field by deleted when this operation is finished
*/
- bool m_deleteData;
+ bool delete_data_;
/**
* \brief determine the coordinate of a flap corner.
*
* \param r: result in bokeh-image space are stored [x,y]
- * \param flapNumber: the flap number to calculate
+ * \param flap_number: the flap number to calculate
* \param distance: the lens distance is used to simulate lens shifts
*/
- void detemineStartPointOfFlap(float r[2], int flapNumber, float distance);
+ void detemine_start_point_of_flap(float r[2], int flap_number, float distance);
/**
* \brief Determine if a coordinate is inside the bokeh image
@@ -104,7 +104,7 @@ class BokehImageOperation : public MultiThreadedOperation {
* \param y: the y coordinate of the pixel to evaluate
* \return float range 0..1 0 is completely outside
*/
- float isInsideBokeh(float distance, float x, float y);
+ float is_inside_bokeh(float distance, float x, float y);
public:
BokehImageOperation();
@@ -112,21 +112,21 @@ class BokehImageOperation : public MultiThreadedOperation {
/**
* \brief The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* \brief Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* \brief Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
/**
* \brief determine the resolution of this operation. currently fixed at [COM_BLUR_BOKEH_PIXELS,
- * COM_BLUR_BOKEH_PIXELS] \param resolution: \param preferredResolution:
+ * COM_BLUR_BOKEH_PIXELS] \param resolution: \param preferred_resolution:
*/
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
@@ -134,21 +134,21 @@ class BokehImageOperation : public MultiThreadedOperation {
* \brief set the node data
* \param data:
*/
- void setData(NodeBokehImage *data)
+ void set_data(NodeBokehImage *data)
{
- this->m_data = data;
+ data_ = data;
}
/**
- * \brief deleteDataOnFinish
+ * \brief delete_data_on_finish
*
* There are cases that the compositor uses this operation on its own (see defocus node)
- * the deleteDataOnFinish must only be called when the data has been created by the compositor.
- *It should not be called when the data has been created by the node-editor/user.
+ * the delete_data_on_finish must only be called when the data has been created by the
+ *compositor. It should not be called when the data has been created by the node-editor/user.
*/
- void deleteDataOnFinish()
+ void delete_data_on_finish()
{
- this->m_deleteData = true;
+ delete_data_ = true;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_BoxMaskOperation.cc b/source/blender/compositor/operations/COM_BoxMaskOperation.cc
index 15bb19660dc..c79179a3e0a 100644
--- a/source/blender/compositor/operations/COM_BoxMaskOperation.cc
+++ b/source/blender/compositor/operations/COM_BoxMaskOperation.cc
@@ -17,73 +17,74 @@
*/
#include "COM_BoxMaskOperation.h"
-#include "BLI_math.h"
-#include "DNA_node_types.h"
namespace blender::compositor {
BoxMaskOperation::BoxMaskOperation()
{
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
- this->m_inputMask = nullptr;
- this->m_inputValue = nullptr;
- this->m_cosine = 0.0f;
- this->m_sine = 0.0f;
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
+ input_mask_ = nullptr;
+ input_value_ = nullptr;
+ cosine_ = 0.0f;
+ sine_ = 0.0f;
}
-void BoxMaskOperation::initExecution()
+void BoxMaskOperation::init_execution()
{
- this->m_inputMask = this->getInputSocketReader(0);
- this->m_inputValue = this->getInputSocketReader(1);
- const double rad = (double)this->m_data->rotation;
- this->m_cosine = cos(rad);
- this->m_sine = sin(rad);
- this->m_aspectRatio = ((float)this->getWidth()) / this->getHeight();
+ input_mask_ = this->get_input_socket_reader(0);
+ input_value_ = this->get_input_socket_reader(1);
+ const double rad = (double)data_->rotation;
+ cosine_ = cos(rad);
+ sine_ = sin(rad);
+ aspect_ratio_ = ((float)this->get_width()) / this->get_height();
}
-void BoxMaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void BoxMaskOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputMask[4];
- float inputValue[4];
+ float input_mask[4];
+ float input_value[4];
- float rx = x / this->getWidth();
- float ry = y / this->getHeight();
+ float rx = x / MAX2(this->get_width() - 1.0f, FLT_EPSILON);
+ float ry = y / MAX2(this->get_height() - 1.0f, FLT_EPSILON);
- const float dy = (ry - this->m_data->y) / this->m_aspectRatio;
- const float dx = rx - this->m_data->x;
- rx = this->m_data->x + (this->m_cosine * dx + this->m_sine * dy);
- ry = this->m_data->y + (-this->m_sine * dx + this->m_cosine * dy);
+ const float dy = (ry - data_->y) / aspect_ratio_;
+ const float dx = rx - data_->x;
+ rx = data_->x + (cosine_ * dx + sine_ * dy);
+ ry = data_->y + (-sine_ * dx + cosine_ * dy);
- this->m_inputMask->readSampled(inputMask, x, y, sampler);
- this->m_inputValue->readSampled(inputValue, x, y, sampler);
+ input_mask_->read_sampled(input_mask, x, y, sampler);
+ input_value_->read_sampled(input_value, x, y, sampler);
- float halfHeight = this->m_data->height / 2.0f;
- float halfWidth = this->m_data->width / 2.0f;
- bool inside = (rx > this->m_data->x - halfWidth && rx < this->m_data->x + halfWidth &&
- ry > this->m_data->y - halfHeight && ry < this->m_data->y + halfHeight);
+ float half_height = data_->height / 2.0f + FLT_EPSILON;
+ float half_width = data_->width / 2.0f + FLT_EPSILON;
+ bool inside = (rx >= data_->x - half_width && rx <= data_->x + half_width &&
+ ry >= data_->y - half_height && ry <= data_->y + half_height);
- switch (this->m_maskType) {
+ switch (mask_type_) {
case CMP_NODE_MASKTYPE_ADD:
if (inside) {
- output[0] = MAX2(inputMask[0], inputValue[0]);
+ output[0] = MAX2(input_mask[0], input_value[0]);
}
else {
- output[0] = inputMask[0];
+ output[0] = input_mask[0];
}
break;
case CMP_NODE_MASKTYPE_SUBTRACT:
if (inside) {
- output[0] = inputMask[0] - inputValue[0];
+ output[0] = input_mask[0] - input_value[0];
CLAMP(output[0], 0, 1);
}
else {
- output[0] = inputMask[0];
+ output[0] = input_mask[0];
}
break;
case CMP_NODE_MASKTYPE_MULTIPLY:
if (inside) {
- output[0] = inputMask[0] * inputValue[0];
+ output[0] = input_mask[0] * input_value[0];
}
else {
output[0] = 0;
@@ -91,15 +92,15 @@ void BoxMaskOperation::executePixelSampled(float output[4], float x, float y, Pi
break;
case CMP_NODE_MASKTYPE_NOT:
if (inside) {
- if (inputMask[0] > 0.0f) {
+ if (input_mask[0] > 0.0f) {
output[0] = 0;
}
else {
- output[0] = inputValue[0];
+ output[0] = input_value[0];
}
}
else {
- output[0] = inputMask[0];
+ output[0] = input_mask[0];
}
break;
}
@@ -110,7 +111,7 @@ void BoxMaskOperation::update_memory_buffer_partial(MemoryBuffer *output,
Span<MemoryBuffer *> inputs)
{
MaskFunc mask_func;
- switch (m_maskType) {
+ switch (mask_type_) {
case CMP_NODE_MASKTYPE_ADD:
mask_func = [](const bool is_inside, const float *mask, const float *value) {
return is_inside ? MAX2(mask[0], value[0]) : mask[0];
@@ -143,30 +144,30 @@ void BoxMaskOperation::apply_mask(MemoryBuffer *output,
Span<MemoryBuffer *> inputs,
MaskFunc mask_func)
{
- const float op_w = this->getWidth();
- const float op_h = this->getHeight();
- const float half_w = this->m_data->width / 2.0f;
- const float half_h = this->m_data->height / 2.0f;
+ const float op_last_x = MAX2(this->get_width() - 1.0f, FLT_EPSILON);
+ const float op_last_y = MAX2(this->get_height() - 1.0f, FLT_EPSILON);
+ const float half_w = data_->width / 2.0f + FLT_EPSILON;
+ const float half_h = data_->height / 2.0f + FLT_EPSILON;
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
- const float op_ry = it.y / op_h;
- const float dy = (op_ry - this->m_data->y) / m_aspectRatio;
- const float op_rx = it.x / op_w;
- const float dx = op_rx - this->m_data->x;
- const float rx = this->m_data->x + (m_cosine * dx + m_sine * dy);
- const float ry = this->m_data->y + (-m_sine * dx + m_cosine * dy);
+ const float op_ry = it.y / op_last_y;
+ const float dy = (op_ry - data_->y) / aspect_ratio_;
+ const float op_rx = it.x / op_last_x;
+ const float dx = op_rx - data_->x;
+ const float rx = data_->x + (cosine_ * dx + sine_ * dy);
+ const float ry = data_->y + (-sine_ * dx + cosine_ * dy);
- const bool inside = (rx > this->m_data->x - half_w && rx < this->m_data->x + half_w &&
- ry > this->m_data->y - half_h && ry < this->m_data->y + half_h);
+ const bool inside = (rx >= data_->x - half_w && rx <= data_->x + half_w &&
+ ry >= data_->y - half_h && ry <= data_->y + half_h);
const float *mask = it.in(0);
const float *value = it.in(1);
*it.out = mask_func(inside, mask, value);
}
}
-void BoxMaskOperation::deinitExecution()
+void BoxMaskOperation::deinit_execution()
{
- this->m_inputMask = nullptr;
- this->m_inputValue = nullptr;
+ input_mask_ = nullptr;
+ input_value_ = nullptr;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_BoxMaskOperation.h b/source/blender/compositor/operations/COM_BoxMaskOperation.h
index 4c48dde844a..4aee88556ee 100644
--- a/source/blender/compositor/operations/COM_BoxMaskOperation.h
+++ b/source/blender/compositor/operations/COM_BoxMaskOperation.h
@@ -27,17 +27,17 @@ class BoxMaskOperation : public MultiThreadedOperation {
using MaskFunc = std::function<float(bool is_inside, const float *mask, const float *value)>;
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputMask;
- SocketReader *m_inputValue;
+ SocketReader *input_mask_;
+ SocketReader *input_value_;
- float m_sine;
- float m_cosine;
- float m_aspectRatio;
- int m_maskType;
+ float sine_;
+ float cosine_;
+ float aspect_ratio_;
+ int mask_type_;
- NodeBoxMask *m_data;
+ NodeBoxMask *data_;
public:
BoxMaskOperation();
@@ -45,26 +45,26 @@ class BoxMaskOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setData(NodeBoxMask *data)
+ void set_data(NodeBoxMask *data)
{
- this->m_data = data;
+ data_ = data;
}
- void setMaskType(int maskType)
+ void set_mask_type(int mask_type)
{
- this->m_maskType = maskType;
+ mask_type_ = mask_type;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.cc b/source/blender/compositor/operations/COM_BrightnessOperation.cc
index 7878eca2bbd..cebcc14b13a 100644
--- a/source/blender/compositor/operations/COM_BrightnessOperation.cc
+++ b/source/blender/compositor/operations/COM_BrightnessOperation.cc
@@ -22,41 +22,41 @@ namespace blender::compositor {
BrightnessOperation::BrightnessOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
- this->m_inputProgram = nullptr;
- this->m_use_premultiply = false;
- flags.can_be_constant = true;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
+ input_program_ = nullptr;
+ use_premultiply_ = false;
+ flags_.can_be_constant = true;
}
-void BrightnessOperation::setUsePremultiply(bool use_premultiply)
+void BrightnessOperation::set_use_premultiply(bool use_premultiply)
{
- this->m_use_premultiply = use_premultiply;
+ use_premultiply_ = use_premultiply;
}
-void BrightnessOperation::initExecution()
+void BrightnessOperation::init_execution()
{
- this->m_inputProgram = this->getInputSocketReader(0);
- this->m_inputBrightnessProgram = this->getInputSocketReader(1);
- this->m_inputContrastProgram = this->getInputSocketReader(2);
+ input_program_ = this->get_input_socket_reader(0);
+ input_brightness_program_ = this->get_input_socket_reader(1);
+ input_contrast_program_ = this->get_input_socket_reader(2);
}
-void BrightnessOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void BrightnessOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue[4];
+ float input_value[4];
float a, b;
- float inputBrightness[4];
- float inputContrast[4];
- this->m_inputProgram->readSampled(inputValue, x, y, sampler);
- this->m_inputBrightnessProgram->readSampled(inputBrightness, x, y, sampler);
- this->m_inputContrastProgram->readSampled(inputContrast, x, y, sampler);
- float brightness = inputBrightness[0];
- float contrast = inputContrast[0];
+ float input_brightness[4];
+ float input_contrast[4];
+ input_program_->read_sampled(input_value, x, y, sampler);
+ input_brightness_program_->read_sampled(input_brightness, x, y, sampler);
+ input_contrast_program_->read_sampled(input_contrast, x, y, sampler);
+ float brightness = input_brightness[0];
+ float contrast = input_contrast[0];
brightness /= 100.0f;
float delta = contrast / 200.0f;
/*
@@ -74,14 +74,14 @@ void BrightnessOperation::executePixelSampled(float output[4],
a = max_ff(1.0f - delta * 2.0f, 0.0f);
b = a * brightness + delta;
}
- if (this->m_use_premultiply) {
- premul_to_straight_v4(inputValue);
+ if (use_premultiply_) {
+ premul_to_straight_v4(input_value);
}
- output[0] = a * inputValue[0] + b;
- output[1] = a * inputValue[1] + b;
- output[2] = a * inputValue[2] + b;
- output[3] = inputValue[3];
- if (this->m_use_premultiply) {
+ output[0] = a * input_value[0] + b;
+ output[1] = a * input_value[1] + b;
+ output[2] = a * input_value[2] + b;
+ output[3] = input_value[3];
+ if (use_premultiply_) {
straight_to_premul_v4(output);
}
}
@@ -113,7 +113,7 @@ void BrightnessOperation::update_memory_buffer_partial(MemoryBuffer *output,
b = a * brightness + delta;
}
const float *color;
- if (this->m_use_premultiply) {
+ if (use_premultiply_) {
premul_to_straight_v4_v4(tmp_color, in_color);
color = tmp_color;
}
@@ -124,17 +124,17 @@ void BrightnessOperation::update_memory_buffer_partial(MemoryBuffer *output,
it.out[1] = a * color[1] + b;
it.out[2] = a * color[2] + b;
it.out[3] = color[3];
- if (this->m_use_premultiply) {
+ if (use_premultiply_) {
straight_to_premul_v4(it.out);
}
}
}
-void BrightnessOperation::deinitExecution()
+void BrightnessOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
- this->m_inputBrightnessProgram = nullptr;
- this->m_inputContrastProgram = nullptr;
+ input_program_ = nullptr;
+ input_brightness_program_ = nullptr;
+ input_contrast_program_ = nullptr;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.h b/source/blender/compositor/operations/COM_BrightnessOperation.h
index 64b4fa0dbe2..003baa96613 100644
--- a/source/blender/compositor/operations/COM_BrightnessOperation.h
+++ b/source/blender/compositor/operations/COM_BrightnessOperation.h
@@ -25,13 +25,13 @@ namespace blender::compositor {
class BrightnessOperation : public MultiThreadedOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
- SocketReader *m_inputBrightnessProgram;
- SocketReader *m_inputContrastProgram;
+ SocketReader *input_program_;
+ SocketReader *input_brightness_program_;
+ SocketReader *input_contrast_program_;
- bool m_use_premultiply;
+ bool use_premultiply_;
public:
BrightnessOperation();
@@ -39,19 +39,19 @@ class BrightnessOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setUsePremultiply(bool use_premultiply);
+ void set_use_premultiply(bool use_premultiply);
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_CalculateMeanOperation.cc b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc
index a573a9d7eed..b8d85675041 100644
--- a/source/blender/compositor/operations/COM_CalculateMeanOperation.cc
+++ b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc
@@ -17,8 +17,7 @@
*/
#include "COM_CalculateMeanOperation.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
+
#include "COM_ExecutionSystem.h"
#include "IMB_colormanagement.h"
@@ -27,74 +26,73 @@ namespace blender::compositor {
CalculateMeanOperation::CalculateMeanOperation()
{
- this->addInputSocket(DataType::Color, ResizeMode::Align);
- this->addOutputSocket(DataType::Value);
- this->m_imageReader = nullptr;
- this->m_iscalculated = false;
- this->m_setting = 1;
- this->flags.complex = true;
+ this->add_input_socket(DataType::Color, ResizeMode::Align);
+ this->add_output_socket(DataType::Value);
+ image_reader_ = nullptr;
+ iscalculated_ = false;
+ setting_ = 1;
+ flags_.complex = true;
}
-void CalculateMeanOperation::initExecution()
+void CalculateMeanOperation::init_execution()
{
- this->m_imageReader = this->getInputSocketReader(0);
- this->m_iscalculated = false;
- NodeOperation::initMutex();
+ image_reader_ = this->get_input_socket_reader(0);
+ iscalculated_ = false;
+ NodeOperation::init_mutex();
}
-void CalculateMeanOperation::executePixel(float output[4], int /*x*/, int /*y*/, void * /*data*/)
+void CalculateMeanOperation::execute_pixel(float output[4], int /*x*/, int /*y*/, void * /*data*/)
{
- output[0] = this->m_result;
+ output[0] = result_;
}
-void CalculateMeanOperation::deinitExecution()
+void CalculateMeanOperation::deinit_execution()
{
- this->m_imageReader = nullptr;
- NodeOperation::deinitMutex();
+ image_reader_ = nullptr;
+ NodeOperation::deinit_mutex();
}
-bool CalculateMeanOperation::determineDependingAreaOfInterest(rcti * /*input*/,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool CalculateMeanOperation::determine_depending_area_of_interest(
+ rcti * /*input*/, ReadBufferOperation *read_operation, rcti *output)
{
- rcti imageInput;
- if (this->m_iscalculated) {
+ rcti image_input;
+ if (iscalculated_) {
return false;
}
- NodeOperation *operation = getInputOperation(0);
- imageInput.xmax = operation->getWidth();
- imageInput.xmin = 0;
- imageInput.ymax = operation->getHeight();
- imageInput.ymin = 0;
- if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output)) {
+ NodeOperation *operation = get_input_operation(0);
+ image_input.xmax = operation->get_width();
+ image_input.xmin = 0;
+ image_input.ymax = operation->get_height();
+ image_input.ymin = 0;
+ if (operation->determine_depending_area_of_interest(&image_input, read_operation, output)) {
return true;
}
return false;
}
-void *CalculateMeanOperation::initializeTileData(rcti *rect)
+void *CalculateMeanOperation::initialize_tile_data(rcti *rect)
{
- lockMutex();
- if (!this->m_iscalculated) {
- MemoryBuffer *tile = (MemoryBuffer *)this->m_imageReader->initializeTileData(rect);
- calculateMean(tile);
- this->m_iscalculated = true;
+ lock_mutex();
+ if (!iscalculated_) {
+ MemoryBuffer *tile = (MemoryBuffer *)image_reader_->initialize_tile_data(rect);
+ calculate_mean(tile);
+ iscalculated_ = true;
}
- unlockMutex();
+ unlock_mutex();
return nullptr;
}
-void CalculateMeanOperation::calculateMean(MemoryBuffer *tile)
+void CalculateMeanOperation::calculate_mean(MemoryBuffer *tile)
{
- this->m_result = 0.0f;
- float *buffer = tile->getBuffer();
- int size = tile->getWidth() * tile->getHeight();
+ result_ = 0.0f;
+ float *buffer = tile->get_buffer();
+ int size = tile->get_width() * tile->get_height();
int pixels = 0;
float sum = 0.0f;
for (int i = 0, offset = 0; i < size; i++, offset += 4) {
if (buffer[offset + 3] > 0) {
pixels++;
- switch (this->m_setting) {
+ switch (setting_) {
case 1: {
sum += IMB_colormanagement_get_luminance(&buffer[offset]);
break;
@@ -126,12 +124,12 @@ void CalculateMeanOperation::calculateMean(MemoryBuffer *tile)
}
}
}
- this->m_result = sum / pixels;
+ result_ = sum / pixels;
}
-void CalculateMeanOperation::setSetting(int setting)
+void CalculateMeanOperation::set_setting(int setting)
{
- this->m_setting = setting;
+ setting_ = setting;
switch (setting) {
case 1: {
setting_func_ = IMB_colormanagement_get_luminance;
@@ -172,10 +170,10 @@ void CalculateMeanOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(o
const rcti &UNUSED(area),
Span<MemoryBuffer *> inputs)
{
- if (!this->m_iscalculated) {
+ if (!iscalculated_) {
MemoryBuffer *input = inputs[0];
- m_result = calc_mean(input);
- this->m_iscalculated = true;
+ result_ = calc_mean(input);
+ iscalculated_ = true;
}
}
@@ -183,7 +181,7 @@ void CalculateMeanOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> UNUSED(inputs))
{
- output->fill(area, &m_result);
+ output->fill(area, &result_);
}
float CalculateMeanOperation::calc_mean(const MemoryBuffer *input)
diff --git a/source/blender/compositor/operations/COM_CalculateMeanOperation.h b/source/blender/compositor/operations/COM_CalculateMeanOperation.h
index 779ca79b38a..7c4fafb2f27 100644
--- a/source/blender/compositor/operations/COM_CalculateMeanOperation.h
+++ b/source/blender/compositor/operations/COM_CalculateMeanOperation.h
@@ -39,11 +39,11 @@ class CalculateMeanOperation : public MultiThreadedOperation {
/**
* \brief Cached reference to the reader
*/
- SocketReader *m_imageReader;
+ SocketReader *image_reader_;
- bool m_iscalculated;
- float m_result;
- int m_setting;
+ bool iscalculated_;
+ float result_;
+ int setting_;
std::function<float(const float *elem)> setting_func_;
public:
@@ -52,24 +52,24 @@ class CalculateMeanOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
- void setSetting(int setting);
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
+ void set_setting(int setting);
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
@@ -82,7 +82,7 @@ class CalculateMeanOperation : public MultiThreadedOperation {
Span<MemoryBuffer *> inputs) override;
protected:
- void calculateMean(MemoryBuffer *tile);
+ void calculate_mean(MemoryBuffer *tile);
float calc_mean(const MemoryBuffer *input);
private:
diff --git a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc
index 494b66cb888..06b3114845e 100644
--- a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc
+++ b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc
@@ -17,39 +17,38 @@
*/
#include "COM_CalculateStandardDeviationOperation.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
+
#include "COM_ExecutionSystem.h"
#include "IMB_colormanagement.h"
namespace blender::compositor {
-void CalculateStandardDeviationOperation::executePixel(float output[4],
- int /*x*/,
- int /*y*/,
- void * /*data*/)
+void CalculateStandardDeviationOperation::execute_pixel(float output[4],
+ int /*x*/,
+ int /*y*/,
+ void * /*data*/)
{
- output[0] = this->m_standardDeviation;
+ output[0] = standard_deviation_;
}
-void *CalculateStandardDeviationOperation::initializeTileData(rcti *rect)
+void *CalculateStandardDeviationOperation::initialize_tile_data(rcti *rect)
{
- lockMutex();
- if (!this->m_iscalculated) {
- MemoryBuffer *tile = (MemoryBuffer *)this->m_imageReader->initializeTileData(rect);
- CalculateMeanOperation::calculateMean(tile);
- this->m_standardDeviation = 0.0f;
- float *buffer = tile->getBuffer();
- int size = tile->getWidth() * tile->getHeight();
+ lock_mutex();
+ if (!iscalculated_) {
+ MemoryBuffer *tile = (MemoryBuffer *)image_reader_->initialize_tile_data(rect);
+ CalculateMeanOperation::calculate_mean(tile);
+ standard_deviation_ = 0.0f;
+ float *buffer = tile->get_buffer();
+ int size = tile->get_width() * tile->get_height();
int pixels = 0;
float sum = 0.0f;
- float mean = this->m_result;
+ float mean = result_;
for (int i = 0, offset = 0; i < size; i++, offset += 4) {
if (buffer[offset + 3] > 0) {
pixels++;
- switch (this->m_setting) {
+ switch (setting_) {
case 1: /* rgb combined */
{
float value = IMB_colormanagement_get_luminance(&buffer[offset]);
@@ -90,17 +89,17 @@ void *CalculateStandardDeviationOperation::initializeTileData(rcti *rect)
}
}
}
- this->m_standardDeviation = sqrt(sum / (float)(pixels - 1));
- this->m_iscalculated = true;
+ standard_deviation_ = sqrt(sum / (float)(pixels - 1));
+ iscalculated_ = true;
}
- unlockMutex();
+ unlock_mutex();
return nullptr;
}
void CalculateStandardDeviationOperation::update_memory_buffer_started(
MemoryBuffer *UNUSED(output), const rcti &UNUSED(area), Span<MemoryBuffer *> inputs)
{
- if (!this->m_iscalculated) {
+ if (!iscalculated_) {
const MemoryBuffer *input = inputs[0];
const float mean = CalculateMeanOperation::calc_mean(input);
@@ -113,17 +112,16 @@ void CalculateStandardDeviationOperation::update_memory_buffer_started(
join.sum += chunk.sum;
join.num_pixels += chunk.num_pixels;
});
- this->m_standardDeviation = total.num_pixels <= 1 ?
- 0.0f :
- sqrt(total.sum / (float)(total.num_pixels - 1));
- this->m_iscalculated = true;
+ standard_deviation_ = total.num_pixels <= 1 ? 0.0f :
+ sqrt(total.sum / (float)(total.num_pixels - 1));
+ iscalculated_ = true;
}
}
void CalculateStandardDeviationOperation::update_memory_buffer_partial(
MemoryBuffer *output, const rcti &area, Span<MemoryBuffer *> UNUSED(inputs))
{
- output->fill(area, &m_standardDeviation);
+ output->fill(area, &standard_deviation_);
}
using PixelsSum = CalculateMeanOperation::PixelsSum;
diff --git a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.h b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.h
index 20de4cf4701..95b9eb21982 100644
--- a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.h
+++ b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.h
@@ -31,15 +31,15 @@ namespace blender::compositor {
*/
class CalculateStandardDeviationOperation : public CalculateMeanOperation {
protected:
- float m_standardDeviation;
+ float standard_deviation_;
public:
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
void update_memory_buffer_started(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.cc b/source/blender/compositor/operations/COM_ChangeHSVOperation.cc
index 1e3e7806968..7c64b1954d4 100644
--- a/source/blender/compositor/operations/COM_ChangeHSVOperation.cc
+++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.cc
@@ -22,54 +22,54 @@ namespace blender::compositor {
ChangeHSVOperation::ChangeHSVOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
- this->m_inputOperation = nullptr;
- this->flags.can_be_constant = true;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
+ input_operation_ = nullptr;
+ flags_.can_be_constant = true;
}
-void ChangeHSVOperation::initExecution()
+void ChangeHSVOperation::init_execution()
{
- this->m_inputOperation = getInputSocketReader(0);
- this->m_hueOperation = getInputSocketReader(1);
- this->m_saturationOperation = getInputSocketReader(2);
- this->m_valueOperation = getInputSocketReader(3);
+ input_operation_ = get_input_socket_reader(0);
+ hue_operation_ = get_input_socket_reader(1);
+ saturation_operation_ = get_input_socket_reader(2);
+ value_operation_ = get_input_socket_reader(3);
}
-void ChangeHSVOperation::deinitExecution()
+void ChangeHSVOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
- this->m_hueOperation = nullptr;
- this->m_saturationOperation = nullptr;
- this->m_valueOperation = nullptr;
+ input_operation_ = nullptr;
+ hue_operation_ = nullptr;
+ saturation_operation_ = nullptr;
+ value_operation_ = nullptr;
}
-void ChangeHSVOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ChangeHSVOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
+ float input_color1[4];
float hue[4], saturation[4], value[4];
- this->m_inputOperation->readSampled(inputColor1, x, y, sampler);
- this->m_hueOperation->readSampled(hue, x, y, sampler);
- this->m_saturationOperation->readSampled(saturation, x, y, sampler);
- this->m_valueOperation->readSampled(value, x, y, sampler);
+ input_operation_->read_sampled(input_color1, x, y, sampler);
+ hue_operation_->read_sampled(hue, x, y, sampler);
+ saturation_operation_->read_sampled(saturation, x, y, sampler);
+ value_operation_->read_sampled(value, x, y, sampler);
- output[0] = inputColor1[0] + (hue[0] - 0.5f);
+ output[0] = input_color1[0] + (hue[0] - 0.5f);
if (output[0] > 1.0f) {
output[0] -= 1.0f;
}
else if (output[0] < 0.0f) {
output[0] += 1.0f;
}
- output[1] = inputColor1[1] * saturation[0];
- output[2] = inputColor1[2] * value[0];
- output[3] = inputColor1[3];
+ output[1] = input_color1[1] * saturation[0];
+ output[2] = input_color1[2] * value[0];
+ output[3] = input_color1[3];
}
void ChangeHSVOperation::update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.h b/source/blender/compositor/operations/COM_ChangeHSVOperation.h
index e7bc3274f25..35e606f63df 100644
--- a/source/blender/compositor/operations/COM_ChangeHSVOperation.h
+++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.h
@@ -28,10 +28,10 @@ namespace blender::compositor {
*/
class ChangeHSVOperation : public MultiThreadedOperation {
private:
- SocketReader *m_inputOperation;
- SocketReader *m_hueOperation;
- SocketReader *m_saturationOperation;
- SocketReader *m_valueOperation;
+ SocketReader *input_operation_;
+ SocketReader *hue_operation_;
+ SocketReader *saturation_operation_;
+ SocketReader *value_operation_;
public:
/**
@@ -39,13 +39,13 @@ class ChangeHSVOperation : public MultiThreadedOperation {
*/
ChangeHSVOperation();
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.cc b/source/blender/compositor/operations/COM_ChannelMatteOperation.cc
index 65742d0cfcc..af20193118c 100644
--- a/source/blender/compositor/operations/COM_ChannelMatteOperation.cc
+++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.cc
@@ -17,55 +17,54 @@
*/
#include "COM_ChannelMatteOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
ChannelMatteOperation::ChannelMatteOperation()
{
- addInputSocket(DataType::Color);
- addOutputSocket(DataType::Value);
+ add_input_socket(DataType::Color);
+ add_output_socket(DataType::Value);
- this->m_inputImageProgram = nullptr;
- flags.can_be_constant = true;
+ input_image_program_ = nullptr;
+ flags_.can_be_constant = true;
}
-void ChannelMatteOperation::initExecution()
+void ChannelMatteOperation::init_execution()
{
- this->m_inputImageProgram = this->getInputSocketReader(0);
+ input_image_program_ = this->get_input_socket_reader(0);
- this->m_limit_range = this->m_limit_max - this->m_limit_min;
+ limit_range_ = limit_max_ - limit_min_;
- switch (this->m_limit_method) {
+ switch (limit_method_) {
/* SINGLE */
case 0: {
/* 123 / RGB / HSV / YUV / YCC */
- const int matte_channel = this->m_matte_channel - 1;
- const int limit_channel = this->m_limit_channel - 1;
- this->m_ids[0] = matte_channel;
- this->m_ids[1] = limit_channel;
- this->m_ids[2] = limit_channel;
+ const int matte_channel = matte_channel_ - 1;
+ const int limit_channel = limit_channel_ - 1;
+ ids_[0] = matte_channel;
+ ids_[1] = limit_channel;
+ ids_[2] = limit_channel;
break;
}
/* MAX */
case 1: {
- switch (this->m_matte_channel) {
+ switch (matte_channel_) {
case 1: {
- this->m_ids[0] = 0;
- this->m_ids[1] = 1;
- this->m_ids[2] = 2;
+ ids_[0] = 0;
+ ids_[1] = 1;
+ ids_[2] = 2;
break;
}
case 2: {
- this->m_ids[0] = 1;
- this->m_ids[1] = 0;
- this->m_ids[2] = 2;
+ ids_[0] = 1;
+ ids_[1] = 0;
+ ids_[2] = 2;
break;
}
case 3: {
- this->m_ids[0] = 2;
- this->m_ids[1] = 0;
- this->m_ids[2] = 1;
+ ids_[0] = 2;
+ ids_[1] = 0;
+ ids_[2] = 1;
break;
}
default:
@@ -78,34 +77,34 @@ void ChannelMatteOperation::initExecution()
}
}
-void ChannelMatteOperation::deinitExecution()
+void ChannelMatteOperation::deinit_execution()
{
- this->m_inputImageProgram = nullptr;
+ input_image_program_ = nullptr;
}
-void ChannelMatteOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ChannelMatteOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inColor[4];
+ float in_color[4];
float alpha;
- const float limit_max = this->m_limit_max;
- const float limit_min = this->m_limit_min;
- const float limit_range = this->m_limit_range;
+ const float limit_max = limit_max_;
+ const float limit_min = limit_min_;
+ const float limit_range = limit_range_;
- this->m_inputImageProgram->readSampled(inColor, x, y, sampler);
+ input_image_program_->read_sampled(in_color, x, y, sampler);
/* matte operation */
- alpha = inColor[this->m_ids[0]] - MAX2(inColor[this->m_ids[1]], inColor[this->m_ids[2]]);
+ alpha = in_color[ids_[0]] - MAX2(in_color[ids_[1]], in_color[ids_[2]]);
/* flip because 0.0 is transparent, not 1.0 */
alpha = 1.0f - alpha;
/* test range */
if (alpha > limit_max) {
- alpha = inColor[3]; /* Whatever it was prior. */
+ alpha = in_color[3]; /* Whatever it was prior. */
}
else if (alpha < limit_min) {
alpha = 0.0f;
@@ -119,7 +118,7 @@ void ChannelMatteOperation::executePixelSampled(float output[4],
*/
/* Don't make something that was more transparent less transparent. */
- output[0] = MIN2(alpha, inColor[3]);
+ output[0] = MIN2(alpha, in_color[3]);
}
void ChannelMatteOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -130,20 +129,20 @@ void ChannelMatteOperation::update_memory_buffer_partial(MemoryBuffer *output,
const float *color = it.in(0);
/* Matte operation. */
- float alpha = color[this->m_ids[0]] - MAX2(color[this->m_ids[1]], color[this->m_ids[2]]);
+ float alpha = color[ids_[0]] - MAX2(color[ids_[1]], color[ids_[2]]);
/* Flip because 0.0 is transparent, not 1.0. */
alpha = 1.0f - alpha;
/* Test range. */
- if (alpha > m_limit_max) {
+ if (alpha > limit_max_) {
alpha = color[3]; /* Whatever it was prior. */
}
- else if (alpha < m_limit_min) {
+ else if (alpha < limit_min_) {
alpha = 0.0f;
}
else { /* Blend. */
- alpha = (alpha - m_limit_min) / m_limit_range;
+ alpha = (alpha - limit_min_) / limit_range_;
}
/* Store matte(alpha) value in [0] to go with
diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.h b/source/blender/compositor/operations/COM_ChannelMatteOperation.h
index ba50105dd3b..64b173885d5 100644
--- a/source/blender/compositor/operations/COM_ChannelMatteOperation.h
+++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.h
@@ -28,16 +28,16 @@ namespace blender::compositor {
*/
class ChannelMatteOperation : public MultiThreadedOperation {
private:
- SocketReader *m_inputImageProgram;
+ SocketReader *input_image_program_;
- /* int m_color_space; */ /* node->custom1 */ /* UNUSED */ /* TODO ? */
- int m_matte_channel; /* node->custom2 */
- int m_limit_method; /* node->algorithm */
- int m_limit_channel; /* node->channel */
- float m_limit_max; /* node->storage->t1 */
- float m_limit_min; /* node->storage->t2 */
+ /* int color_space_; */ /* node->custom1 */ /* UNUSED */ /* TODO ? */
+ int matte_channel_; /* node->custom2 */
+ int limit_method_; /* node->algorithm */
+ int limit_channel_; /* node->channel */
+ float limit_max_; /* node->storage->t1 */
+ float limit_min_; /* node->storage->t2 */
- float m_limit_range;
+ float limit_range_;
/** ids to use for the operations (max and simple)
* alpha = in[ids[0]] - MAX2(in[ids[1]], in[ids[2]])
@@ -47,7 +47,7 @@ class ChannelMatteOperation : public MultiThreadedOperation {
* ids[2] = ids[1]
* alpha = in[ids[0]] - MAX2(in[ids[1]], in[ids[2]])
*/
- int m_ids[3];
+ int ids_[3];
public:
/**
@@ -58,18 +58,18 @@ class ChannelMatteOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void setSettings(NodeChroma *nodeChroma, const int custom2)
+ void set_settings(NodeChroma *node_chroma, const int custom2)
{
- this->m_limit_max = nodeChroma->t1;
- this->m_limit_min = nodeChroma->t2;
- this->m_limit_method = nodeChroma->algorithm;
- this->m_limit_channel = nodeChroma->channel;
- this->m_matte_channel = custom2;
+ limit_max_ = node_chroma->t1;
+ limit_min_ = node_chroma->t2;
+ limit_method_ = node_chroma->algorithm;
+ limit_channel_ = node_chroma->channel;
+ matte_channel_ = custom2;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_ChromaMatteOperation.cc b/source/blender/compositor/operations/COM_ChromaMatteOperation.cc
index 0784f266b19..d0fc65ef331 100644
--- a/source/blender/compositor/operations/COM_ChromaMatteOperation.cc
+++ b/source/blender/compositor/operations/COM_ChromaMatteOperation.cc
@@ -17,51 +17,50 @@
*/
#include "COM_ChromaMatteOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
ChromaMatteOperation::ChromaMatteOperation()
{
- addInputSocket(DataType::Color);
- addInputSocket(DataType::Color);
- addOutputSocket(DataType::Value);
+ add_input_socket(DataType::Color);
+ add_input_socket(DataType::Color);
+ add_output_socket(DataType::Value);
- this->m_inputImageProgram = nullptr;
- this->m_inputKeyProgram = nullptr;
- flags.can_be_constant = true;
+ input_image_program_ = nullptr;
+ input_key_program_ = nullptr;
+ flags_.can_be_constant = true;
}
-void ChromaMatteOperation::initExecution()
+void ChromaMatteOperation::init_execution()
{
- this->m_inputImageProgram = this->getInputSocketReader(0);
- this->m_inputKeyProgram = this->getInputSocketReader(1);
+ input_image_program_ = this->get_input_socket_reader(0);
+ input_key_program_ = this->get_input_socket_reader(1);
}
-void ChromaMatteOperation::deinitExecution()
+void ChromaMatteOperation::deinit_execution()
{
- this->m_inputImageProgram = nullptr;
- this->m_inputKeyProgram = nullptr;
+ input_image_program_ = nullptr;
+ input_key_program_ = nullptr;
}
-void ChromaMatteOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ChromaMatteOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inKey[4];
- float inImage[4];
+ float in_key[4];
+ float in_image[4];
- const float acceptance = this->m_settings->t1; /* in radians */
- const float cutoff = this->m_settings->t2; /* in radians */
- const float gain = this->m_settings->fstrength;
+ const float acceptance = settings_->t1; /* in radians */
+ const float cutoff = settings_->t2; /* in radians */
+ const float gain = settings_->fstrength;
float x_angle, z_angle, alpha;
float theta, beta;
float kfg;
- this->m_inputKeyProgram->readSampled(inKey, x, y, sampler);
- this->m_inputImageProgram->readSampled(inImage, x, y, sampler);
+ input_key_program_->read_sampled(in_key, x, y, sampler);
+ input_image_program_->read_sampled(in_image, x, y, sampler);
/* Store matte(alpha) value in [0] to go with
* #COM_SetAlphaMultiplyOperation and the Value output. */
@@ -70,19 +69,19 @@ void ChromaMatteOperation::executePixelSampled(float output[4],
/* Find theta, the angle that the color space should be rotated based on key. */
/* rescale to -1.0..1.0 */
- // inImage[0] = (inImage[0] * 2.0f) - 1.0f; // UNUSED
- inImage[1] = (inImage[1] * 2.0f) - 1.0f;
- inImage[2] = (inImage[2] * 2.0f) - 1.0f;
+ // in_image[0] = (in_image[0] * 2.0f) - 1.0f; // UNUSED
+ in_image[1] = (in_image[1] * 2.0f) - 1.0f;
+ in_image[2] = (in_image[2] * 2.0f) - 1.0f;
- // inKey[0] = (inKey[0] * 2.0f) - 1.0f; // UNUSED
- inKey[1] = (inKey[1] * 2.0f) - 1.0f;
- inKey[2] = (inKey[2] * 2.0f) - 1.0f;
+ // in_key[0] = (in_key[0] * 2.0f) - 1.0f; // UNUSED
+ in_key[1] = (in_key[1] * 2.0f) - 1.0f;
+ in_key[2] = (in_key[2] * 2.0f) - 1.0f;
- theta = atan2(inKey[2], inKey[1]);
+ theta = atan2(in_key[2], in_key[1]);
/* Rotate the cb and cr into x/z space. */
- x_angle = inImage[1] * cosf(theta) + inImage[2] * sinf(theta);
- z_angle = inImage[2] * cosf(theta) - inImage[1] * sinf(theta);
+ x_angle = in_image[1] * cosf(theta) + in_image[2] * sinf(theta);
+ z_angle = in_image[2] * cosf(theta) - in_image[1] * sinf(theta);
/* If within the acceptance angle. */
/* If kfg is <0 then the pixel is outside of the key color. */
@@ -99,15 +98,15 @@ void ChromaMatteOperation::executePixelSampled(float output[4],
}
/* don't make something that was more transparent less transparent */
- if (alpha < inImage[3]) {
+ if (alpha < in_image[3]) {
output[0] = alpha;
}
else {
- output[0] = inImage[3];
+ output[0] = in_image[3];
}
}
- else { /* Pixel is outside key color. */
- output[0] = inImage[3]; /* Make pixel just as transparent as it was before. */
+ else { /* Pixel is outside key color. */
+ output[0] = in_image[3]; /* Make pixel just as transparent as it was before. */
}
}
@@ -115,9 +114,9 @@ void ChromaMatteOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- const float acceptance = this->m_settings->t1; /* In radians. */
- const float cutoff = this->m_settings->t2; /* In radians. */
- const float gain = this->m_settings->fstrength;
+ const float acceptance = settings_->t1; /* In radians. */
+ const float cutoff = settings_->t2; /* In radians. */
+ const float gain = settings_->fstrength;
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
const float *in_image = it.in(0);
const float *in_key = it.in(1);
diff --git a/source/blender/compositor/operations/COM_ChromaMatteOperation.h b/source/blender/compositor/operations/COM_ChromaMatteOperation.h
index 065349910a7..954daef1be7 100644
--- a/source/blender/compositor/operations/COM_ChromaMatteOperation.h
+++ b/source/blender/compositor/operations/COM_ChromaMatteOperation.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ChromaMatteOperation : public MultiThreadedOperation {
private:
- NodeChroma *m_settings;
- SocketReader *m_inputImageProgram;
- SocketReader *m_inputKeyProgram;
+ NodeChroma *settings_;
+ SocketReader *input_image_program_;
+ SocketReader *input_key_program_;
public:
/**
@@ -41,14 +41,14 @@ class ChromaMatteOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void setSettings(NodeChroma *nodeChroma)
+ void set_settings(NodeChroma *node_chroma)
{
- this->m_settings = nodeChroma;
+ settings_ = node_chroma;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc
index 0b6590ae4c7..533854b62dd 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc
@@ -17,7 +17,6 @@
*/
#include "COM_ColorBalanceASCCDLOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
@@ -35,46 +34,43 @@ inline float colorbalance_cdl(float in, float offset, float power, float slope)
ColorBalanceASCCDLOperation::ColorBalanceASCCDLOperation()
{
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
- this->m_inputValueOperation = nullptr;
- this->m_inputColorOperation = nullptr;
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ input_value_operation_ = nullptr;
+ input_color_operation_ = nullptr;
this->set_canvas_input_index(1);
- flags.can_be_constant = true;
+ flags_.can_be_constant = true;
}
-void ColorBalanceASCCDLOperation::initExecution()
+void ColorBalanceASCCDLOperation::init_execution()
{
- this->m_inputValueOperation = this->getInputSocketReader(0);
- this->m_inputColorOperation = this->getInputSocketReader(1);
+ input_value_operation_ = this->get_input_socket_reader(0);
+ input_color_operation_ = this->get_input_socket_reader(1);
}
-void ColorBalanceASCCDLOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ColorBalanceASCCDLOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor[4];
+ float input_color[4];
float value[4];
- this->m_inputValueOperation->readSampled(value, x, y, sampler);
- this->m_inputColorOperation->readSampled(inputColor, x, y, sampler);
+ input_value_operation_->read_sampled(value, x, y, sampler);
+ input_color_operation_->read_sampled(input_color, x, y, sampler);
float fac = value[0];
fac = MIN2(1.0f, fac);
const float mfac = 1.0f - fac;
- output[0] = mfac * inputColor[0] +
- fac * colorbalance_cdl(
- inputColor[0], this->m_offset[0], this->m_power[0], this->m_slope[0]);
- output[1] = mfac * inputColor[1] +
- fac * colorbalance_cdl(
- inputColor[1], this->m_offset[1], this->m_power[1], this->m_slope[1]);
- output[2] = mfac * inputColor[2] +
- fac * colorbalance_cdl(
- inputColor[2], this->m_offset[2], this->m_power[2], this->m_slope[2]);
- output[3] = inputColor[3];
+ output[0] = mfac * input_color[0] +
+ fac * colorbalance_cdl(input_color[0], offset_[0], power_[0], slope_[0]);
+ output[1] = mfac * input_color[1] +
+ fac * colorbalance_cdl(input_color[1], offset_[1], power_[1], slope_[1]);
+ output[2] = mfac * input_color[2] +
+ fac * colorbalance_cdl(input_color[2], offset_[2], power_[2], slope_[2]);
+ output[3] = input_color[3];
}
void ColorBalanceASCCDLOperation::update_memory_buffer_row(PixelCursor &p)
@@ -85,19 +81,19 @@ void ColorBalanceASCCDLOperation::update_memory_buffer_row(PixelCursor &p)
const float fac = MIN2(1.0f, in_factor[0]);
const float fac_m = 1.0f - fac;
p.out[0] = fac_m * in_color[0] +
- fac * colorbalance_cdl(in_color[0], m_offset[0], m_power[0], m_slope[0]);
+ fac * colorbalance_cdl(in_color[0], offset_[0], power_[0], slope_[0]);
p.out[1] = fac_m * in_color[1] +
- fac * colorbalance_cdl(in_color[1], m_offset[1], m_power[1], m_slope[1]);
+ fac * colorbalance_cdl(in_color[1], offset_[1], power_[1], slope_[1]);
p.out[2] = fac_m * in_color[2] +
- fac * colorbalance_cdl(in_color[2], m_offset[2], m_power[2], m_slope[2]);
+ fac * colorbalance_cdl(in_color[2], offset_[2], power_[2], slope_[2]);
p.out[3] = in_color[3];
}
}
-void ColorBalanceASCCDLOperation::deinitExecution()
+void ColorBalanceASCCDLOperation::deinit_execution()
{
- this->m_inputValueOperation = nullptr;
- this->m_inputColorOperation = nullptr;
+ input_value_operation_ = nullptr;
+ input_color_operation_ = nullptr;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.h b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.h
index d161ea66af2..64622e399d3 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.h
+++ b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.h
@@ -29,14 +29,14 @@ namespace blender::compositor {
class ColorBalanceASCCDLOperation : public MultiThreadedRowOperation {
protected:
/**
- * Prefetched reference to the inputProgram
+ * Prefetched reference to the input_program
*/
- SocketReader *m_inputValueOperation;
- SocketReader *m_inputColorOperation;
+ SocketReader *input_value_operation_;
+ SocketReader *input_color_operation_;
- float m_offset[3];
- float m_power[3];
- float m_slope[3];
+ float offset_[3];
+ float power_[3];
+ float slope_[3];
public:
/**
@@ -47,29 +47,29 @@ class ColorBalanceASCCDLOperation : public MultiThreadedRowOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setOffset(float offset[3])
+ void set_offset(float offset[3])
{
- copy_v3_v3(this->m_offset, offset);
+ copy_v3_v3(offset_, offset);
}
- void setPower(float power[3])
+ void set_power(float power[3])
{
- copy_v3_v3(this->m_power, power);
+ copy_v3_v3(power_, power);
}
- void setSlope(float slope[3])
+ void set_slope(float slope[3])
{
- copy_v3_v3(this->m_slope, slope);
+ copy_v3_v3(slope_, slope);
}
void update_memory_buffer_row(PixelCursor &p) override;
diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc
index c658ecd6394..606fd560cff 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc
@@ -17,7 +17,6 @@
*/
#include "COM_ColorBalanceLGGOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
@@ -40,46 +39,43 @@ inline float colorbalance_lgg(float in, float lift_lgg, float gamma_inv, float g
ColorBalanceLGGOperation::ColorBalanceLGGOperation()
{
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
- this->m_inputValueOperation = nullptr;
- this->m_inputColorOperation = nullptr;
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ input_value_operation_ = nullptr;
+ input_color_operation_ = nullptr;
this->set_canvas_input_index(1);
- flags.can_be_constant = true;
+ flags_.can_be_constant = true;
}
-void ColorBalanceLGGOperation::initExecution()
+void ColorBalanceLGGOperation::init_execution()
{
- this->m_inputValueOperation = this->getInputSocketReader(0);
- this->m_inputColorOperation = this->getInputSocketReader(1);
+ input_value_operation_ = this->get_input_socket_reader(0);
+ input_color_operation_ = this->get_input_socket_reader(1);
}
-void ColorBalanceLGGOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ColorBalanceLGGOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor[4];
+ float input_color[4];
float value[4];
- this->m_inputValueOperation->readSampled(value, x, y, sampler);
- this->m_inputColorOperation->readSampled(inputColor, x, y, sampler);
+ input_value_operation_->read_sampled(value, x, y, sampler);
+ input_color_operation_->read_sampled(input_color, x, y, sampler);
float fac = value[0];
fac = MIN2(1.0f, fac);
const float mfac = 1.0f - fac;
- output[0] = mfac * inputColor[0] +
- fac * colorbalance_lgg(
- inputColor[0], this->m_lift[0], this->m_gamma_inv[0], this->m_gain[0]);
- output[1] = mfac * inputColor[1] +
- fac * colorbalance_lgg(
- inputColor[1], this->m_lift[1], this->m_gamma_inv[1], this->m_gain[1]);
- output[2] = mfac * inputColor[2] +
- fac * colorbalance_lgg(
- inputColor[2], this->m_lift[2], this->m_gamma_inv[2], this->m_gain[2]);
- output[3] = inputColor[3];
+ output[0] = mfac * input_color[0] +
+ fac * colorbalance_lgg(input_color[0], lift_[0], gamma_inv_[0], gain_[0]);
+ output[1] = mfac * input_color[1] +
+ fac * colorbalance_lgg(input_color[1], lift_[1], gamma_inv_[1], gain_[1]);
+ output[2] = mfac * input_color[2] +
+ fac * colorbalance_lgg(input_color[2], lift_[2], gamma_inv_[2], gain_[2]);
+ output[3] = input_color[3];
}
void ColorBalanceLGGOperation::update_memory_buffer_row(PixelCursor &p)
@@ -90,19 +86,19 @@ void ColorBalanceLGGOperation::update_memory_buffer_row(PixelCursor &p)
const float fac = MIN2(1.0f, in_factor[0]);
const float fac_m = 1.0f - fac;
p.out[0] = fac_m * in_color[0] +
- fac * colorbalance_lgg(in_color[0], m_lift[0], m_gamma_inv[0], m_gain[0]);
+ fac * colorbalance_lgg(in_color[0], lift_[0], gamma_inv_[0], gain_[0]);
p.out[1] = fac_m * in_color[1] +
- fac * colorbalance_lgg(in_color[1], m_lift[1], m_gamma_inv[1], m_gain[1]);
+ fac * colorbalance_lgg(in_color[1], lift_[1], gamma_inv_[1], gain_[1]);
p.out[2] = fac_m * in_color[2] +
- fac * colorbalance_lgg(in_color[2], m_lift[2], m_gamma_inv[2], m_gain[2]);
+ fac * colorbalance_lgg(in_color[2], lift_[2], gamma_inv_[2], gain_[2]);
p.out[3] = in_color[3];
}
}
-void ColorBalanceLGGOperation::deinitExecution()
+void ColorBalanceLGGOperation::deinit_execution()
{
- this->m_inputValueOperation = nullptr;
- this->m_inputColorOperation = nullptr;
+ input_value_operation_ = nullptr;
+ input_color_operation_ = nullptr;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.h b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.h
index 4bc929ed76c..738669e71f9 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.h
+++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.h
@@ -29,14 +29,14 @@ namespace blender::compositor {
class ColorBalanceLGGOperation : public MultiThreadedRowOperation {
protected:
/**
- * Prefetched reference to the inputProgram
+ * Prefetched reference to the input_program
*/
- SocketReader *m_inputValueOperation;
- SocketReader *m_inputColorOperation;
+ SocketReader *input_value_operation_;
+ SocketReader *input_color_operation_;
- float m_gain[3];
- float m_lift[3];
- float m_gamma_inv[3];
+ float gain_[3];
+ float lift_[3];
+ float gamma_inv_[3];
public:
/**
@@ -47,29 +47,29 @@ class ColorBalanceLGGOperation : public MultiThreadedRowOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setGain(const float gain[3])
+ void set_gain(const float gain[3])
{
- copy_v3_v3(this->m_gain, gain);
+ copy_v3_v3(gain_, gain);
}
- void setLift(const float lift[3])
+ void set_lift(const float lift[3])
{
- copy_v3_v3(this->m_lift, lift);
+ copy_v3_v3(lift_, lift);
}
- void setGammaInv(const float gamma_inv[3])
+ void set_gamma_inv(const float gamma_inv[3])
{
- copy_v3_v3(this->m_gamma_inv, gamma_inv);
+ copy_v3_v3(gamma_inv_, gamma_inv);
}
void update_memory_buffer_row(PixelCursor &p) override;
diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc
index d3557e541c0..2e7ce6b8497 100644
--- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc
@@ -17,7 +17,6 @@
*/
#include "COM_ColorCorrectionOperation.h"
-#include "BLI_math.h"
#include "IMB_colormanagement.h"
@@ -25,20 +24,20 @@ namespace blender::compositor {
ColorCorrectionOperation::ColorCorrectionOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
- this->m_inputImage = nullptr;
- this->m_inputMask = nullptr;
- this->m_redChannelEnabled = true;
- this->m_greenChannelEnabled = true;
- this->m_blueChannelEnabled = true;
- flags.can_be_constant = true;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
+ input_image_ = nullptr;
+ input_mask_ = nullptr;
+ red_channel_enabled_ = true;
+ green_channel_enabled_ = true;
+ blue_channel_enabled_ = true;
+ flags_.can_be_constant = true;
}
-void ColorCorrectionOperation::initExecution()
+void ColorCorrectionOperation::init_execution()
{
- this->m_inputImage = this->getInputSocketReader(0);
- this->m_inputMask = this->getInputSocketReader(1);
+ input_image_ = this->get_input_socket_reader(0);
+ input_mask_ = this->get_input_socket_reader(1);
}
/* Calculate x^y if the function is defined. Otherwise return the given fallback value. */
@@ -50,74 +49,71 @@ BLI_INLINE float color_correct_powf_safe(const float x, const float y, const flo
return powf(x, y);
}
-void ColorCorrectionOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ColorCorrectionOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputImageColor[4];
- float inputMask[4];
- this->m_inputImage->readSampled(inputImageColor, x, y, sampler);
- this->m_inputMask->readSampled(inputMask, x, y, sampler);
-
- float level = (inputImageColor[0] + inputImageColor[1] + inputImageColor[2]) / 3.0f;
- float contrast = this->m_data->master.contrast;
- float saturation = this->m_data->master.saturation;
- float gamma = this->m_data->master.gamma;
- float gain = this->m_data->master.gain;
- float lift = this->m_data->master.lift;
+ float input_image_color[4];
+ float input_mask[4];
+ input_image_->read_sampled(input_image_color, x, y, sampler);
+ input_mask_->read_sampled(input_mask, x, y, sampler);
+
+ float level = (input_image_color[0] + input_image_color[1] + input_image_color[2]) / 3.0f;
+ float contrast = data_->master.contrast;
+ float saturation = data_->master.saturation;
+ float gamma = data_->master.gamma;
+ float gain = data_->master.gain;
+ float lift = data_->master.lift;
float r, g, b;
- float value = inputMask[0];
+ float value = input_mask[0];
value = MIN2(1.0f, value);
const float mvalue = 1.0f - value;
- float levelShadows = 0.0;
- float levelMidtones = 0.0;
- float levelHighlights = 0.0;
+ float level_shadows = 0.0;
+ float level_midtones = 0.0;
+ float level_highlights = 0.0;
#define MARGIN 0.10f
#define MARGIN_DIV (0.5f / MARGIN)
- if (level < this->m_data->startmidtones - MARGIN) {
- levelShadows = 1.0f;
+ if (level < data_->startmidtones - MARGIN) {
+ level_shadows = 1.0f;
}
- else if (level < this->m_data->startmidtones + MARGIN) {
- levelMidtones = ((level - this->m_data->startmidtones) * MARGIN_DIV) + 0.5f;
- levelShadows = 1.0f - levelMidtones;
+ else if (level < data_->startmidtones + MARGIN) {
+ level_midtones = ((level - data_->startmidtones) * MARGIN_DIV) + 0.5f;
+ level_shadows = 1.0f - level_midtones;
}
- else if (level < this->m_data->endmidtones - MARGIN) {
- levelMidtones = 1.0f;
+ else if (level < data_->endmidtones - MARGIN) {
+ level_midtones = 1.0f;
}
- else if (level < this->m_data->endmidtones + MARGIN) {
- levelHighlights = ((level - this->m_data->endmidtones) * MARGIN_DIV) + 0.5f;
- levelMidtones = 1.0f - levelHighlights;
+ else if (level < data_->endmidtones + MARGIN) {
+ level_highlights = ((level - data_->endmidtones) * MARGIN_DIV) + 0.5f;
+ level_midtones = 1.0f - level_highlights;
}
else {
- levelHighlights = 1.0f;
+ level_highlights = 1.0f;
}
#undef MARGIN
#undef MARGIN_DIV
- contrast *= (levelShadows * this->m_data->shadows.contrast) +
- (levelMidtones * this->m_data->midtones.contrast) +
- (levelHighlights * this->m_data->highlights.contrast);
- saturation *= (levelShadows * this->m_data->shadows.saturation) +
- (levelMidtones * this->m_data->midtones.saturation) +
- (levelHighlights * this->m_data->highlights.saturation);
- gamma *= (levelShadows * this->m_data->shadows.gamma) +
- (levelMidtones * this->m_data->midtones.gamma) +
- (levelHighlights * this->m_data->highlights.gamma);
- gain *= (levelShadows * this->m_data->shadows.gain) +
- (levelMidtones * this->m_data->midtones.gain) +
- (levelHighlights * this->m_data->highlights.gain);
- lift += (levelShadows * this->m_data->shadows.lift) +
- (levelMidtones * this->m_data->midtones.lift) +
- (levelHighlights * this->m_data->highlights.lift);
+ contrast *= (level_shadows * data_->shadows.contrast) +
+ (level_midtones * data_->midtones.contrast) +
+ (level_highlights * data_->highlights.contrast);
+ saturation *= (level_shadows * data_->shadows.saturation) +
+ (level_midtones * data_->midtones.saturation) +
+ (level_highlights * data_->highlights.saturation);
+ gamma *= (level_shadows * data_->shadows.gamma) + (level_midtones * data_->midtones.gamma) +
+ (level_highlights * data_->highlights.gamma);
+ gain *= (level_shadows * data_->shadows.gain) + (level_midtones * data_->midtones.gain) +
+ (level_highlights * data_->highlights.gain);
+ lift += (level_shadows * data_->shadows.lift) + (level_midtones * data_->midtones.lift) +
+ (level_highlights * data_->highlights.lift);
float invgamma = 1.0f / gamma;
- float luma = IMB_colormanagement_get_luminance(inputImageColor);
+ float luma = IMB_colormanagement_get_luminance(input_image_color);
- r = inputImageColor[0];
- g = inputImageColor[1];
- b = inputImageColor[2];
+ r = input_image_color[0];
+ g = input_image_color[1];
+ b = input_image_color[2];
r = (luma + saturation * (r - luma));
g = (luma + saturation * (g - luma));
@@ -133,29 +129,29 @@ void ColorCorrectionOperation::executePixelSampled(float output[4],
b = color_correct_powf_safe(b * gain + lift, invgamma, b);
/* Mix with mask. */
- r = mvalue * inputImageColor[0] + value * r;
- g = mvalue * inputImageColor[1] + value * g;
- b = mvalue * inputImageColor[2] + value * b;
+ r = mvalue * input_image_color[0] + value * r;
+ g = mvalue * input_image_color[1] + value * g;
+ b = mvalue * input_image_color[2] + value * b;
- if (this->m_redChannelEnabled) {
+ if (red_channel_enabled_) {
output[0] = r;
}
else {
- output[0] = inputImageColor[0];
+ output[0] = input_image_color[0];
}
- if (this->m_greenChannelEnabled) {
+ if (green_channel_enabled_) {
output[1] = g;
}
else {
- output[1] = inputImageColor[1];
+ output[1] = input_image_color[1];
}
- if (this->m_blueChannelEnabled) {
+ if (blue_channel_enabled_) {
output[2] = b;
}
else {
- output[2] = inputImageColor[2];
+ output[2] = input_image_color[2];
}
- output[3] = inputImageColor[3];
+ output[3] = input_image_color[3];
}
void ColorCorrectionOperation::update_memory_buffer_row(PixelCursor &p)
@@ -170,43 +166,40 @@ void ColorCorrectionOperation::update_memory_buffer_row(PixelCursor &p)
float level_highlights = 0.0f;
constexpr float MARGIN = 0.10f;
constexpr float MARGIN_DIV = 0.5f / MARGIN;
- if (level < this->m_data->startmidtones - MARGIN) {
+ if (level < data_->startmidtones - MARGIN) {
level_shadows = 1.0f;
}
- else if (level < this->m_data->startmidtones + MARGIN) {
- level_midtones = ((level - this->m_data->startmidtones) * MARGIN_DIV) + 0.5f;
+ else if (level < data_->startmidtones + MARGIN) {
+ level_midtones = ((level - data_->startmidtones) * MARGIN_DIV) + 0.5f;
level_shadows = 1.0f - level_midtones;
}
- else if (level < this->m_data->endmidtones - MARGIN) {
+ else if (level < data_->endmidtones - MARGIN) {
level_midtones = 1.0f;
}
- else if (level < this->m_data->endmidtones + MARGIN) {
- level_highlights = ((level - this->m_data->endmidtones) * MARGIN_DIV) + 0.5f;
+ else if (level < data_->endmidtones + MARGIN) {
+ level_highlights = ((level - data_->endmidtones) * MARGIN_DIV) + 0.5f;
level_midtones = 1.0f - level_highlights;
}
else {
level_highlights = 1.0f;
}
- float contrast = this->m_data->master.contrast;
- float saturation = this->m_data->master.saturation;
- float gamma = this->m_data->master.gamma;
- float gain = this->m_data->master.gain;
- float lift = this->m_data->master.lift;
- contrast *= level_shadows * this->m_data->shadows.contrast +
- level_midtones * this->m_data->midtones.contrast +
- level_highlights * this->m_data->highlights.contrast;
- saturation *= level_shadows * this->m_data->shadows.saturation +
- level_midtones * this->m_data->midtones.saturation +
- level_highlights * this->m_data->highlights.saturation;
- gamma *= level_shadows * this->m_data->shadows.gamma +
- level_midtones * this->m_data->midtones.gamma +
- level_highlights * this->m_data->highlights.gamma;
- gain *= level_shadows * this->m_data->shadows.gain +
- level_midtones * this->m_data->midtones.gain +
- level_highlights * this->m_data->highlights.gain;
- lift += level_shadows * this->m_data->shadows.lift +
- level_midtones * this->m_data->midtones.lift +
- level_highlights * this->m_data->highlights.lift;
+ float contrast = data_->master.contrast;
+ float saturation = data_->master.saturation;
+ float gamma = data_->master.gamma;
+ float gain = data_->master.gain;
+ float lift = data_->master.lift;
+ contrast *= level_shadows * data_->shadows.contrast +
+ level_midtones * data_->midtones.contrast +
+ level_highlights * data_->highlights.contrast;
+ saturation *= level_shadows * data_->shadows.saturation +
+ level_midtones * data_->midtones.saturation +
+ level_highlights * data_->highlights.saturation;
+ gamma *= level_shadows * data_->shadows.gamma + level_midtones * data_->midtones.gamma +
+ level_highlights * data_->highlights.gamma;
+ gain *= level_shadows * data_->shadows.gain + level_midtones * data_->midtones.gain +
+ level_highlights * data_->highlights.gain;
+ lift += level_shadows * data_->shadows.lift + level_midtones * data_->midtones.lift +
+ level_highlights * data_->highlights.lift;
const float inv_gamma = 1.0f / gamma;
const float luma = IMB_colormanagement_get_luminance(in_color);
@@ -226,22 +219,22 @@ void ColorCorrectionOperation::update_memory_buffer_row(PixelCursor &p)
/* Mix with mask. */
const float value = MIN2(1.0f, in_mask[0]);
- const float m_value = 1.0f - value;
- r = m_value * in_color[0] + value * r;
- g = m_value * in_color[1] + value * g;
- b = m_value * in_color[2] + value * b;
-
- p.out[0] = m_redChannelEnabled ? r : in_color[0];
- p.out[1] = m_greenChannelEnabled ? g : in_color[1];
- p.out[2] = m_blueChannelEnabled ? b : in_color[2];
+ const float value_ = 1.0f - value;
+ r = value_ * in_color[0] + value * r;
+ g = value_ * in_color[1] + value * g;
+ b = value_ * in_color[2] + value * b;
+
+ p.out[0] = red_channel_enabled_ ? r : in_color[0];
+ p.out[1] = green_channel_enabled_ ? g : in_color[1];
+ p.out[2] = blue_channel_enabled_ ? b : in_color[2];
p.out[3] = in_color[3];
}
}
-void ColorCorrectionOperation::deinitExecution()
+void ColorCorrectionOperation::deinit_execution()
{
- this->m_inputImage = nullptr;
- this->m_inputMask = nullptr;
+ input_image_ = nullptr;
+ input_mask_ = nullptr;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.h b/source/blender/compositor/operations/COM_ColorCorrectionOperation.h
index 32b5e02e77a..b0d52507204 100644
--- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.h
+++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.h
@@ -25,15 +25,15 @@ namespace blender::compositor {
class ColorCorrectionOperation : public MultiThreadedRowOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputImage;
- SocketReader *m_inputMask;
- NodeColorCorrection *m_data;
+ SocketReader *input_image_;
+ SocketReader *input_mask_;
+ NodeColorCorrection *data_;
- bool m_redChannelEnabled;
- bool m_greenChannelEnabled;
- bool m_blueChannelEnabled;
+ bool red_channel_enabled_;
+ bool green_channel_enabled_;
+ bool blue_channel_enabled_;
public:
ColorCorrectionOperation();
@@ -41,33 +41,33 @@ class ColorCorrectionOperation : public MultiThreadedRowOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setData(NodeColorCorrection *data)
+ void set_data(NodeColorCorrection *data)
{
- this->m_data = data;
+ data_ = data;
}
- void setRedChannelEnabled(bool enabled)
+ void set_red_channel_enabled(bool enabled)
{
- this->m_redChannelEnabled = enabled;
+ red_channel_enabled_ = enabled;
}
- void setGreenChannelEnabled(bool enabled)
+ void set_green_channel_enabled(bool enabled)
{
- this->m_greenChannelEnabled = enabled;
+ green_channel_enabled_ = enabled;
}
- void setBlueChannelEnabled(bool enabled)
+ void set_blue_channel_enabled(bool enabled)
{
- this->m_blueChannelEnabled = enabled;
+ blue_channel_enabled_ = enabled;
}
void update_memory_buffer_row(PixelCursor &p) override;
diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.cc b/source/blender/compositor/operations/COM_ColorCurveOperation.cc
index 364b310945e..bf82ae73d55 100644
--- a/source/blender/compositor/operations/COM_ColorCurveOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorCurveOperation.cc
@@ -20,42 +20,40 @@
#include "BKE_colortools.h"
-#include "MEM_guardedalloc.h"
-
namespace blender::compositor {
ColorCurveOperation::ColorCurveOperation()
{
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
- this->m_inputFacProgram = nullptr;
- this->m_inputImageProgram = nullptr;
- this->m_inputBlackProgram = nullptr;
- this->m_inputWhiteProgram = nullptr;
+ input_fac_program_ = nullptr;
+ input_image_program_ = nullptr;
+ input_black_program_ = nullptr;
+ input_white_program_ = nullptr;
this->set_canvas_input_index(1);
}
-void ColorCurveOperation::initExecution()
+void ColorCurveOperation::init_execution()
{
- CurveBaseOperation::initExecution();
- this->m_inputFacProgram = this->getInputSocketReader(0);
- this->m_inputImageProgram = this->getInputSocketReader(1);
- this->m_inputBlackProgram = this->getInputSocketReader(2);
- this->m_inputWhiteProgram = this->getInputSocketReader(3);
+ CurveBaseOperation::init_execution();
+ input_fac_program_ = this->get_input_socket_reader(0);
+ input_image_program_ = this->get_input_socket_reader(1);
+ input_black_program_ = this->get_input_socket_reader(2);
+ input_white_program_ = this->get_input_socket_reader(3);
- BKE_curvemapping_premultiply(this->m_curveMapping, 0);
+ BKE_curvemapping_premultiply(curve_mapping_, false);
}
-void ColorCurveOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ColorCurveOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- CurveMapping *cumap = this->m_curveMapping;
+ CurveMapping *cumap = curve_mapping_;
float fac[4];
float image[4];
@@ -65,15 +63,15 @@ void ColorCurveOperation::executePixelSampled(float output[4],
float white[4];
float bwmul[3];
- this->m_inputBlackProgram->readSampled(black, x, y, sampler);
- this->m_inputWhiteProgram->readSampled(white, x, y, sampler);
+ input_black_program_->read_sampled(black, x, y, sampler);
+ input_white_program_->read_sampled(white, x, y, sampler);
/* get our own local bwmul value,
* since we can't be threadsafe and use cumap->bwmul & friends */
BKE_curvemapping_set_black_white_ex(black, white, bwmul);
- this->m_inputFacProgram->readSampled(fac, x, y, sampler);
- this->m_inputImageProgram->readSampled(image, x, y, sampler);
+ input_fac_program_->read_sampled(fac, x, y, sampler);
+ input_image_program_->read_sampled(image, x, y, sampler);
if (*fac >= 1.0f) {
BKE_curvemapping_evaluate_premulRGBF_ex(cumap, output, image, black, bwmul);
@@ -89,20 +87,20 @@ void ColorCurveOperation::executePixelSampled(float output[4],
output[3] = image[3];
}
-void ColorCurveOperation::deinitExecution()
+void ColorCurveOperation::deinit_execution()
{
- CurveBaseOperation::deinitExecution();
- this->m_inputFacProgram = nullptr;
- this->m_inputImageProgram = nullptr;
- this->m_inputBlackProgram = nullptr;
- this->m_inputWhiteProgram = nullptr;
+ CurveBaseOperation::deinit_execution();
+ input_fac_program_ = nullptr;
+ input_image_program_ = nullptr;
+ input_black_program_ = nullptr;
+ input_white_program_ = nullptr;
}
void ColorCurveOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- CurveMapping *cumap = this->m_curveMapping;
+ CurveMapping *cumap = curve_mapping_;
float bwmul[3];
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
/* Local versions of `cumap->black` and `cumap->white`. */
@@ -132,63 +130,63 @@ void ColorCurveOperation::update_memory_buffer_partial(MemoryBuffer *output,
ConstantLevelColorCurveOperation::ConstantLevelColorCurveOperation()
{
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
- this->m_inputFacProgram = nullptr;
- this->m_inputImageProgram = nullptr;
+ input_fac_program_ = nullptr;
+ input_image_program_ = nullptr;
this->set_canvas_input_index(1);
}
-void ConstantLevelColorCurveOperation::initExecution()
+void ConstantLevelColorCurveOperation::init_execution()
{
- CurveBaseOperation::initExecution();
- this->m_inputFacProgram = this->getInputSocketReader(0);
- this->m_inputImageProgram = this->getInputSocketReader(1);
+ CurveBaseOperation::init_execution();
+ input_fac_program_ = this->get_input_socket_reader(0);
+ input_image_program_ = this->get_input_socket_reader(1);
- BKE_curvemapping_premultiply(this->m_curveMapping, 0);
+ BKE_curvemapping_premultiply(curve_mapping_, false);
- BKE_curvemapping_set_black_white(this->m_curveMapping, this->m_black, this->m_white);
+ BKE_curvemapping_set_black_white(curve_mapping_, black_, white_);
}
-void ConstantLevelColorCurveOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConstantLevelColorCurveOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float fac[4];
float image[4];
- this->m_inputFacProgram->readSampled(fac, x, y, sampler);
- this->m_inputImageProgram->readSampled(image, x, y, sampler);
+ input_fac_program_->read_sampled(fac, x, y, sampler);
+ input_image_program_->read_sampled(image, x, y, sampler);
if (*fac >= 1.0f) {
- BKE_curvemapping_evaluate_premulRGBF(this->m_curveMapping, output, image);
+ BKE_curvemapping_evaluate_premulRGBF(curve_mapping_, output, image);
}
else if (*fac <= 0.0f) {
copy_v3_v3(output, image);
}
else {
float col[4];
- BKE_curvemapping_evaluate_premulRGBF(this->m_curveMapping, col, image);
+ BKE_curvemapping_evaluate_premulRGBF(curve_mapping_, col, image);
interp_v3_v3v3(output, image, col, *fac);
}
output[3] = image[3];
}
-void ConstantLevelColorCurveOperation::deinitExecution()
+void ConstantLevelColorCurveOperation::deinit_execution()
{
- CurveBaseOperation::deinitExecution();
- this->m_inputFacProgram = nullptr;
- this->m_inputImageProgram = nullptr;
+ CurveBaseOperation::deinit_execution();
+ input_fac_program_ = nullptr;
+ input_image_program_ = nullptr;
}
void ConstantLevelColorCurveOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- CurveMapping *cumap = this->m_curveMapping;
+ CurveMapping *cumap = curve_mapping_;
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
const float fac = *it.in(0);
const float *image = it.in(1);
diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.h b/source/blender/compositor/operations/COM_ColorCurveOperation.h
index d8271e56d1d..eaebf1f3ff6 100644
--- a/source/blender/compositor/operations/COM_ColorCurveOperation.h
+++ b/source/blender/compositor/operations/COM_ColorCurveOperation.h
@@ -19,20 +19,18 @@
#pragma once
#include "COM_CurveBaseOperation.h"
-#include "COM_NodeOperation.h"
-#include "DNA_color_types.h"
namespace blender::compositor {
class ColorCurveOperation : public CurveBaseOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputFacProgram;
- SocketReader *m_inputImageProgram;
- SocketReader *m_inputBlackProgram;
- SocketReader *m_inputWhiteProgram;
+ SocketReader *input_fac_program_;
+ SocketReader *input_image_program_;
+ SocketReader *input_black_program_;
+ SocketReader *input_white_program_;
public:
ColorCurveOperation();
@@ -40,17 +38,17 @@ class ColorCurveOperation : public CurveBaseOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
@@ -60,12 +58,12 @@ class ColorCurveOperation : public CurveBaseOperation {
class ConstantLevelColorCurveOperation : public CurveBaseOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputFacProgram;
- SocketReader *m_inputImageProgram;
- float m_black[3];
- float m_white[3];
+ SocketReader *input_fac_program_;
+ SocketReader *input_image_program_;
+ float black_[3];
+ float white_[3];
public:
ConstantLevelColorCurveOperation();
@@ -73,25 +71,25 @@ class ConstantLevelColorCurveOperation : public CurveBaseOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setBlackLevel(float black[3])
+ void set_black_level(float black[3])
{
- copy_v3_v3(this->m_black, black);
+ copy_v3_v3(black_, black);
}
- void setWhiteLevel(float white[3])
+ void set_white_level(float white[3])
{
- copy_v3_v3(this->m_white, white);
+ copy_v3_v3(white_, white);
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_ColorExposureOperation.cc b/source/blender/compositor/operations/COM_ColorExposureOperation.cc
index 228550a31c5..890a0ab4ccb 100644
--- a/source/blender/compositor/operations/COM_ColorExposureOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorExposureOperation.cc
@@ -22,35 +22,35 @@ namespace blender::compositor {
ExposureOperation::ExposureOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
- this->m_inputProgram = nullptr;
- flags.can_be_constant = true;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
+ input_program_ = nullptr;
+ flags_.can_be_constant = true;
}
-void ExposureOperation::initExecution()
+void ExposureOperation::init_execution()
{
- this->m_inputProgram = this->getInputSocketReader(0);
- this->m_inputExposureProgram = this->getInputSocketReader(1);
+ input_program_ = this->get_input_socket_reader(0);
+ input_exposure_program_ = this->get_input_socket_reader(1);
}
-void ExposureOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ExposureOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue[4];
- float inputExposure[4];
- this->m_inputProgram->readSampled(inputValue, x, y, sampler);
- this->m_inputExposureProgram->readSampled(inputExposure, x, y, sampler);
- const float exposure = pow(2, inputExposure[0]);
+ float input_value[4];
+ float input_exposure[4];
+ input_program_->read_sampled(input_value, x, y, sampler);
+ input_exposure_program_->read_sampled(input_exposure, x, y, sampler);
+ const float exposure = pow(2, input_exposure[0]);
- output[0] = inputValue[0] * exposure;
- output[1] = inputValue[1] * exposure;
- output[2] = inputValue[2] * exposure;
+ output[0] = input_value[0] * exposure;
+ output[1] = input_value[1] * exposure;
+ output[2] = input_value[2] * exposure;
- output[3] = inputValue[3];
+ output[3] = input_value[3];
}
void ExposureOperation::update_memory_buffer_row(PixelCursor &p)
@@ -66,10 +66,10 @@ void ExposureOperation::update_memory_buffer_row(PixelCursor &p)
}
}
-void ExposureOperation::deinitExecution()
+void ExposureOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
- this->m_inputExposureProgram = nullptr;
+ input_program_ = nullptr;
+ input_exposure_program_ = nullptr;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ColorExposureOperation.h b/source/blender/compositor/operations/COM_ColorExposureOperation.h
index 1eb790e8d52..6de93a24ddd 100644
--- a/source/blender/compositor/operations/COM_ColorExposureOperation.h
+++ b/source/blender/compositor/operations/COM_ColorExposureOperation.h
@@ -25,10 +25,10 @@ namespace blender::compositor {
class ExposureOperation : public MultiThreadedRowOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
- SocketReader *m_inputExposureProgram;
+ SocketReader *input_program_;
+ SocketReader *input_exposure_program_;
public:
ExposureOperation();
@@ -36,17 +36,17 @@ class ExposureOperation : public MultiThreadedRowOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
void update_memory_buffer_row(PixelCursor &p) override;
};
diff --git a/source/blender/compositor/operations/COM_ColorMatteOperation.cc b/source/blender/compositor/operations/COM_ColorMatteOperation.cc
index dec6571f217..14123d99b0f 100644
--- a/source/blender/compositor/operations/COM_ColorMatteOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorMatteOperation.cc
@@ -17,49 +17,48 @@
*/
#include "COM_ColorMatteOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
ColorMatteOperation::ColorMatteOperation()
{
- addInputSocket(DataType::Color);
- addInputSocket(DataType::Color);
- addOutputSocket(DataType::Value);
+ add_input_socket(DataType::Color);
+ add_input_socket(DataType::Color);
+ add_output_socket(DataType::Value);
- this->m_inputImageProgram = nullptr;
- this->m_inputKeyProgram = nullptr;
- flags.can_be_constant = true;
+ input_image_program_ = nullptr;
+ input_key_program_ = nullptr;
+ flags_.can_be_constant = true;
}
-void ColorMatteOperation::initExecution()
+void ColorMatteOperation::init_execution()
{
- this->m_inputImageProgram = this->getInputSocketReader(0);
- this->m_inputKeyProgram = this->getInputSocketReader(1);
+ input_image_program_ = this->get_input_socket_reader(0);
+ input_key_program_ = this->get_input_socket_reader(1);
}
-void ColorMatteOperation::deinitExecution()
+void ColorMatteOperation::deinit_execution()
{
- this->m_inputImageProgram = nullptr;
- this->m_inputKeyProgram = nullptr;
+ input_image_program_ = nullptr;
+ input_key_program_ = nullptr;
}
-void ColorMatteOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ColorMatteOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inColor[4];
- float inKey[4];
+ float in_color[4];
+ float in_key[4];
- const float hue = this->m_settings->t1;
- const float sat = this->m_settings->t2;
- const float val = this->m_settings->t3;
+ const float hue = settings_->t1;
+ const float sat = settings_->t2;
+ const float val = settings_->t3;
float h_wrap;
- this->m_inputImageProgram->readSampled(inColor, x, y, sampler);
- this->m_inputKeyProgram->readSampled(inKey, x, y, sampler);
+ input_image_program_->read_sampled(in_color, x, y, sampler);
+ input_key_program_->read_sampled(in_key, x, y, sampler);
/* Store matte(alpha) value in [0] to go with
* COM_SetAlphaMultiplyOperation and the Value output.
@@ -68,18 +67,19 @@ void ColorMatteOperation::executePixelSampled(float output[4],
if (
/* Do hue last because it needs to wrap, and does some more checks. */
- /* sat */ (fabsf(inColor[1] - inKey[1]) < sat) &&
- /* val */ (fabsf(inColor[2] - inKey[2]) < val) &&
+ /* sat */ (fabsf(in_color[1] - in_key[1]) < sat) &&
+ /* val */ (fabsf(in_color[2] - in_key[2]) < val) &&
/* multiply by 2 because it wraps on both sides of the hue,
* otherwise 0.5 would key all hue's */
- /* hue */ ((h_wrap = 2.0f * fabsf(inColor[0] - inKey[0])) < hue || (2.0f - h_wrap) < hue)) {
+ /* hue */
+ ((h_wrap = 2.0f * fabsf(in_color[0] - in_key[0])) < hue || (2.0f - h_wrap) < hue)) {
output[0] = 0.0f; /* make transparent */
}
- else { /* Pixel is outside key color. */
- output[0] = inColor[3]; /* Make pixel just as transparent as it was before. */
+ else { /* Pixel is outside key color. */
+ output[0] = in_color[3]; /* Make pixel just as transparent as it was before. */
}
}
@@ -87,9 +87,9 @@ void ColorMatteOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- const float hue = m_settings->t1;
- const float sat = m_settings->t2;
- const float val = m_settings->t3;
+ const float hue = settings_->t1;
+ const float sat = settings_->t2;
+ const float val = settings_->t3;
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
const float *in_color = it.in(0);
const float *in_key = it.in(1);
diff --git a/source/blender/compositor/operations/COM_ColorMatteOperation.h b/source/blender/compositor/operations/COM_ColorMatteOperation.h
index 49d06e62e65..97cf568621a 100644
--- a/source/blender/compositor/operations/COM_ColorMatteOperation.h
+++ b/source/blender/compositor/operations/COM_ColorMatteOperation.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class ColorMatteOperation : public MultiThreadedOperation {
private:
- NodeChroma *m_settings;
- SocketReader *m_inputImageProgram;
- SocketReader *m_inputKeyProgram;
+ NodeChroma *settings_;
+ SocketReader *input_image_program_;
+ SocketReader *input_key_program_;
public:
/**
@@ -41,14 +41,14 @@ class ColorMatteOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void setSettings(NodeChroma *nodeChroma)
+ void set_settings(NodeChroma *node_chroma)
{
- this->m_settings = nodeChroma;
+ settings_ = node_chroma;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.cc b/source/blender/compositor/operations/COM_ColorRampOperation.cc
index 6c1b23ea731..94b840a6f73 100644
--- a/source/blender/compositor/operations/COM_ColorRampOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorRampOperation.cc
@@ -24,32 +24,32 @@ namespace blender::compositor {
ColorRampOperation::ColorRampOperation()
{
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
- this->m_inputProgram = nullptr;
- this->m_colorBand = nullptr;
- this->flags.can_be_constant = true;
+ input_program_ = nullptr;
+ color_band_ = nullptr;
+ flags_.can_be_constant = true;
}
-void ColorRampOperation::initExecution()
+void ColorRampOperation::init_execution()
{
- this->m_inputProgram = this->getInputSocketReader(0);
+ input_program_ = this->get_input_socket_reader(0);
}
-void ColorRampOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ColorRampOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float values[4];
- this->m_inputProgram->readSampled(values, x, y, sampler);
- BKE_colorband_evaluate(this->m_colorBand, values[0], output);
+ input_program_->read_sampled(values, x, y, sampler);
+ BKE_colorband_evaluate(color_band_, values[0], output);
}
-void ColorRampOperation::deinitExecution()
+void ColorRampOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
+ input_program_ = nullptr;
}
void ColorRampOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -57,7 +57,7 @@ void ColorRampOperation::update_memory_buffer_partial(MemoryBuffer *output,
Span<MemoryBuffer *> inputs)
{
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
- BKE_colorband_evaluate(m_colorBand, *it.in(0), it.out);
+ BKE_colorband_evaluate(color_band_, *it.in(0), it.out);
}
}
diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.h b/source/blender/compositor/operations/COM_ColorRampOperation.h
index ab64b9928fd..2faaab4ba54 100644
--- a/source/blender/compositor/operations/COM_ColorRampOperation.h
+++ b/source/blender/compositor/operations/COM_ColorRampOperation.h
@@ -26,10 +26,10 @@ namespace blender::compositor {
class ColorRampOperation : public MultiThreadedOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
- ColorBand *m_colorBand;
+ SocketReader *input_program_;
+ ColorBand *color_band_;
public:
ColorRampOperation();
@@ -37,21 +37,21 @@ class ColorRampOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setColorBand(ColorBand *colorBand)
+ void set_color_band(ColorBand *color_band)
{
- this->m_colorBand = colorBand;
+ color_band_ = color_band;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_ColorSpillOperation.cc b/source/blender/compositor/operations/COM_ColorSpillOperation.cc
index 5bf7a9ee9cd..d614c963488 100644
--- a/source/blender/compositor/operations/COM_ColorSpillOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorSpillOperation.cc
@@ -17,101 +17,98 @@
*/
#include "COM_ColorSpillOperation.h"
-#include "BLI_math.h"
#define AVG(a, b) ((a + b) / 2)
namespace blender::compositor {
ColorSpillOperation::ColorSpillOperation()
{
- addInputSocket(DataType::Color);
- addInputSocket(DataType::Value);
- addOutputSocket(DataType::Color);
+ add_input_socket(DataType::Color);
+ add_input_socket(DataType::Value);
+ add_output_socket(DataType::Color);
- this->m_inputImageReader = nullptr;
- this->m_inputFacReader = nullptr;
- this->m_spillChannel = 1; /* GREEN */
- this->m_spillMethod = 0;
- flags.can_be_constant = true;
+ input_image_reader_ = nullptr;
+ input_fac_reader_ = nullptr;
+ spill_channel_ = 1; /* GREEN */
+ spill_method_ = 0;
+ flags_.can_be_constant = true;
}
-void ColorSpillOperation::initExecution()
+void ColorSpillOperation::init_execution()
{
- this->m_inputImageReader = this->getInputSocketReader(0);
- this->m_inputFacReader = this->getInputSocketReader(1);
- if (this->m_spillChannel == 0) {
- this->m_rmut = -1.0f;
- this->m_gmut = 1.0f;
- this->m_bmut = 1.0f;
- this->m_channel2 = 1;
- this->m_channel3 = 2;
- if (this->m_settings->unspill == 0) {
- this->m_settings->uspillr = 1.0f;
- this->m_settings->uspillg = 0.0f;
- this->m_settings->uspillb = 0.0f;
+ input_image_reader_ = this->get_input_socket_reader(0);
+ input_fac_reader_ = this->get_input_socket_reader(1);
+ if (spill_channel_ == 0) {
+ rmut_ = -1.0f;
+ gmut_ = 1.0f;
+ bmut_ = 1.0f;
+ channel2_ = 1;
+ channel3_ = 2;
+ if (settings_->unspill == 0) {
+ settings_->uspillr = 1.0f;
+ settings_->uspillg = 0.0f;
+ settings_->uspillb = 0.0f;
}
}
- else if (this->m_spillChannel == 1) {
- this->m_rmut = 1.0f;
- this->m_gmut = -1.0f;
- this->m_bmut = 1.0f;
- this->m_channel2 = 0;
- this->m_channel3 = 2;
- if (this->m_settings->unspill == 0) {
- this->m_settings->uspillr = 0.0f;
- this->m_settings->uspillg = 1.0f;
- this->m_settings->uspillb = 0.0f;
+ else if (spill_channel_ == 1) {
+ rmut_ = 1.0f;
+ gmut_ = -1.0f;
+ bmut_ = 1.0f;
+ channel2_ = 0;
+ channel3_ = 2;
+ if (settings_->unspill == 0) {
+ settings_->uspillr = 0.0f;
+ settings_->uspillg = 1.0f;
+ settings_->uspillb = 0.0f;
}
}
else {
- this->m_rmut = 1.0f;
- this->m_gmut = 1.0f;
- this->m_bmut = -1.0f;
+ rmut_ = 1.0f;
+ gmut_ = 1.0f;
+ bmut_ = -1.0f;
- this->m_channel2 = 0;
- this->m_channel3 = 1;
- if (this->m_settings->unspill == 0) {
- this->m_settings->uspillr = 0.0f;
- this->m_settings->uspillg = 0.0f;
- this->m_settings->uspillb = 1.0f;
+ channel2_ = 0;
+ channel3_ = 1;
+ if (settings_->unspill == 0) {
+ settings_->uspillr = 0.0f;
+ settings_->uspillg = 0.0f;
+ settings_->uspillb = 1.0f;
}
}
}
-void ColorSpillOperation::deinitExecution()
+void ColorSpillOperation::deinit_execution()
{
- this->m_inputImageReader = nullptr;
- this->m_inputFacReader = nullptr;
+ input_image_reader_ = nullptr;
+ input_fac_reader_ = nullptr;
}
-void ColorSpillOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ColorSpillOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float fac[4];
float input[4];
- this->m_inputFacReader->readSampled(fac, x, y, sampler);
- this->m_inputImageReader->readSampled(input, x, y, sampler);
+ input_fac_reader_->read_sampled(fac, x, y, sampler);
+ input_image_reader_->read_sampled(input, x, y, sampler);
float rfac = MIN2(1.0f, fac[0]);
float map;
- switch (this->m_spillMethod) {
+ switch (spill_method_) {
case 0: /* simple */
- map = rfac * (input[this->m_spillChannel] -
- (this->m_settings->limscale * input[this->m_settings->limchan]));
+ map = rfac * (input[spill_channel_] - (settings_->limscale * input[settings_->limchan]));
break;
default: /* average */
- map = rfac *
- (input[this->m_spillChannel] -
- (this->m_settings->limscale * AVG(input[this->m_channel2], input[this->m_channel3])));
+ map = rfac * (input[spill_channel_] -
+ (settings_->limscale * AVG(input[channel2_], input[channel3_])));
break;
}
if (map > 0.0f) {
- output[0] = input[0] + this->m_rmut * (this->m_settings->uspillr * map);
- output[1] = input[1] + this->m_gmut * (this->m_settings->uspillg * map);
- output[2] = input[2] + this->m_bmut * (this->m_settings->uspillb * map);
+ output[0] = input[0] + rmut_ * (settings_->uspillr * map);
+ output[1] = input[1] + gmut_ * (settings_->uspillg * map);
+ output[2] = input[2] + bmut_ * (settings_->uspillb * map);
output[3] = input[3];
}
else {
@@ -128,21 +125,20 @@ void ColorSpillOperation::update_memory_buffer_partial(MemoryBuffer *output,
const float factor = MIN2(1.0f, *it.in(1));
float map;
- switch (m_spillMethod) {
+ switch (spill_method_) {
case 0: /* simple */
- map = factor *
- (color[m_spillChannel] - (m_settings->limscale * color[m_settings->limchan]));
+ map = factor * (color[spill_channel_] - (settings_->limscale * color[settings_->limchan]));
break;
default: /* average */
- map = factor * (color[m_spillChannel] -
- (m_settings->limscale * AVG(color[m_channel2], color[m_channel3])));
+ map = factor * (color[spill_channel_] -
+ (settings_->limscale * AVG(color[channel2_], color[channel3_])));
break;
}
if (map > 0.0f) {
- it.out[0] = color[0] + m_rmut * (m_settings->uspillr * map);
- it.out[1] = color[1] + m_gmut * (m_settings->uspillg * map);
- it.out[2] = color[2] + m_bmut * (m_settings->uspillb * map);
+ it.out[0] = color[0] + rmut_ * (settings_->uspillr * map);
+ it.out[1] = color[1] + gmut_ * (settings_->uspillg * map);
+ it.out[2] = color[2] + bmut_ * (settings_->uspillb * map);
it.out[3] = color[3];
}
else {
diff --git a/source/blender/compositor/operations/COM_ColorSpillOperation.h b/source/blender/compositor/operations/COM_ColorSpillOperation.h
index 6a5e688c160..bfb0c6c963f 100644
--- a/source/blender/compositor/operations/COM_ColorSpillOperation.h
+++ b/source/blender/compositor/operations/COM_ColorSpillOperation.h
@@ -28,14 +28,14 @@ namespace blender::compositor {
*/
class ColorSpillOperation : public MultiThreadedOperation {
protected:
- NodeColorspill *m_settings;
- SocketReader *m_inputImageReader;
- SocketReader *m_inputFacReader;
- int m_spillChannel;
- int m_spillMethod;
- int m_channel2;
- int m_channel3;
- float m_rmut, m_gmut, m_bmut;
+ NodeColorspill *settings_;
+ SocketReader *input_image_reader_;
+ SocketReader *input_fac_reader_;
+ int spill_channel_;
+ int spill_method_;
+ int channel2_;
+ int channel3_;
+ float rmut_, gmut_, bmut_;
public:
/**
@@ -46,25 +46,25 @@ class ColorSpillOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void setSettings(NodeColorspill *nodeColorSpill)
+ void set_settings(NodeColorspill *node_color_spill)
{
- this->m_settings = nodeColorSpill;
+ settings_ = node_color_spill;
}
- void setSpillChannel(int channel)
+ void set_spill_channel(int channel)
{
- this->m_spillChannel = channel;
+ spill_channel_ = channel;
}
- void setSpillMethod(int method)
+ void set_spill_method(int method)
{
- this->m_spillMethod = method;
+ spill_method_ = method;
}
- float calculateMapValue(float fac, float *input);
+ float calculate_map_value(float fac, float *input);
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cc b/source/blender/compositor/operations/COM_CompositorOperation.cc
index 52bc9ed6c2f..696dbb1807c 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.cc
+++ b/source/blender/compositor/operations/COM_CompositorOperation.cc
@@ -17,94 +17,86 @@
*/
#include "COM_CompositorOperation.h"
+
#include "BKE_global.h"
#include "BKE_image.h"
-#include "BLI_listbase.h"
-#include "MEM_guardedalloc.h"
-
-#include "BLI_threads.h"
#include "RE_pipeline.h"
-#include "RE_texture.h"
-
-#include "render_types.h"
-
-#include "PIL_time.h"
namespace blender::compositor {
CompositorOperation::CompositorOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
- this->setRenderData(nullptr);
- this->m_outputBuffer = nullptr;
- this->m_depthBuffer = nullptr;
- this->m_imageInput = nullptr;
- this->m_alphaInput = nullptr;
- this->m_depthInput = nullptr;
+ this->set_render_data(nullptr);
+ output_buffer_ = nullptr;
+ depth_buffer_ = nullptr;
+ image_input_ = nullptr;
+ alpha_input_ = nullptr;
+ depth_input_ = nullptr;
- this->m_useAlphaInput = false;
- this->m_active = false;
+ use_alpha_input_ = false;
+ active_ = false;
- this->m_scene = nullptr;
- this->m_sceneName[0] = '\0';
- this->m_viewName = nullptr;
+ scene_ = nullptr;
+ scene_name_[0] = '\0';
+ view_name_ = nullptr;
- flags.use_render_border = true;
+ flags_.use_render_border = true;
}
-void CompositorOperation::initExecution()
+void CompositorOperation::init_execution()
{
- if (!this->m_active) {
+ if (!active_) {
return;
}
/* When initializing the tree during initial load the width and height can be zero. */
- this->m_imageInput = getInputSocketReader(0);
- this->m_alphaInput = getInputSocketReader(1);
- this->m_depthInput = getInputSocketReader(2);
- if (this->getWidth() * this->getHeight() != 0) {
- this->m_outputBuffer = (float *)MEM_callocN(
- sizeof(float[4]) * this->getWidth() * this->getHeight(), "CompositorOperation");
+ image_input_ = get_input_socket_reader(0);
+ alpha_input_ = get_input_socket_reader(1);
+ depth_input_ = get_input_socket_reader(2);
+ if (this->get_width() * this->get_height() != 0) {
+ output_buffer_ = (float *)MEM_callocN(
+ sizeof(float[4]) * this->get_width() * this->get_height(), "CompositorOperation");
}
- if (this->m_depthInput != nullptr) {
- this->m_depthBuffer = (float *)MEM_callocN(
- sizeof(float) * this->getWidth() * this->getHeight(), "CompositorOperation");
+ if (depth_input_ != nullptr) {
+ depth_buffer_ = (float *)MEM_callocN(sizeof(float) * this->get_width() * this->get_height(),
+ "CompositorOperation");
}
}
-void CompositorOperation::deinitExecution()
+void CompositorOperation::deinit_execution()
{
- if (!this->m_active) {
+ if (!active_) {
return;
}
- if (!isBraked()) {
- Render *re = RE_GetSceneRender(this->m_scene);
+ if (!is_braked()) {
+ Render *re = RE_GetSceneRender(scene_);
RenderResult *rr = RE_AcquireResultWrite(re);
if (rr) {
- RenderView *rv = RE_RenderViewGetByName(rr, this->m_viewName);
+ RenderView *rv = RE_RenderViewGetByName(rr, view_name_);
if (rv->rectf != nullptr) {
MEM_freeN(rv->rectf);
}
- rv->rectf = this->m_outputBuffer;
+ rv->rectf = output_buffer_;
if (rv->rectz != nullptr) {
MEM_freeN(rv->rectz);
}
- rv->rectz = this->m_depthBuffer;
+ rv->rectz = depth_buffer_;
rr->have_combined = true;
}
else {
- if (this->m_outputBuffer) {
- MEM_freeN(this->m_outputBuffer);
+ if (output_buffer_) {
+ MEM_freeN(output_buffer_);
}
- if (this->m_depthBuffer) {
- MEM_freeN(this->m_depthBuffer);
+ if (depth_buffer_) {
+ MEM_freeN(depth_buffer_);
}
}
@@ -121,26 +113,26 @@ void CompositorOperation::deinitExecution()
BLI_thread_unlock(LOCK_DRAW_IMAGE);
}
else {
- if (this->m_outputBuffer) {
- MEM_freeN(this->m_outputBuffer);
+ if (output_buffer_) {
+ MEM_freeN(output_buffer_);
}
- if (this->m_depthBuffer) {
- MEM_freeN(this->m_depthBuffer);
+ if (depth_buffer_) {
+ MEM_freeN(depth_buffer_);
}
}
- this->m_outputBuffer = nullptr;
- this->m_depthBuffer = nullptr;
- this->m_imageInput = nullptr;
- this->m_alphaInput = nullptr;
- this->m_depthInput = nullptr;
+ output_buffer_ = nullptr;
+ depth_buffer_ = nullptr;
+ image_input_ = nullptr;
+ alpha_input_ = nullptr;
+ depth_input_ = nullptr;
}
-void CompositorOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
+void CompositorOperation::execute_region(rcti *rect, unsigned int /*tile_number*/)
{
float color[8]; // 7 is enough
- float *buffer = this->m_outputBuffer;
- float *zbuffer = this->m_depthBuffer;
+ float *buffer = output_buffer_;
+ float *zbuffer = depth_buffer_;
if (!buffer) {
return;
@@ -149,8 +141,8 @@ void CompositorOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
int y1 = rect->ymin;
int x2 = rect->xmax;
int y2 = rect->ymax;
- int offset = (y1 * this->getWidth() + x1);
- int add = (this->getWidth() - (x2 - x1));
+ int offset = (y1 * this->get_width() + x1);
+ int add = (this->get_width() - (x2 - x1));
int offset4 = offset * COM_DATA_TYPE_COLOR_CHANNELS;
int x;
int y;
@@ -158,12 +150,12 @@ void CompositorOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
int dx = 0, dy = 0;
#if 0
- const RenderData *rd = this->m_rd;
+ const RenderData *rd = rd_;
if (rd->mode & R_BORDER && rd->mode & R_CROP) {
/**
* When using cropped render result, need to re-position area of interest,
- * so it'll natch bounds of render border within frame. By default, canvas
+ * so it'll match bounds of render border within frame. By default, canvas
* will be centered between full frame and cropped frame, so we use such
* scheme to map cropped coordinates to full-frame coordinates
*
@@ -191,8 +183,8 @@ void CompositorOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
int full_width = rd->xsch * rd->size / 100;
int full_height = rd->ysch * rd->size / 100;
- dx = rd->border.xmin * full_width - (full_width - this->getWidth()) / 2.0f;
- dy = rd->border.ymin * full_height - (full_height - this->getHeight()) / 2.0f;
+ dx = rd->border.xmin * full_width - (full_width - this->get_width()) / 2.0f;
+ dy = rd->border.ymin * full_height - (full_height - this->get_height()) / 2.0f;
}
#endif
@@ -200,18 +192,18 @@ void CompositorOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
for (x = x1; x < x2 && (!breaked); x++) {
int input_x = x + dx, input_y = y + dy;
- this->m_imageInput->readSampled(color, input_x, input_y, PixelSampler::Nearest);
- if (this->m_useAlphaInput) {
- this->m_alphaInput->readSampled(&(color[3]), input_x, input_y, PixelSampler::Nearest);
+ image_input_->read_sampled(color, input_x, input_y, PixelSampler::Nearest);
+ if (use_alpha_input_) {
+ alpha_input_->read_sampled(&(color[3]), input_x, input_y, PixelSampler::Nearest);
}
copy_v4_v4(buffer + offset4, color);
- this->m_depthInput->readSampled(color, input_x, input_y, PixelSampler::Nearest);
+ depth_input_->read_sampled(color, input_x, input_y, PixelSampler::Nearest);
zbuffer[offset] = color[0];
offset4 += COM_DATA_TYPE_COLOR_CHANNELS;
offset++;
- if (isBraked()) {
+ if (is_braked()) {
breaked = true;
}
}
@@ -224,26 +216,26 @@ void CompositorOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(outp
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- if (!m_outputBuffer) {
+ if (!output_buffer_) {
return;
}
- MemoryBuffer output_buf(m_outputBuffer, COM_DATA_TYPE_COLOR_CHANNELS, getWidth(), getHeight());
+ MemoryBuffer output_buf(output_buffer_, COM_DATA_TYPE_COLOR_CHANNELS, get_width(), get_height());
output_buf.copy_from(inputs[0], area);
- if (this->m_useAlphaInput) {
+ if (use_alpha_input_) {
output_buf.copy_from(inputs[1], area, 0, COM_DATA_TYPE_VALUE_CHANNELS, 3);
}
- MemoryBuffer depth_buf(m_depthBuffer, COM_DATA_TYPE_VALUE_CHANNELS, getWidth(), getHeight());
+ MemoryBuffer depth_buf(depth_buffer_, COM_DATA_TYPE_VALUE_CHANNELS, get_width(), get_height());
depth_buf.copy_from(inputs[2], area);
}
void CompositorOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area)
{
- int width = this->m_rd->xsch * this->m_rd->size / 100;
- int height = this->m_rd->ysch * this->m_rd->size / 100;
+ int width = rd_->xsch * rd_->size / 100;
+ int height = rd_->ysch * rd_->size / 100;
/* Check actual render resolution with cropping it may differ with cropped border.rendering
* Fix for T31777 Border Crop gives black (easy). */
- Render *re = RE_GetSceneRender(this->m_scene);
+ Render *re = RE_GetSceneRender(scene_);
if (re) {
RenderResult *rr = RE_AcquireResultRead(re);
if (rr) {
@@ -256,8 +248,16 @@ void CompositorOperation::determine_canvas(const rcti &UNUSED(preferred_area), r
rcti local_preferred;
BLI_rcti_init(&local_preferred, 0, width, 0, height);
- NodeOperation::determine_canvas(local_preferred, r_area);
- r_area = local_preferred;
+ switch (execution_model_) {
+ case eExecutionModel::Tiled:
+ NodeOperation::determine_canvas(local_preferred, r_area);
+ r_area = local_preferred;
+ break;
+ case eExecutionModel::FullFrame:
+ set_determined_canvas_modifier([&](rcti &canvas) { canvas = local_preferred; });
+ NodeOperation::determine_canvas(local_preferred, r_area);
+ break;
+ }
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.h b/source/blender/compositor/operations/COM_CompositorOperation.h
index 6eb96e01b47..a0960074708 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.h
+++ b/source/blender/compositor/operations/COM_CompositorOperation.h
@@ -18,8 +18,6 @@
#pragma once
-#include "BLI_rect.h"
-#include "BLI_string.h"
#include "COM_MultiThreadedOperation.h"
struct Scene;
@@ -31,98 +29,98 @@ namespace blender::compositor {
*/
class CompositorOperation : public MultiThreadedOperation {
private:
- const struct Scene *m_scene;
+ const struct Scene *scene_;
/**
* \brief Scene name, used for getting the render output, includes 'SC' prefix.
*/
- char m_sceneName[MAX_ID_NAME];
+ char scene_name_[MAX_ID_NAME];
/**
* \brief local reference to the scene
*/
- const RenderData *m_rd;
+ const RenderData *rd_;
/**
* \brief reference to the output float buffer
*/
- float *m_outputBuffer;
+ float *output_buffer_;
/**
* \brief reference to the output depth float buffer
*/
- float *m_depthBuffer;
+ float *depth_buffer_;
/**
* \brief local reference to the input image operation
*/
- SocketReader *m_imageInput;
+ SocketReader *image_input_;
/**
* \brief local reference to the input alpha operation
*/
- SocketReader *m_alphaInput;
+ SocketReader *alpha_input_;
/**
* \brief local reference to the depth operation
*/
- SocketReader *m_depthInput;
+ SocketReader *depth_input_;
/**
* \brief Ignore any alpha input
*/
- bool m_useAlphaInput;
+ bool use_alpha_input_;
/**
* \brief operation is active for calculating final compo result
*/
- bool m_active;
+ bool active_;
/**
* \brief View name, used for multiview
*/
- const char *m_viewName;
+ const char *view_name_;
public:
CompositorOperation();
- bool isActiveCompositorOutput() const
+ bool is_active_compositor_output() const
{
- return this->m_active;
+ return active_;
}
- void executeRegion(rcti *rect, unsigned int tileNumber) override;
- void setScene(const struct Scene *scene)
+ void execute_region(rcti *rect, unsigned int tile_number) override;
+ void set_scene(const struct Scene *scene)
{
- m_scene = scene;
+ scene_ = scene;
}
- void setSceneName(const char *sceneName)
+ void set_scene_name(const char *scene_name)
{
- BLI_strncpy(this->m_sceneName, sceneName, sizeof(this->m_sceneName));
+ BLI_strncpy(scene_name_, scene_name, sizeof(scene_name_));
}
- void setViewName(const char *viewName)
+ void set_view_name(const char *view_name)
{
- this->m_viewName = viewName;
+ view_name_ = view_name;
}
- void setRenderData(const RenderData *rd)
+ void set_render_data(const RenderData *rd)
{
- this->m_rd = rd;
+ rd_ = rd;
}
- bool isOutputOperation(bool /*rendering*/) const override
+ bool is_output_operation(bool /*rendering*/) const override
{
- return this->isActiveCompositorOutput();
+ return this->is_active_compositor_output();
}
- void initExecution() override;
- void deinitExecution() override;
- eCompositorPriority getRenderPriority() const override
+ void init_execution() override;
+ void deinit_execution() override;
+ eCompositorPriority get_render_priority() const override
{
return eCompositorPriority::Medium;
}
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
- void setUseAlphaInput(bool value)
+ void set_use_alpha_input(bool value)
{
- this->m_useAlphaInput = value;
+ use_alpha_input_ = value;
}
- void setActive(bool active)
+ void set_active(bool active)
{
- this->m_active = active;
+ active_ = active;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_ConstantOperation.cc b/source/blender/compositor/operations/COM_ConstantOperation.cc
index c127860a89c..400c04d9592 100644
--- a/source/blender/compositor/operations/COM_ConstantOperation.cc
+++ b/source/blender/compositor/operations/COM_ConstantOperation.cc
@@ -23,13 +23,13 @@ namespace blender::compositor {
ConstantOperation::ConstantOperation()
{
needs_canvas_to_get_constant_ = false;
- flags.is_constant_operation = true;
- flags.is_fullframe_operation = true;
+ flags_.is_constant_operation = true;
+ flags_.is_fullframe_operation = true;
}
bool ConstantOperation::can_get_constant_elem() const
{
- return !needs_canvas_to_get_constant_ || this->flags.is_canvas_set;
+ return !needs_canvas_to_get_constant_ || flags_.is_canvas_set;
}
void ConstantOperation::update_memory_buffer(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_ConstantOperation.h b/source/blender/compositor/operations/COM_ConstantOperation.h
index d44d1939424..d0db1ef1366 100644
--- a/source/blender/compositor/operations/COM_ConstantOperation.h
+++ b/source/blender/compositor/operations/COM_ConstantOperation.h
@@ -22,7 +22,7 @@
namespace blender::compositor {
-/* TODO(manzanilla): After removing tiled implementation, implement a default #determineResolution
+/* TODO(manzanilla): After removing tiled implementation, implement a default #determine_resolution
* for all constant operations and make all initialization and deinitilization methods final. */
/**
* Base class for operations that are always constant. Operations that can be constant only when
diff --git a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc
index c00fe5d5f61..db75b2724c4 100644
--- a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc
+++ b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc
@@ -24,31 +24,31 @@ namespace blender::compositor {
ConvertColorProfileOperation::ConvertColorProfileOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
- this->m_inputOperation = nullptr;
- this->m_predivided = false;
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ input_operation_ = nullptr;
+ predivided_ = false;
}
-void ConvertColorProfileOperation::initExecution()
+void ConvertColorProfileOperation::init_execution()
{
- this->m_inputOperation = this->getInputSocketReader(0);
+ input_operation_ = this->get_input_socket_reader(0);
}
-void ConvertColorProfileOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertColorProfileOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float color[4];
- this->m_inputOperation->readSampled(color, x, y, sampler);
+ input_operation_->read_sampled(color, x, y, sampler);
IMB_buffer_float_from_float(
- output, color, 4, this->m_toProfile, this->m_fromProfile, this->m_predivided, 1, 1, 0, 0);
+ output, color, 4, to_profile_, from_profile_, predivided_, 1, 1, 0, 0);
}
-void ConvertColorProfileOperation::deinitExecution()
+void ConvertColorProfileOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
+ input_operation_ = nullptr;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.h b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.h
index 6162408501b..960d267b906 100644
--- a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.h
+++ b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.h
@@ -29,24 +29,24 @@ namespace blender::compositor {
class ConvertColorProfileOperation : public NodeOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputOperation;
+ SocketReader *input_operation_;
/**
* \brief color profile where to convert from
*/
- int m_fromProfile;
+ int from_profile_;
/**
* \brief color profile where to convert to
*/
- int m_toProfile;
+ int to_profile_;
/**
* \brief is color predivided
*/
- bool m_predivided;
+ bool predivided_;
public:
/**
@@ -57,29 +57,29 @@ class ConvertColorProfileOperation : public NodeOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setFromColorProfile(int colorProfile)
+ void set_from_color_profile(int color_profile)
{
- this->m_fromProfile = colorProfile;
+ from_profile_ = color_profile;
}
- void setToColorProfile(int colorProfile)
+ void set_to_color_profile(int color_profile)
{
- this->m_toProfile = colorProfile;
+ to_profile_ = color_profile;
}
- void setPredivided(bool predivided)
+ void set_predivided(bool predivided)
{
- this->m_predivided = predivided;
+ predivided_ = predivided;
}
};
diff --git a/source/blender/compositor/operations/COM_ConvertColorSpaceOperation.cc b/source/blender/compositor/operations/COM_ConvertColorSpaceOperation.cc
new file mode 100644
index 00000000000..5b1dfb4a02c
--- /dev/null
+++ b/source/blender/compositor/operations/COM_ConvertColorSpaceOperation.cc
@@ -0,0 +1,91 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "COM_ConvertColorSpaceOperation.h"
+
+namespace blender::compositor {
+
+ConvertColorSpaceOperation::ConvertColorSpaceOperation()
+{
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ this->input_program_ = nullptr;
+ color_processor_ = nullptr;
+}
+
+void ConvertColorSpaceOperation::set_settings(NodeConvertColorSpace *node_color_space)
+{
+ this->settings_ = node_color_space;
+}
+
+void ConvertColorSpaceOperation::init_execution()
+{
+ if (BLI_strnlen(settings_->from_color_space, sizeof(settings_->from_color_space)) == 0 ||
+ BLI_strnlen(settings_->to_color_space, sizeof(settings_->to_color_space)) == 0) {
+ return;
+ }
+
+ int in_colorspace_index = IMB_colormanagement_colorspace_get_named_index(
+ settings_->from_color_space);
+ int out_colorspace_index = IMB_colormanagement_colorspace_get_named_index(
+ settings_->to_color_space);
+
+ if (in_colorspace_index == 0 || out_colorspace_index == 0) {
+ return;
+ }
+
+ this->input_program_ = this->get_input_socket_reader(0);
+
+ color_processor_ = IMB_colormanagement_colorspace_processor_new(settings_->from_color_space,
+ settings_->to_color_space);
+}
+
+void ConvertColorSpaceOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ this->input_program_->read_sampled(output, x, y, sampler);
+ if (color_processor_ != nullptr) {
+ IMB_colormanagement_processor_apply_pixel(color_processor_, output, 3);
+ }
+}
+
+void ConvertColorSpaceOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ copy_v4_v4(it.out, it.in(0));
+ }
+
+ if (color_processor_ != nullptr) {
+ output->apply_processor(*color_processor_, area);
+ }
+}
+
+void ConvertColorSpaceOperation::deinit_execution()
+{
+ if (color_processor_ != nullptr) {
+ IMB_colormanagement_processor_free(color_processor_);
+ }
+ this->input_program_ = nullptr;
+ this->color_processor_ = nullptr;
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ConvertColorSpaceOperation.h b/source/blender/compositor/operations/COM_ConvertColorSpaceOperation.h
new file mode 100644
index 00000000000..c065224eadc
--- /dev/null
+++ b/source/blender/compositor/operations/COM_ConvertColorSpaceOperation.h
@@ -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.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "COM_ConvertColorSpaceNode.h"
+#include "COM_MultiThreadedOperation.h"
+#include "IMB_colormanagement.h"
+
+namespace blender::compositor {
+
+class ConvertColorSpaceOperation : public MultiThreadedOperation {
+ private:
+ SocketReader *input_program_;
+ NodeConvertColorSpace *settings_;
+ ColormanageProcessor *color_processor_;
+
+ public:
+ ConvertColorSpaceOperation();
+
+ void set_settings(NodeConvertColorSpace *node_color_space);
+ /**
+ * The inner loop of this operation.
+ */
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ /**
+ * Initialize the execution
+ */
+ void init_execution() override;
+
+ /**
+ * Deinitialize the execution
+ */
+ void deinit_execution() override;
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc
index 405ba03abf3..a781b3ea1ed 100644
--- a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc
+++ b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc
@@ -18,73 +18,71 @@
#include "COM_ConvertDepthToRadiusOperation.h"
#include "BKE_camera.h"
-#include "BLI_math.h"
#include "DNA_camera_types.h"
namespace blender::compositor {
ConvertDepthToRadiusOperation::ConvertDepthToRadiusOperation()
{
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
- this->m_inputOperation = nullptr;
- this->m_fStop = 128.0f;
- this->m_cameraObject = nullptr;
- this->m_maxRadius = 32.0f;
- this->m_blurPostOperation = nullptr;
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
+ input_operation_ = nullptr;
+ f_stop_ = 128.0f;
+ camera_object_ = nullptr;
+ max_radius_ = 32.0f;
+ blur_post_operation_ = nullptr;
}
-float ConvertDepthToRadiusOperation::determineFocalDistance()
+float ConvertDepthToRadiusOperation::determine_focal_distance()
{
- if (this->m_cameraObject && this->m_cameraObject->type == OB_CAMERA) {
- Camera *camera = (Camera *)this->m_cameraObject->data;
- this->m_cam_lens = camera->lens;
- return BKE_camera_object_dof_distance(this->m_cameraObject);
+ if (camera_object_ && camera_object_->type == OB_CAMERA) {
+ Camera *camera = (Camera *)camera_object_->data;
+ cam_lens_ = camera->lens;
+ return BKE_camera_object_dof_distance(camera_object_);
}
return 10.0f;
}
-void ConvertDepthToRadiusOperation::initExecution()
+void ConvertDepthToRadiusOperation::init_execution()
{
float cam_sensor = DEFAULT_SENSOR_WIDTH;
Camera *camera = nullptr;
- if (this->m_cameraObject && this->m_cameraObject->type == OB_CAMERA) {
- camera = (Camera *)this->m_cameraObject->data;
+ if (camera_object_ && camera_object_->type == OB_CAMERA) {
+ camera = (Camera *)camera_object_->data;
cam_sensor = BKE_camera_sensor_size(camera->sensor_fit, camera->sensor_x, camera->sensor_y);
}
- this->m_inputOperation = this->getInputSocketReader(0);
- float focalDistance = determineFocalDistance();
- if (focalDistance == 0.0f) {
- focalDistance = 1e10f; /* If the DOF is 0.0 then set it to be far away. */
+ input_operation_ = this->get_input_socket_reader(0);
+ float focal_distance = determine_focal_distance();
+ if (focal_distance == 0.0f) {
+ focal_distance = 1e10f; /* If the DOF is 0.0 then set it to be far away. */
}
- this->m_inverseFocalDistance = 1.0f / focalDistance;
- this->m_aspect = (this->getWidth() > this->getHeight()) ?
- (this->getHeight() / (float)this->getWidth()) :
- (this->getWidth() / (float)this->getHeight());
- this->m_aperture = 0.5f * (this->m_cam_lens / (this->m_aspect * cam_sensor)) / this->m_fStop;
- const float minsz = MIN2(getWidth(), getHeight());
- this->m_dof_sp =
- minsz / ((cam_sensor / 2.0f) /
- this->m_cam_lens); /* <- == `aspect * MIN2(img->x, img->y) / tan(0.5f * fov)` */
-
- if (this->m_blurPostOperation) {
- m_blurPostOperation->setSigma(MIN2(m_aperture * 128.0f, this->m_maxRadius));
+ inverse_focal_distance_ = 1.0f / focal_distance;
+ aspect_ = (this->get_width() > this->get_height()) ?
+ (this->get_height() / (float)this->get_width()) :
+ (this->get_width() / (float)this->get_height());
+ aperture_ = 0.5f * (cam_lens_ / (aspect_ * cam_sensor)) / f_stop_;
+ const float minsz = MIN2(get_width(), get_height());
+ dof_sp_ = minsz / ((cam_sensor / 2.0f) /
+ cam_lens_); /* <- == `aspect * MIN2(img->x, img->y) / tan(0.5f * fov)` */
+
+ if (blur_post_operation_) {
+ blur_post_operation_->set_sigma(MIN2(aperture_ * 128.0f, max_radius_));
}
}
-void ConvertDepthToRadiusOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertDepthToRadiusOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue[4];
+ float input_value[4];
float z;
float radius;
- this->m_inputOperation->readSampled(inputValue, x, y, sampler);
- z = inputValue[0];
+ input_operation_->read_sampled(input_value, x, y, sampler);
+ z = input_value[0];
if (z != 0.0f) {
float iZ = (1.0f / z);
@@ -94,15 +92,14 @@ void ConvertDepthToRadiusOperation::executePixelSampled(float output[4],
/* Scale crad back to original maximum and blend. */
crad->rect[px] = bcrad + wts->rect[px] * (scf * crad->rect[px] - bcrad);
#endif
- radius = 0.5f * fabsf(this->m_aperture *
- (this->m_dof_sp * (this->m_inverseFocalDistance - iZ) - 1.0f));
+ radius = 0.5f * fabsf(aperture_ * (dof_sp_ * (inverse_focal_distance_ - iZ) - 1.0f));
/* 'bug' T6615, limit minimum radius to 1 pixel,
* not really a solution, but somewhat mitigates the problem. */
if (radius < 0.0f) {
radius = 0.0f;
}
- if (radius > this->m_maxRadius) {
- radius = this->m_maxRadius;
+ if (radius > max_radius_) {
+ radius = max_radius_;
}
output[0] = radius;
}
@@ -111,9 +108,9 @@ void ConvertDepthToRadiusOperation::executePixelSampled(float output[4],
}
}
-void ConvertDepthToRadiusOperation::deinitExecution()
+void ConvertDepthToRadiusOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
+ input_operation_ = nullptr;
}
void ConvertDepthToRadiusOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -136,10 +133,10 @@ void ConvertDepthToRadiusOperation::update_memory_buffer_partial(MemoryBuffer *o
* `crad->rect[px] = bcrad + wts->rect[px] * (scf * crad->rect[px] - bcrad);` */
#endif
const float radius = 0.5f *
- fabsf(m_aperture * (m_dof_sp * (m_inverseFocalDistance - inv_z) - 1.0f));
+ fabsf(aperture_ * (dof_sp_ * (inverse_focal_distance_ - inv_z) - 1.0f));
/* Bug T6615, limit minimum radius to 1 pixel,
* not really a solution, but somewhat mitigates the problem. */
- *it.out = CLAMPIS(radius, 0.0f, m_maxRadius);
+ *it.out = CLAMPIS(radius, 0.0f, max_radius_);
}
}
diff --git a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.h b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.h
index 3d163843d06..72d19eb3dd8 100644
--- a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.h
+++ b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.h
@@ -31,19 +31,19 @@ namespace blender::compositor {
class ConvertDepthToRadiusOperation : public MultiThreadedOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputOperation;
- float m_fStop;
- float m_aspect;
- float m_maxRadius;
- float m_inverseFocalDistance;
- float m_aperture;
- float m_cam_lens;
- float m_dof_sp;
- Object *m_cameraObject;
+ SocketReader *input_operation_;
+ float f_stop_;
+ float aspect_;
+ float max_radius_;
+ float inverse_focal_distance_;
+ float aperture_;
+ float cam_lens_;
+ float dof_sp_;
+ Object *camera_object_;
- FastGaussianBlurValueOperation *m_blurPostOperation;
+ FastGaussianBlurValueOperation *blur_post_operation_;
public:
/**
@@ -54,34 +54,34 @@ class ConvertDepthToRadiusOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setfStop(float fStop)
+ void setf_stop(float f_stop)
{
- this->m_fStop = fStop;
+ f_stop_ = f_stop;
}
- void setMaxRadius(float maxRadius)
+ void set_max_radius(float max_radius)
{
- this->m_maxRadius = maxRadius;
+ max_radius_ = max_radius;
}
- void setCameraObject(Object *camera)
+ void set_camera_object(Object *camera)
{
- this->m_cameraObject = camera;
+ camera_object_ = camera;
}
- float determineFocalDistance();
- void setPostBlur(FastGaussianBlurValueOperation *operation)
+ float determine_focal_distance();
+ void set_post_blur(FastGaussianBlurValueOperation *operation)
{
- this->m_blurPostOperation = operation;
+ blur_post_operation_ = operation;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cc b/source/blender/compositor/operations/COM_ConvertOperation.cc
index 7b2721ebbb2..ec321494c6f 100644
--- a/source/blender/compositor/operations/COM_ConvertOperation.cc
+++ b/source/blender/compositor/operations/COM_ConvertOperation.cc
@@ -26,18 +26,18 @@ namespace blender::compositor {
ConvertBaseOperation::ConvertBaseOperation()
{
- this->m_inputOperation = nullptr;
- this->flags.can_be_constant = true;
+ input_operation_ = nullptr;
+ flags_.can_be_constant = true;
}
-void ConvertBaseOperation::initExecution()
+void ConvertBaseOperation::init_execution()
{
- this->m_inputOperation = this->getInputSocketReader(0);
+ input_operation_ = this->get_input_socket_reader(0);
}
-void ConvertBaseOperation::deinitExecution()
+void ConvertBaseOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
+ input_operation_ = nullptr;
}
void ConvertBaseOperation::hash_output_params()
@@ -56,17 +56,17 @@ void ConvertBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
ConvertValueToColorOperation::ConvertValueToColorOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
}
-void ConvertValueToColorOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertValueToColorOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float value;
- this->m_inputOperation->readSampled(&value, x, y, sampler);
+ input_operation_->read_sampled(&value, x, y, sampler);
output[0] = output[1] = output[2] = value;
output[3] = 1.0f;
}
@@ -83,18 +83,18 @@ void ConvertValueToColorOperation::update_memory_buffer_partial(BuffersIterator<
ConvertColorToValueOperation::ConvertColorToValueOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Value);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Value);
}
-void ConvertColorToValueOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertColorToValueOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor[4];
- this->m_inputOperation->readSampled(inputColor, x, y, sampler);
- output[0] = (inputColor[0] + inputColor[1] + inputColor[2]) / 3.0f;
+ float input_color[4];
+ input_operation_->read_sampled(input_color, x, y, sampler);
+ output[0] = (input_color[0] + input_color[1] + input_color[2]) / 3.0f;
}
void ConvertColorToValueOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -109,18 +109,18 @@ void ConvertColorToValueOperation::update_memory_buffer_partial(BuffersIterator<
ConvertColorToBWOperation::ConvertColorToBWOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Value);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Value);
}
-void ConvertColorToBWOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertColorToBWOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor[4];
- this->m_inputOperation->readSampled(inputColor, x, y, sampler);
- output[0] = IMB_colormanagement_get_luminance(inputColor);
+ float input_color[4];
+ input_operation_->read_sampled(input_color, x, y, sampler);
+ output[0] = IMB_colormanagement_get_luminance(input_color);
}
void ConvertColorToBWOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -134,17 +134,17 @@ void ConvertColorToBWOperation::update_memory_buffer_partial(BuffersIterator<flo
ConvertColorToVectorOperation::ConvertColorToVectorOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Vector);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Vector);
}
-void ConvertColorToVectorOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertColorToVectorOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float color[4];
- this->m_inputOperation->readSampled(color, x, y, sampler);
+ input_operation_->read_sampled(color, x, y, sampler);
copy_v3_v3(output, color);
}
@@ -159,17 +159,17 @@ void ConvertColorToVectorOperation::update_memory_buffer_partial(BuffersIterator
ConvertValueToVectorOperation::ConvertValueToVectorOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Vector);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Vector);
}
-void ConvertValueToVectorOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertValueToVectorOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float value;
- this->m_inputOperation->readSampled(&value, x, y, sampler);
+ input_operation_->read_sampled(&value, x, y, sampler);
output[0] = output[1] = output[2] = value;
}
@@ -184,16 +184,16 @@ void ConvertValueToVectorOperation::update_memory_buffer_partial(BuffersIterator
ConvertVectorToColorOperation::ConvertVectorToColorOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Vector);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Vector);
+ this->add_output_socket(DataType::Color);
}
-void ConvertVectorToColorOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertVectorToColorOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- this->m_inputOperation->readSampled(output, x, y, sampler);
+ input_operation_->read_sampled(output, x, y, sampler);
output[3] = 1.0f;
}
@@ -209,17 +209,17 @@ void ConvertVectorToColorOperation::update_memory_buffer_partial(BuffersIterator
ConvertVectorToValueOperation::ConvertVectorToValueOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Vector);
- this->addOutputSocket(DataType::Value);
+ this->add_input_socket(DataType::Vector);
+ this->add_output_socket(DataType::Value);
}
-void ConvertVectorToValueOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertVectorToValueOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float input[4];
- this->m_inputOperation->readSampled(input, x, y, sampler);
+ input_operation_->read_sampled(input, x, y, sampler);
output[0] = (input[0] + input[1] + input[2]) / 3.0f;
}
@@ -235,55 +235,55 @@ void ConvertVectorToValueOperation::update_memory_buffer_partial(BuffersIterator
ConvertRGBToYCCOperation::ConvertRGBToYCCOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
}
-void ConvertRGBToYCCOperation::setMode(int mode)
+void ConvertRGBToYCCOperation::set_mode(int mode)
{
switch (mode) {
case 0:
- this->m_mode = BLI_YCC_ITU_BT601;
+ mode_ = BLI_YCC_ITU_BT601;
break;
case 2:
- this->m_mode = BLI_YCC_JFIF_0_255;
+ mode_ = BLI_YCC_JFIF_0_255;
break;
case 1:
default:
- this->m_mode = BLI_YCC_ITU_BT709;
+ mode_ = BLI_YCC_ITU_BT709;
break;
}
}
-void ConvertRGBToYCCOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertRGBToYCCOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor[4];
+ float input_color[4];
float color[3];
- this->m_inputOperation->readSampled(inputColor, x, y, sampler);
+ input_operation_->read_sampled(input_color, x, y, sampler);
rgb_to_ycc(
- inputColor[0], inputColor[1], inputColor[2], &color[0], &color[1], &color[2], this->m_mode);
+ input_color[0], input_color[1], input_color[2], &color[0], &color[1], &color[2], mode_);
/* divided by 255 to normalize for viewing in */
/* R,G,B --> Y,Cb,Cr */
mul_v3_v3fl(output, color, 1.0f / 255.0f);
- output[3] = inputColor[3];
+ output[3] = input_color[3];
}
void ConvertRGBToYCCOperation::hash_output_params()
{
ConvertBaseOperation::hash_output_params();
- hash_param(m_mode);
+ hash_param(mode_);
}
void ConvertRGBToYCCOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
{
for (; !it.is_end(); ++it) {
const float *in = it.in(0);
- rgb_to_ycc(in[0], in[1], in[2], &it.out[0], &it.out[1], &it.out[2], this->m_mode);
+ rgb_to_ycc(in[0], in[1], in[2], &it.out[0], &it.out[1], &it.out[2], mode_);
/* Normalize for viewing (#rgb_to_ycc returns 0-255 values). */
mul_v3_fl(it.out, 1.0f / 255.0f);
@@ -295,52 +295,47 @@ void ConvertRGBToYCCOperation::update_memory_buffer_partial(BuffersIterator<floa
ConvertYCCToRGBOperation::ConvertYCCToRGBOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
}
-void ConvertYCCToRGBOperation::setMode(int mode)
+void ConvertYCCToRGBOperation::set_mode(int mode)
{
switch (mode) {
case 0:
- this->m_mode = BLI_YCC_ITU_BT601;
+ mode_ = BLI_YCC_ITU_BT601;
break;
case 2:
- this->m_mode = BLI_YCC_JFIF_0_255;
+ mode_ = BLI_YCC_JFIF_0_255;
break;
case 1:
default:
- this->m_mode = BLI_YCC_ITU_BT709;
+ mode_ = BLI_YCC_ITU_BT709;
break;
}
}
-void ConvertYCCToRGBOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertYCCToRGBOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor[4];
- this->m_inputOperation->readSampled(inputColor, x, y, sampler);
+ float input_color[4];
+ input_operation_->read_sampled(input_color, x, y, sampler);
/* need to un-normalize the data */
/* R,G,B --> Y,Cb,Cr */
- mul_v3_fl(inputColor, 255.0f);
+ mul_v3_fl(input_color, 255.0f);
- ycc_to_rgb(inputColor[0],
- inputColor[1],
- inputColor[2],
- &output[0],
- &output[1],
- &output[2],
- this->m_mode);
- output[3] = inputColor[3];
+ ycc_to_rgb(
+ input_color[0], input_color[1], input_color[2], &output[0], &output[1], &output[2], mode_);
+ output[3] = input_color[3];
}
void ConvertYCCToRGBOperation::hash_output_params()
{
ConvertBaseOperation::hash_output_params();
- hash_param(m_mode);
+ hash_param(mode_);
}
void ConvertYCCToRGBOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -348,13 +343,8 @@ void ConvertYCCToRGBOperation::update_memory_buffer_partial(BuffersIterator<floa
for (; !it.is_end(); ++it) {
const float *in = it.in(0);
/* Multiply by 255 to un-normalize (#ycc_to_rgb needs input values in 0-255 range). */
- ycc_to_rgb(in[0] * 255.0f,
- in[1] * 255.0f,
- in[2] * 255.0f,
- &it.out[0],
- &it.out[1],
- &it.out[2],
- this->m_mode);
+ ycc_to_rgb(
+ in[0] * 255.0f, in[1] * 255.0f, in[2] * 255.0f, &it.out[0], &it.out[1], &it.out[2], mode_);
it.out[3] = in[3];
}
}
@@ -363,25 +353,25 @@ void ConvertYCCToRGBOperation::update_memory_buffer_partial(BuffersIterator<floa
ConvertRGBToYUVOperation::ConvertRGBToYUVOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
}
-void ConvertRGBToYUVOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertRGBToYUVOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor[4];
- this->m_inputOperation->readSampled(inputColor, x, y, sampler);
- rgb_to_yuv(inputColor[0],
- inputColor[1],
- inputColor[2],
+ float input_color[4];
+ input_operation_->read_sampled(input_color, x, y, sampler);
+ rgb_to_yuv(input_color[0],
+ input_color[1],
+ input_color[2],
&output[0],
&output[1],
&output[2],
BLI_YUV_ITU_BT709);
- output[3] = inputColor[3];
+ output[3] = input_color[3];
}
void ConvertRGBToYUVOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -397,25 +387,25 @@ void ConvertRGBToYUVOperation::update_memory_buffer_partial(BuffersIterator<floa
ConvertYUVToRGBOperation::ConvertYUVToRGBOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
}
-void ConvertYUVToRGBOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertYUVToRGBOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor[4];
- this->m_inputOperation->readSampled(inputColor, x, y, sampler);
- yuv_to_rgb(inputColor[0],
- inputColor[1],
- inputColor[2],
+ float input_color[4];
+ input_operation_->read_sampled(input_color, x, y, sampler);
+ yuv_to_rgb(input_color[0],
+ input_color[1],
+ input_color[2],
&output[0],
&output[1],
&output[2],
BLI_YUV_ITU_BT709);
- output[3] = inputColor[3];
+ output[3] = input_color[3];
}
void ConvertYUVToRGBOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -431,19 +421,19 @@ void ConvertYUVToRGBOperation::update_memory_buffer_partial(BuffersIterator<floa
ConvertRGBToHSVOperation::ConvertRGBToHSVOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
}
-void ConvertRGBToHSVOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertRGBToHSVOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor[4];
- this->m_inputOperation->readSampled(inputColor, x, y, sampler);
- rgb_to_hsv_v(inputColor, output);
- output[3] = inputColor[3];
+ float input_color[4];
+ input_operation_->read_sampled(input_color, x, y, sampler);
+ rgb_to_hsv_v(input_color, output);
+ output[3] = input_color[3];
}
void ConvertRGBToHSVOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -459,22 +449,22 @@ void ConvertRGBToHSVOperation::update_memory_buffer_partial(BuffersIterator<floa
ConvertHSVToRGBOperation::ConvertHSVToRGBOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
}
-void ConvertHSVToRGBOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertHSVToRGBOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor[4];
- this->m_inputOperation->readSampled(inputColor, x, y, sampler);
- hsv_to_rgb_v(inputColor, output);
+ float input_color[4];
+ input_operation_->read_sampled(input_color, x, y, sampler);
+ hsv_to_rgb_v(input_color, output);
output[0] = max_ff(output[0], 0.0f);
output[1] = max_ff(output[1], 0.0f);
output[2] = max_ff(output[2], 0.0f);
- output[3] = inputColor[3];
+ output[3] = input_color[3];
}
void ConvertHSVToRGBOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -493,17 +483,17 @@ void ConvertHSVToRGBOperation::update_memory_buffer_partial(BuffersIterator<floa
ConvertPremulToStraightOperation::ConvertPremulToStraightOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
}
-void ConvertPremulToStraightOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertPremulToStraightOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
ColorSceneLinear4f<eAlpha::Premultiplied> input;
- this->m_inputOperation->readSampled(input, x, y, sampler);
+ input_operation_->read_sampled(input, x, y, sampler);
ColorSceneLinear4f<eAlpha::Straight> converted = input.unpremultiply_alpha();
copy_v4_v4(output, converted);
}
@@ -519,17 +509,17 @@ void ConvertPremulToStraightOperation::update_memory_buffer_partial(BuffersItera
ConvertStraightToPremulOperation::ConvertStraightToPremulOperation() : ConvertBaseOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
}
-void ConvertStraightToPremulOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ConvertStraightToPremulOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
ColorSceneLinear4f<eAlpha::Straight> input;
- this->m_inputOperation->readSampled(input, x, y, sampler);
+ input_operation_->read_sampled(input, x, y, sampler);
ColorSceneLinear4f<eAlpha::Premultiplied> converted = input.premultiply_alpha();
copy_v4_v4(output, converted);
}
@@ -545,28 +535,28 @@ void ConvertStraightToPremulOperation::update_memory_buffer_partial(BuffersItera
SeparateChannelOperation::SeparateChannelOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Value);
- this->m_inputOperation = nullptr;
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Value);
+ input_operation_ = nullptr;
}
-void SeparateChannelOperation::initExecution()
+void SeparateChannelOperation::init_execution()
{
- this->m_inputOperation = this->getInputSocketReader(0);
+ input_operation_ = this->get_input_socket_reader(0);
}
-void SeparateChannelOperation::deinitExecution()
+void SeparateChannelOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
+ input_operation_ = nullptr;
}
-void SeparateChannelOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void SeparateChannelOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float input[4];
- this->m_inputOperation->readSampled(input, x, y, sampler);
- output[0] = input[this->m_channel];
+ input_operation_->read_sampled(input, x, y, sampler);
+ output[0] = input[channel_];
}
void SeparateChannelOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -574,7 +564,7 @@ void SeparateChannelOperation::update_memory_buffer_partial(MemoryBuffer *output
Span<MemoryBuffer *> inputs)
{
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
- it.out[0] = it.in(0)[this->m_channel];
+ it.out[0] = it.in(0)[channel_];
}
}
@@ -582,54 +572,54 @@ void SeparateChannelOperation::update_memory_buffer_partial(MemoryBuffer *output
CombineChannelsOperation::CombineChannelsOperation()
{
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
this->set_canvas_input_index(0);
- this->m_inputChannel1Operation = nullptr;
- this->m_inputChannel2Operation = nullptr;
- this->m_inputChannel3Operation = nullptr;
- this->m_inputChannel4Operation = nullptr;
+ input_channel1_operation_ = nullptr;
+ input_channel2_operation_ = nullptr;
+ input_channel3_operation_ = nullptr;
+ input_channel4_operation_ = nullptr;
}
-void CombineChannelsOperation::initExecution()
+void CombineChannelsOperation::init_execution()
{
- this->m_inputChannel1Operation = this->getInputSocketReader(0);
- this->m_inputChannel2Operation = this->getInputSocketReader(1);
- this->m_inputChannel3Operation = this->getInputSocketReader(2);
- this->m_inputChannel4Operation = this->getInputSocketReader(3);
+ input_channel1_operation_ = this->get_input_socket_reader(0);
+ input_channel2_operation_ = this->get_input_socket_reader(1);
+ input_channel3_operation_ = this->get_input_socket_reader(2);
+ input_channel4_operation_ = this->get_input_socket_reader(3);
}
-void CombineChannelsOperation::deinitExecution()
+void CombineChannelsOperation::deinit_execution()
{
- this->m_inputChannel1Operation = nullptr;
- this->m_inputChannel2Operation = nullptr;
- this->m_inputChannel3Operation = nullptr;
- this->m_inputChannel4Operation = nullptr;
+ input_channel1_operation_ = nullptr;
+ input_channel2_operation_ = nullptr;
+ input_channel3_operation_ = nullptr;
+ input_channel4_operation_ = nullptr;
}
-void CombineChannelsOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void CombineChannelsOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float input[4];
- if (this->m_inputChannel1Operation) {
- this->m_inputChannel1Operation->readSampled(input, x, y, sampler);
+ if (input_channel1_operation_) {
+ input_channel1_operation_->read_sampled(input, x, y, sampler);
output[0] = input[0];
}
- if (this->m_inputChannel2Operation) {
- this->m_inputChannel2Operation->readSampled(input, x, y, sampler);
+ if (input_channel2_operation_) {
+ input_channel2_operation_->read_sampled(input, x, y, sampler);
output[1] = input[0];
}
- if (this->m_inputChannel3Operation) {
- this->m_inputChannel3Operation->readSampled(input, x, y, sampler);
+ if (input_channel3_operation_) {
+ input_channel3_operation_->read_sampled(input, x, y, sampler);
output[2] = input[0];
}
- if (this->m_inputChannel4Operation) {
- this->m_inputChannel4Operation->readSampled(input, x, y, sampler);
+ if (input_channel4_operation_) {
+ input_channel4_operation_->read_sampled(input, x, y, sampler);
output[3] = input[0];
}
}
diff --git a/source/blender/compositor/operations/COM_ConvertOperation.h b/source/blender/compositor/operations/COM_ConvertOperation.h
index 72864b3c5e2..3c4ce358eec 100644
--- a/source/blender/compositor/operations/COM_ConvertOperation.h
+++ b/source/blender/compositor/operations/COM_ConvertOperation.h
@@ -24,13 +24,13 @@ namespace blender::compositor {
class ConvertBaseOperation : public MultiThreadedOperation {
protected:
- SocketReader *m_inputOperation;
+ SocketReader *input_operation_;
public:
ConvertBaseOperation();
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
@@ -45,7 +45,7 @@ class ConvertValueToColorOperation : public ConvertBaseOperation {
public:
ConvertValueToColorOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -55,7 +55,7 @@ class ConvertColorToValueOperation : public ConvertBaseOperation {
public:
ConvertColorToValueOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -65,7 +65,7 @@ class ConvertColorToBWOperation : public ConvertBaseOperation {
public:
ConvertColorToBWOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -75,7 +75,7 @@ class ConvertColorToVectorOperation : public ConvertBaseOperation {
public:
ConvertColorToVectorOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -85,7 +85,7 @@ class ConvertValueToVectorOperation : public ConvertBaseOperation {
public:
ConvertValueToVectorOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -95,7 +95,7 @@ class ConvertVectorToColorOperation : public ConvertBaseOperation {
public:
ConvertVectorToColorOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -105,7 +105,7 @@ class ConvertVectorToValueOperation : public ConvertBaseOperation {
public:
ConvertVectorToValueOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -114,15 +114,15 @@ class ConvertVectorToValueOperation : public ConvertBaseOperation {
class ConvertRGBToYCCOperation : public ConvertBaseOperation {
private:
/** YCbCr mode (Jpeg, ITU601, ITU709) */
- int m_mode;
+ int mode_;
public:
ConvertRGBToYCCOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/** Set the YCC mode */
- void setMode(int mode);
+ void set_mode(int mode);
protected:
void hash_output_params() override;
@@ -132,15 +132,15 @@ class ConvertRGBToYCCOperation : public ConvertBaseOperation {
class ConvertYCCToRGBOperation : public ConvertBaseOperation {
private:
/** YCbCr mode (Jpeg, ITU601, ITU709) */
- int m_mode;
+ int mode_;
public:
ConvertYCCToRGBOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/** Set the YCC mode */
- void setMode(int mode);
+ void set_mode(int mode);
protected:
void hash_output_params() override;
@@ -151,7 +151,7 @@ class ConvertRGBToYUVOperation : public ConvertBaseOperation {
public:
ConvertRGBToYUVOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -161,7 +161,7 @@ class ConvertYUVToRGBOperation : public ConvertBaseOperation {
public:
ConvertYUVToRGBOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -171,7 +171,7 @@ class ConvertRGBToHSVOperation : public ConvertBaseOperation {
public:
ConvertRGBToHSVOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -181,7 +181,7 @@ class ConvertHSVToRGBOperation : public ConvertBaseOperation {
public:
ConvertHSVToRGBOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -191,7 +191,7 @@ class ConvertPremulToStraightOperation : public ConvertBaseOperation {
public:
ConvertPremulToStraightOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -201,7 +201,7 @@ class ConvertStraightToPremulOperation : public ConvertBaseOperation {
public:
ConvertStraightToPremulOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -209,19 +209,19 @@ class ConvertStraightToPremulOperation : public ConvertBaseOperation {
class SeparateChannelOperation : public MultiThreadedOperation {
private:
- SocketReader *m_inputOperation;
- int m_channel;
+ SocketReader *input_operation_;
+ int channel_;
public:
SeparateChannelOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void setChannel(int channel)
+ void set_channel(int channel)
{
- this->m_channel = channel;
+ channel_ = channel;
}
void update_memory_buffer_partial(MemoryBuffer *output,
@@ -231,17 +231,17 @@ class SeparateChannelOperation : public MultiThreadedOperation {
class CombineChannelsOperation : public MultiThreadedOperation {
private:
- SocketReader *m_inputChannel1Operation;
- SocketReader *m_inputChannel2Operation;
- SocketReader *m_inputChannel3Operation;
- SocketReader *m_inputChannel4Operation;
+ SocketReader *input_channel1_operation_;
+ SocketReader *input_channel2_operation_;
+ SocketReader *input_channel3_operation_;
+ SocketReader *input_channel4_operation_;
public:
CombineChannelsOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc
index 9127a871b04..7ba1f0bbe14 100644
--- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc
+++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc
@@ -17,11 +17,10 @@
*/
#include "COM_ConvolutionEdgeFilterOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
-void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y, void * /*data*/)
+void ConvolutionEdgeFilterOperation::execute_pixel(float output[4], int x, int y, void * /*data*/)
{
float in1[4], in2[4], res1[4] = {0.0}, res2[4] = {0.0};
@@ -31,52 +30,52 @@ void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y,
int y1 = y - 1;
int y2 = y;
int y3 = y + 1;
- CLAMP(x1, 0, getWidth() - 1);
- CLAMP(x2, 0, getWidth() - 1);
- CLAMP(x3, 0, getWidth() - 1);
- CLAMP(y1, 0, getHeight() - 1);
- CLAMP(y2, 0, getHeight() - 1);
- CLAMP(y3, 0, getHeight() - 1);
+ CLAMP(x1, 0, get_width() - 1);
+ CLAMP(x2, 0, get_width() - 1);
+ CLAMP(x3, 0, get_width() - 1);
+ CLAMP(y1, 0, get_height() - 1);
+ CLAMP(y2, 0, get_height() - 1);
+ CLAMP(y3, 0, get_height() - 1);
float value[4];
- this->m_inputValueOperation->read(value, x2, y2, nullptr);
+ input_value_operation_->read(value, x2, y2, nullptr);
float mval = 1.0f - value[0];
- this->m_inputOperation->read(in1, x1, y1, nullptr);
- madd_v3_v3fl(res1, in1, this->m_filter[0]);
- madd_v3_v3fl(res2, in1, this->m_filter[0]);
+ input_operation_->read(in1, x1, y1, nullptr);
+ madd_v3_v3fl(res1, in1, filter_[0]);
+ madd_v3_v3fl(res2, in1, filter_[0]);
- this->m_inputOperation->read(in1, x2, y1, nullptr);
- madd_v3_v3fl(res1, in1, this->m_filter[1]);
- madd_v3_v3fl(res2, in1, this->m_filter[3]);
+ input_operation_->read(in1, x2, y1, nullptr);
+ madd_v3_v3fl(res1, in1, filter_[1]);
+ madd_v3_v3fl(res2, in1, filter_[3]);
- this->m_inputOperation->read(in1, x3, y1, nullptr);
- madd_v3_v3fl(res1, in1, this->m_filter[2]);
- madd_v3_v3fl(res2, in1, this->m_filter[6]);
+ input_operation_->read(in1, x3, y1, nullptr);
+ madd_v3_v3fl(res1, in1, filter_[2]);
+ madd_v3_v3fl(res2, in1, filter_[6]);
- this->m_inputOperation->read(in1, x1, y2, nullptr);
- madd_v3_v3fl(res1, in1, this->m_filter[3]);
- madd_v3_v3fl(res2, in1, this->m_filter[1]);
+ input_operation_->read(in1, x1, y2, nullptr);
+ madd_v3_v3fl(res1, in1, filter_[3]);
+ madd_v3_v3fl(res2, in1, filter_[1]);
- this->m_inputOperation->read(in2, x2, y2, nullptr);
- madd_v3_v3fl(res1, in2, this->m_filter[4]);
- madd_v3_v3fl(res2, in2, this->m_filter[4]);
+ input_operation_->read(in2, x2, y2, nullptr);
+ madd_v3_v3fl(res1, in2, filter_[4]);
+ madd_v3_v3fl(res2, in2, filter_[4]);
- this->m_inputOperation->read(in1, x3, y2, nullptr);
- madd_v3_v3fl(res1, in1, this->m_filter[5]);
- madd_v3_v3fl(res2, in1, this->m_filter[7]);
+ input_operation_->read(in1, x3, y2, nullptr);
+ madd_v3_v3fl(res1, in1, filter_[5]);
+ madd_v3_v3fl(res2, in1, filter_[7]);
- this->m_inputOperation->read(in1, x1, y3, nullptr);
- madd_v3_v3fl(res1, in1, this->m_filter[6]);
- madd_v3_v3fl(res2, in1, this->m_filter[2]);
+ input_operation_->read(in1, x1, y3, nullptr);
+ madd_v3_v3fl(res1, in1, filter_[6]);
+ madd_v3_v3fl(res2, in1, filter_[2]);
- this->m_inputOperation->read(in1, x2, y3, nullptr);
- madd_v3_v3fl(res1, in1, this->m_filter[7]);
- madd_v3_v3fl(res2, in1, this->m_filter[5]);
+ input_operation_->read(in1, x2, y3, nullptr);
+ madd_v3_v3fl(res1, in1, filter_[7]);
+ madd_v3_v3fl(res2, in1, filter_[5]);
- this->m_inputOperation->read(in1, x3, y3, nullptr);
- madd_v3_v3fl(res1, in1, this->m_filter[8]);
- madd_v3_v3fl(res2, in1, this->m_filter[8]);
+ input_operation_->read(in1, x3, y3, nullptr);
+ madd_v3_v3fl(res1, in1, filter_[8]);
+ madd_v3_v3fl(res2, in1, filter_[8]);
output[0] = sqrt(res1[0] * res1[0] + res2[0] * res2[0]);
output[1] = sqrt(res1[1] * res1[1] + res2[1] * res2[1]);
@@ -100,8 +99,8 @@ void ConvolutionEdgeFilterOperation::update_memory_buffer_partial(MemoryBuffer *
Span<MemoryBuffer *> inputs)
{
const MemoryBuffer *image = inputs[IMAGE_INPUT_INDEX];
- const int last_x = getWidth() - 1;
- const int last_y = getHeight() - 1;
+ const int last_x = get_width() - 1;
+ const int last_y = get_height() - 1;
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
const int left_offset = (it.x == 0) ? 0 : -image->elem_stride;
const int right_offset = (it.x == last_x) ? 0 : image->elem_stride;
@@ -113,44 +112,44 @@ void ConvolutionEdgeFilterOperation::update_memory_buffer_partial(MemoryBuffer *
float res2[4] = {0};
const float *color = center_color + down_offset + left_offset;
- madd_v3_v3fl(res1, color, m_filter[0]);
+ madd_v3_v3fl(res1, color, filter_[0]);
copy_v3_v3(res2, res1);
color = center_color + down_offset;
- madd_v3_v3fl(res1, color, m_filter[1]);
- madd_v3_v3fl(res2, color, m_filter[3]);
+ madd_v3_v3fl(res1, color, filter_[1]);
+ madd_v3_v3fl(res2, color, filter_[3]);
color = center_color + down_offset + right_offset;
- madd_v3_v3fl(res1, color, m_filter[2]);
- madd_v3_v3fl(res2, color, m_filter[6]);
+ madd_v3_v3fl(res1, color, filter_[2]);
+ madd_v3_v3fl(res2, color, filter_[6]);
color = center_color + left_offset;
- madd_v3_v3fl(res1, color, m_filter[3]);
- madd_v3_v3fl(res2, color, m_filter[1]);
+ madd_v3_v3fl(res1, color, filter_[3]);
+ madd_v3_v3fl(res2, color, filter_[1]);
{
float rgb_filtered[3];
- mul_v3_v3fl(rgb_filtered, center_color, m_filter[4]);
+ mul_v3_v3fl(rgb_filtered, center_color, filter_[4]);
add_v3_v3(res1, rgb_filtered);
add_v3_v3(res2, rgb_filtered);
}
color = center_color + right_offset;
- madd_v3_v3fl(res1, color, m_filter[5]);
- madd_v3_v3fl(res2, color, m_filter[7]);
+ madd_v3_v3fl(res1, color, filter_[5]);
+ madd_v3_v3fl(res2, color, filter_[7]);
color = center_color + up_offset + left_offset;
- madd_v3_v3fl(res1, color, m_filter[6]);
- madd_v3_v3fl(res2, color, m_filter[2]);
+ madd_v3_v3fl(res1, color, filter_[6]);
+ madd_v3_v3fl(res2, color, filter_[2]);
color = center_color + up_offset;
- madd_v3_v3fl(res1, color, m_filter[7]);
- madd_v3_v3fl(res2, color, m_filter[5]);
+ madd_v3_v3fl(res1, color, filter_[7]);
+ madd_v3_v3fl(res2, color, filter_[5]);
{
color = center_color + up_offset + right_offset;
float rgb_filtered[3];
- mul_v3_v3fl(rgb_filtered, color, m_filter[8]);
+ mul_v3_v3fl(rgb_filtered, color, filter_[8]);
add_v3_v3(res1, rgb_filtered);
add_v3_v3(res2, rgb_filtered);
}
@@ -160,10 +159,10 @@ void ConvolutionEdgeFilterOperation::update_memory_buffer_partial(MemoryBuffer *
it.out[2] = sqrt(res1[2] * res1[2] + res2[2] * res2[2]);
const float factor = *it.in(FACTOR_INPUT_INDEX);
- const float m_factor = 1.0f - factor;
- it.out[0] = it.out[0] * factor + center_color[0] * m_factor;
- it.out[1] = it.out[1] * factor + center_color[1] * m_factor;
- it.out[2] = it.out[2] * factor + center_color[2] * m_factor;
+ const float factor_ = 1.0f - factor;
+ it.out[0] = it.out[0] * factor + center_color[0] * factor_;
+ it.out[1] = it.out[1] * factor + center_color[1] * factor_;
+ it.out[2] = it.out[2] * factor + center_color[2] * factor_;
it.out[3] = center_color[3];
diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.h b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.h
index bd38e27165a..a89a9412cf2 100644
--- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.h
+++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.h
@@ -24,7 +24,7 @@ namespace blender::compositor {
class ConvolutionEdgeFilterOperation : public ConvolutionFilterOperation {
public:
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc
index 807223fd45f..2e9990348c1 100644
--- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc
+++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc
@@ -18,50 +18,46 @@
#include "COM_ConvolutionFilterOperation.h"
-#include "BLI_utildefines.h"
-
-#include "MEM_guardedalloc.h"
-
namespace blender::compositor {
ConvolutionFilterOperation::ConvolutionFilterOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
this->set_canvas_input_index(0);
- this->m_inputOperation = nullptr;
- this->flags.complex = true;
+ input_operation_ = nullptr;
+ flags_.complex = true;
}
-void ConvolutionFilterOperation::initExecution()
+void ConvolutionFilterOperation::init_execution()
{
- this->m_inputOperation = this->getInputSocketReader(0);
- this->m_inputValueOperation = this->getInputSocketReader(1);
+ input_operation_ = this->get_input_socket_reader(0);
+ input_value_operation_ = this->get_input_socket_reader(1);
}
void ConvolutionFilterOperation::set3x3Filter(
float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9)
{
- this->m_filter[0] = f1;
- this->m_filter[1] = f2;
- this->m_filter[2] = f3;
- this->m_filter[3] = f4;
- this->m_filter[4] = f5;
- this->m_filter[5] = f6;
- this->m_filter[6] = f7;
- this->m_filter[7] = f8;
- this->m_filter[8] = f9;
- this->m_filterHeight = 3;
- this->m_filterWidth = 3;
+ filter_[0] = f1;
+ filter_[1] = f2;
+ filter_[2] = f3;
+ filter_[3] = f4;
+ filter_[4] = f5;
+ filter_[5] = f6;
+ filter_[6] = f7;
+ filter_[7] = f8;
+ filter_[8] = f9;
+ filter_height_ = 3;
+ filter_width_ = 3;
}
-void ConvolutionFilterOperation::deinitExecution()
+void ConvolutionFilterOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
- this->m_inputValueOperation = nullptr;
+ input_operation_ = nullptr;
+ input_value_operation_ = nullptr;
}
-void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, void * /*data*/)
+void ConvolutionFilterOperation::execute_pixel(float output[4], int x, int y, void * /*data*/)
{
float in1[4];
float in2[4];
@@ -71,35 +67,35 @@ void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, voi
int y1 = y - 1;
int y2 = y;
int y3 = y + 1;
- CLAMP(x1, 0, getWidth() - 1);
- CLAMP(x2, 0, getWidth() - 1);
- CLAMP(x3, 0, getWidth() - 1);
- CLAMP(y1, 0, getHeight() - 1);
- CLAMP(y2, 0, getHeight() - 1);
- CLAMP(y3, 0, getHeight() - 1);
+ CLAMP(x1, 0, get_width() - 1);
+ CLAMP(x2, 0, get_width() - 1);
+ CLAMP(x3, 0, get_width() - 1);
+ CLAMP(y1, 0, get_height() - 1);
+ CLAMP(y2, 0, get_height() - 1);
+ CLAMP(y3, 0, get_height() - 1);
float value[4];
- this->m_inputValueOperation->read(value, x2, y2, nullptr);
+ input_value_operation_->read(value, x2, y2, nullptr);
const float mval = 1.0f - value[0];
zero_v4(output);
- this->m_inputOperation->read(in1, x1, y1, nullptr);
- madd_v4_v4fl(output, in1, this->m_filter[0]);
- this->m_inputOperation->read(in1, x2, y1, nullptr);
- madd_v4_v4fl(output, in1, this->m_filter[1]);
- this->m_inputOperation->read(in1, x3, y1, nullptr);
- madd_v4_v4fl(output, in1, this->m_filter[2]);
- this->m_inputOperation->read(in1, x1, y2, nullptr);
- madd_v4_v4fl(output, in1, this->m_filter[3]);
- this->m_inputOperation->read(in2, x2, y2, nullptr);
- madd_v4_v4fl(output, in2, this->m_filter[4]);
- this->m_inputOperation->read(in1, x3, y2, nullptr);
- madd_v4_v4fl(output, in1, this->m_filter[5]);
- this->m_inputOperation->read(in1, x1, y3, nullptr);
- madd_v4_v4fl(output, in1, this->m_filter[6]);
- this->m_inputOperation->read(in1, x2, y3, nullptr);
- madd_v4_v4fl(output, in1, this->m_filter[7]);
- this->m_inputOperation->read(in1, x3, y3, nullptr);
- madd_v4_v4fl(output, in1, this->m_filter[8]);
+ input_operation_->read(in1, x1, y1, nullptr);
+ madd_v4_v4fl(output, in1, filter_[0]);
+ input_operation_->read(in1, x2, y1, nullptr);
+ madd_v4_v4fl(output, in1, filter_[1]);
+ input_operation_->read(in1, x3, y1, nullptr);
+ madd_v4_v4fl(output, in1, filter_[2]);
+ input_operation_->read(in1, x1, y2, nullptr);
+ madd_v4_v4fl(output, in1, filter_[3]);
+ input_operation_->read(in2, x2, y2, nullptr);
+ madd_v4_v4fl(output, in2, filter_[4]);
+ input_operation_->read(in1, x3, y2, nullptr);
+ madd_v4_v4fl(output, in1, filter_[5]);
+ input_operation_->read(in1, x1, y3, nullptr);
+ madd_v4_v4fl(output, in1, filter_[6]);
+ input_operation_->read(in1, x2, y3, nullptr);
+ madd_v4_v4fl(output, in1, filter_[7]);
+ input_operation_->read(in1, x3, y3, nullptr);
+ madd_v4_v4fl(output, in1, filter_[8]);
output[0] = output[0] * value[0] + in2[0] * mval;
output[1] = output[1] * value[0] + in2[1] * mval;
@@ -113,18 +109,18 @@ void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, voi
output[3] = MAX2(output[3], 0.0f);
}
-bool ConvolutionFilterOperation::determineDependingAreaOfInterest(
- rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool ConvolutionFilterOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
- int addx = (this->m_filterWidth - 1) / 2 + 1;
- int addy = (this->m_filterHeight - 1) / 2 + 1;
- newInput.xmax = input->xmax + addx;
- newInput.xmin = input->xmin - addx;
- newInput.ymax = input->ymax + addy;
- newInput.ymin = input->ymin - addy;
-
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ rcti new_input;
+ int addx = (filter_width_ - 1) / 2 + 1;
+ int addy = (filter_height_ - 1) / 2 + 1;
+ new_input.xmax = input->xmax + addx;
+ new_input.xmin = input->xmin - addx;
+ new_input.ymax = input->ymax + addy;
+ new_input.ymin = input->ymin - addy;
+
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void ConvolutionFilterOperation::get_area_of_interest(const int input_idx,
@@ -133,8 +129,8 @@ void ConvolutionFilterOperation::get_area_of_interest(const int input_idx,
{
switch (input_idx) {
case IMAGE_INPUT_INDEX: {
- const int add_x = (m_filterWidth - 1) / 2 + 1;
- const int add_y = (m_filterHeight - 1) / 2 + 1;
+ const int add_x = (filter_width_ - 1) / 2 + 1;
+ const int add_y = (filter_height_ - 1) / 2 + 1;
r_input_area.xmin = output_area.xmin - add_x;
r_input_area.xmax = output_area.xmax + add_x;
r_input_area.ymin = output_area.ymin - add_y;
@@ -153,8 +149,8 @@ void ConvolutionFilterOperation::update_memory_buffer_partial(MemoryBuffer *outp
Span<MemoryBuffer *> inputs)
{
const MemoryBuffer *image = inputs[IMAGE_INPUT_INDEX];
- const int last_x = getWidth() - 1;
- const int last_y = getHeight() - 1;
+ const int last_x = get_width() - 1;
+ const int last_y = get_height() - 1;
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
const int left_offset = (it.x == 0) ? 0 : -image->elem_stride;
const int right_offset = (it.x == last_x) ? 0 : image->elem_stride;
@@ -163,22 +159,22 @@ void ConvolutionFilterOperation::update_memory_buffer_partial(MemoryBuffer *outp
const float *center_color = it.in(IMAGE_INPUT_INDEX);
zero_v4(it.out);
- madd_v4_v4fl(it.out, center_color + down_offset + left_offset, m_filter[0]);
- madd_v4_v4fl(it.out, center_color + down_offset, m_filter[1]);
- madd_v4_v4fl(it.out, center_color + down_offset + right_offset, m_filter[2]);
- madd_v4_v4fl(it.out, center_color + left_offset, m_filter[3]);
- madd_v4_v4fl(it.out, center_color, m_filter[4]);
- madd_v4_v4fl(it.out, center_color + right_offset, m_filter[5]);
- madd_v4_v4fl(it.out, center_color + up_offset + left_offset, m_filter[6]);
- madd_v4_v4fl(it.out, center_color + up_offset, m_filter[7]);
- madd_v4_v4fl(it.out, center_color + up_offset + right_offset, m_filter[8]);
+ madd_v4_v4fl(it.out, center_color + down_offset + left_offset, filter_[0]);
+ madd_v4_v4fl(it.out, center_color + down_offset, filter_[1]);
+ madd_v4_v4fl(it.out, center_color + down_offset + right_offset, filter_[2]);
+ madd_v4_v4fl(it.out, center_color + left_offset, filter_[3]);
+ madd_v4_v4fl(it.out, center_color, filter_[4]);
+ madd_v4_v4fl(it.out, center_color + right_offset, filter_[5]);
+ madd_v4_v4fl(it.out, center_color + up_offset + left_offset, filter_[6]);
+ madd_v4_v4fl(it.out, center_color + up_offset, filter_[7]);
+ madd_v4_v4fl(it.out, center_color + up_offset + right_offset, filter_[8]);
const float factor = *it.in(FACTOR_INPUT_INDEX);
- const float m_factor = 1.0f - factor;
- it.out[0] = it.out[0] * factor + center_color[0] * m_factor;
- it.out[1] = it.out[1] * factor + center_color[1] * m_factor;
- it.out[2] = it.out[2] * factor + center_color[2] * m_factor;
- it.out[3] = it.out[3] * factor + center_color[3] * m_factor;
+ const float factor_ = 1.0f - factor;
+ it.out[0] = it.out[0] * factor + center_color[0] * factor_;
+ it.out[1] = it.out[1] * factor + center_color[1] * factor_;
+ it.out[2] = it.out[2] * factor + center_color[2] * factor_;
+ it.out[3] = it.out[3] * factor + center_color[3] * factor_;
/* Make sure we don't return negative color. */
CLAMP4_MIN(it.out, 0.0f);
diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.h b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.h
index 7e12c7faa5c..d764c7c9081 100644
--- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.h
+++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.h
@@ -28,25 +28,25 @@ class ConvolutionFilterOperation : public MultiThreadedOperation {
static constexpr int FACTOR_INPUT_INDEX = 1;
private:
- int m_filterWidth;
- int m_filterHeight;
+ int filter_width_;
+ int filter_height_;
protected:
- SocketReader *m_inputOperation;
- SocketReader *m_inputValueOperation;
- float m_filter[9];
+ SocketReader *input_operation_;
+ SocketReader *input_value_operation_;
+ float filter_[9];
public:
ConvolutionFilterOperation();
void set3x3Filter(
float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9);
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
- void executePixel(float output[4], int x, int y, void *data) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) final;
virtual void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_CropOperation.cc b/source/blender/compositor/operations/COM_CropOperation.cc
index 6ac30c22ad1..2385a0b54ba 100644
--- a/source/blender/compositor/operations/COM_CropOperation.cc
+++ b/source/blender/compositor/operations/COM_CropOperation.cc
@@ -17,67 +17,66 @@
*/
#include "COM_CropOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
CropBaseOperation::CropBaseOperation()
{
- this->addInputSocket(DataType::Color, ResizeMode::Align);
- this->addOutputSocket(DataType::Color);
- this->m_inputOperation = nullptr;
- this->m_settings = nullptr;
+ this->add_input_socket(DataType::Color, ResizeMode::Align);
+ this->add_output_socket(DataType::Color);
+ input_operation_ = nullptr;
+ settings_ = nullptr;
}
-void CropBaseOperation::updateArea()
+void CropBaseOperation::update_area()
{
- SocketReader *inputReference = this->getInputSocketReader(0);
- float width = inputReference->getWidth();
- float height = inputReference->getHeight();
- NodeTwoXYs local_settings = *this->m_settings;
+ SocketReader *input_reference = this->get_input_socket_reader(0);
+ float width = input_reference->get_width();
+ float height = input_reference->get_height();
+ NodeTwoXYs local_settings = *settings_;
if (width > 0.0f && height > 0.0f) {
- if (this->m_relative) {
+ if (relative_) {
local_settings.x1 = width * local_settings.fac_x1;
local_settings.x2 = width * local_settings.fac_x2;
local_settings.y1 = height * local_settings.fac_y1;
local_settings.y2 = height * local_settings.fac_y2;
}
- if (width <= local_settings.x1 + 1) {
- local_settings.x1 = width - 1;
+ if (width < local_settings.x1) {
+ local_settings.x1 = width;
}
- if (height <= local_settings.y1 + 1) {
- local_settings.y1 = height - 1;
+ if (height < local_settings.y1) {
+ local_settings.y1 = height;
}
- if (width <= local_settings.x2 + 1) {
- local_settings.x2 = width - 1;
+ if (width < local_settings.x2) {
+ local_settings.x2 = width;
}
- if (height <= local_settings.y2 + 1) {
- local_settings.y2 = height - 1;
+ if (height < local_settings.y2) {
+ local_settings.y2 = height;
}
- this->m_xmax = MAX2(local_settings.x1, local_settings.x2) + 1;
- this->m_xmin = MIN2(local_settings.x1, local_settings.x2);
- this->m_ymax = MAX2(local_settings.y1, local_settings.y2) + 1;
- this->m_ymin = MIN2(local_settings.y1, local_settings.y2);
+ xmax_ = MAX2(local_settings.x1, local_settings.x2);
+ xmin_ = MIN2(local_settings.x1, local_settings.x2);
+ ymax_ = MAX2(local_settings.y1, local_settings.y2);
+ ymin_ = MIN2(local_settings.y1, local_settings.y2);
}
else {
- this->m_xmax = 0;
- this->m_xmin = 0;
- this->m_ymax = 0;
- this->m_ymin = 0;
+ xmax_ = 0;
+ xmin_ = 0;
+ ymax_ = 0;
+ ymin_ = 0;
}
}
-void CropBaseOperation::initExecution()
+void CropBaseOperation::init_execution()
{
- this->m_inputOperation = this->getInputSocketReader(0);
- updateArea();
+ input_operation_ = this->get_input_socket_reader(0);
+ update_area();
}
-void CropBaseOperation::deinitExecution()
+void CropBaseOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
+ input_operation_ = nullptr;
}
CropOperation::CropOperation() : CropBaseOperation()
@@ -85,10 +84,10 @@ CropOperation::CropOperation() : CropBaseOperation()
/* pass */
}
-void CropOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void CropOperation::execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler)
{
- if ((x < this->m_xmax && x >= this->m_xmin) && (y < this->m_ymax && y >= this->m_ymin)) {
- this->m_inputOperation->readSampled(output, x, y, sampler);
+ if ((x < xmax_ && x >= xmin_) && (y < ymax_ && y >= ymin_)) {
+ input_operation_->read_sampled(output, x, y, sampler);
}
else {
zero_v4(output);
@@ -99,10 +98,8 @@ void CropOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- rcti crop_area;
- BLI_rcti_init(&crop_area, m_xmin, m_xmax, m_ymin, m_ymax);
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
- if (BLI_rcti_isect_pt(&crop_area, it.x, it.y)) {
+ if ((it.x < xmax_ && it.x >= xmin_) && (it.y < ymax_ && it.y >= ymin_)) {
copy_v4_v4(it.out, it.in(0));
}
else {
@@ -116,18 +113,18 @@ CropImageOperation::CropImageOperation() : CropBaseOperation()
/* pass */
}
-bool CropImageOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool CropImageOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti newInput;
+ rcti new_input;
- newInput.xmax = input->xmax + this->m_xmin;
- newInput.xmin = input->xmin + this->m_xmin;
- newInput.ymax = input->ymax + this->m_ymin;
- newInput.ymin = input->ymin + this->m_ymin;
+ new_input.xmax = input->xmax + xmin_;
+ new_input.xmin = input->xmin + xmin_;
+ new_input.ymax = input->ymax + ymin_;
+ new_input.ymin = input->ymin + ymin_;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void CropImageOperation::get_area_of_interest(const int input_idx,
@@ -136,27 +133,27 @@ void CropImageOperation::get_area_of_interest(const int input_idx,
{
BLI_assert(input_idx == 0);
UNUSED_VARS_NDEBUG(input_idx);
- r_input_area.xmax = output_area.xmax + this->m_xmin;
- r_input_area.xmin = output_area.xmin + this->m_xmin;
- r_input_area.ymax = output_area.ymax + this->m_ymin;
- r_input_area.ymin = output_area.ymin + this->m_ymin;
+ r_input_area.xmax = output_area.xmax + xmin_;
+ r_input_area.xmin = output_area.xmin + xmin_;
+ r_input_area.ymax = output_area.ymax + ymin_;
+ r_input_area.ymin = output_area.ymin + ymin_;
}
void CropImageOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
NodeOperation::determine_canvas(preferred_area, r_area);
- updateArea();
- r_area.xmax = r_area.xmin + (m_xmax - m_xmin);
- r_area.ymax = r_area.ymin + (m_ymax - m_ymin);
+ update_area();
+ r_area.xmax = r_area.xmin + (xmax_ - xmin_);
+ r_area.ymax = r_area.ymin + (ymax_ - ymin_);
}
-void CropImageOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void CropImageOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
- this->m_inputOperation->readSampled(output, (x + this->m_xmin), (y + this->m_ymin), sampler);
+ if (x >= 0 && x < get_width() && y >= 0 && y < get_height()) {
+ input_operation_->read_sampled(output, (x + xmin_), (y + ymin_), sampler);
}
else {
zero_v4(output);
@@ -167,12 +164,12 @@ void CropImageOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- rcti op_area;
- BLI_rcti_init(&op_area, 0, getWidth(), 0, getHeight());
const MemoryBuffer *input = inputs[0];
+ const int width = get_width();
+ const int height = get_height();
for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
- if (BLI_rcti_isect_pt(&op_area, it.x, it.y)) {
- input->read_elem_checked(it.x + this->m_xmin, it.y + this->m_ymin, it.out);
+ if (it.x >= 0 && it.x < width && it.y >= 0 && it.y < height) {
+ input->read_elem_checked(it.x + xmin_, it.y + ymin_, it.out);
}
else {
zero_v4(it.out);
diff --git a/source/blender/compositor/operations/COM_CropOperation.h b/source/blender/compositor/operations/COM_CropOperation.h
index a156727402b..69bfd72b052 100644
--- a/source/blender/compositor/operations/COM_CropOperation.h
+++ b/source/blender/compositor/operations/COM_CropOperation.h
@@ -24,27 +24,27 @@ namespace blender::compositor {
class CropBaseOperation : public MultiThreadedOperation {
protected:
- SocketReader *m_inputOperation;
- NodeTwoXYs *m_settings;
- bool m_relative;
- int m_xmax;
- int m_xmin;
- int m_ymax;
- int m_ymin;
+ SocketReader *input_operation_;
+ NodeTwoXYs *settings_;
+ bool relative_;
+ int xmax_;
+ int xmin_;
+ int ymax_;
+ int ymin_;
- void updateArea();
+ void update_area();
public:
CropBaseOperation();
- void initExecution() override;
- void deinitExecution() override;
- void setCropSettings(NodeTwoXYs *settings)
+ void init_execution() override;
+ void deinit_execution() override;
+ void set_crop_settings(NodeTwoXYs *settings)
{
- this->m_settings = settings;
+ settings_ = settings;
}
- void setRelative(bool rel)
+ void set_relative(bool rel)
{
- this->m_relative = rel;
+ relative_ = rel;
}
};
@@ -52,7 +52,7 @@ class CropOperation : public CropBaseOperation {
private:
public:
CropOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
@@ -63,11 +63,11 @@ class CropImageOperation : public CropBaseOperation {
private:
public:
CropImageOperation();
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.cc b/source/blender/compositor/operations/COM_CryptomatteOperation.cc
index 02e7c5607d8..8a246269691 100644
--- a/source/blender/compositor/operations/COM_CryptomatteOperation.cc
+++ b/source/blender/compositor/operations/COM_CryptomatteOperation.cc
@@ -24,27 +24,27 @@ CryptomatteOperation::CryptomatteOperation(size_t num_inputs)
{
inputs.resize(num_inputs);
for (size_t i = 0; i < num_inputs; i++) {
- this->addInputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
}
- this->addOutputSocket(DataType::Color);
- this->flags.complex = true;
+ this->add_output_socket(DataType::Color);
+ flags_.complex = true;
}
-void CryptomatteOperation::initExecution()
+void CryptomatteOperation::init_execution()
{
for (size_t i = 0; i < inputs.size(); i++) {
- inputs[i] = this->getInputSocketReader(i);
+ inputs[i] = this->get_input_socket_reader(i);
}
}
-void CryptomatteOperation::addObjectIndex(float objectIndex)
+void CryptomatteOperation::add_object_index(float object_index)
{
- if (objectIndex != 0.0f) {
- m_objectIndex.append(objectIndex);
+ if (object_index != 0.0f) {
+ object_index_.append(object_index);
}
}
-void CryptomatteOperation::executePixel(float output[4], int x, int y, void *data)
+void CryptomatteOperation::execute_pixel(float output[4], int x, int y, void *data)
{
float input[4];
output[0] = output[1] = output[2] = output[3] = 0.0f;
@@ -60,7 +60,7 @@ void CryptomatteOperation::executePixel(float output[4], int x, int y, void *dat
output[1] = ((float)(m3hash << 8) / (float)UINT32_MAX);
output[2] = ((float)(m3hash << 16) / (float)UINT32_MAX);
}
- for (float hash : m_objectIndex) {
+ for (float hash : object_index_) {
if (input[0] == hash) {
output[3] += input[1];
}
@@ -89,7 +89,7 @@ void CryptomatteOperation::update_memory_buffer_partial(MemoryBuffer *output,
it.out[1] = ((float)(m3hash << 8) / (float)UINT32_MAX);
it.out[2] = ((float)(m3hash << 16) / (float)UINT32_MAX);
}
- for (const float hash : m_objectIndex) {
+ for (const float hash : object_index_) {
if (input[0] == hash) {
it.out[3] += input[1];
}
diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.h b/source/blender/compositor/operations/COM_CryptomatteOperation.h
index f1bf4cdf624..2fa6fbc8390 100644
--- a/source/blender/compositor/operations/COM_CryptomatteOperation.h
+++ b/source/blender/compositor/operations/COM_CryptomatteOperation.h
@@ -24,17 +24,17 @@ namespace blender::compositor {
class CryptomatteOperation : public MultiThreadedOperation {
private:
- Vector<float> m_objectIndex;
+ Vector<float> object_index_;
public:
Vector<SocketReader *> inputs;
CryptomatteOperation(size_t num_inputs = 6);
- void initExecution() override;
- void executePixel(float output[4], int x, int y, void *data) override;
+ void init_execution() override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
- void addObjectIndex(float objectIndex);
+ void add_object_index(float object_index);
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.cc b/source/blender/compositor/operations/COM_CurveBaseOperation.cc
index 3c4b27aa4cf..a014fb17750 100644
--- a/source/blender/compositor/operations/COM_CurveBaseOperation.cc
+++ b/source/blender/compositor/operations/COM_CurveBaseOperation.cc
@@ -24,37 +24,37 @@ namespace blender::compositor {
CurveBaseOperation::CurveBaseOperation()
{
- this->m_curveMapping = nullptr;
- this->flags.can_be_constant = true;
+ curve_mapping_ = nullptr;
+ flags_.can_be_constant = true;
}
CurveBaseOperation::~CurveBaseOperation()
{
- if (this->m_curveMapping) {
- BKE_curvemapping_free(this->m_curveMapping);
- this->m_curveMapping = nullptr;
+ if (curve_mapping_) {
+ BKE_curvemapping_free(curve_mapping_);
+ curve_mapping_ = nullptr;
}
}
-void CurveBaseOperation::initExecution()
+void CurveBaseOperation::init_execution()
{
- BKE_curvemapping_init(this->m_curveMapping);
+ BKE_curvemapping_init(curve_mapping_);
}
-void CurveBaseOperation::deinitExecution()
+void CurveBaseOperation::deinit_execution()
{
- if (this->m_curveMapping) {
- BKE_curvemapping_free(this->m_curveMapping);
- this->m_curveMapping = nullptr;
+ if (curve_mapping_) {
+ BKE_curvemapping_free(curve_mapping_);
+ curve_mapping_ = nullptr;
}
}
-void CurveBaseOperation::setCurveMapping(CurveMapping *mapping)
+void CurveBaseOperation::set_curve_mapping(CurveMapping *mapping)
{
/* duplicate the curve to avoid glitches while drawing, see bug T32374. */
- if (this->m_curveMapping) {
- BKE_curvemapping_free(this->m_curveMapping);
+ if (curve_mapping_) {
+ BKE_curvemapping_free(curve_mapping_);
}
- this->m_curveMapping = BKE_curvemapping_copy(mapping);
+ curve_mapping_ = BKE_curvemapping_copy(mapping);
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.h b/source/blender/compositor/operations/COM_CurveBaseOperation.h
index da665e7ea60..d3548c36870 100644
--- a/source/blender/compositor/operations/COM_CurveBaseOperation.h
+++ b/source/blender/compositor/operations/COM_CurveBaseOperation.h
@@ -19,16 +19,17 @@
#pragma once
#include "COM_MultiThreadedOperation.h"
-#include "DNA_color_types.h"
+
+struct CurveMapping;
namespace blender::compositor {
class CurveBaseOperation : public MultiThreadedOperation {
protected:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- CurveMapping *m_curveMapping;
+ CurveMapping *curve_mapping_;
public:
CurveBaseOperation();
@@ -37,10 +38,10 @@ class CurveBaseOperation : public MultiThreadedOperation {
/**
* Initialize the execution
*/
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void setCurveMapping(CurveMapping *mapping);
+ void set_curve_mapping(CurveMapping *mapping);
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.cc b/source/blender/compositor/operations/COM_DenoiseOperation.cc
index f8a575acc3a..0174c50450c 100644
--- a/source/blender/compositor/operations/COM_DenoiseOperation.cc
+++ b/source/blender/compositor/operations/COM_DenoiseOperation.cc
@@ -17,14 +17,12 @@
*/
#include "COM_DenoiseOperation.h"
-#include "BLI_math.h"
#include "BLI_system.h"
#ifdef WITH_OPENIMAGEDENOISE
# include "BLI_threads.h"
# include <OpenImageDenoise/oidn.hpp>
static pthread_mutex_t oidn_lock = BLI_MUTEX_INITIALIZER;
#endif
-#include <iostream>
namespace blender::compositor {
@@ -46,8 +44,8 @@ bool COM_is_denoise_supported()
class DenoiseFilter {
private:
#ifdef WITH_OPENIMAGEDENOISE
- oidn::DeviceRef device;
- oidn::FilterRef filter;
+ oidn::DeviceRef device_;
+ oidn::FilterRef filter_;
#endif
bool initialized_ = false;
@@ -65,9 +63,10 @@ class DenoiseFilter {
* nonetheless. */
BLI_mutex_lock(&oidn_lock);
- device = oidn::newDevice();
- device.commit();
- filter = device.newFilter("RT");
+ device_ = oidn::newDevice();
+ device_.set("setAffinity", false);
+ device_.commit();
+ filter_ = device_.newFilter("RT");
initialized_ = true;
set_image("output", output);
}
@@ -82,26 +81,26 @@ class DenoiseFilter {
{
BLI_assert(initialized_);
BLI_assert(!buffer->is_a_single_elem());
- filter.setImage(name.data(),
- buffer->getBuffer(),
- oidn::Format::Float3,
- buffer->getWidth(),
- buffer->getHeight(),
- 0,
- buffer->get_elem_bytes_len());
+ filter_.setImage(name.data(),
+ buffer->get_buffer(),
+ oidn::Format::Float3,
+ buffer->get_width(),
+ buffer->get_height(),
+ 0,
+ buffer->get_elem_bytes_len());
}
template<typename T> void set(const StringRef option_name, T value)
{
BLI_assert(initialized_);
- filter.set(option_name.data(), value);
+ filter_.set(option_name.data(), value);
}
void execute()
{
BLI_assert(initialized_);
- filter.commit();
- filter.execute();
+ filter_.commit();
+ filter_.execute();
}
#else
@@ -129,24 +128,23 @@ class DenoiseFilter {
DenoiseBaseOperation::DenoiseBaseOperation()
{
- flags.is_fullframe_operation = true;
+ flags_.is_fullframe_operation = true;
output_rendered_ = false;
}
-bool DenoiseBaseOperation::determineDependingAreaOfInterest(rcti * /*input*/,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool DenoiseBaseOperation::determine_depending_area_of_interest(
+ rcti * /*input*/, ReadBufferOperation *read_operation, rcti *output)
{
- if (isCached()) {
+ if (is_cached()) {
return false;
}
- rcti newInput;
- newInput.xmax = this->getWidth();
- newInput.xmin = 0;
- newInput.ymax = this->getHeight();
- newInput.ymin = 0;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ rcti new_input;
+ new_input.xmax = this->get_width();
+ new_input.xmin = 0;
+ new_input.ymax = this->get_height();
+ new_input.ymin = 0;
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void DenoiseBaseOperation::get_area_of_interest(const int UNUSED(input_idx),
@@ -158,26 +156,26 @@ void DenoiseBaseOperation::get_area_of_interest(const int UNUSED(input_idx),
DenoiseOperation::DenoiseOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Vector);
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
- this->m_settings = nullptr;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Vector);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ settings_ = nullptr;
}
-void DenoiseOperation::initExecution()
+void DenoiseOperation::init_execution()
{
- SingleThreadedOperation::initExecution();
- this->m_inputProgramColor = getInputSocketReader(0);
- this->m_inputProgramNormal = getInputSocketReader(1);
- this->m_inputProgramAlbedo = getInputSocketReader(2);
+ SingleThreadedOperation::init_execution();
+ input_program_color_ = get_input_socket_reader(0);
+ input_program_normal_ = get_input_socket_reader(1);
+ input_program_albedo_ = get_input_socket_reader(2);
}
-void DenoiseOperation::deinitExecution()
+void DenoiseOperation::deinit_execution()
{
- this->m_inputProgramColor = nullptr;
- this->m_inputProgramNormal = nullptr;
- this->m_inputProgramAlbedo = nullptr;
- SingleThreadedOperation::deinitExecution();
+ input_program_color_ = nullptr;
+ input_program_normal_ = nullptr;
+ input_program_albedo_ = nullptr;
+ SingleThreadedOperation::deinit_execution();
}
static bool are_guiding_passes_noise_free(NodeDenoise *settings)
@@ -194,34 +192,34 @@ static bool are_guiding_passes_noise_free(NodeDenoise *settings)
void DenoiseOperation::hash_output_params()
{
- if (m_settings) {
- hash_params((int)m_settings->hdr, are_guiding_passes_noise_free(m_settings));
+ if (settings_) {
+ hash_params((int)settings_->hdr, are_guiding_passes_noise_free(settings_));
}
}
-MemoryBuffer *DenoiseOperation::createMemoryBuffer(rcti *rect2)
+MemoryBuffer *DenoiseOperation::create_memory_buffer(rcti *rect2)
{
- MemoryBuffer *tileColor = (MemoryBuffer *)this->m_inputProgramColor->initializeTileData(rect2);
- MemoryBuffer *tileNormal = (MemoryBuffer *)this->m_inputProgramNormal->initializeTileData(rect2);
- MemoryBuffer *tileAlbedo = (MemoryBuffer *)this->m_inputProgramAlbedo->initializeTileData(rect2);
+ MemoryBuffer *tile_color = (MemoryBuffer *)input_program_color_->initialize_tile_data(rect2);
+ MemoryBuffer *tile_normal = (MemoryBuffer *)input_program_normal_->initialize_tile_data(rect2);
+ MemoryBuffer *tile_albedo = (MemoryBuffer *)input_program_albedo_->initialize_tile_data(rect2);
rcti rect;
rect.xmin = 0;
rect.ymin = 0;
- rect.xmax = getWidth();
- rect.ymax = getHeight();
+ rect.xmax = get_width();
+ rect.ymax = get_height();
MemoryBuffer *result = new MemoryBuffer(DataType::Color, rect);
- this->generateDenoise(result, tileColor, tileNormal, tileAlbedo, this->m_settings);
+ this->generate_denoise(result, tile_color, tile_normal, tile_albedo, settings_);
return result;
}
-void DenoiseOperation::generateDenoise(MemoryBuffer *output,
- MemoryBuffer *input_color,
- MemoryBuffer *input_normal,
- MemoryBuffer *input_albedo,
- NodeDenoise *settings)
+void DenoiseOperation::generate_denoise(MemoryBuffer *output,
+ MemoryBuffer *input_color,
+ MemoryBuffer *input_normal,
+ MemoryBuffer *input_albedo,
+ NodeDenoise *settings)
{
- BLI_assert(input_color->getBuffer());
- if (!input_color->getBuffer()) {
+ BLI_assert(input_color->get_buffer());
+ if (!input_color->get_buffer()) {
return;
}
@@ -272,15 +270,15 @@ void DenoiseOperation::update_memory_buffer(MemoryBuffer *output,
Span<MemoryBuffer *> inputs)
{
if (!output_rendered_) {
- this->generateDenoise(output, inputs[0], inputs[1], inputs[2], m_settings);
+ this->generate_denoise(output, inputs[0], inputs[1], inputs[2], settings_);
output_rendered_ = true;
}
}
DenoisePrefilterOperation::DenoisePrefilterOperation(DataType data_type)
{
- this->addInputSocket(data_type);
- this->addOutputSocket(data_type);
+ this->add_input_socket(data_type);
+ this->add_output_socket(data_type);
image_name_ = "";
}
@@ -289,13 +287,13 @@ void DenoisePrefilterOperation::hash_output_params()
hash_param(image_name_);
}
-MemoryBuffer *DenoisePrefilterOperation::createMemoryBuffer(rcti *rect2)
+MemoryBuffer *DenoisePrefilterOperation::create_memory_buffer(rcti *rect2)
{
- MemoryBuffer *input = (MemoryBuffer *)this->get_input_operation(0)->initializeTileData(rect2);
+ MemoryBuffer *input = (MemoryBuffer *)this->get_input_operation(0)->initialize_tile_data(rect2);
rcti rect;
- BLI_rcti_init(&rect, 0, getWidth(), 0, getHeight());
+ BLI_rcti_init(&rect, 0, get_width(), 0, get_height());
- MemoryBuffer *result = new MemoryBuffer(getOutputSocket()->getDataType(), rect);
+ MemoryBuffer *result = new MemoryBuffer(get_output_socket()->get_data_type(), rect);
generate_denoise(result, input);
return result;
diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.h b/source/blender/compositor/operations/COM_DenoiseOperation.h
index 1b053b79c2d..a3eb1f57f2f 100644
--- a/source/blender/compositor/operations/COM_DenoiseOperation.h
+++ b/source/blender/compositor/operations/COM_DenoiseOperation.h
@@ -33,9 +33,9 @@ class DenoiseBaseOperation : public SingleThreadedOperation {
DenoiseBaseOperation();
public:
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
};
@@ -45,30 +45,30 @@ class DenoiseOperation : public DenoiseBaseOperation {
/**
* \brief Cached reference to the input programs
*/
- SocketReader *m_inputProgramColor;
- SocketReader *m_inputProgramAlbedo;
- SocketReader *m_inputProgramNormal;
+ SocketReader *input_program_color_;
+ SocketReader *input_program_albedo_;
+ SocketReader *input_program_normal_;
/**
* \brief settings of the denoise node.
*/
- NodeDenoise *m_settings;
+ NodeDenoise *settings_;
public:
DenoiseOperation();
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setDenoiseSettings(NodeDenoise *settings)
+ void set_denoise_settings(NodeDenoise *settings)
{
- this->m_settings = settings;
+ settings_ = settings;
}
void update_memory_buffer(MemoryBuffer *output,
@@ -77,13 +77,13 @@ class DenoiseOperation : public DenoiseBaseOperation {
protected:
void hash_output_params() override;
- void generateDenoise(MemoryBuffer *output,
- MemoryBuffer *input_color,
- MemoryBuffer *input_normal,
- MemoryBuffer *input_albedo,
- NodeDenoise *settings);
+ void generate_denoise(MemoryBuffer *output,
+ MemoryBuffer *input_color,
+ MemoryBuffer *input_normal,
+ MemoryBuffer *input_albedo,
+ NodeDenoise *settings);
- MemoryBuffer *createMemoryBuffer(rcti *rect) override;
+ MemoryBuffer *create_memory_buffer(rcti *rect) override;
};
class DenoisePrefilterOperation : public DenoiseBaseOperation {
@@ -104,7 +104,7 @@ class DenoisePrefilterOperation : public DenoiseBaseOperation {
protected:
void hash_output_params() override;
- MemoryBuffer *createMemoryBuffer(rcti *rect) override;
+ MemoryBuffer *create_memory_buffer(rcti *rect) override;
private:
void generate_denoise(MemoryBuffer *output, MemoryBuffer *input);
diff --git a/source/blender/compositor/operations/COM_DespeckleOperation.cc b/source/blender/compositor/operations/COM_DespeckleOperation.cc
index df637ee6709..c60a4167dfc 100644
--- a/source/blender/compositor/operations/COM_DespeckleOperation.cc
+++ b/source/blender/compositor/operations/COM_DespeckleOperation.cc
@@ -20,29 +20,27 @@
#include "COM_DespeckleOperation.h"
-#include "BLI_utildefines.h"
-
namespace blender::compositor {
DespeckleOperation::DespeckleOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
this->set_canvas_input_index(0);
- this->m_inputOperation = nullptr;
- this->flags.complex = true;
+ input_operation_ = nullptr;
+ flags_.complex = true;
}
-void DespeckleOperation::initExecution()
+void DespeckleOperation::init_execution()
{
- this->m_inputOperation = this->getInputSocketReader(0);
- this->m_inputValueOperation = this->getInputSocketReader(1);
+ input_operation_ = this->get_input_socket_reader(0);
+ input_value_operation_ = this->get_input_socket_reader(1);
}
-void DespeckleOperation::deinitExecution()
+void DespeckleOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
- this->m_inputValueOperation = nullptr;
+ input_operation_ = nullptr;
+ input_value_operation_ = nullptr;
}
BLI_INLINE int color_diff(const float a[3], const float b[3], const float threshold)
@@ -51,7 +49,7 @@ BLI_INLINE int color_diff(const float a[3], const float b[3], const float thresh
(fabsf(a[2] - b[2]) > threshold));
}
-void DespeckleOperation::executePixel(float output[4], int x, int y, void * /*data*/)
+void DespeckleOperation::execute_pixel(float output[4], int x, int y, void * /*data*/)
{
float w = 0.0f;
float color_org[4];
@@ -64,17 +62,17 @@ void DespeckleOperation::executePixel(float output[4], int x, int y, void * /*da
int y1 = y - 1;
int y2 = y;
int y3 = y + 1;
- CLAMP(x1, 0, getWidth() - 1);
- CLAMP(x2, 0, getWidth() - 1);
- CLAMP(x3, 0, getWidth() - 1);
- CLAMP(y1, 0, getHeight() - 1);
- CLAMP(y2, 0, getHeight() - 1);
- CLAMP(y3, 0, getHeight() - 1);
+ CLAMP(x1, 0, get_width() - 1);
+ CLAMP(x2, 0, get_width() - 1);
+ CLAMP(x3, 0, get_width() - 1);
+ CLAMP(y1, 0, get_height() - 1);
+ CLAMP(y2, 0, get_height() - 1);
+ CLAMP(y3, 0, get_height() - 1);
float value[4];
- this->m_inputValueOperation->read(value, x2, y2, nullptr);
+ input_value_operation_->read(value, x2, y2, nullptr);
// const float mval = 1.0f - value[0];
- this->m_inputOperation->read(color_org, x2, y2, nullptr);
+ input_operation_->read(color_org, x2, y2, nullptr);
#define TOT_DIV_ONE 1.0f
#define TOT_DIV_CNR (float)M_SQRT1_2
@@ -84,7 +82,7 @@ void DespeckleOperation::executePixel(float output[4], int x, int y, void * /*da
#define COLOR_ADD(fac) \
{ \
madd_v4_v4fl(color_mid, in1, fac); \
- if (color_diff(in1, color_org, this->m_threshold)) { \
+ if (color_diff(in1, color_org, threshold_)) { \
w += fac; \
madd_v4_v4fl(color_mid_ok, in1, fac); \
} \
@@ -93,34 +91,34 @@ void DespeckleOperation::executePixel(float output[4], int x, int y, void * /*da
zero_v4(color_mid);
zero_v4(color_mid_ok);
- this->m_inputOperation->read(in1, x1, y1, nullptr);
+ input_operation_->read(in1, x1, y1, nullptr);
COLOR_ADD(TOT_DIV_CNR)
- this->m_inputOperation->read(in1, x2, y1, nullptr);
+ input_operation_->read(in1, x2, y1, nullptr);
COLOR_ADD(TOT_DIV_ONE)
- this->m_inputOperation->read(in1, x3, y1, nullptr);
+ input_operation_->read(in1, x3, y1, nullptr);
COLOR_ADD(TOT_DIV_CNR)
- this->m_inputOperation->read(in1, x1, y2, nullptr);
+ input_operation_->read(in1, x1, y2, nullptr);
COLOR_ADD(TOT_DIV_ONE)
#if 0
- this->m_inputOperation->read(in2, x2, y2, nullptr);
- madd_v4_v4fl(color_mid, in2, this->m_filter[4]);
+ input_operation_->read(in2, x2, y2, nullptr);
+ madd_v4_v4fl(color_mid, in2, filter_[4]);
#endif
- this->m_inputOperation->read(in1, x3, y2, nullptr);
+ input_operation_->read(in1, x3, y2, nullptr);
COLOR_ADD(TOT_DIV_ONE)
- this->m_inputOperation->read(in1, x1, y3, nullptr);
+ input_operation_->read(in1, x1, y3, nullptr);
COLOR_ADD(TOT_DIV_CNR)
- this->m_inputOperation->read(in1, x2, y3, nullptr);
+ input_operation_->read(in1, x2, y3, nullptr);
COLOR_ADD(TOT_DIV_ONE)
- this->m_inputOperation->read(in1, x3, y3, nullptr);
+ input_operation_->read(in1, x3, y3, nullptr);
COLOR_ADD(TOT_DIV_CNR)
mul_v4_fl(color_mid, 1.0f / (4.0f + (4.0f * (float)M_SQRT1_2)));
// mul_v4_fl(color_mid, 1.0f / w);
- if ((w != 0.0f) && ((w / WTOT) > (this->m_threshold_neighbor)) &&
- color_diff(color_mid, color_org, this->m_threshold)) {
+ if ((w != 0.0f) && ((w / WTOT) > (threshold_neighbor_)) &&
+ color_diff(color_mid, color_org, threshold_)) {
mul_v4_fl(color_mid_ok, 1.0f / w);
interp_v4_v4v4(output, color_org, color_mid_ok, value[0]);
}
@@ -134,19 +132,19 @@ void DespeckleOperation::executePixel(float output[4], int x, int y, void * /*da
#undef COLOR_ADD
}
-bool DespeckleOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool DespeckleOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti newInput;
- int addx = 2; //(this->m_filterWidth - 1) / 2 + 1;
- int addy = 2; //(this->m_filterHeight - 1) / 2 + 1;
- newInput.xmax = input->xmax + addx;
- newInput.xmin = input->xmin - addx;
- newInput.ymax = input->ymax + addy;
- newInput.ymin = input->ymin - addy;
-
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ rcti new_input;
+ int addx = 2; //(filter_width_ - 1) / 2 + 1;
+ int addy = 2; //(filter_height_ - 1) / 2 + 1;
+ new_input.xmax = input->xmax + addx;
+ new_input.xmin = input->xmin - addx;
+ new_input.ymax = input->ymax + addy;
+ new_input.ymin = input->ymin - addy;
+
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void DespeckleOperation::get_area_of_interest(const int input_idx,
@@ -155,8 +153,8 @@ void DespeckleOperation::get_area_of_interest(const int input_idx,
{
switch (input_idx) {
case IMAGE_INPUT_INDEX: {
- const int add_x = 2; //(this->m_filterWidth - 1) / 2 + 1;
- const int add_y = 2; //(this->m_filterHeight - 1) / 2 + 1;
+ const int add_x = 2; //(filter_width_ - 1) / 2 + 1;
+ const int add_y = 2; //(filter_height_ - 1) / 2 + 1;
r_input_area.xmin = output_area.xmin - add_x;
r_input_area.xmax = output_area.xmax + add_x;
r_input_area.ymin = output_area.ymin - add_y;
@@ -175,8 +173,8 @@ void DespeckleOperation::update_memory_buffer_partial(MemoryBuffer *output,
Span<MemoryBuffer *> inputs)
{
const MemoryBuffer *image = inputs[IMAGE_INPUT_INDEX];
- const int last_x = getWidth() - 1;
- const int last_y = getHeight() - 1;
+ const int last_x = get_width() - 1;
+ const int last_y = get_height() - 1;
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
const int x1 = MAX2(it.x - 1, 0);
const int x2 = it.x;
@@ -199,7 +197,7 @@ void DespeckleOperation::update_memory_buffer_partial(MemoryBuffer *output,
#define COLOR_ADD(fac) \
{ \
madd_v4_v4fl(color_mid, in1, fac); \
- if (color_diff(in1, color_org, m_threshold)) { \
+ if (color_diff(in1, color_org, threshold_)) { \
w += fac; \
madd_v4_v4fl(color_mid_ok, in1, fac); \
} \
@@ -219,7 +217,7 @@ void DespeckleOperation::update_memory_buffer_partial(MemoryBuffer *output,
#if 0
const float* in2 = image->get_elem(x2, y2);
- madd_v4_v4fl(color_mid, in2, this->m_filter[4]);
+ madd_v4_v4fl(color_mid, in2, filter_[4]);
#endif
in1 = image->get_elem(x3, y2);
@@ -234,8 +232,8 @@ void DespeckleOperation::update_memory_buffer_partial(MemoryBuffer *output,
mul_v4_fl(color_mid, 1.0f / (4.0f + (4.0f * (float)M_SQRT1_2)));
// mul_v4_fl(color_mid, 1.0f / w);
- if ((w != 0.0f) && ((w / WTOT) > (m_threshold_neighbor)) &&
- color_diff(color_mid, color_org, m_threshold)) {
+ if ((w != 0.0f) && ((w / WTOT) > (threshold_neighbor_)) &&
+ color_diff(color_mid, color_org, threshold_)) {
const float factor = *it.in(FACTOR_INPUT_INDEX);
mul_v4_fl(color_mid_ok, 1.0f / w);
interp_v4_v4v4(it.out, color_org, color_mid_ok, factor);
diff --git a/source/blender/compositor/operations/COM_DespeckleOperation.h b/source/blender/compositor/operations/COM_DespeckleOperation.h
index 70d6c2227f4..bb5b012a330 100644
--- a/source/blender/compositor/operations/COM_DespeckleOperation.h
+++ b/source/blender/compositor/operations/COM_DespeckleOperation.h
@@ -27,34 +27,34 @@ class DespeckleOperation : public MultiThreadedOperation {
constexpr static int IMAGE_INPUT_INDEX = 0;
constexpr static int FACTOR_INPUT_INDEX = 1;
- float m_threshold;
- float m_threshold_neighbor;
+ float threshold_;
+ float threshold_neighbor_;
- // int m_filterWidth;
- // int m_filterHeight;
+ // int filter_width_;
+ // int filter_height_;
protected:
- SocketReader *m_inputOperation;
- SocketReader *m_inputValueOperation;
+ SocketReader *input_operation_;
+ SocketReader *input_value_operation_;
public:
DespeckleOperation();
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
- void executePixel(float output[4], int x, int y, void *data) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
- void setThreshold(float threshold)
+ void set_threshold(float threshold)
{
- this->m_threshold = threshold;
+ threshold_ = threshold;
}
- void setThresholdNeighbor(float threshold)
+ void set_threshold_neighbor(float threshold)
{
- this->m_threshold_neighbor = threshold;
+ threshold_neighbor_ = threshold;
}
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc
index 31714b03b06..251dc4cc161 100644
--- a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc
+++ b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc
@@ -17,50 +17,49 @@
*/
#include "COM_DifferenceMatteOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
DifferenceMatteOperation::DifferenceMatteOperation()
{
- addInputSocket(DataType::Color);
- addInputSocket(DataType::Color);
- addOutputSocket(DataType::Value);
+ add_input_socket(DataType::Color);
+ add_input_socket(DataType::Color);
+ add_output_socket(DataType::Value);
- this->m_inputImage1Program = nullptr;
- this->m_inputImage2Program = nullptr;
- flags.can_be_constant = true;
+ input_image1_program_ = nullptr;
+ input_image2_program_ = nullptr;
+ flags_.can_be_constant = true;
}
-void DifferenceMatteOperation::initExecution()
+void DifferenceMatteOperation::init_execution()
{
- this->m_inputImage1Program = this->getInputSocketReader(0);
- this->m_inputImage2Program = this->getInputSocketReader(1);
+ input_image1_program_ = this->get_input_socket_reader(0);
+ input_image2_program_ = this->get_input_socket_reader(1);
}
-void DifferenceMatteOperation::deinitExecution()
+void DifferenceMatteOperation::deinit_execution()
{
- this->m_inputImage1Program = nullptr;
- this->m_inputImage2Program = nullptr;
+ input_image1_program_ = nullptr;
+ input_image2_program_ = nullptr;
}
-void DifferenceMatteOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void DifferenceMatteOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inColor1[4];
- float inColor2[4];
+ float in_color1[4];
+ float in_color2[4];
- const float tolerance = this->m_settings->t1;
- const float falloff = this->m_settings->t2;
+ const float tolerance = settings_->t1;
+ const float falloff = settings_->t2;
float difference;
float alpha;
- this->m_inputImage1Program->readSampled(inColor1, x, y, sampler);
- this->m_inputImage2Program->readSampled(inColor2, x, y, sampler);
+ input_image1_program_->read_sampled(in_color1, x, y, sampler);
+ input_image2_program_->read_sampled(in_color2, x, y, sampler);
- difference = (fabsf(inColor2[0] - inColor1[0]) + fabsf(inColor2[1] - inColor1[1]) +
- fabsf(inColor2[2] - inColor1[2]));
+ difference = (fabsf(in_color2[0] - in_color1[0]) + fabsf(in_color2[1] - in_color1[1]) +
+ fabsf(in_color2[2] - in_color1[2]));
/* average together the distances */
difference = difference / 3.0f;
@@ -74,16 +73,16 @@ void DifferenceMatteOperation::executePixelSampled(float output[4],
difference = difference - tolerance;
alpha = difference / falloff;
/* Only change if more transparent than before. */
- if (alpha < inColor1[3]) {
+ if (alpha < in_color1[3]) {
output[0] = alpha;
}
else { /* leave as before */
- output[0] = inColor1[3];
+ output[0] = in_color1[3];
}
}
else {
/* foreground object */
- output[0] = inColor1[3];
+ output[0] = in_color1[3];
}
}
@@ -101,8 +100,8 @@ void DifferenceMatteOperation::update_memory_buffer_partial(MemoryBuffer *output
/* Average together the distances. */
difference = difference / 3.0f;
- const float tolerance = m_settings->t1;
- const float falloff = m_settings->t2;
+ const float tolerance = settings_->t1;
+ const float falloff = settings_->t2;
/* Make 100% transparent. */
if (difference <= tolerance) {
diff --git a/source/blender/compositor/operations/COM_DifferenceMatteOperation.h b/source/blender/compositor/operations/COM_DifferenceMatteOperation.h
index 0a86535d946..700dabc9b8d 100644
--- a/source/blender/compositor/operations/COM_DifferenceMatteOperation.h
+++ b/source/blender/compositor/operations/COM_DifferenceMatteOperation.h
@@ -28,9 +28,9 @@ namespace blender::compositor {
*/
class DifferenceMatteOperation : public MultiThreadedOperation {
private:
- NodeChroma *m_settings;
- SocketReader *m_inputImage1Program;
- SocketReader *m_inputImage2Program;
+ NodeChroma *settings_;
+ SocketReader *input_image1_program_;
+ SocketReader *input_image2_program_;
public:
/**
@@ -41,14 +41,14 @@ class DifferenceMatteOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void setSettings(NodeChroma *nodeChroma)
+ void set_settings(NodeChroma *node_chroma)
{
- this->m_settings = nodeChroma;
+ settings_ = node_chroma;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cc b/source/blender/compositor/operations/COM_DilateErodeOperation.cc
index 28b40021cd9..3aaf402ae24 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.cc
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cc
@@ -17,79 +17,75 @@
*/
#include "COM_DilateErodeOperation.h"
-#include "BLI_math.h"
#include "COM_OpenCLDevice.h"
-#include "MEM_guardedalloc.h"
-
namespace blender::compositor {
-/* DilateErode Distance Threshold */
DilateErodeThresholdOperation::DilateErodeThresholdOperation()
{
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
- this->flags.complex = true;
- this->m_inputProgram = nullptr;
- this->m_inset = 0.0f;
- this->m__switch = 0.5f;
- this->m_distance = 0.0f;
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
+ flags_.complex = true;
+ input_program_ = nullptr;
+ inset_ = 0.0f;
+ switch_ = 0.5f;
+ distance_ = 0.0f;
}
void DilateErodeThresholdOperation::init_data()
{
- if (this->m_distance < 0.0f) {
- this->m_scope = -this->m_distance + this->m_inset;
+ if (distance_ < 0.0f) {
+ scope_ = -distance_ + inset_;
}
else {
- if (this->m_inset * 2 > this->m_distance) {
- this->m_scope = MAX2(this->m_inset * 2 - this->m_distance, this->m_distance);
+ if (inset_ * 2 > distance_) {
+ scope_ = MAX2(inset_ * 2 - distance_, distance_);
}
else {
- this->m_scope = this->m_distance;
+ scope_ = distance_;
}
}
- if (this->m_scope < 3) {
- this->m_scope = 3;
+ if (scope_ < 3) {
+ scope_ = 3;
}
}
-void DilateErodeThresholdOperation::initExecution()
+void DilateErodeThresholdOperation::init_execution()
{
- this->m_inputProgram = this->getInputSocketReader(0);
+ input_program_ = this->get_input_socket_reader(0);
}
-void *DilateErodeThresholdOperation::initializeTileData(rcti * /*rect*/)
+void *DilateErodeThresholdOperation::initialize_tile_data(rcti * /*rect*/)
{
- void *buffer = this->m_inputProgram->initializeTileData(nullptr);
+ void *buffer = input_program_->initialize_tile_data(nullptr);
return buffer;
}
-void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y, void *data)
+void DilateErodeThresholdOperation::execute_pixel(float output[4], int x, int y, void *data)
{
- float inputValue[4];
- const float sw = this->m__switch;
- const float distance = this->m_distance;
+ float input_value[4];
+ const float sw = switch_;
+ const float distance = distance_;
float pixelvalue;
- const float rd = this->m_scope * this->m_scope;
- const float inset = this->m_inset;
+ const float rd = scope_ * scope_;
+ const float inset = inset_;
float mindist = rd * 2;
- MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
- float *buffer = inputBuffer->getBuffer();
- const rcti &input_rect = inputBuffer->get_rect();
- const int minx = MAX2(x - this->m_scope, input_rect.xmin);
- const int miny = MAX2(y - this->m_scope, input_rect.ymin);
- const int maxx = MIN2(x + this->m_scope, input_rect.xmax);
- const int maxy = MIN2(y + this->m_scope, input_rect.ymax);
- const int bufferWidth = inputBuffer->getWidth();
+ MemoryBuffer *input_buffer = (MemoryBuffer *)data;
+ float *buffer = input_buffer->get_buffer();
+ const rcti &input_rect = input_buffer->get_rect();
+ const int minx = MAX2(x - scope_, input_rect.xmin);
+ const int miny = MAX2(y - scope_, input_rect.ymin);
+ const int maxx = MIN2(x + scope_, input_rect.xmax);
+ const int maxy = MIN2(y + scope_, input_rect.ymax);
+ const int buffer_width = input_buffer->get_width();
int offset;
- inputBuffer->read(inputValue, x, y);
- if (inputValue[0] > sw) {
+ input_buffer->read(input_value, x, y);
+ if (input_value[0] > sw) {
for (int yi = miny; yi < maxy; yi++) {
const float dy = yi - y;
- offset = ((yi - input_rect.ymin) * bufferWidth + (minx - input_rect.xmin));
+ offset = ((yi - input_rect.ymin) * buffer_width + (minx - input_rect.xmin));
for (int xi = minx; xi < maxx; xi++) {
if (buffer[offset] < sw) {
const float dx = xi - x;
@@ -104,7 +100,7 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y,
else {
for (int yi = miny; yi < maxy; yi++) {
const float dy = yi - y;
- offset = ((yi - input_rect.ymin) * bufferWidth + (minx - input_rect.xmin));
+ offset = ((yi - input_rect.ymin) * buffer_width + (minx - input_rect.xmin));
for (int xi = minx; xi < maxx; xi++) {
if (buffer[offset] > sw) {
const float dx = xi - x;
@@ -147,22 +143,22 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y,
}
}
-void DilateErodeThresholdOperation::deinitExecution()
+void DilateErodeThresholdOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
+ input_program_ = nullptr;
}
-bool DilateErodeThresholdOperation::determineDependingAreaOfInterest(
- rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool DilateErodeThresholdOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
+ rcti new_input;
- newInput.xmax = input->xmax + this->m_scope;
- newInput.xmin = input->xmin - this->m_scope;
- newInput.ymax = input->ymax + this->m_scope;
- newInput.ymin = input->ymin - this->m_scope;
+ new_input.xmax = input->xmax + scope_;
+ new_input.xmin = input->xmin - scope_;
+ new_input.ymax = input->ymax + scope_;
+ new_input.ymin = input->ymin - scope_;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void DilateErodeThresholdOperation::get_area_of_interest(const int input_idx,
@@ -171,10 +167,10 @@ void DilateErodeThresholdOperation::get_area_of_interest(const int input_idx,
{
BLI_assert(input_idx == 0);
UNUSED_VARS_NDEBUG(input_idx);
- r_input_area.xmin = output_area.xmin - m_scope;
- r_input_area.xmax = output_area.xmax + m_scope;
- r_input_area.ymin = output_area.ymin - m_scope;
- r_input_area.ymax = output_area.ymax + m_scope;
+ r_input_area.xmin = output_area.xmin - scope_;
+ r_input_area.xmax = output_area.xmax + scope_;
+ r_input_area.ymin = output_area.ymin - scope_;
+ r_input_area.ymax = output_area.ymax + scope_;
}
struct DilateErodeThresholdOperation::PixelData {
@@ -225,21 +221,21 @@ void DilateErodeThresholdOperation::update_memory_buffer_partial(MemoryBuffer *o
{
const MemoryBuffer *input = inputs[0];
const rcti &input_rect = input->get_rect();
- const float rd = m_scope * m_scope;
- const float inset = m_inset;
+ const float rd = scope_ * scope_;
+ const float inset = inset_;
PixelData p;
- p.sw = m__switch;
+ p.sw = switch_;
p.distance = rd * 2;
p.elem_stride = input->elem_stride;
p.row_stride = input->row_stride;
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
p.x = it.x;
p.y = it.y;
- p.xmin = MAX2(p.x - m_scope, input_rect.xmin);
- p.ymin = MAX2(p.y - m_scope, input_rect.ymin);
- p.xmax = MIN2(p.x + m_scope, input_rect.xmax);
- p.ymax = MIN2(p.y + m_scope, input_rect.ymax);
+ p.xmin = MAX2(p.x - scope_, input_rect.xmin);
+ p.ymin = MAX2(p.y - scope_, input_rect.ymin);
+ p.xmax = MIN2(p.x + scope_, input_rect.xmax);
+ p.ymax = MIN2(p.y + scope_, input_rect.ymax);
p.elem = it.in(0);
float pixel_value;
@@ -250,8 +246,8 @@ void DilateErodeThresholdOperation::update_memory_buffer_partial(MemoryBuffer *o
pixel_value = sqrtf(get_min_distance<std::greater>(p));
}
- if (m_distance > 0.0f) {
- const float delta = m_distance - pixel_value;
+ if (distance_ > 0.0f) {
+ const float delta = distance_ - pixel_value;
if (delta >= 0.0f) {
*it.out = delta >= inset ? 1.0f : delta / inset;
}
@@ -260,7 +256,7 @@ void DilateErodeThresholdOperation::update_memory_buffer_partial(MemoryBuffer *o
}
}
else {
- const float delta = -m_distance + pixel_value;
+ const float delta = -distance_ + pixel_value;
if (delta < 0.0f) {
*it.out = delta < -inset ? 1.0f : (-delta) / inset;
}
@@ -271,56 +267,55 @@ void DilateErodeThresholdOperation::update_memory_buffer_partial(MemoryBuffer *o
}
}
-/* Dilate Distance. */
DilateDistanceOperation::DilateDistanceOperation()
{
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
- this->m_inputProgram = nullptr;
- this->m_distance = 0.0f;
- flags.complex = true;
- flags.open_cl = true;
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
+ input_program_ = nullptr;
+ distance_ = 0.0f;
+ flags_.complex = true;
+ flags_.open_cl = true;
}
void DilateDistanceOperation::init_data()
{
- this->m_scope = this->m_distance;
- if (this->m_scope < 3) {
- this->m_scope = 3;
+ scope_ = distance_;
+ if (scope_ < 3) {
+ scope_ = 3;
}
}
-void DilateDistanceOperation::initExecution()
+void DilateDistanceOperation::init_execution()
{
- this->m_inputProgram = this->getInputSocketReader(0);
+ input_program_ = this->get_input_socket_reader(0);
}
-void *DilateDistanceOperation::initializeTileData(rcti * /*rect*/)
+void *DilateDistanceOperation::initialize_tile_data(rcti * /*rect*/)
{
- void *buffer = this->m_inputProgram->initializeTileData(nullptr);
+ void *buffer = input_program_->initialize_tile_data(nullptr);
return buffer;
}
-void DilateDistanceOperation::executePixel(float output[4], int x, int y, void *data)
+void DilateDistanceOperation::execute_pixel(float output[4], int x, int y, void *data)
{
- const float distance = this->m_distance;
+ const float distance = distance_;
const float mindist = distance * distance;
- MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
- float *buffer = inputBuffer->getBuffer();
- const rcti &input_rect = inputBuffer->get_rect();
- const int minx = MAX2(x - this->m_scope, input_rect.xmin);
- const int miny = MAX2(y - this->m_scope, input_rect.ymin);
- const int maxx = MIN2(x + this->m_scope, input_rect.xmax);
- const int maxy = MIN2(y + this->m_scope, input_rect.ymax);
- const int bufferWidth = inputBuffer->getWidth();
+ MemoryBuffer *input_buffer = (MemoryBuffer *)data;
+ float *buffer = input_buffer->get_buffer();
+ const rcti &input_rect = input_buffer->get_rect();
+ const int minx = MAX2(x - scope_, input_rect.xmin);
+ const int miny = MAX2(y - scope_, input_rect.ymin);
+ const int maxx = MIN2(x + scope_, input_rect.xmax);
+ const int maxy = MIN2(y + scope_, input_rect.ymax);
+ const int buffer_width = input_buffer->get_width();
int offset;
float value = 0.0f;
for (int yi = miny; yi < maxy; yi++) {
const float dy = yi - y;
- offset = ((yi - input_rect.ymin) * bufferWidth + (minx - input_rect.xmin));
+ offset = ((yi - input_rect.ymin) * buffer_width + (minx - input_rect.xmin));
for (int xi = minx; xi < maxx; xi++) {
const float dx = xi - x;
const float dis = dx * dx + dy * dy;
@@ -333,45 +328,46 @@ void DilateDistanceOperation::executePixel(float output[4], int x, int y, void *
output[0] = value;
}
-void DilateDistanceOperation::deinitExecution()
+void DilateDistanceOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
+ input_program_ = nullptr;
}
-bool DilateDistanceOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool DilateDistanceOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
+ rcti new_input;
- newInput.xmax = input->xmax + this->m_scope;
- newInput.xmin = input->xmin - this->m_scope;
- newInput.ymax = input->ymax + this->m_scope;
- newInput.ymin = input->ymin - this->m_scope;
+ new_input.xmax = input->xmax + scope_;
+ new_input.xmin = input->xmin - scope_;
+ new_input.ymax = input->ymax + scope_;
+ new_input.ymin = input->ymin - scope_;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
-void DilateDistanceOperation::executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer,
- cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers,
- std::list<cl_mem> *clMemToCleanUp,
- std::list<cl_kernel> * /*clKernelsToCleanUp*/)
+void DilateDistanceOperation::execute_opencl(OpenCLDevice *device,
+ MemoryBuffer *output_memory_buffer,
+ cl_mem cl_output_buffer,
+ MemoryBuffer **input_memory_buffers,
+ std::list<cl_mem> *cl_mem_to_clean_up,
+ std::list<cl_kernel> * /*cl_kernels_to_clean_up*/)
{
- cl_kernel dilateKernel = device->COM_clCreateKernel("dilateKernel", nullptr);
+ cl_kernel dilate_kernel = device->COM_cl_create_kernel("dilate_kernel", nullptr);
- cl_int distanceSquared = this->m_distance * this->m_distance;
- cl_int scope = this->m_scope;
+ cl_int distance_squared = distance_ * distance_;
+ cl_int scope = scope_;
- device->COM_clAttachMemoryBufferToKernelParameter(
- dilateKernel, 0, 2, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram);
- device->COM_clAttachOutputMemoryBufferToKernelParameter(dilateKernel, 1, clOutputBuffer);
- device->COM_clAttachMemoryBufferOffsetToKernelParameter(dilateKernel, 3, outputMemoryBuffer);
- clSetKernelArg(dilateKernel, 4, sizeof(cl_int), &scope);
- clSetKernelArg(dilateKernel, 5, sizeof(cl_int), &distanceSquared);
- device->COM_clAttachSizeToKernelParameter(dilateKernel, 6, this);
- device->COM_clEnqueueRange(dilateKernel, outputMemoryBuffer, 7, this);
+ device->COM_cl_attach_memory_buffer_to_kernel_parameter(
+ dilate_kernel, 0, 2, cl_mem_to_clean_up, input_memory_buffers, input_program_);
+ device->COM_cl_attach_output_memory_buffer_to_kernel_parameter(
+ dilate_kernel, 1, cl_output_buffer);
+ device->COM_cl_attach_memory_buffer_offset_to_kernel_parameter(
+ dilate_kernel, 3, output_memory_buffer);
+ clSetKernelArg(dilate_kernel, 4, sizeof(cl_int), &scope);
+ clSetKernelArg(dilate_kernel, 5, sizeof(cl_int), &distance_squared);
+ device->COM_cl_attach_size_to_kernel_parameter(dilate_kernel, 6, this);
+ device->COM_cl_enqueue_range(dilate_kernel, output_memory_buffer, 7, this);
}
void DilateDistanceOperation::get_area_of_interest(const int input_idx,
@@ -380,10 +376,10 @@ void DilateDistanceOperation::get_area_of_interest(const int input_idx,
{
BLI_assert(input_idx == 0);
UNUSED_VARS_NDEBUG(input_idx);
- r_input_area.xmin = output_area.xmin - m_scope;
- r_input_area.xmax = output_area.xmax + m_scope;
- r_input_area.ymin = output_area.ymin - m_scope;
- r_input_area.ymax = output_area.ymax + m_scope;
+ r_input_area.xmin = output_area.xmin - scope_;
+ r_input_area.xmax = output_area.xmax + scope_;
+ r_input_area.ymin = output_area.ymin - scope_;
+ r_input_area.ymax = output_area.ymax + scope_;
}
struct DilateDistanceOperation::PixelData {
@@ -453,39 +449,38 @@ void DilateDistanceOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- PixelData p(inputs[0], m_distance, m_scope);
+ PixelData p(inputs[0], distance_, scope_);
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
p.update(it);
*it.out = get_distance_value<std::greater>(p, 0.0f);
}
}
-/* Erode Distance */
ErodeDistanceOperation::ErodeDistanceOperation() : DilateDistanceOperation()
{
/* pass */
}
-void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *data)
+void ErodeDistanceOperation::execute_pixel(float output[4], int x, int y, void *data)
{
- const float distance = this->m_distance;
+ const float distance = distance_;
const float mindist = distance * distance;
- MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
- float *buffer = inputBuffer->getBuffer();
- const rcti &input_rect = inputBuffer->get_rect();
- const int minx = MAX2(x - this->m_scope, input_rect.xmin);
- const int miny = MAX2(y - this->m_scope, input_rect.ymin);
- const int maxx = MIN2(x + this->m_scope, input_rect.xmax);
- const int maxy = MIN2(y + this->m_scope, input_rect.ymax);
- const int bufferWidth = inputBuffer->getWidth();
+ MemoryBuffer *input_buffer = (MemoryBuffer *)data;
+ float *buffer = input_buffer->get_buffer();
+ const rcti &input_rect = input_buffer->get_rect();
+ const int minx = MAX2(x - scope_, input_rect.xmin);
+ const int miny = MAX2(y - scope_, input_rect.ymin);
+ const int maxx = MIN2(x + scope_, input_rect.xmax);
+ const int maxy = MIN2(y + scope_, input_rect.ymax);
+ const int buffer_width = input_buffer->get_width();
int offset;
float value = 1.0f;
for (int yi = miny; yi < maxy; yi++) {
const float dy = yi - y;
- offset = ((yi - input_rect.ymin) * bufferWidth + (minx - input_rect.xmin));
+ offset = ((yi - input_rect.ymin) * buffer_width + (minx - input_rect.xmin));
for (int xi = minx; xi < maxx; xi++) {
const float dx = xi - x;
const float dis = dx * dx + dy * dy;
@@ -498,53 +493,54 @@ void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *d
output[0] = value;
}
-void ErodeDistanceOperation::executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer,
- cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers,
- std::list<cl_mem> *clMemToCleanUp,
- std::list<cl_kernel> * /*clKernelsToCleanUp*/)
+void ErodeDistanceOperation::execute_opencl(OpenCLDevice *device,
+ MemoryBuffer *output_memory_buffer,
+ cl_mem cl_output_buffer,
+ MemoryBuffer **input_memory_buffers,
+ std::list<cl_mem> *cl_mem_to_clean_up,
+ std::list<cl_kernel> * /*cl_kernels_to_clean_up*/)
{
- cl_kernel erodeKernel = device->COM_clCreateKernel("erodeKernel", nullptr);
+ cl_kernel erode_kernel = device->COM_cl_create_kernel("erode_kernel", nullptr);
- cl_int distanceSquared = this->m_distance * this->m_distance;
- cl_int scope = this->m_scope;
+ cl_int distance_squared = distance_ * distance_;
+ cl_int scope = scope_;
- device->COM_clAttachMemoryBufferToKernelParameter(
- erodeKernel, 0, 2, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram);
- device->COM_clAttachOutputMemoryBufferToKernelParameter(erodeKernel, 1, clOutputBuffer);
- device->COM_clAttachMemoryBufferOffsetToKernelParameter(erodeKernel, 3, outputMemoryBuffer);
- clSetKernelArg(erodeKernel, 4, sizeof(cl_int), &scope);
- clSetKernelArg(erodeKernel, 5, sizeof(cl_int), &distanceSquared);
- device->COM_clAttachSizeToKernelParameter(erodeKernel, 6, this);
- device->COM_clEnqueueRange(erodeKernel, outputMemoryBuffer, 7, this);
+ device->COM_cl_attach_memory_buffer_to_kernel_parameter(
+ erode_kernel, 0, 2, cl_mem_to_clean_up, input_memory_buffers, input_program_);
+ device->COM_cl_attach_output_memory_buffer_to_kernel_parameter(
+ erode_kernel, 1, cl_output_buffer);
+ device->COM_cl_attach_memory_buffer_offset_to_kernel_parameter(
+ erode_kernel, 3, output_memory_buffer);
+ clSetKernelArg(erode_kernel, 4, sizeof(cl_int), &scope);
+ clSetKernelArg(erode_kernel, 5, sizeof(cl_int), &distance_squared);
+ device->COM_cl_attach_size_to_kernel_parameter(erode_kernel, 6, this);
+ device->COM_cl_enqueue_range(erode_kernel, output_memory_buffer, 7, this);
}
void ErodeDistanceOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- PixelData p(inputs[0], m_distance, m_scope);
+ PixelData p(inputs[0], distance_, scope_);
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
p.update(it);
*it.out = get_distance_value<std::less>(p, 1.0f);
}
}
-/* Dilate step */
DilateStepOperation::DilateStepOperation()
{
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
- this->flags.complex = true;
- this->m_inputProgram = nullptr;
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
+ flags_.complex = true;
+ input_program_ = nullptr;
}
-void DilateStepOperation::initExecution()
+void DilateStepOperation::init_execution()
{
- this->m_inputProgram = this->getInputSocketReader(0);
+ input_program_ = this->get_input_socket_reader(0);
}
-/* Small helper to pass data from initializeTileData to executePixel. */
+/* Small helper to pass data from initialize_tile_data to execute_pixel. */
struct tile_info {
rcti rect;
int width;
@@ -564,15 +560,15 @@ static tile_info *create_cache(int xmin, int xmax, int ymin, int ymax)
return result;
}
-void *DilateStepOperation::initializeTileData(rcti *rect)
+void *DilateStepOperation::initialize_tile_data(rcti *rect)
{
- MemoryBuffer *tile = (MemoryBuffer *)this->m_inputProgram->initializeTileData(nullptr);
+ MemoryBuffer *tile = (MemoryBuffer *)input_program_->initialize_tile_data(nullptr);
int x, y, i;
- int width = tile->getWidth();
- int height = tile->getHeight();
- float *buffer = tile->getBuffer();
+ int width = tile->get_width();
+ int height = tile->get_height();
+ float *buffer = tile->get_buffer();
- int half_window = this->m_iterations;
+ int half_window = iterations_;
int window = half_window * 2 + 1;
int xmin = MAX2(0, rect->xmin - half_window);
@@ -654,7 +650,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
return result;
}
-void DilateStepOperation::executePixel(float output[4], int x, int y, void *data)
+void DilateStepOperation::execute_pixel(float output[4], int x, int y, void *data)
{
tile_info *tile = (tile_info *)data;
int nx = x - tile->rect.xmin;
@@ -662,30 +658,30 @@ void DilateStepOperation::executePixel(float output[4], int x, int y, void *data
output[0] = tile->buffer[tile->width * ny + nx];
}
-void DilateStepOperation::deinitExecution()
+void DilateStepOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
+ input_program_ = nullptr;
}
-void DilateStepOperation::deinitializeTileData(rcti * /*rect*/, void *data)
+void DilateStepOperation::deinitialize_tile_data(rcti * /*rect*/, void *data)
{
tile_info *tile = (tile_info *)data;
MEM_freeN(tile->buffer);
MEM_freeN(tile);
}
-bool DilateStepOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool DilateStepOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti newInput;
- int it = this->m_iterations;
- newInput.xmax = input->xmax + it;
- newInput.xmin = input->xmin - it;
- newInput.ymax = input->ymax + it;
- newInput.ymin = input->ymin - it;
+ rcti new_input;
+ int it = iterations_;
+ new_input.xmax = input->xmax + it;
+ new_input.xmin = input->xmin - it;
+ new_input.ymax = input->ymax + it;
+ new_input.ymin = input->ymin - it;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void DilateStepOperation::get_area_of_interest(const int input_idx,
@@ -694,10 +690,10 @@ void DilateStepOperation::get_area_of_interest(const int input_idx,
{
BLI_assert(input_idx == 0);
UNUSED_VARS_NDEBUG(input_idx);
- r_input_area.xmin = output_area.xmin - m_iterations;
- r_input_area.xmax = output_area.xmax + m_iterations;
- r_input_area.ymin = output_area.ymin - m_iterations;
- r_input_area.ymax = output_area.ymax + m_iterations;
+ r_input_area.xmin = output_area.xmin - iterations_;
+ r_input_area.xmax = output_area.xmax + iterations_;
+ r_input_area.ymin = output_area.ymin - iterations_;
+ r_input_area.ymax = output_area.ymax + iterations_;
}
template<typename TCompareSelector>
@@ -709,8 +705,8 @@ static void step_update_memory_buffer(MemoryBuffer *output,
{
TCompareSelector selector;
- const int width = output->getWidth();
- const int height = output->getHeight();
+ const int width = output->get_width();
+ const int height = output->get_height();
const int half_window = num_iterations;
const int window = half_window * 2 + 1;
@@ -783,7 +779,8 @@ static void step_update_memory_buffer(MemoryBuffer *output,
start = half_window + (i - 1) * window + 1;
for (int y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) {
- result.get_value(x, y + start + area.ymin, 0) = selector(temp[y], temp[y + window - 1]);
+ result.get_value(x + area.xmin, y + start + area.ymin, 0) = selector(temp[y],
+ temp[y + window - 1]);
}
}
}
@@ -805,24 +802,23 @@ void DilateStepOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- step_update_memory_buffer<Max2Selector>(output, inputs[0], area, m_iterations, -FLT_MAX);
+ step_update_memory_buffer<Max2Selector>(output, inputs[0], area, iterations_, -FLT_MAX);
}
-/* Erode step */
ErodeStepOperation::ErodeStepOperation() : DilateStepOperation()
{
/* pass */
}
-void *ErodeStepOperation::initializeTileData(rcti *rect)
+void *ErodeStepOperation::initialize_tile_data(rcti *rect)
{
- MemoryBuffer *tile = (MemoryBuffer *)this->m_inputProgram->initializeTileData(nullptr);
+ MemoryBuffer *tile = (MemoryBuffer *)input_program_->initialize_tile_data(nullptr);
int x, y, i;
- int width = tile->getWidth();
- int height = tile->getHeight();
- float *buffer = tile->getBuffer();
+ int width = tile->get_width();
+ int height = tile->get_height();
+ float *buffer = tile->get_buffer();
- int half_window = this->m_iterations;
+ int half_window = iterations_;
int window = half_window * 2 + 1;
int xmin = MAX2(0, rect->xmin - half_window);
@@ -915,7 +911,7 @@ void ErodeStepOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- step_update_memory_buffer<Min2Selector>(output, inputs[0], area, m_iterations, FLT_MAX);
+ step_update_memory_buffer<Min2Selector>(output, inputs[0], area, iterations_, FLT_MAX);
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.h b/source/blender/compositor/operations/COM_DilateErodeOperation.h
index 9c32a5ac1fd..2ca6431862d 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.h
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.h
@@ -28,56 +28,57 @@ class DilateErodeThresholdOperation : public MultiThreadedOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
+ SocketReader *input_program_;
- float m_distance;
- float m__switch;
- float m_inset;
+ float distance_;
+ float switch_;
+ float inset_;
/**
* determines the area of interest to track pixels
* keep this one as small as possible for speed gain.
*/
- int m_scope;
+ int scope_;
public:
+ /* DilateErode Distance Threshold */
DilateErodeThresholdOperation();
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
void init_data() override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setDistance(float distance)
+ void set_distance(float distance)
{
- this->m_distance = distance;
+ distance_ = distance;
}
- void setSwitch(float sw)
+ void set_switch(float sw)
{
- this->m__switch = sw;
+ switch_ = sw;
}
- void setInset(float inset)
+ void set_inset(float inset)
{
- this->m_inset = inset;
+ inset_ = inset;
}
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
@@ -91,46 +92,47 @@ class DilateDistanceOperation : public MultiThreadedOperation {
protected:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
- float m_distance;
- int m_scope;
+ SocketReader *input_program_;
+ float distance_;
+ int scope_;
public:
+ /* Dilate Distance. */
DilateDistanceOperation();
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
void init_data() override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setDistance(float distance)
+ void set_distance(float distance)
{
- this->m_distance = distance;
+ distance_ = distance;
}
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer,
- cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers,
- std::list<cl_mem> *clMemToCleanUp,
- std::list<cl_kernel> *clKernelsToCleanUp) override;
+ void execute_opencl(OpenCLDevice *device,
+ MemoryBuffer *output_memory_buffer,
+ cl_mem cl_output_buffer,
+ MemoryBuffer **input_memory_buffers,
+ std::list<cl_mem> *cl_mem_to_clean_up,
+ std::list<cl_kernel> *cl_kernels_to_clean_up) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) final;
virtual void update_memory_buffer_partial(MemoryBuffer *output,
@@ -140,19 +142,20 @@ class DilateDistanceOperation : public MultiThreadedOperation {
class ErodeDistanceOperation : public DilateDistanceOperation {
public:
+ /* Erode Distance */
ErodeDistanceOperation();
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
- void executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer,
- cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers,
- std::list<cl_mem> *clMemToCleanUp,
- std::list<cl_kernel> *clKernelsToCleanUp) override;
+ void execute_opencl(OpenCLDevice *device,
+ MemoryBuffer *output_memory_buffer,
+ cl_mem cl_output_buffer,
+ MemoryBuffer **input_memory_buffers,
+ std::list<cl_mem> *cl_mem_to_clean_up,
+ std::list<cl_kernel> *cl_kernels_to_clean_up) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
@@ -162,40 +165,41 @@ class ErodeDistanceOperation : public DilateDistanceOperation {
class DilateStepOperation : public MultiThreadedOperation {
protected:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
+ SocketReader *input_program_;
- int m_iterations;
+ int iterations_;
public:
+ /* Dilate step */
DilateStepOperation();
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
- void deinitializeTileData(rcti *rect, void *data) override;
+ void deinit_execution() override;
+ void deinitialize_tile_data(rcti *rect, void *data) override;
- void setIterations(int iterations)
+ void set_iterations(int iterations)
{
- this->m_iterations = iterations;
+ iterations_ = iterations;
}
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) final;
virtual void update_memory_buffer_partial(MemoryBuffer *output,
@@ -205,9 +209,10 @@ class DilateStepOperation : public MultiThreadedOperation {
class ErodeStepOperation : public DilateStepOperation {
public:
+ /** Erode step. */
ErodeStepOperation();
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc
index e69124205d0..1104ef6f71f 100644
--- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc
@@ -19,131 +19,127 @@
#include "COM_DirectionalBlurOperation.h"
#include "COM_OpenCLDevice.h"
-#include "BLI_math.h"
-
-#include "RE_pipeline.h"
-
namespace blender::compositor {
DirectionalBlurOperation::DirectionalBlurOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
- flags.complex = true;
- flags.open_cl = true;
- this->m_inputProgram = nullptr;
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ flags_.complex = true;
+ flags_.open_cl = true;
+ input_program_ = nullptr;
}
-void DirectionalBlurOperation::initExecution()
+void DirectionalBlurOperation::init_execution()
{
- this->m_inputProgram = getInputSocketReader(0);
- QualityStepHelper::initExecution(COM_QH_INCREASE);
- const float angle = this->m_data->angle;
- const float zoom = this->m_data->zoom;
- const float spin = this->m_data->spin;
- const float iterations = this->m_data->iter;
- const float distance = this->m_data->distance;
- const float center_x = this->m_data->center_x;
- const float center_y = this->m_data->center_y;
- const float width = getWidth();
- const float height = getHeight();
+ input_program_ = get_input_socket_reader(0);
+ QualityStepHelper::init_execution(COM_QH_INCREASE);
+ const float angle = data_->angle;
+ const float zoom = data_->zoom;
+ const float spin = data_->spin;
+ const float iterations = data_->iter;
+ const float distance = data_->distance;
+ const float center_x = data_->center_x;
+ const float center_y = data_->center_y;
+ const float width = get_width();
+ const float height = get_height();
const float a = angle;
const float itsc = 1.0f / powf(2.0f, (float)iterations);
float D;
D = distance * sqrtf(width * width + height * height);
- this->m_center_x_pix = center_x * width;
- this->m_center_y_pix = center_y * height;
+ center_x_pix_ = center_x * width;
+ center_y_pix_ = center_y * height;
- this->m_tx = itsc * D * cosf(a);
- this->m_ty = -itsc * D * sinf(a);
- this->m_sc = itsc * zoom;
- this->m_rot = itsc * spin;
+ tx_ = itsc * D * cosf(a);
+ ty_ = -itsc * D * sinf(a);
+ sc_ = itsc * zoom;
+ rot_ = itsc * spin;
}
-void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void * /*data*/)
+void DirectionalBlurOperation::execute_pixel(float output[4], int x, int y, void * /*data*/)
{
- const int iterations = pow(2.0f, this->m_data->iter);
+ const int iterations = pow(2.0f, data_->iter);
float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float col2[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- this->m_inputProgram->readSampled(col2, x, y, PixelSampler::Bilinear);
- float ltx = this->m_tx;
- float lty = this->m_ty;
- float lsc = this->m_sc;
- float lrot = this->m_rot;
+ input_program_->read_sampled(col2, x, y, PixelSampler::Bilinear);
+ float ltx = tx_;
+ float lty = ty_;
+ float lsc = sc_;
+ float lrot = rot_;
/* blur the image */
for (int i = 0; i < iterations; i++) {
const float cs = cosf(lrot), ss = sinf(lrot);
const float isc = 1.0f / (1.0f + lsc);
- const float v = isc * (y - this->m_center_y_pix) + lty;
- const float u = isc * (x - this->m_center_x_pix) + ltx;
+ const float v = isc * (y - center_y_pix_) + lty;
+ const float u = isc * (x - center_x_pix_) + ltx;
- this->m_inputProgram->readSampled(col,
- cs * u + ss * v + this->m_center_x_pix,
- cs * v - ss * u + this->m_center_y_pix,
- PixelSampler::Bilinear);
+ input_program_->read_sampled(col,
+ cs * u + ss * v + center_x_pix_,
+ cs * v - ss * u + center_y_pix_,
+ PixelSampler::Bilinear);
add_v4_v4(col2, col);
/* double transformations */
- ltx += this->m_tx;
- lty += this->m_ty;
- lrot += this->m_rot;
- lsc += this->m_sc;
+ ltx += tx_;
+ lty += ty_;
+ lrot += rot_;
+ lsc += sc_;
}
mul_v4_v4fl(output, col2, 1.0f / (iterations + 1));
}
-void DirectionalBlurOperation::executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer,
- cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers,
- std::list<cl_mem> *clMemToCleanUp,
- std::list<cl_kernel> * /*clKernelsToCleanUp*/)
+void DirectionalBlurOperation::execute_opencl(OpenCLDevice *device,
+ MemoryBuffer *output_memory_buffer,
+ cl_mem cl_output_buffer,
+ MemoryBuffer **input_memory_buffers,
+ std::list<cl_mem> *cl_mem_to_clean_up,
+ std::list<cl_kernel> * /*cl_kernels_to_clean_up*/)
{
- cl_kernel directionalBlurKernel = device->COM_clCreateKernel("directionalBlurKernel", nullptr);
-
- cl_int iterations = pow(2.0f, this->m_data->iter);
- cl_float2 ltxy = {{this->m_tx, this->m_ty}};
- cl_float2 centerpix = {{this->m_center_x_pix, this->m_center_y_pix}};
- cl_float lsc = this->m_sc;
- cl_float lrot = this->m_rot;
-
- device->COM_clAttachMemoryBufferToKernelParameter(
- directionalBlurKernel, 0, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram);
- device->COM_clAttachOutputMemoryBufferToKernelParameter(
- directionalBlurKernel, 1, clOutputBuffer);
- device->COM_clAttachMemoryBufferOffsetToKernelParameter(
- directionalBlurKernel, 2, outputMemoryBuffer);
- clSetKernelArg(directionalBlurKernel, 3, sizeof(cl_int), &iterations);
- clSetKernelArg(directionalBlurKernel, 4, sizeof(cl_float), &lsc);
- clSetKernelArg(directionalBlurKernel, 5, sizeof(cl_float), &lrot);
- clSetKernelArg(directionalBlurKernel, 6, sizeof(cl_float2), &ltxy);
- clSetKernelArg(directionalBlurKernel, 7, sizeof(cl_float2), &centerpix);
-
- device->COM_clEnqueueRange(directionalBlurKernel, outputMemoryBuffer, 8, this);
+ cl_kernel directional_blur_kernel = device->COM_cl_create_kernel("directional_blur_kernel",
+ nullptr);
+
+ cl_int iterations = pow(2.0f, data_->iter);
+ cl_float2 ltxy = {{tx_, ty_}};
+ cl_float2 centerpix = {{center_x_pix_, center_y_pix_}};
+ cl_float lsc = sc_;
+ cl_float lrot = rot_;
+
+ device->COM_cl_attach_memory_buffer_to_kernel_parameter(
+ directional_blur_kernel, 0, -1, cl_mem_to_clean_up, input_memory_buffers, input_program_);
+ device->COM_cl_attach_output_memory_buffer_to_kernel_parameter(
+ directional_blur_kernel, 1, cl_output_buffer);
+ device->COM_cl_attach_memory_buffer_offset_to_kernel_parameter(
+ directional_blur_kernel, 2, output_memory_buffer);
+ clSetKernelArg(directional_blur_kernel, 3, sizeof(cl_int), &iterations);
+ clSetKernelArg(directional_blur_kernel, 4, sizeof(cl_float), &lsc);
+ clSetKernelArg(directional_blur_kernel, 5, sizeof(cl_float), &lrot);
+ clSetKernelArg(directional_blur_kernel, 6, sizeof(cl_float2), &ltxy);
+ clSetKernelArg(directional_blur_kernel, 7, sizeof(cl_float2), &centerpix);
+
+ device->COM_cl_enqueue_range(directional_blur_kernel, output_memory_buffer, 8, this);
}
-void DirectionalBlurOperation::deinitExecution()
+void DirectionalBlurOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
+ input_program_ = nullptr;
}
-bool DirectionalBlurOperation::determineDependingAreaOfInterest(rcti * /*input*/,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool DirectionalBlurOperation::determine_depending_area_of_interest(
+ rcti * /*input*/, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
+ rcti new_input;
- newInput.xmax = this->getWidth();
- newInput.xmin = 0;
- newInput.ymax = this->getHeight();
- newInput.ymin = 0;
+ new_input.xmax = this->get_width();
+ new_input.xmin = 0;
+ new_input.ymax = this->get_height();
+ new_input.ymin = 0;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void DirectionalBlurOperation::get_area_of_interest(const int input_idx,
@@ -160,7 +156,7 @@ void DirectionalBlurOperation::update_memory_buffer_partial(MemoryBuffer *output
Span<MemoryBuffer *> inputs)
{
const MemoryBuffer *input = inputs[0];
- const int iterations = pow(2.0f, this->m_data->iter);
+ const int iterations = pow(2.0f, data_->iter);
for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
const int x = it.x;
const int y = it.y;
@@ -170,27 +166,27 @@ void DirectionalBlurOperation::update_memory_buffer_partial(MemoryBuffer *output
/* Blur pixel. */
/* TODO(manzanilla): Many values used on iterations can be calculated beforehand. Create a
* table on operation initialization. */
- float ltx = this->m_tx;
- float lty = this->m_ty;
- float lsc = this->m_sc;
- float lrot = this->m_rot;
+ float ltx = tx_;
+ float lty = ty_;
+ float lsc = sc_;
+ float lrot = rot_;
for (int i = 0; i < iterations; i++) {
const float cs = cosf(lrot), ss = sinf(lrot);
const float isc = 1.0f / (1.0f + lsc);
- const float v = isc * (y - this->m_center_y_pix) + lty;
- const float u = isc * (x - this->m_center_x_pix) + ltx;
+ const float v = isc * (y - center_y_pix_) + lty;
+ const float u = isc * (x - center_x_pix_) + ltx;
float color[4];
input->read_elem_bilinear(
- cs * u + ss * v + this->m_center_x_pix, cs * v - ss * u + this->m_center_y_pix, color);
+ cs * u + ss * v + center_x_pix_, cs * v - ss * u + center_y_pix_, color);
add_v4_v4(color_accum, color);
/* Double transformations. */
- ltx += this->m_tx;
- lty += this->m_ty;
- lrot += this->m_rot;
- lsc += this->m_sc;
+ ltx += tx_;
+ lty += ty_;
+ lrot += rot_;
+ lsc += sc_;
}
mul_v4_v4fl(it.out, color_accum, 1.0f / (iterations + 1));
diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h
index 9a982bf6481..2dd2fc98ccd 100644
--- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h
+++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h
@@ -25,12 +25,12 @@ namespace blender::compositor {
class DirectionalBlurOperation : public MultiThreadedOperation, public QualityStepHelper {
private:
- SocketReader *m_inputProgram;
- NodeDBlurData *m_data;
+ SocketReader *input_program_;
+ NodeDBlurData *data_;
- float m_center_x_pix, m_center_y_pix;
- float m_tx, m_ty;
- float m_sc, m_rot;
+ float center_x_pix_, center_y_pix_;
+ float tx_, ty_;
+ float sc_, rot_;
public:
DirectionalBlurOperation();
@@ -38,33 +38,33 @@ class DirectionalBlurOperation : public MultiThreadedOperation, public QualitySt
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void setData(NodeDBlurData *data)
+ void set_data(NodeDBlurData *data)
{
- this->m_data = data;
+ data_ = data;
}
- void executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer,
- cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers,
- std::list<cl_mem> *clMemToCleanUp,
- std::list<cl_kernel> *clKernelsToCleanUp) override;
+ void execute_opencl(OpenCLDevice *device,
+ MemoryBuffer *output_memory_buffer,
+ cl_mem cl_output_buffer,
+ MemoryBuffer **input_memory_buffers,
+ std::list<cl_mem> *cl_mem_to_clean_up,
+ std::list<cl_kernel> *cl_kernels_to_clean_up) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cc b/source/blender/compositor/operations/COM_DisplaceOperation.cc
index d08ff60d5d0..4742692b75d 100644
--- a/source/blender/compositor/operations/COM_DisplaceOperation.cc
+++ b/source/blender/compositor/operations/COM_DisplaceOperation.cc
@@ -17,62 +17,60 @@
*/
#include "COM_DisplaceOperation.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
namespace blender::compositor {
DisplaceOperation::DisplaceOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Vector);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
- this->flags.complex = true;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Vector);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
+ flags_.complex = true;
- this->m_inputColorProgram = nullptr;
+ input_color_program_ = nullptr;
}
-void DisplaceOperation::initExecution()
+void DisplaceOperation::init_execution()
{
- this->m_inputColorProgram = this->getInputSocketReader(0);
- NodeOperation *vector = this->getInputSocketReader(1);
- NodeOperation *scale_x = this->getInputSocketReader(2);
- NodeOperation *scale_y = this->getInputSocketReader(3);
+ input_color_program_ = this->get_input_socket_reader(0);
+ NodeOperation *vector = this->get_input_socket_reader(1);
+ NodeOperation *scale_x = this->get_input_socket_reader(2);
+ NodeOperation *scale_y = this->get_input_socket_reader(3);
if (execution_model_ == eExecutionModel::Tiled) {
vector_read_fn_ = [=](float x, float y, float *out) {
- vector->readSampled(out, x, y, PixelSampler::Bilinear);
+ vector->read_sampled(out, x, y, PixelSampler::Bilinear);
};
scale_x_read_fn_ = [=](float x, float y, float *out) {
- scale_x->readSampled(out, x, y, PixelSampler::Nearest);
+ scale_x->read_sampled(out, x, y, PixelSampler::Nearest);
};
scale_y_read_fn_ = [=](float x, float y, float *out) {
- scale_y->readSampled(out, x, y, PixelSampler::Nearest);
+ scale_y->read_sampled(out, x, y, PixelSampler::Nearest);
};
}
- this->m_width_x4 = this->getWidth() * 4;
- this->m_height_x4 = this->getHeight() * 4;
- input_vector_width_ = vector->getWidth();
- input_vector_height_ = vector->getHeight();
+ width_x4_ = this->get_width() * 4;
+ height_x4_ = this->get_height() * 4;
+ input_vector_width_ = vector->get_width();
+ input_vector_height_ = vector->get_height();
}
-void DisplaceOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler /*sampler*/)
+void DisplaceOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
float xy[2] = {x, y};
float uv[2], deriv[2][2];
- pixelTransform(xy, uv, deriv);
+ pixel_transform(xy, uv, deriv);
if (is_zero_v2(deriv[0]) && is_zero_v2(deriv[1])) {
- this->m_inputColorProgram->readSampled(output, uv[0], uv[1], PixelSampler::Bilinear);
+ input_color_program_->read_sampled(output, uv[0], uv[1], PixelSampler::Bilinear);
}
else {
/* EWA filtering (without nearest it gets blurry with NO distortion) */
- this->m_inputColorProgram->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1]);
+ input_color_program_->read_filtered(output, uv[0], uv[1], deriv[0], deriv[1]);
}
}
@@ -94,7 +92,7 @@ bool DisplaceOperation::read_displacement(
return true;
}
-void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2])
+void DisplaceOperation::pixel_transform(const float xy[2], float r_uv[2], float r_deriv[2][2])
{
float col[4];
float uv[2]; /* temporary variables for derivative estimation */
@@ -106,8 +104,8 @@ void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r
float ys = col[0];
/* clamp x and y displacement to triple image resolution -
* to prevent hangs from huge values mistakenly plugged in eg. z buffers */
- CLAMP(xs, -m_width_x4, m_width_x4);
- CLAMP(ys, -m_height_x4, m_height_x4);
+ CLAMP(xs, -width_x4_, width_x4_);
+ CLAMP(ys, -height_x4_, height_x4_);
/* displaced pixel in uv coords, for image sampling */
read_displacement(xy[0], xy[1], xs, ys, xy, r_uv[0], r_uv[1]);
@@ -153,52 +151,52 @@ void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r
}
}
-void DisplaceOperation::deinitExecution()
+void DisplaceOperation::deinit_execution()
{
- this->m_inputColorProgram = nullptr;
+ input_color_program_ = nullptr;
vector_read_fn_ = nullptr;
scale_x_read_fn_ = nullptr;
scale_y_read_fn_ = nullptr;
}
-bool DisplaceOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool DisplaceOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti colorInput;
- rcti vectorInput;
+ rcti color_input;
+ rcti vector_input;
NodeOperation *operation = nullptr;
/* the vector buffer only needs a 2x2 buffer. The image needs whole buffer */
/* image */
- operation = getInputOperation(0);
- colorInput.xmax = operation->getWidth();
- colorInput.xmin = 0;
- colorInput.ymax = operation->getHeight();
- colorInput.ymin = 0;
- if (operation->determineDependingAreaOfInterest(&colorInput, readOperation, output)) {
+ operation = get_input_operation(0);
+ color_input.xmax = operation->get_width();
+ color_input.xmin = 0;
+ color_input.ymax = operation->get_height();
+ color_input.ymin = 0;
+ if (operation->determine_depending_area_of_interest(&color_input, read_operation, output)) {
return true;
}
/* vector */
- operation = getInputOperation(1);
- vectorInput.xmax = input->xmax + 1;
- vectorInput.xmin = input->xmin - 1;
- vectorInput.ymax = input->ymax + 1;
- vectorInput.ymin = input->ymin - 1;
- if (operation->determineDependingAreaOfInterest(&vectorInput, readOperation, output)) {
+ operation = get_input_operation(1);
+ vector_input.xmax = input->xmax + 1;
+ vector_input.xmin = input->xmin - 1;
+ vector_input.ymax = input->ymax + 1;
+ vector_input.ymin = input->ymin - 1;
+ if (operation->determine_depending_area_of_interest(&vector_input, read_operation, output)) {
return true;
}
/* scale x */
- operation = getInputOperation(2);
- if (operation->determineDependingAreaOfInterest(input, readOperation, output)) {
+ operation = get_input_operation(2);
+ if (operation->determine_depending_area_of_interest(input, read_operation, output)) {
return true;
}
/* scale y */
- operation = getInputOperation(3);
- if (operation->determineDependingAreaOfInterest(input, readOperation, output)) {
+ operation = get_input_operation(3);
+ if (operation->determine_depending_area_of_interest(input, read_operation, output)) {
return true;
}
@@ -211,7 +209,7 @@ void DisplaceOperation::get_area_of_interest(const int input_idx,
{
switch (input_idx) {
case 0: {
- r_input_area = getInputOperation(input_idx)->get_canvas();
+ r_input_area = get_input_operation(input_idx)->get_canvas();
break;
}
case 1: {
@@ -248,7 +246,7 @@ void DisplaceOperation::update_memory_buffer_partial(MemoryBuffer *output,
float uv[2];
float deriv[2][2];
- pixelTransform(xy, uv, deriv);
+ pixel_transform(xy, uv, deriv);
if (is_zero_v2(deriv[0]) && is_zero_v2(deriv[1])) {
input_color->read_elem_bilinear(uv[0], uv[1], it.out);
}
diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.h b/source/blender/compositor/operations/COM_DisplaceOperation.h
index 5be914ab672..a6f6927407f 100644
--- a/source/blender/compositor/operations/COM_DisplaceOperation.h
+++ b/source/blender/compositor/operations/COM_DisplaceOperation.h
@@ -25,12 +25,12 @@ namespace blender::compositor {
class DisplaceOperation : public MultiThreadedOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputColorProgram;
+ SocketReader *input_color_program_;
- float m_width_x4;
- float m_height_x4;
+ float width_x4_;
+ float height_x4_;
int input_vector_width_;
int input_vector_height_;
@@ -45,26 +45,26 @@ class DisplaceOperation : public MultiThreadedOperation {
/**
* we need a 2x2 differential filter for Vector Input and full buffer for the image
*/
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2]);
+ void pixel_transform(const float xy[2], float r_uv[2], float r_deriv[2][2]);
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_started(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc
index 712b61be805..729b01d924d 100644
--- a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc
+++ b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc
@@ -17,115 +17,112 @@
*/
#include "COM_DisplaceSimpleOperation.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
namespace blender::compositor {
DisplaceSimpleOperation::DisplaceSimpleOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Vector);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
-
- this->m_inputColorProgram = nullptr;
- this->m_inputVectorProgram = nullptr;
- this->m_inputScaleXProgram = nullptr;
- this->m_inputScaleYProgram = nullptr;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Vector);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
+
+ input_color_program_ = nullptr;
+ input_vector_program_ = nullptr;
+ input_scale_xprogram_ = nullptr;
+ input_scale_yprogram_ = nullptr;
}
-void DisplaceSimpleOperation::initExecution()
+void DisplaceSimpleOperation::init_execution()
{
- this->m_inputColorProgram = this->getInputSocketReader(0);
- this->m_inputVectorProgram = this->getInputSocketReader(1);
- this->m_inputScaleXProgram = this->getInputSocketReader(2);
- this->m_inputScaleYProgram = this->getInputSocketReader(3);
+ input_color_program_ = this->get_input_socket_reader(0);
+ input_vector_program_ = this->get_input_socket_reader(1);
+ input_scale_xprogram_ = this->get_input_socket_reader(2);
+ input_scale_yprogram_ = this->get_input_socket_reader(3);
- this->m_width_x4 = this->getWidth() * 4;
- this->m_height_x4 = this->getHeight() * 4;
+ width_x4_ = this->get_width() * 4;
+ height_x4_ = this->get_height() * 4;
}
/* minimum distance (in pixels) a pixel has to be displaced
* in order to take effect */
// #define DISPLACE_EPSILON 0.01f
-void DisplaceSimpleOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void DisplaceSimpleOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inVector[4];
- float inScale[4];
+ float in_vector[4];
+ float in_scale[4];
float p_dx, p_dy; /* main displacement in pixel space */
float u, v;
- this->m_inputScaleXProgram->readSampled(inScale, x, y, sampler);
- float xs = inScale[0];
- this->m_inputScaleYProgram->readSampled(inScale, x, y, sampler);
- float ys = inScale[0];
+ input_scale_xprogram_->read_sampled(in_scale, x, y, sampler);
+ float xs = in_scale[0];
+ input_scale_yprogram_->read_sampled(in_scale, x, y, sampler);
+ float ys = in_scale[0];
/* clamp x and y displacement to triple image resolution -
* to prevent hangs from huge values mistakenly plugged in eg. z buffers */
- CLAMP(xs, -this->m_width_x4, this->m_width_x4);
- CLAMP(ys, -this->m_height_x4, this->m_height_x4);
+ CLAMP(xs, -width_x4_, width_x4_);
+ CLAMP(ys, -height_x4_, height_x4_);
- this->m_inputVectorProgram->readSampled(inVector, x, y, sampler);
- p_dx = inVector[0] * xs;
- p_dy = inVector[1] * ys;
+ input_vector_program_->read_sampled(in_vector, x, y, sampler);
+ p_dx = in_vector[0] * xs;
+ p_dy = in_vector[1] * ys;
/* displaced pixel in uv coords, for image sampling */
/* clamp nodes to avoid glitches */
u = x - p_dx + 0.5f;
v = y - p_dy + 0.5f;
- CLAMP(u, 0.0f, this->getWidth() - 1.0f);
- CLAMP(v, 0.0f, this->getHeight() - 1.0f);
+ CLAMP(u, 0.0f, this->get_width() - 1.0f);
+ CLAMP(v, 0.0f, this->get_height() - 1.0f);
- this->m_inputColorProgram->readSampled(output, u, v, sampler);
+ input_color_program_->read_sampled(output, u, v, sampler);
}
-void DisplaceSimpleOperation::deinitExecution()
+void DisplaceSimpleOperation::deinit_execution()
{
- this->m_inputColorProgram = nullptr;
- this->m_inputVectorProgram = nullptr;
- this->m_inputScaleXProgram = nullptr;
- this->m_inputScaleYProgram = nullptr;
+ input_color_program_ = nullptr;
+ input_vector_program_ = nullptr;
+ input_scale_xprogram_ = nullptr;
+ input_scale_yprogram_ = nullptr;
}
-bool DisplaceSimpleOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool DisplaceSimpleOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti colorInput;
+ rcti color_input;
NodeOperation *operation = nullptr;
/* the vector buffer only needs a 2x2 buffer. The image needs whole buffer */
/* image */
- operation = getInputOperation(0);
- colorInput.xmax = operation->getWidth();
- colorInput.xmin = 0;
- colorInput.ymax = operation->getHeight();
- colorInput.ymin = 0;
- if (operation->determineDependingAreaOfInterest(&colorInput, readOperation, output)) {
+ operation = get_input_operation(0);
+ color_input.xmax = operation->get_width();
+ color_input.xmin = 0;
+ color_input.ymax = operation->get_height();
+ color_input.ymin = 0;
+ if (operation->determine_depending_area_of_interest(&color_input, read_operation, output)) {
return true;
}
/* vector */
- if (operation->determineDependingAreaOfInterest(input, readOperation, output)) {
+ if (operation->determine_depending_area_of_interest(input, read_operation, output)) {
return true;
}
/* scale x */
- operation = getInputOperation(2);
- if (operation->determineDependingAreaOfInterest(input, readOperation, output)) {
+ operation = get_input_operation(2);
+ if (operation->determine_depending_area_of_interest(input, read_operation, output)) {
return true;
}
/* scale y */
- operation = getInputOperation(3);
- if (operation->determineDependingAreaOfInterest(input, readOperation, output)) {
+ operation = get_input_operation(3);
+ if (operation->determine_depending_area_of_interest(input, read_operation, output)) {
return true;
}
@@ -152,8 +149,8 @@ void DisplaceSimpleOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- const float width = this->getWidth();
- const float height = this->getHeight();
+ const float width = this->get_width();
+ const float height = this->get_height();
const MemoryBuffer *input_color = inputs[0];
for (BuffersIterator<float> it = output->iterate_with(inputs.drop_front(1), area); !it.is_end();
++it) {
@@ -162,8 +159,8 @@ void DisplaceSimpleOperation::update_memory_buffer_partial(MemoryBuffer *output,
/* Clamp x and y displacement to triple image resolution -
* to prevent hangs from huge values mistakenly plugged in eg. z buffers. */
- CLAMP(scale_x, -m_width_x4, m_width_x4);
- CLAMP(scale_y, -m_height_x4, m_height_x4);
+ CLAMP(scale_x, -width_x4_, width_x4_);
+ CLAMP(scale_y, -height_x4_, height_x4_);
/* Main displacement in pixel space. */
const float *vector = it.in(0);
diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h
index 99f52155466..c16146dc464 100644
--- a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h
+++ b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h
@@ -25,15 +25,15 @@ namespace blender::compositor {
class DisplaceSimpleOperation : public MultiThreadedOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputColorProgram;
- SocketReader *m_inputVectorProgram;
- SocketReader *m_inputScaleXProgram;
- SocketReader *m_inputScaleYProgram;
+ SocketReader *input_color_program_;
+ SocketReader *input_vector_program_;
+ SocketReader *input_scale_xprogram_;
+ SocketReader *input_scale_yprogram_;
- float m_width_x4;
- float m_height_x4;
+ float width_x4_;
+ float height_x4_;
public:
DisplaceSimpleOperation();
@@ -41,24 +41,24 @@ class DisplaceSimpleOperation : public MultiThreadedOperation {
/**
* we need a full buffer for the image
*/
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc
index 8155ff769a0..7618e318c77 100644
--- a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc
+++ b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc
@@ -17,56 +17,55 @@
*/
#include "COM_DistanceRGBMatteOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
DistanceRGBMatteOperation::DistanceRGBMatteOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Value);
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Value);
- this->m_inputImageProgram = nullptr;
- this->m_inputKeyProgram = nullptr;
- flags.can_be_constant = true;
+ input_image_program_ = nullptr;
+ input_key_program_ = nullptr;
+ flags_.can_be_constant = true;
}
-void DistanceRGBMatteOperation::initExecution()
+void DistanceRGBMatteOperation::init_execution()
{
- this->m_inputImageProgram = this->getInputSocketReader(0);
- this->m_inputKeyProgram = this->getInputSocketReader(1);
+ input_image_program_ = this->get_input_socket_reader(0);
+ input_key_program_ = this->get_input_socket_reader(1);
}
-void DistanceRGBMatteOperation::deinitExecution()
+void DistanceRGBMatteOperation::deinit_execution()
{
- this->m_inputImageProgram = nullptr;
- this->m_inputKeyProgram = nullptr;
+ input_image_program_ = nullptr;
+ input_key_program_ = nullptr;
}
-float DistanceRGBMatteOperation::calculateDistance(const float key[4], const float image[4])
+float DistanceRGBMatteOperation::calculate_distance(const float key[4], const float image[4])
{
return len_v3v3(key, image);
}
-void DistanceRGBMatteOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void DistanceRGBMatteOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inKey[4];
- float inImage[4];
+ float in_key[4];
+ float in_image[4];
- const float tolerance = this->m_settings->t1;
- const float falloff = this->m_settings->t2;
+ const float tolerance = settings_->t1;
+ const float falloff = settings_->t2;
float distance;
float alpha;
- this->m_inputKeyProgram->readSampled(inKey, x, y, sampler);
- this->m_inputImageProgram->readSampled(inImage, x, y, sampler);
+ input_key_program_->read_sampled(in_key, x, y, sampler);
+ input_image_program_->read_sampled(in_image, x, y, sampler);
- distance = this->calculateDistance(inKey, inImage);
+ distance = this->calculate_distance(in_key, in_image);
/* Store matte(alpha) value in [0] to go with
* COM_SetAlphaMultiplyOperation and the Value output.
@@ -81,16 +80,16 @@ void DistanceRGBMatteOperation::executePixelSampled(float output[4],
distance = distance - tolerance;
alpha = distance / falloff;
/* Only change if more transparent than before. */
- if (alpha < inImage[3]) {
+ if (alpha < in_image[3]) {
output[0] = alpha;
}
else { /* leave as before */
- output[0] = inImage[3];
+ output[0] = in_image[3];
}
}
else {
/* leave as before */
- output[0] = inImage[3];
+ output[0] = in_image[3];
}
}
@@ -102,9 +101,9 @@ void DistanceRGBMatteOperation::update_memory_buffer_partial(MemoryBuffer *outpu
const float *in_image = it.in(0);
const float *in_key = it.in(1);
- float distance = this->calculateDistance(in_key, in_image);
- const float tolerance = this->m_settings->t1;
- const float falloff = this->m_settings->t2;
+ float distance = this->calculate_distance(in_key, in_image);
+ const float tolerance = settings_->t1;
+ const float falloff = settings_->t2;
/* Store matte(alpha) value in [0] to go with
* COM_SetAlphaMultiplyOperation and the Value output.
diff --git a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h
index ba6682214ae..306a4e316f5 100644
--- a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h
+++ b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h
@@ -28,11 +28,11 @@ namespace blender::compositor {
*/
class DistanceRGBMatteOperation : public MultiThreadedOperation {
protected:
- NodeChroma *m_settings;
- SocketReader *m_inputImageProgram;
- SocketReader *m_inputKeyProgram;
+ NodeChroma *settings_;
+ SocketReader *input_image_program_;
+ SocketReader *input_key_program_;
- virtual float calculateDistance(const float key[4], const float image[4]);
+ virtual float calculate_distance(const float key[4], const float image[4]);
public:
/**
@@ -43,14 +43,14 @@ class DistanceRGBMatteOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void setSettings(NodeChroma *nodeChroma)
+ void set_settings(NodeChroma *node_chroma)
{
- this->m_settings = nodeChroma;
+ settings_ = node_chroma;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc
index 50e473ea5b3..682c01a63d5 100644
--- a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc
+++ b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc
@@ -17,11 +17,10 @@
*/
#include "COM_DistanceYCCMatteOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
-float DistanceYCCMatteOperation::calculateDistance(const float key[4], const float image[4])
+float DistanceYCCMatteOperation::calculate_distance(const float key[4], const float image[4])
{
/* only measure the second 2 values */
return len_v2v2(key + 1, image + 1);
diff --git a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h
index 0e178fddc39..1d5ed9f0de1 100644
--- a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h
+++ b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h
@@ -29,7 +29,7 @@ namespace blender::compositor {
*/
class DistanceYCCMatteOperation : public DistanceRGBMatteOperation {
protected:
- float calculateDistance(const float key[4], const float image[4]) override;
+ float calculate_distance(const float key[4], const float image[4]) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_DotproductOperation.cc b/source/blender/compositor/operations/COM_DotproductOperation.cc
index aa18ff1e827..ce1432547ae 100644
--- a/source/blender/compositor/operations/COM_DotproductOperation.cc
+++ b/source/blender/compositor/operations/COM_DotproductOperation.cc
@@ -22,37 +22,37 @@ namespace blender::compositor {
DotproductOperation::DotproductOperation()
{
- this->addInputSocket(DataType::Vector);
- this->addInputSocket(DataType::Vector);
- this->addOutputSocket(DataType::Value);
+ this->add_input_socket(DataType::Vector);
+ this->add_input_socket(DataType::Vector);
+ this->add_output_socket(DataType::Value);
this->set_canvas_input_index(0);
- this->m_input1Operation = nullptr;
- this->m_input2Operation = nullptr;
- flags.can_be_constant = true;
+ input1Operation_ = nullptr;
+ input2Operation_ = nullptr;
+ flags_.can_be_constant = true;
}
-void DotproductOperation::initExecution()
+void DotproductOperation::init_execution()
{
- this->m_input1Operation = this->getInputSocketReader(0);
- this->m_input2Operation = this->getInputSocketReader(1);
+ input1Operation_ = this->get_input_socket_reader(0);
+ input2Operation_ = this->get_input_socket_reader(1);
}
-void DotproductOperation::deinitExecution()
+void DotproductOperation::deinit_execution()
{
- this->m_input1Operation = nullptr;
- this->m_input2Operation = nullptr;
+ input1Operation_ = nullptr;
+ input2Operation_ = nullptr;
}
/** \todo current implementation is the inverse of a dot-product. not 'logically' correct
*/
-void DotproductOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void DotproductOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float input1[4];
float input2[4];
- this->m_input1Operation->readSampled(input1, x, y, sampler);
- this->m_input2Operation->readSampled(input2, x, y, sampler);
+ input1Operation_->read_sampled(input1, x, y, sampler);
+ input2Operation_->read_sampled(input2, x, y, sampler);
output[0] = -(input1[0] * input2[0] + input1[1] * input2[1] + input1[2] * input2[2]);
}
diff --git a/source/blender/compositor/operations/COM_DotproductOperation.h b/source/blender/compositor/operations/COM_DotproductOperation.h
index c3f39d43fff..f9e5d4d39c4 100644
--- a/source/blender/compositor/operations/COM_DotproductOperation.h
+++ b/source/blender/compositor/operations/COM_DotproductOperation.h
@@ -24,15 +24,15 @@ namespace blender::compositor {
class DotproductOperation : public MultiThreadedOperation {
private:
- SocketReader *m_input1Operation;
- SocketReader *m_input2Operation;
+ SocketReader *input1Operation_;
+ SocketReader *input2Operation_;
public:
DotproductOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc
index d112334b749..22899bd396a 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc
@@ -18,10 +18,7 @@
#include <cstdlib>
-#include "BLI_math.h"
#include "COM_DoubleEdgeMaskOperation.h"
-#include "DNA_node_types.h"
-#include "MEM_guardedalloc.h"
namespace blender::compositor {
@@ -948,8 +945,8 @@ static void do_createEdgeLocationBuffer(unsigned int t,
const unsigned int *lres,
float *res,
unsigned short *gbuf,
- unsigned int *innerEdgeOffset,
- unsigned int *outerEdgeOffset,
+ unsigned int *inner_edge_offset,
+ unsigned int *outer_edge_offset,
unsigned int isz,
unsigned int gsz)
{
@@ -959,14 +956,14 @@ static void do_createEdgeLocationBuffer(unsigned int t,
unsigned int dmin; /* Minimum edge distance. */
unsigned int rsl; /* Long used for finding fast `1.0/sqrt`. */
- unsigned int gradientFillOffset;
+ unsigned int gradient_fill_offset;
/* For looping inner edge pixel indexes, represents current position from offset. */
- unsigned int innerAccum = 0;
+ unsigned int inner_accum = 0;
/* For looping outer edge pixel indexes, represents current position from offset. */
- unsigned int outerAccum = 0;
+ unsigned int outer_accum = 0;
/* For looping gradient pixel indexes, represents current position from offset. */
- unsigned int gradientAccum = 0;
+ unsigned int gradient_accum = 0;
/* Disable clang-format to prevent line-wrapping. */
/* clang-format off */
@@ -999,7 +996,7 @@ static void do_createEdgeLocationBuffer(unsigned int t,
* ..oooo...
* .oggggo..
* .oggiggo.
- * .ogiFigo.
+ * .ogi_figo.
* .oggiggo.
* .oggggo..
* ..oooo...
@@ -1012,7 +1009,7 @@ static void do_createEdgeLocationBuffer(unsigned int t,
*
* The memory in gbuf[] after filling will look like this:
*
- * gradientFillOffset (0 pixels) innerEdgeOffset (18 pixels) outerEdgeOffset (22 pixels)
+ * gradient_fill_offset (0 pixels) inner_edge_offset (18 pixels) outer_edge_offset (22 pixels)
* / / /
* / / /
* |X Y X Y X Y X Y > <X Y X Y > <X Y X Y X Y > <X Y X Y | <- (x,y)
@@ -1023,7 +1020,7 @@ static void do_createEdgeLocationBuffer(unsigned int t,
* / / /
* / / /
* / / /
- * +---------- gradientAccum (18) ---------+ +--- innerAccum (22) ---+ +--- outerAccum (40) ---+
+ * +---------- gradient_accum (18) ---------+ +--- inner_accum (22) ---+ +--- outer_accum (40) ---+
*
*
* Ultimately we do need the pixel's memory buffer index to set the output
@@ -1033,36 +1030,36 @@ static void do_createEdgeLocationBuffer(unsigned int t,
*/
/* clang-format on */
- gradientFillOffset = 0; /* Since there are likely "more" of these, put it first. :). */
- *innerEdgeOffset = gradientFillOffset + gsz; /* Set start of inner edge indexes. */
- *outerEdgeOffset = (*innerEdgeOffset) + isz; /* Set start of outer edge indexes. */
- /* Set the accumulators to correct positions */ /* Set up some accumulator variables for loops.
- */
- gradientAccum = gradientFillOffset; /* Each accumulator variable starts at its respective. */
- innerAccum = *innerEdgeOffset; /* Section's offset so when we start filling, each. */
- outerAccum = *outerEdgeOffset; /* Section fills up its allocated space in gbuf. */
+ gradient_fill_offset = 0; /* Since there are likely "more" of these, put it first. :). */
+ *inner_edge_offset = gradient_fill_offset + gsz; /* Set start of inner edge indexes. */
+ *outer_edge_offset = (*inner_edge_offset) + isz; /* Set start of outer edge indexes. */
+ /* Set the accumulators to correct positions */ /* Set up some accumulator variables for loops.
+ */
+ gradient_accum = gradient_fill_offset; /* Each accumulator variable starts at its respective. */
+ inner_accum = *inner_edge_offset; /* Section's offset so when we start filling, each. */
+ outer_accum = *outer_edge_offset; /* Section fills up its allocated space in gbuf. */
/* Uses `dmin=row`, `rsl=col`. */
for (x = 0, dmin = 0; x < t; x += rw, dmin++) {
for (rsl = 0; rsl < rw; rsl++) {
a = x + rsl;
- if (lres[a] == 2) { /* It is a gradient pixel flagged by 2. */
- ud = gradientAccum << 1; /* Double the index to reach correct unsigned short location. */
- gbuf[ud] = dmin; /* Insert pixel's row into gradient pixel location buffer. */
- gbuf[ud + 1] = rsl; /* Insert pixel's column into gradient pixel location buffer. */
- gradientAccum++; /* Increment gradient index buffer pointer. */
+ if (lres[a] == 2) { /* It is a gradient pixel flagged by 2. */
+ ud = gradient_accum << 1; /* Double the index to reach correct unsigned short location. */
+ gbuf[ud] = dmin; /* Insert pixel's row into gradient pixel location buffer. */
+ gbuf[ud + 1] = rsl; /* Insert pixel's column into gradient pixel location buffer. */
+ gradient_accum++; /* Increment gradient index buffer pointer. */
}
else if (lres[a] == 3) { /* It is an outer edge pixel flagged by 3. */
- ud = outerAccum << 1; /* Double the index to reach correct unsigned short location. */
+ ud = outer_accum << 1; /* Double the index to reach correct unsigned short location. */
gbuf[ud] = dmin; /* Insert pixel's row into outer edge pixel location buffer. */
gbuf[ud + 1] = rsl; /* Insert pixel's column into outer edge pixel location buffer. */
- outerAccum++; /* Increment outer edge index buffer pointer. */
+ outer_accum++; /* Increment outer edge index buffer pointer. */
res[a] = 0.0f; /* Set output pixel intensity now since it won't change later. */
}
else if (lres[a] == 4) { /* It is an inner edge pixel flagged by 4. */
- ud = innerAccum << 1; /* Double int index to reach correct unsigned short location. */
+ ud = inner_accum << 1; /* Double int index to reach correct unsigned short location. */
gbuf[ud] = dmin; /* Insert pixel's row into inner edge pixel location buffer. */
gbuf[ud + 1] = rsl; /* Insert pixel's column into inner edge pixel location buffer. */
- innerAccum++; /* Increment inner edge index buffer pointer. */
+ inner_accum++; /* Increment inner edge index buffer pointer. */
res[a] = 1.0f; /* Set output pixel intensity now since it won't change later. */
}
}
@@ -1075,8 +1072,8 @@ static void do_fillGradientBuffer(unsigned int rw,
unsigned int isz,
unsigned int osz,
unsigned int gsz,
- unsigned int innerEdgeOffset,
- unsigned int outerEdgeOffset)
+ unsigned int inner_edge_offset,
+ unsigned int outer_edge_offset)
{
int x; /* Pixel loop counter. */
int a; /* Temporary pixel index buffer loop counter. */
@@ -1085,7 +1082,7 @@ static void do_fillGradientBuffer(unsigned int rw,
float rsf; /* Float used for finding fast `1.0/sqrt`. */
const float rsopf = 1.5f; /* Constant float used for finding fast `1.0/sqrt`. */
- unsigned int gradientFillOffset;
+ unsigned int gradient_fill_offset;
unsigned int t;
unsigned int ud; /* Unscaled edge distance. */
unsigned int dmin; /* Minimum edge distance. */
@@ -1154,11 +1151,11 @@ static void do_fillGradientBuffer(unsigned int rw,
*/
for (x = gsz - 1; x >= 0; x--) {
- gradientFillOffset = x << 1;
- t = gbuf[gradientFillOffset]; /* Calculate column of pixel indexed by `gbuf[x]`. */
- fsz = gbuf[gradientFillOffset + 1]; /* Calculate row of pixel indexed by `gbuf[x]`. */
- dmin = 0xffffffff; /* Reset min distance to edge pixel. */
- for (a = outerEdgeOffset + osz - 1; a >= outerEdgeOffset;
+ gradient_fill_offset = x << 1;
+ t = gbuf[gradient_fill_offset]; /* Calculate column of pixel indexed by `gbuf[x]`. */
+ fsz = gbuf[gradient_fill_offset + 1]; /* Calculate row of pixel indexed by `gbuf[x]`. */
+ dmin = 0xffffffff; /* Reset min distance to edge pixel. */
+ for (a = outer_edge_offset + osz - 1; a >= outer_edge_offset;
a--) { /* Loop through all outer edge buffer pixels. */
ud = a << 1;
dy = t - gbuf[ud]; /* Set dx to gradient pixel column - outer edge pixel row. */
@@ -1176,7 +1173,7 @@ static void do_fillGradientBuffer(unsigned int rw,
odist = odist * (rsopf - (rsf * odist *
odist)); /* -- This line can be iterated for more accuracy. -- */
dmin = 0xffffffff; /* Reset min distance to edge pixel. */
- for (a = innerEdgeOffset + isz - 1; a >= innerEdgeOffset;
+ for (a = inner_edge_offset + isz - 1; a >= inner_edge_offset;
a--) { /* Loop through all inside edge pixels. */
ud = a << 1;
dy = t - gbuf[ud]; /* Compute delta in Y from gradient pixel to inside edge pixel. */
@@ -1204,14 +1201,14 @@ static void do_fillGradientBuffer(unsigned int rw,
/* Here we reconstruct the pixel's memory location in the CompBuf by
* `Pixel Index = Pixel Column + ( Pixel Row * Row Width )`. */
- res[gbuf[gradientFillOffset + 1] + (gbuf[gradientFillOffset] * rw)] =
+ res[gbuf[gradient_fill_offset + 1] + (gbuf[gradient_fill_offset] * rw)] =
(idist / (idist + odist)); /* Set intensity. */
}
}
/* End of copy. */
-void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float *res)
+void DoubleEdgeMaskOperation::do_double_edge_mask(float *imask, float *omask, float *res)
{
unsigned int *lres; /* Pointer to output pixel buffer (for bit operations). */
unsigned int *limask; /* Pointer to inner mask (for bit operations). */
@@ -1225,17 +1222,17 @@ void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float
unsigned int osz = 0; /* Size (in pixels) of outside edge pixel index buffer. */
unsigned int gsz = 0; /* Size (in pixels) of gradient pixel index buffer. */
unsigned int rsize[3]; /* Size storage to pass to helper functions. */
- unsigned int innerEdgeOffset =
+ unsigned int inner_edge_offset =
0; /* Offset into final buffer where inner edge pixel indexes start. */
- unsigned int outerEdgeOffset =
+ unsigned int outer_edge_offset =
0; /* Offset into final buffer where outer edge pixel indexes start. */
unsigned short *gbuf; /* Gradient/inner/outer pixel location index buffer. */
if (true) { /* If both input sockets have some data coming in... */
- rw = this->getWidth(); /* Width of a row of pixels. */
- t = (rw * this->getHeight()) - 1; /* Determine size of the frame. */
+ rw = this->get_width(); /* Width of a row of pixels. */
+ t = (rw * this->get_height()) - 1; /* Determine size of the frame. */
memset(res,
0,
sizeof(float) *
@@ -1270,8 +1267,8 @@ void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float
*
* Each version has slightly different criteria for detecting an edge pixel.
*/
- if (this->m_adjacentOnly) { /* If "adjacent only" inner edge mode is turned on. */
- if (this->m_keepInside) { /* If "keep inside" buffer edge mode is turned on. */
+ if (adjacent_only_) { /* If "adjacent only" inner edge mode is turned on. */
+ if (keep_inside_) { /* If "keep inside" buffer edge mode is turned on. */
do_adjacentKeepBorders(t, rw, limask, lomask, lres, res, rsize);
}
else { /* "bleed out" buffer edge mode is turned on. */
@@ -1284,8 +1281,8 @@ void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float
/* Detect edges in all non-border pixels in the buffer. */
do_adjacentEdgeDetection(t, rw, limask, lomask, lres, res, rsize, isz, osz, gsz);
}
- else { /* "all" inner edge mode is turned on. */
- if (this->m_keepInside) { /* If "keep inside" buffer edge mode is turned on. */
+ else { /* "all" inner edge mode is turned on. */
+ if (keep_inside_) { /* If "keep inside" buffer edge mode is turned on. */
do_allKeepBorders(t, rw, limask, lomask, lres, res, rsize);
}
else { /* "bleed out" buffer edge mode is turned on. */
@@ -1312,8 +1309,8 @@ void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float
gbuf = (unsigned short *)MEM_callocN(sizeof(unsigned short) * fsz * 2, "DEM");
do_createEdgeLocationBuffer(
- t, rw, lres, res, gbuf, &innerEdgeOffset, &outerEdgeOffset, isz, gsz);
- do_fillGradientBuffer(rw, res, gbuf, isz, osz, gsz, innerEdgeOffset, outerEdgeOffset);
+ t, rw, lres, res, gbuf, &inner_edge_offset, &outer_edge_offset, isz, gsz);
+ do_fillGradientBuffer(rw, res, gbuf, isz, osz, gsz, inner_edge_offset, outer_edge_offset);
/* Free the gradient index buffer. */
MEM_freeN(gbuf);
@@ -1322,76 +1319,75 @@ void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float
DoubleEdgeMaskOperation::DoubleEdgeMaskOperation()
{
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
- this->m_inputInnerMask = nullptr;
- this->m_inputOuterMask = nullptr;
- this->m_adjacentOnly = false;
- this->m_keepInside = false;
- this->flags.complex = true;
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
+ input_inner_mask_ = nullptr;
+ input_outer_mask_ = nullptr;
+ adjacent_only_ = false;
+ keep_inside_ = false;
+ flags_.complex = true;
is_output_rendered_ = false;
}
-bool DoubleEdgeMaskOperation::determineDependingAreaOfInterest(rcti * /*input*/,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool DoubleEdgeMaskOperation::determine_depending_area_of_interest(
+ rcti * /*input*/, ReadBufferOperation *read_operation, rcti *output)
{
- if (this->m_cachedInstance == nullptr) {
- rcti newInput;
- newInput.xmax = this->getWidth();
- newInput.xmin = 0;
- newInput.ymax = this->getHeight();
- newInput.ymin = 0;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ if (cached_instance_ == nullptr) {
+ rcti new_input;
+ new_input.xmax = this->get_width();
+ new_input.xmin = 0;
+ new_input.ymax = this->get_height();
+ new_input.ymin = 0;
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
return false;
}
-void DoubleEdgeMaskOperation::initExecution()
+void DoubleEdgeMaskOperation::init_execution()
{
- this->m_inputInnerMask = this->getInputSocketReader(0);
- this->m_inputOuterMask = this->getInputSocketReader(1);
- initMutex();
- this->m_cachedInstance = nullptr;
+ input_inner_mask_ = this->get_input_socket_reader(0);
+ input_outer_mask_ = this->get_input_socket_reader(1);
+ init_mutex();
+ cached_instance_ = nullptr;
}
-void *DoubleEdgeMaskOperation::initializeTileData(rcti *rect)
+void *DoubleEdgeMaskOperation::initialize_tile_data(rcti *rect)
{
- if (this->m_cachedInstance) {
- return this->m_cachedInstance;
+ if (cached_instance_) {
+ return cached_instance_;
}
- lockMutex();
- if (this->m_cachedInstance == nullptr) {
- MemoryBuffer *innerMask = (MemoryBuffer *)this->m_inputInnerMask->initializeTileData(rect);
- MemoryBuffer *outerMask = (MemoryBuffer *)this->m_inputOuterMask->initializeTileData(rect);
- float *data = (float *)MEM_mallocN(sizeof(float) * this->getWidth() * this->getHeight(),
+ lock_mutex();
+ if (cached_instance_ == nullptr) {
+ MemoryBuffer *inner_mask = (MemoryBuffer *)input_inner_mask_->initialize_tile_data(rect);
+ MemoryBuffer *outer_mask = (MemoryBuffer *)input_outer_mask_->initialize_tile_data(rect);
+ float *data = (float *)MEM_mallocN(sizeof(float) * this->get_width() * this->get_height(),
__func__);
- float *imask = innerMask->getBuffer();
- float *omask = outerMask->getBuffer();
- doDoubleEdgeMask(imask, omask, data);
- this->m_cachedInstance = data;
+ float *imask = inner_mask->get_buffer();
+ float *omask = outer_mask->get_buffer();
+ do_double_edge_mask(imask, omask, data);
+ cached_instance_ = data;
}
- unlockMutex();
- return this->m_cachedInstance;
+ unlock_mutex();
+ return cached_instance_;
}
-void DoubleEdgeMaskOperation::executePixel(float output[4], int x, int y, void *data)
+void DoubleEdgeMaskOperation::execute_pixel(float output[4], int x, int y, void *data)
{
float *buffer = (float *)data;
- int index = (y * this->getWidth() + x);
+ int index = (y * this->get_width() + x);
output[0] = buffer[index];
}
-void DoubleEdgeMaskOperation::deinitExecution()
+void DoubleEdgeMaskOperation::deinit_execution()
{
- this->m_inputInnerMask = nullptr;
- this->m_inputOuterMask = nullptr;
- deinitMutex();
- if (this->m_cachedInstance) {
- MEM_freeN(this->m_cachedInstance);
- this->m_cachedInstance = nullptr;
+ input_inner_mask_ = nullptr;
+ input_outer_mask_ = nullptr;
+ deinit_mutex();
+ if (cached_instance_) {
+ MEM_freeN(cached_instance_);
+ cached_instance_ = nullptr;
}
}
@@ -1415,11 +1411,11 @@ void DoubleEdgeMaskOperation::update_memory_buffer(MemoryBuffer *output,
MemoryBuffer *outer_mask = input_outer_mask->is_a_single_elem() ? input_outer_mask->inflate() :
input_outer_mask;
- BLI_assert(output->getWidth() == this->getWidth());
- BLI_assert(output->getHeight() == this->getHeight());
+ BLI_assert(output->get_width() == this->get_width());
+ BLI_assert(output->get_height() == this->get_height());
/* TODO(manzanilla): Once tiled implementation is removed, use execution system to run
* multi-threaded where possible. */
- doDoubleEdgeMask(inner_mask->getBuffer(), outer_mask->getBuffer(), output->getBuffer());
+ do_double_edge_mask(inner_mask->get_buffer(), outer_mask->get_buffer(), output->get_buffer());
is_output_rendered_ = true;
if (inner_mask != input_inner_mask) {
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h
index 45a80bbbbf0..f2086d9ebd4 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h
@@ -25,50 +25,50 @@ namespace blender::compositor {
class DoubleEdgeMaskOperation : public NodeOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputOuterMask;
- SocketReader *m_inputInnerMask;
- bool m_adjacentOnly;
- bool m_keepInside;
+ SocketReader *input_outer_mask_;
+ SocketReader *input_inner_mask_;
+ bool adjacent_only_;
+ bool keep_inside_;
/* TODO(manzanilla): To be removed with tiled implementation. */
- float *m_cachedInstance;
+ float *cached_instance_;
bool is_output_rendered_;
public:
DoubleEdgeMaskOperation();
- void doDoubleEdgeMask(float *imask, float *omask, float *res);
+ void do_double_edge_mask(float *imask, float *omask, float *res);
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void setAdjecentOnly(bool adjacentOnly)
+ void set_adjecent_only(bool adjacent_only)
{
- this->m_adjacentOnly = adjacentOnly;
+ adjacent_only_ = adjacent_only;
}
- void setKeepInside(bool keepInside)
+ void set_keep_inside(bool keep_inside)
{
- this->m_keepInside = keepInside;
+ keep_inside_ = keep_inside;
}
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc
index bf6eee6d3f9..a051e06d15e 100644
--- a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc
+++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc
@@ -17,84 +17,80 @@
*/
#include "COM_EllipseMaskOperation.h"
-#include "BLI_math.h"
-#include "DNA_node_types.h"
-
-#include <functional>
namespace blender::compositor {
EllipseMaskOperation::EllipseMaskOperation()
{
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
- this->m_inputMask = nullptr;
- this->m_inputValue = nullptr;
- this->m_cosine = 0.0f;
- this->m_sine = 0.0f;
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
+ input_mask_ = nullptr;
+ input_value_ = nullptr;
+ cosine_ = 0.0f;
+ sine_ = 0.0f;
}
-void EllipseMaskOperation::initExecution()
+void EllipseMaskOperation::init_execution()
{
- this->m_inputMask = this->getInputSocketReader(0);
- this->m_inputValue = this->getInputSocketReader(1);
- const double rad = (double)this->m_data->rotation;
- this->m_cosine = cos(rad);
- this->m_sine = sin(rad);
- this->m_aspectRatio = ((float)this->getWidth()) / this->getHeight();
+ input_mask_ = this->get_input_socket_reader(0);
+ input_value_ = this->get_input_socket_reader(1);
+ const double rad = (double)data_->rotation;
+ cosine_ = cos(rad);
+ sine_ = sin(rad);
+ aspect_ratio_ = ((float)this->get_width()) / this->get_height();
}
-void EllipseMaskOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void EllipseMaskOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputMask[4];
- float inputValue[4];
+ float input_mask[4];
+ float input_value[4];
- float rx = x / this->getWidth();
- float ry = y / this->getHeight();
+ float rx = x / MAX2(this->get_width() - 1.0f, FLT_EPSILON);
+ float ry = y / MAX2(this->get_height() - 1.0f, FLT_EPSILON);
- const float dy = (ry - this->m_data->y) / this->m_aspectRatio;
- const float dx = rx - this->m_data->x;
- rx = this->m_data->x + (this->m_cosine * dx + this->m_sine * dy);
- ry = this->m_data->y + (-this->m_sine * dx + this->m_cosine * dy);
+ const float dy = (ry - data_->y) / aspect_ratio_;
+ const float dx = rx - data_->x;
+ rx = data_->x + (cosine_ * dx + sine_ * dy);
+ ry = data_->y + (-sine_ * dx + cosine_ * dy);
- this->m_inputMask->readSampled(inputMask, x, y, sampler);
- this->m_inputValue->readSampled(inputValue, x, y, sampler);
+ input_mask_->read_sampled(input_mask, x, y, sampler);
+ input_value_->read_sampled(input_value, x, y, sampler);
- const float halfHeight = (this->m_data->height) / 2.0f;
- const float halfWidth = this->m_data->width / 2.0f;
- float sx = rx - this->m_data->x;
+ const float half_height = (data_->height) / 2.0f;
+ const float half_width = data_->width / 2.0f;
+ float sx = rx - data_->x;
sx *= sx;
- const float tx = halfWidth * halfWidth;
- float sy = ry - this->m_data->y;
+ const float tx = half_width * half_width;
+ float sy = ry - data_->y;
sy *= sy;
- const float ty = halfHeight * halfHeight;
+ const float ty = half_height * half_height;
- bool inside = ((sx / tx) + (sy / ty)) < 1.0f;
+ bool inside = ((sx / tx) + (sy / ty)) <= (1.0f + FLT_EPSILON);
- switch (this->m_maskType) {
+ switch (mask_type_) {
case CMP_NODE_MASKTYPE_ADD:
if (inside) {
- output[0] = MAX2(inputMask[0], inputValue[0]);
+ output[0] = MAX2(input_mask[0], input_value[0]);
}
else {
- output[0] = inputMask[0];
+ output[0] = input_mask[0];
}
break;
case CMP_NODE_MASKTYPE_SUBTRACT:
if (inside) {
- output[0] = inputMask[0] - inputValue[0];
+ output[0] = input_mask[0] - input_value[0];
CLAMP(output[0], 0, 1);
}
else {
- output[0] = inputMask[0];
+ output[0] = input_mask[0];
}
break;
case CMP_NODE_MASKTYPE_MULTIPLY:
if (inside) {
- output[0] = inputMask[0] * inputValue[0];
+ output[0] = input_mask[0] * input_value[0];
}
else {
output[0] = 0;
@@ -102,15 +98,15 @@ void EllipseMaskOperation::executePixelSampled(float output[4],
break;
case CMP_NODE_MASKTYPE_NOT:
if (inside) {
- if (inputMask[0] > 0.0f) {
+ if (input_mask[0] > 0.0f) {
output[0] = 0;
}
else {
- output[0] = inputValue[0];
+ output[0] = input_value[0];
}
}
else {
- output[0] = inputMask[0];
+ output[0] = input_mask[0];
}
break;
}
@@ -121,7 +117,7 @@ void EllipseMaskOperation::update_memory_buffer_partial(MemoryBuffer *output,
Span<MemoryBuffer *> inputs)
{
MaskFunc mask_func;
- switch (m_maskType) {
+ switch (mask_type_) {
case CMP_NODE_MASKTYPE_ADD:
mask_func = [](const bool is_inside, const float *mask, const float *value) {
return is_inside ? MAX2(mask[0], value[0]) : mask[0];
@@ -156,28 +152,28 @@ void EllipseMaskOperation::apply_mask(MemoryBuffer *output,
{
const MemoryBuffer *input_mask = inputs[0];
const MemoryBuffer *input_value = inputs[1];
- const float op_w = this->getWidth();
- const float op_h = this->getHeight();
- const float half_w = this->m_data->width / 2.0f;
- const float half_h = this->m_data->height / 2.0f;
+ const float op_last_x = MAX2(this->get_width() - 1.0f, FLT_EPSILON);
+ const float op_last_y = MAX2(this->get_height() - 1.0f, FLT_EPSILON);
+ const float half_w = data_->width / 2.0f;
+ const float half_h = data_->height / 2.0f;
const float tx = half_w * half_w;
const float ty = half_h * half_h;
for (int y = area.ymin; y < area.ymax; y++) {
- const float op_ry = y / op_h;
- const float dy = (op_ry - this->m_data->y) / m_aspectRatio;
+ const float op_ry = y / op_last_y;
+ const float dy = (op_ry - data_->y) / aspect_ratio_;
float *out = output->get_elem(area.xmin, y);
const float *mask = input_mask->get_elem(area.xmin, y);
const float *value = input_value->get_elem(area.xmin, y);
for (int x = area.xmin; x < area.xmax; x++) {
- const float op_rx = x / op_w;
- const float dx = op_rx - this->m_data->x;
- const float rx = this->m_data->x + (m_cosine * dx + m_sine * dy);
- const float ry = this->m_data->y + (-m_sine * dx + m_cosine * dy);
- float sx = rx - this->m_data->x;
+ const float op_rx = x / op_last_x;
+ const float dx = op_rx - data_->x;
+ const float rx = data_->x + (cosine_ * dx + sine_ * dy);
+ const float ry = data_->y + (-sine_ * dx + cosine_ * dy);
+ float sx = rx - data_->x;
sx *= sx;
- float sy = ry - this->m_data->y;
+ float sy = ry - data_->y;
sy *= sy;
- const bool inside = ((sx / tx) + (sy / ty)) < 1.0f;
+ const bool inside = ((sx / tx) + (sy / ty)) <= (1.0f + FLT_EPSILON);
out[0] = mask_func(inside, mask, value);
mask += input_mask->elem_stride;
@@ -187,10 +183,10 @@ void EllipseMaskOperation::apply_mask(MemoryBuffer *output,
}
}
-void EllipseMaskOperation::deinitExecution()
+void EllipseMaskOperation::deinit_execution()
{
- this->m_inputMask = nullptr;
- this->m_inputValue = nullptr;
+ input_mask_ = nullptr;
+ input_value_ = nullptr;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.h b/source/blender/compositor/operations/COM_EllipseMaskOperation.h
index fba3f979d26..7a6f96ab1b1 100644
--- a/source/blender/compositor/operations/COM_EllipseMaskOperation.h
+++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.h
@@ -27,17 +27,17 @@ class EllipseMaskOperation : public MultiThreadedOperation {
using MaskFunc = std::function<float(bool is_inside, const float *mask, const float *value)>;
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputMask;
- SocketReader *m_inputValue;
+ SocketReader *input_mask_;
+ SocketReader *input_value_;
- float m_sine;
- float m_cosine;
- float m_aspectRatio;
- int m_maskType;
+ float sine_;
+ float cosine_;
+ float aspect_ratio_;
+ int mask_type_;
- NodeEllipseMask *m_data;
+ NodeEllipseMask *data_;
public:
EllipseMaskOperation();
@@ -45,26 +45,26 @@ class EllipseMaskOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setData(NodeEllipseMask *data)
+ void set_data(NodeEllipseMask *data)
{
- this->m_data = data;
+ data_ = data;
}
- void setMaskType(int maskType)
+ void set_mask_type(int mask_type)
{
- this->m_maskType = maskType;
+ mask_type_ = mask_type;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc
index f45b77c6ebc..850fad1d96a 100644
--- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc
@@ -18,105 +18,103 @@
#include <climits>
-#include "BLI_utildefines.h"
#include "COM_FastGaussianBlurOperation.h"
-#include "MEM_guardedalloc.h"
namespace blender::compositor {
FastGaussianBlurOperation::FastGaussianBlurOperation() : BlurBaseOperation(DataType::Color)
{
- this->m_iirgaus = nullptr;
+ iirgaus_ = nullptr;
}
-void FastGaussianBlurOperation::executePixel(float output[4], int x, int y, void *data)
+void FastGaussianBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
{
- MemoryBuffer *newData = (MemoryBuffer *)data;
- newData->read(output, x, y);
+ MemoryBuffer *new_data = (MemoryBuffer *)data;
+ new_data->read(output, x, y);
}
-bool FastGaussianBlurOperation::determineDependingAreaOfInterest(
- rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
+bool FastGaussianBlurOperation::determine_depending_area_of_interest(
+ rcti * /*input*/, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
- rcti sizeInput;
- sizeInput.xmin = 0;
- sizeInput.ymin = 0;
- sizeInput.xmax = 5;
- sizeInput.ymax = 5;
-
- NodeOperation *operation = this->getInputOperation(1);
- if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
+ rcti new_input;
+ rcti size_input;
+ size_input.xmin = 0;
+ size_input.ymin = 0;
+ size_input.xmax = 5;
+ size_input.ymax = 5;
+
+ NodeOperation *operation = this->get_input_operation(1);
+ if (operation->determine_depending_area_of_interest(&size_input, read_operation, output)) {
return true;
}
- if (this->m_iirgaus) {
+ if (iirgaus_) {
return false;
}
- newInput.xmin = 0;
- newInput.ymin = 0;
- newInput.xmax = this->getWidth();
- newInput.ymax = this->getHeight();
+ new_input.xmin = 0;
+ new_input.ymin = 0;
+ new_input.xmax = this->get_width();
+ new_input.ymax = this->get_height();
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void FastGaussianBlurOperation::init_data()
{
BlurBaseOperation::init_data();
- this->m_sx = this->m_data.sizex * this->m_size / 2.0f;
- this->m_sy = this->m_data.sizey * this->m_size / 2.0f;
+ sx_ = data_.sizex * size_ / 2.0f;
+ sy_ = data_.sizey * size_ / 2.0f;
}
-void FastGaussianBlurOperation::initExecution()
+void FastGaussianBlurOperation::init_execution()
{
- BlurBaseOperation::initExecution();
- BlurBaseOperation::initMutex();
+ BlurBaseOperation::init_execution();
+ BlurBaseOperation::init_mutex();
}
-void FastGaussianBlurOperation::deinitExecution()
+void FastGaussianBlurOperation::deinit_execution()
{
- if (this->m_iirgaus) {
- delete this->m_iirgaus;
- this->m_iirgaus = nullptr;
+ if (iirgaus_) {
+ delete iirgaus_;
+ iirgaus_ = nullptr;
}
- BlurBaseOperation::deinitMutex();
+ BlurBaseOperation::deinit_mutex();
}
-void *FastGaussianBlurOperation::initializeTileData(rcti *rect)
+void *FastGaussianBlurOperation::initialize_tile_data(rcti *rect)
{
- lockMutex();
- if (!this->m_iirgaus) {
- MemoryBuffer *newBuf = (MemoryBuffer *)this->m_inputProgram->initializeTileData(rect);
- MemoryBuffer *copy = new MemoryBuffer(*newBuf);
- updateSize();
+ lock_mutex();
+ if (!iirgaus_) {
+ MemoryBuffer *new_buf = (MemoryBuffer *)input_program_->initialize_tile_data(rect);
+ MemoryBuffer *copy = new MemoryBuffer(*new_buf);
+ update_size();
int c;
- this->m_sx = this->m_data.sizex * this->m_size / 2.0f;
- this->m_sy = this->m_data.sizey * this->m_size / 2.0f;
+ sx_ = data_.sizex * size_ / 2.0f;
+ sy_ = data_.sizey * size_ / 2.0f;
- if ((this->m_sx == this->m_sy) && (this->m_sx > 0.0f)) {
+ if ((sx_ == sy_) && (sx_ > 0.0f)) {
for (c = 0; c < COM_DATA_TYPE_COLOR_CHANNELS; c++) {
- IIR_gauss(copy, this->m_sx, c, 3);
+ IIR_gauss(copy, sx_, c, 3);
}
}
else {
- if (this->m_sx > 0.0f) {
+ if (sx_ > 0.0f) {
for (c = 0; c < COM_DATA_TYPE_COLOR_CHANNELS; c++) {
- IIR_gauss(copy, this->m_sx, c, 1);
+ IIR_gauss(copy, sx_, c, 1);
}
}
- if (this->m_sy > 0.0f) {
+ if (sy_ > 0.0f) {
for (c = 0; c < COM_DATA_TYPE_COLOR_CHANNELS; c++) {
- IIR_gauss(copy, this->m_sy, c, 2);
+ IIR_gauss(copy, sy_, c, 2);
}
}
}
- this->m_iirgaus = copy;
+ iirgaus_ = copy;
}
- unlockMutex();
- return this->m_iirgaus;
+ unlock_mutex();
+ return iirgaus_;
}
void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
@@ -127,11 +125,11 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
BLI_assert(!src->is_a_single_elem());
double q, q2, sc, cf[4], tsM[9], tsu[3], tsv[3];
double *X, *Y, *W;
- const unsigned int src_width = src->getWidth();
- const unsigned int src_height = src->getHeight();
+ const unsigned int src_width = src->get_width();
+ const unsigned int src_height = src->get_height();
unsigned int x, y, sz;
unsigned int i;
- float *buffer = src->getBuffer();
+ float *buffer = src->get_buffer();
const uint8_t num_channels = src->get_num_channels();
/* <0.5 not valid, though can have a possibly useful sort of sharpening effect. */
@@ -292,24 +290,24 @@ void FastGaussianBlurOperation::update_memory_buffer_started(MemoryBuffer *outpu
image = output;
}
else {
- image = new MemoryBuffer(getOutputSocket()->getDataType(), area);
+ image = new MemoryBuffer(get_output_socket()->get_data_type(), area);
}
image->copy_from(input, area);
- if ((this->m_sx == this->m_sy) && (this->m_sx > 0.0f)) {
+ if ((sx_ == sy_) && (sx_ > 0.0f)) {
for (const int c : IndexRange(COM_DATA_TYPE_COLOR_CHANNELS)) {
- IIR_gauss(image, this->m_sx, c, 3);
+ IIR_gauss(image, sx_, c, 3);
}
}
else {
- if (this->m_sx > 0.0f) {
+ if (sx_ > 0.0f) {
for (const int c : IndexRange(COM_DATA_TYPE_COLOR_CHANNELS)) {
- IIR_gauss(image, this->m_sx, c, 1);
+ IIR_gauss(image, sx_, c, 1);
}
}
- if (this->m_sy > 0.0f) {
+ if (sy_ > 0.0f) {
for (const int c : IndexRange(COM_DATA_TYPE_COLOR_CHANNELS)) {
- IIR_gauss(image, this->m_sy, c, 2);
+ IIR_gauss(image, sy_, c, 2);
}
}
}
@@ -322,75 +320,75 @@ void FastGaussianBlurOperation::update_memory_buffer_started(MemoryBuffer *outpu
FastGaussianBlurValueOperation::FastGaussianBlurValueOperation()
{
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
- this->m_iirgaus = nullptr;
- this->m_inputprogram = nullptr;
- this->m_sigma = 1.0f;
- this->m_overlay = 0;
- flags.complex = true;
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
+ iirgaus_ = nullptr;
+ inputprogram_ = nullptr;
+ sigma_ = 1.0f;
+ overlay_ = 0;
+ flags_.complex = true;
}
-void FastGaussianBlurValueOperation::executePixel(float output[4], int x, int y, void *data)
+void FastGaussianBlurValueOperation::execute_pixel(float output[4], int x, int y, void *data)
{
- MemoryBuffer *newData = (MemoryBuffer *)data;
- newData->read(output, x, y);
+ MemoryBuffer *new_data = (MemoryBuffer *)data;
+ new_data->read(output, x, y);
}
-bool FastGaussianBlurValueOperation::determineDependingAreaOfInterest(
- rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
+bool FastGaussianBlurValueOperation::determine_depending_area_of_interest(
+ rcti * /*input*/, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
+ rcti new_input;
- if (this->m_iirgaus) {
+ if (iirgaus_) {
return false;
}
- newInput.xmin = 0;
- newInput.ymin = 0;
- newInput.xmax = this->getWidth();
- newInput.ymax = this->getHeight();
+ new_input.xmin = 0;
+ new_input.ymin = 0;
+ new_input.xmax = this->get_width();
+ new_input.ymax = this->get_height();
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
-void FastGaussianBlurValueOperation::initExecution()
+void FastGaussianBlurValueOperation::init_execution()
{
- this->m_inputprogram = getInputSocketReader(0);
- initMutex();
+ inputprogram_ = get_input_socket_reader(0);
+ init_mutex();
}
-void FastGaussianBlurValueOperation::deinitExecution()
+void FastGaussianBlurValueOperation::deinit_execution()
{
- if (this->m_iirgaus) {
- delete this->m_iirgaus;
- this->m_iirgaus = nullptr;
+ if (iirgaus_) {
+ delete iirgaus_;
+ iirgaus_ = nullptr;
}
- deinitMutex();
+ deinit_mutex();
}
-void *FastGaussianBlurValueOperation::initializeTileData(rcti *rect)
+void *FastGaussianBlurValueOperation::initialize_tile_data(rcti *rect)
{
- lockMutex();
- if (!this->m_iirgaus) {
- MemoryBuffer *newBuf = (MemoryBuffer *)this->m_inputprogram->initializeTileData(rect);
- MemoryBuffer *copy = new MemoryBuffer(*newBuf);
- FastGaussianBlurOperation::IIR_gauss(copy, this->m_sigma, 0, 3);
-
- if (this->m_overlay == FAST_GAUSS_OVERLAY_MIN) {
- float *src = newBuf->getBuffer();
- float *dst = copy->getBuffer();
- for (int i = copy->getWidth() * copy->getHeight(); i != 0;
+ lock_mutex();
+ if (!iirgaus_) {
+ MemoryBuffer *new_buf = (MemoryBuffer *)inputprogram_->initialize_tile_data(rect);
+ MemoryBuffer *copy = new MemoryBuffer(*new_buf);
+ FastGaussianBlurOperation::IIR_gauss(copy, sigma_, 0, 3);
+
+ if (overlay_ == FAST_GAUSS_OVERLAY_MIN) {
+ float *src = new_buf->get_buffer();
+ float *dst = copy->get_buffer();
+ for (int i = copy->get_width() * copy->get_height(); i != 0;
i--, src += COM_DATA_TYPE_VALUE_CHANNELS, dst += COM_DATA_TYPE_VALUE_CHANNELS) {
if (*src < *dst) {
*dst = *src;
}
}
}
- else if (this->m_overlay == FAST_GAUSS_OVERLAY_MAX) {
- float *src = newBuf->getBuffer();
- float *dst = copy->getBuffer();
- for (int i = copy->getWidth() * copy->getHeight(); i != 0;
+ else if (overlay_ == FAST_GAUSS_OVERLAY_MAX) {
+ float *src = new_buf->get_buffer();
+ float *dst = copy->get_buffer();
+ for (int i = copy->get_width() * copy->get_height(); i != 0;
i--, src += COM_DATA_TYPE_VALUE_CHANNELS, dst += COM_DATA_TYPE_VALUE_CHANNELS) {
if (*src > *dst) {
*dst = *src;
@@ -398,10 +396,10 @@ void *FastGaussianBlurValueOperation::initializeTileData(rcti *rect)
}
}
- this->m_iirgaus = copy;
+ iirgaus_ = copy;
}
- unlockMutex();
- return this->m_iirgaus;
+ unlock_mutex();
+ return iirgaus_;
}
void FastGaussianBlurValueOperation::get_area_of_interest(const int UNUSED(input_idx),
@@ -415,11 +413,11 @@ void FastGaussianBlurValueOperation::update_memory_buffer_started(MemoryBuffer *
const rcti &UNUSED(area),
Span<MemoryBuffer *> inputs)
{
- if (m_iirgaus == nullptr) {
+ if (iirgaus_ == nullptr) {
const MemoryBuffer *image = inputs[0];
MemoryBuffer *gauss = new MemoryBuffer(*image);
- FastGaussianBlurOperation::IIR_gauss(gauss, m_sigma, 0, 3);
- m_iirgaus = gauss;
+ FastGaussianBlurOperation::IIR_gauss(gauss, sigma_, 0, 3);
+ iirgaus_ = gauss;
}
}
@@ -428,13 +426,13 @@ void FastGaussianBlurValueOperation::update_memory_buffer_partial(MemoryBuffer *
Span<MemoryBuffer *> inputs)
{
MemoryBuffer *image = inputs[0];
- BuffersIterator<float> it = output->iterate_with({image, m_iirgaus}, area);
- if (this->m_overlay == FAST_GAUSS_OVERLAY_MIN) {
+ BuffersIterator<float> it = output->iterate_with({image, iirgaus_}, area);
+ if (overlay_ == FAST_GAUSS_OVERLAY_MIN) {
for (; !it.is_end(); ++it) {
*it.out = MIN2(*it.in(0), *it.in(1));
}
}
- else if (this->m_overlay == FAST_GAUSS_OVERLAY_MAX) {
+ else if (overlay_ == FAST_GAUSS_OVERLAY_MAX) {
for (; !it.is_end(); ++it) {
*it.out = MAX2(*it.in(0), *it.in(1));
}
diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h
index f42fc76a119..8d33e5ef244 100644
--- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h
+++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h
@@ -25,22 +25,22 @@ namespace blender::compositor {
class FastGaussianBlurOperation : public BlurBaseOperation {
private:
- float m_sx;
- float m_sy;
- MemoryBuffer *m_iirgaus;
+ float sx_;
+ float sy_;
+ MemoryBuffer *iirgaus_;
public:
FastGaussianBlurOperation();
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
- void executePixel(float output[4], int x, int y, void *data) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
static void IIR_gauss(MemoryBuffer *src, float sigma, unsigned int channel, unsigned int xy);
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
void init_data() override;
- void deinitExecution() override;
- void initExecution() override;
+ void deinit_execution() override;
+ void init_execution() override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_started(MemoryBuffer *output,
@@ -61,35 +61,35 @@ enum {
class FastGaussianBlurValueOperation : public MultiThreadedOperation {
private:
- float m_sigma;
- MemoryBuffer *m_iirgaus;
- SocketReader *m_inputprogram;
+ float sigma_;
+ MemoryBuffer *iirgaus_;
+ SocketReader *inputprogram_;
/**
* -1: re-mix with darker
* 0: do nothing
* 1 re-mix with lighter */
- int m_overlay;
+ int overlay_;
public:
FastGaussianBlurValueOperation();
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
- void executePixel(float output[4], int x, int y, void *data) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
- void *initializeTileData(rcti *rect) override;
- void deinitExecution() override;
- void initExecution() override;
- void setSigma(float sigma)
+ void *initialize_tile_data(rcti *rect) override;
+ void deinit_execution() override;
+ void init_execution() override;
+ void set_sigma(float sigma)
{
- this->m_sigma = sigma;
+ sigma_ = sigma;
}
/* used for DOF blurring ZBuffer */
- void setOverlay(int overlay)
+ void set_overlay(int overlay)
{
- this->m_overlay = overlay;
+ overlay_ = overlay;
}
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
diff --git a/source/blender/compositor/operations/COM_FlipOperation.cc b/source/blender/compositor/operations/COM_FlipOperation.cc
index c88fcaa7da2..7ca12a504b7 100644
--- a/source/blender/compositor/operations/COM_FlipOperation.cc
+++ b/source/blender/compositor/operations/COM_FlipOperation.cc
@@ -22,57 +22,75 @@ namespace blender::compositor {
FlipOperation::FlipOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color, ResizeMode::None);
+ this->add_output_socket(DataType::Color);
this->set_canvas_input_index(0);
- this->m_inputOperation = nullptr;
- this->m_flipX = true;
- this->m_flipY = false;
+ input_operation_ = nullptr;
+ flip_x_ = true;
+ flip_y_ = false;
}
-void FlipOperation::initExecution()
+void FlipOperation::init_execution()
{
- this->m_inputOperation = this->getInputSocketReader(0);
+ input_operation_ = this->get_input_socket_reader(0);
}
-void FlipOperation::deinitExecution()
+void FlipOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
+ input_operation_ = nullptr;
}
-void FlipOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void FlipOperation::execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler)
{
- float nx = this->m_flipX ? ((int)this->getWidth() - 1) - x : x;
- float ny = this->m_flipY ? ((int)this->getHeight() - 1) - y : y;
+ float nx = flip_x_ ? ((int)this->get_width() - 1) - x : x;
+ float ny = flip_y_ ? ((int)this->get_height() - 1) - y : y;
- this->m_inputOperation->readSampled(output, nx, ny, sampler);
+ input_operation_->read_sampled(output, nx, ny, sampler);
}
-bool FlipOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool FlipOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti newInput;
+ rcti new_input;
- if (this->m_flipX) {
- const int w = (int)this->getWidth() - 1;
- newInput.xmax = (w - input->xmin) + 1;
- newInput.xmin = (w - input->xmax) - 1;
+ if (flip_x_) {
+ const int w = (int)this->get_width() - 1;
+ new_input.xmax = (w - input->xmin) + 1;
+ new_input.xmin = (w - input->xmax) - 1;
}
else {
- newInput.xmin = input->xmin;
- newInput.xmax = input->xmax;
+ new_input.xmin = input->xmin;
+ new_input.xmax = input->xmax;
}
- if (this->m_flipY) {
- const int h = (int)this->getHeight() - 1;
- newInput.ymax = (h - input->ymin) + 1;
- newInput.ymin = (h - input->ymax) - 1;
+ if (flip_y_) {
+ const int h = (int)this->get_height() - 1;
+ new_input.ymax = (h - input->ymin) + 1;
+ new_input.ymin = (h - input->ymax) - 1;
}
else {
- newInput.ymin = input->ymin;
- newInput.ymax = input->ymax;
+ new_input.ymin = input->ymin;
+ new_input.ymax = input->ymax;
}
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
+}
+
+void FlipOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
+{
+ NodeOperation::determine_canvas(preferred_area, r_area);
+ if (execution_model_ == eExecutionModel::FullFrame) {
+ rcti input_area = r_area;
+ if (flip_x_) {
+ const int width = BLI_rcti_size_x(&input_area) - 1;
+ r_area.xmax = (width - input_area.xmin) + 1;
+ r_area.xmin = (width - input_area.xmax) + 1;
+ }
+ if (flip_y_) {
+ const int height = BLI_rcti_size_y(&input_area) - 1;
+ r_area.ymax = (height - input_area.ymin) + 1;
+ r_area.ymin = (height - input_area.ymax) + 1;
+ }
+ }
}
void FlipOperation::get_area_of_interest(const int input_idx,
@@ -81,19 +99,19 @@ void FlipOperation::get_area_of_interest(const int input_idx,
{
BLI_assert(input_idx == 0);
UNUSED_VARS_NDEBUG(input_idx);
- if (this->m_flipX) {
- const int w = (int)this->getWidth() - 1;
+ if (flip_x_) {
+ const int w = (int)this->get_width() - 1;
r_input_area.xmax = (w - output_area.xmin) + 1;
- r_input_area.xmin = (w - output_area.xmax) - 1;
+ r_input_area.xmin = (w - output_area.xmax) + 1;
}
else {
r_input_area.xmin = output_area.xmin;
r_input_area.xmax = output_area.xmax;
}
- if (this->m_flipY) {
- const int h = (int)this->getHeight() - 1;
+ if (flip_y_) {
+ const int h = (int)this->get_height() - 1;
r_input_area.ymax = (h - output_area.ymin) + 1;
- r_input_area.ymin = (h - output_area.ymax) - 1;
+ r_input_area.ymin = (h - output_area.ymax) + 1;
}
else {
r_input_area.ymin = output_area.ymin;
@@ -106,10 +124,12 @@ void FlipOperation::update_memory_buffer_partial(MemoryBuffer *output,
Span<MemoryBuffer *> inputs)
{
const MemoryBuffer *input_img = inputs[0];
+ const int input_offset_x = input_img->get_rect().xmin;
+ const int input_offset_y = input_img->get_rect().ymin;
for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
- const int nx = this->m_flipX ? ((int)this->getWidth() - 1) - it.x : it.x;
- const int ny = this->m_flipY ? ((int)this->getHeight() - 1) - it.y : it.y;
- input_img->read_elem(nx, ny, it.out);
+ const int nx = flip_x_ ? ((int)this->get_width() - 1) - it.x : it.x;
+ const int ny = flip_y_ ? ((int)this->get_height() - 1) - it.y : it.y;
+ input_img->read_elem(input_offset_x + nx, input_offset_y + ny, it.out);
}
}
diff --git a/source/blender/compositor/operations/COM_FlipOperation.h b/source/blender/compositor/operations/COM_FlipOperation.h
index dba7f82c341..001fd652740 100644
--- a/source/blender/compositor/operations/COM_FlipOperation.h
+++ b/source/blender/compositor/operations/COM_FlipOperation.h
@@ -24,28 +24,29 @@ namespace blender::compositor {
class FlipOperation : public MultiThreadedOperation {
private:
- SocketReader *m_inputOperation;
- bool m_flipX;
- bool m_flipY;
+ SocketReader *input_operation_;
+ bool flip_x_;
+ bool flip_y_;
public:
FlipOperation();
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
void setFlipX(bool flipX)
{
- this->m_flipX = flipX;
+ flip_x_ = flipX;
}
void setFlipY(bool flipY)
{
- this->m_flipY = flipY;
+ flip_y_ = flipY;
}
+ void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_GammaCorrectOperation.cc b/source/blender/compositor/operations/COM_GammaCorrectOperation.cc
index 1bff3b965c6..57d2ebd1b84 100644
--- a/source/blender/compositor/operations/COM_GammaCorrectOperation.cc
+++ b/source/blender/compositor/operations/COM_GammaCorrectOperation.cc
@@ -17,45 +17,44 @@
*/
#include "COM_GammaCorrectOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
GammaCorrectOperation::GammaCorrectOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
- this->m_inputProgram = nullptr;
- flags.can_be_constant = true;
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ input_program_ = nullptr;
+ flags_.can_be_constant = true;
}
-void GammaCorrectOperation::initExecution()
+void GammaCorrectOperation::init_execution()
{
- this->m_inputProgram = this->getInputSocketReader(0);
+ input_program_ = this->get_input_socket_reader(0);
}
-void GammaCorrectOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void GammaCorrectOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor[4];
- this->m_inputProgram->readSampled(inputColor, x, y, sampler);
- if (inputColor[3] > 0.0f) {
- inputColor[0] /= inputColor[3];
- inputColor[1] /= inputColor[3];
- inputColor[2] /= inputColor[3];
+ float input_color[4];
+ input_program_->read_sampled(input_color, x, y, sampler);
+ if (input_color[3] > 0.0f) {
+ input_color[0] /= input_color[3];
+ input_color[1] /= input_color[3];
+ input_color[2] /= input_color[3];
}
/* check for negative to avoid nan's */
- output[0] = inputColor[0] > 0.0f ? inputColor[0] * inputColor[0] : 0.0f;
- output[1] = inputColor[1] > 0.0f ? inputColor[1] * inputColor[1] : 0.0f;
- output[2] = inputColor[2] > 0.0f ? inputColor[2] * inputColor[2] : 0.0f;
- output[3] = inputColor[3];
-
- if (inputColor[3] > 0.0f) {
- output[0] *= inputColor[3];
- output[1] *= inputColor[3];
- output[2] *= inputColor[3];
+ output[0] = input_color[0] > 0.0f ? input_color[0] * input_color[0] : 0.0f;
+ output[1] = input_color[1] > 0.0f ? input_color[1] * input_color[1] : 0.0f;
+ output[2] = input_color[2] > 0.0f ? input_color[2] * input_color[2] : 0.0f;
+ output[3] = input_color[3];
+
+ if (input_color[3] > 0.0f) {
+ output[0] *= input_color[3];
+ output[1] *= input_color[3];
+ output[2] *= input_color[3];
}
}
@@ -87,46 +86,46 @@ void GammaCorrectOperation::update_memory_buffer_partial(MemoryBuffer *output,
}
}
-void GammaCorrectOperation::deinitExecution()
+void GammaCorrectOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
+ input_program_ = nullptr;
}
GammaUncorrectOperation::GammaUncorrectOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
- this->m_inputProgram = nullptr;
- flags.can_be_constant = true;
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ input_program_ = nullptr;
+ flags_.can_be_constant = true;
}
-void GammaUncorrectOperation::initExecution()
+void GammaUncorrectOperation::init_execution()
{
- this->m_inputProgram = this->getInputSocketReader(0);
+ input_program_ = this->get_input_socket_reader(0);
}
-void GammaUncorrectOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void GammaUncorrectOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor[4];
- this->m_inputProgram->readSampled(inputColor, x, y, sampler);
+ float input_color[4];
+ input_program_->read_sampled(input_color, x, y, sampler);
- if (inputColor[3] > 0.0f) {
- inputColor[0] /= inputColor[3];
- inputColor[1] /= inputColor[3];
- inputColor[2] /= inputColor[3];
+ if (input_color[3] > 0.0f) {
+ input_color[0] /= input_color[3];
+ input_color[1] /= input_color[3];
+ input_color[2] /= input_color[3];
}
- output[0] = inputColor[0] > 0.0f ? sqrtf(inputColor[0]) : 0.0f;
- output[1] = inputColor[1] > 0.0f ? sqrtf(inputColor[1]) : 0.0f;
- output[2] = inputColor[2] > 0.0f ? sqrtf(inputColor[2]) : 0.0f;
- output[3] = inputColor[3];
+ output[0] = input_color[0] > 0.0f ? sqrtf(input_color[0]) : 0.0f;
+ output[1] = input_color[1] > 0.0f ? sqrtf(input_color[1]) : 0.0f;
+ output[2] = input_color[2] > 0.0f ? sqrtf(input_color[2]) : 0.0f;
+ output[3] = input_color[3];
- if (inputColor[3] > 0.0f) {
- output[0] *= inputColor[3];
- output[1] *= inputColor[3];
- output[2] *= inputColor[3];
+ if (input_color[3] > 0.0f) {
+ output[0] *= input_color[3];
+ output[1] *= input_color[3];
+ output[2] *= input_color[3];
}
}
@@ -157,9 +156,9 @@ void GammaUncorrectOperation::update_memory_buffer_partial(MemoryBuffer *output,
}
}
-void GammaUncorrectOperation::deinitExecution()
+void GammaUncorrectOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
+ input_program_ = nullptr;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_GammaCorrectOperation.h b/source/blender/compositor/operations/COM_GammaCorrectOperation.h
index 2a9fde70e87..e13d96184ad 100644
--- a/source/blender/compositor/operations/COM_GammaCorrectOperation.h
+++ b/source/blender/compositor/operations/COM_GammaCorrectOperation.h
@@ -25,9 +25,9 @@ namespace blender::compositor {
class GammaCorrectOperation : public MultiThreadedOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
+ SocketReader *input_program_;
public:
GammaCorrectOperation();
@@ -35,17 +35,17 @@ class GammaCorrectOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
@@ -55,9 +55,9 @@ class GammaCorrectOperation : public MultiThreadedOperation {
class GammaUncorrectOperation : public MultiThreadedOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
+ SocketReader *input_program_;
public:
GammaUncorrectOperation();
@@ -65,17 +65,17 @@ class GammaUncorrectOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_GammaOperation.cc b/source/blender/compositor/operations/COM_GammaOperation.cc
index 396d3942b06..3ea7f35f1b5 100644
--- a/source/blender/compositor/operations/COM_GammaOperation.cc
+++ b/source/blender/compositor/operations/COM_GammaOperation.cc
@@ -17,39 +17,38 @@
*/
#include "COM_GammaOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
GammaOperation::GammaOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
- this->m_inputProgram = nullptr;
- this->m_inputGammaProgram = nullptr;
- flags.can_be_constant = true;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
+ input_program_ = nullptr;
+ input_gamma_program_ = nullptr;
+ flags_.can_be_constant = true;
}
-void GammaOperation::initExecution()
+void GammaOperation::init_execution()
{
- this->m_inputProgram = this->getInputSocketReader(0);
- this->m_inputGammaProgram = this->getInputSocketReader(1);
+ input_program_ = this->get_input_socket_reader(0);
+ input_gamma_program_ = this->get_input_socket_reader(1);
}
-void GammaOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void GammaOperation::execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler)
{
- float inputValue[4];
- float inputGamma[4];
+ float input_value[4];
+ float input_gamma[4];
- this->m_inputProgram->readSampled(inputValue, x, y, sampler);
- this->m_inputGammaProgram->readSampled(inputGamma, x, y, sampler);
- const float gamma = inputGamma[0];
+ input_program_->read_sampled(input_value, x, y, sampler);
+ input_gamma_program_->read_sampled(input_gamma, x, y, sampler);
+ const float gamma = input_gamma[0];
/* check for negative to avoid nan's */
- output[0] = inputValue[0] > 0.0f ? powf(inputValue[0], gamma) : inputValue[0];
- output[1] = inputValue[1] > 0.0f ? powf(inputValue[1], gamma) : inputValue[1];
- output[2] = inputValue[2] > 0.0f ? powf(inputValue[2], gamma) : inputValue[2];
+ output[0] = input_value[0] > 0.0f ? powf(input_value[0], gamma) : input_value[0];
+ output[1] = input_value[1] > 0.0f ? powf(input_value[1], gamma) : input_value[1];
+ output[2] = input_value[2] > 0.0f ? powf(input_value[2], gamma) : input_value[2];
- output[3] = inputValue[3];
+ output[3] = input_value[3];
}
void GammaOperation::update_memory_buffer_row(PixelCursor &p)
@@ -66,10 +65,10 @@ void GammaOperation::update_memory_buffer_row(PixelCursor &p)
}
}
-void GammaOperation::deinitExecution()
+void GammaOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
- this->m_inputGammaProgram = nullptr;
+ input_program_ = nullptr;
+ input_gamma_program_ = nullptr;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_GammaOperation.h b/source/blender/compositor/operations/COM_GammaOperation.h
index 713d3d8484f..d8703a0a19a 100644
--- a/source/blender/compositor/operations/COM_GammaOperation.h
+++ b/source/blender/compositor/operations/COM_GammaOperation.h
@@ -25,10 +25,10 @@ namespace blender::compositor {
class GammaOperation : public MultiThreadedRowOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
- SocketReader *m_inputGammaProgram;
+ SocketReader *input_program_;
+ SocketReader *input_gamma_program_;
public:
GammaOperation();
@@ -36,17 +36,17 @@ class GammaOperation : public MultiThreadedRowOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
void update_memory_buffer_row(PixelCursor &p) override;
};
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc b/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc
index 9bdc652b466..cfd83102aaf 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc
+++ b/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc
@@ -23,9 +23,9 @@ namespace blender::compositor {
GaussianAlphaBlurBaseOperation::GaussianAlphaBlurBaseOperation(eDimension dim)
: BlurBaseOperation(DataType::Value)
{
- this->m_gausstab = nullptr;
- this->m_filtersize = 0;
- this->m_falloff = -1; /* Intentionally invalid, so we can detect uninitialized values. */
+ gausstab_ = nullptr;
+ filtersize_ = 0;
+ falloff_ = -1; /* Intentionally invalid, so we can detect uninitialized values. */
dimension_ = dim;
}
@@ -33,33 +33,33 @@ void GaussianAlphaBlurBaseOperation::init_data()
{
BlurBaseOperation::init_data();
if (execution_model_ == eExecutionModel::FullFrame) {
- rad_ = max_ff(m_size * this->get_blur_size(dimension_), 0.0f);
+ rad_ = max_ff(size_ * this->get_blur_size(dimension_), 0.0f);
rad_ = min_ff(rad_, MAX_GAUSSTAB_RADIUS);
- m_filtersize = min_ii(ceil(rad_), MAX_GAUSSTAB_RADIUS);
+ filtersize_ = min_ii(ceil(rad_), MAX_GAUSSTAB_RADIUS);
}
}
-void GaussianAlphaBlurBaseOperation::initExecution()
+void GaussianAlphaBlurBaseOperation::init_execution()
{
- BlurBaseOperation::initExecution();
+ BlurBaseOperation::init_execution();
if (execution_model_ == eExecutionModel::FullFrame) {
- m_gausstab = BlurBaseOperation::make_gausstab(rad_, m_filtersize);
- m_distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad_, m_filtersize, m_falloff);
+ gausstab_ = BlurBaseOperation::make_gausstab(rad_, filtersize_);
+ distbuf_inv_ = BlurBaseOperation::make_dist_fac_inverse(rad_, filtersize_, falloff_);
}
}
-void GaussianAlphaBlurBaseOperation::deinitExecution()
+void GaussianAlphaBlurBaseOperation::deinit_execution()
{
- BlurBaseOperation::deinitExecution();
+ BlurBaseOperation::deinit_execution();
- if (this->m_gausstab) {
- MEM_freeN(this->m_gausstab);
- this->m_gausstab = nullptr;
+ if (gausstab_) {
+ MEM_freeN(gausstab_);
+ gausstab_ = nullptr;
}
- if (this->m_distbuf_inv) {
- MEM_freeN(this->m_distbuf_inv);
- this->m_distbuf_inv = nullptr;
+ if (distbuf_inv_) {
+ MEM_freeN(distbuf_inv_);
+ distbuf_inv_ = nullptr;
}
}
@@ -75,21 +75,16 @@ void GaussianAlphaBlurBaseOperation::get_area_of_interest(const int input_idx,
r_input_area = output_area;
switch (dimension_) {
case eDimension::X:
- r_input_area.xmin = output_area.xmin - m_filtersize - 1;
- r_input_area.xmax = output_area.xmax + m_filtersize + 1;
+ r_input_area.xmin = output_area.xmin - filtersize_ - 1;
+ r_input_area.xmax = output_area.xmax + filtersize_ + 1;
break;
case eDimension::Y:
- r_input_area.ymin = output_area.ymin - m_filtersize - 1;
- r_input_area.ymax = output_area.ymax + m_filtersize + 1;
+ r_input_area.ymin = output_area.ymin - filtersize_ - 1;
+ r_input_area.ymax = output_area.ymax + filtersize_ + 1;
break;
}
}
-BLI_INLINE float finv_test(const float f, const bool test)
-{
- return (LIKELY(test == false)) ? f : 1.0f - f;
-}
-
void GaussianAlphaBlurBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
@@ -119,8 +114,8 @@ void GaussianAlphaBlurBaseOperation::update_memory_buffer_partial(MemoryBuffer *
for (; !it.is_end(); ++it) {
const int coord = get_current_coord();
- const int coord_min = max_ii(coord - m_filtersize, min_input_coord);
- const int coord_max = min_ii(coord + m_filtersize + 1, max_input_coord);
+ const int coord_min = max_ii(coord - filtersize_, min_input_coord);
+ const int coord_max = min_ii(coord + filtersize_ + 1, max_input_coord);
/* *** This is the main part which is different to #GaussianBlurBaseOperation. *** */
/* Gauss. */
@@ -128,27 +123,27 @@ void GaussianAlphaBlurBaseOperation::update_memory_buffer_partial(MemoryBuffer *
float multiplier_accum = 0.0f;
/* Dilate. */
- const bool do_invert = m_do_subtract;
+ const bool do_invert = do_subtract_;
/* Init with the current color to avoid unneeded lookups. */
float value_max = finv_test(*it.in(0), do_invert);
float distfacinv_max = 1.0f; /* 0 to 1 */
- const int step = QualityStepHelper::getStep();
+ const int step = QualityStepHelper::get_step();
const float *in = it.in(0) + ((intptr_t)coord_min - coord) * elem_stride;
const int in_stride = elem_stride * step;
- int index = (coord_min - coord) + m_filtersize;
+ int index = (coord_min - coord) + filtersize_;
const int index_end = index + (coord_max - coord_min);
for (; index < index_end; in += in_stride, index += step) {
float value = finv_test(*in, do_invert);
/* Gauss. */
- float multiplier = m_gausstab[index];
+ float multiplier = gausstab_[index];
alpha_accum += value * multiplier;
multiplier_accum += multiplier;
/* Dilate - find most extreme color. */
if (value > value_max) {
- multiplier = m_distbuf_inv[index];
+ multiplier = distbuf_inv_[index];
value *= multiplier;
if (value > value_max) {
value_max = value;
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.h b/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.h
index d7ca975ca0a..2bab6912d34 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.h
@@ -24,11 +24,11 @@ namespace blender::compositor {
class GaussianAlphaBlurBaseOperation : public BlurBaseOperation {
protected:
- float *m_gausstab;
- float *m_distbuf_inv;
- int m_falloff; /* Falloff for #distbuf_inv. */
- bool m_do_subtract;
- int m_filtersize;
+ float *gausstab_;
+ float *distbuf_inv_;
+ int falloff_; /* Falloff for #distbuf_inv. */
+ bool do_subtract_;
+ int filtersize_;
float rad_;
eDimension dimension_;
@@ -36,12 +36,10 @@ class GaussianAlphaBlurBaseOperation : public BlurBaseOperation {
GaussianAlphaBlurBaseOperation(eDimension dim);
virtual void init_data() override;
- virtual void initExecution() override;
- virtual void deinitExecution() override;
+ virtual void init_execution() override;
+ virtual void deinit_execution() override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) final;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) final;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) final;
@@ -49,13 +47,18 @@ class GaussianAlphaBlurBaseOperation : public BlurBaseOperation {
/**
* Set subtract for Dilate/Erode functionality
*/
- void setSubtract(bool subtract)
+ void set_subtract(bool subtract)
{
- this->m_do_subtract = subtract;
+ do_subtract_ = subtract;
}
- void setFalloff(int falloff)
+ void set_falloff(int falloff)
{
- this->m_falloff = falloff;
+ falloff_ = falloff;
+ }
+
+ BLI_INLINE float finv_test(const float f, const bool test)
+ {
+ return (LIKELY(test == false)) ? f : 1.0f - f;
}
};
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc
index 6710ed3cf5b..3836cf45371 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc
@@ -17,10 +17,6 @@
*/
#include "COM_GaussianAlphaXBlurOperation.h"
-#include "BLI_math.h"
-#include "MEM_guardedalloc.h"
-
-#include "RE_pipeline.h"
namespace blender::compositor {
@@ -29,74 +25,69 @@ GaussianAlphaXBlurOperation::GaussianAlphaXBlurOperation()
{
}
-void *GaussianAlphaXBlurOperation::initializeTileData(rcti * /*rect*/)
+void *GaussianAlphaXBlurOperation::initialize_tile_data(rcti * /*rect*/)
{
- lockMutex();
- if (!this->m_sizeavailable) {
- updateGauss();
+ lock_mutex();
+ if (!sizeavailable_) {
+ update_gauss();
}
- void *buffer = getInputOperation(0)->initializeTileData(nullptr);
- unlockMutex();
+ void *buffer = get_input_operation(0)->initialize_tile_data(nullptr);
+ unlock_mutex();
return buffer;
}
-void GaussianAlphaXBlurOperation::initExecution()
+void GaussianAlphaXBlurOperation::init_execution()
{
- GaussianAlphaBlurBaseOperation::initExecution();
+ GaussianAlphaBlurBaseOperation::init_execution();
- initMutex();
+ init_mutex();
- if (this->m_sizeavailable && execution_model_ == eExecutionModel::Tiled) {
- float rad = max_ff(m_size * m_data.sizex, 0.0f);
- m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
+ if (sizeavailable_ && execution_model_ == eExecutionModel::Tiled) {
+ float rad = max_ff(size_ * data_.sizex, 0.0f);
+ filtersize_ = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
- m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
- m_distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad, m_filtersize, m_falloff);
+ gausstab_ = BlurBaseOperation::make_gausstab(rad, filtersize_);
+ distbuf_inv_ = BlurBaseOperation::make_dist_fac_inverse(rad, filtersize_, falloff_);
}
}
-void GaussianAlphaXBlurOperation::updateGauss()
+void GaussianAlphaXBlurOperation::update_gauss()
{
- if (this->m_gausstab == nullptr) {
- updateSize();
- float rad = max_ff(m_size * m_data.sizex, 0.0f);
- m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
+ if (gausstab_ == nullptr) {
+ update_size();
+ float rad = max_ff(size_ * data_.sizex, 0.0f);
+ filtersize_ = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
- m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
+ gausstab_ = BlurBaseOperation::make_gausstab(rad, filtersize_);
}
- if (this->m_distbuf_inv == nullptr) {
- updateSize();
- float rad = max_ff(m_size * m_data.sizex, 0.0f);
+ if (distbuf_inv_ == nullptr) {
+ update_size();
+ float rad = max_ff(size_ * data_.sizex, 0.0f);
rad = min_ff(rad, MAX_GAUSSTAB_RADIUS);
- m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
+ filtersize_ = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
- m_distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad, m_filtersize, m_falloff);
+ distbuf_inv_ = BlurBaseOperation::make_dist_fac_inverse(rad, filtersize_, falloff_);
}
}
-BLI_INLINE float finv_test(const float f, const bool test)
-{
- return (LIKELY(test == false)) ? f : 1.0f - f;
-}
-
-void GaussianAlphaXBlurOperation::executePixel(float output[4], int x, int y, void *data)
+void GaussianAlphaXBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
{
- const bool do_invert = this->m_do_subtract;
- MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
- float *buffer = inputBuffer->getBuffer();
- int bufferwidth = inputBuffer->getWidth();
- const rcti &input_rect = inputBuffer->get_rect();
+ const bool do_invert = do_subtract_;
+ MemoryBuffer *input_buffer = (MemoryBuffer *)data;
+ float *buffer = input_buffer->get_buffer();
+ int bufferwidth = input_buffer->get_width();
+ const rcti &input_rect = input_buffer->get_rect();
int bufferstartx = input_rect.xmin;
int bufferstarty = input_rect.ymin;
- const rcti &rect = inputBuffer->get_rect();
- int xmin = max_ii(x - m_filtersize, rect.xmin);
- int xmax = min_ii(x + m_filtersize + 1, rect.xmax);
+ const rcti &rect = input_buffer->get_rect();
+ int xmin = max_ii(x - filtersize_, rect.xmin);
+ int xmax = min_ii(x + filtersize_ + 1, rect.xmax);
int ymin = max_ii(y, rect.ymin);
/* *** this is the main part which is different to 'GaussianXBlurOperation' *** */
- int step = getStep();
+ int step = get_step();
int bufferindex = ((xmin - bufferstartx)) + ((ymin - bufferstarty) * bufferwidth);
/* gauss */
@@ -110,20 +101,20 @@ void GaussianAlphaXBlurOperation::executePixel(float output[4], int x, int y, vo
float distfacinv_max = 1.0f; /* 0 to 1 */
for (int nx = xmin; nx < xmax; nx += step) {
- const int index = (nx - x) + this->m_filtersize;
+ const int index = (nx - x) + filtersize_;
float value = finv_test(buffer[bufferindex], do_invert);
float multiplier;
/* gauss */
{
- multiplier = this->m_gausstab[index];
+ multiplier = gausstab_[index];
alpha_accum += value * multiplier;
multiplier_accum += multiplier;
}
/* dilate - find most extreme color */
if (value > value_max) {
- multiplier = this->m_distbuf_inv[index];
+ multiplier = distbuf_inv_[index];
value *= multiplier;
if (value > value_max) {
value_max = value;
@@ -139,54 +130,54 @@ void GaussianAlphaXBlurOperation::executePixel(float output[4], int x, int y, vo
output[0] = finv_test(value_final, do_invert);
}
-void GaussianAlphaXBlurOperation::deinitExecution()
+void GaussianAlphaXBlurOperation::deinit_execution()
{
- GaussianAlphaBlurBaseOperation::deinitExecution();
+ GaussianAlphaBlurBaseOperation::deinit_execution();
- if (this->m_gausstab) {
- MEM_freeN(this->m_gausstab);
- this->m_gausstab = nullptr;
+ if (gausstab_) {
+ MEM_freeN(gausstab_);
+ gausstab_ = nullptr;
}
- if (this->m_distbuf_inv) {
- MEM_freeN(this->m_distbuf_inv);
- this->m_distbuf_inv = nullptr;
+ if (distbuf_inv_) {
+ MEM_freeN(distbuf_inv_);
+ distbuf_inv_ = nullptr;
}
- deinitMutex();
+ deinit_mutex();
}
-bool GaussianAlphaXBlurOperation::determineDependingAreaOfInterest(
- rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool GaussianAlphaXBlurOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
+ rcti new_input;
#if 0 /* until we add size input */
- rcti sizeInput;
- sizeInput.xmin = 0;
- sizeInput.ymin = 0;
- sizeInput.xmax = 5;
- sizeInput.ymax = 5;
-
- NodeOperation *operation = this->getInputOperation(1);
- if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
+ rcti size_input;
+ size_input.xmin = 0;
+ size_input.ymin = 0;
+ size_input.xmax = 5;
+ size_input.ymax = 5;
+
+ NodeOperation *operation = this->get_input_operation(1);
+ if (operation->determine_depending_area_of_interest(&size_input, read_operation, output)) {
return true;
}
else
#endif
{
- if (this->m_sizeavailable && this->m_gausstab != nullptr) {
- newInput.xmax = input->xmax + this->m_filtersize + 1;
- newInput.xmin = input->xmin - this->m_filtersize - 1;
- newInput.ymax = input->ymax;
- newInput.ymin = input->ymin;
+ if (sizeavailable_ && gausstab_ != nullptr) {
+ new_input.xmax = input->xmax + filtersize_ + 1;
+ new_input.xmin = input->xmin - filtersize_ - 1;
+ new_input.ymax = input->ymax;
+ new_input.ymin = input->ymin;
}
else {
- newInput.xmax = this->getWidth();
- newInput.xmin = 0;
- newInput.ymax = this->getHeight();
- newInput.ymin = 0;
+ new_input.xmax = this->get_width();
+ new_input.xmin = 0;
+ new_input.ymax = this->get_height();
+ new_input.ymin = 0;
}
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
}
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.h b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.h
index 2a44c639665..31b4a582c4b 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.h
@@ -25,7 +25,7 @@ namespace blender::compositor {
/* TODO(manzanilla): everything to be removed with tiled implementation except the constructor. */
class GaussianAlphaXBlurOperation : public GaussianAlphaBlurBaseOperation {
private:
- void updateGauss();
+ void update_gauss();
public:
GaussianAlphaXBlurOperation();
@@ -33,22 +33,22 @@ class GaussianAlphaXBlurOperation : public GaussianAlphaBlurBaseOperation {
/**
* \brief The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* \brief initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* \brief Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void *initializeTileData(rcti *rect) override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ void *initialize_tile_data(rcti *rect) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc
index 09aeddb6573..d71d90e7fa4 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc
@@ -17,10 +17,6 @@
*/
#include "COM_GaussianAlphaYBlurOperation.h"
-#include "BLI_math.h"
-#include "MEM_guardedalloc.h"
-
-#include "RE_pipeline.h"
namespace blender::compositor {
@@ -29,75 +25,70 @@ GaussianAlphaYBlurOperation::GaussianAlphaYBlurOperation()
{
}
-void *GaussianAlphaYBlurOperation::initializeTileData(rcti * /*rect*/)
+void *GaussianAlphaYBlurOperation::initialize_tile_data(rcti * /*rect*/)
{
- lockMutex();
- if (!this->m_sizeavailable) {
- updateGauss();
+ lock_mutex();
+ if (!sizeavailable_) {
+ update_gauss();
}
- void *buffer = getInputOperation(0)->initializeTileData(nullptr);
- unlockMutex();
+ void *buffer = get_input_operation(0)->initialize_tile_data(nullptr);
+ unlock_mutex();
return buffer;
}
/* TODO(manzanilla): to be removed with tiled implementation. */
-void GaussianAlphaYBlurOperation::initExecution()
+void GaussianAlphaYBlurOperation::init_execution()
{
- GaussianAlphaBlurBaseOperation::initExecution();
+ GaussianAlphaBlurBaseOperation::init_execution();
- initMutex();
+ init_mutex();
- if (this->m_sizeavailable && execution_model_ == eExecutionModel::Tiled) {
- float rad = max_ff(m_size * m_data.sizey, 0.0f);
- m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
+ if (sizeavailable_ && execution_model_ == eExecutionModel::Tiled) {
+ float rad = max_ff(size_ * data_.sizey, 0.0f);
+ filtersize_ = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
- m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
- m_distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad, m_filtersize, m_falloff);
+ gausstab_ = BlurBaseOperation::make_gausstab(rad, filtersize_);
+ distbuf_inv_ = BlurBaseOperation::make_dist_fac_inverse(rad, filtersize_, falloff_);
}
}
/* TODO(manzanilla): to be removed with tiled implementation. */
-void GaussianAlphaYBlurOperation::updateGauss()
+void GaussianAlphaYBlurOperation::update_gauss()
{
- if (this->m_gausstab == nullptr) {
- updateSize();
- float rad = max_ff(m_size * m_data.sizey, 0.0f);
+ if (gausstab_ == nullptr) {
+ update_size();
+ float rad = max_ff(size_ * data_.sizey, 0.0f);
rad = min_ff(rad, MAX_GAUSSTAB_RADIUS);
- m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
+ filtersize_ = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
- m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
+ gausstab_ = BlurBaseOperation::make_gausstab(rad, filtersize_);
}
- if (this->m_distbuf_inv == nullptr) {
- updateSize();
- float rad = max_ff(m_size * m_data.sizey, 0.0f);
- m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
+ if (distbuf_inv_ == nullptr) {
+ update_size();
+ float rad = max_ff(size_ * data_.sizey, 0.0f);
+ filtersize_ = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
- m_distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad, m_filtersize, m_falloff);
+ distbuf_inv_ = BlurBaseOperation::make_dist_fac_inverse(rad, filtersize_, falloff_);
}
}
-BLI_INLINE float finv_test(const float f, const bool test)
-{
- return (LIKELY(test == false)) ? f : 1.0f - f;
-}
-
-void GaussianAlphaYBlurOperation::executePixel(float output[4], int x, int y, void *data)
+void GaussianAlphaYBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
{
- const bool do_invert = this->m_do_subtract;
- MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
- const rcti &input_rect = inputBuffer->get_rect();
- float *buffer = inputBuffer->getBuffer();
- int bufferwidth = inputBuffer->getWidth();
+ const bool do_invert = do_subtract_;
+ MemoryBuffer *input_buffer = (MemoryBuffer *)data;
+ const rcti &input_rect = input_buffer->get_rect();
+ float *buffer = input_buffer->get_buffer();
+ int bufferwidth = input_buffer->get_width();
int bufferstartx = input_rect.xmin;
int bufferstarty = input_rect.ymin;
int xmin = max_ii(x, input_rect.xmin);
- int ymin = max_ii(y - m_filtersize, input_rect.ymin);
- int ymax = min_ii(y + m_filtersize + 1, input_rect.ymax);
+ int ymin = max_ii(y - filtersize_, input_rect.ymin);
+ int ymax = min_ii(y + filtersize_ + 1, input_rect.ymax);
/* *** this is the main part which is different to 'GaussianYBlurOperation' *** */
- int step = getStep();
+ int step = get_step();
/* gauss */
float alpha_accum = 0.0f;
@@ -112,20 +103,20 @@ void GaussianAlphaYBlurOperation::executePixel(float output[4], int x, int y, vo
for (int ny = ymin; ny < ymax; ny += step) {
int bufferindex = ((xmin - bufferstartx)) + ((ny - bufferstarty) * bufferwidth);
- const int index = (ny - y) + this->m_filtersize;
+ const int index = (ny - y) + filtersize_;
float value = finv_test(buffer[bufferindex], do_invert);
float multiplier;
/* gauss */
{
- multiplier = this->m_gausstab[index];
+ multiplier = gausstab_[index];
alpha_accum += value * multiplier;
multiplier_accum += multiplier;
}
/* dilate - find most extreme color */
if (value > value_max) {
- multiplier = this->m_distbuf_inv[index];
+ multiplier = distbuf_inv_[index];
value *= multiplier;
if (value > value_max) {
value_max = value;
@@ -140,54 +131,54 @@ void GaussianAlphaYBlurOperation::executePixel(float output[4], int x, int y, vo
output[0] = finv_test(value_final, do_invert);
}
-void GaussianAlphaYBlurOperation::deinitExecution()
+void GaussianAlphaYBlurOperation::deinit_execution()
{
- GaussianAlphaBlurBaseOperation::deinitExecution();
+ GaussianAlphaBlurBaseOperation::deinit_execution();
- if (this->m_gausstab) {
- MEM_freeN(this->m_gausstab);
- this->m_gausstab = nullptr;
+ if (gausstab_) {
+ MEM_freeN(gausstab_);
+ gausstab_ = nullptr;
}
- if (this->m_distbuf_inv) {
- MEM_freeN(this->m_distbuf_inv);
- this->m_distbuf_inv = nullptr;
+ if (distbuf_inv_) {
+ MEM_freeN(distbuf_inv_);
+ distbuf_inv_ = nullptr;
}
- deinitMutex();
+ deinit_mutex();
}
-bool GaussianAlphaYBlurOperation::determineDependingAreaOfInterest(
- rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool GaussianAlphaYBlurOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
+ rcti new_input;
#if 0 /* until we add size input */
- rcti sizeInput;
- sizeInput.xmin = 0;
- sizeInput.ymin = 0;
- sizeInput.xmax = 5;
- sizeInput.ymax = 5;
-
- NodeOperation *operation = this->getInputOperation(1);
- if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
+ rcti size_input;
+ size_input.xmin = 0;
+ size_input.ymin = 0;
+ size_input.xmax = 5;
+ size_input.ymax = 5;
+
+ NodeOperation *operation = this->get_input_operation(1);
+ if (operation->determine_depending_area_of_interest(&size_input, read_operation, output)) {
return true;
}
else
#endif
{
- if (this->m_sizeavailable && this->m_gausstab != nullptr) {
- newInput.xmax = input->xmax;
- newInput.xmin = input->xmin;
- newInput.ymax = input->ymax + this->m_filtersize + 1;
- newInput.ymin = input->ymin - this->m_filtersize - 1;
+ if (sizeavailable_ && gausstab_ != nullptr) {
+ new_input.xmax = input->xmax;
+ new_input.xmin = input->xmin;
+ new_input.ymax = input->ymax + filtersize_ + 1;
+ new_input.ymin = input->ymin - filtersize_ - 1;
}
else {
- newInput.xmax = this->getWidth();
- newInput.xmin = 0;
- newInput.ymax = this->getHeight();
- newInput.ymin = 0;
+ new_input.xmax = this->get_width();
+ new_input.xmin = 0;
+ new_input.ymax = this->get_height();
+ new_input.ymin = 0;
}
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
}
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.h b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.h
index ef01f7e0f92..28dc289c445 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.h
@@ -25,7 +25,7 @@ namespace blender::compositor {
/* TODO(manzanilla): everything to be removed with tiled implementation except the constructor. */
class GaussianAlphaYBlurOperation : public GaussianAlphaBlurBaseOperation {
private:
- void updateGauss();
+ void update_gauss();
public:
GaussianAlphaYBlurOperation();
@@ -33,22 +33,22 @@ class GaussianAlphaYBlurOperation : public GaussianAlphaBlurBaseOperation {
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* \brief initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void *initializeTileData(rcti *rect) override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ void *initialize_tile_data(rcti *rect) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.cc b/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.cc
index 959f599fab4..9f4ee376fbf 100644
--- a/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.cc
+++ b/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.cc
@@ -23,11 +23,11 @@ namespace blender::compositor {
GaussianBlurBaseOperation::GaussianBlurBaseOperation(eDimension dim)
: BlurBaseOperation(DataType::Color)
{
- m_gausstab = nullptr;
+ gausstab_ = nullptr;
#ifdef BLI_HAVE_SSE2
- m_gausstab_sse = nullptr;
+ gausstab_sse_ = nullptr;
#endif
- m_filtersize = 0;
+ filtersize_ = 0;
rad_ = 0.0f;
dimension_ = dim;
}
@@ -36,35 +36,35 @@ void GaussianBlurBaseOperation::init_data()
{
BlurBaseOperation::init_data();
if (execution_model_ == eExecutionModel::FullFrame) {
- rad_ = max_ff(m_size * this->get_blur_size(dimension_), 0.0f);
+ rad_ = max_ff(size_ * this->get_blur_size(dimension_), 0.0f);
rad_ = min_ff(rad_, MAX_GAUSSTAB_RADIUS);
- m_filtersize = min_ii(ceil(rad_), MAX_GAUSSTAB_RADIUS);
+ filtersize_ = min_ii(ceil(rad_), MAX_GAUSSTAB_RADIUS);
}
}
-void GaussianBlurBaseOperation::initExecution()
+void GaussianBlurBaseOperation::init_execution()
{
- BlurBaseOperation::initExecution();
+ BlurBaseOperation::init_execution();
if (execution_model_ == eExecutionModel::FullFrame) {
- m_gausstab = BlurBaseOperation::make_gausstab(rad_, m_filtersize);
+ gausstab_ = BlurBaseOperation::make_gausstab(rad_, filtersize_);
#ifdef BLI_HAVE_SSE2
- m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(m_gausstab, m_filtersize);
+ gausstab_sse_ = BlurBaseOperation::convert_gausstab_sse(gausstab_, filtersize_);
#endif
}
}
-void GaussianBlurBaseOperation::deinitExecution()
+void GaussianBlurBaseOperation::deinit_execution()
{
- BlurBaseOperation::deinitExecution();
+ BlurBaseOperation::deinit_execution();
- if (m_gausstab) {
- MEM_freeN(m_gausstab);
- m_gausstab = nullptr;
+ if (gausstab_) {
+ MEM_freeN(gausstab_);
+ gausstab_ = nullptr;
}
#ifdef BLI_HAVE_SSE2
- if (m_gausstab_sse) {
- MEM_freeN(m_gausstab_sse);
- m_gausstab_sse = nullptr;
+ if (gausstab_sse_) {
+ MEM_freeN(gausstab_sse_);
+ gausstab_sse_ = nullptr;
}
#endif
}
@@ -81,12 +81,12 @@ void GaussianBlurBaseOperation::get_area_of_interest(const int input_idx,
r_input_area = output_area;
switch (dimension_) {
case eDimension::X:
- r_input_area.xmin = output_area.xmin - m_filtersize - 1;
- r_input_area.xmax = output_area.xmax + m_filtersize + 1;
+ r_input_area.xmin = output_area.xmin - filtersize_ - 1;
+ r_input_area.xmax = output_area.xmax + filtersize_ + 1;
break;
case eDimension::Y:
- r_input_area.ymin = output_area.ymin - m_filtersize - 1;
- r_input_area.ymax = output_area.ymax + m_filtersize + 1;
+ r_input_area.ymin = output_area.ymin - filtersize_ - 1;
+ r_input_area.ymax = output_area.ymax + filtersize_ + 1;
break;
}
}
@@ -120,29 +120,29 @@ void GaussianBlurBaseOperation::update_memory_buffer_partial(MemoryBuffer *outpu
for (; !it.is_end(); ++it) {
const int coord = get_current_coord();
- const int coord_min = max_ii(coord - m_filtersize, min_input_coord);
- const int coord_max = min_ii(coord + m_filtersize + 1, max_input_coord);
+ const int coord_min = max_ii(coord - filtersize_, min_input_coord);
+ const int coord_max = min_ii(coord + filtersize_ + 1, max_input_coord);
float ATTR_ALIGN(16) color_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float multiplier_accum = 0.0f;
- const int step = QualityStepHelper::getStep();
+ const int step = QualityStepHelper::get_step();
const float *in = it.in(0) + ((intptr_t)coord_min - coord) * elem_stride;
const int in_stride = elem_stride * step;
- int gauss_idx = (coord_min - coord) + m_filtersize;
+ int gauss_idx = (coord_min - coord) + filtersize_;
const int gauss_end = gauss_idx + (coord_max - coord_min);
#ifdef BLI_HAVE_SSE2
__m128 accum_r = _mm_load_ps(color_accum);
for (; gauss_idx < gauss_end; in += in_stride, gauss_idx += step) {
__m128 reg_a = _mm_load_ps(in);
- reg_a = _mm_mul_ps(reg_a, m_gausstab_sse[gauss_idx]);
+ reg_a = _mm_mul_ps(reg_a, gausstab_sse_[gauss_idx]);
accum_r = _mm_add_ps(accum_r, reg_a);
- multiplier_accum += m_gausstab[gauss_idx];
+ multiplier_accum += gausstab_[gauss_idx];
}
_mm_store_ps(color_accum, accum_r);
#else
for (; gauss_idx < gauss_end; in += in_stride, gauss_idx += step) {
- const float multiplier = m_gausstab[gauss_idx];
+ const float multiplier = gausstab_[gauss_idx];
madd_v4_v4fl(color_accum, in, multiplier);
multiplier_accum += multiplier;
}
diff --git a/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.h b/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.h
index c0b27078a24..55099c2d9be 100644
--- a/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.h
@@ -24,11 +24,11 @@ namespace blender::compositor {
class GaussianBlurBaseOperation : public BlurBaseOperation {
protected:
- float *m_gausstab;
+ float *gausstab_;
#ifdef BLI_HAVE_SSE2
- __m128 *m_gausstab_sse;
+ __m128 *gausstab_sse_;
#endif
- int m_filtersize;
+ int filtersize_;
float rad_;
eDimension dimension_;
@@ -36,12 +36,10 @@ class GaussianBlurBaseOperation : public BlurBaseOperation {
GaussianBlurBaseOperation(eDimension dim);
virtual void init_data() override;
- virtual void initExecution() override;
- virtual void deinitExecution() override;
+ virtual void init_execution() override;
+ virtual void deinit_execution() override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
virtual void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc
index aafc269abac..db5f9c7c35d 100644
--- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc
@@ -17,8 +17,6 @@
*/
#include "COM_GaussianBokehBlurOperation.h"
-#include "BLI_math.h"
-#include "MEM_guardedalloc.h"
#include "RE_pipeline.h"
@@ -26,57 +24,57 @@ namespace blender::compositor {
GaussianBokehBlurOperation::GaussianBokehBlurOperation() : BlurBaseOperation(DataType::Color)
{
- this->m_gausstab = nullptr;
+ gausstab_ = nullptr;
}
-void *GaussianBokehBlurOperation::initializeTileData(rcti * /*rect*/)
+void *GaussianBokehBlurOperation::initialize_tile_data(rcti * /*rect*/)
{
- lockMutex();
- if (!this->m_sizeavailable) {
- updateGauss();
+ lock_mutex();
+ if (!sizeavailable_) {
+ update_gauss();
}
- void *buffer = getInputOperation(0)->initializeTileData(nullptr);
- unlockMutex();
+ void *buffer = get_input_operation(0)->initialize_tile_data(nullptr);
+ unlock_mutex();
return buffer;
}
void GaussianBokehBlurOperation::init_data()
{
BlurBaseOperation::init_data();
- const float width = this->getWidth();
- const float height = this->getHeight();
+ const float width = this->get_width();
+ const float height = this->get_height();
- if (!this->m_sizeavailable) {
- updateSize();
+ if (!sizeavailable_) {
+ update_size();
}
- radxf_ = this->m_size * (float)this->m_data.sizex;
+ radxf_ = size_ * (float)data_.sizex;
CLAMP(radxf_, 0.0f, width / 2.0f);
/* Vertical. */
- radyf_ = this->m_size * (float)this->m_data.sizey;
+ radyf_ = size_ * (float)data_.sizey;
CLAMP(radyf_, 0.0f, height / 2.0f);
- this->m_radx = ceil(radxf_);
- this->m_rady = ceil(radyf_);
+ radx_ = ceil(radxf_);
+ rady_ = ceil(radyf_);
}
-void GaussianBokehBlurOperation::initExecution()
+void GaussianBokehBlurOperation::init_execution()
{
- BlurBaseOperation::initExecution();
+ BlurBaseOperation::init_execution();
- initMutex();
+ init_mutex();
- if (this->m_sizeavailable) {
- updateGauss();
+ if (sizeavailable_) {
+ update_gauss();
}
}
-void GaussianBokehBlurOperation::updateGauss()
+void GaussianBokehBlurOperation::update_gauss()
{
- if (this->m_gausstab == nullptr) {
- int ddwidth = 2 * this->m_radx + 1;
- int ddheight = 2 * this->m_rady + 1;
+ if (gausstab_ == nullptr) {
+ int ddwidth = 2 * radx_ + 1;
+ int ddheight = 2 * rady_ + 1;
int n = ddwidth * ddheight;
/* create a full filter image */
float *ddgauss = (float *)MEM_mallocN(sizeof(float) * n, __func__);
@@ -84,12 +82,12 @@ void GaussianBokehBlurOperation::updateGauss()
float sum = 0.0f;
float facx = (radxf_ > 0.0f ? 1.0f / radxf_ : 0.0f);
float facy = (radyf_ > 0.0f ? 1.0f / radyf_ : 0.0f);
- for (int j = -this->m_rady; j <= this->m_rady; j++) {
- for (int i = -this->m_radx; i <= this->m_radx; i++, dgauss++) {
+ for (int j = -rady_; j <= rady_; j++) {
+ for (int i = -radx_; i <= radx_; i++, dgauss++) {
float fj = (float)j * facy;
float fi = (float)i * facx;
float dist = sqrt(fj * fj + fi * fi);
- *dgauss = RE_filter_value(this->m_data.filtertype, dist);
+ *dgauss = RE_filter_value(data_.filtertype, dist);
sum += *dgauss;
}
@@ -103,96 +101,97 @@ void GaussianBokehBlurOperation::updateGauss()
}
}
else {
- int center = m_rady * ddwidth + m_radx;
+ int center = rady_ * ddwidth + radx_;
ddgauss[center] = 1.0f;
}
- this->m_gausstab = ddgauss;
+ gausstab_ = ddgauss;
}
}
-void GaussianBokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
+void GaussianBokehBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
{
- float tempColor[4];
- tempColor[0] = 0;
- tempColor[1] = 0;
- tempColor[2] = 0;
- tempColor[3] = 0;
+ float temp_color[4];
+ temp_color[0] = 0;
+ temp_color[1] = 0;
+ temp_color[2] = 0;
+ temp_color[3] = 0;
float multiplier_accum = 0;
- MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
- float *buffer = inputBuffer->getBuffer();
- int bufferwidth = inputBuffer->getWidth();
- const rcti &input_rect = inputBuffer->get_rect();
+ MemoryBuffer *input_buffer = (MemoryBuffer *)data;
+ float *buffer = input_buffer->get_buffer();
+ int bufferwidth = input_buffer->get_width();
+ const rcti &input_rect = input_buffer->get_rect();
int bufferstartx = input_rect.xmin;
int bufferstarty = input_rect.ymin;
- int ymin = max_ii(y - this->m_rady, input_rect.ymin);
- int ymax = min_ii(y + this->m_rady + 1, input_rect.ymax);
- int xmin = max_ii(x - this->m_radx, input_rect.xmin);
- int xmax = min_ii(x + this->m_radx + 1, input_rect.xmax);
+ int ymin = max_ii(y - rady_, input_rect.ymin);
+ int ymax = min_ii(y + rady_ + 1, input_rect.ymax);
+ int xmin = max_ii(x - radx_, input_rect.xmin);
+ int xmax = min_ii(x + radx_ + 1, input_rect.xmax);
int index;
- int step = QualityStepHelper::getStep();
- int offsetadd = QualityStepHelper::getOffsetAdd();
- const int addConst = (xmin - x + this->m_radx);
- const int mulConst = (this->m_radx * 2 + 1);
+ int step = QualityStepHelper::get_step();
+ int offsetadd = QualityStepHelper::get_offset_add();
+ const int add_const = (xmin - x + radx_);
+ const int mul_const = (radx_ * 2 + 1);
for (int ny = ymin; ny < ymax; ny += step) {
- index = ((ny - y) + this->m_rady) * mulConst + addConst;
+ index = ((ny - y) + rady_) * mul_const + add_const;
int bufferindex = ((xmin - bufferstartx) * 4) + ((ny - bufferstarty) * 4 * bufferwidth);
for (int nx = xmin; nx < xmax; nx += step) {
- const float multiplier = this->m_gausstab[index];
- madd_v4_v4fl(tempColor, &buffer[bufferindex], multiplier);
+ const float multiplier = gausstab_[index];
+ madd_v4_v4fl(temp_color, &buffer[bufferindex], multiplier);
multiplier_accum += multiplier;
index += step;
bufferindex += offsetadd;
}
}
- mul_v4_v4fl(output, tempColor, 1.0f / multiplier_accum);
+ mul_v4_v4fl(output, temp_color, 1.0f / multiplier_accum);
}
-void GaussianBokehBlurOperation::deinitExecution()
+void GaussianBokehBlurOperation::deinit_execution()
{
- BlurBaseOperation::deinitExecution();
+ BlurBaseOperation::deinit_execution();
- if (this->m_gausstab) {
- MEM_freeN(this->m_gausstab);
- this->m_gausstab = nullptr;
+ if (gausstab_) {
+ MEM_freeN(gausstab_);
+ gausstab_ = nullptr;
}
- deinitMutex();
+ deinit_mutex();
}
-bool GaussianBokehBlurOperation::determineDependingAreaOfInterest(
- rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool GaussianBokehBlurOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
- rcti sizeInput;
- sizeInput.xmin = 0;
- sizeInput.ymin = 0;
- sizeInput.xmax = 5;
- sizeInput.ymax = 5;
- NodeOperation *operation = this->getInputOperation(1);
-
- if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
+ rcti new_input;
+ rcti size_input;
+ size_input.xmin = 0;
+ size_input.ymin = 0;
+ size_input.xmax = 5;
+ size_input.ymax = 5;
+ NodeOperation *operation = this->get_input_operation(1);
+
+ if (operation->determine_depending_area_of_interest(&size_input, read_operation, output)) {
return true;
}
- if (this->m_sizeavailable && this->m_gausstab != nullptr) {
- newInput.xmin = 0;
- newInput.ymin = 0;
- newInput.xmax = this->getWidth();
- newInput.ymax = this->getHeight();
+ if (sizeavailable_ && gausstab_ != nullptr) {
+ new_input.xmin = 0;
+ new_input.ymin = 0;
+ new_input.xmax = this->get_width();
+ new_input.ymax = this->get_height();
}
else {
- int addx = this->m_radx;
- int addy = this->m_rady;
- newInput.xmax = input->xmax + addx;
- newInput.xmin = input->xmin - addx;
- newInput.ymax = input->ymax + addy;
- newInput.ymin = input->ymin - addy;
+ int addx = radx_;
+ int addy = rady_;
+ new_input.xmax = input->xmax + addx;
+ new_input.xmin = input->xmin - addx;
+ new_input.ymax = input->ymax + addy;
+ new_input.ymin = input->ymin - addy;
}
- return BlurBaseOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return BlurBaseOperation::determine_depending_area_of_interest(
+ &new_input, read_operation, output);
}
void GaussianBokehBlurOperation::get_area_of_interest(const int input_idx,
@@ -204,10 +203,10 @@ void GaussianBokehBlurOperation::get_area_of_interest(const int input_idx,
return;
}
- r_input_area.xmax = output_area.xmax + m_radx;
- r_input_area.xmin = output_area.xmin - m_radx;
- r_input_area.ymax = output_area.ymax + m_rady;
- r_input_area.ymin = output_area.ymin - m_rady;
+ r_input_area.xmax = output_area.xmax + radx_;
+ r_input_area.xmin = output_area.xmin - radx_;
+ r_input_area.ymax = output_area.ymax + rady_;
+ r_input_area.ymin = output_area.ymin - rady_;
}
void GaussianBokehBlurOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -221,29 +220,29 @@ void GaussianBokehBlurOperation::update_memory_buffer_partial(MemoryBuffer *outp
const int x = it.x;
const int y = it.y;
- const int ymin = max_ii(y - this->m_rady, input_rect.ymin);
- const int ymax = min_ii(y + this->m_rady + 1, input_rect.ymax);
- const int xmin = max_ii(x - this->m_radx, input_rect.xmin);
- const int xmax = min_ii(x + this->m_radx + 1, input_rect.xmax);
+ const int ymin = max_ii(y - rady_, input_rect.ymin);
+ const int ymax = min_ii(y + rady_ + 1, input_rect.ymax);
+ const int xmin = max_ii(x - radx_, input_rect.xmin);
+ const int xmax = min_ii(x + radx_ + 1, input_rect.xmax);
- float tempColor[4] = {0};
+ float temp_color[4] = {0};
float multiplier_accum = 0;
- const int step = QualityStepHelper::getStep();
+ const int step = QualityStepHelper::get_step();
const int elem_step = step * input->elem_stride;
- const int add_const = (xmin - x + this->m_radx);
- const int mul_const = (this->m_radx * 2 + 1);
+ const int add_const = (xmin - x + radx_);
+ const int mul_const = (radx_ * 2 + 1);
for (int ny = ymin; ny < ymax; ny += step) {
const float *color = input->get_elem(xmin, ny);
- int gauss_index = ((ny - y) + this->m_rady) * mul_const + add_const;
+ int gauss_index = ((ny - y) + rady_) * mul_const + add_const;
const int gauss_end = gauss_index + (xmax - xmin);
for (; gauss_index < gauss_end; gauss_index += step, color += elem_step) {
- const float multiplier = this->m_gausstab[gauss_index];
- madd_v4_v4fl(tempColor, color, multiplier);
+ const float multiplier = gausstab_[gauss_index];
+ madd_v4_v4fl(temp_color, color, multiplier);
multiplier_accum += multiplier;
}
}
- mul_v4_v4fl(it.out, tempColor, 1.0f / multiplier_accum);
+ mul_v4_v4fl(it.out, temp_color, 1.0f / multiplier_accum);
}
}
@@ -251,110 +250,110 @@ void GaussianBokehBlurOperation::update_memory_buffer_partial(MemoryBuffer *outp
GaussianBlurReferenceOperation::GaussianBlurReferenceOperation()
: BlurBaseOperation(DataType::Color)
{
- this->m_maintabs = nullptr;
+ maintabs_ = nullptr;
use_variable_size_ = true;
}
void GaussianBlurReferenceOperation::init_data()
{
/* Setup variables for gausstab and area of interest. */
- this->m_data.image_in_width = this->getWidth();
- this->m_data.image_in_height = this->getHeight();
- if (this->m_data.relative) {
- switch (this->m_data.aspect) {
+ data_.image_in_width = this->get_width();
+ data_.image_in_height = this->get_height();
+ if (data_.relative) {
+ switch (data_.aspect) {
case CMP_NODE_BLUR_ASPECT_NONE:
- this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_width);
- this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_height);
+ data_.sizex = (int)(data_.percentx * 0.01f * data_.image_in_width);
+ data_.sizey = (int)(data_.percenty * 0.01f * data_.image_in_height);
break;
case CMP_NODE_BLUR_ASPECT_Y:
- this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_width);
- this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_width);
+ data_.sizex = (int)(data_.percentx * 0.01f * data_.image_in_width);
+ data_.sizey = (int)(data_.percenty * 0.01f * data_.image_in_width);
break;
case CMP_NODE_BLUR_ASPECT_X:
- this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_height);
- this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_height);
+ data_.sizex = (int)(data_.percentx * 0.01f * data_.image_in_height);
+ data_.sizey = (int)(data_.percenty * 0.01f * data_.image_in_height);
break;
}
}
/* Horizontal. */
- m_filtersizex = (float)this->m_data.sizex;
- int imgx = getWidth() / 2;
- if (m_filtersizex > imgx) {
- m_filtersizex = imgx;
+ filtersizex_ = (float)data_.sizex;
+ int imgx = get_width() / 2;
+ if (filtersizex_ > imgx) {
+ filtersizex_ = imgx;
}
- else if (m_filtersizex < 1) {
- m_filtersizex = 1;
+ else if (filtersizex_ < 1) {
+ filtersizex_ = 1;
}
- m_radx = (float)m_filtersizex;
+ radx_ = (float)filtersizex_;
/* Vertical. */
- m_filtersizey = (float)this->m_data.sizey;
- int imgy = getHeight() / 2;
- if (m_filtersizey > imgy) {
- m_filtersizey = imgy;
+ filtersizey_ = (float)data_.sizey;
+ int imgy = get_height() / 2;
+ if (filtersizey_ > imgy) {
+ filtersizey_ = imgy;
}
- else if (m_filtersizey < 1) {
- m_filtersizey = 1;
+ else if (filtersizey_ < 1) {
+ filtersizey_ = 1;
}
- m_rady = (float)m_filtersizey;
+ rady_ = (float)filtersizey_;
}
-void *GaussianBlurReferenceOperation::initializeTileData(rcti * /*rect*/)
+void *GaussianBlurReferenceOperation::initialize_tile_data(rcti * /*rect*/)
{
- void *buffer = getInputOperation(0)->initializeTileData(nullptr);
+ void *buffer = get_input_operation(0)->initialize_tile_data(nullptr);
return buffer;
}
-void GaussianBlurReferenceOperation::initExecution()
+void GaussianBlurReferenceOperation::init_execution()
{
- BlurBaseOperation::initExecution();
+ BlurBaseOperation::init_execution();
- updateGauss();
+ update_gauss();
}
-void GaussianBlurReferenceOperation::updateGauss()
+void GaussianBlurReferenceOperation::update_gauss()
{
int i;
- int x = MAX2(m_filtersizex, m_filtersizey);
- m_maintabs = (float **)MEM_mallocN(x * sizeof(float *), "gauss array");
+ int x = MAX2(filtersizex_, filtersizey_);
+ maintabs_ = (float **)MEM_mallocN(x * sizeof(float *), "gauss array");
for (i = 0; i < x; i++) {
- m_maintabs[i] = make_gausstab(i + 1, i + 1);
+ maintabs_[i] = make_gausstab(i + 1, i + 1);
}
}
-void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y, void *data)
+void GaussianBlurReferenceOperation::execute_pixel(float output[4], int x, int y, void *data)
{
MemoryBuffer *memorybuffer = (MemoryBuffer *)data;
- float *buffer = memorybuffer->getBuffer();
+ float *buffer = memorybuffer->get_buffer();
float *gausstabx, *gausstabcenty;
float *gausstaby, *gausstabcentx;
int i, j;
float *src;
float sum, val;
float rval, gval, bval, aval;
- int imgx = getWidth();
- int imgy = getHeight();
- float tempSize[4];
- this->m_inputSize->read(tempSize, x, y, data);
- float refSize = tempSize[0];
- int refradx = (int)(refSize * m_radx);
- int refrady = (int)(refSize * m_rady);
- if (refradx > m_filtersizex) {
- refradx = m_filtersizex;
+ int imgx = get_width();
+ int imgy = get_height();
+ float temp_size[4];
+ input_size_->read(temp_size, x, y, data);
+ float ref_size = temp_size[0];
+ int refradx = (int)(ref_size * radx_);
+ int refrady = (int)(ref_size * rady_);
+ if (refradx > filtersizex_) {
+ refradx = filtersizex_;
}
else if (refradx < 1) {
refradx = 1;
}
- if (refrady > m_filtersizey) {
- refrady = m_filtersizey;
+ if (refrady > filtersizey_) {
+ refrady = filtersizey_;
}
else if (refrady < 1) {
refrady = 1;
}
if (refradx == 1 && refrady == 1) {
- memorybuffer->readNoCheck(output, x, y);
+ memorybuffer->read_no_check(output, x, y);
}
else {
int minxr = x - refradx < 0 ? -x : -refradx;
@@ -364,9 +363,9 @@ void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y,
float *srcd = buffer + COM_DATA_TYPE_COLOR_CHANNELS * ((y + minyr) * imgx + x + minxr);
- gausstabx = m_maintabs[refradx - 1];
+ gausstabx = maintabs_[refradx - 1];
gausstabcentx = gausstabx + refradx;
- gausstaby = m_maintabs[refrady - 1];
+ gausstaby = maintabs_[refrady - 1];
gausstabcenty = gausstaby + refrady;
sum = gval = rval = bval = aval = 0.0f;
@@ -390,34 +389,34 @@ void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y,
}
}
-void GaussianBlurReferenceOperation::deinitExecution()
+void GaussianBlurReferenceOperation::deinit_execution()
{
int x, i;
- x = MAX2(this->m_filtersizex, this->m_filtersizey);
+ x = MAX2(filtersizex_, filtersizey_);
for (i = 0; i < x; i++) {
- MEM_freeN(this->m_maintabs[i]);
+ MEM_freeN(maintabs_[i]);
}
- MEM_freeN(this->m_maintabs);
- BlurBaseOperation::deinitExecution();
+ MEM_freeN(maintabs_);
+ BlurBaseOperation::deinit_execution();
}
-bool GaussianBlurReferenceOperation::determineDependingAreaOfInterest(
- rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool GaussianBlurReferenceOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
- NodeOperation *operation = this->getInputOperation(1);
+ rcti new_input;
+ NodeOperation *operation = this->get_input_operation(1);
- if (operation->determineDependingAreaOfInterest(input, readOperation, output)) {
+ if (operation->determine_depending_area_of_interest(input, read_operation, output)) {
return true;
}
- int addx = this->m_data.sizex + 2;
- int addy = this->m_data.sizey + 2;
- newInput.xmax = input->xmax + addx;
- newInput.xmin = input->xmin - addx;
- newInput.ymax = input->ymax + addy;
- newInput.ymin = input->ymin - addy;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ int addx = data_.sizex + 2;
+ int addy = data_.sizey + 2;
+ new_input.xmax = input->xmax + addx;
+ new_input.xmin = input->xmin - addx;
+ new_input.ymax = input->ymax + addy;
+ new_input.ymin = input->ymin - addy;
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void GaussianBlurReferenceOperation::get_area_of_interest(const int input_idx,
@@ -429,8 +428,8 @@ void GaussianBlurReferenceOperation::get_area_of_interest(const int input_idx,
return;
}
- const int add_x = this->m_data.sizex + 2;
- const int add_y = this->m_data.sizey + 2;
+ const int add_x = data_.sizex + 2;
+ const int add_y = data_.sizey + 2;
r_input_area.xmax = output_area.xmax + add_x;
r_input_area.xmin = output_area.xmin - add_x;
r_input_area.ymax = output_area.ymax + add_y;
@@ -445,16 +444,16 @@ void GaussianBlurReferenceOperation::update_memory_buffer_partial(MemoryBuffer *
MemoryBuffer *size_input = inputs[SIZE_INPUT_INDEX];
for (BuffersIterator<float> it = output->iterate_with({size_input}, area); !it.is_end(); ++it) {
const float ref_size = *it.in(0);
- int ref_radx = (int)(ref_size * m_radx);
- int ref_rady = (int)(ref_size * m_rady);
- if (ref_radx > m_filtersizex) {
- ref_radx = m_filtersizex;
+ int ref_radx = (int)(ref_size * radx_);
+ int ref_rady = (int)(ref_size * rady_);
+ if (ref_radx > filtersizex_) {
+ ref_radx = filtersizex_;
}
else if (ref_radx < 1) {
ref_radx = 1;
}
- if (ref_rady > m_filtersizey) {
- ref_rady = m_filtersizey;
+ if (ref_rady > filtersizey_) {
+ ref_rady = filtersizey_;
}
else if (ref_rady < 1) {
ref_rady = 1;
@@ -467,16 +466,16 @@ void GaussianBlurReferenceOperation::update_memory_buffer_partial(MemoryBuffer *
continue;
}
- const int w = getWidth();
- const int height = getHeight();
+ const int w = get_width();
+ const int height = get_height();
const int minxr = x - ref_radx < 0 ? -x : -ref_radx;
const int maxxr = x + ref_radx > w ? w - x : ref_radx;
const int minyr = y - ref_rady < 0 ? -y : -ref_rady;
const int maxyr = y + ref_rady > height ? height - y : ref_rady;
- const float *gausstabx = m_maintabs[ref_radx - 1];
+ const float *gausstabx = maintabs_[ref_radx - 1];
const float *gausstabcentx = gausstabx + ref_radx;
- const float *gausstaby = m_maintabs[ref_rady - 1];
+ const float *gausstaby = maintabs_[ref_rady - 1];
const float *gausstabcenty = gausstaby + ref_rady;
float gauss_sum = 0.0f;
diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h
index a64b5b327b0..06d7d85894c 100644
--- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h
@@ -26,34 +26,32 @@ namespace blender::compositor {
class GaussianBokehBlurOperation : public BlurBaseOperation {
private:
- float *m_gausstab;
- int m_radx, m_rady;
+ float *gausstab_;
+ int radx_, rady_;
float radxf_;
float radyf_;
- void updateGauss();
+ void update_gauss();
public:
GaussianBokehBlurOperation();
void init_data() override;
- void initExecution() override;
- void *initializeTileData(rcti *rect) override;
+ void init_execution() override;
+ void *initialize_tile_data(rcti *rect) override;
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
@@ -61,36 +59,34 @@ class GaussianBokehBlurOperation : public BlurBaseOperation {
class GaussianBlurReferenceOperation : public BlurBaseOperation {
private:
- float **m_maintabs;
+ float **maintabs_;
- void updateGauss();
- int m_filtersizex;
- int m_filtersizey;
- float m_radx;
- float m_rady;
+ void update_gauss();
+ int filtersizex_;
+ int filtersizey_;
+ float radx_;
+ float rady_;
public:
GaussianBlurReferenceOperation();
void init_data() override;
- void initExecution() override;
- void *initializeTileData(rcti *rect) override;
+ void init_execution() override;
+ void *initialize_tile_data(rcti *rect) override;
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc
index 8d686265231..b43db5ba664 100644
--- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc
@@ -17,11 +17,7 @@
*/
#include "COM_GaussianXBlurOperation.h"
-#include "BLI_math.h"
#include "COM_OpenCLDevice.h"
-#include "MEM_guardedalloc.h"
-
-#include "RE_pipeline.h"
namespace blender::compositor {
@@ -29,86 +25,84 @@ GaussianXBlurOperation::GaussianXBlurOperation() : GaussianBlurBaseOperation(eDi
{
}
-void *GaussianXBlurOperation::initializeTileData(rcti * /*rect*/)
+void *GaussianXBlurOperation::initialize_tile_data(rcti * /*rect*/)
{
- lockMutex();
- if (!this->m_sizeavailable) {
- updateGauss();
+ lock_mutex();
+ if (!sizeavailable_) {
+ update_gauss();
}
- void *buffer = getInputOperation(0)->initializeTileData(nullptr);
- unlockMutex();
+ void *buffer = get_input_operation(0)->initialize_tile_data(nullptr);
+ unlock_mutex();
return buffer;
}
/* TODO(manzanilla): to be removed with tiled implementation. */
-void GaussianXBlurOperation::initExecution()
+void GaussianXBlurOperation::init_execution()
{
- GaussianBlurBaseOperation::initExecution();
+ GaussianBlurBaseOperation::init_execution();
- initMutex();
+ init_mutex();
- if (this->m_sizeavailable && execution_model_ == eExecutionModel::Tiled) {
- float rad = max_ff(m_size * m_data.sizex, 0.0f);
- m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
+ if (sizeavailable_ && execution_model_ == eExecutionModel::Tiled) {
+ float rad = max_ff(size_ * data_.sizex, 0.0f);
+ filtersize_ = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
/* TODO(sergey): De-duplicate with the case below and Y blur. */
- this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
+ gausstab_ = BlurBaseOperation::make_gausstab(rad, filtersize_);
#ifdef BLI_HAVE_SSE2
- this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab, m_filtersize);
+ gausstab_sse_ = BlurBaseOperation::convert_gausstab_sse(gausstab_, filtersize_);
#endif
}
}
/* TODO(manzanilla): to be removed with tiled implementation. */
-void GaussianXBlurOperation::updateGauss()
+void GaussianXBlurOperation::update_gauss()
{
- if (this->m_gausstab == nullptr) {
- updateSize();
- float rad = max_ff(m_size * m_data.sizex, 0.0f);
+ if (gausstab_ == nullptr) {
+ update_size();
+ float rad = max_ff(size_ * data_.sizex, 0.0f);
rad = min_ff(rad, MAX_GAUSSTAB_RADIUS);
- m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
+ filtersize_ = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
- this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
+ gausstab_ = BlurBaseOperation::make_gausstab(rad, filtersize_);
#ifdef BLI_HAVE_SSE2
- this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab, m_filtersize);
+ gausstab_sse_ = BlurBaseOperation::convert_gausstab_sse(gausstab_, filtersize_);
#endif
}
}
-void GaussianXBlurOperation::executePixel(float output[4], int x, int y, void *data)
+void GaussianXBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
{
float ATTR_ALIGN(16) color_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float multiplier_accum = 0.0f;
- MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
- const rcti &input_rect = inputBuffer->get_rect();
- float *buffer = inputBuffer->getBuffer();
- int bufferwidth = inputBuffer->getWidth();
+ MemoryBuffer *input_buffer = (MemoryBuffer *)data;
+ const rcti &input_rect = input_buffer->get_rect();
+ float *buffer = input_buffer->get_buffer();
+ int bufferwidth = input_buffer->get_width();
int bufferstartx = input_rect.xmin;
int bufferstarty = input_rect.ymin;
- int xmin = max_ii(x - m_filtersize, input_rect.xmin);
- int xmax = min_ii(x + m_filtersize + 1, input_rect.xmax);
+ int xmin = max_ii(x - filtersize_, input_rect.xmin);
+ int xmax = min_ii(x + filtersize_ + 1, input_rect.xmax);
int ymin = max_ii(y, input_rect.ymin);
- int step = getStep();
- int offsetadd = getOffsetAdd();
+ int step = get_step();
+ int offsetadd = get_offset_add();
int bufferindex = ((xmin - bufferstartx) * 4) + ((ymin - bufferstarty) * 4 * bufferwidth);
#ifdef BLI_HAVE_SSE2
__m128 accum_r = _mm_load_ps(color_accum);
- for (int nx = xmin, index = (xmin - x) + this->m_filtersize; nx < xmax;
- nx += step, index += step) {
+ for (int nx = xmin, index = (xmin - x) + filtersize_; nx < xmax; nx += step, index += step) {
__m128 reg_a = _mm_load_ps(&buffer[bufferindex]);
- reg_a = _mm_mul_ps(reg_a, this->m_gausstab_sse[index]);
+ reg_a = _mm_mul_ps(reg_a, gausstab_sse_[index]);
accum_r = _mm_add_ps(accum_r, reg_a);
- multiplier_accum += this->m_gausstab[index];
+ multiplier_accum += gausstab_[index];
bufferindex += offsetadd;
}
_mm_store_ps(color_accum, accum_r);
#else
- for (int nx = xmin, index = (xmin - x) + this->m_filtersize; nx < xmax;
- nx += step, index += step) {
- const float multiplier = this->m_gausstab[index];
+ for (int nx = xmin, index = (xmin - x) + filtersize_; nx < xmax; nx += step, index += step) {
+ const float multiplier = gausstab_[index];
madd_v4_v4fl(color_accum, &buffer[bufferindex], multiplier);
multiplier_accum += multiplier;
bufferindex += offsetadd;
@@ -117,91 +111,90 @@ void GaussianXBlurOperation::executePixel(float output[4], int x, int y, void *d
mul_v4_v4fl(output, color_accum, 1.0f / multiplier_accum);
}
-void GaussianXBlurOperation::executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer,
- cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers,
- std::list<cl_mem> *clMemToCleanUp,
- std::list<cl_kernel> * /*clKernelsToCleanUp*/)
+void GaussianXBlurOperation::execute_opencl(OpenCLDevice *device,
+ MemoryBuffer *output_memory_buffer,
+ cl_mem cl_output_buffer,
+ MemoryBuffer **input_memory_buffers,
+ std::list<cl_mem> *cl_mem_to_clean_up,
+ std::list<cl_kernel> * /*cl_kernels_to_clean_up*/)
{
- cl_kernel gaussianXBlurOperationKernel = device->COM_clCreateKernel(
- "gaussianXBlurOperationKernel", nullptr);
- cl_int filter_size = this->m_filtersize;
+ cl_kernel gaussian_xblur_operation_kernel = device->COM_cl_create_kernel(
+ "gaussian_xblur_operation_kernel", nullptr);
+ cl_int filter_size = filtersize_;
- cl_mem gausstab = clCreateBuffer(device->getContext(),
+ cl_mem gausstab = clCreateBuffer(device->get_context(),
CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,
- sizeof(float) * (this->m_filtersize * 2 + 1),
- this->m_gausstab,
+ sizeof(float) * (filtersize_ * 2 + 1),
+ gausstab_,
nullptr);
- device->COM_clAttachMemoryBufferToKernelParameter(gaussianXBlurOperationKernel,
- 0,
- 1,
- clMemToCleanUp,
- inputMemoryBuffers,
- this->m_inputProgram);
- device->COM_clAttachOutputMemoryBufferToKernelParameter(
- gaussianXBlurOperationKernel, 2, clOutputBuffer);
- device->COM_clAttachMemoryBufferOffsetToKernelParameter(
- gaussianXBlurOperationKernel, 3, outputMemoryBuffer);
- clSetKernelArg(gaussianXBlurOperationKernel, 4, sizeof(cl_int), &filter_size);
- device->COM_clAttachSizeToKernelParameter(gaussianXBlurOperationKernel, 5, this);
- clSetKernelArg(gaussianXBlurOperationKernel, 6, sizeof(cl_mem), &gausstab);
-
- device->COM_clEnqueueRange(gaussianXBlurOperationKernel, outputMemoryBuffer, 7, this);
+ device->COM_cl_attach_memory_buffer_to_kernel_parameter(gaussian_xblur_operation_kernel,
+ 0,
+ 1,
+ cl_mem_to_clean_up,
+ input_memory_buffers,
+ input_program_);
+ device->COM_cl_attach_output_memory_buffer_to_kernel_parameter(
+ gaussian_xblur_operation_kernel, 2, cl_output_buffer);
+ device->COM_cl_attach_memory_buffer_offset_to_kernel_parameter(
+ gaussian_xblur_operation_kernel, 3, output_memory_buffer);
+ clSetKernelArg(gaussian_xblur_operation_kernel, 4, sizeof(cl_int), &filter_size);
+ device->COM_cl_attach_size_to_kernel_parameter(gaussian_xblur_operation_kernel, 5, this);
+ clSetKernelArg(gaussian_xblur_operation_kernel, 6, sizeof(cl_mem), &gausstab);
+
+ device->COM_cl_enqueue_range(gaussian_xblur_operation_kernel, output_memory_buffer, 7, this);
clReleaseMemObject(gausstab);
}
-void GaussianXBlurOperation::deinitExecution()
+void GaussianXBlurOperation::deinit_execution()
{
- GaussianBlurBaseOperation::deinitExecution();
+ GaussianBlurBaseOperation::deinit_execution();
- if (this->m_gausstab) {
- MEM_freeN(this->m_gausstab);
- this->m_gausstab = nullptr;
+ if (gausstab_) {
+ MEM_freeN(gausstab_);
+ gausstab_ = nullptr;
}
#ifdef BLI_HAVE_SSE2
- if (this->m_gausstab_sse) {
- MEM_freeN(this->m_gausstab_sse);
- this->m_gausstab_sse = nullptr;
+ if (gausstab_sse_) {
+ MEM_freeN(gausstab_sse_);
+ gausstab_sse_ = nullptr;
}
#endif
- deinitMutex();
+ deinit_mutex();
}
-bool GaussianXBlurOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool GaussianXBlurOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
-
- if (!this->m_sizeavailable) {
- rcti sizeInput;
- sizeInput.xmin = 0;
- sizeInput.ymin = 0;
- sizeInput.xmax = 5;
- sizeInput.ymax = 5;
- NodeOperation *operation = this->getInputOperation(1);
- if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
+ rcti new_input;
+
+ if (!sizeavailable_) {
+ rcti size_input;
+ size_input.xmin = 0;
+ size_input.ymin = 0;
+ size_input.xmax = 5;
+ size_input.ymax = 5;
+ NodeOperation *operation = this->get_input_operation(1);
+ if (operation->determine_depending_area_of_interest(&size_input, read_operation, output)) {
return true;
}
}
{
- if (this->m_sizeavailable && this->m_gausstab != nullptr) {
- newInput.xmax = input->xmax + this->m_filtersize + 1;
- newInput.xmin = input->xmin - this->m_filtersize - 1;
- newInput.ymax = input->ymax;
- newInput.ymin = input->ymin;
+ if (sizeavailable_ && gausstab_ != nullptr) {
+ new_input.xmax = input->xmax + filtersize_ + 1;
+ new_input.xmin = input->xmin - filtersize_ - 1;
+ new_input.ymax = input->ymax;
+ new_input.ymin = input->ymin;
}
else {
- newInput.xmax = this->getWidth();
- newInput.xmin = 0;
- newInput.ymax = this->getHeight();
- newInput.ymin = 0;
+ new_input.xmax = this->get_width();
+ new_input.xmin = 0;
+ new_input.ymax = this->get_height();
+ new_input.ymin = 0;
}
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
}
diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h
index e09e57bad67..72356381da3 100644
--- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h
@@ -25,7 +25,7 @@ namespace blender::compositor {
/* TODO(manzanilla): everything to be removed with tiled implementation except the constructor. */
class GaussianXBlurOperation : public GaussianBlurBaseOperation {
private:
- void updateGauss();
+ void update_gauss();
public:
GaussianXBlurOperation();
@@ -33,33 +33,33 @@ class GaussianXBlurOperation : public GaussianBlurBaseOperation {
/**
* \brief The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
- void executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer,
- cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers,
- std::list<cl_mem> *clMemToCleanUp,
- std::list<cl_kernel> *clKernelsToCleanUp) override;
+ void execute_opencl(OpenCLDevice *device,
+ MemoryBuffer *output_memory_buffer,
+ cl_mem cl_output_buffer,
+ MemoryBuffer **input_memory_buffers,
+ std::list<cl_mem> *cl_mem_to_clean_up,
+ std::list<cl_kernel> *cl_kernels_to_clean_up) override;
/**
* \brief initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* \brief Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void *initializeTileData(rcti *rect) override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ void *initialize_tile_data(rcti *rect) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void checkOpenCL()
+ void check_opencl()
{
- flags.open_cl = (m_data.sizex >= 128);
+ flags_.open_cl = (data_.sizex >= 128);
}
};
diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc
index 32d469a0ae4..639536ebcc1 100644
--- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc
@@ -17,11 +17,7 @@
*/
#include "COM_GaussianYBlurOperation.h"
-#include "BLI_math.h"
#include "COM_OpenCLDevice.h"
-#include "MEM_guardedalloc.h"
-
-#include "RE_pipeline.h"
namespace blender::compositor {
@@ -29,85 +25,85 @@ GaussianYBlurOperation::GaussianYBlurOperation() : GaussianBlurBaseOperation(eDi
{
}
-void *GaussianYBlurOperation::initializeTileData(rcti * /*rect*/)
+void *GaussianYBlurOperation::initialize_tile_data(rcti * /*rect*/)
{
- lockMutex();
- if (!this->m_sizeavailable) {
- updateGauss();
+ lock_mutex();
+ if (!sizeavailable_) {
+ update_gauss();
}
- void *buffer = getInputOperation(0)->initializeTileData(nullptr);
- unlockMutex();
+ void *buffer = get_input_operation(0)->initialize_tile_data(nullptr);
+ unlock_mutex();
return buffer;
}
-void GaussianYBlurOperation::initExecution()
+void GaussianYBlurOperation::init_execution()
{
- GaussianBlurBaseOperation::initExecution();
+ GaussianBlurBaseOperation::init_execution();
- initMutex();
+ init_mutex();
- if (this->m_sizeavailable && execution_model_ == eExecutionModel::Tiled) {
- float rad = max_ff(m_size * m_data.sizey, 0.0f);
- m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
+ if (sizeavailable_ && execution_model_ == eExecutionModel::Tiled) {
+ float rad = max_ff(size_ * data_.sizey, 0.0f);
+ filtersize_ = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
- this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
+ gausstab_ = BlurBaseOperation::make_gausstab(rad, filtersize_);
#ifdef BLI_HAVE_SSE2
- this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab, m_filtersize);
+ gausstab_sse_ = BlurBaseOperation::convert_gausstab_sse(gausstab_, filtersize_);
#endif
}
}
-void GaussianYBlurOperation::updateGauss()
+void GaussianYBlurOperation::update_gauss()
{
- if (this->m_gausstab == nullptr) {
- updateSize();
- float rad = max_ff(m_size * m_data.sizey, 0.0f);
+ if (gausstab_ == nullptr) {
+ update_size();
+ float rad = max_ff(size_ * data_.sizey, 0.0f);
rad = min_ff(rad, MAX_GAUSSTAB_RADIUS);
- m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
+ filtersize_ = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
- this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
+ gausstab_ = BlurBaseOperation::make_gausstab(rad, filtersize_);
#ifdef BLI_HAVE_SSE2
- this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab, m_filtersize);
+ gausstab_sse_ = BlurBaseOperation::convert_gausstab_sse(gausstab_, filtersize_);
#endif
}
}
-void GaussianYBlurOperation::executePixel(float output[4], int x, int y, void *data)
+void GaussianYBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
{
float ATTR_ALIGN(16) color_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float multiplier_accum = 0.0f;
- MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
- const rcti &input_rect = inputBuffer->get_rect();
- float *buffer = inputBuffer->getBuffer();
- int bufferwidth = inputBuffer->getWidth();
+ MemoryBuffer *input_buffer = (MemoryBuffer *)data;
+ const rcti &input_rect = input_buffer->get_rect();
+ float *buffer = input_buffer->get_buffer();
+ int bufferwidth = input_buffer->get_width();
int bufferstartx = input_rect.xmin;
int bufferstarty = input_rect.ymin;
int xmin = max_ii(x, input_rect.xmin);
- int ymin = max_ii(y - m_filtersize, input_rect.ymin);
- int ymax = min_ii(y + m_filtersize + 1, input_rect.ymax);
+ int ymin = max_ii(y - filtersize_, input_rect.ymin);
+ int ymax = min_ii(y + filtersize_ + 1, input_rect.ymax);
int index;
- int step = getStep();
- const int bufferIndexx = ((xmin - bufferstartx) * 4);
+ int step = get_step();
+ const int buffer_indexx = ((xmin - bufferstartx) * 4);
#ifdef BLI_HAVE_SSE2
__m128 accum_r = _mm_load_ps(color_accum);
for (int ny = ymin; ny < ymax; ny += step) {
- index = (ny - y) + this->m_filtersize;
- int bufferindex = bufferIndexx + ((ny - bufferstarty) * 4 * bufferwidth);
- const float multiplier = this->m_gausstab[index];
+ index = (ny - y) + filtersize_;
+ int bufferindex = buffer_indexx + ((ny - bufferstarty) * 4 * bufferwidth);
+ const float multiplier = gausstab_[index];
__m128 reg_a = _mm_load_ps(&buffer[bufferindex]);
- reg_a = _mm_mul_ps(reg_a, this->m_gausstab_sse[index]);
+ reg_a = _mm_mul_ps(reg_a, gausstab_sse_[index]);
accum_r = _mm_add_ps(accum_r, reg_a);
multiplier_accum += multiplier;
}
_mm_store_ps(color_accum, accum_r);
#else
for (int ny = ymin; ny < ymax; ny += step) {
- index = (ny - y) + this->m_filtersize;
- int bufferindex = bufferIndexx + ((ny - bufferstarty) * 4 * bufferwidth);
- const float multiplier = this->m_gausstab[index];
+ index = (ny - y) + filtersize_;
+ int bufferindex = buffer_indexx + ((ny - bufferstarty) * 4 * bufferwidth);
+ const float multiplier = gausstab_[index];
madd_v4_v4fl(color_accum, &buffer[bufferindex], multiplier);
multiplier_accum += multiplier;
}
@@ -115,91 +111,90 @@ void GaussianYBlurOperation::executePixel(float output[4], int x, int y, void *d
mul_v4_v4fl(output, color_accum, 1.0f / multiplier_accum);
}
-void GaussianYBlurOperation::executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer,
- cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers,
- std::list<cl_mem> *clMemToCleanUp,
- std::list<cl_kernel> * /*clKernelsToCleanUp*/)
+void GaussianYBlurOperation::execute_opencl(OpenCLDevice *device,
+ MemoryBuffer *output_memory_buffer,
+ cl_mem cl_output_buffer,
+ MemoryBuffer **input_memory_buffers,
+ std::list<cl_mem> *cl_mem_to_clean_up,
+ std::list<cl_kernel> * /*cl_kernels_to_clean_up*/)
{
- cl_kernel gaussianYBlurOperationKernel = device->COM_clCreateKernel(
- "gaussianYBlurOperationKernel", nullptr);
- cl_int filter_size = this->m_filtersize;
+ cl_kernel gaussian_yblur_operation_kernel = device->COM_cl_create_kernel(
+ "gaussian_yblur_operation_kernel", nullptr);
+ cl_int filter_size = filtersize_;
- cl_mem gausstab = clCreateBuffer(device->getContext(),
+ cl_mem gausstab = clCreateBuffer(device->get_context(),
CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,
- sizeof(float) * (this->m_filtersize * 2 + 1),
- this->m_gausstab,
+ sizeof(float) * (filtersize_ * 2 + 1),
+ gausstab_,
nullptr);
- device->COM_clAttachMemoryBufferToKernelParameter(gaussianYBlurOperationKernel,
- 0,
- 1,
- clMemToCleanUp,
- inputMemoryBuffers,
- this->m_inputProgram);
- device->COM_clAttachOutputMemoryBufferToKernelParameter(
- gaussianYBlurOperationKernel, 2, clOutputBuffer);
- device->COM_clAttachMemoryBufferOffsetToKernelParameter(
- gaussianYBlurOperationKernel, 3, outputMemoryBuffer);
- clSetKernelArg(gaussianYBlurOperationKernel, 4, sizeof(cl_int), &filter_size);
- device->COM_clAttachSizeToKernelParameter(gaussianYBlurOperationKernel, 5, this);
- clSetKernelArg(gaussianYBlurOperationKernel, 6, sizeof(cl_mem), &gausstab);
-
- device->COM_clEnqueueRange(gaussianYBlurOperationKernel, outputMemoryBuffer, 7, this);
+ device->COM_cl_attach_memory_buffer_to_kernel_parameter(gaussian_yblur_operation_kernel,
+ 0,
+ 1,
+ cl_mem_to_clean_up,
+ input_memory_buffers,
+ input_program_);
+ device->COM_cl_attach_output_memory_buffer_to_kernel_parameter(
+ gaussian_yblur_operation_kernel, 2, cl_output_buffer);
+ device->COM_cl_attach_memory_buffer_offset_to_kernel_parameter(
+ gaussian_yblur_operation_kernel, 3, output_memory_buffer);
+ clSetKernelArg(gaussian_yblur_operation_kernel, 4, sizeof(cl_int), &filter_size);
+ device->COM_cl_attach_size_to_kernel_parameter(gaussian_yblur_operation_kernel, 5, this);
+ clSetKernelArg(gaussian_yblur_operation_kernel, 6, sizeof(cl_mem), &gausstab);
+
+ device->COM_cl_enqueue_range(gaussian_yblur_operation_kernel, output_memory_buffer, 7, this);
clReleaseMemObject(gausstab);
}
-void GaussianYBlurOperation::deinitExecution()
+void GaussianYBlurOperation::deinit_execution()
{
- GaussianBlurBaseOperation::deinitExecution();
+ GaussianBlurBaseOperation::deinit_execution();
- if (this->m_gausstab) {
- MEM_freeN(this->m_gausstab);
- this->m_gausstab = nullptr;
+ if (gausstab_) {
+ MEM_freeN(gausstab_);
+ gausstab_ = nullptr;
}
#ifdef BLI_HAVE_SSE2
- if (this->m_gausstab_sse) {
- MEM_freeN(this->m_gausstab_sse);
- this->m_gausstab_sse = nullptr;
+ if (gausstab_sse_) {
+ MEM_freeN(gausstab_sse_);
+ gausstab_sse_ = nullptr;
}
#endif
- deinitMutex();
+ deinit_mutex();
}
-bool GaussianYBlurOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool GaussianYBlurOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
-
- if (!m_sizeavailable) {
- rcti sizeInput;
- sizeInput.xmin = 0;
- sizeInput.ymin = 0;
- sizeInput.xmax = 5;
- sizeInput.ymax = 5;
- NodeOperation *operation = this->getInputOperation(1);
- if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
+ rcti new_input;
+
+ if (!sizeavailable_) {
+ rcti size_input;
+ size_input.xmin = 0;
+ size_input.ymin = 0;
+ size_input.xmax = 5;
+ size_input.ymax = 5;
+ NodeOperation *operation = this->get_input_operation(1);
+ if (operation->determine_depending_area_of_interest(&size_input, read_operation, output)) {
return true;
}
}
{
- if (this->m_sizeavailable && this->m_gausstab != nullptr) {
- newInput.xmax = input->xmax;
- newInput.xmin = input->xmin;
- newInput.ymax = input->ymax + this->m_filtersize + 1;
- newInput.ymin = input->ymin - this->m_filtersize - 1;
+ if (sizeavailable_ && gausstab_ != nullptr) {
+ new_input.xmax = input->xmax;
+ new_input.xmin = input->xmin;
+ new_input.ymax = input->ymax + filtersize_ + 1;
+ new_input.ymin = input->ymin - filtersize_ - 1;
}
else {
- newInput.xmax = this->getWidth();
- newInput.xmin = 0;
- newInput.ymax = this->getHeight();
- newInput.ymin = 0;
+ new_input.xmax = this->get_width();
+ new_input.xmin = 0;
+ new_input.ymax = this->get_height();
+ new_input.ymin = 0;
}
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
}
diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h
index bb33f8b74cb..817e5a137c2 100644
--- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h
@@ -25,7 +25,7 @@ namespace blender::compositor {
/* TODO(manzanilla): everything to be removed with tiled implementation except the constructor. */
class GaussianYBlurOperation : public GaussianBlurBaseOperation {
private:
- void updateGauss();
+ void update_gauss();
public:
GaussianYBlurOperation();
@@ -33,33 +33,33 @@ class GaussianYBlurOperation : public GaussianBlurBaseOperation {
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
- void executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer,
- cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers,
- std::list<cl_mem> *clMemToCleanUp,
- std::list<cl_kernel> *clKernelsToCleanUp) override;
+ void execute_opencl(OpenCLDevice *device,
+ MemoryBuffer *output_memory_buffer,
+ cl_mem cl_output_buffer,
+ MemoryBuffer **input_memory_buffers,
+ std::list<cl_mem> *cl_mem_to_clean_up,
+ std::list<cl_kernel> *cl_kernels_to_clean_up) override;
/**
* \brief initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void *initializeTileData(rcti *rect) override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ void *initialize_tile_data(rcti *rect) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void checkOpenCL()
+ void check_opencl()
{
- flags.open_cl = (m_data.sizex >= 128);
+ flags_.open_cl = (data_.sizex >= 128);
}
};
diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.cc b/source/blender/compositor/operations/COM_GlareBaseOperation.cc
index cd4607b1dde..766b20326db 100644
--- a/source/blender/compositor/operations/COM_GlareBaseOperation.cc
+++ b/source/blender/compositor/operations/COM_GlareBaseOperation.cc
@@ -17,58 +17,57 @@
*/
#include "COM_GlareBaseOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
GlareBaseOperation::GlareBaseOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
- this->m_settings = nullptr;
- flags.is_fullframe_operation = true;
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ settings_ = nullptr;
+ flags_.is_fullframe_operation = true;
is_output_rendered_ = false;
}
-void GlareBaseOperation::initExecution()
+void GlareBaseOperation::init_execution()
{
- SingleThreadedOperation::initExecution();
- this->m_inputProgram = getInputSocketReader(0);
+ SingleThreadedOperation::init_execution();
+ input_program_ = get_input_socket_reader(0);
}
-void GlareBaseOperation::deinitExecution()
+void GlareBaseOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
- SingleThreadedOperation::deinitExecution();
+ input_program_ = nullptr;
+ SingleThreadedOperation::deinit_execution();
}
-MemoryBuffer *GlareBaseOperation::createMemoryBuffer(rcti *rect2)
+MemoryBuffer *GlareBaseOperation::create_memory_buffer(rcti *rect2)
{
- MemoryBuffer *tile = (MemoryBuffer *)this->m_inputProgram->initializeTileData(rect2);
+ MemoryBuffer *tile = (MemoryBuffer *)input_program_->initialize_tile_data(rect2);
rcti rect;
rect.xmin = 0;
rect.ymin = 0;
- rect.xmax = getWidth();
- rect.ymax = getHeight();
+ rect.xmax = get_width();
+ rect.ymax = get_height();
MemoryBuffer *result = new MemoryBuffer(DataType::Color, rect);
- float *data = result->getBuffer();
- this->generateGlare(data, tile, this->m_settings);
+ float *data = result->get_buffer();
+ this->generate_glare(data, tile, settings_);
return result;
}
-bool GlareBaseOperation::determineDependingAreaOfInterest(rcti * /*input*/,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool GlareBaseOperation::determine_depending_area_of_interest(rcti * /*input*/,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- if (isCached()) {
+ if (is_cached()) {
return false;
}
- rcti newInput;
- newInput.xmax = this->getWidth();
- newInput.xmin = 0;
- newInput.ymax = this->getHeight();
- newInput.ymin = 0;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ rcti new_input;
+ new_input.xmax = this->get_width();
+ new_input.xmin = 0;
+ new_input.ymax = this->get_height();
+ new_input.ymin = 0;
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void GlareBaseOperation::get_area_of_interest(const int input_idx,
@@ -78,9 +77,9 @@ void GlareBaseOperation::get_area_of_interest(const int input_idx,
BLI_assert(input_idx == 0);
UNUSED_VARS_NDEBUG(input_idx);
r_input_area.xmin = 0;
- r_input_area.xmax = this->getWidth();
+ r_input_area.xmax = this->get_width();
r_input_area.ymin = 0;
- r_input_area.ymax = this->getHeight();
+ r_input_area.ymax = this->get_height();
}
void GlareBaseOperation::update_memory_buffer(MemoryBuffer *output,
@@ -94,7 +93,7 @@ void GlareBaseOperation::update_memory_buffer(MemoryBuffer *output,
input = input->inflate();
}
- this->generateGlare(output->getBuffer(), input, m_settings);
+ this->generate_glare(output->get_buffer(), input, settings_);
is_output_rendered_ = true;
if (is_input_inflated) {
diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.h b/source/blender/compositor/operations/COM_GlareBaseOperation.h
index 5ca240a9e66..c29587839b1 100644
--- a/source/blender/compositor/operations/COM_GlareBaseOperation.h
+++ b/source/blender/compositor/operations/COM_GlareBaseOperation.h
@@ -40,14 +40,14 @@ typedef float fRGB[4];
class GlareBaseOperation : public SingleThreadedOperation {
private:
/**
- * \brief Cached reference to the inputProgram
+ * \brief Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
+ SocketReader *input_program_;
/**
* \brief settings of the glare node.
*/
- NodeGlare *m_settings;
+ NodeGlare *settings_;
bool is_output_rendered_;
@@ -55,24 +55,22 @@ class GlareBaseOperation : public SingleThreadedOperation {
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setGlareSettings(NodeGlare *settings)
+ void set_glare_settings(NodeGlare *settings)
{
- this->m_settings = settings;
+ settings_ = settings;
}
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) final;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) final;
void update_memory_buffer(MemoryBuffer *output,
const rcti &area,
@@ -81,9 +79,9 @@ class GlareBaseOperation : public SingleThreadedOperation {
protected:
GlareBaseOperation();
- virtual void generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings) = 0;
+ virtual void generate_glare(float *data, MemoryBuffer *input_tile, NodeGlare *settings) = 0;
- MemoryBuffer *createMemoryBuffer(rcti *rect) override;
+ MemoryBuffer *create_memory_buffer(rcti *rect) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc
index 0026615f08b..fa2e2597452 100644
--- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc
+++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc
@@ -17,7 +17,6 @@
*/
#include "COM_GlareFogGlowOperation.h"
-#include "MEM_guardedalloc.h"
namespace blender::compositor {
@@ -28,7 +27,7 @@ namespace blender::compositor {
using fREAL = float;
/* Returns next highest power of 2 of x, as well its log2 in L2. */
-static unsigned int nextPow2(unsigned int x, unsigned int *L2)
+static unsigned int next_pow2(unsigned int x, unsigned int *L2)
{
unsigned int pw, x_notpow2 = x & (x - 1);
*L2 = 0;
@@ -263,24 +262,24 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
int x, y, ch;
int xbl, ybl, nxb, nyb, xbsz, ybsz;
bool in2done = false;
- const unsigned int kernelWidth = in2->getWidth();
- const unsigned int kernelHeight = in2->getHeight();
- const unsigned int imageWidth = in1->getWidth();
- const unsigned int imageHeight = in1->getHeight();
- float *kernelBuffer = in2->getBuffer();
- float *imageBuffer = in1->getBuffer();
+ const unsigned int kernel_width = in2->get_width();
+ const unsigned int kernel_height = in2->get_height();
+ const unsigned int image_width = in1->get_width();
+ const unsigned int image_height = in1->get_height();
+ float *kernel_buffer = in2->get_buffer();
+ float *image_buffer = in1->get_buffer();
MemoryBuffer *rdst = new MemoryBuffer(DataType::Color, in1->get_rect());
- memset(rdst->getBuffer(),
+ memset(rdst->get_buffer(),
0,
- rdst->getWidth() * rdst->getHeight() * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float));
+ rdst->get_width() * rdst->get_height() * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float));
/* Convolution result width & height. */
- w2 = 2 * kernelWidth - 1;
- h2 = 2 * kernelHeight - 1;
+ w2 = 2 * kernel_width - 1;
+ h2 = 2 * kernel_height - 1;
/* FFT pow2 required size & log2. */
- w2 = nextPow2(w2, &log2_w);
- h2 = nextPow2(h2, &log2_h);
+ w2 = next_pow2(w2, &log2_w);
+ h2 = next_pow2(h2, &log2_h);
/* Allocate space. */
data1 = (fREAL *)MEM_callocN(3 * w2 * h2 * sizeof(fREAL), "convolve_fast FHT data1");
@@ -288,9 +287,9 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
/* Normalize convolutor. */
wt[0] = wt[1] = wt[2] = 0.0f;
- for (y = 0; y < kernelHeight; y++) {
- colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_DATA_TYPE_COLOR_CHANNELS];
- for (x = 0; x < kernelWidth; x++) {
+ for (y = 0; y < kernel_height; y++) {
+ colp = (fRGB *)&kernel_buffer[y * kernel_width * COM_DATA_TYPE_COLOR_CHANNELS];
+ for (x = 0; x < kernel_width; x++) {
add_v3_v3(wt, colp[x]);
}
}
@@ -303,9 +302,9 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
if (wt[2] != 0.0f) {
wt[2] = 1.0f / wt[2];
}
- for (y = 0; y < kernelHeight; y++) {
- colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_DATA_TYPE_COLOR_CHANNELS];
- for (x = 0; x < kernelWidth; x++) {
+ for (y = 0; y < kernel_height; y++) {
+ colp = (fRGB *)&kernel_buffer[y * kernel_width * COM_DATA_TYPE_COLOR_CHANNELS];
+ for (x = 0; x < kernel_width; x++) {
mul_v3_v3(colp[x], wt);
}
}
@@ -314,16 +313,16 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
* only need to calc data1 once. */
/* Block add-overlap. */
- hw = kernelWidth >> 1;
- hh = kernelHeight >> 1;
- xbsz = (w2 + 1) - kernelWidth;
- ybsz = (h2 + 1) - kernelHeight;
- nxb = imageWidth / xbsz;
- if (imageWidth % xbsz) {
+ hw = kernel_width >> 1;
+ hh = kernel_height >> 1;
+ xbsz = (w2 + 1) - kernel_width;
+ ybsz = (h2 + 1) - kernel_height;
+ nxb = image_width / xbsz;
+ if (image_width % xbsz) {
nxb++;
}
- nyb = imageHeight / ybsz;
- if (imageHeight % ybsz) {
+ nyb = image_height / ybsz;
+ if (image_height % ybsz) {
nyb++;
}
for (ybl = 0; ybl < nyb; ybl++) {
@@ -336,10 +335,10 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
/* Only need to calc fht data from in2 once, can re-use for every block. */
if (!in2done) {
/* in2, channel ch -> data1 */
- for (y = 0; y < kernelHeight; y++) {
+ for (y = 0; y < kernel_height; y++) {
fp = &data1ch[y * w2];
- colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_DATA_TYPE_COLOR_CHANNELS];
- for (x = 0; x < kernelWidth; x++) {
+ colp = (fRGB *)&kernel_buffer[y * kernel_width * COM_DATA_TYPE_COLOR_CHANNELS];
+ for (x = 0; x < kernel_width; x++) {
fp[x] = colp[x][ch];
}
}
@@ -349,14 +348,14 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
memset(data2, 0, w2 * h2 * sizeof(fREAL));
for (y = 0; y < ybsz; y++) {
int yy = ybl * ybsz + y;
- if (yy >= imageHeight) {
+ if (yy >= image_height) {
continue;
}
fp = &data2[y * w2];
- colp = (fRGB *)&imageBuffer[yy * imageWidth * COM_DATA_TYPE_COLOR_CHANNELS];
+ colp = (fRGB *)&image_buffer[yy * image_width * COM_DATA_TYPE_COLOR_CHANNELS];
for (x = 0; x < xbsz; x++) {
int xx = xbl * xbsz + x;
- if (xx >= imageWidth) {
+ if (xx >= image_width) {
continue;
}
fp[x] = colp[xx][ch];
@@ -366,9 +365,9 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
/* Forward FHT
* zero pad data start is different for each == height+1. */
if (!in2done) {
- FHT2D(data1ch, log2_w, log2_h, kernelHeight + 1, 0);
+ FHT2D(data1ch, log2_w, log2_h, kernel_height + 1, 0);
}
- FHT2D(data2, log2_w, log2_h, kernelHeight + 1, 0);
+ FHT2D(data2, log2_w, log2_h, kernel_height + 1, 0);
/* FHT2D transposed data, row/col now swapped
* convolve & inverse FHT. */
@@ -379,14 +378,14 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
/* Overlap-add result. */
for (y = 0; y < (int)h2; y++) {
const int yy = ybl * ybsz + y - hh;
- if ((yy < 0) || (yy >= imageHeight)) {
+ if ((yy < 0) || (yy >= image_height)) {
continue;
}
fp = &data2[y * w2];
- colp = (fRGB *)&rdst->getBuffer()[yy * imageWidth * COM_DATA_TYPE_COLOR_CHANNELS];
+ colp = (fRGB *)&rdst->get_buffer()[yy * image_width * COM_DATA_TYPE_COLOR_CHANNELS];
for (x = 0; x < (int)w2; x++) {
const int xx = xbl * xbsz + x - hw;
- if ((xx < 0) || (xx >= imageWidth)) {
+ if ((xx < 0) || (xx >= image_width)) {
continue;
}
colp[xx][ch] += fp[x];
@@ -400,14 +399,14 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
MEM_freeN(data2);
MEM_freeN(data1);
memcpy(dst,
- rdst->getBuffer(),
- sizeof(float) * imageWidth * imageHeight * COM_DATA_TYPE_COLOR_CHANNELS);
+ rdst->get_buffer(),
+ sizeof(float) * image_width * image_height * COM_DATA_TYPE_COLOR_CHANNELS);
delete (rdst);
}
-void GlareFogGlowOperation::generateGlare(float *data,
- MemoryBuffer *inputTile,
- NodeGlare *settings)
+void GlareFogGlowOperation::generate_glare(float *data,
+ MemoryBuffer *input_tile,
+ NodeGlare *settings)
{
int x, y;
float scale, u, v, r, w, d;
@@ -418,9 +417,9 @@ void GlareFogGlowOperation::generateGlare(float *data,
/* Temp. src image
* make the convolution kernel. */
- rcti kernelRect;
- BLI_rcti_init(&kernelRect, 0, sz, 0, sz);
- ckrn = new MemoryBuffer(DataType::Color, kernelRect);
+ rcti kernel_rect;
+ BLI_rcti_init(&kernel_rect, 0, sz, 0, sz);
+ ckrn = new MemoryBuffer(DataType::Color, kernel_rect);
scale = 0.25f * sqrtf((float)(sz * sz));
@@ -438,11 +437,11 @@ void GlareFogGlowOperation::generateGlare(float *data,
* actually, Hanning window is ok, `cos^2` for some reason is slower. */
w = (0.5f + 0.5f * cosf(u * (float)M_PI)) * (0.5f + 0.5f * cosf(v * (float)M_PI));
mul_v3_fl(fcol, w);
- ckrn->writePixel(x, y, fcol);
+ ckrn->write_pixel(x, y, fcol);
}
}
- convolve(data, inputTile, ckrn);
+ convolve(data, input_tile, ckrn);
delete ckrn;
}
diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.h b/source/blender/compositor/operations/COM_GlareFogGlowOperation.h
index 5701f76ab13..648351fa692 100644
--- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.h
+++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.h
@@ -31,7 +31,7 @@ class GlareFogGlowOperation : public GlareBaseOperation {
}
protected:
- void generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings) override;
+ void generate_glare(float *data, MemoryBuffer *input_tile, NodeGlare *settings) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.cc b/source/blender/compositor/operations/COM_GlareGhostOperation.cc
index 22c8767632e..930c723e94e 100644
--- a/source/blender/compositor/operations/COM_GlareGhostOperation.cc
+++ b/source/blender/compositor/operations/COM_GlareGhostOperation.cc
@@ -17,12 +17,11 @@
*/
#include "COM_GlareGhostOperation.h"
-#include "BLI_math.h"
#include "COM_FastGaussianBlurOperation.h"
namespace blender::compositor {
-static float smoothMask(float x, float y)
+static float smooth_mask(float x, float y)
{
float t;
x = 2.0f * x - 1.0f;
@@ -34,7 +33,9 @@ static float smoothMask(float x, float y)
return 0.0f;
}
-void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings)
+void GlareGhostOperation::generate_glare(float *data,
+ MemoryBuffer *input_tile,
+ NodeGlare *settings)
{
const int qt = 1 << settings->quality;
const float s1 = 4.0f / (float)qt, s2 = 2.0f * s1;
@@ -43,8 +44,8 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
float sc, isc, u, v, sm, s, t, ofs, scalef[64];
const float cmo = 1.0f - settings->colmod;
- MemoryBuffer gbuf(*inputTile);
- MemoryBuffer tbuf1(*inputTile);
+ MemoryBuffer gbuf(*input_tile);
+ MemoryBuffer tbuf1(*input_tile);
bool breaked = false;
@@ -52,7 +53,7 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
if (!breaked) {
FastGaussianBlurOperation::IIR_gauss(&tbuf1, s1, 1, 3);
}
- if (isBraked()) {
+ if (is_braked()) {
breaked = true;
}
if (!breaked) {
@@ -61,19 +62,19 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
MemoryBuffer tbuf2(tbuf1);
- if (isBraked()) {
+ if (is_braked()) {
breaked = true;
}
if (!breaked) {
FastGaussianBlurOperation::IIR_gauss(&tbuf2, s2, 0, 3);
}
- if (isBraked()) {
+ if (is_braked()) {
breaked = true;
}
if (!breaked) {
FastGaussianBlurOperation::IIR_gauss(&tbuf2, s2, 1, 3);
}
- if (isBraked()) {
+ if (is_braked()) {
breaked = true;
}
if (!breaked) {
@@ -101,59 +102,59 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
sc = 2.13;
isc = -0.97;
- for (y = 0; y < gbuf.getHeight() && (!breaked); y++) {
- v = ((float)y + 0.5f) / (float)gbuf.getHeight();
- for (x = 0; x < gbuf.getWidth(); x++) {
- u = ((float)x + 0.5f) / (float)gbuf.getWidth();
+ for (y = 0; y < gbuf.get_height() && (!breaked); y++) {
+ v = ((float)y + 0.5f) / (float)gbuf.get_height();
+ for (x = 0; x < gbuf.get_width(); x++) {
+ u = ((float)x + 0.5f) / (float)gbuf.get_width();
s = (u - 0.5f) * sc + 0.5f;
t = (v - 0.5f) * sc + 0.5f;
- tbuf1.readBilinear(c, s * gbuf.getWidth(), t * gbuf.getHeight());
- sm = smoothMask(s, t);
+ tbuf1.read_bilinear(c, s * gbuf.get_width(), t * gbuf.get_height());
+ sm = smooth_mask(s, t);
mul_v3_fl(c, sm);
s = (u - 0.5f) * isc + 0.5f;
t = (v - 0.5f) * isc + 0.5f;
- tbuf2.readBilinear(tc, s * gbuf.getWidth() - 0.5f, t * gbuf.getHeight() - 0.5f);
- sm = smoothMask(s, t);
+ tbuf2.read_bilinear(tc, s * gbuf.get_width() - 0.5f, t * gbuf.get_height() - 0.5f);
+ sm = smooth_mask(s, t);
madd_v3_v3fl(c, tc, sm);
- gbuf.writePixel(x, y, c);
+ gbuf.write_pixel(x, y, c);
}
- if (isBraked()) {
+ if (is_braked()) {
breaked = true;
}
}
- memset(tbuf1.getBuffer(),
+ memset(tbuf1.get_buffer(),
0,
- tbuf1.getWidth() * tbuf1.getHeight() * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float));
+ tbuf1.get_width() * tbuf1.get_height() * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float));
for (n = 1; n < settings->iter && (!breaked); n++) {
- for (y = 0; y < gbuf.getHeight() && (!breaked); y++) {
- v = ((float)y + 0.5f) / (float)gbuf.getHeight();
- for (x = 0; x < gbuf.getWidth(); x++) {
- u = ((float)x + 0.5f) / (float)gbuf.getWidth();
+ for (y = 0; y < gbuf.get_height() && (!breaked); y++) {
+ v = ((float)y + 0.5f) / (float)gbuf.get_height();
+ for (x = 0; x < gbuf.get_width(); x++) {
+ u = ((float)x + 0.5f) / (float)gbuf.get_width();
tc[0] = tc[1] = tc[2] = 0.0f;
for (p = 0; p < 4; p++) {
np = (n << 2) + p;
s = (u - 0.5f) * scalef[np] + 0.5f;
t = (v - 0.5f) * scalef[np] + 0.5f;
- gbuf.readBilinear(c, s * gbuf.getWidth() - 0.5f, t * gbuf.getHeight() - 0.5f);
+ gbuf.read_bilinear(c, s * gbuf.get_width() - 0.5f, t * gbuf.get_height() - 0.5f);
mul_v3_v3(c, cm[np]);
- sm = smoothMask(s, t) * 0.25f;
+ sm = smooth_mask(s, t) * 0.25f;
madd_v3_v3fl(tc, c, sm);
}
- tbuf1.addPixel(x, y, tc);
+ tbuf1.add_pixel(x, y, tc);
}
- if (isBraked()) {
+ if (is_braked()) {
breaked = true;
}
}
- memcpy(gbuf.getBuffer(),
- tbuf1.getBuffer(),
- tbuf1.getWidth() * tbuf1.getHeight() * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float));
+ memcpy(gbuf.get_buffer(),
+ tbuf1.get_buffer(),
+ tbuf1.get_width() * tbuf1.get_height() * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float));
}
memcpy(data,
- gbuf.getBuffer(),
- gbuf.getWidth() * gbuf.getHeight() * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float));
+ gbuf.get_buffer(),
+ gbuf.get_width() * gbuf.get_height() * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float));
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.h b/source/blender/compositor/operations/COM_GlareGhostOperation.h
index 60256d8e0ef..e84084c3f6e 100644
--- a/source/blender/compositor/operations/COM_GlareGhostOperation.h
+++ b/source/blender/compositor/operations/COM_GlareGhostOperation.h
@@ -31,7 +31,7 @@ class GlareGhostOperation : public GlareBaseOperation {
}
protected:
- void generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings) override;
+ void generate_glare(float *data, MemoryBuffer *input_tile, NodeGlare *settings) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc
index cc24a50a307..5d8dca055aa 100644
--- a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc
+++ b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc
@@ -20,26 +20,26 @@
namespace blender::compositor {
-void GlareSimpleStarOperation::generateGlare(float *data,
- MemoryBuffer *inputTile,
- NodeGlare *settings)
+void GlareSimpleStarOperation::generate_glare(float *data,
+ MemoryBuffer *input_tile,
+ NodeGlare *settings)
{
int i, x, y, ym, yp, xm, xp;
float c[4] = {0, 0, 0, 0}, tc[4] = {0, 0, 0, 0};
const float f1 = 1.0f - settings->fade;
const float f2 = (1.0f - f1) * 0.5f;
- MemoryBuffer tbuf1(*inputTile);
- MemoryBuffer tbuf2(*inputTile);
+ MemoryBuffer tbuf1(*input_tile);
+ MemoryBuffer tbuf2(*input_tile);
bool breaked = false;
for (i = 0; i < settings->iter && (!breaked); i++) {
// // (x || x-1, y-1) to (x || x+1, y+1)
// // F
- for (y = 0; y < this->getHeight() && (!breaked); y++) {
+ for (y = 0; y < this->get_height() && (!breaked); y++) {
ym = y - i;
yp = y + i;
- for (x = 0; x < this->getWidth(); x++) {
+ for (x = 0; x < this->get_width(); x++) {
xm = x - i;
xp = x + i;
tbuf1.read(c, x, y);
@@ -49,7 +49,7 @@ void GlareSimpleStarOperation::generateGlare(float *data,
tbuf1.read(tc, (settings->star_45 ? xp : x), yp);
madd_v3_v3fl(c, tc, f2);
c[3] = 1.0f;
- tbuf1.writePixel(x, y, c);
+ tbuf1.write_pixel(x, y, c);
tbuf2.read(c, x, y);
mul_v3_fl(c, f1);
@@ -58,17 +58,17 @@ void GlareSimpleStarOperation::generateGlare(float *data,
tbuf2.read(tc, xp, (settings->star_45 ? ym : y));
madd_v3_v3fl(c, tc, f2);
c[3] = 1.0f;
- tbuf2.writePixel(x, y, c);
+ tbuf2.write_pixel(x, y, c);
}
- if (isBraked()) {
+ if (is_braked()) {
breaked = true;
}
}
// // B
- for (y = this->getHeight() - 1; y >= 0 && (!breaked); y--) {
+ for (y = this->get_height() - 1; y >= 0 && (!breaked); y--) {
ym = y - i;
yp = y + i;
- for (x = this->getWidth() - 1; x >= 0; x--) {
+ for (x = this->get_width() - 1; x >= 0; x--) {
xm = x - i;
xp = x + i;
tbuf1.read(c, x, y);
@@ -78,7 +78,7 @@ void GlareSimpleStarOperation::generateGlare(float *data,
tbuf1.read(tc, (settings->star_45 ? xp : x), yp);
madd_v3_v3fl(c, tc, f2);
c[3] = 1.0f;
- tbuf1.writePixel(x, y, c);
+ tbuf1.write_pixel(x, y, c);
tbuf2.read(c, x, y);
mul_v3_fl(c, f1);
@@ -87,16 +87,16 @@ void GlareSimpleStarOperation::generateGlare(float *data,
tbuf2.read(tc, xp, (settings->star_45 ? ym : y));
madd_v3_v3fl(c, tc, f2);
c[3] = 1.0f;
- tbuf2.writePixel(x, y, c);
+ tbuf2.write_pixel(x, y, c);
}
- if (isBraked()) {
+ if (is_braked()) {
breaked = true;
}
}
}
- for (i = 0; i < this->getWidth() * this->getHeight() * 4; i++) {
- data[i] = tbuf1.getBuffer()[i] + tbuf2.getBuffer()[i];
+ for (i = 0; i < this->get_width() * this->get_height() * 4; i++) {
+ data[i] = tbuf1.get_buffer()[i] + tbuf2.get_buffer()[i];
}
}
diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.h b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.h
index 4a074f53e7b..be162bbda44 100644
--- a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.h
+++ b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.h
@@ -31,7 +31,7 @@ class GlareSimpleStarOperation : public GlareBaseOperation {
}
protected:
- void generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings) override;
+ void generate_glare(float *data, MemoryBuffer *input_tile, NodeGlare *settings) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cc b/source/blender/compositor/operations/COM_GlareStreaksOperation.cc
index 5ca64b02586..f4d9b588917 100644
--- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cc
+++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cc
@@ -17,26 +17,25 @@
*/
#include "COM_GlareStreaksOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
-void GlareStreaksOperation::generateGlare(float *data,
- MemoryBuffer *inputTile,
- NodeGlare *settings)
+void GlareStreaksOperation::generate_glare(float *data,
+ MemoryBuffer *input_tile,
+ NodeGlare *settings)
{
int x, y, n;
unsigned int nump = 0;
float c1[4], c2[4], c3[4], c4[4];
float a, ang = DEG2RADF(360.0f) / (float)settings->streaks;
- int size = inputTile->getWidth() * inputTile->getHeight();
+ int size = input_tile->get_width() * input_tile->get_height();
int size4 = size * 4;
bool breaked = false;
- MemoryBuffer tsrc(*inputTile);
- MemoryBuffer tdst(DataType::Color, inputTile->get_rect());
+ MemoryBuffer tsrc(*input_tile);
+ MemoryBuffer tdst(DataType::Color, input_tile->get_rect());
tdst.clear();
memset(data, 0, size4 * sizeof(float));
@@ -51,9 +50,9 @@ void GlareStreaksOperation::generateGlare(float *data,
/* Color-modulation amount relative to current pass. */
const float cmo = 1.0f - (float)pow((double)settings->colmod, (double)n + 1);
- float *tdstcol = tdst.getBuffer();
- for (y = 0; y < tsrc.getHeight() && (!breaked); y++) {
- for (x = 0; x < tsrc.getWidth(); x++, tdstcol += 4) {
+ float *tdstcol = tdst.get_buffer();
+ for (y = 0; y < tsrc.get_height() && (!breaked); y++) {
+ for (x = 0; x < tsrc.get_width(); x++, tdstcol += 4) {
/* First pass no offset, always same for every pass, exact copy,
* otherwise results in uneven brightness, only need once. */
if (n == 0) {
@@ -62,9 +61,9 @@ void GlareStreaksOperation::generateGlare(float *data,
else {
c1[0] = c1[1] = c1[2] = 0;
}
- tsrc.readBilinear(c2, x + vxp, y + vyp);
- tsrc.readBilinear(c3, x + vxp * 2.0f, y + vyp * 2.0f);
- tsrc.readBilinear(c4, x + vxp * 3.0f, y + vyp * 3.0f);
+ tsrc.read_bilinear(c2, x + vxp, y + vyp);
+ tsrc.read_bilinear(c3, x + vxp * 2.0f, y + vyp * 2.0f);
+ tsrc.read_bilinear(c4, x + vxp * 3.0f, y + vyp * 3.0f);
/* Modulate color to look vaguely similar to a color spectrum. */
c2[1] *= cmo;
c2[2] *= cmo;
@@ -80,14 +79,14 @@ void GlareStreaksOperation::generateGlare(float *data,
tdstcol[2] = 0.5f * (tdstcol[2] + c1[2] + wt * (c2[2] + wt * (c3[2] + wt * c4[2])));
tdstcol[3] = 1.0f;
}
- if (isBraked()) {
+ if (is_braked()) {
breaked = true;
}
}
- memcpy(tsrc.getBuffer(), tdst.getBuffer(), sizeof(float) * size4);
+ memcpy(tsrc.get_buffer(), tdst.get_buffer(), sizeof(float) * size4);
}
- float *sourcebuffer = tsrc.getBuffer();
+ float *sourcebuffer = tsrc.get_buffer();
float factor = 1.0f / (float)(6 - settings->iter);
for (int i = 0; i < size4; i += 4) {
madd_v3_v3fl(&data[i], &sourcebuffer[i], factor);
@@ -95,7 +94,7 @@ void GlareStreaksOperation::generateGlare(float *data,
}
tdst.clear();
- memcpy(tsrc.getBuffer(), inputTile->getBuffer(), sizeof(float) * size4);
+ memcpy(tsrc.get_buffer(), input_tile->get_buffer(), sizeof(float) * size4);
nump++;
}
}
diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.h b/source/blender/compositor/operations/COM_GlareStreaksOperation.h
index 487c910960a..bad73687afd 100644
--- a/source/blender/compositor/operations/COM_GlareStreaksOperation.h
+++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.h
@@ -31,7 +31,7 @@ class GlareStreaksOperation : public GlareBaseOperation {
}
protected:
- void generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings) override;
+ void generate_glare(float *data, MemoryBuffer *input_tile, NodeGlare *settings) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.cc b/source/blender/compositor/operations/COM_GlareThresholdOperation.cc
index 1bf7cf5ae07..0538b4e48a0 100644
--- a/source/blender/compositor/operations/COM_GlareThresholdOperation.cc
+++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.cc
@@ -17,7 +17,6 @@
*/
#include "COM_GlareThresholdOperation.h"
-#include "BLI_math.h"
#include "IMB_colormanagement.h"
@@ -25,33 +24,33 @@ namespace blender::compositor {
GlareThresholdOperation::GlareThresholdOperation()
{
- this->addInputSocket(DataType::Color, ResizeMode::FitAny);
- this->addOutputSocket(DataType::Color);
- this->m_inputProgram = nullptr;
+ this->add_input_socket(DataType::Color, ResizeMode::FitAny);
+ this->add_output_socket(DataType::Color);
+ input_program_ = nullptr;
}
void GlareThresholdOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
NodeOperation::determine_canvas(preferred_area, r_area);
- const int width = BLI_rcti_size_x(&r_area) / (1 << this->m_settings->quality);
- const int height = BLI_rcti_size_y(&r_area) / (1 << this->m_settings->quality);
+ const int width = BLI_rcti_size_x(&r_area) / (1 << settings_->quality);
+ const int height = BLI_rcti_size_y(&r_area) / (1 << settings_->quality);
r_area.xmax = r_area.xmin + width;
r_area.ymax = r_area.ymin + height;
}
-void GlareThresholdOperation::initExecution()
+void GlareThresholdOperation::init_execution()
{
- this->m_inputProgram = this->getInputSocketReader(0);
+ input_program_ = this->get_input_socket_reader(0);
}
-void GlareThresholdOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void GlareThresholdOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- const float threshold = this->m_settings->threshold;
+ const float threshold = settings_->threshold;
- this->m_inputProgram->readSampled(output, x, y, sampler);
+ input_program_->read_sampled(output, x, y, sampler);
if (IMB_colormanagement_get_luminance(output) >= threshold) {
output[0] -= threshold;
output[1] -= threshold;
@@ -66,16 +65,16 @@ void GlareThresholdOperation::executePixelSampled(float output[4],
}
}
-void GlareThresholdOperation::deinitExecution()
+void GlareThresholdOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
+ input_program_ = nullptr;
}
void GlareThresholdOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- const float threshold = this->m_settings->threshold;
+ const float threshold = settings_->threshold;
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
const float *color = it.in(0);
if (IMB_colormanagement_get_luminance(color) >= threshold) {
diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.h b/source/blender/compositor/operations/COM_GlareThresholdOperation.h
index 44f2d717c0e..41eac34375d 100644
--- a/source/blender/compositor/operations/COM_GlareThresholdOperation.h
+++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.h
@@ -26,14 +26,14 @@ namespace blender::compositor {
class GlareThresholdOperation : public MultiThreadedOperation {
private:
/**
- * \brief Cached reference to the inputProgram
+ * \brief Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
+ SocketReader *input_program_;
/**
* \brief settings of the glare node.
*/
- NodeGlare *m_settings;
+ NodeGlare *settings_;
public:
GlareThresholdOperation();
@@ -41,21 +41,21 @@ class GlareThresholdOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setGlareSettings(NodeGlare *settings)
+ void set_glare_settings(NodeGlare *settings)
{
- this->m_settings = settings;
+ settings_ = settings;
}
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
diff --git a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc
index 5ae868c5964..d1fad29498a 100644
--- a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc
+++ b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc
@@ -18,7 +18,7 @@
#include "COM_HueSaturationValueCorrectOperation.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BKE_colortools.h"
@@ -26,36 +26,36 @@ namespace blender::compositor {
HueSaturationValueCorrectOperation::HueSaturationValueCorrectOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
- this->m_inputProgram = nullptr;
+ input_program_ = nullptr;
}
-void HueSaturationValueCorrectOperation::initExecution()
+void HueSaturationValueCorrectOperation::init_execution()
{
- CurveBaseOperation::initExecution();
- this->m_inputProgram = this->getInputSocketReader(0);
+ CurveBaseOperation::init_execution();
+ input_program_ = this->get_input_socket_reader(0);
}
-void HueSaturationValueCorrectOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void HueSaturationValueCorrectOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float hsv[4], f;
- this->m_inputProgram->readSampled(hsv, x, y, sampler);
+ input_program_->read_sampled(hsv, x, y, sampler);
/* adjust hue, scaling returned default 0.5 up to 1 */
- f = BKE_curvemapping_evaluateF(this->m_curveMapping, 0, hsv[0]);
+ f = BKE_curvemapping_evaluateF(curve_mapping_, 0, hsv[0]);
hsv[0] += f - 0.5f;
/* adjust saturation, scaling returned default 0.5 up to 1 */
- f = BKE_curvemapping_evaluateF(this->m_curveMapping, 1, hsv[0]);
+ f = BKE_curvemapping_evaluateF(curve_mapping_, 1, hsv[0]);
hsv[1] *= (f * 2.0f);
/* adjust value, scaling returned default 0.5 up to 1 */
- f = BKE_curvemapping_evaluateF(this->m_curveMapping, 2, hsv[0]);
+ f = BKE_curvemapping_evaluateF(curve_mapping_, 2, hsv[0]);
hsv[2] *= (f * 2.0f);
hsv[0] = hsv[0] - floorf(hsv[0]); /* mod 1.0 */
@@ -67,10 +67,10 @@ void HueSaturationValueCorrectOperation::executePixelSampled(float output[4],
output[3] = hsv[3];
}
-void HueSaturationValueCorrectOperation::deinitExecution()
+void HueSaturationValueCorrectOperation::deinit_execution()
{
- CurveBaseOperation::deinitExecution();
- this->m_inputProgram = nullptr;
+ CurveBaseOperation::deinit_execution();
+ input_program_ = nullptr;
}
void HueSaturationValueCorrectOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -82,15 +82,15 @@ void HueSaturationValueCorrectOperation::update_memory_buffer_partial(MemoryBuff
copy_v4_v4(hsv, it.in(0));
/* Adjust hue, scaling returned default 0.5 up to 1. */
- float f = BKE_curvemapping_evaluateF(this->m_curveMapping, 0, hsv[0]);
+ float f = BKE_curvemapping_evaluateF(curve_mapping_, 0, hsv[0]);
hsv[0] += f - 0.5f;
/* Adjust saturation, scaling returned default 0.5 up to 1. */
- f = BKE_curvemapping_evaluateF(this->m_curveMapping, 1, hsv[0]);
+ f = BKE_curvemapping_evaluateF(curve_mapping_, 1, hsv[0]);
hsv[1] *= (f * 2.0f);
/* Adjust value, scaling returned default 0.5 up to 1. */
- f = BKE_curvemapping_evaluateF(this->m_curveMapping, 2, hsv[0]);
+ f = BKE_curvemapping_evaluateF(curve_mapping_, 2, hsv[0]);
hsv[2] *= (f * 2.0f);
hsv[0] = hsv[0] - floorf(hsv[0]); /* Mod 1.0. */
diff --git a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.h b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.h
index 6c1b66aba1f..ac64d31e494 100644
--- a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.h
+++ b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.h
@@ -26,9 +26,9 @@ namespace blender::compositor {
class HueSaturationValueCorrectOperation : public CurveBaseOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
+ SocketReader *input_program_;
public:
HueSaturationValueCorrectOperation();
@@ -36,17 +36,17 @@ class HueSaturationValueCorrectOperation : public CurveBaseOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.cc b/source/blender/compositor/operations/COM_IDMaskOperation.cc
index bb11ac8b1be..503cbf5eb31 100644
--- a/source/blender/compositor/operations/COM_IDMaskOperation.cc
+++ b/source/blender/compositor/operations/COM_IDMaskOperation.cc
@@ -22,25 +22,25 @@ namespace blender::compositor {
IDMaskOperation::IDMaskOperation()
{
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
- this->flags.complex = true;
- flags.can_be_constant = true;
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
+ flags_.complex = true;
+ flags_.can_be_constant = true;
}
-void *IDMaskOperation::initializeTileData(rcti *rect)
+void *IDMaskOperation::initialize_tile_data(rcti *rect)
{
- void *buffer = getInputOperation(0)->initializeTileData(rect);
+ void *buffer = get_input_operation(0)->initialize_tile_data(rect);
return buffer;
}
-void IDMaskOperation::executePixel(float output[4], int x, int y, void *data)
+void IDMaskOperation::execute_pixel(float output[4], int x, int y, void *data)
{
MemoryBuffer *input_buffer = (MemoryBuffer *)data;
- const int buffer_width = input_buffer->getWidth();
- float *buffer = input_buffer->getBuffer();
+ const int buffer_width = input_buffer->get_width();
+ float *buffer = input_buffer->get_buffer();
int buffer_index = (y * buffer_width + x);
- output[0] = (roundf(buffer[buffer_index]) == this->m_objectIndex) ? 1.0f : 0.0f;
+ output[0] = (roundf(buffer[buffer_index]) == object_index_) ? 1.0f : 0.0f;
}
void IDMaskOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -54,7 +54,7 @@ void IDMaskOperation::update_memory_buffer_partial(MemoryBuffer *output,
const float *in = input->get_elem(area.xmin, y);
const float *row_end = out + width * output->elem_stride;
while (out < row_end) {
- out[0] = (roundf(in[0]) == m_objectIndex) ? 1.0f : 0.0f;
+ out[0] = (roundf(in[0]) == object_index_) ? 1.0f : 0.0f;
in += input->elem_stride;
out += output->elem_stride;
}
diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.h b/source/blender/compositor/operations/COM_IDMaskOperation.h
index c2e13641b46..3a7ceec8c49 100644
--- a/source/blender/compositor/operations/COM_IDMaskOperation.h
+++ b/source/blender/compositor/operations/COM_IDMaskOperation.h
@@ -24,17 +24,17 @@ namespace blender::compositor {
class IDMaskOperation : public MultiThreadedOperation {
private:
- float m_objectIndex;
+ float object_index_;
public:
IDMaskOperation();
- void *initializeTileData(rcti *rect) override;
- void executePixel(float output[4], int x, int y, void *data) override;
+ void *initialize_tile_data(rcti *rect) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
- void setObjectIndex(float objectIndex)
+ void set_object_index(float object_index)
{
- this->m_objectIndex = objectIndex;
+ object_index_ = object_index;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_ImageOperation.cc b/source/blender/compositor/operations/COM_ImageOperation.cc
index ff389093f5a..e32343cfbf2 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.cc
+++ b/source/blender/compositor/operations/COM_ImageOperation.cc
@@ -18,94 +18,87 @@
#include "COM_ImageOperation.h"
-#include "BKE_image.h"
#include "BKE_scene.h"
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-#include "DNA_image_types.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-#include "RE_pipeline.h"
-#include "RE_texture.h"
-
namespace blender::compositor {
BaseImageOperation::BaseImageOperation()
{
- this->m_image = nullptr;
- this->m_buffer = nullptr;
- this->m_imageFloatBuffer = nullptr;
- this->m_imageByteBuffer = nullptr;
- this->m_imageUser = nullptr;
- this->m_imagewidth = 0;
- this->m_imageheight = 0;
- this->m_framenumber = 0;
- this->m_depthBuffer = nullptr;
+ image_ = nullptr;
+ buffer_ = nullptr;
+ image_float_buffer_ = nullptr;
+ image_byte_buffer_ = nullptr;
+ image_user_ = nullptr;
+ imagewidth_ = 0;
+ imageheight_ = 0;
+ framenumber_ = 0;
+ image_depth_buffer_ = nullptr;
depth_buffer_ = nullptr;
- this->m_numberOfChannels = 0;
- this->m_rd = nullptr;
- this->m_viewName = nullptr;
+ number_of_channels_ = 0;
+ rd_ = nullptr;
+ view_name_ = nullptr;
}
ImageOperation::ImageOperation() : BaseImageOperation()
{
- this->addOutputSocket(DataType::Color);
+ this->add_output_socket(DataType::Color);
}
ImageAlphaOperation::ImageAlphaOperation() : BaseImageOperation()
{
- this->addOutputSocket(DataType::Value);
+ this->add_output_socket(DataType::Value);
}
ImageDepthOperation::ImageDepthOperation() : BaseImageOperation()
{
- this->addOutputSocket(DataType::Value);
+ this->add_output_socket(DataType::Value);
}
-ImBuf *BaseImageOperation::getImBuf()
+ImBuf *BaseImageOperation::get_im_buf()
{
ImBuf *ibuf;
- ImageUser iuser = *this->m_imageUser;
+ ImageUser iuser = *image_user_;
- if (this->m_image == nullptr) {
+ if (image_ == nullptr) {
return nullptr;
}
/* local changes to the original ImageUser */
- if (BKE_image_is_multilayer(this->m_image) == false) {
- iuser.multi_index = BKE_scene_multiview_view_id_get(this->m_rd, this->m_viewName);
+ if (BKE_image_is_multilayer(image_) == false) {
+ iuser.multi_index = BKE_scene_multiview_view_id_get(rd_, view_name_);
}
- ibuf = BKE_image_acquire_ibuf(this->m_image, &iuser, nullptr);
+ ibuf = BKE_image_acquire_ibuf(image_, &iuser, nullptr);
if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) {
- BKE_image_release_ibuf(this->m_image, ibuf, nullptr);
+ BKE_image_release_ibuf(image_, ibuf, nullptr);
return nullptr;
}
return ibuf;
}
-void BaseImageOperation::initExecution()
+void BaseImageOperation::init_execution()
{
- ImBuf *stackbuf = getImBuf();
- this->m_buffer = stackbuf;
+ ImBuf *stackbuf = get_im_buf();
+ buffer_ = stackbuf;
if (stackbuf) {
- this->m_imageFloatBuffer = stackbuf->rect_float;
- this->m_imageByteBuffer = stackbuf->rect;
- this->m_depthBuffer = stackbuf->zbuf_float;
+ image_float_buffer_ = stackbuf->rect_float;
+ image_byte_buffer_ = stackbuf->rect;
+ image_depth_buffer_ = stackbuf->zbuf_float;
if (stackbuf->zbuf_float) {
depth_buffer_ = new MemoryBuffer(stackbuf->zbuf_float, 1, stackbuf->x, stackbuf->y);
}
- this->m_imagewidth = stackbuf->x;
- this->m_imageheight = stackbuf->y;
- this->m_numberOfChannels = stackbuf->channels;
+ imagewidth_ = stackbuf->x;
+ imageheight_ = stackbuf->y;
+ number_of_channels_ = stackbuf->channels;
}
}
-void BaseImageOperation::deinitExecution()
+void BaseImageOperation::deinit_execution()
{
- this->m_imageFloatBuffer = nullptr;
- this->m_imageByteBuffer = nullptr;
- BKE_image_release_ibuf(this->m_image, this->m_buffer, nullptr);
+ image_float_buffer_ = nullptr;
+ image_byte_buffer_ = nullptr;
+ BKE_image_release_ibuf(image_, buffer_, nullptr);
if (depth_buffer_) {
delete depth_buffer_;
depth_buffer_ = nullptr;
@@ -114,7 +107,7 @@ void BaseImageOperation::deinitExecution()
void BaseImageOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area)
{
- ImBuf *stackbuf = getImBuf();
+ ImBuf *stackbuf = get_im_buf();
r_area = COM_AREA_NONE;
@@ -122,10 +115,10 @@ void BaseImageOperation::determine_canvas(const rcti &UNUSED(preferred_area), rc
BLI_rcti_init(&r_area, 0, stackbuf->x, 0, stackbuf->y);
}
- BKE_image_release_ibuf(this->m_image, stackbuf, nullptr);
+ BKE_image_release_ibuf(image_, stackbuf, nullptr);
}
-static void sampleImageAtLocation(
+static void sample_image_at_location(
ImBuf *ibuf, float x, float y, PixelSampler sampler, bool make_linear_rgb, float color[4])
{
if (ibuf->rect_float) {
@@ -161,17 +154,17 @@ static void sampleImageAtLocation(
}
}
-void ImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void ImageOperation::execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler)
{
int ix = x, iy = y;
- if (this->m_imageFloatBuffer == nullptr && this->m_imageByteBuffer == nullptr) {
+ if (image_float_buffer_ == nullptr && image_byte_buffer_ == nullptr) {
zero_v4(output);
}
- else if (ix < 0 || iy < 0 || ix >= this->m_buffer->x || iy >= this->m_buffer->y) {
+ else if (ix < 0 || iy < 0 || ix >= buffer_->x || iy >= buffer_->y) {
zero_v4(output);
}
else {
- sampleImageAtLocation(this->m_buffer, x, y, sampler, true, output);
+ sample_image_at_location(buffer_, x, y, sampler, true, output);
}
}
@@ -179,22 +172,22 @@ void ImageOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> UNUSED(inputs))
{
- output->copy_from(m_buffer, area, true);
+ output->copy_from(buffer_, area, true);
}
-void ImageAlphaOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ImageAlphaOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float tempcolor[4];
- if (this->m_imageFloatBuffer == nullptr && this->m_imageByteBuffer == nullptr) {
+ if (image_float_buffer_ == nullptr && image_byte_buffer_ == nullptr) {
output[0] = 0.0f;
}
else {
tempcolor[3] = 1.0f;
- sampleImageAtLocation(this->m_buffer, x, y, sampler, false, tempcolor);
+ sample_image_at_location(buffer_, x, y, sampler, false, tempcolor);
output[0] = tempcolor[3];
}
}
@@ -203,24 +196,24 @@ void ImageAlphaOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> UNUSED(inputs))
{
- output->copy_from(m_buffer, area, 3, COM_DATA_TYPE_VALUE_CHANNELS, 0);
+ output->copy_from(buffer_, area, 3, COM_DATA_TYPE_VALUE_CHANNELS, 0);
}
-void ImageDepthOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler /*sampler*/)
+void ImageDepthOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
- if (this->m_depthBuffer == nullptr) {
+ if (image_depth_buffer_ == nullptr) {
output[0] = 0.0f;
}
else {
- if (x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight()) {
+ if (x < 0 || y < 0 || x >= this->get_width() || y >= this->get_height()) {
output[0] = 0.0f;
}
else {
- int offset = y * getWidth() + x;
- output[0] = this->m_depthBuffer[offset];
+ int offset = y * get_width() + x;
+ output[0] = image_depth_buffer_[offset];
}
}
}
diff --git a/source/blender/compositor/operations/COM_ImageOperation.h b/source/blender/compositor/operations/COM_ImageOperation.h
index e2fdfbf6f81..054398604b6 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.h
+++ b/source/blender/compositor/operations/COM_ImageOperation.h
@@ -34,21 +34,21 @@ namespace blender::compositor {
*/
class BaseImageOperation : public MultiThreadedOperation {
protected:
- ImBuf *m_buffer;
- Image *m_image;
- ImageUser *m_imageUser;
+ ImBuf *buffer_;
+ Image *image_;
+ ImageUser *image_user_;
/* TODO: Remove raw buffers when removing Tiled implementation. */
- float *m_imageFloatBuffer;
- unsigned int *m_imageByteBuffer;
- float *m_depthBuffer;
+ float *image_float_buffer_;
+ unsigned int *image_byte_buffer_;
+ float *image_depth_buffer_;
MemoryBuffer *depth_buffer_;
- int m_imageheight;
- int m_imagewidth;
- int m_framenumber;
- int m_numberOfChannels;
- const RenderData *m_rd;
- const char *m_viewName;
+ int imageheight_;
+ int imagewidth_;
+ int framenumber_;
+ int number_of_channels_;
+ const RenderData *rd_;
+ const char *view_name_;
BaseImageOperation();
/**
@@ -56,30 +56,30 @@ class BaseImageOperation : public MultiThreadedOperation {
*/
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
- virtual ImBuf *getImBuf();
+ virtual ImBuf *get_im_buf();
public:
- void initExecution() override;
- void deinitExecution() override;
- void setImage(Image *image)
+ void init_execution() override;
+ void deinit_execution() override;
+ void set_image(Image *image)
{
- this->m_image = image;
+ image_ = image;
}
- void setImageUser(ImageUser *imageuser)
+ void set_image_user(ImageUser *imageuser)
{
- this->m_imageUser = imageuser;
+ image_user_ = imageuser;
}
- void setRenderData(const RenderData *rd)
+ void set_render_data(const RenderData *rd)
{
- this->m_rd = rd;
+ rd_ = rd;
}
- void setViewName(const char *viewName)
+ void set_view_name(const char *view_name)
{
- this->m_viewName = viewName;
+ view_name_ = view_name;
}
- void setFramenumber(int framenumber)
+ void set_framenumber(int framenumber)
{
- this->m_framenumber = framenumber;
+ framenumber_ = framenumber;
}
};
class ImageOperation : public BaseImageOperation {
@@ -88,7 +88,7 @@ class ImageOperation : public BaseImageOperation {
* Constructor
*/
ImageOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
@@ -100,7 +100,7 @@ class ImageAlphaOperation : public BaseImageOperation {
* Constructor
*/
ImageAlphaOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
@@ -112,7 +112,7 @@ class ImageDepthOperation : public BaseImageOperation {
* Constructor
*/
ImageDepthOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_InpaintOperation.cc b/source/blender/compositor/operations/COM_InpaintOperation.cc
index 5d440dd7d76..83bc81d35fc 100644
--- a/source/blender/compositor/operations/COM_InpaintOperation.cc
+++ b/source/blender/compositor/operations/COM_InpaintOperation.cc
@@ -19,44 +19,40 @@
#include "MEM_guardedalloc.h"
#include "COM_InpaintOperation.h"
-#include "COM_OpenCLDevice.h"
-
-#include "BLI_math.h"
namespace blender::compositor {
#define ASSERT_XY_RANGE(x, y) \
- BLI_assert(x >= 0 && x < this->getWidth() && y >= 0 && y < this->getHeight())
+ BLI_assert(x >= 0 && x < this->get_width() && y >= 0 && y < this->get_height())
-/* In-paint (simple convolve using average of known pixels). */
InpaintSimpleOperation::InpaintSimpleOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
- this->flags.complex = true;
- this->m_inputImageProgram = nullptr;
- this->m_pixelorder = nullptr;
- this->m_manhattan_distance = nullptr;
- this->m_cached_buffer = nullptr;
- this->m_cached_buffer_ready = false;
- flags.is_fullframe_operation = true;
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ flags_.complex = true;
+ input_image_program_ = nullptr;
+ pixelorder_ = nullptr;
+ manhattan_distance_ = nullptr;
+ cached_buffer_ = nullptr;
+ cached_buffer_ready_ = false;
+ flags_.is_fullframe_operation = true;
}
-void InpaintSimpleOperation::initExecution()
+void InpaintSimpleOperation::init_execution()
{
- this->m_inputImageProgram = this->getInputSocketReader(0);
+ input_image_program_ = this->get_input_socket_reader(0);
- this->m_pixelorder = nullptr;
- this->m_manhattan_distance = nullptr;
- this->m_cached_buffer = nullptr;
- this->m_cached_buffer_ready = false;
+ pixelorder_ = nullptr;
+ manhattan_distance_ = nullptr;
+ cached_buffer_ = nullptr;
+ cached_buffer_ready_ = false;
- this->initMutex();
+ this->init_mutex();
}
void InpaintSimpleOperation::clamp_xy(int &x, int &y)
{
- int width = this->getWidth();
- int height = this->getHeight();
+ int width = this->get_width();
+ int height = this->get_height();
if (x < 0) {
x = 0;
@@ -75,32 +71,32 @@ void InpaintSimpleOperation::clamp_xy(int &x, int &y)
float *InpaintSimpleOperation::get_pixel(int x, int y)
{
- int width = this->getWidth();
+ int width = this->get_width();
ASSERT_XY_RANGE(x, y);
- return &this->m_cached_buffer[y * width * COM_DATA_TYPE_COLOR_CHANNELS +
- x * COM_DATA_TYPE_COLOR_CHANNELS];
+ return &cached_buffer_[y * width * COM_DATA_TYPE_COLOR_CHANNELS +
+ x * COM_DATA_TYPE_COLOR_CHANNELS];
}
int InpaintSimpleOperation::mdist(int x, int y)
{
- int width = this->getWidth();
+ int width = this->get_width();
ASSERT_XY_RANGE(x, y);
- return this->m_manhattan_distance[y * width + x];
+ return manhattan_distance_[y * width + x];
}
bool InpaintSimpleOperation::next_pixel(int &x, int &y, int &curr, int iters)
{
- int width = this->getWidth();
+ int width = this->get_width();
- if (curr >= this->m_area_size) {
+ if (curr >= area_size_) {
return false;
}
- int r = this->m_pixelorder[curr++];
+ int r = pixelorder_[curr++];
x = r % width;
y = r / width;
@@ -114,10 +110,9 @@ bool InpaintSimpleOperation::next_pixel(int &x, int &y, int &curr, int iters)
void InpaintSimpleOperation::calc_manhattan_distance()
{
- int width = this->getWidth();
- int height = this->getHeight();
- short *m = this->m_manhattan_distance = (short *)MEM_mallocN(sizeof(short) * width * height,
- __func__);
+ int width = this->get_width();
+ int height = this->get_height();
+ short *m = manhattan_distance_ = (short *)MEM_mallocN(sizeof(short) * width * height, __func__);
int *offsets;
offsets = (int *)MEM_callocN(sizeof(int) * (width + height + 1),
@@ -163,12 +158,12 @@ void InpaintSimpleOperation::calc_manhattan_distance()
offsets[i] += offsets[i - 1];
}
- this->m_area_size = offsets[width + height];
- this->m_pixelorder = (int *)MEM_mallocN(sizeof(int) * this->m_area_size, __func__);
+ area_size_ = offsets[width + height];
+ pixelorder_ = (int *)MEM_mallocN(sizeof(int) * area_size_, __func__);
for (int i = 0; i < width * height; i++) {
if (m[i] > 0) {
- this->m_pixelorder[offsets[m[i] - 1]++] = i;
+ pixelorder_[offsets[m[i] - 1]++] = i;
}
}
@@ -217,74 +212,73 @@ void InpaintSimpleOperation::pix_step(int x, int y)
}
}
-void *InpaintSimpleOperation::initializeTileData(rcti *rect)
+void *InpaintSimpleOperation::initialize_tile_data(rcti *rect)
{
- if (this->m_cached_buffer_ready) {
- return this->m_cached_buffer;
+ if (cached_buffer_ready_) {
+ return cached_buffer_;
}
- lockMutex();
- if (!this->m_cached_buffer_ready) {
- MemoryBuffer *buf = (MemoryBuffer *)this->m_inputImageProgram->initializeTileData(rect);
- this->m_cached_buffer = (float *)MEM_dupallocN(buf->getBuffer());
+ lock_mutex();
+ if (!cached_buffer_ready_) {
+ MemoryBuffer *buf = (MemoryBuffer *)input_image_program_->initialize_tile_data(rect);
+ cached_buffer_ = (float *)MEM_dupallocN(buf->get_buffer());
this->calc_manhattan_distance();
int curr = 0;
int x, y;
- while (this->next_pixel(x, y, curr, this->m_iterations)) {
+ while (this->next_pixel(x, y, curr, iterations_)) {
this->pix_step(x, y);
}
- this->m_cached_buffer_ready = true;
+ cached_buffer_ready_ = true;
}
- unlockMutex();
- return this->m_cached_buffer;
+ unlock_mutex();
+ return cached_buffer_;
}
-void InpaintSimpleOperation::executePixel(float output[4], int x, int y, void * /*data*/)
+void InpaintSimpleOperation::execute_pixel(float output[4], int x, int y, void * /*data*/)
{
this->clamp_xy(x, y);
copy_v4_v4(output, this->get_pixel(x, y));
}
-void InpaintSimpleOperation::deinitExecution()
+void InpaintSimpleOperation::deinit_execution()
{
- this->m_inputImageProgram = nullptr;
- this->deinitMutex();
- if (this->m_cached_buffer) {
- MEM_freeN(this->m_cached_buffer);
- this->m_cached_buffer = nullptr;
+ input_image_program_ = nullptr;
+ this->deinit_mutex();
+ if (cached_buffer_) {
+ MEM_freeN(cached_buffer_);
+ cached_buffer_ = nullptr;
}
- if (this->m_pixelorder) {
- MEM_freeN(this->m_pixelorder);
- this->m_pixelorder = nullptr;
+ if (pixelorder_) {
+ MEM_freeN(pixelorder_);
+ pixelorder_ = nullptr;
}
- if (this->m_manhattan_distance) {
- MEM_freeN(this->m_manhattan_distance);
- this->m_manhattan_distance = nullptr;
+ if (manhattan_distance_) {
+ MEM_freeN(manhattan_distance_);
+ manhattan_distance_ = nullptr;
}
- this->m_cached_buffer_ready = false;
+ cached_buffer_ready_ = false;
}
-bool InpaintSimpleOperation::determineDependingAreaOfInterest(rcti * /*input*/,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool InpaintSimpleOperation::determine_depending_area_of_interest(
+ rcti * /*input*/, ReadBufferOperation *read_operation, rcti *output)
{
- if (this->m_cached_buffer_ready) {
+ if (cached_buffer_ready_) {
return false;
}
- rcti newInput;
+ rcti new_input;
- newInput.xmax = getWidth();
- newInput.xmin = 0;
- newInput.ymax = getHeight();
- newInput.ymin = 0;
+ new_input.xmax = get_width();
+ new_input.xmin = 0;
+ new_input.ymax = get_height();
+ new_input.ymin = 0;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void InpaintSimpleOperation::get_area_of_interest(const int input_idx,
@@ -302,28 +296,28 @@ void InpaintSimpleOperation::update_memory_buffer(MemoryBuffer *output,
{
/* TODO(manzanilla): once tiled implementation is removed, run multi-threaded where possible. */
MemoryBuffer *input = inputs[0];
- if (!m_cached_buffer_ready) {
+ if (!cached_buffer_ready_) {
if (input->is_a_single_elem()) {
MemoryBuffer *tmp = input->inflate();
- m_cached_buffer = tmp->release_ownership_buffer();
+ cached_buffer_ = tmp->release_ownership_buffer();
delete tmp;
}
else {
- m_cached_buffer = (float *)MEM_dupallocN(input->getBuffer());
+ cached_buffer_ = (float *)MEM_dupallocN(input->get_buffer());
}
this->calc_manhattan_distance();
int curr = 0;
int x, y;
- while (this->next_pixel(x, y, curr, this->m_iterations)) {
+ while (this->next_pixel(x, y, curr, iterations_)) {
this->pix_step(x, y);
}
- m_cached_buffer_ready = true;
+ cached_buffer_ready_ = true;
}
- const int num_channels = COM_data_type_num_channels(getOutputSocket()->getDataType());
- MemoryBuffer buf(m_cached_buffer, num_channels, input->getWidth(), input->getHeight());
+ const int num_channels = COM_data_type_num_channels(get_output_socket()->get_data_type());
+ MemoryBuffer buf(cached_buffer_, num_channels, input->get_width(), input->get_height());
output->copy_from(&buf, area);
}
diff --git a/source/blender/compositor/operations/COM_InpaintOperation.h b/source/blender/compositor/operations/COM_InpaintOperation.h
index e11610bd263..0e52aa82b92 100644
--- a/source/blender/compositor/operations/COM_InpaintOperation.h
+++ b/source/blender/compositor/operations/COM_InpaintOperation.h
@@ -25,50 +25,49 @@ namespace blender::compositor {
class InpaintSimpleOperation : public NodeOperation {
protected:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputImageProgram;
+ SocketReader *input_image_program_;
- int m_iterations;
+ int iterations_;
- float *m_cached_buffer;
- bool m_cached_buffer_ready;
+ float *cached_buffer_;
+ bool cached_buffer_ready_;
- int *m_pixelorder;
- int m_area_size;
- short *m_manhattan_distance;
+ int *pixelorder_;
+ int area_size_;
+ short *manhattan_distance_;
public:
+ /** In-paint (simple convolve using average of known pixels). */
InpaintSimpleOperation();
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setIterations(int iterations)
+ void set_iterations(int iterations)
{
- this->m_iterations = iterations;
+ iterations_ = iterations;
}
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
diff --git a/source/blender/compositor/operations/COM_InvertOperation.cc b/source/blender/compositor/operations/COM_InvertOperation.cc
index d406b809c7a..3722282bd73 100644
--- a/source/blender/compositor/operations/COM_InvertOperation.cc
+++ b/source/blender/compositor/operations/COM_InvertOperation.cc
@@ -22,53 +22,56 @@ namespace blender::compositor {
InvertOperation::InvertOperation()
{
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
- this->m_inputValueProgram = nullptr;
- this->m_inputColorProgram = nullptr;
- this->m_color = true;
- this->m_alpha = false;
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ input_value_program_ = nullptr;
+ input_color_program_ = nullptr;
+ color_ = true;
+ alpha_ = false;
set_canvas_input_index(1);
- this->flags.can_be_constant = true;
+ flags_.can_be_constant = true;
}
-void InvertOperation::initExecution()
+void InvertOperation::init_execution()
{
- this->m_inputValueProgram = this->getInputSocketReader(0);
- this->m_inputColorProgram = this->getInputSocketReader(1);
+ input_value_program_ = this->get_input_socket_reader(0);
+ input_color_program_ = this->get_input_socket_reader(1);
}
-void InvertOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void InvertOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue[4];
- float inputColor[4];
- this->m_inputValueProgram->readSampled(inputValue, x, y, sampler);
- this->m_inputColorProgram->readSampled(inputColor, x, y, sampler);
+ float input_value[4];
+ float input_color[4];
+ input_value_program_->read_sampled(input_value, x, y, sampler);
+ input_color_program_->read_sampled(input_color, x, y, sampler);
- const float value = inputValue[0];
- const float invertedValue = 1.0f - value;
+ const float value = input_value[0];
+ const float inverted_value = 1.0f - value;
- if (this->m_color) {
- output[0] = (1.0f - inputColor[0]) * value + inputColor[0] * invertedValue;
- output[1] = (1.0f - inputColor[1]) * value + inputColor[1] * invertedValue;
- output[2] = (1.0f - inputColor[2]) * value + inputColor[2] * invertedValue;
+ if (color_) {
+ output[0] = (1.0f - input_color[0]) * value + input_color[0] * inverted_value;
+ output[1] = (1.0f - input_color[1]) * value + input_color[1] * inverted_value;
+ output[2] = (1.0f - input_color[2]) * value + input_color[2] * inverted_value;
}
else {
- copy_v3_v3(output, inputColor);
+ copy_v3_v3(output, input_color);
}
- if (this->m_alpha) {
- output[3] = (1.0f - inputColor[3]) * value + inputColor[3] * invertedValue;
+ if (alpha_) {
+ output[3] = (1.0f - input_color[3]) * value + input_color[3] * inverted_value;
}
else {
- output[3] = inputColor[3];
+ output[3] = input_color[3];
}
}
-void InvertOperation::deinitExecution()
+void InvertOperation::deinit_execution()
{
- this->m_inputValueProgram = nullptr;
- this->m_inputColorProgram = nullptr;
+ input_value_program_ = nullptr;
+ input_color_program_ = nullptr;
}
void InvertOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -80,7 +83,7 @@ void InvertOperation::update_memory_buffer_partial(MemoryBuffer *output,
const float inverted_value = 1.0f - value;
const float *color = it.in(1);
- if (this->m_color) {
+ if (color_) {
it.out[0] = (1.0f - color[0]) * value + color[0] * inverted_value;
it.out[1] = (1.0f - color[1]) * value + color[1] * inverted_value;
it.out[2] = (1.0f - color[2]) * value + color[2] * inverted_value;
@@ -89,7 +92,7 @@ void InvertOperation::update_memory_buffer_partial(MemoryBuffer *output,
copy_v3_v3(it.out, color);
}
- if (this->m_alpha) {
+ if (alpha_) {
it.out[3] = (1.0f - color[3]) * value + color[3] * inverted_value;
}
else {
diff --git a/source/blender/compositor/operations/COM_InvertOperation.h b/source/blender/compositor/operations/COM_InvertOperation.h
index a084bf5d559..19abca968c0 100644
--- a/source/blender/compositor/operations/COM_InvertOperation.h
+++ b/source/blender/compositor/operations/COM_InvertOperation.h
@@ -25,13 +25,13 @@ namespace blender::compositor {
class InvertOperation : public MultiThreadedOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputValueProgram;
- SocketReader *m_inputColorProgram;
+ SocketReader *input_value_program_;
+ SocketReader *input_color_program_;
- bool m_alpha;
- bool m_color;
+ bool alpha_;
+ bool color_;
public:
InvertOperation();
@@ -39,25 +39,25 @@ class InvertOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setColor(bool color)
+ void set_color(bool color)
{
- this->m_color = color;
+ color_ = color;
}
- void setAlpha(bool alpha)
+ void set_alpha(bool alpha)
{
- this->m_alpha = alpha;
+ alpha_ = alpha;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cc b/source/blender/compositor/operations/COM_KeyingBlurOperation.cc
index d5ebd5e9df7..7fbe96d382b 100644
--- a/source/blender/compositor/operations/COM_KeyingBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.cc
@@ -18,53 +18,47 @@
#include "COM_KeyingBlurOperation.h"
-#include "MEM_guardedalloc.h"
-
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-
namespace blender::compositor {
KeyingBlurOperation::KeyingBlurOperation()
{
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
- this->m_size = 0;
- this->m_axis = BLUR_AXIS_X;
+ size_ = 0;
+ axis_ = BLUR_AXIS_X;
- this->flags.complex = true;
+ flags_.complex = true;
}
-void *KeyingBlurOperation::initializeTileData(rcti *rect)
+void *KeyingBlurOperation::initialize_tile_data(rcti *rect)
{
- void *buffer = getInputOperation(0)->initializeTileData(rect);
+ void *buffer = get_input_operation(0)->initialize_tile_data(rect);
return buffer;
}
-void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data)
+void KeyingBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
{
- MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
- const int bufferWidth = inputBuffer->getWidth();
- float *buffer = inputBuffer->getBuffer();
+ MemoryBuffer *input_buffer = (MemoryBuffer *)data;
+ const int buffer_width = input_buffer->get_width();
+ float *buffer = input_buffer->get_buffer();
int count = 0;
float average = 0.0f;
- if (this->m_axis == 0) {
- const int start = MAX2(0, x - this->m_size + 1), end = MIN2(bufferWidth, x + this->m_size);
+ if (axis_ == 0) {
+ const int start = MAX2(0, x - size_ + 1), end = MIN2(buffer_width, x + size_);
for (int cx = start; cx < end; cx++) {
- int bufferIndex = (y * bufferWidth + cx);
- average += buffer[bufferIndex];
+ int buffer_index = (y * buffer_width + cx);
+ average += buffer[buffer_index];
count++;
}
}
else {
- const int start = MAX2(0, y - this->m_size + 1),
- end = MIN2(inputBuffer->getHeight(), y + this->m_size);
+ const int start = MAX2(0, y - size_ + 1), end = MIN2(input_buffer->get_height(), y + size_);
for (int cy = start; cy < end; cy++) {
- int bufferIndex = (cy * bufferWidth + x);
- average += buffer[bufferIndex];
+ int buffer_index = (cy * buffer_width + x);
+ average += buffer[buffer_index];
count++;
}
}
@@ -74,44 +68,44 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data
output[0] = average;
}
-bool KeyingBlurOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool KeyingBlurOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti newInput;
+ rcti new_input;
- if (this->m_axis == BLUR_AXIS_X) {
- newInput.xmin = input->xmin - this->m_size;
- newInput.ymin = input->ymin;
- newInput.xmax = input->xmax + this->m_size;
- newInput.ymax = input->ymax;
+ if (axis_ == BLUR_AXIS_X) {
+ new_input.xmin = input->xmin - size_;
+ new_input.ymin = input->ymin;
+ new_input.xmax = input->xmax + size_;
+ new_input.ymax = input->ymax;
}
else {
- newInput.xmin = input->xmin;
- newInput.ymin = input->ymin - this->m_size;
- newInput.xmax = input->xmax;
- newInput.ymax = input->ymax + this->m_size;
+ new_input.xmin = input->xmin;
+ new_input.ymin = input->ymin - size_;
+ new_input.xmax = input->xmax;
+ new_input.ymax = input->ymax + size_;
}
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void KeyingBlurOperation::get_area_of_interest(const int UNUSED(input_idx),
const rcti &output_area,
rcti &r_input_area)
{
- switch (m_axis) {
+ switch (axis_) {
case BLUR_AXIS_X:
- r_input_area.xmin = output_area.xmin - m_size;
+ r_input_area.xmin = output_area.xmin - size_;
r_input_area.ymin = output_area.ymin;
- r_input_area.xmax = output_area.xmax + m_size;
+ r_input_area.xmax = output_area.xmax + size_;
r_input_area.ymax = output_area.ymax;
break;
case BLUR_AXIS_Y:
r_input_area.xmin = output_area.xmin;
- r_input_area.ymin = output_area.ymin - m_size;
+ r_input_area.ymin = output_area.ymin - size_;
r_input_area.xmax = output_area.xmax;
- r_input_area.ymax = output_area.ymax + m_size;
+ r_input_area.ymax = output_area.ymax + size_;
break;
default:
BLI_assert_msg(0, "Unknown axis");
@@ -129,23 +123,23 @@ void KeyingBlurOperation::update_memory_buffer_partial(MemoryBuffer *output,
int coord_max;
int elem_stride;
std::function<int()> get_current_coord;
- switch (m_axis) {
+ switch (axis_) {
case BLUR_AXIS_X:
get_current_coord = [&] { return it.x; };
- coord_max = this->getWidth();
+ coord_max = this->get_width();
elem_stride = input->elem_stride;
break;
case BLUR_AXIS_Y:
get_current_coord = [&] { return it.y; };
- coord_max = this->getHeight();
+ coord_max = this->get_height();
elem_stride = input->row_stride;
break;
}
for (; !it.is_end(); ++it) {
const int coord = get_current_coord();
- const int start_coord = MAX2(0, coord - m_size + 1);
- const int end_coord = MIN2(coord_max, coord + m_size);
+ const int start_coord = MAX2(0, coord - size_ + 1);
+ const int end_coord = MIN2(coord_max, coord + size_);
const int count = end_coord - start_coord;
float sum = 0.0f;
diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.h b/source/blender/compositor/operations/COM_KeyingBlurOperation.h
index b290b905e63..cc4a98767d8 100644
--- a/source/blender/compositor/operations/COM_KeyingBlurOperation.h
+++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.h
@@ -27,8 +27,8 @@ namespace blender::compositor {
*/
class KeyingBlurOperation : public MultiThreadedOperation {
protected:
- int m_size;
- int m_axis;
+ int size_;
+ int axis_;
public:
enum BlurAxis {
@@ -38,26 +38,24 @@ class KeyingBlurOperation : public MultiThreadedOperation {
KeyingBlurOperation();
- void setSize(int value)
+ void set_size(int value)
{
- this->m_size = value;
+ size_ = value;
}
- void setAxis(int value)
+ void set_axis(int value)
{
- this->m_axis = value;
+ axis_ = value;
}
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.cc b/source/blender/compositor/operations/COM_KeyingClipOperation.cc
index 817c920ed91..d52b2801811 100644
--- a/source/blender/compositor/operations/COM_KeyingClipOperation.cc
+++ b/source/blender/compositor/operations/COM_KeyingClipOperation.cc
@@ -18,56 +18,51 @@
#include "COM_KeyingClipOperation.h"
-#include "MEM_guardedalloc.h"
-
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-
namespace blender::compositor {
KeyingClipOperation::KeyingClipOperation()
{
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
- this->m_kernelRadius = 3;
- this->m_kernelTolerance = 0.1f;
+ kernel_radius_ = 3;
+ kernel_tolerance_ = 0.1f;
- this->m_clipBlack = 0.0f;
- this->m_clipWhite = 1.0f;
+ clip_black_ = 0.0f;
+ clip_white_ = 1.0f;
- this->m_isEdgeMatte = false;
+ is_edge_matte_ = false;
- this->flags.complex = true;
+ flags_.complex = true;
}
-void *KeyingClipOperation::initializeTileData(rcti *rect)
+void *KeyingClipOperation::initialize_tile_data(rcti *rect)
{
- void *buffer = getInputOperation(0)->initializeTileData(rect);
+ void *buffer = get_input_operation(0)->initialize_tile_data(rect);
return buffer;
}
-void KeyingClipOperation::executePixel(float output[4], int x, int y, void *data)
+void KeyingClipOperation::execute_pixel(float output[4], int x, int y, void *data)
{
- const int delta = this->m_kernelRadius;
- const float tolerance = this->m_kernelTolerance;
+ const int delta = kernel_radius_;
+ const float tolerance = kernel_tolerance_;
- MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
- float *buffer = inputBuffer->getBuffer();
+ MemoryBuffer *input_buffer = (MemoryBuffer *)data;
+ float *buffer = input_buffer->get_buffer();
- int bufferWidth = inputBuffer->getWidth();
- int bufferHeight = inputBuffer->getHeight();
+ int buffer_width = input_buffer->get_width();
+ int buffer_height = input_buffer->get_height();
- float value = buffer[(y * bufferWidth + x)];
+ float value = buffer[(y * buffer_width + x)];
bool ok = false;
int start_x = max_ff(0, x - delta + 1), start_y = max_ff(0, y - delta + 1),
- end_x = min_ff(x + delta - 1, bufferWidth - 1),
- end_y = min_ff(y + delta - 1, bufferHeight - 1);
+ end_x = min_ff(x + delta - 1, buffer_width - 1),
+ end_y = min_ff(y + delta - 1, buffer_height - 1);
- int count = 0, totalCount = (end_x - start_x + 1) * (end_y - start_y + 1) - 1;
- int thresholdCount = ceil((float)totalCount * 0.9f);
+ int count = 0, total_count = (end_x - start_x + 1) * (end_y - start_y + 1) - 1;
+ int threshold_count = ceil((float)total_count * 0.9f);
if (delta == 0) {
ok = true;
@@ -79,19 +74,19 @@ void KeyingClipOperation::executePixel(float output[4], int x, int y, void *data
continue;
}
- int bufferIndex = (cy * bufferWidth + cx);
- float currentValue = buffer[bufferIndex];
+ int buffer_index = (cy * buffer_width + cx);
+ float current_value = buffer[buffer_index];
- if (fabsf(currentValue - value) < tolerance) {
+ if (fabsf(current_value - value) < tolerance) {
count++;
- if (count >= thresholdCount) {
+ if (count >= threshold_count) {
ok = true;
}
}
}
}
- if (this->m_isEdgeMatte) {
+ if (is_edge_matte_) {
if (ok) {
output[0] = 0.0f;
}
@@ -103,31 +98,31 @@ void KeyingClipOperation::executePixel(float output[4], int x, int y, void *data
output[0] = value;
if (ok) {
- if (output[0] < this->m_clipBlack) {
+ if (output[0] < clip_black_) {
output[0] = 0.0f;
}
- else if (output[0] >= this->m_clipWhite) {
+ else if (output[0] >= clip_white_) {
output[0] = 1.0f;
}
else {
- output[0] = (output[0] - this->m_clipBlack) / (this->m_clipWhite - this->m_clipBlack);
+ output[0] = (output[0] - clip_black_) / (clip_white_ - clip_black_);
}
}
}
}
-bool KeyingClipOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool KeyingClipOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti newInput;
+ rcti new_input;
- newInput.xmin = input->xmin - this->m_kernelRadius;
- newInput.ymin = input->ymin - this->m_kernelRadius;
- newInput.xmax = input->xmax + this->m_kernelRadius;
- newInput.ymax = input->ymax + this->m_kernelRadius;
+ new_input.xmin = input->xmin - kernel_radius_;
+ new_input.ymin = input->ymin - kernel_radius_;
+ new_input.xmax = input->xmax + kernel_radius_;
+ new_input.ymax = input->ymax + kernel_radius_;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void KeyingClipOperation::get_area_of_interest(const int input_idx,
@@ -136,10 +131,10 @@ void KeyingClipOperation::get_area_of_interest(const int input_idx,
{
BLI_assert(input_idx == 0);
UNUSED_VARS_NDEBUG(input_idx);
- r_input_area.xmin = output_area.xmin - m_kernelRadius;
- r_input_area.xmax = output_area.xmax + m_kernelRadius;
- r_input_area.ymin = output_area.ymin - m_kernelRadius;
- r_input_area.ymax = output_area.ymax + m_kernelRadius;
+ r_input_area.xmin = output_area.xmin - kernel_radius_;
+ r_input_area.xmax = output_area.xmax + kernel_radius_;
+ r_input_area.ymin = output_area.ymin - kernel_radius_;
+ r_input_area.ymax = output_area.ymax + kernel_radius_;
}
void KeyingClipOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -149,10 +144,10 @@ void KeyingClipOperation::update_memory_buffer_partial(MemoryBuffer *output,
const MemoryBuffer *input = inputs[0];
BuffersIterator<float> it = output->iterate_with(inputs, area);
- const int delta = m_kernelRadius;
- const float tolerance = m_kernelTolerance;
- const int width = this->getWidth();
- const int height = this->getHeight();
+ const int delta = kernel_radius_;
+ const float tolerance = kernel_tolerance_;
+ const int width = this->get_width();
+ const int height = this->get_height();
const int row_stride = input->row_stride;
const int elem_stride = input->elem_stride;
for (; !it.is_end(); ++it) {
@@ -195,21 +190,21 @@ void KeyingClipOperation::update_memory_buffer_partial(MemoryBuffer *output,
}
}
- if (m_isEdgeMatte) {
+ if (is_edge_matte_) {
*it.out = ok ? 0.0f : 1.0f;
}
else {
if (!ok) {
*it.out = value;
}
- else if (value < m_clipBlack) {
+ else if (value < clip_black_) {
*it.out = 0.0f;
}
- else if (value >= m_clipWhite) {
+ else if (value >= clip_white_) {
*it.out = 1.0f;
}
else {
- *it.out = (value - m_clipBlack) / (m_clipWhite - m_clipBlack);
+ *it.out = (value - clip_black_) / (clip_white_ - clip_black_);
}
}
}
diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.h b/source/blender/compositor/operations/COM_KeyingClipOperation.h
index 1a17d591781..b945d4264af 100644
--- a/source/blender/compositor/operations/COM_KeyingClipOperation.h
+++ b/source/blender/compositor/operations/COM_KeyingClipOperation.h
@@ -27,51 +27,49 @@ namespace blender::compositor {
*/
class KeyingClipOperation : public MultiThreadedOperation {
protected:
- float m_clipBlack;
- float m_clipWhite;
+ float clip_black_;
+ float clip_white_;
- int m_kernelRadius;
- float m_kernelTolerance;
+ int kernel_radius_;
+ float kernel_tolerance_;
- bool m_isEdgeMatte;
+ bool is_edge_matte_;
public:
KeyingClipOperation();
- void setClipBlack(float value)
+ void set_clip_black(float value)
{
- this->m_clipBlack = value;
+ clip_black_ = value;
}
- void setClipWhite(float value)
+ void set_clip_white(float value)
{
- this->m_clipWhite = value;
+ clip_white_ = value;
}
- void setKernelRadius(int value)
+ void set_kernel_radius(int value)
{
- this->m_kernelRadius = value;
+ kernel_radius_ = value;
}
- void setKernelTolerance(float value)
+ void set_kernel_tolerance(float value)
{
- this->m_kernelTolerance = value;
+ kernel_tolerance_ = value;
}
- void setIsEdgeMatte(bool value)
+ void set_is_edge_matte(bool value)
{
- this->m_isEdgeMatte = value;
+ is_edge_matte_ = value;
}
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.cc b/source/blender/compositor/operations/COM_KeyingDespillOperation.cc
index 620b767e584..d200d1e5eb3 100644
--- a/source/blender/compositor/operations/COM_KeyingDespillOperation.cc
+++ b/source/blender/compositor/operations/COM_KeyingDespillOperation.cc
@@ -18,51 +18,46 @@
#include "COM_KeyingDespillOperation.h"
-#include "MEM_guardedalloc.h"
-
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-
namespace blender::compositor {
KeyingDespillOperation::KeyingDespillOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
- this->m_despillFactor = 0.5f;
- this->m_colorBalance = 0.5f;
+ despill_factor_ = 0.5f;
+ color_balance_ = 0.5f;
- this->m_pixelReader = nullptr;
- this->m_screenReader = nullptr;
- flags.can_be_constant = true;
+ pixel_reader_ = nullptr;
+ screen_reader_ = nullptr;
+ flags_.can_be_constant = true;
}
-void KeyingDespillOperation::initExecution()
+void KeyingDespillOperation::init_execution()
{
- this->m_pixelReader = this->getInputSocketReader(0);
- this->m_screenReader = this->getInputSocketReader(1);
+ pixel_reader_ = this->get_input_socket_reader(0);
+ screen_reader_ = this->get_input_socket_reader(1);
}
-void KeyingDespillOperation::deinitExecution()
+void KeyingDespillOperation::deinit_execution()
{
- this->m_pixelReader = nullptr;
- this->m_screenReader = nullptr;
+ pixel_reader_ = nullptr;
+ screen_reader_ = nullptr;
}
-void KeyingDespillOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void KeyingDespillOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float pixelColor[4];
- float screenColor[4];
+ float pixel_color[4];
+ float screen_color[4];
- this->m_pixelReader->readSampled(pixelColor, x, y, sampler);
- this->m_screenReader->readSampled(screenColor, x, y, sampler);
+ pixel_reader_->read_sampled(pixel_color, x, y, sampler);
+ screen_reader_->read_sampled(screen_color, x, y, sampler);
- const int screen_primary_channel = max_axis_v3(screenColor);
+ const int screen_primary_channel = max_axis_v3(screen_color);
const int other_1 = (screen_primary_channel + 1) % 3;
const int other_2 = (screen_primary_channel + 2) % 3;
@@ -71,15 +66,15 @@ void KeyingDespillOperation::executePixelSampled(float output[4],
float average_value, amount;
- average_value = this->m_colorBalance * pixelColor[min_channel] +
- (1.0f - this->m_colorBalance) * pixelColor[max_channel];
- amount = (pixelColor[screen_primary_channel] - average_value);
+ average_value = color_balance_ * pixel_color[min_channel] +
+ (1.0f - color_balance_) * pixel_color[max_channel];
+ amount = (pixel_color[screen_primary_channel] - average_value);
- copy_v4_v4(output, pixelColor);
+ copy_v4_v4(output, pixel_color);
- const float amount_despill = this->m_despillFactor * amount;
+ const float amount_despill = despill_factor_ * amount;
if (amount_despill > 0.0f) {
- output[screen_primary_channel] = pixelColor[screen_primary_channel] - amount_despill;
+ output[screen_primary_channel] = pixel_color[screen_primary_channel] - amount_despill;
}
}
@@ -98,13 +93,13 @@ void KeyingDespillOperation::update_memory_buffer_partial(MemoryBuffer *output,
const int min_channel = MIN2(other_1, other_2);
const int max_channel = MAX2(other_1, other_2);
- const float average_value = m_colorBalance * pixel_color[min_channel] +
- (1.0f - m_colorBalance) * pixel_color[max_channel];
+ const float average_value = color_balance_ * pixel_color[min_channel] +
+ (1.0f - color_balance_) * pixel_color[max_channel];
const float amount = (pixel_color[screen_primary_channel] - average_value);
copy_v4_v4(it.out, pixel_color);
- const float amount_despill = m_despillFactor * amount;
+ const float amount_despill = despill_factor_ * amount;
if (amount_despill > 0.0f) {
it.out[screen_primary_channel] = pixel_color[screen_primary_channel] - amount_despill;
}
diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.h b/source/blender/compositor/operations/COM_KeyingDespillOperation.h
index 16bed651d3a..b57fbd09e74 100644
--- a/source/blender/compositor/operations/COM_KeyingDespillOperation.h
+++ b/source/blender/compositor/operations/COM_KeyingDespillOperation.h
@@ -27,27 +27,27 @@ namespace blender::compositor {
*/
class KeyingDespillOperation : public MultiThreadedOperation {
protected:
- SocketReader *m_pixelReader;
- SocketReader *m_screenReader;
- float m_despillFactor;
- float m_colorBalance;
+ SocketReader *pixel_reader_;
+ SocketReader *screen_reader_;
+ float despill_factor_;
+ float color_balance_;
public:
KeyingDespillOperation();
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void setDespillFactor(float value)
+ void set_despill_factor(float value)
{
- this->m_despillFactor = value;
+ despill_factor_ = value;
}
- void setColorBalance(float value)
+ void set_color_balance(float value)
{
- this->m_colorBalance = value;
+ color_balance_ = value;
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_KeyingOperation.cc b/source/blender/compositor/operations/COM_KeyingOperation.cc
index 3edb5a5d34e..c7ab3aca2e2 100644
--- a/source/blender/compositor/operations/COM_KeyingOperation.cc
+++ b/source/blender/compositor/operations/COM_KeyingOperation.cc
@@ -18,14 +18,9 @@
#include "COM_KeyingOperation.h"
-#include "MEM_guardedalloc.h"
-
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-
namespace blender::compositor {
-static float get_pixel_saturation(const float pixelColor[4],
+static float get_pixel_saturation(const float pixel_color[4],
float screen_balance,
int primary_channel)
{
@@ -35,43 +30,46 @@ static float get_pixel_saturation(const float pixelColor[4],
const int min_channel = MIN2(other_1, other_2);
const int max_channel = MAX2(other_1, other_2);
- const float val = screen_balance * pixelColor[min_channel] +
- (1.0f - screen_balance) * pixelColor[max_channel];
+ const float val = screen_balance * pixel_color[min_channel] +
+ (1.0f - screen_balance) * pixel_color[max_channel];
- return (pixelColor[primary_channel] - val) * fabsf(1.0f - val);
+ return (pixel_color[primary_channel] - val) * fabsf(1.0f - val);
}
KeyingOperation::KeyingOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Value);
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Value);
- this->m_screenBalance = 0.5f;
+ screen_balance_ = 0.5f;
- this->m_pixelReader = nullptr;
- this->m_screenReader = nullptr;
+ pixel_reader_ = nullptr;
+ screen_reader_ = nullptr;
}
-void KeyingOperation::initExecution()
+void KeyingOperation::init_execution()
{
- this->m_pixelReader = this->getInputSocketReader(0);
- this->m_screenReader = this->getInputSocketReader(1);
+ pixel_reader_ = this->get_input_socket_reader(0);
+ screen_reader_ = this->get_input_socket_reader(1);
}
-void KeyingOperation::deinitExecution()
+void KeyingOperation::deinit_execution()
{
- this->m_pixelReader = nullptr;
- this->m_screenReader = nullptr;
+ pixel_reader_ = nullptr;
+ screen_reader_ = nullptr;
}
-void KeyingOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void KeyingOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float pixel_color[4];
float screen_color[4];
- this->m_pixelReader->readSampled(pixel_color, x, y, sampler);
- this->m_screenReader->readSampled(screen_color, x, y, sampler);
+ pixel_reader_->read_sampled(pixel_color, x, y, sampler);
+ screen_reader_->read_sampled(screen_color, x, y, sampler);
const int primary_channel = max_axis_v3(screen_color);
const float min_pixel_color = min_fff(pixel_color[0], pixel_color[1], pixel_color[2]);
@@ -85,9 +83,8 @@ void KeyingOperation::executePixelSampled(float output[4], float x, float y, Pix
output[0] = 1.0f;
}
else {
- float saturation = get_pixel_saturation(pixel_color, this->m_screenBalance, primary_channel);
- float screen_saturation = get_pixel_saturation(
- screen_color, this->m_screenBalance, primary_channel);
+ float saturation = get_pixel_saturation(pixel_color, screen_balance_, primary_channel);
+ float screen_saturation = get_pixel_saturation(screen_color, screen_balance_, primary_channel);
if (saturation < 0) {
/* means main channel of pixel is different from screen,
@@ -130,9 +127,9 @@ void KeyingOperation::update_memory_buffer_partial(MemoryBuffer *output,
it.out[0] = 1.0f;
}
else {
- const float saturation = get_pixel_saturation(pixel_color, m_screenBalance, primary_channel);
+ const float saturation = get_pixel_saturation(pixel_color, screen_balance_, primary_channel);
const float screen_saturation = get_pixel_saturation(
- screen_color, m_screenBalance, primary_channel);
+ screen_color, screen_balance_, primary_channel);
if (saturation < 0) {
/* Means main channel of pixel is different from screen,
diff --git a/source/blender/compositor/operations/COM_KeyingOperation.h b/source/blender/compositor/operations/COM_KeyingOperation.h
index e134ad54896..d7be4872065 100644
--- a/source/blender/compositor/operations/COM_KeyingOperation.h
+++ b/source/blender/compositor/operations/COM_KeyingOperation.h
@@ -31,23 +31,23 @@ namespace blender::compositor {
*/
class KeyingOperation : public MultiThreadedOperation {
protected:
- SocketReader *m_pixelReader;
- SocketReader *m_screenReader;
+ SocketReader *pixel_reader_;
+ SocketReader *screen_reader_;
- float m_screenBalance;
+ float screen_balance_;
public:
KeyingOperation();
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void setScreenBalance(float value)
+ void set_screen_balance(float value)
{
- this->m_screenBalance = value;
+ screen_balance_ = value;
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc
index b4840926d55..5d12f29b83f 100644
--- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc
+++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc
@@ -18,11 +18,7 @@
#include "COM_KeyingScreenOperation.h"
-#include "MEM_guardedalloc.h"
-
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-#include "BLI_math_color.h"
+#include "DNA_defaults.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
@@ -34,32 +30,32 @@ namespace blender::compositor {
KeyingScreenOperation::KeyingScreenOperation()
{
- this->addOutputSocket(DataType::Color);
- this->m_movieClip = nullptr;
- this->m_framenumber = 0;
- this->m_trackingObject[0] = 0;
- flags.complex = true;
- m_cachedTriangulation = nullptr;
+ this->add_output_socket(DataType::Color);
+ movie_clip_ = nullptr;
+ framenumber_ = 0;
+ tracking_object_[0] = 0;
+ flags_.complex = true;
+ cached_triangulation_ = nullptr;
}
-void KeyingScreenOperation::initExecution()
+void KeyingScreenOperation::init_execution()
{
- initMutex();
+ init_mutex();
if (execution_model_ == eExecutionModel::FullFrame) {
- BLI_assert(m_cachedTriangulation == nullptr);
- if (m_movieClip) {
- m_cachedTriangulation = buildVoronoiTriangulation();
+ BLI_assert(cached_triangulation_ == nullptr);
+ if (movie_clip_) {
+ cached_triangulation_ = build_voronoi_triangulation();
}
}
else {
- this->m_cachedTriangulation = nullptr;
+ cached_triangulation_ = nullptr;
}
}
-void KeyingScreenOperation::deinitExecution()
+void KeyingScreenOperation::deinit_execution()
{
- if (this->m_cachedTriangulation) {
- TriangulationData *triangulation = this->m_cachedTriangulation;
+ if (cached_triangulation_) {
+ TriangulationData *triangulation = cached_triangulation_;
if (triangulation->triangulated_points) {
MEM_freeN(triangulation->triangulated_points);
@@ -73,17 +69,17 @@ void KeyingScreenOperation::deinitExecution()
MEM_freeN(triangulation->triangles_AABB);
}
- MEM_freeN(this->m_cachedTriangulation);
+ MEM_freeN(cached_triangulation_);
- this->m_cachedTriangulation = nullptr;
+ cached_triangulation_ = nullptr;
}
}
-KeyingScreenOperation::TriangulationData *KeyingScreenOperation::buildVoronoiTriangulation()
+KeyingScreenOperation::TriangulationData *KeyingScreenOperation::build_voronoi_triangulation()
{
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
TriangulationData *triangulation;
- MovieTracking *tracking = &this->m_movieClip->tracking;
+ MovieTracking *tracking = &movie_clip_->tracking;
MovieTrackingTrack *track;
VoronoiSite *sites, *site;
ImBuf *ibuf;
@@ -91,12 +87,12 @@ KeyingScreenOperation::TriangulationData *KeyingScreenOperation::buildVoronoiTri
ListBase edges = {nullptr, nullptr};
int sites_total;
int i;
- int width = this->getWidth();
- int height = this->getHeight();
- int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, this->m_framenumber);
+ int width = this->get_width();
+ int height = this->get_height();
+ int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(movie_clip_, framenumber_);
- if (this->m_trackingObject[0]) {
- MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, this->m_trackingObject);
+ if (tracking_object_[0]) {
+ MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, tracking_object_);
if (!object) {
return nullptr;
@@ -132,14 +128,13 @@ KeyingScreenOperation::TriangulationData *KeyingScreenOperation::buildVoronoiTri
}
BKE_movieclip_user_set_frame(&user, clip_frame);
- ibuf = BKE_movieclip_get_ibuf(this->m_movieClip, &user);
+ ibuf = BKE_movieclip_get_ibuf(movie_clip_, &user);
if (!ibuf) {
return nullptr;
}
- triangulation = (TriangulationData *)MEM_callocN(sizeof(TriangulationData),
- "keying screen triangulation data");
+ triangulation = MEM_cnew<TriangulationData>("keying screen triangulation data");
sites = (VoronoiSite *)MEM_callocN(sizeof(VoronoiSite) * sites_total,
"keyingscreen voronoi sites");
@@ -243,13 +238,13 @@ KeyingScreenOperation::TileData *KeyingScreenOperation::triangulate(const rcti *
int chunk_size = 20;
int i;
- triangulation = this->m_cachedTriangulation;
+ triangulation = cached_triangulation_;
if (!triangulation) {
return nullptr;
}
- tile_data = (TileData *)MEM_callocN(sizeof(TileData), "keying screen tile data");
+ tile_data = MEM_cnew<TileData>("keying screen tile data");
for (i = 0; i < triangulation->triangles_total; i++) {
if (BLI_rcti_isect(rect, &triangulation->triangles_AABB[i], nullptr)) {
@@ -275,24 +270,24 @@ KeyingScreenOperation::TileData *KeyingScreenOperation::triangulate(const rcti *
return tile_data;
}
-void *KeyingScreenOperation::initializeTileData(rcti *rect)
+void *KeyingScreenOperation::initialize_tile_data(rcti *rect)
{
- if (this->m_movieClip == nullptr) {
+ if (movie_clip_ == nullptr) {
return nullptr;
}
- if (!this->m_cachedTriangulation) {
- lockMutex();
- if (this->m_cachedTriangulation == nullptr) {
- this->m_cachedTriangulation = buildVoronoiTriangulation();
+ if (!cached_triangulation_) {
+ lock_mutex();
+ if (cached_triangulation_ == nullptr) {
+ cached_triangulation_ = build_voronoi_triangulation();
}
- unlockMutex();
+ unlock_mutex();
}
return triangulate(rect);
}
-void KeyingScreenOperation::deinitializeTileData(rcti * /*rect*/, void *data)
+void KeyingScreenOperation::deinitialize_tile_data(rcti * /*rect*/, void *data)
{
TileData *tile_data = (TileData *)data;
@@ -307,29 +302,28 @@ void KeyingScreenOperation::determine_canvas(const rcti &preferred_area, rcti &r
{
r_area = COM_AREA_NONE;
- if (this->m_movieClip) {
- MovieClipUser user = {0};
+ if (movie_clip_) {
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
int width, height;
- int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip,
- this->m_framenumber);
+ int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(movie_clip_, framenumber_);
BKE_movieclip_user_set_frame(&user, clip_frame);
- BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height);
+ BKE_movieclip_get_size(movie_clip_, &user, &width, &height);
r_area = preferred_area;
r_area.xmax = r_area.xmin + width;
r_area.ymax = r_area.ymin + height;
}
}
-void KeyingScreenOperation::executePixel(float output[4], int x, int y, void *data)
+void KeyingScreenOperation::execute_pixel(float output[4], int x, int y, void *data)
{
output[0] = 0.0f;
output[1] = 0.0f;
output[2] = 0.0f;
output[3] = 1.0f;
- if (this->m_movieClip && data) {
- TriangulationData *triangulation = this->m_cachedTriangulation;
+ if (movie_clip_ && data) {
+ TriangulationData *triangulation = cached_triangulation_;
TileData *tile_data = (TileData *)data;
int i;
float co[2] = {(float)x, (float)y};
@@ -363,7 +357,7 @@ void KeyingScreenOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- if (m_movieClip == nullptr) {
+ if (movie_clip_ == nullptr) {
output->fill(area, COM_COLOR_BLACK);
return;
}
@@ -373,7 +367,7 @@ void KeyingScreenOperation::update_memory_buffer_partial(MemoryBuffer *output,
const int *triangles = tri_area->triangles;
const int num_triangles = tri_area->triangles_total;
- const TriangulationData *triangulation = m_cachedTriangulation;
+ const TriangulationData *triangulation = cached_triangulation_;
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
copy_v4_v4(it.out, COM_COLOR_BLACK);
diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.h b/source/blender/compositor/operations/COM_KeyingScreenOperation.h
index 7a7dda27710..3450a82a485 100644
--- a/source/blender/compositor/operations/COM_KeyingScreenOperation.h
+++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.h
@@ -49,41 +49,41 @@ class KeyingScreenOperation : public MultiThreadedOperation {
int triangles_total;
} TileData;
- MovieClip *m_movieClip;
- int m_framenumber;
- TriangulationData *m_cachedTriangulation;
- char m_trackingObject[64];
+ MovieClip *movie_clip_;
+ int framenumber_;
+ TriangulationData *cached_triangulation_;
+ char tracking_object_[64];
/**
* Determine the output resolution. The resolution is retrieved from the Renderer
*/
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
- TriangulationData *buildVoronoiTriangulation();
+ TriangulationData *build_voronoi_triangulation();
public:
KeyingScreenOperation();
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void *initializeTileData(rcti *rect) override;
- void deinitializeTileData(rcti *rect, void *data) override;
+ void *initialize_tile_data(rcti *rect) override;
+ void deinitialize_tile_data(rcti *rect, void *data) override;
- void setMovieClip(MovieClip *clip)
+ void set_movie_clip(MovieClip *clip)
{
- this->m_movieClip = clip;
+ movie_clip_ = clip;
}
- void setTrackingObject(const char *object)
+ void set_tracking_object(const char *object)
{
- BLI_strncpy(this->m_trackingObject, object, sizeof(this->m_trackingObject));
+ BLI_strncpy(tracking_object_, object, sizeof(tracking_object_));
}
- void setFramenumber(int framenumber)
+ void set_framenumber(int framenumber)
{
- this->m_framenumber = framenumber;
+ framenumber_ = framenumber;
}
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc
index c642c60b912..f2543d0d159 100644
--- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc
+++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc
@@ -17,7 +17,6 @@
*/
#include "COM_LuminanceMatteOperation.h"
-#include "BLI_math.h"
#include "IMB_colormanagement.h"
@@ -25,39 +24,39 @@ namespace blender::compositor {
LuminanceMatteOperation::LuminanceMatteOperation()
{
- addInputSocket(DataType::Color);
- addOutputSocket(DataType::Value);
+ add_input_socket(DataType::Color);
+ add_output_socket(DataType::Value);
- this->m_inputImageProgram = nullptr;
- flags.can_be_constant = true;
+ input_image_program_ = nullptr;
+ flags_.can_be_constant = true;
}
-void LuminanceMatteOperation::initExecution()
+void LuminanceMatteOperation::init_execution()
{
- this->m_inputImageProgram = this->getInputSocketReader(0);
+ input_image_program_ = this->get_input_socket_reader(0);
}
-void LuminanceMatteOperation::deinitExecution()
+void LuminanceMatteOperation::deinit_execution()
{
- this->m_inputImageProgram = nullptr;
+ input_image_program_ = nullptr;
}
-void LuminanceMatteOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void LuminanceMatteOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inColor[4];
- this->m_inputImageProgram->readSampled(inColor, x, y, sampler);
+ float in_color[4];
+ input_image_program_->read_sampled(in_color, x, y, sampler);
- const float high = this->m_settings->t1;
- const float low = this->m_settings->t2;
- const float luminance = IMB_colormanagement_get_luminance(inColor);
+ const float high = settings_->t1;
+ const float low = settings_->t2;
+ const float luminance = IMB_colormanagement_get_luminance(in_color);
float alpha;
/* one line thread-friend algorithm:
- * output[0] = MIN2(inputValue[3], MIN2(1.0f, MAX2(0.0f, ((luminance - low) / (high - low))));
+ * output[0] = MIN2(input_value[3], MIN2(1.0f, MAX2(0.0f, ((luminance - low) / (high - low))));
*/
/* test range */
@@ -76,7 +75,7 @@ void LuminanceMatteOperation::executePixelSampled(float output[4],
*/
/* don't make something that was more transparent less transparent */
- output[0] = min_ff(alpha, inColor[3]);
+ output[0] = min_ff(alpha, in_color[3]);
}
void LuminanceMatteOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -92,8 +91,8 @@ void LuminanceMatteOperation::update_memory_buffer_partial(MemoryBuffer *output,
*/
/* Test range. */
- const float high = m_settings->t1;
- const float low = m_settings->t2;
+ const float high = settings_->t1;
+ const float low = settings_->t2;
float alpha;
if (luminance > high) {
alpha = 1.0f;
diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.h b/source/blender/compositor/operations/COM_LuminanceMatteOperation.h
index aedfc715382..7f9ccfc83ac 100644
--- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.h
+++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.h
@@ -28,8 +28,8 @@ namespace blender::compositor {
*/
class LuminanceMatteOperation : public MultiThreadedOperation {
private:
- NodeChroma *m_settings;
- SocketReader *m_inputImageProgram;
+ NodeChroma *settings_;
+ SocketReader *input_image_program_;
public:
/**
@@ -40,14 +40,14 @@ class LuminanceMatteOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void setSettings(NodeChroma *nodeChroma)
+ void set_settings(NodeChroma *node_chroma)
{
- this->m_settings = nodeChroma;
+ settings_ = node_chroma;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_MapRangeOperation.cc b/source/blender/compositor/operations/COM_MapRangeOperation.cc
index 82fb033bf24..7d63a473500 100644
--- a/source/blender/compositor/operations/COM_MapRangeOperation.cc
+++ b/source/blender/compositor/operations/COM_MapRangeOperation.cc
@@ -22,45 +22,45 @@ namespace blender::compositor {
MapRangeOperation::MapRangeOperation()
{
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
- this->m_inputOperation = nullptr;
- this->m_useClamp = false;
- flags.can_be_constant = true;
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
+ input_operation_ = nullptr;
+ use_clamp_ = false;
+ flags_.can_be_constant = true;
}
-void MapRangeOperation::initExecution()
+void MapRangeOperation::init_execution()
{
- this->m_inputOperation = this->getInputSocketReader(0);
- this->m_sourceMinOperation = this->getInputSocketReader(1);
- this->m_sourceMaxOperation = this->getInputSocketReader(2);
- this->m_destMinOperation = this->getInputSocketReader(3);
- this->m_destMaxOperation = this->getInputSocketReader(4);
+ input_operation_ = this->get_input_socket_reader(0);
+ source_min_operation_ = this->get_input_socket_reader(1);
+ source_max_operation_ = this->get_input_socket_reader(2);
+ dest_min_operation_ = this->get_input_socket_reader(3);
+ dest_max_operation_ = this->get_input_socket_reader(4);
}
/* The code below assumes all data is inside range +- this, and that input buffer is single channel
*/
#define BLENDER_ZMAX 10000.0f
-void MapRangeOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MapRangeOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float inputs[8]; /* includes the 5 inputs + 3 pads */
float value;
float source_min, source_max;
float dest_min, dest_max;
- this->m_inputOperation->readSampled(inputs, x, y, sampler);
- this->m_sourceMinOperation->readSampled(inputs + 1, x, y, sampler);
- this->m_sourceMaxOperation->readSampled(inputs + 2, x, y, sampler);
- this->m_destMinOperation->readSampled(inputs + 3, x, y, sampler);
- this->m_destMaxOperation->readSampled(inputs + 4, x, y, sampler);
+ input_operation_->read_sampled(inputs, x, y, sampler);
+ source_min_operation_->read_sampled(inputs + 1, x, y, sampler);
+ source_max_operation_->read_sampled(inputs + 2, x, y, sampler);
+ dest_min_operation_->read_sampled(inputs + 3, x, y, sampler);
+ dest_max_operation_->read_sampled(inputs + 4, x, y, sampler);
value = inputs[0];
source_min = inputs[1];
@@ -84,7 +84,7 @@ void MapRangeOperation::executePixelSampled(float output[4],
value = dest_min;
}
- if (this->m_useClamp) {
+ if (use_clamp_) {
if (dest_max > dest_min) {
CLAMP(value, dest_min, dest_max);
}
@@ -96,13 +96,13 @@ void MapRangeOperation::executePixelSampled(float output[4],
output[0] = value;
}
-void MapRangeOperation::deinitExecution()
+void MapRangeOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
- this->m_sourceMinOperation = nullptr;
- this->m_sourceMaxOperation = nullptr;
- this->m_destMinOperation = nullptr;
- this->m_destMaxOperation = nullptr;
+ input_operation_ = nullptr;
+ source_min_operation_ = nullptr;
+ source_max_operation_ = nullptr;
+ dest_min_operation_ = nullptr;
+ dest_max_operation_ = nullptr;
}
void MapRangeOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -131,7 +131,7 @@ void MapRangeOperation::update_memory_buffer_partial(MemoryBuffer *output,
value = dest_min;
}
- if (m_useClamp) {
+ if (use_clamp_) {
if (dest_max > dest_min) {
CLAMP(value, dest_min, dest_max);
}
diff --git a/source/blender/compositor/operations/COM_MapRangeOperation.h b/source/blender/compositor/operations/COM_MapRangeOperation.h
index a01be14d528..0d0f3c90e35 100644
--- a/source/blender/compositor/operations/COM_MapRangeOperation.h
+++ b/source/blender/compositor/operations/COM_MapRangeOperation.h
@@ -30,15 +30,15 @@ namespace blender::compositor {
class MapRangeOperation : public MultiThreadedOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputOperation;
- SocketReader *m_sourceMinOperation;
- SocketReader *m_sourceMaxOperation;
- SocketReader *m_destMinOperation;
- SocketReader *m_destMaxOperation;
+ SocketReader *input_operation_;
+ SocketReader *source_min_operation_;
+ SocketReader *source_max_operation_;
+ SocketReader *dest_min_operation_;
+ SocketReader *dest_max_operation_;
- bool m_useClamp;
+ bool use_clamp_;
public:
/**
@@ -49,24 +49,24 @@ class MapRangeOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
/**
* Clamp the output
*/
- void setUseClamp(bool value)
+ void set_use_clamp(bool value)
{
- this->m_useClamp = value;
+ use_clamp_ = value;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cc b/source/blender/compositor/operations/COM_MapUVOperation.cc
index ba38e583b30..8f46332c9bc 100644
--- a/source/blender/compositor/operations/COM_MapUVOperation.cc
+++ b/source/blender/compositor/operations/COM_MapUVOperation.cc
@@ -17,71 +17,70 @@
*/
#include "COM_MapUVOperation.h"
-#include "BLI_math.h"
namespace blender::compositor {
MapUVOperation::MapUVOperation()
{
- this->addInputSocket(DataType::Color, ResizeMode::Align);
- this->addInputSocket(DataType::Vector);
- this->addOutputSocket(DataType::Color);
- this->m_alpha = 0.0f;
- this->flags.complex = true;
+ this->add_input_socket(DataType::Color, ResizeMode::Align);
+ this->add_input_socket(DataType::Vector);
+ this->add_output_socket(DataType::Color);
+ alpha_ = 0.0f;
+ flags_.complex = true;
set_canvas_input_index(UV_INPUT_INDEX);
- this->m_inputUVProgram = nullptr;
- this->m_inputColorProgram = nullptr;
+ inputUVProgram_ = nullptr;
+ input_color_program_ = nullptr;
}
void MapUVOperation::init_data()
{
NodeOperation *image_input = get_input_operation(IMAGE_INPUT_INDEX);
- image_width_ = image_input->getWidth();
- image_height_ = image_input->getHeight();
+ image_width_ = image_input->get_width();
+ image_height_ = image_input->get_height();
NodeOperation *uv_input = get_input_operation(UV_INPUT_INDEX);
- uv_width_ = uv_input->getWidth();
- uv_height_ = uv_input->getHeight();
+ uv_width_ = uv_input->get_width();
+ uv_height_ = uv_input->get_height();
}
-void MapUVOperation::initExecution()
+void MapUVOperation::init_execution()
{
- this->m_inputColorProgram = this->getInputSocketReader(0);
- this->m_inputUVProgram = this->getInputSocketReader(1);
+ input_color_program_ = this->get_input_socket_reader(0);
+ inputUVProgram_ = this->get_input_socket_reader(1);
if (execution_model_ == eExecutionModel::Tiled) {
uv_input_read_fn_ = [=](float x, float y, float *out) {
- this->m_inputUVProgram->readSampled(out, x, y, PixelSampler::Bilinear);
+ inputUVProgram_->read_sampled(out, x, y, PixelSampler::Bilinear);
};
}
}
-void MapUVOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler /*sampler*/)
+void MapUVOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
float xy[2] = {x, y};
float uv[2], deriv[2][2], alpha;
- pixelTransform(xy, uv, deriv, alpha);
+ pixel_transform(xy, uv, deriv, alpha);
if (alpha == 0.0f) {
zero_v4(output);
return;
}
/* EWA filtering */
- this->m_inputColorProgram->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1]);
+ input_color_program_->read_filtered(output, uv[0], uv[1], deriv[0], deriv[1]);
/* UV to alpha threshold */
- const float threshold = this->m_alpha * 0.05f;
+ const float threshold = alpha_ * 0.05f;
/* XXX alpha threshold is used to fade out pixels on boundaries with invalid derivatives.
* this calculation is not very well defined, should be looked into if it becomes a problem ...
*/
float du = len_v2(deriv[0]);
float dv = len_v2(deriv[1]);
- float factor = 1.0f - threshold * (du / m_inputColorProgram->getWidth() +
- dv / m_inputColorProgram->getHeight());
+ float factor = 1.0f - threshold * (du / input_color_program_->get_width() +
+ dv / input_color_program_->get_height());
if (factor < 0.0f) {
alpha = 0.0f;
}
@@ -112,10 +111,10 @@ bool MapUVOperation::read_uv(float x, float y, float &r_u, float &r_v, float &r_
return true;
}
-void MapUVOperation::pixelTransform(const float xy[2],
- float r_uv[2],
- float r_deriv[2][2],
- float &r_alpha)
+void MapUVOperation::pixel_transform(const float xy[2],
+ float r_uv[2],
+ float r_deriv[2][2],
+ float &r_alpha)
{
float uv[2], alpha; /* temporary variables for derivative estimation */
int num;
@@ -163,37 +162,37 @@ void MapUVOperation::pixelTransform(const float xy[2],
}
}
-void MapUVOperation::deinitExecution()
+void MapUVOperation::deinit_execution()
{
- this->m_inputUVProgram = nullptr;
- this->m_inputColorProgram = nullptr;
+ inputUVProgram_ = nullptr;
+ input_color_program_ = nullptr;
}
-bool MapUVOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool MapUVOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti colorInput;
- rcti uvInput;
+ rcti color_input;
+ rcti uv_input;
NodeOperation *operation = nullptr;
/* the uv buffer only needs a 3x3 buffer. The image needs whole buffer */
- operation = getInputOperation(0);
- colorInput.xmax = operation->getWidth();
- colorInput.xmin = 0;
- colorInput.ymax = operation->getHeight();
- colorInput.ymin = 0;
- if (operation->determineDependingAreaOfInterest(&colorInput, readOperation, output)) {
+ operation = get_input_operation(0);
+ color_input.xmax = operation->get_width();
+ color_input.xmin = 0;
+ color_input.ymax = operation->get_height();
+ color_input.ymin = 0;
+ if (operation->determine_depending_area_of_interest(&color_input, read_operation, output)) {
return true;
}
- operation = getInputOperation(1);
- uvInput.xmax = input->xmax + 1;
- uvInput.xmin = input->xmin - 1;
- uvInput.ymax = input->ymax + 1;
- uvInput.ymin = input->ymin - 1;
- if (operation->determineDependingAreaOfInterest(&uvInput, readOperation, output)) {
+ operation = get_input_operation(1);
+ uv_input.xmax = input->xmax + 1;
+ uv_input.xmin = input->xmin - 1;
+ uv_input.ymax = input->ymax + 1;
+ uv_input.ymin = input->ymin - 1;
+ if (operation->determine_depending_area_of_interest(&uv_input, read_operation, output)) {
return true;
}
@@ -237,7 +236,7 @@ void MapUVOperation::update_memory_buffer_partial(MemoryBuffer *output,
float uv[2];
float deriv[2][2];
float alpha;
- pixelTransform(xy, uv, deriv, alpha);
+ pixel_transform(xy, uv, deriv, alpha);
if (alpha == 0.0f) {
zero_v4(it.out);
continue;
@@ -247,7 +246,7 @@ void MapUVOperation::update_memory_buffer_partial(MemoryBuffer *output,
input_image->read_elem_filtered(uv[0], uv[1], deriv[0], deriv[1], it.out);
/* UV to alpha threshold. */
- const float threshold = this->m_alpha * 0.05f;
+ const float threshold = alpha_ * 0.05f;
/* XXX alpha threshold is used to fade out pixels on boundaries with invalid derivatives.
* this calculation is not very well defined, should be looked into if it becomes a problem ...
*/
diff --git a/source/blender/compositor/operations/COM_MapUVOperation.h b/source/blender/compositor/operations/COM_MapUVOperation.h
index 49c6689f700..38d848f61a0 100644
--- a/source/blender/compositor/operations/COM_MapUVOperation.h
+++ b/source/blender/compositor/operations/COM_MapUVOperation.h
@@ -27,17 +27,17 @@ class MapUVOperation : public MultiThreadedOperation {
static constexpr int IMAGE_INPUT_INDEX = 0;
static constexpr int UV_INPUT_INDEX = 1;
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputUVProgram;
- SocketReader *m_inputColorProgram;
+ SocketReader *inputUVProgram_;
+ SocketReader *input_color_program_;
int uv_width_;
int uv_height_;
int image_width_;
int image_height_;
- float m_alpha;
+ float alpha_;
std::function<void(float x, float y, float *out)> uv_input_read_fn_;
@@ -47,32 +47,32 @@ class MapUVOperation : public MultiThreadedOperation {
/**
* we need a 3x3 differential filter for UV Input and full buffer for the image
*/
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2], float &r_alpha);
+ void pixel_transform(const float xy[2], float r_uv[2], float r_deriv[2][2], float &r_alpha);
void init_data() override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setAlpha(float alpha)
+ void set_alpha(float alpha)
{
- this->m_alpha = alpha;
+ alpha_ = alpha;
}
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
diff --git a/source/blender/compositor/operations/COM_MapValueOperation.cc b/source/blender/compositor/operations/COM_MapValueOperation.cc
index 94fecc3f49e..1e6570f2f64 100644
--- a/source/blender/compositor/operations/COM_MapValueOperation.cc
+++ b/source/blender/compositor/operations/COM_MapValueOperation.cc
@@ -22,25 +22,25 @@ namespace blender::compositor {
MapValueOperation::MapValueOperation()
{
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
- this->m_inputOperation = nullptr;
- flags.can_be_constant = true;
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
+ input_operation_ = nullptr;
+ flags_.can_be_constant = true;
}
-void MapValueOperation::initExecution()
+void MapValueOperation::init_execution()
{
- this->m_inputOperation = this->getInputSocketReader(0);
+ input_operation_ = this->get_input_socket_reader(0);
}
-void MapValueOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MapValueOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float src[4];
- this->m_inputOperation->readSampled(src, x, y, sampler);
- TexMapping *texmap = this->m_settings;
+ input_operation_->read_sampled(src, x, y, sampler);
+ TexMapping *texmap = settings_;
float value = (src[0] + texmap->loc[0]) * texmap->size[0];
if (texmap->flag & TEXMAP_CLIP_MIN) {
if (value < texmap->min[0]) {
@@ -56,9 +56,9 @@ void MapValueOperation::executePixelSampled(float output[4],
output[0] = value;
}
-void MapValueOperation::deinitExecution()
+void MapValueOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
+ input_operation_ = nullptr;
}
void MapValueOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -67,7 +67,7 @@ void MapValueOperation::update_memory_buffer_partial(MemoryBuffer *output,
{
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
const float input = *it.in(0);
- TexMapping *texmap = this->m_settings;
+ TexMapping *texmap = settings_;
float value = (input + texmap->loc[0]) * texmap->size[0];
if (texmap->flag & TEXMAP_CLIP_MIN) {
if (value < texmap->min[0]) {
diff --git a/source/blender/compositor/operations/COM_MapValueOperation.h b/source/blender/compositor/operations/COM_MapValueOperation.h
index a595eac3155..77d3a4a2932 100644
--- a/source/blender/compositor/operations/COM_MapValueOperation.h
+++ b/source/blender/compositor/operations/COM_MapValueOperation.h
@@ -30,10 +30,10 @@ namespace blender::compositor {
class MapValueOperation : public MultiThreadedOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputOperation;
- TexMapping *m_settings;
+ SocketReader *input_operation_;
+ TexMapping *settings_;
public:
/**
@@ -44,24 +44,24 @@ class MapValueOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
/**
* \brief set the TexMapping settings
*/
- void setSettings(TexMapping *settings)
+ void set_settings(TexMapping *settings)
{
- this->m_settings = settings;
+ settings_ = settings;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_MaskOperation.cc b/source/blender/compositor/operations/COM_MaskOperation.cc
index 65b89a8c79a..4e4cc820edb 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.cc
+++ b/source/blender/compositor/operations/COM_MaskOperation.cc
@@ -18,11 +18,6 @@
#include "COM_MaskOperation.h"
-#include "MEM_guardedalloc.h"
-
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-
#include "BKE_lib_id.h"
#include "BKE_mask.h"
@@ -30,40 +25,35 @@ namespace blender::compositor {
MaskOperation::MaskOperation()
{
- this->addOutputSocket(DataType::Value);
- this->m_mask = nullptr;
- this->m_maskWidth = 0;
- this->m_maskHeight = 0;
- this->m_maskWidthInv = 0.0f;
- this->m_maskHeightInv = 0.0f;
- this->m_frame_shutter = 0.0f;
- this->m_frame_number = 0;
- this->m_rasterMaskHandleTot = 1;
- memset(this->m_rasterMaskHandles, 0, sizeof(this->m_rasterMaskHandles));
+ this->add_output_socket(DataType::Value);
+ mask_ = nullptr;
+ mask_width_ = 0;
+ mask_height_ = 0;
+ mask_width_inv_ = 0.0f;
+ mask_height_inv_ = 0.0f;
+ frame_shutter_ = 0.0f;
+ frame_number_ = 0;
+ raster_mask_handle_tot_ = 1;
+ memset(raster_mask_handles_, 0, sizeof(raster_mask_handles_));
}
-void MaskOperation::initExecution()
+void MaskOperation::init_execution()
{
- if (this->m_mask && this->m_rasterMaskHandles[0] == nullptr) {
- if (this->m_rasterMaskHandleTot == 1) {
- this->m_rasterMaskHandles[0] = BKE_maskrasterize_handle_new();
-
- BKE_maskrasterize_handle_init(this->m_rasterMaskHandles[0],
- this->m_mask,
- this->m_maskWidth,
- this->m_maskHeight,
- true,
- true,
- this->m_do_feather);
+ if (mask_ && raster_mask_handles_[0] == nullptr) {
+ if (raster_mask_handle_tot_ == 1) {
+ raster_mask_handles_[0] = BKE_maskrasterize_handle_new();
+
+ BKE_maskrasterize_handle_init(
+ raster_mask_handles_[0], mask_, mask_width_, mask_height_, true, true, do_feather_);
}
else {
/* make a throw away copy of the mask */
- const float frame = (float)this->m_frame_number - this->m_frame_shutter;
- const float frame_step = (this->m_frame_shutter * 2.0f) / this->m_rasterMaskHandleTot;
+ const float frame = (float)frame_number_ - frame_shutter_;
+ const float frame_step = (frame_shutter_ * 2.0f) / raster_mask_handle_tot_;
float frame_iter = frame;
Mask *mask_temp = (Mask *)BKE_id_copy_ex(
- nullptr, &this->m_mask->id, nullptr, LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA);
+ nullptr, &mask_->id, nullptr, LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA);
/* trick so we can get unkeyed edits to display */
{
@@ -72,24 +62,24 @@ void MaskOperation::initExecution()
for (masklay = (MaskLayer *)mask_temp->masklayers.first; masklay;
masklay = masklay->next) {
- masklay_shape = BKE_mask_layer_shape_verify_frame(masklay, this->m_frame_number);
+ masklay_shape = BKE_mask_layer_shape_verify_frame(masklay, frame_number_);
BKE_mask_layer_shape_from_mask(masklay, masklay_shape);
}
}
- for (unsigned int i = 0; i < this->m_rasterMaskHandleTot; i++) {
- this->m_rasterMaskHandles[i] = BKE_maskrasterize_handle_new();
+ for (unsigned int i = 0; i < raster_mask_handle_tot_; i++) {
+ raster_mask_handles_[i] = BKE_maskrasterize_handle_new();
/* re-eval frame info */
BKE_mask_evaluate(mask_temp, frame_iter, true);
- BKE_maskrasterize_handle_init(this->m_rasterMaskHandles[i],
+ BKE_maskrasterize_handle_init(raster_mask_handles_[i],
mask_temp,
- this->m_maskWidth,
- this->m_maskHeight,
+ mask_width_,
+ mask_height_,
true,
true,
- this->m_do_feather);
+ do_feather_);
frame_iter += frame_step;
}
@@ -99,41 +89,41 @@ void MaskOperation::initExecution()
}
}
-void MaskOperation::deinitExecution()
+void MaskOperation::deinit_execution()
{
- for (unsigned int i = 0; i < this->m_rasterMaskHandleTot; i++) {
- if (this->m_rasterMaskHandles[i]) {
- BKE_maskrasterize_handle_free(this->m_rasterMaskHandles[i]);
- this->m_rasterMaskHandles[i] = nullptr;
+ for (unsigned int i = 0; i < raster_mask_handle_tot_; i++) {
+ if (raster_mask_handles_[i]) {
+ BKE_maskrasterize_handle_free(raster_mask_handles_[i]);
+ raster_mask_handles_[i] = nullptr;
}
}
}
void MaskOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
- if (this->m_maskWidth == 0 || this->m_maskHeight == 0) {
+ if (mask_width_ == 0 || mask_height_ == 0) {
r_area = COM_AREA_NONE;
}
else {
r_area = preferred_area;
- r_area.xmax = r_area.xmin + m_maskWidth;
- r_area.ymax = r_area.ymin + m_maskHeight;
+ r_area.xmax = r_area.xmin + mask_width_;
+ r_area.ymax = r_area.ymin + mask_height_;
}
}
-void MaskOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler /*sampler*/)
+void MaskOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
const float xy[2] = {
- (x * this->m_maskWidthInv) + this->m_mask_px_ofs[0],
- (y * this->m_maskHeightInv) + this->m_mask_px_ofs[1],
+ (x * mask_width_inv_) + mask_px_ofs_[0],
+ (y * mask_height_inv_) + mask_px_ofs_[1],
};
- if (this->m_rasterMaskHandleTot == 1) {
- if (this->m_rasterMaskHandles[0]) {
- output[0] = BKE_maskrasterize_handle_sample(this->m_rasterMaskHandles[0], xy);
+ if (raster_mask_handle_tot_ == 1) {
+ if (raster_mask_handles_[0]) {
+ output[0] = BKE_maskrasterize_handle_sample(raster_mask_handles_[0], xy);
}
else {
output[0] = 0.0f;
@@ -143,14 +133,14 @@ void MaskOperation::executePixelSampled(float output[4],
/* In case loop below fails. */
output[0] = 0.0f;
- for (unsigned int i = 0; i < this->m_rasterMaskHandleTot; i++) {
- if (this->m_rasterMaskHandles[i]) {
- output[0] += BKE_maskrasterize_handle_sample(this->m_rasterMaskHandles[i], xy);
+ for (unsigned int i = 0; i < raster_mask_handle_tot_; i++) {
+ if (raster_mask_handles_[i]) {
+ output[0] += BKE_maskrasterize_handle_sample(raster_mask_handles_[i], xy);
}
}
/* until we get better falloff */
- output[0] /= this->m_rasterMaskHandleTot;
+ output[0] /= raster_mask_handle_tot_;
}
}
@@ -166,23 +156,23 @@ void MaskOperation::update_memory_buffer_partial(MemoryBuffer *output,
float xy[2];
for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
- xy[0] = it.x * m_maskWidthInv + m_mask_px_ofs[0];
- xy[1] = it.y * m_maskHeightInv + m_mask_px_ofs[1];
+ xy[0] = it.x * mask_width_inv_ + mask_px_ofs_[0];
+ xy[1] = it.y * mask_height_inv_ + mask_px_ofs_[1];
*it.out = 0.0f;
for (MaskRasterHandle *handle : handles) {
*it.out += BKE_maskrasterize_handle_sample(handle, xy);
}
/* Until we get better falloff. */
- *it.out /= m_rasterMaskHandleTot;
+ *it.out /= raster_mask_handle_tot_;
}
}
Vector<MaskRasterHandle *> MaskOperation::get_non_null_handles() const
{
Vector<MaskRasterHandle *> handles;
- for (int i = 0; i < m_rasterMaskHandleTot; i++) {
- MaskRasterHandle *handle = m_rasterMaskHandles[i];
+ for (int i = 0; i < raster_mask_handle_tot_; i++) {
+ MaskRasterHandle *handle = raster_mask_handles_[i];
if (handle == nullptr) {
continue;
}
diff --git a/source/blender/compositor/operations/COM_MaskOperation.h b/source/blender/compositor/operations/COM_MaskOperation.h
index cc7eb0c022c..5fc0ed96c22 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.h
+++ b/source/blender/compositor/operations/COM_MaskOperation.h
@@ -33,23 +33,23 @@ namespace blender::compositor {
*/
class MaskOperation : public MultiThreadedOperation {
protected:
- Mask *m_mask;
+ Mask *mask_;
/* NOTE: these are used more like aspect,
* but they _do_ impact on mask detail */
- int m_maskWidth;
- int m_maskHeight;
- float m_maskWidthInv; /* `1 / m_maskWidth` */
- float m_maskHeightInv; /* `1 / m_maskHeight` */
- float m_mask_px_ofs[2];
+ int mask_width_;
+ int mask_height_;
+ float mask_width_inv_; /* `1 / mask_width_` */
+ float mask_height_inv_; /* `1 / mask_height_` */
+ float mask_px_ofs_[2];
- float m_frame_shutter;
- int m_frame_number;
+ float frame_shutter_;
+ int frame_number_;
- bool m_do_feather;
+ bool do_feather_;
- struct MaskRasterHandle *m_rasterMaskHandles[CMP_NODE_MASK_MBLUR_SAMPLES_MAX];
- unsigned int m_rasterMaskHandleTot;
+ struct MaskRasterHandle *raster_mask_handles_[CMP_NODE_MASK_MBLUR_SAMPLES_MAX];
+ unsigned int raster_mask_handle_tot_;
/**
* Determine the output resolution. The resolution is retrieved from the Renderer
@@ -59,44 +59,44 @@ class MaskOperation : public MultiThreadedOperation {
public:
MaskOperation();
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void setMask(Mask *mask)
+ void set_mask(Mask *mask)
{
- this->m_mask = mask;
+ mask_ = mask;
}
- void setMaskWidth(int width)
+ void set_mask_width(int width)
{
- this->m_maskWidth = width;
- this->m_maskWidthInv = 1.0f / (float)width;
- this->m_mask_px_ofs[0] = this->m_maskWidthInv * 0.5f;
+ mask_width_ = width;
+ mask_width_inv_ = 1.0f / (float)width;
+ mask_px_ofs_[0] = mask_width_inv_ * 0.5f;
}
- void setMaskHeight(int height)
+ void set_mask_height(int height)
{
- this->m_maskHeight = height;
- this->m_maskHeightInv = 1.0f / (float)height;
- this->m_mask_px_ofs[1] = this->m_maskHeightInv * 0.5f;
+ mask_height_ = height;
+ mask_height_inv_ = 1.0f / (float)height;
+ mask_px_ofs_[1] = mask_height_inv_ * 0.5f;
}
- void setFramenumber(int frame_number)
+ void set_framenumber(int frame_number)
{
- this->m_frame_number = frame_number;
+ frame_number_ = frame_number;
}
- void setFeather(bool feather)
+ void set_feather(bool feather)
{
- this->m_do_feather = feather;
+ do_feather_ = feather;
}
- void setMotionBlurSamples(int samples)
+ void set_motion_blur_samples(int samples)
{
- this->m_rasterMaskHandleTot = MIN2(MAX2(1, samples), CMP_NODE_MASK_MBLUR_SAMPLES_MAX);
+ raster_mask_handle_tot_ = MIN2(MAX2(1, samples), CMP_NODE_MASK_MBLUR_SAMPLES_MAX);
}
- void setMotionBlurShutter(float shutter)
+ void set_motion_blur_shutter(float shutter)
{
- this->m_frame_shutter = shutter;
+ frame_shutter_ = shutter;
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cc b/source/blender/compositor/operations/COM_MathBaseOperation.cc
index d3fb83caf7c..1a4684ae3f0 100644
--- a/source/blender/compositor/operations/COM_MathBaseOperation.cc
+++ b/source/blender/compositor/operations/COM_MathBaseOperation.cc
@@ -18,44 +18,42 @@
#include "COM_MathBaseOperation.h"
-#include "BLI_math.h"
-
namespace blender::compositor {
MathBaseOperation::MathBaseOperation()
{
/* TODO(manzanilla): after removing tiled implementation, template this class to only add needed
* number of inputs. */
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
- this->m_inputValue1Operation = nullptr;
- this->m_inputValue2Operation = nullptr;
- this->m_inputValue3Operation = nullptr;
- this->m_useClamp = false;
- this->flags.can_be_constant = true;
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
+ input_value1_operation_ = nullptr;
+ input_value2_operation_ = nullptr;
+ input_value3_operation_ = nullptr;
+ use_clamp_ = false;
+ flags_.can_be_constant = true;
}
-void MathBaseOperation::initExecution()
+void MathBaseOperation::init_execution()
{
- this->m_inputValue1Operation = this->getInputSocketReader(0);
- this->m_inputValue2Operation = this->getInputSocketReader(1);
- this->m_inputValue3Operation = this->getInputSocketReader(2);
+ input_value1_operation_ = this->get_input_socket_reader(0);
+ input_value2_operation_ = this->get_input_socket_reader(1);
+ input_value3_operation_ = this->get_input_socket_reader(2);
}
-void MathBaseOperation::deinitExecution()
+void MathBaseOperation::deinit_execution()
{
- this->m_inputValue1Operation = nullptr;
- this->m_inputValue2Operation = nullptr;
- this->m_inputValue3Operation = nullptr;
+ input_value1_operation_ = nullptr;
+ input_value2_operation_ = nullptr;
+ input_value3_operation_ = nullptr;
}
void MathBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
NodeOperationInput *socket;
- rcti temp_area;
- socket = this->getInputSocket(0);
+ rcti temp_area = COM_AREA_NONE;
+ socket = this->get_input_socket(0);
const bool determined = socket->determine_canvas(COM_AREA_NONE, temp_area);
if (determined) {
this->set_canvas_input_index(0);
@@ -66,9 +64,9 @@ void MathBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_are
NodeOperation::determine_canvas(preferred_area, r_area);
}
-void MathBaseOperation::clampIfNeeded(float *color)
+void MathBaseOperation::clamp_if_needed(float *color)
{
- if (this->m_useClamp) {
+ if (use_clamp_) {
CLAMP(color[0], 0.0f, 1.0f);
}
}
@@ -81,70 +79,73 @@ void MathBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
update_memory_buffer_partial(it);
}
-void MathAddOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MathAddOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = inputValue1[0] + inputValue2[0];
+ output[0] = input_value1[0] + input_value2[0];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
-void MathSubtractOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathSubtractOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = inputValue1[0] - inputValue2[0];
+ output[0] = input_value1[0] - input_value2[0];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
-void MathMultiplyOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathMultiplyOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = inputValue1[0] * inputValue2[0];
+ output[0] = input_value1[0] * input_value2[0];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
-void MathDivideOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathDivideOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- if (inputValue2[0] == 0) { /* We don't want to divide by zero. */
+ if (input_value2[0] == 0) { /* We don't want to divide by zero. */
output[0] = 0.0;
}
else {
- output[0] = inputValue1[0] / inputValue2[0];
+ output[0] = input_value1[0] / input_value2[0];
}
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathDivideOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -155,20 +156,20 @@ void MathDivideOperation::update_memory_buffer_partial(BuffersIterator<float> &i
}
}
-void MathSineOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathSineOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = sin(inputValue1[0]);
+ output[0] = sin(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathSineOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -179,20 +180,20 @@ void MathSineOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
}
}
-void MathCosineOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathCosineOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = cos(inputValue1[0]);
+ output[0] = cos(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathCosineOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -203,20 +204,20 @@ void MathCosineOperation::update_memory_buffer_partial(BuffersIterator<float> &i
}
}
-void MathTangentOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathTangentOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = tan(inputValue1[0]);
+ output[0] = tan(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathTangentOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -227,20 +228,20 @@ void MathTangentOperation::update_memory_buffer_partial(BuffersIterator<float> &
}
}
-void MathHyperbolicSineOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathHyperbolicSineOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = sinh(inputValue1[0]);
+ output[0] = sinh(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathHyperbolicSineOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -251,20 +252,20 @@ void MathHyperbolicSineOperation::update_memory_buffer_partial(BuffersIterator<f
}
}
-void MathHyperbolicCosineOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathHyperbolicCosineOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = cosh(inputValue1[0]);
+ output[0] = cosh(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathHyperbolicCosineOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -275,20 +276,20 @@ void MathHyperbolicCosineOperation::update_memory_buffer_partial(BuffersIterator
}
}
-void MathHyperbolicTangentOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathHyperbolicTangentOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = tanh(inputValue1[0]);
+ output[0] = tanh(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathHyperbolicTangentOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -299,25 +300,25 @@ void MathHyperbolicTangentOperation::update_memory_buffer_partial(BuffersIterato
}
}
-void MathArcSineOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathArcSineOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- if (inputValue1[0] <= 1 && inputValue1[0] >= -1) {
- output[0] = asin(inputValue1[0]);
+ if (input_value1[0] <= 1 && input_value1[0] >= -1) {
+ output[0] = asin(input_value1[0]);
}
else {
output[0] = 0.0;
}
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathArcSineOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -328,25 +329,25 @@ void MathArcSineOperation::update_memory_buffer_partial(BuffersIterator<float> &
}
}
-void MathArcCosineOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathArcCosineOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- if (inputValue1[0] <= 1 && inputValue1[0] >= -1) {
- output[0] = acos(inputValue1[0]);
+ if (input_value1[0] <= 1 && input_value1[0] >= -1) {
+ output[0] = acos(input_value1[0]);
}
else {
output[0] = 0.0;
}
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathArcCosineOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -357,20 +358,20 @@ void MathArcCosineOperation::update_memory_buffer_partial(BuffersIterator<float>
}
}
-void MathArcTangentOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathArcTangentOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = atan(inputValue1[0]);
+ output[0] = atan(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathArcTangentOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -381,32 +382,32 @@ void MathArcTangentOperation::update_memory_buffer_partial(BuffersIterator<float
}
}
-void MathPowerOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathPowerOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- if (inputValue1[0] >= 0) {
- output[0] = pow(inputValue1[0], inputValue2[0]);
+ if (input_value1[0] >= 0) {
+ output[0] = pow(input_value1[0], input_value2[0]);
}
else {
- float y_mod_1 = fmod(inputValue2[0], 1);
+ float y_mod_1 = fmod(input_value2[0], 1);
/* if input value is not nearly an integer, fall back to zero, nicer than straight rounding */
if (y_mod_1 > 0.999f || y_mod_1 < 0.001f) {
- output[0] = pow(inputValue1[0], floorf(inputValue2[0] + 0.5f));
+ output[0] = pow(input_value1[0], floorf(input_value2[0] + 0.5f));
}
else {
output[0] = 0.0;
}
}
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathPowerOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -432,25 +433,25 @@ void MathPowerOperation::update_memory_buffer_partial(BuffersIterator<float> &it
}
}
-void MathLogarithmOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathLogarithmOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- if (inputValue1[0] > 0 && inputValue2[0] > 0) {
- output[0] = log(inputValue1[0]) / log(inputValue2[0]);
+ if (input_value1[0] > 0 && input_value2[0] > 0) {
+ output[0] = log(input_value1[0]) / log(input_value2[0]);
}
else {
output[0] = 0.0;
}
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathLogarithmOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -468,20 +469,20 @@ void MathLogarithmOperation::update_memory_buffer_partial(BuffersIterator<float>
}
}
-void MathMinimumOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathMinimumOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = MIN2(inputValue1[0], inputValue2[0]);
+ output[0] = MIN2(input_value1[0], input_value2[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathMinimumOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -492,20 +493,20 @@ void MathMinimumOperation::update_memory_buffer_partial(BuffersIterator<float> &
}
}
-void MathMaximumOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathMaximumOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = MAX2(inputValue1[0], inputValue2[0]);
+ output[0] = MAX2(input_value1[0], input_value2[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathMaximumOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -516,20 +517,20 @@ void MathMaximumOperation::update_memory_buffer_partial(BuffersIterator<float> &
}
}
-void MathRoundOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathRoundOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = round(inputValue1[0]);
+ output[0] = round(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathRoundOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -540,57 +541,57 @@ void MathRoundOperation::update_memory_buffer_partial(BuffersIterator<float> &it
}
}
-void MathLessThanOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathLessThanOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = inputValue1[0] < inputValue2[0] ? 1.0f : 0.0f;
+ output[0] = input_value1[0] < input_value2[0] ? 1.0f : 0.0f;
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
-void MathGreaterThanOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathGreaterThanOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = inputValue1[0] > inputValue2[0] ? 1.0f : 0.0f;
+ output[0] = input_value1[0] > input_value2[0] ? 1.0f : 0.0f;
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
-void MathModuloOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathModuloOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- if (inputValue2[0] == 0) {
+ if (input_value2[0] == 0) {
output[0] = 0.0;
}
else {
- output[0] = fmod(inputValue1[0], inputValue2[0]);
+ output[0] = fmod(input_value1[0], input_value2[0]);
}
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathModuloOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -602,18 +603,18 @@ void MathModuloOperation::update_memory_buffer_partial(BuffersIterator<float> &i
}
}
-void MathAbsoluteOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathAbsoluteOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
+ float input_value1[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
- output[0] = fabs(inputValue1[0]);
+ output[0] = fabs(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathAbsoluteOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -624,18 +625,18 @@ void MathAbsoluteOperation::update_memory_buffer_partial(BuffersIterator<float>
}
}
-void MathRadiansOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathRadiansOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
+ float input_value1[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
- output[0] = DEG2RADF(inputValue1[0]);
+ output[0] = DEG2RADF(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathRadiansOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -646,18 +647,18 @@ void MathRadiansOperation::update_memory_buffer_partial(BuffersIterator<float> &
}
}
-void MathDegreesOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathDegreesOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
+ float input_value1[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
- output[0] = RAD2DEGF(inputValue1[0]);
+ output[0] = RAD2DEGF(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathDegreesOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -668,20 +669,20 @@ void MathDegreesOperation::update_memory_buffer_partial(BuffersIterator<float> &
}
}
-void MathArcTan2Operation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathArcTan2Operation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = atan2(inputValue1[0], inputValue2[0]);
+ output[0] = atan2(input_value1[0], input_value2[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathArcTan2Operation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -692,18 +693,18 @@ void MathArcTan2Operation::update_memory_buffer_partial(BuffersIterator<float> &
}
}
-void MathFloorOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathFloorOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
+ float input_value1[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
- output[0] = floor(inputValue1[0]);
+ output[0] = floor(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathFloorOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -714,18 +715,18 @@ void MathFloorOperation::update_memory_buffer_partial(BuffersIterator<float> &it
}
}
-void MathCeilOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathCeilOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
+ float input_value1[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
- output[0] = ceil(inputValue1[0]);
+ output[0] = ceil(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathCeilOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -736,18 +737,18 @@ void MathCeilOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
}
}
-void MathFractOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathFractOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
+ float input_value1[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
- output[0] = inputValue1[0] - floor(inputValue1[0]);
+ output[0] = input_value1[0] - floor(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathFractOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -758,23 +759,23 @@ void MathFractOperation::update_memory_buffer_partial(BuffersIterator<float> &it
}
}
-void MathSqrtOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathSqrtOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
+ float input_value1[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
- if (inputValue1[0] > 0) {
- output[0] = sqrt(inputValue1[0]);
+ if (input_value1[0] > 0) {
+ output[0] = sqrt(input_value1[0]);
}
else {
output[0] = 0.0f;
}
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathSqrtOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -785,23 +786,23 @@ void MathSqrtOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
}
}
-void MathInverseSqrtOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathInverseSqrtOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
+ float input_value1[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
- if (inputValue1[0] > 0) {
- output[0] = 1.0f / sqrt(inputValue1[0]);
+ if (input_value1[0] > 0) {
+ output[0] = 1.0f / sqrt(input_value1[0]);
}
else {
output[0] = 0.0f;
}
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathInverseSqrtOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -812,18 +813,18 @@ void MathInverseSqrtOperation::update_memory_buffer_partial(BuffersIterator<floa
}
}
-void MathSignOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathSignOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
+ float input_value1[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
- output[0] = compatible_signf(inputValue1[0]);
+ output[0] = compatible_signf(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathSignOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -834,18 +835,18 @@ void MathSignOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
}
}
-void MathExponentOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathExponentOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
+ float input_value1[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
- output[0] = expf(inputValue1[0]);
+ output[0] = expf(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathExponentOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -856,18 +857,18 @@ void MathExponentOperation::update_memory_buffer_partial(BuffersIterator<float>
}
}
-void MathTruncOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathTruncOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
+ float input_value1[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
- output[0] = (inputValue1[0] >= 0.0f) ? floor(inputValue1[0]) : ceil(inputValue1[0]);
+ output[0] = (input_value1[0] >= 0.0f) ? floor(input_value1[0]) : ceil(input_value1[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathTruncOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -879,25 +880,25 @@ void MathTruncOperation::update_memory_buffer_partial(BuffersIterator<float> &it
}
}
-void MathSnapOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathSnapOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- if (inputValue1[0] == 0 || inputValue2[0] == 0) { /* We don't want to divide by zero. */
+ if (input_value1[0] == 0 || input_value2[0] == 0) { /* We don't want to divide by zero. */
output[0] = 0.0f;
}
else {
- output[0] = floorf(inputValue1[0] / inputValue2[0]) * inputValue2[0];
+ output[0] = floorf(input_value1[0] / input_value2[0]) * input_value2[0];
}
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathSnapOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -915,22 +916,22 @@ void MathSnapOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
}
}
-void MathWrapOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathWrapOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
- float inputValue3[4];
+ float input_value1[4];
+ float input_value2[4];
+ float input_value3[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
- this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
+ input_value3_operation_->read_sampled(input_value3, x, y, sampler);
- output[0] = wrapf(inputValue1[0], inputValue2[0], inputValue3[0]);
+ output[0] = wrapf(input_value1[0], input_value2[0], input_value3[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathWrapOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -941,20 +942,20 @@ void MathWrapOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
}
}
-void MathPingpongOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathPingpongOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
+ float input_value1[4];
+ float input_value2[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
- output[0] = pingpongf(inputValue1[0], inputValue2[0]);
+ output[0] = pingpongf(input_value1[0], input_value2[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathPingpongOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -965,23 +966,23 @@ void MathPingpongOperation::update_memory_buffer_partial(BuffersIterator<float>
}
}
-void MathCompareOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathCompareOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
- float inputValue3[4];
+ float input_value1[4];
+ float input_value2[4];
+ float input_value3[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
- this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
+ input_value3_operation_->read_sampled(input_value3, x, y, sampler);
- output[0] = (fabsf(inputValue1[0] - inputValue2[0]) <= MAX2(inputValue3[0], 1e-5f)) ? 1.0f :
- 0.0f;
+ output[0] = (fabsf(input_value1[0] - input_value2[0]) <= MAX2(input_value3[0], 1e-5f)) ? 1.0f :
+ 0.0f;
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathCompareOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -992,22 +993,22 @@ void MathCompareOperation::update_memory_buffer_partial(BuffersIterator<float> &
}
}
-void MathMultiplyAddOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathMultiplyAddOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
- float inputValue3[4];
+ float input_value1[4];
+ float input_value2[4];
+ float input_value3[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
- this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
+ input_value3_operation_->read_sampled(input_value3, x, y, sampler);
- output[0] = inputValue1[0] * inputValue2[0] + inputValue3[0];
+ output[0] = input_value1[0] * input_value2[0] + input_value3[0];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathMultiplyAddOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -1018,22 +1019,22 @@ void MathMultiplyAddOperation::update_memory_buffer_partial(BuffersIterator<floa
}
}
-void MathSmoothMinOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathSmoothMinOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
- float inputValue3[4];
+ float input_value1[4];
+ float input_value2[4];
+ float input_value3[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
- this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
+ input_value3_operation_->read_sampled(input_value3, x, y, sampler);
- output[0] = smoothminf(inputValue1[0], inputValue2[0], inputValue3[0]);
+ output[0] = smoothminf(input_value1[0], input_value2[0], input_value3[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathSmoothMinOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
@@ -1044,22 +1045,22 @@ void MathSmoothMinOperation::update_memory_buffer_partial(BuffersIterator<float>
}
}
-void MathSmoothMaxOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MathSmoothMaxOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue1[4];
- float inputValue2[4];
- float inputValue3[4];
+ float input_value1[4];
+ float input_value2[4];
+ float input_value3[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
- this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler);
+ input_value1_operation_->read_sampled(input_value1, x, y, sampler);
+ input_value2_operation_->read_sampled(input_value2, x, y, sampler);
+ input_value3_operation_->read_sampled(input_value3, x, y, sampler);
- output[0] = -smoothminf(-inputValue1[0], -inputValue2[0], inputValue3[0]);
+ output[0] = -smoothminf(-input_value1[0], -input_value2[0], input_value3[0]);
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MathSmoothMaxOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.h b/source/blender/compositor/operations/COM_MathBaseOperation.h
index 0188eb50fa8..dc5a16ba4a1 100644
--- a/source/blender/compositor/operations/COM_MathBaseOperation.h
+++ b/source/blender/compositor/operations/COM_MathBaseOperation.h
@@ -29,13 +29,13 @@ namespace blender::compositor {
class MathBaseOperation : public MultiThreadedOperation {
protected:
/**
- * Prefetched reference to the inputProgram
+ * Prefetched reference to the input_program
*/
- SocketReader *m_inputValue1Operation;
- SocketReader *m_inputValue2Operation;
- SocketReader *m_inputValue3Operation;
+ SocketReader *input_value1_operation_;
+ SocketReader *input_value2_operation_;
+ SocketReader *input_value3_operation_;
- bool m_useClamp;
+ bool use_clamp_;
protected:
/**
@@ -44,11 +44,11 @@ class MathBaseOperation : public MultiThreadedOperation {
MathBaseOperation();
/* TODO(manzanilla): to be removed with tiled implementation. */
- void clampIfNeeded(float color[4]);
+ void clamp_if_needed(float color[4]);
float clamp_when_enabled(float value)
{
- if (this->m_useClamp) {
+ if (use_clamp_) {
return CLAMPIS(value, 0.0f, 1.0f);
}
return value;
@@ -56,7 +56,7 @@ class MathBaseOperation : public MultiThreadedOperation {
void clamp_when_enabled(float *out)
{
- if (this->m_useClamp) {
+ if (use_clamp_) {
CLAMP(*out, 0.0f, 1.0f);
}
}
@@ -65,21 +65,21 @@ class MathBaseOperation : public MultiThreadedOperation {
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
/**
* Determine resolution
*/
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
- void setUseClamp(bool value)
+ void set_use_clamp(bool value)
{
- this->m_useClamp = value;
+ use_clamp_ = value;
}
void update_memory_buffer_partial(MemoryBuffer *output,
@@ -104,40 +104,40 @@ class MathFunctor2Operation : public MathBaseOperation {
class MathAddOperation : public MathFunctor2Operation<std::plus> {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
};
class MathSubtractOperation : public MathFunctor2Operation<std::minus> {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
};
class MathMultiplyOperation : public MathFunctor2Operation<std::multiplies> {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
};
class MathDivideOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathSineOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathCosineOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathTangentOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -145,21 +145,21 @@ class MathTangentOperation : public MathBaseOperation {
class MathHyperbolicSineOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathHyperbolicCosineOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathHyperbolicTangentOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -167,72 +167,72 @@ class MathHyperbolicTangentOperation : public MathBaseOperation {
class MathArcSineOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathArcCosineOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathArcTangentOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathPowerOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathLogarithmOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathMinimumOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathMaximumOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathRoundOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathLessThanOperation : public MathFunctor2Operation<std::less> {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
};
class MathGreaterThanOperation : public MathFunctor2Operation<std::greater> {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
};
class MathModuloOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -240,7 +240,7 @@ class MathModuloOperation : public MathBaseOperation {
class MathAbsoluteOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -248,7 +248,7 @@ class MathAbsoluteOperation : public MathBaseOperation {
class MathRadiansOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -256,7 +256,7 @@ class MathRadiansOperation : public MathBaseOperation {
class MathDegreesOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -264,7 +264,7 @@ class MathDegreesOperation : public MathBaseOperation {
class MathArcTan2Operation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -272,7 +272,7 @@ class MathArcTan2Operation : public MathBaseOperation {
class MathFloorOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -280,7 +280,7 @@ class MathFloorOperation : public MathBaseOperation {
class MathCeilOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -288,7 +288,7 @@ class MathCeilOperation : public MathBaseOperation {
class MathFractOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -296,7 +296,7 @@ class MathFractOperation : public MathBaseOperation {
class MathSqrtOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -304,7 +304,7 @@ class MathSqrtOperation : public MathBaseOperation {
class MathInverseSqrtOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -312,7 +312,7 @@ class MathInverseSqrtOperation : public MathBaseOperation {
class MathSignOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -320,7 +320,7 @@ class MathSignOperation : public MathBaseOperation {
class MathExponentOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -328,7 +328,7 @@ class MathExponentOperation : public MathBaseOperation {
class MathTruncOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -336,7 +336,7 @@ class MathTruncOperation : public MathBaseOperation {
class MathSnapOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -344,7 +344,7 @@ class MathSnapOperation : public MathBaseOperation {
class MathWrapOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -352,7 +352,7 @@ class MathWrapOperation : public MathBaseOperation {
class MathPingpongOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -360,7 +360,7 @@ class MathPingpongOperation : public MathBaseOperation {
class MathCompareOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -368,7 +368,7 @@ class MathCompareOperation : public MathBaseOperation {
class MathMultiplyAddOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -376,7 +376,7 @@ class MathMultiplyAddOperation : public MathBaseOperation {
class MathSmoothMinOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
@@ -384,7 +384,7 @@ class MathSmoothMinOperation : public MathBaseOperation {
class MathSmoothMaxOperation : public MathBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
diff --git a/source/blender/compositor/operations/COM_MixOperation.cc b/source/blender/compositor/operations/COM_MixOperation.cc
index 895d32e6fee..edae4454b13 100644
--- a/source/blender/compositor/operations/COM_MixOperation.cc
+++ b/source/blender/compositor/operations/COM_MixOperation.cc
@@ -18,66 +18,67 @@
#include "COM_MixOperation.h"
-#include "BLI_math.h"
-
namespace blender::compositor {
/* ******** Mix Base Operation ******** */
MixBaseOperation::MixBaseOperation()
{
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
- this->m_inputValueOperation = nullptr;
- this->m_inputColor1Operation = nullptr;
- this->m_inputColor2Operation = nullptr;
- this->setUseValueAlphaMultiply(false);
- this->setUseClamp(false);
- flags.can_be_constant = true;
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ input_value_operation_ = nullptr;
+ input_color1_operation_ = nullptr;
+ input_color2_operation_ = nullptr;
+ this->set_use_value_alpha_multiply(false);
+ this->set_use_clamp(false);
+ flags_.can_be_constant = true;
}
-void MixBaseOperation::initExecution()
+void MixBaseOperation::init_execution()
{
- this->m_inputValueOperation = this->getInputSocketReader(0);
- this->m_inputColor1Operation = this->getInputSocketReader(1);
- this->m_inputColor2Operation = this->getInputSocketReader(2);
+ input_value_operation_ = this->get_input_socket_reader(0);
+ input_color1_operation_ = this->get_input_socket_reader(1);
+ input_color2_operation_ = this->get_input_socket_reader(2);
}
-void MixBaseOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MixBaseOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float valuem = 1.0f - value;
- output[0] = valuem * (inputColor1[0]) + value * (inputColor2[0]);
- output[1] = valuem * (inputColor1[1]) + value * (inputColor2[1]);
- output[2] = valuem * (inputColor1[2]) + value * (inputColor2[2]);
- output[3] = inputColor1[3];
+ output[0] = valuem * (input_color1[0]) + value * (input_color2[0]);
+ output[1] = valuem * (input_color1[1]) + value * (input_color2[1]);
+ output[2] = valuem * (input_color1[2]) + value * (input_color2[2]);
+ output[3] = input_color1[3];
}
void MixBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
NodeOperationInput *socket;
- rcti temp_area;
+ rcti temp_area = COM_AREA_NONE;
- socket = this->getInputSocket(1);
+ socket = this->get_input_socket(1);
bool determined = socket->determine_canvas(COM_AREA_NONE, temp_area);
if (determined) {
this->set_canvas_input_index(1);
}
else {
- socket = this->getInputSocket(2);
+ socket = this->get_input_socket(2);
determined = socket->determine_canvas(COM_AREA_NONE, temp_area);
if (determined) {
this->set_canvas_input_index(2);
@@ -89,11 +90,11 @@ void MixBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area
NodeOperation::determine_canvas(preferred_area, r_area);
}
-void MixBaseOperation::deinitExecution()
+void MixBaseOperation::deinit_execution()
{
- this->m_inputValueOperation = nullptr;
- this->m_inputColor1Operation = nullptr;
- this->m_inputColor2Operation = nullptr;
+ input_value_operation_ = nullptr;
+ input_color1_operation_ = nullptr;
+ input_color2_operation_ = nullptr;
}
void MixBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -123,7 +124,7 @@ void MixBaseOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
const float value_m = 1.0f - value;
@@ -137,33 +138,36 @@ void MixBaseOperation::update_memory_buffer_row(PixelCursor &p)
/* ******** Mix Add Operation ******** */
-void MixAddOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MixAddOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
- output[0] = inputColor1[0] + value * inputColor2[0];
- output[1] = inputColor1[1] + value * inputColor2[1];
- output[2] = inputColor1[2] + value * inputColor2[2];
- output[3] = inputColor1[3];
+ output[0] = input_color1[0] + value * input_color2[0];
+ output[1] = input_color1[1] + value * input_color2[1];
+ output[2] = input_color1[2] + value * input_color2[2];
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixAddOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
p.out[0] = p.color1[0] + value * p.color2[0];
@@ -171,45 +175,45 @@ void MixAddOperation::update_memory_buffer_row(PixelCursor &p)
p.out[2] = p.color1[2] + value * p.color2[2];
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Blend Operation ******** */
-void MixBlendOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixBlendOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
float value;
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
- value = inputValue[0];
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
+ value = input_value[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float valuem = 1.0f - value;
- output[0] = valuem * (inputColor1[0]) + value * (inputColor2[0]);
- output[1] = valuem * (inputColor1[1]) + value * (inputColor2[1]);
- output[2] = valuem * (inputColor1[2]) + value * (inputColor2[2]);
- output[3] = inputColor1[3];
+ output[0] = valuem * (input_color1[0]) + value * (input_color2[0]);
+ output[1] = valuem * (input_color1[1]) + value * (input_color2[1]);
+ output[2] = valuem * (input_color1[2]) + value * (input_color2[2]);
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixBlendOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
float value_m = 1.0f - value;
@@ -218,39 +222,39 @@ void MixBlendOperation::update_memory_buffer_row(PixelCursor &p)
p.out[2] = value_m * p.color1[2] + value * p.color2[2];
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Burn Operation ******** */
-void MixColorBurnOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixColorBurnOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
float tmp;
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float valuem = 1.0f - value;
- tmp = valuem + value * inputColor2[0];
+ tmp = valuem + value * input_color2[0];
if (tmp <= 0.0f) {
output[0] = 0.0f;
}
else {
- tmp = 1.0f - (1.0f - inputColor1[0]) / tmp;
+ tmp = 1.0f - (1.0f - input_color1[0]) / tmp;
if (tmp < 0.0f) {
output[0] = 0.0f;
}
@@ -262,12 +266,12 @@ void MixColorBurnOperation::executePixelSampled(float output[4],
}
}
- tmp = valuem + value * inputColor2[1];
+ tmp = valuem + value * input_color2[1];
if (tmp <= 0.0f) {
output[1] = 0.0f;
}
else {
- tmp = 1.0f - (1.0f - inputColor1[1]) / tmp;
+ tmp = 1.0f - (1.0f - input_color1[1]) / tmp;
if (tmp < 0.0f) {
output[1] = 0.0f;
}
@@ -279,12 +283,12 @@ void MixColorBurnOperation::executePixelSampled(float output[4],
}
}
- tmp = valuem + value * inputColor2[2];
+ tmp = valuem + value * input_color2[2];
if (tmp <= 0.0f) {
output[2] = 0.0f;
}
else {
- tmp = 1.0f - (1.0f - inputColor1[2]) / tmp;
+ tmp = 1.0f - (1.0f - input_color1[2]) / tmp;
if (tmp < 0.0f) {
output[2] = 0.0f;
}
@@ -296,16 +300,16 @@ void MixColorBurnOperation::executePixelSampled(float output[4],
}
}
- output[3] = inputColor1[3];
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixColorBurnOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
const float value_m = 1.0f - value;
@@ -338,56 +342,56 @@ void MixColorBurnOperation::update_memory_buffer_row(PixelCursor &p)
}
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Color Operation ******** */
-void MixColorOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixColorOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float valuem = 1.0f - value;
float colH, colS, colV;
- rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV);
+ rgb_to_hsv(input_color2[0], input_color2[1], input_color2[2], &colH, &colS, &colV);
if (colS != 0.0f) {
float rH, rS, rV;
float tmpr, tmpg, tmpb;
- rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV);
+ rgb_to_hsv(input_color1[0], input_color1[1], input_color1[2], &rH, &rS, &rV);
hsv_to_rgb(colH, colS, rV, &tmpr, &tmpg, &tmpb);
- output[0] = (valuem * inputColor1[0]) + (value * tmpr);
- output[1] = (valuem * inputColor1[1]) + (value * tmpg);
- output[2] = (valuem * inputColor1[2]) + (value * tmpb);
+ output[0] = (valuem * input_color1[0]) + (value * tmpr);
+ output[1] = (valuem * input_color1[1]) + (value * tmpg);
+ output[2] = (valuem * input_color1[2]) + (value * tmpb);
}
else {
- copy_v3_v3(output, inputColor1);
+ copy_v3_v3(output, input_color1);
}
- output[3] = inputColor1[3];
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixColorOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
const float value_m = 1.0f - value;
@@ -408,44 +412,44 @@ void MixColorOperation::update_memory_buffer_row(PixelCursor &p)
}
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Darken Operation ******** */
-void MixDarkenOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixDarkenOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float valuem = 1.0f - value;
- output[0] = min_ff(inputColor1[0], inputColor2[0]) * value + inputColor1[0] * valuem;
- output[1] = min_ff(inputColor1[1], inputColor2[1]) * value + inputColor1[1] * valuem;
- output[2] = min_ff(inputColor1[2], inputColor2[2]) * value + inputColor1[2] * valuem;
- output[3] = inputColor1[3];
+ output[0] = min_ff(input_color1[0], input_color2[0]) * value + input_color1[0] * valuem;
+ output[1] = min_ff(input_color1[1], input_color2[1]) * value + input_color1[1] * valuem;
+ output[2] = min_ff(input_color1[2], input_color2[2]) * value + input_color1[2] * valuem;
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixDarkenOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
float value_m = 1.0f - value;
@@ -454,44 +458,44 @@ void MixDarkenOperation::update_memory_buffer_row(PixelCursor &p)
p.out[2] = min_ff(p.color1[2], p.color2[2]) * value + p.color1[2] * value_m;
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Difference Operation ******** */
-void MixDifferenceOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixDifferenceOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float valuem = 1.0f - value;
- output[0] = valuem * inputColor1[0] + value * fabsf(inputColor1[0] - inputColor2[0]);
- output[1] = valuem * inputColor1[1] + value * fabsf(inputColor1[1] - inputColor2[1]);
- output[2] = valuem * inputColor1[2] + value * fabsf(inputColor1[2] - inputColor2[2]);
- output[3] = inputColor1[3];
+ output[0] = valuem * input_color1[0] + value * fabsf(input_color1[0] - input_color2[0]);
+ output[1] = valuem * input_color1[1] + value * fabsf(input_color1[1] - input_color2[1]);
+ output[2] = valuem * input_color1[2] + value * fabsf(input_color1[2] - input_color2[2]);
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixDifferenceOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
const float value_m = 1.0f - value;
@@ -500,61 +504,61 @@ void MixDifferenceOperation::update_memory_buffer_row(PixelCursor &p)
p.out[2] = value_m * p.color1[2] + value * fabsf(p.color1[2] - p.color2[2]);
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Difference Operation ******** */
-void MixDivideOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixDivideOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float valuem = 1.0f - value;
- if (inputColor2[0] != 0.0f) {
- output[0] = valuem * (inputColor1[0]) + value * (inputColor1[0]) / inputColor2[0];
+ if (input_color2[0] != 0.0f) {
+ output[0] = valuem * (input_color1[0]) + value * (input_color1[0]) / input_color2[0];
}
else {
output[0] = 0.0f;
}
- if (inputColor2[1] != 0.0f) {
- output[1] = valuem * (inputColor1[1]) + value * (inputColor1[1]) / inputColor2[1];
+ if (input_color2[1] != 0.0f) {
+ output[1] = valuem * (input_color1[1]) + value * (input_color1[1]) / input_color2[1];
}
else {
output[1] = 0.0f;
}
- if (inputColor2[2] != 0.0f) {
- output[2] = valuem * (inputColor1[2]) + value * (inputColor1[2]) / inputColor2[2];
+ if (input_color2[2] != 0.0f) {
+ output[2] = valuem * (input_color1[2]) + value * (input_color1[2]) / input_color2[2];
}
else {
output[2] = 0.0f;
}
- output[3] = inputColor1[3];
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixDivideOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
const float value_m = 1.0f - value;
@@ -580,39 +584,39 @@ void MixDivideOperation::update_memory_buffer_row(PixelCursor &p)
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Dodge Operation ******** */
-void MixDodgeOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixDodgeOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
float tmp;
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
- if (inputColor1[0] != 0.0f) {
- tmp = 1.0f - value * inputColor2[0];
+ if (input_color1[0] != 0.0f) {
+ tmp = 1.0f - value * input_color2[0];
if (tmp <= 0.0f) {
output[0] = 1.0f;
}
else {
- tmp = inputColor1[0] / tmp;
+ tmp = input_color1[0] / tmp;
if (tmp > 1.0f) {
output[0] = 1.0f;
}
@@ -625,13 +629,13 @@ void MixDodgeOperation::executePixelSampled(float output[4],
output[0] = 0.0f;
}
- if (inputColor1[1] != 0.0f) {
- tmp = 1.0f - value * inputColor2[1];
+ if (input_color1[1] != 0.0f) {
+ tmp = 1.0f - value * input_color2[1];
if (tmp <= 0.0f) {
output[1] = 1.0f;
}
else {
- tmp = inputColor1[1] / tmp;
+ tmp = input_color1[1] / tmp;
if (tmp > 1.0f) {
output[1] = 1.0f;
}
@@ -644,13 +648,13 @@ void MixDodgeOperation::executePixelSampled(float output[4],
output[1] = 0.0f;
}
- if (inputColor1[2] != 0.0f) {
- tmp = 1.0f - value * inputColor2[2];
+ if (input_color1[2] != 0.0f) {
+ tmp = 1.0f - value * input_color2[2];
if (tmp <= 0.0f) {
output[2] = 1.0f;
}
else {
- tmp = inputColor1[2] / tmp;
+ tmp = input_color1[2] / tmp;
if (tmp > 1.0f) {
output[2] = 1.0f;
}
@@ -663,16 +667,16 @@ void MixDodgeOperation::executePixelSampled(float output[4],
output[2] = 0.0f;
}
- output[3] = inputColor1[3];
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixDodgeOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
@@ -721,27 +725,27 @@ void MixDodgeOperation::update_memory_buffer_row(PixelCursor &p)
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Glare Operation ******** */
-void MixGlareOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixGlareOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
float value, input_weight, glare_weight;
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
- value = inputValue[0];
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
+ value = input_value[0];
/* Linear interpolation between 3 cases:
* value=-1:output=input value=0:output=input+glare value=1:output=glare
*/
@@ -753,12 +757,12 @@ void MixGlareOperation::executePixelSampled(float output[4],
input_weight = 1.0f - value;
glare_weight = 1.0f;
}
- output[0] = input_weight * MAX2(inputColor1[0], 0.0f) + glare_weight * inputColor2[0];
- output[1] = input_weight * MAX2(inputColor1[1], 0.0f) + glare_weight * inputColor2[1];
- output[2] = input_weight * MAX2(inputColor1[2], 0.0f) + glare_weight * inputColor2[2];
- output[3] = inputColor1[3];
+ output[0] = input_weight * MAX2(input_color1[0], 0.0f) + glare_weight * input_color2[0];
+ output[1] = input_weight * MAX2(input_color1[1], 0.0f) + glare_weight * input_color2[1];
+ output[2] = input_weight * MAX2(input_color1[2], 0.0f) + glare_weight * input_color2[2];
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixGlareOperation::update_memory_buffer_row(PixelCursor &p)
@@ -783,53 +787,56 @@ void MixGlareOperation::update_memory_buffer_row(PixelCursor &p)
p.out[2] = input_weight * MAX2(p.color1[2], 0.0f) + glare_weight * p.color2[2];
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Hue Operation ******** */
-void MixHueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MixHueOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float valuem = 1.0f - value;
float colH, colS, colV;
- rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV);
+ rgb_to_hsv(input_color2[0], input_color2[1], input_color2[2], &colH, &colS, &colV);
if (colS != 0.0f) {
float rH, rS, rV;
float tmpr, tmpg, tmpb;
- rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV);
+ rgb_to_hsv(input_color1[0], input_color1[1], input_color1[2], &rH, &rS, &rV);
hsv_to_rgb(colH, rS, rV, &tmpr, &tmpg, &tmpb);
- output[0] = valuem * (inputColor1[0]) + value * tmpr;
- output[1] = valuem * (inputColor1[1]) + value * tmpg;
- output[2] = valuem * (inputColor1[2]) + value * tmpb;
+ output[0] = valuem * (input_color1[0]) + value * tmpr;
+ output[1] = valuem * (input_color1[1]) + value * tmpg;
+ output[2] = valuem * (input_color1[2]) + value * tmpb;
}
else {
- copy_v3_v3(output, inputColor1);
+ copy_v3_v3(output, input_color1);
}
- output[3] = inputColor1[3];
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixHueOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
const float value_m = 1.0f - value;
@@ -850,62 +857,62 @@ void MixHueOperation::update_memory_buffer_row(PixelCursor &p)
}
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Lighten Operation ******** */
-void MixLightenOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixLightenOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float tmp;
- tmp = value * inputColor2[0];
- if (tmp > inputColor1[0]) {
+ tmp = value * input_color2[0];
+ if (tmp > input_color1[0]) {
output[0] = tmp;
}
else {
- output[0] = inputColor1[0];
+ output[0] = input_color1[0];
}
- tmp = value * inputColor2[1];
- if (tmp > inputColor1[1]) {
+ tmp = value * input_color2[1];
+ if (tmp > input_color1[1]) {
output[1] = tmp;
}
else {
- output[1] = inputColor1[1];
+ output[1] = input_color1[1];
}
- tmp = value * inputColor2[2];
- if (tmp > inputColor1[2]) {
+ tmp = value * input_color2[2];
+ if (tmp > input_color1[2]) {
output[2] = tmp;
}
else {
- output[2] = inputColor1[2];
+ output[2] = input_color1[2];
}
- output[3] = inputColor1[3];
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixLightenOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
@@ -920,59 +927,59 @@ void MixLightenOperation::update_memory_buffer_row(PixelCursor &p)
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Linear Light Operation ******** */
-void MixLinearLightOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixLinearLightOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
- if (inputColor2[0] > 0.5f) {
- output[0] = inputColor1[0] + value * (2.0f * (inputColor2[0] - 0.5f));
+ if (input_color2[0] > 0.5f) {
+ output[0] = input_color1[0] + value * (2.0f * (input_color2[0] - 0.5f));
}
else {
- output[0] = inputColor1[0] + value * (2.0f * (inputColor2[0]) - 1.0f);
+ output[0] = input_color1[0] + value * (2.0f * (input_color2[0]) - 1.0f);
}
- if (inputColor2[1] > 0.5f) {
- output[1] = inputColor1[1] + value * (2.0f * (inputColor2[1] - 0.5f));
+ if (input_color2[1] > 0.5f) {
+ output[1] = input_color1[1] + value * (2.0f * (input_color2[1] - 0.5f));
}
else {
- output[1] = inputColor1[1] + value * (2.0f * (inputColor2[1]) - 1.0f);
+ output[1] = input_color1[1] + value * (2.0f * (input_color2[1]) - 1.0f);
}
- if (inputColor2[2] > 0.5f) {
- output[2] = inputColor1[2] + value * (2.0f * (inputColor2[2] - 0.5f));
+ if (input_color2[2] > 0.5f) {
+ output[2] = input_color1[2] + value * (2.0f * (input_color2[2] - 0.5f));
}
else {
- output[2] = inputColor1[2] + value * (2.0f * (inputColor2[2]) - 1.0f);
+ output[2] = input_color1[2] + value * (2.0f * (input_color2[2]) - 1.0f);
}
- output[3] = inputColor1[3];
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixLinearLightOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
if (p.color2[0] > 0.5f) {
@@ -996,44 +1003,44 @@ void MixLinearLightOperation::update_memory_buffer_row(PixelCursor &p)
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Multiply Operation ******** */
-void MixMultiplyOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixMultiplyOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float valuem = 1.0f - value;
- output[0] = inputColor1[0] * (valuem + value * inputColor2[0]);
- output[1] = inputColor1[1] * (valuem + value * inputColor2[1]);
- output[2] = inputColor1[2] * (valuem + value * inputColor2[2]);
- output[3] = inputColor1[3];
+ output[0] = input_color1[0] * (valuem + value * input_color2[0]);
+ output[1] = input_color1[1] * (valuem + value * input_color2[1]);
+ output[2] = input_color1[2] * (valuem + value * input_color2[2]);
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixMultiplyOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
const float value_m = 1.0f - value;
@@ -1043,61 +1050,64 @@ void MixMultiplyOperation::update_memory_buffer_row(PixelCursor &p)
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Overlay Operation ******** */
-void MixOverlayOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixOverlayOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float valuem = 1.0f - value;
- if (inputColor1[0] < 0.5f) {
- output[0] = inputColor1[0] * (valuem + 2.0f * value * inputColor2[0]);
+ if (input_color1[0] < 0.5f) {
+ output[0] = input_color1[0] * (valuem + 2.0f * value * input_color2[0]);
}
else {
- output[0] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[0])) * (1.0f - inputColor1[0]);
+ output[0] = 1.0f -
+ (valuem + 2.0f * value * (1.0f - input_color2[0])) * (1.0f - input_color1[0]);
}
- if (inputColor1[1] < 0.5f) {
- output[1] = inputColor1[1] * (valuem + 2.0f * value * inputColor2[1]);
+ if (input_color1[1] < 0.5f) {
+ output[1] = input_color1[1] * (valuem + 2.0f * value * input_color2[1]);
}
else {
- output[1] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[1])) * (1.0f - inputColor1[1]);
+ output[1] = 1.0f -
+ (valuem + 2.0f * value * (1.0f - input_color2[1])) * (1.0f - input_color1[1]);
}
- if (inputColor1[2] < 0.5f) {
- output[2] = inputColor1[2] * (valuem + 2.0f * value * inputColor2[2]);
+ if (input_color1[2] < 0.5f) {
+ output[2] = input_color1[2] * (valuem + 2.0f * value * input_color2[2]);
}
else {
- output[2] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[2])) * (1.0f - inputColor1[2]);
+ output[2] = 1.0f -
+ (valuem + 2.0f * value * (1.0f - input_color2[2])) * (1.0f - input_color1[2]);
}
- output[3] = inputColor1[3];
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixOverlayOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
const float value_m = 1.0f - value;
@@ -1122,53 +1132,53 @@ void MixOverlayOperation::update_memory_buffer_row(PixelCursor &p)
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Saturation Operation ******** */
-void MixSaturationOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixSaturationOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float valuem = 1.0f - value;
float rH, rS, rV;
- rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV);
+ rgb_to_hsv(input_color1[0], input_color1[1], input_color1[2], &rH, &rS, &rV);
if (rS != 0.0f) {
float colH, colS, colV;
- rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV);
+ rgb_to_hsv(input_color2[0], input_color2[1], input_color2[2], &colH, &colS, &colV);
hsv_to_rgb(rH, (valuem * rS + value * colS), rV, &output[0], &output[1], &output[2]);
}
else {
- copy_v3_v3(output, inputColor1);
+ copy_v3_v3(output, input_color1);
}
- output[3] = inputColor1[3];
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixSaturationOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
const float value_m = 1.0f - value;
@@ -1186,45 +1196,45 @@ void MixSaturationOperation::update_memory_buffer_row(PixelCursor &p)
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Screen Operation ******** */
-void MixScreenOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixScreenOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float valuem = 1.0f - value;
- output[0] = 1.0f - (valuem + value * (1.0f - inputColor2[0])) * (1.0f - inputColor1[0]);
- output[1] = 1.0f - (valuem + value * (1.0f - inputColor2[1])) * (1.0f - inputColor1[1]);
- output[2] = 1.0f - (valuem + value * (1.0f - inputColor2[2])) * (1.0f - inputColor1[2]);
- output[3] = inputColor1[3];
+ output[0] = 1.0f - (valuem + value * (1.0f - input_color2[0])) * (1.0f - input_color1[0]);
+ output[1] = 1.0f - (valuem + value * (1.0f - input_color2[1])) * (1.0f - input_color1[1]);
+ output[2] = 1.0f - (valuem + value * (1.0f - input_color2[2])) * (1.0f - input_color1[2]);
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixScreenOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
const float value_m = 1.0f - value;
@@ -1234,57 +1244,57 @@ void MixScreenOperation::update_memory_buffer_row(PixelCursor &p)
p.out[2] = 1.0f - (value_m + value * (1.0f - p.color2[2])) * (1.0f - p.color1[2]);
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Soft Light Operation ******** */
-void MixSoftLightOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixSoftLightOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float valuem = 1.0f - value;
float scr, scg, scb;
/* first calculate non-fac based Screen mix */
- scr = 1.0f - (1.0f - inputColor2[0]) * (1.0f - inputColor1[0]);
- scg = 1.0f - (1.0f - inputColor2[1]) * (1.0f - inputColor1[1]);
- scb = 1.0f - (1.0f - inputColor2[2]) * (1.0f - inputColor1[2]);
-
- output[0] = valuem * (inputColor1[0]) +
- value * (((1.0f - inputColor1[0]) * inputColor2[0] * (inputColor1[0])) +
- (inputColor1[0] * scr));
- output[1] = valuem * (inputColor1[1]) +
- value * (((1.0f - inputColor1[1]) * inputColor2[1] * (inputColor1[1])) +
- (inputColor1[1] * scg));
- output[2] = valuem * (inputColor1[2]) +
- value * (((1.0f - inputColor1[2]) * inputColor2[2] * (inputColor1[2])) +
- (inputColor1[2] * scb));
- output[3] = inputColor1[3];
-
- clampIfNeeded(output);
+ scr = 1.0f - (1.0f - input_color2[0]) * (1.0f - input_color1[0]);
+ scg = 1.0f - (1.0f - input_color2[1]) * (1.0f - input_color1[1]);
+ scb = 1.0f - (1.0f - input_color2[2]) * (1.0f - input_color1[2]);
+
+ output[0] = valuem * (input_color1[0]) +
+ value * (((1.0f - input_color1[0]) * input_color2[0] * (input_color1[0])) +
+ (input_color1[0] * scr));
+ output[1] = valuem * (input_color1[1]) +
+ value * (((1.0f - input_color1[1]) * input_color2[1] * (input_color1[1])) +
+ (input_color1[1] * scg));
+ output[2] = valuem * (input_color1[2]) +
+ value * (((1.0f - input_color1[2]) * input_color2[2] * (input_color1[2])) +
+ (input_color1[2] * scb));
+ output[3] = input_color1[3];
+
+ clamp_if_needed(output);
}
void MixSoftLightOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
const float value_m = 1.0f - value;
@@ -1303,43 +1313,43 @@ void MixSoftLightOperation::update_memory_buffer_row(PixelCursor &p)
value * ((1.0f - p.color1[2]) * p.color2[2] * p.color1[2] + p.color1[2] * scb);
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Subtract Operation ******** */
-void MixSubtractOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixSubtractOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
- output[0] = inputColor1[0] - value * (inputColor2[0]);
- output[1] = inputColor1[1] - value * (inputColor2[1]);
- output[2] = inputColor1[2] - value * (inputColor2[2]);
- output[3] = inputColor1[3];
+ output[0] = input_color1[0] - value * (input_color2[0]);
+ output[1] = input_color1[1] - value * (input_color2[1]);
+ output[2] = input_color1[2] - value * (input_color2[2]);
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixSubtractOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
p.out[0] = p.color1[0] - value * p.color2[0];
@@ -1347,47 +1357,47 @@ void MixSubtractOperation::update_memory_buffer_row(PixelCursor &p)
p.out[2] = p.color1[2] - value * p.color2[2];
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
/* ******** Mix Value Operation ******** */
-void MixValueOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MixValueOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputColor1[4];
- float inputColor2[4];
- float inputValue[4];
+ float input_color1[4];
+ float input_color2[4];
+ float input_value[4];
- this->m_inputValueOperation->readSampled(inputValue, x, y, sampler);
- this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
- this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
+ input_value_operation_->read_sampled(input_value, x, y, sampler);
+ input_color1_operation_->read_sampled(input_color1, x, y, sampler);
+ input_color2_operation_->read_sampled(input_color2, x, y, sampler);
- float value = inputValue[0];
- if (this->useValueAlphaMultiply()) {
- value *= inputColor2[3];
+ float value = input_value[0];
+ if (this->use_value_alpha_multiply()) {
+ value *= input_color2[3];
}
float valuem = 1.0f - value;
float rH, rS, rV;
float colH, colS, colV;
- rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV);
- rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV);
+ rgb_to_hsv(input_color1[0], input_color1[1], input_color1[2], &rH, &rS, &rV);
+ rgb_to_hsv(input_color2[0], input_color2[1], input_color2[2], &colH, &colS, &colV);
hsv_to_rgb(rH, rS, (valuem * rV + value * colV), &output[0], &output[1], &output[2]);
- output[3] = inputColor1[3];
+ output[3] = input_color1[3];
- clampIfNeeded(output);
+ clamp_if_needed(output);
}
void MixValueOperation::update_memory_buffer_row(PixelCursor &p)
{
while (p.out < p.row_end) {
float value = p.value[0];
- if (this->useValueAlphaMultiply()) {
+ if (this->use_value_alpha_multiply()) {
value *= p.color2[3];
}
float value_m = 1.0f - value;
@@ -1399,7 +1409,7 @@ void MixValueOperation::update_memory_buffer_row(PixelCursor &p)
hsv_to_rgb(rH, rS, (value_m * rV + value * colV), &p.out[0], &p.out[1], &p.out[2]);
p.out[3] = p.color1[3];
- clampIfNeeded(p.out);
+ clamp_if_needed(p.out);
p.next();
}
}
diff --git a/source/blender/compositor/operations/COM_MixOperation.h b/source/blender/compositor/operations/COM_MixOperation.h
index fabbea422eb..bf5639f43a3 100644
--- a/source/blender/compositor/operations/COM_MixOperation.h
+++ b/source/blender/compositor/operations/COM_MixOperation.h
@@ -51,17 +51,17 @@ class MixBaseOperation : public MultiThreadedOperation {
};
/**
- * Prefetched reference to the inputProgram
+ * Prefetched reference to the input_program
*/
- SocketReader *m_inputValueOperation;
- SocketReader *m_inputColor1Operation;
- SocketReader *m_inputColor2Operation;
- bool m_valueAlphaMultiply;
- bool m_useClamp;
+ SocketReader *input_value_operation_;
+ SocketReader *input_color1_operation_;
+ SocketReader *input_color2_operation_;
+ bool value_alpha_multiply_;
+ bool use_clamp_;
- inline void clampIfNeeded(float color[4])
+ inline void clamp_if_needed(float color[4])
{
- if (m_useClamp) {
+ if (use_clamp_) {
clamp_v4(color, 0.0f, 1.0f);
}
}
@@ -75,31 +75,31 @@ class MixBaseOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
- void setUseValueAlphaMultiply(const bool value)
+ void set_use_value_alpha_multiply(const bool value)
{
- this->m_valueAlphaMultiply = value;
+ value_alpha_multiply_ = value;
}
- inline bool useValueAlphaMultiply()
+ inline bool use_value_alpha_multiply()
{
- return this->m_valueAlphaMultiply;
+ return value_alpha_multiply_;
}
- void setUseClamp(bool value)
+ void set_use_clamp(bool value)
{
- this->m_useClamp = value;
+ use_clamp_ = value;
}
void update_memory_buffer_partial(MemoryBuffer *output,
@@ -112,7 +112,7 @@ class MixBaseOperation : public MultiThreadedOperation {
class MixAddOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -120,7 +120,7 @@ class MixAddOperation : public MixBaseOperation {
class MixBlendOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -128,7 +128,7 @@ class MixBlendOperation : public MixBaseOperation {
class MixColorBurnOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -136,7 +136,7 @@ class MixColorBurnOperation : public MixBaseOperation {
class MixColorOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -144,7 +144,7 @@ class MixColorOperation : public MixBaseOperation {
class MixDarkenOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -152,7 +152,7 @@ class MixDarkenOperation : public MixBaseOperation {
class MixDifferenceOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -160,7 +160,7 @@ class MixDifferenceOperation : public MixBaseOperation {
class MixDivideOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -168,7 +168,7 @@ class MixDivideOperation : public MixBaseOperation {
class MixDodgeOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -176,7 +176,7 @@ class MixDodgeOperation : public MixBaseOperation {
class MixGlareOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -184,7 +184,7 @@ class MixGlareOperation : public MixBaseOperation {
class MixHueOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -192,7 +192,7 @@ class MixHueOperation : public MixBaseOperation {
class MixLightenOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -200,7 +200,7 @@ class MixLightenOperation : public MixBaseOperation {
class MixLinearLightOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -208,7 +208,7 @@ class MixLinearLightOperation : public MixBaseOperation {
class MixMultiplyOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -216,7 +216,7 @@ class MixMultiplyOperation : public MixBaseOperation {
class MixOverlayOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -224,7 +224,7 @@ class MixOverlayOperation : public MixBaseOperation {
class MixSaturationOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -232,7 +232,7 @@ class MixSaturationOperation : public MixBaseOperation {
class MixScreenOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -240,7 +240,7 @@ class MixScreenOperation : public MixBaseOperation {
class MixSoftLightOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -248,7 +248,7 @@ class MixSoftLightOperation : public MixBaseOperation {
class MixSubtractOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
@@ -256,7 +256,7 @@ class MixSubtractOperation : public MixBaseOperation {
class MixValueOperation : public MixBaseOperation {
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_row(PixelCursor &p) override;
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc
index aed91d4d46e..1765012d873 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc
@@ -25,16 +25,16 @@ namespace blender::compositor {
MovieClipAttributeOperation::MovieClipAttributeOperation()
{
- this->addOutputSocket(DataType::Value);
- this->m_framenumber = 0;
- this->m_attribute = MCA_X;
- this->m_invert = false;
+ this->add_output_socket(DataType::Value);
+ framenumber_ = 0;
+ attribute_ = MCA_X;
+ invert_ = false;
needs_canvas_to_get_constant_ = true;
is_value_calculated_ = false;
stabilization_resolution_socket_ = nullptr;
}
-void MovieClipAttributeOperation::initExecution()
+void MovieClipAttributeOperation::init_execution()
{
if (!is_value_calculated_) {
calc_value();
@@ -45,7 +45,7 @@ void MovieClipAttributeOperation::calc_value()
{
BLI_assert(this->get_flags().is_canvas_set);
is_value_calculated_ = true;
- if (this->m_clip == nullptr) {
+ if (clip_ == nullptr) {
return;
}
float loc[2], scale, angle;
@@ -53,48 +53,48 @@ void MovieClipAttributeOperation::calc_value()
loc[1] = 0.0f;
scale = 1.0f;
angle = 0.0f;
- int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_clip, this->m_framenumber);
+ int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip_, framenumber_);
NodeOperation &stabilization_operation =
stabilization_resolution_socket_ ?
- stabilization_resolution_socket_->getLink()->getOperation() :
+ stabilization_resolution_socket_->get_link()->get_operation() :
*this;
- BKE_tracking_stabilization_data_get(this->m_clip,
+ BKE_tracking_stabilization_data_get(clip_,
clip_framenr,
- stabilization_operation.getWidth(),
- stabilization_operation.getHeight(),
+ stabilization_operation.get_width(),
+ stabilization_operation.get_height(),
loc,
&scale,
&angle);
- switch (this->m_attribute) {
+ switch (attribute_) {
case MCA_SCALE:
- this->m_value = scale;
+ value_ = scale;
break;
case MCA_ANGLE:
- this->m_value = angle;
+ value_ = angle;
break;
case MCA_X:
- this->m_value = loc[0];
+ value_ = loc[0];
break;
case MCA_Y:
- this->m_value = loc[1];
+ value_ = loc[1];
break;
}
- if (this->m_invert) {
- if (this->m_attribute != MCA_SCALE) {
- this->m_value = -this->m_value;
+ if (invert_) {
+ if (attribute_ != MCA_SCALE) {
+ value_ = -value_;
}
else {
- this->m_value = 1.0f / this->m_value;
+ value_ = 1.0f / value_;
}
}
}
-void MovieClipAttributeOperation::executePixelSampled(float output[4],
- float /*x*/,
- float /*y*/,
- PixelSampler /*sampler*/)
+void MovieClipAttributeOperation::execute_pixel_sampled(float output[4],
+ float /*x*/,
+ float /*y*/,
+ PixelSampler /*sampler*/)
{
- output[0] = this->m_value;
+ output[0] = value_;
}
void MovieClipAttributeOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
@@ -107,7 +107,7 @@ const float *MovieClipAttributeOperation::get_constant_elem()
if (!is_value_calculated_) {
calc_value();
}
- return &m_value;
+ return &value_;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h
index 50680653aea..9f333189811 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h
@@ -36,11 +36,11 @@ typedef enum MovieClipAttribute {
*/
class MovieClipAttributeOperation : public ConstantOperation {
private:
- MovieClip *m_clip;
- float m_value;
- int m_framenumber;
- bool m_invert;
- MovieClipAttribute m_attribute;
+ MovieClip *clip_;
+ float value_;
+ int framenumber_;
+ bool invert_;
+ MovieClipAttribute attribute_;
bool is_value_calculated_;
NodeOperationInput *stabilization_resolution_socket_;
@@ -50,31 +50,31 @@ class MovieClipAttributeOperation : public ConstantOperation {
*/
MovieClipAttributeOperation();
- void initExecution() override;
+ void init_execution() override;
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
const float *get_constant_elem() override;
- void setMovieClip(MovieClip *clip)
+ void set_movie_clip(MovieClip *clip)
{
- this->m_clip = clip;
+ clip_ = clip;
}
- void setFramenumber(int framenumber)
+ void set_framenumber(int framenumber)
{
- this->m_framenumber = framenumber;
+ framenumber_ = framenumber;
}
- void setAttribute(MovieClipAttribute attribute)
+ void set_attribute(MovieClipAttribute attribute)
{
- this->m_attribute = attribute;
+ attribute_ = attribute;
}
- void setInvert(bool invert)
+ void set_invert(bool invert)
{
- this->m_invert = invert;
+ invert_ = invert;
}
/**
diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cc b/source/blender/compositor/operations/COM_MovieClipOperation.cc
index 1ca33b12432..a73b408e3ff 100644
--- a/source/blender/compositor/operations/COM_MovieClipOperation.cc
+++ b/source/blender/compositor/operations/COM_MovieClipOperation.cc
@@ -18,9 +18,6 @@
#include "COM_MovieClipOperation.h"
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-
#include "BKE_image.h"
#include "BKE_movieclip.h"
@@ -30,30 +27,30 @@ namespace blender::compositor {
MovieClipBaseOperation::MovieClipBaseOperation()
{
- this->m_movieClip = nullptr;
- this->m_movieClipBuffer = nullptr;
- this->m_movieClipUser = nullptr;
- this->m_movieClipwidth = 0;
- this->m_movieClipheight = 0;
- this->m_framenumber = 0;
+ movie_clip_ = nullptr;
+ movie_clip_buffer_ = nullptr;
+ movie_clip_user_ = nullptr;
+ movie_clipwidth_ = 0;
+ movie_clipheight_ = 0;
+ framenumber_ = 0;
}
-void MovieClipBaseOperation::initExecution()
+void MovieClipBaseOperation::init_execution()
{
- if (this->m_movieClip) {
- BKE_movieclip_user_set_frame(this->m_movieClipUser, this->m_framenumber);
+ if (movie_clip_) {
+ BKE_movieclip_user_set_frame(movie_clip_user_, framenumber_);
ImBuf *ibuf;
- if (this->m_cacheFrame) {
- ibuf = BKE_movieclip_get_ibuf(this->m_movieClip, this->m_movieClipUser);
+ if (cache_frame_) {
+ ibuf = BKE_movieclip_get_ibuf(movie_clip_, movie_clip_user_);
}
else {
ibuf = BKE_movieclip_get_ibuf_flag(
- this->m_movieClip, this->m_movieClipUser, this->m_movieClip->flag, MOVIECLIP_CACHE_SKIP);
+ movie_clip_, movie_clip_user_, movie_clip_->flag, MOVIECLIP_CACHE_SKIP);
}
if (ibuf) {
- this->m_movieClipBuffer = ibuf;
+ movie_clip_buffer_ = ibuf;
if (ibuf->rect_float == nullptr || ibuf->userflags & IB_RECT_INVALID) {
IMB_float_from_rect(ibuf);
ibuf->userflags &= ~IB_RECT_INVALID;
@@ -62,31 +59,31 @@ void MovieClipBaseOperation::initExecution()
}
}
-void MovieClipBaseOperation::deinitExecution()
+void MovieClipBaseOperation::deinit_execution()
{
- if (this->m_movieClipBuffer) {
- IMB_freeImBuf(this->m_movieClipBuffer);
+ if (movie_clip_buffer_) {
+ IMB_freeImBuf(movie_clip_buffer_);
- this->m_movieClipBuffer = nullptr;
+ movie_clip_buffer_ = nullptr;
}
}
void MovieClipBaseOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area)
{
r_area = COM_AREA_NONE;
- if (this->m_movieClip) {
+ if (movie_clip_) {
int width, height;
- BKE_movieclip_get_size(this->m_movieClip, this->m_movieClipUser, &width, &height);
+ BKE_movieclip_get_size(movie_clip_, movie_clip_user_, &width, &height);
BLI_rcti_init(&r_area, 0, width, 0, height);
}
}
-void MovieClipBaseOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MovieClipBaseOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- ImBuf *ibuf = this->m_movieClipBuffer;
+ ImBuf *ibuf = movie_clip_buffer_;
if (ibuf == nullptr) {
zero_v4(output);
@@ -114,8 +111,8 @@ void MovieClipBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> UNUSED(inputs))
{
- if (m_movieClipBuffer) {
- output->copy_from(m_movieClipBuffer, area);
+ if (movie_clip_buffer_) {
+ output->copy_from(movie_clip_buffer_, area);
}
else {
output->fill(area, COM_COLOR_TRANSPARENT);
@@ -124,21 +121,21 @@ void MovieClipBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
MovieClipOperation::MovieClipOperation() : MovieClipBaseOperation()
{
- this->addOutputSocket(DataType::Color);
+ this->add_output_socket(DataType::Color);
}
MovieClipAlphaOperation::MovieClipAlphaOperation() : MovieClipBaseOperation()
{
- this->addOutputSocket(DataType::Value);
+ this->add_output_socket(DataType::Value);
}
-void MovieClipAlphaOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MovieClipAlphaOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float result[4];
- MovieClipBaseOperation::executePixelSampled(result, x, y, sampler);
+ MovieClipBaseOperation::execute_pixel_sampled(result, x, y, sampler);
output[0] = result[3];
}
@@ -146,8 +143,8 @@ void MovieClipAlphaOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> UNUSED(inputs))
{
- if (m_movieClipBuffer) {
- output->copy_from(m_movieClipBuffer, area, 3, COM_DATA_TYPE_VALUE_CHANNELS, 0);
+ if (movie_clip_buffer_) {
+ output->copy_from(movie_clip_buffer_, area, 3, COM_DATA_TYPE_VALUE_CHANNELS, 0);
}
else {
output->fill(area, COM_VALUE_ZERO);
diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.h b/source/blender/compositor/operations/COM_MovieClipOperation.h
index 465ccd4fc00..e576917df1b 100644
--- a/source/blender/compositor/operations/COM_MovieClipOperation.h
+++ b/source/blender/compositor/operations/COM_MovieClipOperation.h
@@ -30,13 +30,13 @@ namespace blender::compositor {
*/
class MovieClipBaseOperation : public MultiThreadedOperation {
protected:
- MovieClip *m_movieClip;
- MovieClipUser *m_movieClipUser;
- ImBuf *m_movieClipBuffer;
- int m_movieClipheight;
- int m_movieClipwidth;
- int m_framenumber;
- bool m_cacheFrame;
+ MovieClip *movie_clip_;
+ MovieClipUser *movie_clip_user_;
+ ImBuf *movie_clip_buffer_;
+ int movie_clipheight_;
+ int movie_clipwidth_;
+ int framenumber_;
+ bool cache_frame_;
/**
* Determine the output resolution. The resolution is retrieved from the Renderer
@@ -46,26 +46,26 @@ class MovieClipBaseOperation : public MultiThreadedOperation {
public:
MovieClipBaseOperation();
- void initExecution() override;
- void deinitExecution() override;
- void setMovieClip(MovieClip *image)
+ void init_execution() override;
+ void deinit_execution() override;
+ void set_movie_clip(MovieClip *image)
{
- this->m_movieClip = image;
+ movie_clip_ = image;
}
- void setMovieClipUser(MovieClipUser *imageuser)
+ void set_movie_clip_user(MovieClipUser *imageuser)
{
- this->m_movieClipUser = imageuser;
+ movie_clip_user_ = imageuser;
}
- void setCacheFrame(bool value)
+ void set_cache_frame(bool value)
{
- this->m_cacheFrame = value;
+ cache_frame_ = value;
}
- void setFramenumber(int framenumber)
+ void set_framenumber(int framenumber)
{
- this->m_framenumber = framenumber;
+ framenumber_ = framenumber;
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
@@ -80,7 +80,7 @@ class MovieClipOperation : public MovieClipBaseOperation {
class MovieClipAlphaOperation : public MovieClipBaseOperation {
public:
MovieClipAlphaOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
index 72162ffb110..b25073394a2 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
@@ -18,114 +18,120 @@
#include "COM_MovieDistortionOperation.h"
-#include "BKE_movieclip.h"
-#include "BKE_tracking.h"
+#include "DNA_defaults.h"
-#include "BLI_linklist.h"
+#include "BKE_movieclip.h"
namespace blender::compositor {
MovieDistortionOperation::MovieDistortionOperation(bool distortion)
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
this->set_canvas_input_index(0);
- this->m_inputOperation = nullptr;
- this->m_movieClip = nullptr;
- this->m_apply = distortion;
+ input_operation_ = nullptr;
+ movie_clip_ = nullptr;
+ apply_ = distortion;
}
-void MovieDistortionOperation::initExecution()
+void MovieDistortionOperation::init_data()
{
- this->m_inputOperation = this->getInputSocketReader(0);
- if (this->m_movieClip) {
- MovieTracking *tracking = &this->m_movieClip->tracking;
- MovieClipUser clipUser = {0};
+ if (movie_clip_) {
+ MovieTracking *tracking = &movie_clip_->tracking;
+ MovieClipUser clip_user = *DNA_struct_default_get(MovieClipUser);
int calibration_width, calibration_height;
- BKE_movieclip_user_set_frame(&clipUser, this->m_framenumber);
- BKE_movieclip_get_size(this->m_movieClip, &clipUser, &calibration_width, &calibration_height);
+ BKE_movieclip_user_set_frame(&clip_user, framenumber_);
+ BKE_movieclip_get_size(movie_clip_, &clip_user, &calibration_width, &calibration_height);
float delta[2];
rcti full_frame;
full_frame.xmin = full_frame.ymin = 0;
- full_frame.xmax = this->getWidth();
- full_frame.ymax = this->getHeight();
+ full_frame.xmax = this->get_width();
+ full_frame.ymax = this->get_height();
BKE_tracking_max_distortion_delta_across_bound(
- tracking, this->getWidth(), this->getHeight(), &full_frame, !this->m_apply, delta);
+ tracking, this->get_width(), this->get_height(), &full_frame, !apply_, delta);
/* 5 is just in case we didn't hit real max of distortion in
* BKE_tracking_max_undistortion_delta_across_bound
*/
- m_margin[0] = delta[0] + 5;
- m_margin[1] = delta[1] + 5;
-
- this->m_distortion = BKE_tracking_distortion_new(
- tracking, calibration_width, calibration_height);
- this->m_calibration_width = calibration_width;
- this->m_calibration_height = calibration_height;
- this->m_pixel_aspect = tracking->camera.pixel_aspect;
+ margin_[0] = delta[0] + 5;
+ margin_[1] = delta[1] + 5;
+
+ calibration_width_ = calibration_width;
+ calibration_height_ = calibration_height;
+ pixel_aspect_ = tracking->camera.pixel_aspect;
+ }
+ else {
+ margin_[0] = margin_[1] = 0;
+ }
+}
+
+void MovieDistortionOperation::init_execution()
+{
+ input_operation_ = this->get_input_socket_reader(0);
+ if (movie_clip_) {
+ MovieTracking *tracking = &movie_clip_->tracking;
+ distortion_ = BKE_tracking_distortion_new(tracking, calibration_width_, calibration_height_);
}
else {
- m_margin[0] = m_margin[1] = 0;
- this->m_distortion = nullptr;
+ distortion_ = nullptr;
}
}
-void MovieDistortionOperation::deinitExecution()
+void MovieDistortionOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
- this->m_movieClip = nullptr;
- if (this->m_distortion != nullptr) {
- BKE_tracking_distortion_free(this->m_distortion);
+ input_operation_ = nullptr;
+ movie_clip_ = nullptr;
+ if (distortion_ != nullptr) {
+ BKE_tracking_distortion_free(distortion_);
}
}
-void MovieDistortionOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler /*sampler*/)
+void MovieDistortionOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
- if (this->m_distortion != nullptr) {
+ if (distortion_ != nullptr) {
/* float overscan = 0.0f; */
- const float pixel_aspect = this->m_pixel_aspect;
- const float w = (float)this->getWidth() /* / (1 + overscan) */;
- const float h = (float)this->getHeight() /* / (1 + overscan) */;
- const float aspx = w / (float)this->m_calibration_width;
- const float aspy = h / (float)this->m_calibration_height;
+ const float pixel_aspect = pixel_aspect_;
+ const float w = (float)this->get_width() /* / (1 + overscan) */;
+ const float h = (float)this->get_height() /* / (1 + overscan) */;
+ const float aspx = w / (float)calibration_width_;
+ const float aspy = h / (float)calibration_height_;
float in[2];
float out[2];
in[0] = (x /* - 0.5 * overscan * w */) / aspx;
in[1] = (y /* - 0.5 * overscan * h */) / aspy / pixel_aspect;
- if (this->m_apply) {
- BKE_tracking_distortion_undistort_v2(this->m_distortion, in, out);
+ if (apply_) {
+ BKE_tracking_distortion_undistort_v2(distortion_, in, out);
}
else {
- BKE_tracking_distortion_distort_v2(this->m_distortion, in, out);
+ BKE_tracking_distortion_distort_v2(distortion_, in, out);
}
float u = out[0] * aspx /* + 0.5 * overscan * w */,
v = (out[1] * aspy /* + 0.5 * overscan * h */) * pixel_aspect;
- this->m_inputOperation->readSampled(output, u, v, PixelSampler::Bilinear);
+ input_operation_->read_sampled(output, u, v, PixelSampler::Bilinear);
}
else {
- this->m_inputOperation->readSampled(output, x, y, PixelSampler::Bilinear);
+ input_operation_->read_sampled(output, x, y, PixelSampler::Bilinear);
}
}
-bool MovieDistortionOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool MovieDistortionOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
- newInput.xmin = input->xmin - m_margin[0];
- newInput.ymin = input->ymin - m_margin[1];
- newInput.xmax = input->xmax + m_margin[0];
- newInput.ymax = input->ymax + m_margin[1];
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ rcti new_input;
+ new_input.xmin = input->xmin - margin_[0];
+ new_input.ymin = input->ymin - margin_[1];
+ new_input.xmax = input->xmax + margin_[0];
+ new_input.ymax = input->ymax + margin_[1];
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void MovieDistortionOperation::get_area_of_interest(const int input_idx,
@@ -134,10 +140,10 @@ void MovieDistortionOperation::get_area_of_interest(const int input_idx,
{
BLI_assert(input_idx == 0);
UNUSED_VARS_NDEBUG(input_idx);
- r_input_area.xmin = output_area.xmin - m_margin[0];
- r_input_area.ymin = output_area.ymin - m_margin[1];
- r_input_area.xmax = output_area.xmax + m_margin[0];
- r_input_area.ymax = output_area.ymax + m_margin[1];
+ r_input_area.xmin = output_area.xmin - margin_[0];
+ r_input_area.ymin = output_area.ymin - margin_[1];
+ r_input_area.xmax = output_area.xmax + margin_[0];
+ r_input_area.ymax = output_area.ymax + margin_[1];
}
void MovieDistortionOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -145,28 +151,28 @@ void MovieDistortionOperation::update_memory_buffer_partial(MemoryBuffer *output
Span<MemoryBuffer *> inputs)
{
const MemoryBuffer *input_img = inputs[0];
- if (this->m_distortion == nullptr) {
+ if (distortion_ == nullptr) {
output->copy_from(input_img, area);
return;
}
/* `float overscan = 0.0f;` */
- const float pixel_aspect = this->m_pixel_aspect;
- const float w = (float)this->getWidth() /* `/ (1 + overscan)` */;
- const float h = (float)this->getHeight() /* `/ (1 + overscan)` */;
- const float aspx = w / (float)this->m_calibration_width;
- const float aspy = h / (float)this->m_calibration_height;
+ const float pixel_aspect = pixel_aspect_;
+ const float w = (float)this->get_width() /* `/ (1 + overscan)` */;
+ const float h = (float)this->get_height() /* `/ (1 + overscan)` */;
+ const float aspx = w / (float)calibration_width_;
+ const float aspy = h / (float)calibration_height_;
float xy[2];
float distorted_xy[2];
for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
xy[0] = (it.x /* `- 0.5 * overscan * w` */) / aspx;
xy[1] = (it.y /* `- 0.5 * overscan * h` */) / aspy / pixel_aspect;
- if (this->m_apply) {
- BKE_tracking_distortion_undistort_v2(this->m_distortion, xy, distorted_xy);
+ if (apply_) {
+ BKE_tracking_distortion_undistort_v2(distortion_, xy, distorted_xy);
}
else {
- BKE_tracking_distortion_distort_v2(this->m_distortion, xy, distorted_xy);
+ BKE_tracking_distortion_distort_v2(distortion_, xy, distorted_xy);
}
const float u = distorted_xy[0] * aspx /* `+ 0.5 * overscan * w` */;
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.h b/source/blender/compositor/operations/COM_MovieDistortionOperation.h
index 69c2f9c269c..cf430c74f30 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.h
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.h
@@ -28,36 +28,37 @@ namespace blender::compositor {
class MovieDistortionOperation : public MultiThreadedOperation {
private:
- SocketReader *m_inputOperation;
- MovieClip *m_movieClip;
- int m_margin[2];
+ SocketReader *input_operation_;
+ MovieClip *movie_clip_;
+ int margin_[2];
protected:
- bool m_apply;
- int m_framenumber;
+ bool apply_;
+ int framenumber_;
- struct MovieDistortion *m_distortion;
- int m_calibration_width, m_calibration_height;
- float m_pixel_aspect;
+ struct MovieDistortion *distortion_;
+ int calibration_width_, calibration_height_;
+ float pixel_aspect_;
public:
MovieDistortionOperation(bool distortion);
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_data() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void setMovieClip(MovieClip *clip)
+ void set_movie_clip(MovieClip *clip)
{
- this->m_movieClip = clip;
+ movie_clip_ = clip;
}
- void setFramenumber(int framenumber)
+ void set_framenumber(int framenumber)
{
- this->m_framenumber = framenumber;
+ framenumber_ = framenumber;
}
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cc b/source/blender/compositor/operations/COM_MultilayerImageOperation.cc
index 3a5de944a00..5549cd1e937 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cc
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cc
@@ -19,7 +19,6 @@
#include "COM_MultilayerImageOperation.h"
#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
namespace blender::compositor {
@@ -27,27 +26,27 @@ MultilayerBaseOperation::MultilayerBaseOperation(RenderLayer *render_layer,
RenderPass *render_pass,
int view)
{
- this->m_passId = BLI_findindex(&render_layer->passes, render_pass);
- this->m_view = view;
- this->m_renderLayer = render_layer;
- this->m_renderPass = render_pass;
+ pass_id_ = BLI_findindex(&render_layer->passes, render_pass);
+ view_ = view;
+ render_layer_ = render_layer;
+ render_pass_ = render_pass;
}
-ImBuf *MultilayerBaseOperation::getImBuf()
+ImBuf *MultilayerBaseOperation::get_im_buf()
{
/* temporarily changes the view to get the right ImBuf */
- int view = this->m_imageUser->view;
+ int view = image_user_->view;
- this->m_imageUser->view = this->m_view;
- this->m_imageUser->pass = this->m_passId;
+ image_user_->view = view_;
+ image_user_->pass = pass_id_;
- if (BKE_image_multilayer_index(this->m_image->rr, this->m_imageUser)) {
- ImBuf *ibuf = BaseImageOperation::getImBuf();
- this->m_imageUser->view = view;
+ if (BKE_image_multilayer_index(image_->rr, image_user_)) {
+ ImBuf *ibuf = BaseImageOperation::get_im_buf();
+ image_user_->view = view;
return ibuf;
}
- this->m_imageUser->view = view;
+ image_user_->view = view;
return nullptr;
}
@@ -55,17 +54,17 @@ void MultilayerBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> UNUSED(inputs))
{
- output->copy_from(m_buffer, area);
+ output->copy_from(buffer_, area);
}
-std::unique_ptr<MetaData> MultilayerColorOperation::getMetaData()
+std::unique_ptr<MetaData> MultilayerColorOperation::get_meta_data()
{
- BLI_assert(this->m_buffer);
+ BLI_assert(buffer_);
MetaDataExtractCallbackData callback_data = {nullptr};
- RenderResult *render_result = this->m_image->rr;
+ RenderResult *render_result = image_->rr;
if (render_result && render_result->stamp_data) {
- RenderLayer *render_layer = this->m_renderLayer;
- RenderPass *render_pass = this->m_renderPass;
+ RenderLayer *render_layer = render_layer_;
+ RenderPass *render_pass = render_pass_;
std::string full_layer_name =
std::string(render_layer->name,
BLI_strnlen(render_layer->name, sizeof(render_layer->name))) +
@@ -73,7 +72,7 @@ std::unique_ptr<MetaData> MultilayerColorOperation::getMetaData()
std::string(render_pass->name, BLI_strnlen(render_pass->name, sizeof(render_pass->name)));
blender::StringRef cryptomatte_layer_name =
blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name(full_layer_name);
- callback_data.setCryptomatteKeys(cryptomatte_layer_name);
+ callback_data.set_cryptomatte_keys(cryptomatte_layer_name);
BKE_stamp_info_callback(&callback_data,
render_result->stamp_data,
@@ -84,83 +83,83 @@ std::unique_ptr<MetaData> MultilayerColorOperation::getMetaData()
return std::move(callback_data.meta_data);
}
-void MultilayerColorOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void MultilayerColorOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- if (this->m_imageFloatBuffer == nullptr) {
+ if (image_float_buffer_ == nullptr) {
zero_v4(output);
}
else {
- if (this->m_numberOfChannels == 4) {
+ if (number_of_channels_ == 4) {
switch (sampler) {
case PixelSampler::Nearest:
- nearest_interpolation_color(this->m_buffer, nullptr, output, x, y);
+ nearest_interpolation_color(buffer_, nullptr, output, x, y);
break;
case PixelSampler::Bilinear:
- bilinear_interpolation_color(this->m_buffer, nullptr, output, x, y);
+ bilinear_interpolation_color(buffer_, nullptr, output, x, y);
break;
case PixelSampler::Bicubic:
- bicubic_interpolation_color(this->m_buffer, nullptr, output, x, y);
+ bicubic_interpolation_color(buffer_, nullptr, output, x, y);
break;
}
}
else {
int yi = y;
int xi = x;
- if (xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() ||
- (unsigned int)yi >= this->getHeight()) {
+ if (xi < 0 || yi < 0 || (unsigned int)xi >= this->get_width() ||
+ (unsigned int)yi >= this->get_height()) {
zero_v4(output);
}
else {
- int offset = (yi * this->getWidth() + xi) * 3;
- copy_v3_v3(output, &this->m_imageFloatBuffer[offset]);
+ int offset = (yi * this->get_width() + xi) * 3;
+ copy_v3_v3(output, &image_float_buffer_[offset]);
}
}
}
}
-void MultilayerValueOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler /*sampler*/)
+void MultilayerValueOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
- if (this->m_imageFloatBuffer == nullptr) {
+ if (image_float_buffer_ == nullptr) {
output[0] = 0.0f;
}
else {
int yi = y;
int xi = x;
- if (xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() ||
- (unsigned int)yi >= this->getHeight()) {
+ if (xi < 0 || yi < 0 || (unsigned int)xi >= this->get_width() ||
+ (unsigned int)yi >= this->get_height()) {
output[0] = 0.0f;
}
else {
- float result = this->m_imageFloatBuffer[yi * this->getWidth() + xi];
+ float result = image_float_buffer_[yi * this->get_width() + xi];
output[0] = result;
}
}
}
-void MultilayerVectorOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler /*sampler*/)
+void MultilayerVectorOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
- if (this->m_imageFloatBuffer == nullptr) {
+ if (image_float_buffer_ == nullptr) {
output[0] = 0.0f;
}
else {
int yi = y;
int xi = x;
- if (xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() ||
- (unsigned int)yi >= this->getHeight()) {
+ if (xi < 0 || yi < 0 || (unsigned int)xi >= this->get_width() ||
+ (unsigned int)yi >= this->get_height()) {
output[0] = 0.0f;
}
else {
- int offset = (yi * this->getWidth() + xi) * 3;
- copy_v3_v3(output, &this->m_imageFloatBuffer[offset]);
+ int offset = (yi * this->get_width() + xi) * 3;
+ copy_v3_v3(output, &image_float_buffer_[offset]);
}
}
}
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.h b/source/blender/compositor/operations/COM_MultilayerImageOperation.h
index a682ca1941c..ea5b0fb46ea 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.h
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.h
@@ -24,13 +24,13 @@ namespace blender::compositor {
class MultilayerBaseOperation : public BaseImageOperation {
private:
- int m_passId;
- int m_view;
+ int pass_id_;
+ int view_;
protected:
- RenderLayer *m_renderLayer;
- RenderPass *m_renderPass;
- ImBuf *getImBuf() override;
+ RenderLayer *render_layer_;
+ RenderPass *render_pass_;
+ ImBuf *get_im_buf() override;
public:
/**
@@ -48,10 +48,10 @@ class MultilayerColorOperation : public MultilayerBaseOperation {
MultilayerColorOperation(RenderLayer *render_layer, RenderPass *render_pass, int view)
: MultilayerBaseOperation(render_layer, render_pass, view)
{
- this->addOutputSocket(DataType::Color);
+ this->add_output_socket(DataType::Color);
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
- std::unique_ptr<MetaData> getMetaData() override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
+ std::unique_ptr<MetaData> get_meta_data() override;
};
class MultilayerValueOperation : public MultilayerBaseOperation {
@@ -59,9 +59,9 @@ class MultilayerValueOperation : public MultilayerBaseOperation {
MultilayerValueOperation(RenderLayer *render_layer, RenderPass *render_pass, int view)
: MultilayerBaseOperation(render_layer, render_pass, view)
{
- this->addOutputSocket(DataType::Value);
+ this->add_output_socket(DataType::Value);
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
};
class MultilayerVectorOperation : public MultilayerBaseOperation {
@@ -69,9 +69,9 @@ class MultilayerVectorOperation : public MultilayerBaseOperation {
MultilayerVectorOperation(RenderLayer *render_layer, RenderPass *render_pass, int view)
: MultilayerBaseOperation(render_layer, render_pass, view)
{
- this->addOutputSocket(DataType::Vector);
+ this->add_output_socket(DataType::Vector);
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.cc b/source/blender/compositor/operations/COM_NormalizeOperation.cc
index 7d79b375b45..0625cdb5ddb 100644
--- a/source/blender/compositor/operations/COM_NormalizeOperation.cc
+++ b/source/blender/compositor/operations/COM_NormalizeOperation.cc
@@ -22,25 +22,25 @@ namespace blender::compositor {
NormalizeOperation::NormalizeOperation()
{
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Value);
- this->m_imageReader = nullptr;
- this->m_cachedInstance = nullptr;
- this->flags.complex = true;
- flags.can_be_constant = true;
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Value);
+ image_reader_ = nullptr;
+ cached_instance_ = nullptr;
+ flags_.complex = true;
+ flags_.can_be_constant = true;
}
-void NormalizeOperation::initExecution()
+void NormalizeOperation::init_execution()
{
- this->m_imageReader = this->getInputSocketReader(0);
- NodeOperation::initMutex();
+ image_reader_ = this->get_input_socket_reader(0);
+ NodeOperation::init_mutex();
}
-void NormalizeOperation::executePixel(float output[4], int x, int y, void *data)
+void NormalizeOperation::execute_pixel(float output[4], int x, int y, void *data)
{
/* using generic two floats struct to store `x: min`, `y: multiply` */
NodeTwoFloats *minmult = (NodeTwoFloats *)data;
- this->m_imageReader->read(output, x, y, nullptr);
+ image_reader_->read(output, x, y, nullptr);
output[0] = (output[0] - minmult->x) * minmult->y;
@@ -53,30 +53,30 @@ void NormalizeOperation::executePixel(float output[4], int x, int y, void *data)
}
}
-void NormalizeOperation::deinitExecution()
+void NormalizeOperation::deinit_execution()
{
- this->m_imageReader = nullptr;
- delete this->m_cachedInstance;
- m_cachedInstance = nullptr;
- NodeOperation::deinitMutex();
+ image_reader_ = nullptr;
+ delete cached_instance_;
+ cached_instance_ = nullptr;
+ NodeOperation::deinit_mutex();
}
-bool NormalizeOperation::determineDependingAreaOfInterest(rcti * /*input*/,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool NormalizeOperation::determine_depending_area_of_interest(rcti * /*input*/,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti imageInput;
- if (this->m_cachedInstance) {
+ rcti image_input;
+ if (cached_instance_) {
return false;
}
- NodeOperation *operation = getInputOperation(0);
- imageInput.xmax = operation->getWidth();
- imageInput.xmin = 0;
- imageInput.ymax = operation->getHeight();
- imageInput.ymin = 0;
+ NodeOperation *operation = get_input_operation(0);
+ image_input.xmax = operation->get_width();
+ image_input.xmin = 0;
+ image_input.ymax = operation->get_height();
+ image_input.ymin = 0;
- if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output)) {
+ if (operation->determine_depending_area_of_interest(&image_input, read_operation, output)) {
return true;
}
return false;
@@ -86,16 +86,16 @@ bool NormalizeOperation::determineDependingAreaOfInterest(rcti * /*input*/,
*/
#define BLENDER_ZMAX 10000.0f
-void *NormalizeOperation::initializeTileData(rcti *rect)
+void *NormalizeOperation::initialize_tile_data(rcti *rect)
{
- lockMutex();
- if (this->m_cachedInstance == nullptr) {
- MemoryBuffer *tile = (MemoryBuffer *)this->m_imageReader->initializeTileData(rect);
+ lock_mutex();
+ if (cached_instance_ == nullptr) {
+ MemoryBuffer *tile = (MemoryBuffer *)image_reader_->initialize_tile_data(rect);
/* using generic two floats struct to store `x: min`, `y: multiply`. */
NodeTwoFloats *minmult = new NodeTwoFloats();
- float *buffer = tile->getBuffer();
- int p = tile->getWidth() * tile->getHeight();
+ float *buffer = tile->get_buffer();
+ int p = tile->get_width() * tile->get_height();
float *bc = buffer;
float minv = 1.0f + BLENDER_ZMAX;
@@ -117,14 +117,14 @@ void *NormalizeOperation::initializeTileData(rcti *rect)
/* The rare case of flat buffer would cause a divide by 0 */
minmult->y = ((maxv != minv) ? 1.0f / (maxv - minv) : 0.0f);
- this->m_cachedInstance = minmult;
+ cached_instance_ = minmult;
}
- unlockMutex();
- return this->m_cachedInstance;
+ unlock_mutex();
+ return cached_instance_;
}
-void NormalizeOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/)
+void NormalizeOperation::deinitialize_tile_data(rcti * /*rect*/, void * /*data*/)
{
/* pass */
}
@@ -140,7 +140,7 @@ void NormalizeOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(outpu
const rcti &UNUSED(area),
Span<MemoryBuffer *> inputs)
{
- if (m_cachedInstance == nullptr) {
+ if (cached_instance_ == nullptr) {
MemoryBuffer *input = inputs[0];
/* Using generic two floats struct to store `x: min`, `y: multiply`. */
@@ -162,7 +162,7 @@ void NormalizeOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(outpu
/* The case of a flat buffer would cause a divide by 0. */
minmult->y = ((maxv != minv) ? 1.0f / (maxv - minv) : 0.0f);
- m_cachedInstance = minmult;
+ cached_instance_ = minmult;
}
}
@@ -170,7 +170,7 @@ void NormalizeOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- NodeTwoFloats *minmult = m_cachedInstance;
+ NodeTwoFloats *minmult = cached_instance_;
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
const float input_value = *it.in(0);
diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.h b/source/blender/compositor/operations/COM_NormalizeOperation.h
index 7af2aad8a88..dd9abcfad26 100644
--- a/source/blender/compositor/operations/COM_NormalizeOperation.h
+++ b/source/blender/compositor/operations/COM_NormalizeOperation.h
@@ -32,13 +32,13 @@ class NormalizeOperation : public MultiThreadedOperation {
/**
* \brief Cached reference to the reader
*/
- SocketReader *m_imageReader;
+ SocketReader *image_reader_;
/**
* \brief temporarily cache of the execution storage
* it stores `x->min` and `y->multiply`.
*/
- NodeTwoFloats *m_cachedInstance;
+ NodeTwoFloats *cached_instance_;
public:
NormalizeOperation();
@@ -46,24 +46,24 @@ class NormalizeOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
- void *initializeTileData(rcti *rect) override;
- void deinitializeTileData(rcti *rect, void *data) override;
+ void *initialize_tile_data(rcti *rect) override;
+ void deinitialize_tile_data(rcti *rect, void *data) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_started(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_OpenCLKernels.cl b/source/blender/compositor/operations/COM_OpenCLKernels.cl
index ebe8a6d08ec..d01e209d3e4 100644
--- a/source/blender/compositor/operations/COM_OpenCLKernels.cl
+++ b/source/blender/compositor/operations/COM_OpenCLKernels.cl
@@ -29,101 +29,101 @@ const sampler_t SAMPLER_NEAREST_CLAMP = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRES
__constant const int2 zero = {0,0};
// KERNEL --- BOKEH BLUR ---
-__kernel void bokehBlurKernel(__read_only image2d_t boundingBox, __read_only image2d_t inputImage,
- __read_only image2d_t bokehImage, __write_only image2d_t output,
- int2 offsetInput, int2 offsetOutput, int radius, int step, int2 dimension, int2 offset)
+__kernel void bokeh_blur_kernel(__read_only image2d_t bounding_box, __read_only image2d_t input_image,
+ __read_only image2d_t bokeh_image, __write_only image2d_t output,
+ int2 offset_input, int2 offset_output, int radius, int step, int2 dimension, int2 offset)
{
int2 coords = {get_global_id(0), get_global_id(1)};
coords += offset;
- float tempBoundingBox;
+ float temp_bounding_box;
float4 color = {0.0f,0.0f,0.0f,0.0f};
float4 multiplyer = {0.0f,0.0f,0.0f,0.0f};
float4 bokeh;
const float radius2 = radius*2.0f;
- const int2 realCoordinate = coords + offsetOutput;
- int2 imageCoordinates = realCoordinate - offsetInput;
+ const int2 real_coordinate = coords + offset_output;
+ int2 image_coordinates = real_coordinate - offset_input;
- tempBoundingBox = read_imagef(boundingBox, SAMPLER_NEAREST, coords).s0;
+ temp_bounding_box = read_imagef(bounding_box, SAMPLER_NEAREST, coords).s0;
- if (tempBoundingBox > 0.0f && radius > 0 ) {
- const int2 bokehImageDim = get_image_dim(bokehImage);
- const int2 bokehImageCenter = bokehImageDim/2;
- const int2 minXY = max(realCoordinate - radius, zero);
- const int2 maxXY = min(realCoordinate + radius, dimension);
+ if (temp_bounding_box > 0.0f && radius > 0 ) {
+ const int2 bokeh_image_dim = get_image_dim(bokeh_image);
+ const int2 bokeh_image_center = bokeh_image_dim/2;
+ const int2 minXY = max(real_coordinate - radius, zero);
+ const int2 maxXY = min(real_coordinate + radius, dimension);
int nx, ny;
float2 uv;
- int2 inputXy;
+ int2 input_xy;
if (radius < 2) {
- color = read_imagef(inputImage, SAMPLER_NEAREST, imageCoordinates);
+ color = read_imagef(input_image, SAMPLER_NEAREST, image_coordinates);
multiplyer = (float4)(1.0f, 1.0f, 1.0f, 1.0f);
}
- for (ny = minXY.y, inputXy.y = ny - offsetInput.y ; ny < maxXY.y ; ny += step, inputXy.y += step) {
- uv.y = ((realCoordinate.y-ny)/radius2)*bokehImageDim.y+bokehImageCenter.y;
+ for (ny = minXY.y, input_xy.y = ny - offset_input.y ; ny < maxXY.y ; ny += step, input_xy.y += step) {
+ uv.y = ((real_coordinate.y-ny)/radius2)*bokeh_image_dim.y+bokeh_image_center.y;
- for (nx = minXY.x, inputXy.x = nx - offsetInput.x; nx < maxXY.x ; nx += step, inputXy.x += step) {
- uv.x = ((realCoordinate.x-nx)/radius2)*bokehImageDim.x+bokehImageCenter.x;
- bokeh = read_imagef(bokehImage, SAMPLER_NEAREST, uv);
- color += bokeh * read_imagef(inputImage, SAMPLER_NEAREST, inputXy);
+ for (nx = minXY.x, input_xy.x = nx - offset_input.x; nx < maxXY.x ; nx += step, input_xy.x += step) {
+ uv.x = ((real_coordinate.x-nx)/radius2)*bokeh_image_dim.x+bokeh_image_center.x;
+ bokeh = read_imagef(bokeh_image, SAMPLER_NEAREST, uv);
+ color += bokeh * read_imagef(input_image, SAMPLER_NEAREST, input_xy);
multiplyer += bokeh;
}
}
color /= multiplyer;
}
else {
- color = read_imagef(inputImage, SAMPLER_NEAREST, imageCoordinates);
+ color = read_imagef(input_image, SAMPLER_NEAREST, image_coordinates);
}
write_imagef(output, coords, color);
}
//KERNEL --- DEFOCUS /VARIABLESIZEBOKEHBLUR ---
-__kernel void defocusKernel(__read_only image2d_t inputImage, __read_only image2d_t bokehImage,
- __read_only image2d_t inputSize,
- __write_only image2d_t output, int2 offsetInput, int2 offsetOutput,
- int step, int maxBlurScalar, float threshold, float scalar, int2 dimension, int2 offset)
+__kernel void defocus_kernel(__read_only image2d_t input_image, __read_only image2d_t bokeh_image,
+ __read_only image2d_t input_size,
+ __write_only image2d_t output, int2 offset_input, int2 offset_output,
+ int step, int max_blur_scalar, float threshold, float scalar, int2 dimension, int2 offset)
{
float4 color = {1.0f, 0.0f, 0.0f, 1.0f};
int2 coords = {get_global_id(0), get_global_id(1)};
coords += offset;
- const int2 realCoordinate = coords + offsetOutput;
+ const int2 real_coordinate = coords + offset_output;
- float4 readColor;
- float4 tempColor;
+ float4 read_color;
+ float4 temp_color;
float4 bokeh;
float size;
float4 multiplier_accum = {1.0f, 1.0f, 1.0f, 1.0f};
float4 color_accum;
- int minx = max(realCoordinate.s0 - maxBlurScalar, 0);
- int miny = max(realCoordinate.s1 - maxBlurScalar, 0);
- int maxx = min(realCoordinate.s0 + maxBlurScalar, dimension.s0);
- int maxy = min(realCoordinate.s1 + maxBlurScalar, dimension.s1);
+ int minx = max(real_coordinate.s0 - max_blur_scalar, 0);
+ int miny = max(real_coordinate.s1 - max_blur_scalar, 0);
+ int maxx = min(real_coordinate.s0 + max_blur_scalar, dimension.s0);
+ int maxy = min(real_coordinate.s1 + max_blur_scalar, dimension.s1);
{
- int2 inputCoordinate = realCoordinate - offsetInput;
- float size_center = read_imagef(inputSize, SAMPLER_NEAREST, inputCoordinate).s0 * scalar;
- color_accum = read_imagef(inputImage, SAMPLER_NEAREST, inputCoordinate);
- readColor = color_accum;
+ int2 input_coordinate = real_coordinate - offset_input;
+ float size_center = read_imagef(input_size, SAMPLER_NEAREST, input_coordinate).s0 * scalar;
+ color_accum = read_imagef(input_image, SAMPLER_NEAREST, input_coordinate);
+ read_color = color_accum;
if (size_center > threshold) {
for (int ny = miny; ny < maxy; ny += step) {
- inputCoordinate.s1 = ny - offsetInput.s1;
- float dy = ny - realCoordinate.s1;
+ input_coordinate.s1 = ny - offset_input.s1;
+ float dy = ny - real_coordinate.s1;
for (int nx = minx; nx < maxx; nx += step) {
- float dx = nx - realCoordinate.s0;
+ float dx = nx - real_coordinate.s0;
if (dx != 0 || dy != 0) {
- inputCoordinate.s0 = nx - offsetInput.s0;
- size = min(read_imagef(inputSize, SAMPLER_NEAREST, inputCoordinate).s0 * scalar, size_center);
+ input_coordinate.s0 = nx - offset_input.s0;
+ size = min(read_imagef(input_size, SAMPLER_NEAREST, input_coordinate).s0 * scalar, size_center);
if (size > threshold) {
if (size >= fabs(dx) && size >= fabs(dy)) {
float2 uv = {256.0f + dx * 255.0f / size,
256.0f + dy * 255.0f / size};
- bokeh = read_imagef(bokehImage, SAMPLER_NEAREST, uv);
- tempColor = read_imagef(inputImage, SAMPLER_NEAREST, inputCoordinate);
- color_accum += bokeh * tempColor;
+ bokeh = read_imagef(bokeh_image, SAMPLER_NEAREST, uv);
+ temp_color = read_imagef(input_image, SAMPLER_NEAREST, input_coordinate);
+ color_accum += bokeh * temp_color;
multiplier_accum += bokeh;
}
}
@@ -140,7 +140,7 @@ __kernel void defocusKernel(__read_only image2d_t inputImage, __read_only image2
{
/* factor from 0-1 */
float fac = (size_center - threshold) / threshold;
- color = (readColor * (1.0f - fac)) + (color * fac);
+ color = (read_color * (1.0f - fac)) + (color * fac);
}
write_imagef(output, coords, color);
@@ -149,28 +149,28 @@ __kernel void defocusKernel(__read_only image2d_t inputImage, __read_only image2
// KERNEL --- DILATE ---
-__kernel void dilateKernel(__read_only image2d_t inputImage, __write_only image2d_t output,
- int2 offsetInput, int2 offsetOutput, int scope, int distanceSquared, int2 dimension,
+__kernel void dilate_kernel(__read_only image2d_t input_image, __write_only image2d_t output,
+ int2 offset_input, int2 offset_output, int scope, int distance_squared, int2 dimension,
int2 offset)
{
int2 coords = {get_global_id(0), get_global_id(1)};
coords += offset;
- const int2 realCoordinate = coords + offsetOutput;
+ const int2 real_coordinate = coords + offset_output;
- const int2 minXY = max(realCoordinate - scope, zero);
- const int2 maxXY = min(realCoordinate + scope, dimension);
+ const int2 minXY = max(real_coordinate - scope, zero);
+ const int2 maxXY = min(real_coordinate + scope, dimension);
float value = 0.0f;
int nx, ny;
- int2 inputXy;
+ int2 input_xy;
- for (ny = minXY.y, inputXy.y = ny - offsetInput.y ; ny < maxXY.y ; ny ++, inputXy.y++) {
- const float deltaY = (realCoordinate.y - ny);
- for (nx = minXY.x, inputXy.x = nx - offsetInput.x; nx < maxXY.x ; nx ++, inputXy.x++) {
- const float deltaX = (realCoordinate.x - nx);
- const float measuredDistance = deltaX * deltaX + deltaY * deltaY;
- if (measuredDistance <= distanceSquared) {
- value = max(value, read_imagef(inputImage, SAMPLER_NEAREST, inputXy).s0);
+ for (ny = minXY.y, input_xy.y = ny - offset_input.y ; ny < maxXY.y ; ny ++, input_xy.y++) {
+ const float deltaY = (real_coordinate.y - ny);
+ for (nx = minXY.x, input_xy.x = nx - offset_input.x; nx < maxXY.x ; nx ++, input_xy.x++) {
+ const float deltaX = (real_coordinate.x - nx);
+ const float measured_distance = deltaX * deltaX + deltaY * deltaY;
+ if (measured_distance <= distance_squared) {
+ value = max(value, read_imagef(input_image, SAMPLER_NEAREST, input_xy).s0);
}
}
}
@@ -180,28 +180,28 @@ __kernel void dilateKernel(__read_only image2d_t inputImage, __write_only image
}
// KERNEL --- DILATE ---
-__kernel void erodeKernel(__read_only image2d_t inputImage, __write_only image2d_t output,
- int2 offsetInput, int2 offsetOutput, int scope, int distanceSquared, int2 dimension,
+__kernel void erode_kernel(__read_only image2d_t input_image, __write_only image2d_t output,
+ int2 offset_input, int2 offset_output, int scope, int distance_squared, int2 dimension,
int2 offset)
{
int2 coords = {get_global_id(0), get_global_id(1)};
coords += offset;
- const int2 realCoordinate = coords + offsetOutput;
+ const int2 real_coordinate = coords + offset_output;
- const int2 minXY = max(realCoordinate - scope, zero);
- const int2 maxXY = min(realCoordinate + scope, dimension);
+ const int2 minXY = max(real_coordinate - scope, zero);
+ const int2 maxXY = min(real_coordinate + scope, dimension);
float value = 1.0f;
int nx, ny;
- int2 inputXy;
+ int2 input_xy;
- for (ny = minXY.y, inputXy.y = ny - offsetInput.y ; ny < maxXY.y ; ny ++, inputXy.y++) {
- for (nx = minXY.x, inputXy.x = nx - offsetInput.x; nx < maxXY.x ; nx ++, inputXy.x++) {
- const float deltaX = (realCoordinate.x - nx);
- const float deltaY = (realCoordinate.y - ny);
- const float measuredDistance = deltaX * deltaX+deltaY * deltaY;
- if (measuredDistance <= distanceSquared) {
- value = min(value, read_imagef(inputImage, SAMPLER_NEAREST, inputXy).s0);
+ for (ny = minXY.y, input_xy.y = ny - offset_input.y ; ny < maxXY.y ; ny ++, input_xy.y++) {
+ for (nx = minXY.x, input_xy.x = nx - offset_input.x; nx < maxXY.x ; nx ++, input_xy.x++) {
+ const float deltaX = (real_coordinate.x - nx);
+ const float deltaY = (real_coordinate.y - ny);
+ const float measured_distance = deltaX * deltaX+deltaY * deltaY;
+ if (measured_distance <= distance_squared) {
+ value = min(value, read_imagef(input_image, SAMPLER_NEAREST, input_xy).s0);
}
}
}
@@ -211,34 +211,34 @@ __kernel void erodeKernel(__read_only image2d_t inputImage, __write_only image2
}
// KERNEL --- DIRECTIONAL BLUR ---
-__kernel void directionalBlurKernel(__read_only image2d_t inputImage, __write_only image2d_t output,
- int2 offsetOutput, int iterations, float scale, float rotation, float2 translate,
+__kernel void directional_blur_kernel(__read_only image2d_t input_image, __write_only image2d_t output,
+ int2 offset_output, int iterations, float scale, float rotation, float2 translate,
float2 center, int2 offset)
{
int2 coords = {get_global_id(0), get_global_id(1)};
coords += offset;
- const int2 realCoordinate = coords + offsetOutput;
+ const int2 real_coordinate = coords + offset_output;
float4 col;
float2 ltxy = translate;
float lsc = scale;
float lrot = rotation;
- col = read_imagef(inputImage, SAMPLER_NEAREST, realCoordinate);
+ col = read_imagef(input_image, SAMPLER_NEAREST, real_coordinate);
/* blur the image */
for (int i = 0; i < iterations; ++i) {
const float cs = cos(lrot), ss = sin(lrot);
const float isc = 1.0f / (1.0f + lsc);
- const float v = isc * (realCoordinate.s1 - center.s1) + ltxy.s1;
- const float u = isc * (realCoordinate.s0 - center.s0) + ltxy.s0;
+ const float v = isc * (real_coordinate.s1 - center.s1) + ltxy.s1;
+ const float u = isc * (real_coordinate.s0 - center.s0) + ltxy.s0;
float2 uv = {
cs * u + ss * v + center.s0,
cs * v - ss * u + center.s1
};
- col += read_imagef(inputImage, SAMPLER_NEAREST_CLAMP, uv);
+ col += read_imagef(input_image, SAMPLER_NEAREST_CLAMP, uv);
/* double transformations */
ltxy += translate;
@@ -252,10 +252,10 @@ __kernel void directionalBlurKernel(__read_only image2d_t inputImage, __write_o
}
// KERNEL --- GAUSSIAN BLUR ---
-__kernel void gaussianXBlurOperationKernel(__read_only image2d_t inputImage,
- int2 offsetInput,
+__kernel void gaussian_xblur_operation_kernel(__read_only image2d_t input_image,
+ int2 offset_input,
__write_only image2d_t output,
- int2 offsetOutput,
+ int2 offset_output,
int filter_size,
int2 dimension,
__global float *gausstab,
@@ -264,17 +264,17 @@ __kernel void gaussianXBlurOperationKernel(__read_only image2d_t inputImage,
float4 color = {0.0f, 0.0f, 0.0f, 0.0f};
int2 coords = {get_global_id(0), get_global_id(1)};
coords += offset;
- const int2 realCoordinate = coords + offsetOutput;
- int2 inputCoordinate = realCoordinate - offsetInput;
+ const int2 real_coordinate = coords + offset_output;
+ int2 input_coordinate = real_coordinate - offset_input;
float weight = 0.0f;
- int xmin = max(realCoordinate.x - filter_size, 0) - offsetInput.x;
- int xmax = min(realCoordinate.x + filter_size + 1, dimension.x) - offsetInput.x;
+ int xmin = max(real_coordinate.x - filter_size, 0) - offset_input.x;
+ int xmax = min(real_coordinate.x + filter_size + 1, dimension.x) - offset_input.x;
- for (int nx = xmin, i = max(filter_size - realCoordinate.x, 0); nx < xmax; ++nx, ++i) {
+ for (int nx = xmin, i = max(filter_size - real_coordinate.x, 0); nx < xmax; ++nx, ++i) {
float w = gausstab[i];
- inputCoordinate.x = nx;
- color += read_imagef(inputImage, SAMPLER_NEAREST, inputCoordinate) * w;
+ input_coordinate.x = nx;
+ color += read_imagef(input_image, SAMPLER_NEAREST, input_coordinate) * w;
weight += w;
}
@@ -283,10 +283,10 @@ __kernel void gaussianXBlurOperationKernel(__read_only image2d_t inputImage,
write_imagef(output, coords, color);
}
-__kernel void gaussianYBlurOperationKernel(__read_only image2d_t inputImage,
- int2 offsetInput,
+__kernel void gaussian_yblur_operation_kernel(__read_only image2d_t input_image,
+ int2 offset_input,
__write_only image2d_t output,
- int2 offsetOutput,
+ int2 offset_output,
int filter_size,
int2 dimension,
__global float *gausstab,
@@ -295,17 +295,17 @@ __kernel void gaussianYBlurOperationKernel(__read_only image2d_t inputImage,
float4 color = {0.0f, 0.0f, 0.0f, 0.0f};
int2 coords = {get_global_id(0), get_global_id(1)};
coords += offset;
- const int2 realCoordinate = coords + offsetOutput;
- int2 inputCoordinate = realCoordinate - offsetInput;
+ const int2 real_coordinate = coords + offset_output;
+ int2 input_coordinate = real_coordinate - offset_input;
float weight = 0.0f;
- int ymin = max(realCoordinate.y - filter_size, 0) - offsetInput.y;
- int ymax = min(realCoordinate.y + filter_size + 1, dimension.y) - offsetInput.y;
+ int ymin = max(real_coordinate.y - filter_size, 0) - offset_input.y;
+ int ymax = min(real_coordinate.y + filter_size + 1, dimension.y) - offset_input.y;
- for (int ny = ymin, i = max(filter_size - realCoordinate.y, 0); ny < ymax; ++ny, ++i) {
+ for (int ny = ymin, i = max(filter_size - real_coordinate.y, 0); ny < ymax; ++ny, ++i) {
float w = gausstab[i];
- inputCoordinate.y = ny;
- color += read_imagef(inputImage, SAMPLER_NEAREST, inputCoordinate) * w;
+ input_coordinate.y = ny;
+ color += read_imagef(input_image, SAMPLER_NEAREST, input_coordinate) * w;
weight += w;
}
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
index d436b00a6e3..7f2968a4719 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
@@ -17,22 +17,11 @@
*/
#include "COM_OutputFileMultiViewOperation.h"
-#include "COM_OutputFileOperation.h"
-#include <cstring>
-
-#include "BLI_listbase.h"
-#include "BLI_path_util.h"
-#include "BLI_string.h"
-
-#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_scene.h"
-#include "DNA_color_types.h"
-#include "MEM_guardedalloc.h"
-
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -47,19 +36,26 @@ OutputOpenExrSingleLayerMultiViewOperation::OutputOpenExrSingleLayerMultiViewOpe
DataType datatype,
ImageFormatData *format,
const char *path,
- const ColorManagedViewSettings *viewSettings,
- const ColorManagedDisplaySettings *displaySettings,
- const char *viewName,
- const bool saveAsRender)
- : OutputSingleLayerOperation(
- rd, tree, datatype, format, path, viewSettings, displaySettings, viewName, saveAsRender)
+ const ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ const char *view_name,
+ const bool save_as_render)
+ : OutputSingleLayerOperation(rd,
+ tree,
+ datatype,
+ format,
+ path,
+ view_settings,
+ display_settings,
+ view_name,
+ save_as_render)
{
}
void *OutputOpenExrSingleLayerMultiViewOperation::get_handle(const char *filename)
{
- size_t width = this->getWidth();
- size_t height = this->getHeight();
+ size_t width = this->get_width();
+ size_t height = this->get_height();
SceneRenderView *srv;
if (width != 0 && height != 0) {
@@ -67,27 +63,26 @@ void *OutputOpenExrSingleLayerMultiViewOperation::get_handle(const char *filenam
exrhandle = IMB_exr_get_handle_name(filename);
- if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName)) {
+ if (!BKE_scene_multiview_is_render_view_first(rd_, view_name_)) {
return exrhandle;
}
IMB_exr_clear_channels(exrhandle);
- for (srv = (SceneRenderView *)this->m_rd->views.first; srv; srv = srv->next) {
- if (BKE_scene_multiview_is_render_view_active(this->m_rd, srv) == false) {
+ for (srv = (SceneRenderView *)rd_->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd_, srv) == false) {
continue;
}
IMB_exr_add_view(exrhandle, srv->name);
- add_exr_channels(exrhandle, nullptr, this->m_datatype, srv->name, width, false, nullptr);
+ add_exr_channels(exrhandle, nullptr, datatype_, srv->name, width, false, nullptr);
}
BLI_make_existing_file(filename);
/* prepare the file with all the channels */
- if (!IMB_exr_begin_write(
- exrhandle, filename, width, height, this->m_format->exr_codec, nullptr)) {
+ if (!IMB_exr_begin_write(exrhandle, filename, width, height, format_->exr_codec, nullptr)) {
printf("Error Writing Singlelayer Multiview Openexr\n");
IMB_exr_close(exrhandle);
}
@@ -99,43 +94,43 @@ void *OutputOpenExrSingleLayerMultiViewOperation::get_handle(const char *filenam
return nullptr;
}
-void OutputOpenExrSingleLayerMultiViewOperation::deinitExecution()
+void OutputOpenExrSingleLayerMultiViewOperation::deinit_execution()
{
- unsigned int width = this->getWidth();
- unsigned int height = this->getHeight();
+ unsigned int width = this->get_width();
+ unsigned int height = this->get_height();
if (width != 0 && height != 0) {
void *exrhandle;
char filename[FILE_MAX];
BKE_image_path_from_imtype(filename,
- this->m_path,
+ path_,
BKE_main_blendfile_path_from_global(),
- this->m_rd->cfra,
+ rd_->cfra,
R_IMF_IMTYPE_OPENEXR,
- (this->m_rd->scemode & R_EXTENSION) != 0,
+ (rd_->scemode & R_EXTENSION) != 0,
true,
nullptr);
exrhandle = this->get_handle(filename);
add_exr_channels(exrhandle,
nullptr,
- this->m_datatype,
- this->m_viewName,
+ datatype_,
+ view_name_,
width,
- this->m_format->depth == R_IMF_CHAN_DEPTH_16,
- this->m_outputBuffer);
+ format_->depth == R_IMF_CHAN_DEPTH_16,
+ output_buffer_);
/* memory can only be freed after we write all views to the file */
- this->m_outputBuffer = nullptr;
- this->m_imageInput = nullptr;
+ output_buffer_ = nullptr;
+ image_input_ = nullptr;
/* ready to close the file */
- if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) {
+ if (BKE_scene_multiview_is_render_view_last(rd_, view_name_)) {
IMB_exr_write_channels(exrhandle);
/* free buffer memory for all the views */
- free_exr_channels(exrhandle, this->m_rd, nullptr, this->m_datatype);
+ free_exr_channels(exrhandle, rd_, nullptr, datatype_);
/* remove exr handle and data */
IMB_exr_close(exrhandle);
@@ -152,15 +147,15 @@ OutputOpenExrMultiLayerMultiViewOperation::OutputOpenExrMultiLayerMultiViewOpera
const char *path,
char exr_codec,
bool exr_half_float,
- const char *viewName)
- : OutputOpenExrMultiLayerOperation(scene, rd, tree, path, exr_codec, exr_half_float, viewName)
+ const char *view_name)
+ : OutputOpenExrMultiLayerOperation(scene, rd, tree, path, exr_codec, exr_half_float, view_name)
{
}
void *OutputOpenExrMultiLayerMultiViewOperation::get_handle(const char *filename)
{
- unsigned int width = this->getWidth();
- unsigned int height = this->getHeight();
+ unsigned int width = this->get_width();
+ unsigned int height = this->get_height();
if (width != 0 && height != 0) {
@@ -170,28 +165,28 @@ void *OutputOpenExrMultiLayerMultiViewOperation::get_handle(const char *filename
/* get a new global handle */
exrhandle = IMB_exr_get_handle_name(filename);
- if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName)) {
+ if (!BKE_scene_multiview_is_render_view_first(rd_, view_name_)) {
return exrhandle;
}
IMB_exr_clear_channels(exrhandle);
/* check renderdata for amount of views */
- for (srv = (SceneRenderView *)this->m_rd->views.first; srv; srv = srv->next) {
+ for (srv = (SceneRenderView *)rd_->views.first; srv; srv = srv->next) {
- if (BKE_scene_multiview_is_render_view_active(this->m_rd, srv) == false) {
+ if (BKE_scene_multiview_is_render_view_active(rd_, srv) == false) {
continue;
}
IMB_exr_add_view(exrhandle, srv->name);
- for (unsigned int i = 0; i < this->m_layers.size(); i++) {
+ for (unsigned int i = 0; i < layers_.size(); i++) {
add_exr_channels(exrhandle,
- this->m_layers[i].name,
- this->m_layers[i].datatype,
+ layers_[i].name,
+ layers_[i].datatype,
srv->name,
width,
- this->m_exr_half_float,
+ exr_half_float_,
nullptr);
}
}
@@ -199,8 +194,8 @@ void *OutputOpenExrMultiLayerMultiViewOperation::get_handle(const char *filename
BLI_make_existing_file(filename);
/* prepare the file with all the channels for the header */
- StampData *stamp_data = createStampData();
- if (!IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, stamp_data)) {
+ StampData *stamp_data = create_stamp_data();
+ if (!IMB_exr_begin_write(exrhandle, filename, width, height, exr_codec_, stamp_data)) {
printf("Error Writing Multilayer Multiview Openexr\n");
IMB_exr_close(exrhandle);
BKE_stamp_data_free(stamp_data);
@@ -214,50 +209,49 @@ void *OutputOpenExrMultiLayerMultiViewOperation::get_handle(const char *filename
return nullptr;
}
-void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution()
+void OutputOpenExrMultiLayerMultiViewOperation::deinit_execution()
{
- unsigned int width = this->getWidth();
- unsigned int height = this->getHeight();
+ unsigned int width = this->get_width();
+ unsigned int height = this->get_height();
if (width != 0 && height != 0) {
void *exrhandle;
char filename[FILE_MAX];
BKE_image_path_from_imtype(filename,
- this->m_path,
+ path_,
BKE_main_blendfile_path_from_global(),
- this->m_rd->cfra,
+ rd_->cfra,
R_IMF_IMTYPE_MULTILAYER,
- (this->m_rd->scemode & R_EXTENSION) != 0,
+ (rd_->scemode & R_EXTENSION) != 0,
true,
nullptr);
exrhandle = this->get_handle(filename);
- for (unsigned int i = 0; i < this->m_layers.size(); i++) {
+ for (unsigned int i = 0; i < layers_.size(); i++) {
add_exr_channels(exrhandle,
- this->m_layers[i].name,
- this->m_layers[i].datatype,
- this->m_viewName,
+ layers_[i].name,
+ layers_[i].datatype,
+ view_name_,
width,
- this->m_exr_half_float,
- this->m_layers[i].outputBuffer);
+ exr_half_float_,
+ layers_[i].output_buffer);
}
- for (unsigned int i = 0; i < this->m_layers.size(); i++) {
+ for (unsigned int i = 0; i < layers_.size(); i++) {
/* memory can only be freed after we write all views to the file */
- this->m_layers[i].outputBuffer = nullptr;
- this->m_layers[i].imageInput = nullptr;
+ layers_[i].output_buffer = nullptr;
+ layers_[i].image_input = nullptr;
}
/* ready to close the file */
- if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) {
+ if (BKE_scene_multiview_is_render_view_last(rd_, view_name_)) {
IMB_exr_write_channels(exrhandle);
/* free buffer memory for all the views */
- for (unsigned int i = 0; i < this->m_layers.size(); i++) {
- free_exr_channels(
- exrhandle, this->m_rd, this->m_layers[i].name, this->m_layers[i].datatype);
+ for (unsigned int i = 0; i < layers_.size(); i++) {
+ free_exr_channels(exrhandle, rd_, layers_[i].name, layers_[i].datatype);
}
IMB_exr_close(exrhandle);
@@ -273,21 +267,28 @@ OutputStereoOperation::OutputStereoOperation(const RenderData *rd,
ImageFormatData *format,
const char *path,
const char *name,
- const ColorManagedViewSettings *viewSettings,
- const ColorManagedDisplaySettings *displaySettings,
- const char *viewName,
- const bool saveAsRender)
- : OutputSingleLayerOperation(
- rd, tree, datatype, format, path, viewSettings, displaySettings, viewName, saveAsRender)
+ const ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ const char *view_name,
+ const bool save_as_render)
+ : OutputSingleLayerOperation(rd,
+ tree,
+ datatype,
+ format,
+ path,
+ view_settings,
+ display_settings,
+ view_name,
+ save_as_render)
{
- BLI_strncpy(this->m_name, name, sizeof(this->m_name));
- this->m_channels = get_datatype_size(datatype);
+ BLI_strncpy(name_, name, sizeof(name_));
+ channels_ = get_datatype_size(datatype);
}
void *OutputStereoOperation::get_handle(const char *filename)
{
- size_t width = this->getWidth();
- size_t height = this->getHeight();
+ size_t width = this->get_width();
+ size_t height = this->get_height();
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
size_t i;
@@ -296,7 +297,7 @@ void *OutputStereoOperation::get_handle(const char *filename)
exrhandle = IMB_exr_get_handle_name(filename);
- if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName)) {
+ if (!BKE_scene_multiview_is_render_view_first(rd_, view_name_)) {
return exrhandle;
}
@@ -311,32 +312,32 @@ void *OutputStereoOperation::get_handle(const char *filename)
return nullptr;
}
-void OutputStereoOperation::deinitExecution()
+void OutputStereoOperation::deinit_execution()
{
- unsigned int width = this->getWidth();
- unsigned int height = this->getHeight();
+ unsigned int width = this->get_width();
+ unsigned int height = this->get_height();
if (width != 0 && height != 0) {
void *exrhandle;
- exrhandle = this->get_handle(this->m_path);
- float *buf = this->m_outputBuffer;
+ exrhandle = this->get_handle(path_);
+ float *buf = output_buffer_;
/* populate single EXR channel with view data */
IMB_exr_add_channel(exrhandle,
nullptr,
- this->m_name,
- this->m_viewName,
+ name_,
+ view_name_,
1,
- this->m_channels * width * height,
+ channels_ * width * height,
buf,
- this->m_format->depth == R_IMF_CHAN_DEPTH_16);
+ format_->depth == R_IMF_CHAN_DEPTH_16);
- this->m_imageInput = nullptr;
- this->m_outputBuffer = nullptr;
+ image_input_ = nullptr;
+ output_buffer_ = nullptr;
/* create stereo ibuf */
- if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) {
+ if (BKE_scene_multiview_is_render_view_last(rd_, view_name_)) {
ImBuf *ibuf[3] = {nullptr};
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
char filename[FILE_MAX];
@@ -344,33 +345,33 @@ void OutputStereoOperation::deinitExecution()
/* get rectf from EXR */
for (i = 0; i < 2; i++) {
- float *rectf = IMB_exr_channel_rect(exrhandle, nullptr, this->m_name, names[i]);
- ibuf[i] = IMB_allocImBuf(width, height, this->m_format->planes, 0);
+ float *rectf = IMB_exr_channel_rect(exrhandle, nullptr, name_, names[i]);
+ ibuf[i] = IMB_allocImBuf(width, height, format_->planes, 0);
- ibuf[i]->channels = this->m_channels;
+ ibuf[i]->channels = channels_;
ibuf[i]->rect_float = rectf;
ibuf[i]->mall |= IB_rectfloat;
- ibuf[i]->dither = this->m_rd->dither_intensity;
+ ibuf[i]->dither = rd_->dither_intensity;
/* do colormanagement in the individual views, so it doesn't need to do in the stereo */
IMB_colormanagement_imbuf_for_write(
- ibuf[i], true, false, this->m_viewSettings, this->m_displaySettings, this->m_format);
+ ibuf[i], true, false, view_settings_, display_settings_, format_);
IMB_prepare_write_ImBuf(IMB_isfloat(ibuf[i]), ibuf[i]);
}
/* create stereo buffer */
- ibuf[2] = IMB_stereo3d_ImBuf(this->m_format, ibuf[0], ibuf[1]);
+ ibuf[2] = IMB_stereo3d_ImBuf(format_, ibuf[0], ibuf[1]);
BKE_image_path_from_imformat(filename,
- this->m_path,
+ path_,
BKE_main_blendfile_path_from_global(),
- this->m_rd->cfra,
- this->m_format,
- (this->m_rd->scemode & R_EXTENSION) != 0,
+ rd_->cfra,
+ format_,
+ (rd_->scemode & R_EXTENSION) != 0,
true,
nullptr);
- BKE_imbuf_write(ibuf[2], filename, this->m_format);
+ BKE_imbuf_write(ibuf[2], filename, format_);
/* imbuf knows which rects are not part of ibuf */
for (i = 0; i < 3; i++) {
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
index 6230a6f306b..864eb68ac24 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
@@ -38,13 +38,13 @@ class OutputOpenExrSingleLayerMultiViewOperation : public OutputSingleLayerOpera
DataType datatype,
ImageFormatData *format,
const char *path,
- const ColorManagedViewSettings *viewSettings,
- const ColorManagedDisplaySettings *displaySettings,
- const char *viewName,
- const bool saveAsRender);
+ const ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ const char *view_name,
+ bool save_as_render);
void *get_handle(const char *filename);
- void deinitExecution() override;
+ void deinit_execution() override;
};
/* Writes inputs into OpenEXR multilayer channels. */
@@ -57,16 +57,16 @@ class OutputOpenExrMultiLayerMultiViewOperation : public OutputOpenExrMultiLayer
const char *path,
char exr_codec,
bool exr_half_float,
- const char *viewName);
+ const char *view_name);
void *get_handle(const char *filename);
- void deinitExecution() override;
+ void deinit_execution() override;
};
class OutputStereoOperation : public OutputSingleLayerOperation {
private:
- char m_name[FILE_MAX];
- size_t m_channels;
+ char name_[FILE_MAX];
+ size_t channels_;
public:
OutputStereoOperation(const RenderData *rd,
@@ -75,12 +75,12 @@ class OutputStereoOperation : public OutputSingleLayerOperation {
struct ImageFormatData *format,
const char *path,
const char *name,
- const ColorManagedViewSettings *viewSettings,
- const ColorManagedDisplaySettings *displaySettings,
- const char *viewName,
- const bool saveAsRender);
+ const ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ const char *view_name,
+ bool save_as_render);
void *get_handle(const char *filename);
- void deinitExecution() override;
+ void deinit_execution() override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cc b/source/blender/compositor/operations/COM_OutputFileOperation.cc
index 79be95bb686..77e291e9dc4 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cc
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cc
@@ -18,21 +18,15 @@
#include "COM_OutputFileOperation.h"
-#include "COM_MetaData.h"
-
-#include <cstring>
-
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
-#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_scene.h"
#include "DNA_color_types.h"
-#include "MEM_guardedalloc.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
@@ -43,9 +37,9 @@
namespace blender::compositor {
void add_exr_channels(void *exrhandle,
- const char *layerName,
+ const char *layer_name,
const DataType datatype,
- const char *viewName,
+ const char *view_name,
const size_t width,
bool use_half_float,
float *buf)
@@ -54,51 +48,63 @@ void add_exr_channels(void *exrhandle,
switch (datatype) {
case DataType::Value:
IMB_exr_add_channel(
- exrhandle, layerName, "V", viewName, 1, width, buf ? buf : nullptr, use_half_float);
+ exrhandle, layer_name, "V", view_name, 1, width, buf ? buf : nullptr, use_half_float);
break;
case DataType::Vector:
- IMB_exr_add_channel(
- exrhandle, layerName, "X", viewName, 3, 3 * width, buf ? buf : nullptr, use_half_float);
IMB_exr_add_channel(exrhandle,
- layerName,
+ layer_name,
+ "X",
+ view_name,
+ 3,
+ 3 * width,
+ buf ? buf : nullptr,
+ use_half_float);
+ IMB_exr_add_channel(exrhandle,
+ layer_name,
"Y",
- viewName,
+ view_name,
3,
3 * width,
buf ? buf + 1 : nullptr,
use_half_float);
IMB_exr_add_channel(exrhandle,
- layerName,
+ layer_name,
"Z",
- viewName,
+ view_name,
3,
3 * width,
buf ? buf + 2 : nullptr,
use_half_float);
break;
case DataType::Color:
- IMB_exr_add_channel(
- exrhandle, layerName, "R", viewName, 4, 4 * width, buf ? buf : nullptr, use_half_float);
IMB_exr_add_channel(exrhandle,
- layerName,
+ layer_name,
+ "R",
+ view_name,
+ 4,
+ 4 * width,
+ buf ? buf : nullptr,
+ use_half_float);
+ IMB_exr_add_channel(exrhandle,
+ layer_name,
"G",
- viewName,
+ view_name,
4,
4 * width,
buf ? buf + 1 : nullptr,
use_half_float);
IMB_exr_add_channel(exrhandle,
- layerName,
+ layer_name,
"B",
- viewName,
+ view_name,
4,
4 * width,
buf ? buf + 2 : nullptr,
use_half_float);
IMB_exr_add_channel(exrhandle,
- layerName,
+ layer_name,
"A",
- viewName,
+ view_name,
4,
4 * width,
buf ? buf + 3 : nullptr,
@@ -111,7 +117,7 @@ void add_exr_channels(void *exrhandle,
void free_exr_channels(void *exrhandle,
const RenderData *rd,
- const char *layerName,
+ const char *layer_name,
const DataType datatype)
{
SceneRenderView *srv;
@@ -127,13 +133,13 @@ void free_exr_channels(void *exrhandle,
/* the pointer is stored in the first channel of each datatype */
switch (datatype) {
case DataType::Value:
- rect = IMB_exr_channel_rect(exrhandle, layerName, "V", srv->name);
+ rect = IMB_exr_channel_rect(exrhandle, layer_name, "V", srv->name);
break;
case DataType::Vector:
- rect = IMB_exr_channel_rect(exrhandle, layerName, "X", srv->name);
+ rect = IMB_exr_channel_rect(exrhandle, layer_name, "X", srv->name);
break;
case DataType::Color:
- rect = IMB_exr_channel_rect(exrhandle, layerName, "R", srv->name);
+ rect = IMB_exr_channel_rect(exrhandle, layer_name, "R", srv->name);
break;
default:
break;
@@ -193,7 +199,7 @@ static void write_buffer_rect(rcti *rect,
for (y = y1; y < y2 && (!breaked); y++) {
for (x = x1; x < x2 && (!breaked); x++) {
- reader->readSampled(color, x, y, PixelSampler::Nearest);
+ reader->read_sampled(color, x, y, PixelSampler::Nearest);
for (i = 0; i < size; i++) {
buffer[offset + i] = color[i];
@@ -214,74 +220,69 @@ OutputSingleLayerOperation::OutputSingleLayerOperation(
DataType datatype,
ImageFormatData *format,
const char *path,
- const ColorManagedViewSettings *viewSettings,
- const ColorManagedDisplaySettings *displaySettings,
- const char *viewName,
- const bool saveAsRender)
+ const ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ const char *view_name,
+ const bool save_as_render)
{
- this->m_rd = rd;
- this->m_tree = tree;
+ rd_ = rd;
+ tree_ = tree;
- this->addInputSocket(datatype);
+ this->add_input_socket(datatype);
- this->m_outputBuffer = nullptr;
- this->m_datatype = datatype;
- this->m_imageInput = nullptr;
+ output_buffer_ = nullptr;
+ datatype_ = datatype;
+ image_input_ = nullptr;
- this->m_format = format;
- BLI_strncpy(this->m_path, path, sizeof(this->m_path));
+ format_ = format;
+ BLI_strncpy(path_, path, sizeof(path_));
- this->m_viewSettings = viewSettings;
- this->m_displaySettings = displaySettings;
- this->m_viewName = viewName;
- this->m_saveAsRender = saveAsRender;
+ view_settings_ = view_settings;
+ display_settings_ = display_settings;
+ view_name_ = view_name;
+ save_as_render_ = save_as_render;
}
-void OutputSingleLayerOperation::initExecution()
+void OutputSingleLayerOperation::init_execution()
{
- this->m_imageInput = getInputSocketReader(0);
- this->m_outputBuffer = init_buffer(this->getWidth(), this->getHeight(), this->m_datatype);
+ image_input_ = get_input_socket_reader(0);
+ output_buffer_ = init_buffer(this->get_width(), this->get_height(), datatype_);
}
-void OutputSingleLayerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
+void OutputSingleLayerOperation::execute_region(rcti *rect, unsigned int /*tile_number*/)
{
- write_buffer_rect(rect,
- this->m_tree,
- this->m_imageInput,
- this->m_outputBuffer,
- this->getWidth(),
- this->m_datatype);
+ write_buffer_rect(rect, tree_, image_input_, output_buffer_, this->get_width(), datatype_);
}
-void OutputSingleLayerOperation::deinitExecution()
+void OutputSingleLayerOperation::deinit_execution()
{
- if (this->getWidth() * this->getHeight() != 0) {
+ if (this->get_width() * this->get_height() != 0) {
- int size = get_datatype_size(this->m_datatype);
- ImBuf *ibuf = IMB_allocImBuf(this->getWidth(), this->getHeight(), this->m_format->planes, 0);
+ int size = get_datatype_size(datatype_);
+ ImBuf *ibuf = IMB_allocImBuf(this->get_width(), this->get_height(), format_->planes, 0);
char filename[FILE_MAX];
const char *suffix;
ibuf->channels = size;
- ibuf->rect_float = this->m_outputBuffer;
+ ibuf->rect_float = output_buffer_;
ibuf->mall |= IB_rectfloat;
- ibuf->dither = this->m_rd->dither_intensity;
+ ibuf->dither = rd_->dither_intensity;
IMB_colormanagement_imbuf_for_write(
- ibuf, m_saveAsRender, false, m_viewSettings, m_displaySettings, this->m_format);
+ ibuf, save_as_render_, false, view_settings_, display_settings_, format_);
- suffix = BKE_scene_multiview_view_suffix_get(this->m_rd, this->m_viewName);
+ suffix = BKE_scene_multiview_view_suffix_get(rd_, view_name_);
BKE_image_path_from_imformat(filename,
- this->m_path,
+ path_,
BKE_main_blendfile_path_from_global(),
- this->m_rd->cfra,
- this->m_format,
- (this->m_rd->scemode & R_EXTENSION) != 0,
+ rd_->cfra,
+ format_,
+ (rd_->scemode & R_EXTENSION) != 0,
true,
suffix);
- if (0 == BKE_imbuf_write(ibuf, filename, this->m_format)) {
+ if (0 == BKE_imbuf_write(ibuf, filename, format_)) {
printf("Cannot save Node File Output to %s\n", filename);
}
else {
@@ -290,22 +291,22 @@ void OutputSingleLayerOperation::deinitExecution()
IMB_freeImBuf(ibuf);
}
- this->m_outputBuffer = nullptr;
- this->m_imageInput = nullptr;
+ output_buffer_ = nullptr;
+ image_input_ = nullptr;
}
void OutputSingleLayerOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(output),
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- if (!m_outputBuffer) {
+ if (!output_buffer_) {
return;
}
- MemoryBuffer output_buf(m_outputBuffer,
- COM_data_type_num_channels(this->m_datatype),
- this->getWidth(),
- this->getHeight());
+ MemoryBuffer output_buf(output_buffer_,
+ COM_data_type_num_channels(datatype_),
+ this->get_width(),
+ this->get_height());
const MemoryBuffer *input_image = inputs[0];
output_buf.copy_from(input_image, area);
}
@@ -318,9 +319,9 @@ OutputOpenExrLayer::OutputOpenExrLayer(const char *name_, DataType datatype_, bo
this->datatype = datatype_;
this->use_layer = use_layer_;
- /* these are created in initExecution */
- this->outputBuffer = nullptr;
- this->imageInput = nullptr;
+ /* these are created in init_execution */
+ this->output_buffer = nullptr;
+ this->image_input = nullptr;
}
OutputOpenExrMultiLayerOperation::OutputOpenExrMultiLayerOperation(const Scene *scene,
@@ -329,16 +330,16 @@ OutputOpenExrMultiLayerOperation::OutputOpenExrMultiLayerOperation(const Scene *
const char *path,
char exr_codec,
bool exr_half_float,
- const char *viewName)
+ const char *view_name)
{
- this->m_scene = scene;
- this->m_rd = rd;
- this->m_tree = tree;
-
- BLI_strncpy(this->m_path, path, sizeof(this->m_path));
- this->m_exr_codec = exr_codec;
- this->m_exr_half_float = exr_half_float;
- this->m_viewName = viewName;
+ scene_ = scene;
+ rd_ = rd;
+ tree_ = tree;
+
+ BLI_strncpy(path_, path, sizeof(path_));
+ exr_codec_ = exr_codec;
+ exr_half_float_ = exr_half_float;
+ view_name_ = view_name;
this->set_canvas_input_index(RESOLUTION_INPUT_ANY);
}
@@ -346,99 +347,95 @@ void OutputOpenExrMultiLayerOperation::add_layer(const char *name,
DataType datatype,
bool use_layer)
{
- this->addInputSocket(datatype);
- this->m_layers.append(OutputOpenExrLayer(name, datatype, use_layer));
+ this->add_input_socket(datatype);
+ layers_.append(OutputOpenExrLayer(name, datatype, use_layer));
}
-StampData *OutputOpenExrMultiLayerOperation::createStampData() const
+StampData *OutputOpenExrMultiLayerOperation::create_stamp_data() const
{
/* StampData API doesn't provide functions to modify an instance without having a RenderResult.
*/
RenderResult render_result;
- StampData *stamp_data = BKE_stamp_info_from_scene_static(m_scene);
+ StampData *stamp_data = BKE_stamp_info_from_scene_static(scene_);
render_result.stamp_data = stamp_data;
- for (const OutputOpenExrLayer &layer : m_layers) {
+ for (const OutputOpenExrLayer &layer : layers_) {
/* Skip unconnected sockets. */
- if (layer.imageInput == nullptr) {
+ if (layer.image_input == nullptr) {
continue;
}
- std::unique_ptr<MetaData> meta_data = layer.imageInput->getMetaData();
+ std::unique_ptr<MetaData> meta_data = layer.image_input->get_meta_data();
if (meta_data) {
blender::StringRef layer_name =
blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name(
blender::StringRef(layer.name, BLI_strnlen(layer.name, sizeof(layer.name))));
- meta_data->replaceHashNeutralCryptomatteKeys(layer_name);
- meta_data->addToRenderResult(&render_result);
+ meta_data->replace_hash_neutral_cryptomatte_keys(layer_name);
+ meta_data->add_to_render_result(&render_result);
}
}
return stamp_data;
}
-void OutputOpenExrMultiLayerOperation::initExecution()
+void OutputOpenExrMultiLayerOperation::init_execution()
{
- for (unsigned int i = 0; i < this->m_layers.size(); i++) {
- if (this->m_layers[i].use_layer) {
- SocketReader *reader = getInputSocketReader(i);
- this->m_layers[i].imageInput = reader;
- this->m_layers[i].outputBuffer = init_buffer(
- this->getWidth(), this->getHeight(), this->m_layers[i].datatype);
+ for (unsigned int i = 0; i < layers_.size(); i++) {
+ if (layers_[i].use_layer) {
+ SocketReader *reader = get_input_socket_reader(i);
+ layers_[i].image_input = reader;
+ layers_[i].output_buffer = init_buffer(
+ this->get_width(), this->get_height(), layers_[i].datatype);
}
}
}
-void OutputOpenExrMultiLayerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
+void OutputOpenExrMultiLayerOperation::execute_region(rcti *rect, unsigned int /*tile_number*/)
{
- for (unsigned int i = 0; i < this->m_layers.size(); i++) {
- OutputOpenExrLayer &layer = this->m_layers[i];
- if (layer.imageInput) {
- write_buffer_rect(rect,
- this->m_tree,
- layer.imageInput,
- layer.outputBuffer,
- this->getWidth(),
- layer.datatype);
+ for (unsigned int i = 0; i < layers_.size(); i++) {
+ OutputOpenExrLayer &layer = layers_[i];
+ if (layer.image_input) {
+ write_buffer_rect(
+ rect, tree_, layer.image_input, layer.output_buffer, this->get_width(), layer.datatype);
}
}
}
-void OutputOpenExrMultiLayerOperation::deinitExecution()
+void OutputOpenExrMultiLayerOperation::deinit_execution()
{
- unsigned int width = this->getWidth();
- unsigned int height = this->getHeight();
+ unsigned int width = this->get_width();
+ unsigned int height = this->get_height();
if (width != 0 && height != 0) {
char filename[FILE_MAX];
const char *suffix;
void *exrhandle = IMB_exr_get_handle();
- suffix = BKE_scene_multiview_view_suffix_get(this->m_rd, this->m_viewName);
+ suffix = BKE_scene_multiview_view_suffix_get(rd_, view_name_);
BKE_image_path_from_imtype(filename,
- this->m_path,
+ path_,
BKE_main_blendfile_path_from_global(),
- this->m_rd->cfra,
+ rd_->cfra,
R_IMF_IMTYPE_MULTILAYER,
- (this->m_rd->scemode & R_EXTENSION) != 0,
+ (rd_->scemode & R_EXTENSION) != 0,
true,
suffix);
BLI_make_existing_file(filename);
- for (unsigned int i = 0; i < this->m_layers.size(); i++) {
- OutputOpenExrLayer &layer = this->m_layers[i];
- if (!layer.imageInput) {
+ for (unsigned int i = 0; i < layers_.size(); i++) {
+ OutputOpenExrLayer &layer = layers_[i];
+ if (!layer.image_input) {
continue; /* skip unconnected sockets */
}
add_exr_channels(exrhandle,
- this->m_layers[i].name,
- this->m_layers[i].datatype,
+ layers_[i].name,
+ layers_[i].datatype,
"",
width,
- this->m_exr_half_float,
- this->m_layers[i].outputBuffer);
+ exr_half_float_,
+ layers_[i].output_buffer);
}
/* when the filename has no permissions, this can fail */
- StampData *stamp_data = createStampData();
- if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, stamp_data)) {
+ StampData *stamp_data = create_stamp_data();
+ if (IMB_exr_begin_write(exrhandle, filename, width, height, exr_codec_, stamp_data)) {
IMB_exr_write_channels(exrhandle);
}
else {
@@ -448,13 +445,13 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
}
IMB_exr_close(exrhandle);
- for (unsigned int i = 0; i < this->m_layers.size(); i++) {
- if (this->m_layers[i].outputBuffer) {
- MEM_freeN(this->m_layers[i].outputBuffer);
- this->m_layers[i].outputBuffer = nullptr;
+ for (unsigned int i = 0; i < layers_.size(); i++) {
+ if (layers_[i].output_buffer) {
+ MEM_freeN(layers_[i].output_buffer);
+ layers_[i].output_buffer = nullptr;
}
- this->m_layers[i].imageInput = nullptr;
+ layers_[i].image_input = nullptr;
}
BKE_stamp_data_free(stamp_data);
}
@@ -465,13 +462,13 @@ void OutputOpenExrMultiLayerOperation::update_memory_buffer_partial(MemoryBuffer
Span<MemoryBuffer *> inputs)
{
const MemoryBuffer *input_image = inputs[0];
- for (int i = 0; i < this->m_layers.size(); i++) {
- OutputOpenExrLayer &layer = this->m_layers[i];
- if (layer.outputBuffer) {
- MemoryBuffer output_buf(layer.outputBuffer,
+ for (int i = 0; i < layers_.size(); i++) {
+ OutputOpenExrLayer &layer = layers_[i];
+ if (layer.output_buffer) {
+ MemoryBuffer output_buf(layer.output_buffer,
COM_data_type_num_channels(layer.datatype),
- this->getWidth(),
- this->getHeight());
+ this->get_width(),
+ this->get_height());
output_buf.copy_from(input_image, area);
}
}
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.h b/source/blender/compositor/operations/COM_OutputFileOperation.h
index 057cee0c43e..e601ebac4e1 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.h
@@ -32,21 +32,21 @@ namespace blender::compositor {
/* Writes the image to a single-layer file. */
class OutputSingleLayerOperation : public MultiThreadedOperation {
protected:
- const RenderData *m_rd;
- const bNodeTree *m_tree;
+ const RenderData *rd_;
+ const bNodeTree *tree_;
- ImageFormatData *m_format;
- char m_path[FILE_MAX];
+ ImageFormatData *format_;
+ char path_[FILE_MAX];
- float *m_outputBuffer;
- DataType m_datatype;
- SocketReader *m_imageInput;
+ float *output_buffer_;
+ DataType datatype_;
+ SocketReader *image_input_;
- const ColorManagedViewSettings *m_viewSettings;
- const ColorManagedDisplaySettings *m_displaySettings;
+ const ColorManagedViewSettings *view_settings_;
+ const ColorManagedDisplaySettings *display_settings_;
- const char *m_viewName;
- bool m_saveAsRender;
+ const char *view_name_;
+ bool save_as_render_;
public:
OutputSingleLayerOperation(const RenderData *rd,
@@ -54,19 +54,19 @@ class OutputSingleLayerOperation : public MultiThreadedOperation {
DataType datatype,
ImageFormatData *format,
const char *path,
- const ColorManagedViewSettings *viewSettings,
- const ColorManagedDisplaySettings *displaySettings,
- const char *viewName,
- const bool saveAsRender);
+ const ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ const char *view_name,
+ bool save_as_render);
- void executeRegion(rcti *rect, unsigned int tileNumber) override;
- bool isOutputOperation(bool /*rendering*/) const override
+ void execute_region(rcti *rect, unsigned int tile_number) override;
+ bool is_output_operation(bool /*rendering*/) const override
{
return true;
}
- void initExecution() override;
- void deinitExecution() override;
- eCompositorPriority getRenderPriority() const override
+ void init_execution() override;
+ void deinit_execution() override;
+ eCompositorPriority get_render_priority() const override
{
return eCompositorPriority::Low;
}
@@ -85,24 +85,24 @@ struct OutputOpenExrLayer {
bool use_layer;
/* internals */
- float *outputBuffer;
- SocketReader *imageInput;
+ float *output_buffer;
+ SocketReader *image_input;
};
/* Writes inputs into OpenEXR multilayer channels. */
class OutputOpenExrMultiLayerOperation : public MultiThreadedOperation {
protected:
- const Scene *m_scene;
- const RenderData *m_rd;
- const bNodeTree *m_tree;
+ const Scene *scene_;
+ const RenderData *rd_;
+ const bNodeTree *tree_;
- char m_path[FILE_MAX];
- char m_exr_codec;
- bool m_exr_half_float;
- Vector<OutputOpenExrLayer> m_layers;
- const char *m_viewName;
+ char path_[FILE_MAX];
+ char exr_codec_;
+ bool exr_half_float_;
+ Vector<OutputOpenExrLayer> layers_;
+ const char *view_name_;
- StampData *createStampData() const;
+ StampData *create_stamp_data() const;
public:
OutputOpenExrMultiLayerOperation(const Scene *scene,
@@ -111,18 +111,18 @@ class OutputOpenExrMultiLayerOperation : public MultiThreadedOperation {
const char *path,
char exr_codec,
bool exr_half_float,
- const char *viewName);
+ const char *view_name);
void add_layer(const char *name, DataType datatype, bool use_layer);
- void executeRegion(rcti *rect, unsigned int tileNumber) override;
- bool isOutputOperation(bool /*rendering*/) const override
+ void execute_region(rcti *rect, unsigned int tile_number) override;
+ bool is_output_operation(bool /*rendering*/) const override
{
return true;
}
- void initExecution() override;
- void deinitExecution() override;
- eCompositorPriority getRenderPriority() const override
+ void init_execution() override;
+ void deinit_execution() override;
+ eCompositorPriority get_render_priority() const override
{
return eCompositorPriority::Low;
}
@@ -133,15 +133,15 @@ class OutputOpenExrMultiLayerOperation : public MultiThreadedOperation {
};
void add_exr_channels(void *exrhandle,
- const char *layerName,
+ const char *layer_name,
const DataType datatype,
- const char *viewName,
- const size_t width,
+ const char *view_name,
+ size_t width,
bool use_half_float,
float *buf);
void free_exr_channels(void *exrhandle,
const RenderData *rd,
- const char *layerName,
+ const char *layer_name,
const DataType datatype);
int get_datatype_size(DataType datatype);
diff --git a/source/blender/compositor/operations/COM_PixelateOperation.cc b/source/blender/compositor/operations/COM_PixelateOperation.cc
index 4fc238bc094..869e2357126 100644
--- a/source/blender/compositor/operations/COM_PixelateOperation.cc
+++ b/source/blender/compositor/operations/COM_PixelateOperation.cc
@@ -20,32 +20,32 @@
namespace blender::compositor {
-PixelateOperation::PixelateOperation(DataType datatype)
+PixelateOperation::PixelateOperation(DataType data_type)
{
- this->addInputSocket(datatype);
- this->addOutputSocket(datatype);
+ this->add_input_socket(data_type);
+ this->add_output_socket(data_type);
this->set_canvas_input_index(0);
- this->m_inputOperation = nullptr;
+ input_operation_ = nullptr;
}
-void PixelateOperation::initExecution()
+void PixelateOperation::init_execution()
{
- this->m_inputOperation = this->getInputSocketReader(0);
+ input_operation_ = this->get_input_socket_reader(0);
}
-void PixelateOperation::deinitExecution()
+void PixelateOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
+ input_operation_ = nullptr;
}
-void PixelateOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void PixelateOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float nx = round(x);
float ny = round(y);
- this->m_inputOperation->readSampled(output, nx, ny, sampler);
+ input_operation_->read_sampled(output, nx, ny, sampler);
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_PixelateOperation.h b/source/blender/compositor/operations/COM_PixelateOperation.h
index e8b272853da..51a480b98e9 100644
--- a/source/blender/compositor/operations/COM_PixelateOperation.h
+++ b/source/blender/compositor/operations/COM_PixelateOperation.h
@@ -34,33 +34,33 @@ class PixelateOperation : public NodeOperation {
/**
* \brief cached reference to the input operation
*/
- SocketReader *m_inputOperation;
+ SocketReader *input_operation_;
public:
/**
* \brief PixelateOperation
- * \param dataType: the datatype to create this operator for (saves datatype conversions)
+ * \param data_type: the datatype to create this operator for (saves datatype conversions)
*/
- PixelateOperation(DataType dataType);
+ PixelateOperation(DataType data_type);
/**
* \brief initialization of the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* \brief de-initialization of the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
/**
- * \brief executePixel
+ * \brief execute_pixel
* \param output: result
* \param x: x-coordinate
* \param y: y-coordinate
* \param sampler: sampler
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc
index 65cd08456ef..8467a5d9d97 100644
--- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc
+++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc
@@ -17,15 +17,6 @@
#include "COM_PlaneCornerPinOperation.h"
#include "COM_ConstantOperation.h"
-#include "COM_ReadBufferOperation.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-#include "BLI_math_color.h"
-
-#include "BKE_node.h"
namespace blender::compositor {
@@ -65,11 +56,11 @@ static bool check_corners(float corners[4][2])
}
/* TODO(manzanilla): to be removed with tiled implementation. */
-static void readCornersFromSockets(rcti *rect, SocketReader *readers[4], float corners[4][2])
+static void read_corners_from_sockets(rcti *rect, SocketReader *readers[4], float corners[4][2])
{
for (int i = 0; i < 4; i++) {
float result[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- readers[i]->readSampled(result, rect->xmin, rect->ymin, PixelSampler::Nearest);
+ readers[i]->read_sampled(result, rect->xmin, rect->ymin, PixelSampler::Nearest);
corners[i][0] = result[0];
corners[i][1] = result[1];
}
@@ -143,18 +134,18 @@ static void read_input_corners(NodeOperation *op, const int first_input_idx, flo
/* ******** PlaneCornerPinMaskOperation ******** */
-PlaneCornerPinMaskOperation::PlaneCornerPinMaskOperation() : m_corners_ready(false)
+PlaneCornerPinMaskOperation::PlaneCornerPinMaskOperation() : corners_ready_(false)
{
- addInputSocket(DataType::Vector);
- addInputSocket(DataType::Vector);
- addInputSocket(DataType::Vector);
- addInputSocket(DataType::Vector);
+ add_input_socket(DataType::Vector);
+ add_input_socket(DataType::Vector);
+ add_input_socket(DataType::Vector);
+ add_input_socket(DataType::Vector);
/* XXX this is stupid: we need to make this "complex",
- * so we can use the initializeTileData function
+ * so we can use the initialize_tile_data function
* to read corners from input sockets ...
*/
- flags.complex = true;
+ flags_.complex = true;
}
void PlaneCornerPinMaskOperation::init_data()
@@ -162,49 +153,49 @@ void PlaneCornerPinMaskOperation::init_data()
if (execution_model_ == eExecutionModel::FullFrame) {
float corners[4][2];
read_input_corners(this, 0, corners);
- calculateCorners(corners, true, 0);
+ calculate_corners(corners, true, 0);
}
}
-/* TODO(manzanilla): to be removed with tiled implementation. Same for #deinitExecution and do the
+/* TODO(manzanilla): to be removed with tiled implementation. Same for #deinit_execution and do the
* same on #PlaneCornerPinWarpImageOperation. */
-void PlaneCornerPinMaskOperation::initExecution()
+void PlaneCornerPinMaskOperation::init_execution()
{
- PlaneDistortMaskOperation::initExecution();
+ PlaneDistortMaskOperation::init_execution();
- initMutex();
+ init_mutex();
}
-void PlaneCornerPinMaskOperation::deinitExecution()
+void PlaneCornerPinMaskOperation::deinit_execution()
{
- PlaneDistortMaskOperation::deinitExecution();
+ PlaneDistortMaskOperation::deinit_execution();
- deinitMutex();
+ deinit_mutex();
}
-void *PlaneCornerPinMaskOperation::initializeTileData(rcti *rect)
+void *PlaneCornerPinMaskOperation::initialize_tile_data(rcti *rect)
{
- void *data = PlaneDistortMaskOperation::initializeTileData(rect);
+ void *data = PlaneDistortMaskOperation::initialize_tile_data(rect);
/* get corner values once, by reading inputs at (0,0)
* XXX this assumes invariable values (no image inputs),
* we don't have a nice generic system for that yet
*/
- lockMutex();
- if (!m_corners_ready) {
+ lock_mutex();
+ if (!corners_ready_) {
SocketReader *readers[4] = {
- getInputSocketReader(0),
- getInputSocketReader(1),
- getInputSocketReader(2),
- getInputSocketReader(3),
+ get_input_socket_reader(0),
+ get_input_socket_reader(1),
+ get_input_socket_reader(2),
+ get_input_socket_reader(3),
};
float corners[4][2];
- readCornersFromSockets(rect, readers, corners);
- calculateCorners(corners, true, 0);
+ read_corners_from_sockets(rect, readers, corners);
+ calculate_corners(corners, true, 0);
- m_corners_ready = true;
+ corners_ready_ = true;
}
- unlockMutex();
+ unlock_mutex();
return data;
}
@@ -228,12 +219,12 @@ void PlaneCornerPinMaskOperation::get_area_of_interest(const int UNUSED(input_id
/* ******** PlaneCornerPinWarpImageOperation ******** */
-PlaneCornerPinWarpImageOperation::PlaneCornerPinWarpImageOperation() : m_corners_ready(false)
+PlaneCornerPinWarpImageOperation::PlaneCornerPinWarpImageOperation() : corners_ready_(false)
{
- addInputSocket(DataType::Vector);
- addInputSocket(DataType::Vector);
- addInputSocket(DataType::Vector);
- addInputSocket(DataType::Vector);
+ add_input_socket(DataType::Vector);
+ add_input_socket(DataType::Vector);
+ add_input_socket(DataType::Vector);
+ add_input_socket(DataType::Vector);
}
void PlaneCornerPinWarpImageOperation::init_data()
@@ -241,57 +232,58 @@ void PlaneCornerPinWarpImageOperation::init_data()
if (execution_model_ == eExecutionModel::FullFrame) {
float corners[4][2];
read_input_corners(this, 1, corners);
- calculateCorners(corners, true, 0);
+ calculate_corners(corners, true, 0);
}
}
-void PlaneCornerPinWarpImageOperation::initExecution()
+void PlaneCornerPinWarpImageOperation::init_execution()
{
- PlaneDistortWarpImageOperation::initExecution();
+ PlaneDistortWarpImageOperation::init_execution();
- initMutex();
+ init_mutex();
}
-void PlaneCornerPinWarpImageOperation::deinitExecution()
+void PlaneCornerPinWarpImageOperation::deinit_execution()
{
- PlaneDistortWarpImageOperation::deinitExecution();
+ PlaneDistortWarpImageOperation::deinit_execution();
- deinitMutex();
+ deinit_mutex();
}
-void *PlaneCornerPinWarpImageOperation::initializeTileData(rcti *rect)
+void *PlaneCornerPinWarpImageOperation::initialize_tile_data(rcti *rect)
{
- void *data = PlaneDistortWarpImageOperation::initializeTileData(rect);
+ void *data = PlaneDistortWarpImageOperation::initialize_tile_data(rect);
/* get corner values once, by reading inputs at (0,0)
* XXX this assumes invariable values (no image inputs),
* we don't have a nice generic system for that yet
*/
- lockMutex();
- if (!m_corners_ready) {
+ lock_mutex();
+ if (!corners_ready_) {
/* corner sockets start at index 1 */
SocketReader *readers[4] = {
- getInputSocketReader(1),
- getInputSocketReader(2),
- getInputSocketReader(3),
- getInputSocketReader(4),
+ get_input_socket_reader(1),
+ get_input_socket_reader(2),
+ get_input_socket_reader(3),
+ get_input_socket_reader(4),
};
float corners[4][2];
- readCornersFromSockets(rect, readers, corners);
- calculateCorners(corners, true, 0);
+ read_corners_from_sockets(rect, readers, corners);
+ calculate_corners(corners, true, 0);
- m_corners_ready = true;
+ corners_ready_ = true;
}
- unlockMutex();
+ unlock_mutex();
return data;
}
-bool PlaneCornerPinWarpImageOperation::determineDependingAreaOfInterest(
- rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool PlaneCornerPinWarpImageOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
for (int i = 0; i < 4; i++) {
- if (getInputOperation(i + 1)->determineDependingAreaOfInterest(input, readOperation, output)) {
+ if (get_input_operation(i + 1)->determine_depending_area_of_interest(
+ input, read_operation, output)) {
return true;
}
}
@@ -302,12 +294,12 @@ bool PlaneCornerPinWarpImageOperation::determineDependingAreaOfInterest(
*/
output->xmin = 0;
output->ymin = 0;
- output->xmax = getInputOperation(0)->getWidth();
- output->ymax = getInputOperation(0)->getHeight();
+ output->xmax = get_input_operation(0)->get_width();
+ output->ymax = get_input_operation(0)->get_height();
return true;
#if 0
- return PlaneDistortWarpImageOperation::determineDependingAreaOfInterest(
- input, readOperation, output);
+ return PlaneDistortWarpImageOperation::determine_depending_area_of_interest(
+ input, read_operation, output);
#endif
}
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h
index 7b3917923d2..bb2166bf8b8 100644
--- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h
+++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h
@@ -32,16 +32,16 @@ namespace blender::compositor {
class PlaneCornerPinMaskOperation : public PlaneDistortMaskOperation {
private:
/* TODO(manzanilla): to be removed with tiled implementation. */
- bool m_corners_ready;
+ bool corners_ready_;
public:
PlaneCornerPinMaskOperation();
void init_data() override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
@@ -50,20 +50,20 @@ class PlaneCornerPinMaskOperation : public PlaneDistortMaskOperation {
class PlaneCornerPinWarpImageOperation : public PlaneDistortWarpImageOperation {
private:
- bool m_corners_ready;
+ bool corners_ready_;
public:
PlaneCornerPinWarpImageOperation();
void init_data() override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
};
diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc
index 31ef41789fd..a11a358c71d 100644
--- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc
+++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc
@@ -18,47 +18,40 @@
#include "COM_PlaneDistortCommonOperation.h"
-#include "MEM_guardedalloc.h"
-
#include "BLI_jitter_2d.h"
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-#include "BLI_math_color.h"
-#include "BKE_movieclip.h"
-#include "BKE_node.h"
#include "BKE_tracking.h"
namespace blender::compositor {
PlaneDistortBaseOperation::PlaneDistortBaseOperation()
- : m_motion_blur_samples(1), m_motion_blur_shutter(0.5f)
+ : motion_blur_samples_(1), motion_blur_shutter_(0.5f)
{
}
-void PlaneDistortBaseOperation::calculateCorners(const float corners[4][2],
- bool normalized,
- int sample)
+void PlaneDistortBaseOperation::calculate_corners(const float corners[4][2],
+ bool normalized,
+ int sample)
{
- BLI_assert(sample < this->m_motion_blur_samples);
- MotionSample *sample_data = &this->m_samples[sample];
+ BLI_assert(sample < motion_blur_samples_);
+ MotionSample *sample_data = &samples_[sample];
if (normalized) {
for (int i = 0; i < 4; i++) {
- sample_data->frameSpaceCorners[i][0] = corners[i][0] * this->getWidth();
- sample_data->frameSpaceCorners[i][1] = corners[i][1] * this->getHeight();
+ sample_data->frame_space_corners[i][0] = corners[i][0] * this->get_width();
+ sample_data->frame_space_corners[i][1] = corners[i][1] * this->get_height();
}
}
else {
for (int i = 0; i < 4; i++) {
- sample_data->frameSpaceCorners[i][0] = corners[i][0];
- sample_data->frameSpaceCorners[i][1] = corners[i][1];
+ sample_data->frame_space_corners[i][0] = corners[i][0];
+ sample_data->frame_space_corners[i][1] = corners[i][1];
}
}
}
/* ******** PlaneDistort WarpImage ******** */
-BLI_INLINE void warpCoord(float x, float y, float matrix[3][3], float uv[2], float deriv[2][2])
+BLI_INLINE void warp_coord(float x, float y, float matrix[3][3], float uv[2], float deriv[2][2])
{
float vec[3] = {x, y, 1.0f};
mul_m3_v3(matrix, vec);
@@ -73,58 +66,58 @@ BLI_INLINE void warpCoord(float x, float y, float matrix[3][3], float uv[2], flo
PlaneDistortWarpImageOperation::PlaneDistortWarpImageOperation() : PlaneDistortBaseOperation()
{
- this->addInputSocket(DataType::Color, ResizeMode::Align);
- this->addOutputSocket(DataType::Color);
- this->m_pixelReader = nullptr;
- this->flags.complex = true;
+ this->add_input_socket(DataType::Color, ResizeMode::Align);
+ this->add_output_socket(DataType::Color);
+ pixel_reader_ = nullptr;
+ flags_.complex = true;
}
-void PlaneDistortWarpImageOperation::calculateCorners(const float corners[4][2],
- bool normalized,
- int sample)
+void PlaneDistortWarpImageOperation::calculate_corners(const float corners[4][2],
+ bool normalized,
+ int sample)
{
- PlaneDistortBaseOperation::calculateCorners(corners, normalized, sample);
+ PlaneDistortBaseOperation::calculate_corners(corners, normalized, sample);
const NodeOperation *image = get_input_operation(0);
- const int width = image->getWidth();
- const int height = image->getHeight();
+ const int width = image->get_width();
+ const int height = image->get_height();
float frame_corners[4][2] = {
{0.0f, 0.0f}, {(float)width, 0.0f}, {(float)width, (float)height}, {0.0f, (float)height}};
- MotionSample *sample_data = &this->m_samples[sample];
+ MotionSample *sample_data = &samples_[sample];
BKE_tracking_homography_between_two_quads(
- sample_data->frameSpaceCorners, frame_corners, sample_data->perspectiveMatrix);
+ sample_data->frame_space_corners, frame_corners, sample_data->perspective_matrix);
}
-void PlaneDistortWarpImageOperation::initExecution()
+void PlaneDistortWarpImageOperation::init_execution()
{
- this->m_pixelReader = this->getInputSocketReader(0);
+ pixel_reader_ = this->get_input_socket_reader(0);
}
-void PlaneDistortWarpImageOperation::deinitExecution()
+void PlaneDistortWarpImageOperation::deinit_execution()
{
- this->m_pixelReader = nullptr;
+ pixel_reader_ = nullptr;
}
-void PlaneDistortWarpImageOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler /*sampler*/)
+void PlaneDistortWarpImageOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
float uv[2];
float deriv[2][2];
- if (this->m_motion_blur_samples == 1) {
- warpCoord(x, y, this->m_samples[0].perspectiveMatrix, uv, deriv);
- m_pixelReader->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1]);
+ if (motion_blur_samples_ == 1) {
+ warp_coord(x, y, samples_[0].perspective_matrix, uv, deriv);
+ pixel_reader_->read_filtered(output, uv[0], uv[1], deriv[0], deriv[1]);
}
else {
zero_v4(output);
- for (int sample = 0; sample < this->m_motion_blur_samples; sample++) {
+ for (int sample = 0; sample < motion_blur_samples_; sample++) {
float color[4];
- warpCoord(x, y, this->m_samples[sample].perspectiveMatrix, uv, deriv);
- m_pixelReader->readFiltered(color, uv[0], uv[1], deriv[0], deriv[1]);
+ warp_coord(x, y, samples_[sample].perspective_matrix, uv, deriv);
+ pixel_reader_->read_filtered(color, uv[0], uv[1], deriv[0], deriv[1]);
add_v4_v4(output, color);
}
- mul_v4_fl(output, 1.0f / (float)this->m_motion_blur_samples);
+ mul_v4_fl(output, 1.0f / (float)motion_blur_samples_);
}
}
@@ -136,54 +129,54 @@ void PlaneDistortWarpImageOperation::update_memory_buffer_partial(MemoryBuffer *
float uv[2];
float deriv[2][2];
BuffersIterator<float> it = output->iterate_with({}, area);
- if (this->m_motion_blur_samples == 1) {
+ if (motion_blur_samples_ == 1) {
for (; !it.is_end(); ++it) {
- warpCoord(it.x, it.y, this->m_samples[0].perspectiveMatrix, uv, deriv);
+ warp_coord(it.x, it.y, samples_[0].perspective_matrix, uv, deriv);
input_img->read_elem_filtered(uv[0], uv[1], deriv[0], deriv[1], it.out);
}
}
else {
for (; !it.is_end(); ++it) {
zero_v4(it.out);
- for (const int sample : IndexRange(this->m_motion_blur_samples)) {
+ for (const int sample : IndexRange(motion_blur_samples_)) {
float color[4];
- warpCoord(it.x, it.y, this->m_samples[sample].perspectiveMatrix, uv, deriv);
+ warp_coord(it.x, it.y, samples_[sample].perspective_matrix, uv, deriv);
input_img->read_elem_filtered(uv[0], uv[1], deriv[0], deriv[1], color);
add_v4_v4(it.out, color);
}
- mul_v4_fl(it.out, 1.0f / (float)this->m_motion_blur_samples);
+ mul_v4_fl(it.out, 1.0f / (float)motion_blur_samples_);
}
}
}
-bool PlaneDistortWarpImageOperation::determineDependingAreaOfInterest(
- rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool PlaneDistortWarpImageOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
float min[2], max[2];
INIT_MINMAX2(min, max);
- for (int sample = 0; sample < this->m_motion_blur_samples; sample++) {
+ for (int sample = 0; sample < motion_blur_samples_; sample++) {
float UVs[4][2];
float deriv[2][2];
- MotionSample *sample_data = &this->m_samples[sample];
+ MotionSample *sample_data = &samples_[sample];
/* TODO(sergey): figure out proper way to do this. */
- warpCoord(input->xmin - 2, input->ymin - 2, sample_data->perspectiveMatrix, UVs[0], deriv);
- warpCoord(input->xmax + 2, input->ymin - 2, sample_data->perspectiveMatrix, UVs[1], deriv);
- warpCoord(input->xmax + 2, input->ymax + 2, sample_data->perspectiveMatrix, UVs[2], deriv);
- warpCoord(input->xmin - 2, input->ymax + 2, sample_data->perspectiveMatrix, UVs[3], deriv);
+ warp_coord(input->xmin - 2, input->ymin - 2, sample_data->perspective_matrix, UVs[0], deriv);
+ warp_coord(input->xmax + 2, input->ymin - 2, sample_data->perspective_matrix, UVs[1], deriv);
+ warp_coord(input->xmax + 2, input->ymax + 2, sample_data->perspective_matrix, UVs[2], deriv);
+ warp_coord(input->xmin - 2, input->ymax + 2, sample_data->perspective_matrix, UVs[3], deriv);
for (int i = 0; i < 4; i++) {
minmax_v2v2_v2(min, max, UVs[i]);
}
}
- rcti newInput;
+ rcti new_input;
- newInput.xmin = min[0] - 1;
- newInput.ymin = min[1] - 1;
- newInput.xmax = max[0] + 1;
- newInput.ymax = max[1] + 1;
+ new_input.xmin = min[0] - 1;
+ new_input.ymin = min[1] - 1;
+ new_input.xmax = max[0] + 1;
+ new_input.ymax = max[1] + 1;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void PlaneDistortWarpImageOperation::get_area_of_interest(const int input_idx,
@@ -203,19 +196,19 @@ void PlaneDistortWarpImageOperation::get_area_of_interest(const int input_idx,
#if 0
float min[2], max[2];
INIT_MINMAX2(min, max);
- for (int sample = 0; sample < this->m_motion_blur_samples; sample++) {
+ for (int sample = 0; sample < motion_blur_samples_; sample++) {
float UVs[4][2];
float deriv[2][2];
- MotionSample *sample_data = &this->m_samples[sample];
+ MotionSample *sample_data = &samples_[sample];
/* TODO(sergey): figure out proper way to do this. */
- warpCoord(
- output_area.xmin - 2, output_area.ymin - 2, sample_data->perspectiveMatrix, UVs[0], deriv);
- warpCoord(
- output_area.xmax + 2, output_area.ymin - 2, sample_data->perspectiveMatrix, UVs[1], deriv);
- warpCoord(
- output_area.xmax + 2, output_area.ymax + 2, sample_data->perspectiveMatrix, UVs[2], deriv);
- warpCoord(
- output_area.xmin - 2, output_area.ymax + 2, sample_data->perspectiveMatrix, UVs[3], deriv);
+ warp_coord(
+ output_area.xmin - 2, output_area.ymin - 2, sample_data->perspective_matrix, UVs[0], deriv);
+ warp_coord(
+ output_area.xmax + 2, output_area.ymin - 2, sample_data->perspective_matrix, UVs[1], deriv);
+ warp_coord(
+ output_area.xmax + 2, output_area.ymax + 2, sample_data->perspective_matrix, UVs[2], deriv);
+ warp_coord(
+ output_area.xmin - 2, output_area.ymax + 2, sample_data->perspective_matrix, UVs[3], deriv);
for (int i = 0; i < 4; i++) {
minmax_v2v2_v2(min, max, UVs[i]);
}
@@ -232,61 +225,61 @@ void PlaneDistortWarpImageOperation::get_area_of_interest(const int input_idx,
PlaneDistortMaskOperation::PlaneDistortMaskOperation() : PlaneDistortBaseOperation()
{
- addOutputSocket(DataType::Value);
+ add_output_socket(DataType::Value);
/* Currently hardcoded to 8 samples. */
- m_osa = 8;
+ osa_ = 8;
}
-void PlaneDistortMaskOperation::initExecution()
+void PlaneDistortMaskOperation::init_execution()
{
- BLI_jitter_init(m_jitter, m_osa);
+ BLI_jitter_init(jitter_, osa_);
}
-void PlaneDistortMaskOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler /*sampler*/)
+void PlaneDistortMaskOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
float point[2];
int inside_counter = 0;
- if (this->m_motion_blur_samples == 1) {
- MotionSample *sample_data = &this->m_samples[0];
- for (int sample = 0; sample < this->m_osa; sample++) {
- point[0] = x + this->m_jitter[sample][0];
- point[1] = y + this->m_jitter[sample][1];
+ if (motion_blur_samples_ == 1) {
+ MotionSample *sample_data = &samples_[0];
+ for (int sample = 0; sample < osa_; sample++) {
+ point[0] = x + jitter_[sample][0];
+ point[1] = y + jitter_[sample][1];
if (isect_point_tri_v2(point,
- sample_data->frameSpaceCorners[0],
- sample_data->frameSpaceCorners[1],
- sample_data->frameSpaceCorners[2]) ||
+ sample_data->frame_space_corners[0],
+ sample_data->frame_space_corners[1],
+ sample_data->frame_space_corners[2]) ||
isect_point_tri_v2(point,
- sample_data->frameSpaceCorners[0],
- sample_data->frameSpaceCorners[2],
- sample_data->frameSpaceCorners[3])) {
+ sample_data->frame_space_corners[0],
+ sample_data->frame_space_corners[2],
+ sample_data->frame_space_corners[3])) {
inside_counter++;
}
}
- output[0] = (float)inside_counter / this->m_osa;
+ output[0] = (float)inside_counter / osa_;
}
else {
- for (int motion_sample = 0; motion_sample < this->m_motion_blur_samples; motion_sample++) {
- MotionSample *sample_data = &this->m_samples[motion_sample];
- for (int osa_sample = 0; osa_sample < this->m_osa; osa_sample++) {
- point[0] = x + this->m_jitter[osa_sample][0];
- point[1] = y + this->m_jitter[osa_sample][1];
+ for (int motion_sample = 0; motion_sample < motion_blur_samples_; motion_sample++) {
+ MotionSample *sample_data = &samples_[motion_sample];
+ for (int osa_sample = 0; osa_sample < osa_; osa_sample++) {
+ point[0] = x + jitter_[osa_sample][0];
+ point[1] = y + jitter_[osa_sample][1];
if (isect_point_tri_v2(point,
- sample_data->frameSpaceCorners[0],
- sample_data->frameSpaceCorners[1],
- sample_data->frameSpaceCorners[2]) ||
+ sample_data->frame_space_corners[0],
+ sample_data->frame_space_corners[1],
+ sample_data->frame_space_corners[2]) ||
isect_point_tri_v2(point,
- sample_data->frameSpaceCorners[0],
- sample_data->frameSpaceCorners[2],
- sample_data->frameSpaceCorners[3])) {
+ sample_data->frame_space_corners[0],
+ sample_data->frame_space_corners[2],
+ sample_data->frame_space_corners[3])) {
inside_counter++;
}
}
}
- output[0] = (float)inside_counter / (this->m_osa * this->m_motion_blur_samples);
+ output[0] = (float)inside_counter / (osa_ * motion_blur_samples_);
}
}
@@ -296,11 +289,11 @@ void PlaneDistortMaskOperation::update_memory_buffer_partial(MemoryBuffer *outpu
{
for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
int inside_count = 0;
- for (const int motion_sample : IndexRange(this->m_motion_blur_samples)) {
- MotionSample &sample = this->m_samples[motion_sample];
+ for (const int motion_sample : IndexRange(motion_blur_samples_)) {
+ MotionSample &sample = samples_[motion_sample];
inside_count += get_jitter_samples_inside_count(it.x, it.y, sample);
}
- *it.out = (float)inside_count / (this->m_osa * this->m_motion_blur_samples);
+ *it.out = (float)inside_count / (osa_ * motion_blur_samples_);
}
}
@@ -310,17 +303,17 @@ int PlaneDistortMaskOperation::get_jitter_samples_inside_count(int x,
{
float point[2];
int inside_count = 0;
- for (int sample = 0; sample < this->m_osa; sample++) {
- point[0] = x + this->m_jitter[sample][0];
- point[1] = y + this->m_jitter[sample][1];
+ for (int sample = 0; sample < osa_; sample++) {
+ point[0] = x + jitter_[sample][0];
+ point[1] = y + jitter_[sample][1];
if (isect_point_tri_v2(point,
- sample_data.frameSpaceCorners[0],
- sample_data.frameSpaceCorners[1],
- sample_data.frameSpaceCorners[2]) ||
+ sample_data.frame_space_corners[0],
+ sample_data.frame_space_corners[1],
+ sample_data.frame_space_corners[2]) ||
isect_point_tri_v2(point,
- sample_data.frameSpaceCorners[0],
- sample_data.frameSpaceCorners[2],
- sample_data.frameSpaceCorners[3])) {
+ sample_data.frame_space_corners[0],
+ sample_data.frame_space_corners[2],
+ sample_data.frame_space_corners[3])) {
inside_count++;
}
}
diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h
index 3ef9c1dfab8..bf330ed7230 100644
--- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h
+++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h
@@ -35,27 +35,27 @@ namespace blender::compositor {
class PlaneDistortBaseOperation : public MultiThreadedOperation {
protected:
struct MotionSample {
- float frameSpaceCorners[4][2]; /* Corners coordinates in pixel space. */
- float perspectiveMatrix[3][3];
+ float frame_space_corners[4][2]; /* Corners coordinates in pixel space. */
+ float perspective_matrix[3][3];
};
- MotionSample m_samples[PLANE_DISTORT_MAX_SAMPLES];
- int m_motion_blur_samples;
- float m_motion_blur_shutter;
+ MotionSample samples_[PLANE_DISTORT_MAX_SAMPLES];
+ int motion_blur_samples_;
+ float motion_blur_shutter_;
public:
PlaneDistortBaseOperation();
- void setMotionBlurSamples(int samples)
+ void set_motion_blur_samples(int samples)
{
BLI_assert(samples <= PLANE_DISTORT_MAX_SAMPLES);
- this->m_motion_blur_samples = samples;
+ motion_blur_samples_ = samples;
}
- void setMotionBlurShutter(float shutter)
+ void set_motion_blur_shutter(float shutter)
{
- this->m_motion_blur_shutter = shutter;
+ motion_blur_shutter_ = shutter;
}
- virtual void calculateCorners(const float corners[4][2], bool normalized, int sample);
+ virtual void calculate_corners(const float corners[4][2], bool normalized, int sample);
private:
friend class PlaneTrackCommon;
@@ -63,21 +63,21 @@ class PlaneDistortBaseOperation : public MultiThreadedOperation {
class PlaneDistortWarpImageOperation : public PlaneDistortBaseOperation {
protected:
- SocketReader *m_pixelReader;
+ SocketReader *pixel_reader_;
public:
PlaneDistortWarpImageOperation();
- void calculateCorners(const float corners[4][2], bool normalized, int sample) override;
+ void calculate_corners(const float corners[4][2], bool normalized, int sample) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
@@ -87,15 +87,15 @@ class PlaneDistortWarpImageOperation : public PlaneDistortBaseOperation {
class PlaneDistortMaskOperation : public PlaneDistortBaseOperation {
protected:
- int m_osa;
- float m_jitter[32][2];
+ int osa_;
+ float jitter_[32][2];
public:
PlaneDistortMaskOperation();
- void initExecution() override;
+ void init_execution() override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cc b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc
index 7226a133a52..cb73fa9af7b 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cc
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc
@@ -17,16 +17,10 @@
*/
#include "COM_PlaneTrackOperation.h"
-#include "COM_ReadBufferOperation.h"
-#include "MEM_guardedalloc.h"
-
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-#include "BLI_math_color.h"
+#include "DNA_defaults.h"
#include "BKE_movieclip.h"
-#include "BKE_node.h"
#include "BKE_tracking.h"
namespace blender::compositor {
@@ -35,49 +29,49 @@ namespace blender::compositor {
PlaneTrackCommon::PlaneTrackCommon()
{
- this->m_movieClip = nullptr;
- this->m_framenumber = 0;
- this->m_trackingObjectName[0] = '\0';
- this->m_planeTrackName[0] = '\0';
+ movie_clip_ = nullptr;
+ framenumber_ = 0;
+ tracking_object_name_[0] = '\0';
+ plane_track_name_[0] = '\0';
}
void PlaneTrackCommon::read_and_calculate_corners(PlaneDistortBaseOperation *distort_op)
{
float corners[4][2];
- if (distort_op->m_motion_blur_samples == 1) {
- readCornersFromTrack(corners, this->m_framenumber);
- distort_op->calculateCorners(corners, true, 0);
+ if (distort_op->motion_blur_samples_ == 1) {
+ read_corners_from_track(corners, framenumber_);
+ distort_op->calculate_corners(corners, true, 0);
}
else {
- const float frame = (float)this->m_framenumber - distort_op->m_motion_blur_shutter;
- const float frame_step = (distort_op->m_motion_blur_shutter * 2.0f) /
- distort_op->m_motion_blur_samples;
+ const float frame = (float)framenumber_ - distort_op->motion_blur_shutter_;
+ const float frame_step = (distort_op->motion_blur_shutter_ * 2.0f) /
+ distort_op->motion_blur_samples_;
float frame_iter = frame;
- for (int sample = 0; sample < distort_op->m_motion_blur_samples; sample++) {
- readCornersFromTrack(corners, frame_iter);
- distort_op->calculateCorners(corners, true, sample);
+ for (int sample = 0; sample < distort_op->motion_blur_samples_; sample++) {
+ read_corners_from_track(corners, frame_iter);
+ distort_op->calculate_corners(corners, true, sample);
frame_iter += frame_step;
}
}
}
-void PlaneTrackCommon::readCornersFromTrack(float corners[4][2], float frame)
+void PlaneTrackCommon::read_corners_from_track(float corners[4][2], float frame)
{
MovieTracking *tracking;
MovieTrackingObject *object;
- if (!this->m_movieClip) {
+ if (!movie_clip_) {
return;
}
- tracking = &this->m_movieClip->tracking;
+ tracking = &movie_clip_->tracking;
- object = BKE_tracking_object_get_named(tracking, this->m_trackingObjectName);
+ object = BKE_tracking_object_get_named(tracking, tracking_object_name_);
if (object) {
MovieTrackingPlaneTrack *plane_track;
- plane_track = BKE_tracking_plane_track_get_named(tracking, object, this->m_planeTrackName);
+ plane_track = BKE_tracking_plane_track_get_named(tracking, object, plane_track_name_);
if (plane_track) {
- float clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, frame);
+ float clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(movie_clip_, frame);
BKE_tracking_plane_marker_get_subframe_corners(plane_track, clip_framenr, corners);
}
}
@@ -86,11 +80,11 @@ void PlaneTrackCommon::readCornersFromTrack(float corners[4][2], float frame)
void PlaneTrackCommon::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
r_area = COM_AREA_NONE;
- if (this->m_movieClip) {
+ if (movie_clip_) {
int width, height;
- MovieClipUser user = {0};
- BKE_movieclip_user_set_frame(&user, this->m_framenumber);
- BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height);
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
+ BKE_movieclip_user_set_frame(&user, framenumber_);
+ BKE_movieclip_get_size(movie_clip_, &user, &width, &height);
r_area = preferred_area;
r_area.xmax = r_area.xmin + width;
r_area.ymax = r_area.ymin + height;
@@ -108,9 +102,9 @@ void PlaneTrackMaskOperation::init_data()
}
/* TODO(manzanilla): to be removed with tiled implementation. */
-void PlaneTrackMaskOperation::initExecution()
+void PlaneTrackMaskOperation::init_execution()
{
- PlaneDistortMaskOperation::initExecution();
+ PlaneDistortMaskOperation::init_execution();
if (execution_model_ == eExecutionModel::Tiled) {
PlaneTrackCommon::read_and_calculate_corners(this);
}
@@ -127,9 +121,9 @@ void PlaneTrackWarpImageOperation::init_data()
}
/* TODO(manzanilla): to be removed with tiled implementation. */
-void PlaneTrackWarpImageOperation::initExecution()
+void PlaneTrackWarpImageOperation::init_execution()
{
- PlaneDistortWarpImageOperation::initExecution();
+ PlaneDistortWarpImageOperation::init_execution();
if (execution_model_ == eExecutionModel::Tiled) {
PlaneTrackCommon::read_and_calculate_corners(this);
}
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.h b/source/blender/compositor/operations/COM_PlaneTrackOperation.h
index 60845aac514..22ece04b900 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.h
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.h
@@ -32,10 +32,10 @@ namespace blender::compositor {
class PlaneTrackCommon {
protected:
- MovieClip *m_movieClip;
- int m_framenumber;
- char m_trackingObjectName[64];
- char m_planeTrackName[64];
+ MovieClip *movie_clip_;
+ int framenumber_;
+ char tracking_object_name_[64];
+ char plane_track_name_[64];
/* NOTE: this class is not an operation itself (to prevent virtual inheritance issues)
* implementation classes must make wrappers to use these methods, see below.
@@ -46,25 +46,25 @@ class PlaneTrackCommon {
public:
PlaneTrackCommon();
- void setMovieClip(MovieClip *clip)
+ void set_movie_clip(MovieClip *clip)
{
- this->m_movieClip = clip;
+ movie_clip_ = clip;
}
- void setTrackingObject(char *object)
+ void set_tracking_object(char *object)
{
- BLI_strncpy(this->m_trackingObjectName, object, sizeof(this->m_trackingObjectName));
+ BLI_strncpy(tracking_object_name_, object, sizeof(tracking_object_name_));
}
- void setPlaneTrackName(char *plane_track)
+ void set_plane_track_name(char *plane_track)
{
- BLI_strncpy(this->m_planeTrackName, plane_track, sizeof(this->m_planeTrackName));
+ BLI_strncpy(plane_track_name_, plane_track, sizeof(plane_track_name_));
}
- void setFramenumber(int framenumber)
+ void set_framenumber(int framenumber)
{
- this->m_framenumber = framenumber;
+ framenumber_ = framenumber;
}
private:
- void readCornersFromTrack(float corners[4][2], float frame);
+ void read_corners_from_track(float corners[4][2], float frame);
};
class PlaneTrackMaskOperation : public PlaneDistortMaskOperation, public PlaneTrackCommon {
@@ -75,13 +75,13 @@ class PlaneTrackMaskOperation : public PlaneDistortMaskOperation, public PlaneTr
void init_data() override;
- void initExecution() override;
+ void init_execution() override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override
{
PlaneTrackCommon::determine_canvas(preferred_area, r_area);
- rcti unused;
+ rcti unused = COM_AREA_NONE;
rcti &preferred = r_area;
NodeOperation::determine_canvas(preferred, unused);
}
@@ -96,13 +96,13 @@ class PlaneTrackWarpImageOperation : public PlaneDistortWarpImageOperation,
void init_data() override;
- void initExecution() override;
+ void init_execution() override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override
{
PlaneTrackCommon::determine_canvas(preferred_area, r_area);
- rcti unused;
+ rcti unused = COM_AREA_NONE;
rcti &preferred = r_area;
NodeOperation::determine_canvas(preferred, unused);
}
diff --git a/source/blender/compositor/operations/COM_PosterizeOperation.cc b/source/blender/compositor/operations/COM_PosterizeOperation.cc
index db5860f48f8..585acb31e68 100644
--- a/source/blender/compositor/operations/COM_PosterizeOperation.cc
+++ b/source/blender/compositor/operations/COM_PosterizeOperation.cc
@@ -22,37 +22,37 @@ namespace blender::compositor {
PosterizeOperation::PosterizeOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
- this->m_inputProgram = nullptr;
- this->m_inputStepsProgram = nullptr;
- flags.can_be_constant = true;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
+ input_program_ = nullptr;
+ input_steps_program_ = nullptr;
+ flags_.can_be_constant = true;
}
-void PosterizeOperation::initExecution()
+void PosterizeOperation::init_execution()
{
- this->m_inputProgram = this->getInputSocketReader(0);
- this->m_inputStepsProgram = this->getInputSocketReader(1);
+ input_program_ = this->get_input_socket_reader(0);
+ input_steps_program_ = this->get_input_socket_reader(1);
}
-void PosterizeOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void PosterizeOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float inputValue[4];
- float inputSteps[4];
+ float input_value[4];
+ float input_steps[4];
- this->m_inputProgram->readSampled(inputValue, x, y, sampler);
- this->m_inputStepsProgram->readSampled(inputSteps, x, y, sampler);
- CLAMP(inputSteps[0], 2.0f, 1024.0f);
- const float steps_inv = 1.0f / inputSteps[0];
+ input_program_->read_sampled(input_value, x, y, sampler);
+ input_steps_program_->read_sampled(input_steps, x, y, sampler);
+ CLAMP(input_steps[0], 2.0f, 1024.0f);
+ const float steps_inv = 1.0f / input_steps[0];
- output[0] = floor(inputValue[0] / steps_inv) * steps_inv;
- output[1] = floor(inputValue[1] / steps_inv) * steps_inv;
- output[2] = floor(inputValue[2] / steps_inv) * steps_inv;
- output[3] = inputValue[3];
+ output[0] = floor(input_value[0] / steps_inv) * steps_inv;
+ output[1] = floor(input_value[1] / steps_inv) * steps_inv;
+ output[2] = floor(input_value[2] / steps_inv) * steps_inv;
+ output[3] = input_value[3];
}
void PosterizeOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -73,10 +73,10 @@ void PosterizeOperation::update_memory_buffer_partial(MemoryBuffer *output,
}
}
-void PosterizeOperation::deinitExecution()
+void PosterizeOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
- this->m_inputStepsProgram = nullptr;
+ input_program_ = nullptr;
+ input_steps_program_ = nullptr;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_PosterizeOperation.h b/source/blender/compositor/operations/COM_PosterizeOperation.h
index c625cbb83c6..70e516bccf8 100644
--- a/source/blender/compositor/operations/COM_PosterizeOperation.h
+++ b/source/blender/compositor/operations/COM_PosterizeOperation.h
@@ -25,10 +25,10 @@ namespace blender::compositor {
class PosterizeOperation : public MultiThreadedOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
- SocketReader *m_inputStepsProgram;
+ SocketReader *input_program_;
+ SocketReader *input_steps_program_;
public:
PosterizeOperation();
@@ -36,17 +36,17 @@ class PosterizeOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cc b/source/blender/compositor/operations/COM_PreviewOperation.cc
index 34520264d54..a3fe0acebdf 100644
--- a/source/blender/compositor/operations/COM_PreviewOperation.cc
+++ b/source/blender/compositor/operations/COM_PreviewOperation.cc
@@ -17,126 +17,113 @@
*/
#include "COM_PreviewOperation.h"
-#include "BKE_image.h"
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-#include "BLI_math_color.h"
-#include "BLI_utildefines.h"
-#include "COM_defines.h"
-#include "MEM_guardedalloc.h"
-#include "PIL_time.h"
-#include "WM_api.h"
-#include "WM_types.h"
#include "BKE_node.h"
#include "IMB_colormanagement.h"
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
namespace blender::compositor {
-PreviewOperation::PreviewOperation(const ColorManagedViewSettings *viewSettings,
- const ColorManagedDisplaySettings *displaySettings,
- const unsigned int defaultWidth,
- const unsigned int defaultHeight)
+PreviewOperation::PreviewOperation(const ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ const unsigned int default_width,
+ const unsigned int default_height)
{
- this->addInputSocket(DataType::Color, ResizeMode::Align);
- this->m_preview = nullptr;
- this->m_outputBuffer = nullptr;
- this->m_input = nullptr;
- this->m_divider = 1.0f;
- this->m_viewSettings = viewSettings;
- this->m_displaySettings = displaySettings;
- this->m_defaultWidth = defaultWidth;
- this->m_defaultHeight = defaultHeight;
- flags.use_viewer_border = true;
- flags.is_preview_operation = true;
+ this->add_input_socket(DataType::Color, ResizeMode::Align);
+ preview_ = nullptr;
+ output_buffer_ = nullptr;
+ input_ = nullptr;
+ divider_ = 1.0f;
+ view_settings_ = view_settings;
+ display_settings_ = display_settings;
+ default_width_ = default_width;
+ default_height_ = default_height;
+ flags_.use_viewer_border = true;
+ flags_.is_preview_operation = true;
}
-void PreviewOperation::verifyPreview(bNodeInstanceHash *previews, bNodeInstanceKey key)
+void PreviewOperation::verify_preview(bNodeInstanceHash *previews, bNodeInstanceKey key)
{
/* Size (0, 0) ensures the preview rect is not allocated in advance,
- * this is set later in initExecution once the resolution is determined.
+ * this is set later in init_execution once the resolution is determined.
*/
- this->m_preview = BKE_node_preview_verify(previews, key, 0, 0, true);
+ preview_ = BKE_node_preview_verify(previews, key, 0, 0, true);
}
-void PreviewOperation::initExecution()
+void PreviewOperation::init_execution()
{
- this->m_input = getInputSocketReader(0);
+ input_ = get_input_socket_reader(0);
- if (this->getWidth() == (unsigned int)this->m_preview->xsize &&
- this->getHeight() == (unsigned int)this->m_preview->ysize) {
- this->m_outputBuffer = this->m_preview->rect;
+ if (this->get_width() == (unsigned int)preview_->xsize &&
+ this->get_height() == (unsigned int)preview_->ysize) {
+ output_buffer_ = preview_->rect;
}
- if (this->m_outputBuffer == nullptr) {
- this->m_outputBuffer = (unsigned char *)MEM_callocN(
- sizeof(unsigned char) * 4 * getWidth() * getHeight(), "PreviewOperation");
- if (this->m_preview->rect) {
- MEM_freeN(this->m_preview->rect);
+ if (output_buffer_ == nullptr) {
+ output_buffer_ = (unsigned char *)MEM_callocN(
+ sizeof(unsigned char) * 4 * get_width() * get_height(), "PreviewOperation");
+ if (preview_->rect) {
+ MEM_freeN(preview_->rect);
}
- this->m_preview->xsize = getWidth();
- this->m_preview->ysize = getHeight();
- this->m_preview->rect = this->m_outputBuffer;
+ preview_->xsize = get_width();
+ preview_->ysize = get_height();
+ preview_->rect = output_buffer_;
}
}
-void PreviewOperation::deinitExecution()
+void PreviewOperation::deinit_execution()
{
- this->m_outputBuffer = nullptr;
- this->m_input = nullptr;
+ output_buffer_ = nullptr;
+ input_ = nullptr;
}
-void PreviewOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
+void PreviewOperation::execute_region(rcti *rect, unsigned int /*tile_number*/)
{
int offset;
float color[4];
struct ColormanageProcessor *cm_processor;
- cm_processor = IMB_colormanagement_display_processor_new(this->m_viewSettings,
- this->m_displaySettings);
+ cm_processor = IMB_colormanagement_display_processor_new(view_settings_, display_settings_);
for (int y = rect->ymin; y < rect->ymax; y++) {
- offset = (y * getWidth() + rect->xmin) * 4;
+ offset = (y * get_width() + rect->xmin) * 4;
for (int x = rect->xmin; x < rect->xmax; x++) {
- float rx = floor(x / this->m_divider);
- float ry = floor(y / this->m_divider);
+ float rx = floor(x / divider_);
+ float ry = floor(y / divider_);
color[0] = 0.0f;
color[1] = 0.0f;
color[2] = 0.0f;
color[3] = 1.0f;
- this->m_input->readSampled(color, rx, ry, PixelSampler::Nearest);
+ input_->read_sampled(color, rx, ry, PixelSampler::Nearest);
IMB_colormanagement_processor_apply_v4(cm_processor, color);
- rgba_float_to_uchar(this->m_outputBuffer + offset, color);
+ rgba_float_to_uchar(output_buffer_ + offset, color);
offset += 4;
}
}
IMB_colormanagement_processor_free(cm_processor);
}
-bool PreviewOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool PreviewOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti newInput;
+ rcti new_input;
- newInput.xmin = input->xmin / this->m_divider;
- newInput.xmax = input->xmax / this->m_divider;
- newInput.ymin = input->ymin / this->m_divider;
- newInput.ymax = input->ymax / this->m_divider;
+ new_input.xmin = input->xmin / divider_;
+ new_input.xmax = input->xmax / divider_;
+ new_input.ymin = input->ymin / divider_;
+ new_input.ymax = input->ymax / divider_;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void PreviewOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area)
{
/* Use default preview resolution as preferred ensuring it has size so that
* generated inputs (which don't have resolution on their own) are displayed */
- BLI_assert(this->m_defaultWidth > 0 && this->m_defaultHeight > 0);
+ BLI_assert(default_width_ > 0 && default_height_ > 0);
rcti local_preferred;
- BLI_rcti_init(&local_preferred, 0, m_defaultWidth, 0, m_defaultHeight);
+ BLI_rcti_init(&local_preferred, 0, default_width_, 0, default_height_);
NodeOperation::determine_canvas(local_preferred, r_area);
/* If resolution is 0 there are two possible scenarios:
@@ -150,22 +137,22 @@ void PreviewOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti
*/
int width = BLI_rcti_size_x(&r_area);
int height = BLI_rcti_size_y(&r_area);
- this->m_divider = 0.0f;
+ divider_ = 0.0f;
if (width > 0 && height > 0) {
if (width > height) {
- this->m_divider = (float)COM_PREVIEW_SIZE / (width);
+ divider_ = (float)COM_PREVIEW_SIZE / (width);
}
else {
- this->m_divider = (float)COM_PREVIEW_SIZE / (height);
+ divider_ = (float)COM_PREVIEW_SIZE / (height);
}
}
- width = width * this->m_divider;
- height = height * this->m_divider;
+ width = width * divider_;
+ height = height * divider_;
BLI_rcti_init(&r_area, r_area.xmin, r_area.xmin + width, r_area.ymin, r_area.ymin + height);
}
-eCompositorPriority PreviewOperation::getRenderPriority() const
+eCompositorPriority PreviewOperation::get_render_priority() const
{
return eCompositorPriority::Low;
}
@@ -177,10 +164,10 @@ void PreviewOperation::get_area_of_interest(const int input_idx,
BLI_assert(input_idx == 0);
UNUSED_VARS_NDEBUG(input_idx);
- r_input_area.xmin = output_area.xmin / m_divider;
- r_input_area.xmax = output_area.xmax / m_divider;
- r_input_area.ymin = output_area.ymin / m_divider;
- r_input_area.ymax = output_area.ymax / m_divider;
+ r_input_area.xmin = output_area.xmin / divider_;
+ r_input_area.xmax = output_area.xmax / divider_;
+ r_input_area.ymin = output_area.ymin / divider_;
+ r_input_area.ymax = output_area.ymax / divider_;
}
void PreviewOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(output),
@@ -189,16 +176,16 @@ void PreviewOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(output)
{
MemoryBuffer *input = inputs[0];
struct ColormanageProcessor *cm_processor = IMB_colormanagement_display_processor_new(
- m_viewSettings, m_displaySettings);
+ view_settings_, display_settings_);
rcti buffer_area;
- BLI_rcti_init(&buffer_area, 0, this->getWidth(), 0, this->getHeight());
+ BLI_rcti_init(&buffer_area, 0, this->get_width(), 0, this->get_height());
BuffersIteratorBuilder<uchar> it_builder(
- m_outputBuffer, buffer_area, area, COM_data_type_num_channels(DataType::Color));
+ output_buffer_, buffer_area, area, COM_data_type_num_channels(DataType::Color));
for (BuffersIterator<uchar> it = it_builder.build(); !it.is_end(); ++it) {
- const float rx = it.x / m_divider;
- const float ry = it.y / m_divider;
+ const float rx = it.x / divider_;
+ const float ry = it.y / divider_;
float color[4];
input->read_elem_checked(rx, ry, color);
diff --git a/source/blender/compositor/operations/COM_PreviewOperation.h b/source/blender/compositor/operations/COM_PreviewOperation.h
index 4bd0f07d882..97d1884c9a7 100644
--- a/source/blender/compositor/operations/COM_PreviewOperation.h
+++ b/source/blender/compositor/operations/COM_PreviewOperation.h
@@ -28,40 +28,40 @@ namespace blender::compositor {
class PreviewOperation : public MultiThreadedOperation {
protected:
- unsigned char *m_outputBuffer;
+ unsigned char *output_buffer_;
/**
* \brief holds reference to the SDNA bNode, where this nodes will render the preview image for
*/
- bNodePreview *m_preview;
- SocketReader *m_input;
- float m_divider;
- unsigned int m_defaultWidth;
- unsigned int m_defaultHeight;
+ bNodePreview *preview_;
+ SocketReader *input_;
+ float divider_;
+ unsigned int default_width_;
+ unsigned int default_height_;
- const ColorManagedViewSettings *m_viewSettings;
- const ColorManagedDisplaySettings *m_displaySettings;
+ const ColorManagedViewSettings *view_settings_;
+ const ColorManagedDisplaySettings *display_settings_;
public:
- PreviewOperation(const ColorManagedViewSettings *viewSettings,
- const ColorManagedDisplaySettings *displaySettings,
- unsigned int defaultWidth,
- unsigned int defaultHeight);
- void verifyPreview(bNodeInstanceHash *previews, bNodeInstanceKey key);
+ PreviewOperation(const ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ unsigned int default_width,
+ unsigned int default_height);
+ void verify_preview(bNodeInstanceHash *previews, bNodeInstanceKey key);
- bool isOutputOperation(bool /*rendering*/) const override
+ bool is_output_operation(bool /*rendering*/) const override
{
return !G.background;
}
- void initExecution() override;
- void deinitExecution() override;
- eCompositorPriority getRenderPriority() const override;
+ void init_execution() override;
+ void deinit_execution() override;
+ eCompositorPriority get_render_priority() const override;
- void executeRegion(rcti *rect, unsigned int tileNumber) override;
+ void execute_region(rcti *rect, unsigned int tile_number) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc
index 2982f59a019..4813af511f7 100644
--- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc
+++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc
@@ -19,20 +19,17 @@
#include "COM_ProjectorLensDistortionOperation.h"
#include "COM_ConstantOperation.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
namespace blender::compositor {
ProjectorLensDistortionOperation::ProjectorLensDistortionOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
- this->flags.complex = true;
- this->m_inputProgram = nullptr;
- this->m_dispersionAvailable = false;
- this->m_dispersion = 0.0f;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
+ flags_.complex = true;
+ input_program_ = nullptr;
+ dispersion_available_ = false;
+ dispersion_ = 0.0f;
}
void ProjectorLensDistortionOperation::init_data()
@@ -40,95 +37,94 @@ void ProjectorLensDistortionOperation::init_data()
if (execution_model_ == eExecutionModel::FullFrame) {
NodeOperation *dispersion_input = get_input_operation(1);
if (dispersion_input->get_flags().is_constant_operation) {
- this->m_dispersion =
- static_cast<ConstantOperation *>(dispersion_input)->get_constant_elem()[0];
+ dispersion_ = static_cast<ConstantOperation *>(dispersion_input)->get_constant_elem()[0];
}
- this->m_kr = 0.25f * max_ff(min_ff(this->m_dispersion, 1.0f), 0.0f);
- this->m_kr2 = this->m_kr * 20;
+ kr_ = 0.25f * max_ff(min_ff(dispersion_, 1.0f), 0.0f);
+ kr2_ = kr_ * 20;
}
}
-void ProjectorLensDistortionOperation::initExecution()
+void ProjectorLensDistortionOperation::init_execution()
{
- this->initMutex();
- this->m_inputProgram = this->getInputSocketReader(0);
+ this->init_mutex();
+ input_program_ = this->get_input_socket_reader(0);
}
-void *ProjectorLensDistortionOperation::initializeTileData(rcti * /*rect*/)
+void *ProjectorLensDistortionOperation::initialize_tile_data(rcti * /*rect*/)
{
- updateDispersion();
- void *buffer = this->m_inputProgram->initializeTileData(nullptr);
+ update_dispersion();
+ void *buffer = input_program_->initialize_tile_data(nullptr);
return buffer;
}
-void ProjectorLensDistortionOperation::executePixel(float output[4], int x, int y, void *data)
+void ProjectorLensDistortionOperation::execute_pixel(float output[4], int x, int y, void *data)
{
- float inputValue[4];
- const float height = this->getHeight();
- const float width = this->getWidth();
+ float input_value[4];
+ const float height = this->get_height();
+ const float width = this->get_width();
const float v = (y + 0.5f) / height;
const float u = (x + 0.5f) / width;
- MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
- inputBuffer->readBilinear(inputValue, (u * width + this->m_kr2) - 0.5f, v * height - 0.5f);
- output[0] = inputValue[0];
- inputBuffer->read(inputValue, x, y);
- output[1] = inputValue[1];
- inputBuffer->readBilinear(inputValue, (u * width - this->m_kr2) - 0.5f, v * height - 0.5f);
- output[2] = inputValue[2];
+ MemoryBuffer *input_buffer = (MemoryBuffer *)data;
+ input_buffer->read_bilinear(input_value, (u * width + kr2_) - 0.5f, v * height - 0.5f);
+ output[0] = input_value[0];
+ input_buffer->read(input_value, x, y);
+ output[1] = input_value[1];
+ input_buffer->read_bilinear(input_value, (u * width - kr2_) - 0.5f, v * height - 0.5f);
+ output[2] = input_value[2];
output[3] = 1.0f;
}
-void ProjectorLensDistortionOperation::deinitExecution()
+void ProjectorLensDistortionOperation::deinit_execution()
{
- this->deinitMutex();
- this->m_inputProgram = nullptr;
+ this->deinit_mutex();
+ input_program_ = nullptr;
}
-bool ProjectorLensDistortionOperation::determineDependingAreaOfInterest(
- rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool ProjectorLensDistortionOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
- if (this->m_dispersionAvailable) {
- newInput.ymax = input->ymax;
- newInput.ymin = input->ymin;
- newInput.xmin = input->xmin - this->m_kr2 - 2;
- newInput.xmax = input->xmax + this->m_kr2 + 2;
+ rcti new_input;
+ if (dispersion_available_) {
+ new_input.ymax = input->ymax;
+ new_input.ymin = input->ymin;
+ new_input.xmin = input->xmin - kr2_ - 2;
+ new_input.xmax = input->xmax + kr2_ + 2;
}
else {
- rcti dispInput;
- BLI_rcti_init(&dispInput, 0, 5, 0, 5);
- if (this->getInputOperation(1)->determineDependingAreaOfInterest(
- &dispInput, readOperation, output)) {
+ rcti disp_input;
+ BLI_rcti_init(&disp_input, 0, 5, 0, 5);
+ if (this->get_input_operation(1)->determine_depending_area_of_interest(
+ &disp_input, read_operation, output)) {
return true;
}
- newInput.xmin = input->xmin - 7; /* (0.25f * 20 * 1) + 2 == worse case dispersion */
- newInput.ymin = input->ymin;
- newInput.ymax = input->ymax;
- newInput.xmax = input->xmax + 7; /* (0.25f * 20 * 1) + 2 == worse case dispersion */
+ new_input.xmin = input->xmin - 7; /* (0.25f * 20 * 1) + 2 == worse case dispersion */
+ new_input.ymin = input->ymin;
+ new_input.ymax = input->ymax;
+ new_input.xmax = input->xmax + 7; /* (0.25f * 20 * 1) + 2 == worse case dispersion */
}
- if (this->getInputOperation(0)->determineDependingAreaOfInterest(
- &newInput, readOperation, output)) {
+ if (this->get_input_operation(0)->determine_depending_area_of_interest(
+ &new_input, read_operation, output)) {
return true;
}
return false;
}
/* TODO(manzanilla): to be removed with tiled implementation. */
-void ProjectorLensDistortionOperation::updateDispersion()
+void ProjectorLensDistortionOperation::update_dispersion()
{
- if (this->m_dispersionAvailable) {
+ if (dispersion_available_) {
return;
}
- this->lockMutex();
- if (!this->m_dispersionAvailable) {
+ this->lock_mutex();
+ if (!dispersion_available_) {
float result[4];
- this->getInputSocketReader(1)->readSampled(result, 1, 1, PixelSampler::Nearest);
- this->m_dispersion = result[0];
- this->m_kr = 0.25f * max_ff(min_ff(this->m_dispersion, 1.0f), 0.0f);
- this->m_kr2 = this->m_kr * 20;
- this->m_dispersionAvailable = true;
+ this->get_input_socket_reader(1)->read_sampled(result, 1, 1, PixelSampler::Nearest);
+ dispersion_ = result[0];
+ kr_ = 0.25f * max_ff(min_ff(dispersion_, 1.0f), 0.0f);
+ kr2_ = kr_ * 20;
+ dispersion_available_ = true;
}
- this->unlockMutex();
+ this->unlock_mutex();
}
void ProjectorLensDistortionOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
@@ -160,8 +156,8 @@ void ProjectorLensDistortionOperation::get_area_of_interest(const int input_idx,
r_input_area.ymax = output_area.ymax;
r_input_area.ymin = output_area.ymin;
- r_input_area.xmin = output_area.xmin - this->m_kr2 - 2;
- r_input_area.xmax = output_area.xmax + this->m_kr2 + 2;
+ r_input_area.xmin = output_area.xmin - kr2_ - 2;
+ r_input_area.xmax = output_area.xmax + kr2_ + 2;
}
void ProjectorLensDistortionOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -169,17 +165,17 @@ void ProjectorLensDistortionOperation::update_memory_buffer_partial(MemoryBuffer
Span<MemoryBuffer *> inputs)
{
const MemoryBuffer *input_image = inputs[0];
- const float height = this->getHeight();
- const float width = this->getWidth();
+ const float height = this->get_height();
+ const float width = this->get_width();
float color[4];
for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
const float v = (it.y + 0.5f) / height;
const float u = (it.x + 0.5f) / width;
- input_image->read_elem_bilinear((u * width + this->m_kr2) - 0.5f, v * height - 0.5f, color);
+ input_image->read_elem_bilinear((u * width + kr2_) - 0.5f, v * height - 0.5f, color);
it.out[0] = color[0];
input_image->read_elem(it.x, it.y, color);
it.out[1] = color[1];
- input_image->read_elem_bilinear((u * width - this->m_kr2) - 0.5f, v * height - 0.5f, color);
+ input_image->read_elem_bilinear((u * width - kr2_) - 0.5f, v * height - 0.5f, color);
it.out[2] = color[2];
it.out[3] = 1.0f;
}
diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h
index b42fa3a361c..ea90840e61c 100644
--- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h
+++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h
@@ -26,15 +26,15 @@ namespace blender::compositor {
class ProjectorLensDistortionOperation : public MultiThreadedOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
+ SocketReader *input_program_;
- float m_dispersion;
+ float dispersion_;
/* TODO(manzanilla): to be removed with tiled implementation. */
- bool m_dispersionAvailable;
+ bool dispersion_available_;
- float m_kr, m_kr2;
+ float kr_, kr2_;
public:
ProjectorLensDistortionOperation();
@@ -42,25 +42,25 @@ class ProjectorLensDistortionOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
void init_data() override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void updateDispersion();
+ void update_dispersion();
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
diff --git a/source/blender/compositor/operations/COM_QualityStepHelper.cc b/source/blender/compositor/operations/COM_QualityStepHelper.cc
index e347d278ce4..895e341d550 100644
--- a/source/blender/compositor/operations/COM_QualityStepHelper.cc
+++ b/source/blender/compositor/operations/COM_QualityStepHelper.cc
@@ -22,45 +22,45 @@ namespace blender::compositor {
QualityStepHelper::QualityStepHelper()
{
- this->m_quality = eCompositorQuality::High;
- this->m_step = 1;
- this->m_offsetadd = 4;
+ quality_ = eCompositorQuality::High;
+ step_ = 1;
+ offsetadd_ = 4;
}
-void QualityStepHelper::initExecution(QualityHelper helper)
+void QualityStepHelper::init_execution(QualityHelper helper)
{
switch (helper) {
case COM_QH_INCREASE:
- switch (this->m_quality) {
+ switch (quality_) {
case eCompositorQuality::High:
default:
- this->m_step = 1;
- this->m_offsetadd = 1;
+ step_ = 1;
+ offsetadd_ = 1;
break;
case eCompositorQuality::Medium:
- this->m_step = 2;
- this->m_offsetadd = 2;
+ step_ = 2;
+ offsetadd_ = 2;
break;
case eCompositorQuality::Low:
- this->m_step = 3;
- this->m_offsetadd = 3;
+ step_ = 3;
+ offsetadd_ = 3;
break;
}
break;
case COM_QH_MULTIPLY:
- switch (this->m_quality) {
+ switch (quality_) {
case eCompositorQuality::High:
default:
- this->m_step = 1;
- this->m_offsetadd = 4;
+ step_ = 1;
+ offsetadd_ = 4;
break;
case eCompositorQuality::Medium:
- this->m_step = 2;
- this->m_offsetadd = 8;
+ step_ = 2;
+ offsetadd_ = 8;
break;
case eCompositorQuality::Low:
- this->m_step = 4;
- this->m_offsetadd = 16;
+ step_ = 4;
+ offsetadd_ = 16;
break;
}
break;
diff --git a/source/blender/compositor/operations/COM_QualityStepHelper.h b/source/blender/compositor/operations/COM_QualityStepHelper.h
index c5f16a58686..6f168babeae 100644
--- a/source/blender/compositor/operations/COM_QualityStepHelper.h
+++ b/source/blender/compositor/operations/COM_QualityStepHelper.h
@@ -29,31 +29,31 @@ typedef enum QualityHelper {
class QualityStepHelper {
private:
- eCompositorQuality m_quality;
- int m_step;
- int m_offsetadd;
+ eCompositorQuality quality_;
+ int step_;
+ int offsetadd_;
protected:
/**
* Initialize the execution
*/
- void initExecution(QualityHelper helper);
+ void init_execution(QualityHelper helper);
- inline int getStep() const
+ inline int get_step() const
{
- return this->m_step;
+ return step_;
}
- inline int getOffsetAdd() const
+ inline int get_offset_add() const
{
- return this->m_offsetadd;
+ return offsetadd_;
}
public:
QualityStepHelper();
- void setQuality(eCompositorQuality quality)
+ void set_quality(eCompositorQuality quality)
{
- this->m_quality = quality;
+ quality_ = quality;
}
};
diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.cc b/source/blender/compositor/operations/COM_ReadBufferOperation.cc
index 599370751bb..b0e0b2c219f 100644
--- a/source/blender/compositor/operations/COM_ReadBufferOperation.cc
+++ b/source/blender/compositor/operations/COM_ReadBufferOperation.cc
@@ -17,123 +17,124 @@
*/
#include "COM_ReadBufferOperation.h"
+
+#include "COM_ExecutionGroup.h"
#include "COM_WriteBufferOperation.h"
-#include "COM_defines.h"
namespace blender::compositor {
ReadBufferOperation::ReadBufferOperation(DataType datatype)
{
- this->addOutputSocket(datatype);
- this->m_single_value = false;
- this->m_offset = 0;
- this->m_buffer = nullptr;
- flags.is_read_buffer_operation = true;
+ this->add_output_socket(datatype);
+ single_value_ = false;
+ offset_ = 0;
+ buffer_ = nullptr;
+ flags_.is_read_buffer_operation = true;
}
-void *ReadBufferOperation::initializeTileData(rcti * /*rect*/)
+void *ReadBufferOperation::initialize_tile_data(rcti * /*rect*/)
{
- return m_buffer;
+ return buffer_;
}
void ReadBufferOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
- if (this->m_memoryProxy != nullptr) {
- WriteBufferOperation *operation = this->m_memoryProxy->getWriteBufferOperation();
+ if (memory_proxy_ != nullptr) {
+ WriteBufferOperation *operation = memory_proxy_->get_write_buffer_operation();
operation->determine_canvas(preferred_area, r_area);
operation->set_canvas(r_area);
/** \todo may not occur! But does with blur node. */
- if (this->m_memoryProxy->getExecutor()) {
+ if (memory_proxy_->get_executor()) {
uint resolution[2] = {static_cast<uint>(BLI_rcti_size_x(&r_area)),
static_cast<uint>(BLI_rcti_size_y(&r_area))};
- this->m_memoryProxy->getExecutor()->setResolution(resolution);
+ memory_proxy_->get_executor()->set_resolution(resolution);
}
- m_single_value = operation->isSingleValue();
+ single_value_ = operation->is_single_value();
}
}
-void ReadBufferOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ReadBufferOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- if (m_single_value) {
+ if (single_value_) {
/* write buffer has a single value stored at (0,0) */
- m_buffer->read(output, 0, 0);
+ buffer_->read(output, 0, 0);
}
else {
switch (sampler) {
case PixelSampler::Nearest:
- m_buffer->read(output, x, y);
+ buffer_->read(output, x, y);
break;
case PixelSampler::Bilinear:
default:
- m_buffer->readBilinear(output, x, y);
+ buffer_->read_bilinear(output, x, y);
break;
case PixelSampler::Bicubic:
- m_buffer->readBilinear(output, x, y);
+ buffer_->read_bilinear(output, x, y);
break;
}
}
}
-void ReadBufferOperation::executePixelExtend(float output[4],
- float x,
- float y,
- PixelSampler sampler,
- MemoryBufferExtend extend_x,
- MemoryBufferExtend extend_y)
+void ReadBufferOperation::execute_pixel_extend(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler,
+ MemoryBufferExtend extend_x,
+ MemoryBufferExtend extend_y)
{
- if (m_single_value) {
+ if (single_value_) {
/* write buffer has a single value stored at (0,0) */
- m_buffer->read(output, 0, 0);
+ buffer_->read(output, 0, 0);
}
else if (sampler == PixelSampler::Nearest) {
- m_buffer->read(output, x, y, extend_x, extend_y);
+ buffer_->read(output, x, y, extend_x, extend_y);
}
else {
- m_buffer->readBilinear(output, x, y, extend_x, extend_y);
+ buffer_->read_bilinear(output, x, y, extend_x, extend_y);
}
}
-void ReadBufferOperation::executePixelFiltered(
+void ReadBufferOperation::execute_pixel_filtered(
float output[4], float x, float y, float dx[2], float dy[2])
{
- if (m_single_value) {
+ if (single_value_) {
/* write buffer has a single value stored at (0,0) */
- m_buffer->read(output, 0, 0);
+ buffer_->read(output, 0, 0);
}
else {
const float uv[2] = {x, y};
const float deriv[2][2] = {{dx[0], dx[1]}, {dy[0], dy[1]}};
- m_buffer->readEWA(output, uv, deriv);
+ buffer_->readEWA(output, uv, deriv);
}
}
-bool ReadBufferOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool ReadBufferOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- if (this == readOperation) {
+ if (this == read_operation) {
BLI_rcti_init(output, input->xmin, input->xmax, input->ymin, input->ymax);
return true;
}
return false;
}
-void ReadBufferOperation::readResolutionFromWriteBuffer()
+void ReadBufferOperation::read_resolution_from_write_buffer()
{
- if (this->m_memoryProxy != nullptr) {
- WriteBufferOperation *operation = this->m_memoryProxy->getWriteBufferOperation();
- this->setWidth(operation->getWidth());
- this->setHeight(operation->getHeight());
+ if (memory_proxy_ != nullptr) {
+ WriteBufferOperation *operation = memory_proxy_->get_write_buffer_operation();
+ this->set_width(operation->get_width());
+ this->set_height(operation->get_height());
}
}
-void ReadBufferOperation::updateMemoryBuffer()
+void ReadBufferOperation::update_memory_buffer()
{
- this->m_buffer = this->getMemoryProxy()->getBuffer();
+ buffer_ = this->get_memory_proxy()->get_buffer();
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.h b/source/blender/compositor/operations/COM_ReadBufferOperation.h
index 02f6eccd246..7f461d1c925 100644
--- a/source/blender/compositor/operations/COM_ReadBufferOperation.h
+++ b/source/blender/compositor/operations/COM_ReadBufferOperation.h
@@ -26,51 +26,52 @@ namespace blender::compositor {
class ReadBufferOperation : public NodeOperation {
private:
- MemoryProxy *m_memoryProxy;
- bool m_single_value; /* single value stored in buffer, copied from associated write operation */
- unsigned int m_offset;
- MemoryBuffer *m_buffer;
+ MemoryProxy *memory_proxy_;
+ bool single_value_; /* single value stored in buffer, copied from associated write operation */
+ unsigned int offset_;
+ MemoryBuffer *buffer_;
public:
ReadBufferOperation(DataType datatype);
- void setMemoryProxy(MemoryProxy *memoryProxy)
+ void set_memory_proxy(MemoryProxy *memory_proxy)
{
- this->m_memoryProxy = memoryProxy;
+ memory_proxy_ = memory_proxy;
}
- MemoryProxy *getMemoryProxy() const
+ MemoryProxy *get_memory_proxy() const
{
- return this->m_memoryProxy;
+ return memory_proxy_;
}
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
- void *initializeTileData(rcti *rect) override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
- void executePixelExtend(float output[4],
- float x,
- float y,
- PixelSampler sampler,
- MemoryBufferExtend extend_x,
- MemoryBufferExtend extend_y);
- void executePixelFiltered(float output[4], float x, float y, float dx[2], float dy[2]) override;
- void setOffset(unsigned int offset)
+ void *initialize_tile_data(rcti *rect) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_extend(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler,
+ MemoryBufferExtend extend_x,
+ MemoryBufferExtend extend_y);
+ void execute_pixel_filtered(
+ float output[4], float x, float y, float dx[2], float dy[2]) override;
+ void set_offset(unsigned int offset)
{
- this->m_offset = offset;
+ offset_ = offset;
}
- unsigned int getOffset() const
+ unsigned int get_offset() const
{
- return this->m_offset;
+ return offset_;
}
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
- MemoryBuffer *getInputMemoryBuffer(MemoryBuffer **memoryBuffers) override
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
+ MemoryBuffer *get_input_memory_buffer(MemoryBuffer **memory_buffers) override
{
- return memoryBuffers[this->m_offset];
+ return memory_buffers[offset_];
}
- void readResolutionFromWriteBuffer();
- void updateMemoryBuffer();
+ void read_resolution_from_write_buffer();
+ void update_memory_buffer();
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cc b/source/blender/compositor/operations/COM_RenderLayersProg.cc
index 2ac551ffe6f..d8e73b7c979 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cc
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cc
@@ -18,39 +18,27 @@
#include "COM_RenderLayersProg.h"
-#include "COM_MetaData.h"
-
#include "BKE_image.h"
-#include "BKE_scene.h"
-
-#include "BLI_listbase.h"
-#include "BLI_string.h"
-#include "BLI_string_ref.hh"
-
-#include "DNA_scene_types.h"
-
-#include "RE_pipeline.h"
-#include "RE_texture.h"
namespace blender::compositor {
/* ******** Render Layers Base Prog ******** */
-RenderLayersProg::RenderLayersProg(const char *passName, DataType type, int elementsize)
- : m_passName(passName)
+RenderLayersProg::RenderLayersProg(const char *pass_name, DataType type, int elementsize)
+ : pass_name_(pass_name)
{
- this->setScene(nullptr);
- this->m_inputBuffer = nullptr;
- this->m_elementsize = elementsize;
- this->m_rd = nullptr;
+ this->set_scene(nullptr);
+ input_buffer_ = nullptr;
+ elementsize_ = elementsize;
+ rd_ = nullptr;
layer_buffer_ = nullptr;
- this->addOutputSocket(type);
+ this->add_output_socket(type);
}
-void RenderLayersProg::initExecution()
+void RenderLayersProg::init_execution()
{
- Scene *scene = this->getScene();
+ Scene *scene = this->get_scene();
Render *re = (scene) ? RE_GetSceneRender(scene) : nullptr;
RenderResult *rr = nullptr;
@@ -59,15 +47,14 @@ void RenderLayersProg::initExecution()
}
if (rr) {
- ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, getLayerId());
+ ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, get_layer_id());
if (view_layer) {
RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name);
if (rl) {
- this->m_inputBuffer = RE_RenderLayerGetPass(
- rl, this->m_passName.c_str(), this->m_viewName);
- if (m_inputBuffer) {
- layer_buffer_ = new MemoryBuffer(m_inputBuffer, m_elementsize, getWidth(), getHeight());
+ input_buffer_ = RE_RenderLayerGetPass(rl, pass_name_.c_str(), view_name_);
+ if (input_buffer_) {
+ layer_buffer_ = new MemoryBuffer(input_buffer_, elementsize_, get_width(), get_height());
}
}
}
@@ -78,17 +65,17 @@ void RenderLayersProg::initExecution()
}
}
-void RenderLayersProg::doInterpolation(float output[4], float x, float y, PixelSampler sampler)
+void RenderLayersProg::do_interpolation(float output[4], float x, float y, PixelSampler sampler)
{
unsigned int offset;
- int width = this->getWidth(), height = this->getHeight();
+ int width = this->get_width(), height = this->get_height();
int ix = x, iy = y;
if (ix < 0 || iy < 0 || ix >= width || iy >= height) {
- if (this->m_elementsize == 1) {
+ if (elementsize_ == 1) {
output[0] = 0.0f;
}
- else if (this->m_elementsize == 3) {
+ else if (elementsize_ == 3) {
zero_v3(output);
}
else {
@@ -99,48 +86,49 @@ void RenderLayersProg::doInterpolation(float output[4], float x, float y, PixelS
switch (sampler) {
case PixelSampler::Nearest: {
- offset = (iy * width + ix) * this->m_elementsize;
+ offset = (iy * width + ix) * elementsize_;
- if (this->m_elementsize == 1) {
- output[0] = this->m_inputBuffer[offset];
+ if (elementsize_ == 1) {
+ output[0] = input_buffer_[offset];
}
- else if (this->m_elementsize == 3) {
- copy_v3_v3(output, &this->m_inputBuffer[offset]);
+ else if (elementsize_ == 3) {
+ copy_v3_v3(output, &input_buffer_[offset]);
}
else {
- copy_v4_v4(output, &this->m_inputBuffer[offset]);
+ copy_v4_v4(output, &input_buffer_[offset]);
}
break;
}
case PixelSampler::Bilinear:
- BLI_bilinear_interpolation_fl(
- this->m_inputBuffer, output, width, height, this->m_elementsize, x, y);
+ BLI_bilinear_interpolation_fl(input_buffer_, output, width, height, elementsize_, x, y);
break;
case PixelSampler::Bicubic:
- BLI_bicubic_interpolation_fl(
- this->m_inputBuffer, output, width, height, this->m_elementsize, x, y);
+ BLI_bicubic_interpolation_fl(input_buffer_, output, width, height, elementsize_, x, y);
break;
}
}
-void RenderLayersProg::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void RenderLayersProg::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
#if 0
- const RenderData *rd = this->m_rd;
+ const RenderData *rd = rd_;
int dx = 0, dy = 0;
if (rd->mode & R_BORDER && rd->mode & R_CROP) {
- /* see comment in executeRegion describing coordinate mapping,
+ /* see comment in execute_region describing coordinate mapping,
* here it simply goes other way around
*/
int full_width = rd->xsch * rd->size / 100;
int full_height = rd->ysch * rd->size / 100;
- dx = rd->border.xmin * full_width - (full_width - this->getWidth()) / 2.0f;
- dy = rd->border.ymin * full_height - (full_height - this->getHeight()) / 2.0f;
+ dx = rd->border.xmin * full_width - (full_width - this->get_width()) / 2.0f;
+ dy = rd->border.ymin * full_height - (full_height - this->get_height()) / 2.0f;
}
int ix = x - dx;
@@ -149,8 +137,8 @@ void RenderLayersProg::executePixelSampled(float output[4], float x, float y, Pi
#ifndef NDEBUG
{
- const DataType data_type = this->getOutputSocket()->getDataType();
- int actual_element_size = this->m_elementsize;
+ const DataType data_type = this->get_output_socket()->get_data_type();
+ int actual_element_size = elementsize_;
int expected_element_size;
if (data_type == DataType::Value) {
expected_element_size = 1;
@@ -169,8 +157,8 @@ void RenderLayersProg::executePixelSampled(float output[4], float x, float y, Pi
}
#endif
- if (this->m_inputBuffer == nullptr) {
- int elemsize = this->m_elementsize;
+ if (input_buffer_ == nullptr) {
+ int elemsize = elementsize_;
if (elemsize == 1) {
output[0] = 0.0f;
}
@@ -183,13 +171,13 @@ void RenderLayersProg::executePixelSampled(float output[4], float x, float y, Pi
}
}
else {
- doInterpolation(output, x, y, sampler);
+ do_interpolation(output, x, y, sampler);
}
}
-void RenderLayersProg::deinitExecution()
+void RenderLayersProg::deinit_execution()
{
- this->m_inputBuffer = nullptr;
+ input_buffer_ = nullptr;
if (layer_buffer_) {
delete layer_buffer_;
layer_buffer_ = nullptr;
@@ -198,7 +186,7 @@ void RenderLayersProg::deinitExecution()
void RenderLayersProg::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area)
{
- Scene *sce = this->getScene();
+ Scene *sce = this->get_scene();
Render *re = (sce) ? RE_GetSceneRender(sce) : nullptr;
RenderResult *rr = nullptr;
@@ -209,7 +197,7 @@ void RenderLayersProg::determine_canvas(const rcti &UNUSED(preferred_area), rcti
}
if (rr) {
- ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&sce->view_layers, getLayerId());
+ ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&sce->view_layers, get_layer_id());
if (view_layer) {
RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name);
if (rl) {
@@ -223,9 +211,9 @@ void RenderLayersProg::determine_canvas(const rcti &UNUSED(preferred_area), rcti
}
}
-std::unique_ptr<MetaData> RenderLayersProg::getMetaData()
+std::unique_ptr<MetaData> RenderLayersProg::get_meta_data()
{
- Scene *scene = this->getScene();
+ Scene *scene = this->get_scene();
Render *re = (scene) ? RE_GetSceneRender(scene) : nullptr;
RenderResult *render_result = nullptr;
MetaDataExtractCallbackData callback_data = {nullptr};
@@ -235,15 +223,15 @@ std::unique_ptr<MetaData> RenderLayersProg::getMetaData()
}
if (render_result && render_result->stamp_data) {
- ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, getLayerId());
+ ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, get_layer_id());
if (view_layer) {
std::string full_layer_name = std::string(
view_layer->name,
BLI_strnlen(view_layer->name, sizeof(view_layer->name))) +
- "." + m_passName;
+ "." + pass_name_;
blender::StringRef cryptomatte_layer_name =
blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name(full_layer_name);
- callback_data.setCryptomatteKeys(cryptomatte_layer_name);
+ callback_data.set_cryptomatte_keys(cryptomatte_layer_name);
BKE_stamp_info_callback(&callback_data,
render_result->stamp_data,
@@ -264,28 +252,29 @@ void RenderLayersProg::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> UNUSED(inputs))
{
- BLI_assert(output->get_num_channels() >= m_elementsize);
+ BLI_assert(output->get_num_channels() >= elementsize_);
if (layer_buffer_) {
- output->copy_from(layer_buffer_, area, 0, m_elementsize, 0);
+ output->copy_from(layer_buffer_, area, 0, elementsize_, 0);
}
else {
- std::unique_ptr<float[]> zero_elem = std::make_unique<float[]>(m_elementsize);
- output->fill(area, 0, zero_elem.get(), m_elementsize);
+ std::unique_ptr<float[]> zero_elem = std::make_unique<float[]>(elementsize_);
+ output->fill(area, 0, zero_elem.get(), elementsize_);
}
}
/* ******** Render Layers AO Operation ******** */
-void RenderLayersAOOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+
+void RenderLayersAOOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float *inputBuffer = this->getInputBuffer();
- if (inputBuffer == nullptr) {
+ float *input_buffer = this->get_input_buffer();
+ if (input_buffer == nullptr) {
zero_v3(output);
}
else {
- doInterpolation(output, x, y, sampler);
+ do_interpolation(output, x, y, sampler);
}
output[3] = 1.0f;
}
@@ -295,7 +284,7 @@ void RenderLayersAOOperation::update_memory_buffer_partial(MemoryBuffer *output,
Span<MemoryBuffer *> UNUSED(inputs))
{
BLI_assert(output->get_num_channels() == COM_DATA_TYPE_COLOR_CHANNELS);
- BLI_assert(m_elementsize == COM_DATA_TYPE_COLOR_CHANNELS);
+ BLI_assert(elementsize_ == COM_DATA_TYPE_COLOR_CHANNELS);
if (layer_buffer_) {
output->copy_from(layer_buffer_, area, 0, COM_DATA_TYPE_VECTOR_CHANNELS, 0);
}
@@ -306,19 +295,20 @@ void RenderLayersAOOperation::update_memory_buffer_partial(MemoryBuffer *output,
}
/* ******** Render Layers Alpha Operation ******** */
-void RenderLayersAlphaProg::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+
+void RenderLayersAlphaProg::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- float *inputBuffer = this->getInputBuffer();
+ float *input_buffer = this->get_input_buffer();
- if (inputBuffer == nullptr) {
+ if (input_buffer == nullptr) {
output[0] = 0.0f;
}
else {
float temp[4];
- doInterpolation(temp, x, y, sampler);
+ do_interpolation(temp, x, y, sampler);
output[0] = temp[3];
}
}
@@ -328,7 +318,7 @@ void RenderLayersAlphaProg::update_memory_buffer_partial(MemoryBuffer *output,
Span<MemoryBuffer *> UNUSED(inputs))
{
BLI_assert(output->get_num_channels() == COM_DATA_TYPE_VALUE_CHANNELS);
- BLI_assert(m_elementsize == COM_DATA_TYPE_COLOR_CHANNELS);
+ BLI_assert(elementsize_ == COM_DATA_TYPE_COLOR_CHANNELS);
if (layer_buffer_) {
output->copy_from(layer_buffer_, area, 3, COM_DATA_TYPE_VALUE_CHANNELS, 0);
}
@@ -338,22 +328,23 @@ void RenderLayersAlphaProg::update_memory_buffer_partial(MemoryBuffer *output,
}
/* ******** Render Layers Depth Operation ******** */
-void RenderLayersDepthProg::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler /*sampler*/)
+
+void RenderLayersDepthProg::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
int ix = x;
int iy = y;
- float *inputBuffer = this->getInputBuffer();
+ float *input_buffer = this->get_input_buffer();
- if (inputBuffer == nullptr || ix < 0 || iy < 0 || ix >= (int)this->getWidth() ||
- iy >= (int)this->getHeight()) {
+ if (input_buffer == nullptr || ix < 0 || iy < 0 || ix >= (int)this->get_width() ||
+ iy >= (int)this->get_height()) {
output[0] = 10e10f;
}
else {
- unsigned int offset = (iy * this->getWidth() + ix);
- output[0] = inputBuffer[offset];
+ unsigned int offset = (iy * this->get_width() + ix);
+ output[0] = input_buffer[offset];
}
}
@@ -362,7 +353,7 @@ void RenderLayersDepthProg::update_memory_buffer_partial(MemoryBuffer *output,
Span<MemoryBuffer *> UNUSED(inputs))
{
BLI_assert(output->get_num_channels() == COM_DATA_TYPE_VALUE_CHANNELS);
- BLI_assert(m_elementsize == COM_DATA_TYPE_VALUE_CHANNELS);
+ BLI_assert(elementsize_ == COM_DATA_TYPE_VALUE_CHANNELS);
if (layer_buffer_) {
output->copy_from(layer_buffer_, area);
}
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h
index b499afd45df..79afe3c2a8c 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.h
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.h
@@ -38,17 +38,17 @@ class RenderLayersProg : public MultiThreadedOperation {
/**
* Reference to the scene object.
*/
- Scene *m_scene;
+ Scene *scene_;
/**
- * layerId of the layer where this operation needs to get its data from
+ * layer_id of the layer where this operation needs to get its data from
*/
- short m_layerId;
+ short layer_id_;
/**
- * viewName of the view to use (unless another view is specified by the node
+ * view_name of the view to use (unless another view is specified by the node
*/
- const char *m_viewName;
+ const char *view_name_;
const MemoryBuffer *layer_buffer_;
@@ -56,19 +56,19 @@ class RenderLayersProg : public MultiThreadedOperation {
* Cached instance to the float buffer inside the layer.
* TODO: To be removed with tiled implementation.
*/
- float *m_inputBuffer;
+ float *input_buffer_;
/**
* Render-pass where this operation needs to get its data from.
*/
- std::string m_passName;
+ std::string pass_name_;
- int m_elementsize;
+ int elementsize_;
/**
* \brief render data used for active rendering
*/
- const RenderData *m_rd;
+ const RenderData *rd_;
/**
* Determine the output resolution. The resolution is retrieved from the Renderer
@@ -78,56 +78,56 @@ class RenderLayersProg : public MultiThreadedOperation {
/**
* retrieve the reference to the float buffer of the renderer.
*/
- inline float *getInputBuffer()
+ inline float *get_input_buffer()
{
- return this->m_inputBuffer;
+ return input_buffer_;
}
- void doInterpolation(float output[4], float x, float y, PixelSampler sampler);
+ void do_interpolation(float output[4], float x, float y, PixelSampler sampler);
public:
/**
* Constructor
*/
- RenderLayersProg(const char *passName, DataType type, int elementsize);
+ RenderLayersProg(const char *pass_name, DataType type, int elementsize);
/**
* setter for the scene field. Will be called from
* \see RenderLayerNode to set the actual scene where
* the data will be retrieved from.
*/
- void setScene(Scene *scene)
+ void set_scene(Scene *scene)
{
- this->m_scene = scene;
+ scene_ = scene;
}
- Scene *getScene() const
+ Scene *get_scene() const
{
- return this->m_scene;
+ return scene_;
}
- void setRenderData(const RenderData *rd)
+ void set_render_data(const RenderData *rd)
{
- this->m_rd = rd;
+ rd_ = rd;
}
- void setLayerId(short layerId)
+ void set_layer_id(short layer_id)
{
- this->m_layerId = layerId;
+ layer_id_ = layer_id;
}
- short getLayerId() const
+ short get_layer_id() const
{
- return this->m_layerId;
+ return layer_id_;
}
- void setViewName(const char *viewName)
+ void set_view_name(const char *view_name)
{
- this->m_viewName = viewName;
+ view_name_ = view_name;
}
- const char *getViewName()
+ const char *get_view_name()
{
- return this->m_viewName;
+ return view_name_;
}
- void initExecution() override;
- void deinitExecution() override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void init_execution() override;
+ void deinit_execution() override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- std::unique_ptr<MetaData> getMetaData() override;
+ std::unique_ptr<MetaData> get_meta_data() override;
virtual void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
@@ -136,11 +136,11 @@ class RenderLayersProg : public MultiThreadedOperation {
class RenderLayersAOOperation : public RenderLayersProg {
public:
- RenderLayersAOOperation(const char *passName, DataType type, int elementsize)
- : RenderLayersProg(passName, type, elementsize)
+ RenderLayersAOOperation(const char *pass_name, DataType type, int elementsize)
+ : RenderLayersProg(pass_name, type, elementsize)
{
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
@@ -149,11 +149,11 @@ class RenderLayersAOOperation : public RenderLayersProg {
class RenderLayersAlphaProg : public RenderLayersProg {
public:
- RenderLayersAlphaProg(const char *passName, DataType type, int elementsize)
- : RenderLayersProg(passName, type, elementsize)
+ RenderLayersAlphaProg(const char *pass_name, DataType type, int elementsize)
+ : RenderLayersProg(pass_name, type, elementsize)
{
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
@@ -162,11 +162,11 @@ class RenderLayersAlphaProg : public RenderLayersProg {
class RenderLayersDepthProg : public RenderLayersProg {
public:
- RenderLayersDepthProg(const char *passName, DataType type, int elementsize)
- : RenderLayersProg(passName, type, elementsize)
+ RenderLayersDepthProg(const char *pass_name, DataType type, int elementsize)
+ : RenderLayersProg(pass_name, type, elementsize)
{
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_RotateOperation.cc b/source/blender/compositor/operations/COM_RotateOperation.cc
index 9e26c93feac..145a2f9c9d0 100644
--- a/source/blender/compositor/operations/COM_RotateOperation.cc
+++ b/source/blender/compositor/operations/COM_RotateOperation.cc
@@ -17,22 +17,19 @@
*/
#include "COM_RotateOperation.h"
-#include "COM_ConstantOperation.h"
-
-#include "BLI_math.h"
namespace blender::compositor {
RotateOperation::RotateOperation()
{
- this->addInputSocket(DataType::Color, ResizeMode::None);
- this->addInputSocket(DataType::Value, ResizeMode::None);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color, ResizeMode::None);
+ this->add_input_socket(DataType::Value, ResizeMode::None);
+ this->add_output_socket(DataType::Color);
this->set_canvas_input_index(0);
- this->m_imageSocket = nullptr;
- this->m_degreeSocket = nullptr;
- this->m_doDegree2RadConversion = false;
- this->m_isDegreeSet = false;
+ image_socket_ = nullptr;
+ degree_socket_ = nullptr;
+ do_degree2_rad_conversion_ = false;
+ is_degree_set_ = false;
sampler_ = PixelSampler::Bilinear;
}
@@ -130,29 +127,29 @@ void RotateOperation::get_rotation_canvas(const rcti &input_canvas,
void RotateOperation::init_data()
{
if (execution_model_ == eExecutionModel::Tiled) {
- get_rotation_center(get_canvas(), m_centerX, m_centerY);
+ get_rotation_center(get_canvas(), center_x_, center_y_);
}
}
-void RotateOperation::initExecution()
+void RotateOperation::init_execution()
{
- this->m_imageSocket = this->getInputSocketReader(0);
- this->m_degreeSocket = this->getInputSocketReader(1);
+ image_socket_ = this->get_input_socket_reader(0);
+ degree_socket_ = this->get_input_socket_reader(1);
}
-void RotateOperation::deinitExecution()
+void RotateOperation::deinit_execution()
{
- this->m_imageSocket = nullptr;
- this->m_degreeSocket = nullptr;
+ image_socket_ = nullptr;
+ degree_socket_ = nullptr;
}
-inline void RotateOperation::ensureDegree()
+inline void RotateOperation::ensure_degree()
{
- if (!this->m_isDegreeSet) {
+ if (!is_degree_set_) {
float degree[4];
switch (execution_model_) {
case eExecutionModel::Tiled:
- this->m_degreeSocket->readSampled(degree, 0, 0, PixelSampler::Nearest);
+ degree_socket_->read_sampled(degree, 0, 0, PixelSampler::Nearest);
break;
case eExecutionModel::FullFrame:
degree[0] = get_input_operation(DEGREE_INPUT_INDEX)->get_constant_value_default(0.0f);
@@ -160,60 +157,63 @@ inline void RotateOperation::ensureDegree()
}
double rad;
- if (this->m_doDegree2RadConversion) {
+ if (do_degree2_rad_conversion_) {
rad = DEG2RAD((double)degree[0]);
}
else {
rad = degree[0];
}
- this->m_cosine = cos(rad);
- this->m_sine = sin(rad);
+ cosine_ = cos(rad);
+ sine_ = sin(rad);
- this->m_isDegreeSet = true;
+ is_degree_set_ = true;
}
}
-void RotateOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void RotateOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- ensureDegree();
- const float dy = y - this->m_centerY;
- const float dx = x - this->m_centerX;
- const float nx = this->m_centerX + (this->m_cosine * dx + this->m_sine * dy);
- const float ny = this->m_centerY + (-this->m_sine * dx + this->m_cosine * dy);
- this->m_imageSocket->readSampled(output, nx, ny, sampler);
+ ensure_degree();
+ const float dy = y - center_y_;
+ const float dx = x - center_x_;
+ const float nx = center_x_ + (cosine_ * dx + sine_ * dy);
+ const float ny = center_y_ + (-sine_ * dx + cosine_ * dy);
+ image_socket_->read_sampled(output, nx, ny, sampler);
}
-bool RotateOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool RotateOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- ensureDegree();
- rcti newInput;
-
- const float dxmin = input->xmin - this->m_centerX;
- const float dymin = input->ymin - this->m_centerY;
- const float dxmax = input->xmax - this->m_centerX;
- const float dymax = input->ymax - this->m_centerY;
-
- const float x1 = this->m_centerX + (this->m_cosine * dxmin + this->m_sine * dymin);
- const float x2 = this->m_centerX + (this->m_cosine * dxmax + this->m_sine * dymin);
- const float x3 = this->m_centerX + (this->m_cosine * dxmin + this->m_sine * dymax);
- const float x4 = this->m_centerX + (this->m_cosine * dxmax + this->m_sine * dymax);
- const float y1 = this->m_centerY + (-this->m_sine * dxmin + this->m_cosine * dymin);
- const float y2 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymin);
- const float y3 = this->m_centerY + (-this->m_sine * dxmin + this->m_cosine * dymax);
- const float y4 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymax);
+ ensure_degree();
+ rcti new_input;
+
+ const float dxmin = input->xmin - center_x_;
+ const float dymin = input->ymin - center_y_;
+ const float dxmax = input->xmax - center_x_;
+ const float dymax = input->ymax - center_y_;
+
+ const float x1 = center_x_ + (cosine_ * dxmin + sine_ * dymin);
+ const float x2 = center_x_ + (cosine_ * dxmax + sine_ * dymin);
+ const float x3 = center_x_ + (cosine_ * dxmin + sine_ * dymax);
+ const float x4 = center_x_ + (cosine_ * dxmax + sine_ * dymax);
+ const float y1 = center_y_ + (-sine_ * dxmin + cosine_ * dymin);
+ const float y2 = center_y_ + (-sine_ * dxmax + cosine_ * dymin);
+ const float y3 = center_y_ + (-sine_ * dxmin + cosine_ * dymax);
+ const float y4 = center_y_ + (-sine_ * dxmax + cosine_ * dymax);
const float minx = MIN2(x1, MIN2(x2, MIN2(x3, x4)));
const float maxx = MAX2(x1, MAX2(x2, MAX2(x3, x4)));
const float miny = MIN2(y1, MIN2(y2, MIN2(y3, y4)));
const float maxy = MAX2(y1, MAX2(y2, MAX2(y3, y4)));
- newInput.xmax = ceil(maxx) + 1;
- newInput.xmin = floor(minx) - 1;
- newInput.ymax = ceil(maxy) + 1;
- newInput.ymin = floor(miny) - 1;
+ new_input.xmax = ceil(maxx) + 1;
+ new_input.xmin = floor(minx) - 1;
+ new_input.ymax = ceil(maxy) + 1;
+ new_input.ymin = floor(miny) - 1;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void RotateOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
@@ -224,15 +224,15 @@ void RotateOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
}
const bool image_determined =
- getInputSocket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
+ get_input_socket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
if (image_determined) {
rcti input_canvas = r_area;
- rcti unused;
- getInputSocket(DEGREE_INPUT_INDEX)->determine_canvas(input_canvas, unused);
+ rcti unused = COM_AREA_NONE;
+ get_input_socket(DEGREE_INPUT_INDEX)->determine_canvas(input_canvas, unused);
- ensureDegree();
+ ensure_degree();
- get_rotation_canvas(input_canvas, m_sine, m_cosine, r_area);
+ get_rotation_canvas(input_canvas, sine_, cosine_, r_area);
}
}
@@ -245,11 +245,11 @@ void RotateOperation::get_area_of_interest(const int input_idx,
return;
}
- ensureDegree();
+ ensure_degree();
const rcti &input_image_canvas = get_input_operation(IMAGE_INPUT_INDEX)->get_canvas();
get_rotation_area_of_interest(
- input_image_canvas, this->get_canvas(), m_sine, m_cosine, output_area, r_input_area);
+ input_image_canvas, this->get_canvas(), sine_, cosine_, output_area, r_input_area);
expand_area_for_sampler(r_input_area, sampler_);
}
@@ -269,7 +269,7 @@ void RotateOperation::update_memory_buffer_partial(MemoryBuffer *output,
for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
float x = rotate_offset_x + it.x + canvas_.xmin;
float y = rotate_offset_y + it.y + canvas_.ymin;
- rotate_coords(x, y, center_x, center_y, m_sine, m_cosine);
+ rotate_coords(x, y, center_x, center_y, sine_, cosine_);
input_img->read_elem_sampled(x - canvas_.xmin, y - canvas_.ymin, sampler_, it.out);
}
}
diff --git a/source/blender/compositor/operations/COM_RotateOperation.h b/source/blender/compositor/operations/COM_RotateOperation.h
index 76f203cfbc0..f53fb3a4932 100644
--- a/source/blender/compositor/operations/COM_RotateOperation.h
+++ b/source/blender/compositor/operations/COM_RotateOperation.h
@@ -27,16 +27,16 @@ class RotateOperation : public MultiThreadedOperation {
constexpr static int IMAGE_INPUT_INDEX = 0;
constexpr static int DEGREE_INPUT_INDEX = 1;
- SocketReader *m_imageSocket;
- SocketReader *m_degreeSocket;
+ SocketReader *image_socket_;
+ SocketReader *degree_socket_;
/* TODO(manzanilla): to be removed with tiled implementation. */
- float m_centerX;
- float m_centerY;
+ float center_x_;
+ float center_y_;
- float m_cosine;
- float m_sine;
- bool m_doDegree2RadConversion;
- bool m_isDegreeSet;
+ float cosine_;
+ float sine_;
+ bool do_degree2_rad_conversion_;
+ bool is_degree_set_;
PixelSampler sampler_;
public:
@@ -56,40 +56,32 @@ class RotateOperation : public MultiThreadedOperation {
const rcti &rotate_canvas,
float &r_offset_x,
float &r_offset_y);
- static void get_area_rotation_bounds(const rcti &area,
- const float center_x,
- const float center_y,
- const float sine,
- const float cosine,
- rcti &r_bounds);
- static void get_area_rotation_bounds_inverted(const rcti &area,
- const float center_x,
- const float center_y,
- const float sine,
- const float cosine,
- rcti &r_bounds);
+ static void get_area_rotation_bounds(
+ const rcti &area, float center_x, float center_y, float sine, float cosine, rcti &r_bounds);
+ static void get_area_rotation_bounds_inverted(
+ const rcti &area, float center_x, float center_y, float sine, float cosine, rcti &r_bounds);
static void get_rotation_area_of_interest(const rcti &input_canvas,
const rcti &rotate_canvas,
- const float sine,
- const float cosine,
+ float sine,
+ float cosine,
const rcti &output_area,
rcti &r_input_area);
static void get_rotation_canvas(const rcti &input_canvas,
- const float sine,
- const float cosine,
+ float sine,
+ float cosine,
rcti &r_canvas);
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void init_data() override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
- void setDoDegree2RadConversion(bool abool)
+ void set_do_degree2_rad_conversion(bool abool)
{
- this->m_doDegree2RadConversion = abool;
+ do_degree2_rad_conversion_ = abool;
}
void set_sampler(PixelSampler sampler)
@@ -97,7 +89,7 @@ class RotateOperation : public MultiThreadedOperation {
sampler_ = sampler;
}
- void ensureDegree();
+ void ensure_degree();
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_SMAAOperation.cc b/source/blender/compositor/operations/COM_SMAAOperation.cc
index 4153b9c8523..20e85c69ac8 100644
--- a/source/blender/compositor/operations/COM_SMAAOperation.cc
+++ b/source/blender/compositor/operations/COM_SMAAOperation.cc
@@ -20,7 +20,6 @@
#include "COM_SMAAOperation.h"
#include "BKE_node.h"
-#include "BLI_math.h"
#include "COM_SMAAAreaTexture.h"
extern "C" {
@@ -39,7 +38,7 @@ namespace blender::compositor {
*
* This file is based on SMAA-CPP:
*
- * https://github.com/iRi-E/smaa-cpp
+ * https://github.com/i_ri-E/smaa-cpp
*
* Currently only SMAA 1x mode is provided, so the operation will be done
* with no spatial multi-sampling nor temporal super-sampling.
@@ -65,7 +64,7 @@ namespace blender::compositor {
* #buffer->read_elem_checked. */
static inline void sample(SocketReader *reader, int x, int y, float color[4])
{
- if (x < 0 || x >= reader->getWidth() || y < 0 || y >= reader->getHeight()) {
+ if (x < 0 || x >= reader->get_width() || y < 0 || y >= reader->get_height()) {
color[0] = color[1] = color[2] = color[3] = 0.0;
return;
}
@@ -168,50 +167,50 @@ static void area_diag(int d1, int d2, int e1, int e2, float weights[2])
SMAAEdgeDetectionOperation::SMAAEdgeDetectionOperation()
{
- this->addInputSocket(DataType::Color); /* image */
- this->addInputSocket(DataType::Value); /* Depth, material ID, etc. TODO: currently unused. */
- this->addOutputSocket(DataType::Color);
- this->flags.complex = true;
- this->m_imageReader = nullptr;
- this->m_valueReader = nullptr;
- this->setThreshold(CMP_DEFAULT_SMAA_THRESHOLD);
- this->setLocalContrastAdaptationFactor(CMP_DEFAULT_SMAA_CONTRAST_LIMIT);
+ this->add_input_socket(DataType::Color); /* image */
+ this->add_input_socket(DataType::Value); /* Depth, material ID, etc. TODO: currently unused. */
+ this->add_output_socket(DataType::Color);
+ flags_.complex = true;
+ image_reader_ = nullptr;
+ value_reader_ = nullptr;
+ this->set_threshold(CMP_DEFAULT_SMAA_THRESHOLD);
+ this->set_local_contrast_adaptation_factor(CMP_DEFAULT_SMAA_CONTRAST_LIMIT);
}
-void SMAAEdgeDetectionOperation::initExecution()
+void SMAAEdgeDetectionOperation::init_execution()
{
- this->m_imageReader = this->getInputSocketReader(0);
- this->m_valueReader = this->getInputSocketReader(1);
+ image_reader_ = this->get_input_socket_reader(0);
+ value_reader_ = this->get_input_socket_reader(1);
}
-void SMAAEdgeDetectionOperation::deinitExecution()
+void SMAAEdgeDetectionOperation::deinit_execution()
{
- this->m_imageReader = nullptr;
- this->m_valueReader = nullptr;
+ image_reader_ = nullptr;
+ value_reader_ = nullptr;
}
-void SMAAEdgeDetectionOperation::setThreshold(float threshold)
+void SMAAEdgeDetectionOperation::set_threshold(float threshold)
{
/* UI values are between 0 and 1 for simplicity but algorithm expects values between 0 and 0.5 */
- m_threshold = scalenorm(0, 0.5, threshold);
+ threshold_ = scalenorm(0, 0.5, threshold);
}
-void SMAAEdgeDetectionOperation::setLocalContrastAdaptationFactor(float factor)
+void SMAAEdgeDetectionOperation::set_local_contrast_adaptation_factor(float factor)
{
/* UI values are between 0 and 1 for simplicity but algorithm expects values between 1 and 10 */
- m_contrast_limit = scalenorm(1, 10, factor);
+ contrast_limit_ = scalenorm(1, 10, factor);
}
-bool SMAAEdgeDetectionOperation::determineDependingAreaOfInterest(
- rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool SMAAEdgeDetectionOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
- newInput.xmax = input->xmax + 1;
- newInput.xmin = input->xmin - 2;
- newInput.ymax = input->ymax + 1;
- newInput.ymin = input->ymin - 2;
+ rcti new_input;
+ new_input.xmax = input->xmax + 1;
+ new_input.xmin = input->xmin - 2;
+ new_input.ymax = input->ymax + 1;
+ new_input.ymin = input->ymin - 2;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void SMAAEdgeDetectionOperation::get_area_of_interest(const int UNUSED(input_idx),
@@ -224,23 +223,23 @@ void SMAAEdgeDetectionOperation::get_area_of_interest(const int UNUSED(input_idx
r_input_area.ymin = output_area.ymin - 2;
}
-void SMAAEdgeDetectionOperation::executePixel(float output[4], int x, int y, void * /*data*/)
+void SMAAEdgeDetectionOperation::execute_pixel(float output[4], int x, int y, void * /*data*/)
{
float color[4];
/* Calculate luma deltas: */
- sample(m_imageReader, x, y, color);
+ sample(image_reader_, x, y, color);
float L = IMB_colormanagement_get_luminance(color);
- sample(m_imageReader, x - 1, y, color);
+ sample(image_reader_, x - 1, y, color);
float Lleft = IMB_colormanagement_get_luminance(color);
- sample(m_imageReader, x, y - 1, color);
+ sample(image_reader_, x, y - 1, color);
float Ltop = IMB_colormanagement_get_luminance(color);
float Dleft = fabsf(L - Lleft);
float Dtop = fabsf(L - Ltop);
/* We do the usual threshold: */
- output[0] = (x > 0 && Dleft >= m_threshold) ? 1.0f : 0.0f;
- output[1] = (y > 0 && Dtop >= m_threshold) ? 1.0f : 0.0f;
+ output[0] = (x > 0 && Dleft >= threshold_) ? 1.0f : 0.0f;
+ output[1] = (y > 0 && Dtop >= threshold_) ? 1.0f : 0.0f;
output[2] = 0.0f;
output[3] = 1.0f;
@@ -250,36 +249,36 @@ void SMAAEdgeDetectionOperation::executePixel(float output[4], int x, int y, voi
}
/* Calculate right and bottom deltas: */
- sample(m_imageReader, x + 1, y, color);
+ sample(image_reader_, x + 1, y, color);
float Lright = IMB_colormanagement_get_luminance(color);
- sample(m_imageReader, x, y + 1, color);
+ sample(image_reader_, x, y + 1, color);
float Lbottom = IMB_colormanagement_get_luminance(color);
float Dright = fabsf(L - Lright);
float Dbottom = fabsf(L - Lbottom);
/* Calculate the maximum delta in the direct neighborhood: */
- float maxDelta = fmaxf(fmaxf(Dleft, Dright), fmaxf(Dtop, Dbottom));
+ float max_delta = fmaxf(fmaxf(Dleft, Dright), fmaxf(Dtop, Dbottom));
/* Calculate luma used for both left and top edges: */
- sample(m_imageReader, x - 1, y - 1, color);
+ sample(image_reader_, x - 1, y - 1, color);
float Llefttop = IMB_colormanagement_get_luminance(color);
/* Left edge */
if (output[0] != 0.0f) {
/* Calculate deltas around the left pixel: */
- sample(m_imageReader, x - 2, y, color);
+ sample(image_reader_, x - 2, y, color);
float Lleftleft = IMB_colormanagement_get_luminance(color);
- sample(m_imageReader, x - 1, y + 1, color);
+ sample(image_reader_, x - 1, y + 1, color);
float Lleftbottom = IMB_colormanagement_get_luminance(color);
float Dleftleft = fabsf(Lleft - Lleftleft);
float Dlefttop = fabsf(Lleft - Llefttop);
float Dleftbottom = fabsf(Lleft - Lleftbottom);
/* Calculate the final maximum delta: */
- maxDelta = fmaxf(maxDelta, fmaxf(Dleftleft, fmaxf(Dlefttop, Dleftbottom)));
+ max_delta = fmaxf(max_delta, fmaxf(Dleftleft, fmaxf(Dlefttop, Dleftbottom)));
/* Local contrast adaptation: */
- if (maxDelta > m_contrast_limit * Dleft) {
+ if (max_delta > contrast_limit_ * Dleft) {
output[0] = 0.0f;
}
}
@@ -287,19 +286,19 @@ void SMAAEdgeDetectionOperation::executePixel(float output[4], int x, int y, voi
/* Top edge */
if (output[1] != 0.0f) {
/* Calculate top-top delta: */
- sample(m_imageReader, x, y - 2, color);
+ sample(image_reader_, x, y - 2, color);
float Ltoptop = IMB_colormanagement_get_luminance(color);
- sample(m_imageReader, x + 1, y - 1, color);
+ sample(image_reader_, x + 1, y - 1, color);
float Ltopright = IMB_colormanagement_get_luminance(color);
float Dtoptop = fabsf(Ltop - Ltoptop);
float Dtopleft = fabsf(Ltop - Llefttop);
float Dtopright = fabsf(Ltop - Ltopright);
/* Calculate the final maximum delta: */
- maxDelta = fmaxf(maxDelta, fmaxf(Dtoptop, fmaxf(Dtopleft, Dtopright)));
+ max_delta = fmaxf(max_delta, fmaxf(Dtoptop, fmaxf(Dtopleft, Dtopright)));
/* Local contrast adaptation: */
- if (maxDelta > m_contrast_limit * Dtop) {
+ if (max_delta > contrast_limit_ * Dtop) {
output[1] = 0.0f;
}
}
@@ -326,8 +325,8 @@ void SMAAEdgeDetectionOperation::update_memory_buffer_partial(MemoryBuffer *outp
const float Dtop = fabsf(L - Ltop);
/* We do the usual threshold: */
- it.out[0] = (x > 0 && Dleft >= m_threshold) ? 1.0f : 0.0f;
- it.out[1] = (y > 0 && Dtop >= m_threshold) ? 1.0f : 0.0f;
+ it.out[0] = (x > 0 && Dleft >= threshold_) ? 1.0f : 0.0f;
+ it.out[1] = (y > 0 && Dtop >= threshold_) ? 1.0f : 0.0f;
it.out[2] = 0.0f;
it.out[3] = 1.0f;
@@ -345,7 +344,7 @@ void SMAAEdgeDetectionOperation::update_memory_buffer_partial(MemoryBuffer *outp
const float Dbottom = fabsf(L - Lbottom);
/* Calculate the maximum delta in the direct neighborhood: */
- float maxDelta = fmaxf(fmaxf(Dleft, Dright), fmaxf(Dtop, Dbottom));
+ float max_delta = fmaxf(fmaxf(Dleft, Dright), fmaxf(Dtop, Dbottom));
/* Calculate luma used for both left and top edges: */
image->read_elem_checked(x - 1, y - 1, color);
@@ -363,10 +362,10 @@ void SMAAEdgeDetectionOperation::update_memory_buffer_partial(MemoryBuffer *outp
const float Dleftbottom = fabsf(Lleft - Lleftbottom);
/* Calculate the final maximum delta: */
- maxDelta = fmaxf(maxDelta, fmaxf(Dleftleft, fmaxf(Dlefttop, Dleftbottom)));
+ max_delta = fmaxf(max_delta, fmaxf(Dleftleft, fmaxf(Dlefttop, Dleftbottom)));
/* Local contrast adaptation: */
- if (maxDelta > m_contrast_limit * Dleft) {
+ if (max_delta > contrast_limit_ * Dleft) {
it.out[0] = 0.0f;
}
}
@@ -383,10 +382,10 @@ void SMAAEdgeDetectionOperation::update_memory_buffer_partial(MemoryBuffer *outp
const float Dtopright = fabsf(Ltop - Ltopright);
/* Calculate the final maximum delta: */
- maxDelta = fmaxf(maxDelta, fmaxf(Dtoptop, fmaxf(Dtopleft, Dtopright)));
+ max_delta = fmaxf(max_delta, fmaxf(Dtoptop, fmaxf(Dtopleft, Dtopright)));
/* Local contrast adaptation: */
- if (maxDelta > m_contrast_limit * Dtop) {
+ if (max_delta > contrast_limit_ * Dtop) {
it.out[1] = 0.0f;
}
}
@@ -399,47 +398,47 @@ void SMAAEdgeDetectionOperation::update_memory_buffer_partial(MemoryBuffer *outp
SMAABlendingWeightCalculationOperation::SMAABlendingWeightCalculationOperation()
{
- this->addInputSocket(DataType::Color); /* edges */
- this->addOutputSocket(DataType::Color);
- this->flags.complex = true;
- this->m_imageReader = nullptr;
- this->setCornerRounding(CMP_DEFAULT_SMAA_CORNER_ROUNDING);
+ this->add_input_socket(DataType::Color); /* edges */
+ this->add_output_socket(DataType::Color);
+ flags_.complex = true;
+ image_reader_ = nullptr;
+ this->set_corner_rounding(CMP_DEFAULT_SMAA_CORNER_ROUNDING);
}
-void *SMAABlendingWeightCalculationOperation::initializeTileData(rcti *rect)
+void *SMAABlendingWeightCalculationOperation::initialize_tile_data(rcti *rect)
{
- return getInputOperation(0)->initializeTileData(rect);
+ return get_input_operation(0)->initialize_tile_data(rect);
}
-void SMAABlendingWeightCalculationOperation::initExecution()
+void SMAABlendingWeightCalculationOperation::init_execution()
{
- this->m_imageReader = this->getInputSocketReader(0);
+ image_reader_ = this->get_input_socket_reader(0);
if (execution_model_ == eExecutionModel::Tiled) {
- sample_image_fn_ = [=](int x, int y, float *out) { sample(m_imageReader, x, y, out); };
+ sample_image_fn_ = [=](int x, int y, float *out) { sample(image_reader_, x, y, out); };
}
}
-void SMAABlendingWeightCalculationOperation::setCornerRounding(float rounding)
+void SMAABlendingWeightCalculationOperation::set_corner_rounding(float rounding)
{
/* UI values are between 0 and 1 for simplicity but algorithm expects values between 0 and 100 */
- m_corner_rounding = static_cast<int>(scalenorm(0, 100, rounding));
+ corner_rounding_ = static_cast<int>(scalenorm(0, 100, rounding));
}
-void SMAABlendingWeightCalculationOperation::executePixel(float output[4],
- int x,
- int y,
- void * /*data*/)
+void SMAABlendingWeightCalculationOperation::execute_pixel(float output[4],
+ int x,
+ int y,
+ void * /*data*/)
{
float edges[4], c[4];
zero_v4(output);
- sample(m_imageReader, x, y, edges);
+ sample(image_reader_, x, y, edges);
/* Edge at north */
if (edges[1] > 0.0f) {
/* Diagonals have both north and west edges, so calculating weights for them */
/* in one of the boundaries is enough. */
- calculateDiagWeights(x, y, edges, output);
+ calculate_diag_weights(x, y, edges, output);
/* We give priority to diagonals, so if we find a diagonal we skip. */
/* horizontal/vertical processing. */
@@ -448,25 +447,25 @@ void SMAABlendingWeightCalculationOperation::executePixel(float output[4],
}
/* Find the distance to the left and the right: */
- int left = searchXLeft(x, y);
- int right = searchXRight(x, y);
+ int left = search_xleft(x, y);
+ int right = search_xright(x, y);
int d1 = x - left, d2 = right - x;
/* Fetch the left and right crossing edges: */
int e1 = 0, e2 = 0;
- sample(m_imageReader, left, y - 1, c);
+ sample(image_reader_, left, y - 1, c);
if (c[0] > 0.0) {
e1 += 1;
}
- sample(m_imageReader, left, y, c);
+ sample(image_reader_, left, y, c);
if (c[0] > 0.0) {
e1 += 2;
}
- sample(m_imageReader, right + 1, y - 1, c);
+ sample(image_reader_, right + 1, y - 1, c);
if (c[0] > 0.0) {
e2 += 1;
}
- sample(m_imageReader, right + 1, y, c);
+ sample(image_reader_, right + 1, y, c);
if (c[0] > 0.0) {
e2 += 2;
}
@@ -476,38 +475,38 @@ void SMAABlendingWeightCalculationOperation::executePixel(float output[4],
area(d1, d2, e1, e2, output); /* R, G */
/* Fix corners: */
- if (m_corner_rounding) {
- detectHorizontalCornerPattern(output, left, right, y, d1, d2);
+ if (corner_rounding_) {
+ detect_horizontal_corner_pattern(output, left, right, y, d1, d2);
}
}
/* Edge at west */
if (edges[0] > 0.0f) {
/* Did we already do diagonal search for this west edge from the left neighboring pixel? */
- if (isVerticalSearchUnneeded(x, y)) {
+ if (is_vertical_search_unneeded(x, y)) {
return;
}
/* Find the distance to the top and the bottom: */
- int top = searchYUp(x, y);
- int bottom = searchYDown(x, y);
+ int top = search_yup(x, y);
+ int bottom = search_ydown(x, y);
int d1 = y - top, d2 = bottom - y;
/* Fetch the top and bottom crossing edges: */
int e1 = 0, e2 = 0;
- sample(m_imageReader, x - 1, top, c);
+ sample(image_reader_, x - 1, top, c);
if (c[1] > 0.0) {
e1 += 1;
}
- sample(m_imageReader, x, top, c);
+ sample(image_reader_, x, top, c);
if (c[1] > 0.0) {
e1 += 2;
}
- sample(m_imageReader, x - 1, bottom + 1, c);
+ sample(image_reader_, x - 1, bottom + 1, c);
if (c[1] > 0.0) {
e2 += 1;
}
- sample(m_imageReader, x, bottom + 1, c);
+ sample(image_reader_, x, bottom + 1, c);
if (c[1] > 0.0) {
e2 += 2;
}
@@ -516,8 +515,8 @@ void SMAABlendingWeightCalculationOperation::executePixel(float output[4],
area(d1, d2, e1, e2, output + 2); /* B, A */
/* Fix corners: */
- if (m_corner_rounding) {
- detectVerticalCornerPattern(output + 2, x, top, bottom, d1, d2);
+ if (corner_rounding_) {
+ detect_vertical_corner_pattern(output + 2, x, top, bottom, d1, d2);
}
}
}
@@ -545,7 +544,7 @@ void SMAABlendingWeightCalculationOperation::update_memory_buffer_partial(
if (edges[1] > 0.0f) {
/* Diagonals have both north and west edges, so calculating weights for them */
/* in one of the boundaries is enough. */
- calculateDiagWeights(x, y, edges, it.out);
+ calculate_diag_weights(x, y, edges, it.out);
/* We give priority to diagonals, so if we find a diagonal we skip. */
/* horizontal/vertical processing. */
@@ -554,8 +553,8 @@ void SMAABlendingWeightCalculationOperation::update_memory_buffer_partial(
}
/* Find the distance to the left and the right: */
- int left = searchXLeft(x, y);
- int right = searchXRight(x, y);
+ int left = search_xleft(x, y);
+ int right = search_xright(x, y);
int d1 = x - left, d2 = right - x;
/* Fetch the left and right crossing edges: */
@@ -582,21 +581,21 @@ void SMAABlendingWeightCalculationOperation::update_memory_buffer_partial(
area(d1, d2, e1, e2, it.out); /* R, G */
/* Fix corners: */
- if (m_corner_rounding) {
- detectHorizontalCornerPattern(it.out, left, right, y, d1, d2);
+ if (corner_rounding_) {
+ detect_horizontal_corner_pattern(it.out, left, right, y, d1, d2);
}
}
/* Edge at west */
if (edges[0] > 0.0f) {
/* Did we already do diagonal search for this west edge from the left neighboring pixel? */
- if (isVerticalSearchUnneeded(x, y)) {
+ if (is_vertical_search_unneeded(x, y)) {
continue;
}
/* Find the distance to the top and the bottom: */
- int top = searchYUp(x, y);
- int bottom = searchYDown(x, y);
+ int top = search_yup(x, y);
+ int bottom = search_ydown(x, y);
int d1 = y - top, d2 = bottom - y;
/* Fetch the top and bottom crossing edges: */
@@ -622,31 +621,31 @@ void SMAABlendingWeightCalculationOperation::update_memory_buffer_partial(
area(d1, d2, e1, e2, it.out + 2); /* B, A */
/* Fix corners: */
- if (m_corner_rounding) {
- detectVerticalCornerPattern(it.out + 2, x, top, bottom, d1, d2);
+ if (corner_rounding_) {
+ detect_vertical_corner_pattern(it.out + 2, x, top, bottom, d1, d2);
}
}
}
}
-void SMAABlendingWeightCalculationOperation::deinitExecution()
+void SMAABlendingWeightCalculationOperation::deinit_execution()
{
- this->m_imageReader = nullptr;
+ image_reader_ = nullptr;
}
-bool SMAABlendingWeightCalculationOperation::determineDependingAreaOfInterest(
- rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool SMAABlendingWeightCalculationOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
+ rcti new_input;
- newInput.xmax = input->xmax + fmax(SMAA_MAX_SEARCH_STEPS, SMAA_MAX_SEARCH_STEPS_DIAG + 1);
- newInput.xmin = input->xmin -
- fmax(fmax(SMAA_MAX_SEARCH_STEPS - 1, 1), SMAA_MAX_SEARCH_STEPS_DIAG + 1);
- newInput.ymax = input->ymax + fmax(SMAA_MAX_SEARCH_STEPS, SMAA_MAX_SEARCH_STEPS_DIAG);
- newInput.ymin = input->ymin -
- fmax(fmax(SMAA_MAX_SEARCH_STEPS - 1, 1), SMAA_MAX_SEARCH_STEPS_DIAG);
+ new_input.xmax = input->xmax + fmax(SMAA_MAX_SEARCH_STEPS, SMAA_MAX_SEARCH_STEPS_DIAG + 1);
+ new_input.xmin = input->xmin -
+ fmax(fmax(SMAA_MAX_SEARCH_STEPS - 1, 1), SMAA_MAX_SEARCH_STEPS_DIAG + 1);
+ new_input.ymax = input->ymax + fmax(SMAA_MAX_SEARCH_STEPS, SMAA_MAX_SEARCH_STEPS_DIAG);
+ new_input.ymin = input->ymin -
+ fmax(fmax(SMAA_MAX_SEARCH_STEPS - 1, 1), SMAA_MAX_SEARCH_STEPS_DIAG);
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void SMAABlendingWeightCalculationOperation::get_area_of_interest(const int UNUSED(input_idx),
@@ -665,10 +664,7 @@ void SMAABlendingWeightCalculationOperation::get_area_of_interest(const int UNUS
/*-----------------------------------------------------------------------------*/
/* Diagonal Search Functions */
-/**
- * These functions allows to perform diagonal pattern searches.
- */
-int SMAABlendingWeightCalculationOperation::searchDiag1(int x, int y, int dir, bool *found)
+int SMAABlendingWeightCalculationOperation::search_diag1(int x, int y, int dir, bool *found)
{
float e[4];
int end = x + SMAA_MAX_SEARCH_STEPS_DIAG * dir;
@@ -691,7 +687,7 @@ int SMAABlendingWeightCalculationOperation::searchDiag1(int x, int y, int dir, b
return x - dir;
}
-int SMAABlendingWeightCalculationOperation::searchDiag2(int x, int y, int dir, bool *found)
+int SMAABlendingWeightCalculationOperation::search_diag2(int x, int y, int dir, bool *found)
{
float e[4];
int end = x + SMAA_MAX_SEARCH_STEPS_DIAG * dir;
@@ -715,13 +711,10 @@ int SMAABlendingWeightCalculationOperation::searchDiag2(int x, int y, int dir, b
return x - dir;
}
-/**
- * This searches for diagonal patterns and returns the corresponding weights.
- */
-void SMAABlendingWeightCalculationOperation::calculateDiagWeights(int x,
- int y,
- const float edges[2],
- float weights[2])
+void SMAABlendingWeightCalculationOperation::calculate_diag_weights(int x,
+ int y,
+ const float edges[2],
+ float weights[2])
{
int d1, d2;
bool d1_found, d2_found;
@@ -735,13 +728,13 @@ void SMAABlendingWeightCalculationOperation::calculateDiagWeights(int x,
/* Search for the line ends: */
if (edges[0] > 0.0f) {
- d1 = x - searchDiag1(x, y, -1, &d1_found);
+ d1 = x - search_diag1(x, y, -1, &d1_found);
}
else {
d1 = 0;
d1_found = true;
}
- d2 = searchDiag1(x, y, 1, &d2_found) - x;
+ d2 = search_diag1(x, y, 1, &d2_found) - x;
if (d1 + d2 > 2) { /* d1 + d2 + 1 > 3 */
int e1 = 0, e2 = 0;
@@ -779,10 +772,10 @@ void SMAABlendingWeightCalculationOperation::calculateDiagWeights(int x,
}
/* Search for the line ends: */
- d1 = x - searchDiag2(x, y, -1, &d1_found);
+ d1 = x - search_diag2(x, y, -1, &d1_found);
sample_image_fn_(x + 1, y, e);
if (e[0] > 0.0f) {
- d2 = searchDiag2(x, y, 1, &d2_found) - x;
+ d2 = search_diag2(x, y, 1, &d2_found) - x;
}
else {
d2 = 0;
@@ -827,7 +820,7 @@ void SMAABlendingWeightCalculationOperation::calculateDiagWeights(int x,
}
}
-bool SMAABlendingWeightCalculationOperation::isVerticalSearchUnneeded(int x, int y)
+bool SMAABlendingWeightCalculationOperation::is_vertical_search_unneeded(int x, int y)
{
int d1, d2;
bool found;
@@ -840,12 +833,12 @@ bool SMAABlendingWeightCalculationOperation::isVerticalSearchUnneeded(int x, int
/* Search for the line ends: */
sample_image_fn_(x - 1, y, e);
if (e[1] > 0.0f) {
- d1 = x - searchDiag2(x - 1, y, -1, &found);
+ d1 = x - search_diag2(x - 1, y, -1, &found);
}
else {
d1 = 0;
}
- d2 = searchDiag2(x - 1, y, 1, &found) - x;
+ d2 = search_diag2(x - 1, y, 1, &found) - x;
return (d1 + d2 > 2); /* d1 + d2 + 1 > 3 */
}
@@ -853,7 +846,7 @@ bool SMAABlendingWeightCalculationOperation::isVerticalSearchUnneeded(int x, int
/*-----------------------------------------------------------------------------*/
/* Horizontal/Vertical Search Functions */
-int SMAABlendingWeightCalculationOperation::searchXLeft(int x, int y)
+int SMAABlendingWeightCalculationOperation::search_xleft(int x, int y)
{
int end = x - SMAA_MAX_SEARCH_STEPS;
float e[4];
@@ -876,7 +869,7 @@ int SMAABlendingWeightCalculationOperation::searchXLeft(int x, int y)
return x + 1;
}
-int SMAABlendingWeightCalculationOperation::searchXRight(int x, int y)
+int SMAABlendingWeightCalculationOperation::search_xright(int x, int y)
{
int end = x + SMAA_MAX_SEARCH_STEPS;
float e[4];
@@ -897,7 +890,7 @@ int SMAABlendingWeightCalculationOperation::searchXRight(int x, int y)
return x - 1;
}
-int SMAABlendingWeightCalculationOperation::searchYUp(int x, int y)
+int SMAABlendingWeightCalculationOperation::search_yup(int x, int y)
{
int end = y - SMAA_MAX_SEARCH_STEPS;
float e[4];
@@ -920,7 +913,7 @@ int SMAABlendingWeightCalculationOperation::searchYUp(int x, int y)
return y + 1;
}
-int SMAABlendingWeightCalculationOperation::searchYDown(int x, int y)
+int SMAABlendingWeightCalculationOperation::search_ydown(int x, int y)
{
int end = y + SMAA_MAX_SEARCH_STEPS;
float e[4];
@@ -944,11 +937,11 @@ int SMAABlendingWeightCalculationOperation::searchYDown(int x, int y)
/*-----------------------------------------------------------------------------*/
/* Corner Detection Functions */
-void SMAABlendingWeightCalculationOperation::detectHorizontalCornerPattern(
+void SMAABlendingWeightCalculationOperation::detect_horizontal_corner_pattern(
float weights[2], int left, int right, int y, int d1, int d2)
{
float factor[2] = {1.0f, 1.0f};
- float rounding = m_corner_rounding / 100.0f;
+ float rounding = corner_rounding_ / 100.0f;
float e[4];
/* Reduce blending for pixels in the center of a line. */
@@ -973,11 +966,11 @@ void SMAABlendingWeightCalculationOperation::detectHorizontalCornerPattern(
weights[1] *= CLAMPIS(factor[1], 0.0f, 1.0f);
}
-void SMAABlendingWeightCalculationOperation::detectVerticalCornerPattern(
+void SMAABlendingWeightCalculationOperation::detect_vertical_corner_pattern(
float weights[2], int x, int top, int bottom, int d1, int d2)
{
float factor[2] = {1.0f, 1.0f};
- float rounding = m_corner_rounding / 100.0f;
+ float rounding = corner_rounding_ / 100.0f;
float e[4];
/* Reduce blending for pixels in the center of a line. */
@@ -1008,43 +1001,43 @@ void SMAABlendingWeightCalculationOperation::detectVerticalCornerPattern(
SMAANeighborhoodBlendingOperation::SMAANeighborhoodBlendingOperation()
{
- this->addInputSocket(DataType::Color); /* image */
- this->addInputSocket(DataType::Color); /* blend */
- this->addOutputSocket(DataType::Color);
- this->flags.complex = true;
- this->m_image1Reader = nullptr;
- this->m_image2Reader = nullptr;
+ this->add_input_socket(DataType::Color); /* image */
+ this->add_input_socket(DataType::Color); /* blend */
+ this->add_output_socket(DataType::Color);
+ flags_.complex = true;
+ image1Reader_ = nullptr;
+ image2Reader_ = nullptr;
}
-void *SMAANeighborhoodBlendingOperation::initializeTileData(rcti *rect)
+void *SMAANeighborhoodBlendingOperation::initialize_tile_data(rcti *rect)
{
- return getInputOperation(0)->initializeTileData(rect);
+ return get_input_operation(0)->initialize_tile_data(rect);
}
-void SMAANeighborhoodBlendingOperation::initExecution()
+void SMAANeighborhoodBlendingOperation::init_execution()
{
- this->m_image1Reader = this->getInputSocketReader(0);
- this->m_image2Reader = this->getInputSocketReader(1);
+ image1Reader_ = this->get_input_socket_reader(0);
+ image2Reader_ = this->get_input_socket_reader(1);
}
-void SMAANeighborhoodBlendingOperation::executePixel(float output[4],
- int x,
- int y,
- void * /*data*/)
+void SMAANeighborhoodBlendingOperation::execute_pixel(float output[4],
+ int x,
+ int y,
+ void * /*data*/)
{
float w[4];
/* Fetch the blending weights for current pixel: */
- sample(m_image2Reader, x, y, w);
+ sample(image2Reader_, x, y, w);
float left = w[2], top = w[0];
- sample(m_image2Reader, x + 1, y, w);
+ sample(image2Reader_, x + 1, y, w);
float right = w[3];
- sample(m_image2Reader, x, y + 1, w);
+ sample(image2Reader_, x, y + 1, w);
float bottom = w[1];
/* Is there any blending weight with a value greater than 0.0? */
if (right + bottom + left + top < 1e-5f) {
- sample(m_image1Reader, x, y, output);
+ sample(image1Reader_, x, y, output);
return;
}
@@ -1068,8 +1061,8 @@ void SMAANeighborhoodBlendingOperation::executePixel(float output[4],
}
/* We exploit bilinear filtering to mix current pixel with the chosen neighbor: */
- samplefunc(m_image1Reader, x, y, offset1, color1);
- samplefunc(m_image1Reader, x, y, offset2, color2);
+ samplefunc(image1Reader_, x, y, offset1, color1);
+ samplefunc(image1Reader_, x, y, offset2, color2);
mul_v4_v4fl(output, color1, weight1);
madd_v4_v4fl(output, color2, weight2);
@@ -1128,23 +1121,23 @@ void SMAANeighborhoodBlendingOperation::update_memory_buffer_partial(MemoryBuffe
}
}
-void SMAANeighborhoodBlendingOperation::deinitExecution()
+void SMAANeighborhoodBlendingOperation::deinit_execution()
{
- this->m_image1Reader = nullptr;
- this->m_image2Reader = nullptr;
+ image1Reader_ = nullptr;
+ image2Reader_ = nullptr;
}
-bool SMAANeighborhoodBlendingOperation::determineDependingAreaOfInterest(
- rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool SMAANeighborhoodBlendingOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
+ rcti new_input;
- newInput.xmax = input->xmax + 1;
- newInput.xmin = input->xmin - 1;
- newInput.ymax = input->ymax + 1;
- newInput.ymin = input->ymin - 1;
+ new_input.xmax = input->xmax + 1;
+ new_input.xmin = input->xmin - 1;
+ new_input.ymax = input->ymax + 1;
+ new_input.ymin = input->ymin - 1;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void SMAANeighborhoodBlendingOperation::get_area_of_interest(const int UNUSED(input_idx),
diff --git a/source/blender/compositor/operations/COM_SMAAOperation.h b/source/blender/compositor/operations/COM_SMAAOperation.h
index 91b9299ee43..ec04594e0aa 100644
--- a/source/blender/compositor/operations/COM_SMAAOperation.h
+++ b/source/blender/compositor/operations/COM_SMAAOperation.h
@@ -29,11 +29,11 @@ namespace blender::compositor {
class SMAAEdgeDetectionOperation : public MultiThreadedOperation {
protected:
- SocketReader *m_imageReader;
- SocketReader *m_valueReader;
+ SocketReader *image_reader_;
+ SocketReader *value_reader_;
- float m_threshold;
- float m_contrast_limit;
+ float threshold_;
+ float contrast_limit_;
public:
SMAAEdgeDetectionOperation();
@@ -41,25 +41,25 @@ class SMAAEdgeDetectionOperation : public MultiThreadedOperation {
/**
* the inner loop of this program
*/
- virtual void executePixel(float output[4], int x, int y, void *data) override;
+ virtual void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setThreshold(float threshold);
+ void set_threshold(float threshold);
- void setLocalContrastAdaptationFactor(float factor);
+ void set_local_contrast_adaptation_factor(float factor);
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
@@ -72,9 +72,9 @@ class SMAAEdgeDetectionOperation : public MultiThreadedOperation {
class SMAABlendingWeightCalculationOperation : public MultiThreadedOperation {
private:
- SocketReader *m_imageReader;
+ SocketReader *image_reader_;
std::function<void(int x, int y, float *out)> sample_image_fn_;
- int m_corner_rounding;
+ int corner_rounding_;
public:
SMAABlendingWeightCalculationOperation();
@@ -82,24 +82,24 @@ class SMAABlendingWeightCalculationOperation : public MultiThreadedOperation {
/**
* the inner loop of this program
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
- void *initializeTileData(rcti *rect) override;
+ void init_execution() override;
+ void *initialize_tile_data(rcti *rect) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setCornerRounding(float rounding);
+ void set_corner_rounding(float rounding);
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_started(MemoryBuffer *output,
@@ -111,20 +111,28 @@ class SMAABlendingWeightCalculationOperation : public MultiThreadedOperation {
private:
/* Diagonal Search Functions */
- int searchDiag1(int x, int y, int dir, bool *found);
- int searchDiag2(int x, int y, int dir, bool *found);
- void calculateDiagWeights(int x, int y, const float edges[2], float weights[2]);
- bool isVerticalSearchUnneeded(int x, int y);
+ /**
+ * These functions allows to perform diagonal pattern searches.
+ */
+ int search_diag1(int x, int y, int dir, bool *found);
+ int search_diag2(int x, int y, int dir, bool *found);
+ /**
+ * This searches for diagonal patterns and returns the corresponding weights.
+ */
+ void calculate_diag_weights(int x, int y, const float edges[2], float weights[2]);
+ bool is_vertical_search_unneeded(int x, int y);
/* Horizontal/Vertical Search Functions */
- int searchXLeft(int x, int y);
- int searchXRight(int x, int y);
- int searchYUp(int x, int y);
- int searchYDown(int x, int y);
+ int search_xleft(int x, int y);
+ int search_xright(int x, int y);
+ int search_yup(int x, int y);
+ int search_ydown(int x, int y);
/* Corner Detection Functions */
- void detectHorizontalCornerPattern(float weights[2], int left, int right, int y, int d1, int d2);
- void detectVerticalCornerPattern(float weights[2], int x, int top, int bottom, int d1, int d2);
+ void detect_horizontal_corner_pattern(
+ float weights[2], int left, int right, int y, int d1, int d2);
+ void detect_vertical_corner_pattern(
+ float weights[2], int x, int top, int bottom, int d1, int d2);
};
/*-----------------------------------------------------------------------------*/
@@ -132,8 +140,8 @@ class SMAABlendingWeightCalculationOperation : public MultiThreadedOperation {
class SMAANeighborhoodBlendingOperation : public MultiThreadedOperation {
private:
- SocketReader *m_image1Reader;
- SocketReader *m_image2Reader;
+ SocketReader *image1Reader_;
+ SocketReader *image2Reader_;
public:
SMAANeighborhoodBlendingOperation();
@@ -141,22 +149,22 @@ class SMAANeighborhoodBlendingOperation : public MultiThreadedOperation {
/**
* the inner loop of this program
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
- void *initializeTileData(rcti *rect) override;
+ void init_execution() override;
+ void *initialize_tile_data(rcti *rect) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cc b/source/blender/compositor/operations/COM_ScaleOperation.cc
index dbd8faf0f1d..281087bb4c7 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.cc
+++ b/source/blender/compositor/operations/COM_ScaleOperation.cc
@@ -31,11 +31,11 @@ namespace blender::compositor {
BaseScaleOperation::BaseScaleOperation()
{
#ifdef USE_FORCE_BILINEAR
- m_sampler = (int)PixelSampler::Bilinear;
+ sampler_ = (int)PixelSampler::Bilinear;
#else
- m_sampler = -1;
+ sampler_ = -1;
#endif
- m_variable_size = false;
+ variable_size_ = false;
}
void BaseScaleOperation::set_scale_canvas_max_size(Size2f size)
@@ -49,20 +49,21 @@ ScaleOperation::ScaleOperation() : ScaleOperation(DataType::Color)
ScaleOperation::ScaleOperation(DataType data_type) : BaseScaleOperation()
{
- this->addInputSocket(data_type, ResizeMode::None);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(data_type);
- this->m_inputOperation = nullptr;
- this->m_inputXOperation = nullptr;
- this->m_inputYOperation = nullptr;
+ this->add_input_socket(data_type, ResizeMode::None);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(data_type);
+ input_operation_ = nullptr;
+ input_xoperation_ = nullptr;
+ input_yoperation_ = nullptr;
}
float ScaleOperation::get_constant_scale(const int input_op_idx, const float factor)
{
- const bool is_constant = getInputOperation(input_op_idx)->get_flags().is_constant_operation;
+ const bool is_constant = get_input_operation(input_op_idx)->get_flags().is_constant_operation;
if (is_constant) {
- return ((ConstantOperation *)getInputOperation(input_op_idx))->get_constant_elem()[0] * factor;
+ return ((ConstantOperation *)get_input_operation(input_op_idx))->get_constant_elem()[0] *
+ factor;
}
return 1.0f;
@@ -112,22 +113,22 @@ void ScaleOperation::clamp_area_size_max(rcti &area, Size2f max_size)
void ScaleOperation::init_data()
{
- canvas_center_x_ = canvas_.xmin + getWidth() / 2.0f;
- canvas_center_y_ = canvas_.ymin + getHeight() / 2.0f;
+ canvas_center_x_ = canvas_.xmin + get_width() / 2.0f;
+ canvas_center_y_ = canvas_.ymin + get_height() / 2.0f;
}
-void ScaleOperation::initExecution()
+void ScaleOperation::init_execution()
{
- this->m_inputOperation = this->getInputSocketReader(0);
- this->m_inputXOperation = this->getInputSocketReader(1);
- this->m_inputYOperation = this->getInputSocketReader(2);
+ input_operation_ = this->get_input_socket_reader(0);
+ input_xoperation_ = this->get_input_socket_reader(1);
+ input_yoperation_ = this->get_input_socket_reader(2);
}
-void ScaleOperation::deinitExecution()
+void ScaleOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
- this->m_inputXOperation = nullptr;
- this->m_inputYOperation = nullptr;
+ input_operation_ = nullptr;
+ input_xoperation_ = nullptr;
+ input_yoperation_ = nullptr;
}
void ScaleOperation::get_scale_offset(const rcti &input_canvas,
@@ -171,12 +172,12 @@ void ScaleOperation::get_area_of_interest(const int input_idx,
}
NodeOperation *image_op = get_input_operation(IMAGE_INPUT_INDEX);
- const float scale_x = get_constant_scale_x(image_op->getWidth());
- const float scale_y = get_constant_scale_y(image_op->getHeight());
+ const float scale_x = get_constant_scale_x(image_op->get_width());
+ const float scale_y = get_constant_scale_y(image_op->get_height());
get_scale_area_of_interest(
image_op->get_canvas(), this->get_canvas(), scale_x, scale_y, output_area, r_input_area);
- expand_area_for_sampler(r_input_area, (PixelSampler)m_sampler);
+ expand_area_for_sampler(r_input_area, (PixelSampler)sampler_);
}
void ScaleOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -184,8 +185,8 @@ void ScaleOperation::update_memory_buffer_partial(MemoryBuffer *output,
Span<MemoryBuffer *> inputs)
{
NodeOperation *input_image_op = get_input_operation(IMAGE_INPUT_INDEX);
- const int input_image_width = input_image_op->getWidth();
- const int input_image_height = input_image_op->getHeight();
+ const int input_image_width = input_image_op->get_width();
+ const int input_image_height = input_image_op->get_height();
const float scale_x_factor = get_relative_scale_x_factor(input_image_width);
const float scale_y_factor = get_relative_scale_y_factor(input_image_height);
const float scale_center_x = input_image_width / 2.0f;
@@ -207,7 +208,7 @@ void ScaleOperation::update_memory_buffer_partial(MemoryBuffer *output,
from_scale_offset_y + canvas_.ymin + it.y, scale_center_y, rel_scale_y);
input_image->read_elem_sampled(
- scaled_x - canvas_.xmin, scaled_y - canvas_.ymin, (PixelSampler)m_sampler, it.out);
+ scaled_x - canvas_.xmin, scaled_y - canvas_.ymin, (PixelSampler)sampler_, it.out);
}
}
@@ -219,12 +220,12 @@ void ScaleOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
}
const bool image_determined =
- getInputSocket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
+ get_input_socket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
if (image_determined) {
rcti image_canvas = r_area;
- rcti unused;
- NodeOperationInput *x_socket = getInputSocket(X_INPUT_INDEX);
- NodeOperationInput *y_socket = getInputSocket(Y_INPUT_INDEX);
+ rcti unused = COM_AREA_NONE;
+ NodeOperationInput *x_socket = get_input_socket(X_INPUT_INDEX);
+ NodeOperationInput *y_socket = get_input_socket(Y_INPUT_INDEX);
x_socket->determine_canvas(image_canvas, unused);
y_socket->determine_canvas(image_canvas, unused);
if (is_scaling_variable()) {
@@ -258,266 +259,264 @@ ScaleRelativeOperation::ScaleRelativeOperation(DataType data_type) : ScaleOperat
{
}
-void ScaleRelativeOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ScaleRelativeOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- PixelSampler effective_sampler = getEffectiveSampler(sampler);
+ PixelSampler effective_sampler = get_effective_sampler(sampler);
float scaleX[4];
float scaleY[4];
- this->m_inputXOperation->readSampled(scaleX, x, y, effective_sampler);
- this->m_inputYOperation->readSampled(scaleY, x, y, effective_sampler);
+ input_xoperation_->read_sampled(scaleX, x, y, effective_sampler);
+ input_yoperation_->read_sampled(scaleY, x, y, effective_sampler);
const float scx = scaleX[0];
const float scy = scaleY[0];
float nx = this->canvas_center_x_ + (x - this->canvas_center_x_) / scx;
float ny = this->canvas_center_y_ + (y - this->canvas_center_y_) / scy;
- this->m_inputOperation->readSampled(output, nx, ny, effective_sampler);
+ input_operation_->read_sampled(output, nx, ny, effective_sampler);
}
-bool ScaleRelativeOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool ScaleRelativeOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
- if (!m_variable_size) {
+ rcti new_input;
+ if (!variable_size_) {
float scaleX[4];
float scaleY[4];
- this->m_inputXOperation->readSampled(scaleX, 0, 0, PixelSampler::Nearest);
- this->m_inputYOperation->readSampled(scaleY, 0, 0, PixelSampler::Nearest);
+ input_xoperation_->read_sampled(scaleX, 0, 0, PixelSampler::Nearest);
+ input_yoperation_->read_sampled(scaleY, 0, 0, PixelSampler::Nearest);
const float scx = scaleX[0];
const float scy = scaleY[0];
- newInput.xmax = this->canvas_center_x_ + (input->xmax - this->canvas_center_x_) / scx + 1;
- newInput.xmin = this->canvas_center_x_ + (input->xmin - this->canvas_center_x_) / scx - 1;
- newInput.ymax = this->canvas_center_y_ + (input->ymax - this->canvas_center_y_) / scy + 1;
- newInput.ymin = this->canvas_center_y_ + (input->ymin - this->canvas_center_y_) / scy - 1;
+ new_input.xmax = this->canvas_center_x_ + (input->xmax - this->canvas_center_x_) / scx + 1;
+ new_input.xmin = this->canvas_center_x_ + (input->xmin - this->canvas_center_x_) / scx - 1;
+ new_input.ymax = this->canvas_center_y_ + (input->ymax - this->canvas_center_y_) / scy + 1;
+ new_input.ymin = this->canvas_center_y_ + (input->ymin - this->canvas_center_y_) / scy - 1;
}
else {
- newInput.xmax = this->getWidth();
- newInput.xmin = 0;
- newInput.ymax = this->getHeight();
- newInput.ymin = 0;
+ new_input.xmax = this->get_width();
+ new_input.xmin = 0;
+ new_input.ymax = this->get_height();
+ new_input.ymin = 0;
}
- return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return BaseScaleOperation::determine_depending_area_of_interest(
+ &new_input, read_operation, output);
}
-void ScaleAbsoluteOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ScaleAbsoluteOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- PixelSampler effective_sampler = getEffectiveSampler(sampler);
+ PixelSampler effective_sampler = get_effective_sampler(sampler);
float scaleX[4];
float scaleY[4];
- this->m_inputXOperation->readSampled(scaleX, x, y, effective_sampler);
- this->m_inputYOperation->readSampled(scaleY, x, y, effective_sampler);
+ input_xoperation_->read_sampled(scaleX, x, y, effective_sampler);
+ input_yoperation_->read_sampled(scaleY, x, y, effective_sampler);
const float scx = scaleX[0]; /* Target absolute scale. */
const float scy = scaleY[0]; /* Target absolute scale. */
- const float width = this->getWidth();
- const float height = this->getHeight();
+ const float width = this->get_width();
+ const float height = this->get_height();
/* Divide. */
- float relativeXScale = scx / width;
- float relativeYScale = scy / height;
+ float relative_xscale = scx / width;
+ float relative_yscale = scy / height;
- float nx = this->canvas_center_x_ + (x - this->canvas_center_x_) / relativeXScale;
- float ny = this->canvas_center_y_ + (y - this->canvas_center_y_) / relativeYScale;
+ float nx = this->canvas_center_x_ + (x - this->canvas_center_x_) / relative_xscale;
+ float ny = this->canvas_center_y_ + (y - this->canvas_center_y_) / relative_yscale;
- this->m_inputOperation->readSampled(output, nx, ny, effective_sampler);
+ input_operation_->read_sampled(output, nx, ny, effective_sampler);
}
-bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool ScaleAbsoluteOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
- if (!m_variable_size) {
+ rcti new_input;
+ if (!variable_size_) {
float scaleX[4];
float scaleY[4];
- this->m_inputXOperation->readSampled(scaleX, 0, 0, PixelSampler::Nearest);
- this->m_inputYOperation->readSampled(scaleY, 0, 0, PixelSampler::Nearest);
+ input_xoperation_->read_sampled(scaleX, 0, 0, PixelSampler::Nearest);
+ input_yoperation_->read_sampled(scaleY, 0, 0, PixelSampler::Nearest);
const float scx = scaleX[0];
const float scy = scaleY[0];
- const float width = this->getWidth();
- const float height = this->getHeight();
+ const float width = this->get_width();
+ const float height = this->get_height();
/* Divide. */
- float relateveXScale = scx / width;
- float relateveYScale = scy / height;
-
- newInput.xmax = this->canvas_center_x_ +
- (input->xmax - this->canvas_center_x_) / relateveXScale;
- newInput.xmin = this->canvas_center_x_ +
- (input->xmin - this->canvas_center_x_) / relateveXScale;
- newInput.ymax = this->canvas_center_y_ +
- (input->ymax - this->canvas_center_y_) / relateveYScale;
- newInput.ymin = this->canvas_center_y_ +
- (input->ymin - this->canvas_center_y_) / relateveYScale;
+ float relateve_xscale = scx / width;
+ float relateve_yscale = scy / height;
+
+ new_input.xmax = this->canvas_center_x_ +
+ (input->xmax - this->canvas_center_x_) / relateve_xscale;
+ new_input.xmin = this->canvas_center_x_ +
+ (input->xmin - this->canvas_center_x_) / relateve_xscale;
+ new_input.ymax = this->canvas_center_y_ +
+ (input->ymax - this->canvas_center_y_) / relateve_yscale;
+ new_input.ymin = this->canvas_center_y_ +
+ (input->ymin - this->canvas_center_y_) / relateve_yscale;
}
else {
- newInput.xmax = this->getWidth();
- newInput.xmin = 0;
- newInput.ymax = this->getHeight();
- newInput.ymin = 0;
+ new_input.xmax = this->get_width();
+ new_input.xmin = 0;
+ new_input.ymax = this->get_height();
+ new_input.ymin = 0;
}
- return ScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return ScaleOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
-/* Absolute fixed size. */
ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation()
{
- this->addInputSocket(DataType::Color, ResizeMode::None);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color, ResizeMode::None);
+ this->add_output_socket(DataType::Color);
this->set_canvas_input_index(0);
- this->m_inputOperation = nullptr;
- this->m_is_offset = false;
+ input_operation_ = nullptr;
+ is_offset_ = false;
}
void ScaleFixedSizeOperation::init_data(const rcti &input_canvas)
{
const int input_width = BLI_rcti_size_x(&input_canvas);
const int input_height = BLI_rcti_size_y(&input_canvas);
- this->m_relX = input_width / (float)this->m_newWidth;
- this->m_relY = input_height / (float)this->m_newHeight;
+ rel_x_ = input_width / (float)new_width_;
+ rel_y_ = input_height / (float)new_height_;
/* *** all the options below are for a fairly special case - camera framing *** */
- if (this->m_offsetX != 0.0f || this->m_offsetY != 0.0f) {
- this->m_is_offset = true;
+ if (offset_x_ != 0.0f || offset_y_ != 0.0f) {
+ is_offset_ = true;
- if (this->m_newWidth > this->m_newHeight) {
- this->m_offsetX *= this->m_newWidth;
- this->m_offsetY *= this->m_newWidth;
+ if (new_width_ > new_height_) {
+ offset_x_ *= new_width_;
+ offset_y_ *= new_width_;
}
else {
- this->m_offsetX *= this->m_newHeight;
- this->m_offsetY *= this->m_newHeight;
+ offset_x_ *= new_height_;
+ offset_y_ *= new_height_;
}
}
- if (this->m_is_aspect) {
+ if (is_aspect_) {
/* apply aspect from clip */
const float w_src = input_width;
const float h_src = input_height;
/* destination aspect is already applied from the camera frame */
- const float w_dst = this->m_newWidth;
- const float h_dst = this->m_newHeight;
+ const float w_dst = new_width_;
+ const float h_dst = new_height_;
const float asp_src = w_src / h_src;
const float asp_dst = w_dst / h_dst;
if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) {
- if ((asp_src > asp_dst) == (this->m_is_crop == true)) {
+ if ((asp_src > asp_dst) == (is_crop_ == true)) {
/* fit X */
const float div = asp_src / asp_dst;
- this->m_relX /= div;
- this->m_offsetX += ((w_src - (w_src * div)) / (w_src / w_dst)) / 2.0f;
- if (m_is_crop && execution_model_ == eExecutionModel::FullFrame) {
- int fit_width = m_newWidth * div;
+ rel_x_ /= div;
+ offset_x_ += ((w_src - (w_src * div)) / (w_src / w_dst)) / 2.0f;
+ if (is_crop_ && execution_model_ == eExecutionModel::FullFrame) {
+ int fit_width = new_width_ * div;
if (fit_width > max_scale_canvas_size_.x) {
fit_width = max_scale_canvas_size_.x;
}
- const int added_width = fit_width - m_newWidth;
- m_newWidth += added_width;
- m_offsetX += added_width / 2.0f;
+ const int added_width = fit_width - new_width_;
+ new_width_ += added_width;
+ offset_x_ += added_width / 2.0f;
}
}
else {
/* fit Y */
const float div = asp_dst / asp_src;
- this->m_relY /= div;
- this->m_offsetY += ((h_src - (h_src * div)) / (h_src / h_dst)) / 2.0f;
- if (m_is_crop && execution_model_ == eExecutionModel::FullFrame) {
- int fit_height = m_newHeight * div;
+ rel_y_ /= div;
+ offset_y_ += ((h_src - (h_src * div)) / (h_src / h_dst)) / 2.0f;
+ if (is_crop_ && execution_model_ == eExecutionModel::FullFrame) {
+ int fit_height = new_height_ * div;
if (fit_height > max_scale_canvas_size_.y) {
fit_height = max_scale_canvas_size_.y;
}
- const int added_height = fit_height - m_newHeight;
- m_newHeight += added_height;
- m_offsetY += added_height / 2.0f;
+ const int added_height = fit_height - new_height_;
+ new_height_ += added_height;
+ offset_y_ += added_height / 2.0f;
}
}
- this->m_is_offset = true;
+ is_offset_ = true;
}
}
/* *** end framing options *** */
}
-void ScaleFixedSizeOperation::initExecution()
+void ScaleFixedSizeOperation::init_execution()
{
- this->m_inputOperation = this->getInputSocketReader(0);
+ input_operation_ = this->get_input_socket_reader(0);
}
-void ScaleFixedSizeOperation::deinitExecution()
+void ScaleFixedSizeOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
+ input_operation_ = nullptr;
}
-void ScaleFixedSizeOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ScaleFixedSizeOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- PixelSampler effective_sampler = getEffectiveSampler(sampler);
+ PixelSampler effective_sampler = get_effective_sampler(sampler);
- if (this->m_is_offset) {
- float nx = ((x - this->m_offsetX) * this->m_relX);
- float ny = ((y - this->m_offsetY) * this->m_relY);
- this->m_inputOperation->readSampled(output, nx, ny, effective_sampler);
+ if (is_offset_) {
+ float nx = ((x - offset_x_) * rel_x_);
+ float ny = ((y - offset_y_) * rel_y_);
+ input_operation_->read_sampled(output, nx, ny, effective_sampler);
}
else {
- this->m_inputOperation->readSampled(
- output, x * this->m_relX, y * this->m_relY, effective_sampler);
+ input_operation_->read_sampled(output, x * rel_x_, y * rel_y_, effective_sampler);
}
}
-bool ScaleFixedSizeOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool ScaleFixedSizeOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
+ rcti new_input;
- newInput.xmax = (input->xmax - m_offsetX) * this->m_relX + 1;
- newInput.xmin = (input->xmin - m_offsetX) * this->m_relX;
- newInput.ymax = (input->ymax - m_offsetY) * this->m_relY + 1;
- newInput.ymin = (input->ymin - m_offsetY) * this->m_relY;
+ new_input.xmax = (input->xmax - offset_x_) * rel_x_ + 1;
+ new_input.xmin = (input->xmin - offset_x_) * rel_x_;
+ new_input.ymax = (input->ymax - offset_y_) * rel_y_ + 1;
+ new_input.ymin = (input->ymin - offset_y_) * rel_y_;
- return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return BaseScaleOperation::determine_depending_area_of_interest(
+ &new_input, read_operation, output);
}
void ScaleFixedSizeOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
rcti local_preferred = preferred_area;
- local_preferred.xmax = local_preferred.xmin + m_newWidth;
- local_preferred.ymax = local_preferred.ymin + m_newHeight;
- rcti input_canvas;
- const bool input_determined = getInputSocket(0)->determine_canvas(local_preferred, input_canvas);
+ local_preferred.xmax = local_preferred.xmin + new_width_;
+ local_preferred.ymax = local_preferred.ymin + new_height_;
+ rcti input_canvas = COM_AREA_NONE;
+ const bool input_determined = get_input_socket(0)->determine_canvas(local_preferred,
+ input_canvas);
if (input_determined) {
init_data(input_canvas);
r_area = input_canvas;
if (execution_model_ == eExecutionModel::FullFrame) {
- r_area.xmin /= m_relX;
- r_area.ymin /= m_relY;
- r_area.xmin += m_offsetX;
- r_area.ymin += m_offsetY;
+ r_area.xmin /= rel_x_;
+ r_area.ymin /= rel_y_;
+ r_area.xmin += offset_x_;
+ r_area.ymin += offset_y_;
}
- r_area.xmax = r_area.xmin + m_newWidth;
- r_area.ymax = r_area.ymin + m_newHeight;
+ r_area.xmax = r_area.xmin + new_width_;
+ r_area.ymax = r_area.ymin + new_height_;
}
}
@@ -528,11 +527,11 @@ void ScaleFixedSizeOperation::get_area_of_interest(const int input_idx,
BLI_assert(input_idx == 0);
UNUSED_VARS_NDEBUG(input_idx);
- r_input_area.xmax = ceilf((output_area.xmax - m_offsetX) * this->m_relX);
- r_input_area.xmin = floorf((output_area.xmin - m_offsetX) * this->m_relX);
- r_input_area.ymax = ceilf((output_area.ymax - m_offsetY) * this->m_relY);
- r_input_area.ymin = floorf((output_area.ymin - m_offsetY) * this->m_relY);
- expand_area_for_sampler(r_input_area, (PixelSampler)m_sampler);
+ r_input_area.xmax = ceilf((output_area.xmax - offset_x_) * rel_x_);
+ r_input_area.xmin = floorf((output_area.xmin - offset_x_) * rel_x_);
+ r_input_area.ymax = ceilf((output_area.ymax - offset_y_) * rel_y_);
+ r_input_area.ymin = floorf((output_area.ymin - offset_y_) * rel_y_);
+ expand_area_for_sampler(r_input_area, (PixelSampler)sampler_);
}
void ScaleFixedSizeOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -540,19 +539,19 @@ void ScaleFixedSizeOperation::update_memory_buffer_partial(MemoryBuffer *output,
Span<MemoryBuffer *> inputs)
{
const MemoryBuffer *input_img = inputs[0];
- PixelSampler sampler = (PixelSampler)m_sampler;
+ PixelSampler sampler = (PixelSampler)sampler_;
BuffersIterator<float> it = output->iterate_with({}, area);
- if (this->m_is_offset) {
+ if (is_offset_) {
for (; !it.is_end(); ++it) {
- const float nx = (canvas_.xmin + it.x - this->m_offsetX) * this->m_relX;
- const float ny = (canvas_.ymin + it.y - this->m_offsetY) * this->m_relY;
+ const float nx = (canvas_.xmin + it.x - offset_x_) * rel_x_;
+ const float ny = (canvas_.ymin + it.y - offset_y_) * rel_y_;
input_img->read_elem_sampled(nx - canvas_.xmin, ny - canvas_.ymin, sampler, it.out);
}
}
else {
for (; !it.is_end(); ++it) {
- input_img->read_elem_sampled((canvas_.xmin + it.x) * this->m_relX - canvas_.xmin,
- (canvas_.ymin + it.y) * this->m_relY - canvas_.ymin,
+ input_img->read_elem_sampled((canvas_.xmin + it.x) * rel_x_ - canvas_.xmin,
+ (canvas_.ymin + it.y) * rel_y_ - canvas_.ymin,
sampler,
it.out);
}
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h
index 746e490d900..132e9c8fed0 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.h
+++ b/source/blender/compositor/operations/COM_ScaleOperation.h
@@ -27,13 +27,13 @@ class BaseScaleOperation : public MultiThreadedOperation {
static constexpr float DEFAULT_MAX_SCALE_CANVAS_SIZE = 12000;
public:
- void setSampler(PixelSampler sampler)
+ void set_sampler(PixelSampler sampler)
{
- this->m_sampler = (int)sampler;
+ sampler_ = (int)sampler;
}
- void setVariableSize(bool variable_size)
+ void set_variable_size(bool variable_size)
{
- m_variable_size = variable_size;
+ variable_size_ = variable_size;
};
void set_scale_canvas_max_size(Size2f size);
@@ -41,15 +41,15 @@ class BaseScaleOperation : public MultiThreadedOperation {
protected:
BaseScaleOperation();
- PixelSampler getEffectiveSampler(PixelSampler sampler)
+ PixelSampler get_effective_sampler(PixelSampler sampler)
{
- return (m_sampler == -1) ? sampler : (PixelSampler)m_sampler;
+ return (sampler_ == -1) ? sampler : (PixelSampler)sampler_;
}
Size2f max_scale_canvas_size_ = {DEFAULT_MAX_SCALE_CANVAS_SIZE, DEFAULT_MAX_SCALE_CANVAS_SIZE};
- int m_sampler;
+ int sampler_;
/* TODO(manzanilla): to be removed with tiled implementation. */
- bool m_variable_size;
+ bool variable_size_;
};
class ScaleOperation : public BaseScaleOperation {
@@ -61,9 +61,9 @@ class ScaleOperation : public BaseScaleOperation {
static constexpr int X_INPUT_INDEX = 1;
static constexpr int Y_INPUT_INDEX = 2;
- SocketReader *m_inputOperation;
- SocketReader *m_inputXOperation;
- SocketReader *m_inputYOperation;
+ SocketReader *input_operation_;
+ SocketReader *input_xoperation_;
+ SocketReader *input_yoperation_;
float canvas_center_x_;
float canvas_center_y_;
@@ -90,15 +90,15 @@ class ScaleOperation : public BaseScaleOperation {
static void scale_area(rcti &area, float relative_scale_x, float relative_scale_y);
static void get_scale_area_of_interest(const rcti &input_canvas,
const rcti &scale_canvas,
- const float relative_scale_x,
- const float relative_scale_y,
+ float relative_scale_x,
+ float relative_scale_y,
const rcti &output_area,
rcti &r_input_area);
static void clamp_area_size_max(rcti &area, Size2f max_size);
void init_data() override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
@@ -122,10 +122,10 @@ class ScaleRelativeOperation : public ScaleOperation {
public:
ScaleRelativeOperation();
ScaleRelativeOperation(DataType data_type);
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
float get_relative_scale_x_factor(float UNUSED(width)) override
{
@@ -140,10 +140,10 @@ class ScaleRelativeOperation : public ScaleOperation {
class ScaleAbsoluteOperation : public ScaleOperation {
public:
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
float get_relative_scale_x_factor(float width) override
{
@@ -157,51 +157,52 @@ class ScaleAbsoluteOperation : public ScaleOperation {
};
class ScaleFixedSizeOperation : public BaseScaleOperation {
- SocketReader *m_inputOperation;
- int m_newWidth;
- int m_newHeight;
- float m_relX;
- float m_relY;
+ SocketReader *input_operation_;
+ int new_width_;
+ int new_height_;
+ float rel_x_;
+ float rel_y_;
/* center is only used for aspect correction */
- float m_offsetX;
- float m_offsetY;
- bool m_is_aspect;
- bool m_is_crop;
+ float offset_x_;
+ float offset_y_;
+ bool is_aspect_;
+ bool is_crop_;
/* set from other properties on initialization,
* check if we need to apply offset */
- bool m_is_offset;
+ bool is_offset_;
public:
+ /** Absolute fixed size. */
ScaleFixedSizeOperation();
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
- void setNewWidth(int width)
+ void init_execution() override;
+ void deinit_execution() override;
+ void set_new_width(int width)
{
- this->m_newWidth = width;
+ new_width_ = width;
}
- void setNewHeight(int height)
+ void set_new_height(int height)
{
- this->m_newHeight = height;
+ new_height_ = height;
}
- void setIsAspect(bool is_aspect)
+ void set_is_aspect(bool is_aspect)
{
- this->m_is_aspect = is_aspect;
+ is_aspect_ = is_aspect;
}
- void setIsCrop(bool is_crop)
+ void set_is_crop(bool is_crop)
{
- this->m_is_crop = is_crop;
+ is_crop_ = is_crop;
}
- void setOffset(float x, float y)
+ void set_offset(float x, float y)
{
- this->m_offsetX = x;
- this->m_offsetY = y;
+ offset_x_ = x;
+ offset_y_ = y;
}
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc
index 21d9210bdac..e36770b11a1 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc
@@ -17,11 +17,10 @@
*/
#include "COM_ScreenLensDistortionOperation.h"
+
#include "COM_ConstantOperation.h"
-#include "BLI_math.h"
#include "BLI_rand.h"
-#include "BLI_utildefines.h"
#include "PIL_time.h"
@@ -29,96 +28,96 @@ namespace blender::compositor {
ScreenLensDistortionOperation::ScreenLensDistortionOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
- this->flags.complex = true;
- this->m_inputProgram = nullptr;
- this->m_distortion = 0.0f;
- this->m_dispersion = 0.0f;
- this->m_distortion_const = false;
- this->m_dispersion_const = false;
- this->m_variables_ready = false;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
+ flags_.complex = true;
+ input_program_ = nullptr;
+ distortion_ = 0.0f;
+ dispersion_ = 0.0f;
+ distortion_const_ = false;
+ dispersion_const_ = false;
+ variables_ready_ = false;
}
-void ScreenLensDistortionOperation::setDistortion(float distortion)
+void ScreenLensDistortionOperation::set_distortion(float distortion)
{
- m_distortion = distortion;
- m_distortion_const = true;
+ distortion_ = distortion;
+ distortion_const_ = true;
}
-void ScreenLensDistortionOperation::setDispersion(float dispersion)
+void ScreenLensDistortionOperation::set_dispersion(float dispersion)
{
- m_dispersion = dispersion;
- m_dispersion_const = true;
+ dispersion_ = dispersion;
+ dispersion_const_ = true;
}
void ScreenLensDistortionOperation::init_data()
{
- this->m_cx = 0.5f * (float)getWidth();
- this->m_cy = 0.5f * (float)getHeight();
+ cx_ = 0.5f * (float)get_width();
+ cy_ = 0.5f * (float)get_height();
switch (execution_model_) {
case eExecutionModel::FullFrame: {
NodeOperation *distortion_op = get_input_operation(1);
NodeOperation *dispersion_op = get_input_operation(2);
- if (!m_distortion_const && distortion_op->get_flags().is_constant_operation) {
- m_distortion = static_cast<ConstantOperation *>(distortion_op)->get_constant_elem()[0];
+ if (!distortion_const_ && distortion_op->get_flags().is_constant_operation) {
+ distortion_ = static_cast<ConstantOperation *>(distortion_op)->get_constant_elem()[0];
}
- if (!m_dispersion_const && distortion_op->get_flags().is_constant_operation) {
- m_dispersion = static_cast<ConstantOperation *>(dispersion_op)->get_constant_elem()[0];
+ if (!dispersion_const_ && distortion_op->get_flags().is_constant_operation) {
+ dispersion_ = static_cast<ConstantOperation *>(dispersion_op)->get_constant_elem()[0];
}
- updateVariables(m_distortion, m_dispersion);
+ update_variables(distortion_, dispersion_);
break;
}
case eExecutionModel::Tiled: {
/* If both are constant, init variables once. */
- if (m_distortion_const && m_dispersion_const) {
- updateVariables(m_distortion, m_dispersion);
- m_variables_ready = true;
+ if (distortion_const_ && dispersion_const_) {
+ update_variables(distortion_, dispersion_);
+ variables_ready_ = true;
}
break;
}
}
}
-void ScreenLensDistortionOperation::initExecution()
+void ScreenLensDistortionOperation::init_execution()
{
- this->m_inputProgram = this->getInputSocketReader(0);
- this->initMutex();
+ input_program_ = this->get_input_socket_reader(0);
+ this->init_mutex();
uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
- rng_seed ^= (uint)POINTER_AS_INT(m_inputProgram);
- this->m_rng = BLI_rng_new(rng_seed);
+ rng_seed ^= (uint)POINTER_AS_INT(input_program_);
+ rng_ = BLI_rng_new(rng_seed);
}
-void *ScreenLensDistortionOperation::initializeTileData(rcti * /*rect*/)
+void *ScreenLensDistortionOperation::initialize_tile_data(rcti * /*rect*/)
{
- void *buffer = this->m_inputProgram->initializeTileData(nullptr);
+ void *buffer = input_program_->initialize_tile_data(nullptr);
/* get distortion/dispersion values once, by reading inputs at (0,0)
* XXX this assumes invariable values (no image inputs),
* we don't have a nice generic system for that yet
*/
- if (!m_variables_ready) {
- this->lockMutex();
+ if (!variables_ready_) {
+ this->lock_mutex();
- if (!m_distortion_const) {
+ if (!distortion_const_) {
float result[4];
- getInputSocketReader(1)->readSampled(result, 0, 0, PixelSampler::Nearest);
- m_distortion = result[0];
+ get_input_socket_reader(1)->read_sampled(result, 0, 0, PixelSampler::Nearest);
+ distortion_ = result[0];
}
- if (!m_dispersion_const) {
+ if (!dispersion_const_) {
float result[4];
- getInputSocketReader(2)->readSampled(result, 0, 0, PixelSampler::Nearest);
- m_dispersion = result[0];
+ get_input_socket_reader(2)->read_sampled(result, 0, 0, PixelSampler::Nearest);
+ dispersion_ = result[0];
}
- updateVariables(m_distortion, m_dispersion);
- m_variables_ready = true;
+ update_variables(distortion_, dispersion_);
+ variables_ready_ = true;
- this->unlockMutex();
+ this->unlock_mutex();
}
return buffer;
@@ -126,15 +125,15 @@ void *ScreenLensDistortionOperation::initializeTileData(rcti * /*rect*/)
void ScreenLensDistortionOperation::get_uv(const float xy[2], float uv[2]) const
{
- uv[0] = m_sc * ((xy[0] + 0.5f) - m_cx) / m_cx;
- uv[1] = m_sc * ((xy[1] + 0.5f) - m_cy) / m_cy;
+ uv[0] = sc_ * ((xy[0] + 0.5f) - cx_) / cx_;
+ uv[1] = sc_ * ((xy[1] + 0.5f) - cy_) / cy_;
}
void ScreenLensDistortionOperation::distort_uv(const float uv[2], float t, float xy[2]) const
{
float d = 1.0f / (1.0f + sqrtf(t));
- xy[0] = (uv[0] * d + 0.5f) * getWidth() - 0.5f;
- xy[1] = (uv[1] * d + 0.5f) * getHeight() - 0.5f;
+ xy[0] = (uv[0] * d + 0.5f) * get_width() - 0.5f;
+ xy[1] = (uv[1] * d + 0.5f) * get_height() - 0.5f;
}
bool ScreenLensDistortionOperation::get_delta(float r_sq,
@@ -163,21 +162,21 @@ void ScreenLensDistortionOperation::accumulate(const MemoryBuffer *buffer,
float color[4];
float dsf = len_v2v2(delta[a], delta[b]) + 1.0f;
- int ds = m_jitter ? (dsf < 4.0f ? 2 : (int)sqrtf(dsf)) : (int)dsf;
+ int ds = jitter_ ? (dsf < 4.0f ? 2 : (int)sqrtf(dsf)) : (int)dsf;
float sd = 1.0f / (float)ds;
- float k4 = m_k4[a];
- float dk4 = m_dk4[a];
+ float k4 = k4_[a];
+ float dk4 = dk4_[a];
for (float z = 0; z < ds; z++) {
- float tz = (z + (m_jitter ? BLI_rng_get_float(m_rng) : 0.5f)) * sd;
+ float tz = (z + (jitter_ ? BLI_rng_get_float(rng_) : 0.5f)) * sd;
float t = 1.0f - (k4 + tz * dk4) * r_sq;
float xy[2];
distort_uv(uv, t, xy);
switch (execution_model_) {
case eExecutionModel::Tiled:
- buffer->readBilinear(color, xy[0], xy[1]);
+ buffer->read_bilinear(color, xy[0], xy[1]);
break;
case eExecutionModel::FullFrame:
buffer->read_elem_bilinear(xy[0], xy[1], color);
@@ -191,7 +190,7 @@ void ScreenLensDistortionOperation::accumulate(const MemoryBuffer *buffer,
}
}
-void ScreenLensDistortionOperation::executePixel(float output[4], int x, int y, void *data)
+void ScreenLensDistortionOperation::execute_pixel(float output[4], int x, int y, void *data)
{
MemoryBuffer *buffer = (MemoryBuffer *)data;
float xy[2] = {(float)x, (float)y};
@@ -203,9 +202,9 @@ void ScreenLensDistortionOperation::executePixel(float output[4], int x, int y,
float delta[3][2];
float sum[4] = {0, 0, 0, 0};
- bool valid_r = get_delta(uv_dot, m_k4[0], uv, delta[0]);
- bool valid_g = get_delta(uv_dot, m_k4[1], uv, delta[1]);
- bool valid_b = get_delta(uv_dot, m_k4[2], uv, delta[2]);
+ bool valid_r = get_delta(uv_dot, k4_[0], uv, delta[0]);
+ bool valid_g = get_delta(uv_dot, k4_[1], uv, delta[1]);
+ bool valid_b = get_delta(uv_dot, k4_[2], uv, delta[2]);
if (valid_r && valid_g && valid_b) {
accumulate(buffer, 0, 1, uv_dot, uv, delta, sum, count);
@@ -229,11 +228,11 @@ void ScreenLensDistortionOperation::executePixel(float output[4], int x, int y,
}
}
-void ScreenLensDistortionOperation::deinitExecution()
+void ScreenLensDistortionOperation::deinit_execution()
{
- this->deinitMutex();
- this->m_inputProgram = nullptr;
- BLI_rng_free(this->m_rng);
+ this->deinit_mutex();
+ input_program_ = nullptr;
+ BLI_rng_free(rng_);
}
void ScreenLensDistortionOperation::determineUV(float result[6], float x, float y) const
@@ -246,27 +245,27 @@ void ScreenLensDistortionOperation::determineUV(float result[6], float x, float
copy_v2_v2(result + 0, xy);
copy_v2_v2(result + 2, xy);
copy_v2_v2(result + 4, xy);
- get_delta(uv_dot, m_k4[0], uv, result + 0);
- get_delta(uv_dot, m_k4[1], uv, result + 2);
- get_delta(uv_dot, m_k4[2], uv, result + 4);
+ get_delta(uv_dot, k4_[0], uv, result + 0);
+ get_delta(uv_dot, k4_[1], uv, result + 2);
+ get_delta(uv_dot, k4_[2], uv, result + 4);
}
-bool ScreenLensDistortionOperation::determineDependingAreaOfInterest(
- rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
+bool ScreenLensDistortionOperation::determine_depending_area_of_interest(
+ rcti * /*input*/, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInputValue;
- newInputValue.xmin = 0;
- newInputValue.ymin = 0;
- newInputValue.xmax = 2;
- newInputValue.ymax = 2;
-
- NodeOperation *operation = getInputOperation(1);
- if (operation->determineDependingAreaOfInterest(&newInputValue, readOperation, output)) {
+ rcti new_input_value;
+ new_input_value.xmin = 0;
+ new_input_value.ymin = 0;
+ new_input_value.xmax = 2;
+ new_input_value.ymax = 2;
+
+ NodeOperation *operation = get_input_operation(1);
+ if (operation->determine_depending_area_of_interest(&new_input_value, read_operation, output)) {
return true;
}
- operation = getInputOperation(2);
- if (operation->determineDependingAreaOfInterest(&newInputValue, readOperation, output)) {
+ operation = get_input_operation(2);
+ if (operation->determine_depending_area_of_interest(&new_input_value, read_operation, output)) {
return true;
}
@@ -276,34 +275,34 @@ bool ScreenLensDistortionOperation::determineDependingAreaOfInterest(
* So now just use the full image area, which may not be as efficient but works at least ...
*/
#if 1
- rcti imageInput;
+ rcti image_input;
- operation = getInputOperation(0);
- imageInput.xmax = operation->getWidth();
- imageInput.xmin = 0;
- imageInput.ymax = operation->getHeight();
- imageInput.ymin = 0;
+ operation = get_input_operation(0);
+ image_input.xmax = operation->get_width();
+ image_input.xmin = 0;
+ image_input.ymax = operation->get_height();
+ image_input.ymin = 0;
- if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output)) {
+ if (operation->determine_depending_area_of_interest(&image_input, read_operation, output)) {
return true;
}
return false;
#else
- rcti newInput;
+ rcti new_input;
const float margin = 2;
- BLI_rcti_init_minmax(&newInput);
+ BLI_rcti_init_minmax(&new_input);
- if (m_dispersion_const && m_distortion_const) {
+ if (dispersion_const_ && distortion_const_) {
/* update from fixed distortion/dispersion */
# define UPDATE_INPUT(x, y) \
{ \
float coords[6]; \
determineUV(coords, x, y); \
- newInput.xmin = min_ffff(newInput.xmin, coords[0], coords[2], coords[4]); \
- newInput.ymin = min_ffff(newInput.ymin, coords[1], coords[3], coords[5]); \
- newInput.xmax = max_ffff(newInput.xmax, coords[0], coords[2], coords[4]); \
- newInput.ymax = max_ffff(newInput.ymax, coords[1], coords[3], coords[5]); \
+ new_input.xmin = min_ffff(new_input.xmin, coords[0], coords[2], coords[4]); \
+ new_input.ymin = min_ffff(new_input.ymin, coords[1], coords[3], coords[5]); \
+ new_input.xmax = max_ffff(new_input.xmax, coords[0], coords[2], coords[4]); \
+ new_input.ymax = max_ffff(new_input.ymax, coords[1], coords[3], coords[5]); \
} \
(void)0
@@ -316,26 +315,26 @@ bool ScreenLensDistortionOperation::determineDependingAreaOfInterest(
}
else {
/* use maximum dispersion 1.0 if not const */
- float dispersion = m_dispersion_const ? m_dispersion : 1.0f;
+ float dispersion = dispersion_const_ ? dispersion_ : 1.0f;
# define UPDATE_INPUT(x, y, distortion) \
{ \
float coords[6]; \
- updateVariables(distortion, dispersion); \
+ update_variables(distortion, dispersion); \
determineUV(coords, x, y); \
- newInput.xmin = min_ffff(newInput.xmin, coords[0], coords[2], coords[4]); \
- newInput.ymin = min_ffff(newInput.ymin, coords[1], coords[3], coords[5]); \
- newInput.xmax = max_ffff(newInput.xmax, coords[0], coords[2], coords[4]); \
- newInput.ymax = max_ffff(newInput.ymax, coords[1], coords[3], coords[5]); \
+ new_input.xmin = min_ffff(new_input.xmin, coords[0], coords[2], coords[4]); \
+ new_input.ymin = min_ffff(new_input.ymin, coords[1], coords[3], coords[5]); \
+ new_input.xmax = max_ffff(new_input.xmax, coords[0], coords[2], coords[4]); \
+ new_input.ymax = max_ffff(new_input.ymax, coords[1], coords[3], coords[5]); \
} \
(void)0
- if (m_distortion_const) {
+ if (distortion_const_) {
/* update from fixed distortion */
- UPDATE_INPUT(input->xmin, input->xmax, m_distortion);
- UPDATE_INPUT(input->xmin, input->ymax, m_distortion);
- UPDATE_INPUT(input->xmax, input->ymax, m_distortion);
- UPDATE_INPUT(input->xmax, input->ymin, m_distortion);
+ UPDATE_INPUT(input->xmin, input->xmax, distortion_);
+ UPDATE_INPUT(input->xmin, input->ymax, distortion_);
+ UPDATE_INPUT(input->xmax, input->ymax, distortion_);
+ UPDATE_INPUT(input->xmax, input->ymin, distortion_);
}
else {
/* update from min/max distortion (-1..1) */
@@ -353,33 +352,33 @@ bool ScreenLensDistortionOperation::determineDependingAreaOfInterest(
}
}
- newInput.xmin -= margin;
- newInput.ymin -= margin;
- newInput.xmax += margin;
- newInput.ymax += margin;
+ new_input.xmin -= margin;
+ new_input.ymin -= margin;
+ new_input.xmax += margin;
+ new_input.ymax += margin;
- operation = getInputOperation(0);
- if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) {
+ operation = get_input_operation(0);
+ if (operation->determine_depending_area_of_interest(&new_input, read_operation, output)) {
return true;
}
return false;
#endif
}
-void ScreenLensDistortionOperation::updateVariables(float distortion, float dispersion)
+void ScreenLensDistortionOperation::update_variables(float distortion, float dispersion)
{
- m_k[1] = max_ff(min_ff(distortion, 1.0f), -0.999f);
+ k_[1] = max_ff(min_ff(distortion, 1.0f), -0.999f);
/* Smaller dispersion range for somewhat more control. */
float d = 0.25f * max_ff(min_ff(dispersion, 1.0f), 0.0f);
- m_k[0] = max_ff(min_ff((m_k[1] + d), 1.0f), -0.999f);
- m_k[2] = max_ff(min_ff((m_k[1] - d), 1.0f), -0.999f);
- m_maxk = max_fff(m_k[0], m_k[1], m_k[2]);
- m_sc = (m_fit && (m_maxk > 0.0f)) ? (1.0f / (1.0f + 2.0f * m_maxk)) : (1.0f / (1.0f + m_maxk));
- m_dk4[0] = 4.0f * (m_k[1] - m_k[0]);
- m_dk4[1] = 4.0f * (m_k[2] - m_k[1]);
- m_dk4[2] = 0.0f; /* unused */
-
- mul_v3_v3fl(m_k4, m_k, 4.0f);
+ k_[0] = max_ff(min_ff((k_[1] + d), 1.0f), -0.999f);
+ k_[2] = max_ff(min_ff((k_[1] - d), 1.0f), -0.999f);
+ maxk_ = max_fff(k_[0], k_[1], k_[2]);
+ sc_ = (fit_ && (maxk_ > 0.0f)) ? (1.0f / (1.0f + 2.0f * maxk_)) : (1.0f / (1.0f + maxk_));
+ dk4_[0] = 4.0f * (k_[1] - k_[0]);
+ dk4_[1] = 4.0f * (k_[2] - k_[1]);
+ dk4_[2] = 0.0f; /* unused */
+
+ mul_v3_v3fl(k4_, k_, 4.0f);
}
void ScreenLensDistortionOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
@@ -414,25 +413,25 @@ void ScreenLensDistortionOperation::get_area_of_interest(const int input_idx,
* So now just use the full image area, which may not be as efficient but works at least ...
*/
#if 1
- NodeOperation *image = getInputOperation(0);
+ NodeOperation *image = get_input_operation(0);
r_input_area = image->get_canvas();
#else /* Original method in tiled implementation. */
- rcti newInput;
+ rcti new_input;
const float margin = 2;
- BLI_rcti_init_minmax(&newInput);
+ BLI_rcti_init_minmax(&new_input);
- if (m_dispersion_const && m_distortion_const) {
+ if (dispersion_const_ && distortion_const_) {
/* update from fixed distortion/dispersion */
# define UPDATE_INPUT(x, y) \
{ \
float coords[6]; \
determineUV(coords, x, y); \
- newInput.xmin = min_ffff(newInput.xmin, coords[0], coords[2], coords[4]); \
- newInput.ymin = min_ffff(newInput.ymin, coords[1], coords[3], coords[5]); \
- newInput.xmax = max_ffff(newInput.xmax, coords[0], coords[2], coords[4]); \
- newInput.ymax = max_ffff(newInput.ymax, coords[1], coords[3], coords[5]); \
+ new_input.xmin = min_ffff(new_input.xmin, coords[0], coords[2], coords[4]); \
+ new_input.ymin = min_ffff(new_input.ymin, coords[1], coords[3], coords[5]); \
+ new_input.xmax = max_ffff(new_input.xmax, coords[0], coords[2], coords[4]); \
+ new_input.ymax = max_ffff(new_input.ymax, coords[1], coords[3], coords[5]); \
} \
(void)0
@@ -445,26 +444,26 @@ void ScreenLensDistortionOperation::get_area_of_interest(const int input_idx,
}
else {
/* use maximum dispersion 1.0 if not const */
- float dispersion = m_dispersion_const ? m_dispersion : 1.0f;
+ float dispersion = dispersion_const_ ? dispersion_ : 1.0f;
# define UPDATE_INPUT(x, y, distortion) \
{ \
float coords[6]; \
- updateVariables(distortion, dispersion); \
+ update_variables(distortion, dispersion); \
determineUV(coords, x, y); \
- newInput.xmin = min_ffff(newInput.xmin, coords[0], coords[2], coords[4]); \
- newInput.ymin = min_ffff(newInput.ymin, coords[1], coords[3], coords[5]); \
- newInput.xmax = max_ffff(newInput.xmax, coords[0], coords[2], coords[4]); \
- newInput.ymax = max_ffff(newInput.ymax, coords[1], coords[3], coords[5]); \
+ new_input.xmin = min_ffff(new_input.xmin, coords[0], coords[2], coords[4]); \
+ new_input.ymin = min_ffff(new_input.ymin, coords[1], coords[3], coords[5]); \
+ new_input.xmax = max_ffff(new_input.xmax, coords[0], coords[2], coords[4]); \
+ new_input.ymax = max_ffff(new_input.ymax, coords[1], coords[3], coords[5]); \
} \
(void)0
- if (m_distortion_const) {
+ if (distortion_const_) {
/* update from fixed distortion */
- UPDATE_INPUT(input->xmin, input->xmax, m_distortion);
- UPDATE_INPUT(input->xmin, input->ymax, m_distortion);
- UPDATE_INPUT(input->xmax, input->ymax, m_distortion);
- UPDATE_INPUT(input->xmax, input->ymin, m_distortion);
+ UPDATE_INPUT(input->xmin, input->xmax, distortion_);
+ UPDATE_INPUT(input->xmin, input->ymax, distortion_);
+ UPDATE_INPUT(input->xmax, input->ymax, distortion_);
+ UPDATE_INPUT(input->xmax, input->ymin, distortion_);
}
else {
/* update from min/max distortion (-1..1) */
@@ -482,13 +481,13 @@ void ScreenLensDistortionOperation::get_area_of_interest(const int input_idx,
}
}
- newInput.xmin -= margin;
- newInput.ymin -= margin;
- newInput.xmax += margin;
- newInput.ymax += margin;
+ new_input.xmin -= margin;
+ new_input.ymin -= margin;
+ new_input.xmax += margin;
+ new_input.ymax += margin;
- operation = getInputOperation(0);
- if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) {
+ operation = get_input_operation(0);
+ if (operation->determine_depending_area_of_interest(&new_input, read_operation, output)) {
return true;
}
return false;
@@ -507,9 +506,9 @@ void ScreenLensDistortionOperation::update_memory_buffer_partial(MemoryBuffer *o
const float uv_dot = len_squared_v2(uv);
float delta[3][2];
- const bool valid_r = get_delta(uv_dot, m_k4[0], uv, delta[0]);
- const bool valid_g = get_delta(uv_dot, m_k4[1], uv, delta[1]);
- const bool valid_b = get_delta(uv_dot, m_k4[2], uv, delta[2]);
+ const bool valid_r = get_delta(uv_dot, k4_[0], uv, delta[0]);
+ const bool valid_g = get_delta(uv_dot, k4_[1], uv, delta[1]);
+ const bool valid_b = get_delta(uv_dot, k4_[2], uv, delta[2]);
if (!(valid_r && valid_g && valid_b)) {
zero_v4(it.out);
continue;
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h
index 93681b2f934..fb610b90466 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h
@@ -28,24 +28,24 @@ namespace blender::compositor {
class ScreenLensDistortionOperation : public MultiThreadedOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
- struct RNG *m_rng;
-
- bool m_fit;
- bool m_jitter;
-
- float m_dispersion;
- float m_distortion;
- bool m_dispersion_const;
- bool m_distortion_const;
- bool m_variables_ready;
- float m_k[3];
- float m_k4[3];
- float m_dk4[3];
- float m_maxk;
- float m_sc, m_cx, m_cy;
+ SocketReader *input_program_;
+ struct RNG *rng_;
+
+ bool fit_;
+ bool jitter_;
+
+ float dispersion_;
+ float distortion_;
+ bool dispersion_const_;
+ bool distortion_const_;
+ bool variables_ready_;
+ float k_[3];
+ float k4_[3];
+ float dk4_[3];
+ float maxk_;
+ float sc_, cx_, cy_;
public:
ScreenLensDistortionOperation();
@@ -55,36 +55,36 @@ class ScreenLensDistortionOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setFit(bool fit)
+ void set_fit(bool fit)
{
- m_fit = fit;
+ fit_ = fit;
}
- void setJitter(bool jitter)
+ void set_jitter(bool jitter)
{
- m_jitter = jitter;
+ jitter_ = jitter;
}
/** Set constant distortion value */
- void setDistortion(float distortion);
+ void set_distortion(float distortion);
/** Set constant dispersion value */
- void setDispersion(float dispersion);
+ void set_dispersion(float dispersion);
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
@@ -94,7 +94,7 @@ class ScreenLensDistortionOperation : public MultiThreadedOperation {
private:
void determineUV(float result[6], float x, float y) const;
- void updateVariables(float distortion, float dispersion);
+ void update_variables(float distortion, float dispersion);
void get_uv(const float xy[2], float uv[2]) const;
void distort_uv(const float uv[2], float t, float xy[2]) const;
diff --git a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc
index e4686ffa76d..9f193985d38 100644
--- a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc
+++ b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc
@@ -22,39 +22,39 @@ namespace blender::compositor {
SetAlphaMultiplyOperation::SetAlphaMultiplyOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
- this->m_inputColor = nullptr;
- this->m_inputAlpha = nullptr;
- this->flags.can_be_constant = true;
+ input_color_ = nullptr;
+ input_alpha_ = nullptr;
+ flags_.can_be_constant = true;
}
-void SetAlphaMultiplyOperation::initExecution()
+void SetAlphaMultiplyOperation::init_execution()
{
- this->m_inputColor = getInputSocketReader(0);
- this->m_inputAlpha = getInputSocketReader(1);
+ input_color_ = get_input_socket_reader(0);
+ input_alpha_ = get_input_socket_reader(1);
}
-void SetAlphaMultiplyOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void SetAlphaMultiplyOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float color_input[4];
float alpha_input[4];
- this->m_inputColor->readSampled(color_input, x, y, sampler);
- this->m_inputAlpha->readSampled(alpha_input, x, y, sampler);
+ input_color_->read_sampled(color_input, x, y, sampler);
+ input_alpha_->read_sampled(alpha_input, x, y, sampler);
mul_v4_v4fl(output, color_input, alpha_input[0]);
}
-void SetAlphaMultiplyOperation::deinitExecution()
+void SetAlphaMultiplyOperation::deinit_execution()
{
- this->m_inputColor = nullptr;
- this->m_inputAlpha = nullptr;
+ input_color_ = nullptr;
+ input_alpha_ = nullptr;
}
void SetAlphaMultiplyOperation::update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.h b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.h
index 44885318901..2aa56800ff7 100644
--- a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.h
+++ b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.h
@@ -29,16 +29,16 @@ namespace blender::compositor {
*/
class SetAlphaMultiplyOperation : public MultiThreadedOperation {
private:
- SocketReader *m_inputColor;
- SocketReader *m_inputAlpha;
+ SocketReader *input_color_;
+ SocketReader *input_alpha_;
public:
SetAlphaMultiplyOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc
index 434f5d9b63c..c4490cab178 100644
--- a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc
+++ b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc
@@ -22,37 +22,37 @@ namespace blender::compositor {
SetAlphaReplaceOperation::SetAlphaReplaceOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
- this->m_inputColor = nullptr;
- this->m_inputAlpha = nullptr;
- this->flags.can_be_constant = true;
+ input_color_ = nullptr;
+ input_alpha_ = nullptr;
+ flags_.can_be_constant = true;
}
-void SetAlphaReplaceOperation::initExecution()
+void SetAlphaReplaceOperation::init_execution()
{
- this->m_inputColor = getInputSocketReader(0);
- this->m_inputAlpha = getInputSocketReader(1);
+ input_color_ = get_input_socket_reader(0);
+ input_alpha_ = get_input_socket_reader(1);
}
-void SetAlphaReplaceOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void SetAlphaReplaceOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float alpha_input[4];
- this->m_inputColor->readSampled(output, x, y, sampler);
- this->m_inputAlpha->readSampled(alpha_input, x, y, sampler);
+ input_color_->read_sampled(output, x, y, sampler);
+ input_alpha_->read_sampled(alpha_input, x, y, sampler);
output[3] = alpha_input[0];
}
-void SetAlphaReplaceOperation::deinitExecution()
+void SetAlphaReplaceOperation::deinit_execution()
{
- this->m_inputColor = nullptr;
- this->m_inputAlpha = nullptr;
+ input_color_ = nullptr;
+ input_alpha_ = nullptr;
}
void SetAlphaReplaceOperation::update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.h b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.h
index 2c2d4cddf5b..ea27e6af672 100644
--- a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.h
+++ b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.h
@@ -28,8 +28,8 @@ namespace blender::compositor {
*/
class SetAlphaReplaceOperation : public MultiThreadedOperation {
private:
- SocketReader *m_inputColor;
- SocketReader *m_inputAlpha;
+ SocketReader *input_color_;
+ SocketReader *input_alpha_;
public:
/**
@@ -40,10 +40,10 @@ class SetAlphaReplaceOperation : public MultiThreadedOperation {
/**
* the inner loop of this program
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_SetColorOperation.cc b/source/blender/compositor/operations/COM_SetColorOperation.cc
index 1e7a950e727..b7fee856053 100644
--- a/source/blender/compositor/operations/COM_SetColorOperation.cc
+++ b/source/blender/compositor/operations/COM_SetColorOperation.cc
@@ -22,16 +22,16 @@ namespace blender::compositor {
SetColorOperation::SetColorOperation()
{
- this->addOutputSocket(DataType::Color);
- flags.is_set_operation = true;
+ this->add_output_socket(DataType::Color);
+ flags_.is_set_operation = true;
}
-void SetColorOperation::executePixelSampled(float output[4],
- float /*x*/,
- float /*y*/,
- PixelSampler /*sampler*/)
+void SetColorOperation::execute_pixel_sampled(float output[4],
+ float /*x*/,
+ float /*y*/,
+ PixelSampler /*sampler*/)
{
- copy_v4_v4(output, this->m_color);
+ copy_v4_v4(output, color_);
}
void SetColorOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
diff --git a/source/blender/compositor/operations/COM_SetColorOperation.h b/source/blender/compositor/operations/COM_SetColorOperation.h
index 34ea35bdcbc..0e04c0324b8 100644
--- a/source/blender/compositor/operations/COM_SetColorOperation.h
+++ b/source/blender/compositor/operations/COM_SetColorOperation.h
@@ -28,7 +28,7 @@ namespace blender::compositor {
*/
class SetColorOperation : public ConstantOperation {
private:
- float m_color[4];
+ float color_[4];
public:
/**
@@ -38,50 +38,50 @@ class SetColorOperation : public ConstantOperation {
const float *get_constant_elem() override
{
- return m_color;
+ return color_;
}
- float getChannel1()
+ float get_channel1()
{
- return this->m_color[0];
+ return color_[0];
}
- void setChannel1(float value)
+ void set_channel1(float value)
{
- this->m_color[0] = value;
+ color_[0] = value;
}
- float getChannel2()
+ float get_channel2()
{
- return this->m_color[1];
+ return color_[1];
}
- void setChannel2(float value)
+ void set_channel2(float value)
{
- this->m_color[1] = value;
+ color_[1] = value;
}
- float getChannel3()
+ float get_channel3()
{
- return this->m_color[2];
+ return color_[2];
}
- void setChannel3(float value)
+ void set_channel3(float value)
{
- this->m_color[2] = value;
+ color_[2] = value;
}
- float getChannel4()
+ float get_channel4()
{
- return this->m_color[3];
+ return color_[3];
}
- void setChannel4(const float value)
+ void set_channel4(const float value)
{
- this->m_color[3] = value;
+ color_[3] = value;
}
- void setChannels(const float value[4])
+ void set_channels(const float value[4])
{
- copy_v4_v4(this->m_color, value);
+ copy_v4_v4(color_, value);
}
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
};
diff --git a/source/blender/compositor/operations/COM_SetSamplerOperation.cc b/source/blender/compositor/operations/COM_SetSamplerOperation.cc
index e68774736f3..6f5ac63317b 100644
--- a/source/blender/compositor/operations/COM_SetSamplerOperation.cc
+++ b/source/blender/compositor/operations/COM_SetSamplerOperation.cc
@@ -22,25 +22,25 @@ namespace blender::compositor {
SetSamplerOperation::SetSamplerOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
}
-void SetSamplerOperation::initExecution()
+void SetSamplerOperation::init_execution()
{
- this->m_reader = this->getInputSocketReader(0);
+ reader_ = this->get_input_socket_reader(0);
}
-void SetSamplerOperation::deinitExecution()
+void SetSamplerOperation::deinit_execution()
{
- this->m_reader = nullptr;
+ reader_ = nullptr;
}
-void SetSamplerOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler /*sampler*/)
+void SetSamplerOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
- this->m_reader->readSampled(output, x, y, this->m_sampler);
+ reader_->read_sampled(output, x, y, sampler_);
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_SetSamplerOperation.h b/source/blender/compositor/operations/COM_SetSamplerOperation.h
index d355d937806..27ef6603ae4 100644
--- a/source/blender/compositor/operations/COM_SetSamplerOperation.h
+++ b/source/blender/compositor/operations/COM_SetSamplerOperation.h
@@ -28,8 +28,8 @@ namespace blender::compositor {
*/
class SetSamplerOperation : public NodeOperation {
private:
- PixelSampler m_sampler;
- SocketReader *m_reader;
+ PixelSampler sampler_;
+ SocketReader *reader_;
public:
/**
@@ -37,17 +37,17 @@ class SetSamplerOperation : public NodeOperation {
*/
SetSamplerOperation();
- void setSampler(PixelSampler sampler)
+ void set_sampler(PixelSampler sampler)
{
- this->m_sampler = sampler;
+ sampler_ = sampler;
}
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void init_execution() override;
+ void deinit_execution() override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_SetValueOperation.cc b/source/blender/compositor/operations/COM_SetValueOperation.cc
index b7c50f94887..d11a35aefc3 100644
--- a/source/blender/compositor/operations/COM_SetValueOperation.cc
+++ b/source/blender/compositor/operations/COM_SetValueOperation.cc
@@ -22,16 +22,16 @@ namespace blender::compositor {
SetValueOperation::SetValueOperation()
{
- this->addOutputSocket(DataType::Value);
- flags.is_set_operation = true;
+ this->add_output_socket(DataType::Value);
+ flags_.is_set_operation = true;
}
-void SetValueOperation::executePixelSampled(float output[4],
- float /*x*/,
- float /*y*/,
- PixelSampler /*sampler*/)
+void SetValueOperation::execute_pixel_sampled(float output[4],
+ float /*x*/,
+ float /*y*/,
+ PixelSampler /*sampler*/)
{
- output[0] = this->m_value;
+ output[0] = value_;
}
void SetValueOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
diff --git a/source/blender/compositor/operations/COM_SetValueOperation.h b/source/blender/compositor/operations/COM_SetValueOperation.h
index e72652450a9..4c824d00294 100644
--- a/source/blender/compositor/operations/COM_SetValueOperation.h
+++ b/source/blender/compositor/operations/COM_SetValueOperation.h
@@ -28,7 +28,7 @@ namespace blender::compositor {
*/
class SetValueOperation : public ConstantOperation {
private:
- float m_value;
+ float value_;
public:
/**
@@ -38,22 +38,22 @@ class SetValueOperation : public ConstantOperation {
const float *get_constant_elem() override
{
- return &m_value;
+ return &value_;
}
- float getValue()
+ float get_value()
{
- return this->m_value;
+ return value_;
}
- void setValue(float value)
+ void set_value(float value)
{
- this->m_value = value;
+ value_ = value;
}
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
};
diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.cc b/source/blender/compositor/operations/COM_SetVectorOperation.cc
index 3e8514f1f59..c1db429b41e 100644
--- a/source/blender/compositor/operations/COM_SetVectorOperation.cc
+++ b/source/blender/compositor/operations/COM_SetVectorOperation.cc
@@ -17,20 +17,19 @@
*/
#include "COM_SetVectorOperation.h"
-#include "COM_defines.h"
namespace blender::compositor {
SetVectorOperation::SetVectorOperation()
{
- this->addOutputSocket(DataType::Vector);
- flags.is_set_operation = true;
+ this->add_output_socket(DataType::Vector);
+ flags_.is_set_operation = true;
}
-void SetVectorOperation::executePixelSampled(float output[4],
- float /*x*/,
- float /*y*/,
- PixelSampler /*sampler*/)
+void SetVectorOperation::execute_pixel_sampled(float output[4],
+ float /*x*/,
+ float /*y*/,
+ PixelSampler /*sampler*/)
{
output[0] = vector_.x;
output[1] = vector_.y;
diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.h b/source/blender/compositor/operations/COM_SetVectorOperation.h
index 920ea8051e4..291fef37817 100644
--- a/source/blender/compositor/operations/COM_SetVectorOperation.h
+++ b/source/blender/compositor/operations/COM_SetVectorOperation.h
@@ -82,11 +82,11 @@ class SetVectorOperation : public ConstantOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
- void setVector(const float vector[3])
+ void set_vector(const float vector[3])
{
setX(vector[0]);
setY(vector[1]);
diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.cc b/source/blender/compositor/operations/COM_SocketProxyOperation.cc
index 39876439b7b..fd37f0b5f4f 100644
--- a/source/blender/compositor/operations/COM_SocketProxyOperation.cc
+++ b/source/blender/compositor/operations/COM_SocketProxyOperation.cc
@@ -22,15 +22,15 @@ namespace blender::compositor {
SocketProxyOperation::SocketProxyOperation(DataType type, bool use_conversion)
{
- this->addInputSocket(type);
- this->addOutputSocket(type);
- flags.is_proxy_operation = true;
- flags.use_datatype_conversion = use_conversion;
+ this->add_input_socket(type);
+ this->add_output_socket(type);
+ flags_.is_proxy_operation = true;
+ flags_.use_datatype_conversion = use_conversion;
}
-std::unique_ptr<MetaData> SocketProxyOperation::getMetaData()
+std::unique_ptr<MetaData> SocketProxyOperation::get_meta_data()
{
- return this->getInputSocket(0)->getReader()->getMetaData();
+ return this->get_input_socket(0)->get_reader()->get_meta_data();
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.h b/source/blender/compositor/operations/COM_SocketProxyOperation.h
index 1d3b76055bd..e9740cf43bc 100644
--- a/source/blender/compositor/operations/COM_SocketProxyOperation.h
+++ b/source/blender/compositor/operations/COM_SocketProxyOperation.h
@@ -26,7 +26,7 @@ class SocketProxyOperation : public NodeOperation {
public:
SocketProxyOperation(DataType type, bool use_conversion);
- std::unique_ptr<MetaData> getMetaData() override;
+ std::unique_ptr<MetaData> get_meta_data() override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_SplitOperation.cc b/source/blender/compositor/operations/COM_SplitOperation.cc
index 47b2bbb7e94..39d097b02e1 100644
--- a/source/blender/compositor/operations/COM_SplitOperation.cc
+++ b/source/blender/compositor/operations/COM_SplitOperation.cc
@@ -17,61 +17,52 @@
*/
#include "COM_SplitOperation.h"
-#include "BKE_image.h"
-#include "BLI_listbase.h"
-#include "BLI_math_color.h"
-#include "BLI_math_vector.h"
-#include "BLI_utildefines.h"
-#include "MEM_guardedalloc.h"
-
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
namespace blender::compositor {
SplitOperation::SplitOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
- this->m_image1Input = nullptr;
- this->m_image2Input = nullptr;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ image1Input_ = nullptr;
+ image2Input_ = nullptr;
}
-void SplitOperation::initExecution()
+void SplitOperation::init_execution()
{
/* When initializing the tree during initial load the width and height can be zero. */
- this->m_image1Input = getInputSocketReader(0);
- this->m_image2Input = getInputSocketReader(1);
+ image1Input_ = get_input_socket_reader(0);
+ image2Input_ = get_input_socket_reader(1);
}
-void SplitOperation::deinitExecution()
+void SplitOperation::deinit_execution()
{
- this->m_image1Input = nullptr;
- this->m_image2Input = nullptr;
+ image1Input_ = nullptr;
+ image2Input_ = nullptr;
}
-void SplitOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler /*sampler*/)
+void SplitOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
- int perc = this->m_xSplit ? this->m_splitPercentage * this->getWidth() / 100.0f :
- this->m_splitPercentage * this->getHeight() / 100.0f;
- bool image1 = this->m_xSplit ? x > perc : y > perc;
+ int perc = x_split_ ? split_percentage_ * this->get_width() / 100.0f :
+ split_percentage_ * this->get_height() / 100.0f;
+ bool image1 = x_split_ ? x > perc : y > perc;
if (image1) {
- this->m_image1Input->readSampled(output, x, y, PixelSampler::Nearest);
+ image1Input_->read_sampled(output, x, y, PixelSampler::Nearest);
}
else {
- this->m_image2Input->readSampled(output, x, y, PixelSampler::Nearest);
+ image2Input_->read_sampled(output, x, y, PixelSampler::Nearest);
}
}
void SplitOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
- rcti unused_area;
+ rcti unused_area = COM_AREA_NONE;
- const bool determined = this->getInputSocket(0)->determine_canvas(COM_AREA_NONE, unused_area);
+ const bool determined = this->get_input_socket(0)->determine_canvas(COM_AREA_NONE, unused_area);
this->set_canvas_input_index(determined ? 0 : 1);
NodeOperation::determine_canvas(preferred_area, r_area);
@@ -81,11 +72,11 @@ void SplitOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- const int percent = this->m_xSplit ? this->m_splitPercentage * this->getWidth() / 100.0f :
- this->m_splitPercentage * this->getHeight() / 100.0f;
- const size_t elem_bytes = COM_data_type_bytes_len(getOutputSocket()->getDataType());
+ const int percent = x_split_ ? split_percentage_ * this->get_width() / 100.0f :
+ split_percentage_ * this->get_height() / 100.0f;
+ const size_t elem_bytes = COM_data_type_bytes_len(get_output_socket()->get_data_type());
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
- const bool is_image1 = this->m_xSplit ? it.x > percent : it.y > percent;
+ const bool is_image1 = x_split_ ? it.x > percent : it.y > percent;
memcpy(it.out, it.in(is_image1 ? 0 : 1), elem_bytes);
}
}
diff --git a/source/blender/compositor/operations/COM_SplitOperation.h b/source/blender/compositor/operations/COM_SplitOperation.h
index f923c9f8b7a..2d2b2e89cca 100644
--- a/source/blender/compositor/operations/COM_SplitOperation.h
+++ b/source/blender/compositor/operations/COM_SplitOperation.h
@@ -24,25 +24,25 @@ namespace blender::compositor {
class SplitOperation : public MultiThreadedOperation {
private:
- SocketReader *m_image1Input;
- SocketReader *m_image2Input;
+ SocketReader *image1Input_;
+ SocketReader *image2Input_;
- float m_splitPercentage;
- bool m_xSplit;
+ float split_percentage_;
+ bool x_split_;
public:
SplitOperation();
- void initExecution() override;
- void deinitExecution() override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void init_execution() override;
+ void deinit_execution() override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
- void setSplitPercentage(float splitPercentage)
+ void set_split_percentage(float split_percentage)
{
- this->m_splitPercentage = splitPercentage;
+ split_percentage_ = split_percentage;
}
- void setXSplit(bool xsplit)
+ void set_xsplit(bool xsplit)
{
- this->m_xSplit = xsplit;
+ x_split_ = xsplit;
}
void update_memory_buffer_partial(MemoryBuffer *output,
diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cc b/source/blender/compositor/operations/COM_SunBeamsOperation.cc
index 494506389c5..ba1363d1193 100644
--- a/source/blender/compositor/operations/COM_SunBeamsOperation.cc
+++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cc
@@ -23,22 +23,22 @@ namespace blender::compositor {
SunBeamsOperation::SunBeamsOperation()
{
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
this->set_canvas_input_index(0);
- this->flags.complex = true;
+ flags_.complex = true;
}
void SunBeamsOperation::calc_rays_common_data()
{
/* convert to pixels */
- this->m_source_px[0] = this->m_data.source[0] * this->getWidth();
- this->m_source_px[1] = this->m_data.source[1] * this->getHeight();
- this->m_ray_length_px = this->m_data.ray_length * MAX2(this->getWidth(), this->getHeight());
+ source_px_[0] = data_.source[0] * this->get_width();
+ source_px_[1] = data_.source[1] * this->get_height();
+ ray_length_px_ = data_.ray_length * MAX2(this->get_width(), this->get_height());
}
-void SunBeamsOperation::initExecution()
+void SunBeamsOperation::init_execution()
{
calc_rays_common_data();
}
@@ -64,16 +64,6 @@ template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator {
/* utility functions implementing the matrix transform to/from sector space */
- static inline void buffer_to_sector(const float source[2], int x, int y, int &u, int &v)
- {
- int x0 = (int)source[0];
- int y0 = (int)source[1];
- x -= x0;
- y -= y0;
- u = x * fxu + y * fyu;
- v = x * fxv + y * fyv;
- }
-
static inline void buffer_to_sector(const float source[2], float x, float y, float &u, float &v)
{
int x0 = (int)source[0];
@@ -92,14 +82,6 @@ template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator {
y = y0 + u * fyu + v * fyv;
}
- static inline void sector_to_buffer(const float source[2], float u, float v, float &x, float &y)
- {
- int x0 = (int)source[0];
- int y0 = (int)source[1];
- x = (float)x0 + u * fxu + v * fxv;
- y = (float)y0 + u * fyu + v * fyv;
- }
-
/**
* Set up the initial buffer pointer and calculate necessary variables for looping.
*
@@ -127,9 +109,9 @@ template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator {
buffer_to_sector(source, co[0], co[1], pu, pv);
/* line angle */
- float tan_phi = pv / pu;
- float dr = sqrtf(tan_phi * tan_phi + 1.0f);
- float cos_phi = 1.0f / dr;
+ double tan_phi = pv / (double)pu;
+ double dr = sqrt(tan_phi * tan_phi + 1.0);
+ double cos_phi = 1.0 / dr;
/* clamp u range to avoid influence of pixels "behind" the source */
float umin = max_ff(pu - cos_phi * dist_min, 0.0f);
@@ -143,9 +125,9 @@ template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator {
sector_to_buffer(source, end, (int)ceilf(v), x, y);
- falloff_factor = dist_max > dist_min ? dr / (float)(dist_max - dist_min) : 0.0f;
+ falloff_factor = dist_max > dist_min ? dr / (double)(dist_max - dist_min) : 0.0f;
- float *iter = input->getBuffer() + input->get_coords_offset(x, y);
+ float *iter = input->get_buffer() + input->get_coords_offset(x, y);
return iter;
}
@@ -312,18 +294,17 @@ static void accumulate_line(MemoryBuffer *input,
}
}
-void *SunBeamsOperation::initializeTileData(rcti * /*rect*/)
+void *SunBeamsOperation::initialize_tile_data(rcti * /*rect*/)
{
- void *buffer = getInputOperation(0)->initializeTileData(nullptr);
+ void *buffer = get_input_operation(0)->initialize_tile_data(nullptr);
return buffer;
}
-void SunBeamsOperation::executePixel(float output[4], int x, int y, void *data)
+void SunBeamsOperation::execute_pixel(float output[4], int x, int y, void *data)
{
const float co[2] = {(float)x, (float)y};
- accumulate_line(
- (MemoryBuffer *)data, output, co, this->m_source_px, 0.0f, this->m_ray_length_px);
+ accumulate_line((MemoryBuffer *)data, output, co, source_px_, 0.0f, ray_length_px_);
}
static void calc_ray_shift(rcti *rect, float x, float y, const float source[2], float ray_length)
@@ -341,21 +322,21 @@ static void calc_ray_shift(rcti *rect, float x, float y, const float source[2],
BLI_rcti_do_minmax_v(rect, ico);
}
-bool SunBeamsOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool SunBeamsOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
/* Enlarges the rect by moving each corner toward the source.
* This is the maximum distance that pixels can influence each other
* and gives a rect that contains all possible accumulated pixels.
*/
rcti rect = *input;
- calc_ray_shift(&rect, input->xmin, input->ymin, this->m_source_px, this->m_ray_length_px);
- calc_ray_shift(&rect, input->xmin, input->ymax, this->m_source_px, this->m_ray_length_px);
- calc_ray_shift(&rect, input->xmax, input->ymin, this->m_source_px, this->m_ray_length_px);
- calc_ray_shift(&rect, input->xmax, input->ymax, this->m_source_px, this->m_ray_length_px);
+ calc_ray_shift(&rect, input->xmin, input->ymin, source_px_, ray_length_px_);
+ calc_ray_shift(&rect, input->xmin, input->ymax, source_px_, ray_length_px_);
+ calc_ray_shift(&rect, input->xmax, input->ymin, source_px_, ray_length_px_);
+ calc_ray_shift(&rect, input->xmax, input->ymax, source_px_, ray_length_px_);
- return NodeOperation::determineDependingAreaOfInterest(&rect, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&rect, read_operation, output);
}
void SunBeamsOperation::get_area_of_interest(const int input_idx,
@@ -370,10 +351,10 @@ void SunBeamsOperation::get_area_of_interest(const int input_idx,
/* Enlarges the rect by moving each corner toward the source.
* This is the maximum distance that pixels can influence each other
* and gives a rect that contains all possible accumulated pixels. */
- calc_ray_shift(&r_input_area, output_area.xmin, output_area.ymin, m_source_px, m_ray_length_px);
- calc_ray_shift(&r_input_area, output_area.xmin, output_area.ymax, m_source_px, m_ray_length_px);
- calc_ray_shift(&r_input_area, output_area.xmax, output_area.ymin, m_source_px, m_ray_length_px);
- calc_ray_shift(&r_input_area, output_area.xmax, output_area.ymax, m_source_px, m_ray_length_px);
+ calc_ray_shift(&r_input_area, output_area.xmin, output_area.ymin, source_px_, ray_length_px_);
+ calc_ray_shift(&r_input_area, output_area.xmin, output_area.ymax, source_px_, ray_length_px_);
+ calc_ray_shift(&r_input_area, output_area.xmax, output_area.ymin, source_px_, ray_length_px_);
+ calc_ray_shift(&r_input_area, output_area.xmax, output_area.ymax, source_px_, ray_length_px_);
}
void SunBeamsOperation::update_memory_buffer_partial(MemoryBuffer *output,
@@ -387,7 +368,7 @@ void SunBeamsOperation::update_memory_buffer_partial(MemoryBuffer *output,
float *out_elem = output->get_elem(area.xmin, y);
for (int x = area.xmin; x < area.xmax; x++) {
coords[0] = x;
- accumulate_line(input, out_elem, coords, m_source_px, 0.0f, m_ray_length_px);
+ accumulate_line(input, out_elem, coords, source_px_, 0.0f, ray_length_px_);
out_elem += output->elem_stride;
}
}
diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.h b/source/blender/compositor/operations/COM_SunBeamsOperation.h
index 71fc04453fe..c40d540996e 100644
--- a/source/blender/compositor/operations/COM_SunBeamsOperation.h
+++ b/source/blender/compositor/operations/COM_SunBeamsOperation.h
@@ -25,19 +25,19 @@ class SunBeamsOperation : public MultiThreadedOperation {
public:
SunBeamsOperation();
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
- void initExecution() override;
+ void init_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void setData(const NodeSunBeams &data)
+ void set_data(const NodeSunBeams &data)
{
- m_data = data;
+ data_ = data;
}
void update_memory_buffer_partial(MemoryBuffer *output,
@@ -49,10 +49,10 @@ class SunBeamsOperation : public MultiThreadedOperation {
void calc_rays_common_data();
private:
- NodeSunBeams m_data;
+ NodeSunBeams data_;
- float m_source_px[2];
- float m_ray_length_px;
+ float source_px_[2];
+ float ray_length_px_;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cc b/source/blender/compositor/operations/COM_TextureOperation.cc
index c06e3ac7cb0..a4990993d73 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cc
+++ b/source/blender/compositor/operations/COM_TextureOperation.cc
@@ -22,126 +22,116 @@
#include "BKE_image.h"
#include "BKE_node.h"
-#include "BLI_listbase.h"
-#include "BLI_threads.h"
+#include "NOD_texture.h"
namespace blender::compositor {
TextureBaseOperation::TextureBaseOperation()
{
- this->addInputSocket(DataType::Vector); // offset
- this->addInputSocket(DataType::Vector); // size
- this->m_texture = nullptr;
- this->m_inputSize = nullptr;
- this->m_inputOffset = nullptr;
- this->m_rd = nullptr;
- this->m_pool = nullptr;
- this->m_sceneColorManage = false;
- flags.complex = true;
+ this->add_input_socket(DataType::Vector); // offset
+ this->add_input_socket(DataType::Vector); // size
+ texture_ = nullptr;
+ input_size_ = nullptr;
+ input_offset_ = nullptr;
+ rd_ = nullptr;
+ pool_ = nullptr;
+ scene_color_manage_ = false;
+ flags_.complex = true;
}
TextureOperation::TextureOperation() : TextureBaseOperation()
{
- this->addOutputSocket(DataType::Color);
+ this->add_output_socket(DataType::Color);
}
TextureAlphaOperation::TextureAlphaOperation() : TextureBaseOperation()
{
- this->addOutputSocket(DataType::Value);
+ this->add_output_socket(DataType::Value);
}
-void TextureBaseOperation::initExecution()
+void TextureBaseOperation::init_execution()
{
- this->m_inputOffset = getInputSocketReader(0);
- this->m_inputSize = getInputSocketReader(1);
- this->m_pool = BKE_image_pool_new();
- if (this->m_texture != nullptr && this->m_texture->nodetree != nullptr &&
- this->m_texture->use_nodes) {
- ntreeTexBeginExecTree(this->m_texture->nodetree);
+ input_offset_ = get_input_socket_reader(0);
+ input_size_ = get_input_socket_reader(1);
+ pool_ = BKE_image_pool_new();
+ if (texture_ != nullptr && texture_->nodetree != nullptr && texture_->use_nodes) {
+ ntreeTexBeginExecTree(texture_->nodetree);
}
- NodeOperation::initExecution();
+ NodeOperation::init_execution();
}
-void TextureBaseOperation::deinitExecution()
+void TextureBaseOperation::deinit_execution()
{
- this->m_inputSize = nullptr;
- this->m_inputOffset = nullptr;
- BKE_image_pool_free(this->m_pool);
- this->m_pool = nullptr;
- if (this->m_texture != nullptr && this->m_texture->use_nodes &&
- this->m_texture->nodetree != nullptr && this->m_texture->nodetree->execdata != nullptr) {
- ntreeTexEndExecTree(this->m_texture->nodetree->execdata);
+ input_size_ = nullptr;
+ input_offset_ = nullptr;
+ BKE_image_pool_free(pool_);
+ pool_ = nullptr;
+ if (texture_ != nullptr && texture_->use_nodes && texture_->nodetree != nullptr &&
+ texture_->nodetree->execdata != nullptr) {
+ ntreeTexEndExecTree(texture_->nodetree->execdata);
}
- NodeOperation::deinitExecution();
+ NodeOperation::deinit_execution();
}
void TextureBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
r_area = preferred_area;
if (BLI_rcti_is_empty(&preferred_area)) {
- int width = this->m_rd->xsch * this->m_rd->size / 100;
- int height = this->m_rd->ysch * this->m_rd->size / 100;
+ int width = rd_->xsch * rd_->size / 100;
+ int height = rd_->ysch * rd_->size / 100;
r_area.xmax = preferred_area.xmin + width;
r_area.ymax = preferred_area.ymin + height;
}
if (execution_model_ == eExecutionModel::FullFrame) {
/* Determine inputs. */
- rcti temp;
+ rcti temp = COM_AREA_NONE;
NodeOperation::determine_canvas(r_area, temp);
}
}
-void TextureAlphaOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void TextureAlphaOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float color[4];
- TextureBaseOperation::executePixelSampled(color, x, y, sampler);
+ TextureBaseOperation::execute_pixel_sampled(color, x, y, sampler);
output[0] = color[3];
}
-void TextureBaseOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void TextureBaseOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
TexResult texres = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, nullptr};
- float textureSize[4];
- float textureOffset[4];
+ float texture_size[4];
+ float texture_offset[4];
float vec[3];
int retval;
- const float cx = this->getWidth() / 2;
- const float cy = this->getHeight() / 2;
- float u = (x - cx) / this->getWidth() * 2;
- float v = (y - cy) / this->getHeight() * 2;
+ const float cx = this->get_width() / 2;
+ const float cy = this->get_height() / 2;
+ float u = (x - cx) / this->get_width() * 2;
+ float v = (y - cy) / this->get_height() * 2;
/* When no interpolation/filtering happens in multitex() force nearest interpolation.
* We do it here because (a) we can't easily say multitex() that we want nearest
* interpolation and (b) in such configuration multitex() simply floor's the value
* which often produces artifacts.
*/
- if (m_texture != nullptr && (m_texture->imaflag & TEX_INTERPOL) == 0) {
+ if (texture_ != nullptr && (texture_->imaflag & TEX_INTERPOL) == 0) {
u += 0.5f / cx;
v += 0.5f / cy;
}
- this->m_inputSize->readSampled(textureSize, x, y, sampler);
- this->m_inputOffset->readSampled(textureOffset, x, y, sampler);
+ input_size_->read_sampled(texture_size, x, y, sampler);
+ input_offset_->read_sampled(texture_offset, x, y, sampler);
- vec[0] = textureSize[0] * (u + textureOffset[0]);
- vec[1] = textureSize[1] * (v + textureOffset[1]);
- vec[2] = textureSize[2] * textureOffset[2];
+ vec[0] = texture_size[0] * (u + texture_offset[0]);
+ vec[1] = texture_size[1] * (v + texture_offset[1]);
+ vec[2] = texture_size[2] * texture_offset[2];
const int thread_id = WorkScheduler::current_thread_id();
- retval = multitex_ext(this->m_texture,
- vec,
- nullptr,
- nullptr,
- 0,
- &texres,
- thread_id,
- m_pool,
- m_sceneColorManage,
- false);
+ retval = multitex_ext(
+ texture_, vec, nullptr, nullptr, 0, &texres, thread_id, pool_, scene_color_manage_, false);
output[3] = texres.talpha ? texres.ta : texres.tin;
if (retval & TEX_RGB) {
@@ -158,8 +148,8 @@ void TextureBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- const int op_width = this->getWidth();
- const int op_height = this->getHeight();
+ const int op_width = this->get_width();
+ const int op_height = this->get_height();
const float center_x = op_width / 2;
const float center_y = op_height / 2;
TexResult tex_result = {0};
@@ -176,7 +166,7 @@ void TextureBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
* interpolation and (b) in such configuration multitex() simply floor's the value
* which often produces artifacts.
*/
- if (m_texture != nullptr && (m_texture->imaflag & TEX_INTERPOL) == 0) {
+ if (texture_ != nullptr && (texture_->imaflag & TEX_INTERPOL) == 0) {
u += 0.5f / center_x;
v += 0.5f / center_y;
}
@@ -185,15 +175,15 @@ void TextureBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
vec[1] = tex_size[1] * (v + tex_offset[1]);
vec[2] = tex_size[2] * tex_offset[2];
- const int retval = multitex_ext(this->m_texture,
+ const int retval = multitex_ext(texture_,
vec,
nullptr,
nullptr,
0,
&tex_result,
thread_id,
- m_pool,
- m_sceneColorManage,
+ pool_,
+ scene_color_manage_,
false);
it.out[3] = tex_result.talpha ? tex_result.ta : tex_result.tin;
diff --git a/source/blender/compositor/operations/COM_TextureOperation.h b/source/blender/compositor/operations/COM_TextureOperation.h
index 5bc21da1f96..bf1bb1affb8 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.h
+++ b/source/blender/compositor/operations/COM_TextureOperation.h
@@ -35,12 +35,12 @@ namespace blender::compositor {
*/
class TextureBaseOperation : public MultiThreadedOperation {
private:
- Tex *m_texture;
- const RenderData *m_rd;
- SocketReader *m_inputSize;
- SocketReader *m_inputOffset;
- struct ImagePool *m_pool;
- bool m_sceneColorManage;
+ Tex *texture_;
+ const RenderData *rd_;
+ SocketReader *input_size_;
+ SocketReader *input_offset_;
+ struct ImagePool *pool_;
+ bool scene_color_manage_;
protected:
/**
@@ -54,21 +54,21 @@ class TextureBaseOperation : public MultiThreadedOperation {
TextureBaseOperation();
public:
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void setTexture(Tex *texture)
+ void set_texture(Tex *texture)
{
- this->m_texture = texture;
+ texture_ = texture;
}
- void initExecution() override;
- void deinitExecution() override;
- void setRenderData(const RenderData *rd)
+ void init_execution() override;
+ void deinit_execution() override;
+ void set_render_data(const RenderData *rd)
{
- this->m_rd = rd;
+ rd_ = rd;
}
- void setSceneColorManage(bool sceneColorManage)
+ void set_scene_color_manage(bool scene_color_manage)
{
- this->m_sceneColorManage = sceneColorManage;
+ scene_color_manage_ = scene_color_manage;
}
void update_memory_buffer_partial(MemoryBuffer *output,
@@ -83,7 +83,7 @@ class TextureOperation : public TextureBaseOperation {
class TextureAlphaOperation : public TextureBaseOperation {
public:
TextureAlphaOperation();
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cc b/source/blender/compositor/operations/COM_TonemapOperation.cc
index cb671c54abe..bc370e3496b 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.cc
+++ b/source/blender/compositor/operations/COM_TonemapOperation.cc
@@ -17,10 +17,8 @@
*/
#include "COM_TonemapOperation.h"
-#include "COM_ExecutionSystem.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
+#include "COM_ExecutionSystem.h"
#include "IMB_colormanagement.h"
@@ -28,28 +26,28 @@ namespace blender::compositor {
TonemapOperation::TonemapOperation()
{
- this->addInputSocket(DataType::Color, ResizeMode::Align);
- this->addOutputSocket(DataType::Color);
- this->m_imageReader = nullptr;
- this->m_data = nullptr;
- this->m_cachedInstance = nullptr;
- this->flags.complex = true;
+ this->add_input_socket(DataType::Color, ResizeMode::Align);
+ this->add_output_socket(DataType::Color);
+ image_reader_ = nullptr;
+ data_ = nullptr;
+ cached_instance_ = nullptr;
+ flags_.complex = true;
}
-void TonemapOperation::initExecution()
+void TonemapOperation::init_execution()
{
- this->m_imageReader = this->getInputSocketReader(0);
- NodeOperation::initMutex();
+ image_reader_ = this->get_input_socket_reader(0);
+ NodeOperation::init_mutex();
}
-void TonemapOperation::executePixel(float output[4], int x, int y, void *data)
+void TonemapOperation::execute_pixel(float output[4], int x, int y, void *data)
{
AvgLogLum *avg = (AvgLogLum *)data;
- this->m_imageReader->read(output, x, y, nullptr);
+ image_reader_->read(output, x, y, nullptr);
mul_v3_fl(output, avg->al);
- float dr = output[0] + this->m_data->offset;
- float dg = output[1] + this->m_data->offset;
- float db = output[2] + this->m_data->offset;
+ float dr = output[0] + data_->offset;
+ float dg = output[1] + data_->offset;
+ float db = output[2] + data_->offset;
output[0] /= ((dr == 0.0f) ? 1.0f : dr);
output[1] /= ((dg == 0.0f) ? 1.0f : dg);
output[2] /= ((db == 0.0f) ? 1.0f : db);
@@ -60,16 +58,16 @@ void TonemapOperation::executePixel(float output[4], int x, int y, void *data)
output[2] = powf(MAX2(output[2], 0.0f), igm);
}
}
-void PhotoreceptorTonemapOperation::executePixel(float output[4], int x, int y, void *data)
+void PhotoreceptorTonemapOperation::execute_pixel(float output[4], int x, int y, void *data)
{
AvgLogLum *avg = (AvgLogLum *)data;
- NodeTonemap *ntm = this->m_data;
+ NodeTonemap *ntm = data_;
- const float f = expf(-this->m_data->f);
+ const float f = expf(-data_->f);
const float m = (ntm->m > 0.0f) ? ntm->m : (0.3f + 0.7f * powf(avg->auto_key, 1.4f));
const float ic = 1.0f - ntm->c, ia = 1.0f - ntm->a;
- this->m_imageReader->read(output, x, y, nullptr);
+ image_reader_->read(output, x, y, nullptr);
const float L = IMB_colormanagement_get_luminance(output);
float I_l = output[0] + ic * (L - output[0]);
@@ -86,41 +84,41 @@ void PhotoreceptorTonemapOperation::executePixel(float output[4], int x, int y,
output[2] /= (output[2] + powf(f * I_a, m));
}
-void TonemapOperation::deinitExecution()
+void TonemapOperation::deinit_execution()
{
- this->m_imageReader = nullptr;
- delete this->m_cachedInstance;
- NodeOperation::deinitMutex();
+ image_reader_ = nullptr;
+ delete cached_instance_;
+ NodeOperation::deinit_mutex();
}
-bool TonemapOperation::determineDependingAreaOfInterest(rcti * /*input*/,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool TonemapOperation::determine_depending_area_of_interest(rcti * /*input*/,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti imageInput;
+ rcti image_input;
- NodeOperation *operation = getInputOperation(0);
- imageInput.xmax = operation->getWidth();
- imageInput.xmin = 0;
- imageInput.ymax = operation->getHeight();
- imageInput.ymin = 0;
- if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output)) {
+ NodeOperation *operation = get_input_operation(0);
+ image_input.xmax = operation->get_width();
+ image_input.xmin = 0;
+ image_input.ymax = operation->get_height();
+ image_input.ymin = 0;
+ if (operation->determine_depending_area_of_interest(&image_input, read_operation, output)) {
return true;
}
return false;
}
-void *TonemapOperation::initializeTileData(rcti *rect)
+void *TonemapOperation::initialize_tile_data(rcti *rect)
{
- lockMutex();
- if (this->m_cachedInstance == nullptr) {
- MemoryBuffer *tile = (MemoryBuffer *)this->m_imageReader->initializeTileData(rect);
+ lock_mutex();
+ if (cached_instance_ == nullptr) {
+ MemoryBuffer *tile = (MemoryBuffer *)image_reader_->initialize_tile_data(rect);
AvgLogLum *data = new AvgLogLum();
- float *buffer = tile->getBuffer();
+ float *buffer = tile->get_buffer();
float lsum = 0.0f;
- int p = tile->getWidth() * tile->getHeight();
+ int p = tile->get_width() * tile->get_height();
float *bc = buffer;
float avl, maxl = -1e10f, minl = 1e10f;
const float sc = 1.0f / p;
@@ -142,15 +140,15 @@ void *TonemapOperation::initializeTileData(rcti *rect)
avl = lsum * sc;
data->auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.0f;
float al = exp((double)avl);
- data->al = (al == 0.0f) ? 0.0f : (this->m_data->key / al);
- data->igm = (this->m_data->gamma == 0.0f) ? 1 : (1.0f / this->m_data->gamma);
- this->m_cachedInstance = data;
+ data->al = (al == 0.0f) ? 0.0f : (data_->key / al);
+ data->igm = (data_->gamma == 0.0f) ? 1 : (1.0f / data_->gamma);
+ cached_instance_ = data;
}
- unlockMutex();
- return this->m_cachedInstance;
+ unlock_mutex();
+ return cached_instance_;
}
-void TonemapOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/)
+void TonemapOperation::deinitialize_tile_data(rcti * /*rect*/, void * /*data*/)
{
/* pass */
}
@@ -191,7 +189,7 @@ void TonemapOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output)
const rcti &UNUSED(area),
Span<MemoryBuffer *> inputs)
{
- if (this->m_cachedInstance == nullptr) {
+ if (cached_instance_ == nullptr) {
Luminance lum = {0};
const MemoryBuffer *input = inputs[0];
exec_system_->execute_work<Luminance>(
@@ -215,9 +213,9 @@ void TonemapOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output)
const float avg_log = lum.log_sum / lum.num_pixels;
avg->auto_key = (max_log > min_log) ? ((max_log - avg_log) / (max_log - min_log)) : 1.0f;
const float al = exp((double)avg_log);
- avg->al = (al == 0.0f) ? 0.0f : (this->m_data->key / al);
- avg->igm = (this->m_data->gamma == 0.0f) ? 1 : (1.0f / this->m_data->gamma);
- this->m_cachedInstance = avg;
+ avg->al = (al == 0.0f) ? 0.0f : (data_->key / al);
+ avg->igm = (data_->gamma == 0.0f) ? 1 : (1.0f / data_->gamma);
+ cached_instance_ = avg;
}
}
@@ -225,9 +223,9 @@ void TonemapOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- AvgLogLum *avg = m_cachedInstance;
+ AvgLogLum *avg = cached_instance_;
const float igm = avg->igm;
- const float offset = this->m_data->offset;
+ const float offset = data_->offset;
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
copy_v4_v4(it.out, it.in(0));
mul_v3_fl(it.out, avg->al);
@@ -249,9 +247,9 @@ void PhotoreceptorTonemapOperation::update_memory_buffer_partial(MemoryBuffer *o
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- AvgLogLum *avg = m_cachedInstance;
- NodeTonemap *ntm = this->m_data;
- const float f = expf(-this->m_data->f);
+ AvgLogLum *avg = cached_instance_;
+ NodeTonemap *ntm = data_;
+ const float f = expf(-data_->f);
const float m = (ntm->m > 0.0f) ? ntm->m : (0.3f + 0.7f * powf(avg->auto_key, 1.4f));
const float ic = 1.0f - ntm->c;
const float ia = 1.0f - ntm->a;
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.h b/source/blender/compositor/operations/COM_TonemapOperation.h
index 56b57730ec1..a20c061965e 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.h
+++ b/source/blender/compositor/operations/COM_TonemapOperation.h
@@ -44,17 +44,17 @@ class TonemapOperation : public MultiThreadedOperation {
/**
* \brief Cached reference to the reader
*/
- SocketReader *m_imageReader;
+ SocketReader *image_reader_;
/**
* \brief settings of the Tonemap
*/
- NodeTonemap *m_data;
+ NodeTonemap *data_;
/**
* \brief temporarily cache of the execution storage
*/
- AvgLogLum *m_cachedInstance;
+ AvgLogLum *cached_instance_;
public:
TonemapOperation();
@@ -62,29 +62,29 @@ class TonemapOperation : public MultiThreadedOperation {
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
- void *initializeTileData(rcti *rect) override;
- void deinitializeTileData(rcti *rect, void *data) override;
+ void *initialize_tile_data(rcti *rect) override;
+ void deinitialize_tile_data(rcti *rect, void *data) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void setData(NodeTonemap *data)
+ void set_data(NodeTonemap *data)
{
- this->m_data = data;
+ data_ = data;
}
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_started(MemoryBuffer *output,
@@ -106,7 +106,7 @@ class PhotoreceptorTonemapOperation : public TonemapOperation {
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.cc b/source/blender/compositor/operations/COM_TrackPositionOperation.cc
index 1929c578177..61ce750a2f4 100644
--- a/source/blender/compositor/operations/COM_TrackPositionOperation.cc
+++ b/source/blender/compositor/operations/COM_TrackPositionOperation.cc
@@ -18,11 +18,7 @@
#include "COM_TrackPositionOperation.h"
-#include "MEM_guardedalloc.h"
-
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-#include "BLI_math_color.h"
+#include "DNA_defaults.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
@@ -32,20 +28,20 @@ namespace blender::compositor {
TrackPositionOperation::TrackPositionOperation()
{
- this->addOutputSocket(DataType::Value);
- this->m_movieClip = nullptr;
- this->m_framenumber = 0;
- this->m_trackingObjectName[0] = 0;
- this->m_trackName[0] = 0;
- this->m_axis = 0;
- this->m_position = CMP_TRACKPOS_ABSOLUTE;
- this->m_relativeFrame = 0;
- this->m_speed_output = false;
- flags.is_set_operation = true;
+ this->add_output_socket(DataType::Value);
+ movie_clip_ = nullptr;
+ framenumber_ = 0;
+ tracking_object_name_[0] = 0;
+ track_name_[0] = 0;
+ axis_ = 0;
+ position_ = CMP_TRACKPOS_ABSOLUTE;
+ relative_frame_ = 0;
+ speed_output_ = false;
+ flags_.is_set_operation = true;
is_track_position_calculated_ = false;
}
-void TrackPositionOperation::initExecution()
+void TrackPositionOperation::init_execution()
{
if (!is_track_position_calculated_) {
calc_track_position();
@@ -56,96 +52,95 @@ void TrackPositionOperation::calc_track_position()
{
is_track_position_calculated_ = true;
MovieTracking *tracking = nullptr;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
MovieTrackingObject *object;
track_position_ = 0;
- zero_v2(this->m_markerPos);
- zero_v2(this->m_relativePos);
+ zero_v2(marker_pos_);
+ zero_v2(relative_pos_);
- if (!this->m_movieClip) {
+ if (!movie_clip_) {
return;
}
- tracking = &this->m_movieClip->tracking;
+ tracking = &movie_clip_->tracking;
- BKE_movieclip_user_set_frame(&user, this->m_framenumber);
- BKE_movieclip_get_size(this->m_movieClip, &user, &this->m_width, &this->m_height);
+ BKE_movieclip_user_set_frame(&user, framenumber_);
+ BKE_movieclip_get_size(movie_clip_, &user, &width_, &height_);
- object = BKE_tracking_object_get_named(tracking, this->m_trackingObjectName);
+ object = BKE_tracking_object_get_named(tracking, tracking_object_name_);
if (object) {
MovieTrackingTrack *track;
- track = BKE_tracking_track_get_named(tracking, object, this->m_trackName);
+ track = BKE_tracking_track_get_named(tracking, object, track_name_);
if (track) {
MovieTrackingMarker *marker;
- int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip,
- this->m_framenumber);
+ int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(movie_clip_, framenumber_);
marker = BKE_tracking_marker_get(track, clip_framenr);
- copy_v2_v2(this->m_markerPos, marker->pos);
+ copy_v2_v2(marker_pos_, marker->pos);
- if (this->m_speed_output) {
- int relative_clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip,
- this->m_relativeFrame);
+ if (speed_output_) {
+ int relative_clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(movie_clip_,
+ relative_frame_);
marker = BKE_tracking_marker_get_exact(track, relative_clip_framenr);
if (marker != nullptr && (marker->flag & MARKER_DISABLED) == 0) {
- copy_v2_v2(this->m_relativePos, marker->pos);
+ copy_v2_v2(relative_pos_, marker->pos);
}
else {
- copy_v2_v2(this->m_relativePos, this->m_markerPos);
+ copy_v2_v2(relative_pos_, marker_pos_);
}
- if (this->m_relativeFrame < this->m_framenumber) {
- swap_v2_v2(this->m_relativePos, this->m_markerPos);
+ if (relative_frame_ < framenumber_) {
+ swap_v2_v2(relative_pos_, marker_pos_);
}
}
- else if (this->m_position == CMP_TRACKPOS_RELATIVE_START) {
+ else if (position_ == CMP_TRACKPOS_RELATIVE_START) {
int i;
for (i = 0; i < track->markersnr; i++) {
marker = &track->markers[i];
if ((marker->flag & MARKER_DISABLED) == 0) {
- copy_v2_v2(this->m_relativePos, marker->pos);
+ copy_v2_v2(relative_pos_, marker->pos);
break;
}
}
}
- else if (this->m_position == CMP_TRACKPOS_RELATIVE_FRAME) {
- int relative_clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip,
- this->m_relativeFrame);
+ else if (position_ == CMP_TRACKPOS_RELATIVE_FRAME) {
+ int relative_clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(movie_clip_,
+ relative_frame_);
marker = BKE_tracking_marker_get(track, relative_clip_framenr);
- copy_v2_v2(this->m_relativePos, marker->pos);
+ copy_v2_v2(relative_pos_, marker->pos);
}
}
}
- track_position_ = this->m_markerPos[this->m_axis] - this->m_relativePos[this->m_axis];
- if (this->m_axis == 0) {
- track_position_ *= this->m_width;
+ track_position_ = marker_pos_[axis_] - relative_pos_[axis_];
+ if (axis_ == 0) {
+ track_position_ *= width_;
}
else {
- track_position_ *= this->m_height;
+ track_position_ *= height_;
}
}
-void TrackPositionOperation::executePixelSampled(float output[4],
- float /*x*/,
- float /*y*/,
- PixelSampler /*sampler*/)
+void TrackPositionOperation::execute_pixel_sampled(float output[4],
+ float /*x*/,
+ float /*y*/,
+ PixelSampler /*sampler*/)
{
- output[0] = this->m_markerPos[this->m_axis] - this->m_relativePos[this->m_axis];
+ output[0] = marker_pos_[axis_] - relative_pos_[axis_];
- if (this->m_axis == 0) {
- output[0] *= this->m_width;
+ if (axis_ == 0) {
+ output[0] *= width_;
}
else {
- output[0] *= this->m_height;
+ output[0] *= height_;
}
}
diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.h b/source/blender/compositor/operations/COM_TrackPositionOperation.h
index a47d3e03ed4..1de8b72f783 100644
--- a/source/blender/compositor/operations/COM_TrackPositionOperation.h
+++ b/source/blender/compositor/operations/COM_TrackPositionOperation.h
@@ -35,18 +35,18 @@ namespace blender::compositor {
*/
class TrackPositionOperation : public ConstantOperation {
protected:
- MovieClip *m_movieClip;
- int m_framenumber;
- char m_trackingObjectName[64];
- char m_trackName[64];
- int m_axis;
- int m_position;
- int m_relativeFrame;
- bool m_speed_output;
-
- int m_width, m_height;
- float m_markerPos[2];
- float m_relativePos[2];
+ MovieClip *movie_clip_;
+ int framenumber_;
+ char tracking_object_name_[64];
+ char track_name_[64];
+ int axis_;
+ int position_;
+ int relative_frame_;
+ bool speed_output_;
+
+ int width_, height_;
+ float marker_pos_[2];
+ float relative_pos_[2];
float track_position_;
bool is_track_position_calculated_;
@@ -58,42 +58,42 @@ class TrackPositionOperation : public ConstantOperation {
public:
TrackPositionOperation();
- void setMovieClip(MovieClip *clip)
+ void set_movie_clip(MovieClip *clip)
{
- this->m_movieClip = clip;
+ movie_clip_ = clip;
}
- void setTrackingObject(char *object)
+ void set_tracking_object(char *object)
{
- BLI_strncpy(this->m_trackingObjectName, object, sizeof(this->m_trackingObjectName));
+ BLI_strncpy(tracking_object_name_, object, sizeof(tracking_object_name_));
}
- void setTrackName(char *track)
+ void set_track_name(char *track)
{
- BLI_strncpy(this->m_trackName, track, sizeof(this->m_trackName));
+ BLI_strncpy(track_name_, track, sizeof(track_name_));
}
- void setFramenumber(int framenumber)
+ void set_framenumber(int framenumber)
{
- this->m_framenumber = framenumber;
+ framenumber_ = framenumber;
}
- void setAxis(int value)
+ void set_axis(int value)
{
- this->m_axis = value;
+ axis_ = value;
}
- void setPosition(int value)
+ void set_position(int value)
{
- this->m_position = value;
+ position_ = value;
}
- void setRelativeFrame(int value)
+ void set_relative_frame(int value)
{
- this->m_relativeFrame = value;
+ relative_frame_ = value;
}
- void setSpeedOutput(bool speed_output)
+ void set_speed_output(bool speed_output)
{
- this->m_speed_output = speed_output;
+ speed_output_ = speed_output;
}
- void initExecution() override;
+ void init_execution() override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
const float *get_constant_elem() override;
diff --git a/source/blender/compositor/operations/COM_TransformOperation.cc b/source/blender/compositor/operations/COM_TransformOperation.cc
index 5f6e9ed4d21..f18e7e44094 100644
--- a/source/blender/compositor/operations/COM_TransformOperation.cc
+++ b/source/blender/compositor/operations/COM_TransformOperation.cc
@@ -17,22 +17,19 @@
*/
#include "COM_TransformOperation.h"
-#include "COM_ConstantOperation.h"
#include "COM_RotateOperation.h"
#include "COM_ScaleOperation.h"
-#include "BLI_math.h"
-
namespace blender::compositor {
TransformOperation::TransformOperation()
{
- addInputSocket(DataType::Color, ResizeMode::None);
- addInputSocket(DataType::Value, ResizeMode::None);
- addInputSocket(DataType::Value, ResizeMode::None);
- addInputSocket(DataType::Value, ResizeMode::None);
- addInputSocket(DataType::Value, ResizeMode::None);
- addOutputSocket(DataType::Color);
+ add_input_socket(DataType::Color, ResizeMode::None);
+ add_input_socket(DataType::Value, ResizeMode::None);
+ add_input_socket(DataType::Value, ResizeMode::None);
+ add_input_socket(DataType::Value, ResizeMode::None);
+ add_input_socket(DataType::Value, ResizeMode::None);
+ add_output_socket(DataType::Color);
translate_factor_x_ = 1.0f;
translate_factor_y_ = 1.0f;
convert_degree_to_rad_ = false;
@@ -126,14 +123,14 @@ void TransformOperation::update_memory_buffer_partial(MemoryBuffer *output,
void TransformOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
const bool image_determined =
- getInputSocket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
+ get_input_socket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
if (image_determined) {
rcti image_canvas = r_area;
- rcti unused;
- getInputSocket(X_INPUT_INDEX)->determine_canvas(image_canvas, unused);
- getInputSocket(Y_INPUT_INDEX)->determine_canvas(image_canvas, unused);
- getInputSocket(DEGREE_INPUT_INDEX)->determine_canvas(image_canvas, unused);
- getInputSocket(SCALE_INPUT_INDEX)->determine_canvas(image_canvas, unused);
+ rcti unused = COM_AREA_NONE;
+ get_input_socket(X_INPUT_INDEX)->determine_canvas(image_canvas, unused);
+ get_input_socket(Y_INPUT_INDEX)->determine_canvas(image_canvas, unused);
+ get_input_socket(DEGREE_INPUT_INDEX)->determine_canvas(image_canvas, unused);
+ get_input_socket(SCALE_INPUT_INDEX)->determine_canvas(image_canvas, unused);
init_data();
if (invert_) {
@@ -174,7 +171,6 @@ void TransformOperation::determine_canvas(const rcti &preferred_area, rcti &r_ar
}
}
-/** Translate -> Rotate -> Scale. */
void TransformOperation::transform(BuffersIterator<float> &it, const MemoryBuffer *input_img)
{
float rotate_center_x, rotate_center_y;
@@ -201,7 +197,6 @@ void TransformOperation::transform(BuffersIterator<float> &it, const MemoryBuffe
}
}
-/** Scale -> Rotate -> Translate. */
void TransformOperation::transform_inverted(BuffersIterator<float> &it,
const MemoryBuffer *input_img)
{
diff --git a/source/blender/compositor/operations/COM_TransformOperation.h b/source/blender/compositor/operations/COM_TransformOperation.h
index 3c5584a1bea..4db2145cc2d 100644
--- a/source/blender/compositor/operations/COM_TransformOperation.h
+++ b/source/blender/compositor/operations/COM_TransformOperation.h
@@ -35,9 +35,9 @@ class TransformOperation : public MultiThreadedOperation {
int translate_x_;
int translate_y_;
float scale_;
- rcti scale_canvas_;
- rcti rotate_canvas_;
- rcti translate_canvas_;
+ rcti scale_canvas_ = COM_AREA_NONE;
+ rcti rotate_canvas_ = COM_AREA_NONE;
+ rcti translate_canvas_ = COM_AREA_NONE;
/* Set variables. */
PixelSampler sampler_;
@@ -82,7 +82,9 @@ class TransformOperation : public MultiThreadedOperation {
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
private:
+ /** Translate -> Rotate -> Scale. */
void transform(BuffersIterator<float> &it, const MemoryBuffer *input_img);
+ /** Scale -> Rotate -> Translate. */
void transform_inverted(BuffersIterator<float> &it, const MemoryBuffer *input_img);
};
diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cc b/source/blender/compositor/operations/COM_TranslateOperation.cc
index 9868f21654e..d3c87b09fb7 100644
--- a/source/blender/compositor/operations/COM_TranslateOperation.cc
+++ b/source/blender/compositor/operations/COM_TranslateOperation.cc
@@ -25,68 +25,68 @@ TranslateOperation::TranslateOperation() : TranslateOperation(DataType::Color)
}
TranslateOperation::TranslateOperation(DataType data_type, ResizeMode resize_mode)
{
- this->addInputSocket(data_type, resize_mode);
- this->addInputSocket(DataType::Value, ResizeMode::None);
- this->addInputSocket(DataType::Value, ResizeMode::None);
- this->addOutputSocket(data_type);
+ this->add_input_socket(data_type, resize_mode);
+ this->add_input_socket(DataType::Value, ResizeMode::None);
+ this->add_input_socket(DataType::Value, ResizeMode::None);
+ this->add_output_socket(data_type);
this->set_canvas_input_index(0);
- this->m_inputOperation = nullptr;
- this->m_inputXOperation = nullptr;
- this->m_inputYOperation = nullptr;
- this->m_isDeltaSet = false;
- this->m_factorX = 1.0f;
- this->m_factorY = 1.0f;
+ input_operation_ = nullptr;
+ input_xoperation_ = nullptr;
+ input_yoperation_ = nullptr;
+ is_delta_set_ = false;
+ factor_x_ = 1.0f;
+ factor_y_ = 1.0f;
this->x_extend_mode_ = MemoryBufferExtend::Clip;
this->y_extend_mode_ = MemoryBufferExtend::Clip;
}
-void TranslateOperation::initExecution()
+void TranslateOperation::init_execution()
{
- this->m_inputOperation = this->getInputSocketReader(0);
- this->m_inputXOperation = this->getInputSocketReader(1);
- this->m_inputYOperation = this->getInputSocketReader(2);
+ input_operation_ = this->get_input_socket_reader(0);
+ input_xoperation_ = this->get_input_socket_reader(1);
+ input_yoperation_ = this->get_input_socket_reader(2);
}
-void TranslateOperation::deinitExecution()
+void TranslateOperation::deinit_execution()
{
- this->m_inputOperation = nullptr;
- this->m_inputXOperation = nullptr;
- this->m_inputYOperation = nullptr;
+ input_operation_ = nullptr;
+ input_xoperation_ = nullptr;
+ input_yoperation_ = nullptr;
}
-void TranslateOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler /*sampler*/)
+void TranslateOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
- ensureDelta();
+ ensure_delta();
- float originalXPos = x - this->getDeltaX();
- float originalYPos = y - this->getDeltaY();
+ float original_xpos = x - this->getDeltaX();
+ float original_ypos = y - this->getDeltaY();
- this->m_inputOperation->readSampled(output, originalXPos, originalYPos, PixelSampler::Bilinear);
+ input_operation_->read_sampled(output, original_xpos, original_ypos, PixelSampler::Bilinear);
}
-bool TranslateOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool TranslateOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti newInput;
+ rcti new_input;
- ensureDelta();
+ ensure_delta();
- newInput.xmin = input->xmin - this->getDeltaX();
- newInput.xmax = input->xmax - this->getDeltaX();
- newInput.ymin = input->ymin - this->getDeltaY();
- newInput.ymax = input->ymax - this->getDeltaY();
+ new_input.xmin = input->xmin - this->getDeltaX();
+ new_input.xmax = input->xmax - this->getDeltaX();
+ new_input.ymin = input->ymin - this->getDeltaY();
+ new_input.ymax = input->ymax - this->getDeltaY();
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
void TranslateOperation::setFactorXY(float factorX, float factorY)
{
- m_factorX = factorX;
- m_factorY = factorY;
+ factor_x_ = factorX;
+ factor_y_ = factorY;
}
void TranslateOperation::set_wrapping(int wrapping_type)
@@ -112,7 +112,7 @@ void TranslateOperation::get_area_of_interest(const int input_idx,
rcti &r_input_area)
{
if (input_idx == 0) {
- ensureDelta();
+ ensure_delta();
r_input_area = output_area;
if (x_extend_mode_ == MemoryBufferExtend::Clip) {
const int delta_x = this->getDeltaX();
@@ -154,15 +154,15 @@ TranslateCanvasOperation::TranslateCanvasOperation()
void TranslateCanvasOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
const bool determined =
- getInputSocket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
+ get_input_socket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
if (determined) {
- NodeOperationInput *x_socket = getInputSocket(X_INPUT_INDEX);
- NodeOperationInput *y_socket = getInputSocket(Y_INPUT_INDEX);
- rcti unused;
+ NodeOperationInput *x_socket = get_input_socket(X_INPUT_INDEX);
+ NodeOperationInput *y_socket = get_input_socket(Y_INPUT_INDEX);
+ rcti unused = COM_AREA_NONE;
x_socket->determine_canvas(r_area, unused);
y_socket->determine_canvas(r_area, unused);
- ensureDelta();
+ ensure_delta();
const float delta_x = x_extend_mode_ == MemoryBufferExtend::Clip ? getDeltaX() : 0.0f;
const float delta_y = y_extend_mode_ == MemoryBufferExtend::Clip ? getDeltaY() : 0.0f;
BLI_rcti_translate(&r_area, delta_x, delta_y);
diff --git a/source/blender/compositor/operations/COM_TranslateOperation.h b/source/blender/compositor/operations/COM_TranslateOperation.h
index c5a3d1ffd99..30e489bf395 100644
--- a/source/blender/compositor/operations/COM_TranslateOperation.h
+++ b/source/blender/compositor/operations/COM_TranslateOperation.h
@@ -30,14 +30,14 @@ class TranslateOperation : public MultiThreadedOperation {
static constexpr int Y_INPUT_INDEX = 2;
private:
- SocketReader *m_inputOperation;
- SocketReader *m_inputXOperation;
- SocketReader *m_inputYOperation;
- float m_deltaX;
- float m_deltaY;
- bool m_isDeltaSet;
- float m_factorX;
- float m_factorY;
+ SocketReader *input_operation_;
+ SocketReader *input_xoperation_;
+ SocketReader *input_yoperation_;
+ float delta_x_;
+ float delta_y_;
+ bool is_delta_set_;
+ float factor_x_;
+ float factor_y_;
protected:
MemoryBufferExtend x_extend_mode_;
@@ -46,39 +46,39 @@ class TranslateOperation : public MultiThreadedOperation {
public:
TranslateOperation();
TranslateOperation(DataType data_type, ResizeMode mode = ResizeMode::Center);
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
float getDeltaX()
{
- return this->m_deltaX * this->m_factorX;
+ return delta_x_ * factor_x_;
}
float getDeltaY()
{
- return this->m_deltaY * this->m_factorY;
+ return delta_y_ * factor_y_;
}
- inline void ensureDelta()
+ inline void ensure_delta()
{
- if (!this->m_isDeltaSet) {
+ if (!is_delta_set_) {
if (execution_model_ == eExecutionModel::Tiled) {
- float tempDelta[4];
- this->m_inputXOperation->readSampled(tempDelta, 0, 0, PixelSampler::Nearest);
- this->m_deltaX = tempDelta[0];
- this->m_inputYOperation->readSampled(tempDelta, 0, 0, PixelSampler::Nearest);
- this->m_deltaY = tempDelta[0];
+ float temp_delta[4];
+ input_xoperation_->read_sampled(temp_delta, 0, 0, PixelSampler::Nearest);
+ delta_x_ = temp_delta[0];
+ input_yoperation_->read_sampled(temp_delta, 0, 0, PixelSampler::Nearest);
+ delta_y_ = temp_delta[0];
}
else {
- m_deltaX = get_input_operation(X_INPUT_INDEX)->get_constant_value_default(0.0f);
- m_deltaY = get_input_operation(Y_INPUT_INDEX)->get_constant_value_default(0.0f);
+ delta_x_ = get_input_operation(X_INPUT_INDEX)->get_constant_value_default(0.0f);
+ delta_y_ = get_input_operation(Y_INPUT_INDEX)->get_constant_value_default(0.0f);
}
- this->m_isDeltaSet = true;
+ is_delta_set_ = true;
}
}
diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc
index c524447a4fa..86bc6d0041a 100644
--- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc
@@ -17,139 +17,135 @@
*/
#include "COM_VariableSizeBokehBlurOperation.h"
-#include "BLI_math.h"
-#include "COM_ExecutionSystem.h"
#include "COM_OpenCLDevice.h"
-#include "RE_pipeline.h"
-
namespace blender::compositor {
VariableSizeBokehBlurOperation::VariableSizeBokehBlurOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Color, ResizeMode::Align); /* Do not resize the bokeh image. */
- this->addInputSocket(DataType::Value); /* Radius. */
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Color, ResizeMode::Align); /* Do not resize the bokeh image. */
+ this->add_input_socket(DataType::Value); /* Radius. */
#ifdef COM_DEFOCUS_SEARCH
/* Inverse search radius optimization structure. */
- this->addInputSocket(DataType::Color, ResizeMode::None);
+ this->add_input_socket(DataType::Color, ResizeMode::None);
#endif
- this->addOutputSocket(DataType::Color);
- flags.complex = true;
- flags.open_cl = true;
-
- this->m_inputProgram = nullptr;
- this->m_inputBokehProgram = nullptr;
- this->m_inputSizeProgram = nullptr;
- this->m_maxBlur = 32.0f;
- this->m_threshold = 1.0f;
- this->m_do_size_scale = false;
+ this->add_output_socket(DataType::Color);
+ flags_.complex = true;
+ flags_.open_cl = true;
+
+ input_program_ = nullptr;
+ input_bokeh_program_ = nullptr;
+ input_size_program_ = nullptr;
+ max_blur_ = 32.0f;
+ threshold_ = 1.0f;
+ do_size_scale_ = false;
#ifdef COM_DEFOCUS_SEARCH
- this->m_inputSearchProgram = nullptr;
+ input_search_program_ = nullptr;
#endif
}
-void VariableSizeBokehBlurOperation::initExecution()
+void VariableSizeBokehBlurOperation::init_execution()
{
- this->m_inputProgram = getInputSocketReader(0);
- this->m_inputBokehProgram = getInputSocketReader(1);
- this->m_inputSizeProgram = getInputSocketReader(2);
+ input_program_ = get_input_socket_reader(0);
+ input_bokeh_program_ = get_input_socket_reader(1);
+ input_size_program_ = get_input_socket_reader(2);
#ifdef COM_DEFOCUS_SEARCH
- this->m_inputSearchProgram = getInputSocketReader(3);
+ input_search_program_ = get_input_socket_reader(3);
#endif
- QualityStepHelper::initExecution(COM_QH_INCREASE);
+ QualityStepHelper::init_execution(COM_QH_INCREASE);
}
struct VariableSizeBokehBlurTileData {
MemoryBuffer *color;
MemoryBuffer *bokeh;
MemoryBuffer *size;
- int maxBlurScalar;
+ int max_blur_scalar;
};
-void *VariableSizeBokehBlurOperation::initializeTileData(rcti *rect)
+void *VariableSizeBokehBlurOperation::initialize_tile_data(rcti *rect)
{
VariableSizeBokehBlurTileData *data = new VariableSizeBokehBlurTileData();
- data->color = (MemoryBuffer *)this->m_inputProgram->initializeTileData(rect);
- data->bokeh = (MemoryBuffer *)this->m_inputBokehProgram->initializeTileData(rect);
- data->size = (MemoryBuffer *)this->m_inputSizeProgram->initializeTileData(rect);
+ data->color = (MemoryBuffer *)input_program_->initialize_tile_data(rect);
+ data->bokeh = (MemoryBuffer *)input_bokeh_program_->initialize_tile_data(rect);
+ data->size = (MemoryBuffer *)input_size_program_->initialize_tile_data(rect);
- rcti rect2;
- this->determineDependingAreaOfInterest(
- rect, (ReadBufferOperation *)this->m_inputSizeProgram, &rect2);
+ rcti rect2 = COM_AREA_NONE;
+ this->determine_depending_area_of_interest(
+ rect, (ReadBufferOperation *)input_size_program_, &rect2);
- const float max_dim = MAX2(this->getWidth(), this->getHeight());
- const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
+ const float max_dim = MAX2(this->get_width(), this->get_height());
+ const float scalar = do_size_scale_ ? (max_dim / 100.0f) : 1.0f;
- data->maxBlurScalar = (int)(data->size->get_max_value(rect2) * scalar);
- CLAMP(data->maxBlurScalar, 1.0f, this->m_maxBlur);
+ data->max_blur_scalar = (int)(data->size->get_max_value(rect2) * scalar);
+ CLAMP(data->max_blur_scalar, 1.0f, max_blur_);
return data;
}
-void VariableSizeBokehBlurOperation::deinitializeTileData(rcti * /*rect*/, void *data)
+void VariableSizeBokehBlurOperation::deinitialize_tile_data(rcti * /*rect*/, void *data)
{
VariableSizeBokehBlurTileData *result = (VariableSizeBokehBlurTileData *)data;
delete result;
}
-void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
+void VariableSizeBokehBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
{
- VariableSizeBokehBlurTileData *tileData = (VariableSizeBokehBlurTileData *)data;
- MemoryBuffer *inputProgramBuffer = tileData->color;
- MemoryBuffer *inputBokehBuffer = tileData->bokeh;
- MemoryBuffer *inputSizeBuffer = tileData->size;
- float *inputSizeFloatBuffer = inputSizeBuffer->getBuffer();
- float *inputProgramFloatBuffer = inputProgramBuffer->getBuffer();
- float readColor[4];
+ VariableSizeBokehBlurTileData *tile_data = (VariableSizeBokehBlurTileData *)data;
+ MemoryBuffer *input_program_buffer = tile_data->color;
+ MemoryBuffer *input_bokeh_buffer = tile_data->bokeh;
+ MemoryBuffer *input_size_buffer = tile_data->size;
+ float *input_size_float_buffer = input_size_buffer->get_buffer();
+ float *input_program_float_buffer = input_program_buffer->get_buffer();
+ float read_color[4];
float bokeh[4];
- float tempSize[4];
+ float temp_size[4];
float multiplier_accum[4];
float color_accum[4];
- const float max_dim = MAX2(getWidth(), getHeight());
- const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
- int maxBlurScalar = tileData->maxBlurScalar;
+ const float max_dim = MAX2(get_width(), get_height());
+ const float scalar = do_size_scale_ ? (max_dim / 100.0f) : 1.0f;
+ int max_blur_scalar = tile_data->max_blur_scalar;
- BLI_assert(inputBokehBuffer->getWidth() == COM_BLUR_BOKEH_PIXELS);
- BLI_assert(inputBokehBuffer->getHeight() == COM_BLUR_BOKEH_PIXELS);
+ BLI_assert(input_bokeh_buffer->get_width() == COM_BLUR_BOKEH_PIXELS);
+ BLI_assert(input_bokeh_buffer->get_height() == COM_BLUR_BOKEH_PIXELS);
#ifdef COM_DEFOCUS_SEARCH
float search[4];
- this->m_inputSearchProgram->read(search,
- x / InverseSearchRadiusOperation::DIVIDER,
- y / InverseSearchRadiusOperation::DIVIDER,
- nullptr);
+ input_search_program_->read(search,
+ x / InverseSearchRadiusOperation::DIVIDER,
+ y / InverseSearchRadiusOperation::DIVIDER,
+ nullptr);
int minx = search[0];
int miny = search[1];
int maxx = search[2];
int maxy = search[3];
#else
- int minx = MAX2(x - maxBlurScalar, 0);
- int miny = MAX2(y - maxBlurScalar, 0);
- int maxx = MIN2(x + maxBlurScalar, (int)getWidth());
- int maxy = MIN2(y + maxBlurScalar, (int)getHeight());
+ int minx = MAX2(x - max_blur_scalar, 0);
+ int miny = MAX2(y - max_blur_scalar, 0);
+ int maxx = MIN2(x + max_blur_scalar, (int)get_width());
+ int maxy = MIN2(y + max_blur_scalar, (int)get_height());
#endif
{
- inputSizeBuffer->readNoCheck(tempSize, x, y);
- inputProgramBuffer->readNoCheck(readColor, x, y);
+ input_size_buffer->read_no_check(temp_size, x, y);
+ input_program_buffer->read_no_check(read_color, x, y);
- copy_v4_v4(color_accum, readColor);
+ copy_v4_v4(color_accum, read_color);
copy_v4_fl(multiplier_accum, 1.0f);
- float size_center = tempSize[0] * scalar;
+ float size_center = temp_size[0] * scalar;
- const int addXStepValue = QualityStepHelper::getStep();
- const int addYStepValue = addXStepValue;
- const int addXStepColor = addXStepValue * COM_DATA_TYPE_COLOR_CHANNELS;
+ const int add_xstep_value = QualityStepHelper::get_step();
+ const int add_ystep_value = add_xstep_value;
+ const int add_xstep_color = add_xstep_value * COM_DATA_TYPE_COLOR_CHANNELS;
- if (size_center > this->m_threshold) {
- for (int ny = miny; ny < maxy; ny += addYStepValue) {
+ if (size_center > threshold_) {
+ for (int ny = miny; ny < maxy; ny += add_ystep_value) {
float dy = ny - y;
- int offsetValueNy = ny * inputSizeBuffer->getWidth();
- int offsetValueNxNy = offsetValueNy + (minx);
- int offsetColorNxNy = offsetValueNxNy * COM_DATA_TYPE_COLOR_CHANNELS;
- for (int nx = minx; nx < maxx; nx += addXStepValue) {
+ int offset_value_ny = ny * input_size_buffer->get_width();
+ int offset_value_nx_ny = offset_value_ny + (minx);
+ int offset_color_nx_ny = offset_value_nx_ny * COM_DATA_TYPE_COLOR_CHANNELS;
+ for (int nx = minx; nx < maxx; nx += add_xstep_value) {
if (nx != x || ny != y) {
- float size = MIN2(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center);
- if (size > this->m_threshold) {
+ float size = MIN2(input_size_float_buffer[offset_value_nx_ny] * scalar, size_center);
+ if (size > threshold_) {
float dx = nx - x;
if (size > fabsf(dx) && size > fabsf(dy)) {
float uv[2] = {
@@ -158,14 +154,14 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y,
(float)(COM_BLUR_BOKEH_PIXELS / 2) +
(dy / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1),
};
- inputBokehBuffer->read(bokeh, uv[0], uv[1]);
- madd_v4_v4v4(color_accum, bokeh, &inputProgramFloatBuffer[offsetColorNxNy]);
+ input_bokeh_buffer->read(bokeh, uv[0], uv[1]);
+ madd_v4_v4v4(color_accum, bokeh, &input_program_float_buffer[offset_color_nx_ny]);
add_v4_v4(multiplier_accum, bokeh);
}
}
}
- offsetColorNxNy += addXStepColor;
- offsetValueNxNy += addXStepValue;
+ offset_color_nx_ny += add_xstep_color;
+ offset_value_nx_ny += add_xstep_value;
}
}
}
@@ -176,102 +172,105 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y,
output[3] = color_accum[3] / multiplier_accum[3];
/* blend in out values over the threshold, otherwise we get sharp, ugly transitions */
- if ((size_center > this->m_threshold) && (size_center < this->m_threshold * 2.0f)) {
+ if ((size_center > threshold_) && (size_center < threshold_ * 2.0f)) {
/* factor from 0-1 */
- float fac = (size_center - this->m_threshold) / this->m_threshold;
- interp_v4_v4v4(output, readColor, output, fac);
+ float fac = (size_center - threshold_) / threshold_;
+ interp_v4_v4v4(output, read_color, output, fac);
}
}
}
-void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer,
- cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers,
- std::list<cl_mem> *clMemToCleanUp,
- std::list<cl_kernel> * /*clKernelsToCleanUp*/)
+void VariableSizeBokehBlurOperation::execute_opencl(
+ OpenCLDevice *device,
+ MemoryBuffer *output_memory_buffer,
+ cl_mem cl_output_buffer,
+ MemoryBuffer **input_memory_buffers,
+ std::list<cl_mem> *cl_mem_to_clean_up,
+ std::list<cl_kernel> * /*cl_kernels_to_clean_up*/)
{
- cl_kernel defocusKernel = device->COM_clCreateKernel("defocusKernel", nullptr);
-
- cl_int step = this->getStep();
- cl_int maxBlur;
- cl_float threshold = this->m_threshold;
-
- MemoryBuffer *sizeMemoryBuffer = this->m_inputSizeProgram->getInputMemoryBuffer(
- inputMemoryBuffers);
-
- const float max_dim = MAX2(getWidth(), getHeight());
- cl_float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
-
- maxBlur = (cl_int)min_ff(sizeMemoryBuffer->get_max_value() * scalar, (float)this->m_maxBlur);
-
- device->COM_clAttachMemoryBufferToKernelParameter(
- defocusKernel, 0, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram);
- device->COM_clAttachMemoryBufferToKernelParameter(
- defocusKernel, 1, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputBokehProgram);
- device->COM_clAttachMemoryBufferToKernelParameter(
- defocusKernel, 2, 4, clMemToCleanUp, inputMemoryBuffers, this->m_inputSizeProgram);
- device->COM_clAttachOutputMemoryBufferToKernelParameter(defocusKernel, 3, clOutputBuffer);
- device->COM_clAttachMemoryBufferOffsetToKernelParameter(defocusKernel, 5, outputMemoryBuffer);
- clSetKernelArg(defocusKernel, 6, sizeof(cl_int), &step);
- clSetKernelArg(defocusKernel, 7, sizeof(cl_int), &maxBlur);
- clSetKernelArg(defocusKernel, 8, sizeof(cl_float), &threshold);
- clSetKernelArg(defocusKernel, 9, sizeof(cl_float), &scalar);
- device->COM_clAttachSizeToKernelParameter(defocusKernel, 10, this);
-
- device->COM_clEnqueueRange(defocusKernel, outputMemoryBuffer, 11, this);
+ cl_kernel defocus_kernel = device->COM_cl_create_kernel("defocus_kernel", nullptr);
+
+ cl_int step = this->get_step();
+ cl_int max_blur;
+ cl_float threshold = threshold_;
+
+ MemoryBuffer *size_memory_buffer = input_size_program_->get_input_memory_buffer(
+ input_memory_buffers);
+
+ const float max_dim = MAX2(get_width(), get_height());
+ cl_float scalar = do_size_scale_ ? (max_dim / 100.0f) : 1.0f;
+
+ max_blur = (cl_int)min_ff(size_memory_buffer->get_max_value() * scalar, (float)max_blur_);
+
+ device->COM_cl_attach_memory_buffer_to_kernel_parameter(
+ defocus_kernel, 0, -1, cl_mem_to_clean_up, input_memory_buffers, input_program_);
+ device->COM_cl_attach_memory_buffer_to_kernel_parameter(
+ defocus_kernel, 1, -1, cl_mem_to_clean_up, input_memory_buffers, input_bokeh_program_);
+ device->COM_cl_attach_memory_buffer_to_kernel_parameter(
+ defocus_kernel, 2, 4, cl_mem_to_clean_up, input_memory_buffers, input_size_program_);
+ device->COM_cl_attach_output_memory_buffer_to_kernel_parameter(
+ defocus_kernel, 3, cl_output_buffer);
+ device->COM_cl_attach_memory_buffer_offset_to_kernel_parameter(
+ defocus_kernel, 5, output_memory_buffer);
+ clSetKernelArg(defocus_kernel, 6, sizeof(cl_int), &step);
+ clSetKernelArg(defocus_kernel, 7, sizeof(cl_int), &max_blur);
+ clSetKernelArg(defocus_kernel, 8, sizeof(cl_float), &threshold);
+ clSetKernelArg(defocus_kernel, 9, sizeof(cl_float), &scalar);
+ device->COM_cl_attach_size_to_kernel_parameter(defocus_kernel, 10, this);
+
+ device->COM_cl_enqueue_range(defocus_kernel, output_memory_buffer, 11, this);
}
-void VariableSizeBokehBlurOperation::deinitExecution()
+void VariableSizeBokehBlurOperation::deinit_execution()
{
- this->m_inputProgram = nullptr;
- this->m_inputBokehProgram = nullptr;
- this->m_inputSizeProgram = nullptr;
+ input_program_ = nullptr;
+ input_bokeh_program_ = nullptr;
+ input_size_program_ = nullptr;
#ifdef COM_DEFOCUS_SEARCH
- this->m_inputSearchProgram = nullptr;
+ input_search_program_ = nullptr;
#endif
}
-bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest(
- rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool VariableSizeBokehBlurOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newInput;
- rcti bokehInput;
-
- const float max_dim = MAX2(getWidth(), getHeight());
- const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
- int maxBlurScalar = this->m_maxBlur * scalar;
-
- newInput.xmax = input->xmax + maxBlurScalar + 2;
- newInput.xmin = input->xmin - maxBlurScalar + 2;
- newInput.ymax = input->ymax + maxBlurScalar - 2;
- newInput.ymin = input->ymin - maxBlurScalar - 2;
- bokehInput.xmax = COM_BLUR_BOKEH_PIXELS;
- bokehInput.xmin = 0;
- bokehInput.ymax = COM_BLUR_BOKEH_PIXELS;
- bokehInput.ymin = 0;
-
- NodeOperation *operation = getInputOperation(2);
- if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) {
+ rcti new_input;
+ rcti bokeh_input;
+
+ const float max_dim = MAX2(get_width(), get_height());
+ const float scalar = do_size_scale_ ? (max_dim / 100.0f) : 1.0f;
+ int max_blur_scalar = max_blur_ * scalar;
+
+ new_input.xmax = input->xmax + max_blur_scalar + 2;
+ new_input.xmin = input->xmin - max_blur_scalar + 2;
+ new_input.ymax = input->ymax + max_blur_scalar - 2;
+ new_input.ymin = input->ymin - max_blur_scalar - 2;
+ bokeh_input.xmax = COM_BLUR_BOKEH_PIXELS;
+ bokeh_input.xmin = 0;
+ bokeh_input.ymax = COM_BLUR_BOKEH_PIXELS;
+ bokeh_input.ymin = 0;
+
+ NodeOperation *operation = get_input_operation(2);
+ if (operation->determine_depending_area_of_interest(&new_input, read_operation, output)) {
return true;
}
- operation = getInputOperation(1);
- if (operation->determineDependingAreaOfInterest(&bokehInput, readOperation, output)) {
+ operation = get_input_operation(1);
+ if (operation->determine_depending_area_of_interest(&bokeh_input, read_operation, output)) {
return true;
}
#ifdef COM_DEFOCUS_SEARCH
- rcti searchInput;
- searchInput.xmax = (input->xmax / InverseSearchRadiusOperation::DIVIDER) + 1;
- searchInput.xmin = (input->xmin / InverseSearchRadiusOperation::DIVIDER) - 1;
- searchInput.ymax = (input->ymax / InverseSearchRadiusOperation::DIVIDER) + 1;
- searchInput.ymin = (input->ymin / InverseSearchRadiusOperation::DIVIDER) - 1;
- operation = getInputOperation(3);
- if (operation->determineDependingAreaOfInterest(&searchInput, readOperation, output)) {
+ rcti search_input;
+ search_input.xmax = (input->xmax / InverseSearchRadiusOperation::DIVIDER) + 1;
+ search_input.xmin = (input->xmin / InverseSearchRadiusOperation::DIVIDER) - 1;
+ search_input.ymax = (input->ymax / InverseSearchRadiusOperation::DIVIDER) + 1;
+ search_input.ymin = (input->ymin / InverseSearchRadiusOperation::DIVIDER) - 1;
+ operation = get_input_operation(3);
+ if (operation->determine_depending_area_of_interest(&search_input, read_operation, output)) {
return true;
}
#endif
- operation = getInputOperation(0);
- if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) {
+ operation = get_input_operation(0);
+ if (operation->determine_depending_area_of_interest(&new_input, read_operation, output)) {
return true;
}
return false;
@@ -284,9 +283,9 @@ void VariableSizeBokehBlurOperation::get_area_of_interest(const int input_idx,
switch (input_idx) {
case IMAGE_INPUT_INDEX:
case SIZE_INPUT_INDEX: {
- const float max_dim = MAX2(getWidth(), getHeight());
- const float scalar = m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
- const int max_blur_scalar = m_maxBlur * scalar;
+ const float max_dim = MAX2(get_width(), get_height());
+ const float scalar = do_size_scale_ ? (max_dim / 100.0f) : 1.0f;
+ const int max_blur_scalar = max_blur_ * scalar;
r_input_area.xmax = output_area.xmax + max_blur_scalar + 2;
r_input_area.xmin = output_area.xmin - max_blur_scalar - 2;
r_input_area.ymax = output_area.ymax + max_blur_scalar + 2;
@@ -328,8 +327,8 @@ struct PixelData {
static void blur_pixel(int x, int y, PixelData &p)
{
- BLI_assert(p.bokeh_input->getWidth() == COM_BLUR_BOKEH_PIXELS);
- BLI_assert(p.bokeh_input->getHeight() == COM_BLUR_BOKEH_PIXELS);
+ BLI_assert(p.bokeh_input->get_width() == COM_BLUR_BOKEH_PIXELS);
+ BLI_assert(p.bokeh_input->get_height() == COM_BLUR_BOKEH_PIXELS);
#ifdef COM_DEFOCUS_SEARCH
float search[4];
@@ -394,20 +393,20 @@ void VariableSizeBokehBlurOperation::update_memory_buffer_partial(MemoryBuffer *
p.bokeh_input = inputs[BOKEH_INPUT_INDEX];
p.size_input = inputs[SIZE_INPUT_INDEX];
p.image_input = inputs[IMAGE_INPUT_INDEX];
- p.step = QualityStepHelper::getStep();
- p.threshold = m_threshold;
- p.image_width = this->getWidth();
- p.image_height = this->getHeight();
+ p.step = QualityStepHelper::get_step();
+ p.threshold = threshold_;
+ p.image_width = this->get_width();
+ p.image_height = this->get_height();
- rcti scalar_area;
+ rcti scalar_area = COM_AREA_NONE;
this->get_area_of_interest(SIZE_INPUT_INDEX, area, scalar_area);
BLI_rcti_isect(&scalar_area, &p.size_input->get_rect(), &scalar_area);
const float max_size = p.size_input->get_max_value(scalar_area);
- const float max_dim = MAX2(this->getWidth(), this->getHeight());
- p.scalar = m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
+ const float max_dim = MAX2(this->get_width(), this->get_height());
+ p.scalar = do_size_scale_ ? (max_dim / 100.0f) : 1.0f;
p.max_blur_scalar = static_cast<int>(max_size * p.scalar);
- CLAMP(p.max_blur_scalar, 1, m_maxBlur);
+ CLAMP(p.max_blur_scalar, 1, max_blur_);
for (BuffersIterator<float> it = output->iterate_with({p.image_input, p.size_input}, area);
!it.is_end();
@@ -440,34 +439,34 @@ void VariableSizeBokehBlurOperation::update_memory_buffer_partial(MemoryBuffer *
/* #InverseSearchRadiusOperation. */
InverseSearchRadiusOperation::InverseSearchRadiusOperation()
{
- this->addInputSocket(DataType::Value, ResizeMode::Align); /* Radius. */
- this->addOutputSocket(DataType::Color);
+ this->add_input_socket(DataType::Value, ResizeMode::Align); /* Radius. */
+ this->add_output_socket(DataType::Color);
this->flags.complex = true;
- this->m_inputRadius = nullptr;
+ input_radius_ = nullptr;
}
-void InverseSearchRadiusOperation::initExecution()
+void InverseSearchRadiusOperation::init_execution()
{
- this->m_inputRadius = this->getInputSocketReader(0);
+ input_radius_ = this->get_input_socket_reader(0);
}
-void *InverseSearchRadiusOperation::initializeTileData(rcti *rect)
+void *InverseSearchRadiusOperation::initialize_tile_data(rcti *rect)
{
MemoryBuffer *data = new MemoryBuffer(DataType::Color, rect);
- float *buffer = data->getBuffer();
+ float *buffer = data->get_buffer();
int x, y;
- int width = this->m_inputRadius->getWidth();
- int height = this->m_inputRadius->getHeight();
+ int width = input_radius_->get_width();
+ int height = input_radius_->get_height();
float temp[4];
int offset = 0;
for (y = rect->ymin; y < rect->ymax; y++) {
for (x = rect->xmin; x < rect->xmax; x++) {
int rx = x * DIVIDER;
int ry = y * DIVIDER;
- buffer[offset] = MAX2(rx - m_maxBlur, 0);
- buffer[offset + 1] = MAX2(ry - m_maxBlur, 0);
- buffer[offset + 2] = MIN2(rx + DIVIDER + m_maxBlur, width);
- buffer[offset + 3] = MIN2(ry + DIVIDER + m_maxBlur, height);
+ buffer[offset] = MAX2(rx - max_blur_, 0);
+ buffer[offset + 1] = MAX2(ry - max_blur_, 0);
+ buffer[offset + 2] = MIN2(rx + DIVIDER + max_blur_, width);
+ buffer[offset + 3] = MIN2(ry + DIVIDER + max_blur_, height);
offset += 4;
}
}
@@ -482,7 +481,7 @@ void *InverseSearchRadiusOperation::initializeTileData(rcti *rect)
for (int x2 = 0; x2 < DIVIDER; x2++) {
for (int y2 = 0; y2 < DIVIDER; y2++) {
- this->m_inputRadius->read(temp, rx + x2, ry + y2, PixelSampler::Nearest);
+ input_radius_->read(temp, rx + x2, ry + y2, PixelSampler::Nearest);
if (radius < temp[0]) {
radius = temp[0];
maxx = x2;
@@ -490,15 +489,15 @@ void *InverseSearchRadiusOperation::initializeTileData(rcti *rect)
}
}
}
- int impactRadius = ceil(radius / DIVIDER);
- for (int x2 = x - impactRadius; x2 < x + impactRadius; x2++) {
- for (int y2 = y - impactRadius; y2 < y + impactRadius; y2++) {
+ int impact_radius = ceil(radius / DIVIDER);
+ for (int x2 = x - impact_radius; x2 < x + impact_radius; x2++) {
+ for (int y2 = y - impact_radius; y2 < y + impact_radius; y2++) {
data->read(temp, x2, y2);
temp[0] = MIN2(temp[0], maxx);
temp[1] = MIN2(temp[1], maxy);
temp[2] = MAX2(temp[2], maxx);
temp[3] = MAX2(temp[3], maxy);
- data->writePixel(x2, y2, temp);
+ data->write_pixel(x2, y2, temp);
}
}
}
@@ -507,13 +506,13 @@ void *InverseSearchRadiusOperation::initializeTileData(rcti *rect)
return data;
}
-void InverseSearchRadiusOperation::executePixelChunk(float output[4], int x, int y, void *data)
+void InverseSearchRadiusOperation::execute_pixel_chunk(float output[4], int x, int y, void *data)
{
MemoryBuffer *buffer = (MemoryBuffer *)data;
- buffer->readNoCheck(output, x, y);
+ buffer->read_no_check(output, x, y);
}
-void InverseSearchRadiusOperation::deinitializeTileData(rcti *rect, void *data)
+void InverseSearchRadiusOperation::deinitialize_tile_data(rcti *rect, void *data)
{
if (data) {
MemoryBuffer *mb = (MemoryBuffer *)data;
@@ -521,28 +520,28 @@ void InverseSearchRadiusOperation::deinitializeTileData(rcti *rect, void *data)
}
}
-void InverseSearchRadiusOperation::deinitExecution()
+void InverseSearchRadiusOperation::deinit_execution()
{
- this->m_inputRadius = nullptr;
+ input_radius_ = nullptr;
}
-void InverseSearchRadiusOperation::determineResolution(unsigned int resolution[2],
- unsigned int preferredResolution[2])
+void InverseSearchRadiusOperation::determine_resolution(unsigned int resolution[2],
+ unsigned int preferred_resolution[2])
{
- NodeOperation::determineResolution(resolution, preferredResolution);
+ NodeOperation::determine_resolution(resolution, preferred_resolution);
resolution[0] = resolution[0] / DIVIDER;
resolution[1] = resolution[1] / DIVIDER;
}
-bool InverseSearchRadiusOperation::determineDependingAreaOfInterest(
- rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool InverseSearchRadiusOperation::determine_depending_area_of_interest(
+ rcti *input, ReadBufferOperation *read_operation, rcti *output)
{
- rcti newRect;
- newRect.ymin = input->ymin * DIVIDER - m_maxBlur;
- newRect.ymax = input->ymax * DIVIDER + m_maxBlur;
- newRect.xmin = input->xmin * DIVIDER - m_maxBlur;
- newRect.xmax = input->xmax * DIVIDER + m_maxBlur;
- return NodeOperation::determineDependingAreaOfInterest(&newRect, readOperation, output);
+ rcti new_rect;
+ new_rect.ymin = input->ymin * DIVIDER - max_blur_;
+ new_rect.ymax = input->ymax * DIVIDER + max_blur_;
+ new_rect.xmin = input->xmin * DIVIDER - max_blur_;
+ new_rect.xmax = input->xmax * DIVIDER + max_blur_;
+ return NodeOperation::determine_depending_area_of_interest(&new_rect, read_operation, output);
}
#endif
diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h
index 3634bc2f1d7..7e53ed8a979 100644
--- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h
+++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h
@@ -34,14 +34,14 @@ class VariableSizeBokehBlurOperation : public MultiThreadedOperation, public Qua
static constexpr int DEFOCUS_INPUT_INDEX = 3;
#endif
- int m_maxBlur;
- float m_threshold;
- bool m_do_size_scale; /* scale size, matching 'BokehBlurNode' */
- SocketReader *m_inputProgram;
- SocketReader *m_inputBokehProgram;
- SocketReader *m_inputSizeProgram;
+ int max_blur_;
+ float threshold_;
+ bool do_size_scale_; /* scale size, matching 'BokehBlurNode' */
+ SocketReader *input_program_;
+ SocketReader *input_bokeh_program_;
+ SocketReader *input_size_program_;
#ifdef COM_DEFOCUS_SEARCH
- SocketReader *m_inputSearchProgram;
+ SocketReader *input_search_program_;
#endif
public:
@@ -50,47 +50,47 @@ class VariableSizeBokehBlurOperation : public MultiThreadedOperation, public Qua
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
- void deinitializeTileData(rcti *rect, void *data) override;
+ void deinitialize_tile_data(rcti *rect, void *data) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void setMaxBlur(int maxRadius)
+ void set_max_blur(int max_radius)
{
- this->m_maxBlur = maxRadius;
+ max_blur_ = max_radius;
}
- void setThreshold(float threshold)
+ void set_threshold(float threshold)
{
- this->m_threshold = threshold;
+ threshold_ = threshold;
}
- void setDoScaleSize(bool scale_size)
+ void set_do_scale_size(bool scale_size)
{
- this->m_do_size_scale = scale_size;
+ do_size_scale_ = scale_size;
}
- void executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer,
- cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers,
- std::list<cl_mem> *clMemToCleanUp,
- std::list<cl_kernel> *clKernelsToCleanUp) override;
+ void execute_opencl(OpenCLDevice *device,
+ MemoryBuffer *output_memory_buffer,
+ cl_mem cl_output_buffer,
+ MemoryBuffer **input_memory_buffers,
+ std::list<cl_mem> *cl_mem_to_clean_up,
+ std::list<cl_kernel> *cl_kernels_to_clean_up) override;
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
@@ -102,8 +102,8 @@ class VariableSizeBokehBlurOperation : public MultiThreadedOperation, public Qua
#ifdef COM_DEFOCUS_SEARCH
class InverseSearchRadiusOperation : public NodeOperation {
private:
- int m_maxBlur;
- SocketReader *m_inputRadius;
+ int max_blur_;
+ SocketReader *input_radius_;
public:
static const int DIVIDER = 4;
@@ -113,28 +113,28 @@ class InverseSearchRadiusOperation : public NodeOperation {
/**
* The inner loop of this operation.
*/
- void executePixelChunk(float output[4], int x, int y, void *data);
+ void execute_pixel_chunk(float output[4], int x, int y, void *data);
/**
* Initialize the execution
*/
- void initExecution() override;
- void *initializeTileData(rcti *rect) override;
- void deinitializeTileData(rcti *rect, void *data) override;
+ void init_execution() override;
+ void *initialize_tile_data(rcti *rect) override;
+ void deinitialize_tile_data(rcti *rect, void *data) override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
- void setMaxBlur(int maxRadius)
+ void set_max_blur(int max_radius)
{
- this->m_maxBlur = maxRadius;
+ max_blur_ = max_radius;
}
};
#endif
diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cc b/source/blender/compositor/operations/COM_VectorBlurOperation.cc
index 63956410b60..1d097b37ca5 100644
--- a/source/blender/compositor/operations/COM_VectorBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cc
@@ -16,12 +16,7 @@
* Copyright 2011, Blender Foundation.
*/
-#include <cstring>
-
-#include "MEM_guardedalloc.h"
-
#include "BLI_jitter_2d.h"
-#include "BLI_math.h"
#include "COM_VectorBlurOperation.h"
@@ -45,78 +40,79 @@ void zbuf_free_span(ZSpan *zspan);
void antialias_tagbuf(int xsize, int ysize, char *rectmove);
/* VectorBlurOperation */
+
VectorBlurOperation::VectorBlurOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value); /* ZBUF */
- this->addInputSocket(DataType::Color); /* SPEED */
- this->addOutputSocket(DataType::Color);
- this->m_settings = nullptr;
- this->m_cachedInstance = nullptr;
- this->m_inputImageProgram = nullptr;
- this->m_inputSpeedProgram = nullptr;
- this->m_inputZProgram = nullptr;
- flags.complex = true;
- flags.is_fullframe_operation = true;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value); /* ZBUF */
+ this->add_input_socket(DataType::Color); /* SPEED */
+ this->add_output_socket(DataType::Color);
+ settings_ = nullptr;
+ cached_instance_ = nullptr;
+ input_image_program_ = nullptr;
+ input_speed_program_ = nullptr;
+ input_zprogram_ = nullptr;
+ flags_.complex = true;
+ flags_.is_fullframe_operation = true;
}
-void VectorBlurOperation::initExecution()
+void VectorBlurOperation::init_execution()
{
- initMutex();
- this->m_inputImageProgram = getInputSocketReader(0);
- this->m_inputZProgram = getInputSocketReader(1);
- this->m_inputSpeedProgram = getInputSocketReader(2);
- this->m_cachedInstance = nullptr;
- QualityStepHelper::initExecution(COM_QH_INCREASE);
+ init_mutex();
+ input_image_program_ = get_input_socket_reader(0);
+ input_zprogram_ = get_input_socket_reader(1);
+ input_speed_program_ = get_input_socket_reader(2);
+ cached_instance_ = nullptr;
+ QualityStepHelper::init_execution(COM_QH_INCREASE);
}
-void VectorBlurOperation::executePixel(float output[4], int x, int y, void *data)
+void VectorBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
{
float *buffer = (float *)data;
- int index = (y * this->getWidth() + x) * COM_DATA_TYPE_COLOR_CHANNELS;
+ int index = (y * this->get_width() + x) * COM_DATA_TYPE_COLOR_CHANNELS;
copy_v4_v4(output, &buffer[index]);
}
-void VectorBlurOperation::deinitExecution()
+void VectorBlurOperation::deinit_execution()
{
- deinitMutex();
- this->m_inputImageProgram = nullptr;
- this->m_inputSpeedProgram = nullptr;
- this->m_inputZProgram = nullptr;
- if (this->m_cachedInstance) {
- MEM_freeN(this->m_cachedInstance);
- this->m_cachedInstance = nullptr;
+ deinit_mutex();
+ input_image_program_ = nullptr;
+ input_speed_program_ = nullptr;
+ input_zprogram_ = nullptr;
+ if (cached_instance_) {
+ MEM_freeN(cached_instance_);
+ cached_instance_ = nullptr;
}
}
-void *VectorBlurOperation::initializeTileData(rcti *rect)
+void *VectorBlurOperation::initialize_tile_data(rcti *rect)
{
- if (this->m_cachedInstance) {
- return this->m_cachedInstance;
+ if (cached_instance_) {
+ return cached_instance_;
}
- lockMutex();
- if (this->m_cachedInstance == nullptr) {
- MemoryBuffer *tile = (MemoryBuffer *)this->m_inputImageProgram->initializeTileData(rect);
- MemoryBuffer *speed = (MemoryBuffer *)this->m_inputSpeedProgram->initializeTileData(rect);
- MemoryBuffer *z = (MemoryBuffer *)this->m_inputZProgram->initializeTileData(rect);
- float *data = (float *)MEM_dupallocN(tile->getBuffer());
- this->generateVectorBlur(data, tile, speed, z);
- this->m_cachedInstance = data;
+ lock_mutex();
+ if (cached_instance_ == nullptr) {
+ MemoryBuffer *tile = (MemoryBuffer *)input_image_program_->initialize_tile_data(rect);
+ MemoryBuffer *speed = (MemoryBuffer *)input_speed_program_->initialize_tile_data(rect);
+ MemoryBuffer *z = (MemoryBuffer *)input_zprogram_->initialize_tile_data(rect);
+ float *data = (float *)MEM_dupallocN(tile->get_buffer());
+ this->generate_vector_blur(data, tile, speed, z);
+ cached_instance_ = data;
}
- unlockMutex();
- return this->m_cachedInstance;
+ unlock_mutex();
+ return cached_instance_;
}
-bool VectorBlurOperation::determineDependingAreaOfInterest(rcti * /*input*/,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool VectorBlurOperation::determine_depending_area_of_interest(rcti * /*input*/,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- if (this->m_cachedInstance == nullptr) {
- rcti newInput;
- newInput.xmax = this->getWidth();
- newInput.xmin = 0;
- newInput.ymax = this->getHeight();
- newInput.ymin = 0;
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ if (cached_instance_ == nullptr) {
+ rcti new_input;
+ new_input.xmax = this->get_width();
+ new_input.xmin = 0;
+ new_input.ymax = this->get_height();
+ new_input.ymin = 0;
+ return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
return false;
@@ -134,12 +130,12 @@ void VectorBlurOperation::update_memory_buffer(MemoryBuffer *output,
Span<MemoryBuffer *> inputs)
{
/* TODO(manzanilla): once tiled implementation is removed, run multi-threaded where possible. */
- if (!m_cachedInstance) {
+ if (!cached_instance_) {
MemoryBuffer *image = inputs[IMAGE_INPUT_INDEX];
const bool is_image_inflated = image->is_a_single_elem();
image = is_image_inflated ? image->inflate() : image;
- /* Must be a copy because it's modified in #generateVectorBlur. */
+ /* Must be a copy because it's modified in #generate_vector_blur. */
MemoryBuffer *speed = inputs[SPEED_INPUT_INDEX];
speed = speed->is_a_single_elem() ? speed->inflate() : new MemoryBuffer(*speed);
@@ -147,8 +143,8 @@ void VectorBlurOperation::update_memory_buffer(MemoryBuffer *output,
const bool is_z_inflated = z->is_a_single_elem();
z = is_z_inflated ? z->inflate() : z;
- m_cachedInstance = (float *)MEM_dupallocN(image->getBuffer());
- this->generateVectorBlur(m_cachedInstance, image, speed, z);
+ cached_instance_ = (float *)MEM_dupallocN(image->get_buffer());
+ this->generate_vector_blur(cached_instance_, image, speed, z);
if (is_image_inflated) {
delete image;
@@ -159,33 +155,38 @@ void VectorBlurOperation::update_memory_buffer(MemoryBuffer *output,
}
}
- const int num_channels = COM_data_type_num_channels(getOutputSocket()->getDataType());
- MemoryBuffer buf(m_cachedInstance, num_channels, this->getWidth(), this->getHeight());
+ const int num_channels = COM_data_type_num_channels(get_output_socket()->get_data_type());
+ MemoryBuffer buf(cached_instance_, num_channels, this->get_width(), this->get_height());
output->copy_from(&buf, area);
}
-void VectorBlurOperation::generateVectorBlur(float *data,
- MemoryBuffer *inputImage,
- MemoryBuffer *inputSpeed,
- MemoryBuffer *inputZ)
+void VectorBlurOperation::generate_vector_blur(float *data,
+ MemoryBuffer *input_image,
+ MemoryBuffer *input_speed,
+ MemoryBuffer *inputZ)
{
NodeBlurData blurdata;
- blurdata.samples = this->m_settings->samples / QualityStepHelper::getStep();
- blurdata.maxspeed = this->m_settings->maxspeed;
- blurdata.minspeed = this->m_settings->minspeed;
- blurdata.curved = this->m_settings->curved;
- blurdata.fac = this->m_settings->fac;
+ blurdata.samples = settings_->samples / QualityStepHelper::get_step();
+ blurdata.maxspeed = settings_->maxspeed;
+ blurdata.minspeed = settings_->minspeed;
+ blurdata.curved = settings_->curved;
+ blurdata.fac = settings_->fac;
zbuf_accumulate_vecblur(&blurdata,
- this->getWidth(),
- this->getHeight(),
+ this->get_width(),
+ this->get_height(),
data,
- inputImage->getBuffer(),
- inputSpeed->getBuffer(),
- inputZ->getBuffer());
+ input_image->get_buffer(),
+ input_speed->get_buffer(),
+ inputZ->get_buffer());
}
-/* ****************** Spans ******************************* */
-/* span fill in method, is also used to localize data for zbuffering */
+/* -------------------------------------------------------------------- */
+/** \name Spans
+ *
+ * Duplicated logic from `zbuf.c`.
+ * \{ */
+
+/** Span fill in method, is also used to localize data for Z-buffering. */
struct ZSpan {
/* range for clipping */
int rectx, recty;
@@ -331,11 +332,13 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2])
}
for (y = my2; y >= my0; y--, xs0 += dx0) {
- /* xs0 is the xcoord! */
+ /* xs0 is the X-coordinate! */
span[y] = xs0;
}
}
+/** \} */
+
/* ******************** VECBLUR ACCUM BUF ************************* */
struct DrawBufPixel {
@@ -343,6 +346,9 @@ struct DrawBufPixel {
float alpha;
};
+/**
+ * \note Near duplicate of `zspan_scanconvert` in `zbuf.c` with some minor adjustments.
+ */
static void zbuf_fill_in_rgba(
ZSpan *zspan, DrawBufPixel *col, float *v1, float *v2, float *v3, float *v4)
{
diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.h b/source/blender/compositor/operations/COM_VectorBlurOperation.h
index c30c150db3c..75df9d9e024 100644
--- a/source/blender/compositor/operations/COM_VectorBlurOperation.h
+++ b/source/blender/compositor/operations/COM_VectorBlurOperation.h
@@ -31,18 +31,18 @@ class VectorBlurOperation : public NodeOperation, public QualityStepHelper {
static constexpr int SPEED_INPUT_INDEX = 2;
/**
- * \brief Cached reference to the inputProgram
+ * \brief Cached reference to the input_program
*/
- SocketReader *m_inputImageProgram;
- SocketReader *m_inputSpeedProgram;
- SocketReader *m_inputZProgram;
+ SocketReader *input_image_program_;
+ SocketReader *input_speed_program_;
+ SocketReader *input_zprogram_;
/**
* \brief settings of the glare node.
*/
- NodeBlurData *m_settings;
+ NodeBlurData *settings_;
- float *m_cachedInstance;
+ float *cached_instance_;
public:
VectorBlurOperation();
@@ -50,40 +50,38 @@ class VectorBlurOperation : public NodeOperation, public QualityStepHelper {
/**
* The inner loop of this operation.
*/
- void executePixel(float output[4], int x, int y, void *data) override;
+ void execute_pixel(float output[4], int x, int y, void *data) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
- void *initializeTileData(rcti *rect) override;
+ void *initialize_tile_data(rcti *rect) override;
- void setVectorBlurSettings(NodeBlurData *settings)
+ void set_vector_blur_settings(NodeBlurData *settings)
{
- this->m_settings = settings;
+ settings_ = settings;
}
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
protected:
- void generateVectorBlur(float *data,
- MemoryBuffer *inputImage,
- MemoryBuffer *inputSpeed,
- MemoryBuffer *inputZ);
+ void generate_vector_blur(float *data,
+ MemoryBuffer *input_image,
+ MemoryBuffer *input_speed,
+ MemoryBuffer *inputZ);
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_VectorCurveOperation.cc b/source/blender/compositor/operations/COM_VectorCurveOperation.cc
index c2087fd071e..c7cd8dc5684 100644
--- a/source/blender/compositor/operations/COM_VectorCurveOperation.cc
+++ b/source/blender/compositor/operations/COM_VectorCurveOperation.cc
@@ -24,40 +24,40 @@ namespace blender::compositor {
VectorCurveOperation::VectorCurveOperation()
{
- this->addInputSocket(DataType::Vector);
- this->addOutputSocket(DataType::Vector);
+ this->add_input_socket(DataType::Vector);
+ this->add_output_socket(DataType::Vector);
- this->m_inputProgram = nullptr;
+ input_program_ = nullptr;
}
-void VectorCurveOperation::initExecution()
+void VectorCurveOperation::init_execution()
{
- CurveBaseOperation::initExecution();
- this->m_inputProgram = this->getInputSocketReader(0);
+ CurveBaseOperation::init_execution();
+ input_program_ = this->get_input_socket_reader(0);
}
-void VectorCurveOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void VectorCurveOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float input[4];
- this->m_inputProgram->readSampled(input, x, y, sampler);
+ input_program_->read_sampled(input, x, y, sampler);
- BKE_curvemapping_evaluate_premulRGBF(this->m_curveMapping, output, input);
+ BKE_curvemapping_evaluate_premulRGBF(curve_mapping_, output, input);
}
-void VectorCurveOperation::deinitExecution()
+void VectorCurveOperation::deinit_execution()
{
- CurveBaseOperation::deinitExecution();
- this->m_inputProgram = nullptr;
+ CurveBaseOperation::deinit_execution();
+ input_program_ = nullptr;
}
void VectorCurveOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- CurveMapping *curve_map = this->m_curveMapping;
+ CurveMapping *curve_map = curve_mapping_;
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
BKE_curvemapping_evaluate_premulRGBF(curve_map, it.out, it.in(0));
}
diff --git a/source/blender/compositor/operations/COM_VectorCurveOperation.h b/source/blender/compositor/operations/COM_VectorCurveOperation.h
index 27b3ad69e17..87864e08e25 100644
--- a/source/blender/compositor/operations/COM_VectorCurveOperation.h
+++ b/source/blender/compositor/operations/COM_VectorCurveOperation.h
@@ -26,9 +26,9 @@ namespace blender::compositor {
class VectorCurveOperation : public CurveBaseOperation {
private:
/**
- * Cached reference to the inputProgram
+ * Cached reference to the input_program
*/
- SocketReader *m_inputProgram;
+ SocketReader *input_program_;
public:
VectorCurveOperation();
@@ -36,17 +36,17 @@ class VectorCurveOperation : public CurveBaseOperation {
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
/**
* Initialize the execution
*/
- void initExecution() override;
+ void init_execution() override;
/**
* Deinitialize the execution
*/
- void deinitExecution() override;
+ void deinit_execution() override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cc b/source/blender/compositor/operations/COM_ViewerOperation.cc
index 1faff0fd07f..205596b46d1 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.cc
+++ b/source/blender/compositor/operations/COM_ViewerOperation.cc
@@ -19,15 +19,7 @@
#include "COM_ViewerOperation.h"
#include "BKE_image.h"
#include "BKE_scene.h"
-#include "BLI_listbase.h"
-#include "BLI_math_color.h"
-#include "BLI_math_vector.h"
-#include "BLI_utildefines.h"
#include "COM_ExecutionSystem.h"
-#include "MEM_guardedalloc.h"
-#include "PIL_time.h"
-#include "WM_api.h"
-#include "WM_types.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
@@ -39,54 +31,54 @@ static int MAX_VIEWER_TRANSLATION_PADDING = 12000;
ViewerOperation::ViewerOperation()
{
- this->setImage(nullptr);
- this->setImageUser(nullptr);
- this->m_outputBuffer = nullptr;
- this->m_depthBuffer = nullptr;
- this->m_active = false;
- this->m_doDepthBuffer = false;
- this->m_viewSettings = nullptr;
- this->m_displaySettings = nullptr;
- this->m_useAlphaInput = false;
-
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Value);
-
- this->m_imageInput = nullptr;
- this->m_alphaInput = nullptr;
- this->m_depthInput = nullptr;
- this->m_rd = nullptr;
- this->m_viewName = nullptr;
- flags.use_viewer_border = true;
- flags.is_viewer_operation = true;
+ this->set_image(nullptr);
+ this->set_image_user(nullptr);
+ output_buffer_ = nullptr;
+ depth_buffer_ = nullptr;
+ active_ = false;
+ do_depth_buffer_ = false;
+ view_settings_ = nullptr;
+ display_settings_ = nullptr;
+ use_alpha_input_ = false;
+
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Value);
+
+ image_input_ = nullptr;
+ alpha_input_ = nullptr;
+ depth_input_ = nullptr;
+ rd_ = nullptr;
+ view_name_ = nullptr;
+ flags_.use_viewer_border = true;
+ flags_.is_viewer_operation = true;
}
-void ViewerOperation::initExecution()
+void ViewerOperation::init_execution()
{
/* When initializing the tree during initial load the width and height can be zero. */
- this->m_imageInput = getInputSocketReader(0);
- this->m_alphaInput = getInputSocketReader(1);
- this->m_depthInput = getInputSocketReader(2);
- this->m_doDepthBuffer = (this->m_depthInput != nullptr);
+ image_input_ = get_input_socket_reader(0);
+ alpha_input_ = get_input_socket_reader(1);
+ depth_input_ = get_input_socket_reader(2);
+ do_depth_buffer_ = (depth_input_ != nullptr);
- if (isActiveViewerOutput() && !exec_system_->is_breaked()) {
- initImage();
+ if (is_active_viewer_output() && !exec_system_->is_breaked()) {
+ init_image();
}
}
-void ViewerOperation::deinitExecution()
+void ViewerOperation::deinit_execution()
{
- this->m_imageInput = nullptr;
- this->m_alphaInput = nullptr;
- this->m_depthInput = nullptr;
- this->m_outputBuffer = nullptr;
+ image_input_ = nullptr;
+ alpha_input_ = nullptr;
+ depth_input_ = nullptr;
+ output_buffer_ = nullptr;
}
-void ViewerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
+void ViewerOperation::execute_region(rcti *rect, unsigned int /*tile_number*/)
{
- float *buffer = this->m_outputBuffer;
- float *depthbuffer = this->m_depthBuffer;
+ float *buffer = output_buffer_;
+ float *depthbuffer = depth_buffer_;
if (!buffer) {
return;
}
@@ -94,9 +86,9 @@ void ViewerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
const int y1 = rect->ymin;
const int x2 = rect->xmax;
const int y2 = rect->ymax;
- const int offsetadd = (this->getWidth() - (x2 - x1));
+ const int offsetadd = (this->get_width() - (x2 - x1));
const int offsetadd4 = offsetadd * 4;
- int offset = (y1 * this->getWidth() + x1);
+ int offset = (y1 * this->get_width() + x1);
int offset4 = offset * 4;
float alpha[4], depth[4];
int x;
@@ -105,54 +97,54 @@ void ViewerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
for (y = y1; y < y2 && (!breaked); y++) {
for (x = x1; x < x2; x++) {
- this->m_imageInput->readSampled(&(buffer[offset4]), x, y, PixelSampler::Nearest);
- if (this->m_useAlphaInput) {
- this->m_alphaInput->readSampled(alpha, x, y, PixelSampler::Nearest);
+ image_input_->read_sampled(&(buffer[offset4]), x, y, PixelSampler::Nearest);
+ if (use_alpha_input_) {
+ alpha_input_->read_sampled(alpha, x, y, PixelSampler::Nearest);
buffer[offset4 + 3] = alpha[0];
}
- this->m_depthInput->readSampled(depth, x, y, PixelSampler::Nearest);
+ depth_input_->read_sampled(depth, x, y, PixelSampler::Nearest);
depthbuffer[offset] = depth[0];
offset++;
offset4 += 4;
}
- if (isBraked()) {
+ if (is_braked()) {
breaked = true;
}
offset += offsetadd;
offset4 += offsetadd4;
}
- updateImage(rect);
+ update_image(rect);
}
void ViewerOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
- const int sceneRenderWidth = this->m_rd->xsch * this->m_rd->size / 100;
- const int sceneRenderHeight = this->m_rd->ysch * this->m_rd->size / 100;
+ const int scene_render_width = rd_->xsch * rd_->size / 100;
+ const int scene_render_height = rd_->ysch * rd_->size / 100;
rcti local_preferred = preferred_area;
- local_preferred.xmax = local_preferred.xmin + sceneRenderWidth;
- local_preferred.ymax = local_preferred.ymin + sceneRenderHeight;
+ local_preferred.xmax = local_preferred.xmin + scene_render_width;
+ local_preferred.ymax = local_preferred.ymin + scene_render_height;
NodeOperation::determine_canvas(local_preferred, r_area);
}
-void ViewerOperation::initImage()
+void ViewerOperation::init_image()
{
- Image *ima = this->m_image;
- ImageUser iuser = *this->m_imageUser;
+ Image *ima = image_;
+ ImageUser iuser = *image_user_;
void *lock;
ImBuf *ibuf;
/* make sure the image has the correct number of views */
- if (ima && BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName)) {
- BKE_image_ensure_viewer_views(this->m_rd, ima, this->m_imageUser);
+ if (ima && BKE_scene_multiview_is_render_view_first(rd_, view_name_)) {
+ BKE_image_ensure_viewer_views(rd_, ima, image_user_);
}
BLI_thread_lock(LOCK_DRAW_IMAGE);
/* local changes to the original ImageUser */
- iuser.multi_index = BKE_scene_multiview_view_id_get(this->m_rd, this->m_viewName);
+ iuser.multi_index = BKE_scene_multiview_view_id_get(rd_, view_name_);
ibuf = BKE_image_acquire_ibuf(ima, &iuser, &lock);
if (!ibuf) {
@@ -169,8 +161,8 @@ void ViewerOperation::initImage()
padding_y = MAX_VIEWER_TRANSLATION_PADDING;
}
- display_width_ = getWidth() + padding_x;
- display_height_ = getHeight() + padding_y;
+ display_width_ = get_width() + padding_x;
+ display_height_ = get_height() + padding_y;
if (ibuf->x != display_width_ || ibuf->y != display_height_) {
imb_freerectImBuf(ibuf);
imb_freerectfloatImBuf(ibuf);
@@ -181,57 +173,55 @@ void ViewerOperation::initImage()
if (ibuf->x > 0 && ibuf->y > 0) {
imb_addrectfloatImBuf(ibuf);
}
- ImageTile *tile = BKE_image_get_tile(ima, 0);
- tile->ok = IMA_OK_LOADED;
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
}
- if (m_doDepthBuffer) {
+ if (do_depth_buffer_) {
addzbuffloatImBuf(ibuf);
}
/* now we combine the input with ibuf */
- this->m_outputBuffer = ibuf->rect_float;
+ output_buffer_ = ibuf->rect_float;
/* needed for display buffer update */
- this->m_ibuf = ibuf;
+ ibuf_ = ibuf;
- if (m_doDepthBuffer) {
- this->m_depthBuffer = ibuf->zbuf_float;
+ if (do_depth_buffer_) {
+ depth_buffer_ = ibuf->zbuf_float;
}
- BKE_image_release_ibuf(this->m_image, this->m_ibuf, lock);
+ BKE_image_release_ibuf(image_, ibuf_, lock);
BLI_thread_unlock(LOCK_DRAW_IMAGE);
}
-void ViewerOperation::updateImage(const rcti *rect)
+void ViewerOperation::update_image(const rcti *rect)
{
if (exec_system_->is_breaked()) {
return;
}
- float *buffer = m_outputBuffer;
- IMB_partial_display_buffer_update(this->m_ibuf,
+ float *buffer = output_buffer_;
+ IMB_partial_display_buffer_update(ibuf_,
buffer,
nullptr,
display_width_,
0,
0,
- this->m_viewSettings,
- this->m_displaySettings,
+ view_settings_,
+ display_settings_,
rect->xmin,
rect->ymin,
rect->xmax,
rect->ymax);
- this->m_image->gpuflag |= IMA_GPU_REFRESH;
- this->updateDraw();
+ image_->gpuflag |= IMA_GPU_REFRESH;
+ this->update_draw();
}
-eCompositorPriority ViewerOperation::getRenderPriority() const
+eCompositorPriority ViewerOperation::get_render_priority() const
{
- if (this->isActiveViewerOutput()) {
+ if (this->is_active_viewer_output()) {
return eCompositorPriority::High;
}
@@ -242,25 +232,25 @@ void ViewerOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(output),
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- if (!m_outputBuffer) {
+ if (!output_buffer_) {
return;
}
const int offset_x = area.xmin + (canvas_.xmin > 0 ? canvas_.xmin * 2 : 0);
const int offset_y = area.ymin + (canvas_.ymin > 0 ? canvas_.ymin * 2 : 0);
MemoryBuffer output_buffer(
- m_outputBuffer, COM_DATA_TYPE_COLOR_CHANNELS, display_width_, display_height_);
+ output_buffer_, COM_DATA_TYPE_COLOR_CHANNELS, display_width_, display_height_);
const MemoryBuffer *input_image = inputs[0];
output_buffer.copy_from(input_image, area, offset_x, offset_y);
- if (this->m_useAlphaInput) {
+ if (use_alpha_input_) {
const MemoryBuffer *input_alpha = inputs[1];
output_buffer.copy_from(
input_alpha, area, 0, COM_DATA_TYPE_VALUE_CHANNELS, offset_x, offset_y, 3);
}
- if (m_depthBuffer) {
+ if (depth_buffer_) {
MemoryBuffer depth_buffer(
- m_depthBuffer, COM_DATA_TYPE_VALUE_CHANNELS, display_width_, display_height_);
+ depth_buffer_, COM_DATA_TYPE_VALUE_CHANNELS, display_width_, display_height_);
const MemoryBuffer *input_depth = inputs[2];
depth_buffer.copy_from(input_depth, area, offset_x, offset_y);
}
@@ -271,27 +261,27 @@ void ViewerOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(output),
offset_x + BLI_rcti_size_x(&area),
offset_y,
offset_y + BLI_rcti_size_y(&area));
- updateImage(&display_area);
+ update_image(&display_area);
}
void ViewerOperation::clear_display_buffer()
{
- BLI_assert(isActiveViewerOutput());
+ BLI_assert(is_active_viewer_output());
if (exec_system_->is_breaked()) {
return;
}
- initImage();
- if (m_outputBuffer == nullptr) {
+ init_image();
+ if (output_buffer_ == nullptr) {
return;
}
- size_t buf_bytes = (size_t)m_ibuf->y * m_ibuf->x * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float);
+ size_t buf_bytes = (size_t)ibuf_->y * ibuf_->x * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float);
if (buf_bytes > 0) {
- memset(m_outputBuffer, 0, buf_bytes);
+ memset(output_buffer_, 0, buf_bytes);
rcti display_area;
- BLI_rcti_init(&display_area, 0, m_ibuf->x, 0, m_ibuf->y);
- updateImage(&display_area);
+ BLI_rcti_init(&display_area, 0, ibuf_->x, 0, ibuf_->y);
+ update_image(&display_area);
}
}
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.h b/source/blender/compositor/operations/COM_ViewerOperation.h
index 95ee982f692..7fc5ae36ad9 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.h
+++ b/source/blender/compositor/operations/COM_ViewerOperation.h
@@ -28,105 +28,105 @@ namespace blender::compositor {
class ViewerOperation : public MultiThreadedOperation {
private:
/* TODO(manzanilla): To be removed together with tiled implementation. */
- float *m_outputBuffer;
- float *m_depthBuffer;
+ float *output_buffer_;
+ float *depth_buffer_;
- Image *m_image;
- ImageUser *m_imageUser;
- bool m_active;
- float m_centerX;
- float m_centerY;
- ChunkOrdering m_chunkOrder;
- bool m_doDepthBuffer;
- ImBuf *m_ibuf;
- bool m_useAlphaInput;
- const RenderData *m_rd;
- const char *m_viewName;
+ Image *image_;
+ ImageUser *image_user_;
+ bool active_;
+ float center_x_;
+ float center_y_;
+ ChunkOrdering chunk_order_;
+ bool do_depth_buffer_;
+ ImBuf *ibuf_;
+ bool use_alpha_input_;
+ const RenderData *rd_;
+ const char *view_name_;
- const ColorManagedViewSettings *m_viewSettings;
- const ColorManagedDisplaySettings *m_displaySettings;
+ const ColorManagedViewSettings *view_settings_;
+ const ColorManagedDisplaySettings *display_settings_;
- SocketReader *m_imageInput;
- SocketReader *m_alphaInput;
- SocketReader *m_depthInput;
+ SocketReader *image_input_;
+ SocketReader *alpha_input_;
+ SocketReader *depth_input_;
int display_width_;
int display_height_;
public:
ViewerOperation();
- void initExecution() override;
- void deinitExecution() override;
- void executeRegion(rcti *rect, unsigned int tileNumber) override;
+ void init_execution() override;
+ void deinit_execution() override;
+ void execute_region(rcti *rect, unsigned int tile_number) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
- bool isOutputOperation(bool /*rendering*/) const override
+ bool is_output_operation(bool /*rendering*/) const override
{
if (G.background) {
return false;
}
- return isActiveViewerOutput();
+ return is_active_viewer_output();
}
- void setImage(Image *image)
+ void set_image(Image *image)
{
- this->m_image = image;
+ image_ = image;
}
- void setImageUser(ImageUser *imageUser)
+ void set_image_user(ImageUser *image_user)
{
- this->m_imageUser = imageUser;
+ image_user_ = image_user;
}
- bool isActiveViewerOutput() const override
+ bool is_active_viewer_output() const override
{
- return this->m_active;
+ return active_;
}
- void setActive(bool active)
+ void set_active(bool active)
{
- this->m_active = active;
+ active_ = active;
}
void setCenterX(float centerX)
{
- this->m_centerX = centerX;
+ center_x_ = centerX;
}
void setCenterY(float centerY)
{
- this->m_centerY = centerY;
+ center_y_ = centerY;
}
- void setChunkOrder(ChunkOrdering tileOrder)
+ void set_chunk_order(ChunkOrdering tile_order)
{
- this->m_chunkOrder = tileOrder;
+ chunk_order_ = tile_order;
}
float getCenterX() const
{
- return this->m_centerX;
+ return center_x_;
}
float getCenterY() const
{
- return this->m_centerY;
+ return center_y_;
}
- ChunkOrdering getChunkOrder() const
+ ChunkOrdering get_chunk_order() const
{
- return this->m_chunkOrder;
+ return chunk_order_;
}
- eCompositorPriority getRenderPriority() const override;
- void setUseAlphaInput(bool value)
+ eCompositorPriority get_render_priority() const override;
+ void set_use_alpha_input(bool value)
{
- this->m_useAlphaInput = value;
+ use_alpha_input_ = value;
}
- void setRenderData(const RenderData *rd)
+ void set_render_data(const RenderData *rd)
{
- this->m_rd = rd;
+ rd_ = rd;
}
- void setViewName(const char *viewName)
+ void set_view_name(const char *view_name)
{
- this->m_viewName = viewName;
+ view_name_ = view_name;
}
- void setViewSettings(const ColorManagedViewSettings *viewSettings)
+ void set_view_settings(const ColorManagedViewSettings *view_settings)
{
- this->m_viewSettings = viewSettings;
+ view_settings_ = view_settings;
}
- void setDisplaySettings(const ColorManagedDisplaySettings *displaySettings)
+ void set_display_settings(const ColorManagedDisplaySettings *display_settings)
{
- this->m_displaySettings = displaySettings;
+ display_settings_ = display_settings;
}
void update_memory_buffer_partial(MemoryBuffer *output,
@@ -136,8 +136,8 @@ class ViewerOperation : public MultiThreadedOperation {
void clear_display_buffer();
private:
- void updateImage(const rcti *rect);
- void initImage();
+ void update_image(const rcti *rect);
+ void init_image();
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_WrapOperation.cc b/source/blender/compositor/operations/COM_WrapOperation.cc
index 393128ded41..336e1b72520 100644
--- a/source/blender/compositor/operations/COM_WrapOperation.cc
+++ b/source/blender/compositor/operations/COM_WrapOperation.cc
@@ -24,98 +24,99 @@ namespace blender::compositor {
WrapOperation::WrapOperation(DataType datatype) : ReadBufferOperation(datatype)
{
- this->m_wrappingType = CMP_NODE_WRAP_NONE;
+ wrapping_type_ = CMP_NODE_WRAP_NONE;
}
-inline float WrapOperation::getWrappedOriginalXPos(float x)
+inline float WrapOperation::get_wrapped_original_xpos(float x)
{
- if (this->getWidth() == 0) {
+ if (this->get_width() == 0) {
return 0;
}
while (x < 0) {
- x += this->getWidth();
+ x += this->get_width();
}
- return fmodf(x, this->getWidth());
+ return fmodf(x, this->get_width());
}
-inline float WrapOperation::getWrappedOriginalYPos(float y)
+inline float WrapOperation::get_wrapped_original_ypos(float y)
{
- if (this->getHeight() == 0) {
+ if (this->get_height() == 0) {
return 0;
}
while (y < 0) {
- y += this->getHeight();
+ y += this->get_height();
}
- return fmodf(y, this->getHeight());
+ return fmodf(y, this->get_height());
}
-void WrapOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void WrapOperation::execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler)
{
float nx, ny;
nx = x;
ny = y;
MemoryBufferExtend extend_x = MemoryBufferExtend::Clip, extend_y = MemoryBufferExtend::Clip;
- switch (m_wrappingType) {
+ switch (wrapping_type_) {
case CMP_NODE_WRAP_NONE:
- /* Intentionally empty, originalXPos and originalYPos have been set before. */
+ /* Intentionally empty, original_xpos and original_ypos have been set before. */
break;
case CMP_NODE_WRAP_X:
/* Wrap only on the x-axis. */
- nx = this->getWrappedOriginalXPos(x);
+ nx = this->get_wrapped_original_xpos(x);
extend_x = MemoryBufferExtend::Repeat;
break;
case CMP_NODE_WRAP_Y:
/* Wrap only on the y-axis. */
- ny = this->getWrappedOriginalYPos(y);
+ ny = this->get_wrapped_original_ypos(y);
extend_y = MemoryBufferExtend::Repeat;
break;
case CMP_NODE_WRAP_XY:
/* Wrap on both. */
- nx = this->getWrappedOriginalXPos(x);
- ny = this->getWrappedOriginalYPos(y);
+ nx = this->get_wrapped_original_xpos(x);
+ ny = this->get_wrapped_original_ypos(y);
extend_x = MemoryBufferExtend::Repeat;
extend_y = MemoryBufferExtend::Repeat;
break;
}
- executePixelExtend(output, nx, ny, sampler, extend_x, extend_y);
+ execute_pixel_extend(output, nx, ny, sampler, extend_x, extend_y);
}
-bool WrapOperation::determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output)
+bool WrapOperation::determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output)
{
- rcti newInput;
- newInput.xmin = input->xmin;
- newInput.xmax = input->xmax;
- newInput.ymin = input->ymin;
- newInput.ymax = input->ymax;
+ rcti new_input;
+ new_input.xmin = input->xmin;
+ new_input.xmax = input->xmax;
+ new_input.ymin = input->ymin;
+ new_input.ymax = input->ymax;
- if (ELEM(m_wrappingType, CMP_NODE_WRAP_X, CMP_NODE_WRAP_XY)) {
+ if (ELEM(wrapping_type_, CMP_NODE_WRAP_X, CMP_NODE_WRAP_XY)) {
/* Wrap only on the x-axis if tile is wrapping. */
- newInput.xmin = getWrappedOriginalXPos(input->xmin);
- newInput.xmax = roundf(getWrappedOriginalXPos(input->xmax));
- if (newInput.xmin >= newInput.xmax) {
- newInput.xmin = 0;
- newInput.xmax = this->getWidth();
+ new_input.xmin = get_wrapped_original_xpos(input->xmin);
+ new_input.xmax = roundf(get_wrapped_original_xpos(input->xmax));
+ if (new_input.xmin >= new_input.xmax) {
+ new_input.xmin = 0;
+ new_input.xmax = this->get_width();
}
}
- if (ELEM(m_wrappingType, CMP_NODE_WRAP_Y, CMP_NODE_WRAP_XY)) {
+ if (ELEM(wrapping_type_, CMP_NODE_WRAP_Y, CMP_NODE_WRAP_XY)) {
/* Wrap only on the y-axis if tile is wrapping. */
- newInput.ymin = getWrappedOriginalYPos(input->ymin);
- newInput.ymax = roundf(getWrappedOriginalYPos(input->ymax));
- if (newInput.ymin >= newInput.ymax) {
- newInput.ymin = 0;
- newInput.ymax = this->getHeight();
+ new_input.ymin = get_wrapped_original_ypos(input->ymin);
+ new_input.ymax = roundf(get_wrapped_original_ypos(input->ymax));
+ if (new_input.ymin >= new_input.ymax) {
+ new_input.ymin = 0;
+ new_input.ymax = this->get_height();
}
}
- return ReadBufferOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return ReadBufferOperation::determine_depending_area_of_interest(
+ &new_input, read_operation, output);
}
-void WrapOperation::setWrapping(int wrapping_type)
+void WrapOperation::set_wrapping(int wrapping_type)
{
- m_wrappingType = wrapping_type;
+ wrapping_type_ = wrapping_type;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_WrapOperation.h b/source/blender/compositor/operations/COM_WrapOperation.h
index 6279129a550..e8ec97fa5f2 100644
--- a/source/blender/compositor/operations/COM_WrapOperation.h
+++ b/source/blender/compositor/operations/COM_WrapOperation.h
@@ -24,18 +24,18 @@ namespace blender::compositor {
class WrapOperation : public ReadBufferOperation {
private:
- int m_wrappingType;
+ int wrapping_type_;
public:
WrapOperation(DataType datatype);
- bool determineDependingAreaOfInterest(rcti *input,
- ReadBufferOperation *readOperation,
- rcti *output) override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
-
- void setWrapping(int wrapping_type);
- float getWrappedOriginalXPos(float x);
- float getWrappedOriginalYPos(float y);
+ bool determine_depending_area_of_interest(rcti *input,
+ ReadBufferOperation *read_operation,
+ rcti *output) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ void set_wrapping(int wrapping_type);
+ float get_wrapped_original_xpos(float x);
+ float get_wrapped_original_ypos(float y);
void setFactorXY(float factorX, float factorY);
};
diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cc b/source/blender/compositor/operations/COM_WriteBufferOperation.cc
index a1c1e514eb7..2511488615e 100644
--- a/source/blender/compositor/operations/COM_WriteBufferOperation.cc
+++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cc
@@ -18,54 +18,52 @@
#include "COM_WriteBufferOperation.h"
#include "COM_OpenCLDevice.h"
-#include "COM_defines.h"
-#include <cstdio>
namespace blender::compositor {
WriteBufferOperation::WriteBufferOperation(DataType datatype)
{
- this->addInputSocket(datatype);
- this->m_memoryProxy = new MemoryProxy(datatype);
- this->m_memoryProxy->setWriteBufferOperation(this);
- this->m_memoryProxy->setExecutor(nullptr);
- flags.is_write_buffer_operation = true;
+ this->add_input_socket(datatype);
+ memory_proxy_ = new MemoryProxy(datatype);
+ memory_proxy_->set_write_buffer_operation(this);
+ memory_proxy_->set_executor(nullptr);
+ flags_.is_write_buffer_operation = true;
}
WriteBufferOperation::~WriteBufferOperation()
{
- if (this->m_memoryProxy) {
- delete this->m_memoryProxy;
- this->m_memoryProxy = nullptr;
+ if (memory_proxy_) {
+ delete memory_proxy_;
+ memory_proxy_ = nullptr;
}
}
-void WriteBufferOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void WriteBufferOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
- this->m_input->readSampled(output, x, y, sampler);
+ input_->read_sampled(output, x, y, sampler);
}
-void WriteBufferOperation::initExecution()
+void WriteBufferOperation::init_execution()
{
- this->m_input = this->getInputOperation(0);
- this->m_memoryProxy->allocate(this->getWidth(), this->getHeight());
+ input_ = this->get_input_operation(0);
+ memory_proxy_->allocate(this->get_width(), this->get_height());
}
-void WriteBufferOperation::deinitExecution()
+void WriteBufferOperation::deinit_execution()
{
- this->m_input = nullptr;
- this->m_memoryProxy->free();
+ input_ = nullptr;
+ memory_proxy_->free();
}
-void WriteBufferOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
+void WriteBufferOperation::execute_region(rcti *rect, unsigned int /*tile_number*/)
{
- MemoryBuffer *memoryBuffer = this->m_memoryProxy->getBuffer();
- float *buffer = memoryBuffer->getBuffer();
- const uint8_t num_channels = memoryBuffer->get_num_channels();
- if (this->m_input->get_flags().complex) {
- void *data = this->m_input->initializeTileData(rect);
+ MemoryBuffer *memory_buffer = memory_proxy_->get_buffer();
+ float *buffer = memory_buffer->get_buffer();
+ const uint8_t num_channels = memory_buffer->get_num_channels();
+ if (input_->get_flags().complex) {
+ void *data = input_->initialize_tile_data(rect);
int x1 = rect->xmin;
int y1 = rect->ymin;
int x2 = rect->xmax;
@@ -74,17 +72,17 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/
int y;
bool breaked = false;
for (y = y1; y < y2 && (!breaked); y++) {
- int offset4 = (y * memoryBuffer->getWidth() + x1) * num_channels;
+ int offset4 = (y * memory_buffer->get_width() + x1) * num_channels;
for (x = x1; x < x2; x++) {
- this->m_input->read(&(buffer[offset4]), x, y, data);
+ input_->read(&(buffer[offset4]), x, y, data);
offset4 += num_channels;
}
- if (isBraked()) {
+ if (is_braked()) {
breaked = true;
}
}
if (data) {
- this->m_input->deinitializeTileData(rect, data);
+ input_->deinitialize_tile_data(rect, data);
data = nullptr;
}
}
@@ -98,25 +96,25 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/
int y;
bool breaked = false;
for (y = y1; y < y2 && (!breaked); y++) {
- int offset4 = (y * memoryBuffer->getWidth() + x1) * num_channels;
+ int offset4 = (y * memory_buffer->get_width() + x1) * num_channels;
for (x = x1; x < x2; x++) {
- this->m_input->readSampled(&(buffer[offset4]), x, y, PixelSampler::Nearest);
+ input_->read_sampled(&(buffer[offset4]), x, y, PixelSampler::Nearest);
offset4 += num_channels;
}
- if (isBraked()) {
+ if (is_braked()) {
breaked = true;
}
}
}
}
-void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device,
- rcti * /*rect*/,
- unsigned int /*chunkNumber*/,
- MemoryBuffer **inputMemoryBuffers,
- MemoryBuffer *outputBuffer)
+void WriteBufferOperation::execute_opencl_region(OpenCLDevice *device,
+ rcti * /*rect*/,
+ unsigned int /*chunk_number*/,
+ MemoryBuffer **input_memory_buffers,
+ MemoryBuffer *output_buffer)
{
- float *outputFloatBuffer = outputBuffer->getBuffer();
+ float *output_float_buffer = output_buffer->get_buffer();
cl_int error;
/*
* 1. create cl_mem from outputbuffer
@@ -127,55 +125,55 @@ void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device,
* NOTE: list of cl_mem will be filled by 2, and needs to be cleaned up by 4
*/
/* STEP 1 */
- const unsigned int outputBufferWidth = outputBuffer->getWidth();
- const unsigned int outputBufferHeight = outputBuffer->getHeight();
-
- const cl_image_format *imageFormat = OpenCLDevice::determineImageFormat(outputBuffer);
-
- cl_mem clOutputBuffer = clCreateImage2D(device->getContext(),
- CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR,
- imageFormat,
- outputBufferWidth,
- outputBufferHeight,
- 0,
- outputFloatBuffer,
- &error);
+ const unsigned int output_buffer_width = output_buffer->get_width();
+ const unsigned int output_buffer_height = output_buffer->get_height();
+
+ const cl_image_format *image_format = OpenCLDevice::determine_image_format(output_buffer);
+
+ cl_mem cl_output_buffer = clCreateImage2D(device->get_context(),
+ CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR,
+ image_format,
+ output_buffer_width,
+ output_buffer_height,
+ 0,
+ output_float_buffer,
+ &error);
if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
/* STEP 2 */
- std::list<cl_mem> *clMemToCleanUp = new std::list<cl_mem>();
- clMemToCleanUp->push_back(clOutputBuffer);
- std::list<cl_kernel> *clKernelsToCleanUp = new std::list<cl_kernel>();
+ std::list<cl_mem> *cl_mem_to_clean_up = new std::list<cl_mem>();
+ cl_mem_to_clean_up->push_back(cl_output_buffer);
+ std::list<cl_kernel> *cl_kernels_to_clean_up = new std::list<cl_kernel>();
- this->m_input->executeOpenCL(device,
- outputBuffer,
- clOutputBuffer,
- inputMemoryBuffers,
- clMemToCleanUp,
- clKernelsToCleanUp);
+ input_->execute_opencl(device,
+ output_buffer,
+ cl_output_buffer,
+ input_memory_buffers,
+ cl_mem_to_clean_up,
+ cl_kernels_to_clean_up);
/* STEP 3 */
size_t origin[3] = {0, 0, 0};
- size_t region[3] = {outputBufferWidth, outputBufferHeight, 1};
+ size_t region[3] = {output_buffer_width, output_buffer_height, 1};
// clFlush(queue);
// clFinish(queue);
- error = clEnqueueBarrier(device->getQueue());
+ error = clEnqueueBarrier(device->get_queue());
if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
- error = clEnqueueReadImage(device->getQueue(),
- clOutputBuffer,
+ error = clEnqueueReadImage(device->get_queue(),
+ cl_output_buffer,
CL_TRUE,
origin,
region,
0,
0,
- outputFloatBuffer,
+ output_float_buffer,
0,
nullptr,
nullptr);
@@ -183,49 +181,49 @@ void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device,
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
- this->getMemoryProxy()->getBuffer()->fill_from(*outputBuffer);
+ this->get_memory_proxy()->get_buffer()->fill_from(*output_buffer);
/* STEP 4 */
- while (!clMemToCleanUp->empty()) {
- cl_mem mem = clMemToCleanUp->front();
+ while (!cl_mem_to_clean_up->empty()) {
+ cl_mem mem = cl_mem_to_clean_up->front();
error = clReleaseMemObject(mem);
if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
- clMemToCleanUp->pop_front();
+ cl_mem_to_clean_up->pop_front();
}
- while (!clKernelsToCleanUp->empty()) {
- cl_kernel kernel = clKernelsToCleanUp->front();
+ while (!cl_kernels_to_clean_up->empty()) {
+ cl_kernel kernel = cl_kernels_to_clean_up->front();
error = clReleaseKernel(kernel);
if (error != CL_SUCCESS) {
printf("CLERROR[%d]: %s\n", error, clewErrorString(error));
}
- clKernelsToCleanUp->pop_front();
+ cl_kernels_to_clean_up->pop_front();
}
- delete clKernelsToCleanUp;
+ delete cl_kernels_to_clean_up;
}
void WriteBufferOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
NodeOperation::determine_canvas(preferred_area, r_area);
/* make sure there is at least one pixel stored in case the input is a single value */
- m_single_value = false;
+ single_value_ = false;
if (BLI_rcti_size_x(&r_area) == 0) {
r_area.xmax += 1;
- m_single_value = true;
+ single_value_ = true;
}
if (BLI_rcti_size_y(&r_area) == 0) {
r_area.ymax += 1;
- m_single_value = true;
+ single_value_ = true;
}
}
-void WriteBufferOperation::readResolutionFromInputSocket()
+void WriteBufferOperation::read_resolution_from_input_socket()
{
- NodeOperation *inputOperation = this->getInputOperation(0);
- this->setWidth(inputOperation->getWidth());
- this->setHeight(inputOperation->getHeight());
+ NodeOperation *input_operation = this->get_input_operation(0);
+ this->set_width(input_operation->get_width());
+ this->set_height(input_operation->get_height());
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.h b/source/blender/compositor/operations/COM_WriteBufferOperation.h
index b7dededc69f..cf6b7f655ce 100644
--- a/source/blender/compositor/operations/COM_WriteBufferOperation.h
+++ b/source/blender/compositor/operations/COM_WriteBufferOperation.h
@@ -31,36 +31,36 @@ class MemoryProxy;
* \ingroup Operation
*/
class WriteBufferOperation : public NodeOperation {
- MemoryProxy *m_memoryProxy;
- bool m_single_value; /* single value stored in buffer */
- NodeOperation *m_input;
+ MemoryProxy *memory_proxy_;
+ bool single_value_; /* single value stored in buffer */
+ NodeOperation *input_;
public:
WriteBufferOperation(DataType datatype);
~WriteBufferOperation();
- MemoryProxy *getMemoryProxy()
+ MemoryProxy *get_memory_proxy()
{
- return this->m_memoryProxy;
+ return memory_proxy_;
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
- bool isSingleValue() const
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
+ bool is_single_value() const
{
- return m_single_value;
+ return single_value_;
}
- void executeRegion(rcti *rect, unsigned int tileNumber) override;
- void initExecution() override;
- void deinitExecution() override;
- void executeOpenCLRegion(OpenCLDevice *device,
- rcti *rect,
- unsigned int chunkNumber,
- MemoryBuffer **memoryBuffers,
- MemoryBuffer *outputBuffer) override;
+ void execute_region(rcti *rect, unsigned int tile_number) override;
+ void init_execution() override;
+ void deinit_execution() override;
+ void execute_opencl_region(OpenCLDevice *device,
+ rcti *rect,
+ unsigned int chunk_number,
+ MemoryBuffer **memory_buffers,
+ MemoryBuffer *output_buffer) override;
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
- void readResolutionFromInputSocket();
- inline NodeOperation *getInput()
+ void read_resolution_from_input_socket();
+ inline NodeOperation *get_input()
{
- return m_input;
+ return input_;
}
};
diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.cc b/source/blender/compositor/operations/COM_ZCombineOperation.cc
index 7050c3b2d83..c9b3e70a9cd 100644
--- a/source/blender/compositor/operations/COM_ZCombineOperation.cc
+++ b/source/blender/compositor/operations/COM_ZCombineOperation.cc
@@ -17,48 +17,47 @@
*/
#include "COM_ZCombineOperation.h"
-#include "BLI_utildefines.h"
namespace blender::compositor {
ZCombineOperation::ZCombineOperation()
{
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Value);
- this->addOutputSocket(DataType::Color);
-
- this->m_image1Reader = nullptr;
- this->m_depth1Reader = nullptr;
- this->m_image2Reader = nullptr;
- this->m_depth2Reader = nullptr;
- this->flags.can_be_constant = true;
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Value);
+ this->add_output_socket(DataType::Color);
+
+ image1Reader_ = nullptr;
+ depth1Reader_ = nullptr;
+ image2Reader_ = nullptr;
+ depth2Reader_ = nullptr;
+ flags_.can_be_constant = true;
}
-void ZCombineOperation::initExecution()
+void ZCombineOperation::init_execution()
{
- this->m_image1Reader = this->getInputSocketReader(0);
- this->m_depth1Reader = this->getInputSocketReader(1);
- this->m_image2Reader = this->getInputSocketReader(2);
- this->m_depth2Reader = this->getInputSocketReader(3);
+ image1Reader_ = this->get_input_socket_reader(0);
+ depth1Reader_ = this->get_input_socket_reader(1);
+ image2Reader_ = this->get_input_socket_reader(2);
+ depth2Reader_ = this->get_input_socket_reader(3);
}
-void ZCombineOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ZCombineOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float depth1[4];
float depth2[4];
- this->m_depth1Reader->readSampled(depth1, x, y, sampler);
- this->m_depth2Reader->readSampled(depth2, x, y, sampler);
+ depth1Reader_->read_sampled(depth1, x, y, sampler);
+ depth2Reader_->read_sampled(depth2, x, y, sampler);
if (depth1[0] < depth2[0]) {
- this->m_image1Reader->readSampled(output, x, y, sampler);
+ image1Reader_->read_sampled(output, x, y, sampler);
}
else {
- this->m_image2Reader->readSampled(output, x, y, sampler);
+ image2Reader_->read_sampled(output, x, y, sampler);
}
}
@@ -74,25 +73,25 @@ void ZCombineOperation::update_memory_buffer_partial(MemoryBuffer *output,
}
}
-void ZCombineAlphaOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ZCombineAlphaOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float depth1[4];
float depth2[4];
float color1[4];
float color2[4];
- this->m_depth1Reader->readSampled(depth1, x, y, sampler);
- this->m_depth2Reader->readSampled(depth2, x, y, sampler);
+ depth1Reader_->read_sampled(depth1, x, y, sampler);
+ depth2Reader_->read_sampled(depth2, x, y, sampler);
if (depth1[0] <= depth2[0]) {
- this->m_image1Reader->readSampled(color1, x, y, sampler);
- this->m_image2Reader->readSampled(color2, x, y, sampler);
+ image1Reader_->read_sampled(color1, x, y, sampler);
+ image2Reader_->read_sampled(color2, x, y, sampler);
}
else {
- this->m_image1Reader->readSampled(color2, x, y, sampler);
- this->m_image2Reader->readSampled(color1, x, y, sampler);
+ image1Reader_->read_sampled(color2, x, y, sampler);
+ image2Reader_->read_sampled(color1, x, y, sampler);
}
float fac = color1[3];
float ifac = 1.0f - fac;
@@ -128,46 +127,46 @@ void ZCombineAlphaOperation::update_memory_buffer_partial(MemoryBuffer *output,
}
}
-void ZCombineOperation::deinitExecution()
+void ZCombineOperation::deinit_execution()
{
- this->m_image1Reader = nullptr;
- this->m_depth1Reader = nullptr;
- this->m_image2Reader = nullptr;
- this->m_depth2Reader = nullptr;
+ image1Reader_ = nullptr;
+ depth1Reader_ = nullptr;
+ image2Reader_ = nullptr;
+ depth2Reader_ = nullptr;
}
// MASK combine
ZCombineMaskOperation::ZCombineMaskOperation()
{
- this->addInputSocket(DataType::Value); // mask
- this->addInputSocket(DataType::Color);
- this->addInputSocket(DataType::Color);
- this->addOutputSocket(DataType::Color);
-
- this->m_maskReader = nullptr;
- this->m_image1Reader = nullptr;
- this->m_image2Reader = nullptr;
+ this->add_input_socket(DataType::Value); // mask
+ this->add_input_socket(DataType::Color);
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+
+ mask_reader_ = nullptr;
+ image1Reader_ = nullptr;
+ image2Reader_ = nullptr;
}
-void ZCombineMaskOperation::initExecution()
+void ZCombineMaskOperation::init_execution()
{
- this->m_maskReader = this->getInputSocketReader(0);
- this->m_image1Reader = this->getInputSocketReader(1);
- this->m_image2Reader = this->getInputSocketReader(2);
+ mask_reader_ = this->get_input_socket_reader(0);
+ image1Reader_ = this->get_input_socket_reader(1);
+ image2Reader_ = this->get_input_socket_reader(2);
}
-void ZCombineMaskOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ZCombineMaskOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float mask[4];
float color1[4];
float color2[4];
- this->m_maskReader->readSampled(mask, x, y, sampler);
- this->m_image1Reader->readSampled(color1, x, y, sampler);
- this->m_image2Reader->readSampled(color2, x, y, sampler);
+ mask_reader_->read_sampled(mask, x, y, sampler);
+ image1Reader_->read_sampled(color1, x, y, sampler);
+ image2Reader_->read_sampled(color2, x, y, sampler);
interp_v4_v4v4(output, color1, color2, 1.0f - mask[0]);
}
@@ -184,18 +183,18 @@ void ZCombineMaskOperation::update_memory_buffer_partial(MemoryBuffer *output,
}
}
-void ZCombineMaskAlphaOperation::executePixelSampled(float output[4],
- float x,
- float y,
- PixelSampler sampler)
+void ZCombineMaskAlphaOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
{
float mask[4];
float color1[4];
float color2[4];
- this->m_maskReader->readSampled(mask, x, y, sampler);
- this->m_image1Reader->readSampled(color1, x, y, sampler);
- this->m_image2Reader->readSampled(color2, x, y, sampler);
+ mask_reader_->read_sampled(mask, x, y, sampler);
+ image1Reader_->read_sampled(color1, x, y, sampler);
+ image2Reader_->read_sampled(color2, x, y, sampler);
float fac = (1.0f - mask[0]) * (1.0f - color1[3]) + mask[0] * color2[3];
float mfac = 1.0f - fac;
@@ -224,11 +223,11 @@ void ZCombineMaskAlphaOperation::update_memory_buffer_partial(MemoryBuffer *outp
}
}
-void ZCombineMaskOperation::deinitExecution()
+void ZCombineMaskOperation::deinit_execution()
{
- this->m_image1Reader = nullptr;
- this->m_maskReader = nullptr;
- this->m_image2Reader = nullptr;
+ image1Reader_ = nullptr;
+ mask_reader_ = nullptr;
+ image2Reader_ = nullptr;
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.h b/source/blender/compositor/operations/COM_ZCombineOperation.h
index acd60b6c866..ffc1bdd93b4 100644
--- a/source/blender/compositor/operations/COM_ZCombineOperation.h
+++ b/source/blender/compositor/operations/COM_ZCombineOperation.h
@@ -28,10 +28,10 @@ namespace blender::compositor {
*/
class ZCombineOperation : public MultiThreadedOperation {
protected:
- SocketReader *m_image1Reader;
- SocketReader *m_depth1Reader;
- SocketReader *m_image2Reader;
- SocketReader *m_depth2Reader;
+ SocketReader *image1Reader_;
+ SocketReader *depth1Reader_;
+ SocketReader *image2Reader_;
+ SocketReader *depth2Reader_;
public:
/**
@@ -39,13 +39,13 @@ class ZCombineOperation : public MultiThreadedOperation {
*/
ZCombineOperation();
- void initExecution() override;
- void deinitExecution() override;
+ void init_execution() override;
+ void deinit_execution() override;
/**
* The inner loop of this operation.
*/
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
@@ -53,7 +53,7 @@ class ZCombineOperation : public MultiThreadedOperation {
};
class ZCombineAlphaOperation : public ZCombineOperation {
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
@@ -62,23 +62,23 @@ class ZCombineAlphaOperation : public ZCombineOperation {
class ZCombineMaskOperation : public MultiThreadedOperation {
protected:
- SocketReader *m_maskReader;
- SocketReader *m_image1Reader;
- SocketReader *m_image2Reader;
+ SocketReader *mask_reader_;
+ SocketReader *image1Reader_;
+ SocketReader *image2Reader_;
public:
ZCombineMaskOperation();
- void initExecution() override;
- void deinitExecution() override;
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void init_execution() override;
+ void deinit_execution() override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
};
class ZCombineMaskAlphaOperation : public ZCombineMaskOperation {
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/tests/COM_NodeOperation_test.cc b/source/blender/compositor/tests/COM_NodeOperation_test.cc
index 94e9fdeedb1..ea61df22f88 100644
--- a/source/blender/compositor/tests/COM_NodeOperation_test.cc
+++ b/source/blender/compositor/tests/COM_NodeOperation_test.cc
@@ -27,9 +27,9 @@ class NonHashedOperation : public NodeOperation {
NonHashedOperation(int id)
{
set_id(id);
- addOutputSocket(DataType::Value);
- setWidth(2);
- setHeight(3);
+ add_output_socket(DataType::Value);
+ set_width(2);
+ set_height(3);
}
};
@@ -40,9 +40,9 @@ class NonHashedConstantOperation : public ConstantOperation {
NonHashedConstantOperation(int id)
{
set_id(id);
- addOutputSocket(DataType::Value);
- setWidth(2);
- setHeight(3);
+ add_output_socket(DataType::Value);
+ set_width(2);
+ set_height(3);
constant_ = 1.0f;
}
@@ -65,14 +65,14 @@ class HashedOperation : public NodeOperation {
public:
HashedOperation(NodeOperation &input, int width, int height)
{
- addInputSocket(DataType::Value);
- addOutputSocket(DataType::Color);
- setWidth(width);
- setHeight(height);
+ add_input_socket(DataType::Value);
+ add_output_socket(DataType::Color);
+ set_width(width);
+ set_height(height);
param1 = 2;
param2 = 7.0f;
- getInputSocket(0)->setLink(input.getOutputSocket());
+ get_input_socket(0)->set_link(input.get_output_socket());
}
void set_param1(int value)
diff --git a/source/blender/datatoc/CMakeLists.txt b/source/blender/datatoc/CMakeLists.txt
index 8411a1a468e..756ab15b163 100644
--- a/source/blender/datatoc/CMakeLists.txt
+++ b/source/blender/datatoc/CMakeLists.txt
@@ -52,10 +52,6 @@ if(NOT WITH_HEADLESS)
endif()
include_directories(${PNG_INCLUDE_DIRS})
- if(NOT APPLE)
- # APPLE platform uses full paths for linking libraries.
- link_directories(${PNG_LIBPATH} ${ZLIB_LIBPATH})
- endif()
add_executable(datatoc_icon ${SRC})
setup_platform_linker_flags(datatoc_icon)
diff --git a/source/blender/datatoc/datatoc_icon.c b/source/blender/datatoc/datatoc_icon.c
index ba7120daa92..b4ee1c6d4c9 100644
--- a/source/blender/datatoc/datatoc_icon.c
+++ b/source/blender/datatoc/datatoc_icon.c
@@ -32,7 +32,7 @@
# include <dirent.h>
#endif
-#include "png.h"
+#include <png.h>
/* for Win32 DIR functions */
#ifdef WIN32
@@ -245,7 +245,7 @@ static struct IconInfo *icon_merge_context_info_for_icon_head(struct IconMergeCo
static void icon_merge_context_register_icon(struct IconMergeContext *context,
const char *file_name,
- struct IconHead *icon_head)
+ const struct IconHead *icon_head)
{
context->read_icons = realloc(context->read_icons,
sizeof(struct IconInfo) * (context->num_read_icons + 1));
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index aa184cce433..b8ff49640b7 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -80,45 +80,67 @@ extern "C" {
/* ************************************************ */
/* Depsgraph API */
-/* CRUD ------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name CRUD
+ * \{ */
/* Get main depsgraph instance from context! */
-/* Create new Depsgraph instance */
-/* TODO: what args are needed here? What's the building-graph entry point? */
+/**
+ * Create new Depsgraph instance.
+ *
+ * TODO: what arguments are needed here? What's the building-graph entry point?
+ */
Depsgraph *DEG_graph_new(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
eEvaluationMode mode);
+/**
+ * Replace the "owner" pointers (currently Main/Scene/ViewLayer) of this depsgraph.
+ * Used for:
+ * - Undo steps when we do want to re-use the old depsgraph data as much as possible.
+ * - Rendering where we want to re-use objects between different view layers.
+ */
void DEG_graph_replace_owners(struct Depsgraph *depsgraph,
struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
-/* Free Depsgraph itself and all its data */
+/** Free graph's contents and graph itself. */
void DEG_graph_free(Depsgraph *graph);
-/* Node Types Registry ---------------------------- */
+/** \} */
-/* Register all node types */
+/* -------------------------------------------------------------------- */
+/** \name Node Types Registry
+ * \{ */
+
+/** Register all node types. */
void DEG_register_node_types(void);
-/* Free node type registry on exit */
+/** Free node type registry on exit. */
void DEG_free_node_types(void);
-/* Update Tagging -------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Update Tagging
+ * \{ */
-/* Tag dependency graph for updates when visible scenes/layers changes. */
-void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, const bool do_time);
+/** Tag dependency graph for updates when visible scenes/layers changes. */
+void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, bool do_time);
-/* Tag all dependency graphs for update when visible scenes/layers changes. */
-void DEG_tag_on_visible_update(struct Main *bmain, const bool do_time);
+/** Tag all dependency graphs for update when visible scenes/layers changes. */
+void DEG_tag_on_visible_update(struct Main *bmain, bool do_time);
-/* NOTE: Will return NULL if the flag is not known, allowing to gracefully handle situations
- * when recalc flag has been removed. */
+/**
+ * \note Will return NULL if the flag is not known, allowing to gracefully handle situations
+ * when recalc flag has been removed.
+ */
const char *DEG_update_tag_as_string(IDRecalcFlag flag);
+/** Tag given ID for an update in all the dependency graphs. */
void DEG_id_tag_update(struct ID *id, int flag);
void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag);
@@ -127,48 +149,68 @@ void DEG_graph_id_tag_update(struct Main *bmain,
struct ID *id,
int flag);
-/* Tag all dependency graphs when time has changed. */
+/** Tag all dependency graphs when time has changed. */
void DEG_time_tag_update(struct Main *bmain);
-/* Tag a dependency graph when time has changed. */
+/** Tag a dependency graph when time has changed. */
void DEG_graph_time_tag_update(struct Depsgraph *depsgraph);
-/* Mark a particular datablock type as having changing. This does
- * not cause any updates but is used by external render engines to detect if for
- * example a datablock was removed. */
+/**
+ * Mark a particular data-block type as having changing.
+ * This does not cause any updates but is used by external
+ * render engines to detect if for example a data-block was removed.
+ */
void DEG_graph_id_type_tag(struct Depsgraph *depsgraph, short id_type);
void DEG_id_type_tag(struct Main *bmain, short id_type);
-/* Set a depsgraph to flush updates to editors. This would be done
- * for viewport depsgraphs, but not render or export depsgraph for example. */
+/**
+ * Set a depsgraph to flush updates to editors. This would be done
+ * for viewport depsgraphs, but not render or export depsgraph for example.
+ */
void DEG_enable_editors_update(struct Depsgraph *depsgraph);
-/* Check if something was changed in the database and inform editors about this. */
+/** Check if something was changed in the database and inform editors about this. */
void DEG_editors_update(struct Depsgraph *depsgraph, bool time);
-/* Clear recalc flags after editors or renderers have handled updates. */
-void DEG_ids_clear_recalc(Depsgraph *depsgraph, const bool backup);
+/** Clear recalc flags after editors or renderers have handled updates. */
+void DEG_ids_clear_recalc(Depsgraph *depsgraph, bool backup);
-/* Restore recalc flags, backed up by a previous call to DEG_ids_clear_recalc.
- * This also clears the backup. */
+/**
+ * Restore recalc flags, backed up by a previous call to #DEG_ids_clear_recalc.
+ * This also clears the backup.
+ */
void DEG_ids_restore_recalc(Depsgraph *depsgraph);
+/** \} */
+
/* ************************************************ */
/* Evaluation Engine API */
-/* Graph Evaluation ----------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Graph Evaluation
+ * \{ */
-/* Frame changed recalculation entry point. */
+/**
+ * Frame changed recalculation entry point.
+ *
+ * \note The frame-change happened for root scene that graph belongs to.
+ */
void DEG_evaluate_on_framechange(Depsgraph *graph, float frame);
-/* Data changed recalculation entry point. */
+/**
+ * Data changed recalculation entry point.
+ * Evaluate all nodes tagged for updating.
+ */
void DEG_evaluate_on_refresh(Depsgraph *graph);
-/* Editors Integration -------------------------- */
+/** \} */
-/* Mechanism to allow editors to be informed of depsgraph updates,
+/* -------------------------------------------------------------------- */
+/** \name Editors Integration
+ *
+ * Mechanism to allow editors to be informed of depsgraph updates,
* to do their own updates based on changes.
- */
+ * \{ */
typedef struct DEGEditorUpdateContext {
struct Main *bmain;
@@ -178,13 +220,16 @@ typedef struct DEGEditorUpdateContext {
} DEGEditorUpdateContext;
typedef void (*DEG_EditorUpdateIDCb)(const DEGEditorUpdateContext *update_ctx, struct ID *id);
-typedef void (*DEG_EditorUpdateSceneCb)(const DEGEditorUpdateContext *update_ctx,
- const bool updated);
+typedef void (*DEG_EditorUpdateSceneCb)(const DEGEditorUpdateContext *update_ctx, bool updated);
-/* Set callbacks which are being called when depsgraph changes. */
+/** Set callbacks which are being called when depsgraph changes. */
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSceneCb scene_func);
-/* Evaluation ----------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation
+ * \{ */
bool DEG_is_evaluating(const struct Depsgraph *depsgraph);
@@ -192,7 +237,11 @@ bool DEG_is_active(const struct Depsgraph *depsgraph);
void DEG_make_active(struct Depsgraph *depsgraph);
void DEG_make_inactive(struct Depsgraph *depsgraph);
-/* Evaluation Debug ------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation Debug
+ * \{ */
void DEG_debug_print_begin(struct Depsgraph *depsgraph);
@@ -216,7 +265,7 @@ void DEG_debug_print_eval_subdata_index(struct Depsgraph *depsgraph,
const char *subdata_comment,
const char *subdata_name,
const void *subdata_address,
- const int subdata_index);
+ int subdata_index);
void DEG_debug_print_eval_parent_typed(struct Depsgraph *depsgraph,
const char *function_name,
@@ -232,6 +281,8 @@ void DEG_debug_print_eval_time(struct Depsgraph *depsgraph,
const void *object_address,
float time);
+/** \} */
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index c029d203574..0461d8b63fd 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -50,37 +50,43 @@ extern "C" {
/* Graph Building -------------------------------- */
-/* Build depsgraph for the given scene, and dump results in given graph container. */
+/** Build depsgraph for the given scene layer, and dump results in given graph container. */
void DEG_graph_build_from_view_layer(struct Depsgraph *graph);
-/* Build depsgraph for all objects (so also invisible ones) in the given view layer. */
+/**
+ * Build depsgraph for all objects (so also invisible ones) in the given view layer.
+ */
void DEG_graph_build_for_all_objects(struct Depsgraph *graph);
-/* Special version of builder which produces dependency graph suitable for the render pipeline.
- * It will contain sequencer and compositor (if needed) and all their dependencies. */
+/**
+ * Special version of builder which produces dependency graph suitable for the render pipeline.
+ * It will contain sequencer and compositor (if needed) and all their dependencies.
+ */
void DEG_graph_build_for_render_pipeline(struct Depsgraph *graph);
-/* Builds minimal dependency graph for compositor preview.
+/**
+ * Builds minimal dependency graph for compositor preview.
*
* Note that compositor editor might have pinned node tree, which is different from scene's node
* tree.
*/
void DEG_graph_build_for_compositor_preview(struct Depsgraph *graph, struct bNodeTree *nodetree);
-void DEG_graph_build_from_ids(struct Depsgraph *graph, struct ID **ids, const int num_ids);
+void DEG_graph_build_from_ids(struct Depsgraph *graph, struct ID **ids, int num_ids);
-/* Tag relations from the given graph for update. */
+/** Tag relations from the given graph for update. */
void DEG_graph_tag_relations_update(struct Depsgraph *graph);
-/* Create or update relations in the specified graph. */
+/** Create or update relations in the specified graph. */
void DEG_graph_relations_update(struct Depsgraph *graph);
-/* Tag all relations in the database for update. */
+/** Tag all relations in the database for update. */
void DEG_relations_tag_update(struct Main *bmain);
/* Add Dependencies ----------------------------- */
-/* Handle for components to define their dependencies from callbacks.
+/**
+ * Handle for components to define their dependencies from callbacks.
* This is generated by the depsgraph and passed to dependency callbacks
* as a symbolic reference to the current DepsNode.
* All relations will be defined in reference to that node.
@@ -114,7 +120,7 @@ typedef enum eDepsObjectComponentType {
DEG_OB_COMP_ANIMATION,
/* Transform Component (Parenting/Constraints) */
DEG_OB_COMP_TRANSFORM,
- /* Geometry Component (Mesh/Displist) */
+ /* Geometry Component (#Mesh / #DispList). */
DEG_OB_COMP_GEOMETRY,
/* Evaluation-Related Outer Types (with Sub-data) */
@@ -147,9 +153,9 @@ void DEG_add_collection_geometry_customdata_mask(struct DepsNodeHandle *node_han
void DEG_add_simulation_relation(struct DepsNodeHandle *node_handle,
struct Simulation *simulation,
const char *description);
-void DEG_add_node_tree_relation(struct DepsNodeHandle *node_handle,
- struct bNodeTree *node_tree,
- const char *description);
+void DEG_add_node_tree_output_relation(struct DepsNodeHandle *node_handle,
+ struct bNodeTree *node_tree,
+ const char *description);
void DEG_add_bone_relation(struct DepsNodeHandle *handle,
struct Object *object,
const char *bone_name,
@@ -159,23 +165,28 @@ void DEG_add_object_cache_relation(struct DepsNodeHandle *handle,
struct CacheFile *cache_file,
eDepsObjectComponentType component,
const char *description);
-/* Adds relation from DEG_OPCODE_GENERIC_DATABLOCK_UPDATE of a given ID.
- * Is used for such entities as textures and images. */
+/**
+ * Adds relation from #DEG_OPCODE_GENERIC_DATABLOCK_UPDATE of a given ID.
+ * Is used for such entities as textures and images.
+ */
void DEG_add_generic_id_relation(struct DepsNodeHandle *node_handle,
struct ID *id,
const char *description);
-/* Special function which is used from modifiers' updateDepsgraph() callback
+/**
+ * Special function which is used from modifiers' #updateDepsgraph() callback
* to indicate that the modifier needs to know transformation of the object
* which that modifier belongs to.
* This function will take care of checking which operation is required to
- * have transformation for the modifier, taking into account possible simulation
- * solvers. */
+ * have transformation for the modifier, taking into account possible simulation solvers.
+ */
void DEG_add_modifier_to_transform_relation(struct DepsNodeHandle *node_handle,
const char *description);
-/* Adds relations from the given component of a given object to the given node
- * handle AND the component to the point cache component of the node's ID. */
+/**
+ * Adds relations from the given component of a given object to the given node
+ * handle AND the component to the point cache component of the node's ID.
+ */
void DEG_add_object_pointcache_relation(struct DepsNodeHandle *node_handle,
struct Object *object,
eDepsObjectComponentType component,
diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h
index 2aea10fd5b4..5c400a1392f 100644
--- a/source/blender/depsgraph/DEG_depsgraph_debug.h
+++ b/source/blender/depsgraph/DEG_depsgraph_debug.h
@@ -37,7 +37,7 @@ struct ViewLayer;
/* ------------------------------------------------ */
-/* NOTE: Those flags are same bitmask as G.debug_flags */
+/* NOTE: Those flags are same bit-mask as #G.debug_flags */
void DEG_debug_flags_set(struct Depsgraph *depsgraph, int flags);
int DEG_debug_flags_get(const struct Depsgraph *depsgraph);
@@ -47,6 +47,12 @@ const char *DEG_debug_name_get(struct Depsgraph *depsgraph);
/* ------------------------------------------------ */
+/**
+ * Obtain simple statistics about the complexity of the depsgraph.
+ * \param[out] r_outer: The number of outer nodes in the graph.
+ * \param[out] r_operations: The number of operation nodes in the graph.
+ * \param[out] r_relations: The number of relations between (executable) nodes in the graph.
+ */
void DEG_stats_simple(const struct Depsgraph *graph,
size_t *r_outer,
size_t *r_operations,
@@ -64,16 +70,16 @@ void DEG_debug_stats_gnuplot(const struct Depsgraph *graph,
/* ************************************************ */
-/* Compare two dependency graphs. */
+/** Compare two dependency graphs. */
bool DEG_debug_compare(const struct Depsgraph *graph1, const struct Depsgraph *graph2);
-/* Check that dependencies in the graph are really up to date. */
+/** Check that dependencies in the graph are really up to date. */
bool DEG_debug_graph_relations_validate(struct Depsgraph *graph,
struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
-/* Perform consistency check on the graph. */
+/** Perform consistency check on the graph. */
bool DEG_debug_consistency_check(struct Depsgraph *graph);
#ifdef __cplusplus
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index e9195a1eb26..ebb5f4d669c 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -47,87 +47,106 @@ struct ViewLayer;
extern "C" {
#endif
-/* *********************** DEG input data ********************* */
+/* -------------------------------------------------------------------- */
+/** \name DEG input data
+ * \{ */
-/* Get scene that depsgraph was built for. */
+/** Get scene that depsgraph was built for. */
struct Scene *DEG_get_input_scene(const Depsgraph *graph);
-/* Get view layer that depsgraph was built for. */
+/** Get view layer that depsgraph was built for. */
struct ViewLayer *DEG_get_input_view_layer(const Depsgraph *graph);
-/* Get bmain that depsgraph was built for. */
+/** Get bmain that depsgraph was built for. */
struct Main *DEG_get_bmain(const Depsgraph *graph);
-/* Get evaluation mode that depsgraph was built for. */
+/** Get evaluation mode that depsgraph was built for. */
eEvaluationMode DEG_get_mode(const Depsgraph *graph);
-/* Get time that depsgraph is being evaluated or was last evaluated at. */
+/** Get time that depsgraph is being evaluated or was last evaluated at. */
float DEG_get_ctime(const Depsgraph *graph);
-/* ********************* DEG evaluated data ******************* */
+/** \} */
-/* Check if given ID type was tagged for update. */
+/* -------------------------------------------------------------------- */
+/** \name DEG evaluated data
+ * \{ */
+
+/** Check if given ID type was tagged for update. */
bool DEG_id_type_updated(const struct Depsgraph *depsgraph, short id_type);
bool DEG_id_type_any_updated(const struct Depsgraph *depsgraph);
-/* Check if given ID type is present in the depsgraph */
+/** Check if given ID type is present in the depsgraph */
bool DEG_id_type_any_exists(const struct Depsgraph *depsgraph, short id_type);
-/* Get additional evaluation flags for the given ID. */
+/** Get additional evaluation flags for the given ID. */
uint32_t DEG_get_eval_flags_for_id(const struct Depsgraph *graph, struct ID *id);
-/* Get additional mesh CustomData_MeshMasks flags for the given object. */
+/** Get additional mesh CustomData_MeshMasks flags for the given object. */
void DEG_get_customdata_mask_for_object(const struct Depsgraph *graph,
struct Object *object,
struct CustomData_MeshMasks *r_mask);
-/* Get scene at its evaluated state.
+/**
+ * Get scene at its evaluated state.
*
* Technically, this is a copied-on-written and fully evaluated version of the input scene.
* This function will check that the data-block has been expanded (and copied) from the original
- * one. Assert will happen if it's not. */
+ * one. Assert will happen if it's not.
+ */
struct Scene *DEG_get_evaluated_scene(const struct Depsgraph *graph);
-/* Get view layer at its evaluated state.
- * This is a shortcut for accessing active view layer from evaluated scene. */
+/**
+ * Get view layer at its evaluated state.
+ * This is a shortcut for accessing active view layer from evaluated scene.
+ */
struct ViewLayer *DEG_get_evaluated_view_layer(const struct Depsgraph *graph);
-/* Get evaluated version of object for given original one. */
+/** Get evaluated version of object for given original one. */
struct Object *DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object);
-/* Get evaluated version of given ID data-block. */
+/** Get evaluated version of given ID data-block. */
struct ID *DEG_get_evaluated_id(const struct Depsgraph *depsgraph, struct ID *id);
-/* Get evaluated version of data pointed to by RNA pointer */
+/** Get evaluated version of data pointed to by RNA pointer */
void DEG_get_evaluated_rna_pointer(const struct Depsgraph *depsgraph,
struct PointerRNA *ptr,
struct PointerRNA *r_ptr_eval);
-/* Get original version of object for given evaluated one. */
+/** Get original version of object for given evaluated one. */
struct Object *DEG_get_original_object(struct Object *object);
-/* Get original version of given evaluated ID data-block. */
+/** Get original version of given evaluated ID data-block. */
struct ID *DEG_get_original_id(struct ID *id);
-/* Check whether given ID is an original,
+/**
+ * Check whether given ID is an original,
*
* Original IDs are considered all the IDs which are not covered by copy-on-write system and are
- * not out-of-main localized data-blocks. */
+ * not out-of-main localized data-blocks.
+ */
bool DEG_is_original_id(const struct ID *id);
bool DEG_is_original_object(const struct Object *object);
/* Opposite of the above.
*
* If the data-block is not original it must be evaluated, and vice versa. */
+
bool DEG_is_evaluated_id(const struct ID *id);
bool DEG_is_evaluated_object(const struct Object *object);
-/* Check whether depsgraph is fully evaluated. This includes the following checks:
+/**
+ * Check whether depsgraph is fully evaluated. This includes the following checks:
* - Relations are up-to-date.
- * - Nothing is tagged for update. */
+ * - Nothing is tagged for update.
+ */
bool DEG_is_fully_evaluated(const struct Depsgraph *depsgraph);
-/* ************************ DEG object iterators ********************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DEG object iterators
+ * \{ */
enum {
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY = (1 << 0),
@@ -207,7 +226,11 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter);
#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END DEG_OBJECT_ITER_END
-/* ************************ DEG ID iterators ********************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DEG ID iterators
+ * \{ */
typedef struct DEGIDIterData {
struct Depsgraph *graph;
@@ -221,15 +244,20 @@ void DEG_iterator_ids_begin(struct BLI_Iterator *iter, DEGIDIterData *data);
void DEG_iterator_ids_next(struct BLI_Iterator *iter);
void DEG_iterator_ids_end(struct BLI_Iterator *iter);
-/* ************************ DEG traversal ********************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DEG traversal
+ * \{ */
typedef void (*DEGForeachIDCallback)(ID *id, void *user_data);
typedef void (*DEGForeachIDComponentCallback)(ID *id,
eDepsObjectComponentType component,
void *user_data);
-/* NOTE: Modifies runtime flags in depsgraph nodes, so can not be used in
- * parallel. Keep an eye on that!
+/**
+ * \note Modifies runtime flags in depsgraph nodes,
+ * so can not be used in parallel. Keep an eye on that!
*/
void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph,
const ID *id,
@@ -240,8 +268,10 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
DEGForeachIDCallback callback,
void *user_data);
-/* Starts traversal from given component of the given ID, invokes callback for every other
- * component which is directly on indirectly dependent on the source one. */
+/**
+ * Starts traversal from given component of the given ID, invokes callback for every other
+ * component which is directly on indirectly dependent on the source one.
+ */
enum {
/* Ignore transform solvers which depends on multiple inputs and affects final transform.
* Is used for cases like snapping objects which are part of a rigid body simulation:
@@ -262,6 +292,8 @@ void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph,
void DEG_foreach_ID(const Depsgraph *depsgraph, DEGForeachIDCallback callback, void *user_data);
+/** \} */
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 41512168f57..b2e136c3d3b 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -176,7 +176,22 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
for (Relation *rel : op_node->inlinks) {
if (rel->from->type == NodeType::OPERATION) {
OperationNode *op_from = (OperationNode *)rel->from;
- op_from->owner->affects_directly_visible |= op_node->owner->affects_directly_visible;
+ ComponentNode *comp_from = op_from->owner;
+ const bool target_directly_visible = op_node->owner->affects_directly_visible;
+
+ /* Visibility component forces all components of the current ID to be considered as
+ * affecting directly visible. */
+ if (comp_from->type == NodeType::VISIBILITY) {
+ if (target_directly_visible) {
+ IDNode *id_node_from = comp_from->owner;
+ for (ComponentNode *comp_node : id_node_from->components.values()) {
+ comp_node->affects_directly_visible |= target_directly_visible;
+ }
+ }
+ }
+ else {
+ comp_from->affects_directly_visible |= target_directly_visible;
+ }
}
}
/* Schedule parent nodes. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
index af7717d7595..0afaa72aad0 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
@@ -127,6 +127,7 @@ void AnimatedPropertyStorage::initializeFromID(DepsgraphBuilderCache *builder_ca
void AnimatedPropertyStorage::tagPropertyAsAnimated(const AnimatedPropertyID &property_id)
{
+ animated_objects_set.add(property_id.data);
animated_properties_set.add(property_id);
}
@@ -147,6 +148,11 @@ bool AnimatedPropertyStorage::isPropertyAnimated(const PointerRNA *pointer_rna,
return isPropertyAnimated(AnimatedPropertyID(pointer_rna, property_rna));
}
+bool AnimatedPropertyStorage::isAnyPropertyAnimated(const PointerRNA *pointer_rna)
+{
+ return animated_objects_set.contains(pointer_rna->data);
+}
+
/* Builder cache itself. */
DepsgraphBuilderCache::~DepsgraphBuilderCache()
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.h b/source/blender/depsgraph/intern/builder/deg_builder_cache.h
index c955a22a5cf..690046cb0d3 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cache.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.h
@@ -69,10 +69,13 @@ class AnimatedPropertyStorage {
bool isPropertyAnimated(const AnimatedPropertyID &property_id);
bool isPropertyAnimated(const PointerRNA *pointer_rna, const PropertyRNA *property_rna);
+ bool isAnyPropertyAnimated(const PointerRNA *pointer_rna);
+
/* The storage is fully initialized from all F-Curves from corresponding ID. */
bool is_fully_initialized;
/* indexed by PointerRNA.data. */
+ Set<void *> animated_objects_set;
Set<AnimatedPropertyID> animated_properties_set;
MEM_CXX_CLASS_ALLOC_FUNCS("AnimatedPropertyStorage");
@@ -102,6 +105,13 @@ class DepsgraphBuilderCache {
return animated_property_storage->isPropertyAnimated(args...);
}
+ bool isAnyPropertyAnimated(const PointerRNA *ptr)
+ {
+ AnimatedPropertyStorage *animated_property_storage = ensureInitializedAnimatedPropertyStorage(
+ ptr->owner_id);
+ return animated_property_storage->isAnyPropertyAnimated(ptr);
+ }
+
Map<ID *, AnimatedPropertyStorage *> animated_property_storage_map_;
MEM_CXX_CLASS_ALLOC_FUNCS("DepsgraphBuilderCache");
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index a09f79ffa39..79d674e8415 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -179,15 +179,28 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id)
id_node->previously_visible_components_mask = previously_visible_components_mask;
id_node->previous_eval_flags = previous_eval_flags;
id_node->previous_customdata_masks = previous_customdata_masks;
+
/* NOTE: Zero number of components indicates that ID node was just created. */
- if (id_node->components.is_empty() && deg_copy_on_write_is_needed(id_type)) {
- ComponentNode *comp_cow = id_node->add_component(NodeType::COPY_ON_WRITE);
- OperationNode *op_cow = comp_cow->add_operation(
- [id_node](::Depsgraph *depsgraph) { deg_evaluate_copy_on_write(depsgraph, id_node); },
- OperationCode::COPY_ON_WRITE,
- "",
- -1);
- graph_->operations.append(op_cow);
+ const bool is_newly_created = id_node->components.is_empty();
+
+ if (is_newly_created) {
+ if (deg_copy_on_write_is_needed(id_type)) {
+ ComponentNode *comp_cow = id_node->add_component(NodeType::COPY_ON_WRITE);
+ OperationNode *op_cow = comp_cow->add_operation(
+ [id_node](::Depsgraph *depsgraph) { deg_evaluate_copy_on_write(depsgraph, id_node); },
+ OperationCode::COPY_ON_WRITE,
+ "",
+ -1);
+ graph_->operations.append(op_cow);
+ }
+
+ ComponentNode *visibility_component = id_node->add_component(NodeType::VISIBILITY);
+ OperationNode *visibility_operation = visibility_component->add_operation(
+ nullptr, OperationCode::OPERATION, "", -1);
+ /* Pin the node so that it and its relations are preserved by the unused nodes/relations
+ * deletion. This is mainly to make it easier to debug visibility. */
+ visibility_operation->flag |= OperationFlag::DEPSOP_FLAG_PINNED;
+ graph_->operations.append(visibility_operation);
}
return id_node;
}
@@ -258,6 +271,21 @@ OperationNode *DepsgraphNodeBuilder::add_operation_node(ID *id,
OperationNode *DepsgraphNodeBuilder::ensure_operation_node(ID *id,
NodeType comp_type,
+ const char *comp_name,
+ OperationCode opcode,
+ const DepsEvalOperationCb &op,
+ const char *name,
+ int name_tag)
+{
+ OperationNode *operation = find_operation_node(id, comp_type, comp_name, opcode, name, name_tag);
+ if (operation != nullptr) {
+ return operation;
+ }
+ return add_operation_node(id, comp_type, comp_name, opcode, op, name, name_tag);
+}
+
+OperationNode *DepsgraphNodeBuilder::ensure_operation_node(ID *id,
+ NodeType comp_type,
OperationCode opcode,
const DepsEvalOperationCb &op,
const char *name,
@@ -375,8 +403,6 @@ void DepsgraphNodeBuilder::begin_build()
* NOTE: This is split in two, a static function and a public method of the node builder, to allow
* the code to access the builder's data more easily. */
-/* `id_cow_self` is the user of `id_pointer`, see also `LibraryIDLinkCallbackData` struct
- * definition. */
int DepsgraphNodeBuilder::foreach_id_cow_detect_need_for_update_callback(ID *id_cow_self,
ID *id_pointer)
{
@@ -425,21 +451,18 @@ static int foreach_id_cow_detect_need_for_update_callback(LibraryIDLinkCallbackD
return builder->foreach_id_cow_detect_need_for_update_callback(id_cow_self, id);
}
-/* Check for IDs that need to be flushed (COW-updated) because the depsgraph itself created or
- * removed some of their evaluated dependencies.
- *
- * NOTE: Currently the only ID types that depsgraph may decide to not evaluate/generate COW
- * copies for, even though they are referenced by other data-blocks, are Collections and Objects
- * (through their various visibility flags, and the ones from LayerCollections too). However, this
- * code is kept generic as it makes it more future-proof, and optimization here would give
- * negligible performance improvements in typical cases.
- *
- * NOTE: This mechanism may also 'fix' some missing update tagging from non-depsgraph code in
- * some cases. This is slightly unfortunate (as it may hide issues in other parts of Blender
- * code), but cannot really be avoided currently.
- */
void DepsgraphNodeBuilder::update_invalid_cow_pointers()
{
+ /* NOTE: Currently the only ID types that depsgraph may decide to not evaluate/generate COW
+ * copies for, even though they are referenced by other data-blocks, are Collections and Objects
+ * (through their various visibility flags, and the ones from #LayerCollections too). However,
+ * this code is kept generic as it makes it more future-proof, and optimization here would give
+ * negligible performance improvements in typical cases.
+ *
+ * NOTE: This mechanism may also 'fix' some missing update tagging from non-depsgraph code in
+ * some cases. This is slightly unfortunate (as it may hide issues in other parts of Blender
+ * code), but cannot really be avoided currently. */
+
for (const IDNode *id_node : graph_->id_nodes) {
if (id_node->previously_visible_components_mask == 0) {
/* Newly added node/ID, no need to check it. */
@@ -579,11 +602,7 @@ void DepsgraphNodeBuilder::build_id(ID *id)
case ID_HA:
case ID_PT:
case ID_VO:
- /* TODO(sergey): Get visibility from a "parent" somehow.
- *
- * NOTE: Similarly to above, we don't want false-positives on
- * visibility. */
- build_object_data_geometry_datablock(id, false);
+ build_object_data_geometry_datablock(id);
break;
case ID_SPK:
build_speaker((Speaker *)id);
@@ -759,32 +778,28 @@ void DepsgraphNodeBuilder::build_object(int base_index,
if (object->modifiers.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_visible;
BKE_modifiers_foreach_ID_link(object, modifier_walk, &data);
}
/* Grease Pencil Modifiers. */
if (object->greasepencil_modifiers.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_visible;
BKE_gpencil_modifiers_foreach_ID_link(object, modifier_walk, &data);
}
/* Shader FX. */
if (object->shader_fx.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_visible;
BKE_shaderfx_foreach_ID_link(object, modifier_walk, &data);
}
/* Constraints. */
if (object->constraints.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_visible;
BKE_constraints_id_loop(&object->constraints, constraint_walk, &data);
}
/* Object data. */
- build_object_data(object, is_visible);
+ build_object_data(object);
/* Parameters, used by both drivers/animation and also to inform dependency
* from object's data. */
build_parameters(&object->id);
@@ -887,7 +902,7 @@ void DepsgraphNodeBuilder::build_object_instance_collection(Object *object, bool
is_parent_collection_visible_ = is_current_parent_collection_visible;
}
-void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visible)
+void DepsgraphNodeBuilder::build_object_data(Object *object)
{
if (object->data == nullptr) {
return;
@@ -904,14 +919,14 @@ void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visi
case OB_HAIR:
case OB_POINTCLOUD:
case OB_VOLUME:
- build_object_data_geometry(object, is_object_visible);
+ build_object_data_geometry(object);
break;
case OB_ARMATURE:
if (ID_IS_LINKED(object) && object->proxy_from != nullptr) {
- build_proxy_rig(object, is_object_visible);
+ build_proxy_rig(object);
}
else {
- build_rig(object, is_object_visible);
+ build_rig(object);
}
break;
case OB_LAMP:
@@ -1056,10 +1071,6 @@ void DepsgraphNodeBuilder::build_object_pointcache(Object *object)
});
}
-/**
- * Build graph nodes for AnimData block and any animated images used.
- * \param id: ID-Block which hosts the AnimData
- */
void DepsgraphNodeBuilder::build_animdata(ID *id)
{
/* Special handling for animated images/sequences. */
@@ -1113,12 +1124,16 @@ void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips)
}
}
-/**
- * Build graph nodes to update the current frame in image users.
- */
void DepsgraphNodeBuilder::build_animation_images(ID *id)
{
- if (BKE_image_user_id_has_animation(id)) {
+ /* GPU materials might use an animated image. However, these materials have no been built yet. We
+ * could scan the entire node tree recursively to check if any texture node has a video. That is
+ * quite expensive. For now just always add this operation node, because it is very fast. */
+ /* TODO: Add a more precise check when it is cheaper to iterate over all image nodes in a node
+ * tree. */
+ const bool can_have_gpu_material = ELEM(GS(id->name), ID_MA, ID_WO);
+
+ if (BKE_image_user_id_has_animation(id) || can_have_gpu_material) {
ID *id_cow = get_cow_id(id);
add_operation_node(
id,
@@ -1137,12 +1152,6 @@ void DepsgraphNodeBuilder::build_action(bAction *action)
add_operation_node(&action->id, NodeType::ANIMATION, OperationCode::ANIMATION_EVAL);
}
-/**
- * Build graph node(s) for Driver
- * \param id: ID-Block that driver is attached to
- * \param fcu: Driver-FCurve
- * \param driver_index: Index in animation data drivers list
- */
void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve, int driver_index)
{
/* Create data node for this driver */
@@ -1204,8 +1213,16 @@ void DepsgraphNodeBuilder::build_driver_id_property(ID *id, const char *rna_path
return;
}
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
- ensure_operation_node(
- id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, nullptr, prop_identifier);
+ /* Custom properties of bones are placed in their components to improve granularity. */
+ if (RNA_struct_is_a(ptr.type, &RNA_PoseBone)) {
+ const bPoseChannel *pchan = static_cast<const bPoseChannel *>(ptr.data);
+ ensure_operation_node(
+ id, NodeType::BONE, pchan->name, OperationCode::ID_PROPERTY, nullptr, prop_identifier);
+ }
+ else {
+ ensure_operation_node(
+ id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, nullptr, prop_identifier);
+ }
}
void DepsgraphNodeBuilder::build_parameters(ID *id)
@@ -1468,7 +1485,7 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key)
/* ObData Geometry Evaluation */
/* XXX: what happens if the datablock is shared! */
-void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_object_visible)
+void DepsgraphNodeBuilder::build_object_data_geometry(Object *object)
{
OperationNode *op_node;
Scene *scene_cow = get_cow_datablock(scene_);
@@ -1490,7 +1507,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_ob
/* Point caches. */
build_object_pointcache(object);
/* Geometry. */
- build_object_data_geometry_datablock((ID *)object->data, is_object_visible);
+ build_object_data_geometry_datablock((ID *)object->data);
build_dimensions(object);
/* Batch cache. */
add_operation_node(
@@ -1500,7 +1517,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_ob
[object_cow](::Depsgraph *depsgraph) { BKE_object_select_update(depsgraph, object_cow); });
}
-void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool is_object_visible)
+void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata)
{
if (built_map_.checkIsBuiltAndTag(obdata)) {
return;
@@ -1544,17 +1561,15 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool
BKE_curve_eval_geometry(depsgraph, (Curve *)obdata_cow);
});
op_node->set_as_entry();
- /* Make sure objects used for bevel.taper are in the graph.
- * NOTE: This objects might be not linked to the scene. */
Curve *cu = (Curve *)obdata;
if (cu->bevobj != nullptr) {
- build_object(-1, cu->bevobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ build_object(-1, cu->bevobj, DEG_ID_LINKED_INDIRECTLY, false);
}
if (cu->taperobj != nullptr) {
- build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY, false);
}
if (cu->textoncurve != nullptr) {
- build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY, false);
}
break;
}
@@ -1713,9 +1728,8 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
build_idproperties(ntree->id.properties);
/* Animation, */
build_animdata(&ntree->id);
- /* Shading update. */
- add_operation_node(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
- add_operation_node(&ntree->id, NodeType::SHADING_PARAMETERS, OperationCode::MATERIAL_UPDATE);
+ /* Output update. */
+ add_operation_node(&ntree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
build_idproperties(bnode->prop);
@@ -2118,10 +2132,7 @@ void DepsgraphNodeBuilder::modifier_walk(void *user_data,
}
switch (GS(id->name)) {
case ID_OB:
- /* Special case for object, so we take owner visibility into
- * account. */
- data->builder->build_object(
- -1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, data->is_parent_visible);
+ data->builder->build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, false);
break;
default:
data->builder->build_id(id);
@@ -2141,10 +2152,7 @@ void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/,
}
switch (GS(id->name)) {
case ID_OB:
- /* Special case for object, so we take owner visibility into
- * account. */
- data->builder->build_object(
- -1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, data->is_parent_visible);
+ data->builder->build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, false);
break;
default:
data->builder->build_id(id);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index d31290ecbff..a1db4aaf693 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -102,6 +102,10 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void begin_build();
virtual void end_build();
+ /**
+ * `id_cow_self` is the user of `id_pointer`,
+ * see also `LibraryIDLinkCallbackData` struct definition.
+ */
int foreach_id_cow_detect_need_for_update_callback(ID *id_cow_self, ID *id_pointer);
IDNode *add_id_node(ID *id);
@@ -131,6 +135,13 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
OperationNode *ensure_operation_node(ID *id,
NodeType comp_type,
+ const char *comp_name,
+ OperationCode opcode,
+ const DepsEvalOperationCb &op = nullptr,
+ const char *name = "",
+ int name_tag = -1);
+ OperationNode *ensure_operation_node(ID *id,
+ NodeType comp_type,
OperationCode opcode,
const DepsEvalOperationCb &op = nullptr,
const char *name = "",
@@ -182,27 +193,37 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_object_flags(int base_index,
Object *object,
eDepsNode_LinkedState_Type linked_state);
- virtual void build_object_data(Object *object, bool is_object_visible);
+ virtual void build_object_data(Object *object);
virtual void build_object_data_camera(Object *object);
- virtual void build_object_data_geometry(Object *object, bool is_object_visible);
- virtual void build_object_data_geometry_datablock(ID *obdata, bool is_object_visible);
+ virtual void build_object_data_geometry(Object *object);
+ virtual void build_object_data_geometry_datablock(ID *obdata);
virtual void build_object_data_light(Object *object);
virtual void build_object_data_lightprobe(Object *object);
virtual void build_object_data_speaker(Object *object);
virtual void build_object_transform(Object *object);
virtual void build_object_constraints(Object *object);
virtual void build_object_pointcache(Object *object);
- virtual void build_pose_constraints(Object *object,
- bPoseChannel *pchan,
- int pchan_index,
- bool is_object_visible);
+ virtual void build_pose_constraints(Object *object, bPoseChannel *pchan, int pchan_index);
virtual void build_rigidbody(Scene *scene);
virtual void build_particle_systems(Object *object, bool is_object_visible);
virtual void build_particle_settings(ParticleSettings *part);
+ /**
+ * Build graph nodes for #AnimData block and any animated images used.
+ * \param id: ID-Block which hosts the #AnimData
+ */
virtual void build_animdata(ID *id);
virtual void build_animdata_nlastrip_targets(ListBase *strips);
+ /**
+ * Build graph nodes to update the current frame in image users.
+ */
virtual void build_animation_images(ID *id);
virtual void build_action(bAction *action);
+ /**
+ * Build graph node(s) for Driver
+ * \param id: ID-Block that driver is attached to
+ * \param fcurve: Driver-FCurve
+ * \param driver_index: Index in animation data drivers list
+ */
virtual void build_driver(ID *id, FCurve *fcurve, int driver_index);
virtual void build_driver_variables(ID *id, FCurve *fcurve);
virtual void build_driver_id_property(ID *id, const char *rna_path);
@@ -210,8 +231,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_dimensions(Object *object);
virtual void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
virtual void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
- virtual void build_rig(Object *object, bool is_object_visible);
- virtual void build_proxy_rig(Object *object, bool is_object_visible);
+ virtual void build_rig(Object *object);
+ virtual void build_proxy_rig(Object *object);
virtual void build_armature(bArmature *armature);
virtual void build_armature_bones(ListBase *bones);
virtual void build_shapekeys(Key *key);
@@ -267,8 +288,6 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
struct BuilderWalkUserData {
DepsgraphNodeBuilder *builder;
- /* Denotes whether object the walk is invoked from is visible. */
- bool is_parent_visible;
};
static void modifier_walk(void *user_data,
struct Object *object,
@@ -280,6 +299,10 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
void *user_data);
void tag_previously_tagged_nodes();
+ /**
+ * Check for IDs that need to be flushed (COW-updated)
+ * because the depsgraph itself created or removed some of their evaluated dependencies.
+ */
void update_invalid_cow_pointers();
/* State which demotes currently built entities. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
index 00c78b8edce..e8dda7b8de4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -58,13 +58,11 @@ namespace blender::deg {
void DepsgraphNodeBuilder::build_pose_constraints(Object *object,
bPoseChannel *pchan,
- int pchan_index,
- bool is_object_visible)
+ int pchan_index)
{
/* Pull indirect dependencies via constraints. */
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_object_visible;
BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data);
/* Create node for constraint stack. */
@@ -147,7 +145,7 @@ void DepsgraphNodeBuilder::build_splineik_pose(Object *object,
}
/* Pose/Armature Bones Graph */
-void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
+void DepsgraphNodeBuilder::build_rig(Object *object)
{
bArmature *armature = (bArmature *)object->data;
Scene *scene_cow = get_cow_datablock(scene_);
@@ -272,7 +270,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
}
/* Build constraints. */
if (pchan->constraints.first != nullptr) {
- build_pose_constraints(object, pchan, pchan_index, is_object_visible);
+ build_pose_constraints(object, pchan, pchan_index);
}
/**
* IK Solvers.
@@ -301,14 +299,14 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
}
/* Custom shape. */
if (pchan->custom != nullptr) {
- /* TODO(sergey): Use own visibility. */
- build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ /* NOTE: The relation builder will ensure visibility of the custom shape object. */
+ build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, false);
}
pchan_index++;
}
}
-void DepsgraphNodeBuilder::build_proxy_rig(Object *object, bool is_object_visible)
+void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
{
bArmature *armature = (bArmature *)object->data;
OperationNode *op_node;
@@ -356,7 +354,8 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object, bool is_object_visibl
/* Custom shape. */
if (pchan->custom != nullptr) {
- build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ /* NOTE: The relation builder will ensure visibility of the custom shape object. */
+ build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, false);
}
pchan_index++;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
index 17c2925b7f4..79f358213d3 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
@@ -30,7 +30,6 @@
namespace blender::deg {
-/* Debug contents of map */
void RootPChanMap::print_debug()
{
map_.foreach_item([](StringRefNull key, const Set<StringRefNull> &values) {
@@ -42,13 +41,11 @@ void RootPChanMap::print_debug()
});
}
-/* Add a mapping. */
void RootPChanMap::add_bone(const char *bone, const char *root)
{
map_.lookup_or_add_default(bone).add(root);
}
-/* Check if there's a common root bone between two bones. */
bool RootPChanMap::has_common_root(const char *bone1, const char *bone2) const
{
const Set<StringRefNull> *bone1_roots = map_.lookup_ptr(bone1);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
index 0dd4062c353..42f9ec9cc6a 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
@@ -29,13 +29,13 @@ namespace blender {
namespace deg {
struct RootPChanMap {
- /* Debug contents of map. */
+ /** Debug contents of map. */
void print_debug();
- /* Add a mapping. */
+ /** Add a mapping. */
void add_bone(const char *bone, const char *root);
- /* Check if there's a common root bone between two bones. */
+ /** Check if there's a common root bone between two bones. */
bool has_common_root(const char *bone1, const char *bone2) const;
protected:
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 55e8c5ed033..cb43ef685d4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -368,6 +368,13 @@ Relation *DepsgraphRelationBuilder::add_time_relation(TimeSourceNode *timesrc,
return nullptr;
}
+void DepsgraphRelationBuilder::add_visibility_relation(ID *id_from, ID *id_to)
+{
+ ComponentKey from_key(id_from, NodeType::VISIBILITY);
+ ComponentKey to_key(id_to, NodeType::VISIBILITY);
+ add_relation(from_key, to_key, "visibility");
+}
+
Relation *DepsgraphRelationBuilder::add_operation_relation(OperationNode *node_from,
OperationNode *node_to,
const char *description,
@@ -1459,12 +1466,26 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id)
void DepsgraphRelationBuilder::build_animation_images(ID *id)
{
+ /* See #DepsgraphNodeBuilder::build_animation_images. */
+ const bool can_have_gpu_material = ELEM(GS(id->name), ID_MA, ID_WO);
+
/* TODO: can we check for existence of node for performance? */
- if (BKE_image_user_id_has_animation(id)) {
+ if (BKE_image_user_id_has_animation(id) || can_have_gpu_material) {
OperationKey image_animation_key(
id, NodeType::IMAGE_ANIMATION, OperationCode::IMAGE_ANIMATION);
TimeSourceKey time_src_key;
add_relation(time_src_key, image_animation_key, "TimeSrc -> Image Animation");
+
+ /* The image users of these ids may change during evaluation. Make sure that the image
+ * animation update happens after evaluation. */
+ if (GS(id->name) == ID_MA) {
+ OperationKey material_update_key(id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
+ add_relation(material_update_key, image_animation_key, "Material Update -> Image Animation");
+ }
+ else if (GS(id->name) == ID_WO) {
+ OperationKey world_update_key(id, NodeType::SHADING, OperationCode::WORLD_UPDATE);
+ add_relation(world_update_key, image_animation_key, "World Update -> Image Animation");
+ }
}
}
@@ -1719,8 +1740,22 @@ void DepsgraphRelationBuilder::build_driver_id_property(ID *id, const char *rna_
return;
}
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
- OperationKey id_property_key(
- id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, prop_identifier);
+ /* Custom properties of bones are placed in their components to improve granularity. */
+ OperationKey id_property_key;
+ if (RNA_struct_is_a(ptr.type, &RNA_PoseBone)) {
+ const bPoseChannel *pchan = static_cast<const bPoseChannel *>(ptr.data);
+ id_property_key = OperationKey(
+ id, NodeType::BONE, pchan->name, OperationCode::ID_PROPERTY, prop_identifier);
+ /* Create relation from the parameters component so that tagging armature for parameters update
+ * properly propagates updates to all properties on bones and deeper (if needed). */
+ OperationKey parameters_init_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_ENTRY);
+ add_relation(
+ parameters_init_key, id_property_key, "Init -> ID Property", RELATION_CHECK_BEFORE_ADD);
+ }
+ else {
+ id_property_key = OperationKey(
+ id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, prop_identifier);
+ }
OperationKey parameters_exit_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT);
add_relation(
id_property_key, parameters_exit_key, "ID Property -> Done", RELATION_CHECK_BEFORE_ADD);
@@ -1763,7 +1798,7 @@ void DepsgraphRelationBuilder::build_world(World *world)
if (world->nodetree != nullptr) {
build_nodetree(world->nodetree);
OperationKey ntree_key(
- &world->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
+ &world->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
add_relation(ntree_key, world_key, "World's NTree");
build_nested_nodetree(&world->id, world->nodetree);
}
@@ -2066,7 +2101,8 @@ void DepsgraphRelationBuilder::build_shapekeys(Key *key)
* and also for the links coming from the shapekey data-blocks
* - Animation/Drivers affecting the parameters of the geometry are made to
* trigger updates on the obdata geometry component, which then trigger
- * downstream re-evaluation of the individual instances of this geometry. */
+ * downstream re-evaluation of the individual instances of this geometry.
+ */
void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
{
ID *obdata = (ID *)object->data;
@@ -2373,17 +2409,17 @@ void DepsgraphRelationBuilder::build_light(Light *lamp)
ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS);
+ /* For allowing drivers on lamp properties. */
+ ComponentKey shading_key(&lamp->id, NodeType::SHADING);
+ add_relation(lamp_parameters_key, shading_key, "Light Shading Parameters");
+
/* light's nodetree */
if (lamp->nodetree != nullptr) {
build_nodetree(lamp->nodetree);
- ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::SHADING);
- add_relation(nodetree_key, lamp_parameters_key, "NTree->Light Parameters");
+ ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::NTREE_OUTPUT);
+ add_relation(nodetree_key, shading_key, "NTree->Light Parameters");
build_nested_nodetree(&lamp->id, lamp->nodetree);
}
-
- /* For allowing drivers on lamp properties. */
- ComponentKey shading_key(&lamp->id, NodeType::SHADING);
- add_relation(lamp_parameters_key, shading_key, "Light Shading Parameters");
}
void DepsgraphRelationBuilder::build_nodetree_socket(bNodeSocket *socket)
@@ -2433,7 +2469,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
build_idproperties(ntree->id.properties);
build_animdata(&ntree->id);
build_parameters(&ntree->id);
- ComponentKey shading_key(&ntree->id, NodeType::SHADING);
+ OperationKey ntree_output_key(&ntree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
build_idproperties(bnode->prop);
@@ -2452,25 +2488,25 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
if (id_type == ID_MA) {
build_material((Material *)bnode->id);
ComponentKey material_key(id, NodeType::SHADING);
- add_relation(material_key, shading_key, "Material -> Node");
+ add_relation(material_key, ntree_output_key, "Material -> Node");
}
else if (id_type == ID_TE) {
build_texture((Tex *)bnode->id);
ComponentKey texture_key(id, NodeType::GENERIC_DATABLOCK);
- add_relation(texture_key, shading_key, "Texture -> Node");
+ add_relation(texture_key, ntree_output_key, "Texture -> Node");
}
else if (id_type == ID_IM) {
build_image((Image *)bnode->id);
ComponentKey image_key(id, NodeType::GENERIC_DATABLOCK);
- add_relation(image_key, shading_key, "Image -> Node");
+ add_relation(image_key, ntree_output_key, "Image -> Node");
}
else if (id_type == ID_OB) {
build_object((Object *)id);
ComponentKey object_transform_key(id, NodeType::TRANSFORM);
- add_relation(object_transform_key, shading_key, "Object Transform -> Node");
+ add_relation(object_transform_key, ntree_output_key, "Object Transform -> Node");
if (object_have_geometry_component(reinterpret_cast<Object *>(id))) {
ComponentKey object_geometry_key(id, NodeType::GEOMETRY);
- add_relation(object_geometry_key, shading_key, "Object Geometry -> Node");
+ add_relation(object_geometry_key, ntree_output_key, "Object Geometry -> Node");
}
}
else if (id_type == ID_SCE) {
@@ -2490,23 +2526,26 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
else if (id_type == ID_MSK) {
build_mask((Mask *)id);
OperationKey mask_key(id, NodeType::PARAMETERS, OperationCode::MASK_EVAL);
- add_relation(mask_key, shading_key, "Mask -> Node");
+ add_relation(mask_key, ntree_output_key, "Mask -> Node");
}
else if (id_type == ID_MC) {
build_movieclip((MovieClip *)id);
OperationKey clip_key(id, NodeType::PARAMETERS, OperationCode::MOVIECLIP_EVAL);
- add_relation(clip_key, shading_key, "Clip -> Node");
+ add_relation(clip_key, ntree_output_key, "Clip -> Node");
}
else if (id_type == ID_VF) {
build_vfont((VFont *)id);
ComponentKey vfont_key(id, NodeType::GENERIC_DATABLOCK);
- add_relation(vfont_key, shading_key, "VFont -> Node");
+ add_relation(vfont_key, ntree_output_key, "VFont -> Node");
}
else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
bNodeTree *group_ntree = (bNodeTree *)id;
build_nodetree(group_ntree);
- ComponentKey group_shading_key(&group_ntree->id, NodeType::SHADING);
- add_relation(group_shading_key, shading_key, "Group Node");
+ ComponentKey group_output_key(&group_ntree->id, NodeType::NTREE_OUTPUT);
+ /* This relation is not necessary in all cases (e.g. when the group node is not connected to
+ * the output). Currently, we lack the infrastructure to check for these cases efficiently.
+ * That can be added later. */
+ add_relation(group_output_key, ntree_output_key, "Group Node");
}
else {
BLI_assert_msg(0, "Unknown ID type used for node");
@@ -2520,17 +2559,10 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
build_idproperties(socket->prop);
}
- OperationKey shading_update_key(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
- OperationKey shading_parameters_key(
- &ntree->id, NodeType::SHADING_PARAMETERS, OperationCode::MATERIAL_UPDATE);
- add_relation(shading_parameters_key, shading_update_key, "NTree Shading Parameters");
-
if (check_id_has_anim_component(&ntree->id)) {
ComponentKey animation_key(&ntree->id, NodeType::ANIMATION);
- add_relation(animation_key, shading_parameters_key, "NTree Shading Parameters");
+ add_relation(animation_key, ntree_output_key, "NTree Shading Parameters");
}
- ComponentKey parameters_key(&ntree->id, NodeType::PARAMETERS);
- add_relation(parameters_key, shading_parameters_key, "NTree Shading Parameters");
}
/* Recursively build graph for material */
@@ -2553,7 +2585,7 @@ void DepsgraphRelationBuilder::build_material(Material *material)
if (material->nodetree != nullptr) {
build_nodetree(material->nodetree);
OperationKey ntree_key(
- &material->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
+ &material->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
add_relation(ntree_key, material_key, "Material's NTree");
build_nested_nodetree(&material->id, material->nodetree);
}
@@ -2582,8 +2614,13 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture)
build_parameters(&texture->id);
/* texture's nodetree */
- build_nodetree(texture->nodetree);
- build_nested_nodetree(&texture->id, texture->nodetree);
+ if (texture->nodetree) {
+ build_nodetree(texture->nodetree);
+ OperationKey ntree_key(
+ &texture->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
+ add_relation(ntree_key, texture_key, "Texture's NTree");
+ build_nested_nodetree(&texture->id, texture->nodetree);
+ }
/* Special cases for different IDs which texture uses. */
if (texture->type == TEX_IMAGE) {
@@ -2864,17 +2901,22 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations()
}
}
-/* Nested datablocks (node trees, shape keys) requires special relation to
+/**
+ * Nested datablocks (node trees, shape keys) requires special relation to
* ensure owner's datablock remapping happens after node tree itself is ready.
*
* This is similar to what happens in ntree_hack_remap_pointers().
*/
-void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id)
+void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id, bool flush_cow_changes)
{
+ int relation_flag = 0;
+ if (!flush_cow_changes) {
+ relation_flag |= RELATION_FLAG_NO_FLUSH;
+ }
OperationKey owner_copy_on_write_key(
owner, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE);
OperationKey id_copy_on_write_key(id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE);
- add_relation(id_copy_on_write_key, owner_copy_on_write_key, "Eval Order");
+ add_relation(id_copy_on_write_key, owner_copy_on_write_key, "Eval Order", relation_flag);
}
void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree)
@@ -2882,7 +2924,10 @@ void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree
if (ntree == nullptr) {
return;
}
- build_nested_datablock(owner, &ntree->id);
+ /* Don't flush cow changes, because the node tree may change in ways that do not affect the
+ * owner data block (e.g. when a node is deleted that is not connected to any output).
+ * Data blocks owning node trees should add a relation to the `NTREE_OUTPUT` node instead. */
+ build_nested_datablock(owner, &ntree->id, false);
}
void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key)
@@ -2890,7 +2935,7 @@ void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key)
if (key == nullptr) {
return;
}
- build_nested_datablock(owner, &key->id);
+ build_nested_datablock(owner, &key->id, true);
}
void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index f0393544511..d699c799e40 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -71,8 +71,8 @@ struct Scene;
struct Simulation;
struct Speaker;
struct Tex;
-struct ViewLayer;
struct VFont;
+struct ViewLayer;
struct World;
struct bAction;
struct bArmature;
@@ -299,7 +299,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
virtual void build_vfont(VFont *vfont);
- virtual void build_nested_datablock(ID *owner, ID *id);
+ virtual void build_nested_datablock(ID *owner, ID *id, bool flush_cow_changes);
virtual void build_nested_nodetree(ID *owner, bNodeTree *ntree);
virtual void build_nested_shapekey(ID *owner, Key *key);
@@ -336,6 +336,11 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
Node *node_to,
const char *description,
int flags = 0);
+
+ /* Add relation which ensures visibility of `id_from` when `id_to` is visible.
+ * For the more detailed explanation see comment for `NodeType::VISIBILITY`. */
+ void add_visibility_relation(ID *id_from, ID *id_to);
+
Relation *add_operation_relation(OperationNode *node_from,
OperationNode *node_to,
const char *description,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc
index bf3af571f0b..6e5c1f05cf3 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc
@@ -83,7 +83,6 @@ bool DriverDescriptor::is_array() const
return is_array_;
}
-/* Assumes that 'other' comes from the same RNA group, that is, has the same RNA path prefix. */
bool DriverDescriptor::is_same_array_as(const DriverDescriptor &other) const
{
if (!is_array_ || !other.is_array_) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h
index c80c69be9e2..4ad5bdda1ef 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h
@@ -37,14 +37,17 @@ namespace deg {
/* Helper class for determining which relations are needed between driver evaluation nodes. */
class DriverDescriptor {
public:
- /* Drivers are grouped by their RNA prefix. The prefix is the part of the RNA
+ /**
+ * Drivers are grouped by their RNA prefix. The prefix is the part of the RNA
* path up to the last dot, the suffix is the remainder of the RNA path:
*
+ * \code{.unparsed}
* fcu->rna_path rna_prefix rna_suffix
* ------------------------------- ---------------------- ----------
* 'color' '' 'color'
* 'rigidbody_world.time_scale' 'rigidbody_world' 'time_scale'
* 'pose.bones["master"].location' 'pose.bones["master"]' 'location'
+ * \endcode
*/
StringRef rna_prefix;
StringRef rna_suffix;
@@ -54,7 +57,7 @@ class DriverDescriptor {
bool driver_relations_needed() const;
bool is_array() const;
- /* Assumes that 'other' comes from the same RNA group, that is, has the same RNA path prefix. */
+ /** Assumes that 'other' comes from the same RNA group, that is, has the same RNA path prefix. */
bool is_same_array_as(const DriverDescriptor &other) const;
OperationKey depsgraph_key() const;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index 4754749e2e5..856e37ee473 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -49,6 +49,7 @@
#include "DEG_depsgraph_build.h"
#include "intern/builder/deg_builder.h"
+#include "intern/builder/deg_builder_cache.h"
#include "intern/builder/deg_builder_pchanmap.h"
#include "intern/debug/deg_debug.h"
#include "intern/node/deg_node.h"
@@ -84,14 +85,21 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
OperationKey solver_key(
&object->id, NodeType::EVAL_POSE, rootchan->name, OperationCode::POSE_IK_SOLVER);
OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP);
- add_relation(pchan_local_key, init_ik_key, "IK Constraint -> Init IK Tree");
+ /* If any of the constraint parameters are animated, connect the relation. Since there is only
+ * one Init IK node per armature, this link has quite high risk of spurious dependency cycles.
+ */
+ const bool is_itasc = (object->pose->iksolver == IKSOLVER_ITASC);
+ PointerRNA con_ptr;
+ RNA_pointer_create(&object->id, &RNA_Constraint, con, &con_ptr);
+ if (is_itasc || cache_->isAnyPropertyAnimated(&con_ptr)) {
+ add_relation(pchan_local_key, init_ik_key, "IK Constraint -> Init IK Tree");
+ }
add_relation(init_ik_key, solver_key, "Init IK -> IK Solver");
/* Never cleanup before solver is run. */
add_relation(solver_key, pose_cleanup_key, "IK Solver -> Cleanup", RELATION_FLAG_GODMODE);
/* The ITASC solver currently accesses the target transforms in init tree :(
* TODO: Fix ITASC and remove this.
*/
- bool is_itasc = (object->pose->iksolver == IKSOLVER_ITASC);
OperationKey target_dependent_key = is_itasc ? init_ik_key : solver_key;
/* IK target */
/* TODO(sergey): This should get handled as part of the constraint code. */
@@ -100,6 +108,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
if (data->tar != object) {
ComponentKey target_key(&data->tar->id, NodeType::TRANSFORM);
add_relation(target_key, target_dependent_key, con->name);
+ /* Ensure target CoW is ready by the time IK tree is built just in case. */
+ ComponentKey target_cow_key(&data->tar->id, NodeType::COPY_ON_WRITE);
+ add_relation(
+ target_cow_key, init_ik_key, "IK Target CoW -> Init IK Tree", RELATION_CHECK_BEFORE_ADD);
}
/* Subtarget references: */
if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
@@ -129,6 +141,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
if (data->poletar != object) {
ComponentKey target_key(&data->poletar->id, NodeType::TRANSFORM);
add_relation(target_key, target_dependent_key, con->name);
+ /* Ensure target CoW is ready by the time IK tree is built just in case. */
+ ComponentKey target_cow_key(&data->poletar->id, NodeType::COPY_ON_WRITE);
+ add_relation(
+ target_cow_key, init_ik_key, "IK Target CoW -> Init IK Tree", RELATION_CHECK_BEFORE_ADD);
}
/* Subtarget references: */
if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) {
@@ -450,6 +466,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
/* Custom shape. */
if (pchan->custom != nullptr) {
build_object(pchan->custom);
+ add_visibility_relation(&pchan->custom->id, &armature->id);
}
}
}
@@ -506,6 +523,12 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object)
&proxy_from->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name);
add_relation(from_bone_parameters, bone_parameters, "Proxy Bone Parameters");
}
+
+ /* Custom shape. */
+ if (pchan->custom != nullptr) {
+ build_object(pchan->custom);
+ add_visibility_relation(&pchan->custom->id, &armature->id);
+ }
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index 40e59875832..76a115a06c8 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -181,7 +181,15 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
node_identifier.operation_name_tag = -1;
/* Handling of commonly known scenarios. */
if (rna_prop_affects_parameters_node(ptr, prop)) {
- node_identifier.type = NodeType::PARAMETERS;
+ /* Custom properties of bones are placed in their components to improve granularity. */
+ if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
+ const bPoseChannel *pchan = static_cast<const bPoseChannel *>(ptr->data);
+ node_identifier.type = NodeType::BONE;
+ node_identifier.component_name = pchan->name;
+ }
+ else {
+ node_identifier.type = NodeType::PARAMETERS;
+ }
node_identifier.operation_code = OperationCode::ID_PROPERTY;
node_identifier.operation_name = RNA_property_identifier(
reinterpret_cast<const PropertyRNA *>(prop));
@@ -351,7 +359,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
return node_identifier;
}
else if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
- node_identifier.type = NodeType::SHADING;
+ node_identifier.type = NodeType::NTREE_OUTPUT;
return node_identifier;
}
else if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) {
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
index 57c6f062611..36120ae76d1 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
@@ -105,11 +105,10 @@ static const int deg_debug_node_type_color_map[][2] = {
{NodeType::GEOMETRY, 6},
{NodeType::SEQUENCER, 7},
{NodeType::SHADING, 8},
- {NodeType::SHADING_PARAMETERS, 9},
- {NodeType::CACHE, 10},
- {NodeType::POINT_CACHE, 11},
- {NodeType::LAYER_COLLECTIONS, 12},
- {NodeType::COPY_ON_WRITE, 13},
+ {NodeType::CACHE, 9},
+ {NodeType::POINT_CACHE, 10},
+ {NodeType::LAYER_COLLECTIONS, 11},
+ {NodeType::COPY_ON_WRITE, 12},
{-1, 0},
};
#endif
@@ -411,7 +410,6 @@ static void deg_debug_graphviz_node(DotExportContext &ctx,
case NodeType::EVAL_POSE:
case NodeType::BONE:
case NodeType::SHADING:
- case NodeType::SHADING_PARAMETERS:
case NodeType::CACHE:
case NodeType::POINT_CACHE:
case NodeType::IMAGE_ANIMATION:
@@ -426,6 +424,8 @@ static void deg_debug_graphviz_node(DotExportContext &ctx,
case NodeType::AUDIO:
case NodeType::ARMATURE:
case NodeType::GENERIC_DATABLOCK:
+ case NodeType::VISIBILITY:
+ case NodeType::NTREE_OUTPUT:
case NodeType::SIMULATION: {
ComponentNode *comp_node = (ComponentNode *)node;
if (comp_node->operations.is_empty()) {
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 4c036417ba0..b348ab0f432 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -182,7 +182,6 @@ void Depsgraph::clear_id_nodes()
clear_physics_relations(this);
}
-/* Add new relation between two nodes */
Relation *Depsgraph::add_new_relation(Node *from, Node *to, const char *description, int flags)
{
Relation *rel = nullptr;
@@ -228,7 +227,6 @@ Relation *Depsgraph::check_nodes_connected(const Node *from,
/* Low level tagging -------------------------------------- */
-/* Tag a specific node as needing updates. */
void Depsgraph::add_entry_tag(OperationNode *node)
{
/* Sanity check. */
@@ -280,7 +278,6 @@ ID *Depsgraph::get_cow_id(const ID *id_orig) const
/* **************** */
/* Public Graph API */
-/* Initialize a new Depsgraph */
Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
{
deg::Depsgraph *deg_depsgraph = new deg::Depsgraph(bmain, scene, view_layer, mode);
@@ -288,10 +285,6 @@ Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEval
return reinterpret_cast<Depsgraph *>(deg_depsgraph);
}
-/* Replace the "owner" pointers (currently Main/Scene/ViewLayer) of this depsgraph.
- * Used for:
- * - Undo steps when we do want to re-use the old depsgraph data as much as possible.
- * - Rendering where we want to re-use objects between different view layers. */
void DEG_graph_replace_owners(struct Depsgraph *depsgraph,
Main *bmain,
Scene *scene,
@@ -313,7 +306,6 @@ void DEG_graph_replace_owners(struct Depsgraph *depsgraph,
}
}
-/* Free graph's contents and graph itself */
void DEG_graph_free(Depsgraph *graph)
{
if (graph == nullptr) {
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 913b61ca563..bfe6ed649f6 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -72,7 +72,7 @@ struct Depsgraph {
IDNode *add_id_node(ID *id, ID *id_cow_hint = nullptr);
void clear_id_nodes();
- /* Add new relationship between two nodes. */
+ /** Add new relationship between two nodes. */
Relation *add_new_relation(Node *from, Node *to, const char *description, int flags = 0);
/* Check whether two nodes are connected by relation with given
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 9e9191c5ab9..acb8fa8fe88 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -148,15 +148,15 @@ void DEG_add_simulation_relation(DepsNodeHandle *node_handle,
deg_node_handle->builder->add_node_handle_relation(operation_key, deg_node_handle, description);
}
-void DEG_add_node_tree_relation(DepsNodeHandle *node_handle,
- bNodeTree *node_tree,
- const char *description)
+void DEG_add_node_tree_output_relation(DepsNodeHandle *node_handle,
+ bNodeTree *node_tree,
+ const char *description)
{
- /* Using shading key, because that's the one that exists right now. Should use something else in
- * the future. */
- deg::ComponentKey shading_key(&node_tree->id, deg::NodeType::SHADING);
+ deg::OperationKey ntree_output_key(
+ &node_tree->id, deg::NodeType::NTREE_OUTPUT, deg::OperationCode::NTREE_OUTPUT);
deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
- deg_node_handle->builder->add_node_handle_relation(shading_key, deg_node_handle, description);
+ deg_node_handle->builder->add_node_handle_relation(
+ ntree_output_key, deg_node_handle, description);
}
void DEG_add_object_cache_relation(DepsNodeHandle *node_handle,
@@ -252,7 +252,6 @@ struct Depsgraph *DEG_get_graph_from_handle(struct DepsNodeHandle *node_handle)
/* ******************** */
/* Graph Building API's */
-/* Build depsgraph for the given scene layer, and dump results in given graph container. */
void DEG_graph_build_from_view_layer(Depsgraph *graph)
{
deg::ViewLayerBuilderPipeline builder(graph);
@@ -283,7 +282,6 @@ void DEG_graph_build_from_ids(Depsgraph *graph, ID **ids, const int num_ids)
builder.build();
}
-/* Tag graph relations for update. */
void DEG_graph_tag_relations_update(Depsgraph *graph)
{
DEG_DEBUG_PRINTF(graph, TAG, "%s: Tagging relations for update.\n", __func__);
@@ -301,7 +299,6 @@ void DEG_graph_tag_relations_update(Depsgraph *graph)
}
}
-/* Create or update relations in the specified graph. */
void DEG_graph_relations_update(Depsgraph *graph)
{
deg::Depsgraph *deg_graph = (deg::Depsgraph *)graph;
@@ -312,7 +309,6 @@ void DEG_graph_relations_update(Depsgraph *graph)
DEG_graph_build_from_view_layer(graph);
}
-/* Tag all relations for update. */
void DEG_relations_tag_update(Main *bmain)
{
DEG_GLOBAL_DEBUG_PRINTF(TAG, "%s: Tagging relations for update.\n", __func__);
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index 3677f80469c..9e3cbdbec09 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -196,12 +196,6 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
/* ------------------------------------------------ */
-/**
- * Obtain simple statistics about the complexity of the depsgraph.
- * \param[out] r_outer: The number of outer nodes in the graph
- * \param[out] r_operations: The number of operation nodes in the graph
- * \param[out] r_relations: The number of relations between (executable) nodes in the graph
- */
void DEG_stats_simple(const Depsgraph *graph,
size_t *r_outer,
size_t *r_operations,
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index cc7ce871419..7952f27507f 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -44,6 +44,7 @@
#include "intern/node/deg_node_time.h"
#include "intern/depsgraph.h"
+#include "intern/depsgraph_tag.h"
namespace deg = blender::deg;
@@ -54,11 +55,11 @@ static void deg_flush_updates_and_refresh(deg::Depsgraph *deg_graph)
BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->frame);
}
+ deg::graph_tag_ids_for_visible_update(deg_graph);
deg::deg_graph_flush_updates(deg_graph);
deg::deg_evaluate_on_refresh(deg_graph);
}
-/* Evaluate all nodes tagged for updating. */
void DEG_evaluate_on_refresh(Depsgraph *graph)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
@@ -75,7 +76,6 @@ void DEG_evaluate_on_refresh(Depsgraph *graph)
deg_flush_updates_and_refresh(deg_graph);
}
-/* Frame-change happened for root scene that graph belongs to. */
void DEG_evaluate_on_framechange(Depsgraph *graph, float frame)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index aab4c3ca0f6..6c1947728b5 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -200,7 +200,6 @@ ID *DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
return id_node->id_cow;
}
-/* Get evaluated version of data pointed to by RNA pointer */
void DEG_get_evaluated_rna_pointer(const Depsgraph *depsgraph,
PointerRNA *ptr,
PointerRNA *r_ptr_eval)
diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
index 6ce7cc0837b..65a21323258 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
@@ -77,6 +77,12 @@ void deg_foreach_dependent_operation(const Depsgraph *UNUSED(graph),
TraversalQueue queue;
Set<OperationNode *> scheduled;
for (ComponentNode *comp_node : target_id_node->components.values()) {
+ if (comp_node->type == NodeType::VISIBILITY) {
+ /* Visibility component is only used internally. It is not to be reporting dependencies to
+ * the outer world. */
+ continue;
+ }
+
if (source_component_type != DEG_OB_COMP_ANY &&
nodeTypeToObjectComponent(comp_node->type) != source_component_type) {
continue;
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
index 7af3d03d478..0b219dcbf5e 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -76,14 +76,8 @@ void deg_invalidate_iterator_work_data(DEGObjectIterData *data)
#endif
}
-void verify_id_properties_freed(DEGObjectIterData *data)
+void ensure_id_properties_freed(const Object *dupli_object, Object *temp_dupli_object)
{
- if (data->dupli_object_current == nullptr) {
- /* We didn't enter duplication yet, so we can't have any dangling pointers. */
- return;
- }
- const Object *dupli_object = data->dupli_object_current->ob;
- Object *temp_dupli_object = &data->temp_dupli_object;
if (temp_dupli_object->id.properties == nullptr) {
/* No ID properties in temp data-block -- no leak is possible. */
return;
@@ -97,6 +91,35 @@ void verify_id_properties_freed(DEGObjectIterData *data)
temp_dupli_object->id.properties = nullptr;
}
+void ensure_boundbox_freed(const Object *dupli_object, Object *temp_dupli_object)
+{
+ if (temp_dupli_object->runtime.bb == nullptr) {
+ /* No Bounding Box in temp data-block -- no leak is possible. */
+ return;
+ }
+ if (temp_dupli_object->runtime.bb == dupli_object->runtime.bb) {
+ /* Temp copy of object did not modify Bounding Box. */
+ return;
+ }
+ /* Free memory which is owned by temporary storage which is about to get overwritten. */
+ MEM_freeN(temp_dupli_object->runtime.bb);
+ temp_dupli_object->runtime.bb = nullptr;
+}
+
+void free_owned_memory(DEGObjectIterData *data)
+{
+ if (data->dupli_object_current == nullptr) {
+ /* We didn't enter duplication yet, so we can't have any dangling pointers. */
+ return;
+ }
+
+ const Object *dupli_object = data->dupli_object_current->ob;
+ Object *temp_dupli_object = &data->temp_dupli_object;
+
+ ensure_id_properties_freed(dupli_object, temp_dupli_object);
+ ensure_boundbox_freed(dupli_object, temp_dupli_object);
+}
+
bool deg_object_hide_original(eEvaluationMode eval_mode, Object *ob, DupliObject *dob)
{
/* Automatic hiding if this object is being instanced on verts/faces/frames
@@ -153,7 +176,7 @@ bool deg_iterator_duplis_step(DEGObjectIterData *data)
continue;
}
- verify_id_properties_freed(data);
+ free_owned_memory(data);
data->dupli_object_current = dob;
@@ -169,6 +192,8 @@ bool deg_iterator_duplis_step(DEGObjectIterData *data)
copy_v4_v4(temp_dupli_object->color, dupli_parent->color);
temp_dupli_object->runtime.select_id = dupli_parent->runtime.select_id;
if (dob->ob->data != dob->ob_data) {
+ /* Do not modify the original boundbox. */
+ temp_dupli_object->runtime.bb = nullptr;
BKE_object_replace_data_on_shallow_copy(temp_dupli_object, dob->ob_data);
}
@@ -192,7 +217,7 @@ bool deg_iterator_duplis_step(DEGObjectIterData *data)
return true;
}
- verify_id_properties_freed(data);
+ free_owned_memory(data);
free_object_duplilist(data->dupli_list);
data->dupli_parent = nullptr;
data->dupli_list = nullptr;
@@ -334,10 +359,13 @@ static void DEG_iterator_ids_step(BLI_Iterator *iter, deg::IDNode *id_node, bool
return;
}
if (only_updated && !(id_cow->recalc & ID_RECALC_ALL)) {
- bNodeTree *ntree = ntreeFromID(id_cow);
-
/* Node-tree is considered part of the data-block. */
- if (!(ntree && (ntree->id.recalc & ID_RECALC_ALL))) {
+ bNodeTree *ntree = ntreeFromID(id_cow);
+ if (ntree == nullptr) {
+ iter->skip = true;
+ return;
+ }
+ if ((ntree->id.recalc & ID_RECALC_NTREE_OUTPUT) == 0) {
iter->skip = true;
return;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index dd96c5a3b2b..4bc9e0d2d14 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -193,12 +193,7 @@ void depsgraph_tag_to_component_opcode(const ID *id,
*component_type = NodeType::COPY_ON_WRITE;
break;
case ID_RECALC_SHADING:
- if (id_type == ID_NT) {
- *component_type = NodeType::SHADING_PARAMETERS;
- }
- else {
- *component_type = NodeType::SHADING;
- }
+ *component_type = NodeType::SHADING;
break;
case ID_RECALC_SELECT:
depsgraph_select_tag_to_component_opcode(id, component_type, operation_code);
@@ -237,6 +232,10 @@ void depsgraph_tag_to_component_opcode(const ID *id,
break;
case ID_RECALC_TAG_FOR_UNDO:
break; /* Must be ignored by depsgraph. */
+ case ID_RECALC_NTREE_OUTPUT:
+ *component_type = NodeType::NTREE_OUTPUT;
+ *operation_code = OperationCode::NTREE_OUTPUT;
+ break;
}
}
@@ -754,13 +753,14 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
return "ALL";
case ID_RECALC_TAG_FOR_UNDO:
return "TAG_FOR_UNDO";
+ case ID_RECALC_NTREE_OUTPUT:
+ return "ID_RECALC_NTREE_OUTPUT";
}
return nullptr;
}
/* Data-Based Tagging. */
-/* Tag given ID for an update in all the dependency graphs. */
void DEG_id_tag_update(ID *id, int flag)
{
DEG_id_tag_update_ex(G.main, id, flag);
@@ -797,7 +797,6 @@ void DEG_graph_time_tag_update(struct Depsgraph *depsgraph)
deg_graph->tag_time_source();
}
-/* Mark a particular data-block type as having changing. */
void DEG_graph_id_type_tag(Depsgraph *depsgraph, short id_type)
{
if (id_type == ID_NT) {
@@ -822,7 +821,6 @@ void DEG_id_type_tag(Main *bmain, short id_type)
}
}
-/* Update dependency graph when visible scenes/layers changes. */
void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, const bool do_time)
{
deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph;
@@ -842,8 +840,6 @@ void DEG_enable_editors_update(Depsgraph *depsgraph)
graph->use_editors_update = true;
}
-/* Check if something was changed in the database and inform
- * editors about this. */
void DEG_editors_update(Depsgraph *depsgraph, bool time)
{
deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph;
diff --git a/source/blender/depsgraph/intern/depsgraph_type.cc b/source/blender/depsgraph/intern/depsgraph_type.cc
index 07664cb4f0b..0405a7d90b4 100644
--- a/source/blender/depsgraph/intern/depsgraph_type.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type.cc
@@ -39,8 +39,7 @@
namespace deg = blender::deg;
-/* Register all node types */
-void DEG_register_node_types(void)
+void DEG_register_node_types()
{
/* register node types */
deg::deg_register_base_depsnodes();
@@ -48,8 +47,7 @@ void DEG_register_node_types(void)
deg::deg_register_operation_depsnodes();
}
-/* Free registry on exit */
-void DEG_free_node_types(void)
+void DEG_free_node_types()
{
}
diff --git a/source/blender/depsgraph/intern/depsgraph_update.cc b/source/blender/depsgraph/intern/depsgraph_update.cc
index bb72320ca67..ec287edbd12 100644
--- a/source/blender/depsgraph/intern/depsgraph_update.cc
+++ b/source/blender/depsgraph/intern/depsgraph_update.cc
@@ -50,7 +50,6 @@ void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, bool upd
} // namespace blender::deg
-/* Set callbacks which are being called when depsgraph changes. */
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSceneCb scene_func)
{
deg::deg_editor_update_id_cb = id_func;
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index c816c7b8db5..30aeeee5b2c 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -361,17 +361,8 @@ static TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state)
return BLI_task_pool_create_suspended(state, TASK_PRIORITY_HIGH);
}
-/**
- * Evaluate all nodes tagged for updating,
- * \warning This is usually done as part of main loop, but may also be
- * called from frame-change update.
- *
- * \note Time sources should be all valid!
- */
void deg_evaluate_on_refresh(Depsgraph *graph)
{
- graph_tag_ids_for_visible_update(graph);
-
/* Nothing to update, early out. */
if (graph->entry_tags.is_empty()) {
return;
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 a844d23b558..851d0bcf000 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
@@ -511,12 +511,6 @@ inline bool check_datablock_expanded(const ID *id_cow)
struct RemapCallbackUserData {
/* Dependency graph for which remapping is happening. */
const Depsgraph *depsgraph;
- /* Create placeholder for ID nodes for cases when we need to remap original
- * ID to it[s CoW version but we don't have required ID node yet.
- *
- * This happens when expansion happens a ta construction time. */
- DepsgraphNodeBuilder *node_builder;
- bool create_placeholders;
};
int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
@@ -526,38 +520,11 @@ int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
- ID *id_self = cb_data->id_self;
RemapCallbackUserData *user_data = (RemapCallbackUserData *)cb_data->user_data;
const Depsgraph *depsgraph = user_data->depsgraph;
ID *id_orig = *id_p;
if (deg_copy_on_write_is_needed(id_orig)) {
- ID *id_cow;
- if (user_data->create_placeholders) {
- /* Special workaround to stop creating temp datablocks for
- * objects which are coming from scene's collection and which
- * are never linked to any of layers.
- *
- * TODO(sergey): Ideally we need to tell ID looper to ignore
- * those or at least make it more reliable check where the
- * pointer is coming from. */
- const ID_Type id_type = GS(id_orig->name);
- const ID_Type id_type_self = GS(id_self->name);
- if (id_type == ID_OB && id_type_self == ID_SCE) {
- IDNode *id_node = depsgraph->find_id_node(id_orig);
- if (id_node == nullptr) {
- id_cow = id_orig;
- }
- else {
- id_cow = id_node->id_cow;
- }
- }
- else {
- id_cow = user_data->node_builder->ensure_cow_id(id_orig);
- }
- }
- else {
- id_cow = depsgraph->get_cow_id(id_orig);
- }
+ ID *id_cow = depsgraph->get_cow_id(id_orig);
BLI_assert(id_cow != nullptr);
DEG_COW_PRINT(
" Remapping datablock for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow);
@@ -834,34 +801,29 @@ int foreach_libblock_validate_callback(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
-} // namespace
-
/* Actual implementation of logic which "expands" all the data which was not
* yet copied-on-write.
*
* NOTE: Expects that CoW datablock is empty. */
-ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
- const IDNode *id_node,
- DepsgraphNodeBuilder *node_builder,
- bool create_placeholders)
+ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode *id_node)
{
const ID *id_orig = id_node->id_orig;
ID *id_cow = id_node->id_cow;
const int id_cow_recalc = id_cow->recalc;
+
/* No need to expand such datablocks, their copied ID is same as original
* one already. */
if (!deg_copy_on_write_is_needed(id_orig)) {
return id_cow;
}
+
DEG_COW_PRINT(
"Expanding datablock for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow);
+
/* Sanity checks. */
- /* NOTE: Disabled for now, conflicts when re-using evaluated datablock when
- * rebuilding dependencies. */
- if (check_datablock_expanded(id_cow) && create_placeholders) {
- deg_free_copy_on_write_datablock(id_cow);
- }
- // BLI_assert(check_datablock_expanded(id_cow) == false);
+ BLI_assert(check_datablock_expanded(id_cow) == false);
+ BLI_assert(id_cow->py_instance == nullptr);
+
/* Copy data from original ID to a copied version. */
/* TODO(sergey): Avoid doing full ID copy somehow, make Mesh to reference
* original geometry arrays for until those are modified. */
@@ -914,8 +876,6 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
/* Perform remapping of the nodes. */
RemapCallbackUserData user_data = {nullptr};
user_data.depsgraph = depsgraph;
- user_data.node_builder = node_builder;
- user_data.create_placeholders = create_placeholders;
BKE_library_foreach_ID_link(nullptr,
id_cow,
foreach_libblock_remap_callback,
@@ -928,16 +888,7 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
return id_cow;
}
-/* NOTE: Depsgraph is supposed to have ID node already. */
-ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
- ID *id_orig,
- DepsgraphNodeBuilder *node_builder,
- bool create_placeholders)
-{
- IDNode *id_node = depsgraph->find_id_node(id_orig);
- BLI_assert(id_node != nullptr);
- return deg_expand_copy_on_write_datablock(depsgraph, id_node, node_builder, create_placeholders);
-}
+} // namespace
ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode *id_node)
{
@@ -947,6 +898,29 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode
if (!deg_copy_on_write_is_needed(id_orig)) {
return id_cow;
}
+
+ /* When updating object data in edit-mode, don't request COW update since this will duplicate
+ * all object data which is unnecessary when the edit-mode data is used for calculating
+ * modifiers.
+ *
+ * TODO: Investigate modes besides edit-mode. */
+ if (check_datablock_expanded(id_cow)) {
+ const ID_Type id_type = GS(id_orig->name);
+ if (OB_DATA_SUPPORT_EDITMODE(id_type) && BKE_object_data_is_in_editmode(id_orig)) {
+ /* Make sure pointers in the edit mode data are updated in the copy.
+ * This allows depsgraph to pick up changes made in another context after it has been
+ * evaluated. Consider the following scenario:
+ *
+ * - ObjectA in SceneA is using Mesh.
+ * - ObjectB in SceneB is using Mesh (same exact datablock).
+ * - Depsgraph of SceneA is evaluated.
+ * - Depsgraph of SceneB is evaluated.
+ * - User enters edit mode of ObjectA in SceneA. */
+ update_edit_mode_pointers(depsgraph, id_orig, id_cow);
+ return id_cow;
+ }
+ }
+
RuntimeBackup backup(depsgraph);
backup.init_from_id(id_cow);
deg_free_copy_on_write_datablock(id_cow);
@@ -955,7 +929,9 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode
return id_cow;
}
-/* NOTE: Depsgraph is supposed to have ID node already. */
+/**
+ * \note Depsgraph is supposed to have ID node already.
+ */
ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, ID *id_orig)
{
IDNode *id_node = depsgraph->find_id_node(id_orig);
@@ -1036,10 +1012,12 @@ void discard_edit_mode_pointers(ID *id_cow)
} // namespace
-/* Free content of the CoW data-block
+/**
+ Free content of the CoW data-block.
* Notes:
* - Does not recurse into nested ID data-blocks.
- * - Does not free data-block itself. */
+ * - Does not free data-block itself.
+ */
void deg_free_copy_on_write_datablock(ID *id_cow)
{
if (!check_datablock_expanded(id_cow)) {
@@ -1055,7 +1033,7 @@ void deg_free_copy_on_write_datablock(ID *id_cow)
case ID_OB: {
/* TODO(sergey): This workaround is only to prevent free derived
* caches from modifying object->data. This is currently happening
- * due to mesh/curve datablock boundbox tagging dirty. */
+ * due to mesh/curve data-block bound-box tagging dirty. */
Object *ob_cow = (Object *)id_cow;
ob_cow->data = nullptr;
ob_cow->sculpt = nullptr;
@@ -1065,6 +1043,7 @@ void deg_free_copy_on_write_datablock(ID *id_cow)
break;
}
discard_edit_mode_pointers(id_cow);
+ BKE_libblock_free_data_py(id_cow);
BKE_libblock_free_datablock(id_cow, 0);
BKE_libblock_free_data(id_cow, false);
/* Signal datablock as not being expanded. */
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
index d0bb841caab..bc023766a46 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
@@ -50,46 +50,40 @@ struct Depsgraph;
class DepsgraphNodeBuilder;
struct IDNode;
-/* Get fully expanded (ready for use) copy-on-write data-block for the given
- * original data-block.
- */
-ID *deg_expand_copy_on_write_datablock(const struct Depsgraph *depsgraph,
- const IDNode *id_node,
- DepsgraphNodeBuilder *node_builder = nullptr,
- bool create_placeholders = false);
-ID *deg_expand_copy_on_write_datablock(const struct Depsgraph *depsgraph,
- struct ID *id_orig,
- DepsgraphNodeBuilder *node_builder = nullptr,
- bool create_placeholders = false);
-
-/* Makes sure given CoW data-block is brought back to state of the original
+/**
+ * Makes sure given CoW data-block is brought back to state of the original
* data-block.
*/
ID *deg_update_copy_on_write_datablock(const struct Depsgraph *depsgraph, const IDNode *id_node);
ID *deg_update_copy_on_write_datablock(const struct Depsgraph *depsgraph, struct ID *id_orig);
-/* Helper function which frees memory used by copy-on-written data-block. */
+/** Helper function which frees memory used by copy-on-written data-block. */
void deg_free_copy_on_write_datablock(struct ID *id_cow);
-/* Callback function for depsgraph operation node which ensures copy-on-write
+/**
+ * Callback function for depsgraph operation node which ensures copy-on-write
* data-block is ready for use by further evaluation routines.
*/
void deg_evaluate_copy_on_write(struct ::Depsgraph *depsgraph, const struct IDNode *id_node);
-/* Check that given ID is properly expanded and does not have any shallow
- * copies inside. */
+/**
+ * Check that given ID is properly expanded and does not have any shallow
+ * copies inside.
+ */
bool deg_validate_copy_on_write_datablock(ID *id_cow);
-/* Tag given ID block as being copy-on-written. */
+/** Tag given ID block as being copy-on-written. */
void deg_tag_copy_on_write_id(struct ID *id_cow, const struct ID *id_orig);
-/* Check whether ID data-block is expanded.
+/**
+ * Check whether ID data-block is expanded.
*
* TODO(sergey): Make it an inline function or a macro.
*/
bool deg_copy_on_write_is_expanded(const struct ID *id_cow);
-/* Check whether copy-on-write data-block is needed for given ID.
+/**
+ * Check whether copy-on-write data-block is needed for given ID.
*
* There are some exceptions on data-blocks which are covered by dependency graph
* but which we don't want to start duplicating.
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index a015491e2d7..7ec77689ba5 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -346,9 +346,6 @@ void invalidate_tagged_evaluated_data(Depsgraph *graph)
} // namespace
-/* Flush updates from tagged nodes outwards until all affected nodes
- * are tagged.
- */
void deg_graph_flush_updates(Depsgraph *graph)
{
/* Sanity checks. */
@@ -395,7 +392,6 @@ void deg_graph_flush_updates(Depsgraph *graph)
invalidate_tagged_evaluated_data(graph);
}
-/* Clear tags from all operation nodes. */
void deg_graph_clear_tags(Depsgraph *graph)
{
/* Go over all operation nodes, clearing tags. */
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
index ec661360fdf..d70df62cb38 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
@@ -30,12 +30,14 @@ namespace deg {
struct Depsgraph;
-/* Flush updates from tagged nodes outwards until all affected nodes
- * are tagged.
+/**
+ * Flush updates from tagged nodes outwards until all affected nodes are tagged.
*/
void deg_graph_flush_updates(struct Depsgraph *graph);
-/* Clear tags from all operation nodes. */
+/**
+ * Clear tags from all operation nodes.
+ */
void deg_graph_clear_tags(struct Depsgraph *graph);
} // namespace deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
index 7893e8c64c1..8bf64af7d5d 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
@@ -52,7 +52,9 @@ void RuntimeBackup::init_from_id(ID *id)
}
have_backup = true;
+ /* Clear, so freeing the expanded data doesn't touch this Python reference. */
id_data.py_instance = id->py_instance;
+ id->py_instance = nullptr;
animation_backup.init_from_id(id);
diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc
index fee5342df59..075bfd35ec1 100644
--- a/source/blender/depsgraph/intern/node/deg_node.cc
+++ b/source/blender/depsgraph/intern/node/deg_node.cc
@@ -94,8 +94,6 @@ const char *nodeTypeAsString(NodeType type)
return "PARTICLE_SETTINGS";
case NodeType::SHADING:
return "SHADING";
- case NodeType::SHADING_PARAMETERS:
- return "SHADING_PARAMETERS";
case NodeType::CACHE:
return "CACHE";
case NodeType::POINT_CACHE:
@@ -114,8 +112,12 @@ const char *nodeTypeAsString(NodeType type)
return "ARMATURE";
case NodeType::GENERIC_DATABLOCK:
return "GENERIC_DATABLOCK";
+ case NodeType::VISIBILITY:
+ return "VISIBILITY";
case NodeType::SIMULATION:
return "SIMULATION";
+ case NodeType::NTREE_OUTPUT:
+ return "NTREE_OUTPUT";
/* Total number of meaningful node types. */
case NodeType::NUM_TYPES:
@@ -159,7 +161,6 @@ eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type)
case NodeType::GENERIC_DATABLOCK:
case NodeType::PARTICLE_SYSTEM:
case NodeType::PARTICLE_SETTINGS:
- case NodeType::SHADING_PARAMETERS:
case NodeType::POINT_CACHE:
case NodeType::IMAGE_ANIMATION:
case NodeType::BATCH_CACHE:
@@ -175,9 +176,14 @@ eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type)
case NodeType::CACHE:
case NodeType::PROXY:
case NodeType::SIMULATION:
+ case NodeType::NTREE_OUTPUT:
+ return DEG_SCENE_COMP_PARAMETERS;
+
+ case NodeType::VISIBILITY:
+ BLI_assert_msg(0, "Visibility component is supposed to be only used internally.");
return DEG_SCENE_COMP_PARAMETERS;
}
- BLI_assert_msg(0, "Unhandled node type, not suppsed to happen.");
+ BLI_assert_msg(0, "Unhandled node type, not supposed to happen.");
return DEG_SCENE_COMP_PARAMETERS;
}
@@ -242,16 +248,20 @@ eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type)
case NodeType::GENERIC_DATABLOCK:
case NodeType::PARTICLE_SYSTEM:
case NodeType::PARTICLE_SETTINGS:
- case NodeType::SHADING_PARAMETERS:
case NodeType::POINT_CACHE:
case NodeType::IMAGE_ANIMATION:
case NodeType::BATCH_CACHE:
case NodeType::DUPLI:
case NodeType::SYNCHRONIZATION:
case NodeType::SIMULATION:
+ case NodeType::NTREE_OUTPUT:
case NodeType::UNDEFINED:
case NodeType::NUM_TYPES:
return DEG_OB_COMP_PARAMETERS;
+
+ case NodeType::VISIBILITY:
+ BLI_assert_msg(0, "Visibility component is supposed to be only used internally.");
+ return DEG_OB_COMP_PARAMETERS;
}
BLI_assert_msg(0, "Unhandled node type, not suppsed to happen.");
return DEG_OB_COMP_PARAMETERS;
@@ -305,7 +315,6 @@ Node::~Node()
}
}
-/* Generic identifier for Depsgraph Nodes. */
string Node::identifier() const
{
return string(nodeTypeAsString(type)) + " : " + name;
diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h
index e1469b68b0e..25bbb9a7237 100644
--- a/source/blender/depsgraph/intern/node/deg_node.h
+++ b/source/blender/depsgraph/intern/node/deg_node.h
@@ -83,7 +83,7 @@ enum class NodeType {
ANIMATION,
/* Transform Component (Parenting/Constraints) */
TRANSFORM,
- /* Geometry Component (Mesh/Displist) */
+ /* Geometry Component (#Mesh / #DispList) */
GEOMETRY,
/* Sequencer Component (Scene Only) */
SEQUENCER,
@@ -103,6 +103,22 @@ enum class NodeType {
* not have very distinctive update procedure. */
GENERIC_DATABLOCK,
+ /* Component which is used to define visibility relation between IDs, on the ID level.
+ *
+ * Consider two ID nodes NodeA and NodeB, with the relation between visibility components going
+ * as NodeA -> NodeB. If NodeB is considered visible on screen, then the relation will ensure
+ * that NodeA is also visible. The way how relation is oriented could be seen as a inverted from
+ * visibility dependency point of view, but it follows the same direction as data dependency
+ * which simplifies common algorithms which are dealing with relations and visibility.
+ *
+ * The fact that the visibility operates on the ID level basically means that all components in
+ * the NodeA will be considered as affecting directly visible when NodeB's visibility is
+ * affecting directly visible ID.
+ *
+ * This is the way to ensure objects needed for visualization without any actual data dependency
+ * properly evaluated. Example of this is custom shapes for bones. */
+ VISIBILITY,
+
/* **** Evaluation-Related Outer Types (with Subdata) **** */
/* Pose Component - Owner/Container of Bones Eval */
@@ -114,7 +130,6 @@ enum class NodeType {
PARTICLE_SETTINGS,
/* Material Shading Component */
SHADING,
- SHADING_PARAMETERS,
/* Point cache Component */
POINT_CACHE,
/* Image Animation Component */
@@ -132,6 +147,8 @@ enum class NodeType {
SYNCHRONIZATION,
/* Simulation component. */
SIMULATION,
+ /* Node tree output component. */
+ NTREE_OUTPUT,
/* Total number of meaningful node types. */
NUM_TYPES,
@@ -186,6 +203,7 @@ struct Node {
Node();
virtual ~Node();
+ /** Generic identifier for Depsgraph Nodes. */
virtual string identifier() const;
virtual void init(const ID * /*id*/, const char * /*subdata*/)
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc
index 0947fad7670..4c430904e44 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_component.cc
@@ -43,7 +43,9 @@ namespace blender::deg {
/* *********** */
/* Outer Nodes */
-/* Standard Component Methods ============================= */
+/* -------------------------------------------------------------------- */
+/** \name Standard Component Methods
+ * \{ */
ComponentNode::OperationIDKey::OperationIDKey()
: opcode(OperationCode::OPERATION), name(""), name_tag(-1)
@@ -86,7 +88,6 @@ ComponentNode::ComponentNode()
operations_map = new Map<ComponentNode::OperationIDKey, OperationNode *>();
}
-/* Initialize 'component' node - from pointer data given */
void ComponentNode::init(const ID * /*id*/, const char * /*subdata*/)
{
/* hook up eval context? */
@@ -297,9 +298,12 @@ void ComponentNode::finalize_build(Depsgraph * /*graph*/)
operations_map = nullptr;
}
-/* Bone Component ========================================= */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Component
+ * \{ */
-/* Initialize 'bone component' node - from pointer data given */
void BoneComponentNode::init(const ID *id, const char *subdata)
{
/* generic component-node... */
@@ -315,7 +319,11 @@ void BoneComponentNode::init(const ID *id, const char *subdata)
this->pchan = BKE_pose_channel_find_name(object->pose, subdata);
}
-/* Register all components. =============================== */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Register All Components
+ * \{ */
DEG_COMPONENT_NODE_DEFINE(Animation, ANIMATION, ID_RECALC_ANIMATION);
/* TODO(sergey): Is this a correct tag? */
@@ -334,7 +342,6 @@ DEG_COMPONENT_NODE_DEFINE(Pose, EVAL_POSE, ID_RECALC_GEOMETRY);
DEG_COMPONENT_NODE_DEFINE(Proxy, PROXY, ID_RECALC_GEOMETRY);
DEG_COMPONENT_NODE_DEFINE(Sequencer, SEQUENCER, 0);
DEG_COMPONENT_NODE_DEFINE(Shading, SHADING, ID_RECALC_SHADING);
-DEG_COMPONENT_NODE_DEFINE(ShadingParameters, SHADING_PARAMETERS, ID_RECALC_SHADING);
DEG_COMPONENT_NODE_DEFINE(Transform, TRANSFORM, ID_RECALC_TRANSFORM);
DEG_COMPONENT_NODE_DEFINE(ObjectFromLayer, OBJECT_FROM_LAYER, 0);
DEG_COMPONENT_NODE_DEFINE(Dupli, DUPLI, 0);
@@ -342,9 +349,15 @@ DEG_COMPONENT_NODE_DEFINE(Synchronization, SYNCHRONIZATION, 0);
DEG_COMPONENT_NODE_DEFINE(Audio, AUDIO, 0);
DEG_COMPONENT_NODE_DEFINE(Armature, ARMATURE, 0);
DEG_COMPONENT_NODE_DEFINE(GenericDatablock, GENERIC_DATABLOCK, 0);
+DEG_COMPONENT_NODE_DEFINE(Visibility, VISIBILITY, 0);
DEG_COMPONENT_NODE_DEFINE(Simulation, SIMULATION, 0);
+DEG_COMPONENT_NODE_DEFINE(NTreeOutput, NTREE_OUTPUT, ID_RECALC_NTREE_OUTPUT);
-/* Node Types Register =================================== */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Types Register
+ * \{ */
void deg_register_component_depsnodes()
{
@@ -364,7 +377,6 @@ void deg_register_component_depsnodes()
register_node_typeinfo(&DNTI_EVAL_POSE);
register_node_typeinfo(&DNTI_SEQUENCER);
register_node_typeinfo(&DNTI_SHADING);
- register_node_typeinfo(&DNTI_SHADING_PARAMETERS);
register_node_typeinfo(&DNTI_TRANSFORM);
register_node_typeinfo(&DNTI_OBJECT_FROM_LAYER);
register_node_typeinfo(&DNTI_DUPLI);
@@ -372,7 +384,11 @@ void deg_register_component_depsnodes()
register_node_typeinfo(&DNTI_AUDIO);
register_node_typeinfo(&DNTI_ARMATURE);
register_node_typeinfo(&DNTI_GENERIC_DATABLOCK);
+ register_node_typeinfo(&DNTI_VISIBILITY);
register_node_typeinfo(&DNTI_SIMULATION);
+ register_node_typeinfo(&DNTI_NTREE_OUTPUT);
}
+/** \} */
+
} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h
index 6e31ef268ed..f7acd8c72c3 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.h
+++ b/source/blender/depsgraph/intern/node/deg_node_component.h
@@ -67,6 +67,7 @@ struct ComponentNode : public Node {
ComponentNode();
~ComponentNode();
+ /** Initialize 'component' node - from pointer data given. */
void init(const ID *id, const char *subdata) override;
virtual string identifier() const override;
@@ -162,27 +163,19 @@ struct ComponentNode : public Node {
DEG_COMPONENT_NODE_DECLARE; \
}
-/* When updating object data in edit-mode, don't request COW update since this will duplicate
- * all object data which is unnecessary when the edit-mode data is used for calculating modifiers.
- *
- * TODO: Investigate modes besides edit-mode. */
-#define DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_OBDATA_IN_EDIT_MODE(name) \
+#define DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(name) \
struct name##ComponentNode : public ComponentNode { \
DEG_COMPONENT_NODE_DECLARE; \
- virtual bool need_tag_cow_before_update() override \
+ virtual bool need_tag_cow_before_update() \
{ \
- if (OB_DATA_SUPPORT_EDITMODE(owner->id_type) && \
- BKE_object_data_is_in_editmode(owner->id_orig)) { \
- return false; \
- } \
- return true; \
+ return false; \
} \
}
-#define DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(name) \
+#define DEG_COMPONENT_NODE_DECLARE_NO_COW(name) \
struct name##ComponentNode : public ComponentNode { \
DEG_COMPONENT_NODE_DECLARE; \
- virtual bool need_tag_cow_before_update() \
+ virtual bool depends_on_cow() \
{ \
return false; \
} \
@@ -192,7 +185,7 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(Animation);
DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(BatchCache);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Cache);
DEG_COMPONENT_NODE_DECLARE_GENERIC(CopyOnWrite);
-DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_OBDATA_IN_EDIT_MODE(Geometry);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Geometry);
DEG_COMPONENT_NODE_DECLARE_GENERIC(ImageAnimation);
DEG_COMPONENT_NODE_DECLARE_GENERIC(LayerCollections);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Particles);
@@ -210,10 +203,13 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(Synchronization);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Audio);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Armature);
DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock);
+DEG_COMPONENT_NODE_DECLARE_NO_COW(Visibility);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Simulation);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(NTreeOutput);
/* Bone Component */
struct BoneComponentNode : public ComponentNode {
+ /** Initialize 'bone component' node - from pointer data given. */
void init(const ID *id, const char *subdata);
struct bPoseChannel *pchan; /* the bone that this component represents */
diff --git a/source/blender/depsgraph/intern/node/deg_node_factory.h b/source/blender/depsgraph/intern/node/deg_node_factory.h
index 125f340a0fa..b3153a7ddfb 100644
--- a/source/blender/depsgraph/intern/node/deg_node_factory.h
+++ b/source/blender/depsgraph/intern/node/deg_node_factory.h
@@ -55,7 +55,7 @@ template<class ModeObjectType> struct DepsNodeFactoryImpl : public DepsNodeFacto
void register_node_typeinfo(DepsNodeFactory *factory);
/* Get typeinfo for specified type */
-DepsNodeFactory *type_get_factory(const NodeType type);
+DepsNodeFactory *type_get_factory(NodeType type);
} // namespace deg
} // namespace blender
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc
index 2b1ebc663fe..baad8318de2 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_id.cc
@@ -73,7 +73,6 @@ uint64_t IDNode::ComponentIDKey::hash() const
BLI_ghashutil_strhash_p(name));
}
-/* Initialize 'id' node - from pointer data given. */
void IDNode::init(const ID *id, const char *UNUSED(subdata))
{
BLI_assert(id != nullptr);
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h
index 073469598dc..257e42b8e67 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.h
+++ b/source/blender/depsgraph/intern/node/deg_node_id.h
@@ -58,6 +58,7 @@ struct IDNode : public Node {
const char *name;
};
+ /** Initialize 'id' node - from pointer data given. */
virtual void init(const ID *id, const char *subdata) override;
void init_copy_on_write(ID *id_cow_hint = nullptr);
~IDNode();
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc
index c25dc6fc8d5..2d0d6854851 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc
@@ -182,6 +182,9 @@ const char *operationCodeAsString(OperationCode opcode)
return "LIGHT_UPDATE";
case OperationCode::WORLD_UPDATE:
return "WORLD_UPDATE";
+ /* Node Tree. */
+ case OperationCode::NTREE_OUTPUT:
+ return "NTREE_OUTPUT";
/* Movie clip. */
case OperationCode::MOVIECLIP_EVAL:
return "MOVIECLIP_EVAL";
@@ -218,8 +221,6 @@ string OperationNode::identifier() const
return string(operationCodeAsString(opcode)) + "(" + name + ")";
}
-/* Full node identifier, including owner name.
- * used for logging and debug prints. */
string OperationNode::full_identifier() const
{
string owner_str = owner->owner->name;
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h
index a17186da941..4abdc014946 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.h
@@ -177,6 +177,9 @@ enum class OperationCode {
LIGHT_UPDATE,
WORLD_UPDATE,
+ /* Node Tree. ----------------------------------------------------------- */
+ NTREE_OUTPUT,
+
/* Batch caches. -------------------------------------------------------- */
GEOMETRY_SELECT_UPDATE,
@@ -233,6 +236,10 @@ struct OperationNode : public Node {
OperationNode();
virtual string identifier() const override;
+ /**
+ * Full node identifier, including owner name.
+ * used for logging and debug prints.
+ */
string full_identifier() const;
virtual void tag_update(Depsgraph *graph, eUpdateSource source) override;
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 8d27a492156..f8741ea48c4 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -44,9 +44,11 @@ set(INC
../../../intern/atomic
../../../intern/glew-mx
../../../intern/guardedalloc
+ ../../../intern/opensubdiv
# dna_type_offsets.h
${CMAKE_CURRENT_BINARY_DIR}/../makesdna/intern
+ ${OPENSUBDIV_INCLUDE_DIRS}
)
set(EEVEE_BUILD_DIR
@@ -80,6 +82,7 @@ set(SRC
intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
intern/mesh_extractors/extract_mesh_ibo_points.cc
intern/mesh_extractors/extract_mesh_ibo_tris.cc
+ intern/mesh_extractors/extract_mesh_vbo_attributes.cc
intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
@@ -103,17 +106,17 @@ set(SRC
intern/draw_cache_impl_curve.cc
intern/draw_cache_impl_displist.c
intern/draw_cache_impl_gpencil.c
- intern/draw_cache_impl_hair.c
+ intern/draw_cache_impl_hair.cc
intern/draw_cache_impl_lattice.c
intern/draw_cache_impl_mesh.c
intern/draw_cache_impl_metaball.c
intern/draw_cache_impl_particles.c
intern/draw_cache_impl_pointcloud.c
+ intern/draw_cache_impl_subdivision.cc
intern/draw_cache_impl_volume.c
intern/draw_color_management.cc
intern/draw_common.c
intern/draw_debug.c
- intern/draw_view_data.cc
intern/draw_fluid.c
intern/draw_hair.c
intern/draw_instance_data.c
@@ -125,12 +128,15 @@ set(SRC
intern/draw_manager_text.c
intern/draw_manager_texture.c
intern/draw_select_buffer.c
- intern/draw_texture_pool.cc
intern/draw_shader.c
+ intern/draw_texture_pool.cc
intern/draw_view.c
+ intern/draw_view_data.cc
+ intern/smaa_textures.c
engines/basic/basic_engine.c
- engines/image/image_engine.c
- engines/image/image_shader.c
+ engines/basic/basic_shader.c
+ engines/image/image_engine.cc
+ engines/image/image_shader.cc
engines/eevee/eevee_camera.cc
engines/eevee/eevee_depth_of_field.cc
engines/eevee/eevee_engine.c
@@ -167,7 +173,7 @@ set(SRC
engines/workbench/workbench_materials.c
engines/workbench/workbench_opaque.c
engines/workbench/workbench_render.c
- engines/workbench/workbench_shader.c
+ engines/workbench/workbench_shader.cc
engines/workbench/workbench_shadow.c
engines/workbench/workbench_transparent.c
engines/workbench/workbench_volume.c
@@ -210,6 +216,7 @@ set(SRC
DRW_engine.h
DRW_select_buffer.h
+ intern/DRW_gpu_wrapper.hh
intern/DRW_render.h
intern/draw_cache.h
intern/draw_cache_extract.h
@@ -218,19 +225,22 @@ set(SRC
intern/draw_color_management.h
intern/draw_common.h
intern/draw_debug.h
- intern/draw_view_data.h
intern/draw_hair_private.h
intern/draw_instance_data.h
intern/draw_manager.h
intern/draw_manager_profiling.h
intern/draw_manager_testing.h
intern/draw_manager_text.h
- intern/draw_texture_pool.h
intern/draw_shader.h
+ intern/draw_shader_shared.h
+ intern/draw_subdivision.h
+ intern/draw_texture_pool.h
intern/draw_view.h
+ intern/draw_view_data.h
intern/mesh_extractors/extract_mesh.h
intern/smaa_textures.h
engines/basic/basic_engine.h
+ engines/basic/basic_private.h
engines/eevee/eevee_engine.h
engines/eevee/eevee_lightcache.h
engines/eevee/eevee_camera.hh
@@ -240,10 +250,14 @@ set(SRC
engines/eevee/eevee_lut.h
engines/eevee/eevee_private.h
engines/external/external_engine.h
+ engines/image/image_drawing_mode_image_space.hh
engines/image/image_engine.h
- engines/image/image_private.h
+ engines/image/image_private.hh
+ engines/image/image_space_image.hh
+ engines/image/image_space_node.hh
engines/workbench/workbench_engine.h
engines/workbench/workbench_private.h
+ engines/workbench/workbench_shader_shared.h
engines/select/select_engine.h
engines/select/select_private.h
engines/overlay/overlay_engine.h
@@ -256,286 +270,328 @@ set(LIB
bf_windowmanager
)
-data_to_c(${EEVEE_BUILD_DIR}/shaders/eevee_raytrace_resolve_lib.glsl ${EEVEE_BUILD_DIR}/shaders/eevee_raytrace_resolve_lib.glsl.c SRC)
-
-data_to_c_simple(engines/eevee/shaders/eevee_bsdf_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_bsdf_microfacet_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_bsdf_sampling_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_bsdf_stubs_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_camera_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_camera_velocity_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_closure_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_cubemap_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_culling_debug_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_culling_iter_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_culling_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_culling_select_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_culling_sort_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_culling_tile_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_deferred_direct_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_deferred_holdout_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_deferred_transparent_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_deferred_volume_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_clear_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_hiz_copy_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_hiz_downsample_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_accumulator_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_bokeh_lut_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_filter_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_gather_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_gather_holefill_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_reduce_copy_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_reduce_downsample_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_reduce_recursive_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_resolve_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_scatter_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_scatter_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_scatter_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_setup_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_tiles_dilate_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_depth_of_field_tiles_flatten_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_film_filter_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_film_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_film_resolve_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_film_resolve_depth_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_gbuffer_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_irradiance_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_light_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_light_eval_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lightprobe_display_cubemap_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lightprobe_display_cubemap_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lightprobe_display_grid_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lightprobe_display_grid_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lightprobe_display_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lightprobe_eval_cubemap_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lightprobe_eval_grid_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lightprobe_filter_diffuse_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lightprobe_filter_downsample_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lightprobe_filter_geom.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lightprobe_filter_glossy_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lightprobe_filter_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lightprobe_filter_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lightprobe_filter_visibility_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_lookdev_background_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_ltc_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_motion_blur_gather_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_motion_blur_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_motion_blur_tiles_dilate_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_motion_blur_tiles_flatten_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_nodetree_eval_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_raytrace_denoise_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_raytrace_raygen_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_raytrace_raygen_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_raytrace_resolve_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_raytrace_trace_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_sampling_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_debug_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_alloc_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_copy_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_debug_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_defrag_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_free_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_init_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_mark_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_tilemap_depth_scan_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_tilemap_lod_mask_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_tilemap_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_tilemap_setup_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_tilemap_tag_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_shadow_tilemap_visibility_comp.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_subsurface_eval_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_background_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_deferred_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_depth_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_depth_simple_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_forward_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_gpencil_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_hair_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_lookdev_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_mesh_geom.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_mesh_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_velocity_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_velocity_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_velocity_mesh_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_surface_world_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_velocity_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_volume_deferred_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_volume_eval_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_volume_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/eevee_volume_vert.glsl SRC)
-
-data_to_c_simple(engines/eevee/eevee_shader_shared.hh SRC)
-
-data_to_c_simple(engines/workbench/shaders/workbench_cavity_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_composite_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_curvature_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_effect_cavity_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_effect_dof_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_effect_outline_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_vert.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_effect_taa_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_image_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_matcap_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_material_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_merge_infront_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_prepass_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_prepass_hair_vert.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_shader_interface_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_shadow_caps_geom.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_shadow_debug_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_shadow_geom.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_transparent_accum_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_transparent_resolve_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_volume_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC)
-
-data_to_c_simple(intern/shaders/common_attribute_lib.glsl SRC)
-data_to_c_simple(intern/shaders/common_colormanagement_lib.glsl SRC)
-data_to_c_simple(intern/shaders/common_debug_lib.glsl SRC)
-data_to_c_simple(intern/shaders/common_globals_lib.glsl SRC)
-data_to_c_simple(intern/shaders/common_gpencil_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_hair_refine_comp.glsl SRC)
-data_to_c_simple(intern/shaders/common_intersection_lib.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_obinfos_lib.glsl SRC)
-data_to_c_simple(intern/shaders/common_uniform_attribute_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)
-data_to_c_simple(intern/shaders/common_fullscreen_vert.glsl SRC)
-
-data_to_c_simple(engines/gpencil/shaders/gpencil_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_vert.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_antialiasing_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_antialiasing_vert.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_common_lib.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_layer_blend_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_mask_invert_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_depth_merge_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_depth_merge_vert.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_vfx_frag.glsl SRC)
-
-data_to_c_simple(engines/select/shaders/selection_id_3D_vert.glsl SRC)
-data_to_c_simple(engines/select/shaders/selection_id_frag.glsl SRC)
-
-data_to_c_simple(engines/basic/shaders/conservative_depth_geom.glsl SRC)
-data_to_c_simple(engines/basic/shaders/depth_vert.glsl SRC)
-data_to_c_simple(engines/basic/shaders/depth_frag.glsl SRC)
-
-data_to_c_simple(engines/overlay/shaders/common_overlay_lib.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/antialiasing_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/antialiasing_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_dof_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_dof_solid_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_envelope_outline_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_envelope_solid_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_envelope_solid_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_shape_outline_geom.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_shape_outline_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_shape_solid_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_shape_solid_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_shape_wire_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_sphere_outline_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_sphere_solid_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_sphere_solid_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_stick_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_stick_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_wire_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_wire_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/background_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/clipbound_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/depth_only_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_curve_handle_geom.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_curve_handle_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_curve_point_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_curve_wire_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_gpencil_canvas_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_gpencil_guide_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_gpencil_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_lattice_point_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_lattice_wire_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_common_lib.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_facefill_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_facefill_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_geom.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_normal_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_analysis_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_analysis_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_skin_root_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_particle_strand_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_particle_point_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_edges_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_edges_geom.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_edges_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_verts_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_verts_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_faces_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_face_dots_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_image_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_image_mask_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_stretching_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_groundline_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_lightprobe_grid_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_loose_point_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_loose_point_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_point_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_wire_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_wire_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/facing_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/facing_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/grid_background_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/grid_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/grid_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/image_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/image_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/motion_path_line_geom.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/motion_path_line_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/motion_path_point_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/outline_detect_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/outline_prepass_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/outline_prepass_geom.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/outline_prepass_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_face_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_point_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_texture_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_texture_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_vertcol_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_vertcol_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_weight_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_weight_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_wire_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/particle_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/particle_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/sculpt_mask_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/sculpt_mask_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/volume_velocity_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/volume_gridlines_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/wireframe_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/wireframe_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/xray_fade_frag.glsl SRC)
-
-data_to_c_simple(engines/image/shaders/engine_image_frag.glsl SRC)
-data_to_c_simple(engines/image/shaders/engine_image_vert.glsl SRC)
+set(GLSL_SRC
+ ${EEVEE_BUILD_DIR}/shaders/eevee_raytrace_resolve_lib.glsl
+
+ engines/eevee/shaders/eevee_bsdf_lib.glsl
+ engines/eevee/shaders/eevee_bsdf_microfacet_lib.glsl
+ engines/eevee/shaders/eevee_bsdf_sampling_lib.glsl
+ engines/eevee/shaders/eevee_bsdf_stubs_lib.glsl
+ engines/eevee/shaders/eevee_camera_lib.glsl
+ engines/eevee/shaders/eevee_camera_velocity_frag.glsl
+ engines/eevee/shaders/eevee_closure_lib.glsl
+ engines/eevee/shaders/eevee_cubemap_lib.glsl
+ engines/eevee/shaders/eevee_culling_debug_frag.glsl
+ engines/eevee/shaders/eevee_culling_iter_lib.glsl
+ engines/eevee/shaders/eevee_culling_lib.glsl
+ engines/eevee/shaders/eevee_culling_select_comp.glsl
+ engines/eevee/shaders/eevee_culling_sort_comp.glsl
+ engines/eevee/shaders/eevee_culling_tile_comp.glsl
+ engines/eevee/shaders/eevee_deferred_direct_frag.glsl
+ engines/eevee/shaders/eevee_deferred_holdout_frag.glsl
+ engines/eevee/shaders/eevee_deferred_transparent_frag.glsl
+ engines/eevee/shaders/eevee_deferred_volume_frag.glsl
+ engines/eevee/shaders/eevee_depth_clear_frag.glsl
+ engines/eevee/shaders/eevee_hiz_copy_frag.glsl
+ engines/eevee/shaders/eevee_hiz_downsample_frag.glsl
+ engines/eevee/shaders/eevee_depth_of_field_accumulator_lib.glsl
+ engines/eevee/shaders/eevee_depth_of_field_bokeh_lut_frag.glsl
+ engines/eevee/shaders/eevee_depth_of_field_filter_frag.glsl
+ engines/eevee/shaders/eevee_depth_of_field_gather_frag.glsl
+ engines/eevee/shaders/eevee_depth_of_field_gather_holefill_frag.glsl
+ engines/eevee/shaders/eevee_depth_of_field_lib.glsl
+ engines/eevee/shaders/eevee_depth_of_field_reduce_copy_frag.glsl
+ engines/eevee/shaders/eevee_depth_of_field_reduce_downsample_frag.glsl
+ engines/eevee/shaders/eevee_depth_of_field_reduce_recursive_frag.glsl
+ engines/eevee/shaders/eevee_depth_of_field_resolve_frag.glsl
+ engines/eevee/shaders/eevee_depth_of_field_scatter_frag.glsl
+ engines/eevee/shaders/eevee_depth_of_field_scatter_lib.glsl
+ engines/eevee/shaders/eevee_depth_of_field_scatter_vert.glsl
+ engines/eevee/shaders/eevee_depth_of_field_setup_frag.glsl
+ engines/eevee/shaders/eevee_depth_of_field_tiles_dilate_frag.glsl
+ engines/eevee/shaders/eevee_depth_of_field_tiles_flatten_frag.glsl
+ engines/eevee/shaders/eevee_film_filter_frag.glsl
+ engines/eevee/shaders/eevee_film_lib.glsl
+ engines/eevee/shaders/eevee_film_resolve_frag.glsl
+ engines/eevee/shaders/eevee_film_resolve_depth_frag.glsl
+ engines/eevee/shaders/eevee_gbuffer_lib.glsl
+ engines/eevee/shaders/eevee_irradiance_lib.glsl
+ engines/eevee/shaders/eevee_light_lib.glsl
+ engines/eevee/shaders/eevee_light_eval_lib.glsl
+ engines/eevee/shaders/eevee_lightprobe_display_cubemap_frag.glsl
+ engines/eevee/shaders/eevee_lightprobe_display_cubemap_vert.glsl
+ engines/eevee/shaders/eevee_lightprobe_display_grid_frag.glsl
+ engines/eevee/shaders/eevee_lightprobe_display_grid_vert.glsl
+ engines/eevee/shaders/eevee_lightprobe_display_lib.glsl
+ engines/eevee/shaders/eevee_lightprobe_eval_cubemap_lib.glsl
+ engines/eevee/shaders/eevee_lightprobe_eval_grid_lib.glsl
+ engines/eevee/shaders/eevee_lightprobe_filter_diffuse_frag.glsl
+ engines/eevee/shaders/eevee_lightprobe_filter_downsample_frag.glsl
+ engines/eevee/shaders/eevee_lightprobe_filter_geom.glsl
+ engines/eevee/shaders/eevee_lightprobe_filter_glossy_frag.glsl
+ engines/eevee/shaders/eevee_lightprobe_filter_lib.glsl
+ engines/eevee/shaders/eevee_lightprobe_filter_vert.glsl
+ engines/eevee/shaders/eevee_lightprobe_filter_visibility_frag.glsl
+ engines/eevee/shaders/eevee_lookdev_background_frag.glsl
+ engines/eevee/shaders/eevee_ltc_lib.glsl
+ engines/eevee/shaders/eevee_motion_blur_gather_frag.glsl
+ engines/eevee/shaders/eevee_motion_blur_lib.glsl
+ engines/eevee/shaders/eevee_motion_blur_tiles_dilate_frag.glsl
+ engines/eevee/shaders/eevee_motion_blur_tiles_flatten_frag.glsl
+ engines/eevee/shaders/eevee_nodetree_eval_lib.glsl
+ engines/eevee/shaders/eevee_raytrace_denoise_comp.glsl
+ engines/eevee/shaders/eevee_raytrace_raygen_frag.glsl
+ engines/eevee/shaders/eevee_raytrace_raygen_lib.glsl
+ engines/eevee/shaders/eevee_raytrace_resolve_frag.glsl
+ engines/eevee/shaders/eevee_raytrace_trace_lib.glsl
+ engines/eevee/shaders/eevee_sampling_lib.glsl
+ engines/eevee/shaders/eevee_shadow_debug_frag.glsl
+ engines/eevee/shaders/eevee_shadow_lib.glsl
+ engines/eevee/shaders/eevee_shadow_page_alloc_comp.glsl
+ engines/eevee/shaders/eevee_shadow_page_copy_comp.glsl
+ engines/eevee/shaders/eevee_shadow_page_debug_comp.glsl
+ engines/eevee/shaders/eevee_shadow_page_defrag_comp.glsl
+ engines/eevee/shaders/eevee_shadow_page_free_comp.glsl
+ engines/eevee/shaders/eevee_shadow_page_init_comp.glsl
+ engines/eevee/shaders/eevee_shadow_page_lib.glsl
+ engines/eevee/shaders/eevee_shadow_page_mark_vert.glsl
+ engines/eevee/shaders/eevee_shadow_tilemap_depth_scan_comp.glsl
+ engines/eevee/shaders/eevee_shadow_tilemap_lod_mask_comp.glsl
+ engines/eevee/shaders/eevee_shadow_tilemap_lib.glsl
+ engines/eevee/shaders/eevee_shadow_tilemap_setup_comp.glsl
+ engines/eevee/shaders/eevee_shadow_tilemap_tag_comp.glsl
+ engines/eevee/shaders/eevee_shadow_tilemap_visibility_comp.glsl
+ engines/eevee/shaders/eevee_subsurface_eval_frag.glsl
+ engines/eevee/shaders/eevee_surface_background_frag.glsl
+ engines/eevee/shaders/eevee_surface_deferred_frag.glsl
+ engines/eevee/shaders/eevee_surface_depth_frag.glsl
+ engines/eevee/shaders/eevee_surface_depth_simple_frag.glsl
+ engines/eevee/shaders/eevee_surface_forward_frag.glsl
+ engines/eevee/shaders/eevee_surface_gpencil_vert.glsl
+ engines/eevee/shaders/eevee_surface_hair_vert.glsl
+ engines/eevee/shaders/eevee_surface_lib.glsl
+ engines/eevee/shaders/eevee_surface_lookdev_vert.glsl
+ engines/eevee/shaders/eevee_surface_mesh_geom.glsl
+ engines/eevee/shaders/eevee_surface_mesh_vert.glsl
+ engines/eevee/shaders/eevee_surface_velocity_frag.glsl
+ engines/eevee/shaders/eevee_surface_velocity_lib.glsl
+ engines/eevee/shaders/eevee_surface_velocity_mesh_vert.glsl
+ engines/eevee/shaders/eevee_surface_world_vert.glsl
+ engines/eevee/shaders/eevee_velocity_lib.glsl
+ engines/eevee/shaders/eevee_volume_deferred_frag.glsl
+ engines/eevee/shaders/eevee_volume_eval_lib.glsl
+ engines/eevee/shaders/eevee_volume_lib.glsl
+ engines/eevee/shaders/eevee_volume_vert.glsl
+
+ engines/eevee/eevee_shader_shared.hh
+
+ engines/workbench/shaders/workbench_cavity_lib.glsl
+ engines/workbench/shaders/workbench_common_lib.glsl
+ engines/workbench/shaders/workbench_composite_frag.glsl
+ engines/workbench/shaders/workbench_curvature_lib.glsl
+ engines/workbench/shaders/workbench_effect_cavity_frag.glsl
+ engines/workbench/shaders/workbench_effect_dof_frag.glsl
+ engines/workbench/shaders/workbench_effect_outline_frag.glsl
+ engines/workbench/shaders/workbench_effect_smaa_frag.glsl
+ engines/workbench/shaders/workbench_effect_smaa_vert.glsl
+ engines/workbench/shaders/workbench_effect_taa_frag.glsl
+ engines/workbench/shaders/workbench_image_lib.glsl
+ engines/workbench/shaders/workbench_matcap_lib.glsl
+ engines/workbench/shaders/workbench_material_lib.glsl
+ engines/workbench/shaders/workbench_merge_infront_frag.glsl
+ engines/workbench/shaders/workbench_prepass_frag.glsl
+ engines/workbench/shaders/workbench_prepass_hair_vert.glsl
+ engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl
+ engines/workbench/shaders/workbench_prepass_vert.glsl
+ engines/workbench/shaders/workbench_shadow_caps_geom.glsl
+ engines/workbench/shaders/workbench_shadow_debug_frag.glsl
+ engines/workbench/shaders/workbench_shadow_geom.glsl
+ engines/workbench/shaders/workbench_shadow_vert.glsl
+ engines/workbench/shaders/workbench_transparent_accum_frag.glsl
+ engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
+ engines/workbench/shaders/workbench_volume_frag.glsl
+ engines/workbench/shaders/workbench_volume_vert.glsl
+ engines/workbench/shaders/workbench_world_light_lib.glsl
+
+ engines/workbench/workbench_shader_shared.h
+
+ intern/shaders/common_attribute_lib.glsl
+ intern/shaders/common_colormanagement_lib.glsl
+ intern/shaders/common_debug_lib.glsl
+ intern/shaders/common_fullscreen_vert.glsl
+ intern/shaders/common_fxaa_lib.glsl
+ intern/shaders/common_globals_lib.glsl
+ intern/shaders/common_gpencil_lib.glsl
+ intern/shaders/common_hair_lib.glsl
+ intern/shaders/common_hair_refine_comp.glsl
+ intern/shaders/common_hair_refine_vert.glsl
+ intern/shaders/common_intersection_lib.glsl
+ intern/shaders/common_math_geom_lib.glsl
+ intern/shaders/common_math_lib.glsl
+ intern/shaders/common_obinfos_lib.glsl
+ intern/shaders/common_pointcloud_lib.glsl
+ intern/shaders/common_smaa_lib.glsl
+ intern/shaders/common_uniform_attribute_lib.glsl
+ intern/shaders/common_view_lib.glsl
+
+ intern/shaders/common_subdiv_custom_data_interp_comp.glsl
+ intern/shaders/common_subdiv_ibo_lines_comp.glsl
+ intern/shaders/common_subdiv_ibo_tris_comp.glsl
+ intern/shaders/common_subdiv_lib.glsl
+ intern/shaders/common_subdiv_normals_accumulate_comp.glsl
+ intern/shaders/common_subdiv_normals_finalize_comp.glsl
+ intern/shaders/common_subdiv_patch_evaluation_comp.glsl
+ intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl
+ intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl
+ intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl
+ intern/shaders/common_subdiv_vbo_lnor_comp.glsl
+ intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl
+
+ intern/draw_shader_shared.h
+
+ engines/gpencil/shaders/gpencil_frag.glsl
+ engines/gpencil/shaders/gpencil_vert.glsl
+ engines/gpencil/shaders/gpencil_antialiasing_frag.glsl
+ engines/gpencil/shaders/gpencil_antialiasing_vert.glsl
+ engines/gpencil/shaders/gpencil_common_lib.glsl
+ engines/gpencil/shaders/gpencil_layer_blend_frag.glsl
+ engines/gpencil/shaders/gpencil_mask_invert_frag.glsl
+ engines/gpencil/shaders/gpencil_depth_merge_frag.glsl
+ engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
+ engines/gpencil/shaders/gpencil_vfx_frag.glsl
+
+ engines/select/shaders/selection_id_3D_vert.glsl
+ engines/select/shaders/selection_id_frag.glsl
+
+ engines/basic/shaders/conservative_depth_geom.glsl
+ engines/basic/shaders/depth_vert.glsl
+ engines/basic/shaders/depth_frag.glsl
+
+ engines/overlay/shaders/common_overlay_lib.glsl
+ engines/overlay/shaders/antialiasing_frag.glsl
+ engines/overlay/shaders/antialiasing_vert.glsl
+ engines/overlay/shaders/armature_dof_vert.glsl
+ engines/overlay/shaders/armature_dof_solid_frag.glsl
+ engines/overlay/shaders/armature_envelope_outline_vert.glsl
+ engines/overlay/shaders/armature_envelope_solid_frag.glsl
+ engines/overlay/shaders/armature_envelope_solid_vert.glsl
+ engines/overlay/shaders/armature_shape_outline_geom.glsl
+ engines/overlay/shaders/armature_shape_outline_vert.glsl
+ engines/overlay/shaders/armature_shape_solid_frag.glsl
+ engines/overlay/shaders/armature_shape_solid_vert.glsl
+ engines/overlay/shaders/armature_shape_wire_vert.glsl
+ engines/overlay/shaders/armature_sphere_outline_vert.glsl
+ engines/overlay/shaders/armature_sphere_solid_frag.glsl
+ engines/overlay/shaders/armature_sphere_solid_vert.glsl
+ engines/overlay/shaders/armature_stick_frag.glsl
+ engines/overlay/shaders/armature_stick_vert.glsl
+ engines/overlay/shaders/armature_wire_frag.glsl
+ engines/overlay/shaders/armature_wire_vert.glsl
+ engines/overlay/shaders/background_frag.glsl
+ engines/overlay/shaders/clipbound_vert.glsl
+ engines/overlay/shaders/depth_only_vert.glsl
+ engines/overlay/shaders/edit_curve_handle_geom.glsl
+ engines/overlay/shaders/edit_curve_handle_vert.glsl
+ engines/overlay/shaders/edit_curve_point_vert.glsl
+ engines/overlay/shaders/edit_curve_wire_vert.glsl
+ engines/overlay/shaders/edit_gpencil_canvas_vert.glsl
+ engines/overlay/shaders/edit_gpencil_guide_vert.glsl
+ engines/overlay/shaders/edit_gpencil_vert.glsl
+ engines/overlay/shaders/edit_lattice_point_vert.glsl
+ engines/overlay/shaders/edit_lattice_wire_vert.glsl
+ engines/overlay/shaders/edit_mesh_common_lib.glsl
+ engines/overlay/shaders/edit_mesh_facefill_frag.glsl
+ engines/overlay/shaders/edit_mesh_facefill_vert.glsl
+ engines/overlay/shaders/edit_mesh_frag.glsl
+ engines/overlay/shaders/edit_mesh_geom.glsl
+ engines/overlay/shaders/edit_mesh_normal_vert.glsl
+ engines/overlay/shaders/edit_mesh_analysis_frag.glsl
+ engines/overlay/shaders/edit_mesh_analysis_vert.glsl
+ engines/overlay/shaders/edit_mesh_skin_root_vert.glsl
+ engines/overlay/shaders/edit_mesh_vert.glsl
+ engines/overlay/shaders/edit_particle_strand_vert.glsl
+ engines/overlay/shaders/edit_particle_point_vert.glsl
+ engines/overlay/shaders/edit_uv_edges_vert.glsl
+ engines/overlay/shaders/edit_uv_edges_geom.glsl
+ engines/overlay/shaders/edit_uv_edges_frag.glsl
+ engines/overlay/shaders/edit_uv_verts_vert.glsl
+ engines/overlay/shaders/edit_uv_verts_frag.glsl
+ engines/overlay/shaders/edit_uv_faces_vert.glsl
+ engines/overlay/shaders/edit_uv_face_dots_vert.glsl
+ engines/overlay/shaders/edit_uv_image_vert.glsl
+ engines/overlay/shaders/edit_uv_image_mask_frag.glsl
+ engines/overlay/shaders/edit_uv_stretching_vert.glsl
+ engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl
+ engines/overlay/shaders/extra_frag.glsl
+ engines/overlay/shaders/extra_vert.glsl
+ engines/overlay/shaders/extra_groundline_vert.glsl
+ engines/overlay/shaders/extra_lightprobe_grid_vert.glsl
+ engines/overlay/shaders/extra_loose_point_frag.glsl
+ engines/overlay/shaders/extra_loose_point_vert.glsl
+ engines/overlay/shaders/extra_point_vert.glsl
+ engines/overlay/shaders/extra_wire_frag.glsl
+ engines/overlay/shaders/extra_wire_vert.glsl
+ engines/overlay/shaders/facing_frag.glsl
+ engines/overlay/shaders/facing_vert.glsl
+ engines/overlay/shaders/grid_background_frag.glsl
+ engines/overlay/shaders/grid_frag.glsl
+ engines/overlay/shaders/grid_vert.glsl
+ engines/overlay/shaders/image_vert.glsl
+ engines/overlay/shaders/image_frag.glsl
+ engines/overlay/shaders/motion_path_line_geom.glsl
+ engines/overlay/shaders/motion_path_line_vert.glsl
+ engines/overlay/shaders/motion_path_point_vert.glsl
+ engines/overlay/shaders/outline_detect_frag.glsl
+ engines/overlay/shaders/outline_prepass_frag.glsl
+ engines/overlay/shaders/outline_prepass_geom.glsl
+ engines/overlay/shaders/outline_prepass_vert.glsl
+ engines/overlay/shaders/paint_face_vert.glsl
+ engines/overlay/shaders/paint_point_vert.glsl
+ engines/overlay/shaders/paint_texture_frag.glsl
+ engines/overlay/shaders/paint_texture_vert.glsl
+ engines/overlay/shaders/paint_vertcol_frag.glsl
+ engines/overlay/shaders/paint_vertcol_vert.glsl
+ engines/overlay/shaders/paint_weight_frag.glsl
+ engines/overlay/shaders/paint_weight_vert.glsl
+ engines/overlay/shaders/paint_wire_vert.glsl
+ engines/overlay/shaders/particle_vert.glsl
+ engines/overlay/shaders/particle_frag.glsl
+ engines/overlay/shaders/sculpt_mask_vert.glsl
+ engines/overlay/shaders/sculpt_mask_frag.glsl
+ engines/overlay/shaders/volume_velocity_vert.glsl
+ engines/overlay/shaders/volume_gridlines_vert.glsl
+ engines/overlay/shaders/wireframe_vert.glsl
+ engines/overlay/shaders/wireframe_frag.glsl
+ engines/overlay/shaders/xray_fade_frag.glsl
+
+ engines/image/shaders/engine_image_frag.glsl
+ engines/image/shaders/engine_image_vert.glsl
+)
+
+set(GLSL_C)
+foreach(GLSL_FILE ${GLSL_SRC})
+ data_to_c_simple(${GLSL_FILE} GLSL_C)
+endforeach()
+
+blender_add_lib(bf_draw_shaders "${GLSL_C}" "" "" "")
+
+list(APPEND LIB
+ bf_draw_shaders
+)
+
+set(GLSL_SOURCE_CONTENT "")
+foreach(GLSL_FILE ${GLSL_SRC})
+ get_filename_component(GLSL_FILE_NAME ${GLSL_FILE} NAME)
+ string(REPLACE "." "_" GLSL_FILE_NAME_UNDERSCORES ${GLSL_FILE_NAME})
+ string(APPEND GLSL_SOURCE_CONTENT "SHADER_SOURCE\(datatoc_${GLSL_FILE_NAME_UNDERSCORES}, \"${GLSL_FILE_NAME}\", \"${GLSL_FILE}\"\)\n")
+endforeach()
+
+set(glsl_source_list_file "${CMAKE_CURRENT_BINARY_DIR}/glsl_draw_source_list.h")
+file(GENERATE OUTPUT ${glsl_source_list_file} CONTENT "${GLSL_SOURCE_CONTENT}")
+list(APPEND SRC ${glsl_source_list_file})
+list(APPEND INC ${CMAKE_CURRENT_BINARY_DIR})
+
+target_include_directories(bf_draw_shaders PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
list(APPEND INC
)
@@ -583,8 +639,8 @@ if(WITH_GTESTS)
tests/draw_testing.hh
)
set(TEST_INC
- "../../../intern/ghost/"
- "../gpu/tests/"
+ ../../../intern/ghost
+ ../gpu/tests
)
set(TEST_LIB
)
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 927a29ed6b6..7e411fff72b 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -75,9 +75,21 @@ typedef enum eDRWSelectStage {
typedef bool (*DRW_SelectPassFn)(eDRWSelectStage stage, void *user_data);
typedef bool (*DRW_ObjectFilterFn)(struct Object *ob, void *user_data);
+/**
+ * Everything starts here.
+ * This function takes care of calling all cache and rendering functions
+ * for each relevant engine / mode engine.
+ */
void DRW_draw_view(const struct bContext *C);
+/**
+ * Draw render engine info.
+ */
void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height);
+/**
+ * Used for both regular and off-screen drawing.
+ * Need to reset DST before calling this function
+ */
void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
struct RenderEngineType *engine_type,
struct ARegion *region,
@@ -88,39 +100,54 @@ void DRW_draw_render_loop(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
struct GPUViewport *viewport);
+/**
+ * \param viewport: can be NULL, in this case we create one.
+ */
void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
struct RenderEngineType *engine_type,
struct ARegion *region,
struct View3D *v3d,
- const bool is_image_render,
- const bool draw_background,
- const bool do_color_management,
+ bool is_image_render,
+ bool draw_background,
+ bool do_color_management,
struct GPUOffScreen *ofs,
struct GPUViewport *viewport);
void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph,
struct ARegion *region,
struct GPUViewport *viewport,
const struct bContext *evil_C);
+/**
+ * object mode select-loop, see: #ED_view3d_draw_select_loop (legacy drawing).
+ */
void DRW_draw_select_loop(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
bool use_obedit_skip,
bool draw_surface,
bool use_nearest,
- const bool do_material_sub_selection,
+ bool do_material_sub_selection,
const struct rcti *rect,
DRW_SelectPassFn select_pass_fn,
void *select_pass_user_data,
DRW_ObjectFilterFn object_filter_fn,
void *object_filter_user_data);
+/**
+ * object mode select-loop, see: #ED_view3d_draw_depth_loop (legacy drawing).
+ */
void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
struct GPUViewport *viewport);
+/**
+ * Converted from #ED_view3d_draw_depth_gpencil (legacy drawing).
+ */
void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
struct GPUViewport *viewport);
+/**
+ * Clears the Depth Buffer and draws only the specified object.
+ */
void DRW_draw_depth_object(struct Scene *scene,
struct ARegion *region,
struct View3D *v3d,
@@ -131,11 +158,17 @@ void DRW_draw_select_id(struct Depsgraph *depsgraph,
struct View3D *v3d,
const struct rcti *rect);
-/* grease pencil render */
+/* Grease pencil render. */
+
+/**
+ * Helper to check if exit object type to render.
+ */
bool DRW_render_check_grease_pencil(struct Depsgraph *depsgraph);
void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph);
-/* This is here because GPUViewport needs it */
+/**
+ * This is here because #GPUViewport needs it.
+ */
struct DRWInstanceDataList *DRW_instance_data_list_create(void);
void DRW_instance_data_list_free(struct DRWInstanceDataList *idatalist);
void DRW_uniform_attrs_pool_free(struct GHash *table);
@@ -158,6 +191,10 @@ void DRW_xr_drawing_end(void);
/* For garbage collection */
void DRW_cache_free_old_batches(struct Main *bmain);
+void DRW_cache_free_old_subdiv(void);
+
+/* For the OpenGL evaluators and garbage collected subdivision data. */
+void DRW_subdiv_free(void);
/* Never use this. Only for closing blender. */
void DRW_opengl_context_enable_ex(bool restore);
@@ -165,11 +202,21 @@ void DRW_opengl_context_disable_ex(bool restore);
void DRW_opengl_render_context_enable(void *re_gl_context);
void DRW_opengl_render_context_disable(void *re_gl_context);
+/**
+ * Needs to be called AFTER #DRW_opengl_render_context_enable().
+ */
void DRW_gpu_render_context_enable(void *re_gpu_context);
+/**
+ * Needs to be called BEFORE #DRW_opengl_render_context_disable().
+ */
void DRW_gpu_render_context_disable(void *re_gpu_context);
void DRW_deferred_shader_remove(struct GPUMaterial *mat);
+/**
+ * Get DrawData from the given ID-block. In order for this to work, we assume that
+ * the DrawData pointer is stored in the struct in the same fashion as in #IdDdtTemplate.
+ */
struct DrawDataList *DRW_drawdatalist_from_id(struct ID *id);
void DRW_drawdata_free(struct ID *id);
@@ -179,6 +226,12 @@ void DRW_viewport_data_free(struct DRWData *drw_data);
bool DRW_opengl_context_release(void);
void DRW_opengl_context_activate(bool drw_state);
+/**
+ * We may want to move this into a more general location.
+ * \note This doesn't require the draw context to be in use.
+ */
+void DRW_draw_cursor_2d_ex(const struct ARegion *region, const float cursor[2]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/DRW_select_buffer.h b/source/blender/draw/DRW_select_buffer.h
index 43d4005c3a9..0d5c417457c 100644
--- a/source/blender/draw/DRW_select_buffer.h
+++ b/source/blender/draw/DRW_select_buffer.h
@@ -81,47 +81,70 @@ typedef struct SELECTID_Context {
} SELECTID_Context;
/* draw_select_buffer.c */
-bool DRW_select_buffer_elem_get(const uint sel_id,
- uint *r_elem,
- uint *r_base_index,
- char *r_elem_type);
+
+bool DRW_select_buffer_elem_get(uint sel_id, uint *r_elem, uint *r_base_index, char *r_elem_type);
uint DRW_select_buffer_context_offset_for_object_elem(struct Depsgraph *depsgraph,
struct Object *object,
char elem_type);
+/**
+ * Main function to read a block of pixels from the select frame buffer.
+ */
uint *DRW_select_buffer_read(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const rcti *rect,
uint *r_buf_len);
+/**
+ * \param rect: The rectangle to sample indices from (min/max inclusive).
+ * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure.
+ */
uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const struct rcti *rect,
uint *r_bitmap_len);
+/**
+ * \param center: Circle center.
+ * \param radius: Circle radius.
+ * \param r_bitmap_len: Number of indices in the selection id buffer.
+ * \returns a #BLI_bitmap the length of \a r_bitmap_len or NULL on failure.
+ */
uint *DRW_select_buffer_bitmap_from_circle(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const int center[2],
- const int radius,
+ int radius,
uint *r_bitmap_len);
+/**
+ * \param poly: The polygon coordinates.
+ * \param poly_len: Length of the polygon.
+ * \param rect: Polygon boundaries.
+ * \returns a #BLI_bitmap.
+ */
uint *DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const int poly[][2],
- const int poly_len,
+ int poly_len,
const struct rcti *rect,
uint *r_bitmap_len);
+/**
+ * Samples a single pixel.
+ */
uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const int center[2]);
+/**
+ * Find the selection id closest to \a center.
+ * \param dist: Use to initialize the distance,
+ * when found, this value is set to the distance of the selection that's returned.
+ */
uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const int center[2],
- const uint id_min,
- const uint id_max,
+ uint id_min,
+ uint id_max,
uint *dist);
-void DRW_select_buffer_context_create(struct Base **bases,
- const uint bases_len,
- short select_mode);
+void DRW_select_buffer_context_create(struct Base **bases, uint bases_len, short select_mode);
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index 567d14016b8..228281af2b0 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -36,16 +36,10 @@
#include "GPU_shader.h"
#include "basic_engine.h"
-/* Shaders */
+#include "basic_private.h"
#define BASIC_ENGINE "BLENDER_BASIC"
-extern char datatoc_depth_frag_glsl[];
-extern char datatoc_depth_vert_glsl[];
-extern char datatoc_conservative_depth_geom_glsl[];
-
-extern char datatoc_common_view_lib_glsl[];
-
/* *********** LISTS *********** */
/* GPUViewport.storage
@@ -56,6 +50,7 @@ typedef struct BASIC_StorageList {
typedef struct BASIC_PassList {
struct DRWPass *depth_pass[2];
+ struct DRWPass *depth_pass_pointcloud[2];
struct DRWPass *depth_pass_cull[2];
} BASIC_PassList;
@@ -67,60 +62,16 @@ typedef struct BASIC_Data {
BASIC_StorageList *stl;
} BASIC_Data;
-typedef struct BASIC_Shaders {
- /* Depth Pre Pass */
- struct GPUShader *depth;
- struct GPUShader *depth_conservative;
-} BASIC_Shaders;
-
/* *********** STATIC *********** */
-static struct {
- BASIC_Shaders sh_data[GPU_SHADER_CFG_LEN];
-} e_data = {{{NULL}}}; /* Engine data */
-
typedef struct BASIC_PrivateData {
DRWShadingGroup *depth_shgrp[2];
DRWShadingGroup *depth_shgrp_cull[2];
DRWShadingGroup *depth_hair_shgrp[2];
+ DRWShadingGroup *depth_pointcloud_shgrp[2];
bool use_material_slot_selection;
} BASIC_PrivateData; /* Transient data */
-/* Functions */
-
-static void basic_engine_init(void *UNUSED(vedata))
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- BASIC_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
-
- /* Depth prepass */
- if (!sh_data->depth) {
- const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
-
- sh_data->depth = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg->lib,
- datatoc_common_view_lib_glsl,
- datatoc_depth_vert_glsl,
- NULL},
- .frag = (const char *[]){datatoc_depth_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg->def, NULL},
- });
-
- sh_data->depth_conservative = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg->lib,
- datatoc_common_view_lib_glsl,
- datatoc_depth_vert_glsl,
- NULL},
- .geom = (const char *[]){sh_cfg->lib,
- datatoc_common_view_lib_glsl,
- datatoc_conservative_depth_geom_glsl,
- NULL},
- .frag = (const char *[]){datatoc_depth_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg->def, "#define CONSERVATIVE_RASTER\n", NULL},
- });
- }
-}
-
static void basic_cache_init(void *vedata)
{
BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl;
@@ -128,7 +79,6 @@ static void basic_cache_init(void *vedata)
DRWShadingGroup *grp;
const DRWContextState *draw_ctx = DRW_context_state_get();
- BASIC_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
if (!stl->g_data) {
/* Alloc transient pointers */
@@ -143,16 +93,29 @@ static void basic_cache_init(void *vedata)
DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- GPUShader *sh = DRW_state_is_select() ? sh_data->depth_conservative : sh_data->depth;
+ GPUShader *sh = DRW_state_is_select() ?
+ BASIC_shaders_depth_conservative_sh_get(draw_ctx->sh_cfg) :
+ BASIC_shaders_depth_sh_get(draw_ctx->sh_cfg);
DRW_PASS_CREATE(psl->depth_pass[i], state | clip_state | infront_state);
stl->g_data->depth_shgrp[i] = grp = DRW_shgroup_create(sh, psl->depth_pass[i]);
DRW_shgroup_uniform_vec2(grp, "sizeViewport", DRW_viewport_size_get(), 1);
DRW_shgroup_uniform_vec2(grp, "sizeViewportInv", DRW_viewport_invert_size_get(), 1);
- stl->g_data->depth_hair_shgrp[i] = grp = DRW_shgroup_create(sh_data->depth,
- psl->depth_pass[i]);
+ sh = DRW_state_is_select() ?
+ BASIC_shaders_pointcloud_depth_conservative_sh_get(draw_ctx->sh_cfg) :
+ BASIC_shaders_pointcloud_depth_sh_get(draw_ctx->sh_cfg);
+ DRW_PASS_CREATE(psl->depth_pass_pointcloud[i], state | clip_state | infront_state);
+ stl->g_data->depth_pointcloud_shgrp[i] = grp = DRW_shgroup_create(
+ sh, psl->depth_pass_pointcloud[i]);
+ DRW_shgroup_uniform_vec2(grp, "sizeViewport", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_vec2(grp, "sizeViewportInv", DRW_viewport_invert_size_get(), 1);
+
+ stl->g_data->depth_hair_shgrp[i] = grp = DRW_shgroup_create(
+ BASIC_shaders_depth_sh_get(draw_ctx->sh_cfg), psl->depth_pass[i]);
+ sh = DRW_state_is_select() ? BASIC_shaders_depth_conservative_sh_get(draw_ctx->sh_cfg) :
+ BASIC_shaders_depth_sh_get(draw_ctx->sh_cfg);
state |= DRW_STATE_CULL_BACK;
DRW_PASS_CREATE(psl->depth_pass_cull[i], state | clip_state | infront_state);
stl->g_data->depth_shgrp_cull[i] = grp = DRW_shgroup_create(sh, psl->depth_pass_cull[i]);
@@ -231,8 +194,16 @@ static void basic_cache_populate(void *vedata, Object *ob)
!DRW_state_is_image_render();
const bool do_cull = (draw_ctx->v3d &&
(draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING));
- DRWShadingGroup *shgrp = (do_cull) ? stl->g_data->depth_shgrp_cull[do_in_front] :
- stl->g_data->depth_shgrp[do_in_front];
+
+ DRWShadingGroup *shgrp = NULL;
+
+ if (ob->type == OB_POINTCLOUD) {
+ shgrp = stl->g_data->depth_pointcloud_shgrp[do_in_front];
+ }
+ else {
+ shgrp = (do_cull) ? stl->g_data->depth_shgrp_cull[do_in_front] :
+ stl->g_data->depth_shgrp[do_in_front];
+ }
if (use_sculpt_pbvh) {
DRW_shgroup_call_sculpt(shgrp, ob, false, false);
@@ -273,18 +244,16 @@ static void basic_draw_scene(void *vedata)
BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl;
DRW_draw_pass(psl->depth_pass[0]);
+ DRW_draw_pass(psl->depth_pass_pointcloud[0]);
DRW_draw_pass(psl->depth_pass_cull[0]);
DRW_draw_pass(psl->depth_pass[1]);
+ DRW_draw_pass(psl->depth_pass_pointcloud[1]);
DRW_draw_pass(psl->depth_pass_cull[1]);
}
static void basic_engine_free(void)
{
- for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) {
- BASIC_Shaders *sh_data = &e_data.sh_data[i];
- DRW_SHADER_FREE_SAFE(sh_data->depth);
- DRW_SHADER_FREE_SAFE(sh_data->depth_conservative);
- }
+ BASIC_shaders_free();
}
static const DrawEngineDataSize basic_data_size = DRW_VIEWPORT_DATA_SIZE(BASIC_Data);
@@ -294,9 +263,9 @@ DrawEngineType draw_engine_basic_type = {
NULL,
N_("Basic"),
&basic_data_size,
- &basic_engine_init,
- &basic_engine_free,
NULL,
+ &basic_engine_free,
+ NULL, /* instance_free */
&basic_cache_init,
&basic_cache_populate,
&basic_cache_finish,
diff --git a/source/blender/draw/engines/basic/basic_private.h b/source/blender/draw/engines/basic/basic_private.h
new file mode 100644
index 00000000000..e5f494bf0e7
--- /dev/null
+++ b/source/blender/draw/engines/basic/basic_private.h
@@ -0,0 +1,35 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GPUShader *BASIC_shaders_depth_sh_get(eGPUShaderConfig config);
+GPUShader *BASIC_shaders_pointcloud_depth_sh_get(eGPUShaderConfig config);
+GPUShader *BASIC_shaders_depth_conservative_sh_get(eGPUShaderConfig config);
+GPUShader *BASIC_shaders_pointcloud_depth_conservative_sh_get(eGPUShaderConfig config);
+void BASIC_shaders_free(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/engines/basic/basic_shader.c b/source/blender/draw/engines/basic/basic_shader.c
new file mode 100644
index 00000000000..4b92406d5c0
--- /dev/null
+++ b/source/blender/draw/engines/basic/basic_shader.c
@@ -0,0 +1,167 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "GPU_shader.h"
+
+#include "basic_private.h"
+
+extern char datatoc_depth_frag_glsl[];
+extern char datatoc_depth_vert_glsl[];
+extern char datatoc_conservative_depth_geom_glsl[];
+
+extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_common_pointcloud_lib_glsl[];
+
+/* Shaders */
+
+typedef struct BASIC_Shaders {
+ /* Depth Pre Pass */
+ struct GPUShader *depth;
+ struct GPUShader *pointcloud_depth;
+ struct GPUShader *depth_conservative;
+ struct GPUShader *pointcloud_depth_conservative;
+} BASIC_Shaders;
+
+static struct {
+ BASIC_Shaders sh_data[GPU_SHADER_CFG_LEN];
+} e_data = {{{NULL}}}; /* Engine data */
+
+static GPUShader *BASIC_shader_create_depth_sh(const GPUShaderConfigData *sh_cfg)
+{
+ return GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_depth_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_depth_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+}
+
+static GPUShader *BASIC_shader_create_pointcloud_depth_sh(const GPUShaderConfigData *sh_cfg)
+{
+ return GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_common_pointcloud_lib_glsl,
+ datatoc_depth_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_depth_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def,
+ "#define POINTCLOUD\n",
+ "#define INSTANCED_ATTR\n",
+ "#define UNIFORM_RESOURCE_ID\n",
+ NULL},
+ });
+}
+
+static GPUShader *BASIC_shader_create_depth_conservative_sh(const GPUShaderConfigData *sh_cfg)
+{
+ return GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_depth_vert_glsl,
+ NULL},
+ .geom = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_conservative_depth_geom_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_depth_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define CONSERVATIVE_RASTER\n", NULL},
+ });
+}
+
+static GPUShader *BASIC_shader_create_pointcloud_depth_conservative_sh(
+ const GPUShaderConfigData *sh_cfg)
+{
+ return GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_common_pointcloud_lib_glsl,
+ datatoc_depth_vert_glsl,
+ NULL},
+ .geom = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_conservative_depth_geom_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_depth_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def,
+ "#define CONSERVATIVE_RASTER\n",
+ "#define POINTCLOUD\n",
+ "#define INSTANCED_ATTR\n",
+ "#define UNIFORM_RESOURCE_ID\n",
+ NULL},
+ });
+}
+
+GPUShader *BASIC_shaders_depth_sh_get(eGPUShaderConfig config)
+{
+ BASIC_Shaders *sh_data = &e_data.sh_data[config];
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[config];
+ if (sh_data->depth == NULL) {
+ sh_data->depth = BASIC_shader_create_depth_sh(sh_cfg);
+ }
+ return sh_data->depth;
+}
+
+GPUShader *BASIC_shaders_pointcloud_depth_sh_get(eGPUShaderConfig config)
+{
+ BASIC_Shaders *sh_data = &e_data.sh_data[config];
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[config];
+ if (sh_data->pointcloud_depth == NULL) {
+ sh_data->pointcloud_depth = BASIC_shader_create_pointcloud_depth_sh(sh_cfg);
+ }
+ return sh_data->pointcloud_depth;
+}
+
+GPUShader *BASIC_shaders_depth_conservative_sh_get(eGPUShaderConfig config)
+{
+ BASIC_Shaders *sh_data = &e_data.sh_data[config];
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[config];
+ if (sh_data->depth_conservative == NULL) {
+ sh_data->depth_conservative = BASIC_shader_create_depth_conservative_sh(sh_cfg);
+ }
+ return sh_data->depth_conservative;
+}
+
+GPUShader *BASIC_shaders_pointcloud_depth_conservative_sh_get(eGPUShaderConfig config)
+{
+ BASIC_Shaders *sh_data = &e_data.sh_data[config];
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[config];
+ if (sh_data->pointcloud_depth_conservative == NULL) {
+ sh_data->pointcloud_depth_conservative = BASIC_shader_create_pointcloud_depth_conservative_sh(
+ sh_cfg);
+ }
+ return sh_data->pointcloud_depth_conservative;
+}
+
+void BASIC_shaders_free(void)
+{
+ for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) {
+ GPUShader **sh_data_as_array = (GPUShader **)&e_data.sh_data[i];
+ for (int j = 0; j < (sizeof(BASIC_Shaders) / sizeof(GPUShader *)); j++) {
+ DRW_SHADER_FREE_SAFE(sh_data_as_array[j]);
+ }
+ }
+}
diff --git a/source/blender/draw/engines/basic/shaders/depth_vert.glsl b/source/blender/draw/engines/basic/shaders/depth_vert.glsl
index 318d0acef6f..be2a7d56d19 100644
--- a/source/blender/draw/engines/basic/shaders/depth_vert.glsl
+++ b/source/blender/draw/engines/basic/shaders/depth_vert.glsl
@@ -3,7 +3,9 @@
RESOURCE_ID_VARYING
#endif
+#ifndef POINTCLOUD
in vec3 pos;
+#endif
void main()
{
@@ -12,7 +14,12 @@ void main()
PASS_RESOURCE_ID
#endif
+#ifdef POINTCLOUD
+ vec3 world_pos = pointcloud_get_pos();
+#else
vec3 world_pos = point_object_to_world(pos);
+#endif
+
gl_Position = point_world_to_ndc(world_pos);
#ifdef USE_WORLD_CLIP_PLANES
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h
index 433ad4fdc61..240eecf9547 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.h
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.h
@@ -18,18 +18,12 @@
/** \file
* \ingroup eevee
- *
- * Contains functions used outside of EEVEE for lightcache baking.
*/
#pragma once
#include "BLI_sys_types.h" /* for bool */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
struct BlendDataReader;
struct BlendWriter;
struct EEVEE_Data;
@@ -39,7 +33,13 @@ struct Scene;
struct SceneEEVEE;
struct ViewLayer;
-/* Light Bake */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Light Bake.
+ */
struct wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm,
struct wmWindow *win,
struct Main *bmain,
@@ -47,6 +47,9 @@ struct wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm,
struct Scene *scene,
int delay,
int frame);
+/**
+ * MUST run on the main thread.
+ */
void *EEVEE_lightbake_job_data_alloc(struct Main *bmain,
struct ViewLayer *view_layer,
struct Scene *scene,
@@ -56,8 +59,21 @@ void EEVEE_lightbake_job_data_free(void *custom_data);
void EEVEE_lightbake_update(void *custom_data);
void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float *progress);
-/* Light Cache */
+/**
+ * This is to update the world irradiance and reflection contribution from
+ * within the viewport drawing (does not have the overhead of a full light cache rebuild.)
+ */
+void EEVEE_lightbake_update_world_quick(struct EEVEE_ViewLayerData *sldata,
+ struct EEVEE_Data *vedata,
+ const Scene *scene);
+
+/**
+ * Light Cache.
+ */
+struct LightCache *EEVEE_lightcache_create(
+ int grid_len, int cube_len, int cube_size, int vis_size, const int irr_size[3]);
void EEVEE_lightcache_free(struct LightCache *lcache);
+bool EEVEE_lightcache_load(struct LightCache *lcache);
void EEVEE_lightcache_info_update(struct SceneEEVEE *eevee);
void EEVEE_lightcache_blend_write(struct BlendWriter *writer, struct LightCache *cache);
diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c
index 4ce76072fce..1d899c3935b 100644
--- a/source/blender/draw/engines/external/external_engine.c
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -88,7 +88,8 @@ typedef struct EXTERNAL_Data {
EXTERNAL_TextureList *txl;
EXTERNAL_PassList *psl;
EXTERNAL_StorageList *stl;
- void *no_instance_data;
+ void *instance_data;
+
char info[GPU_INFO_SIZE];
} EXTERNAL_Data;
@@ -452,7 +453,7 @@ DrawEngineType draw_engine_external_type = {
&external_data_size,
&external_engine_init,
&external_engine_free,
- NULL,
+ NULL, /* instance_free */
&external_cache_init,
&external_cache_populate,
&external_cache_finish,
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
index e3e84dd4c8c..8aba1090b58 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
@@ -59,7 +59,6 @@ static struct GPUTexture *gpencil_image_texture_get(Image *image, bool *r_alpha_
struct GPUTexture *gpu_tex = NULL;
void *lock;
- iuser.ok = true;
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
if (ibuf != NULL && ibuf->rect != NULL) {
@@ -177,11 +176,6 @@ static MaterialGPencilStyle *gpencil_viewport_material_overrides(
return gp_style;
}
-/**
- * Creates a linked list of material pool containing all materials assigned for a given object.
- * We merge the material pools together if object does not contain a huge amount of materials.
- * Also return an offset to the first material of the object in the ubo.
- */
GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs)
{
GPENCIL_MaterialPool *matpool = pd->last_material_pool;
@@ -430,9 +424,6 @@ void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob)
}
}
-/**
- * Creates a single pool containing all lights assigned (light linked) for a given object.
- */
GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_PrivateData *pd, Object *UNUSED(ob))
{
GPENCIL_LightPool *lightpool = pd->last_light_pool;
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index e4204e69e90..9bc340a2786 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -120,15 +120,9 @@ void GPENCIL_engine_init(void *ved)
bool use_scene_world = false;
if (v3d) {
- use_scene_lights = ((v3d->shading.type == OB_MATERIAL) &&
- (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS)) ||
- ((v3d->shading.type == OB_RENDER) &&
- (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS_RENDER));
+ use_scene_lights = V3D_USES_SCENE_LIGHTS(v3d);
- use_scene_world = ((v3d->shading.type == OB_MATERIAL) &&
- (v3d->shading.flag & V3D_SHADING_SCENE_WORLD)) ||
- ((v3d->shading.type == OB_RENDER) &&
- (v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER));
+ use_scene_world = V3D_USES_SCENE_WORLD(v3d);
stl->pd->v3d_color_type = (v3d->shading.type == OB_SOLID) ? v3d->shading.color_type : -1;
/* Special case: If Vertex Paint mode, use always Vertex mode. */
@@ -996,7 +990,7 @@ DrawEngineType draw_engine_gpencil_type = {
&GPENCIL_data_size,
&GPENCIL_engine_init,
&GPENCIL_engine_free,
- NULL,
+ NULL, /* instance_free */
&GPENCIL_cache_init,
&GPENCIL_cache_populate,
&GPENCIL_cache_finish,
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index bac21001537..17a0084689b 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -103,9 +103,9 @@ typedef struct gpLight {
BLI_STATIC_ASSERT_ALIGN(gpMaterial, 16)
BLI_STATIC_ASSERT_ALIGN(gpLight, 16)
-/* *********** Draw Datas *********** */
+/* *********** Draw Data *********** */
typedef struct GPENCIL_MaterialPool {
- /* Linklist. */
+ /* Single linked-list. */
struct GPENCIL_MaterialPool *next;
/* GPU representation of materials. */
gpMaterial mat_data[GP_MATERIAL_BUFFER_LEN];
@@ -145,7 +145,7 @@ typedef struct GPENCIL_ViewLayerData {
/* *********** GPencil *********** */
typedef struct GPENCIL_tVfx {
- /** Linklist */
+ /** Single linked-list. */
struct GPENCIL_tVfx *next;
DRWPass *vfx_ps;
/* Frame-buffer reference since it may not be allocated yet. */
@@ -153,7 +153,7 @@ typedef struct GPENCIL_tVfx {
} GPENCIL_tVfx;
typedef struct GPENCIL_tLayer {
- /** Linklist */
+ /** Single linked-list. */
struct GPENCIL_tLayer *next;
/** Geometry pass (draw all strokes). */
DRWPass *geom_ps;
@@ -169,7 +169,7 @@ typedef struct GPENCIL_tLayer {
} GPENCIL_tLayer;
typedef struct GPENCIL_tObject {
- /** Linklist */
+ /** Single linked-list. */
struct GPENCIL_tObject *next;
struct {
@@ -295,14 +295,14 @@ typedef struct GPENCIL_PrivateData {
/* Current frame */
int cfra;
/* If we are rendering for final render (F12).
- * NOTE: set to false for viewport and opengl rendering (including VSE scene rendering), but set
- * to true when rendering in `OB_RENDER` shading mode (viewport or opengl rendering) */
+ * NOTE: set to false for viewport and opengl rendering (including sequencer scene rendering),
+ * but set to true when rendering in #OB_RENDER shading mode (viewport or opengl rendering). */
bool is_render;
/* If we are in viewport display (used for VFX). */
bool is_viewport;
/* True in selection and auto_depth drawing */
bool draw_depth_only;
- /* Is shading set to wireframe. */
+ /* Is shading set to wire-frame. */
bool draw_wireframe;
/* Used by the depth merge step. */
int is_stroke_order_3d;
@@ -389,6 +389,11 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
GPENCIL_tObject *tgp_ob);
GPENCIL_tLayer *gpencil_layer_cache_get(GPENCIL_tObject *tgp_ob, int number);
+/**
+ * Creates a linked list of material pool containing all materials assigned for a given object.
+ * We merge the material pools together if object does not contain a huge amount of materials.
+ * Also return an offset to the first material of the object in the UBO.
+ */
GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs);
void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool,
int mat_id,
@@ -399,6 +404,9 @@ void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool,
void gpencil_light_ambient_add(GPENCIL_LightPool *lightpool, const float color[3]);
void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob);
GPENCIL_LightPool *gpencil_light_pool_add(GPENCIL_PrivateData *pd);
+/**
+ * Creates a single pool containing all lights assigned (light linked) for a given object.
+ */
GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_PrivateData *pd, Object *ob);
/* effects */
@@ -433,6 +441,10 @@ void GPENCIL_cache_finish(void *vedata);
void GPENCIL_draw_scene(void *vedata);
/* render */
+
+/**
+ * Initialize render data.
+ */
void GPENCIL_render_init(struct GPENCIL_Data *ved,
struct RenderEngine *engine,
struct RenderLayer *render_layer,
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index b597a786e86..26a14c433b3 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -33,7 +33,6 @@
#include "gpencil_engine.h"
-/* init render data */
void GPENCIL_render_init(GPENCIL_Data *vedata,
RenderEngine *engine,
struct RenderLayer *render_layer,
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
index 315133186da..dfff45cbca5 100644
--- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
+++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
@@ -99,6 +99,11 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it
return;
}
+ if ((fx->flag & FX_BLUR_DOF_MODE) && iter->pd->camera == NULL) {
+ /* No blur outside camera view (or when DOF is disabled on the camera). */
+ return;
+ }
+
DRWShadingGroup *grp;
const float s = sin(fx->rotation);
const float c = cos(fx->rotation);
@@ -108,7 +113,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it
DRW_view_persmat_get(NULL, persmat, false);
const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3]));
- if ((fx->flag & FX_BLUR_DOF_MODE) && iter->pd->camera != NULL) {
+ if ((fx->flag & FX_BLUR_DOF_MODE)) {
/* Compute circle of confusion size. */
float coc = (iter->pd->dof_params[0] / -w) - iter->pd->dof_params[1];
copy_v2_fl(blur_size, fabsf(coc));
diff --git a/source/blender/draw/engines/image/image_drawing_mode_image_space.hh b/source/blender/draw/engines/image/image_drawing_mode_image_space.hh
new file mode 100644
index 00000000000..26f4bc28106
--- /dev/null
+++ b/source/blender/draw/engines/image/image_drawing_mode_image_space.hh
@@ -0,0 +1,147 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#pragma once
+
+#include "image_private.hh"
+
+namespace blender::draw::image_engine {
+
+class ImageSpaceDrawingMode : public AbstractDrawingMode {
+ private:
+ DRWPass *create_image_pass() const
+ {
+ /* Write depth is needed for background overlay rendering. Near depth is used for
+ * transparency checker and Far depth is used for indicating the image size. */
+ DRWState state = static_cast<DRWState>(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
+ DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA_PREMUL);
+ return DRW_pass_create("Image", state);
+ }
+
+ void add_to_shgroup(AbstractSpaceAccessor *space,
+ DRWShadingGroup *grp,
+ const Image *image,
+ const ImBuf *image_buffer) const
+ {
+ float image_mat[4][4];
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const ARegion *region = draw_ctx->region;
+ space->get_image_mat(image_buffer, region, image_mat);
+
+ GPUBatch *geom = DRW_cache_quad_get();
+
+ const float translate_x = image_mat[3][0];
+ const float translate_y = image_mat[3][1];
+ LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
+ const int tile_x = ((tile->tile_number - 1001) % 10);
+ const int tile_y = ((tile->tile_number - 1001) / 10);
+ image_mat[3][0] = (float)tile_x + translate_x;
+ image_mat[3][1] = (float)tile_y + translate_y;
+ DRW_shgroup_call_obmat(grp, geom, image_mat);
+ }
+ }
+
+ public:
+ void cache_init(IMAGE_Data *vedata) const override
+ {
+ IMAGE_PassList *psl = vedata->psl;
+
+ psl->image_pass = create_image_pass();
+ }
+
+ void cache_image(AbstractSpaceAccessor *space,
+ IMAGE_Data *vedata,
+ Image *image,
+ ImageUser *iuser,
+ ImBuf *image_buffer) const override
+ {
+ IMAGE_PassList *psl = vedata->psl;
+ IMAGE_StorageList *stl = vedata->stl;
+ IMAGE_PrivateData *pd = stl->pd;
+
+ GPUTexture *tex_tile_data = nullptr;
+ space->get_gpu_textures(
+ image, iuser, image_buffer, &pd->texture, &pd->owns_texture, &tex_tile_data);
+ if (pd->texture == nullptr) {
+ return;
+ }
+ const bool is_tiled_texture = tex_tile_data != nullptr;
+
+ ShaderParameters sh_params;
+ sh_params.use_premul_alpha = BKE_image_has_gpu_texture_premultiplied_alpha(image,
+ image_buffer);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+ if (scene->camera && scene->camera->type == OB_CAMERA) {
+ Camera *camera = static_cast<Camera *>(scene->camera->data);
+ copy_v2_fl2(sh_params.far_near, camera->clip_end, camera->clip_start);
+ }
+ space->get_shader_parameters(sh_params, image_buffer, is_tiled_texture);
+
+ GPUShader *shader = IMAGE_shader_image_get(is_tiled_texture);
+ DRWShadingGroup *shgrp = DRW_shgroup_create(shader, psl->image_pass);
+ if (is_tiled_texture) {
+ DRW_shgroup_uniform_texture_ex(shgrp, "imageTileArray", pd->texture, GPU_SAMPLER_DEFAULT);
+ DRW_shgroup_uniform_texture(shgrp, "imageTileData", tex_tile_data);
+ }
+ else {
+ DRW_shgroup_uniform_texture_ex(shgrp, "imageTexture", pd->texture, GPU_SAMPLER_DEFAULT);
+ }
+ DRW_shgroup_uniform_vec2_copy(shgrp, "farNearDistances", sh_params.far_near);
+ DRW_shgroup_uniform_vec4_copy(shgrp, "color", ShaderParameters::color);
+ DRW_shgroup_uniform_vec4_copy(shgrp, "shuffle", sh_params.shuffle);
+ DRW_shgroup_uniform_int_copy(shgrp, "drawFlags", sh_params.flags);
+ DRW_shgroup_uniform_bool_copy(shgrp, "imgPremultiplied", sh_params.use_premul_alpha);
+
+ add_to_shgroup(space, shgrp, image, image_buffer);
+ }
+
+ void draw_finish(IMAGE_Data *vedata) const override
+ {
+ IMAGE_StorageList *stl = vedata->stl;
+ IMAGE_PrivateData *pd = stl->pd;
+
+ if (pd->texture && pd->owns_texture) {
+ GPU_texture_free(pd->texture);
+ pd->owns_texture = false;
+ }
+ pd->texture = nullptr;
+ }
+
+ void draw_scene(IMAGE_Data *vedata) const override
+ {
+ IMAGE_PassList *psl = vedata->psl;
+ IMAGE_PrivateData *pd = vedata->stl->pd;
+
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ GPU_framebuffer_bind(dfbl->default_fb);
+ static float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ GPU_framebuffer_clear_color_depth(dfbl->default_fb, clear_col, 1.0);
+
+ DRW_view_set_active(pd->view);
+ DRW_draw_pass(psl->image_pass);
+ DRW_view_set_active(nullptr);
+ }
+};
+
+} // namespace blender::draw::image_engine
diff --git a/source/blender/draw/engines/image/image_engine.c b/source/blender/draw/engines/image/image_engine.c
deleted file mode 100644
index d0c21489c9e..00000000000
--- a/source/blender/draw/engines/image/image_engine.c
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2020, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_editors
- *
- * Draw engine to draw the Image/UV editor
- */
-
-#include "DRW_render.h"
-
-#include "BKE_image.h"
-#include "BKE_main.h"
-#include "BKE_object.h"
-
-#include "DNA_camera_types.h"
-#include "DNA_screen_types.h"
-
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-
-#include "ED_image.h"
-
-#include "GPU_batch.h"
-
-#include "image_engine.h"
-#include "image_private.h"
-
-#define IMAGE_DRAW_FLAG_SHOW_ALPHA (1 << 0)
-#define IMAGE_DRAW_FLAG_APPLY_ALPHA (1 << 1)
-#define IMAGE_DRAW_FLAG_SHUFFLING (1 << 2)
-#define IMAGE_DRAW_FLAG_DEPTH (1 << 3)
-#define IMAGE_DRAW_FLAG_DO_REPEAT (1 << 4)
-#define IMAGE_DRAW_FLAG_USE_WORLD_POS (1 << 5)
-
-static void image_cache_image_add(DRWShadingGroup *grp, Image *image, ImBuf *ibuf)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const ARegion *region = draw_ctx->region;
- const char space_type = draw_ctx->space_data->spacetype;
-
- float zoom_x = 1.0f;
- float zoom_y = 1.0f;
- float translate_x = 0.0f;
- float translate_y = 0.0f;
-
- /* User can freely move the backdrop in the space of the node editor */
- if (space_type == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)draw_ctx->space_data;
- const float ibuf_width = ibuf->x;
- const float ibuf_height = ibuf->y;
- const float x = (region->winx - snode->zoom * ibuf_width) / 2 + snode->xof;
- const float y = (region->winy - snode->zoom * ibuf_height) / 2 + snode->yof;
-
- zoom_x = ibuf_width * snode->zoom;
- zoom_y = ibuf_height * snode->zoom;
- translate_x = x;
- translate_y = y;
- }
-
- const bool is_tiled_texture = image && image->source == IMA_SRC_TILED;
- float obmat[4][4];
- unit_m4(obmat);
-
- GPUBatch *geom = DRW_cache_quad_get();
-
- obmat[0][0] = zoom_x;
- obmat[1][1] = zoom_y;
- obmat[3][1] = translate_y;
- obmat[3][0] = translate_x;
-
- if (is_tiled_texture) {
- LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
- const int tile_x = ((tile->tile_number - 1001) % 10);
- const int tile_y = ((tile->tile_number - 1001) / 10);
- obmat[3][1] = (float)tile_y + translate_y;
- obmat[3][0] = (float)tile_x + translate_x;
- DRW_shgroup_call_obmat(grp, geom, obmat);
- }
- }
- else {
- DRW_shgroup_call_obmat(grp, geom, obmat);
- }
-}
-
-static void space_image_gpu_texture_get(Image *image,
- ImageUser *iuser,
- ImBuf *ibuf,
- GPUTexture **r_gpu_texture,
- bool *r_owns_texture,
- GPUTexture **r_tex_tile_data)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- SpaceImage *sima = (SpaceImage *)draw_ctx->space_data;
- if (BKE_image_is_multilayer(image)) {
- /* Update multi-index and pass for the current eye. */
- BKE_image_multilayer_index(image->rr, &sima->iuser);
- }
- else {
- BKE_image_multiview_index(image, &sima->iuser);
- }
-
- if (ibuf == NULL) {
- return;
- }
-
- if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
- /* This code-path is only supposed to happen when drawing a lazily-allocatable render result.
- * In all the other cases the `ED_space_image_acquire_buffer()` is expected to return NULL as
- * an image buffer when it has no pixels. */
-
- BLI_assert(image->type == IMA_TYPE_R_RESULT);
-
- float zero[4] = {0, 0, 0, 0};
- *r_gpu_texture = GPU_texture_create_2d(__func__, 1, 1, 0, GPU_RGBA16F, zero);
- *r_owns_texture = true;
- return;
- }
-
- const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(ibuf);
- if (sima_flag & SI_SHOW_ZBUF && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels == 1))) {
- if (ibuf->zbuf) {
- BLI_assert_msg(0, "Integer based depth buffers not supported");
- }
- else if (ibuf->zbuf_float) {
- *r_gpu_texture = GPU_texture_create_2d(
- __func__, ibuf->x, ibuf->y, 0, GPU_R16F, ibuf->zbuf_float);
- *r_owns_texture = true;
- }
- else if (ibuf->rect_float && ibuf->channels == 1) {
- *r_gpu_texture = GPU_texture_create_2d(
- __func__, ibuf->x, ibuf->y, 0, GPU_R16F, ibuf->rect_float);
- *r_owns_texture = true;
- }
- }
- else if (image->source == IMA_SRC_TILED) {
- *r_gpu_texture = BKE_image_get_gpu_tiles(image, iuser, ibuf);
- *r_tex_tile_data = BKE_image_get_gpu_tilemap(image, iuser, NULL);
- *r_owns_texture = false;
- }
- else {
- *r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, ibuf);
- *r_owns_texture = false;
- }
-}
-
-static void space_node_gpu_texture_get(Image *image,
- ImageUser *iuser,
- ImBuf *ibuf,
- GPUTexture **r_gpu_texture,
- bool *r_owns_texture,
- GPUTexture **r_tex_tile_data)
-{
- *r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, ibuf);
- *r_owns_texture = false;
- *r_tex_tile_data = NULL;
-}
-
-static void image_gpu_texture_get(Image *image,
- ImageUser *iuser,
- ImBuf *ibuf,
- GPUTexture **r_gpu_texture,
- bool *r_owns_texture,
- GPUTexture **r_tex_tile_data)
-{
- if (!image) {
- return;
- }
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const char space_type = draw_ctx->space_data->spacetype;
-
- if (space_type == SPACE_IMAGE) {
- space_image_gpu_texture_get(
- image, iuser, ibuf, r_gpu_texture, r_owns_texture, r_tex_tile_data);
- }
- else if (space_type == SPACE_NODE) {
- space_node_gpu_texture_get(image, iuser, ibuf, r_gpu_texture, r_owns_texture, r_tex_tile_data);
- }
-}
-
-static void image_cache_image(IMAGE_Data *vedata, Image *image, ImageUser *iuser, ImBuf *ibuf)
-{
- IMAGE_PassList *psl = vedata->psl;
- IMAGE_StorageList *stl = vedata->stl;
- IMAGE_PrivateData *pd = stl->pd;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const char space_type = draw_ctx->space_data->spacetype;
- const Scene *scene = draw_ctx->scene;
-
- GPUTexture *tex_tile_data = NULL;
- image_gpu_texture_get(image, iuser, ibuf, &pd->texture, &pd->owns_texture, &tex_tile_data);
-
- if (pd->texture) {
- static float color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- static float shuffle[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- static float far_near[2] = {100.0f, 0.0f};
-
- if (scene->camera && scene->camera->type == OB_CAMERA) {
- far_near[1] = ((Camera *)scene->camera->data)->clip_start;
- far_near[0] = ((Camera *)scene->camera->data)->clip_end;
- }
-
- const bool use_premul_alpha = BKE_image_has_gpu_texture_premultiplied_alpha(image, ibuf);
- const bool is_tiled_texture = tex_tile_data != NULL;
-
- int draw_flags = 0;
- if (space_type == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)draw_ctx->space_data;
- const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(ibuf);
- const bool do_repeat = (!is_tiled_texture) && ((sima->flag & SI_DRAW_TILE) != 0);
- SET_FLAG_FROM_TEST(draw_flags, do_repeat, IMAGE_DRAW_FLAG_DO_REPEAT);
- SET_FLAG_FROM_TEST(draw_flags, is_tiled_texture, IMAGE_DRAW_FLAG_USE_WORLD_POS);
- if ((sima_flag & SI_USE_ALPHA) != 0) {
- /* Show RGBA */
- draw_flags |= IMAGE_DRAW_FLAG_SHOW_ALPHA | IMAGE_DRAW_FLAG_APPLY_ALPHA;
- }
- else if ((sima_flag & SI_SHOW_ALPHA) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
- copy_v4_fl4(shuffle, 0.0f, 0.0f, 0.0f, 1.0f);
- }
- else if ((sima_flag & SI_SHOW_ZBUF) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_DEPTH | IMAGE_DRAW_FLAG_SHUFFLING;
- copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f);
- }
- else if ((sima_flag & SI_SHOW_R) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
- if (IMB_alpha_affects_rgb(ibuf)) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
- }
- copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f);
- }
- else if ((sima_flag & SI_SHOW_G) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
- if (IMB_alpha_affects_rgb(ibuf)) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
- }
- copy_v4_fl4(shuffle, 0.0f, 1.0f, 0.0f, 0.0f);
- }
- else if ((sima_flag & SI_SHOW_B) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
- if (IMB_alpha_affects_rgb(ibuf)) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
- }
- copy_v4_fl4(shuffle, 0.0f, 0.0f, 1.0f, 0.0f);
- }
- else /* RGB */ {
- if (IMB_alpha_affects_rgb(ibuf)) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
- }
- }
- }
- if (space_type == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)draw_ctx->space_data;
- if ((snode->flag & SNODE_USE_ALPHA) != 0) {
- /* Show RGBA */
- draw_flags |= IMAGE_DRAW_FLAG_SHOW_ALPHA | IMAGE_DRAW_FLAG_APPLY_ALPHA;
- }
- else if ((snode->flag & SNODE_SHOW_ALPHA) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
- copy_v4_fl4(shuffle, 0.0f, 0.0f, 0.0f, 1.0f);
- }
- else if ((snode->flag & SNODE_SHOW_R) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
- if (IMB_alpha_affects_rgb(ibuf)) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
- }
- copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f);
- }
- else if ((snode->flag & SNODE_SHOW_G) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
- if (IMB_alpha_affects_rgb(ibuf)) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
- }
- copy_v4_fl4(shuffle, 0.0f, 1.0f, 0.0f, 0.0f);
- }
- else if ((snode->flag & SNODE_SHOW_B) != 0) {
- draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING;
- if (IMB_alpha_affects_rgb(ibuf)) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
- }
- copy_v4_fl4(shuffle, 0.0f, 0.0f, 1.0f, 0.0f);
- }
- else /* RGB */ {
- if (IMB_alpha_affects_rgb(ibuf)) {
- draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
- }
- }
- }
-
- GPUShader *shader = IMAGE_shader_image_get(is_tiled_texture);
- DRWShadingGroup *shgrp = DRW_shgroup_create(shader, psl->image_pass);
- if (is_tiled_texture) {
- DRW_shgroup_uniform_texture_ex(shgrp, "imageTileArray", pd->texture, 0);
- DRW_shgroup_uniform_texture(shgrp, "imageTileData", tex_tile_data);
- }
- else {
- DRW_shgroup_uniform_texture_ex(shgrp, "imageTexture", pd->texture, 0);
- }
- DRW_shgroup_uniform_vec2_copy(shgrp, "farNearDistances", far_near);
- DRW_shgroup_uniform_vec4_copy(shgrp, "color", color);
- DRW_shgroup_uniform_vec4_copy(shgrp, "shuffle", shuffle);
- DRW_shgroup_uniform_int_copy(shgrp, "drawFlags", draw_flags);
- DRW_shgroup_uniform_bool_copy(shgrp, "imgPremultiplied", use_premul_alpha);
- image_cache_image_add(shgrp, image, ibuf);
- }
-}
-
-/* -------------------------------------------------------------------- */
-/** \name Engine Callbacks
- * \{ */
-
-static void IMAGE_engine_init(void *ved)
-{
- IMAGE_shader_library_ensure();
- IMAGE_Data *vedata = (IMAGE_Data *)ved;
- IMAGE_StorageList *stl = vedata->stl;
- if (!stl->pd) {
- stl->pd = MEM_callocN(sizeof(IMAGE_PrivateData), __func__);
- }
- IMAGE_PrivateData *pd = stl->pd;
-
- pd->ibuf = NULL;
- pd->lock = NULL;
- pd->texture = NULL;
-}
-
-static void IMAGE_cache_init(void *ved)
-{
- IMAGE_Data *vedata = (IMAGE_Data *)ved;
- IMAGE_StorageList *stl = vedata->stl;
- IMAGE_PrivateData *pd = stl->pd;
- IMAGE_PassList *psl = vedata->psl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- {
- /* Write depth is needed for background overlay rendering. Near depth is used for
- * transparency checker and Far depth is used for indicating the image size. */
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS |
- DRW_STATE_BLEND_ALPHA_PREMUL;
- psl->image_pass = DRW_pass_create("Image", state);
- }
-
- const SpaceLink *space_link = draw_ctx->space_data;
- const char space_type = space_link->spacetype;
- pd->view = NULL;
- if (space_type == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)draw_ctx->space_data;
- Image *image = ED_space_image(sima);
- ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &pd->lock, 0);
- image_cache_image(vedata, image, &sima->iuser, ibuf);
- pd->image = image;
- pd->ibuf = ibuf;
- }
- else if (space_type == SPACE_NODE) {
- ARegion *region = draw_ctx->region;
- Main *bmain = CTX_data_main(draw_ctx->evil_C);
- Image *image = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, &pd->lock);
- {
- /* Setup a screen pixel view. The backdrop of the node editor doesn't follow the region. */
- float winmat[4][4], viewmat[4][4];
- orthographic_m4(viewmat, 0.0, region->winx, 0.0, region->winy, 0.0, 1.0);
- unit_m4(winmat);
- pd->view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL);
- }
- image_cache_image(vedata, image, NULL, ibuf);
- pd->image = image;
- pd->ibuf = ibuf;
- }
-}
-
-static void IMAGE_cache_populate(void *UNUSED(vedata), Object *UNUSED(ob))
-{
- /* Function intentional left empty. `cache_populate` is required to be implemented. */
-}
-
-static void image_draw_finish(IMAGE_Data *ved)
-{
- IMAGE_Data *vedata = (IMAGE_Data *)ved;
- IMAGE_StorageList *stl = vedata->stl;
- IMAGE_PrivateData *pd = stl->pd;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const char space_type = draw_ctx->space_data->spacetype;
- if (space_type == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)draw_ctx->space_data;
- ED_space_image_release_buffer(sima, pd->ibuf, pd->lock);
- }
- else if (space_type == SPACE_NODE) {
- BKE_image_release_ibuf(pd->image, pd->ibuf, pd->lock);
- }
- pd->image = NULL;
- pd->ibuf = NULL;
-
- if (pd->texture && pd->owns_texture) {
- GPU_texture_free(pd->texture);
- pd->owns_texture = false;
- }
- pd->texture = NULL;
-}
-
-static void IMAGE_draw_scene(void *ved)
-{
- IMAGE_Data *vedata = (IMAGE_Data *)ved;
- IMAGE_PassList *psl = vedata->psl;
- IMAGE_PrivateData *pd = vedata->stl->pd;
-
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- GPU_framebuffer_bind(dfbl->default_fb);
- static float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- GPU_framebuffer_clear_color_depth(dfbl->default_fb, clear_col, 1.0);
-
- DRW_view_set_active(pd->view);
- DRW_draw_pass(psl->image_pass);
- DRW_view_set_active(NULL);
- image_draw_finish(vedata);
-}
-
-static void IMAGE_engine_free(void)
-{
- IMAGE_shader_free();
-}
-
-/** \} */
-
-static const DrawEngineDataSize IMAGE_data_size = DRW_VIEWPORT_DATA_SIZE(IMAGE_Data);
-
-DrawEngineType draw_engine_image_type = {
- NULL, /* next */
- NULL, /* prev */
- N_("UV/Image"), /* idname */
- &IMAGE_data_size, /* vedata_size */
- &IMAGE_engine_init, /* engine_init */
- &IMAGE_engine_free, /* engine_free */
- NULL,
- &IMAGE_cache_init, /* cache_init */
- &IMAGE_cache_populate, /* cache_populate */
- NULL, /* cache_finish */
- &IMAGE_draw_scene, /* draw_scene */
- NULL, /* view_update */
- NULL, /* id_update */
- NULL, /* render_to_image */
- NULL, /* store_metadata */
-};
diff --git a/source/blender/draw/engines/image/image_engine.cc b/source/blender/draw/engines/image/image_engine.cc
new file mode 100644
index 00000000000..be5946f34eb
--- /dev/null
+++ b/source/blender/draw/engines/image/image_engine.cc
@@ -0,0 +1,204 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Draw engine to draw the Image/UV editor
+ */
+
+#include "DRW_render.h"
+
+#include <memory>
+#include <optional>
+
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_screen_types.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "ED_image.h"
+
+#include "GPU_batch.h"
+
+#include "image_drawing_mode_image_space.hh"
+#include "image_engine.h"
+#include "image_private.hh"
+#include "image_space_image.hh"
+#include "image_space_node.hh"
+
+namespace blender::draw::image_engine {
+
+static std::unique_ptr<AbstractSpaceAccessor> space_accessor_from_context(
+ const DRWContextState *draw_ctx)
+{
+ const char space_type = draw_ctx->space_data->spacetype;
+ if (space_type == SPACE_IMAGE) {
+ return std::make_unique<SpaceImageAccessor>((SpaceImage *)draw_ctx->space_data);
+ }
+ if (space_type == SPACE_NODE) {
+ return std::make_unique<SpaceNodeAccessor>((SpaceNode *)draw_ctx->space_data);
+ }
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+template<
+ /** \brief Drawing mode to use.
+ *
+ * Useful during development to switch between drawing implementations.
+ */
+ typename DrawingMode = ImageSpaceDrawingMode>
+class ImageEngine {
+ private:
+ const DRWContextState *draw_ctx;
+ IMAGE_Data *vedata;
+ std::unique_ptr<AbstractSpaceAccessor> space;
+ DrawingMode drawing_mode;
+
+ public:
+ ImageEngine(const DRWContextState *draw_ctx, IMAGE_Data *vedata)
+ : draw_ctx(draw_ctx), vedata(vedata), space(space_accessor_from_context(draw_ctx))
+ {
+ }
+
+ virtual ~ImageEngine() = default;
+
+ void cache_init()
+ {
+ IMAGE_StorageList *stl = vedata->stl;
+ IMAGE_PrivateData *pd = stl->pd;
+
+ drawing_mode.cache_init(vedata);
+ pd->view = nullptr;
+ if (space->has_view_override()) {
+ const ARegion *region = draw_ctx->region;
+ pd->view = space->create_view_override(region);
+ }
+ }
+
+ void cache_populate()
+ {
+ IMAGE_StorageList *stl = vedata->stl;
+ IMAGE_PrivateData *pd = stl->pd;
+ Main *bmain = CTX_data_main(draw_ctx->evil_C);
+ pd->image = space->get_image(bmain);
+ if (pd->image == nullptr) {
+ /* Early exit, nothing to draw. */
+ return;
+ }
+ pd->ibuf = space->acquire_image_buffer(pd->image, &pd->lock);
+ ImageUser *iuser = space->get_image_user();
+ drawing_mode.cache_image(space.get(), vedata, pd->image, iuser, pd->ibuf);
+ }
+
+ void draw_finish()
+ {
+ drawing_mode.draw_finish(vedata);
+
+ IMAGE_StorageList *stl = vedata->stl;
+ IMAGE_PrivateData *pd = stl->pd;
+ space->release_buffer(pd->image, pd->ibuf, pd->lock);
+ pd->image = nullptr;
+ pd->ibuf = nullptr;
+ }
+
+ void draw_scene()
+ {
+ drawing_mode.draw_scene(vedata);
+ }
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Engine Callbacks
+ * \{ */
+
+static void IMAGE_engine_init(void *ved)
+{
+ IMAGE_shader_library_ensure();
+ IMAGE_Data *vedata = (IMAGE_Data *)ved;
+ IMAGE_StorageList *stl = vedata->stl;
+ if (!stl->pd) {
+ stl->pd = static_cast<IMAGE_PrivateData *>(MEM_callocN(sizeof(IMAGE_PrivateData), __func__));
+ }
+ IMAGE_PrivateData *pd = stl->pd;
+
+ pd->ibuf = nullptr;
+ pd->lock = nullptr;
+ pd->texture = nullptr;
+}
+
+static void IMAGE_cache_init(void *vedata)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ImageEngine image_engine(draw_ctx, static_cast<IMAGE_Data *>(vedata));
+ image_engine.cache_init();
+ image_engine.cache_populate();
+}
+
+static void IMAGE_cache_populate(void *UNUSED(vedata), Object *UNUSED(ob))
+{
+ /* Function intentional left empty. `cache_populate` is required to be implemented. */
+}
+
+static void IMAGE_draw_scene(void *vedata)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ImageEngine image_engine(draw_ctx, static_cast<IMAGE_Data *>(vedata));
+ image_engine.draw_scene();
+ image_engine.draw_finish();
+}
+
+static void IMAGE_engine_free()
+{
+ IMAGE_shader_free();
+}
+
+/** \} */
+
+static const DrawEngineDataSize IMAGE_data_size = DRW_VIEWPORT_DATA_SIZE(IMAGE_Data);
+
+} // namespace blender::draw::image_engine
+
+extern "C" {
+
+using namespace blender::draw::image_engine;
+
+DrawEngineType draw_engine_image_type = {
+ nullptr, /* next */
+ nullptr, /* prev */
+ N_("UV/Image"), /* idname */
+ &IMAGE_data_size, /* vedata_size */
+ &IMAGE_engine_init, /* engine_init */
+ &IMAGE_engine_free, /* engine_free */
+ nullptr, /* instance_free */
+ &IMAGE_cache_init, /* cache_init */
+ &IMAGE_cache_populate, /* cache_populate */
+ nullptr, /* cache_finish */
+ &IMAGE_draw_scene, /* draw_scene */
+ nullptr, /* view_update */
+ nullptr, /* id_update */
+ nullptr, /* render_to_image */
+ nullptr, /* store_metadata */
+};
+}
diff --git a/source/blender/draw/engines/image/image_engine.h b/source/blender/draw/engines/image/image_engine.h
index 0098d863ef9..f7e2f53d41b 100644
--- a/source/blender/draw/engines/image/image_engine.h
+++ b/source/blender/draw/engines/image/image_engine.h
@@ -17,9 +17,17 @@
*/
/** \file
- * \ingroup draw_editors
+ * \ingroup draw_engine
*/
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern DrawEngineType draw_engine_image_type;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/engines/image/image_private.h b/source/blender/draw/engines/image/image_private.h
deleted file mode 100644
index 76a94e68da1..00000000000
--- a/source/blender/draw/engines/image/image_private.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2020, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Forward declarations */
-struct GPUTexture;
-struct ImBuf;
-struct Image;
-
-/* *********** LISTS *********** */
-
-/* GPUViewport.storage
- * Is freed every time the viewport engine changes. */
-typedef struct IMAGE_PassList {
- DRWPass *image_pass;
-} IMAGE_PassList;
-
-typedef struct IMAGE_PrivateData {
- void *lock;
- struct ImBuf *ibuf;
- struct Image *image;
- struct DRWView *view;
-
- struct GPUTexture *texture;
- bool owns_texture;
-} IMAGE_PrivateData;
-
-typedef struct IMAGE_StorageList {
- IMAGE_PrivateData *pd;
-} IMAGE_StorageList;
-
-typedef struct IMAGE_Data {
- void *engine_type;
- DRWViewportEmptyList *fbl;
- DRWViewportEmptyList *txl;
- IMAGE_PassList *psl;
- IMAGE_StorageList *stl;
-} IMAGE_Data;
-
-/* image_shader.c */
-GPUShader *IMAGE_shader_image_get(bool is_tiled_image);
-void IMAGE_shader_library_ensure(void);
-void IMAGE_shader_free(void);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/draw/engines/image/image_private.hh b/source/blender/draw/engines/image/image_private.hh
new file mode 100644
index 00000000000..fc3ce72d0aa
--- /dev/null
+++ b/source/blender/draw/engines/image/image_private.hh
@@ -0,0 +1,196 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#pragma once
+
+#include <optional>
+
+/* Forward declarations */
+extern "C" {
+struct GPUTexture;
+struct ImBuf;
+struct Image;
+}
+
+/* *********** LISTS *********** */
+
+namespace blender::draw::image_engine {
+
+/* GPUViewport.storage
+ * Is freed every time the viewport engine changes. */
+struct IMAGE_PassList {
+ DRWPass *image_pass;
+};
+
+struct IMAGE_PrivateData {
+ void *lock;
+ struct ImBuf *ibuf;
+ struct Image *image;
+ struct DRWView *view;
+
+ struct GPUTexture *texture;
+ bool owns_texture;
+};
+
+struct IMAGE_StorageList {
+ IMAGE_PrivateData *pd;
+};
+
+struct IMAGE_Data {
+ void *engine_type;
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ IMAGE_PassList *psl;
+ IMAGE_StorageList *stl;
+};
+
+/* Shader parameters. */
+#define IMAGE_DRAW_FLAG_SHOW_ALPHA (1 << 0)
+#define IMAGE_DRAW_FLAG_APPLY_ALPHA (1 << 1)
+#define IMAGE_DRAW_FLAG_SHUFFLING (1 << 2)
+#define IMAGE_DRAW_FLAG_DEPTH (1 << 3)
+#define IMAGE_DRAW_FLAG_DO_REPEAT (1 << 4)
+#define IMAGE_DRAW_FLAG_USE_WORLD_POS (1 << 5)
+
+struct ShaderParameters {
+ constexpr static float color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ int flags = 0;
+ float shuffle[4];
+ float far_near[2];
+ bool use_premul_alpha = false;
+
+ ShaderParameters()
+ {
+ copy_v4_fl(shuffle, 1.0f);
+ copy_v2_fl2(far_near, 100.0f, 0.0f);
+ }
+};
+
+/**
+ * Space accessor.
+ *
+ * Image engine is used to draw the images inside multiple spaces \see SpaceLink.
+ * The AbstractSpaceAccessor is an interface to communicate with a space.
+ */
+class AbstractSpaceAccessor {
+ public:
+ virtual ~AbstractSpaceAccessor() = default;
+
+ /**
+ * Return the active image of the space.
+ *
+ * The returned image will be drawn in the space.
+ *
+ * The return value is optional.
+ */
+ virtual Image *get_image(Main *bmain) = 0;
+
+ /**
+ * Return the #ImageUser of the space.
+ *
+ * The return value is optional.
+ */
+ virtual ImageUser *get_image_user() = 0;
+
+ /**
+ * Acquire the image buffer of the image.
+ *
+ * \param image: Image to get the buffer from. Image is the same as returned from the #get_image
+ * member.
+ * \param lock: pointer to a lock object.
+ * \return Image buffer of the given image.
+ */
+ virtual ImBuf *acquire_image_buffer(Image *image, void **lock) = 0;
+
+ /**
+ * Release a previous locked image from #acquire_image_buffer.
+ */
+ virtual void release_buffer(Image *image, ImBuf *image_buffer, void *lock) = 0;
+
+ /**
+ * Update the r_shader_parameters with space specific settings.
+ *
+ * Only update the #ShaderParameters.flags and #ShaderParameters.shuffle. Other parameters
+ * are updated inside the image engine.
+ */
+ virtual void get_shader_parameters(ShaderParameters &r_shader_parameters,
+ ImBuf *image_buffer,
+ bool is_tiled) = 0;
+
+ /**
+ * Retrieve the gpu textures to draw.
+ */
+ virtual void get_gpu_textures(Image *image,
+ ImageUser *iuser,
+ ImBuf *image_buffer,
+ GPUTexture **r_gpu_texture,
+ bool *r_owns_texture,
+ GPUTexture **r_tex_tile_data) = 0;
+
+ /**
+ * Does this space override the view.
+ * When so this member should return true and the create_view_override must return the view to
+ * use during drawing.
+ */
+ virtual bool has_view_override() const = 0;
+
+ /**
+ * Override the view for drawing.
+ * Should match #has_view_override.
+ */
+ virtual DRWView *create_view_override(const ARegion *UNUSED(region)) = 0;
+
+ /**
+ * Initialize the matrix that will be used to draw the image. The matrix will be send as object
+ * matrix to the drawing pipeline.
+ */
+ virtual void get_image_mat(const ImBuf *image_buffer,
+ const ARegion *region,
+ float r_mat[4][4]) const = 0;
+}; // namespace blender::draw::image_engine
+
+/**
+ * Abstract class for a drawing mode of the image engine.
+ *
+ * The drawing mode decides how to draw the image on the screen. Each way how to draw would have
+ * its own subclass. For now there is only a single drawing mode. #DefaultDrawingMode.
+ **/
+class AbstractDrawingMode {
+ public:
+ virtual ~AbstractDrawingMode() = default;
+ virtual void cache_init(IMAGE_Data *vedata) const = 0;
+ virtual void cache_image(AbstractSpaceAccessor *space,
+ IMAGE_Data *vedata,
+ Image *image,
+ ImageUser *iuser,
+ ImBuf *image_buffer) const = 0;
+ virtual void draw_scene(IMAGE_Data *vedata) const = 0;
+ virtual void draw_finish(IMAGE_Data *vedata) const = 0;
+};
+
+/* image_shader.c */
+GPUShader *IMAGE_shader_image_get(bool is_tiled_image);
+void IMAGE_shader_library_ensure();
+void IMAGE_shader_free();
+
+} // namespace blender::draw::image_engine
diff --git a/source/blender/draw/engines/image/image_shader.c b/source/blender/draw/engines/image/image_shader.cc
index 691c0d7029a..1c6abf36505 100644
--- a/source/blender/draw/engines/image/image_shader.c
+++ b/source/blender/draw/engines/image/image_shader.cc
@@ -27,27 +27,31 @@
#include "GPU_batch.h"
#include "image_engine.h"
-#include "image_private.h"
+#include "image_private.hh"
+extern "C" {
extern char datatoc_common_colormanagement_lib_glsl[];
extern char datatoc_common_globals_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
extern char datatoc_engine_image_frag_glsl[];
extern char datatoc_engine_image_vert_glsl[];
+}
+
+namespace blender::draw::image_engine {
-typedef struct IMAGE_Shaders {
+struct IMAGE_Shaders {
GPUShader *image_sh[2];
-} IMAGE_Shaders;
+};
static struct {
IMAGE_Shaders shaders;
DRWShaderLibrary *lib;
-} e_data = {{{0}}}; /* Engine data */
+} e_data = {{{nullptr}}}; /* Engine data */
-void IMAGE_shader_library_ensure(void)
+void IMAGE_shader_library_ensure()
{
- if (e_data.lib == NULL) {
+ if (e_data.lib == nullptr) {
e_data.lib = DRW_shader_library_create();
/* NOTE: These need to be ordered by dependencies. */
DRW_SHADER_LIB_ADD(e_data.lib, common_colormanagement_lib);
@@ -60,18 +64,18 @@ GPUShader *IMAGE_shader_image_get(bool is_tiled_image)
{
const int index = is_tiled_image ? 1 : 0;
IMAGE_Shaders *sh_data = &e_data.shaders;
- if (!sh_data->image_sh[index]) {
+ if (sh_data->image_sh[index] == nullptr) {
sh_data->image_sh[index] = DRW_shader_create_with_shaderlib(
datatoc_engine_image_vert_glsl,
- NULL,
+ nullptr,
datatoc_engine_image_frag_glsl,
e_data.lib,
- is_tiled_image ? "#define TILED_IMAGE\n" : NULL);
+ is_tiled_image ? "#define TILED_IMAGE\n" : nullptr);
}
return sh_data->image_sh[index];
}
-void IMAGE_shader_free(void)
+void IMAGE_shader_free()
{
GPUShader **sh_data_as_array = (GPUShader **)&e_data.shaders;
for (int i = 0; i < (sizeof(IMAGE_Shaders) / sizeof(GPUShader *)); i++) {
@@ -80,3 +84,5 @@ void IMAGE_shader_free(void)
DRW_SHADER_LIB_FREE_SAFE(e_data.lib);
}
+
+} // namespace blender::draw::image_engine
diff --git a/source/blender/draw/engines/image/image_space_image.hh b/source/blender/draw/engines/image/image_space_image.hh
new file mode 100644
index 00000000000..7728a963254
--- /dev/null
+++ b/source/blender/draw/engines/image/image_space_image.hh
@@ -0,0 +1,182 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#pragma once
+
+#include "image_private.hh"
+
+namespace blender::draw::image_engine {
+
+class SpaceImageAccessor : public AbstractSpaceAccessor {
+ SpaceImage *sima;
+
+ public:
+ SpaceImageAccessor(SpaceImage *sima) : sima(sima)
+ {
+ }
+
+ Image *get_image(Main *UNUSED(bmain)) override
+ {
+ return ED_space_image(sima);
+ }
+
+ ImageUser *get_image_user() override
+ {
+ return &sima->iuser;
+ }
+
+ ImBuf *acquire_image_buffer(Image *UNUSED(image), void **lock) override
+ {
+ return ED_space_image_acquire_buffer(sima, lock, 0);
+ }
+
+ void release_buffer(Image *UNUSED(image), ImBuf *image_buffer, void *lock) override
+ {
+ ED_space_image_release_buffer(sima, image_buffer, lock);
+ }
+
+ void get_shader_parameters(ShaderParameters &r_shader_parameters,
+ ImBuf *image_buffer,
+ bool is_tiled) override
+ {
+ const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(image_buffer);
+ const bool do_repeat = (!is_tiled) && ((sima->flag & SI_DRAW_TILE) != 0);
+ SET_FLAG_FROM_TEST(r_shader_parameters.flags, do_repeat, IMAGE_DRAW_FLAG_DO_REPEAT);
+ SET_FLAG_FROM_TEST(r_shader_parameters.flags, is_tiled, IMAGE_DRAW_FLAG_USE_WORLD_POS);
+ if ((sima_flag & SI_USE_ALPHA) != 0) {
+ /* Show RGBA */
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHOW_ALPHA | IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
+ else if ((sima_flag & SI_SHOW_ALPHA) != 0) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 0.0f, 0.0f, 1.0f);
+ }
+ else if ((sima_flag & SI_SHOW_ZBUF) != 0) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_DEPTH | IMAGE_DRAW_FLAG_SHUFFLING;
+ copy_v4_fl4(r_shader_parameters.shuffle, 1.0f, 0.0f, 0.0f, 0.0f);
+ }
+ else if ((sima_flag & SI_SHOW_R) != 0) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(image_buffer)) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
+ copy_v4_fl4(r_shader_parameters.shuffle, 1.0f, 0.0f, 0.0f, 0.0f);
+ }
+ else if ((sima_flag & SI_SHOW_G) != 0) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(image_buffer)) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
+ copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 1.0f, 0.0f, 0.0f);
+ }
+ else if ((sima_flag & SI_SHOW_B) != 0) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(image_buffer)) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
+ copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 0.0f, 1.0f, 0.0f);
+ }
+ else /* RGB */ {
+ if (IMB_alpha_affects_rgb(image_buffer)) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
+ }
+ }
+
+ bool has_view_override() const override
+ {
+ return false;
+ }
+ DRWView *create_view_override(const ARegion *UNUSED(region)) override
+ {
+ return nullptr;
+ }
+
+ void get_gpu_textures(Image *image,
+ ImageUser *iuser,
+ ImBuf *image_buffer,
+ GPUTexture **r_gpu_texture,
+ bool *r_owns_texture,
+ GPUTexture **r_tex_tile_data) override
+ {
+ if (image->rr != nullptr) {
+ /* Update multi-index and pass for the current eye. */
+ BKE_image_multilayer_index(image->rr, iuser);
+ }
+ else {
+ BKE_image_multiview_index(image, iuser);
+ }
+
+ if (image_buffer == nullptr) {
+ return;
+ }
+
+ if (image_buffer->rect == nullptr && image_buffer->rect_float == nullptr) {
+ /* This code-path is only supposed to happen when drawing a lazily-allocatable render result.
+ * In all the other cases the `ED_space_image_acquire_buffer()` is expected to return nullptr
+ * as an image buffer when it has no pixels. */
+
+ BLI_assert(image->type == IMA_TYPE_R_RESULT);
+
+ float zero[4] = {0, 0, 0, 0};
+ *r_gpu_texture = GPU_texture_create_2d(__func__, 1, 1, 0, GPU_RGBA16F, zero);
+ *r_owns_texture = true;
+ return;
+ }
+
+ const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(image_buffer);
+ if (sima_flag & SI_SHOW_ZBUF &&
+ (image_buffer->zbuf || image_buffer->zbuf_float || (image_buffer->channels == 1))) {
+ if (image_buffer->zbuf) {
+ BLI_assert_msg(0, "Integer based depth buffers not supported");
+ }
+ else if (image_buffer->zbuf_float) {
+ *r_gpu_texture = GPU_texture_create_2d(
+ __func__, image_buffer->x, image_buffer->y, 0, GPU_R16F, image_buffer->zbuf_float);
+ *r_owns_texture = true;
+ }
+ else if (image_buffer->rect_float && image_buffer->channels == 1) {
+ *r_gpu_texture = GPU_texture_create_2d(
+ __func__, image_buffer->x, image_buffer->y, 0, GPU_R16F, image_buffer->rect_float);
+ *r_owns_texture = true;
+ }
+ }
+ else if (image->source == IMA_SRC_TILED) {
+ *r_gpu_texture = BKE_image_get_gpu_tiles(image, iuser, image_buffer);
+ *r_tex_tile_data = BKE_image_get_gpu_tilemap(image, iuser, nullptr);
+ *r_owns_texture = false;
+ }
+ else {
+ *r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, image_buffer);
+ *r_owns_texture = false;
+ }
+ }
+
+ void get_image_mat(const ImBuf *UNUSED(image_buffer),
+ const ARegion *UNUSED(region),
+ float r_mat[4][4]) const override
+ {
+ unit_m4(r_mat);
+ }
+};
+
+} // namespace blender::draw::image_engine
diff --git a/source/blender/draw/engines/image/image_space_node.hh b/source/blender/draw/engines/image/image_space_node.hh
new file mode 100644
index 00000000000..3ca18eec742
--- /dev/null
+++ b/source/blender/draw/engines/image/image_space_node.hh
@@ -0,0 +1,138 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#pragma once
+
+#include "image_private.hh"
+
+namespace blender::draw::image_engine {
+
+class SpaceNodeAccessor : public AbstractSpaceAccessor {
+ SpaceNode *snode;
+
+ public:
+ SpaceNodeAccessor(SpaceNode *snode) : snode(snode)
+ {
+ }
+
+ Image *get_image(Main *bmain) override
+ {
+ return BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
+ }
+
+ ImageUser *get_image_user() override
+ {
+ return nullptr;
+ }
+
+ ImBuf *acquire_image_buffer(Image *image, void **lock) override
+ {
+ return BKE_image_acquire_ibuf(image, nullptr, lock);
+ }
+
+ void release_buffer(Image *image, ImBuf *ibuf, void *lock) override
+ {
+ BKE_image_release_ibuf(image, ibuf, lock);
+ }
+
+ bool has_view_override() const override
+ {
+ return true;
+ }
+
+ DRWView *create_view_override(const ARegion *region) override
+ {
+ /* Setup a screen pixel view. The backdrop of the node editor doesn't follow the region. */
+ float winmat[4][4], viewmat[4][4];
+ orthographic_m4(viewmat, 0.0, region->winx, 0.0, region->winy, 0.0, 1.0);
+ unit_m4(winmat);
+ return DRW_view_create(viewmat, winmat, nullptr, nullptr, nullptr);
+ }
+
+ void get_shader_parameters(ShaderParameters &r_shader_parameters,
+ ImBuf *ibuf,
+ bool UNUSED(is_tiled)) override
+ {
+ if ((snode->flag & SNODE_USE_ALPHA) != 0) {
+ /* Show RGBA */
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHOW_ALPHA | IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
+ else if ((snode->flag & SNODE_SHOW_ALPHA) != 0) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 0.0f, 0.0f, 1.0f);
+ }
+ else if ((snode->flag & SNODE_SHOW_R) != 0) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
+ copy_v4_fl4(r_shader_parameters.shuffle, 1.0f, 0.0f, 0.0f, 0.0f);
+ }
+ else if ((snode->flag & SNODE_SHOW_G) != 0) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
+ copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 1.0f, 0.0f, 0.0f);
+ }
+ else if ((snode->flag & SNODE_SHOW_B) != 0) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING;
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
+ copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 0.0f, 1.0f, 0.0f);
+ }
+ else /* RGB */ {
+ if (IMB_alpha_affects_rgb(ibuf)) {
+ r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA;
+ }
+ }
+ }
+
+ void get_gpu_textures(Image *image,
+ ImageUser *iuser,
+ ImBuf *ibuf,
+ GPUTexture **r_gpu_texture,
+ bool *r_owns_texture,
+ GPUTexture **r_tex_tile_data) override
+ {
+ *r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, ibuf);
+ *r_owns_texture = false;
+ *r_tex_tile_data = nullptr;
+ }
+
+ void get_image_mat(const ImBuf *image_buffer,
+ const ARegion *region,
+ float r_mat[4][4]) const override
+ {
+ unit_m4(r_mat);
+ const float ibuf_width = image_buffer->x;
+ const float ibuf_height = image_buffer->y;
+
+ r_mat[0][0] = ibuf_width * snode->zoom;
+ r_mat[1][1] = ibuf_height * snode->zoom;
+ r_mat[3][0] = (region->winx - snode->zoom * ibuf_width) / 2 + snode->xof;
+ r_mat[3][1] = (region->winy - snode->zoom * ibuf_height) / 2 + snode->yof;
+ }
+};
+
+} // namespace blender::draw::image_engine
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index 1da682ff01b..4029f1237e8 100644
--- a/source/blender/draw/engines/overlay/overlay_armature.c
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -26,6 +26,7 @@
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
@@ -39,6 +40,7 @@
#include "BKE_armature.h"
#include "BKE_deform.h"
#include "BKE_modifier.h"
+#include "BKE_object.h"
#include "DEG_depsgraph_query.h"
@@ -52,6 +54,8 @@
#include "overlay_private.h"
+#include "draw_cache_impl.h"
+
#define BONE_VAR(eBone, pchan, var) ((eBone) ? (eBone->var) : (pchan->var))
#define BONE_FLAG(eBone, pchan) ((eBone) ? (eBone->flag) : (pchan->bone->flag))
@@ -100,9 +104,6 @@ typedef struct ArmatureDrawContext {
const ThemeWireColor *bcolor; /* pchan color */
} ArmatureDrawContext;
-/**
- * Return true if armature should be handled by the pose mode engine.
- */
bool OVERLAY_armature_is_pose_mode(Object *ob, const DRWContextState *draw_ctx)
{
Object *active_ob = draw_ctx->obact;
@@ -138,6 +139,10 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
pd->armature.do_pose_fade_geom = pd->armature.do_pose_xray &&
((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) == 0) &&
draw_ctx->object_pose != NULL;
+
+ const float wire_alpha = pd->overlay.bone_wire_alpha;
+ const bool use_wire_alpha = (wire_alpha < 1.0f);
+
DRWState state;
if (pd->armature.do_pose_fade_geom) {
@@ -163,8 +168,8 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
OVERLAY_ArmatureCallBuffers *cb = &pd->armature_call_buffers[i];
- cb->custom_shapes_ghash = BLI_ghash_ptr_new(__func__);
- cb->custom_shapes_transp_ghash = BLI_ghash_ptr_new(__func__);
+ cb->solid.custom_shapes_ghash = BLI_ghash_ptr_new(__func__);
+ cb->transp.custom_shapes_ghash = BLI_ghash_ptr_new(__func__);
DRWPass **p_armature_ps = &psl->armature_ps[i];
DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
@@ -188,44 +193,85 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
- cb->point_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get());
+ cb->solid.point_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get());
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_state_disable(grp, DRW_STATE_WRITE_DEPTH);
DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
- DRW_shgroup_uniform_float_copy(grp, "alpha", 0.4f);
- cb->point_transp = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get());
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.4f);
+ cb->transp.point_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get());
sh = OVERLAY_shader_armature_shape(false);
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
- cb->custom_solid = grp;
- cb->box_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get());
- cb->octa_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get());
+ cb->solid.custom_fill = grp;
+ cb->solid.box_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get());
+ cb->solid.octa_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get());
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_state_disable(grp, DRW_STATE_WRITE_DEPTH);
DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
- DRW_shgroup_uniform_float_copy(grp, "alpha", 0.6f);
- cb->custom_transp = grp;
- cb->box_transp = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get());
- cb->octa_transp = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get());
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.6f);
+ cb->transp.custom_fill = grp;
+ cb->transp.box_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get());
+ cb->transp.octa_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get());
sh = OVERLAY_shader_armature_sphere(true);
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- cb->point_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get());
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+ cb->solid.point_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get());
+
+ if (use_wire_alpha) {
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ cb->transp.point_outline = BUF_INSTANCE(
+ grp, format, DRW_cache_bone_point_wire_outline_get());
+ }
+ else {
+ cb->transp.point_outline = cb->solid.point_outline;
+ }
sh = OVERLAY_shader_armature_shape(true);
- cb->custom_outline = grp = DRW_shgroup_create(sh, armature_ps);
+ cb->solid.custom_outline = grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- cb->box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get());
- cb->octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get());
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+ cb->solid.box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get());
+ cb->solid.octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get());
+
+ if (use_wire_alpha) {
+ cb->transp.custom_outline = grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ cb->transp.box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get());
+ cb->transp.octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get());
+ }
+ else {
+ cb->transp.custom_outline = cb->solid.custom_outline;
+ cb->transp.box_outline = cb->solid.box_outline;
+ cb->transp.octa_outline = cb->solid.octa_outline;
+ }
sh = OVERLAY_shader_armature_shape_wire();
- cb->custom_wire = grp = DRW_shgroup_create(sh, armature_ps);
+ cb->solid.custom_wire = grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+
+ if (use_wire_alpha) {
+ cb->transp.custom_wire = grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ }
+ else {
+ cb->transp.custom_wire = cb->solid.custom_wire;
+ }
}
{
format = formats->instance_extra;
@@ -233,12 +279,35 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_degrees_of_freedom_wire();
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- cb->dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get());
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+ cb->solid.dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get());
+
+ if (use_wire_alpha) {
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ cb->transp.dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get());
+ }
+ else {
+ cb->transp.dof_lines = cb->solid.dof_lines;
+ }
sh = OVERLAY_shader_armature_degrees_of_freedom_solid();
grp = DRW_shgroup_create(sh, armature_transp_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- cb->dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get());
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+ cb->solid.dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get());
+
+ if (use_wire_alpha) {
+ grp = DRW_shgroup_create(sh, armature_transp_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ cb->transp.dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get());
+ }
+ else {
+ cb->transp.dof_sphere = cb->solid.dof_sphere;
+ }
}
{
format = formats->instance_bone_stick;
@@ -246,7 +315,19 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_stick();
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- cb->stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get());
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+ cb->solid.stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get());
+
+ if (use_wire_alpha) {
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ cb->transp.stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get());
+ }
+ else {
+ cb->transp.stick = cb->solid.stick;
+ }
}
{
format = formats->instance_bone_envelope;
@@ -257,29 +338,57 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_bool_copy(grp, "isDistance", false);
DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
- cb->envelope_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
+ cb->solid.envelope_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_state_disable(grp, DRW_STATE_WRITE_DEPTH);
DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA | DRW_STATE_CULL_BACK);
- DRW_shgroup_uniform_float_copy(grp, "alpha", 0.6f);
- cb->envelope_transp = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.6f);
+ cb->transp.envelope_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
format = formats->instance_bone_envelope_outline;
sh = OVERLAY_shader_armature_envelope(true);
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- cb->envelope_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_outline_get());
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+ cb->solid.envelope_outline = BUF_INSTANCE(
+ grp, format, DRW_cache_bone_envelope_outline_get());
+
+ if (use_wire_alpha) {
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ cb->transp.envelope_outline = BUF_INSTANCE(
+ grp, format, DRW_cache_bone_envelope_outline_get());
+ }
+ else {
+ cb->transp.envelope_outline = cb->solid.envelope_outline;
+ }
format = formats->instance_bone_envelope_distance;
sh = OVERLAY_shader_armature_envelope(false);
grp = DRW_shgroup_create(sh, armature_transp_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
DRW_shgroup_uniform_bool_copy(grp, "isDistance", true);
DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT);
- cb->envelope_distance = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
+ cb->solid.envelope_distance = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
+
+ if (use_wire_alpha) {
+ grp = DRW_shgroup_create(sh, armature_transp_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ DRW_shgroup_uniform_bool_copy(grp, "isDistance", true);
+ DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT);
+ cb->transp.envelope_distance = BUF_INSTANCE(
+ grp, format, DRW_cache_bone_envelope_solid_get());
+ }
+ else {
+ cb->transp.envelope_distance = cb->solid.envelope_distance;
+ }
}
{
format = formats->pos_color;
@@ -287,7 +396,19 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_wire();
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- cb->wire = BUF_LINE(grp, format);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+ cb->solid.wire = BUF_LINE(grp, format);
+
+ if (use_wire_alpha) {
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ cb->transp.wire = BUF_LINE(grp, format);
+ }
+ else {
+ cb->transp.wire = cb->solid.wire;
+ }
}
}
}
@@ -535,13 +656,22 @@ static void drw_shgroup_bone_custom_solid(ArmatureDrawContext *ctx,
const float outline_color[4],
Object *custom)
{
+ /* The custom object is not an evaluated object, so its object->data field hasn't been replaced
+ * by #data_eval. This is bad since it gives preference to an object's evaluated mesh over any
+ * other data type, but supporting all evaluated geometry components would require a much larger
+ * refactor of this area. */
+ Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(custom);
+ if (mesh == NULL) {
+ return;
+ }
+
/* TODO(fclem): arg... less than ideal but we never iter on this object
* to assure batch cache is valid. */
- drw_batch_cache_validate(custom);
+ DRW_mesh_batch_cache_validate(custom, mesh);
- struct GPUBatch *surf = DRW_cache_object_surface_get(custom);
- struct GPUBatch *edges = DRW_cache_object_edge_detection_get(custom, NULL);
- struct GPUBatch *ledges = DRW_cache_object_loose_edges_get(custom);
+ struct GPUBatch *surf = DRW_mesh_batch_cache_get_surface(mesh);
+ struct GPUBatch *edges = DRW_mesh_batch_cache_get_edge_detection(mesh, NULL);
+ struct GPUBatch *ledges = DRW_mesh_batch_cache_get_loose_edges(mesh);
BoneInstanceData inst_data;
DRWCallBuffer *buf;
@@ -578,12 +708,16 @@ static void drw_shgroup_bone_custom_wire(ArmatureDrawContext *ctx,
const float color[4],
Object *custom)
{
+ /* See comments in #drw_shgroup_bone_custom_solid. */
+ Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(custom);
+ if (mesh == NULL) {
+ return;
+ }
/* TODO(fclem): arg... less than ideal but we never iter on this object
* to assure batch cache is valid. */
- drw_batch_cache_validate(custom);
-
- struct GPUBatch *geom = DRW_cache_object_all_edges_get(custom);
+ DRW_mesh_batch_cache_validate(custom, mesh);
+ struct GPUBatch *geom = DRW_mesh_batch_cache_get_all_edges(mesh);
if (geom) {
DRWCallBuffer *buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, geom);
BoneInstanceData inst_data;
@@ -1906,6 +2040,7 @@ static void draw_bone_name(ArmatureDrawContext *ctx,
DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
color);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2146,16 +2281,15 @@ static void armature_context_setup(ArmatureDrawContext *ctx,
const bool is_filled = (!pd->armature.transparent && !draw_as_wire) || !is_object_mode;
const bool is_transparent = pd->armature.transparent || (draw_as_wire && !is_object_mode);
bArmature *arm = ob->data;
- OVERLAY_ArmatureCallBuffers *cb = &pd->armature_call_buffers[is_xray];
+ OVERLAY_ArmatureCallBuffers *cbo = &pd->armature_call_buffers[is_xray];
+ OVERLAY_ArmatureCallBuffersInner *cb = is_transparent ? &cbo->transp : &cbo->solid;
static const float select_const_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
switch (arm->drawtype) {
case ARM_ENVELOPE:
ctx->envelope_outline = cb->envelope_outline;
- ctx->envelope_solid = (is_filled) ?
- (is_transparent ? cb->envelope_transp : cb->envelope_solid) :
- NULL;
+ ctx->envelope_solid = (is_filled) ? cb->envelope_fill : NULL;
ctx->envelope_distance = (do_envelope_dist) ? cb->envelope_distance : NULL;
break;
case ARM_LINE:
@@ -2166,24 +2300,23 @@ static void armature_context_setup(ArmatureDrawContext *ctx,
break;
case ARM_B_BONE:
ctx->outline = cb->box_outline;
- ctx->solid = (is_filled) ? (is_transparent ? cb->box_transp : cb->box_solid) : NULL;
+ ctx->solid = (is_filled) ? cb->box_fill : NULL;
break;
case ARM_OCTA:
ctx->outline = cb->octa_outline;
- ctx->solid = (is_filled) ? (is_transparent ? cb->octa_transp : cb->octa_solid) : NULL;
+ ctx->solid = (is_filled) ? cb->octa_fill : NULL;
break;
}
ctx->ob = ob;
ctx->extras = &pd->extra_call_buffers[is_xray];
ctx->dof_lines = cb->dof_lines;
ctx->dof_sphere = cb->dof_sphere;
- ctx->point_solid = (is_filled) ? (is_transparent ? cb->point_transp : cb->point_solid) : NULL;
+ ctx->point_solid = (is_filled) ? cb->point_fill : NULL;
ctx->point_outline = cb->point_outline;
- ctx->custom_solid = (is_filled) ? (is_transparent ? cb->custom_transp : cb->custom_solid) : NULL;
+ ctx->custom_solid = (is_filled) ? cb->custom_fill : NULL;
ctx->custom_outline = cb->custom_outline;
ctx->custom_wire = cb->custom_wire;
- ctx->custom_shapes_ghash = is_transparent ? cb->custom_shapes_transp_ghash :
- cb->custom_shapes_ghash;
+ ctx->custom_shapes_ghash = cb->custom_shapes_ghash;
ctx->show_relations = pd->armature.show_relations;
ctx->do_relations = !DRW_state_is_select() && pd->armature.show_relations &&
(is_edit_mode | is_pose_mode);
@@ -2267,10 +2400,10 @@ void OVERLAY_armature_cache_finish(OVERLAY_Data *vedata)
OVERLAY_PrivateData *pd = vedata->stl->pd;
for (int i = 0; i < 2; i++) {
- if (pd->armature_call_buffers[i].custom_shapes_ghash) {
+ if (pd->armature_call_buffers[i].solid.custom_shapes_ghash) {
/* TODO(fclem): Do not free it for each frame but reuse it. Avoiding alloc cost. */
- BLI_ghash_free(pd->armature_call_buffers[i].custom_shapes_ghash, NULL, NULL);
- BLI_ghash_free(pd->armature_call_buffers[i].custom_shapes_transp_ghash, NULL, NULL);
+ BLI_ghash_free(pd->armature_call_buffers[i].solid.custom_shapes_ghash, NULL, NULL);
+ BLI_ghash_free(pd->armature_call_buffers[i].transp.custom_shapes_ghash, NULL, NULL);
}
}
}
@@ -2314,3 +2447,5 @@ void OVERLAY_pose_draw(OVERLAY_Data *vedata)
DRW_draw_pass(psl->armature_ps[1]);
}
}
+
+/** \} */
diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.c b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
index 3a2871249a2..ad929cc0835 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_mesh.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
@@ -28,6 +28,7 @@
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
+#include "BKE_object.h"
#include "draw_cache_impl.h"
#include "draw_manager_text.h"
@@ -229,7 +230,10 @@ static void overlay_edit_mesh_add_ob_to_pass(OVERLAY_PrivateData *pd, Object *ob
Mesh *me = (Mesh *)ob->data;
BMEditMesh *embm = me->edit_mesh;
if (embm) {
- has_edit_mesh_cage = embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final);
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
+
+ has_edit_mesh_cage = editmesh_eval_cage && (editmesh_eval_cage != editmesh_eval_final);
has_skin_roots = CustomData_get_offset(&embm->bm->vdata, CD_MVERT_SKIN) != -1;
}
diff --git a/source/blender/draw/engines/overlay/overlay_edit_text.c b/source/blender/draw/engines/overlay/overlay_edit_text.c
index 5356700f156..b899767acc4 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_text.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_text.c
@@ -22,7 +22,7 @@
#include "DRW_render.h"
-#include "BKE_font.h"
+#include "BKE_vfont.h"
#include "DNA_curve_types.h"
diff --git a/source/blender/draw/engines/overlay/overlay_edit_uv.c b/source/blender/draw/engines/overlay/overlay_edit_uv.c
index 983df1ceac8..f51df908fbf 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_uv.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_uv.c
@@ -412,7 +412,7 @@ void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata)
draw_ctx->view_layer, NULL, &objects_len, draw_ctx->object_mode);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *object_eval = DEG_get_evaluated_object(draw_ctx->depsgraph, objects[ob_index]);
- DRW_mesh_batch_cache_validate((Mesh *)object_eval->data);
+ DRW_mesh_batch_cache_validate(object_eval, (Mesh *)object_eval->data);
overlay_edit_uv_cache_populate(vedata, object_eval);
}
MEM_freeN(objects);
@@ -441,22 +441,22 @@ static void overlay_edit_uv_cache_populate(OVERLAY_Data *vedata, Object *ob)
if (has_active_edit_uvmap) {
if (pd->edit_uv.do_uv_overlay) {
- geom = DRW_mesh_batch_cache_get_edituv_edges(ob->data);
+ geom = DRW_mesh_batch_cache_get_edituv_edges(ob, ob->data);
if (geom) {
DRW_shgroup_call_obmat(pd->edit_uv_edges_grp, geom, NULL);
}
- geom = DRW_mesh_batch_cache_get_edituv_verts(ob->data);
+ geom = DRW_mesh_batch_cache_get_edituv_verts(ob, ob->data);
if (geom) {
DRW_shgroup_call_obmat(pd->edit_uv_verts_grp, geom, NULL);
}
if (pd->edit_uv.do_faces) {
- geom = DRW_mesh_batch_cache_get_edituv_faces(ob->data);
+ geom = DRW_mesh_batch_cache_get_edituv_faces(ob, ob->data);
if (geom) {
DRW_shgroup_call_obmat(pd->edit_uv_faces_grp, geom, NULL);
}
}
if (pd->edit_uv.do_face_dots) {
- geom = DRW_mesh_batch_cache_get_edituv_facedots(ob->data);
+ geom = DRW_mesh_batch_cache_get_edituv_facedots(ob, ob->data);
if (geom) {
DRW_shgroup_call_obmat(pd->edit_uv_face_dots_grp, geom, NULL);
}
@@ -465,14 +465,14 @@ static void overlay_edit_uv_cache_populate(OVERLAY_Data *vedata, Object *ob)
if (pd->edit_uv.do_uv_stretching_overlay) {
if (pd->edit_uv.draw_type == SI_UVDT_STRETCH_ANGLE) {
- geom = DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(me);
+ geom = DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(ob, me);
}
else /* SI_UVDT_STRETCH_AREA */ {
OVERLAY_StretchingAreaTotals *totals = MEM_mallocN(sizeof(OVERLAY_StretchingAreaTotals),
__func__);
BLI_addtail(&pd->edit_uv.totals, totals);
geom = DRW_mesh_batch_cache_get_edituv_faces_stretch_area(
- me, &totals->total_area, &totals->total_area_uv);
+ ob, me, &totals->total_area, &totals->total_area_uv);
}
if (geom) {
DRW_shgroup_call_obmat(pd->edit_uv_stretching_grp, geom, NULL);
@@ -482,7 +482,7 @@ static void overlay_edit_uv_cache_populate(OVERLAY_Data *vedata, Object *ob)
if (draw_shadows && (has_active_object_uvmap || has_active_edit_uvmap)) {
if (pd->edit_uv.do_uv_shadow_overlay) {
- geom = DRW_mesh_batch_cache_get_uv_edges(ob->data);
+ geom = DRW_mesh_batch_cache_get_uv_edges(ob, ob->data);
if (geom) {
DRW_shgroup_call_obmat(pd->edit_uv_shadow_edges_grp, geom, NULL);
}
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
index 67ac8dd2422..12db2bd02cf 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.c
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -56,7 +56,7 @@ static void OVERLAY_engine_init(void *vedata)
OVERLAY_shader_library_ensure();
if (!stl->pd) {
- /* Alloc transient pointers */
+ /* Allocate transient pointers. */
stl->pd = MEM_callocN(sizeof(*stl->pd), __func__);
}
@@ -235,7 +235,7 @@ BLI_INLINE OVERLAY_DupliData *OVERLAY_duplidata_get(Object *ob, void *vedata, bo
*do_init = true;
}
else if ((*dupli_data)->base_flag != ob->base_flag) {
- /* Select state might have change, reinit. */
+ /* Select state might have change, reinitialize. */
*do_init = true;
}
return *dupli_data;
@@ -463,9 +463,14 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
case OB_LIGHTPROBE:
OVERLAY_lightprobe_cache_populate(vedata, ob);
break;
- case OB_LATTICE:
- OVERLAY_lattice_cache_populate(vedata, ob);
+ case OB_LATTICE: {
+ /* Unlike the other types above, lattices actually have a bounding box defined, so hide the
+ * lattice wires if only the bounding-box is requested. */
+ if (ob->dt > OB_BOUNDBOX) {
+ OVERLAY_lattice_cache_populate(vedata, ob);
+ }
break;
+ }
}
}
@@ -473,7 +478,7 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
OVERLAY_particle_cache_populate(vedata, ob);
}
- /* Relationship, object center, bounbox ... */
+ /* Relationship, object center, bounding-box... etc. */
if (!pd->hide_overlays) {
OVERLAY_extra_cache_populate(vedata, ob);
}
@@ -576,7 +581,7 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_extra_blend_draw(vedata);
OVERLAY_volume_draw(vedata);
- /* These overlays are drawn here to avoid artifacts with wireframe opacity. */
+ /* These overlays are drawn here to avoid artifacts with wire-frame opacity. */
switch (pd->ctx_mode) {
case CTX_MODE_SCULPT:
OVERLAY_sculpt_draw(vedata);
@@ -698,7 +703,7 @@ DrawEngineType draw_engine_overlay_type = {
&overlay_data_size,
&OVERLAY_engine_init,
&OVERLAY_engine_free,
- NULL,
+ NULL, /* instance_free */
&OVERLAY_cache_init,
&OVERLAY_cache_populate,
&OVERLAY_cache_finish,
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
index 98db7136398..a2362cd8850 100644
--- a/source/blender/draw/engines/overlay/overlay_extra.c
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -762,10 +762,7 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob)
instdata.mat[1][3] = prb->grid_resolution_y;
instdata.mat[2][3] = prb->grid_resolution_z;
/* Put theme id in matrix. */
- if (UNLIKELY(ob->base_flag & BASE_FROM_DUPLI)) {
- instdata.mat[3][3] = 0.0;
- }
- else if (theme_id == TH_ACTIVE) {
+ if (theme_id == TH_ACTIVE) {
instdata.mat[3][3] = 1.0;
}
else /* TH_SELECT */ {
diff --git a/source/blender/draw/engines/overlay/overlay_grid.c b/source/blender/draw/engines/overlay/overlay_grid.c
index 31c8ed9d664..4a551c4dec5 100644
--- a/source/blender/draw/engines/overlay/overlay_grid.c
+++ b/source/blender/draw/engines/overlay/overlay_grid.c
@@ -200,6 +200,15 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata)
shd->grid_distance = dist / 2.0f;
ED_view3d_grid_steps(scene, v3d, rv3d, shd->grid_steps);
+
+ if ((v3d->flag & (V3D_XR_SESSION_SURFACE | V3D_XR_SESSION_MIRROR)) != 0) {
+ /* The calculations for the grid parameters assume that the view matrix has no scale component,
+ * which may not be correct if the user is "shrunk" or "enlarged" by zooming in or out.
+ * Therefore, we need to compensate the values here. */
+ float viewinvscale = len_v3(
+ viewinv[0]); /* Assumption is uniform scaling (all column vectors are of same length). */
+ shd->grid_distance *= viewinvscale;
+ }
}
void OVERLAY_grid_cache_init(OVERLAY_Data *vedata)
diff --git a/source/blender/draw/engines/overlay/overlay_image.c b/source/blender/draw/engines/overlay/overlay_image.c
index ada07499d1c..0608725d342 100644
--- a/source/blender/draw/engines/overlay/overlay_image.c
+++ b/source/blender/draw/engines/overlay/overlay_image.c
@@ -344,7 +344,6 @@ void OVERLAY_image_camera_cache_populate(OVERLAY_Data *vedata, Object *ob)
if (tex) {
image_camera_background_matrix_get(cam, bgpic, draw_ctx, aspect, mat);
- mul_m4_m4m4(mat, modelmat, mat);
const bool is_foreground = (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != 0;
/* Alpha is clamped just below 1.0 to fix background images to interfere with foreground
* images. Without this a background image with 1.0 will be rendered on top of a transparent
@@ -361,6 +360,7 @@ void OVERLAY_image_camera_cache_populate(OVERLAY_Data *vedata, Object *ob)
DRW_shgroup_uniform_texture(grp, "imgTexture", tex);
DRW_shgroup_uniform_bool_copy(grp, "imgPremultiplied", use_alpha_premult);
DRW_shgroup_uniform_bool_copy(grp, "imgAlphaBlend", true);
+ DRW_shgroup_uniform_bool_copy(grp, "isCameraBackground", true);
DRW_shgroup_uniform_bool_copy(grp, "depthSet", true);
DRW_shgroup_uniform_vec4_copy(grp, "color", color_premult_alpha);
DRW_shgroup_call_obmat(grp, DRW_cache_quad_get(), mat);
@@ -446,6 +446,7 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob)
DRW_shgroup_uniform_texture(grp, "imgTexture", tex);
DRW_shgroup_uniform_bool_copy(grp, "imgPremultiplied", use_alpha_premult);
DRW_shgroup_uniform_bool_copy(grp, "imgAlphaBlend", use_alpha_blend);
+ DRW_shgroup_uniform_bool_copy(grp, "isCameraBackground", false);
DRW_shgroup_uniform_bool_copy(grp, "depthSet", depth_mode != OB_EMPTY_IMAGE_DEPTH_DEFAULT);
DRW_shgroup_uniform_vec4_copy(grp, "color", ob->color);
DRW_shgroup_call_obmat(grp, DRW_cache_quad_get(), mat);
@@ -461,8 +462,6 @@ void OVERLAY_image_cache_finish(OVERLAY_Data *vedata)
DRW_pass_sort_shgroup_z(psl->image_empties_back_ps);
}
-/* This function draws images that needs the view transform applied.
- * It draws these images directly into the scene color buffer. */
void OVERLAY_image_scene_background_draw(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;
diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h
index def278f98df..c8891a53213 100644
--- a/source/blender/draw/engines/overlay/overlay_private.h
+++ b/source/blender/draw/engines/overlay/overlay_private.h
@@ -216,37 +216,37 @@ typedef struct OVERLAY_ExtraCallBuffers {
DRWShadingGroup *extra_loose_points;
} OVERLAY_ExtraCallBuffers;
-typedef struct OVERLAY_ArmatureCallBuffers {
+typedef struct OVERLAY_ArmatureCallBuffersInner {
DRWCallBuffer *box_outline;
- DRWCallBuffer *box_solid;
- DRWCallBuffer *box_transp;
+ DRWCallBuffer *box_fill;
DRWCallBuffer *dof_lines;
DRWCallBuffer *dof_sphere;
DRWCallBuffer *envelope_distance;
DRWCallBuffer *envelope_outline;
- DRWCallBuffer *envelope_solid;
- DRWCallBuffer *envelope_transp;
+ DRWCallBuffer *envelope_fill;
DRWCallBuffer *octa_outline;
- DRWCallBuffer *octa_solid;
- DRWCallBuffer *octa_transp;
+ DRWCallBuffer *octa_fill;
DRWCallBuffer *point_outline;
- DRWCallBuffer *point_solid;
- DRWCallBuffer *point_transp;
+ DRWCallBuffer *point_fill;
DRWCallBuffer *stick;
DRWCallBuffer *wire;
DRWShadingGroup *custom_outline;
- DRWShadingGroup *custom_solid;
- DRWShadingGroup *custom_transp;
+ DRWShadingGroup *custom_fill;
DRWShadingGroup *custom_wire;
- GHash *custom_shapes_transp_ghash;
+
GHash *custom_shapes_ghash;
+} OVERLAY_ArmatureCallBuffersInner;
+
+typedef struct OVERLAY_ArmatureCallBuffers {
+ OVERLAY_ArmatureCallBuffersInner solid;
+ OVERLAY_ArmatureCallBuffersInner transp;
} OVERLAY_ArmatureCallBuffers;
typedef struct OVERLAY_PrivateData {
@@ -510,6 +510,9 @@ void OVERLAY_xray_fade_draw(OVERLAY_Data *vedata);
void OVERLAY_xray_depth_copy(OVERLAY_Data *vedata);
void OVERLAY_xray_depth_infront_copy(OVERLAY_Data *vedata);
+/**
+ * Return true if armature should be handled by the pose mode engine.
+ */
bool OVERLAY_armature_is_pose_mode(Object *ob, const struct DRWContextState *draw_ctx);
void OVERLAY_armature_cache_init(OVERLAY_Data *vedata);
void OVERLAY_armature_cache_populate(OVERLAY_Data *vedata, Object *ob);
@@ -587,11 +590,11 @@ void OVERLAY_extra_line_dashed(OVERLAY_ExtraCallBuffers *cb,
void OVERLAY_extra_line(OVERLAY_ExtraCallBuffers *cb,
const float start[3],
const float end[3],
- const int color_id);
+ int color_id);
void OVERLAY_empty_shape(OVERLAY_ExtraCallBuffers *cb,
const float mat[4][4],
- const float draw_size,
- const char draw_type,
+ float draw_size,
+ char draw_type,
const float color[4]);
void OVERLAY_extra_loose_points(OVERLAY_ExtraCallBuffers *cb,
struct GPUBatch *geom,
@@ -631,6 +634,10 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_image_cache_finish(OVERLAY_Data *vedata);
void OVERLAY_image_draw(OVERLAY_Data *vedata);
void OVERLAY_image_background_draw(OVERLAY_Data *vedata);
+/**
+ * This function draws images that needs the view transform applied.
+ * It draws these images directly into the scene color buffer.
+ */
void OVERLAY_image_scene_background_draw(OVERLAY_Data *vedata);
void OVERLAY_image_in_front_draw(OVERLAY_Data *vedata);
diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c
index 96c83d90bc9..c1a2b184c6b 100644
--- a/source/blender/draw/engines/overlay/overlay_shader.c
+++ b/source/blender/draw/engines/overlay/overlay_shader.c
@@ -323,7 +323,9 @@ GPUShader *OVERLAY_shader_edit_mesh_vert(void)
datatoc_edit_mesh_common_lib_glsl,
datatoc_edit_mesh_vert_glsl,
NULL},
- .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .frag = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_gpu_shader_point_varying_color_frag_glsl,
+ NULL},
.defs = (const char *[]){sh_cfg->def, "#define VERT\n", NULL},
});
}
@@ -383,7 +385,7 @@ GPUShader *OVERLAY_shader_armature_sphere(bool use_outline)
const DRWContextState *draw_ctx = DRW_context_state_get();
const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
- const char extensions[] = "#extension GL_ARB_conservative_depth : enable\n";
+ const char extensions[] = "";
if (use_outline && !sh_data->armature_sphere_outline) {
sh_data->armature_sphere_outline = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg->lib,
diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c
index fde376beeb2..1eb8fc981cf 100644
--- a/source/blender/draw/engines/overlay/overlay_wireframe.c
+++ b/source/blender/draw/engines/overlay/overlay_wireframe.c
@@ -185,10 +185,11 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
Mesh *me = ob->data;
if (is_edit_mode) {
BLI_assert(me->edit_mesh);
- BMEditMesh *embm = me->edit_mesh;
- has_edit_mesh_cage = embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final);
- if (embm->mesh_eval_final) {
- me = embm->mesh_eval_final;
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
+ has_edit_mesh_cage = editmesh_eval_cage && (editmesh_eval_cage != editmesh_eval_final);
+ if (editmesh_eval_final) {
+ me = editmesh_eval_final;
}
}
is_mesh_verts_only = me->totedge == 0 && me->totvert > 0;
@@ -237,7 +238,21 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
if (dupli && !init_dupli) {
if (dupli->wire_shgrp && dupli->wire_geom) {
if (dupli->base_flag == ob->base_flag) {
- DRW_shgroup_call(dupli->wire_shgrp, dupli->wire_geom, ob);
+ /* Check for the special cases used below, assign specific theme colors to the shaders. */
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ if (dupli->wire_shgrp == cb->extra_loose_points) {
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+ OVERLAY_extra_loose_points(cb, dupli->wire_geom, ob->obmat, color);
+ }
+ else if (dupli->wire_shgrp == cb->extra_wire) {
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+ OVERLAY_extra_wire(cb, dupli->wire_geom, ob->obmat, color);
+ }
+ else {
+ DRW_shgroup_call(dupli->wire_shgrp, dupli->wire_geom, ob);
+ }
return;
}
}
@@ -268,6 +283,9 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
}
}
+ DRWShadingGroup *shgrp = NULL;
+ struct GPUBatch *geom = NULL;
+
/* Don't do that in edit Mesh mode, unless there is a modifier preview. */
if (use_wire && (!is_mesh || (!is_edit_mode || has_edit_mesh_cage))) {
const bool is_sculpt_mode = ((ob->mode & OB_MODE_SCULPT) != 0) && (ob->sculpt != NULL);
@@ -275,8 +293,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
!DRW_state_is_image_render();
const bool use_coloring = (use_wire && !is_edit_mode && !is_sculpt_mode &&
!has_edit_mesh_cage);
- DRWShadingGroup *shgrp = NULL;
- struct GPUBatch *geom = DRW_cache_object_face_wireframe_get(ob);
+ geom = DRW_cache_object_face_wireframe_get(ob);
if (geom || use_sculpt_pbvh) {
if (use_sculpt_pbvh) {
@@ -300,11 +317,6 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
DRW_shgroup_call(shgrp, geom, ob);
}
}
-
- if (dupli) {
- dupli->wire_shgrp = shgrp;
- dupli->wire_geom = geom;
- }
}
else if (is_mesh && (!is_edit_mode || has_edit_mesh_cage)) {
OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
@@ -313,18 +325,25 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
/* Draw loose geometry. */
if (is_mesh_verts_only) {
- struct GPUBatch *geom = DRW_cache_mesh_all_verts_get(ob);
+ geom = DRW_cache_mesh_all_verts_get(ob);
if (geom) {
OVERLAY_extra_loose_points(cb, geom, ob->obmat, color);
+ shgrp = cb->extra_loose_points;
}
}
else {
- struct GPUBatch *geom = DRW_cache_mesh_loose_edges_get(ob);
+ geom = DRW_cache_mesh_loose_edges_get(ob);
if (geom) {
OVERLAY_extra_wire(cb, geom, ob->obmat, color);
+ shgrp = cb->extra_wire;
}
}
}
+
+ if (dupli) {
+ dupli->wire_shgrp = shgrp;
+ dupli->wire_geom = geom;
+ }
}
void OVERLAY_wireframe_draw(OVERLAY_Data *data)
diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl
index e511aab69c1..aedc9bcda61 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl
@@ -1,4 +1,6 @@
+uniform float alpha = 1.0;
+
flat in vec4 finalColor;
layout(location = 0) out vec4 fragColor;
@@ -6,6 +8,6 @@ layout(location = 1) out vec4 lineOutput;
void main()
{
- fragColor = finalColor;
+ fragColor = vec4(finalColor.rgb, finalColor.a * alpha);
lineOutput = vec4(0.0);
}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl
index e4a4f0875f8..51cfe6250be 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl
@@ -14,7 +14,7 @@ void main()
float n = normalize(normalView).z;
if (isDistance) {
n = 1.0 - clamp(-n, 0.0, 1.0);
- fragColor = vec4(1.0, 1.0, 1.0, 0.2) * n;
+ fragColor = vec4(1.0, 1.0, 1.0, 0.33 * alpha) * n;
}
else {
/* Smooth lighting factor. */
diff --git a/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl
index e7696c1ea7d..85136672180 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl
@@ -1,4 +1,6 @@
+uniform float alpha = 1.0;
+
noperspective in float colorFac;
flat in vec4 finalWireColor;
flat in vec4 finalInnerColor;
@@ -10,6 +12,6 @@ void main()
{
float fac = smoothstep(1.0, 0.2, colorFac);
fragColor.rgb = mix(finalInnerColor.rgb, finalWireColor.rgb, fac);
- fragColor.a = 1.0;
+ fragColor.a = alpha;
lineOutput = vec4(0.0);
}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl
index 9413ac0f365..55278515f74 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl
@@ -1,4 +1,6 @@
+uniform float alpha = 1.0;
+
flat in vec4 finalColor;
flat in vec2 edgeStart;
noperspective in vec2 edgePos;
@@ -9,5 +11,5 @@ layout(location = 1) out vec4 lineOutput;
void main()
{
lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos);
- fragColor = finalColor;
+ fragColor = vec4(finalColor.rgb, finalColor.a * alpha);
}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
index 195d2a5a7b7..418c7bceb63 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
@@ -36,7 +36,7 @@ vec4 EDIT_MESH_edge_vertex_color(int vertex_flag)
return color;
}
-vec4 EDIT_MESH_vertex_color(int vertex_flag)
+vec4 EDIT_MESH_vertex_color(int vertex_flag, float vertex_crease)
{
if ((vertex_flag & VERT_ACTIVE) != 0) {
return vec4(colorEditMeshActive.xyz, 1.0);
@@ -45,6 +45,10 @@ vec4 EDIT_MESH_vertex_color(int vertex_flag)
return colorVertexSelect;
}
else {
+ /* Full crease color if not selected nor active. */
+ if (vertex_crease > 0.0) {
+ return mix(colorVertex, colorEdgeCrease, vertex_crease);
+ }
return colorVertex;
}
}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
index a3ff277b714..5cee976f9a8 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
@@ -13,6 +13,9 @@ in vec4 norAndFlag;
#endif
out vec4 finalColor;
+#ifdef VERT
+out float vertexCrease;
+#endif
#ifdef EDGE
out vec4 finalColorOuter;
#endif
@@ -44,8 +47,9 @@ void main()
ivec4 m_data = data & dataMask;
#if defined(VERT)
- finalColor = EDIT_MESH_vertex_color(m_data.y);
- gl_PointSize = sizeVertex * 2.0;
+ vertexCrease = float(m_data.z >> 4) / 15.0;
+ finalColor = EDIT_MESH_vertex_color(m_data.y, vertexCrease);
+ gl_PointSize = sizeVertex * ((vertexCrease > 0.0) ? 3.0 : 2.0);
/* Make selected and active vertex always on top. */
if ((data.x & VERT_SELECTED) != 0) {
gl_Position.z -= 5e-7 * abs(gl_Position.w);
@@ -65,9 +69,9 @@ void main()
selectOverride = (m_data.y & EDGE_SELECTED);
# endif
- float crease = float(m_data.z) / 255.0;
+ float edge_crease = float(m_data.z & 0xF) / 15.0;
float bweight = float(m_data.w) / 255.0;
- finalColorOuter = EDIT_MESH_edge_color_outer(m_data.y, m_data.x, crease, bweight);
+ finalColorOuter = EDIT_MESH_edge_color_outer(m_data.y, m_data.x, edge_crease, bweight);
if (finalColorOuter.a > 0.0) {
gl_Position.z -= 5e-7 * abs(gl_Position.w);
diff --git a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl
index 3746cbcf90b..1f3a23324bb 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl
@@ -10,9 +10,6 @@ vec4 color_from_id(float color_id)
if (isTransform) {
return colorTransform;
}
- else if (color_id == 0.0) {
- return colorDupliSelect;
- }
else if (color_id == 1.0) {
return colorActive;
}
diff --git a/source/blender/draw/engines/overlay/shaders/image_vert.glsl b/source/blender/draw/engines/overlay/shaders/image_vert.glsl
index 621e1d8068b..a44ea7081ba 100644
--- a/source/blender/draw/engines/overlay/shaders/image_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/image_vert.glsl
@@ -1,5 +1,6 @@
uniform bool depthSet;
+uniform bool isCameraBackground;
in vec3 pos;
@@ -7,8 +8,14 @@ out vec2 uvs;
void main()
{
- vec3 world_pos = point_object_to_world(pos);
- gl_Position = point_world_to_ndc(world_pos);
+ if (isCameraBackground) {
+ vec3 vP = (ModelMatrix * vec4(pos, 1.0)).xyz;
+ gl_Position = point_view_to_ndc(vP);
+ }
+ else {
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+ }
if (depthSet) {
/* Result in a position at 1.0 (far plane). Small epsilon to avoid precision issue.
diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
index df10f3f7ae2..0e4757f8ea8 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
@@ -241,9 +241,6 @@ void main()
else if (color_id == 1u) {
fragColor = colorSelect;
}
- else if (color_id == 2u) {
- fragColor = colorDupliSelect;
- }
else if (color_id == 3u) {
fragColor = colorActive;
}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
index 582a7c6cae2..701760dac18 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
@@ -17,18 +17,8 @@ flat out uint objectId;
uint outline_colorid_get(void)
{
int flag = int(abs(ObjectInfo.w));
- bool is_from_dupli = (flag & DRW_BASE_FROM_DUPLI) != 0;
bool is_active = (flag & DRW_BASE_ACTIVE) != 0;
- if (is_from_dupli) {
- if (isTransform) {
- return 0u; /* colorTransform */
- }
- else {
- return 2u; /* colorDupliSelect */
- }
- }
-
if (isTransform) {
return 0u; /* colorTransform */
}
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
index c083fdacbbe..060b7a957c1 100644
--- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
@@ -28,27 +28,12 @@ void wire_color_get(out vec3 rim_col, out vec3 wire_col)
{
int flag = int(abs(ObjectInfo.w));
bool is_selected = (flag & DRW_BASE_SELECTED) != 0;
- bool is_from_dupli = (flag & DRW_BASE_FROM_DUPLI) != 0;
bool is_from_set = (flag & DRW_BASE_FROM_SET) != 0;
bool is_active = (flag & DRW_BASE_ACTIVE) != 0;
if (is_from_set) {
- rim_col = colorDupli.rgb;
- wire_col = colorDupli.rgb;
- }
- else if (is_from_dupli) {
- if (is_selected) {
- if (isTransform) {
- rim_col = colorTransform.rgb;
- }
- else {
- rim_col = colorDupliSelect.rgb;
- }
- }
- else {
- rim_col = colorDupli.rgb;
- }
- wire_col = colorDupli.rgb;
+ rim_col = colorWire.rgb;
+ wire_col = colorWire.rgb;
}
else if (is_selected && useColoring) {
if (isTransform) {
diff --git a/source/blender/draw/engines/select/select_debug_engine.c b/source/blender/draw/engines/select/select_debug_engine.c
index e9437c5ab92..f66eabdcdcc 100644
--- a/source/blender/draw/engines/select/select_debug_engine.c
+++ b/source/blender/draw/engines/select/select_debug_engine.c
@@ -120,6 +120,7 @@ DrawEngineType draw_engine_debug_select_type = {
&select_debug_data_size,
&select_debug_engine_init,
&select_debug_engine_free,
+ NULL, /* instance_free */
NULL,
NULL,
NULL,
diff --git a/source/blender/draw/engines/select/select_draw_utils.c b/source/blender/draw/engines/select/select_draw_utils.c
index e9930dbdb30..2801f2d7720 100644
--- a/source/blender/draw/engines/select/select_draw_utils.c
+++ b/source/blender/draw/engines/select/select_draw_utils.c
@@ -49,7 +49,7 @@ void select_id_object_min_max(Object *obj, float r_min[3], float r_max[3])
BoundBox *bb;
BMEditMesh *em = BKE_editmesh_from_object(obj);
if (em) {
- bb = BKE_editmesh_cage_boundbox_get(em);
+ bb = BKE_editmesh_cage_boundbox_get(obj, em);
}
else {
bb = BKE_object_boundbox_get(obj);
diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c
index 56acbdd68dd..7f9645013ce 100644
--- a/source/blender/draw/engines/select/select_engine.c
+++ b/source/blender/draw/engines/select/select_engine.c
@@ -363,7 +363,7 @@ DrawEngineType draw_engine_select_type = {
&select_data_size,
&select_engine_init,
&select_engine_free,
- NULL,
+ NULL, /* instance_free */
&select_cache_init,
&select_cache_populate,
NULL,
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh
new file mode 100644
index 00000000000..030be382a14
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh
@@ -0,0 +1,41 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Base Composite
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_composite)
+ .sampler(0, ImageType::FLOAT_2D, "normalBuffer", Frequency::PASS)
+ .sampler(1, ImageType::FLOAT_2D, "materialBuffer", Frequency::PASS)
+ .uniform_buf(4, "WorldData", "world_data", Frequency::PASS)
+ .push_constant(0, Type::BOOL, "forceShadowing")
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .typedef_source("workbench_shader_shared.h")
+ .fragment_source("workbench_composite_frag.glsl")
+ .additional_info("draw_fullscreen");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lighting Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_composite_studio)
+ .define("V3D_LIGHTING_STUDIO")
+ .additional_info("workbench_composite")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_composite_matcap)
+ .define("V3D_LIGHTING_MATCAP")
+ .sampler(2, ImageType::FLOAT_2D, "matcap_diffuse_tx", Frequency::PASS)
+ .sampler(3, ImageType::FLOAT_2D, "matcap_specular_tx", Frequency::PASS)
+ .additional_info("workbench_composite")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_composite_flat)
+ .define("V3D_LIGHTING_FLAT")
+ .additional_info("workbench_composite")
+ .do_static_compilation(true);
+
+/** \} */
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh
new file mode 100644
index 00000000000..00978b5c43b
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh
@@ -0,0 +1,64 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name TAA
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_taa)
+ .sampler(0, ImageType::FLOAT_2D, "colorBuffer")
+ .push_constant(0, Type::FLOAT, "samplesWeights", 9)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .fragment_source("workbench_effect_taa_frag.glsl")
+ .additional_info("draw_fullscreen")
+ .do_static_compilation(true);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name SMAA
+ * \{ */
+
+GPU_SHADER_INTERFACE_INFO(workbench_smaa_iface, "")
+ .smooth(Type::VEC2, "uvs")
+ .smooth(Type::VEC2, "pixcoord")
+ .smooth(Type::VEC4, "offset[3]");
+
+GPU_SHADER_CREATE_INFO(workbench_smaa)
+ .define("SMAA_GLSL_3")
+ .define("SMAA_RT_METRICS", "viewportMetrics")
+ .define("SMAA_PRESET_HIGH")
+ .define("SMAA_LUMA_WEIGHT", "float4(1.0, 1.0, 1.0, 1.0)")
+ .define("SMAA_NO_DISCARD")
+ .vertex_out(workbench_smaa_iface)
+ .push_constant(1, Type::VEC4, "viewportMetrics")
+ .vertex_source("workbench_effect_smaa_vert.glsl")
+ .fragment_source("workbench_effect_smaa_frag.glsl");
+
+GPU_SHADER_CREATE_INFO(workbench_smaa_stage_0)
+ .define("SMAA_STAGE", "0")
+ .sampler(0, ImageType::FLOAT_2D, "colorTex")
+ .fragment_out(0, Type::VEC2, "out_edges")
+ .additional_info("workbench_smaa")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_smaa_stage_1)
+ .define("SMAA_STAGE", "1")
+ .sampler(0, ImageType::FLOAT_2D, "edgesTex")
+ .sampler(1, ImageType::FLOAT_2D, "areaTex")
+ .sampler(2, ImageType::FLOAT_2D, "searchTex")
+ .fragment_out(0, Type::VEC4, "out_weights")
+ .additional_info("workbench_smaa")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_smaa_stage_2)
+ .define("SMAA_STAGE", "2")
+ .sampler(0, ImageType::FLOAT_2D, "colorTex")
+ .sampler(1, ImageType::FLOAT_2D, "blendTex")
+ .push_constant(2, Type::FLOAT, "mixFactor")
+ .push_constant(3, Type::FLOAT, "taaAccumulatedWeight")
+ .fragment_out(0, Type::VEC4, "out_color")
+ .additional_info("workbench_smaa")
+ .do_static_compilation(true);
+
+/** \} */
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh
new file mode 100644
index 00000000000..60d79ed50d9
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh
@@ -0,0 +1,31 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(workbench_effect_cavity_common)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .sampler(0, ImageType::DEPTH_2D, "depthBuffer")
+ .sampler(1, ImageType::FLOAT_2D, "normalBuffer")
+ .sampler(2, ImageType::UINT_2D, "objectIdBuffer")
+ .sampler(3, ImageType::FLOAT_2D, "cavityJitter")
+ .uniform_buf(3, "vec4", "samples_coords[512]")
+ .uniform_buf(4, "WorldData", "world_data", Frequency::PASS)
+ .typedef_source("workbench_shader_shared.h")
+ .fragment_source("workbench_effect_cavity_frag.glsl")
+ .additional_info("draw_fullscreen")
+ .additional_info("draw_view");
+
+GPU_SHADER_CREATE_INFO(workbench_effect_cavity)
+ .do_static_compilation(true)
+ .define("USE_CAVITY")
+ .additional_info("workbench_effect_cavity_common");
+
+GPU_SHADER_CREATE_INFO(workbench_effect_curvature)
+ .do_static_compilation(true)
+ .define("USE_CURVATURE")
+ .additional_info("workbench_effect_cavity_common");
+
+GPU_SHADER_CREATE_INFO(workbench_effect_cavity_curvature)
+ .do_static_compilation(true)
+ .define("USE_CAVITY")
+ .define("USE_CURVATURE")
+ .additional_info("workbench_effect_cavity_common");
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_dof_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_dof_info.hh
new file mode 100644
index 00000000000..a885fca6f07
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_dof_info.hh
@@ -0,0 +1,55 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(workbench_effect_dof)
+ /* TODO(fclem): Split resources per stage. */
+ .sampler(0, ImageType::FLOAT_2D, "inputCocTex")
+ .sampler(1, ImageType::FLOAT_2D, "maxCocTilesTex")
+ .sampler(2, ImageType::FLOAT_2D, "sceneColorTex")
+ .sampler(3, ImageType::FLOAT_2D, "sceneDepthTex")
+ .sampler(4, ImageType::FLOAT_2D, "backgroundTex")
+ .sampler(5, ImageType::FLOAT_2D, "halfResColorTex")
+ .sampler(6, ImageType::FLOAT_2D, "blurTex")
+ .sampler(7, ImageType::FLOAT_2D, "noiseTex")
+ .push_constant(0, Type::VEC2, "invertedViewportSize")
+ .push_constant(1, Type::VEC2, "nearFar")
+ .push_constant(2, Type::VEC3, "dofParams")
+ .push_constant(3, Type::FLOAT, "noiseOffset")
+ .fragment_source("workbench_effect_dof_frag.glsl")
+ .additional_info("draw_fullscreen")
+ .additional_info("draw_view");
+
+GPU_SHADER_CREATE_INFO(workbench_effect_dof_prepare)
+ .define("PREPARE")
+ .fragment_out(0, Type::VEC4, "halfResColor")
+ .fragment_out(1, Type::VEC2, "normalizedCoc")
+ .additional_info("workbench_effect_dof")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_effect_dof_downsample)
+ .define("DOWNSAMPLE")
+ .fragment_out(0, Type::VEC4, "outColor")
+ .fragment_out(1, Type::VEC2, "outCocs")
+ .additional_info("workbench_effect_dof")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_effect_dof_blur1)
+ .define("BLUR1")
+ .define("NUM_SAMPLES", "49")
+ .uniform_buf(1, "vec4", "samples[49]")
+ .fragment_out(0, Type::VEC4, "blurColor")
+ .additional_info("workbench_effect_dof")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_effect_dof_blur2)
+ .define("BLUR2")
+ .fragment_out(0, Type::VEC4, "finalColor")
+ .additional_info("workbench_effect_dof")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_effect_dof_resolve)
+ .define("RESOLVE")
+ .fragment_out(0, Type::VEC4, "finalColorAdd", DualBlend::SRC_0)
+ .fragment_out(0, Type::VEC4, "finalColorMul", DualBlend::SRC_1)
+ .additional_info("workbench_effect_dof")
+ .do_static_compilation(true); \ No newline at end of file
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_outline_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_outline_info.hh
new file mode 100644
index 00000000000..3849fe57a25
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_outline_info.hh
@@ -0,0 +1,11 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(workbench_effect_outline)
+ .typedef_source("workbench_shader_shared.h")
+ .fragment_source("workbench_effect_outline_frag.glsl")
+ .sampler(0, ImageType::UINT_2D, "objectIdBuffer")
+ .uniform_buf(4, "WorldData", "world_data", Frequency::PASS)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .additional_info("draw_fullscreen")
+ .do_static_compilation(true);
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_merge_infront_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_merge_infront_info.hh
new file mode 100644
index 00000000000..78403c292f0
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_merge_infront_info.hh
@@ -0,0 +1,9 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(workbench_merge_infront)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .sampler(0, ImageType::DEPTH_2D, "depthBuffer")
+ .fragment_source("workbench_merge_infront_frag.glsl")
+ .additional_info("draw_fullscreen")
+ .do_static_compilation(true);
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh
new file mode 100644
index 00000000000..5e3b593ee6f
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh
@@ -0,0 +1,149 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Object Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_mesh)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC3, "nor")
+ .vertex_in(2, Type::VEC4, "ac")
+ .vertex_in(3, Type::VEC2, "au")
+ .vertex_source("workbench_prepass_vert.glsl")
+ .additional_info("draw_mesh")
+ .additional_info("draw_resource_handle");
+
+GPU_SHADER_CREATE_INFO(workbench_hair)
+ .sampler(0, ImageType::FLOAT_BUFFER, "ac", Frequency::BATCH)
+ .sampler(1, ImageType::FLOAT_BUFFER, "au", Frequency::BATCH)
+ .vertex_source("workbench_prepass_hair_vert.glsl")
+ .additional_info("draw_hair")
+ .additional_info("draw_resource_handle");
+
+GPU_SHADER_CREATE_INFO(workbench_pointcloud)
+ .vertex_source("workbench_prepass_pointcloud_vert.glsl")
+ .additional_info("draw_pointcloud")
+ .additional_info("draw_resource_handle");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Texture Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_texture_none).define("TEXTURE_NONE");
+
+GPU_SHADER_CREATE_INFO(workbench_texture_single)
+ .sampler(2, ImageType::FLOAT_2D, "imageTexture", Frequency::BATCH)
+ .push_constant(1, Type::BOOL, "imagePremult")
+ .push_constant(2, Type::FLOAT, "imageTransparencyCutoff")
+ .define("V3D_SHADING_TEXTURE_COLOR");
+
+GPU_SHADER_CREATE_INFO(workbench_texture_tile)
+ .sampler(2, ImageType::FLOAT_2D_ARRAY, "imageTileArray", Frequency::BATCH)
+ .sampler(3, ImageType::FLOAT_1D_ARRAY, "imageTileData", Frequency::BATCH)
+ .push_constant(1, Type::BOOL, "imagePremult")
+ .push_constant(2, Type::FLOAT, "imageTransparencyCutoff")
+ .define("V3D_SHADING_TEXTURE_COLOR")
+ .define("TEXTURE_IMAGE_ARRAY");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lighting Type (only for transparent)
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_lighting_flat).define("V3D_LIGHTING_FLAT");
+GPU_SHADER_CREATE_INFO(workbench_lighting_studio).define("V3D_LIGHTING_STUDIO");
+GPU_SHADER_CREATE_INFO(workbench_lighting_matcap)
+ .define("V3D_LIGHTING_MATCAP")
+ .sampler(4, ImageType::FLOAT_2D, "matcap_diffuse_tx", Frequency::PASS)
+ .sampler(5, ImageType::FLOAT_2D, "matcap_specular_tx", Frequency::PASS);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Material Interface
+ * \{ */
+
+GPU_SHADER_INTERFACE_INFO(workbench_material_iface, "")
+ .smooth(Type::VEC3, "normal_interp")
+ .smooth(Type::VEC3, "color_interp")
+ .smooth(Type::FLOAT, "alpha_interp")
+ .smooth(Type::VEC2, "uv_interp")
+ .flat(Type::INT, "object_id")
+ .flat(Type::FLOAT, "roughness")
+ .flat(Type::FLOAT, "metallic");
+
+GPU_SHADER_CREATE_INFO(workbench_material)
+ .uniform_buf(4, "WorldData", "world_data", Frequency::PASS)
+ .uniform_buf(5, "vec4", "materials_data[4096]", Frequency::PASS)
+ .push_constant(4, Type::INT, "materialIndex")
+ .push_constant(5, Type::BOOL, "useMatcap")
+ .vertex_out(workbench_material_iface);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pipeline Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_transparent_accum)
+ /* Note: Blending will be skipped on objectId because output is a
+ non-normalized integer buffer. */
+ .fragment_out(0, Type::VEC4, "transparentAccum")
+ .fragment_out(1, Type::VEC4, "revealageAccum")
+ .fragment_out(2, Type::UINT, "objectId")
+ .push_constant(3, Type::BOOL, "forceShadowing")
+ .typedef_source("workbench_shader_shared.h")
+ .fragment_source("workbench_transparent_accum_frag.glsl");
+
+GPU_SHADER_CREATE_INFO(workbench_opaque)
+ .fragment_out(0, Type::VEC4, "materialData")
+ .fragment_out(1, Type::VEC2, "normalData")
+ .fragment_out(2, Type::UINT, "objectId")
+ .typedef_source("workbench_shader_shared.h")
+ .fragment_source("workbench_prepass_frag.glsl");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Variations Declaration
+ * \{ */
+
+#define WORKBENCH_FINAL_VARIATION(name, ...) \
+ GPU_SHADER_CREATE_INFO(name).additional_info(__VA_ARGS__).do_static_compilation(true);
+
+#define WORKBENCH_CLIPPING_VARIATIONS(prefix, ...) \
+ WORKBENCH_FINAL_VARIATION(prefix##_clip, "drw_clipped", __VA_ARGS__) \
+ WORKBENCH_FINAL_VARIATION(prefix##_no_clip, __VA_ARGS__)
+
+#define WORKBENCH_TEXTURE_VARIATIONS(prefix, ...) \
+ WORKBENCH_CLIPPING_VARIATIONS(prefix##_tex_none, "workbench_texture_none", __VA_ARGS__) \
+ WORKBENCH_CLIPPING_VARIATIONS(prefix##_tex_single, "workbench_texture_single", __VA_ARGS__) \
+ WORKBENCH_CLIPPING_VARIATIONS(prefix##_tex_tile, "workbench_texture_tile", __VA_ARGS__)
+
+#define WORKBENCH_DATATYPE_VARIATIONS(prefix, ...) \
+ WORKBENCH_TEXTURE_VARIATIONS(prefix##_mesh, "workbench_mesh", __VA_ARGS__) \
+ WORKBENCH_TEXTURE_VARIATIONS(prefix##_hair, "workbench_hair", __VA_ARGS__) \
+ WORKBENCH_TEXTURE_VARIATIONS(prefix##_ptcloud, "workbench_pointcloud", __VA_ARGS__)
+
+#define WORKBENCH_PIPELINE_VARIATIONS(prefix, ...) \
+ WORKBENCH_DATATYPE_VARIATIONS(prefix##_transp_studio, \
+ "workbench_transparent_accum", \
+ "workbench_lighting_studio", \
+ __VA_ARGS__) \
+ WORKBENCH_DATATYPE_VARIATIONS(prefix##_transp_matcap, \
+ "workbench_transparent_accum", \
+ "workbench_lighting_matcap", \
+ __VA_ARGS__) \
+ WORKBENCH_DATATYPE_VARIATIONS(prefix##_transp_flat, \
+ "workbench_transparent_accum", \
+ "workbench_lighting_flat", \
+ __VA_ARGS__) \
+ WORKBENCH_DATATYPE_VARIATIONS(prefix##_opaque, "workbench_opaque", __VA_ARGS__)
+
+WORKBENCH_PIPELINE_VARIATIONS(workbench, "workbench_material");
+
+/** \} */
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_shadow_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_shadow_info.hh
new file mode 100644
index 00000000000..64f491aa201
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_shadow_info.hh
@@ -0,0 +1,98 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Common
+ * \{ */
+
+GPU_SHADER_INTERFACE_INFO(workbench_shadow_iface, "vData")
+ .smooth(Type::VEC3, "pos")
+ .smooth(Type::VEC4, "frontPosition")
+ .smooth(Type::VEC4, "backPosition");
+
+GPU_SHADER_CREATE_INFO(workbench_shadow_common)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_out(workbench_shadow_iface)
+ .push_constant(0, Type::FLOAT, "lightDistance")
+ .push_constant(1, Type::VEC3, "lightDirection")
+ .vertex_source("workbench_shadow_vert.glsl")
+ .additional_info("draw_mesh");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Manifold Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_shadow_manifold)
+ .geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::TRIANGLE_STRIP, 4, 1)
+ .geometry_source("workbench_shadow_geom.glsl");
+
+GPU_SHADER_CREATE_INFO(workbench_shadow_no_manifold)
+ .geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::TRIANGLE_STRIP, 4, 2)
+ .geometry_source("workbench_shadow_geom.glsl");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Caps Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_shadow_caps)
+ .geometry_layout(PrimitiveIn::TRIANGLES, PrimitiveOut::TRIANGLE_STRIP, 3, 2)
+ .geometry_source("workbench_shadow_caps_geom.glsl");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Debug Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_shadow_no_debug)
+ .fragment_source("gpu_shader_depth_only_frag.glsl");
+
+GPU_SHADER_CREATE_INFO(workbench_shadow_debug)
+ .fragment_out(0, Type::VEC4, "materialData")
+ .fragment_out(1, Type::VEC4, "normalData")
+ .fragment_out(2, Type::UINT, "objectId")
+ .fragment_source("workbench_shadow_debug_frag.glsl");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Variations Declaration
+ * \{ */
+
+#define WORKBENCH_SHADOW_VARIATIONS(suffix, ...) \
+ GPU_SHADER_CREATE_INFO(workbench_shadow_pass_manifold_no_caps##suffix) \
+ .define("SHADOW_PASS") \
+ .additional_info("workbench_shadow_common", "workbench_shadow_manifold", __VA_ARGS__) \
+ .do_static_compilation(true); \
+ GPU_SHADER_CREATE_INFO(workbench_shadow_pass_no_manifold_no_caps##suffix) \
+ .define("SHADOW_PASS") \
+ .define("DOUBLE_MANIFOLD") \
+ .additional_info("workbench_shadow_common", "workbench_shadow_no_manifold", __VA_ARGS__) \
+ .do_static_compilation(true); \
+ GPU_SHADER_CREATE_INFO(workbench_shadow_fail_manifold_caps##suffix) \
+ .define("SHADOW_FAIL") \
+ .additional_info("workbench_shadow_common", "workbench_shadow_caps", __VA_ARGS__) \
+ .do_static_compilation(true); \
+ GPU_SHADER_CREATE_INFO(workbench_shadow_fail_manifold_no_caps##suffix) \
+ .define("SHADOW_FAIL") \
+ .additional_info("workbench_shadow_common", "workbench_shadow_manifold", __VA_ARGS__) \
+ .do_static_compilation(true); \
+ GPU_SHADER_CREATE_INFO(workbench_shadow_fail_no_manifold_caps##suffix) \
+ .define("SHADOW_FAIL") \
+ .define("DOUBLE_MANIFOLD") \
+ .additional_info("workbench_shadow_common", "workbench_shadow_caps", __VA_ARGS__) \
+ .do_static_compilation(true); \
+ GPU_SHADER_CREATE_INFO(workbench_shadow_fail_no_manifold_no_caps##suffix) \
+ .define("SHADOW_FAIL") \
+ .define("DOUBLE_MANIFOLD") \
+ .additional_info("workbench_shadow_common", "workbench_shadow_no_manifold", __VA_ARGS__) \
+ .do_static_compilation(true);
+
+WORKBENCH_SHADOW_VARIATIONS(, "workbench_shadow_no_debug")
+WORKBENCH_SHADOW_VARIATIONS(_debug, "workbench_shadow_debug")
+
+/** \} */
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_transparent_resolve_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_transparent_resolve_info.hh
new file mode 100644
index 00000000000..e5b7bc8e2a7
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_transparent_resolve_info.hh
@@ -0,0 +1,10 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(workbench_transparent_resolve)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .sampler(0, ImageType::FLOAT_2D, "transparentAccum")
+ .sampler(1, ImageType::FLOAT_2D, "transparentRevealage")
+ .fragment_source("workbench_transparent_resolve_frag.glsl")
+ .additional_info("draw_fullscreen")
+ .do_static_compilation(true);
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh
new file mode 100644
index 00000000000..f212ba9ec1d
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh
@@ -0,0 +1,114 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Volume shader base
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_volume)
+ .vertex_in(0, Type::VEC3, "pos")
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .sampler(0, ImageType::DEPTH_2D, "depthBuffer")
+ .sampler(1, ImageType::FLOAT_3D, "densityTexture")
+ .push_constant(28, Type::INT, "samplesLen")
+ .push_constant(29, Type::FLOAT, "noiseOfs")
+ .push_constant(30, Type::FLOAT, "stepLength")
+ .push_constant(31, Type::FLOAT, "densityScale")
+ .vertex_source("workbench_volume_vert.glsl")
+ .fragment_source("workbench_volume_frag.glsl")
+ .additional_info("draw_object_infos");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smoke variation
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_volume_smoke)
+ .define("VOLUME_SMOKE")
+ .sampler(2, ImageType::FLOAT_3D, "flameTexture")
+ .sampler(3, ImageType::FLOAT_1D, "flameColorTexture")
+ .additional_info("draw_mesh", "draw_resource_id_varying");
+
+GPU_SHADER_CREATE_INFO(workbench_volume_object)
+ .define("VOLUME_OBJECT")
+ .push_constant(0, Type::MAT4, "volumeTextureToObject")
+ /* FIXME(fclem): This overflow the push_constant limit. */
+ .push_constant(16, Type::MAT4, "volumeObjectToTexture")
+ .additional_info("draw_volume", "draw_resource_id_varying");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Band variation
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_volume_coba)
+ .define("USE_COBA")
+ .sampler(4, ImageType::UINT_3D, "flagTexture")
+ .sampler(5, ImageType::FLOAT_1D, "transferTexture")
+ .push_constant(18, Type::BOOL, "showPhi")
+ .push_constant(19, Type::BOOL, "showFlags")
+ .push_constant(20, Type::BOOL, "showPressure")
+ .push_constant(21, Type::FLOAT, "gridScale");
+
+GPU_SHADER_CREATE_INFO(workbench_volume_no_coba)
+ .sampler(4, ImageType::FLOAT_3D, "shadowTexture")
+ .sampler(5, ImageType::UINT_2D, "transferTexture")
+ .push_constant(18, Type::VEC3, "activeColor");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sampling variation
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_volume_linear).define("USE_TRILINEAR");
+GPU_SHADER_CREATE_INFO(workbench_volume_cubic).define("USE_TRICUBIC");
+GPU_SHADER_CREATE_INFO(workbench_volume_closest).define("USE_CLOSEST");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Slice variation
+ * \{ */
+
+GPU_SHADER_INTERFACE_INFO(workbench_volume_iface, "").smooth(Type::VEC3, "localPos");
+
+GPU_SHADER_CREATE_INFO(workbench_volume_slice)
+ .define("VOLUME_SLICE")
+ .vertex_in(1, Type::VEC3, "uvs")
+ .vertex_out(workbench_volume_iface)
+ .push_constant(32, Type::INT, "sliceAxis") /* -1 is no slice. */
+ .push_constant(33, Type::FLOAT, "slicePosition");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Variations Declaration
+ * \{ */
+
+#define WORKBENCH_VOLUME_SLICE_VARIATIONS(prefix, ...) \
+ GPU_SHADER_CREATE_INFO(prefix##_slice) \
+ .additional_info("workbench_volume_slice", __VA_ARGS__) \
+ .do_static_compilation(true); \
+ GPU_SHADER_CREATE_INFO(prefix##_no_slice) \
+ .additional_info(__VA_ARGS__) \
+ .do_static_compilation(true);
+
+#define WORKBENCH_VOLUME_COBA_VARIATIONS(prefix, ...) \
+ WORKBENCH_VOLUME_SLICE_VARIATIONS(prefix##_coba, "workbench_volume_coba", __VA_ARGS__) \
+ WORKBENCH_VOLUME_SLICE_VARIATIONS(prefix##_no_coba, "workbench_volume_no_coba", __VA_ARGS__)
+
+#define WORKBENCH_VOLUME_INTERP_VARIATIONS(prefix, ...) \
+ WORKBENCH_VOLUME_COBA_VARIATIONS(prefix##_linear, "workbench_volume_linear", __VA_ARGS__) \
+ WORKBENCH_VOLUME_COBA_VARIATIONS(prefix##_cubic, "workbench_volume_cubic", __VA_ARGS__) \
+ WORKBENCH_VOLUME_COBA_VARIATIONS(prefix##_closest, "workbench_volume_closest", __VA_ARGS__)
+
+#define WORKBENCH_VOLUME_SMOKE_VARIATIONS(prefix, ...) \
+ WORKBENCH_VOLUME_INTERP_VARIATIONS(prefix##_smoke, "workbench_volume_smoke", __VA_ARGS__) \
+ WORKBENCH_VOLUME_INTERP_VARIATIONS(prefix##_object, "workbench_volume_object", __VA_ARGS__)
+
+WORKBENCH_VOLUME_SMOKE_VARIATIONS(workbench_volume, "workbench_volume")
+
+/** \} */
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 9038aae533b..ad83d6f39e5 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
@@ -1,15 +1,7 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
-layout(std140) uniform samples_block
-{
- vec4 samples_coords[512];
-};
-
-uniform sampler2D cavityJitter;
-
/* From The Alchemy screen-space ambient obscurance algorithm
* http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */
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 8cbc8608f5b..9b142fe56b5 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
@@ -3,10 +3,6 @@
#define CAVITY_BUFFER_RANGE 4.0
-#ifdef WORKBENCH_ENCODE_NORMALS
-
-# define WB_Normal vec2
-
/* From http://aras-p.info/texts/CompactNormalStorage.html
* Using Method #4: Spheremap Transform */
vec3 workbench_normal_decode(vec4 enc)
@@ -22,7 +18,7 @@ vec3 workbench_normal_decode(vec4 enc)
/* From http://aras-p.info/texts/CompactNormalStorage.html
* Using Method #4: Spheremap Transform */
-WB_Normal workbench_normal_encode(bool front_face, vec3 n)
+vec2 workbench_normal_encode(bool front_face, vec3 n)
{
n = normalize(front_face ? n : -n);
float p = sqrt(n.z * 8.0 + 8.0);
@@ -30,13 +26,6 @@ WB_Normal workbench_normal_encode(bool front_face, vec3 n)
return n.xy;
}
-#else
-# define WB_Normal vec3
-/* Well just do nothing... */
-# define workbench_normal_encode(f, a) (a)
-# define workbench_normal_decode(a) (a.xyz)
-#endif /* WORKBENCH_ENCODE_NORMALS */
-
/* Encoding into the alpha of a RGBA16F texture. (10bit mantissa) */
#define TARGET_BITCOUNT 8u
#define METALLIC_BITS 3u /* Metallic channel is less important. */
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 c5b2ce0fd99..5e43fe27f38 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl
@@ -4,13 +4,6 @@
#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl)
-uniform sampler2D materialBuffer;
-uniform sampler2D normalBuffer;
-
-in vec4 uvcoordsvar;
-
-out vec4 fragColor;
-
void main()
{
/* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */
@@ -27,7 +20,7 @@ void main()
/* When using matcaps, mat_data.a is the back-face sign. */
N = (mat_data.a > 0.0) ? N : -N;
- fragColor.rgb = get_matcap_lighting(base_color, N, I);
+ fragColor.rgb = get_matcap_lighting(matcap_diffuse_tx, matcap_specular_tx, base_color, N, I);
#endif
#ifdef V3D_LIGHTING_STUDIO
@@ -38,7 +31,7 @@ void main()
fragColor.rgb = base_color;
#endif
- fragColor.rgb *= get_shadow(N);
+ fragColor.rgb *= get_shadow(N, forceShadowing);
fragColor.a = 1.0;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
index a4d81393dbc..18a093275c5 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
@@ -1,6 +1,4 @@
-#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
-
float curvature_soft_clamp(float curvature, float control)
{
if (curvature < 0.5 / control) {
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
index 328d50e69e0..59222b588a0 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
@@ -4,14 +4,6 @@
#pragma BLENDER_REQUIRE(workbench_cavity_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_curvature_lib.glsl)
-uniform sampler2D depthBuffer;
-uniform sampler2D normalBuffer;
-uniform usampler2D objectIdBuffer;
-
-in vec4 uvcoordsvar;
-
-out vec4 fragColor;
-
void main()
{
float cavity = 0.0, edges = 0.0, curvature = 0.0;
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 92d5df1a13a..e9525ce9de0 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
@@ -7,19 +7,6 @@
* Converted and adapted from HLSL to GLSL by Clément Foucault
*/
-uniform vec2 invertedViewportSize;
-uniform vec2 nearFar;
-uniform vec3 dofParams;
-uniform float noiseOffset;
-uniform sampler2D inputCocTex;
-uniform sampler2D maxCocTilesTex;
-uniform sampler2D sceneColorTex;
-uniform sampler2D sceneDepthTex;
-uniform sampler2D backgroundTex;
-uniform sampler2D halfResColorTex;
-uniform sampler2D blurTex;
-uniform sampler2D noiseTex;
-
#define dof_aperturesize dofParams.x
#define dof_distance dofParams.y
#define dof_invsensorsize dofParams.z
@@ -53,9 +40,6 @@ float decode_signed_coc(vec2 cocs)
*/
#ifdef PREPARE
-layout(location = 0) out vec4 halfResColor;
-layout(location = 1) out vec2 normalizedCoc;
-
void main()
{
ivec4 texel = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
@@ -95,13 +79,10 @@ void main()
/**
* ----------------- STEP 0.5 ------------------
- * Custom Coc aware downsampling. Quater res pass.
+ * Custom Coc aware downsampling. Quarter res pass.
*/
#ifdef DOWNSAMPLE
-layout(location = 0) out vec4 outColor;
-layout(location = 1) out vec2 outCocs;
-
void main()
{
vec4 texel = vec4(gl_FragCoord.xyxy) * 2.0 + vec4(0.0, 0.0, 1.0, 1.0);
@@ -216,14 +197,6 @@ void main()
* Outputs vertical blur and combined blur in MRT
*/
#ifdef BLUR1
-layout(location = 0) out vec4 blurColor;
-
-# define NUM_SAMPLES 49
-
-layout(std140) uniform dofSamplesBlock
-{
- vec4 samples[NUM_SAMPLES];
-};
vec2 get_random_vector(float offset)
{
@@ -308,7 +281,6 @@ void main()
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef BLUR2
-out vec4 finalColor;
void main()
{
@@ -385,9 +357,6 @@ void main()
*/
#ifdef RESOLVE
-layout(location = 0, index = 0) out vec4 finalColorAdd;
-layout(location = 0, index = 1) out vec4 finalColorMul;
-
void main()
{
/* Fullscreen pass */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl
index fb6fdb93462..5d74933abf4 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl
@@ -1,12 +1,4 @@
-#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
-
-uniform usampler2D objectIdBuffer;
-
-in vec4 uvcoordsvar;
-
-out vec4 fragColor;
-
void main()
{
vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl
index 9797a5e3301..8b9e3f968ea 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl
@@ -1,50 +1,35 @@
-uniform sampler2D edgesTex;
-uniform sampler2D areaTex;
-uniform sampler2D searchTex;
-uniform sampler2D blendTex;
-uniform sampler2D colorTex;
-uniform float mixFactor;
-uniform float taaAccumulatedWeight;
-
-in vec2 uvs;
-in vec2 pixcoord;
-in vec4 offset[3];
-
-#if SMAA_STAGE == 0
-out vec2 fragColor;
-#else
-out vec4 fragColor;
-#endif
+#pragma BLENDER_REQUIRE(common_smaa_lib.glsl)
void main()
{
#if SMAA_STAGE == 0
/* Detect edges in color and revealage buffer. */
- fragColor = SMAALumaEdgeDetectionPS(uvs, offset, colorTex);
+ out_edges = SMAALumaEdgeDetectionPS(uvs, offset, colorTex);
/* Discard if there is no edge. */
- if (dot(fragColor, float2(1.0, 1.0)) == 0.0) {
+ if (dot(out_edges, float2(1.0, 1.0)) == 0.0) {
discard;
}
#elif SMAA_STAGE == 1
- fragColor = SMAABlendingWeightCalculationPS(
+ out_weights = SMAABlendingWeightCalculationPS(
uvs, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0));
#elif SMAA_STAGE == 2
- fragColor = vec4(0.0);
+ out_color = vec4(0.0);
if (mixFactor > 0.0) {
- fragColor += SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex) * mixFactor;
+ out_color += SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex) * mixFactor;
}
if (mixFactor < 1.0) {
- fragColor += texture(colorTex, uvs) * (1.0 - mixFactor);
+ out_color += texture(colorTex, uvs) * (1.0 - mixFactor);
}
- fragColor /= taaAccumulatedWeight;
- fragColor = exp2(fragColor) - 0.5;
+ out_color /= taaAccumulatedWeight;
+ /* Exit log2 space used for Antialiasing. */
+ out_color = exp2(out_color) - 0.5;
/* Avoid float precision issue. */
- if (fragColor.a > 0.999) {
- fragColor.a = 1.0;
+ if (out_color.a > 0.999) {
+ out_color.a = 1.0;
}
#endif
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl
index 07734d19972..b76433a23e5 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl
@@ -1,7 +1,5 @@
-out vec2 uvs;
-out vec2 pixcoord;
-out vec4 offset[3];
+#pragma BLENDER_REQUIRE(common_smaa_lib.glsl)
void main()
{
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl
index d021e4696f7..0c4dee11756 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl
@@ -1,9 +1,4 @@
-uniform sampler2D colorBuffer;
-uniform float samplesWeights[9];
-
-out vec4 fragColor;
-
void main()
{
vec2 texel_size = 1.0 / vec2(textureSize(colorBuffer, 0));
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl
index 57d648d3565..78782bdc777 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl
@@ -25,13 +25,6 @@ bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map)
return true;
}
-uniform sampler2DArray imageTileArray;
-uniform sampler1DArray imageTileData;
-uniform sampler2D imageTexture;
-
-uniform float imageTransparencyCutoff = 0.1;
-uniform bool imagePremult;
-
vec3 workbench_image_color(vec2 uvs)
{
#ifdef V3D_SHADING_TEXTURE_COLOR
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl
index 2d18cc1b014..a0cec54251d 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl
@@ -1,6 +1,4 @@
-#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
-
vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped)
{
/* Quick creation of an orthonormal basis */
@@ -15,16 +13,14 @@ vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped)
return matcap_uv * 0.496 + 0.5;
}
-uniform sampler2D matcapDiffuseImage;
-uniform sampler2D matcapSpecularImage;
-
-vec3 get_matcap_lighting(vec3 base_color, vec3 N, vec3 I)
+vec3 get_matcap_lighting(
+ sampler2D diffuse_matcap, sampler2D specular_matcap, vec3 base_color, vec3 N, vec3 I)
{
bool flipped = world_data.matcap_orientation != 0;
vec2 uv = matcap_uv_compute(I, N, flipped);
- vec3 diffuse = textureLod(matcapDiffuseImage, uv, 0.0).rgb;
- vec3 specular = textureLod(matcapSpecularImage, uv, 0.0).rgb;
+ vec3 diffuse = textureLod(diffuse_matcap, uv, 0.0).rgb;
+ vec3 specular = textureLod(specular_matcap, uv, 0.0).rgb;
return diffuse * base_color + specular * float(world_data.use_specular);
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl
index 1d8950e34b3..b6dc26ecc65 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl
@@ -1,17 +1,9 @@
-layout(std140) uniform material_block
-{
- vec4 mat_data[4096];
-};
-
-/* If set to -1, the resource handle is used instead. */
-uniform int materialIndex;
-
void workbench_material_data_get(
int handle, out vec3 color, out float alpha, out float roughness, out float metallic)
{
handle = (materialIndex != -1) ? materialIndex : handle;
- vec4 data = mat_data[uint(handle) & 0xFFFu];
+ vec4 data = materials_data[uint(handle) & 0xFFFu];
color = data.rgb;
uint encoded_data = floatBitsToUint(data.w);
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
index 856654549ca..ae564435258 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
@@ -1,10 +1,4 @@
-uniform sampler2D depthBuffer;
-
-in vec4 uvcoordsvar;
-
-out vec4 fragColor;
-
void main()
{
float depth = texture(depthBuffer, uvcoordsvar.st).r;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
index 6d24b001d4d..1b20171b3ff 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
@@ -1,20 +1,13 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
-layout(location = 0) out vec4 materialData;
-layout(location = 1) out WB_Normal normalData;
-layout(location = 2) out uint objectId;
-
-uniform bool useMatcap = false;
-
void main()
{
normalData = workbench_normal_encode(gl_FrontFacing, normal_interp);
- materialData = vec4(color_interp, packed_rough_metal);
+ materialData = vec4(color_interp, workbench_float_pair_encode(roughness, metallic));
objectId = uint(object_id);
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl
index 3e1ea14f47c..65b9f4de4b6 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl
@@ -1,13 +1,10 @@
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_material_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
-uniform samplerBuffer ac; /* active color layer */
-uniform samplerBuffer au; /* active texture layer */
-
/* From http://libnoise.sourceforge.net/noisegen/index.html */
float integer_noise(int n)
{
@@ -63,17 +60,12 @@ void main()
float hair_rand = integer_noise(hair_get_strand_id());
vec3 nor = workbench_hair_random_normal(tan, binor, hair_rand);
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos);
-#endif
+ view_clipping_distances(world_pos);
uv_interp = hair_get_customdata_vec2(au);
normal_interp = normalize(normal_world_to_view(nor));
-#ifdef OPAQUE_MATERIAL
- float metallic, roughness;
-#endif
workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic);
if (materialIndex == 0) {
@@ -86,9 +78,5 @@ void main()
workbench_hair_random_material(hair_rand, color_interp, roughness, metallic);
-#ifdef OPAQUE_MATERIAL
- packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
-#endif
-
object_id = int(uint(resource_handle) & 0xFFFFu) + 1;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl
index 6f61874b8f5..911d6f5b036 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl
@@ -1,7 +1,7 @@
+#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl)
-#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_material_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
@@ -15,24 +15,15 @@ void main()
gl_Position = point_world_to_ndc(world_pos);
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos);
-#endif
+ view_clipping_distances(world_pos);
uv_interp = vec2(0.0);
-#ifdef OPAQUE_MATERIAL
- float metallic, roughness;
-#endif
workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic);
if (materialIndex == 0) {
color_interp = vec3(1.0);
}
-#ifdef OPAQUE_MATERIAL
- packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
-#endif
-
object_id = int(uint(resource_handle) & 0xFFFFu) + 1;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
index 1192081caf1..3a63b141c5f 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
@@ -1,40 +1,26 @@
+#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_material_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
-in vec3 pos;
-in vec3 nor;
-in vec4 ac; /* active color */
-in vec2 au; /* active texture layer */
-
void main()
{
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos);
-#endif
+ view_clipping_distances(world_pos);
uv_interp = au;
normal_interp = normalize(normal_object_to_view(nor));
-#ifdef OPAQUE_MATERIAL
- float metallic, roughness;
-#endif
workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic);
if (materialIndex == 0) {
color_interp = ac.rgb;
}
-#ifdef OPAQUE_MATERIAL
- packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
-#endif
-
object_id = int(uint(resource_handle) & 0xFFFFu) + 1;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl
deleted file mode 100644
index 6bfa351aeb0..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl
+++ /dev/null
@@ -1,15 +0,0 @@
-
-IN_OUT ShaderStageInterface
-{
- vec3 normal_interp;
- vec3 color_interp;
- float alpha_interp;
- vec2 uv_interp;
-#ifdef TRANSPARENT_MATERIAL
- flat float roughness;
- flat float metallic;
-#else
- flat float packed_rough_metal;
-#endif
- flat int object_id;
-};
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_caps_geom.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_caps_geom.glsl
index 09bafb8ff11..4a7b1522426 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_caps_geom.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_caps_geom.glsl
@@ -1,41 +1,7 @@
-#extension GL_ARB_gpu_shader5 : enable
-
-#ifdef GL_ARB_gpu_shader5
+#ifdef GPU_ARB_gpu_shader5
# define USE_INVOC_EXT
#endif
-#ifdef DOUBLE_MANIFOLD
-# ifdef USE_INVOC_EXT
-# define invoc_len 2
-# else
-# define vert_len 6
-# endif
-#else
-# ifdef USE_INVOC_EXT
-# define invoc_len 2
-# else
-# define vert_len 6
-# endif
-#endif
-
-#ifdef USE_INVOC_EXT
-layout(triangles, invocations = invoc_len) in;
-layout(triangle_strip, max_vertices = 3) out;
-#else
-layout(triangles) in;
-layout(triangle_strip, max_vertices = vert_len) out;
-#endif
-
-uniform vec3 lightDirection = vec3(0.57, 0.57, -0.57);
-
-in VertexData
-{
- vec3 pos; /* local position */
- vec4 frontPosition; /* final ndc position */
- vec4 backPosition;
-}
-vData[];
-
vec4 get_pos(int v, bool backface)
{
return (backface) ? vData[v].backPosition : vData[v].frontPosition;
@@ -76,18 +42,19 @@ void main()
/* In case of non manifold geom, we only increase/decrease
* the stencil buffer by one but do every faces as they were facing the light. */
bool invert = backface;
+ const bool is_manifold = false;
#else
const bool invert = false;
- if (!backface) {
+ const bool is_manifold = true;
#endif
+
+ if (!is_manifold || !backface) {
#ifdef USE_INVOC_EXT
- bool do_front = (gl_InvocationID & 1) == 0;
- emit_cap(do_front, invert);
+ bool do_front = (gl_InvocationID & 1) == 0;
+ emit_cap(do_front, invert);
#else
emit_cap(true, invert);
emit_cap(false, invert);
#endif
-#ifndef DOUBLE_MANIFOLD
-}
-#endif
+ }
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl
index 6fa76510e6e..c9977a8d91a 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl
@@ -1,10 +1,4 @@
-out vec4 fragColor;
-
-layout(location = 0) out vec4 materialData;
-layout(location = 1) out vec4 normalData;
-layout(location = 2) out uint objectId;
-
void main()
{
const float a = 0.25;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl
index 2c9190bfcf4..9902884fc12 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl
@@ -1,41 +1,7 @@
-#extension GL_ARB_gpu_shader5 : enable
-
-#ifdef GL_ARB_gpu_shader5
+#ifdef GPU_ARB_gpu_shader5
# define USE_INVOC_EXT
#endif
-#ifdef DOUBLE_MANIFOLD
-# ifdef USE_INVOC_EXT
-# define invoc_len 2
-# else
-# define vert_len 8
-# endif
-#else
-# ifdef USE_INVOC_EXT
-# define invoc_len 1
-# else
-# define vert_len 4
-# endif
-#endif
-
-#ifdef USE_INVOC_EXT
-layout(lines_adjacency, invocations = invoc_len) in;
-layout(triangle_strip, max_vertices = 4) out;
-#else
-layout(lines_adjacency) in;
-layout(triangle_strip, max_vertices = vert_len) out;
-#endif
-
-uniform vec3 lightDirection = vec3(0.57, 0.57, -0.57);
-
-in VertexData
-{
- vec3 pos; /* local position */
- vec4 frontPosition; /* final ndc position */
- vec4 backPosition;
-}
-vData[];
-
#define DEGENERATE_TRIS_WORKAROUND
#define DEGENERATE_TRIS_AREA_THRESHOLD 4e-17
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl
index e07f87525e2..a220434ec45 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl
@@ -1,17 +1,5 @@
-#define INFINITE 1000.0
-uniform vec3 lightDirection = vec3(0.57, 0.57, -0.57);
-uniform float lightDistance = 1e4;
-
-in vec3 pos;
-
-out VertexData
-{
- vec3 pos; /* local position */
- vec4 frontPosition; /* final ndc position */
- vec4 backPosition;
-}
-vData;
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
void main()
{
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 fd4d00d96dd..9c0f93c67d9 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
@@ -1,19 +1,10 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl)
-/* Revealage is actually stored in transparentAccum alpha channel.
- * This is a workaround to older hardware not having separate blend equation per render target. */
-layout(location = 0) out vec4 transparentAccum;
-layout(location = 1) out vec4 revealageAccum;
-
-/* Note: Blending will be skipped on objectId because output is a non-normalized integer buffer. */
-layout(location = 2) out uint objectId;
-
/* Special function only to be used with calculate_transparent_weight(). */
float linear_zdepth(float depth, vec4 viewvecs[2], mat4 proj_mat)
{
@@ -67,7 +58,7 @@ void main()
#endif
#ifdef V3D_LIGHTING_MATCAP
- vec3 shaded_color = get_matcap_lighting(color, N, I);
+ vec3 shaded_color = get_matcap_lighting(matcap_diffuse_tx, matcap_specular_tx, color, N, I);
#endif
#ifdef V3D_LIGHTING_STUDIO
@@ -78,7 +69,7 @@ void main()
vec3 shaded_color = color;
#endif
- shaded_color *= get_shadow(N);
+ shaded_color *= get_shadow(N, forceShadowing);
/* Listing 4 */
float weight = calculate_transparent_weight() * alpha_interp;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
index d985737a35b..a2c45d2f8e3 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
@@ -1,11 +1,4 @@
-uniform sampler2D transparentAccum;
-uniform sampler2D transparentRevealage;
-
-in vec4 uvcoordsvar;
-
-out vec4 fragColor;
-
/* Based on :
* McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of
* Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013
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 86fef6b23ad..076f6e80104 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
@@ -1,40 +1,8 @@
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(common_obinfos_lib.glsl)
-#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
-uniform sampler2D depthBuffer;
-
-uniform sampler3D densityTexture;
-uniform sampler3D shadowTexture;
-uniform sampler3D flameTexture;
-uniform usampler3D flagTexture;
-uniform sampler1D flameColorTexture;
-uniform sampler1D transferTexture;
-uniform mat4 volumeObjectToTexture;
-
-uniform int samplesLen = 256;
-uniform float noiseOfs = 0.0;
-uniform float stepLength; /* Step length in local space. */
-uniform float densityScale; /* Simple Opacity multiplicator. */
-uniform float gridScale; /* Multiplicator for grid scaling. */
-uniform vec3 activeColor;
-
-uniform float slicePosition;
-uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
-
-uniform bool showPhi = false;
-uniform bool showFlags = false;
-uniform bool showPressure = false;
-
-#ifdef VOLUME_SLICE
-in vec3 localPos;
-#endif
-
-out vec4 fragColor;
-
float phase_function_isotropic()
{
return 1.0 / (4.0 * M_PI);
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
index 8549af4709a..d2b12f41421 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
@@ -1,22 +1,8 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(common_obinfos_lib.glsl)
-
-uniform float slicePosition;
-uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
-
-uniform mat4 volumeTextureToObject;
-
-in vec3 pos;
RESOURCE_ID_VARYING
-#ifdef VOLUME_SLICE
-in vec3 uvs;
-
-out vec3 localPos;
-#endif
-
void main()
{
#ifdef VOLUME_SLICE
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
index 41ef516ee4d..531ed461057 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
@@ -1,6 +1,4 @@
-#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
-
/* [Drobot2014a] Low Level Optimizations for GCN */
vec4 fast_rcp(vec4 v)
{
@@ -120,12 +118,10 @@ vec3 get_world_lighting(vec3 base_color, float roughness, float metallic, vec3 N
return diffuse_light + specular_light;
}
-uniform bool forceShadowing = false;
-
-float get_shadow(vec3 N)
+float get_shadow(vec3 N, bool force_shadowing)
{
float light_factor = -dot(N, world_data.shadow_direction_vs.xyz);
float shadow_mix = smoothstep(world_data.shadow_shift, world_data.shadow_focus, light_factor);
- shadow_mix *= forceShadowing ? 0.0 : world_data.shadow_mul;
+ shadow_mix *= force_shadowing ? 0.0 : world_data.shadow_mul;
return shadow_mix + world_data.shadow_add;
}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
index 8206add7412..f4014fac41f 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
@@ -371,7 +371,6 @@ void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata)
}
}
-/* Return true if render is not cached. */
bool workbench_antialiasing_setup(WORKBENCH_Data *vedata)
{
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
diff --git a/source/blender/draw/engines/workbench/workbench_effect_cavity.c b/source/blender/draw/engines/workbench/workbench_effect_cavity.c
index b294b9a62ca..6ab74d179f6 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_cavity.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_cavity.c
@@ -165,7 +165,7 @@ void workbench_cavity_cache_init(WORKBENCH_Data *data)
grp = DRW_shgroup_create(sh, psl->cavity_ps);
DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx);
DRW_shgroup_uniform_block(grp, "samples_block", wpd->vldata->cavity_sample_ubo);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
if (SSAO_ENABLED(wpd)) {
DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth);
diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c
index 2261790226a..b5f43251a43 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_dof.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c
@@ -328,7 +328,7 @@ void workbench_dof_cache_init(WORKBENCH_Data *vedata)
float offset = wpd->taa_sample / (float)max_ii(1, wpd->taa_sample_len);
DRWShadingGroup *grp = DRW_shgroup_create(blur1_sh, psl->dof_blur1_ps);
- DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->vldata->dof_sample_ubo);
+ DRW_shgroup_uniform_block(grp, "samples", wpd->vldata->dof_sample_ubo);
DRW_shgroup_uniform_texture(grp, "noiseTex", wpd->vldata->cavity_jitter_tx);
DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx);
diff --git a/source/blender/draw/engines/workbench/workbench_effect_outline.c b/source/blender/draw/engines/workbench/workbench_effect_outline.c
index d1bc6b6c435..4f716c5a7bc 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_outline.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_outline.c
@@ -46,7 +46,7 @@ void workbench_outline_cache_init(WORKBENCH_Data *data)
grp = DRW_shgroup_create(sh, psl->outline_ps);
DRW_shgroup_uniform_texture(grp, "objectIdBuffer", wpd->object_id_tx);
DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
else {
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index f294055cc17..0a0c20b0d6a 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -51,8 +51,6 @@ void workbench_engine_init(void *ved)
WORKBENCH_StorageList *stl = vedata->stl;
WORKBENCH_TextureList *txl = vedata->txl;
- workbench_shader_library_ensure();
-
workbench_private_data_alloc(stl);
WORKBENCH_PrivateData *wpd = stl->wpd;
workbench_private_data_init(wpd);
@@ -379,7 +377,7 @@ void workbench_cache_populate(void *ved, Object *ob)
return;
}
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_POINTCLOUD)) {
+ if (ELEM(ob->type, OB_MESH, OB_SURF, OB_MBALL, OB_POINTCLOUD)) {
bool use_sculpt_pbvh, use_texpaint_mode, draw_shadow, has_transp_mat = false;
eV3DShadingColorType color_type = workbench_color_type_get(
wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, &draw_shadow);
@@ -473,8 +471,6 @@ void workbench_cache_finish(void *ved)
}
}
-/* Used by viewport rendering & final rendering.
- * Do one render loop iteration (i.e: One TAA sample). */
void workbench_draw_sample(void *ved)
{
WORKBENCH_Data *vedata = ved;
@@ -629,7 +625,7 @@ DrawEngineType draw_engine_workbench = {
&workbench_data_size,
&workbench_engine_init,
&workbench_engine_free,
- NULL,
+ NULL, /* instance_free */
&workbench_cache_init,
&workbench_cache_populate,
&workbench_cache_finish,
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index aaa1a5a6ff6..1b12e29617c 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -198,7 +198,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
}
DRWShadingGroup **grp_mat = NULL;
- /* A hashmap stores material shgroups to pack all similar drawcalls together. */
+ /* A hash-map stores material shgroups to pack all similar drawcalls together. */
if (BLI_ghash_ensure_p(prepass->material_hash, ma, (void ***)&grp_mat)) {
return *grp_mat;
}
@@ -210,7 +210,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp = prepass->common_shgrp;
*grp_mat = grp = DRW_shgroup_create_sub(grp);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", mat_id);
return grp;
}
@@ -234,7 +234,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
DRWShadingGroup **grp = &wpd->prepass[transp][infront][datatype].common_shgrp;
if (resource_changed) {
*grp = DRW_shgroup_create_sub(*grp);
- DRW_shgroup_uniform_block(*grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(*grp, "materials_data", wpd->material_ubo_curr);
}
if (r_transp && transp) {
*r_transp = true;
@@ -244,7 +244,6 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
}
}
-/* If ima is null, search appropriate image node but will fallback to purple texture otherwise. */
DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
Object *ob,
int mat_nr,
@@ -278,7 +277,7 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][datatype];
DRWShadingGroup **grp_tex = NULL;
- /* A hashmap stores image shgroups to pack all similar drawcalls together. */
+ /* A hash-map stores image shgroups to pack all similar drawcalls together. */
if (BLI_ghash_ensure_p(prepass->material_hash, tex, (void ***)&grp_tex)) {
return *grp_tex;
}
@@ -294,5 +293,6 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
DRW_shgroup_uniform_texture_ex(grp, "imageTexture", tex, sampler);
}
DRW_shgroup_uniform_bool_copy(grp, "imagePremult", (ima && ima->alpha_mode == IMA_ALPHA_PREMUL));
+ DRW_shgroup_uniform_float_copy(grp, "imageTransparencyCutoff", 0.1f);
return grp;
}
diff --git a/source/blender/draw/engines/workbench/workbench_opaque.c b/source/blender/draw/engines/workbench/workbench_opaque.c
index 9fdefed019f..e4534d923ab 100644
--- a/source/blender/draw/engines/workbench/workbench_opaque.c
+++ b/source/blender/draw/engines/workbench/workbench_opaque.c
@@ -88,26 +88,26 @@ void workbench_opaque_cache_init(WORKBENCH_Data *vedata)
sh = workbench_shader_opaque_get(wpd, data);
wpd->prepass[opaque][infront][data].common_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1);
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
wpd->prepass[opaque][infront][data].vcol_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
sh = workbench_shader_opaque_image_get(wpd, data, false);
wpd->prepass[opaque][infront][data].image_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
sh = workbench_shader_opaque_image_get(wpd, data, true);
wpd->prepass[opaque][infront][data].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
}
@@ -121,7 +121,7 @@ void workbench_opaque_cache_init(WORKBENCH_Data *vedata)
sh = workbench_shader_composite_get(wpd);
grp = DRW_shgroup_create(sh, psl->composite_ps);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
DRW_shgroup_uniform_texture(grp, "materialBuffer", wpd->material_buffer_tx);
DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx);
DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false);
@@ -135,8 +135,8 @@ void workbench_opaque_cache_init(WORKBENCH_Data *vedata)
struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture;
const bool use_spec = workbench_is_specular_highlight_enabled(wpd);
spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx;
- DRW_shgroup_uniform_texture(grp, "matcapDiffuseImage", diff_tx);
- DRW_shgroup_uniform_texture(grp, "matcapSpecularImage", spec_tx);
+ DRW_shgroup_uniform_texture(grp, "matcap_diffuse_tx", diff_tx);
+ DRW_shgroup_uniform_texture(grp, "matcap_specular_tx", spec_tx);
}
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index e17bd7d9956..2cf96a8e139 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -414,12 +414,16 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data);
/* workbench_transparent.c */
void workbench_transparent_engine_init(WORKBENCH_Data *data);
void workbench_transparent_cache_init(WORKBENCH_Data *data);
+/**
+ * Redraw the transparent passes but with depth test
+ * to output correct outline IDs and depth.
+ */
void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data);
/* workbench_shadow.c */
void workbench_shadow_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd);
void workbench_shadow_cache_init(WORKBENCH_Data *data);
-void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, const bool has_transp_mat);
+void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, bool has_transp_mat);
/* workbench_shader.c */
GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, eWORKBENCH_DataType data);
@@ -455,7 +459,6 @@ void workbench_shader_depth_of_field_get(GPUShader **prepare_sh,
GPUShader **blur2_sh,
GPUShader **resolve_sh);
-void workbench_shader_library_ensure(void);
void workbench_shader_free(void);
/* workbench_effect_antialiasing.c */
@@ -463,6 +466,9 @@ int workbench_antialiasing_sample_count_get(WORKBENCH_PrivateData *wpd);
void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata);
void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata);
void workbench_antialiasing_view_updated(WORKBENCH_Data *vedata);
+/**
+ * Return true if render is not cached.
+ */
bool workbench_antialiasing_setup(WORKBENCH_Data *vedata);
void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata);
@@ -491,6 +497,9 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
eV3DShadingColorType color_type,
eWORKBENCH_DataType datatype,
bool *r_transp);
+/**
+ * If `ima` is null, search appropriate image node but will fallback to purple texture otherwise.
+ */
DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
Object *ob,
int mat_nr,
@@ -535,6 +544,10 @@ void workbench_engine_init(void *ved);
void workbench_cache_init(void *ved);
void workbench_cache_populate(void *ved, Object *ob);
void workbench_cache_finish(void *ved);
+/**
+ * Used by viewport rendering & final rendering.
+ * Do one render loop iteration (i.e: One TAA sample).
+ */
void workbench_draw_sample(void *ved);
void workbench_draw_finish(void *ved);
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
index f2d178f6565..125bee87614 100644
--- a/source/blender/draw/engines/workbench/workbench_render.c
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -185,7 +185,7 @@ void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer
DRW_render_instance_buffer_finish();
- /* Also we weed to have a correct fbo bound for DRW_hair_update */
+ /* Also we weed to have a correct FBO bound for #DRW_hair_update */
GPU_framebuffer_bind(dfbl->default_fb);
DRW_hair_update();
diff --git a/source/blender/draw/engines/workbench/workbench_shader.c b/source/blender/draw/engines/workbench/workbench_shader.c
deleted file mode 100644
index 0dcc7b6c773..00000000000
--- a/source/blender/draw/engines/workbench/workbench_shader.c
+++ /dev/null
@@ -1,562 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2020, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-
-#include "DRW_render.h"
-
-#include "BLI_dynstr.h"
-#include "BLI_string_utils.h"
-
-#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[];
-extern char datatoc_common_smaa_lib_glsl[];
-
-extern char datatoc_workbench_prepass_vert_glsl[];
-extern char datatoc_workbench_prepass_hair_vert_glsl[];
-extern char datatoc_workbench_prepass_pointcloud_vert_glsl[];
-extern char datatoc_workbench_prepass_frag_glsl[];
-
-extern char datatoc_workbench_effect_cavity_frag_glsl[];
-extern char datatoc_workbench_effect_outline_frag_glsl[];
-extern char datatoc_workbench_effect_dof_frag_glsl[];
-extern char datatoc_workbench_effect_taa_frag_glsl[];
-extern char datatoc_workbench_effect_smaa_frag_glsl[];
-extern char datatoc_workbench_effect_smaa_vert_glsl[];
-
-extern char datatoc_workbench_composite_frag_glsl[];
-
-extern char datatoc_workbench_transparent_accum_frag_glsl[];
-extern char datatoc_workbench_transparent_resolve_frag_glsl[];
-
-extern char datatoc_workbench_merge_infront_frag_glsl[];
-
-extern char datatoc_workbench_shadow_vert_glsl[];
-extern char datatoc_workbench_shadow_geom_glsl[];
-extern char datatoc_workbench_shadow_caps_geom_glsl[];
-extern char datatoc_workbench_shadow_debug_frag_glsl[];
-
-extern char datatoc_workbench_volume_vert_glsl[];
-extern char datatoc_workbench_volume_frag_glsl[];
-
-extern char datatoc_workbench_cavity_lib_glsl[];
-extern char datatoc_workbench_common_lib_glsl[];
-extern char datatoc_workbench_curvature_lib_glsl[];
-extern char datatoc_workbench_data_lib_glsl[];
-extern char datatoc_workbench_image_lib_glsl[];
-extern char datatoc_workbench_matcap_lib_glsl[];
-extern char datatoc_workbench_material_lib_glsl[];
-extern char datatoc_workbench_shader_interface_lib_glsl[];
-extern char datatoc_workbench_world_light_lib_glsl[];
-
-extern char datatoc_gpu_shader_depth_only_frag_glsl[];
-extern char datatoc_common_obinfos_lib_glsl[];
-
-/* Maximum number of variations. */
-#define MAX_LIGHTING 3
-#define MAX_COLOR 3
-
-enum {
- VOLUME_SH_SLICE = 0,
- VOLUME_SH_COBA,
- VOLUME_SH_CUBIC,
-};
-
-#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1))
-
-static struct {
- struct GPUShader *opaque_prepass_sh_cache[GPU_SHADER_CFG_LEN][WORKBENCH_DATATYPE_MAX][MAX_COLOR];
- struct GPUShader *transp_prepass_sh_cache[GPU_SHADER_CFG_LEN][WORKBENCH_DATATYPE_MAX]
- [MAX_LIGHTING][MAX_COLOR];
-
- struct GPUShader *opaque_composite_sh[MAX_LIGHTING];
- struct GPUShader *oit_resolve_sh;
- struct GPUShader *outline_sh;
- struct GPUShader *merge_infront_sh;
-
- struct GPUShader *shadow_depth_pass_sh[2];
- struct GPUShader *shadow_depth_fail_sh[2][2];
-
- struct GPUShader *cavity_sh[2][2];
-
- struct GPUShader *dof_prepare_sh;
- struct GPUShader *dof_downsample_sh;
- struct GPUShader *dof_blur1_sh;
- struct GPUShader *dof_blur2_sh;
- struct GPUShader *dof_resolve_sh;
-
- struct GPUShader *aa_accum_sh;
- struct GPUShader *smaa_sh[3];
-
- struct GPUShader *volume_sh[2][2][3][2];
-
- struct DRWShaderLibrary *lib;
-} e_data = {{{{NULL}}}};
-
-void workbench_shader_library_ensure(void)
-{
- if (e_data.lib == NULL) {
- e_data.lib = DRW_shader_library_create();
- /* NOTE: These need 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);
- DRW_SHADER_LIB_ADD(e_data.lib, common_obinfos_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_shader_interface_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_common_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_image_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_material_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_data_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_matcap_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_cavity_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_curvature_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_world_light_lib);
- }
-}
-
-static char *workbench_build_defines(
- WORKBENCH_PrivateData *wpd, bool textured, bool tiled, bool cavity, bool curvature)
-{
- char *str = NULL;
-
- DynStr *ds = BLI_dynstr_new();
-
- if (wpd && wpd->shading.light == V3D_LIGHTING_STUDIO) {
- BLI_dynstr_append(ds, "#define V3D_LIGHTING_STUDIO\n");
- }
- else if (wpd && wpd->shading.light == V3D_LIGHTING_MATCAP) {
- BLI_dynstr_append(ds, "#define V3D_LIGHTING_MATCAP\n");
- }
- else {
- BLI_dynstr_append(ds, "#define V3D_LIGHTING_FLAT\n");
- }
-
- if (NORMAL_ENCODING_ENABLED()) {
- BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n");
- }
-
- if (textured) {
- BLI_dynstr_append(ds, "#define V3D_SHADING_TEXTURE_COLOR\n");
- }
- if (tiled) {
- BLI_dynstr_append(ds, "#define TEXTURE_IMAGE_ARRAY\n");
- }
- if (cavity) {
- BLI_dynstr_append(ds, "#define USE_CAVITY\n");
- }
- if (curvature) {
- BLI_dynstr_append(ds, "#define USE_CURVATURE\n");
- }
-
- str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static int workbench_color_index(WORKBENCH_PrivateData *UNUSED(wpd), bool textured, bool tiled)
-{
- BLI_assert(2 < MAX_COLOR);
- return (textured) ? (tiled ? 2 : 1) : 0;
-}
-
-static GPUShader *workbench_shader_get_ex(WORKBENCH_PrivateData *wpd,
- bool transp,
- eWORKBENCH_DataType datatype,
- bool textured,
- bool tiled)
-{
- int color = workbench_color_index(wpd, textured, tiled);
- int light = wpd->shading.light;
- BLI_assert(light < MAX_LIGHTING);
- struct GPUShader **shader =
- (transp) ? &e_data.transp_prepass_sh_cache[wpd->sh_cfg][datatype][light][color] :
- &e_data.opaque_prepass_sh_cache[wpd->sh_cfg][datatype][color];
-
- if (*shader == NULL) {
- char *defines = workbench_build_defines(wpd, textured, tiled, false, false);
-
- char *frag_file = transp ? datatoc_workbench_transparent_accum_frag_glsl :
- datatoc_workbench_prepass_frag_glsl;
- char *frag_src = DRW_shader_library_create_shader_string(e_data.lib, frag_file);
-
- char *vert_file = (datatype == WORKBENCH_DATATYPE_HAIR) ?
- datatoc_workbench_prepass_hair_vert_glsl :
- ((datatype == WORKBENCH_DATATYPE_POINTCLOUD) ?
- datatoc_workbench_prepass_pointcloud_vert_glsl :
- datatoc_workbench_prepass_vert_glsl);
- char *vert_src = DRW_shader_library_create_shader_string(e_data.lib, vert_file);
-
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[wpd->sh_cfg];
-
- *shader = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, vert_src, NULL},
- .frag = (const char *[]){frag_src, NULL},
- .defs = (const char *[]){sh_cfg_data->def,
- defines,
- transp ? "#define TRANSPARENT_MATERIAL\n" :
- "#define OPAQUE_MATERIAL\n",
- (datatype == WORKBENCH_DATATYPE_POINTCLOUD) ?
- "#define UNIFORM_RESOURCE_ID\n"
- "#define INSTANCED_ATTR\n" :
- NULL,
- NULL},
- });
-
- MEM_freeN(defines);
- MEM_freeN(frag_src);
- MEM_freeN(vert_src);
- }
- return *shader;
-}
-
-GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, eWORKBENCH_DataType datatype)
-{
- return workbench_shader_get_ex(wpd, false, datatype, false, false);
-}
-
-GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd,
- eWORKBENCH_DataType datatype,
- bool tiled)
-{
- return workbench_shader_get_ex(wpd, false, datatype, true, tiled);
-}
-
-GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd,
- eWORKBENCH_DataType datatype)
-{
- return workbench_shader_get_ex(wpd, true, datatype, false, false);
-}
-
-GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd,
- eWORKBENCH_DataType datatype,
- bool tiled)
-{
- return workbench_shader_get_ex(wpd, true, datatype, true, tiled);
-}
-
-GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd)
-{
- int light = wpd->shading.light;
- struct GPUShader **shader = &e_data.opaque_composite_sh[light];
- BLI_assert(light < MAX_LIGHTING);
-
- if (*shader == NULL) {
- char *defines = workbench_build_defines(wpd, false, false, false, false);
- char *frag = DRW_shader_library_create_shader_string(e_data.lib,
- datatoc_workbench_composite_frag_glsl);
-
- *shader = DRW_shader_create_fullscreen(frag, defines);
-
- MEM_freeN(defines);
- MEM_freeN(frag);
- }
- return *shader;
-}
-
-GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *UNUSED(wpd))
-{
- if (e_data.merge_infront_sh == NULL) {
- char *frag = DRW_shader_library_create_shader_string(
- e_data.lib, datatoc_workbench_merge_infront_frag_glsl);
-
- e_data.merge_infront_sh = DRW_shader_create_fullscreen(frag, NULL);
-
- MEM_freeN(frag);
- }
- return e_data.merge_infront_sh;
-}
-
-GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd)
-{
- if (e_data.oit_resolve_sh == NULL) {
- char *defines = workbench_build_defines(wpd, false, false, false, false);
-
- e_data.oit_resolve_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_transparent_resolve_frag_glsl, defines);
-
- MEM_freeN(defines);
- }
- return e_data.oit_resolve_sh;
-}
-
-static GPUShader *workbench_shader_shadow_pass_get_ex(bool depth_pass, bool manifold, bool cap)
-{
- struct GPUShader **shader = (depth_pass) ? &e_data.shadow_depth_pass_sh[manifold] :
- &e_data.shadow_depth_fail_sh[manifold][cap];
-
- if (*shader == NULL) {
-#if DEBUG_SHADOW_VOLUME
- const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl;
-#else
- const char *shadow_frag = datatoc_gpu_shader_depth_only_frag_glsl;
-#endif
-
- *shader = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_workbench_shadow_vert_glsl,
- NULL},
- .geom = (const char *[]){(cap) ? datatoc_workbench_shadow_caps_geom_glsl :
- datatoc_workbench_shadow_geom_glsl,
- NULL},
- .frag = (const char *[]){shadow_frag, NULL},
- .defs = (const char *[]){(depth_pass) ? "#define SHADOW_PASS\n" : "#define SHADOW_FAIL\n",
- (manifold) ? "" : "#define DOUBLE_MANIFOLD\n",
- NULL},
- });
- }
- return *shader;
-}
-
-GPUShader *workbench_shader_shadow_pass_get(bool manifold)
-{
- return workbench_shader_shadow_pass_get_ex(true, manifold, false);
-}
-
-GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap)
-{
- return workbench_shader_shadow_pass_get_ex(false, manifold, cap);
-}
-
-GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature)
-{
- BLI_assert(cavity || curvature);
- struct GPUShader **shader = &e_data.cavity_sh[cavity][curvature];
-
- if (*shader == NULL) {
- char *defines = workbench_build_defines(NULL, false, false, cavity, curvature);
- char *frag = DRW_shader_library_create_shader_string(
- e_data.lib, datatoc_workbench_effect_cavity_frag_glsl);
-
- *shader = DRW_shader_create_fullscreen(frag, defines);
-
- MEM_freeN(defines);
- MEM_freeN(frag);
- }
- return *shader;
-}
-
-GPUShader *workbench_shader_outline_get(void)
-{
- if (e_data.outline_sh == NULL) {
- char *frag = DRW_shader_library_create_shader_string(
- e_data.lib, datatoc_workbench_effect_outline_frag_glsl);
-
- e_data.outline_sh = DRW_shader_create_fullscreen(frag, NULL);
-
- MEM_freeN(frag);
- }
- return e_data.outline_sh;
-}
-
-void workbench_shader_depth_of_field_get(GPUShader **prepare_sh,
- GPUShader **downsample_sh,
- GPUShader **blur1_sh,
- GPUShader **blur2_sh,
- GPUShader **resolve_sh)
-{
- if (e_data.dof_prepare_sh == NULL) {
- e_data.dof_prepare_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define PREPARE\n");
- e_data.dof_downsample_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define DOWNSAMPLE\n");
-#if 0 /* TODO(fclem): finish COC min_max optimization */
- e_data.dof_flatten_v_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define FLATTEN_VERTICAL\n");
- e_data.dof_flatten_h_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define FLATTEN_HORIZONTAL\n");
- e_data.dof_dilate_v_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define DILATE_VERTICAL\n");
- e_data.dof_dilate_h_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define DILATE_HORIZONTAL\n");
-#endif
- e_data.dof_blur1_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define BLUR1\n");
- e_data.dof_blur2_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define BLUR2\n");
- e_data.dof_resolve_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define RESOLVE\n");
- }
-
- *prepare_sh = e_data.dof_prepare_sh;
- *downsample_sh = e_data.dof_downsample_sh;
- *blur1_sh = e_data.dof_blur1_sh;
- *blur2_sh = e_data.dof_blur2_sh;
- *resolve_sh = e_data.dof_resolve_sh;
-}
-
-GPUShader *workbench_shader_antialiasing_accumulation_get(void)
-{
- if (e_data.aa_accum_sh == NULL) {
- char *frag = DRW_shader_library_create_shader_string(e_data.lib,
- datatoc_workbench_effect_taa_frag_glsl);
-
- e_data.aa_accum_sh = DRW_shader_create_fullscreen(frag, NULL);
-
- MEM_freeN(frag);
- }
- return e_data.aa_accum_sh;
-}
-
-GPUShader *workbench_shader_antialiasing_get(int stage)
-{
- BLI_assert(stage < 3);
- if (!e_data.smaa_sh[stage]) {
- char stage_define[32];
- BLI_snprintf(stage_define, sizeof(stage_define), "#define SMAA_STAGE %d\n", stage);
-
- e_data.smaa_sh[stage] = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){
- "#define SMAA_INCLUDE_VS 1\n",
- "#define SMAA_INCLUDE_PS 0\n",
- "uniform vec4 viewportMetrics;\n",
- datatoc_common_smaa_lib_glsl,
- datatoc_workbench_effect_smaa_vert_glsl,
- NULL,
- },
- .frag =
- (const char *[]){
- "#define SMAA_INCLUDE_VS 0\n",
- "#define SMAA_INCLUDE_PS 1\n",
- "uniform vec4 viewportMetrics;\n",
- datatoc_common_smaa_lib_glsl,
- datatoc_workbench_effect_smaa_frag_glsl,
- NULL,
- },
- .defs =
- (const char *[]){
- "#define SMAA_GLSL_3\n",
- "#define SMAA_RT_METRICS viewportMetrics\n",
- "#define SMAA_PRESET_HIGH\n",
- "#define SMAA_LUMA_WEIGHT float4(1.0, 1.0, 1.0, 1.0)\n",
- "#define SMAA_NO_DISCARD\n",
- stage_define,
- NULL,
- },
- });
- }
- return e_data.smaa_sh[stage];
-}
-
-GPUShader *workbench_shader_volume_get(bool slice,
- bool coba,
- eWORKBENCH_VolumeInterpType interp_type,
- bool smoke)
-{
- GPUShader **shader = &e_data.volume_sh[slice][coba][interp_type][smoke];
-
- if (*shader == NULL) {
- DynStr *ds = BLI_dynstr_new();
-
- if (slice) {
- BLI_dynstr_append(ds, "#define VOLUME_SLICE\n");
- }
- if (coba) {
- BLI_dynstr_append(ds, "#define USE_COBA\n");
- }
- switch (interp_type) {
- case WORKBENCH_VOLUME_INTERP_LINEAR:
- BLI_dynstr_append(ds, "#define USE_TRILINEAR\n");
- break;
- case WORKBENCH_VOLUME_INTERP_CUBIC:
- BLI_dynstr_append(ds, "#define USE_TRICUBIC\n");
- break;
- case WORKBENCH_VOLUME_INTERP_CLOSEST:
- BLI_dynstr_append(ds, "#define USE_CLOSEST\n");
- break;
- }
- if (smoke) {
- BLI_dynstr_append(ds, "#define VOLUME_SMOKE\n");
- }
-
- char *defines = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
- char *vert = DRW_shader_library_create_shader_string(e_data.lib,
- datatoc_workbench_volume_vert_glsl);
- char *frag = DRW_shader_library_create_shader_string(e_data.lib,
- datatoc_workbench_volume_frag_glsl);
-
- *shader = DRW_shader_create(vert, NULL, frag, defines);
-
- MEM_freeN(vert);
- MEM_freeN(frag);
- MEM_freeN(defines);
- }
- return *shader;
-}
-
-void workbench_shader_free(void)
-{
- for (int j = 0; j < sizeof(e_data.opaque_prepass_sh_cache) / sizeof(void *); j++) {
- struct GPUShader **sh_array = &e_data.opaque_prepass_sh_cache[0][0][0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
- for (int j = 0; j < sizeof(e_data.transp_prepass_sh_cache) / sizeof(void *); j++) {
- struct GPUShader **sh_array = &e_data.transp_prepass_sh_cache[0][0][0][0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
- for (int j = 0; j < ARRAY_SIZE(e_data.opaque_composite_sh); j++) {
- struct GPUShader **sh_array = &e_data.opaque_composite_sh[0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
- for (int j = 0; j < ARRAY_SIZE(e_data.shadow_depth_pass_sh); j++) {
- struct GPUShader **sh_array = &e_data.shadow_depth_pass_sh[0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
- for (int j = 0; j < sizeof(e_data.shadow_depth_fail_sh) / sizeof(void *); j++) {
- struct GPUShader **sh_array = &e_data.shadow_depth_fail_sh[0][0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
- for (int j = 0; j < sizeof(e_data.cavity_sh) / sizeof(void *); j++) {
- struct GPUShader **sh_array = &e_data.cavity_sh[0][0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
- for (int j = 0; j < ARRAY_SIZE(e_data.smaa_sh); j++) {
- struct GPUShader **sh_array = &e_data.smaa_sh[0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
- for (int j = 0; j < sizeof(e_data.volume_sh) / sizeof(void *); j++) {
- struct GPUShader **sh_array = &e_data.volume_sh[0][0][0][0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
-
- DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh);
- DRW_SHADER_FREE_SAFE(e_data.outline_sh);
- DRW_SHADER_FREE_SAFE(e_data.merge_infront_sh);
-
- DRW_SHADER_FREE_SAFE(e_data.dof_prepare_sh);
- DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh);
- DRW_SHADER_FREE_SAFE(e_data.dof_blur1_sh);
- DRW_SHADER_FREE_SAFE(e_data.dof_blur2_sh);
- DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh);
-
- DRW_SHADER_FREE_SAFE(e_data.aa_accum_sh);
-
- DRW_SHADER_LIB_FREE_SAFE(e_data.lib);
-}
diff --git a/source/blender/draw/engines/workbench/workbench_shader.cc b/source/blender/draw/engines/workbench/workbench_shader.cc
new file mode 100644
index 00000000000..b38286303f1
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_shader.cc
@@ -0,0 +1,444 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include <string>
+
+#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[];
+extern char datatoc_common_smaa_lib_glsl[];
+
+extern char datatoc_workbench_prepass_vert_glsl[];
+extern char datatoc_workbench_prepass_hair_vert_glsl[];
+extern char datatoc_workbench_prepass_pointcloud_vert_glsl[];
+extern char datatoc_workbench_prepass_frag_glsl[];
+
+extern char datatoc_workbench_effect_cavity_frag_glsl[];
+extern char datatoc_workbench_effect_outline_frag_glsl[];
+extern char datatoc_workbench_effect_dof_frag_glsl[];
+extern char datatoc_workbench_effect_taa_frag_glsl[];
+extern char datatoc_workbench_effect_smaa_frag_glsl[];
+extern char datatoc_workbench_effect_smaa_vert_glsl[];
+
+extern char datatoc_workbench_composite_frag_glsl[];
+
+extern char datatoc_workbench_transparent_accum_frag_glsl[];
+extern char datatoc_workbench_transparent_resolve_frag_glsl[];
+
+extern char datatoc_workbench_merge_infront_frag_glsl[];
+
+extern char datatoc_workbench_shadow_vert_glsl[];
+extern char datatoc_workbench_shadow_geom_glsl[];
+extern char datatoc_workbench_shadow_caps_geom_glsl[];
+extern char datatoc_workbench_shadow_debug_frag_glsl[];
+
+extern char datatoc_workbench_volume_vert_glsl[];
+extern char datatoc_workbench_volume_frag_glsl[];
+
+extern char datatoc_workbench_cavity_lib_glsl[];
+extern char datatoc_workbench_common_lib_glsl[];
+extern char datatoc_workbench_curvature_lib_glsl[];
+extern char datatoc_workbench_data_lib_glsl[];
+extern char datatoc_workbench_image_lib_glsl[];
+extern char datatoc_workbench_matcap_lib_glsl[];
+extern char datatoc_workbench_material_lib_glsl[];
+extern char datatoc_workbench_world_light_lib_glsl[];
+
+extern char datatoc_gpu_shader_depth_only_frag_glsl[];
+extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
+
+/* Maximum number of variations. */
+#define MAX_LIGHTING 3
+
+enum eWORKBENCH_TextureType {
+ TEXTURE_SH_NONE = 0,
+ TEXTURE_SH_SINGLE,
+ TEXTURE_SH_TILED,
+ TEXTURE_SH_MAX,
+};
+
+static struct {
+ struct GPUShader
+ *opaque_prepass_sh_cache[GPU_SHADER_CFG_LEN][WORKBENCH_DATATYPE_MAX][TEXTURE_SH_MAX];
+ struct GPUShader *transp_prepass_sh_cache[GPU_SHADER_CFG_LEN][WORKBENCH_DATATYPE_MAX]
+ [MAX_LIGHTING][TEXTURE_SH_MAX];
+
+ struct GPUShader *opaque_composite_sh[MAX_LIGHTING];
+ struct GPUShader *oit_resolve_sh;
+ struct GPUShader *outline_sh;
+ struct GPUShader *merge_infront_sh;
+
+ struct GPUShader *shadow_depth_pass_sh[2];
+ struct GPUShader *shadow_depth_fail_sh[2][2];
+
+ struct GPUShader *cavity_sh[2][2];
+
+ struct GPUShader *dof_prepare_sh;
+ struct GPUShader *dof_downsample_sh;
+ struct GPUShader *dof_blur1_sh;
+ struct GPUShader *dof_blur2_sh;
+ struct GPUShader *dof_resolve_sh;
+
+ struct GPUShader *aa_accum_sh;
+ struct GPUShader *smaa_sh[3];
+
+ struct GPUShader *volume_sh[2][2][3][2];
+
+} e_data = {{{{NULL}}}};
+
+/* -------------------------------------------------------------------- */
+/** \name Conversions
+ * \{ */
+
+static const char *workbench_lighting_mode_to_str(int light)
+{
+ switch (light) {
+ default:
+ BLI_assert_msg(0, "Error: Unknown lighting mode.");
+ ATTR_FALLTHROUGH;
+ case V3D_LIGHTING_STUDIO:
+ return "_studio";
+ case V3D_LIGHTING_MATCAP:
+ return "_matcap";
+ case V3D_LIGHTING_FLAT:
+ return "_flat";
+ return "";
+ }
+}
+
+static const char *workbench_datatype_mode_to_str(eWORKBENCH_DataType datatype)
+{
+ switch (datatype) {
+ default:
+ BLI_assert_msg(0, "Error: Unknown data mode.");
+ ATTR_FALLTHROUGH;
+ case WORKBENCH_DATATYPE_MESH:
+ return "_mesh";
+ case WORKBENCH_DATATYPE_HAIR:
+ return "_hair";
+ case WORKBENCH_DATATYPE_POINTCLOUD:
+ return "_ptcloud";
+ }
+}
+
+static const char *workbench_volume_interp_to_str(eWORKBENCH_VolumeInterpType interp_type)
+{
+ switch (interp_type) {
+ default:
+ BLI_assert_msg(0, "Error: Unknown lighting mode.");
+ ATTR_FALLTHROUGH;
+ case WORKBENCH_VOLUME_INTERP_LINEAR:
+ return "_linear";
+ case WORKBENCH_VOLUME_INTERP_CUBIC:
+ return "_cubic";
+ case WORKBENCH_VOLUME_INTERP_CLOSEST:
+ return "_closest";
+ }
+}
+
+static const char *workbench_texture_type_to_str(eWORKBENCH_TextureType tex_type)
+{
+ switch (tex_type) {
+ default:
+ BLI_assert_msg(0, "Error: Unknown texture mode.");
+ ATTR_FALLTHROUGH;
+ case TEXTURE_SH_NONE:
+ return "_tex_none";
+ case TEXTURE_SH_TILED:
+ return "_tex_tile";
+ case TEXTURE_SH_SINGLE:
+ return "_tex_single";
+ }
+}
+
+static eWORKBENCH_TextureType workbench_texture_type_get(bool textured, bool tiled)
+{
+ return textured ? (tiled ? TEXTURE_SH_TILED : TEXTURE_SH_SINGLE) : TEXTURE_SH_NONE;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Shader request
+ * \{ */
+
+static GPUShader *workbench_shader_get_ex(WORKBENCH_PrivateData *wpd,
+ bool transp,
+ eWORKBENCH_DataType datatype,
+ bool textured,
+ bool tiled)
+{
+ eWORKBENCH_TextureType tex_type = workbench_texture_type_get(textured, tiled);
+ int light = wpd->shading.light;
+ BLI_assert(light < MAX_LIGHTING);
+ struct GPUShader **shader =
+ (transp) ? &e_data.transp_prepass_sh_cache[wpd->sh_cfg][datatype][light][tex_type] :
+ &e_data.opaque_prepass_sh_cache[wpd->sh_cfg][datatype][tex_type];
+
+ if (*shader == nullptr) {
+ std::string create_info_name = "workbench";
+ create_info_name += (transp) ? "_transp" : "_opaque";
+ if (transp) {
+ create_info_name += workbench_lighting_mode_to_str(light);
+ }
+ create_info_name += workbench_datatype_mode_to_str(datatype);
+ create_info_name += workbench_texture_type_to_str(tex_type);
+ create_info_name += (wpd->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? "_clip" : "_no_clip";
+
+ *shader = GPU_shader_create_from_info_name(create_info_name.c_str());
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, eWORKBENCH_DataType datatype)
+{
+ return workbench_shader_get_ex(wpd, false, datatype, false, false);
+}
+
+GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd,
+ eWORKBENCH_DataType datatype,
+ bool tiled)
+{
+ return workbench_shader_get_ex(wpd, false, datatype, true, tiled);
+}
+
+GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd,
+ eWORKBENCH_DataType datatype)
+{
+ return workbench_shader_get_ex(wpd, true, datatype, false, false);
+}
+
+GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd,
+ eWORKBENCH_DataType datatype,
+ bool tiled)
+{
+ return workbench_shader_get_ex(wpd, true, datatype, true, tiled);
+}
+
+GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd)
+{
+ int light = wpd->shading.light;
+ struct GPUShader **shader = &e_data.opaque_composite_sh[light];
+ BLI_assert(light < MAX_LIGHTING);
+
+ if (*shader == nullptr) {
+ std::string create_info_name = "workbench_composite";
+ create_info_name += workbench_lighting_mode_to_str(light);
+ *shader = GPU_shader_create_from_info_name(create_info_name.c_str());
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *UNUSED(wpd))
+{
+ if (e_data.merge_infront_sh == nullptr) {
+ e_data.merge_infront_sh = GPU_shader_create_from_info_name("workbench_merge_infront");
+ }
+ return e_data.merge_infront_sh;
+}
+
+GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *UNUSED(wpd))
+{
+ if (e_data.oit_resolve_sh == nullptr) {
+ e_data.oit_resolve_sh = GPU_shader_create_from_info_name("workbench_transparent_resolve");
+ }
+ return e_data.oit_resolve_sh;
+}
+
+static GPUShader *workbench_shader_shadow_pass_get_ex(bool depth_pass, bool manifold, bool cap)
+{
+ struct GPUShader **shader = (depth_pass) ? &e_data.shadow_depth_pass_sh[manifold] :
+ &e_data.shadow_depth_fail_sh[manifold][cap];
+
+ if (*shader == nullptr) {
+ std::string create_info_name = "workbench_shadow";
+ create_info_name += (depth_pass) ? "_pass" : "_fail";
+ create_info_name += (manifold) ? "_manifold" : "_no_manifold";
+ create_info_name += (cap) ? "_caps" : "_no_caps";
+#if DEBUG_SHADOW_VOLUME
+ create_info_name += "_debug";
+#endif
+ *shader = GPU_shader_create_from_info_name(create_info_name.c_str());
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_shadow_pass_get(bool manifold)
+{
+ return workbench_shader_shadow_pass_get_ex(true, manifold, false);
+}
+
+GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap)
+{
+ return workbench_shader_shadow_pass_get_ex(false, manifold, cap);
+}
+
+GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature)
+{
+ BLI_assert(cavity || curvature);
+ struct GPUShader **shader = &e_data.cavity_sh[cavity][curvature];
+
+ if (*shader == nullptr) {
+ std::string create_info_name = "workbench_effect";
+ create_info_name += (cavity) ? "_cavity" : "";
+ create_info_name += (curvature) ? "_curvature" : "";
+ *shader = GPU_shader_create_from_info_name(create_info_name.c_str());
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_outline_get(void)
+{
+ if (e_data.outline_sh == nullptr) {
+ e_data.outline_sh = GPU_shader_create_from_info_name("workbench_effect_outline");
+ }
+ return e_data.outline_sh;
+}
+
+void workbench_shader_depth_of_field_get(GPUShader **prepare_sh,
+ GPUShader **downsample_sh,
+ GPUShader **blur1_sh,
+ GPUShader **blur2_sh,
+ GPUShader **resolve_sh)
+{
+ if (e_data.dof_prepare_sh == nullptr) {
+ e_data.dof_prepare_sh = GPU_shader_create_from_info_name("workbench_effect_dof_prepare");
+ e_data.dof_downsample_sh = GPU_shader_create_from_info_name("workbench_effect_dof_downsample");
+#if 0 /* TODO(fclem): finish COC min_max optimization */
+ e_data.dof_flatten_v_sh = GPU_shader_create_from_info_name("workbench_effect_dof_flatten_v");
+ e_data.dof_flatten_h_sh = GPU_shader_create_from_info_name("workbench_effect_dof_flatten_h");
+ e_data.dof_dilate_v_sh = GPU_shader_create_from_info_name("workbench_effect_dof_dilate_v");
+ e_data.dof_dilate_h_sh = GPU_shader_create_from_info_name("workbench_effect_dof_dilate_h");
+#endif
+ e_data.dof_blur1_sh = GPU_shader_create_from_info_name("workbench_effect_dof_blur1");
+ e_data.dof_blur2_sh = GPU_shader_create_from_info_name("workbench_effect_dof_blur2");
+ e_data.dof_resolve_sh = GPU_shader_create_from_info_name("workbench_effect_dof_resolve");
+ }
+
+ *prepare_sh = e_data.dof_prepare_sh;
+ *downsample_sh = e_data.dof_downsample_sh;
+ *blur1_sh = e_data.dof_blur1_sh;
+ *blur2_sh = e_data.dof_blur2_sh;
+ *resolve_sh = e_data.dof_resolve_sh;
+}
+
+GPUShader *workbench_shader_antialiasing_accumulation_get(void)
+{
+ if (e_data.aa_accum_sh == nullptr) {
+ e_data.aa_accum_sh = GPU_shader_create_from_info_name("workbench_taa");
+ }
+ return e_data.aa_accum_sh;
+}
+
+GPUShader *workbench_shader_antialiasing_get(int stage)
+{
+ BLI_assert(stage < 3);
+ GPUShader **shader = &e_data.smaa_sh[stage];
+
+ if (*shader == nullptr) {
+ std::string create_info_name = "workbench_smaa_stage_";
+ create_info_name += std::to_string(stage);
+ *shader = GPU_shader_create_from_info_name(create_info_name.c_str());
+ }
+ return e_data.smaa_sh[stage];
+}
+
+GPUShader *workbench_shader_volume_get(bool slice,
+ bool coba,
+ eWORKBENCH_VolumeInterpType interp_type,
+ bool smoke)
+{
+ GPUShader **shader = &e_data.volume_sh[slice][coba][interp_type][smoke];
+
+ if (*shader == nullptr) {
+ std::string create_info_name = "workbench_volume";
+ create_info_name += (smoke) ? "_smoke" : "_object";
+ create_info_name += workbench_volume_interp_to_str(interp_type);
+ create_info_name += (coba) ? "_coba" : "_no_coba";
+ create_info_name += (slice) ? "_slice" : "_no_slice";
+ *shader = GPU_shader_create_from_info_name(create_info_name.c_str());
+ }
+ return *shader;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cleanup
+ * \{ */
+
+void workbench_shader_free(void)
+{
+ for (int j = 0; j < sizeof(e_data.opaque_prepass_sh_cache) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.opaque_prepass_sh_cache[0][0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.transp_prepass_sh_cache) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.transp_prepass_sh_cache[0][0][0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < ARRAY_SIZE(e_data.opaque_composite_sh); j++) {
+ struct GPUShader **sh_array = &e_data.opaque_composite_sh[0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < ARRAY_SIZE(e_data.shadow_depth_pass_sh); j++) {
+ struct GPUShader **sh_array = &e_data.shadow_depth_pass_sh[0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.shadow_depth_fail_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.shadow_depth_fail_sh[0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.cavity_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.cavity_sh[0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < ARRAY_SIZE(e_data.smaa_sh); j++) {
+ struct GPUShader **sh_array = &e_data.smaa_sh[0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.volume_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.volume_sh[0][0][0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+
+ DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_sh);
+ DRW_SHADER_FREE_SAFE(e_data.merge_infront_sh);
+
+ DRW_SHADER_FREE_SAFE(e_data.dof_prepare_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_blur1_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_blur2_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh);
+
+ DRW_SHADER_FREE_SAFE(e_data.aa_accum_sh);
+}
+
+/** \} */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/workbench_shader_shared.h
index 2e229d4d83a..0bfd5957834 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
+++ b/source/blender/draw/engines/workbench/workbench_shader_shared.h
@@ -1,20 +1,27 @@
+
+#ifndef GPU_SHADER
+# include "gpu_shader_shared_utils.h"
+#endif
+
+#define WORKBENCH_SHADER_SHARED_H
+
struct LightData {
- vec4 direction;
- vec4 specular_color;
- vec4 diffuse_color_wrap; /* rgb: diffuse col a: wrapped lighting factor */
+ float4 direction;
+ float4 specular_color;
+ float4 diffuse_color_wrap; /* rgb: diffuse col a: wrapped lighting factor */
};
struct WorldData {
- vec4 viewport_size;
- vec4 object_outline_color;
- vec4 shadow_direction_vs;
+ float4 viewport_size;
+ float4 object_outline_color;
+ float4 shadow_direction_vs;
float shadow_focus;
float shadow_shift;
float shadow_mul;
float shadow_add;
/* - 16 bytes alignment - */
LightData lights[4];
- vec4 ambient_color;
+ float4 ambient_color;
int cavity_sample_start;
int cavity_sample_end;
@@ -38,8 +45,3 @@ struct WorldData {
};
#define viewport_size_inv viewport_size.zw
-
-layout(std140) uniform world_block
-{
- WorldData world_data;
-};
diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c
index ad855cb284c..2f9b85acf31 100644
--- a/source/blender/draw/engines/workbench/workbench_transparent.c
+++ b/source/blender/draw/engines/workbench/workbench_transparent.c
@@ -65,7 +65,7 @@ void workbench_transparent_engine_init(WORKBENCH_Data *data)
static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp)
{
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false);
if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
@@ -76,8 +76,8 @@ static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd,
struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture;
const bool use_spec = workbench_is_specular_highlight_enabled(wpd);
spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx;
- DRW_shgroup_uniform_texture(grp, "matcapDiffuseImage", diff_tx);
- DRW_shgroup_uniform_texture(grp, "matcapSpecularImage", spec_tx);
+ DRW_shgroup_uniform_texture(grp, "matcap_diffuse_tx", diff_tx);
+ DRW_shgroup_uniform_texture(grp, "matcap_specular_tx", spec_tx);
}
}
@@ -111,25 +111,25 @@ void workbench_transparent_cache_init(WORKBENCH_Data *vedata)
sh = workbench_shader_transparent_get(wpd, data);
wpd->prepass[transp][infront][data].common_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1);
workbench_transparent_lighting_uniforms(wpd, grp);
wpd->prepass[transp][infront][data].vcol_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */
sh = workbench_shader_transparent_image_get(wpd, data, false);
wpd->prepass[transp][infront][data].image_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
workbench_transparent_lighting_uniforms(wpd, grp);
sh = workbench_shader_transparent_image_get(wpd, data, true);
wpd->prepass[transp][infront][data].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
workbench_transparent_lighting_uniforms(wpd, grp);
}
@@ -149,8 +149,6 @@ void workbench_transparent_cache_init(WORKBENCH_Data *vedata)
}
}
-/* Redraw the transparent passes but with depth test
- * to output correct outline IDs and depth. */
void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data)
{
WORKBENCH_PrivateData *wpd = data->stl->wpd;
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index daeadce3059..9632060d69c 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -129,7 +129,7 @@ static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata,
float step_length = max_ff(1e-16f, dim[axis] * 0.05f);
grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
DRW_shgroup_uniform_float_copy(grp, "slicePosition", fds->slice_depth);
DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis);
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
@@ -148,7 +148,7 @@ static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata,
step_length = len_v3(dim);
grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice);
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs);
@@ -272,7 +272,7 @@ static void workbench_volume_object_cache_populate(WORKBENCH_Data *vedata,
const float slice_position = volume->display.slice_depth;
grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
DRW_shgroup_uniform_float_copy(grp, "slicePosition", slice_position);
DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis);
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
@@ -299,7 +299,7 @@ static void workbench_volume_object_cache_populate(WORKBENCH_Data *vedata,
/* Set uniforms. */
grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice);
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs);
diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh
new file mode 100644
index 00000000000..7a9bdb377fe
--- /dev/null
+++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh
@@ -0,0 +1,812 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2022, Blender Foundation.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup draw
+ *
+ * Wrapper classes that make it easier to use GPU objects in C++.
+ *
+ * All Buffers need to be sent to GPU memory before being used. This is done by using the
+ * `push_update()`.
+ *
+ * A Storage[Array]Buffer can hold much more data than a Uniform[Array]Buffer
+ * which can only holds 16KB of data.
+ *
+ * All types are not copyable and Buffers are not Movable.
+ *
+ * `drw::UniformArrayBuffer<T, len>`
+ * Uniform buffer object containing an array of T with len elements.
+ * Data can be accessed using the [] operator.
+ *
+ * `drw::UniformBuffer<T>`
+ * A uniform buffer object class inheriting from T.
+ * Data can be accessed just like a normal T object.
+ *
+ * `drw::StorageArrayBuffer<T, len>`
+ * Storage buffer object containing an array of T with len elements.
+ * The item count can be changed after creation using `resize()`.
+ * However, this requires the invalidation of the whole buffer and
+ * discarding all data inside it.
+ * Data can be accessed using the [] operator.
+ *
+ * `drw::StorageBuffer<T>`
+ * A storage buffer object class inheriting from T.
+ * Data can be accessed just like a normal T object.
+ *
+ * `drw::Texture`
+ * A simple wrapper to #GPUTexture. A #drw::Texture can be created without allocation.
+ * The `ensure_[1d|2d|3d|cube][_array]()` method is here to make sure the underlying texture
+ * will meet the requirements and create (or recreate) the #GPUTexture if needed.
+ *
+ * `drw::TextureFromPool`
+ * A GPUTexture from the viewport texture pool. This texture can be shared with other engines
+ * and its content is undefined when acquiring it.
+ * A #drw::TextureFromPool is acquired for rendering using `acquire()` and released once the
+ * rendering is done using `release()`. The same texture can be acquired & released multiple
+ * time in one draw loop.
+ * The `sync()` method *MUST* be called once during the cache populate (aka: Sync) phase.
+ *
+ * `drw::Framebuffer`
+ * Simple wrapper to #GPUFramebuffer that can be moved.
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "draw_texture_pool.h"
+
+#include "BLI_float4.hh"
+#include "BLI_int2.hh"
+#include "BLI_int3.hh"
+#include "BLI_int4.hh"
+#include "BLI_span.hh"
+#include "BLI_utildefines.h"
+#include "BLI_utility_mixins.hh"
+
+#include "GPU_framebuffer.h"
+#include "GPU_texture.h"
+#include "GPU_uniform_buffer.h"
+#include "GPU_vertex_buffer.h"
+
+namespace blender::draw {
+
+/* -------------------------------------------------------------------- */
+/** \name Implementation Details
+ * \{ */
+
+namespace detail {
+
+template<
+ /** Type of the values stored in this uniform buffer. */
+ typename T,
+ /** The number of values that can be stored in this uniform buffer. */
+ int64_t len,
+ /** True if the buffer only resides on GPU memory and cannot be accessed. */
+ bool device_only>
+class DataBuffer {
+ protected:
+ T *data_ = nullptr;
+ int64_t len_ = len;
+
+ BLI_STATIC_ASSERT((sizeof(T) % 16) == 0, "Type need to be aligned to size of float4.");
+
+ public:
+ /**
+ * Get the value at the given index. This invokes undefined behavior when the
+ * index is out of bounds.
+ */
+ const T &operator[](int64_t index) const
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ BLI_assert(index >= 0);
+ BLI_assert(index < len);
+ return data_[index];
+ }
+
+ T &operator[](int64_t index)
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ BLI_assert(index >= 0);
+ BLI_assert(index < len);
+ return data_[index];
+ }
+
+ /**
+ * Get a pointer to the beginning of the array.
+ */
+ const T *data() const
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ return data_;
+ }
+ T *data()
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ return data_;
+ }
+
+ /**
+ * Iterator
+ */
+ const T *begin() const
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ return data_;
+ }
+ const T *end() const
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ return data_ + len;
+ }
+
+ T *begin()
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ return data_;
+ }
+ T *end()
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ return data_ + len;
+ }
+
+ operator Span<T>() const
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ return Span<T>(data_, len);
+ }
+};
+
+template<typename T, int64_t len, bool device_only>
+class UniformCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable {
+ protected:
+ GPUUniformBuf *ubo_;
+
+#ifdef DEBUG
+ const char *name_ = typeid(T).name();
+#else
+ constexpr static const char *name_ = "UniformBuffer";
+#endif
+
+ public:
+ UniformCommon()
+ {
+ ubo_ = GPU_uniformbuf_create_ex(sizeof(T) * len, nullptr, name_);
+ }
+
+ ~UniformCommon()
+ {
+ GPU_uniformbuf_free(ubo_);
+ }
+
+ void push_update(void)
+ {
+ GPU_uniformbuf_update(ubo_, this->data_);
+ }
+
+ /* To be able to use it with DRW_shgroup_*_ref(). */
+ operator GPUUniformBuf *() const
+ {
+ return ubo_;
+ }
+
+ /* To be able to use it with DRW_shgroup_*_ref(). */
+ GPUUniformBuf **operator&()
+ {
+ return &ubo_;
+ }
+};
+
+template<typename T, int64_t len, bool device_only>
+class StorageCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable {
+ protected:
+ /* Use vertex buffer for now. Until there is a complete GPUStorageBuf implementation. */
+ GPUVertBuf *ssbo_;
+
+#ifdef DEBUG
+ const char *name_ = typeid(T).name();
+#else
+ constexpr static const char *name_ = "StorageBuffer";
+#endif
+
+ public:
+ StorageCommon()
+ {
+ init(len);
+ }
+
+ ~StorageCommon()
+ {
+ GPU_vertbuf_discard(ssbo_);
+ }
+
+ void resize(int64_t new_size)
+ {
+ BLI_assert(new_size > 0);
+ if (new_size != this->len_) {
+ GPU_vertbuf_discard(ssbo_);
+ this->init(new_size);
+ }
+ }
+
+ operator GPUVertBuf *() const
+ {
+ return ssbo_;
+ }
+ /* To be able to use it with DRW_shgroup_*_ref(). */
+ GPUVertBuf **operator&()
+ {
+ return &ssbo_;
+ }
+
+ private:
+ void init(int64_t new_size)
+ {
+ this->len_ = new_size;
+
+ GPUVertFormat format = {0};
+ GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+
+ GPUUsageType usage = device_only ? GPU_USAGE_DEVICE_ONLY : GPU_USAGE_DYNAMIC;
+ ssbo_ = GPU_vertbuf_create_with_format_ex(&format, usage);
+ GPU_vertbuf_data_alloc(ssbo_, divide_ceil_u(sizeof(T) * this->len_, 4));
+ if (!device_only) {
+ this->data_ = (T *)GPU_vertbuf_get_data(ssbo_);
+ GPU_vertbuf_use(ssbo_);
+ }
+ }
+};
+
+} // namespace detail
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Uniform Buffers
+ * \{ */
+
+template<
+ /** Type of the values stored in this uniform buffer. */
+ typename T,
+ /** The number of values that can be stored in this uniform buffer. */
+ int64_t len
+ /** True if the buffer only resides on GPU memory and cannot be accessed. */
+ /* TODO(fclem): Currently unsupported. */
+ /* bool device_only = false */>
+class UniformArrayBuffer : public detail::UniformCommon<T, len, false> {
+ public:
+ UniformArrayBuffer()
+ {
+ /* TODO(fclem) We should map memory instead. */
+ this->data_ = MEM_mallocN_aligned(this->name_);
+ }
+};
+
+template<
+ /** Type of the values stored in this uniform buffer. */
+ typename T
+ /** True if the buffer only resides on GPU memory and cannot be accessed. */
+ /* TODO(fclem): Currently unsupported. */
+ /* bool device_only = false */>
+class UniformBuffer : public T, public detail::UniformCommon<T, 1, false> {
+ public:
+ UniformBuffer()
+ {
+ /* TODO(fclem) How could we map this? */
+ this->data_ = static_cast<T *>(this);
+ }
+
+ UniformBuffer<T> &operator=(const T &other)
+ {
+ *static_cast<T *>(this) = other;
+ return *this;
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Storage Buffer
+ * \{ */
+
+template<
+ /** Type of the values stored in this uniform buffer. */
+ typename T,
+ /** The number of values that can be stored in this uniform buffer. */
+ int64_t len,
+ /** True if created on device and no memory host memory is allocated. */
+ bool device_only = false>
+class StorageArrayBuffer : public detail::StorageCommon<T, len, device_only> {
+ public:
+ void push_update(void)
+ {
+ BLI_assert(!device_only);
+ /* Get the data again to tag for update. The actual pointer should not
+ * change. */
+ this->data_ = (T *)GPU_vertbuf_get_data(this->ssbo_);
+ GPU_vertbuf_use(this->ssbo_);
+ }
+};
+
+template<
+ /** Type of the values stored in this uniform buffer. */
+ typename T,
+ /** True if created on device and no memory host memory is allocated. */
+ bool device_only = false>
+class StorageBuffer : public T, public detail::StorageCommon<T, 1, device_only> {
+ public:
+ void push_update(void)
+ {
+ BLI_assert(!device_only);
+ /* TODO(fclem): Avoid a full copy. */
+ T &vert_data = *(T *)GPU_vertbuf_get_data(this->ssbo_);
+ vert_data = *this;
+
+ GPU_vertbuf_use(this->ssbo_);
+ }
+
+ StorageBuffer<T> &operator=(const T &other)
+ {
+ *static_cast<T *>(this) = other;
+ return *this;
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Texture
+ * \{ */
+
+class Texture : NonCopyable {
+ protected:
+ GPUTexture *tx_ = nullptr;
+ const char *name_;
+
+ public:
+ Texture(const char *name = "gpu::Texture") : name_(name)
+ {
+ }
+
+ Texture(const char *name,
+ eGPUTextureFormat format,
+ int extent,
+ float *data = nullptr,
+ bool cubemap = false,
+ int mips = 1)
+ : name_(name)
+ {
+ tx_ = create(extent, 0, 0, mips, format, data, false, cubemap);
+ }
+
+ Texture(const char *name,
+ eGPUTextureFormat format,
+ int extent,
+ int layers,
+ float *data = nullptr,
+ bool cubemap = false,
+ int mips = 1)
+ : name_(name)
+ {
+ tx_ = create(extent, layers, 0, mips, format, data, true, cubemap);
+ }
+
+ Texture(
+ const char *name, eGPUTextureFormat format, int2 extent, float *data = nullptr, int mips = 1)
+ : name_(name)
+ {
+ tx_ = create(UNPACK2(extent), 0, mips, format, data, false, false);
+ }
+
+ Texture(const char *name,
+ eGPUTextureFormat format,
+ int2 extent,
+ int layers,
+ float *data = nullptr,
+ int mips = 1)
+ : name_(name)
+ {
+ tx_ = create(UNPACK2(extent), layers, mips, format, data, true, false);
+ }
+
+ Texture(
+ const char *name, eGPUTextureFormat format, int3 extent, float *data = nullptr, int mips = 1)
+ : name_(name)
+ {
+ tx_ = create(UNPACK3(extent), mips, format, data, false, false);
+ }
+
+ ~Texture()
+ {
+ free();
+ }
+
+ /* To be able to use it with DRW_shgroup_uniform_texture(). */
+ operator GPUTexture *() const
+ {
+ BLI_assert(tx_ != nullptr);
+ return tx_;
+ }
+
+ /* To be able to use it with DRW_shgroup_uniform_texture_ref(). */
+ GPUTexture **operator&()
+ {
+ return &tx_;
+ }
+
+ Texture &operator=(Texture &&a)
+ {
+ if (*this != a) {
+ this->tx_ = a.tx_;
+ this->name_ = a.name_;
+ a.tx_ = nullptr;
+ }
+ return *this;
+ }
+
+ /**
+ * Ensure the texture has the correct properties. Recreating it if needed.
+ * Return true if a texture has been created.
+ */
+ bool ensure_1d(eGPUTextureFormat format, int extent, float *data = nullptr, int mips = 1)
+ {
+ return ensure_impl(extent, 0, 0, mips, format, data, false, false);
+ }
+
+ /**
+ * Ensure the texture has the correct properties. Recreating it if needed.
+ * Return true if a texture has been created.
+ */
+ bool ensure_1d_array(
+ eGPUTextureFormat format, int extent, int layers, float *data = nullptr, int mips = 1)
+ {
+ return ensure_impl(extent, layers, 0, mips, format, data, true, false);
+ }
+
+ /**
+ * Ensure the texture has the correct properties. Recreating it if needed.
+ * Return true if a texture has been created.
+ */
+ bool ensure_2d(eGPUTextureFormat format, const int2 &extent, float *data = nullptr, int mips = 1)
+ {
+ return ensure_impl(UNPACK2(extent), 0, mips, format, data, false, false);
+ }
+
+ /**
+ * Ensure the texture has the correct properties. Recreating it if needed.
+ * Return true if a texture has been created.
+ */
+ bool ensure_2d_array(eGPUTextureFormat format,
+ const int2 &extent,
+ int layers,
+ float *data = nullptr,
+ int mips = 1)
+ {
+ return ensure_impl(UNPACK2(extent), layers, mips, format, data, true, false);
+ }
+
+ /**
+ * Ensure the texture has the correct properties. Recreating it if needed.
+ * Return true if a texture has been created.
+ */
+ bool ensure_3d(eGPUTextureFormat format, const int3 &extent, float *data = nullptr, int mips = 1)
+ {
+ return ensure_impl(UNPACK3(extent), mips, format, data, false, false);
+ }
+
+ /**
+ * Ensure the texture has the correct properties. Recreating it if needed.
+ * Return true if a texture has been created.
+ */
+ bool ensure_cube(eGPUTextureFormat format, int extent, float *data = nullptr, int mips = 1)
+ {
+ return ensure_impl(extent, extent, 0, mips, format, data, false, true);
+ }
+
+ /**
+ * Ensure the texture has the correct properties. Recreating it if needed.
+ * Return true if a texture has been created.
+ */
+ bool ensure_cube_array(
+ eGPUTextureFormat format, int extent, int layers, float *data = nullptr, int mips = 1)
+ {
+ return ensure_impl(extent, extent, layers, mips, format, data, false, true);
+ }
+
+ /**
+ * Returns true if the texture has been allocated or acquired from the pool.
+ */
+ bool is_valid(void) const
+ {
+ return tx_ != nullptr;
+ }
+
+ int width(void) const
+ {
+ return GPU_texture_width(tx_);
+ }
+
+ int height(void) const
+ {
+ return GPU_texture_height(tx_);
+ }
+
+ bool depth(void) const
+ {
+ return GPU_texture_depth(tx_);
+ }
+
+ bool is_stencil(void) const
+ {
+ return GPU_texture_stencil(tx_);
+ }
+
+ bool is_integer(void) const
+ {
+ return GPU_texture_integer(tx_);
+ }
+
+ bool is_cube(void) const
+ {
+ return GPU_texture_cube(tx_);
+ }
+
+ bool is_array(void) const
+ {
+ return GPU_texture_array(tx_);
+ }
+
+ int3 size(int miplvl = 0) const
+ {
+ int3 size(0);
+ GPU_texture_get_mipmap_size(tx_, miplvl, size);
+ return size;
+ }
+
+ /**
+ * Clear the entirety of the texture using one pixel worth of data.
+ */
+ void clear(float4 values)
+ {
+ GPU_texture_clear(tx_, GPU_DATA_FLOAT, &values[0]);
+ }
+
+ /**
+ * Clear the entirety of the texture using one pixel worth of data.
+ */
+ void clear(uint4 values)
+ {
+ GPU_texture_clear(tx_, GPU_DATA_UINT, &values[0]);
+ }
+
+ /**
+ * Clear the entirety of the texture using one pixel worth of data.
+ */
+ void clear(uchar4 values)
+ {
+ GPU_texture_clear(tx_, GPU_DATA_UBYTE, &values[0]);
+ }
+
+ /**
+ * Clear the entirety of the texture using one pixel worth of data.
+ */
+ void clear(int4 values)
+ {
+ GPU_texture_clear(tx_, GPU_DATA_INT, &values[0]);
+ }
+
+ /**
+ * Returns a buffer containing the texture data for the specified miplvl.
+ * The memory block needs to be manually freed by MEM_freeN().
+ */
+ template<typename T> T *read(eGPUDataFormat format, int miplvl = 0)
+ {
+ return reinterpret_cast<T *>(GPU_texture_read(tx_, format, miplvl));
+ }
+
+ void filter_mode(bool do_filter)
+ {
+ GPU_texture_filter_mode(tx_, do_filter);
+ }
+
+ /**
+ * Free the internal texture but not the #drw::Texture itself.
+ */
+ void free()
+ {
+ GPU_TEXTURE_FREE_SAFE(tx_);
+ }
+
+ private:
+ bool ensure_impl(int w,
+ int h = 0,
+ int d = 0,
+ int mips = 1,
+ eGPUTextureFormat format = GPU_RGBA8,
+ float *data = nullptr,
+ bool layered = false,
+ bool cubemap = false)
+
+ {
+ /* TODO(fclem) In the future, we need to check if mip_count did not change.
+ * For now it's ok as we always define all MIP level. */
+ if (tx_) {
+ int3 size = this->size();
+ if (size != int3(w, h, d) || GPU_texture_format(tx_) != format ||
+ GPU_texture_cube(tx_) != cubemap || GPU_texture_array(tx_) != layered) {
+ GPU_TEXTURE_FREE_SAFE(tx_);
+ }
+ }
+ if (tx_ == nullptr) {
+ tx_ = create(w, h, d, mips, format, data, layered, cubemap);
+ if (mips > 1) {
+ /* TODO(fclem) Remove once we have immutable storage or when mips are
+ * generated on creation. */
+ GPU_texture_generate_mipmap(tx_);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ GPUTexture *create(int w,
+ int h,
+ int d,
+ int mips,
+ eGPUTextureFormat format,
+ float *data,
+ bool layered,
+ bool cubemap)
+ {
+ if (h == 0) {
+ return GPU_texture_create_1d(name_, w, mips, format, data);
+ }
+ else if (d == 0) {
+ if (layered) {
+ return GPU_texture_create_1d_array(name_, w, h, mips, format, data);
+ }
+ else {
+ return GPU_texture_create_2d(name_, w, h, mips, format, data);
+ }
+ }
+ else if (cubemap) {
+ if (layered) {
+ return GPU_texture_create_cube_array(name_, w, d, mips, format, data);
+ }
+ else {
+ return GPU_texture_create_cube(name_, w, mips, format, data);
+ }
+ }
+ else {
+ if (layered) {
+ return GPU_texture_create_2d_array(name_, w, h, d, mips, format, data);
+ }
+ else {
+ return GPU_texture_create_3d(name_, w, h, d, mips, format, GPU_DATA_FLOAT, data);
+ }
+ }
+ }
+};
+
+class TextureFromPool : public Texture, NonMovable {
+ private:
+ GPUTexture *tx_tmp_saved_ = nullptr;
+
+ public:
+ TextureFromPool(const char *name = "gpu::Texture") : Texture(name){};
+
+ /* Always use `release()` after rendering. */
+ void acquire(int w, int h, eGPUTextureFormat format, void *owner_)
+ {
+ if (this->tx_ == nullptr) {
+ if (tx_tmp_saved_ != nullptr) {
+ this->tx_ = tx_tmp_saved_;
+ return;
+ }
+ DrawEngineType *owner = (DrawEngineType *)owner_;
+ this->tx_ = DRW_texture_pool_query_2d(w, h, format, owner);
+ }
+ }
+
+ void release(void)
+ {
+ tx_tmp_saved_ = this->tx_;
+ this->tx_ = nullptr;
+ }
+
+ /**
+ * Clears any reference. Workaround for pool texture not being able to release on demand.
+ * Needs to be called at during the sync phase.
+ */
+ void sync(void)
+ {
+ tx_tmp_saved_ = nullptr;
+ }
+
+ /** Remove methods that are forbidden with this type of textures. */
+ bool ensure_1d(int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_1d_array(int, int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_2d(int, int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_2d_array(int, int, int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_3d(int, int, int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_cube(int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_cube_array(int, int, int, eGPUTextureFormat, float *) = delete;
+ void filter_mode(bool) = delete;
+ void free() = delete;
+ /**
+ * Forbid the use of DRW_shgroup_uniform_texture.
+ * Use DRW_shgroup_uniform_texture_ref instead.
+ */
+ operator GPUTexture *() const = delete;
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Framebuffer
+ * \{ */
+
+class Framebuffer : NonCopyable {
+ private:
+ GPUFrameBuffer *fb_ = nullptr;
+ const char *name_;
+
+ public:
+ Framebuffer() : name_(""){};
+ Framebuffer(const char *name) : name_(name){};
+
+ ~Framebuffer()
+ {
+ GPU_FRAMEBUFFER_FREE_SAFE(fb_);
+ }
+
+ void ensure(GPUAttachment depth = GPU_ATTACHMENT_NONE,
+ GPUAttachment color1 = GPU_ATTACHMENT_NONE,
+ GPUAttachment color2 = GPU_ATTACHMENT_NONE,
+ GPUAttachment color3 = GPU_ATTACHMENT_NONE,
+ GPUAttachment color4 = GPU_ATTACHMENT_NONE,
+ GPUAttachment color5 = GPU_ATTACHMENT_NONE,
+ GPUAttachment color6 = GPU_ATTACHMENT_NONE,
+ GPUAttachment color7 = GPU_ATTACHMENT_NONE,
+ GPUAttachment color8 = GPU_ATTACHMENT_NONE)
+ {
+ GPU_framebuffer_ensure_config(
+ &fb_, {depth, color1, color2, color3, color4, color5, color6, color7, color8});
+ }
+
+ Framebuffer &operator=(Framebuffer &&a)
+ {
+ if (*this != a) {
+ this->fb_ = a.fb_;
+ this->name_ = a.name_;
+ a.fb_ = nullptr;
+ }
+ return *this;
+ }
+
+ operator GPUFrameBuffer *() const
+ {
+ return fb_;
+ }
+};
+
+/** \} */
+
+} // namespace blender::draw
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index cff92ccfd1c..ee5aa401c6e 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -122,7 +122,7 @@ typedef struct DrawEngineType {
void (*engine_init)(void *vedata);
void (*engine_free)(void);
- void (*instance_free)(void *vedata);
+ void (*instance_free)(void *instance_data);
void (*cache_init)(void *vedata);
void (*cache_populate)(void *vedata, struct Object *ob);
@@ -138,10 +138,6 @@ typedef struct DrawEngineType {
struct RenderLayer *layer,
const struct rcti *rect);
void (*store_metadata)(void *vedata, struct RenderResult *render_result);
-
- /** Index of the type in the list. Used for dupli data. Set at runtime. */
- /** TODO(fclem) Can we avoid this? */
- int index;
} DrawEngineType;
/* Textures */
@@ -152,9 +148,11 @@ typedef enum {
DRW_TEX_MIPMAP = (1 << 3),
} DRWTextureFlag;
-/* Textures from DRW_texture_pool_query_* have the options
- * DRW_TEX_FILTER for color float textures, and no options
- * for depth textures and integer textures. */
+/**
+ * Textures from `DRW_texture_pool_query_*` have the options
+ * #DRW_TEX_FILTER for color float textures, and no options
+ * for depth textures and integer textures.
+ */
struct GPUTexture *DRW_texture_pool_query_2d(int w,
int h,
eGPUTextureFormat format,
@@ -222,9 +220,9 @@ struct GPUShader *DRW_shader_create_with_shaderlib_ex(const char *vert,
struct GPUShader *DRW_shader_create_with_transform_feedback(const char *vert,
const char *geom,
const char *defines,
- const eGPUShaderTFBType prim_type,
+ eGPUShaderTFBType prim_type,
const char **varying_names,
- const int varying_count);
+ int varying_count);
struct GPUShader *DRW_shader_create_fullscreen_ex(const char *frag,
const char *defines,
const char *name);
@@ -268,13 +266,17 @@ void DRW_shader_free(struct GPUShader *shader);
DRWShaderLibrary *DRW_shader_library_create(void);
-/* Warning: Each library must be added after all its dependencies. */
-void DRW_shader_library_add_file(DRWShaderLibrary *lib,
- const char *lib_code,
- const char *lib_name);
+/**
+ * \warning Each library must be added after all its dependencies.
+ */
+void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const char *lib_name);
#define DRW_SHADER_LIB_ADD(lib, lib_name) \
DRW_shader_library_add_file(lib, datatoc_##lib_name##_glsl, STRINGIFY(lib_name) ".glsl")
+/**
+ * \return an allocN'ed string containing the shader code with its dependencies prepended.
+ * Caller must free the string with #MEM_freeN after use.
+ */
char *DRW_shader_library_create_shader_string(const DRWShaderLibrary *lib,
const char *shader_code);
@@ -288,11 +290,14 @@ void DRW_shader_library_free(DRWShaderLibrary *lib);
} while (0)
/* Batches */
-/* DRWState is a bitmask that stores the current render state and the desired render state. Based
+
+/**
+ * DRWState is a bit-mask that stores the current render state and the desired render state. Based
* on the differences the minimum state changes can be invoked to setup the desired render state.
*
* The Write Stencil, Stencil test, Depth test and Blend state options are mutual exclusive
- * therefore they aren't ordered as a bit mask. */
+ * therefore they aren't ordered as a bit mask.
+ */
typedef enum {
/** Write mask */
DRW_STATE_WRITE_DEPTH = (1 << 0),
@@ -322,7 +327,7 @@ typedef enum {
DRW_STATE_BLEND_ADD_FULL = (2 << 11),
/** Standard alpha blending. */
DRW_STATE_BLEND_ALPHA = (3 << 11),
- /** Use that if color is already premult by alpha. */
+ /** Use that if color is already pre-multiply by alpha. */
DRW_STATE_BLEND_ALPHA_PREMUL = (4 << 11),
DRW_STATE_BLEND_BACKGROUND = (5 << 11),
DRW_STATE_BLEND_OIT = (6 << 11),
@@ -392,7 +397,9 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial *material);
-/* return final visibility */
+/**
+ * Return final visibility.
+ */
typedef bool(DRWCallVisibilityFn)(bool vis_in, void *user_data);
void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
@@ -402,11 +409,15 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
bool bypass_culling,
void *user_data);
-/* If ob is NULL, unit modelmatrix is assumed and culling is bypassed. */
+/**
+ * If ob is NULL, unit modelmatrix is assumed and culling is bypassed.
+ */
#define DRW_shgroup_call(shgroup, geom, ob) \
DRW_shgroup_call_ex(shgroup, ob, NULL, geom, false, NULL)
-/* Same as DRW_shgroup_call but override the obmat. Not culled. */
+/**
+ * Same as #DRW_shgroup_call but override the `obmat`. Not culled.
+ */
#define DRW_shgroup_call_obmat(shgroup, geom, obmat) \
DRW_shgroup_call_ex(shgroup, NULL, obmat, geom, false, NULL)
@@ -415,12 +426,17 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
#define DRW_shgroup_call_with_callback(shgroup, geom, ob, user_data) \
DRW_shgroup_call_ex(shgroup, ob, NULL, geom, false, user_data)
-/* Same as DRW_shgroup_call but bypass culling even if ob is not NULL. */
+/**
+ * Same as #DRW_shgroup_call but bypass culling even if ob is not NULL.
+ */
#define DRW_shgroup_call_no_cull(shgroup, geom, ob) \
DRW_shgroup_call_ex(shgroup, ob, NULL, geom, true, NULL)
void DRW_shgroup_call_range(
DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint v_sta, uint v_ct);
+/**
+ * A count of 0 instance will use the default number of instance in the batch.
+ */
void DRW_shgroup_call_instance_range(
DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct);
@@ -434,12 +450,17 @@ void DRW_shgroup_call_compute_ref(DRWShadingGroup *shgroup, int groups_ref[3]);
void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_count);
void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_count);
void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *sh, Object *ob, uint tri_count);
-/* Warning: Only use with Shaders that have IN_PLACE_INSTANCES defined. */
+/**
+ * \warning Only use with Shaders that have `IN_PLACE_INSTANCES` defined.
+ * TODO: Should be removed.
+ */
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
uint count);
-/* Warning: Only use with Shaders that have INSTANCED_ATTR defined. */
+/**
+ * \warning Only use with Shaders that have INSTANCED_ATTR defined.
+ */
void DRW_shgroup_call_instances_with_attrs(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
@@ -469,13 +490,20 @@ void DRW_buffer_add_entry_array(DRWCallBuffer *callbuf, const void *attr[], uint
DRW_buffer_add_entry_array(buffer, array, (sizeof(array) / sizeof(*array))); \
} while (0)
-/* Can only be called during iter phase. */
+/**
+ * Can only be called during iteration phase.
+ */
uint32_t DRW_object_resource_id_get(Object *ob);
+/**
+ * State is added to #Pass.state while drawing.
+ * Use to temporarily enable draw options.
+ */
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
-/* Reminders:
+/**
+ * Reminders:
* - (compare_mask & reference) is what is tested against (compare_mask & stencil_value)
* stencil_value being the value stored in the stencil buffer.
* - (write-mask & reference) is what gets written if the test condition is fulfilled.
@@ -484,12 +512,16 @@ void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup,
uint write_mask,
uint reference,
uint compare_mask);
-/* TODO: remove this function. Obsolete version. mask is actually reference value. */
+/**
+ * TODO: remove this function. Obsolete version. mask is actually reference value.
+ */
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask);
void DRW_shgroup_barrier(DRWShadingGroup *shgroup, eGPUBarrier type);
-/* Issue a clear command. */
+/**
+ * Issue a clear command.
+ */
void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
eGPUFrameBufferBits channels,
uchar r,
@@ -535,7 +567,6 @@ void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup,
const char *name,
const float *value,
int arraysize);
-/* Boolean are expected to be 4bytes longs for opengl! */
void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup,
const char *name,
const int *value,
@@ -558,16 +589,20 @@ void DRW_shgroup_uniform_ivec4(DRWShadingGroup *shgroup,
int arraysize);
void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float (*value)[3]);
void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float (*value)[4]);
-/* Only to be used when image load store is supported (GPU_shader_image_load_store_support()). */
+/**
+ * Only to be used when image load store is supported (#GPU_shader_image_load_store_support()).
+ */
void DRW_shgroup_uniform_image(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex);
void DRW_shgroup_uniform_image_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex);
+
/* Store value instead of referencing it. */
-void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value);
+
+void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, int value);
void DRW_shgroup_uniform_ivec2_copy(DRWShadingGroup *shgroup, const char *name, const int *value);
void DRW_shgroup_uniform_ivec3_copy(DRWShadingGroup *shgroup, const char *name, const int *value);
void DRW_shgroup_uniform_ivec4_copy(DRWShadingGroup *shgroup, const char *name, const int *value);
-void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value);
-void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value);
+void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, bool value);
+void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, float value);
void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
@@ -584,14 +619,29 @@ void DRW_shgroup_vertex_buffer_ref(DRWShadingGroup *shgroup,
bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup);
-/* Passes */
+/* Passes. */
+
DRWPass *DRW_pass_create(const char *name, DRWState state);
+/**
+ * Create an instance of the original pass that will execute the same drawcalls but with its own
+ * #DRWState.
+ */
DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState state);
+/**
+ * Link two passes so that they are both rendered if the first one is being drawn.
+ */
void DRW_pass_link(DRWPass *first, DRWPass *second);
void DRW_pass_foreach_shgroup(DRWPass *pass,
void (*callback)(void *userData, DRWShadingGroup *shgroup),
void *userData);
+/**
+ * Sort Shading groups by decreasing Z of their first draw call.
+ * This is useful for order dependent effect such as alpha-blending.
+ */
void DRW_pass_sort_shgroup_z(DRWPass *pass);
+/**
+ * Reverse Shading group submission order.
+ */
void DRW_pass_sort_shgroup_reverse(DRWPass *pass);
bool DRW_pass_is_empty(DRWPass *pass);
@@ -600,59 +650,115 @@ bool DRW_pass_is_empty(DRWPass *pass);
#define DRW_PASS_INSTANCE_CREATE(pass, original, state) \
(pass = DRW_pass_create_instance(#pass, (original), state))
-/* Views */
+/* Views. */
+
+/**
+ * Create a view with culling.
+ */
DRWView *DRW_view_create(const float viewmat[4][4],
const float winmat[4][4],
const float (*culling_viewmat)[4],
const float (*culling_winmat)[4],
DRWCallVisibilityFn *visibility_fn);
+/**
+ * Create a view with culling done by another view.
+ */
DRWView *DRW_view_create_sub(const DRWView *parent_view,
const float viewmat[4][4],
const float winmat[4][4]);
+/**
+ * Update matrices of a view created with #DRW_view_create.
+ */
void DRW_view_update(DRWView *view,
const float viewmat[4][4],
const float winmat[4][4],
const float (*culling_viewmat)[4],
const float (*culling_winmat)[4]);
+/**
+ * Update matrices of a view created with #DRW_view_create_sub.
+ */
void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float winmat[4][4]);
+/**
+ * \return default view if it is a viewport render.
+ */
const DRWView *DRW_view_default_get(void);
+/**
+ * MUST only be called once per render and only in render mode. Sets default view.
+ */
void DRW_view_default_set(DRWView *view);
+/**
+ * \warning Only use in render AND only if you are going to set view_default again.
+ */
void DRW_view_reset(void);
-/* TODO(fclem) Cleanup: put set/get at the end of function. */
-void DRW_view_set_active(const DRWView *view);
+/**
+ * Set active view for rendering.
+ */
+void DRW_view_set_active(DRWView *view);
const DRWView *DRW_view_get_active(void);
+/**
+ * This only works if DRWPasses have been tagged with DRW_STATE_CLIP_PLANES,
+ * and if the shaders have support for it (see usage of gl_ClipDistance).
+ * \note planes must be in world space.
+ */
void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len);
void DRW_view_camtexco_set(DRWView *view, const float texco[4]);
void DRW_view_camtexco_get(const DRWView *view, float r_texco[4]);
/* For all getters, if view is NULL, default view is assumed. */
+
void DRW_view_winmat_get(const DRWView *view, float mat[4][4], bool inverse);
void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse);
void DRW_view_persmat_get(const DRWView *view, float mat[4][4], bool inverse);
+/**
+ * \return world space frustum corners.
+ */
void DRW_view_frustum_corners_get(const DRWView *view, BoundBox *corners);
+/**
+ * \return world space frustum sides as planes.
+ * See #draw_frustum_culling_planes_calc() for the plane order.
+ */
void DRW_view_frustum_planes_get(const DRWView *view, float planes[6][4]);
BoundSphere DRW_view_frustum_bsphere_get(const DRWView *view);
-/* These are in view-space, so negative if in perspective.
- * Extract near and far clip distance from the projection matrix. */
+/**
+ * These are in view-space, so negative if in perspective.
+ * Extract near and far clip distance from the projection matrix.
+ */
float DRW_view_near_distance_get(const DRWView *view);
float DRW_view_far_distance_get(const DRWView *view);
bool DRW_view_is_persp_get(const DRWView *view);
/* Culling, return true if object is inside view frustum. */
+
+/**
+ * \return True if the given BoundSphere intersect the current view frustum.
+ * bsphere must be in world space.
+ */
bool DRW_culling_sphere_test(const DRWView *view, const BoundSphere *bsphere);
+/**
+ * \return True if the given BoundBox intersect the current view frustum.
+ * bbox must be in world space.
+ */
bool DRW_culling_box_test(const DRWView *view, const BoundBox *bbox);
+/**
+ * \return True if the view frustum is inside or intersect the given plane.
+ * plane must be in world space.
+ */
bool DRW_culling_plane_test(const DRWView *view, const float plane[4]);
+/**
+ * Return True if the given box intersect the current view frustum.
+ * This function will have to be replaced when world space bb per objects is implemented.
+ */
bool DRW_culling_min_max_test(const DRWView *view, float obmat[4][4], float min[3], float max[3]);
void DRW_culling_frustum_corners_get(const DRWView *view, BoundBox *corners);
void DRW_culling_frustum_planes_get(const DRWView *view, float planes[6][4]);
-/* Viewport */
+/* Viewport. */
const float *DRW_viewport_size_get(void);
const float *DRW_viewport_invert_size_get(void);
@@ -672,18 +778,35 @@ void DRW_render_object_iter(void *vedata,
struct Object *ob,
struct RenderEngine *engine,
struct Depsgraph *depsgraph));
+/**
+ * Must run after all instance datas have been added.
+ */
void DRW_render_instance_buffer_finish(void);
+/**
+ * \warning Changing frame might free the #ViewLayerEngineData.
+ */
void DRW_render_set_time(struct RenderEngine *engine,
struct Depsgraph *depsgraph,
int frame,
float subframe);
+/**
+ * \warning only use for custom pipeline. 99% of the time, you don't want to use this.
+ */
void DRW_render_viewport_size_set(const int size[2]);
+/**
+ * Assume a valid GL context is bound (and that the gl_context_mutex has been acquired).
+ * This function only setup DST and execute the given function.
+ * \warning similar to DRW_render_to_image you cannot use default lists (dfbl & dtxl).
+ */
void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
struct Depsgraph *depsgraph,
void (*callback)(void *vedata, void *user_data),
void *user_data);
+/**
+ * Used when the render engine want to redo another cache populate inside the same render frame.
+ */
void DRW_cache_restart(void);
/* ViewLayers */
@@ -701,11 +824,26 @@ DrawData *DRW_drawdata_ensure(ID *id,
size_t size,
DrawDataInitCb init_cb,
DrawDataFreeCb free_cb);
+/**
+ * Return NULL if not a dupli or a pointer of pointer to the engine data.
+ */
void **DRW_duplidata_get(void *vedata);
-/* Settings */
+/* Settings. */
+
bool DRW_object_is_renderable(const struct Object *ob);
+/**
+ * Does `ob` needs to be rendered in edit mode.
+ *
+ * When using duplicate linked meshes, objects that are not in edit-mode will be drawn as
+ * it is in edit mode, when another object with the same mesh is in edit mode.
+ * This will not be the case when one of the objects are influenced by modifiers.
+ */
bool DRW_object_is_in_edit_mode(const struct Object *ob);
+/**
+ * Return whether this object is visible depending if
+ * we are rendering or drawing in the viewport.
+ */
int DRW_object_visibility_in_active_context(const struct Object *ob);
bool DRW_object_is_flat_normal(const struct Object *ob);
bool DRW_object_use_hide_faces(const struct Object *ob);
@@ -717,31 +855,76 @@ struct Object *DRW_object_get_dupli_parent(const struct Object *ob);
struct DupliObject *DRW_object_get_dupli(const struct Object *ob);
/* Draw commands */
+
void DRW_draw_pass(DRWPass *pass);
+/**
+ * Draw only a subset of shgroups. Used in special situations as grease pencil strokes.
+ */
void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group);
void DRW_draw_callbacks_pre_scene(void);
void DRW_draw_callbacks_post_scene(void);
+/**
+ * Reset state to not interfere with other UI draw-call.
+ */
void DRW_state_reset_ex(DRWState state);
void DRW_state_reset(void);
+/**
+ * Use with care, intended so selection code can override passes depth settings,
+ * which is important for selection to work properly.
+ *
+ * Should be set in main draw loop, cleared afterwards
+ */
void DRW_state_lock(DRWState state);
-/* Selection */
+/* Selection. */
+
void DRW_select_load_id(uint id);
-/* Draw State */
+/* Draw State. */
+
+/**
+ * When false, drawing doesn't output to a pixel buffer
+ * eg: Occlusion queries, or when we have setup a context to draw in already.
+ */
bool DRW_state_is_fbo(void);
+/**
+ * For when engines need to know if this is drawing for selection or not.
+ */
bool DRW_state_is_select(void);
bool DRW_state_is_material_select(void);
bool DRW_state_is_depth(void);
+/**
+ * Whether we are rendering for an image
+ */
bool DRW_state_is_image_render(void);
+/**
+ * Whether we are rendering only the render engine,
+ * or if we should also render the mode engines.
+ */
bool DRW_state_is_scene_render(void);
+/**
+ * Whether we are rendering simple opengl render
+ */
bool DRW_state_is_opengl_render(void);
bool DRW_state_is_playback(void);
+/**
+ * Is the user navigating the region.
+ */
bool DRW_state_is_navigating(void);
+/**
+ * Should text draw in this mode?
+ */
bool DRW_state_show_text(void);
+/**
+ * Should draw support elements
+ * Objects center, selection outline, probe data, ...
+ */
bool DRW_state_draw_support(void);
+/**
+ * Whether we should render the background
+ */
bool DRW_state_draw_background(void);
/* Avoid too many lookups while drawing */
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index a3a5d6b065a..a4564ce2668 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -47,6 +47,10 @@
#include "draw_cache_impl.h"
#include "draw_manager.h"
+/* -------------------------------------------------------------------- */
+/** \name Internal Defines
+ * \{ */
+
#define VCLASS_LIGHT_AREA_SHAPE (1 << 0)
#define VCLASS_LIGHT_SPOT_SHAPE (1 << 1)
#define VCLASS_LIGHT_SPOT_BLEND (1 << 2)
@@ -77,6 +81,12 @@
#define DRW_SPHERE_SHAPE_LATITUDE_HIGH 80
#define DRW_SPHERE_SHAPE_LONGITUDE_HIGH 60
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
typedef struct Vert {
float pos[3];
int class;
@@ -163,6 +173,8 @@ void DRW_shape_cache_free(void)
}
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Procedural Batches
* \{ */
@@ -354,7 +366,6 @@ static GPUVertBuf *sphere_wire_vbo(const float rad, int flag)
}
/* Quads */
-/* Use this one for rendering fullscreen passes. For 3D objects use DRW_cache_quad_get(). */
GPUBatch *DRW_cache_fullscreen_quad_get(void)
{
if (!SHC.drw_fullscreen_quad) {
@@ -388,7 +399,6 @@ GPUBatch *DRW_cache_fullscreen_quad_get(void)
return SHC.drw_fullscreen_quad;
}
-/* Just a regular quad with 4 vertices. */
GPUBatch *DRW_cache_quad_get(void)
{
if (!SHC.drw_quad) {
@@ -409,7 +419,6 @@ GPUBatch *DRW_cache_quad_get(void)
return SHC.drw_quad;
}
-/* Just a regular quad with 4 vertices - wires. */
GPUBatch *DRW_cache_quad_wires_get(void)
{
if (!SHC.drw_quad_wires) {
@@ -430,7 +439,6 @@ GPUBatch *DRW_cache_quad_wires_get(void)
return SHC.drw_quad_wires;
}
-/* Grid */
GPUBatch *DRW_cache_grid_get(void)
{
if (!SHC.drw_grid) {
@@ -769,6 +777,8 @@ GPUBatch *DRW_cache_normal_arrow_get(void)
return SHC.drw_normal_arrow;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Dummy VBO's
*
@@ -911,10 +921,9 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob)
}
}
-/* Returns the vertbuf used by shaded surface batch. */
GPUVertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob)
{
- Mesh *me = BKE_object_get_evaluated_mesh(ob);
+ Mesh *me = BKE_object_get_evaluated_mesh_no_subsurf(ob);
short type = (me != NULL) ? OB_MESH : ob->type;
switch (type) {
@@ -941,7 +950,7 @@ int DRW_cache_object_material_count_get(struct Object *ob)
{
short type = ob->type;
- Mesh *me = BKE_object_get_evaluated_mesh(ob);
+ Mesh *me = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (me != NULL && type != OB_POINTCLOUD) {
/* Some object types can have one data type in ob->data, but will be rendered as mesh.
* For point clouds this never happens. Ideally this check would happen at another level
@@ -951,7 +960,7 @@ int DRW_cache_object_material_count_get(struct Object *ob)
switch (type) {
case OB_MESH:
- return DRW_mesh_material_count_get((me != NULL) ? me : ob->data);
+ return DRW_mesh_material_count_get(ob, (me != NULL) ? me : ob->data);
case OB_CURVE:
case OB_SURF:
case OB_FONT:
@@ -1260,7 +1269,6 @@ GPUBatch *DRW_cache_empty_capsule_cap_get(void)
#undef NSEGMENTS
}
-/* Force Field */
GPUBatch *DRW_cache_field_wind_get(void)
{
#define CIRCLE_RESOL 32
@@ -1336,7 +1344,6 @@ GPUBatch *DRW_cache_field_vortex_get(void)
#undef SPIRAL_RESOL
}
-/* Screen-aligned circle. */
GPUBatch *DRW_cache_field_curve_get(void)
{
#define CIRCLE_RESOL 32
@@ -1425,7 +1432,6 @@ GPUBatch *DRW_cache_field_cone_limit_get(void)
#undef CIRCLE_RESOL
}
-/* Screen-aligned dashed circle */
GPUBatch *DRW_cache_field_sphere_limit_get(void)
{
#define CIRCLE_RESOL 32
@@ -2431,9 +2437,9 @@ GPUBatch *DRW_cache_bone_stick_get(void)
/* Bone rectangle */
pos[0] = 0.0f;
for (int i = 0; i < 6; i++) {
- pos[1] = (ELEM(i, 0, 3)) ? 0.0f : ((i < 3) ? 1.0f : -1.0f);
- flag = ((i < 2 || i > 4) ? POS_HEAD : POS_TAIL) | ((i == 0 || i == 3) ? 0 : COL_WIRE) |
- COL_BONE | POS_BONE;
+ pos[1] = ELEM(i, 0, 3) ? 0.0f : ((i < 3) ? 1.0f : -1.0f);
+ flag = ((i < 2 || i > 4) ? POS_HEAD : POS_TAIL) | (ELEM(i, 0, 3) ? 0 : COL_WIRE) | COL_BONE |
+ POS_BONE;
GPU_vertbuf_attr_set(vbo, attr_id.pos, v, pos);
GPU_vertbuf_attr_set(vbo, attr_id.flag, v, &flag);
GPU_indexbuf_add_generic_vert(&elb, v++);
@@ -2869,41 +2875,39 @@ GPUBatch *DRW_cache_mesh_surface_get(Object *ob)
GPUBatch *DRW_cache_mesh_surface_edges_get(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
- return DRW_mesh_batch_cache_get_surface_edges(ob->data);
+ return DRW_mesh_batch_cache_get_surface_edges(ob, ob->data);
}
-/* Return list of batches with length equal to max(1, totcol). */
GPUBatch **DRW_cache_mesh_surface_shaded_get(Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len)
{
BLI_assert(ob->type == OB_MESH);
- return DRW_mesh_batch_cache_get_surface_shaded(ob->data, gpumat_array, gpumat_array_len);
+ return DRW_mesh_batch_cache_get_surface_shaded(ob, ob->data, gpumat_array, gpumat_array_len);
}
-/* Return list of batches with length equal to max(1, totcol). */
GPUBatch **DRW_cache_mesh_surface_texpaint_get(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
- return DRW_mesh_batch_cache_get_surface_texpaint(ob->data);
+ return DRW_mesh_batch_cache_get_surface_texpaint(ob, ob->data);
}
GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
- return DRW_mesh_batch_cache_get_surface_texpaint_single(ob->data);
+ return DRW_mesh_batch_cache_get_surface_texpaint_single(ob, ob->data);
}
GPUBatch *DRW_cache_mesh_surface_vertpaint_get(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
- return DRW_mesh_batch_cache_get_surface_vertpaint(ob->data);
+ return DRW_mesh_batch_cache_get_surface_vertpaint(ob, ob->data);
}
GPUBatch *DRW_cache_mesh_surface_sculptcolors_get(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
- return DRW_mesh_batch_cache_get_surface_sculpt(ob->data);
+ return DRW_mesh_batch_cache_get_surface_sculpt(ob, ob->data);
}
GPUBatch *DRW_cache_mesh_surface_weights_get(Object *ob)
@@ -3017,7 +3021,7 @@ GPUBatch *DRW_cache_surf_surface_get(Object *ob)
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_surface(mesh_eval);
}
@@ -3030,7 +3034,7 @@ GPUBatch *DRW_cache_surf_edge_wire_get(Object *ob)
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_loose_edges(mesh_eval);
}
@@ -3043,7 +3047,7 @@ GPUBatch *DRW_cache_surf_face_wireframe_get(Object *ob)
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_wireframes_face(mesh_eval);
}
@@ -3055,7 +3059,7 @@ GPUBatch *DRW_cache_surf_edge_detection_get(Object *ob, bool *r_is_manifold)
{
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_edge_detection(mesh_eval, r_is_manifold);
}
@@ -3068,7 +3072,7 @@ GPUBatch *DRW_cache_surf_loose_edges_get(Object *ob)
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_loose_edges(mesh_eval);
}
@@ -3078,7 +3082,6 @@ GPUBatch *DRW_cache_surf_loose_edges_get(Object *ob)
return NULL;
}
-/* Return list of batches */
GPUBatch **DRW_cache_surf_surface_shaded_get(Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len)
@@ -3086,9 +3089,9 @@ GPUBatch **DRW_cache_surf_surface_shaded_get(Object *ob,
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
- return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len);
+ return DRW_mesh_batch_cache_get_surface_shaded(ob, mesh_eval, gpumat_array, gpumat_array_len);
}
return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len);
@@ -3148,6 +3151,8 @@ GPUBatch *DRW_cache_pointcloud_surface_get(Object *object)
return DRW_pointcloud_batch_cache_get_surface(object);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Volume
* \{ */
@@ -3275,7 +3280,6 @@ GPUBatch *DRW_cache_particles_get_prim(int type)
return NULL;
}
-/* 3D cursor */
GPUBatch *DRW_cache_cursor_get(bool crosshair_lines)
{
GPUBatch **drw_cursor = crosshair_lines ? &SHC.drw_cursor : &SHC.drw_cursor_only_circle;
@@ -3378,10 +3382,10 @@ GPUBatch *DRW_cache_cursor_get(bool crosshair_lines)
void drw_batch_cache_validate(Object *ob)
{
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
switch (ob->type) {
case OB_MESH:
- DRW_mesh_batch_cache_validate((Mesh *)ob->data);
+ DRW_mesh_batch_cache_validate(ob, (Mesh *)ob->data);
break;
case OB_CURVE:
case OB_FONT:
@@ -3389,7 +3393,7 @@ void drw_batch_cache_validate(Object *ob)
break;
case OB_SURF:
if (mesh_eval != NULL) {
- DRW_mesh_batch_cache_validate(mesh_eval);
+ DRW_mesh_batch_cache_validate(ob, mesh_eval);
}
DRW_curve_batch_cache_validate((Curve *)ob->data);
break;
@@ -3427,7 +3431,7 @@ void drw_batch_cache_generate_requested(Object *ob)
DRW_object_use_hide_faces(ob)) ||
((mode == CTX_MODE_EDIT_MESH) && DRW_object_is_in_edit_mode(ob))));
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
switch (ob->type) {
case OB_MESH:
DRW_mesh_batch_cache_create_requested(
@@ -3450,6 +3454,26 @@ void drw_batch_cache_generate_requested(Object *ob)
}
}
+void drw_batch_cache_generate_requested_evaluated_mesh(Object *ob)
+{
+ /* NOTE: Logic here is duplicated from #drw_batch_cache_generate_requested. */
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+ const enum eContextObjectMode mode = CTX_data_mode_enum_ex(
+ draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
+ const bool is_paint_mode = ELEM(
+ mode, CTX_MODE_SCULPT, CTX_MODE_PAINT_TEXTURE, CTX_MODE_PAINT_VERTEX, CTX_MODE_PAINT_WEIGHT);
+
+ const bool use_hide = ((ob->type == OB_MESH) &&
+ ((is_paint_mode && (ob == draw_ctx->obact) &&
+ DRW_object_use_hide_faces(ob)) ||
+ ((mode == CTX_MODE_EDIT_MESH) && DRW_object_is_in_edit_mode(ob))));
+
+ Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(ob);
+ DRW_mesh_batch_cache_create_requested(DST.task_graph, ob, mesh, scene, is_paint_mode, use_hide);
+}
+
void drw_batch_cache_generate_requested_delayed(Object *ob)
{
BLI_gset_add(DST.delayed_extraction, ob);
@@ -3457,7 +3481,7 @@ void drw_batch_cache_generate_requested_delayed(Object *ob)
void DRW_batch_cache_free_old(Object *ob, int ctime)
{
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
switch (ob->type) {
case OB_MESH:
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 5863ada2ccf..30e5a10df91 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -36,7 +36,9 @@ struct Volume;
struct VolumeGrid;
struct bGPDstroke;
-/* Shape resolution level of detail */
+/**
+ * Shape resolution level of detail.
+ */
typedef enum eDRWLevelOfDetail {
DRW_LOD_LOW = 0,
DRW_LOD_MEDIUM = 1,
@@ -52,19 +54,27 @@ struct GPUBatch *DRW_cache_cursor_get(bool crosshair_lines);
/* Common Shapes */
struct GPUBatch *DRW_cache_groundline_get(void);
+/* Grid */
struct GPUBatch *DRW_cache_grid_get(void);
+/**
+ * Use this one for rendering full-screen passes. For 3D objects use #DRW_cache_quad_get().
+ */
struct GPUBatch *DRW_cache_fullscreen_quad_get(void);
+/* Just a regular quad with 4 vertices. */
struct GPUBatch *DRW_cache_quad_get(void);
+/* Just a regular quad with 4 vertices - wires. */
struct GPUBatch *DRW_cache_quad_wires_get(void);
struct GPUBatch *DRW_cache_cube_get(void);
struct GPUBatch *DRW_cache_normal_arrow_get(void);
-struct GPUBatch *DRW_cache_sphere_get(const eDRWLevelOfDetail level_of_detail);
+struct GPUBatch *DRW_cache_sphere_get(eDRWLevelOfDetail level_of_detail);
/* Dummy VBOs */
+
struct GPUBatch *DRW_gpencil_dummy_buffer_get(void);
/* Common Object */
+
struct GPUBatch *DRW_cache_object_all_edges_get(struct Object *ob);
struct GPUBatch *DRW_cache_object_edge_detection_get(struct Object *ob, bool *r_is_manifold);
struct GPUBatch *DRW_cache_object_surface_get(struct Object *ob);
@@ -75,6 +85,9 @@ struct GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob,
struct GPUBatch *DRW_cache_object_face_wireframe_get(struct Object *ob);
int DRW_cache_object_material_count_get(struct Object *ob);
+/**
+ * Returns the vertbuf used by shaded surface batch.
+ */
struct GPUVertBuf *DRW_cache_object_pos_vertbuf_get(struct Object *ob);
/* Empties */
@@ -89,15 +102,23 @@ struct GPUBatch *DRW_cache_empty_capsule_cap_get(void);
struct GPUBatch *DRW_cache_empty_capsule_body_get(void);
/* Force Field */
+
struct GPUBatch *DRW_cache_field_wind_get(void);
struct GPUBatch *DRW_cache_field_force_get(void);
struct GPUBatch *DRW_cache_field_vortex_get(void);
+
+/* Screen-aligned circle. */
+
struct GPUBatch *DRW_cache_field_curve_get(void);
struct GPUBatch *DRW_cache_field_tube_limit_get(void);
struct GPUBatch *DRW_cache_field_cone_limit_get(void);
+
+/* Screen-aligned dashed circle */
+
struct GPUBatch *DRW_cache_field_sphere_limit_get(void);
/* Lights */
+
struct GPUBatch *DRW_cache_light_point_lines_get(void);
struct GPUBatch *DRW_cache_light_sun_lines_get(void);
struct GPUBatch *DRW_cache_light_spot_lines_get(void);
@@ -106,6 +127,7 @@ struct GPUBatch *DRW_cache_light_area_square_lines_get(void);
struct GPUBatch *DRW_cache_light_spot_volume_get(void);
/* Camera */
+
struct GPUBatch *DRW_cache_camera_frame_get(void);
struct GPUBatch *DRW_cache_camera_volume_get(void);
struct GPUBatch *DRW_cache_camera_volume_wire_get(void);
@@ -114,14 +136,17 @@ struct GPUBatch *DRW_cache_camera_tria_get(void);
struct GPUBatch *DRW_cache_camera_distances_get(void);
/* Speaker */
+
struct GPUBatch *DRW_cache_speaker_get(void);
/* Probe */
+
struct GPUBatch *DRW_cache_lightprobe_cube_get(void);
struct GPUBatch *DRW_cache_lightprobe_grid_get(void);
struct GPUBatch *DRW_cache_lightprobe_planar_get(void);
/* Bones */
+
struct GPUBatch *DRW_cache_bone_octahedral_get(void);
struct GPUBatch *DRW_cache_bone_octahedral_wire_get(void);
struct GPUBatch *DRW_cache_bone_box_get(void);
@@ -136,15 +161,22 @@ struct GPUBatch *DRW_cache_bone_dof_sphere_get(void);
struct GPUBatch *DRW_cache_bone_dof_lines_get(void);
/* Meshes */
+
struct GPUBatch *DRW_cache_mesh_all_verts_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_all_edges_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_loose_edges_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_edge_detection_get(struct Object *ob, bool *r_is_manifold);
struct GPUBatch *DRW_cache_mesh_surface_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_edges_get(struct Object *ob);
+/**
+ * Return list of batches with length equal to `max(1, totcol)`.
+ */
struct GPUBatch **DRW_cache_mesh_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
+/**
+ * Return list of batches with length equal to `max(1, totcol)`.
+ */
struct GPUBatch **DRW_cache_mesh_surface_texpaint_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_vertpaint_get(struct Object *ob);
@@ -154,19 +186,27 @@ struct GPUBatch *DRW_cache_mesh_surface_mesh_analysis_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_face_wireframe_get(struct Object *ob);
/* Curve */
+
struct GPUBatch *DRW_cache_curve_edge_wire_get(struct Object *ob);
+
/* edit-mode */
+
struct GPUBatch *DRW_cache_curve_edge_normal_get(struct Object *ob);
struct GPUBatch *DRW_cache_curve_edge_overlay_get(struct Object *ob);
struct GPUBatch *DRW_cache_curve_vert_overlay_get(struct Object *ob);
/* Font */
+
struct GPUBatch *DRW_cache_text_edge_wire_get(struct Object *ob);
/* Surface */
+
struct GPUBatch *DRW_cache_surf_surface_get(struct Object *ob);
struct GPUBatch *DRW_cache_surf_edge_wire_get(struct Object *ob);
struct GPUBatch *DRW_cache_surf_loose_edges_get(struct Object *ob);
+
+/* Return list of batches */
+
struct GPUBatch **DRW_cache_surf_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
@@ -174,11 +214,13 @@ struct GPUBatch *DRW_cache_surf_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_surf_edge_detection_get(struct Object *ob, bool *r_is_manifold);
/* Lattice */
+
struct GPUBatch *DRW_cache_lattice_verts_get(struct Object *ob);
struct GPUBatch *DRW_cache_lattice_wire_get(struct Object *ob, bool use_weight);
struct GPUBatch *DRW_cache_lattice_vert_overlay_get(struct Object *ob);
/* Particles */
+
struct GPUBatch *DRW_cache_particles_get_hair(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md);
@@ -196,6 +238,7 @@ struct GPUBatch *DRW_cache_particles_get_edit_tip_points(struct Object *object,
struct GPUBatch *DRW_cache_particles_get_prim(int type);
/* Metaball */
+
struct GPUBatch *DRW_cache_mball_surface_get(struct Object *ob);
struct GPUBatch **DRW_cache_mball_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
@@ -204,6 +247,7 @@ struct GPUBatch *DRW_cache_mball_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_mball_edge_detection_get(struct Object *ob, bool *r_is_manifold);
/* Hair */
+
struct GPUBatch *DRW_cache_hair_surface_get(struct Object *ob);
struct GPUBatch **DRW_cache_hair_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
@@ -212,10 +256,12 @@ struct GPUBatch *DRW_cache_hair_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_hair_edge_detection_get(struct Object *ob, bool *r_is_manifold);
/* PointCloud */
+
struct GPUBatch *DRW_cache_pointcloud_get_dots(struct Object *obj);
struct GPUBatch *DRW_cache_pointcloud_surface_get(struct Object *obj);
/* Volume */
+
typedef struct DRWVolumeGrid {
struct DRWVolumeGrid *next, *prev;
@@ -240,6 +286,7 @@ struct GPUBatch *DRW_cache_volume_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_volume_selection_surface_get(struct Object *ob);
/* GPencil */
+
struct GPUBatch *DRW_cache_gpencil_strokes_get(struct Object *ob, int cfra);
struct GPUBatch *DRW_cache_gpencil_fills_get(struct Object *ob, int cfra);
struct GPUBatch *DRW_cache_gpencil_edit_lines_get(struct Object *ob, int cfra);
@@ -252,6 +299,9 @@ struct GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(struct Object *ob);
struct GPUBatch *DRW_cache_gpencil_face_wireframe_get(struct Object *ob);
struct bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(struct Object *ob);
+/**
+ * Sbuffer batches are temporary. We need to clear it after drawing.
+ */
void DRW_cache_gpencil_sbuffer_clear(struct Object *ob);
#ifdef __cplusplus
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index a680cc0d6b7..e7f66ebacd0 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -22,8 +22,14 @@
#pragma once
+struct DRWSubdivCache;
struct TaskGraph;
+#include "DNA_customdata_types.h"
+
+#include "BKE_attribute.h"
+#include "BKE_object.h"
+
#include "GPU_batch.h"
#include "GPU_index_buffer.h"
#include "GPU_vertex_buffer.h"
@@ -56,7 +62,6 @@ typedef struct DRW_MeshCDMask {
uint32_t uv : 8;
uint32_t tan : 8;
uint32_t vcol : 8;
- uint32_t sculpt_vcol : 8;
uint32_t orco : 1;
uint32_t tan_orco : 1;
uint32_t sculpt_overlays : 1;
@@ -64,10 +69,10 @@ typedef struct DRW_MeshCDMask {
* modifiers could remove it. (see T68857) */
uint32_t edit_uv : 1;
} DRW_MeshCDMask;
-/* Keep `DRW_MeshCDMask` struct within an `uint64_t`.
+/* Keep `DRW_MeshCDMask` struct within an `uint32_t`.
* bit-wise and atomic operations are used to compare and update the struct.
* See `mesh_cd_layers_type_*` functions. */
-BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint64_t), "DRW_MeshCDMask exceeds 64 bits")
+BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint32_t), "DRW_MeshCDMask exceeds 32 bits")
typedef enum eMRIterType {
MR_ITER_LOOPTRI = 1 << 0,
MR_ITER_POLY = 1 << 1,
@@ -76,6 +81,17 @@ typedef enum eMRIterType {
} eMRIterType;
ENUM_OPERATORS(eMRIterType, MR_ITER_LVERT)
+typedef struct DRW_AttributeRequest {
+ CustomDataType cd_type;
+ int layer_index;
+ AttributeDomain domain;
+} DRW_AttributeRequest;
+
+typedef struct DRW_MeshAttributes {
+ DRW_AttributeRequest requests[GPU_MAX_ATTR];
+ int num_requests;
+} DRW_MeshAttributes;
+
typedef enum eMRDataType {
MR_DATA_NONE = 0,
MR_DATA_POLY_NOR = 1 << 1,
@@ -92,11 +108,13 @@ ENUM_OPERATORS(eMRDataType, MR_DATA_POLYS_SORTED)
extern "C" {
#endif
-BLI_INLINE int mesh_render_mat_len_get(const Mesh *me)
+BLI_INLINE int mesh_render_mat_len_get(const Object *object, const Mesh *me)
{
- /* In edit mode, the displayed mesh is stored in the edit-mesh. */
- if (me->edit_mesh && me->edit_mesh->mesh_eval_final) {
- return MAX2(1, me->edit_mesh->mesh_eval_final->totcol);
+ if (me->edit_mesh != NULL) {
+ const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
+ if (editmesh_eval_final != NULL) {
+ return MAX2(1, editmesh_eval_final->totcol);
+ }
}
return MAX2(1, me->totcol);
}
@@ -133,6 +151,7 @@ typedef struct MeshBufferList {
GPUVertBuf *edge_idx; /* extend */
GPUVertBuf *poly_idx;
GPUVertBuf *fdot_idx;
+ GPUVertBuf *attr[GPU_MAX_ATTR];
} vbo;
/* Index Buffers:
* Only need to be updated when topology changes. */
@@ -229,6 +248,13 @@ typedef enum DRWBatchFlag {
BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of bit fields");
+typedef struct MeshExtractLooseGeom {
+ int edge_len;
+ int vert_len;
+ int *verts;
+ int *edges;
+} MeshExtractLooseGeom;
+
/**
* Data that are kept around between extractions to reduce rebuilding time.
*
@@ -237,12 +263,7 @@ BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of b
typedef struct MeshBufferCache {
MeshBufferList buff;
- struct {
- int edge_len;
- int vert_len;
- int *verts;
- int *edges;
- } loose_geom;
+ MeshExtractLooseGeom loose_geom;
struct {
int *tri_first_index;
@@ -268,6 +289,8 @@ typedef struct MeshBatchCache {
GPUBatch **surface_per_mat;
+ struct DRWSubdivCache *subdiv_cache;
+
DRWBatchFlag batch_requested; /* DRWBatchFlag */
DRWBatchFlag batch_ready; /* DRWBatchFlag */
@@ -285,6 +308,8 @@ typedef struct MeshBatchCache {
DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time;
+ DRW_MeshAttributes attr_used, attr_needed, attr_used_over_time;
+
int lastmatch;
/* Valid only if edge_detection is up to date. */
@@ -306,17 +331,23 @@ typedef struct MeshBatchCache {
void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshBatchCache *cache,
MeshBufferCache *mbc,
+ Object *object,
Mesh *me,
- const bool is_editmode,
- const bool is_paint_mode,
- const bool is_mode_active,
+ bool is_editmode,
+ bool is_paint_mode,
+ bool is_mode_active,
const float obmat[4][4],
- const bool do_final,
- const bool do_uvedit,
- const bool use_subsurf_fdots,
+ bool do_final,
+ bool do_uvedit,
+ bool use_subsurf_fdots,
const Scene *scene,
- const ToolSettings *ts,
- const bool use_hide);
+ const struct ToolSettings *ts,
+ bool use_hide);
+
+void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ struct DRWSubdivCache *subdiv_cache,
+ const struct ToolSettings *ts);
#ifdef __cplusplus
}
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index 06c449fe590..987ddf3a938 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -42,6 +42,7 @@
#include "draw_cache_extract.h"
#include "draw_cache_inline.h"
+#include "draw_subdivision.h"
#include "mesh_extractors/extract_mesh.h"
@@ -56,6 +57,7 @@ namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Mesh Elements Extract Struct
* \{ */
+
using TaskId = int;
using TaskLen = int;
@@ -158,6 +160,7 @@ class ExtractorRunDatas : public Vector<ExtractorRunData> {
/* ---------------------------------------------------------------------- */
/** \name ExtractTaskData
* \{ */
+
struct ExtractTaskData {
const MeshRenderData *mr = nullptr;
MeshBatchCache *cache = nullptr;
@@ -495,6 +498,7 @@ static struct TaskNode *extract_task_node_create(struct TaskGraph *task_graph,
/* ---------------------------------------------------------------------- */
/** \name Task Node - Update Mesh Render Data
* \{ */
+
struct MeshRenderDataUpdateTaskData {
MeshRenderData *mr = nullptr;
MeshBufferCache *cache = nullptr;
@@ -566,6 +570,7 @@ static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *t
static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshBatchCache *cache,
MeshBufferCache *mbc,
+ Object *object,
Mesh *me,
const bool is_editmode,
@@ -611,7 +616,7 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
*/
const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
GPU_use_hq_normals_workaround();
- const bool override_single_mat = mesh_render_mat_len_get(me) <= 1;
+ const bool override_single_mat = mesh_render_mat_len_get(object, me) <= 1;
/* Create an array containing all the extractors that needs to be executed. */
ExtractorRunDatas extractors;
@@ -650,6 +655,9 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
EXTRACT_ADD_REQUESTED(vbo, vert_idx);
EXTRACT_ADD_REQUESTED(vbo, fdot_idx);
EXTRACT_ADD_REQUESTED(vbo, skin_roots);
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ EXTRACT_ADD_REQUESTED(vbo, attr[i]);
+ }
EXTRACT_ADD_REQUESTED(ibo, tris);
if (DRW_ibo_requested(mbuflist->ibo.lines_loose)) {
@@ -693,7 +701,7 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
#endif
MeshRenderData *mr = mesh_render_data_create(
- me, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts);
+ object, me, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts);
mr->use_hide = use_hide;
mr->use_subsurf_fdots = use_subsurf_fdots;
mr->use_final_mesh = do_final;
@@ -775,12 +783,127 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
#endif
}
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Subdivision Extract Loop
+ * \{ */
+
+static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ DRWSubdivCache *subdiv_cache,
+ const ToolSettings *ts)
+{
+ /* Create an array containing all the extractors that needs to be executed. */
+ ExtractorRunDatas extractors;
+
+ MeshBufferList *mbuflist = &mbc->buff;
+
+#define EXTRACT_ADD_REQUESTED(type, name) \
+ do { \
+ if (DRW_##type##_requested(mbuflist->type.name)) { \
+ const MeshExtract *extractor = &extract_##name; \
+ extractors.append(extractor); \
+ } \
+ } while (0)
+
+ /* The order in which extractors are added to the list matters somewhat, as some buffers are
+ * reused when building others. */
+ EXTRACT_ADD_REQUESTED(ibo, tris);
+ EXTRACT_ADD_REQUESTED(vbo, pos_nor);
+ EXTRACT_ADD_REQUESTED(vbo, lnor);
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ EXTRACT_ADD_REQUESTED(vbo, attr[i]);
+ }
+
+ /* We use only one extractor for face dots, as the work is done in a single compute shader. */
+ if (DRW_vbo_requested(mbuflist->vbo.fdots_nor) || DRW_vbo_requested(mbuflist->vbo.fdots_pos) ||
+ DRW_ibo_requested(mbuflist->ibo.fdots)) {
+ extractors.append(&extract_fdots_pos);
+ }
+
+ EXTRACT_ADD_REQUESTED(ibo, lines);
+ EXTRACT_ADD_REQUESTED(ibo, edituv_points);
+ EXTRACT_ADD_REQUESTED(ibo, edituv_tris);
+ EXTRACT_ADD_REQUESTED(ibo, edituv_lines);
+ EXTRACT_ADD_REQUESTED(vbo, vert_idx);
+ EXTRACT_ADD_REQUESTED(vbo, edge_idx);
+ EXTRACT_ADD_REQUESTED(vbo, poly_idx);
+ EXTRACT_ADD_REQUESTED(vbo, edge_fac);
+ EXTRACT_ADD_REQUESTED(ibo, points);
+ EXTRACT_ADD_REQUESTED(vbo, edit_data);
+ EXTRACT_ADD_REQUESTED(vbo, edituv_data);
+ /* Make sure UVs are computed before edituv stuffs. */
+ EXTRACT_ADD_REQUESTED(vbo, uv);
+ EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_area);
+ EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
+ EXTRACT_ADD_REQUESTED(ibo, lines_adjacency);
+ EXTRACT_ADD_REQUESTED(vbo, vcol);
+ EXTRACT_ADD_REQUESTED(vbo, weights);
+ EXTRACT_ADD_REQUESTED(vbo, sculpt_data);
+
+#undef EXTRACT_ADD_REQUESTED
+
+ if (extractors.is_empty()) {
+ return;
+ }
+
+ MeshRenderData mr;
+ memset(&mr, 0, sizeof(MeshRenderData));
+ draw_subdiv_init_mesh_render_data(subdiv_cache, &mr, ts);
+ mesh_render_data_update_loose_geom(&mr, mbc, MR_ITER_LEDGE | MR_ITER_LVERT, MR_DATA_LOOSE_GEOM);
+
+ void *data_stack = MEM_mallocN(extractors.data_size_total(), __func__);
+ uint32_t data_offset = 0;
+ for (const ExtractorRunData &run_data : extractors) {
+ const MeshExtract *extractor = run_data.extractor;
+ void *buffer = mesh_extract_buffer_get(extractor, mbuflist);
+ void *data = POINTER_OFFSET(data_stack, data_offset);
+
+ extractor->init_subdiv(subdiv_cache, &mr, cache, buffer, data);
+
+ if (extractor->iter_subdiv_mesh || extractor->iter_subdiv_bm) {
+ int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index;
+ if (subdiv_cache->bm) {
+ for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) {
+ /* Multiply by 4 to have the start index of the quad's loop, as subdiv_loop_poly_index is
+ * based on the subdivision loops. */
+ const int poly_origindex = subdiv_loop_poly_index[i * 4];
+ const BMFace *efa = bm_original_face_get(&mr, poly_origindex);
+ extractor->iter_subdiv_bm(subdiv_cache, &mr, data, i, efa);
+ }
+ }
+ else {
+ for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) {
+ /* Multiply by 4 to have the start index of the quad's loop, as subdiv_loop_poly_index is
+ * based on the subdivision loops. */
+ const int poly_origindex = subdiv_loop_poly_index[i * 4];
+ const MPoly *mp = &mr.mpoly[poly_origindex];
+ extractor->iter_subdiv_mesh(subdiv_cache, &mr, data, i, mp);
+ }
+ }
+ }
+
+ if (extractor->iter_loose_geom_subdiv) {
+ extractor->iter_loose_geom_subdiv(subdiv_cache, &mr, &mbc->loose_geom, buffer, data);
+ }
+
+ if (extractor->finish_subdiv) {
+ extractor->finish_subdiv(subdiv_cache, &mr, cache, buffer, data);
+ }
+ }
+ MEM_freeN(data_stack);
+}
+
+/** \} */
+
} // namespace blender::draw
extern "C" {
void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshBatchCache *cache,
MeshBufferCache *mbc,
+ Object *object,
Mesh *me,
const bool is_editmode,
@@ -797,6 +920,7 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
blender::draw::mesh_buffer_cache_create_requested(task_graph,
cache,
mbc,
+ object,
me,
is_editmode,
is_paint_mode,
@@ -810,6 +934,12 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
use_hide);
}
-} // extern "C"
+void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ DRWSubdivCache *subdiv_cache,
+ const ToolSettings *ts)
+{
+ blender::draw::mesh_buffer_cache_create_requested_subdiv(cache, mbc, subdiv_cache, ts);
+}
-/** \} */
+} // extern "C"
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
index abfbeabef6b..a47a124bd24 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
@@ -174,8 +174,8 @@ void mesh_render_data_update_loose_geom(MeshRenderData *mr,
/** \name Polygons sorted per material
*
* Contains polygon indices sorted based on their material.
- *
* \{ */
+
static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, const MeshBufferCache *cache);
static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferCache *cache);
static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache);
@@ -335,9 +335,6 @@ static int *mesh_render_data_mat_tri_len_build(MeshRenderData *mr)
/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data).
* \{ */
-/**
- * Part of the creation of the #MeshRenderData that happens in a thread.
- */
void mesh_render_data_update_looptris(MeshRenderData *mr,
const eMRIterType iter_type,
const eMRDataType data_flag)
@@ -382,14 +379,15 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
if (mr->extract_type != MR_EXTRACT_BMESH) {
/* Mesh */
+ mr->vert_normals = BKE_mesh_vertex_normals_ensure(mr->me);
if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) {
- BKE_mesh_ensure_normals_for_display(mr->me);
- mr->poly_normals = CustomData_get_layer(&mr->me->pdata, CD_NORMAL);
+ mr->poly_normals = BKE_mesh_poly_normals_ensure(mr->me);
}
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
short(*clnors)[2] = CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL);
BKE_mesh_normals_loop_split(mr->me->mvert,
+ mr->vert_normals,
mr->vert_len,
mr->me->medge,
mr->edge_len,
@@ -440,11 +438,8 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
}
}
-/**
- * \param is_mode_active: When true, use the modifiers from the edit-data,
- * otherwise don't use modifiers as they are not from this object.
- */
-MeshRenderData *mesh_render_data_create(Mesh *me,
+MeshRenderData *mesh_render_data_create(Object *object,
+ Mesh *me,
const bool is_editmode,
const bool is_paint_mode,
const bool is_mode_active,
@@ -455,15 +450,18 @@ MeshRenderData *mesh_render_data_create(Mesh *me,
{
MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__);
mr->toolsettings = ts;
- mr->mat_len = mesh_render_mat_len_get(me);
+ mr->mat_len = mesh_render_mat_len_get(object, me);
copy_m4_m4(mr->obmat, obmat);
if (is_editmode) {
- BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final);
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(object);
+
+ BLI_assert(editmesh_eval_cage && editmesh_eval_final);
mr->bm = me->edit_mesh->bm;
mr->edit_bmesh = me->edit_mesh;
- mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage;
+ mr->me = (do_final) ? editmesh_eval_final : editmesh_eval_cage;
mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : NULL;
if (mr->edit_data) {
@@ -493,7 +491,8 @@ MeshRenderData *mesh_render_data_create(Mesh *me,
mr->eed_act = BM_mesh_active_edge_get(mr->bm);
mr->eve_act = BM_mesh_active_vert_get(mr->bm);
- mr->crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE);
+ mr->vert_crease_ofs = CustomData_get_offset(&mr->bm->vdata, CD_CREASE);
+ mr->edge_crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE);
mr->bweight_ofs = CustomData_get_offset(&mr->bm->edata, CD_BWEIGHT);
#ifdef WITH_FREESTYLE
mr->freestyle_edge_ofs = CustomData_get_offset(&mr->bm->edata, CD_FREESTYLE_EDGE);
@@ -512,7 +511,7 @@ MeshRenderData *mesh_render_data_create(Mesh *me,
/* Seems like the mesh_eval_final do not have the right origin indices.
* Force not mapped in this case. */
- if (has_mdata && do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) {
+ if (has_mdata && do_final && editmesh_eval_final != editmesh_eval_cage) {
// mr->edit_bmesh = NULL;
mr->extract_type = MR_EXTRACT_MESH;
}
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 220a7f37c3d..6a2f4b91ad1 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -47,7 +47,10 @@ struct bGPdata;
extern "C" {
#endif
-/* Expose via BKE callbacks */
+/* -------------------------------------------------------------------- */
+/** \name Expose via BKE callbacks
+ * \{ */
+
void DRW_mball_batch_cache_dirty_tag(struct MetaBall *mb, int mode);
void DRW_mball_batch_cache_validate(struct MetaBall *mb);
void DRW_mball_batch_cache_free(struct MetaBall *mb);
@@ -57,7 +60,7 @@ void DRW_curve_batch_cache_validate(struct Curve *cu);
void DRW_curve_batch_cache_free(struct Curve *cu);
void DRW_mesh_batch_cache_dirty_tag(struct Mesh *me, eMeshBatchDirtyMode mode);
-void DRW_mesh_batch_cache_validate(struct Mesh *me);
+void DRW_mesh_batch_cache_validate(struct Object *object, struct Mesh *me);
void DRW_mesh_batch_cache_free(struct Mesh *me);
void DRW_lattice_batch_cache_dirty_tag(struct Lattice *lt, int mode);
@@ -82,15 +85,34 @@ void DRW_volume_batch_cache_dirty_tag(struct Volume *volume, int mode);
void DRW_volume_batch_cache_validate(struct Volume *volume);
void DRW_volume_batch_cache_free(struct Volume *volume);
-/* Garbage collection */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Garbage Collection
+ * \{ */
+
void DRW_batch_cache_free_old(struct Object *ob, int ctime);
+/**
+ * Thread safety need to be assured by caller. Don't call this during drawing.
+ * \note For now this only free the shading batches / VBO if any cd layers is not needed anymore.
+ */
void DRW_mesh_batch_cache_free_old(struct Mesh *me, int ctime);
-/* Generic */
-void DRW_vertbuf_create_wiredata(struct GPUVertBuf *vbo, const int vert_len);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generic
+ * \{ */
+
+void DRW_vertbuf_create_wiredata(struct GPUVertBuf *vbo, int vert_len);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Curve
+ * \{ */
-/* Curve */
void DRW_curve_batch_cache_create_requested(struct Object *ob, const struct Scene *scene);
int DRW_curve_material_count_get(struct Curve *cu);
@@ -107,7 +129,12 @@ struct GPUBatch **DRW_curve_batch_cache_get_surface_shaded(struct Curve *cu,
uint gpumat_array_len);
struct GPUBatch *DRW_curve_batch_cache_get_wireframes_face(struct Curve *cu);
-/* Metaball */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Metaball
+ * \{ */
+
int DRW_metaball_material_count_get(struct MetaBall *mb);
struct GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(struct Object *ob);
@@ -119,7 +146,12 @@ struct GPUBatch *DRW_metaball_batch_cache_get_wireframes_face(struct Object *ob)
struct GPUBatch *DRW_metaball_batch_cache_get_edge_detection(struct Object *ob,
bool *r_is_manifold);
-/* DispList */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DispList
+ * \{ */
+
void DRW_displist_vertbuf_create_pos_and_nor(struct ListBase *lb,
struct GPUVertBuf *vbo,
const struct Scene *scene);
@@ -138,17 +170,32 @@ void DRW_displist_indexbuf_create_edges_adjacency_lines(struct ListBase *lb,
struct GPUIndexBuf *ibo,
bool *r_is_manifold);
-/* Lattice */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lattice
+ * \{ */
+
struct GPUBatch *DRW_lattice_batch_cache_get_all_edges(struct Lattice *lt,
bool use_weight,
- const int actdef);
+ int actdef);
struct GPUBatch *DRW_lattice_batch_cache_get_all_verts(struct Lattice *lt);
struct GPUBatch *DRW_lattice_batch_cache_get_edit_verts(struct Lattice *lt);
-/* Hair */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hair
+ * \{ */
+
int DRW_hair_material_count_get(struct Hair *hair);
-/* PointCloud */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name PointCloud
+ * \{ */
+
int DRW_pointcloud_material_count_get(struct PointCloud *pointcloud);
struct GPUBatch *DRW_pointcloud_batch_cache_get_dots(struct Object *ob);
@@ -157,36 +204,59 @@ struct GPUBatch **DRW_cache_pointcloud_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
-/* Volume */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Volume
+ * \{ */
+
int DRW_volume_material_count_get(struct Volume *volume);
struct GPUBatch *DRW_volume_batch_cache_get_wireframes_face(struct Volume *volume);
struct GPUBatch *DRW_volume_batch_cache_get_selection_surface(struct Volume *volume);
-/* Mesh */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh
+ * \{ */
+
+/**
+ * Can be called for any surface type. Mesh *me is the final mesh.
+ */
void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
struct Object *ob,
struct Mesh *me,
const struct Scene *scene,
- const bool is_paint_mode,
- const bool use_hide);
+ bool is_paint_mode,
+ bool use_hide);
struct GPUBatch *DRW_mesh_batch_cache_get_all_verts(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_all_edges(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_loose_edges(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edge_detection(struct Mesh *me, bool *r_is_manifold);
struct GPUBatch *DRW_mesh_batch_cache_get_surface(struct Mesh *me);
-struct GPUBatch *DRW_mesh_batch_cache_get_surface_edges(struct Mesh *me);
-struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(struct Mesh *me,
+struct GPUBatch *DRW_mesh_batch_cache_get_surface_edges(struct Object *object, struct Mesh *me);
+struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(struct Object *object,
+ struct Mesh *me,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
-struct GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(struct Mesh *me);
-struct GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Mesh *me);
-struct GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(struct Mesh *me);
-struct GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(struct Mesh *me);
+struct GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(struct Object *object,
+ struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Object *object,
+ struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(struct Object *object,
+ struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(struct Object *object, struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_surface_weights(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_sculpt_overlays(struct Mesh *me);
-/* edit-mesh drawing */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-Mesh Drawing
+ * \{ */
+
struct GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_vertices(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_edges(struct Mesh *me);
@@ -194,32 +264,70 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edit_vnors(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_lnors(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_skin_roots(struct Mesh *me);
-/* edit-mesh selection */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-mesh Selection
+ * \{ */
+
struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_id(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_facedots_with_select_id(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edges_with_select_id(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(struct Mesh *me);
-/* Object mode Wireframe overlays */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Mode Wireframe Overlays
+ * \{ */
+
struct GPUBatch *DRW_mesh_batch_cache_get_wireframes_face(struct Mesh *me);
-/* edit-mesh UV editor */
-struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(struct Mesh *me,
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-mesh UV Editor
+ * \{ */
+
+/**
+ * Creates the #GPUBatch for drawing the UV Stretching Area Overlay.
+ * Optional retrieves the total area or total uv area of the mesh.
+ *
+ * The `cache->tot_area` and cache->tot_uv_area` update are calculation are
+ * only valid after calling `DRW_mesh_batch_cache_create_requested`.
+ */
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(struct Object *object,
+ struct Mesh *me,
float **tot_area,
float **tot_uv_area);
-struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(struct Mesh *me);
-struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(struct Mesh *me);
-struct GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(struct Mesh *me);
-struct GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(struct Mesh *me);
-struct GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(struct Mesh *me);
-/* For Image UV editor. */
-struct GPUBatch *DRW_mesh_batch_cache_get_uv_edges(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(struct Object *object,
+ struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(struct Object *object, struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(struct Object *object, struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(struct Object *object, struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(struct Object *object, struct Mesh *me);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name For Image UV Editor
+ * \{ */
+
+struct GPUBatch *DRW_mesh_batch_cache_get_uv_edges(struct Object *object, struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(struct Mesh *me);
-/* For direct data access. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name For Direct Data Access
+ * \{ */
+
struct GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(struct Mesh *me);
struct GPUVertBuf *DRW_curve_batch_cache_pos_vertbuf_get(struct Curve *cu);
struct GPUVertBuf *DRW_mball_batch_cache_pos_vertbuf_get(struct Object *ob);
-int DRW_mesh_material_count_get(const struct Mesh *me);
+int DRW_mesh_material_count_get(const struct Object *object, const struct Mesh *me);
/* See 'common_globals_lib.glsl' for duplicate defines. */
@@ -250,7 +358,12 @@ enum {
/* Beware to not go over 1 << 7 (it's a byte flag). */
};
-/* Particles */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Particles
+ * \{ */
+
struct GPUBatch *DRW_particles_batch_cache_get_hair(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md);
@@ -266,6 +379,9 @@ struct GPUBatch *DRW_particles_batch_cache_get_edit_inner_points(struct Object *
struct GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(struct Object *object,
struct ParticleSystem *psys,
struct PTCacheEdit *edit);
+
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/intern/draw_cache_impl_curve.cc b/source/blender/draw/intern/draw_cache_impl_curve.cc
index dc8f382b7f8..33cf0e9a3cd 100644
--- a/source/blender/draw/intern/draw_cache_impl_curve.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curve.cc
@@ -26,8 +26,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_array.hh"
-#include "BLI_float3.hh"
#include "BLI_listbase.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.h"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
@@ -36,9 +36,9 @@
#include "BKE_curve.h"
#include "BKE_displist.h"
-#include "BKE_font.h"
#include "BKE_geometry_set.hh"
#include "BKE_spline.hh"
+#include "BKE_vfont.h"
#include "GPU_batch.h"
#include "GPU_capabilities.h"
diff --git a/source/blender/draw/intern/draw_cache_impl_displist.c b/source/blender/draw/intern/draw_cache_impl_displist.c
index 1fed5d79697..fb8f998f036 100644
--- a/source/blender/draw/intern/draw_cache_impl_displist.c
+++ b/source/blender/draw/intern/draw_cache_impl_displist.c
@@ -372,10 +372,10 @@ static void surf_uv_quad(const DispList *dl, const uint quad[4], float r_uv[4][2
r_uv[i][1] = (quad[i] % dl->nr) / (float)orco_sizeu;
/* cyclic correction */
- if ((i == 1 || i == 2) && r_uv[i][0] == 0.0f) {
+ if (ELEM(i, 1, 2) && r_uv[i][0] == 0.0f) {
r_uv[i][0] = 1.0f;
}
- if ((i == 0 || i == 1) && r_uv[i][1] == 0.0f) {
+ if (ELEM(i, 0, 1) && r_uv[i][1] == 0.0f) {
r_uv[i][1] = 1.0f;
}
}
diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c
index e78e41b917a..ddad07a7476 100644
--- a/source/blender/draw/intern/draw_cache_impl_gpencil.c
+++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c
@@ -47,7 +47,10 @@
#define BEZIER_HANDLE (1 << 3)
#define COLOR_SHIFT 5
-/* ---------------------------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
typedef struct GpencilBatchCache {
/** Instancing Data */
GPUVertBuf *vbo;
@@ -74,6 +77,12 @@ typedef struct GpencilBatchCache {
int cache_frame;
} GpencilBatchCache;
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
{
bool valid = true;
@@ -151,6 +160,12 @@ static GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra)
return cache;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE Callbacks
+ * \{ */
+
void DRW_gpencil_batch_cache_dirty_tag(bGPdata *gpd)
{
gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
@@ -166,7 +181,7 @@ void DRW_gpencil_batch_cache_free(bGPdata *gpd)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Vertex Formats.
+/** \name Vertex Formats
* \{ */
/* MUST match the format below. */
@@ -247,7 +262,7 @@ static GPUVertFormat *gpencil_color_format(void)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Vertex Buffers.
+/** \name Vertex Buffers
* \{ */
typedef struct gpIterData {
@@ -627,7 +642,7 @@ static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_
float(*tpoints2d)[2] = MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__);
/* Triangulate in 2D. */
for (int i = 0; i < vert_len; i++) {
- copy_v2_v2(tpoints2d[i], &tpoints[i].x);
+ copy_v2_v2(tpoints2d[i], tpoints[i].m_xy);
}
/* Compute directly inside the IBO data buffer. */
/* OPTI: This is a bottleneck if the stroke is very long. */
@@ -671,7 +686,6 @@ GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(Object *ob)
return gpd->runtime.sbuffer_fill_batch;
}
-/* Sbuffer batches are temporary. We need to clear it after drawing */
void DRW_cache_gpencil_sbuffer_clear(Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -682,8 +696,9 @@ void DRW_cache_gpencil_sbuffer_clear(Object *ob)
/** \} */
-/* ---------------------------------------------------------------------- */
-/* Edit GPencil Batches */
+/* -------------------------------------------------------------------- */
+/** \name Edit GPencil Batches
+ * \{ */
#define GP_EDIT_POINT_SELECTED (1 << 0)
#define GP_EDIT_STROKE_SELECTED (1 << 1)
diff --git a/source/blender/draw/intern/draw_cache_impl_hair.c b/source/blender/draw/intern/draw_cache_impl_hair.cc
index 41a0cca8a8f..d236f0c2f59 100644
--- a/source/blender/draw/intern/draw_cache_impl_hair.c
+++ b/source/blender/draw/intern/draw_cache_impl_hair.cc
@@ -23,7 +23,7 @@
* \brief Hair API for render engines
*/
-#include <string.h>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -49,27 +49,28 @@ static void hair_batch_cache_clear(Hair *hair);
/* ---------------------------------------------------------------------- */
/* Hair GPUBatch Cache */
-typedef struct HairBatchCache {
+struct HairBatchCache {
ParticleHairCache hair;
/* settings to determine if cache is invalid */
bool is_dirty;
-} HairBatchCache;
+};
/* GPUBatch cache management. */
static bool hair_batch_cache_valid(Hair *hair)
{
- HairBatchCache *cache = hair->batch_cache;
+ HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache);
return (cache && cache->is_dirty == false);
}
static void hair_batch_cache_init(Hair *hair)
{
- HairBatchCache *cache = hair->batch_cache;
+ HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache);
if (!cache) {
- cache = hair->batch_cache = MEM_callocN(sizeof(*cache), __func__);
+ cache = MEM_cnew<HairBatchCache>(__func__);
+ hair->batch_cache = cache;
}
else {
memset(cache, 0, sizeof(*cache));
@@ -89,13 +90,13 @@ void DRW_hair_batch_cache_validate(Hair *hair)
static HairBatchCache *hair_batch_cache_get(Hair *hair)
{
DRW_hair_batch_cache_validate(hair);
- return hair->batch_cache;
+ return static_cast<HairBatchCache *>(hair->batch_cache);
}
void DRW_hair_batch_cache_dirty_tag(Hair *hair, int mode)
{
- HairBatchCache *cache = hair->batch_cache;
- if (cache == NULL) {
+ HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache);
+ if (cache == nullptr) {
return;
}
switch (mode) {
@@ -109,7 +110,7 @@ void DRW_hair_batch_cache_dirty_tag(Hair *hair, int mode)
static void hair_batch_cache_clear(Hair *hair)
{
- HairBatchCache *cache = hair->batch_cache;
+ HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache);
if (!cache) {
return;
}
@@ -125,8 +126,8 @@ void DRW_hair_batch_cache_free(Hair *hair)
static void ensure_seg_pt_count(Hair *hair, ParticleHairCache *hair_cache)
{
- if ((hair_cache->pos != NULL && hair_cache->indices != NULL) ||
- (hair_cache->proc_point_buf != NULL)) {
+ if ((hair_cache->pos != nullptr && hair_cache->indices != nullptr) ||
+ (hair_cache->proc_point_buf != nullptr)) {
return;
}
@@ -153,7 +154,7 @@ static void hair_batch_cache_fill_segments_proc_pos(Hair *hair,
for (int i = 0; i < num_curves; i++, curve++) {
float(*curve_co)[3] = hair->co + curve->firstpoint;
float total_len = 0.0f;
- float *co_prev = NULL, *seg_data_first;
+ float *co_prev = nullptr, *seg_data_first;
for (int j = 0; j < curve->numpoints; j++) {
float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step);
copy_v3_v3(seg_data, curve_co[j]);
@@ -166,7 +167,7 @@ static void hair_batch_cache_fill_segments_proc_pos(Hair *hair,
seg_data[3] = total_len;
co_prev = curve_co[j];
}
- /* Assign length value*/
+ /* Assign length value. */
*(float *)GPU_vertbuf_raw_step(length_step) = total_len;
if (total_len > 0.0f) {
/* Divide by total length to have a [0-1] number. */
@@ -181,7 +182,7 @@ static void hair_batch_cache_ensure_procedural_pos(Hair *hair,
ParticleHairCache *cache,
GPUMaterial *gpu_material)
{
- if (cache->proc_point_buf == NULL) {
+ if (cache->proc_point_buf == nullptr) {
/* initialize vertex format */
GPUVertFormat format = {0};
uint pos_id = GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
@@ -209,7 +210,7 @@ static void hair_batch_cache_ensure_procedural_pos(Hair *hair,
cache->point_tex = GPU_texture_create_from_vertbuf("hair_point", cache->proc_point_buf);
}
- if (gpu_material && cache->proc_length_buf != NULL && cache->length_tex) {
+ if (gpu_material && cache->proc_length_buf != nullptr && cache->length_tex) {
ListBase gpu_attrs = GPU_material_attributes(gpu_material);
LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &gpu_attrs) {
if (attr->type == CD_HAIRLENGTH) {
@@ -306,7 +307,7 @@ static void hair_batch_cache_ensure_procedural_indices(Hair *hair,
{
BLI_assert(thickness_res <= MAX_THICKRES); /* Cylinder strip not currently supported. */
- if (cache->final[subdiv].proc_hairs[thickness_res - 1] != NULL) {
+ if (cache->final[subdiv].proc_hairs[thickness_res - 1] != nullptr) {
return;
}
@@ -333,7 +334,6 @@ static void hair_batch_cache_ensure_procedural_indices(Hair *hair,
prim_type, vbo, GPU_indexbuf_build(&elb), GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
}
-/* Ensure all textures and buffers needed for GPU accelerated drawing. */
bool hair_ensure_procedural_data(Object *object,
ParticleHairCache **r_hair_cache,
GPUMaterial *gpu_material,
@@ -341,7 +341,7 @@ bool hair_ensure_procedural_data(Object *object,
int thickness_res)
{
bool need_ft_update = false;
- Hair *hair = object->data;
+ Hair *hair = static_cast<Hair *>(object->data);
HairBatchCache *cache = hair_batch_cache_get(hair);
*r_hair_cache = &cache->hair;
@@ -350,23 +350,23 @@ bool hair_ensure_procedural_data(Object *object,
(*r_hair_cache)->final[subdiv].strands_res = 1 << (steps + subdiv);
/* Refreshed on combing and simulation. */
- if ((*r_hair_cache)->proc_point_buf == NULL) {
+ if ((*r_hair_cache)->proc_point_buf == nullptr) {
ensure_seg_pt_count(hair, &cache->hair);
hair_batch_cache_ensure_procedural_pos(hair, &cache->hair, gpu_material);
need_ft_update = true;
}
/* Refreshed if active layer or custom data changes. */
- if ((*r_hair_cache)->strand_tex == NULL) {
+ if ((*r_hair_cache)->strand_tex == nullptr) {
hair_batch_cache_ensure_procedural_strand_data(hair, &cache->hair);
}
/* Refreshed only on subdiv count change. */
- if ((*r_hair_cache)->final[subdiv].proc_buf == NULL) {
+ if ((*r_hair_cache)->final[subdiv].proc_buf == nullptr) {
hair_batch_cache_ensure_procedural_final_points(&cache->hair, subdiv);
need_ft_update = true;
}
- if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == NULL) {
+ if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == nullptr) {
hair_batch_cache_ensure_procedural_indices(hair, &cache->hair, thickness_res, subdiv);
}
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 18664498d00..f57921d058c 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -41,6 +41,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BKE_attribute.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
@@ -53,6 +54,7 @@
#include "BKE_object_deform.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_subdiv_modifier.h"
#include "atomic_ops.h"
@@ -68,6 +70,7 @@
#include "draw_cache_extract.h"
#include "draw_cache_inline.h"
+#include "draw_subdivision.h"
#include "draw_cache_impl.h" /* own include */
@@ -121,6 +124,8 @@
# define _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5) _MDEPS_ASSERT5(b, n1, n2, n3, n4); _MDEPS_ASSERT2(b, n5)
# define _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6) _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5); _MDEPS_ASSERT2(b, n6)
# define _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7) _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6); _MDEPS_ASSERT2(b, n7)
+# define _MDEPS_ASSERT21(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20) _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7); _MDEPS_ASSERT8(b, n8, n9, n10, n11, n12, n13, n14); _MDEPS_ASSERT7(b, n15, n16, n17, n18, n19, n20)
+# define _MDEPS_ASSERT22(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20, n21) _MDEPS_ASSERT21(b, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20); _MDEPS_ASSERT2(b, n21);
# define MDEPS_ASSERT_FLAG(...) VA_NARGS_CALL_OVERLOAD(_MDEPS_ASSERT, __VA_ARGS__)
# define MDEPS_ASSERT(batch_name, ...) MDEPS_ASSERT_FLAG(BATCH_FLAG(batch_name), __VA_ARGS__)
@@ -192,6 +197,21 @@ static const DRWBatchFlag g_buffer_deps[] = {
[BUFFER_INDEX(vbo.edge_idx)] = BATCH_FLAG(edit_selection_edges),
[BUFFER_INDEX(vbo.poly_idx)] = BATCH_FLAG(edit_selection_faces),
[BUFFER_INDEX(vbo.fdot_idx)] = BATCH_FLAG(edit_selection_fdots),
+ [BUFFER_INDEX(vbo.attr) + 0] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 1] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 2] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 3] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 4] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 5] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 6] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 7] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 8] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 9] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 10] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 11] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 12] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 13] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
+ [BUFFER_INDEX(vbo.attr) + 14] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
[BUFFER_INDEX(ibo.tris)] = BATCH_FLAG(surface,
surface_weights,
@@ -240,12 +260,12 @@ static void mesh_batch_cache_discard_batch(MeshBatchCache *cache, const DRWBatch
/* Return true is all layers in _b_ are inside _a_. */
BLI_INLINE bool mesh_cd_layers_type_overlap(DRW_MeshCDMask a, DRW_MeshCDMask b)
{
- return (*((uint64_t *)&a) & *((uint64_t *)&b)) == *((uint64_t *)&b);
+ return (*((uint32_t *)&a) & *((uint32_t *)&b)) == *((uint32_t *)&b);
}
BLI_INLINE bool mesh_cd_layers_type_equal(DRW_MeshCDMask a, DRW_MeshCDMask b)
{
- return *((uint64_t *)&a) == *((uint64_t *)&b);
+ return *((uint32_t *)&a) == *((uint32_t *)&b);
}
BLI_INLINE void mesh_cd_layers_type_merge(DRW_MeshCDMask *a, DRW_MeshCDMask b)
@@ -253,17 +273,23 @@ BLI_INLINE void mesh_cd_layers_type_merge(DRW_MeshCDMask *a, DRW_MeshCDMask b)
uint32_t *a_p = (uint32_t *)a;
uint32_t *b_p = (uint32_t *)&b;
atomic_fetch_and_or_uint32(a_p, *b_p);
- atomic_fetch_and_or_uint32(a_p + 1, *(b_p + 1));
}
BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a)
{
- *((uint64_t *)a) = 0;
+ *((uint32_t *)a) = 0;
}
-BLI_INLINE const Mesh *editmesh_final_or_this(const Mesh *me)
+BLI_INLINE const Mesh *editmesh_final_or_this(const Object *object, const Mesh *me)
{
- return (me->edit_mesh && me->edit_mesh->mesh_eval_final) ? me->edit_mesh->mesh_eval_final : me;
+ if (me->edit_mesh != NULL) {
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
+ if (editmesh_eval_final != NULL) {
+ return editmesh_eval_final;
+ }
+ }
+
+ return me;
}
static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *cd_used)
@@ -271,9 +297,99 @@ static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *c
cd_used->edit_uv = 1;
}
+/** \name DRW_MeshAttributes
+ *
+ * Utilities for handling requested attributes.
+ * \{ */
+
+/* Return true if the given DRW_AttributeRequest is already in the requests. */
+static bool has_request(const DRW_MeshAttributes *requests, DRW_AttributeRequest req)
+{
+ for (int i = 0; i < requests->num_requests; i++) {
+ const DRW_AttributeRequest src_req = requests->requests[i];
+ if (src_req.domain != req.domain) {
+ continue;
+ }
+ if (src_req.layer_index != req.layer_index) {
+ continue;
+ }
+ if (src_req.cd_type != req.cd_type) {
+ continue;
+ }
+ return true;
+ }
+ return false;
+}
+
+static void mesh_attrs_merge_requests(const DRW_MeshAttributes *src_requests,
+ DRW_MeshAttributes *dst_requests)
+{
+ for (int i = 0; i < src_requests->num_requests; i++) {
+ if (dst_requests->num_requests == GPU_MAX_ATTR) {
+ return;
+ }
+
+ if (has_request(dst_requests, src_requests->requests[i])) {
+ continue;
+ }
+
+ dst_requests->requests[dst_requests->num_requests] = src_requests->requests[i];
+ dst_requests->num_requests += 1;
+ }
+}
+
+static void drw_mesh_attributes_clear(DRW_MeshAttributes *attributes)
+{
+ memset(attributes, 0, sizeof(DRW_MeshAttributes));
+}
+
+static void drw_mesh_attributes_merge(DRW_MeshAttributes *dst,
+ const DRW_MeshAttributes *src,
+ ThreadMutex *mesh_render_mutex)
+{
+ BLI_mutex_lock(mesh_render_mutex);
+ mesh_attrs_merge_requests(src, dst);
+ BLI_mutex_unlock(mesh_render_mutex);
+}
+
+/* Return true if all requests in b are in a. */
+static bool drw_mesh_attributes_overlap(DRW_MeshAttributes *a, DRW_MeshAttributes *b)
+{
+ if (a->num_requests != b->num_requests) {
+ return false;
+ }
+
+ for (int i = 0; i < a->num_requests; i++) {
+ if (!has_request(a, b->requests[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void drw_mesh_attributes_add_request(DRW_MeshAttributes *attrs,
+ CustomDataType type,
+ int layer,
+ AttributeDomain domain)
+{
+ if (attrs->num_requests >= GPU_MAX_ATTR) {
+ return;
+ }
+
+ DRW_AttributeRequest *req = &attrs->requests[attrs->num_requests];
+ req->cd_type = type;
+ req->layer_index = layer;
+ req->domain = domain;
+ attrs->num_requests += 1;
+}
+
+/** \} */
+
BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->ldata;
break;
@@ -286,9 +402,42 @@ BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
return &me->ldata;
}
+BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me)
+{
+ switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
+ case ME_WRAPPER_TYPE_MDATA:
+ return &me->pdata;
+ break;
+ case ME_WRAPPER_TYPE_BMESH:
+ return &me->edit_mesh->bm->pdata;
+ break;
+ }
+
+ BLI_assert(0);
+ return &me->pdata;
+}
+
+BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me)
+{
+ switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
+ case ME_WRAPPER_TYPE_MDATA:
+ return &me->edata;
+ break;
+ case ME_WRAPPER_TYPE_BMESH:
+ return &me->edit_mesh->bm->edata;
+ break;
+ }
+
+ BLI_assert(0);
+ return &me->edata;
+}
+
BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->vdata;
break;
@@ -301,9 +450,11 @@ BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me)
return &me->vdata;
}
-static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
+static void mesh_cd_calc_active_uv_layer(const Object *object,
+ const Mesh *me,
+ DRW_MeshCDMask *cd_used)
{
- const Mesh *me_final = editmesh_final_or_this(me);
+ const Mesh *me_final = editmesh_final_or_this(object, me);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
if (layer != -1) {
@@ -311,9 +462,11 @@ static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used
}
}
-static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
+static void mesh_cd_calc_active_mask_uv_layer(const Object *object,
+ const Mesh *me,
+ DRW_MeshCDMask *cd_used)
{
- const Mesh *me_final = editmesh_final_or_this(me);
+ const Mesh *me_final = editmesh_final_or_this(object, me);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
int layer = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV);
if (layer != -1) {
@@ -321,20 +474,24 @@ static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd
}
}
-static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
+static void mesh_cd_calc_active_vcol_layer(const Object *object,
+ const Mesh *me,
+ DRW_MeshAttributes *attrs_used)
{
- const Mesh *me_final = editmesh_final_or_this(me);
+ const Mesh *me_final = editmesh_final_or_this(object, me);
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
int layer = CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR);
if (layer != -1) {
- cd_used->sculpt_vcol |= (1 << layer);
+ drw_mesh_attributes_add_request(attrs_used, CD_PROP_COLOR, layer, ATTR_DOMAIN_POINT);
}
}
-static void mesh_cd_calc_active_mloopcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
+static void mesh_cd_calc_active_mloopcol_layer(const Object *object,
+ const Mesh *me,
+ DRW_MeshCDMask *cd_used)
{
- const Mesh *me_final = editmesh_final_or_this(me);
+ const Mesh *me_final = editmesh_final_or_this(object, me);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL);
@@ -343,13 +500,46 @@ static void mesh_cd_calc_active_mloopcol_layer(const Mesh *me, DRW_MeshCDMask *c
}
}
-static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
+static bool custom_data_match_attribute(const CustomData *custom_data,
+ const char *name,
+ int *r_layer_index,
+ int *r_type)
+{
+ const int possible_attribute_types[6] = {
+ CD_PROP_BOOL,
+ CD_PROP_INT32,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT2,
+ CD_PROP_FLOAT3,
+ CD_PROP_COLOR,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(possible_attribute_types); i++) {
+ const int attr_type = possible_attribute_types[i];
+ int layer_index = CustomData_get_named_layer(custom_data, attr_type, name);
+ if (layer_index == -1) {
+ continue;
+ }
+
+ *r_layer_index = layer_index;
+ *r_type = attr_type;
+ return true;
+ }
+
+ return false;
+}
+
+static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
+ const Mesh *me,
struct GPUMaterial **gpumat_array,
- int gpumat_array_len)
+ int gpumat_array_len,
+ DRW_MeshAttributes *attributes)
{
- const Mesh *me_final = editmesh_final_or_this(me);
+ const Mesh *me_final = editmesh_final_or_this(object, me);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
+ const CustomData *cd_pdata = mesh_cd_pdata_get_from_mesh(me_final);
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
+ const CustomData *cd_edata = mesh_cd_edata_get_from_mesh(me_final);
/* See: DM_vertex_attributes_from_gpu for similar logic */
DRW_MeshCDMask cd_used;
@@ -363,9 +553,11 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
const char *name = gpu_attr->name;
int type = gpu_attr->type;
int layer = -1;
+ /* ATTR_DOMAIN_NUM is standard for "invalid value". */
+ AttributeDomain domain = ATTR_DOMAIN_NUM;
if (type == CD_AUTO_FROM_NAME) {
- /* We need to deduct what exact layer is used.
+ /* We need to deduce what exact layer is used.
*
* We do it based on the specified name.
*/
@@ -374,13 +566,6 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
type = CD_MTFACE;
if (layer == -1) {
- if (U.experimental.use_sculpt_vertex_colors) {
- layer = CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name);
- type = CD_PROP_COLOR;
- }
- }
-
- if (layer == -1) {
layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name);
type = CD_MCOL;
}
@@ -392,6 +577,27 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
}
#endif
if (layer == -1) {
+ /* Try to match a generic attribute, we use the first attribute domain with a
+ * matching name. */
+ if (custom_data_match_attribute(cd_vdata, name, &layer, &type)) {
+ domain = ATTR_DOMAIN_POINT;
+ }
+ else if (custom_data_match_attribute(cd_ldata, name, &layer, &type)) {
+ domain = ATTR_DOMAIN_CORNER;
+ }
+ else if (custom_data_match_attribute(cd_pdata, name, &layer, &type)) {
+ domain = ATTR_DOMAIN_FACE;
+ }
+ else if (custom_data_match_attribute(cd_edata, name, &layer, &type)) {
+ domain = ATTR_DOMAIN_EDGE;
+ }
+ else {
+ layer = -1;
+ domain = ATTR_DOMAIN_NUM;
+ }
+ }
+
+ if (layer == -1) {
continue;
}
}
@@ -432,31 +638,6 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
}
break;
}
- case CD_PROP_COLOR: {
- /* Sculpt Vertex Colors */
- bool use_mloop_cols = false;
- if (layer == -1) {
- layer = (name[0] != '\0') ?
- CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name) :
- CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR);
- /* Fallback to Vertex Color data */
- if (layer == -1) {
- layer = (name[0] != '\0') ?
- CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name) :
- CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL);
- use_mloop_cols = true;
- }
- }
- if (layer != -1) {
- if (use_mloop_cols) {
- cd_used.vcol |= (1 << layer);
- }
- else {
- cd_used.sculpt_vcol |= (1 << layer);
- }
- }
- break;
- }
case CD_MCOL: {
/* Vertex Color Data */
if (layer == -1) {
@@ -473,6 +654,17 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
cd_used.orco = 1;
break;
}
+ case CD_PROP_BOOL:
+ case CD_PROP_INT32:
+ case CD_PROP_FLOAT:
+ case CD_PROP_FLOAT2:
+ case CD_PROP_FLOAT3:
+ case CD_PROP_COLOR: {
+ if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
+ drw_mesh_attributes_add_request(attributes, type, layer, domain);
+ }
+ break;
+ }
}
}
}
@@ -617,7 +809,7 @@ BLI_INLINE void mesh_batch_cache_add_request(MeshBatchCache *cache, DRWBatchFlag
/* GPUBatch cache management. */
-static bool mesh_batch_cache_valid(Mesh *me)
+static bool mesh_batch_cache_valid(Object *object, Mesh *me)
{
MeshBatchCache *cache = me->runtime.batch_cache;
@@ -633,14 +825,14 @@ static bool mesh_batch_cache_valid(Mesh *me)
return false;
}
- if (cache->mat_len != mesh_render_mat_len_get(me)) {
+ if (cache->mat_len != mesh_render_mat_len_get(object, me)) {
return false;
}
return true;
}
-static void mesh_batch_cache_init(Mesh *me)
+static void mesh_batch_cache_init(Object *object, Mesh *me)
{
MeshBatchCache *cache = me->runtime.batch_cache;
@@ -660,7 +852,7 @@ static void mesh_batch_cache_init(Mesh *me)
// cache->vert_len = mesh_render_verts_len_get(me);
}
- cache->mat_len = mesh_render_mat_len_get(me);
+ cache->mat_len = mesh_render_mat_len_get(object, me);
cache->surface_per_mat = MEM_callocN(sizeof(*cache->surface_per_mat) * cache->mat_len, __func__);
cache->tris_per_mat = MEM_callocN(sizeof(*cache->tris_per_mat) * cache->mat_len, __func__);
@@ -671,11 +863,11 @@ static void mesh_batch_cache_init(Mesh *me)
drw_mesh_weight_state_clear(&cache->weight_state);
}
-void DRW_mesh_batch_cache_validate(Mesh *me)
+void DRW_mesh_batch_cache_validate(Object *object, Mesh *me)
{
- if (!mesh_batch_cache_valid(me)) {
+ if (!mesh_batch_cache_valid(object, me)) {
mesh_batch_cache_clear(me);
- mesh_batch_cache_init(me);
+ mesh_batch_cache_init(object, me);
}
}
@@ -867,6 +1059,15 @@ static void mesh_buffer_cache_clear(MeshBufferCache *mbc)
mbc->poly_sorted.visible_tri_len = 0;
}
+static void mesh_batch_cache_free_subdiv_cache(MeshBatchCache *cache)
+{
+ if (cache->subdiv_cache) {
+ draw_subdiv_cache_free(cache->subdiv_cache);
+ MEM_freeN(cache->subdiv_cache);
+ cache->subdiv_cache = NULL;
+ }
+}
+
static void mesh_batch_cache_clear(Mesh *me)
{
MeshBatchCache *cache = me->runtime.batch_cache;
@@ -894,6 +1095,8 @@ static void mesh_batch_cache_clear(Mesh *me)
cache->batch_ready = 0;
drw_mesh_weight_state_clear(&cache->weight_state);
+
+ mesh_batch_cache_free_subdiv_cache(cache);
}
void DRW_mesh_batch_cache_free(Mesh *me)
@@ -908,24 +1111,24 @@ void DRW_mesh_batch_cache_free(Mesh *me)
/** \name Public API
* \{ */
-static void texpaint_request_active_uv(MeshBatchCache *cache, Mesh *me)
+static void texpaint_request_active_uv(MeshBatchCache *cache, Object *object, Mesh *me)
{
DRW_MeshCDMask cd_needed;
mesh_cd_layers_type_clear(&cd_needed);
- mesh_cd_calc_active_uv_layer(me, &cd_needed);
+ mesh_cd_calc_active_uv_layer(object, me, &cd_needed);
BLI_assert(cd_needed.uv != 0 &&
"No uv layer available in texpaint, but batches requested anyway!");
- mesh_cd_calc_active_mask_uv_layer(me, &cd_needed);
+ mesh_cd_calc_active_mask_uv_layer(object, me, &cd_needed);
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
}
-static void texpaint_request_active_vcol(MeshBatchCache *cache, Mesh *me)
+static void texpaint_request_active_vcol(MeshBatchCache *cache, Object *object, Mesh *me)
{
DRW_MeshCDMask cd_needed;
mesh_cd_layers_type_clear(&cd_needed);
- mesh_cd_calc_active_mloopcol_layer(me, &cd_needed);
+ mesh_cd_calc_active_mloopcol_layer(object, me, &cd_needed);
BLI_assert(cd_needed.vcol != 0 &&
"No MLOOPCOL layer available in vertpaint, but batches requested anyway!");
@@ -933,16 +1136,16 @@ static void texpaint_request_active_vcol(MeshBatchCache *cache, Mesh *me)
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
}
-static void sculpt_request_active_vcol(MeshBatchCache *cache, Mesh *me)
+static void sculpt_request_active_vcol(MeshBatchCache *cache, Object *object, Mesh *me)
{
- DRW_MeshCDMask cd_needed;
- mesh_cd_layers_type_clear(&cd_needed);
- mesh_cd_calc_active_vcol_layer(me, &cd_needed);
+ DRW_MeshAttributes attrs_needed;
+ drw_mesh_attributes_clear(&attrs_needed);
+ mesh_cd_calc_active_vcol_layer(object, me, &attrs_needed);
- BLI_assert(cd_needed.sculpt_vcol != 0 &&
+ BLI_assert(attrs_needed.num_requests != 0 &&
"No MPropCol layer available in Sculpt, but batches requested anyway!");
- mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
+ drw_mesh_attributes_merge(&cache->attr_needed, &attrs_needed, me->runtime.render_mutex);
}
GPUBatch *DRW_mesh_batch_cache_get_all_verts(Mesh *me)
@@ -1010,55 +1213,61 @@ GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(Mesh *me)
return DRW_batch_request(&cache->batch.edit_mesh_analysis);
}
-GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me,
+GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Object *object,
+ Mesh *me,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- DRW_MeshCDMask cd_needed = mesh_cd_calc_used_gpu_layers(me, gpumat_array, gpumat_array_len);
+ DRW_MeshAttributes attrs_needed;
+ drw_mesh_attributes_clear(&attrs_needed);
+ DRW_MeshCDMask cd_needed = mesh_cd_calc_used_gpu_layers(
+ object, me, gpumat_array, gpumat_array_len, &attrs_needed);
BLI_assert(gpumat_array_len == cache->mat_len);
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
+ ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex;
+ drw_mesh_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex);
mesh_batch_cache_request_surface_batches(cache);
return cache->surface_per_mat;
}
-GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me)
+GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_uv(cache, me);
+ texpaint_request_active_uv(cache, object, me);
mesh_batch_cache_request_surface_batches(cache);
return cache->surface_per_mat;
}
-GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_uv(cache, me);
+ texpaint_request_active_uv(cache, object, me);
mesh_batch_cache_request_surface_batches(cache);
return cache->batch.surface;
}
-GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_vcol(cache, me);
+ texpaint_request_active_vcol(cache, object, me);
mesh_batch_cache_request_surface_batches(cache);
return cache->batch.surface;
}
-GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- sculpt_request_active_vcol(cache, me);
+ sculpt_request_active_vcol(cache, object, me);
mesh_batch_cache_request_surface_batches(cache);
return cache->batch.surface;
}
-int DRW_mesh_material_count_get(const Mesh *me)
+int DRW_mesh_material_count_get(const Object *object, const Mesh *me)
{
- return mesh_render_mat_len_get(me);
+ return mesh_render_mat_len_get(object, me);
}
GPUBatch *DRW_mesh_batch_cache_get_sculpt_overlays(Mesh *me)
@@ -1183,31 +1392,27 @@ GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me)
/** \name UV Image editor API
* \{ */
-static void edituv_request_active_uv(MeshBatchCache *cache, Mesh *me)
+static void edituv_request_active_uv(MeshBatchCache *cache, Object *object, Mesh *me)
{
DRW_MeshCDMask cd_needed;
mesh_cd_layers_type_clear(&cd_needed);
- mesh_cd_calc_active_uv_layer(me, &cd_needed);
+ mesh_cd_calc_active_uv_layer(object, me, &cd_needed);
mesh_cd_calc_edit_uv_layer(me, &cd_needed);
BLI_assert(cd_needed.edit_uv != 0 &&
"No uv layer available in edituv, but batches requested anyway!");
- mesh_cd_calc_active_mask_uv_layer(me, &cd_needed);
+ mesh_cd_calc_active_mask_uv_layer(object, me, &cd_needed);
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
}
-/* Creates the GPUBatch for drawing the UV Stretching Area Overlay.
- * Optional retrieves the total area or total uv area of the mesh.
- *
- * The `cache->tot_area` and cache->tot_uv_area` update are calculation are
- * only valid after calling `DRW_mesh_batch_cache_create_requested`. */
-GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me,
+GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Object *object,
+ Mesh *me,
float **tot_area,
float **tot_uv_area)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- edituv_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_AREA);
if (tot_area != NULL) {
@@ -1219,58 +1424,58 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me,
return DRW_batch_request(&cache->batch.edituv_faces_stretch_area);
}
-GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- edituv_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_ANGLE);
return DRW_batch_request(&cache->batch.edituv_faces_stretch_angle);
}
-GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- edituv_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES);
return DRW_batch_request(&cache->batch.edituv_faces);
}
-GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- edituv_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_EDGES);
return DRW_batch_request(&cache->batch.edituv_edges);
}
-GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- edituv_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_VERTS);
return DRW_batch_request(&cache->batch.edituv_verts);
}
-GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- edituv_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACEDOTS);
return DRW_batch_request(&cache->batch.edituv_fdots);
}
-GPUBatch *DRW_mesh_batch_cache_get_uv_edges(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_uv_edges(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- edituv_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS_UVS);
return DRW_batch_request(&cache->batch.wire_loops_uvs);
}
-GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_uv(cache, me);
+ texpaint_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS);
return DRW_batch_request(&cache->batch.wire_loops);
}
@@ -1281,9 +1486,6 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Mesh *me)
/** \name Grouped batch generation
* \{ */
-/* Thread safety need to be assured by caller. Don't call this during drawing.
- * NOTE: For now this only free the shading batches / vbo if any cd layers is
- * not needed anymore. */
void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
{
MeshBatchCache *cache = me->runtime.batch_cache;
@@ -1296,11 +1498,25 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
cache->lastmatch = ctime;
}
+ if (drw_mesh_attributes_overlap(&cache->attr_used_over_time, &cache->attr_used)) {
+ cache->lastmatch = ctime;
+ }
+
if (ctime - cache->lastmatch > U.vbotimeout) {
mesh_batch_cache_discard_shaded_tri(cache);
}
mesh_cd_layers_type_clear(&cache->cd_used_over_time);
+ drw_mesh_attributes_clear(&cache->attr_used_over_time);
+}
+
+static void drw_add_attributes_vbo(GPUBatch *batch,
+ MeshBufferList *mbuflist,
+ DRW_MeshAttributes *attr_used)
+{
+ for (int i = 0; i < attr_used->num_requests; i++) {
+ DRW_vbo_request(batch, &mbuflist->vbo.attr[i]);
+ }
}
#ifdef DEBUG
@@ -1337,7 +1553,6 @@ static void drw_mesh_batch_cache_check_available(struct TaskGraph *task_graph, M
}
#endif
-/* Can be called for any surface type. Mesh *me is the final mesh. */
void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
Object *ob,
Mesh *me,
@@ -1363,20 +1578,12 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
/* Sanity check. */
if ((me->edit_mesh != NULL) && (ob->mode & OB_MODE_EDIT)) {
- BLI_assert(me->edit_mesh->mesh_eval_final != NULL);
+ BLI_assert(BKE_object_get_editmesh_eval_final(ob) != NULL);
}
- /* Don't check `DRW_object_is_in_edit_mode(ob)` here because it means the same mesh
- * may draw with edit-mesh data and regular mesh data.
- * In this case the custom-data layers used won't always match in `me->runtime.batch_cache`.
- * If we want to display regular mesh data, we should have a separate cache for the edit-mesh.
- * See T77359. */
const bool is_editmode = (me->edit_mesh != NULL) &&
- /* In rare cases we have the edit-mode data but not the generated cache.
- * This can happen when switching an objects data to a mesh which
- * happens to be in edit-mode in another scene, see: T82952. */
- (me->edit_mesh->mesh_eval_final !=
- NULL) /* && DRW_object_is_in_edit_mode(ob) */;
+ (BKE_object_get_editmesh_eval_final(ob) != NULL) &&
+ DRW_object_is_in_edit_mode(ob);
/* This could be set for paint mode too, currently it's only used for edit-mode. */
const bool is_mode_active = is_editmode && DRW_object_is_in_edit_mode(ob);
@@ -1402,19 +1609,22 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
/* Modifiers will only generate an orco layer if the mesh is deformed. */
if (cache->cd_needed.orco != 0) {
/* Orco is always extracted from final mesh. */
- Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
+ Mesh *me_final = (me->edit_mesh) ? BKE_object_get_editmesh_eval_final(ob) : me;
if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == NULL) {
/* Skip orco calculation */
cache->cd_needed.orco = 0;
}
}
+ ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex;
+
/* Verify that all surface batches have needed attribute layers.
*/
/* TODO(fclem): We could be a bit smarter here and only do it per
* material. */
bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_used, cache->cd_needed);
- if (cd_overlap == false) {
+ bool attr_overlap = drw_mesh_attributes_overlap(&cache->attr_used, &cache->attr_needed);
+ if (cd_overlap == false || attr_overlap == false) {
FOREACH_MESH_BUFFER_CACHE (cache, mbc) {
if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.uv);
@@ -1430,11 +1640,14 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if (cache->cd_used.sculpt_overlays != cache->cd_needed.sculpt_overlays) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.sculpt_data);
}
- if (((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) ||
- ((cache->cd_used.sculpt_vcol & cache->cd_needed.sculpt_vcol) !=
- cache->cd_needed.sculpt_vcol)) {
+ if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.vcol);
}
+ if (!drw_mesh_attributes_overlap(&cache->attr_used, &cache->attr_needed)) {
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.attr[i]);
+ }
+ }
}
/* We can't discard batches at this point as they have been
* referenced for drawing. Just clear them in place. */
@@ -1445,9 +1658,13 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
cache->batch_ready &= ~(MBC_SURFACE);
mesh_cd_layers_type_merge(&cache->cd_used, cache->cd_needed);
+ drw_mesh_attributes_merge(&cache->attr_used, &cache->attr_needed, mesh_render_mutex);
}
mesh_cd_layers_type_merge(&cache->cd_used_over_time, cache->cd_needed);
mesh_cd_layers_type_clear(&cache->cd_needed);
+
+ drw_mesh_attributes_merge(&cache->attr_used_over_time, &cache->attr_needed, mesh_render_mutex);
+ drw_mesh_attributes_clear(&cache->attr_needed);
}
if (batch_requested & MBC_EDITUV) {
@@ -1498,15 +1715,43 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
cache->batch_ready |= batch_requested;
- const bool do_cage = (is_editmode &&
- (me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage));
+ bool do_cage = false, do_uvcage = false;
+ if (is_editmode) {
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
- const bool do_uvcage = is_editmode && !me->edit_mesh->mesh_eval_final->runtime.is_original;
+ do_cage = editmesh_eval_final != editmesh_eval_cage;
+ do_uvcage = !editmesh_eval_final->runtime.is_original;
+ }
+
+ const int required_mode = BKE_subsurf_modifier_eval_required_mode(DRW_state_is_scene_render(),
+ is_editmode);
+ const bool do_subdivision = BKE_subsurf_modifier_can_do_gpu_subdiv(scene, ob, required_mode);
MeshBufferList *mbuflist = &cache->final.buff;
/* Initialize batches and request VBO's & IBO's. */
- MDEPS_ASSERT(surface, ibo.tris, vbo.lnor, vbo.pos_nor, vbo.uv, vbo.vcol);
+ MDEPS_ASSERT(surface,
+ ibo.tris,
+ vbo.lnor,
+ vbo.pos_nor,
+ vbo.uv,
+ vbo.vcol,
+ vbo.attr[0],
+ vbo.attr[1],
+ vbo.attr[2],
+ vbo.attr[3],
+ vbo.attr[4],
+ vbo.attr[5],
+ vbo.attr[6],
+ vbo.attr[7],
+ vbo.attr[8],
+ vbo.attr[9],
+ vbo.attr[10],
+ vbo.attr[11],
+ vbo.attr[12],
+ vbo.attr[13],
+ vbo.attr[14]);
if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.surface, &mbuflist->ibo.tris);
/* Order matters. First ones override latest VBO's attributes. */
@@ -1515,9 +1760,10 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if (cache->cd_used.uv != 0) {
DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.uv);
}
- if (cache->cd_used.vcol != 0 || cache->cd_used.sculpt_vcol != 0) {
+ if (cache->cd_used.vcol != 0) {
DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.vcol);
}
+ drw_add_attributes_vbo(cache->batch.surface, mbuflist, &cache->attr_used);
}
MDEPS_ASSERT(all_verts, vbo.pos_nor);
if (DRW_batch_requested(cache->batch.all_verts, GPU_PRIM_POINTS)) {
@@ -1580,8 +1826,28 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
}
/* Per Material */
- MDEPS_ASSERT_FLAG(
- SURFACE_PER_MAT_FLAG, vbo.lnor, vbo.pos_nor, vbo.uv, vbo.tan, vbo.vcol, vbo.orco);
+ MDEPS_ASSERT_FLAG(SURFACE_PER_MAT_FLAG,
+ vbo.lnor,
+ vbo.pos_nor,
+ vbo.uv,
+ vbo.tan,
+ vbo.vcol,
+ vbo.orco,
+ vbo.attr[0],
+ vbo.attr[1],
+ vbo.attr[2],
+ vbo.attr[3],
+ vbo.attr[4],
+ vbo.attr[5],
+ vbo.attr[6],
+ vbo.attr[7],
+ vbo.attr[8],
+ vbo.attr[9],
+ vbo.attr[10],
+ vbo.attr[11],
+ vbo.attr[12],
+ vbo.attr[13],
+ vbo.attr[14]);
MDEPS_ASSERT_INDEX(TRIS_PER_MAT_INDEX, SURFACE_PER_MAT_FLAG);
for (int i = 0; i < cache->mat_len; i++) {
if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) {
@@ -1595,12 +1861,13 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if ((cache->cd_used.tan != 0) || (cache->cd_used.tan_orco != 0)) {
DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.tan);
}
- if (cache->cd_used.vcol != 0 || cache->cd_used.sculpt_vcol != 0) {
+ if (cache->cd_used.vcol != 0) {
DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.vcol);
}
if (cache->cd_used.orco != 0) {
DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.orco);
}
+ drw_add_attributes_vbo(cache->surface_per_mat[i], mbuflist, &cache->attr_used);
}
}
@@ -1751,6 +2018,9 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
MDEPS_ASSERT_MAP(vbo.edituv_stretch_angle);
MDEPS_ASSERT_MAP(vbo.fdots_uv);
MDEPS_ASSERT_MAP(vbo.fdots_edituv_data);
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ MDEPS_ASSERT_MAP(vbo.attr[i]);
+ }
MDEPS_ASSERT_MAP(ibo.tris);
MDEPS_ASSERT_MAP(ibo.lines);
@@ -1773,6 +2043,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mesh_buffer_cache_create_requested(task_graph,
cache,
&cache->uv_cage,
+ ob,
me,
is_editmode,
is_paint_mode,
@@ -1790,6 +2061,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mesh_buffer_cache_create_requested(task_graph,
cache,
&cache->cage,
+ ob,
me,
is_editmode,
is_paint_mode,
@@ -1803,9 +2075,19 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
true);
}
+ if (do_subdivision) {
+ DRW_create_subdivision(scene, ob, me, cache, &cache->final, ts);
+ }
+ else {
+ /* The subsurf modifier may have been recently removed, or another modifier was added after it,
+ * so free any potential subdivision cache as it is not needed anymore. */
+ mesh_batch_cache_free_subdiv_cache(cache);
+ }
+
mesh_buffer_cache_create_requested(task_graph,
cache,
&cache->final,
+ ob,
me,
is_editmode,
is_paint_mode,
diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c
index 4d3a990ec72..63bffed0eaf 100644
--- a/source/blender/draw/intern/draw_cache_impl_metaball.c
+++ b/source/blender/draw/intern/draw_cache_impl_metaball.c
@@ -41,8 +41,9 @@
static void metaball_batch_cache_clear(MetaBall *mb);
-/* ---------------------------------------------------------------------- */
-/* MetaBall GPUBatch Cache */
+/* -------------------------------------------------------------------- */
+/** \name MetaBall GPUBatch Cache
+ * \{ */
typedef struct MetaBallBatchCache {
GPUBatch *batch;
@@ -175,6 +176,8 @@ static GPUIndexBuf *mball_batch_cache_get_edges_adj_lines(Object *ob, MetaBallBa
return cache->edges_adj_lines;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Public Object/MetaBall API
* \{ */
@@ -303,3 +306,5 @@ int DRW_metaball_material_count_get(MetaBall *mb)
{
return max_ii(1, mb->totcol);
}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index 96bdca7d935..9493a6debeb 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -634,7 +634,7 @@ static void particle_batch_cache_fill_segments_proc_pos(ParticleCacheKey **path_
seg_data[3] = total_len;
co_prev = path[j].co;
}
- /* Assign length value*/
+ /* Assign length value. */
*(float *)GPU_vertbuf_raw_step(length_step) = total_len;
if (total_len > 0.0f) {
/* Divide by total length to have a [0-1] number. */
@@ -1674,7 +1674,6 @@ GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(Object *object,
return cache->edit_tip_points;
}
-/* Ensure all textures and buffers needed for GPU accelerated drawing. */
bool particles_ensure_procedural_data(Object *object,
ParticleSystem *psys,
ModifierData *md,
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
new file mode 100644
index 00000000000..a24a3a5a3a7
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -0,0 +1,1944 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "draw_subdivision.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_eval.h"
+#include "BKE_subdiv_foreach.h"
+#include "BKE_subdiv_mesh.h"
+#include "BKE_subdiv_modifier.h"
+
+#include "BLI_linklist.h"
+
+#include "BLI_string.h"
+
+#include "PIL_time.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "GPU_capabilities.h"
+#include "GPU_compute.h"
+#include "GPU_index_buffer.h"
+#include "GPU_state.h"
+#include "GPU_vertex_buffer.h"
+
+#include "opensubdiv_capi.h"
+#include "opensubdiv_capi_type.h"
+#include "opensubdiv_converter_capi.h"
+#include "opensubdiv_evaluator_capi.h"
+#include "opensubdiv_topology_refiner_capi.h"
+
+#include "draw_cache_extract.h"
+#include "draw_cache_impl.h"
+#include "draw_cache_inline.h"
+#include "mesh_extractors/extract_mesh.h"
+
+extern "C" char datatoc_common_subdiv_custom_data_interp_comp_glsl[];
+extern "C" char datatoc_common_subdiv_ibo_lines_comp_glsl[];
+extern "C" char datatoc_common_subdiv_ibo_tris_comp_glsl[];
+extern "C" char datatoc_common_subdiv_lib_glsl[];
+extern "C" char datatoc_common_subdiv_normals_accumulate_comp_glsl[];
+extern "C" char datatoc_common_subdiv_normals_finalize_comp_glsl[];
+extern "C" char datatoc_common_subdiv_patch_evaluation_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_edge_fac_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_lnor_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_sculpt_data_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_edituv_strech_angle_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_edituv_strech_area_comp_glsl[];
+
+enum {
+ SHADER_BUFFER_LINES,
+ SHADER_BUFFER_LINES_LOOSE,
+ SHADER_BUFFER_EDGE_FAC,
+ SHADER_BUFFER_LNOR,
+ SHADER_BUFFER_TRIS,
+ SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS,
+ SHADER_BUFFER_NORMALS_ACCUMULATE,
+ SHADER_BUFFER_NORMALS_FINALIZE,
+ SHADER_PATCH_EVALUATION,
+ SHADER_PATCH_EVALUATION_LIMIT_NORMALS,
+ SHADER_PATCH_EVALUATION_FVAR,
+ SHADER_PATCH_EVALUATION_FACE_DOTS,
+ SHADER_COMP_CUSTOM_DATA_INTERP_1D,
+ SHADER_COMP_CUSTOM_DATA_INTERP_2D,
+ SHADER_COMP_CUSTOM_DATA_INTERP_3D,
+ SHADER_COMP_CUSTOM_DATA_INTERP_4D,
+ SHADER_BUFFER_SCULPT_DATA,
+ SHADER_BUFFER_UV_STRETCH_ANGLE,
+ SHADER_BUFFER_UV_STRETCH_AREA,
+
+ NUM_SHADERS,
+};
+
+static GPUShader *g_subdiv_shaders[NUM_SHADERS];
+
+static const char *get_shader_code(int shader_type)
+{
+ switch (shader_type) {
+ case SHADER_BUFFER_LINES:
+ case SHADER_BUFFER_LINES_LOOSE: {
+ return datatoc_common_subdiv_ibo_lines_comp_glsl;
+ }
+ case SHADER_BUFFER_EDGE_FAC: {
+ return datatoc_common_subdiv_vbo_edge_fac_comp_glsl;
+ }
+ case SHADER_BUFFER_LNOR: {
+ return datatoc_common_subdiv_vbo_lnor_comp_glsl;
+ }
+ case SHADER_BUFFER_TRIS:
+ case SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS: {
+ return datatoc_common_subdiv_ibo_tris_comp_glsl;
+ }
+ case SHADER_BUFFER_NORMALS_ACCUMULATE: {
+ return datatoc_common_subdiv_normals_accumulate_comp_glsl;
+ }
+ case SHADER_BUFFER_NORMALS_FINALIZE: {
+ return datatoc_common_subdiv_normals_finalize_comp_glsl;
+ }
+ case SHADER_PATCH_EVALUATION:
+ case SHADER_PATCH_EVALUATION_LIMIT_NORMALS:
+ case SHADER_PATCH_EVALUATION_FVAR:
+ case SHADER_PATCH_EVALUATION_FACE_DOTS: {
+ return datatoc_common_subdiv_patch_evaluation_comp_glsl;
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_1D:
+ case SHADER_COMP_CUSTOM_DATA_INTERP_2D:
+ case SHADER_COMP_CUSTOM_DATA_INTERP_3D:
+ case SHADER_COMP_CUSTOM_DATA_INTERP_4D: {
+ return datatoc_common_subdiv_custom_data_interp_comp_glsl;
+ }
+ case SHADER_BUFFER_SCULPT_DATA: {
+ return datatoc_common_subdiv_vbo_sculpt_data_comp_glsl;
+ }
+ case SHADER_BUFFER_UV_STRETCH_ANGLE: {
+ return datatoc_common_subdiv_vbo_edituv_strech_angle_comp_glsl;
+ }
+ case SHADER_BUFFER_UV_STRETCH_AREA: {
+ return datatoc_common_subdiv_vbo_edituv_strech_area_comp_glsl;
+ }
+ }
+ return nullptr;
+}
+
+static const char *get_shader_name(int shader_type)
+{
+ switch (shader_type) {
+ case SHADER_BUFFER_LINES: {
+ return "subdiv lines build";
+ }
+ case SHADER_BUFFER_LINES_LOOSE: {
+ return "subdiv lines loose build";
+ }
+ case SHADER_BUFFER_LNOR: {
+ return "subdiv lnor build";
+ }
+ case SHADER_BUFFER_EDGE_FAC: {
+ return "subdiv edge fac build";
+ }
+ case SHADER_BUFFER_TRIS:
+ case SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS: {
+ return "subdiv tris";
+ }
+ case SHADER_BUFFER_NORMALS_ACCUMULATE: {
+ return "subdiv normals accumulate";
+ }
+ case SHADER_BUFFER_NORMALS_FINALIZE: {
+ return "subdiv normals finalize";
+ }
+ case SHADER_PATCH_EVALUATION: {
+ return "subdiv patch evaluation";
+ }
+ case SHADER_PATCH_EVALUATION_LIMIT_NORMALS: {
+ return "subdiv patch evaluation limit normals";
+ }
+ case SHADER_PATCH_EVALUATION_FVAR: {
+ return "subdiv patch evaluation face-varying";
+ }
+ case SHADER_PATCH_EVALUATION_FACE_DOTS: {
+ return "subdiv patch evaluation face dots";
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_1D: {
+ return "subdiv custom data interp 1D";
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_2D: {
+ return "subdiv custom data interp 2D";
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_3D: {
+ return "subdiv custom data interp 3D";
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_4D: {
+ return "subdiv custom data interp 4D";
+ }
+ case SHADER_BUFFER_SCULPT_DATA: {
+ return "subdiv sculpt data";
+ }
+ case SHADER_BUFFER_UV_STRETCH_ANGLE: {
+ return "subdiv uv stretch angle";
+ }
+ case SHADER_BUFFER_UV_STRETCH_AREA: {
+ return "subdiv uv stretch area";
+ }
+ }
+ return nullptr;
+}
+
+static GPUShader *get_patch_evaluation_shader(int shader_type)
+{
+ if (g_subdiv_shaders[shader_type] == nullptr) {
+ const char *compute_code = get_shader_code(shader_type);
+
+ const char *defines = nullptr;
+ if (shader_type == SHADER_PATCH_EVALUATION_LIMIT_NORMALS) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define LIMIT_NORMALS\n";
+ }
+ else if (shader_type == SHADER_PATCH_EVALUATION_FVAR) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define FVAR_EVALUATION\n";
+ }
+ else if (shader_type == SHADER_PATCH_EVALUATION_FACE_DOTS) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define FDOTS_EVALUATION\n";
+ }
+ else {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n";
+ }
+
+ /* Merge OpenSubdiv library code with our own library code. */
+ const char *patch_basis_source = openSubdiv_getGLSLPatchBasisSource();
+ const char *subdiv_lib_code = datatoc_common_subdiv_lib_glsl;
+ char *library_code = static_cast<char *>(
+ MEM_mallocN(strlen(patch_basis_source) + strlen(subdiv_lib_code) + 1,
+ "subdiv patch evaluation library code"));
+ library_code[0] = '\0';
+ strcat(library_code, patch_basis_source);
+ strcat(library_code, subdiv_lib_code);
+
+ g_subdiv_shaders[shader_type] = GPU_shader_create_compute(
+ compute_code, library_code, defines, get_shader_name(shader_type));
+
+ MEM_freeN(library_code);
+ }
+
+ return g_subdiv_shaders[shader_type];
+}
+
+static GPUShader *get_subdiv_shader(int shader_type, const char *defines)
+{
+ if (ELEM(shader_type,
+ SHADER_PATCH_EVALUATION,
+ SHADER_PATCH_EVALUATION_LIMIT_NORMALS,
+ SHADER_PATCH_EVALUATION_FVAR,
+ SHADER_PATCH_EVALUATION_FACE_DOTS)) {
+ return get_patch_evaluation_shader(shader_type);
+ }
+ if (g_subdiv_shaders[shader_type] == nullptr) {
+ const char *compute_code = get_shader_code(shader_type);
+ g_subdiv_shaders[shader_type] = GPU_shader_create_compute(
+ compute_code, datatoc_common_subdiv_lib_glsl, defines, get_shader_name(shader_type));
+ }
+ return g_subdiv_shaders[shader_type];
+}
+
+/* -------------------------------------------------------------------- */
+/** Vertex formats used for data transfer from OpenSubdiv, and for data processing on our side.
+ * \{ */
+
+static GPUVertFormat *get_uvs_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
+/* Vertex format for `OpenSubdiv::Osd::PatchArray`. */
+static GPUVertFormat *get_patch_array_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "regDesc", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "desc", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "numPatches", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "indexBase", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "stride", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "primitiveIdBase", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/* Vertex format used for the `PatchTable::PatchHandle`. */
+static GPUVertFormat *get_patch_handle_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "vertex_index", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "array_index", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "patch_index", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/* Vertex format used for the quad-tree nodes of the PatchMap. */
+static GPUVertFormat *get_quadtree_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "child", GPU_COMP_U32, 4, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/* Vertex format for `OpenSubdiv::Osd::PatchParam`, not really used, it is only for making sure
+ * that the #GPUVertBuf used to wrap the OpenSubdiv patch param buffer is valid. */
+static GPUVertFormat *get_patch_param_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
+/* Vertex format for the patches' vertices index buffer. */
+static GPUVertFormat *get_patch_index_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/* Vertex format for the OpenSubdiv vertex buffer. */
+static GPUVertFormat *get_subdiv_vertex_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* We use 4 components for the vectors to account for padding in the compute shaders, where
+ * vec3 is promoted to vec4. */
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
+struct CompressedPatchCoord {
+ int ptex_face_index;
+ /* UV coordinate encoded as u << 16 | v, where u and v are quantized on 16-bits. */
+ unsigned int encoded_uv;
+};
+
+MINLINE CompressedPatchCoord make_patch_coord(int ptex_face_index, float u, float v)
+{
+ CompressedPatchCoord patch_coord = {
+ ptex_face_index,
+ (static_cast<unsigned int>(u * 65535.0f) << 16) | static_cast<unsigned int>(v * 65535.0f),
+ };
+ return patch_coord;
+}
+
+/* Vertex format used for the #CompressedPatchCoord. */
+static GPUVertFormat *get_blender_patch_coords_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* WARNING! Adjust #CompressedPatchCoord accordingly. */
+ GPU_vertformat_attr_add(&format, "ptex_face_index", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "uv", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+static GPUVertFormat *get_origindex_format()
+{
+ static GPUVertFormat format;
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities to initialize a OpenSubdiv_Buffer for a GPUVertBuf.
+ * \{ */
+
+static void vertbuf_bind_gpu(const OpenSubdiv_Buffer *buffer)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(buffer->data);
+ GPU_vertbuf_use(verts);
+}
+
+static void *vertbuf_alloc(const OpenSubdiv_Buffer *interface, const uint len)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(interface->data);
+ GPU_vertbuf_data_alloc(verts, len);
+ return GPU_vertbuf_get_data(verts);
+}
+
+static void vertbuf_device_alloc(const OpenSubdiv_Buffer *interface, const uint len)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(interface->data);
+ /* This assumes that GPU_USAGE_DEVICE_ONLY was used, which won't allocate host memory. */
+ // BLI_assert(GPU_vertbuf_get_usage(verts) == GPU_USAGE_DEVICE_ONLY);
+ GPU_vertbuf_data_alloc(verts, len);
+}
+
+static void vertbuf_wrap_device_handle(const OpenSubdiv_Buffer *interface, uint64_t handle)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(interface->data);
+ GPU_vertbuf_wrap_handle(verts, handle);
+}
+
+static void vertbuf_update_data(const OpenSubdiv_Buffer *interface,
+ uint start,
+ uint len,
+ const void *data)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(interface->data);
+ GPU_vertbuf_update_sub(verts, start, len, data);
+}
+
+static void opensubdiv_gpu_buffer_init(OpenSubdiv_Buffer *buffer_interface, GPUVertBuf *vertbuf)
+{
+ buffer_interface->data = vertbuf;
+ buffer_interface->bind_gpu = vertbuf_bind_gpu;
+ buffer_interface->buffer_offset = 0;
+ buffer_interface->wrap_device_handle = vertbuf_wrap_device_handle;
+ buffer_interface->alloc = vertbuf_alloc;
+ buffer_interface->device_alloc = vertbuf_device_alloc;
+ buffer_interface->device_update = vertbuf_update_data;
+}
+
+static GPUVertBuf *create_buffer_and_interface(OpenSubdiv_Buffer *interface, GPUVertFormat *format)
+{
+ GPUVertBuf *buffer = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(buffer, format, GPU_USAGE_DEVICE_ONLY);
+ opensubdiv_gpu_buffer_init(interface, buffer);
+ return buffer;
+}
+
+/** \} */
+
+// --------------------------------------------------------
+
+static uint tris_count_from_number_of_loops(const uint number_of_loops)
+{
+ const uint32_t number_of_quads = number_of_loops / 4;
+ return number_of_quads * 2;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities to build a GPUVertBuf from an origindex buffer.
+ * \{ */
+
+void draw_subdiv_init_origindex_buffer(GPUVertBuf *buffer,
+ int *vert_origindex,
+ uint num_loops,
+ uint loose_len)
+{
+ GPU_vertbuf_init_with_format_ex(buffer, get_origindex_format(), GPU_USAGE_STATIC);
+ GPU_vertbuf_data_alloc(buffer, num_loops + loose_len);
+
+ int *vbo_data = (int *)GPU_vertbuf_get_data(buffer);
+ memcpy(vbo_data, vert_origindex, num_loops * sizeof(int));
+}
+
+GPUVertBuf *draw_subdiv_build_origindex_buffer(int *vert_origindex, uint num_loops)
+{
+ GPUVertBuf *buffer = GPU_vertbuf_calloc();
+ draw_subdiv_init_origindex_buffer(buffer, vert_origindex, num_loops, 0);
+ return buffer;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities for DRWPatchMap.
+ * \{ */
+
+static void draw_patch_map_build(DRWPatchMap *gpu_patch_map, Subdiv *subdiv)
+{
+ GPUVertBuf *patch_map_handles = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(patch_map_handles, get_patch_handle_format(), GPU_USAGE_STATIC);
+
+ GPUVertBuf *patch_map_quadtree = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(patch_map_quadtree, get_quadtree_format(), GPU_USAGE_STATIC);
+
+ OpenSubdiv_Buffer patch_map_handles_interface;
+ opensubdiv_gpu_buffer_init(&patch_map_handles_interface, patch_map_handles);
+
+ OpenSubdiv_Buffer patch_map_quad_tree_interface;
+ opensubdiv_gpu_buffer_init(&patch_map_quad_tree_interface, patch_map_quadtree);
+
+ int min_patch_face = 0;
+ int max_patch_face = 0;
+ int max_depth = 0;
+ int patches_are_triangular = 0;
+
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+ evaluator->getPatchMap(evaluator,
+ &patch_map_handles_interface,
+ &patch_map_quad_tree_interface,
+ &min_patch_face,
+ &max_patch_face,
+ &max_depth,
+ &patches_are_triangular);
+
+ gpu_patch_map->patch_map_handles = patch_map_handles;
+ gpu_patch_map->patch_map_quadtree = patch_map_quadtree;
+ gpu_patch_map->min_patch_face = min_patch_face;
+ gpu_patch_map->max_patch_face = max_patch_face;
+ gpu_patch_map->max_depth = max_depth;
+ gpu_patch_map->patches_are_triangular = patches_are_triangular;
+}
+
+static void draw_patch_map_free(DRWPatchMap *gpu_patch_map)
+{
+ GPU_VERTBUF_DISCARD_SAFE(gpu_patch_map->patch_map_handles);
+ GPU_VERTBUF_DISCARD_SAFE(gpu_patch_map->patch_map_quadtree);
+ gpu_patch_map->min_patch_face = 0;
+ gpu_patch_map->max_patch_face = 0;
+ gpu_patch_map->max_depth = 0;
+ gpu_patch_map->patches_are_triangular = 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DRWSubdivCache
+ * \{ */
+
+static void draw_subdiv_cache_free_material_data(DRWSubdivCache *cache)
+{
+ GPU_VERTBUF_DISCARD_SAFE(cache->polygon_mat_offset);
+ MEM_SAFE_FREE(cache->mat_start);
+ MEM_SAFE_FREE(cache->mat_end);
+}
+
+static void draw_subdiv_free_edit_mode_cache(DRWSubdivCache *cache)
+{
+ GPU_VERTBUF_DISCARD_SAFE(cache->verts_orig_index);
+ GPU_VERTBUF_DISCARD_SAFE(cache->edges_orig_index);
+ GPU_VERTBUF_DISCARD_SAFE(cache->fdots_patch_coords);
+}
+
+void draw_subdiv_cache_free(DRWSubdivCache *cache)
+{
+ GPU_VERTBUF_DISCARD_SAFE(cache->patch_coords);
+ GPU_VERTBUF_DISCARD_SAFE(cache->face_ptex_offset_buffer);
+ GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_polygon_offset_buffer);
+ GPU_VERTBUF_DISCARD_SAFE(cache->extra_coarse_face_data);
+ MEM_SAFE_FREE(cache->subdiv_loop_subdiv_vert_index);
+ MEM_SAFE_FREE(cache->subdiv_loop_poly_index);
+ MEM_SAFE_FREE(cache->point_indices);
+ MEM_SAFE_FREE(cache->subdiv_polygon_offset);
+ GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_vertex_face_adjacency_offsets);
+ GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_vertex_face_adjacency);
+ cache->resolution = 0;
+ cache->num_subdiv_loops = 0;
+ cache->num_subdiv_edges = 0;
+ cache->num_subdiv_verts = 0;
+ cache->num_subdiv_triangles = 0;
+ cache->num_coarse_poly = 0;
+ cache->num_subdiv_quads = 0;
+ draw_subdiv_free_edit_mode_cache(cache);
+ draw_subdiv_cache_free_material_data(cache);
+ draw_patch_map_free(&cache->gpu_patch_map);
+ if (cache->ubo) {
+ GPU_uniformbuf_free(cache->ubo);
+ cache->ubo = nullptr;
+ }
+}
+
+/* Flags used in #DRWSubdivCache.extra_coarse_face_data. The flags are packed in the upper bits of
+ * each uint (one per coarse face), #SUBDIV_COARSE_FACE_FLAG_OFFSET tells where they are in the
+ * packed bits. */
+#define SUBDIV_COARSE_FACE_FLAG_SMOOTH 1u
+#define SUBDIV_COARSE_FACE_FLAG_SELECT 2u
+#define SUBDIV_COARSE_FACE_FLAG_ACTIVE 4u
+
+#define SUBDIV_COARSE_FACE_FLAG_OFFSET 29u
+
+#define SUBDIV_COARSE_FACE_FLAG_SMOOTH_MASK \
+ (SUBDIV_COARSE_FACE_FLAG_SMOOTH << SUBDIV_COARSE_FACE_FLAG_OFFSET)
+#define SUBDIV_COARSE_FACE_FLAG_SELECT_MASK \
+ (SUBDIV_COARSE_FACE_FLAG_SELECT << SUBDIV_COARSE_FACE_FLAG_OFFSET)
+#define SUBDIV_COARSE_FACE_FLAG_ACTIVE_MASK \
+ (SUBDIV_COARSE_FACE_FLAG_ACTIVE << SUBDIV_COARSE_FACE_FLAG_OFFSET)
+
+#define SUBDIV_COARSE_FACE_LOOP_START_MASK \
+ ~((SUBDIV_COARSE_FACE_FLAG_SMOOTH | SUBDIV_COARSE_FACE_FLAG_SELECT | \
+ SUBDIV_COARSE_FACE_FLAG_ACTIVE) \
+ << SUBDIV_COARSE_FACE_FLAG_OFFSET)
+
+static void draw_subdiv_cache_update_extra_coarse_face_data(DRWSubdivCache *cache, Mesh *mesh)
+{
+ if (cache->extra_coarse_face_data == nullptr) {
+ cache->extra_coarse_face_data = GPU_vertbuf_calloc();
+ static GPUVertFormat format;
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+ GPU_vertbuf_init_with_format_ex(cache->extra_coarse_face_data, &format, GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(cache->extra_coarse_face_data, mesh->totpoly);
+ }
+
+ uint32_t *flags_data = (uint32_t *)(GPU_vertbuf_get_data(cache->extra_coarse_face_data));
+
+ if (cache->bm) {
+ BMesh *bm = cache->bm;
+ BMFace *f;
+ BMIter iter;
+
+ /* Ensure all current elements follow new customdata layout. */
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ const int index = BM_elem_index_get(f);
+ uint32_t flag = 0;
+ if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
+ flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH;
+ }
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ flag |= SUBDIV_COARSE_FACE_FLAG_SELECT;
+ }
+ if (f == bm->act_face) {
+ flag |= SUBDIV_COARSE_FACE_FLAG_ACTIVE;
+ }
+ const int loopstart = BM_elem_index_get(f->l_first);
+ flags_data[index] = (uint)(loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totpoly; i++) {
+ uint32_t flag = 0;
+ if ((mesh->mpoly[i].flag & ME_SMOOTH) != 0) {
+ flag = SUBDIV_COARSE_FACE_FLAG_SMOOTH;
+ }
+ flags_data[i] = (uint)(mesh->mpoly[i].loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);
+ }
+ }
+
+ /* Make sure updated data is re-uploaded. */
+ GPU_vertbuf_tag_dirty(cache->extra_coarse_face_data);
+}
+
+static DRWSubdivCache *mesh_batch_cache_ensure_subdiv_cache(MeshBatchCache *mbc)
+{
+ DRWSubdivCache *subdiv_cache = mbc->subdiv_cache;
+ if (subdiv_cache == nullptr) {
+ subdiv_cache = static_cast<DRWSubdivCache *>(
+ MEM_callocN(sizeof(DRWSubdivCache), "DRWSubdivCache"));
+ }
+ mbc->subdiv_cache = subdiv_cache;
+ return subdiv_cache;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Subdivision grid traversal.
+ *
+ * Traverse the uniform subdivision grid over coarse faces and gather useful information for
+ * building the draw buffers on the GPU. We primarily gather the patch coordinates for all
+ * subdivision faces, as well as the original coarse indices for each subdivision element (vertex,
+ * face, or edge) which directly maps to its coarse counterpart (note that all subdivision faces
+ * map to a coarse face). This information will then be cached in #DRWSubdivCache for subsequent
+ * reevaluations, as long as the topology does not change.
+ * \{ */
+
+struct DRWCacheBuildingContext {
+ const Mesh *coarse_mesh;
+ const SubdivToMeshSettings *settings;
+
+ DRWSubdivCache *cache;
+
+ /* Pointers into DRWSubdivCache buffers for easier access during traversal. */
+ CompressedPatchCoord *patch_coords;
+ int *subdiv_loop_vert_index;
+ int *subdiv_loop_subdiv_vert_index;
+ int *subdiv_loop_edge_index;
+ int *subdiv_loop_poly_index;
+ int *point_indices;
+
+ /* Temporary buffers used during traversal. */
+ int *vert_origindex_map;
+ int *edge_origindex_map;
+
+ /* Origindex layers from the mesh to directly look up during traversal the origindex from the
+ * base mesh for edit data so that we do not have to handle yet another GPU buffer and do this in
+ * the shaders. */
+ int *v_origindex;
+ int *e_origindex;
+};
+
+static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_context,
+ const int num_vertices,
+ const int num_edges,
+ const int num_loops,
+ const int num_polygons,
+ const int *subdiv_polygon_offset)
+{
+ if (num_loops == 0) {
+ return false;
+ }
+
+ DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
+ DRWSubdivCache *cache = ctx->cache;
+
+ /* Set topology information. */
+ cache->num_subdiv_edges = (uint)num_edges;
+ cache->num_subdiv_loops = (uint)num_loops;
+ cache->num_subdiv_verts = (uint)num_vertices;
+ cache->num_subdiv_quads = (uint)num_polygons;
+ cache->subdiv_polygon_offset = static_cast<int *>(MEM_dupallocN(subdiv_polygon_offset));
+
+ /* Initialize cache buffers, prefer dynamic usage so we can reuse memory on the host even after
+ * it was sent to the device, since we may use the data while building other buffers on the CPU
+ * side. */
+ cache->patch_coords = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(
+ cache->patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(cache->patch_coords, cache->num_subdiv_loops);
+
+ cache->verts_orig_index = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(
+ cache->verts_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(cache->verts_orig_index, cache->num_subdiv_loops);
+
+ cache->edges_orig_index = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(
+ cache->edges_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(cache->edges_orig_index, cache->num_subdiv_loops);
+
+ cache->subdiv_loop_subdiv_vert_index = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_subdiv_vert_index"));
+
+ cache->subdiv_loop_poly_index = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_poly_index"));
+
+ const int num_coarse_vertices = ctx->coarse_mesh->totvert;
+ cache->point_indices = static_cast<int *>(
+ MEM_mallocN(num_coarse_vertices * sizeof(int), "point_indices"));
+ for (int i = 0; i < num_coarse_vertices; i++) {
+ cache->point_indices[i] = -1;
+ }
+
+ /* Initialize context pointers and temporary buffers. */
+ ctx->patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data(cache->patch_coords);
+ ctx->subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(cache->verts_orig_index);
+ ctx->subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(cache->edges_orig_index);
+ ctx->subdiv_loop_subdiv_vert_index = cache->subdiv_loop_subdiv_vert_index;
+ ctx->subdiv_loop_poly_index = cache->subdiv_loop_poly_index;
+ ctx->point_indices = cache->point_indices;
+
+ ctx->v_origindex = static_cast<int *>(
+ CustomData_get_layer(&ctx->coarse_mesh->vdata, CD_ORIGINDEX));
+
+ ctx->e_origindex = static_cast<int *>(
+ CustomData_get_layer(&ctx->coarse_mesh->edata, CD_ORIGINDEX));
+
+ ctx->vert_origindex_map = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_verts * sizeof(int), "subdiv_vert_origindex_map"));
+ for (int i = 0; i < num_vertices; i++) {
+ ctx->vert_origindex_map[i] = -1;
+ }
+
+ ctx->edge_origindex_map = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_edges * sizeof(int), "subdiv_edge_origindex_map"));
+ for (int i = 0; i < num_edges; i++) {
+ ctx->edge_origindex_map[i] = -1;
+ }
+
+ return true;
+}
+
+static void draw_subdiv_vertex_corner_cb(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int UNUSED(ptex_face_index),
+ const float UNUSED(u),
+ const float UNUSED(v),
+ const int coarse_vertex_index,
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int subdiv_vertex_index)
+{
+ BLI_assert(coarse_vertex_index != ORIGINDEX_NONE);
+ DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
+ ctx->vert_origindex_map[subdiv_vertex_index] = coarse_vertex_index;
+}
+
+static void draw_subdiv_vertex_edge_cb(const SubdivForeachContext *UNUSED(foreach_context),
+ void *UNUSED(tls_v),
+ const int UNUSED(ptex_face_index),
+ const float UNUSED(u),
+ const float UNUSED(v),
+ const int UNUSED(coarse_edge_index),
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int UNUSED(subdiv_vertex_index))
+{
+ /* Required if SubdivForeachContext.vertex_corner is also set. */
+}
+
+static void draw_subdiv_edge_cb(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_edge_index,
+ const int subdiv_edge_index,
+ const int UNUSED(subdiv_v1),
+ const int UNUSED(subdiv_v2))
+{
+ DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
+
+ int coarse_index = coarse_edge_index;
+
+ if (coarse_index != -1) {
+ if (ctx->e_origindex) {
+ coarse_index = ctx->e_origindex[coarse_index];
+ }
+ }
+
+ ctx->edge_origindex_map[subdiv_edge_index] = coarse_index;
+}
+
+static void draw_subdiv_loop_cb(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls_v),
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int UNUSED(coarse_loop_index),
+ const int coarse_poly_index,
+ const int UNUSED(coarse_corner),
+ const int subdiv_loop_index,
+ const int subdiv_vertex_index,
+ const int subdiv_edge_index)
+{
+ DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
+ ctx->patch_coords[subdiv_loop_index] = make_patch_coord(ptex_face_index, u, v);
+
+ int coarse_vertex_index = ctx->vert_origindex_map[subdiv_vertex_index];
+
+ if (coarse_vertex_index != -1) {
+ if (ctx->v_origindex) {
+ coarse_vertex_index = ctx->v_origindex[coarse_vertex_index];
+ }
+
+ /* Double check as vorigindex may have modified the index. */
+ if (coarse_vertex_index != -1) {
+ ctx->point_indices[coarse_vertex_index] = subdiv_loop_index;
+ }
+ }
+
+ ctx->subdiv_loop_subdiv_vert_index[subdiv_loop_index] = subdiv_vertex_index;
+ /* For now index the subdiv_edge_index, it will be replaced by the actual coarse edge index
+ * at the end of the traversal as some edges are only then traversed. */
+ ctx->subdiv_loop_edge_index[subdiv_loop_index] = subdiv_edge_index;
+ ctx->subdiv_loop_poly_index[subdiv_loop_index] = coarse_poly_index;
+ ctx->subdiv_loop_vert_index[subdiv_loop_index] = coarse_vertex_index;
+}
+
+static void draw_subdiv_foreach_callbacks(SubdivForeachContext *foreach_context)
+{
+ memset(foreach_context, 0, sizeof(*foreach_context));
+ foreach_context->topology_info = draw_subdiv_topology_info_cb;
+ foreach_context->loop = draw_subdiv_loop_cb;
+ foreach_context->edge = draw_subdiv_edge_cb;
+ foreach_context->vertex_corner = draw_subdiv_vertex_corner_cb;
+ foreach_context->vertex_edge = draw_subdiv_vertex_edge_cb;
+}
+
+static void do_subdiv_traversal(DRWCacheBuildingContext *cache_building_context, Subdiv *subdiv)
+{
+ SubdivForeachContext foreach_context;
+ draw_subdiv_foreach_callbacks(&foreach_context);
+ foreach_context.user_data = cache_building_context;
+
+ BKE_subdiv_foreach_subdiv_geometry(subdiv,
+ &foreach_context,
+ cache_building_context->settings,
+ cache_building_context->coarse_mesh);
+
+ /* Now that traversal is done, we can set up the right original indices for the loop-to-edge map.
+ */
+ for (int i = 0; i < cache_building_context->cache->num_subdiv_loops; i++) {
+ cache_building_context->subdiv_loop_edge_index[i] =
+ cache_building_context
+ ->edge_origindex_map[cache_building_context->subdiv_loop_edge_index[i]];
+ }
+}
+
+static GPUVertBuf *gpu_vertbuf_create_from_format(GPUVertFormat *format, uint len)
+{
+ GPUVertBuf *verts = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format(verts, format);
+ GPU_vertbuf_data_alloc(verts, len);
+ return verts;
+}
+
+/* Build maps to hold enough information to tell which face is adjacent to which vertex; those will
+ * be used for computing normals if limit surfaces are unavailable. */
+static void build_vertex_face_adjacency_maps(DRWSubdivCache *cache)
+{
+ /* +1 so that we do not require a special case for the last vertex, this extra offset will
+ * contain the total number of adjacent faces. */
+ cache->subdiv_vertex_face_adjacency_offsets = gpu_vertbuf_create_from_format(
+ get_origindex_format(), cache->num_subdiv_verts + 1);
+
+ int *vertex_offsets = (int *)GPU_vertbuf_get_data(cache->subdiv_vertex_face_adjacency_offsets);
+ memset(vertex_offsets, 0, sizeof(int) * cache->num_subdiv_verts + 1);
+
+ for (int i = 0; i < cache->num_subdiv_loops; i++) {
+ vertex_offsets[cache->subdiv_loop_subdiv_vert_index[i]]++;
+ }
+
+ int ofs = vertex_offsets[0];
+ vertex_offsets[0] = 0;
+ for (uint i = 1; i < cache->num_subdiv_verts + 1; i++) {
+ int tmp = vertex_offsets[i];
+ vertex_offsets[i] = ofs;
+ ofs += tmp;
+ }
+
+ cache->subdiv_vertex_face_adjacency = gpu_vertbuf_create_from_format(get_origindex_format(),
+ cache->num_subdiv_loops);
+ int *adjacent_faces = (int *)GPU_vertbuf_get_data(cache->subdiv_vertex_face_adjacency);
+ int *tmp_set_faces = static_cast<int *>(
+ MEM_callocN(sizeof(int) * cache->num_subdiv_verts, "tmp subdiv vertex offset"));
+
+ for (int i = 0; i < cache->num_subdiv_loops / 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ const int subdiv_vertex = cache->subdiv_loop_subdiv_vert_index[i * 4 + j];
+ int first_face_offset = vertex_offsets[subdiv_vertex] + tmp_set_faces[subdiv_vertex];
+ adjacent_faces[first_face_offset] = i;
+ tmp_set_faces[subdiv_vertex] += 1;
+ }
+ }
+
+ MEM_freeN(tmp_set_faces);
+}
+
+static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
+ Subdiv *subdiv,
+ Mesh *mesh_eval,
+ const Scene *scene,
+ const SubsurfModifierData *smd,
+ const bool is_final_render)
+{
+ const int requested_levels = (is_final_render) ? smd->renderLevels : smd->levels;
+ const int level = get_render_subsurf_level(&scene->r, requested_levels, is_final_render);
+ SubdivToMeshSettings to_mesh_settings;
+ to_mesh_settings.resolution = (1 << level) + 1;
+ to_mesh_settings.use_optimal_display = false;
+
+ if (cache->resolution != to_mesh_settings.resolution) {
+ /* Resolution changed, we need to rebuild, free any existing cached data. */
+ draw_subdiv_cache_free(cache);
+ }
+
+ /* If the resolution between the cache and the settings match for some reason, check if the patch
+ * coordinates were not already generated. Those coordinates are specific to the resolution, so
+ * they should be null either after initialization, or after freeing if the resolution (or some
+ * other subdivision setting) changed.
+ */
+ if (cache->patch_coords != nullptr) {
+ return true;
+ }
+
+ DRWCacheBuildingContext cache_building_context;
+ memset(&cache_building_context, 0, sizeof(DRWCacheBuildingContext));
+ cache_building_context.coarse_mesh = mesh_eval;
+ cache_building_context.settings = &to_mesh_settings;
+ cache_building_context.cache = cache;
+
+ do_subdiv_traversal(&cache_building_context, subdiv);
+ if (cache->num_subdiv_loops == 0) {
+ /* Either the traversal failed, or we have an empty mesh, either way we cannot go any further.
+ * The subdiv_polygon_offset cannot then be reliably stored in the cache, so free it directly.
+ */
+ MEM_SAFE_FREE(cache->subdiv_polygon_offset);
+ return false;
+ }
+
+ /* Build buffers for the PatchMap. */
+ draw_patch_map_build(&cache->gpu_patch_map, subdiv);
+
+ cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
+
+ // Build patch coordinates for all the face dots
+ cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(),
+ mesh_eval->totpoly);
+ CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data(
+ cache->fdots_patch_coords);
+ for (int i = 0; i < mesh_eval->totpoly; i++) {
+ const int ptex_face_index = cache->face_ptex_offset[i];
+ if (mesh_eval->mpoly[i].totloop == 4) {
+ /* For quads, the center coordinate of the coarse face has `u = v = 0.5`. */
+ blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 0.5f, 0.5f);
+ }
+ else {
+ /* For N-gons, since they are split into quads from the center, and since the center is
+ * chosen to be the top right corner of each quad, the center coordinate of the coarse face
+ * is any one of those top right corners with `u = v = 1.0`. */
+ blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 1.0f, 1.0f);
+ }
+ }
+
+ cache->resolution = to_mesh_settings.resolution;
+
+ cache->subdiv_polygon_offset_buffer = draw_subdiv_build_origindex_buffer(
+ cache->subdiv_polygon_offset, mesh_eval->totpoly);
+
+ cache->face_ptex_offset_buffer = draw_subdiv_build_origindex_buffer(cache->face_ptex_offset,
+ mesh_eval->totpoly + 1);
+ cache->num_coarse_poly = mesh_eval->totpoly;
+ cache->point_indices = cache_building_context.point_indices;
+
+ build_vertex_face_adjacency_maps(cache);
+
+ /* Cleanup. */
+ MEM_freeN(cache_building_context.vert_origindex_map);
+ MEM_freeN(cache_building_context.edge_origindex_map);
+
+ return true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DRWSubdivUboStorage.
+ *
+ * Common uniforms for the various shaders.
+ * \{ */
+
+struct DRWSubdivUboStorage {
+ /* Offsets in the buffers data where the source and destination data start. */
+ int src_offset;
+ int dst_offset;
+
+ /* Parameters for the DRWPatchMap. */
+ int min_patch_face;
+ int max_patch_face;
+ int max_depth;
+ int patches_are_triangular;
+
+ /* Coarse topology information. */
+ int coarse_poly_count;
+ uint edge_loose_offset;
+
+ /* Refined topology information. */
+ uint num_subdiv_loops;
+
+ /* Subdivision settings, is int in C but bool in the GLSL code, as there, bools have the same
+ * size as ints, so we should use int in C to ensure that the size of the structure is what GLSL
+ * expects. */
+ int optimal_display;
+
+ /* The sculpt mask data layer may be null. */
+ int has_sculpt_mask;
+
+ /* Masks for the extra coarse face data. */
+ uint coarse_face_select_mask;
+ uint coarse_face_smooth_mask;
+ uint coarse_face_active_mask;
+ uint coarse_face_loopstart_mask;
+
+ /* Number of elements to process in the compute shader (can be the coarse quad count, or the
+ * final vertex count, depending on which compute pass we do). This is used to early out in case
+ * of out of bond accesses as compute dispatch are of fixed size. */
+ uint total_dispatch_size;
+};
+
+static_assert((sizeof(DRWSubdivUboStorage) % 16) == 0,
+ "DRWSubdivUboStorage is not padded to a multiple of the size of vec4");
+
+static void draw_subdiv_init_ubo_storage(const DRWSubdivCache *cache,
+ DRWSubdivUboStorage *ubo,
+ const int src_offset,
+ const int dst_offset,
+ const uint total_dispatch_size,
+ const bool has_sculpt_mask)
+{
+ ubo->src_offset = src_offset;
+ ubo->dst_offset = dst_offset;
+ ubo->min_patch_face = cache->gpu_patch_map.min_patch_face;
+ ubo->max_patch_face = cache->gpu_patch_map.max_patch_face;
+ ubo->max_depth = cache->gpu_patch_map.max_depth;
+ ubo->patches_are_triangular = cache->gpu_patch_map.patches_are_triangular;
+ ubo->coarse_poly_count = cache->num_coarse_poly;
+ ubo->optimal_display = cache->optimal_display;
+ ubo->num_subdiv_loops = cache->num_subdiv_loops;
+ ubo->edge_loose_offset = cache->num_subdiv_loops * 2;
+ ubo->has_sculpt_mask = has_sculpt_mask;
+ ubo->coarse_face_smooth_mask = SUBDIV_COARSE_FACE_FLAG_SMOOTH_MASK;
+ ubo->coarse_face_select_mask = SUBDIV_COARSE_FACE_FLAG_SELECT_MASK;
+ ubo->coarse_face_active_mask = SUBDIV_COARSE_FACE_FLAG_ACTIVE_MASK;
+ ubo->coarse_face_loopstart_mask = SUBDIV_COARSE_FACE_LOOP_START_MASK;
+ ubo->total_dispatch_size = total_dispatch_size;
+}
+
+static void draw_subdiv_ubo_update_and_bind(const DRWSubdivCache *cache,
+ GPUShader *shader,
+ const int src_offset,
+ const int dst_offset,
+ const uint total_dispatch_size,
+ const bool has_sculpt_mask = false)
+{
+ DRWSubdivUboStorage storage;
+ draw_subdiv_init_ubo_storage(
+ cache, &storage, src_offset, dst_offset, total_dispatch_size, has_sculpt_mask);
+
+ if (!cache->ubo) {
+ const_cast<DRWSubdivCache *>(cache)->ubo = GPU_uniformbuf_create_ex(
+ sizeof(DRWSubdivUboStorage), &storage, "DRWSubdivUboStorage");
+ }
+
+ GPU_uniformbuf_update(cache->ubo, &storage);
+
+ const int location = GPU_shader_get_uniform_block(shader, "shader_data");
+ GPU_uniformbuf_bind(cache->ubo, location);
+}
+
+/** \} */
+
+// --------------------------------------------------------
+
+#define SUBDIV_LOCAL_WORK_GROUP_SIZE 64
+static uint get_dispatch_size(uint elements)
+{
+ return divide_ceil_u(elements, SUBDIV_LOCAL_WORK_GROUP_SIZE);
+}
+
+/**
+ * Helper to ensure that the UBO is always initialized before dispatching computes and that the
+ * same number of elements that need to be processed is used for the UBO and the dispatch size.
+ * Use this instead of a raw call to #GPU_compute_dispatch.
+ */
+static void drw_subdiv_compute_dispatch(const DRWSubdivCache *cache,
+ GPUShader *shader,
+ const int src_offset,
+ const int dst_offset,
+ uint total_dispatch_size,
+ const bool has_sculpt_mask = false)
+{
+ const uint max_res_x = static_cast<uint>(GPU_max_work_group_count(0));
+
+ const uint dispatch_size = get_dispatch_size(total_dispatch_size);
+ uint dispatch_rx = dispatch_size;
+ uint dispatch_ry = 1u;
+ if (dispatch_rx > max_res_x) {
+ /* Since there are some limitations with regards to the maximum work group size (could be as
+ * low as 64k elements per call), we split the number elements into a "2d" number, with the
+ * final index being computed as `res_x + res_y * max_work_group_size`. Even with a maximum
+ * work group size of 64k, that still leaves us with roughly `64k * 64k = 4` billion elements
+ * total, which should be enough. If not, we could also use the 3rd dimension. */
+ /* TODO(fclem): We could dispatch fewer groups if we compute the prime factorization and
+ * get the smallest rect fitting the requirements. */
+ dispatch_rx = dispatch_ry = ceilf(sqrtf(dispatch_size));
+ /* Avoid a completely empty dispatch line caused by rounding. */
+ if ((dispatch_rx * (dispatch_ry - 1)) >= dispatch_size) {
+ dispatch_ry -= 1;
+ }
+ }
+
+ /* X and Y dimensions may have different limits so the above computation may not be right, but
+ * even with the standard 64k minimum on all dimensions we still have a lot of room. Therefore,
+ * we presume it all fits. */
+ BLI_assert(dispatch_ry < static_cast<uint>(GPU_max_work_group_count(1)));
+
+ draw_subdiv_ubo_update_and_bind(
+ cache, shader, src_offset, dst_offset, total_dispatch_size, has_sculpt_mask);
+
+ GPU_compute_dispatch(shader, dispatch_rx, dispatch_ry, 1);
+}
+
+void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ const bool do_limit_normals)
+{
+ Subdiv *subdiv = cache->subdiv;
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+
+ OpenSubdiv_Buffer src_buffer_interface;
+ GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface,
+ get_subdiv_vertex_format());
+ evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface);
+
+ OpenSubdiv_Buffer patch_arrays_buffer_interface;
+ GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface,
+ get_patch_array_format());
+ evaluator->fillPatchArraysBuffer(evaluator, &patch_arrays_buffer_interface);
+
+ OpenSubdiv_Buffer patch_index_buffer_interface;
+ GPUVertBuf *patch_index_buffer = create_buffer_and_interface(&patch_index_buffer_interface,
+ get_patch_index_format());
+ evaluator->wrapPatchIndexBuffer(evaluator, &patch_index_buffer_interface);
+
+ OpenSubdiv_Buffer patch_param_buffer_interface;
+ GPUVertBuf *patch_param_buffer = create_buffer_and_interface(&patch_param_buffer_interface,
+ get_patch_param_format());
+ evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface);
+
+ GPUShader *shader = get_patch_evaluation_shader(
+ do_limit_normals ? SHADER_PATCH_EVALUATION_LIMIT_NORMALS : SHADER_PATCH_EVALUATION);
+ GPU_shader_bind(shader);
+
+ GPU_vertbuf_bind_as_ssbo(src_buffer, 0);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, 1);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, 2);
+ GPU_vertbuf_bind_as_ssbo(cache->patch_coords, 3);
+ GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, 4);
+ GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, 5);
+ GPU_vertbuf_bind_as_ssbo(patch_index_buffer, 6);
+ GPU_vertbuf_bind_as_ssbo(patch_param_buffer, 7);
+ GPU_vertbuf_bind_as_ssbo(pos_nor, 8);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array.
+ * We also need it for subsequent compute shaders, so a barrier on the shader storage is also
+ * needed. */
+ GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+
+ GPU_vertbuf_discard(patch_index_buffer);
+ GPU_vertbuf_discard(patch_param_buffer);
+ GPU_vertbuf_discard(patch_arrays_buffer);
+ GPU_vertbuf_discard(src_buffer);
+}
+
+void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
+ GPUVertBuf *uvs,
+ const int face_varying_channel,
+ const int dst_offset)
+{
+ Subdiv *subdiv = cache->subdiv;
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+
+ OpenSubdiv_Buffer src_buffer_interface;
+ GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface, get_uvs_format());
+ evaluator->wrapFVarSrcBuffer(evaluator, face_varying_channel, &src_buffer_interface);
+
+ OpenSubdiv_Buffer patch_arrays_buffer_interface;
+ GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface,
+ get_patch_array_format());
+ evaluator->fillFVarPatchArraysBuffer(
+ evaluator, face_varying_channel, &patch_arrays_buffer_interface);
+
+ OpenSubdiv_Buffer patch_index_buffer_interface;
+ GPUVertBuf *patch_index_buffer = create_buffer_and_interface(&patch_index_buffer_interface,
+ get_patch_index_format());
+ evaluator->wrapFVarPatchIndexBuffer(
+ evaluator, face_varying_channel, &patch_index_buffer_interface);
+
+ OpenSubdiv_Buffer patch_param_buffer_interface;
+ GPUVertBuf *patch_param_buffer = create_buffer_and_interface(&patch_param_buffer_interface,
+ get_patch_param_format());
+ evaluator->wrapFVarPatchParamBuffer(
+ evaluator, face_varying_channel, &patch_param_buffer_interface);
+
+ GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION_FVAR);
+ GPU_shader_bind(shader);
+
+ GPU_vertbuf_bind_as_ssbo(src_buffer, 0);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, 1);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, 2);
+ GPU_vertbuf_bind_as_ssbo(cache->patch_coords, 3);
+ GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, 4);
+ GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, 5);
+ GPU_vertbuf_bind_as_ssbo(patch_index_buffer, 6);
+ GPU_vertbuf_bind_as_ssbo(patch_param_buffer, 7);
+ GPU_vertbuf_bind_as_ssbo(uvs, 8);
+
+ /* The buffer offset has the stride baked in (which is 2 as we have UVs) so remove the stride by
+ * dividing by 2 */
+ const int src_offset = src_buffer_interface.buffer_offset / 2;
+ drw_subdiv_compute_dispatch(cache, shader, src_offset, dst_offset, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array.
+ * Since it may also be used for computing UV stretches, we also need a barrier on the shader
+ * storage. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY | GPU_BARRIER_SHADER_STORAGE);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+
+ GPU_vertbuf_discard(patch_index_buffer);
+ GPU_vertbuf_discard(patch_param_buffer);
+ GPU_vertbuf_discard(patch_arrays_buffer);
+ GPU_vertbuf_discard(src_buffer);
+}
+
+void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
+ GPUVertBuf *src_data,
+ GPUVertBuf *dst_data,
+ int dimensions,
+ int dst_offset)
+{
+ GPUShader *shader = nullptr;
+
+ if (dimensions == 1) {
+ shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_1D,
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define DIMENSIONS 1\n");
+ }
+ else if (dimensions == 2) {
+ shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_2D,
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define DIMENSIONS 2\n");
+ }
+ else if (dimensions == 3) {
+ shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_3D,
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define DIMENSIONS 3\n");
+ }
+ else if (dimensions == 4) {
+ shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_4D,
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define DIMENSIONS 4\n"
+ "#define GPU_FETCH_U16_TO_FLOAT\n");
+ }
+ else {
+ /* Crash if dimensions are not supported. */
+ }
+
+ GPU_shader_bind(shader);
+
+ /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
+ GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0);
+ GPU_vertbuf_bind_as_ssbo(src_data, 1);
+ GPU_vertbuf_bind_as_ssbo(cache->face_ptex_offset_buffer, 2);
+ GPU_vertbuf_bind_as_ssbo(cache->patch_coords, 3);
+ GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, 4);
+ GPU_vertbuf_bind_as_ssbo(dst_data, 5);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, dst_offset, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_sculpt_data_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *mask_vbo,
+ GPUVertBuf *face_set_vbo,
+ GPUVertBuf *sculpt_data)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_SCULPT_DATA, nullptr);
+ GPU_shader_bind(shader);
+
+ if (mask_vbo) {
+ GPU_vertbuf_bind_as_ssbo(mask_vbo, 0);
+ }
+
+ GPU_vertbuf_bind_as_ssbo(face_set_vbo, 1);
+ GPU_vertbuf_bind_as_ssbo(sculpt_data, 2);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads, mask_vbo != nullptr);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_accumulate_normals(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *face_adjacency_offsets,
+ GPUVertBuf *face_adjacency_lists,
+ GPUVertBuf *vertex_normals)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_NORMALS_ACCUMULATE, nullptr);
+ GPU_shader_bind(shader);
+
+ int binding_point = 0;
+
+ GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(face_adjacency_offsets, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(face_adjacency_lists, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(vertex_normals, binding_point++);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_verts);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array.
+ * We also need it for subsequent compute shaders, so a barrier on the shader storage is also
+ * needed. */
+ GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_finalize_normals(const DRWSubdivCache *cache,
+ GPUVertBuf *vertex_normals,
+ GPUVertBuf *subdiv_loop_subdiv_vert_index,
+ GPUVertBuf *pos_nor)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_NORMALS_FINALIZE, nullptr);
+ GPU_shader_bind(shader);
+
+ int binding_point = 0;
+ GPU_vertbuf_bind_as_ssbo(vertex_normals, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(subdiv_loop_subdiv_vert_index, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array.
+ * We also need it for subsequent compute shaders, so a barrier on the shader storage is also
+ * needed. */
+ GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache,
+ GPUIndexBuf *subdiv_tris,
+ const int material_count)
+{
+ const bool do_single_material = material_count <= 1;
+
+ const char *defines = "#define SUBDIV_POLYGON_OFFSET\n";
+ if (do_single_material) {
+ defines =
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define SINGLE_MATERIAL\n";
+ }
+
+ GPUShader *shader = get_subdiv_shader(
+ do_single_material ? SHADER_BUFFER_TRIS : SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS, defines);
+ GPU_shader_bind(shader);
+
+ /* Outputs */
+ GPU_indexbuf_bind_as_ssbo(subdiv_tris, 1);
+
+ if (!do_single_material) {
+ GPU_vertbuf_bind_as_ssbo(cache->polygon_mat_offset, 2);
+ /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
+ GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0);
+ }
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates an index buffer, so we need to put a barrier on the element array. */
+ GPU_memory_barrier(GPU_BARRIER_ELEMENT_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
+ GPUVertBuf *fdots_pos,
+ GPUVertBuf *fdots_nor,
+ GPUIndexBuf *fdots_indices)
+{
+ Subdiv *subdiv = cache->subdiv;
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+
+ OpenSubdiv_Buffer src_buffer_interface;
+ GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface,
+ get_subdiv_vertex_format());
+ evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface);
+
+ OpenSubdiv_Buffer patch_arrays_buffer_interface;
+ GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface,
+ get_patch_array_format());
+ opensubdiv_gpu_buffer_init(&patch_arrays_buffer_interface, patch_arrays_buffer);
+ evaluator->fillPatchArraysBuffer(evaluator, &patch_arrays_buffer_interface);
+
+ OpenSubdiv_Buffer patch_index_buffer_interface;
+ GPUVertBuf *patch_index_buffer = create_buffer_and_interface(&patch_index_buffer_interface,
+ get_patch_index_format());
+ evaluator->wrapPatchIndexBuffer(evaluator, &patch_index_buffer_interface);
+
+ OpenSubdiv_Buffer patch_param_buffer_interface;
+ GPUVertBuf *patch_param_buffer = create_buffer_and_interface(&patch_param_buffer_interface,
+ get_patch_param_format());
+ evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface);
+
+ GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION_FACE_DOTS);
+ GPU_shader_bind(shader);
+
+ GPU_vertbuf_bind_as_ssbo(src_buffer, 0);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, 1);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, 2);
+ GPU_vertbuf_bind_as_ssbo(cache->fdots_patch_coords, 3);
+ GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, 4);
+ GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, 5);
+ GPU_vertbuf_bind_as_ssbo(patch_index_buffer, 6);
+ GPU_vertbuf_bind_as_ssbo(patch_param_buffer, 7);
+ GPU_vertbuf_bind_as_ssbo(fdots_pos, 8);
+ GPU_vertbuf_bind_as_ssbo(fdots_nor, 9);
+ GPU_indexbuf_bind_as_ssbo(fdots_indices, 10);
+ GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, 11);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_coarse_poly);
+
+ /* This generates two vertex buffers and an index buffer, so we need to put a barrier on the
+ * vertex attributes and element arrays. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY | GPU_BARRIER_ELEMENT_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+
+ GPU_vertbuf_discard(patch_index_buffer);
+ GPU_vertbuf_discard(patch_param_buffer);
+ GPU_vertbuf_discard(patch_arrays_buffer);
+ GPU_vertbuf_discard(src_buffer);
+}
+
+void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache, GPUIndexBuf *lines_indices)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LINES, nullptr);
+ GPU_shader_bind(shader);
+
+ GPU_vertbuf_bind_as_ssbo(cache->edges_orig_index, 0);
+ GPU_indexbuf_bind_as_ssbo(lines_indices, 1);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates an index buffer, so we need to put a barrier on the element array. */
+ GPU_memory_barrier(GPU_BARRIER_ELEMENT_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache *cache,
+ GPUIndexBuf *lines_indices,
+ uint num_loose_edges)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LINES_LOOSE, "#define LINES_LOOSE\n");
+ GPU_shader_bind(shader);
+
+ GPU_indexbuf_bind_as_ssbo(lines_indices, 1);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, num_loose_edges);
+
+ /* This generates an index buffer, so we need to put a barrier on the element array. */
+ GPU_memory_barrier(GPU_BARRIER_ELEMENT_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *edge_idx,
+ GPUVertBuf *edge_fac)
+{
+ /* No separate shader for the AMD driver case as we assume that the GPU will not change during
+ * the execution of the program. */
+ const char *defines = GPU_crappy_amd_driver() ? "#define GPU_AMD_DRIVER_BYTE_BUG\n" : nullptr;
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_EDGE_FAC, defines);
+ GPU_shader_bind(shader);
+
+ GPU_vertbuf_bind_as_ssbo(pos_nor, 0);
+ GPU_vertbuf_bind_as_ssbo(edge_idx, 1);
+ GPU_vertbuf_bind_as_ssbo(edge_fac, 2);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *lnor)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LNOR, "#define SUBDIV_POLYGON_OFFSET\n");
+ GPU_shader_bind(shader);
+
+ /* Inputs */
+ GPU_vertbuf_bind_as_ssbo(pos_nor, 1);
+ GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, 2);
+ /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
+ GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0);
+
+ /* Outputs */
+ GPU_vertbuf_bind_as_ssbo(lnor, 3);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_edituv_stretch_area_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *coarse_data,
+ GPUVertBuf *subdiv_data)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_UV_STRETCH_AREA,
+ "#define SUBDIV_POLYGON_OFFSET\n");
+ GPU_shader_bind(shader);
+
+ /* Inputs */
+ GPU_vertbuf_bind_as_ssbo(coarse_data, 1);
+ /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
+ GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0);
+
+ /* Outputs */
+ GPU_vertbuf_bind_as_ssbo(subdiv_data, 2);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *uvs,
+ int uvs_offset,
+ GPUVertBuf *stretch_angles)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_UV_STRETCH_ANGLE, nullptr);
+ GPU_shader_bind(shader);
+
+ /* Inputs */
+ GPU_vertbuf_bind_as_ssbo(pos_nor, 0);
+ GPU_vertbuf_bind_as_ssbo(uvs, 1);
+
+ /* Outputs */
+ GPU_vertbuf_bind_as_ssbo(stretch_angles, 2);
+
+ drw_subdiv_compute_dispatch(cache, shader, uvs_offset, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+/* -------------------------------------------------------------------- */
+
+void draw_subdiv_init_mesh_render_data(DRWSubdivCache *cache,
+ MeshRenderData *mr,
+ const ToolSettings *toolsettings)
+{
+ Mesh *mesh = cache->mesh;
+
+ /* Setup required data for loose geometry. */
+ mr->me = mesh;
+ mr->medge = mesh->medge;
+ mr->mvert = mesh->mvert;
+ mr->mpoly = mesh->mpoly;
+ mr->mloop = mesh->mloop;
+ mr->vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
+ mr->vert_len = mesh->totvert;
+ mr->edge_len = mesh->totedge;
+ mr->poly_len = mesh->totpoly;
+ mr->loop_len = mesh->totloop;
+ mr->extract_type = MR_EXTRACT_MESH;
+ mr->toolsettings = toolsettings;
+ mr->v_origindex = static_cast<int *>(CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX));
+ mr->e_origindex = static_cast<int *>(CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX));
+ mr->p_origindex = static_cast<int *>(CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX));
+
+ /* MeshRenderData is only used for generating edit mode data here. */
+ if (!cache->bm) {
+ return;
+ }
+
+ BMesh *bm = cache->bm;
+ BM_mesh_elem_table_ensure(bm, BM_EDGE | BM_FACE | BM_VERT);
+
+ mr->bm = bm;
+ mr->eed_act = BM_mesh_active_edge_get(bm);
+ mr->efa_act = BM_mesh_active_face_get(bm, false, true);
+ mr->eve_act = BM_mesh_active_vert_get(bm);
+ mr->edge_crease_ofs = CustomData_get_offset(&bm->edata, CD_CREASE);
+ mr->vert_crease_ofs = CustomData_get_offset(&bm->vdata, CD_CREASE);
+ mr->bweight_ofs = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
+#ifdef WITH_FREESTYLE
+ mr->freestyle_edge_ofs = CustomData_get_offset(&bm->edata, CD_FREESTYLE_EDGE);
+ mr->freestyle_face_ofs = CustomData_get_offset(&bm->pdata, CD_FREESTYLE_FACE);
+#endif
+}
+
+/**
+ * For material assignments we want indices for triangles that share a common material to be laid
+ * out contiguously in memory. To achieve this, we sort the indices based on which material the
+ * coarse polygon was assigned. The sort is performed by offsetting the loops indices so that they
+ * are directly assigned to the right sorted indices.
+ *
+ * \code{.unparsed}
+ * Here is a visual representation, considering four quads:
+ * +---------+---------+---------+---------+
+ * | 3 2 | 7 6 | 11 10 | 15 14 |
+ * | | | | |
+ * | 0 1 | 4 5 | 8 9 | 12 13 |
+ * +---------+---------+---------+---------+
+ *
+ * If the first and third quads have the same material, we should have:
+ * +---------+---------+---------+---------+
+ * | 3 2 | 11 10 | 7 6 | 15 14 |
+ * | | | | |
+ * | 0 1 | 8 9 | 4 5 | 12 13 |
+ * +---------+---------+---------+---------+
+ *
+ * So the offsets would be:
+ * +---------+---------+---------+---------+
+ * | 0 0 | 4 4 | -4 -4 | 0 0 |
+ * | | | | |
+ * | 0 0 | 4 4 | -4 -4 | 0 0 |
+ * +---------+---------+---------+---------+
+ * \endcode
+ *
+ * The offsets are computed not based on the loops indices, but on the number of subdivided
+ * polygons for each coarse polygon. We then only store a single offset for each coarse polygon,
+ * since all sub-faces are contiguous, they all share the same offset.
+ */
+static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache,
+ Mesh *mesh_eval,
+ uint mat_len)
+{
+ draw_subdiv_cache_free_material_data(cache);
+
+ const int number_of_quads = cache->num_subdiv_loops / 4;
+
+ if (mat_len == 1) {
+ cache->mat_start = static_cast<int *>(MEM_callocN(sizeof(int), "subdiv mat_end"));
+ cache->mat_end = static_cast<int *>(MEM_callocN(sizeof(int), "subdiv mat_end"));
+ cache->mat_start[0] = 0;
+ cache->mat_end[0] = number_of_quads;
+ return;
+ }
+
+ /* Count number of subdivided polygons for each material. */
+ int *mat_start = static_cast<int *>(MEM_callocN(sizeof(int) * mat_len, "subdiv mat_start"));
+ int *subdiv_polygon_offset = cache->subdiv_polygon_offset;
+
+ // TODO: parallel_reduce?
+ for (int i = 0; i < mesh_eval->totpoly; i++) {
+ const MPoly *mpoly = &mesh_eval->mpoly[i];
+ const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads :
+ subdiv_polygon_offset[i + 1];
+ const int quad_count = next_offset - subdiv_polygon_offset[i];
+ const int mat_index = mpoly->mat_nr;
+ mat_start[mat_index] += quad_count;
+ }
+
+ /* Accumulate offsets. */
+ int ofs = mat_start[0];
+ mat_start[0] = 0;
+ for (uint i = 1; i < mat_len; i++) {
+ int tmp = mat_start[i];
+ mat_start[i] = ofs;
+ ofs += tmp;
+ }
+
+ /* Compute per polygon offsets. */
+ int *mat_end = static_cast<int *>(MEM_dupallocN(mat_start));
+ int *per_polygon_mat_offset = static_cast<int *>(
+ MEM_mallocN(sizeof(int) * mesh_eval->totpoly, "per_polygon_mat_offset"));
+
+ for (int i = 0; i < mesh_eval->totpoly; i++) {
+ const MPoly *mpoly = &mesh_eval->mpoly[i];
+ const int mat_index = mpoly->mat_nr;
+ const int single_material_index = subdiv_polygon_offset[i];
+ const int material_offset = mat_end[mat_index];
+ const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads :
+ subdiv_polygon_offset[i + 1];
+ const int quad_count = next_offset - subdiv_polygon_offset[i];
+ mat_end[mat_index] += quad_count;
+
+ per_polygon_mat_offset[i] = material_offset - single_material_index;
+ }
+
+ cache->polygon_mat_offset = draw_subdiv_build_origindex_buffer(per_polygon_mat_offset,
+ mesh_eval->totpoly);
+ cache->mat_start = mat_start;
+ cache->mat_end = mat_end;
+
+ MEM_freeN(per_polygon_mat_offset);
+}
+
+static bool draw_subdiv_create_requested_buffers(const Scene *scene,
+ Object *ob,
+ Mesh *mesh,
+ struct MeshBatchCache *batch_cache,
+ MeshBufferCache *mbc,
+ const ToolSettings *toolsettings,
+ OpenSubdiv_EvaluatorCache *evaluator_cache)
+{
+ SubsurfModifierData *smd = BKE_object_get_last_subsurf_modifier(ob);
+ BLI_assert(smd);
+
+ const bool is_final_render = DRW_state_is_scene_render();
+
+ SubdivSettings settings;
+ BKE_subsurf_modifier_subdiv_settings_init(&settings, smd, is_final_render);
+
+ if (settings.level == 0) {
+ return false;
+ }
+
+ Mesh *mesh_eval = mesh;
+ BMesh *bm = nullptr;
+ if (mesh->edit_mesh) {
+ mesh_eval = BKE_object_get_editmesh_eval_final(ob);
+ bm = mesh->edit_mesh->bm;
+ }
+
+ BKE_subsurf_modifier_ensure_runtime(smd);
+
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &settings, mesh_eval, true);
+ if (!subdiv) {
+ return false;
+ }
+
+ if (!BKE_subdiv_eval_begin_from_mesh(
+ subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) {
+ return false;
+ }
+
+ DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache);
+ if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, scene, smd, is_final_render)) {
+ return false;
+ }
+
+ const bool optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges);
+
+ draw_cache->bm = bm;
+ draw_cache->mesh = mesh_eval;
+ draw_cache->subdiv = subdiv;
+ draw_cache->optimal_display = optimal_display;
+ draw_cache->num_subdiv_triangles = tris_count_from_number_of_loops(draw_cache->num_subdiv_loops);
+ /* We can only evaluate limit normals if the patches are adaptive. */
+ draw_cache->do_limit_normals = settings.is_adaptive;
+
+ if (DRW_ibo_requested(mbc->buff.ibo.tris)) {
+ draw_subdiv_cache_ensure_mat_offsets(draw_cache, mesh_eval, batch_cache->mat_len);
+ }
+
+ draw_subdiv_cache_update_extra_coarse_face_data(draw_cache, mesh_eval);
+
+ mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, toolsettings);
+
+ return true;
+}
+
+static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr;
+
+void DRW_create_subdivision(const Scene *scene,
+ Object *ob,
+ Mesh *mesh,
+ struct MeshBatchCache *batch_cache,
+ MeshBufferCache *mbc,
+ const ToolSettings *toolsettings)
+{
+ if (g_evaluator_cache == nullptr) {
+ g_evaluator_cache = openSubdiv_createEvaluatorCache(OPENSUBDIV_EVALUATOR_GLSL_COMPUTE);
+ }
+
+#undef TIME_SUBDIV
+
+#ifdef TIME_SUBDIV
+ const double begin_time = PIL_check_seconds_timer();
+#endif
+
+ if (!draw_subdiv_create_requested_buffers(
+ scene, ob, mesh, batch_cache, mbc, toolsettings, g_evaluator_cache)) {
+ return;
+ }
+
+#ifdef TIME_SUBDIV
+ const double end_time = PIL_check_seconds_timer();
+ fprintf(stderr, "Time to update subdivision: %f\n", end_time - begin_time);
+ fprintf(stderr, "Maximum FPS: %f\n", 1.0 / (end_time - begin_time));
+#endif
+}
+
+void DRW_subdiv_free()
+{
+ for (int i = 0; i < NUM_SHADERS; ++i) {
+ GPU_shader_free(g_subdiv_shaders[i]);
+ }
+
+ DRW_cache_free_old_subdiv();
+
+ if (g_evaluator_cache) {
+ openSubdiv_deleteEvaluatorCache(g_evaluator_cache);
+ g_evaluator_cache = nullptr;
+ }
+}
+
+static LinkNode *gpu_subdiv_free_queue = nullptr;
+static ThreadMutex gpu_subdiv_queue_mutex = BLI_MUTEX_INITIALIZER;
+
+void DRW_subdiv_cache_free(Subdiv *subdiv)
+{
+ BLI_mutex_lock(&gpu_subdiv_queue_mutex);
+ BLI_linklist_prepend(&gpu_subdiv_free_queue, subdiv);
+ BLI_mutex_unlock(&gpu_subdiv_queue_mutex);
+}
+
+void DRW_cache_free_old_subdiv()
+{
+ if (gpu_subdiv_free_queue == nullptr) {
+ return;
+ }
+
+ BLI_mutex_lock(&gpu_subdiv_queue_mutex);
+
+ while (gpu_subdiv_free_queue != nullptr) {
+ Subdiv *subdiv = static_cast<Subdiv *>(BLI_linklist_pop(&gpu_subdiv_free_queue));
+ /* Set the type to CPU so that we do actually free the cache. */
+ subdiv->evaluator->type = OPENSUBDIV_EVALUATOR_CPU;
+ BKE_subdiv_free(subdiv);
+ }
+
+ BLI_mutex_unlock(&gpu_subdiv_queue_mutex);
+}
diff --git a/source/blender/draw/intern/draw_color_management.cc b/source/blender/draw/intern/draw_color_management.cc
index 23fa18c83c5..6259236e3cf 100644
--- a/source/blender/draw/intern/draw_color_management.cc
+++ b/source/blender/draw/intern/draw_color_management.cc
@@ -30,6 +30,7 @@
#include "GPU_texture.h"
#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
#include "BKE_colortools.h"
@@ -60,14 +61,8 @@ static eDRWColorManagementType drw_color_management_type_for_v3d(const Scene &sc
{
const bool use_workbench = BKE_scene_uses_blender_workbench(&scene);
- const bool use_scene_lights = ((v3d.shading.type == OB_MATERIAL) &&
- (v3d.shading.flag & V3D_SHADING_SCENE_LIGHTS)) ||
- ((v3d.shading.type == OB_RENDER) &&
- (v3d.shading.flag & V3D_SHADING_SCENE_LIGHTS_RENDER));
- const bool use_scene_world = ((v3d.shading.type == OB_MATERIAL) &&
- (v3d.shading.flag & V3D_SHADING_SCENE_WORLD)) ||
- ((v3d.shading.type == OB_RENDER) &&
- (v3d.shading.flag & V3D_SHADING_SCENE_WORLD_RENDER));
+ const bool use_scene_lights = V3D_USES_SCENE_LIGHTS(&v3d);
+ const bool use_scene_world = V3D_USES_SCENE_WORLD(&v3d);
if ((use_workbench && v3d.shading.type == OB_RENDER) || use_scene_lights || use_scene_world) {
return eDRWColorManagementType::UseRenderSettings;
@@ -180,7 +175,6 @@ void DRW_viewport_colormanagement_set(GPUViewport *viewport)
blender::draw::color_management::viewport_color_management_set(*viewport);
}
-/* Draw texture to framebuffer without any color transforms */
void DRW_transform_none(GPUTexture *tex)
{
drw_state_set(DRW_STATE_WRITE_COLOR);
diff --git a/source/blender/draw/intern/draw_color_management.h b/source/blender/draw/intern/draw_color_management.h
index 9be105b88ec..7dff17b14c6 100644
--- a/source/blender/draw/intern/draw_color_management.h
+++ b/source/blender/draw/intern/draw_color_management.h
@@ -28,6 +28,9 @@ extern "C" {
struct GPUViewport;
+/**
+ * Draw texture to frame-buffer without any color transforms.
+ */
void DRW_transform_none(struct GPUTexture *tex);
void DRW_viewport_colormanagement_set(struct GPUViewport *viewport);
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
index 62d715460bb..65afc5ed3d8 100644
--- a/source/blender/draw/intern/draw_common.c
+++ b/source/blender/draw/intern/draw_common.c
@@ -41,7 +41,9 @@
#define UI_COLOR_RGBA_FROM_U8(r, g, b, a, v4) \
ARRAY_SET_ITEMS(v4, (float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)a / 255.0f)
-/* Colors & Constant */
+/**
+ * Colors & Constant.
+ */
struct DRW_Global G_draw = {{{0}}};
static bool weight_ramp_custom = false;
@@ -101,11 +103,6 @@ void DRW_globals_update(void)
gb->colorEditMeshMiddle,
dot_v3v3(gb->colorEditMeshMiddle, (float[3]){0.3333f, 0.3333f, 0.3333f})); /* Desaturate */
- interp_v4_v4v4(gb->colorDupliSelect, gb->colorBackground, gb->colorSelect, 0.5f);
- /* Was 50% in 2.7x since the background was lighter making it easier to tell the color from
- * black, with a darker background we need a more faded color. */
- interp_v4_v4v4(gb->colorDupli, gb->colorBackground, gb->colorWire, 0.3f);
-
#ifdef WITH_FREESTYLE
UI_GetThemeColor4fv(TH_FREESTYLE_EDGE_MARK, gb->colorEdgeFreestyle);
UI_GetThemeColor4fv(TH_FREESTYLE_FACE_MARK, gb->colorFaceFreestyle);
@@ -292,15 +289,15 @@ DRWView *DRW_view_create_with_zoffset(const DRWView *parent_view,
/* ******************************************** COLOR UTILS ************************************ */
/* TODO: FINISH. */
-/**
- * Get the wire color theme_id of an object based on its state
- * \a r_color is a way to get a pointer to the static color var associated
- */
int DRW_object_wire_theme_get(Object *ob, ViewLayer *view_layer, float **r_color)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
const bool is_edit = (draw_ctx->object_mode & OB_MODE_EDIT) && (ob->mode & OB_MODE_EDIT);
- const bool active = (view_layer->basact && view_layer->basact->object == ob);
+ const bool active = view_layer->basact &&
+ ((ob->base_flag & BASE_FROM_DUPLI) ?
+ (DRW_object_get_dupli_parent(ob) == view_layer->basact->object) :
+ (view_layer->basact->object == ob));
+
/* confusing logic here, there are 2 methods of setting the color
* 'colortab[colindex]' and 'theme_id', colindex overrides theme_id.
*
@@ -345,21 +342,7 @@ int DRW_object_wire_theme_get(Object *ob, ViewLayer *view_layer, float **r_color
if (r_color != NULL) {
if (UNLIKELY(ob->base_flag & BASE_FROM_SET)) {
- *r_color = G_draw.block.colorDupli;
- }
- else if (UNLIKELY(ob->base_flag & BASE_FROM_DUPLI)) {
- switch (theme_id) {
- case TH_ACTIVE:
- case TH_SELECT:
- *r_color = G_draw.block.colorDupliSelect;
- break;
- case TH_TRANSFORM:
- *r_color = G_draw.block.colorTransform;
- break;
- default:
- *r_color = G_draw.block.colorDupli;
- break;
- }
+ *r_color = G_draw.block.colorWire;
}
else {
switch (theme_id) {
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 0fe2afa2399..f4be85d5116 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -28,12 +28,12 @@ extern "C" {
struct DRWShadingGroup;
struct FluidModifierData;
+struct GPUMaterial;
struct ModifierData;
struct Object;
struct ParticleSystem;
struct RegionView3D;
struct ViewLayer;
-struct GPUMaterial;
#define UBO_FIRST_COLOR colorWire
#define UBO_LAST_COLOR colorUVShadow
@@ -47,8 +47,6 @@ typedef struct GlobalsUboStorage {
float colorWireEdit[4];
float colorActive[4];
float colorSelect[4];
- float colorDupliSelect[4];
- float colorDupli[4];
float colorLibrarySelect[4];
float colorLibrary[4];
float colorTransform[4];
@@ -167,6 +165,10 @@ struct DRWView *DRW_view_create_with_zoffset(const struct DRWView *parent_view,
const struct RegionView3D *rv3d,
float offset);
+/**
+ * Get the wire color theme_id of an object based on its state
+ * \a r_color is a way to get a pointer to the static color var associated
+ */
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);
@@ -175,13 +177,18 @@ bool DRW_object_axis_orthogonal_to_view(struct Object *ob, int axis);
/* draw_hair.c */
-/* This creates a shading group with display hairs.
- * The draw call is already added by this function, just add additional uniforms. */
+/**
+ * This creates a shading group with display hairs.
+ * The draw call is already added by this function, just add additional uniforms.
+ */
struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md,
struct DRWShadingGroup *shgrp,
struct GPUMaterial *gpu_material);
+/**
+ * \note Only valid after #DRW_hair_update().
+ */
struct GPUVertBuf *DRW_hair_pos_buffer_get(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md);
@@ -207,6 +214,7 @@ 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
* Add needed theme colors / values to DRW_globals_update() and update UBO
diff --git a/source/blender/draw/intern/draw_debug.c b/source/blender/draw/intern/draw_debug.c
index a4cf74d8a62..d5183f4e368 100644
--- a/source/blender/draw/intern/draw_debug.c
+++ b/source/blender/draw/intern/draw_debug.c
@@ -68,7 +68,6 @@ void DRW_debug_polygon_v3(const float (*v)[3], const int vert_len, const float c
}
}
-/* NOTE: g_modelmat is still applied on top. */
void DRW_debug_m4(const float m[4][4])
{
float v0[3] = {0.0f, 0.0f, 0.0f};
diff --git a/source/blender/draw/intern/draw_debug.h b/source/blender/draw/intern/draw_debug.h
index 2b4a19bfacd..3f3cfe91652 100644
--- a/source/blender/draw/intern/draw_debug.h
+++ b/source/blender/draw/intern/draw_debug.h
@@ -33,13 +33,16 @@ void DRW_debug_modelmat_reset(void);
void DRW_debug_modelmat(const float modelmat[4][4]);
void DRW_debug_line_v3v3(const float v1[3], const float v2[3], const float color[4]);
-void DRW_debug_polygon_v3(const float (*v)[3], const int vert_len, const float color[4]);
+void DRW_debug_polygon_v3(const float (*v)[3], int vert_len, const float color[4]);
+/**
+ * \note g_modelmat is still applied on top.
+ */
void DRW_debug_m4(const float m[4][4]);
-void DRW_debug_m4_as_bbox(const float m[4][4], const float color[4], const bool invert);
+void DRW_debug_m4_as_bbox(const float m[4][4], const float color[4], bool invert);
void DRW_debug_view(const struct DRWView *view, const float color[4]);
void DRW_debug_bbox(const struct BoundBox *bbox, const float color[4]);
-void DRW_debug_sphere(const float center[3], const float radius, const float color[4]);
+void DRW_debug_sphere(const float center[3], float radius, const float color[4]);
#ifdef __cplusplus
}
-#endif
+#endif \ No newline at end of file
diff --git a/source/blender/draw/intern/draw_fluid.c b/source/blender/draw/intern/draw_fluid.c
index 9cfdbf7c688..616307ca86b 100644
--- a/source/blender/draw/intern/draw_fluid.c
+++ b/source/blender/draw/intern/draw_fluid.c
@@ -589,9 +589,10 @@ void DRW_fluid_ensure_range_field(FluidModifierData *fmd)
#endif /* WITH_FLUID */
}
-/* TODO: Unify with the other #GPU_free_smoke. */
void DRW_smoke_free_velocity(FluidModifierData *fmd)
{
+ /* TODO: Unify with the other #GPU_free_smoke. */
+
if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
if (fmd->domain->tex_velocity_x) {
GPU_texture_free(fmd->domain->tex_velocity_x);
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index 5c7eb083fc9..e9010d7a81a 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -54,7 +54,7 @@
BLI_INLINE eParticleRefineShaderType drw_hair_shader_type_get(void)
{
#ifdef USE_COMPUTE_SHADERS
- if (GPU_compute_shader_support()) {
+ if (GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support()) {
return PART_REFINE_SHADER_COMPUTE;
}
#endif
@@ -130,7 +130,7 @@ static void drw_hair_particle_cache_update_compute(ParticleHairCache *cache, con
GPUShader *shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM);
DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass);
drw_hair_particle_cache_shgrp_attach_resources(shgrp, cache, subdiv);
- DRW_shgroup_vertex_buffer(shgrp, "hairPointOutputBuffer", cache->final[subdiv].proc_buf);
+ DRW_shgroup_vertex_buffer(shgrp, "posTime", cache->final[subdiv].proc_buf);
const int max_strands_per_call = GPU_max_work_group_count(0);
int strands_start = 0;
@@ -203,7 +203,6 @@ static ParticleHairCache *drw_hair_particle_cache_get(Object *object,
return cache;
}
-/* NOTE: Only valid after DRW_hair_update(). */
GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, ModifierData *md)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h
index 289a1690fc6..d5d9a9fb299 100644
--- a/source/blender/draw/intern/draw_hair_private.h
+++ b/source/blender/draw/intern/draw_hair_private.h
@@ -93,6 +93,9 @@ typedef struct ParticleHairCache {
void particle_batch_cache_clear_hair(struct ParticleHairCache *hair_cache);
+/**
+ * Ensure all textures and buffers needed for GPU accelerated drawing.
+ */
bool particles_ensure_procedural_data(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md,
@@ -101,6 +104,9 @@ bool particles_ensure_procedural_data(struct Object *object,
int subdiv,
int thickness_res);
+/**
+ * Ensure all textures and buffers needed for GPU accelerated drawing.
+ */
bool hair_ensure_procedural_data(struct Object *object,
struct ParticleHairCache **r_hair_cache,
struct GPUMaterial *gpu_material,
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
index 29112ee4788..7e1d1208698 100644
--- a/source/blender/draw/intern/draw_instance_data.c
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -112,14 +112,6 @@ static void instancing_batch_references_remove(GPUBatch *batch)
/** \name Instance Buffer Management
* \{ */
-/**
- * This manager allows to distribute existing batches for instancing
- * attributes. This reduce the number of batches creation.
- * Querying a batch is done with a vertex format. This format should
- * be static so that its pointer never changes (because we are using
- * this pointer as identifier [we don't want to check the full format
- * that would be too slow]).
- */
GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
GPUVertFormat *format,
int *vert_len)
@@ -143,8 +135,6 @@ GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
return handle->buf;
}
-/* NOTE: Does not return a valid drawable batch until DRW_instance_buffer_finish has run.
- * Initialization is delayed because instancer or geom could still not be initialized. */
GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUBatch *instancer,
@@ -185,7 +175,6 @@ GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
return batch;
}
-/* NOTE: Use only with buf allocated via DRW_temp_buffer_request. */
GPUBatch *DRW_temp_batch_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUPrimType prim_type)
@@ -301,9 +290,6 @@ static void DRW_instance_data_free(DRWInstanceData *idata)
BLI_mempool_destroy(idata->mempool);
}
-/**
- * Return a pointer to the next instance data space.
- */
void *DRW_instance_data_next(DRWInstanceData *idata)
{
return BLI_mempool_alloc(idata->mempool);
@@ -421,6 +407,7 @@ void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist)
}
/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Sparse Uniform Buffer
* \{ */
@@ -453,7 +440,6 @@ static void drw_sparse_uniform_buffer_init(DRWSparseUniformBuf *buffer,
buffer->chunk_bytes = item_size * chunk_size;
}
-/** Allocate a chunked UBO with the specified item and chunk size. */
DRWSparseUniformBuf *DRW_sparse_uniform_buffer_new(unsigned int item_size, unsigned int chunk_size)
{
DRWSparseUniformBuf *buf = MEM_mallocN(sizeof(DRWSparseUniformBuf), __func__);
@@ -461,7 +447,6 @@ DRWSparseUniformBuf *DRW_sparse_uniform_buffer_new(unsigned int item_size, unsig
return buf;
}
-/** Flush data from ordinary memory to UBOs. */
void DRW_sparse_uniform_buffer_flush(DRWSparseUniformBuf *buffer)
{
for (int i = 0; i < buffer->num_chunks; i++) {
@@ -474,7 +459,6 @@ void DRW_sparse_uniform_buffer_flush(DRWSparseUniformBuf *buffer)
}
}
-/** Clean all buffers and free unused ones. */
void DRW_sparse_uniform_buffer_clear(DRWSparseUniformBuf *buffer, bool free_all)
{
int max_used_chunk = 0;
@@ -517,14 +501,12 @@ void DRW_sparse_uniform_buffer_clear(DRWSparseUniformBuf *buffer, bool free_all)
BLI_bitmap_set_all(buffer->chunk_used, false, buffer->num_chunks);
}
-/** Frees the buffer. */
void DRW_sparse_uniform_buffer_free(DRWSparseUniformBuf *buffer)
{
DRW_sparse_uniform_buffer_clear(buffer, true);
MEM_freeN(buffer);
}
-/** Checks if the buffer contains any allocated chunks. */
bool DRW_sparse_uniform_buffer_is_empty(DRWSparseUniformBuf *buffer)
{
return buffer->num_chunks == 0;
@@ -538,7 +520,6 @@ static GPUUniformBuf *drw_sparse_uniform_buffer_get_ubo(DRWSparseUniformBuf *buf
return NULL;
}
-/** Bind the UBO for the given chunk, if present. A NULL buffer pointer is handled as empty. */
void DRW_sparse_uniform_buffer_bind(DRWSparseUniformBuf *buffer, int chunk, int location)
{
GPUUniformBuf *ubo = drw_sparse_uniform_buffer_get_ubo(buffer, chunk);
@@ -547,7 +528,6 @@ void DRW_sparse_uniform_buffer_bind(DRWSparseUniformBuf *buffer, int chunk, int
}
}
-/** Unbind the UBO for the given chunk, if present. A NULL buffer pointer is handled as empty. */
void DRW_sparse_uniform_buffer_unbind(DRWSparseUniformBuf *buffer, int chunk)
{
GPUUniformBuf *ubo = drw_sparse_uniform_buffer_get_ubo(buffer, chunk);
@@ -556,7 +536,6 @@ void DRW_sparse_uniform_buffer_unbind(DRWSparseUniformBuf *buffer, int chunk)
}
}
-/** Returns a pointer to the given item of the given chunk, allocating memory if necessary. */
void *DRW_sparse_uniform_buffer_ensure_item(DRWSparseUniformBuf *buffer, int chunk, int item)
{
if (chunk >= buffer->num_chunks) {
diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h
index c959a9e19d6..fb88b3dc6ec 100644
--- a/source/blender/draw/intern/draw_instance_data.h
+++ b/source/blender/draw/intern/draw_instance_data.h
@@ -38,21 +38,41 @@ typedef struct DRWInstanceData DRWInstanceData;
typedef struct DRWInstanceDataList DRWInstanceDataList;
typedef struct DRWSparseUniformBuf DRWSparseUniformBuf;
+/**
+ * Return a pointer to the next instance data space.
+ */
void *DRW_instance_data_next(DRWInstanceData *idata);
DRWInstanceData *DRW_instance_data_request(DRWInstanceDataList *idatalist, uint attr_size);
+/**
+ * This manager allows to distribute existing batches for instancing
+ * attributes. This reduce the number of batches creation.
+ * Querying a batch is done with a vertex format. This format should
+ * be static so that its pointer never changes (because we are using
+ * this pointer as identifier [we don't want to check the full format
+ * that would be too slow]).
+ */
GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
GPUVertFormat *format,
int *vert_len);
+/**
+ * \note Does not return a valid drawable batch until DRW_instance_buffer_finish has run.
+ * Initialization is delayed because instancer or geom could still not be initialized.
+ */
GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUBatch *instancer,
GPUBatch *geom);
+/**
+ * \note Use only with buf allocated via DRW_temp_buffer_request.
+ */
GPUBatch *DRW_temp_batch_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUPrimType type);
-/* Upload all instance data to the GPU as soon as possible. */
+/**
+ * Upload all instance data to the GPU as soon as possible.
+ */
void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist);
void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist);
@@ -60,17 +80,43 @@ void DRW_instance_data_list_free_unused(DRWInstanceDataList *idatalist);
void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist);
/* Sparse chunked UBO manager. */
+
+/**
+ * Allocate a chunked UBO with the specified item and chunk size.
+ */
DRWSparseUniformBuf *DRW_sparse_uniform_buffer_new(unsigned int item_size,
unsigned int chunk_size);
+/**
+ * Flush data from ordinary memory to UBOs.
+ */
void DRW_sparse_uniform_buffer_flush(DRWSparseUniformBuf *buffer);
+/**
+ * Clean all buffers and free unused ones.
+ */
void DRW_sparse_uniform_buffer_clear(DRWSparseUniformBuf *buffer, bool free_all);
+/**
+ * Frees the buffer.
+ */
void DRW_sparse_uniform_buffer_free(DRWSparseUniformBuf *buffer);
+/**
+ * Checks if the buffer contains any allocated chunks.
+ */
bool DRW_sparse_uniform_buffer_is_empty(DRWSparseUniformBuf *buffer);
+/**
+ * Bind the UBO for the given chunk, if present. A NULL buffer pointer is handled as empty.
+ */
void DRW_sparse_uniform_buffer_bind(DRWSparseUniformBuf *buffer, int chunk, int location);
+/**
+ * Unbind the UBO for the given chunk, if present. A NULL buffer pointer is handled as empty.
+ */
void DRW_sparse_uniform_buffer_unbind(DRWSparseUniformBuf *buffer, int chunk);
+/**
+ * Returns a pointer to the given item of the given chunk, allocating memory if necessary.
+ */
void *DRW_sparse_uniform_buffer_ensure_item(DRWSparseUniformBuf *buffer, int chunk, int item);
/* Uniform attribute UBO management. */
+
struct GHash *DRW_uniform_attrs_pool_new(void);
void DRW_uniform_attrs_pool_flush_all(struct GHash *table);
void DRW_uniform_attrs_pool_clear_all(struct GHash *table);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 5ae0351cdd3..45e4c2a575e 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -51,6 +51,8 @@
#include "BKE_pbvh.h"
#include "BKE_pointcache.h"
#include "BKE_pointcloud.h"
+#include "BKE_screen.h"
+#include "BKE_subdiv_modifier.h"
#include "BKE_volume.h"
#include "DNA_camera_types.h"
@@ -68,6 +70,7 @@
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
+#include "GPU_shader_shared.h"
#include "GPU_state.h"
#include "GPU_uniform_buffer.h"
#include "GPU_viewport.h"
@@ -84,10 +87,12 @@
#include "wm_window.h"
#include "draw_color_management.h"
+#include "draw_manager.h"
#include "draw_manager_profiling.h"
#include "draw_manager_testing.h"
#include "draw_manager_text.h"
#include "draw_shader.h"
+#include "draw_subdivision.h"
#include "draw_texture_pool.h"
/* only for callbacks */
@@ -112,8 +117,10 @@
/** Render State: No persistent data between draw calls. */
DRWManager DST = {NULL};
-static ListBase DRW_engines = {NULL, NULL};
-static int g_registered_engine_len = 0;
+static struct {
+ ListBase /*DRWRegisteredDrawEngine*/ engines;
+ int len;
+} g_registered_engines = {{NULL}};
static void drw_state_prepare_clean_for_draw(DRWManager *dst)
{
@@ -169,7 +176,8 @@ static void drw_task_graph_deinit(void)
{
BLI_task_graph_work_and_wait(DST.task_graph);
- BLI_gset_free(DST.delayed_extraction, (void (*)(void *key))drw_batch_cache_generate_requested);
+ BLI_gset_free(DST.delayed_extraction,
+ (void (*)(void *key))drw_batch_cache_generate_requested_evaluated_mesh);
DST.delayed_extraction = NULL;
BLI_task_graph_work_and_wait(DST.task_graph);
@@ -199,31 +207,12 @@ bool DRW_object_is_renderable(const Object *ob)
return true;
}
-/* Does `ob` needs to be rendered in edit mode.
- *
- * When using duplicate linked meshes, objects that are not in edit-mode will be drawn as
- * it is in edit mode, when another object with the same mesh is in edit mode.
- * This will not be the case when one of the objects are influenced by modifiers. */
bool DRW_object_is_in_edit_mode(const Object *ob)
{
if (BKE_object_is_in_editmode(ob)) {
if (ob->type == OB_MESH) {
if ((ob->mode & OB_MODE_EDIT) == 0) {
- Mesh *me = (Mesh *)ob->data;
- BMEditMesh *embm = me->edit_mesh;
- /* Sanity check when rendering in multiple windows. */
- if (embm && embm->mesh_eval_final == NULL) {
- return false;
- }
- /* Do not draw ob with edit overlay when edit data is present and is modified. */
- if (embm && embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final)) {
- return false;
- }
- /* Check if the object that we are drawing is modified. */
- if (!DEG_is_original_id(&me->id)) {
- return false;
- }
- return true;
+ return false;
}
}
return true;
@@ -231,10 +220,6 @@ bool DRW_object_is_in_edit_mode(const Object *ob)
return false;
}
-/**
- * Return whether this object is visible depending if
- * we are rendering or drawing in the viewport.
- */
int DRW_object_visibility_in_active_context(const Object *ob)
{
const eEvaluationMode mode = DRW_state_is_scene_render() ? DAG_EVAL_RENDER : DAG_EVAL_VIEWPORT;
@@ -317,7 +302,6 @@ struct DupliObject *DRW_object_get_dupli(const Object *UNUSED(ob))
/** \name Viewport (DRW_viewport)
* \{ */
-/* WARNING: only use for custom pipeline. 99% of the time, you don't want to use this. */
void DRW_render_viewport_size_set(const int size[2])
{
DST.size[0] = size[0];
@@ -439,7 +423,7 @@ DRWData *DRW_viewport_data_create(void)
}
for (int i = 0; i < 2; i++) {
- drw_data->view_data[i] = DRW_view_data_create(&DRW_engines);
+ drw_data->view_data[i] = DRW_view_data_create(&g_registered_engines.engines);
}
return drw_data;
}
@@ -561,8 +545,9 @@ static void drw_manager_init(DRWManager *dst, GPUViewport *viewport, const int s
drw_viewport_data_reset(dst->vmempool);
+ bool do_validation = true;
if (size == NULL && viewport == NULL) {
- /* Avoid division by 0. Engines will either overide this or not use it. */
+ /* Avoid division by 0. Engines will either override this or not use it. */
dst->size[0] = 1.0f;
dst->size[1] = 1.0f;
}
@@ -576,11 +561,15 @@ static void drw_manager_init(DRWManager *dst, GPUViewport *viewport, const int s
BLI_assert(size);
dst->size[0] = size[0];
dst->size[1] = size[1];
+ /* Fix case when used in DRW_cache_restart(). */
+ do_validation = false;
}
dst->inv_size[0] = 1.0f / dst->size[0];
dst->inv_size[1] = 1.0f / dst->size[1];
- DRW_view_data_texture_list_size_validate(dst->view_data_active, (int[2]){UNPACK2(dst->size)});
+ if (do_validation) {
+ DRW_view_data_texture_list_size_validate(dst->view_data_active, (int[2]){UNPACK2(dst->size)});
+ }
if (viewport) {
DRW_view_data_default_lists_from_viewport(dst->view_data_active, viewport);
@@ -726,7 +715,7 @@ static void drw_duplidata_load(Object *ob)
void **value;
if (!BLI_ghash_ensure_p(DST.dupli_ghash, key, &value)) {
- *value = MEM_callocN(sizeof(void *) * g_registered_engine_len, __func__);
+ *value = MEM_callocN(sizeof(void *) * g_registered_engines.len, __func__);
/* TODO: Meh a bit out of place but this is nice as it is
* only done once per instance type. */
@@ -741,7 +730,7 @@ static void drw_duplidata_load(Object *ob)
static void duplidata_value_free(void *val)
{
void **dupli_datas = val;
- for (int i = 0; i < g_registered_engine_len; i++) {
+ for (int i = 0; i < g_registered_engines.len; i++) {
MEM_SAFE_FREE(dupli_datas[i]);
}
MEM_freeN(val);
@@ -755,8 +744,11 @@ static void duplidata_key_free(void *key)
}
else {
Object temp_object = *dupli_key->ob;
+ /* Do not modify the original bound-box. */
+ temp_object.runtime.bb = NULL;
BKE_object_replace_data_on_shallow_copy(&temp_object, dupli_key->ob_data);
drw_batch_cache_generate_requested(&temp_object);
+ MEM_SAFE_FREE(temp_object.runtime.bb);
}
MEM_freeN(key);
}
@@ -769,14 +761,13 @@ static void drw_duplidata_free(void)
}
}
-/* Return NULL if not a dupli or a pointer of pointer to the engine data */
void **DRW_duplidata_get(void *vedata)
{
if (DST.dupli_source == NULL) {
return NULL;
}
ViewportEngineData *ved = (ViewportEngineData *)vedata;
- DrawEngineType *engine_type = (DrawEngineType *)ved->engine_type;
+ DRWRegisteredDrawEngine *engine_type = (DRWRegisteredDrawEngine *)ved->engine_type;
return &DST.dupli_datas[engine_type->index];
}
@@ -865,9 +856,6 @@ static bool id_can_have_drawdata(const ID *id)
return id_type_can_have_drawdata(GS(id->name));
}
-/* Get DrawData from the given ID-block. In order for this to work, we assume that
- * the DrawData pointer is stored in the struct in the same fashion as in IdDdtTemplate.
- */
DrawDataList *DRW_drawdatalist_from_id(ID *id)
{
/* only some ID-blocks have this info for now, so we cast the
@@ -1139,7 +1127,6 @@ static void drw_engines_draw_text(void)
}
}
-/* Draw render engine info. */
void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height)
{
DRW_ENABLED_ENGINE_ITER (DST.view_data_active, engine, data) {
@@ -1332,7 +1319,7 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
.object_mode = OB_MODE_OBJECT,
};
- /* Custom lightweight init to avoid reseting the mempools. */
+ /* Custom lightweight initialize to avoid resetting the memory-pools. */
DST.viewport = viewport;
DST.vmempool = drw_viewport_data_ensure(DST.viewport);
@@ -1358,6 +1345,61 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
BLI_ticket_mutex_unlock(DST.gl_context_mutex);
}
+/* update a viewport which belongs to a GPUOffscreen */
+static void drw_notify_view_update_offscreen(struct Depsgraph *depsgraph,
+ RenderEngineType *engine_type,
+ ARegion *region,
+ View3D *v3d,
+ GPUViewport *viewport)
+{
+
+ if (viewport && GPU_viewport_do_update(viewport)) {
+
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ RegionView3D *rv3d = region->regiondata;
+
+ const bool gpencil_engine_needed = drw_gpencil_engine_needed(depsgraph, v3d);
+
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
+
+ DST.draw_ctx = (DRWContextState){
+ .region = region,
+ .rv3d = rv3d,
+ .v3d = v3d,
+ .scene = scene,
+ .view_layer = view_layer,
+ .obact = OBACT(view_layer),
+ .engine_type = engine_type,
+ .depsgraph = depsgraph,
+ };
+
+ /* Custom lightweight initialize to avoid resetting the memory-pools. */
+ DST.viewport = viewport;
+ DST.vmempool = drw_viewport_data_ensure(DST.viewport);
+
+ /* Separate update for each stereo view. */
+ int view_count = GPU_viewport_is_stereo_get(viewport) ? 2 : 1;
+ for (int view = 0; view < view_count; view++) {
+ DST.view_data_active = DST.vmempool->view_data[view];
+
+ drw_engines_enable(view_layer, engine_type, gpencil_engine_needed);
+ drw_engines_data_validate();
+
+ DRW_ENABLED_ENGINE_ITER (DST.view_data_active, draw_engine, data) {
+ if (draw_engine->view_update) {
+ draw_engine->view_update(data);
+ }
+ }
+
+ drw_engines_disable();
+ }
+
+ drw_manager_exit(&DST);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1415,6 +1457,27 @@ void DRW_draw_callbacks_post_scene(void)
ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_POST_VIEW);
+#ifdef WITH_XR_OPENXR
+ /* XR callbacks (controllers, custom draw functions) for session mirror. */
+ if ((v3d->flag & V3D_XR_SESSION_MIRROR) != 0) {
+ if ((v3d->flag2 & V3D_XR_SHOW_CONTROLLERS) != 0) {
+ ARegionType *art = WM_xr_surface_controller_region_type_get();
+ if (art) {
+ ED_region_surface_draw_cb_draw(art, REGION_DRAW_POST_VIEW);
+ }
+ }
+ if ((v3d->flag2 & V3D_XR_SHOW_CUSTOM_OVERLAYS) != 0) {
+ SpaceType *st = BKE_spacetype_from_id(SPACE_VIEW3D);
+ if (st) {
+ ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_XR);
+ if (art) {
+ ED_region_surface_draw_cb_draw(art, REGION_DRAW_POST_VIEW);
+ }
+ }
+ }
+ }
+#endif
+
/* Callback can be nasty and do whatever they want with the state.
* Don't trust them! */
DRW_state_reset();
@@ -1461,6 +1524,46 @@ void DRW_draw_callbacks_post_scene(void)
ED_annotation_draw_view3d(DEG_get_input_scene(depsgraph), depsgraph, v3d, region, true);
GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
}
+
+#ifdef WITH_XR_OPENXR
+ if ((v3d->flag & V3D_XR_SESSION_SURFACE) != 0) {
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ DRW_state_reset();
+
+ GPU_framebuffer_bind(dfbl->overlay_fb);
+
+ GPU_matrix_projection_set(rv3d->winmat);
+ GPU_matrix_set(rv3d->viewmat);
+
+ /* XR callbacks (controllers, custom draw functions) for session surface. */
+ if (((v3d->flag2 & V3D_XR_SHOW_CONTROLLERS) != 0) ||
+ ((v3d->flag2 & V3D_XR_SHOW_CUSTOM_OVERLAYS) != 0)) {
+ GPU_depth_test(GPU_DEPTH_NONE);
+ GPU_apply_state();
+
+ if ((v3d->flag2 & V3D_XR_SHOW_CONTROLLERS) != 0) {
+ ARegionType *art = WM_xr_surface_controller_region_type_get();
+ if (art) {
+ ED_region_surface_draw_cb_draw(art, REGION_DRAW_POST_VIEW);
+ }
+ }
+ if ((v3d->flag2 & V3D_XR_SHOW_CUSTOM_OVERLAYS) != 0) {
+ SpaceType *st = BKE_spacetype_from_id(SPACE_VIEW3D);
+ if (st) {
+ ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_XR);
+ if (art) {
+ ED_region_surface_draw_cb_draw(art, REGION_DRAW_POST_VIEW);
+ }
+ }
+ }
+
+ DRW_state_reset();
+ }
+
+ GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
+ }
+#endif
}
}
@@ -1479,9 +1582,6 @@ struct DRWTextStore *DRW_text_cache_ensure(void)
/** \name Main Draw Loops (DRW_draw)
* \{ */
-/* Everything starts here.
- * This function takes care of calling all cache and rendering functions
- * for each relevant engine / mode engine. */
void DRW_draw_view(const bContext *C)
{
View3D *v3d = CTX_wm_view3d(C);
@@ -1509,10 +1609,6 @@ void DRW_draw_view(const bContext *C)
}
}
-/**
- * Used for both regular and off-screen drawing.
- * Need to reset DST before calling this function
- */
void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
RenderEngineType *engine_type,
ARegion *region,
@@ -1659,9 +1755,6 @@ void DRW_draw_render_loop(struct Depsgraph *depsgraph,
DRW_draw_render_loop_ex(depsgraph, engine_type, region, v3d, viewport, NULL);
}
-/**
- * \param viewport: can be NULL, in this case we create one.
- */
void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
RenderEngineType *engine_type,
ARegion *region,
@@ -1672,11 +1765,14 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
GPUOffScreen *ofs,
GPUViewport *viewport)
{
- /* Create temporary viewport if needed. */
+ /* Create temporary viewport if needed or update the existing viewport. */
GPUViewport *render_viewport = viewport;
if (viewport == NULL) {
render_viewport = GPU_viewport_create();
}
+ else {
+ drw_notify_view_update_offscreen(depsgraph, engine_type, region, v3d, render_viewport);
+ }
GPU_viewport_bind_from_offscreen(render_viewport, ofs);
@@ -1690,12 +1786,12 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
DRW_draw_render_loop_ex(depsgraph, engine_type, region, v3d, render_viewport, NULL);
if (draw_background) {
- /* HACK(fclem): In this case we need to make sure the final alpha is 1.
+ /* HACK(@fclem): In this case we need to make sure the final alpha is 1.
* We use the blend mode to ensure that. A better way to fix that would
* be to do that in the color-management shader. */
GPU_offscreen_bind(ofs, false);
GPU_clear_color(0.0f, 0.0f, 0.0f, 1.0f);
- /* Premult Alpha over black background. */
+ /* Pre-multiply alpha over black background. */
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
}
@@ -1720,7 +1816,6 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
}
}
-/* Helper to check if exit object type to render. */
bool DRW_render_check_grease_pencil(Depsgraph *depsgraph)
{
if (!drw_gpencil_engine_needed(depsgraph, NULL)) {
@@ -1949,9 +2044,6 @@ void DRW_render_object_iter(
drw_task_graph_deinit();
}
-/* Assume a valid gl context is bound (and that the gl_context_mutex has been acquired).
- * This function only setup DST and execute the given function.
- * Warning: similar to DRW_render_to_image you cannot use default lists (dfbl & dtxl). */
void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
struct Depsgraph *depsgraph,
void (*callback)(void *vedata, void *user_data),
@@ -1997,8 +2089,6 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
drw_manager_exit(&DST);
}
-/* Used when the render engine want to redo another cache populate inside the same render frame.
- */
void DRW_cache_restart(void)
{
drw_manager_init(&DST, DST.viewport, (int[2]){UNPACK2(DST.size)});
@@ -2189,7 +2279,6 @@ static void draw_select_framebuffer_depth_only_setup(const int size[2])
}
}
-/* Must run after all instance datas have been added. */
void DRW_render_instance_buffer_finish(void)
{
BLI_assert_msg(!DST.buffer_finish_called, "DRW_render_instance_buffer_finish called twice!");
@@ -2198,7 +2287,6 @@ void DRW_render_instance_buffer_finish(void)
drw_resource_buffer_finish(DST.vmempool);
}
-/* WARNING: Changing frame might free the ViewLayerEngineData */
void DRW_render_set_time(RenderEngine *engine, Depsgraph *depsgraph, int frame, float subframe)
{
RE_engine_frame_set(engine, frame, subframe);
@@ -2206,9 +2294,6 @@ void DRW_render_set_time(RenderEngine *engine, Depsgraph *depsgraph, int frame,
DST.draw_ctx.view_layer = DEG_get_evaluated_view_layer(depsgraph);
}
-/**
- * object mode select-loop, see: ED_view3d_draw_select_loop (legacy drawing).
- */
void DRW_draw_select_loop(struct Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
@@ -2437,16 +2522,17 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
GPUViewport *viewport,
- const bool use_opengl_context)
+ const bool use_gpencil,
+ const bool use_basic,
+ const bool use_overlay)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
RegionView3D *rv3d = region->regiondata;
- if (use_opengl_context) {
- DRW_opengl_context_enable();
- }
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
DST.options.is_depth = true;
@@ -2462,6 +2548,18 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
.depsgraph = depsgraph,
};
drw_context_state_init();
+ drw_manager_init(&DST, viewport, NULL);
+
+ if (use_gpencil) {
+ use_drw_engine(&draw_engine_gpencil_type);
+ }
+ if (use_basic) {
+ drw_engines_enable_basic();
+ }
+ if (use_overlay) {
+ drw_engines_enable_overlays();
+ }
+
drw_task_graph_init();
/* Setup frame-buffer. */
@@ -2529,62 +2627,23 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
drw_engines_disable();
drw_manager_exit(&DST);
-
- /* Changing context. */
- if (use_opengl_context) {
- DRW_opengl_context_disable();
- }
}
-/**
- * object mode select-loop, see: ED_view3d_draw_depth_loop (legacy drawing).
- */
void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
GPUViewport *viewport)
{
- /* Reset before using it. */
- drw_state_prepare_clean_for_draw(&DST);
-
- /* Required by `drw_manager_init()` */
- DST.draw_ctx.region = region;
- DST.draw_ctx.rv3d = region->regiondata;
- drw_manager_init(&DST, viewport, NULL);
-
- /* Get list of enabled engines */
- {
- /* Required by `DRW_state_draw_support()` */
- DST.draw_ctx.v3d = v3d;
-
- drw_engines_enable_basic();
- if (DRW_state_draw_support()) {
- drw_engines_enable_overlays();
- }
- }
-
- drw_draw_depth_loop_impl(depsgraph, region, v3d, viewport, false);
+ drw_draw_depth_loop_impl(
+ depsgraph, region, v3d, viewport, false, true, DRW_state_draw_support());
}
-/**
- * Converted from ED_view3d_draw_depth_gpencil (legacy drawing).
- */
void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
GPUViewport *viewport)
{
- /* Reset before using it. */
- drw_state_prepare_clean_for_draw(&DST);
-
- /* Required by `drw_manager_init()` */
- DST.draw_ctx.region = region;
- DST.draw_ctx.rv3d = region->regiondata;
- drw_manager_init(&DST, viewport, NULL);
-
- use_drw_engine(&draw_engine_gpencil_type);
-
- drw_draw_depth_loop_impl(depsgraph, region, v3d, viewport, false);
+ drw_draw_depth_loop_impl(depsgraph, region, v3d, viewport, true, false, false);
}
void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, const rcti *rect)
@@ -2661,9 +2720,6 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons
drw_manager_exit(&DST);
}
-/**
- * Clears the Depth Buffer and draws only the specified object.
- */
void DRW_draw_depth_object(
Scene *scene, ARegion *region, View3D *v3d, GPUViewport *viewport, Object *object)
{
@@ -2687,11 +2743,15 @@ void DRW_draw_depth_object(
GPU_framebuffer_clear_depth(depth_fb, 1.0f);
GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
- const float(*world_clip_planes)[4] = NULL;
- if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
+ struct GPUClipPlanes planes;
+ const bool use_clipping_planes = RV3D_CLIPPING_ENABLED(v3d, rv3d);
+ if (use_clipping_planes) {
GPU_clip_distances(6);
ED_view3d_clipping_local(rv3d, object->obmat);
- world_clip_planes = rv3d->clip_local;
+ for (int i = 0; i < 6; i++) {
+ copy_v4_v4(planes.world[i], rv3d->clip_local[i]);
+ }
+ copy_m4_m4(planes.ModelMatrix, object->obmat);
}
drw_batch_cache_validate(object);
@@ -2713,14 +2773,19 @@ void DRW_draw_depth_object(
BLI_task_graph_work_and_wait(task_graph);
BLI_task_graph_free(task_graph);
- const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED :
- GPU_SHADER_CFG_DEFAULT;
+ const eGPUShaderConfig sh_cfg = use_clipping_planes ? GPU_SHADER_CFG_CLIPPED :
+ GPU_SHADER_CFG_DEFAULT;
GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_DEPTH_ONLY, sh_cfg);
- if (world_clip_planes != NULL) {
- GPU_batch_uniform_4fv_array(batch, "WorldClipPlanes", 6, world_clip_planes);
+
+ GPUUniformBuf *ubo = NULL;
+ if (use_clipping_planes) {
+ ubo = GPU_uniformbuf_create_ex(sizeof(struct GPUClipPlanes), &planes, __func__);
+ GPU_batch_uniformbuf_bind(batch, "clipPlanes", ubo);
}
GPU_batch_draw(batch);
+ GPU_uniformbuf_free(ubo);
+
} break;
case OB_CURVE:
case OB_SURF:
@@ -2736,7 +2801,6 @@ void DRW_draw_depth_object(
GPU_framebuffer_restore();
GPU_framebuffer_free(depth_fb);
- DRW_opengl_context_disable();
}
/** \} */
@@ -2745,19 +2809,12 @@ void DRW_draw_depth_object(
/** \name Draw Manager State (DRW_state)
* \{ */
-/**
- * When false, drawing doesn't output to a pixel buffer
- * eg: Occlusion queries, or when we have setup a context to draw in already.
- */
bool DRW_state_is_fbo(void)
{
return ((DST.default_framebuffer != NULL) || DST.options.is_image_render) &&
!DRW_state_is_depth() && !DRW_state_is_select();
}
-/**
- * For when engines need to know if this is drawing for selection or not.
- */
bool DRW_state_is_select(void)
{
return DST.options.is_select;
@@ -2773,27 +2830,17 @@ bool DRW_state_is_depth(void)
return DST.options.is_depth;
}
-/**
- * Whether we are rendering for an image
- */
bool DRW_state_is_image_render(void)
{
return DST.options.is_image_render;
}
-/**
- * Whether we are rendering only the render engine,
- * or if we should also render the mode engines.
- */
bool DRW_state_is_scene_render(void)
{
BLI_assert(DST.options.is_scene_render ? DST.options.is_image_render : true);
return DST.options.is_scene_render;
}
-/**
- * Whether we are rendering simple opengl render
- */
bool DRW_state_is_opengl_render(void)
{
return DST.options.is_image_render && !DST.options.is_scene_render;
@@ -2808,28 +2855,18 @@ bool DRW_state_is_playback(void)
return false;
}
-/**
- * Is the user navigating the region.
- */
bool DRW_state_is_navigating(void)
{
const RegionView3D *rv3d = DST.draw_ctx.rv3d;
return (rv3d) && (rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING));
}
-/**
- * Should text draw in this mode?
- */
bool DRW_state_show_text(void)
{
return (DST.options.is_select) == 0 && (DST.options.is_depth) == 0 &&
(DST.options.is_scene_render) == 0 && (DST.options.draw_text) == 0;
}
-/**
- * Should draw support elements
- * Objects center, selection outline, probe data, ...
- */
bool DRW_state_draw_support(void)
{
View3D *v3d = DST.draw_ctx.v3d;
@@ -2837,9 +2874,6 @@ bool DRW_state_draw_support(void)
((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0);
}
-/**
- * Whether we should render the background
- */
bool DRW_state_draw_background(void)
{
return DST.options.draw_background;
@@ -2869,9 +2903,12 @@ bool DRW_engine_render_support(DrawEngineType *draw_engine_type)
void DRW_engine_register(DrawEngineType *draw_engine_type)
{
- BLI_addtail(&DRW_engines, draw_engine_type);
- g_registered_engine_len = BLI_listbase_count(&DRW_engines);
- draw_engine_type->index = g_registered_engine_len - 1;
+ DRWRegisteredDrawEngine *draw_engine = MEM_mallocN(sizeof(DRWRegisteredDrawEngine), __func__);
+ draw_engine->draw_engine = draw_engine_type;
+ draw_engine->index = g_registered_engines.len;
+
+ BLI_addtail(&g_registered_engines.engines, draw_engine);
+ g_registered_engines.len = BLI_listbase_count(&g_registered_engines.engines);
}
void DRW_engines_register(void)
@@ -2919,11 +2956,32 @@ void DRW_engines_register(void)
BKE_volume_batch_cache_dirty_tag_cb = DRW_volume_batch_cache_dirty_tag;
BKE_volume_batch_cache_free_cb = DRW_volume_batch_cache_free;
+
+ BKE_subsurf_modifier_free_gpu_cache_cb = DRW_subdiv_cache_free;
}
}
+static void drw_registered_engines_free(void)
+{
+ DRWRegisteredDrawEngine *next;
+ for (DRWRegisteredDrawEngine *type = g_registered_engines.engines.first; type; type = next) {
+ next = type->next;
+ BLI_remlink(&R_engines, type);
+
+ if (type->draw_engine->engine_free) {
+ type->draw_engine->engine_free();
+ }
+ MEM_freeN(type);
+ }
+
+ BLI_listbase_clear(&g_registered_engines.engines);
+ g_registered_engines.len = 0;
+}
+
void DRW_engines_free(void)
{
+ drw_registered_engines_free();
+
if (DST.gl_context == NULL) {
/* Nothing has been setup. Nothing to clear.
* Otherwise, DRW_opengl_context_enable can
@@ -2942,16 +3000,6 @@ void DRW_engines_free(void)
DRW_stats_free();
DRW_globals_free();
- DrawEngineType *next;
- for (DrawEngineType *type = DRW_engines.first; type; type = next) {
- next = type->next;
- BLI_remlink(&R_engines, type);
-
- if (type->engine_free) {
- type->engine_free();
- }
- }
-
DRW_UBO_FREE_SAFE(G_draw.block_ubo);
DRW_UBO_FREE_SAFE(G_draw.view_ubo);
DRW_TEXTURE_FREE_SAFE(G_draw.ramp);
@@ -3079,6 +3127,8 @@ void DRW_opengl_context_disable_ex(bool restore)
void DRW_opengl_context_enable(void)
{
+ /* TODO: should be replace by a more elegant alternative. */
+
if (G.background && DST.gl_context == NULL) {
WM_init_opengl();
}
@@ -3107,7 +3157,6 @@ void DRW_opengl_render_context_disable(void *re_gl_context)
BLI_ticket_mutex_unlock(DST.gl_context_mutex);
}
-/* Needs to be called AFTER DRW_opengl_render_context_enable() */
void DRW_gpu_render_context_enable(void *re_gpu_context)
{
/* If thread is main you should use DRW_opengl_context_enable(). */
@@ -3116,7 +3165,6 @@ void DRW_gpu_render_context_enable(void *re_gpu_context)
GPU_context_active_set(re_gpu_context);
}
-/* Needs to be called BEFORE DRW_opengl_render_context_disable() */
void DRW_gpu_render_context_disable(void *UNUSED(re_gpu_context))
{
GPU_flush();
@@ -3161,6 +3209,8 @@ void DRW_xr_drawing_end(void)
#endif
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Internal testing API for gtests
* \{ */
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index cfdc8b0df19..929fe9e2e1d 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -98,6 +98,17 @@ struct Object;
/* ------------ Data Structure --------------- */
/**
+ * Data structure to for registered draw engines that can store draw manager
+ * specific data.
+ */
+typedef struct DRWRegisteredDrawEngine {
+ void /*DRWRegisteredDrawEngine*/ *next, *prev;
+ DrawEngineType *draw_engine;
+ /** Index of the type in the lists. Index is used for dupli data. */
+ int index;
+} DRWRegisteredDrawEngine;
+
+/**
* Data structure containing all drawcalls organized by passes and materials.
* DRWPass > DRWShadingGroup > DRWCall > DRWCallState
* > DRWUniform
@@ -531,7 +542,7 @@ typedef struct DRWDebugBuffer {
typedef struct DRWData {
/** Instance data. */
DRWInstanceDataList *idatalist;
- /** Mempools for drawcalls. */
+ /** Memory-pools for draw-calls. */
struct BLI_memblock *commands;
struct BLI_memblock *commands_small;
struct BLI_memblock *callbuffers;
@@ -589,7 +600,7 @@ typedef struct DRWManager {
struct Object *dupli_origin;
/** Object-data referenced by the current dupli object. */
struct ID *dupli_origin_data;
- /** Ghash: #DupliKey -> void pointer for each enabled engine. */
+ /** Hash-map: #DupliKey -> void pointer for each enabled engine. */
struct GHash *dupli_ghash;
/** TODO(fclem): try to remove usage of this. */
DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE];
@@ -684,7 +695,12 @@ eDRWCommandType command_type_get(const uint64_t *command_type_bits, int index);
void drw_batch_cache_validate(Object *ob);
void drw_batch_cache_generate_requested(struct Object *ob);
+
+/**
+ * \warning Only evaluated mesh data is handled by this delayed generation.
+ */
void drw_batch_cache_generate_requested_delayed(Object *ob);
+void drw_batch_cache_generate_requested_evaluated_mesh(Object *ob);
void drw_resource_buffer_finish(DRWData *vmempool);
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 58271eba509..0a41e1a27c3 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -307,6 +307,7 @@ void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup,
const int *value,
int arraysize)
{
+ /* Boolean are expected to be 4bytes longs for OpenGL! */
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize);
}
@@ -384,7 +385,6 @@ void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, (float *)value, 16, 1);
}
-/* Stores the int instead of a pointer. */
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value)
{
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, &value, 1, 1);
@@ -557,7 +557,7 @@ static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob)
drw_call_calc_orco(ob, ob_infos->orcotexfac);
/* Random float value. */
uint random = (DST.dupli_source) ?
- DST.dupli_source->random_id :
+ DST.dupli_source->random_id :
/* TODO(fclem): this is rather costly to do at runtime. Maybe we can
* put it in ob->runtime and make depsgraph ensure it is up to date. */
BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
@@ -567,7 +567,12 @@ static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob)
ob_infos->ob_flag += (ob->base_flag & BASE_SELECTED) ? (1 << 1) : 0;
ob_infos->ob_flag += (ob->base_flag & BASE_FROM_DUPLI) ? (1 << 2) : 0;
ob_infos->ob_flag += (ob->base_flag & BASE_FROM_SET) ? (1 << 3) : 0;
- ob_infos->ob_flag += (ob == DST.draw_ctx.obact) ? (1 << 4) : 0;
+ if (ob->base_flag & BASE_FROM_DUPLI) {
+ ob_infos->ob_flag += (DRW_object_get_dupli_parent(ob) == DST.draw_ctx.obact) ? (1 << 4) : 0;
+ }
+ else {
+ ob_infos->ob_flag += (ob == DST.draw_ctx.obact) ? (1 << 4) : 0;
+ }
/* Negative scaling. */
ob_infos->ob_flag *= (ob->transflag & OB_NEG_SCALE) ? -1.0f : 1.0f;
/* Object Color. */
@@ -878,7 +883,6 @@ void DRW_shgroup_call_range(
drw_command_draw_range(shgroup, geom, handle, v_sta, v_ct);
}
-/* A count of 0 instance will use the default number of instance in the batch. */
void DRW_shgroup_call_instance_range(
DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct)
{
@@ -947,7 +951,6 @@ void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *shgroup, Object *ob,
drw_shgroup_call_procedural_add_ex(shgroup, geom, ob, tri_count * 3);
}
-/* Should be removed */
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
@@ -1336,6 +1339,17 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
int chunkid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_CHUNK);
int resourceid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_ID);
+ /* TODO(fclem) Will take the place of the above after the GPUShaderCreateInfo port. */
+ if (view_ubo_location == -1) {
+ view_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_DRW_VIEW);
+ }
+ if (model_ubo_location == -1) {
+ model_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_DRW_MODEL);
+ }
+ if (info_ubo_location == -1) {
+ info_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_DRW_INFOS);
+ }
+
if (chunkid_location != -1) {
drw_shgroup_uniform_create_ex(
shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 0, 1);
@@ -1461,14 +1475,15 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial
if (tex->ima) {
/* Image */
GPUTexture *gputex;
+ ImageUser *iuser = tex->iuser_available ? &tex->iuser : NULL;
if (tex->tiled_mapping_name[0]) {
- gputex = BKE_image_get_gpu_tiles(tex->ima, tex->iuser, NULL);
+ gputex = BKE_image_get_gpu_tiles(tex->ima, 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);
+ gputex = BKE_image_get_gpu_tilemap(tex->ima, iuser, NULL);
drw_shgroup_material_texture(grp, gputex, tex->tiled_mapping_name, tex->sampler_state);
}
else {
- gputex = BKE_image_get_gpu_texture(tex->ima, tex->iuser, NULL);
+ gputex = BKE_image_get_gpu_texture(tex->ima, iuser, NULL);
drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state);
}
}
@@ -1536,10 +1551,6 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
return shgroup;
}
-/**
- * State is added to #Pass.state while drawing.
- * Use to temporarily enable draw options.
- */
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state)
{
drw_command_set_mutable_state(shgroup, state, 0x0);
@@ -1558,7 +1569,6 @@ void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup,
drw_command_set_stencil_mask(shgroup, write_mask, reference, compare_mask);
}
-/* TODO: remove this function. */
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask)
{
drw_command_set_stencil_mask(shgroup, 0xFF, mask, 0xFF);
@@ -1784,10 +1794,12 @@ static void draw_frustum_bound_sphere_calc(const BoundBox *bbox,
bsphere->center[0] = farcenter[0] * z / e;
bsphere->center[1] = farcenter[1] * z / e;
bsphere->center[2] = z;
- bsphere->radius = len_v3v3(bsphere->center, farpoint);
- /* Transform to world space. */
- mul_m4_v3(viewinv, bsphere->center);
+ /* For XR, the view matrix may contain a scale factor. Then, transforming only the center
+ * into world space after calculating the radius will result in incorrect behavior. */
+ mul_m4_v3(viewinv, bsphere->center); /* Transform to world space. */
+ mul_m4_v3(viewinv, farpoint);
+ bsphere->radius = len_v3v3(bsphere->center, farpoint);
}
}
@@ -1851,7 +1863,6 @@ static void draw_view_matrix_state_update(DRWViewUboStorage *storage,
storage->viewvecs[1][2] = view_vecs[3][2] - view_vecs[0][2];
}
-/* Create a view with culling. */
DRWView *DRW_view_create(const float viewmat[4][4],
const float winmat[4][4],
const float (*culling_viewmat)[4],
@@ -1878,7 +1889,6 @@ DRWView *DRW_view_create(const float viewmat[4][4],
return view;
}
-/* Create a view with culling done by another view. */
DRWView *DRW_view_create_sub(const DRWView *parent_view,
const float viewmat[4][4],
const float winmat[4][4])
@@ -1900,13 +1910,10 @@ DRWView *DRW_view_create_sub(const DRWView *parent_view,
return view;
}
-/**
- * DRWView Update:
+/* DRWView Update:
* This is meant to be done on existing views when rendering in a loop and there is no
- * need to allocate more DRWViews.
- */
+ * need to allocate more DRWViews. */
-/* Update matrices of a view created with DRW_view_create_sub. */
void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float winmat[4][4])
{
BLI_assert(view->parent != NULL);
@@ -1917,7 +1924,6 @@ void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float w
draw_view_matrix_state_update(&view->storage, viewmat, winmat);
}
-/* Update matrices of a view created with DRW_view_create. */
void DRW_view_update(DRWView *view,
const float viewmat[4][4],
const float winmat[4][4],
@@ -1994,13 +2000,11 @@ void DRW_view_update(DRWView *view,
#endif
}
-/* Return default view if it is a viewport render. */
const DRWView *DRW_view_default_get(void)
{
return DST.view_default;
}
-/* WARNING: Only use in render AND only if you are going to set view_default again. */
void DRW_view_reset(void)
{
DST.view_default = NULL;
@@ -2008,18 +2012,12 @@ void DRW_view_reset(void)
DST.view_previous = NULL;
}
-/* MUST only be called once per render and only in render mode. Sets default view. */
void DRW_view_default_set(DRWView *view)
{
BLI_assert(DST.view_default == NULL);
DST.view_default = view;
}
-/**
- * This only works if DRWPasses have been tagged with DRW_STATE_CLIP_PLANES,
- * and if the shaders have support for it (see usage of gl_ClipDistance).
- * NOTE: planes must be in world space.
- */
void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len)
{
BLI_assert(plane_len <= MAX_CLIP_PLANES);
@@ -2039,14 +2037,11 @@ void DRW_view_camtexco_get(const DRWView *view, float r_texco[4])
copy_v4_v4(r_texco, view->storage.viewcamtexcofac);
}
-/* Return world space frustum corners. */
void DRW_view_frustum_corners_get(const DRWView *view, BoundBox *corners)
{
memcpy(corners, &view->frustum_corners, sizeof(view->frustum_corners));
}
-/* Return world space frustum sides as planes.
- * See draw_frustum_culling_planes_calc() for the plane order. */
void DRW_view_frustum_planes_get(const DRWView *view, float planes[6][4])
{
memcpy(planes, &view->frustum_planes, sizeof(view->frustum_planes));
@@ -2134,8 +2129,6 @@ DRWPass *DRW_pass_create(const char *name, DRWState state)
return pass;
}
-/* Create an instance of the original pass that will execute the same drawcalls but with its own
- * DRWState. */
DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState state)
{
DRWPass *pass = DRW_pass_create(name, state);
@@ -2144,7 +2137,6 @@ DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState
return pass;
}
-/* Link two passes so that they are both rendered if the first one is being drawn. */
void DRW_pass_link(DRWPass *first, DRWPass *second)
{
BLI_assert(first != second);
@@ -2205,10 +2197,6 @@ static int pass_shgroup_dist_sort(const void *a, const void *b)
#undef SORT_IMPL_LINKTYPE
-/**
- * Sort Shading groups by decreasing Z of their first draw call.
- * This is useful for order dependent effect such as alpha-blending.
- */
void DRW_pass_sort_shgroup_z(DRWPass *pass)
{
const float(*viewinv)[4] = DST.view_active->storage.viewinv;
@@ -2259,9 +2247,6 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass)
pass->shgroups.last = last;
}
-/**
- * Reverse Shading group submission order.
- */
void DRW_pass_sort_shgroup_reverse(DRWPass *pass)
{
pass->shgroups.last = pass->shgroups.first;
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 491367078e7..070b6d2eae8 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -273,7 +273,6 @@ static void drw_stencil_state_set(uint write_mask, uint reference, uint compare_
GPU_stencil_compare_mask_set(compare_mask);
}
-/* Reset state to not interfere with other UI draw-call. */
void DRW_state_reset_ex(DRWState state)
{
DST.state = ~state;
@@ -292,12 +291,6 @@ static void drw_state_validate(void)
}
}
-/**
- * Use with care, intended so selection code can override passes depth settings,
- * which is important for selection to work properly.
- *
- * Should be set in main draw loop, cleared afterwards
- */
void DRW_state_lock(DRWState state)
{
DST.state_lock = state;
@@ -361,8 +354,7 @@ static bool draw_call_is_culled(const DRWResourceHandle *handle, DRWView *view)
return (culling->mask & view->culling_mask) != 0;
}
-/* Set active view for rendering. */
-void DRW_view_set_active(const DRWView *view)
+void DRW_view_set_active(DRWView *view)
{
/* TODO(fclem) DST.view_active should be const too. */
DST.view_active = (view) ? (DRWView *)view : DST.view_default;
@@ -436,32 +428,24 @@ static bool draw_culling_plane_test(const BoundBox *corners, const float plane[4
return false;
}
-/* Return True if the given BoundSphere intersect the current view frustum.
- * bsphere must be in world space. */
bool DRW_culling_sphere_test(const DRWView *view, const BoundSphere *bsphere)
{
view = view ? view : DST.view_default;
return draw_culling_sphere_test(&view->frustum_bsphere, view->frustum_planes, bsphere);
}
-/* Return True if the given BoundBox intersect the current view frustum.
- * bbox must be in world space. */
bool DRW_culling_box_test(const DRWView *view, const BoundBox *bbox)
{
view = view ? view : DST.view_default;
return draw_culling_box_test(view->frustum_planes, bbox);
}
-/* Return True if the view frustum is inside or intersect the given plane.
- * plane must be in world space. */
bool DRW_culling_plane_test(const DRWView *view, const float plane[4])
{
view = view ? view : DST.view_default;
return draw_culling_plane_test(&view->frustum_corners, plane);
}
-/* Return True if the given box intersect the current view frustum.
- * This function will have to be replaced when world space bb per objects is implemented. */
bool DRW_culling_min_max_test(const DRWView *view, float obmat[4][4], float min[3], float max[3])
{
view = view ? view : DST.view_default;
@@ -1190,7 +1174,6 @@ void DRW_draw_pass(DRWPass *pass)
}
}
-/* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */
void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
{
drw_draw_pass_ex(pass, start_group, end_group);
diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c
index 70fe12270f5..80ea7bf654d 100644
--- a/source/blender/draw/intern/draw_manager_profiling.c
+++ b/source/blender/draw/intern/draw_manager_profiling.c
@@ -129,8 +129,6 @@ static void drw_stats_timer_start_ex(const char *name, const bool is_query)
}
}
-/* Use this to group the queries. It does NOT keep track
- * of the time, it only sum what the queries inside it. */
void DRW_stats_group_start(const char *name)
{
drw_stats_timer_start_ex(name, false);
@@ -147,7 +145,6 @@ void DRW_stats_group_end(void)
}
}
-/* NOTE: Only call this when no sub timer will be called. */
void DRW_stats_query_start(const char *name)
{
GPU_debug_group_begin(name);
@@ -257,8 +254,7 @@ void DRW_stats_draw(const rcti *rect)
/* Engines rows */
char time_to_txt[16];
- DRW_ENABLED_ENGINE_ITER(DST.view_data_active, engine, data)
- {
+ DRW_ENABLED_ENGINE_ITER (DST.view_data_active, engine, data) {
u = 0;
draw_stat_5row(rect, u++, v, engine->idname, sizeof(engine->idname));
diff --git a/source/blender/draw/intern/draw_manager_profiling.h b/source/blender/draw/intern/draw_manager_profiling.h
index 98a827e58c3..5626ac52049 100644
--- a/source/blender/draw/intern/draw_manager_profiling.h
+++ b/source/blender/draw/intern/draw_manager_profiling.h
@@ -32,9 +32,16 @@ void DRW_stats_free(void);
void DRW_stats_begin(void);
void DRW_stats_reset(void);
+/**
+ * Use this to group the queries. It does NOT keep track
+ * of the time, it only sum what the queries inside it.
+ */
void DRW_stats_group_start(const char *name);
void DRW_stats_group_end(void);
+/**
+ * \note Only call this when no sub timer will be called.
+ */
void DRW_stats_query_start(const char *name);
void DRW_stats_query_end(void);
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index e27a0954f19..ca8284af691 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -618,8 +618,6 @@ void DRW_shader_library_add_file(DRWShaderLibrary *lib, const char *lib_code, co
}
}
-/* Return an allocN'ed string containing the shader code with its dependencies prepended.
- * Caller must free the string with MEM_freeN after use. */
char *DRW_shader_library_create_shader_string(const DRWShaderLibrary *lib, const char *shader_code)
{
/* TODO(fclem) Could be done in one pass. */
diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.c
index cfaa22ba7c6..5d7b2c142c2 100644
--- a/source/blender/draw/intern/draw_manager_text.c
+++ b/source/blender/draw/intern/draw_manager_text.c
@@ -223,7 +223,6 @@ void DRW_text_cache_draw(DRWTextStore *dt, ARegion *region, struct View3D *v3d)
}
}
-/* Copied from drawobject.c */
void DRW_text_edit_mesh_measure_stats(ARegion *region,
View3D *v3d,
Object *ob,
diff --git a/source/blender/draw/intern/draw_manager_text.h b/source/blender/draw/intern/draw_manager_text.h
index 4f3a6153775..098b636cc98 100644
--- a/source/blender/draw/intern/draw_manager_text.h
+++ b/source/blender/draw/intern/draw_manager_text.h
@@ -38,7 +38,7 @@ void DRW_text_cache_destroy(struct DRWTextStore *dt);
void DRW_text_cache_add(struct DRWTextStore *dt,
const float co[3],
const char *str,
- const int str_len,
+ int str_len,
short xoffs,
short yoffs,
short flag,
@@ -60,8 +60,9 @@ enum {
};
/* draw_manager.c */
+
struct DRWTextStore *DRW_text_cache_ensure(void);
#ifdef __cplusplus
}
-#endif \ No newline at end of file
+#endif
diff --git a/source/blender/draw/intern/draw_select_buffer.c b/source/blender/draw/intern/draw_select_buffer.c
index d7438b7e0f0..bae07753336 100644
--- a/source/blender/draw/intern/draw_select_buffer.c
+++ b/source/blender/draw/intern/draw_select_buffer.c
@@ -47,7 +47,6 @@
/** \name Buffer of select ID's
* \{ */
-/* Main function to read a block of pixels from the select frame buffer. */
uint *DRW_select_buffer_read(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -122,10 +121,6 @@ uint *DRW_select_buffer_read(struct Depsgraph *depsgraph,
*
* \{ */
-/**
- * \param rect: The rectangle to sample indices from (min/max inclusive).
- * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure.
- */
uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -165,12 +160,6 @@ uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph,
return bitmap_buf;
}
-/**
- * \param center: Circle center.
- * \param radius: Circle radius.
- * \param r_bitmap_len: Number of indices in the selection id buffer.
- * \returns a #BLI_bitmap the length of \a r_bitmap_len or NULL on failure.
- */
uint *DRW_select_buffer_bitmap_from_circle(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -235,12 +224,6 @@ static void drw_select_mask_px_cb(int x, int x_end, int y, void *user_data)
} while (++x != x_end);
}
-/**
- * \param poly: The polygon coordinates.
- * \param poly_len: Length of the polygon.
- * \param rect: Polygon boundaries.
- * \returns a #BLI_bitmap.
- */
uint *DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -309,9 +292,6 @@ uint *DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph,
*
* \{ */
-/**
- * Samples a single pixel.
- */
uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -357,11 +337,6 @@ static bool select_buffer_test_fn(const void *__restrict value, void *__restrict
return false;
}
-/**
- * Find the selection id closest to \a center.
- * \param dist: Use to initialize the distance,
- * when found, this value is set to the distance of the selection that's returned.
- */
uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -522,4 +497,5 @@ void DRW_select_buffer_context_create(Base **bases, const uint bases_len, short
select_ctx->select_mode = select_mode;
memset(select_ctx->persmat, 0, sizeof(select_ctx->persmat));
}
+
/** \} */
diff --git a/source/blender/draw/intern/draw_shader.c b/source/blender/draw/intern/draw_shader.c
index 121a0acd059..28ac76ccd7f 100644
--- a/source/blender/draw/intern/draw_shader.c
+++ b/source/blender/draw/intern/draw_shader.c
@@ -47,12 +47,7 @@ static struct {
static GPUShader *hair_refine_shader_compute_create(ParticleRefineShader UNUSED(refinement))
{
- GPUShader *sh = NULL;
- sh = GPU_shader_create_compute(datatoc_common_hair_refine_comp_glsl,
- datatoc_common_hair_lib_glsl,
- "#define HAIR_PHASE_SUBDIV\n",
- __func__);
- return sh;
+ return GPU_shader_create_from_info_name("draw_hair_refine_compute");
}
static GPUShader *hair_refine_shader_transform_feedback_create(
diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h
new file mode 100644
index 00000000000..35350417ca8
--- /dev/null
+++ b/source/blender/draw/intern/draw_shader_shared.h
@@ -0,0 +1,52 @@
+
+#ifndef GPU_SHADER
+# include "gpu_shader_shared_utils.h"
+#endif
+
+#define DRW_SHADER_SHARED_H
+
+#define DRW_RESOURCE_CHUNK_LEN 512
+
+struct ViewInfos {
+ /* View matrices */
+ float4x4 persmat;
+ float4x4 persinv;
+ float4x4 viewmat;
+ float4x4 viewinv;
+ float4x4 winmat;
+ float4x4 wininv;
+
+ float4 clip_planes[6];
+ float4 viewvecs[2];
+ /* Should not be here. Not view dependent (only main view). */
+ float4 viewcamtexcofac;
+};
+BLI_STATIC_ASSERT_ALIGN(ViewInfos, 16)
+
+/* TODO(fclem) Mass rename. */
+#define ViewProjectionMatrix drw_view.persmat
+#define ViewProjectionMatrixInverse drw_view.persinv
+#define ViewMatrix drw_view.viewmat
+#define ViewMatrixInverse drw_view.viewinv
+#define ProjectionMatrix drw_view.winmat
+#define ProjectionMatrixInverse drw_view.wininv
+#define clipPlanes drw_view.clip_planes
+#define ViewVecs drw_view.viewvecs
+#define CameraTexCoFactors drw_view.viewcamtexcofac
+
+struct ObjectMatrices {
+ float4x4 drw_modelMatrix;
+ float4x4 drw_modelMatrixInverse;
+};
+BLI_STATIC_ASSERT_ALIGN(ViewInfos, 16)
+
+struct ObjectInfos {
+ float4 drw_OrcoTexCoFactors[2];
+ float4 drw_ObjectColor;
+ float4 drw_Infos;
+};
+BLI_STATIC_ASSERT_ALIGN(ViewInfos, 16)
+
+#define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
+#define ObjectInfo (drw_infos[resource_id].drw_Infos)
+#define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h
new file mode 100644
index 00000000000..eeef2156e35
--- /dev/null
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -0,0 +1,231 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_sys_types.h"
+
+struct BMesh;
+struct GPUIndexBuf;
+struct GPUUniformBuf;
+struct GPUVertBuf;
+struct Mesh;
+struct MeshBatchCache;
+struct MeshBufferCache;
+struct MeshRenderData;
+struct Object;
+struct Scene;
+struct Subdiv;
+struct ToolSettings;
+
+/* -------------------------------------------------------------------- */
+/** \name DRWPatchMap
+ *
+ * This is a GPU version of the OpenSubDiv PatchMap. The quad tree and the patch handles are copied
+ * to GPU buffers in order to lookup the right patch for a given set of patch coordinates.
+ * \{ */
+
+typedef struct DRWPatchMap {
+ struct GPUVertBuf *patch_map_handles;
+ struct GPUVertBuf *patch_map_quadtree;
+ int min_patch_face;
+ int max_patch_face;
+ int max_depth;
+ int patches_are_triangular;
+} DRWPatchMap;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DRWSubdivCache
+ *
+ * This holds the various buffers used to evaluate and render subdivision through OpenGL.
+ * \{ */
+
+typedef struct DRWSubdivCache {
+ struct Mesh *mesh;
+ struct BMesh *bm;
+ struct Subdiv *subdiv;
+ bool optimal_display;
+ bool do_limit_normals;
+
+ /* Coordinates used to evaluate patches for UVs, positions, and normals. */
+ struct GPUVertBuf *patch_coords;
+ /* Coordinates used to evaluate patches for the face centers (or face dots) in edit-mode. */
+ struct GPUVertBuf *fdots_patch_coords;
+
+ /* Resolution used to generate the patch coordinates. */
+ int resolution;
+
+ /* Number of subdivided loops, also the number of patch coordinates since we have one coordinate
+ * but quad corner/vertex. */
+ uint num_subdiv_loops;
+ uint num_subdiv_edges;
+ uint num_subdiv_triangles;
+ uint num_subdiv_verts;
+ uint num_subdiv_quads;
+
+ /* Number of polygons in the coarse mesh, notably used to compute a coarse polygon index given a
+ * subdivision loop index. */
+ int num_coarse_poly;
+
+ /* Maps subdivision loop to subdivided vertex index. */
+ int *subdiv_loop_subdiv_vert_index;
+ /* Maps subdivision loop to original coarse poly index. */
+ int *subdiv_loop_poly_index;
+
+ /* Indices of faces adjacent to the vertices, ordered by vertex index, with no particular
+ * winding. */
+ struct GPUVertBuf *subdiv_vertex_face_adjacency;
+ /* The difference between value (i + 1) and (i) gives the number of faces adjacent to vertex (i).
+ */
+ struct GPUVertBuf *subdiv_vertex_face_adjacency_offsets;
+
+ /* Maps subdivision loop to original coarse vertex index, only really useful for edit mode. */
+ struct GPUVertBuf *verts_orig_index;
+ /* Maps subdivision loop to original coarse edge index, only really useful for edit mode. */
+ struct GPUVertBuf *edges_orig_index;
+
+ /* Owned by #Subdiv. Indexed by coarse polygon index, difference between value (i + 1) and (i)
+ * gives the number of ptex faces for coarse polygon (i). */
+ int *face_ptex_offset;
+ /* Vertex buffer for face_ptex_offset. */
+ struct GPUVertBuf *face_ptex_offset_buffer;
+
+ int *subdiv_polygon_offset;
+ struct GPUVertBuf *subdiv_polygon_offset_buffer;
+
+ /* Contains the start loop index and the smooth flag for each coarse polygon. */
+ struct GPUVertBuf *extra_coarse_face_data;
+
+ /* Computed for ibo.points, one value per subdivided vertex, mapping coarse vertices ->
+ * subdivided loop */
+ int *point_indices;
+
+ /* Material offsets. */
+ int *mat_start;
+ int *mat_end;
+ struct GPUVertBuf *polygon_mat_offset;
+
+ DRWPatchMap gpu_patch_map;
+
+ /* UBO to store settings for the various compute shaders. */
+ struct GPUUniformBuf *ubo;
+} DRWSubdivCache;
+
+/* Only frees the data of the cache, caller is responsible to free the cache itself if necessary.
+ */
+void draw_subdiv_cache_free(DRWSubdivCache *cache);
+
+/** \} */
+
+void DRW_create_subdivision(const struct Scene *scene,
+ struct Object *ob,
+ struct Mesh *mesh,
+ struct MeshBatchCache *batch_cache,
+ struct MeshBufferCache *mbc,
+ const struct ToolSettings *toolsettings);
+
+void DRW_subdiv_cache_free(struct Subdiv *subdiv);
+
+void draw_subdiv_init_mesh_render_data(DRWSubdivCache *cache,
+ struct MeshRenderData *mr,
+ const struct ToolSettings *toolsettings);
+
+void draw_subdiv_init_origindex_buffer(struct GPUVertBuf *buffer,
+ int *vert_origindex,
+ uint num_loops,
+ uint loose_len);
+
+struct GPUVertBuf *draw_subdiv_build_origindex_buffer(int *vert_origindex, uint num_loops);
+
+/* Compute shader functions. */
+
+void draw_subdiv_build_sculpt_data_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *mask_vbo,
+ struct GPUVertBuf *face_set_vbo,
+ struct GPUVertBuf *sculpt_data);
+
+void draw_subdiv_accumulate_normals(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *face_adjacency_offsets,
+ struct GPUVertBuf *face_adjacency_lists,
+ struct GPUVertBuf *vertex_normals);
+
+void draw_subdiv_finalize_normals(const DRWSubdivCache *cache,
+ struct GPUVertBuf *vertex_normals,
+ struct GPUVertBuf *subdiv_loop_subdiv_vert_index,
+ struct GPUVertBuf *pos_nor);
+
+void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ bool do_limit_normals);
+
+void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
+ struct GPUVertBuf *src_data,
+ struct GPUVertBuf *dst_data,
+ int dimensions,
+ int dst_offset);
+
+void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
+ struct GPUVertBuf *uvs,
+ int face_varying_channel,
+ int dst_offset);
+
+void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *edge_idx,
+ struct GPUVertBuf *edge_fac);
+
+void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache,
+ struct GPUIndexBuf *subdiv_tris,
+ int material_count);
+
+void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache,
+ struct GPUIndexBuf *lines_indices);
+
+void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache *cache,
+ struct GPUIndexBuf *lines_indices,
+ uint num_loose_edges);
+
+void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
+ struct GPUVertBuf *fdots_pos,
+ struct GPUVertBuf *fdots_nor,
+ struct GPUIndexBuf *fdots_indices);
+
+void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *lnor);
+
+void draw_subdiv_build_edituv_stretch_area_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *coarse_data,
+ struct GPUVertBuf *subdiv_data);
+
+void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *uvs,
+ int uvs_offset,
+ struct GPUVertBuf *stretch_angles);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/intern/draw_texture_pool.cc b/source/blender/draw/intern/draw_texture_pool.cc
index 544a763ddb9..e3882d4acb6 100644
--- a/source/blender/draw/intern/draw_texture_pool.cc
+++ b/source/blender/draw/intern/draw_texture_pool.cc
@@ -28,10 +28,10 @@
using namespace blender;
-typedef struct DRWTexturePoolHandle {
+struct DRWTexturePoolHandle {
uint64_t users_bits;
GPUTexture *texture;
-} DRWTexturePoolHandle;
+};
struct DRWTexturePool {
Vector<void *, 16> users;
@@ -40,23 +40,19 @@ struct DRWTexturePool {
int last_user_id = -1;
};
-DRWTexturePool *DRW_texture_pool_create(void)
+DRWTexturePool *DRW_texture_pool_create()
{
return new DRWTexturePool();
}
void DRW_texture_pool_free(DRWTexturePool *pool)
{
- /* Reseting the pool twice will effectively free all textures. */
+ /* Resetting the pool twice will effectively free all textures. */
DRW_texture_pool_reset(pool);
DRW_texture_pool_reset(pool);
delete pool;
}
-/**
- * Try to find a texture corresponding to params into the texture pool.
- * If no texture was found, create one and add it to the pool.
- */
GPUTexture *DRW_texture_pool_query(
DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user)
{
@@ -86,7 +82,7 @@ GPUTexture *DRW_texture_pool_query(
if (user_bit & handle.users_bits) {
continue;
}
- /* If everthing matches reuse the texture. */
+ /* If everything matches reuse the texture. */
if ((GPU_texture_format(handle.texture) == format) &&
(GPU_texture_width(handle.texture) == width) &&
(GPU_texture_height(handle.texture) == height)) {
@@ -113,7 +109,6 @@ GPUTexture *DRW_texture_pool_query(
return handle.texture;
}
-/* Resets the user bits for each texture in the pool and delete unused ones. */
void DRW_texture_pool_reset(DRWTexturePool *pool)
{
pool->last_user_id = -1;
@@ -137,4 +132,4 @@ void DRW_texture_pool_reset(DRWTexturePool *pool)
pool->handles.remove_and_reorder(i);
}
}
-} \ No newline at end of file
+}
diff --git a/source/blender/draw/intern/draw_texture_pool.h b/source/blender/draw/intern/draw_texture_pool.h
index f0b8f775c75..920d29b4cca 100644
--- a/source/blender/draw/intern/draw_texture_pool.h
+++ b/source/blender/draw/intern/draw_texture_pool.h
@@ -38,8 +38,15 @@ extern "C" {
DRWTexturePool *DRW_texture_pool_create(void);
void DRW_texture_pool_free(DRWTexturePool *pool);
+/**
+ * Try to find a texture corresponding to params into the texture pool.
+ * If no texture was found, create one and add it to the pool.
+ */
GPUTexture *DRW_texture_pool_query(
DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user);
+/**
+ * Resets the user bits for each texture in the pool and delete unused ones.
+ */
void DRW_texture_pool_reset(DRWTexturePool *pool);
#ifdef __cplusplus
diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c
index 90bb3762473..6fe0abf1adf 100644
--- a/source/blender/draw/intern/draw_view.c
+++ b/source/blender/draw/intern/draw_view.c
@@ -28,6 +28,7 @@
#include "DNA_view3d_types.h"
#include "ED_screen.h"
+#include "ED_util.h"
#include "ED_view3d.h"
#include "GPU_immediate.h"
@@ -39,6 +40,7 @@
#include "WM_types.h"
+#include "BKE_global.h"
#include "BKE_object.h"
#include "BKE_paint.h"
@@ -62,6 +64,10 @@ void DRW_draw_region_info(void)
static bool is_cursor_visible(const DRWContextState *draw_ctx, Scene *scene, ViewLayer *view_layer)
{
+ if (G.moving & G_TRANSFORM_CURSOR) {
+ return true;
+ }
+
View3D *v3d = draw_ctx->v3d;
if ((v3d->flag2 & V3D_HIDE_OVERLAYS) || (v3d->overlay.flag & V3D_OVERLAY_HIDE_CURSOR)) {
return false;
@@ -226,6 +232,43 @@ static bool is_cursor_visible_2d(const DRWContextState *draw_ctx)
return (sima->overlay.flag & SI_OVERLAY_SHOW_OVERLAYS) != 0;
}
+/* -------------------------------------------------------------------- */
+/** \name Generic Cursor
+ * \{ */
+
+void DRW_draw_cursor_2d_ex(const ARegion *region, const float cursor[2])
+{
+ int co[2];
+ UI_view2d_view_to_region(&region->v2d, cursor[0], cursor[1], &co[0], &co[1]);
+
+ /* Draw nice Anti Aliased cursor. */
+ GPU_line_width(1.0f);
+ GPU_blend(GPU_BLEND_ALPHA);
+ GPU_line_smooth(true);
+
+ /* Draw lines */
+ float original_proj[4][4];
+ GPU_matrix_projection_get(original_proj);
+ GPU_matrix_push();
+ ED_region_pixelspace(region);
+ GPU_matrix_translate_2f(co[0] + 0.5f, co[1] + 0.5f);
+ GPU_matrix_scale_2f(U.widget_unit, U.widget_unit);
+
+ GPUBatch *cursor_batch = DRW_cache_cursor_get(true);
+
+ GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_FLAT_COLOR);
+ GPU_batch_set_shader(cursor_batch, shader);
+
+ GPU_batch_draw(cursor_batch);
+
+ GPU_blend(GPU_BLEND_NONE);
+ GPU_line_smooth(false);
+ GPU_matrix_pop();
+ GPU_matrix_projection_set(original_proj);
+}
+
+/** \} */
+
void DRW_draw_cursor_2d(void)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -236,35 +279,11 @@ void DRW_draw_cursor_2d(void)
GPU_depth_test(GPU_DEPTH_NONE);
if (is_cursor_visible_2d(draw_ctx)) {
- SpaceImage *sima = (SpaceImage *)draw_ctx->space_data;
- int co[2];
- UI_view2d_view_to_region(&region->v2d, sima->cursor[0], sima->cursor[1], &co[0], &co[1]);
-
- /* Draw nice Anti Aliased cursor. */
- GPU_line_width(1.0f);
- GPU_blend(GPU_BLEND_ALPHA);
- GPU_line_smooth(true);
-
- /* Draw lines */
- float original_proj[4][4];
- GPU_matrix_projection_get(original_proj);
- GPU_matrix_push();
- ED_region_pixelspace(region);
- GPU_matrix_translate_2f(co[0] + 0.5f, co[1] + 0.5f);
- GPU_matrix_scale_2f(U.widget_unit, U.widget_unit);
-
- GPUBatch *cursor_batch = DRW_cache_cursor_get(true);
- GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_FLAT_COLOR);
- GPU_batch_set_shader(cursor_batch, shader);
-
- GPU_batch_draw(cursor_batch);
-
- GPU_blend(GPU_BLEND_NONE);
- GPU_line_smooth(false);
- GPU_matrix_pop();
- GPU_matrix_projection_set(original_proj);
+ const SpaceImage *sima = (SpaceImage *)draw_ctx->space_data;
+ DRW_draw_cursor_2d_ex(region, sima->cursor);
}
}
+
/** \} */
/* **************************** 3D Gizmo ******************************** */
diff --git a/source/blender/draw/intern/draw_view.h b/source/blender/draw/intern/draw_view.h
index 24fabaae05e..2646918cd3e 100644
--- a/source/blender/draw/intern/draw_view.h
+++ b/source/blender/draw/intern/draw_view.h
@@ -22,6 +22,8 @@
#pragma once
+struct ARegion;
+
void DRW_draw_region_info(void);
void DRW_clear_background(void);
void DRW_draw_cursor(void);
diff --git a/source/blender/draw/intern/draw_view_data.cc b/source/blender/draw/intern/draw_view_data.cc
index b8f22a846ba..f7304737830 100644
--- a/source/blender/draw/intern/draw_view_data.cc
+++ b/source/blender/draw/intern/draw_view_data.cc
@@ -30,6 +30,7 @@
#include "draw_manager_text.h"
+#include "draw_manager.h"
#include "draw_view_data.h"
using namespace blender;
@@ -49,13 +50,12 @@ struct DRWViewData {
Vector<ViewportEngineData *> enabled_engines;
};
-/* Creates a view data with all possible engines type for this view. */
DRWViewData *DRW_view_data_create(ListBase *engine_types)
{
DRWViewData *view_data = new DRWViewData();
- LISTBASE_FOREACH (DrawEngineType *, type, engine_types) {
+ LISTBASE_FOREACH (DRWRegisteredDrawEngine *, type, engine_types) {
ViewportEngineData engine = {};
- engine.engine_type = static_cast<void *>(type);
+ engine.engine_type = type;
view_data->engines.append(engine);
}
return view_data;
@@ -102,7 +102,7 @@ void DRW_view_data_default_lists_from_viewport(DRWViewData *view_data, GPUViewpo
static void draw_viewport_engines_data_clear(ViewportEngineData *data)
{
- DrawEngineType *engine_type = static_cast<DrawEngineType *>(data->engine_type);
+ DrawEngineType *engine_type = data->engine_type->draw_engine;
const DrawEngineDataSize *data_size = engine_type->vedata_size;
for (int i = 0; data->fbl && i < data_size->fbl_len; i++) {
@@ -171,13 +171,12 @@ void DRW_view_data_texture_list_size_validate(DRWViewData *view_data, const int
}
ViewportEngineData *DRW_view_data_engine_data_get_ensure(DRWViewData *view_data,
- DrawEngineType *engine_type_)
+ DrawEngineType *engine_type)
{
- void *engine_type = static_cast<void *>(engine_type_);
for (ViewportEngineData &engine : view_data->engines) {
- if (engine.engine_type == engine_type) {
+ if (engine.engine_type->draw_engine == engine_type) {
if (engine.fbl == nullptr) {
- const DrawEngineDataSize *data_size = engine_type_->vedata_size;
+ const DrawEngineDataSize *data_size = engine_type->vedata_size;
engine.fbl = (FramebufferList *)MEM_calloc_arrayN(
data_size->fbl_len, sizeof(GPUFrameBuffer *), "FramebufferList");
engine.txl = (TextureList *)MEM_calloc_arrayN(
diff --git a/source/blender/draw/intern/draw_view_data.h b/source/blender/draw/intern/draw_view_data.h
index d19ffd9e1b6..b37e48c11e8 100644
--- a/source/blender/draw/intern/draw_view_data.h
+++ b/source/blender/draw/intern/draw_view_data.h
@@ -31,8 +31,9 @@
extern "C" {
#endif
-struct GPUViewport;
+struct DRWRegisteredDrawEngine;
struct DrawEngineType;
+struct GPUViewport;
/* NOTE these structs are only here for reading the actual lists from the engine.
* The actual length of them is stored in a ViewportEngineData_Info.
@@ -55,13 +56,17 @@ typedef struct StorageList {
} StorageList;
typedef struct ViewportEngineData {
- void *engine_type;
+ /* Not owning pointer to the draw engine. */
+ struct DRWRegisteredDrawEngine *engine_type;
FramebufferList *fbl;
TextureList *txl;
PassList *psl;
StorageList *stl;
- /** Memory block that will be free using */
+ /**
+ * \brief Memory block that can be freely used by the draw engine.
+ * When used the draw engine must implement #DrawEngineType.instance_free callback.
+ */
void *instance_data;
char info[GPU_INFO_SIZE];
@@ -101,6 +106,11 @@ typedef struct DefaultTextureList {
typedef struct DRWViewData DRWViewData;
+/**
+ * Creates a view data with all possible engines type for this view.
+ *
+ * `engine_types` contains #DRWRegisteredDrawEngine.
+ */
DRWViewData *DRW_view_data_create(ListBase *engine_types);
void DRW_view_data_free(DRWViewData *view_data);
@@ -132,7 +142,8 @@ ViewportEngineData *DRW_view_data_enabled_engine_iter_step(DRWEngineIterator *it
DRW_view_data_enabled_engine_iter_begin(&iterator, view_data_); \
/* WATCH Comma operator trickery ahead! This tests engine_ == NULL. */ \
while ((data_ = DRW_view_data_enabled_engine_iter_step(&iterator), \
- engine_ = (data_ != NULL) ? (struct DrawEngineType *)data_->engine_type : NULL))
+ engine_ = (data_ != NULL) ? (struct DrawEngineType *)data_->engine_type->draw_engine : \
+ NULL))
#ifdef __cplusplus
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
index d9f397fd8b8..37eb4f80442 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
@@ -39,6 +39,8 @@
extern "C" {
#endif
+struct DRWSubdivCache;
+
#define MIN_RANGE_LEN 1024
/* ---------------------------------------------------------------------- */
@@ -82,7 +84,8 @@ typedef struct MeshRenderData {
const float (*bm_poly_centers)[3];
int *v_origindex, *e_origindex, *p_origindex;
- int crease_ofs;
+ int edge_crease_ofs;
+ int vert_crease_ofs;
int bweight_ofs;
int freestyle_edge_ofs;
int freestyle_face_ofs;
@@ -98,8 +101,9 @@ typedef struct MeshRenderData {
BMFace *efa_act_uv;
/* Data created on-demand (usually not for #BMesh based data). */
MLoopTri *mlooptri;
+ const float (*vert_normals)[3];
+ const float (*poly_normals)[3];
float (*loop_normals)[3];
- float (*poly_normals)[3];
int *lverts, *ledges;
struct {
@@ -168,39 +172,43 @@ BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *e
/* ---------------------------------------------------------------------- */
/** \name Mesh Elements Extract Struct
* \{ */
+
/* TODO(jbakker): move parameters inside a struct. */
-typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr,
- BMLoop **elt,
- const int elt_index,
- void *data);
+
+typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr, BMLoop **elt, int elt_index, void *data);
typedef void(ExtractTriMeshFn)(const MeshRenderData *mr,
const MLoopTri *mlt,
- const int elt_index,
+ int elt_index,
void *data);
typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr,
const BMFace *f,
- const int f_index,
+ int f_index,
void *data);
typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr,
const MPoly *mp,
- const int mp_index,
+ int mp_index,
void *data);
typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr,
const BMEdge *eed,
- const int ledge_index,
+ int ledge_index,
void *data);
typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr,
const MEdge *med,
- const int ledge_index,
+ int ledge_index,
void *data);
typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr,
const BMVert *eve,
- const int lvert_index,
+ int lvert_index,
void *data);
typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
const MVert *mv,
- const int lvert_index,
+ int lvert_index,
void *data);
+typedef void(ExtractLooseGeomSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *data);
typedef void(ExtractInitFn)(const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buffer,
@@ -211,6 +219,27 @@ typedef void(ExtractFinishFn)(const MeshRenderData *mr,
void *data);
typedef void(ExtractTaskReduceFn)(void *userdata, void *task_userdata);
+typedef void(ExtractInitSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *data);
+typedef void(ExtractIterSubdivBMeshFn)(const struct DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *data,
+ uint subdiv_quad_index,
+ const BMFace *coarse_quad);
+typedef void(ExtractIterSubdivMeshFn)(const struct DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_quad);
+typedef void(ExtractFinishSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *data);
+
typedef struct MeshExtract {
/** Executed on main thread and return user data for iteration functions. */
ExtractInitFn *init;
@@ -223,9 +252,15 @@ typedef struct MeshExtract {
ExtractLEdgeMeshFn *iter_ledge_mesh;
ExtractLVertBMeshFn *iter_lvert_bm;
ExtractLVertMeshFn *iter_lvert_mesh;
+ ExtractLooseGeomSubdivFn *iter_loose_geom_subdiv;
/** Executed on one worker thread after all elements iterations. */
ExtractTaskReduceFn *task_reduce;
ExtractFinishFn *finish;
+ /** Executed on main thread for subdivision evaluation. */
+ ExtractInitSubdivFn *init_subdiv;
+ ExtractIterSubdivBMeshFn *iter_subdiv_bm;
+ ExtractIterSubdivMeshFn *iter_subdiv_mesh;
+ ExtractFinishSubdivFn *finish_subdiv;
/** Used to request common data. */
eMRDataType data_type;
size_t data_size;
@@ -241,31 +276,42 @@ typedef struct MeshExtract {
/** \} */
/* draw_cache_extract_mesh_render_data.c */
-MeshRenderData *mesh_render_data_create(Mesh *me,
- const bool is_editmode,
- const bool is_paint_mode,
- const bool is_mode_active,
+
+/**
+ * \param is_mode_active: When true, use the modifiers from the edit-data,
+ * otherwise don't use modifiers as they are not from this object.
+ */
+MeshRenderData *mesh_render_data_create(Object *object,
+ Mesh *me,
+ bool is_editmode,
+ bool is_paint_mode,
+ bool is_mode_active,
const float obmat[4][4],
- const bool do_final,
- const bool do_uvedit,
+ bool do_final,
+ bool do_uvedit,
const ToolSettings *ts);
void mesh_render_data_free(MeshRenderData *mr);
-void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_flag);
+void mesh_render_data_update_normals(MeshRenderData *mr, eMRDataType data_flag);
void mesh_render_data_update_loose_geom(MeshRenderData *mr,
MeshBufferCache *cache,
- const eMRIterType iter_type,
- const eMRDataType data_flag);
+ eMRIterType iter_type,
+ eMRDataType data_flag);
void mesh_render_data_update_polys_sorted(MeshRenderData *mr,
MeshBufferCache *cache,
- const eMRDataType data_flag);
+ eMRDataType data_flag);
+/**
+ * Part of the creation of the #MeshRenderData that happens in a thread.
+ */
void mesh_render_data_update_looptris(MeshRenderData *mr,
- const eMRIterType iter_type,
- const eMRDataType data_flag);
+ eMRIterType iter_type,
+ eMRDataType data_flag);
/* draw_cache_extract_mesh_extractors.c */
typedef struct EditLoopData {
uchar v_flag;
uchar e_flag;
+ /* This is used for both vertex and edge creases. The edge crease value is stored in the bottom 4
+ * bits, while the vertex crease is stored in the upper 4 bits. */
uchar crease;
uchar bweight;
} EditLoopData;
@@ -273,19 +319,19 @@ typedef struct EditLoopData {
void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist);
eMRIterType mesh_extract_iter_type(const MeshExtract *ext);
const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor,
- const bool do_hq_normals,
- const bool do_single_mat);
+ bool do_hq_normals,
+ bool do_single_mat);
void mesh_render_data_face_flag(const MeshRenderData *mr,
const BMFace *efa,
- const int cd_ofs,
+ int cd_ofs,
EditLoopData *eattr);
void mesh_render_data_loop_flag(const MeshRenderData *mr,
BMLoop *l,
- const int cd_ofs,
+ int cd_ofs,
EditLoopData *eattr);
void mesh_render_data_loop_edge_flag(const MeshRenderData *mr,
BMLoop *l,
- const int cd_ofs,
+ int cd_ofs,
EditLoopData *eattr);
extern const MeshExtract extract_tris;
@@ -328,6 +374,7 @@ extern const MeshExtract extract_poly_idx;
extern const MeshExtract extract_edge_idx;
extern const MeshExtract extract_vert_idx;
extern const MeshExtract extract_fdot_idx;
+extern const MeshExtract extract_attr[GPU_MAX_ATTR];
#ifdef __cplusplus
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
index d06fb91411e..cd71beb1f02 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
@@ -27,6 +27,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Edit UV Triangles Indices
@@ -94,6 +96,79 @@ static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(&data->elb, ibo);
}
+static void extract_edituv_tris_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *tls_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
+ GPU_indexbuf_init(&data->elb,
+ GPU_PRIM_TRIS,
+ subdiv_cache->num_subdiv_triangles,
+ subdiv_cache->num_subdiv_loops);
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+}
+
+static void extract_edituv_tris_iter_subdiv_bm(const DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *UNUSED(mr),
+ void *_data,
+ uint subdiv_quad_index,
+ const BMFace *coarse_quad)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ const uint loop_idx = subdiv_quad_index * 4;
+
+ edituv_tri_add(data,
+ BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN) != 0,
+ BM_elem_flag_test(coarse_quad, BM_ELEM_SELECT) != 0,
+ loop_idx,
+ loop_idx + 1,
+ loop_idx + 2);
+
+ edituv_tri_add(data,
+ BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN) != 0,
+ BM_elem_flag_test(coarse_quad, BM_ELEM_SELECT) != 0,
+ loop_idx,
+ loop_idx + 2,
+ loop_idx + 3);
+}
+
+static void extract_edituv_tris_iter_subdiv_mesh(const DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *UNUSED(mr),
+ void *_data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_quad)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ const uint loop_idx = subdiv_quad_index * 4;
+
+ edituv_tri_add(data,
+ (coarse_quad->flag & ME_HIDE) != 0,
+ (coarse_quad->flag & ME_FACE_SEL) != 0,
+ loop_idx,
+ loop_idx + 1,
+ loop_idx + 2);
+
+ edituv_tri_add(data,
+ (coarse_quad->flag & ME_HIDE) != 0,
+ (coarse_quad->flag & ME_FACE_SEL) != 0,
+ loop_idx,
+ loop_idx + 2,
+ loop_idx + 3);
+}
+
+static void extract_edituv_tris_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+}
+
constexpr MeshExtract create_extractor_edituv_tris()
{
MeshExtract extractor = {nullptr};
@@ -101,6 +176,10 @@ constexpr MeshExtract create_extractor_edituv_tris()
extractor.iter_looptri_bm = extract_edituv_tris_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh;
extractor.finish = extract_edituv_tris_finish;
+ extractor.init_subdiv = extract_edituv_tris_init_subdiv;
+ extractor.iter_subdiv_bm = extract_edituv_tris_iter_subdiv_bm;
+ extractor.iter_subdiv_mesh = extract_edituv_tris_iter_subdiv_mesh;
+ extractor.finish_subdiv = extract_edituv_tris_finish_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
@@ -184,6 +263,77 @@ static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(&data->elb, ibo);
}
+static void extract_edituv_lines_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *tls_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
+ GPU_indexbuf_init(
+ &data->elb, GPU_PRIM_LINES, subdiv_cache->num_subdiv_loops, subdiv_cache->num_subdiv_loops);
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+}
+
+static void extract_edituv_lines_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const BMFace *coarse_poly)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index);
+
+ uint start_loop_idx = subdiv_quad_index * 4;
+ uint end_loop_idx = (subdiv_quad_index + 1) * 4;
+ for (uint loop_idx = start_loop_idx; loop_idx < end_loop_idx; loop_idx++) {
+ const int edge_origindex = subdiv_loop_edge_index[loop_idx];
+ const bool real_edge = (edge_origindex != -1 &&
+ (mr->e_origindex == nullptr ||
+ mr->e_origindex[edge_origindex] != ORIGINDEX_NONE));
+ edituv_edge_add(data,
+ BM_elem_flag_test_bool(coarse_poly, BM_ELEM_HIDDEN) != 0 || !real_edge,
+ BM_elem_flag_test_bool(coarse_poly, BM_ELEM_SELECT) != 0,
+ loop_idx,
+ (loop_idx + 1 == end_loop_idx) ? start_loop_idx : (loop_idx + 1));
+ }
+}
+
+static void extract_edituv_lines_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_poly)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index);
+
+ uint start_loop_idx = subdiv_quad_index * 4;
+ uint end_loop_idx = (subdiv_quad_index + 1) * 4;
+ for (uint loop_idx = start_loop_idx; loop_idx < end_loop_idx; loop_idx++) {
+ const int edge_origindex = subdiv_loop_edge_index[loop_idx];
+ const bool real_edge = (edge_origindex != -1 &&
+ (mr->e_origindex == nullptr ||
+ mr->e_origindex[edge_origindex] != ORIGINDEX_NONE));
+ edituv_edge_add(data,
+ (coarse_poly->flag & ME_HIDE) != 0 || !real_edge,
+ (coarse_poly->flag & ME_FACE_SEL) != 0,
+ loop_idx,
+ (loop_idx + 1 == end_loop_idx) ? start_loop_idx : (loop_idx + 1));
+ }
+}
+
+static void extract_edituv_lines_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+}
+
constexpr MeshExtract create_extractor_edituv_lines()
{
MeshExtract extractor = {nullptr};
@@ -191,6 +341,10 @@ constexpr MeshExtract create_extractor_edituv_lines()
extractor.iter_poly_bm = extract_edituv_lines_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_lines_iter_poly_mesh;
extractor.finish = extract_edituv_lines_finish;
+ extractor.init_subdiv = extract_edituv_lines_init_subdiv;
+ extractor.iter_subdiv_bm = extract_edituv_lines_iter_subdiv_bm;
+ extractor.iter_subdiv_mesh = extract_edituv_lines_iter_subdiv_mesh;
+ extractor.finish_subdiv = extract_edituv_lines_finish_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
@@ -268,6 +422,75 @@ static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(&data->elb, ibo);
}
+static void extract_edituv_points_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *tls_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
+ GPU_indexbuf_init(
+ &data->elb, GPU_PRIM_POINTS, subdiv_cache->num_subdiv_loops, subdiv_cache->num_subdiv_loops);
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+}
+
+static void extract_edituv_points_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const BMFace *coarse_quad)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index);
+
+ uint start_loop_idx = subdiv_quad_index * 4;
+ uint end_loop_idx = (subdiv_quad_index + 1) * 4;
+ for (uint i = start_loop_idx; i < end_loop_idx; i++) {
+ const int vert_origindex = subdiv_loop_vert_index[i];
+ const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
+ vert_origindex != -1 &&
+ mr->v_origindex[vert_origindex] != ORIGINDEX_NONE);
+ edituv_point_add(data,
+ (BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN)) || !real_vert,
+ BM_elem_flag_test(coarse_quad, BM_ELEM_SELECT) != 0,
+ i);
+ }
+}
+
+static void extract_edituv_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_quad)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index);
+
+ uint start_loop_idx = subdiv_quad_index * 4;
+ uint end_loop_idx = (subdiv_quad_index + 1) * 4;
+ for (uint i = start_loop_idx; i < end_loop_idx; i++) {
+ const int vert_origindex = subdiv_loop_vert_index[i];
+ const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
+ vert_origindex != -1 &&
+ mr->v_origindex[vert_origindex] != ORIGINDEX_NONE);
+ edituv_point_add(data,
+ ((coarse_quad->flag & ME_HIDE) != 0) || !real_vert,
+ (coarse_quad->flag & ME_FACE_SEL) != 0,
+ i);
+ }
+}
+
+static void extract_edituv_points_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+}
+
constexpr MeshExtract create_extractor_edituv_points()
{
MeshExtract extractor = {nullptr};
@@ -275,6 +498,10 @@ constexpr MeshExtract create_extractor_edituv_points()
extractor.iter_poly_bm = extract_edituv_points_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_points_iter_poly_mesh;
extractor.finish = extract_edituv_points_finish;
+ extractor.init_subdiv = extract_edituv_points_init_subdiv;
+ extractor.iter_subdiv_bm = extract_edituv_points_iter_subdiv_bm;
+ extractor.iter_subdiv_mesh = extract_edituv_points_iter_subdiv_mesh;
+ extractor.finish_subdiv = extract_edituv_points_finish_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
@@ -388,5 +615,3 @@ const MeshExtract extract_edituv_lines = blender::draw::create_extractor_edituv_
const MeshExtract extract_edituv_points = blender::draw::create_extractor_edituv_points();
const MeshExtract extract_edituv_fdots = blender::draw::create_extractor_edituv_fdots();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
index ea58e1aeed8..2e8b85250f3 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
@@ -110,10 +110,9 @@ constexpr MeshExtract create_extractor_fdots()
}
/** \} */
+
} // namespace blender::draw
extern "C" {
const MeshExtract extract_fdots = blender::draw::create_extractor_fdots();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
index 54f5611106f..3d9729dea56 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
@@ -25,6 +25,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -155,6 +157,33 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(elb, ibo);
}
+static void extract_lines_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
+ GPU_indexbuf_init_build_on_device(ibo,
+ subdiv_cache->num_subdiv_loops * 2 + mr->edge_loose_len * 2);
+
+ draw_subdiv_build_lines_buffer(subdiv_cache, ibo);
+}
+
+static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ if (loose_geom->edge_len == 0) {
+ return;
+ }
+
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
+ draw_subdiv_build_lines_loose_buffer(subdiv_cache, ibo, static_cast<uint>(loose_geom->edge_len));
+}
+
constexpr MeshExtract create_extractor_lines()
{
MeshExtract extractor = {nullptr};
@@ -163,6 +192,8 @@ constexpr MeshExtract create_extractor_lines()
extractor.iter_poly_mesh = extract_lines_iter_poly_mesh;
extractor.iter_ledge_bm = extract_lines_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_lines_iter_ledge_mesh;
+ extractor.init_subdiv = extract_lines_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_lines_loose_geom_subdiv;
extractor.task_reduce = extract_lines_task_reduce;
extractor.finish = extract_lines_finish;
extractor.data_type = MR_DATA_NONE;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
index 522afcd44a1..2b01b6801c2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
@@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -44,6 +45,18 @@ struct MeshExtract_LineAdjacency_Data {
uint *vert_to_loop;
};
+static void line_adjacency_data_init(MeshExtract_LineAdjacency_Data *data,
+ uint vert_len,
+ uint loop_len,
+ uint tess_edge_len)
+{
+ data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * vert_len, __func__));
+
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, loop_len);
+ data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len);
+ data->is_manifold = true;
+}
+
static void extract_lines_adjacency_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
@@ -55,11 +68,7 @@ static void extract_lines_adjacency_init(const MeshRenderData *mr,
uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len;
MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(tls_data);
- data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * mr->vert_len, __func__));
-
- GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, mr->loop_len);
- data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len);
- data->is_manifold = true;
+ line_adjacency_data_init(data, mr->vert_len, mr->loop_len, tess_edge_len);
}
BLI_INLINE void lines_adjacency_triangle(
@@ -171,9 +180,72 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
MEM_freeN(data->vert_to_loop);
}
-#undef NO_EDGE
+static void extract_lines_adjacency_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *_data)
+{
+ MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data);
-/** \} */
+ /* For each polygon there is (loop + triangle - 1) edges. Since we only have quads, and a quad
+ * is split into 2 triangles, we have (loop + 2 - 1) = (loop + 1) edges for each quad, or in
+ * total: (number_of_loops + number_of_quads). */
+ const uint tess_len = subdiv_cache->num_subdiv_loops + subdiv_cache->num_subdiv_quads;
+ line_adjacency_data_init(
+ data, subdiv_cache->num_subdiv_verts, subdiv_cache->num_subdiv_loops, tess_len);
+}
+
+static void extract_lines_adjacency_iter_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ void *_data,
+ uint subdiv_quad_index)
+{
+ MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data);
+
+ const uint loop_index = subdiv_quad_index * 4;
+ const uint l0 = loop_index + 0;
+ const uint l1 = loop_index + 1;
+ const uint l2 = loop_index + 2;
+ const uint l3 = loop_index + 3;
+
+ const uint v0 = subdiv_cache->subdiv_loop_subdiv_vert_index[l0];
+ const uint v1 = subdiv_cache->subdiv_loop_subdiv_vert_index[l1];
+ const uint v2 = subdiv_cache->subdiv_loop_subdiv_vert_index[l2];
+ const uint v3 = subdiv_cache->subdiv_loop_subdiv_vert_index[l3];
+
+ lines_adjacency_triangle(v0, v1, v2, l0, l1, l2, data);
+ lines_adjacency_triangle(v0, v2, v3, l0, l2, l3, data);
+}
+
+static void extract_lines_adjacency_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const BMFace *UNUSED(coarse_quad))
+{
+ extract_lines_adjacency_iter_subdiv(subdiv_cache, mr, _data, subdiv_quad_index);
+}
+
+static void extract_lines_adjacency_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const MPoly *UNUSED(coarse_quad))
+{
+ extract_lines_adjacency_iter_subdiv(subdiv_cache, mr, _data, subdiv_quad_index);
+}
+
+static void extract_lines_adjacency_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *_data)
+{
+ extract_lines_adjacency_finish(mr, cache, buf, _data);
+}
+
+#undef NO_EDGE
constexpr MeshExtract create_extractor_lines_adjacency()
{
@@ -182,6 +254,10 @@ constexpr MeshExtract create_extractor_lines_adjacency()
extractor.iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh;
extractor.finish = extract_lines_adjacency_finish;
+ extractor.init_subdiv = extract_lines_adjacency_init_subdiv;
+ extractor.iter_subdiv_bm = extract_lines_adjacency_iter_subdiv_bm;
+ extractor.iter_subdiv_mesh = extract_lines_adjacency_iter_subdiv_mesh;
+ extractor.finish_subdiv = extract_lines_adjacency_finish_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_LineAdjacency_Data);
extractor.use_threading = false;
@@ -189,10 +265,10 @@ constexpr MeshExtract create_extractor_lines_adjacency()
return extractor;
}
+/** \} */
+
} // namespace blender::draw
extern "C" {
const MeshExtract extract_lines_adjacency = blender::draw::create_extractor_lines_adjacency();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
index 494a43e97d1..f7eb5022cdc 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
@@ -103,8 +103,6 @@ static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr),
MEM_freeN(data->select_map);
}
-/** \} */
-
constexpr MeshExtract create_extractor_lines_paint_mask()
{
MeshExtract extractor = {nullptr};
@@ -118,10 +116,10 @@ constexpr MeshExtract create_extractor_lines_paint_mask()
return extractor;
}
+/** \} */
+
} // namespace blender::draw
extern "C" {
const MeshExtract extract_lines_paint_mask = blender::draw::create_extractor_lines_paint_mask();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
index b801ba04162..c3f89ab96ee 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
@@ -25,6 +25,7 @@
#include "MEM_guardedalloc.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -32,6 +33,7 @@ namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Point Indices
* \{ */
+
static void extract_points_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
@@ -154,6 +156,69 @@ static void extract_points_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(elb, ibo);
}
+static void extract_points_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buffer),
+ void *data)
+{
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data);
+ /* Copy the points as the data upload will free them. */
+ elb->data = (uint *)MEM_dupallocN(subdiv_cache->point_indices);
+ elb->index_len = mr->vert_len;
+ elb->index_min = 0;
+ elb->index_max = subdiv_cache->num_subdiv_loops + mr->loop_loose_len;
+ elb->prim_type = GPU_PRIM_POINTS;
+}
+
+static void extract_points_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *UNUSED(buffer),
+ void *data)
+{
+ const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
+ if (loop_loose_len == 0) {
+ return;
+ }
+
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data);
+
+ const Mesh *coarse_mesh = subdiv_cache->mesh;
+ const MEdge *coarse_edges = coarse_mesh->medge;
+
+ uint offset = subdiv_cache->num_subdiv_loops;
+
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
+ if (elb->data[loose_edge->v1] == -1u) {
+ GPU_indexbuf_set_point_vert(elb, loose_edge->v1, offset);
+ }
+ if (elb->data[loose_edge->v2] == -1u) {
+ GPU_indexbuf_set_point_vert(elb, loose_edge->v2, offset + 1);
+ }
+ offset += 2;
+ }
+
+ for (int i = 0; i < loose_geom->vert_len; i++) {
+ if (elb->data[loose_geom->verts[i]] == -1u) {
+ GPU_indexbuf_set_point_vert(elb, loose_geom->verts[i], offset);
+ }
+ offset += 1;
+ }
+}
+
+static void extract_points_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *_userdata)
+{
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
+ GPU_indexbuf_build_in_place(elb, ibo);
+}
+
constexpr MeshExtract create_extractor_points()
{
MeshExtract extractor = {nullptr};
@@ -166,6 +231,9 @@ constexpr MeshExtract create_extractor_points()
extractor.iter_lvert_mesh = extract_points_iter_lvert_mesh;
extractor.task_reduce = extract_points_task_reduce;
extractor.finish = extract_points_finish;
+ extractor.init_subdiv = extract_points_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_points_loose_geom_subdiv;
+ extractor.finish_subdiv = extract_points_finish_subdiv;
extractor.use_threading = true;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(GPUIndexBufBuilder);
@@ -173,10 +241,10 @@ constexpr MeshExtract create_extractor_points()
return extractor;
}
+/** \} */
+
} // namespace blender::draw
extern "C" {
const MeshExtract extract_points = blender::draw::create_extractor_points();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
index 54e733d3d86..b1ace8bc6c9 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
@@ -25,6 +25,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
static void extract_tris_mat_task_reduce(void *_userdata_to, void *_userdata_from)
@@ -123,10 +125,37 @@ static void extract_tris_finish(const MeshRenderData *mr,
}
}
+static void extract_tris_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
+ /* Initialize the index buffer, it was already allocated, it will be filled on the device. */
+ GPU_indexbuf_init_build_on_device(ibo, subdiv_cache->num_subdiv_triangles * 3);
+
+ if (cache->tris_per_mat) {
+ for (int i = 0; i < cache->mat_len; i++) {
+ if (cache->tris_per_mat[i] == nullptr) {
+ cache->tris_per_mat[i] = GPU_indexbuf_calloc();
+ }
+
+ /* Multiply by 6 since we have 2 triangles per quad. */
+ const int start = subdiv_cache->mat_start[i] * 6;
+ const int len = (subdiv_cache->mat_end[i] - subdiv_cache->mat_start[i]) * 6;
+ GPU_indexbuf_create_subrange_in_place(cache->tris_per_mat[i], ibo, start, len);
+ }
+ }
+
+ draw_subdiv_build_tris_buffer(subdiv_cache, ibo, cache->mat_len);
+}
+
constexpr MeshExtract create_extractor_tris()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_tris_init;
+ extractor.init_subdiv = extract_tris_init_subdiv;
extractor.iter_poly_bm = extract_tris_iter_poly_bm;
extractor.iter_poly_mesh = extract_tris_iter_poly_mesh;
extractor.task_reduce = extract_tris_mat_task_reduce;
@@ -214,6 +243,7 @@ constexpr MeshExtract create_extractor_tris_single_mat()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_tris_single_mat_init;
+ extractor.init_subdiv = extract_tris_init_subdiv;
extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_tris_single_mat_iter_looptri_mesh;
extractor.task_reduce = extract_tris_mat_task_reduce;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
new file mode 100644
index 00000000000..b846da3f016
--- /dev/null
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
@@ -0,0 +1,489 @@
+/*
+ * 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) 2021 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include <functional>
+
+#include "BLI_math_vec_types.hh"
+#include "BLI_string.h"
+
+#include "BKE_attribute.h"
+
+#include "draw_subdivision.h"
+#include "extract_mesh.h"
+
+namespace blender::draw {
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Attributes
+ * \{ */
+
+static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, AttributeDomain domain)
+{
+ switch (domain) {
+ default: {
+ return nullptr;
+ }
+ case ATTR_DOMAIN_POINT: {
+ return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
+ }
+ case ATTR_DOMAIN_FACE: {
+ return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->edata : &mr->me->edata;
+ }
+ }
+}
+
+/* Utility to convert from the type used in the attributes to the types for the VBO.
+ * This is mostly used to promote integers and booleans to floats, as other types (float, float2,
+ * etc.) directly map to available GPU types. Booleans are still converted as attributes are vec4
+ * in the shader.
+ */
+template<typename AttributeType, typename VBOType> struct attribute_type_converter {
+ static VBOType convert_value(AttributeType value)
+ {
+ if constexpr (std::is_same_v<AttributeType, VBOType>) {
+ return value;
+ }
+
+ /* This should only concern bools which are converted to floats. */
+ return static_cast<VBOType>(value);
+ }
+};
+
+/* Similar to the one in #extract_mesh_vcol_vbo.cc */
+struct gpuMeshCol {
+ ushort r, g, b, a;
+};
+
+template<> struct attribute_type_converter<MPropCol, gpuMeshCol> {
+ static gpuMeshCol convert_value(MPropCol value)
+ {
+ gpuMeshCol result;
+ result.r = unit_float_to_ushort_clamp(value.color[0]);
+ result.g = unit_float_to_ushort_clamp(value.color[1]);
+ result.b = unit_float_to_ushort_clamp(value.color[2]);
+ result.a = unit_float_to_ushort_clamp(value.color[3]);
+ return result;
+ }
+};
+
+/* Return the number of component for the attribute's value type, or 0 if is it unsupported. */
+static uint gpu_component_size_for_attribute_type(CustomDataType type)
+{
+ switch (type) {
+ case CD_PROP_BOOL:
+ case CD_PROP_INT32:
+ case CD_PROP_FLOAT: {
+ /* TODO(kevindietrich) : should be 1 when scalar attributes conversion is handled by us. See
+ * comment #extract_attr_init. */
+ return 3;
+ }
+ case CD_PROP_FLOAT2: {
+ return 2;
+ }
+ case CD_PROP_FLOAT3: {
+ return 3;
+ }
+ case CD_PROP_COLOR: {
+ return 4;
+ }
+ default: {
+ return 0;
+ }
+ }
+}
+
+static GPUVertFetchMode get_fetch_mode_for_type(CustomDataType type)
+{
+ switch (type) {
+ case CD_PROP_INT32: {
+ return GPU_FETCH_INT_TO_FLOAT;
+ }
+ case CD_PROP_COLOR: {
+ return GPU_FETCH_INT_TO_FLOAT_UNIT;
+ }
+ default: {
+ return GPU_FETCH_FLOAT;
+ }
+ }
+}
+
+static GPUVertCompType get_comp_type_for_type(CustomDataType type)
+{
+ switch (type) {
+ case CD_PROP_INT32: {
+ return GPU_COMP_I32;
+ }
+ case CD_PROP_COLOR: {
+ return GPU_COMP_U16;
+ }
+ default: {
+ return GPU_COMP_F32;
+ }
+ }
+}
+
+static void init_vbo_for_attribute(const MeshRenderData *mr,
+ GPUVertBuf *vbo,
+ const DRW_AttributeRequest &request,
+ bool build_on_device,
+ uint32_t len)
+{
+ GPUVertCompType comp_type = get_comp_type_for_type(request.cd_type);
+ GPUVertFetchMode fetch_mode = get_fetch_mode_for_type(request.cd_type);
+ const uint comp_size = gpu_component_size_for_attribute_type(request.cd_type);
+ /* We should not be here if the attribute type is not supported. */
+ BLI_assert(comp_size != 0);
+
+ const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain);
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
+ const char *layer_name = CustomData_get_layer_name(
+ custom_data, request.cd_type, request.layer_index);
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
+ /* Attributes use auto-name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
+
+ GPUVertFormat format = {0};
+ GPU_vertformat_deinterleave(&format);
+ GPU_vertformat_attr_add(&format, attr_name, comp_type, comp_size, fetch_mode);
+
+ /* Ensure Sculpt Vertex Colors are properly aliased. */
+ if (request.cd_type == CD_PROP_COLOR && request.domain == ATTR_DOMAIN_POINT) {
+ CustomData *cd_vdata = get_custom_data_for_domain(mr, ATTR_DOMAIN_POINT);
+ if (request.layer_index == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) {
+ GPU_vertformat_alias_add(&format, "c");
+ }
+ if (request.layer_index == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) {
+ GPU_vertformat_alias_add(&format, "ac");
+ }
+ }
+
+ if (build_on_device) {
+ GPU_vertbuf_init_build_on_device(vbo, &format, len);
+ }
+ else {
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, len);
+ }
+}
+
+template<typename AttributeType, typename VBOType>
+static void fill_vertbuf_with_attribute(const MeshRenderData *mr,
+ VBOType *vbo_data,
+ const DRW_AttributeRequest &request)
+{
+ const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain);
+ BLI_assert(custom_data);
+ const int layer_index = request.layer_index;
+
+ const MPoly *mpoly = mr->mpoly;
+ const MLoop *mloop = mr->mloop;
+
+ const AttributeType *attr_data = static_cast<AttributeType *>(
+ CustomData_get_layer_n(custom_data, request.cd_type, layer_index));
+
+ using converter = attribute_type_converter<AttributeType, VBOType>;
+
+ switch (request.domain) {
+ default: {
+ BLI_assert(false);
+ break;
+ }
+ case ATTR_DOMAIN_POINT: {
+ for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) {
+ *vbo_data = converter::convert_value(attr_data[mloop->v]);
+ }
+ break;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++) {
+ *vbo_data = converter::convert_value(attr_data[ml_index]);
+ }
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) {
+ *vbo_data = converter::convert_value(attr_data[mloop->e]);
+ }
+ break;
+ }
+ case ATTR_DOMAIN_FACE: {
+ for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) {
+ const MPoly &poly = mpoly[mp_index];
+ const VBOType value = converter::convert_value(attr_data[mp_index]);
+ for (int l = 0; l < poly.totloop; l++) {
+ *vbo_data++ = value;
+ }
+ }
+ break;
+ }
+ }
+}
+
+template<typename AttributeType, typename VBOType>
+static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr,
+ VBOType *&vbo_data,
+ const DRW_AttributeRequest &request)
+{
+ const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain);
+ BLI_assert(custom_data);
+ const int layer_index = request.layer_index;
+
+ int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index);
+
+ using converter = attribute_type_converter<AttributeType, VBOType>;
+
+ BMIter f_iter;
+ BMFace *efa;
+ BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ const AttributeType *attr_data = nullptr;
+ if (request.domain == ATTR_DOMAIN_POINT) {
+ attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs));
+ }
+ else if (request.domain == ATTR_DOMAIN_CORNER) {
+ attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs));
+ }
+ else if (request.domain == ATTR_DOMAIN_FACE) {
+ attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(efa, cd_ofs));
+ }
+ else if (request.domain == ATTR_DOMAIN_EDGE) {
+ attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->e, cd_ofs));
+ }
+ else {
+ BLI_assert(false);
+ continue;
+ }
+ *vbo_data = converter::convert_value(*attr_data);
+ vbo_data++;
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+}
+
+template<typename AttributeType, typename VBOType = AttributeType>
+static void extract_attr_generic(const MeshRenderData *mr,
+ GPUVertBuf *vbo,
+ const DRW_AttributeRequest &request)
+{
+ VBOType *vbo_data = static_cast<VBOType *>(GPU_vertbuf_get_data(vbo));
+
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ fill_vertbuf_with_attribute_bm<AttributeType>(mr, vbo_data, request);
+ }
+ else {
+ fill_vertbuf_with_attribute<AttributeType>(mr, vbo_data, request);
+ }
+}
+
+static void extract_attr_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(tls_data),
+ int index)
+{
+ const DRW_MeshAttributes *attrs_used = &cache->attr_used;
+ const DRW_AttributeRequest &request = attrs_used->requests[index];
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+
+ init_vbo_for_attribute(mr, vbo, request, false, static_cast<uint32_t>(mr->loop_len));
+
+ /* TODO(kevindietrich) : float3 is used for scalar attributes as the implicit conversion done by
+ * OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following the
+ * Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a similar
+ * texture as for volume attribute, so we can control the conversion ourselves. */
+ switch (request.cd_type) {
+ case CD_PROP_BOOL: {
+ extract_attr_generic<bool, float3>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_INT32: {
+ extract_attr_generic<int32_t, float3>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_FLOAT: {
+ extract_attr_generic<float, float3>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_FLOAT2: {
+ extract_attr_generic<float2>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_FLOAT3: {
+ extract_attr_generic<float3>(mr, vbo, request);
+ break;
+ }
+ case CD_PROP_COLOR: {
+ extract_attr_generic<MPropCol, gpuMeshCol>(mr, vbo, request);
+ break;
+ }
+ default: {
+ BLI_assert(false);
+ }
+ }
+}
+
+static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(tls_data),
+ int index)
+{
+ const DRW_MeshAttributes *attrs_used = &cache->attr_used;
+ const DRW_AttributeRequest &request = attrs_used->requests[index];
+
+ Mesh *coarse_mesh = subdiv_cache->mesh;
+
+ const uint32_t dimensions = gpu_component_size_for_attribute_type(request.cd_type);
+
+ /* Prepare VBO for coarse data. The compute shader only expects floats. */
+ GPUVertBuf *src_data = GPU_vertbuf_calloc();
+ static GPUVertFormat coarse_format = {0};
+ GPU_vertformat_attr_add(&coarse_format, "data", GPU_COMP_F32, dimensions, GPU_FETCH_FLOAT);
+ GPU_vertbuf_init_with_format_ex(src_data, &coarse_format, GPU_USAGE_STATIC);
+ GPU_vertbuf_data_alloc(src_data, static_cast<uint32_t>(coarse_mesh->totloop));
+
+ switch (request.cd_type) {
+ case CD_PROP_BOOL: {
+ extract_attr_generic<bool, float3>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_INT32: {
+ extract_attr_generic<int32_t, float3>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_FLOAT: {
+ extract_attr_generic<float, float3>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_FLOAT2: {
+ extract_attr_generic<float2>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_FLOAT3: {
+ extract_attr_generic<float3>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_COLOR: {
+ extract_attr_generic<MPropCol, gpuMeshCol>(mr, src_data, request);
+ break;
+ }
+ default: {
+ BLI_assert(false);
+ }
+ }
+
+ GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
+ init_vbo_for_attribute(mr, dst_buffer, request, true, subdiv_cache->num_subdiv_loops);
+
+ /* Ensure data is uploaded properly. */
+ GPU_vertbuf_tag_dirty(src_data);
+ draw_subdiv_interp_custom_data(
+ subdiv_cache, src_data, dst_buffer, static_cast<int>(dimensions), 0);
+
+ GPU_vertbuf_discard(src_data);
+}
+
+/* Wrappers around extract_attr_init so we can pass the index of the attribute that we want to
+ * extract. The overall API does not allow us to pass this in a convenient way. */
+#define EXTRACT_INIT_WRAPPER(index) \
+ static void extract_attr_init##index( \
+ const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf, void *tls_data) \
+ { \
+ extract_attr_init(mr, cache, buf, tls_data, index); \
+ } \
+ static void extract_attr_init_subdiv##index(const DRWSubdivCache *subdiv_cache, \
+ const MeshRenderData *mr, \
+ struct MeshBatchCache *cache, \
+ void *buf, \
+ void *tls_data) \
+ { \
+ extract_attr_init_subdiv(subdiv_cache, mr, cache, buf, tls_data, index); \
+ }
+
+EXTRACT_INIT_WRAPPER(0)
+EXTRACT_INIT_WRAPPER(1)
+EXTRACT_INIT_WRAPPER(2)
+EXTRACT_INIT_WRAPPER(3)
+EXTRACT_INIT_WRAPPER(4)
+EXTRACT_INIT_WRAPPER(5)
+EXTRACT_INIT_WRAPPER(6)
+EXTRACT_INIT_WRAPPER(7)
+EXTRACT_INIT_WRAPPER(8)
+EXTRACT_INIT_WRAPPER(9)
+EXTRACT_INIT_WRAPPER(10)
+EXTRACT_INIT_WRAPPER(11)
+EXTRACT_INIT_WRAPPER(12)
+EXTRACT_INIT_WRAPPER(13)
+EXTRACT_INIT_WRAPPER(14)
+
+template<int index>
+constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivFn subdiv_fn)
+{
+ MeshExtract extractor = {nullptr};
+ extractor.init = fn;
+ extractor.init_subdiv = subdiv_fn;
+ extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = 0;
+ extractor.use_threading = false;
+ extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[index]);
+ return extractor;
+}
+
+/** \} */
+
+} // namespace blender::draw
+
+extern "C" {
+#define CREATE_EXTRACTOR_ATTR(index) \
+ blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index, \
+ blender::draw::extract_attr_init_subdiv##index)
+
+const MeshExtract extract_attr[GPU_MAX_ATTR] = {
+ CREATE_EXTRACTOR_ATTR(0),
+ CREATE_EXTRACTOR_ATTR(1),
+ CREATE_EXTRACTOR_ATTR(2),
+ CREATE_EXTRACTOR_ATTR(3),
+ CREATE_EXTRACTOR_ATTR(4),
+ CREATE_EXTRACTOR_ATTR(5),
+ CREATE_EXTRACTOR_ATTR(6),
+ CREATE_EXTRACTOR_ATTR(7),
+ CREATE_EXTRACTOR_ATTR(8),
+ CREATE_EXTRACTOR_ATTR(9),
+ CREATE_EXTRACTOR_ATTR(10),
+ CREATE_EXTRACTOR_ATTR(11),
+ CREATE_EXTRACTOR_ATTR(12),
+ CREATE_EXTRACTOR_ATTR(13),
+ CREATE_EXTRACTOR_ATTR(14),
+};
+}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
index 2e2444a8e3d..8470a71059f 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
@@ -25,6 +25,7 @@
#include "GPU_capabilities.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -148,9 +149,8 @@ static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr,
const MLoop *ml_next = &mr->mloop[ml_index_other];
const MVert *v1 = &mr->mvert[ml->v];
const MVert *v2 = &mr->mvert[ml_next->v];
- float vnor_f[3];
- normal_short_to_float_v3(vnor_f, v1->no);
- float ratio = loop_edge_factor_get(mr->poly_normals[mp_index], v1->co, vnor_f, v2->co);
+ float ratio = loop_edge_factor_get(
+ mr->poly_normals[mp_index], v1->co, mr->vert_normals[ml->v], v2->co);
data->vbo_data[ml_index] = ratio * 253 + 1;
}
else {
@@ -216,6 +216,86 @@ static void extract_edge_fac_finish(const MeshRenderData *mr,
MEM_SAFE_FREE(data->edge_loop_count);
}
+/* Different function than the one used for the non-subdivision case, as we directly take care of
+ * the buggy AMD driver case. */
+static GPUVertFormat *get_subdiv_edge_fac_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ if (GPU_crappy_amd_driver()) {
+ GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+ else {
+ GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+ }
+ return &format;
+}
+
+static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *edge_idx = cache->final.buff.vbo.edge_idx;
+ GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ GPU_vertbuf_init_build_on_device(
+ vbo, get_subdiv_edge_fac_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
+
+ /* Create a temporary buffer for the edge original indices if it was not requested. */
+ const bool has_edge_idx = edge_idx != nullptr;
+ GPUVertBuf *loop_edge_idx = nullptr;
+ if (has_edge_idx) {
+ loop_edge_idx = edge_idx;
+ }
+ else {
+ loop_edge_idx = GPU_vertbuf_calloc();
+ draw_subdiv_init_origindex_buffer(
+ loop_edge_idx,
+ static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)),
+ subdiv_cache->num_subdiv_loops,
+ 0);
+ }
+
+ draw_subdiv_build_edge_fac_buffer(subdiv_cache, pos_nor, loop_edge_idx, vbo);
+
+ if (!has_edge_idx) {
+ GPU_vertbuf_discard(loop_edge_idx);
+ }
+}
+
+static void extract_edge_fac_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ if (loose_geom->edge_len == 0) {
+ return;
+ }
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+
+ /* Make sure buffer is active for sending loose data. */
+ GPU_vertbuf_use(vbo);
+
+ uint offset = subdiv_cache->num_subdiv_loops;
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ if (GPU_crappy_amd_driver()) {
+ float loose_edge_fac[2] = {1.0f, 1.0f};
+ GPU_vertbuf_update_sub(vbo, offset * sizeof(float), sizeof(loose_edge_fac), loose_edge_fac);
+ }
+ else {
+ char loose_edge_fac[2] = {255, 255};
+ GPU_vertbuf_update_sub(vbo, offset * sizeof(char), sizeof(loose_edge_fac), loose_edge_fac);
+ }
+
+ offset += 2;
+ }
+}
+
constexpr MeshExtract create_extractor_edge_fac()
{
MeshExtract extractor = {nullptr};
@@ -224,6 +304,8 @@ constexpr MeshExtract create_extractor_edge_fac()
extractor.iter_poly_mesh = extract_edge_fac_iter_poly_mesh;
extractor.iter_ledge_bm = extract_edge_fac_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh;
+ extractor.init_subdiv = extract_edge_fac_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_edge_fac_loose_geom_subdiv;
extractor.finish = extract_edge_fac_finish;
extractor.data_type = MR_DATA_POLY_NOR;
extractor.data_size = sizeof(MeshExtract_EdgeFac_Data);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
index 5232346e51e..0002b95c867 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
@@ -25,6 +25,8 @@
#include "draw_cache_impl.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -70,11 +72,11 @@ static void mesh_render_data_edge_flag(const MeshRenderData *mr,
}
}
- /* Use a byte for value range */
- if (mr->crease_ofs != -1) {
- float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->crease_ofs);
+ /* Use half a byte for value range */
+ if (mr->edge_crease_ofs != -1) {
+ float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->edge_crease_ofs);
if (crease > 0) {
- eattr->crease = (uchar)(crease * 255.0f);
+ eattr->crease = (uchar)ceil(crease * 15.0f);
}
}
/* Use a byte for value range */
@@ -105,21 +107,34 @@ static void mesh_render_data_vert_flag(const MeshRenderData *mr,
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
eattr->e_flag |= VFLAG_VERT_SELECTED;
}
+ /* Use half a byte for value range */
+ if (mr->vert_crease_ofs != -1) {
+ float crease = BM_ELEM_CD_GET_FLOAT(eve, mr->vert_crease_ofs);
+ if (crease > 0) {
+ eattr->crease |= (uchar)ceil(crease * 15.0f) << 4;
+ }
+ }
}
-static void extract_edit_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf,
- void *tls_data)
+static GPUVertFormat *get_edit_data_format()
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* WARNING: Adjust #EditLoopData struct accordingly. */
GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
GPU_vertformat_alias_add(&format, "flag");
}
- GPU_vertbuf_init_with_format(vbo, &format);
+ return &format;
+}
+
+static void extract_edit_data_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPUVertFormat *format = get_edit_data_format();
+ GPU_vertbuf_init_with_format(vbo, format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
*(EditLoopData **)tls_data = vbo_data;
@@ -240,6 +255,92 @@ static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr,
}
}
+static void extract_edit_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPU_vertbuf_init_with_format(vbo, get_edit_data_format());
+ GPU_vertbuf_data_alloc(vbo, subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
+ EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
+ *(EditLoopData **)data = vbo_data;
+}
+
+static void extract_edit_data_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const BMFace *coarse_quad)
+{
+ EditLoopData *vbo_data = *(EditLoopData **)_data;
+ int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index);
+ int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index);
+
+ uint start_loop_idx = subdiv_quad_index * 4;
+ uint end_loop_idx = (subdiv_quad_index + 1) * 4;
+ for (uint i = start_loop_idx; i < end_loop_idx; i++) {
+ const int vert_origindex = subdiv_loop_vert_index[i];
+ const int edge_origindex = subdiv_loop_edge_index[i];
+
+ EditLoopData *edit_loop_data = &vbo_data[i];
+ memset(edit_loop_data, 0, sizeof(EditLoopData));
+
+ if (vert_origindex != -1) {
+ const BMVert *eve = bm_original_vert_get(mr, vert_origindex);
+ if (eve) {
+ mesh_render_data_vert_flag(mr, eve, edit_loop_data);
+ }
+ }
+
+ if (edge_origindex != -1) {
+ const BMEdge *eed = bm_original_edge_get(mr, edge_origindex);
+ if (eed) {
+ mesh_render_data_edge_flag(mr, eed, edit_loop_data);
+ }
+ }
+
+ /* The -1 parameter is for edit_uvs, which we don't do here. */
+ mesh_render_data_face_flag(mr, coarse_quad, -1, edit_loop_data);
+ }
+}
+
+static void extract_edit_data_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_quad)
+{
+ const int coarse_quad_index = static_cast<int>(coarse_quad - mr->mpoly);
+ BMFace *coarse_quad_bm = bm_original_face_get(mr, coarse_quad_index);
+ extract_edit_data_iter_subdiv_bm(subdiv_cache, mr, _data, subdiv_quad_index, coarse_quad_bm);
+}
+
+static void extract_edit_data_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ const MeshExtractLooseGeom *loose_geom,
+ void *UNUSED(buffer),
+ void *_data)
+{
+ if (loose_geom->edge_len == 0) {
+ return;
+ }
+
+ EditLoopData *vbo_data = *(EditLoopData **)_data;
+
+ for (int ledge_index = 0; ledge_index < loose_geom->edge_len; ledge_index++) {
+ const int offset = subdiv_cache->num_subdiv_loops + ledge_index * 2;
+ EditLoopData *data = &vbo_data[offset];
+ memset(data, 0, sizeof(EditLoopData));
+ BMEdge *eed = bm_original_edge_get(mr, loose_geom->edges[ledge_index]);
+ mesh_render_data_edge_flag(mr, eed, &data[0]);
+ data[1] = data[0];
+ mesh_render_data_vert_flag(mr, eed->v1, &data[0]);
+ mesh_render_data_vert_flag(mr, eed->v2, &data[1]);
+ }
+}
+
constexpr MeshExtract create_extractor_edit_data()
{
MeshExtract extractor = {nullptr};
@@ -250,6 +351,10 @@ constexpr MeshExtract create_extractor_edit_data()
extractor.iter_ledge_mesh = extract_edit_data_iter_ledge_mesh;
extractor.iter_lvert_bm = extract_edit_data_iter_lvert_bm;
extractor.iter_lvert_mesh = extract_edit_data_iter_lvert_mesh;
+ extractor.init_subdiv = extract_edit_data_init_subdiv;
+ extractor.iter_subdiv_bm = extract_edit_data_iter_subdiv_bm;
+ extractor.iter_subdiv_mesh = extract_edit_data_iter_subdiv_mesh;
+ extractor.iter_loose_geom_subdiv = extract_edit_data_loose_geom_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(EditLoopData *);
extractor.use_threading = true;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
index b8494428eed..b25e40690c9 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
@@ -25,6 +25,8 @@
#include "draw_cache_impl.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -36,12 +38,11 @@ struct MeshExtract_EditUVData_Data {
int cd_ofs;
};
-static void extract_edituv_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf,
- void *tls_data)
+static void extract_edituv_data_init_common(const MeshRenderData *mr,
+ GPUVertBuf *vbo,
+ MeshExtract_EditUVData_Data *data,
+ uint loop_len)
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* WARNING: Adjust #EditLoopData struct accordingly. */
@@ -50,15 +51,23 @@ static void extract_edituv_data_init(const MeshRenderData *mr,
}
GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+ GPU_vertbuf_data_alloc(vbo, loop_len);
CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
-
- MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data);
data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
data->cd_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV);
}
+static void extract_edituv_data_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data);
+ extract_edituv_data_init_common(mr, vbo, data, mr->loop_len);
+}
+
static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr,
const BMFace *f,
const int UNUSED(f_index),
@@ -119,12 +128,66 @@ static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr,
}
}
+static void extract_edituv_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data);
+ extract_edituv_data_init_common(mr, vbo, data, subdiv_cache->num_subdiv_loops);
+}
+
+static void extract_edituv_data_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const BMFace *coarse_quad)
+{
+ MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(_data);
+ int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index);
+ int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index);
+
+ uint start_loop_idx = subdiv_quad_index * 4;
+ uint end_loop_idx = (subdiv_quad_index + 1) * 4;
+ for (uint i = start_loop_idx; i < end_loop_idx; i++) {
+ const int vert_origindex = subdiv_loop_vert_index[i];
+ const int edge_origindex = subdiv_loop_edge_index[i];
+
+ EditLoopData *edit_loop_data = &data->vbo_data[i];
+ memset(edit_loop_data, 0, sizeof(EditLoopData));
+
+ if (vert_origindex != -1 && edge_origindex != -1) {
+ BMEdge *eed = bm_original_edge_get(mr, edge_origindex);
+ /* Loop on an edge endpoint. */
+ BMLoop *l = BM_face_edge_share_loop(const_cast<BMFace *>(coarse_quad), eed);
+ mesh_render_data_loop_flag(mr, l, data->cd_ofs, edit_loop_data);
+ mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, edit_loop_data);
+ }
+ }
+}
+
+static void extract_edituv_data_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_quad)
+{
+ const int coarse_quad_index = static_cast<int>(coarse_quad - mr->mpoly);
+ BMFace *coarse_quad_bm = bm_original_face_get(mr, coarse_quad_index);
+ extract_edituv_data_iter_subdiv_bm(subdiv_cache, mr, _data, subdiv_quad_index, coarse_quad_bm);
+}
+
constexpr MeshExtract create_extractor_edituv_data()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_data_init;
extractor.iter_poly_bm = extract_edituv_data_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_data_iter_poly_mesh;
+ extractor.init_subdiv = extract_edituv_data_init_subdiv;
+ extractor.iter_subdiv_bm = extract_edituv_data_iter_subdiv_bm;
+ extractor.iter_subdiv_mesh = extract_edituv_data_iter_subdiv_mesh;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUVData_Data);
extractor.use_threading = true;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
index a947d98f955..49b23ff1efe 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
@@ -27,6 +27,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -213,12 +215,69 @@ static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr
}
}
+static GPUVertFormat *get_edituv_stretch_angle_format_subdiv()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* Waning: adjust #UVStretchAngle struct accordingly. */
+ GPU_vertformat_attr_add(&format, "angle", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
+static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(tls_data))
+{
+ GPUVertBuf *refined_vbo = static_cast<GPUVertBuf *>(buffer);
+
+ GPU_vertbuf_init_build_on_device(
+ refined_vbo, get_edituv_stretch_angle_format_subdiv(), subdiv_cache->num_subdiv_loops);
+
+ GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
+ GPUVertBuf *uvs = cache->final.buff.vbo.uv;
+
+ /* UVs are stored contiguously so we need to compute the offset in the UVs buffer for the active
+ * UV layer. */
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_MESH) ? &mr->me->ldata : &mr->bm->ldata;
+
+ uint32_t uv_layers = cache->cd_used.uv;
+ /* HACK to fix T68857 */
+ if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) {
+ int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
+ if (layer != -1) {
+ uv_layers |= (1 << layer);
+ }
+ }
+
+ int uvs_offset = 0;
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (uv_layers & (1 << i)) {
+ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
+ break;
+ }
+
+ uvs_offset += 1;
+ }
+ }
+
+ /* The data is at `offset * num loops`, and we have 2 values per index. */
+ uvs_offset *= subdiv_cache->num_subdiv_loops * 2;
+
+ draw_subdiv_build_edituv_stretch_angle_buffer(
+ subdiv_cache, pos_nor, uvs, uvs_offset, refined_vbo);
+}
+
constexpr MeshExtract create_extractor_edituv_edituv_stretch_angle()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_stretch_angle_init;
extractor.iter_poly_bm = extract_edituv_stretch_angle_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_stretch_angle_iter_poly_mesh;
+ extractor.init_subdiv = extract_edituv_stretch_angle_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_StretchAngle_Data);
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc
index 3db8cd79af5..c116fa5ba07 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc
@@ -27,6 +27,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -63,14 +65,12 @@ BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_t
return (ratio > 1.0f) ? (1.0f / ratio) : ratio;
}
-static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf,
- void *UNUSED(data))
+static void compute_area_ratio(const MeshRenderData *mr,
+ float *r_area_ratio,
+ float &r_tot_area,
+ float &r_tot_uv_area)
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
float tot_area = 0.0f, tot_uv_area = 0.0f;
- float *area_ratio = static_cast<float *>(MEM_mallocN(sizeof(float) * mr->poly_len, __func__));
if (mr->extract_type == MR_EXTRACT_BMESH) {
CustomData *cd_ldata = &mr->bm->ldata;
@@ -84,7 +84,7 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
float uvarea = BM_face_calc_area_uv(efa, uv_ofs);
tot_area += area;
tot_uv_area += uvarea;
- area_ratio[f] = area_ratio_get(area, uvarea);
+ r_area_ratio[f] = area_ratio_get(area, uvarea);
}
}
else {
@@ -96,12 +96,22 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
float uvarea = BKE_mesh_calc_poly_uv_area(mp, uv_data);
tot_area += area;
tot_uv_area += uvarea;
- area_ratio[mp_index] = area_ratio_get(area, uvarea);
+ r_area_ratio[mp_index] = area_ratio_get(area, uvarea);
}
}
- cache->tot_area = tot_area;
- cache->tot_uv_area = tot_uv_area;
+ r_tot_area = tot_area;
+ r_tot_uv_area = tot_uv_area;
+}
+
+static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ float *area_ratio = static_cast<float *>(MEM_mallocN(sizeof(float) * mr->poly_len, __func__));
+ compute_area_ratio(mr, area_ratio, cache->tot_area, cache->tot_uv_area);
/* Convert in place to avoid an extra allocation */
uint16_t *poly_stretch = (uint16_t *)area_ratio;
@@ -135,11 +145,46 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
MEM_freeN(area_ratio);
}
+static void extract_edituv_stretch_area_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+
+ /* Initialize final buffer. */
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+
+ GPU_vertbuf_init_build_on_device(vbo, &format, subdiv_cache->num_subdiv_loops);
+
+ /* Initialize coarse data buffer. */
+
+ GPUVertBuf *coarse_data = GPU_vertbuf_calloc();
+
+ /* We use the same format as we just copy data around. */
+ GPU_vertbuf_init_with_format(coarse_data, &format);
+ GPU_vertbuf_data_alloc(coarse_data, mr->loop_len);
+
+ compute_area_ratio(mr,
+ static_cast<float *>(GPU_vertbuf_get_data(coarse_data)),
+ cache->tot_area,
+ cache->tot_uv_area);
+
+ draw_subdiv_build_edituv_stretch_area_buffer(subdiv_cache, coarse_data, vbo);
+
+ GPU_vertbuf_discard(coarse_data);
+}
+
constexpr MeshExtract create_extractor_edituv_stretch_area()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_stretch_area_init;
extractor.finish = extract_edituv_stretch_area_finish;
+ extractor.init_subdiv = extract_edituv_stretch_area_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
index fed66f0057d..b2ebff08abf 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
@@ -28,6 +28,7 @@ namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Face-dots Normal and edit flag
* \{ */
+
#define NOR_AND_FLAG_DEFAULT 0
#define NOR_AND_FLAG_SELECT 1
#define NOR_AND_FLAG_ACTIVE -1
@@ -114,6 +115,7 @@ constexpr MeshExtract create_extractor_fdots_nor()
/* ---------------------------------------------------------------------- */
/** \name Extract Face-dots High Quality Normal and edit flag
* \{ */
+
static void extract_fdots_nor_hq_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf,
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
index 33f9180e122..f65159f9b95 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
@@ -23,24 +23,40 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Face-dots positions
* \{ */
-static void extract_fdots_pos_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf,
- void *tls_data)
+static GPUVertFormat *get_fdots_pos_format()
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
}
+ return &format;
+}
+
+static GPUVertFormat *get_fdots_nor_format_subdiv()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
- GPU_vertbuf_init_with_format(vbo, &format);
+static void extract_fdots_pos_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPUVertFormat *format = get_fdots_pos_format();
+ GPU_vertbuf_init_with_format(vbo, format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
void *vbo_data = GPU_vertbuf_get_data(vbo);
*(float(**)[3])tls_data = static_cast<float(*)[3]>(vbo_data);
@@ -97,10 +113,30 @@ static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr,
}
}
+static void extract_fdots_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ /* We "extract" positions, normals, and indices at once. */
+ GPUVertBuf *fdots_pos_vbo = static_cast<GPUVertBuf *>(buffer);
+ GPUVertBuf *fdots_nor_vbo = cache->final.buff.vbo.fdots_nor;
+ GPUIndexBuf *fdots_pos_ibo = cache->final.buff.ibo.fdots;
+
+ GPU_vertbuf_init_build_on_device(
+ fdots_nor_vbo, get_fdots_nor_format_subdiv(), subdiv_cache->num_coarse_poly);
+ GPU_vertbuf_init_build_on_device(
+ fdots_pos_vbo, get_fdots_pos_format(), subdiv_cache->num_coarse_poly);
+ GPU_indexbuf_init_build_on_device(fdots_pos_ibo, subdiv_cache->num_coarse_poly);
+ draw_subdiv_build_fdots_buffers(subdiv_cache, fdots_pos_vbo, fdots_nor_vbo, fdots_pos_ibo);
+}
+
constexpr MeshExtract create_extractor_fdots_pos()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_fdots_pos_init;
+ extractor.init_subdiv = extract_fdots_init_subdiv;
extractor.iter_poly_bm = extract_fdots_pos_iter_poly_bm;
extractor.iter_poly_mesh = extract_fdots_pos_iter_poly_mesh;
extractor.data_type = MR_DATA_NONE;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
index f9f66c27aaa..93b94b210b2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
@@ -23,6 +23,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -85,7 +87,7 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr,
*lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]);
}
else if (mp->flag & ME_SMOOTH) {
- *lnor_data = GPU_normal_convert_i10_s3(mr->mvert[ml->v].no);
+ *lnor_data = GPU_normal_convert_i10_v3(mr->vert_normals[ml->v]);
}
else {
*lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[mp_index]);
@@ -107,10 +109,34 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr,
}
}
+static GPUVertFormat *get_subdiv_lnor_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "lnor");
+ }
+ return &format;
+}
+
+static void extract_lnor_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
+ BLI_assert(pos_nor);
+ GPU_vertbuf_init_build_on_device(vbo, get_subdiv_lnor_format(), subdiv_cache->num_subdiv_loops);
+ draw_subdiv_build_lnor_buffer(subdiv_cache, pos_nor, vbo);
+}
+
constexpr MeshExtract create_extractor_lnor()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_lnor_init;
+ extractor.init_subdiv = extract_lnor_init_subdiv;
extractor.iter_poly_bm = extract_lnor_iter_poly_bm;
extractor.iter_poly_mesh = extract_lnor_iter_poly_mesh;
extractor.data_type = MR_DATA_LOOP_NOR;
@@ -121,6 +147,7 @@ constexpr MeshExtract create_extractor_lnor()
}
/** \} */
+
/* ---------------------------------------------------------------------- */
/** \name Extract HQ Loop Normal
* \{ */
@@ -183,7 +210,7 @@ static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr,
normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]);
}
else if (mp->flag & ME_SMOOTH) {
- copy_v3_v3_short(&lnor_data->x, mr->mvert[ml->v].no);
+ normal_float_to_short_v3(&lnor_data->x, mr->vert_normals[ml->v]);
}
else {
normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[mp_index]);
@@ -209,6 +236,7 @@ constexpr MeshExtract create_extractor_lnor_hq()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_lnor_hq_init;
+ extractor.init_subdiv = extract_lnor_init_subdiv;
extractor.iter_poly_bm = extract_lnor_hq_iter_poly_bm;
extractor.iter_poly_mesh = extract_lnor_hq_iter_poly_mesh;
extractor.data_type = MR_DATA_LOOP_NOR;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc
index 33a33c81bc2..706c6ad5403 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc
@@ -460,7 +460,7 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort)
float fac = -1.0f;
if (mp->totloop > 3) {
- float *f_no = mr->poly_normals[mp_index];
+ const float *f_no = mr->poly_normals[mp_index];
fac = 0.0f;
for (int i = 1; i <= mp->totloop; i++) {
@@ -555,7 +555,7 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp)
void **pval;
bool value_is_init = BLI_edgehash_ensure_p(eh, l_curr->v, l_next->v, &pval);
if (!value_is_init) {
- *pval = mr->poly_normals[mp_index];
+ *pval = (void *)mr->poly_normals[mp_index];
/* non-manifold edge, yet... */
continue;
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
index eb9a138590c..5d2ea923658 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
@@ -25,6 +25,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -72,9 +74,8 @@ static void extract_pos_nor_init(const MeshRenderData *mr,
}
}
else {
- const MVert *mv = mr->mvert;
- for (int v = 0; v < mr->vert_len; v++, mv++) {
- data->normals[v].low = GPU_normal_convert_i10_s3(mv->no);
+ for (int v = 0; v < mr->vert_len; v++) {
+ data->normals[v].low = GPU_normal_convert_i10_v3(mr->vert_normals[v]);
}
}
}
@@ -194,6 +195,123 @@ static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr),
MEM_freeN(data->normals);
}
+static GPUVertFormat *get_pos_nor_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "vnor");
+ }
+ return &format;
+}
+
+static GPUVertFormat *get_normals_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "lnor");
+ }
+ return &format;
+}
+
+static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ const bool do_limit_normals = subdiv_cache->do_limit_normals;
+
+ /* Initialize the vertex buffer, it was already allocated. */
+ GPU_vertbuf_init_build_on_device(
+ vbo, get_pos_nor_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
+
+ draw_subdiv_extract_pos_nor(subdiv_cache, vbo, do_limit_normals);
+
+ if (!do_limit_normals) {
+ /* We cannot evaluate vertex normals using the limit surface, so compute them manually. */
+ GPUVertBuf *subdiv_loop_subdiv_vert_index = draw_subdiv_build_origindex_buffer(
+ subdiv_cache->subdiv_loop_subdiv_vert_index, subdiv_cache->num_subdiv_loops);
+
+ GPUVertBuf *vertex_normals = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_build_on_device(
+ vertex_normals, get_normals_format(), subdiv_cache->num_subdiv_verts);
+
+ draw_subdiv_accumulate_normals(subdiv_cache,
+ vbo,
+ subdiv_cache->subdiv_vertex_face_adjacency_offsets,
+ subdiv_cache->subdiv_vertex_face_adjacency,
+ vertex_normals);
+
+ draw_subdiv_finalize_normals(subdiv_cache, vertex_normals, subdiv_loop_subdiv_vert_index, vbo);
+
+ GPU_vertbuf_discard(vertex_normals);
+ GPU_vertbuf_discard(subdiv_loop_subdiv_vert_index);
+ }
+}
+
+static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
+ if (loop_loose_len == 0) {
+ return;
+ }
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ const Mesh *coarse_mesh = subdiv_cache->mesh;
+ const MEdge *coarse_edges = coarse_mesh->medge;
+ const MVert *coarse_verts = coarse_mesh->mvert;
+ uint offset = subdiv_cache->num_subdiv_loops;
+
+ /* TODO(kevindietrich) : replace this when compressed normals are supported. */
+ struct SubdivPosNorLoop {
+ float pos[3];
+ float nor[3];
+ float flag;
+ };
+
+ SubdivPosNorLoop edge_data[2];
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
+ const MVert *loose_vert1 = &coarse_verts[loose_edge->v1];
+ const MVert *loose_vert2 = &coarse_verts[loose_edge->v2];
+
+ copy_v3_v3(edge_data[0].pos, loose_vert1->co);
+ copy_v3_v3(edge_data[0].nor, mr->vert_normals[loose_edge->v1]);
+ edge_data[0].flag = 0.0f;
+
+ copy_v3_v3(edge_data[1].pos, loose_vert2->co);
+ copy_v3_v3(edge_data[1].nor, mr->vert_normals[loose_edge->v2]);
+ edge_data[1].flag = 0.0f;
+
+ GPU_vertbuf_update_sub(
+ vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop) * 2, &edge_data);
+
+ offset += 2;
+ }
+
+ SubdivPosNorLoop vert_data;
+ vert_data.flag = 0.0f;
+ for (int i = 0; i < loose_geom->vert_len; i++) {
+ const MVert *loose_vertex = &coarse_verts[loose_geom->verts[i]];
+
+ copy_v3_v3(vert_data.pos, loose_vertex->co);
+ copy_v3_v3(vert_data.nor, mr->vert_normals[loose_geom->verts[i]]);
+
+ GPU_vertbuf_update_sub(
+ vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop), &vert_data);
+
+ offset += 1;
+ }
+}
+
constexpr MeshExtract create_extractor_pos_nor()
{
MeshExtract extractor = {nullptr};
@@ -205,6 +323,8 @@ constexpr MeshExtract create_extractor_pos_nor()
extractor.iter_lvert_bm = extract_pos_nor_iter_lvert_bm;
extractor.iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh;
extractor.finish = extract_pos_nor_finish;
+ extractor.init_subdiv = extract_pos_nor_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_pos_nor_loose_geom_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_PosNor_Data);
extractor.use_threading = true;
@@ -259,9 +379,8 @@ static void extract_pos_nor_hq_init(const MeshRenderData *mr,
}
}
else {
- const MVert *mv = mr->mvert;
- for (int v = 0; v < mr->vert_len; v++, mv++) {
- copy_v3_v3_short(data->normals[v].high, mv->no);
+ for (int v = 0; v < mr->vert_len; v++) {
+ normal_float_to_short_v3(data->normals[v].high, mr->vert_normals[v]);
}
}
}
@@ -391,6 +510,7 @@ constexpr MeshExtract create_extractor_pos_nor_hq()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_pos_nor_hq_init;
+ extractor.init_subdiv = extract_pos_nor_init_subdiv;
extractor.iter_poly_bm = extract_pos_nor_hq_iter_poly_bm;
extractor.iter_poly_mesh = extract_pos_nor_hq_iter_poly_mesh;
extractor.iter_ledge_bm = extract_pos_nor_hq_iter_ledge_bm;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
index fd91bc5258f..753fbe7e0e2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
@@ -27,6 +27,7 @@
#include "BKE_paint.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -35,13 +36,23 @@ namespace blender::draw {
/** \name Extract Sculpt Data
* \{ */
+static GPUVertFormat *get_sculpt_data_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
static void extract_sculpt_data_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
- GPUVertFormat format = {0};
+ GPUVertFormat *format = get_sculpt_data_format();
CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
@@ -50,12 +61,7 @@ static void extract_sculpt_data_init(const MeshRenderData *mr,
float *cd_mask = (float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
int *cd_face_set = (int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS);
- if (format.attr_len == 0) {
- GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- }
-
- GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_init_with_format(vbo, format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
struct gpuSculptData {
@@ -121,10 +127,99 @@ static void extract_sculpt_data_init(const MeshRenderData *mr,
}
}
+static void extract_sculpt_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+
+ Mesh *coarse_mesh = mr->me;
+ CustomData *cd_vdata = &coarse_mesh->vdata;
+ CustomData *cd_pdata = &coarse_mesh->pdata;
+
+ /* First, interpolate mask if available. */
+ GPUVertBuf *mask_vbo = nullptr;
+ GPUVertBuf *subdiv_mask_vbo = nullptr;
+ float *cd_mask = (float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
+
+ if (cd_mask) {
+ GPUVertFormat mask_format = {0};
+ GPU_vertformat_attr_add(&mask_format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+
+ mask_vbo = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format(mask_vbo, &mask_format);
+ GPU_vertbuf_data_alloc(mask_vbo, coarse_mesh->totloop);
+ float *v_mask = static_cast<float *>(GPU_vertbuf_get_data(mask_vbo));
+
+ for (int i = 0; i < coarse_mesh->totpoly; i++) {
+ const MPoly *mpoly = &coarse_mesh->mpoly[i];
+
+ for (int loop_index = mpoly->loopstart; loop_index < mpoly->loopstart + mpoly->totloop;
+ loop_index++) {
+ const MLoop *ml = &coarse_mesh->mloop[loop_index];
+ *v_mask++ = cd_mask[ml->v];
+ }
+ }
+
+ subdiv_mask_vbo = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_build_on_device(
+ subdiv_mask_vbo, &mask_format, subdiv_cache->num_subdiv_loops);
+
+ draw_subdiv_interp_custom_data(subdiv_cache, mask_vbo, subdiv_mask_vbo, 1, 0);
+ }
+
+ /* Then, gather face sets. */
+ GPUVertFormat face_set_format = {0};
+ GPU_vertformat_attr_add(&face_set_format, "msk", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ GPUVertBuf *face_set_vbo = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format(face_set_vbo, &face_set_format);
+ GPU_vertbuf_data_alloc(face_set_vbo, subdiv_cache->num_subdiv_loops);
+
+ struct gpuFaceSet {
+ uint8_t color[4];
+ };
+
+ gpuFaceSet *face_sets = (gpuFaceSet *)GPU_vertbuf_get_data(face_set_vbo);
+ int *cd_face_set = (int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS);
+
+ GPUVertFormat *format = get_sculpt_data_format();
+ GPU_vertbuf_init_build_on_device(vbo, format, subdiv_cache->num_subdiv_loops);
+ int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index;
+
+ for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) {
+ const int mp_index = subdiv_loop_poly_index[i];
+
+ uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
+ if (cd_face_set) {
+ const int face_set_id = cd_face_set[mp_index];
+ /* Skip for the default color Face Set to render it white. */
+ if (face_set_id != coarse_mesh->face_sets_color_default) {
+ BKE_paint_face_set_overlay_color_get(
+ face_set_id, coarse_mesh->face_sets_color_seed, face_set_color);
+ }
+ }
+ copy_v3_v3_uchar(face_sets->color, face_set_color);
+ face_sets++;
+ }
+
+ /* Finally, interleave mask and face sets. */
+ draw_subdiv_build_sculpt_data_buffer(subdiv_cache, subdiv_mask_vbo, face_set_vbo, vbo);
+
+ if (mask_vbo) {
+ GPU_vertbuf_discard(mask_vbo);
+ GPU_vertbuf_discard(subdiv_mask_vbo);
+ }
+ GPU_vertbuf_discard(face_set_vbo);
+}
+
constexpr MeshExtract create_extractor_sculpt_data()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_sculpt_data_init;
+ extractor.init_subdiv = extract_sculpt_data_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
index 5ac30dd3be9..33c27b45627 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
@@ -21,6 +21,7 @@
* \ingroup draw
*/
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -196,12 +197,104 @@ static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr,
(*(uint32_t **)data)[offset + lvert_index] = v_orig;
}
+static void extract_vert_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ /* Each element points to an element in the ibo.points. */
+ draw_subdiv_init_origindex_buffer(vbo,
+ subdiv_cache->subdiv_loop_subdiv_vert_index,
+ subdiv_cache->num_subdiv_loops,
+ mr->loop_loose_len);
+}
+
+static void extract_vert_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
+ if (loop_loose_len == 0) {
+ return;
+ }
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo);
+ const Mesh *coarse_mesh = subdiv_cache->mesh;
+ const MEdge *coarse_edges = coarse_mesh->medge;
+ uint offset = subdiv_cache->num_subdiv_loops;
+
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
+ vert_idx_data[offset] = loose_edge->v1;
+ vert_idx_data[offset + 1] = loose_edge->v2;
+ offset += 2;
+ }
+
+ for (int i = 0; i < loose_geom->vert_len; i++) {
+ vert_idx_data[offset] = loose_geom->verts[i];
+ offset += 1;
+ }
+}
+
+static void extract_edge_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ draw_subdiv_init_origindex_buffer(
+ vbo,
+ static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)),
+ subdiv_cache->num_subdiv_loops,
+ mr->edge_loose_len * 2);
+}
+
+static void extract_edge_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
+ if (loop_loose_len == 0) {
+ return;
+ }
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo);
+ uint offset = subdiv_cache->num_subdiv_loops;
+
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ vert_idx_data[offset] = loose_geom->edges[i];
+ vert_idx_data[offset + 1] = loose_geom->edges[i];
+ offset += 2;
+ }
+}
+
+static void extract_poly_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ draw_subdiv_init_origindex_buffer(
+ vbo, subdiv_cache->subdiv_loop_poly_index, subdiv_cache->num_subdiv_loops, 0);
+}
+
constexpr MeshExtract create_extractor_poly_idx()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_select_idx_init;
extractor.iter_poly_bm = extract_poly_idx_iter_poly_bm;
extractor.iter_poly_mesh = extract_poly_idx_iter_poly_mesh;
+ extractor.init_subdiv = extract_poly_idx_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(uint32_t *);
extractor.use_threading = true;
@@ -217,6 +310,8 @@ constexpr MeshExtract create_extractor_edge_idx()
extractor.iter_poly_mesh = extract_edge_idx_iter_poly_mesh;
extractor.iter_ledge_bm = extract_edge_idx_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_edge_idx_iter_ledge_mesh;
+ extractor.init_subdiv = extract_edge_idx_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_edge_idx_loose_geom_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(uint32_t *);
extractor.use_threading = true;
@@ -234,6 +329,8 @@ constexpr MeshExtract create_extractor_vert_idx()
extractor.iter_ledge_mesh = extract_vert_idx_iter_ledge_mesh;
extractor.iter_lvert_bm = extract_vert_idx_iter_lvert_bm;
extractor.iter_lvert_mesh = extract_vert_idx_iter_lvert_mesh;
+ extractor.init_subdiv = extract_vert_idx_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_vert_idx_loose_geom_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(uint32_t *);
extractor.use_threading = true;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
index 1f8776fc98e..03d1b327689 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
@@ -54,11 +54,18 @@ static void extract_tan_ex_init(const MeshRenderData *mr,
uint32_t tan_layers = cache->cd_used.tan;
float(*orco)[3] = (float(*)[3])CustomData_get_layer(cd_vdata, CD_ORCO);
bool orco_allocated = false;
- const bool use_orco_tan = cache->cd_used.tan_orco != 0;
+ bool use_orco_tan = cache->cd_used.tan_orco != 0;
int tan_len = 0;
char tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME];
+ /* FIXME(T91838): This is to avoid a crash when orco tangent was requested but there are valid
+ * uv layers. It would be better to fix the root cause. */
+ if (tan_layers == 0 && use_orco_tan && CustomData_get_layer_index(cd_ldata, CD_MLOOPUV) != -1) {
+ tan_layers = 1;
+ use_orco_tan = false;
+ }
+
for (int i = 0; i < MAX_MTFACE; i++) {
if (tan_layers & (1 << i)) {
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
@@ -131,6 +138,7 @@ static void extract_tan_ex_init(const MeshRenderData *mr,
calc_active_tangent,
tangent_names,
tan_len,
+ mr->vert_normals,
mr->poly_normals,
mr->loop_normals,
orco,
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
index af279b08a59..6e9d8ef6926 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
@@ -23,6 +23,7 @@
#include "BLI_string.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -31,25 +32,27 @@ namespace blender::draw {
/** \name Extract UV layers
* \{ */
-static void extract_uv_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf,
- void *UNUSED(tls_data))
+/* Initialize the vertex format to be used for UVs. Return true if any UV layer is
+ * found, false otherwise. */
+static bool mesh_extract_uv_format_init(GPUVertFormat *format,
+ struct MeshBatchCache *cache,
+ CustomData *cd_ldata,
+ eMRExtractType extract_type,
+ uint32_t &r_uv_layers)
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
- GPUVertFormat format = {0};
- GPU_vertformat_deinterleave(&format);
+ GPU_vertformat_deinterleave(format);
- CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
uint32_t uv_layers = cache->cd_used.uv;
/* HACK to fix T68857 */
- if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) {
+ if (extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) {
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
if (layer != -1) {
uv_layers |= (1 << layer);
}
}
+ r_uv_layers = uv_layers;
+
for (int i = 0; i < MAX_MTFACE; i++) {
if (uv_layers & (1 << i)) {
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
@@ -58,30 +61,47 @@ static void extract_uv_init(const MeshRenderData *mr,
GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
/* UV layer name. */
BLI_snprintf(attr_name, sizeof(attr_name), "u%s", attr_safe_name);
- GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
/* Auto layer name. */
BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
- GPU_vertformat_alias_add(&format, attr_name);
+ GPU_vertformat_alias_add(format, attr_name);
/* Active render layer name. */
if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) {
- GPU_vertformat_alias_add(&format, "u");
+ GPU_vertformat_alias_add(format, "u");
}
/* Active display layer name. */
if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
- GPU_vertformat_alias_add(&format, "au");
+ GPU_vertformat_alias_add(format, "au");
/* Alias to `pos` for edit uvs. */
- GPU_vertformat_alias_add(&format, "pos");
+ GPU_vertformat_alias_add(format, "pos");
}
/* Stencil mask uv layer name. */
if (i == CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV)) {
- GPU_vertformat_alias_add(&format, "mu");
+ GPU_vertformat_alias_add(format, "mu");
}
}
}
+ if (format->attr_len == 0) {
+ GPU_vertformat_attr_add(format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ return false;
+ }
+
+ return true;
+}
+
+static void extract_uv_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(tls_data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPUVertFormat format = {0};
+
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
int v_len = mr->loop_len;
- if (format.attr_len == 0) {
- GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint32_t uv_layers = cache->cd_used.uv;
+ if (!mesh_extract_uv_format_init(&format, cache, cd_ldata, mr->extract_type, uv_layers)) {
/* VBO will not be used, only allocate minimum of memory. */
v_len = 1;
}
@@ -116,10 +136,45 @@ static void extract_uv_init(const MeshRenderData *mr,
}
}
+static void extract_uv_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ Mesh *coarse_mesh = subdiv_cache->mesh;
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ GPUVertFormat format = {0};
+
+ uint v_len = subdiv_cache->num_subdiv_loops;
+ uint uv_layers;
+ if (!mesh_extract_uv_format_init(
+ &format, cache, &coarse_mesh->ldata, MR_EXTRACT_MESH, uv_layers)) {
+ // TODO(kevindietrich): handle this more gracefully.
+ v_len = 1;
+ }
+
+ GPU_vertbuf_init_build_on_device(vbo, &format, v_len);
+
+ if (uv_layers == 0) {
+ return;
+ }
+
+ /* Index of the UV layer in the compact buffer. Used UV layers are stored in a single buffer. */
+ int pack_layer_index = 0;
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (uv_layers & (1 << i)) {
+ const int offset = (int)subdiv_cache->num_subdiv_loops * pack_layer_index++;
+ draw_subdiv_extract_uvs(subdiv_cache, vbo, i, offset);
+ }
+ }
+}
+
constexpr MeshExtract create_extractor_uv()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_uv_init;
+ extractor.init_subdiv = extract_uv_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
index 2c7770c8e72..a0307b9b2cd 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
@@ -25,6 +25,7 @@
#include "BLI_string.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -33,19 +34,14 @@ namespace blender::draw {
/** \name Extract VCol
* \{ */
-static void extract_vcol_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf,
- void *UNUSED(tls_data))
+/* Initialize the common vertex format for vcol for coarse and subdivided meshes. */
+static void init_vcol_format(GPUVertFormat *format,
+ const MeshBatchCache *cache,
+ CustomData *cd_ldata)
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
- GPUVertFormat format = {0};
- GPU_vertformat_deinterleave(&format);
+ GPU_vertformat_deinterleave(format);
- CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
- CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
- uint32_t vcol_layers = cache->cd_used.vcol;
- uint32_t svcol_layers = cache->cd_used.sculpt_vcol;
+ const uint32_t vcol_layers = cache->cd_used.vcol;
for (int i = 0; i < MAX_MCOL; i++) {
if (vcol_layers & (1 << i)) {
@@ -54,61 +50,57 @@ static void extract_vcol_init(const MeshRenderData *mr,
GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
- GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) {
- GPU_vertformat_alias_add(&format, "c");
+ GPU_vertformat_alias_add(format, "c");
}
if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) {
- GPU_vertformat_alias_add(&format, "ac");
+ GPU_vertformat_alias_add(format, "ac");
}
/* Gather number of auto layers. */
- /* We only do `vcols` that are not overridden by `uvs` and sculpt vertex colors. */
- if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1 &&
- CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, layer_name) == -1) {
+ /* We only do `vcols` that are not overridden by `uvs`. */
+ if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) {
BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
- GPU_vertformat_alias_add(&format, attr_name);
+ GPU_vertformat_alias_add(format, attr_name);
}
}
}
+}
- /* Sculpt Vertex Colors */
- if (U.experimental.use_sculpt_vertex_colors) {
- for (int i = 0; i < 8; i++) {
- if (svcol_layers & (1 << i)) {
- char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
- const char *layer_name = CustomData_get_layer_name(cd_vdata, CD_PROP_COLOR, i);
- GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
+/* Vertex format for vertex colors, only used during the coarse data upload for the subdivision
+ * case. */
+static GPUVertFormat *get_coarse_vcol_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "cCol", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "c");
+ GPU_vertformat_alias_add(&format, "ac");
+ }
+ return &format;
+}
- BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
- GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+using gpuMeshVcol = struct gpuMeshVcol {
+ ushort r, g, b, a;
+};
- if (i == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) {
- GPU_vertformat_alias_add(&format, "c");
- }
- if (i == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) {
- GPU_vertformat_alias_add(&format, "ac");
- }
- /* Gather number of auto layers. */
- /* We only do `vcols` that are not overridden by `uvs`. */
- if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) {
- BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
- GPU_vertformat_alias_add(&format, attr_name);
- }
- }
- }
- }
+static void extract_vcol_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(tls_data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPUVertFormat format = {0};
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
+ const uint32_t vcol_layers = cache->cd_used.vcol;
+ init_vcol_format(&format, cache, cd_ldata);
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
- using gpuMeshVcol = struct gpuMeshVcol {
- ushort r, g, b, a;
- };
-
gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo);
- MLoop *loops = (MLoop *)CustomData_get_layer(cd_ldata, CD_MLOOP);
for (int i = 0; i < MAX_MCOL; i++) {
if (vcol_layers & (1 << i)) {
@@ -139,42 +131,67 @@ static void extract_vcol_init(const MeshRenderData *mr,
}
}
}
+ }
+}
- if (svcol_layers & (1 << i) && U.experimental.use_sculpt_vertex_colors) {
- if (mr->extract_type == MR_EXTRACT_BMESH) {
- int cd_ofs = CustomData_get_n_offset(cd_vdata, CD_PROP_COLOR, i);
- BMIter f_iter;
- BMFace *efa;
- BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- const MPropCol *prop_col = (const MPropCol *)BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs);
- vcol_data->r = unit_float_to_ushort_clamp(prop_col->color[0]);
- vcol_data->g = unit_float_to_ushort_clamp(prop_col->color[1]);
- vcol_data->b = unit_float_to_ushort_clamp(prop_col->color[2]);
- vcol_data->a = unit_float_to_ushort_clamp(prop_col->color[3]);
- vcol_data++;
- } while ((l_iter = l_iter->next) != l_first);
- }
- }
- else {
- MPropCol *vcol = (MPropCol *)CustomData_get_layer_n(cd_vdata, CD_PROP_COLOR, i);
- for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vcol_data++) {
- vcol_data->r = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[0]);
- vcol_data->g = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[1]);
- vcol_data->b = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[2]);
- vcol_data->a = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[3]);
- }
+static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
+ Mesh *coarse_mesh = subdiv_cache->mesh;
+
+ GPUVertFormat format = {0};
+ init_vcol_format(&format, cache, &coarse_mesh->ldata);
+
+ GPU_vertbuf_init_build_on_device(dst_buffer, &format, subdiv_cache->num_subdiv_loops);
+
+ GPUVertBuf *src_data = GPU_vertbuf_calloc();
+ /* Dynamic as we upload and interpolate layers one at a time. */
+ GPU_vertbuf_init_with_format_ex(src_data, get_coarse_vcol_format(), GPU_USAGE_DYNAMIC);
+
+ GPU_vertbuf_data_alloc(src_data, coarse_mesh->totloop);
+
+ gpuMeshVcol *mesh_vcol = (gpuMeshVcol *)GPU_vertbuf_get_data(src_data);
+
+ const CustomData *cd_ldata = &coarse_mesh->ldata;
+
+ const uint vcol_layers = cache->cd_used.vcol;
+
+ /* Index of the vertex color layer in the compact buffer. Used vertex color layers are stored in
+ * a single buffer. */
+ int pack_layer_index = 0;
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (vcol_layers & (1 << i)) {
+ /* Include stride in offset, we use a stride of 2 since colors are packed into 2 uints. */
+ const int dst_offset = (int)subdiv_cache->num_subdiv_loops * 2 * pack_layer_index++;
+ const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
+
+ gpuMeshVcol *vcol = mesh_vcol;
+
+ for (int ml_index = 0; ml_index < coarse_mesh->totloop; ml_index++, vcol++, mloopcol++) {
+ vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
+ vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
+ vcol->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
+ vcol->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
}
+
+ /* Ensure data is uploaded properly. */
+ GPU_vertbuf_tag_dirty(src_data);
+ draw_subdiv_interp_custom_data(subdiv_cache, src_data, dst_buffer, 4, dst_offset);
}
}
+
+ GPU_vertbuf_discard(src_data);
}
constexpr MeshExtract create_extractor_vcol()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_vcol_init;
+ extractor.init_subdiv = extract_vcol_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc
index bdb1410a755..bb8853b8154 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc
@@ -25,6 +25,7 @@
#include "BKE_deform.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -167,10 +168,57 @@ static void extract_weights_iter_poly_mesh(const MeshRenderData *mr,
}
}
+static void extract_weights_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ Mesh *coarse_mesh = subdiv_cache->mesh;
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+ GPU_vertbuf_init_build_on_device(vbo, &format, subdiv_cache->num_subdiv_loops);
+
+ GPUVertBuf *coarse_weights = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format(coarse_weights, &format);
+ GPU_vertbuf_data_alloc(coarse_weights, coarse_mesh->totloop);
+ float *coarse_weights_data = static_cast<float *>(GPU_vertbuf_get_data(coarse_weights));
+
+ const DRW_MeshWeightState *wstate = &cache->weight_state;
+ const MDeformVert *dverts = static_cast<const MDeformVert *>(
+ CustomData_get_layer(&coarse_mesh->vdata, CD_MDEFORMVERT));
+
+ for (int i = 0; i < coarse_mesh->totpoly; i++) {
+ const MPoly *mpoly = &coarse_mesh->mpoly[i];
+
+ for (int loop_index = mpoly->loopstart; loop_index < mpoly->loopstart + mpoly->totloop;
+ loop_index++) {
+ const MLoop *ml = &coarse_mesh->mloop[loop_index];
+
+ if (dverts != nullptr) {
+ const MDeformVert *dvert = &dverts[ml->v];
+ coarse_weights_data[loop_index] = evaluate_vertex_weight(dvert, wstate);
+ }
+ else {
+ coarse_weights_data[loop_index] = evaluate_vertex_weight(nullptr, wstate);
+ }
+ }
+ }
+
+ draw_subdiv_interp_custom_data(subdiv_cache, coarse_weights, vbo, 1, 0);
+
+ GPU_vertbuf_discard(coarse_weights);
+}
+
constexpr MeshExtract create_extractor_weights()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_weights_init;
+ extractor.init_subdiv = extract_weights_init_subdiv;
extractor.iter_poly_bm = extract_weights_iter_poly_bm;
extractor.iter_poly_mesh = extract_weights_iter_poly_mesh;
extractor.data_type = MR_DATA_NONE;
diff --git a/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl b/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl
index 8a7fb97d98c..53ec38fea0b 100644
--- a/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl
+++ b/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl
@@ -1,5 +1,7 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
out vec4 uvcoordsvar;
+#endif
void main()
{
diff --git a/source/blender/draw/intern/shaders/common_fxaa_lib.glsl b/source/blender/draw/intern/shaders/common_fxaa_lib.glsl
index 0ecfc397e95..bf59972fbaa 100644
--- a/source/blender/draw/intern/shaders/common_fxaa_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_fxaa_lib.glsl
@@ -296,7 +296,7 @@ NOTE the other tuning knobs are now in the shader function inputs!
/* (#B1#) */
float FxaaLuma(vec4 rgba)
{
- /* note: sqrt because the sampled colors are in a linear colorspace!
+ /* NOTE: sqrt because the sampled colors are in a linear colorspace!
* this approximates a perceptual conversion, which is good enough for the
* algorithm */
return sqrt(dot(rgba.rgb, vec3(0.2126, 0.7152, 0.0722)));
diff --git a/source/blender/draw/intern/shaders/common_globals_lib.glsl b/source/blender/draw/intern/shaders/common_globals_lib.glsl
index 3c76c8a5b28..77b34543989 100644
--- a/source/blender/draw/intern/shaders/common_globals_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_globals_lib.glsl
@@ -7,8 +7,6 @@ layout(std140) uniform globalsBlock
vec4 colorWireEdit;
vec4 colorActive;
vec4 colorSelect;
- vec4 colorDupliSelect;
- vec4 colorDupli;
vec4 colorLibrarySelect;
vec4 colorLibrary;
vec4 colorTransform;
diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl
index b25057c06b6..25e4abc5ebc 100644
--- a/source/blender/draw/intern/shaders/common_hair_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl
@@ -5,6 +5,9 @@
* of data the CPU has to precompute and transfer for each update.
*/
+/* TODO(fclem): Keep documentation but remove the uniform declaration. */
+#ifndef USE_GPU_SHADER_CREATE_INFO
+
/**
* hairStrandsRes: Number of points per hair strand.
* 2 - no subdivision
@@ -33,8 +36,6 @@ uniform int hairStrandOffset = 0;
/* -- Per control points -- */
uniform samplerBuffer hairPointBuffer; /* RGBA32F */
-#define point_position xyz
-#define point_time w /* Position along the hair length */
/* -- Per strands data -- */
uniform usamplerBuffer hairStrandBuffer; /* R32UI */
@@ -43,6 +44,10 @@ uniform usamplerBuffer hairStrandSegBuffer; /* R16UI */
/* Not used, use one buffer per uv layer */
// uniform samplerBuffer hairUVBuffer; /* RG32F */
// uniform samplerBuffer hairColBuffer; /* RGBA16 linear color */
+#endif
+
+#define point_position xyz
+#define point_time w /* Position along the hair length */
/* -- Subdivision stage -- */
/**
diff --git a/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl b/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl
index 4dcde4b0245..6a3a7815cdc 100644
--- a/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+#ifndef USE_GPU_SHADER_CREATE_INFO
/*
* To be compiled with common_hair_lib.glsl.
*/
@@ -9,6 +11,7 @@ layout(std430, binding = 0) writeonly buffer hairPointOutputBuffer
vec4 posTime[];
}
out_vertbuf;
+#endif
void main(void)
{
@@ -20,5 +23,5 @@ void main(void)
vec4 result = hair_interp_data(data0, data1, data2, data3, weights);
uint index = uint(hair_get_id() * hairStrandsRes) + gl_GlobalInvocationID.y;
- out_vertbuf.posTime[index] = result;
+ posTime[index] = result;
}
diff --git a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl
index 74b989441a2..dd725ad327f 100644
--- a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl
@@ -2,6 +2,8 @@
/* NOTE: To be used with UNIFORM_RESOURCE_ID and INSTANCED_ATTR as define. */
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#ifndef DRW_SHADER_SHARED_H
+
in vec4 pos; /* Position and radius. */
/* ---- Instanced attribs ---- */
@@ -9,6 +11,8 @@ in vec4 pos; /* Position and radius. */
in vec3 pos_inst;
in vec3 nor;
+#endif
+
mat3 pointcloud_get_facing_matrix(vec3 p)
{
mat3 facing_mat;
@@ -18,13 +22,22 @@ mat3 pointcloud_get_facing_matrix(vec3 p)
return facing_mat;
}
+/* Returns world center position and radius. */
+void pointcloud_get_pos_and_radius(out vec3 outpos, out float outradius)
+{
+ outpos = point_object_to_world(pos.xyz);
+ outradius = dot(abs(mat3(ModelMatrix) * pos.www), vec3(1.0 / 3.0));
+}
+
/* Return world position and normal. */
void pointcloud_get_pos_and_nor(out vec3 outpos, out vec3 outnor)
{
- vec3 p = point_object_to_world(pos.xyz);
+ vec3 p;
+ float radius;
+ pointcloud_get_pos_and_radius(p, radius);
+
mat3 facing_mat = pointcloud_get_facing_matrix(p);
- float radius = dot(abs(mat3(ModelMatrix) * pos.www), vec3(1.0 / 3.0));
/* TODO(fclem): remove multiplication here. Here only for keeping the size correct for now. */
radius *= 0.01;
outpos = p + (facing_mat * pos_inst) * radius;
diff --git a/source/blender/draw/intern/shaders/common_smaa_lib.glsl b/source/blender/draw/intern/shaders/common_smaa_lib.glsl
index 36ffb4d8b32..73f65fb0799 100644
--- a/source/blender/draw/intern/shaders/common_smaa_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_smaa_lib.glsl
@@ -736,9 +736,11 @@ float2 SMAALumaEdgeDetectionPS(float2 texcoord,
float2 edges = step(threshold, delta.xy);
# ifndef SMAA_NO_DISCARD
+# ifdef GPU_FRAGMENT_SHADER
// Then discard if there is no edge:
if (dot(edges, float2(1.0, 1.0)) == 0.0)
discard;
+# endif
# endif
// Calculate right and bottom deltas:
@@ -804,9 +806,11 @@ float2 SMAAColorEdgeDetectionPS(float2 texcoord,
float2 edges = step(threshold, delta.xy);
# ifndef SMAA_NO_DISCARD
+# ifdef GPU_FRAGMENT_SHADER
// Then discard if there is no edge:
if (dot(edges, float2(1.0, 1.0)) == 0.0)
discard;
+# endif
# endif
// Calculate right and bottom deltas:
@@ -851,8 +855,10 @@ float2 SMAADepthEdgeDetectionPS(float2 texcoord, float4 offset[3], SMAATexture2D
float2 delta = abs(neighbours.xx - float2(neighbours.y, neighbours.z));
float2 edges = step(SMAA_DEPTH_THRESHOLD, delta);
+# ifdef GPU_FRAGMENT_SHADER
if (dot(edges, float2(1.0, 1.0)) == 0.0)
discard;
+# endif
return edges;
}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl
new file mode 100644
index 00000000000..36c3970d9a0
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl
@@ -0,0 +1,230 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 1) readonly restrict buffer sourceBuffer
+{
+#ifdef GPU_FETCH_U16_TO_FLOAT
+ uint src_data[];
+#else
+ float src_data[];
+#endif
+};
+
+layout(std430, binding = 2) readonly restrict buffer facePTexOffset
+{
+ uint face_ptex_offset[];
+};
+
+layout(std430, binding = 3) readonly restrict buffer patchCoords
+{
+ BlenderPatchCoord patch_coords[];
+};
+
+layout(std430, binding = 4) readonly restrict buffer extraCoarseFaceData
+{
+ uint extra_coarse_face_data[];
+};
+
+layout(std430, binding = 5) writeonly restrict buffer destBuffer
+{
+#ifdef GPU_FETCH_U16_TO_FLOAT
+ uint dst_data[];
+#else
+ float dst_data[];
+#endif
+};
+
+struct Vertex {
+ float vertex_data[DIMENSIONS];
+};
+
+void clear(inout Vertex v)
+{
+ for (int i = 0; i < DIMENSIONS; i++) {
+ v.vertex_data[i] = 0.0;
+ }
+}
+
+Vertex read_vertex(uint index)
+{
+ Vertex result;
+#ifdef GPU_FETCH_U16_TO_FLOAT
+ uint base_index = index * 2;
+ if (DIMENSIONS == 4) {
+ uint xy = src_data[base_index];
+ uint zw = src_data[base_index + 1];
+
+ float x = float((xy >> 16) & 0xffff) / 65535.0;
+ float y = float(xy & 0xffff) / 65535.0;
+ float z = float((zw >> 16) & 0xffff) / 65535.0;
+ float w = float(zw & 0xffff) / 65535.0;
+
+ result.vertex_data[0] = x;
+ result.vertex_data[1] = y;
+ result.vertex_data[2] = z;
+ result.vertex_data[3] = w;
+ }
+ else {
+ /* This case is unsupported for now. */
+ clear(result);
+ }
+#else
+ uint base_index = index * DIMENSIONS;
+ for (int i = 0; i < DIMENSIONS; i++) {
+ result.vertex_data[i] = src_data[base_index + i];
+ }
+#endif
+ return result;
+}
+
+void write_vertex(uint index, Vertex v)
+{
+#ifdef GPU_FETCH_U16_TO_FLOAT
+ uint base_index = dst_offset + index * 2;
+ if (DIMENSIONS == 4) {
+ uint x = uint(v.vertex_data[0] * 65535.0);
+ uint y = uint(v.vertex_data[1] * 65535.0);
+ uint z = uint(v.vertex_data[2] * 65535.0);
+ uint w = uint(v.vertex_data[3] * 65535.0);
+
+ uint xy = x << 16 | y;
+ uint zw = z << 16 | w;
+
+ dst_data[base_index] = xy;
+ dst_data[base_index + 1] = zw;
+ }
+ else {
+ /* This case is unsupported for now. */
+ dst_data[base_index] = 0;
+ }
+#else
+ uint base_index = dst_offset + index * DIMENSIONS;
+ for (int i = 0; i < DIMENSIONS; i++) {
+ dst_data[base_index + i] = v.vertex_data[i];
+ }
+#endif
+}
+
+Vertex interp_vertex(Vertex v0, Vertex v1, Vertex v2, Vertex v3, vec2 uv)
+{
+ Vertex result;
+ for (int i = 0; i < DIMENSIONS; i++) {
+ float e = mix(v0.vertex_data[i], v1.vertex_data[i], uv.x);
+ float f = mix(v2.vertex_data[i], v3.vertex_data[i], uv.x);
+ result.vertex_data[i] = mix(e, f, uv.y);
+ }
+ return result;
+}
+
+void add_with_weight(inout Vertex v0, Vertex v1, float weight)
+{
+ for (int i = 0; i < DIMENSIONS; i++) {
+ v0.vertex_data[i] += v1.vertex_data[i] * weight;
+ }
+}
+
+Vertex average(Vertex v0, Vertex v1)
+{
+ Vertex result;
+ for (int i = 0; i < DIMENSIONS; i++) {
+ result.vertex_data[i] = (v0.vertex_data[i] + v1.vertex_data[i]) * 0.5;
+ }
+ return result;
+}
+
+uint get_vertex_count(uint coarse_polygon)
+{
+ uint number_of_patches = face_ptex_offset[coarse_polygon + 1] - face_ptex_offset[coarse_polygon];
+ if (number_of_patches == 1) {
+ /* If there is only one patch for the current coarse polygon, then it is a quad. */
+ return 4;
+ }
+ /* Otherwise, the number of patches is the number of vertices. */
+ return number_of_patches;
+}
+
+uint get_polygon_corner_index(uint coarse_polygon, uint patch_index)
+{
+ uint patch_offset = face_ptex_offset[coarse_polygon];
+ return patch_index - patch_offset;
+}
+
+uint get_loop_start(uint coarse_polygon)
+{
+ return extra_coarse_face_data[coarse_polygon] & coarse_face_loopstart_mask;
+}
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ /* Find which coarse polygon we came from. */
+ uint coarse_polygon = coarse_polygon_index_from_subdiv_quad_index(quad_index, coarse_poly_count);
+ uint loop_start = get_loop_start(coarse_polygon);
+
+ /* Find the number of vertices for the coarse polygon. */
+ Vertex v0, v1, v2, v3;
+ clear(v0);
+ clear(v1);
+ clear(v2);
+ clear(v3);
+
+ uint number_of_vertices = get_vertex_count(coarse_polygon);
+ if (number_of_vertices == 4) {
+ /* Interpolate the src data. */
+ v0 = read_vertex(loop_start + 0);
+ v1 = read_vertex(loop_start + 1);
+ v2 = read_vertex(loop_start + 2);
+ v3 = read_vertex(loop_start + 3);
+ }
+ else {
+ /* Interpolate the src data for the center. */
+ uint loop_end = loop_start + number_of_vertices - 1;
+ Vertex center_value;
+ clear(center_value);
+
+ float weight = 1.0 / float(number_of_vertices);
+
+ for (uint l = loop_start; l < loop_end; l++) {
+ add_with_weight(center_value, read_vertex(l), weight);
+ }
+
+ /* Interpolate between the previous and next corner for the middle values for the edges. */
+ uint patch_index = uint(patch_coords[start_loop_index].patch_index);
+ uint current_coarse_corner = get_polygon_corner_index(coarse_polygon, patch_index);
+ uint next_coarse_corner = (current_coarse_corner + 1) % number_of_vertices;
+ uint prev_coarse_corner = (current_coarse_corner + number_of_vertices - 1) %
+ number_of_vertices;
+
+ v0 = read_vertex(loop_start);
+ v1 = average(v0, read_vertex(loop_start + next_coarse_corner));
+ v3 = average(v0, read_vertex(loop_start + prev_coarse_corner));
+
+ /* Interpolate between the current value, and the ones for the center and mid-edges. */
+ v2 = center_value;
+ }
+
+ /* Do a linear interpolation of the data based on the UVs for each loop of this subdivided quad.
+ */
+ for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
+ BlenderPatchCoord co = patch_coords[loop_index];
+ vec2 uv = decode_uv(co.encoded_uv);
+ /* NOTE: v2 and v3 are reversed to stay consistent with the interpolation weight on the x-axis:
+ *
+ * v3 +-----+ v2
+ * | |
+ * | |
+ * v0 +-----+ v1
+ *
+ * otherwise, weight would be `1.0 - uv.x` for `v2 <-> v3`, but `uv.x` for `v0 <-> v1`.
+ */
+ Vertex result = interp_vertex(v0, v1, v3, v2, uv);
+ write_vertex(loop_index, result);
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl
new file mode 100644
index 00000000000..f11c0f6427e
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl
@@ -0,0 +1,57 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputEdgeOrigIndex
+{
+ int input_origindex[];
+};
+
+layout(std430, binding = 1) writeonly buffer outputLinesIndices
+{
+ uint output_lines[];
+};
+
+#ifndef LINES_LOOSE
+void emit_line(uint line_offset, uint start_loop_index, uint corner_index)
+{
+ uint vertex_index = start_loop_index + corner_index;
+
+ if (input_origindex[vertex_index] == ORIGINDEX_NONE && optimal_display) {
+ output_lines[line_offset + 0] = 0xffffffff;
+ output_lines[line_offset + 1] = 0xffffffff;
+ }
+ else {
+ /* Mod 4 so we loop back at the first vertex on the last loop index (3). */
+ uint next_vertex_index = start_loop_index + (corner_index + 1) % 4;
+
+ output_lines[line_offset + 0] = vertex_index;
+ output_lines[line_offset + 1] = next_vertex_index;
+ }
+}
+#endif
+
+void main()
+{
+ uint index = get_global_invocation_index();
+ if (index >= total_dispatch_size) {
+ return;
+ }
+
+#ifdef LINES_LOOSE
+ /* In the loose lines case, we execute for each line, with two vertices per line. */
+ uint line_offset = edge_loose_offset + index * 2;
+ uint loop_index = num_subdiv_loops + index * 2;
+ output_lines[line_offset] = loop_index;
+ output_lines[line_offset + 1] = loop_index + 1;
+#else
+ /* We execute for each quad, so the start index of the loop is quad_index * 4. */
+ uint start_loop_index = index * 4;
+ /* We execute for each quad, so the start index of the line is quad_index * 8 (with 2 vertices
+ * per line). */
+ uint start_line_index = index * 8;
+
+ for (int i = 0; i < 4; i++) {
+ emit_line(start_line_index + i * 2, start_loop_index, i);
+ }
+#endif
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl
new file mode 100644
index 00000000000..3257ebdae17
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl
@@ -0,0 +1,43 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+/* Generate triangles from subdivision quads indices. */
+
+layout(std430, binding = 1) writeonly buffer outputTriangles
+{
+ uint output_tris[];
+};
+
+#ifndef SINGLE_MATERIAL
+layout(std430, binding = 2) readonly buffer inputPolygonMatOffset
+{
+ int polygon_mat_offset[];
+};
+#endif
+
+void main()
+{
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint loop_index = quad_index * 4;
+
+#ifdef SINGLE_MATERIAL
+ uint triangle_loop_index = quad_index * 6;
+#else
+ uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
+ coarse_poly_count);
+ int mat_offset = polygon_mat_offset[coarse_quad_index];
+
+ int triangle_loop_index = (int(quad_index) + mat_offset) * 6;
+#endif
+
+ output_tris[triangle_loop_index + 0] = loop_index + 0;
+ output_tris[triangle_loop_index + 1] = loop_index + 1;
+ output_tris[triangle_loop_index + 2] = loop_index + 2;
+ output_tris[triangle_loop_index + 3] = loop_index + 0;
+ output_tris[triangle_loop_index + 4] = loop_index + 2;
+ output_tris[triangle_loop_index + 5] = loop_index + 3;
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
new file mode 100644
index 00000000000..9dd86c35ee4
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
@@ -0,0 +1,176 @@
+
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+
+/* Uniform block for #DRWSubivUboStorage. */
+layout(std140) uniform shader_data
+{
+ /* Offsets in the buffers data where the source and destination data start. */
+ int src_offset;
+ int dst_offset;
+
+ /* Parameters for the DRWPatchMap. */
+ int min_patch_face;
+ int max_patch_face;
+ int max_depth;
+ int patches_are_triangular;
+
+ /* Coarse topology information. */
+ int coarse_poly_count;
+ uint edge_loose_offset;
+
+ /* Subdiv topology information. */
+ uint num_subdiv_loops;
+
+ /* Subdivision settings. */
+ bool optimal_display;
+
+ /* Sculpt data. */
+ bool has_sculpt_mask;
+
+ /* Masks for the extra coarse face data. */
+ uint coarse_face_select_mask;
+ uint coarse_face_smooth_mask;
+ uint coarse_face_active_mask;
+ uint coarse_face_loopstart_mask;
+
+ /* Total number of elements to process. */
+ uint total_dispatch_size;
+};
+
+uint get_global_invocation_index()
+{
+ uint invocations_per_row = gl_WorkGroupSize.x * gl_NumWorkGroups.x;
+ return gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * invocations_per_row;
+}
+
+/* Structure for #CompressedPatchCoord. */
+struct BlenderPatchCoord {
+ int patch_index;
+ uint encoded_uv;
+};
+
+vec2 decode_uv(uint encoded_uv)
+{
+ float u = float((encoded_uv >> 16) & 0xFFFFu) / 65535.0;
+ float v = float(encoded_uv & 0xFFFFu) / 65535.0;
+ return vec2(u, v);
+}
+
+/* This structure is a carbon copy of OpenSubDiv's PatchTable::PatchHandle. */
+struct PatchHandle {
+ int array_index;
+ int patch_index;
+ int vertex_index;
+};
+
+/* This structure is a carbon copy of OpenSubDiv's PatchCoord. */
+struct PatchCoord {
+ int array_index;
+ int patch_index;
+ int vertex_index;
+ float u;
+ float v;
+};
+
+/* This structure is a carbon copy of OpenSubDiv's PatchCoord.QuadNode.
+ * Each child is a bitfield. */
+struct QuadNode {
+ uvec4 child;
+};
+
+bool is_set(uint i)
+{
+ /* QuadNode.Child.isSet is the first bit of the bitfield. */
+ return (i & 0x1u) != 0;
+}
+
+bool is_leaf(uint i)
+{
+ /* QuadNode.Child.isLeaf is the second bit of the bitfield. */
+ return (i & 0x2u) != 0;
+}
+
+uint get_index(uint i)
+{
+ /* QuadNode.Child.index is made of the remaining bits. */
+ return (i >> 2) & 0x3FFFFFFFu;
+}
+
+/* Duplicate of #PosNorLoop from the mesh extract CPU code.
+ * We do not use a vec3 for the position as it will be padded to a vec4 which is incompatible with
+ * the format. */
+struct PosNorLoop {
+ float x, y, z;
+ /* TODO(kevindietrich) : figure how to compress properly as GLSL does not have char/short types,
+ * bit operations get tricky. */
+ float nx, ny, nz;
+ float flag;
+};
+
+vec3 get_vertex_pos(PosNorLoop vertex_data)
+{
+ return vec3(vertex_data.x, vertex_data.y, vertex_data.z);
+}
+
+vec3 get_vertex_nor(PosNorLoop vertex_data)
+{
+ return vec3(vertex_data.nx, vertex_data.ny, vertex_data.nz);
+}
+
+void set_vertex_pos(inout PosNorLoop vertex_data, vec3 pos)
+{
+ vertex_data.x = pos.x;
+ vertex_data.y = pos.y;
+ vertex_data.z = pos.z;
+}
+
+void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor, uint flag)
+{
+ vertex_data.nx = nor.x;
+ vertex_data.ny = nor.y;
+ vertex_data.nz = nor.z;
+ vertex_data.flag = float(flag);
+}
+
+/* Set the vertex normal but preserve the existing flag. This is for when we compute manually the
+ * vertex normals when we cannot use the limit surface, in which case the flag and the normal are
+ * set by two separate compute pass. */
+void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor)
+{
+ set_vertex_nor(vertex_data, nor, 0);
+}
+
+#define ORIGINDEX_NONE -1
+
+#ifdef SUBDIV_POLYGON_OFFSET
+layout(std430, binding = 0) readonly buffer inputSubdivPolygonOffset
+{
+ uint subdiv_polygon_offset[];
+};
+
+/* Given the index of the subdivision quad, return the index of the corresponding coarse polygon.
+ * This uses subdiv_polygon_offset and since it is a growing list of offsets, we can use binary
+ * search to locate the right index. */
+uint coarse_polygon_index_from_subdiv_quad_index(uint subdiv_quad_index, uint coarse_poly_count)
+{
+ uint first = 0;
+ uint last = coarse_poly_count;
+
+ while (first != last) {
+ uint middle = (first + last) / 2;
+
+ if (subdiv_polygon_offset[middle] < subdiv_quad_index) {
+ first = middle + 1;
+ }
+ else {
+ last = middle;
+ }
+ }
+
+ if (subdiv_polygon_offset[first] == subdiv_quad_index) {
+ return first;
+ }
+
+ return first - 1;
+}
+#endif
diff --git a/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl
new file mode 100644
index 00000000000..575090472b1
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl
@@ -0,0 +1,56 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputVertexData
+{
+ PosNorLoop pos_nor[];
+};
+
+layout(std430, binding = 1) readonly buffer faceAdjacencyOffsets
+{
+ uint face_adjacency_offsets[];
+};
+
+layout(std430, binding = 2) readonly buffer faceAdjacencyLists
+{
+ uint face_adjacency_lists[];
+};
+
+layout(std430, binding = 3) writeonly buffer vertexNormals
+{
+ vec3 normals[];
+};
+
+void main()
+{
+ uint vertex_index = get_global_invocation_index();
+ if (vertex_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint first_adjacent_face_offset = face_adjacency_offsets[vertex_index];
+ uint number_of_adjacent_faces = face_adjacency_offsets[vertex_index + 1] -
+ first_adjacent_face_offset;
+
+ vec3 accumulated_normal = vec3(0.0);
+
+ /* For each adjacent face. */
+ for (uint i = 0; i < number_of_adjacent_faces; i++) {
+ uint adjacent_face = face_adjacency_lists[first_adjacent_face_offset + i];
+ uint start_loop_index = adjacent_face * 4;
+
+ /* Compute face normal. */
+ vec3 adjacent_verts[3];
+ for (uint j = 0; j < 3; j++) {
+ adjacent_verts[j] = get_vertex_pos(pos_nor[start_loop_index + j]);
+ }
+
+ vec3 face_normal = normalize(
+ cross(adjacent_verts[1] - adjacent_verts[0], adjacent_verts[2] - adjacent_verts[0]));
+ accumulated_normal += face_normal;
+ }
+
+ float weight = 1.0 / float(number_of_adjacent_faces);
+ vec3 normal = normalize(accumulated_normal);
+ normals[vertex_index] = normal;
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl
new file mode 100644
index 00000000000..84cd65d4161
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl
@@ -0,0 +1,34 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputNormals
+{
+ vec3 vertex_normals[];
+};
+
+layout(std430, binding = 1) readonly buffer inputSubdivVertLoopMap
+{
+ uint vert_loop_map[];
+};
+
+layout(std430, binding = 2) buffer outputPosNor
+{
+ PosNorLoop pos_nor[];
+};
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (int i = 0; i < 4; i++) {
+ uint subdiv_vert_index = vert_loop_map[start_loop_index + i];
+ vec3 nor = vertex_normals[subdiv_vert_index];
+ set_vertex_nor(pos_nor[start_loop_index + i], nor);
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
new file mode 100644
index 00000000000..5dd7decf663
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
@@ -0,0 +1,416 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+/* Source buffer. */
+layout(std430, binding = 0) buffer src_buffer
+{
+ float srcVertexBuffer[];
+};
+
+/* #DRWPatchMap */
+layout(std430, binding = 1) readonly buffer inputPatchHandles
+{
+ PatchHandle input_patch_handles[];
+};
+
+layout(std430, binding = 2) readonly buffer inputQuadNodes
+{
+ QuadNode quad_nodes[];
+};
+
+layout(std430, binding = 3) readonly buffer inputPatchCoords
+{
+ BlenderPatchCoord patch_coords[];
+};
+
+layout(std430, binding = 4) readonly buffer inputVertOrigIndices
+{
+ int input_vert_origindex[];
+};
+
+/* Patch buffers. */
+layout(std430, binding = 5) buffer patchArray_buffer
+{
+ OsdPatchArray patchArrayBuffer[];
+};
+
+layout(std430, binding = 6) buffer patchIndex_buffer
+{
+ int patchIndexBuffer[];
+};
+
+layout(std430, binding = 7) buffer patchParam_buffer
+{
+ OsdPatchParam patchParamBuffer[];
+};
+
+ /* Output buffer(s). */
+
+#if defined(FVAR_EVALUATION)
+layout(std430, binding = 8) writeonly buffer outputFVarData
+{
+ vec2 output_fvar[];
+};
+#elif defined(FDOTS_EVALUATION)
+/* For face dots, we build the position, normals, and index buffers in one go. */
+
+/* vec3 is padded to vec4, but the format used for fdots does not have any padding. */
+struct FDotVert {
+ float x, y, z;
+};
+
+/* Same here, do not use vec3. */
+struct FDotNor {
+ float x, y, z;
+ float flag;
+};
+
+layout(std430, binding = 8) writeonly buffer outputVertices
+{
+ FDotVert output_verts[];
+};
+
+layout(std430, binding = 9) writeonly buffer outputNormals
+{
+ FDotNor output_nors[];
+};
+
+layout(std430, binding = 10) writeonly buffer outputFdotsIndices
+{
+ uint output_indices[];
+};
+
+layout(std430, binding = 11) readonly buffer extraCoarseFaceData
+{
+ uint extra_coarse_face_data[];
+};
+#else
+layout(std430, binding = 8) writeonly buffer outputVertexData
+{
+ PosNorLoop output_verts[];
+};
+#endif
+
+vec2 read_vec2(int index)
+{
+ vec2 result;
+ result.x = srcVertexBuffer[index * 2];
+ result.y = srcVertexBuffer[index * 2 + 1];
+ return result;
+}
+
+vec3 read_vec3(int index)
+{
+ vec3 result;
+ result.x = srcVertexBuffer[index * 3];
+ result.y = srcVertexBuffer[index * 3 + 1];
+ result.z = srcVertexBuffer[index * 3 + 2];
+ return result;
+}
+
+OsdPatchArray GetPatchArray(int arrayIndex)
+{
+ return patchArrayBuffer[arrayIndex];
+}
+
+OsdPatchParam GetPatchParam(int patchIndex)
+{
+ return patchParamBuffer[patchIndex];
+}
+
+/* ------------------------------------------------------------------------------
+ * Patch Coordinate lookup. Return an OsdPatchCoord for the given patch_index and uvs.
+ * This code is a port of the OpenSubdiv PatchMap lookup code.
+ */
+
+PatchHandle bogus_patch_handle()
+{
+ PatchHandle ret;
+ ret.array_index = -1;
+ ret.vertex_index = -1;
+ ret.patch_index = -1;
+ return ret;
+}
+
+int transformUVToQuadQuadrant(float median, inout float u, inout float v)
+{
+ int uHalf = (u >= median) ? 1 : 0;
+ if (uHalf != 0)
+ u -= median;
+
+ int vHalf = (v >= median) ? 1 : 0;
+ if (vHalf != 0)
+ v -= median;
+
+ return (vHalf << 1) | uHalf;
+}
+
+int transformUVToTriQuadrant(float median, inout float u, inout float v, inout bool rotated)
+{
+
+ if (!rotated) {
+ if (u >= median) {
+ u -= median;
+ return 1;
+ }
+ if (v >= median) {
+ v -= median;
+ return 2;
+ }
+ if ((u + v) >= median) {
+ rotated = true;
+ return 3;
+ }
+ return 0;
+ }
+ else {
+ if (u < median) {
+ v -= median;
+ return 1;
+ }
+ if (v < median) {
+ u -= median;
+ return 2;
+ }
+ u -= median;
+ v -= median;
+ if ((u + v) < median) {
+ rotated = false;
+ return 3;
+ }
+ return 0;
+ }
+}
+
+PatchHandle find_patch(int face_index, float u, float v)
+{
+ if (face_index < min_patch_face || face_index > max_patch_face) {
+ return bogus_patch_handle();
+ }
+
+ QuadNode node = quad_nodes[face_index - min_patch_face];
+
+ if (!is_set(node.child[0])) {
+ return bogus_patch_handle();
+ }
+
+ float median = 0.5;
+ bool tri_rotated = false;
+
+ for (int depth = 0; depth <= max_depth; ++depth, median *= 0.5) {
+ int quadrant = (patches_are_triangular != 0) ?
+ transformUVToTriQuadrant(median, u, v, tri_rotated) :
+ transformUVToQuadQuadrant(median, u, v);
+
+ if (is_leaf(node.child[quadrant])) {
+ return input_patch_handles[get_index(node.child[quadrant])];
+ }
+
+ node = quad_nodes[get_index(node.child[quadrant])];
+ }
+}
+
+OsdPatchCoord bogus_patch_coord(int face_index, float u, float v)
+{
+ OsdPatchCoord coord;
+ coord.arrayIndex = 0;
+ coord.patchIndex = face_index;
+ coord.vertIndex = 0;
+ coord.s = u;
+ coord.t = v;
+ return coord;
+}
+
+OsdPatchCoord GetPatchCoord(int face_index, float u, float v)
+{
+ PatchHandle patch_handle = find_patch(face_index, u, v);
+
+ if (patch_handle.array_index == -1) {
+ return bogus_patch_coord(face_index, u, v);
+ }
+
+ OsdPatchCoord coord;
+ coord.arrayIndex = patch_handle.array_index;
+ coord.patchIndex = patch_handle.patch_index;
+ coord.vertIndex = patch_handle.vertex_index;
+ coord.s = u;
+ coord.t = v;
+ return coord;
+}
+
+/* ------------------------------------------------------------------------------
+ * Patch evaluation. Note that the 1st and 2nd derivatives are always computed, although we
+ * only return and use the 1st derivatives if adaptive patches are used. This could
+ * perhaps be optimized.
+ */
+
+#if defined(FVAR_EVALUATION)
+void evaluate_patches_limits(int patch_index, float u, float v, inout vec2 dst)
+{
+ OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
+ OsdPatchArray array = GetPatchArray(coord.arrayIndex);
+ OsdPatchParam param = GetPatchParam(coord.patchIndex);
+
+ int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
+
+ float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
+ int nPoints = OsdEvaluatePatchBasis(
+ patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
+
+ int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);
+
+ for (int cv = 0; cv < nPoints; ++cv) {
+ int index = patchIndexBuffer[indexBase + cv];
+ vec2 src_fvar = read_vec2(src_offset + index);
+ dst += src_fvar * wP[cv];
+ }
+}
+#else
+void evaluate_patches_limits(
+ int patch_index, float u, float v, inout vec3 dst, inout vec3 du, inout vec3 dv)
+{
+ OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
+ OsdPatchArray array = GetPatchArray(coord.arrayIndex);
+ OsdPatchParam param = GetPatchParam(coord.patchIndex);
+
+ int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
+
+ float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
+ int nPoints = OsdEvaluatePatchBasis(
+ patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
+
+ int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);
+
+ for (int cv = 0; cv < nPoints; ++cv) {
+ int index = patchIndexBuffer[indexBase + cv];
+ vec3 src_vertex = read_vec3(index);
+
+ dst += src_vertex * wP[cv];
+ du += src_vertex * wDu[cv];
+ dv += src_vertex * wDv[cv];
+ }
+}
+#endif
+
+/* ------------------------------------------------------------------------------
+ * Entry point.
+ */
+
+#if defined(FVAR_EVALUATION)
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
+ vec2 fvar = vec2(0.0);
+
+ BlenderPatchCoord patch_co = patch_coords[loop_index];
+ vec2 uv = decode_uv(patch_co.encoded_uv);
+
+ evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, fvar);
+ output_fvar[dst_offset + loop_index] = fvar;
+ }
+}
+#elif defined(FDOTS_EVALUATION)
+bool is_face_selected(uint coarse_quad_index)
+{
+ return (extra_coarse_face_data[coarse_quad_index] & coarse_face_select_mask) != 0;
+}
+
+bool is_face_active(uint coarse_quad_index)
+{
+ return (extra_coarse_face_data[coarse_quad_index] & coarse_face_active_mask) != 0;
+}
+
+float get_face_flag(uint coarse_quad_index)
+{
+ if (is_face_active(coarse_quad_index)) {
+ return -1.0;
+ }
+
+ if (is_face_selected(coarse_quad_index)) {
+ return 1.0;
+ }
+
+ return 0.0;
+}
+
+void main()
+{
+ /* We execute for each coarse quad. */
+ uint coarse_quad_index = get_global_invocation_index();
+ if (coarse_quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ BlenderPatchCoord patch_co = patch_coords[coarse_quad_index];
+ vec2 uv = decode_uv(patch_co.encoded_uv);
+
+ vec3 pos = vec3(0.0);
+ vec3 du = vec3(0.0);
+ vec3 dv = vec3(0.0);
+ evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv);
+ vec3 nor = normalize(cross(du, dv));
+
+ FDotVert vert;
+ vert.x = pos.x;
+ vert.y = pos.y;
+ vert.z = pos.z;
+
+ FDotNor fnor;
+ fnor.x = nor.x;
+ fnor.y = nor.y;
+ fnor.z = nor.z;
+ fnor.flag = get_face_flag(coarse_quad_index);
+
+ output_verts[coarse_quad_index] = vert;
+ output_nors[coarse_quad_index] = fnor;
+ output_indices[coarse_quad_index] = coarse_quad_index;
+}
+#else
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
+ vec3 pos = vec3(0.0);
+ vec3 du = vec3(0.0);
+ vec3 dv = vec3(0.0);
+
+ BlenderPatchCoord patch_co = patch_coords[loop_index];
+ vec2 uv = decode_uv(patch_co.encoded_uv);
+
+ evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv);
+
+# if defined(LIMIT_NORMALS)
+ vec3 nor = normalize(cross(du, dv));
+# else
+ /* This will be computed later. */
+ vec3 nor = vec3(0.0);
+# endif
+
+ int origindex = input_vert_origindex[loop_index];
+ uint flag = 0;
+ if (origindex == -1) {
+ flag = -1;
+ }
+
+ PosNorLoop vertex_data;
+ set_vertex_pos(vertex_data, pos);
+ set_vertex_nor(vertex_data, nor, flag);
+ output_verts[loop_index] = vertex_data;
+ }
+}
+#endif
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl
new file mode 100644
index 00000000000..6c76cd41ca4
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl
@@ -0,0 +1,97 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputVertexData
+{
+ PosNorLoop pos_nor[];
+};
+
+layout(std430, binding = 1) readonly buffer inputEdgeIndex
+{
+ uint input_edge_index[];
+};
+
+layout(std430, binding = 2) writeonly buffer outputEdgeFactors
+{
+#ifdef GPU_AMD_DRIVER_BYTE_BUG
+ float output_edge_fac[];
+#else
+ uint output_edge_fac[];
+#endif
+};
+
+void write_vec4(uint index, vec4 edge_facs)
+{
+#ifdef GPU_AMD_DRIVER_BYTE_BUG
+ for (uint i = 0; i < 4; i++) {
+ output_edge_fac[index + i] = edge_facs[i];
+ }
+#else
+ /* Use same scaling as in extract_edge_fac_iter_poly_mesh. */
+ uint a = uint(clamp(edge_facs.x * 253.0 + 1.0, 0.0, 255.0));
+ uint b = uint(clamp(edge_facs.y * 253.0 + 1.0, 0.0, 255.0));
+ uint c = uint(clamp(edge_facs.z * 253.0 + 1.0, 0.0, 255.0));
+ uint d = uint(clamp(edge_facs.w * 253.0 + 1.0, 0.0, 255.0));
+ uint packed_edge_fac = a << 24 | b << 16 | c << 8 | d;
+ output_edge_fac[index] = packed_edge_fac;
+#endif
+}
+
+/* From extract_mesh_vbo_edge_fac.cc, keep in sync! */
+float loop_edge_factor_get(vec3 f_no, vec3 v_co, vec3 v_no, vec3 v_next_co)
+{
+ vec3 evec = v_next_co - v_co;
+ vec3 enor = normalize(cross(v_no, evec));
+ float d = abs(dot(enor, f_no));
+ /* Re-scale to the slider range. */
+ d *= (1.0 / 0.065);
+ return clamp(d, 0.0, 1.0);
+}
+
+float compute_line_factor(uint start_loop_index, uint corner_index, vec3 face_normal)
+{
+ uint vertex_index = start_loop_index + corner_index;
+ uint edge_index = input_edge_index[vertex_index];
+
+ if (edge_index == -1 && optimal_display) {
+ return 0.0;
+ }
+
+ /* Mod 4 so we loop back at the first vertex on the last loop index (3), but only the corner
+ * index needs to be wrapped. */
+ uint next_vertex_index = start_loop_index + (corner_index + 1) % 4;
+ vec3 vertex_pos = get_vertex_pos(pos_nor[vertex_index]);
+ vec3 vertex_nor = get_vertex_nor(pos_nor[vertex_index]);
+ vec3 next_vertex_pos = get_vertex_pos(pos_nor[next_vertex_index]);
+ return loop_edge_factor_get(face_normal, vertex_pos, vertex_nor, next_vertex_pos);
+}
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ /* The start index of the loop is quad_index * 4. */
+ uint start_loop_index = quad_index * 4;
+
+ /* First compute the face normal, we need it to compute the bihedral edge angle. */
+ vec3 v0 = get_vertex_pos(pos_nor[start_loop_index + 0]);
+ vec3 v1 = get_vertex_pos(pos_nor[start_loop_index + 1]);
+ vec3 v2 = get_vertex_pos(pos_nor[start_loop_index + 2]);
+ vec3 face_normal = normalize(cross(v1 - v0, v2 - v0));
+
+ vec4 edge_facs = vec4(0.0);
+ for (int i = 0; i < 4; i++) {
+ edge_facs[i] = compute_line_factor(start_loop_index, i, face_normal);
+ }
+
+#ifdef GPU_AMD_DRIVER_BYTE_BUG
+ write_vec4(start_loop_index, edge_facs);
+#else
+ /* When packed into bytes, the index is the same as for the quad. */
+ write_vec4(quad_index, edge_facs);
+#endif
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl
new file mode 100644
index 00000000000..ea73b9482d3
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl
@@ -0,0 +1,80 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputVerts
+{
+ PosNorLoop pos_nor[];
+};
+
+layout(std430, binding = 1) readonly buffer inputUVs
+{
+ vec2 uvs[];
+};
+
+/* Mirror of #UVStretchAngle in the C++ code, but using floats until proper data compression
+ * is implemented for all subdivision data. */
+struct UVStretchAngle {
+ float angle;
+ float uv_angle0;
+ float uv_angle1;
+};
+
+layout(std430, binding = 2) writeonly buffer outputStretchAngles
+{
+ UVStretchAngle uv_stretches[];
+};
+
+#define M_PI 3.1415926535897932
+#define M_1_PI 0.31830988618379067154
+
+/* Adapted from BLI_math_vector.h */
+float angle_normalized_v3v3(vec3 v1, vec3 v2)
+{
+ /* this is the same as acos(dot_v3v3(v1, v2)), but more accurate */
+ bool q = (dot(v1, v2) >= 0.0);
+ vec3 v = (q) ? (v1 - v2) : (v1 + v2);
+ float a = 2.0 * asin(length(v) / 2.0);
+ return (q) ? a : M_PI - a;
+}
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (uint i = 0; i < 4; i++) {
+ uint cur_loop_index = start_loop_index + i;
+ uint next_loop_index = start_loop_index + (i + 1) % 4;
+ uint prev_loop_index = start_loop_index + (i + 3) % 4;
+
+ /* Compute 2d edge vectors from UVs. */
+ vec2 cur_uv = uvs[src_offset + cur_loop_index];
+ vec2 next_uv = uvs[src_offset + next_loop_index];
+ vec2 prev_uv = uvs[src_offset + prev_loop_index];
+
+ vec2 norm_uv_edge0 = normalize(prev_uv - cur_uv);
+ vec2 norm_uv_edge1 = normalize(cur_uv - next_uv);
+
+ /* Compute 3d edge vectors from positions. */
+ vec3 cur_pos = get_vertex_pos(pos_nor[cur_loop_index]);
+ vec3 next_pos = get_vertex_pos(pos_nor[next_loop_index]);
+ vec3 prev_pos = get_vertex_pos(pos_nor[prev_loop_index]);
+
+ vec3 norm_pos_edge0 = normalize(prev_pos - cur_pos);
+ vec3 norm_pos_edge1 = normalize(cur_pos - next_pos);
+
+ /* Compute stretches, this logic is adapted from #edituv_get_edituv_stretch_angle.
+ * Keep in sync! */
+ UVStretchAngle stretch;
+ stretch.uv_angle0 = atan(norm_uv_edge0.y, norm_uv_edge0.x) * M_1_PI;
+ stretch.uv_angle1 = atan(norm_uv_edge1.y, norm_uv_edge1.x) * M_1_PI;
+ stretch.angle = angle_normalized_v3v3(norm_pos_edge0, norm_pos_edge1) * M_1_PI;
+
+ uv_stretches[cur_loop_index] = stretch;
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl
new file mode 100644
index 00000000000..e897fb3f3c0
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl
@@ -0,0 +1,31 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 1) readonly buffer inputCoarseData
+{
+ float coarse_stretch_area[];
+};
+
+layout(std430, binding = 2) writeonly buffer outputSubdivData
+{
+ float subdiv_stretch_area[];
+};
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ /* The start index of the loop is quad_index * 4. */
+ uint start_loop_index = quad_index * 4;
+
+ uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
+ coarse_poly_count);
+
+ for (int i = 0; i < 4; i++) {
+ subdiv_stretch_area[start_loop_index + i] = coarse_stretch_area[coarse_quad_index];
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl
new file mode 100644
index 00000000000..41a8df3cf82
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl
@@ -0,0 +1,52 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 1) readonly buffer inputVertexData
+{
+ PosNorLoop pos_nor[];
+};
+
+layout(std430, binding = 2) readonly buffer extraCoarseFaceData
+{
+ uint extra_coarse_face_data[];
+};
+
+layout(std430, binding = 3) writeonly buffer outputLoopNormals
+{
+ vec3 output_lnor[];
+};
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ /* The start index of the loop is quad_index * 4. */
+ uint start_loop_index = quad_index * 4;
+
+ uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
+ coarse_poly_count);
+
+ if ((extra_coarse_face_data[coarse_quad_index] & coarse_face_smooth_mask) != 0) {
+ /* Face is smooth, use vertex normals. */
+ for (int i = 0; i < 4; i++) {
+ PosNorLoop pos_nor_loop = pos_nor[start_loop_index + i];
+ output_lnor[start_loop_index + i] = get_vertex_nor(pos_nor_loop);
+ }
+ }
+ else {
+ /* Face is flat shaded, compute flat face normal from an inscribed triangle. */
+ vec3 verts[3];
+ for (int i = 0; i < 3; i++) {
+ verts[i] = get_vertex_pos(pos_nor[start_loop_index + i]);
+ }
+
+ vec3 face_normal = normalize(cross(verts[1] - verts[0], verts[2] - verts[0]));
+ for (int i = 0; i < 4; i++) {
+ output_lnor[start_loop_index + i] = face_normal;
+ }
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl
new file mode 100644
index 00000000000..7182ce57ad3
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl
@@ -0,0 +1,47 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+struct SculptData {
+ uint face_set_color;
+ float mask;
+};
+
+layout(std430, binding = 0) readonly restrict buffer sculptMask
+{
+ float sculpt_mask[];
+};
+
+layout(std430, binding = 1) readonly restrict buffer faceSetColor
+{
+ uint face_set_color[];
+};
+
+layout(std430, binding = 2) writeonly restrict buffer sculptData
+{
+ SculptData sculpt_data[];
+};
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
+ SculptData data;
+ data.face_set_color = face_set_color[loop_index];
+
+ if (has_sculpt_mask) {
+ data.mask = sculpt_mask[loop_index];
+ }
+ else {
+ data.mask = 0.0;
+ }
+
+ sculpt_data[loop_index] = data;
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_view_clipping_lib.glsl b/source/blender/draw/intern/shaders/common_view_clipping_lib.glsl
new file mode 100644
index 00000000000..d55808c42d2
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_view_clipping_lib.glsl
@@ -0,0 +1,33 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
+#if defined(GPU_VERTEX_SHADER) || defined(GPU_GEOMETRY_SHADER)
+
+void view_clipping_distances(vec3 wpos)
+{
+# ifdef USE_WORLD_CLIP_PLANES
+ vec4 pos = vec4(wpos, 1.0);
+ gl_ClipDistance[0] = dot(drw_view.clip_planes[0], pos);
+ gl_ClipDistance[1] = dot(drw_view.clip_planes[1], pos);
+ gl_ClipDistance[2] = dot(drw_view.clip_planes[2], pos);
+ gl_ClipDistance[3] = dot(drw_view.clip_planes[3], pos);
+ gl_ClipDistance[4] = dot(drw_view.clip_planes[4], pos);
+ gl_ClipDistance[5] = dot(drw_view.clip_planes[5], pos);
+# endif
+}
+
+/* Kept as define for compiler compatibility. */
+# ifdef USE_WORLD_CLIP_PLANES
+# define view_clipping_distances_set(c) \
+ gl_ClipDistance[0] = (c).gl_ClipDistance[0]; \
+ gl_ClipDistance[1] = (c).gl_ClipDistance[1]; \
+ gl_ClipDistance[2] = (c).gl_ClipDistance[2]; \
+ gl_ClipDistance[3] = (c).gl_ClipDistance[3]; \
+ gl_ClipDistance[4] = (c).gl_ClipDistance[4]; \
+ gl_ClipDistance[5] = (c).gl_ClipDistance[5];
+
+# else
+# define view_clipping_distances_set(c)
+# endif
+
+#endif
diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl
index 23feeae3e8b..573ad046ea9 100644
--- a/source/blender/draw/intern/shaders/common_view_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_view_lib.glsl
@@ -1,5 +1,7 @@
-#define COMMON_VIEW_LIB
-#define DRW_RESOURCE_CHUNK_LEN 512
+/* Temporary until we fully make the switch. */
+#ifndef DRW_SHADER_SHARED_H
+
+# define DRW_RESOURCE_CHUNK_LEN 512
/* keep in sync with DRWManager.view_data */
layout(std140) uniform viewBlock
@@ -27,6 +29,8 @@ layout(std140) uniform viewBlock
vec4 frustum_planes[6];
};
+#endif /* DRW_SHADER_SHARED_H */
+
#define ViewNear (ViewVecs[0].w)
#define ViewFar (ViewVecs[1].w)
@@ -85,67 +89,96 @@ vec4 pack_line_data(vec2 frag_co, vec2 edge_start, vec2 edge_pos)
}
}
-uniform int resourceChunk;
+/* Temporary until we fully make the switch. */
+#ifndef DRW_SHADER_SHARED_H
+uniform int drw_resourceChunk;
+#endif /* DRW_SHADER_SHARED_H */
#ifdef GPU_VERTEX_SHADER
-# ifdef GPU_ARB_shader_draw_parameters
-# define baseInstance gl_BaseInstanceARB
-# else /* no ARB_shader_draw_parameters */
-uniform int baseInstance;
-# endif
-# if defined(IN_PLACE_INSTANCES) || defined(INSTANCED_ATTR)
-/* When drawing instances of an object at the same position. */
-# define instanceId 0
-# elif defined(GPU_DEPRECATED_AMD_DRIVER)
-/* A driver bug make it so that when using an attribute with GL_INT_2_10_10_10_REV as format,
- * the gl_InstanceID is incremented by the 2 bit component of the attribute.
- * Ignore gl_InstanceID then. */
-# define instanceId 0
-# else
-# define instanceId gl_InstanceID
-# endif
+/* Temporary until we fully make the switch. */
+# ifndef DRW_SHADER_SHARED_H
-# ifdef UNIFORM_RESOURCE_ID
-/* This is in the case we want to do a special instance drawcall but still want to have the
- * right resourceId and all the correct ubo datas. */
-uniform int resourceId;
-# define resource_id resourceId
-# else
-# define resource_id (baseInstance + instanceId)
-# endif
+/* clang-format off */
+# if defined(IN_PLACE_INSTANCES) || defined(INSTANCED_ATTR) || defined(DRW_LEGACY_MODEL_MATRIX) || defined(GPU_DEPRECATED_AMD_DRIVER)
+/* clang-format on */
+/* When drawing instances of an object at the same position. */
+# define instanceId 0
+# else
+# define instanceId gl_InstanceID
+# endif
+
+# if defined(UNIFORM_RESOURCE_ID)
+/* This is in the case we want to do a special instance drawcall for one object but still want to
+ * have the right resourceId and all the correct ubo datas. */
+uniform int drw_ResourceID;
+# define resource_id drw_ResourceID
+# else
+# define resource_id (gpu_BaseInstance + instanceId)
+# endif
/* Use this to declare and pass the value if
* the fragment shader uses the 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;
+# 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 /* DRW_SHADER_SHARED_H */
+
+#endif /* GPU_VERTEX_SHADER */
+
+/* Temporary until we fully make the switch. */
+#ifdef DRW_SHADER_SHARED_H
+/* TODO(fclem): Rename PASS_RESOURCE_ID to DRW_RESOURCE_ID_VARYING_SET */
+# if defined(UNIFORM_RESOURCE_ID)
+# define resource_id drw_ResourceID
+# define PASS_RESOURCE_ID
+
+# elif defined(GPU_VERTEX_SHADER)
+# define resource_id gpu_InstanceIndex
+# define PASS_RESOURCE_ID drw_ResourceID_iface.resource_index = resource_id;
+
+# elif defined(GPU_GEOMETRY_SHADER)
+# define resource_id drw_ResourceID_iface_in[0].index
+# define PASS_RESOURCE_ID drw_ResourceID_iface_out.resource_index = resource_id;
+
+# elif defined(GPU_FRAGMENT_SHADER)
+# define resource_id drw_ResourceID_iface.resource_index
# endif
-#endif
+/* TODO(fclem): Remove. */
+# define RESOURCE_ID_VARYING
+
+#else
/* If used in a fragment / geometry shader, we pass
* resource_id as varying. */
-#ifdef GPU_GEOMETRY_SHADER
-# define RESOURCE_ID_VARYING \
- flat out int resourceIDFrag; \
- flat in int resourceIDGeom[];
+# ifdef GPU_GEOMETRY_SHADER
+# define RESOURCE_ID_VARYING \
+ flat out int resourceIDFrag; \
+ flat in int resourceIDGeom[];
-# define resource_id resourceIDGeom
-# define PASS_RESOURCE_ID resourceIDFrag = resource_id[0];
-#endif
+# define resource_id resourceIDGeom
+# define PASS_RESOURCE_ID resourceIDFrag = resource_id[0];
+# endif
-#ifdef GPU_FRAGMENT_SHADER
+# ifdef GPU_FRAGMENT_SHADER
flat in int resourceIDFrag;
-# define resource_id resourceIDFrag
+# define resource_id resourceIDFrag
+# endif
#endif
/* Breaking this across multiple lines causes issues for some older GLSL compilers. */
/* clang-format off */
-#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC) && !defined(INSTANCED_ATTR)
+#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC) && !defined(INSTANCED_ATTR) && !defined(DRW_LEGACY_MODEL_MATRIX)
/* clang-format on */
+
+/* Temporary until we fully make the switch. */
+# ifndef DRW_SHADER_SHARED_H
+
struct ObjectMatrices {
mat4 drw_modelMatrix;
mat4 drw_modelMatrixInverse;
@@ -156,19 +189,28 @@ layout(std140) uniform modelBlock
ObjectMatrices drw_matrices[DRW_RESOURCE_CHUNK_LEN];
};
-# define ModelMatrix (drw_matrices[resource_id].drw_modelMatrix)
-# define ModelMatrixInverse (drw_matrices[resource_id].drw_modelMatrixInverse)
+# define ModelMatrix (drw_matrices[resource_id].drw_modelMatrix)
+# define ModelMatrixInverse (drw_matrices[resource_id].drw_modelMatrixInverse)
+# endif /* DRW_SHADER_SHARED_H */
#else /* GPU_INTEL */
+
+/* Temporary until we fully make the switch. */
+# ifndef DRW_SHADER_SHARED_H
/* Intel GPU seems to suffer performance impact when the model matrix is in UBO storage.
* So for now we just force using the legacy path. */
/* Note that this is also a workaround of a problem on osx (amd or nvidia)
* and older amd driver on windows. */
uniform mat4 ModelMatrix;
uniform mat4 ModelMatrixInverse;
+# endif /* DRW_SHADER_SHARED_H */
+
#endif
-#define resource_handle (resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id)
+/* Temporary until we fully make the switch. */
+#ifndef DRW_SHADER_SHARED_H
+# define resource_handle (drw_resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id)
+#endif
/** Transform shortcuts. */
/* Rule of thumb: Try to reuse world positions and normals because converting through viewspace
@@ -184,7 +226,7 @@ uniform mat4 ModelMatrixInverse;
* transpose(ViewMatrixInverse) * transpose(ModelMatrixInverse)
*
* Knowing that the view matrix is orthogonal, the transpose is also the inverse.
- * Note: This is only valid because we are only using the mat3 of the ViewMatrixInverse.
+ * NOTE: This is only valid because we are only using the mat3 of the ViewMatrixInverse.
* ViewMatrix * transpose(ModelMatrixInverse)
*/
#define NormalMatrix transpose(mat3(ModelMatrixInverse))
diff --git a/source/blender/draw/intern/shaders/draw_fullscreen_info.hh b/source/blender/draw/intern/shaders/draw_fullscreen_info.hh
new file mode 100644
index 00000000000..803ad69ffb7
--- /dev/null
+++ b/source/blender/draw/intern/shaders/draw_fullscreen_info.hh
@@ -0,0 +1,8 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(fullscreen_iface, "").smooth(Type::VEC4, "uvcoordsvar");
+
+GPU_SHADER_CREATE_INFO(draw_fullscreen)
+ .vertex_out(fullscreen_iface)
+ .vertex_source("common_fullscreen_vert.glsl");
diff --git a/source/blender/draw/intern/shaders/draw_hair_refine_info.hh b/source/blender/draw/intern/shaders/draw_hair_refine_info.hh
new file mode 100644
index 00000000000..3c1af1bf759
--- /dev/null
+++ b/source/blender/draw/intern/shaders/draw_hair_refine_info.hh
@@ -0,0 +1,42 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(draw_hair_refine_compute)
+ .local_group_size(1, 1)
+ .storage_buf(0, Qualifier::WRITE_ONLY, "vec4", "posTime[]")
+ .sampler(0, ImageType::FLOAT_BUFFER, "hairPointBuffer")
+ .sampler(1, ImageType::UINT_BUFFER, "hairStrandBuffer")
+ .sampler(2, ImageType::UINT_BUFFER, "hairStrandSegBuffer")
+ .push_constant(0, Type::VEC4, "hairDupliMatrix", 4)
+ .push_constant(16, Type::BOOL, "hairCloseTip")
+ .push_constant(17, Type::FLOAT, "hairRadShape")
+ .push_constant(18, Type::FLOAT, "hairRadTip")
+ .push_constant(19, Type::FLOAT, "hairRadRoot")
+ .push_constant(20, Type::INT, "hairThicknessRes")
+ .push_constant(21, Type::INT, "hairStrandsRes")
+ .push_constant(22, Type::INT, "hairStrandOffset")
+ .compute_source("common_hair_refine_comp.glsl")
+ .define("HAIR_PHASE_SUBDIV")
+ .do_static_compilation(true);
diff --git a/source/blender/draw/intern/shaders/draw_object_infos_info.hh b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
new file mode 100644
index 00000000000..17a32c7d5ed
--- /dev/null
+++ b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
@@ -0,0 +1,6 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(draw_object_infos)
+ .typedef_source("draw_shader_shared.h")
+ .uniform_buf(1, "ObjectInfos", "drw_infos[DRW_RESOURCE_CHUNK_LEN]", Frequency::BATCH);
diff --git a/source/blender/draw/intern/shaders/draw_view_info.hh b/source/blender/draw/intern/shaders/draw_view_info.hh
new file mode 100644
index 00000000000..d40f51df543
--- /dev/null
+++ b/source/blender/draw/intern/shaders/draw_view_info.hh
@@ -0,0 +1,105 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Resource ID
+ *
+ * This is used to fetch per object data in drw_matrices and other object indexed
+ * buffers. There is multiple possibilities depending on how we are drawing the object.
+ *
+ * \{ */
+
+/* Standard way. Use gpu_InstanceIndex to index the object data. */
+GPU_SHADER_CREATE_INFO(draw_resource_id).define("DYNAMIC_RESOURCE_ID");
+
+/**
+ * Used if the resource index needs to be passed to the fragment shader.
+ * IMPORTANT: Vertex and Geometry shaders need to use PASS_RESOURCE_ID in main().
+ */
+GPU_SHADER_INTERFACE_INFO(draw_resource_id_iface, "drw_ResourceID_iface")
+ .flat(Type::INT, "resource_index");
+
+GPU_SHADER_CREATE_INFO(draw_resource_id_varying)
+ .vertex_out(draw_resource_id_iface)
+ .geometry_out(draw_resource_id_iface); /* Used if needed. */
+
+/* Variation used when drawing multiple instances for one object. */
+GPU_SHADER_CREATE_INFO(draw_resource_id_uniform)
+ .define("UNIFORM_RESOURCE_ID")
+ .push_constant(64, Type::INT, "drw_ResourceID");
+
+/**
+ * Declare a resource handle that identify a unique object.
+ * Requires draw_resource_id[_constant].
+ */
+GPU_SHADER_CREATE_INFO(draw_resource_handle)
+ .define("resource_handle (drw_resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id)")
+ .push_constant(63, Type::INT, "drw_resourceChunk");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw View
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(draw_view)
+ .uniform_buf(0, "ViewInfos", "drw_view", Frequency::PASS)
+ .typedef_source("draw_shader_shared.h");
+
+GPU_SHADER_CREATE_INFO(draw_modelmat)
+ .uniform_buf(8, "ObjectMatrices", "drw_matrices[DRW_RESOURCE_CHUNK_LEN]", Frequency::BATCH)
+ .define("ModelMatrix", "(drw_matrices[resource_id].drw_modelMatrix)")
+ .define("ModelMatrixInverse", "(drw_matrices[resource_id].drw_modelMatrixInverse)")
+ .additional_info("draw_view");
+
+GPU_SHADER_CREATE_INFO(draw_modelmat_legacy)
+ .define("DRW_LEGACY_MODEL_MATRIX")
+ .push_constant(38, Type::MAT4, "ModelMatrix")
+ .push_constant(54, Type::MAT4, "ModelMatrixInverse")
+ .additional_info("draw_view");
+
+GPU_SHADER_CREATE_INFO(draw_modelmat_instanced_attr)
+ .push_constant(0, Type::MAT4, "ModelMatrix")
+ .push_constant(16, Type::MAT4, "ModelMatrixInverse")
+ .additional_info("draw_view");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw View
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(drw_clipped).define("USE_WORLD_CLIP_PLANES");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(draw_mesh).additional_info("draw_modelmat", "draw_resource_id");
+
+GPU_SHADER_CREATE_INFO(draw_hair)
+ .sampler(15, ImageType::FLOAT_BUFFER, "hairPointBuffer")
+ .sampler(14, ImageType::UINT_BUFFER, "hairStrandBuffer")
+ .sampler(13, ImageType::UINT_BUFFER, "hairStrandSegBuffer")
+ /* TODO(fclem) Pack thoses into one UBO. */
+ .push_constant(9, Type::INT, "hairStrandsRes")
+ .push_constant(10, Type::INT, "hairThicknessRes")
+ .push_constant(11, Type::FLOAT, "hairRadRoot")
+ .push_constant(12, Type::FLOAT, "hairRadTip")
+ .push_constant(13, Type::FLOAT, "hairRadShape")
+ .push_constant(14, Type::BOOL, "hairCloseTip")
+ .push_constant(15, Type::INT, "hairStrandOffset")
+ .push_constant(16, Type::VEC4, "hairDupliMatrix", 4)
+ .additional_info("draw_modelmat", "draw_resource_id");
+
+GPU_SHADER_CREATE_INFO(draw_pointcloud)
+ .vertex_in(0, Type::VEC4, "pos")
+ .vertex_in(1, Type::VEC3, "pos_inst")
+ .vertex_in(2, Type::VEC3, "nor")
+ .additional_info("draw_modelmat_instanced_attr", "draw_resource_id_uniform");
+
+GPU_SHADER_CREATE_INFO(draw_volume).additional_info("draw_modelmat", "draw_resource_id_uniform");
+
+/** \} */
diff --git a/source/blender/draw/intern/smaa_textures.c b/source/blender/draw/intern/smaa_textures.c
new file mode 100644
index 00000000000..b34a641d838
--- /dev/null
+++ b/source/blender/draw/intern/smaa_textures.c
@@ -0,0 +1,15068 @@
+/**
+ * Copyright (C) 2013 Jorge Jimenez <jorge@iryoku.com>
+ * Copyright (C) 2013 Jose I. Echevarria <joseignacioechevarria@gmail.com>
+ * Copyright (C) 2013 Belen Masia <bmasia@unizar.es>
+ * Copyright (C) 2013 Fernando Navarro <fernandn@microsoft.com>
+ * Copyright (C) 2013 Diego Gutierrez <diegog@unizar.es>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to
+ * do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software. As clarification, there
+ * is no requirement that the copyright notice and permission be included in
+ * binary distributions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "smaa_textures.h"
+
+/* Don't re-wrap large data definitions. */
+/* clang-format off */
+
+/**
+ * Stored in R8G8 format. Load it in the following format:
+ * - DX10: DXGI_FORMAT_R8G8_UNORM
+ */
+const unsigned char areaTexBytes[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x44, 0x7b, 0x41, 0x5d,
+ 0x42, 0x54, 0x41, 0x4f, 0x42, 0x4b, 0x42, 0x49, 0x42, 0x48, 0x41, 0x47,
+ 0x42, 0x46, 0x42, 0x45, 0x42, 0x45, 0x42, 0x44, 0x42, 0x44, 0x42, 0x44,
+ 0x42, 0x43, 0x41, 0x43, 0x42, 0x43, 0x42, 0x43, 0x42, 0x43, 0x42, 0x43,
+ 0x04, 0x7f, 0x22, 0x3d, 0x2b, 0x3d, 0x30, 0x3d, 0x33, 0x3d, 0x35, 0x3d,
+ 0x37, 0x3d, 0x38, 0x3d, 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
+ 0x3b, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d,
+ 0x3c, 0x3d, 0x3c, 0x3d, 0x40, 0x7f, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x62, 0x20, 0x4d, 0x2a, 0x48, 0x30, 0x44, 0x33,
+ 0x44, 0x35, 0x44, 0x36, 0x43, 0x37, 0x42, 0x38, 0x43, 0x39, 0x42, 0x39,
+ 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b, 0x42, 0x3b, 0x42, 0x3b, 0x41, 0x3b,
+ 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c, 0x00, 0x5d, 0x0c, 0x49,
+ 0x16, 0x43, 0x1d, 0x41, 0x22, 0x40, 0x26, 0x3f, 0x29, 0x3f, 0x2c, 0x3f,
+ 0x2e, 0x3e, 0x2f, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x33, 0x3e, 0x33, 0x3e,
+ 0x34, 0x3e, 0x35, 0x3e, 0x35, 0x3e, 0x36, 0x3e, 0x37, 0x3e, 0x37, 0x3e,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x00, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x6d, 0x0b, 0x57, 0x16, 0x4f, 0x1d, 0x4a, 0x22, 0x48, 0x26, 0x47, 0x29,
+ 0x46, 0x2b, 0x44, 0x2d, 0x44, 0x2f, 0x44, 0x30, 0x44, 0x31, 0x44, 0x32,
+ 0x43, 0x33, 0x43, 0x34, 0x43, 0x34, 0x42, 0x35, 0x43, 0x36, 0x42, 0x36,
+ 0x42, 0x37, 0x42, 0x37, 0x00, 0x68, 0x06, 0x54, 0x0d, 0x4b, 0x14, 0x47,
+ 0x19, 0x44, 0x1d, 0x43, 0x20, 0x41, 0x23, 0x41, 0x26, 0x40, 0x27, 0x40,
+ 0x29, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f, 0x2d, 0x3f, 0x2e, 0x3f, 0x2f, 0x3f,
+ 0x30, 0x3f, 0x30, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c,
+ 0x00, 0x2d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x5c, 0x00, 0x2d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x72, 0x06, 0x5f, 0x0d,
+ 0x56, 0x14, 0x4f, 0x19, 0x4d, 0x1d, 0x4a, 0x20, 0x49, 0x23, 0x47, 0x25,
+ 0x46, 0x27, 0x46, 0x29, 0x45, 0x2a, 0x45, 0x2c, 0x44, 0x2d, 0x44, 0x2e,
+ 0x44, 0x2f, 0x43, 0x30, 0x44, 0x30, 0x44, 0x31, 0x43, 0x32, 0x43, 0x33,
+ 0x00, 0x6d, 0x04, 0x5b, 0x09, 0x51, 0x0e, 0x4c, 0x13, 0x48, 0x17, 0x46,
+ 0x1a, 0x44, 0x1d, 0x43, 0x1f, 0x42, 0x22, 0x42, 0x24, 0x41, 0x25, 0x41,
+ 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f,
+ 0x2d, 0x3f, 0x2e, 0x3f, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00,
+ 0x48, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x75, 0x03, 0x64, 0x09, 0x5a, 0x0e, 0x54, 0x13,
+ 0x51, 0x17, 0x4e, 0x1a, 0x4c, 0x1d, 0x49, 0x1f, 0x49, 0x22, 0x48, 0x23,
+ 0x47, 0x25, 0x46, 0x26, 0x46, 0x28, 0x45, 0x29, 0x45, 0x2a, 0x44, 0x2b,
+ 0x44, 0x2c, 0x44, 0x2d, 0x44, 0x2e, 0x44, 0x2e, 0x00, 0x70, 0x02, 0x60,
+ 0x07, 0x56, 0x0b, 0x50, 0x0f, 0x4c, 0x12, 0x49, 0x16, 0x47, 0x18, 0x46,
+ 0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x43, 0x21, 0x42, 0x22, 0x42, 0x24, 0x41,
+ 0x25, 0x41, 0x26, 0x40, 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00,
+ 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x77, 0x02, 0x68, 0x06, 0x5f, 0x0b, 0x58, 0x0f, 0x54, 0x12, 0x51, 0x15,
+ 0x4f, 0x18, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1f, 0x49, 0x21, 0x48, 0x22,
+ 0x48, 0x23, 0x47, 0x25, 0x46, 0x26, 0x45, 0x27, 0x45, 0x28, 0x45, 0x29,
+ 0x45, 0x2a, 0x44, 0x2b, 0x00, 0x72, 0x02, 0x64, 0x05, 0x5b, 0x08, 0x54,
+ 0x0c, 0x50, 0x0f, 0x4d, 0x12, 0x4a, 0x14, 0x48, 0x17, 0x47, 0x19, 0x46,
+ 0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x44, 0x20, 0x42, 0x21, 0x42, 0x22, 0x42,
+ 0x24, 0x41, 0x25, 0x41, 0x26, 0x41, 0x27, 0x40, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75,
+ 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x78, 0x02, 0x6b, 0x05,
+ 0x62, 0x08, 0x5b, 0x0c, 0x57, 0x0f, 0x54, 0x12, 0x51, 0x14, 0x4e, 0x17,
+ 0x4d, 0x19, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e, 0x49, 0x20, 0x48, 0x21,
+ 0x48, 0x22, 0x46, 0x24, 0x46, 0x25, 0x46, 0x26, 0x46, 0x27, 0x45, 0x27,
+ 0x00, 0x74, 0x01, 0x66, 0x04, 0x5e, 0x07, 0x57, 0x0a, 0x53, 0x0d, 0x4f,
+ 0x10, 0x4d, 0x12, 0x4b, 0x14, 0x49, 0x16, 0x48, 0x18, 0x46, 0x1a, 0x45,
+ 0x1b, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x20, 0x43, 0x21, 0x42, 0x22, 0x42,
+ 0x23, 0x42, 0x24, 0x41, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56,
+ 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00,
+ 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x79, 0x01, 0x6d, 0x04, 0x65, 0x07, 0x5e, 0x0a,
+ 0x5a, 0x0d, 0x56, 0x0f, 0x54, 0x12, 0x51, 0x14, 0x4f, 0x16, 0x4e, 0x18,
+ 0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e, 0x49, 0x1f, 0x48, 0x21,
+ 0x48, 0x22, 0x48, 0x23, 0x47, 0x23, 0x46, 0x25, 0x00, 0x75, 0x01, 0x69,
+ 0x03, 0x61, 0x06, 0x5a, 0x08, 0x56, 0x0b, 0x52, 0x0d, 0x4f, 0x10, 0x4d,
+ 0x12, 0x4b, 0x14, 0x4a, 0x16, 0x48, 0x17, 0x47, 0x19, 0x46, 0x1a, 0x45,
+ 0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x20, 0x43, 0x21, 0x42,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37,
+ 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00,
+ 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7a, 0x01, 0x6f, 0x03, 0x67, 0x06, 0x60, 0x08, 0x5d, 0x0b, 0x59, 0x0d,
+ 0x56, 0x10, 0x53, 0x11, 0x51, 0x14, 0x50, 0x15, 0x4e, 0x17, 0x4d, 0x19,
+ 0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x48, 0x1e, 0x49, 0x1f, 0x49, 0x20,
+ 0x48, 0x21, 0x48, 0x22, 0x00, 0x76, 0x01, 0x6b, 0x03, 0x63, 0x05, 0x5d,
+ 0x07, 0x58, 0x09, 0x54, 0x0c, 0x52, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c,
+ 0x13, 0x4a, 0x15, 0x49, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x45,
+ 0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a,
+ 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f,
+ 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00,
+ 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7b, 0x01, 0x71, 0x02,
+ 0x69, 0x05, 0x63, 0x07, 0x5f, 0x09, 0x5b, 0x0c, 0x58, 0x0e, 0x55, 0x10,
+ 0x53, 0x11, 0x52, 0x13, 0x50, 0x15, 0x4e, 0x16, 0x4e, 0x18, 0x4c, 0x19,
+ 0x4c, 0x1a, 0x4a, 0x1c, 0x4b, 0x1d, 0x49, 0x1e, 0x49, 0x1f, 0x49, 0x20,
+ 0x00, 0x77, 0x00, 0x6c, 0x02, 0x65, 0x04, 0x5f, 0x06, 0x5a, 0x08, 0x57,
+ 0x0a, 0x54, 0x0c, 0x51, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c, 0x13, 0x4a,
+ 0x15, 0x49, 0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x1a, 0x46, 0x1b, 0x45,
+ 0x1c, 0x45, 0x1d, 0x45, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69,
+ 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00,
+ 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7b, 0x00, 0x72, 0x02, 0x6b, 0x04, 0x64, 0x06,
+ 0x61, 0x08, 0x5d, 0x0a, 0x5a, 0x0c, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11,
+ 0x52, 0x13, 0x50, 0x15, 0x4f, 0x16, 0x4e, 0x17, 0x4d, 0x18, 0x4b, 0x1a,
+ 0x4b, 0x1a, 0x4b, 0x1c, 0x4b, 0x1d, 0x49, 0x1d, 0x00, 0x77, 0x00, 0x6e,
+ 0x02, 0x66, 0x04, 0x61, 0x05, 0x5c, 0x07, 0x59, 0x09, 0x56, 0x0b, 0x53,
+ 0x0d, 0x51, 0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a,
+ 0x15, 0x48, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x46, 0x1b, 0x45,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53,
+ 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00,
+ 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7c, 0x00, 0x73, 0x02, 0x6c, 0x03, 0x66, 0x05, 0x63, 0x07, 0x5e, 0x09,
+ 0x5c, 0x0b, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13,
+ 0x50, 0x14, 0x4f, 0x15, 0x4e, 0x17, 0x4c, 0x18, 0x4c, 0x19, 0x4c, 0x1a,
+ 0x4b, 0x1a, 0x4b, 0x1c, 0x00, 0x77, 0x00, 0x6f, 0x02, 0x68, 0x03, 0x63,
+ 0x05, 0x5e, 0x06, 0x5a, 0x08, 0x57, 0x0a, 0x55, 0x0b, 0x53, 0x0d, 0x50,
+ 0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x49,
+ 0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x19, 0x46, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c,
+ 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e,
+ 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00,
+ 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7c, 0x00, 0x74, 0x02,
+ 0x6e, 0x03, 0x68, 0x05, 0x64, 0x06, 0x60, 0x08, 0x5d, 0x0a, 0x5a, 0x0b,
+ 0x58, 0x0d, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x14,
+ 0x50, 0x15, 0x4d, 0x16, 0x4e, 0x18, 0x4c, 0x18, 0x4c, 0x19, 0x4c, 0x1a,
+ 0x00, 0x78, 0x00, 0x70, 0x01, 0x69, 0x03, 0x64, 0x04, 0x60, 0x06, 0x5c,
+ 0x07, 0x59, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x52, 0x0d, 0x50, 0x0f, 0x4f,
+ 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x48,
+ 0x17, 0x48, 0x18, 0x47, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71,
+ 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c,
+ 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00,
+ 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00,
+ 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x75, 0x01, 0x6f, 0x02, 0x69, 0x04,
+ 0x65, 0x06, 0x62, 0x07, 0x5f, 0x09, 0x5b, 0x0b, 0x5a, 0x0c, 0x58, 0x0d,
+ 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x13, 0x4f, 0x15,
+ 0x4e, 0x15, 0x4e, 0x17, 0x4d, 0x18, 0x4c, 0x18, 0x00, 0x78, 0x00, 0x71,
+ 0x01, 0x6a, 0x03, 0x66, 0x04, 0x61, 0x05, 0x5d, 0x06, 0x5a, 0x08, 0x58,
+ 0x09, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0e, 0x50, 0x0f, 0x4e, 0x10, 0x4e,
+ 0x11, 0x4c, 0x13, 0x4c, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x49, 0x16, 0x48,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62,
+ 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e,
+ 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00,
+ 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00,
+ 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7d, 0x00, 0x76, 0x01, 0x70, 0x02, 0x6a, 0x03, 0x67, 0x05, 0x63, 0x06,
+ 0x60, 0x08, 0x5d, 0x09, 0x5b, 0x0b, 0x59, 0x0c, 0x57, 0x0d, 0x55, 0x0e,
+ 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x4f, 0x13, 0x50, 0x15, 0x4f, 0x15,
+ 0x4e, 0x16, 0x4e, 0x18, 0x00, 0x79, 0x00, 0x71, 0x01, 0x6c, 0x02, 0x66,
+ 0x04, 0x62, 0x05, 0x5f, 0x06, 0x5c, 0x07, 0x59, 0x09, 0x57, 0x0a, 0x55,
+ 0x0b, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c,
+ 0x13, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x4a, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d,
+ 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51,
+ 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00,
+ 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00,
+ 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x76, 0x01,
+ 0x71, 0x02, 0x6c, 0x03, 0x68, 0x05, 0x64, 0x06, 0x61, 0x07, 0x5e, 0x09,
+ 0x5c, 0x0a, 0x5a, 0x0b, 0x59, 0x0c, 0x57, 0x0e, 0x55, 0x0e, 0x55, 0x11,
+ 0x52, 0x11, 0x51, 0x12, 0x51, 0x13, 0x50, 0x14, 0x4f, 0x15, 0x4e, 0x15,
+ 0x00, 0x79, 0x00, 0x72, 0x01, 0x6d, 0x02, 0x68, 0x03, 0x63, 0x04, 0x60,
+ 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x53,
+ 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c,
+ 0x13, 0x4b, 0x14, 0x4a, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x1f, 0x00, 0x3f,
+ 0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c,
+ 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x58, 0x00, 0x70, 0x00, 0x77,
+ 0x00, 0x79, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x00, 0x3f,
+ 0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c,
+ 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
+ 0x00, 0x7e, 0x00, 0x7e, 0x1f, 0x1f, 0x00, 0x3f, 0x00, 0x66, 0x00, 0x72,
+ 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x77, 0x01, 0x72, 0x02, 0x6d, 0x03,
+ 0x69, 0x04, 0x66, 0x06, 0x63, 0x07, 0x5f, 0x08, 0x5e, 0x09, 0x5c, 0x0b,
+ 0x5a, 0x0c, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x0f, 0x54, 0x11, 0x51, 0x11,
+ 0x52, 0x12, 0x51, 0x13, 0x50, 0x14, 0x50, 0x15, 0x00, 0x79, 0x00, 0x73,
+ 0x01, 0x6d, 0x02, 0x69, 0x03, 0x65, 0x04, 0x61, 0x05, 0x5e, 0x06, 0x5c,
+ 0x07, 0x59, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54, 0x0d, 0x53, 0x0d, 0x51,
+ 0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c, 0x13, 0x4b,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x3f, 0x00, 0x5c,
+ 0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a,
+ 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d,
+ 0x00, 0x58, 0x00, 0x44, 0x00, 0x55, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x72,
+ 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c,
+ 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x0a, 0x00, 0x3f, 0x00, 0x5c,
+ 0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a,
+ 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d,
+ 0x3f, 0x00, 0x0a, 0x0a, 0x00, 0x3f, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x71,
+ 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c,
+ 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7d, 0x00, 0x78, 0x01, 0x72, 0x02, 0x6e, 0x02, 0x6a, 0x03, 0x67, 0x05,
+ 0x64, 0x06, 0x60, 0x07, 0x5f, 0x09, 0x5c, 0x0a, 0x5b, 0x0b, 0x5a, 0x0c,
+ 0x57, 0x0c, 0x56, 0x0e, 0x55, 0x0f, 0x53, 0x11, 0x52, 0x11, 0x52, 0x12,
+ 0x51, 0x13, 0x50, 0x13, 0x00, 0x79, 0x00, 0x73, 0x01, 0x6e, 0x02, 0x69,
+ 0x03, 0x66, 0x04, 0x62, 0x05, 0x5f, 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58,
+ 0x09, 0x56, 0x0b, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50,
+ 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4d, 0x12, 0x4c, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59,
+ 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76,
+ 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x70, 0x00, 0x55,
+ 0x00, 0x20, 0x00, 0x3e, 0x00, 0x50, 0x00, 0x5a, 0x00, 0x63, 0x00, 0x6a,
+ 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78,
+ 0x00, 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x3f, 0x00, 0x03, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59,
+ 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76,
+ 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x66, 0x00, 0x3f, 0x00,
+ 0x03, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00, 0x63, 0x00, 0x6a,
+ 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78,
+ 0x00, 0x79, 0x00, 0x7a, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x78, 0x01,
+ 0x73, 0x02, 0x6e, 0x02, 0x6b, 0x03, 0x68, 0x05, 0x65, 0x06, 0x61, 0x07,
+ 0x5f, 0x07, 0x5e, 0x09, 0x5c, 0x0b, 0x5a, 0x0b, 0x59, 0x0c, 0x57, 0x0d,
+ 0x56, 0x0e, 0x54, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x52, 0x12, 0x51, 0x13,
+ 0x00, 0x79, 0x00, 0x74, 0x00, 0x6f, 0x02, 0x6a, 0x03, 0x66, 0x04, 0x63,
+ 0x05, 0x60, 0x05, 0x5e, 0x06, 0x5b, 0x07, 0x59, 0x09, 0x58, 0x09, 0x55,
+ 0x0b, 0x55, 0x0c, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50, 0x0f, 0x4e,
+ 0x11, 0x4e, 0x11, 0x4d, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56,
+ 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71,
+ 0x00, 0x73, 0x00, 0x75, 0x00, 0x77, 0x00, 0x67, 0x00, 0x3e, 0x00, 0x0d,
+ 0x00, 0x28, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64,
+ 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c, 0x00,
+ 0x2d, 0x00, 0x01, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56,
+ 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71,
+ 0x00, 0x73, 0x00, 0x75, 0x72, 0x00, 0x5c, 0x00, 0x2d, 0x00, 0x01, 0x01,
+ 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64,
+ 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x78, 0x00, 0x74, 0x01, 0x6f, 0x02,
+ 0x6c, 0x03, 0x68, 0x04, 0x65, 0x05, 0x62, 0x06, 0x61, 0x07, 0x5f, 0x09,
+ 0x5c, 0x09, 0x5b, 0x0b, 0x5a, 0x0b, 0x58, 0x0c, 0x57, 0x0d, 0x55, 0x0e,
+ 0x55, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x52, 0x12, 0x00, 0x79, 0x00, 0x74,
+ 0x00, 0x70, 0x01, 0x6b, 0x02, 0x67, 0x03, 0x64, 0x04, 0x61, 0x05, 0x5f,
+ 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54,
+ 0x0c, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54,
+ 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e,
+ 0x00, 0x79, 0x00, 0x6e, 0x00, 0x50, 0x00, 0x28, 0x00, 0x01, 0x00, 0x1b,
+ 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61,
+ 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00,
+ 0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54,
+ 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e,
+ 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x1b,
+ 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61,
+ 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x21, 0x5d, 0x0c, 0x68,
+ 0x06, 0x6d, 0x04, 0x71, 0x02, 0x72, 0x02, 0x74, 0x01, 0x75, 0x01, 0x76,
+ 0x01, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x79,
+ 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x7a,
+ 0x42, 0x40, 0x17, 0x55, 0x0c, 0x60, 0x08, 0x66, 0x05, 0x6a, 0x04, 0x6d,
+ 0x03, 0x6f, 0x02, 0x71, 0x02, 0x73, 0x01, 0x73, 0x01, 0x74, 0x01, 0x75,
+ 0x01, 0x76, 0x01, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78,
+ 0x00, 0x78, 0x00, 0x78, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x21, 0x5d, 0x0c, 0x68,
+ 0x06, 0x6d, 0x04, 0x71, 0x02, 0x72, 0x02, 0x74, 0x01, 0x75, 0x01, 0x76,
+ 0x01, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x79,
+ 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x7a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53,
+ 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x7b, 0x00, 0x72,
+ 0x00, 0x5a, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x16, 0x00, 0x28,
+ 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e,
+ 0x00, 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x00,
+ 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53,
+ 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x7a, 0x00, 0x71, 0x00,
+ 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x28,
+ 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e,
+ 0x00, 0x62, 0x00, 0x65, 0x2b, 0x49, 0x16, 0x53, 0x0d, 0x5b, 0x09, 0x60,
+ 0x07, 0x64, 0x05, 0x67, 0x04, 0x69, 0x03, 0x6b, 0x03, 0x6c, 0x02, 0x6e,
+ 0x02, 0x6f, 0x02, 0x70, 0x01, 0x71, 0x01, 0x71, 0x01, 0x72, 0x01, 0x73,
+ 0x01, 0x73, 0x01, 0x74, 0x00, 0x74, 0x00, 0x75, 0x57, 0x16, 0x2d, 0x2c,
+ 0x1b, 0x3b, 0x12, 0x45, 0x0d, 0x4d, 0x0b, 0x53, 0x08, 0x57, 0x07, 0x5b,
+ 0x05, 0x5e, 0x05, 0x61, 0x04, 0x63, 0x04, 0x65, 0x03, 0x67, 0x02, 0x68,
+ 0x02, 0x69, 0x02, 0x6b, 0x02, 0x6c, 0x01, 0x6d, 0x01, 0x6e, 0x01, 0x6f,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x2b, 0x49, 0x16, 0x53, 0x0d, 0x5b, 0x09, 0x60,
+ 0x07, 0x64, 0x05, 0x67, 0x04, 0x69, 0x03, 0x6b, 0x03, 0x6c, 0x02, 0x6e,
+ 0x02, 0x6f, 0x02, 0x70, 0x01, 0x71, 0x01, 0x71, 0x01, 0x72, 0x01, 0x73,
+ 0x01, 0x73, 0x01, 0x74, 0x00, 0x74, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13,
+ 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52,
+ 0x00, 0x57, 0x00, 0x5b, 0x00, 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a,
+ 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30,
+ 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75, 0x00,
+ 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x13,
+ 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52,
+ 0x00, 0x57, 0x00, 0x5b, 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a, 0x00,
+ 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30,
+ 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b,
+ 0x31, 0x43, 0x1d, 0x4b, 0x14, 0x51, 0x0e, 0x56, 0x0b, 0x5b, 0x08, 0x5e,
+ 0x07, 0x61, 0x06, 0x63, 0x05, 0x65, 0x04, 0x67, 0x04, 0x68, 0x03, 0x69,
+ 0x03, 0x6a, 0x03, 0x6c, 0x02, 0x6d, 0x02, 0x6d, 0x02, 0x6e, 0x02, 0x6f,
+ 0x02, 0x70, 0x01, 0x70, 0x61, 0x0c, 0x3b, 0x1b, 0x28, 0x28, 0x1d, 0x32,
+ 0x16, 0x3a, 0x11, 0x41, 0x0e, 0x47, 0x0c, 0x4b, 0x0a, 0x4f, 0x09, 0x53,
+ 0x07, 0x55, 0x06, 0x58, 0x05, 0x5a, 0x05, 0x5c, 0x05, 0x5e, 0x04, 0x60,
+ 0x04, 0x61, 0x04, 0x63, 0x03, 0x64, 0x02, 0x66, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x31, 0x43, 0x1d, 0x4b, 0x14, 0x51, 0x0e, 0x56, 0x0b, 0x5b, 0x08, 0x5e,
+ 0x07, 0x61, 0x06, 0x63, 0x05, 0x65, 0x04, 0x67, 0x04, 0x68, 0x03, 0x69,
+ 0x03, 0x6a, 0x03, 0x6c, 0x02, 0x6d, 0x02, 0x6d, 0x02, 0x6e, 0x02, 0x6f,
+ 0x02, 0x70, 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
+ 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51,
+ 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28,
+ 0x00, 0x13, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35,
+ 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00,
+ 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
+ 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51,
+ 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28, 0x00,
+ 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35,
+ 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x33, 0x41, 0x22, 0x46,
+ 0x19, 0x4c, 0x13, 0x50, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x5a, 0x08, 0x5d,
+ 0x07, 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x66, 0x04, 0x66,
+ 0x04, 0x68, 0x03, 0x69, 0x03, 0x69, 0x03, 0x6a, 0x03, 0x6b, 0x02, 0x6c,
+ 0x67, 0x07, 0x45, 0x12, 0x32, 0x1d, 0x26, 0x26, 0x1e, 0x2e, 0x18, 0x34,
+ 0x14, 0x3a, 0x11, 0x3f, 0x0f, 0x44, 0x0c, 0x47, 0x0b, 0x4b, 0x0a, 0x4d,
+ 0x09, 0x51, 0x07, 0x52, 0x07, 0x55, 0x06, 0x57, 0x05, 0x58, 0x05, 0x5a,
+ 0x05, 0x5c, 0x04, 0x5d, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x33, 0x41, 0x22, 0x46,
+ 0x19, 0x4c, 0x13, 0x50, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x5a, 0x08, 0x5d,
+ 0x07, 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x66, 0x04, 0x66,
+ 0x04, 0x68, 0x03, 0x69, 0x03, 0x69, 0x03, 0x6a, 0x03, 0x6b, 0x02, 0x6c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27,
+ 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x7d, 0x00, 0x79,
+ 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39,
+ 0x00, 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00,
+ 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27,
+ 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x7d, 0x00, 0x79, 0x00,
+ 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39,
+ 0x00, 0x40, 0x00, 0x46, 0x35, 0x40, 0x27, 0x44, 0x1d, 0x48, 0x17, 0x4c,
+ 0x12, 0x50, 0x0f, 0x53, 0x0d, 0x56, 0x0b, 0x58, 0x09, 0x5a, 0x08, 0x5c,
+ 0x07, 0x5e, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63, 0x04, 0x65,
+ 0x04, 0x66, 0x04, 0x66, 0x04, 0x67, 0x03, 0x68, 0x6b, 0x05, 0x4d, 0x0d,
+ 0x3b, 0x16, 0x2e, 0x1e, 0x25, 0x25, 0x1f, 0x2b, 0x1a, 0x31, 0x16, 0x36,
+ 0x13, 0x3a, 0x10, 0x3e, 0x0f, 0x42, 0x0d, 0x45, 0x0c, 0x47, 0x0a, 0x4a,
+ 0x0a, 0x4c, 0x09, 0x4f, 0x07, 0x51, 0x07, 0x52, 0x07, 0x54, 0x06, 0x56,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x35, 0x40, 0x27, 0x44, 0x1d, 0x48, 0x17, 0x4c,
+ 0x12, 0x50, 0x0f, 0x53, 0x0d, 0x56, 0x0b, 0x58, 0x09, 0x5a, 0x08, 0x5c,
+ 0x07, 0x5e, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63, 0x04, 0x65,
+ 0x04, 0x66, 0x04, 0x66, 0x04, 0x67, 0x03, 0x68, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c,
+ 0x00, 0x34, 0x00, 0x3b, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64,
+ 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00,
+ 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a, 0x00,
+ 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c,
+ 0x00, 0x34, 0x00, 0x3b, 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64, 0x00,
+ 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b,
+ 0x37, 0x3f, 0x29, 0x43, 0x21, 0x46, 0x1a, 0x49, 0x16, 0x4d, 0x12, 0x50,
+ 0x10, 0x52, 0x0d, 0x54, 0x0c, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c,
+ 0x07, 0x5d, 0x06, 0x5f, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63,
+ 0x04, 0x64, 0x04, 0x65, 0x6e, 0x04, 0x53, 0x0a, 0x41, 0x11, 0x34, 0x18,
+ 0x2b, 0x1f, 0x24, 0x24, 0x1f, 0x29, 0x1b, 0x2e, 0x17, 0x33, 0x15, 0x37,
+ 0x12, 0x3a, 0x10, 0x3d, 0x0f, 0x40, 0x0d, 0x43, 0x0c, 0x45, 0x0c, 0x48,
+ 0x0a, 0x4a, 0x0a, 0x4c, 0x09, 0x4e, 0x07, 0x4f, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x37, 0x3f, 0x29, 0x43, 0x21, 0x46, 0x1a, 0x49, 0x16, 0x4d, 0x12, 0x50,
+ 0x10, 0x52, 0x0d, 0x54, 0x0c, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c,
+ 0x07, 0x5d, 0x06, 0x5f, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63,
+ 0x04, 0x64, 0x04, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30,
+ 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b,
+ 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c,
+ 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00,
+ 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30,
+ 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b, 0x00,
+ 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x0c,
+ 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x38, 0x3f, 0x2c, 0x41,
+ 0x23, 0x44, 0x1d, 0x47, 0x19, 0x4a, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x52,
+ 0x0e, 0x54, 0x0c, 0x56, 0x0b, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c,
+ 0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x61, 0x05, 0x61, 0x05, 0x62,
+ 0x70, 0x03, 0x58, 0x08, 0x47, 0x0e, 0x3a, 0x14, 0x31, 0x1a, 0x29, 0x1f,
+ 0x24, 0x24, 0x20, 0x28, 0x1c, 0x2d, 0x19, 0x31, 0x16, 0x34, 0x14, 0x37,
+ 0x12, 0x3a, 0x10, 0x3d, 0x0f, 0x3f, 0x0e, 0x42, 0x0c, 0x44, 0x0c, 0x46,
+ 0x0b, 0x47, 0x0a, 0x4a, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x38, 0x3f, 0x2c, 0x41,
+ 0x23, 0x44, 0x1d, 0x47, 0x19, 0x4a, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x52,
+ 0x0e, 0x54, 0x0c, 0x56, 0x0b, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c,
+ 0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x61, 0x05, 0x61, 0x05, 0x62,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x7e, 0x00, 0x7c,
+ 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35,
+ 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15,
+ 0x00, 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00,
+ 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x7e, 0x00, 0x7c, 0x00,
+ 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35, 0x00,
+ 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15,
+ 0x00, 0x1e, 0x00, 0x26, 0x39, 0x3f, 0x2e, 0x41, 0x26, 0x43, 0x20, 0x46,
+ 0x1b, 0x48, 0x17, 0x4b, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x51, 0x0e, 0x53,
+ 0x0d, 0x55, 0x0b, 0x56, 0x0b, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
+ 0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x60, 0x71, 0x02, 0x5b, 0x07,
+ 0x4c, 0x0c, 0x3f, 0x11, 0x36, 0x16, 0x2e, 0x1b, 0x29, 0x20, 0x24, 0x23,
+ 0x20, 0x28, 0x1d, 0x2b, 0x19, 0x2f, 0x17, 0x32, 0x16, 0x35, 0x12, 0x37,
+ 0x12, 0x3a, 0x10, 0x3c, 0x0f, 0x3f, 0x0e, 0x41, 0x0c, 0x42, 0x0c, 0x45,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x39, 0x3f, 0x2e, 0x41, 0x26, 0x43, 0x20, 0x46,
+ 0x1b, 0x48, 0x17, 0x4b, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x51, 0x0e, 0x53,
+ 0x0d, 0x55, 0x0b, 0x56, 0x0b, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
+ 0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x13, 0x00, 0x1b, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f,
+ 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23,
+ 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00,
+ 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00,
+ 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x13, 0x00, 0x1b, 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f, 0x00,
+ 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23, 0x00,
+ 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b,
+ 0x39, 0x3e, 0x2f, 0x40, 0x28, 0x42, 0x22, 0x45, 0x1d, 0x47, 0x19, 0x49,
+ 0x16, 0x4b, 0x14, 0x4d, 0x11, 0x4f, 0x10, 0x51, 0x0f, 0x53, 0x0d, 0x54,
+ 0x0c, 0x55, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
+ 0x07, 0x5c, 0x07, 0x5e, 0x73, 0x02, 0x5e, 0x05, 0x4f, 0x0a, 0x44, 0x0f,
+ 0x3a, 0x13, 0x33, 0x18, 0x2d, 0x1c, 0x27, 0x20, 0x23, 0x23, 0x20, 0x27,
+ 0x1d, 0x2a, 0x1a, 0x2d, 0x18, 0x30, 0x16, 0x33, 0x14, 0x35, 0x12, 0x38,
+ 0x12, 0x3a, 0x10, 0x3c, 0x0f, 0x3e, 0x0f, 0x41, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x39, 0x3e, 0x2f, 0x40, 0x28, 0x42, 0x22, 0x45, 0x1d, 0x47, 0x19, 0x49,
+ 0x16, 0x4b, 0x14, 0x4d, 0x11, 0x4f, 0x10, 0x51, 0x0f, 0x53, 0x0d, 0x54,
+ 0x0c, 0x55, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
+ 0x07, 0x5c, 0x07, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12,
+ 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e,
+ 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15,
+ 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00,
+ 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00,
+ 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12,
+ 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e, 0x00,
+ 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, 0x3a, 0x3e, 0x31, 0x40,
+ 0x29, 0x42, 0x23, 0x44, 0x1f, 0x46, 0x1b, 0x48, 0x18, 0x4a, 0x15, 0x4c,
+ 0x13, 0x4d, 0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x55,
+ 0x0b, 0x56, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
+ 0x74, 0x01, 0x62, 0x05, 0x53, 0x08, 0x47, 0x0c, 0x3e, 0x11, 0x37, 0x15,
+ 0x31, 0x19, 0x2b, 0x1d, 0x27, 0x20, 0x23, 0x23, 0x20, 0x26, 0x1d, 0x2a,
+ 0x1b, 0x2c, 0x19, 0x2f, 0x16, 0x31, 0x16, 0x34, 0x13, 0x35, 0x12, 0x38,
+ 0x12, 0x3b, 0x0f, 0x3b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3a, 0x3e, 0x31, 0x40,
+ 0x29, 0x42, 0x23, 0x44, 0x1f, 0x46, 0x1b, 0x48, 0x18, 0x4a, 0x15, 0x4c,
+ 0x13, 0x4d, 0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x55,
+ 0x0b, 0x56, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x7e, 0x00, 0x7d,
+ 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c,
+ 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00,
+ 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00,
+ 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7e, 0x00, 0x7d, 0x00,
+ 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c, 0x00,
+ 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x3a, 0x3e, 0x32, 0x3f, 0x2b, 0x41, 0x25, 0x43,
+ 0x21, 0x45, 0x1d, 0x46, 0x1a, 0x48, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e,
+ 0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55,
+ 0x0b, 0x56, 0x0b, 0x58, 0x09, 0x58, 0x09, 0x59, 0x75, 0x01, 0x64, 0x04,
+ 0x56, 0x07, 0x4b, 0x0b, 0x42, 0x0f, 0x3a, 0x12, 0x34, 0x16, 0x2f, 0x19,
+ 0x2a, 0x1d, 0x26, 0x20, 0x23, 0x23, 0x21, 0x26, 0x1d, 0x29, 0x1b, 0x2b,
+ 0x19, 0x2e, 0x18, 0x30, 0x16, 0x32, 0x15, 0x35, 0x12, 0x35, 0x12, 0x38,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x3a, 0x3e, 0x32, 0x3f, 0x2b, 0x41, 0x25, 0x43,
+ 0x21, 0x45, 0x1d, 0x46, 0x1a, 0x48, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e,
+ 0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55,
+ 0x0b, 0x56, 0x0b, 0x58, 0x09, 0x58, 0x09, 0x59, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75,
+ 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b,
+ 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00,
+ 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00,
+ 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75, 0x00,
+ 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b, 0x00,
+ 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x3b, 0x3e, 0x33, 0x3f, 0x2c, 0x41, 0x27, 0x42, 0x22, 0x44, 0x1f, 0x45,
+ 0x1c, 0x47, 0x19, 0x49, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e, 0x11, 0x4f,
+ 0x10, 0x50, 0x0f, 0x51, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x0b, 0x55,
+ 0x0b, 0x57, 0x0a, 0x58, 0x76, 0x01, 0x66, 0x04, 0x58, 0x06, 0x4d, 0x0a,
+ 0x45, 0x0d, 0x3e, 0x10, 0x37, 0x14, 0x32, 0x17, 0x2d, 0x1a, 0x2a, 0x1d,
+ 0x26, 0x21, 0x22, 0x22, 0x21, 0x26, 0x1d, 0x28, 0x1c, 0x2b, 0x19, 0x2c,
+ 0x19, 0x30, 0x16, 0x30, 0x16, 0x33, 0x14, 0x35, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x3b, 0x3e, 0x33, 0x3f, 0x2c, 0x41, 0x27, 0x42, 0x22, 0x44, 0x1f, 0x45,
+ 0x1c, 0x47, 0x19, 0x49, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e, 0x11, 0x4f,
+ 0x10, 0x50, 0x0f, 0x51, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x0b, 0x55,
+ 0x0b, 0x57, 0x0a, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x3e, 0x33, 0x3f,
+ 0x2d, 0x40, 0x28, 0x42, 0x24, 0x44, 0x20, 0x45, 0x1d, 0x46, 0x1a, 0x48,
+ 0x18, 0x49, 0x16, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x10, 0x50,
+ 0x0f, 0x51, 0x0f, 0x53, 0x0d, 0x53, 0x0d, 0x55, 0x0b, 0x55, 0x0b, 0x56,
+ 0x77, 0x01, 0x67, 0x03, 0x5a, 0x05, 0x51, 0x09, 0x48, 0x0c, 0x40, 0x0f,
+ 0x3a, 0x12, 0x35, 0x16, 0x30, 0x18, 0x2c, 0x1b, 0x29, 0x1d, 0x26, 0x21,
+ 0x22, 0x22, 0x21, 0x26, 0x1d, 0x27, 0x1d, 0x2b, 0x1a, 0x2b, 0x19, 0x2e,
+ 0x17, 0x30, 0x16, 0x31, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3b, 0x3e, 0x33, 0x3f,
+ 0x2d, 0x40, 0x28, 0x42, 0x24, 0x44, 0x20, 0x45, 0x1d, 0x46, 0x1a, 0x48,
+ 0x18, 0x49, 0x16, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x10, 0x50,
+ 0x0f, 0x51, 0x0f, 0x53, 0x0d, 0x53, 0x0d, 0x55, 0x0b, 0x55, 0x0b, 0x56,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3b, 0x3e, 0x34, 0x3f, 0x2e, 0x40, 0x29, 0x41,
+ 0x25, 0x43, 0x21, 0x44, 0x1e, 0x45, 0x1c, 0x47, 0x19, 0x48, 0x18, 0x4a,
+ 0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50,
+ 0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x77, 0x01, 0x68, 0x02,
+ 0x5d, 0x05, 0x52, 0x07, 0x4a, 0x0a, 0x43, 0x0d, 0x3d, 0x10, 0x38, 0x12,
+ 0x33, 0x16, 0x2f, 0x19, 0x2b, 0x1b, 0x28, 0x1d, 0x26, 0x21, 0x22, 0x22,
+ 0x21, 0x26, 0x1e, 0x26, 0x1d, 0x2a, 0x1a, 0x2b, 0x19, 0x2d, 0x18, 0x30,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x3b, 0x3e, 0x34, 0x3f, 0x2e, 0x40, 0x29, 0x41,
+ 0x25, 0x43, 0x21, 0x44, 0x1e, 0x45, 0x1c, 0x47, 0x19, 0x48, 0x18, 0x4a,
+ 0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50,
+ 0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3c, 0x3e, 0x35, 0x3f, 0x2f, 0x40, 0x2a, 0x41, 0x26, 0x42, 0x22, 0x44,
+ 0x20, 0x45, 0x1d, 0x46, 0x1b, 0x48, 0x18, 0x48, 0x17, 0x4a, 0x15, 0x4b,
+ 0x13, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x52,
+ 0x0d, 0x53, 0x0d, 0x53, 0x77, 0x00, 0x6a, 0x02, 0x5e, 0x04, 0x55, 0x07,
+ 0x4c, 0x0a, 0x45, 0x0c, 0x40, 0x0f, 0x3a, 0x12, 0x35, 0x14, 0x31, 0x16,
+ 0x2e, 0x19, 0x2b, 0x1c, 0x27, 0x1d, 0x26, 0x22, 0x21, 0x22, 0x21, 0x25,
+ 0x1e, 0x26, 0x1d, 0x29, 0x1b, 0x2b, 0x19, 0x2b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x3c, 0x3e, 0x35, 0x3f, 0x2f, 0x40, 0x2a, 0x41, 0x26, 0x42, 0x22, 0x44,
+ 0x20, 0x45, 0x1d, 0x46, 0x1b, 0x48, 0x18, 0x48, 0x17, 0x4a, 0x15, 0x4b,
+ 0x13, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x52,
+ 0x0d, 0x53, 0x0d, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x35, 0x3f,
+ 0x30, 0x3f, 0x2b, 0x40, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44, 0x1e, 0x45,
+ 0x1c, 0x46, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a, 0x15, 0x4c, 0x13, 0x4c,
+ 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x0e, 0x53,
+ 0x78, 0x00, 0x6b, 0x02, 0x60, 0x04, 0x57, 0x06, 0x4f, 0x09, 0x48, 0x0c,
+ 0x42, 0x0e, 0x3c, 0x10, 0x38, 0x12, 0x34, 0x16, 0x30, 0x18, 0x2d, 0x19,
+ 0x2b, 0x1d, 0x26, 0x1e, 0x25, 0x22, 0x21, 0x22, 0x21, 0x25, 0x1e, 0x26,
+ 0x1d, 0x28, 0x1c, 0x2b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x35, 0x3f,
+ 0x30, 0x3f, 0x2b, 0x40, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44, 0x1e, 0x45,
+ 0x1c, 0x46, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a, 0x15, 0x4c, 0x13, 0x4c,
+ 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x0e, 0x53,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x36, 0x3f, 0x30, 0x3f, 0x2c, 0x40,
+ 0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47,
+ 0x19, 0x48, 0x18, 0x4a, 0x15, 0x4a, 0x15, 0x4c, 0x13, 0x4c, 0x13, 0x4e,
+ 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x78, 0x00, 0x6d, 0x02,
+ 0x61, 0x04, 0x58, 0x05, 0x51, 0x07, 0x4a, 0x0a, 0x44, 0x0c, 0x3f, 0x0f,
+ 0x3a, 0x12, 0x35, 0x14, 0x32, 0x16, 0x30, 0x19, 0x2b, 0x19, 0x2a, 0x1d,
+ 0x26, 0x1e, 0x25, 0x22, 0x21, 0x22, 0x21, 0x25, 0x1e, 0x26, 0x1d, 0x27,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x36, 0x3f, 0x30, 0x3f, 0x2c, 0x40,
+ 0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47,
+ 0x19, 0x48, 0x18, 0x4a, 0x15, 0x4a, 0x15, 0x4c, 0x13, 0x4c, 0x13, 0x4e,
+ 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3c, 0x3e, 0x37, 0x3e, 0x31, 0x3f, 0x2d, 0x40, 0x29, 0x41, 0x26, 0x42,
+ 0x23, 0x44, 0x20, 0x45, 0x1e, 0x45, 0x1c, 0x46, 0x1a, 0x48, 0x18, 0x48,
+ 0x17, 0x4a, 0x15, 0x4a, 0x14, 0x4c, 0x13, 0x4c, 0x12, 0x4e, 0x11, 0x4e,
+ 0x11, 0x50, 0x0f, 0x50, 0x78, 0x00, 0x6d, 0x02, 0x63, 0x04, 0x5a, 0x05,
+ 0x53, 0x07, 0x4c, 0x0a, 0x46, 0x0c, 0x41, 0x0f, 0x3c, 0x0f, 0x38, 0x12,
+ 0x35, 0x16, 0x30, 0x16, 0x2e, 0x19, 0x2b, 0x1a, 0x29, 0x1d, 0x26, 0x1e,
+ 0x25, 0x22, 0x21, 0x22, 0x21, 0x25, 0x1f, 0x26, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x3c, 0x3e, 0x37, 0x3e, 0x31, 0x3f, 0x2d, 0x40, 0x29, 0x41, 0x26, 0x42,
+ 0x23, 0x44, 0x20, 0x45, 0x1e, 0x45, 0x1c, 0x46, 0x1a, 0x48, 0x18, 0x48,
+ 0x17, 0x4a, 0x15, 0x4a, 0x14, 0x4c, 0x13, 0x4c, 0x12, 0x4e, 0x11, 0x4e,
+ 0x11, 0x50, 0x0f, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x37, 0x3e,
+ 0x32, 0x3f, 0x2e, 0x40, 0x2a, 0x41, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44,
+ 0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a,
+ 0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x11, 0x50,
+ 0x78, 0x00, 0x6e, 0x01, 0x65, 0x03, 0x5c, 0x05, 0x54, 0x07, 0x4e, 0x09,
+ 0x48, 0x0b, 0x43, 0x0c, 0x3e, 0x0f, 0x3b, 0x12, 0x36, 0x12, 0x33, 0x16,
+ 0x30, 0x17, 0x2d, 0x19, 0x2b, 0x1b, 0x28, 0x1d, 0x26, 0x1e, 0x25, 0x22,
+ 0x21, 0x22, 0x21, 0x24, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x37, 0x3e,
+ 0x32, 0x3f, 0x2e, 0x40, 0x2a, 0x41, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44,
+ 0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a,
+ 0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x11, 0x50,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x37, 0x3e, 0x33, 0x3f, 0x2e, 0x3f,
+ 0x2b, 0x40, 0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x20, 0x45, 0x1e, 0x45,
+ 0x1c, 0x46, 0x1b, 0x48, 0x19, 0x48, 0x18, 0x4a, 0x16, 0x4a, 0x15, 0x4b,
+ 0x13, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x79, 0x00, 0x6f, 0x01,
+ 0x66, 0x02, 0x5d, 0x04, 0x56, 0x06, 0x4f, 0x07, 0x4a, 0x0a, 0x45, 0x0c,
+ 0x41, 0x0f, 0x3b, 0x0f, 0x38, 0x12, 0x35, 0x14, 0x31, 0x16, 0x30, 0x18,
+ 0x2b, 0x19, 0x2b, 0x1c, 0x27, 0x1d, 0x26, 0x1f, 0x24, 0x22, 0x21, 0x22,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
+ 0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x37, 0x3e, 0x33, 0x3f, 0x2e, 0x3f,
+ 0x2b, 0x40, 0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x20, 0x45, 0x1e, 0x45,
+ 0x1c, 0x46, 0x1b, 0x48, 0x19, 0x48, 0x18, 0x4a, 0x16, 0x4a, 0x15, 0x4b,
+ 0x13, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x62, 0x00, 0x6c, 0x00, 0x72, 0x00, 0x74, 0x00, 0x77, 0x00, 0x79, 0x00,
+ 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00,
+ 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x7e, 0x00,
+ 0x7e, 0x00, 0x7e, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x08, 0x00, 0x44, 0x00,
+ 0x56, 0x00, 0x61, 0x00, 0x67, 0x00, 0x6b, 0x00, 0x6e, 0x00, 0x70, 0x00,
+ 0x71, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00, 0x76, 0x00,
+ 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00,
+ 0x44, 0x00, 0x63, 0x00, 0x6c, 0x00, 0x71, 0x00, 0x75, 0x00, 0x77, 0x00,
+ 0x79, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7c, 0x00,
+ 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7e, 0x00,
+ 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x0b, 0x57, 0x06,
+ 0x5f, 0x03, 0x63, 0x02, 0x68, 0x02, 0x6b, 0x01, 0x6d, 0x01, 0x6e, 0x01,
+ 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00,
+ 0x76, 0x00, 0x76, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0x79, 0x00,
+ 0x82, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x00, 0x40, 0x17, 0x17, 0x2c, 0x0c, 0x3b, 0x07,
+ 0x45, 0x05, 0x4d, 0x04, 0x53, 0x03, 0x57, 0x02, 0x5c, 0x02, 0x5e, 0x01,
+ 0x61, 0x01, 0x63, 0x01, 0x66, 0x01, 0x67, 0x01, 0x68, 0x00, 0x69, 0x00,
+ 0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x41, 0x20, 0x4d, 0x0b,
+ 0x58, 0x06, 0x5e, 0x03, 0x64, 0x02, 0x68, 0x02, 0x6b, 0x01, 0x6c, 0x01,
+ 0x6f, 0x01, 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00,
+ 0x76, 0x00, 0x75, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x47, 0x15, 0x4f, 0x0d, 0x56, 0x09, 0x59, 0x06,
+ 0x5f, 0x05, 0x62, 0x04, 0x65, 0x03, 0x67, 0x02, 0x69, 0x02, 0x6b, 0x02,
+ 0x6c, 0x02, 0x6e, 0x01, 0x6f, 0x01, 0x70, 0x01, 0x71, 0x01, 0x70, 0x01,
+ 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x74, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x00, 0x55, 0x0c, 0x2c, 0x1b, 0x1b, 0x27, 0x12, 0x32, 0x0d, 0x3a, 0x0b,
+ 0x41, 0x08, 0x47, 0x07, 0x4c, 0x05, 0x4f, 0x05, 0x53, 0x04, 0x56, 0x04,
+ 0x58, 0x03, 0x5a, 0x02, 0x5d, 0x02, 0x5e, 0x02, 0x60, 0x02, 0x61, 0x01,
+ 0x63, 0x01, 0x64, 0x01, 0x41, 0x2a, 0x47, 0x16, 0x4f, 0x0d, 0x54, 0x09,
+ 0x5b, 0x06, 0x5f, 0x05, 0x62, 0x04, 0x64, 0x03, 0x67, 0x02, 0x69, 0x02,
+ 0x6b, 0x02, 0x6c, 0x02, 0x6e, 0x01, 0x6f, 0x01, 0x70, 0x01, 0x70, 0x01,
+ 0x71, 0x01, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x45, 0x1d, 0x4a, 0x14, 0x50, 0x0e, 0x54, 0x0b, 0x59, 0x08, 0x5c, 0x07,
+ 0x5f, 0x06, 0x60, 0x05, 0x64, 0x04, 0x65, 0x03, 0x67, 0x03, 0x68, 0x02,
+ 0x6a, 0x02, 0x6b, 0x02, 0x6c, 0x02, 0x6c, 0x02, 0x6e, 0x02, 0x6f, 0x01,
+ 0x70, 0x01, 0x70, 0x01, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x60, 0x08, 0x3b,
+ 0x12, 0x28, 0x1d, 0x1d, 0x26, 0x16, 0x2e, 0x11, 0x34, 0x0e, 0x3a, 0x0c,
+ 0x3f, 0x0a, 0x44, 0x08, 0x47, 0x07, 0x4b, 0x06, 0x4d, 0x05, 0x51, 0x05,
+ 0x52, 0x04, 0x55, 0x04, 0x57, 0x04, 0x58, 0x04, 0x5a, 0x03, 0x5c, 0x02,
+ 0x42, 0x30, 0x45, 0x1d, 0x4b, 0x14, 0x4f, 0x0e, 0x55, 0x0b, 0x59, 0x08,
+ 0x5c, 0x07, 0x5e, 0x06, 0x61, 0x05, 0x64, 0x04, 0x65, 0x03, 0x67, 0x03,
+ 0x68, 0x02, 0x6a, 0x02, 0x6b, 0x02, 0x6b, 0x02, 0x6d, 0x02, 0x6e, 0x02,
+ 0x6f, 0x01, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x22, 0x48, 0x19,
+ 0x4d, 0x13, 0x50, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x5a, 0x08, 0x5c, 0x07,
+ 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x65, 0x03, 0x67, 0x03,
+ 0x68, 0x03, 0x68, 0x02, 0x6a, 0x02, 0x6b, 0x02, 0x6c, 0x02, 0x6d, 0x02,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x00, 0x66, 0x05, 0x45, 0x0d, 0x32, 0x16, 0x26,
+ 0x1e, 0x1e, 0x25, 0x18, 0x2b, 0x14, 0x31, 0x11, 0x36, 0x0f, 0x3a, 0x0c,
+ 0x3e, 0x0b, 0x42, 0x0a, 0x45, 0x09, 0x47, 0x07, 0x4a, 0x07, 0x4c, 0x06,
+ 0x4f, 0x05, 0x51, 0x05, 0x52, 0x05, 0x54, 0x04, 0x41, 0x33, 0x44, 0x22,
+ 0x48, 0x19, 0x4c, 0x13, 0x51, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x59, 0x08,
+ 0x5d, 0x07, 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x65, 0x03,
+ 0x67, 0x03, 0x67, 0x03, 0x69, 0x02, 0x6a, 0x02, 0x6b, 0x02, 0x6c, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x43, 0x26, 0x47, 0x1d, 0x4a, 0x17, 0x4d, 0x12,
+ 0x51, 0x0f, 0x54, 0x0d, 0x56, 0x0b, 0x58, 0x09, 0x5b, 0x08, 0x5d, 0x07,
+ 0x5f, 0x06, 0x60, 0x06, 0x62, 0x05, 0x63, 0x05, 0x64, 0x04, 0x65, 0x03,
+ 0x67, 0x03, 0x67, 0x03, 0x68, 0x03, 0x69, 0x02, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x00, 0x6a, 0x04, 0x4d, 0x0b, 0x3a, 0x11, 0x2e, 0x18, 0x25, 0x1f, 0x1f,
+ 0x24, 0x1a, 0x29, 0x16, 0x2e, 0x13, 0x33, 0x11, 0x37, 0x0f, 0x3a, 0x0d,
+ 0x3d, 0x0c, 0x40, 0x0a, 0x43, 0x0a, 0x45, 0x09, 0x48, 0x07, 0x4a, 0x07,
+ 0x4c, 0x07, 0x4e, 0x06, 0x41, 0x35, 0x43, 0x26, 0x47, 0x1d, 0x49, 0x17,
+ 0x4e, 0x12, 0x51, 0x0f, 0x54, 0x0d, 0x55, 0x0b, 0x59, 0x09, 0x5b, 0x08,
+ 0x5d, 0x07, 0x5f, 0x06, 0x60, 0x06, 0x62, 0x05, 0x63, 0x05, 0x63, 0x04,
+ 0x65, 0x03, 0x67, 0x03, 0x67, 0x03, 0x68, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x43, 0x29, 0x45, 0x20, 0x49, 0x1a, 0x4b, 0x15, 0x4f, 0x12, 0x51, 0x0f,
+ 0x54, 0x0d, 0x55, 0x0b, 0x58, 0x0a, 0x5a, 0x09, 0x5b, 0x08, 0x5d, 0x07,
+ 0x5f, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x64, 0x05, 0x65, 0x04,
+ 0x65, 0x03, 0x66, 0x03, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x6d, 0x03, 0x52,
+ 0x08, 0x41, 0x0e, 0x34, 0x14, 0x2b, 0x1a, 0x24, 0x1f, 0x1f, 0x24, 0x1b,
+ 0x28, 0x17, 0x2d, 0x15, 0x31, 0x12, 0x34, 0x10, 0x37, 0x0f, 0x3a, 0x0d,
+ 0x3d, 0x0c, 0x40, 0x0b, 0x42, 0x0a, 0x44, 0x0a, 0x46, 0x09, 0x47, 0x07,
+ 0x41, 0x36, 0x43, 0x29, 0x46, 0x20, 0x48, 0x1a, 0x4c, 0x15, 0x4f, 0x12,
+ 0x51, 0x0f, 0x53, 0x0d, 0x56, 0x0b, 0x58, 0x0a, 0x5a, 0x09, 0x5b, 0x08,
+ 0x5d, 0x07, 0x5f, 0x06, 0x60, 0x06, 0x60, 0x05, 0x62, 0x05, 0x64, 0x05,
+ 0x65, 0x04, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x2b, 0x45, 0x23,
+ 0x48, 0x1d, 0x49, 0x18, 0x4d, 0x14, 0x4f, 0x12, 0x51, 0x10, 0x53, 0x0e,
+ 0x55, 0x0c, 0x57, 0x0b, 0x59, 0x0a, 0x5a, 0x09, 0x5c, 0x08, 0x5d, 0x07,
+ 0x5f, 0x07, 0x5f, 0x06, 0x61, 0x06, 0x62, 0x05, 0x63, 0x05, 0x64, 0x05,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x00, 0x6f, 0x02, 0x57, 0x07, 0x47, 0x0c, 0x3a,
+ 0x11, 0x31, 0x16, 0x29, 0x1b, 0x24, 0x20, 0x20, 0x23, 0x1c, 0x28, 0x19,
+ 0x2b, 0x16, 0x2f, 0x14, 0x32, 0x12, 0x35, 0x10, 0x38, 0x0f, 0x3a, 0x0e,
+ 0x3c, 0x0c, 0x3f, 0x0c, 0x41, 0x0b, 0x42, 0x0a, 0x41, 0x37, 0x43, 0x2b,
+ 0x45, 0x23, 0x47, 0x1d, 0x4a, 0x18, 0x4d, 0x14, 0x4f, 0x12, 0x51, 0x10,
+ 0x53, 0x0e, 0x55, 0x0c, 0x57, 0x0b, 0x59, 0x0a, 0x5a, 0x09, 0x5c, 0x08,
+ 0x5d, 0x07, 0x5e, 0x07, 0x60, 0x06, 0x61, 0x06, 0x62, 0x05, 0x63, 0x05,
+ 0x1f, 0x00, 0x3f, 0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00,
+ 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00,
+ 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x1f, 0x1f, 0x3f, 0x00,
+ 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00,
+ 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00,
+ 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7d, 0x00, 0x58, 0x00, 0x70, 0x00, 0x77, 0x00, 0x79, 0x00, 0x7b, 0x00,
+ 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00,
+ 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x1f, 0x1f, 0x3f, 0x00,
+ 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00,
+ 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00,
+ 0x7e, 0x00, 0x7e, 0x00, 0x43, 0x2d, 0x44, 0x25, 0x46, 0x1f, 0x48, 0x1b,
+ 0x4b, 0x17, 0x4d, 0x14, 0x50, 0x12, 0x51, 0x10, 0x53, 0x0e, 0x55, 0x0c,
+ 0x57, 0x0b, 0x58, 0x0b, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x08, 0x5c, 0x07,
+ 0x5f, 0x07, 0x60, 0x06, 0x61, 0x06, 0x62, 0x06, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x00, 0x71, 0x02, 0x5b, 0x05, 0x4b, 0x0a, 0x3f, 0x0f, 0x36, 0x13, 0x2e,
+ 0x18, 0x29, 0x1c, 0x23, 0x20, 0x20, 0x23, 0x1d, 0x27, 0x19, 0x2a, 0x17,
+ 0x2d, 0x16, 0x30, 0x12, 0x33, 0x12, 0x35, 0x10, 0x38, 0x0f, 0x3b, 0x0e,
+ 0x3c, 0x0c, 0x3e, 0x0c, 0x41, 0x38, 0x43, 0x2d, 0x44, 0x25, 0x45, 0x1f,
+ 0x49, 0x1b, 0x4b, 0x17, 0x4d, 0x14, 0x4f, 0x11, 0x51, 0x10, 0x53, 0x0e,
+ 0x55, 0x0c, 0x57, 0x0b, 0x58, 0x0b, 0x5a, 0x09, 0x5b, 0x09, 0x5b, 0x08,
+ 0x5e, 0x07, 0x5f, 0x07, 0x60, 0x06, 0x61, 0x06, 0x00, 0x00, 0x0a, 0x00,
+ 0x3f, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00,
+ 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00,
+ 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x3f, 0x0a, 0x0a, 0x3f, 0x00, 0x5c, 0x00,
+ 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00,
+ 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x44, 0x00,
+ 0x55, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x75, 0x00, 0x78, 0x00,
+ 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00,
+ 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x3f, 0x0a, 0x0a, 0x3f, 0x00, 0x5c, 0x00,
+ 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00,
+ 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00,
+ 0x42, 0x2f, 0x44, 0x27, 0x46, 0x22, 0x47, 0x1d, 0x4a, 0x19, 0x4c, 0x16,
+ 0x4e, 0x13, 0x4f, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x56, 0x0c,
+ 0x58, 0x0b, 0x59, 0x0a, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x07, 0x5e, 0x07,
+ 0x5f, 0x07, 0x5f, 0x06, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x73, 0x01, 0x5e,
+ 0x05, 0x4f, 0x08, 0x44, 0x0c, 0x3a, 0x10, 0x33, 0x15, 0x2d, 0x19, 0x28,
+ 0x1d, 0x23, 0x20, 0x20, 0x23, 0x1d, 0x26, 0x1a, 0x2a, 0x18, 0x2c, 0x16,
+ 0x2f, 0x14, 0x31, 0x12, 0x34, 0x12, 0x35, 0x0f, 0x38, 0x0f, 0x3b, 0x0f,
+ 0x41, 0x39, 0x42, 0x2f, 0x44, 0x27, 0x45, 0x22, 0x48, 0x1d, 0x4a, 0x19,
+ 0x4c, 0x16, 0x4d, 0x14, 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d,
+ 0x56, 0x0c, 0x58, 0x0b, 0x59, 0x0a, 0x59, 0x09, 0x5c, 0x09, 0x5c, 0x07,
+ 0x5e, 0x07, 0x5f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x2d, 0x00,
+ 0x48, 0x00, 0x59, 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00,
+ 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00,
+ 0x00, 0x66, 0x00, 0x3f, 0x03, 0x03, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00,
+ 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00,
+ 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x55, 0x00, 0x20, 0x00, 0x3e, 0x00,
+ 0x50, 0x00, 0x5a, 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00,
+ 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00,
+ 0x00, 0x66, 0x00, 0x3f, 0x03, 0x03, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00,
+ 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00,
+ 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x42, 0x30, 0x44, 0x29,
+ 0x45, 0x23, 0x46, 0x1f, 0x49, 0x1b, 0x4b, 0x18, 0x4c, 0x15, 0x4d, 0x13,
+ 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x56, 0x0c, 0x57, 0x0b,
+ 0x59, 0x0b, 0x59, 0x09, 0x5b, 0x09, 0x5c, 0x09, 0x5c, 0x07, 0x5e, 0x07,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x00, 0x73, 0x01, 0x61, 0x04, 0x52, 0x07, 0x47,
+ 0x0b, 0x3e, 0x0f, 0x37, 0x12, 0x31, 0x16, 0x2b, 0x19, 0x27, 0x1d, 0x23,
+ 0x20, 0x20, 0x23, 0x1d, 0x26, 0x1b, 0x29, 0x19, 0x2b, 0x16, 0x2e, 0x16,
+ 0x30, 0x13, 0x32, 0x12, 0x35, 0x12, 0x36, 0x0f, 0x41, 0x39, 0x42, 0x30,
+ 0x44, 0x29, 0x44, 0x23, 0x47, 0x1f, 0x49, 0x1b, 0x4b, 0x18, 0x4c, 0x15,
+ 0x4e, 0x13, 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x56, 0x0c,
+ 0x57, 0x0b, 0x57, 0x0b, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x09, 0x5c, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00,
+ 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00,
+ 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75, 0x00, 0x00, 0x72, 0x00, 0x5c,
+ 0x00, 0x2d, 0x01, 0x01, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00,
+ 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00,
+ 0x73, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x67, 0x00, 0x3e, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x3a, 0x00,
+ 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00,
+ 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75, 0x00, 0x00, 0x72, 0x00, 0x5c,
+ 0x00, 0x2d, 0x01, 0x01, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00,
+ 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00,
+ 0x73, 0x00, 0x75, 0x00, 0x42, 0x32, 0x44, 0x2a, 0x45, 0x25, 0x46, 0x21,
+ 0x48, 0x1d, 0x4a, 0x1a, 0x4b, 0x17, 0x4c, 0x15, 0x4e, 0x13, 0x50, 0x11,
+ 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x55, 0x0c, 0x57, 0x0c, 0x57, 0x0b,
+ 0x5a, 0x0a, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x09, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x00, 0x74, 0x01, 0x64, 0x04, 0x55, 0x06, 0x4a, 0x0a, 0x42, 0x0d, 0x3a,
+ 0x10, 0x34, 0x14, 0x2f, 0x17, 0x2a, 0x1a, 0x26, 0x1d, 0x23, 0x21, 0x21,
+ 0x22, 0x1d, 0x26, 0x1b, 0x28, 0x19, 0x2b, 0x18, 0x2c, 0x16, 0x30, 0x15,
+ 0x30, 0x12, 0x33, 0x12, 0x41, 0x3a, 0x42, 0x32, 0x44, 0x2a, 0x44, 0x25,
+ 0x46, 0x21, 0x48, 0x1d, 0x4a, 0x1a, 0x4b, 0x17, 0x4d, 0x15, 0x4e, 0x13,
+ 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x55, 0x0c, 0x56, 0x0c,
+ 0x58, 0x0b, 0x5a, 0x0a, 0x5a, 0x09, 0x5b, 0x09, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00,
+ 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00,
+ 0x6b, 0x00, 0x6e, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22,
+ 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00,
+ 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x6e, 0x00,
+ 0x50, 0x00, 0x28, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00,
+ 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00,
+ 0x6b, 0x00, 0x6e, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22,
+ 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00,
+ 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00,
+ 0x42, 0x32, 0x43, 0x2c, 0x44, 0x26, 0x45, 0x22, 0x48, 0x1f, 0x49, 0x1b,
+ 0x4b, 0x19, 0x4c, 0x16, 0x4e, 0x15, 0x4f, 0x13, 0x50, 0x11, 0x52, 0x10,
+ 0x53, 0x0e, 0x55, 0x0e, 0x55, 0x0c, 0x56, 0x0c, 0x57, 0x0b, 0x59, 0x0b,
+ 0x5a, 0x0a, 0x5a, 0x09, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x75, 0x01, 0x65,
+ 0x03, 0x58, 0x05, 0x4d, 0x09, 0x45, 0x0c, 0x3e, 0x0f, 0x37, 0x12, 0x32,
+ 0x16, 0x2d, 0x18, 0x2a, 0x1b, 0x26, 0x1d, 0x22, 0x21, 0x21, 0x22, 0x1d,
+ 0x26, 0x1c, 0x27, 0x19, 0x2b, 0x19, 0x2b, 0x16, 0x2e, 0x16, 0x30, 0x14,
+ 0x41, 0x3a, 0x42, 0x32, 0x43, 0x2c, 0x44, 0x26, 0x46, 0x22, 0x48, 0x1f,
+ 0x49, 0x1b, 0x4a, 0x19, 0x4c, 0x16, 0x4e, 0x15, 0x4f, 0x13, 0x50, 0x11,
+ 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0e, 0x54, 0x0c, 0x57, 0x0c, 0x57, 0x0b,
+ 0x59, 0x0b, 0x5a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00,
+ 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00,
+ 0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00,
+ 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00,
+ 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x72, 0x00, 0x5a, 0x00, 0x3a, 0x00,
+ 0x1b, 0x00, 0x01, 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00,
+ 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00,
+ 0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00,
+ 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00,
+ 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x42, 0x33, 0x43, 0x2d,
+ 0x44, 0x28, 0x45, 0x23, 0x47, 0x20, 0x48, 0x1d, 0x4a, 0x1a, 0x4a, 0x18,
+ 0x4c, 0x16, 0x4e, 0x14, 0x4f, 0x13, 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e,
+ 0x55, 0x0e, 0x54, 0x0d, 0x57, 0x0c, 0x57, 0x0b, 0x58, 0x0b, 0x5a, 0x0b,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x00, 0x76, 0x01, 0x67, 0x02, 0x5a, 0x05, 0x50,
+ 0x07, 0x47, 0x0a, 0x40, 0x0d, 0x3a, 0x10, 0x35, 0x12, 0x30, 0x16, 0x2c,
+ 0x19, 0x29, 0x1b, 0x26, 0x1d, 0x22, 0x21, 0x21, 0x22, 0x1d, 0x26, 0x1d,
+ 0x26, 0x1a, 0x2a, 0x19, 0x2b, 0x17, 0x2d, 0x16, 0x41, 0x3b, 0x42, 0x33,
+ 0x43, 0x2d, 0x44, 0x28, 0x45, 0x23, 0x47, 0x20, 0x48, 0x1d, 0x49, 0x1a,
+ 0x4b, 0x18, 0x4c, 0x16, 0x4e, 0x14, 0x4f, 0x13, 0x50, 0x11, 0x52, 0x10,
+ 0x53, 0x0e, 0x54, 0x0e, 0x55, 0x0d, 0x57, 0x0c, 0x57, 0x0b, 0x58, 0x0b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00,
+ 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b, 0x00, 0x00, 0x7c, 0x00, 0x75,
+ 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00,
+ 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00,
+ 0x57, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00,
+ 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00,
+ 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b, 0x00, 0x00, 0x7c, 0x00, 0x75,
+ 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00,
+ 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00,
+ 0x57, 0x00, 0x5b, 0x00, 0x42, 0x34, 0x43, 0x2e, 0x44, 0x29, 0x45, 0x25,
+ 0x46, 0x21, 0x48, 0x1e, 0x49, 0x1b, 0x4a, 0x19, 0x4c, 0x17, 0x4d, 0x15,
+ 0x4e, 0x14, 0x50, 0x13, 0x50, 0x11, 0x52, 0x11, 0x52, 0x0f, 0x53, 0x0e,
+ 0x55, 0x0d, 0x56, 0x0c, 0x57, 0x0c, 0x57, 0x0b, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x00, 0x77, 0x00, 0x68, 0x02, 0x5c, 0x05, 0x52, 0x07, 0x4a, 0x0a, 0x43,
+ 0x0c, 0x3d, 0x0f, 0x37, 0x12, 0x33, 0x14, 0x2f, 0x16, 0x2b, 0x19, 0x28,
+ 0x1c, 0x26, 0x1d, 0x22, 0x21, 0x22, 0x21, 0x1e, 0x25, 0x1d, 0x26, 0x1a,
+ 0x29, 0x19, 0x2b, 0x18, 0x41, 0x3b, 0x42, 0x34, 0x43, 0x2e, 0x44, 0x29,
+ 0x45, 0x25, 0x46, 0x21, 0x48, 0x1e, 0x48, 0x1b, 0x4b, 0x19, 0x4c, 0x17,
+ 0x4d, 0x15, 0x4e, 0x14, 0x50, 0x13, 0x50, 0x11, 0x52, 0x11, 0x51, 0x0f,
+ 0x54, 0x0e, 0x55, 0x0d, 0x56, 0x0c, 0x57, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00,
+ 0x4c, 0x00, 0x51, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56,
+ 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00,
+ 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00,
+ 0x4c, 0x00, 0x51, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56,
+ 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00,
+ 0x42, 0x34, 0x43, 0x2f, 0x44, 0x2a, 0x44, 0x26, 0x46, 0x22, 0x47, 0x1f,
+ 0x48, 0x1d, 0x49, 0x1a, 0x4b, 0x18, 0x4c, 0x17, 0x4e, 0x15, 0x4e, 0x13,
+ 0x50, 0x13, 0x50, 0x11, 0x52, 0x11, 0x51, 0x0f, 0x54, 0x0e, 0x55, 0x0d,
+ 0x56, 0x0c, 0x57, 0x0c, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x77, 0x00, 0x69,
+ 0x02, 0x5e, 0x04, 0x55, 0x06, 0x4c, 0x09, 0x45, 0x0c, 0x3f, 0x0e, 0x3a,
+ 0x10, 0x35, 0x12, 0x31, 0x16, 0x2e, 0x18, 0x2b, 0x19, 0x27, 0x1d, 0x26,
+ 0x1e, 0x22, 0x21, 0x22, 0x21, 0x1e, 0x25, 0x1d, 0x26, 0x1b, 0x28, 0x19,
+ 0x41, 0x3b, 0x42, 0x34, 0x43, 0x2f, 0x43, 0x2a, 0x45, 0x26, 0x46, 0x22,
+ 0x47, 0x1f, 0x48, 0x1d, 0x4a, 0x1a, 0x4b, 0x18, 0x4c, 0x17, 0x4e, 0x15,
+ 0x4e, 0x13, 0x50, 0x13, 0x50, 0x11, 0x51, 0x11, 0x52, 0x0f, 0x54, 0x0e,
+ 0x55, 0x0d, 0x56, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,
+ 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00,
+ 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37,
+ 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00,
+ 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00,
+ 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00,
+ 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00,
+ 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37,
+ 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00,
+ 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x42, 0x35, 0x43, 0x30,
+ 0x44, 0x2b, 0x44, 0x27, 0x45, 0x24, 0x46, 0x21, 0x48, 0x1e, 0x48, 0x1c,
+ 0x4b, 0x1a, 0x4b, 0x18, 0x4c, 0x16, 0x4e, 0x15, 0x4e, 0x13, 0x50, 0x12,
+ 0x50, 0x11, 0x51, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x55, 0x0e, 0x55, 0x0c,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x00, 0x77, 0x00, 0x6b, 0x02, 0x60, 0x04, 0x57,
+ 0x05, 0x4f, 0x07, 0x48, 0x0a, 0x42, 0x0c, 0x3c, 0x0f, 0x38, 0x12, 0x34,
+ 0x14, 0x30, 0x16, 0x2c, 0x19, 0x2b, 0x19, 0x26, 0x1d, 0x25, 0x1e, 0x22,
+ 0x21, 0x22, 0x21, 0x1e, 0x25, 0x1d, 0x26, 0x1c, 0x41, 0x3b, 0x42, 0x35,
+ 0x43, 0x30, 0x43, 0x2b, 0x44, 0x27, 0x45, 0x24, 0x46, 0x21, 0x47, 0x1e,
+ 0x49, 0x1c, 0x4b, 0x1a, 0x4b, 0x18, 0x4c, 0x16, 0x4e, 0x15, 0x4e, 0x13,
+ 0x50, 0x12, 0x50, 0x11, 0x52, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x55, 0x0e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00,
+ 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x00, 0x7d, 0x00, 0x7a,
+ 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f,
+ 0x00, 0x0e, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00,
+ 0x34, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00,
+ 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00,
+ 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x00, 0x7d, 0x00, 0x7a,
+ 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f,
+ 0x00, 0x0e, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00,
+ 0x34, 0x00, 0x3b, 0x00, 0x42, 0x36, 0x43, 0x30, 0x44, 0x2c, 0x44, 0x28,
+ 0x45, 0x25, 0x46, 0x22, 0x48, 0x1f, 0x48, 0x1d, 0x49, 0x1a, 0x4b, 0x19,
+ 0x4c, 0x18, 0x4d, 0x15, 0x4e, 0x15, 0x4f, 0x13, 0x50, 0x12, 0x50, 0x11,
+ 0x52, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x55, 0x0e, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x00, 0x77, 0x00, 0x6c, 0x02, 0x61, 0x04, 0x58, 0x05, 0x51, 0x07, 0x4a,
+ 0x0a, 0x44, 0x0c, 0x3f, 0x0f, 0x3a, 0x10, 0x35, 0x12, 0x32, 0x16, 0x30,
+ 0x16, 0x2b, 0x19, 0x2a, 0x1a, 0x26, 0x1d, 0x25, 0x1e, 0x22, 0x21, 0x22,
+ 0x21, 0x1e, 0x25, 0x1d, 0x41, 0x3b, 0x42, 0x36, 0x43, 0x30, 0x43, 0x2c,
+ 0x44, 0x28, 0x45, 0x25, 0x46, 0x22, 0x47, 0x1f, 0x49, 0x1d, 0x49, 0x1a,
+ 0x4b, 0x19, 0x4c, 0x18, 0x4d, 0x15, 0x4e, 0x15, 0x4f, 0x13, 0x4f, 0x12,
+ 0x51, 0x11, 0x52, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00,
+ 0x29, 0x00, 0x30, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69,
+ 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d,
+ 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00,
+ 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00,
+ 0x29, 0x00, 0x30, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69,
+ 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d,
+ 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00,
+ 0x42, 0x36, 0x42, 0x31, 0x43, 0x2d, 0x44, 0x29, 0x45, 0x26, 0x46, 0x23,
+ 0x47, 0x20, 0x47, 0x1e, 0x49, 0x1c, 0x4b, 0x1a, 0x4b, 0x18, 0x4c, 0x17,
+ 0x4d, 0x15, 0x4e, 0x14, 0x4f, 0x13, 0x4f, 0x12, 0x51, 0x11, 0x52, 0x11,
+ 0x52, 0x0f, 0x54, 0x0e, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x78, 0x00, 0x6d,
+ 0x01, 0x62, 0x03, 0x5a, 0x05, 0x52, 0x07, 0x4c, 0x09, 0x46, 0x0b, 0x41,
+ 0x0c, 0x3c, 0x0f, 0x38, 0x12, 0x35, 0x12, 0x30, 0x16, 0x2e, 0x17, 0x2b,
+ 0x19, 0x29, 0x1b, 0x26, 0x1d, 0x25, 0x1e, 0x22, 0x21, 0x22, 0x21, 0x1f,
+ 0x41, 0x3c, 0x42, 0x36, 0x42, 0x31, 0x43, 0x2d, 0x44, 0x29, 0x45, 0x26,
+ 0x46, 0x23, 0x46, 0x20, 0x48, 0x1e, 0x49, 0x1c, 0x4b, 0x1a, 0x4b, 0x18,
+ 0x4c, 0x17, 0x4d, 0x15, 0x4e, 0x14, 0x4e, 0x13, 0x50, 0x12, 0x51, 0x11,
+ 0x52, 0x11, 0x52, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00,
+ 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53,
+ 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00,
+ 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00,
+ 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00,
+ 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53,
+ 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00,
+ 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x42, 0x37, 0x42, 0x32,
+ 0x43, 0x2d, 0x44, 0x2a, 0x45, 0x27, 0x45, 0x23, 0x46, 0x21, 0x47, 0x1f,
+ 0x49, 0x1d, 0x49, 0x1a, 0x4b, 0x19, 0x4c, 0x18, 0x4c, 0x16, 0x4e, 0x15,
+ 0x4e, 0x14, 0x4f, 0x13, 0x50, 0x12, 0x51, 0x11, 0x52, 0x11, 0x52, 0x0f,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
+ 0x83, 0x00, 0x83, 0x00, 0x00, 0x78, 0x00, 0x6e, 0x01, 0x64, 0x02, 0x5b,
+ 0x04, 0x54, 0x06, 0x4e, 0x07, 0x47, 0x0a, 0x42, 0x0c, 0x3e, 0x0f, 0x3b,
+ 0x0f, 0x35, 0x12, 0x33, 0x14, 0x30, 0x16, 0x2d, 0x19, 0x2b, 0x19, 0x28,
+ 0x1c, 0x26, 0x1d, 0x25, 0x1f, 0x22, 0x21, 0x22, 0x41, 0x3c, 0x42, 0x37,
+ 0x42, 0x32, 0x43, 0x2d, 0x44, 0x2a, 0x45, 0x27, 0x45, 0x23, 0x46, 0x21,
+ 0x48, 0x1f, 0x49, 0x1d, 0x49, 0x1a, 0x4b, 0x19, 0x4c, 0x18, 0x4c, 0x16,
+ 0x4e, 0x15, 0x4d, 0x14, 0x50, 0x13, 0x50, 0x12, 0x51, 0x11, 0x52, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b, 0x00, 0x00, 0x7e, 0x00, 0x7c,
+ 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e,
+ 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x0a, 0x00,
+ 0x13, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00,
+ 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b, 0x00, 0x00, 0x7e, 0x00, 0x7c,
+ 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e,
+ 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x0a, 0x00,
+ 0x13, 0x00, 0x1b, 0x00, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x61, 0x20, 0x4d, 0x2a,
+ 0x48, 0x30, 0x44, 0x33, 0x44, 0x35, 0x44, 0x36, 0x43, 0x37, 0x42, 0x38,
+ 0x43, 0x39, 0x42, 0x39, 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b, 0x42, 0x3b,
+ 0x42, 0x3b, 0x41, 0x3b, 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c,
+ 0x04, 0x3d, 0x22, 0x3d, 0x2b, 0x3d, 0x30, 0x3d, 0x33, 0x3d, 0x35, 0x3d,
+ 0x37, 0x3d, 0x38, 0x3d, 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
+ 0x3b, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d,
+ 0x3c, 0x3d, 0x3c, 0x3d, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x12, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71,
+ 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c,
+ 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00,
+ 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00,
+ 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x12, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71,
+ 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c,
+ 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x6c, 0x0b, 0x57, 0x16, 0x4f, 0x1d, 0x4a, 0x22,
+ 0x48, 0x26, 0x47, 0x29, 0x46, 0x2b, 0x44, 0x2d, 0x44, 0x2f, 0x44, 0x30,
+ 0x44, 0x31, 0x44, 0x32, 0x43, 0x33, 0x43, 0x34, 0x43, 0x34, 0x42, 0x35,
+ 0x43, 0x36, 0x42, 0x36, 0x42, 0x37, 0x42, 0x37, 0x00, 0x5d, 0x0c, 0x49,
+ 0x16, 0x43, 0x1d, 0x41, 0x22, 0x40, 0x26, 0x3f, 0x29, 0x3f, 0x2c, 0x3f,
+ 0x2e, 0x3e, 0x2f, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x33, 0x3e, 0x33, 0x3e,
+ 0x34, 0x3e, 0x35, 0x3e, 0x35, 0x3e, 0x36, 0x3e, 0x37, 0x3e, 0x37, 0x3e,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62,
+ 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e,
+ 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00,
+ 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00,
+ 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62,
+ 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e,
+ 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x08, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x72, 0x06, 0x5f, 0x0d, 0x56, 0x14, 0x4f, 0x19, 0x4d, 0x1d, 0x4a, 0x20,
+ 0x49, 0x23, 0x47, 0x25, 0x46, 0x27, 0x46, 0x29, 0x45, 0x2a, 0x45, 0x2c,
+ 0x44, 0x2d, 0x44, 0x2e, 0x44, 0x2f, 0x43, 0x30, 0x44, 0x30, 0x44, 0x31,
+ 0x43, 0x32, 0x43, 0x33, 0x00, 0x68, 0x06, 0x54, 0x0d, 0x4b, 0x14, 0x47,
+ 0x19, 0x44, 0x1d, 0x43, 0x20, 0x41, 0x23, 0x41, 0x26, 0x40, 0x27, 0x40,
+ 0x29, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f, 0x2d, 0x3f, 0x2e, 0x3f, 0x2f, 0x3f,
+ 0x30, 0x3f, 0x30, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d,
+ 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51,
+ 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00,
+ 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00,
+ 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d,
+ 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51,
+ 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12,
+ 0x00, 0x08, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x75, 0x03, 0x64, 0x09,
+ 0x5a, 0x0e, 0x54, 0x13, 0x51, 0x17, 0x4e, 0x1a, 0x4c, 0x1d, 0x49, 0x1f,
+ 0x49, 0x22, 0x48, 0x23, 0x47, 0x25, 0x46, 0x26, 0x46, 0x28, 0x45, 0x29,
+ 0x45, 0x2a, 0x44, 0x2b, 0x44, 0x2c, 0x44, 0x2d, 0x44, 0x2e, 0x44, 0x2e,
+ 0x00, 0x6d, 0x04, 0x5b, 0x09, 0x51, 0x0e, 0x4c, 0x13, 0x48, 0x17, 0x46,
+ 0x1a, 0x44, 0x1d, 0x43, 0x1f, 0x42, 0x22, 0x42, 0x24, 0x41, 0x25, 0x41,
+ 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f,
+ 0x2d, 0x3f, 0x2e, 0x3f, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x3f, 0x00, 0x66, 0x00, 0x72, 0x00,
+ 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00,
+ 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x00, 0x3f,
+ 0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c,
+ 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x77, 0x02, 0x68, 0x06, 0x5f, 0x0b, 0x58, 0x0f,
+ 0x54, 0x12, 0x51, 0x15, 0x4f, 0x18, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1f,
+ 0x49, 0x21, 0x48, 0x22, 0x48, 0x23, 0x47, 0x25, 0x46, 0x26, 0x45, 0x27,
+ 0x45, 0x28, 0x45, 0x29, 0x45, 0x2a, 0x44, 0x2b, 0x00, 0x70, 0x02, 0x60,
+ 0x07, 0x56, 0x0b, 0x50, 0x0f, 0x4c, 0x12, 0x49, 0x16, 0x47, 0x18, 0x46,
+ 0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x43, 0x21, 0x42, 0x22, 0x42, 0x24, 0x41,
+ 0x25, 0x41, 0x26, 0x40, 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3f, 0x0a, 0x0a, 0x3f, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x71, 0x00,
+ 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00,
+ 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x0a, 0x00, 0x3f, 0x00, 0x5c,
+ 0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a,
+ 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x78, 0x02, 0x6b, 0x05, 0x62, 0x08, 0x5b, 0x0c, 0x57, 0x0f, 0x54, 0x12,
+ 0x51, 0x14, 0x4e, 0x17, 0x4d, 0x19, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e,
+ 0x49, 0x20, 0x48, 0x21, 0x48, 0x22, 0x46, 0x24, 0x46, 0x25, 0x46, 0x26,
+ 0x46, 0x27, 0x45, 0x27, 0x00, 0x72, 0x02, 0x64, 0x05, 0x5b, 0x08, 0x54,
+ 0x0c, 0x50, 0x0f, 0x4d, 0x12, 0x4a, 0x14, 0x48, 0x17, 0x47, 0x19, 0x46,
+ 0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x44, 0x20, 0x42, 0x21, 0x42, 0x22, 0x42,
+ 0x24, 0x41, 0x25, 0x41, 0x26, 0x41, 0x27, 0x40, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x3f,
+ 0x03, 0x03, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00, 0x63, 0x00, 0x6a, 0x00,
+ 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00,
+ 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x3f, 0x00, 0x03, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59,
+ 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76,
+ 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x79, 0x01, 0x6d, 0x04,
+ 0x65, 0x07, 0x5e, 0x0a, 0x5a, 0x0d, 0x56, 0x0f, 0x54, 0x12, 0x51, 0x14,
+ 0x4f, 0x16, 0x4e, 0x18, 0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e,
+ 0x49, 0x1f, 0x48, 0x21, 0x48, 0x22, 0x48, 0x23, 0x47, 0x23, 0x46, 0x25,
+ 0x00, 0x74, 0x01, 0x66, 0x04, 0x5e, 0x07, 0x57, 0x0a, 0x53, 0x0d, 0x4f,
+ 0x10, 0x4d, 0x12, 0x4b, 0x14, 0x49, 0x16, 0x48, 0x18, 0x46, 0x1a, 0x45,
+ 0x1b, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x20, 0x43, 0x21, 0x42, 0x22, 0x42,
+ 0x23, 0x42, 0x24, 0x41, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c, 0x00, 0x2d, 0x01, 0x01,
+ 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64, 0x00,
+ 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c, 0x00,
+ 0x2d, 0x00, 0x01, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56,
+ 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71,
+ 0x00, 0x73, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7a, 0x01, 0x6f, 0x03, 0x67, 0x06, 0x60, 0x08,
+ 0x5d, 0x0b, 0x59, 0x0d, 0x56, 0x10, 0x53, 0x11, 0x51, 0x14, 0x50, 0x15,
+ 0x4e, 0x17, 0x4d, 0x19, 0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x48, 0x1e,
+ 0x49, 0x1f, 0x49, 0x20, 0x48, 0x21, 0x48, 0x22, 0x00, 0x75, 0x01, 0x69,
+ 0x03, 0x61, 0x06, 0x5a, 0x08, 0x56, 0x0b, 0x52, 0x0d, 0x4f, 0x10, 0x4d,
+ 0x12, 0x4b, 0x14, 0x4a, 0x16, 0x48, 0x17, 0x47, 0x19, 0x46, 0x1a, 0x45,
+ 0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x20, 0x43, 0x21, 0x42,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00, 0x00, 0x1b, 0x00,
+ 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61, 0x00,
+ 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00,
+ 0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54,
+ 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7b, 0x01, 0x71, 0x02, 0x69, 0x05, 0x62, 0x07, 0x5f, 0x09, 0x5b, 0x0c,
+ 0x58, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x15, 0x4e, 0x16,
+ 0x4e, 0x18, 0x4c, 0x19, 0x4c, 0x1a, 0x4a, 0x1c, 0x4b, 0x1d, 0x49, 0x1e,
+ 0x49, 0x1f, 0x49, 0x20, 0x00, 0x76, 0x01, 0x6b, 0x03, 0x63, 0x05, 0x5d,
+ 0x07, 0x58, 0x09, 0x54, 0x0c, 0x52, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c,
+ 0x13, 0x4a, 0x15, 0x49, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x45,
+ 0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x71,
+ 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x16, 0x00, 0x28, 0x00,
+ 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e, 0x00,
+ 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x00,
+ 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53,
+ 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7b, 0x00, 0x72, 0x02,
+ 0x6b, 0x04, 0x64, 0x06, 0x61, 0x08, 0x5d, 0x0a, 0x5a, 0x0c, 0x56, 0x0e,
+ 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x15, 0x4f, 0x16, 0x4e, 0x17,
+ 0x4d, 0x18, 0x4b, 0x1a, 0x4b, 0x1a, 0x4b, 0x1c, 0x4b, 0x1d, 0x49, 0x1d,
+ 0x00, 0x77, 0x00, 0x6c, 0x02, 0x65, 0x04, 0x5f, 0x06, 0x5a, 0x08, 0x57,
+ 0x0a, 0x54, 0x0c, 0x51, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c, 0x13, 0x4a,
+ 0x15, 0x49, 0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x1a, 0x46, 0x1b, 0x45,
+ 0x1c, 0x45, 0x1d, 0x45, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a,
+ 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30, 0x00,
+ 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75, 0x00,
+ 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x13,
+ 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52,
+ 0x00, 0x57, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7c, 0x00, 0x73, 0x02, 0x6c, 0x03, 0x66, 0x05,
+ 0x63, 0x07, 0x5e, 0x09, 0x5c, 0x0b, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x10,
+ 0x53, 0x11, 0x52, 0x13, 0x50, 0x14, 0x4f, 0x15, 0x4e, 0x17, 0x4c, 0x18,
+ 0x4c, 0x19, 0x4c, 0x1a, 0x4b, 0x1a, 0x4b, 0x1c, 0x00, 0x77, 0x00, 0x6e,
+ 0x02, 0x66, 0x04, 0x61, 0x05, 0x5c, 0x07, 0x59, 0x09, 0x56, 0x0b, 0x53,
+ 0x0d, 0x51, 0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a,
+ 0x15, 0x48, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x46, 0x1b, 0x45,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28,
+ 0x00, 0x13, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35, 0x00,
+ 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00,
+ 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
+ 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7c, 0x00, 0x74, 0x02, 0x6e, 0x03, 0x68, 0x05, 0x64, 0x06, 0x60, 0x08,
+ 0x5d, 0x0a, 0x5a, 0x0b, 0x58, 0x0d, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11,
+ 0x52, 0x13, 0x50, 0x14, 0x50, 0x15, 0x4d, 0x16, 0x4e, 0x18, 0x4c, 0x18,
+ 0x4c, 0x19, 0x4c, 0x1a, 0x00, 0x77, 0x00, 0x6f, 0x02, 0x68, 0x03, 0x63,
+ 0x05, 0x5e, 0x06, 0x5a, 0x08, 0x57, 0x0a, 0x55, 0x0b, 0x53, 0x0d, 0x50,
+ 0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x49,
+ 0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x19, 0x46, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x79,
+ 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10,
+ 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, 0x00,
+ 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00,
+ 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27,
+ 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x75, 0x01,
+ 0x6f, 0x02, 0x69, 0x04, 0x65, 0x06, 0x62, 0x07, 0x5f, 0x09, 0x5b, 0x0b,
+ 0x5a, 0x0c, 0x58, 0x0d, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13,
+ 0x50, 0x13, 0x4f, 0x15, 0x4e, 0x15, 0x4e, 0x17, 0x4d, 0x18, 0x4c, 0x18,
+ 0x00, 0x78, 0x00, 0x70, 0x01, 0x69, 0x03, 0x64, 0x04, 0x60, 0x06, 0x5c,
+ 0x07, 0x59, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x52, 0x0d, 0x50, 0x0f, 0x4f,
+ 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x48,
+ 0x17, 0x48, 0x18, 0x47, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64,
+ 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00,
+ 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a, 0x00,
+ 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c,
+ 0x00, 0x34, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x76, 0x01, 0x70, 0x02, 0x6a, 0x03,
+ 0x67, 0x05, 0x63, 0x06, 0x60, 0x08, 0x5d, 0x09, 0x5b, 0x0b, 0x59, 0x0c,
+ 0x57, 0x0d, 0x55, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x4f, 0x13,
+ 0x50, 0x15, 0x4f, 0x15, 0x4e, 0x16, 0x4e, 0x18, 0x00, 0x78, 0x00, 0x71,
+ 0x01, 0x6a, 0x03, 0x66, 0x04, 0x61, 0x05, 0x5d, 0x06, 0x5a, 0x08, 0x58,
+ 0x09, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0e, 0x50, 0x0f, 0x4e, 0x10, 0x4e,
+ 0x11, 0x4c, 0x13, 0x4c, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x49, 0x16, 0x48,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b,
+ 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x0c, 0x00,
+ 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00,
+ 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7d, 0x00, 0x76, 0x01, 0x71, 0x02, 0x6c, 0x03, 0x68, 0x05, 0x64, 0x06,
+ 0x61, 0x07, 0x5e, 0x09, 0x5c, 0x0a, 0x5a, 0x0b, 0x59, 0x0c, 0x57, 0x0e,
+ 0x55, 0x0e, 0x55, 0x11, 0x52, 0x11, 0x51, 0x12, 0x51, 0x13, 0x50, 0x14,
+ 0x4f, 0x15, 0x4e, 0x15, 0x00, 0x79, 0x00, 0x71, 0x01, 0x6c, 0x02, 0x66,
+ 0x04, 0x62, 0x05, 0x5f, 0x06, 0x5c, 0x07, 0x59, 0x09, 0x57, 0x0a, 0x55,
+ 0x0b, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c,
+ 0x13, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x4a, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c,
+ 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35,
+ 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00,
+ 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00,
+ 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x77, 0x01,
+ 0x72, 0x02, 0x6d, 0x03, 0x69, 0x04, 0x66, 0x06, 0x63, 0x07, 0x5f, 0x08,
+ 0x5e, 0x09, 0x5c, 0x0b, 0x5a, 0x0c, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x0f,
+ 0x54, 0x11, 0x51, 0x11, 0x52, 0x12, 0x51, 0x13, 0x50, 0x14, 0x50, 0x15,
+ 0x00, 0x79, 0x00, 0x72, 0x01, 0x6d, 0x02, 0x68, 0x03, 0x63, 0x04, 0x60,
+ 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x53,
+ 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c,
+ 0x13, 0x4b, 0x14, 0x4a, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f,
+ 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23,
+ 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00,
+ 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00,
+ 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x13, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x78, 0x01, 0x72, 0x02, 0x6e, 0x02,
+ 0x6a, 0x03, 0x67, 0x05, 0x64, 0x06, 0x60, 0x07, 0x5f, 0x09, 0x5c, 0x0a,
+ 0x5b, 0x0b, 0x5a, 0x0c, 0x57, 0x0c, 0x56, 0x0e, 0x55, 0x0f, 0x53, 0x11,
+ 0x52, 0x11, 0x52, 0x12, 0x51, 0x13, 0x50, 0x13, 0x00, 0x79, 0x00, 0x73,
+ 0x01, 0x6d, 0x02, 0x69, 0x03, 0x65, 0x04, 0x61, 0x05, 0x5e, 0x06, 0x5c,
+ 0x07, 0x59, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54, 0x0d, 0x53, 0x0d, 0x51,
+ 0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c, 0x13, 0x4b,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e,
+ 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15,
+ 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00,
+ 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00,
+ 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x7e, 0x00, 0x78, 0x01, 0x73, 0x02, 0x6e, 0x02, 0x6b, 0x03, 0x68, 0x05,
+ 0x65, 0x06, 0x62, 0x07, 0x5f, 0x07, 0x5e, 0x09, 0x5c, 0x0b, 0x5a, 0x0b,
+ 0x59, 0x0c, 0x57, 0x0d, 0x56, 0x0e, 0x54, 0x0f, 0x54, 0x11, 0x52, 0x11,
+ 0x52, 0x12, 0x51, 0x13, 0x00, 0x79, 0x00, 0x73, 0x01, 0x6e, 0x02, 0x69,
+ 0x03, 0x66, 0x04, 0x62, 0x05, 0x5f, 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58,
+ 0x09, 0x56, 0x0b, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50,
+ 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4d, 0x12, 0x4c, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d,
+ 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c,
+ 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00,
+ 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00,
+ 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x78, 0x00,
+ 0x74, 0x01, 0x6f, 0x02, 0x6c, 0x03, 0x68, 0x04, 0x65, 0x05, 0x62, 0x06,
+ 0x61, 0x07, 0x5f, 0x09, 0x5c, 0x09, 0x5b, 0x0b, 0x5a, 0x0b, 0x58, 0x0c,
+ 0x57, 0x0d, 0x55, 0x0e, 0x55, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x52, 0x12,
+ 0x00, 0x79, 0x00, 0x74, 0x00, 0x6f, 0x02, 0x6a, 0x03, 0x66, 0x04, 0x63,
+ 0x05, 0x60, 0x05, 0x5e, 0x06, 0x5b, 0x07, 0x59, 0x09, 0x58, 0x09, 0x55,
+ 0x0b, 0x55, 0x0c, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50, 0x0f, 0x4e,
+ 0x11, 0x4e, 0x11, 0x4d, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75,
+ 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b,
+ 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00,
+ 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00,
+ 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x79, 0x00, 0x74, 0x01, 0x70, 0x02,
+ 0x6c, 0x03, 0x69, 0x03, 0x66, 0x05, 0x63, 0x06, 0x62, 0x07, 0x5f, 0x07,
+ 0x5e, 0x09, 0x5c, 0x0a, 0x5a, 0x0b, 0x5a, 0x0c, 0x57, 0x0c, 0x56, 0x0e,
+ 0x55, 0x0e, 0x55, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x00, 0x79, 0x00, 0x74,
+ 0x00, 0x70, 0x01, 0x6b, 0x02, 0x67, 0x03, 0x64, 0x04, 0x61, 0x05, 0x5f,
+ 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54,
+ 0x0c, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x66, 0x7f, 0x4d, 0x68, 0x49, 0x5c, 0x47, 0x55, 0x45, 0x51, 0x45, 0x4e,
+ 0x44, 0x4c, 0x43, 0x4a, 0x43, 0x49, 0x43, 0x48, 0x43, 0x47, 0x42, 0x47,
+ 0x42, 0x46, 0x42, 0x46, 0x42, 0x45, 0x42, 0x45, 0x42, 0x45, 0x42, 0x44,
+ 0x42, 0x44, 0x42, 0x44, 0x57, 0x7f, 0x2e, 0x58, 0x34, 0x4d, 0x37, 0x49,
+ 0x39, 0x47, 0x3a, 0x45, 0x3b, 0x44, 0x3b, 0x44, 0x3c, 0x43, 0x3c, 0x43,
+ 0x3c, 0x43, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x41,
+ 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x99, 0x7f, 0x4d, 0x58,
+ 0x49, 0x4d, 0x47, 0x49, 0x45, 0x47, 0x45, 0x45, 0x44, 0x44, 0x43, 0x44,
+ 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+ 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xa5, 0x16, 0x74, 0x23,
+ 0x62, 0x29, 0x59, 0x2d, 0x53, 0x30, 0x50, 0x32, 0x4e, 0x34, 0x4c, 0x35,
+ 0x4a, 0x36, 0x49, 0x37, 0x48, 0x38, 0x48, 0x38, 0x47, 0x39, 0x46, 0x39,
+ 0x46, 0x39, 0x46, 0x3a, 0x45, 0x3a, 0x45, 0x3a, 0x45, 0x3a, 0x44, 0x3b,
+ 0x23, 0x2f, 0x25, 0x35, 0x2a, 0x37, 0x2e, 0x39, 0x31, 0x3a, 0x33, 0x3b,
+ 0x34, 0x3b, 0x35, 0x3c, 0x37, 0x3c, 0x37, 0x3c, 0x38, 0x3d, 0x38, 0x3d,
+ 0x39, 0x3d, 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
+ 0x3b, 0x3d, 0x3b, 0x3d, 0x77, 0x27, 0x5f, 0x31, 0x56, 0x35, 0x52, 0x38,
+ 0x4f, 0x39, 0x4c, 0x3a, 0x4b, 0x3b, 0x49, 0x3b, 0x48, 0x3c, 0x48, 0x3c,
+ 0x47, 0x3c, 0x47, 0x3c, 0x46, 0x3d, 0x46, 0x3d, 0x45, 0x3d, 0x45, 0x3d,
+ 0x45, 0x3d, 0x44, 0x3d, 0x44, 0x3d, 0x44, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x5f, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xbb, 0x01, 0x91, 0x09, 0x78, 0x11, 0x6b, 0x17,
+ 0x62, 0x1c, 0x5c, 0x20, 0x58, 0x23, 0x55, 0x25, 0x52, 0x28, 0x51, 0x2a,
+ 0x4f, 0x2b, 0x4e, 0x2c, 0x4d, 0x2e, 0x4c, 0x2f, 0x4b, 0x30, 0x4a, 0x31,
+ 0x49, 0x31, 0x49, 0x32, 0x48, 0x33, 0x47, 0x33, 0x22, 0x25, 0x23, 0x2a,
+ 0x26, 0x2e, 0x2a, 0x31, 0x2c, 0x33, 0x2e, 0x34, 0x30, 0x36, 0x31, 0x37,
+ 0x32, 0x37, 0x33, 0x38, 0x34, 0x38, 0x35, 0x39, 0x36, 0x39, 0x36, 0x3a,
+ 0x37, 0x3a, 0x37, 0x3a, 0x38, 0x3a, 0x38, 0x3b, 0x39, 0x3b, 0x39, 0x3b,
+ 0x7a, 0x1a, 0x68, 0x24, 0x5f, 0x2a, 0x5a, 0x2e, 0x55, 0x31, 0x53, 0x33,
+ 0x51, 0x34, 0x4f, 0x35, 0x4d, 0x36, 0x4c, 0x37, 0x4b, 0x38, 0x4b, 0x38,
+ 0x4a, 0x39, 0x49, 0x39, 0x49, 0x39, 0x48, 0x3a, 0x47, 0x3a, 0x47, 0x3a,
+ 0x46, 0x3b, 0x46, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x39, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x8b, 0x00, 0x44, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xc6, 0x00, 0xa3, 0x02, 0x8a, 0x07, 0x7a, 0x0c, 0x6f, 0x11, 0x68, 0x15,
+ 0x62, 0x18, 0x5e, 0x1b, 0x5b, 0x1d, 0x58, 0x20, 0x56, 0x22, 0x54, 0x23,
+ 0x53, 0x25, 0x51, 0x26, 0x50, 0x28, 0x4e, 0x29, 0x4d, 0x2a, 0x4d, 0x2b,
+ 0x4d, 0x2c, 0x4c, 0x2c, 0x22, 0x23, 0x22, 0x27, 0x25, 0x2a, 0x27, 0x2c,
+ 0x2a, 0x2e, 0x2b, 0x30, 0x2d, 0x32, 0x2e, 0x33, 0x30, 0x34, 0x31, 0x34,
+ 0x32, 0x35, 0x33, 0x36, 0x33, 0x36, 0x34, 0x37, 0x34, 0x37, 0x35, 0x38,
+ 0x36, 0x38, 0x36, 0x39, 0x36, 0x39, 0x36, 0x39, 0x7b, 0x16, 0x6d, 0x1f,
+ 0x65, 0x24, 0x5f, 0x28, 0x5b, 0x2b, 0x58, 0x2d, 0x55, 0x2f, 0x54, 0x31,
+ 0x52, 0x32, 0x50, 0x33, 0x4f, 0x34, 0x4e, 0x35, 0x4d, 0x35, 0x4c, 0x36,
+ 0x4b, 0x36, 0x4a, 0x37, 0x4a, 0x38, 0x4a, 0x38, 0x4a, 0x39, 0x49, 0x39,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35,
+ 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xb3, 0x00, 0x9f, 0x00, 0x6d, 0x00, 0x33, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xcc, 0x00, 0xaf, 0x00,
+ 0x98, 0x03, 0x87, 0x06, 0x7b, 0x0a, 0x73, 0x0e, 0x6c, 0x11, 0x67, 0x13,
+ 0x63, 0x16, 0x5f, 0x18, 0x5c, 0x1a, 0x5a, 0x1c, 0x58, 0x1e, 0x56, 0x20,
+ 0x55, 0x21, 0x54, 0x22, 0x52, 0x24, 0x51, 0x25, 0x50, 0x26, 0x4f, 0x27,
+ 0x22, 0x22, 0x22, 0x25, 0x24, 0x27, 0x26, 0x2a, 0x28, 0x2b, 0x29, 0x2d,
+ 0x2b, 0x2f, 0x2c, 0x30, 0x2d, 0x31, 0x2f, 0x32, 0x30, 0x33, 0x30, 0x33,
+ 0x31, 0x34, 0x32, 0x35, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36, 0x34, 0x36,
+ 0x35, 0x36, 0x35, 0x37, 0x7c, 0x15, 0x71, 0x1b, 0x68, 0x20, 0x63, 0x24,
+ 0x5f, 0x27, 0x5c, 0x29, 0x59, 0x2c, 0x57, 0x2d, 0x55, 0x2f, 0x54, 0x30,
+ 0x53, 0x31, 0x51, 0x32, 0x50, 0x32, 0x4f, 0x33, 0x4f, 0x34, 0x4e, 0x35,
+ 0x4d, 0x35, 0x4c, 0x35, 0x4b, 0x35, 0x4a, 0x36, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x1d,
+ 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa, 0x00,
+ 0x85, 0x00, 0x57, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xcf, 0x00, 0xb7, 0x00, 0xa2, 0x00, 0x92, 0x03,
+ 0x85, 0x06, 0x7c, 0x09, 0x75, 0x0b, 0x6f, 0x0e, 0x6a, 0x11, 0x66, 0x13,
+ 0x63, 0x15, 0x5f, 0x17, 0x5e, 0x19, 0x5c, 0x1a, 0x5a, 0x1c, 0x57, 0x1d,
+ 0x56, 0x1f, 0x55, 0x1f, 0x55, 0x21, 0x54, 0x22, 0x22, 0x22, 0x22, 0x24,
+ 0x23, 0x26, 0x25, 0x28, 0x26, 0x29, 0x28, 0x2b, 0x29, 0x2c, 0x2b, 0x2d,
+ 0x2c, 0x2f, 0x2d, 0x30, 0x2d, 0x30, 0x2f, 0x31, 0x30, 0x32, 0x30, 0x33,
+ 0x30, 0x33, 0x32, 0x33, 0x32, 0x34, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36,
+ 0x7c, 0x14, 0x73, 0x19, 0x6c, 0x1e, 0x67, 0x22, 0x63, 0x24, 0x5f, 0x26,
+ 0x5c, 0x28, 0x5a, 0x2a, 0x58, 0x2c, 0x57, 0x2d, 0x55, 0x2e, 0x53, 0x2f,
+ 0x53, 0x30, 0x52, 0x31, 0x51, 0x31, 0x4f, 0x32, 0x4f, 0x33, 0x4f, 0x33,
+ 0x4f, 0x34, 0x4e, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70, 0x00,
+ 0x48, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xd2, 0x00, 0xbd, 0x00, 0xaa, 0x00, 0x9b, 0x01, 0x8e, 0x03, 0x84, 0x05,
+ 0x7c, 0x08, 0x76, 0x0a, 0x71, 0x0c, 0x6c, 0x0f, 0x69, 0x11, 0x66, 0x12,
+ 0x63, 0x14, 0x60, 0x16, 0x5e, 0x17, 0x5d, 0x19, 0x5b, 0x1a, 0x59, 0x1b,
+ 0x57, 0x1c, 0x56, 0x1e, 0x22, 0x22, 0x22, 0x23, 0x23, 0x25, 0x24, 0x27,
+ 0x25, 0x28, 0x27, 0x29, 0x28, 0x2b, 0x29, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d,
+ 0x2d, 0x2f, 0x2d, 0x30, 0x2d, 0x30, 0x2f, 0x30, 0x30, 0x32, 0x30, 0x33,
+ 0x30, 0x33, 0x31, 0x33, 0x32, 0x33, 0x33, 0x33, 0x7d, 0x13, 0x75, 0x18,
+ 0x6e, 0x1c, 0x69, 0x1f, 0x65, 0x22, 0x62, 0x24, 0x60, 0x26, 0x5c, 0x28,
+ 0x5b, 0x29, 0x59, 0x2a, 0x57, 0x2c, 0x57, 0x2d, 0x55, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2f, 0x53, 0x31, 0x51, 0x31, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x32,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c,
+ 0x00, 0x35, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbb, 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd3, 0x00, 0xc2, 0x00,
+ 0xb1, 0x00, 0xa2, 0x00, 0x96, 0x02, 0x8c, 0x03, 0x83, 0x05, 0x7d, 0x07,
+ 0x77, 0x09, 0x73, 0x0b, 0x6f, 0x0d, 0x6a, 0x0f, 0x68, 0x11, 0x66, 0x12,
+ 0x63, 0x14, 0x60, 0x15, 0x5f, 0x16, 0x5e, 0x18, 0x5c, 0x19, 0x5a, 0x1a,
+ 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x27, 0x26, 0x29,
+ 0x27, 0x29, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2d, 0x2b, 0x2d, 0x2c, 0x2e,
+ 0x2d, 0x2f, 0x2d, 0x30, 0x2e, 0x30, 0x2f, 0x30, 0x30, 0x31, 0x30, 0x32,
+ 0x30, 0x33, 0x30, 0x33, 0x7d, 0x13, 0x76, 0x17, 0x70, 0x1b, 0x6b, 0x1e,
+ 0x68, 0x20, 0x65, 0x22, 0x61, 0x24, 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x29,
+ 0x5a, 0x2a, 0x58, 0x2b, 0x57, 0x2c, 0x57, 0x2d, 0x55, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2f, 0x53, 0x30, 0x53, 0x31, 0x51, 0x31, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f,
+ 0x00, 0x25, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb6, 0x00,
+ 0xa6, 0x00, 0x8e, 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xd4, 0x00, 0xc5, 0x00, 0xb6, 0x00, 0xa8, 0x00,
+ 0x9c, 0x00, 0x92, 0x02, 0x8a, 0x03, 0x82, 0x05, 0x7d, 0x07, 0x78, 0x09,
+ 0x74, 0x0a, 0x71, 0x0c, 0x6c, 0x0e, 0x69, 0x0f, 0x68, 0x11, 0x65, 0x12,
+ 0x63, 0x13, 0x60, 0x14, 0x5f, 0x16, 0x5e, 0x17, 0x21, 0x22, 0x22, 0x23,
+ 0x22, 0x24, 0x23, 0x25, 0x24, 0x26, 0x25, 0x27, 0x27, 0x28, 0x27, 0x29,
+ 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2e,
+ 0x2d, 0x2f, 0x2d, 0x30, 0x2e, 0x30, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x31,
+ 0x7d, 0x12, 0x77, 0x16, 0x71, 0x19, 0x6d, 0x1c, 0x69, 0x1f, 0x66, 0x20,
+ 0x64, 0x23, 0x61, 0x24, 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x28, 0x5b, 0x2a,
+ 0x58, 0x2a, 0x57, 0x2b, 0x57, 0x2c, 0x56, 0x2e, 0x54, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21,
+ 0x00, 0x18, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97, 0x00,
+ 0x7e, 0x00, 0x64, 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xd5, 0x00, 0xc7, 0x00, 0xba, 0x00, 0xad, 0x00, 0xa2, 0x00, 0x98, 0x01,
+ 0x8f, 0x02, 0x88, 0x03, 0x82, 0x05, 0x7e, 0x07, 0x78, 0x08, 0x74, 0x0a,
+ 0x72, 0x0b, 0x6e, 0x0c, 0x6b, 0x0e, 0x69, 0x0f, 0x67, 0x11, 0x65, 0x12,
+ 0x63, 0x13, 0x60, 0x14, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
+ 0x24, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x28, 0x27, 0x29, 0x28, 0x2b,
+ 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2d, 0x2a, 0x2d, 0x2c, 0x2d, 0x2d, 0x2e,
+ 0x2d, 0x2f, 0x2d, 0x30, 0x2e, 0x30, 0x2f, 0x30, 0x7d, 0x12, 0x77, 0x15,
+ 0x72, 0x18, 0x6e, 0x1b, 0x6b, 0x1d, 0x68, 0x20, 0x65, 0x21, 0x64, 0x23,
+ 0x60, 0x24, 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x27, 0x5c, 0x29, 0x59, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2b, 0x57, 0x2c, 0x56, 0x2e, 0x54, 0x2e, 0x53, 0x2e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d,
+ 0x00, 0x3a, 0x00, 0x34, 0x00, 0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15,
+ 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71, 0x00,
+ 0x59, 0x00, 0x41, 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd6, 0x00, 0xc9, 0x00,
+ 0xbd, 0x00, 0xb2, 0x00, 0xa7, 0x00, 0x9d, 0x00, 0x95, 0x01, 0x8e, 0x02,
+ 0x87, 0x03, 0x82, 0x05, 0x7e, 0x06, 0x79, 0x08, 0x75, 0x09, 0x73, 0x0b,
+ 0x70, 0x0c, 0x6c, 0x0d, 0x6a, 0x0e, 0x68, 0x0f, 0x67, 0x11, 0x65, 0x12,
+ 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x24, 0x26,
+ 0x25, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b,
+ 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e,
+ 0x2d, 0x2f, 0x2d, 0x30, 0x7d, 0x12, 0x78, 0x15, 0x73, 0x18, 0x70, 0x1a,
+ 0x6d, 0x1d, 0x69, 0x1e, 0x67, 0x20, 0x65, 0x21, 0x63, 0x23, 0x60, 0x24,
+ 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x27, 0x5c, 0x28, 0x5a, 0x2a, 0x58, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2b, 0x57, 0x2c, 0x56, 0x2e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36,
+ 0x00, 0x30, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c,
+ 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00,
+ 0xb1, 0x00, 0xa3, 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50, 0x00,
+ 0x3a, 0x00, 0x25, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xd7, 0x00, 0xcb, 0x00, 0xc0, 0x00, 0xb5, 0x00,
+ 0xab, 0x00, 0xa2, 0x00, 0x9a, 0x00, 0x92, 0x02, 0x8d, 0x02, 0x87, 0x03,
+ 0x81, 0x05, 0x7e, 0x06, 0x79, 0x07, 0x76, 0x09, 0x74, 0x0a, 0x71, 0x0b,
+ 0x6e, 0x0c, 0x6b, 0x0d, 0x6a, 0x0e, 0x68, 0x10, 0x21, 0x22, 0x22, 0x22,
+ 0x22, 0x23, 0x23, 0x24, 0x23, 0x25, 0x24, 0x25, 0x25, 0x27, 0x25, 0x27,
+ 0x27, 0x28, 0x27, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b, 0x2a, 0x2b,
+ 0x2b, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e,
+ 0x7e, 0x12, 0x79, 0x15, 0x75, 0x17, 0x71, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d,
+ 0x69, 0x1f, 0x65, 0x20, 0x65, 0x22, 0x62, 0x23, 0x60, 0x23, 0x60, 0x25,
+ 0x5d, 0x27, 0x5c, 0x27, 0x5c, 0x28, 0x5c, 0x29, 0x59, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c,
+ 0x00, 0x26, 0x00, 0x1f, 0x00, 0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7, 0x00,
+ 0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35, 0x00,
+ 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xd7, 0x00, 0xcc, 0x00, 0xc2, 0x00, 0xb9, 0x00, 0xae, 0x00, 0xa6, 0x00,
+ 0x9e, 0x00, 0x97, 0x01, 0x90, 0x02, 0x8b, 0x02, 0x85, 0x04, 0x81, 0x05,
+ 0x7e, 0x06, 0x7a, 0x07, 0x76, 0x08, 0x74, 0x09, 0x72, 0x0b, 0x6f, 0x0c,
+ 0x6c, 0x0c, 0x6a, 0x0e, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
+ 0x23, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x28,
+ 0x26, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b,
+ 0x2b, 0x2d, 0x2b, 0x2d, 0x2c, 0x2d, 0x2d, 0x2d, 0x7e, 0x12, 0x79, 0x15,
+ 0x75, 0x17, 0x72, 0x19, 0x6e, 0x1a, 0x6c, 0x1d, 0x69, 0x1d, 0x68, 0x20,
+ 0x65, 0x20, 0x65, 0x22, 0x61, 0x23, 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27,
+ 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x29, 0x5a, 0x2a, 0x58, 0x2a, 0x57, 0x2a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e,
+ 0x00, 0x3c, 0x00, 0x38, 0x00, 0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22,
+ 0x00, 0x1c, 0x00, 0x16, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d, 0x00,
+ 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd8, 0x00, 0xce, 0x00,
+ 0xc5, 0x00, 0xbb, 0x00, 0xb2, 0x00, 0xaa, 0x00, 0xa1, 0x00, 0x9b, 0x00,
+ 0x94, 0x01, 0x8f, 0x02, 0x8a, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7e, 0x06,
+ 0x7b, 0x07, 0x77, 0x08, 0x75, 0x09, 0x73, 0x0a, 0x71, 0x0b, 0x6e, 0x0c,
+ 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25,
+ 0x24, 0x25, 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28,
+ 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c,
+ 0x2b, 0x2d, 0x2b, 0x2d, 0x7e, 0x12, 0x7a, 0x14, 0x76, 0x16, 0x72, 0x18,
+ 0x6f, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65, 0x20,
+ 0x64, 0x23, 0x61, 0x23, 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27, 0x5c, 0x27,
+ 0x5c, 0x27, 0x5c, 0x28, 0x5b, 0x2a, 0x59, 0x2a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39,
+ 0x00, 0x35, 0x00, 0x31, 0x00, 0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a,
+ 0x00, 0x14, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00,
+ 0xb6, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72, 0x00,
+ 0x60, 0x00, 0x4f, 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xd8, 0x00, 0xcf, 0x00, 0xc6, 0x00, 0xbd, 0x00,
+ 0xb5, 0x00, 0xad, 0x00, 0xa6, 0x00, 0x9e, 0x00, 0x99, 0x00, 0x92, 0x01,
+ 0x8e, 0x02, 0x89, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7e, 0x06, 0x7b, 0x07,
+ 0x77, 0x07, 0x75, 0x09, 0x73, 0x09, 0x72, 0x0b, 0x21, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25,
+ 0x25, 0x27, 0x25, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28,
+ 0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2d,
+ 0x7e, 0x12, 0x7a, 0x14, 0x76, 0x15, 0x72, 0x18, 0x71, 0x1a, 0x6d, 0x1a,
+ 0x6c, 0x1d, 0x69, 0x1d, 0x68, 0x1f, 0x65, 0x20, 0x65, 0x21, 0x64, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x27,
+ 0x5c, 0x27, 0x5c, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32,
+ 0x00, 0x2d, 0x00, 0x28, 0x00, 0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13,
+ 0x00, 0x0d, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00,
+ 0xa5, 0x00, 0x98, 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59, 0x00,
+ 0x49, 0x00, 0x39, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xd8, 0x00, 0xd0, 0x00, 0xc7, 0x00, 0xbf, 0x00, 0xb8, 0x00, 0xaf, 0x00,
+ 0xa9, 0x00, 0xa1, 0x00, 0x9c, 0x00, 0x96, 0x01, 0x90, 0x02, 0x8d, 0x02,
+ 0x88, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7f, 0x06, 0x7b, 0x07, 0x77, 0x07,
+ 0x76, 0x09, 0x74, 0x09, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23,
+ 0x23, 0x24, 0x23, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x26, 0x25, 0x27,
+ 0x26, 0x27, 0x27, 0x27, 0x26, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a,
+ 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x7e, 0x11, 0x7a, 0x13,
+ 0x76, 0x15, 0x74, 0x18, 0x72, 0x19, 0x6e, 0x1a, 0x6d, 0x1c, 0x69, 0x1d,
+ 0x69, 0x1e, 0x67, 0x20, 0x65, 0x20, 0x65, 0x21, 0x63, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27,
+ 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3c, 0x00, 0x3d,
+ 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f,
+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x58, 0x00, 0x3d,
+ 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x48, 0x00, 0x42, 0x00, 0x3e, 0x00, 0x3e,
+ 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0x0b, 0x07, 0x17, 0x00, 0x2c, 0x00, 0x36, 0x00, 0x3a, 0x00, 0x3c,
+ 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e,
+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x47, 0x07, 0x0f, 0x0f,
+ 0x00, 0x26, 0x00, 0x33, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3d,
+ 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f,
+ 0x00, 0x3f, 0x00, 0x3f, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd9, 0x00, 0xd1, 0x00,
+ 0xc9, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xb2, 0x00, 0xac, 0x00, 0xa5, 0x00,
+ 0x9e, 0x00, 0x9a, 0x00, 0x93, 0x01, 0x8f, 0x02, 0x8c, 0x02, 0x88, 0x03,
+ 0x83, 0x04, 0x81, 0x05, 0x7f, 0x06, 0x7b, 0x06, 0x78, 0x07, 0x76, 0x08,
+ 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24,
+ 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x25, 0x27, 0x27, 0x27,
+ 0x27, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b,
+ 0x2a, 0x2b, 0x2b, 0x2b, 0x7e, 0x11, 0x7b, 0x13, 0x77, 0x15, 0x75, 0x17,
+ 0x72, 0x18, 0x6f, 0x1a, 0x6d, 0x1a, 0x6c, 0x1d, 0x69, 0x1d, 0x69, 0x1f,
+ 0x65, 0x20, 0x65, 0x20, 0x65, 0x22, 0x62, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x25, 0x5f, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x1f, 0x00, 0x2e, 0x00, 0x35, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c,
+ 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e,
+ 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x30, 0x00, 0x39, 0x00, 0x42,
+ 0x00, 0x41, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d,
+ 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x27, 0x02,
+ 0x02, 0x12, 0x00, 0x25, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x38, 0x00, 0x3a,
+ 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e,
+ 0x00, 0x3e, 0x00, 0x3e, 0x7f, 0x00, 0x3f, 0x00, 0x05, 0x05, 0x00, 0x1c,
+ 0x00, 0x2a, 0x00, 0x31, 0x00, 0x35, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3b,
+ 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xd9, 0x00, 0xd2, 0x00, 0xca, 0x00, 0xc3, 0x00,
+ 0xbb, 0x00, 0xb5, 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa1, 0x00, 0x9d, 0x00,
+ 0x98, 0x00, 0x92, 0x01, 0x8e, 0x02, 0x8b, 0x02, 0x87, 0x03, 0x83, 0x04,
+ 0x81, 0x05, 0x7f, 0x06, 0x7c, 0x06, 0x78, 0x07, 0x21, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25,
+ 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x27, 0x27, 0x28,
+ 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x29, 0x2b,
+ 0x7e, 0x11, 0x7b, 0x13, 0x77, 0x15, 0x76, 0x17, 0x72, 0x18, 0x71, 0x1a,
+ 0x6d, 0x1a, 0x6d, 0x1c, 0x69, 0x1d, 0x69, 0x1d, 0x68, 0x20, 0x65, 0x20,
+ 0x65, 0x20, 0x65, 0x22, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x25,
+ 0x5f, 0x27, 0x5c, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x16,
+ 0x00, 0x24, 0x00, 0x2c, 0x00, 0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39,
+ 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d,
+ 0x00, 0x4c, 0x00, 0x39, 0x00, 0x16, 0x00, 0x28, 0x00, 0x2f, 0x00, 0x2e,
+ 0x00, 0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b,
+ 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x6f, 0x00, 0x22, 0x00, 0x09, 0x0b,
+ 0x00, 0x16, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x35,
+ 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c,
+ 0xa5, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x12, 0x00, 0x00, 0x09, 0x00, 0x19,
+ 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36,
+ 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3a, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xd9, 0x00, 0xd2, 0x00, 0xca, 0x00, 0xc5, 0x00, 0xbd, 0x00, 0xb7, 0x00,
+ 0xb0, 0x00, 0xab, 0x00, 0xa4, 0x00, 0x9f, 0x00, 0x9b, 0x00, 0x95, 0x01,
+ 0x91, 0x01, 0x8e, 0x02, 0x8a, 0x02, 0x86, 0x03, 0x83, 0x04, 0x81, 0x05,
+ 0x7f, 0x06, 0x7c, 0x06, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23,
+ 0x22, 0x23, 0x23, 0x24, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25,
+ 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x7f, 0x11, 0x7b, 0x13,
+ 0x77, 0x15, 0x76, 0x16, 0x72, 0x18, 0x72, 0x19, 0x6d, 0x1a, 0x6d, 0x1b,
+ 0x6b, 0x1d, 0x69, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65, 0x20, 0x65, 0x20,
+ 0x64, 0x22, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x24, 0x5f, 0x26,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x1d,
+ 0x00, 0x25, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36,
+ 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x4c, 0x00, 0x42,
+ 0x00, 0x28, 0x00, 0x09, 0x00, 0x16, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x2b,
+ 0x00, 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38,
+ 0x00, 0x39, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xaf, 0x00, 0x93, 0x00, 0x58, 0x00, 0x21, 0x00, 0x0e, 0x08, 0x02, 0x0e,
+ 0x00, 0x18, 0x00, 0x20, 0x00, 0x27, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x31,
+ 0x00, 0x33, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38, 0xb2, 0x00, 0x9c, 0x00,
+ 0x6d, 0x00, 0x3f, 0x00, 0x1d, 0x00, 0x05, 0x00, 0x00, 0x0b, 0x00, 0x16,
+ 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32,
+ 0x00, 0x33, 0x00, 0x35, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xda, 0x00, 0xd2, 0x00,
+ 0xcb, 0x00, 0xc6, 0x00, 0xbe, 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xac, 0x00,
+ 0xa8, 0x00, 0xa1, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x01, 0x90, 0x02,
+ 0x8d, 0x02, 0x89, 0x02, 0x85, 0x03, 0x83, 0x04, 0x81, 0x05, 0x7f, 0x06,
+ 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23,
+ 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27,
+ 0x25, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x29, 0x27, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x29, 0x7f, 0x11, 0x7b, 0x13, 0x78, 0x15, 0x76, 0x15,
+ 0x73, 0x18, 0x72, 0x18, 0x6f, 0x1a, 0x6d, 0x1a, 0x6d, 0x1c, 0x69, 0x1d,
+ 0x69, 0x1d, 0x69, 0x1f, 0x65, 0x20, 0x65, 0x20, 0x65, 0x21, 0x64, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x24, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f,
+ 0x00, 0x25, 0x00, 0x2a, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34,
+ 0x00, 0x35, 0x00, 0x37, 0x00, 0x48, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16,
+ 0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x2a,
+ 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34, 0x00, 0x35, 0x00, 0x37,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x00, 0xa4, 0x00,
+ 0x7a, 0x00, 0x4a, 0x00, 0x20, 0x00, 0x12, 0x06, 0x07, 0x0c, 0x00, 0x10,
+ 0x00, 0x18, 0x00, 0x1f, 0x00, 0x24, 0x00, 0x28, 0x00, 0x2c, 0x00, 0x2e,
+ 0x00, 0x30, 0x00, 0x32, 0xb7, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x62, 0x00,
+ 0x3f, 0x00, 0x24, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14,
+ 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2b, 0x00, 0x2e,
+ 0x33, 0x22, 0x28, 0x22, 0x25, 0x22, 0x24, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21,
+ 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x22, 0x22, 0x21, 0x22, 0x21,
+ 0x22, 0x21, 0x22, 0x21, 0x9d, 0x05, 0x6b, 0x0d, 0x51, 0x12, 0x45, 0x15,
+ 0x3d, 0x17, 0x38, 0x18, 0x35, 0x1a, 0x32, 0x1b, 0x30, 0x1b, 0x2f, 0x1c,
+ 0x2d, 0x1c, 0x2d, 0x1c, 0x2c, 0x1d, 0x2b, 0x1d, 0x2a, 0x1e, 0x2a, 0x1e,
+ 0x29, 0x1e, 0x29, 0x1e, 0x28, 0x1e, 0x28, 0x1e, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x5f, 0x13, 0x46, 0x17, 0x39, 0x1a, 0x33, 0x1b, 0x2f, 0x1c, 0x2d, 0x1d,
+ 0x2b, 0x1e, 0x2a, 0x1e, 0x29, 0x1e, 0x28, 0x1f, 0x27, 0x1f, 0x27, 0x1f,
+ 0x27, 0x1f, 0x26, 0x1f, 0x26, 0x20, 0x26, 0x20, 0x25, 0x20, 0x25, 0x20,
+ 0x25, 0x20, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21,
+ 0x00, 0x25, 0x00, 0x29, 0x00, 0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32,
+ 0x00, 0x42, 0x00, 0x3d, 0x00, 0x2e, 0x00, 0x1d, 0x00, 0x0d, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29,
+ 0x00, 0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, 0xad, 0x00, 0x8f, 0x00, 0x68, 0x00,
+ 0x42, 0x00, 0x20, 0x00, 0x14, 0x05, 0x0b, 0x0a, 0x04, 0x0d, 0x00, 0x12,
+ 0x00, 0x19, 0x00, 0x1e, 0x00, 0x23, 0x00, 0x26, 0x00, 0x29, 0x00, 0x2c,
+ 0xba, 0x00, 0xb1, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5b, 0x00, 0x3f, 0x00,
+ 0x29, 0x00, 0x16, 0x00, 0x08, 0x00, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x13,
+ 0x00, 0x19, 0x00, 0x1e, 0x00, 0x22, 0x00, 0x25, 0x37, 0x28, 0x2d, 0x25,
+ 0x28, 0x23, 0x26, 0x23, 0x25, 0x23, 0x24, 0x22, 0x24, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0xbc, 0x00, 0x8e, 0x01, 0x73, 0x04, 0x60, 0x08, 0x55, 0x0b, 0x4c, 0x0d,
+ 0x47, 0x0f, 0x42, 0x11, 0x3e, 0x12, 0x3b, 0x13, 0x39, 0x14, 0x37, 0x15,
+ 0x36, 0x16, 0x34, 0x16, 0x33, 0x17, 0x32, 0x18, 0x31, 0x18, 0x30, 0x19,
+ 0x2f, 0x19, 0x2f, 0x19, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x6f, 0x11, 0x58, 0x11,
+ 0x4a, 0x13, 0x41, 0x15, 0x3b, 0x16, 0x37, 0x17, 0x34, 0x18, 0x32, 0x19,
+ 0x30, 0x1a, 0x2e, 0x1a, 0x2d, 0x1b, 0x2c, 0x1b, 0x2c, 0x1c, 0x2b, 0x1c,
+ 0x2a, 0x1c, 0x2a, 0x1d, 0x29, 0x1d, 0x29, 0x1d, 0x28, 0x1d, 0x28, 0x1d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x09, 0x00, 0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22,
+ 0x00, 0x26, 0x00, 0x29, 0x00, 0x2b, 0x00, 0x2d, 0x00, 0x3e, 0x00, 0x3a,
+ 0x00, 0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x09,
+ 0x00, 0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22, 0x00, 0x26, 0x00, 0x29,
+ 0x00, 0x2b, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xba, 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x7d, 0x00, 0x5c, 0x00, 0x3c, 0x00,
+ 0x20, 0x00, 0x16, 0x04, 0x0e, 0x08, 0x07, 0x0c, 0x02, 0x0e, 0x00, 0x13,
+ 0x00, 0x19, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x25, 0xbb, 0x00, 0xb5, 0x00,
+ 0xa3, 0x00, 0x8a, 0x00, 0x6f, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x2c, 0x00,
+ 0x1c, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x12,
+ 0x00, 0x17, 0x00, 0x1c, 0x38, 0x2c, 0x30, 0x28, 0x2b, 0x26, 0x29, 0x25,
+ 0x27, 0x24, 0x26, 0x24, 0x25, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xc6, 0x00, 0xa4, 0x00,
+ 0x89, 0x00, 0x77, 0x02, 0x67, 0x04, 0x5e, 0x06, 0x55, 0x08, 0x50, 0x0a,
+ 0x4b, 0x0c, 0x47, 0x0d, 0x44, 0x0e, 0x41, 0x0f, 0x3e, 0x10, 0x3d, 0x11,
+ 0x3b, 0x12, 0x39, 0x12, 0x38, 0x13, 0x37, 0x14, 0x35, 0x15, 0x35, 0x16,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x74, 0x11, 0x63, 0x11, 0x55, 0x11, 0x4c, 0x12,
+ 0x44, 0x13, 0x40, 0x14, 0x3b, 0x15, 0x39, 0x16, 0x36, 0x17, 0x34, 0x17,
+ 0x33, 0x18, 0x31, 0x18, 0x30, 0x19, 0x2f, 0x19, 0x2e, 0x1a, 0x2d, 0x1a,
+ 0x2d, 0x1a, 0x2c, 0x1b, 0x2b, 0x1b, 0x2b, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22,
+ 0x00, 0x26, 0x00, 0x28, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b,
+ 0x00, 0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f,
+ 0x00, 0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22, 0x00, 0x26, 0x00, 0x28,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb5, 0x00,
+ 0xa4, 0x00, 0x8b, 0x00, 0x6f, 0x00, 0x52, 0x00, 0x37, 0x00, 0x20, 0x00,
+ 0x17, 0x04, 0x10, 0x07, 0x0a, 0x0a, 0x05, 0x0d, 0x00, 0x0f, 0x00, 0x14,
+ 0x00, 0x19, 0x00, 0x1d, 0xbc, 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x96, 0x00,
+ 0x7f, 0x00, 0x68, 0x00, 0x53, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x20, 0x00,
+ 0x14, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11,
+ 0x3a, 0x2f, 0x32, 0x2b, 0x2e, 0x28, 0x2b, 0x27, 0x28, 0x25, 0x27, 0x25,
+ 0x27, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23,
+ 0x24, 0x23, 0x23, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0xcd, 0x00, 0xb0, 0x00, 0x9a, 0x00, 0x87, 0x00,
+ 0x78, 0x01, 0x6c, 0x03, 0x64, 0x04, 0x5c, 0x05, 0x57, 0x07, 0x51, 0x09,
+ 0x4e, 0x0a, 0x4a, 0x0b, 0x48, 0x0c, 0x45, 0x0c, 0x43, 0x0e, 0x40, 0x0f,
+ 0x3f, 0x0f, 0x3d, 0x0f, 0x3c, 0x11, 0x3b, 0x12, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x77, 0x11, 0x69, 0x11, 0x5e, 0x11, 0x54, 0x11, 0x4d, 0x11, 0x47, 0x12,
+ 0x43, 0x13, 0x3f, 0x13, 0x3c, 0x14, 0x39, 0x15, 0x38, 0x16, 0x36, 0x16,
+ 0x35, 0x17, 0x33, 0x17, 0x32, 0x18, 0x31, 0x18, 0x30, 0x18, 0x2f, 0x18,
+ 0x2f, 0x19, 0x2e, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+ 0x00, 0x0d, 0x00, 0x13, 0x00, 0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23,
+ 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x25, 0x00, 0x1b,
+ 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13,
+ 0x00, 0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xaa, 0x00, 0x96, 0x00,
+ 0x7e, 0x00, 0x64, 0x00, 0x4c, 0x00, 0x34, 0x00, 0x20, 0x00, 0x18, 0x03,
+ 0x11, 0x06, 0x0c, 0x09, 0x07, 0x0c, 0x03, 0x0e, 0x00, 0x10, 0x00, 0x15,
+ 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x8b, 0x00, 0x77, 0x00,
+ 0x63, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x30, 0x00, 0x23, 0x00, 0x18, 0x00,
+ 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3b, 0x32, 0x34, 0x2d,
+ 0x2f, 0x2a, 0x2c, 0x28, 0x2a, 0x27, 0x29, 0x26, 0x27, 0x25, 0x27, 0x25,
+ 0x26, 0x24, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x23, 0x24, 0x23,
+ 0x24, 0x23, 0x24, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x22,
+ 0xcf, 0x00, 0xb9, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x85, 0x00, 0x7a, 0x01,
+ 0x70, 0x02, 0x68, 0x03, 0x61, 0x04, 0x5c, 0x05, 0x57, 0x07, 0x53, 0x07,
+ 0x50, 0x09, 0x4c, 0x0a, 0x4a, 0x0a, 0x48, 0x0c, 0x45, 0x0c, 0x44, 0x0c,
+ 0x42, 0x0d, 0x41, 0x0f, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x78, 0x11, 0x6d, 0x11,
+ 0x63, 0x11, 0x5b, 0x11, 0x53, 0x11, 0x4e, 0x11, 0x49, 0x12, 0x45, 0x12,
+ 0x41, 0x13, 0x3f, 0x13, 0x3c, 0x14, 0x3a, 0x14, 0x39, 0x15, 0x37, 0x16,
+ 0x36, 0x16, 0x35, 0x17, 0x33, 0x17, 0x33, 0x17, 0x32, 0x17, 0x31, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c,
+ 0x00, 0x11, 0x00, 0x16, 0x00, 0x1a, 0x00, 0x1d, 0x00, 0x3e, 0x00, 0x3d,
+ 0x00, 0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f,
+ 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x16,
+ 0x00, 0x1a, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9d, 0x00, 0x89, 0x00, 0x73, 0x00,
+ 0x5c, 0x00, 0x46, 0x00, 0x32, 0x00, 0x20, 0x00, 0x19, 0x03, 0x13, 0x06,
+ 0x0e, 0x08, 0x09, 0x0b, 0x05, 0x0d, 0x01, 0x0e, 0xbd, 0x00, 0xba, 0x00,
+ 0xb1, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x82, 0x00, 0x70, 0x00, 0x5e, 0x00,
+ 0x4e, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x26, 0x00, 0x1c, 0x00, 0x13, 0x00,
+ 0x0b, 0x00, 0x03, 0x00, 0x3c, 0x34, 0x35, 0x2f, 0x31, 0x2c, 0x2e, 0x2a,
+ 0x2c, 0x28, 0x2a, 0x27, 0x28, 0x27, 0x28, 0x26, 0x27, 0x25, 0x27, 0x25,
+ 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x24, 0x24, 0x23,
+ 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x23, 0x23, 0xd2, 0x00, 0xbe, 0x00,
+ 0xad, 0x00, 0x9d, 0x00, 0x90, 0x00, 0x84, 0x00, 0x7a, 0x00, 0x72, 0x01,
+ 0x6b, 0x02, 0x65, 0x04, 0x60, 0x04, 0x5b, 0x05, 0x58, 0x06, 0x54, 0x07,
+ 0x51, 0x07, 0x4f, 0x09, 0x4c, 0x0a, 0x4a, 0x0a, 0x48, 0x0b, 0x46, 0x0c,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x7a, 0x11, 0x70, 0x11, 0x67, 0x11, 0x5f, 0x11,
+ 0x59, 0x11, 0x53, 0x11, 0x4e, 0x11, 0x4a, 0x11, 0x46, 0x12, 0x43, 0x13,
+ 0x41, 0x13, 0x3e, 0x13, 0x3d, 0x14, 0x3b, 0x14, 0x39, 0x14, 0x38, 0x15,
+ 0x37, 0x16, 0x36, 0x16, 0x35, 0x16, 0x34, 0x17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10,
+ 0x00, 0x14, 0x00, 0x18, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x34,
+ 0x00, 0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x06,
+ 0x00, 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00,
+ 0xb1, 0x00, 0xa3, 0x00, 0x92, 0x00, 0x7e, 0x00, 0x6a, 0x00, 0x56, 0x00,
+ 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x19, 0x03, 0x14, 0x05, 0x0f, 0x08,
+ 0x0b, 0x0a, 0x07, 0x0c, 0xbd, 0x00, 0xbb, 0x00, 0xb4, 0x00, 0xa9, 0x00,
+ 0x9b, 0x00, 0x8b, 0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4d, 0x00,
+ 0x3f, 0x00, 0x33, 0x00, 0x28, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0e, 0x00,
+ 0x3c, 0x35, 0x36, 0x31, 0x32, 0x2e, 0x2f, 0x2b, 0x2d, 0x2a, 0x2b, 0x28,
+ 0x2a, 0x28, 0x28, 0x27, 0x28, 0x27, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25,
+ 0x25, 0x25, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x24, 0x24, 0x24,
+ 0x24, 0x23, 0x24, 0x23, 0xd3, 0x00, 0xc2, 0x00, 0xb2, 0x00, 0xa4, 0x00,
+ 0x98, 0x00, 0x8d, 0x00, 0x83, 0x00, 0x7b, 0x00, 0x73, 0x01, 0x6e, 0x02,
+ 0x67, 0x02, 0x63, 0x04, 0x5f, 0x04, 0x5b, 0x05, 0x58, 0x05, 0x55, 0x07,
+ 0x52, 0x07, 0x50, 0x07, 0x4e, 0x09, 0x4c, 0x0a, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x7a, 0x11, 0x72, 0x11, 0x6a, 0x11, 0x63, 0x11, 0x5d, 0x11, 0x57, 0x11,
+ 0x52, 0x11, 0x4e, 0x11, 0x4a, 0x11, 0x48, 0x12, 0x44, 0x12, 0x42, 0x13,
+ 0x40, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b, 0x14, 0x3a, 0x14, 0x39, 0x14,
+ 0x38, 0x15, 0x37, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13,
+ 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29,
+ 0x00, 0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa8, 0x00,
+ 0x99, 0x00, 0x87, 0x00, 0x75, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f, 0x00,
+ 0x2e, 0x00, 0x1f, 0x00, 0x1a, 0x02, 0x15, 0x05, 0x10, 0x07, 0x0c, 0x09,
+ 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xac, 0x00, 0xa0, 0x00, 0x93, 0x00,
+ 0x84, 0x00, 0x75, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4b, 0x00, 0x3f, 0x00,
+ 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x19, 0x00, 0x3c, 0x36, 0x37, 0x32,
+ 0x33, 0x2f, 0x30, 0x2d, 0x2e, 0x2b, 0x2d, 0x2a, 0x2b, 0x28, 0x2a, 0x28,
+ 0x28, 0x27, 0x28, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25,
+ 0x25, 0x25, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x24, 0x24, 0x24,
+ 0xd5, 0x00, 0xc5, 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x9f, 0x00, 0x95, 0x00,
+ 0x8b, 0x00, 0x83, 0x00, 0x7c, 0x00, 0x75, 0x01, 0x6f, 0x01, 0x69, 0x02,
+ 0x66, 0x02, 0x61, 0x04, 0x5e, 0x04, 0x5a, 0x05, 0x58, 0x05, 0x55, 0x06,
+ 0x53, 0x07, 0x51, 0x07, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7b, 0x11, 0x73, 0x11,
+ 0x6c, 0x11, 0x66, 0x11, 0x60, 0x11, 0x5b, 0x11, 0x56, 0x11, 0x52, 0x11,
+ 0x4f, 0x11, 0x4b, 0x11, 0x48, 0x11, 0x45, 0x12, 0x44, 0x12, 0x41, 0x13,
+ 0x40, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b, 0x14, 0x3a, 0x14, 0x39, 0x14,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x3f, 0x00, 0x3e,
+ 0x00, 0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x26, 0x00, 0x1f,
+ 0x00, 0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x09, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xab, 0x00, 0x9e, 0x00, 0x8f, 0x00,
+ 0x7e, 0x00, 0x6d, 0x00, 0x5c, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2d, 0x00,
+ 0x1f, 0x00, 0x1a, 0x02, 0x16, 0x04, 0x11, 0x06, 0xbe, 0x00, 0xbc, 0x00,
+ 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00, 0x8b, 0x00, 0x7e, 0x00,
+ 0x70, 0x00, 0x63, 0x00, 0x56, 0x00, 0x4a, 0x00, 0x3f, 0x00, 0x35, 0x00,
+ 0x2c, 0x00, 0x23, 0x00, 0x3c, 0x37, 0x38, 0x33, 0x34, 0x30, 0x31, 0x2e,
+ 0x2f, 0x2c, 0x2d, 0x2a, 0x2c, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x27,
+ 0x28, 0x27, 0x27, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x25, 0x25,
+ 0x25, 0x25, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0xd5, 0x00, 0xc8, 0x00,
+ 0xbb, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x92, 0x00, 0x8a, 0x00,
+ 0x82, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x70, 0x01, 0x6c, 0x02, 0x67, 0x02,
+ 0x64, 0x03, 0x60, 0x04, 0x5d, 0x04, 0x5b, 0x05, 0x58, 0x05, 0x55, 0x05,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x7b, 0x11, 0x75, 0x11, 0x6e, 0x11, 0x68, 0x11,
+ 0x63, 0x11, 0x5e, 0x11, 0x5a, 0x11, 0x56, 0x11, 0x52, 0x11, 0x4f, 0x11,
+ 0x4c, 0x11, 0x49, 0x11, 0x47, 0x12, 0x44, 0x12, 0x43, 0x12, 0x41, 0x13,
+ 0x3f, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b, 0x13, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x00, 0x09, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38,
+ 0x00, 0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1c, 0x00, 0x16,
+ 0x00, 0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00,
+ 0xb7, 0x00, 0xae, 0x00, 0xa2, 0x00, 0x95, 0x00, 0x86, 0x00, 0x77, 0x00,
+ 0x67, 0x00, 0x57, 0x00, 0x48, 0x00, 0x3a, 0x00, 0x2c, 0x00, 0x1f, 0x00,
+ 0x1b, 0x02, 0x16, 0x04, 0xbe, 0x00, 0xbd, 0x00, 0xb8, 0x00, 0xb1, 0x00,
+ 0xa8, 0x00, 0x9d, 0x00, 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6c, 0x00,
+ 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2d, 0x00,
+ 0x3d, 0x38, 0x38, 0x34, 0x35, 0x31, 0x33, 0x2f, 0x30, 0x2d, 0x2e, 0x2c,
+ 0x2d, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x27, 0x28, 0x27,
+ 0x28, 0x27, 0x27, 0x27, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25,
+ 0x25, 0x25, 0x25, 0x24, 0xd6, 0x00, 0xca, 0x00, 0xbe, 0x00, 0xb3, 0x00,
+ 0xaa, 0x00, 0xa0, 0x00, 0x98, 0x00, 0x90, 0x00, 0x88, 0x00, 0x82, 0x00,
+ 0x7d, 0x00, 0x77, 0x00, 0x71, 0x01, 0x6d, 0x01, 0x69, 0x02, 0x66, 0x02,
+ 0x63, 0x04, 0x60, 0x04, 0x5d, 0x04, 0x5b, 0x05, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x7c, 0x11, 0x76, 0x11, 0x70, 0x11, 0x6a, 0x11, 0x66, 0x11, 0x61, 0x11,
+ 0x5d, 0x11, 0x59, 0x11, 0x55, 0x11, 0x52, 0x11, 0x4f, 0x11, 0x4c, 0x11,
+ 0x49, 0x11, 0x47, 0x11, 0x45, 0x12, 0x44, 0x12, 0x42, 0x13, 0x41, 0x13,
+ 0x3f, 0x13, 0x3e, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39, 0x00, 0x35, 0x00, 0x31,
+ 0x00, 0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0f,
+ 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xb0, 0x00,
+ 0xa6, 0x00, 0x9a, 0x00, 0x8d, 0x00, 0x7f, 0x00, 0x70, 0x00, 0x61, 0x00,
+ 0x53, 0x00, 0x45, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x1b, 0x02,
+ 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb3, 0x00, 0xab, 0x00, 0xa1, 0x00,
+ 0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x74, 0x00, 0x68, 0x00, 0x5d, 0x00,
+ 0x53, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x3d, 0x38, 0x39, 0x35,
+ 0x36, 0x32, 0x33, 0x30, 0x31, 0x2e, 0x30, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b,
+ 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x26, 0x28, 0x27,
+ 0x27, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25,
+ 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb7, 0x00, 0xad, 0x00, 0xa5, 0x00,
+ 0x9d, 0x00, 0x96, 0x00, 0x8f, 0x00, 0x88, 0x00, 0x81, 0x00, 0x7d, 0x00,
+ 0x77, 0x00, 0x73, 0x01, 0x6f, 0x01, 0x6b, 0x02, 0x67, 0x02, 0x64, 0x02,
+ 0x62, 0x04, 0x5f, 0x04, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7c, 0x11, 0x77, 0x11,
+ 0x71, 0x11, 0x6c, 0x11, 0x67, 0x11, 0x63, 0x11, 0x5f, 0x11, 0x5c, 0x11,
+ 0x58, 0x11, 0x55, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4c, 0x11, 0x4a, 0x11,
+ 0x48, 0x11, 0x46, 0x12, 0x44, 0x12, 0x43, 0x12, 0x42, 0x13, 0x40, 0x13,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e,
+ 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x28,
+ 0x00, 0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x09,
+ 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xa9, 0x00, 0x9e, 0x00,
+ 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x5c, 0x00, 0x4f, 0x00,
+ 0x42, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0xbe, 0x00, 0xbd, 0x00,
+ 0xba, 0x00, 0xb4, 0x00, 0xad, 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x91, 0x00,
+ 0x86, 0x00, 0x7b, 0x00, 0x70, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00,
+ 0x48, 0x00, 0x3f, 0x00, 0x3d, 0x39, 0x39, 0x36, 0x36, 0x33, 0x33, 0x30,
+ 0x32, 0x2f, 0x30, 0x2d, 0x2e, 0x2d, 0x2d, 0x2a, 0x2c, 0x2b, 0x2b, 0x29,
+ 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x26, 0x28, 0x27, 0x27, 0x27,
+ 0x27, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0xd7, 0x00, 0xcc, 0x00,
+ 0xc3, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0xa0, 0x00, 0x99, 0x00,
+ 0x93, 0x00, 0x8d, 0x00, 0x87, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00,
+ 0x74, 0x00, 0x70, 0x01, 0x6c, 0x01, 0x69, 0x02, 0x66, 0x02, 0x63, 0x02,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x7c, 0x11, 0x77, 0x11, 0x72, 0x11, 0x6e, 0x11,
+ 0x69, 0x11, 0x65, 0x11, 0x61, 0x11, 0x5d, 0x11, 0x5a, 0x11, 0x57, 0x11,
+ 0x54, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x49, 0x11,
+ 0x47, 0x11, 0x45, 0x12, 0x44, 0x12, 0x42, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x39, 0x39, 0x36, 0x36, 0x33, 0x34, 0x32, 0x33, 0x30, 0x30, 0x2e,
+ 0x30, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28,
+ 0x29, 0x28, 0x28, 0x28, 0x28, 0x27, 0x29, 0x27, 0x27, 0x27, 0x27, 0x27,
+ 0x27, 0x27, 0x27, 0x25, 0xd7, 0x00, 0xce, 0x00, 0xc5, 0x00, 0xbc, 0x00,
+ 0xb4, 0x00, 0xac, 0x00, 0xa5, 0x00, 0x9e, 0x00, 0x97, 0x00, 0x91, 0x00,
+ 0x8c, 0x00, 0x87, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x75, 0x00,
+ 0x71, 0x01, 0x6d, 0x01, 0x6b, 0x02, 0x68, 0x02, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x7c, 0x11, 0x78, 0x11, 0x73, 0x11, 0x6f, 0x11, 0x6b, 0x11, 0x67, 0x11,
+ 0x63, 0x11, 0x60, 0x11, 0x5c, 0x11, 0x59, 0x11, 0x57, 0x11, 0x54, 0x11,
+ 0x51, 0x11, 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x49, 0x11, 0x47, 0x11,
+ 0x46, 0x12, 0x45, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x39, 0x3a, 0x36,
+ 0x37, 0x34, 0x35, 0x33, 0x33, 0x30, 0x31, 0x30, 0x30, 0x2d, 0x2e, 0x2d,
+ 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28,
+ 0x28, 0x28, 0x28, 0x27, 0x28, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, 0x27,
+ 0xd8, 0x00, 0xcf, 0x00, 0xc6, 0x00, 0xbe, 0x00, 0xb6, 0x00, 0xaf, 0x00,
+ 0xa8, 0x00, 0xa1, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x90, 0x00, 0x8a, 0x00,
+ 0x86, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x75, 0x00, 0x72, 0x01,
+ 0x6f, 0x01, 0x6b, 0x01, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x78, 0x11,
+ 0x74, 0x11, 0x70, 0x11, 0x6c, 0x11, 0x68, 0x11, 0x65, 0x11, 0x61, 0x11,
+ 0x5f, 0x11, 0x5c, 0x11, 0x59, 0x11, 0x56, 0x11, 0x54, 0x11, 0x51, 0x11,
+ 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x4a, 0x11, 0x48, 0x11, 0x46, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3a, 0x3a, 0x37, 0x38, 0x35, 0x36, 0x33,
+ 0x33, 0x31, 0x32, 0x30, 0x30, 0x2e, 0x30, 0x2d, 0x2d, 0x2d, 0x2d, 0x2b,
+ 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28,
+ 0x28, 0x27, 0x28, 0x26, 0x28, 0x27, 0x27, 0x27, 0xd8, 0x00, 0xd0, 0x00,
+ 0xc8, 0x00, 0xc0, 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xab, 0x00, 0xa5, 0x00,
+ 0x9f, 0x00, 0x99, 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8a, 0x00, 0x86, 0x00,
+ 0x81, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x76, 0x00, 0x73, 0x00, 0x70, 0x01,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x79, 0x11, 0x75, 0x11, 0x71, 0x11,
+ 0x6d, 0x11, 0x6a, 0x11, 0x66, 0x11, 0x63, 0x11, 0x60, 0x11, 0x5d, 0x11,
+ 0x5b, 0x11, 0x58, 0x11, 0x56, 0x11, 0x54, 0x11, 0x51, 0x11, 0x4f, 0x11,
+ 0x4d, 0x11, 0x4c, 0x11, 0x4a, 0x11, 0x49, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x3a, 0x3a, 0x37, 0x38, 0x36, 0x36, 0x33, 0x33, 0x32, 0x33, 0x30,
+ 0x30, 0x30, 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2c, 0x2b,
+ 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x27, 0x29, 0x27, 0xd9, 0x00, 0xd1, 0x00, 0xc9, 0x00, 0xc2, 0x00,
+ 0xbb, 0x00, 0xb4, 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa2, 0x00, 0x9c, 0x00,
+ 0x97, 0x00, 0x92, 0x00, 0x8e, 0x00, 0x89, 0x00, 0x85, 0x00, 0x81, 0x00,
+ 0x7d, 0x00, 0x7a, 0x00, 0x76, 0x00, 0x73, 0x00, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x7d, 0x11, 0x79, 0x11, 0x75, 0x11, 0x72, 0x11, 0x6e, 0x11, 0x6b, 0x11,
+ 0x68, 0x11, 0x65, 0x11, 0x62, 0x11, 0x5f, 0x11, 0x5c, 0x11, 0x5a, 0x11,
+ 0x58, 0x11, 0x55, 0x11, 0x53, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4e, 0x11,
+ 0x4c, 0x11, 0x4a, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3a, 0x3b, 0x38,
+ 0x39, 0x36, 0x36, 0x33, 0x34, 0x33, 0x33, 0x30, 0x32, 0x30, 0x30, 0x2e,
+ 0x30, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+ 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27,
+ 0xd9, 0x00, 0xd1, 0x00, 0xca, 0x00, 0xc3, 0x00, 0xbc, 0x00, 0xb6, 0x00,
+ 0xb0, 0x00, 0xaa, 0x00, 0xa5, 0x00, 0xa0, 0x00, 0x9a, 0x00, 0x96, 0x00,
+ 0x91, 0x00, 0x8d, 0x00, 0x89, 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00,
+ 0x7a, 0x00, 0x77, 0x00, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x79, 0x11,
+ 0x76, 0x11, 0x72, 0x11, 0x6f, 0x11, 0x6c, 0x11, 0x69, 0x11, 0x66, 0x11,
+ 0x63, 0x11, 0x61, 0x11, 0x5e, 0x11, 0x5c, 0x11, 0x59, 0x11, 0x57, 0x11,
+ 0x55, 0x11, 0x53, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4e, 0x11, 0x4c, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3a, 0x3b, 0x39, 0x39, 0x36, 0x36, 0x34,
+ 0x35, 0x33, 0x33, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x2f, 0x2d,
+ 0x2d, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x29,
+ 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0xd9, 0x00, 0xd2, 0x00,
+ 0xcb, 0x00, 0xc4, 0x00, 0xbe, 0x00, 0xb8, 0x00, 0xb2, 0x00, 0xad, 0x00,
+ 0xa8, 0x00, 0xa2, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x94, 0x00, 0x90, 0x00,
+ 0x8b, 0x00, 0x88, 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7b, 0x00,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x7a, 0x11, 0x76, 0x11, 0x73, 0x11,
+ 0x70, 0x11, 0x6d, 0x11, 0x6a, 0x11, 0x67, 0x11, 0x65, 0x11, 0x62, 0x11,
+ 0x5f, 0x11, 0x5d, 0x11, 0x5b, 0x11, 0x59, 0x11, 0x56, 0x11, 0x55, 0x11,
+ 0x53, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4e, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x3b, 0x3b, 0x39, 0x3a, 0x36, 0x36, 0x35, 0x36, 0x33, 0x33, 0x32,
+ 0x33, 0x30, 0x31, 0x30, 0x30, 0x2f, 0x30, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+ 0x2d, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x2b, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0xd9, 0x00, 0xd3, 0x00, 0xcc, 0x00, 0xc6, 0x00,
+ 0xc0, 0x00, 0xba, 0x00, 0xb4, 0x00, 0xaf, 0x00, 0xaa, 0x00, 0xa5, 0x00,
+ 0xa0, 0x00, 0x9b, 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f, 0x00, 0x8b, 0x00,
+ 0x88, 0x00, 0x83, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x7d, 0x11, 0x7a, 0x11, 0x77, 0x11, 0x74, 0x11, 0x71, 0x11, 0x6e, 0x11,
+ 0x6b, 0x11, 0x68, 0x11, 0x66, 0x11, 0x63, 0x11, 0x61, 0x11, 0x5e, 0x11,
+ 0x5c, 0x11, 0x5a, 0x11, 0x58, 0x11, 0x56, 0x11, 0x55, 0x11, 0x52, 0x11,
+ 0x51, 0x11, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3b, 0x3b, 0x39,
+ 0x39, 0x36, 0x37, 0x36, 0x36, 0x33, 0x34, 0x33, 0x33, 0x31, 0x32, 0x30,
+ 0x30, 0x30, 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b,
+ 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28,
+ 0xd9, 0x00, 0xd3, 0x00, 0xcd, 0x00, 0xc7, 0x00, 0xc1, 0x00, 0xbc, 0x00,
+ 0xb7, 0x00, 0xb0, 0x00, 0xac, 0x00, 0xa7, 0x00, 0xa2, 0x00, 0x9e, 0x00,
+ 0x9a, 0x00, 0x95, 0x00, 0x93, 0x00, 0x8e, 0x00, 0x8b, 0x00, 0x87, 0x00,
+ 0x83, 0x00, 0x81, 0x00, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x7a, 0x11,
+ 0x77, 0x11, 0x74, 0x11, 0x71, 0x11, 0x6f, 0x11, 0x6c, 0x11, 0x69, 0x11,
+ 0x67, 0x11, 0x64, 0x11, 0x62, 0x11, 0x60, 0x11, 0x5e, 0x11, 0x5b, 0x11,
+ 0x5a, 0x11, 0x58, 0x11, 0x56, 0x11, 0x54, 0x11, 0x52, 0x11, 0x51, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0xb8, 0x00, 0xc5, 0x00, 0xcb, 0x00,
+ 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00,
+ 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd9, 0x00,
+ 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0x44, 0x00, 0x9d, 0x00, 0xbc, 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xcf, 0x00,
+ 0xd2, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00,
+ 0xd7, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00,
+ 0xd9, 0x00, 0xd9, 0x00, 0x90, 0x00, 0xbd, 0x00, 0xcc, 0x00, 0xd1, 0x00,
+ 0xd5, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00,
+ 0xd9, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00,
+ 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x68, 0x01, 0x8b, 0x00, 0xa0, 0x00, 0xad, 0x00, 0xb6, 0x00, 0xbc, 0x00,
+ 0xc1, 0x00, 0xc4, 0x00, 0xc7, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc, 0x00,
+ 0xcd, 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd2, 0x00,
+ 0xd2, 0x00, 0xd3, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x25, 0x05, 0x6b, 0x00,
+ 0x8e, 0x00, 0xa4, 0x00, 0xb0, 0x00, 0xb9, 0x00, 0xbe, 0x00, 0xc2, 0x00,
+ 0xc5, 0x00, 0xc8, 0x00, 0xca, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xce, 0x00,
+ 0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00,
+ 0x81, 0x02, 0xa4, 0x00, 0xb5, 0x00, 0xc0, 0x00, 0xc6, 0x00, 0xcb, 0x00,
+ 0xcd, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00,
+ 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd7, 0x00,
+ 0xd7, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x09, 0x72, 0x02,
+ 0x87, 0x00, 0x96, 0x00, 0xa0, 0x00, 0xa9, 0x00, 0xb0, 0x00, 0xb5, 0x00,
+ 0xb9, 0x00, 0xbd, 0x00, 0xbf, 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xc6, 0x00,
+ 0xc7, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0x23, 0x0d, 0x51, 0x01, 0x73, 0x00, 0x89, 0x00,
+ 0x9a, 0x00, 0xa4, 0x00, 0xad, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbb, 0x00,
+ 0xbe, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc8, 0x00,
+ 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0x80, 0x06, 0x97, 0x00,
+ 0xa8, 0x00, 0xb3, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc5, 0x00, 0xc7, 0x00,
+ 0xca, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xd0, 0x00, 0xd1, 0x00,
+ 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd4, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4f, 0x11, 0x65, 0x07, 0x76, 0x03, 0x84, 0x01,
+ 0x8f, 0x00, 0x99, 0x00, 0xa1, 0x00, 0xa7, 0x00, 0xad, 0x00, 0xb1, 0x00,
+ 0xb4, 0x00, 0xb8, 0x00, 0xbb, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc0, 0x00,
+ 0xc2, 0x00, 0xc4, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0x22, 0x12, 0x45, 0x04, 0x60, 0x00, 0x77, 0x00, 0x87, 0x00, 0x94, 0x00,
+ 0x9d, 0x00, 0xa4, 0x00, 0xaa, 0x00, 0xaf, 0x00, 0xb3, 0x00, 0xb7, 0x00,
+ 0xba, 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc2, 0x00, 0xc3, 0x00,
+ 0xc4, 0x00, 0xc6, 0x00, 0x7f, 0x09, 0x91, 0x02, 0x9e, 0x00, 0xaa, 0x00,
+ 0xb2, 0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc6, 0x00,
+ 0xc8, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00,
+ 0xcf, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4b, 0x17, 0x5d, 0x0c, 0x6c, 0x06, 0x78, 0x03, 0x83, 0x01, 0x8c, 0x00,
+ 0x94, 0x00, 0x9b, 0x00, 0xa1, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xae, 0x00,
+ 0xb1, 0x00, 0xb4, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbd, 0x00,
+ 0xbe, 0x00, 0xbf, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x22, 0x15, 0x3d, 0x08,
+ 0x55, 0x02, 0x67, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00, 0x98, 0x00,
+ 0x9f, 0x00, 0xa5, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xb1, 0x00, 0xb4, 0x00,
+ 0xb6, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc0, 0x00,
+ 0x7f, 0x0a, 0x8d, 0x04, 0x99, 0x01, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00,
+ 0xb6, 0x00, 0xba, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc3, 0x00, 0xc5, 0x00,
+ 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcc, 0x00,
+ 0xcd, 0x00, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x1c, 0x57, 0x11,
+ 0x64, 0x0a, 0x70, 0x06, 0x79, 0x03, 0x82, 0x02, 0x8a, 0x00, 0x91, 0x00,
+ 0x97, 0x00, 0x9c, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa9, 0x00, 0xad, 0x00,
+ 0xaf, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb9, 0x00, 0xba, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x17, 0x38, 0x0b, 0x4c, 0x04, 0x5e, 0x01,
+ 0x6c, 0x00, 0x7a, 0x00, 0x84, 0x00, 0x8d, 0x00, 0x95, 0x00, 0x9b, 0x00,
+ 0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb2, 0x00,
+ 0xb4, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0x7f, 0x0b, 0x8a, 0x05,
+ 0x94, 0x02, 0x9d, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb5, 0x00,
+ 0xb9, 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00,
+ 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x47, 0x20, 0x54, 0x15, 0x5f, 0x0e, 0x69, 0x09,
+ 0x72, 0x05, 0x7a, 0x03, 0x82, 0x02, 0x88, 0x01, 0x8f, 0x00, 0x94, 0x00,
+ 0x99, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa4, 0x00, 0xa8, 0x00, 0xac, 0x00,
+ 0xae, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0x22, 0x18, 0x35, 0x0d, 0x47, 0x06, 0x55, 0x03, 0x64, 0x01, 0x70, 0x00,
+ 0x7a, 0x00, 0x83, 0x00, 0x8b, 0x00, 0x92, 0x00, 0x98, 0x00, 0x9d, 0x00,
+ 0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00,
+ 0xb2, 0x00, 0xb4, 0x00, 0x7f, 0x0c, 0x89, 0x06, 0x92, 0x03, 0x99, 0x01,
+ 0xa0, 0x00, 0xa6, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb4, 0x00, 0xb7, 0x00,
+ 0xba, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00,
+ 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x46, 0x23, 0x50, 0x18, 0x5b, 0x11, 0x64, 0x0b, 0x6c, 0x08, 0x74, 0x05,
+ 0x7b, 0x03, 0x82, 0x02, 0x87, 0x01, 0x8c, 0x00, 0x91, 0x00, 0x95, 0x00,
+ 0x9a, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa4, 0x00, 0xa7, 0x00, 0xab, 0x00,
+ 0xac, 0x00, 0xaf, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1a, 0x32, 0x0f,
+ 0x42, 0x08, 0x50, 0x04, 0x5c, 0x02, 0x68, 0x00, 0x72, 0x00, 0x7b, 0x00,
+ 0x83, 0x00, 0x8a, 0x00, 0x90, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9e, 0x00,
+ 0xa1, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00,
+ 0x7f, 0x0d, 0x88, 0x07, 0x8f, 0x04, 0x96, 0x02, 0x9c, 0x01, 0xa2, 0x00,
+ 0xa7, 0x00, 0xac, 0x00, 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb9, 0x00,
+ 0xbb, 0x00, 0xbd, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00,
+ 0xc5, 0x00, 0xc6, 0x00, 0x2f, 0x00, 0x5f, 0x00, 0x99, 0x00, 0xac, 0x00,
+ 0xb3, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00,
+ 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00,
+ 0x3b, 0x0b, 0x6f, 0x00, 0x9f, 0x00, 0xaf, 0x00, 0xb5, 0x00, 0xb9, 0x00,
+ 0xba, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00,
+ 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x6d, 0x00, 0x8d, 0x00, 0x9b, 0x00,
+ 0xa6, 0x00, 0xb2, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00,
+ 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00,
+ 0x47, 0x07, 0x7f, 0x00, 0xa5, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xba, 0x00,
+ 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00,
+ 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x45, 0x25, 0x4e, 0x1b,
+ 0x57, 0x13, 0x60, 0x0e, 0x68, 0x0a, 0x6f, 0x07, 0x76, 0x05, 0x7b, 0x03,
+ 0x82, 0x02, 0x86, 0x02, 0x8b, 0x01, 0x90, 0x00, 0x93, 0x00, 0x97, 0x00,
+ 0x9b, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa6, 0x00, 0xaa, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0x22, 0x1b, 0x30, 0x11, 0x3e, 0x0a, 0x4b, 0x05,
+ 0x57, 0x03, 0x61, 0x01, 0x6b, 0x00, 0x73, 0x00, 0x7c, 0x00, 0x82, 0x00,
+ 0x88, 0x00, 0x8f, 0x00, 0x93, 0x00, 0x97, 0x00, 0x9c, 0x00, 0x9f, 0x00,
+ 0xa2, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0x7f, 0x0d, 0x86, 0x08,
+ 0x8d, 0x05, 0x94, 0x02, 0x9a, 0x01, 0x9f, 0x00, 0xa4, 0x00, 0xa8, 0x00,
+ 0xac, 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00,
+ 0xbc, 0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00,
+ 0x00, 0x00, 0x0f, 0x00, 0x5f, 0x00, 0x8b, 0x00, 0x9f, 0x00, 0xaa, 0x00,
+ 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00,
+ 0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x07, 0x17, 0x27, 0x02,
+ 0x6f, 0x00, 0x93, 0x00, 0xa4, 0x00, 0xad, 0x00, 0xb2, 0x00, 0xb5, 0x00,
+ 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00,
+ 0xbc, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6d, 0x00, 0x54, 0x00, 0x6b, 0x00, 0x87, 0x00, 0x98, 0x00, 0xa6, 0x00,
+ 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00,
+ 0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x0f, 0x0f, 0x3f, 0x00,
+ 0x7f, 0x00, 0x9c, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb5, 0x00, 0xb7, 0x00,
+ 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00,
+ 0xbd, 0x00, 0xbd, 0x00, 0x45, 0x28, 0x4d, 0x1d, 0x55, 0x16, 0x5d, 0x11,
+ 0x64, 0x0c, 0x6b, 0x09, 0x71, 0x07, 0x77, 0x05, 0x7b, 0x03, 0x81, 0x02,
+ 0x85, 0x02, 0x8a, 0x01, 0x8e, 0x00, 0x92, 0x00, 0x95, 0x00, 0x98, 0x00,
+ 0x9d, 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0x21, 0x1b, 0x2f, 0x12, 0x3b, 0x0c, 0x47, 0x07, 0x51, 0x04, 0x5c, 0x02,
+ 0x65, 0x01, 0x6e, 0x00, 0x75, 0x00, 0x7c, 0x00, 0x82, 0x00, 0x88, 0x00,
+ 0x8d, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9c, 0x00, 0xa0, 0x00,
+ 0xa2, 0x00, 0xa5, 0x00, 0x7f, 0x0d, 0x86, 0x09, 0x8c, 0x06, 0x92, 0x03,
+ 0x97, 0x02, 0x9c, 0x01, 0xa1, 0x00, 0xa5, 0x00, 0xa9, 0x00, 0xac, 0x00,
+ 0xaf, 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00,
+ 0xbc, 0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x44, 0x00, 0x6d, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f, 0x00,
+ 0xa6, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00,
+ 0xb6, 0x00, 0xb7, 0x00, 0x00, 0x2c, 0x02, 0x12, 0x22, 0x00, 0x58, 0x00,
+ 0x7a, 0x00, 0x8f, 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xaa, 0x00, 0xae, 0x00,
+ 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x6b, 0x00,
+ 0x28, 0x00, 0x52, 0x00, 0x70, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f, 0x00,
+ 0xa6, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00,
+ 0xb6, 0x00, 0xb7, 0x00, 0x00, 0x26, 0x05, 0x05, 0x3f, 0x00, 0x6d, 0x00,
+ 0x88, 0x00, 0x99, 0x00, 0xa3, 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1, 0x00,
+ 0xb4, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00,
+ 0x44, 0x2a, 0x4b, 0x20, 0x53, 0x18, 0x5a, 0x13, 0x61, 0x0f, 0x67, 0x0b,
+ 0x6d, 0x09, 0x73, 0x07, 0x77, 0x05, 0x7c, 0x03, 0x81, 0x02, 0x85, 0x02,
+ 0x88, 0x01, 0x8d, 0x01, 0x90, 0x00, 0x93, 0x00, 0x96, 0x00, 0x9a, 0x00,
+ 0x9d, 0x00, 0x9f, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x22, 0x1c, 0x2d, 0x13,
+ 0x39, 0x0d, 0x44, 0x09, 0x4e, 0x05, 0x57, 0x04, 0x60, 0x02, 0x67, 0x01,
+ 0x6f, 0x00, 0x76, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x87, 0x00, 0x8c, 0x00,
+ 0x90, 0x00, 0x94, 0x00, 0x97, 0x00, 0x9a, 0x00, 0x9d, 0x00, 0xa0, 0x00,
+ 0x7f, 0x0e, 0x85, 0x09, 0x8b, 0x06, 0x90, 0x04, 0x95, 0x02, 0x9a, 0x02,
+ 0x9e, 0x01, 0xa2, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xad, 0x00, 0xaf, 0x00,
+ 0xb2, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00,
+ 0xbd, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x33, 0x00, 0x57, 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97, 0x00,
+ 0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00,
+ 0x00, 0x36, 0x00, 0x25, 0x09, 0x0b, 0x21, 0x00, 0x4a, 0x00, 0x68, 0x00,
+ 0x7d, 0x00, 0x8b, 0x00, 0x96, 0x00, 0x9d, 0x00, 0xa3, 0x00, 0xa8, 0x00,
+ 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x87, 0x00, 0x52, 0x00, 0x11, 0x00,
+ 0x39, 0x00, 0x57, 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97, 0x00,
+ 0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00,
+ 0x00, 0x33, 0x00, 0x1c, 0x12, 0x00, 0x3f, 0x00, 0x62, 0x00, 0x7a, 0x00,
+ 0x8a, 0x00, 0x96, 0x00, 0x9e, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xac, 0x00,
+ 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0x43, 0x2b, 0x4a, 0x22,
+ 0x51, 0x1a, 0x57, 0x15, 0x5e, 0x11, 0x63, 0x0d, 0x69, 0x0a, 0x6e, 0x08,
+ 0x74, 0x06, 0x78, 0x05, 0x7c, 0x04, 0x81, 0x03, 0x84, 0x02, 0x87, 0x02,
+ 0x8c, 0x01, 0x8f, 0x00, 0x92, 0x00, 0x94, 0x00, 0x97, 0x00, 0x9b, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1c, 0x2d, 0x14, 0x37, 0x0e, 0x41, 0x0a,
+ 0x4a, 0x07, 0x53, 0x04, 0x5b, 0x02, 0x63, 0x01, 0x69, 0x00, 0x70, 0x00,
+ 0x77, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x87, 0x00, 0x8a, 0x00, 0x8f, 0x00,
+ 0x92, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x7f, 0x0e, 0x85, 0x0a,
+ 0x8a, 0x07, 0x8f, 0x05, 0x93, 0x03, 0x98, 0x02, 0x9c, 0x01, 0xa0, 0x00,
+ 0xa3, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb2, 0x00,
+ 0xb3, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x28, 0x00,
+ 0x48, 0x00, 0x5f, 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91, 0x00,
+ 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x3a, 0x00, 0x2f,
+ 0x00, 0x16, 0x0e, 0x08, 0x20, 0x00, 0x42, 0x00, 0x5c, 0x00, 0x6f, 0x00,
+ 0x7e, 0x00, 0x89, 0x00, 0x92, 0x00, 0x99, 0x00, 0x9e, 0x00, 0xa2, 0x00,
+ 0xa6, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xa6, 0x00, 0x98, 0x00, 0x70, 0x00, 0x39, 0x00, 0x02, 0x00, 0x28, 0x00,
+ 0x48, 0x00, 0x5f, 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91, 0x00,
+ 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x38, 0x00, 0x2a,
+ 0x00, 0x09, 0x1d, 0x00, 0x3f, 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7f, 0x00,
+ 0x8b, 0x00, 0x94, 0x00, 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00,
+ 0xab, 0x00, 0xad, 0x00, 0x43, 0x2c, 0x49, 0x23, 0x50, 0x1c, 0x56, 0x17,
+ 0x5b, 0x12, 0x61, 0x0f, 0x66, 0x0c, 0x6b, 0x0a, 0x6f, 0x08, 0x75, 0x06,
+ 0x78, 0x05, 0x7c, 0x04, 0x81, 0x03, 0x84, 0x02, 0x87, 0x02, 0x8b, 0x01,
+ 0x8e, 0x01, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0x22, 0x1c, 0x2c, 0x15, 0x36, 0x0f, 0x3e, 0x0b, 0x48, 0x07, 0x50, 0x05,
+ 0x58, 0x04, 0x5f, 0x02, 0x66, 0x01, 0x6c, 0x00, 0x71, 0x00, 0x77, 0x00,
+ 0x7d, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x91, 0x00,
+ 0x94, 0x00, 0x97, 0x00, 0x7f, 0x0e, 0x84, 0x0a, 0x89, 0x07, 0x8d, 0x05,
+ 0x92, 0x03, 0x96, 0x02, 0x9a, 0x02, 0x9e, 0x01, 0xa1, 0x00, 0xa4, 0x00,
+ 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00,
+ 0xb5, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x3d, 0x00,
+ 0x52, 0x00, 0x64, 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d, 0x00,
+ 0x93, 0x00, 0x98, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x23, 0x02, 0x0e,
+ 0x12, 0x06, 0x20, 0x00, 0x3c, 0x00, 0x52, 0x00, 0x64, 0x00, 0x73, 0x00,
+ 0x7e, 0x00, 0x87, 0x00, 0x8f, 0x00, 0x95, 0x00, 0x9a, 0x00, 0x9e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x00, 0xa6, 0x00,
+ 0x85, 0x00, 0x57, 0x00, 0x28, 0x00, 0x01, 0x00, 0x21, 0x00, 0x3d, 0x00,
+ 0x52, 0x00, 0x64, 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d, 0x00,
+ 0x93, 0x00, 0x98, 0x00, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x19, 0x05, 0x00,
+ 0x24, 0x00, 0x3f, 0x00, 0x56, 0x00, 0x68, 0x00, 0x77, 0x00, 0x82, 0x00,
+ 0x8b, 0x00, 0x93, 0x00, 0x99, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00,
+ 0x43, 0x2e, 0x48, 0x25, 0x4e, 0x1e, 0x54, 0x19, 0x59, 0x14, 0x5f, 0x11,
+ 0x63, 0x0e, 0x69, 0x0b, 0x6c, 0x09, 0x71, 0x07, 0x76, 0x06, 0x78, 0x05,
+ 0x7c, 0x04, 0x81, 0x03, 0x84, 0x02, 0x86, 0x02, 0x8a, 0x01, 0x8e, 0x01,
+ 0x90, 0x00, 0x92, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1d, 0x2b, 0x16,
+ 0x34, 0x10, 0x3d, 0x0c, 0x45, 0x09, 0x4c, 0x06, 0x54, 0x04, 0x5b, 0x02,
+ 0x61, 0x02, 0x67, 0x01, 0x6d, 0x00, 0x73, 0x00, 0x78, 0x00, 0x7d, 0x00,
+ 0x81, 0x00, 0x86, 0x00, 0x89, 0x00, 0x8d, 0x00, 0x90, 0x00, 0x93, 0x00,
+ 0x7f, 0x0e, 0x84, 0x0b, 0x88, 0x08, 0x8d, 0x06, 0x91, 0x04, 0x94, 0x03,
+ 0x98, 0x02, 0x9c, 0x01, 0x9f, 0x01, 0xa2, 0x00, 0xa5, 0x00, 0xa8, 0x00,
+ 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00,
+ 0xb6, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48, 0x00,
+ 0x59, 0x00, 0x66, 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89, 0x00,
+ 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x18, 0x07, 0x0c, 0x14, 0x05,
+ 0x20, 0x00, 0x37, 0x00, 0x4c, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x75, 0x00,
+ 0x7e, 0x00, 0x86, 0x00, 0x8d, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70, 0x00,
+ 0x48, 0x00, 0x21, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48, 0x00,
+ 0x59, 0x00, 0x66, 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89, 0x00,
+ 0x00, 0x3c, 0x00, 0x35, 0x00, 0x23, 0x00, 0x0b, 0x0f, 0x00, 0x29, 0x00,
+ 0x3f, 0x00, 0x53, 0x00, 0x63, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x84, 0x00,
+ 0x8b, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9b, 0x00, 0x42, 0x2f, 0x48, 0x26,
+ 0x4d, 0x20, 0x52, 0x1a, 0x58, 0x16, 0x5c, 0x12, 0x61, 0x0f, 0x66, 0x0c,
+ 0x6b, 0x0b, 0x6d, 0x09, 0x73, 0x07, 0x76, 0x06, 0x79, 0x05, 0x7d, 0x04,
+ 0x81, 0x03, 0x83, 0x02, 0x86, 0x02, 0x89, 0x02, 0x8d, 0x01, 0x8f, 0x01,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0x22, 0x1d, 0x2a, 0x16, 0x33, 0x11, 0x3b, 0x0c,
+ 0x43, 0x0a, 0x4a, 0x07, 0x51, 0x05, 0x58, 0x04, 0x5e, 0x02, 0x64, 0x01,
+ 0x69, 0x01, 0x6f, 0x00, 0x74, 0x00, 0x78, 0x00, 0x7d, 0x00, 0x81, 0x00,
+ 0x85, 0x00, 0x89, 0x00, 0x8b, 0x00, 0x8f, 0x00, 0x7f, 0x0e, 0x83, 0x0b,
+ 0x88, 0x08, 0x8c, 0x06, 0x90, 0x05, 0x93, 0x03, 0x97, 0x02, 0x9a, 0x02,
+ 0x9d, 0x01, 0xa0, 0x00, 0xa3, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00,
+ 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0xb6, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50, 0x00,
+ 0x5d, 0x00, 0x68, 0x00, 0x72, 0x00, 0x7a, 0x00, 0x00, 0x3d, 0x00, 0x3a,
+ 0x00, 0x2f, 0x00, 0x20, 0x00, 0x10, 0x0b, 0x0a, 0x16, 0x04, 0x20, 0x00,
+ 0x34, 0x00, 0x46, 0x00, 0x56, 0x00, 0x62, 0x00, 0x6d, 0x00, 0x77, 0x00,
+ 0x7f, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbb, 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50, 0x00,
+ 0x5d, 0x00, 0x68, 0x00, 0x72, 0x00, 0x7a, 0x00, 0x00, 0x3d, 0x00, 0x38,
+ 0x00, 0x2a, 0x00, 0x16, 0x00, 0x00, 0x16, 0x00, 0x2c, 0x00, 0x3f, 0x00,
+ 0x50, 0x00, 0x5e, 0x00, 0x6b, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x85, 0x00,
+ 0x8b, 0x00, 0x91, 0x00, 0x42, 0x30, 0x47, 0x28, 0x4c, 0x21, 0x51, 0x1c,
+ 0x56, 0x17, 0x5a, 0x14, 0x60, 0x11, 0x63, 0x0e, 0x68, 0x0c, 0x6c, 0x0a,
+ 0x6f, 0x08, 0x74, 0x07, 0x77, 0x06, 0x79, 0x05, 0x7d, 0x04, 0x81, 0x03,
+ 0x83, 0x02, 0x85, 0x02, 0x88, 0x02, 0x8c, 0x01, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0x21, 0x1e, 0x2a, 0x17, 0x32, 0x12, 0x39, 0x0e, 0x40, 0x0a, 0x48, 0x07,
+ 0x4f, 0x05, 0x55, 0x04, 0x5a, 0x03, 0x60, 0x02, 0x66, 0x01, 0x6b, 0x00,
+ 0x70, 0x00, 0x75, 0x00, 0x79, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x84, 0x00,
+ 0x88, 0x00, 0x8b, 0x00, 0x7f, 0x0f, 0x83, 0x0b, 0x87, 0x09, 0x8b, 0x07,
+ 0x8e, 0x05, 0x92, 0x03, 0x96, 0x02, 0x99, 0x02, 0x9b, 0x01, 0x9e, 0x01,
+ 0xa1, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00,
+ 0xaf, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x16, 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55, 0x00,
+ 0x60, 0x00, 0x6a, 0x00, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x33, 0x00, 0x27,
+ 0x00, 0x18, 0x04, 0x0d, 0x0e, 0x08, 0x17, 0x04, 0x20, 0x00, 0x32, 0x00,
+ 0x42, 0x00, 0x50, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x70, 0x00, 0x78, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb6, 0x00,
+ 0xa6, 0x00, 0x8e, 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19, 0x00,
+ 0x00, 0x00, 0x16, 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55, 0x00,
+ 0x60, 0x00, 0x6a, 0x00, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x2f, 0x00, 0x1f,
+ 0x00, 0x0b, 0x08, 0x00, 0x1c, 0x00, 0x2e, 0x00, 0x3f, 0x00, 0x4e, 0x00,
+ 0x5b, 0x00, 0x66, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x86, 0x00,
+ 0x42, 0x31, 0x47, 0x29, 0x4b, 0x22, 0x50, 0x1d, 0x55, 0x19, 0x58, 0x15,
+ 0x5e, 0x12, 0x61, 0x0f, 0x65, 0x0d, 0x6a, 0x0b, 0x6c, 0x09, 0x70, 0x08,
+ 0x75, 0x07, 0x77, 0x06, 0x79, 0x05, 0x7d, 0x04, 0x81, 0x03, 0x83, 0x02,
+ 0x85, 0x02, 0x87, 0x02, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1e, 0x29, 0x18,
+ 0x31, 0x12, 0x38, 0x0f, 0x3f, 0x0c, 0x45, 0x09, 0x4c, 0x07, 0x52, 0x05,
+ 0x58, 0x04, 0x5d, 0x02, 0x63, 0x02, 0x67, 0x01, 0x6c, 0x00, 0x71, 0x00,
+ 0x75, 0x00, 0x79, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x84, 0x00, 0x88, 0x00,
+ 0x7f, 0x0f, 0x83, 0x0c, 0x87, 0x09, 0x8a, 0x07, 0x8e, 0x06, 0x91, 0x04,
+ 0x94, 0x03, 0x97, 0x02, 0x9a, 0x02, 0x9d, 0x01, 0xa0, 0x01, 0xa2, 0x00,
+ 0xa4, 0x00, 0xa7, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00,
+ 0xb0, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x13, 0x00, 0x25, 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59, 0x00,
+ 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x12,
+ 0x07, 0x0c, 0x10, 0x07, 0x18, 0x03, 0x20, 0x00, 0x30, 0x00, 0x3f, 0x00,
+ 0x4c, 0x00, 0x57, 0x00, 0x61, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97, 0x00,
+ 0x7e, 0x00, 0x64, 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00,
+ 0x13, 0x00, 0x25, 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59, 0x00,
+ 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x25, 0x00, 0x14, 0x00, 0x02,
+ 0x0f, 0x00, 0x20, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4d, 0x00, 0x58, 0x00,
+ 0x63, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x7b, 0x00, 0x42, 0x31, 0x46, 0x2a,
+ 0x4a, 0x24, 0x4f, 0x1f, 0x53, 0x1a, 0x58, 0x16, 0x5c, 0x13, 0x60, 0x11,
+ 0x63, 0x0e, 0x67, 0x0c, 0x6b, 0x0b, 0x6d, 0x09, 0x72, 0x07, 0x75, 0x07,
+ 0x77, 0x06, 0x79, 0x05, 0x7e, 0x04, 0x81, 0x03, 0x83, 0x02, 0x85, 0x02,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1e, 0x29, 0x18, 0x30, 0x13, 0x37, 0x0f,
+ 0x3d, 0x0c, 0x44, 0x0a, 0x4a, 0x07, 0x50, 0x05, 0x55, 0x04, 0x5b, 0x04,
+ 0x60, 0x02, 0x64, 0x01, 0x69, 0x01, 0x6d, 0x00, 0x72, 0x00, 0x76, 0x00,
+ 0x7a, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x83, 0x00, 0x7f, 0x0f, 0x83, 0x0c,
+ 0x86, 0x09, 0x8a, 0x07, 0x8d, 0x06, 0x90, 0x05, 0x93, 0x03, 0x96, 0x02,
+ 0x99, 0x02, 0x9c, 0x02, 0x9e, 0x01, 0xa0, 0x00, 0xa3, 0x00, 0xa5, 0x00,
+ 0xa7, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00,
+ 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x49, 0x00, 0x00, 0x3e, 0x00, 0x3c,
+ 0x00, 0x37, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x19, 0x02, 0x0e, 0x0a, 0x0a,
+ 0x11, 0x06, 0x19, 0x03, 0x1f, 0x00, 0x2e, 0x00, 0x3c, 0x00, 0x48, 0x00,
+ 0x53, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71, 0x00,
+ 0x59, 0x00, 0x41, 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00,
+ 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x49, 0x00, 0x00, 0x3e, 0x00, 0x3c,
+ 0x00, 0x34, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0c, 0x04, 0x00, 0x14, 0x00,
+ 0x23, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x56, 0x00, 0x60, 0x00,
+ 0x68, 0x00, 0x70, 0x00, 0x42, 0x32, 0x46, 0x2b, 0x49, 0x25, 0x4f, 0x1f,
+ 0x52, 0x1b, 0x57, 0x18, 0x59, 0x14, 0x5f, 0x12, 0x62, 0x0f, 0x65, 0x0d,
+ 0x6a, 0x0c, 0x6c, 0x0a, 0x6e, 0x09, 0x73, 0x07, 0x76, 0x06, 0x78, 0x06,
+ 0x7a, 0x05, 0x7e, 0x04, 0x81, 0x03, 0x83, 0x02, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0x21, 0x1e, 0x28, 0x19, 0x2f, 0x14, 0x35, 0x0f, 0x3c, 0x0c, 0x42, 0x0a,
+ 0x48, 0x07, 0x4e, 0x06, 0x53, 0x05, 0x58, 0x04, 0x5d, 0x02, 0x62, 0x02,
+ 0x66, 0x01, 0x6b, 0x01, 0x6f, 0x00, 0x73, 0x00, 0x76, 0x00, 0x7a, 0x00,
+ 0x7d, 0x00, 0x81, 0x00, 0x7f, 0x0f, 0x82, 0x0c, 0x86, 0x0a, 0x89, 0x07,
+ 0x8c, 0x06, 0x8f, 0x05, 0x92, 0x03, 0x95, 0x03, 0x98, 0x02, 0x9a, 0x02,
+ 0x9d, 0x01, 0x9f, 0x01, 0xa1, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00,
+ 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x2d, 0x00, 0x39, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x31,
+ 0x00, 0x28, 0x00, 0x1e, 0x00, 0x13, 0x05, 0x0d, 0x0c, 0x09, 0x13, 0x06,
+ 0x19, 0x03, 0x1f, 0x00, 0x2d, 0x00, 0x3a, 0x00, 0x45, 0x00, 0x4f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00,
+ 0xb1, 0x00, 0xa3, 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50, 0x00,
+ 0x3a, 0x00, 0x25, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x2d, 0x00, 0x39, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x36, 0x00, 0x2d,
+ 0x00, 0x21, 0x00, 0x13, 0x00, 0x04, 0x0a, 0x00, 0x18, 0x00, 0x26, 0x00,
+ 0x33, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x65, 0x00,
+ 0x42, 0x33, 0x45, 0x2c, 0x48, 0x26, 0x4e, 0x21, 0x50, 0x1c, 0x56, 0x19,
+ 0x58, 0x16, 0x5c, 0x13, 0x60, 0x11, 0x62, 0x0e, 0x67, 0x0c, 0x6a, 0x0b,
+ 0x6d, 0x0a, 0x70, 0x09, 0x74, 0x07, 0x76, 0x06, 0x78, 0x06, 0x7a, 0x05,
+ 0x7e, 0x04, 0x81, 0x03, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1e, 0x28, 0x19,
+ 0x2f, 0x15, 0x35, 0x11, 0x3b, 0x0d, 0x41, 0x0b, 0x46, 0x09, 0x4c, 0x07,
+ 0x51, 0x05, 0x55, 0x04, 0x5b, 0x04, 0x5f, 0x02, 0x63, 0x02, 0x68, 0x01,
+ 0x6b, 0x00, 0x70, 0x00, 0x73, 0x00, 0x77, 0x00, 0x7b, 0x00, 0x7d, 0x00,
+ 0x7f, 0x0f, 0x82, 0x0c, 0x86, 0x0a, 0x89, 0x08, 0x8c, 0x06, 0x8f, 0x05,
+ 0x91, 0x04, 0x94, 0x03, 0x97, 0x02, 0x99, 0x02, 0x9c, 0x02, 0x9e, 0x01,
+ 0xa0, 0x01, 0xa2, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00,
+ 0xac, 0x00, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29, 0x00,
+ 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x33, 0x00, 0x2c, 0x00, 0x23,
+ 0x00, 0x19, 0x00, 0x0f, 0x07, 0x0c, 0x0e, 0x08, 0x14, 0x05, 0x1a, 0x02,
+ 0x1f, 0x00, 0x2c, 0x00, 0x38, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7, 0x00,
+ 0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35, 0x00,
+ 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29, 0x00,
+ 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x30, 0x00, 0x25, 0x00, 0x19,
+ 0x00, 0x0c, 0x01, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x34, 0x00,
+ 0x3f, 0x00, 0x49, 0x00, 0x53, 0x00, 0x5b, 0x00, 0x5d, 0x1a, 0x6d, 0x16,
+ 0x72, 0x15, 0x75, 0x14, 0x77, 0x13, 0x78, 0x13, 0x79, 0x13, 0x7a, 0x12,
+ 0x7a, 0x12, 0x7b, 0x12, 0x7b, 0x12, 0x7b, 0x12, 0x7c, 0x12, 0x7c, 0x11,
+ 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7d, 0x11,
+ 0xbd, 0x02, 0xa4, 0x06, 0x97, 0x09, 0x91, 0x0a, 0x8d, 0x0b, 0x8a, 0x0c,
+ 0x89, 0x0d, 0x88, 0x0d, 0x86, 0x0d, 0x86, 0x0e, 0x85, 0x0e, 0x85, 0x0e,
+ 0x84, 0x0e, 0x84, 0x0e, 0x83, 0x0f, 0x83, 0x0f, 0x83, 0x0f, 0x83, 0x0f,
+ 0x82, 0x0f, 0x82, 0x0f, 0x33, 0x11, 0x5f, 0x11, 0x6f, 0x11, 0x74, 0x11,
+ 0x77, 0x11, 0x78, 0x11, 0x7a, 0x11, 0x7a, 0x11, 0x7b, 0x11, 0x7b, 0x11,
+ 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7d, 0x11, 0x7d, 0x11,
+ 0x7d, 0x11, 0x7d, 0x11, 0x7d, 0x11, 0x7d, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x00, 0x3f, 0x00, 0x3e,
+ 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x26, 0x00, 0x1d, 0x00, 0x14,
+ 0x03, 0x0e, 0x09, 0x0b, 0x0f, 0x08, 0x15, 0x05, 0x1a, 0x02, 0x1f, 0x00,
+ 0x2b, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d, 0x00,
+ 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x00, 0x3f, 0x00, 0x3d,
+ 0x00, 0x39, 0x00, 0x32, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x06,
+ 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x3f, 0x00,
+ 0x49, 0x00, 0x51, 0x00, 0x50, 0x24, 0x5f, 0x1f, 0x66, 0x1b, 0x6b, 0x19,
+ 0x6e, 0x18, 0x70, 0x17, 0x73, 0x16, 0x73, 0x15, 0x75, 0x15, 0x76, 0x15,
+ 0x76, 0x15, 0x77, 0x14, 0x77, 0x14, 0x78, 0x13, 0x78, 0x13, 0x79, 0x13,
+ 0x79, 0x13, 0x7a, 0x13, 0x7a, 0x13, 0x7b, 0x13, 0xcc, 0x00, 0xb5, 0x00,
+ 0xa8, 0x02, 0x9e, 0x04, 0x99, 0x05, 0x94, 0x06, 0x92, 0x07, 0x8f, 0x08,
+ 0x8d, 0x09, 0x8c, 0x09, 0x8b, 0x0a, 0x8a, 0x0a, 0x89, 0x0b, 0x88, 0x0b,
+ 0x88, 0x0b, 0x87, 0x0c, 0x87, 0x0c, 0x86, 0x0c, 0x86, 0x0c, 0x86, 0x0c,
+ 0x23, 0x13, 0x46, 0x11, 0x58, 0x11, 0x63, 0x11, 0x69, 0x11, 0x6d, 0x11,
+ 0x70, 0x11, 0x72, 0x11, 0x73, 0x11, 0x75, 0x11, 0x76, 0x11, 0x77, 0x11,
+ 0x77, 0x11, 0x78, 0x11, 0x78, 0x11, 0x79, 0x11, 0x79, 0x11, 0x79, 0x11,
+ 0x7a, 0x11, 0x7a, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0d, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36,
+ 0x00, 0x30, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00, 0x10, 0x05, 0x0d,
+ 0x0b, 0x0a, 0x10, 0x07, 0x16, 0x04, 0x1b, 0x02, 0x1f, 0x00, 0x2a, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00,
+ 0xb6, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72, 0x00,
+ 0x60, 0x00, 0x4f, 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e, 0x00,
+ 0x00, 0x00, 0x0d, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x33,
+ 0x00, 0x2b, 0x00, 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00, 0x00, 0x0b, 0x00,
+ 0x16, 0x00, 0x21, 0x00, 0x2c, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48, 0x00,
+ 0x4a, 0x2a, 0x57, 0x24, 0x5f, 0x20, 0x64, 0x1e, 0x68, 0x1c, 0x6a, 0x1b,
+ 0x6d, 0x19, 0x6e, 0x18, 0x70, 0x18, 0x72, 0x17, 0x72, 0x17, 0x73, 0x16,
+ 0x74, 0x15, 0x75, 0x15, 0x76, 0x15, 0x76, 0x15, 0x76, 0x15, 0x76, 0x15,
+ 0x76, 0x15, 0x77, 0x14, 0xd1, 0x00, 0xc0, 0x00, 0xb3, 0x00, 0xaa, 0x01,
+ 0xa2, 0x02, 0x9d, 0x03, 0x99, 0x04, 0x96, 0x05, 0x94, 0x06, 0x92, 0x06,
+ 0x90, 0x07, 0x8f, 0x07, 0x8d, 0x08, 0x8d, 0x08, 0x8c, 0x09, 0x8b, 0x09,
+ 0x8a, 0x09, 0x8a, 0x0a, 0x89, 0x0a, 0x89, 0x0b, 0x22, 0x17, 0x39, 0x11,
+ 0x4a, 0x11, 0x55, 0x11, 0x5e, 0x11, 0x63, 0x11, 0x67, 0x11, 0x6a, 0x11,
+ 0x6c, 0x11, 0x6e, 0x11, 0x70, 0x11, 0x71, 0x11, 0x72, 0x11, 0x73, 0x11,
+ 0x74, 0x11, 0x75, 0x11, 0x75, 0x11, 0x76, 0x11, 0x76, 0x11, 0x77, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00, 0x32, 0x00, 0x2c,
+ 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x01, 0x0e, 0x07, 0x0c, 0x0c, 0x09,
+ 0x11, 0x06, 0x16, 0x04, 0x1b, 0x02, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00,
+ 0xa5, 0x00, 0x98, 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59, 0x00,
+ 0x49, 0x00, 0x39, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x25,
+ 0x00, 0x1c, 0x00, 0x11, 0x00, 0x07, 0x03, 0x00, 0x0e, 0x00, 0x19, 0x00,
+ 0x23, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48, 0x2e, 0x53, 0x28,
+ 0x5a, 0x24, 0x5f, 0x22, 0x63, 0x1f, 0x66, 0x1e, 0x69, 0x1c, 0x6a, 0x1b,
+ 0x6c, 0x1a, 0x6d, 0x1a, 0x6e, 0x19, 0x70, 0x18, 0x71, 0x18, 0x72, 0x18,
+ 0x72, 0x17, 0x72, 0x17, 0x73, 0x16, 0x74, 0x15, 0x75, 0x15, 0x76, 0x15,
+ 0xd5, 0x00, 0xc6, 0x00, 0xbb, 0x00, 0xb2, 0x00, 0xaa, 0x00, 0xa4, 0x01,
+ 0xa0, 0x02, 0x9c, 0x02, 0x9a, 0x03, 0x97, 0x04, 0x95, 0x05, 0x93, 0x05,
+ 0x92, 0x06, 0x91, 0x06, 0x90, 0x07, 0x8e, 0x07, 0x8e, 0x07, 0x8d, 0x07,
+ 0x8c, 0x08, 0x8c, 0x09, 0x22, 0x1a, 0x33, 0x13, 0x41, 0x11, 0x4c, 0x11,
+ 0x54, 0x11, 0x5b, 0x11, 0x5f, 0x11, 0x63, 0x11, 0x66, 0x11, 0x68, 0x11,
+ 0x6a, 0x11, 0x6c, 0x11, 0x6e, 0x11, 0x6f, 0x11, 0x70, 0x11, 0x71, 0x11,
+ 0x72, 0x11, 0x72, 0x11, 0x73, 0x11, 0x74, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x07, 0x7f, 0x00,
+ 0xa5, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00,
+ 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00,
+ 0xbe, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x47, 0x07, 0x0f, 0x0f, 0x00, 0x26, 0x00, 0x33, 0x00, 0x38, 0x00, 0x3a,
+ 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e,
+ 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x46, 0x31, 0x50, 0x2b, 0x56, 0x27, 0x5b, 0x24,
+ 0x5f, 0x22, 0x62, 0x20, 0x65, 0x1f, 0x67, 0x1d, 0x69, 0x1d, 0x6a, 0x1b,
+ 0x6c, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x19, 0x6f, 0x18, 0x71, 0x18,
+ 0x72, 0x18, 0x72, 0x18, 0x72, 0x18, 0x72, 0x17, 0xd6, 0x00, 0xcb, 0x00,
+ 0xc0, 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xab, 0x00, 0xa6, 0x01, 0xa2, 0x01,
+ 0x9f, 0x02, 0x9c, 0x02, 0x9a, 0x03, 0x98, 0x03, 0x96, 0x04, 0x94, 0x05,
+ 0x93, 0x05, 0x92, 0x06, 0x91, 0x06, 0x90, 0x06, 0x8f, 0x06, 0x8f, 0x07,
+ 0x22, 0x1b, 0x2f, 0x15, 0x3b, 0x12, 0x44, 0x11, 0x4d, 0x11, 0x53, 0x11,
+ 0x59, 0x11, 0x5d, 0x11, 0x60, 0x11, 0x63, 0x11, 0x66, 0x11, 0x67, 0x11,
+ 0x69, 0x11, 0x6b, 0x11, 0x6c, 0x11, 0x6d, 0x11, 0x6e, 0x11, 0x6f, 0x11,
+ 0x70, 0x11, 0x71, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x3f, 0x00, 0x7f, 0x00, 0x9c, 0x00,
+ 0xaa, 0x00, 0xb1, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xba, 0x00,
+ 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x3f, 0x00,
+ 0x05, 0x05, 0x00, 0x1c, 0x00, 0x2a, 0x00, 0x31, 0x00, 0x35, 0x00, 0x38,
+ 0x00, 0x39, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d,
+ 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x45, 0x33, 0x4d, 0x2e, 0x53, 0x29, 0x58, 0x26, 0x5c, 0x24, 0x5f, 0x22,
+ 0x61, 0x21, 0x65, 0x20, 0x65, 0x1e, 0x68, 0x1d, 0x69, 0x1d, 0x6a, 0x1b,
+ 0x6b, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x19, 0x6f, 0x18,
+ 0x71, 0x18, 0x72, 0x18, 0xd7, 0x00, 0xcd, 0x00, 0xc5, 0x00, 0xbd, 0x00,
+ 0xb6, 0x00, 0xb0, 0x00, 0xab, 0x00, 0xa7, 0x00, 0xa4, 0x01, 0xa1, 0x02,
+ 0x9e, 0x02, 0x9c, 0x02, 0x9a, 0x03, 0x98, 0x03, 0x97, 0x03, 0x96, 0x04,
+ 0x94, 0x05, 0x93, 0x05, 0x92, 0x05, 0x91, 0x06, 0x21, 0x1c, 0x2d, 0x16,
+ 0x37, 0x13, 0x40, 0x11, 0x47, 0x11, 0x4e, 0x11, 0x53, 0x11, 0x57, 0x11,
+ 0x5b, 0x11, 0x5e, 0x11, 0x61, 0x11, 0x63, 0x11, 0x65, 0x11, 0x67, 0x11,
+ 0x68, 0x11, 0x6a, 0x11, 0x6b, 0x11, 0x6c, 0x11, 0x6d, 0x11, 0x6e, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x26, 0x05, 0x05, 0x3f, 0x00, 0x6d, 0x00, 0x88, 0x00, 0x99, 0x00,
+ 0xa3, 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00,
+ 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x12, 0x00,
+ 0x00, 0x09, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x32,
+ 0x00, 0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x34, 0x4c, 0x2f,
+ 0x51, 0x2c, 0x56, 0x28, 0x5a, 0x26, 0x5c, 0x24, 0x60, 0x23, 0x61, 0x21,
+ 0x64, 0x20, 0x65, 0x1f, 0x66, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1c,
+ 0x6b, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x19,
+ 0xd8, 0x00, 0xcf, 0x00, 0xc7, 0x00, 0xc0, 0x00, 0xba, 0x00, 0xb5, 0x00,
+ 0xb0, 0x00, 0xac, 0x00, 0xa8, 0x00, 0xa5, 0x01, 0xa2, 0x01, 0xa0, 0x02,
+ 0x9e, 0x02, 0x9c, 0x02, 0x9a, 0x02, 0x99, 0x03, 0x97, 0x03, 0x96, 0x03,
+ 0x95, 0x04, 0x94, 0x05, 0x22, 0x1d, 0x2b, 0x17, 0x34, 0x14, 0x3b, 0x12,
+ 0x43, 0x11, 0x49, 0x11, 0x4e, 0x11, 0x52, 0x11, 0x56, 0x11, 0x5a, 0x11,
+ 0x5d, 0x11, 0x5f, 0x11, 0x61, 0x11, 0x63, 0x11, 0x65, 0x11, 0x66, 0x11,
+ 0x68, 0x11, 0x69, 0x11, 0x6a, 0x11, 0x6b, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x1c,
+ 0x12, 0x00, 0x3f, 0x00, 0x62, 0x00, 0x7a, 0x00, 0x8a, 0x00, 0x96, 0x00,
+ 0x9e, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb1, 0x00,
+ 0xb3, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xb2, 0x00, 0x9c, 0x00, 0x6d, 0x00, 0x3f, 0x00, 0x1d, 0x00, 0x05, 0x00,
+ 0x00, 0x0b, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d,
+ 0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x36, 0x4a, 0x31, 0x50, 0x2d, 0x54, 0x2a,
+ 0x57, 0x28, 0x5b, 0x26, 0x5c, 0x24, 0x60, 0x23, 0x61, 0x21, 0x63, 0x20,
+ 0x65, 0x20, 0x65, 0x1e, 0x67, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1c,
+ 0x6a, 0x1b, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0xd9, 0x00, 0xd1, 0x00,
+ 0xca, 0x00, 0xc3, 0x00, 0xbe, 0x00, 0xb9, 0x00, 0xb4, 0x00, 0xb0, 0x00,
+ 0xac, 0x00, 0xa9, 0x00, 0xa6, 0x00, 0xa3, 0x01, 0xa1, 0x01, 0x9f, 0x02,
+ 0x9d, 0x02, 0x9b, 0x02, 0x9a, 0x02, 0x99, 0x03, 0x98, 0x03, 0x97, 0x03,
+ 0x21, 0x1e, 0x2a, 0x18, 0x32, 0x15, 0x39, 0x13, 0x3f, 0x12, 0x45, 0x11,
+ 0x4a, 0x11, 0x4e, 0x11, 0x52, 0x11, 0x56, 0x11, 0x59, 0x11, 0x5c, 0x11,
+ 0x5d, 0x11, 0x60, 0x11, 0x61, 0x11, 0x63, 0x11, 0x65, 0x11, 0x66, 0x11,
+ 0x67, 0x11, 0x68, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x09, 0x1d, 0x00,
+ 0x3f, 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7f, 0x00, 0x8b, 0x00, 0x94, 0x00,
+ 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xad, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa, 0x00,
+ 0x88, 0x00, 0x62, 0x00, 0x3f, 0x00, 0x24, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29,
+ 0x00, 0x2b, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x43, 0x36, 0x49, 0x32, 0x4e, 0x2f, 0x52, 0x2c, 0x56, 0x29, 0x58, 0x27,
+ 0x5b, 0x26, 0x5d, 0x24, 0x60, 0x23, 0x60, 0x22, 0x62, 0x20, 0x65, 0x20,
+ 0x65, 0x1f, 0x66, 0x1e, 0x68, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1c,
+ 0x6a, 0x1b, 0x6c, 0x1a, 0xd9, 0x00, 0xd2, 0x00, 0xcc, 0x00, 0xc6, 0x00,
+ 0xc1, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xb3, 0x00, 0xaf, 0x00, 0xac, 0x00,
+ 0xa9, 0x00, 0xa6, 0x00, 0xa4, 0x01, 0xa2, 0x01, 0xa0, 0x01, 0x9e, 0x02,
+ 0x9d, 0x02, 0x9c, 0x02, 0x9a, 0x02, 0x99, 0x02, 0x22, 0x1e, 0x29, 0x19,
+ 0x30, 0x16, 0x36, 0x13, 0x3c, 0x12, 0x41, 0x11, 0x46, 0x11, 0x4a, 0x11,
+ 0x4f, 0x11, 0x52, 0x11, 0x55, 0x11, 0x58, 0x11, 0x5a, 0x11, 0x5c, 0x11,
+ 0x5f, 0x11, 0x60, 0x11, 0x62, 0x11, 0x63, 0x11, 0x65, 0x11, 0x66, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3a, 0x00, 0x31, 0x00, 0x19, 0x05, 0x00, 0x24, 0x00, 0x3f, 0x00,
+ 0x56, 0x00, 0x68, 0x00, 0x77, 0x00, 0x82, 0x00, 0x8b, 0x00, 0x93, 0x00,
+ 0x99, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb1, 0x00, 0x99, 0x00, 0x7a, 0x00,
+ 0x5b, 0x00, 0x3f, 0x00, 0x29, 0x00, 0x16, 0x00, 0x08, 0x00, 0x00, 0x02,
+ 0x00, 0x0c, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x22, 0x00, 0x25,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x37, 0x48, 0x33,
+ 0x4d, 0x30, 0x51, 0x2d, 0x54, 0x2a, 0x57, 0x29, 0x59, 0x27, 0x5c, 0x26,
+ 0x5d, 0x24, 0x60, 0x23, 0x60, 0x22, 0x62, 0x20, 0x65, 0x20, 0x65, 0x20,
+ 0x65, 0x1f, 0x66, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1d,
+ 0xd9, 0x00, 0xd3, 0x00, 0xcd, 0x00, 0xc8, 0x00, 0xc3, 0x00, 0xbe, 0x00,
+ 0xba, 0x00, 0xb6, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00,
+ 0xa7, 0x00, 0xa5, 0x00, 0xa3, 0x01, 0xa1, 0x01, 0xa0, 0x02, 0x9e, 0x02,
+ 0x9d, 0x02, 0x9c, 0x02, 0x21, 0x1e, 0x28, 0x1a, 0x2e, 0x17, 0x34, 0x14,
+ 0x39, 0x13, 0x3f, 0x12, 0x43, 0x11, 0x48, 0x11, 0x4b, 0x11, 0x4f, 0x11,
+ 0x52, 0x11, 0x55, 0x11, 0x57, 0x11, 0x59, 0x11, 0x5c, 0x11, 0x5d, 0x11,
+ 0x5f, 0x11, 0x61, 0x11, 0x62, 0x11, 0x63, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35,
+ 0x00, 0x23, 0x00, 0x0b, 0x0f, 0x00, 0x29, 0x00, 0x3f, 0x00, 0x53, 0x00,
+ 0x63, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x84, 0x00, 0x8b, 0x00, 0x92, 0x00,
+ 0x97, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbb, 0x00, 0xb5, 0x00, 0xa3, 0x00, 0x8a, 0x00, 0x6f, 0x00, 0x56, 0x00,
+ 0x3f, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x00, 0x04,
+ 0x00, 0x0c, 0x00, 0x12, 0x00, 0x17, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x43, 0x38, 0x48, 0x34, 0x4c, 0x31, 0x4f, 0x2e,
+ 0x53, 0x2c, 0x56, 0x2a, 0x57, 0x28, 0x5a, 0x27, 0x5c, 0x26, 0x5d, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x61, 0x21, 0x64, 0x20, 0x65, 0x20, 0x65, 0x20,
+ 0x65, 0x1e, 0x67, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0xd9, 0x00, 0xd4, 0x00,
+ 0xce, 0x00, 0xca, 0x00, 0xc5, 0x00, 0xc1, 0x00, 0xbd, 0x00, 0xb9, 0x00,
+ 0xb6, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa8, 0x00,
+ 0xa6, 0x00, 0xa4, 0x01, 0xa2, 0x01, 0xa0, 0x01, 0x9f, 0x02, 0x9e, 0x02,
+ 0x22, 0x1f, 0x27, 0x1a, 0x2d, 0x17, 0x33, 0x15, 0x38, 0x13, 0x3c, 0x13,
+ 0x41, 0x12, 0x44, 0x11, 0x48, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x11,
+ 0x54, 0x11, 0x57, 0x11, 0x59, 0x11, 0x5b, 0x11, 0x5c, 0x11, 0x5e, 0x11,
+ 0x5f, 0x11, 0x61, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x16,
+ 0x00, 0x00, 0x16, 0x00, 0x2c, 0x00, 0x3f, 0x00, 0x50, 0x00, 0x5e, 0x00,
+ 0x6b, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x85, 0x00, 0x8b, 0x00, 0x91, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb7, 0x00,
+ 0xaa, 0x00, 0x96, 0x00, 0x7f, 0x00, 0x68, 0x00, 0x53, 0x00, 0x3f, 0x00,
+ 0x2e, 0x00, 0x20, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x06,
+ 0x00, 0x0c, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x43, 0x38, 0x47, 0x35, 0x4b, 0x32, 0x4e, 0x2f, 0x52, 0x2d, 0x53, 0x2b,
+ 0x57, 0x2a, 0x58, 0x27, 0x5b, 0x27, 0x5c, 0x25, 0x5d, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x61, 0x21, 0x64, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x1f,
+ 0x66, 0x1e, 0x68, 0x1d, 0xda, 0x00, 0xd4, 0x00, 0xd0, 0x00, 0xcb, 0x00,
+ 0xc7, 0x00, 0xc2, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb5, 0x00,
+ 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa8, 0x00, 0xa6, 0x00,
+ 0xa4, 0x00, 0xa3, 0x01, 0xa1, 0x01, 0xa0, 0x01, 0x21, 0x1f, 0x27, 0x1b,
+ 0x2c, 0x18, 0x31, 0x16, 0x36, 0x14, 0x3a, 0x13, 0x3e, 0x12, 0x42, 0x11,
+ 0x45, 0x11, 0x49, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x54, 0x11,
+ 0x56, 0x11, 0x58, 0x11, 0x5a, 0x11, 0x5c, 0x11, 0x5d, 0x11, 0x5e, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3d, 0x00, 0x39, 0x00, 0x2f, 0x00, 0x1f, 0x00, 0x0b, 0x08, 0x00,
+ 0x1c, 0x00, 0x2e, 0x00, 0x3f, 0x00, 0x4e, 0x00, 0x5b, 0x00, 0x66, 0x00,
+ 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00,
+ 0x8b, 0x00, 0x77, 0x00, 0x63, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x30, 0x00,
+ 0x23, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x39, 0x46, 0x35,
+ 0x4a, 0x32, 0x4e, 0x30, 0x50, 0x2e, 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x29,
+ 0x58, 0x27, 0x5c, 0x27, 0x5c, 0x25, 0x5d, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x22, 0x63, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x1f,
+ 0xda, 0x00, 0xd5, 0x00, 0xd1, 0x00, 0xcc, 0x00, 0xc8, 0x00, 0xc4, 0x00,
+ 0xc1, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb7, 0x00, 0xb4, 0x00, 0xb2, 0x00,
+ 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa9, 0x00, 0xa7, 0x00, 0xa5, 0x00,
+ 0xa4, 0x01, 0xa2, 0x01, 0x22, 0x1f, 0x27, 0x1b, 0x2c, 0x18, 0x30, 0x16,
+ 0x35, 0x14, 0x39, 0x13, 0x3d, 0x13, 0x40, 0x12, 0x44, 0x11, 0x47, 0x11,
+ 0x49, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x54, 0x11, 0x56, 0x11,
+ 0x58, 0x11, 0x59, 0x11, 0x5b, 0x11, 0x5c, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3b,
+ 0x00, 0x32, 0x00, 0x25, 0x00, 0x14, 0x00, 0x02, 0x0f, 0x00, 0x20, 0x00,
+ 0x30, 0x00, 0x3f, 0x00, 0x4d, 0x00, 0x58, 0x00, 0x63, 0x00, 0x6c, 0x00,
+ 0x74, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x82, 0x00,
+ 0x70, 0x00, 0x5e, 0x00, 0x4e, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x26, 0x00,
+ 0x1c, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x39, 0x46, 0x36, 0x4a, 0x33, 0x4d, 0x31,
+ 0x4f, 0x2e, 0x52, 0x2d, 0x53, 0x2b, 0x57, 0x2a, 0x57, 0x28, 0x5a, 0x27,
+ 0x5c, 0x27, 0x5c, 0x25, 0x5e, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x22,
+ 0x62, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0xda, 0x00, 0xd6, 0x00,
+ 0xd1, 0x00, 0xcd, 0x00, 0xc9, 0x00, 0xc6, 0x00, 0xc2, 0x00, 0xbf, 0x00,
+ 0xbc, 0x00, 0xb9, 0x00, 0xb6, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf, 0x00,
+ 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa7, 0x00, 0xa6, 0x00, 0xa4, 0x00,
+ 0x21, 0x1f, 0x26, 0x1c, 0x2b, 0x19, 0x2f, 0x17, 0x33, 0x15, 0x37, 0x14,
+ 0x3b, 0x13, 0x3e, 0x12, 0x41, 0x12, 0x44, 0x11, 0x47, 0x11, 0x4a, 0x11,
+ 0x4d, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x54, 0x11, 0x55, 0x11, 0x57, 0x11,
+ 0x59, 0x11, 0x5a, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x34, 0x00, 0x29,
+ 0x00, 0x1b, 0x00, 0x0c, 0x04, 0x00, 0x14, 0x00, 0x23, 0x00, 0x32, 0x00,
+ 0x3f, 0x00, 0x4b, 0x00, 0x56, 0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00,
+ 0xb4, 0x00, 0xa9, 0x00, 0x9b, 0x00, 0x8b, 0x00, 0x7b, 0x00, 0x6b, 0x00,
+ 0x5b, 0x00, 0x4d, 0x00, 0x3f, 0x00, 0x33, 0x00, 0x28, 0x00, 0x1f, 0x00,
+ 0x16, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x39, 0x45, 0x36, 0x49, 0x34, 0x4c, 0x31, 0x4f, 0x30, 0x51, 0x2e,
+ 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x2a, 0x57, 0x28, 0x5b, 0x27, 0x5c, 0x27,
+ 0x5c, 0x25, 0x5e, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x22, 0x61, 0x21,
+ 0x64, 0x20, 0x65, 0x20, 0xda, 0x00, 0xd6, 0x00, 0xd2, 0x00, 0xce, 0x00,
+ 0xcb, 0x00, 0xc7, 0x00, 0xc4, 0x00, 0xc1, 0x00, 0xbe, 0x00, 0xbb, 0x00,
+ 0xb8, 0x00, 0xb6, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf, 0x00, 0xad, 0x00,
+ 0xab, 0x00, 0xa9, 0x00, 0xa8, 0x00, 0xa6, 0x00, 0x22, 0x1f, 0x26, 0x1c,
+ 0x2a, 0x19, 0x2e, 0x17, 0x32, 0x16, 0x36, 0x14, 0x39, 0x13, 0x3d, 0x13,
+ 0x40, 0x12, 0x43, 0x11, 0x45, 0x11, 0x48, 0x11, 0x4b, 0x11, 0x4d, 0x11,
+ 0x4f, 0x11, 0x51, 0x11, 0x53, 0x11, 0x55, 0x11, 0x56, 0x11, 0x58, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x36, 0x00, 0x2d, 0x00, 0x21, 0x00, 0x13,
+ 0x00, 0x04, 0x0a, 0x00, 0x18, 0x00, 0x26, 0x00, 0x33, 0x00, 0x3f, 0x00,
+ 0x4a, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xac, 0x00,
+ 0xa0, 0x00, 0x93, 0x00, 0x84, 0x00, 0x75, 0x00, 0x66, 0x00, 0x58, 0x00,
+ 0x4b, 0x00, 0x3f, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x19, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3a, 0x45, 0x37,
+ 0x48, 0x35, 0x4a, 0x32, 0x4e, 0x31, 0x50, 0x2e, 0x53, 0x2e, 0x53, 0x2b,
+ 0x57, 0x2a, 0x57, 0x29, 0x58, 0x27, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x25,
+ 0x5e, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x61, 0x21, 0x64, 0x20,
+ 0xdb, 0x00, 0xd7, 0x00, 0xd3, 0x00, 0xcf, 0x00, 0xcc, 0x00, 0xc8, 0x00,
+ 0xc5, 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbc, 0x00, 0xba, 0x00, 0xb7, 0x00,
+ 0xb5, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00,
+ 0xa9, 0x00, 0xa8, 0x00, 0x21, 0x20, 0x26, 0x1c, 0x2a, 0x1a, 0x2d, 0x18,
+ 0x31, 0x16, 0x35, 0x14, 0x38, 0x13, 0x3b, 0x13, 0x3e, 0x12, 0x41, 0x12,
+ 0x44, 0x11, 0x46, 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11,
+ 0x51, 0x11, 0x53, 0x11, 0x55, 0x11, 0x56, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d,
+ 0x00, 0x38, 0x00, 0x30, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c, 0x01, 0x00,
+ 0x0e, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x34, 0x00, 0x3f, 0x00, 0x49, 0x00,
+ 0x53, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00,
+ 0x8b, 0x00, 0x7e, 0x00, 0x70, 0x00, 0x63, 0x00, 0x56, 0x00, 0x4a, 0x00,
+ 0x3f, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3a, 0x45, 0x37, 0x48, 0x35, 0x4a, 0x33,
+ 0x4d, 0x31, 0x4f, 0x2f, 0x52, 0x2e, 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x2a,
+ 0x57, 0x29, 0x59, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x25, 0x5f, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x22, 0xdb, 0x00, 0xd7, 0x00,
+ 0xd3, 0x00, 0xd0, 0x00, 0xcc, 0x00, 0xc9, 0x00, 0xc6, 0x00, 0xc3, 0x00,
+ 0xc1, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb9, 0x00, 0xb7, 0x00, 0xb5, 0x00,
+ 0xb3, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00, 0xaa, 0x00,
+ 0x21, 0x20, 0x25, 0x1d, 0x29, 0x1a, 0x2d, 0x18, 0x30, 0x17, 0x33, 0x15,
+ 0x37, 0x14, 0x3a, 0x13, 0x3d, 0x13, 0x3f, 0x12, 0x42, 0x12, 0x44, 0x11,
+ 0x47, 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11, 0x51, 0x11,
+ 0x53, 0x11, 0x55, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x32,
+ 0x00, 0x29, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x06, 0x06, 0x00, 0x13, 0x00,
+ 0x1f, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x3f, 0x00, 0x49, 0x00, 0x51, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00,
+ 0xb8, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9d, 0x00, 0x92, 0x00, 0x85, 0x00,
+ 0x78, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3f, 0x00,
+ 0x36, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x3a, 0x45, 0x38, 0x47, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x30,
+ 0x51, 0x2e, 0x53, 0x2e, 0x53, 0x2b, 0x56, 0x2a, 0x57, 0x2a, 0x57, 0x28,
+ 0x5a, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x25, 0x5f, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0xdb, 0x00, 0xd7, 0x00, 0xd4, 0x00, 0xd0, 0x00,
+ 0xcd, 0x00, 0xca, 0x00, 0xc7, 0x00, 0xc5, 0x00, 0xc2, 0x00, 0xbf, 0x00,
+ 0xbd, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb4, 0x00, 0xb2, 0x00,
+ 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xac, 0x00, 0x21, 0x20, 0x25, 0x1d,
+ 0x29, 0x1a, 0x2c, 0x18, 0x2f, 0x17, 0x33, 0x16, 0x36, 0x14, 0x39, 0x13,
+ 0x3b, 0x13, 0x3e, 0x13, 0x41, 0x12, 0x43, 0x11, 0x45, 0x11, 0x47, 0x11,
+ 0x4a, 0x11, 0x4c, 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x52, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x33, 0x00, 0x2b, 0x00, 0x22,
+ 0x00, 0x17, 0x00, 0x0c, 0x00, 0x00, 0x0b, 0x00, 0x16, 0x00, 0x21, 0x00,
+ 0x2c, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb3, 0x00,
+ 0xab, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x74, 0x00,
+ 0x68, 0x00, 0x5d, 0x00, 0x53, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39,
+ 0x46, 0x35, 0x4a, 0x34, 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x58, 0x27, 0x5b, 0x27,
+ 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x24, 0x5f, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0xdb, 0x00, 0xd8, 0x00, 0xd4, 0x00, 0xd1, 0x00, 0xce, 0x00, 0xcb, 0x00,
+ 0xc8, 0x00, 0xc6, 0x00, 0xc3, 0x00, 0xc1, 0x00, 0xbe, 0x00, 0xbc, 0x00,
+ 0xba, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb4, 0x00, 0xb2, 0x00, 0xb0, 0x00,
+ 0xaf, 0x00, 0xad, 0x00, 0x21, 0x20, 0x25, 0x1d, 0x28, 0x1b, 0x2b, 0x18,
+ 0x2f, 0x17, 0x32, 0x16, 0x35, 0x14, 0x38, 0x14, 0x3a, 0x13, 0x3d, 0x13,
+ 0x3f, 0x12, 0x42, 0x12, 0x44, 0x11, 0x46, 0x11, 0x48, 0x11, 0x4a, 0x11,
+ 0x4c, 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e,
+ 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x25, 0x00, 0x1c, 0x00, 0x11,
+ 0x00, 0x07, 0x03, 0x00, 0x0e, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2d, 0x00,
+ 0x36, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xbe, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb4, 0x00, 0xad, 0x00, 0xa5, 0x00,
+ 0x9b, 0x00, 0x91, 0x00, 0x86, 0x00, 0x7b, 0x00, 0x70, 0x00, 0x65, 0x00,
+ 0x5b, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39, 0x46, 0x36, 0x4a, 0x35,
+ 0x4a, 0x32, 0x4e, 0x31, 0x4f, 0x2f, 0x51, 0x2e, 0x53, 0x2e, 0x53, 0x2b,
+ 0x56, 0x2a, 0x57, 0x2a, 0x57, 0x29, 0x59, 0x27, 0x5c, 0x27, 0x5c, 0x27,
+ 0x5c, 0x26, 0x5c, 0x24, 0x5f, 0x23, 0x60, 0x23, 0xdb, 0x00, 0xd8, 0x00,
+ 0xd5, 0x00, 0xd2, 0x00, 0xcf, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xc6, 0x00,
+ 0xc4, 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb9, 0x00,
+ 0xb8, 0x00, 0xb5, 0x00, 0xb4, 0x00, 0xb2, 0x00, 0xb0, 0x00, 0xaf, 0x00,
+ 0x21, 0x20, 0x25, 0x1d, 0x28, 0x1b, 0x2b, 0x19, 0x2e, 0x17, 0x31, 0x16,
+ 0x34, 0x15, 0x37, 0x14, 0x39, 0x13, 0x3b, 0x13, 0x3e, 0x13, 0x40, 0x12,
+ 0x42, 0x12, 0x45, 0x11, 0x46, 0x11, 0x49, 0x11, 0x4a, 0x11, 0x4c, 0x11,
+ 0x4e, 0x11, 0x4f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
+ 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x27, 0x68, 0x32, 0x51, 0x36, 0x4a, 0x38, 0x47,
+ 0x3a, 0x46, 0x3a, 0x45, 0x3b, 0x44, 0x3c, 0x43, 0x3c, 0x43, 0x3c, 0x43,
+ 0x3c, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x41,
+ 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x41, 0x0e, 0x16, 0x27,
+ 0x23, 0x31, 0x2a, 0x35, 0x2e, 0x38, 0x31, 0x39, 0x33, 0x3a, 0x34, 0x3b,
+ 0x35, 0x3b, 0x36, 0x3c, 0x37, 0x3c, 0x38, 0x3c, 0x38, 0x3c, 0x39, 0x3d,
+ 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3b, 0x3d,
+ 0x68, 0x00, 0x32, 0x27, 0x36, 0x31, 0x38, 0x35, 0x3a, 0x38, 0x3a, 0x39,
+ 0x3b, 0x3a, 0x3c, 0x3b, 0x3c, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3c,
+ 0x3d, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
+ 0x3d, 0x3d, 0x3d, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x22, 0x32, 0x28, 0x36, 0x2c, 0x38, 0x2f, 0x3a, 0x32, 0x3a, 0x34, 0x3b,
+ 0x35, 0x3c, 0x36, 0x3c, 0x37, 0x3c, 0x37, 0x3c, 0x38, 0x3d, 0x39, 0x3d,
+ 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
+ 0x3b, 0x3d, 0x3b, 0x3d, 0x00, 0x97, 0x01, 0x67, 0x09, 0x56, 0x11, 0x4f,
+ 0x17, 0x4b, 0x1c, 0x49, 0x20, 0x47, 0x23, 0x46, 0x25, 0x45, 0x28, 0x44,
+ 0x2a, 0x44, 0x2b, 0x43, 0x2c, 0x43, 0x2e, 0x43, 0x2f, 0x42, 0x30, 0x42,
+ 0x31, 0x42, 0x31, 0x42, 0x32, 0x42, 0x33, 0x42, 0x1a, 0x5c, 0x25, 0x4f,
+ 0x2a, 0x4a, 0x2e, 0x48, 0x31, 0x46, 0x33, 0x45, 0x34, 0x44, 0x36, 0x44,
+ 0x37, 0x43, 0x37, 0x43, 0x38, 0x43, 0x38, 0x42, 0x39, 0x42, 0x39, 0x42,
+ 0x39, 0x41, 0x3a, 0x41, 0x3a, 0x41, 0x3a, 0x41, 0x3b, 0x41, 0x3b, 0x41,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x5f,
+ 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x33, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x28, 0x25, 0x2d,
+ 0x28, 0x30, 0x2b, 0x32, 0x2e, 0x34, 0x2f, 0x35, 0x31, 0x36, 0x32, 0x37,
+ 0x33, 0x38, 0x34, 0x38, 0x35, 0x39, 0x36, 0x39, 0x36, 0x39, 0x36, 0x3a,
+ 0x37, 0x3a, 0x37, 0x3a, 0x38, 0x3b, 0x38, 0x3b, 0x39, 0x3b, 0x39, 0x3b,
+ 0x00, 0xb7, 0x00, 0x8b, 0x02, 0x72, 0x07, 0x65, 0x0c, 0x5c, 0x11, 0x57,
+ 0x15, 0x53, 0x18, 0x50, 0x1b, 0x4e, 0x1d, 0x4d, 0x20, 0x4b, 0x22, 0x4a,
+ 0x23, 0x49, 0x25, 0x48, 0x26, 0x48, 0x28, 0x47, 0x29, 0x47, 0x2a, 0x46,
+ 0x2b, 0x46, 0x2c, 0x45, 0x16, 0x6d, 0x1f, 0x5f, 0x24, 0x57, 0x28, 0x53,
+ 0x2b, 0x50, 0x2d, 0x4d, 0x2f, 0x4c, 0x31, 0x4a, 0x32, 0x49, 0x33, 0x48,
+ 0x34, 0x48, 0x35, 0x47, 0x35, 0x46, 0x36, 0x46, 0x36, 0x45, 0x37, 0x45,
+ 0x38, 0x45, 0x38, 0x45, 0x39, 0x44, 0x39, 0x44, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x8b, 0x00, 0x44, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x2e, 0x00,
+ 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x25, 0x23, 0x28, 0x26, 0x2b, 0x28, 0x2e,
+ 0x2a, 0x2f, 0x2c, 0x31, 0x2e, 0x32, 0x2f, 0x33, 0x30, 0x34, 0x31, 0x35,
+ 0x32, 0x36, 0x33, 0x36, 0x33, 0x36, 0x34, 0x37, 0x35, 0x38, 0x36, 0x38,
+ 0x36, 0x39, 0x36, 0x39, 0x36, 0x39, 0x36, 0x39, 0x00, 0xc5, 0x00, 0xa0,
+ 0x00, 0x87, 0x03, 0x76, 0x06, 0x6b, 0x0a, 0x64, 0x0e, 0x5f, 0x11, 0x5b,
+ 0x13, 0x57, 0x16, 0x55, 0x18, 0x53, 0x1a, 0x51, 0x1c, 0x50, 0x1e, 0x4e,
+ 0x20, 0x4d, 0x21, 0x4c, 0x22, 0x4b, 0x24, 0x4a, 0x25, 0x49, 0x26, 0x48,
+ 0x15, 0x72, 0x1b, 0x66, 0x20, 0x5f, 0x24, 0x5a, 0x27, 0x56, 0x29, 0x53,
+ 0x2c, 0x51, 0x2d, 0x50, 0x2f, 0x4e, 0x30, 0x4d, 0x31, 0x4c, 0x32, 0x4b,
+ 0x32, 0x4a, 0x33, 0x49, 0x34, 0x49, 0x35, 0x48, 0x35, 0x48, 0x35, 0x47,
+ 0x35, 0x46, 0x36, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x6d, 0x00, 0x33, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x24, 0x00, 0x11, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x22, 0x24, 0x23, 0x26, 0x25, 0x29, 0x27, 0x2b, 0x28, 0x2c, 0x2a, 0x2e,
+ 0x2c, 0x2f, 0x2d, 0x30, 0x2e, 0x31, 0x2f, 0x32, 0x30, 0x33, 0x30, 0x33,
+ 0x32, 0x34, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36, 0x33, 0x36, 0x34, 0x36,
+ 0x35, 0x36, 0x36, 0x37, 0x00, 0xcb, 0x00, 0xad, 0x00, 0x96, 0x01, 0x84,
+ 0x03, 0x78, 0x06, 0x70, 0x09, 0x69, 0x0b, 0x64, 0x0e, 0x60, 0x10, 0x5d,
+ 0x13, 0x59, 0x15, 0x57, 0x17, 0x56, 0x19, 0x54, 0x1a, 0x52, 0x1c, 0x51,
+ 0x1d, 0x50, 0x1f, 0x4f, 0x1f, 0x4f, 0x21, 0x4e, 0x14, 0x75, 0x19, 0x6b,
+ 0x1e, 0x64, 0x22, 0x5f, 0x24, 0x5b, 0x27, 0x58, 0x29, 0x56, 0x2a, 0x54,
+ 0x2c, 0x52, 0x2d, 0x51, 0x2e, 0x4f, 0x2f, 0x4e, 0x30, 0x4e, 0x31, 0x4d,
+ 0x31, 0x4c, 0x32, 0x4a, 0x33, 0x4a, 0x33, 0x4a, 0x34, 0x4a, 0x35, 0x4a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa,
+ 0x00, 0x85, 0x00, 0x57, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x1d, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x23, 0x23, 0x25,
+ 0x24, 0x27, 0x25, 0x28, 0x27, 0x2a, 0x28, 0x2c, 0x2a, 0x2d, 0x2b, 0x2e,
+ 0x2c, 0x2f, 0x2d, 0x30, 0x2e, 0x31, 0x2f, 0x32, 0x30, 0x32, 0x30, 0x33,
+ 0x31, 0x33, 0x32, 0x33, 0x33, 0x34, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36,
+ 0x00, 0xcf, 0x00, 0xb6, 0x00, 0xa0, 0x00, 0x8f, 0x01, 0x83, 0x03, 0x79,
+ 0x05, 0x72, 0x08, 0x6c, 0x0a, 0x68, 0x0c, 0x64, 0x0f, 0x61, 0x10, 0x5e,
+ 0x12, 0x5b, 0x14, 0x59, 0x16, 0x58, 0x17, 0x56, 0x19, 0x55, 0x1a, 0x53,
+ 0x1b, 0x52, 0x1c, 0x50, 0x13, 0x77, 0x18, 0x6e, 0x1c, 0x68, 0x1f, 0x63,
+ 0x22, 0x5f, 0x24, 0x5c, 0x26, 0x59, 0x28, 0x57, 0x29, 0x56, 0x2a, 0x54,
+ 0x2c, 0x53, 0x2d, 0x52, 0x2e, 0x50, 0x2e, 0x4f, 0x2f, 0x4f, 0x31, 0x4e,
+ 0x31, 0x4d, 0x31, 0x4d, 0x31, 0x4c, 0x32, 0x4a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70,
+ 0x00, 0x48, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3a, 0x00,
+ 0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x23, 0x22, 0x24, 0x24, 0x26, 0x25, 0x27,
+ 0x26, 0x29, 0x27, 0x2a, 0x28, 0x2b, 0x2a, 0x2d, 0x2a, 0x2d, 0x2c, 0x2e,
+ 0x2d, 0x30, 0x2d, 0x30, 0x2e, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33,
+ 0x30, 0x33, 0x31, 0x33, 0x32, 0x33, 0x33, 0x34, 0x00, 0xd1, 0x00, 0xbc,
+ 0x00, 0xa9, 0x00, 0x99, 0x00, 0x8c, 0x02, 0x82, 0x03, 0x7a, 0x05, 0x74,
+ 0x07, 0x6f, 0x09, 0x6b, 0x0b, 0x67, 0x0d, 0x63, 0x0f, 0x61, 0x10, 0x5f,
+ 0x12, 0x5c, 0x14, 0x5a, 0x15, 0x58, 0x16, 0x58, 0x18, 0x57, 0x19, 0x56,
+ 0x13, 0x78, 0x17, 0x70, 0x1b, 0x6a, 0x1e, 0x66, 0x20, 0x62, 0x22, 0x5f,
+ 0x24, 0x5c, 0x26, 0x5b, 0x27, 0x58, 0x29, 0x57, 0x2a, 0x56, 0x2b, 0x53,
+ 0x2c, 0x53, 0x2d, 0x52, 0x2e, 0x51, 0x2e, 0x50, 0x2f, 0x4f, 0x30, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbb, 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d,
+ 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00,
+ 0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x22, 0x22, 0x22, 0x24, 0x23, 0x25, 0x24, 0x27, 0x25, 0x27, 0x27, 0x28,
+ 0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2e,
+ 0x2d, 0x30, 0x2d, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x33,
+ 0x30, 0x33, 0x31, 0x33, 0x00, 0xd3, 0x00, 0xc1, 0x00, 0xaf, 0x00, 0xa1,
+ 0x00, 0x94, 0x00, 0x8a, 0x02, 0x82, 0x03, 0x7b, 0x05, 0x76, 0x07, 0x71,
+ 0x09, 0x6d, 0x0a, 0x69, 0x0c, 0x66, 0x0e, 0x63, 0x0f, 0x61, 0x10, 0x60,
+ 0x12, 0x5d, 0x13, 0x5c, 0x14, 0x59, 0x16, 0x58, 0x13, 0x79, 0x16, 0x72,
+ 0x19, 0x6d, 0x1c, 0x69, 0x1f, 0x65, 0x20, 0x61, 0x23, 0x60, 0x24, 0x5c,
+ 0x26, 0x5b, 0x27, 0x59, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2b, 0x53,
+ 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2e, 0x51, 0x2e, 0x4f, 0x2f, 0x4f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb6,
+ 0x00, 0xa6, 0x00, 0x8e, 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x25, 0x00, 0x1b, 0x00,
+ 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x23,
+ 0x23, 0x24, 0x24, 0x25, 0x25, 0x27, 0x26, 0x28, 0x26, 0x28, 0x28, 0x2a,
+ 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2d, 0x2a, 0x2d, 0x2c, 0x2d, 0x2d, 0x2e,
+ 0x2d, 0x30, 0x2d, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x32,
+ 0x00, 0xd4, 0x00, 0xc4, 0x00, 0xb5, 0x00, 0xa7, 0x00, 0x9b, 0x00, 0x91,
+ 0x01, 0x88, 0x02, 0x82, 0x03, 0x7b, 0x05, 0x77, 0x07, 0x73, 0x08, 0x6e,
+ 0x0a, 0x6b, 0x0b, 0x69, 0x0c, 0x66, 0x0e, 0x63, 0x0f, 0x61, 0x10, 0x60,
+ 0x12, 0x5f, 0x13, 0x5c, 0x12, 0x79, 0x15, 0x73, 0x18, 0x6e, 0x1b, 0x6a,
+ 0x1d, 0x67, 0x20, 0x65, 0x21, 0x61, 0x23, 0x60, 0x24, 0x5d, 0x26, 0x5c,
+ 0x27, 0x5a, 0x27, 0x58, 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2b, 0x53,
+ 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x51, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97,
+ 0x00, 0x7e, 0x00, 0x64, 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00,
+ 0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25,
+ 0x24, 0x26, 0x25, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x2a, 0x28, 0x2b,
+ 0x2a, 0x2b, 0x2b, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2f,
+ 0x2d, 0x30, 0x2d, 0x30, 0x2f, 0x30, 0x30, 0x30, 0x00, 0xd5, 0x00, 0xc7,
+ 0x00, 0xb9, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8f, 0x01, 0x87,
+ 0x02, 0x82, 0x03, 0x7b, 0x05, 0x77, 0x06, 0x74, 0x08, 0x6f, 0x09, 0x6c,
+ 0x0b, 0x6b, 0x0c, 0x68, 0x0d, 0x65, 0x0e, 0x63, 0x0f, 0x62, 0x10, 0x60,
+ 0x12, 0x7a, 0x15, 0x75, 0x18, 0x70, 0x1a, 0x6c, 0x1d, 0x69, 0x1e, 0x65,
+ 0x20, 0x64, 0x21, 0x61, 0x23, 0x60, 0x24, 0x5d, 0x26, 0x5c, 0x27, 0x5b,
+ 0x27, 0x58, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2b, 0x53,
+ 0x2c, 0x53, 0x2e, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71,
+ 0x00, 0x59, 0x00, 0x41, 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x34, 0x00,
+ 0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x06, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x23, 0x24, 0x24, 0x25, 0x25, 0x27,
+ 0x25, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x29, 0x2b,
+ 0x2b, 0x2b, 0x2b, 0x2d, 0x2b, 0x2d, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2f,
+ 0x2d, 0x30, 0x2d, 0x30, 0x00, 0xd6, 0x00, 0xc9, 0x00, 0xbc, 0x00, 0xb1,
+ 0x00, 0xa6, 0x00, 0x9c, 0x00, 0x94, 0x00, 0x8c, 0x02, 0x86, 0x02, 0x81,
+ 0x03, 0x7c, 0x05, 0x78, 0x06, 0x75, 0x07, 0x71, 0x09, 0x6d, 0x0a, 0x6c,
+ 0x0b, 0x6a, 0x0c, 0x67, 0x0d, 0x65, 0x0e, 0x62, 0x12, 0x7b, 0x15, 0x76,
+ 0x18, 0x72, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d, 0x68, 0x1f, 0x65, 0x20, 0x63,
+ 0x22, 0x60, 0x23, 0x60, 0x23, 0x5d, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5a,
+ 0x28, 0x57, 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x2a, 0x55, 0x2b, 0x53,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba,
+ 0x00, 0xb1, 0x00, 0xa3, 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50,
+ 0x00, 0x3a, 0x00, 0x25, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29, 0x00,
+ 0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x21, 0x22, 0x22, 0x23,
+ 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x27, 0x26, 0x27,
+ 0x27, 0x28, 0x27, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b,
+ 0x2b, 0x2c, 0x2b, 0x2d, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2f,
+ 0x00, 0xd6, 0x00, 0xcb, 0x00, 0xbf, 0x00, 0xb4, 0x00, 0xab, 0x00, 0xa1,
+ 0x00, 0x99, 0x00, 0x91, 0x01, 0x8b, 0x02, 0x85, 0x02, 0x81, 0x04, 0x7c,
+ 0x05, 0x78, 0x06, 0x76, 0x07, 0x73, 0x08, 0x6f, 0x09, 0x6c, 0x0b, 0x6b,
+ 0x0c, 0x6a, 0x0c, 0x67, 0x12, 0x7b, 0x15, 0x76, 0x17, 0x72, 0x19, 0x6e,
+ 0x1a, 0x6c, 0x1d, 0x69, 0x1d, 0x66, 0x20, 0x65, 0x20, 0x62, 0x22, 0x60,
+ 0x23, 0x60, 0x23, 0x5d, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5b, 0x27, 0x58,
+ 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7,
+ 0x00, 0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35,
+ 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
+ 0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x26, 0x00, 0x1f, 0x00,
+ 0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
+ 0x24, 0x25, 0x24, 0x25, 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x28,
+ 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c,
+ 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x00, 0xd7, 0x00, 0xcc,
+ 0x00, 0xc2, 0x00, 0xb8, 0x00, 0xae, 0x00, 0xa5, 0x00, 0x9e, 0x00, 0x95,
+ 0x00, 0x90, 0x01, 0x8a, 0x02, 0x85, 0x03, 0x81, 0x04, 0x7c, 0x05, 0x78,
+ 0x06, 0x76, 0x07, 0x74, 0x08, 0x70, 0x09, 0x6d, 0x0a, 0x6c, 0x0b, 0x6a,
+ 0x12, 0x7b, 0x14, 0x77, 0x16, 0x73, 0x18, 0x70, 0x1a, 0x6d, 0x1c, 0x6a,
+ 0x1d, 0x69, 0x1e, 0x65, 0x20, 0x65, 0x20, 0x62, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x5d, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x59, 0x28, 0x57,
+ 0x2a, 0x57, 0x2a, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d,
+ 0x00, 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f,
+ 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00,
+ 0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1c, 0x00, 0x16, 0x00,
+ 0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x23, 0x24, 0x24, 0x25,
+ 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x28, 0x26, 0x28, 0x28, 0x28,
+ 0x28, 0x29, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2d,
+ 0x2b, 0x2d, 0x2c, 0x2d, 0x00, 0xd7, 0x00, 0xcd, 0x00, 0xc4, 0x00, 0xbb,
+ 0x00, 0xb1, 0x00, 0xa9, 0x00, 0xa1, 0x00, 0x9a, 0x00, 0x93, 0x00, 0x8e,
+ 0x01, 0x88, 0x02, 0x84, 0x03, 0x81, 0x04, 0x7c, 0x05, 0x79, 0x06, 0x77,
+ 0x07, 0x75, 0x07, 0x72, 0x09, 0x6e, 0x09, 0x6d, 0x12, 0x7b, 0x14, 0x77,
+ 0x15, 0x73, 0x18, 0x71, 0x1a, 0x6d, 0x1a, 0x6b, 0x1d, 0x69, 0x1d, 0x67,
+ 0x1f, 0x65, 0x20, 0x65, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5e,
+ 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5a, 0x27, 0x58, 0x29, 0x57,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc,
+ 0x00, 0xb6, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72,
+ 0x00, 0x60, 0x00, 0x4f, 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39, 0x00, 0x35, 0x00, 0x31, 0x00,
+ 0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0f, 0x00,
+ 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x26,
+ 0x25, 0x27, 0x27, 0x27, 0x27, 0x28, 0x26, 0x28, 0x28, 0x28, 0x28, 0x29,
+ 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2b, 0x2d,
+ 0x00, 0xd8, 0x00, 0xcf, 0x00, 0xc6, 0x00, 0xbd, 0x00, 0xb4, 0x00, 0xad,
+ 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x97, 0x00, 0x92, 0x01, 0x8d, 0x02, 0x88,
+ 0x02, 0x84, 0x03, 0x81, 0x04, 0x7d, 0x05, 0x79, 0x06, 0x77, 0x07, 0x75,
+ 0x07, 0x73, 0x09, 0x70, 0x12, 0x7c, 0x13, 0x78, 0x15, 0x75, 0x18, 0x72,
+ 0x19, 0x6e, 0x1a, 0x6d, 0x1c, 0x69, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65,
+ 0x20, 0x64, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5e, 0x25, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5b, 0x27, 0x59, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf,
+ 0x00, 0xa5, 0x00, 0x98, 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59,
+ 0x00, 0x49, 0x00, 0x39, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
+ 0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x28, 0x00,
+ 0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x09, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
+ 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x25, 0x27,
+ 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b,
+ 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x00, 0xd8, 0x00, 0xd0,
+ 0x00, 0xc7, 0x00, 0xbe, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa8, 0x00, 0xa1,
+ 0x00, 0x9b, 0x00, 0x95, 0x00, 0x90, 0x01, 0x8c, 0x02, 0x87, 0x02, 0x84,
+ 0x03, 0x81, 0x04, 0x7d, 0x05, 0x79, 0x06, 0x77, 0x06, 0x76, 0x07, 0x74,
+ 0x11, 0x7c, 0x13, 0x78, 0x15, 0x76, 0x17, 0x72, 0x18, 0x6f, 0x1a, 0x6d,
+ 0x1b, 0x6a, 0x1d, 0x69, 0x1d, 0x68, 0x1f, 0x65, 0x20, 0x65, 0x20, 0x64,
+ 0x22, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5e, 0x25, 0x5c, 0x27, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5c, 0x00, 0x2f, 0x00, 0x5f, 0x00, 0x99, 0x00, 0xac,
+ 0x00, 0xb3, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc,
+ 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe,
+ 0x00, 0x9a, 0x00, 0x6d, 0x00, 0x8d, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0xb2,
+ 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd,
+ 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0b, 0x3b, 0x00, 0x6f, 0x00, 0x9f, 0x00, 0xaf,
+ 0x00, 0xb5, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd,
+ 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe,
+ 0x07, 0x47, 0x00, 0x7f, 0x00, 0xa5, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xba,
+ 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe,
+ 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x23, 0x24,
+ 0x24, 0x25, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x27,
+ 0x27, 0x29, 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x29, 0x2b,
+ 0x2b, 0x2b, 0x2b, 0x2b, 0x00, 0xd8, 0x00, 0xd1, 0x00, 0xc9, 0x00, 0xc0,
+ 0x00, 0xba, 0x00, 0xb1, 0x00, 0xac, 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x98,
+ 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8b, 0x02, 0x86, 0x02, 0x83, 0x03, 0x81,
+ 0x04, 0x7d, 0x05, 0x79, 0x06, 0x78, 0x06, 0x76, 0x11, 0x7c, 0x13, 0x79,
+ 0x15, 0x76, 0x17, 0x72, 0x18, 0x71, 0x1a, 0x6d, 0x1a, 0x6d, 0x1c, 0x69,
+ 0x1d, 0x69, 0x1d, 0x66, 0x20, 0x65, 0x20, 0x65, 0x20, 0x63, 0x22, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x5f, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5c,
+ 0x00, 0x00, 0x00, 0x0f, 0x00, 0x5f, 0x00, 0x8b, 0x00, 0x9f, 0x00, 0xaa,
+ 0x00, 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba,
+ 0x00, 0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x6d, 0x00, 0x54,
+ 0x00, 0x6b, 0x00, 0x87, 0x00, 0x98, 0x00, 0xa6, 0x00, 0xb0, 0x00, 0xb3,
+ 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbb,
+ 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x17, 0x07, 0x02, 0x27, 0x00, 0x6f, 0x00, 0x93, 0x00, 0xa4, 0x00, 0xad,
+ 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb,
+ 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x0f, 0x0f, 0x00, 0x3f,
+ 0x00, 0x7f, 0x00, 0x9c, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb5, 0x00, 0xb7,
+ 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd,
+ 0x00, 0xbd, 0x00, 0xbd, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25,
+ 0x25, 0x25, 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28,
+ 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b, 0x2a, 0x2b,
+ 0x00, 0xd9, 0x00, 0xd2, 0x00, 0xc9, 0x00, 0xc2, 0x00, 0xbb, 0x00, 0xb4,
+ 0x00, 0xae, 0x00, 0xa7, 0x00, 0xa1, 0x00, 0x9d, 0x00, 0x96, 0x00, 0x92,
+ 0x01, 0x8e, 0x01, 0x89, 0x02, 0x86, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7e,
+ 0x05, 0x7a, 0x06, 0x78, 0x11, 0x7c, 0x13, 0x79, 0x15, 0x76, 0x16, 0x73,
+ 0x18, 0x72, 0x19, 0x6e, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d, 0x69, 0x1d, 0x69,
+ 0x1e, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0x62, 0x22, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x5f, 0x24, 0x5c, 0x26, 0x5c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x44, 0x00, 0x6d, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f,
+ 0x00, 0xa6, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5,
+ 0x00, 0xb6, 0x00, 0xb7, 0x00, 0x8d, 0x00, 0x6b, 0x00, 0x28, 0x00, 0x52,
+ 0x00, 0x70, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f, 0x00, 0xa6, 0x00, 0xab,
+ 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x12, 0x02,
+ 0x00, 0x22, 0x00, 0x58, 0x00, 0x7a, 0x00, 0x8f, 0x00, 0x9c, 0x00, 0xa4,
+ 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb7,
+ 0x00, 0xb8, 0x00, 0xb9, 0x26, 0x00, 0x05, 0x05, 0x00, 0x3f, 0x00, 0x6d,
+ 0x00, 0x88, 0x00, 0x99, 0x00, 0xa3, 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1,
+ 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23,
+ 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x25,
+ 0x25, 0x27, 0x26, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b, 0x00, 0xd9, 0x00, 0xd2,
+ 0x00, 0xca, 0x00, 0xc4, 0x00, 0xbd, 0x00, 0xb6, 0x00, 0xb0, 0x00, 0xaa,
+ 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x94, 0x00, 0x91, 0x01, 0x8e,
+ 0x02, 0x89, 0x02, 0x85, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7e, 0x05, 0x7a,
+ 0x11, 0x7c, 0x13, 0x7a, 0x15, 0x76, 0x15, 0x74, 0x18, 0x72, 0x18, 0x6f,
+ 0x1a, 0x6d, 0x1a, 0x6c, 0x1c, 0x69, 0x1d, 0x69, 0x1d, 0x67, 0x1f, 0x65,
+ 0x20, 0x65, 0x20, 0x65, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x5f, 0x24, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x33, 0x00, 0x57, 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97,
+ 0x00, 0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf,
+ 0x00, 0x9b, 0x00, 0x87, 0x00, 0x52, 0x00, 0x11, 0x00, 0x39, 0x00, 0x57,
+ 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97, 0x00, 0x9e, 0x00, 0xa3,
+ 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x25, 0x00, 0x0b, 0x09, 0x00, 0x21,
+ 0x00, 0x4a, 0x00, 0x68, 0x00, 0x7d, 0x00, 0x8b, 0x00, 0x96, 0x00, 0x9d,
+ 0x00, 0xa3, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2,
+ 0x33, 0x00, 0x1c, 0x00, 0x00, 0x12, 0x00, 0x3f, 0x00, 0x62, 0x00, 0x7a,
+ 0x00, 0x8a, 0x00, 0x96, 0x00, 0x9e, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xac,
+ 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24,
+ 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x25, 0x27,
+ 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x2a, 0x00, 0xd9, 0x00, 0xd2, 0x00, 0xcb, 0x00, 0xc6,
+ 0x00, 0xbe, 0x00, 0xb9, 0x00, 0xb1, 0x00, 0xac, 0x00, 0xa6, 0x00, 0xa1,
+ 0x00, 0x9d, 0x00, 0x97, 0x00, 0x93, 0x00, 0x90, 0x01, 0x8d, 0x02, 0x88,
+ 0x02, 0x85, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7e, 0x11, 0x7c, 0x13, 0x7a,
+ 0x15, 0x76, 0x15, 0x75, 0x18, 0x72, 0x18, 0x71, 0x1a, 0x6d, 0x1a, 0x6d,
+ 0x1b, 0x6a, 0x1d, 0x69, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65, 0x20, 0x65,
+ 0x20, 0x64, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x28,
+ 0x00, 0x48, 0x00, 0x5f, 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91,
+ 0x00, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0x98,
+ 0x00, 0x70, 0x00, 0x39, 0x00, 0x02, 0x00, 0x28, 0x00, 0x48, 0x00, 0x5f,
+ 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91, 0x00, 0x98, 0x00, 0x9d,
+ 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3a, 0x00, 0x2f, 0x00, 0x16, 0x00, 0x08, 0x0e, 0x00, 0x20, 0x00, 0x42,
+ 0x00, 0x5c, 0x00, 0x6f, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x92, 0x00, 0x99,
+ 0x00, 0x9e, 0x00, 0xa2, 0x00, 0xa6, 0x00, 0xa9, 0x38, 0x00, 0x2a, 0x00,
+ 0x09, 0x00, 0x00, 0x1d, 0x00, 0x3f, 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7f,
+ 0x00, 0x8b, 0x00, 0x94, 0x00, 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8,
+ 0x00, 0xab, 0x00, 0xad, 0x16, 0xa4, 0x01, 0xbb, 0x00, 0xc6, 0x00, 0xcc,
+ 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6,
+ 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd9,
+ 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xda, 0x05, 0x9d, 0x00, 0xbc,
+ 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd5,
+ 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xd8,
+ 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x02, 0xbd, 0x00, 0xcc, 0x00, 0xd1, 0x00, 0xd5,
+ 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9,
+ 0x00, 0xd9, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00, 0xdb,
+ 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x3d,
+ 0x00, 0x52, 0x00, 0x64, 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d,
+ 0x00, 0x93, 0x00, 0x98, 0x00, 0xb2, 0x00, 0xa6, 0x00, 0x85, 0x00, 0x57,
+ 0x00, 0x28, 0x00, 0x01, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x52, 0x00, 0x64,
+ 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d, 0x00, 0x93, 0x00, 0x98,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00,
+ 0x23, 0x00, 0x0e, 0x02, 0x06, 0x12, 0x00, 0x20, 0x00, 0x3c, 0x00, 0x52,
+ 0x00, 0x64, 0x00, 0x73, 0x00, 0x7e, 0x00, 0x87, 0x00, 0x8f, 0x00, 0x95,
+ 0x00, 0x9a, 0x00, 0x9e, 0x3a, 0x00, 0x31, 0x00, 0x19, 0x00, 0x00, 0x05,
+ 0x00, 0x24, 0x00, 0x3f, 0x00, 0x56, 0x00, 0x68, 0x00, 0x77, 0x00, 0x82,
+ 0x00, 0x8b, 0x00, 0x93, 0x00, 0x99, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5,
+ 0x23, 0x74, 0x09, 0x91, 0x02, 0xa3, 0x00, 0xaf, 0x00, 0xb7, 0x00, 0xbd,
+ 0x00, 0xc2, 0x00, 0xc5, 0x00, 0xc7, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc,
+ 0x00, 0xce, 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd2,
+ 0x00, 0xd2, 0x00, 0xd3, 0x0d, 0x6b, 0x01, 0x8e, 0x00, 0xa4, 0x00, 0xb0,
+ 0x00, 0xb9, 0x00, 0xbe, 0x00, 0xc2, 0x00, 0xc5, 0x00, 0xc8, 0x00, 0xca,
+ 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1,
+ 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x06, 0xa4, 0x00, 0xb5, 0x00, 0xc0, 0x00, 0xc6, 0x00, 0xcb, 0x00, 0xcd,
+ 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd4,
+ 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xd7,
+ 0x00, 0xd8, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48,
+ 0x00, 0x59, 0x00, 0x66, 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89,
+ 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70, 0x00, 0x48, 0x00, 0x21,
+ 0x00, 0x01, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48, 0x00, 0x59, 0x00, 0x66,
+ 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x18, 0x00,
+ 0x0c, 0x07, 0x05, 0x14, 0x00, 0x20, 0x00, 0x37, 0x00, 0x4c, 0x00, 0x5c,
+ 0x00, 0x6a, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x86, 0x00, 0x8d, 0x00, 0x92,
+ 0x3c, 0x00, 0x35, 0x00, 0x23, 0x00, 0x0b, 0x00, 0x00, 0x0f, 0x00, 0x29,
+ 0x00, 0x3f, 0x00, 0x53, 0x00, 0x63, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x84,
+ 0x00, 0x8b, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9b, 0x2a, 0x61, 0x11, 0x78,
+ 0x07, 0x8a, 0x03, 0x98, 0x01, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb6,
+ 0x00, 0xba, 0x00, 0xbd, 0x00, 0xc0, 0x00, 0xc2, 0x00, 0xc5, 0x00, 0xc6,
+ 0x00, 0xc7, 0x00, 0xc9, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc,
+ 0x12, 0x51, 0x04, 0x73, 0x00, 0x89, 0x00, 0x9a, 0x00, 0xa4, 0x00, 0xad,
+ 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbb, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc3,
+ 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb,
+ 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x09, 0x97, 0x02, 0xa8,
+ 0x00, 0xb3, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc5, 0x00, 0xc7, 0x00, 0xca,
+ 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd1,
+ 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd5,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50,
+ 0x00, 0x5d, 0x00, 0x68, 0x00, 0x72, 0x00, 0x7a, 0x00, 0xbb, 0x00, 0xb3,
+ 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d, 0x00, 0x1c, 0x00, 0x00,
+ 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50, 0x00, 0x5d, 0x00, 0x68,
+ 0x00, 0x72, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x20, 0x00, 0x10, 0x00, 0x0a, 0x0b,
+ 0x04, 0x16, 0x00, 0x20, 0x00, 0x34, 0x00, 0x46, 0x00, 0x56, 0x00, 0x62,
+ 0x00, 0x6d, 0x00, 0x77, 0x00, 0x7f, 0x00, 0x85, 0x3d, 0x00, 0x38, 0x00,
+ 0x2a, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x2c, 0x00, 0x3f,
+ 0x00, 0x50, 0x00, 0x5e, 0x00, 0x6b, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x85,
+ 0x00, 0x8b, 0x00, 0x91, 0x2e, 0x59, 0x17, 0x6b, 0x0c, 0x7a, 0x06, 0x87,
+ 0x03, 0x92, 0x01, 0x9b, 0x00, 0xa2, 0x00, 0xa8, 0x00, 0xad, 0x00, 0xb1,
+ 0x00, 0xb5, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc1,
+ 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc6, 0x00, 0xc7, 0x15, 0x45, 0x08, 0x60,
+ 0x02, 0x77, 0x00, 0x87, 0x00, 0x94, 0x00, 0x9d, 0x00, 0xa4, 0x00, 0xaa,
+ 0x00, 0xaf, 0x00, 0xb3, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbc, 0x00, 0xbe,
+ 0x00, 0xc0, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc6, 0x00, 0xc7,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x0a, 0x91, 0x04, 0x9e, 0x01, 0xaa, 0x00, 0xb2,
+ 0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc6, 0x00, 0xc8,
+ 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf,
+ 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x16, 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55,
+ 0x00, 0x60, 0x00, 0x6a, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xa6, 0x00, 0x8e,
+ 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19, 0x00, 0x00, 0x00, 0x16,
+ 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55, 0x00, 0x60, 0x00, 0x6a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3b, 0x00,
+ 0x33, 0x00, 0x27, 0x00, 0x18, 0x00, 0x0d, 0x04, 0x08, 0x0e, 0x04, 0x17,
+ 0x00, 0x20, 0x00, 0x32, 0x00, 0x42, 0x00, 0x50, 0x00, 0x5c, 0x00, 0x67,
+ 0x00, 0x70, 0x00, 0x78, 0x3d, 0x00, 0x39, 0x00, 0x2f, 0x00, 0x1f, 0x00,
+ 0x0b, 0x00, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x2e, 0x00, 0x3f, 0x00, 0x4e,
+ 0x00, 0x5b, 0x00, 0x66, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x86,
+ 0x31, 0x53, 0x1c, 0x62, 0x11, 0x70, 0x0a, 0x7b, 0x06, 0x85, 0x03, 0x8e,
+ 0x02, 0x96, 0x00, 0x9c, 0x00, 0xa2, 0x00, 0xa7, 0x00, 0xab, 0x00, 0xae,
+ 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbd,
+ 0x00, 0xbe, 0x00, 0xbf, 0x17, 0x3d, 0x0b, 0x55, 0x04, 0x67, 0x01, 0x78,
+ 0x00, 0x85, 0x00, 0x90, 0x00, 0x98, 0x00, 0x9f, 0x00, 0xa5, 0x00, 0xaa,
+ 0x00, 0xad, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb9, 0x00, 0xbb,
+ 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x0b, 0x8d, 0x05, 0x99, 0x02, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb6,
+ 0x00, 0xba, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc3, 0x00, 0xc5, 0x00, 0xc7,
+ 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcd,
+ 0x00, 0xce, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x13, 0x00, 0x25, 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59,
+ 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97, 0x00, 0x7e, 0x00, 0x64,
+ 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x25,
+ 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00,
+ 0x1f, 0x00, 0x12, 0x00, 0x0c, 0x07, 0x07, 0x10, 0x03, 0x18, 0x00, 0x20,
+ 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4c, 0x00, 0x57, 0x00, 0x61, 0x00, 0x6a,
+ 0x3e, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x25, 0x00, 0x14, 0x00, 0x02, 0x00,
+ 0x00, 0x0f, 0x00, 0x20, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4d, 0x00, 0x58,
+ 0x00, 0x63, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x7b, 0x33, 0x50, 0x20, 0x5c,
+ 0x15, 0x68, 0x0e, 0x72, 0x09, 0x7c, 0x05, 0x84, 0x03, 0x8c, 0x02, 0x92,
+ 0x01, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xad,
+ 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xba,
+ 0x18, 0x38, 0x0d, 0x4c, 0x06, 0x5e, 0x03, 0x6c, 0x01, 0x7a, 0x00, 0x84,
+ 0x00, 0x8d, 0x00, 0x95, 0x00, 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8,
+ 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8,
+ 0x00, 0xba, 0x00, 0xbc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0c, 0x8a, 0x06, 0x94,
+ 0x03, 0x9d, 0x01, 0xa4, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb5, 0x00, 0xb9,
+ 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xc6,
+ 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
+ 0x00, 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x49, 0x00, 0xbd, 0x00, 0xb9,
+ 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71, 0x00, 0x59, 0x00, 0x41,
+ 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x22, 0x00, 0x30,
+ 0x00, 0x3d, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x19, 0x00,
+ 0x0e, 0x02, 0x0a, 0x0a, 0x06, 0x11, 0x03, 0x19, 0x00, 0x1f, 0x00, 0x2e,
+ 0x00, 0x3c, 0x00, 0x48, 0x00, 0x53, 0x00, 0x5c, 0x3e, 0x00, 0x3c, 0x00,
+ 0x34, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0c, 0x00, 0x00, 0x04, 0x00, 0x14,
+ 0x00, 0x23, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x56, 0x00, 0x60,
+ 0x00, 0x68, 0x00, 0x70, 0x34, 0x4e, 0x23, 0x58, 0x18, 0x62, 0x10, 0x6c,
+ 0x0b, 0x75, 0x08, 0x7c, 0x05, 0x83, 0x03, 0x8a, 0x02, 0x8f, 0x01, 0x95,
+ 0x00, 0x9a, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa9, 0x00, 0xac,
+ 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb5, 0x1a, 0x35, 0x0f, 0x47,
+ 0x08, 0x55, 0x04, 0x64, 0x02, 0x70, 0x00, 0x7a, 0x00, 0x83, 0x00, 0x8b,
+ 0x00, 0x92, 0x00, 0x98, 0x00, 0x9d, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8,
+ 0x00, 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0xb7,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x0d, 0x89, 0x07, 0x92, 0x04, 0x99, 0x02, 0xa0,
+ 0x01, 0xa6, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb4, 0x00, 0xb7, 0x00, 0xba,
+ 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xc5,
+ 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xca, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
+ 0x00, 0x2d, 0x00, 0x39, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa3,
+ 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50, 0x00, 0x3a, 0x00, 0x25,
+ 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x39,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00,
+ 0x38, 0x00, 0x31, 0x00, 0x28, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x0d, 0x05,
+ 0x09, 0x0c, 0x06, 0x13, 0x03, 0x19, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x3a,
+ 0x00, 0x45, 0x00, 0x4f, 0x3e, 0x00, 0x3c, 0x00, 0x36, 0x00, 0x2d, 0x00,
+ 0x21, 0x00, 0x13, 0x00, 0x04, 0x00, 0x00, 0x0a, 0x00, 0x18, 0x00, 0x26,
+ 0x00, 0x33, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x65,
+ 0x35, 0x4c, 0x26, 0x55, 0x1b, 0x5e, 0x13, 0x67, 0x0e, 0x6f, 0x0a, 0x76,
+ 0x07, 0x7d, 0x05, 0x82, 0x03, 0x88, 0x02, 0x8e, 0x02, 0x92, 0x01, 0x97,
+ 0x00, 0x9b, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab,
+ 0x00, 0xac, 0x00, 0xaf, 0x1b, 0x33, 0x10, 0x42, 0x0a, 0x50, 0x05, 0x5c,
+ 0x03, 0x68, 0x01, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x8a, 0x00, 0x90,
+ 0x00, 0x96, 0x00, 0x99, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa8,
+ 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x0d, 0x88, 0x08, 0x8f, 0x05, 0x96, 0x02, 0x9c, 0x01, 0xa2, 0x00, 0xa7,
+ 0x00, 0xac, 0x00, 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb9, 0x00, 0xbb,
+ 0x00, 0xbd, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc5,
+ 0x00, 0xc6, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29,
+ 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7, 0x00, 0x98, 0x00, 0x85,
+ 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35, 0x00, 0x22, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x33, 0x00,
+ 0x2c, 0x00, 0x23, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x0c, 0x07, 0x08, 0x0e,
+ 0x05, 0x14, 0x02, 0x1a, 0x00, 0x1f, 0x00, 0x2c, 0x00, 0x38, 0x00, 0x42,
+ 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x30, 0x00, 0x25, 0x00, 0x19, 0x00,
+ 0x0c, 0x00, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x34,
+ 0x00, 0x3f, 0x00, 0x49, 0x00, 0x53, 0x00, 0x5b, 0x36, 0x4a, 0x28, 0x52,
+ 0x1d, 0x5b, 0x16, 0x63, 0x10, 0x6a, 0x0c, 0x71, 0x09, 0x77, 0x07, 0x7d,
+ 0x05, 0x82, 0x03, 0x87, 0x02, 0x8c, 0x02, 0x90, 0x01, 0x94, 0x00, 0x99,
+ 0x00, 0x9c, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa4, 0x00, 0xa7, 0x00, 0xaa,
+ 0x1b, 0x30, 0x12, 0x3e, 0x0c, 0x4b, 0x07, 0x57, 0x04, 0x61, 0x02, 0x6b,
+ 0x01, 0x73, 0x00, 0x7c, 0x00, 0x82, 0x00, 0x88, 0x00, 0x8f, 0x00, 0x93,
+ 0x00, 0x97, 0x00, 0x9c, 0x00, 0x9f, 0x00, 0xa2, 0x00, 0xa5, 0x00, 0xa8,
+ 0x00, 0xaa, 0x00, 0xac, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0d, 0x86, 0x09, 0x8d,
+ 0x06, 0x94, 0x03, 0x9a, 0x02, 0x9f, 0x01, 0xa4, 0x00, 0xa8, 0x00, 0xac,
+ 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbc,
+ 0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0xbe, 0x00, 0xbb,
+ 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d, 0x00, 0x7b, 0x00, 0x68,
+ 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x26, 0x00,
+ 0x1d, 0x00, 0x14, 0x00, 0x0e, 0x03, 0x0b, 0x09, 0x08, 0x0f, 0x05, 0x15,
+ 0x02, 0x1a, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x3f, 0x00, 0x3d, 0x00,
+ 0x39, 0x00, 0x32, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x06, 0x00,
+ 0x00, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x3f,
+ 0x00, 0x49, 0x00, 0x51, 0x37, 0x49, 0x2a, 0x51, 0x20, 0x58, 0x18, 0x5f,
+ 0x13, 0x66, 0x0f, 0x6c, 0x0b, 0x73, 0x09, 0x78, 0x07, 0x7e, 0x05, 0x82,
+ 0x03, 0x86, 0x02, 0x8b, 0x02, 0x8f, 0x01, 0x92, 0x01, 0x96, 0x00, 0x9a,
+ 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa4, 0x1c, 0x2f, 0x13, 0x3b,
+ 0x0d, 0x47, 0x09, 0x51, 0x05, 0x5c, 0x04, 0x65, 0x02, 0x6e, 0x01, 0x75,
+ 0x00, 0x7c, 0x00, 0x82, 0x00, 0x88, 0x00, 0x8d, 0x00, 0x91, 0x00, 0x96,
+ 0x00, 0x99, 0x00, 0x9c, 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa5, 0x00, 0xa7,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x0e, 0x86, 0x09, 0x8c, 0x06, 0x92, 0x04, 0x97,
+ 0x02, 0x9c, 0x02, 0xa1, 0x01, 0xa5, 0x00, 0xa9, 0x00, 0xac, 0x00, 0xaf,
+ 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc,
+ 0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0d, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xad,
+ 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72, 0x00, 0x60, 0x00, 0x4f,
+ 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
+ 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00,
+ 0x10, 0x00, 0x0d, 0x05, 0x0a, 0x0b, 0x07, 0x10, 0x04, 0x16, 0x02, 0x1b,
+ 0x00, 0x1f, 0x00, 0x2a, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x33, 0x00,
+ 0x2b, 0x00, 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0b,
+ 0x00, 0x16, 0x00, 0x21, 0x00, 0x2c, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48,
+ 0x38, 0x48, 0x2b, 0x4f, 0x22, 0x56, 0x1a, 0x5c, 0x15, 0x63, 0x11, 0x69,
+ 0x0d, 0x6e, 0x0a, 0x74, 0x08, 0x78, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x85,
+ 0x03, 0x8a, 0x02, 0x8e, 0x02, 0x90, 0x01, 0x93, 0x00, 0x98, 0x00, 0x9b,
+ 0x00, 0x9d, 0x00, 0x9f, 0x1c, 0x2d, 0x14, 0x39, 0x0e, 0x44, 0x0a, 0x4e,
+ 0x07, 0x57, 0x04, 0x60, 0x02, 0x67, 0x01, 0x6f, 0x00, 0x76, 0x00, 0x7d,
+ 0x00, 0x81, 0x00, 0x87, 0x00, 0x8c, 0x00, 0x90, 0x00, 0x94, 0x00, 0x97,
+ 0x00, 0x9a, 0x00, 0x9d, 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x0e, 0x85, 0x0a, 0x8b, 0x07, 0x90, 0x05, 0x95, 0x03, 0x9a, 0x02, 0x9e,
+ 0x01, 0xa2, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb2,
+ 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbd,
+ 0x00, 0xbe, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x98,
+ 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59, 0x00, 0x49, 0x00, 0x39,
+ 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00,
+ 0x32, 0x00, 0x2c, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0e, 0x01,
+ 0x0c, 0x07, 0x09, 0x0c, 0x06, 0x11, 0x04, 0x16, 0x02, 0x1b, 0x00, 0x1f,
+ 0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x25, 0x00,
+ 0x1c, 0x00, 0x11, 0x00, 0x07, 0x00, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x19,
+ 0x00, 0x23, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x3f, 0x38, 0x48, 0x2d, 0x4e,
+ 0x23, 0x54, 0x1c, 0x5a, 0x17, 0x5f, 0x12, 0x66, 0x0f, 0x6a, 0x0c, 0x71,
+ 0x0a, 0x74, 0x08, 0x79, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84, 0x03, 0x89,
+ 0x02, 0x8d, 0x02, 0x8f, 0x01, 0x92, 0x01, 0x95, 0x00, 0x99, 0x00, 0x9b,
+ 0x1c, 0x2d, 0x15, 0x37, 0x0f, 0x41, 0x0b, 0x4a, 0x07, 0x53, 0x05, 0x5b,
+ 0x04, 0x63, 0x02, 0x69, 0x01, 0x70, 0x00, 0x77, 0x00, 0x7d, 0x00, 0x81,
+ 0x00, 0x87, 0x00, 0x8a, 0x00, 0x8f, 0x00, 0x92, 0x00, 0x96, 0x00, 0x99,
+ 0x00, 0x9b, 0x00, 0x9e, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0e, 0x85, 0x0a, 0x8a,
+ 0x07, 0x8f, 0x05, 0x93, 0x03, 0x98, 0x02, 0x9c, 0x02, 0xa0, 0x01, 0xa3,
+ 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb3,
+ 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x39, 0x47, 0x2e, 0x4d, 0x25, 0x53, 0x1e, 0x58,
+ 0x19, 0x5e, 0x14, 0x63, 0x11, 0x68, 0x0e, 0x6c, 0x0b, 0x72, 0x09, 0x75,
+ 0x07, 0x79, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84, 0x03, 0x88, 0x02, 0x8c,
+ 0x02, 0x8e, 0x01, 0x91, 0x01, 0x93, 0x00, 0x97, 0x1d, 0x2c, 0x16, 0x36,
+ 0x10, 0x3e, 0x0c, 0x48, 0x09, 0x50, 0x06, 0x58, 0x04, 0x5f, 0x02, 0x66,
+ 0x02, 0x6c, 0x01, 0x71, 0x00, 0x77, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x86,
+ 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x91, 0x00, 0x94, 0x00, 0x97, 0x00, 0x9a,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x0e, 0x84, 0x0b, 0x89, 0x08, 0x8d, 0x06, 0x92,
+ 0x04, 0x96, 0x03, 0x9a, 0x02, 0x9e, 0x01, 0xa1, 0x01, 0xa4, 0x00, 0xa7,
+ 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5,
+ 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x39, 0x46, 0x2f, 0x4c, 0x26, 0x51, 0x20, 0x56, 0x1a, 0x5c, 0x16, 0x60,
+ 0x12, 0x66, 0x0f, 0x69, 0x0c, 0x6e, 0x0b, 0x73, 0x09, 0x76, 0x07, 0x7a,
+ 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84, 0x03, 0x88, 0x02, 0x8b, 0x02, 0x8e,
+ 0x02, 0x90, 0x01, 0x92, 0x1d, 0x2b, 0x16, 0x34, 0x11, 0x3d, 0x0c, 0x45,
+ 0x0a, 0x4c, 0x07, 0x54, 0x05, 0x5b, 0x04, 0x61, 0x02, 0x67, 0x01, 0x6d,
+ 0x01, 0x73, 0x00, 0x78, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x86, 0x00, 0x89,
+ 0x00, 0x8d, 0x00, 0x90, 0x00, 0x93, 0x00, 0x95, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x0e, 0x84, 0x0b, 0x88, 0x08, 0x8d, 0x06, 0x91, 0x05, 0x94, 0x03, 0x98,
+ 0x02, 0x9c, 0x02, 0x9f, 0x01, 0xa2, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xaa,
+ 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb6,
+ 0x00, 0xb8, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x46, 0x30, 0x4b,
+ 0x28, 0x50, 0x21, 0x55, 0x1c, 0x59, 0x17, 0x5e, 0x14, 0x63, 0x10, 0x68,
+ 0x0e, 0x6b, 0x0c, 0x70, 0x0a, 0x74, 0x08, 0x76, 0x07, 0x7b, 0x06, 0x7e,
+ 0x05, 0x81, 0x04, 0x83, 0x03, 0x87, 0x02, 0x8a, 0x02, 0x8d, 0x02, 0x8f,
+ 0x1e, 0x2a, 0x17, 0x33, 0x12, 0x3b, 0x0e, 0x43, 0x0a, 0x4a, 0x07, 0x51,
+ 0x05, 0x58, 0x04, 0x5e, 0x03, 0x64, 0x02, 0x69, 0x01, 0x6f, 0x00, 0x74,
+ 0x00, 0x78, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x85, 0x00, 0x89, 0x00, 0x8b,
+ 0x00, 0x8f, 0x00, 0x93, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x83, 0x0b, 0x88,
+ 0x09, 0x8c, 0x07, 0x90, 0x05, 0x93, 0x03, 0x97, 0x02, 0x9a, 0x02, 0x9d,
+ 0x01, 0xa0, 0x01, 0xa3, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xad,
+ 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x31, 0x4a, 0x29, 0x4e, 0x22, 0x54,
+ 0x1d, 0x57, 0x19, 0x5d, 0x15, 0x60, 0x12, 0x65, 0x0f, 0x69, 0x0d, 0x6c,
+ 0x0b, 0x71, 0x09, 0x74, 0x08, 0x77, 0x07, 0x7b, 0x06, 0x7f, 0x05, 0x81,
+ 0x04, 0x83, 0x03, 0x86, 0x02, 0x8a, 0x02, 0x8c, 0x1e, 0x2a, 0x18, 0x32,
+ 0x12, 0x39, 0x0f, 0x40, 0x0c, 0x48, 0x09, 0x4f, 0x07, 0x55, 0x05, 0x5a,
+ 0x04, 0x60, 0x02, 0x66, 0x02, 0x6b, 0x01, 0x70, 0x00, 0x75, 0x00, 0x79,
+ 0x00, 0x7d, 0x00, 0x81, 0x00, 0x84, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x83, 0x0c, 0x87, 0x09, 0x8b, 0x07, 0x8e,
+ 0x06, 0x92, 0x04, 0x96, 0x03, 0x99, 0x02, 0x9b, 0x02, 0x9e, 0x01, 0xa1,
+ 0x01, 0xa4, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf,
+ 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0xb5, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3a, 0x45, 0x31, 0x49, 0x2a, 0x4d, 0x24, 0x52, 0x1f, 0x56, 0x1a, 0x5b,
+ 0x16, 0x5f, 0x13, 0x63, 0x10, 0x67, 0x0e, 0x6a, 0x0c, 0x6e, 0x0b, 0x72,
+ 0x09, 0x75, 0x07, 0x77, 0x07, 0x7b, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83,
+ 0x03, 0x85, 0x02, 0x89, 0x1e, 0x29, 0x18, 0x31, 0x13, 0x38, 0x0f, 0x3f,
+ 0x0c, 0x45, 0x0a, 0x4c, 0x07, 0x52, 0x05, 0x58, 0x04, 0x5d, 0x04, 0x63,
+ 0x02, 0x67, 0x01, 0x6c, 0x01, 0x71, 0x00, 0x75, 0x00, 0x79, 0x00, 0x7d,
+ 0x00, 0x81, 0x00, 0x84, 0x00, 0x88, 0x00, 0x8b, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x0f, 0x83, 0x0c, 0x87, 0x09, 0x8a, 0x07, 0x8e, 0x06, 0x91, 0x05, 0x94,
+ 0x03, 0x97, 0x02, 0x9a, 0x02, 0x9d, 0x02, 0xa0, 0x01, 0xa2, 0x00, 0xa4,
+ 0x00, 0xa7, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0,
+ 0x00, 0xb2, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x45, 0x32, 0x48,
+ 0x2b, 0x4d, 0x25, 0x51, 0x20, 0x55, 0x1b, 0x59, 0x18, 0x5e, 0x14, 0x60,
+ 0x12, 0x65, 0x0f, 0x68, 0x0d, 0x6b, 0x0c, 0x6f, 0x0a, 0x73, 0x09, 0x75,
+ 0x07, 0x77, 0x06, 0x7b, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85,
+ 0x1e, 0x29, 0x19, 0x30, 0x14, 0x37, 0x0f, 0x3d, 0x0c, 0x44, 0x0a, 0x4a,
+ 0x07, 0x50, 0x06, 0x55, 0x05, 0x5b, 0x04, 0x60, 0x02, 0x64, 0x02, 0x69,
+ 0x01, 0x6d, 0x01, 0x72, 0x00, 0x76, 0x00, 0x7a, 0x00, 0x7d, 0x00, 0x81,
+ 0x00, 0x83, 0x00, 0x87, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x83, 0x0c, 0x86,
+ 0x0a, 0x8a, 0x07, 0x8d, 0x06, 0x90, 0x05, 0x93, 0x03, 0x96, 0x03, 0x99,
+ 0x02, 0x9c, 0x02, 0x9e, 0x01, 0xa0, 0x01, 0xa3, 0x00, 0xa5, 0x00, 0xa7,
+ 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb2,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3b, 0x45, 0x33, 0x48, 0x2c, 0x4d, 0x26, 0x4f,
+ 0x21, 0x55, 0x1c, 0x57, 0x19, 0x5c, 0x16, 0x5f, 0x13, 0x63, 0x10, 0x67,
+ 0x0e, 0x6a, 0x0c, 0x6c, 0x0b, 0x71, 0x0a, 0x73, 0x09, 0x76, 0x07, 0x78,
+ 0x06, 0x7c, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x1e, 0x28, 0x19, 0x2f,
+ 0x15, 0x35, 0x10, 0x3c, 0x0d, 0x42, 0x0b, 0x48, 0x09, 0x4e, 0x07, 0x53,
+ 0x05, 0x58, 0x04, 0x5d, 0x04, 0x62, 0x02, 0x66, 0x02, 0x6b, 0x01, 0x6f,
+ 0x00, 0x73, 0x00, 0x76, 0x00, 0x7a, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x83,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x82, 0x0c, 0x86, 0x0a, 0x89, 0x08, 0x8c,
+ 0x06, 0x8f, 0x05, 0x92, 0x04, 0x95, 0x03, 0x98, 0x02, 0x9a, 0x02, 0x9d,
+ 0x02, 0x9f, 0x01, 0xa1, 0x01, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xa9,
+ 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0x44, 0x33, 0x47, 0x2c, 0x4c, 0x27, 0x4f, 0x22, 0x54, 0x1e, 0x56,
+ 0x1a, 0x5a, 0x17, 0x5e, 0x14, 0x60, 0x12, 0x65, 0x10, 0x68, 0x0e, 0x6a,
+ 0x0c, 0x6e, 0x0b, 0x72, 0x09, 0x74, 0x08, 0x76, 0x07, 0x78, 0x06, 0x7c,
+ 0x06, 0x7f, 0x05, 0x81, 0x1e, 0x28, 0x19, 0x2f, 0x16, 0x35, 0x12, 0x3b,
+ 0x0f, 0x41, 0x0c, 0x46, 0x0a, 0x4c, 0x07, 0x51, 0x05, 0x55, 0x05, 0x5b,
+ 0x04, 0x5f, 0x02, 0x63, 0x02, 0x68, 0x01, 0x6b, 0x01, 0x70, 0x00, 0x73,
+ 0x00, 0x77, 0x00, 0x7b, 0x00, 0x7d, 0x00, 0x81, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x0f, 0x82, 0x0c, 0x86, 0x0b, 0x89, 0x09, 0x8c, 0x07, 0x8f, 0x06, 0x91,
+ 0x05, 0x94, 0x03, 0x97, 0x02, 0x99, 0x02, 0x9c, 0x02, 0x9e, 0x01, 0xa0,
+ 0x01, 0xa2, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xac,
+ 0x00, 0xad, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x23, 0x25, 0x22,
+ 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x00, 0x44, 0x05, 0x25, 0x0d, 0x23, 0x12, 0x22,
+ 0x15, 0x22, 0x17, 0x22, 0x18, 0x22, 0x1a, 0x22, 0x1b, 0x22, 0x1b, 0x22,
+ 0x1c, 0x22, 0x1c, 0x22, 0x1c, 0x22, 0x1d, 0x22, 0x1d, 0x22, 0x1e, 0x22,
+ 0x1e, 0x22, 0x1e, 0x22, 0x1e, 0x22, 0x1e, 0x22, 0x10, 0x33, 0x13, 0x23,
+ 0x17, 0x22, 0x1a, 0x22, 0x1b, 0x22, 0x1c, 0x22, 0x1d, 0x22, 0x1e, 0x22,
+ 0x1e, 0x22, 0x1e, 0x22, 0x1f, 0x22, 0x1f, 0x22, 0x1f, 0x22, 0x1f, 0x22,
+ 0x1f, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x35, 0x25, 0x2b, 0x23, 0x27, 0x22, 0x25, 0x22,
+ 0x24, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x00, 0x9d, 0x00, 0x6b, 0x01, 0x51, 0x04, 0x45, 0x08, 0x3d, 0x0b, 0x38,
+ 0x0d, 0x35, 0x0f, 0x33, 0x10, 0x30, 0x12, 0x2f, 0x13, 0x2d, 0x14, 0x2d,
+ 0x15, 0x2c, 0x16, 0x2b, 0x16, 0x2a, 0x17, 0x2a, 0x18, 0x29, 0x18, 0x29,
+ 0x19, 0x28, 0x19, 0x28, 0x10, 0x5f, 0x10, 0x46, 0x11, 0x39, 0x13, 0x33,
+ 0x15, 0x2f, 0x16, 0x2d, 0x17, 0x2b, 0x18, 0x2a, 0x19, 0x29, 0x1a, 0x28,
+ 0x1a, 0x27, 0x1b, 0x27, 0x1b, 0x27, 0x1c, 0x26, 0x1c, 0x26, 0x1c, 0x26,
+ 0x1d, 0x25, 0x1d, 0x25, 0x1d, 0x25, 0x1d, 0x25, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x2a, 0x2e, 0x26, 0x2a, 0x25, 0x27, 0x24, 0x26, 0x23, 0x25, 0x23,
+ 0x24, 0x23, 0x24, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xbc, 0x00, 0x8e,
+ 0x00, 0x73, 0x00, 0x60, 0x02, 0x55, 0x04, 0x4c, 0x06, 0x47, 0x08, 0x42,
+ 0x0a, 0x3e, 0x0c, 0x3b, 0x0d, 0x39, 0x0e, 0x37, 0x0f, 0x36, 0x10, 0x34,
+ 0x11, 0x33, 0x12, 0x32, 0x12, 0x31, 0x13, 0x30, 0x14, 0x2f, 0x15, 0x2f,
+ 0x10, 0x6f, 0x10, 0x58, 0x10, 0x4a, 0x11, 0x41, 0x12, 0x3b, 0x13, 0x37,
+ 0x14, 0x34, 0x15, 0x32, 0x16, 0x30, 0x17, 0x2e, 0x17, 0x2d, 0x18, 0x2c,
+ 0x18, 0x2c, 0x19, 0x2b, 0x19, 0x2a, 0x1a, 0x2a, 0x1a, 0x29, 0x1a, 0x29,
+ 0x1b, 0x28, 0x1b, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x2e, 0x31, 0x29,
+ 0x2c, 0x27, 0x2a, 0x26, 0x28, 0x25, 0x27, 0x24, 0x25, 0x24, 0x25, 0x23,
+ 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x23, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x00, 0xc6, 0x00, 0xa4, 0x00, 0x89, 0x00, 0x77,
+ 0x00, 0x67, 0x01, 0x5e, 0x03, 0x55, 0x04, 0x50, 0x05, 0x4b, 0x07, 0x47,
+ 0x09, 0x44, 0x0a, 0x41, 0x0b, 0x3e, 0x0c, 0x3d, 0x0c, 0x3b, 0x0e, 0x39,
+ 0x0f, 0x38, 0x0f, 0x37, 0x0f, 0x35, 0x10, 0x35, 0x10, 0x74, 0x10, 0x63,
+ 0x10, 0x55, 0x10, 0x4c, 0x11, 0x44, 0x11, 0x40, 0x12, 0x3b, 0x13, 0x39,
+ 0x13, 0x36, 0x14, 0x34, 0x15, 0x33, 0x16, 0x31, 0x16, 0x30, 0x17, 0x2f,
+ 0x17, 0x2e, 0x18, 0x2d, 0x18, 0x2d, 0x18, 0x2c, 0x18, 0x2b, 0x19, 0x2b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3a, 0x31, 0x33, 0x2c, 0x2f, 0x29, 0x2b, 0x28,
+ 0x29, 0x26, 0x28, 0x25, 0x27, 0x25, 0x26, 0x24, 0x25, 0x24, 0x25, 0x24,
+ 0x25, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x23, 0x23,
+ 0x23, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x00, 0xcd, 0x00, 0xb0, 0x00, 0x9a, 0x00, 0x87, 0x00, 0x78, 0x00, 0x6c,
+ 0x01, 0x64, 0x02, 0x5c, 0x03, 0x57, 0x04, 0x51, 0x05, 0x4e, 0x07, 0x4a,
+ 0x07, 0x48, 0x09, 0x45, 0x0a, 0x43, 0x0a, 0x40, 0x0c, 0x3f, 0x0c, 0x3d,
+ 0x0c, 0x3c, 0x0d, 0x3b, 0x10, 0x77, 0x10, 0x69, 0x10, 0x5e, 0x10, 0x54,
+ 0x10, 0x4d, 0x11, 0x47, 0x11, 0x43, 0x12, 0x3f, 0x12, 0x3c, 0x13, 0x39,
+ 0x13, 0x38, 0x14, 0x36, 0x14, 0x35, 0x15, 0x33, 0x16, 0x32, 0x16, 0x31,
+ 0x17, 0x30, 0x17, 0x2f, 0x17, 0x2f, 0x17, 0x2e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0x33, 0x34, 0x2e, 0x30, 0x2b, 0x2d, 0x29, 0x2b, 0x28, 0x29, 0x27,
+ 0x29, 0x26, 0x27, 0x25, 0x27, 0x25, 0x26, 0x24, 0x25, 0x24, 0x25, 0x24,
+ 0x25, 0x24, 0x24, 0x24, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23,
+ 0x23, 0x23, 0x23, 0x23, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xcf, 0x00, 0xb9,
+ 0x00, 0xa4, 0x00, 0x94, 0x00, 0x85, 0x00, 0x7a, 0x00, 0x70, 0x00, 0x68,
+ 0x01, 0x61, 0x02, 0x5c, 0x04, 0x57, 0x04, 0x53, 0x05, 0x50, 0x06, 0x4c,
+ 0x07, 0x4a, 0x07, 0x48, 0x09, 0x45, 0x0a, 0x44, 0x0a, 0x42, 0x0b, 0x41,
+ 0x10, 0x78, 0x10, 0x6d, 0x10, 0x63, 0x10, 0x5b, 0x10, 0x53, 0x10, 0x4e,
+ 0x11, 0x49, 0x11, 0x45, 0x11, 0x41, 0x12, 0x3f, 0x13, 0x3c, 0x13, 0x3a,
+ 0x13, 0x39, 0x14, 0x37, 0x14, 0x36, 0x14, 0x35, 0x15, 0x33, 0x16, 0x33,
+ 0x16, 0x32, 0x16, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x34, 0x36, 0x30,
+ 0x32, 0x2d, 0x2f, 0x2b, 0x2d, 0x29, 0x2b, 0x28, 0x29, 0x27, 0x28, 0x27,
+ 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24,
+ 0x25, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x00, 0xd2, 0x00, 0xbe, 0x00, 0xad, 0x00, 0x9d,
+ 0x00, 0x90, 0x00, 0x84, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x6b, 0x01, 0x65,
+ 0x02, 0x60, 0x02, 0x5b, 0x04, 0x58, 0x04, 0x54, 0x05, 0x51, 0x05, 0x4f,
+ 0x07, 0x4c, 0x07, 0x4a, 0x07, 0x48, 0x09, 0x46, 0x10, 0x7a, 0x10, 0x70,
+ 0x10, 0x67, 0x10, 0x5f, 0x10, 0x59, 0x10, 0x53, 0x10, 0x4e, 0x11, 0x4a,
+ 0x11, 0x46, 0x11, 0x43, 0x12, 0x41, 0x12, 0x3e, 0x13, 0x3d, 0x13, 0x3b,
+ 0x13, 0x39, 0x13, 0x38, 0x14, 0x37, 0x14, 0x36, 0x14, 0x35, 0x15, 0x34,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x35, 0x37, 0x31, 0x33, 0x2e, 0x30, 0x2c,
+ 0x2d, 0x2a, 0x2c, 0x29, 0x2b, 0x28, 0x29, 0x27, 0x28, 0x27, 0x28, 0x27,
+ 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24,
+ 0x25, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x00, 0xd3, 0x00, 0xc2, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x98, 0x00, 0x8d,
+ 0x00, 0x83, 0x00, 0x7b, 0x00, 0x73, 0x00, 0x6e, 0x01, 0x67, 0x01, 0x63,
+ 0x02, 0x5f, 0x02, 0x5b, 0x04, 0x58, 0x04, 0x55, 0x05, 0x52, 0x05, 0x50,
+ 0x06, 0x4e, 0x07, 0x4c, 0x10, 0x7a, 0x10, 0x72, 0x10, 0x6a, 0x10, 0x63,
+ 0x10, 0x5d, 0x10, 0x57, 0x10, 0x52, 0x10, 0x4e, 0x11, 0x4a, 0x11, 0x48,
+ 0x11, 0x44, 0x11, 0x42, 0x12, 0x40, 0x12, 0x3e, 0x13, 0x3d, 0x13, 0x3b,
+ 0x13, 0x3a, 0x13, 0x39, 0x14, 0x38, 0x14, 0x37, 0x0f, 0x00, 0x1f, 0x00,
+ 0x33, 0x00, 0x39, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00,
+ 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00,
+ 0x3f, 0x00, 0x3f, 0x00, 0x0b, 0x3b, 0x17, 0x07, 0x2c, 0x00, 0x36, 0x00,
+ 0x3a, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00,
+ 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x3d, 0x00,
+ 0x4c, 0x00, 0x4c, 0x00, 0x48, 0x00, 0x42, 0x00, 0x3e, 0x00, 0x3e, 0x00,
+ 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00,
+ 0x3f, 0x00, 0x3f, 0x00, 0x07, 0x47, 0x0f, 0x0f, 0x26, 0x00, 0x33, 0x00,
+ 0x38, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00,
+ 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00,
+ 0x3c, 0x37, 0x37, 0x32, 0x34, 0x30, 0x31, 0x2d, 0x2f, 0x2c, 0x2d, 0x2b,
+ 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x27, 0x28, 0x27, 0x28, 0x27, 0x27, 0x26,
+ 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24,
+ 0x25, 0x24, 0x24, 0x24, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd5, 0x00, 0xc5,
+ 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x9f, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x83,
+ 0x00, 0x7c, 0x00, 0x75, 0x00, 0x6f, 0x00, 0x69, 0x01, 0x66, 0x02, 0x61,
+ 0x02, 0x5e, 0x03, 0x5a, 0x04, 0x58, 0x04, 0x55, 0x05, 0x53, 0x05, 0x51,
+ 0x10, 0x7b, 0x10, 0x73, 0x10, 0x6c, 0x10, 0x66, 0x10, 0x60, 0x10, 0x5b,
+ 0x10, 0x56, 0x10, 0x52, 0x10, 0x4f, 0x11, 0x4b, 0x11, 0x48, 0x11, 0x45,
+ 0x11, 0x44, 0x12, 0x41, 0x12, 0x40, 0x12, 0x3e, 0x13, 0x3d, 0x13, 0x3b,
+ 0x13, 0x3a, 0x13, 0x39, 0x00, 0x00, 0x05, 0x00, 0x1f, 0x00, 0x2e, 0x00,
+ 0x35, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00,
+ 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00,
+ 0x00, 0x6f, 0x02, 0x27, 0x12, 0x02, 0x25, 0x00, 0x2f, 0x00, 0x35, 0x00,
+ 0x38, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00,
+ 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x30, 0x00, 0x39, 0x00, 0x42, 0x00,
+ 0x41, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00,
+ 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00,
+ 0x00, 0x7f, 0x00, 0x3f, 0x05, 0x05, 0x1c, 0x00, 0x2a, 0x00, 0x31, 0x00,
+ 0x35, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00,
+ 0x3d, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3c, 0x37, 0x38, 0x33,
+ 0x34, 0x31, 0x32, 0x2f, 0x30, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x29,
+ 0x2b, 0x28, 0x29, 0x28, 0x28, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, 0x25,
+ 0x27, 0x25, 0x27, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x00, 0xd5, 0x00, 0xc8, 0x00, 0xbb, 0x00, 0xaf,
+ 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x92, 0x00, 0x8a, 0x00, 0x82, 0x00, 0x7c,
+ 0x00, 0x76, 0x00, 0x70, 0x00, 0x6c, 0x01, 0x67, 0x01, 0x64, 0x02, 0x60,
+ 0x02, 0x5d, 0x04, 0x5b, 0x04, 0x58, 0x04, 0x55, 0x10, 0x7b, 0x10, 0x75,
+ 0x10, 0x6e, 0x10, 0x68, 0x10, 0x63, 0x10, 0x5e, 0x10, 0x5a, 0x10, 0x56,
+ 0x10, 0x52, 0x10, 0x4f, 0x11, 0x4c, 0x11, 0x49, 0x11, 0x47, 0x11, 0x44,
+ 0x11, 0x43, 0x12, 0x41, 0x12, 0x3f, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x16, 0x00, 0x24, 0x00, 0x2c, 0x00,
+ 0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00,
+ 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x00, 0x9f, 0x00, 0x6f,
+ 0x00, 0x22, 0x0b, 0x09, 0x16, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00,
+ 0x33, 0x00, 0x35, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00,
+ 0x3b, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4c, 0x00, 0x39, 0x00, 0x16, 0x00, 0x28, 0x00, 0x2f, 0x00, 0x2e, 0x00,
+ 0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00,
+ 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x00, 0xa5, 0x00, 0x7f,
+ 0x00, 0x3f, 0x00, 0x12, 0x09, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2a, 0x00,
+ 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x39, 0x00,
+ 0x3a, 0x00, 0x3a, 0x00, 0x3d, 0x38, 0x39, 0x34, 0x35, 0x32, 0x33, 0x30,
+ 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2b, 0x2c, 0x2b, 0x2b, 0x29, 0x2b, 0x28,
+ 0x29, 0x28, 0x28, 0x26, 0x28, 0x27, 0x27, 0x27, 0x27, 0x26, 0x27, 0x25,
+ 0x27, 0x25, 0x26, 0x25, 0x25, 0x25, 0x25, 0x25, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x00, 0xd6, 0x00, 0xca, 0x00, 0xbe, 0x00, 0xb3, 0x00, 0xaa, 0x00, 0xa0,
+ 0x00, 0x98, 0x00, 0x90, 0x00, 0x88, 0x00, 0x82, 0x00, 0x7d, 0x00, 0x77,
+ 0x00, 0x71, 0x00, 0x6d, 0x01, 0x69, 0x01, 0x66, 0x02, 0x63, 0x02, 0x60,
+ 0x02, 0x5d, 0x04, 0x5b, 0x10, 0x7c, 0x10, 0x76, 0x10, 0x70, 0x10, 0x6a,
+ 0x10, 0x65, 0x10, 0x61, 0x10, 0x5d, 0x10, 0x59, 0x10, 0x55, 0x10, 0x52,
+ 0x10, 0x4f, 0x11, 0x4c, 0x11, 0x49, 0x11, 0x47, 0x11, 0x45, 0x11, 0x44,
+ 0x12, 0x42, 0x12, 0x41, 0x12, 0x3f, 0x13, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x2b, 0x00,
+ 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00,
+ 0x39, 0x00, 0x3a, 0x00, 0x00, 0xaf, 0x00, 0x93, 0x00, 0x58, 0x00, 0x21,
+ 0x08, 0x0e, 0x0e, 0x02, 0x18, 0x00, 0x20, 0x00, 0x27, 0x00, 0x2b, 0x00,
+ 0x2f, 0x00, 0x31, 0x00, 0x33, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x42, 0x00,
+ 0x28, 0x00, 0x09, 0x00, 0x16, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x2b, 0x00,
+ 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00,
+ 0x39, 0x00, 0x3a, 0x00, 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x6d, 0x00, 0x3f,
+ 0x00, 0x1d, 0x00, 0x05, 0x0b, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x25, 0x00,
+ 0x29, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, 0x00,
+ 0x3d, 0x38, 0x39, 0x35, 0x36, 0x33, 0x33, 0x30, 0x31, 0x2f, 0x30, 0x2d,
+ 0x2e, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x2b, 0x28, 0x28, 0x28,
+ 0x28, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x26, 0x27, 0x25,
+ 0x27, 0x25, 0x25, 0x25, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd6, 0x00, 0xcc,
+ 0x00, 0xc0, 0x00, 0xb7, 0x00, 0xad, 0x00, 0xa5, 0x00, 0x9d, 0x00, 0x96,
+ 0x00, 0x8f, 0x00, 0x88, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x77, 0x00, 0x73,
+ 0x00, 0x6f, 0x00, 0x6b, 0x01, 0x67, 0x01, 0x64, 0x02, 0x62, 0x02, 0x5f,
+ 0x10, 0x7c, 0x10, 0x77, 0x10, 0x71, 0x10, 0x6c, 0x10, 0x67, 0x10, 0x63,
+ 0x10, 0x5f, 0x10, 0x5c, 0x10, 0x58, 0x10, 0x55, 0x10, 0x51, 0x10, 0x4f,
+ 0x11, 0x4c, 0x11, 0x4a, 0x11, 0x48, 0x11, 0x46, 0x11, 0x44, 0x11, 0x43,
+ 0x12, 0x42, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x2a, 0x00,
+ 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34, 0x00, 0x35, 0x00, 0x37, 0x00,
+ 0x00, 0xb5, 0x00, 0xa4, 0x00, 0x7a, 0x00, 0x4a, 0x00, 0x20, 0x06, 0x12,
+ 0x0c, 0x07, 0x10, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x24, 0x00, 0x28, 0x00,
+ 0x2c, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16, 0x00,
+ 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x2a, 0x00,
+ 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34, 0x00, 0x35, 0x00, 0x37, 0x00,
+ 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x62, 0x00, 0x3f, 0x00, 0x24,
+ 0x00, 0x0f, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00,
+ 0x25, 0x00, 0x29, 0x00, 0x2b, 0x00, 0x2e, 0x00, 0x3d, 0x39, 0x3a, 0x36,
+ 0x36, 0x33, 0x34, 0x31, 0x32, 0x30, 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2b,
+ 0x2d, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x27,
+ 0x28, 0x26, 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x25, 0x27, 0x25,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x00, 0xd7, 0x00, 0xcc, 0x00, 0xc3, 0x00, 0xba,
+ 0x00, 0xb1, 0x00, 0xa8, 0x00, 0xa0, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8d,
+ 0x00, 0x87, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x74, 0x00, 0x70,
+ 0x00, 0x6c, 0x01, 0x69, 0x01, 0x66, 0x02, 0x63, 0x10, 0x7c, 0x10, 0x77,
+ 0x10, 0x72, 0x10, 0x6e, 0x10, 0x69, 0x10, 0x65, 0x10, 0x61, 0x10, 0x5d,
+ 0x10, 0x5a, 0x10, 0x57, 0x10, 0x54, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d,
+ 0x11, 0x4b, 0x11, 0x49, 0x11, 0x47, 0x11, 0x45, 0x11, 0x44, 0x12, 0x42,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00,
+ 0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32, 0x00, 0x00, 0xb9, 0x00, 0xad,
+ 0x00, 0x8f, 0x00, 0x68, 0x00, 0x42, 0x00, 0x20, 0x05, 0x14, 0x0a, 0x0b,
+ 0x0d, 0x04, 0x12, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x23, 0x00, 0x26, 0x00,
+ 0x29, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x00, 0x3d, 0x00, 0x2e, 0x00, 0x1d, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00,
+ 0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32, 0x00, 0x00, 0xba, 0x00, 0xb1,
+ 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5b, 0x00, 0x3f, 0x00, 0x29, 0x00, 0x16,
+ 0x00, 0x08, 0x02, 0x00, 0x0c, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1e, 0x00,
+ 0x22, 0x00, 0x25, 0x00, 0x3d, 0x39, 0x3a, 0x36, 0x37, 0x34, 0x35, 0x32,
+ 0x33, 0x30, 0x31, 0x2f, 0x30, 0x2d, 0x2e, 0x2d, 0x2d, 0x2a, 0x2c, 0x2b,
+ 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27,
+ 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x26, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x00, 0xd7, 0x00, 0xce, 0x00, 0xc5, 0x00, 0xbc, 0x00, 0xb4, 0x00, 0xac,
+ 0x00, 0xa5, 0x00, 0x9e, 0x00, 0x97, 0x00, 0x91, 0x00, 0x8c, 0x00, 0x87,
+ 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x75, 0x00, 0x71, 0x00, 0x6d,
+ 0x01, 0x6b, 0x01, 0x68, 0x10, 0x7c, 0x10, 0x78, 0x10, 0x73, 0x10, 0x6f,
+ 0x10, 0x6b, 0x10, 0x67, 0x10, 0x63, 0x10, 0x60, 0x10, 0x5c, 0x10, 0x59,
+ 0x10, 0x57, 0x10, 0x54, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d, 0x11, 0x4b,
+ 0x11, 0x49, 0x11, 0x47, 0x11, 0x46, 0x11, 0x45, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22, 0x00, 0x26, 0x00, 0x29, 0x00,
+ 0x2b, 0x00, 0x2d, 0x00, 0x00, 0xba, 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x7d,
+ 0x00, 0x5c, 0x00, 0x3c, 0x00, 0x20, 0x04, 0x16, 0x08, 0x0e, 0x0c, 0x07,
+ 0x0e, 0x02, 0x13, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x25, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3a, 0x00,
+ 0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22, 0x00, 0x26, 0x00, 0x29, 0x00,
+ 0x2b, 0x00, 0x2d, 0x00, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xa3, 0x00, 0x8a,
+ 0x00, 0x6f, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0f,
+ 0x00, 0x04, 0x04, 0x00, 0x0c, 0x00, 0x12, 0x00, 0x17, 0x00, 0x1c, 0x00,
+ 0x3d, 0x39, 0x3a, 0x36, 0x37, 0x34, 0x35, 0x33, 0x33, 0x30, 0x32, 0x30,
+ 0x30, 0x2e, 0x2f, 0x2d, 0x2d, 0x2c, 0x2d, 0x2a, 0x2c, 0x2b, 0x2b, 0x2a,
+ 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x26, 0x28, 0x27,
+ 0x27, 0x27, 0x27, 0x27, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd8, 0x00, 0xcf,
+ 0x00, 0xc6, 0x00, 0xbe, 0x00, 0xb6, 0x00, 0xaf, 0x00, 0xa8, 0x00, 0xa1,
+ 0x00, 0x9c, 0x00, 0x96, 0x00, 0x90, 0x00, 0x8a, 0x00, 0x86, 0x00, 0x81,
+ 0x00, 0x7d, 0x00, 0x79, 0x00, 0x75, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x6b,
+ 0x10, 0x7d, 0x10, 0x78, 0x10, 0x74, 0x10, 0x70, 0x10, 0x6c, 0x10, 0x68,
+ 0x10, 0x65, 0x10, 0x61, 0x10, 0x5f, 0x10, 0x5c, 0x10, 0x59, 0x10, 0x56,
+ 0x10, 0x54, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x4a,
+ 0x11, 0x48, 0x11, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00,
+ 0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22, 0x00, 0x26, 0x00, 0x28, 0x00,
+ 0x00, 0xbc, 0x00, 0xb5, 0x00, 0xa4, 0x00, 0x8b, 0x00, 0x6f, 0x00, 0x52,
+ 0x00, 0x37, 0x00, 0x20, 0x04, 0x17, 0x07, 0x10, 0x0a, 0x0a, 0x0d, 0x05,
+ 0x0f, 0x00, 0x14, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00,
+ 0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00,
+ 0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22, 0x00, 0x26, 0x00, 0x28, 0x00,
+ 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x96, 0x00, 0x7f, 0x00, 0x68,
+ 0x00, 0x53, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x20, 0x00, 0x14, 0x00, 0x0a,
+ 0x00, 0x01, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x3d, 0x3a, 0x3a, 0x37,
+ 0x38, 0x35, 0x36, 0x33, 0x33, 0x32, 0x33, 0x30, 0x30, 0x2f, 0x30, 0x2d,
+ 0x2e, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28,
+ 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27, 0x29, 0x27, 0x27, 0x27,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x00, 0xd8, 0x00, 0xd0, 0x00, 0xc8, 0x00, 0xc0,
+ 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xab, 0x00, 0xa5, 0x00, 0x9f, 0x00, 0x99,
+ 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8a, 0x00, 0x86, 0x00, 0x81, 0x00, 0x7d,
+ 0x00, 0x79, 0x00, 0x76, 0x00, 0x73, 0x00, 0x70, 0x10, 0x7d, 0x10, 0x79,
+ 0x10, 0x75, 0x10, 0x71, 0x10, 0x6d, 0x10, 0x6a, 0x10, 0x66, 0x10, 0x63,
+ 0x10, 0x60, 0x10, 0x5d, 0x10, 0x5b, 0x10, 0x58, 0x10, 0x56, 0x10, 0x54,
+ 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d, 0x11, 0x4c, 0x11, 0x4a, 0x11, 0x49,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13, 0x00,
+ 0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23, 0x00, 0x00, 0xbc, 0x00, 0xb8,
+ 0x00, 0xaa, 0x00, 0x96, 0x00, 0x7e, 0x00, 0x64, 0x00, 0x4c, 0x00, 0x34,
+ 0x00, 0x20, 0x03, 0x18, 0x06, 0x11, 0x09, 0x0c, 0x0c, 0x07, 0x0e, 0x03,
+ 0x10, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x25, 0x00, 0x1b, 0x00,
+ 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13, 0x00,
+ 0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23, 0x00, 0x00, 0xbd, 0x00, 0xb9,
+ 0x00, 0xae, 0x00, 0x9e, 0x00, 0x8b, 0x00, 0x77, 0x00, 0x63, 0x00, 0x50,
+ 0x00, 0x3f, 0x00, 0x30, 0x00, 0x23, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x06,
+ 0x00, 0x00, 0x07, 0x00, 0x3d, 0x3a, 0x3a, 0x38, 0x38, 0x36, 0x36, 0x33,
+ 0x34, 0x33, 0x33, 0x30, 0x31, 0x30, 0x30, 0x2e, 0x2f, 0x2d, 0x2d, 0x2d,
+ 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x27, 0x28, 0x27, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x00, 0xd9, 0x00, 0xd1, 0x00, 0xc9, 0x00, 0xc2, 0x00, 0xbb, 0x00, 0xb4,
+ 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa2, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x92,
+ 0x00, 0x8e, 0x00, 0x89, 0x00, 0x85, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7a,
+ 0x00, 0x76, 0x00, 0x73, 0x10, 0x7d, 0x10, 0x79, 0x10, 0x75, 0x10, 0x72,
+ 0x10, 0x6e, 0x10, 0x6b, 0x10, 0x68, 0x10, 0x65, 0x10, 0x62, 0x10, 0x5f,
+ 0x10, 0x5c, 0x10, 0x5a, 0x10, 0x58, 0x10, 0x55, 0x10, 0x53, 0x10, 0x51,
+ 0x10, 0x4f, 0x11, 0x4e, 0x11, 0x4c, 0x11, 0x4a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x16, 0x00,
+ 0x1a, 0x00, 0x1d, 0x00, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9d,
+ 0x00, 0x89, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x46, 0x00, 0x32, 0x00, 0x20,
+ 0x03, 0x19, 0x06, 0x13, 0x08, 0x0e, 0x0b, 0x09, 0x0d, 0x05, 0x0e, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00,
+ 0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x16, 0x00,
+ 0x1a, 0x00, 0x1d, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa4,
+ 0x00, 0x94, 0x00, 0x82, 0x00, 0x70, 0x00, 0x5e, 0x00, 0x4e, 0x00, 0x3f,
+ 0x00, 0x32, 0x00, 0x26, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x03,
+ 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x36, 0x34, 0x35, 0x33, 0x33, 0x31,
+ 0x32, 0x30, 0x30, 0x2f, 0x30, 0x2d, 0x2e, 0x2d, 0x2d, 0x2c, 0x2d, 0x2a,
+ 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd9, 0x00, 0xd1,
+ 0x00, 0xca, 0x00, 0xc3, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xb0, 0x00, 0xaa,
+ 0x00, 0xa5, 0x00, 0xa0, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x91, 0x00, 0x8d,
+ 0x00, 0x89, 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x77,
+ 0x10, 0x7d, 0x10, 0x79, 0x10, 0x76, 0x10, 0x72, 0x10, 0x6f, 0x10, 0x6c,
+ 0x10, 0x69, 0x10, 0x66, 0x10, 0x63, 0x10, 0x61, 0x10, 0x5e, 0x10, 0x5c,
+ 0x10, 0x59, 0x10, 0x57, 0x10, 0x55, 0x10, 0x53, 0x10, 0x51, 0x10, 0x4f,
+ 0x11, 0x4e, 0x11, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00,
+ 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa3, 0x00, 0x92, 0x00, 0x7e,
+ 0x00, 0x6a, 0x00, 0x56, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x03, 0x19,
+ 0x05, 0x14, 0x08, 0x0f, 0x0a, 0x0b, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x34, 0x00,
+ 0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x06, 0x00,
+ 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00,
+ 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb4, 0x00, 0xa9, 0x00, 0x9b, 0x00, 0x8b,
+ 0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4d, 0x00, 0x3f, 0x00, 0x33,
+ 0x00, 0x28, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0e, 0x3d, 0x3b, 0x3b, 0x39,
+ 0x3a, 0x36, 0x36, 0x35, 0x36, 0x33, 0x33, 0x32, 0x33, 0x30, 0x30, 0x30,
+ 0x30, 0x2e, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b,
+ 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x00, 0xd9, 0x00, 0xd2, 0x00, 0xcb, 0x00, 0xc4,
+ 0x00, 0xbe, 0x00, 0xb8, 0x00, 0xb2, 0x00, 0xad, 0x00, 0xa8, 0x00, 0xa2,
+ 0x00, 0x9d, 0x00, 0x99, 0x00, 0x94, 0x00, 0x90, 0x00, 0x8b, 0x00, 0x88,
+ 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7b, 0x10, 0x7d, 0x10, 0x7a,
+ 0x10, 0x76, 0x10, 0x73, 0x10, 0x70, 0x10, 0x6d, 0x10, 0x6a, 0x10, 0x67,
+ 0x10, 0x65, 0x10, 0x62, 0x10, 0x5f, 0x10, 0x5d, 0x10, 0x5b, 0x10, 0x59,
+ 0x10, 0x56, 0x10, 0x55, 0x10, 0x53, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x00, 0xbd, 0x00, 0xbb,
+ 0x00, 0xb3, 0x00, 0xa8, 0x00, 0x99, 0x00, 0x87, 0x00, 0x75, 0x00, 0x62,
+ 0x00, 0x50, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x1f, 0x02, 0x1a, 0x05, 0x15,
+ 0x07, 0x10, 0x09, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29, 0x00,
+ 0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x00, 0xbe, 0x00, 0xbc,
+ 0x00, 0xb6, 0x00, 0xac, 0x00, 0xa0, 0x00, 0x93, 0x00, 0x84, 0x00, 0x75,
+ 0x00, 0x66, 0x00, 0x58, 0x00, 0x4b, 0x00, 0x3f, 0x00, 0x34, 0x00, 0x2a,
+ 0x00, 0x21, 0x00, 0x19, 0x3d, 0x3b, 0x3b, 0x39, 0x39, 0x36, 0x37, 0x35,
+ 0x36, 0x33, 0x33, 0x33, 0x33, 0x30, 0x31, 0x30, 0x30, 0x2f, 0x30, 0x2d,
+ 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+ 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
+ 0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcc, 0x00, 0xc6, 0x00, 0xc0, 0x00, 0xba,
+ 0x00, 0xb4, 0x00, 0xaf, 0x00, 0xaa, 0x00, 0xa5, 0x00, 0xa0, 0x00, 0x9b,
+ 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f, 0x00, 0x8b, 0x00, 0x88, 0x00, 0x83,
+ 0x00, 0x81, 0x00, 0x7d, 0x10, 0x7d, 0x10, 0x7a, 0x10, 0x77, 0x10, 0x74,
+ 0x10, 0x71, 0x10, 0x6e, 0x10, 0x6b, 0x10, 0x68, 0x10, 0x65, 0x10, 0x63,
+ 0x10, 0x61, 0x10, 0x5e, 0x10, 0x5c, 0x10, 0x5a, 0x10, 0x58, 0x10, 0x56,
+ 0x10, 0x55, 0x10, 0x52, 0x10, 0x51, 0x10, 0x4f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x09, 0x00, 0x0d, 0x00, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xab,
+ 0x00, 0x9e, 0x00, 0x8f, 0x00, 0x7e, 0x00, 0x6d, 0x00, 0x5c, 0x00, 0x4c,
+ 0x00, 0x3c, 0x00, 0x2d, 0x00, 0x1f, 0x02, 0x1a, 0x04, 0x16, 0x06, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
+ 0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x26, 0x00, 0x1f, 0x00,
+ 0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x09, 0x00, 0x0d, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf,
+ 0x00, 0xa5, 0x00, 0x99, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x70, 0x00, 0x63,
+ 0x00, 0x56, 0x00, 0x4a, 0x00, 0x3f, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x23,
+ 0x27, 0x76, 0x1a, 0x79, 0x16, 0x7b, 0x15, 0x7c, 0x14, 0x7c, 0x13, 0x7d,
+ 0x13, 0x7d, 0x13, 0x7d, 0x12, 0x7d, 0x12, 0x7d, 0x12, 0x7e, 0x12, 0x7e,
+ 0x12, 0x7e, 0x12, 0x7e, 0x12, 0x7e, 0x11, 0x7e, 0x11, 0x7e, 0x11, 0x7e,
+ 0x11, 0x7f, 0x11, 0x7f, 0x13, 0x5f, 0x10, 0x6f, 0x10, 0x74, 0x10, 0x77,
+ 0x10, 0x78, 0x10, 0x7a, 0x10, 0x7a, 0x10, 0x7b, 0x10, 0x7b, 0x10, 0x7c,
+ 0x10, 0x7c, 0x10, 0x7c, 0x10, 0x7c, 0x10, 0x7d, 0x10, 0x7d, 0x10, 0x7d,
+ 0x10, 0x7d, 0x10, 0x7d, 0x10, 0x7d, 0x10, 0x7d, 0x00, 0x90, 0x02, 0x81,
+ 0x06, 0x80, 0x09, 0x7f, 0x0a, 0x7f, 0x0b, 0x7f, 0x0c, 0x7f, 0x0d, 0x7f,
+ 0x0d, 0x7f, 0x0d, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f,
+ 0x0e, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00,
+ 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xae, 0x00, 0xa2, 0x00, 0x95,
+ 0x00, 0x86, 0x00, 0x77, 0x00, 0x67, 0x00, 0x57, 0x00, 0x48, 0x00, 0x3a,
+ 0x00, 0x2c, 0x00, 0x1f, 0x02, 0x1b, 0x04, 0x16, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00,
+ 0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1c, 0x00, 0x16, 0x00,
+ 0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00,
+ 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9d,
+ 0x00, 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54,
+ 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2d, 0x32, 0x5f, 0x25, 0x68,
+ 0x1f, 0x6d, 0x1c, 0x71, 0x19, 0x72, 0x18, 0x74, 0x17, 0x76, 0x16, 0x77,
+ 0x16, 0x77, 0x15, 0x78, 0x15, 0x79, 0x15, 0x79, 0x14, 0x7a, 0x14, 0x7a,
+ 0x13, 0x7a, 0x13, 0x7b, 0x13, 0x7b, 0x13, 0x7b, 0x13, 0x7b, 0x13, 0x7b,
+ 0x17, 0x46, 0x11, 0x58, 0x10, 0x63, 0x10, 0x69, 0x10, 0x6d, 0x10, 0x70,
+ 0x10, 0x72, 0x10, 0x73, 0x10, 0x75, 0x10, 0x76, 0x10, 0x77, 0x10, 0x77,
+ 0x10, 0x78, 0x10, 0x78, 0x10, 0x79, 0x10, 0x79, 0x10, 0x79, 0x10, 0x7a,
+ 0x10, 0x7a, 0x10, 0x7a, 0x00, 0xbd, 0x00, 0xa4, 0x00, 0x97, 0x02, 0x91,
+ 0x04, 0x8d, 0x05, 0x8a, 0x06, 0x89, 0x07, 0x88, 0x08, 0x86, 0x09, 0x86,
+ 0x09, 0x85, 0x0a, 0x85, 0x0a, 0x84, 0x0b, 0x84, 0x0b, 0x83, 0x0b, 0x83,
+ 0x0c, 0x83, 0x0c, 0x83, 0x0c, 0x82, 0x0c, 0x82, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xbe, 0x00, 0xbc,
+ 0x00, 0xb8, 0x00, 0xb0, 0x00, 0xa6, 0x00, 0x9a, 0x00, 0x8d, 0x00, 0x7f,
+ 0x00, 0x70, 0x00, 0x61, 0x00, 0x53, 0x00, 0x45, 0x00, 0x38, 0x00, 0x2b,
+ 0x00, 0x1f, 0x02, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39, 0x00, 0x35, 0x00, 0x31, 0x00,
+ 0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0f, 0x00,
+ 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xbe, 0x00, 0xbd,
+ 0x00, 0xb9, 0x00, 0xb3, 0x00, 0xab, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8b,
+ 0x00, 0x80, 0x00, 0x74, 0x00, 0x68, 0x00, 0x5d, 0x00, 0x53, 0x00, 0x49,
+ 0x00, 0x3f, 0x00, 0x36, 0x36, 0x56, 0x2a, 0x5f, 0x24, 0x65, 0x20, 0x68,
+ 0x1e, 0x6c, 0x1c, 0x6e, 0x1b, 0x70, 0x19, 0x71, 0x18, 0x72, 0x18, 0x73,
+ 0x18, 0x75, 0x17, 0x75, 0x16, 0x76, 0x15, 0x76, 0x15, 0x76, 0x15, 0x77,
+ 0x15, 0x77, 0x15, 0x77, 0x15, 0x78, 0x15, 0x79, 0x1a, 0x39, 0x13, 0x4a,
+ 0x11, 0x55, 0x10, 0x5e, 0x10, 0x63, 0x10, 0x67, 0x10, 0x6a, 0x10, 0x6c,
+ 0x10, 0x6e, 0x10, 0x70, 0x10, 0x71, 0x10, 0x72, 0x10, 0x73, 0x10, 0x74,
+ 0x10, 0x75, 0x10, 0x75, 0x10, 0x76, 0x10, 0x76, 0x10, 0x77, 0x10, 0x77,
+ 0x00, 0xcc, 0x00, 0xb5, 0x00, 0xa8, 0x00, 0x9e, 0x01, 0x99, 0x02, 0x94,
+ 0x03, 0x92, 0x04, 0x8f, 0x05, 0x8d, 0x06, 0x8c, 0x06, 0x8b, 0x07, 0x8a,
+ 0x07, 0x89, 0x08, 0x88, 0x08, 0x88, 0x09, 0x87, 0x09, 0x87, 0x09, 0x86,
+ 0x0a, 0x86, 0x0a, 0x86, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb2,
+ 0x00, 0xa9, 0x00, 0x9e, 0x00, 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6a,
+ 0x00, 0x5c, 0x00, 0x4f, 0x00, 0x42, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
+ 0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x28, 0x00,
+ 0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x09, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb4,
+ 0x00, 0xad, 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x91, 0x00, 0x86, 0x00, 0x7b,
+ 0x00, 0x70, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3f,
+ 0x38, 0x52, 0x2e, 0x59, 0x28, 0x5f, 0x24, 0x63, 0x22, 0x67, 0x1f, 0x69,
+ 0x1e, 0x6b, 0x1c, 0x6d, 0x1b, 0x6e, 0x1a, 0x70, 0x1a, 0x71, 0x19, 0x72,
+ 0x18, 0x72, 0x18, 0x72, 0x18, 0x73, 0x17, 0x75, 0x17, 0x76, 0x16, 0x76,
+ 0x15, 0x76, 0x15, 0x76, 0x1b, 0x33, 0x15, 0x41, 0x12, 0x4c, 0x11, 0x54,
+ 0x10, 0x5b, 0x10, 0x5f, 0x10, 0x63, 0x10, 0x66, 0x10, 0x68, 0x10, 0x6a,
+ 0x10, 0x6c, 0x10, 0x6e, 0x10, 0x6f, 0x10, 0x70, 0x10, 0x71, 0x10, 0x72,
+ 0x10, 0x72, 0x10, 0x73, 0x10, 0x74, 0x10, 0x74, 0x00, 0xd1, 0x00, 0xc0,
+ 0x00, 0xb3, 0x00, 0xaa, 0x00, 0xa2, 0x00, 0x9d, 0x01, 0x99, 0x02, 0x96,
+ 0x02, 0x94, 0x03, 0x92, 0x04, 0x90, 0x05, 0x8f, 0x05, 0x8d, 0x06, 0x8d,
+ 0x06, 0x8c, 0x07, 0x8b, 0x07, 0x8a, 0x07, 0x8a, 0x07, 0x89, 0x08, 0x89,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x47, 0x0f, 0x0f, 0x26, 0x00, 0x33, 0x00, 0x38, 0x00, 0x3a, 0x00,
+ 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00,
+ 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x47, 0x00, 0x7f, 0x00, 0xa5, 0x00, 0xb2,
+ 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd,
+ 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x4f, 0x31, 0x55,
+ 0x2b, 0x5b, 0x27, 0x5f, 0x24, 0x63, 0x22, 0x65, 0x20, 0x68, 0x1f, 0x69,
+ 0x1d, 0x6b, 0x1d, 0x6d, 0x1b, 0x6d, 0x1a, 0x6e, 0x1a, 0x6f, 0x1a, 0x71,
+ 0x19, 0x72, 0x18, 0x72, 0x18, 0x72, 0x18, 0x72, 0x18, 0x73, 0x18, 0x74,
+ 0x1c, 0x2f, 0x16, 0x3b, 0x13, 0x44, 0x11, 0x4d, 0x11, 0x53, 0x10, 0x59,
+ 0x10, 0x5d, 0x10, 0x60, 0x10, 0x63, 0x10, 0x65, 0x10, 0x67, 0x10, 0x69,
+ 0x10, 0x6b, 0x10, 0x6c, 0x10, 0x6d, 0x10, 0x6e, 0x10, 0x6f, 0x10, 0x70,
+ 0x10, 0x71, 0x10, 0x71, 0x00, 0xd5, 0x00, 0xc6, 0x00, 0xbb, 0x00, 0xb2,
+ 0x00, 0xaa, 0x00, 0xa4, 0x00, 0xa0, 0x01, 0x9c, 0x01, 0x9a, 0x02, 0x97,
+ 0x02, 0x95, 0x03, 0x93, 0x03, 0x92, 0x04, 0x91, 0x05, 0x90, 0x05, 0x8e,
+ 0x06, 0x8e, 0x06, 0x8d, 0x06, 0x8c, 0x06, 0x8c, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x3f,
+ 0x05, 0x05, 0x1c, 0x00, 0x2a, 0x00, 0x31, 0x00, 0x35, 0x00, 0x38, 0x00,
+ 0x39, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00,
+ 0x3d, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0f, 0x0f, 0x00, 0x3f, 0x00, 0x7f, 0x00, 0x9c, 0x00, 0xaa, 0x00, 0xb1,
+ 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc,
+ 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3a, 0x4c, 0x33, 0x53, 0x2e, 0x58, 0x29, 0x5c,
+ 0x27, 0x5f, 0x24, 0x62, 0x22, 0x64, 0x20, 0x66, 0x20, 0x68, 0x1e, 0x69,
+ 0x1d, 0x6a, 0x1d, 0x6c, 0x1c, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x1a, 0x6f,
+ 0x1a, 0x71, 0x19, 0x72, 0x18, 0x72, 0x18, 0x72, 0x1d, 0x2d, 0x17, 0x37,
+ 0x14, 0x40, 0x12, 0x47, 0x11, 0x4e, 0x11, 0x53, 0x10, 0x57, 0x10, 0x5b,
+ 0x10, 0x5e, 0x10, 0x61, 0x10, 0x63, 0x10, 0x65, 0x10, 0x67, 0x10, 0x68,
+ 0x10, 0x6a, 0x10, 0x6b, 0x10, 0x6c, 0x10, 0x6d, 0x10, 0x6e, 0x10, 0x6f,
+ 0x00, 0xd6, 0x00, 0xcb, 0x00, 0xc0, 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xab,
+ 0x00, 0xa6, 0x00, 0xa2, 0x00, 0x9f, 0x01, 0x9c, 0x02, 0x9a, 0x02, 0x98,
+ 0x02, 0x96, 0x03, 0x94, 0x03, 0x93, 0x03, 0x92, 0x04, 0x91, 0x05, 0x90,
+ 0x05, 0x8f, 0x05, 0x8f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x12,
+ 0x09, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x32, 0x00,
+ 0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3a, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x05, 0x05,
+ 0x00, 0x3f, 0x00, 0x6d, 0x00, 0x88, 0x00, 0x99, 0x00, 0xa3, 0x00, 0xaa,
+ 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8,
+ 0x00, 0xb9, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0x4b, 0x34, 0x51, 0x2f, 0x55, 0x2c, 0x59, 0x29, 0x5c, 0x26, 0x60,
+ 0x24, 0x61, 0x23, 0x64, 0x21, 0x65, 0x20, 0x67, 0x1f, 0x69, 0x1d, 0x69,
+ 0x1d, 0x6a, 0x1d, 0x6c, 0x1c, 0x6d, 0x1b, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d,
+ 0x1a, 0x6f, 0x1a, 0x71, 0x1e, 0x2b, 0x18, 0x34, 0x15, 0x3b, 0x13, 0x43,
+ 0x12, 0x49, 0x11, 0x4e, 0x11, 0x52, 0x10, 0x56, 0x10, 0x5a, 0x10, 0x5d,
+ 0x10, 0x5f, 0x10, 0x61, 0x10, 0x63, 0x10, 0x65, 0x10, 0x66, 0x10, 0x68,
+ 0x10, 0x69, 0x10, 0x6a, 0x10, 0x6b, 0x10, 0x6c, 0x00, 0xd7, 0x00, 0xcd,
+ 0x00, 0xc5, 0x00, 0xbd, 0x00, 0xb6, 0x00, 0xb0, 0x00, 0xab, 0x00, 0xa7,
+ 0x00, 0xa4, 0x00, 0xa1, 0x01, 0x9e, 0x01, 0x9c, 0x02, 0x9a, 0x02, 0x98,
+ 0x02, 0x97, 0x02, 0x96, 0x03, 0x94, 0x03, 0x93, 0x03, 0x92, 0x04, 0x91,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x6d, 0x00, 0x3f, 0x00, 0x1d, 0x00, 0x05,
+ 0x0b, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, 0x00,
+ 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x1c, 0x00, 0x00, 0x12, 0x00, 0x3f,
+ 0x00, 0x62, 0x00, 0x7a, 0x00, 0x8a, 0x00, 0x96, 0x00, 0x9e, 0x00, 0xa4,
+ 0x00, 0xa9, 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x49, 0x36, 0x4f,
+ 0x31, 0x54, 0x2d, 0x57, 0x2a, 0x5a, 0x28, 0x5c, 0x26, 0x60, 0x24, 0x61,
+ 0x23, 0x64, 0x21, 0x65, 0x20, 0x65, 0x20, 0x68, 0x1e, 0x69, 0x1d, 0x69,
+ 0x1d, 0x69, 0x1d, 0x6b, 0x1c, 0x6d, 0x1b, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d,
+ 0x1e, 0x2a, 0x19, 0x32, 0x16, 0x39, 0x13, 0x3f, 0x12, 0x45, 0x11, 0x4a,
+ 0x11, 0x4e, 0x11, 0x52, 0x10, 0x56, 0x10, 0x59, 0x10, 0x5c, 0x10, 0x5d,
+ 0x10, 0x60, 0x10, 0x61, 0x10, 0x63, 0x10, 0x65, 0x10, 0x66, 0x10, 0x67,
+ 0x10, 0x68, 0x10, 0x69, 0x00, 0xd8, 0x00, 0xcf, 0x00, 0xc7, 0x00, 0xc0,
+ 0x00, 0xba, 0x00, 0xb5, 0x00, 0xb0, 0x00, 0xac, 0x00, 0xa8, 0x00, 0xa5,
+ 0x00, 0xa2, 0x00, 0xa0, 0x01, 0x9e, 0x01, 0x9c, 0x02, 0x9a, 0x02, 0x99,
+ 0x02, 0x97, 0x02, 0x96, 0x03, 0x95, 0x03, 0x94, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa,
+ 0x00, 0x88, 0x00, 0x62, 0x00, 0x3f, 0x00, 0x24, 0x00, 0x0f, 0x00, 0x00,
+ 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00,
+ 0x2b, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x2a, 0x00, 0x09, 0x00, 0x00, 0x1d, 0x00, 0x3f, 0x00, 0x5b,
+ 0x00, 0x6f, 0x00, 0x7f, 0x00, 0x8b, 0x00, 0x94, 0x00, 0x9b, 0x00, 0xa0,
+ 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xad, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x48, 0x37, 0x4d, 0x32, 0x51, 0x2f, 0x55,
+ 0x2c, 0x58, 0x29, 0x5b, 0x27, 0x5d, 0x26, 0x60, 0x24, 0x60, 0x23, 0x63,
+ 0x22, 0x65, 0x20, 0x65, 0x20, 0x66, 0x1f, 0x68, 0x1e, 0x69, 0x1d, 0x69,
+ 0x1d, 0x69, 0x1d, 0x6b, 0x1c, 0x6d, 0x1b, 0x6d, 0x1e, 0x29, 0x1a, 0x30,
+ 0x17, 0x36, 0x14, 0x3c, 0x13, 0x41, 0x12, 0x46, 0x11, 0x4a, 0x11, 0x4f,
+ 0x11, 0x52, 0x10, 0x55, 0x10, 0x58, 0x10, 0x5a, 0x10, 0x5c, 0x10, 0x5f,
+ 0x10, 0x60, 0x10, 0x62, 0x10, 0x63, 0x10, 0x65, 0x10, 0x65, 0x10, 0x67,
+ 0x00, 0xd9, 0x00, 0xd1, 0x00, 0xca, 0x00, 0xc3, 0x00, 0xbe, 0x00, 0xb9,
+ 0x00, 0xb4, 0x00, 0xb0, 0x00, 0xac, 0x00, 0xa9, 0x00, 0xa6, 0x00, 0xa3,
+ 0x00, 0xa1, 0x01, 0x9f, 0x01, 0x9d, 0x01, 0x9b, 0x02, 0x9a, 0x02, 0x99,
+ 0x02, 0x98, 0x02, 0x97, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb1, 0x00, 0x99, 0x00, 0x7a,
+ 0x00, 0x5b, 0x00, 0x3f, 0x00, 0x29, 0x00, 0x16, 0x00, 0x08, 0x02, 0x00,
+ 0x0c, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x22, 0x00, 0x25, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x31, 0x00,
+ 0x19, 0x00, 0x00, 0x05, 0x00, 0x24, 0x00, 0x3f, 0x00, 0x56, 0x00, 0x68,
+ 0x00, 0x77, 0x00, 0x82, 0x00, 0x8b, 0x00, 0x93, 0x00, 0x99, 0x00, 0x9d,
+ 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3c, 0x48, 0x37, 0x4c, 0x33, 0x50, 0x30, 0x54, 0x2d, 0x57, 0x2a, 0x59,
+ 0x29, 0x5c, 0x27, 0x5d, 0x26, 0x60, 0x24, 0x60, 0x23, 0x62, 0x22, 0x65,
+ 0x20, 0x65, 0x20, 0x65, 0x20, 0x67, 0x1f, 0x69, 0x1d, 0x69, 0x1d, 0x69,
+ 0x1d, 0x69, 0x1d, 0x6a, 0x1f, 0x28, 0x1a, 0x2e, 0x17, 0x34, 0x15, 0x39,
+ 0x13, 0x3f, 0x13, 0x43, 0x12, 0x48, 0x11, 0x4b, 0x11, 0x4f, 0x11, 0x52,
+ 0x10, 0x55, 0x10, 0x57, 0x10, 0x59, 0x10, 0x5c, 0x10, 0x5d, 0x10, 0x5f,
+ 0x10, 0x61, 0x10, 0x62, 0x10, 0x63, 0x10, 0x64, 0x00, 0xd9, 0x00, 0xd2,
+ 0x00, 0xcc, 0x00, 0xc6, 0x00, 0xc1, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xb3,
+ 0x00, 0xaf, 0x00, 0xac, 0x00, 0xa9, 0x00, 0xa6, 0x00, 0xa4, 0x00, 0xa2,
+ 0x00, 0xa0, 0x01, 0x9e, 0x01, 0x9d, 0x02, 0x9c, 0x02, 0x9a, 0x02, 0x99,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xa3, 0x00, 0x8a, 0x00, 0x6f, 0x00, 0x56,
+ 0x00, 0x3f, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0f, 0x00, 0x04, 0x04, 0x00,
+ 0x0c, 0x00, 0x12, 0x00, 0x17, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x23, 0x00, 0x0b, 0x00,
+ 0x00, 0x0f, 0x00, 0x29, 0x00, 0x3f, 0x00, 0x53, 0x00, 0x63, 0x00, 0x70,
+ 0x00, 0x7b, 0x00, 0x84, 0x00, 0x8b, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x47, 0x38, 0x4b,
+ 0x34, 0x4f, 0x31, 0x53, 0x2e, 0x55, 0x2c, 0x57, 0x2a, 0x5a, 0x28, 0x5c,
+ 0x27, 0x5d, 0x26, 0x60, 0x23, 0x60, 0x23, 0x61, 0x23, 0x64, 0x21, 0x65,
+ 0x20, 0x65, 0x20, 0x65, 0x20, 0x68, 0x1e, 0x69, 0x1d, 0x69, 0x1d, 0x69,
+ 0x1f, 0x27, 0x1b, 0x2d, 0x18, 0x33, 0x16, 0x38, 0x14, 0x3c, 0x13, 0x41,
+ 0x12, 0x44, 0x11, 0x48, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54,
+ 0x10, 0x57, 0x10, 0x59, 0x10, 0x5b, 0x10, 0x5c, 0x10, 0x5e, 0x10, 0x5f,
+ 0x10, 0x61, 0x10, 0x62, 0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcd, 0x00, 0xc8,
+ 0x00, 0xc3, 0x00, 0xbe, 0x00, 0xba, 0x00, 0xb6, 0x00, 0xb2, 0x00, 0xaf,
+ 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa7, 0x00, 0xa5, 0x00, 0xa3, 0x00, 0xa1,
+ 0x01, 0xa0, 0x01, 0x9e, 0x01, 0x9d, 0x02, 0x9c, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb7,
+ 0x00, 0xaa, 0x00, 0x96, 0x00, 0x7f, 0x00, 0x68, 0x00, 0x53, 0x00, 0x3f,
+ 0x00, 0x2e, 0x00, 0x20, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x06, 0x00,
+ 0x0c, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x16,
+ 0x00, 0x2c, 0x00, 0x3f, 0x00, 0x50, 0x00, 0x5e, 0x00, 0x6b, 0x00, 0x75,
+ 0x00, 0x7e, 0x00, 0x85, 0x00, 0x8b, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x47, 0x38, 0x4b, 0x35, 0x4e, 0x32, 0x51,
+ 0x2f, 0x53, 0x2d, 0x57, 0x2b, 0x58, 0x2a, 0x5b, 0x27, 0x5c, 0x27, 0x5d,
+ 0x25, 0x60, 0x23, 0x60, 0x23, 0x61, 0x23, 0x64, 0x21, 0x65, 0x20, 0x65,
+ 0x20, 0x65, 0x20, 0x66, 0x1f, 0x69, 0x1e, 0x69, 0x1f, 0x27, 0x1b, 0x2c,
+ 0x18, 0x31, 0x16, 0x36, 0x14, 0x3a, 0x13, 0x3e, 0x13, 0x42, 0x12, 0x45,
+ 0x11, 0x49, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54, 0x10, 0x56,
+ 0x10, 0x58, 0x10, 0x5a, 0x10, 0x5c, 0x10, 0x5d, 0x10, 0x5e, 0x10, 0x60,
+ 0x00, 0xd9, 0x00, 0xd4, 0x00, 0xce, 0x00, 0xca, 0x00, 0xc5, 0x00, 0xc1,
+ 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb6, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad,
+ 0x00, 0xaa, 0x00, 0xa8, 0x00, 0xa6, 0x00, 0xa4, 0x00, 0xa2, 0x00, 0xa0,
+ 0x01, 0x9f, 0x01, 0x9e, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e,
+ 0x00, 0x8b, 0x00, 0x77, 0x00, 0x63, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x30,
+ 0x00, 0x23, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x39, 0x00,
+ 0x2f, 0x00, 0x1f, 0x00, 0x0b, 0x00, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x2e,
+ 0x00, 0x3f, 0x00, 0x4e, 0x00, 0x5b, 0x00, 0x66, 0x00, 0x70, 0x00, 0x78,
+ 0x00, 0x80, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x46, 0x39, 0x4a, 0x35, 0x4d, 0x32, 0x50, 0x30, 0x53, 0x2e, 0x55,
+ 0x2c, 0x57, 0x2a, 0x58, 0x29, 0x5c, 0x27, 0x5c, 0x27, 0x5d, 0x25, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x63, 0x22, 0x65, 0x20, 0x65, 0x20, 0x65,
+ 0x20, 0x65, 0x20, 0x67, 0x1f, 0x27, 0x1c, 0x2c, 0x19, 0x30, 0x17, 0x35,
+ 0x15, 0x39, 0x14, 0x3d, 0x13, 0x40, 0x12, 0x44, 0x12, 0x47, 0x11, 0x49,
+ 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54, 0x10, 0x56, 0x10, 0x58,
+ 0x10, 0x59, 0x10, 0x5b, 0x10, 0x5c, 0x10, 0x5e, 0x00, 0xda, 0x00, 0xd4,
+ 0x00, 0xd0, 0x00, 0xcb, 0x00, 0xc7, 0x00, 0xc2, 0x00, 0xbe, 0x00, 0xbb,
+ 0x00, 0xb8, 0x00, 0xb5, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa,
+ 0x00, 0xa8, 0x00, 0xa6, 0x00, 0xa4, 0x00, 0xa3, 0x00, 0xa1, 0x01, 0xa0,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x82,
+ 0x00, 0x70, 0x00, 0x5e, 0x00, 0x4e, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x26,
+ 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x25, 0x00,
+ 0x14, 0x00, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x20, 0x00, 0x30, 0x00, 0x3f,
+ 0x00, 0x4d, 0x00, 0x58, 0x00, 0x63, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x7b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x46, 0x39, 0x49,
+ 0x36, 0x4c, 0x33, 0x4f, 0x31, 0x52, 0x2e, 0x53, 0x2d, 0x57, 0x2b, 0x57,
+ 0x2a, 0x59, 0x28, 0x5c, 0x27, 0x5c, 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x62, 0x22, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65,
+ 0x1f, 0x26, 0x1c, 0x2b, 0x19, 0x2f, 0x17, 0x33, 0x16, 0x37, 0x14, 0x3b,
+ 0x13, 0x3e, 0x13, 0x41, 0x12, 0x44, 0x11, 0x47, 0x11, 0x4a, 0x11, 0x4d,
+ 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54, 0x10, 0x55, 0x10, 0x57, 0x10, 0x59,
+ 0x10, 0x5a, 0x10, 0x5b, 0x00, 0xda, 0x00, 0xd5, 0x00, 0xd1, 0x00, 0xcc,
+ 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc1, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb7,
+ 0x00, 0xb4, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa9,
+ 0x00, 0xa7, 0x00, 0xa5, 0x00, 0xa4, 0x00, 0xa2, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb,
+ 0x00, 0xb4, 0x00, 0xa9, 0x00, 0x9b, 0x00, 0x8b, 0x00, 0x7b, 0x00, 0x6b,
+ 0x00, 0x5b, 0x00, 0x4d, 0x00, 0x3f, 0x00, 0x33, 0x00, 0x28, 0x00, 0x1f,
+ 0x00, 0x16, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x3c, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0c, 0x00,
+ 0x00, 0x04, 0x00, 0x14, 0x00, 0x23, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4b,
+ 0x00, 0x56, 0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x39, 0x48, 0x36, 0x4b, 0x34, 0x4f,
+ 0x31, 0x50, 0x30, 0x53, 0x2e, 0x55, 0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x5a,
+ 0x28, 0x5c, 0x27, 0x5c, 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x61, 0x22, 0x64, 0x21, 0x65, 0x20, 0x65, 0x20, 0x26, 0x1c, 0x2a,
+ 0x1a, 0x2e, 0x18, 0x32, 0x16, 0x36, 0x14, 0x39, 0x13, 0x3d, 0x13, 0x40,
+ 0x12, 0x43, 0x12, 0x45, 0x11, 0x48, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f,
+ 0x11, 0x51, 0x10, 0x53, 0x10, 0x55, 0x10, 0x56, 0x10, 0x58, 0x10, 0x5a,
+ 0x00, 0xda, 0x00, 0xd6, 0x00, 0xd1, 0x00, 0xcd, 0x00, 0xc9, 0x00, 0xc6,
+ 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbc, 0x00, 0xb9, 0x00, 0xb6, 0x00, 0xb3,
+ 0x00, 0xb1, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa7,
+ 0x00, 0xa6, 0x00, 0xa4, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xac,
+ 0x00, 0xa0, 0x00, 0x93, 0x00, 0x84, 0x00, 0x75, 0x00, 0x66, 0x00, 0x58,
+ 0x00, 0x4b, 0x00, 0x3f, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x19,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00,
+ 0x36, 0x00, 0x2d, 0x00, 0x21, 0x00, 0x13, 0x00, 0x04, 0x00, 0x00, 0x0a,
+ 0x00, 0x18, 0x00, 0x26, 0x00, 0x33, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x54,
+ 0x00, 0x5d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x45, 0x3a, 0x48, 0x37, 0x4a, 0x35, 0x4e, 0x32, 0x4f, 0x31, 0x53,
+ 0x2e, 0x53, 0x2e, 0x56, 0x2b, 0x57, 0x2a, 0x58, 0x29, 0x5b, 0x27, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x61,
+ 0x23, 0x64, 0x21, 0x65, 0x20, 0x26, 0x1d, 0x2a, 0x1a, 0x2d, 0x18, 0x31,
+ 0x17, 0x35, 0x15, 0x38, 0x14, 0x3b, 0x13, 0x3e, 0x13, 0x41, 0x12, 0x44,
+ 0x12, 0x46, 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11, 0x51,
+ 0x10, 0x53, 0x10, 0x55, 0x10, 0x56, 0x10, 0x58, 0x00, 0xda, 0x00, 0xd6,
+ 0x00, 0xd2, 0x00, 0xce, 0x00, 0xcb, 0x00, 0xc7, 0x00, 0xc4, 0x00, 0xc1,
+ 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb3, 0x00, 0xb1,
+ 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa8, 0x00, 0xa6,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99,
+ 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x70, 0x00, 0x63, 0x00, 0x56, 0x00, 0x4a,
+ 0x00, 0x3f, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x30, 0x00,
+ 0x25, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x1c,
+ 0x00, 0x28, 0x00, 0x34, 0x00, 0x3f, 0x00, 0x49, 0x00, 0x53, 0x00, 0x5b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x3a, 0x47,
+ 0x38, 0x4a, 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x51, 0x2f, 0x53, 0x2e, 0x54,
+ 0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x59, 0x29, 0x5c, 0x27, 0x5c, 0x27, 0x5c,
+ 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x63,
+ 0x20, 0x25, 0x1d, 0x29, 0x1a, 0x2d, 0x18, 0x30, 0x17, 0x33, 0x16, 0x37,
+ 0x14, 0x3a, 0x13, 0x3d, 0x13, 0x3f, 0x13, 0x42, 0x12, 0x44, 0x11, 0x47,
+ 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x53,
+ 0x10, 0x55, 0x10, 0x56, 0x00, 0xdb, 0x00, 0xd7, 0x00, 0xd3, 0x00, 0xcf,
+ 0x00, 0xcc, 0x00, 0xc8, 0x00, 0xc5, 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbc,
+ 0x00, 0xba, 0x00, 0xb7, 0x00, 0xb5, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf,
+ 0x00, 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa8, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd,
+ 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9d, 0x00, 0x92, 0x00, 0x85,
+ 0x00, 0x78, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3f,
+ 0x00, 0x36, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x32, 0x00, 0x29, 0x00, 0x1e, 0x00,
+ 0x12, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a,
+ 0x00, 0x35, 0x00, 0x3f, 0x00, 0x49, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x44, 0x3a, 0x47, 0x38, 0x4a, 0x35, 0x4c,
+ 0x33, 0x4f, 0x31, 0x50, 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x56, 0x2b, 0x57,
+ 0x2a, 0x57, 0x2a, 0x5a, 0x28, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5f,
+ 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x20, 0x25, 0x1d, 0x29,
+ 0x1b, 0x2c, 0x18, 0x2f, 0x17, 0x33, 0x16, 0x36, 0x14, 0x39, 0x14, 0x3b,
+ 0x13, 0x3e, 0x13, 0x41, 0x12, 0x43, 0x12, 0x45, 0x11, 0x47, 0x11, 0x4a,
+ 0x11, 0x4c, 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x52, 0x10, 0x54,
+ 0x00, 0xdb, 0x00, 0xd7, 0x00, 0xd3, 0x00, 0xd0, 0x00, 0xcc, 0x00, 0xc9,
+ 0x00, 0xc6, 0x00, 0xc3, 0x00, 0xc1, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb9,
+ 0x00, 0xb7, 0x00, 0xb5, 0x00, 0xb3, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad,
+ 0x00, 0xab, 0x00, 0xaa, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb3,
+ 0x00, 0xab, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x74,
+ 0x00, 0x68, 0x00, 0x5d, 0x00, 0x53, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00,
+ 0x3a, 0x00, 0x33, 0x00, 0x2b, 0x00, 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00,
+ 0x00, 0x00, 0x00, 0x0b, 0x00, 0x16, 0x00, 0x21, 0x00, 0x2c, 0x00, 0x36,
+ 0x00, 0x3f, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x44, 0x3b, 0x46, 0x39, 0x4a, 0x35, 0x4b, 0x34, 0x4f, 0x31, 0x4f,
+ 0x31, 0x53, 0x2e, 0x53, 0x2e, 0x54, 0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x58,
+ 0x2a, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5f, 0x24, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x20, 0x25, 0x1d, 0x28, 0x1b, 0x2b, 0x19, 0x2f,
+ 0x17, 0x32, 0x16, 0x35, 0x15, 0x38, 0x14, 0x3a, 0x13, 0x3d, 0x13, 0x3f,
+ 0x13, 0x42, 0x12, 0x44, 0x12, 0x46, 0x11, 0x48, 0x11, 0x4a, 0x11, 0x4c,
+ 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x52, 0x00, 0xdb, 0x00, 0xd7,
+ 0x00, 0xd4, 0x00, 0xd0, 0x00, 0xcd, 0x00, 0xca, 0x00, 0xc7, 0x00, 0xc5,
+ 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb6,
+ 0x00, 0xb4, 0x00, 0xb2, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xac,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb4, 0x00, 0xad, 0x00, 0xa5,
+ 0x00, 0x9b, 0x00, 0x91, 0x00, 0x86, 0x00, 0x7b, 0x00, 0x70, 0x00, 0x65,
+ 0x00, 0x5b, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00,
+ 0x2e, 0x00, 0x25, 0x00, 0x1c, 0x00, 0x11, 0x00, 0x07, 0x00, 0x00, 0x03,
+ 0x00, 0x0e, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x44, 0x3b, 0x46,
+ 0x39, 0x49, 0x36, 0x4a, 0x35, 0x4e, 0x32, 0x4f, 0x31, 0x51, 0x2f, 0x53,
+ 0x2e, 0x53, 0x2e, 0x56, 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x58, 0x29, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x26, 0x5f, 0x24, 0x60, 0x23, 0x60,
+ 0x20, 0x25, 0x1d, 0x28, 0x1c, 0x2b, 0x1a, 0x2e, 0x18, 0x31, 0x17, 0x34,
+ 0x16, 0x37, 0x14, 0x39, 0x13, 0x3b, 0x13, 0x3e, 0x13, 0x40, 0x12, 0x42,
+ 0x12, 0x45, 0x11, 0x46, 0x11, 0x49, 0x11, 0x4a, 0x11, 0x4c, 0x11, 0x4e,
+ 0x11, 0x4f, 0x11, 0x51, 0x00, 0xdb, 0x00, 0xd8, 0x00, 0xd4, 0x00, 0xd1,
+ 0x00, 0xce, 0x00, 0xcb, 0x00, 0xc8, 0x00, 0xc6, 0x00, 0xc3, 0x00, 0xc1,
+ 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xba, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb4,
+ 0x00, 0xb2, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x56, 0x7f, 0x47, 0x63,
+ 0x44, 0x57, 0x43, 0x52, 0x43, 0x4e, 0x42, 0x4c, 0x42, 0x4a, 0x42, 0x49,
+ 0x42, 0x48, 0x42, 0x47, 0x42, 0x46, 0x42, 0x45, 0x42, 0x45, 0x42, 0x45,
+ 0x42, 0x44, 0x42, 0x44, 0x42, 0x44, 0x42, 0x43, 0x42, 0x43, 0x42, 0x43,
+ 0x4c, 0x7f, 0x27, 0x4d, 0x2f, 0x46, 0x33, 0x44, 0x36, 0x43, 0x37, 0x43,
+ 0x39, 0x42, 0x3a, 0x41, 0x3a, 0x41, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x41,
+ 0x3c, 0x41, 0x3c, 0x41, 0x3c, 0x41, 0x3c, 0x41, 0x3c, 0x41, 0x3d, 0x41,
+ 0x3d, 0x41, 0x3d, 0x41, 0x8e, 0x7f, 0x47, 0x4d, 0x44, 0x46, 0x43, 0x44,
+ 0x43, 0x43, 0x42, 0x43, 0x42, 0x42, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41,
+ 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41,
+ 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x0d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x85, 0x1b, 0x60, 0x27, 0x54, 0x2d, 0x4e, 0x30,
+ 0x4b, 0x33, 0x49, 0x34, 0x47, 0x35, 0x46, 0x37, 0x45, 0x38, 0x45, 0x38,
+ 0x44, 0x39, 0x43, 0x39, 0x43, 0x3a, 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b,
+ 0x42, 0x3b, 0x42, 0x3b, 0x42, 0x3b, 0x42, 0x3b, 0x09, 0x43, 0x16, 0x3f,
+ 0x1f, 0x3e, 0x25, 0x3e, 0x29, 0x3e, 0x2c, 0x3e, 0x2f, 0x3e, 0x30, 0x3e,
+ 0x32, 0x3e, 0x33, 0x3e, 0x34, 0x3e, 0x35, 0x3e, 0x36, 0x3e, 0x36, 0x3e,
+ 0x37, 0x3e, 0x37, 0x3e, 0x38, 0x3e, 0x38, 0x3e, 0x38, 0x3e, 0x39, 0x3e,
+ 0x59, 0x31, 0x4f, 0x38, 0x4b, 0x3a, 0x48, 0x3b, 0x47, 0x3c, 0x46, 0x3c,
+ 0x45, 0x3d, 0x45, 0x3d, 0x44, 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x4c, 0x00, 0x2f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x4f, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x96, 0x05, 0x74, 0x0f, 0x63, 0x17, 0x5a, 0x1d, 0x54, 0x21, 0x51, 0x24,
+ 0x4e, 0x27, 0x4c, 0x29, 0x4a, 0x2b, 0x49, 0x2d, 0x49, 0x2e, 0x48, 0x2f,
+ 0x48, 0x31, 0x47, 0x31, 0x46, 0x32, 0x46, 0x33, 0x44, 0x33, 0x44, 0x34,
+ 0x43, 0x34, 0x43, 0x35, 0x09, 0x43, 0x11, 0x3e, 0x18, 0x3c, 0x1d, 0x3c,
+ 0x22, 0x3c, 0x25, 0x3c, 0x27, 0x3c, 0x2a, 0x3c, 0x2c, 0x3d, 0x2d, 0x3d,
+ 0x2f, 0x3d, 0x30, 0x3e, 0x31, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x33, 0x3e,
+ 0x33, 0x3e, 0x34, 0x3e, 0x35, 0x3e, 0x35, 0x3e, 0x5b, 0x2a, 0x53, 0x31,
+ 0x4f, 0x34, 0x4c, 0x36, 0x4b, 0x38, 0x4a, 0x39, 0x48, 0x39, 0x47, 0x3a,
+ 0x46, 0x3b, 0x46, 0x3b, 0x46, 0x3c, 0x46, 0x3c, 0x46, 0x3d, 0x45, 0x3d,
+ 0x44, 0x3d, 0x44, 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x45,
+ 0x00, 0x22, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x8f, 0x00, 0x73, 0x00, 0x38, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x9e, 0x01, 0x81, 0x06,
+ 0x6f, 0x0d, 0x64, 0x12, 0x5d, 0x16, 0x58, 0x1a, 0x54, 0x1d, 0x53, 0x20,
+ 0x50, 0x22, 0x4e, 0x24, 0x4c, 0x26, 0x4b, 0x27, 0x4a, 0x29, 0x49, 0x2a,
+ 0x49, 0x2b, 0x49, 0x2c, 0x48, 0x2d, 0x48, 0x2e, 0x48, 0x2f, 0x47, 0x2f,
+ 0x09, 0x44, 0x0f, 0x3e, 0x14, 0x3c, 0x19, 0x3c, 0x1d, 0x3b, 0x20, 0x3b,
+ 0x23, 0x3b, 0x25, 0x3c, 0x27, 0x3c, 0x28, 0x3c, 0x2a, 0x3b, 0x2c, 0x3b,
+ 0x2c, 0x3b, 0x2d, 0x3b, 0x2f, 0x3c, 0x2f, 0x3c, 0x30, 0x3d, 0x31, 0x3e,
+ 0x32, 0x3e, 0x32, 0x3e, 0x5c, 0x28, 0x56, 0x2d, 0x52, 0x31, 0x4f, 0x33,
+ 0x4e, 0x35, 0x4b, 0x36, 0x4a, 0x37, 0x4a, 0x38, 0x49, 0x39, 0x47, 0x39,
+ 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x3a, 0x46, 0x3a, 0x46, 0x3b,
+ 0x46, 0x3c, 0x46, 0x3c, 0x46, 0x3d, 0x45, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x19,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x84, 0x00,
+ 0x5b, 0x00, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xa4, 0x00, 0x8a, 0x03, 0x78, 0x07, 0x6d, 0x0c,
+ 0x65, 0x10, 0x60, 0x13, 0x5b, 0x16, 0x57, 0x19, 0x55, 0x1b, 0x53, 0x1e,
+ 0x52, 0x1f, 0x4f, 0x22, 0x4d, 0x23, 0x4c, 0x24, 0x4b, 0x25, 0x4b, 0x27,
+ 0x4a, 0x28, 0x49, 0x29, 0x49, 0x29, 0x49, 0x2b, 0x09, 0x45, 0x0d, 0x40,
+ 0x11, 0x3d, 0x16, 0x3c, 0x19, 0x3b, 0x1d, 0x3b, 0x1f, 0x3b, 0x21, 0x3a,
+ 0x23, 0x3b, 0x25, 0x3b, 0x26, 0x3c, 0x28, 0x3c, 0x29, 0x3c, 0x2a, 0x3b,
+ 0x2b, 0x3b, 0x2c, 0x3b, 0x2d, 0x3b, 0x2e, 0x3b, 0x2e, 0x3b, 0x2f, 0x3b,
+ 0x5d, 0x27, 0x57, 0x2c, 0x54, 0x2f, 0x52, 0x31, 0x4f, 0x32, 0x4e, 0x34,
+ 0x4c, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x37, 0x4a, 0x38, 0x48, 0x39,
+ 0x47, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39,
+ 0x46, 0x39, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5b, 0x00, 0x55, 0x00, 0x42, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x8d, 0x00, 0x6f, 0x00, 0x48, 0x00,
+ 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xa7, 0x00, 0x91, 0x01, 0x80, 0x04, 0x75, 0x08, 0x6c, 0x0b, 0x65, 0x0e,
+ 0x61, 0x11, 0x5d, 0x14, 0x59, 0x16, 0x56, 0x19, 0x55, 0x1a, 0x54, 0x1c,
+ 0x53, 0x1e, 0x51, 0x1f, 0x4f, 0x21, 0x4d, 0x22, 0x4c, 0x23, 0x4b, 0x24,
+ 0x4b, 0x25, 0x4b, 0x26, 0x09, 0x45, 0x0d, 0x41, 0x10, 0x3e, 0x14, 0x3d,
+ 0x17, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1e, 0x3b, 0x20, 0x3b, 0x22, 0x3a,
+ 0x23, 0x3a, 0x25, 0x3b, 0x26, 0x3c, 0x28, 0x3c, 0x28, 0x3c, 0x29, 0x3c,
+ 0x2a, 0x3c, 0x2b, 0x3b, 0x2c, 0x3b, 0x2d, 0x3b, 0x5d, 0x26, 0x59, 0x2a,
+ 0x56, 0x2d, 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x32, 0x4f, 0x33, 0x4d, 0x35,
+ 0x4b, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x37, 0x4a, 0x38, 0x49, 0x39,
+ 0x48, 0x39, 0x47, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58,
+ 0x00, 0x4a, 0x00, 0x38, 0x00, 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x00, 0x92, 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xa9, 0x00, 0x96, 0x00,
+ 0x86, 0x02, 0x7a, 0x05, 0x72, 0x08, 0x6b, 0x0b, 0x65, 0x0e, 0x62, 0x10,
+ 0x5f, 0x12, 0x5b, 0x14, 0x58, 0x16, 0x56, 0x18, 0x55, 0x1a, 0x54, 0x1b,
+ 0x53, 0x1d, 0x52, 0x1e, 0x50, 0x1f, 0x4f, 0x20, 0x4d, 0x21, 0x4c, 0x22,
+ 0x09, 0x46, 0x0c, 0x41, 0x0f, 0x3f, 0x12, 0x3d, 0x15, 0x3c, 0x17, 0x3c,
+ 0x1a, 0x3b, 0x1c, 0x3a, 0x1e, 0x3b, 0x1f, 0x3b, 0x21, 0x3a, 0x22, 0x3a,
+ 0x24, 0x3a, 0x25, 0x3a, 0x26, 0x3b, 0x27, 0x3c, 0x28, 0x3c, 0x29, 0x3c,
+ 0x2a, 0x3c, 0x2a, 0x3c, 0x5e, 0x26, 0x5a, 0x29, 0x57, 0x2c, 0x53, 0x2e,
+ 0x53, 0x30, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x33, 0x4e, 0x34, 0x4c, 0x35,
+ 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x37, 0x4a, 0x38,
+ 0x48, 0x39, 0x47, 0x39, 0x46, 0x39, 0x46, 0x39, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40,
+ 0x00, 0x2f, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x95, 0x00,
+ 0x84, 0x00, 0x6c, 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xab, 0x00, 0x9a, 0x00, 0x8b, 0x01, 0x7f, 0x03,
+ 0x77, 0x06, 0x71, 0x08, 0x6a, 0x0b, 0x66, 0x0d, 0x63, 0x0f, 0x60, 0x11,
+ 0x5d, 0x13, 0x59, 0x14, 0x57, 0x16, 0x56, 0x18, 0x55, 0x19, 0x54, 0x1b,
+ 0x53, 0x1c, 0x53, 0x1d, 0x51, 0x1e, 0x50, 0x1f, 0x0a, 0x46, 0x0c, 0x42,
+ 0x0e, 0x3f, 0x11, 0x3f, 0x13, 0x3c, 0x16, 0x3c, 0x18, 0x3c, 0x1a, 0x3b,
+ 0x1c, 0x3a, 0x1e, 0x3b, 0x1f, 0x3b, 0x20, 0x3b, 0x21, 0x3a, 0x23, 0x3a,
+ 0x24, 0x3a, 0x25, 0x39, 0x26, 0x3a, 0x27, 0x3c, 0x27, 0x3c, 0x28, 0x3c,
+ 0x5e, 0x26, 0x5a, 0x29, 0x57, 0x2b, 0x55, 0x2d, 0x53, 0x2e, 0x53, 0x30,
+ 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x32, 0x4f, 0x34, 0x4d, 0x35, 0x4b, 0x35,
+ 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x38,
+ 0x4a, 0x39, 0x48, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29,
+ 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76, 0x00,
+ 0x5e, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xac, 0x00, 0x9d, 0x00, 0x8f, 0x01, 0x85, 0x02, 0x7b, 0x04, 0x75, 0x06,
+ 0x6f, 0x08, 0x69, 0x0b, 0x66, 0x0d, 0x63, 0x0e, 0x61, 0x10, 0x5e, 0x12,
+ 0x5b, 0x13, 0x58, 0x15, 0x57, 0x16, 0x56, 0x18, 0x55, 0x19, 0x55, 0x1a,
+ 0x54, 0x1b, 0x53, 0x1c, 0x0a, 0x47, 0x0b, 0x42, 0x0e, 0x40, 0x10, 0x3f,
+ 0x12, 0x3d, 0x15, 0x3c, 0x17, 0x3c, 0x18, 0x3c, 0x1a, 0x3b, 0x1c, 0x3a,
+ 0x1d, 0x3b, 0x1f, 0x3b, 0x20, 0x3b, 0x21, 0x3b, 0x22, 0x3a, 0x23, 0x3a,
+ 0x24, 0x3a, 0x25, 0x39, 0x26, 0x3a, 0x27, 0x3b, 0x5e, 0x26, 0x5b, 0x28,
+ 0x57, 0x2a, 0x57, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x33, 0x4e, 0x35, 0x4b, 0x35, 0x4a, 0x35,
+ 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x37,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c,
+ 0x00, 0x55, 0x00, 0x4b, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17,
+ 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53, 0x00,
+ 0x3c, 0x00, 0x26, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xad, 0x00, 0xa0, 0x00,
+ 0x92, 0x00, 0x89, 0x02, 0x7f, 0x03, 0x78, 0x05, 0x73, 0x07, 0x6e, 0x09,
+ 0x69, 0x0b, 0x66, 0x0c, 0x64, 0x0e, 0x62, 0x0f, 0x60, 0x11, 0x5c, 0x12,
+ 0x59, 0x14, 0x58, 0x15, 0x57, 0x16, 0x56, 0x18, 0x55, 0x18, 0x55, 0x1a,
+ 0x0a, 0x47, 0x0b, 0x43, 0x0d, 0x41, 0x0f, 0x3f, 0x11, 0x3f, 0x13, 0x3c,
+ 0x15, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x1a, 0x3b, 0x1c, 0x3a, 0x1d, 0x3a,
+ 0x1f, 0x3b, 0x1f, 0x3b, 0x21, 0x3b, 0x21, 0x3b, 0x22, 0x3a, 0x24, 0x3a,
+ 0x24, 0x3a, 0x24, 0x39, 0x5e, 0x26, 0x5c, 0x27, 0x58, 0x2a, 0x57, 0x2b,
+ 0x55, 0x2e, 0x53, 0x2e, 0x53, 0x2f, 0x52, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x32, 0x4e, 0x34, 0x4c, 0x35, 0x4a, 0x35, 0x4a, 0x35,
+ 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f,
+ 0x00, 0x44, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00,
+ 0x91, 0x00, 0x83, 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36, 0x00,
+ 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xae, 0x00, 0xa2, 0x00, 0x95, 0x00, 0x8b, 0x01,
+ 0x83, 0x02, 0x7b, 0x04, 0x76, 0x05, 0x73, 0x07, 0x6e, 0x09, 0x69, 0x0a,
+ 0x66, 0x0c, 0x64, 0x0d, 0x62, 0x0f, 0x61, 0x10, 0x5e, 0x11, 0x5b, 0x13,
+ 0x58, 0x14, 0x58, 0x15, 0x56, 0x16, 0x56, 0x18, 0x0a, 0x47, 0x0b, 0x43,
+ 0x0d, 0x42, 0x0f, 0x3f, 0x11, 0x3f, 0x12, 0x3e, 0x14, 0x3c, 0x16, 0x3c,
+ 0x17, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3a, 0x1d, 0x39, 0x1f, 0x3b,
+ 0x1f, 0x3b, 0x20, 0x3b, 0x21, 0x3b, 0x21, 0x3a, 0x22, 0x3a, 0x24, 0x3a,
+ 0x5e, 0x26, 0x5c, 0x27, 0x59, 0x2a, 0x57, 0x2a, 0x56, 0x2c, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x32, 0x4f, 0x33, 0x4d, 0x35, 0x4b, 0x35, 0x4a, 0x35, 0x4a, 0x35,
+ 0x4a, 0x35, 0x4a, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e,
+ 0x00, 0x33, 0x00, 0x28, 0x00, 0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88, 0x00,
+ 0x79, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xaf, 0x00, 0xa3, 0x00, 0x98, 0x00, 0x8e, 0x00, 0x87, 0x02, 0x7f, 0x03,
+ 0x79, 0x04, 0x75, 0x06, 0x71, 0x07, 0x6c, 0x09, 0x68, 0x0a, 0x66, 0x0c,
+ 0x64, 0x0d, 0x63, 0x0e, 0x61, 0x10, 0x5f, 0x11, 0x5c, 0x12, 0x59, 0x13,
+ 0x58, 0x14, 0x58, 0x15, 0x0a, 0x47, 0x0b, 0x43, 0x0d, 0x42, 0x0e, 0x40,
+ 0x10, 0x3e, 0x11, 0x3f, 0x13, 0x3c, 0x15, 0x3b, 0x17, 0x3c, 0x17, 0x3c,
+ 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x39, 0x1e, 0x3a, 0x1f, 0x3b,
+ 0x1f, 0x3b, 0x21, 0x3b, 0x21, 0x3b, 0x22, 0x3a, 0x5e, 0x25, 0x5c, 0x27,
+ 0x5a, 0x29, 0x57, 0x2a, 0x57, 0x2b, 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2f, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x33, 0x4e, 0x34, 0x4c, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d,
+ 0x00, 0x59, 0x00, 0x53, 0x00, 0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e,
+ 0x00, 0x24, 0x00, 0x1a, 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f, 0x00,
+ 0x5f, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xaf, 0x00, 0xa5, 0x00,
+ 0x9a, 0x00, 0x90, 0x00, 0x8a, 0x01, 0x83, 0x02, 0x7c, 0x03, 0x77, 0x05,
+ 0x74, 0x06, 0x70, 0x07, 0x6c, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x64, 0x0c,
+ 0x63, 0x0e, 0x61, 0x0f, 0x60, 0x11, 0x5d, 0x11, 0x5b, 0x13, 0x59, 0x13,
+ 0x0a, 0x47, 0x0a, 0x44, 0x0d, 0x42, 0x0e, 0x41, 0x0f, 0x3e, 0x11, 0x3f,
+ 0x13, 0x3e, 0x14, 0x3c, 0x15, 0x3a, 0x17, 0x3c, 0x17, 0x3c, 0x19, 0x3c,
+ 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x39, 0x1e, 0x3a, 0x1f, 0x3b, 0x1f, 0x3b,
+ 0x20, 0x3b, 0x21, 0x3b, 0x5e, 0x25, 0x5c, 0x27, 0x5a, 0x29, 0x57, 0x2a,
+ 0x57, 0x2a, 0x56, 0x2d, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x30,
+ 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x32,
+ 0x4f, 0x33, 0x4d, 0x35, 0x4b, 0x35, 0x4a, 0x35, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55,
+ 0x00, 0x4e, 0x00, 0x46, 0x00, 0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21,
+ 0x00, 0x18, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
+ 0x97, 0x00, 0x8e, 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57, 0x00,
+ 0x47, 0x00, 0x37, 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xb0, 0x00, 0xa6, 0x00, 0x9d, 0x00, 0x92, 0x00,
+ 0x8c, 0x01, 0x86, 0x02, 0x7e, 0x02, 0x7a, 0x04, 0x76, 0x05, 0x73, 0x06,
+ 0x70, 0x07, 0x6b, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c, 0x63, 0x0e,
+ 0x62, 0x0e, 0x61, 0x10, 0x5e, 0x11, 0x5c, 0x12, 0x0a, 0x47, 0x0a, 0x44,
+ 0x0c, 0x42, 0x0d, 0x41, 0x0f, 0x3f, 0x11, 0x3f, 0x11, 0x3f, 0x13, 0x3d,
+ 0x15, 0x3c, 0x16, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x1a, 0x3b,
+ 0x1c, 0x3b, 0x1c, 0x39, 0x1e, 0x39, 0x1f, 0x3b, 0x1f, 0x3b, 0x1f, 0x3b,
+ 0x5f, 0x25, 0x5c, 0x27, 0x5b, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2b,
+ 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x33,
+ 0x4e, 0x34, 0x4c, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49,
+ 0x00, 0x41, 0x00, 0x39, 0x00, 0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16,
+ 0x00, 0x0e, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90, 0x00,
+ 0x86, 0x00, 0x7a, 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41, 0x00,
+ 0x33, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xb0, 0x00, 0xa7, 0x00, 0x9f, 0x00, 0x95, 0x00, 0x8e, 0x00, 0x88, 0x01,
+ 0x82, 0x02, 0x7c, 0x03, 0x78, 0x05, 0x75, 0x06, 0x72, 0x07, 0x6f, 0x08,
+ 0x6a, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c, 0x63, 0x0d, 0x62, 0x0e,
+ 0x61, 0x0f, 0x60, 0x11, 0x0a, 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0d, 0x42,
+ 0x0e, 0x40, 0x10, 0x3d, 0x11, 0x3f, 0x13, 0x3e, 0x14, 0x3c, 0x15, 0x3b,
+ 0x17, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b,
+ 0x1c, 0x3a, 0x1d, 0x39, 0x1f, 0x3a, 0x1f, 0x3b, 0x5f, 0x25, 0x5c, 0x27,
+ 0x5c, 0x27, 0x58, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x2d, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x32, 0x4f, 0x34,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e,
+ 0x00, 0x5b, 0x00, 0x57, 0x00, 0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d,
+ 0x00, 0x35, 0x00, 0x2c, 0x00, 0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d,
+ 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00,
+ 0x72, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f, 0x00,
+ 0x22, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xb1, 0x00, 0xa7, 0x00,
+ 0xa0, 0x00, 0x97, 0x00, 0x90, 0x00, 0x8a, 0x01, 0x85, 0x02, 0x7e, 0x02,
+ 0x7a, 0x03, 0x77, 0x05, 0x74, 0x06, 0x72, 0x07, 0x6e, 0x08, 0x6a, 0x09,
+ 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c, 0x63, 0x0d, 0x63, 0x0e, 0x61, 0x0f,
+ 0x0a, 0x47, 0x0a, 0x45, 0x0b, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x0f, 0x3e,
+ 0x11, 0x3f, 0x12, 0x3f, 0x13, 0x3d, 0x15, 0x3c, 0x15, 0x3a, 0x17, 0x3c,
+ 0x17, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x3a,
+ 0x1d, 0x39, 0x1f, 0x39, 0x5f, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x59, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x00, 0x17, 0x00, 0x2f,
+ 0x00, 0x4c, 0x00, 0x56, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5d, 0x00, 0x5d,
+ 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f,
+ 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x6c, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x62,
+ 0x00, 0x62, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e,
+ 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x14, 0x01, 0x29,
+ 0x00, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d,
+ 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e,
+ 0x00, 0x5f, 0x00, 0x5f, 0x31, 0x11, 0x03, 0x23, 0x00, 0x46, 0x00, 0x52,
+ 0x00, 0x58, 0x00, 0x5a, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e,
+ 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xb1, 0x00, 0xa8, 0x00, 0xa1, 0x00, 0x99, 0x00,
+ 0x91, 0x00, 0x8c, 0x00, 0x88, 0x01, 0x82, 0x02, 0x7c, 0x03, 0x79, 0x04,
+ 0x76, 0x05, 0x74, 0x06, 0x71, 0x07, 0x6d, 0x08, 0x6a, 0x09, 0x68, 0x0a,
+ 0x66, 0x0b, 0x65, 0x0c, 0x64, 0x0c, 0x63, 0x0e, 0x0a, 0x47, 0x0a, 0x45,
+ 0x0b, 0x42, 0x0d, 0x42, 0x0e, 0x41, 0x0f, 0x3f, 0x11, 0x3e, 0x11, 0x3f,
+ 0x13, 0x3e, 0x13, 0x3c, 0x15, 0x3c, 0x16, 0x3a, 0x17, 0x3c, 0x17, 0x3c,
+ 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x3a, 0x1d, 0x39,
+ 0x5f, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5a, 0x29, 0x57, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x55, 0x2d, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x2f, 0x00, 0x45,
+ 0x00, 0x4f, 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c,
+ 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e,
+ 0x00, 0x4c, 0x00, 0x3b, 0x00, 0x48, 0x00, 0x55, 0x00, 0x58, 0x00, 0x57,
+ 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d,
+ 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x16, 0x04, 0x00, 0x27, 0x00, 0x41,
+ 0x00, 0x4d, 0x00, 0x53, 0x00, 0x56, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b,
+ 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e,
+ 0x5f, 0x00, 0x20, 0x00, 0x00, 0x1f, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x51,
+ 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5c,
+ 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0xb1, 0x00, 0xa9, 0x00, 0xa2, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x8e, 0x00,
+ 0x89, 0x01, 0x84, 0x02, 0x7e, 0x02, 0x7a, 0x03, 0x78, 0x05, 0x75, 0x05,
+ 0x73, 0x06, 0x71, 0x07, 0x6c, 0x08, 0x69, 0x09, 0x68, 0x0a, 0x66, 0x0b,
+ 0x65, 0x0c, 0x64, 0x0c, 0x0a, 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x42,
+ 0x0e, 0x42, 0x0f, 0x40, 0x10, 0x3d, 0x11, 0x3f, 0x12, 0x3f, 0x13, 0x3d,
+ 0x15, 0x3c, 0x15, 0x3b, 0x17, 0x3a, 0x17, 0x3c, 0x17, 0x3c, 0x19, 0x3c,
+ 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x3b, 0x5f, 0x25, 0x5c, 0x27,
+ 0x5c, 0x27, 0x5b, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2c,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x30,
+ 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x22, 0x00, 0x36, 0x00, 0x42,
+ 0x00, 0x4a, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58,
+ 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5f, 0x00, 0x48,
+ 0x00, 0x1b, 0x00, 0x34, 0x00, 0x40, 0x00, 0x44, 0x00, 0x4a, 0x00, 0x4f,
+ 0x00, 0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a,
+ 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x82, 0x00, 0x57, 0x00, 0x12, 0x01, 0x00, 0x17, 0x00, 0x2f, 0x00, 0x3e,
+ 0x00, 0x47, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x53, 0x00, 0x56, 0x00, 0x57,
+ 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x85, 0x00, 0x5f, 0x00,
+ 0x1f, 0x00, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4a,
+ 0x00, 0x4e, 0x00, 0x52, 0x00, 0x54, 0x00, 0x56, 0x00, 0x57, 0x00, 0x59,
+ 0x00, 0x59, 0x00, 0x5a, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xb2, 0x00, 0xa9, 0x00,
+ 0xa3, 0x00, 0x9d, 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8b, 0x01, 0x87, 0x02,
+ 0x81, 0x02, 0x7c, 0x03, 0x79, 0x03, 0x77, 0x05, 0x75, 0x06, 0x72, 0x06,
+ 0x70, 0x07, 0x6c, 0x08, 0x69, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c,
+ 0x0a, 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x42, 0x0d, 0x42, 0x0e, 0x40,
+ 0x0f, 0x3e, 0x11, 0x3e, 0x11, 0x3f, 0x13, 0x3f, 0x13, 0x3c, 0x15, 0x3c,
+ 0x15, 0x3a, 0x17, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x19, 0x3c,
+ 0x1a, 0x3b, 0x1c, 0x3b, 0x5f, 0x24, 0x5c, 0x27, 0x5c, 0x27, 0x5b, 0x28,
+ 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2b, 0x55, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x50, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x19, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40,
+ 0x00, 0x47, 0x00, 0x4b, 0x00, 0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55,
+ 0x00, 0x56, 0x00, 0x57, 0x00, 0x62, 0x00, 0x55, 0x00, 0x34, 0x00, 0x0b,
+ 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40, 0x00, 0x47, 0x00, 0x4b,
+ 0x00, 0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x78, 0x00,
+ 0x43, 0x00, 0x10, 0x00, 0x00, 0x0e, 0x00, 0x23, 0x00, 0x31, 0x00, 0x3b,
+ 0x00, 0x42, 0x00, 0x48, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x51, 0x00, 0x53,
+ 0x00, 0x55, 0x00, 0x56, 0x92, 0x00, 0x7c, 0x00, 0x4d, 0x00, 0x1f, 0x00,
+ 0x00, 0x02, 0x00, 0x1a, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x3e, 0x00, 0x45,
+ 0x00, 0x49, 0x00, 0x4d, 0x00, 0x4f, 0x00, 0x52, 0x00, 0x53, 0x00, 0x55,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0xb2, 0x00, 0xaa, 0x00, 0xa4, 0x00, 0x9e, 0x00,
+ 0x96, 0x00, 0x90, 0x00, 0x8c, 0x00, 0x88, 0x01, 0x84, 0x02, 0x7e, 0x02,
+ 0x7b, 0x03, 0x78, 0x04, 0x76, 0x05, 0x74, 0x06, 0x72, 0x07, 0x6f, 0x07,
+ 0x6b, 0x09, 0x69, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x0a, 0x47, 0x0a, 0x46,
+ 0x0b, 0x44, 0x0d, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x0f, 0x3f, 0x10, 0x3d,
+ 0x11, 0x3f, 0x12, 0x3f, 0x13, 0x3e, 0x14, 0x3c, 0x15, 0x3c, 0x16, 0x3a,
+ 0x17, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3b,
+ 0x5f, 0x24, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x58, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x14, 0x00, 0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f,
+ 0x00, 0x44, 0x00, 0x48, 0x00, 0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52,
+ 0x00, 0x62, 0x00, 0x58, 0x00, 0x40, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x14,
+ 0x00, 0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f, 0x00, 0x44, 0x00, 0x48,
+ 0x00, 0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x87, 0x00, 0x61, 0x00, 0x36, 0x00,
+ 0x10, 0x00, 0x02, 0x0a, 0x00, 0x1a, 0x00, 0x27, 0x00, 0x32, 0x00, 0x3a,
+ 0x00, 0x40, 0x00, 0x44, 0x00, 0x48, 0x00, 0x4b, 0x00, 0x4e, 0x00, 0x50,
+ 0x97, 0x00, 0x8a, 0x00, 0x68, 0x00, 0x42, 0x00, 0x1f, 0x00, 0x04, 0x00,
+ 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x41,
+ 0x00, 0x45, 0x00, 0x49, 0x00, 0x4b, 0x00, 0x4e, 0x28, 0x3c, 0x16, 0x41,
+ 0x11, 0x43, 0x0f, 0x44, 0x0e, 0x45, 0x0d, 0x46, 0x0c, 0x46, 0x0c, 0x46,
+ 0x0b, 0x47, 0x0b, 0x47, 0x0b, 0x47, 0x0b, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x6e, 0x1c, 0x3a, 0x29, 0x27, 0x31, 0x1e, 0x36, 0x19, 0x3a, 0x17, 0x3b,
+ 0x14, 0x3d, 0x13, 0x3f, 0x11, 0x40, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x42,
+ 0x0f, 0x43, 0x0f, 0x43, 0x0e, 0x43, 0x0e, 0x44, 0x0d, 0x44, 0x0d, 0x44,
+ 0x0c, 0x44, 0x0c, 0x44, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x3c, 0x32, 0x22, 0x38,
+ 0x18, 0x3c, 0x14, 0x3f, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x42, 0x0e, 0x43,
+ 0x0e, 0x44, 0x0d, 0x44, 0x0d, 0x44, 0x0c, 0x44, 0x0c, 0x45, 0x0c, 0x45,
+ 0x0c, 0x45, 0x0c, 0x45, 0x0b, 0x45, 0x0b, 0x45, 0x0b, 0x46, 0x0b, 0x46,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x1e, 0x00, 0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e,
+ 0x00, 0x42, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x57,
+ 0x00, 0x44, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1e,
+ 0x00, 0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x46,
+ 0x00, 0x49, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x99, 0x00, 0x8f, 0x00, 0x74, 0x00, 0x51, 0x00, 0x2e, 0x00, 0x10, 0x00,
+ 0x04, 0x08, 0x00, 0x13, 0x00, 0x20, 0x00, 0x2a, 0x00, 0x32, 0x00, 0x38,
+ 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x48, 0x9a, 0x00, 0x91, 0x00,
+ 0x79, 0x00, 0x5a, 0x00, 0x3b, 0x00, 0x1f, 0x00, 0x09, 0x00, 0x00, 0x08,
+ 0x00, 0x17, 0x00, 0x22, 0x00, 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3e,
+ 0x00, 0x42, 0x00, 0x45, 0x30, 0x38, 0x20, 0x3a, 0x18, 0x3d, 0x14, 0x3e,
+ 0x12, 0x40, 0x10, 0x41, 0x0f, 0x42, 0x0e, 0x42, 0x0e, 0x42, 0x0d, 0x43,
+ 0x0d, 0x43, 0x0d, 0x44, 0x0d, 0x44, 0x0c, 0x45, 0x0c, 0x45, 0x0b, 0x45,
+ 0x0b, 0x46, 0x0b, 0x46, 0x0b, 0x46, 0x0b, 0x47, 0x8a, 0x03, 0x59, 0x0f,
+ 0x40, 0x18, 0x32, 0x1f, 0x2a, 0x24, 0x24, 0x28, 0x20, 0x2c, 0x1c, 0x2f,
+ 0x1b, 0x31, 0x18, 0x33, 0x17, 0x34, 0x16, 0x36, 0x15, 0x37, 0x14, 0x38,
+ 0x13, 0x39, 0x12, 0x3a, 0x12, 0x3a, 0x12, 0x3b, 0x11, 0x3c, 0x10, 0x3c,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x4a, 0x25, 0x31, 0x2b, 0x25, 0x30, 0x1e, 0x33,
+ 0x1a, 0x36, 0x17, 0x38, 0x15, 0x39, 0x13, 0x3b, 0x12, 0x3c, 0x11, 0x3d,
+ 0x10, 0x3e, 0x10, 0x3f, 0x0f, 0x3f, 0x0f, 0x40, 0x0e, 0x40, 0x0e, 0x40,
+ 0x0e, 0x41, 0x0e, 0x41, 0x0d, 0x42, 0x0d, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
+ 0x00, 0x1a, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d,
+ 0x00, 0x41, 0x00, 0x44, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x38,
+ 0x00, 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24,
+ 0x00, 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x41, 0x00, 0x44,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x94, 0x00,
+ 0x7f, 0x00, 0x64, 0x00, 0x46, 0x00, 0x29, 0x00, 0x10, 0x00, 0x06, 0x07,
+ 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32, 0x00, 0x38,
+ 0x00, 0x3c, 0x00, 0x40, 0x9b, 0x00, 0x95, 0x00, 0x83, 0x00, 0x6a, 0x00,
+ 0x4f, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x10,
+ 0x00, 0x1b, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32, 0x00, 0x37, 0x00, 0x3c,
+ 0x34, 0x38, 0x25, 0x39, 0x1e, 0x3b, 0x19, 0x3c, 0x16, 0x3d, 0x14, 0x3d,
+ 0x13, 0x3f, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x41, 0x0f, 0x42, 0x0e, 0x42,
+ 0x0e, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x43, 0x0d, 0x43,
+ 0x0d, 0x44, 0x0d, 0x44, 0x97, 0x00, 0x6c, 0x06, 0x52, 0x0d, 0x43, 0x12,
+ 0x38, 0x18, 0x30, 0x1c, 0x2a, 0x20, 0x27, 0x23, 0x23, 0x26, 0x20, 0x28,
+ 0x1e, 0x2a, 0x1c, 0x2c, 0x1b, 0x2e, 0x19, 0x2f, 0x18, 0x31, 0x17, 0x32,
+ 0x16, 0x33, 0x16, 0x34, 0x16, 0x35, 0x15, 0x35, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x50, 0x24, 0x3b, 0x27, 0x2e, 0x2a, 0x26, 0x2d, 0x21, 0x2f, 0x1d, 0x32,
+ 0x1a, 0x33, 0x18, 0x35, 0x16, 0x36, 0x15, 0x38, 0x14, 0x39, 0x13, 0x3a,
+ 0x12, 0x3a, 0x11, 0x3b, 0x11, 0x3c, 0x11, 0x3c, 0x10, 0x3d, 0x10, 0x3e,
+ 0x10, 0x3e, 0x0f, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17,
+ 0x00, 0x20, 0x00, 0x28, 0x00, 0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d,
+ 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e,
+ 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x20, 0x00, 0x28,
+ 0x00, 0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x87, 0x00, 0x71, 0x00,
+ 0x57, 0x00, 0x3d, 0x00, 0x25, 0x00, 0x10, 0x00, 0x07, 0x06, 0x00, 0x0b,
+ 0x00, 0x15, 0x00, 0x1f, 0x00, 0x26, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x37,
+ 0x9c, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x48, 0x00,
+ 0x33, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15,
+ 0x00, 0x1e, 0x00, 0x25, 0x00, 0x2c, 0x00, 0x31, 0x36, 0x39, 0x2a, 0x39,
+ 0x22, 0x39, 0x1d, 0x3a, 0x1a, 0x3b, 0x17, 0x3d, 0x15, 0x3d, 0x13, 0x3d,
+ 0x13, 0x3e, 0x12, 0x3f, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x41, 0x0f, 0x42,
+ 0x0e, 0x41, 0x0e, 0x42, 0x0e, 0x42, 0x0e, 0x41, 0x0e, 0x42, 0x0d, 0x42,
+ 0x9e, 0x00, 0x79, 0x02, 0x61, 0x07, 0x50, 0x0b, 0x44, 0x10, 0x3b, 0x14,
+ 0x34, 0x18, 0x2f, 0x1b, 0x2b, 0x1e, 0x28, 0x20, 0x25, 0x23, 0x23, 0x25,
+ 0x21, 0x27, 0x1f, 0x28, 0x1d, 0x2a, 0x1c, 0x2b, 0x1b, 0x2c, 0x19, 0x2e,
+ 0x19, 0x2f, 0x19, 0x30, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x54, 0x23, 0x42, 0x25,
+ 0x35, 0x27, 0x2d, 0x29, 0x27, 0x2c, 0x22, 0x2e, 0x1f, 0x2f, 0x1c, 0x31,
+ 0x1a, 0x33, 0x19, 0x34, 0x17, 0x35, 0x16, 0x36, 0x15, 0x37, 0x14, 0x38,
+ 0x13, 0x38, 0x13, 0x39, 0x12, 0x3a, 0x11, 0x3a, 0x11, 0x3b, 0x11, 0x3c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d,
+ 0x00, 0x24, 0x00, 0x2a, 0x00, 0x30, 0x00, 0x35, 0x00, 0x5e, 0x00, 0x5b,
+ 0x00, 0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29, 0x00, 0x1a, 0x00, 0x0c,
+ 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d, 0x00, 0x24, 0x00, 0x2a,
+ 0x00, 0x30, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9d, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00,
+ 0x37, 0x00, 0x22, 0x00, 0x10, 0x00, 0x08, 0x05, 0x02, 0x0a, 0x00, 0x12,
+ 0x00, 0x1a, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2d, 0x9d, 0x00, 0x99, 0x00,
+ 0x8e, 0x00, 0x7e, 0x00, 0x6b, 0x00, 0x57, 0x00, 0x43, 0x00, 0x30, 0x00,
+ 0x1f, 0x00, 0x11, 0x00, 0x04, 0x00, 0x00, 0x07, 0x00, 0x10, 0x00, 0x19,
+ 0x00, 0x20, 0x00, 0x26, 0x38, 0x39, 0x2d, 0x39, 0x25, 0x39, 0x20, 0x3a,
+ 0x1d, 0x3b, 0x1a, 0x3b, 0x18, 0x3c, 0x16, 0x3d, 0x14, 0x3d, 0x13, 0x3d,
+ 0x13, 0x3d, 0x12, 0x3e, 0x11, 0x3f, 0x11, 0x40, 0x10, 0x40, 0x0f, 0x41,
+ 0x0f, 0x42, 0x0f, 0x42, 0x0e, 0x42, 0x0e, 0x42, 0xa2, 0x00, 0x84, 0x00,
+ 0x6c, 0x04, 0x5a, 0x07, 0x4e, 0x0b, 0x45, 0x0f, 0x3e, 0x12, 0x38, 0x15,
+ 0x32, 0x18, 0x2f, 0x1a, 0x2c, 0x1d, 0x29, 0x1f, 0x26, 0x21, 0x24, 0x22,
+ 0x22, 0x24, 0x21, 0x26, 0x1f, 0x27, 0x1e, 0x28, 0x1d, 0x2a, 0x1c, 0x2b,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x56, 0x23, 0x47, 0x24, 0x3b, 0x25, 0x32, 0x27,
+ 0x2c, 0x29, 0x27, 0x2b, 0x24, 0x2d, 0x21, 0x2e, 0x1e, 0x30, 0x1c, 0x31,
+ 0x1b, 0x32, 0x19, 0x33, 0x18, 0x34, 0x17, 0x35, 0x16, 0x36, 0x15, 0x37,
+ 0x14, 0x37, 0x14, 0x38, 0x13, 0x38, 0x13, 0x39, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21,
+ 0x00, 0x27, 0x00, 0x2c, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x4b,
+ 0x00, 0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00,
+ 0x90, 0x00, 0x81, 0x00, 0x6f, 0x00, 0x5b, 0x00, 0x46, 0x00, 0x32, 0x00,
+ 0x20, 0x00, 0x10, 0x00, 0x09, 0x04, 0x03, 0x09, 0x00, 0x0f, 0x00, 0x17,
+ 0x00, 0x1e, 0x00, 0x24, 0x9d, 0x00, 0x9a, 0x00, 0x92, 0x00, 0x84, 0x00,
+ 0x74, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x1f, 0x00,
+ 0x12, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x1b,
+ 0x39, 0x3a, 0x2f, 0x39, 0x28, 0x39, 0x23, 0x39, 0x20, 0x3a, 0x1c, 0x3b,
+ 0x1a, 0x3a, 0x18, 0x3b, 0x17, 0x3c, 0x15, 0x3e, 0x14, 0x3e, 0x13, 0x3d,
+ 0x13, 0x3d, 0x12, 0x3d, 0x11, 0x3e, 0x11, 0x3f, 0x11, 0x40, 0x10, 0x40,
+ 0x0f, 0x40, 0x0f, 0x41, 0xa6, 0x00, 0x8b, 0x00, 0x75, 0x02, 0x63, 0x05,
+ 0x57, 0x07, 0x4d, 0x0b, 0x45, 0x0e, 0x3e, 0x11, 0x39, 0x13, 0x35, 0x16,
+ 0x32, 0x18, 0x2e, 0x1a, 0x2c, 0x1c, 0x29, 0x1d, 0x27, 0x1f, 0x26, 0x22,
+ 0x24, 0x22, 0x21, 0x23, 0x21, 0x25, 0x20, 0x26, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x58, 0x23, 0x4a, 0x23, 0x3f, 0x24, 0x36, 0x26, 0x30, 0x27, 0x2b, 0x29,
+ 0x27, 0x2a, 0x24, 0x2c, 0x22, 0x2d, 0x20, 0x2e, 0x1e, 0x30, 0x1c, 0x30,
+ 0x1b, 0x32, 0x1a, 0x32, 0x18, 0x33, 0x18, 0x34, 0x17, 0x34, 0x16, 0x35,
+ 0x16, 0x36, 0x15, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x09, 0x00, 0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24,
+ 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38,
+ 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09,
+ 0x00, 0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x86, 0x00,
+ 0x76, 0x00, 0x65, 0x00, 0x52, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e, 0x00,
+ 0x10, 0x00, 0x09, 0x04, 0x04, 0x08, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x1a,
+ 0x9e, 0x00, 0x9b, 0x00, 0x94, 0x00, 0x89, 0x00, 0x7b, 0x00, 0x6b, 0x00,
+ 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2d, 0x00, 0x1f, 0x00, 0x13, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x11, 0x3a, 0x3a, 0x31, 0x3a,
+ 0x2a, 0x39, 0x25, 0x3a, 0x22, 0x39, 0x1e, 0x3b, 0x1c, 0x3b, 0x1a, 0x3a,
+ 0x19, 0x3a, 0x17, 0x3c, 0x16, 0x3c, 0x15, 0x3e, 0x14, 0x3e, 0x13, 0x3d,
+ 0x13, 0x3d, 0x12, 0x3d, 0x11, 0x3d, 0x11, 0x3e, 0x11, 0x3f, 0x10, 0x40,
+ 0xa8, 0x00, 0x90, 0x00, 0x7c, 0x01, 0x6b, 0x02, 0x5f, 0x05, 0x55, 0x07,
+ 0x4c, 0x0a, 0x45, 0x0d, 0x40, 0x0f, 0x3c, 0x12, 0x37, 0x14, 0x34, 0x16,
+ 0x31, 0x18, 0x2e, 0x19, 0x2b, 0x1b, 0x2a, 0x1d, 0x28, 0x1e, 0x26, 0x20,
+ 0x25, 0x22, 0x23, 0x22, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x59, 0x23, 0x4d, 0x23,
+ 0x43, 0x24, 0x3b, 0x25, 0x34, 0x26, 0x2f, 0x27, 0x2b, 0x29, 0x28, 0x2a,
+ 0x25, 0x2b, 0x23, 0x2d, 0x21, 0x2e, 0x1f, 0x2e, 0x1d, 0x30, 0x1c, 0x30,
+ 0x1b, 0x31, 0x1a, 0x32, 0x19, 0x32, 0x18, 0x33, 0x17, 0x34, 0x16, 0x34,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x0f, 0x00, 0x16, 0x00, 0x1c, 0x00, 0x5e, 0x00, 0x5d,
+ 0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x28,
+ 0x00, 0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f,
+ 0x00, 0x16, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9b, 0x00, 0x95, 0x00, 0x8a, 0x00, 0x7d, 0x00, 0x6d, 0x00,
+ 0x5d, 0x00, 0x4c, 0x00, 0x3b, 0x00, 0x2c, 0x00, 0x1d, 0x00, 0x10, 0x00,
+ 0x0a, 0x04, 0x05, 0x07, 0x00, 0x0b, 0x00, 0x11, 0x9e, 0x00, 0x9c, 0x00,
+ 0x96, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x73, 0x00, 0x64, 0x00, 0x55, 0x00,
+ 0x46, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0a, 0x00,
+ 0x01, 0x00, 0x00, 0x06, 0x3a, 0x3b, 0x32, 0x3a, 0x2c, 0x39, 0x27, 0x3a,
+ 0x23, 0x39, 0x21, 0x39, 0x1e, 0x3b, 0x1c, 0x3c, 0x1a, 0x3a, 0x19, 0x3a,
+ 0x17, 0x3b, 0x17, 0x3c, 0x15, 0x3d, 0x15, 0x3e, 0x14, 0x3e, 0x13, 0x3d,
+ 0x13, 0x3d, 0x13, 0x3d, 0x11, 0x3d, 0x11, 0x3e, 0xaa, 0x00, 0x94, 0x00,
+ 0x82, 0x00, 0x72, 0x01, 0x65, 0x04, 0x5b, 0x05, 0x53, 0x07, 0x4b, 0x0a,
+ 0x45, 0x0c, 0x41, 0x0f, 0x3d, 0x11, 0x39, 0x12, 0x36, 0x15, 0x33, 0x16,
+ 0x30, 0x18, 0x2e, 0x19, 0x2b, 0x1a, 0x2b, 0x1d, 0x29, 0x1d, 0x26, 0x1e,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x5a, 0x23, 0x4f, 0x23, 0x46, 0x24, 0x3e, 0x24,
+ 0x37, 0x25, 0x32, 0x26, 0x2e, 0x27, 0x2b, 0x28, 0x28, 0x2a, 0x25, 0x2b,
+ 0x23, 0x2c, 0x21, 0x2d, 0x20, 0x2e, 0x1e, 0x2e, 0x1d, 0x30, 0x1c, 0x30,
+ 0x1b, 0x31, 0x1a, 0x32, 0x19, 0x32, 0x18, 0x33, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+ 0x00, 0x0e, 0x00, 0x14, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53,
+ 0x00, 0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e, 0x00, 0x24, 0x00, 0x1a,
+ 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x14,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
+ 0x96, 0x00, 0x8d, 0x00, 0x81, 0x00, 0x74, 0x00, 0x65, 0x00, 0x56, 0x00,
+ 0x46, 0x00, 0x37, 0x00, 0x29, 0x00, 0x1c, 0x00, 0x10, 0x00, 0x0a, 0x03,
+ 0x06, 0x07, 0x01, 0x0a, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8f, 0x00,
+ 0x85, 0x00, 0x79, 0x00, 0x6b, 0x00, 0x5e, 0x00, 0x50, 0x00, 0x43, 0x00,
+ 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x15, 0x00, 0x0c, 0x00, 0x03, 0x00,
+ 0x3b, 0x3b, 0x33, 0x3b, 0x2d, 0x39, 0x29, 0x39, 0x25, 0x3a, 0x22, 0x39,
+ 0x20, 0x39, 0x1e, 0x3b, 0x1c, 0x3c, 0x1a, 0x3a, 0x19, 0x3a, 0x18, 0x3a,
+ 0x17, 0x3c, 0x16, 0x3c, 0x15, 0x3d, 0x15, 0x3e, 0x13, 0x3f, 0x13, 0x3d,
+ 0x13, 0x3d, 0x13, 0x3d, 0xaa, 0x00, 0x98, 0x00, 0x87, 0x00, 0x78, 0x01,
+ 0x6b, 0x02, 0x61, 0x04, 0x58, 0x06, 0x51, 0x08, 0x4b, 0x0a, 0x46, 0x0c,
+ 0x42, 0x0e, 0x3e, 0x0f, 0x3a, 0x12, 0x37, 0x12, 0x35, 0x16, 0x32, 0x16,
+ 0x30, 0x18, 0x2e, 0x19, 0x2b, 0x1a, 0x2b, 0x1c, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x5a, 0x23, 0x51, 0x23, 0x48, 0x23, 0x41, 0x24, 0x3a, 0x25, 0x35, 0x25,
+ 0x31, 0x26, 0x2e, 0x27, 0x2a, 0x28, 0x28, 0x2a, 0x26, 0x2b, 0x24, 0x2b,
+ 0x22, 0x2d, 0x21, 0x2d, 0x1f, 0x2e, 0x1e, 0x2e, 0x1d, 0x30, 0x1c, 0x30,
+ 0x1b, 0x30, 0x1a, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d,
+ 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x46,
+ 0x00, 0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f,
+ 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x90, 0x00,
+ 0x85, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x5e, 0x00, 0x50, 0x00, 0x42, 0x00,
+ 0x34, 0x00, 0x27, 0x00, 0x1b, 0x00, 0x0f, 0x00, 0x0b, 0x03, 0x06, 0x06,
+ 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x91, 0x00, 0x88, 0x00, 0x7e, 0x00,
+ 0x72, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00,
+ 0x2a, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0d, 0x00, 0x3b, 0x3c, 0x34, 0x3a,
+ 0x2f, 0x3a, 0x2a, 0x39, 0x26, 0x3a, 0x23, 0x3a, 0x21, 0x39, 0x1f, 0x3a,
+ 0x1d, 0x3b, 0x1c, 0x3c, 0x1a, 0x3b, 0x19, 0x3a, 0x18, 0x3a, 0x17, 0x3b,
+ 0x17, 0x3c, 0x15, 0x3c, 0x15, 0x3d, 0x15, 0x3f, 0x13, 0x3f, 0x13, 0x3e,
+ 0xac, 0x00, 0x9b, 0x00, 0x8b, 0x00, 0x7c, 0x00, 0x71, 0x01, 0x67, 0x03,
+ 0x5e, 0x05, 0x57, 0x07, 0x51, 0x08, 0x4b, 0x0a, 0x46, 0x0c, 0x42, 0x0d,
+ 0x3f, 0x0f, 0x3b, 0x11, 0x39, 0x12, 0x35, 0x14, 0x34, 0x16, 0x31, 0x16,
+ 0x30, 0x18, 0x2e, 0x19, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5b, 0x23, 0x52, 0x23,
+ 0x4a, 0x23, 0x43, 0x24, 0x3d, 0x24, 0x38, 0x25, 0x34, 0x26, 0x30, 0x27,
+ 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x2a, 0x26, 0x2a, 0x24, 0x2b, 0x22, 0x2c,
+ 0x21, 0x2d, 0x20, 0x2d, 0x1f, 0x2e, 0x1d, 0x2e, 0x1d, 0x30, 0x1c, 0x30,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x5e,
+ 0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49, 0x00, 0x41, 0x00, 0x39,
+ 0x00, 0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x07,
+ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00,
+ 0x72, 0x00, 0x65, 0x00, 0x58, 0x00, 0x4b, 0x00, 0x3e, 0x00, 0x31, 0x00,
+ 0x25, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x0b, 0x03, 0x9e, 0x00, 0x9d, 0x00,
+ 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82, 0x00, 0x77, 0x00, 0x6c, 0x00,
+ 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3d, 0x00, 0x33, 0x00, 0x29, 0x00,
+ 0x1f, 0x00, 0x17, 0x00, 0x3b, 0x3c, 0x35, 0x3a, 0x30, 0x3b, 0x2c, 0x39,
+ 0x28, 0x3a, 0x25, 0x3b, 0x22, 0x39, 0x21, 0x39, 0x1f, 0x3a, 0x1d, 0x3b,
+ 0x1c, 0x3c, 0x1a, 0x3b, 0x19, 0x3a, 0x19, 0x3a, 0x17, 0x3a, 0x17, 0x3c,
+ 0x16, 0x3c, 0x15, 0x3c, 0x15, 0x3e, 0x14, 0x3f, 0xad, 0x00, 0x9d, 0x00,
+ 0x8e, 0x00, 0x81, 0x00, 0x76, 0x01, 0x6b, 0x02, 0x63, 0x04, 0x5c, 0x05,
+ 0x56, 0x07, 0x50, 0x08, 0x4b, 0x0a, 0x47, 0x0c, 0x43, 0x0c, 0x40, 0x0f,
+ 0x3c, 0x0f, 0x3a, 0x12, 0x37, 0x12, 0x35, 0x14, 0x33, 0x16, 0x30, 0x16,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x5b, 0x23, 0x53, 0x23, 0x4c, 0x23, 0x45, 0x23,
+ 0x40, 0x24, 0x3b, 0x25, 0x36, 0x25, 0x33, 0x26, 0x30, 0x27, 0x2d, 0x28,
+ 0x2a, 0x28, 0x28, 0x2a, 0x26, 0x2a, 0x25, 0x2b, 0x23, 0x2b, 0x22, 0x2d,
+ 0x20, 0x2d, 0x20, 0x2e, 0x1e, 0x2e, 0x1d, 0x2e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x57,
+ 0x00, 0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x2c,
+ 0x00, 0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00,
+ 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82, 0x00, 0x77, 0x00, 0x6b, 0x00,
+ 0x5f, 0x00, 0x53, 0x00, 0x46, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x24, 0x00,
+ 0x19, 0x00, 0x0f, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x95, 0x00,
+ 0x8d, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00, 0x66, 0x00, 0x5b, 0x00,
+ 0x50, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x31, 0x00, 0x28, 0x00, 0x1f, 0x00,
+ 0x3c, 0x3d, 0x36, 0x3a, 0x31, 0x3b, 0x2c, 0x3a, 0x29, 0x39, 0x26, 0x3a,
+ 0x24, 0x3b, 0x21, 0x39, 0x20, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3c,
+ 0x1a, 0x3c, 0x19, 0x3a, 0x19, 0x3a, 0x17, 0x3a, 0x17, 0x3b, 0x17, 0x3c,
+ 0x15, 0x3c, 0x15, 0x3c, 0xad, 0x00, 0x9f, 0x00, 0x91, 0x00, 0x85, 0x00,
+ 0x79, 0x00, 0x6f, 0x01, 0x67, 0x02, 0x60, 0x04, 0x59, 0x05, 0x54, 0x07,
+ 0x4f, 0x08, 0x4b, 0x0a, 0x47, 0x0c, 0x43, 0x0c, 0x41, 0x0f, 0x3d, 0x0f,
+ 0x3b, 0x11, 0x38, 0x12, 0x35, 0x12, 0x35, 0x15, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x5b, 0x23, 0x54, 0x23, 0x4e, 0x23, 0x47, 0x23, 0x42, 0x24, 0x3c, 0x24,
+ 0x38, 0x25, 0x35, 0x25, 0x32, 0x26, 0x2f, 0x27, 0x2d, 0x28, 0x2a, 0x28,
+ 0x28, 0x2a, 0x26, 0x2a, 0x25, 0x2b, 0x23, 0x2b, 0x22, 0x2c, 0x21, 0x2d,
+ 0x20, 0x2d, 0x20, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3d, 0x36, 0x3a,
+ 0x32, 0x3b, 0x2d, 0x3b, 0x2b, 0x39, 0x28, 0x3a, 0x25, 0x3a, 0x23, 0x3a,
+ 0x21, 0x39, 0x1f, 0x39, 0x1f, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c,
+ 0x19, 0x3a, 0x19, 0x3a, 0x18, 0x3a, 0x17, 0x3a, 0x17, 0x3c, 0x16, 0x3c,
+ 0xad, 0x00, 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7e, 0x00, 0x74, 0x01,
+ 0x6c, 0x02, 0x65, 0x03, 0x5e, 0x04, 0x58, 0x05, 0x53, 0x07, 0x4f, 0x08,
+ 0x4b, 0x0a, 0x47, 0x0b, 0x44, 0x0c, 0x41, 0x0e, 0x3e, 0x0f, 0x3b, 0x0f,
+ 0x3a, 0x12, 0x37, 0x12, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x55, 0x23,
+ 0x4f, 0x23, 0x49, 0x23, 0x44, 0x24, 0x3f, 0x24, 0x3b, 0x25, 0x37, 0x25,
+ 0x34, 0x26, 0x31, 0x26, 0x2e, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29,
+ 0x27, 0x2a, 0x25, 0x2b, 0x24, 0x2b, 0x22, 0x2b, 0x22, 0x2d, 0x20, 0x2d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x37, 0x3b, 0x33, 0x3b, 0x2f, 0x3b,
+ 0x2b, 0x39, 0x29, 0x39, 0x26, 0x3a, 0x24, 0x3b, 0x22, 0x3a, 0x21, 0x39,
+ 0x1f, 0x39, 0x1e, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3b,
+ 0x19, 0x3a, 0x18, 0x3a, 0x17, 0x3a, 0x17, 0x3b, 0xae, 0x00, 0xa2, 0x00,
+ 0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x77, 0x00, 0x6f, 0x01, 0x67, 0x02,
+ 0x61, 0x04, 0x5c, 0x05, 0x57, 0x05, 0x52, 0x07, 0x4e, 0x08, 0x4b, 0x0a,
+ 0x47, 0x0b, 0x44, 0x0c, 0x41, 0x0d, 0x3f, 0x0f, 0x3c, 0x0f, 0x3b, 0x11,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x56, 0x23, 0x50, 0x23, 0x4a, 0x23,
+ 0x45, 0x23, 0x40, 0x24, 0x3c, 0x24, 0x39, 0x25, 0x35, 0x25, 0x33, 0x26,
+ 0x30, 0x26, 0x2e, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29, 0x27, 0x2a,
+ 0x25, 0x2a, 0x24, 0x2b, 0x23, 0x2b, 0x22, 0x2c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3c, 0x3e, 0x37, 0x3b, 0x33, 0x3a, 0x2f, 0x3b, 0x2c, 0x3a, 0x2a, 0x39,
+ 0x27, 0x3a, 0x25, 0x3a, 0x23, 0x3b, 0x21, 0x39, 0x20, 0x39, 0x1f, 0x39,
+ 0x1e, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3b, 0x19, 0x3a,
+ 0x19, 0x3a, 0x17, 0x3a, 0xaf, 0x00, 0xa3, 0x00, 0x98, 0x00, 0x8e, 0x00,
+ 0x84, 0x00, 0x7a, 0x00, 0x72, 0x01, 0x6c, 0x02, 0x65, 0x02, 0x5f, 0x04,
+ 0x5a, 0x05, 0x56, 0x05, 0x52, 0x07, 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0b,
+ 0x45, 0x0c, 0x41, 0x0c, 0x40, 0x0f, 0x3d, 0x0f, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x5c, 0x23, 0x56, 0x23, 0x51, 0x23, 0x4c, 0x23, 0x47, 0x23, 0x42, 0x24,
+ 0x3e, 0x24, 0x3b, 0x25, 0x37, 0x25, 0x34, 0x25, 0x32, 0x26, 0x30, 0x26,
+ 0x2e, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29, 0x27, 0x2a, 0x25, 0x2a,
+ 0x25, 0x2b, 0x23, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x38, 0x3c,
+ 0x34, 0x3a, 0x30, 0x3b, 0x2d, 0x3b, 0x2a, 0x39, 0x28, 0x39, 0x26, 0x3a,
+ 0x24, 0x3b, 0x22, 0x3b, 0x21, 0x39, 0x20, 0x39, 0x1f, 0x39, 0x1e, 0x3b,
+ 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3b, 0x19, 0x3a, 0x19, 0x3a,
+ 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00, 0x90, 0x00, 0x87, 0x00, 0x7e, 0x00,
+ 0x76, 0x00, 0x6f, 0x01, 0x68, 0x02, 0x62, 0x04, 0x5e, 0x04, 0x59, 0x05,
+ 0x55, 0x06, 0x51, 0x07, 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0a, 0x45, 0x0c,
+ 0x41, 0x0c, 0x41, 0x0f, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x57, 0x23,
+ 0x52, 0x23, 0x4d, 0x23, 0x48, 0x23, 0x44, 0x23, 0x40, 0x24, 0x3c, 0x24,
+ 0x39, 0x25, 0x36, 0x25, 0x34, 0x25, 0x31, 0x26, 0x2f, 0x27, 0x2d, 0x27,
+ 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29, 0x27, 0x2a, 0x25, 0x2a, 0x25, 0x2b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3e, 0x38, 0x3c, 0x34, 0x3a, 0x31, 0x3b,
+ 0x2e, 0x3c, 0x2b, 0x39, 0x29, 0x39, 0x27, 0x3a, 0x25, 0x3a, 0x24, 0x3b,
+ 0x21, 0x3a, 0x21, 0x39, 0x1f, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3b,
+ 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x3a, 0xaf, 0x00, 0xa6, 0x00,
+ 0x9b, 0x00, 0x91, 0x00, 0x88, 0x00, 0x80, 0x00, 0x78, 0x00, 0x71, 0x01,
+ 0x6b, 0x02, 0x66, 0x02, 0x61, 0x04, 0x5c, 0x04, 0x58, 0x05, 0x55, 0x07,
+ 0x50, 0x07, 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0c,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x58, 0x23, 0x53, 0x23, 0x4d, 0x23,
+ 0x49, 0x23, 0x45, 0x23, 0x41, 0x24, 0x3d, 0x24, 0x3b, 0x24, 0x38, 0x25,
+ 0x35, 0x25, 0x33, 0x26, 0x31, 0x26, 0x2f, 0x27, 0x2d, 0x27, 0x2c, 0x28,
+ 0x2a, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x26, 0x2a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x3e, 0x38, 0x3d, 0x35, 0x3a, 0x32, 0x3b, 0x2e, 0x3b, 0x2c, 0x3a,
+ 0x2a, 0x39, 0x27, 0x39, 0x26, 0x3a, 0x24, 0x3a, 0x23, 0x3b, 0x21, 0x39,
+ 0x21, 0x39, 0x1f, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c,
+ 0x1a, 0x3c, 0x19, 0x3c, 0xb0, 0x00, 0xa6, 0x00, 0x9d, 0x00, 0x93, 0x00,
+ 0x8b, 0x00, 0x83, 0x00, 0x7c, 0x00, 0x75, 0x00, 0x6e, 0x01, 0x69, 0x02,
+ 0x63, 0x03, 0x5f, 0x04, 0x5b, 0x05, 0x56, 0x05, 0x54, 0x07, 0x4f, 0x07,
+ 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0a, 0x46, 0x0c, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x5d, 0x23, 0x58, 0x23, 0x53, 0x23, 0x4f, 0x23, 0x4a, 0x23, 0x46, 0x23,
+ 0x43, 0x24, 0x3f, 0x24, 0x3c, 0x24, 0x39, 0x25, 0x36, 0x25, 0x34, 0x25,
+ 0x33, 0x26, 0x30, 0x26, 0x2f, 0x27, 0x2d, 0x27, 0x2c, 0x28, 0x2a, 0x28,
+ 0x28, 0x28, 0x28, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3e, 0x39, 0x3e,
+ 0x35, 0x3a, 0x32, 0x3a, 0x2f, 0x3b, 0x2d, 0x3c, 0x2a, 0x39, 0x28, 0x39,
+ 0x27, 0x3a, 0x24, 0x3a, 0x24, 0x3b, 0x22, 0x3b, 0x21, 0x39, 0x20, 0x39,
+ 0x1f, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c,
+ 0xb0, 0x00, 0xa7, 0x00, 0x9e, 0x00, 0x96, 0x00, 0x8d, 0x00, 0x86, 0x00,
+ 0x7e, 0x00, 0x77, 0x00, 0x71, 0x01, 0x6b, 0x01, 0x66, 0x02, 0x62, 0x04,
+ 0x5d, 0x04, 0x5a, 0x05, 0x55, 0x05, 0x53, 0x07, 0x4f, 0x07, 0x4e, 0x09,
+ 0x4a, 0x0a, 0x47, 0x0a, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5d, 0x23, 0x58, 0x23,
+ 0x54, 0x23, 0x50, 0x23, 0x4c, 0x23, 0x48, 0x23, 0x44, 0x23, 0x40, 0x24,
+ 0x3d, 0x24, 0x3a, 0x24, 0x38, 0x25, 0x36, 0x25, 0x33, 0x25, 0x32, 0x26,
+ 0x2f, 0x26, 0x2f, 0x27, 0x2c, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x28,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3e, 0x39, 0x3e, 0x35, 0x3b, 0x32, 0x3a,
+ 0x30, 0x3b, 0x2e, 0x3c, 0x2b, 0x3a, 0x2a, 0x39, 0x27, 0x39, 0x26, 0x3a,
+ 0x24, 0x3a, 0x23, 0x3b, 0x21, 0x3a, 0x21, 0x39, 0x1f, 0x39, 0x1f, 0x39,
+ 0x1e, 0x3b, 0x1c, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0xb1, 0x00, 0xa7, 0x00,
+ 0x9f, 0x00, 0x97, 0x00, 0x8f, 0x00, 0x87, 0x00, 0x80, 0x00, 0x79, 0x00,
+ 0x73, 0x00, 0x6e, 0x01, 0x69, 0x02, 0x64, 0x02, 0x60, 0x04, 0x5c, 0x04,
+ 0x59, 0x05, 0x55, 0x05, 0x53, 0x07, 0x4e, 0x07, 0x4e, 0x09, 0x4a, 0x0a,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
+ 0x0a, 0x47, 0x0a, 0x47, 0x5d, 0x23, 0x58, 0x23, 0x54, 0x23, 0x50, 0x23,
+ 0x4c, 0x23, 0x48, 0x23, 0x45, 0x23, 0x42, 0x24, 0x3f, 0x24, 0x3c, 0x24,
+ 0x39, 0x25, 0x37, 0x25, 0x35, 0x25, 0x33, 0x25, 0x31, 0x26, 0x2f, 0x26,
+ 0x2e, 0x27, 0x2c, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0x00, 0x94, 0x00, 0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xa9, 0x00,
+ 0xab, 0x00, 0xac, 0x00, 0xad, 0x00, 0xae, 0x00, 0xae, 0x00, 0xaf, 0x00,
+ 0xaf, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb1, 0x00,
+ 0xb2, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x21, 0x00, 0x6e, 0x00,
+ 0x8a, 0x00, 0x97, 0x00, 0x9e, 0x00, 0xa2, 0x00, 0xa6, 0x00, 0xa8, 0x00,
+ 0xaa, 0x00, 0xaa, 0x00, 0xac, 0x00, 0xad, 0x00, 0xad, 0x00, 0xad, 0x00,
+ 0xae, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb0, 0x00,
+ 0x6c, 0x00, 0x92, 0x00, 0xa1, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xac, 0x00,
+ 0xae, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb2, 0x00,
+ 0xb2, 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00,
+ 0xb3, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x04, 0x70, 0x01,
+ 0x7f, 0x00, 0x88, 0x00, 0x90, 0x00, 0x95, 0x00, 0x99, 0x00, 0x9c, 0x00,
+ 0x9f, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7, 0x00,
+ 0xa7, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x1c, 0x3a, 0x03, 0x59, 0x00, 0x6c, 0x00,
+ 0x79, 0x00, 0x84, 0x00, 0x8b, 0x00, 0x90, 0x00, 0x94, 0x00, 0x98, 0x00,
+ 0x9b, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa3, 0x00,
+ 0xa5, 0x00, 0xa6, 0x00, 0xa6, 0x00, 0xa7, 0x00, 0x60, 0x0e, 0x79, 0x01,
+ 0x88, 0x00, 0x92, 0x00, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa3, 0x00,
+ 0xa5, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xab, 0x00, 0xac, 0x00,
+ 0xac, 0x00, 0xad, 0x00, 0xae, 0x00, 0xae, 0x00, 0xae, 0x00, 0xaf, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4e, 0x0f, 0x60, 0x07, 0x6d, 0x03, 0x77, 0x01,
+ 0x7f, 0x00, 0x85, 0x00, 0x8b, 0x00, 0x8f, 0x00, 0x92, 0x00, 0x94, 0x00,
+ 0x97, 0x00, 0x9a, 0x00, 0x9c, 0x00, 0x9e, 0x00, 0xa0, 0x00, 0xa1, 0x00,
+ 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa4, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0x0a, 0x29, 0x27, 0x0f, 0x40, 0x06, 0x52, 0x02, 0x61, 0x00, 0x6c, 0x00,
+ 0x75, 0x00, 0x7c, 0x00, 0x82, 0x00, 0x87, 0x00, 0x8b, 0x00, 0x8e, 0x00,
+ 0x91, 0x00, 0x94, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9b, 0x00,
+ 0x9d, 0x00, 0x9e, 0x00, 0x60, 0x14, 0x6f, 0x07, 0x7b, 0x03, 0x84, 0x01,
+ 0x8c, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9d, 0x00, 0x9f, 0x00,
+ 0xa1, 0x00, 0xa2, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa7, 0x00, 0xa7, 0x00,
+ 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x49, 0x17, 0x56, 0x0d, 0x62, 0x07, 0x6b, 0x04, 0x73, 0x02, 0x79, 0x01,
+ 0x7e, 0x01, 0x83, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00,
+ 0x92, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9c, 0x00,
+ 0x9e, 0x00, 0x9f, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x31, 0x1e, 0x18,
+ 0x32, 0x0d, 0x43, 0x07, 0x50, 0x04, 0x5a, 0x02, 0x63, 0x01, 0x6b, 0x00,
+ 0x72, 0x00, 0x78, 0x00, 0x7c, 0x00, 0x81, 0x00, 0x85, 0x00, 0x88, 0x00,
+ 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00,
+ 0x60, 0x18, 0x6b, 0x0c, 0x74, 0x06, 0x7d, 0x03, 0x83, 0x02, 0x89, 0x01,
+ 0x8d, 0x00, 0x91, 0x00, 0x95, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9c, 0x00,
+ 0x9e, 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xa4, 0x00,
+ 0xa5, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x1d, 0x51, 0x12,
+ 0x5b, 0x0c, 0x63, 0x08, 0x6a, 0x05, 0x70, 0x03, 0x77, 0x02, 0x7b, 0x02,
+ 0x7e, 0x01, 0x82, 0x00, 0x86, 0x00, 0x8a, 0x00, 0x8c, 0x00, 0x8e, 0x00,
+ 0x90, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x97, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x36, 0x19, 0x1f, 0x2a, 0x12, 0x38, 0x0b,
+ 0x44, 0x07, 0x4e, 0x05, 0x57, 0x02, 0x5f, 0x01, 0x65, 0x01, 0x6b, 0x00,
+ 0x71, 0x00, 0x76, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x80, 0x00, 0x84, 0x00,
+ 0x87, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d, 0x00, 0x60, 0x1b, 0x68, 0x0f,
+ 0x70, 0x09, 0x77, 0x05, 0x7d, 0x03, 0x82, 0x02, 0x87, 0x01, 0x8b, 0x00,
+ 0x8e, 0x00, 0x91, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00,
+ 0x9b, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1, 0x00, 0xa2, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x45, 0x21, 0x4e, 0x16, 0x56, 0x10, 0x5d, 0x0b,
+ 0x65, 0x08, 0x69, 0x06, 0x6f, 0x04, 0x74, 0x03, 0x78, 0x02, 0x7b, 0x02,
+ 0x7e, 0x01, 0x81, 0x01, 0x85, 0x00, 0x88, 0x00, 0x8a, 0x00, 0x8c, 0x00,
+ 0x8e, 0x00, 0x8f, 0x00, 0x90, 0x00, 0x92, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0x09, 0x3a, 0x17, 0x24, 0x24, 0x18, 0x30, 0x10, 0x3b, 0x0b, 0x45, 0x07,
+ 0x4d, 0x05, 0x55, 0x04, 0x5b, 0x02, 0x61, 0x01, 0x67, 0x01, 0x6b, 0x00,
+ 0x6f, 0x00, 0x74, 0x00, 0x77, 0x00, 0x7a, 0x00, 0x7e, 0x00, 0x80, 0x00,
+ 0x83, 0x00, 0x86, 0x00, 0x60, 0x1d, 0x67, 0x12, 0x6d, 0x0c, 0x73, 0x08,
+ 0x79, 0x05, 0x7e, 0x03, 0x82, 0x02, 0x86, 0x02, 0x89, 0x01, 0x8c, 0x00,
+ 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x00, 0x99, 0x00,
+ 0x9a, 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x44, 0x24, 0x4c, 0x1a, 0x53, 0x13, 0x59, 0x0e, 0x5f, 0x0b, 0x65, 0x08,
+ 0x69, 0x06, 0x6d, 0x05, 0x73, 0x04, 0x76, 0x03, 0x79, 0x02, 0x7c, 0x02,
+ 0x7e, 0x01, 0x81, 0x01, 0x84, 0x00, 0x87, 0x00, 0x89, 0x00, 0x8b, 0x00,
+ 0x8c, 0x00, 0x8d, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x3b, 0x14, 0x28,
+ 0x20, 0x1c, 0x2a, 0x14, 0x34, 0x0f, 0x3e, 0x0b, 0x45, 0x07, 0x4c, 0x05,
+ 0x53, 0x04, 0x58, 0x03, 0x5e, 0x02, 0x63, 0x01, 0x67, 0x01, 0x6c, 0x00,
+ 0x6f, 0x00, 0x72, 0x00, 0x76, 0x00, 0x78, 0x00, 0x7c, 0x00, 0x7e, 0x00,
+ 0x60, 0x1d, 0x66, 0x14, 0x6b, 0x0e, 0x71, 0x0a, 0x76, 0x07, 0x7a, 0x05,
+ 0x7e, 0x03, 0x81, 0x02, 0x85, 0x02, 0x88, 0x01, 0x8b, 0x01, 0x8d, 0x00,
+ 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x96, 0x00, 0x98, 0x00,
+ 0x99, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x27, 0x4a, 0x1d,
+ 0x4f, 0x16, 0x57, 0x11, 0x5b, 0x0e, 0x61, 0x0b, 0x66, 0x08, 0x69, 0x07,
+ 0x6d, 0x05, 0x71, 0x04, 0x75, 0x03, 0x77, 0x02, 0x7a, 0x02, 0x7c, 0x02,
+ 0x7e, 0x01, 0x80, 0x01, 0x83, 0x01, 0x86, 0x00, 0x88, 0x00, 0x89, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x3d, 0x13, 0x2c, 0x1c, 0x20, 0x27, 0x18,
+ 0x2f, 0x12, 0x38, 0x0e, 0x3e, 0x0a, 0x45, 0x07, 0x4b, 0x06, 0x51, 0x05,
+ 0x57, 0x04, 0x5c, 0x02, 0x60, 0x02, 0x65, 0x01, 0x67, 0x01, 0x6c, 0x00,
+ 0x6f, 0x00, 0x71, 0x00, 0x75, 0x00, 0x77, 0x00, 0x60, 0x1e, 0x65, 0x16,
+ 0x6a, 0x10, 0x6f, 0x0c, 0x73, 0x09, 0x77, 0x07, 0x7b, 0x05, 0x7e, 0x03,
+ 0x81, 0x03, 0x84, 0x02, 0x87, 0x02, 0x89, 0x01, 0x8b, 0x01, 0x8e, 0x00,
+ 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00,
+ 0x27, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x8f, 0x00, 0x96, 0x00, 0x99, 0x00,
+ 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00,
+ 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x2c, 0x14, 0x57, 0x00,
+ 0x82, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x9c, 0x00,
+ 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00,
+ 0x9e, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x8c, 0x00, 0x63, 0x00, 0x7f, 0x00, 0x89, 0x00, 0x90, 0x00, 0x96, 0x00,
+ 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00,
+ 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x31, 0x11, 0x5f, 0x00,
+ 0x85, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00,
+ 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00,
+ 0x9e, 0x00, 0x9e, 0x00, 0x43, 0x29, 0x48, 0x20, 0x4d, 0x19, 0x54, 0x14,
+ 0x58, 0x10, 0x5c, 0x0d, 0x62, 0x0b, 0x66, 0x09, 0x69, 0x07, 0x6c, 0x06,
+ 0x70, 0x05, 0x74, 0x04, 0x76, 0x03, 0x78, 0x02, 0x7a, 0x02, 0x7c, 0x02,
+ 0x7e, 0x02, 0x80, 0x01, 0x82, 0x01, 0x85, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0x09, 0x3f, 0x11, 0x2f, 0x1b, 0x23, 0x23, 0x1b, 0x2b, 0x15, 0x32, 0x11,
+ 0x39, 0x0d, 0x40, 0x0a, 0x45, 0x08, 0x4b, 0x07, 0x51, 0x05, 0x56, 0x04,
+ 0x59, 0x03, 0x5e, 0x02, 0x61, 0x02, 0x65, 0x01, 0x68, 0x01, 0x6b, 0x00,
+ 0x6e, 0x00, 0x71, 0x00, 0x60, 0x1f, 0x64, 0x17, 0x69, 0x11, 0x6d, 0x0d,
+ 0x71, 0x0a, 0x75, 0x08, 0x78, 0x06, 0x7b, 0x05, 0x7e, 0x04, 0x81, 0x03,
+ 0x84, 0x02, 0x86, 0x02, 0x88, 0x01, 0x8a, 0x01, 0x8c, 0x01, 0x8e, 0x00,
+ 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x00, 0x00, 0x0d, 0x00,
+ 0x4f, 0x00, 0x73, 0x00, 0x84, 0x00, 0x8d, 0x00, 0x92, 0x00, 0x95, 0x00,
+ 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00,
+ 0x9c, 0x00, 0x9d, 0x00, 0x01, 0x29, 0x16, 0x04, 0x57, 0x00, 0x78, 0x00,
+ 0x87, 0x00, 0x8f, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00,
+ 0x9b, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x4d, 0x00,
+ 0x60, 0x00, 0x77, 0x00, 0x83, 0x00, 0x8c, 0x00, 0x92, 0x00, 0x95, 0x00,
+ 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00,
+ 0x9c, 0x00, 0x9d, 0x00, 0x03, 0x23, 0x20, 0x00, 0x5f, 0x00, 0x7c, 0x00,
+ 0x8a, 0x00, 0x91, 0x00, 0x95, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a, 0x00,
+ 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00,
+ 0x43, 0x2b, 0x47, 0x22, 0x4c, 0x1b, 0x51, 0x16, 0x56, 0x12, 0x59, 0x0f,
+ 0x5e, 0x0d, 0x63, 0x0b, 0x66, 0x09, 0x69, 0x07, 0x6b, 0x06, 0x6f, 0x05,
+ 0x73, 0x05, 0x75, 0x03, 0x77, 0x03, 0x79, 0x02, 0x7a, 0x02, 0x7c, 0x02,
+ 0x7e, 0x02, 0x7f, 0x01, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x40, 0x11, 0x31,
+ 0x18, 0x26, 0x20, 0x1e, 0x28, 0x18, 0x2f, 0x13, 0x35, 0x0f, 0x3c, 0x0c,
+ 0x41, 0x0a, 0x46, 0x08, 0x4b, 0x07, 0x50, 0x05, 0x54, 0x04, 0x58, 0x04,
+ 0x5c, 0x02, 0x5f, 0x02, 0x62, 0x02, 0x66, 0x01, 0x69, 0x01, 0x6b, 0x00,
+ 0x60, 0x20, 0x64, 0x18, 0x68, 0x13, 0x6b, 0x0f, 0x6f, 0x0c, 0x73, 0x09,
+ 0x76, 0x07, 0x79, 0x06, 0x7c, 0x05, 0x7e, 0x04, 0x81, 0x03, 0x83, 0x02,
+ 0x85, 0x02, 0x88, 0x02, 0x89, 0x01, 0x8b, 0x01, 0x8d, 0x01, 0x8e, 0x00,
+ 0x90, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x38, 0x00,
+ 0x5b, 0x00, 0x6f, 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e, 0x00,
+ 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00,
+ 0x00, 0x49, 0x00, 0x27, 0x12, 0x01, 0x43, 0x00, 0x61, 0x00, 0x74, 0x00,
+ 0x7f, 0x00, 0x87, 0x00, 0x8c, 0x00, 0x90, 0x00, 0x93, 0x00, 0x95, 0x00,
+ 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x60, 0x00, 0x24, 0x00, 0x48, 0x00,
+ 0x60, 0x00, 0x70, 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e, 0x00,
+ 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00,
+ 0x00, 0x46, 0x00, 0x1f, 0x1f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x79, 0x00,
+ 0x83, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x92, 0x00, 0x94, 0x00, 0x96, 0x00,
+ 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x43, 0x2d, 0x46, 0x24,
+ 0x4b, 0x1e, 0x4f, 0x19, 0x55, 0x14, 0x58, 0x11, 0x5b, 0x0e, 0x5f, 0x0c,
+ 0x64, 0x0a, 0x66, 0x09, 0x68, 0x07, 0x6a, 0x06, 0x6e, 0x06, 0x72, 0x05,
+ 0x74, 0x04, 0x76, 0x03, 0x78, 0x03, 0x79, 0x02, 0x7b, 0x02, 0x7c, 0x02,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x40, 0x10, 0x33, 0x17, 0x28, 0x1e, 0x20,
+ 0x25, 0x1a, 0x2c, 0x16, 0x32, 0x12, 0x37, 0x0f, 0x3d, 0x0c, 0x42, 0x0a,
+ 0x46, 0x08, 0x4b, 0x07, 0x4f, 0x05, 0x53, 0x05, 0x57, 0x04, 0x5a, 0x04,
+ 0x5e, 0x02, 0x61, 0x02, 0x63, 0x01, 0x66, 0x01, 0x60, 0x20, 0x63, 0x19,
+ 0x67, 0x14, 0x6a, 0x10, 0x6e, 0x0d, 0x71, 0x0b, 0x74, 0x09, 0x77, 0x07,
+ 0x7a, 0x06, 0x7c, 0x05, 0x7f, 0x04, 0x81, 0x03, 0x83, 0x02, 0x85, 0x02,
+ 0x87, 0x02, 0x88, 0x02, 0x8a, 0x01, 0x8c, 0x01, 0x8d, 0x00, 0x8e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2a, 0x00, 0x48, 0x00,
+ 0x5d, 0x00, 0x6c, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88, 0x00,
+ 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x92, 0x00, 0x00, 0x54, 0x00, 0x41,
+ 0x00, 0x17, 0x10, 0x00, 0x36, 0x00, 0x51, 0x00, 0x64, 0x00, 0x71, 0x00,
+ 0x7a, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8a, 0x00, 0x8d, 0x00, 0x90, 0x00,
+ 0x92, 0x00, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x89, 0x00, 0x77, 0x00, 0x48, 0x00, 0x0f, 0x00, 0x30, 0x00, 0x48, 0x00,
+ 0x5d, 0x00, 0x6c, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88, 0x00,
+ 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x92, 0x00, 0x00, 0x52, 0x00, 0x3c,
+ 0x00, 0x0d, 0x1f, 0x00, 0x42, 0x00, 0x5a, 0x00, 0x6a, 0x00, 0x76, 0x00,
+ 0x7e, 0x00, 0x84, 0x00, 0x89, 0x00, 0x8c, 0x00, 0x8f, 0x00, 0x91, 0x00,
+ 0x93, 0x00, 0x95, 0x00, 0x42, 0x2e, 0x45, 0x26, 0x4b, 0x1f, 0x4d, 0x1a,
+ 0x52, 0x16, 0x56, 0x13, 0x59, 0x10, 0x5c, 0x0e, 0x61, 0x0c, 0x64, 0x0a,
+ 0x66, 0x09, 0x68, 0x07, 0x6a, 0x07, 0x6d, 0x06, 0x71, 0x05, 0x74, 0x05,
+ 0x75, 0x03, 0x77, 0x03, 0x78, 0x02, 0x7a, 0x02, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0x09, 0x41, 0x0f, 0x34, 0x16, 0x2a, 0x1c, 0x23, 0x23, 0x1d, 0x29, 0x18,
+ 0x2e, 0x14, 0x34, 0x11, 0x39, 0x0e, 0x3e, 0x0c, 0x42, 0x0a, 0x47, 0x08,
+ 0x4b, 0x07, 0x4f, 0x05, 0x52, 0x05, 0x56, 0x04, 0x59, 0x04, 0x5c, 0x03,
+ 0x5f, 0x02, 0x62, 0x02, 0x60, 0x20, 0x63, 0x1a, 0x66, 0x15, 0x6a, 0x11,
+ 0x6d, 0x0e, 0x70, 0x0c, 0x73, 0x0a, 0x75, 0x08, 0x78, 0x07, 0x7a, 0x06,
+ 0x7d, 0x05, 0x7f, 0x04, 0x81, 0x03, 0x83, 0x02, 0x85, 0x02, 0x86, 0x02,
+ 0x88, 0x02, 0x89, 0x01, 0x8b, 0x01, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f, 0x00,
+ 0x5e, 0x00, 0x69, 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83, 0x00,
+ 0x86, 0x00, 0x89, 0x00, 0x00, 0x59, 0x00, 0x4d, 0x00, 0x2f, 0x00, 0x0e,
+ 0x10, 0x00, 0x2e, 0x00, 0x46, 0x00, 0x57, 0x00, 0x64, 0x00, 0x6f, 0x00,
+ 0x76, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x85, 0x00, 0x89, 0x00, 0x8b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x83, 0x00,
+ 0x60, 0x00, 0x30, 0x00, 0x02, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f, 0x00,
+ 0x5e, 0x00, 0x69, 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83, 0x00,
+ 0x86, 0x00, 0x89, 0x00, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x28, 0x00, 0x02,
+ 0x1f, 0x00, 0x3b, 0x00, 0x4f, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x74, 0x00,
+ 0x7b, 0x00, 0x80, 0x00, 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d, 0x00,
+ 0x42, 0x2f, 0x44, 0x27, 0x4a, 0x22, 0x4c, 0x1c, 0x50, 0x18, 0x55, 0x14,
+ 0x57, 0x12, 0x5a, 0x0f, 0x5d, 0x0d, 0x62, 0x0c, 0x64, 0x0a, 0x66, 0x09,
+ 0x68, 0x08, 0x6a, 0x07, 0x6c, 0x06, 0x70, 0x05, 0x73, 0x05, 0x75, 0x04,
+ 0x76, 0x03, 0x78, 0x03, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x42, 0x0f, 0x36,
+ 0x15, 0x2c, 0x1b, 0x25, 0x21, 0x1f, 0x26, 0x1a, 0x2c, 0x16, 0x31, 0x12,
+ 0x36, 0x0f, 0x3a, 0x0d, 0x3f, 0x0c, 0x43, 0x0a, 0x47, 0x08, 0x4b, 0x07,
+ 0x4e, 0x05, 0x52, 0x05, 0x55, 0x04, 0x58, 0x04, 0x5b, 0x04, 0x5d, 0x02,
+ 0x60, 0x21, 0x63, 0x1b, 0x66, 0x16, 0x69, 0x12, 0x6c, 0x0f, 0x6e, 0x0d,
+ 0x71, 0x0b, 0x74, 0x09, 0x76, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7d, 0x05,
+ 0x7f, 0x04, 0x81, 0x03, 0x82, 0x02, 0x84, 0x02, 0x86, 0x02, 0x87, 0x02,
+ 0x89, 0x02, 0x8a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53, 0x00,
+ 0x5e, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e, 0x00,
+ 0x00, 0x5b, 0x00, 0x53, 0x00, 0x3e, 0x00, 0x23, 0x02, 0x0a, 0x10, 0x00,
+ 0x29, 0x00, 0x3d, 0x00, 0x4e, 0x00, 0x5b, 0x00, 0x65, 0x00, 0x6d, 0x00,
+ 0x74, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x8c, 0x00, 0x70, 0x00, 0x48, 0x00,
+ 0x22, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53, 0x00,
+ 0x5e, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e, 0x00,
+ 0x00, 0x5a, 0x00, 0x51, 0x00, 0x39, 0x00, 0x1a, 0x04, 0x00, 0x1f, 0x00,
+ 0x36, 0x00, 0x48, 0x00, 0x57, 0x00, 0x62, 0x00, 0x6b, 0x00, 0x73, 0x00,
+ 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x85, 0x00, 0x42, 0x31, 0x44, 0x29,
+ 0x49, 0x23, 0x4c, 0x1e, 0x4e, 0x1a, 0x53, 0x16, 0x56, 0x13, 0x58, 0x11,
+ 0x5a, 0x0f, 0x5f, 0x0d, 0x63, 0x0b, 0x64, 0x0a, 0x66, 0x09, 0x68, 0x08,
+ 0x6a, 0x07, 0x6b, 0x06, 0x6f, 0x06, 0x72, 0x05, 0x74, 0x05, 0x75, 0x03,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x43, 0x0f, 0x37, 0x14, 0x2e, 0x19, 0x27,
+ 0x1f, 0x21, 0x24, 0x1c, 0x29, 0x18, 0x2e, 0x15, 0x33, 0x12, 0x37, 0x0f,
+ 0x3b, 0x0c, 0x40, 0x0c, 0x43, 0x0a, 0x47, 0x08, 0x4b, 0x07, 0x4e, 0x06,
+ 0x51, 0x05, 0x55, 0x05, 0x56, 0x04, 0x5a, 0x04, 0x60, 0x21, 0x63, 0x1b,
+ 0x65, 0x17, 0x68, 0x13, 0x6b, 0x10, 0x6e, 0x0e, 0x70, 0x0c, 0x73, 0x0a,
+ 0x75, 0x09, 0x77, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7d, 0x05, 0x7f, 0x04,
+ 0x81, 0x03, 0x82, 0x03, 0x84, 0x02, 0x86, 0x02, 0x87, 0x02, 0x88, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55, 0x00,
+ 0x5f, 0x00, 0x66, 0x00, 0x6d, 0x00, 0x72, 0x00, 0x00, 0x5c, 0x00, 0x56,
+ 0x00, 0x47, 0x00, 0x31, 0x00, 0x1a, 0x04, 0x08, 0x10, 0x00, 0x25, 0x00,
+ 0x37, 0x00, 0x46, 0x00, 0x52, 0x00, 0x5d, 0x00, 0x65, 0x00, 0x6c, 0x00,
+ 0x72, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x00, 0x92, 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c, 0x00,
+ 0x01, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55, 0x00,
+ 0x5f, 0x00, 0x66, 0x00, 0x6d, 0x00, 0x72, 0x00, 0x00, 0x5c, 0x00, 0x55,
+ 0x00, 0x43, 0x00, 0x2a, 0x00, 0x10, 0x09, 0x00, 0x1f, 0x00, 0x33, 0x00,
+ 0x43, 0x00, 0x50, 0x00, 0x5b, 0x00, 0x64, 0x00, 0x6b, 0x00, 0x72, 0x00,
+ 0x77, 0x00, 0x7b, 0x00, 0x42, 0x31, 0x44, 0x2a, 0x48, 0x24, 0x4b, 0x1f,
+ 0x4d, 0x1b, 0x51, 0x18, 0x55, 0x15, 0x57, 0x12, 0x59, 0x10, 0x5b, 0x0e,
+ 0x5f, 0x0c, 0x63, 0x0b, 0x65, 0x0a, 0x66, 0x09, 0x68, 0x08, 0x6a, 0x07,
+ 0x6b, 0x06, 0x6e, 0x06, 0x71, 0x05, 0x73, 0x05, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0x0a, 0x43, 0x0e, 0x38, 0x13, 0x2f, 0x18, 0x28, 0x1d, 0x22, 0x22, 0x1d,
+ 0x27, 0x19, 0x2b, 0x16, 0x30, 0x12, 0x35, 0x11, 0x39, 0x0f, 0x3c, 0x0c,
+ 0x41, 0x0b, 0x44, 0x0a, 0x47, 0x09, 0x4a, 0x07, 0x4e, 0x07, 0x50, 0x05,
+ 0x54, 0x05, 0x55, 0x04, 0x60, 0x21, 0x63, 0x1c, 0x65, 0x17, 0x68, 0x14,
+ 0x6a, 0x11, 0x6c, 0x0e, 0x6f, 0x0c, 0x71, 0x0b, 0x73, 0x09, 0x76, 0x08,
+ 0x78, 0x07, 0x79, 0x06, 0x7c, 0x05, 0x7d, 0x05, 0x7f, 0x04, 0x81, 0x03,
+ 0x82, 0x03, 0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x26, 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57, 0x00,
+ 0x5f, 0x00, 0x66, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4d, 0x00, 0x3b,
+ 0x00, 0x27, 0x00, 0x13, 0x06, 0x07, 0x10, 0x00, 0x22, 0x00, 0x32, 0x00,
+ 0x40, 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x65, 0x00, 0x6b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x95, 0x00,
+ 0x84, 0x00, 0x6c, 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x26, 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57, 0x00,
+ 0x5f, 0x00, 0x66, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x36,
+ 0x00, 0x1f, 0x00, 0x08, 0x0c, 0x00, 0x1f, 0x00, 0x30, 0x00, 0x3f, 0x00,
+ 0x4b, 0x00, 0x55, 0x00, 0x5e, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x71, 0x00,
+ 0x42, 0x32, 0x44, 0x2b, 0x47, 0x25, 0x4b, 0x21, 0x4c, 0x1d, 0x4f, 0x19,
+ 0x54, 0x16, 0x56, 0x14, 0x58, 0x11, 0x5a, 0x10, 0x5d, 0x0e, 0x61, 0x0c,
+ 0x63, 0x0b, 0x65, 0x0a, 0x66, 0x09, 0x68, 0x08, 0x69, 0x07, 0x6b, 0x07,
+ 0x6d, 0x06, 0x71, 0x05, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x43, 0x0e, 0x39,
+ 0x12, 0x31, 0x17, 0x2a, 0x1c, 0x24, 0x21, 0x1f, 0x26, 0x1b, 0x2a, 0x18,
+ 0x2e, 0x16, 0x32, 0x12, 0x35, 0x0f, 0x3a, 0x0f, 0x3d, 0x0c, 0x41, 0x0b,
+ 0x44, 0x0a, 0x47, 0x09, 0x4a, 0x07, 0x4e, 0x07, 0x4f, 0x05, 0x53, 0x05,
+ 0x60, 0x21, 0x62, 0x1c, 0x65, 0x18, 0x67, 0x15, 0x6a, 0x12, 0x6c, 0x0f,
+ 0x6e, 0x0d, 0x71, 0x0c, 0x73, 0x0b, 0x74, 0x09, 0x76, 0x07, 0x79, 0x07,
+ 0x7a, 0x06, 0x7c, 0x05, 0x7d, 0x05, 0x7f, 0x04, 0x81, 0x03, 0x82, 0x03,
+ 0x83, 0x02, 0x85, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00,
+ 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58, 0x00,
+ 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x51, 0x00, 0x42, 0x00, 0x32, 0x00, 0x20,
+ 0x00, 0x0e, 0x07, 0x06, 0x10, 0x00, 0x20, 0x00, 0x2f, 0x00, 0x3b, 0x00,
+ 0x46, 0x00, 0x50, 0x00, 0x58, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76, 0x00,
+ 0x5e, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x00,
+ 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58, 0x00,
+ 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4e, 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x17,
+ 0x00, 0x03, 0x0f, 0x00, 0x1f, 0x00, 0x2e, 0x00, 0x3b, 0x00, 0x46, 0x00,
+ 0x50, 0x00, 0x59, 0x00, 0x60, 0x00, 0x66, 0x00, 0x42, 0x33, 0x43, 0x2c,
+ 0x46, 0x27, 0x4a, 0x22, 0x4c, 0x1e, 0x4d, 0x1b, 0x52, 0x18, 0x55, 0x15,
+ 0x57, 0x13, 0x58, 0x11, 0x5a, 0x0f, 0x5e, 0x0e, 0x62, 0x0c, 0x63, 0x0b,
+ 0x65, 0x0a, 0x66, 0x09, 0x68, 0x08, 0x69, 0x07, 0x6b, 0x07, 0x6c, 0x06,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x44, 0x0d, 0x3a, 0x12, 0x32, 0x16, 0x2b,
+ 0x1b, 0x26, 0x1f, 0x22, 0x24, 0x1d, 0x28, 0x19, 0x2b, 0x16, 0x30, 0x14,
+ 0x34, 0x12, 0x37, 0x0f, 0x3b, 0x0e, 0x3e, 0x0c, 0x41, 0x0b, 0x45, 0x0a,
+ 0x47, 0x09, 0x4a, 0x07, 0x4e, 0x07, 0x4f, 0x05, 0x60, 0x22, 0x62, 0x1d,
+ 0x65, 0x19, 0x66, 0x15, 0x69, 0x13, 0x6b, 0x11, 0x6d, 0x0e, 0x6f, 0x0c,
+ 0x71, 0x0b, 0x73, 0x0a, 0x76, 0x09, 0x77, 0x07, 0x79, 0x07, 0x7a, 0x06,
+ 0x7c, 0x05, 0x7e, 0x05, 0x7f, 0x04, 0x80, 0x03, 0x82, 0x03, 0x83, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x2c, 0x00, 0x37, 0x00, 0x41, 0x00, 0x4a, 0x00, 0x00, 0x5e, 0x00, 0x5b,
+ 0x00, 0x53, 0x00, 0x48, 0x00, 0x3a, 0x00, 0x2a, 0x00, 0x1a, 0x00, 0x0b,
+ 0x08, 0x05, 0x10, 0x00, 0x1e, 0x00, 0x2c, 0x00, 0x37, 0x00, 0x42, 0x00,
+ 0x4b, 0x00, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53, 0x00,
+ 0x3c, 0x00, 0x26, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x2c, 0x00, 0x37, 0x00, 0x41, 0x00, 0x4a, 0x00, 0x00, 0x5e, 0x00, 0x5b,
+ 0x00, 0x52, 0x00, 0x45, 0x00, 0x34, 0x00, 0x22, 0x00, 0x10, 0x00, 0x00,
+ 0x11, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x43, 0x00, 0x4c, 0x00,
+ 0x54, 0x00, 0x5b, 0x00, 0x42, 0x33, 0x43, 0x2d, 0x45, 0x28, 0x49, 0x23,
+ 0x4b, 0x1f, 0x4d, 0x1c, 0x50, 0x19, 0x55, 0x16, 0x56, 0x14, 0x58, 0x12,
+ 0x59, 0x11, 0x5b, 0x0e, 0x5f, 0x0d, 0x62, 0x0c, 0x63, 0x0b, 0x65, 0x0a,
+ 0x66, 0x09, 0x68, 0x09, 0x69, 0x07, 0x6b, 0x07, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0x0a, 0x44, 0x0d, 0x3a, 0x12, 0x33, 0x16, 0x2c, 0x19, 0x27, 0x1e, 0x22,
+ 0x21, 0x1e, 0x26, 0x1a, 0x2b, 0x18, 0x2e, 0x16, 0x31, 0x12, 0x35, 0x11,
+ 0x38, 0x0f, 0x3b, 0x0d, 0x3f, 0x0c, 0x41, 0x0a, 0x45, 0x0a, 0x47, 0x09,
+ 0x4a, 0x07, 0x4e, 0x07, 0x60, 0x22, 0x62, 0x1d, 0x64, 0x19, 0x66, 0x16,
+ 0x68, 0x13, 0x6a, 0x11, 0x6c, 0x0f, 0x6e, 0x0d, 0x71, 0x0c, 0x73, 0x0b,
+ 0x74, 0x09, 0x76, 0x08, 0x78, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7c, 0x05,
+ 0x7e, 0x05, 0x7f, 0x04, 0x80, 0x03, 0x82, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28, 0x00,
+ 0x33, 0x00, 0x3d, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4c,
+ 0x00, 0x40, 0x00, 0x32, 0x00, 0x24, 0x00, 0x15, 0x02, 0x0a, 0x09, 0x04,
+ 0x10, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x34, 0x00, 0x3e, 0x00, 0x46, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00,
+ 0x91, 0x00, 0x83, 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36, 0x00,
+ 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28, 0x00,
+ 0x33, 0x00, 0x3d, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x49,
+ 0x00, 0x3b, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x0b, 0x04, 0x00, 0x12, 0x00,
+ 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x00, 0x40, 0x00, 0x49, 0x00, 0x50, 0x00,
+ 0x42, 0x34, 0x43, 0x2e, 0x44, 0x29, 0x49, 0x24, 0x4b, 0x20, 0x4c, 0x1d,
+ 0x4e, 0x1a, 0x53, 0x18, 0x55, 0x15, 0x56, 0x13, 0x58, 0x11, 0x5a, 0x10,
+ 0x5c, 0x0e, 0x60, 0x0d, 0x63, 0x0c, 0x64, 0x0b, 0x65, 0x0a, 0x66, 0x09,
+ 0x68, 0x09, 0x69, 0x07, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x44, 0x0c, 0x3b,
+ 0x11, 0x34, 0x16, 0x2e, 0x19, 0x28, 0x1d, 0x23, 0x21, 0x20, 0x25, 0x1d,
+ 0x29, 0x19, 0x2b, 0x16, 0x30, 0x14, 0x33, 0x12, 0x35, 0x0f, 0x3a, 0x0f,
+ 0x3c, 0x0c, 0x40, 0x0c, 0x41, 0x0a, 0x45, 0x0a, 0x47, 0x09, 0x4a, 0x07,
+ 0x60, 0x22, 0x62, 0x1d, 0x64, 0x1a, 0x66, 0x17, 0x68, 0x14, 0x6a, 0x11,
+ 0x6c, 0x10, 0x6e, 0x0e, 0x70, 0x0c, 0x71, 0x0b, 0x73, 0x0a, 0x75, 0x09,
+ 0x76, 0x07, 0x78, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7c, 0x05, 0x7e, 0x05,
+ 0x7f, 0x04, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f, 0x00,
+ 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38,
+ 0x00, 0x2c, 0x00, 0x1f, 0x00, 0x12, 0x03, 0x09, 0x09, 0x04, 0x10, 0x00,
+ 0x1c, 0x00, 0x27, 0x00, 0x31, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88, 0x00,
+ 0x79, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f, 0x00,
+ 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x41, 0x00, 0x33,
+ 0x00, 0x24, 0x00, 0x15, 0x00, 0x07, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00,
+ 0x2a, 0x00, 0x34, 0x00, 0x3d, 0x00, 0x46, 0x00, 0x42, 0x34, 0x43, 0x2f,
+ 0x44, 0x29, 0x49, 0x25, 0x4b, 0x21, 0x4c, 0x1e, 0x4d, 0x1b, 0x51, 0x18,
+ 0x55, 0x16, 0x56, 0x14, 0x58, 0x13, 0x59, 0x11, 0x5a, 0x0f, 0x5d, 0x0e,
+ 0x61, 0x0c, 0x63, 0x0c, 0x64, 0x0b, 0x65, 0x0a, 0x66, 0x09, 0x68, 0x09,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
+ 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x44, 0x0c, 0x3c, 0x10, 0x35, 0x15, 0x2f,
+ 0x19, 0x2a, 0x1c, 0x25, 0x20, 0x22, 0x23, 0x1d, 0x26, 0x1a, 0x2b, 0x18,
+ 0x2e, 0x16, 0x30, 0x12, 0x35, 0x12, 0x37, 0x0f, 0x3b, 0x0f, 0x3d, 0x0c,
+ 0x41, 0x0c, 0x42, 0x0a, 0x46, 0x0a, 0x47, 0x09, 0x60, 0x22, 0x62, 0x1e,
+ 0x64, 0x1a, 0x66, 0x17, 0x68, 0x15, 0x6a, 0x12, 0x6b, 0x11, 0x6d, 0x0e,
+ 0x6e, 0x0d, 0x71, 0x0c, 0x72, 0x0b, 0x74, 0x09, 0x76, 0x09, 0x77, 0x07,
+ 0x79, 0x07, 0x7a, 0x06, 0x7c, 0x06, 0x7c, 0x05, 0x7e, 0x05, 0x7f, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x22, 0x00, 0x00, 0x5e, 0x00, 0x5d,
+ 0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x26,
+ 0x00, 0x1a, 0x00, 0x0f, 0x04, 0x08, 0x0a, 0x04, 0x10, 0x00, 0x1b, 0x00,
+ 0x25, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f, 0x00,
+ 0x5f, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d, 0x00,
+ 0x00, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x22, 0x00, 0x00, 0x5e, 0x00, 0x5d,
+ 0x00, 0x57, 0x00, 0x4f, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x1e,
+ 0x00, 0x10, 0x00, 0x03, 0x08, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x2a, 0x00,
+ 0x33, 0x00, 0x3b, 0x00, 0x4f, 0x2a, 0x56, 0x28, 0x59, 0x27, 0x5a, 0x26,
+ 0x5c, 0x26, 0x5c, 0x26, 0x5c, 0x26, 0x5d, 0x26, 0x5d, 0x26, 0x5d, 0x25,
+ 0x5d, 0x25, 0x5d, 0x25, 0x5d, 0x25, 0x5d, 0x25, 0x5e, 0x25, 0x5e, 0x25,
+ 0x5e, 0x24, 0x5e, 0x24, 0x5e, 0x24, 0x5e, 0x24, 0x92, 0x0e, 0x79, 0x14,
+ 0x6f, 0x18, 0x6b, 0x1b, 0x68, 0x1d, 0x67, 0x1d, 0x66, 0x1e, 0x65, 0x1f,
+ 0x64, 0x20, 0x64, 0x20, 0x63, 0x20, 0x63, 0x21, 0x63, 0x21, 0x63, 0x21,
+ 0x63, 0x21, 0x62, 0x22, 0x62, 0x22, 0x62, 0x22, 0x62, 0x22, 0x62, 0x22,
+ 0x16, 0x23, 0x3c, 0x23, 0x4a, 0x23, 0x50, 0x23, 0x54, 0x23, 0x56, 0x23,
+ 0x58, 0x23, 0x59, 0x23, 0x5a, 0x23, 0x5a, 0x23, 0x5b, 0x23, 0x5b, 0x23,
+ 0x5b, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23,
+ 0x5d, 0x23, 0x5d, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x16, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53,
+ 0x00, 0x4b, 0x00, 0x42, 0x00, 0x38, 0x00, 0x2d, 0x00, 0x22, 0x00, 0x17,
+ 0x00, 0x0c, 0x05, 0x07, 0x0a, 0x03, 0x0f, 0x00, 0x1a, 0x00, 0x24, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
+ 0x97, 0x00, 0x8e, 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57, 0x00,
+ 0x47, 0x00, 0x37, 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x16, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x52,
+ 0x00, 0x49, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c,
+ 0x00, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x31, 0x00,
+ 0x48, 0x31, 0x4f, 0x2e, 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x29, 0x58, 0x29,
+ 0x59, 0x28, 0x59, 0x27, 0x5a, 0x27, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x27,
+ 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27,
+ 0x5c, 0x27, 0x5c, 0x27, 0xa1, 0x01, 0x88, 0x07, 0x7b, 0x0c, 0x74, 0x0f,
+ 0x70, 0x12, 0x6d, 0x14, 0x6b, 0x16, 0x6a, 0x17, 0x69, 0x18, 0x68, 0x19,
+ 0x67, 0x1a, 0x66, 0x1b, 0x66, 0x1b, 0x65, 0x1c, 0x65, 0x1c, 0x65, 0x1d,
+ 0x65, 0x1d, 0x64, 0x1d, 0x64, 0x1e, 0x64, 0x1e, 0x0a, 0x32, 0x22, 0x25,
+ 0x31, 0x24, 0x3b, 0x23, 0x42, 0x23, 0x47, 0x23, 0x4a, 0x23, 0x4d, 0x23,
+ 0x4f, 0x23, 0x51, 0x23, 0x52, 0x23, 0x53, 0x23, 0x54, 0x23, 0x55, 0x23,
+ 0x56, 0x23, 0x56, 0x23, 0x57, 0x23, 0x58, 0x23, 0x58, 0x23, 0x58, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45,
+ 0x00, 0x3c, 0x00, 0x32, 0x00, 0x28, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x0b,
+ 0x06, 0x07, 0x0b, 0x03, 0x0f, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90, 0x00,
+ 0x86, 0x00, 0x7a, 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41, 0x00,
+ 0x33, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42,
+ 0x00, 0x37, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x01, 0x00,
+ 0x0c, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x28, 0x00, 0x45, 0x34, 0x4b, 0x31,
+ 0x4f, 0x2f, 0x52, 0x2d, 0x54, 0x2c, 0x55, 0x2b, 0x57, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x29, 0x58, 0x29, 0x59, 0x28, 0x59, 0x27, 0x5a, 0x27,
+ 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27,
+ 0xa7, 0x00, 0x92, 0x03, 0x84, 0x06, 0x7d, 0x09, 0x77, 0x0c, 0x73, 0x0e,
+ 0x71, 0x10, 0x6f, 0x11, 0x6d, 0x13, 0x6b, 0x14, 0x6a, 0x15, 0x6a, 0x16,
+ 0x69, 0x17, 0x68, 0x17, 0x68, 0x18, 0x67, 0x19, 0x66, 0x19, 0x66, 0x1a,
+ 0x66, 0x1a, 0x66, 0x1a, 0x0a, 0x38, 0x18, 0x2b, 0x25, 0x27, 0x2e, 0x25,
+ 0x35, 0x24, 0x3b, 0x23, 0x3f, 0x23, 0x43, 0x23, 0x46, 0x23, 0x48, 0x23,
+ 0x4a, 0x23, 0x4c, 0x23, 0x4e, 0x23, 0x4f, 0x23, 0x50, 0x23, 0x51, 0x23,
+ 0x52, 0x23, 0x53, 0x23, 0x53, 0x23, 0x54, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e,
+ 0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x48, 0x00, 0x40, 0x00, 0x37,
+ 0x00, 0x2d, 0x00, 0x24, 0x00, 0x1a, 0x00, 0x11, 0x01, 0x0a, 0x06, 0x06,
+ 0x0b, 0x03, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00,
+ 0x72, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f, 0x00,
+ 0x22, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d,
+ 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x31,
+ 0x00, 0x26, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x06, 0x03, 0x00, 0x0d, 0x00,
+ 0x17, 0x00, 0x1f, 0x00, 0x44, 0x36, 0x49, 0x33, 0x4d, 0x31, 0x4f, 0x2f,
+ 0x51, 0x2e, 0x53, 0x2d, 0x53, 0x2c, 0x55, 0x2b, 0x56, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x29, 0x58, 0x29,
+ 0x59, 0x28, 0x5a, 0x27, 0x5b, 0x27, 0x5c, 0x27, 0xaa, 0x00, 0x98, 0x01,
+ 0x8c, 0x03, 0x83, 0x05, 0x7d, 0x08, 0x79, 0x0a, 0x76, 0x0c, 0x73, 0x0d,
+ 0x71, 0x0f, 0x6f, 0x10, 0x6e, 0x11, 0x6d, 0x12, 0x6c, 0x13, 0x6b, 0x14,
+ 0x6a, 0x15, 0x6a, 0x15, 0x69, 0x16, 0x68, 0x17, 0x68, 0x17, 0x68, 0x18,
+ 0x0a, 0x3c, 0x14, 0x30, 0x1e, 0x2a, 0x26, 0x27, 0x2d, 0x25, 0x32, 0x24,
+ 0x36, 0x24, 0x3b, 0x24, 0x3e, 0x23, 0x41, 0x23, 0x43, 0x23, 0x45, 0x23,
+ 0x47, 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23, 0x4d, 0x23, 0x4d, 0x23,
+ 0x4f, 0x23, 0x50, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x31, 0x11, 0x5f, 0x00, 0x85, 0x00, 0x92, 0x00,
+ 0x97, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00,
+ 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x11, 0x03, 0x23,
+ 0x00, 0x46, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5a, 0x00, 0x5c, 0x00, 0x5d,
+ 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e,
+ 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x43, 0x38, 0x48, 0x35, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x30, 0x50, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2c, 0x54, 0x2b, 0x56, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x58, 0x29, 0xac, 0x00, 0x9d, 0x00, 0x91, 0x02, 0x89, 0x03,
+ 0x82, 0x05, 0x7e, 0x07, 0x7a, 0x09, 0x77, 0x0a, 0x75, 0x0c, 0x73, 0x0d,
+ 0x71, 0x0e, 0x70, 0x0f, 0x6e, 0x10, 0x6e, 0x11, 0x6c, 0x12, 0x6c, 0x13,
+ 0x6b, 0x13, 0x6a, 0x14, 0x6a, 0x15, 0x6a, 0x15, 0x09, 0x3f, 0x11, 0x33,
+ 0x1a, 0x2d, 0x21, 0x29, 0x27, 0x27, 0x2c, 0x26, 0x30, 0x25, 0x34, 0x24,
+ 0x37, 0x24, 0x3a, 0x24, 0x3d, 0x23, 0x40, 0x23, 0x42, 0x23, 0x44, 0x23,
+ 0x45, 0x23, 0x47, 0x23, 0x48, 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x23, 0x20, 0x00, 0x5f, 0x00, 0x7c, 0x00, 0x8a, 0x00, 0x91, 0x00,
+ 0x95, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00,
+ 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x20, 0x00, 0x00, 0x1f, 0x00, 0x3c,
+ 0x00, 0x4a, 0x00, 0x51, 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b,
+ 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x39, 0x46, 0x36,
+ 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x54, 0x2b, 0x55, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a,
+ 0xae, 0x00, 0xa1, 0x00, 0x96, 0x01, 0x8d, 0x02, 0x87, 0x03, 0x82, 0x05,
+ 0x7e, 0x07, 0x7b, 0x08, 0x78, 0x09, 0x76, 0x0b, 0x74, 0x0c, 0x73, 0x0d,
+ 0x71, 0x0e, 0x70, 0x0e, 0x6f, 0x0f, 0x6e, 0x11, 0x6d, 0x11, 0x6c, 0x11,
+ 0x6c, 0x12, 0x6b, 0x13, 0x09, 0x40, 0x10, 0x36, 0x17, 0x2f, 0x1d, 0x2c,
+ 0x22, 0x29, 0x27, 0x27, 0x2b, 0x26, 0x2f, 0x25, 0x32, 0x25, 0x35, 0x24,
+ 0x38, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3f, 0x23, 0x40, 0x23, 0x42, 0x23,
+ 0x44, 0x23, 0x45, 0x23, 0x46, 0x23, 0x48, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x1f,
+ 0x1f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x79, 0x00, 0x83, 0x00, 0x8a, 0x00,
+ 0x8e, 0x00, 0x92, 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00,
+ 0x99, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x85, 0x00, 0x5f, 0x00, 0x1f, 0x00, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x39,
+ 0x00, 0x43, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x52, 0x00, 0x54, 0x00, 0x56,
+ 0x00, 0x57, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x39, 0x45, 0x37, 0x48, 0x35, 0x4a, 0x33,
+ 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x52, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x54, 0x2c, 0x55, 0x2a, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0xaf, 0x00, 0xa3, 0x00,
+ 0x99, 0x00, 0x91, 0x01, 0x8b, 0x02, 0x86, 0x03, 0x81, 0x05, 0x7e, 0x06,
+ 0x7b, 0x07, 0x79, 0x09, 0x77, 0x0a, 0x75, 0x0b, 0x74, 0x0c, 0x73, 0x0c,
+ 0x71, 0x0d, 0x71, 0x0e, 0x6f, 0x0f, 0x6e, 0x10, 0x6e, 0x11, 0x6d, 0x11,
+ 0x09, 0x41, 0x0f, 0x38, 0x15, 0x32, 0x1a, 0x2e, 0x1f, 0x2b, 0x24, 0x29,
+ 0x27, 0x27, 0x2b, 0x26, 0x2e, 0x25, 0x31, 0x25, 0x34, 0x25, 0x36, 0x24,
+ 0x38, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3e, 0x23, 0x40, 0x23, 0x41, 0x23,
+ 0x43, 0x23, 0x44, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x3c, 0x00, 0x0d, 0x1f, 0x00,
+ 0x42, 0x00, 0x5a, 0x00, 0x6a, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x84, 0x00,
+ 0x89, 0x00, 0x8c, 0x00, 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x7c, 0x00,
+ 0x4d, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x2a, 0x00, 0x36,
+ 0x00, 0x3e, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4d, 0x00, 0x4f, 0x00, 0x52,
+ 0x00, 0x53, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x3a, 0x45, 0x38, 0x47, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x2f, 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x53, 0x2c, 0x55, 0x2b, 0x57, 0x2a,
+ 0x57, 0x2a, 0x57, 0x2a, 0xb0, 0x00, 0xa5, 0x00, 0x9d, 0x00, 0x95, 0x00,
+ 0x8e, 0x02, 0x89, 0x02, 0x85, 0x03, 0x81, 0x05, 0x7e, 0x06, 0x7c, 0x07,
+ 0x7a, 0x08, 0x78, 0x09, 0x76, 0x0a, 0x75, 0x0b, 0x73, 0x0c, 0x73, 0x0c,
+ 0x71, 0x0d, 0x71, 0x0e, 0x70, 0x0e, 0x6e, 0x0f, 0x09, 0x42, 0x0e, 0x39,
+ 0x13, 0x33, 0x18, 0x2f, 0x1c, 0x2d, 0x21, 0x2a, 0x24, 0x29, 0x28, 0x27,
+ 0x2b, 0x26, 0x2e, 0x26, 0x30, 0x25, 0x33, 0x25, 0x35, 0x25, 0x37, 0x24,
+ 0x39, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x3f, 0x23, 0x40, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x58, 0x00, 0x4a, 0x00, 0x28, 0x00, 0x02, 0x1f, 0x00, 0x3b, 0x00,
+ 0x4f, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x74, 0x00, 0x7b, 0x00, 0x80, 0x00,
+ 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x68, 0x00, 0x42, 0x00,
+ 0x1f, 0x00, 0x04, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x34,
+ 0x00, 0x3b, 0x00, 0x41, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4b, 0x00, 0x4e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39,
+ 0x46, 0x36, 0x49, 0x35, 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x2f, 0x51, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2c, 0x54, 0x2b, 0x56, 0x2a,
+ 0xb1, 0x00, 0xa8, 0x00, 0x9f, 0x00, 0x98, 0x00, 0x91, 0x01, 0x8c, 0x02,
+ 0x88, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7e, 0x06, 0x7c, 0x07, 0x7a, 0x07,
+ 0x79, 0x09, 0x77, 0x09, 0x76, 0x0b, 0x74, 0x0b, 0x73, 0x0c, 0x73, 0x0c,
+ 0x71, 0x0d, 0x71, 0x0e, 0x09, 0x43, 0x0e, 0x3b, 0x12, 0x35, 0x16, 0x31,
+ 0x1a, 0x2e, 0x1e, 0x2c, 0x22, 0x2a, 0x25, 0x28, 0x28, 0x27, 0x2a, 0x27,
+ 0x2d, 0x26, 0x30, 0x25, 0x32, 0x25, 0x34, 0x25, 0x35, 0x25, 0x37, 0x24,
+ 0x39, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x51,
+ 0x00, 0x39, 0x00, 0x1a, 0x04, 0x00, 0x1f, 0x00, 0x36, 0x00, 0x48, 0x00,
+ 0x57, 0x00, 0x62, 0x00, 0x6b, 0x00, 0x73, 0x00, 0x79, 0x00, 0x7e, 0x00,
+ 0x82, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9a, 0x00, 0x91, 0x00, 0x79, 0x00, 0x5a, 0x00, 0x3b, 0x00, 0x1f, 0x00,
+ 0x09, 0x00, 0x00, 0x08, 0x00, 0x17, 0x00, 0x22, 0x00, 0x2c, 0x00, 0x33,
+ 0x00, 0x39, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39, 0x46, 0x37, 0x48, 0x35,
+ 0x4a, 0x35, 0x4a, 0x34, 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0xb1, 0x00, 0xa9, 0x00,
+ 0xa1, 0x00, 0x9a, 0x00, 0x94, 0x00, 0x8f, 0x01, 0x8b, 0x02, 0x87, 0x03,
+ 0x84, 0x04, 0x81, 0x05, 0x7f, 0x06, 0x7d, 0x06, 0x7b, 0x07, 0x79, 0x08,
+ 0x78, 0x09, 0x76, 0x0a, 0x76, 0x0b, 0x74, 0x0b, 0x73, 0x0c, 0x72, 0x0c,
+ 0x09, 0x44, 0x0d, 0x3c, 0x11, 0x36, 0x15, 0x33, 0x19, 0x30, 0x1c, 0x2d,
+ 0x20, 0x2b, 0x23, 0x2a, 0x25, 0x28, 0x28, 0x27, 0x2a, 0x27, 0x2d, 0x26,
+ 0x2f, 0x26, 0x31, 0x25, 0x33, 0x25, 0x34, 0x25, 0x36, 0x24, 0x38, 0x24,
+ 0x39, 0x24, 0x3a, 0x24, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x43, 0x00, 0x2a,
+ 0x00, 0x10, 0x09, 0x00, 0x1f, 0x00, 0x33, 0x00, 0x43, 0x00, 0x50, 0x00,
+ 0x5b, 0x00, 0x64, 0x00, 0x6b, 0x00, 0x72, 0x00, 0x77, 0x00, 0x7b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x95, 0x00,
+ 0x83, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x0c, 0x00,
+ 0x00, 0x03, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32,
+ 0x00, 0x37, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x3c, 0x43, 0x39, 0x46, 0x38, 0x46, 0x35, 0x4a, 0x35, 0x4a, 0x35,
+ 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x30,
+ 0x50, 0x2e, 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0xb2, 0x00, 0xaa, 0x00, 0xa2, 0x00, 0x9c, 0x00,
+ 0x96, 0x00, 0x91, 0x01, 0x8d, 0x02, 0x89, 0x02, 0x86, 0x03, 0x83, 0x04,
+ 0x81, 0x05, 0x7f, 0x06, 0x7d, 0x06, 0x7b, 0x07, 0x79, 0x07, 0x79, 0x09,
+ 0x77, 0x09, 0x76, 0x0a, 0x75, 0x0b, 0x74, 0x0b, 0x0a, 0x44, 0x0d, 0x3d,
+ 0x10, 0x38, 0x14, 0x34, 0x17, 0x31, 0x1b, 0x2e, 0x1e, 0x2d, 0x21, 0x2b,
+ 0x23, 0x2a, 0x26, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2d, 0x26, 0x2e, 0x26,
+ 0x30, 0x25, 0x32, 0x25, 0x34, 0x25, 0x35, 0x25, 0x36, 0x24, 0x38, 0x24,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x08,
+ 0x0c, 0x00, 0x1f, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x55, 0x00,
+ 0x5e, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x76, 0x00,
+ 0x5f, 0x00, 0x48, 0x00, 0x33, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x25, 0x00, 0x2c, 0x00, 0x31,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3c, 0x43, 0x39,
+ 0x46, 0x39, 0x46, 0x37, 0x49, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4b, 0x32,
+ 0x4e, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x2f,
+ 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0xb2, 0x00, 0xab, 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x98, 0x00, 0x93, 0x00,
+ 0x8f, 0x01, 0x8b, 0x02, 0x88, 0x02, 0x85, 0x03, 0x83, 0x04, 0x81, 0x05,
+ 0x7f, 0x06, 0x7d, 0x06, 0x7c, 0x07, 0x7a, 0x07, 0x79, 0x08, 0x78, 0x09,
+ 0x76, 0x09, 0x76, 0x0a, 0x0a, 0x44, 0x0c, 0x3e, 0x10, 0x39, 0x13, 0x35,
+ 0x16, 0x32, 0x19, 0x30, 0x1c, 0x2e, 0x1f, 0x2c, 0x21, 0x2b, 0x24, 0x2a,
+ 0x26, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x26, 0x2e, 0x26, 0x30, 0x25,
+ 0x31, 0x25, 0x33, 0x25, 0x34, 0x25, 0x36, 0x25, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59,
+ 0x00, 0x4e, 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x17, 0x00, 0x03, 0x0f, 0x00,
+ 0x1f, 0x00, 0x2e, 0x00, 0x3b, 0x00, 0x46, 0x00, 0x50, 0x00, 0x59, 0x00,
+ 0x60, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x6b, 0x00, 0x57, 0x00,
+ 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x11, 0x00, 0x04, 0x00, 0x00, 0x07,
+ 0x00, 0x10, 0x00, 0x19, 0x00, 0x20, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x39, 0x46, 0x39, 0x46, 0x38,
+ 0x47, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x2f, 0x51, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0xb2, 0x00, 0xac, 0x00,
+ 0xa5, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x91, 0x01, 0x8e, 0x01,
+ 0x8a, 0x02, 0x88, 0x02, 0x85, 0x03, 0x83, 0x04, 0x81, 0x05, 0x7f, 0x05,
+ 0x7d, 0x06, 0x7c, 0x07, 0x7a, 0x07, 0x79, 0x07, 0x78, 0x09, 0x77, 0x09,
+ 0x0a, 0x44, 0x0c, 0x3f, 0x0f, 0x3a, 0x12, 0x36, 0x15, 0x33, 0x18, 0x30,
+ 0x1b, 0x2e, 0x1d, 0x2d, 0x20, 0x2b, 0x22, 0x2a, 0x24, 0x2a, 0x26, 0x28,
+ 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x26, 0x2e, 0x26, 0x2f, 0x26, 0x31, 0x25,
+ 0x33, 0x25, 0x33, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x52, 0x00, 0x45,
+ 0x00, 0x34, 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x11, 0x00, 0x1f, 0x00,
+ 0x2d, 0x00, 0x38, 0x00, 0x43, 0x00, 0x4c, 0x00, 0x54, 0x00, 0x5b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00,
+ 0x92, 0x00, 0x84, 0x00, 0x74, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f, 0x00,
+ 0x2e, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0c,
+ 0x00, 0x14, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x3d, 0x42, 0x3a, 0x45, 0x39, 0x46, 0x39, 0x46, 0x36, 0x49, 0x35,
+ 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e,
+ 0x53, 0x2e, 0x53, 0x2e, 0xb3, 0x00, 0xac, 0x00, 0xa7, 0x00, 0xa1, 0x00,
+ 0x9b, 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8c, 0x02, 0x89, 0x02,
+ 0x87, 0x02, 0x85, 0x03, 0x82, 0x04, 0x81, 0x05, 0x7f, 0x05, 0x7d, 0x06,
+ 0x7c, 0x06, 0x7b, 0x07, 0x79, 0x07, 0x79, 0x08, 0x0a, 0x45, 0x0c, 0x3f,
+ 0x0f, 0x3a, 0x11, 0x37, 0x14, 0x34, 0x17, 0x32, 0x1a, 0x30, 0x1c, 0x2e,
+ 0x1e, 0x2d, 0x21, 0x2b, 0x22, 0x2a, 0x25, 0x2a, 0x26, 0x28, 0x28, 0x28,
+ 0x2a, 0x27, 0x2c, 0x27, 0x2d, 0x26, 0x2f, 0x26, 0x30, 0x25, 0x32, 0x25,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3b, 0x00, 0x2c,
+ 0x00, 0x1b, 0x00, 0x0b, 0x04, 0x00, 0x12, 0x00, 0x1f, 0x00, 0x2b, 0x00,
+ 0x36, 0x00, 0x40, 0x00, 0x49, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x94, 0x00, 0x89, 0x00,
+ 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2d, 0x00,
+ 0x1f, 0x00, 0x13, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3a,
+ 0x44, 0x39, 0x46, 0x39, 0x46, 0x37, 0x48, 0x35, 0x4a, 0x35, 0x4a, 0x35,
+ 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
+ 0xb3, 0x00, 0xad, 0x00, 0xa7, 0x00, 0xa3, 0x00, 0x9d, 0x00, 0x99, 0x00,
+ 0x95, 0x00, 0x91, 0x01, 0x8e, 0x01, 0x8b, 0x02, 0x88, 0x02, 0x86, 0x02,
+ 0x84, 0x03, 0x82, 0x04, 0x81, 0x05, 0x7f, 0x05, 0x7e, 0x06, 0x7c, 0x06,
+ 0x7b, 0x07, 0x7a, 0x07, 0x0a, 0x45, 0x0c, 0x40, 0x0e, 0x3b, 0x11, 0x38,
+ 0x13, 0x35, 0x16, 0x32, 0x18, 0x30, 0x1b, 0x2e, 0x1d, 0x2d, 0x1f, 0x2c,
+ 0x21, 0x2b, 0x23, 0x2a, 0x25, 0x29, 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27,
+ 0x2c, 0x27, 0x2d, 0x26, 0x2f, 0x26, 0x2f, 0x25, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c,
+ 0x00, 0x56, 0x00, 0x4d, 0x00, 0x41, 0x00, 0x33, 0x00, 0x24, 0x00, 0x15,
+ 0x00, 0x07, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x34, 0x00,
+ 0x3d, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x73, 0x00,
+ 0x64, 0x00, 0x55, 0x00, 0x46, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f, 0x00,
+ 0x14, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3b, 0x44, 0x39, 0x46, 0x39,
+ 0x46, 0x38, 0x47, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x34,
+ 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2f, 0x52, 0x2e, 0xb3, 0x00, 0xae, 0x00,
+ 0xa8, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x93, 0x00,
+ 0x8f, 0x01, 0x8d, 0x02, 0x8a, 0x02, 0x88, 0x02, 0x86, 0x03, 0x84, 0x03,
+ 0x82, 0x04, 0x81, 0x05, 0x7f, 0x05, 0x7e, 0x06, 0x7c, 0x06, 0x7c, 0x07,
+ 0x0a, 0x45, 0x0c, 0x40, 0x0e, 0x3c, 0x11, 0x38, 0x13, 0x36, 0x15, 0x33,
+ 0x18, 0x31, 0x1a, 0x30, 0x1c, 0x2e, 0x1e, 0x2d, 0x20, 0x2b, 0x22, 0x2b,
+ 0x23, 0x2a, 0x25, 0x29, 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x27,
+ 0x2d, 0x26, 0x2f, 0x26, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x57, 0x00, 0x4f,
+ 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x1e, 0x00, 0x10, 0x00, 0x03,
+ 0x08, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x33, 0x00, 0x3b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
+ 0x97, 0x00, 0x8f, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6b, 0x00, 0x5e, 0x00,
+ 0x50, 0x00, 0x43, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x15, 0x00,
+ 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x3d, 0x42, 0x3c, 0x43, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x36,
+ 0x49, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4c, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x2f, 0xb3, 0x00, 0xae, 0x00, 0xa9, 0x00, 0xa4, 0x00,
+ 0xa0, 0x00, 0x9b, 0x00, 0x98, 0x00, 0x94, 0x00, 0x91, 0x01, 0x8e, 0x01,
+ 0x8c, 0x02, 0x89, 0x02, 0x87, 0x02, 0x86, 0x03, 0x84, 0x03, 0x82, 0x04,
+ 0x80, 0x05, 0x7f, 0x05, 0x7e, 0x06, 0x7c, 0x06, 0x0a, 0x45, 0x0b, 0x40,
+ 0x0e, 0x3c, 0x10, 0x39, 0x12, 0x37, 0x14, 0x34, 0x17, 0x32, 0x19, 0x30,
+ 0x1b, 0x2e, 0x1d, 0x2d, 0x1f, 0x2d, 0x20, 0x2b, 0x22, 0x2b, 0x24, 0x2a,
+ 0x25, 0x29, 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x27, 0x2c, 0x26,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x52, 0x00, 0x49, 0x00, 0x3e,
+ 0x00, 0x32, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x0a, 0x00,
+ 0x15, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x91, 0x00,
+ 0x88, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00,
+ 0x40, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3c,
+ 0x43, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x37, 0x48, 0x35, 0x4a, 0x35,
+ 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0xb3, 0x00, 0xae, 0x00, 0xaa, 0x00, 0xa5, 0x00, 0xa1, 0x00, 0x9d, 0x00,
+ 0x99, 0x00, 0x96, 0x00, 0x93, 0x00, 0x90, 0x01, 0x8d, 0x01, 0x8b, 0x02,
+ 0x89, 0x02, 0x87, 0x02, 0x85, 0x03, 0x83, 0x03, 0x82, 0x04, 0x80, 0x05,
+ 0x7f, 0x05, 0x7e, 0x06, 0x0a, 0x45, 0x0b, 0x41, 0x0e, 0x3d, 0x10, 0x3a,
+ 0x11, 0x37, 0x14, 0x34, 0x16, 0x32, 0x18, 0x31, 0x1a, 0x30, 0x1c, 0x2e,
+ 0x1d, 0x2d, 0x20, 0x2c, 0x21, 0x2b, 0x22, 0x2a, 0x24, 0x2a, 0x25, 0x29,
+ 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x27, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d,
+ 0x00, 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42, 0x00, 0x37, 0x00, 0x2c,
+ 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x01, 0x00, 0x0c, 0x00, 0x16, 0x00,
+ 0x1f, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82, 0x00,
+ 0x77, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3d, 0x00,
+ 0x33, 0x00, 0x29, 0x00, 0x1f, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x39, 0x46, 0x39,
+ 0x46, 0x39, 0x46, 0x39, 0x46, 0x36, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35,
+ 0x4a, 0x35, 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0xb4, 0x00, 0xaf, 0x00,
+ 0xaa, 0x00, 0xa6, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x9a, 0x00, 0x97, 0x00,
+ 0x94, 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8c, 0x02, 0x8a, 0x02, 0x88, 0x02,
+ 0x86, 0x02, 0x85, 0x03, 0x83, 0x03, 0x82, 0x04, 0x80, 0x05, 0x7f, 0x05,
+ 0x0a, 0x45, 0x0b, 0x41, 0x0d, 0x3e, 0x10, 0x3a, 0x11, 0x38, 0x13, 0x35,
+ 0x16, 0x33, 0x17, 0x32, 0x19, 0x30, 0x1b, 0x2e, 0x1d, 0x2e, 0x1e, 0x2d,
+ 0x20, 0x2b, 0x22, 0x2b, 0x23, 0x2a, 0x25, 0x2a, 0x25, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x2a, 0x27, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55,
+ 0x00, 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x31, 0x00, 0x26, 0x00, 0x1b,
+ 0x00, 0x11, 0x00, 0x06, 0x03, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x1f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00,
+ 0x9a, 0x00, 0x95, 0x00, 0x8d, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00,
+ 0x66, 0x00, 0x5b, 0x00, 0x50, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x31, 0x00,
+ 0x28, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3a, 0x45, 0x39, 0x46, 0x39, 0x46, 0x39,
+ 0x46, 0x37, 0x49, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35,
+ 0x4a, 0x34, 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
+ 0x4f, 0x31, 0x4f, 0x31, 0xb4, 0x00, 0xaf, 0x00, 0xab, 0x00, 0xa7, 0x00,
+ 0xa3, 0x00, 0x9f, 0x00, 0x9b, 0x00, 0x98, 0x00, 0x95, 0x00, 0x92, 0x00,
+ 0x90, 0x01, 0x8d, 0x01, 0x8b, 0x02, 0x89, 0x02, 0x88, 0x02, 0x86, 0x02,
+ 0x85, 0x03, 0x82, 0x03, 0x82, 0x04, 0x80, 0x05, 0x0a, 0x46, 0x0b, 0x42,
+ 0x0d, 0x3e, 0x0f, 0x3b, 0x11, 0x38, 0x13, 0x36, 0x15, 0x34, 0x16, 0x32,
+ 0x18, 0x30, 0x1a, 0x30, 0x1c, 0x2e, 0x1d, 0x2d, 0x20, 0x2d, 0x20, 0x2b,
+ 0x22, 0x2b, 0x23, 0x2a, 0x25, 0x2a, 0x26, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
+ 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x32, 0x74, 0x38, 0x57, 0x3a, 0x4f, 0x3c, 0x4b, 0x3c, 0x49, 0x3d, 0x47,
+ 0x3d, 0x46, 0x3d, 0x45, 0x3d, 0x45, 0x3d, 0x44, 0x3d, 0x43, 0x3d, 0x43,
+ 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42,
+ 0x3d, 0x42, 0x3d, 0x42, 0x41, 0x09, 0x1b, 0x31, 0x27, 0x38, 0x2d, 0x3a,
+ 0x31, 0x3b, 0x33, 0x3c, 0x35, 0x3c, 0x36, 0x3d, 0x37, 0x3d, 0x38, 0x3d,
+ 0x38, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
+ 0x3b, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x73, 0x00, 0x38, 0x31,
+ 0x3a, 0x38, 0x3c, 0x3a, 0x3c, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, 0x3d,
+ 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
+ 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x3d, 0x28, 0x38, 0x30,
+ 0x38, 0x34, 0x39, 0x36, 0x39, 0x38, 0x3a, 0x39, 0x3a, 0x39, 0x3b, 0x3a,
+ 0x3b, 0x3b, 0x3c, 0x3b, 0x3c, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3e, 0x3c,
+ 0x3e, 0x3c, 0x3e, 0x3c, 0x3e, 0x3c, 0x3e, 0x3d, 0x3e, 0x3d, 0x3e, 0x3d,
+ 0x00, 0x7e, 0x05, 0x58, 0x0f, 0x4e, 0x17, 0x49, 0x1d, 0x47, 0x21, 0x45,
+ 0x24, 0x44, 0x27, 0x43, 0x29, 0x43, 0x2b, 0x43, 0x2d, 0x43, 0x2e, 0x42,
+ 0x2f, 0x42, 0x31, 0x42, 0x31, 0x42, 0x32, 0x42, 0x33, 0x42, 0x33, 0x42,
+ 0x34, 0x42, 0x34, 0x42, 0x2b, 0x4e, 0x31, 0x47, 0x34, 0x45, 0x36, 0x44,
+ 0x38, 0x43, 0x39, 0x42, 0x39, 0x42, 0x3a, 0x41, 0x3b, 0x41, 0x3b, 0x41,
+ 0x3c, 0x41, 0x3c, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41,
+ 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x4f, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x2f, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x16, 0x3a, 0x20, 0x39, 0x25, 0x39, 0x29,
+ 0x39, 0x2d, 0x39, 0x2f, 0x3a, 0x31, 0x3a, 0x32, 0x3b, 0x33, 0x3a, 0x34,
+ 0x3a, 0x35, 0x3a, 0x36, 0x3a, 0x36, 0x3b, 0x37, 0x3b, 0x37, 0x3c, 0x38,
+ 0x3c, 0x38, 0x3d, 0x38, 0x3e, 0x39, 0x3e, 0x39, 0x00, 0x93, 0x01, 0x70,
+ 0x06, 0x60, 0x0d, 0x56, 0x12, 0x52, 0x16, 0x4e, 0x1a, 0x4c, 0x1d, 0x4a,
+ 0x20, 0x48, 0x22, 0x47, 0x24, 0x46, 0x26, 0x45, 0x27, 0x44, 0x29, 0x44,
+ 0x2a, 0x44, 0x2b, 0x44, 0x2c, 0x43, 0x2d, 0x43, 0x2e, 0x43, 0x2f, 0x43,
+ 0x28, 0x56, 0x2e, 0x4f, 0x31, 0x4b, 0x33, 0x49, 0x35, 0x48, 0x36, 0x46,
+ 0x37, 0x45, 0x38, 0x45, 0x39, 0x44, 0x39, 0x44, 0x39, 0x43, 0x39, 0x43,
+ 0x39, 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b, 0x42, 0x3c, 0x42, 0x3c, 0x42,
+ 0x3d, 0x42, 0x3d, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x8f, 0x00, 0x73, 0x00, 0x38, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x45, 0x00, 0x22, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x43, 0x11, 0x3d, 0x18, 0x3b, 0x1e, 0x3a, 0x22, 0x39, 0x25, 0x39, 0x28,
+ 0x39, 0x2a, 0x39, 0x2c, 0x39, 0x2d, 0x3a, 0x2f, 0x3b, 0x30, 0x3b, 0x31,
+ 0x3b, 0x32, 0x3b, 0x33, 0x3a, 0x33, 0x3a, 0x34, 0x3a, 0x34, 0x3a, 0x35,
+ 0x3a, 0x35, 0x3b, 0x35, 0x00, 0x9d, 0x00, 0x7f, 0x03, 0x6d, 0x07, 0x62,
+ 0x0c, 0x5b, 0x10, 0x56, 0x13, 0x52, 0x16, 0x50, 0x19, 0x4d, 0x1c, 0x4c,
+ 0x1e, 0x4b, 0x1f, 0x4b, 0x22, 0x4a, 0x23, 0x49, 0x24, 0x48, 0x25, 0x47,
+ 0x27, 0x46, 0x28, 0x45, 0x29, 0x44, 0x29, 0x44, 0x27, 0x59, 0x2c, 0x53,
+ 0x2f, 0x4f, 0x31, 0x4d, 0x32, 0x4b, 0x34, 0x4a, 0x35, 0x48, 0x35, 0x47,
+ 0x36, 0x46, 0x37, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x45,
+ 0x39, 0x44, 0x39, 0x44, 0x39, 0x43, 0x39, 0x43, 0x39, 0x42, 0x3a, 0x42,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x84,
+ 0x00, 0x5b, 0x00, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x59, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x44, 0x0f, 0x3e, 0x14,
+ 0x3c, 0x19, 0x3a, 0x1d, 0x3a, 0x20, 0x39, 0x23, 0x3a, 0x25, 0x3a, 0x27,
+ 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2c, 0x3a, 0x2c, 0x3b, 0x2d, 0x3b, 0x2f,
+ 0x3b, 0x2f, 0x3b, 0x30, 0x3b, 0x31, 0x3b, 0x32, 0x3a, 0x32, 0x3a, 0x33,
+ 0x00, 0xa3, 0x00, 0x88, 0x01, 0x77, 0x04, 0x6b, 0x08, 0x63, 0x0b, 0x5d,
+ 0x0e, 0x59, 0x11, 0x57, 0x14, 0x54, 0x16, 0x51, 0x19, 0x4f, 0x1a, 0x4d,
+ 0x1c, 0x4c, 0x1e, 0x4c, 0x1f, 0x4b, 0x21, 0x4b, 0x22, 0x4a, 0x23, 0x49,
+ 0x24, 0x49, 0x25, 0x49, 0x27, 0x5a, 0x2a, 0x55, 0x2d, 0x52, 0x2f, 0x4f,
+ 0x31, 0x4e, 0x32, 0x4b, 0x33, 0x4a, 0x35, 0x4a, 0x35, 0x49, 0x35, 0x48,
+ 0x35, 0x46, 0x37, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46,
+ 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x45, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x8d, 0x00, 0x6f, 0x00, 0x48,
+ 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x55, 0x00,
+ 0x42, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x45, 0x0e, 0x40, 0x12, 0x3d, 0x16, 0x3b, 0x1a,
+ 0x3b, 0x1d, 0x3a, 0x20, 0x39, 0x22, 0x39, 0x23, 0x3a, 0x25, 0x3a, 0x26,
+ 0x3a, 0x28, 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2b, 0x3a, 0x2c, 0x3b, 0x2d,
+ 0x3c, 0x2e, 0x3b, 0x2e, 0x3b, 0x2f, 0x3b, 0x30, 0x00, 0xa7, 0x00, 0x90,
+ 0x00, 0x7e, 0x02, 0x73, 0x05, 0x6a, 0x08, 0x65, 0x0b, 0x5f, 0x0d, 0x5b,
+ 0x10, 0x58, 0x12, 0x56, 0x14, 0x55, 0x16, 0x52, 0x18, 0x50, 0x1a, 0x4e,
+ 0x1b, 0x4d, 0x1d, 0x4c, 0x1e, 0x4c, 0x1f, 0x4b, 0x20, 0x4b, 0x21, 0x4b,
+ 0x26, 0x5b, 0x2a, 0x57, 0x2c, 0x54, 0x2e, 0x51, 0x30, 0x4f, 0x31, 0x4e,
+ 0x31, 0x4c, 0x33, 0x4a, 0x34, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x49,
+ 0x35, 0x47, 0x36, 0x46, 0x37, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46,
+ 0x39, 0x46, 0x39, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9b, 0x00, 0x92, 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x38, 0x00,
+ 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x46, 0x0d, 0x41, 0x11, 0x3d, 0x14, 0x3d, 0x17, 0x3b, 0x1a, 0x3b, 0x1c,
+ 0x3b, 0x1e, 0x39, 0x21, 0x39, 0x22, 0x3a, 0x23, 0x3a, 0x25, 0x3a, 0x26,
+ 0x3a, 0x28, 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2a, 0x39, 0x2b, 0x3b, 0x2c,
+ 0x3c, 0x2d, 0x3c, 0x2e, 0x00, 0xa9, 0x00, 0x95, 0x00, 0x85, 0x01, 0x79,
+ 0x03, 0x70, 0x06, 0x69, 0x08, 0x65, 0x0b, 0x61, 0x0d, 0x5c, 0x0f, 0x59,
+ 0x11, 0x58, 0x13, 0x56, 0x14, 0x55, 0x16, 0x53, 0x18, 0x51, 0x19, 0x4f,
+ 0x1b, 0x4d, 0x1c, 0x4d, 0x1d, 0x4c, 0x1e, 0x4c, 0x26, 0x5c, 0x29, 0x58,
+ 0x2b, 0x55, 0x2d, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4d,
+ 0x32, 0x4b, 0x34, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x49,
+ 0x35, 0x48, 0x35, 0x47, 0x36, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x95,
+ 0x00, 0x84, 0x00, 0x6c, 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x46, 0x0c, 0x42, 0x0f,
+ 0x3f, 0x13, 0x3d, 0x15, 0x3c, 0x18, 0x3a, 0x1a, 0x3b, 0x1c, 0x3b, 0x1e,
+ 0x39, 0x20, 0x39, 0x21, 0x39, 0x22, 0x3b, 0x24, 0x3a, 0x25, 0x3a, 0x26,
+ 0x3a, 0x27, 0x39, 0x28, 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2a, 0x3a, 0x2b,
+ 0x00, 0xab, 0x00, 0x99, 0x00, 0x8b, 0x01, 0x7e, 0x02, 0x77, 0x04, 0x6f,
+ 0x06, 0x69, 0x08, 0x66, 0x0b, 0x62, 0x0d, 0x5e, 0x0e, 0x5b, 0x10, 0x59,
+ 0x12, 0x57, 0x13, 0x56, 0x15, 0x55, 0x16, 0x54, 0x18, 0x52, 0x19, 0x50,
+ 0x1a, 0x4e, 0x1b, 0x4d, 0x26, 0x5c, 0x28, 0x59, 0x2a, 0x57, 0x2c, 0x53,
+ 0x2e, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4e, 0x31, 0x4c,
+ 0x33, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
+ 0x35, 0x49, 0x35, 0x48, 0x36, 0x46, 0x37, 0x46, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76,
+ 0x00, 0x5e, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00,
+ 0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29, 0x00, 0x1a, 0x00, 0x0c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x46, 0x0c, 0x42, 0x0e, 0x40, 0x11, 0x3d, 0x13,
+ 0x3d, 0x16, 0x3b, 0x18, 0x3b, 0x1a, 0x3c, 0x1c, 0x3b, 0x1e, 0x3a, 0x1f,
+ 0x39, 0x21, 0x39, 0x21, 0x3a, 0x23, 0x3b, 0x24, 0x3a, 0x25, 0x3a, 0x26,
+ 0x3a, 0x27, 0x39, 0x27, 0x39, 0x28, 0x39, 0x2a, 0x00, 0xac, 0x00, 0x9c,
+ 0x00, 0x8f, 0x00, 0x83, 0x02, 0x7b, 0x03, 0x74, 0x05, 0x6d, 0x07, 0x69,
+ 0x09, 0x66, 0x0b, 0x63, 0x0c, 0x5f, 0x0e, 0x5c, 0x0f, 0x5a, 0x11, 0x58,
+ 0x12, 0x57, 0x14, 0x56, 0x15, 0x55, 0x16, 0x55, 0x18, 0x53, 0x18, 0x51,
+ 0x26, 0x5d, 0x27, 0x59, 0x2a, 0x57, 0x2b, 0x55, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2f, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4d, 0x32, 0x4b,
+ 0x34, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
+ 0x35, 0x4a, 0x35, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53,
+ 0x00, 0x3c, 0x00, 0x26, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x4b, 0x00,
+ 0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x47, 0x0b, 0x42, 0x0d, 0x41, 0x10, 0x3e, 0x13, 0x3d, 0x15, 0x3c, 0x17,
+ 0x3a, 0x19, 0x3b, 0x1a, 0x3c, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f, 0x39, 0x20,
+ 0x39, 0x21, 0x3a, 0x22, 0x3b, 0x23, 0x3b, 0x24, 0x3a, 0x25, 0x3a, 0x26,
+ 0x3a, 0x27, 0x39, 0x27, 0x00, 0xad, 0x00, 0x9f, 0x00, 0x92, 0x00, 0x88,
+ 0x01, 0x7e, 0x02, 0x78, 0x04, 0x72, 0x05, 0x6d, 0x07, 0x69, 0x09, 0x66,
+ 0x0a, 0x64, 0x0c, 0x61, 0x0d, 0x5d, 0x0f, 0x5a, 0x10, 0x59, 0x11, 0x58,
+ 0x13, 0x57, 0x14, 0x56, 0x15, 0x55, 0x16, 0x55, 0x26, 0x5d, 0x27, 0x5a,
+ 0x2a, 0x57, 0x2a, 0x56, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4e, 0x32, 0x4b, 0x33, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a,
+ 0x00, 0x91, 0x00, 0x83, 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36,
+ 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38, 0x00,
+ 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0b, 0x43, 0x0d,
+ 0x41, 0x0f, 0x3f, 0x12, 0x3d, 0x13, 0x3e, 0x15, 0x3c, 0x17, 0x3a, 0x19,
+ 0x3a, 0x1a, 0x3c, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f, 0x39, 0x1f, 0x39, 0x21,
+ 0x39, 0x21, 0x3b, 0x22, 0x3b, 0x24, 0x3a, 0x24, 0x3a, 0x24, 0x3a, 0x26,
+ 0x00, 0xae, 0x00, 0xa2, 0x00, 0x94, 0x00, 0x8b, 0x00, 0x82, 0x02, 0x7b,
+ 0x03, 0x76, 0x05, 0x71, 0x06, 0x6c, 0x07, 0x69, 0x09, 0x66, 0x0a, 0x64,
+ 0x0c, 0x62, 0x0d, 0x5f, 0x0e, 0x5b, 0x10, 0x5a, 0x10, 0x58, 0x12, 0x58,
+ 0x13, 0x56, 0x14, 0x56, 0x25, 0x5d, 0x27, 0x5b, 0x29, 0x57, 0x2a, 0x57,
+ 0x2b, 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4e, 0x31, 0x4d, 0x33, 0x4a, 0x34, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88,
+ 0x00, 0x79, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f,
+ 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00,
+ 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x28, 0x00,
+ 0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0b, 0x43, 0x0d, 0x42, 0x0f, 0x40, 0x11,
+ 0x3d, 0x13, 0x3e, 0x14, 0x3c, 0x16, 0x3b, 0x17, 0x3a, 0x19, 0x3b, 0x1a,
+ 0x3c, 0x1c, 0x3b, 0x1d, 0x3b, 0x1f, 0x39, 0x1f, 0x39, 0x20, 0x39, 0x21,
+ 0x3a, 0x21, 0x3b, 0x22, 0x3b, 0x24, 0x3a, 0x24, 0x00, 0xae, 0x00, 0xa3,
+ 0x00, 0x97, 0x00, 0x8e, 0x00, 0x86, 0x01, 0x7e, 0x02, 0x79, 0x03, 0x75,
+ 0x05, 0x70, 0x06, 0x6b, 0x07, 0x68, 0x09, 0x66, 0x0a, 0x64, 0x0b, 0x63,
+ 0x0c, 0x5f, 0x0e, 0x5d, 0x0f, 0x5a, 0x10, 0x59, 0x11, 0x58, 0x13, 0x58,
+ 0x25, 0x5d, 0x27, 0x5c, 0x29, 0x58, 0x2a, 0x57, 0x2a, 0x56, 0x2d, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x51, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4d, 0x32, 0x4b, 0x33, 0x4a, 0x35, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f,
+ 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00,
+ 0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e, 0x00, 0x24, 0x00, 0x1a, 0x00,
+ 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x47, 0x0b, 0x44, 0x0d, 0x42, 0x0e, 0x41, 0x10, 0x3e, 0x12, 0x3d, 0x13,
+ 0x3e, 0x15, 0x3c, 0x17, 0x3a, 0x18, 0x3b, 0x19, 0x3b, 0x1a, 0x3c, 0x1c,
+ 0x3b, 0x1c, 0x3b, 0x1e, 0x39, 0x1f, 0x39, 0x20, 0x39, 0x21, 0x39, 0x21,
+ 0x3b, 0x22, 0x3b, 0x23, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00, 0x90,
+ 0x00, 0x8a, 0x01, 0x81, 0x02, 0x7c, 0x02, 0x77, 0x04, 0x74, 0x05, 0x6f,
+ 0x06, 0x6a, 0x07, 0x68, 0x09, 0x66, 0x0a, 0x64, 0x0b, 0x63, 0x0c, 0x61,
+ 0x0e, 0x5e, 0x0e, 0x5b, 0x10, 0x5a, 0x10, 0x59, 0x25, 0x5d, 0x27, 0x5c,
+ 0x28, 0x59, 0x2a, 0x57, 0x2a, 0x57, 0x2b, 0x54, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4e, 0x31, 0x4c, 0x33, 0x4a, 0x34, 0x4a, 0x35, 0x4a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c,
+ 0x00, 0x97, 0x00, 0x8e, 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57,
+ 0x00, 0x47, 0x00, 0x37, 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x46, 0x00,
+ 0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x44, 0x0d,
+ 0x42, 0x0e, 0x41, 0x0f, 0x3f, 0x11, 0x3d, 0x13, 0x3e, 0x14, 0x3d, 0x15,
+ 0x3c, 0x17, 0x3a, 0x18, 0x3a, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c,
+ 0x3b, 0x1e, 0x39, 0x1f, 0x39, 0x1f, 0x39, 0x21, 0x39, 0x21, 0x3a, 0x21,
+ 0x00, 0xaf, 0x00, 0xa6, 0x00, 0x9c, 0x00, 0x92, 0x00, 0x8c, 0x00, 0x85,
+ 0x01, 0x7e, 0x02, 0x7a, 0x03, 0x76, 0x05, 0x73, 0x06, 0x6e, 0x07, 0x6a,
+ 0x08, 0x68, 0x09, 0x66, 0x0a, 0x65, 0x0b, 0x63, 0x0c, 0x62, 0x0d, 0x5f,
+ 0x0e, 0x5c, 0x0f, 0x5a, 0x25, 0x5d, 0x27, 0x5c, 0x27, 0x59, 0x2a, 0x57,
+ 0x2a, 0x57, 0x2a, 0x55, 0x2d, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4d, 0x32, 0x4b, 0x34, 0x4a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90,
+ 0x00, 0x86, 0x00, 0x7a, 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41,
+ 0x00, 0x33, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00,
+ 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49, 0x00, 0x41, 0x00, 0x39, 0x00,
+ 0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0d, 0x42, 0x0f,
+ 0x40, 0x11, 0x3d, 0x12, 0x3d, 0x13, 0x3e, 0x15, 0x3c, 0x16, 0x3b, 0x17,
+ 0x3a, 0x19, 0x3a, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1e,
+ 0x3a, 0x1f, 0x39, 0x1f, 0x39, 0x20, 0x39, 0x21, 0x00, 0xb0, 0x00, 0xa7,
+ 0x00, 0x9e, 0x00, 0x94, 0x00, 0x8e, 0x00, 0x88, 0x01, 0x81, 0x02, 0x7c,
+ 0x02, 0x78, 0x03, 0x75, 0x05, 0x72, 0x06, 0x6d, 0x07, 0x6a, 0x08, 0x68,
+ 0x09, 0x66, 0x0a, 0x65, 0x0b, 0x63, 0x0c, 0x62, 0x0d, 0x60, 0x0e, 0x5d,
+ 0x25, 0x5d, 0x27, 0x5c, 0x27, 0x5a, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
+ 0x2c, 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4e, 0x31, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e,
+ 0x00, 0x72, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f,
+ 0x00, 0x22, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x57, 0x00,
+ 0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x2c, 0x00,
+ 0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x10, 0x3e, 0x11,
+ 0x3d, 0x13, 0x3e, 0x14, 0x3d, 0x15, 0x3c, 0x17, 0x3a, 0x17, 0x3a, 0x19,
+ 0x3b, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f,
+ 0x39, 0x1f, 0x39, 0x1f, 0x00, 0xb0, 0x00, 0xa7, 0x00, 0xa0, 0x00, 0x96,
+ 0x00, 0x90, 0x00, 0x8a, 0x00, 0x84, 0x01, 0x7e, 0x02, 0x7a, 0x03, 0x77,
+ 0x04, 0x74, 0x05, 0x71, 0x06, 0x6c, 0x07, 0x6a, 0x08, 0x68, 0x09, 0x66,
+ 0x0a, 0x65, 0x0b, 0x63, 0x0c, 0x63, 0x0c, 0x61, 0x25, 0x5e, 0x27, 0x5c,
+ 0x27, 0x5c, 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2d, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x00, 0x27, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x8f, 0x00, 0x96, 0x00, 0x99,
+ 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e,
+ 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x8c, 0x00, 0x63,
+ 0x00, 0x7f, 0x00, 0x89, 0x00, 0x90, 0x00, 0x96, 0x00, 0x9b, 0x00, 0x9c,
+ 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e,
+ 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x14, 0x2c, 0x00, 0x57, 0x00, 0x82, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99,
+ 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e,
+ 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x11, 0x31, 0x00, 0x5f,
+ 0x00, 0x85, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c,
+ 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e,
+ 0x00, 0x9e, 0x00, 0x9e, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x45, 0x0b,
+ 0x42, 0x0d, 0x42, 0x0e, 0x41, 0x0f, 0x3f, 0x11, 0x3d, 0x12, 0x3d, 0x13,
+ 0x3e, 0x15, 0x3c, 0x15, 0x3c, 0x17, 0x3a, 0x17, 0x3a, 0x19, 0x3b, 0x19,
+ 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f, 0x39, 0x1f,
+ 0x00, 0xb1, 0x00, 0xa8, 0x00, 0xa1, 0x00, 0x98, 0x00, 0x91, 0x00, 0x8c,
+ 0x00, 0x87, 0x01, 0x80, 0x02, 0x7c, 0x02, 0x79, 0x03, 0x76, 0x05, 0x74,
+ 0x05, 0x70, 0x06, 0x6b, 0x07, 0x6a, 0x08, 0x68, 0x09, 0x66, 0x0a, 0x65,
+ 0x0b, 0x64, 0x0c, 0x63, 0x25, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x29, 0x58,
+ 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x51, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x00, 0x00, 0x00, 0x0d,
+ 0x00, 0x4f, 0x00, 0x73, 0x00, 0x84, 0x00, 0x8d, 0x00, 0x92, 0x00, 0x95,
+ 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c,
+ 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x63, 0x00, 0x4d, 0x00, 0x60, 0x00, 0x77,
+ 0x00, 0x83, 0x00, 0x8c, 0x00, 0x92, 0x00, 0x95, 0x00, 0x98, 0x00, 0x99,
+ 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x01, 0x04, 0x16,
+ 0x00, 0x57, 0x00, 0x78, 0x00, 0x87, 0x00, 0x8f, 0x00, 0x94, 0x00, 0x96,
+ 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c,
+ 0x00, 0x9d, 0x00, 0x9d, 0x23, 0x03, 0x00, 0x20, 0x00, 0x5f, 0x00, 0x7c,
+ 0x00, 0x8a, 0x00, 0x91, 0x00, 0x95, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a,
+ 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d,
+ 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x41, 0x0e,
+ 0x42, 0x0f, 0x40, 0x11, 0x3d, 0x11, 0x3d, 0x13, 0x3f, 0x13, 0x3d, 0x15,
+ 0x3c, 0x16, 0x3b, 0x17, 0x3a, 0x18, 0x3a, 0x19, 0x3b, 0x19, 0x3c, 0x1a,
+ 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1d, 0x3b, 0x1e, 0x00, 0xb1, 0x00, 0xa9,
+ 0x00, 0xa2, 0x00, 0x9a, 0x00, 0x93, 0x00, 0x8d, 0x00, 0x89, 0x01, 0x83,
+ 0x02, 0x7e, 0x02, 0x7a, 0x03, 0x78, 0x03, 0x75, 0x05, 0x73, 0x06, 0x6f,
+ 0x06, 0x6b, 0x07, 0x69, 0x08, 0x68, 0x09, 0x66, 0x0a, 0x66, 0x0b, 0x64,
+ 0x24, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x28, 0x59, 0x2a, 0x57, 0x2a, 0x57,
+ 0x2a, 0x57, 0x2b, 0x55, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x38,
+ 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e,
+ 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99,
+ 0x00, 0x7f, 0x00, 0x60, 0x00, 0x24, 0x00, 0x48, 0x00, 0x60, 0x00, 0x70,
+ 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x91, 0x00, 0x93,
+ 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x27, 0x00, 0x01, 0x12, 0x00, 0x43,
+ 0x00, 0x61, 0x00, 0x74, 0x00, 0x7f, 0x00, 0x87, 0x00, 0x8c, 0x00, 0x90,
+ 0x00, 0x93, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99,
+ 0x46, 0x00, 0x1f, 0x00, 0x00, 0x1f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x79,
+ 0x00, 0x83, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x92, 0x00, 0x94, 0x00, 0x96,
+ 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x41, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x41, 0x0e, 0x42, 0x0f, 0x40, 0x10,
+ 0x3e, 0x11, 0x3d, 0x13, 0x3d, 0x13, 0x3f, 0x15, 0x3c, 0x15, 0x3c, 0x17,
+ 0x3a, 0x17, 0x3a, 0x18, 0x3b, 0x19, 0x3b, 0x19, 0x3c, 0x1a, 0x3c, 0x1c,
+ 0x3b, 0x1c, 0x3b, 0x1c, 0x00, 0xb1, 0x00, 0xa9, 0x00, 0xa3, 0x00, 0x9c,
+ 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8b, 0x00, 0x86, 0x01, 0x80, 0x02, 0x7c,
+ 0x02, 0x79, 0x03, 0x77, 0x04, 0x75, 0x05, 0x72, 0x06, 0x6e, 0x07, 0x6b,
+ 0x07, 0x69, 0x09, 0x68, 0x09, 0x66, 0x0a, 0x66, 0x24, 0x5e, 0x27, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5a, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
+ 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2a, 0x00, 0x48,
+ 0x00, 0x5d, 0x00, 0x6c, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88,
+ 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x92, 0x00, 0x89, 0x00, 0x77,
+ 0x00, 0x48, 0x00, 0x0f, 0x00, 0x30, 0x00, 0x48, 0x00, 0x5d, 0x00, 0x6c,
+ 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e,
+ 0x00, 0x90, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x54, 0x00, 0x41, 0x00, 0x17, 0x00, 0x00, 0x10, 0x00, 0x36, 0x00, 0x51,
+ 0x00, 0x64, 0x00, 0x71, 0x00, 0x7a, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8a,
+ 0x00, 0x8d, 0x00, 0x90, 0x00, 0x92, 0x00, 0x93, 0x52, 0x00, 0x3c, 0x00,
+ 0x0d, 0x00, 0x00, 0x1f, 0x00, 0x42, 0x00, 0x5a, 0x00, 0x6a, 0x00, 0x76,
+ 0x00, 0x7e, 0x00, 0x84, 0x00, 0x89, 0x00, 0x8c, 0x00, 0x8f, 0x00, 0x91,
+ 0x00, 0x93, 0x00, 0x95, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
+ 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x46, 0x0b,
+ 0x44, 0x0d, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x0f, 0x40, 0x11, 0x3d, 0x11,
+ 0x3d, 0x13, 0x3f, 0x13, 0x3e, 0x15, 0x3c, 0x15, 0x3c, 0x17, 0x3a, 0x17,
+ 0x3a, 0x18, 0x3b, 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c,
+ 0x00, 0xb2, 0x00, 0xaa, 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x95, 0x00, 0x90,
+ 0x00, 0x8c, 0x00, 0x88, 0x01, 0x82, 0x02, 0x7e, 0x02, 0x7b, 0x02, 0x78,
+ 0x03, 0x76, 0x05, 0x74, 0x05, 0x71, 0x06, 0x6d, 0x07, 0x6b, 0x07, 0x69,
+ 0x09, 0x68, 0x09, 0x66, 0x24, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5b,
+ 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2b, 0x54, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x50,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f,
+ 0x00, 0x5e, 0x00, 0x69, 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83,
+ 0x00, 0x86, 0x00, 0x89, 0x00, 0x90, 0x00, 0x83, 0x00, 0x60, 0x00, 0x30,
+ 0x00, 0x02, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x5e, 0x00, 0x69,
+ 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x86, 0x00, 0x89,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x4d, 0x00,
+ 0x2f, 0x00, 0x0e, 0x00, 0x00, 0x10, 0x00, 0x2e, 0x00, 0x46, 0x00, 0x57,
+ 0x00, 0x64, 0x00, 0x6f, 0x00, 0x76, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x85,
+ 0x00, 0x89, 0x00, 0x8b, 0x58, 0x00, 0x4a, 0x00, 0x28, 0x00, 0x02, 0x00,
+ 0x00, 0x1f, 0x00, 0x3b, 0x00, 0x4f, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x74,
+ 0x00, 0x7b, 0x00, 0x80, 0x00, 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d,
+ 0x1b, 0x85, 0x05, 0x96, 0x01, 0x9e, 0x00, 0xa4, 0x00, 0xa7, 0x00, 0xa9,
+ 0x00, 0xab, 0x00, 0xac, 0x00, 0xad, 0x00, 0xae, 0x00, 0xaf, 0x00, 0xaf,
+ 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb2,
+ 0x00, 0xb2, 0x00, 0xb2, 0x1c, 0x6e, 0x03, 0x8a, 0x00, 0x97, 0x00, 0x9e,
+ 0x00, 0xa2, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xac,
+ 0x00, 0xad, 0x00, 0xad, 0x00, 0xad, 0x00, 0xae, 0x00, 0xaf, 0x00, 0xaf,
+ 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x0e, 0x92, 0x01, 0xa1, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xac, 0x00, 0xae,
+ 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb2,
+ 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3,
+ 0x00, 0xb4, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53,
+ 0x00, 0x5e, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e,
+ 0x00, 0x96, 0x00, 0x8c, 0x00, 0x70, 0x00, 0x48, 0x00, 0x22, 0x00, 0x01,
+ 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53, 0x00, 0x5e, 0x00, 0x68,
+ 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x53, 0x00, 0x3e, 0x00, 0x23, 0x00,
+ 0x0a, 0x02, 0x00, 0x10, 0x00, 0x29, 0x00, 0x3d, 0x00, 0x4e, 0x00, 0x5b,
+ 0x00, 0x65, 0x00, 0x6d, 0x00, 0x74, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82,
+ 0x5a, 0x00, 0x51, 0x00, 0x39, 0x00, 0x1a, 0x00, 0x00, 0x04, 0x00, 0x1f,
+ 0x00, 0x36, 0x00, 0x48, 0x00, 0x57, 0x00, 0x62, 0x00, 0x6b, 0x00, 0x73,
+ 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x85, 0x27, 0x60, 0x0f, 0x73,
+ 0x07, 0x81, 0x03, 0x8a, 0x01, 0x91, 0x00, 0x95, 0x00, 0x99, 0x00, 0x9d,
+ 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7,
+ 0x00, 0xa7, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa,
+ 0x29, 0x3a, 0x0f, 0x59, 0x06, 0x6c, 0x02, 0x79, 0x00, 0x84, 0x00, 0x8b,
+ 0x00, 0x90, 0x00, 0x94, 0x00, 0x98, 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9f,
+ 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa6,
+ 0x00, 0xa7, 0x00, 0xa7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x14, 0x79, 0x07, 0x88,
+ 0x03, 0x92, 0x01, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa5,
+ 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xab, 0x00, 0xac, 0x00, 0xac,
+ 0x00, 0xad, 0x00, 0xae, 0x00, 0xae, 0x00, 0xae, 0x00, 0xaf, 0x00, 0xaf,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55,
+ 0x00, 0x5f, 0x00, 0x66, 0x00, 0x6d, 0x00, 0x72, 0x00, 0x9b, 0x00, 0x92,
+ 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x18,
+ 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55, 0x00, 0x5f, 0x00, 0x66,
+ 0x00, 0x6d, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x56, 0x00, 0x47, 0x00, 0x31, 0x00, 0x1a, 0x00, 0x08, 0x04,
+ 0x00, 0x10, 0x00, 0x25, 0x00, 0x37, 0x00, 0x46, 0x00, 0x52, 0x00, 0x5d,
+ 0x00, 0x65, 0x00, 0x6c, 0x00, 0x72, 0x00, 0x77, 0x5c, 0x00, 0x55, 0x00,
+ 0x43, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x09, 0x00, 0x1f, 0x00, 0x33,
+ 0x00, 0x43, 0x00, 0x50, 0x00, 0x5b, 0x00, 0x64, 0x00, 0x6b, 0x00, 0x72,
+ 0x00, 0x77, 0x00, 0x7b, 0x2d, 0x54, 0x17, 0x63, 0x0d, 0x6f, 0x07, 0x78,
+ 0x04, 0x80, 0x02, 0x86, 0x01, 0x8b, 0x01, 0x8f, 0x00, 0x92, 0x00, 0x95,
+ 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1,
+ 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa4, 0x31, 0x27, 0x18, 0x40,
+ 0x0d, 0x52, 0x07, 0x61, 0x04, 0x6c, 0x02, 0x75, 0x01, 0x7c, 0x00, 0x82,
+ 0x00, 0x87, 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x91, 0x00, 0x94, 0x00, 0x97,
+ 0x00, 0x98, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x18, 0x6f, 0x0c, 0x7b, 0x06, 0x84, 0x03, 0x8c,
+ 0x02, 0x91, 0x01, 0x96, 0x00, 0x99, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa1,
+ 0x00, 0xa2, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0xa8,
+ 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xab, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x14, 0x00, 0x26, 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57,
+ 0x00, 0x5f, 0x00, 0x66, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x84, 0x00, 0x6c,
+ 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x26,
+ 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57, 0x00, 0x5f, 0x00, 0x66,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00,
+ 0x4d, 0x00, 0x3b, 0x00, 0x27, 0x00, 0x13, 0x00, 0x07, 0x06, 0x00, 0x10,
+ 0x00, 0x22, 0x00, 0x32, 0x00, 0x40, 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5e,
+ 0x00, 0x65, 0x00, 0x6b, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x36, 0x00,
+ 0x1f, 0x00, 0x08, 0x00, 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x30, 0x00, 0x3f,
+ 0x00, 0x4b, 0x00, 0x55, 0x00, 0x5e, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x71,
+ 0x30, 0x4e, 0x1d, 0x5a, 0x12, 0x64, 0x0c, 0x6d, 0x08, 0x75, 0x05, 0x7a,
+ 0x03, 0x7f, 0x02, 0x85, 0x02, 0x89, 0x01, 0x8b, 0x00, 0x8e, 0x00, 0x90,
+ 0x00, 0x92, 0x00, 0x94, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x9c,
+ 0x00, 0x9e, 0x00, 0x9f, 0x36, 0x1e, 0x1f, 0x32, 0x12, 0x43, 0x0b, 0x50,
+ 0x07, 0x5a, 0x05, 0x63, 0x02, 0x6b, 0x01, 0x72, 0x01, 0x78, 0x00, 0x7c,
+ 0x00, 0x81, 0x00, 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x90,
+ 0x00, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x1b, 0x6b, 0x0f, 0x74, 0x09, 0x7d, 0x05, 0x83, 0x03, 0x89, 0x02, 0x8d,
+ 0x01, 0x91, 0x00, 0x95, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9c, 0x00, 0x9e,
+ 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5,
+ 0x00, 0xa6, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
+ 0x00, 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58,
+ 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76, 0x00, 0x5e, 0x00, 0x45,
+ 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x22, 0x00, 0x30,
+ 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x51, 0x00, 0x42, 0x00,
+ 0x32, 0x00, 0x20, 0x00, 0x0e, 0x00, 0x06, 0x07, 0x00, 0x10, 0x00, 0x20,
+ 0x00, 0x2f, 0x00, 0x3b, 0x00, 0x46, 0x00, 0x50, 0x00, 0x58, 0x00, 0x5f,
+ 0x5d, 0x00, 0x59, 0x00, 0x4e, 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x17, 0x00,
+ 0x03, 0x00, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x2e, 0x00, 0x3b, 0x00, 0x46,
+ 0x00, 0x50, 0x00, 0x59, 0x00, 0x60, 0x00, 0x66, 0x33, 0x4b, 0x21, 0x54,
+ 0x16, 0x5d, 0x10, 0x65, 0x0b, 0x6c, 0x08, 0x72, 0x06, 0x77, 0x04, 0x7b,
+ 0x03, 0x7f, 0x02, 0x83, 0x02, 0x87, 0x01, 0x8a, 0x01, 0x8c, 0x00, 0x8e,
+ 0x00, 0x90, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x98,
+ 0x3a, 0x19, 0x24, 0x2a, 0x18, 0x38, 0x10, 0x44, 0x0b, 0x4e, 0x07, 0x57,
+ 0x05, 0x5f, 0x04, 0x65, 0x02, 0x6b, 0x01, 0x71, 0x01, 0x76, 0x00, 0x79,
+ 0x00, 0x7e, 0x00, 0x80, 0x00, 0x84, 0x00, 0x87, 0x00, 0x88, 0x00, 0x8b,
+ 0x00, 0x8d, 0x00, 0x8f, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x1d, 0x68, 0x12, 0x70,
+ 0x0c, 0x77, 0x08, 0x7d, 0x05, 0x82, 0x03, 0x87, 0x02, 0x8b, 0x02, 0x8e,
+ 0x01, 0x91, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9b,
+ 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
+ 0x00, 0x2c, 0x00, 0x37, 0x00, 0x41, 0x00, 0x4a, 0x00, 0x9d, 0x00, 0x99,
+ 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53, 0x00, 0x3c, 0x00, 0x26,
+ 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2c, 0x00, 0x37,
+ 0x00, 0x41, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5e, 0x00, 0x5b, 0x00, 0x53, 0x00, 0x48, 0x00, 0x3a, 0x00, 0x2a, 0x00,
+ 0x1a, 0x00, 0x0b, 0x00, 0x05, 0x08, 0x00, 0x10, 0x00, 0x1e, 0x00, 0x2c,
+ 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x5e, 0x00, 0x5b, 0x00,
+ 0x52, 0x00, 0x45, 0x00, 0x34, 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x11, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x43, 0x00, 0x4c,
+ 0x00, 0x54, 0x00, 0x5b, 0x34, 0x49, 0x25, 0x51, 0x1a, 0x58, 0x13, 0x60,
+ 0x0e, 0x65, 0x0b, 0x6b, 0x08, 0x71, 0x06, 0x75, 0x05, 0x78, 0x04, 0x7b,
+ 0x03, 0x7f, 0x02, 0x83, 0x02, 0x86, 0x01, 0x88, 0x01, 0x8a, 0x00, 0x8c,
+ 0x00, 0x8d, 0x00, 0x8f, 0x00, 0x90, 0x00, 0x92, 0x3b, 0x17, 0x28, 0x24,
+ 0x1c, 0x30, 0x14, 0x3b, 0x0f, 0x45, 0x0b, 0x4d, 0x07, 0x55, 0x05, 0x5b,
+ 0x04, 0x61, 0x03, 0x67, 0x02, 0x6b, 0x01, 0x6f, 0x01, 0x74, 0x00, 0x77,
+ 0x00, 0x7a, 0x00, 0x7e, 0x00, 0x80, 0x00, 0x83, 0x00, 0x86, 0x00, 0x87,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x1d, 0x67, 0x14, 0x6d, 0x0e, 0x73, 0x0a, 0x79,
+ 0x07, 0x7e, 0x05, 0x82, 0x03, 0x86, 0x02, 0x89, 0x02, 0x8c, 0x01, 0x8f,
+ 0x01, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a,
+ 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28,
+ 0x00, 0x33, 0x00, 0x3d, 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x91, 0x00, 0x83,
+ 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36, 0x00, 0x22, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x33, 0x00, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00,
+ 0x56, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x32, 0x00, 0x24, 0x00, 0x15, 0x00,
+ 0x0a, 0x02, 0x04, 0x09, 0x00, 0x10, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x34,
+ 0x00, 0x3e, 0x00, 0x46, 0x5e, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x49, 0x00,
+ 0x3b, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x0b, 0x00, 0x00, 0x04, 0x00, 0x12,
+ 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x00, 0x40, 0x00, 0x49, 0x00, 0x50,
+ 0x36, 0x47, 0x27, 0x4e, 0x1d, 0x54, 0x16, 0x5b, 0x11, 0x61, 0x0e, 0x65,
+ 0x0b, 0x6a, 0x08, 0x6f, 0x07, 0x73, 0x05, 0x76, 0x05, 0x79, 0x03, 0x7c,
+ 0x02, 0x7e, 0x02, 0x82, 0x02, 0x85, 0x01, 0x88, 0x01, 0x89, 0x01, 0x8b,
+ 0x00, 0x8c, 0x00, 0x8d, 0x3d, 0x14, 0x2c, 0x20, 0x20, 0x2a, 0x18, 0x34,
+ 0x12, 0x3e, 0x0e, 0x45, 0x0a, 0x4c, 0x07, 0x53, 0x06, 0x58, 0x05, 0x5e,
+ 0x04, 0x63, 0x02, 0x67, 0x02, 0x6c, 0x01, 0x6f, 0x01, 0x72, 0x00, 0x76,
+ 0x00, 0x78, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x80, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x1e, 0x66, 0x16, 0x6b, 0x10, 0x71, 0x0c, 0x76, 0x09, 0x7a, 0x07, 0x7e,
+ 0x05, 0x81, 0x03, 0x85, 0x03, 0x88, 0x02, 0x8b, 0x02, 0x8d, 0x01, 0x8f,
+ 0x01, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x96, 0x00, 0x98, 0x00, 0x99,
+ 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f,
+ 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88, 0x00, 0x79, 0x00, 0x68,
+ 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00,
+ 0x44, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x09, 0x03,
+ 0x04, 0x09, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x27, 0x00, 0x31, 0x00, 0x3a,
+ 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x41, 0x00, 0x33, 0x00,
+ 0x24, 0x00, 0x15, 0x00, 0x07, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x1f,
+ 0x00, 0x2a, 0x00, 0x34, 0x00, 0x3d, 0x00, 0x46, 0x37, 0x46, 0x29, 0x4c,
+ 0x20, 0x52, 0x19, 0x57, 0x14, 0x5d, 0x10, 0x62, 0x0d, 0x66, 0x0b, 0x69,
+ 0x09, 0x6e, 0x07, 0x73, 0x06, 0x75, 0x05, 0x77, 0x04, 0x7a, 0x03, 0x7c,
+ 0x02, 0x7e, 0x02, 0x82, 0x02, 0x84, 0x02, 0x87, 0x01, 0x88, 0x01, 0x89,
+ 0x3f, 0x13, 0x2f, 0x1c, 0x23, 0x27, 0x1b, 0x2f, 0x15, 0x38, 0x10, 0x3e,
+ 0x0d, 0x45, 0x0a, 0x4b, 0x08, 0x51, 0x07, 0x57, 0x05, 0x5c, 0x04, 0x60,
+ 0x03, 0x65, 0x02, 0x67, 0x02, 0x6c, 0x01, 0x6f, 0x01, 0x71, 0x00, 0x75,
+ 0x00, 0x77, 0x00, 0x79, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x1f, 0x65, 0x17, 0x6a,
+ 0x11, 0x6f, 0x0d, 0x73, 0x0a, 0x77, 0x08, 0x7b, 0x06, 0x7e, 0x05, 0x81,
+ 0x04, 0x84, 0x03, 0x87, 0x02, 0x89, 0x02, 0x8b, 0x01, 0x8e, 0x01, 0x8f,
+ 0x01, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x22, 0x00, 0x9e, 0x00, 0x9c,
+ 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f, 0x00, 0x5f, 0x00, 0x4e,
+ 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c,
+ 0x00, 0x18, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5e, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00,
+ 0x32, 0x00, 0x26, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x08, 0x04, 0x04, 0x0a,
+ 0x00, 0x10, 0x00, 0x1b, 0x00, 0x25, 0x00, 0x2f, 0x5e, 0x00, 0x5d, 0x00,
+ 0x57, 0x00, 0x4f, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x1e, 0x00,
+ 0x10, 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x2a,
+ 0x00, 0x33, 0x00, 0x3b, 0x38, 0x45, 0x2b, 0x4a, 0x22, 0x50, 0x1c, 0x55,
+ 0x16, 0x59, 0x12, 0x5f, 0x0f, 0x63, 0x0d, 0x66, 0x0b, 0x69, 0x09, 0x6e,
+ 0x07, 0x71, 0x06, 0x74, 0x05, 0x76, 0x05, 0x78, 0x03, 0x7a, 0x03, 0x7c,
+ 0x02, 0x7e, 0x02, 0x81, 0x02, 0x84, 0x02, 0x86, 0x40, 0x11, 0x31, 0x1b,
+ 0x26, 0x23, 0x1e, 0x2b, 0x18, 0x33, 0x13, 0x39, 0x0f, 0x40, 0x0c, 0x45,
+ 0x0a, 0x4b, 0x08, 0x51, 0x07, 0x56, 0x05, 0x59, 0x04, 0x5e, 0x04, 0x61,
+ 0x02, 0x65, 0x02, 0x68, 0x02, 0x6b, 0x01, 0x6e, 0x01, 0x71, 0x00, 0x73,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x20, 0x64, 0x18, 0x69, 0x13, 0x6d, 0x0f, 0x71,
+ 0x0c, 0x75, 0x09, 0x78, 0x07, 0x7b, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84,
+ 0x03, 0x86, 0x02, 0x88, 0x02, 0x8a, 0x02, 0x8c, 0x01, 0x8e, 0x01, 0x8f,
+ 0x01, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x16, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8e,
+ 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57, 0x00, 0x47, 0x00, 0x37,
+ 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x16,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00,
+ 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42, 0x00, 0x38, 0x00, 0x2d, 0x00,
+ 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00, 0x07, 0x05, 0x03, 0x0a, 0x00, 0x0f,
+ 0x00, 0x1a, 0x00, 0x24, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x52, 0x00,
+ 0x49, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c, 0x00,
+ 0x00, 0x00, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x31,
+ 0x38, 0x45, 0x2d, 0x49, 0x24, 0x4e, 0x1e, 0x53, 0x19, 0x56, 0x14, 0x5b,
+ 0x11, 0x60, 0x0e, 0x63, 0x0c, 0x66, 0x0a, 0x69, 0x09, 0x6c, 0x07, 0x70,
+ 0x06, 0x73, 0x06, 0x75, 0x05, 0x77, 0x04, 0x79, 0x03, 0x7a, 0x03, 0x7c,
+ 0x02, 0x7e, 0x02, 0x80, 0x40, 0x11, 0x32, 0x18, 0x28, 0x20, 0x20, 0x28,
+ 0x1a, 0x2f, 0x16, 0x35, 0x12, 0x3c, 0x0f, 0x41, 0x0c, 0x46, 0x0a, 0x4b,
+ 0x08, 0x50, 0x07, 0x54, 0x05, 0x58, 0x05, 0x5c, 0x04, 0x5f, 0x04, 0x62,
+ 0x02, 0x66, 0x02, 0x69, 0x01, 0x6b, 0x01, 0x6e, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x20, 0x64, 0x19, 0x68, 0x14, 0x6b, 0x10, 0x6f, 0x0d, 0x73, 0x0b, 0x76,
+ 0x09, 0x79, 0x07, 0x7c, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85,
+ 0x02, 0x88, 0x02, 0x89, 0x02, 0x8b, 0x02, 0x8d, 0x01, 0x8e, 0x01, 0x90,
+ 0x00, 0x91, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90, 0x00, 0x86, 0x00, 0x7a,
+ 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41, 0x00, 0x33, 0x00, 0x25,
+ 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00,
+ 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x32, 0x00, 0x28, 0x00, 0x1e, 0x00,
+ 0x14, 0x00, 0x0b, 0x00, 0x07, 0x06, 0x03, 0x0b, 0x00, 0x0f, 0x00, 0x19,
+ 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42, 0x00,
+ 0x37, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x01,
+ 0x00, 0x0c, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x28, 0x39, 0x44, 0x2e, 0x49,
+ 0x26, 0x4c, 0x1f, 0x52, 0x1a, 0x55, 0x16, 0x58, 0x13, 0x5d, 0x10, 0x61,
+ 0x0e, 0x64, 0x0c, 0x66, 0x0a, 0x68, 0x09, 0x6c, 0x07, 0x70, 0x07, 0x72,
+ 0x06, 0x74, 0x05, 0x76, 0x05, 0x78, 0x03, 0x79, 0x03, 0x7b, 0x02, 0x7c,
+ 0x41, 0x10, 0x34, 0x17, 0x2a, 0x1e, 0x23, 0x25, 0x1d, 0x2c, 0x18, 0x32,
+ 0x14, 0x37, 0x10, 0x3d, 0x0e, 0x42, 0x0c, 0x46, 0x0a, 0x4b, 0x08, 0x4f,
+ 0x07, 0x53, 0x05, 0x57, 0x05, 0x5a, 0x04, 0x5e, 0x04, 0x61, 0x03, 0x63,
+ 0x02, 0x66, 0x02, 0x69, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x20, 0x63, 0x1a, 0x67,
+ 0x15, 0x6a, 0x11, 0x6e, 0x0e, 0x71, 0x0c, 0x74, 0x0a, 0x77, 0x08, 0x7a,
+ 0x07, 0x7c, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85, 0x02, 0x87,
+ 0x02, 0x88, 0x02, 0x8a, 0x02, 0x8c, 0x01, 0x8d, 0x01, 0x8e, 0x01, 0x90,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d,
+ 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x66,
+ 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f, 0x00, 0x22, 0x00, 0x16,
+ 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x48, 0x00,
+ 0x40, 0x00, 0x37, 0x00, 0x2d, 0x00, 0x24, 0x00, 0x1a, 0x00, 0x11, 0x00,
+ 0x0a, 0x01, 0x06, 0x06, 0x03, 0x0b, 0x00, 0x0f, 0x5f, 0x00, 0x5d, 0x00,
+ 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x31, 0x00,
+ 0x26, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0d,
+ 0x00, 0x17, 0x00, 0x1f, 0x39, 0x43, 0x2f, 0x48, 0x27, 0x4b, 0x22, 0x4f,
+ 0x1c, 0x54, 0x18, 0x56, 0x14, 0x59, 0x12, 0x5e, 0x0f, 0x62, 0x0d, 0x64,
+ 0x0c, 0x66, 0x0a, 0x68, 0x09, 0x6b, 0x08, 0x6f, 0x07, 0x72, 0x06, 0x74,
+ 0x05, 0x75, 0x05, 0x77, 0x04, 0x78, 0x03, 0x7a, 0x42, 0x0f, 0x36, 0x16,
+ 0x2c, 0x1c, 0x25, 0x23, 0x1f, 0x29, 0x1a, 0x2e, 0x16, 0x34, 0x12, 0x39,
+ 0x0f, 0x3e, 0x0d, 0x42, 0x0c, 0x47, 0x0a, 0x4b, 0x08, 0x4f, 0x07, 0x52,
+ 0x05, 0x56, 0x05, 0x59, 0x04, 0x5c, 0x04, 0x5f, 0x04, 0x62, 0x02, 0x64,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x21, 0x63, 0x1b, 0x66, 0x16, 0x6a, 0x12, 0x6d,
+ 0x0f, 0x70, 0x0d, 0x73, 0x0b, 0x75, 0x09, 0x78, 0x07, 0x7a, 0x06, 0x7d,
+ 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85, 0x02, 0x86, 0x02, 0x88,
+ 0x02, 0x89, 0x02, 0x8b, 0x02, 0x8c, 0x01, 0x8d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3a, 0x43, 0x31, 0x48, 0x29, 0x4a, 0x23, 0x4d, 0x1e, 0x53, 0x1a, 0x55,
+ 0x16, 0x57, 0x13, 0x5b, 0x11, 0x60, 0x0f, 0x62, 0x0d, 0x64, 0x0b, 0x66,
+ 0x0a, 0x68, 0x09, 0x6a, 0x08, 0x6e, 0x07, 0x71, 0x06, 0x73, 0x06, 0x75,
+ 0x05, 0x76, 0x05, 0x78, 0x43, 0x0f, 0x37, 0x15, 0x2e, 0x1b, 0x27, 0x21,
+ 0x21, 0x26, 0x1c, 0x2c, 0x18, 0x31, 0x15, 0x36, 0x12, 0x3a, 0x0f, 0x3f,
+ 0x0c, 0x43, 0x0c, 0x47, 0x0a, 0x4b, 0x08, 0x4e, 0x07, 0x52, 0x06, 0x55,
+ 0x05, 0x58, 0x05, 0x5b, 0x04, 0x5d, 0x04, 0x60, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x21, 0x63, 0x1b, 0x66, 0x17, 0x69, 0x13, 0x6c, 0x10, 0x6e, 0x0e, 0x71,
+ 0x0c, 0x74, 0x0a, 0x76, 0x09, 0x79, 0x07, 0x7b, 0x06, 0x7d, 0x06, 0x7f,
+ 0x05, 0x81, 0x04, 0x82, 0x03, 0x84, 0x03, 0x86, 0x02, 0x87, 0x02, 0x89,
+ 0x02, 0x8a, 0x02, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x42, 0x31, 0x47,
+ 0x2a, 0x49, 0x24, 0x4c, 0x1f, 0x51, 0x1b, 0x54, 0x18, 0x56, 0x15, 0x58,
+ 0x12, 0x5c, 0x10, 0x61, 0x0e, 0x63, 0x0c, 0x64, 0x0b, 0x66, 0x0a, 0x68,
+ 0x09, 0x6a, 0x08, 0x6d, 0x07, 0x71, 0x06, 0x72, 0x06, 0x74, 0x05, 0x75,
+ 0x43, 0x0f, 0x38, 0x14, 0x2f, 0x19, 0x28, 0x1f, 0x22, 0x24, 0x1d, 0x29,
+ 0x19, 0x2e, 0x16, 0x33, 0x12, 0x37, 0x11, 0x3b, 0x0f, 0x40, 0x0c, 0x43,
+ 0x0b, 0x47, 0x0a, 0x4b, 0x09, 0x4e, 0x07, 0x51, 0x07, 0x55, 0x05, 0x56,
+ 0x05, 0x5a, 0x04, 0x5c, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x21, 0x63, 0x1c, 0x65,
+ 0x17, 0x68, 0x14, 0x6b, 0x11, 0x6e, 0x0e, 0x70, 0x0c, 0x73, 0x0b, 0x75,
+ 0x09, 0x77, 0x08, 0x79, 0x07, 0x7b, 0x06, 0x7d, 0x05, 0x7f, 0x05, 0x81,
+ 0x04, 0x82, 0x03, 0x84, 0x03, 0x86, 0x02, 0x87, 0x02, 0x88, 0x02, 0x89,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3a, 0x42, 0x32, 0x46, 0x2b, 0x49, 0x25, 0x4b,
+ 0x21, 0x4f, 0x1d, 0x53, 0x19, 0x55, 0x16, 0x57, 0x14, 0x59, 0x11, 0x5e,
+ 0x10, 0x61, 0x0e, 0x63, 0x0c, 0x65, 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x6a,
+ 0x08, 0x6c, 0x07, 0x70, 0x07, 0x72, 0x06, 0x73, 0x43, 0x0e, 0x39, 0x13,
+ 0x31, 0x18, 0x2a, 0x1d, 0x24, 0x22, 0x1f, 0x27, 0x1b, 0x2b, 0x18, 0x30,
+ 0x16, 0x35, 0x12, 0x39, 0x0f, 0x3c, 0x0f, 0x41, 0x0c, 0x44, 0x0b, 0x47,
+ 0x0a, 0x4a, 0x09, 0x4e, 0x07, 0x50, 0x07, 0x54, 0x05, 0x55, 0x05, 0x59,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x21, 0x63, 0x1c, 0x65, 0x18, 0x68, 0x15, 0x6a,
+ 0x12, 0x6c, 0x0f, 0x6f, 0x0d, 0x71, 0x0c, 0x73, 0x0b, 0x76, 0x09, 0x78,
+ 0x07, 0x79, 0x07, 0x7c, 0x06, 0x7d, 0x05, 0x7f, 0x05, 0x81, 0x04, 0x82,
+ 0x03, 0x84, 0x03, 0x85, 0x02, 0x86, 0x02, 0x88, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0x42, 0x33, 0x45, 0x2c, 0x49, 0x27, 0x4b, 0x22, 0x4d, 0x1e, 0x52,
+ 0x1b, 0x54, 0x18, 0x56, 0x15, 0x58, 0x13, 0x5b, 0x10, 0x5f, 0x0f, 0x61,
+ 0x0e, 0x63, 0x0c, 0x65, 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x69, 0x08, 0x6c,
+ 0x07, 0x6f, 0x07, 0x72, 0x44, 0x0e, 0x3a, 0x12, 0x32, 0x17, 0x2b, 0x1c,
+ 0x26, 0x21, 0x21, 0x26, 0x1d, 0x2a, 0x19, 0x2e, 0x16, 0x32, 0x14, 0x35,
+ 0x12, 0x3a, 0x0f, 0x3d, 0x0e, 0x41, 0x0c, 0x44, 0x0b, 0x47, 0x0a, 0x4a,
+ 0x09, 0x4e, 0x07, 0x4f, 0x07, 0x53, 0x05, 0x55, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x22, 0x62, 0x1d, 0x65, 0x19, 0x67, 0x15, 0x6a, 0x13, 0x6c, 0x10, 0x6e,
+ 0x0e, 0x71, 0x0c, 0x73, 0x0b, 0x74, 0x0a, 0x76, 0x09, 0x79, 0x07, 0x7a,
+ 0x07, 0x7c, 0x06, 0x7d, 0x05, 0x7f, 0x05, 0x81, 0x04, 0x82, 0x03, 0x83,
+ 0x03, 0x85, 0x02, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x42, 0x33, 0x44,
+ 0x2d, 0x48, 0x28, 0x4a, 0x23, 0x4c, 0x1f, 0x50, 0x1c, 0x53, 0x19, 0x55,
+ 0x16, 0x57, 0x14, 0x58, 0x12, 0x5c, 0x10, 0x60, 0x0e, 0x62, 0x0d, 0x63,
+ 0x0c, 0x65, 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x69, 0x09, 0x6b, 0x07, 0x6e,
+ 0x44, 0x0d, 0x3a, 0x12, 0x33, 0x16, 0x2c, 0x1b, 0x27, 0x1f, 0x21, 0x24,
+ 0x1e, 0x28, 0x1a, 0x2b, 0x18, 0x30, 0x16, 0x34, 0x12, 0x37, 0x11, 0x3b,
+ 0x0f, 0x3e, 0x0d, 0x41, 0x0c, 0x45, 0x0a, 0x47, 0x0a, 0x4a, 0x09, 0x4e,
+ 0x07, 0x4f, 0x07, 0x53, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x22, 0x62, 0x1d, 0x65,
+ 0x19, 0x66, 0x16, 0x69, 0x13, 0x6b, 0x10, 0x6d, 0x0f, 0x6f, 0x0d, 0x71,
+ 0x0c, 0x73, 0x0b, 0x76, 0x09, 0x77, 0x08, 0x79, 0x07, 0x7a, 0x06, 0x7c,
+ 0x06, 0x7e, 0x05, 0x7f, 0x05, 0x80, 0x04, 0x82, 0x03, 0x83, 0x03, 0x85,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3b, 0x42, 0x34, 0x44, 0x2e, 0x48, 0x29, 0x49,
+ 0x24, 0x4b, 0x20, 0x4f, 0x1d, 0x53, 0x1a, 0x55, 0x18, 0x56, 0x15, 0x58,
+ 0x13, 0x59, 0x11, 0x5d, 0x10, 0x61, 0x0e, 0x62, 0x0d, 0x63, 0x0c, 0x65,
+ 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x69, 0x09, 0x6b, 0x44, 0x0d, 0x3b, 0x12,
+ 0x34, 0x16, 0x2e, 0x19, 0x28, 0x1e, 0x23, 0x22, 0x20, 0x26, 0x1d, 0x2b,
+ 0x19, 0x2e, 0x16, 0x31, 0x14, 0x35, 0x12, 0x38, 0x0f, 0x3b, 0x0f, 0x3f,
+ 0x0c, 0x41, 0x0c, 0x45, 0x0a, 0x47, 0x0a, 0x4a, 0x09, 0x4e, 0x07, 0x4e,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x22, 0x62, 0x1d, 0x64, 0x1a, 0x66, 0x17, 0x68,
+ 0x14, 0x6a, 0x11, 0x6c, 0x10, 0x6e, 0x0e, 0x71, 0x0c, 0x73, 0x0b, 0x74,
+ 0x0a, 0x76, 0x09, 0x78, 0x07, 0x79, 0x07, 0x7b, 0x06, 0x7c, 0x06, 0x7e,
+ 0x05, 0x7f, 0x05, 0x80, 0x04, 0x82, 0x03, 0x82, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0x42, 0x34, 0x43, 0x2f, 0x48, 0x29, 0x49, 0x25, 0x4b, 0x21, 0x4d,
+ 0x1e, 0x51, 0x1b, 0x54, 0x18, 0x55, 0x16, 0x56, 0x14, 0x58, 0x13, 0x5b,
+ 0x10, 0x5e, 0x0f, 0x61, 0x0e, 0x63, 0x0c, 0x64, 0x0c, 0x66, 0x0b, 0x66,
+ 0x0a, 0x68, 0x09, 0x69, 0x44, 0x0c, 0x3c, 0x11, 0x35, 0x16, 0x2f, 0x19,
+ 0x2a, 0x1d, 0x25, 0x22, 0x21, 0x25, 0x1d, 0x29, 0x1a, 0x2b, 0x18, 0x30,
+ 0x16, 0x33, 0x12, 0x35, 0x12, 0x3a, 0x0f, 0x3c, 0x0f, 0x40, 0x0c, 0x41,
+ 0x0c, 0x45, 0x0a, 0x47, 0x0a, 0x4a, 0x09, 0x4e, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x22, 0x62, 0x1e, 0x64, 0x1a, 0x66, 0x17, 0x68, 0x15, 0x6a, 0x12, 0x6c,
+ 0x10, 0x6e, 0x0e, 0x70, 0x0d, 0x71, 0x0c, 0x73, 0x0b, 0x75, 0x09, 0x76,
+ 0x09, 0x78, 0x07, 0x79, 0x07, 0x7b, 0x06, 0x7c, 0x06, 0x7e, 0x05, 0x7f,
+ 0x05, 0x80, 0x04, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x42, 0x35, 0x43,
+ 0x2f, 0x47, 0x2b, 0x49, 0x26, 0x4b, 0x22, 0x4c, 0x1f, 0x4f, 0x1c, 0x53,
+ 0x1a, 0x55, 0x18, 0x56, 0x15, 0x58, 0x13, 0x59, 0x12, 0x5c, 0x10, 0x60,
+ 0x0f, 0x61, 0x0e, 0x63, 0x0c, 0x64, 0x0c, 0x66, 0x0b, 0x66, 0x0a, 0x68,
+ 0x44, 0x0c, 0x3c, 0x10, 0x35, 0x15, 0x30, 0x19, 0x2b, 0x1c, 0x26, 0x20,
+ 0x21, 0x23, 0x1e, 0x26, 0x1c, 0x2b, 0x19, 0x2e, 0x16, 0x30, 0x15, 0x35,
+ 0x12, 0x37, 0x11, 0x3b, 0x0f, 0x3d, 0x0f, 0x41, 0x0c, 0x42, 0x0c, 0x46,
+ 0x0a, 0x47, 0x0a, 0x4a, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
+ 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x22, 0x62, 0x1e, 0x64,
+ 0x1a, 0x66, 0x18, 0x68, 0x15, 0x6a, 0x13, 0x6b, 0x10, 0x6d, 0x0f, 0x6e,
+ 0x0e, 0x71, 0x0c, 0x72, 0x0b, 0x74, 0x0a, 0x76, 0x09, 0x77, 0x08, 0x79,
+ 0x07, 0x7a, 0x07, 0x7c, 0x06, 0x7c, 0x06, 0x7e, 0x05, 0x7f, 0x05, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x09, 0x43, 0x09, 0x44, 0x09, 0x45, 0x09,
+ 0x45, 0x09, 0x46, 0x09, 0x46, 0x09, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x00, 0x22, 0x1c, 0x0a, 0x29, 0x0a, 0x31, 0x09, 0x36, 0x09, 0x3a, 0x09,
+ 0x3b, 0x09, 0x3d, 0x09, 0x3f, 0x09, 0x40, 0x09, 0x40, 0x09, 0x41, 0x09,
+ 0x42, 0x09, 0x43, 0x09, 0x43, 0x0a, 0x43, 0x0a, 0x44, 0x0a, 0x44, 0x0a,
+ 0x44, 0x0a, 0x44, 0x0a, 0x23, 0x16, 0x32, 0x0a, 0x38, 0x0a, 0x3c, 0x0a,
+ 0x3f, 0x09, 0x40, 0x09, 0x41, 0x09, 0x42, 0x09, 0x43, 0x09, 0x44, 0x09,
+ 0x44, 0x0a, 0x44, 0x0a, 0x44, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x45, 0x0a,
+ 0x45, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x46, 0x0a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x16, 0x3e, 0x11, 0x3f, 0x0f, 0x40, 0x0d, 0x41, 0x0d, 0x41, 0x0c,
+ 0x42, 0x0c, 0x43, 0x0b, 0x43, 0x0b, 0x43, 0x0b, 0x43, 0x0b, 0x44, 0x0a,
+ 0x44, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x46, 0x0a, 0x46, 0x0a,
+ 0x46, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0x6e, 0x03, 0x3a,
+ 0x0f, 0x27, 0x18, 0x1e, 0x1f, 0x19, 0x24, 0x17, 0x28, 0x14, 0x2c, 0x13,
+ 0x2f, 0x11, 0x31, 0x11, 0x32, 0x10, 0x34, 0x0f, 0x36, 0x0f, 0x37, 0x0f,
+ 0x38, 0x0e, 0x39, 0x0e, 0x3a, 0x0d, 0x3a, 0x0d, 0x3b, 0x0c, 0x3c, 0x0c,
+ 0x23, 0x3c, 0x25, 0x22, 0x2b, 0x18, 0x30, 0x14, 0x33, 0x11, 0x36, 0x10,
+ 0x38, 0x0f, 0x39, 0x0e, 0x3b, 0x0e, 0x3c, 0x0d, 0x3d, 0x0d, 0x3e, 0x0c,
+ 0x3f, 0x0c, 0x3f, 0x0c, 0x40, 0x0c, 0x40, 0x0c, 0x40, 0x0b, 0x41, 0x0b,
+ 0x41, 0x0b, 0x42, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x1f, 0x3c, 0x18,
+ 0x3c, 0x14, 0x3d, 0x11, 0x3e, 0x11, 0x3f, 0x0f, 0x3f, 0x0e, 0x40, 0x0e,
+ 0x41, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0c, 0x42, 0x0c,
+ 0x42, 0x0b, 0x42, 0x0b, 0x43, 0x0b, 0x43, 0x0b, 0x44, 0x0b, 0x44, 0x0b,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x00, 0x8a, 0x00, 0x59, 0x06, 0x40, 0x0d, 0x32,
+ 0x12, 0x2a, 0x18, 0x24, 0x1c, 0x20, 0x20, 0x1c, 0x23, 0x1b, 0x26, 0x18,
+ 0x28, 0x17, 0x2a, 0x16, 0x2c, 0x15, 0x2e, 0x14, 0x2f, 0x13, 0x31, 0x12,
+ 0x32, 0x12, 0x33, 0x12, 0x34, 0x11, 0x35, 0x10, 0x23, 0x4a, 0x24, 0x31,
+ 0x27, 0x25, 0x2a, 0x1e, 0x2d, 0x1a, 0x2f, 0x17, 0x32, 0x15, 0x33, 0x13,
+ 0x35, 0x12, 0x36, 0x11, 0x38, 0x10, 0x39, 0x10, 0x3a, 0x0f, 0x3a, 0x0f,
+ 0x3b, 0x0e, 0x3c, 0x0e, 0x3c, 0x0e, 0x3d, 0x0e, 0x3e, 0x0d, 0x3e, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x25, 0x3c, 0x1d, 0x3c, 0x19, 0x3c, 0x16,
+ 0x3d, 0x14, 0x3d, 0x12, 0x3f, 0x11, 0x3f, 0x10, 0x3f, 0x0f, 0x3f, 0x0f,
+ 0x40, 0x0e, 0x41, 0x0e, 0x41, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d,
+ 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0c, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x00, 0x97, 0x00, 0x6c, 0x02, 0x52, 0x07, 0x43, 0x0b, 0x38, 0x10, 0x30,
+ 0x14, 0x2a, 0x18, 0x27, 0x1b, 0x23, 0x1e, 0x20, 0x20, 0x1e, 0x23, 0x1c,
+ 0x25, 0x1b, 0x27, 0x19, 0x28, 0x18, 0x2a, 0x17, 0x2b, 0x16, 0x2c, 0x16,
+ 0x2e, 0x16, 0x2f, 0x15, 0x23, 0x50, 0x23, 0x3b, 0x25, 0x2e, 0x27, 0x26,
+ 0x29, 0x21, 0x2c, 0x1d, 0x2e, 0x1a, 0x2f, 0x18, 0x31, 0x16, 0x33, 0x15,
+ 0x34, 0x14, 0x35, 0x13, 0x36, 0x12, 0x37, 0x11, 0x38, 0x11, 0x38, 0x11,
+ 0x39, 0x10, 0x3a, 0x10, 0x3a, 0x10, 0x3b, 0x0f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x29, 0x3c, 0x22, 0x3b, 0x1d, 0x3b, 0x19, 0x3c, 0x17, 0x3c, 0x15,
+ 0x3c, 0x13, 0x3d, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x10, 0x3e, 0x0f,
+ 0x3f, 0x0f, 0x40, 0x0e, 0x40, 0x0e, 0x41, 0x0e, 0x42, 0x0e, 0x42, 0x0d,
+ 0x42, 0x0d, 0x42, 0x0d, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0x9e, 0x00, 0x79,
+ 0x00, 0x61, 0x04, 0x50, 0x07, 0x44, 0x0b, 0x3b, 0x0f, 0x34, 0x12, 0x2f,
+ 0x15, 0x2b, 0x18, 0x28, 0x1a, 0x25, 0x1d, 0x23, 0x1f, 0x21, 0x21, 0x1f,
+ 0x22, 0x1d, 0x24, 0x1c, 0x26, 0x1b, 0x27, 0x19, 0x28, 0x19, 0x2a, 0x19,
+ 0x23, 0x54, 0x23, 0x42, 0x24, 0x35, 0x25, 0x2d, 0x27, 0x27, 0x29, 0x22,
+ 0x2b, 0x1f, 0x2d, 0x1c, 0x2e, 0x1a, 0x30, 0x19, 0x31, 0x17, 0x32, 0x16,
+ 0x33, 0x15, 0x34, 0x14, 0x35, 0x13, 0x36, 0x13, 0x37, 0x12, 0x37, 0x11,
+ 0x38, 0x11, 0x38, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x2c, 0x3c, 0x25,
+ 0x3b, 0x20, 0x3b, 0x1d, 0x3b, 0x1a, 0x3c, 0x17, 0x3c, 0x16, 0x3c, 0x14,
+ 0x3c, 0x13, 0x3e, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3f, 0x11, 0x3d, 0x10,
+ 0x3e, 0x0f, 0x3f, 0x0f, 0x40, 0x0f, 0x40, 0x0e, 0x40, 0x0e, 0x41, 0x0e,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xa2, 0x00, 0x84, 0x00, 0x6c, 0x02, 0x5a,
+ 0x05, 0x4e, 0x07, 0x45, 0x0b, 0x3e, 0x0e, 0x38, 0x10, 0x33, 0x13, 0x2f,
+ 0x16, 0x2c, 0x18, 0x29, 0x1a, 0x26, 0x1c, 0x24, 0x1d, 0x22, 0x1f, 0x21,
+ 0x21, 0x1f, 0x21, 0x1e, 0x23, 0x1d, 0x25, 0x1c, 0x23, 0x56, 0x23, 0x47,
+ 0x23, 0x3b, 0x24, 0x32, 0x26, 0x2c, 0x27, 0x27, 0x29, 0x24, 0x2a, 0x21,
+ 0x2c, 0x1e, 0x2d, 0x1c, 0x2e, 0x1b, 0x30, 0x19, 0x30, 0x18, 0x32, 0x17,
+ 0x32, 0x16, 0x33, 0x15, 0x34, 0x14, 0x34, 0x14, 0x35, 0x13, 0x36, 0x13,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x2e, 0x3c, 0x27, 0x3b, 0x23, 0x3b, 0x1f,
+ 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x18, 0x3c, 0x17, 0x3b, 0x15, 0x3c, 0x14,
+ 0x3c, 0x13, 0x3e, 0x13, 0x3f, 0x11, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x11,
+ 0x3d, 0x10, 0x3e, 0x0f, 0x3f, 0x0f, 0x40, 0x0f, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x00, 0xa6, 0x00, 0x8b, 0x00, 0x75, 0x01, 0x63, 0x02, 0x57, 0x05, 0x4d,
+ 0x07, 0x45, 0x0a, 0x3e, 0x0d, 0x39, 0x0f, 0x35, 0x12, 0x32, 0x14, 0x2e,
+ 0x16, 0x2c, 0x18, 0x29, 0x19, 0x27, 0x1b, 0x26, 0x1d, 0x24, 0x1e, 0x22,
+ 0x20, 0x22, 0x21, 0x20, 0x23, 0x58, 0x23, 0x4a, 0x23, 0x3f, 0x24, 0x36,
+ 0x25, 0x30, 0x26, 0x2b, 0x27, 0x27, 0x29, 0x24, 0x2a, 0x22, 0x2b, 0x20,
+ 0x2d, 0x1e, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x30, 0x18, 0x31, 0x18,
+ 0x32, 0x17, 0x32, 0x16, 0x33, 0x16, 0x34, 0x15, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x30, 0x3c, 0x2a, 0x3c, 0x25, 0x3a, 0x21, 0x3b, 0x1e, 0x3a, 0x1c,
+ 0x3b, 0x1a, 0x3c, 0x18, 0x3c, 0x17, 0x3c, 0x16, 0x3b, 0x15, 0x3c, 0x14,
+ 0x3d, 0x13, 0x3e, 0x13, 0x3f, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x11,
+ 0x3d, 0x10, 0x3e, 0x0f, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xa8, 0x00, 0x90,
+ 0x00, 0x7c, 0x00, 0x6b, 0x01, 0x5f, 0x04, 0x55, 0x05, 0x4c, 0x07, 0x45,
+ 0x0a, 0x40, 0x0c, 0x3c, 0x0f, 0x37, 0x10, 0x34, 0x12, 0x31, 0x15, 0x2e,
+ 0x16, 0x2b, 0x18, 0x2a, 0x19, 0x28, 0x1a, 0x26, 0x1d, 0x25, 0x1d, 0x23,
+ 0x23, 0x59, 0x23, 0x4d, 0x23, 0x43, 0x24, 0x3b, 0x24, 0x34, 0x25, 0x2f,
+ 0x26, 0x2b, 0x27, 0x28, 0x28, 0x25, 0x2a, 0x23, 0x2b, 0x21, 0x2c, 0x1f,
+ 0x2d, 0x1d, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x30, 0x19, 0x31, 0x18,
+ 0x32, 0x17, 0x32, 0x16, 0x17, 0x00, 0x2f, 0x00, 0x4c, 0x00, 0x56, 0x00,
+ 0x59, 0x00, 0x5b, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00,
+ 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5f, 0x00,
+ 0x14, 0x2c, 0x29, 0x01, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x5b, 0x00,
+ 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00,
+ 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x62, 0x00,
+ 0x62, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00,
+ 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5f, 0x00,
+ 0x11, 0x31, 0x23, 0x03, 0x46, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5a, 0x00,
+ 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00,
+ 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x3e, 0x32, 0x3d, 0x2c,
+ 0x3c, 0x26, 0x3b, 0x23, 0x3b, 0x20, 0x3b, 0x1e, 0x3a, 0x1c, 0x3b, 0x1a,
+ 0x3c, 0x18, 0x3c, 0x17, 0x3c, 0x17, 0x3a, 0x15, 0x3c, 0x15, 0x3c, 0x14,
+ 0x3d, 0x13, 0x3e, 0x13, 0x3f, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x11,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xaa, 0x00, 0x94, 0x00, 0x82, 0x00, 0x72,
+ 0x01, 0x65, 0x02, 0x5b, 0x04, 0x53, 0x06, 0x4b, 0x08, 0x45, 0x0a, 0x41,
+ 0x0c, 0x3d, 0x0e, 0x39, 0x0f, 0x36, 0x12, 0x33, 0x12, 0x30, 0x16, 0x2e,
+ 0x16, 0x2b, 0x18, 0x2b, 0x19, 0x29, 0x1a, 0x26, 0x23, 0x5a, 0x23, 0x4f,
+ 0x23, 0x46, 0x23, 0x3e, 0x24, 0x37, 0x25, 0x32, 0x25, 0x2e, 0x26, 0x2b,
+ 0x27, 0x28, 0x28, 0x25, 0x2a, 0x23, 0x2b, 0x21, 0x2b, 0x20, 0x2d, 0x1e,
+ 0x2d, 0x1d, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x30, 0x19, 0x30, 0x18,
+ 0x00, 0x00, 0x07, 0x00, 0x2f, 0x00, 0x45, 0x00, 0x4f, 0x00, 0x55, 0x00,
+ 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00,
+ 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x00, 0x57, 0x04, 0x16,
+ 0x27, 0x00, 0x41, 0x00, 0x4d, 0x00, 0x53, 0x00, 0x56, 0x00, 0x59, 0x00,
+ 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00,
+ 0x5d, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4c, 0x00, 0x3b, 0x00, 0x48, 0x00, 0x55, 0x00, 0x58, 0x00, 0x57, 0x00,
+ 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00,
+ 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x00, 0x5f, 0x00, 0x20,
+ 0x1f, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x51, 0x00, 0x55, 0x00, 0x58, 0x00,
+ 0x59, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00,
+ 0x5d, 0x00, 0x5d, 0x00, 0x3e, 0x33, 0x3d, 0x2d, 0x3c, 0x28, 0x3b, 0x25,
+ 0x3a, 0x22, 0x3b, 0x1f, 0x3b, 0x1e, 0x3a, 0x1c, 0x3b, 0x1a, 0x3c, 0x19,
+ 0x3c, 0x17, 0x3c, 0x17, 0x3b, 0x16, 0x3b, 0x15, 0x3c, 0x15, 0x3c, 0x13,
+ 0x3d, 0x13, 0x3f, 0x13, 0x3f, 0x12, 0x3f, 0x11, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x00, 0xaa, 0x00, 0x98, 0x00, 0x87, 0x00, 0x78, 0x00, 0x6b, 0x01, 0x61,
+ 0x03, 0x58, 0x05, 0x51, 0x07, 0x4b, 0x08, 0x46, 0x0a, 0x42, 0x0c, 0x3e,
+ 0x0d, 0x3a, 0x0f, 0x37, 0x11, 0x35, 0x12, 0x32, 0x14, 0x30, 0x16, 0x2e,
+ 0x16, 0x2b, 0x18, 0x2b, 0x23, 0x5a, 0x23, 0x51, 0x23, 0x48, 0x23, 0x41,
+ 0x24, 0x3a, 0x24, 0x35, 0x25, 0x31, 0x26, 0x2e, 0x27, 0x2a, 0x27, 0x28,
+ 0x28, 0x26, 0x2a, 0x24, 0x2a, 0x22, 0x2b, 0x21, 0x2c, 0x1f, 0x2d, 0x1e,
+ 0x2d, 0x1d, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x22, 0x00, 0x36, 0x00, 0x42, 0x00, 0x4a, 0x00, 0x4f, 0x00,
+ 0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
+ 0x5b, 0x00, 0x5b, 0x00, 0x00, 0x82, 0x00, 0x57, 0x01, 0x12, 0x17, 0x00,
+ 0x2f, 0x00, 0x3e, 0x00, 0x47, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x53, 0x00,
+ 0x56, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x48, 0x00,
+ 0x1b, 0x00, 0x34, 0x00, 0x40, 0x00, 0x44, 0x00, 0x4a, 0x00, 0x4f, 0x00,
+ 0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
+ 0x5b, 0x00, 0x5b, 0x00, 0x00, 0x85, 0x00, 0x5f, 0x00, 0x1f, 0x0d, 0x00,
+ 0x28, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x52, 0x00,
+ 0x54, 0x00, 0x56, 0x00, 0x57, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5a, 0x00,
+ 0x3e, 0x34, 0x3d, 0x2f, 0x3b, 0x2a, 0x3c, 0x26, 0x3a, 0x23, 0x3b, 0x21,
+ 0x3b, 0x1f, 0x3b, 0x1d, 0x3a, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x17,
+ 0x3c, 0x17, 0x3b, 0x17, 0x3a, 0x15, 0x3c, 0x15, 0x3c, 0x15, 0x3c, 0x13,
+ 0x3e, 0x13, 0x3f, 0x13, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xac, 0x00, 0x9b,
+ 0x00, 0x8b, 0x00, 0x7c, 0x00, 0x71, 0x01, 0x67, 0x02, 0x5e, 0x04, 0x57,
+ 0x05, 0x51, 0x07, 0x4b, 0x08, 0x46, 0x0a, 0x42, 0x0c, 0x3f, 0x0c, 0x3b,
+ 0x0f, 0x39, 0x0f, 0x35, 0x12, 0x34, 0x12, 0x31, 0x14, 0x30, 0x16, 0x2e,
+ 0x23, 0x5b, 0x23, 0x52, 0x23, 0x4a, 0x23, 0x43, 0x23, 0x3d, 0x24, 0x38,
+ 0x25, 0x34, 0x25, 0x30, 0x26, 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x26,
+ 0x2a, 0x24, 0x2a, 0x22, 0x2b, 0x21, 0x2b, 0x20, 0x2d, 0x1f, 0x2d, 0x1d,
+ 0x2e, 0x1d, 0x2e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x19, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40, 0x00, 0x47, 0x00, 0x4b, 0x00,
+ 0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
+ 0x00, 0x91, 0x00, 0x78, 0x00, 0x43, 0x00, 0x10, 0x0e, 0x00, 0x23, 0x00,
+ 0x31, 0x00, 0x3b, 0x00, 0x42, 0x00, 0x48, 0x00, 0x4c, 0x00, 0x4f, 0x00,
+ 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x55, 0x00, 0x34, 0x00, 0x0b, 0x00,
+ 0x1f, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40, 0x00, 0x47, 0x00, 0x4b, 0x00,
+ 0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
+ 0x00, 0x92, 0x00, 0x7c, 0x00, 0x4d, 0x00, 0x1f, 0x02, 0x00, 0x1a, 0x00,
+ 0x2a, 0x00, 0x36, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4d, 0x00,
+ 0x4f, 0x00, 0x52, 0x00, 0x53, 0x00, 0x55, 0x00, 0x3e, 0x35, 0x3e, 0x30,
+ 0x3b, 0x2c, 0x3c, 0x28, 0x3b, 0x25, 0x3a, 0x22, 0x3b, 0x20, 0x3b, 0x1f,
+ 0x3a, 0x1d, 0x3a, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x18, 0x3c, 0x17,
+ 0x3c, 0x17, 0x3a, 0x16, 0x3b, 0x15, 0x3c, 0x15, 0x3c, 0x14, 0x3c, 0x13,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xad, 0x00, 0x9d, 0x00, 0x8e, 0x00, 0x81,
+ 0x00, 0x76, 0x00, 0x6b, 0x01, 0x63, 0x02, 0x5c, 0x04, 0x56, 0x05, 0x50,
+ 0x07, 0x4b, 0x08, 0x47, 0x0a, 0x43, 0x0c, 0x40, 0x0c, 0x3c, 0x0f, 0x3a,
+ 0x0f, 0x37, 0x11, 0x35, 0x12, 0x33, 0x12, 0x30, 0x23, 0x5b, 0x23, 0x53,
+ 0x23, 0x4c, 0x23, 0x45, 0x23, 0x40, 0x24, 0x3b, 0x24, 0x36, 0x25, 0x33,
+ 0x25, 0x30, 0x26, 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x26, 0x2a, 0x25,
+ 0x2a, 0x23, 0x2b, 0x22, 0x2b, 0x20, 0x2c, 0x20, 0x2d, 0x1e, 0x2d, 0x1d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00,
+ 0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f, 0x00, 0x44, 0x00, 0x48, 0x00,
+ 0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52, 0x00, 0x00, 0x96, 0x00, 0x87,
+ 0x00, 0x61, 0x00, 0x36, 0x00, 0x10, 0x0a, 0x02, 0x1a, 0x00, 0x27, 0x00,
+ 0x32, 0x00, 0x3a, 0x00, 0x40, 0x00, 0x44, 0x00, 0x48, 0x00, 0x4b, 0x00,
+ 0x4e, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x62, 0x00, 0x58, 0x00, 0x40, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x14, 0x00,
+ 0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f, 0x00, 0x44, 0x00, 0x48, 0x00,
+ 0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52, 0x00, 0x00, 0x97, 0x00, 0x8a,
+ 0x00, 0x68, 0x00, 0x42, 0x00, 0x1f, 0x00, 0x04, 0x10, 0x00, 0x1f, 0x00,
+ 0x2b, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x41, 0x00, 0x45, 0x00, 0x49, 0x00,
+ 0x4b, 0x00, 0x4e, 0x00, 0x3e, 0x36, 0x3e, 0x31, 0x3b, 0x2c, 0x3c, 0x29,
+ 0x3c, 0x26, 0x3a, 0x24, 0x3a, 0x21, 0x3b, 0x20, 0x3b, 0x1f, 0x39, 0x1d,
+ 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x18, 0x3c, 0x17, 0x3c, 0x17,
+ 0x3a, 0x17, 0x3a, 0x15, 0x3c, 0x15, 0x3c, 0x15, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x00, 0xad, 0x00, 0x9f, 0x00, 0x91, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6f,
+ 0x01, 0x67, 0x02, 0x60, 0x03, 0x59, 0x04, 0x54, 0x05, 0x4f, 0x07, 0x4b,
+ 0x08, 0x47, 0x0a, 0x43, 0x0b, 0x41, 0x0c, 0x3d, 0x0e, 0x3b, 0x0f, 0x38,
+ 0x0f, 0x35, 0x12, 0x35, 0x23, 0x5b, 0x23, 0x54, 0x23, 0x4e, 0x23, 0x47,
+ 0x23, 0x42, 0x24, 0x3c, 0x24, 0x38, 0x25, 0x35, 0x25, 0x32, 0x26, 0x2f,
+ 0x26, 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x26, 0x29, 0x25, 0x2a, 0x23,
+ 0x2b, 0x22, 0x2b, 0x21, 0x2b, 0x20, 0x2d, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1e, 0x00,
+ 0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x46, 0x00,
+ 0x49, 0x00, 0x4c, 0x00, 0x00, 0x99, 0x00, 0x8f, 0x00, 0x74, 0x00, 0x51,
+ 0x00, 0x2e, 0x00, 0x10, 0x08, 0x04, 0x13, 0x00, 0x20, 0x00, 0x2a, 0x00,
+ 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x48, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x57, 0x00,
+ 0x44, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1e, 0x00,
+ 0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x46, 0x00,
+ 0x49, 0x00, 0x4c, 0x00, 0x00, 0x9a, 0x00, 0x91, 0x00, 0x79, 0x00, 0x5a,
+ 0x00, 0x3b, 0x00, 0x1f, 0x00, 0x09, 0x08, 0x00, 0x17, 0x00, 0x22, 0x00,
+ 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00,
+ 0x3e, 0x36, 0x3e, 0x31, 0x3b, 0x2d, 0x3b, 0x2a, 0x3c, 0x27, 0x3a, 0x25,
+ 0x3a, 0x23, 0x3b, 0x21, 0x3b, 0x1f, 0x3b, 0x1f, 0x39, 0x1c, 0x3b, 0x1c,
+ 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x17, 0x3c, 0x17, 0x3b, 0x17,
+ 0x3a, 0x16, 0x3b, 0x15, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xad, 0x00, 0xa0,
+ 0x00, 0x94, 0x00, 0x88, 0x00, 0x7e, 0x00, 0x74, 0x00, 0x6c, 0x01, 0x65,
+ 0x02, 0x5e, 0x04, 0x58, 0x05, 0x53, 0x05, 0x4f, 0x07, 0x4b, 0x08, 0x47,
+ 0x0a, 0x44, 0x0b, 0x41, 0x0c, 0x3e, 0x0d, 0x3b, 0x0f, 0x3a, 0x0f, 0x37,
+ 0x23, 0x5c, 0x23, 0x55, 0x23, 0x4f, 0x23, 0x49, 0x23, 0x44, 0x23, 0x3f,
+ 0x24, 0x3b, 0x24, 0x37, 0x25, 0x34, 0x25, 0x31, 0x26, 0x2e, 0x26, 0x2c,
+ 0x27, 0x2a, 0x28, 0x28, 0x28, 0x27, 0x29, 0x25, 0x2a, 0x24, 0x2a, 0x22,
+ 0x2b, 0x22, 0x2b, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00,
+ 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x41, 0x00, 0x44, 0x00,
+ 0x00, 0x9b, 0x00, 0x94, 0x00, 0x7f, 0x00, 0x64, 0x00, 0x46, 0x00, 0x29,
+ 0x00, 0x10, 0x07, 0x06, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00, 0x2c, 0x00,
+ 0x32, 0x00, 0x38, 0x00, 0x3c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x38, 0x00,
+ 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00,
+ 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x41, 0x00, 0x44, 0x00,
+ 0x00, 0x9b, 0x00, 0x95, 0x00, 0x83, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x36,
+ 0x00, 0x1f, 0x00, 0x0c, 0x03, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x24, 0x00,
+ 0x2c, 0x00, 0x32, 0x00, 0x37, 0x00, 0x3c, 0x00, 0x3e, 0x37, 0x3e, 0x32,
+ 0x3c, 0x2f, 0x3b, 0x2b, 0x3c, 0x28, 0x3b, 0x26, 0x3a, 0x24, 0x3a, 0x22,
+ 0x3b, 0x21, 0x3b, 0x1f, 0x3a, 0x1e, 0x39, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a,
+ 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x17, 0x3c, 0x17, 0x3b, 0x17, 0x3a, 0x17,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xae, 0x00, 0xa2, 0x00, 0x97, 0x00, 0x8b,
+ 0x00, 0x80, 0x00, 0x77, 0x00, 0x6f, 0x01, 0x67, 0x02, 0x61, 0x02, 0x5c,
+ 0x04, 0x57, 0x05, 0x52, 0x05, 0x4e, 0x07, 0x4b, 0x09, 0x47, 0x0a, 0x44,
+ 0x0b, 0x41, 0x0c, 0x3f, 0x0c, 0x3c, 0x0f, 0x3b, 0x23, 0x5c, 0x23, 0x56,
+ 0x23, 0x50, 0x23, 0x4a, 0x23, 0x45, 0x23, 0x40, 0x24, 0x3c, 0x24, 0x39,
+ 0x25, 0x35, 0x25, 0x33, 0x25, 0x30, 0x26, 0x2e, 0x26, 0x2c, 0x27, 0x2a,
+ 0x28, 0x28, 0x28, 0x27, 0x29, 0x25, 0x2a, 0x24, 0x2a, 0x23, 0x2b, 0x22,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x20, 0x00, 0x28, 0x00,
+ 0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x00, 0x9c, 0x00, 0x96,
+ 0x00, 0x87, 0x00, 0x71, 0x00, 0x57, 0x00, 0x3d, 0x00, 0x25, 0x00, 0x10,
+ 0x06, 0x07, 0x0b, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x26, 0x00, 0x2d, 0x00,
+ 0x32, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x20, 0x00, 0x28, 0x00,
+ 0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x00, 0x9c, 0x00, 0x97,
+ 0x00, 0x8a, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x48, 0x00, 0x33, 0x00, 0x1f,
+ 0x00, 0x0f, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x25, 0x00,
+ 0x2c, 0x00, 0x31, 0x00, 0x3e, 0x37, 0x3e, 0x33, 0x3c, 0x2f, 0x3b, 0x2c,
+ 0x3c, 0x29, 0x3c, 0x27, 0x39, 0x25, 0x3a, 0x23, 0x3b, 0x21, 0x3b, 0x20,
+ 0x3b, 0x1f, 0x3a, 0x1e, 0x39, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19,
+ 0x3c, 0x19, 0x3c, 0x18, 0x3c, 0x17, 0x3b, 0x17, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x00, 0xaf, 0x00, 0xa3, 0x00, 0x98, 0x00, 0x8e, 0x00, 0x84, 0x00, 0x7a,
+ 0x00, 0x72, 0x00, 0x6c, 0x01, 0x65, 0x02, 0x5f, 0x04, 0x5a, 0x04, 0x56,
+ 0x05, 0x52, 0x06, 0x4e, 0x07, 0x4a, 0x09, 0x47, 0x0a, 0x45, 0x0a, 0x41,
+ 0x0c, 0x40, 0x0c, 0x3d, 0x23, 0x5c, 0x23, 0x56, 0x23, 0x51, 0x23, 0x4c,
+ 0x23, 0x47, 0x23, 0x42, 0x23, 0x3e, 0x24, 0x3b, 0x24, 0x37, 0x25, 0x34,
+ 0x25, 0x32, 0x25, 0x30, 0x26, 0x2e, 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28,
+ 0x28, 0x27, 0x29, 0x25, 0x2a, 0x25, 0x2a, 0x23, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d, 0x00, 0x24, 0x00, 0x2a, 0x00,
+ 0x30, 0x00, 0x35, 0x00, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x7a,
+ 0x00, 0x64, 0x00, 0x4e, 0x00, 0x37, 0x00, 0x22, 0x00, 0x10, 0x05, 0x08,
+ 0x0a, 0x02, 0x12, 0x00, 0x1a, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00,
+ 0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29, 0x00, 0x1a, 0x00, 0x0c, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d, 0x00, 0x24, 0x00, 0x2a, 0x00,
+ 0x30, 0x00, 0x35, 0x00, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e,
+ 0x00, 0x6b, 0x00, 0x57, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x11,
+ 0x00, 0x04, 0x07, 0x00, 0x10, 0x00, 0x19, 0x00, 0x20, 0x00, 0x26, 0x00,
+ 0x3e, 0x38, 0x3e, 0x33, 0x3d, 0x30, 0x3b, 0x2d, 0x3c, 0x2a, 0x3c, 0x27,
+ 0x3a, 0x26, 0x3a, 0x24, 0x3a, 0x22, 0x3b, 0x21, 0x3b, 0x1f, 0x3b, 0x1f,
+ 0x39, 0x1e, 0x3a, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19,
+ 0x3c, 0x18, 0x3c, 0x17, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xaf, 0x00, 0xa5,
+ 0x00, 0x99, 0x00, 0x90, 0x00, 0x87, 0x00, 0x7e, 0x00, 0x76, 0x00, 0x6f,
+ 0x01, 0x68, 0x02, 0x62, 0x02, 0x5e, 0x04, 0x59, 0x04, 0x55, 0x05, 0x51,
+ 0x07, 0x4e, 0x07, 0x4a, 0x09, 0x47, 0x0a, 0x45, 0x0a, 0x41, 0x0c, 0x41,
+ 0x23, 0x5c, 0x23, 0x57, 0x23, 0x52, 0x23, 0x4d, 0x23, 0x48, 0x23, 0x44,
+ 0x23, 0x40, 0x24, 0x3c, 0x24, 0x39, 0x24, 0x36, 0x25, 0x34, 0x25, 0x31,
+ 0x26, 0x2f, 0x26, 0x2d, 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x27,
+ 0x28, 0x25, 0x2a, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2c, 0x00,
+ 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x90, 0x00, 0x81, 0x00, 0x6f, 0x00, 0x5b,
+ 0x00, 0x46, 0x00, 0x32, 0x00, 0x20, 0x00, 0x10, 0x04, 0x09, 0x09, 0x03,
+ 0x0f, 0x00, 0x17, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x4b, 0x00,
+ 0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2c, 0x00,
+ 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x92, 0x00, 0x84, 0x00, 0x74, 0x00, 0x62,
+ 0x00, 0x50, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x06,
+ 0x03, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x3e, 0x38, 0x3e, 0x34,
+ 0x3e, 0x31, 0x3b, 0x2e, 0x3b, 0x2b, 0x3c, 0x29, 0x3c, 0x27, 0x39, 0x25,
+ 0x3a, 0x24, 0x3a, 0x21, 0x3b, 0x21, 0x3b, 0x1f, 0x3b, 0x1f, 0x39, 0x1d,
+ 0x3a, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x19,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xaf, 0x00, 0xa6, 0x00, 0x9b, 0x00, 0x91,
+ 0x00, 0x88, 0x00, 0x80, 0x00, 0x78, 0x00, 0x71, 0x00, 0x6b, 0x01, 0x66,
+ 0x02, 0x61, 0x03, 0x5c, 0x04, 0x58, 0x05, 0x55, 0x05, 0x50, 0x07, 0x4e,
+ 0x07, 0x4a, 0x09, 0x47, 0x0a, 0x45, 0x0a, 0x42, 0x23, 0x5c, 0x23, 0x58,
+ 0x23, 0x53, 0x23, 0x4d, 0x23, 0x49, 0x23, 0x45, 0x23, 0x41, 0x24, 0x3d,
+ 0x24, 0x3b, 0x24, 0x38, 0x25, 0x35, 0x25, 0x33, 0x25, 0x31, 0x26, 0x2f,
+ 0x26, 0x2d, 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x26,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x9d, 0x00, 0x9b,
+ 0x00, 0x93, 0x00, 0x86, 0x00, 0x76, 0x00, 0x65, 0x00, 0x52, 0x00, 0x40,
+ 0x00, 0x2f, 0x00, 0x1e, 0x00, 0x10, 0x04, 0x09, 0x08, 0x04, 0x0c, 0x00,
+ 0x14, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38, 0x00,
+ 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x9e, 0x00, 0x9b,
+ 0x00, 0x94, 0x00, 0x89, 0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4b,
+ 0x00, 0x3b, 0x00, 0x2d, 0x00, 0x1f, 0x00, 0x13, 0x00, 0x08, 0x00, 0x00,
+ 0x09, 0x00, 0x11, 0x00, 0x3e, 0x38, 0x3e, 0x35, 0x3e, 0x32, 0x3b, 0x2e,
+ 0x3b, 0x2c, 0x3c, 0x2a, 0x3c, 0x27, 0x3a, 0x26, 0x3a, 0x24, 0x3a, 0x23,
+ 0x3b, 0x21, 0x3b, 0x20, 0x3b, 0x1f, 0x3a, 0x1f, 0x39, 0x1d, 0x3a, 0x1c,
+ 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x00, 0xb0, 0x00, 0xa6, 0x00, 0x9d, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x83,
+ 0x00, 0x7c, 0x00, 0x75, 0x00, 0x6e, 0x01, 0x69, 0x01, 0x63, 0x02, 0x5f,
+ 0x04, 0x5b, 0x04, 0x56, 0x05, 0x54, 0x05, 0x4f, 0x07, 0x4e, 0x07, 0x4a,
+ 0x09, 0x47, 0x0a, 0x46, 0x23, 0x5d, 0x23, 0x58, 0x23, 0x53, 0x23, 0x4f,
+ 0x23, 0x4a, 0x23, 0x46, 0x23, 0x43, 0x23, 0x3f, 0x24, 0x3c, 0x24, 0x39,
+ 0x24, 0x36, 0x25, 0x34, 0x25, 0x32, 0x25, 0x30, 0x26, 0x2f, 0x26, 0x2d,
+ 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00,
+ 0x16, 0x00, 0x1c, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x95, 0x00, 0x8a,
+ 0x00, 0x7d, 0x00, 0x6d, 0x00, 0x5d, 0x00, 0x4c, 0x00, 0x3b, 0x00, 0x2c,
+ 0x00, 0x1d, 0x00, 0x10, 0x04, 0x0a, 0x07, 0x05, 0x0b, 0x00, 0x11, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00,
+ 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x28, 0x00,
+ 0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00,
+ 0x16, 0x00, 0x1c, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8c,
+ 0x00, 0x80, 0x00, 0x73, 0x00, 0x64, 0x00, 0x55, 0x00, 0x46, 0x00, 0x38,
+ 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x06, 0x00,
+ 0x3e, 0x39, 0x3e, 0x35, 0x3e, 0x32, 0x3b, 0x2f, 0x3b, 0x2d, 0x3c, 0x2a,
+ 0x3c, 0x28, 0x3b, 0x27, 0x39, 0x24, 0x3a, 0x24, 0x3a, 0x22, 0x3b, 0x21,
+ 0x3b, 0x1f, 0x3b, 0x1f, 0x39, 0x1f, 0x39, 0x1d, 0x3b, 0x1c, 0x3b, 0x1c,
+ 0x3b, 0x1a, 0x3c, 0x19, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
+ 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xb0, 0x00, 0xa7,
+ 0x00, 0x9e, 0x00, 0x96, 0x00, 0x8d, 0x00, 0x86, 0x00, 0x7e, 0x00, 0x77,
+ 0x00, 0x71, 0x00, 0x6b, 0x01, 0x66, 0x02, 0x62, 0x02, 0x5d, 0x04, 0x5a,
+ 0x04, 0x55, 0x05, 0x53, 0x05, 0x4f, 0x07, 0x4e, 0x07, 0x4a, 0x09, 0x47,
+ 0x23, 0x5d, 0x23, 0x58, 0x23, 0x54, 0x23, 0x50, 0x23, 0x4c, 0x23, 0x48,
+ 0x23, 0x44, 0x23, 0x40, 0x24, 0x3d, 0x24, 0x3a, 0x24, 0x38, 0x25, 0x36,
+ 0x25, 0x33, 0x25, 0x32, 0x25, 0x2f, 0x26, 0x2f, 0x26, 0x2c, 0x27, 0x2c,
+ 0x27, 0x2a, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x14, 0x00,
+ 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8d, 0x00, 0x81, 0x00, 0x74,
+ 0x00, 0x65, 0x00, 0x56, 0x00, 0x46, 0x00, 0x37, 0x00, 0x29, 0x00, 0x1c,
+ 0x00, 0x10, 0x03, 0x0a, 0x07, 0x06, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00,
+ 0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e, 0x00, 0x24, 0x00, 0x1a, 0x00,
+ 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x14, 0x00,
+ 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8f, 0x00, 0x85, 0x00, 0x79,
+ 0x00, 0x6b, 0x00, 0x5e, 0x00, 0x50, 0x00, 0x43, 0x00, 0x36, 0x00, 0x2a,
+ 0x00, 0x1f, 0x00, 0x15, 0x00, 0x0c, 0x00, 0x03, 0x32, 0x59, 0x2a, 0x5b,
+ 0x28, 0x5c, 0x27, 0x5d, 0x27, 0x5d, 0x26, 0x5e, 0x26, 0x5e, 0x26, 0x5e,
+ 0x26, 0x5e, 0x26, 0x5e, 0x25, 0x5e, 0x25, 0x5e, 0x25, 0x5f, 0x25, 0x5f,
+ 0x25, 0x5f, 0x25, 0x5f, 0x25, 0x5f, 0x24, 0x5f, 0x24, 0x5f, 0x24, 0x60,
+ 0x32, 0x3c, 0x25, 0x4a, 0x24, 0x50, 0x23, 0x54, 0x23, 0x56, 0x23, 0x58,
+ 0x23, 0x59, 0x23, 0x5a, 0x23, 0x5a, 0x23, 0x5b, 0x23, 0x5b, 0x23, 0x5b,
+ 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5d,
+ 0x23, 0x5d, 0x23, 0x5d, 0x00, 0x6c, 0x0e, 0x60, 0x14, 0x60, 0x18, 0x60,
+ 0x1b, 0x60, 0x1d, 0x60, 0x1d, 0x60, 0x1e, 0x60, 0x1f, 0x60, 0x20, 0x60,
+ 0x20, 0x60, 0x20, 0x60, 0x21, 0x60, 0x21, 0x60, 0x21, 0x60, 0x21, 0x60,
+ 0x22, 0x60, 0x22, 0x60, 0x22, 0x60, 0x22, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x9e, 0x00, 0x9c,
+ 0x00, 0x97, 0x00, 0x90, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x5e,
+ 0x00, 0x50, 0x00, 0x42, 0x00, 0x34, 0x00, 0x27, 0x00, 0x1b, 0x00, 0x0f,
+ 0x03, 0x0b, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x46, 0x00,
+ 0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x9e, 0x00, 0x9d,
+ 0x00, 0x98, 0x00, 0x91, 0x00, 0x88, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65,
+ 0x00, 0x59, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x1f,
+ 0x00, 0x16, 0x00, 0x0d, 0x38, 0x4f, 0x31, 0x53, 0x2e, 0x56, 0x2c, 0x57,
+ 0x2a, 0x59, 0x29, 0x5a, 0x29, 0x5a, 0x28, 0x5b, 0x27, 0x5c, 0x27, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x38, 0x22, 0x2b, 0x31,
+ 0x27, 0x3b, 0x25, 0x42, 0x24, 0x47, 0x23, 0x4a, 0x23, 0x4d, 0x23, 0x4f,
+ 0x23, 0x51, 0x23, 0x52, 0x23, 0x53, 0x23, 0x54, 0x23, 0x55, 0x23, 0x56,
+ 0x23, 0x56, 0x23, 0x57, 0x23, 0x58, 0x23, 0x58, 0x23, 0x58, 0x23, 0x58,
+ 0x00, 0x92, 0x01, 0x79, 0x07, 0x6f, 0x0c, 0x6b, 0x0f, 0x68, 0x12, 0x67,
+ 0x14, 0x66, 0x16, 0x65, 0x17, 0x64, 0x18, 0x64, 0x19, 0x63, 0x1a, 0x63,
+ 0x1b, 0x63, 0x1b, 0x63, 0x1c, 0x63, 0x1c, 0x62, 0x1d, 0x62, 0x1d, 0x62,
+ 0x1d, 0x62, 0x1e, 0x62, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x92,
+ 0x00, 0x89, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x58, 0x00, 0x4b,
+ 0x00, 0x3e, 0x00, 0x31, 0x00, 0x25, 0x00, 0x1a, 0x00, 0x0f, 0x03, 0x0b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00,
+ 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49, 0x00, 0x41, 0x00, 0x39, 0x00,
+ 0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x07, 0x00,
+ 0x00, 0x00, 0x06, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93,
+ 0x00, 0x8b, 0x00, 0x82, 0x00, 0x77, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54,
+ 0x00, 0x49, 0x00, 0x3d, 0x00, 0x33, 0x00, 0x29, 0x00, 0x1f, 0x00, 0x17,
+ 0x3a, 0x4b, 0x34, 0x4f, 0x31, 0x52, 0x2f, 0x54, 0x2d, 0x56, 0x2c, 0x57,
+ 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x59, 0x29, 0x5a, 0x29, 0x5a,
+ 0x28, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c,
+ 0x27, 0x5c, 0x27, 0x5c, 0x3c, 0x18, 0x30, 0x25, 0x2a, 0x2e, 0x27, 0x35,
+ 0x25, 0x3b, 0x24, 0x3f, 0x24, 0x43, 0x24, 0x46, 0x23, 0x48, 0x23, 0x4a,
+ 0x23, 0x4c, 0x23, 0x4e, 0x23, 0x4f, 0x23, 0x50, 0x23, 0x51, 0x23, 0x52,
+ 0x23, 0x53, 0x23, 0x53, 0x23, 0x54, 0x23, 0x54, 0x00, 0xa1, 0x00, 0x88,
+ 0x03, 0x7b, 0x06, 0x74, 0x09, 0x70, 0x0c, 0x6d, 0x0e, 0x6b, 0x10, 0x6a,
+ 0x11, 0x69, 0x13, 0x68, 0x14, 0x67, 0x15, 0x66, 0x16, 0x66, 0x17, 0x65,
+ 0x17, 0x65, 0x18, 0x65, 0x19, 0x65, 0x19, 0x64, 0x1a, 0x64, 0x1a, 0x64,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82,
+ 0x00, 0x77, 0x00, 0x6b, 0x00, 0x5f, 0x00, 0x53, 0x00, 0x46, 0x00, 0x3a,
+ 0x00, 0x2f, 0x00, 0x24, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x57, 0x00,
+ 0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x2c, 0x00,
+ 0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x8d, 0x00, 0x85,
+ 0x00, 0x7b, 0x00, 0x71, 0x00, 0x66, 0x00, 0x5b, 0x00, 0x50, 0x00, 0x46,
+ 0x00, 0x3b, 0x00, 0x31, 0x00, 0x28, 0x00, 0x1f, 0x3b, 0x48, 0x36, 0x4c,
+ 0x33, 0x4f, 0x31, 0x52, 0x2f, 0x53, 0x2e, 0x53, 0x2d, 0x55, 0x2c, 0x57,
+ 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x58,
+ 0x2a, 0x59, 0x29, 0x5a, 0x29, 0x5b, 0x28, 0x5b, 0x27, 0x5c, 0x27, 0x5c,
+ 0x3f, 0x14, 0x33, 0x1e, 0x2d, 0x26, 0x29, 0x2d, 0x27, 0x32, 0x26, 0x36,
+ 0x25, 0x3b, 0x24, 0x3e, 0x24, 0x41, 0x24, 0x43, 0x23, 0x45, 0x23, 0x47,
+ 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23, 0x4d, 0x23, 0x4d, 0x23, 0x4f,
+ 0x23, 0x50, 0x23, 0x50, 0x00, 0xa7, 0x00, 0x92, 0x01, 0x84, 0x03, 0x7d,
+ 0x05, 0x77, 0x08, 0x73, 0x0a, 0x71, 0x0c, 0x6f, 0x0d, 0x6d, 0x0f, 0x6b,
+ 0x10, 0x6a, 0x11, 0x6a, 0x12, 0x69, 0x13, 0x68, 0x14, 0x68, 0x15, 0x67,
+ 0x15, 0x66, 0x16, 0x66, 0x17, 0x66, 0x17, 0x66, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x31, 0x23, 0x03,
+ 0x46, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5a, 0x00, 0x5c, 0x00, 0x5d, 0x00,
+ 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00,
+ 0x5e, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x31, 0x00, 0x5f, 0x00, 0x85, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9a,
+ 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e,
+ 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x47, 0x38, 0x4b, 0x35, 0x4e, 0x32, 0x4f,
+ 0x31, 0x51, 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x55, 0x2c, 0x56,
+ 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
+ 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x58, 0x2a, 0x59, 0x40, 0x11, 0x36, 0x1a,
+ 0x2f, 0x21, 0x2c, 0x27, 0x29, 0x2c, 0x27, 0x30, 0x26, 0x34, 0x25, 0x37,
+ 0x25, 0x3a, 0x24, 0x3d, 0x24, 0x40, 0x24, 0x42, 0x24, 0x44, 0x23, 0x45,
+ 0x23, 0x47, 0x23, 0x48, 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23, 0x4c,
+ 0x00, 0xaa, 0x00, 0x98, 0x00, 0x8c, 0x02, 0x83, 0x03, 0x7d, 0x05, 0x79,
+ 0x07, 0x76, 0x09, 0x73, 0x0a, 0x71, 0x0c, 0x6f, 0x0d, 0x6e, 0x0e, 0x6d,
+ 0x0f, 0x6c, 0x10, 0x6b, 0x11, 0x6a, 0x12, 0x6a, 0x13, 0x69, 0x13, 0x68,
+ 0x14, 0x68, 0x15, 0x68, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x20, 0x1f, 0x00, 0x3c, 0x00,
+ 0x4a, 0x00, 0x51, 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00,
+ 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x03, 0x00, 0x20,
+ 0x00, 0x5f, 0x00, 0x7c, 0x00, 0x8a, 0x00, 0x91, 0x00, 0x95, 0x00, 0x97,
+ 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d,
+ 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x46, 0x39, 0x4a, 0x36, 0x4b, 0x34, 0x4e, 0x32, 0x4f, 0x31, 0x50,
+ 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x54, 0x2d, 0x56,
+ 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
+ 0x2a, 0x57, 0x2a, 0x57, 0x41, 0x10, 0x38, 0x17, 0x32, 0x1d, 0x2e, 0x22,
+ 0x2b, 0x27, 0x29, 0x2b, 0x27, 0x2f, 0x26, 0x32, 0x25, 0x35, 0x25, 0x38,
+ 0x25, 0x3b, 0x24, 0x3c, 0x24, 0x3f, 0x24, 0x40, 0x24, 0x42, 0x23, 0x44,
+ 0x23, 0x45, 0x23, 0x46, 0x23, 0x48, 0x23, 0x48, 0x00, 0xac, 0x00, 0x9d,
+ 0x00, 0x91, 0x01, 0x89, 0x02, 0x82, 0x03, 0x7e, 0x05, 0x7a, 0x07, 0x77,
+ 0x08, 0x75, 0x09, 0x73, 0x0b, 0x71, 0x0c, 0x70, 0x0d, 0x6e, 0x0e, 0x6e,
+ 0x0e, 0x6c, 0x0f, 0x6c, 0x10, 0x6b, 0x10, 0x6a, 0x11, 0x6a, 0x12, 0x6a,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x85, 0x00, 0x5f, 0x00, 0x1f, 0x0d, 0x00, 0x28, 0x00, 0x39, 0x00,
+ 0x43, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x52, 0x00, 0x54, 0x00, 0x56, 0x00,
+ 0x57, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x1f, 0x00, 0x00, 0x1f, 0x00, 0x4d,
+ 0x00, 0x68, 0x00, 0x79, 0x00, 0x83, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x92,
+ 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x39, 0x48,
+ 0x37, 0x4a, 0x35, 0x4c, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x52,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x54, 0x2d, 0x56,
+ 0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
+ 0x42, 0x0f, 0x39, 0x15, 0x33, 0x1a, 0x2f, 0x1f, 0x2d, 0x24, 0x2a, 0x27,
+ 0x29, 0x2b, 0x27, 0x2e, 0x26, 0x31, 0x26, 0x34, 0x25, 0x36, 0x25, 0x38,
+ 0x25, 0x3b, 0x24, 0x3c, 0x24, 0x3e, 0x24, 0x40, 0x24, 0x41, 0x24, 0x43,
+ 0x23, 0x44, 0x23, 0x45, 0x00, 0xae, 0x00, 0xa1, 0x00, 0x96, 0x00, 0x8d,
+ 0x01, 0x87, 0x02, 0x82, 0x03, 0x7e, 0x05, 0x7b, 0x06, 0x78, 0x07, 0x76,
+ 0x09, 0x74, 0x0a, 0x73, 0x0b, 0x71, 0x0c, 0x70, 0x0c, 0x6f, 0x0d, 0x6e,
+ 0x0e, 0x6d, 0x0f, 0x6c, 0x10, 0x6c, 0x10, 0x6b, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x7c,
+ 0x00, 0x4d, 0x00, 0x1f, 0x02, 0x00, 0x1a, 0x00, 0x2a, 0x00, 0x36, 0x00,
+ 0x3e, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4d, 0x00, 0x4f, 0x00, 0x52, 0x00,
+ 0x53, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x52, 0x00, 0x3c, 0x00, 0x0d, 0x00, 0x00, 0x1f, 0x00, 0x42, 0x00, 0x5a,
+ 0x00, 0x6a, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x84, 0x00, 0x89, 0x00, 0x8c,
+ 0x00, 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x3a, 0x47, 0x38, 0x4a, 0x35, 0x4a,
+ 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x52, 0x2f, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x55,
+ 0x2c, 0x57, 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x43, 0x0e, 0x3b, 0x13,
+ 0x35, 0x18, 0x31, 0x1c, 0x2e, 0x21, 0x2c, 0x24, 0x2a, 0x28, 0x28, 0x2b,
+ 0x27, 0x2e, 0x27, 0x30, 0x26, 0x33, 0x25, 0x35, 0x25, 0x37, 0x25, 0x39,
+ 0x25, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x3f, 0x24, 0x40, 0x24, 0x42,
+ 0x00, 0xaf, 0x00, 0xa3, 0x00, 0x99, 0x00, 0x91, 0x00, 0x8b, 0x02, 0x86,
+ 0x02, 0x81, 0x03, 0x7e, 0x05, 0x7b, 0x06, 0x79, 0x07, 0x77, 0x08, 0x75,
+ 0x09, 0x74, 0x0a, 0x73, 0x0b, 0x71, 0x0c, 0x71, 0x0c, 0x6f, 0x0d, 0x6e,
+ 0x0e, 0x6e, 0x0e, 0x6d, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x68, 0x00, 0x42,
+ 0x00, 0x1f, 0x00, 0x04, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x34, 0x00,
+ 0x3b, 0x00, 0x41, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4b, 0x00, 0x4e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x4a, 0x00,
+ 0x28, 0x00, 0x02, 0x00, 0x00, 0x1f, 0x00, 0x3b, 0x00, 0x4f, 0x00, 0x5f,
+ 0x00, 0x6b, 0x00, 0x74, 0x00, 0x7b, 0x00, 0x80, 0x00, 0x85, 0x00, 0x88,
+ 0x00, 0x8b, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x44, 0x3b, 0x46, 0x39, 0x49, 0x36, 0x4a, 0x35, 0x4b, 0x34, 0x4e,
+ 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x51, 0x2f, 0x53, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x55,
+ 0x2c, 0x56, 0x2b, 0x57, 0x44, 0x0e, 0x3c, 0x12, 0x36, 0x16, 0x33, 0x1a,
+ 0x30, 0x1e, 0x2d, 0x22, 0x2b, 0x25, 0x2a, 0x28, 0x28, 0x2a, 0x27, 0x2d,
+ 0x27, 0x30, 0x26, 0x32, 0x26, 0x34, 0x25, 0x35, 0x25, 0x37, 0x25, 0x39,
+ 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x3f, 0x00, 0xb0, 0x00, 0xa5,
+ 0x00, 0x9d, 0x00, 0x95, 0x00, 0x8e, 0x01, 0x89, 0x02, 0x85, 0x03, 0x81,
+ 0x04, 0x7e, 0x05, 0x7c, 0x06, 0x7a, 0x07, 0x78, 0x07, 0x76, 0x09, 0x75,
+ 0x09, 0x73, 0x0b, 0x73, 0x0b, 0x71, 0x0c, 0x71, 0x0c, 0x70, 0x0d, 0x6e,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9a, 0x00, 0x91, 0x00, 0x79, 0x00, 0x5a, 0x00, 0x3b, 0x00, 0x1f,
+ 0x00, 0x09, 0x08, 0x00, 0x17, 0x00, 0x22, 0x00, 0x2c, 0x00, 0x33, 0x00,
+ 0x39, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x51, 0x00, 0x39, 0x00, 0x1a, 0x00,
+ 0x00, 0x04, 0x00, 0x1f, 0x00, 0x36, 0x00, 0x48, 0x00, 0x57, 0x00, 0x62,
+ 0x00, 0x6b, 0x00, 0x73, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x85,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x44, 0x3b, 0x46,
+ 0x39, 0x48, 0x37, 0x4a, 0x35, 0x4a, 0x35, 0x4c, 0x34, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x55,
+ 0x44, 0x0d, 0x3d, 0x11, 0x38, 0x15, 0x34, 0x19, 0x31, 0x1c, 0x2e, 0x20,
+ 0x2d, 0x23, 0x2b, 0x25, 0x2a, 0x28, 0x28, 0x2a, 0x28, 0x2d, 0x27, 0x2f,
+ 0x26, 0x31, 0x26, 0x33, 0x25, 0x34, 0x25, 0x36, 0x25, 0x38, 0x25, 0x39,
+ 0x24, 0x3a, 0x24, 0x3c, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9f, 0x00, 0x98,
+ 0x00, 0x91, 0x00, 0x8c, 0x01, 0x88, 0x02, 0x84, 0x03, 0x81, 0x04, 0x7e,
+ 0x05, 0x7c, 0x06, 0x7a, 0x06, 0x79, 0x07, 0x77, 0x08, 0x76, 0x09, 0x74,
+ 0x0a, 0x73, 0x0b, 0x73, 0x0b, 0x71, 0x0c, 0x71, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x95,
+ 0x00, 0x83, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x0c,
+ 0x03, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32, 0x00,
+ 0x37, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x55, 0x00, 0x43, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x09,
+ 0x00, 0x1f, 0x00, 0x33, 0x00, 0x43, 0x00, 0x50, 0x00, 0x5b, 0x00, 0x64,
+ 0x00, 0x6b, 0x00, 0x72, 0x00, 0x77, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x43, 0x3c, 0x46, 0x39, 0x46, 0x39, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x50, 0x30, 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x44, 0x0d, 0x3e, 0x10,
+ 0x39, 0x14, 0x35, 0x17, 0x32, 0x1b, 0x30, 0x1e, 0x2e, 0x21, 0x2c, 0x23,
+ 0x2b, 0x26, 0x2a, 0x28, 0x28, 0x2a, 0x28, 0x2d, 0x27, 0x2e, 0x26, 0x30,
+ 0x26, 0x32, 0x25, 0x34, 0x25, 0x35, 0x25, 0x36, 0x25, 0x38, 0x25, 0x39,
+ 0x00, 0xb1, 0x00, 0xa9, 0x00, 0xa1, 0x00, 0x9a, 0x00, 0x94, 0x00, 0x8f,
+ 0x01, 0x8b, 0x02, 0x87, 0x02, 0x84, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d,
+ 0x06, 0x7b, 0x06, 0x79, 0x07, 0x78, 0x07, 0x76, 0x09, 0x76, 0x09, 0x74,
+ 0x0a, 0x73, 0x0b, 0x72, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x76,
+ 0x00, 0x5f, 0x00, 0x48, 0x00, 0x33, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
+ 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x25, 0x00, 0x2c, 0x00, 0x31, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00,
+ 0x4a, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x08, 0x00, 0x00, 0x0c, 0x00, 0x1f,
+ 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x55, 0x00, 0x5e, 0x00, 0x65,
+ 0x00, 0x6c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x42, 0x3c, 0x46, 0x39, 0x46, 0x39, 0x48, 0x37, 0x4a, 0x35, 0x4a,
+ 0x35, 0x4b, 0x35, 0x4e, 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x52, 0x2f, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x44, 0x0c, 0x3f, 0x10, 0x3a, 0x13, 0x36, 0x16,
+ 0x33, 0x19, 0x30, 0x1c, 0x2e, 0x1f, 0x2d, 0x21, 0x2b, 0x24, 0x2a, 0x26,
+ 0x2a, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2e, 0x26, 0x30, 0x26, 0x31,
+ 0x26, 0x33, 0x25, 0x34, 0x25, 0x36, 0x25, 0x37, 0x00, 0xb2, 0x00, 0xaa,
+ 0x00, 0xa2, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x91, 0x00, 0x8d, 0x01, 0x89,
+ 0x02, 0x86, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d, 0x06, 0x7b,
+ 0x06, 0x79, 0x07, 0x79, 0x07, 0x77, 0x08, 0x76, 0x09, 0x75, 0x09, 0x74,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x6b, 0x00, 0x57,
+ 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x11, 0x00, 0x04, 0x07, 0x00,
+ 0x10, 0x00, 0x19, 0x00, 0x20, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4e, 0x00, 0x3e, 0x00,
+ 0x2b, 0x00, 0x17, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x2e,
+ 0x00, 0x3b, 0x00, 0x46, 0x00, 0x50, 0x00, 0x59, 0x00, 0x60, 0x00, 0x66,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x46,
+ 0x39, 0x46, 0x39, 0x47, 0x38, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4b,
+ 0x34, 0x4e, 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x51, 0x2f, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
+ 0x45, 0x0c, 0x3f, 0x0f, 0x3a, 0x12, 0x37, 0x15, 0x34, 0x18, 0x32, 0x1b,
+ 0x30, 0x1d, 0x2e, 0x20, 0x2d, 0x22, 0x2b, 0x24, 0x2a, 0x26, 0x2a, 0x28,
+ 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2e, 0x27, 0x2f, 0x26, 0x31, 0x26, 0x32,
+ 0x25, 0x33, 0x25, 0x35, 0x00, 0xb2, 0x00, 0xab, 0x00, 0xa4, 0x00, 0x9e,
+ 0x00, 0x98, 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8b, 0x01, 0x88, 0x02, 0x85,
+ 0x02, 0x83, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d, 0x05, 0x7c, 0x06, 0x7a,
+ 0x07, 0x79, 0x07, 0x78, 0x07, 0x76, 0x09, 0x76, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a,
+ 0x00, 0x92, 0x00, 0x84, 0x00, 0x74, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f,
+ 0x00, 0x2e, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x06, 0x03, 0x00, 0x0c, 0x00,
+ 0x14, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5e, 0x00, 0x5b, 0x00, 0x52, 0x00, 0x45, 0x00, 0x34, 0x00, 0x22, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x38,
+ 0x00, 0x43, 0x00, 0x4c, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x45, 0x3a, 0x46, 0x39, 0x46,
+ 0x39, 0x49, 0x36, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4c, 0x33, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x51,
+ 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x45, 0x0c, 0x40, 0x0f,
+ 0x3b, 0x11, 0x38, 0x14, 0x35, 0x17, 0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1e,
+ 0x2d, 0x21, 0x2c, 0x22, 0x2b, 0x25, 0x2a, 0x26, 0x29, 0x28, 0x28, 0x2a,
+ 0x28, 0x2c, 0x27, 0x2d, 0x27, 0x2f, 0x26, 0x30, 0x26, 0x32, 0x25, 0x33,
+ 0x00, 0xb2, 0x00, 0xac, 0x00, 0xa5, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x96,
+ 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8a, 0x02, 0x88, 0x02, 0x85, 0x02, 0x83,
+ 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d, 0x05, 0x7c, 0x06, 0x7a, 0x06, 0x79,
+ 0x07, 0x78, 0x07, 0x77, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x94, 0x00, 0x89,
+ 0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2d,
+ 0x00, 0x1f, 0x00, 0x13, 0x00, 0x08, 0x00, 0x00, 0x09, 0x00, 0x11, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00,
+ 0x54, 0x00, 0x49, 0x00, 0x3b, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x0b, 0x00,
+ 0x00, 0x04, 0x00, 0x12, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x00, 0x40,
+ 0x00, 0x49, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x42, 0x3d, 0x44, 0x3a, 0x46, 0x39, 0x46, 0x39, 0x48, 0x37, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x53,
+ 0x2e, 0x53, 0x2e, 0x53, 0x45, 0x0c, 0x40, 0x0e, 0x3c, 0x11, 0x38, 0x13,
+ 0x36, 0x16, 0x33, 0x18, 0x31, 0x1b, 0x30, 0x1d, 0x2e, 0x1f, 0x2d, 0x21,
+ 0x2b, 0x23, 0x2b, 0x25, 0x2a, 0x27, 0x29, 0x28, 0x28, 0x2a, 0x28, 0x2c,
+ 0x27, 0x2d, 0x27, 0x2f, 0x26, 0x2f, 0x26, 0x31, 0x00, 0xb3, 0x00, 0xac,
+ 0x00, 0xa7, 0x00, 0xa1, 0x00, 0x9b, 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f,
+ 0x01, 0x8c, 0x01, 0x89, 0x02, 0x87, 0x02, 0x85, 0x02, 0x82, 0x03, 0x81,
+ 0x04, 0x7f, 0x05, 0x7d, 0x05, 0x7c, 0x06, 0x7b, 0x06, 0x79, 0x07, 0x79,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x73,
+ 0x00, 0x64, 0x00, 0x55, 0x00, 0x46, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f,
+ 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4d, 0x00,
+ 0x41, 0x00, 0x33, 0x00, 0x24, 0x00, 0x15, 0x00, 0x07, 0x00, 0x00, 0x06,
+ 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x34, 0x00, 0x3d, 0x00, 0x46,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x44,
+ 0x3b, 0x46, 0x39, 0x46, 0x39, 0x47, 0x38, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4b, 0x34, 0x4e, 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x52, 0x2f, 0x53,
+ 0x45, 0x0c, 0x40, 0x0e, 0x3c, 0x11, 0x39, 0x13, 0x37, 0x15, 0x34, 0x18,
+ 0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1e, 0x2d, 0x20, 0x2d, 0x22, 0x2b, 0x23,
+ 0x2b, 0x25, 0x2a, 0x27, 0x29, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2d,
+ 0x27, 0x2f, 0x26, 0x2f, 0x00, 0xb3, 0x00, 0xad, 0x00, 0xa7, 0x00, 0xa3,
+ 0x00, 0x9d, 0x00, 0x99, 0x00, 0x95, 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8b,
+ 0x02, 0x88, 0x02, 0x86, 0x02, 0x84, 0x03, 0x82, 0x03, 0x81, 0x04, 0x7f,
+ 0x05, 0x7e, 0x05, 0x7c, 0x06, 0x7b, 0x06, 0x7a, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c,
+ 0x00, 0x97, 0x00, 0x8f, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6b, 0x00, 0x5e,
+ 0x00, 0x50, 0x00, 0x43, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x15,
+ 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5e, 0x00, 0x5d, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x45, 0x00, 0x39, 0x00,
+ 0x2c, 0x00, 0x1e, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x14,
+ 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x33, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x43, 0x3c, 0x46, 0x39, 0x46,
+ 0x39, 0x46, 0x39, 0x49, 0x36, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
+ 0x35, 0x4c, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x52, 0x45, 0x0b, 0x41, 0x0e,
+ 0x3d, 0x10, 0x3a, 0x12, 0x37, 0x14, 0x34, 0x17, 0x32, 0x19, 0x31, 0x1b,
+ 0x30, 0x1d, 0x2e, 0x1f, 0x2d, 0x20, 0x2c, 0x22, 0x2b, 0x24, 0x2a, 0x25,
+ 0x2a, 0x27, 0x29, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2c, 0x27, 0x2e,
+ 0x00, 0xb3, 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x9a,
+ 0x00, 0x96, 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8d, 0x01, 0x8a, 0x02, 0x88,
+ 0x02, 0x86, 0x02, 0x84, 0x03, 0x82, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7e,
+ 0x05, 0x7c, 0x06, 0x7c, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x91,
+ 0x00, 0x88, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c,
+ 0x00, 0x40, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00,
+ 0x59, 0x00, 0x52, 0x00, 0x49, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x25, 0x00,
+ 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x1f,
+ 0x00, 0x29, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0x42, 0x3d, 0x43, 0x3c, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x47,
+ 0x38, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4d,
+ 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x45, 0x0b, 0x41, 0x0e, 0x3e, 0x10, 0x3a, 0x11,
+ 0x38, 0x14, 0x35, 0x16, 0x33, 0x18, 0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1d,
+ 0x2e, 0x20, 0x2d, 0x21, 0x2b, 0x22, 0x2b, 0x24, 0x2a, 0x25, 0x2a, 0x27,
+ 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2c, 0x00, 0xb3, 0x00, 0xae,
+ 0x00, 0xa9, 0x00, 0xa4, 0x00, 0xa0, 0x00, 0x9b, 0x00, 0x98, 0x00, 0x94,
+ 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8c, 0x01, 0x89, 0x02, 0x87, 0x02, 0x86,
+ 0x02, 0x84, 0x03, 0x82, 0x03, 0x80, 0x04, 0x7f, 0x05, 0x7e, 0x05, 0x7c,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82,
+ 0x00, 0x77, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3d,
+ 0x00, 0x33, 0x00, 0x29, 0x00, 0x1f, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00,
+ 0x4b, 0x00, 0x42, 0x00, 0x37, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00,
+ 0x09, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x28,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x42,
+ 0x3d, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x4a, 0x36, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4b, 0x34, 0x4e, 0x32, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x46, 0x0b, 0x42, 0x0d, 0x3e, 0x10, 0x3b, 0x11, 0x38, 0x13, 0x36, 0x16,
+ 0x34, 0x17, 0x32, 0x19, 0x30, 0x1b, 0x30, 0x1d, 0x2e, 0x1e, 0x2d, 0x20,
+ 0x2d, 0x22, 0x2b, 0x23, 0x2b, 0x25, 0x2a, 0x25, 0x2a, 0x28, 0x28, 0x28,
+ 0x28, 0x2a, 0x28, 0x2c, 0x00, 0xb3, 0x00, 0xae, 0x00, 0xaa, 0x00, 0xa5,
+ 0x00, 0xa1, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x96, 0x00, 0x93, 0x00, 0x90,
+ 0x00, 0x8d, 0x01, 0x8b, 0x02, 0x89, 0x02, 0x87, 0x02, 0x85, 0x02, 0x83,
+ 0x03, 0x82, 0x03, 0x80, 0x04, 0x7f, 0x05, 0x7e, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d,
+ 0x00, 0x9a, 0x00, 0x95, 0x00, 0x8d, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71,
+ 0x00, 0x66, 0x00, 0x5b, 0x00, 0x50, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x31,
+ 0x00, 0x28, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45, 0x00,
+ 0x3c, 0x00, 0x31, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x06, 0x00,
+ 0x00, 0x03, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x45, 0x3a, 0x46,
+ 0x39, 0x46, 0x39, 0x46, 0x39, 0x48, 0x37, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
+ 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4c, 0x34, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
+ 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x46, 0x0b, 0x42, 0x0d,
+ 0x3e, 0x0f, 0x3c, 0x11, 0x39, 0x13, 0x37, 0x15, 0x34, 0x16, 0x33, 0x18,
+ 0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1d, 0x2e, 0x20, 0x2d, 0x20, 0x2c, 0x22,
+ 0x2b, 0x23, 0x2b, 0x25, 0x2a, 0x26, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x2a,
+ 0x00, 0xb4, 0x00, 0xaf, 0x00, 0xaa, 0x00, 0xa6, 0x00, 0xa2, 0x00, 0x9e,
+ 0x00, 0x9a, 0x00, 0x97, 0x00, 0x94, 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8c,
+ 0x01, 0x8a, 0x02, 0x88, 0x02, 0x86, 0x02, 0x85, 0x02, 0x83, 0x03, 0x82,
+ 0x03, 0x80, 0x04, 0x7f, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
+ 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xb2, 0x00, 0x6f, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0xa2, 0x00,
+ 0x4f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x7f, 0x00, 0x3c, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c,
+ 0x00, 0x16, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xd6, 0x00, 0xc6, 0x00, 0x9c, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12,
+ 0x00, 0x0c, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x00, 0xcd, 0x00,
+ 0xae, 0x00, 0x82, 0x00, 0x54, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a,
+ 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97, 0x00,
+ 0x6f, 0x00, 0x47, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e,
+ 0x00, 0x1b, 0x00, 0x17, 0x00, 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdb, 0x00, 0xd4, 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60, 0x00,
+ 0x3d, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19,
+ 0x00, 0x15, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00,
+ 0xc7, 0x00, 0xb0, 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12,
+ 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8, 0x00,
+ 0xa0, 0x00, 0x84, 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d,
+ 0x00, 0x09, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdd, 0x00, 0xd9, 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91, 0x00,
+ 0x78, 0x00, 0x5d, 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b,
+ 0x00, 0x19, 0x00, 0x16, 0x00, 0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08,
+ 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00,
+ 0xd1, 0x00, 0xc3, 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d, 0x00,
+ 0x55, 0x00, 0x3e, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17,
+ 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7, 0x00,
+ 0xb7, 0x00, 0xa4, 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00,
+ 0x39, 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13,
+ 0x00, 0x10, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdd, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab, 0x00,
+ 0x99, 0x00, 0x85, 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34, 0x00,
+ 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d,
+ 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e,
+ 0x00, 0x0c, 0x00, 0x09, 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00,
+ 0xd6, 0x00, 0xcd, 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e, 0x00,
+ 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x1c,
+ 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x24,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4c, 0x04, 0x11, 0x09, 0x01, 0x11, 0x00, 0x17,
+ 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
+ 0x61, 0x01, 0x23, 0x03, 0x03, 0x09, 0x00, 0x13, 0x00, 0x18, 0x00, 0x1a,
+ 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e,
+ 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x17, 0x00, 0x1a, 0x00, 0x1c,
+ 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x21,
+ 0x00, 0x27, 0x00, 0x2b, 0x00, 0x28, 0x00, 0x21, 0x00, 0x1d, 0x00, 0x1e,
+ 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x87, 0x00, 0x39, 0x01, 0x0f, 0x07, 0x02, 0x0c, 0x00, 0x12, 0x00, 0x17,
+ 0x00, 0x19, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d,
+ 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x9f, 0x00, 0x5f, 0x00,
+ 0x1f, 0x00, 0x04, 0x01, 0x00, 0x0a, 0x00, 0x11, 0x00, 0x15, 0x00, 0x18,
+ 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d,
+ 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0b, 0x00, 0x12, 0x00, 0x16, 0x00, 0x18, 0x00, 0x1a,
+ 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e,
+ 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x34, 0x00, 0x27, 0x00, 0x0f, 0x00, 0x1a,
+ 0x00, 0x1c, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c,
+ 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x87, 0x00,
+ 0x32, 0x00, 0x19, 0x05, 0x0b, 0x09, 0x03, 0x0b, 0x00, 0x0e, 0x00, 0x12,
+ 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1b,
+ 0x00, 0x1c, 0x00, 0x1c, 0xc5, 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x32, 0x00,
+ 0x16, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x12,
+ 0x00, 0x14, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19,
+ 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d,
+ 0x00, 0x32, 0x00, 0x2b, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x0e,
+ 0x00, 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b,
+ 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xcd, 0x00, 0xaf, 0x00, 0x6e, 0x00, 0x31, 0x00,
+ 0x1e, 0x04, 0x12, 0x07, 0x0a, 0x09, 0x04, 0x0a, 0x00, 0x0b, 0x00, 0x0f,
+ 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19,
+ 0xd2, 0x00, 0xbc, 0x00, 0x8d, 0x00, 0x5f, 0x00, 0x3d, 0x00, 0x25, 0x00,
+ 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0d,
+ 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
+ 0x00, 0x0c, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18,
+ 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x2c, 0x00, 0x28,
+ 0x00, 0x1c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x0f,
+ 0x00, 0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a,
+ 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xd4, 0x00, 0xc1, 0x00, 0x93, 0x00, 0x5f, 0x00, 0x30, 0x00, 0x22, 0x03,
+ 0x17, 0x06, 0x0f, 0x07, 0x0a, 0x09, 0x05, 0x0a, 0x02, 0x0b, 0x00, 0x0c,
+ 0x00, 0x0f, 0x00, 0x11, 0x00, 0x13, 0x00, 0x15, 0xd7, 0x00, 0xc9, 0x00,
+ 0xa8, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x44, 0x00, 0x2f, 0x00, 0x1f, 0x00,
+ 0x14, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x09,
+ 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a,
+ 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17,
+ 0x00, 0x18, 0x00, 0x19, 0x00, 0x24, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0e,
+ 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10,
+ 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0xcb, 0x00,
+ 0xaa, 0x00, 0x7f, 0x00, 0x55, 0x00, 0x30, 0x00, 0x24, 0x02, 0x1b, 0x05,
+ 0x14, 0x06, 0x0e, 0x08, 0x09, 0x09, 0x06, 0x0a, 0x03, 0x0b, 0x00, 0x0b,
+ 0x00, 0x0d, 0x00, 0x0f, 0xda, 0x00, 0xd0, 0x00, 0xb8, 0x00, 0x99, 0x00,
+ 0x7a, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x36, 0x00, 0x28, 0x00, 0x1c, 0x00,
+ 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c,
+ 0x00, 0x0e, 0x00, 0x11, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16,
+ 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x11,
+ 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xb8, 0x00, 0x96, 0x00,
+ 0x71, 0x00, 0x4e, 0x00, 0x30, 0x00, 0x26, 0x02, 0x1e, 0x04, 0x17, 0x06,
+ 0x12, 0x07, 0x0d, 0x08, 0x09, 0x09, 0x06, 0x0a, 0x04, 0x0a, 0x01, 0x0b,
+ 0xdb, 0x00, 0xd5, 0x00, 0xc3, 0x00, 0xaa, 0x00, 0x8f, 0x00, 0x76, 0x00,
+ 0x5f, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x1b, 0x00,
+ 0x13, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d,
+ 0x00, 0x0f, 0x00, 0x11, 0x00, 0x13, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x1e,
+ 0x00, 0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x11,
+ 0x00, 0x13, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdb, 0x00, 0xd4, 0x00, 0xc1, 0x00, 0xa6, 0x00, 0x87, 0x00, 0x67, 0x00,
+ 0x4a, 0x00, 0x30, 0x00, 0x27, 0x02, 0x20, 0x03, 0x1a, 0x05, 0x14, 0x06,
+ 0x10, 0x07, 0x0c, 0x08, 0x09, 0x09, 0x07, 0x0a, 0xdc, 0x00, 0xd7, 0x00,
+ 0xc9, 0x00, 0xb6, 0x00, 0x9f, 0x00, 0x88, 0x00, 0x72, 0x00, 0x5f, 0x00,
+ 0x4e, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00,
+ 0x13, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e,
+ 0x00, 0x10, 0x00, 0x11, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17,
+ 0x00, 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00,
+ 0xc8, 0x00, 0xb2, 0x00, 0x97, 0x00, 0x7b, 0x00, 0x60, 0x00, 0x46, 0x00,
+ 0x30, 0x00, 0x28, 0x01, 0x21, 0x03, 0x1c, 0x04, 0x17, 0x06, 0x13, 0x07,
+ 0x0f, 0x08, 0x0c, 0x08, 0xdd, 0x00, 0xd9, 0x00, 0xce, 0x00, 0xbe, 0x00,
+ 0xab, 0x00, 0x96, 0x00, 0x82, 0x00, 0x70, 0x00, 0x5f, 0x00, 0x50, 0x00,
+ 0x43, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x26, 0x00, 0x1f, 0x00, 0x18, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x06, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e,
+ 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x10,
+ 0x00, 0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06,
+ 0x00, 0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xba, 0x00,
+ 0xa4, 0x00, 0x8b, 0x00, 0x72, 0x00, 0x5a, 0x00, 0x44, 0x00, 0x2f, 0x00,
+ 0x29, 0x01, 0x23, 0x03, 0x1e, 0x04, 0x19, 0x05, 0x15, 0x06, 0x11, 0x07,
+ 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc4, 0x00, 0xb4, 0x00, 0xa2, 0x00,
+ 0x90, 0x00, 0x7e, 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x52, 0x00, 0x46, 0x00,
+ 0x3c, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x05, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x1e,
+ 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x0a,
+ 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x08,
+ 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdd, 0x00, 0xd9, 0x00, 0xd0, 0x00, 0xc0, 0x00, 0xad, 0x00, 0x98, 0x00,
+ 0x81, 0x00, 0x6b, 0x00, 0x56, 0x00, 0x42, 0x00, 0x2f, 0x00, 0x29, 0x01,
+ 0x24, 0x02, 0x1f, 0x04, 0x1b, 0x05, 0x17, 0x06, 0xdd, 0x00, 0xdb, 0x00,
+ 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xab, 0x00, 0x9b, 0x00, 0x8a, 0x00,
+ 0x7b, 0x00, 0x6c, 0x00, 0x5f, 0x00, 0x53, 0x00, 0x48, 0x00, 0x3f, 0x00,
+ 0x36, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05,
+ 0x00, 0x07, 0x00, 0x09, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b,
+ 0x00, 0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00,
+ 0xd2, 0x00, 0xc5, 0x00, 0xb5, 0x00, 0xa2, 0x00, 0x8e, 0x00, 0x79, 0x00,
+ 0x65, 0x00, 0x52, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x2a, 0x01, 0x25, 0x02,
+ 0x20, 0x03, 0x1c, 0x04, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc, 0x00,
+ 0xc0, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x95, 0x00, 0x86, 0x00, 0x78, 0x00,
+ 0x6b, 0x00, 0x5f, 0x00, 0x54, 0x00, 0x4a, 0x00, 0x41, 0x00, 0x39, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16,
+ 0x00, 0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9, 0x00,
+ 0xbb, 0x00, 0xaa, 0x00, 0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x60, 0x00,
+ 0x4f, 0x00, 0x3e, 0x00, 0x2f, 0x00, 0x2a, 0x01, 0x26, 0x02, 0x21, 0x03,
+ 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xcf, 0x00, 0xc4, 0x00, 0xb8, 0x00,
+ 0xab, 0x00, 0x9e, 0x00, 0x90, 0x00, 0x83, 0x00, 0x76, 0x00, 0x6a, 0x00,
+ 0x5f, 0x00, 0x55, 0x00, 0x4c, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x14, 0x00, 0x11,
+ 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb1, 0x00,
+ 0xa0, 0x00, 0x8f, 0x00, 0x7e, 0x00, 0x6d, 0x00, 0x5c, 0x00, 0x4c, 0x00,
+ 0x3d, 0x00, 0x2f, 0x00, 0x2b, 0x01, 0x26, 0x02, 0xde, 0x00, 0xdc, 0x00,
+ 0xd8, 0x00, 0xd1, 0x00, 0xc8, 0x00, 0xbd, 0x00, 0xb1, 0x00, 0xa5, 0x00,
+ 0x98, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5f, 0x00,
+ 0x56, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c,
+ 0x00, 0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d,
+ 0x00, 0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00,
+ 0xd7, 0x00, 0xce, 0x00, 0xc3, 0x00, 0xb6, 0x00, 0xa8, 0x00, 0x98, 0x00,
+ 0x88, 0x00, 0x78, 0x00, 0x68, 0x00, 0x59, 0x00, 0x4a, 0x00, 0x3c, 0x00,
+ 0x2f, 0x00, 0x2b, 0x01, 0xde, 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xd3, 0x00,
+ 0xcb, 0x00, 0xc1, 0x00, 0xb7, 0x00, 0xab, 0x00, 0xa0, 0x00, 0x94, 0x00,
+ 0x88, 0x00, 0x7d, 0x00, 0x73, 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19,
+ 0x00, 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x09,
+ 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd0, 0x00,
+ 0xc7, 0x00, 0xbb, 0x00, 0xae, 0x00, 0xa0, 0x00, 0x91, 0x00, 0x82, 0x00,
+ 0x73, 0x00, 0x64, 0x00, 0x56, 0x00, 0x48, 0x00, 0x3b, 0x00, 0x2f, 0x00,
+ 0xde, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd4, 0x00, 0xcd, 0x00, 0xc5, 0x00,
+ 0xbb, 0x00, 0xb1, 0x00, 0xa6, 0x00, 0x9b, 0x00, 0x90, 0x00, 0x85, 0x00,
+ 0x7b, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x6f, 0x00,
+ 0xb2, 0x00, 0xc8, 0x00, 0xd2, 0x00, 0xd6, 0x00, 0xd9, 0x00, 0xda, 0x00,
+ 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xde, 0x00, 0x4c, 0x04, 0x87, 0x00, 0xbc, 0x00, 0xcd, 0x00,
+ 0xd4, 0x00, 0xd8, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x76, 0x00,
+ 0x9b, 0x00, 0xac, 0x00, 0xbc, 0x00, 0xcd, 0x00, 0xd9, 0x00, 0xda, 0x00,
+ 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xde, 0x00, 0x61, 0x01, 0x9f, 0x00, 0xc5, 0x00, 0xd2, 0x00,
+ 0xd7, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00,
+ 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x6f, 0x00, 0xa2, 0x00,
+ 0xb9, 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7, 0x00,
+ 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc, 0x00,
+ 0x11, 0x09, 0x39, 0x01, 0x87, 0x00, 0xaf, 0x00, 0xc1, 0x00, 0xcb, 0x00,
+ 0xd1, 0x00, 0xd4, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00,
+ 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x5b, 0x00, 0x75, 0x00, 0x96, 0x00,
+ 0xab, 0x00, 0xc0, 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7, 0x00,
+ 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc, 0x00,
+ 0x23, 0x03, 0x5f, 0x00, 0x9f, 0x00, 0xbc, 0x00, 0xc9, 0x00, 0xd0, 0x00,
+ 0xd5, 0x00, 0xd7, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00,
+ 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x9c, 0x00,
+ 0xae, 0x00, 0xb9, 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf, 0x00,
+ 0xd1, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x01, 0x11, 0x0f, 0x07,
+ 0x32, 0x00, 0x6e, 0x00, 0x93, 0x00, 0xaa, 0x00, 0xb8, 0x00, 0xc1, 0x00,
+ 0xc8, 0x00, 0xcc, 0x00, 0xd0, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd6, 0x00,
+ 0xd7, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x00, 0x75, 0x00, 0x2b, 0x00, 0x5b, 0x00, 0x7f, 0x00, 0x9b, 0x00,
+ 0xae, 0x00, 0xb9, 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf, 0x00,
+ 0xd1, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x03, 0x09, 0x1f, 0x00,
+ 0x5f, 0x00, 0x8d, 0x00, 0xa8, 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xc9, 0x00,
+ 0xce, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00,
+ 0xd9, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97, 0x00,
+ 0xa5, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7, 0x00,
+ 0xca, 0x00, 0xcd, 0x00, 0x00, 0x17, 0x02, 0x0c, 0x19, 0x05, 0x31, 0x00,
+ 0x5f, 0x00, 0x7f, 0x00, 0x96, 0x00, 0xa6, 0x00, 0xb2, 0x00, 0xba, 0x00,
+ 0xc0, 0x00, 0xc5, 0x00, 0xc9, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xd0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x96, 0x00,
+ 0x5b, 0x00, 0x13, 0x00, 0x41, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97, 0x00,
+ 0xa5, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7, 0x00,
+ 0xca, 0x00, 0xcd, 0x00, 0x00, 0x13, 0x04, 0x01, 0x32, 0x00, 0x5f, 0x00,
+ 0x81, 0x00, 0x99, 0x00, 0xaa, 0x00, 0xb6, 0x00, 0xbe, 0x00, 0xc4, 0x00,
+ 0xc9, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x2f, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93, 0x00,
+ 0xa0, 0x00, 0xa9, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0, 0x00,
+ 0x00, 0x1b, 0x00, 0x12, 0x0b, 0x09, 0x1e, 0x04, 0x30, 0x00, 0x55, 0x00,
+ 0x71, 0x00, 0x87, 0x00, 0x97, 0x00, 0xa4, 0x00, 0xad, 0x00, 0xb5, 0x00,
+ 0xbb, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xab, 0x00, 0x7f, 0x00, 0x41, 0x00,
+ 0x03, 0x00, 0x2f, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93, 0x00,
+ 0xa0, 0x00, 0xa9, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0, 0x00,
+ 0x00, 0x18, 0x00, 0x0a, 0x16, 0x00, 0x3d, 0x00, 0x5f, 0x00, 0x7a, 0x00,
+ 0x8f, 0x00, 0x9f, 0x00, 0xab, 0x00, 0xb4, 0x00, 0xbb, 0x00, 0xc0, 0x00,
+ 0xc4, 0x00, 0xc8, 0x00, 0xcb, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x27, 0x00, 0x47, 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91, 0x00,
+ 0x9c, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x1c, 0x00, 0x17,
+ 0x03, 0x0b, 0x12, 0x07, 0x22, 0x03, 0x30, 0x00, 0x4e, 0x00, 0x67, 0x00,
+ 0x7b, 0x00, 0x8b, 0x00, 0x98, 0x00, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00,
+ 0xb6, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xcd, 0x00, 0xc0, 0x00, 0x9b, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x02, 0x00,
+ 0x27, 0x00, 0x47, 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91, 0x00,
+ 0x9c, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x1a, 0x00, 0x11,
+ 0x06, 0x00, 0x25, 0x00, 0x44, 0x00, 0x5f, 0x00, 0x76, 0x00, 0x88, 0x00,
+ 0x96, 0x00, 0xa2, 0x00, 0xab, 0x00, 0xb2, 0x00, 0xb8, 0x00, 0xbd, 0x00,
+ 0xc1, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00,
+ 0x3d, 0x00, 0x55, 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00,
+ 0x99, 0x00, 0xa0, 0x00, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x0e, 0x0a, 0x09,
+ 0x17, 0x06, 0x24, 0x02, 0x30, 0x00, 0x4a, 0x00, 0x60, 0x00, 0x72, 0x00,
+ 0x81, 0x00, 0x8e, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa8, 0x00, 0xae, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x00, 0xcd, 0x00,
+ 0xae, 0x00, 0x82, 0x00, 0x54, 0x00, 0x27, 0x00, 0x01, 0x00, 0x21, 0x00,
+ 0x3d, 0x00, 0x55, 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00,
+ 0x99, 0x00, 0xa0, 0x00, 0x00, 0x1c, 0x00, 0x15, 0x00, 0x03, 0x14, 0x00,
+ 0x2f, 0x00, 0x49, 0x00, 0x5f, 0x00, 0x72, 0x00, 0x82, 0x00, 0x90, 0x00,
+ 0x9b, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbb, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x36, 0x00,
+ 0x4b, 0x00, 0x5d, 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e, 0x00,
+ 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x04, 0x0a, 0x0f, 0x07, 0x1b, 0x05,
+ 0x26, 0x02, 0x30, 0x00, 0x46, 0x00, 0x5a, 0x00, 0x6b, 0x00, 0x79, 0x00,
+ 0x85, 0x00, 0x8f, 0x00, 0x98, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97, 0x00,
+ 0x6f, 0x00, 0x47, 0x00, 0x21, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x36, 0x00,
+ 0x4b, 0x00, 0x5d, 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e, 0x00,
+ 0x00, 0x1d, 0x00, 0x18, 0x00, 0x0a, 0x09, 0x00, 0x1f, 0x00, 0x36, 0x00,
+ 0x4c, 0x00, 0x5f, 0x00, 0x70, 0x00, 0x7e, 0x00, 0x8a, 0x00, 0x95, 0x00,
+ 0x9e, 0x00, 0xa5, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44, 0x00,
+ 0x55, 0x00, 0x64, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x00, 0x1e, 0x00, 0x1c,
+ 0x00, 0x15, 0x00, 0x0b, 0x0a, 0x09, 0x14, 0x06, 0x1e, 0x04, 0x27, 0x02,
+ 0x30, 0x00, 0x44, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x7e, 0x00,
+ 0x88, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdb, 0x00, 0xd4, 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60, 0x00,
+ 0x3d, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44, 0x00,
+ 0x55, 0x00, 0x64, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x00, 0x1d, 0x00, 0x1a,
+ 0x00, 0x0f, 0x00, 0x00, 0x14, 0x00, 0x28, 0x00, 0x3c, 0x00, 0x4e, 0x00,
+ 0x5f, 0x00, 0x6e, 0x00, 0x7b, 0x00, 0x86, 0x00, 0x90, 0x00, 0x98, 0x00,
+ 0xa0, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e, 0x00,
+ 0x5c, 0x00, 0x68, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x17, 0x00, 0x0f,
+ 0x05, 0x0a, 0x0e, 0x08, 0x17, 0x06, 0x20, 0x03, 0x28, 0x01, 0x2f, 0x00,
+ 0x42, 0x00, 0x52, 0x00, 0x60, 0x00, 0x6d, 0x00, 0x78, 0x00, 0x82, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00,
+ 0xc7, 0x00, 0xb0, 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e, 0x00,
+ 0x5c, 0x00, 0x68, 0x00, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x05,
+ 0x0b, 0x00, 0x1c, 0x00, 0x2f, 0x00, 0x40, 0x00, 0x50, 0x00, 0x5f, 0x00,
+ 0x6c, 0x00, 0x78, 0x00, 0x83, 0x00, 0x8c, 0x00, 0x94, 0x00, 0x9b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x15, 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55, 0x00,
+ 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x02, 0x0b, 0x09, 0x09,
+ 0x12, 0x07, 0x1a, 0x05, 0x21, 0x03, 0x29, 0x01, 0x2f, 0x00, 0x40, 0x00,
+ 0x4f, 0x00, 0x5c, 0x00, 0x68, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8, 0x00,
+ 0xa0, 0x00, 0x84, 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17, 0x00,
+ 0x00, 0x00, 0x15, 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55, 0x00,
+ 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x09, 0x04, 0x00, 0x13, 0x00,
+ 0x24, 0x00, 0x34, 0x00, 0x43, 0x00, 0x52, 0x00, 0x5f, 0x00, 0x6b, 0x00,
+ 0x76, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x42, 0x00, 0x00, 0x1f, 0x00, 0x1d,
+ 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x06, 0x0a, 0x0d, 0x08, 0x14, 0x06,
+ 0x1c, 0x04, 0x23, 0x03, 0x29, 0x01, 0x2f, 0x00, 0x3e, 0x00, 0x4c, 0x00,
+ 0x59, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdd, 0x00, 0xd9, 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91, 0x00,
+ 0x78, 0x00, 0x5d, 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00, 0x00,
+ 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x42, 0x00, 0x00, 0x1e, 0x00, 0x1c,
+ 0x00, 0x16, 0x00, 0x0d, 0x00, 0x01, 0x0c, 0x00, 0x1b, 0x00, 0x29, 0x00,
+ 0x38, 0x00, 0x46, 0x00, 0x53, 0x00, 0x5f, 0x00, 0x6a, 0x00, 0x74, 0x00,
+ 0x7d, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00,
+ 0x22, 0x00, 0x30, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x16,
+ 0x00, 0x0f, 0x03, 0x0b, 0x09, 0x09, 0x10, 0x07, 0x17, 0x06, 0x1e, 0x04,
+ 0x24, 0x02, 0x2a, 0x01, 0x2f, 0x00, 0x3d, 0x00, 0x4a, 0x00, 0x56, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00,
+ 0xd1, 0x00, 0xc3, 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d, 0x00,
+ 0x55, 0x00, 0x3e, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x11, 0x00,
+ 0x22, 0x00, 0x30, 0x00, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x10,
+ 0x00, 0x05, 0x06, 0x00, 0x13, 0x00, 0x21, 0x00, 0x2e, 0x00, 0x3c, 0x00,
+ 0x48, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x73, 0x00, 0x7b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00, 0x11, 0x00, 0x0b,
+ 0x06, 0x0a, 0x0c, 0x08, 0x13, 0x07, 0x19, 0x05, 0x1f, 0x04, 0x25, 0x02,
+ 0x2a, 0x01, 0x2f, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7, 0x00,
+ 0xb7, 0x00, 0xa4, 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00,
+ 0x39, 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
+ 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00, 0x09, 0x01, 0x00,
+ 0x0d, 0x00, 0x19, 0x00, 0x26, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4a, 0x00,
+ 0x55, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x1f, 0x00, 0x1e,
+ 0x00, 0x1c, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x04, 0x0a, 0x09, 0x09,
+ 0x0f, 0x08, 0x15, 0x06, 0x1b, 0x05, 0x20, 0x03, 0x26, 0x02, 0x2b, 0x01,
+ 0x2f, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdd, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab, 0x00,
+ 0x99, 0x00, 0x85, 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34, 0x00,
+ 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x1f, 0x00, 0x1d,
+ 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x02, 0x08, 0x00, 0x13, 0x00,
+ 0x1f, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x56, 0x00,
+ 0x5f, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19,
+ 0x00, 0x15, 0x00, 0x0f, 0x01, 0x0b, 0x07, 0x0a, 0x0c, 0x08, 0x11, 0x07,
+ 0x17, 0x06, 0x1c, 0x04, 0x21, 0x03, 0x26, 0x02, 0x2b, 0x01, 0x2f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00,
+ 0xd6, 0x00, 0xcd, 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e, 0x00,
+ 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15,
+ 0x00, 0x0e, 0x00, 0x05, 0x03, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x23, 0x00,
+ 0x2e, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x56, 0x00, 0x5f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x61, 0x01, 0x9f, 0x00, 0xc5, 0x00, 0xd2, 0x00, 0xd7, 0x00, 0xda, 0x00,
+ 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde, 0x00,
+ 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x61, 0x01, 0x23, 0x03, 0x03, 0x09, 0x00, 0x13,
+ 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e,
+ 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x03, 0x5f, 0x00,
+ 0x9f, 0x00, 0xbc, 0x00, 0xc9, 0x00, 0xd0, 0x00, 0xd5, 0x00, 0xd7, 0x00,
+ 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc, 0x00,
+ 0xdd, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9f, 0x00, 0x5f, 0x00, 0x1f, 0x00, 0x04, 0x01, 0x00, 0x0a, 0x00, 0x11,
+ 0x00, 0x15, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c,
+ 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x09, 0x1f, 0x00, 0x5f, 0x00, 0x8d, 0x00,
+ 0xa8, 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xc9, 0x00, 0xce, 0x00, 0xd1, 0x00,
+ 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x9f, 0x00,
+ 0x5f, 0x00, 0x32, 0x00, 0x16, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0a,
+ 0x00, 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19,
+ 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x13, 0x04, 0x01, 0x32, 0x00, 0x5f, 0x00, 0x81, 0x00, 0x99, 0x00,
+ 0xaa, 0x00, 0xb6, 0x00, 0xbe, 0x00, 0xc4, 0x00, 0xc9, 0x00, 0xcc, 0x00,
+ 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xbc, 0x00, 0x8d, 0x00, 0x5f, 0x00,
+ 0x3d, 0x00, 0x25, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x09, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x15,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x0a,
+ 0x16, 0x00, 0x3d, 0x00, 0x5f, 0x00, 0x7a, 0x00, 0x8f, 0x00, 0x9f, 0x00,
+ 0xab, 0x00, 0xb4, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc4, 0x00, 0xc8, 0x00,
+ 0xcb, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xd7, 0x00, 0xc9, 0x00, 0xa8, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x44, 0x00,
+ 0x2f, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x01,
+ 0x00, 0x05, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x11, 0x06, 0x00, 0x25, 0x00,
+ 0x44, 0x00, 0x5f, 0x00, 0x76, 0x00, 0x88, 0x00, 0x96, 0x00, 0xa2, 0x00,
+ 0xab, 0x00, 0xb2, 0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc1, 0x00, 0xc5, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd0, 0x00,
+ 0xb8, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x36, 0x00,
+ 0x28, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x01, 0x00,
+ 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1c, 0x00, 0x15, 0x00, 0x03, 0x14, 0x00, 0x2f, 0x00, 0x49, 0x00,
+ 0x5f, 0x00, 0x72, 0x00, 0x82, 0x00, 0x90, 0x00, 0x9b, 0x00, 0xa4, 0x00,
+ 0xab, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xc3, 0x00, 0xaa, 0x00,
+ 0x8f, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2f, 0x00,
+ 0x24, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x18,
+ 0x00, 0x0a, 0x09, 0x00, 0x1f, 0x00, 0x36, 0x00, 0x4c, 0x00, 0x5f, 0x00,
+ 0x70, 0x00, 0x7e, 0x00, 0x8a, 0x00, 0x95, 0x00, 0x9e, 0x00, 0xa5, 0x00,
+ 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdc, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xb6, 0x00, 0x9f, 0x00, 0x88, 0x00,
+ 0x72, 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00,
+ 0x21, 0x00, 0x19, 0x00, 0x13, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x00,
+ 0x14, 0x00, 0x28, 0x00, 0x3c, 0x00, 0x4e, 0x00, 0x5f, 0x00, 0x6e, 0x00,
+ 0x7b, 0x00, 0x86, 0x00, 0x90, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa6, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xd9, 0x00,
+ 0xce, 0x00, 0xbe, 0x00, 0xab, 0x00, 0x96, 0x00, 0x82, 0x00, 0x70, 0x00,
+ 0x5f, 0x00, 0x50, 0x00, 0x43, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x26, 0x00,
+ 0x1f, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x05, 0x0b, 0x00, 0x1c, 0x00,
+ 0x2f, 0x00, 0x40, 0x00, 0x50, 0x00, 0x5f, 0x00, 0x6c, 0x00, 0x78, 0x00,
+ 0x83, 0x00, 0x8c, 0x00, 0x94, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc4, 0x00,
+ 0xb4, 0x00, 0xa2, 0x00, 0x90, 0x00, 0x7e, 0x00, 0x6e, 0x00, 0x5f, 0x00,
+ 0x52, 0x00, 0x46, 0x00, 0x3c, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x23, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c,
+ 0x00, 0x14, 0x00, 0x09, 0x04, 0x00, 0x13, 0x00, 0x24, 0x00, 0x34, 0x00,
+ 0x43, 0x00, 0x52, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x76, 0x00, 0x80, 0x00,
+ 0x88, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xab, 0x00,
+ 0x9b, 0x00, 0x8a, 0x00, 0x7b, 0x00, 0x6c, 0x00, 0x5f, 0x00, 0x53, 0x00,
+ 0x48, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x16, 0x00, 0x0d,
+ 0x00, 0x01, 0x0c, 0x00, 0x1b, 0x00, 0x29, 0x00, 0x38, 0x00, 0x46, 0x00,
+ 0x53, 0x00, 0x5f, 0x00, 0x6a, 0x00, 0x74, 0x00, 0x7d, 0x00, 0x85, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00,
+ 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x95, 0x00,
+ 0x86, 0x00, 0x78, 0x00, 0x6b, 0x00, 0x5f, 0x00, 0x54, 0x00, 0x4a, 0x00,
+ 0x41, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x10, 0x00, 0x05, 0x06, 0x00,
+ 0x13, 0x00, 0x21, 0x00, 0x2e, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x54, 0x00,
+ 0x5f, 0x00, 0x69, 0x00, 0x73, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xcf, 0x00,
+ 0xc4, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x9e, 0x00, 0x90, 0x00, 0x83, 0x00,
+ 0x76, 0x00, 0x6a, 0x00, 0x5f, 0x00, 0x55, 0x00, 0x4c, 0x00, 0x43, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d,
+ 0x00, 0x19, 0x00, 0x12, 0x00, 0x09, 0x01, 0x00, 0x0d, 0x00, 0x19, 0x00,
+ 0x26, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x55, 0x00, 0x5f, 0x00,
+ 0x69, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd1, 0x00, 0xc8, 0x00, 0xbd, 0x00,
+ 0xb1, 0x00, 0xa5, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x74, 0x00,
+ 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x14,
+ 0x00, 0x0c, 0x00, 0x02, 0x08, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00,
+ 0x36, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5f, 0x00, 0x68, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd, 0x00,
+ 0xd9, 0x00, 0xd3, 0x00, 0xcb, 0x00, 0xc1, 0x00, 0xb7, 0x00, 0xab, 0x00,
+ 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7d, 0x00, 0x73, 0x00, 0x69, 0x00,
+ 0x5f, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15, 0x00, 0x0e, 0x00, 0x05,
+ 0x03, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x23, 0x00, 0x2e, 0x00, 0x39, 0x00,
+ 0x43, 0x00, 0x4d, 0x00, 0x56, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd4, 0x00,
+ 0xcd, 0x00, 0xc5, 0x00, 0xbb, 0x00, 0xb1, 0x00, 0xa6, 0x00, 0x9b, 0x00,
+ 0x90, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xb2, 0x00, 0x6f, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0xa2,
+ 0x00, 0x4f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x7f, 0x00, 0x3c,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1a, 0x00,
+ 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd6, 0x00, 0xc6, 0x00, 0x9c, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x16, 0x00, 0x0e, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x00, 0xcd,
+ 0x00, 0xae, 0x00, 0x82, 0x00, 0x54, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x05, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97,
+ 0x00, 0x6f, 0x00, 0x47, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
+ 0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60,
+ 0x00, 0x3d, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00,
+ 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7,
+ 0x00, 0xc7, 0x00, 0xb0, 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36,
+ 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x10, 0x00,
+ 0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8,
+ 0x00, 0xa0, 0x00, 0x84, 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
+ 0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x0a, 0x00,
+ 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91,
+ 0x00, 0x78, 0x00, 0x5d, 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00,
+ 0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda,
+ 0x00, 0xd1, 0x00, 0xc3, 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d,
+ 0x00, 0x55, 0x00, 0x3e, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16, 0x00,
+ 0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7,
+ 0x00, 0xb7, 0x00, 0xa4, 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e,
+ 0x00, 0x39, 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x14, 0x00, 0x11, 0x00,
+ 0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab,
+ 0x00, 0x99, 0x00, 0x85, 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34,
+ 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00,
+ 0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0x00,
+ 0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc,
+ 0x00, 0xd6, 0x00, 0xcd, 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e,
+ 0x00, 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f,
+ 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00,
+ 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x09, 0x00,
+ 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x6f,
+ 0x00, 0xb2, 0x00, 0xc8, 0x00, 0xd2, 0x00, 0xd6, 0x00, 0xd9, 0x00, 0xda,
+ 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xde, 0x00, 0xa6, 0x00, 0x76, 0x00, 0x9b, 0x00, 0xac,
+ 0x00, 0xbc, 0x00, 0xcd, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc,
+ 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x4c, 0x00, 0x87,
+ 0x00, 0xbc, 0x00, 0xcd, 0x00, 0xd4, 0x00, 0xd8, 0x00, 0xda, 0x00, 0xdb,
+ 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde,
+ 0x00, 0xde, 0x00, 0xde, 0x01, 0x61, 0x00, 0x9f, 0x00, 0xc5, 0x00, 0xd2,
+ 0x00, 0xd7, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x6f, 0x00, 0xa2,
+ 0x00, 0xb9, 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7,
+ 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc,
+ 0x00, 0x76, 0x00, 0x5b, 0x00, 0x75, 0x00, 0x96, 0x00, 0xab, 0x00, 0xc0,
+ 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9,
+ 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x11, 0x01, 0x39, 0x00, 0x87, 0x00, 0xaf,
+ 0x00, 0xc1, 0x00, 0xcb, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd7, 0x00, 0xd8,
+ 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc,
+ 0x03, 0x23, 0x00, 0x5f, 0x00, 0x9f, 0x00, 0xbc, 0x00, 0xc9, 0x00, 0xd0,
+ 0x00, 0xd5, 0x00, 0xd7, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc,
+ 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x9c,
+ 0x00, 0xae, 0x00, 0xb9, 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf,
+ 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x9b, 0x00, 0x75,
+ 0x00, 0x2b, 0x00, 0x5b, 0x00, 0x7f, 0x00, 0x9b, 0x00, 0xae, 0x00, 0xb9,
+ 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3,
+ 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x01, 0x07, 0x0f, 0x00, 0x32, 0x00, 0x6e, 0x00, 0x93, 0x00, 0xaa,
+ 0x00, 0xb8, 0x00, 0xc1, 0x00, 0xc8, 0x00, 0xcc, 0x00, 0xd0, 0x00, 0xd2,
+ 0x00, 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x09, 0x03, 0x00, 0x1f,
+ 0x00, 0x5f, 0x00, 0x8d, 0x00, 0xa8, 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xc9,
+ 0x00, 0xce, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8,
+ 0x00, 0xd9, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97,
+ 0x00, 0xa5, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7,
+ 0x00, 0xca, 0x00, 0xcd, 0x00, 0xac, 0x00, 0x96, 0x00, 0x5b, 0x00, 0x13,
+ 0x00, 0x41, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97, 0x00, 0xa5, 0x00, 0xb0,
+ 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7, 0x00, 0xca, 0x00, 0xcd,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x0c, 0x02,
+ 0x05, 0x19, 0x00, 0x31, 0x00, 0x5f, 0x00, 0x7f, 0x00, 0x96, 0x00, 0xa6,
+ 0x00, 0xb2, 0x00, 0xba, 0x00, 0xc0, 0x00, 0xc5, 0x00, 0xc9, 0x00, 0xcc,
+ 0x00, 0xce, 0x00, 0xd0, 0x13, 0x00, 0x01, 0x04, 0x00, 0x32, 0x00, 0x5f,
+ 0x00, 0x81, 0x00, 0x99, 0x00, 0xaa, 0x00, 0xb6, 0x00, 0xbe, 0x00, 0xc4,
+ 0x00, 0xc9, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x2f, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93,
+ 0x00, 0xa0, 0x00, 0xa9, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0,
+ 0x00, 0xbc, 0x00, 0xab, 0x00, 0x7f, 0x00, 0x41, 0x00, 0x03, 0x00, 0x2f,
+ 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93, 0x00, 0xa0, 0x00, 0xa9,
+ 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x09, 0x0b, 0x04, 0x1e,
+ 0x00, 0x30, 0x00, 0x55, 0x00, 0x71, 0x00, 0x87, 0x00, 0x97, 0x00, 0xa4,
+ 0x00, 0xad, 0x00, 0xb5, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc7,
+ 0x18, 0x00, 0x0a, 0x00, 0x00, 0x16, 0x00, 0x3d, 0x00, 0x5f, 0x00, 0x7a,
+ 0x00, 0x8f, 0x00, 0x9f, 0x00, 0xab, 0x00, 0xb4, 0x00, 0xbb, 0x00, 0xc0,
+ 0x00, 0xc4, 0x00, 0xc8, 0x00, 0xcb, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x27, 0x00, 0x47, 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91,
+ 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0xcd, 0x00, 0xc0,
+ 0x00, 0x9b, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x02, 0x00, 0x27, 0x00, 0x47,
+ 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91, 0x00, 0x9c, 0x00, 0xa4,
+ 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x17, 0x00, 0x0b, 0x03, 0x07, 0x12, 0x03, 0x22, 0x00, 0x30,
+ 0x00, 0x4e, 0x00, 0x67, 0x00, 0x7b, 0x00, 0x8b, 0x00, 0x98, 0x00, 0xa2,
+ 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb6, 0x00, 0xbb, 0x1a, 0x00, 0x11, 0x00,
+ 0x00, 0x06, 0x00, 0x25, 0x00, 0x44, 0x00, 0x5f, 0x00, 0x76, 0x00, 0x88,
+ 0x00, 0x96, 0x00, 0xa2, 0x00, 0xab, 0x00, 0xb2, 0x00, 0xb8, 0x00, 0xbd,
+ 0x00, 0xc1, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21,
+ 0x00, 0x3d, 0x00, 0x55, 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90,
+ 0x00, 0x99, 0x00, 0xa0, 0x00, 0xd9, 0x00, 0xcd, 0x00, 0xae, 0x00, 0x82,
+ 0x00, 0x54, 0x00, 0x27, 0x00, 0x01, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x55,
+ 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00, 0x99, 0x00, 0xa0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x19, 0x00,
+ 0x0e, 0x00, 0x09, 0x0a, 0x06, 0x17, 0x02, 0x24, 0x00, 0x30, 0x00, 0x4a,
+ 0x00, 0x60, 0x00, 0x72, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x98, 0x00, 0xa0,
+ 0x00, 0xa8, 0x00, 0xae, 0x1c, 0x00, 0x15, 0x00, 0x03, 0x00, 0x00, 0x14,
+ 0x00, 0x2f, 0x00, 0x49, 0x00, 0x5f, 0x00, 0x72, 0x00, 0x82, 0x00, 0x90,
+ 0x00, 0x9b, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbb,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x36,
+ 0x00, 0x4b, 0x00, 0x5d, 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e,
+ 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97, 0x00, 0x6f, 0x00, 0x47,
+ 0x00, 0x21, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x36, 0x00, 0x4b, 0x00, 0x5d,
+ 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x0a, 0x04,
+ 0x07, 0x0f, 0x05, 0x1b, 0x02, 0x26, 0x00, 0x30, 0x00, 0x46, 0x00, 0x5a,
+ 0x00, 0x6b, 0x00, 0x79, 0x00, 0x85, 0x00, 0x8f, 0x00, 0x98, 0x00, 0xa0,
+ 0x1d, 0x00, 0x18, 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x1f, 0x00, 0x36,
+ 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x70, 0x00, 0x7e, 0x00, 0x8a, 0x00, 0x95,
+ 0x00, 0x9e, 0x00, 0xa5, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44,
+ 0x00, 0x55, 0x00, 0x64, 0x00, 0x70, 0x00, 0x7b, 0x00, 0xdb, 0x00, 0xd4,
+ 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60, 0x00, 0x3d, 0x00, 0x1d,
+ 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44, 0x00, 0x55, 0x00, 0x64,
+ 0x00, 0x70, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1e, 0x00, 0x1c, 0x00, 0x15, 0x00, 0x0b, 0x00, 0x09, 0x0a, 0x06, 0x14,
+ 0x04, 0x1e, 0x02, 0x27, 0x00, 0x30, 0x00, 0x44, 0x00, 0x56, 0x00, 0x65,
+ 0x00, 0x72, 0x00, 0x7e, 0x00, 0x88, 0x00, 0x91, 0x1d, 0x00, 0x1a, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x28, 0x00, 0x3c, 0x00, 0x4e,
+ 0x00, 0x5f, 0x00, 0x6e, 0x00, 0x7b, 0x00, 0x86, 0x00, 0x90, 0x00, 0x98,
+ 0x00, 0xa0, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e,
+ 0x00, 0x5c, 0x00, 0x68, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc7, 0x00, 0xb0,
+ 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36, 0x00, 0x19, 0x00, 0x00,
+ 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e, 0x00, 0x5c, 0x00, 0x68,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00,
+ 0x17, 0x00, 0x0f, 0x00, 0x0a, 0x05, 0x08, 0x0e, 0x06, 0x17, 0x03, 0x20,
+ 0x01, 0x28, 0x00, 0x2f, 0x00, 0x42, 0x00, 0x52, 0x00, 0x60, 0x00, 0x6d,
+ 0x00, 0x78, 0x00, 0x82, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x05, 0x00,
+ 0x00, 0x0b, 0x00, 0x1c, 0x00, 0x2f, 0x00, 0x40, 0x00, 0x50, 0x00, 0x5f,
+ 0x00, 0x6c, 0x00, 0x78, 0x00, 0x83, 0x00, 0x8c, 0x00, 0x94, 0x00, 0x9b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x15, 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55,
+ 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8, 0x00, 0xa0, 0x00, 0x84,
+ 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17, 0x00, 0x00, 0x00, 0x15,
+ 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00,
+ 0x0b, 0x02, 0x09, 0x09, 0x07, 0x12, 0x05, 0x1a, 0x03, 0x21, 0x01, 0x29,
+ 0x00, 0x2f, 0x00, 0x40, 0x00, 0x4f, 0x00, 0x5c, 0x00, 0x68, 0x00, 0x73,
+ 0x1e, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x04, 0x00, 0x13,
+ 0x00, 0x24, 0x00, 0x34, 0x00, 0x43, 0x00, 0x52, 0x00, 0x5f, 0x00, 0x6b,
+ 0x00, 0x76, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x42, 0x00, 0xdd, 0x00, 0xd9,
+ 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91, 0x00, 0x78, 0x00, 0x5d,
+ 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x24,
+ 0x00, 0x34, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x0a, 0x06,
+ 0x08, 0x0d, 0x06, 0x14, 0x04, 0x1c, 0x03, 0x23, 0x01, 0x29, 0x00, 0x2f,
+ 0x00, 0x3e, 0x00, 0x4c, 0x00, 0x59, 0x00, 0x64, 0x1e, 0x00, 0x1c, 0x00,
+ 0x16, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x29,
+ 0x00, 0x38, 0x00, 0x46, 0x00, 0x53, 0x00, 0x5f, 0x00, 0x6a, 0x00, 0x74,
+ 0x00, 0x7d, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x00, 0x22, 0x00, 0x30, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc3,
+ 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d, 0x00, 0x55, 0x00, 0x3e,
+ 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x30,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
+ 0x1b, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x0b, 0x03, 0x09, 0x09, 0x07, 0x10,
+ 0x06, 0x17, 0x04, 0x1e, 0x02, 0x24, 0x01, 0x2a, 0x00, 0x2f, 0x00, 0x3d,
+ 0x00, 0x4a, 0x00, 0x56, 0x1e, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x10, 0x00,
+ 0x05, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x21, 0x00, 0x2e, 0x00, 0x3c,
+ 0x00, 0x48, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x73, 0x00, 0x7b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
+ 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7, 0x00, 0xb7, 0x00, 0xa4,
+ 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00, 0x39, 0x00, 0x24,
+ 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00,
+ 0x11, 0x00, 0x0b, 0x00, 0x0a, 0x06, 0x08, 0x0c, 0x07, 0x13, 0x05, 0x19,
+ 0x04, 0x1f, 0x02, 0x25, 0x01, 0x2a, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x48,
+ 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x01,
+ 0x00, 0x0d, 0x00, 0x19, 0x00, 0x26, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4a,
+ 0x00, 0x55, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xdd, 0x00, 0xdb,
+ 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab, 0x00, 0x99, 0x00, 0x85,
+ 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34, 0x00, 0x22, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00,
+ 0x0a, 0x04, 0x09, 0x09, 0x08, 0x0f, 0x06, 0x15, 0x05, 0x1b, 0x03, 0x20,
+ 0x02, 0x26, 0x01, 0x2b, 0x00, 0x2f, 0x00, 0x3b, 0x1f, 0x00, 0x1d, 0x00,
+ 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x08, 0x00, 0x13,
+ 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x56,
+ 0x00, 0x5f, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcd,
+ 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e, 0x00, 0x7b, 0x00, 0x68,
+ 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
+ 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0b, 0x01, 0x0a, 0x07,
+ 0x08, 0x0c, 0x07, 0x11, 0x06, 0x17, 0x04, 0x1c, 0x03, 0x21, 0x02, 0x26,
+ 0x01, 0x2b, 0x00, 0x2f, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15, 0x00,
+ 0x0e, 0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x23,
+ 0x00, 0x2e, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x56, 0x00, 0x5f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x1e, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x04, 0x4c, 0x09, 0x11,
+ 0x11, 0x01, 0x17, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00,
+ 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x24, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x01, 0x61, 0x03, 0x23,
+ 0x09, 0x03, 0x13, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00,
+ 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x0f, 0x00, 0x17, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00,
+ 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x87, 0x01, 0x39, 0x07, 0x0f, 0x0c, 0x02,
+ 0x12, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00,
+ 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x21, 0x00,
+ 0x27, 0x00, 0x2b, 0x00, 0x28, 0x00, 0x21, 0x00, 0x1d, 0x00, 0x1e, 0x00,
+ 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x1f, 0x01, 0x04,
+ 0x0a, 0x00, 0x11, 0x00, 0x15, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00,
+ 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x12, 0x00, 0x16, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00,
+ 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00,
+ 0x00, 0xbc, 0x00, 0x87, 0x00, 0x32, 0x05, 0x19, 0x09, 0x0b, 0x0b, 0x03,
+ 0x0e, 0x00, 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00,
+ 0x1b, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x27, 0x00, 0x0f, 0x00, 0x1a, 0x00,
+ 0x1c, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00,
+ 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00,
+ 0x00, 0xc5, 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x32, 0x00, 0x16, 0x00, 0x06,
+ 0x03, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00,
+ 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0e, 0x00,
+ 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00,
+ 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x00, 0xcd, 0x00, 0xaf,
+ 0x00, 0x6e, 0x00, 0x31, 0x04, 0x1e, 0x07, 0x12, 0x09, 0x0a, 0x0a, 0x04,
+ 0x0b, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00,
+ 0x18, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x32, 0x00, 0x2b, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x0e, 0x00,
+ 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00,
+ 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x00, 0xd2, 0x00, 0xbc,
+ 0x00, 0x8d, 0x00, 0x5f, 0x00, 0x3d, 0x00, 0x25, 0x00, 0x14, 0x00, 0x09,
+ 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00,
+ 0x14, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x0f, 0x00,
+ 0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00,
+ 0x1a, 0x00, 0x1b, 0x00, 0x00, 0xd4, 0x00, 0xc1, 0x00, 0x93, 0x00, 0x5f,
+ 0x00, 0x30, 0x03, 0x22, 0x06, 0x17, 0x07, 0x0f, 0x09, 0x0a, 0x0a, 0x05,
+ 0x0b, 0x02, 0x0c, 0x00, 0x0f, 0x00, 0x11, 0x00, 0x13, 0x00, 0x15, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x28, 0x00,
+ 0x1c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x0f, 0x00,
+ 0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00,
+ 0x1a, 0x00, 0x1b, 0x00, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xa8, 0x00, 0x81,
+ 0x00, 0x5f, 0x00, 0x44, 0x00, 0x2f, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0b,
+ 0x00, 0x04, 0x01, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10, 0x00,
+ 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00,
+ 0x00, 0xd8, 0x00, 0xcb, 0x00, 0xaa, 0x00, 0x7f, 0x00, 0x55, 0x00, 0x30,
+ 0x02, 0x24, 0x05, 0x1b, 0x06, 0x14, 0x08, 0x0e, 0x09, 0x09, 0x0a, 0x06,
+ 0x0b, 0x03, 0x0b, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0e, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10, 0x00,
+ 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00,
+ 0x00, 0xda, 0x00, 0xd0, 0x00, 0xb8, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5f,
+ 0x00, 0x49, 0x00, 0x36, 0x00, 0x28, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0c,
+ 0x00, 0x06, 0x00, 0x01, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x11, 0x00,
+ 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0xda, 0x00, 0xd1,
+ 0x00, 0xb8, 0x00, 0x96, 0x00, 0x71, 0x00, 0x4e, 0x00, 0x30, 0x02, 0x26,
+ 0x04, 0x1e, 0x06, 0x17, 0x07, 0x12, 0x08, 0x0d, 0x09, 0x09, 0x0a, 0x06,
+ 0x0a, 0x04, 0x0b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x05, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x11, 0x00,
+ 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0xdb, 0x00, 0xd5,
+ 0x00, 0xc3, 0x00, 0xaa, 0x00, 0x8f, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x4c,
+ 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x0d,
+ 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x11, 0x00,
+ 0x13, 0x00, 0x14, 0x00, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc1, 0x00, 0xa6,
+ 0x00, 0x87, 0x00, 0x67, 0x00, 0x4a, 0x00, 0x30, 0x02, 0x27, 0x03, 0x20,
+ 0x05, 0x1a, 0x06, 0x14, 0x07, 0x10, 0x08, 0x0c, 0x09, 0x09, 0x0a, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
+ 0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x11, 0x00,
+ 0x13, 0x00, 0x14, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xb6,
+ 0x00, 0x9f, 0x00, 0x88, 0x00, 0x72, 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x40,
+ 0x00, 0x34, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00, 0x13, 0x00, 0x0e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x11, 0x00,
+ 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc8, 0x00, 0xb2, 0x00, 0x97, 0x00, 0x7b,
+ 0x00, 0x60, 0x00, 0x46, 0x00, 0x30, 0x01, 0x28, 0x03, 0x21, 0x04, 0x1c,
+ 0x06, 0x17, 0x07, 0x13, 0x08, 0x0f, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00,
+ 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x11, 0x00,
+ 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xce, 0x00, 0xbe, 0x00, 0xab, 0x00, 0x96,
+ 0x00, 0x82, 0x00, 0x70, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x43, 0x00, 0x38,
+ 0x00, 0x2e, 0x00, 0x26, 0x00, 0x1f, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00,
+ 0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x00, 0xdc, 0x00, 0xd8,
+ 0x00, 0xcc, 0x00, 0xba, 0x00, 0xa4, 0x00, 0x8b, 0x00, 0x72, 0x00, 0x5a,
+ 0x00, 0x44, 0x00, 0x2f, 0x01, 0x29, 0x03, 0x23, 0x04, 0x1e, 0x05, 0x19,
+ 0x06, 0x15, 0x07, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x10, 0x00,
+ 0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00,
+ 0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x00, 0xdd, 0x00, 0xda,
+ 0x00, 0xd1, 0x00, 0xc4, 0x00, 0xb4, 0x00, 0xa2, 0x00, 0x90, 0x00, 0x7e,
+ 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x52, 0x00, 0x46, 0x00, 0x3c, 0x00, 0x32,
+ 0x00, 0x2a, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x08, 0x00,
+ 0x0a, 0x00, 0x0c, 0x00, 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xd0, 0x00, 0xc0,
+ 0x00, 0xad, 0x00, 0x98, 0x00, 0x81, 0x00, 0x6b, 0x00, 0x56, 0x00, 0x42,
+ 0x00, 0x2f, 0x01, 0x29, 0x02, 0x24, 0x04, 0x1f, 0x05, 0x1b, 0x06, 0x17,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
+ 0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x0a, 0x00,
+ 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x08, 0x00,
+ 0x0a, 0x00, 0x0c, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9,
+ 0x00, 0xbb, 0x00, 0xab, 0x00, 0x9b, 0x00, 0x8a, 0x00, 0x7b, 0x00, 0x6c,
+ 0x00, 0x5f, 0x00, 0x53, 0x00, 0x48, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09, 0x00,
+ 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xc5, 0x00, 0xb5, 0x00, 0xa2,
+ 0x00, 0x8e, 0x00, 0x79, 0x00, 0x65, 0x00, 0x52, 0x00, 0x40, 0x00, 0x2f,
+ 0x01, 0x2a, 0x02, 0x25, 0x03, 0x20, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00,
+ 0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09, 0x00,
+ 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb2,
+ 0x00, 0xa4, 0x00, 0x95, 0x00, 0x86, 0x00, 0x78, 0x00, 0x6b, 0x00, 0x5f,
+ 0x00, 0x54, 0x00, 0x4a, 0x00, 0x41, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0xdd, 0x00, 0xdb,
+ 0x00, 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xaa, 0x00, 0x98, 0x00, 0x85,
+ 0x00, 0x72, 0x00, 0x60, 0x00, 0x4f, 0x00, 0x3e, 0x00, 0x2f, 0x01, 0x2a,
+ 0x02, 0x26, 0x03, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16, 0x00,
+ 0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0xde, 0x00, 0xdc,
+ 0x00, 0xd7, 0x00, 0xcf, 0x00, 0xc4, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x9e,
+ 0x00, 0x90, 0x00, 0x83, 0x00, 0x76, 0x00, 0x6a, 0x00, 0x5f, 0x00, 0x55,
+ 0x00, 0x4c, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x04, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc,
+ 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8f, 0x00, 0x7e, 0x00, 0x6d,
+ 0x00, 0x5c, 0x00, 0x4c, 0x00, 0x3d, 0x00, 0x2f, 0x01, 0x2b, 0x02, 0x26,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x14, 0x00, 0x11, 0x00,
+ 0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x04, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd1,
+ 0x00, 0xc8, 0x00, 0xbd, 0x00, 0xb1, 0x00, 0xa5, 0x00, 0x98, 0x00, 0x8c,
+ 0x00, 0x80, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x4d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xce, 0x00, 0xc3, 0x00, 0xb6,
+ 0x00, 0xa8, 0x00, 0x98, 0x00, 0x88, 0x00, 0x78, 0x00, 0x68, 0x00, 0x59,
+ 0x00, 0x4a, 0x00, 0x3c, 0x00, 0x2f, 0x01, 0x2b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00,
+ 0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0x00,
+ 0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0xde, 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcb, 0x00, 0xc1,
+ 0x00, 0xb7, 0x00, 0xab, 0x00, 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7d,
+ 0x00, 0x73, 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc,
+ 0x00, 0xd8, 0x00, 0xd0, 0x00, 0xc7, 0x00, 0xbb, 0x00, 0xae, 0x00, 0xa0,
+ 0x00, 0x91, 0x00, 0x82, 0x00, 0x73, 0x00, 0x64, 0x00, 0x56, 0x00, 0x48,
+ 0x00, 0x3b, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00,
+ 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x09, 0x00,
+ 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd,
+ 0x00, 0xda, 0x00, 0xd4, 0x00, 0xcd, 0x00, 0xc5, 0x00, 0xbb, 0x00, 0xb1,
+ 0x00, 0xa6, 0x00, 0x9b, 0x00, 0x90, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71,
+ 0x00, 0x68, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x61, 0x03, 0x23, 0x09, 0x03, 0x13, 0x00,
+ 0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00,
+ 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x9f,
+ 0x00, 0xc5, 0x00, 0xd2, 0x00, 0xd7, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc,
+ 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde,
+ 0x00, 0xde, 0x00, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x1f, 0x01, 0x04, 0x0a, 0x00, 0x11, 0x00,
+ 0x15, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00,
+ 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, 0x5f, 0x00, 0x9f, 0x00, 0xbc,
+ 0x00, 0xc9, 0x00, 0xd0, 0x00, 0xd5, 0x00, 0xd7, 0x00, 0xd9, 0x00, 0xda,
+ 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x9f,
+ 0x00, 0x5f, 0x00, 0x32, 0x00, 0x16, 0x00, 0x06, 0x03, 0x00, 0x0a, 0x00,
+ 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00,
+ 0x1a, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x03, 0x00, 0x1f, 0x00, 0x5f, 0x00, 0x8d, 0x00, 0xa8, 0x00, 0xb8,
+ 0x00, 0xc3, 0x00, 0xc9, 0x00, 0xce, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd6,
+ 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xbc, 0x00, 0x8d, 0x00, 0x5f,
+ 0x00, 0x3d, 0x00, 0x25, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x05, 0x00,
+ 0x09, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x15, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x01, 0x04,
+ 0x00, 0x32, 0x00, 0x5f, 0x00, 0x81, 0x00, 0x99, 0x00, 0xaa, 0x00, 0xb6,
+ 0x00, 0xbe, 0x00, 0xc4, 0x00, 0xc9, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1,
+ 0x00, 0xd3, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xa8, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x44,
+ 0x00, 0x2f, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0b, 0x00, 0x04, 0x01, 0x00,
+ 0x05, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x0a, 0x00, 0x00, 0x16, 0x00, 0x3d,
+ 0x00, 0x5f, 0x00, 0x7a, 0x00, 0x8f, 0x00, 0x9f, 0x00, 0xab, 0x00, 0xb4,
+ 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc4, 0x00, 0xc8, 0x00, 0xcb, 0x00, 0xcd,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd0,
+ 0x00, 0xb8, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x36,
+ 0x00, 0x28, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x01,
+ 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1a, 0x00, 0x11, 0x00, 0x00, 0x06, 0x00, 0x25, 0x00, 0x44, 0x00, 0x5f,
+ 0x00, 0x76, 0x00, 0x88, 0x00, 0x96, 0x00, 0xa2, 0x00, 0xab, 0x00, 0xb2,
+ 0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc1, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xc3, 0x00, 0xaa,
+ 0x00, 0x8f, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2f,
+ 0x00, 0x24, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x15, 0x00,
+ 0x03, 0x00, 0x00, 0x14, 0x00, 0x2f, 0x00, 0x49, 0x00, 0x5f, 0x00, 0x72,
+ 0x00, 0x82, 0x00, 0x90, 0x00, 0x9b, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1,
+ 0x00, 0xb7, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xb6, 0x00, 0x9f, 0x00, 0x88,
+ 0x00, 0x72, 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29,
+ 0x00, 0x21, 0x00, 0x19, 0x00, 0x13, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x0a, 0x00, 0x00, 0x09,
+ 0x00, 0x1f, 0x00, 0x36, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x70, 0x00, 0x7e,
+ 0x00, 0x8a, 0x00, 0x95, 0x00, 0x9e, 0x00, 0xa5, 0x00, 0xab, 0x00, 0xb1,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xd9,
+ 0x00, 0xce, 0x00, 0xbe, 0x00, 0xab, 0x00, 0x96, 0x00, 0x82, 0x00, 0x70,
+ 0x00, 0x5f, 0x00, 0x50, 0x00, 0x43, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x26,
+ 0x00, 0x1f, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1d, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x28,
+ 0x00, 0x3c, 0x00, 0x4e, 0x00, 0x5f, 0x00, 0x6e, 0x00, 0x7b, 0x00, 0x86,
+ 0x00, 0x90, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc4,
+ 0x00, 0xb4, 0x00, 0xa2, 0x00, 0x90, 0x00, 0x7e, 0x00, 0x6e, 0x00, 0x5f,
+ 0x00, 0x52, 0x00, 0x46, 0x00, 0x3c, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x23,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1b, 0x00,
+ 0x12, 0x00, 0x05, 0x00, 0x00, 0x0b, 0x00, 0x1c, 0x00, 0x2f, 0x00, 0x40,
+ 0x00, 0x50, 0x00, 0x5f, 0x00, 0x6c, 0x00, 0x78, 0x00, 0x83, 0x00, 0x8c,
+ 0x00, 0x94, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xab,
+ 0x00, 0x9b, 0x00, 0x8a, 0x00, 0x7b, 0x00, 0x6c, 0x00, 0x5f, 0x00, 0x53,
+ 0x00, 0x48, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x09, 0x00,
+ 0x00, 0x04, 0x00, 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x43, 0x00, 0x52,
+ 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x76, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc,
+ 0x00, 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x95,
+ 0x00, 0x86, 0x00, 0x78, 0x00, 0x6b, 0x00, 0x5f, 0x00, 0x54, 0x00, 0x4a,
+ 0x00, 0x41, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1e, 0x00, 0x1c, 0x00, 0x16, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x0c,
+ 0x00, 0x1b, 0x00, 0x29, 0x00, 0x38, 0x00, 0x46, 0x00, 0x53, 0x00, 0x5f,
+ 0x00, 0x6a, 0x00, 0x74, 0x00, 0x7d, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xcf,
+ 0x00, 0xc4, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x9e, 0x00, 0x90, 0x00, 0x83,
+ 0x00, 0x76, 0x00, 0x6a, 0x00, 0x5f, 0x00, 0x55, 0x00, 0x4c, 0x00, 0x43,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1d, 0x00,
+ 0x18, 0x00, 0x10, 0x00, 0x05, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x21,
+ 0x00, 0x2e, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x69,
+ 0x00, 0x73, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd1, 0x00, 0xc8, 0x00, 0xbd,
+ 0x00, 0xb1, 0x00, 0xa5, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x74,
+ 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00,
+ 0x09, 0x00, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x26, 0x00, 0x32,
+ 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x55, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x71,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd,
+ 0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcb, 0x00, 0xc1, 0x00, 0xb7, 0x00, 0xab,
+ 0x00, 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7d, 0x00, 0x73, 0x00, 0x69,
+ 0x00, 0x5f, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x02, 0x00,
+ 0x00, 0x08, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x41,
+ 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5f, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd4,
+ 0x00, 0xcd, 0x00, 0xc5, 0x00, 0xbb, 0x00, 0xb1, 0x00, 0xa6, 0x00, 0x9b,
+ 0x00, 0x90, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
+ 0x1a, 0x00, 0x15, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x0e,
+ 0x00, 0x18, 0x00, 0x23, 0x00, 0x2e, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4d,
+ 0x00, 0x56, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+/**
+ * Stored in R8 format. Load it in the following format:
+ * - DX10: DXGI_FORMAT_R8_UNORM
+ */
+const unsigned char searchTexBytes[] = {
+ 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00,
+ 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0xfe, 0x7f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe,
+ 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
+ 0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00,
+ 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0xfe, 0x7f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe,
+ 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
+ 0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f,
+ 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
+ 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00,
+ 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f,
+ 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
+ 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00,
+ 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+};
+
+/* clang-format on */
diff --git a/source/blender/draw/intern/smaa_textures.h b/source/blender/draw/intern/smaa_textures.h
index 8f150c6cd7d..bb3e3bdfb2f 100644
--- a/source/blender/draw/intern/smaa_textures.h
+++ b/source/blender/draw/intern/smaa_textures.h
@@ -33,15051 +33,19 @@
#define AREATEX_PITCH (AREATEX_WIDTH * 2)
#define AREATEX_SIZE (AREATEX_HEIGHT * AREATEX_PITCH)
-/* Don't re-wrap large data definitions. */
-/* clang-format off */
-
/**
* Stored in R8G8 format. Load it in the following format:
* - DX10: DXGI_FORMAT_R8G8_UNORM
*/
-static const unsigned char areaTexBytes[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x44, 0x7b, 0x41, 0x5d,
- 0x42, 0x54, 0x41, 0x4f, 0x42, 0x4b, 0x42, 0x49, 0x42, 0x48, 0x41, 0x47,
- 0x42, 0x46, 0x42, 0x45, 0x42, 0x45, 0x42, 0x44, 0x42, 0x44, 0x42, 0x44,
- 0x42, 0x43, 0x41, 0x43, 0x42, 0x43, 0x42, 0x43, 0x42, 0x43, 0x42, 0x43,
- 0x04, 0x7f, 0x22, 0x3d, 0x2b, 0x3d, 0x30, 0x3d, 0x33, 0x3d, 0x35, 0x3d,
- 0x37, 0x3d, 0x38, 0x3d, 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
- 0x3b, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d,
- 0x3c, 0x3d, 0x3c, 0x3d, 0x40, 0x7f, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x62, 0x20, 0x4d, 0x2a, 0x48, 0x30, 0x44, 0x33,
- 0x44, 0x35, 0x44, 0x36, 0x43, 0x37, 0x42, 0x38, 0x43, 0x39, 0x42, 0x39,
- 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b, 0x42, 0x3b, 0x42, 0x3b, 0x41, 0x3b,
- 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c, 0x00, 0x5d, 0x0c, 0x49,
- 0x16, 0x43, 0x1d, 0x41, 0x22, 0x40, 0x26, 0x3f, 0x29, 0x3f, 0x2c, 0x3f,
- 0x2e, 0x3e, 0x2f, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x33, 0x3e, 0x33, 0x3e,
- 0x34, 0x3e, 0x35, 0x3e, 0x35, 0x3e, 0x36, 0x3e, 0x37, 0x3e, 0x37, 0x3e,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x66, 0x00, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x6d, 0x0b, 0x57, 0x16, 0x4f, 0x1d, 0x4a, 0x22, 0x48, 0x26, 0x47, 0x29,
- 0x46, 0x2b, 0x44, 0x2d, 0x44, 0x2f, 0x44, 0x30, 0x44, 0x31, 0x44, 0x32,
- 0x43, 0x33, 0x43, 0x34, 0x43, 0x34, 0x42, 0x35, 0x43, 0x36, 0x42, 0x36,
- 0x42, 0x37, 0x42, 0x37, 0x00, 0x68, 0x06, 0x54, 0x0d, 0x4b, 0x14, 0x47,
- 0x19, 0x44, 0x1d, 0x43, 0x20, 0x41, 0x23, 0x41, 0x26, 0x40, 0x27, 0x40,
- 0x29, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f, 0x2d, 0x3f, 0x2e, 0x3f, 0x2f, 0x3f,
- 0x30, 0x3f, 0x30, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c,
- 0x00, 0x2d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x72, 0x00, 0x5c, 0x00, 0x2d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x72, 0x06, 0x5f, 0x0d,
- 0x56, 0x14, 0x4f, 0x19, 0x4d, 0x1d, 0x4a, 0x20, 0x49, 0x23, 0x47, 0x25,
- 0x46, 0x27, 0x46, 0x29, 0x45, 0x2a, 0x45, 0x2c, 0x44, 0x2d, 0x44, 0x2e,
- 0x44, 0x2f, 0x43, 0x30, 0x44, 0x30, 0x44, 0x31, 0x43, 0x32, 0x43, 0x33,
- 0x00, 0x6d, 0x04, 0x5b, 0x09, 0x51, 0x0e, 0x4c, 0x13, 0x48, 0x17, 0x46,
- 0x1a, 0x44, 0x1d, 0x43, 0x1f, 0x42, 0x22, 0x42, 0x24, 0x41, 0x25, 0x41,
- 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f,
- 0x2d, 0x3f, 0x2e, 0x3f, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00,
- 0x48, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x75, 0x03, 0x64, 0x09, 0x5a, 0x0e, 0x54, 0x13,
- 0x51, 0x17, 0x4e, 0x1a, 0x4c, 0x1d, 0x49, 0x1f, 0x49, 0x22, 0x48, 0x23,
- 0x47, 0x25, 0x46, 0x26, 0x46, 0x28, 0x45, 0x29, 0x45, 0x2a, 0x44, 0x2b,
- 0x44, 0x2c, 0x44, 0x2d, 0x44, 0x2e, 0x44, 0x2e, 0x00, 0x70, 0x02, 0x60,
- 0x07, 0x56, 0x0b, 0x50, 0x0f, 0x4c, 0x12, 0x49, 0x16, 0x47, 0x18, 0x46,
- 0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x43, 0x21, 0x42, 0x22, 0x42, 0x24, 0x41,
- 0x25, 0x41, 0x26, 0x40, 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00,
- 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x77, 0x02, 0x68, 0x06, 0x5f, 0x0b, 0x58, 0x0f, 0x54, 0x12, 0x51, 0x15,
- 0x4f, 0x18, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1f, 0x49, 0x21, 0x48, 0x22,
- 0x48, 0x23, 0x47, 0x25, 0x46, 0x26, 0x45, 0x27, 0x45, 0x28, 0x45, 0x29,
- 0x45, 0x2a, 0x44, 0x2b, 0x00, 0x72, 0x02, 0x64, 0x05, 0x5b, 0x08, 0x54,
- 0x0c, 0x50, 0x0f, 0x4d, 0x12, 0x4a, 0x14, 0x48, 0x17, 0x47, 0x19, 0x46,
- 0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x44, 0x20, 0x42, 0x21, 0x42, 0x22, 0x42,
- 0x24, 0x41, 0x25, 0x41, 0x26, 0x41, 0x27, 0x40, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75,
- 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x78, 0x02, 0x6b, 0x05,
- 0x62, 0x08, 0x5b, 0x0c, 0x57, 0x0f, 0x54, 0x12, 0x51, 0x14, 0x4e, 0x17,
- 0x4d, 0x19, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e, 0x49, 0x20, 0x48, 0x21,
- 0x48, 0x22, 0x46, 0x24, 0x46, 0x25, 0x46, 0x26, 0x46, 0x27, 0x45, 0x27,
- 0x00, 0x74, 0x01, 0x66, 0x04, 0x5e, 0x07, 0x57, 0x0a, 0x53, 0x0d, 0x4f,
- 0x10, 0x4d, 0x12, 0x4b, 0x14, 0x49, 0x16, 0x48, 0x18, 0x46, 0x1a, 0x45,
- 0x1b, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x20, 0x43, 0x21, 0x42, 0x22, 0x42,
- 0x23, 0x42, 0x24, 0x41, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56,
- 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00,
- 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x79, 0x01, 0x6d, 0x04, 0x65, 0x07, 0x5e, 0x0a,
- 0x5a, 0x0d, 0x56, 0x0f, 0x54, 0x12, 0x51, 0x14, 0x4f, 0x16, 0x4e, 0x18,
- 0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e, 0x49, 0x1f, 0x48, 0x21,
- 0x48, 0x22, 0x48, 0x23, 0x47, 0x23, 0x46, 0x25, 0x00, 0x75, 0x01, 0x69,
- 0x03, 0x61, 0x06, 0x5a, 0x08, 0x56, 0x0b, 0x52, 0x0d, 0x4f, 0x10, 0x4d,
- 0x12, 0x4b, 0x14, 0x4a, 0x16, 0x48, 0x17, 0x47, 0x19, 0x46, 0x1a, 0x45,
- 0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x20, 0x43, 0x21, 0x42,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37,
- 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00,
- 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x7a, 0x01, 0x6f, 0x03, 0x67, 0x06, 0x60, 0x08, 0x5d, 0x0b, 0x59, 0x0d,
- 0x56, 0x10, 0x53, 0x11, 0x51, 0x14, 0x50, 0x15, 0x4e, 0x17, 0x4d, 0x19,
- 0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x48, 0x1e, 0x49, 0x1f, 0x49, 0x20,
- 0x48, 0x21, 0x48, 0x22, 0x00, 0x76, 0x01, 0x6b, 0x03, 0x63, 0x05, 0x5d,
- 0x07, 0x58, 0x09, 0x54, 0x0c, 0x52, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c,
- 0x13, 0x4a, 0x15, 0x49, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x45,
- 0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a,
- 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f,
- 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00,
- 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7b, 0x01, 0x71, 0x02,
- 0x69, 0x05, 0x63, 0x07, 0x5f, 0x09, 0x5b, 0x0c, 0x58, 0x0e, 0x55, 0x10,
- 0x53, 0x11, 0x52, 0x13, 0x50, 0x15, 0x4e, 0x16, 0x4e, 0x18, 0x4c, 0x19,
- 0x4c, 0x1a, 0x4a, 0x1c, 0x4b, 0x1d, 0x49, 0x1e, 0x49, 0x1f, 0x49, 0x20,
- 0x00, 0x77, 0x00, 0x6c, 0x02, 0x65, 0x04, 0x5f, 0x06, 0x5a, 0x08, 0x57,
- 0x0a, 0x54, 0x0c, 0x51, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c, 0x13, 0x4a,
- 0x15, 0x49, 0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x1a, 0x46, 0x1b, 0x45,
- 0x1c, 0x45, 0x1d, 0x45, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69,
- 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00,
- 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00,
- 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x7b, 0x00, 0x72, 0x02, 0x6b, 0x04, 0x64, 0x06,
- 0x61, 0x08, 0x5d, 0x0a, 0x5a, 0x0c, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11,
- 0x52, 0x13, 0x50, 0x15, 0x4f, 0x16, 0x4e, 0x17, 0x4d, 0x18, 0x4b, 0x1a,
- 0x4b, 0x1a, 0x4b, 0x1c, 0x4b, 0x1d, 0x49, 0x1d, 0x00, 0x77, 0x00, 0x6e,
- 0x02, 0x66, 0x04, 0x61, 0x05, 0x5c, 0x07, 0x59, 0x09, 0x56, 0x0b, 0x53,
- 0x0d, 0x51, 0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a,
- 0x15, 0x48, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x46, 0x1b, 0x45,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53,
- 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00,
- 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00,
- 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x7c, 0x00, 0x73, 0x02, 0x6c, 0x03, 0x66, 0x05, 0x63, 0x07, 0x5e, 0x09,
- 0x5c, 0x0b, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13,
- 0x50, 0x14, 0x4f, 0x15, 0x4e, 0x17, 0x4c, 0x18, 0x4c, 0x19, 0x4c, 0x1a,
- 0x4b, 0x1a, 0x4b, 0x1c, 0x00, 0x77, 0x00, 0x6f, 0x02, 0x68, 0x03, 0x63,
- 0x05, 0x5e, 0x06, 0x5a, 0x08, 0x57, 0x0a, 0x55, 0x0b, 0x53, 0x0d, 0x50,
- 0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x49,
- 0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x19, 0x46, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c,
- 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e,
- 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00,
- 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7c, 0x00, 0x74, 0x02,
- 0x6e, 0x03, 0x68, 0x05, 0x64, 0x06, 0x60, 0x08, 0x5d, 0x0a, 0x5a, 0x0b,
- 0x58, 0x0d, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x14,
- 0x50, 0x15, 0x4d, 0x16, 0x4e, 0x18, 0x4c, 0x18, 0x4c, 0x19, 0x4c, 0x1a,
- 0x00, 0x78, 0x00, 0x70, 0x01, 0x69, 0x03, 0x64, 0x04, 0x60, 0x06, 0x5c,
- 0x07, 0x59, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x52, 0x0d, 0x50, 0x0f, 0x4f,
- 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x48,
- 0x17, 0x48, 0x18, 0x47, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71,
- 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c,
- 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00,
- 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00,
- 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x75, 0x01, 0x6f, 0x02, 0x69, 0x04,
- 0x65, 0x06, 0x62, 0x07, 0x5f, 0x09, 0x5b, 0x0b, 0x5a, 0x0c, 0x58, 0x0d,
- 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x13, 0x4f, 0x15,
- 0x4e, 0x15, 0x4e, 0x17, 0x4d, 0x18, 0x4c, 0x18, 0x00, 0x78, 0x00, 0x71,
- 0x01, 0x6a, 0x03, 0x66, 0x04, 0x61, 0x05, 0x5d, 0x06, 0x5a, 0x08, 0x58,
- 0x09, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0e, 0x50, 0x0f, 0x4e, 0x10, 0x4e,
- 0x11, 0x4c, 0x13, 0x4c, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x49, 0x16, 0x48,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62,
- 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e,
- 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00,
- 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00,
- 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x7d, 0x00, 0x76, 0x01, 0x70, 0x02, 0x6a, 0x03, 0x67, 0x05, 0x63, 0x06,
- 0x60, 0x08, 0x5d, 0x09, 0x5b, 0x0b, 0x59, 0x0c, 0x57, 0x0d, 0x55, 0x0e,
- 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x4f, 0x13, 0x50, 0x15, 0x4f, 0x15,
- 0x4e, 0x16, 0x4e, 0x18, 0x00, 0x79, 0x00, 0x71, 0x01, 0x6c, 0x02, 0x66,
- 0x04, 0x62, 0x05, 0x5f, 0x06, 0x5c, 0x07, 0x59, 0x09, 0x57, 0x0a, 0x55,
- 0x0b, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c,
- 0x13, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x4a, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d,
- 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51,
- 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12,
- 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00,
- 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00,
- 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x76, 0x01,
- 0x71, 0x02, 0x6c, 0x03, 0x68, 0x05, 0x64, 0x06, 0x61, 0x07, 0x5e, 0x09,
- 0x5c, 0x0a, 0x5a, 0x0b, 0x59, 0x0c, 0x57, 0x0e, 0x55, 0x0e, 0x55, 0x11,
- 0x52, 0x11, 0x51, 0x12, 0x51, 0x13, 0x50, 0x14, 0x4f, 0x15, 0x4e, 0x15,
- 0x00, 0x79, 0x00, 0x72, 0x01, 0x6d, 0x02, 0x68, 0x03, 0x63, 0x04, 0x60,
- 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x53,
- 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c,
- 0x13, 0x4b, 0x14, 0x4a, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x1f, 0x00, 0x3f,
- 0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c,
- 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
- 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x58, 0x00, 0x70, 0x00, 0x77,
- 0x00, 0x79, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d,
- 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x00, 0x3f,
- 0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c,
- 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
- 0x00, 0x7e, 0x00, 0x7e, 0x1f, 0x1f, 0x00, 0x3f, 0x00, 0x66, 0x00, 0x72,
- 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d,
- 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x77, 0x01, 0x72, 0x02, 0x6d, 0x03,
- 0x69, 0x04, 0x66, 0x06, 0x63, 0x07, 0x5f, 0x08, 0x5e, 0x09, 0x5c, 0x0b,
- 0x5a, 0x0c, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x0f, 0x54, 0x11, 0x51, 0x11,
- 0x52, 0x12, 0x51, 0x13, 0x50, 0x14, 0x50, 0x15, 0x00, 0x79, 0x00, 0x73,
- 0x01, 0x6d, 0x02, 0x69, 0x03, 0x65, 0x04, 0x61, 0x05, 0x5e, 0x06, 0x5c,
- 0x07, 0x59, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54, 0x0d, 0x53, 0x0d, 0x51,
- 0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c, 0x13, 0x4b,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x3f, 0x00, 0x5c,
- 0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a,
- 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d,
- 0x00, 0x58, 0x00, 0x44, 0x00, 0x55, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x72,
- 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c,
- 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x0a, 0x00, 0x3f, 0x00, 0x5c,
- 0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a,
- 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d,
- 0x3f, 0x00, 0x0a, 0x0a, 0x00, 0x3f, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x71,
- 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c,
- 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x7d, 0x00, 0x78, 0x01, 0x72, 0x02, 0x6e, 0x02, 0x6a, 0x03, 0x67, 0x05,
- 0x64, 0x06, 0x60, 0x07, 0x5f, 0x09, 0x5c, 0x0a, 0x5b, 0x0b, 0x5a, 0x0c,
- 0x57, 0x0c, 0x56, 0x0e, 0x55, 0x0f, 0x53, 0x11, 0x52, 0x11, 0x52, 0x12,
- 0x51, 0x13, 0x50, 0x13, 0x00, 0x79, 0x00, 0x73, 0x01, 0x6e, 0x02, 0x69,
- 0x03, 0x66, 0x04, 0x62, 0x05, 0x5f, 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58,
- 0x09, 0x56, 0x0b, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50,
- 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4d, 0x12, 0x4c, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59,
- 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76,
- 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x70, 0x00, 0x55,
- 0x00, 0x20, 0x00, 0x3e, 0x00, 0x50, 0x00, 0x5a, 0x00, 0x63, 0x00, 0x6a,
- 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78,
- 0x00, 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x66, 0x00, 0x3f, 0x00, 0x03, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59,
- 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76,
- 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x66, 0x00, 0x3f, 0x00,
- 0x03, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00, 0x63, 0x00, 0x6a,
- 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78,
- 0x00, 0x79, 0x00, 0x7a, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x78, 0x01,
- 0x73, 0x02, 0x6e, 0x02, 0x6b, 0x03, 0x68, 0x05, 0x65, 0x06, 0x61, 0x07,
- 0x5f, 0x07, 0x5e, 0x09, 0x5c, 0x0b, 0x5a, 0x0b, 0x59, 0x0c, 0x57, 0x0d,
- 0x56, 0x0e, 0x54, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x52, 0x12, 0x51, 0x13,
- 0x00, 0x79, 0x00, 0x74, 0x00, 0x6f, 0x02, 0x6a, 0x03, 0x66, 0x04, 0x63,
- 0x05, 0x60, 0x05, 0x5e, 0x06, 0x5b, 0x07, 0x59, 0x09, 0x58, 0x09, 0x55,
- 0x0b, 0x55, 0x0c, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50, 0x0f, 0x4e,
- 0x11, 0x4e, 0x11, 0x4d, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56,
- 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71,
- 0x00, 0x73, 0x00, 0x75, 0x00, 0x77, 0x00, 0x67, 0x00, 0x3e, 0x00, 0x0d,
- 0x00, 0x28, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64,
- 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c, 0x00,
- 0x2d, 0x00, 0x01, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56,
- 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71,
- 0x00, 0x73, 0x00, 0x75, 0x72, 0x00, 0x5c, 0x00, 0x2d, 0x00, 0x01, 0x01,
- 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64,
- 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x78, 0x00, 0x74, 0x01, 0x6f, 0x02,
- 0x6c, 0x03, 0x68, 0x04, 0x65, 0x05, 0x62, 0x06, 0x61, 0x07, 0x5f, 0x09,
- 0x5c, 0x09, 0x5b, 0x0b, 0x5a, 0x0b, 0x58, 0x0c, 0x57, 0x0d, 0x55, 0x0e,
- 0x55, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x52, 0x12, 0x00, 0x79, 0x00, 0x74,
- 0x00, 0x70, 0x01, 0x6b, 0x02, 0x67, 0x03, 0x64, 0x04, 0x61, 0x05, 0x5f,
- 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54,
- 0x0c, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54,
- 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e,
- 0x00, 0x79, 0x00, 0x6e, 0x00, 0x50, 0x00, 0x28, 0x00, 0x01, 0x00, 0x1b,
- 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61,
- 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00,
- 0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54,
- 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e,
- 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x1b,
- 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61,
- 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x21, 0x5d, 0x0c, 0x68,
- 0x06, 0x6d, 0x04, 0x71, 0x02, 0x72, 0x02, 0x74, 0x01, 0x75, 0x01, 0x76,
- 0x01, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x79,
- 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x7a,
- 0x42, 0x40, 0x17, 0x55, 0x0c, 0x60, 0x08, 0x66, 0x05, 0x6a, 0x04, 0x6d,
- 0x03, 0x6f, 0x02, 0x71, 0x02, 0x73, 0x01, 0x73, 0x01, 0x74, 0x01, 0x75,
- 0x01, 0x76, 0x01, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78,
- 0x00, 0x78, 0x00, 0x78, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x21, 0x5d, 0x0c, 0x68,
- 0x06, 0x6d, 0x04, 0x71, 0x02, 0x72, 0x02, 0x74, 0x01, 0x75, 0x01, 0x76,
- 0x01, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x79,
- 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x7a,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53,
- 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x7b, 0x00, 0x72,
- 0x00, 0x5a, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x16, 0x00, 0x28,
- 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e,
- 0x00, 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x00,
- 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53,
- 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x7a, 0x00, 0x71, 0x00,
- 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x28,
- 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e,
- 0x00, 0x62, 0x00, 0x65, 0x2b, 0x49, 0x16, 0x53, 0x0d, 0x5b, 0x09, 0x60,
- 0x07, 0x64, 0x05, 0x67, 0x04, 0x69, 0x03, 0x6b, 0x03, 0x6c, 0x02, 0x6e,
- 0x02, 0x6f, 0x02, 0x70, 0x01, 0x71, 0x01, 0x71, 0x01, 0x72, 0x01, 0x73,
- 0x01, 0x73, 0x01, 0x74, 0x00, 0x74, 0x00, 0x75, 0x57, 0x16, 0x2d, 0x2c,
- 0x1b, 0x3b, 0x12, 0x45, 0x0d, 0x4d, 0x0b, 0x53, 0x08, 0x57, 0x07, 0x5b,
- 0x05, 0x5e, 0x05, 0x61, 0x04, 0x63, 0x04, 0x65, 0x03, 0x67, 0x02, 0x68,
- 0x02, 0x69, 0x02, 0x6b, 0x02, 0x6c, 0x01, 0x6d, 0x01, 0x6e, 0x01, 0x6f,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x2b, 0x49, 0x16, 0x53, 0x0d, 0x5b, 0x09, 0x60,
- 0x07, 0x64, 0x05, 0x67, 0x04, 0x69, 0x03, 0x6b, 0x03, 0x6c, 0x02, 0x6e,
- 0x02, 0x6f, 0x02, 0x70, 0x01, 0x71, 0x01, 0x71, 0x01, 0x72, 0x01, 0x73,
- 0x01, 0x73, 0x01, 0x74, 0x00, 0x74, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13,
- 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52,
- 0x00, 0x57, 0x00, 0x5b, 0x00, 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a,
- 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30,
- 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75, 0x00,
- 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x13,
- 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52,
- 0x00, 0x57, 0x00, 0x5b, 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a, 0x00,
- 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30,
- 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b,
- 0x31, 0x43, 0x1d, 0x4b, 0x14, 0x51, 0x0e, 0x56, 0x0b, 0x5b, 0x08, 0x5e,
- 0x07, 0x61, 0x06, 0x63, 0x05, 0x65, 0x04, 0x67, 0x04, 0x68, 0x03, 0x69,
- 0x03, 0x6a, 0x03, 0x6c, 0x02, 0x6d, 0x02, 0x6d, 0x02, 0x6e, 0x02, 0x6f,
- 0x02, 0x70, 0x01, 0x70, 0x61, 0x0c, 0x3b, 0x1b, 0x28, 0x28, 0x1d, 0x32,
- 0x16, 0x3a, 0x11, 0x41, 0x0e, 0x47, 0x0c, 0x4b, 0x0a, 0x4f, 0x09, 0x53,
- 0x07, 0x55, 0x06, 0x58, 0x05, 0x5a, 0x05, 0x5c, 0x05, 0x5e, 0x04, 0x60,
- 0x04, 0x61, 0x04, 0x63, 0x03, 0x64, 0x02, 0x66, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x31, 0x43, 0x1d, 0x4b, 0x14, 0x51, 0x0e, 0x56, 0x0b, 0x5b, 0x08, 0x5e,
- 0x07, 0x61, 0x06, 0x63, 0x05, 0x65, 0x04, 0x67, 0x04, 0x68, 0x03, 0x69,
- 0x03, 0x6a, 0x03, 0x6c, 0x02, 0x6d, 0x02, 0x6d, 0x02, 0x6e, 0x02, 0x6f,
- 0x02, 0x70, 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
- 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51,
- 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28,
- 0x00, 0x13, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35,
- 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00,
- 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
- 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51,
- 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28, 0x00,
- 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35,
- 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x33, 0x41, 0x22, 0x46,
- 0x19, 0x4c, 0x13, 0x50, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x5a, 0x08, 0x5d,
- 0x07, 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x66, 0x04, 0x66,
- 0x04, 0x68, 0x03, 0x69, 0x03, 0x69, 0x03, 0x6a, 0x03, 0x6b, 0x02, 0x6c,
- 0x67, 0x07, 0x45, 0x12, 0x32, 0x1d, 0x26, 0x26, 0x1e, 0x2e, 0x18, 0x34,
- 0x14, 0x3a, 0x11, 0x3f, 0x0f, 0x44, 0x0c, 0x47, 0x0b, 0x4b, 0x0a, 0x4d,
- 0x09, 0x51, 0x07, 0x52, 0x07, 0x55, 0x06, 0x57, 0x05, 0x58, 0x05, 0x5a,
- 0x05, 0x5c, 0x04, 0x5d, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x33, 0x41, 0x22, 0x46,
- 0x19, 0x4c, 0x13, 0x50, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x5a, 0x08, 0x5d,
- 0x07, 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x66, 0x04, 0x66,
- 0x04, 0x68, 0x03, 0x69, 0x03, 0x69, 0x03, 0x6a, 0x03, 0x6b, 0x02, 0x6c,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27,
- 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x7d, 0x00, 0x79,
- 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10,
- 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39,
- 0x00, 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00,
- 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27,
- 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x7d, 0x00, 0x79, 0x00,
- 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10, 0x00,
- 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39,
- 0x00, 0x40, 0x00, 0x46, 0x35, 0x40, 0x27, 0x44, 0x1d, 0x48, 0x17, 0x4c,
- 0x12, 0x50, 0x0f, 0x53, 0x0d, 0x56, 0x0b, 0x58, 0x09, 0x5a, 0x08, 0x5c,
- 0x07, 0x5e, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63, 0x04, 0x65,
- 0x04, 0x66, 0x04, 0x66, 0x04, 0x67, 0x03, 0x68, 0x6b, 0x05, 0x4d, 0x0d,
- 0x3b, 0x16, 0x2e, 0x1e, 0x25, 0x25, 0x1f, 0x2b, 0x1a, 0x31, 0x16, 0x36,
- 0x13, 0x3a, 0x10, 0x3e, 0x0f, 0x42, 0x0d, 0x45, 0x0c, 0x47, 0x0a, 0x4a,
- 0x0a, 0x4c, 0x09, 0x4f, 0x07, 0x51, 0x07, 0x52, 0x07, 0x54, 0x06, 0x56,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x35, 0x40, 0x27, 0x44, 0x1d, 0x48, 0x17, 0x4c,
- 0x12, 0x50, 0x0f, 0x53, 0x0d, 0x56, 0x0b, 0x58, 0x09, 0x5a, 0x08, 0x5c,
- 0x07, 0x5e, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63, 0x04, 0x65,
- 0x04, 0x66, 0x04, 0x66, 0x04, 0x67, 0x03, 0x68, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c,
- 0x00, 0x34, 0x00, 0x3b, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64,
- 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00,
- 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a, 0x00,
- 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00,
- 0x0e, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c,
- 0x00, 0x34, 0x00, 0x3b, 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64, 0x00,
- 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00,
- 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b,
- 0x37, 0x3f, 0x29, 0x43, 0x21, 0x46, 0x1a, 0x49, 0x16, 0x4d, 0x12, 0x50,
- 0x10, 0x52, 0x0d, 0x54, 0x0c, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c,
- 0x07, 0x5d, 0x06, 0x5f, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63,
- 0x04, 0x64, 0x04, 0x65, 0x6e, 0x04, 0x53, 0x0a, 0x41, 0x11, 0x34, 0x18,
- 0x2b, 0x1f, 0x24, 0x24, 0x1f, 0x29, 0x1b, 0x2e, 0x17, 0x33, 0x15, 0x37,
- 0x12, 0x3a, 0x10, 0x3d, 0x0f, 0x40, 0x0d, 0x43, 0x0c, 0x45, 0x0c, 0x48,
- 0x0a, 0x4a, 0x0a, 0x4c, 0x09, 0x4e, 0x07, 0x4f, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x37, 0x3f, 0x29, 0x43, 0x21, 0x46, 0x1a, 0x49, 0x16, 0x4d, 0x12, 0x50,
- 0x10, 0x52, 0x0d, 0x54, 0x0c, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c,
- 0x07, 0x5d, 0x06, 0x5f, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63,
- 0x04, 0x64, 0x04, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30,
- 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b,
- 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c,
- 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00,
- 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00,
- 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30,
- 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b, 0x00,
- 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x0c,
- 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x38, 0x3f, 0x2c, 0x41,
- 0x23, 0x44, 0x1d, 0x47, 0x19, 0x4a, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x52,
- 0x0e, 0x54, 0x0c, 0x56, 0x0b, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c,
- 0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x61, 0x05, 0x61, 0x05, 0x62,
- 0x70, 0x03, 0x58, 0x08, 0x47, 0x0e, 0x3a, 0x14, 0x31, 0x1a, 0x29, 0x1f,
- 0x24, 0x24, 0x20, 0x28, 0x1c, 0x2d, 0x19, 0x31, 0x16, 0x34, 0x14, 0x37,
- 0x12, 0x3a, 0x10, 0x3d, 0x0f, 0x3f, 0x0e, 0x42, 0x0c, 0x44, 0x0c, 0x46,
- 0x0b, 0x47, 0x0a, 0x4a, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x38, 0x3f, 0x2c, 0x41,
- 0x23, 0x44, 0x1d, 0x47, 0x19, 0x4a, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x52,
- 0x0e, 0x54, 0x0c, 0x56, 0x0b, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c,
- 0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x61, 0x05, 0x61, 0x05, 0x62,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x7e, 0x00, 0x7c,
- 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35,
- 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15,
- 0x00, 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00,
- 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00,
- 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x7e, 0x00, 0x7c, 0x00,
- 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35, 0x00,
- 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15,
- 0x00, 0x1e, 0x00, 0x26, 0x39, 0x3f, 0x2e, 0x41, 0x26, 0x43, 0x20, 0x46,
- 0x1b, 0x48, 0x17, 0x4b, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x51, 0x0e, 0x53,
- 0x0d, 0x55, 0x0b, 0x56, 0x0b, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
- 0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x60, 0x71, 0x02, 0x5b, 0x07,
- 0x4c, 0x0c, 0x3f, 0x11, 0x36, 0x16, 0x2e, 0x1b, 0x29, 0x20, 0x24, 0x23,
- 0x20, 0x28, 0x1d, 0x2b, 0x19, 0x2f, 0x17, 0x32, 0x16, 0x35, 0x12, 0x37,
- 0x12, 0x3a, 0x10, 0x3c, 0x0f, 0x3f, 0x0e, 0x41, 0x0c, 0x42, 0x0c, 0x45,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x39, 0x3f, 0x2e, 0x41, 0x26, 0x43, 0x20, 0x46,
- 0x1b, 0x48, 0x17, 0x4b, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x51, 0x0e, 0x53,
- 0x0d, 0x55, 0x0b, 0x56, 0x0b, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
- 0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
- 0x00, 0x13, 0x00, 0x1b, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f,
- 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23,
- 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00,
- 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00,
- 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0a,
- 0x00, 0x13, 0x00, 0x1b, 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f, 0x00,
- 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23, 0x00,
- 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b,
- 0x39, 0x3e, 0x2f, 0x40, 0x28, 0x42, 0x22, 0x45, 0x1d, 0x47, 0x19, 0x49,
- 0x16, 0x4b, 0x14, 0x4d, 0x11, 0x4f, 0x10, 0x51, 0x0f, 0x53, 0x0d, 0x54,
- 0x0c, 0x55, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
- 0x07, 0x5c, 0x07, 0x5e, 0x73, 0x02, 0x5e, 0x05, 0x4f, 0x0a, 0x44, 0x0f,
- 0x3a, 0x13, 0x33, 0x18, 0x2d, 0x1c, 0x27, 0x20, 0x23, 0x23, 0x20, 0x27,
- 0x1d, 0x2a, 0x1a, 0x2d, 0x18, 0x30, 0x16, 0x33, 0x14, 0x35, 0x12, 0x38,
- 0x12, 0x3a, 0x10, 0x3c, 0x0f, 0x3e, 0x0f, 0x41, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x39, 0x3e, 0x2f, 0x40, 0x28, 0x42, 0x22, 0x45, 0x1d, 0x47, 0x19, 0x49,
- 0x16, 0x4b, 0x14, 0x4d, 0x11, 0x4f, 0x10, 0x51, 0x0f, 0x53, 0x0d, 0x54,
- 0x0c, 0x55, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
- 0x07, 0x5c, 0x07, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12,
- 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e,
- 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15,
- 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00,
- 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00,
- 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12,
- 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e, 0x00,
- 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15, 0x00,
- 0x0a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, 0x3a, 0x3e, 0x31, 0x40,
- 0x29, 0x42, 0x23, 0x44, 0x1f, 0x46, 0x1b, 0x48, 0x18, 0x4a, 0x15, 0x4c,
- 0x13, 0x4d, 0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x55,
- 0x0b, 0x56, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
- 0x74, 0x01, 0x62, 0x05, 0x53, 0x08, 0x47, 0x0c, 0x3e, 0x11, 0x37, 0x15,
- 0x31, 0x19, 0x2b, 0x1d, 0x27, 0x20, 0x23, 0x23, 0x20, 0x26, 0x1d, 0x2a,
- 0x1b, 0x2c, 0x19, 0x2f, 0x16, 0x31, 0x16, 0x34, 0x13, 0x35, 0x12, 0x38,
- 0x12, 0x3b, 0x0f, 0x3b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3a, 0x3e, 0x31, 0x40,
- 0x29, 0x42, 0x23, 0x44, 0x1f, 0x46, 0x1b, 0x48, 0x18, 0x4a, 0x15, 0x4c,
- 0x13, 0x4d, 0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x55,
- 0x0b, 0x56, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x7e, 0x00, 0x7d,
- 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c,
- 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09,
- 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00,
- 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00,
- 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7e, 0x00, 0x7d, 0x00,
- 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c, 0x00,
- 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09, 0x00,
- 0x00, 0x00, 0x00, 0x08, 0x3a, 0x3e, 0x32, 0x3f, 0x2b, 0x41, 0x25, 0x43,
- 0x21, 0x45, 0x1d, 0x46, 0x1a, 0x48, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e,
- 0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55,
- 0x0b, 0x56, 0x0b, 0x58, 0x09, 0x58, 0x09, 0x59, 0x75, 0x01, 0x64, 0x04,
- 0x56, 0x07, 0x4b, 0x0b, 0x42, 0x0f, 0x3a, 0x12, 0x34, 0x16, 0x2f, 0x19,
- 0x2a, 0x1d, 0x26, 0x20, 0x23, 0x23, 0x21, 0x26, 0x1d, 0x29, 0x1b, 0x2b,
- 0x19, 0x2e, 0x18, 0x30, 0x16, 0x32, 0x15, 0x35, 0x12, 0x35, 0x12, 0x38,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x3a, 0x3e, 0x32, 0x3f, 0x2b, 0x41, 0x25, 0x43,
- 0x21, 0x45, 0x1d, 0x46, 0x1a, 0x48, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e,
- 0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55,
- 0x0b, 0x56, 0x0b, 0x58, 0x09, 0x58, 0x09, 0x59, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75,
- 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b,
- 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00,
- 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00,
- 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75, 0x00,
- 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b, 0x00,
- 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00,
- 0x3b, 0x3e, 0x33, 0x3f, 0x2c, 0x41, 0x27, 0x42, 0x22, 0x44, 0x1f, 0x45,
- 0x1c, 0x47, 0x19, 0x49, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e, 0x11, 0x4f,
- 0x10, 0x50, 0x0f, 0x51, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x0b, 0x55,
- 0x0b, 0x57, 0x0a, 0x58, 0x76, 0x01, 0x66, 0x04, 0x58, 0x06, 0x4d, 0x0a,
- 0x45, 0x0d, 0x3e, 0x10, 0x37, 0x14, 0x32, 0x17, 0x2d, 0x1a, 0x2a, 0x1d,
- 0x26, 0x21, 0x22, 0x22, 0x21, 0x26, 0x1d, 0x28, 0x1c, 0x2b, 0x19, 0x2c,
- 0x19, 0x30, 0x16, 0x30, 0x16, 0x33, 0x14, 0x35, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x3b, 0x3e, 0x33, 0x3f, 0x2c, 0x41, 0x27, 0x42, 0x22, 0x44, 0x1f, 0x45,
- 0x1c, 0x47, 0x19, 0x49, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e, 0x11, 0x4f,
- 0x10, 0x50, 0x0f, 0x51, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x0b, 0x55,
- 0x0b, 0x57, 0x0a, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x3e, 0x33, 0x3f,
- 0x2d, 0x40, 0x28, 0x42, 0x24, 0x44, 0x20, 0x45, 0x1d, 0x46, 0x1a, 0x48,
- 0x18, 0x49, 0x16, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x10, 0x50,
- 0x0f, 0x51, 0x0f, 0x53, 0x0d, 0x53, 0x0d, 0x55, 0x0b, 0x55, 0x0b, 0x56,
- 0x77, 0x01, 0x67, 0x03, 0x5a, 0x05, 0x51, 0x09, 0x48, 0x0c, 0x40, 0x0f,
- 0x3a, 0x12, 0x35, 0x16, 0x30, 0x18, 0x2c, 0x1b, 0x29, 0x1d, 0x26, 0x21,
- 0x22, 0x22, 0x21, 0x26, 0x1d, 0x27, 0x1d, 0x2b, 0x1a, 0x2b, 0x19, 0x2e,
- 0x17, 0x30, 0x16, 0x31, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3b, 0x3e, 0x33, 0x3f,
- 0x2d, 0x40, 0x28, 0x42, 0x24, 0x44, 0x20, 0x45, 0x1d, 0x46, 0x1a, 0x48,
- 0x18, 0x49, 0x16, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x10, 0x50,
- 0x0f, 0x51, 0x0f, 0x53, 0x0d, 0x53, 0x0d, 0x55, 0x0b, 0x55, 0x0b, 0x56,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3b, 0x3e, 0x34, 0x3f, 0x2e, 0x40, 0x29, 0x41,
- 0x25, 0x43, 0x21, 0x44, 0x1e, 0x45, 0x1c, 0x47, 0x19, 0x48, 0x18, 0x4a,
- 0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50,
- 0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x77, 0x01, 0x68, 0x02,
- 0x5d, 0x05, 0x52, 0x07, 0x4a, 0x0a, 0x43, 0x0d, 0x3d, 0x10, 0x38, 0x12,
- 0x33, 0x16, 0x2f, 0x19, 0x2b, 0x1b, 0x28, 0x1d, 0x26, 0x21, 0x22, 0x22,
- 0x21, 0x26, 0x1e, 0x26, 0x1d, 0x2a, 0x1a, 0x2b, 0x19, 0x2d, 0x18, 0x30,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x3b, 0x3e, 0x34, 0x3f, 0x2e, 0x40, 0x29, 0x41,
- 0x25, 0x43, 0x21, 0x44, 0x1e, 0x45, 0x1c, 0x47, 0x19, 0x48, 0x18, 0x4a,
- 0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50,
- 0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3c, 0x3e, 0x35, 0x3f, 0x2f, 0x40, 0x2a, 0x41, 0x26, 0x42, 0x22, 0x44,
- 0x20, 0x45, 0x1d, 0x46, 0x1b, 0x48, 0x18, 0x48, 0x17, 0x4a, 0x15, 0x4b,
- 0x13, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x52,
- 0x0d, 0x53, 0x0d, 0x53, 0x77, 0x00, 0x6a, 0x02, 0x5e, 0x04, 0x55, 0x07,
- 0x4c, 0x0a, 0x45, 0x0c, 0x40, 0x0f, 0x3a, 0x12, 0x35, 0x14, 0x31, 0x16,
- 0x2e, 0x19, 0x2b, 0x1c, 0x27, 0x1d, 0x26, 0x22, 0x21, 0x22, 0x21, 0x25,
- 0x1e, 0x26, 0x1d, 0x29, 0x1b, 0x2b, 0x19, 0x2b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x3c, 0x3e, 0x35, 0x3f, 0x2f, 0x40, 0x2a, 0x41, 0x26, 0x42, 0x22, 0x44,
- 0x20, 0x45, 0x1d, 0x46, 0x1b, 0x48, 0x18, 0x48, 0x17, 0x4a, 0x15, 0x4b,
- 0x13, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x52,
- 0x0d, 0x53, 0x0d, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x35, 0x3f,
- 0x30, 0x3f, 0x2b, 0x40, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44, 0x1e, 0x45,
- 0x1c, 0x46, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a, 0x15, 0x4c, 0x13, 0x4c,
- 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x0e, 0x53,
- 0x78, 0x00, 0x6b, 0x02, 0x60, 0x04, 0x57, 0x06, 0x4f, 0x09, 0x48, 0x0c,
- 0x42, 0x0e, 0x3c, 0x10, 0x38, 0x12, 0x34, 0x16, 0x30, 0x18, 0x2d, 0x19,
- 0x2b, 0x1d, 0x26, 0x1e, 0x25, 0x22, 0x21, 0x22, 0x21, 0x25, 0x1e, 0x26,
- 0x1d, 0x28, 0x1c, 0x2b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x35, 0x3f,
- 0x30, 0x3f, 0x2b, 0x40, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44, 0x1e, 0x45,
- 0x1c, 0x46, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a, 0x15, 0x4c, 0x13, 0x4c,
- 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x0e, 0x53,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x36, 0x3f, 0x30, 0x3f, 0x2c, 0x40,
- 0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47,
- 0x19, 0x48, 0x18, 0x4a, 0x15, 0x4a, 0x15, 0x4c, 0x13, 0x4c, 0x13, 0x4e,
- 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x78, 0x00, 0x6d, 0x02,
- 0x61, 0x04, 0x58, 0x05, 0x51, 0x07, 0x4a, 0x0a, 0x44, 0x0c, 0x3f, 0x0f,
- 0x3a, 0x12, 0x35, 0x14, 0x32, 0x16, 0x30, 0x19, 0x2b, 0x19, 0x2a, 0x1d,
- 0x26, 0x1e, 0x25, 0x22, 0x21, 0x22, 0x21, 0x25, 0x1e, 0x26, 0x1d, 0x27,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x36, 0x3f, 0x30, 0x3f, 0x2c, 0x40,
- 0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47,
- 0x19, 0x48, 0x18, 0x4a, 0x15, 0x4a, 0x15, 0x4c, 0x13, 0x4c, 0x13, 0x4e,
- 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3c, 0x3e, 0x37, 0x3e, 0x31, 0x3f, 0x2d, 0x40, 0x29, 0x41, 0x26, 0x42,
- 0x23, 0x44, 0x20, 0x45, 0x1e, 0x45, 0x1c, 0x46, 0x1a, 0x48, 0x18, 0x48,
- 0x17, 0x4a, 0x15, 0x4a, 0x14, 0x4c, 0x13, 0x4c, 0x12, 0x4e, 0x11, 0x4e,
- 0x11, 0x50, 0x0f, 0x50, 0x78, 0x00, 0x6d, 0x02, 0x63, 0x04, 0x5a, 0x05,
- 0x53, 0x07, 0x4c, 0x0a, 0x46, 0x0c, 0x41, 0x0f, 0x3c, 0x0f, 0x38, 0x12,
- 0x35, 0x16, 0x30, 0x16, 0x2e, 0x19, 0x2b, 0x1a, 0x29, 0x1d, 0x26, 0x1e,
- 0x25, 0x22, 0x21, 0x22, 0x21, 0x25, 0x1f, 0x26, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x3c, 0x3e, 0x37, 0x3e, 0x31, 0x3f, 0x2d, 0x40, 0x29, 0x41, 0x26, 0x42,
- 0x23, 0x44, 0x20, 0x45, 0x1e, 0x45, 0x1c, 0x46, 0x1a, 0x48, 0x18, 0x48,
- 0x17, 0x4a, 0x15, 0x4a, 0x14, 0x4c, 0x13, 0x4c, 0x12, 0x4e, 0x11, 0x4e,
- 0x11, 0x50, 0x0f, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x37, 0x3e,
- 0x32, 0x3f, 0x2e, 0x40, 0x2a, 0x41, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44,
- 0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a,
- 0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x11, 0x50,
- 0x78, 0x00, 0x6e, 0x01, 0x65, 0x03, 0x5c, 0x05, 0x54, 0x07, 0x4e, 0x09,
- 0x48, 0x0b, 0x43, 0x0c, 0x3e, 0x0f, 0x3b, 0x12, 0x36, 0x12, 0x33, 0x16,
- 0x30, 0x17, 0x2d, 0x19, 0x2b, 0x1b, 0x28, 0x1d, 0x26, 0x1e, 0x25, 0x22,
- 0x21, 0x22, 0x21, 0x24, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x37, 0x3e,
- 0x32, 0x3f, 0x2e, 0x40, 0x2a, 0x41, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44,
- 0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a,
- 0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x11, 0x50,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x37, 0x3e, 0x33, 0x3f, 0x2e, 0x3f,
- 0x2b, 0x40, 0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x20, 0x45, 0x1e, 0x45,
- 0x1c, 0x46, 0x1b, 0x48, 0x19, 0x48, 0x18, 0x4a, 0x16, 0x4a, 0x15, 0x4b,
- 0x13, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x79, 0x00, 0x6f, 0x01,
- 0x66, 0x02, 0x5d, 0x04, 0x56, 0x06, 0x4f, 0x07, 0x4a, 0x0a, 0x45, 0x0c,
- 0x41, 0x0f, 0x3b, 0x0f, 0x38, 0x12, 0x35, 0x14, 0x31, 0x16, 0x30, 0x18,
- 0x2b, 0x19, 0x2b, 0x1c, 0x27, 0x1d, 0x26, 0x1f, 0x24, 0x22, 0x21, 0x22,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
- 0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x37, 0x3e, 0x33, 0x3f, 0x2e, 0x3f,
- 0x2b, 0x40, 0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x20, 0x45, 0x1e, 0x45,
- 0x1c, 0x46, 0x1b, 0x48, 0x19, 0x48, 0x18, 0x4a, 0x16, 0x4a, 0x15, 0x4b,
- 0x13, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x62, 0x00, 0x6c, 0x00, 0x72, 0x00, 0x74, 0x00, 0x77, 0x00, 0x79, 0x00,
- 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00,
- 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x7e, 0x00,
- 0x7e, 0x00, 0x7e, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x08, 0x00, 0x44, 0x00,
- 0x56, 0x00, 0x61, 0x00, 0x67, 0x00, 0x6b, 0x00, 0x6e, 0x00, 0x70, 0x00,
- 0x71, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00, 0x76, 0x00,
- 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00,
- 0x44, 0x00, 0x63, 0x00, 0x6c, 0x00, 0x71, 0x00, 0x75, 0x00, 0x77, 0x00,
- 0x79, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7c, 0x00,
- 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7e, 0x00,
- 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x0b, 0x57, 0x06,
- 0x5f, 0x03, 0x63, 0x02, 0x68, 0x02, 0x6b, 0x01, 0x6d, 0x01, 0x6e, 0x01,
- 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00,
- 0x76, 0x00, 0x76, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0x79, 0x00,
- 0x82, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x00, 0x40, 0x17, 0x17, 0x2c, 0x0c, 0x3b, 0x07,
- 0x45, 0x05, 0x4d, 0x04, 0x53, 0x03, 0x57, 0x02, 0x5c, 0x02, 0x5e, 0x01,
- 0x61, 0x01, 0x63, 0x01, 0x66, 0x01, 0x67, 0x01, 0x68, 0x00, 0x69, 0x00,
- 0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x41, 0x20, 0x4d, 0x0b,
- 0x58, 0x06, 0x5e, 0x03, 0x64, 0x02, 0x68, 0x02, 0x6b, 0x01, 0x6c, 0x01,
- 0x6f, 0x01, 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00,
- 0x76, 0x00, 0x75, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x47, 0x15, 0x4f, 0x0d, 0x56, 0x09, 0x59, 0x06,
- 0x5f, 0x05, 0x62, 0x04, 0x65, 0x03, 0x67, 0x02, 0x69, 0x02, 0x6b, 0x02,
- 0x6c, 0x02, 0x6e, 0x01, 0x6f, 0x01, 0x70, 0x01, 0x71, 0x01, 0x70, 0x01,
- 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x74, 0x00, 0x83, 0x00, 0x82, 0x00,
- 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x00, 0x55, 0x0c, 0x2c, 0x1b, 0x1b, 0x27, 0x12, 0x32, 0x0d, 0x3a, 0x0b,
- 0x41, 0x08, 0x47, 0x07, 0x4c, 0x05, 0x4f, 0x05, 0x53, 0x04, 0x56, 0x04,
- 0x58, 0x03, 0x5a, 0x02, 0x5d, 0x02, 0x5e, 0x02, 0x60, 0x02, 0x61, 0x01,
- 0x63, 0x01, 0x64, 0x01, 0x41, 0x2a, 0x47, 0x16, 0x4f, 0x0d, 0x54, 0x09,
- 0x5b, 0x06, 0x5f, 0x05, 0x62, 0x04, 0x64, 0x03, 0x67, 0x02, 0x69, 0x02,
- 0x6b, 0x02, 0x6c, 0x02, 0x6e, 0x01, 0x6f, 0x01, 0x70, 0x01, 0x70, 0x01,
- 0x71, 0x01, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x45, 0x1d, 0x4a, 0x14, 0x50, 0x0e, 0x54, 0x0b, 0x59, 0x08, 0x5c, 0x07,
- 0x5f, 0x06, 0x60, 0x05, 0x64, 0x04, 0x65, 0x03, 0x67, 0x03, 0x68, 0x02,
- 0x6a, 0x02, 0x6b, 0x02, 0x6c, 0x02, 0x6c, 0x02, 0x6e, 0x02, 0x6f, 0x01,
- 0x70, 0x01, 0x70, 0x01, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x60, 0x08, 0x3b,
- 0x12, 0x28, 0x1d, 0x1d, 0x26, 0x16, 0x2e, 0x11, 0x34, 0x0e, 0x3a, 0x0c,
- 0x3f, 0x0a, 0x44, 0x08, 0x47, 0x07, 0x4b, 0x06, 0x4d, 0x05, 0x51, 0x05,
- 0x52, 0x04, 0x55, 0x04, 0x57, 0x04, 0x58, 0x04, 0x5a, 0x03, 0x5c, 0x02,
- 0x42, 0x30, 0x45, 0x1d, 0x4b, 0x14, 0x4f, 0x0e, 0x55, 0x0b, 0x59, 0x08,
- 0x5c, 0x07, 0x5e, 0x06, 0x61, 0x05, 0x64, 0x04, 0x65, 0x03, 0x67, 0x03,
- 0x68, 0x02, 0x6a, 0x02, 0x6b, 0x02, 0x6b, 0x02, 0x6d, 0x02, 0x6e, 0x02,
- 0x6f, 0x01, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x22, 0x48, 0x19,
- 0x4d, 0x13, 0x50, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x5a, 0x08, 0x5c, 0x07,
- 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x65, 0x03, 0x67, 0x03,
- 0x68, 0x03, 0x68, 0x02, 0x6a, 0x02, 0x6b, 0x02, 0x6c, 0x02, 0x6d, 0x02,
- 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x00, 0x66, 0x05, 0x45, 0x0d, 0x32, 0x16, 0x26,
- 0x1e, 0x1e, 0x25, 0x18, 0x2b, 0x14, 0x31, 0x11, 0x36, 0x0f, 0x3a, 0x0c,
- 0x3e, 0x0b, 0x42, 0x0a, 0x45, 0x09, 0x47, 0x07, 0x4a, 0x07, 0x4c, 0x06,
- 0x4f, 0x05, 0x51, 0x05, 0x52, 0x05, 0x54, 0x04, 0x41, 0x33, 0x44, 0x22,
- 0x48, 0x19, 0x4c, 0x13, 0x51, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x59, 0x08,
- 0x5d, 0x07, 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x65, 0x03,
- 0x67, 0x03, 0x67, 0x03, 0x69, 0x02, 0x6a, 0x02, 0x6b, 0x02, 0x6c, 0x02,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x43, 0x26, 0x47, 0x1d, 0x4a, 0x17, 0x4d, 0x12,
- 0x51, 0x0f, 0x54, 0x0d, 0x56, 0x0b, 0x58, 0x09, 0x5b, 0x08, 0x5d, 0x07,
- 0x5f, 0x06, 0x60, 0x06, 0x62, 0x05, 0x63, 0x05, 0x64, 0x04, 0x65, 0x03,
- 0x67, 0x03, 0x67, 0x03, 0x68, 0x03, 0x69, 0x02, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x00, 0x6a, 0x04, 0x4d, 0x0b, 0x3a, 0x11, 0x2e, 0x18, 0x25, 0x1f, 0x1f,
- 0x24, 0x1a, 0x29, 0x16, 0x2e, 0x13, 0x33, 0x11, 0x37, 0x0f, 0x3a, 0x0d,
- 0x3d, 0x0c, 0x40, 0x0a, 0x43, 0x0a, 0x45, 0x09, 0x48, 0x07, 0x4a, 0x07,
- 0x4c, 0x07, 0x4e, 0x06, 0x41, 0x35, 0x43, 0x26, 0x47, 0x1d, 0x49, 0x17,
- 0x4e, 0x12, 0x51, 0x0f, 0x54, 0x0d, 0x55, 0x0b, 0x59, 0x09, 0x5b, 0x08,
- 0x5d, 0x07, 0x5f, 0x06, 0x60, 0x06, 0x62, 0x05, 0x63, 0x05, 0x63, 0x04,
- 0x65, 0x03, 0x67, 0x03, 0x67, 0x03, 0x68, 0x03, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x43, 0x29, 0x45, 0x20, 0x49, 0x1a, 0x4b, 0x15, 0x4f, 0x12, 0x51, 0x0f,
- 0x54, 0x0d, 0x55, 0x0b, 0x58, 0x0a, 0x5a, 0x09, 0x5b, 0x08, 0x5d, 0x07,
- 0x5f, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x64, 0x05, 0x65, 0x04,
- 0x65, 0x03, 0x66, 0x03, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x6d, 0x03, 0x52,
- 0x08, 0x41, 0x0e, 0x34, 0x14, 0x2b, 0x1a, 0x24, 0x1f, 0x1f, 0x24, 0x1b,
- 0x28, 0x17, 0x2d, 0x15, 0x31, 0x12, 0x34, 0x10, 0x37, 0x0f, 0x3a, 0x0d,
- 0x3d, 0x0c, 0x40, 0x0b, 0x42, 0x0a, 0x44, 0x0a, 0x46, 0x09, 0x47, 0x07,
- 0x41, 0x36, 0x43, 0x29, 0x46, 0x20, 0x48, 0x1a, 0x4c, 0x15, 0x4f, 0x12,
- 0x51, 0x0f, 0x53, 0x0d, 0x56, 0x0b, 0x58, 0x0a, 0x5a, 0x09, 0x5b, 0x08,
- 0x5d, 0x07, 0x5f, 0x06, 0x60, 0x06, 0x60, 0x05, 0x62, 0x05, 0x64, 0x05,
- 0x65, 0x04, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x2b, 0x45, 0x23,
- 0x48, 0x1d, 0x49, 0x18, 0x4d, 0x14, 0x4f, 0x12, 0x51, 0x10, 0x53, 0x0e,
- 0x55, 0x0c, 0x57, 0x0b, 0x59, 0x0a, 0x5a, 0x09, 0x5c, 0x08, 0x5d, 0x07,
- 0x5f, 0x07, 0x5f, 0x06, 0x61, 0x06, 0x62, 0x05, 0x63, 0x05, 0x64, 0x05,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x00, 0x6f, 0x02, 0x57, 0x07, 0x47, 0x0c, 0x3a,
- 0x11, 0x31, 0x16, 0x29, 0x1b, 0x24, 0x20, 0x20, 0x23, 0x1c, 0x28, 0x19,
- 0x2b, 0x16, 0x2f, 0x14, 0x32, 0x12, 0x35, 0x10, 0x38, 0x0f, 0x3a, 0x0e,
- 0x3c, 0x0c, 0x3f, 0x0c, 0x41, 0x0b, 0x42, 0x0a, 0x41, 0x37, 0x43, 0x2b,
- 0x45, 0x23, 0x47, 0x1d, 0x4a, 0x18, 0x4d, 0x14, 0x4f, 0x12, 0x51, 0x10,
- 0x53, 0x0e, 0x55, 0x0c, 0x57, 0x0b, 0x59, 0x0a, 0x5a, 0x09, 0x5c, 0x08,
- 0x5d, 0x07, 0x5e, 0x07, 0x60, 0x06, 0x61, 0x06, 0x62, 0x05, 0x63, 0x05,
- 0x1f, 0x00, 0x3f, 0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00,
- 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00,
- 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x1f, 0x1f, 0x3f, 0x00,
- 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00,
- 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00,
- 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7d, 0x00, 0x58, 0x00, 0x70, 0x00, 0x77, 0x00, 0x79, 0x00, 0x7b, 0x00,
- 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00,
- 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x1f, 0x1f, 0x3f, 0x00,
- 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00,
- 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00,
- 0x7e, 0x00, 0x7e, 0x00, 0x43, 0x2d, 0x44, 0x25, 0x46, 0x1f, 0x48, 0x1b,
- 0x4b, 0x17, 0x4d, 0x14, 0x50, 0x12, 0x51, 0x10, 0x53, 0x0e, 0x55, 0x0c,
- 0x57, 0x0b, 0x58, 0x0b, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x08, 0x5c, 0x07,
- 0x5f, 0x07, 0x60, 0x06, 0x61, 0x06, 0x62, 0x06, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x00, 0x71, 0x02, 0x5b, 0x05, 0x4b, 0x0a, 0x3f, 0x0f, 0x36, 0x13, 0x2e,
- 0x18, 0x29, 0x1c, 0x23, 0x20, 0x20, 0x23, 0x1d, 0x27, 0x19, 0x2a, 0x17,
- 0x2d, 0x16, 0x30, 0x12, 0x33, 0x12, 0x35, 0x10, 0x38, 0x0f, 0x3b, 0x0e,
- 0x3c, 0x0c, 0x3e, 0x0c, 0x41, 0x38, 0x43, 0x2d, 0x44, 0x25, 0x45, 0x1f,
- 0x49, 0x1b, 0x4b, 0x17, 0x4d, 0x14, 0x4f, 0x11, 0x51, 0x10, 0x53, 0x0e,
- 0x55, 0x0c, 0x57, 0x0b, 0x58, 0x0b, 0x5a, 0x09, 0x5b, 0x09, 0x5b, 0x08,
- 0x5e, 0x07, 0x5f, 0x07, 0x60, 0x06, 0x61, 0x06, 0x00, 0x00, 0x0a, 0x00,
- 0x3f, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00,
- 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00,
- 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x3f, 0x0a, 0x0a, 0x3f, 0x00, 0x5c, 0x00,
- 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00,
- 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x44, 0x00,
- 0x55, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x75, 0x00, 0x78, 0x00,
- 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00,
- 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x3f, 0x0a, 0x0a, 0x3f, 0x00, 0x5c, 0x00,
- 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00,
- 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00,
- 0x42, 0x2f, 0x44, 0x27, 0x46, 0x22, 0x47, 0x1d, 0x4a, 0x19, 0x4c, 0x16,
- 0x4e, 0x13, 0x4f, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x56, 0x0c,
- 0x58, 0x0b, 0x59, 0x0a, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x07, 0x5e, 0x07,
- 0x5f, 0x07, 0x5f, 0x06, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x73, 0x01, 0x5e,
- 0x05, 0x4f, 0x08, 0x44, 0x0c, 0x3a, 0x10, 0x33, 0x15, 0x2d, 0x19, 0x28,
- 0x1d, 0x23, 0x20, 0x20, 0x23, 0x1d, 0x26, 0x1a, 0x2a, 0x18, 0x2c, 0x16,
- 0x2f, 0x14, 0x31, 0x12, 0x34, 0x12, 0x35, 0x0f, 0x38, 0x0f, 0x3b, 0x0f,
- 0x41, 0x39, 0x42, 0x2f, 0x44, 0x27, 0x45, 0x22, 0x48, 0x1d, 0x4a, 0x19,
- 0x4c, 0x16, 0x4d, 0x14, 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d,
- 0x56, 0x0c, 0x58, 0x0b, 0x59, 0x0a, 0x59, 0x09, 0x5c, 0x09, 0x5c, 0x07,
- 0x5e, 0x07, 0x5f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x2d, 0x00,
- 0x48, 0x00, 0x59, 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00,
- 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00,
- 0x00, 0x66, 0x00, 0x3f, 0x03, 0x03, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00,
- 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00,
- 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x55, 0x00, 0x20, 0x00, 0x3e, 0x00,
- 0x50, 0x00, 0x5a, 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00,
- 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00,
- 0x00, 0x66, 0x00, 0x3f, 0x03, 0x03, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00,
- 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00,
- 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x42, 0x30, 0x44, 0x29,
- 0x45, 0x23, 0x46, 0x1f, 0x49, 0x1b, 0x4b, 0x18, 0x4c, 0x15, 0x4d, 0x13,
- 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x56, 0x0c, 0x57, 0x0b,
- 0x59, 0x0b, 0x59, 0x09, 0x5b, 0x09, 0x5c, 0x09, 0x5c, 0x07, 0x5e, 0x07,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x00, 0x73, 0x01, 0x61, 0x04, 0x52, 0x07, 0x47,
- 0x0b, 0x3e, 0x0f, 0x37, 0x12, 0x31, 0x16, 0x2b, 0x19, 0x27, 0x1d, 0x23,
- 0x20, 0x20, 0x23, 0x1d, 0x26, 0x1b, 0x29, 0x19, 0x2b, 0x16, 0x2e, 0x16,
- 0x30, 0x13, 0x32, 0x12, 0x35, 0x12, 0x36, 0x0f, 0x41, 0x39, 0x42, 0x30,
- 0x44, 0x29, 0x44, 0x23, 0x47, 0x1f, 0x49, 0x1b, 0x4b, 0x18, 0x4c, 0x15,
- 0x4e, 0x13, 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x56, 0x0c,
- 0x57, 0x0b, 0x57, 0x0b, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x09, 0x5c, 0x07,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00,
- 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00,
- 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75, 0x00, 0x00, 0x72, 0x00, 0x5c,
- 0x00, 0x2d, 0x01, 0x01, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00,
- 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00,
- 0x73, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x77, 0x00, 0x67, 0x00, 0x3e, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x3a, 0x00,
- 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00,
- 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75, 0x00, 0x00, 0x72, 0x00, 0x5c,
- 0x00, 0x2d, 0x01, 0x01, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00,
- 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00,
- 0x73, 0x00, 0x75, 0x00, 0x42, 0x32, 0x44, 0x2a, 0x45, 0x25, 0x46, 0x21,
- 0x48, 0x1d, 0x4a, 0x1a, 0x4b, 0x17, 0x4c, 0x15, 0x4e, 0x13, 0x50, 0x11,
- 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x55, 0x0c, 0x57, 0x0c, 0x57, 0x0b,
- 0x5a, 0x0a, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x09, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x00, 0x74, 0x01, 0x64, 0x04, 0x55, 0x06, 0x4a, 0x0a, 0x42, 0x0d, 0x3a,
- 0x10, 0x34, 0x14, 0x2f, 0x17, 0x2a, 0x1a, 0x26, 0x1d, 0x23, 0x21, 0x21,
- 0x22, 0x1d, 0x26, 0x1b, 0x28, 0x19, 0x2b, 0x18, 0x2c, 0x16, 0x30, 0x15,
- 0x30, 0x12, 0x33, 0x12, 0x41, 0x3a, 0x42, 0x32, 0x44, 0x2a, 0x44, 0x25,
- 0x46, 0x21, 0x48, 0x1d, 0x4a, 0x1a, 0x4b, 0x17, 0x4d, 0x15, 0x4e, 0x13,
- 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x55, 0x0c, 0x56, 0x0c,
- 0x58, 0x0b, 0x5a, 0x0a, 0x5a, 0x09, 0x5b, 0x09, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00,
- 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00,
- 0x6b, 0x00, 0x6e, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22,
- 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00,
- 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x6e, 0x00,
- 0x50, 0x00, 0x28, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00,
- 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00,
- 0x6b, 0x00, 0x6e, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22,
- 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00,
- 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00,
- 0x42, 0x32, 0x43, 0x2c, 0x44, 0x26, 0x45, 0x22, 0x48, 0x1f, 0x49, 0x1b,
- 0x4b, 0x19, 0x4c, 0x16, 0x4e, 0x15, 0x4f, 0x13, 0x50, 0x11, 0x52, 0x10,
- 0x53, 0x0e, 0x55, 0x0e, 0x55, 0x0c, 0x56, 0x0c, 0x57, 0x0b, 0x59, 0x0b,
- 0x5a, 0x0a, 0x5a, 0x09, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x75, 0x01, 0x65,
- 0x03, 0x58, 0x05, 0x4d, 0x09, 0x45, 0x0c, 0x3e, 0x0f, 0x37, 0x12, 0x32,
- 0x16, 0x2d, 0x18, 0x2a, 0x1b, 0x26, 0x1d, 0x22, 0x21, 0x21, 0x22, 0x1d,
- 0x26, 0x1c, 0x27, 0x19, 0x2b, 0x19, 0x2b, 0x16, 0x2e, 0x16, 0x30, 0x14,
- 0x41, 0x3a, 0x42, 0x32, 0x43, 0x2c, 0x44, 0x26, 0x46, 0x22, 0x48, 0x1f,
- 0x49, 0x1b, 0x4a, 0x19, 0x4c, 0x16, 0x4e, 0x15, 0x4f, 0x13, 0x50, 0x11,
- 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0e, 0x54, 0x0c, 0x57, 0x0c, 0x57, 0x0b,
- 0x59, 0x0b, 0x5a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00,
- 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00,
- 0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00,
- 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00,
- 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x72, 0x00, 0x5a, 0x00, 0x3a, 0x00,
- 0x1b, 0x00, 0x01, 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00,
- 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00,
- 0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00,
- 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00,
- 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x42, 0x33, 0x43, 0x2d,
- 0x44, 0x28, 0x45, 0x23, 0x47, 0x20, 0x48, 0x1d, 0x4a, 0x1a, 0x4a, 0x18,
- 0x4c, 0x16, 0x4e, 0x14, 0x4f, 0x13, 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e,
- 0x55, 0x0e, 0x54, 0x0d, 0x57, 0x0c, 0x57, 0x0b, 0x58, 0x0b, 0x5a, 0x0b,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x00, 0x76, 0x01, 0x67, 0x02, 0x5a, 0x05, 0x50,
- 0x07, 0x47, 0x0a, 0x40, 0x0d, 0x3a, 0x10, 0x35, 0x12, 0x30, 0x16, 0x2c,
- 0x19, 0x29, 0x1b, 0x26, 0x1d, 0x22, 0x21, 0x21, 0x22, 0x1d, 0x26, 0x1d,
- 0x26, 0x1a, 0x2a, 0x19, 0x2b, 0x17, 0x2d, 0x16, 0x41, 0x3b, 0x42, 0x33,
- 0x43, 0x2d, 0x44, 0x28, 0x45, 0x23, 0x47, 0x20, 0x48, 0x1d, 0x49, 0x1a,
- 0x4b, 0x18, 0x4c, 0x16, 0x4e, 0x14, 0x4f, 0x13, 0x50, 0x11, 0x52, 0x10,
- 0x53, 0x0e, 0x54, 0x0e, 0x55, 0x0d, 0x57, 0x0c, 0x57, 0x0b, 0x58, 0x0b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00,
- 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b, 0x00, 0x00, 0x7c, 0x00, 0x75,
- 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00,
- 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00,
- 0x57, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00,
- 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00,
- 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b, 0x00, 0x00, 0x7c, 0x00, 0x75,
- 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00,
- 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00,
- 0x57, 0x00, 0x5b, 0x00, 0x42, 0x34, 0x43, 0x2e, 0x44, 0x29, 0x45, 0x25,
- 0x46, 0x21, 0x48, 0x1e, 0x49, 0x1b, 0x4a, 0x19, 0x4c, 0x17, 0x4d, 0x15,
- 0x4e, 0x14, 0x50, 0x13, 0x50, 0x11, 0x52, 0x11, 0x52, 0x0f, 0x53, 0x0e,
- 0x55, 0x0d, 0x56, 0x0c, 0x57, 0x0c, 0x57, 0x0b, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x00, 0x77, 0x00, 0x68, 0x02, 0x5c, 0x05, 0x52, 0x07, 0x4a, 0x0a, 0x43,
- 0x0c, 0x3d, 0x0f, 0x37, 0x12, 0x33, 0x14, 0x2f, 0x16, 0x2b, 0x19, 0x28,
- 0x1c, 0x26, 0x1d, 0x22, 0x21, 0x22, 0x21, 0x1e, 0x25, 0x1d, 0x26, 0x1a,
- 0x29, 0x19, 0x2b, 0x18, 0x41, 0x3b, 0x42, 0x34, 0x43, 0x2e, 0x44, 0x29,
- 0x45, 0x25, 0x46, 0x21, 0x48, 0x1e, 0x48, 0x1b, 0x4b, 0x19, 0x4c, 0x17,
- 0x4d, 0x15, 0x4e, 0x14, 0x50, 0x13, 0x50, 0x11, 0x52, 0x11, 0x51, 0x0f,
- 0x54, 0x0e, 0x55, 0x0d, 0x56, 0x0c, 0x57, 0x0c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00,
- 0x4c, 0x00, 0x51, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56,
- 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
- 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00,
- 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00,
- 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00,
- 0x4c, 0x00, 0x51, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56,
- 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
- 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00,
- 0x42, 0x34, 0x43, 0x2f, 0x44, 0x2a, 0x44, 0x26, 0x46, 0x22, 0x47, 0x1f,
- 0x48, 0x1d, 0x49, 0x1a, 0x4b, 0x18, 0x4c, 0x17, 0x4e, 0x15, 0x4e, 0x13,
- 0x50, 0x13, 0x50, 0x11, 0x52, 0x11, 0x51, 0x0f, 0x54, 0x0e, 0x55, 0x0d,
- 0x56, 0x0c, 0x57, 0x0c, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x77, 0x00, 0x69,
- 0x02, 0x5e, 0x04, 0x55, 0x06, 0x4c, 0x09, 0x45, 0x0c, 0x3f, 0x0e, 0x3a,
- 0x10, 0x35, 0x12, 0x31, 0x16, 0x2e, 0x18, 0x2b, 0x19, 0x27, 0x1d, 0x26,
- 0x1e, 0x22, 0x21, 0x22, 0x21, 0x1e, 0x25, 0x1d, 0x26, 0x1b, 0x28, 0x19,
- 0x41, 0x3b, 0x42, 0x34, 0x43, 0x2f, 0x43, 0x2a, 0x45, 0x26, 0x46, 0x22,
- 0x47, 0x1f, 0x48, 0x1d, 0x4a, 0x1a, 0x4b, 0x18, 0x4c, 0x17, 0x4e, 0x15,
- 0x4e, 0x13, 0x50, 0x13, 0x50, 0x11, 0x51, 0x11, 0x52, 0x0f, 0x54, 0x0e,
- 0x55, 0x0d, 0x56, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,
- 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00,
- 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37,
- 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00,
- 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00,
- 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00,
- 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00,
- 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37,
- 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00,
- 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x42, 0x35, 0x43, 0x30,
- 0x44, 0x2b, 0x44, 0x27, 0x45, 0x24, 0x46, 0x21, 0x48, 0x1e, 0x48, 0x1c,
- 0x4b, 0x1a, 0x4b, 0x18, 0x4c, 0x16, 0x4e, 0x15, 0x4e, 0x13, 0x50, 0x12,
- 0x50, 0x11, 0x51, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x55, 0x0e, 0x55, 0x0c,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x00, 0x77, 0x00, 0x6b, 0x02, 0x60, 0x04, 0x57,
- 0x05, 0x4f, 0x07, 0x48, 0x0a, 0x42, 0x0c, 0x3c, 0x0f, 0x38, 0x12, 0x34,
- 0x14, 0x30, 0x16, 0x2c, 0x19, 0x2b, 0x19, 0x26, 0x1d, 0x25, 0x1e, 0x22,
- 0x21, 0x22, 0x21, 0x1e, 0x25, 0x1d, 0x26, 0x1c, 0x41, 0x3b, 0x42, 0x35,
- 0x43, 0x30, 0x43, 0x2b, 0x44, 0x27, 0x45, 0x24, 0x46, 0x21, 0x47, 0x1e,
- 0x49, 0x1c, 0x4b, 0x1a, 0x4b, 0x18, 0x4c, 0x16, 0x4e, 0x15, 0x4e, 0x13,
- 0x50, 0x12, 0x50, 0x11, 0x52, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x55, 0x0e,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00,
- 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x00, 0x7d, 0x00, 0x7a,
- 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f,
- 0x00, 0x0e, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00,
- 0x34, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00,
- 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00,
- 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x00, 0x7d, 0x00, 0x7a,
- 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f,
- 0x00, 0x0e, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00,
- 0x34, 0x00, 0x3b, 0x00, 0x42, 0x36, 0x43, 0x30, 0x44, 0x2c, 0x44, 0x28,
- 0x45, 0x25, 0x46, 0x22, 0x48, 0x1f, 0x48, 0x1d, 0x49, 0x1a, 0x4b, 0x19,
- 0x4c, 0x18, 0x4d, 0x15, 0x4e, 0x15, 0x4f, 0x13, 0x50, 0x12, 0x50, 0x11,
- 0x52, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x55, 0x0e, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x00, 0x77, 0x00, 0x6c, 0x02, 0x61, 0x04, 0x58, 0x05, 0x51, 0x07, 0x4a,
- 0x0a, 0x44, 0x0c, 0x3f, 0x0f, 0x3a, 0x10, 0x35, 0x12, 0x32, 0x16, 0x30,
- 0x16, 0x2b, 0x19, 0x2a, 0x1a, 0x26, 0x1d, 0x25, 0x1e, 0x22, 0x21, 0x22,
- 0x21, 0x1e, 0x25, 0x1d, 0x41, 0x3b, 0x42, 0x36, 0x43, 0x30, 0x43, 0x2c,
- 0x44, 0x28, 0x45, 0x25, 0x46, 0x22, 0x47, 0x1f, 0x49, 0x1d, 0x49, 0x1a,
- 0x4b, 0x19, 0x4c, 0x18, 0x4d, 0x15, 0x4e, 0x15, 0x4f, 0x13, 0x4f, 0x12,
- 0x51, 0x11, 0x52, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00,
- 0x29, 0x00, 0x30, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69,
- 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d,
- 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00,
- 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00,
- 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00,
- 0x29, 0x00, 0x30, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69,
- 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d,
- 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00,
- 0x42, 0x36, 0x42, 0x31, 0x43, 0x2d, 0x44, 0x29, 0x45, 0x26, 0x46, 0x23,
- 0x47, 0x20, 0x47, 0x1e, 0x49, 0x1c, 0x4b, 0x1a, 0x4b, 0x18, 0x4c, 0x17,
- 0x4d, 0x15, 0x4e, 0x14, 0x4f, 0x13, 0x4f, 0x12, 0x51, 0x11, 0x52, 0x11,
- 0x52, 0x0f, 0x54, 0x0e, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x78, 0x00, 0x6d,
- 0x01, 0x62, 0x03, 0x5a, 0x05, 0x52, 0x07, 0x4c, 0x09, 0x46, 0x0b, 0x41,
- 0x0c, 0x3c, 0x0f, 0x38, 0x12, 0x35, 0x12, 0x30, 0x16, 0x2e, 0x17, 0x2b,
- 0x19, 0x29, 0x1b, 0x26, 0x1d, 0x25, 0x1e, 0x22, 0x21, 0x22, 0x21, 0x1f,
- 0x41, 0x3c, 0x42, 0x36, 0x42, 0x31, 0x43, 0x2d, 0x44, 0x29, 0x45, 0x26,
- 0x46, 0x23, 0x46, 0x20, 0x48, 0x1e, 0x49, 0x1c, 0x4b, 0x1a, 0x4b, 0x18,
- 0x4c, 0x17, 0x4d, 0x15, 0x4e, 0x14, 0x4e, 0x13, 0x50, 0x12, 0x51, 0x11,
- 0x52, 0x11, 0x52, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00,
- 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53,
- 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00,
- 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00,
- 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00,
- 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00,
- 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53,
- 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00,
- 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x42, 0x37, 0x42, 0x32,
- 0x43, 0x2d, 0x44, 0x2a, 0x45, 0x27, 0x45, 0x23, 0x46, 0x21, 0x47, 0x1f,
- 0x49, 0x1d, 0x49, 0x1a, 0x4b, 0x19, 0x4c, 0x18, 0x4c, 0x16, 0x4e, 0x15,
- 0x4e, 0x14, 0x4f, 0x13, 0x50, 0x12, 0x51, 0x11, 0x52, 0x11, 0x52, 0x0f,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00,
- 0x83, 0x00, 0x83, 0x00, 0x00, 0x78, 0x00, 0x6e, 0x01, 0x64, 0x02, 0x5b,
- 0x04, 0x54, 0x06, 0x4e, 0x07, 0x47, 0x0a, 0x42, 0x0c, 0x3e, 0x0f, 0x3b,
- 0x0f, 0x35, 0x12, 0x33, 0x14, 0x30, 0x16, 0x2d, 0x19, 0x2b, 0x19, 0x28,
- 0x1c, 0x26, 0x1d, 0x25, 0x1f, 0x22, 0x21, 0x22, 0x41, 0x3c, 0x42, 0x37,
- 0x42, 0x32, 0x43, 0x2d, 0x44, 0x2a, 0x45, 0x27, 0x45, 0x23, 0x46, 0x21,
- 0x48, 0x1f, 0x49, 0x1d, 0x49, 0x1a, 0x4b, 0x19, 0x4c, 0x18, 0x4c, 0x16,
- 0x4e, 0x15, 0x4d, 0x14, 0x50, 0x13, 0x50, 0x12, 0x51, 0x11, 0x52, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b, 0x00, 0x00, 0x7e, 0x00, 0x7c,
- 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e,
- 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x0a, 0x00,
- 0x13, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00,
- 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00,
- 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b, 0x00, 0x00, 0x7e, 0x00, 0x7c,
- 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e,
- 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x0a, 0x00,
- 0x13, 0x00, 0x1b, 0x00, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x61, 0x20, 0x4d, 0x2a,
- 0x48, 0x30, 0x44, 0x33, 0x44, 0x35, 0x44, 0x36, 0x43, 0x37, 0x42, 0x38,
- 0x43, 0x39, 0x42, 0x39, 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b, 0x42, 0x3b,
- 0x42, 0x3b, 0x41, 0x3b, 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c,
- 0x04, 0x3d, 0x22, 0x3d, 0x2b, 0x3d, 0x30, 0x3d, 0x33, 0x3d, 0x35, 0x3d,
- 0x37, 0x3d, 0x38, 0x3d, 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
- 0x3b, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d,
- 0x3c, 0x3d, 0x3c, 0x3d, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x09, 0x00, 0x12, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71,
- 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c,
- 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00,
- 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00,
- 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00,
- 0x09, 0x00, 0x12, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71,
- 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c,
- 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x6c, 0x0b, 0x57, 0x16, 0x4f, 0x1d, 0x4a, 0x22,
- 0x48, 0x26, 0x47, 0x29, 0x46, 0x2b, 0x44, 0x2d, 0x44, 0x2f, 0x44, 0x30,
- 0x44, 0x31, 0x44, 0x32, 0x43, 0x33, 0x43, 0x34, 0x43, 0x34, 0x42, 0x35,
- 0x43, 0x36, 0x42, 0x36, 0x42, 0x37, 0x42, 0x37, 0x00, 0x5d, 0x0c, 0x49,
- 0x16, 0x43, 0x1d, 0x41, 0x22, 0x40, 0x26, 0x3f, 0x29, 0x3f, 0x2c, 0x3f,
- 0x2e, 0x3e, 0x2f, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x33, 0x3e, 0x33, 0x3e,
- 0x34, 0x3e, 0x35, 0x3e, 0x35, 0x3e, 0x36, 0x3e, 0x37, 0x3e, 0x37, 0x3e,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
- 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62,
- 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e,
- 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00,
- 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00,
- 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00,
- 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62,
- 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e,
- 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x08, 0x00, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x72, 0x06, 0x5f, 0x0d, 0x56, 0x14, 0x4f, 0x19, 0x4d, 0x1d, 0x4a, 0x20,
- 0x49, 0x23, 0x47, 0x25, 0x46, 0x27, 0x46, 0x29, 0x45, 0x2a, 0x45, 0x2c,
- 0x44, 0x2d, 0x44, 0x2e, 0x44, 0x2f, 0x43, 0x30, 0x44, 0x30, 0x44, 0x31,
- 0x43, 0x32, 0x43, 0x33, 0x00, 0x68, 0x06, 0x54, 0x0d, 0x4b, 0x14, 0x47,
- 0x19, 0x44, 0x1d, 0x43, 0x20, 0x41, 0x23, 0x41, 0x26, 0x40, 0x27, 0x40,
- 0x29, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f, 0x2d, 0x3f, 0x2e, 0x3f, 0x2f, 0x3f,
- 0x30, 0x3f, 0x30, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d,
- 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51,
- 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12,
- 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00,
- 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00,
- 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d,
- 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51,
- 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12,
- 0x00, 0x08, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x75, 0x03, 0x64, 0x09,
- 0x5a, 0x0e, 0x54, 0x13, 0x51, 0x17, 0x4e, 0x1a, 0x4c, 0x1d, 0x49, 0x1f,
- 0x49, 0x22, 0x48, 0x23, 0x47, 0x25, 0x46, 0x26, 0x46, 0x28, 0x45, 0x29,
- 0x45, 0x2a, 0x44, 0x2b, 0x44, 0x2c, 0x44, 0x2d, 0x44, 0x2e, 0x44, 0x2e,
- 0x00, 0x6d, 0x04, 0x5b, 0x09, 0x51, 0x0e, 0x4c, 0x13, 0x48, 0x17, 0x46,
- 0x1a, 0x44, 0x1d, 0x43, 0x1f, 0x42, 0x22, 0x42, 0x24, 0x41, 0x25, 0x41,
- 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f,
- 0x2d, 0x3f, 0x2e, 0x3f, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x3f, 0x00, 0x66, 0x00, 0x72, 0x00,
- 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00,
- 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x00, 0x3f,
- 0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c,
- 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e,
- 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x77, 0x02, 0x68, 0x06, 0x5f, 0x0b, 0x58, 0x0f,
- 0x54, 0x12, 0x51, 0x15, 0x4f, 0x18, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1f,
- 0x49, 0x21, 0x48, 0x22, 0x48, 0x23, 0x47, 0x25, 0x46, 0x26, 0x45, 0x27,
- 0x45, 0x28, 0x45, 0x29, 0x45, 0x2a, 0x44, 0x2b, 0x00, 0x70, 0x02, 0x60,
- 0x07, 0x56, 0x0b, 0x50, 0x0f, 0x4c, 0x12, 0x49, 0x16, 0x47, 0x18, 0x46,
- 0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x43, 0x21, 0x42, 0x22, 0x42, 0x24, 0x41,
- 0x25, 0x41, 0x26, 0x40, 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3f, 0x0a, 0x0a, 0x3f, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x71, 0x00,
- 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00,
- 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x0a, 0x00, 0x3f, 0x00, 0x5c,
- 0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a,
- 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x78, 0x02, 0x6b, 0x05, 0x62, 0x08, 0x5b, 0x0c, 0x57, 0x0f, 0x54, 0x12,
- 0x51, 0x14, 0x4e, 0x17, 0x4d, 0x19, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e,
- 0x49, 0x20, 0x48, 0x21, 0x48, 0x22, 0x46, 0x24, 0x46, 0x25, 0x46, 0x26,
- 0x46, 0x27, 0x45, 0x27, 0x00, 0x72, 0x02, 0x64, 0x05, 0x5b, 0x08, 0x54,
- 0x0c, 0x50, 0x0f, 0x4d, 0x12, 0x4a, 0x14, 0x48, 0x17, 0x47, 0x19, 0x46,
- 0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x44, 0x20, 0x42, 0x21, 0x42, 0x22, 0x42,
- 0x24, 0x41, 0x25, 0x41, 0x26, 0x41, 0x27, 0x40, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x3f,
- 0x03, 0x03, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00, 0x63, 0x00, 0x6a, 0x00,
- 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00,
- 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x66, 0x00, 0x3f, 0x00, 0x03, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59,
- 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76,
- 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x79, 0x01, 0x6d, 0x04,
- 0x65, 0x07, 0x5e, 0x0a, 0x5a, 0x0d, 0x56, 0x0f, 0x54, 0x12, 0x51, 0x14,
- 0x4f, 0x16, 0x4e, 0x18, 0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e,
- 0x49, 0x1f, 0x48, 0x21, 0x48, 0x22, 0x48, 0x23, 0x47, 0x23, 0x46, 0x25,
- 0x00, 0x74, 0x01, 0x66, 0x04, 0x5e, 0x07, 0x57, 0x0a, 0x53, 0x0d, 0x4f,
- 0x10, 0x4d, 0x12, 0x4b, 0x14, 0x49, 0x16, 0x48, 0x18, 0x46, 0x1a, 0x45,
- 0x1b, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x20, 0x43, 0x21, 0x42, 0x22, 0x42,
- 0x23, 0x42, 0x24, 0x41, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c, 0x00, 0x2d, 0x01, 0x01,
- 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64, 0x00,
- 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c, 0x00,
- 0x2d, 0x00, 0x01, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56,
- 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71,
- 0x00, 0x73, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x7a, 0x01, 0x6f, 0x03, 0x67, 0x06, 0x60, 0x08,
- 0x5d, 0x0b, 0x59, 0x0d, 0x56, 0x10, 0x53, 0x11, 0x51, 0x14, 0x50, 0x15,
- 0x4e, 0x17, 0x4d, 0x19, 0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x48, 0x1e,
- 0x49, 0x1f, 0x49, 0x20, 0x48, 0x21, 0x48, 0x22, 0x00, 0x75, 0x01, 0x69,
- 0x03, 0x61, 0x06, 0x5a, 0x08, 0x56, 0x0b, 0x52, 0x0d, 0x4f, 0x10, 0x4d,
- 0x12, 0x4b, 0x14, 0x4a, 0x16, 0x48, 0x17, 0x47, 0x19, 0x46, 0x1a, 0x45,
- 0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x20, 0x43, 0x21, 0x42,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00, 0x00, 0x1b, 0x00,
- 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61, 0x00,
- 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00,
- 0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54,
- 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x7b, 0x01, 0x71, 0x02, 0x69, 0x05, 0x62, 0x07, 0x5f, 0x09, 0x5b, 0x0c,
- 0x58, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x15, 0x4e, 0x16,
- 0x4e, 0x18, 0x4c, 0x19, 0x4c, 0x1a, 0x4a, 0x1c, 0x4b, 0x1d, 0x49, 0x1e,
- 0x49, 0x1f, 0x49, 0x20, 0x00, 0x76, 0x01, 0x6b, 0x03, 0x63, 0x05, 0x5d,
- 0x07, 0x58, 0x09, 0x54, 0x0c, 0x52, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c,
- 0x13, 0x4a, 0x15, 0x49, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x45,
- 0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x71,
- 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x16, 0x00, 0x28, 0x00,
- 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e, 0x00,
- 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x00,
- 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53,
- 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7b, 0x00, 0x72, 0x02,
- 0x6b, 0x04, 0x64, 0x06, 0x61, 0x08, 0x5d, 0x0a, 0x5a, 0x0c, 0x56, 0x0e,
- 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x15, 0x4f, 0x16, 0x4e, 0x17,
- 0x4d, 0x18, 0x4b, 0x1a, 0x4b, 0x1a, 0x4b, 0x1c, 0x4b, 0x1d, 0x49, 0x1d,
- 0x00, 0x77, 0x00, 0x6c, 0x02, 0x65, 0x04, 0x5f, 0x06, 0x5a, 0x08, 0x57,
- 0x0a, 0x54, 0x0c, 0x51, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c, 0x13, 0x4a,
- 0x15, 0x49, 0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x1a, 0x46, 0x1b, 0x45,
- 0x1c, 0x45, 0x1d, 0x45, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a,
- 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30, 0x00,
- 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75, 0x00,
- 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x13,
- 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52,
- 0x00, 0x57, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x7c, 0x00, 0x73, 0x02, 0x6c, 0x03, 0x66, 0x05,
- 0x63, 0x07, 0x5e, 0x09, 0x5c, 0x0b, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x10,
- 0x53, 0x11, 0x52, 0x13, 0x50, 0x14, 0x4f, 0x15, 0x4e, 0x17, 0x4c, 0x18,
- 0x4c, 0x19, 0x4c, 0x1a, 0x4b, 0x1a, 0x4b, 0x1c, 0x00, 0x77, 0x00, 0x6e,
- 0x02, 0x66, 0x04, 0x61, 0x05, 0x5c, 0x07, 0x59, 0x09, 0x56, 0x0b, 0x53,
- 0x0d, 0x51, 0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a,
- 0x15, 0x48, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x46, 0x1b, 0x45,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28,
- 0x00, 0x13, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35, 0x00,
- 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00,
- 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
- 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x7c, 0x00, 0x74, 0x02, 0x6e, 0x03, 0x68, 0x05, 0x64, 0x06, 0x60, 0x08,
- 0x5d, 0x0a, 0x5a, 0x0b, 0x58, 0x0d, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11,
- 0x52, 0x13, 0x50, 0x14, 0x50, 0x15, 0x4d, 0x16, 0x4e, 0x18, 0x4c, 0x18,
- 0x4c, 0x19, 0x4c, 0x1a, 0x00, 0x77, 0x00, 0x6f, 0x02, 0x68, 0x03, 0x63,
- 0x05, 0x5e, 0x06, 0x5a, 0x08, 0x57, 0x0a, 0x55, 0x0b, 0x53, 0x0d, 0x50,
- 0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x49,
- 0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x19, 0x46, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x79,
- 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10,
- 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, 0x00,
- 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00,
- 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27,
- 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x75, 0x01,
- 0x6f, 0x02, 0x69, 0x04, 0x65, 0x06, 0x62, 0x07, 0x5f, 0x09, 0x5b, 0x0b,
- 0x5a, 0x0c, 0x58, 0x0d, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13,
- 0x50, 0x13, 0x4f, 0x15, 0x4e, 0x15, 0x4e, 0x17, 0x4d, 0x18, 0x4c, 0x18,
- 0x00, 0x78, 0x00, 0x70, 0x01, 0x69, 0x03, 0x64, 0x04, 0x60, 0x06, 0x5c,
- 0x07, 0x59, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x52, 0x0d, 0x50, 0x0f, 0x4f,
- 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x48,
- 0x17, 0x48, 0x18, 0x47, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64,
- 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00,
- 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a, 0x00,
- 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00,
- 0x0e, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c,
- 0x00, 0x34, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x76, 0x01, 0x70, 0x02, 0x6a, 0x03,
- 0x67, 0x05, 0x63, 0x06, 0x60, 0x08, 0x5d, 0x09, 0x5b, 0x0b, 0x59, 0x0c,
- 0x57, 0x0d, 0x55, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x4f, 0x13,
- 0x50, 0x15, 0x4f, 0x15, 0x4e, 0x16, 0x4e, 0x18, 0x00, 0x78, 0x00, 0x71,
- 0x01, 0x6a, 0x03, 0x66, 0x04, 0x61, 0x05, 0x5d, 0x06, 0x5a, 0x08, 0x58,
- 0x09, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0e, 0x50, 0x0f, 0x4e, 0x10, 0x4e,
- 0x11, 0x4c, 0x13, 0x4c, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x49, 0x16, 0x48,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b,
- 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x0c, 0x00,
- 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00,
- 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00,
- 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x7d, 0x00, 0x76, 0x01, 0x71, 0x02, 0x6c, 0x03, 0x68, 0x05, 0x64, 0x06,
- 0x61, 0x07, 0x5e, 0x09, 0x5c, 0x0a, 0x5a, 0x0b, 0x59, 0x0c, 0x57, 0x0e,
- 0x55, 0x0e, 0x55, 0x11, 0x52, 0x11, 0x51, 0x12, 0x51, 0x13, 0x50, 0x14,
- 0x4f, 0x15, 0x4e, 0x15, 0x00, 0x79, 0x00, 0x71, 0x01, 0x6c, 0x02, 0x66,
- 0x04, 0x62, 0x05, 0x5f, 0x06, 0x5c, 0x07, 0x59, 0x09, 0x57, 0x0a, 0x55,
- 0x0b, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c,
- 0x13, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x4a, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c,
- 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35,
- 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00,
- 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00,
- 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00,
- 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x77, 0x01,
- 0x72, 0x02, 0x6d, 0x03, 0x69, 0x04, 0x66, 0x06, 0x63, 0x07, 0x5f, 0x08,
- 0x5e, 0x09, 0x5c, 0x0b, 0x5a, 0x0c, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x0f,
- 0x54, 0x11, 0x51, 0x11, 0x52, 0x12, 0x51, 0x13, 0x50, 0x14, 0x50, 0x15,
- 0x00, 0x79, 0x00, 0x72, 0x01, 0x6d, 0x02, 0x68, 0x03, 0x63, 0x04, 0x60,
- 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x53,
- 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c,
- 0x13, 0x4b, 0x14, 0x4a, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f,
- 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23,
- 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00,
- 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00,
- 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0a,
- 0x00, 0x13, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x78, 0x01, 0x72, 0x02, 0x6e, 0x02,
- 0x6a, 0x03, 0x67, 0x05, 0x64, 0x06, 0x60, 0x07, 0x5f, 0x09, 0x5c, 0x0a,
- 0x5b, 0x0b, 0x5a, 0x0c, 0x57, 0x0c, 0x56, 0x0e, 0x55, 0x0f, 0x53, 0x11,
- 0x52, 0x11, 0x52, 0x12, 0x51, 0x13, 0x50, 0x13, 0x00, 0x79, 0x00, 0x73,
- 0x01, 0x6d, 0x02, 0x69, 0x03, 0x65, 0x04, 0x61, 0x05, 0x5e, 0x06, 0x5c,
- 0x07, 0x59, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54, 0x0d, 0x53, 0x0d, 0x51,
- 0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c, 0x13, 0x4b,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e,
- 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15,
- 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00,
- 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00,
- 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x7e, 0x00, 0x78, 0x01, 0x73, 0x02, 0x6e, 0x02, 0x6b, 0x03, 0x68, 0x05,
- 0x65, 0x06, 0x62, 0x07, 0x5f, 0x07, 0x5e, 0x09, 0x5c, 0x0b, 0x5a, 0x0b,
- 0x59, 0x0c, 0x57, 0x0d, 0x56, 0x0e, 0x54, 0x0f, 0x54, 0x11, 0x52, 0x11,
- 0x52, 0x12, 0x51, 0x13, 0x00, 0x79, 0x00, 0x73, 0x01, 0x6e, 0x02, 0x69,
- 0x03, 0x66, 0x04, 0x62, 0x05, 0x5f, 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58,
- 0x09, 0x56, 0x0b, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50,
- 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4d, 0x12, 0x4c, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d,
- 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c,
- 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09,
- 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00,
- 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00,
- 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x78, 0x00,
- 0x74, 0x01, 0x6f, 0x02, 0x6c, 0x03, 0x68, 0x04, 0x65, 0x05, 0x62, 0x06,
- 0x61, 0x07, 0x5f, 0x09, 0x5c, 0x09, 0x5b, 0x0b, 0x5a, 0x0b, 0x58, 0x0c,
- 0x57, 0x0d, 0x55, 0x0e, 0x55, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x52, 0x12,
- 0x00, 0x79, 0x00, 0x74, 0x00, 0x6f, 0x02, 0x6a, 0x03, 0x66, 0x04, 0x63,
- 0x05, 0x60, 0x05, 0x5e, 0x06, 0x5b, 0x07, 0x59, 0x09, 0x58, 0x09, 0x55,
- 0x0b, 0x55, 0x0c, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50, 0x0f, 0x4e,
- 0x11, 0x4e, 0x11, 0x4d, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75,
- 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b,
- 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00,
- 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00,
- 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x79, 0x00, 0x74, 0x01, 0x70, 0x02,
- 0x6c, 0x03, 0x69, 0x03, 0x66, 0x05, 0x63, 0x06, 0x62, 0x07, 0x5f, 0x07,
- 0x5e, 0x09, 0x5c, 0x0a, 0x5a, 0x0b, 0x5a, 0x0c, 0x57, 0x0c, 0x56, 0x0e,
- 0x55, 0x0e, 0x55, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x00, 0x79, 0x00, 0x74,
- 0x00, 0x70, 0x01, 0x6b, 0x02, 0x67, 0x03, 0x64, 0x04, 0x61, 0x05, 0x5f,
- 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54,
- 0x0c, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x66, 0x7f, 0x4d, 0x68, 0x49, 0x5c, 0x47, 0x55, 0x45, 0x51, 0x45, 0x4e,
- 0x44, 0x4c, 0x43, 0x4a, 0x43, 0x49, 0x43, 0x48, 0x43, 0x47, 0x42, 0x47,
- 0x42, 0x46, 0x42, 0x46, 0x42, 0x45, 0x42, 0x45, 0x42, 0x45, 0x42, 0x44,
- 0x42, 0x44, 0x42, 0x44, 0x57, 0x7f, 0x2e, 0x58, 0x34, 0x4d, 0x37, 0x49,
- 0x39, 0x47, 0x3a, 0x45, 0x3b, 0x44, 0x3b, 0x44, 0x3c, 0x43, 0x3c, 0x43,
- 0x3c, 0x43, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x41,
- 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x99, 0x7f, 0x4d, 0x58,
- 0x49, 0x4d, 0x47, 0x49, 0x45, 0x47, 0x45, 0x45, 0x44, 0x44, 0x43, 0x44,
- 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
- 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x05,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xa5, 0x16, 0x74, 0x23,
- 0x62, 0x29, 0x59, 0x2d, 0x53, 0x30, 0x50, 0x32, 0x4e, 0x34, 0x4c, 0x35,
- 0x4a, 0x36, 0x49, 0x37, 0x48, 0x38, 0x48, 0x38, 0x47, 0x39, 0x46, 0x39,
- 0x46, 0x39, 0x46, 0x3a, 0x45, 0x3a, 0x45, 0x3a, 0x45, 0x3a, 0x44, 0x3b,
- 0x23, 0x2f, 0x25, 0x35, 0x2a, 0x37, 0x2e, 0x39, 0x31, 0x3a, 0x33, 0x3b,
- 0x34, 0x3b, 0x35, 0x3c, 0x37, 0x3c, 0x37, 0x3c, 0x38, 0x3d, 0x38, 0x3d,
- 0x39, 0x3d, 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
- 0x3b, 0x3d, 0x3b, 0x3d, 0x77, 0x27, 0x5f, 0x31, 0x56, 0x35, 0x52, 0x38,
- 0x4f, 0x39, 0x4c, 0x3a, 0x4b, 0x3b, 0x49, 0x3b, 0x48, 0x3c, 0x48, 0x3c,
- 0x47, 0x3c, 0x47, 0x3c, 0x46, 0x3d, 0x46, 0x3d, 0x45, 0x3d, 0x45, 0x3d,
- 0x45, 0x3d, 0x44, 0x3d, 0x44, 0x3d, 0x44, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x5f, 0x00,
- 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0xbb, 0x01, 0x91, 0x09, 0x78, 0x11, 0x6b, 0x17,
- 0x62, 0x1c, 0x5c, 0x20, 0x58, 0x23, 0x55, 0x25, 0x52, 0x28, 0x51, 0x2a,
- 0x4f, 0x2b, 0x4e, 0x2c, 0x4d, 0x2e, 0x4c, 0x2f, 0x4b, 0x30, 0x4a, 0x31,
- 0x49, 0x31, 0x49, 0x32, 0x48, 0x33, 0x47, 0x33, 0x22, 0x25, 0x23, 0x2a,
- 0x26, 0x2e, 0x2a, 0x31, 0x2c, 0x33, 0x2e, 0x34, 0x30, 0x36, 0x31, 0x37,
- 0x32, 0x37, 0x33, 0x38, 0x34, 0x38, 0x35, 0x39, 0x36, 0x39, 0x36, 0x3a,
- 0x37, 0x3a, 0x37, 0x3a, 0x38, 0x3a, 0x38, 0x3b, 0x39, 0x3b, 0x39, 0x3b,
- 0x7a, 0x1a, 0x68, 0x24, 0x5f, 0x2a, 0x5a, 0x2e, 0x55, 0x31, 0x53, 0x33,
- 0x51, 0x34, 0x4f, 0x35, 0x4d, 0x36, 0x4c, 0x37, 0x4b, 0x38, 0x4b, 0x38,
- 0x4a, 0x39, 0x49, 0x39, 0x49, 0x39, 0x48, 0x3a, 0x47, 0x3a, 0x47, 0x3a,
- 0x46, 0x3b, 0x46, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x39, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x8b, 0x00, 0x44, 0x00, 0x02, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0xc6, 0x00, 0xa3, 0x02, 0x8a, 0x07, 0x7a, 0x0c, 0x6f, 0x11, 0x68, 0x15,
- 0x62, 0x18, 0x5e, 0x1b, 0x5b, 0x1d, 0x58, 0x20, 0x56, 0x22, 0x54, 0x23,
- 0x53, 0x25, 0x51, 0x26, 0x50, 0x28, 0x4e, 0x29, 0x4d, 0x2a, 0x4d, 0x2b,
- 0x4d, 0x2c, 0x4c, 0x2c, 0x22, 0x23, 0x22, 0x27, 0x25, 0x2a, 0x27, 0x2c,
- 0x2a, 0x2e, 0x2b, 0x30, 0x2d, 0x32, 0x2e, 0x33, 0x30, 0x34, 0x31, 0x34,
- 0x32, 0x35, 0x33, 0x36, 0x33, 0x36, 0x34, 0x37, 0x34, 0x37, 0x35, 0x38,
- 0x36, 0x38, 0x36, 0x39, 0x36, 0x39, 0x36, 0x39, 0x7b, 0x16, 0x6d, 0x1f,
- 0x65, 0x24, 0x5f, 0x28, 0x5b, 0x2b, 0x58, 0x2d, 0x55, 0x2f, 0x54, 0x31,
- 0x52, 0x32, 0x50, 0x33, 0x4f, 0x34, 0x4e, 0x35, 0x4d, 0x35, 0x4c, 0x36,
- 0x4b, 0x36, 0x4a, 0x37, 0x4a, 0x38, 0x4a, 0x38, 0x4a, 0x39, 0x49, 0x39,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35,
- 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xb3, 0x00, 0x9f, 0x00, 0x6d, 0x00, 0x33, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xcc, 0x00, 0xaf, 0x00,
- 0x98, 0x03, 0x87, 0x06, 0x7b, 0x0a, 0x73, 0x0e, 0x6c, 0x11, 0x67, 0x13,
- 0x63, 0x16, 0x5f, 0x18, 0x5c, 0x1a, 0x5a, 0x1c, 0x58, 0x1e, 0x56, 0x20,
- 0x55, 0x21, 0x54, 0x22, 0x52, 0x24, 0x51, 0x25, 0x50, 0x26, 0x4f, 0x27,
- 0x22, 0x22, 0x22, 0x25, 0x24, 0x27, 0x26, 0x2a, 0x28, 0x2b, 0x29, 0x2d,
- 0x2b, 0x2f, 0x2c, 0x30, 0x2d, 0x31, 0x2f, 0x32, 0x30, 0x33, 0x30, 0x33,
- 0x31, 0x34, 0x32, 0x35, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36, 0x34, 0x36,
- 0x35, 0x36, 0x35, 0x37, 0x7c, 0x15, 0x71, 0x1b, 0x68, 0x20, 0x63, 0x24,
- 0x5f, 0x27, 0x5c, 0x29, 0x59, 0x2c, 0x57, 0x2d, 0x55, 0x2f, 0x54, 0x30,
- 0x53, 0x31, 0x51, 0x32, 0x50, 0x32, 0x4f, 0x33, 0x4f, 0x34, 0x4e, 0x35,
- 0x4d, 0x35, 0x4c, 0x35, 0x4b, 0x35, 0x4a, 0x36, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x1d,
- 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa, 0x00,
- 0x85, 0x00, 0x57, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0xcf, 0x00, 0xb7, 0x00, 0xa2, 0x00, 0x92, 0x03,
- 0x85, 0x06, 0x7c, 0x09, 0x75, 0x0b, 0x6f, 0x0e, 0x6a, 0x11, 0x66, 0x13,
- 0x63, 0x15, 0x5f, 0x17, 0x5e, 0x19, 0x5c, 0x1a, 0x5a, 0x1c, 0x57, 0x1d,
- 0x56, 0x1f, 0x55, 0x1f, 0x55, 0x21, 0x54, 0x22, 0x22, 0x22, 0x22, 0x24,
- 0x23, 0x26, 0x25, 0x28, 0x26, 0x29, 0x28, 0x2b, 0x29, 0x2c, 0x2b, 0x2d,
- 0x2c, 0x2f, 0x2d, 0x30, 0x2d, 0x30, 0x2f, 0x31, 0x30, 0x32, 0x30, 0x33,
- 0x30, 0x33, 0x32, 0x33, 0x32, 0x34, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36,
- 0x7c, 0x14, 0x73, 0x19, 0x6c, 0x1e, 0x67, 0x22, 0x63, 0x24, 0x5f, 0x26,
- 0x5c, 0x28, 0x5a, 0x2a, 0x58, 0x2c, 0x57, 0x2d, 0x55, 0x2e, 0x53, 0x2f,
- 0x53, 0x30, 0x52, 0x31, 0x51, 0x31, 0x4f, 0x32, 0x4f, 0x33, 0x4f, 0x33,
- 0x4f, 0x34, 0x4e, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70, 0x00,
- 0x48, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0xd2, 0x00, 0xbd, 0x00, 0xaa, 0x00, 0x9b, 0x01, 0x8e, 0x03, 0x84, 0x05,
- 0x7c, 0x08, 0x76, 0x0a, 0x71, 0x0c, 0x6c, 0x0f, 0x69, 0x11, 0x66, 0x12,
- 0x63, 0x14, 0x60, 0x16, 0x5e, 0x17, 0x5d, 0x19, 0x5b, 0x1a, 0x59, 0x1b,
- 0x57, 0x1c, 0x56, 0x1e, 0x22, 0x22, 0x22, 0x23, 0x23, 0x25, 0x24, 0x27,
- 0x25, 0x28, 0x27, 0x29, 0x28, 0x2b, 0x29, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d,
- 0x2d, 0x2f, 0x2d, 0x30, 0x2d, 0x30, 0x2f, 0x30, 0x30, 0x32, 0x30, 0x33,
- 0x30, 0x33, 0x31, 0x33, 0x32, 0x33, 0x33, 0x33, 0x7d, 0x13, 0x75, 0x18,
- 0x6e, 0x1c, 0x69, 0x1f, 0x65, 0x22, 0x62, 0x24, 0x60, 0x26, 0x5c, 0x28,
- 0x5b, 0x29, 0x59, 0x2a, 0x57, 0x2c, 0x57, 0x2d, 0x55, 0x2e, 0x53, 0x2e,
- 0x53, 0x2f, 0x53, 0x31, 0x51, 0x31, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x32,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c,
- 0x00, 0x35, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xbb, 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d, 0x00,
- 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd3, 0x00, 0xc2, 0x00,
- 0xb1, 0x00, 0xa2, 0x00, 0x96, 0x02, 0x8c, 0x03, 0x83, 0x05, 0x7d, 0x07,
- 0x77, 0x09, 0x73, 0x0b, 0x6f, 0x0d, 0x6a, 0x0f, 0x68, 0x11, 0x66, 0x12,
- 0x63, 0x14, 0x60, 0x15, 0x5f, 0x16, 0x5e, 0x18, 0x5c, 0x19, 0x5a, 0x1a,
- 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x27, 0x26, 0x29,
- 0x27, 0x29, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2d, 0x2b, 0x2d, 0x2c, 0x2e,
- 0x2d, 0x2f, 0x2d, 0x30, 0x2e, 0x30, 0x2f, 0x30, 0x30, 0x31, 0x30, 0x32,
- 0x30, 0x33, 0x30, 0x33, 0x7d, 0x13, 0x76, 0x17, 0x70, 0x1b, 0x6b, 0x1e,
- 0x68, 0x20, 0x65, 0x22, 0x61, 0x24, 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x29,
- 0x5a, 0x2a, 0x58, 0x2b, 0x57, 0x2c, 0x57, 0x2d, 0x55, 0x2e, 0x53, 0x2e,
- 0x53, 0x2f, 0x53, 0x30, 0x53, 0x31, 0x51, 0x31, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f,
- 0x00, 0x25, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb6, 0x00,
- 0xa6, 0x00, 0x8e, 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0xd4, 0x00, 0xc5, 0x00, 0xb6, 0x00, 0xa8, 0x00,
- 0x9c, 0x00, 0x92, 0x02, 0x8a, 0x03, 0x82, 0x05, 0x7d, 0x07, 0x78, 0x09,
- 0x74, 0x0a, 0x71, 0x0c, 0x6c, 0x0e, 0x69, 0x0f, 0x68, 0x11, 0x65, 0x12,
- 0x63, 0x13, 0x60, 0x14, 0x5f, 0x16, 0x5e, 0x17, 0x21, 0x22, 0x22, 0x23,
- 0x22, 0x24, 0x23, 0x25, 0x24, 0x26, 0x25, 0x27, 0x27, 0x28, 0x27, 0x29,
- 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2e,
- 0x2d, 0x2f, 0x2d, 0x30, 0x2e, 0x30, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x31,
- 0x7d, 0x12, 0x77, 0x16, 0x71, 0x19, 0x6d, 0x1c, 0x69, 0x1f, 0x66, 0x20,
- 0x64, 0x23, 0x61, 0x24, 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x28, 0x5b, 0x2a,
- 0x58, 0x2a, 0x57, 0x2b, 0x57, 0x2c, 0x56, 0x2e, 0x54, 0x2e, 0x53, 0x2e,
- 0x53, 0x2e, 0x53, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21,
- 0x00, 0x18, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97, 0x00,
- 0x7e, 0x00, 0x64, 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0xd5, 0x00, 0xc7, 0x00, 0xba, 0x00, 0xad, 0x00, 0xa2, 0x00, 0x98, 0x01,
- 0x8f, 0x02, 0x88, 0x03, 0x82, 0x05, 0x7e, 0x07, 0x78, 0x08, 0x74, 0x0a,
- 0x72, 0x0b, 0x6e, 0x0c, 0x6b, 0x0e, 0x69, 0x0f, 0x67, 0x11, 0x65, 0x12,
- 0x63, 0x13, 0x60, 0x14, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
- 0x24, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x28, 0x27, 0x29, 0x28, 0x2b,
- 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2d, 0x2a, 0x2d, 0x2c, 0x2d, 0x2d, 0x2e,
- 0x2d, 0x2f, 0x2d, 0x30, 0x2e, 0x30, 0x2f, 0x30, 0x7d, 0x12, 0x77, 0x15,
- 0x72, 0x18, 0x6e, 0x1b, 0x6b, 0x1d, 0x68, 0x20, 0x65, 0x21, 0x64, 0x23,
- 0x60, 0x24, 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x27, 0x5c, 0x29, 0x59, 0x2a,
- 0x57, 0x2a, 0x57, 0x2b, 0x57, 0x2c, 0x56, 0x2e, 0x54, 0x2e, 0x53, 0x2e,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d,
- 0x00, 0x3a, 0x00, 0x34, 0x00, 0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15,
- 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71, 0x00,
- 0x59, 0x00, 0x41, 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd6, 0x00, 0xc9, 0x00,
- 0xbd, 0x00, 0xb2, 0x00, 0xa7, 0x00, 0x9d, 0x00, 0x95, 0x01, 0x8e, 0x02,
- 0x87, 0x03, 0x82, 0x05, 0x7e, 0x06, 0x79, 0x08, 0x75, 0x09, 0x73, 0x0b,
- 0x70, 0x0c, 0x6c, 0x0d, 0x6a, 0x0e, 0x68, 0x0f, 0x67, 0x11, 0x65, 0x12,
- 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x24, 0x26,
- 0x25, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b,
- 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e,
- 0x2d, 0x2f, 0x2d, 0x30, 0x7d, 0x12, 0x78, 0x15, 0x73, 0x18, 0x70, 0x1a,
- 0x6d, 0x1d, 0x69, 0x1e, 0x67, 0x20, 0x65, 0x21, 0x63, 0x23, 0x60, 0x24,
- 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x27, 0x5c, 0x28, 0x5a, 0x2a, 0x58, 0x2a,
- 0x57, 0x2a, 0x57, 0x2b, 0x57, 0x2c, 0x56, 0x2e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36,
- 0x00, 0x30, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c,
- 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00,
- 0xb1, 0x00, 0xa3, 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50, 0x00,
- 0x3a, 0x00, 0x25, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0xd7, 0x00, 0xcb, 0x00, 0xc0, 0x00, 0xb5, 0x00,
- 0xab, 0x00, 0xa2, 0x00, 0x9a, 0x00, 0x92, 0x02, 0x8d, 0x02, 0x87, 0x03,
- 0x81, 0x05, 0x7e, 0x06, 0x79, 0x07, 0x76, 0x09, 0x74, 0x0a, 0x71, 0x0b,
- 0x6e, 0x0c, 0x6b, 0x0d, 0x6a, 0x0e, 0x68, 0x10, 0x21, 0x22, 0x22, 0x22,
- 0x22, 0x23, 0x23, 0x24, 0x23, 0x25, 0x24, 0x25, 0x25, 0x27, 0x25, 0x27,
- 0x27, 0x28, 0x27, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b, 0x2a, 0x2b,
- 0x2b, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e,
- 0x7e, 0x12, 0x79, 0x15, 0x75, 0x17, 0x71, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d,
- 0x69, 0x1f, 0x65, 0x20, 0x65, 0x22, 0x62, 0x23, 0x60, 0x23, 0x60, 0x25,
- 0x5d, 0x27, 0x5c, 0x27, 0x5c, 0x28, 0x5c, 0x29, 0x59, 0x2a, 0x57, 0x2a,
- 0x57, 0x2a, 0x57, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c,
- 0x00, 0x26, 0x00, 0x1f, 0x00, 0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7, 0x00,
- 0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35, 0x00,
- 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0xd7, 0x00, 0xcc, 0x00, 0xc2, 0x00, 0xb9, 0x00, 0xae, 0x00, 0xa6, 0x00,
- 0x9e, 0x00, 0x97, 0x01, 0x90, 0x02, 0x8b, 0x02, 0x85, 0x04, 0x81, 0x05,
- 0x7e, 0x06, 0x7a, 0x07, 0x76, 0x08, 0x74, 0x09, 0x72, 0x0b, 0x6f, 0x0c,
- 0x6c, 0x0c, 0x6a, 0x0e, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
- 0x23, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x28,
- 0x26, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b,
- 0x2b, 0x2d, 0x2b, 0x2d, 0x2c, 0x2d, 0x2d, 0x2d, 0x7e, 0x12, 0x79, 0x15,
- 0x75, 0x17, 0x72, 0x19, 0x6e, 0x1a, 0x6c, 0x1d, 0x69, 0x1d, 0x68, 0x20,
- 0x65, 0x20, 0x65, 0x22, 0x61, 0x23, 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27,
- 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x29, 0x5a, 0x2a, 0x58, 0x2a, 0x57, 0x2a,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e,
- 0x00, 0x3c, 0x00, 0x38, 0x00, 0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22,
- 0x00, 0x1c, 0x00, 0x16, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d, 0x00,
- 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00,
- 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd8, 0x00, 0xce, 0x00,
- 0xc5, 0x00, 0xbb, 0x00, 0xb2, 0x00, 0xaa, 0x00, 0xa1, 0x00, 0x9b, 0x00,
- 0x94, 0x01, 0x8f, 0x02, 0x8a, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7e, 0x06,
- 0x7b, 0x07, 0x77, 0x08, 0x75, 0x09, 0x73, 0x0a, 0x71, 0x0b, 0x6e, 0x0c,
- 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25,
- 0x24, 0x25, 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28,
- 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c,
- 0x2b, 0x2d, 0x2b, 0x2d, 0x7e, 0x12, 0x7a, 0x14, 0x76, 0x16, 0x72, 0x18,
- 0x6f, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65, 0x20,
- 0x64, 0x23, 0x61, 0x23, 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27, 0x5c, 0x27,
- 0x5c, 0x27, 0x5c, 0x28, 0x5b, 0x2a, 0x59, 0x2a, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39,
- 0x00, 0x35, 0x00, 0x31, 0x00, 0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a,
- 0x00, 0x14, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00,
- 0xb6, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72, 0x00,
- 0x60, 0x00, 0x4f, 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0xd8, 0x00, 0xcf, 0x00, 0xc6, 0x00, 0xbd, 0x00,
- 0xb5, 0x00, 0xad, 0x00, 0xa6, 0x00, 0x9e, 0x00, 0x99, 0x00, 0x92, 0x01,
- 0x8e, 0x02, 0x89, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7e, 0x06, 0x7b, 0x07,
- 0x77, 0x07, 0x75, 0x09, 0x73, 0x09, 0x72, 0x0b, 0x21, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25,
- 0x25, 0x27, 0x25, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28,
- 0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2d,
- 0x7e, 0x12, 0x7a, 0x14, 0x76, 0x15, 0x72, 0x18, 0x71, 0x1a, 0x6d, 0x1a,
- 0x6c, 0x1d, 0x69, 0x1d, 0x68, 0x1f, 0x65, 0x20, 0x65, 0x21, 0x64, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x27,
- 0x5c, 0x27, 0x5c, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32,
- 0x00, 0x2d, 0x00, 0x28, 0x00, 0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13,
- 0x00, 0x0d, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00,
- 0xa5, 0x00, 0x98, 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59, 0x00,
- 0x49, 0x00, 0x39, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0xd8, 0x00, 0xd0, 0x00, 0xc7, 0x00, 0xbf, 0x00, 0xb8, 0x00, 0xaf, 0x00,
- 0xa9, 0x00, 0xa1, 0x00, 0x9c, 0x00, 0x96, 0x01, 0x90, 0x02, 0x8d, 0x02,
- 0x88, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7f, 0x06, 0x7b, 0x07, 0x77, 0x07,
- 0x76, 0x09, 0x74, 0x09, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23,
- 0x23, 0x24, 0x23, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x26, 0x25, 0x27,
- 0x26, 0x27, 0x27, 0x27, 0x26, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a,
- 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x7e, 0x11, 0x7a, 0x13,
- 0x76, 0x15, 0x74, 0x18, 0x72, 0x19, 0x6e, 0x1a, 0x6d, 0x1c, 0x69, 0x1d,
- 0x69, 0x1e, 0x67, 0x20, 0x65, 0x20, 0x65, 0x21, 0x63, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27,
- 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3c, 0x00, 0x3d,
- 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f,
- 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x58, 0x00, 0x3d,
- 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x48, 0x00, 0x42, 0x00, 0x3e, 0x00, 0x3e,
- 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
- 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3b, 0x0b, 0x07, 0x17, 0x00, 0x2c, 0x00, 0x36, 0x00, 0x3a, 0x00, 0x3c,
- 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e,
- 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x47, 0x07, 0x0f, 0x0f,
- 0x00, 0x26, 0x00, 0x33, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3d,
- 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f,
- 0x00, 0x3f, 0x00, 0x3f, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd9, 0x00, 0xd1, 0x00,
- 0xc9, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xb2, 0x00, 0xac, 0x00, 0xa5, 0x00,
- 0x9e, 0x00, 0x9a, 0x00, 0x93, 0x01, 0x8f, 0x02, 0x8c, 0x02, 0x88, 0x03,
- 0x83, 0x04, 0x81, 0x05, 0x7f, 0x06, 0x7b, 0x06, 0x78, 0x07, 0x76, 0x08,
- 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24,
- 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x25, 0x27, 0x27, 0x27,
- 0x27, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b,
- 0x2a, 0x2b, 0x2b, 0x2b, 0x7e, 0x11, 0x7b, 0x13, 0x77, 0x15, 0x75, 0x17,
- 0x72, 0x18, 0x6f, 0x1a, 0x6d, 0x1a, 0x6c, 0x1d, 0x69, 0x1d, 0x69, 0x1f,
- 0x65, 0x20, 0x65, 0x20, 0x65, 0x22, 0x62, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x25, 0x5f, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x00, 0x00, 0x00, 0x05,
- 0x00, 0x1f, 0x00, 0x2e, 0x00, 0x35, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c,
- 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e,
- 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x30, 0x00, 0x39, 0x00, 0x42,
- 0x00, 0x41, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d,
- 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x27, 0x02,
- 0x02, 0x12, 0x00, 0x25, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x38, 0x00, 0x3a,
- 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e,
- 0x00, 0x3e, 0x00, 0x3e, 0x7f, 0x00, 0x3f, 0x00, 0x05, 0x05, 0x00, 0x1c,
- 0x00, 0x2a, 0x00, 0x31, 0x00, 0x35, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3b,
- 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0xd9, 0x00, 0xd2, 0x00, 0xca, 0x00, 0xc3, 0x00,
- 0xbb, 0x00, 0xb5, 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa1, 0x00, 0x9d, 0x00,
- 0x98, 0x00, 0x92, 0x01, 0x8e, 0x02, 0x8b, 0x02, 0x87, 0x03, 0x83, 0x04,
- 0x81, 0x05, 0x7f, 0x06, 0x7c, 0x06, 0x78, 0x07, 0x21, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25,
- 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x27, 0x27, 0x28,
- 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x29, 0x2b,
- 0x7e, 0x11, 0x7b, 0x13, 0x77, 0x15, 0x76, 0x17, 0x72, 0x18, 0x71, 0x1a,
- 0x6d, 0x1a, 0x6d, 0x1c, 0x69, 0x1d, 0x69, 0x1d, 0x68, 0x20, 0x65, 0x20,
- 0x65, 0x20, 0x65, 0x22, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x25,
- 0x5f, 0x27, 0x5c, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x16,
- 0x00, 0x24, 0x00, 0x2c, 0x00, 0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39,
- 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d,
- 0x00, 0x4c, 0x00, 0x39, 0x00, 0x16, 0x00, 0x28, 0x00, 0x2f, 0x00, 0x2e,
- 0x00, 0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b,
- 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x6f, 0x00, 0x22, 0x00, 0x09, 0x0b,
- 0x00, 0x16, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x35,
- 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c,
- 0xa5, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x12, 0x00, 0x00, 0x09, 0x00, 0x19,
- 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36,
- 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3a, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0xd9, 0x00, 0xd2, 0x00, 0xca, 0x00, 0xc5, 0x00, 0xbd, 0x00, 0xb7, 0x00,
- 0xb0, 0x00, 0xab, 0x00, 0xa4, 0x00, 0x9f, 0x00, 0x9b, 0x00, 0x95, 0x01,
- 0x91, 0x01, 0x8e, 0x02, 0x8a, 0x02, 0x86, 0x03, 0x83, 0x04, 0x81, 0x05,
- 0x7f, 0x06, 0x7c, 0x06, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23,
- 0x22, 0x23, 0x23, 0x24, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25,
- 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x7f, 0x11, 0x7b, 0x13,
- 0x77, 0x15, 0x76, 0x16, 0x72, 0x18, 0x72, 0x19, 0x6d, 0x1a, 0x6d, 0x1b,
- 0x6b, 0x1d, 0x69, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65, 0x20, 0x65, 0x20,
- 0x64, 0x22, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x24, 0x5f, 0x26,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x1d,
- 0x00, 0x25, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36,
- 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x4c, 0x00, 0x42,
- 0x00, 0x28, 0x00, 0x09, 0x00, 0x16, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x2b,
- 0x00, 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38,
- 0x00, 0x39, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xaf, 0x00, 0x93, 0x00, 0x58, 0x00, 0x21, 0x00, 0x0e, 0x08, 0x02, 0x0e,
- 0x00, 0x18, 0x00, 0x20, 0x00, 0x27, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x31,
- 0x00, 0x33, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38, 0xb2, 0x00, 0x9c, 0x00,
- 0x6d, 0x00, 0x3f, 0x00, 0x1d, 0x00, 0x05, 0x00, 0x00, 0x0b, 0x00, 0x16,
- 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32,
- 0x00, 0x33, 0x00, 0x35, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xda, 0x00, 0xd2, 0x00,
- 0xcb, 0x00, 0xc6, 0x00, 0xbe, 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xac, 0x00,
- 0xa8, 0x00, 0xa1, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x01, 0x90, 0x02,
- 0x8d, 0x02, 0x89, 0x02, 0x85, 0x03, 0x83, 0x04, 0x81, 0x05, 0x7f, 0x06,
- 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23,
- 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27,
- 0x25, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x29, 0x27, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x29, 0x7f, 0x11, 0x7b, 0x13, 0x78, 0x15, 0x76, 0x15,
- 0x73, 0x18, 0x72, 0x18, 0x6f, 0x1a, 0x6d, 0x1a, 0x6d, 0x1c, 0x69, 0x1d,
- 0x69, 0x1d, 0x69, 0x1f, 0x65, 0x20, 0x65, 0x20, 0x65, 0x21, 0x64, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x24, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f,
- 0x00, 0x25, 0x00, 0x2a, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34,
- 0x00, 0x35, 0x00, 0x37, 0x00, 0x48, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16,
- 0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x2a,
- 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34, 0x00, 0x35, 0x00, 0x37,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x00, 0xa4, 0x00,
- 0x7a, 0x00, 0x4a, 0x00, 0x20, 0x00, 0x12, 0x06, 0x07, 0x0c, 0x00, 0x10,
- 0x00, 0x18, 0x00, 0x1f, 0x00, 0x24, 0x00, 0x28, 0x00, 0x2c, 0x00, 0x2e,
- 0x00, 0x30, 0x00, 0x32, 0xb7, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x62, 0x00,
- 0x3f, 0x00, 0x24, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14,
- 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2b, 0x00, 0x2e,
- 0x33, 0x22, 0x28, 0x22, 0x25, 0x22, 0x24, 0x22, 0x23, 0x22, 0x23, 0x22,
- 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21,
- 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x22, 0x22, 0x21, 0x22, 0x21,
- 0x22, 0x21, 0x22, 0x21, 0x9d, 0x05, 0x6b, 0x0d, 0x51, 0x12, 0x45, 0x15,
- 0x3d, 0x17, 0x38, 0x18, 0x35, 0x1a, 0x32, 0x1b, 0x30, 0x1b, 0x2f, 0x1c,
- 0x2d, 0x1c, 0x2d, 0x1c, 0x2c, 0x1d, 0x2b, 0x1d, 0x2a, 0x1e, 0x2a, 0x1e,
- 0x29, 0x1e, 0x29, 0x1e, 0x28, 0x1e, 0x28, 0x1e, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x5f, 0x13, 0x46, 0x17, 0x39, 0x1a, 0x33, 0x1b, 0x2f, 0x1c, 0x2d, 0x1d,
- 0x2b, 0x1e, 0x2a, 0x1e, 0x29, 0x1e, 0x28, 0x1f, 0x27, 0x1f, 0x27, 0x1f,
- 0x27, 0x1f, 0x26, 0x1f, 0x26, 0x20, 0x26, 0x20, 0x25, 0x20, 0x25, 0x20,
- 0x25, 0x20, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21,
- 0x00, 0x25, 0x00, 0x29, 0x00, 0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32,
- 0x00, 0x42, 0x00, 0x3d, 0x00, 0x2e, 0x00, 0x1d, 0x00, 0x0d, 0x00, 0x00,
- 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29,
- 0x00, 0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, 0xad, 0x00, 0x8f, 0x00, 0x68, 0x00,
- 0x42, 0x00, 0x20, 0x00, 0x14, 0x05, 0x0b, 0x0a, 0x04, 0x0d, 0x00, 0x12,
- 0x00, 0x19, 0x00, 0x1e, 0x00, 0x23, 0x00, 0x26, 0x00, 0x29, 0x00, 0x2c,
- 0xba, 0x00, 0xb1, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5b, 0x00, 0x3f, 0x00,
- 0x29, 0x00, 0x16, 0x00, 0x08, 0x00, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x13,
- 0x00, 0x19, 0x00, 0x1e, 0x00, 0x22, 0x00, 0x25, 0x37, 0x28, 0x2d, 0x25,
- 0x28, 0x23, 0x26, 0x23, 0x25, 0x23, 0x24, 0x22, 0x24, 0x22, 0x23, 0x22,
- 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0xbc, 0x00, 0x8e, 0x01, 0x73, 0x04, 0x60, 0x08, 0x55, 0x0b, 0x4c, 0x0d,
- 0x47, 0x0f, 0x42, 0x11, 0x3e, 0x12, 0x3b, 0x13, 0x39, 0x14, 0x37, 0x15,
- 0x36, 0x16, 0x34, 0x16, 0x33, 0x17, 0x32, 0x18, 0x31, 0x18, 0x30, 0x19,
- 0x2f, 0x19, 0x2f, 0x19, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x6f, 0x11, 0x58, 0x11,
- 0x4a, 0x13, 0x41, 0x15, 0x3b, 0x16, 0x37, 0x17, 0x34, 0x18, 0x32, 0x19,
- 0x30, 0x1a, 0x2e, 0x1a, 0x2d, 0x1b, 0x2c, 0x1b, 0x2c, 0x1c, 0x2b, 0x1c,
- 0x2a, 0x1c, 0x2a, 0x1d, 0x29, 0x1d, 0x29, 0x1d, 0x28, 0x1d, 0x28, 0x1d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x09, 0x00, 0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22,
- 0x00, 0x26, 0x00, 0x29, 0x00, 0x2b, 0x00, 0x2d, 0x00, 0x3e, 0x00, 0x3a,
- 0x00, 0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x09,
- 0x00, 0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22, 0x00, 0x26, 0x00, 0x29,
- 0x00, 0x2b, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xba, 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x7d, 0x00, 0x5c, 0x00, 0x3c, 0x00,
- 0x20, 0x00, 0x16, 0x04, 0x0e, 0x08, 0x07, 0x0c, 0x02, 0x0e, 0x00, 0x13,
- 0x00, 0x19, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x25, 0xbb, 0x00, 0xb5, 0x00,
- 0xa3, 0x00, 0x8a, 0x00, 0x6f, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x2c, 0x00,
- 0x1c, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x12,
- 0x00, 0x17, 0x00, 0x1c, 0x38, 0x2c, 0x30, 0x28, 0x2b, 0x26, 0x29, 0x25,
- 0x27, 0x24, 0x26, 0x24, 0x25, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x22,
- 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xc6, 0x00, 0xa4, 0x00,
- 0x89, 0x00, 0x77, 0x02, 0x67, 0x04, 0x5e, 0x06, 0x55, 0x08, 0x50, 0x0a,
- 0x4b, 0x0c, 0x47, 0x0d, 0x44, 0x0e, 0x41, 0x0f, 0x3e, 0x10, 0x3d, 0x11,
- 0x3b, 0x12, 0x39, 0x12, 0x38, 0x13, 0x37, 0x14, 0x35, 0x15, 0x35, 0x16,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x74, 0x11, 0x63, 0x11, 0x55, 0x11, 0x4c, 0x12,
- 0x44, 0x13, 0x40, 0x14, 0x3b, 0x15, 0x39, 0x16, 0x36, 0x17, 0x34, 0x17,
- 0x33, 0x18, 0x31, 0x18, 0x30, 0x19, 0x2f, 0x19, 0x2e, 0x1a, 0x2d, 0x1a,
- 0x2d, 0x1a, 0x2c, 0x1b, 0x2b, 0x1b, 0x2b, 0x1c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x08, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22,
- 0x00, 0x26, 0x00, 0x28, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b,
- 0x00, 0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f,
- 0x00, 0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22, 0x00, 0x26, 0x00, 0x28,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb5, 0x00,
- 0xa4, 0x00, 0x8b, 0x00, 0x6f, 0x00, 0x52, 0x00, 0x37, 0x00, 0x20, 0x00,
- 0x17, 0x04, 0x10, 0x07, 0x0a, 0x0a, 0x05, 0x0d, 0x00, 0x0f, 0x00, 0x14,
- 0x00, 0x19, 0x00, 0x1d, 0xbc, 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x96, 0x00,
- 0x7f, 0x00, 0x68, 0x00, 0x53, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x20, 0x00,
- 0x14, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11,
- 0x3a, 0x2f, 0x32, 0x2b, 0x2e, 0x28, 0x2b, 0x27, 0x28, 0x25, 0x27, 0x25,
- 0x27, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23,
- 0x24, 0x23, 0x23, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
- 0x23, 0x22, 0x23, 0x22, 0xcd, 0x00, 0xb0, 0x00, 0x9a, 0x00, 0x87, 0x00,
- 0x78, 0x01, 0x6c, 0x03, 0x64, 0x04, 0x5c, 0x05, 0x57, 0x07, 0x51, 0x09,
- 0x4e, 0x0a, 0x4a, 0x0b, 0x48, 0x0c, 0x45, 0x0c, 0x43, 0x0e, 0x40, 0x0f,
- 0x3f, 0x0f, 0x3d, 0x0f, 0x3c, 0x11, 0x3b, 0x12, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x77, 0x11, 0x69, 0x11, 0x5e, 0x11, 0x54, 0x11, 0x4d, 0x11, 0x47, 0x12,
- 0x43, 0x13, 0x3f, 0x13, 0x3c, 0x14, 0x39, 0x15, 0x38, 0x16, 0x36, 0x16,
- 0x35, 0x17, 0x33, 0x17, 0x32, 0x18, 0x31, 0x18, 0x30, 0x18, 0x2f, 0x18,
- 0x2f, 0x19, 0x2e, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
- 0x00, 0x0d, 0x00, 0x13, 0x00, 0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23,
- 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x25, 0x00, 0x1b,
- 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13,
- 0x00, 0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xaa, 0x00, 0x96, 0x00,
- 0x7e, 0x00, 0x64, 0x00, 0x4c, 0x00, 0x34, 0x00, 0x20, 0x00, 0x18, 0x03,
- 0x11, 0x06, 0x0c, 0x09, 0x07, 0x0c, 0x03, 0x0e, 0x00, 0x10, 0x00, 0x15,
- 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x8b, 0x00, 0x77, 0x00,
- 0x63, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x30, 0x00, 0x23, 0x00, 0x18, 0x00,
- 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3b, 0x32, 0x34, 0x2d,
- 0x2f, 0x2a, 0x2c, 0x28, 0x2a, 0x27, 0x29, 0x26, 0x27, 0x25, 0x27, 0x25,
- 0x26, 0x24, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x23, 0x24, 0x23,
- 0x24, 0x23, 0x24, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x22,
- 0xcf, 0x00, 0xb9, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x85, 0x00, 0x7a, 0x01,
- 0x70, 0x02, 0x68, 0x03, 0x61, 0x04, 0x5c, 0x05, 0x57, 0x07, 0x53, 0x07,
- 0x50, 0x09, 0x4c, 0x0a, 0x4a, 0x0a, 0x48, 0x0c, 0x45, 0x0c, 0x44, 0x0c,
- 0x42, 0x0d, 0x41, 0x0f, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x78, 0x11, 0x6d, 0x11,
- 0x63, 0x11, 0x5b, 0x11, 0x53, 0x11, 0x4e, 0x11, 0x49, 0x12, 0x45, 0x12,
- 0x41, 0x13, 0x3f, 0x13, 0x3c, 0x14, 0x3a, 0x14, 0x39, 0x15, 0x37, 0x16,
- 0x36, 0x16, 0x35, 0x17, 0x33, 0x17, 0x33, 0x17, 0x32, 0x17, 0x31, 0x18,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c,
- 0x00, 0x11, 0x00, 0x16, 0x00, 0x1a, 0x00, 0x1d, 0x00, 0x3e, 0x00, 0x3d,
- 0x00, 0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f,
- 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x16,
- 0x00, 0x1a, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9d, 0x00, 0x89, 0x00, 0x73, 0x00,
- 0x5c, 0x00, 0x46, 0x00, 0x32, 0x00, 0x20, 0x00, 0x19, 0x03, 0x13, 0x06,
- 0x0e, 0x08, 0x09, 0x0b, 0x05, 0x0d, 0x01, 0x0e, 0xbd, 0x00, 0xba, 0x00,
- 0xb1, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x82, 0x00, 0x70, 0x00, 0x5e, 0x00,
- 0x4e, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x26, 0x00, 0x1c, 0x00, 0x13, 0x00,
- 0x0b, 0x00, 0x03, 0x00, 0x3c, 0x34, 0x35, 0x2f, 0x31, 0x2c, 0x2e, 0x2a,
- 0x2c, 0x28, 0x2a, 0x27, 0x28, 0x27, 0x28, 0x26, 0x27, 0x25, 0x27, 0x25,
- 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x24, 0x24, 0x23,
- 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x23, 0x23, 0xd2, 0x00, 0xbe, 0x00,
- 0xad, 0x00, 0x9d, 0x00, 0x90, 0x00, 0x84, 0x00, 0x7a, 0x00, 0x72, 0x01,
- 0x6b, 0x02, 0x65, 0x04, 0x60, 0x04, 0x5b, 0x05, 0x58, 0x06, 0x54, 0x07,
- 0x51, 0x07, 0x4f, 0x09, 0x4c, 0x0a, 0x4a, 0x0a, 0x48, 0x0b, 0x46, 0x0c,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x7a, 0x11, 0x70, 0x11, 0x67, 0x11, 0x5f, 0x11,
- 0x59, 0x11, 0x53, 0x11, 0x4e, 0x11, 0x4a, 0x11, 0x46, 0x12, 0x43, 0x13,
- 0x41, 0x13, 0x3e, 0x13, 0x3d, 0x14, 0x3b, 0x14, 0x39, 0x14, 0x38, 0x15,
- 0x37, 0x16, 0x36, 0x16, 0x35, 0x16, 0x34, 0x17, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10,
- 0x00, 0x14, 0x00, 0x18, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x34,
- 0x00, 0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x06,
- 0x00, 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00,
- 0xb1, 0x00, 0xa3, 0x00, 0x92, 0x00, 0x7e, 0x00, 0x6a, 0x00, 0x56, 0x00,
- 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x19, 0x03, 0x14, 0x05, 0x0f, 0x08,
- 0x0b, 0x0a, 0x07, 0x0c, 0xbd, 0x00, 0xbb, 0x00, 0xb4, 0x00, 0xa9, 0x00,
- 0x9b, 0x00, 0x8b, 0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4d, 0x00,
- 0x3f, 0x00, 0x33, 0x00, 0x28, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0e, 0x00,
- 0x3c, 0x35, 0x36, 0x31, 0x32, 0x2e, 0x2f, 0x2b, 0x2d, 0x2a, 0x2b, 0x28,
- 0x2a, 0x28, 0x28, 0x27, 0x28, 0x27, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25,
- 0x25, 0x25, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x24, 0x24, 0x24,
- 0x24, 0x23, 0x24, 0x23, 0xd3, 0x00, 0xc2, 0x00, 0xb2, 0x00, 0xa4, 0x00,
- 0x98, 0x00, 0x8d, 0x00, 0x83, 0x00, 0x7b, 0x00, 0x73, 0x01, 0x6e, 0x02,
- 0x67, 0x02, 0x63, 0x04, 0x5f, 0x04, 0x5b, 0x05, 0x58, 0x05, 0x55, 0x07,
- 0x52, 0x07, 0x50, 0x07, 0x4e, 0x09, 0x4c, 0x0a, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x7a, 0x11, 0x72, 0x11, 0x6a, 0x11, 0x63, 0x11, 0x5d, 0x11, 0x57, 0x11,
- 0x52, 0x11, 0x4e, 0x11, 0x4a, 0x11, 0x48, 0x12, 0x44, 0x12, 0x42, 0x13,
- 0x40, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b, 0x14, 0x3a, 0x14, 0x39, 0x14,
- 0x38, 0x15, 0x37, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13,
- 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29,
- 0x00, 0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00,
- 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa8, 0x00,
- 0x99, 0x00, 0x87, 0x00, 0x75, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f, 0x00,
- 0x2e, 0x00, 0x1f, 0x00, 0x1a, 0x02, 0x15, 0x05, 0x10, 0x07, 0x0c, 0x09,
- 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xac, 0x00, 0xa0, 0x00, 0x93, 0x00,
- 0x84, 0x00, 0x75, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4b, 0x00, 0x3f, 0x00,
- 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x19, 0x00, 0x3c, 0x36, 0x37, 0x32,
- 0x33, 0x2f, 0x30, 0x2d, 0x2e, 0x2b, 0x2d, 0x2a, 0x2b, 0x28, 0x2a, 0x28,
- 0x28, 0x27, 0x28, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25,
- 0x25, 0x25, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x24, 0x24, 0x24,
- 0xd5, 0x00, 0xc5, 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x9f, 0x00, 0x95, 0x00,
- 0x8b, 0x00, 0x83, 0x00, 0x7c, 0x00, 0x75, 0x01, 0x6f, 0x01, 0x69, 0x02,
- 0x66, 0x02, 0x61, 0x04, 0x5e, 0x04, 0x5a, 0x05, 0x58, 0x05, 0x55, 0x06,
- 0x53, 0x07, 0x51, 0x07, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7b, 0x11, 0x73, 0x11,
- 0x6c, 0x11, 0x66, 0x11, 0x60, 0x11, 0x5b, 0x11, 0x56, 0x11, 0x52, 0x11,
- 0x4f, 0x11, 0x4b, 0x11, 0x48, 0x11, 0x45, 0x12, 0x44, 0x12, 0x41, 0x13,
- 0x40, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b, 0x14, 0x3a, 0x14, 0x39, 0x14,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x3f, 0x00, 0x3e,
- 0x00, 0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x26, 0x00, 0x1f,
- 0x00, 0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05,
- 0x00, 0x09, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xab, 0x00, 0x9e, 0x00, 0x8f, 0x00,
- 0x7e, 0x00, 0x6d, 0x00, 0x5c, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2d, 0x00,
- 0x1f, 0x00, 0x1a, 0x02, 0x16, 0x04, 0x11, 0x06, 0xbe, 0x00, 0xbc, 0x00,
- 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00, 0x8b, 0x00, 0x7e, 0x00,
- 0x70, 0x00, 0x63, 0x00, 0x56, 0x00, 0x4a, 0x00, 0x3f, 0x00, 0x35, 0x00,
- 0x2c, 0x00, 0x23, 0x00, 0x3c, 0x37, 0x38, 0x33, 0x34, 0x30, 0x31, 0x2e,
- 0x2f, 0x2c, 0x2d, 0x2a, 0x2c, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x27,
- 0x28, 0x27, 0x27, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x25, 0x25,
- 0x25, 0x25, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0xd5, 0x00, 0xc8, 0x00,
- 0xbb, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x92, 0x00, 0x8a, 0x00,
- 0x82, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x70, 0x01, 0x6c, 0x02, 0x67, 0x02,
- 0x64, 0x03, 0x60, 0x04, 0x5d, 0x04, 0x5b, 0x05, 0x58, 0x05, 0x55, 0x05,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x7b, 0x11, 0x75, 0x11, 0x6e, 0x11, 0x68, 0x11,
- 0x63, 0x11, 0x5e, 0x11, 0x5a, 0x11, 0x56, 0x11, 0x52, 0x11, 0x4f, 0x11,
- 0x4c, 0x11, 0x49, 0x11, 0x47, 0x12, 0x44, 0x12, 0x43, 0x12, 0x41, 0x13,
- 0x3f, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b, 0x13, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x04, 0x00, 0x09, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38,
- 0x00, 0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1c, 0x00, 0x16,
- 0x00, 0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00,
- 0xb7, 0x00, 0xae, 0x00, 0xa2, 0x00, 0x95, 0x00, 0x86, 0x00, 0x77, 0x00,
- 0x67, 0x00, 0x57, 0x00, 0x48, 0x00, 0x3a, 0x00, 0x2c, 0x00, 0x1f, 0x00,
- 0x1b, 0x02, 0x16, 0x04, 0xbe, 0x00, 0xbd, 0x00, 0xb8, 0x00, 0xb1, 0x00,
- 0xa8, 0x00, 0x9d, 0x00, 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6c, 0x00,
- 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2d, 0x00,
- 0x3d, 0x38, 0x38, 0x34, 0x35, 0x31, 0x33, 0x2f, 0x30, 0x2d, 0x2e, 0x2c,
- 0x2d, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x27, 0x28, 0x27,
- 0x28, 0x27, 0x27, 0x27, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25,
- 0x25, 0x25, 0x25, 0x24, 0xd6, 0x00, 0xca, 0x00, 0xbe, 0x00, 0xb3, 0x00,
- 0xaa, 0x00, 0xa0, 0x00, 0x98, 0x00, 0x90, 0x00, 0x88, 0x00, 0x82, 0x00,
- 0x7d, 0x00, 0x77, 0x00, 0x71, 0x01, 0x6d, 0x01, 0x69, 0x02, 0x66, 0x02,
- 0x63, 0x04, 0x60, 0x04, 0x5d, 0x04, 0x5b, 0x05, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x7c, 0x11, 0x76, 0x11, 0x70, 0x11, 0x6a, 0x11, 0x66, 0x11, 0x61, 0x11,
- 0x5d, 0x11, 0x59, 0x11, 0x55, 0x11, 0x52, 0x11, 0x4f, 0x11, 0x4c, 0x11,
- 0x49, 0x11, 0x47, 0x11, 0x45, 0x12, 0x44, 0x12, 0x42, 0x13, 0x41, 0x13,
- 0x3f, 0x13, 0x3e, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
- 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39, 0x00, 0x35, 0x00, 0x31,
- 0x00, 0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0f,
- 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xb0, 0x00,
- 0xa6, 0x00, 0x9a, 0x00, 0x8d, 0x00, 0x7f, 0x00, 0x70, 0x00, 0x61, 0x00,
- 0x53, 0x00, 0x45, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x1b, 0x02,
- 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb3, 0x00, 0xab, 0x00, 0xa1, 0x00,
- 0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x74, 0x00, 0x68, 0x00, 0x5d, 0x00,
- 0x53, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x3d, 0x38, 0x39, 0x35,
- 0x36, 0x32, 0x33, 0x30, 0x31, 0x2e, 0x30, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b,
- 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x26, 0x28, 0x27,
- 0x27, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25,
- 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb7, 0x00, 0xad, 0x00, 0xa5, 0x00,
- 0x9d, 0x00, 0x96, 0x00, 0x8f, 0x00, 0x88, 0x00, 0x81, 0x00, 0x7d, 0x00,
- 0x77, 0x00, 0x73, 0x01, 0x6f, 0x01, 0x6b, 0x02, 0x67, 0x02, 0x64, 0x02,
- 0x62, 0x04, 0x5f, 0x04, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7c, 0x11, 0x77, 0x11,
- 0x71, 0x11, 0x6c, 0x11, 0x67, 0x11, 0x63, 0x11, 0x5f, 0x11, 0x5c, 0x11,
- 0x58, 0x11, 0x55, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4c, 0x11, 0x4a, 0x11,
- 0x48, 0x11, 0x46, 0x12, 0x44, 0x12, 0x43, 0x12, 0x42, 0x13, 0x40, 0x13,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e,
- 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x28,
- 0x00, 0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x09,
- 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xa9, 0x00, 0x9e, 0x00,
- 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x5c, 0x00, 0x4f, 0x00,
- 0x42, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0xbe, 0x00, 0xbd, 0x00,
- 0xba, 0x00, 0xb4, 0x00, 0xad, 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x91, 0x00,
- 0x86, 0x00, 0x7b, 0x00, 0x70, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00,
- 0x48, 0x00, 0x3f, 0x00, 0x3d, 0x39, 0x39, 0x36, 0x36, 0x33, 0x33, 0x30,
- 0x32, 0x2f, 0x30, 0x2d, 0x2e, 0x2d, 0x2d, 0x2a, 0x2c, 0x2b, 0x2b, 0x29,
- 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x26, 0x28, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0xd7, 0x00, 0xcc, 0x00,
- 0xc3, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0xa0, 0x00, 0x99, 0x00,
- 0x93, 0x00, 0x8d, 0x00, 0x87, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00,
- 0x74, 0x00, 0x70, 0x01, 0x6c, 0x01, 0x69, 0x02, 0x66, 0x02, 0x63, 0x02,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x7c, 0x11, 0x77, 0x11, 0x72, 0x11, 0x6e, 0x11,
- 0x69, 0x11, 0x65, 0x11, 0x61, 0x11, 0x5d, 0x11, 0x5a, 0x11, 0x57, 0x11,
- 0x54, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x49, 0x11,
- 0x47, 0x11, 0x45, 0x12, 0x44, 0x12, 0x42, 0x12, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x39, 0x39, 0x36, 0x36, 0x33, 0x34, 0x32, 0x33, 0x30, 0x30, 0x2e,
- 0x30, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28,
- 0x29, 0x28, 0x28, 0x28, 0x28, 0x27, 0x29, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0x27, 0x27, 0x27, 0x25, 0xd7, 0x00, 0xce, 0x00, 0xc5, 0x00, 0xbc, 0x00,
- 0xb4, 0x00, 0xac, 0x00, 0xa5, 0x00, 0x9e, 0x00, 0x97, 0x00, 0x91, 0x00,
- 0x8c, 0x00, 0x87, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x75, 0x00,
- 0x71, 0x01, 0x6d, 0x01, 0x6b, 0x02, 0x68, 0x02, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x7c, 0x11, 0x78, 0x11, 0x73, 0x11, 0x6f, 0x11, 0x6b, 0x11, 0x67, 0x11,
- 0x63, 0x11, 0x60, 0x11, 0x5c, 0x11, 0x59, 0x11, 0x57, 0x11, 0x54, 0x11,
- 0x51, 0x11, 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x49, 0x11, 0x47, 0x11,
- 0x46, 0x12, 0x45, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x39, 0x3a, 0x36,
- 0x37, 0x34, 0x35, 0x33, 0x33, 0x30, 0x31, 0x30, 0x30, 0x2d, 0x2e, 0x2d,
- 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28,
- 0x28, 0x28, 0x28, 0x27, 0x28, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, 0x27,
- 0xd8, 0x00, 0xcf, 0x00, 0xc6, 0x00, 0xbe, 0x00, 0xb6, 0x00, 0xaf, 0x00,
- 0xa8, 0x00, 0xa1, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x90, 0x00, 0x8a, 0x00,
- 0x86, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x75, 0x00, 0x72, 0x01,
- 0x6f, 0x01, 0x6b, 0x01, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x78, 0x11,
- 0x74, 0x11, 0x70, 0x11, 0x6c, 0x11, 0x68, 0x11, 0x65, 0x11, 0x61, 0x11,
- 0x5f, 0x11, 0x5c, 0x11, 0x59, 0x11, 0x56, 0x11, 0x54, 0x11, 0x51, 0x11,
- 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x4a, 0x11, 0x48, 0x11, 0x46, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3a, 0x3a, 0x37, 0x38, 0x35, 0x36, 0x33,
- 0x33, 0x31, 0x32, 0x30, 0x30, 0x2e, 0x30, 0x2d, 0x2d, 0x2d, 0x2d, 0x2b,
- 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28,
- 0x28, 0x27, 0x28, 0x26, 0x28, 0x27, 0x27, 0x27, 0xd8, 0x00, 0xd0, 0x00,
- 0xc8, 0x00, 0xc0, 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xab, 0x00, 0xa5, 0x00,
- 0x9f, 0x00, 0x99, 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8a, 0x00, 0x86, 0x00,
- 0x81, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x76, 0x00, 0x73, 0x00, 0x70, 0x01,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x79, 0x11, 0x75, 0x11, 0x71, 0x11,
- 0x6d, 0x11, 0x6a, 0x11, 0x66, 0x11, 0x63, 0x11, 0x60, 0x11, 0x5d, 0x11,
- 0x5b, 0x11, 0x58, 0x11, 0x56, 0x11, 0x54, 0x11, 0x51, 0x11, 0x4f, 0x11,
- 0x4d, 0x11, 0x4c, 0x11, 0x4a, 0x11, 0x49, 0x11, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x3a, 0x3a, 0x37, 0x38, 0x36, 0x36, 0x33, 0x33, 0x32, 0x33, 0x30,
- 0x30, 0x30, 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2c, 0x2b,
- 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x27, 0x29, 0x27, 0xd9, 0x00, 0xd1, 0x00, 0xc9, 0x00, 0xc2, 0x00,
- 0xbb, 0x00, 0xb4, 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa2, 0x00, 0x9c, 0x00,
- 0x97, 0x00, 0x92, 0x00, 0x8e, 0x00, 0x89, 0x00, 0x85, 0x00, 0x81, 0x00,
- 0x7d, 0x00, 0x7a, 0x00, 0x76, 0x00, 0x73, 0x00, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x7d, 0x11, 0x79, 0x11, 0x75, 0x11, 0x72, 0x11, 0x6e, 0x11, 0x6b, 0x11,
- 0x68, 0x11, 0x65, 0x11, 0x62, 0x11, 0x5f, 0x11, 0x5c, 0x11, 0x5a, 0x11,
- 0x58, 0x11, 0x55, 0x11, 0x53, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4e, 0x11,
- 0x4c, 0x11, 0x4a, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3a, 0x3b, 0x38,
- 0x39, 0x36, 0x36, 0x33, 0x34, 0x33, 0x33, 0x30, 0x32, 0x30, 0x30, 0x2e,
- 0x30, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
- 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27,
- 0xd9, 0x00, 0xd1, 0x00, 0xca, 0x00, 0xc3, 0x00, 0xbc, 0x00, 0xb6, 0x00,
- 0xb0, 0x00, 0xaa, 0x00, 0xa5, 0x00, 0xa0, 0x00, 0x9a, 0x00, 0x96, 0x00,
- 0x91, 0x00, 0x8d, 0x00, 0x89, 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00,
- 0x7a, 0x00, 0x77, 0x00, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x79, 0x11,
- 0x76, 0x11, 0x72, 0x11, 0x6f, 0x11, 0x6c, 0x11, 0x69, 0x11, 0x66, 0x11,
- 0x63, 0x11, 0x61, 0x11, 0x5e, 0x11, 0x5c, 0x11, 0x59, 0x11, 0x57, 0x11,
- 0x55, 0x11, 0x53, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4e, 0x11, 0x4c, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3a, 0x3b, 0x39, 0x39, 0x36, 0x36, 0x34,
- 0x35, 0x33, 0x33, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x2f, 0x2d,
- 0x2d, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x29,
- 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0xd9, 0x00, 0xd2, 0x00,
- 0xcb, 0x00, 0xc4, 0x00, 0xbe, 0x00, 0xb8, 0x00, 0xb2, 0x00, 0xad, 0x00,
- 0xa8, 0x00, 0xa2, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x94, 0x00, 0x90, 0x00,
- 0x8b, 0x00, 0x88, 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7b, 0x00,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x7a, 0x11, 0x76, 0x11, 0x73, 0x11,
- 0x70, 0x11, 0x6d, 0x11, 0x6a, 0x11, 0x67, 0x11, 0x65, 0x11, 0x62, 0x11,
- 0x5f, 0x11, 0x5d, 0x11, 0x5b, 0x11, 0x59, 0x11, 0x56, 0x11, 0x55, 0x11,
- 0x53, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4e, 0x11, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x3b, 0x3b, 0x39, 0x3a, 0x36, 0x36, 0x35, 0x36, 0x33, 0x33, 0x32,
- 0x33, 0x30, 0x31, 0x30, 0x30, 0x2f, 0x30, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
- 0x2d, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x2b, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0xd9, 0x00, 0xd3, 0x00, 0xcc, 0x00, 0xc6, 0x00,
- 0xc0, 0x00, 0xba, 0x00, 0xb4, 0x00, 0xaf, 0x00, 0xaa, 0x00, 0xa5, 0x00,
- 0xa0, 0x00, 0x9b, 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f, 0x00, 0x8b, 0x00,
- 0x88, 0x00, 0x83, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x7d, 0x11, 0x7a, 0x11, 0x77, 0x11, 0x74, 0x11, 0x71, 0x11, 0x6e, 0x11,
- 0x6b, 0x11, 0x68, 0x11, 0x66, 0x11, 0x63, 0x11, 0x61, 0x11, 0x5e, 0x11,
- 0x5c, 0x11, 0x5a, 0x11, 0x58, 0x11, 0x56, 0x11, 0x55, 0x11, 0x52, 0x11,
- 0x51, 0x11, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3b, 0x3b, 0x39,
- 0x39, 0x36, 0x37, 0x36, 0x36, 0x33, 0x34, 0x33, 0x33, 0x31, 0x32, 0x30,
- 0x30, 0x30, 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b,
- 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28,
- 0xd9, 0x00, 0xd3, 0x00, 0xcd, 0x00, 0xc7, 0x00, 0xc1, 0x00, 0xbc, 0x00,
- 0xb7, 0x00, 0xb0, 0x00, 0xac, 0x00, 0xa7, 0x00, 0xa2, 0x00, 0x9e, 0x00,
- 0x9a, 0x00, 0x95, 0x00, 0x93, 0x00, 0x8e, 0x00, 0x8b, 0x00, 0x87, 0x00,
- 0x83, 0x00, 0x81, 0x00, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x7a, 0x11,
- 0x77, 0x11, 0x74, 0x11, 0x71, 0x11, 0x6f, 0x11, 0x6c, 0x11, 0x69, 0x11,
- 0x67, 0x11, 0x64, 0x11, 0x62, 0x11, 0x60, 0x11, 0x5e, 0x11, 0x5b, 0x11,
- 0x5a, 0x11, 0x58, 0x11, 0x56, 0x11, 0x54, 0x11, 0x52, 0x11, 0x51, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0xb8, 0x00, 0xc5, 0x00, 0xcb, 0x00,
- 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00,
- 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd9, 0x00,
- 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0x44, 0x00, 0x9d, 0x00, 0xbc, 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xcf, 0x00,
- 0xd2, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00,
- 0xd7, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00,
- 0xd9, 0x00, 0xd9, 0x00, 0x90, 0x00, 0xbd, 0x00, 0xcc, 0x00, 0xd1, 0x00,
- 0xd5, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00,
- 0xd9, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00,
- 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x68, 0x01, 0x8b, 0x00, 0xa0, 0x00, 0xad, 0x00, 0xb6, 0x00, 0xbc, 0x00,
- 0xc1, 0x00, 0xc4, 0x00, 0xc7, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc, 0x00,
- 0xcd, 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd2, 0x00,
- 0xd2, 0x00, 0xd3, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x25, 0x05, 0x6b, 0x00,
- 0x8e, 0x00, 0xa4, 0x00, 0xb0, 0x00, 0xb9, 0x00, 0xbe, 0x00, 0xc2, 0x00,
- 0xc5, 0x00, 0xc8, 0x00, 0xca, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xce, 0x00,
- 0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00,
- 0x81, 0x02, 0xa4, 0x00, 0xb5, 0x00, 0xc0, 0x00, 0xc6, 0x00, 0xcb, 0x00,
- 0xcd, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00,
- 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd7, 0x00,
- 0xd7, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x09, 0x72, 0x02,
- 0x87, 0x00, 0x96, 0x00, 0xa0, 0x00, 0xa9, 0x00, 0xb0, 0x00, 0xb5, 0x00,
- 0xb9, 0x00, 0xbd, 0x00, 0xbf, 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xc6, 0x00,
- 0xc7, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0x23, 0x0d, 0x51, 0x01, 0x73, 0x00, 0x89, 0x00,
- 0x9a, 0x00, 0xa4, 0x00, 0xad, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbb, 0x00,
- 0xbe, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc8, 0x00,
- 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0x80, 0x06, 0x97, 0x00,
- 0xa8, 0x00, 0xb3, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc5, 0x00, 0xc7, 0x00,
- 0xca, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xd0, 0x00, 0xd1, 0x00,
- 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd4, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x4f, 0x11, 0x65, 0x07, 0x76, 0x03, 0x84, 0x01,
- 0x8f, 0x00, 0x99, 0x00, 0xa1, 0x00, 0xa7, 0x00, 0xad, 0x00, 0xb1, 0x00,
- 0xb4, 0x00, 0xb8, 0x00, 0xbb, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc0, 0x00,
- 0xc2, 0x00, 0xc4, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0x22, 0x12, 0x45, 0x04, 0x60, 0x00, 0x77, 0x00, 0x87, 0x00, 0x94, 0x00,
- 0x9d, 0x00, 0xa4, 0x00, 0xaa, 0x00, 0xaf, 0x00, 0xb3, 0x00, 0xb7, 0x00,
- 0xba, 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc2, 0x00, 0xc3, 0x00,
- 0xc4, 0x00, 0xc6, 0x00, 0x7f, 0x09, 0x91, 0x02, 0x9e, 0x00, 0xaa, 0x00,
- 0xb2, 0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc6, 0x00,
- 0xc8, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00,
- 0xcf, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x4b, 0x17, 0x5d, 0x0c, 0x6c, 0x06, 0x78, 0x03, 0x83, 0x01, 0x8c, 0x00,
- 0x94, 0x00, 0x9b, 0x00, 0xa1, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xae, 0x00,
- 0xb1, 0x00, 0xb4, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbd, 0x00,
- 0xbe, 0x00, 0xbf, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x22, 0x15, 0x3d, 0x08,
- 0x55, 0x02, 0x67, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00, 0x98, 0x00,
- 0x9f, 0x00, 0xa5, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xb1, 0x00, 0xb4, 0x00,
- 0xb6, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc0, 0x00,
- 0x7f, 0x0a, 0x8d, 0x04, 0x99, 0x01, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00,
- 0xb6, 0x00, 0xba, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc3, 0x00, 0xc5, 0x00,
- 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcc, 0x00,
- 0xcd, 0x00, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x1c, 0x57, 0x11,
- 0x64, 0x0a, 0x70, 0x06, 0x79, 0x03, 0x82, 0x02, 0x8a, 0x00, 0x91, 0x00,
- 0x97, 0x00, 0x9c, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa9, 0x00, 0xad, 0x00,
- 0xaf, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb9, 0x00, 0xba, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x17, 0x38, 0x0b, 0x4c, 0x04, 0x5e, 0x01,
- 0x6c, 0x00, 0x7a, 0x00, 0x84, 0x00, 0x8d, 0x00, 0x95, 0x00, 0x9b, 0x00,
- 0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb2, 0x00,
- 0xb4, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0x7f, 0x0b, 0x8a, 0x05,
- 0x94, 0x02, 0x9d, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb5, 0x00,
- 0xb9, 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00,
- 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x47, 0x20, 0x54, 0x15, 0x5f, 0x0e, 0x69, 0x09,
- 0x72, 0x05, 0x7a, 0x03, 0x82, 0x02, 0x88, 0x01, 0x8f, 0x00, 0x94, 0x00,
- 0x99, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa4, 0x00, 0xa8, 0x00, 0xac, 0x00,
- 0xae, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0x22, 0x18, 0x35, 0x0d, 0x47, 0x06, 0x55, 0x03, 0x64, 0x01, 0x70, 0x00,
- 0x7a, 0x00, 0x83, 0x00, 0x8b, 0x00, 0x92, 0x00, 0x98, 0x00, 0x9d, 0x00,
- 0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00,
- 0xb2, 0x00, 0xb4, 0x00, 0x7f, 0x0c, 0x89, 0x06, 0x92, 0x03, 0x99, 0x01,
- 0xa0, 0x00, 0xa6, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb4, 0x00, 0xb7, 0x00,
- 0xba, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00,
- 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x46, 0x23, 0x50, 0x18, 0x5b, 0x11, 0x64, 0x0b, 0x6c, 0x08, 0x74, 0x05,
- 0x7b, 0x03, 0x82, 0x02, 0x87, 0x01, 0x8c, 0x00, 0x91, 0x00, 0x95, 0x00,
- 0x9a, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa4, 0x00, 0xa7, 0x00, 0xab, 0x00,
- 0xac, 0x00, 0xaf, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1a, 0x32, 0x0f,
- 0x42, 0x08, 0x50, 0x04, 0x5c, 0x02, 0x68, 0x00, 0x72, 0x00, 0x7b, 0x00,
- 0x83, 0x00, 0x8a, 0x00, 0x90, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9e, 0x00,
- 0xa1, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00,
- 0x7f, 0x0d, 0x88, 0x07, 0x8f, 0x04, 0x96, 0x02, 0x9c, 0x01, 0xa2, 0x00,
- 0xa7, 0x00, 0xac, 0x00, 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb9, 0x00,
- 0xbb, 0x00, 0xbd, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00,
- 0xc5, 0x00, 0xc6, 0x00, 0x2f, 0x00, 0x5f, 0x00, 0x99, 0x00, 0xac, 0x00,
- 0xb3, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00,
- 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00,
- 0x3b, 0x0b, 0x6f, 0x00, 0x9f, 0x00, 0xaf, 0x00, 0xb5, 0x00, 0xb9, 0x00,
- 0xba, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00,
- 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x6d, 0x00, 0x8d, 0x00, 0x9b, 0x00,
- 0xa6, 0x00, 0xb2, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00,
- 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00,
- 0x47, 0x07, 0x7f, 0x00, 0xa5, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xba, 0x00,
- 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00,
- 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x45, 0x25, 0x4e, 0x1b,
- 0x57, 0x13, 0x60, 0x0e, 0x68, 0x0a, 0x6f, 0x07, 0x76, 0x05, 0x7b, 0x03,
- 0x82, 0x02, 0x86, 0x02, 0x8b, 0x01, 0x90, 0x00, 0x93, 0x00, 0x97, 0x00,
- 0x9b, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa6, 0x00, 0xaa, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0x22, 0x1b, 0x30, 0x11, 0x3e, 0x0a, 0x4b, 0x05,
- 0x57, 0x03, 0x61, 0x01, 0x6b, 0x00, 0x73, 0x00, 0x7c, 0x00, 0x82, 0x00,
- 0x88, 0x00, 0x8f, 0x00, 0x93, 0x00, 0x97, 0x00, 0x9c, 0x00, 0x9f, 0x00,
- 0xa2, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0x7f, 0x0d, 0x86, 0x08,
- 0x8d, 0x05, 0x94, 0x02, 0x9a, 0x01, 0x9f, 0x00, 0xa4, 0x00, 0xa8, 0x00,
- 0xac, 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00,
- 0xbc, 0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00,
- 0x00, 0x00, 0x0f, 0x00, 0x5f, 0x00, 0x8b, 0x00, 0x9f, 0x00, 0xaa, 0x00,
- 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00,
- 0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x07, 0x17, 0x27, 0x02,
- 0x6f, 0x00, 0x93, 0x00, 0xa4, 0x00, 0xad, 0x00, 0xb2, 0x00, 0xb5, 0x00,
- 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00,
- 0xbc, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x6d, 0x00, 0x54, 0x00, 0x6b, 0x00, 0x87, 0x00, 0x98, 0x00, 0xa6, 0x00,
- 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00,
- 0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x0f, 0x0f, 0x3f, 0x00,
- 0x7f, 0x00, 0x9c, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb5, 0x00, 0xb7, 0x00,
- 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00,
- 0xbd, 0x00, 0xbd, 0x00, 0x45, 0x28, 0x4d, 0x1d, 0x55, 0x16, 0x5d, 0x11,
- 0x64, 0x0c, 0x6b, 0x09, 0x71, 0x07, 0x77, 0x05, 0x7b, 0x03, 0x81, 0x02,
- 0x85, 0x02, 0x8a, 0x01, 0x8e, 0x00, 0x92, 0x00, 0x95, 0x00, 0x98, 0x00,
- 0x9d, 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0x21, 0x1b, 0x2f, 0x12, 0x3b, 0x0c, 0x47, 0x07, 0x51, 0x04, 0x5c, 0x02,
- 0x65, 0x01, 0x6e, 0x00, 0x75, 0x00, 0x7c, 0x00, 0x82, 0x00, 0x88, 0x00,
- 0x8d, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9c, 0x00, 0xa0, 0x00,
- 0xa2, 0x00, 0xa5, 0x00, 0x7f, 0x0d, 0x86, 0x09, 0x8c, 0x06, 0x92, 0x03,
- 0x97, 0x02, 0x9c, 0x01, 0xa1, 0x00, 0xa5, 0x00, 0xa9, 0x00, 0xac, 0x00,
- 0xaf, 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00,
- 0xbc, 0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x05, 0x00, 0x44, 0x00, 0x6d, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f, 0x00,
- 0xa6, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00,
- 0xb6, 0x00, 0xb7, 0x00, 0x00, 0x2c, 0x02, 0x12, 0x22, 0x00, 0x58, 0x00,
- 0x7a, 0x00, 0x8f, 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xaa, 0x00, 0xae, 0x00,
- 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x6b, 0x00,
- 0x28, 0x00, 0x52, 0x00, 0x70, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f, 0x00,
- 0xa6, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00,
- 0xb6, 0x00, 0xb7, 0x00, 0x00, 0x26, 0x05, 0x05, 0x3f, 0x00, 0x6d, 0x00,
- 0x88, 0x00, 0x99, 0x00, 0xa3, 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1, 0x00,
- 0xb4, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00,
- 0x44, 0x2a, 0x4b, 0x20, 0x53, 0x18, 0x5a, 0x13, 0x61, 0x0f, 0x67, 0x0b,
- 0x6d, 0x09, 0x73, 0x07, 0x77, 0x05, 0x7c, 0x03, 0x81, 0x02, 0x85, 0x02,
- 0x88, 0x01, 0x8d, 0x01, 0x90, 0x00, 0x93, 0x00, 0x96, 0x00, 0x9a, 0x00,
- 0x9d, 0x00, 0x9f, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x22, 0x1c, 0x2d, 0x13,
- 0x39, 0x0d, 0x44, 0x09, 0x4e, 0x05, 0x57, 0x04, 0x60, 0x02, 0x67, 0x01,
- 0x6f, 0x00, 0x76, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x87, 0x00, 0x8c, 0x00,
- 0x90, 0x00, 0x94, 0x00, 0x97, 0x00, 0x9a, 0x00, 0x9d, 0x00, 0xa0, 0x00,
- 0x7f, 0x0e, 0x85, 0x09, 0x8b, 0x06, 0x90, 0x04, 0x95, 0x02, 0x9a, 0x02,
- 0x9e, 0x01, 0xa2, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xad, 0x00, 0xaf, 0x00,
- 0xb2, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00,
- 0xbd, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
- 0x33, 0x00, 0x57, 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97, 0x00,
- 0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00,
- 0x00, 0x36, 0x00, 0x25, 0x09, 0x0b, 0x21, 0x00, 0x4a, 0x00, 0x68, 0x00,
- 0x7d, 0x00, 0x8b, 0x00, 0x96, 0x00, 0x9d, 0x00, 0xa3, 0x00, 0xa8, 0x00,
- 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x87, 0x00, 0x52, 0x00, 0x11, 0x00,
- 0x39, 0x00, 0x57, 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97, 0x00,
- 0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00,
- 0x00, 0x33, 0x00, 0x1c, 0x12, 0x00, 0x3f, 0x00, 0x62, 0x00, 0x7a, 0x00,
- 0x8a, 0x00, 0x96, 0x00, 0x9e, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xac, 0x00,
- 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0x43, 0x2b, 0x4a, 0x22,
- 0x51, 0x1a, 0x57, 0x15, 0x5e, 0x11, 0x63, 0x0d, 0x69, 0x0a, 0x6e, 0x08,
- 0x74, 0x06, 0x78, 0x05, 0x7c, 0x04, 0x81, 0x03, 0x84, 0x02, 0x87, 0x02,
- 0x8c, 0x01, 0x8f, 0x00, 0x92, 0x00, 0x94, 0x00, 0x97, 0x00, 0x9b, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1c, 0x2d, 0x14, 0x37, 0x0e, 0x41, 0x0a,
- 0x4a, 0x07, 0x53, 0x04, 0x5b, 0x02, 0x63, 0x01, 0x69, 0x00, 0x70, 0x00,
- 0x77, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x87, 0x00, 0x8a, 0x00, 0x8f, 0x00,
- 0x92, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x7f, 0x0e, 0x85, 0x0a,
- 0x8a, 0x07, 0x8f, 0x05, 0x93, 0x03, 0x98, 0x02, 0x9c, 0x01, 0xa0, 0x00,
- 0xa3, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb2, 0x00,
- 0xb3, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x28, 0x00,
- 0x48, 0x00, 0x5f, 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91, 0x00,
- 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x3a, 0x00, 0x2f,
- 0x00, 0x16, 0x0e, 0x08, 0x20, 0x00, 0x42, 0x00, 0x5c, 0x00, 0x6f, 0x00,
- 0x7e, 0x00, 0x89, 0x00, 0x92, 0x00, 0x99, 0x00, 0x9e, 0x00, 0xa2, 0x00,
- 0xa6, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xa6, 0x00, 0x98, 0x00, 0x70, 0x00, 0x39, 0x00, 0x02, 0x00, 0x28, 0x00,
- 0x48, 0x00, 0x5f, 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91, 0x00,
- 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x38, 0x00, 0x2a,
- 0x00, 0x09, 0x1d, 0x00, 0x3f, 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7f, 0x00,
- 0x8b, 0x00, 0x94, 0x00, 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00,
- 0xab, 0x00, 0xad, 0x00, 0x43, 0x2c, 0x49, 0x23, 0x50, 0x1c, 0x56, 0x17,
- 0x5b, 0x12, 0x61, 0x0f, 0x66, 0x0c, 0x6b, 0x0a, 0x6f, 0x08, 0x75, 0x06,
- 0x78, 0x05, 0x7c, 0x04, 0x81, 0x03, 0x84, 0x02, 0x87, 0x02, 0x8b, 0x01,
- 0x8e, 0x01, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0x22, 0x1c, 0x2c, 0x15, 0x36, 0x0f, 0x3e, 0x0b, 0x48, 0x07, 0x50, 0x05,
- 0x58, 0x04, 0x5f, 0x02, 0x66, 0x01, 0x6c, 0x00, 0x71, 0x00, 0x77, 0x00,
- 0x7d, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x91, 0x00,
- 0x94, 0x00, 0x97, 0x00, 0x7f, 0x0e, 0x84, 0x0a, 0x89, 0x07, 0x8d, 0x05,
- 0x92, 0x03, 0x96, 0x02, 0x9a, 0x02, 0x9e, 0x01, 0xa1, 0x00, 0xa4, 0x00,
- 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00,
- 0xb5, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x3d, 0x00,
- 0x52, 0x00, 0x64, 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d, 0x00,
- 0x93, 0x00, 0x98, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x23, 0x02, 0x0e,
- 0x12, 0x06, 0x20, 0x00, 0x3c, 0x00, 0x52, 0x00, 0x64, 0x00, 0x73, 0x00,
- 0x7e, 0x00, 0x87, 0x00, 0x8f, 0x00, 0x95, 0x00, 0x9a, 0x00, 0x9e, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x00, 0xa6, 0x00,
- 0x85, 0x00, 0x57, 0x00, 0x28, 0x00, 0x01, 0x00, 0x21, 0x00, 0x3d, 0x00,
- 0x52, 0x00, 0x64, 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d, 0x00,
- 0x93, 0x00, 0x98, 0x00, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x19, 0x05, 0x00,
- 0x24, 0x00, 0x3f, 0x00, 0x56, 0x00, 0x68, 0x00, 0x77, 0x00, 0x82, 0x00,
- 0x8b, 0x00, 0x93, 0x00, 0x99, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00,
- 0x43, 0x2e, 0x48, 0x25, 0x4e, 0x1e, 0x54, 0x19, 0x59, 0x14, 0x5f, 0x11,
- 0x63, 0x0e, 0x69, 0x0b, 0x6c, 0x09, 0x71, 0x07, 0x76, 0x06, 0x78, 0x05,
- 0x7c, 0x04, 0x81, 0x03, 0x84, 0x02, 0x86, 0x02, 0x8a, 0x01, 0x8e, 0x01,
- 0x90, 0x00, 0x92, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1d, 0x2b, 0x16,
- 0x34, 0x10, 0x3d, 0x0c, 0x45, 0x09, 0x4c, 0x06, 0x54, 0x04, 0x5b, 0x02,
- 0x61, 0x02, 0x67, 0x01, 0x6d, 0x00, 0x73, 0x00, 0x78, 0x00, 0x7d, 0x00,
- 0x81, 0x00, 0x86, 0x00, 0x89, 0x00, 0x8d, 0x00, 0x90, 0x00, 0x93, 0x00,
- 0x7f, 0x0e, 0x84, 0x0b, 0x88, 0x08, 0x8d, 0x06, 0x91, 0x04, 0x94, 0x03,
- 0x98, 0x02, 0x9c, 0x01, 0x9f, 0x01, 0xa2, 0x00, 0xa5, 0x00, 0xa8, 0x00,
- 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00,
- 0xb6, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48, 0x00,
- 0x59, 0x00, 0x66, 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89, 0x00,
- 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x18, 0x07, 0x0c, 0x14, 0x05,
- 0x20, 0x00, 0x37, 0x00, 0x4c, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x75, 0x00,
- 0x7e, 0x00, 0x86, 0x00, 0x8d, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70, 0x00,
- 0x48, 0x00, 0x21, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48, 0x00,
- 0x59, 0x00, 0x66, 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89, 0x00,
- 0x00, 0x3c, 0x00, 0x35, 0x00, 0x23, 0x00, 0x0b, 0x0f, 0x00, 0x29, 0x00,
- 0x3f, 0x00, 0x53, 0x00, 0x63, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x84, 0x00,
- 0x8b, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9b, 0x00, 0x42, 0x2f, 0x48, 0x26,
- 0x4d, 0x20, 0x52, 0x1a, 0x58, 0x16, 0x5c, 0x12, 0x61, 0x0f, 0x66, 0x0c,
- 0x6b, 0x0b, 0x6d, 0x09, 0x73, 0x07, 0x76, 0x06, 0x79, 0x05, 0x7d, 0x04,
- 0x81, 0x03, 0x83, 0x02, 0x86, 0x02, 0x89, 0x02, 0x8d, 0x01, 0x8f, 0x01,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0x22, 0x1d, 0x2a, 0x16, 0x33, 0x11, 0x3b, 0x0c,
- 0x43, 0x0a, 0x4a, 0x07, 0x51, 0x05, 0x58, 0x04, 0x5e, 0x02, 0x64, 0x01,
- 0x69, 0x01, 0x6f, 0x00, 0x74, 0x00, 0x78, 0x00, 0x7d, 0x00, 0x81, 0x00,
- 0x85, 0x00, 0x89, 0x00, 0x8b, 0x00, 0x8f, 0x00, 0x7f, 0x0e, 0x83, 0x0b,
- 0x88, 0x08, 0x8c, 0x06, 0x90, 0x05, 0x93, 0x03, 0x97, 0x02, 0x9a, 0x02,
- 0x9d, 0x01, 0xa0, 0x00, 0xa3, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00,
- 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0xb6, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50, 0x00,
- 0x5d, 0x00, 0x68, 0x00, 0x72, 0x00, 0x7a, 0x00, 0x00, 0x3d, 0x00, 0x3a,
- 0x00, 0x2f, 0x00, 0x20, 0x00, 0x10, 0x0b, 0x0a, 0x16, 0x04, 0x20, 0x00,
- 0x34, 0x00, 0x46, 0x00, 0x56, 0x00, 0x62, 0x00, 0x6d, 0x00, 0x77, 0x00,
- 0x7f, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xbb, 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d, 0x00,
- 0x1c, 0x00, 0x00, 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50, 0x00,
- 0x5d, 0x00, 0x68, 0x00, 0x72, 0x00, 0x7a, 0x00, 0x00, 0x3d, 0x00, 0x38,
- 0x00, 0x2a, 0x00, 0x16, 0x00, 0x00, 0x16, 0x00, 0x2c, 0x00, 0x3f, 0x00,
- 0x50, 0x00, 0x5e, 0x00, 0x6b, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x85, 0x00,
- 0x8b, 0x00, 0x91, 0x00, 0x42, 0x30, 0x47, 0x28, 0x4c, 0x21, 0x51, 0x1c,
- 0x56, 0x17, 0x5a, 0x14, 0x60, 0x11, 0x63, 0x0e, 0x68, 0x0c, 0x6c, 0x0a,
- 0x6f, 0x08, 0x74, 0x07, 0x77, 0x06, 0x79, 0x05, 0x7d, 0x04, 0x81, 0x03,
- 0x83, 0x02, 0x85, 0x02, 0x88, 0x02, 0x8c, 0x01, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0x21, 0x1e, 0x2a, 0x17, 0x32, 0x12, 0x39, 0x0e, 0x40, 0x0a, 0x48, 0x07,
- 0x4f, 0x05, 0x55, 0x04, 0x5a, 0x03, 0x60, 0x02, 0x66, 0x01, 0x6b, 0x00,
- 0x70, 0x00, 0x75, 0x00, 0x79, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x84, 0x00,
- 0x88, 0x00, 0x8b, 0x00, 0x7f, 0x0f, 0x83, 0x0b, 0x87, 0x09, 0x8b, 0x07,
- 0x8e, 0x05, 0x92, 0x03, 0x96, 0x02, 0x99, 0x02, 0x9b, 0x01, 0x9e, 0x01,
- 0xa1, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00,
- 0xaf, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x16, 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55, 0x00,
- 0x60, 0x00, 0x6a, 0x00, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x33, 0x00, 0x27,
- 0x00, 0x18, 0x04, 0x0d, 0x0e, 0x08, 0x17, 0x04, 0x20, 0x00, 0x32, 0x00,
- 0x42, 0x00, 0x50, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x70, 0x00, 0x78, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb6, 0x00,
- 0xa6, 0x00, 0x8e, 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19, 0x00,
- 0x00, 0x00, 0x16, 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55, 0x00,
- 0x60, 0x00, 0x6a, 0x00, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x2f, 0x00, 0x1f,
- 0x00, 0x0b, 0x08, 0x00, 0x1c, 0x00, 0x2e, 0x00, 0x3f, 0x00, 0x4e, 0x00,
- 0x5b, 0x00, 0x66, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x86, 0x00,
- 0x42, 0x31, 0x47, 0x29, 0x4b, 0x22, 0x50, 0x1d, 0x55, 0x19, 0x58, 0x15,
- 0x5e, 0x12, 0x61, 0x0f, 0x65, 0x0d, 0x6a, 0x0b, 0x6c, 0x09, 0x70, 0x08,
- 0x75, 0x07, 0x77, 0x06, 0x79, 0x05, 0x7d, 0x04, 0x81, 0x03, 0x83, 0x02,
- 0x85, 0x02, 0x87, 0x02, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1e, 0x29, 0x18,
- 0x31, 0x12, 0x38, 0x0f, 0x3f, 0x0c, 0x45, 0x09, 0x4c, 0x07, 0x52, 0x05,
- 0x58, 0x04, 0x5d, 0x02, 0x63, 0x02, 0x67, 0x01, 0x6c, 0x00, 0x71, 0x00,
- 0x75, 0x00, 0x79, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x84, 0x00, 0x88, 0x00,
- 0x7f, 0x0f, 0x83, 0x0c, 0x87, 0x09, 0x8a, 0x07, 0x8e, 0x06, 0x91, 0x04,
- 0x94, 0x03, 0x97, 0x02, 0x9a, 0x02, 0x9d, 0x01, 0xa0, 0x01, 0xa2, 0x00,
- 0xa4, 0x00, 0xa7, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00,
- 0xb0, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x13, 0x00, 0x25, 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59, 0x00,
- 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x12,
- 0x07, 0x0c, 0x10, 0x07, 0x18, 0x03, 0x20, 0x00, 0x30, 0x00, 0x3f, 0x00,
- 0x4c, 0x00, 0x57, 0x00, 0x61, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97, 0x00,
- 0x7e, 0x00, 0x64, 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00,
- 0x13, 0x00, 0x25, 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59, 0x00,
- 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x25, 0x00, 0x14, 0x00, 0x02,
- 0x0f, 0x00, 0x20, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4d, 0x00, 0x58, 0x00,
- 0x63, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x7b, 0x00, 0x42, 0x31, 0x46, 0x2a,
- 0x4a, 0x24, 0x4f, 0x1f, 0x53, 0x1a, 0x58, 0x16, 0x5c, 0x13, 0x60, 0x11,
- 0x63, 0x0e, 0x67, 0x0c, 0x6b, 0x0b, 0x6d, 0x09, 0x72, 0x07, 0x75, 0x07,
- 0x77, 0x06, 0x79, 0x05, 0x7e, 0x04, 0x81, 0x03, 0x83, 0x02, 0x85, 0x02,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1e, 0x29, 0x18, 0x30, 0x13, 0x37, 0x0f,
- 0x3d, 0x0c, 0x44, 0x0a, 0x4a, 0x07, 0x50, 0x05, 0x55, 0x04, 0x5b, 0x04,
- 0x60, 0x02, 0x64, 0x01, 0x69, 0x01, 0x6d, 0x00, 0x72, 0x00, 0x76, 0x00,
- 0x7a, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x83, 0x00, 0x7f, 0x0f, 0x83, 0x0c,
- 0x86, 0x09, 0x8a, 0x07, 0x8d, 0x06, 0x90, 0x05, 0x93, 0x03, 0x96, 0x02,
- 0x99, 0x02, 0x9c, 0x02, 0x9e, 0x01, 0xa0, 0x00, 0xa3, 0x00, 0xa5, 0x00,
- 0xa7, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00,
- 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x49, 0x00, 0x00, 0x3e, 0x00, 0x3c,
- 0x00, 0x37, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x19, 0x02, 0x0e, 0x0a, 0x0a,
- 0x11, 0x06, 0x19, 0x03, 0x1f, 0x00, 0x2e, 0x00, 0x3c, 0x00, 0x48, 0x00,
- 0x53, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71, 0x00,
- 0x59, 0x00, 0x41, 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00,
- 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x49, 0x00, 0x00, 0x3e, 0x00, 0x3c,
- 0x00, 0x34, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0c, 0x04, 0x00, 0x14, 0x00,
- 0x23, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x56, 0x00, 0x60, 0x00,
- 0x68, 0x00, 0x70, 0x00, 0x42, 0x32, 0x46, 0x2b, 0x49, 0x25, 0x4f, 0x1f,
- 0x52, 0x1b, 0x57, 0x18, 0x59, 0x14, 0x5f, 0x12, 0x62, 0x0f, 0x65, 0x0d,
- 0x6a, 0x0c, 0x6c, 0x0a, 0x6e, 0x09, 0x73, 0x07, 0x76, 0x06, 0x78, 0x06,
- 0x7a, 0x05, 0x7e, 0x04, 0x81, 0x03, 0x83, 0x02, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0x21, 0x1e, 0x28, 0x19, 0x2f, 0x14, 0x35, 0x0f, 0x3c, 0x0c, 0x42, 0x0a,
- 0x48, 0x07, 0x4e, 0x06, 0x53, 0x05, 0x58, 0x04, 0x5d, 0x02, 0x62, 0x02,
- 0x66, 0x01, 0x6b, 0x01, 0x6f, 0x00, 0x73, 0x00, 0x76, 0x00, 0x7a, 0x00,
- 0x7d, 0x00, 0x81, 0x00, 0x7f, 0x0f, 0x82, 0x0c, 0x86, 0x0a, 0x89, 0x07,
- 0x8c, 0x06, 0x8f, 0x05, 0x92, 0x03, 0x95, 0x03, 0x98, 0x02, 0x9a, 0x02,
- 0x9d, 0x01, 0x9f, 0x01, 0xa1, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00,
- 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
- 0x2d, 0x00, 0x39, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x31,
- 0x00, 0x28, 0x00, 0x1e, 0x00, 0x13, 0x05, 0x0d, 0x0c, 0x09, 0x13, 0x06,
- 0x19, 0x03, 0x1f, 0x00, 0x2d, 0x00, 0x3a, 0x00, 0x45, 0x00, 0x4f, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00,
- 0xb1, 0x00, 0xa3, 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50, 0x00,
- 0x3a, 0x00, 0x25, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
- 0x2d, 0x00, 0x39, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x36, 0x00, 0x2d,
- 0x00, 0x21, 0x00, 0x13, 0x00, 0x04, 0x0a, 0x00, 0x18, 0x00, 0x26, 0x00,
- 0x33, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x65, 0x00,
- 0x42, 0x33, 0x45, 0x2c, 0x48, 0x26, 0x4e, 0x21, 0x50, 0x1c, 0x56, 0x19,
- 0x58, 0x16, 0x5c, 0x13, 0x60, 0x11, 0x62, 0x0e, 0x67, 0x0c, 0x6a, 0x0b,
- 0x6d, 0x0a, 0x70, 0x09, 0x74, 0x07, 0x76, 0x06, 0x78, 0x06, 0x7a, 0x05,
- 0x7e, 0x04, 0x81, 0x03, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1e, 0x28, 0x19,
- 0x2f, 0x15, 0x35, 0x11, 0x3b, 0x0d, 0x41, 0x0b, 0x46, 0x09, 0x4c, 0x07,
- 0x51, 0x05, 0x55, 0x04, 0x5b, 0x04, 0x5f, 0x02, 0x63, 0x02, 0x68, 0x01,
- 0x6b, 0x00, 0x70, 0x00, 0x73, 0x00, 0x77, 0x00, 0x7b, 0x00, 0x7d, 0x00,
- 0x7f, 0x0f, 0x82, 0x0c, 0x86, 0x0a, 0x89, 0x08, 0x8c, 0x06, 0x8f, 0x05,
- 0x91, 0x04, 0x94, 0x03, 0x97, 0x02, 0x99, 0x02, 0x9c, 0x02, 0x9e, 0x01,
- 0xa0, 0x01, 0xa2, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00,
- 0xac, 0x00, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29, 0x00,
- 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x33, 0x00, 0x2c, 0x00, 0x23,
- 0x00, 0x19, 0x00, 0x0f, 0x07, 0x0c, 0x0e, 0x08, 0x14, 0x05, 0x1a, 0x02,
- 0x1f, 0x00, 0x2c, 0x00, 0x38, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7, 0x00,
- 0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35, 0x00,
- 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29, 0x00,
- 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x30, 0x00, 0x25, 0x00, 0x19,
- 0x00, 0x0c, 0x01, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x34, 0x00,
- 0x3f, 0x00, 0x49, 0x00, 0x53, 0x00, 0x5b, 0x00, 0x5d, 0x1a, 0x6d, 0x16,
- 0x72, 0x15, 0x75, 0x14, 0x77, 0x13, 0x78, 0x13, 0x79, 0x13, 0x7a, 0x12,
- 0x7a, 0x12, 0x7b, 0x12, 0x7b, 0x12, 0x7b, 0x12, 0x7c, 0x12, 0x7c, 0x11,
- 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7d, 0x11,
- 0xbd, 0x02, 0xa4, 0x06, 0x97, 0x09, 0x91, 0x0a, 0x8d, 0x0b, 0x8a, 0x0c,
- 0x89, 0x0d, 0x88, 0x0d, 0x86, 0x0d, 0x86, 0x0e, 0x85, 0x0e, 0x85, 0x0e,
- 0x84, 0x0e, 0x84, 0x0e, 0x83, 0x0f, 0x83, 0x0f, 0x83, 0x0f, 0x83, 0x0f,
- 0x82, 0x0f, 0x82, 0x0f, 0x33, 0x11, 0x5f, 0x11, 0x6f, 0x11, 0x74, 0x11,
- 0x77, 0x11, 0x78, 0x11, 0x7a, 0x11, 0x7a, 0x11, 0x7b, 0x11, 0x7b, 0x11,
- 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7d, 0x11, 0x7d, 0x11,
- 0x7d, 0x11, 0x7d, 0x11, 0x7d, 0x11, 0x7d, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x00, 0x3f, 0x00, 0x3e,
- 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x26, 0x00, 0x1d, 0x00, 0x14,
- 0x03, 0x0e, 0x09, 0x0b, 0x0f, 0x08, 0x15, 0x05, 0x1a, 0x02, 0x1f, 0x00,
- 0x2b, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d, 0x00,
- 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00,
- 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x00, 0x3f, 0x00, 0x3d,
- 0x00, 0x39, 0x00, 0x32, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x06,
- 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x3f, 0x00,
- 0x49, 0x00, 0x51, 0x00, 0x50, 0x24, 0x5f, 0x1f, 0x66, 0x1b, 0x6b, 0x19,
- 0x6e, 0x18, 0x70, 0x17, 0x73, 0x16, 0x73, 0x15, 0x75, 0x15, 0x76, 0x15,
- 0x76, 0x15, 0x77, 0x14, 0x77, 0x14, 0x78, 0x13, 0x78, 0x13, 0x79, 0x13,
- 0x79, 0x13, 0x7a, 0x13, 0x7a, 0x13, 0x7b, 0x13, 0xcc, 0x00, 0xb5, 0x00,
- 0xa8, 0x02, 0x9e, 0x04, 0x99, 0x05, 0x94, 0x06, 0x92, 0x07, 0x8f, 0x08,
- 0x8d, 0x09, 0x8c, 0x09, 0x8b, 0x0a, 0x8a, 0x0a, 0x89, 0x0b, 0x88, 0x0b,
- 0x88, 0x0b, 0x87, 0x0c, 0x87, 0x0c, 0x86, 0x0c, 0x86, 0x0c, 0x86, 0x0c,
- 0x23, 0x13, 0x46, 0x11, 0x58, 0x11, 0x63, 0x11, 0x69, 0x11, 0x6d, 0x11,
- 0x70, 0x11, 0x72, 0x11, 0x73, 0x11, 0x75, 0x11, 0x76, 0x11, 0x77, 0x11,
- 0x77, 0x11, 0x78, 0x11, 0x78, 0x11, 0x79, 0x11, 0x79, 0x11, 0x79, 0x11,
- 0x7a, 0x11, 0x7a, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x0d, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36,
- 0x00, 0x30, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00, 0x10, 0x05, 0x0d,
- 0x0b, 0x0a, 0x10, 0x07, 0x16, 0x04, 0x1b, 0x02, 0x1f, 0x00, 0x2a, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00,
- 0xb6, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72, 0x00,
- 0x60, 0x00, 0x4f, 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e, 0x00,
- 0x00, 0x00, 0x0d, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x33,
- 0x00, 0x2b, 0x00, 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00, 0x00, 0x0b, 0x00,
- 0x16, 0x00, 0x21, 0x00, 0x2c, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48, 0x00,
- 0x4a, 0x2a, 0x57, 0x24, 0x5f, 0x20, 0x64, 0x1e, 0x68, 0x1c, 0x6a, 0x1b,
- 0x6d, 0x19, 0x6e, 0x18, 0x70, 0x18, 0x72, 0x17, 0x72, 0x17, 0x73, 0x16,
- 0x74, 0x15, 0x75, 0x15, 0x76, 0x15, 0x76, 0x15, 0x76, 0x15, 0x76, 0x15,
- 0x76, 0x15, 0x77, 0x14, 0xd1, 0x00, 0xc0, 0x00, 0xb3, 0x00, 0xaa, 0x01,
- 0xa2, 0x02, 0x9d, 0x03, 0x99, 0x04, 0x96, 0x05, 0x94, 0x06, 0x92, 0x06,
- 0x90, 0x07, 0x8f, 0x07, 0x8d, 0x08, 0x8d, 0x08, 0x8c, 0x09, 0x8b, 0x09,
- 0x8a, 0x09, 0x8a, 0x0a, 0x89, 0x0a, 0x89, 0x0b, 0x22, 0x17, 0x39, 0x11,
- 0x4a, 0x11, 0x55, 0x11, 0x5e, 0x11, 0x63, 0x11, 0x67, 0x11, 0x6a, 0x11,
- 0x6c, 0x11, 0x6e, 0x11, 0x70, 0x11, 0x71, 0x11, 0x72, 0x11, 0x73, 0x11,
- 0x74, 0x11, 0x75, 0x11, 0x75, 0x11, 0x76, 0x11, 0x76, 0x11, 0x77, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00, 0x32, 0x00, 0x2c,
- 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x01, 0x0e, 0x07, 0x0c, 0x0c, 0x09,
- 0x11, 0x06, 0x16, 0x04, 0x1b, 0x02, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00,
- 0xa5, 0x00, 0x98, 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59, 0x00,
- 0x49, 0x00, 0x39, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00,
- 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x25,
- 0x00, 0x1c, 0x00, 0x11, 0x00, 0x07, 0x03, 0x00, 0x0e, 0x00, 0x19, 0x00,
- 0x23, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48, 0x2e, 0x53, 0x28,
- 0x5a, 0x24, 0x5f, 0x22, 0x63, 0x1f, 0x66, 0x1e, 0x69, 0x1c, 0x6a, 0x1b,
- 0x6c, 0x1a, 0x6d, 0x1a, 0x6e, 0x19, 0x70, 0x18, 0x71, 0x18, 0x72, 0x18,
- 0x72, 0x17, 0x72, 0x17, 0x73, 0x16, 0x74, 0x15, 0x75, 0x15, 0x76, 0x15,
- 0xd5, 0x00, 0xc6, 0x00, 0xbb, 0x00, 0xb2, 0x00, 0xaa, 0x00, 0xa4, 0x01,
- 0xa0, 0x02, 0x9c, 0x02, 0x9a, 0x03, 0x97, 0x04, 0x95, 0x05, 0x93, 0x05,
- 0x92, 0x06, 0x91, 0x06, 0x90, 0x07, 0x8e, 0x07, 0x8e, 0x07, 0x8d, 0x07,
- 0x8c, 0x08, 0x8c, 0x09, 0x22, 0x1a, 0x33, 0x13, 0x41, 0x11, 0x4c, 0x11,
- 0x54, 0x11, 0x5b, 0x11, 0x5f, 0x11, 0x63, 0x11, 0x66, 0x11, 0x68, 0x11,
- 0x6a, 0x11, 0x6c, 0x11, 0x6e, 0x11, 0x6f, 0x11, 0x70, 0x11, 0x71, 0x11,
- 0x72, 0x11, 0x72, 0x11, 0x73, 0x11, 0x74, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x07, 0x7f, 0x00,
- 0xa5, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00,
- 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00,
- 0xbe, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x47, 0x07, 0x0f, 0x0f, 0x00, 0x26, 0x00, 0x33, 0x00, 0x38, 0x00, 0x3a,
- 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e,
- 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x46, 0x31, 0x50, 0x2b, 0x56, 0x27, 0x5b, 0x24,
- 0x5f, 0x22, 0x62, 0x20, 0x65, 0x1f, 0x67, 0x1d, 0x69, 0x1d, 0x6a, 0x1b,
- 0x6c, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x19, 0x6f, 0x18, 0x71, 0x18,
- 0x72, 0x18, 0x72, 0x18, 0x72, 0x18, 0x72, 0x17, 0xd6, 0x00, 0xcb, 0x00,
- 0xc0, 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xab, 0x00, 0xa6, 0x01, 0xa2, 0x01,
- 0x9f, 0x02, 0x9c, 0x02, 0x9a, 0x03, 0x98, 0x03, 0x96, 0x04, 0x94, 0x05,
- 0x93, 0x05, 0x92, 0x06, 0x91, 0x06, 0x90, 0x06, 0x8f, 0x06, 0x8f, 0x07,
- 0x22, 0x1b, 0x2f, 0x15, 0x3b, 0x12, 0x44, 0x11, 0x4d, 0x11, 0x53, 0x11,
- 0x59, 0x11, 0x5d, 0x11, 0x60, 0x11, 0x63, 0x11, 0x66, 0x11, 0x67, 0x11,
- 0x69, 0x11, 0x6b, 0x11, 0x6c, 0x11, 0x6d, 0x11, 0x6e, 0x11, 0x6f, 0x11,
- 0x70, 0x11, 0x71, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x3f, 0x00, 0x7f, 0x00, 0x9c, 0x00,
- 0xaa, 0x00, 0xb1, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xba, 0x00,
- 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x3f, 0x00,
- 0x05, 0x05, 0x00, 0x1c, 0x00, 0x2a, 0x00, 0x31, 0x00, 0x35, 0x00, 0x38,
- 0x00, 0x39, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d,
- 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x45, 0x33, 0x4d, 0x2e, 0x53, 0x29, 0x58, 0x26, 0x5c, 0x24, 0x5f, 0x22,
- 0x61, 0x21, 0x65, 0x20, 0x65, 0x1e, 0x68, 0x1d, 0x69, 0x1d, 0x6a, 0x1b,
- 0x6b, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x19, 0x6f, 0x18,
- 0x71, 0x18, 0x72, 0x18, 0xd7, 0x00, 0xcd, 0x00, 0xc5, 0x00, 0xbd, 0x00,
- 0xb6, 0x00, 0xb0, 0x00, 0xab, 0x00, 0xa7, 0x00, 0xa4, 0x01, 0xa1, 0x02,
- 0x9e, 0x02, 0x9c, 0x02, 0x9a, 0x03, 0x98, 0x03, 0x97, 0x03, 0x96, 0x04,
- 0x94, 0x05, 0x93, 0x05, 0x92, 0x05, 0x91, 0x06, 0x21, 0x1c, 0x2d, 0x16,
- 0x37, 0x13, 0x40, 0x11, 0x47, 0x11, 0x4e, 0x11, 0x53, 0x11, 0x57, 0x11,
- 0x5b, 0x11, 0x5e, 0x11, 0x61, 0x11, 0x63, 0x11, 0x65, 0x11, 0x67, 0x11,
- 0x68, 0x11, 0x6a, 0x11, 0x6b, 0x11, 0x6c, 0x11, 0x6d, 0x11, 0x6e, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x26, 0x05, 0x05, 0x3f, 0x00, 0x6d, 0x00, 0x88, 0x00, 0x99, 0x00,
- 0xa3, 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00,
- 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x12, 0x00,
- 0x00, 0x09, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x32,
- 0x00, 0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3a,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x34, 0x4c, 0x2f,
- 0x51, 0x2c, 0x56, 0x28, 0x5a, 0x26, 0x5c, 0x24, 0x60, 0x23, 0x61, 0x21,
- 0x64, 0x20, 0x65, 0x1f, 0x66, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1c,
- 0x6b, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x19,
- 0xd8, 0x00, 0xcf, 0x00, 0xc7, 0x00, 0xc0, 0x00, 0xba, 0x00, 0xb5, 0x00,
- 0xb0, 0x00, 0xac, 0x00, 0xa8, 0x00, 0xa5, 0x01, 0xa2, 0x01, 0xa0, 0x02,
- 0x9e, 0x02, 0x9c, 0x02, 0x9a, 0x02, 0x99, 0x03, 0x97, 0x03, 0x96, 0x03,
- 0x95, 0x04, 0x94, 0x05, 0x22, 0x1d, 0x2b, 0x17, 0x34, 0x14, 0x3b, 0x12,
- 0x43, 0x11, 0x49, 0x11, 0x4e, 0x11, 0x52, 0x11, 0x56, 0x11, 0x5a, 0x11,
- 0x5d, 0x11, 0x5f, 0x11, 0x61, 0x11, 0x63, 0x11, 0x65, 0x11, 0x66, 0x11,
- 0x68, 0x11, 0x69, 0x11, 0x6a, 0x11, 0x6b, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x1c,
- 0x12, 0x00, 0x3f, 0x00, 0x62, 0x00, 0x7a, 0x00, 0x8a, 0x00, 0x96, 0x00,
- 0x9e, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb1, 0x00,
- 0xb3, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xb2, 0x00, 0x9c, 0x00, 0x6d, 0x00, 0x3f, 0x00, 0x1d, 0x00, 0x05, 0x00,
- 0x00, 0x0b, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d,
- 0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x44, 0x36, 0x4a, 0x31, 0x50, 0x2d, 0x54, 0x2a,
- 0x57, 0x28, 0x5b, 0x26, 0x5c, 0x24, 0x60, 0x23, 0x61, 0x21, 0x63, 0x20,
- 0x65, 0x20, 0x65, 0x1e, 0x67, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1c,
- 0x6a, 0x1b, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0xd9, 0x00, 0xd1, 0x00,
- 0xca, 0x00, 0xc3, 0x00, 0xbe, 0x00, 0xb9, 0x00, 0xb4, 0x00, 0xb0, 0x00,
- 0xac, 0x00, 0xa9, 0x00, 0xa6, 0x00, 0xa3, 0x01, 0xa1, 0x01, 0x9f, 0x02,
- 0x9d, 0x02, 0x9b, 0x02, 0x9a, 0x02, 0x99, 0x03, 0x98, 0x03, 0x97, 0x03,
- 0x21, 0x1e, 0x2a, 0x18, 0x32, 0x15, 0x39, 0x13, 0x3f, 0x12, 0x45, 0x11,
- 0x4a, 0x11, 0x4e, 0x11, 0x52, 0x11, 0x56, 0x11, 0x59, 0x11, 0x5c, 0x11,
- 0x5d, 0x11, 0x60, 0x11, 0x61, 0x11, 0x63, 0x11, 0x65, 0x11, 0x66, 0x11,
- 0x67, 0x11, 0x68, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x09, 0x1d, 0x00,
- 0x3f, 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7f, 0x00, 0x8b, 0x00, 0x94, 0x00,
- 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xad, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa, 0x00,
- 0x88, 0x00, 0x62, 0x00, 0x3f, 0x00, 0x24, 0x00, 0x0f, 0x00, 0x00, 0x00,
- 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29,
- 0x00, 0x2b, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x43, 0x36, 0x49, 0x32, 0x4e, 0x2f, 0x52, 0x2c, 0x56, 0x29, 0x58, 0x27,
- 0x5b, 0x26, 0x5d, 0x24, 0x60, 0x23, 0x60, 0x22, 0x62, 0x20, 0x65, 0x20,
- 0x65, 0x1f, 0x66, 0x1e, 0x68, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1c,
- 0x6a, 0x1b, 0x6c, 0x1a, 0xd9, 0x00, 0xd2, 0x00, 0xcc, 0x00, 0xc6, 0x00,
- 0xc1, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xb3, 0x00, 0xaf, 0x00, 0xac, 0x00,
- 0xa9, 0x00, 0xa6, 0x00, 0xa4, 0x01, 0xa2, 0x01, 0xa0, 0x01, 0x9e, 0x02,
- 0x9d, 0x02, 0x9c, 0x02, 0x9a, 0x02, 0x99, 0x02, 0x22, 0x1e, 0x29, 0x19,
- 0x30, 0x16, 0x36, 0x13, 0x3c, 0x12, 0x41, 0x11, 0x46, 0x11, 0x4a, 0x11,
- 0x4f, 0x11, 0x52, 0x11, 0x55, 0x11, 0x58, 0x11, 0x5a, 0x11, 0x5c, 0x11,
- 0x5f, 0x11, 0x60, 0x11, 0x62, 0x11, 0x63, 0x11, 0x65, 0x11, 0x66, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3a, 0x00, 0x31, 0x00, 0x19, 0x05, 0x00, 0x24, 0x00, 0x3f, 0x00,
- 0x56, 0x00, 0x68, 0x00, 0x77, 0x00, 0x82, 0x00, 0x8b, 0x00, 0x93, 0x00,
- 0x99, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb1, 0x00, 0x99, 0x00, 0x7a, 0x00,
- 0x5b, 0x00, 0x3f, 0x00, 0x29, 0x00, 0x16, 0x00, 0x08, 0x00, 0x00, 0x02,
- 0x00, 0x0c, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x22, 0x00, 0x25,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x37, 0x48, 0x33,
- 0x4d, 0x30, 0x51, 0x2d, 0x54, 0x2a, 0x57, 0x29, 0x59, 0x27, 0x5c, 0x26,
- 0x5d, 0x24, 0x60, 0x23, 0x60, 0x22, 0x62, 0x20, 0x65, 0x20, 0x65, 0x20,
- 0x65, 0x1f, 0x66, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1d,
- 0xd9, 0x00, 0xd3, 0x00, 0xcd, 0x00, 0xc8, 0x00, 0xc3, 0x00, 0xbe, 0x00,
- 0xba, 0x00, 0xb6, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00,
- 0xa7, 0x00, 0xa5, 0x00, 0xa3, 0x01, 0xa1, 0x01, 0xa0, 0x02, 0x9e, 0x02,
- 0x9d, 0x02, 0x9c, 0x02, 0x21, 0x1e, 0x28, 0x1a, 0x2e, 0x17, 0x34, 0x14,
- 0x39, 0x13, 0x3f, 0x12, 0x43, 0x11, 0x48, 0x11, 0x4b, 0x11, 0x4f, 0x11,
- 0x52, 0x11, 0x55, 0x11, 0x57, 0x11, 0x59, 0x11, 0x5c, 0x11, 0x5d, 0x11,
- 0x5f, 0x11, 0x61, 0x11, 0x62, 0x11, 0x63, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35,
- 0x00, 0x23, 0x00, 0x0b, 0x0f, 0x00, 0x29, 0x00, 0x3f, 0x00, 0x53, 0x00,
- 0x63, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x84, 0x00, 0x8b, 0x00, 0x92, 0x00,
- 0x97, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xbb, 0x00, 0xb5, 0x00, 0xa3, 0x00, 0x8a, 0x00, 0x6f, 0x00, 0x56, 0x00,
- 0x3f, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x00, 0x04,
- 0x00, 0x0c, 0x00, 0x12, 0x00, 0x17, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x43, 0x38, 0x48, 0x34, 0x4c, 0x31, 0x4f, 0x2e,
- 0x53, 0x2c, 0x56, 0x2a, 0x57, 0x28, 0x5a, 0x27, 0x5c, 0x26, 0x5d, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x61, 0x21, 0x64, 0x20, 0x65, 0x20, 0x65, 0x20,
- 0x65, 0x1e, 0x67, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0xd9, 0x00, 0xd4, 0x00,
- 0xce, 0x00, 0xca, 0x00, 0xc5, 0x00, 0xc1, 0x00, 0xbd, 0x00, 0xb9, 0x00,
- 0xb6, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa8, 0x00,
- 0xa6, 0x00, 0xa4, 0x01, 0xa2, 0x01, 0xa0, 0x01, 0x9f, 0x02, 0x9e, 0x02,
- 0x22, 0x1f, 0x27, 0x1a, 0x2d, 0x17, 0x33, 0x15, 0x38, 0x13, 0x3c, 0x13,
- 0x41, 0x12, 0x44, 0x11, 0x48, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x11,
- 0x54, 0x11, 0x57, 0x11, 0x59, 0x11, 0x5b, 0x11, 0x5c, 0x11, 0x5e, 0x11,
- 0x5f, 0x11, 0x61, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x16,
- 0x00, 0x00, 0x16, 0x00, 0x2c, 0x00, 0x3f, 0x00, 0x50, 0x00, 0x5e, 0x00,
- 0x6b, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x85, 0x00, 0x8b, 0x00, 0x91, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb7, 0x00,
- 0xaa, 0x00, 0x96, 0x00, 0x7f, 0x00, 0x68, 0x00, 0x53, 0x00, 0x3f, 0x00,
- 0x2e, 0x00, 0x20, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x06,
- 0x00, 0x0c, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x43, 0x38, 0x47, 0x35, 0x4b, 0x32, 0x4e, 0x2f, 0x52, 0x2d, 0x53, 0x2b,
- 0x57, 0x2a, 0x58, 0x27, 0x5b, 0x27, 0x5c, 0x25, 0x5d, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x61, 0x21, 0x64, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x1f,
- 0x66, 0x1e, 0x68, 0x1d, 0xda, 0x00, 0xd4, 0x00, 0xd0, 0x00, 0xcb, 0x00,
- 0xc7, 0x00, 0xc2, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb5, 0x00,
- 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa8, 0x00, 0xa6, 0x00,
- 0xa4, 0x00, 0xa3, 0x01, 0xa1, 0x01, 0xa0, 0x01, 0x21, 0x1f, 0x27, 0x1b,
- 0x2c, 0x18, 0x31, 0x16, 0x36, 0x14, 0x3a, 0x13, 0x3e, 0x12, 0x42, 0x11,
- 0x45, 0x11, 0x49, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x54, 0x11,
- 0x56, 0x11, 0x58, 0x11, 0x5a, 0x11, 0x5c, 0x11, 0x5d, 0x11, 0x5e, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3d, 0x00, 0x39, 0x00, 0x2f, 0x00, 0x1f, 0x00, 0x0b, 0x08, 0x00,
- 0x1c, 0x00, 0x2e, 0x00, 0x3f, 0x00, 0x4e, 0x00, 0x5b, 0x00, 0x66, 0x00,
- 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00,
- 0x8b, 0x00, 0x77, 0x00, 0x63, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x30, 0x00,
- 0x23, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x07,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x39, 0x46, 0x35,
- 0x4a, 0x32, 0x4e, 0x30, 0x50, 0x2e, 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x29,
- 0x58, 0x27, 0x5c, 0x27, 0x5c, 0x25, 0x5d, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x22, 0x63, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x1f,
- 0xda, 0x00, 0xd5, 0x00, 0xd1, 0x00, 0xcc, 0x00, 0xc8, 0x00, 0xc4, 0x00,
- 0xc1, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb7, 0x00, 0xb4, 0x00, 0xb2, 0x00,
- 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa9, 0x00, 0xa7, 0x00, 0xa5, 0x00,
- 0xa4, 0x01, 0xa2, 0x01, 0x22, 0x1f, 0x27, 0x1b, 0x2c, 0x18, 0x30, 0x16,
- 0x35, 0x14, 0x39, 0x13, 0x3d, 0x13, 0x40, 0x12, 0x44, 0x11, 0x47, 0x11,
- 0x49, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x54, 0x11, 0x56, 0x11,
- 0x58, 0x11, 0x59, 0x11, 0x5b, 0x11, 0x5c, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3b,
- 0x00, 0x32, 0x00, 0x25, 0x00, 0x14, 0x00, 0x02, 0x0f, 0x00, 0x20, 0x00,
- 0x30, 0x00, 0x3f, 0x00, 0x4d, 0x00, 0x58, 0x00, 0x63, 0x00, 0x6c, 0x00,
- 0x74, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x82, 0x00,
- 0x70, 0x00, 0x5e, 0x00, 0x4e, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x26, 0x00,
- 0x1c, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x42, 0x39, 0x46, 0x36, 0x4a, 0x33, 0x4d, 0x31,
- 0x4f, 0x2e, 0x52, 0x2d, 0x53, 0x2b, 0x57, 0x2a, 0x57, 0x28, 0x5a, 0x27,
- 0x5c, 0x27, 0x5c, 0x25, 0x5e, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x22,
- 0x62, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0xda, 0x00, 0xd6, 0x00,
- 0xd1, 0x00, 0xcd, 0x00, 0xc9, 0x00, 0xc6, 0x00, 0xc2, 0x00, 0xbf, 0x00,
- 0xbc, 0x00, 0xb9, 0x00, 0xb6, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf, 0x00,
- 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa7, 0x00, 0xa6, 0x00, 0xa4, 0x00,
- 0x21, 0x1f, 0x26, 0x1c, 0x2b, 0x19, 0x2f, 0x17, 0x33, 0x15, 0x37, 0x14,
- 0x3b, 0x13, 0x3e, 0x12, 0x41, 0x12, 0x44, 0x11, 0x47, 0x11, 0x4a, 0x11,
- 0x4d, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x54, 0x11, 0x55, 0x11, 0x57, 0x11,
- 0x59, 0x11, 0x5a, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x34, 0x00, 0x29,
- 0x00, 0x1b, 0x00, 0x0c, 0x04, 0x00, 0x14, 0x00, 0x23, 0x00, 0x32, 0x00,
- 0x3f, 0x00, 0x4b, 0x00, 0x56, 0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00,
- 0xb4, 0x00, 0xa9, 0x00, 0x9b, 0x00, 0x8b, 0x00, 0x7b, 0x00, 0x6b, 0x00,
- 0x5b, 0x00, 0x4d, 0x00, 0x3f, 0x00, 0x33, 0x00, 0x28, 0x00, 0x1f, 0x00,
- 0x16, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x42, 0x39, 0x45, 0x36, 0x49, 0x34, 0x4c, 0x31, 0x4f, 0x30, 0x51, 0x2e,
- 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x2a, 0x57, 0x28, 0x5b, 0x27, 0x5c, 0x27,
- 0x5c, 0x25, 0x5e, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x22, 0x61, 0x21,
- 0x64, 0x20, 0x65, 0x20, 0xda, 0x00, 0xd6, 0x00, 0xd2, 0x00, 0xce, 0x00,
- 0xcb, 0x00, 0xc7, 0x00, 0xc4, 0x00, 0xc1, 0x00, 0xbe, 0x00, 0xbb, 0x00,
- 0xb8, 0x00, 0xb6, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf, 0x00, 0xad, 0x00,
- 0xab, 0x00, 0xa9, 0x00, 0xa8, 0x00, 0xa6, 0x00, 0x22, 0x1f, 0x26, 0x1c,
- 0x2a, 0x19, 0x2e, 0x17, 0x32, 0x16, 0x36, 0x14, 0x39, 0x13, 0x3d, 0x13,
- 0x40, 0x12, 0x43, 0x11, 0x45, 0x11, 0x48, 0x11, 0x4b, 0x11, 0x4d, 0x11,
- 0x4f, 0x11, 0x51, 0x11, 0x53, 0x11, 0x55, 0x11, 0x56, 0x11, 0x58, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x36, 0x00, 0x2d, 0x00, 0x21, 0x00, 0x13,
- 0x00, 0x04, 0x0a, 0x00, 0x18, 0x00, 0x26, 0x00, 0x33, 0x00, 0x3f, 0x00,
- 0x4a, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xac, 0x00,
- 0xa0, 0x00, 0x93, 0x00, 0x84, 0x00, 0x75, 0x00, 0x66, 0x00, 0x58, 0x00,
- 0x4b, 0x00, 0x3f, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x19, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3a, 0x45, 0x37,
- 0x48, 0x35, 0x4a, 0x32, 0x4e, 0x31, 0x50, 0x2e, 0x53, 0x2e, 0x53, 0x2b,
- 0x57, 0x2a, 0x57, 0x29, 0x58, 0x27, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x25,
- 0x5e, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x61, 0x21, 0x64, 0x20,
- 0xdb, 0x00, 0xd7, 0x00, 0xd3, 0x00, 0xcf, 0x00, 0xcc, 0x00, 0xc8, 0x00,
- 0xc5, 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbc, 0x00, 0xba, 0x00, 0xb7, 0x00,
- 0xb5, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00,
- 0xa9, 0x00, 0xa8, 0x00, 0x21, 0x20, 0x26, 0x1c, 0x2a, 0x1a, 0x2d, 0x18,
- 0x31, 0x16, 0x35, 0x14, 0x38, 0x13, 0x3b, 0x13, 0x3e, 0x12, 0x41, 0x12,
- 0x44, 0x11, 0x46, 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11,
- 0x51, 0x11, 0x53, 0x11, 0x55, 0x11, 0x56, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d,
- 0x00, 0x38, 0x00, 0x30, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c, 0x01, 0x00,
- 0x0e, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x34, 0x00, 0x3f, 0x00, 0x49, 0x00,
- 0x53, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00,
- 0x8b, 0x00, 0x7e, 0x00, 0x70, 0x00, 0x63, 0x00, 0x56, 0x00, 0x4a, 0x00,
- 0x3f, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x42, 0x3a, 0x45, 0x37, 0x48, 0x35, 0x4a, 0x33,
- 0x4d, 0x31, 0x4f, 0x2f, 0x52, 0x2e, 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x2a,
- 0x57, 0x29, 0x59, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x25, 0x5f, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x22, 0xdb, 0x00, 0xd7, 0x00,
- 0xd3, 0x00, 0xd0, 0x00, 0xcc, 0x00, 0xc9, 0x00, 0xc6, 0x00, 0xc3, 0x00,
- 0xc1, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb9, 0x00, 0xb7, 0x00, 0xb5, 0x00,
- 0xb3, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00, 0xaa, 0x00,
- 0x21, 0x20, 0x25, 0x1d, 0x29, 0x1a, 0x2d, 0x18, 0x30, 0x17, 0x33, 0x15,
- 0x37, 0x14, 0x3a, 0x13, 0x3d, 0x13, 0x3f, 0x12, 0x42, 0x12, 0x44, 0x11,
- 0x47, 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11, 0x51, 0x11,
- 0x53, 0x11, 0x55, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x32,
- 0x00, 0x29, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x06, 0x06, 0x00, 0x13, 0x00,
- 0x1f, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x3f, 0x00, 0x49, 0x00, 0x51, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00,
- 0xb8, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9d, 0x00, 0x92, 0x00, 0x85, 0x00,
- 0x78, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3f, 0x00,
- 0x36, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x42, 0x3a, 0x45, 0x38, 0x47, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x30,
- 0x51, 0x2e, 0x53, 0x2e, 0x53, 0x2b, 0x56, 0x2a, 0x57, 0x2a, 0x57, 0x28,
- 0x5a, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x25, 0x5f, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0xdb, 0x00, 0xd7, 0x00, 0xd4, 0x00, 0xd0, 0x00,
- 0xcd, 0x00, 0xca, 0x00, 0xc7, 0x00, 0xc5, 0x00, 0xc2, 0x00, 0xbf, 0x00,
- 0xbd, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb4, 0x00, 0xb2, 0x00,
- 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xac, 0x00, 0x21, 0x20, 0x25, 0x1d,
- 0x29, 0x1a, 0x2c, 0x18, 0x2f, 0x17, 0x33, 0x16, 0x36, 0x14, 0x39, 0x13,
- 0x3b, 0x13, 0x3e, 0x13, 0x41, 0x12, 0x43, 0x11, 0x45, 0x11, 0x47, 0x11,
- 0x4a, 0x11, 0x4c, 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x52, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x33, 0x00, 0x2b, 0x00, 0x22,
- 0x00, 0x17, 0x00, 0x0c, 0x00, 0x00, 0x0b, 0x00, 0x16, 0x00, 0x21, 0x00,
- 0x2c, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb3, 0x00,
- 0xab, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x74, 0x00,
- 0x68, 0x00, 0x5d, 0x00, 0x53, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39,
- 0x46, 0x35, 0x4a, 0x34, 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x2e, 0x53, 0x2e,
- 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x58, 0x27, 0x5b, 0x27,
- 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x24, 0x5f, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0xdb, 0x00, 0xd8, 0x00, 0xd4, 0x00, 0xd1, 0x00, 0xce, 0x00, 0xcb, 0x00,
- 0xc8, 0x00, 0xc6, 0x00, 0xc3, 0x00, 0xc1, 0x00, 0xbe, 0x00, 0xbc, 0x00,
- 0xba, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb4, 0x00, 0xb2, 0x00, 0xb0, 0x00,
- 0xaf, 0x00, 0xad, 0x00, 0x21, 0x20, 0x25, 0x1d, 0x28, 0x1b, 0x2b, 0x18,
- 0x2f, 0x17, 0x32, 0x16, 0x35, 0x14, 0x38, 0x14, 0x3a, 0x13, 0x3d, 0x13,
- 0x3f, 0x12, 0x42, 0x12, 0x44, 0x11, 0x46, 0x11, 0x48, 0x11, 0x4a, 0x11,
- 0x4c, 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e,
- 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x25, 0x00, 0x1c, 0x00, 0x11,
- 0x00, 0x07, 0x03, 0x00, 0x0e, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2d, 0x00,
- 0x36, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xbe, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb4, 0x00, 0xad, 0x00, 0xa5, 0x00,
- 0x9b, 0x00, 0x91, 0x00, 0x86, 0x00, 0x7b, 0x00, 0x70, 0x00, 0x65, 0x00,
- 0x5b, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39, 0x46, 0x36, 0x4a, 0x35,
- 0x4a, 0x32, 0x4e, 0x31, 0x4f, 0x2f, 0x51, 0x2e, 0x53, 0x2e, 0x53, 0x2b,
- 0x56, 0x2a, 0x57, 0x2a, 0x57, 0x29, 0x59, 0x27, 0x5c, 0x27, 0x5c, 0x27,
- 0x5c, 0x26, 0x5c, 0x24, 0x5f, 0x23, 0x60, 0x23, 0xdb, 0x00, 0xd8, 0x00,
- 0xd5, 0x00, 0xd2, 0x00, 0xcf, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xc6, 0x00,
- 0xc4, 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb9, 0x00,
- 0xb8, 0x00, 0xb5, 0x00, 0xb4, 0x00, 0xb2, 0x00, 0xb0, 0x00, 0xaf, 0x00,
- 0x21, 0x20, 0x25, 0x1d, 0x28, 0x1b, 0x2b, 0x19, 0x2e, 0x17, 0x31, 0x16,
- 0x34, 0x15, 0x37, 0x14, 0x39, 0x13, 0x3b, 0x13, 0x3e, 0x13, 0x40, 0x12,
- 0x42, 0x12, 0x45, 0x11, 0x46, 0x11, 0x49, 0x11, 0x4a, 0x11, 0x4c, 0x11,
- 0x4e, 0x11, 0x4f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11,
- 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x27, 0x68, 0x32, 0x51, 0x36, 0x4a, 0x38, 0x47,
- 0x3a, 0x46, 0x3a, 0x45, 0x3b, 0x44, 0x3c, 0x43, 0x3c, 0x43, 0x3c, 0x43,
- 0x3c, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x41,
- 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x41, 0x0e, 0x16, 0x27,
- 0x23, 0x31, 0x2a, 0x35, 0x2e, 0x38, 0x31, 0x39, 0x33, 0x3a, 0x34, 0x3b,
- 0x35, 0x3b, 0x36, 0x3c, 0x37, 0x3c, 0x38, 0x3c, 0x38, 0x3c, 0x39, 0x3d,
- 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3b, 0x3d,
- 0x68, 0x00, 0x32, 0x27, 0x36, 0x31, 0x38, 0x35, 0x3a, 0x38, 0x3a, 0x39,
- 0x3b, 0x3a, 0x3c, 0x3b, 0x3c, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3c,
- 0x3d, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
- 0x3d, 0x3d, 0x3d, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x5f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x22, 0x32, 0x28, 0x36, 0x2c, 0x38, 0x2f, 0x3a, 0x32, 0x3a, 0x34, 0x3b,
- 0x35, 0x3c, 0x36, 0x3c, 0x37, 0x3c, 0x37, 0x3c, 0x38, 0x3d, 0x39, 0x3d,
- 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
- 0x3b, 0x3d, 0x3b, 0x3d, 0x00, 0x97, 0x01, 0x67, 0x09, 0x56, 0x11, 0x4f,
- 0x17, 0x4b, 0x1c, 0x49, 0x20, 0x47, 0x23, 0x46, 0x25, 0x45, 0x28, 0x44,
- 0x2a, 0x44, 0x2b, 0x43, 0x2c, 0x43, 0x2e, 0x43, 0x2f, 0x42, 0x30, 0x42,
- 0x31, 0x42, 0x31, 0x42, 0x32, 0x42, 0x33, 0x42, 0x1a, 0x5c, 0x25, 0x4f,
- 0x2a, 0x4a, 0x2e, 0x48, 0x31, 0x46, 0x33, 0x45, 0x34, 0x44, 0x36, 0x44,
- 0x37, 0x43, 0x37, 0x43, 0x38, 0x43, 0x38, 0x42, 0x39, 0x42, 0x39, 0x42,
- 0x39, 0x41, 0x3a, 0x41, 0x3a, 0x41, 0x3a, 0x41, 0x3b, 0x41, 0x3b, 0x41,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x5f,
- 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x33, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x28, 0x25, 0x2d,
- 0x28, 0x30, 0x2b, 0x32, 0x2e, 0x34, 0x2f, 0x35, 0x31, 0x36, 0x32, 0x37,
- 0x33, 0x38, 0x34, 0x38, 0x35, 0x39, 0x36, 0x39, 0x36, 0x39, 0x36, 0x3a,
- 0x37, 0x3a, 0x37, 0x3a, 0x38, 0x3b, 0x38, 0x3b, 0x39, 0x3b, 0x39, 0x3b,
- 0x00, 0xb7, 0x00, 0x8b, 0x02, 0x72, 0x07, 0x65, 0x0c, 0x5c, 0x11, 0x57,
- 0x15, 0x53, 0x18, 0x50, 0x1b, 0x4e, 0x1d, 0x4d, 0x20, 0x4b, 0x22, 0x4a,
- 0x23, 0x49, 0x25, 0x48, 0x26, 0x48, 0x28, 0x47, 0x29, 0x47, 0x2a, 0x46,
- 0x2b, 0x46, 0x2c, 0x45, 0x16, 0x6d, 0x1f, 0x5f, 0x24, 0x57, 0x28, 0x53,
- 0x2b, 0x50, 0x2d, 0x4d, 0x2f, 0x4c, 0x31, 0x4a, 0x32, 0x49, 0x33, 0x48,
- 0x34, 0x48, 0x35, 0x47, 0x35, 0x46, 0x36, 0x46, 0x36, 0x45, 0x37, 0x45,
- 0x38, 0x45, 0x38, 0x45, 0x39, 0x44, 0x39, 0x44, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x8b, 0x00, 0x44, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x2e, 0x00,
- 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x25, 0x23, 0x28, 0x26, 0x2b, 0x28, 0x2e,
- 0x2a, 0x2f, 0x2c, 0x31, 0x2e, 0x32, 0x2f, 0x33, 0x30, 0x34, 0x31, 0x35,
- 0x32, 0x36, 0x33, 0x36, 0x33, 0x36, 0x34, 0x37, 0x35, 0x38, 0x36, 0x38,
- 0x36, 0x39, 0x36, 0x39, 0x36, 0x39, 0x36, 0x39, 0x00, 0xc5, 0x00, 0xa0,
- 0x00, 0x87, 0x03, 0x76, 0x06, 0x6b, 0x0a, 0x64, 0x0e, 0x5f, 0x11, 0x5b,
- 0x13, 0x57, 0x16, 0x55, 0x18, 0x53, 0x1a, 0x51, 0x1c, 0x50, 0x1e, 0x4e,
- 0x20, 0x4d, 0x21, 0x4c, 0x22, 0x4b, 0x24, 0x4a, 0x25, 0x49, 0x26, 0x48,
- 0x15, 0x72, 0x1b, 0x66, 0x20, 0x5f, 0x24, 0x5a, 0x27, 0x56, 0x29, 0x53,
- 0x2c, 0x51, 0x2d, 0x50, 0x2f, 0x4e, 0x30, 0x4d, 0x31, 0x4c, 0x32, 0x4b,
- 0x32, 0x4a, 0x33, 0x49, 0x34, 0x49, 0x35, 0x48, 0x35, 0x48, 0x35, 0x47,
- 0x35, 0x46, 0x36, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x6d, 0x00, 0x33, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x24, 0x00, 0x11, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x22, 0x24, 0x23, 0x26, 0x25, 0x29, 0x27, 0x2b, 0x28, 0x2c, 0x2a, 0x2e,
- 0x2c, 0x2f, 0x2d, 0x30, 0x2e, 0x31, 0x2f, 0x32, 0x30, 0x33, 0x30, 0x33,
- 0x32, 0x34, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36, 0x33, 0x36, 0x34, 0x36,
- 0x35, 0x36, 0x36, 0x37, 0x00, 0xcb, 0x00, 0xad, 0x00, 0x96, 0x01, 0x84,
- 0x03, 0x78, 0x06, 0x70, 0x09, 0x69, 0x0b, 0x64, 0x0e, 0x60, 0x10, 0x5d,
- 0x13, 0x59, 0x15, 0x57, 0x17, 0x56, 0x19, 0x54, 0x1a, 0x52, 0x1c, 0x51,
- 0x1d, 0x50, 0x1f, 0x4f, 0x1f, 0x4f, 0x21, 0x4e, 0x14, 0x75, 0x19, 0x6b,
- 0x1e, 0x64, 0x22, 0x5f, 0x24, 0x5b, 0x27, 0x58, 0x29, 0x56, 0x2a, 0x54,
- 0x2c, 0x52, 0x2d, 0x51, 0x2e, 0x4f, 0x2f, 0x4e, 0x30, 0x4e, 0x31, 0x4d,
- 0x31, 0x4c, 0x32, 0x4a, 0x33, 0x4a, 0x33, 0x4a, 0x34, 0x4a, 0x35, 0x4a,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa,
- 0x00, 0x85, 0x00, 0x57, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x1d, 0x00, 0x0d, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x23, 0x23, 0x25,
- 0x24, 0x27, 0x25, 0x28, 0x27, 0x2a, 0x28, 0x2c, 0x2a, 0x2d, 0x2b, 0x2e,
- 0x2c, 0x2f, 0x2d, 0x30, 0x2e, 0x31, 0x2f, 0x32, 0x30, 0x32, 0x30, 0x33,
- 0x31, 0x33, 0x32, 0x33, 0x33, 0x34, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36,
- 0x00, 0xcf, 0x00, 0xb6, 0x00, 0xa0, 0x00, 0x8f, 0x01, 0x83, 0x03, 0x79,
- 0x05, 0x72, 0x08, 0x6c, 0x0a, 0x68, 0x0c, 0x64, 0x0f, 0x61, 0x10, 0x5e,
- 0x12, 0x5b, 0x14, 0x59, 0x16, 0x58, 0x17, 0x56, 0x19, 0x55, 0x1a, 0x53,
- 0x1b, 0x52, 0x1c, 0x50, 0x13, 0x77, 0x18, 0x6e, 0x1c, 0x68, 0x1f, 0x63,
- 0x22, 0x5f, 0x24, 0x5c, 0x26, 0x59, 0x28, 0x57, 0x29, 0x56, 0x2a, 0x54,
- 0x2c, 0x53, 0x2d, 0x52, 0x2e, 0x50, 0x2e, 0x4f, 0x2f, 0x4f, 0x31, 0x4e,
- 0x31, 0x4d, 0x31, 0x4d, 0x31, 0x4c, 0x32, 0x4a, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70,
- 0x00, 0x48, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3a, 0x00,
- 0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x23, 0x22, 0x24, 0x24, 0x26, 0x25, 0x27,
- 0x26, 0x29, 0x27, 0x2a, 0x28, 0x2b, 0x2a, 0x2d, 0x2a, 0x2d, 0x2c, 0x2e,
- 0x2d, 0x30, 0x2d, 0x30, 0x2e, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33,
- 0x30, 0x33, 0x31, 0x33, 0x32, 0x33, 0x33, 0x34, 0x00, 0xd1, 0x00, 0xbc,
- 0x00, 0xa9, 0x00, 0x99, 0x00, 0x8c, 0x02, 0x82, 0x03, 0x7a, 0x05, 0x74,
- 0x07, 0x6f, 0x09, 0x6b, 0x0b, 0x67, 0x0d, 0x63, 0x0f, 0x61, 0x10, 0x5f,
- 0x12, 0x5c, 0x14, 0x5a, 0x15, 0x58, 0x16, 0x58, 0x18, 0x57, 0x19, 0x56,
- 0x13, 0x78, 0x17, 0x70, 0x1b, 0x6a, 0x1e, 0x66, 0x20, 0x62, 0x22, 0x5f,
- 0x24, 0x5c, 0x26, 0x5b, 0x27, 0x58, 0x29, 0x57, 0x2a, 0x56, 0x2b, 0x53,
- 0x2c, 0x53, 0x2d, 0x52, 0x2e, 0x51, 0x2e, 0x50, 0x2f, 0x4f, 0x30, 0x4f,
- 0x31, 0x4f, 0x31, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xbb, 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d,
- 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00,
- 0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x22, 0x22, 0x22, 0x24, 0x23, 0x25, 0x24, 0x27, 0x25, 0x27, 0x27, 0x28,
- 0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2e,
- 0x2d, 0x30, 0x2d, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x33,
- 0x30, 0x33, 0x31, 0x33, 0x00, 0xd3, 0x00, 0xc1, 0x00, 0xaf, 0x00, 0xa1,
- 0x00, 0x94, 0x00, 0x8a, 0x02, 0x82, 0x03, 0x7b, 0x05, 0x76, 0x07, 0x71,
- 0x09, 0x6d, 0x0a, 0x69, 0x0c, 0x66, 0x0e, 0x63, 0x0f, 0x61, 0x10, 0x60,
- 0x12, 0x5d, 0x13, 0x5c, 0x14, 0x59, 0x16, 0x58, 0x13, 0x79, 0x16, 0x72,
- 0x19, 0x6d, 0x1c, 0x69, 0x1f, 0x65, 0x20, 0x61, 0x23, 0x60, 0x24, 0x5c,
- 0x26, 0x5b, 0x27, 0x59, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2b, 0x53,
- 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2e, 0x51, 0x2e, 0x4f, 0x2f, 0x4f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb6,
- 0x00, 0xa6, 0x00, 0x8e, 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x25, 0x00, 0x1b, 0x00,
- 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x23,
- 0x23, 0x24, 0x24, 0x25, 0x25, 0x27, 0x26, 0x28, 0x26, 0x28, 0x28, 0x2a,
- 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2d, 0x2a, 0x2d, 0x2c, 0x2d, 0x2d, 0x2e,
- 0x2d, 0x30, 0x2d, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x32,
- 0x00, 0xd4, 0x00, 0xc4, 0x00, 0xb5, 0x00, 0xa7, 0x00, 0x9b, 0x00, 0x91,
- 0x01, 0x88, 0x02, 0x82, 0x03, 0x7b, 0x05, 0x77, 0x07, 0x73, 0x08, 0x6e,
- 0x0a, 0x6b, 0x0b, 0x69, 0x0c, 0x66, 0x0e, 0x63, 0x0f, 0x61, 0x10, 0x60,
- 0x12, 0x5f, 0x13, 0x5c, 0x12, 0x79, 0x15, 0x73, 0x18, 0x6e, 0x1b, 0x6a,
- 0x1d, 0x67, 0x20, 0x65, 0x21, 0x61, 0x23, 0x60, 0x24, 0x5d, 0x26, 0x5c,
- 0x27, 0x5a, 0x27, 0x58, 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2b, 0x53,
- 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x51, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97,
- 0x00, 0x7e, 0x00, 0x64, 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00,
- 0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00,
- 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25,
- 0x24, 0x26, 0x25, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x2a, 0x28, 0x2b,
- 0x2a, 0x2b, 0x2b, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2f,
- 0x2d, 0x30, 0x2d, 0x30, 0x2f, 0x30, 0x30, 0x30, 0x00, 0xd5, 0x00, 0xc7,
- 0x00, 0xb9, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8f, 0x01, 0x87,
- 0x02, 0x82, 0x03, 0x7b, 0x05, 0x77, 0x06, 0x74, 0x08, 0x6f, 0x09, 0x6c,
- 0x0b, 0x6b, 0x0c, 0x68, 0x0d, 0x65, 0x0e, 0x63, 0x0f, 0x62, 0x10, 0x60,
- 0x12, 0x7a, 0x15, 0x75, 0x18, 0x70, 0x1a, 0x6c, 0x1d, 0x69, 0x1e, 0x65,
- 0x20, 0x64, 0x21, 0x61, 0x23, 0x60, 0x24, 0x5d, 0x26, 0x5c, 0x27, 0x5b,
- 0x27, 0x58, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2b, 0x53,
- 0x2c, 0x53, 0x2e, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71,
- 0x00, 0x59, 0x00, 0x41, 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x34, 0x00,
- 0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x06, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x23, 0x24, 0x24, 0x25, 0x25, 0x27,
- 0x25, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x29, 0x2b,
- 0x2b, 0x2b, 0x2b, 0x2d, 0x2b, 0x2d, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2f,
- 0x2d, 0x30, 0x2d, 0x30, 0x00, 0xd6, 0x00, 0xc9, 0x00, 0xbc, 0x00, 0xb1,
- 0x00, 0xa6, 0x00, 0x9c, 0x00, 0x94, 0x00, 0x8c, 0x02, 0x86, 0x02, 0x81,
- 0x03, 0x7c, 0x05, 0x78, 0x06, 0x75, 0x07, 0x71, 0x09, 0x6d, 0x0a, 0x6c,
- 0x0b, 0x6a, 0x0c, 0x67, 0x0d, 0x65, 0x0e, 0x62, 0x12, 0x7b, 0x15, 0x76,
- 0x18, 0x72, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d, 0x68, 0x1f, 0x65, 0x20, 0x63,
- 0x22, 0x60, 0x23, 0x60, 0x23, 0x5d, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5a,
- 0x28, 0x57, 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x2a, 0x55, 0x2b, 0x53,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba,
- 0x00, 0xb1, 0x00, 0xa3, 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50,
- 0x00, 0x3a, 0x00, 0x25, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29, 0x00,
- 0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x21, 0x22, 0x22, 0x23,
- 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x27, 0x26, 0x27,
- 0x27, 0x28, 0x27, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b,
- 0x2b, 0x2c, 0x2b, 0x2d, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2f,
- 0x00, 0xd6, 0x00, 0xcb, 0x00, 0xbf, 0x00, 0xb4, 0x00, 0xab, 0x00, 0xa1,
- 0x00, 0x99, 0x00, 0x91, 0x01, 0x8b, 0x02, 0x85, 0x02, 0x81, 0x04, 0x7c,
- 0x05, 0x78, 0x06, 0x76, 0x07, 0x73, 0x08, 0x6f, 0x09, 0x6c, 0x0b, 0x6b,
- 0x0c, 0x6a, 0x0c, 0x67, 0x12, 0x7b, 0x15, 0x76, 0x17, 0x72, 0x19, 0x6e,
- 0x1a, 0x6c, 0x1d, 0x69, 0x1d, 0x66, 0x20, 0x65, 0x20, 0x62, 0x22, 0x60,
- 0x23, 0x60, 0x23, 0x5d, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5b, 0x27, 0x58,
- 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7,
- 0x00, 0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35,
- 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
- 0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x26, 0x00, 0x1f, 0x00,
- 0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
- 0x24, 0x25, 0x24, 0x25, 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x28,
- 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c,
- 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x00, 0xd7, 0x00, 0xcc,
- 0x00, 0xc2, 0x00, 0xb8, 0x00, 0xae, 0x00, 0xa5, 0x00, 0x9e, 0x00, 0x95,
- 0x00, 0x90, 0x01, 0x8a, 0x02, 0x85, 0x03, 0x81, 0x04, 0x7c, 0x05, 0x78,
- 0x06, 0x76, 0x07, 0x74, 0x08, 0x70, 0x09, 0x6d, 0x0a, 0x6c, 0x0b, 0x6a,
- 0x12, 0x7b, 0x14, 0x77, 0x16, 0x73, 0x18, 0x70, 0x1a, 0x6d, 0x1c, 0x6a,
- 0x1d, 0x69, 0x1e, 0x65, 0x20, 0x65, 0x20, 0x62, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x5d, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x59, 0x28, 0x57,
- 0x2a, 0x57, 0x2a, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d,
- 0x00, 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f,
- 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00,
- 0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1c, 0x00, 0x16, 0x00,
- 0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x23, 0x24, 0x24, 0x25,
- 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x28, 0x26, 0x28, 0x28, 0x28,
- 0x28, 0x29, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2d,
- 0x2b, 0x2d, 0x2c, 0x2d, 0x00, 0xd7, 0x00, 0xcd, 0x00, 0xc4, 0x00, 0xbb,
- 0x00, 0xb1, 0x00, 0xa9, 0x00, 0xa1, 0x00, 0x9a, 0x00, 0x93, 0x00, 0x8e,
- 0x01, 0x88, 0x02, 0x84, 0x03, 0x81, 0x04, 0x7c, 0x05, 0x79, 0x06, 0x77,
- 0x07, 0x75, 0x07, 0x72, 0x09, 0x6e, 0x09, 0x6d, 0x12, 0x7b, 0x14, 0x77,
- 0x15, 0x73, 0x18, 0x71, 0x1a, 0x6d, 0x1a, 0x6b, 0x1d, 0x69, 0x1d, 0x67,
- 0x1f, 0x65, 0x20, 0x65, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5e,
- 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5a, 0x27, 0x58, 0x29, 0x57,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc,
- 0x00, 0xb6, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72,
- 0x00, 0x60, 0x00, 0x4f, 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39, 0x00, 0x35, 0x00, 0x31, 0x00,
- 0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0f, 0x00,
- 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x26,
- 0x25, 0x27, 0x27, 0x27, 0x27, 0x28, 0x26, 0x28, 0x28, 0x28, 0x28, 0x29,
- 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2b, 0x2d,
- 0x00, 0xd8, 0x00, 0xcf, 0x00, 0xc6, 0x00, 0xbd, 0x00, 0xb4, 0x00, 0xad,
- 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x97, 0x00, 0x92, 0x01, 0x8d, 0x02, 0x88,
- 0x02, 0x84, 0x03, 0x81, 0x04, 0x7d, 0x05, 0x79, 0x06, 0x77, 0x07, 0x75,
- 0x07, 0x73, 0x09, 0x70, 0x12, 0x7c, 0x13, 0x78, 0x15, 0x75, 0x18, 0x72,
- 0x19, 0x6e, 0x1a, 0x6d, 0x1c, 0x69, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65,
- 0x20, 0x64, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5e, 0x25, 0x5c,
- 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5b, 0x27, 0x59, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf,
- 0x00, 0xa5, 0x00, 0x98, 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59,
- 0x00, 0x49, 0x00, 0x39, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
- 0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x28, 0x00,
- 0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x09, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
- 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x25, 0x27,
- 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b,
- 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x00, 0xd8, 0x00, 0xd0,
- 0x00, 0xc7, 0x00, 0xbe, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa8, 0x00, 0xa1,
- 0x00, 0x9b, 0x00, 0x95, 0x00, 0x90, 0x01, 0x8c, 0x02, 0x87, 0x02, 0x84,
- 0x03, 0x81, 0x04, 0x7d, 0x05, 0x79, 0x06, 0x77, 0x06, 0x76, 0x07, 0x74,
- 0x11, 0x7c, 0x13, 0x78, 0x15, 0x76, 0x17, 0x72, 0x18, 0x6f, 0x1a, 0x6d,
- 0x1b, 0x6a, 0x1d, 0x69, 0x1d, 0x68, 0x1f, 0x65, 0x20, 0x65, 0x20, 0x64,
- 0x22, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5e, 0x25, 0x5c, 0x27, 0x5c,
- 0x27, 0x5c, 0x27, 0x5c, 0x00, 0x2f, 0x00, 0x5f, 0x00, 0x99, 0x00, 0xac,
- 0x00, 0xb3, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc,
- 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe,
- 0x00, 0x9a, 0x00, 0x6d, 0x00, 0x8d, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0xb2,
- 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd,
- 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0b, 0x3b, 0x00, 0x6f, 0x00, 0x9f, 0x00, 0xaf,
- 0x00, 0xb5, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd,
- 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe,
- 0x07, 0x47, 0x00, 0x7f, 0x00, 0xa5, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xba,
- 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe,
- 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x23, 0x24,
- 0x24, 0x25, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x27,
- 0x27, 0x29, 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x29, 0x2b,
- 0x2b, 0x2b, 0x2b, 0x2b, 0x00, 0xd8, 0x00, 0xd1, 0x00, 0xc9, 0x00, 0xc0,
- 0x00, 0xba, 0x00, 0xb1, 0x00, 0xac, 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x98,
- 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8b, 0x02, 0x86, 0x02, 0x83, 0x03, 0x81,
- 0x04, 0x7d, 0x05, 0x79, 0x06, 0x78, 0x06, 0x76, 0x11, 0x7c, 0x13, 0x79,
- 0x15, 0x76, 0x17, 0x72, 0x18, 0x71, 0x1a, 0x6d, 0x1a, 0x6d, 0x1c, 0x69,
- 0x1d, 0x69, 0x1d, 0x66, 0x20, 0x65, 0x20, 0x65, 0x20, 0x63, 0x22, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x5f, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5c,
- 0x00, 0x00, 0x00, 0x0f, 0x00, 0x5f, 0x00, 0x8b, 0x00, 0x9f, 0x00, 0xaa,
- 0x00, 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba,
- 0x00, 0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x6d, 0x00, 0x54,
- 0x00, 0x6b, 0x00, 0x87, 0x00, 0x98, 0x00, 0xa6, 0x00, 0xb0, 0x00, 0xb3,
- 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbb,
- 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x17, 0x07, 0x02, 0x27, 0x00, 0x6f, 0x00, 0x93, 0x00, 0xa4, 0x00, 0xad,
- 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb,
- 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x0f, 0x0f, 0x00, 0x3f,
- 0x00, 0x7f, 0x00, 0x9c, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb5, 0x00, 0xb7,
- 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd,
- 0x00, 0xbd, 0x00, 0xbd, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25,
- 0x25, 0x25, 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28,
- 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b, 0x2a, 0x2b,
- 0x00, 0xd9, 0x00, 0xd2, 0x00, 0xc9, 0x00, 0xc2, 0x00, 0xbb, 0x00, 0xb4,
- 0x00, 0xae, 0x00, 0xa7, 0x00, 0xa1, 0x00, 0x9d, 0x00, 0x96, 0x00, 0x92,
- 0x01, 0x8e, 0x01, 0x89, 0x02, 0x86, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7e,
- 0x05, 0x7a, 0x06, 0x78, 0x11, 0x7c, 0x13, 0x79, 0x15, 0x76, 0x16, 0x73,
- 0x18, 0x72, 0x19, 0x6e, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d, 0x69, 0x1d, 0x69,
- 0x1e, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0x62, 0x22, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x5f, 0x24, 0x5c, 0x26, 0x5c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x05, 0x00, 0x44, 0x00, 0x6d, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f,
- 0x00, 0xa6, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5,
- 0x00, 0xb6, 0x00, 0xb7, 0x00, 0x8d, 0x00, 0x6b, 0x00, 0x28, 0x00, 0x52,
- 0x00, 0x70, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f, 0x00, 0xa6, 0x00, 0xab,
- 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x12, 0x02,
- 0x00, 0x22, 0x00, 0x58, 0x00, 0x7a, 0x00, 0x8f, 0x00, 0x9c, 0x00, 0xa4,
- 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb7,
- 0x00, 0xb8, 0x00, 0xb9, 0x26, 0x00, 0x05, 0x05, 0x00, 0x3f, 0x00, 0x6d,
- 0x00, 0x88, 0x00, 0x99, 0x00, 0xa3, 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1,
- 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23,
- 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x25,
- 0x25, 0x27, 0x26, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b, 0x00, 0xd9, 0x00, 0xd2,
- 0x00, 0xca, 0x00, 0xc4, 0x00, 0xbd, 0x00, 0xb6, 0x00, 0xb0, 0x00, 0xaa,
- 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x94, 0x00, 0x91, 0x01, 0x8e,
- 0x02, 0x89, 0x02, 0x85, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7e, 0x05, 0x7a,
- 0x11, 0x7c, 0x13, 0x7a, 0x15, 0x76, 0x15, 0x74, 0x18, 0x72, 0x18, 0x6f,
- 0x1a, 0x6d, 0x1a, 0x6c, 0x1c, 0x69, 0x1d, 0x69, 0x1d, 0x67, 0x1f, 0x65,
- 0x20, 0x65, 0x20, 0x65, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x5f, 0x24, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
- 0x00, 0x33, 0x00, 0x57, 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97,
- 0x00, 0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf,
- 0x00, 0x9b, 0x00, 0x87, 0x00, 0x52, 0x00, 0x11, 0x00, 0x39, 0x00, 0x57,
- 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97, 0x00, 0x9e, 0x00, 0xa3,
- 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x25, 0x00, 0x0b, 0x09, 0x00, 0x21,
- 0x00, 0x4a, 0x00, 0x68, 0x00, 0x7d, 0x00, 0x8b, 0x00, 0x96, 0x00, 0x9d,
- 0x00, 0xa3, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2,
- 0x33, 0x00, 0x1c, 0x00, 0x00, 0x12, 0x00, 0x3f, 0x00, 0x62, 0x00, 0x7a,
- 0x00, 0x8a, 0x00, 0x96, 0x00, 0x9e, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xac,
- 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24,
- 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x25, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x2a, 0x00, 0xd9, 0x00, 0xd2, 0x00, 0xcb, 0x00, 0xc6,
- 0x00, 0xbe, 0x00, 0xb9, 0x00, 0xb1, 0x00, 0xac, 0x00, 0xa6, 0x00, 0xa1,
- 0x00, 0x9d, 0x00, 0x97, 0x00, 0x93, 0x00, 0x90, 0x01, 0x8d, 0x02, 0x88,
- 0x02, 0x85, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7e, 0x11, 0x7c, 0x13, 0x7a,
- 0x15, 0x76, 0x15, 0x75, 0x18, 0x72, 0x18, 0x71, 0x1a, 0x6d, 0x1a, 0x6d,
- 0x1b, 0x6a, 0x1d, 0x69, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65, 0x20, 0x65,
- 0x20, 0x64, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x28,
- 0x00, 0x48, 0x00, 0x5f, 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91,
- 0x00, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0x98,
- 0x00, 0x70, 0x00, 0x39, 0x00, 0x02, 0x00, 0x28, 0x00, 0x48, 0x00, 0x5f,
- 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91, 0x00, 0x98, 0x00, 0x9d,
- 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3a, 0x00, 0x2f, 0x00, 0x16, 0x00, 0x08, 0x0e, 0x00, 0x20, 0x00, 0x42,
- 0x00, 0x5c, 0x00, 0x6f, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x92, 0x00, 0x99,
- 0x00, 0x9e, 0x00, 0xa2, 0x00, 0xa6, 0x00, 0xa9, 0x38, 0x00, 0x2a, 0x00,
- 0x09, 0x00, 0x00, 0x1d, 0x00, 0x3f, 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7f,
- 0x00, 0x8b, 0x00, 0x94, 0x00, 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8,
- 0x00, 0xab, 0x00, 0xad, 0x16, 0xa4, 0x01, 0xbb, 0x00, 0xc6, 0x00, 0xcc,
- 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6,
- 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd9,
- 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xda, 0x05, 0x9d, 0x00, 0xbc,
- 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd5,
- 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xd8,
- 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x02, 0xbd, 0x00, 0xcc, 0x00, 0xd1, 0x00, 0xd5,
- 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9,
- 0x00, 0xd9, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00, 0xdb,
- 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x3d,
- 0x00, 0x52, 0x00, 0x64, 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d,
- 0x00, 0x93, 0x00, 0x98, 0x00, 0xb2, 0x00, 0xa6, 0x00, 0x85, 0x00, 0x57,
- 0x00, 0x28, 0x00, 0x01, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x52, 0x00, 0x64,
- 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d, 0x00, 0x93, 0x00, 0x98,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00,
- 0x23, 0x00, 0x0e, 0x02, 0x06, 0x12, 0x00, 0x20, 0x00, 0x3c, 0x00, 0x52,
- 0x00, 0x64, 0x00, 0x73, 0x00, 0x7e, 0x00, 0x87, 0x00, 0x8f, 0x00, 0x95,
- 0x00, 0x9a, 0x00, 0x9e, 0x3a, 0x00, 0x31, 0x00, 0x19, 0x00, 0x00, 0x05,
- 0x00, 0x24, 0x00, 0x3f, 0x00, 0x56, 0x00, 0x68, 0x00, 0x77, 0x00, 0x82,
- 0x00, 0x8b, 0x00, 0x93, 0x00, 0x99, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5,
- 0x23, 0x74, 0x09, 0x91, 0x02, 0xa3, 0x00, 0xaf, 0x00, 0xb7, 0x00, 0xbd,
- 0x00, 0xc2, 0x00, 0xc5, 0x00, 0xc7, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc,
- 0x00, 0xce, 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd2,
- 0x00, 0xd2, 0x00, 0xd3, 0x0d, 0x6b, 0x01, 0x8e, 0x00, 0xa4, 0x00, 0xb0,
- 0x00, 0xb9, 0x00, 0xbe, 0x00, 0xc2, 0x00, 0xc5, 0x00, 0xc8, 0x00, 0xca,
- 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1,
- 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x06, 0xa4, 0x00, 0xb5, 0x00, 0xc0, 0x00, 0xc6, 0x00, 0xcb, 0x00, 0xcd,
- 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd4,
- 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xd7,
- 0x00, 0xd8, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48,
- 0x00, 0x59, 0x00, 0x66, 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89,
- 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70, 0x00, 0x48, 0x00, 0x21,
- 0x00, 0x01, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48, 0x00, 0x59, 0x00, 0x66,
- 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x18, 0x00,
- 0x0c, 0x07, 0x05, 0x14, 0x00, 0x20, 0x00, 0x37, 0x00, 0x4c, 0x00, 0x5c,
- 0x00, 0x6a, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x86, 0x00, 0x8d, 0x00, 0x92,
- 0x3c, 0x00, 0x35, 0x00, 0x23, 0x00, 0x0b, 0x00, 0x00, 0x0f, 0x00, 0x29,
- 0x00, 0x3f, 0x00, 0x53, 0x00, 0x63, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x84,
- 0x00, 0x8b, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9b, 0x2a, 0x61, 0x11, 0x78,
- 0x07, 0x8a, 0x03, 0x98, 0x01, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb6,
- 0x00, 0xba, 0x00, 0xbd, 0x00, 0xc0, 0x00, 0xc2, 0x00, 0xc5, 0x00, 0xc6,
- 0x00, 0xc7, 0x00, 0xc9, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc,
- 0x12, 0x51, 0x04, 0x73, 0x00, 0x89, 0x00, 0x9a, 0x00, 0xa4, 0x00, 0xad,
- 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbb, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc3,
- 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb,
- 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x09, 0x97, 0x02, 0xa8,
- 0x00, 0xb3, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc5, 0x00, 0xc7, 0x00, 0xca,
- 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd1,
- 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd5,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50,
- 0x00, 0x5d, 0x00, 0x68, 0x00, 0x72, 0x00, 0x7a, 0x00, 0xbb, 0x00, 0xb3,
- 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d, 0x00, 0x1c, 0x00, 0x00,
- 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50, 0x00, 0x5d, 0x00, 0x68,
- 0x00, 0x72, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x20, 0x00, 0x10, 0x00, 0x0a, 0x0b,
- 0x04, 0x16, 0x00, 0x20, 0x00, 0x34, 0x00, 0x46, 0x00, 0x56, 0x00, 0x62,
- 0x00, 0x6d, 0x00, 0x77, 0x00, 0x7f, 0x00, 0x85, 0x3d, 0x00, 0x38, 0x00,
- 0x2a, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x2c, 0x00, 0x3f,
- 0x00, 0x50, 0x00, 0x5e, 0x00, 0x6b, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x85,
- 0x00, 0x8b, 0x00, 0x91, 0x2e, 0x59, 0x17, 0x6b, 0x0c, 0x7a, 0x06, 0x87,
- 0x03, 0x92, 0x01, 0x9b, 0x00, 0xa2, 0x00, 0xa8, 0x00, 0xad, 0x00, 0xb1,
- 0x00, 0xb5, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc1,
- 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc6, 0x00, 0xc7, 0x15, 0x45, 0x08, 0x60,
- 0x02, 0x77, 0x00, 0x87, 0x00, 0x94, 0x00, 0x9d, 0x00, 0xa4, 0x00, 0xaa,
- 0x00, 0xaf, 0x00, 0xb3, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbc, 0x00, 0xbe,
- 0x00, 0xc0, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc6, 0x00, 0xc7,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x0a, 0x91, 0x04, 0x9e, 0x01, 0xaa, 0x00, 0xb2,
- 0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc6, 0x00, 0xc8,
- 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf,
- 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x16, 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55,
- 0x00, 0x60, 0x00, 0x6a, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xa6, 0x00, 0x8e,
- 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19, 0x00, 0x00, 0x00, 0x16,
- 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55, 0x00, 0x60, 0x00, 0x6a,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3b, 0x00,
- 0x33, 0x00, 0x27, 0x00, 0x18, 0x00, 0x0d, 0x04, 0x08, 0x0e, 0x04, 0x17,
- 0x00, 0x20, 0x00, 0x32, 0x00, 0x42, 0x00, 0x50, 0x00, 0x5c, 0x00, 0x67,
- 0x00, 0x70, 0x00, 0x78, 0x3d, 0x00, 0x39, 0x00, 0x2f, 0x00, 0x1f, 0x00,
- 0x0b, 0x00, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x2e, 0x00, 0x3f, 0x00, 0x4e,
- 0x00, 0x5b, 0x00, 0x66, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x86,
- 0x31, 0x53, 0x1c, 0x62, 0x11, 0x70, 0x0a, 0x7b, 0x06, 0x85, 0x03, 0x8e,
- 0x02, 0x96, 0x00, 0x9c, 0x00, 0xa2, 0x00, 0xa7, 0x00, 0xab, 0x00, 0xae,
- 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbd,
- 0x00, 0xbe, 0x00, 0xbf, 0x17, 0x3d, 0x0b, 0x55, 0x04, 0x67, 0x01, 0x78,
- 0x00, 0x85, 0x00, 0x90, 0x00, 0x98, 0x00, 0x9f, 0x00, 0xa5, 0x00, 0xaa,
- 0x00, 0xad, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb9, 0x00, 0xbb,
- 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x0b, 0x8d, 0x05, 0x99, 0x02, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb6,
- 0x00, 0xba, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc3, 0x00, 0xc5, 0x00, 0xc7,
- 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcd,
- 0x00, 0xce, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x13, 0x00, 0x25, 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59,
- 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97, 0x00, 0x7e, 0x00, 0x64,
- 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x25,
- 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00,
- 0x1f, 0x00, 0x12, 0x00, 0x0c, 0x07, 0x07, 0x10, 0x03, 0x18, 0x00, 0x20,
- 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4c, 0x00, 0x57, 0x00, 0x61, 0x00, 0x6a,
- 0x3e, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x25, 0x00, 0x14, 0x00, 0x02, 0x00,
- 0x00, 0x0f, 0x00, 0x20, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4d, 0x00, 0x58,
- 0x00, 0x63, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x7b, 0x33, 0x50, 0x20, 0x5c,
- 0x15, 0x68, 0x0e, 0x72, 0x09, 0x7c, 0x05, 0x84, 0x03, 0x8c, 0x02, 0x92,
- 0x01, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xad,
- 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xba,
- 0x18, 0x38, 0x0d, 0x4c, 0x06, 0x5e, 0x03, 0x6c, 0x01, 0x7a, 0x00, 0x84,
- 0x00, 0x8d, 0x00, 0x95, 0x00, 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8,
- 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8,
- 0x00, 0xba, 0x00, 0xbc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0c, 0x8a, 0x06, 0x94,
- 0x03, 0x9d, 0x01, 0xa4, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb5, 0x00, 0xb9,
- 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xc6,
- 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
- 0x00, 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x49, 0x00, 0xbd, 0x00, 0xb9,
- 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71, 0x00, 0x59, 0x00, 0x41,
- 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x22, 0x00, 0x30,
- 0x00, 0x3d, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x19, 0x00,
- 0x0e, 0x02, 0x0a, 0x0a, 0x06, 0x11, 0x03, 0x19, 0x00, 0x1f, 0x00, 0x2e,
- 0x00, 0x3c, 0x00, 0x48, 0x00, 0x53, 0x00, 0x5c, 0x3e, 0x00, 0x3c, 0x00,
- 0x34, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0c, 0x00, 0x00, 0x04, 0x00, 0x14,
- 0x00, 0x23, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x56, 0x00, 0x60,
- 0x00, 0x68, 0x00, 0x70, 0x34, 0x4e, 0x23, 0x58, 0x18, 0x62, 0x10, 0x6c,
- 0x0b, 0x75, 0x08, 0x7c, 0x05, 0x83, 0x03, 0x8a, 0x02, 0x8f, 0x01, 0x95,
- 0x00, 0x9a, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa9, 0x00, 0xac,
- 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb5, 0x1a, 0x35, 0x0f, 0x47,
- 0x08, 0x55, 0x04, 0x64, 0x02, 0x70, 0x00, 0x7a, 0x00, 0x83, 0x00, 0x8b,
- 0x00, 0x92, 0x00, 0x98, 0x00, 0x9d, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8,
- 0x00, 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0xb7,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x0d, 0x89, 0x07, 0x92, 0x04, 0x99, 0x02, 0xa0,
- 0x01, 0xa6, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb4, 0x00, 0xb7, 0x00, 0xba,
- 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xc5,
- 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xca, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
- 0x00, 0x2d, 0x00, 0x39, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa3,
- 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50, 0x00, 0x3a, 0x00, 0x25,
- 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x39,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00,
- 0x38, 0x00, 0x31, 0x00, 0x28, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x0d, 0x05,
- 0x09, 0x0c, 0x06, 0x13, 0x03, 0x19, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x3a,
- 0x00, 0x45, 0x00, 0x4f, 0x3e, 0x00, 0x3c, 0x00, 0x36, 0x00, 0x2d, 0x00,
- 0x21, 0x00, 0x13, 0x00, 0x04, 0x00, 0x00, 0x0a, 0x00, 0x18, 0x00, 0x26,
- 0x00, 0x33, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x65,
- 0x35, 0x4c, 0x26, 0x55, 0x1b, 0x5e, 0x13, 0x67, 0x0e, 0x6f, 0x0a, 0x76,
- 0x07, 0x7d, 0x05, 0x82, 0x03, 0x88, 0x02, 0x8e, 0x02, 0x92, 0x01, 0x97,
- 0x00, 0x9b, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab,
- 0x00, 0xac, 0x00, 0xaf, 0x1b, 0x33, 0x10, 0x42, 0x0a, 0x50, 0x05, 0x5c,
- 0x03, 0x68, 0x01, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x8a, 0x00, 0x90,
- 0x00, 0x96, 0x00, 0x99, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa8,
- 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x0d, 0x88, 0x08, 0x8f, 0x05, 0x96, 0x02, 0x9c, 0x01, 0xa2, 0x00, 0xa7,
- 0x00, 0xac, 0x00, 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb9, 0x00, 0xbb,
- 0x00, 0xbd, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc5,
- 0x00, 0xc6, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29,
- 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7, 0x00, 0x98, 0x00, 0x85,
- 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35, 0x00, 0x22, 0x00, 0x10,
- 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x33, 0x00,
- 0x2c, 0x00, 0x23, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x0c, 0x07, 0x08, 0x0e,
- 0x05, 0x14, 0x02, 0x1a, 0x00, 0x1f, 0x00, 0x2c, 0x00, 0x38, 0x00, 0x42,
- 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x30, 0x00, 0x25, 0x00, 0x19, 0x00,
- 0x0c, 0x00, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x34,
- 0x00, 0x3f, 0x00, 0x49, 0x00, 0x53, 0x00, 0x5b, 0x36, 0x4a, 0x28, 0x52,
- 0x1d, 0x5b, 0x16, 0x63, 0x10, 0x6a, 0x0c, 0x71, 0x09, 0x77, 0x07, 0x7d,
- 0x05, 0x82, 0x03, 0x87, 0x02, 0x8c, 0x02, 0x90, 0x01, 0x94, 0x00, 0x99,
- 0x00, 0x9c, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa4, 0x00, 0xa7, 0x00, 0xaa,
- 0x1b, 0x30, 0x12, 0x3e, 0x0c, 0x4b, 0x07, 0x57, 0x04, 0x61, 0x02, 0x6b,
- 0x01, 0x73, 0x00, 0x7c, 0x00, 0x82, 0x00, 0x88, 0x00, 0x8f, 0x00, 0x93,
- 0x00, 0x97, 0x00, 0x9c, 0x00, 0x9f, 0x00, 0xa2, 0x00, 0xa5, 0x00, 0xa8,
- 0x00, 0xaa, 0x00, 0xac, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0d, 0x86, 0x09, 0x8d,
- 0x06, 0x94, 0x03, 0x9a, 0x02, 0x9f, 0x01, 0xa4, 0x00, 0xa8, 0x00, 0xac,
- 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbc,
- 0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0xbe, 0x00, 0xbb,
- 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d, 0x00, 0x7b, 0x00, 0x68,
- 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
- 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x26, 0x00,
- 0x1d, 0x00, 0x14, 0x00, 0x0e, 0x03, 0x0b, 0x09, 0x08, 0x0f, 0x05, 0x15,
- 0x02, 0x1a, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x3f, 0x00, 0x3d, 0x00,
- 0x39, 0x00, 0x32, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x06, 0x00,
- 0x00, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x3f,
- 0x00, 0x49, 0x00, 0x51, 0x37, 0x49, 0x2a, 0x51, 0x20, 0x58, 0x18, 0x5f,
- 0x13, 0x66, 0x0f, 0x6c, 0x0b, 0x73, 0x09, 0x78, 0x07, 0x7e, 0x05, 0x82,
- 0x03, 0x86, 0x02, 0x8b, 0x02, 0x8f, 0x01, 0x92, 0x01, 0x96, 0x00, 0x9a,
- 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa4, 0x1c, 0x2f, 0x13, 0x3b,
- 0x0d, 0x47, 0x09, 0x51, 0x05, 0x5c, 0x04, 0x65, 0x02, 0x6e, 0x01, 0x75,
- 0x00, 0x7c, 0x00, 0x82, 0x00, 0x88, 0x00, 0x8d, 0x00, 0x91, 0x00, 0x96,
- 0x00, 0x99, 0x00, 0x9c, 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa5, 0x00, 0xa7,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x0e, 0x86, 0x09, 0x8c, 0x06, 0x92, 0x04, 0x97,
- 0x02, 0x9c, 0x02, 0xa1, 0x01, 0xa5, 0x00, 0xa9, 0x00, 0xac, 0x00, 0xaf,
- 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc,
- 0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x0d, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xad,
- 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72, 0x00, 0x60, 0x00, 0x4f,
- 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
- 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00,
- 0x10, 0x00, 0x0d, 0x05, 0x0a, 0x0b, 0x07, 0x10, 0x04, 0x16, 0x02, 0x1b,
- 0x00, 0x1f, 0x00, 0x2a, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x33, 0x00,
- 0x2b, 0x00, 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0b,
- 0x00, 0x16, 0x00, 0x21, 0x00, 0x2c, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48,
- 0x38, 0x48, 0x2b, 0x4f, 0x22, 0x56, 0x1a, 0x5c, 0x15, 0x63, 0x11, 0x69,
- 0x0d, 0x6e, 0x0a, 0x74, 0x08, 0x78, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x85,
- 0x03, 0x8a, 0x02, 0x8e, 0x02, 0x90, 0x01, 0x93, 0x00, 0x98, 0x00, 0x9b,
- 0x00, 0x9d, 0x00, 0x9f, 0x1c, 0x2d, 0x14, 0x39, 0x0e, 0x44, 0x0a, 0x4e,
- 0x07, 0x57, 0x04, 0x60, 0x02, 0x67, 0x01, 0x6f, 0x00, 0x76, 0x00, 0x7d,
- 0x00, 0x81, 0x00, 0x87, 0x00, 0x8c, 0x00, 0x90, 0x00, 0x94, 0x00, 0x97,
- 0x00, 0x9a, 0x00, 0x9d, 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x0e, 0x85, 0x0a, 0x8b, 0x07, 0x90, 0x05, 0x95, 0x03, 0x9a, 0x02, 0x9e,
- 0x01, 0xa2, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb2,
- 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbd,
- 0x00, 0xbe, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x98,
- 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59, 0x00, 0x49, 0x00, 0x39,
- 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00,
- 0x32, 0x00, 0x2c, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0e, 0x01,
- 0x0c, 0x07, 0x09, 0x0c, 0x06, 0x11, 0x04, 0x16, 0x02, 0x1b, 0x00, 0x1f,
- 0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x25, 0x00,
- 0x1c, 0x00, 0x11, 0x00, 0x07, 0x00, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x19,
- 0x00, 0x23, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x3f, 0x38, 0x48, 0x2d, 0x4e,
- 0x23, 0x54, 0x1c, 0x5a, 0x17, 0x5f, 0x12, 0x66, 0x0f, 0x6a, 0x0c, 0x71,
- 0x0a, 0x74, 0x08, 0x79, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84, 0x03, 0x89,
- 0x02, 0x8d, 0x02, 0x8f, 0x01, 0x92, 0x01, 0x95, 0x00, 0x99, 0x00, 0x9b,
- 0x1c, 0x2d, 0x15, 0x37, 0x0f, 0x41, 0x0b, 0x4a, 0x07, 0x53, 0x05, 0x5b,
- 0x04, 0x63, 0x02, 0x69, 0x01, 0x70, 0x00, 0x77, 0x00, 0x7d, 0x00, 0x81,
- 0x00, 0x87, 0x00, 0x8a, 0x00, 0x8f, 0x00, 0x92, 0x00, 0x96, 0x00, 0x99,
- 0x00, 0x9b, 0x00, 0x9e, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0e, 0x85, 0x0a, 0x8a,
- 0x07, 0x8f, 0x05, 0x93, 0x03, 0x98, 0x02, 0x9c, 0x02, 0xa0, 0x01, 0xa3,
- 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb3,
- 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x39, 0x47, 0x2e, 0x4d, 0x25, 0x53, 0x1e, 0x58,
- 0x19, 0x5e, 0x14, 0x63, 0x11, 0x68, 0x0e, 0x6c, 0x0b, 0x72, 0x09, 0x75,
- 0x07, 0x79, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84, 0x03, 0x88, 0x02, 0x8c,
- 0x02, 0x8e, 0x01, 0x91, 0x01, 0x93, 0x00, 0x97, 0x1d, 0x2c, 0x16, 0x36,
- 0x10, 0x3e, 0x0c, 0x48, 0x09, 0x50, 0x06, 0x58, 0x04, 0x5f, 0x02, 0x66,
- 0x02, 0x6c, 0x01, 0x71, 0x00, 0x77, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x86,
- 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x91, 0x00, 0x94, 0x00, 0x97, 0x00, 0x9a,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x0e, 0x84, 0x0b, 0x89, 0x08, 0x8d, 0x06, 0x92,
- 0x04, 0x96, 0x03, 0x9a, 0x02, 0x9e, 0x01, 0xa1, 0x01, 0xa4, 0x00, 0xa7,
- 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5,
- 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x39, 0x46, 0x2f, 0x4c, 0x26, 0x51, 0x20, 0x56, 0x1a, 0x5c, 0x16, 0x60,
- 0x12, 0x66, 0x0f, 0x69, 0x0c, 0x6e, 0x0b, 0x73, 0x09, 0x76, 0x07, 0x7a,
- 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84, 0x03, 0x88, 0x02, 0x8b, 0x02, 0x8e,
- 0x02, 0x90, 0x01, 0x92, 0x1d, 0x2b, 0x16, 0x34, 0x11, 0x3d, 0x0c, 0x45,
- 0x0a, 0x4c, 0x07, 0x54, 0x05, 0x5b, 0x04, 0x61, 0x02, 0x67, 0x01, 0x6d,
- 0x01, 0x73, 0x00, 0x78, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x86, 0x00, 0x89,
- 0x00, 0x8d, 0x00, 0x90, 0x00, 0x93, 0x00, 0x95, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x0e, 0x84, 0x0b, 0x88, 0x08, 0x8d, 0x06, 0x91, 0x05, 0x94, 0x03, 0x98,
- 0x02, 0x9c, 0x02, 0x9f, 0x01, 0xa2, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xaa,
- 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb6,
- 0x00, 0xb8, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x46, 0x30, 0x4b,
- 0x28, 0x50, 0x21, 0x55, 0x1c, 0x59, 0x17, 0x5e, 0x14, 0x63, 0x10, 0x68,
- 0x0e, 0x6b, 0x0c, 0x70, 0x0a, 0x74, 0x08, 0x76, 0x07, 0x7b, 0x06, 0x7e,
- 0x05, 0x81, 0x04, 0x83, 0x03, 0x87, 0x02, 0x8a, 0x02, 0x8d, 0x02, 0x8f,
- 0x1e, 0x2a, 0x17, 0x33, 0x12, 0x3b, 0x0e, 0x43, 0x0a, 0x4a, 0x07, 0x51,
- 0x05, 0x58, 0x04, 0x5e, 0x03, 0x64, 0x02, 0x69, 0x01, 0x6f, 0x00, 0x74,
- 0x00, 0x78, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x85, 0x00, 0x89, 0x00, 0x8b,
- 0x00, 0x8f, 0x00, 0x93, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x83, 0x0b, 0x88,
- 0x09, 0x8c, 0x07, 0x90, 0x05, 0x93, 0x03, 0x97, 0x02, 0x9a, 0x02, 0x9d,
- 0x01, 0xa0, 0x01, 0xa3, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xad,
- 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x31, 0x4a, 0x29, 0x4e, 0x22, 0x54,
- 0x1d, 0x57, 0x19, 0x5d, 0x15, 0x60, 0x12, 0x65, 0x0f, 0x69, 0x0d, 0x6c,
- 0x0b, 0x71, 0x09, 0x74, 0x08, 0x77, 0x07, 0x7b, 0x06, 0x7f, 0x05, 0x81,
- 0x04, 0x83, 0x03, 0x86, 0x02, 0x8a, 0x02, 0x8c, 0x1e, 0x2a, 0x18, 0x32,
- 0x12, 0x39, 0x0f, 0x40, 0x0c, 0x48, 0x09, 0x4f, 0x07, 0x55, 0x05, 0x5a,
- 0x04, 0x60, 0x02, 0x66, 0x02, 0x6b, 0x01, 0x70, 0x00, 0x75, 0x00, 0x79,
- 0x00, 0x7d, 0x00, 0x81, 0x00, 0x84, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x83, 0x0c, 0x87, 0x09, 0x8b, 0x07, 0x8e,
- 0x06, 0x92, 0x04, 0x96, 0x03, 0x99, 0x02, 0x9b, 0x02, 0x9e, 0x01, 0xa1,
- 0x01, 0xa4, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf,
- 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0xb5, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3a, 0x45, 0x31, 0x49, 0x2a, 0x4d, 0x24, 0x52, 0x1f, 0x56, 0x1a, 0x5b,
- 0x16, 0x5f, 0x13, 0x63, 0x10, 0x67, 0x0e, 0x6a, 0x0c, 0x6e, 0x0b, 0x72,
- 0x09, 0x75, 0x07, 0x77, 0x07, 0x7b, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83,
- 0x03, 0x85, 0x02, 0x89, 0x1e, 0x29, 0x18, 0x31, 0x13, 0x38, 0x0f, 0x3f,
- 0x0c, 0x45, 0x0a, 0x4c, 0x07, 0x52, 0x05, 0x58, 0x04, 0x5d, 0x04, 0x63,
- 0x02, 0x67, 0x01, 0x6c, 0x01, 0x71, 0x00, 0x75, 0x00, 0x79, 0x00, 0x7d,
- 0x00, 0x81, 0x00, 0x84, 0x00, 0x88, 0x00, 0x8b, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x0f, 0x83, 0x0c, 0x87, 0x09, 0x8a, 0x07, 0x8e, 0x06, 0x91, 0x05, 0x94,
- 0x03, 0x97, 0x02, 0x9a, 0x02, 0x9d, 0x02, 0xa0, 0x01, 0xa2, 0x00, 0xa4,
- 0x00, 0xa7, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0,
- 0x00, 0xb2, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x45, 0x32, 0x48,
- 0x2b, 0x4d, 0x25, 0x51, 0x20, 0x55, 0x1b, 0x59, 0x18, 0x5e, 0x14, 0x60,
- 0x12, 0x65, 0x0f, 0x68, 0x0d, 0x6b, 0x0c, 0x6f, 0x0a, 0x73, 0x09, 0x75,
- 0x07, 0x77, 0x06, 0x7b, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85,
- 0x1e, 0x29, 0x19, 0x30, 0x14, 0x37, 0x0f, 0x3d, 0x0c, 0x44, 0x0a, 0x4a,
- 0x07, 0x50, 0x06, 0x55, 0x05, 0x5b, 0x04, 0x60, 0x02, 0x64, 0x02, 0x69,
- 0x01, 0x6d, 0x01, 0x72, 0x00, 0x76, 0x00, 0x7a, 0x00, 0x7d, 0x00, 0x81,
- 0x00, 0x83, 0x00, 0x87, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x83, 0x0c, 0x86,
- 0x0a, 0x8a, 0x07, 0x8d, 0x06, 0x90, 0x05, 0x93, 0x03, 0x96, 0x03, 0x99,
- 0x02, 0x9c, 0x02, 0x9e, 0x01, 0xa0, 0x01, 0xa3, 0x00, 0xa5, 0x00, 0xa7,
- 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb2,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3b, 0x45, 0x33, 0x48, 0x2c, 0x4d, 0x26, 0x4f,
- 0x21, 0x55, 0x1c, 0x57, 0x19, 0x5c, 0x16, 0x5f, 0x13, 0x63, 0x10, 0x67,
- 0x0e, 0x6a, 0x0c, 0x6c, 0x0b, 0x71, 0x0a, 0x73, 0x09, 0x76, 0x07, 0x78,
- 0x06, 0x7c, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x1e, 0x28, 0x19, 0x2f,
- 0x15, 0x35, 0x10, 0x3c, 0x0d, 0x42, 0x0b, 0x48, 0x09, 0x4e, 0x07, 0x53,
- 0x05, 0x58, 0x04, 0x5d, 0x04, 0x62, 0x02, 0x66, 0x02, 0x6b, 0x01, 0x6f,
- 0x00, 0x73, 0x00, 0x76, 0x00, 0x7a, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x83,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x82, 0x0c, 0x86, 0x0a, 0x89, 0x08, 0x8c,
- 0x06, 0x8f, 0x05, 0x92, 0x04, 0x95, 0x03, 0x98, 0x02, 0x9a, 0x02, 0x9d,
- 0x02, 0x9f, 0x01, 0xa1, 0x01, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xa9,
- 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3b, 0x44, 0x33, 0x47, 0x2c, 0x4c, 0x27, 0x4f, 0x22, 0x54, 0x1e, 0x56,
- 0x1a, 0x5a, 0x17, 0x5e, 0x14, 0x60, 0x12, 0x65, 0x10, 0x68, 0x0e, 0x6a,
- 0x0c, 0x6e, 0x0b, 0x72, 0x09, 0x74, 0x08, 0x76, 0x07, 0x78, 0x06, 0x7c,
- 0x06, 0x7f, 0x05, 0x81, 0x1e, 0x28, 0x19, 0x2f, 0x16, 0x35, 0x12, 0x3b,
- 0x0f, 0x41, 0x0c, 0x46, 0x0a, 0x4c, 0x07, 0x51, 0x05, 0x55, 0x05, 0x5b,
- 0x04, 0x5f, 0x02, 0x63, 0x02, 0x68, 0x01, 0x6b, 0x01, 0x70, 0x00, 0x73,
- 0x00, 0x77, 0x00, 0x7b, 0x00, 0x7d, 0x00, 0x81, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x0f, 0x82, 0x0c, 0x86, 0x0b, 0x89, 0x09, 0x8c, 0x07, 0x8f, 0x06, 0x91,
- 0x05, 0x94, 0x03, 0x97, 0x02, 0x99, 0x02, 0x9c, 0x02, 0x9e, 0x01, 0xa0,
- 0x01, 0xa2, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xac,
- 0x00, 0xad, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x23, 0x25, 0x22,
- 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x00, 0x44, 0x05, 0x25, 0x0d, 0x23, 0x12, 0x22,
- 0x15, 0x22, 0x17, 0x22, 0x18, 0x22, 0x1a, 0x22, 0x1b, 0x22, 0x1b, 0x22,
- 0x1c, 0x22, 0x1c, 0x22, 0x1c, 0x22, 0x1d, 0x22, 0x1d, 0x22, 0x1e, 0x22,
- 0x1e, 0x22, 0x1e, 0x22, 0x1e, 0x22, 0x1e, 0x22, 0x10, 0x33, 0x13, 0x23,
- 0x17, 0x22, 0x1a, 0x22, 0x1b, 0x22, 0x1c, 0x22, 0x1d, 0x22, 0x1e, 0x22,
- 0x1e, 0x22, 0x1e, 0x22, 0x1f, 0x22, 0x1f, 0x22, 0x1f, 0x22, 0x1f, 0x22,
- 0x1f, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x35, 0x25, 0x2b, 0x23, 0x27, 0x22, 0x25, 0x22,
- 0x24, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x00, 0x9d, 0x00, 0x6b, 0x01, 0x51, 0x04, 0x45, 0x08, 0x3d, 0x0b, 0x38,
- 0x0d, 0x35, 0x0f, 0x33, 0x10, 0x30, 0x12, 0x2f, 0x13, 0x2d, 0x14, 0x2d,
- 0x15, 0x2c, 0x16, 0x2b, 0x16, 0x2a, 0x17, 0x2a, 0x18, 0x29, 0x18, 0x29,
- 0x19, 0x28, 0x19, 0x28, 0x10, 0x5f, 0x10, 0x46, 0x11, 0x39, 0x13, 0x33,
- 0x15, 0x2f, 0x16, 0x2d, 0x17, 0x2b, 0x18, 0x2a, 0x19, 0x29, 0x1a, 0x28,
- 0x1a, 0x27, 0x1b, 0x27, 0x1b, 0x27, 0x1c, 0x26, 0x1c, 0x26, 0x1c, 0x26,
- 0x1d, 0x25, 0x1d, 0x25, 0x1d, 0x25, 0x1d, 0x25, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x38, 0x2a, 0x2e, 0x26, 0x2a, 0x25, 0x27, 0x24, 0x26, 0x23, 0x25, 0x23,
- 0x24, 0x23, 0x24, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
- 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xbc, 0x00, 0x8e,
- 0x00, 0x73, 0x00, 0x60, 0x02, 0x55, 0x04, 0x4c, 0x06, 0x47, 0x08, 0x42,
- 0x0a, 0x3e, 0x0c, 0x3b, 0x0d, 0x39, 0x0e, 0x37, 0x0f, 0x36, 0x10, 0x34,
- 0x11, 0x33, 0x12, 0x32, 0x12, 0x31, 0x13, 0x30, 0x14, 0x2f, 0x15, 0x2f,
- 0x10, 0x6f, 0x10, 0x58, 0x10, 0x4a, 0x11, 0x41, 0x12, 0x3b, 0x13, 0x37,
- 0x14, 0x34, 0x15, 0x32, 0x16, 0x30, 0x17, 0x2e, 0x17, 0x2d, 0x18, 0x2c,
- 0x18, 0x2c, 0x19, 0x2b, 0x19, 0x2a, 0x1a, 0x2a, 0x1a, 0x29, 0x1a, 0x29,
- 0x1b, 0x28, 0x1b, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x2e, 0x31, 0x29,
- 0x2c, 0x27, 0x2a, 0x26, 0x28, 0x25, 0x27, 0x24, 0x25, 0x24, 0x25, 0x23,
- 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x23, 0x22, 0x23, 0x22,
- 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x00, 0xc6, 0x00, 0xa4, 0x00, 0x89, 0x00, 0x77,
- 0x00, 0x67, 0x01, 0x5e, 0x03, 0x55, 0x04, 0x50, 0x05, 0x4b, 0x07, 0x47,
- 0x09, 0x44, 0x0a, 0x41, 0x0b, 0x3e, 0x0c, 0x3d, 0x0c, 0x3b, 0x0e, 0x39,
- 0x0f, 0x38, 0x0f, 0x37, 0x0f, 0x35, 0x10, 0x35, 0x10, 0x74, 0x10, 0x63,
- 0x10, 0x55, 0x10, 0x4c, 0x11, 0x44, 0x11, 0x40, 0x12, 0x3b, 0x13, 0x39,
- 0x13, 0x36, 0x14, 0x34, 0x15, 0x33, 0x16, 0x31, 0x16, 0x30, 0x17, 0x2f,
- 0x17, 0x2e, 0x18, 0x2d, 0x18, 0x2d, 0x18, 0x2c, 0x18, 0x2b, 0x19, 0x2b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3a, 0x31, 0x33, 0x2c, 0x2f, 0x29, 0x2b, 0x28,
- 0x29, 0x26, 0x28, 0x25, 0x27, 0x25, 0x26, 0x24, 0x25, 0x24, 0x25, 0x24,
- 0x25, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x23, 0x23,
- 0x23, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x00, 0xcd, 0x00, 0xb0, 0x00, 0x9a, 0x00, 0x87, 0x00, 0x78, 0x00, 0x6c,
- 0x01, 0x64, 0x02, 0x5c, 0x03, 0x57, 0x04, 0x51, 0x05, 0x4e, 0x07, 0x4a,
- 0x07, 0x48, 0x09, 0x45, 0x0a, 0x43, 0x0a, 0x40, 0x0c, 0x3f, 0x0c, 0x3d,
- 0x0c, 0x3c, 0x0d, 0x3b, 0x10, 0x77, 0x10, 0x69, 0x10, 0x5e, 0x10, 0x54,
- 0x10, 0x4d, 0x11, 0x47, 0x11, 0x43, 0x12, 0x3f, 0x12, 0x3c, 0x13, 0x39,
- 0x13, 0x38, 0x14, 0x36, 0x14, 0x35, 0x15, 0x33, 0x16, 0x32, 0x16, 0x31,
- 0x17, 0x30, 0x17, 0x2f, 0x17, 0x2f, 0x17, 0x2e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3b, 0x33, 0x34, 0x2e, 0x30, 0x2b, 0x2d, 0x29, 0x2b, 0x28, 0x29, 0x27,
- 0x29, 0x26, 0x27, 0x25, 0x27, 0x25, 0x26, 0x24, 0x25, 0x24, 0x25, 0x24,
- 0x25, 0x24, 0x24, 0x24, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23,
- 0x23, 0x23, 0x23, 0x23, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xcf, 0x00, 0xb9,
- 0x00, 0xa4, 0x00, 0x94, 0x00, 0x85, 0x00, 0x7a, 0x00, 0x70, 0x00, 0x68,
- 0x01, 0x61, 0x02, 0x5c, 0x04, 0x57, 0x04, 0x53, 0x05, 0x50, 0x06, 0x4c,
- 0x07, 0x4a, 0x07, 0x48, 0x09, 0x45, 0x0a, 0x44, 0x0a, 0x42, 0x0b, 0x41,
- 0x10, 0x78, 0x10, 0x6d, 0x10, 0x63, 0x10, 0x5b, 0x10, 0x53, 0x10, 0x4e,
- 0x11, 0x49, 0x11, 0x45, 0x11, 0x41, 0x12, 0x3f, 0x13, 0x3c, 0x13, 0x3a,
- 0x13, 0x39, 0x14, 0x37, 0x14, 0x36, 0x14, 0x35, 0x15, 0x33, 0x16, 0x33,
- 0x16, 0x32, 0x16, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x34, 0x36, 0x30,
- 0x32, 0x2d, 0x2f, 0x2b, 0x2d, 0x29, 0x2b, 0x28, 0x29, 0x27, 0x28, 0x27,
- 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24,
- 0x25, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x00, 0xd2, 0x00, 0xbe, 0x00, 0xad, 0x00, 0x9d,
- 0x00, 0x90, 0x00, 0x84, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x6b, 0x01, 0x65,
- 0x02, 0x60, 0x02, 0x5b, 0x04, 0x58, 0x04, 0x54, 0x05, 0x51, 0x05, 0x4f,
- 0x07, 0x4c, 0x07, 0x4a, 0x07, 0x48, 0x09, 0x46, 0x10, 0x7a, 0x10, 0x70,
- 0x10, 0x67, 0x10, 0x5f, 0x10, 0x59, 0x10, 0x53, 0x10, 0x4e, 0x11, 0x4a,
- 0x11, 0x46, 0x11, 0x43, 0x12, 0x41, 0x12, 0x3e, 0x13, 0x3d, 0x13, 0x3b,
- 0x13, 0x39, 0x13, 0x38, 0x14, 0x37, 0x14, 0x36, 0x14, 0x35, 0x15, 0x34,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3c, 0x35, 0x37, 0x31, 0x33, 0x2e, 0x30, 0x2c,
- 0x2d, 0x2a, 0x2c, 0x29, 0x2b, 0x28, 0x29, 0x27, 0x28, 0x27, 0x28, 0x27,
- 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24,
- 0x25, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x00, 0xd3, 0x00, 0xc2, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x98, 0x00, 0x8d,
- 0x00, 0x83, 0x00, 0x7b, 0x00, 0x73, 0x00, 0x6e, 0x01, 0x67, 0x01, 0x63,
- 0x02, 0x5f, 0x02, 0x5b, 0x04, 0x58, 0x04, 0x55, 0x05, 0x52, 0x05, 0x50,
- 0x06, 0x4e, 0x07, 0x4c, 0x10, 0x7a, 0x10, 0x72, 0x10, 0x6a, 0x10, 0x63,
- 0x10, 0x5d, 0x10, 0x57, 0x10, 0x52, 0x10, 0x4e, 0x11, 0x4a, 0x11, 0x48,
- 0x11, 0x44, 0x11, 0x42, 0x12, 0x40, 0x12, 0x3e, 0x13, 0x3d, 0x13, 0x3b,
- 0x13, 0x3a, 0x13, 0x39, 0x14, 0x38, 0x14, 0x37, 0x0f, 0x00, 0x1f, 0x00,
- 0x33, 0x00, 0x39, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00,
- 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00,
- 0x3f, 0x00, 0x3f, 0x00, 0x0b, 0x3b, 0x17, 0x07, 0x2c, 0x00, 0x36, 0x00,
- 0x3a, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00,
- 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x3d, 0x00,
- 0x4c, 0x00, 0x4c, 0x00, 0x48, 0x00, 0x42, 0x00, 0x3e, 0x00, 0x3e, 0x00,
- 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00,
- 0x3f, 0x00, 0x3f, 0x00, 0x07, 0x47, 0x0f, 0x0f, 0x26, 0x00, 0x33, 0x00,
- 0x38, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00,
- 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00,
- 0x3c, 0x37, 0x37, 0x32, 0x34, 0x30, 0x31, 0x2d, 0x2f, 0x2c, 0x2d, 0x2b,
- 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x27, 0x28, 0x27, 0x28, 0x27, 0x27, 0x26,
- 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24,
- 0x25, 0x24, 0x24, 0x24, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd5, 0x00, 0xc5,
- 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x9f, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x83,
- 0x00, 0x7c, 0x00, 0x75, 0x00, 0x6f, 0x00, 0x69, 0x01, 0x66, 0x02, 0x61,
- 0x02, 0x5e, 0x03, 0x5a, 0x04, 0x58, 0x04, 0x55, 0x05, 0x53, 0x05, 0x51,
- 0x10, 0x7b, 0x10, 0x73, 0x10, 0x6c, 0x10, 0x66, 0x10, 0x60, 0x10, 0x5b,
- 0x10, 0x56, 0x10, 0x52, 0x10, 0x4f, 0x11, 0x4b, 0x11, 0x48, 0x11, 0x45,
- 0x11, 0x44, 0x12, 0x41, 0x12, 0x40, 0x12, 0x3e, 0x13, 0x3d, 0x13, 0x3b,
- 0x13, 0x3a, 0x13, 0x39, 0x00, 0x00, 0x05, 0x00, 0x1f, 0x00, 0x2e, 0x00,
- 0x35, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00,
- 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00,
- 0x00, 0x6f, 0x02, 0x27, 0x12, 0x02, 0x25, 0x00, 0x2f, 0x00, 0x35, 0x00,
- 0x38, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00,
- 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x30, 0x00, 0x39, 0x00, 0x42, 0x00,
- 0x41, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00,
- 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00,
- 0x00, 0x7f, 0x00, 0x3f, 0x05, 0x05, 0x1c, 0x00, 0x2a, 0x00, 0x31, 0x00,
- 0x35, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00,
- 0x3d, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3c, 0x37, 0x38, 0x33,
- 0x34, 0x31, 0x32, 0x2f, 0x30, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x29,
- 0x2b, 0x28, 0x29, 0x28, 0x28, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, 0x25,
- 0x27, 0x25, 0x27, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x00, 0xd5, 0x00, 0xc8, 0x00, 0xbb, 0x00, 0xaf,
- 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x92, 0x00, 0x8a, 0x00, 0x82, 0x00, 0x7c,
- 0x00, 0x76, 0x00, 0x70, 0x00, 0x6c, 0x01, 0x67, 0x01, 0x64, 0x02, 0x60,
- 0x02, 0x5d, 0x04, 0x5b, 0x04, 0x58, 0x04, 0x55, 0x10, 0x7b, 0x10, 0x75,
- 0x10, 0x6e, 0x10, 0x68, 0x10, 0x63, 0x10, 0x5e, 0x10, 0x5a, 0x10, 0x56,
- 0x10, 0x52, 0x10, 0x4f, 0x11, 0x4c, 0x11, 0x49, 0x11, 0x47, 0x11, 0x44,
- 0x11, 0x43, 0x12, 0x41, 0x12, 0x3f, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x16, 0x00, 0x24, 0x00, 0x2c, 0x00,
- 0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00,
- 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x00, 0x9f, 0x00, 0x6f,
- 0x00, 0x22, 0x0b, 0x09, 0x16, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00,
- 0x33, 0x00, 0x35, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00,
- 0x3b, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x4c, 0x00, 0x39, 0x00, 0x16, 0x00, 0x28, 0x00, 0x2f, 0x00, 0x2e, 0x00,
- 0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00,
- 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x00, 0xa5, 0x00, 0x7f,
- 0x00, 0x3f, 0x00, 0x12, 0x09, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2a, 0x00,
- 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x39, 0x00,
- 0x3a, 0x00, 0x3a, 0x00, 0x3d, 0x38, 0x39, 0x34, 0x35, 0x32, 0x33, 0x30,
- 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2b, 0x2c, 0x2b, 0x2b, 0x29, 0x2b, 0x28,
- 0x29, 0x28, 0x28, 0x26, 0x28, 0x27, 0x27, 0x27, 0x27, 0x26, 0x27, 0x25,
- 0x27, 0x25, 0x26, 0x25, 0x25, 0x25, 0x25, 0x25, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x00, 0xd6, 0x00, 0xca, 0x00, 0xbe, 0x00, 0xb3, 0x00, 0xaa, 0x00, 0xa0,
- 0x00, 0x98, 0x00, 0x90, 0x00, 0x88, 0x00, 0x82, 0x00, 0x7d, 0x00, 0x77,
- 0x00, 0x71, 0x00, 0x6d, 0x01, 0x69, 0x01, 0x66, 0x02, 0x63, 0x02, 0x60,
- 0x02, 0x5d, 0x04, 0x5b, 0x10, 0x7c, 0x10, 0x76, 0x10, 0x70, 0x10, 0x6a,
- 0x10, 0x65, 0x10, 0x61, 0x10, 0x5d, 0x10, 0x59, 0x10, 0x55, 0x10, 0x52,
- 0x10, 0x4f, 0x11, 0x4c, 0x11, 0x49, 0x11, 0x47, 0x11, 0x45, 0x11, 0x44,
- 0x12, 0x42, 0x12, 0x41, 0x12, 0x3f, 0x13, 0x3e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x2b, 0x00,
- 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00,
- 0x39, 0x00, 0x3a, 0x00, 0x00, 0xaf, 0x00, 0x93, 0x00, 0x58, 0x00, 0x21,
- 0x08, 0x0e, 0x0e, 0x02, 0x18, 0x00, 0x20, 0x00, 0x27, 0x00, 0x2b, 0x00,
- 0x2f, 0x00, 0x31, 0x00, 0x33, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x42, 0x00,
- 0x28, 0x00, 0x09, 0x00, 0x16, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x2b, 0x00,
- 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00,
- 0x39, 0x00, 0x3a, 0x00, 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x6d, 0x00, 0x3f,
- 0x00, 0x1d, 0x00, 0x05, 0x0b, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x25, 0x00,
- 0x29, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, 0x00,
- 0x3d, 0x38, 0x39, 0x35, 0x36, 0x33, 0x33, 0x30, 0x31, 0x2f, 0x30, 0x2d,
- 0x2e, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x2b, 0x28, 0x28, 0x28,
- 0x28, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x26, 0x27, 0x25,
- 0x27, 0x25, 0x25, 0x25, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd6, 0x00, 0xcc,
- 0x00, 0xc0, 0x00, 0xb7, 0x00, 0xad, 0x00, 0xa5, 0x00, 0x9d, 0x00, 0x96,
- 0x00, 0x8f, 0x00, 0x88, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x77, 0x00, 0x73,
- 0x00, 0x6f, 0x00, 0x6b, 0x01, 0x67, 0x01, 0x64, 0x02, 0x62, 0x02, 0x5f,
- 0x10, 0x7c, 0x10, 0x77, 0x10, 0x71, 0x10, 0x6c, 0x10, 0x67, 0x10, 0x63,
- 0x10, 0x5f, 0x10, 0x5c, 0x10, 0x58, 0x10, 0x55, 0x10, 0x51, 0x10, 0x4f,
- 0x11, 0x4c, 0x11, 0x4a, 0x11, 0x48, 0x11, 0x46, 0x11, 0x44, 0x11, 0x43,
- 0x12, 0x42, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x2a, 0x00,
- 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34, 0x00, 0x35, 0x00, 0x37, 0x00,
- 0x00, 0xb5, 0x00, 0xa4, 0x00, 0x7a, 0x00, 0x4a, 0x00, 0x20, 0x06, 0x12,
- 0x0c, 0x07, 0x10, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x24, 0x00, 0x28, 0x00,
- 0x2c, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16, 0x00,
- 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x2a, 0x00,
- 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34, 0x00, 0x35, 0x00, 0x37, 0x00,
- 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x62, 0x00, 0x3f, 0x00, 0x24,
- 0x00, 0x0f, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00,
- 0x25, 0x00, 0x29, 0x00, 0x2b, 0x00, 0x2e, 0x00, 0x3d, 0x39, 0x3a, 0x36,
- 0x36, 0x33, 0x34, 0x31, 0x32, 0x30, 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2b,
- 0x2d, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x27,
- 0x28, 0x26, 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x25, 0x27, 0x25,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x00, 0xd7, 0x00, 0xcc, 0x00, 0xc3, 0x00, 0xba,
- 0x00, 0xb1, 0x00, 0xa8, 0x00, 0xa0, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8d,
- 0x00, 0x87, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x74, 0x00, 0x70,
- 0x00, 0x6c, 0x01, 0x69, 0x01, 0x66, 0x02, 0x63, 0x10, 0x7c, 0x10, 0x77,
- 0x10, 0x72, 0x10, 0x6e, 0x10, 0x69, 0x10, 0x65, 0x10, 0x61, 0x10, 0x5d,
- 0x10, 0x5a, 0x10, 0x57, 0x10, 0x54, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d,
- 0x11, 0x4b, 0x11, 0x49, 0x11, 0x47, 0x11, 0x45, 0x11, 0x44, 0x12, 0x42,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00,
- 0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32, 0x00, 0x00, 0xb9, 0x00, 0xad,
- 0x00, 0x8f, 0x00, 0x68, 0x00, 0x42, 0x00, 0x20, 0x05, 0x14, 0x0a, 0x0b,
- 0x0d, 0x04, 0x12, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x23, 0x00, 0x26, 0x00,
- 0x29, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x42, 0x00, 0x3d, 0x00, 0x2e, 0x00, 0x1d, 0x00, 0x0d, 0x00, 0x00, 0x00,
- 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00,
- 0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32, 0x00, 0x00, 0xba, 0x00, 0xb1,
- 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5b, 0x00, 0x3f, 0x00, 0x29, 0x00, 0x16,
- 0x00, 0x08, 0x02, 0x00, 0x0c, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1e, 0x00,
- 0x22, 0x00, 0x25, 0x00, 0x3d, 0x39, 0x3a, 0x36, 0x37, 0x34, 0x35, 0x32,
- 0x33, 0x30, 0x31, 0x2f, 0x30, 0x2d, 0x2e, 0x2d, 0x2d, 0x2a, 0x2c, 0x2b,
- 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27,
- 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x26, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x00, 0xd7, 0x00, 0xce, 0x00, 0xc5, 0x00, 0xbc, 0x00, 0xb4, 0x00, 0xac,
- 0x00, 0xa5, 0x00, 0x9e, 0x00, 0x97, 0x00, 0x91, 0x00, 0x8c, 0x00, 0x87,
- 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x75, 0x00, 0x71, 0x00, 0x6d,
- 0x01, 0x6b, 0x01, 0x68, 0x10, 0x7c, 0x10, 0x78, 0x10, 0x73, 0x10, 0x6f,
- 0x10, 0x6b, 0x10, 0x67, 0x10, 0x63, 0x10, 0x60, 0x10, 0x5c, 0x10, 0x59,
- 0x10, 0x57, 0x10, 0x54, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d, 0x11, 0x4b,
- 0x11, 0x49, 0x11, 0x47, 0x11, 0x46, 0x11, 0x45, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22, 0x00, 0x26, 0x00, 0x29, 0x00,
- 0x2b, 0x00, 0x2d, 0x00, 0x00, 0xba, 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x7d,
- 0x00, 0x5c, 0x00, 0x3c, 0x00, 0x20, 0x04, 0x16, 0x08, 0x0e, 0x0c, 0x07,
- 0x0e, 0x02, 0x13, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x25, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3a, 0x00,
- 0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22, 0x00, 0x26, 0x00, 0x29, 0x00,
- 0x2b, 0x00, 0x2d, 0x00, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xa3, 0x00, 0x8a,
- 0x00, 0x6f, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0f,
- 0x00, 0x04, 0x04, 0x00, 0x0c, 0x00, 0x12, 0x00, 0x17, 0x00, 0x1c, 0x00,
- 0x3d, 0x39, 0x3a, 0x36, 0x37, 0x34, 0x35, 0x33, 0x33, 0x30, 0x32, 0x30,
- 0x30, 0x2e, 0x2f, 0x2d, 0x2d, 0x2c, 0x2d, 0x2a, 0x2c, 0x2b, 0x2b, 0x2a,
- 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x26, 0x28, 0x27,
- 0x27, 0x27, 0x27, 0x27, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd8, 0x00, 0xcf,
- 0x00, 0xc6, 0x00, 0xbe, 0x00, 0xb6, 0x00, 0xaf, 0x00, 0xa8, 0x00, 0xa1,
- 0x00, 0x9c, 0x00, 0x96, 0x00, 0x90, 0x00, 0x8a, 0x00, 0x86, 0x00, 0x81,
- 0x00, 0x7d, 0x00, 0x79, 0x00, 0x75, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x6b,
- 0x10, 0x7d, 0x10, 0x78, 0x10, 0x74, 0x10, 0x70, 0x10, 0x6c, 0x10, 0x68,
- 0x10, 0x65, 0x10, 0x61, 0x10, 0x5f, 0x10, 0x5c, 0x10, 0x59, 0x10, 0x56,
- 0x10, 0x54, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x4a,
- 0x11, 0x48, 0x11, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00,
- 0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22, 0x00, 0x26, 0x00, 0x28, 0x00,
- 0x00, 0xbc, 0x00, 0xb5, 0x00, 0xa4, 0x00, 0x8b, 0x00, 0x6f, 0x00, 0x52,
- 0x00, 0x37, 0x00, 0x20, 0x04, 0x17, 0x07, 0x10, 0x0a, 0x0a, 0x0d, 0x05,
- 0x0f, 0x00, 0x14, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00,
- 0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00,
- 0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22, 0x00, 0x26, 0x00, 0x28, 0x00,
- 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x96, 0x00, 0x7f, 0x00, 0x68,
- 0x00, 0x53, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x20, 0x00, 0x14, 0x00, 0x0a,
- 0x00, 0x01, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x3d, 0x3a, 0x3a, 0x37,
- 0x38, 0x35, 0x36, 0x33, 0x33, 0x32, 0x33, 0x30, 0x30, 0x2f, 0x30, 0x2d,
- 0x2e, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28,
- 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27, 0x29, 0x27, 0x27, 0x27,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x00, 0xd8, 0x00, 0xd0, 0x00, 0xc8, 0x00, 0xc0,
- 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xab, 0x00, 0xa5, 0x00, 0x9f, 0x00, 0x99,
- 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8a, 0x00, 0x86, 0x00, 0x81, 0x00, 0x7d,
- 0x00, 0x79, 0x00, 0x76, 0x00, 0x73, 0x00, 0x70, 0x10, 0x7d, 0x10, 0x79,
- 0x10, 0x75, 0x10, 0x71, 0x10, 0x6d, 0x10, 0x6a, 0x10, 0x66, 0x10, 0x63,
- 0x10, 0x60, 0x10, 0x5d, 0x10, 0x5b, 0x10, 0x58, 0x10, 0x56, 0x10, 0x54,
- 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d, 0x11, 0x4c, 0x11, 0x4a, 0x11, 0x49,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13, 0x00,
- 0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23, 0x00, 0x00, 0xbc, 0x00, 0xb8,
- 0x00, 0xaa, 0x00, 0x96, 0x00, 0x7e, 0x00, 0x64, 0x00, 0x4c, 0x00, 0x34,
- 0x00, 0x20, 0x03, 0x18, 0x06, 0x11, 0x09, 0x0c, 0x0c, 0x07, 0x0e, 0x03,
- 0x10, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x25, 0x00, 0x1b, 0x00,
- 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13, 0x00,
- 0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23, 0x00, 0x00, 0xbd, 0x00, 0xb9,
- 0x00, 0xae, 0x00, 0x9e, 0x00, 0x8b, 0x00, 0x77, 0x00, 0x63, 0x00, 0x50,
- 0x00, 0x3f, 0x00, 0x30, 0x00, 0x23, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x06,
- 0x00, 0x00, 0x07, 0x00, 0x3d, 0x3a, 0x3a, 0x38, 0x38, 0x36, 0x36, 0x33,
- 0x34, 0x33, 0x33, 0x30, 0x31, 0x30, 0x30, 0x2e, 0x2f, 0x2d, 0x2d, 0x2d,
- 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x27, 0x28, 0x27, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x00, 0xd9, 0x00, 0xd1, 0x00, 0xc9, 0x00, 0xc2, 0x00, 0xbb, 0x00, 0xb4,
- 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa2, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x92,
- 0x00, 0x8e, 0x00, 0x89, 0x00, 0x85, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7a,
- 0x00, 0x76, 0x00, 0x73, 0x10, 0x7d, 0x10, 0x79, 0x10, 0x75, 0x10, 0x72,
- 0x10, 0x6e, 0x10, 0x6b, 0x10, 0x68, 0x10, 0x65, 0x10, 0x62, 0x10, 0x5f,
- 0x10, 0x5c, 0x10, 0x5a, 0x10, 0x58, 0x10, 0x55, 0x10, 0x53, 0x10, 0x51,
- 0x10, 0x4f, 0x11, 0x4e, 0x11, 0x4c, 0x11, 0x4a, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x16, 0x00,
- 0x1a, 0x00, 0x1d, 0x00, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9d,
- 0x00, 0x89, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x46, 0x00, 0x32, 0x00, 0x20,
- 0x03, 0x19, 0x06, 0x13, 0x08, 0x0e, 0x0b, 0x09, 0x0d, 0x05, 0x0e, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00,
- 0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00,
- 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x16, 0x00,
- 0x1a, 0x00, 0x1d, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa4,
- 0x00, 0x94, 0x00, 0x82, 0x00, 0x70, 0x00, 0x5e, 0x00, 0x4e, 0x00, 0x3f,
- 0x00, 0x32, 0x00, 0x26, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x03,
- 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x36, 0x34, 0x35, 0x33, 0x33, 0x31,
- 0x32, 0x30, 0x30, 0x2f, 0x30, 0x2d, 0x2e, 0x2d, 0x2d, 0x2c, 0x2d, 0x2a,
- 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd9, 0x00, 0xd1,
- 0x00, 0xca, 0x00, 0xc3, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xb0, 0x00, 0xaa,
- 0x00, 0xa5, 0x00, 0xa0, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x91, 0x00, 0x8d,
- 0x00, 0x89, 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x77,
- 0x10, 0x7d, 0x10, 0x79, 0x10, 0x76, 0x10, 0x72, 0x10, 0x6f, 0x10, 0x6c,
- 0x10, 0x69, 0x10, 0x66, 0x10, 0x63, 0x10, 0x61, 0x10, 0x5e, 0x10, 0x5c,
- 0x10, 0x59, 0x10, 0x57, 0x10, 0x55, 0x10, 0x53, 0x10, 0x51, 0x10, 0x4f,
- 0x11, 0x4e, 0x11, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00,
- 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa3, 0x00, 0x92, 0x00, 0x7e,
- 0x00, 0x6a, 0x00, 0x56, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x03, 0x19,
- 0x05, 0x14, 0x08, 0x0f, 0x0a, 0x0b, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x34, 0x00,
- 0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x06, 0x00,
- 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00,
- 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb4, 0x00, 0xa9, 0x00, 0x9b, 0x00, 0x8b,
- 0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4d, 0x00, 0x3f, 0x00, 0x33,
- 0x00, 0x28, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0e, 0x3d, 0x3b, 0x3b, 0x39,
- 0x3a, 0x36, 0x36, 0x35, 0x36, 0x33, 0x33, 0x32, 0x33, 0x30, 0x30, 0x30,
- 0x30, 0x2e, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b,
- 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x00, 0xd9, 0x00, 0xd2, 0x00, 0xcb, 0x00, 0xc4,
- 0x00, 0xbe, 0x00, 0xb8, 0x00, 0xb2, 0x00, 0xad, 0x00, 0xa8, 0x00, 0xa2,
- 0x00, 0x9d, 0x00, 0x99, 0x00, 0x94, 0x00, 0x90, 0x00, 0x8b, 0x00, 0x88,
- 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7b, 0x10, 0x7d, 0x10, 0x7a,
- 0x10, 0x76, 0x10, 0x73, 0x10, 0x70, 0x10, 0x6d, 0x10, 0x6a, 0x10, 0x67,
- 0x10, 0x65, 0x10, 0x62, 0x10, 0x5f, 0x10, 0x5d, 0x10, 0x5b, 0x10, 0x59,
- 0x10, 0x56, 0x10, 0x55, 0x10, 0x53, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4e,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x00, 0xbd, 0x00, 0xbb,
- 0x00, 0xb3, 0x00, 0xa8, 0x00, 0x99, 0x00, 0x87, 0x00, 0x75, 0x00, 0x62,
- 0x00, 0x50, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x1f, 0x02, 0x1a, 0x05, 0x15,
- 0x07, 0x10, 0x09, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29, 0x00,
- 0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00,
- 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x00, 0xbe, 0x00, 0xbc,
- 0x00, 0xb6, 0x00, 0xac, 0x00, 0xa0, 0x00, 0x93, 0x00, 0x84, 0x00, 0x75,
- 0x00, 0x66, 0x00, 0x58, 0x00, 0x4b, 0x00, 0x3f, 0x00, 0x34, 0x00, 0x2a,
- 0x00, 0x21, 0x00, 0x19, 0x3d, 0x3b, 0x3b, 0x39, 0x39, 0x36, 0x37, 0x35,
- 0x36, 0x33, 0x33, 0x33, 0x33, 0x30, 0x31, 0x30, 0x30, 0x2f, 0x30, 0x2d,
- 0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
- 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22,
- 0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcc, 0x00, 0xc6, 0x00, 0xc0, 0x00, 0xba,
- 0x00, 0xb4, 0x00, 0xaf, 0x00, 0xaa, 0x00, 0xa5, 0x00, 0xa0, 0x00, 0x9b,
- 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f, 0x00, 0x8b, 0x00, 0x88, 0x00, 0x83,
- 0x00, 0x81, 0x00, 0x7d, 0x10, 0x7d, 0x10, 0x7a, 0x10, 0x77, 0x10, 0x74,
- 0x10, 0x71, 0x10, 0x6e, 0x10, 0x6b, 0x10, 0x68, 0x10, 0x65, 0x10, 0x63,
- 0x10, 0x61, 0x10, 0x5e, 0x10, 0x5c, 0x10, 0x5a, 0x10, 0x58, 0x10, 0x56,
- 0x10, 0x55, 0x10, 0x52, 0x10, 0x51, 0x10, 0x4f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
- 0x09, 0x00, 0x0d, 0x00, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xab,
- 0x00, 0x9e, 0x00, 0x8f, 0x00, 0x7e, 0x00, 0x6d, 0x00, 0x5c, 0x00, 0x4c,
- 0x00, 0x3c, 0x00, 0x2d, 0x00, 0x1f, 0x02, 0x1a, 0x04, 0x16, 0x06, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
- 0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x26, 0x00, 0x1f, 0x00,
- 0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00,
- 0x09, 0x00, 0x0d, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf,
- 0x00, 0xa5, 0x00, 0x99, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x70, 0x00, 0x63,
- 0x00, 0x56, 0x00, 0x4a, 0x00, 0x3f, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x23,
- 0x27, 0x76, 0x1a, 0x79, 0x16, 0x7b, 0x15, 0x7c, 0x14, 0x7c, 0x13, 0x7d,
- 0x13, 0x7d, 0x13, 0x7d, 0x12, 0x7d, 0x12, 0x7d, 0x12, 0x7e, 0x12, 0x7e,
- 0x12, 0x7e, 0x12, 0x7e, 0x12, 0x7e, 0x11, 0x7e, 0x11, 0x7e, 0x11, 0x7e,
- 0x11, 0x7f, 0x11, 0x7f, 0x13, 0x5f, 0x10, 0x6f, 0x10, 0x74, 0x10, 0x77,
- 0x10, 0x78, 0x10, 0x7a, 0x10, 0x7a, 0x10, 0x7b, 0x10, 0x7b, 0x10, 0x7c,
- 0x10, 0x7c, 0x10, 0x7c, 0x10, 0x7c, 0x10, 0x7d, 0x10, 0x7d, 0x10, 0x7d,
- 0x10, 0x7d, 0x10, 0x7d, 0x10, 0x7d, 0x10, 0x7d, 0x00, 0x90, 0x02, 0x81,
- 0x06, 0x80, 0x09, 0x7f, 0x0a, 0x7f, 0x0b, 0x7f, 0x0c, 0x7f, 0x0d, 0x7f,
- 0x0d, 0x7f, 0x0d, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f,
- 0x0e, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00,
- 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xae, 0x00, 0xa2, 0x00, 0x95,
- 0x00, 0x86, 0x00, 0x77, 0x00, 0x67, 0x00, 0x57, 0x00, 0x48, 0x00, 0x3a,
- 0x00, 0x2c, 0x00, 0x1f, 0x02, 0x1b, 0x04, 0x16, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00,
- 0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1c, 0x00, 0x16, 0x00,
- 0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00,
- 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9d,
- 0x00, 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54,
- 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2d, 0x32, 0x5f, 0x25, 0x68,
- 0x1f, 0x6d, 0x1c, 0x71, 0x19, 0x72, 0x18, 0x74, 0x17, 0x76, 0x16, 0x77,
- 0x16, 0x77, 0x15, 0x78, 0x15, 0x79, 0x15, 0x79, 0x14, 0x7a, 0x14, 0x7a,
- 0x13, 0x7a, 0x13, 0x7b, 0x13, 0x7b, 0x13, 0x7b, 0x13, 0x7b, 0x13, 0x7b,
- 0x17, 0x46, 0x11, 0x58, 0x10, 0x63, 0x10, 0x69, 0x10, 0x6d, 0x10, 0x70,
- 0x10, 0x72, 0x10, 0x73, 0x10, 0x75, 0x10, 0x76, 0x10, 0x77, 0x10, 0x77,
- 0x10, 0x78, 0x10, 0x78, 0x10, 0x79, 0x10, 0x79, 0x10, 0x79, 0x10, 0x7a,
- 0x10, 0x7a, 0x10, 0x7a, 0x00, 0xbd, 0x00, 0xa4, 0x00, 0x97, 0x02, 0x91,
- 0x04, 0x8d, 0x05, 0x8a, 0x06, 0x89, 0x07, 0x88, 0x08, 0x86, 0x09, 0x86,
- 0x09, 0x85, 0x0a, 0x85, 0x0a, 0x84, 0x0b, 0x84, 0x0b, 0x83, 0x0b, 0x83,
- 0x0c, 0x83, 0x0c, 0x83, 0x0c, 0x82, 0x0c, 0x82, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xbe, 0x00, 0xbc,
- 0x00, 0xb8, 0x00, 0xb0, 0x00, 0xa6, 0x00, 0x9a, 0x00, 0x8d, 0x00, 0x7f,
- 0x00, 0x70, 0x00, 0x61, 0x00, 0x53, 0x00, 0x45, 0x00, 0x38, 0x00, 0x2b,
- 0x00, 0x1f, 0x02, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39, 0x00, 0x35, 0x00, 0x31, 0x00,
- 0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0f, 0x00,
- 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xbe, 0x00, 0xbd,
- 0x00, 0xb9, 0x00, 0xb3, 0x00, 0xab, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8b,
- 0x00, 0x80, 0x00, 0x74, 0x00, 0x68, 0x00, 0x5d, 0x00, 0x53, 0x00, 0x49,
- 0x00, 0x3f, 0x00, 0x36, 0x36, 0x56, 0x2a, 0x5f, 0x24, 0x65, 0x20, 0x68,
- 0x1e, 0x6c, 0x1c, 0x6e, 0x1b, 0x70, 0x19, 0x71, 0x18, 0x72, 0x18, 0x73,
- 0x18, 0x75, 0x17, 0x75, 0x16, 0x76, 0x15, 0x76, 0x15, 0x76, 0x15, 0x77,
- 0x15, 0x77, 0x15, 0x77, 0x15, 0x78, 0x15, 0x79, 0x1a, 0x39, 0x13, 0x4a,
- 0x11, 0x55, 0x10, 0x5e, 0x10, 0x63, 0x10, 0x67, 0x10, 0x6a, 0x10, 0x6c,
- 0x10, 0x6e, 0x10, 0x70, 0x10, 0x71, 0x10, 0x72, 0x10, 0x73, 0x10, 0x74,
- 0x10, 0x75, 0x10, 0x75, 0x10, 0x76, 0x10, 0x76, 0x10, 0x77, 0x10, 0x77,
- 0x00, 0xcc, 0x00, 0xb5, 0x00, 0xa8, 0x00, 0x9e, 0x01, 0x99, 0x02, 0x94,
- 0x03, 0x92, 0x04, 0x8f, 0x05, 0x8d, 0x06, 0x8c, 0x06, 0x8b, 0x07, 0x8a,
- 0x07, 0x89, 0x08, 0x88, 0x08, 0x88, 0x09, 0x87, 0x09, 0x87, 0x09, 0x86,
- 0x0a, 0x86, 0x0a, 0x86, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb2,
- 0x00, 0xa9, 0x00, 0x9e, 0x00, 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6a,
- 0x00, 0x5c, 0x00, 0x4f, 0x00, 0x42, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
- 0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x28, 0x00,
- 0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x09, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb4,
- 0x00, 0xad, 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x91, 0x00, 0x86, 0x00, 0x7b,
- 0x00, 0x70, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3f,
- 0x38, 0x52, 0x2e, 0x59, 0x28, 0x5f, 0x24, 0x63, 0x22, 0x67, 0x1f, 0x69,
- 0x1e, 0x6b, 0x1c, 0x6d, 0x1b, 0x6e, 0x1a, 0x70, 0x1a, 0x71, 0x19, 0x72,
- 0x18, 0x72, 0x18, 0x72, 0x18, 0x73, 0x17, 0x75, 0x17, 0x76, 0x16, 0x76,
- 0x15, 0x76, 0x15, 0x76, 0x1b, 0x33, 0x15, 0x41, 0x12, 0x4c, 0x11, 0x54,
- 0x10, 0x5b, 0x10, 0x5f, 0x10, 0x63, 0x10, 0x66, 0x10, 0x68, 0x10, 0x6a,
- 0x10, 0x6c, 0x10, 0x6e, 0x10, 0x6f, 0x10, 0x70, 0x10, 0x71, 0x10, 0x72,
- 0x10, 0x72, 0x10, 0x73, 0x10, 0x74, 0x10, 0x74, 0x00, 0xd1, 0x00, 0xc0,
- 0x00, 0xb3, 0x00, 0xaa, 0x00, 0xa2, 0x00, 0x9d, 0x01, 0x99, 0x02, 0x96,
- 0x02, 0x94, 0x03, 0x92, 0x04, 0x90, 0x05, 0x8f, 0x05, 0x8d, 0x06, 0x8d,
- 0x06, 0x8c, 0x07, 0x8b, 0x07, 0x8a, 0x07, 0x8a, 0x07, 0x89, 0x08, 0x89,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x07, 0x47, 0x0f, 0x0f, 0x26, 0x00, 0x33, 0x00, 0x38, 0x00, 0x3a, 0x00,
- 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00,
- 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x07, 0x47, 0x00, 0x7f, 0x00, 0xa5, 0x00, 0xb2,
- 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd,
- 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x4f, 0x31, 0x55,
- 0x2b, 0x5b, 0x27, 0x5f, 0x24, 0x63, 0x22, 0x65, 0x20, 0x68, 0x1f, 0x69,
- 0x1d, 0x6b, 0x1d, 0x6d, 0x1b, 0x6d, 0x1a, 0x6e, 0x1a, 0x6f, 0x1a, 0x71,
- 0x19, 0x72, 0x18, 0x72, 0x18, 0x72, 0x18, 0x72, 0x18, 0x73, 0x18, 0x74,
- 0x1c, 0x2f, 0x16, 0x3b, 0x13, 0x44, 0x11, 0x4d, 0x11, 0x53, 0x10, 0x59,
- 0x10, 0x5d, 0x10, 0x60, 0x10, 0x63, 0x10, 0x65, 0x10, 0x67, 0x10, 0x69,
- 0x10, 0x6b, 0x10, 0x6c, 0x10, 0x6d, 0x10, 0x6e, 0x10, 0x6f, 0x10, 0x70,
- 0x10, 0x71, 0x10, 0x71, 0x00, 0xd5, 0x00, 0xc6, 0x00, 0xbb, 0x00, 0xb2,
- 0x00, 0xaa, 0x00, 0xa4, 0x00, 0xa0, 0x01, 0x9c, 0x01, 0x9a, 0x02, 0x97,
- 0x02, 0x95, 0x03, 0x93, 0x03, 0x92, 0x04, 0x91, 0x05, 0x90, 0x05, 0x8e,
- 0x06, 0x8e, 0x06, 0x8d, 0x06, 0x8c, 0x06, 0x8c, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x3f,
- 0x05, 0x05, 0x1c, 0x00, 0x2a, 0x00, 0x31, 0x00, 0x35, 0x00, 0x38, 0x00,
- 0x39, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00,
- 0x3d, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0f, 0x0f, 0x00, 0x3f, 0x00, 0x7f, 0x00, 0x9c, 0x00, 0xaa, 0x00, 0xb1,
- 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc,
- 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3a, 0x4c, 0x33, 0x53, 0x2e, 0x58, 0x29, 0x5c,
- 0x27, 0x5f, 0x24, 0x62, 0x22, 0x64, 0x20, 0x66, 0x20, 0x68, 0x1e, 0x69,
- 0x1d, 0x6a, 0x1d, 0x6c, 0x1c, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x1a, 0x6f,
- 0x1a, 0x71, 0x19, 0x72, 0x18, 0x72, 0x18, 0x72, 0x1d, 0x2d, 0x17, 0x37,
- 0x14, 0x40, 0x12, 0x47, 0x11, 0x4e, 0x11, 0x53, 0x10, 0x57, 0x10, 0x5b,
- 0x10, 0x5e, 0x10, 0x61, 0x10, 0x63, 0x10, 0x65, 0x10, 0x67, 0x10, 0x68,
- 0x10, 0x6a, 0x10, 0x6b, 0x10, 0x6c, 0x10, 0x6d, 0x10, 0x6e, 0x10, 0x6f,
- 0x00, 0xd6, 0x00, 0xcb, 0x00, 0xc0, 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xab,
- 0x00, 0xa6, 0x00, 0xa2, 0x00, 0x9f, 0x01, 0x9c, 0x02, 0x9a, 0x02, 0x98,
- 0x02, 0x96, 0x03, 0x94, 0x03, 0x93, 0x03, 0x92, 0x04, 0x91, 0x05, 0x90,
- 0x05, 0x8f, 0x05, 0x8f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x12,
- 0x09, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x32, 0x00,
- 0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3a, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x05, 0x05,
- 0x00, 0x3f, 0x00, 0x6d, 0x00, 0x88, 0x00, 0x99, 0x00, 0xa3, 0x00, 0xaa,
- 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8,
- 0x00, 0xb9, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3b, 0x4b, 0x34, 0x51, 0x2f, 0x55, 0x2c, 0x59, 0x29, 0x5c, 0x26, 0x60,
- 0x24, 0x61, 0x23, 0x64, 0x21, 0x65, 0x20, 0x67, 0x1f, 0x69, 0x1d, 0x69,
- 0x1d, 0x6a, 0x1d, 0x6c, 0x1c, 0x6d, 0x1b, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d,
- 0x1a, 0x6f, 0x1a, 0x71, 0x1e, 0x2b, 0x18, 0x34, 0x15, 0x3b, 0x13, 0x43,
- 0x12, 0x49, 0x11, 0x4e, 0x11, 0x52, 0x10, 0x56, 0x10, 0x5a, 0x10, 0x5d,
- 0x10, 0x5f, 0x10, 0x61, 0x10, 0x63, 0x10, 0x65, 0x10, 0x66, 0x10, 0x68,
- 0x10, 0x69, 0x10, 0x6a, 0x10, 0x6b, 0x10, 0x6c, 0x00, 0xd7, 0x00, 0xcd,
- 0x00, 0xc5, 0x00, 0xbd, 0x00, 0xb6, 0x00, 0xb0, 0x00, 0xab, 0x00, 0xa7,
- 0x00, 0xa4, 0x00, 0xa1, 0x01, 0x9e, 0x01, 0x9c, 0x02, 0x9a, 0x02, 0x98,
- 0x02, 0x97, 0x02, 0x96, 0x03, 0x94, 0x03, 0x93, 0x03, 0x92, 0x04, 0x91,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x6d, 0x00, 0x3f, 0x00, 0x1d, 0x00, 0x05,
- 0x0b, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, 0x00,
- 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x1c, 0x00, 0x00, 0x12, 0x00, 0x3f,
- 0x00, 0x62, 0x00, 0x7a, 0x00, 0x8a, 0x00, 0x96, 0x00, 0x9e, 0x00, 0xa4,
- 0x00, 0xa9, 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x49, 0x36, 0x4f,
- 0x31, 0x54, 0x2d, 0x57, 0x2a, 0x5a, 0x28, 0x5c, 0x26, 0x60, 0x24, 0x61,
- 0x23, 0x64, 0x21, 0x65, 0x20, 0x65, 0x20, 0x68, 0x1e, 0x69, 0x1d, 0x69,
- 0x1d, 0x69, 0x1d, 0x6b, 0x1c, 0x6d, 0x1b, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d,
- 0x1e, 0x2a, 0x19, 0x32, 0x16, 0x39, 0x13, 0x3f, 0x12, 0x45, 0x11, 0x4a,
- 0x11, 0x4e, 0x11, 0x52, 0x10, 0x56, 0x10, 0x59, 0x10, 0x5c, 0x10, 0x5d,
- 0x10, 0x60, 0x10, 0x61, 0x10, 0x63, 0x10, 0x65, 0x10, 0x66, 0x10, 0x67,
- 0x10, 0x68, 0x10, 0x69, 0x00, 0xd8, 0x00, 0xcf, 0x00, 0xc7, 0x00, 0xc0,
- 0x00, 0xba, 0x00, 0xb5, 0x00, 0xb0, 0x00, 0xac, 0x00, 0xa8, 0x00, 0xa5,
- 0x00, 0xa2, 0x00, 0xa0, 0x01, 0x9e, 0x01, 0x9c, 0x02, 0x9a, 0x02, 0x99,
- 0x02, 0x97, 0x02, 0x96, 0x03, 0x95, 0x03, 0x94, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa,
- 0x00, 0x88, 0x00, 0x62, 0x00, 0x3f, 0x00, 0x24, 0x00, 0x0f, 0x00, 0x00,
- 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00,
- 0x2b, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x38, 0x00, 0x2a, 0x00, 0x09, 0x00, 0x00, 0x1d, 0x00, 0x3f, 0x00, 0x5b,
- 0x00, 0x6f, 0x00, 0x7f, 0x00, 0x8b, 0x00, 0x94, 0x00, 0x9b, 0x00, 0xa0,
- 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xad, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3c, 0x48, 0x37, 0x4d, 0x32, 0x51, 0x2f, 0x55,
- 0x2c, 0x58, 0x29, 0x5b, 0x27, 0x5d, 0x26, 0x60, 0x24, 0x60, 0x23, 0x63,
- 0x22, 0x65, 0x20, 0x65, 0x20, 0x66, 0x1f, 0x68, 0x1e, 0x69, 0x1d, 0x69,
- 0x1d, 0x69, 0x1d, 0x6b, 0x1c, 0x6d, 0x1b, 0x6d, 0x1e, 0x29, 0x1a, 0x30,
- 0x17, 0x36, 0x14, 0x3c, 0x13, 0x41, 0x12, 0x46, 0x11, 0x4a, 0x11, 0x4f,
- 0x11, 0x52, 0x10, 0x55, 0x10, 0x58, 0x10, 0x5a, 0x10, 0x5c, 0x10, 0x5f,
- 0x10, 0x60, 0x10, 0x62, 0x10, 0x63, 0x10, 0x65, 0x10, 0x65, 0x10, 0x67,
- 0x00, 0xd9, 0x00, 0xd1, 0x00, 0xca, 0x00, 0xc3, 0x00, 0xbe, 0x00, 0xb9,
- 0x00, 0xb4, 0x00, 0xb0, 0x00, 0xac, 0x00, 0xa9, 0x00, 0xa6, 0x00, 0xa3,
- 0x00, 0xa1, 0x01, 0x9f, 0x01, 0x9d, 0x01, 0x9b, 0x02, 0x9a, 0x02, 0x99,
- 0x02, 0x98, 0x02, 0x97, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb1, 0x00, 0x99, 0x00, 0x7a,
- 0x00, 0x5b, 0x00, 0x3f, 0x00, 0x29, 0x00, 0x16, 0x00, 0x08, 0x02, 0x00,
- 0x0c, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x22, 0x00, 0x25, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x31, 0x00,
- 0x19, 0x00, 0x00, 0x05, 0x00, 0x24, 0x00, 0x3f, 0x00, 0x56, 0x00, 0x68,
- 0x00, 0x77, 0x00, 0x82, 0x00, 0x8b, 0x00, 0x93, 0x00, 0x99, 0x00, 0x9d,
- 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3c, 0x48, 0x37, 0x4c, 0x33, 0x50, 0x30, 0x54, 0x2d, 0x57, 0x2a, 0x59,
- 0x29, 0x5c, 0x27, 0x5d, 0x26, 0x60, 0x24, 0x60, 0x23, 0x62, 0x22, 0x65,
- 0x20, 0x65, 0x20, 0x65, 0x20, 0x67, 0x1f, 0x69, 0x1d, 0x69, 0x1d, 0x69,
- 0x1d, 0x69, 0x1d, 0x6a, 0x1f, 0x28, 0x1a, 0x2e, 0x17, 0x34, 0x15, 0x39,
- 0x13, 0x3f, 0x13, 0x43, 0x12, 0x48, 0x11, 0x4b, 0x11, 0x4f, 0x11, 0x52,
- 0x10, 0x55, 0x10, 0x57, 0x10, 0x59, 0x10, 0x5c, 0x10, 0x5d, 0x10, 0x5f,
- 0x10, 0x61, 0x10, 0x62, 0x10, 0x63, 0x10, 0x64, 0x00, 0xd9, 0x00, 0xd2,
- 0x00, 0xcc, 0x00, 0xc6, 0x00, 0xc1, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xb3,
- 0x00, 0xaf, 0x00, 0xac, 0x00, 0xa9, 0x00, 0xa6, 0x00, 0xa4, 0x00, 0xa2,
- 0x00, 0xa0, 0x01, 0x9e, 0x01, 0x9d, 0x02, 0x9c, 0x02, 0x9a, 0x02, 0x99,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xa3, 0x00, 0x8a, 0x00, 0x6f, 0x00, 0x56,
- 0x00, 0x3f, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0f, 0x00, 0x04, 0x04, 0x00,
- 0x0c, 0x00, 0x12, 0x00, 0x17, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x23, 0x00, 0x0b, 0x00,
- 0x00, 0x0f, 0x00, 0x29, 0x00, 0x3f, 0x00, 0x53, 0x00, 0x63, 0x00, 0x70,
- 0x00, 0x7b, 0x00, 0x84, 0x00, 0x8b, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x47, 0x38, 0x4b,
- 0x34, 0x4f, 0x31, 0x53, 0x2e, 0x55, 0x2c, 0x57, 0x2a, 0x5a, 0x28, 0x5c,
- 0x27, 0x5d, 0x26, 0x60, 0x23, 0x60, 0x23, 0x61, 0x23, 0x64, 0x21, 0x65,
- 0x20, 0x65, 0x20, 0x65, 0x20, 0x68, 0x1e, 0x69, 0x1d, 0x69, 0x1d, 0x69,
- 0x1f, 0x27, 0x1b, 0x2d, 0x18, 0x33, 0x16, 0x38, 0x14, 0x3c, 0x13, 0x41,
- 0x12, 0x44, 0x11, 0x48, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54,
- 0x10, 0x57, 0x10, 0x59, 0x10, 0x5b, 0x10, 0x5c, 0x10, 0x5e, 0x10, 0x5f,
- 0x10, 0x61, 0x10, 0x62, 0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcd, 0x00, 0xc8,
- 0x00, 0xc3, 0x00, 0xbe, 0x00, 0xba, 0x00, 0xb6, 0x00, 0xb2, 0x00, 0xaf,
- 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa7, 0x00, 0xa5, 0x00, 0xa3, 0x00, 0xa1,
- 0x01, 0xa0, 0x01, 0x9e, 0x01, 0x9d, 0x02, 0x9c, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb7,
- 0x00, 0xaa, 0x00, 0x96, 0x00, 0x7f, 0x00, 0x68, 0x00, 0x53, 0x00, 0x3f,
- 0x00, 0x2e, 0x00, 0x20, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x06, 0x00,
- 0x0c, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x16,
- 0x00, 0x2c, 0x00, 0x3f, 0x00, 0x50, 0x00, 0x5e, 0x00, 0x6b, 0x00, 0x75,
- 0x00, 0x7e, 0x00, 0x85, 0x00, 0x8b, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3d, 0x47, 0x38, 0x4b, 0x35, 0x4e, 0x32, 0x51,
- 0x2f, 0x53, 0x2d, 0x57, 0x2b, 0x58, 0x2a, 0x5b, 0x27, 0x5c, 0x27, 0x5d,
- 0x25, 0x60, 0x23, 0x60, 0x23, 0x61, 0x23, 0x64, 0x21, 0x65, 0x20, 0x65,
- 0x20, 0x65, 0x20, 0x66, 0x1f, 0x69, 0x1e, 0x69, 0x1f, 0x27, 0x1b, 0x2c,
- 0x18, 0x31, 0x16, 0x36, 0x14, 0x3a, 0x13, 0x3e, 0x13, 0x42, 0x12, 0x45,
- 0x11, 0x49, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54, 0x10, 0x56,
- 0x10, 0x58, 0x10, 0x5a, 0x10, 0x5c, 0x10, 0x5d, 0x10, 0x5e, 0x10, 0x60,
- 0x00, 0xd9, 0x00, 0xd4, 0x00, 0xce, 0x00, 0xca, 0x00, 0xc5, 0x00, 0xc1,
- 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb6, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad,
- 0x00, 0xaa, 0x00, 0xa8, 0x00, 0xa6, 0x00, 0xa4, 0x00, 0xa2, 0x00, 0xa0,
- 0x01, 0x9f, 0x01, 0x9e, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e,
- 0x00, 0x8b, 0x00, 0x77, 0x00, 0x63, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x30,
- 0x00, 0x23, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x07, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x39, 0x00,
- 0x2f, 0x00, 0x1f, 0x00, 0x0b, 0x00, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x2e,
- 0x00, 0x3f, 0x00, 0x4e, 0x00, 0x5b, 0x00, 0x66, 0x00, 0x70, 0x00, 0x78,
- 0x00, 0x80, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x46, 0x39, 0x4a, 0x35, 0x4d, 0x32, 0x50, 0x30, 0x53, 0x2e, 0x55,
- 0x2c, 0x57, 0x2a, 0x58, 0x29, 0x5c, 0x27, 0x5c, 0x27, 0x5d, 0x25, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x63, 0x22, 0x65, 0x20, 0x65, 0x20, 0x65,
- 0x20, 0x65, 0x20, 0x67, 0x1f, 0x27, 0x1c, 0x2c, 0x19, 0x30, 0x17, 0x35,
- 0x15, 0x39, 0x14, 0x3d, 0x13, 0x40, 0x12, 0x44, 0x12, 0x47, 0x11, 0x49,
- 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54, 0x10, 0x56, 0x10, 0x58,
- 0x10, 0x59, 0x10, 0x5b, 0x10, 0x5c, 0x10, 0x5e, 0x00, 0xda, 0x00, 0xd4,
- 0x00, 0xd0, 0x00, 0xcb, 0x00, 0xc7, 0x00, 0xc2, 0x00, 0xbe, 0x00, 0xbb,
- 0x00, 0xb8, 0x00, 0xb5, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa,
- 0x00, 0xa8, 0x00, 0xa6, 0x00, 0xa4, 0x00, 0xa3, 0x00, 0xa1, 0x01, 0xa0,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x82,
- 0x00, 0x70, 0x00, 0x5e, 0x00, 0x4e, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x26,
- 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x25, 0x00,
- 0x14, 0x00, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x20, 0x00, 0x30, 0x00, 0x3f,
- 0x00, 0x4d, 0x00, 0x58, 0x00, 0x63, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x7b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x46, 0x39, 0x49,
- 0x36, 0x4c, 0x33, 0x4f, 0x31, 0x52, 0x2e, 0x53, 0x2d, 0x57, 0x2b, 0x57,
- 0x2a, 0x59, 0x28, 0x5c, 0x27, 0x5c, 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x62, 0x22, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65,
- 0x1f, 0x26, 0x1c, 0x2b, 0x19, 0x2f, 0x17, 0x33, 0x16, 0x37, 0x14, 0x3b,
- 0x13, 0x3e, 0x13, 0x41, 0x12, 0x44, 0x11, 0x47, 0x11, 0x4a, 0x11, 0x4d,
- 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54, 0x10, 0x55, 0x10, 0x57, 0x10, 0x59,
- 0x10, 0x5a, 0x10, 0x5b, 0x00, 0xda, 0x00, 0xd5, 0x00, 0xd1, 0x00, 0xcc,
- 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc1, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb7,
- 0x00, 0xb4, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa9,
- 0x00, 0xa7, 0x00, 0xa5, 0x00, 0xa4, 0x00, 0xa2, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb,
- 0x00, 0xb4, 0x00, 0xa9, 0x00, 0x9b, 0x00, 0x8b, 0x00, 0x7b, 0x00, 0x6b,
- 0x00, 0x5b, 0x00, 0x4d, 0x00, 0x3f, 0x00, 0x33, 0x00, 0x28, 0x00, 0x1f,
- 0x00, 0x16, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3e, 0x00, 0x3c, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0c, 0x00,
- 0x00, 0x04, 0x00, 0x14, 0x00, 0x23, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4b,
- 0x00, 0x56, 0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x39, 0x48, 0x36, 0x4b, 0x34, 0x4f,
- 0x31, 0x50, 0x30, 0x53, 0x2e, 0x55, 0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x5a,
- 0x28, 0x5c, 0x27, 0x5c, 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x61, 0x22, 0x64, 0x21, 0x65, 0x20, 0x65, 0x20, 0x26, 0x1c, 0x2a,
- 0x1a, 0x2e, 0x18, 0x32, 0x16, 0x36, 0x14, 0x39, 0x13, 0x3d, 0x13, 0x40,
- 0x12, 0x43, 0x12, 0x45, 0x11, 0x48, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f,
- 0x11, 0x51, 0x10, 0x53, 0x10, 0x55, 0x10, 0x56, 0x10, 0x58, 0x10, 0x5a,
- 0x00, 0xda, 0x00, 0xd6, 0x00, 0xd1, 0x00, 0xcd, 0x00, 0xc9, 0x00, 0xc6,
- 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbc, 0x00, 0xb9, 0x00, 0xb6, 0x00, 0xb3,
- 0x00, 0xb1, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa7,
- 0x00, 0xa6, 0x00, 0xa4, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xac,
- 0x00, 0xa0, 0x00, 0x93, 0x00, 0x84, 0x00, 0x75, 0x00, 0x66, 0x00, 0x58,
- 0x00, 0x4b, 0x00, 0x3f, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x19,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00,
- 0x36, 0x00, 0x2d, 0x00, 0x21, 0x00, 0x13, 0x00, 0x04, 0x00, 0x00, 0x0a,
- 0x00, 0x18, 0x00, 0x26, 0x00, 0x33, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x54,
- 0x00, 0x5d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x45, 0x3a, 0x48, 0x37, 0x4a, 0x35, 0x4e, 0x32, 0x4f, 0x31, 0x53,
- 0x2e, 0x53, 0x2e, 0x56, 0x2b, 0x57, 0x2a, 0x58, 0x29, 0x5b, 0x27, 0x5c,
- 0x27, 0x5c, 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x61,
- 0x23, 0x64, 0x21, 0x65, 0x20, 0x26, 0x1d, 0x2a, 0x1a, 0x2d, 0x18, 0x31,
- 0x17, 0x35, 0x15, 0x38, 0x14, 0x3b, 0x13, 0x3e, 0x13, 0x41, 0x12, 0x44,
- 0x12, 0x46, 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11, 0x51,
- 0x10, 0x53, 0x10, 0x55, 0x10, 0x56, 0x10, 0x58, 0x00, 0xda, 0x00, 0xd6,
- 0x00, 0xd2, 0x00, 0xce, 0x00, 0xcb, 0x00, 0xc7, 0x00, 0xc4, 0x00, 0xc1,
- 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb3, 0x00, 0xb1,
- 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa8, 0x00, 0xa6,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99,
- 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x70, 0x00, 0x63, 0x00, 0x56, 0x00, 0x4a,
- 0x00, 0x3f, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x30, 0x00,
- 0x25, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x1c,
- 0x00, 0x28, 0x00, 0x34, 0x00, 0x3f, 0x00, 0x49, 0x00, 0x53, 0x00, 0x5b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x3a, 0x47,
- 0x38, 0x4a, 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x51, 0x2f, 0x53, 0x2e, 0x54,
- 0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x59, 0x29, 0x5c, 0x27, 0x5c, 0x27, 0x5c,
- 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x63,
- 0x20, 0x25, 0x1d, 0x29, 0x1a, 0x2d, 0x18, 0x30, 0x17, 0x33, 0x16, 0x37,
- 0x14, 0x3a, 0x13, 0x3d, 0x13, 0x3f, 0x13, 0x42, 0x12, 0x44, 0x11, 0x47,
- 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x53,
- 0x10, 0x55, 0x10, 0x56, 0x00, 0xdb, 0x00, 0xd7, 0x00, 0xd3, 0x00, 0xcf,
- 0x00, 0xcc, 0x00, 0xc8, 0x00, 0xc5, 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbc,
- 0x00, 0xba, 0x00, 0xb7, 0x00, 0xb5, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf,
- 0x00, 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa8, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd,
- 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9d, 0x00, 0x92, 0x00, 0x85,
- 0x00, 0x78, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3f,
- 0x00, 0x36, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x32, 0x00, 0x29, 0x00, 0x1e, 0x00,
- 0x12, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a,
- 0x00, 0x35, 0x00, 0x3f, 0x00, 0x49, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3d, 0x44, 0x3a, 0x47, 0x38, 0x4a, 0x35, 0x4c,
- 0x33, 0x4f, 0x31, 0x50, 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x56, 0x2b, 0x57,
- 0x2a, 0x57, 0x2a, 0x5a, 0x28, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5f,
- 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x20, 0x25, 0x1d, 0x29,
- 0x1b, 0x2c, 0x18, 0x2f, 0x17, 0x33, 0x16, 0x36, 0x14, 0x39, 0x14, 0x3b,
- 0x13, 0x3e, 0x13, 0x41, 0x12, 0x43, 0x12, 0x45, 0x11, 0x47, 0x11, 0x4a,
- 0x11, 0x4c, 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x52, 0x10, 0x54,
- 0x00, 0xdb, 0x00, 0xd7, 0x00, 0xd3, 0x00, 0xd0, 0x00, 0xcc, 0x00, 0xc9,
- 0x00, 0xc6, 0x00, 0xc3, 0x00, 0xc1, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb9,
- 0x00, 0xb7, 0x00, 0xb5, 0x00, 0xb3, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad,
- 0x00, 0xab, 0x00, 0xaa, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb3,
- 0x00, 0xab, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x74,
- 0x00, 0x68, 0x00, 0x5d, 0x00, 0x53, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00,
- 0x3a, 0x00, 0x33, 0x00, 0x2b, 0x00, 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00,
- 0x00, 0x00, 0x00, 0x0b, 0x00, 0x16, 0x00, 0x21, 0x00, 0x2c, 0x00, 0x36,
- 0x00, 0x3f, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x44, 0x3b, 0x46, 0x39, 0x4a, 0x35, 0x4b, 0x34, 0x4f, 0x31, 0x4f,
- 0x31, 0x53, 0x2e, 0x53, 0x2e, 0x54, 0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x58,
- 0x2a, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5f, 0x24, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x20, 0x25, 0x1d, 0x28, 0x1b, 0x2b, 0x19, 0x2f,
- 0x17, 0x32, 0x16, 0x35, 0x15, 0x38, 0x14, 0x3a, 0x13, 0x3d, 0x13, 0x3f,
- 0x13, 0x42, 0x12, 0x44, 0x12, 0x46, 0x11, 0x48, 0x11, 0x4a, 0x11, 0x4c,
- 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x52, 0x00, 0xdb, 0x00, 0xd7,
- 0x00, 0xd4, 0x00, 0xd0, 0x00, 0xcd, 0x00, 0xca, 0x00, 0xc7, 0x00, 0xc5,
- 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb6,
- 0x00, 0xb4, 0x00, 0xb2, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xac,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb4, 0x00, 0xad, 0x00, 0xa5,
- 0x00, 0x9b, 0x00, 0x91, 0x00, 0x86, 0x00, 0x7b, 0x00, 0x70, 0x00, 0x65,
- 0x00, 0x5b, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00,
- 0x2e, 0x00, 0x25, 0x00, 0x1c, 0x00, 0x11, 0x00, 0x07, 0x00, 0x00, 0x03,
- 0x00, 0x0e, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x3f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x44, 0x3b, 0x46,
- 0x39, 0x49, 0x36, 0x4a, 0x35, 0x4e, 0x32, 0x4f, 0x31, 0x51, 0x2f, 0x53,
- 0x2e, 0x53, 0x2e, 0x56, 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x58, 0x29, 0x5c,
- 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x26, 0x5f, 0x24, 0x60, 0x23, 0x60,
- 0x20, 0x25, 0x1d, 0x28, 0x1c, 0x2b, 0x1a, 0x2e, 0x18, 0x31, 0x17, 0x34,
- 0x16, 0x37, 0x14, 0x39, 0x13, 0x3b, 0x13, 0x3e, 0x13, 0x40, 0x12, 0x42,
- 0x12, 0x45, 0x11, 0x46, 0x11, 0x49, 0x11, 0x4a, 0x11, 0x4c, 0x11, 0x4e,
- 0x11, 0x4f, 0x11, 0x51, 0x00, 0xdb, 0x00, 0xd8, 0x00, 0xd4, 0x00, 0xd1,
- 0x00, 0xce, 0x00, 0xcb, 0x00, 0xc8, 0x00, 0xc6, 0x00, 0xc3, 0x00, 0xc1,
- 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xba, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb4,
- 0x00, 0xb2, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x56, 0x7f, 0x47, 0x63,
- 0x44, 0x57, 0x43, 0x52, 0x43, 0x4e, 0x42, 0x4c, 0x42, 0x4a, 0x42, 0x49,
- 0x42, 0x48, 0x42, 0x47, 0x42, 0x46, 0x42, 0x45, 0x42, 0x45, 0x42, 0x45,
- 0x42, 0x44, 0x42, 0x44, 0x42, 0x44, 0x42, 0x43, 0x42, 0x43, 0x42, 0x43,
- 0x4c, 0x7f, 0x27, 0x4d, 0x2f, 0x46, 0x33, 0x44, 0x36, 0x43, 0x37, 0x43,
- 0x39, 0x42, 0x3a, 0x41, 0x3a, 0x41, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x41,
- 0x3c, 0x41, 0x3c, 0x41, 0x3c, 0x41, 0x3c, 0x41, 0x3c, 0x41, 0x3d, 0x41,
- 0x3d, 0x41, 0x3d, 0x41, 0x8e, 0x7f, 0x47, 0x4d, 0x44, 0x46, 0x43, 0x44,
- 0x43, 0x43, 0x42, 0x43, 0x42, 0x42, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41,
- 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41,
- 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x0d, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x85, 0x1b, 0x60, 0x27, 0x54, 0x2d, 0x4e, 0x30,
- 0x4b, 0x33, 0x49, 0x34, 0x47, 0x35, 0x46, 0x37, 0x45, 0x38, 0x45, 0x38,
- 0x44, 0x39, 0x43, 0x39, 0x43, 0x3a, 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b,
- 0x42, 0x3b, 0x42, 0x3b, 0x42, 0x3b, 0x42, 0x3b, 0x09, 0x43, 0x16, 0x3f,
- 0x1f, 0x3e, 0x25, 0x3e, 0x29, 0x3e, 0x2c, 0x3e, 0x2f, 0x3e, 0x30, 0x3e,
- 0x32, 0x3e, 0x33, 0x3e, 0x34, 0x3e, 0x35, 0x3e, 0x36, 0x3e, 0x36, 0x3e,
- 0x37, 0x3e, 0x37, 0x3e, 0x38, 0x3e, 0x38, 0x3e, 0x38, 0x3e, 0x39, 0x3e,
- 0x59, 0x31, 0x4f, 0x38, 0x4b, 0x3a, 0x48, 0x3b, 0x47, 0x3c, 0x46, 0x3c,
- 0x45, 0x3d, 0x45, 0x3d, 0x44, 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x4c, 0x00, 0x2f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x4f, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x96, 0x05, 0x74, 0x0f, 0x63, 0x17, 0x5a, 0x1d, 0x54, 0x21, 0x51, 0x24,
- 0x4e, 0x27, 0x4c, 0x29, 0x4a, 0x2b, 0x49, 0x2d, 0x49, 0x2e, 0x48, 0x2f,
- 0x48, 0x31, 0x47, 0x31, 0x46, 0x32, 0x46, 0x33, 0x44, 0x33, 0x44, 0x34,
- 0x43, 0x34, 0x43, 0x35, 0x09, 0x43, 0x11, 0x3e, 0x18, 0x3c, 0x1d, 0x3c,
- 0x22, 0x3c, 0x25, 0x3c, 0x27, 0x3c, 0x2a, 0x3c, 0x2c, 0x3d, 0x2d, 0x3d,
- 0x2f, 0x3d, 0x30, 0x3e, 0x31, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x33, 0x3e,
- 0x33, 0x3e, 0x34, 0x3e, 0x35, 0x3e, 0x35, 0x3e, 0x5b, 0x2a, 0x53, 0x31,
- 0x4f, 0x34, 0x4c, 0x36, 0x4b, 0x38, 0x4a, 0x39, 0x48, 0x39, 0x47, 0x3a,
- 0x46, 0x3b, 0x46, 0x3b, 0x46, 0x3c, 0x46, 0x3c, 0x46, 0x3d, 0x45, 0x3d,
- 0x44, 0x3d, 0x44, 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x45,
- 0x00, 0x22, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x8f, 0x00, 0x73, 0x00, 0x38, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x9e, 0x01, 0x81, 0x06,
- 0x6f, 0x0d, 0x64, 0x12, 0x5d, 0x16, 0x58, 0x1a, 0x54, 0x1d, 0x53, 0x20,
- 0x50, 0x22, 0x4e, 0x24, 0x4c, 0x26, 0x4b, 0x27, 0x4a, 0x29, 0x49, 0x2a,
- 0x49, 0x2b, 0x49, 0x2c, 0x48, 0x2d, 0x48, 0x2e, 0x48, 0x2f, 0x47, 0x2f,
- 0x09, 0x44, 0x0f, 0x3e, 0x14, 0x3c, 0x19, 0x3c, 0x1d, 0x3b, 0x20, 0x3b,
- 0x23, 0x3b, 0x25, 0x3c, 0x27, 0x3c, 0x28, 0x3c, 0x2a, 0x3b, 0x2c, 0x3b,
- 0x2c, 0x3b, 0x2d, 0x3b, 0x2f, 0x3c, 0x2f, 0x3c, 0x30, 0x3d, 0x31, 0x3e,
- 0x32, 0x3e, 0x32, 0x3e, 0x5c, 0x28, 0x56, 0x2d, 0x52, 0x31, 0x4f, 0x33,
- 0x4e, 0x35, 0x4b, 0x36, 0x4a, 0x37, 0x4a, 0x38, 0x49, 0x39, 0x47, 0x39,
- 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x3a, 0x46, 0x3a, 0x46, 0x3b,
- 0x46, 0x3c, 0x46, 0x3c, 0x46, 0x3d, 0x45, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x19,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x84, 0x00,
- 0x5b, 0x00, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0xa4, 0x00, 0x8a, 0x03, 0x78, 0x07, 0x6d, 0x0c,
- 0x65, 0x10, 0x60, 0x13, 0x5b, 0x16, 0x57, 0x19, 0x55, 0x1b, 0x53, 0x1e,
- 0x52, 0x1f, 0x4f, 0x22, 0x4d, 0x23, 0x4c, 0x24, 0x4b, 0x25, 0x4b, 0x27,
- 0x4a, 0x28, 0x49, 0x29, 0x49, 0x29, 0x49, 0x2b, 0x09, 0x45, 0x0d, 0x40,
- 0x11, 0x3d, 0x16, 0x3c, 0x19, 0x3b, 0x1d, 0x3b, 0x1f, 0x3b, 0x21, 0x3a,
- 0x23, 0x3b, 0x25, 0x3b, 0x26, 0x3c, 0x28, 0x3c, 0x29, 0x3c, 0x2a, 0x3b,
- 0x2b, 0x3b, 0x2c, 0x3b, 0x2d, 0x3b, 0x2e, 0x3b, 0x2e, 0x3b, 0x2f, 0x3b,
- 0x5d, 0x27, 0x57, 0x2c, 0x54, 0x2f, 0x52, 0x31, 0x4f, 0x32, 0x4e, 0x34,
- 0x4c, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x37, 0x4a, 0x38, 0x48, 0x39,
- 0x47, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39,
- 0x46, 0x39, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x5b, 0x00, 0x55, 0x00, 0x42, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x8d, 0x00, 0x6f, 0x00, 0x48, 0x00,
- 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0xa7, 0x00, 0x91, 0x01, 0x80, 0x04, 0x75, 0x08, 0x6c, 0x0b, 0x65, 0x0e,
- 0x61, 0x11, 0x5d, 0x14, 0x59, 0x16, 0x56, 0x19, 0x55, 0x1a, 0x54, 0x1c,
- 0x53, 0x1e, 0x51, 0x1f, 0x4f, 0x21, 0x4d, 0x22, 0x4c, 0x23, 0x4b, 0x24,
- 0x4b, 0x25, 0x4b, 0x26, 0x09, 0x45, 0x0d, 0x41, 0x10, 0x3e, 0x14, 0x3d,
- 0x17, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1e, 0x3b, 0x20, 0x3b, 0x22, 0x3a,
- 0x23, 0x3a, 0x25, 0x3b, 0x26, 0x3c, 0x28, 0x3c, 0x28, 0x3c, 0x29, 0x3c,
- 0x2a, 0x3c, 0x2b, 0x3b, 0x2c, 0x3b, 0x2d, 0x3b, 0x5d, 0x26, 0x59, 0x2a,
- 0x56, 0x2d, 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x32, 0x4f, 0x33, 0x4d, 0x35,
- 0x4b, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x37, 0x4a, 0x38, 0x49, 0x39,
- 0x48, 0x39, 0x47, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58,
- 0x00, 0x4a, 0x00, 0x38, 0x00, 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9b, 0x00, 0x92, 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xa9, 0x00, 0x96, 0x00,
- 0x86, 0x02, 0x7a, 0x05, 0x72, 0x08, 0x6b, 0x0b, 0x65, 0x0e, 0x62, 0x10,
- 0x5f, 0x12, 0x5b, 0x14, 0x58, 0x16, 0x56, 0x18, 0x55, 0x1a, 0x54, 0x1b,
- 0x53, 0x1d, 0x52, 0x1e, 0x50, 0x1f, 0x4f, 0x20, 0x4d, 0x21, 0x4c, 0x22,
- 0x09, 0x46, 0x0c, 0x41, 0x0f, 0x3f, 0x12, 0x3d, 0x15, 0x3c, 0x17, 0x3c,
- 0x1a, 0x3b, 0x1c, 0x3a, 0x1e, 0x3b, 0x1f, 0x3b, 0x21, 0x3a, 0x22, 0x3a,
- 0x24, 0x3a, 0x25, 0x3a, 0x26, 0x3b, 0x27, 0x3c, 0x28, 0x3c, 0x29, 0x3c,
- 0x2a, 0x3c, 0x2a, 0x3c, 0x5e, 0x26, 0x5a, 0x29, 0x57, 0x2c, 0x53, 0x2e,
- 0x53, 0x30, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x33, 0x4e, 0x34, 0x4c, 0x35,
- 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x37, 0x4a, 0x38,
- 0x48, 0x39, 0x47, 0x39, 0x46, 0x39, 0x46, 0x39, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40,
- 0x00, 0x2f, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x95, 0x00,
- 0x84, 0x00, 0x6c, 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0xab, 0x00, 0x9a, 0x00, 0x8b, 0x01, 0x7f, 0x03,
- 0x77, 0x06, 0x71, 0x08, 0x6a, 0x0b, 0x66, 0x0d, 0x63, 0x0f, 0x60, 0x11,
- 0x5d, 0x13, 0x59, 0x14, 0x57, 0x16, 0x56, 0x18, 0x55, 0x19, 0x54, 0x1b,
- 0x53, 0x1c, 0x53, 0x1d, 0x51, 0x1e, 0x50, 0x1f, 0x0a, 0x46, 0x0c, 0x42,
- 0x0e, 0x3f, 0x11, 0x3f, 0x13, 0x3c, 0x16, 0x3c, 0x18, 0x3c, 0x1a, 0x3b,
- 0x1c, 0x3a, 0x1e, 0x3b, 0x1f, 0x3b, 0x20, 0x3b, 0x21, 0x3a, 0x23, 0x3a,
- 0x24, 0x3a, 0x25, 0x39, 0x26, 0x3a, 0x27, 0x3c, 0x27, 0x3c, 0x28, 0x3c,
- 0x5e, 0x26, 0x5a, 0x29, 0x57, 0x2b, 0x55, 0x2d, 0x53, 0x2e, 0x53, 0x30,
- 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x32, 0x4f, 0x34, 0x4d, 0x35, 0x4b, 0x35,
- 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x38,
- 0x4a, 0x39, 0x48, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29,
- 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76, 0x00,
- 0x5e, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0xac, 0x00, 0x9d, 0x00, 0x8f, 0x01, 0x85, 0x02, 0x7b, 0x04, 0x75, 0x06,
- 0x6f, 0x08, 0x69, 0x0b, 0x66, 0x0d, 0x63, 0x0e, 0x61, 0x10, 0x5e, 0x12,
- 0x5b, 0x13, 0x58, 0x15, 0x57, 0x16, 0x56, 0x18, 0x55, 0x19, 0x55, 0x1a,
- 0x54, 0x1b, 0x53, 0x1c, 0x0a, 0x47, 0x0b, 0x42, 0x0e, 0x40, 0x10, 0x3f,
- 0x12, 0x3d, 0x15, 0x3c, 0x17, 0x3c, 0x18, 0x3c, 0x1a, 0x3b, 0x1c, 0x3a,
- 0x1d, 0x3b, 0x1f, 0x3b, 0x20, 0x3b, 0x21, 0x3b, 0x22, 0x3a, 0x23, 0x3a,
- 0x24, 0x3a, 0x25, 0x39, 0x26, 0x3a, 0x27, 0x3b, 0x5e, 0x26, 0x5b, 0x28,
- 0x57, 0x2a, 0x57, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x33, 0x4e, 0x35, 0x4b, 0x35, 0x4a, 0x35,
- 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x37,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c,
- 0x00, 0x55, 0x00, 0x4b, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17,
- 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53, 0x00,
- 0x3c, 0x00, 0x26, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xad, 0x00, 0xa0, 0x00,
- 0x92, 0x00, 0x89, 0x02, 0x7f, 0x03, 0x78, 0x05, 0x73, 0x07, 0x6e, 0x09,
- 0x69, 0x0b, 0x66, 0x0c, 0x64, 0x0e, 0x62, 0x0f, 0x60, 0x11, 0x5c, 0x12,
- 0x59, 0x14, 0x58, 0x15, 0x57, 0x16, 0x56, 0x18, 0x55, 0x18, 0x55, 0x1a,
- 0x0a, 0x47, 0x0b, 0x43, 0x0d, 0x41, 0x0f, 0x3f, 0x11, 0x3f, 0x13, 0x3c,
- 0x15, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x1a, 0x3b, 0x1c, 0x3a, 0x1d, 0x3a,
- 0x1f, 0x3b, 0x1f, 0x3b, 0x21, 0x3b, 0x21, 0x3b, 0x22, 0x3a, 0x24, 0x3a,
- 0x24, 0x3a, 0x24, 0x39, 0x5e, 0x26, 0x5c, 0x27, 0x58, 0x2a, 0x57, 0x2b,
- 0x55, 0x2e, 0x53, 0x2e, 0x53, 0x2f, 0x52, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x32, 0x4e, 0x34, 0x4c, 0x35, 0x4a, 0x35, 0x4a, 0x35,
- 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f,
- 0x00, 0x44, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00,
- 0x91, 0x00, 0x83, 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36, 0x00,
- 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0xae, 0x00, 0xa2, 0x00, 0x95, 0x00, 0x8b, 0x01,
- 0x83, 0x02, 0x7b, 0x04, 0x76, 0x05, 0x73, 0x07, 0x6e, 0x09, 0x69, 0x0a,
- 0x66, 0x0c, 0x64, 0x0d, 0x62, 0x0f, 0x61, 0x10, 0x5e, 0x11, 0x5b, 0x13,
- 0x58, 0x14, 0x58, 0x15, 0x56, 0x16, 0x56, 0x18, 0x0a, 0x47, 0x0b, 0x43,
- 0x0d, 0x42, 0x0f, 0x3f, 0x11, 0x3f, 0x12, 0x3e, 0x14, 0x3c, 0x16, 0x3c,
- 0x17, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3a, 0x1d, 0x39, 0x1f, 0x3b,
- 0x1f, 0x3b, 0x20, 0x3b, 0x21, 0x3b, 0x21, 0x3a, 0x22, 0x3a, 0x24, 0x3a,
- 0x5e, 0x26, 0x5c, 0x27, 0x59, 0x2a, 0x57, 0x2a, 0x56, 0x2c, 0x53, 0x2e,
- 0x53, 0x2e, 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0x4f, 0x32, 0x4f, 0x33, 0x4d, 0x35, 0x4b, 0x35, 0x4a, 0x35, 0x4a, 0x35,
- 0x4a, 0x35, 0x4a, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e,
- 0x00, 0x33, 0x00, 0x28, 0x00, 0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88, 0x00,
- 0x79, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00,
- 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0xaf, 0x00, 0xa3, 0x00, 0x98, 0x00, 0x8e, 0x00, 0x87, 0x02, 0x7f, 0x03,
- 0x79, 0x04, 0x75, 0x06, 0x71, 0x07, 0x6c, 0x09, 0x68, 0x0a, 0x66, 0x0c,
- 0x64, 0x0d, 0x63, 0x0e, 0x61, 0x10, 0x5f, 0x11, 0x5c, 0x12, 0x59, 0x13,
- 0x58, 0x14, 0x58, 0x15, 0x0a, 0x47, 0x0b, 0x43, 0x0d, 0x42, 0x0e, 0x40,
- 0x10, 0x3e, 0x11, 0x3f, 0x13, 0x3c, 0x15, 0x3b, 0x17, 0x3c, 0x17, 0x3c,
- 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x39, 0x1e, 0x3a, 0x1f, 0x3b,
- 0x1f, 0x3b, 0x21, 0x3b, 0x21, 0x3b, 0x22, 0x3a, 0x5e, 0x25, 0x5c, 0x27,
- 0x5a, 0x29, 0x57, 0x2a, 0x57, 0x2b, 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
- 0x53, 0x2f, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0x4f, 0x33, 0x4e, 0x34, 0x4c, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d,
- 0x00, 0x59, 0x00, 0x53, 0x00, 0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e,
- 0x00, 0x24, 0x00, 0x1a, 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9e, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f, 0x00,
- 0x5f, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xaf, 0x00, 0xa5, 0x00,
- 0x9a, 0x00, 0x90, 0x00, 0x8a, 0x01, 0x83, 0x02, 0x7c, 0x03, 0x77, 0x05,
- 0x74, 0x06, 0x70, 0x07, 0x6c, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x64, 0x0c,
- 0x63, 0x0e, 0x61, 0x0f, 0x60, 0x11, 0x5d, 0x11, 0x5b, 0x13, 0x59, 0x13,
- 0x0a, 0x47, 0x0a, 0x44, 0x0d, 0x42, 0x0e, 0x41, 0x0f, 0x3e, 0x11, 0x3f,
- 0x13, 0x3e, 0x14, 0x3c, 0x15, 0x3a, 0x17, 0x3c, 0x17, 0x3c, 0x19, 0x3c,
- 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x39, 0x1e, 0x3a, 0x1f, 0x3b, 0x1f, 0x3b,
- 0x20, 0x3b, 0x21, 0x3b, 0x5e, 0x25, 0x5c, 0x27, 0x5a, 0x29, 0x57, 0x2a,
- 0x57, 0x2a, 0x56, 0x2d, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x30,
- 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x32,
- 0x4f, 0x33, 0x4d, 0x35, 0x4b, 0x35, 0x4a, 0x35, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55,
- 0x00, 0x4e, 0x00, 0x46, 0x00, 0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21,
- 0x00, 0x18, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
- 0x97, 0x00, 0x8e, 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57, 0x00,
- 0x47, 0x00, 0x37, 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0xb0, 0x00, 0xa6, 0x00, 0x9d, 0x00, 0x92, 0x00,
- 0x8c, 0x01, 0x86, 0x02, 0x7e, 0x02, 0x7a, 0x04, 0x76, 0x05, 0x73, 0x06,
- 0x70, 0x07, 0x6b, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c, 0x63, 0x0e,
- 0x62, 0x0e, 0x61, 0x10, 0x5e, 0x11, 0x5c, 0x12, 0x0a, 0x47, 0x0a, 0x44,
- 0x0c, 0x42, 0x0d, 0x41, 0x0f, 0x3f, 0x11, 0x3f, 0x11, 0x3f, 0x13, 0x3d,
- 0x15, 0x3c, 0x16, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x1a, 0x3b,
- 0x1c, 0x3b, 0x1c, 0x39, 0x1e, 0x39, 0x1f, 0x3b, 0x1f, 0x3b, 0x1f, 0x3b,
- 0x5f, 0x25, 0x5c, 0x27, 0x5b, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2b,
- 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x33,
- 0x4e, 0x34, 0x4c, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49,
- 0x00, 0x41, 0x00, 0x39, 0x00, 0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16,
- 0x00, 0x0e, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90, 0x00,
- 0x86, 0x00, 0x7a, 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41, 0x00,
- 0x33, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0xb0, 0x00, 0xa7, 0x00, 0x9f, 0x00, 0x95, 0x00, 0x8e, 0x00, 0x88, 0x01,
- 0x82, 0x02, 0x7c, 0x03, 0x78, 0x05, 0x75, 0x06, 0x72, 0x07, 0x6f, 0x08,
- 0x6a, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c, 0x63, 0x0d, 0x62, 0x0e,
- 0x61, 0x0f, 0x60, 0x11, 0x0a, 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0d, 0x42,
- 0x0e, 0x40, 0x10, 0x3d, 0x11, 0x3f, 0x13, 0x3e, 0x14, 0x3c, 0x15, 0x3b,
- 0x17, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b,
- 0x1c, 0x3a, 0x1d, 0x39, 0x1f, 0x3a, 0x1f, 0x3b, 0x5f, 0x25, 0x5c, 0x27,
- 0x5c, 0x27, 0x58, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x2d, 0x53, 0x2e,
- 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x32, 0x4f, 0x34,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e,
- 0x00, 0x5b, 0x00, 0x57, 0x00, 0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d,
- 0x00, 0x35, 0x00, 0x2c, 0x00, 0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d,
- 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00,
- 0x72, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f, 0x00,
- 0x22, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xb1, 0x00, 0xa7, 0x00,
- 0xa0, 0x00, 0x97, 0x00, 0x90, 0x00, 0x8a, 0x01, 0x85, 0x02, 0x7e, 0x02,
- 0x7a, 0x03, 0x77, 0x05, 0x74, 0x06, 0x72, 0x07, 0x6e, 0x08, 0x6a, 0x09,
- 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c, 0x63, 0x0d, 0x63, 0x0e, 0x61, 0x0f,
- 0x0a, 0x47, 0x0a, 0x45, 0x0b, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x0f, 0x3e,
- 0x11, 0x3f, 0x12, 0x3f, 0x13, 0x3d, 0x15, 0x3c, 0x15, 0x3a, 0x17, 0x3c,
- 0x17, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x3a,
- 0x1d, 0x39, 0x1f, 0x39, 0x5f, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x59, 0x2a,
- 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
- 0x53, 0x2e, 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x00, 0x17, 0x00, 0x2f,
- 0x00, 0x4c, 0x00, 0x56, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5d, 0x00, 0x5d,
- 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f,
- 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x6c, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x62,
- 0x00, 0x62, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e,
- 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x14, 0x01, 0x29,
- 0x00, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d,
- 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e,
- 0x00, 0x5f, 0x00, 0x5f, 0x31, 0x11, 0x03, 0x23, 0x00, 0x46, 0x00, 0x52,
- 0x00, 0x58, 0x00, 0x5a, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e,
- 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0xb1, 0x00, 0xa8, 0x00, 0xa1, 0x00, 0x99, 0x00,
- 0x91, 0x00, 0x8c, 0x00, 0x88, 0x01, 0x82, 0x02, 0x7c, 0x03, 0x79, 0x04,
- 0x76, 0x05, 0x74, 0x06, 0x71, 0x07, 0x6d, 0x08, 0x6a, 0x09, 0x68, 0x0a,
- 0x66, 0x0b, 0x65, 0x0c, 0x64, 0x0c, 0x63, 0x0e, 0x0a, 0x47, 0x0a, 0x45,
- 0x0b, 0x42, 0x0d, 0x42, 0x0e, 0x41, 0x0f, 0x3f, 0x11, 0x3e, 0x11, 0x3f,
- 0x13, 0x3e, 0x13, 0x3c, 0x15, 0x3c, 0x16, 0x3a, 0x17, 0x3c, 0x17, 0x3c,
- 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x3a, 0x1d, 0x39,
- 0x5f, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5a, 0x29, 0x57, 0x2a, 0x57, 0x2a,
- 0x57, 0x2a, 0x55, 0x2d, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
- 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x2f, 0x00, 0x45,
- 0x00, 0x4f, 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c,
- 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e,
- 0x00, 0x4c, 0x00, 0x3b, 0x00, 0x48, 0x00, 0x55, 0x00, 0x58, 0x00, 0x57,
- 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d,
- 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x16, 0x04, 0x00, 0x27, 0x00, 0x41,
- 0x00, 0x4d, 0x00, 0x53, 0x00, 0x56, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b,
- 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e,
- 0x5f, 0x00, 0x20, 0x00, 0x00, 0x1f, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x51,
- 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5c,
- 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0xb1, 0x00, 0xa9, 0x00, 0xa2, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x8e, 0x00,
- 0x89, 0x01, 0x84, 0x02, 0x7e, 0x02, 0x7a, 0x03, 0x78, 0x05, 0x75, 0x05,
- 0x73, 0x06, 0x71, 0x07, 0x6c, 0x08, 0x69, 0x09, 0x68, 0x0a, 0x66, 0x0b,
- 0x65, 0x0c, 0x64, 0x0c, 0x0a, 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x42,
- 0x0e, 0x42, 0x0f, 0x40, 0x10, 0x3d, 0x11, 0x3f, 0x12, 0x3f, 0x13, 0x3d,
- 0x15, 0x3c, 0x15, 0x3b, 0x17, 0x3a, 0x17, 0x3c, 0x17, 0x3c, 0x19, 0x3c,
- 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x3b, 0x5f, 0x25, 0x5c, 0x27,
- 0x5c, 0x27, 0x5b, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2c,
- 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x30,
- 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x22, 0x00, 0x36, 0x00, 0x42,
- 0x00, 0x4a, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58,
- 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5f, 0x00, 0x48,
- 0x00, 0x1b, 0x00, 0x34, 0x00, 0x40, 0x00, 0x44, 0x00, 0x4a, 0x00, 0x4f,
- 0x00, 0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a,
- 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x82, 0x00, 0x57, 0x00, 0x12, 0x01, 0x00, 0x17, 0x00, 0x2f, 0x00, 0x3e,
- 0x00, 0x47, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x53, 0x00, 0x56, 0x00, 0x57,
- 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x85, 0x00, 0x5f, 0x00,
- 0x1f, 0x00, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4a,
- 0x00, 0x4e, 0x00, 0x52, 0x00, 0x54, 0x00, 0x56, 0x00, 0x57, 0x00, 0x59,
- 0x00, 0x59, 0x00, 0x5a, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xb2, 0x00, 0xa9, 0x00,
- 0xa3, 0x00, 0x9d, 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8b, 0x01, 0x87, 0x02,
- 0x81, 0x02, 0x7c, 0x03, 0x79, 0x03, 0x77, 0x05, 0x75, 0x06, 0x72, 0x06,
- 0x70, 0x07, 0x6c, 0x08, 0x69, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c,
- 0x0a, 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x42, 0x0d, 0x42, 0x0e, 0x40,
- 0x0f, 0x3e, 0x11, 0x3e, 0x11, 0x3f, 0x13, 0x3f, 0x13, 0x3c, 0x15, 0x3c,
- 0x15, 0x3a, 0x17, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x19, 0x3c,
- 0x1a, 0x3b, 0x1c, 0x3b, 0x5f, 0x24, 0x5c, 0x27, 0x5c, 0x27, 0x5b, 0x28,
- 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2b, 0x55, 0x2e, 0x53, 0x2e,
- 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x50, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x19, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40,
- 0x00, 0x47, 0x00, 0x4b, 0x00, 0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55,
- 0x00, 0x56, 0x00, 0x57, 0x00, 0x62, 0x00, 0x55, 0x00, 0x34, 0x00, 0x0b,
- 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40, 0x00, 0x47, 0x00, 0x4b,
- 0x00, 0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x78, 0x00,
- 0x43, 0x00, 0x10, 0x00, 0x00, 0x0e, 0x00, 0x23, 0x00, 0x31, 0x00, 0x3b,
- 0x00, 0x42, 0x00, 0x48, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x51, 0x00, 0x53,
- 0x00, 0x55, 0x00, 0x56, 0x92, 0x00, 0x7c, 0x00, 0x4d, 0x00, 0x1f, 0x00,
- 0x00, 0x02, 0x00, 0x1a, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x3e, 0x00, 0x45,
- 0x00, 0x49, 0x00, 0x4d, 0x00, 0x4f, 0x00, 0x52, 0x00, 0x53, 0x00, 0x55,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0xb2, 0x00, 0xaa, 0x00, 0xa4, 0x00, 0x9e, 0x00,
- 0x96, 0x00, 0x90, 0x00, 0x8c, 0x00, 0x88, 0x01, 0x84, 0x02, 0x7e, 0x02,
- 0x7b, 0x03, 0x78, 0x04, 0x76, 0x05, 0x74, 0x06, 0x72, 0x07, 0x6f, 0x07,
- 0x6b, 0x09, 0x69, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x0a, 0x47, 0x0a, 0x46,
- 0x0b, 0x44, 0x0d, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x0f, 0x3f, 0x10, 0x3d,
- 0x11, 0x3f, 0x12, 0x3f, 0x13, 0x3e, 0x14, 0x3c, 0x15, 0x3c, 0x16, 0x3a,
- 0x17, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3b,
- 0x5f, 0x24, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x58, 0x2a, 0x57, 0x2a,
- 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
- 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x4f, 0x31, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x14, 0x00, 0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f,
- 0x00, 0x44, 0x00, 0x48, 0x00, 0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52,
- 0x00, 0x62, 0x00, 0x58, 0x00, 0x40, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x14,
- 0x00, 0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f, 0x00, 0x44, 0x00, 0x48,
- 0x00, 0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x87, 0x00, 0x61, 0x00, 0x36, 0x00,
- 0x10, 0x00, 0x02, 0x0a, 0x00, 0x1a, 0x00, 0x27, 0x00, 0x32, 0x00, 0x3a,
- 0x00, 0x40, 0x00, 0x44, 0x00, 0x48, 0x00, 0x4b, 0x00, 0x4e, 0x00, 0x50,
- 0x97, 0x00, 0x8a, 0x00, 0x68, 0x00, 0x42, 0x00, 0x1f, 0x00, 0x04, 0x00,
- 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x41,
- 0x00, 0x45, 0x00, 0x49, 0x00, 0x4b, 0x00, 0x4e, 0x28, 0x3c, 0x16, 0x41,
- 0x11, 0x43, 0x0f, 0x44, 0x0e, 0x45, 0x0d, 0x46, 0x0c, 0x46, 0x0c, 0x46,
- 0x0b, 0x47, 0x0b, 0x47, 0x0b, 0x47, 0x0b, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x6e, 0x1c, 0x3a, 0x29, 0x27, 0x31, 0x1e, 0x36, 0x19, 0x3a, 0x17, 0x3b,
- 0x14, 0x3d, 0x13, 0x3f, 0x11, 0x40, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x42,
- 0x0f, 0x43, 0x0f, 0x43, 0x0e, 0x43, 0x0e, 0x44, 0x0d, 0x44, 0x0d, 0x44,
- 0x0c, 0x44, 0x0c, 0x44, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x3c, 0x32, 0x22, 0x38,
- 0x18, 0x3c, 0x14, 0x3f, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x42, 0x0e, 0x43,
- 0x0e, 0x44, 0x0d, 0x44, 0x0d, 0x44, 0x0c, 0x44, 0x0c, 0x45, 0x0c, 0x45,
- 0x0c, 0x45, 0x0c, 0x45, 0x0b, 0x45, 0x0b, 0x45, 0x0b, 0x46, 0x0b, 0x46,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x10, 0x00, 0x1e, 0x00, 0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e,
- 0x00, 0x42, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x57,
- 0x00, 0x44, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1e,
- 0x00, 0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x46,
- 0x00, 0x49, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x99, 0x00, 0x8f, 0x00, 0x74, 0x00, 0x51, 0x00, 0x2e, 0x00, 0x10, 0x00,
- 0x04, 0x08, 0x00, 0x13, 0x00, 0x20, 0x00, 0x2a, 0x00, 0x32, 0x00, 0x38,
- 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x48, 0x9a, 0x00, 0x91, 0x00,
- 0x79, 0x00, 0x5a, 0x00, 0x3b, 0x00, 0x1f, 0x00, 0x09, 0x00, 0x00, 0x08,
- 0x00, 0x17, 0x00, 0x22, 0x00, 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3e,
- 0x00, 0x42, 0x00, 0x45, 0x30, 0x38, 0x20, 0x3a, 0x18, 0x3d, 0x14, 0x3e,
- 0x12, 0x40, 0x10, 0x41, 0x0f, 0x42, 0x0e, 0x42, 0x0e, 0x42, 0x0d, 0x43,
- 0x0d, 0x43, 0x0d, 0x44, 0x0d, 0x44, 0x0c, 0x45, 0x0c, 0x45, 0x0b, 0x45,
- 0x0b, 0x46, 0x0b, 0x46, 0x0b, 0x46, 0x0b, 0x47, 0x8a, 0x03, 0x59, 0x0f,
- 0x40, 0x18, 0x32, 0x1f, 0x2a, 0x24, 0x24, 0x28, 0x20, 0x2c, 0x1c, 0x2f,
- 0x1b, 0x31, 0x18, 0x33, 0x17, 0x34, 0x16, 0x36, 0x15, 0x37, 0x14, 0x38,
- 0x13, 0x39, 0x12, 0x3a, 0x12, 0x3a, 0x12, 0x3b, 0x11, 0x3c, 0x10, 0x3c,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x4a, 0x25, 0x31, 0x2b, 0x25, 0x30, 0x1e, 0x33,
- 0x1a, 0x36, 0x17, 0x38, 0x15, 0x39, 0x13, 0x3b, 0x12, 0x3c, 0x11, 0x3d,
- 0x10, 0x3e, 0x10, 0x3f, 0x0f, 0x3f, 0x0f, 0x40, 0x0e, 0x40, 0x0e, 0x40,
- 0x0e, 0x41, 0x0e, 0x41, 0x0d, 0x42, 0x0d, 0x42, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
- 0x00, 0x1a, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d,
- 0x00, 0x41, 0x00, 0x44, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x38,
- 0x00, 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24,
- 0x00, 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x41, 0x00, 0x44,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x94, 0x00,
- 0x7f, 0x00, 0x64, 0x00, 0x46, 0x00, 0x29, 0x00, 0x10, 0x00, 0x06, 0x07,
- 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32, 0x00, 0x38,
- 0x00, 0x3c, 0x00, 0x40, 0x9b, 0x00, 0x95, 0x00, 0x83, 0x00, 0x6a, 0x00,
- 0x4f, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x10,
- 0x00, 0x1b, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32, 0x00, 0x37, 0x00, 0x3c,
- 0x34, 0x38, 0x25, 0x39, 0x1e, 0x3b, 0x19, 0x3c, 0x16, 0x3d, 0x14, 0x3d,
- 0x13, 0x3f, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x41, 0x0f, 0x42, 0x0e, 0x42,
- 0x0e, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x43, 0x0d, 0x43,
- 0x0d, 0x44, 0x0d, 0x44, 0x97, 0x00, 0x6c, 0x06, 0x52, 0x0d, 0x43, 0x12,
- 0x38, 0x18, 0x30, 0x1c, 0x2a, 0x20, 0x27, 0x23, 0x23, 0x26, 0x20, 0x28,
- 0x1e, 0x2a, 0x1c, 0x2c, 0x1b, 0x2e, 0x19, 0x2f, 0x18, 0x31, 0x17, 0x32,
- 0x16, 0x33, 0x16, 0x34, 0x16, 0x35, 0x15, 0x35, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x50, 0x24, 0x3b, 0x27, 0x2e, 0x2a, 0x26, 0x2d, 0x21, 0x2f, 0x1d, 0x32,
- 0x1a, 0x33, 0x18, 0x35, 0x16, 0x36, 0x15, 0x38, 0x14, 0x39, 0x13, 0x3a,
- 0x12, 0x3a, 0x11, 0x3b, 0x11, 0x3c, 0x11, 0x3c, 0x10, 0x3d, 0x10, 0x3e,
- 0x10, 0x3e, 0x0f, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17,
- 0x00, 0x20, 0x00, 0x28, 0x00, 0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d,
- 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e,
- 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x20, 0x00, 0x28,
- 0x00, 0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x87, 0x00, 0x71, 0x00,
- 0x57, 0x00, 0x3d, 0x00, 0x25, 0x00, 0x10, 0x00, 0x07, 0x06, 0x00, 0x0b,
- 0x00, 0x15, 0x00, 0x1f, 0x00, 0x26, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x37,
- 0x9c, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x48, 0x00,
- 0x33, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15,
- 0x00, 0x1e, 0x00, 0x25, 0x00, 0x2c, 0x00, 0x31, 0x36, 0x39, 0x2a, 0x39,
- 0x22, 0x39, 0x1d, 0x3a, 0x1a, 0x3b, 0x17, 0x3d, 0x15, 0x3d, 0x13, 0x3d,
- 0x13, 0x3e, 0x12, 0x3f, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x41, 0x0f, 0x42,
- 0x0e, 0x41, 0x0e, 0x42, 0x0e, 0x42, 0x0e, 0x41, 0x0e, 0x42, 0x0d, 0x42,
- 0x9e, 0x00, 0x79, 0x02, 0x61, 0x07, 0x50, 0x0b, 0x44, 0x10, 0x3b, 0x14,
- 0x34, 0x18, 0x2f, 0x1b, 0x2b, 0x1e, 0x28, 0x20, 0x25, 0x23, 0x23, 0x25,
- 0x21, 0x27, 0x1f, 0x28, 0x1d, 0x2a, 0x1c, 0x2b, 0x1b, 0x2c, 0x19, 0x2e,
- 0x19, 0x2f, 0x19, 0x30, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x54, 0x23, 0x42, 0x25,
- 0x35, 0x27, 0x2d, 0x29, 0x27, 0x2c, 0x22, 0x2e, 0x1f, 0x2f, 0x1c, 0x31,
- 0x1a, 0x33, 0x19, 0x34, 0x17, 0x35, 0x16, 0x36, 0x15, 0x37, 0x14, 0x38,
- 0x13, 0x38, 0x13, 0x39, 0x12, 0x3a, 0x11, 0x3a, 0x11, 0x3b, 0x11, 0x3c,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d,
- 0x00, 0x24, 0x00, 0x2a, 0x00, 0x30, 0x00, 0x35, 0x00, 0x5e, 0x00, 0x5b,
- 0x00, 0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29, 0x00, 0x1a, 0x00, 0x0c,
- 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d, 0x00, 0x24, 0x00, 0x2a,
- 0x00, 0x30, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9d, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00,
- 0x37, 0x00, 0x22, 0x00, 0x10, 0x00, 0x08, 0x05, 0x02, 0x0a, 0x00, 0x12,
- 0x00, 0x1a, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2d, 0x9d, 0x00, 0x99, 0x00,
- 0x8e, 0x00, 0x7e, 0x00, 0x6b, 0x00, 0x57, 0x00, 0x43, 0x00, 0x30, 0x00,
- 0x1f, 0x00, 0x11, 0x00, 0x04, 0x00, 0x00, 0x07, 0x00, 0x10, 0x00, 0x19,
- 0x00, 0x20, 0x00, 0x26, 0x38, 0x39, 0x2d, 0x39, 0x25, 0x39, 0x20, 0x3a,
- 0x1d, 0x3b, 0x1a, 0x3b, 0x18, 0x3c, 0x16, 0x3d, 0x14, 0x3d, 0x13, 0x3d,
- 0x13, 0x3d, 0x12, 0x3e, 0x11, 0x3f, 0x11, 0x40, 0x10, 0x40, 0x0f, 0x41,
- 0x0f, 0x42, 0x0f, 0x42, 0x0e, 0x42, 0x0e, 0x42, 0xa2, 0x00, 0x84, 0x00,
- 0x6c, 0x04, 0x5a, 0x07, 0x4e, 0x0b, 0x45, 0x0f, 0x3e, 0x12, 0x38, 0x15,
- 0x32, 0x18, 0x2f, 0x1a, 0x2c, 0x1d, 0x29, 0x1f, 0x26, 0x21, 0x24, 0x22,
- 0x22, 0x24, 0x21, 0x26, 0x1f, 0x27, 0x1e, 0x28, 0x1d, 0x2a, 0x1c, 0x2b,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x56, 0x23, 0x47, 0x24, 0x3b, 0x25, 0x32, 0x27,
- 0x2c, 0x29, 0x27, 0x2b, 0x24, 0x2d, 0x21, 0x2e, 0x1e, 0x30, 0x1c, 0x31,
- 0x1b, 0x32, 0x19, 0x33, 0x18, 0x34, 0x17, 0x35, 0x16, 0x36, 0x15, 0x37,
- 0x14, 0x37, 0x14, 0x38, 0x13, 0x38, 0x13, 0x39, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21,
- 0x00, 0x27, 0x00, 0x2c, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x4b,
- 0x00, 0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00,
- 0x00, 0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2c,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00,
- 0x90, 0x00, 0x81, 0x00, 0x6f, 0x00, 0x5b, 0x00, 0x46, 0x00, 0x32, 0x00,
- 0x20, 0x00, 0x10, 0x00, 0x09, 0x04, 0x03, 0x09, 0x00, 0x0f, 0x00, 0x17,
- 0x00, 0x1e, 0x00, 0x24, 0x9d, 0x00, 0x9a, 0x00, 0x92, 0x00, 0x84, 0x00,
- 0x74, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x1f, 0x00,
- 0x12, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x1b,
- 0x39, 0x3a, 0x2f, 0x39, 0x28, 0x39, 0x23, 0x39, 0x20, 0x3a, 0x1c, 0x3b,
- 0x1a, 0x3a, 0x18, 0x3b, 0x17, 0x3c, 0x15, 0x3e, 0x14, 0x3e, 0x13, 0x3d,
- 0x13, 0x3d, 0x12, 0x3d, 0x11, 0x3e, 0x11, 0x3f, 0x11, 0x40, 0x10, 0x40,
- 0x0f, 0x40, 0x0f, 0x41, 0xa6, 0x00, 0x8b, 0x00, 0x75, 0x02, 0x63, 0x05,
- 0x57, 0x07, 0x4d, 0x0b, 0x45, 0x0e, 0x3e, 0x11, 0x39, 0x13, 0x35, 0x16,
- 0x32, 0x18, 0x2e, 0x1a, 0x2c, 0x1c, 0x29, 0x1d, 0x27, 0x1f, 0x26, 0x22,
- 0x24, 0x22, 0x21, 0x23, 0x21, 0x25, 0x20, 0x26, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x58, 0x23, 0x4a, 0x23, 0x3f, 0x24, 0x36, 0x26, 0x30, 0x27, 0x2b, 0x29,
- 0x27, 0x2a, 0x24, 0x2c, 0x22, 0x2d, 0x20, 0x2e, 0x1e, 0x30, 0x1c, 0x30,
- 0x1b, 0x32, 0x1a, 0x32, 0x18, 0x33, 0x18, 0x34, 0x17, 0x34, 0x16, 0x35,
- 0x16, 0x36, 0x15, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x09, 0x00, 0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24,
- 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38,
- 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09,
- 0x00, 0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x86, 0x00,
- 0x76, 0x00, 0x65, 0x00, 0x52, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e, 0x00,
- 0x10, 0x00, 0x09, 0x04, 0x04, 0x08, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x1a,
- 0x9e, 0x00, 0x9b, 0x00, 0x94, 0x00, 0x89, 0x00, 0x7b, 0x00, 0x6b, 0x00,
- 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2d, 0x00, 0x1f, 0x00, 0x13, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x11, 0x3a, 0x3a, 0x31, 0x3a,
- 0x2a, 0x39, 0x25, 0x3a, 0x22, 0x39, 0x1e, 0x3b, 0x1c, 0x3b, 0x1a, 0x3a,
- 0x19, 0x3a, 0x17, 0x3c, 0x16, 0x3c, 0x15, 0x3e, 0x14, 0x3e, 0x13, 0x3d,
- 0x13, 0x3d, 0x12, 0x3d, 0x11, 0x3d, 0x11, 0x3e, 0x11, 0x3f, 0x10, 0x40,
- 0xa8, 0x00, 0x90, 0x00, 0x7c, 0x01, 0x6b, 0x02, 0x5f, 0x05, 0x55, 0x07,
- 0x4c, 0x0a, 0x45, 0x0d, 0x40, 0x0f, 0x3c, 0x12, 0x37, 0x14, 0x34, 0x16,
- 0x31, 0x18, 0x2e, 0x19, 0x2b, 0x1b, 0x2a, 0x1d, 0x28, 0x1e, 0x26, 0x20,
- 0x25, 0x22, 0x23, 0x22, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x59, 0x23, 0x4d, 0x23,
- 0x43, 0x24, 0x3b, 0x25, 0x34, 0x26, 0x2f, 0x27, 0x2b, 0x29, 0x28, 0x2a,
- 0x25, 0x2b, 0x23, 0x2d, 0x21, 0x2e, 0x1f, 0x2e, 0x1d, 0x30, 0x1c, 0x30,
- 0x1b, 0x31, 0x1a, 0x32, 0x19, 0x32, 0x18, 0x33, 0x17, 0x34, 0x16, 0x34,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x08, 0x00, 0x0f, 0x00, 0x16, 0x00, 0x1c, 0x00, 0x5e, 0x00, 0x5d,
- 0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x28,
- 0x00, 0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f,
- 0x00, 0x16, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9e, 0x00, 0x9b, 0x00, 0x95, 0x00, 0x8a, 0x00, 0x7d, 0x00, 0x6d, 0x00,
- 0x5d, 0x00, 0x4c, 0x00, 0x3b, 0x00, 0x2c, 0x00, 0x1d, 0x00, 0x10, 0x00,
- 0x0a, 0x04, 0x05, 0x07, 0x00, 0x0b, 0x00, 0x11, 0x9e, 0x00, 0x9c, 0x00,
- 0x96, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x73, 0x00, 0x64, 0x00, 0x55, 0x00,
- 0x46, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0a, 0x00,
- 0x01, 0x00, 0x00, 0x06, 0x3a, 0x3b, 0x32, 0x3a, 0x2c, 0x39, 0x27, 0x3a,
- 0x23, 0x39, 0x21, 0x39, 0x1e, 0x3b, 0x1c, 0x3c, 0x1a, 0x3a, 0x19, 0x3a,
- 0x17, 0x3b, 0x17, 0x3c, 0x15, 0x3d, 0x15, 0x3e, 0x14, 0x3e, 0x13, 0x3d,
- 0x13, 0x3d, 0x13, 0x3d, 0x11, 0x3d, 0x11, 0x3e, 0xaa, 0x00, 0x94, 0x00,
- 0x82, 0x00, 0x72, 0x01, 0x65, 0x04, 0x5b, 0x05, 0x53, 0x07, 0x4b, 0x0a,
- 0x45, 0x0c, 0x41, 0x0f, 0x3d, 0x11, 0x39, 0x12, 0x36, 0x15, 0x33, 0x16,
- 0x30, 0x18, 0x2e, 0x19, 0x2b, 0x1a, 0x2b, 0x1d, 0x29, 0x1d, 0x26, 0x1e,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x5a, 0x23, 0x4f, 0x23, 0x46, 0x24, 0x3e, 0x24,
- 0x37, 0x25, 0x32, 0x26, 0x2e, 0x27, 0x2b, 0x28, 0x28, 0x2a, 0x25, 0x2b,
- 0x23, 0x2c, 0x21, 0x2d, 0x20, 0x2e, 0x1e, 0x2e, 0x1d, 0x30, 0x1c, 0x30,
- 0x1b, 0x31, 0x1a, 0x32, 0x19, 0x32, 0x18, 0x33, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
- 0x00, 0x0e, 0x00, 0x14, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53,
- 0x00, 0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e, 0x00, 0x24, 0x00, 0x1a,
- 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x14,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
- 0x96, 0x00, 0x8d, 0x00, 0x81, 0x00, 0x74, 0x00, 0x65, 0x00, 0x56, 0x00,
- 0x46, 0x00, 0x37, 0x00, 0x29, 0x00, 0x1c, 0x00, 0x10, 0x00, 0x0a, 0x03,
- 0x06, 0x07, 0x01, 0x0a, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8f, 0x00,
- 0x85, 0x00, 0x79, 0x00, 0x6b, 0x00, 0x5e, 0x00, 0x50, 0x00, 0x43, 0x00,
- 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x15, 0x00, 0x0c, 0x00, 0x03, 0x00,
- 0x3b, 0x3b, 0x33, 0x3b, 0x2d, 0x39, 0x29, 0x39, 0x25, 0x3a, 0x22, 0x39,
- 0x20, 0x39, 0x1e, 0x3b, 0x1c, 0x3c, 0x1a, 0x3a, 0x19, 0x3a, 0x18, 0x3a,
- 0x17, 0x3c, 0x16, 0x3c, 0x15, 0x3d, 0x15, 0x3e, 0x13, 0x3f, 0x13, 0x3d,
- 0x13, 0x3d, 0x13, 0x3d, 0xaa, 0x00, 0x98, 0x00, 0x87, 0x00, 0x78, 0x01,
- 0x6b, 0x02, 0x61, 0x04, 0x58, 0x06, 0x51, 0x08, 0x4b, 0x0a, 0x46, 0x0c,
- 0x42, 0x0e, 0x3e, 0x0f, 0x3a, 0x12, 0x37, 0x12, 0x35, 0x16, 0x32, 0x16,
- 0x30, 0x18, 0x2e, 0x19, 0x2b, 0x1a, 0x2b, 0x1c, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x5a, 0x23, 0x51, 0x23, 0x48, 0x23, 0x41, 0x24, 0x3a, 0x25, 0x35, 0x25,
- 0x31, 0x26, 0x2e, 0x27, 0x2a, 0x28, 0x28, 0x2a, 0x26, 0x2b, 0x24, 0x2b,
- 0x22, 0x2d, 0x21, 0x2d, 0x1f, 0x2e, 0x1e, 0x2e, 0x1d, 0x30, 0x1c, 0x30,
- 0x1b, 0x30, 0x1a, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d,
- 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x46,
- 0x00, 0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f,
- 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x90, 0x00,
- 0x85, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x5e, 0x00, 0x50, 0x00, 0x42, 0x00,
- 0x34, 0x00, 0x27, 0x00, 0x1b, 0x00, 0x0f, 0x00, 0x0b, 0x03, 0x06, 0x06,
- 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x91, 0x00, 0x88, 0x00, 0x7e, 0x00,
- 0x72, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00,
- 0x2a, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0d, 0x00, 0x3b, 0x3c, 0x34, 0x3a,
- 0x2f, 0x3a, 0x2a, 0x39, 0x26, 0x3a, 0x23, 0x3a, 0x21, 0x39, 0x1f, 0x3a,
- 0x1d, 0x3b, 0x1c, 0x3c, 0x1a, 0x3b, 0x19, 0x3a, 0x18, 0x3a, 0x17, 0x3b,
- 0x17, 0x3c, 0x15, 0x3c, 0x15, 0x3d, 0x15, 0x3f, 0x13, 0x3f, 0x13, 0x3e,
- 0xac, 0x00, 0x9b, 0x00, 0x8b, 0x00, 0x7c, 0x00, 0x71, 0x01, 0x67, 0x03,
- 0x5e, 0x05, 0x57, 0x07, 0x51, 0x08, 0x4b, 0x0a, 0x46, 0x0c, 0x42, 0x0d,
- 0x3f, 0x0f, 0x3b, 0x11, 0x39, 0x12, 0x35, 0x14, 0x34, 0x16, 0x31, 0x16,
- 0x30, 0x18, 0x2e, 0x19, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5b, 0x23, 0x52, 0x23,
- 0x4a, 0x23, 0x43, 0x24, 0x3d, 0x24, 0x38, 0x25, 0x34, 0x26, 0x30, 0x27,
- 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x2a, 0x26, 0x2a, 0x24, 0x2b, 0x22, 0x2c,
- 0x21, 0x2d, 0x20, 0x2d, 0x1f, 0x2e, 0x1d, 0x2e, 0x1d, 0x30, 0x1c, 0x30,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x5e,
- 0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49, 0x00, 0x41, 0x00, 0x39,
- 0x00, 0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x07,
- 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00,
- 0x72, 0x00, 0x65, 0x00, 0x58, 0x00, 0x4b, 0x00, 0x3e, 0x00, 0x31, 0x00,
- 0x25, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x0b, 0x03, 0x9e, 0x00, 0x9d, 0x00,
- 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82, 0x00, 0x77, 0x00, 0x6c, 0x00,
- 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3d, 0x00, 0x33, 0x00, 0x29, 0x00,
- 0x1f, 0x00, 0x17, 0x00, 0x3b, 0x3c, 0x35, 0x3a, 0x30, 0x3b, 0x2c, 0x39,
- 0x28, 0x3a, 0x25, 0x3b, 0x22, 0x39, 0x21, 0x39, 0x1f, 0x3a, 0x1d, 0x3b,
- 0x1c, 0x3c, 0x1a, 0x3b, 0x19, 0x3a, 0x19, 0x3a, 0x17, 0x3a, 0x17, 0x3c,
- 0x16, 0x3c, 0x15, 0x3c, 0x15, 0x3e, 0x14, 0x3f, 0xad, 0x00, 0x9d, 0x00,
- 0x8e, 0x00, 0x81, 0x00, 0x76, 0x01, 0x6b, 0x02, 0x63, 0x04, 0x5c, 0x05,
- 0x56, 0x07, 0x50, 0x08, 0x4b, 0x0a, 0x47, 0x0c, 0x43, 0x0c, 0x40, 0x0f,
- 0x3c, 0x0f, 0x3a, 0x12, 0x37, 0x12, 0x35, 0x14, 0x33, 0x16, 0x30, 0x16,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x5b, 0x23, 0x53, 0x23, 0x4c, 0x23, 0x45, 0x23,
- 0x40, 0x24, 0x3b, 0x25, 0x36, 0x25, 0x33, 0x26, 0x30, 0x27, 0x2d, 0x28,
- 0x2a, 0x28, 0x28, 0x2a, 0x26, 0x2a, 0x25, 0x2b, 0x23, 0x2b, 0x22, 0x2d,
- 0x20, 0x2d, 0x20, 0x2e, 0x1e, 0x2e, 0x1d, 0x2e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x57,
- 0x00, 0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x2c,
- 0x00, 0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00,
- 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82, 0x00, 0x77, 0x00, 0x6b, 0x00,
- 0x5f, 0x00, 0x53, 0x00, 0x46, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x24, 0x00,
- 0x19, 0x00, 0x0f, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x95, 0x00,
- 0x8d, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00, 0x66, 0x00, 0x5b, 0x00,
- 0x50, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x31, 0x00, 0x28, 0x00, 0x1f, 0x00,
- 0x3c, 0x3d, 0x36, 0x3a, 0x31, 0x3b, 0x2c, 0x3a, 0x29, 0x39, 0x26, 0x3a,
- 0x24, 0x3b, 0x21, 0x39, 0x20, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3c,
- 0x1a, 0x3c, 0x19, 0x3a, 0x19, 0x3a, 0x17, 0x3a, 0x17, 0x3b, 0x17, 0x3c,
- 0x15, 0x3c, 0x15, 0x3c, 0xad, 0x00, 0x9f, 0x00, 0x91, 0x00, 0x85, 0x00,
- 0x79, 0x00, 0x6f, 0x01, 0x67, 0x02, 0x60, 0x04, 0x59, 0x05, 0x54, 0x07,
- 0x4f, 0x08, 0x4b, 0x0a, 0x47, 0x0c, 0x43, 0x0c, 0x41, 0x0f, 0x3d, 0x0f,
- 0x3b, 0x11, 0x38, 0x12, 0x35, 0x12, 0x35, 0x15, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x5b, 0x23, 0x54, 0x23, 0x4e, 0x23, 0x47, 0x23, 0x42, 0x24, 0x3c, 0x24,
- 0x38, 0x25, 0x35, 0x25, 0x32, 0x26, 0x2f, 0x27, 0x2d, 0x28, 0x2a, 0x28,
- 0x28, 0x2a, 0x26, 0x2a, 0x25, 0x2b, 0x23, 0x2b, 0x22, 0x2c, 0x21, 0x2d,
- 0x20, 0x2d, 0x20, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3d, 0x36, 0x3a,
- 0x32, 0x3b, 0x2d, 0x3b, 0x2b, 0x39, 0x28, 0x3a, 0x25, 0x3a, 0x23, 0x3a,
- 0x21, 0x39, 0x1f, 0x39, 0x1f, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c,
- 0x19, 0x3a, 0x19, 0x3a, 0x18, 0x3a, 0x17, 0x3a, 0x17, 0x3c, 0x16, 0x3c,
- 0xad, 0x00, 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7e, 0x00, 0x74, 0x01,
- 0x6c, 0x02, 0x65, 0x03, 0x5e, 0x04, 0x58, 0x05, 0x53, 0x07, 0x4f, 0x08,
- 0x4b, 0x0a, 0x47, 0x0b, 0x44, 0x0c, 0x41, 0x0e, 0x3e, 0x0f, 0x3b, 0x0f,
- 0x3a, 0x12, 0x37, 0x12, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x55, 0x23,
- 0x4f, 0x23, 0x49, 0x23, 0x44, 0x24, 0x3f, 0x24, 0x3b, 0x25, 0x37, 0x25,
- 0x34, 0x26, 0x31, 0x26, 0x2e, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29,
- 0x27, 0x2a, 0x25, 0x2b, 0x24, 0x2b, 0x22, 0x2b, 0x22, 0x2d, 0x20, 0x2d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x37, 0x3b, 0x33, 0x3b, 0x2f, 0x3b,
- 0x2b, 0x39, 0x29, 0x39, 0x26, 0x3a, 0x24, 0x3b, 0x22, 0x3a, 0x21, 0x39,
- 0x1f, 0x39, 0x1e, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3b,
- 0x19, 0x3a, 0x18, 0x3a, 0x17, 0x3a, 0x17, 0x3b, 0xae, 0x00, 0xa2, 0x00,
- 0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x77, 0x00, 0x6f, 0x01, 0x67, 0x02,
- 0x61, 0x04, 0x5c, 0x05, 0x57, 0x05, 0x52, 0x07, 0x4e, 0x08, 0x4b, 0x0a,
- 0x47, 0x0b, 0x44, 0x0c, 0x41, 0x0d, 0x3f, 0x0f, 0x3c, 0x0f, 0x3b, 0x11,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x56, 0x23, 0x50, 0x23, 0x4a, 0x23,
- 0x45, 0x23, 0x40, 0x24, 0x3c, 0x24, 0x39, 0x25, 0x35, 0x25, 0x33, 0x26,
- 0x30, 0x26, 0x2e, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29, 0x27, 0x2a,
- 0x25, 0x2a, 0x24, 0x2b, 0x23, 0x2b, 0x22, 0x2c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3c, 0x3e, 0x37, 0x3b, 0x33, 0x3a, 0x2f, 0x3b, 0x2c, 0x3a, 0x2a, 0x39,
- 0x27, 0x3a, 0x25, 0x3a, 0x23, 0x3b, 0x21, 0x39, 0x20, 0x39, 0x1f, 0x39,
- 0x1e, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3b, 0x19, 0x3a,
- 0x19, 0x3a, 0x17, 0x3a, 0xaf, 0x00, 0xa3, 0x00, 0x98, 0x00, 0x8e, 0x00,
- 0x84, 0x00, 0x7a, 0x00, 0x72, 0x01, 0x6c, 0x02, 0x65, 0x02, 0x5f, 0x04,
- 0x5a, 0x05, 0x56, 0x05, 0x52, 0x07, 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0b,
- 0x45, 0x0c, 0x41, 0x0c, 0x40, 0x0f, 0x3d, 0x0f, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x5c, 0x23, 0x56, 0x23, 0x51, 0x23, 0x4c, 0x23, 0x47, 0x23, 0x42, 0x24,
- 0x3e, 0x24, 0x3b, 0x25, 0x37, 0x25, 0x34, 0x25, 0x32, 0x26, 0x30, 0x26,
- 0x2e, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29, 0x27, 0x2a, 0x25, 0x2a,
- 0x25, 0x2b, 0x23, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x38, 0x3c,
- 0x34, 0x3a, 0x30, 0x3b, 0x2d, 0x3b, 0x2a, 0x39, 0x28, 0x39, 0x26, 0x3a,
- 0x24, 0x3b, 0x22, 0x3b, 0x21, 0x39, 0x20, 0x39, 0x1f, 0x39, 0x1e, 0x3b,
- 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3b, 0x19, 0x3a, 0x19, 0x3a,
- 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00, 0x90, 0x00, 0x87, 0x00, 0x7e, 0x00,
- 0x76, 0x00, 0x6f, 0x01, 0x68, 0x02, 0x62, 0x04, 0x5e, 0x04, 0x59, 0x05,
- 0x55, 0x06, 0x51, 0x07, 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0a, 0x45, 0x0c,
- 0x41, 0x0c, 0x41, 0x0f, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x57, 0x23,
- 0x52, 0x23, 0x4d, 0x23, 0x48, 0x23, 0x44, 0x23, 0x40, 0x24, 0x3c, 0x24,
- 0x39, 0x25, 0x36, 0x25, 0x34, 0x25, 0x31, 0x26, 0x2f, 0x27, 0x2d, 0x27,
- 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29, 0x27, 0x2a, 0x25, 0x2a, 0x25, 0x2b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3e, 0x38, 0x3c, 0x34, 0x3a, 0x31, 0x3b,
- 0x2e, 0x3c, 0x2b, 0x39, 0x29, 0x39, 0x27, 0x3a, 0x25, 0x3a, 0x24, 0x3b,
- 0x21, 0x3a, 0x21, 0x39, 0x1f, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3b,
- 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x3a, 0xaf, 0x00, 0xa6, 0x00,
- 0x9b, 0x00, 0x91, 0x00, 0x88, 0x00, 0x80, 0x00, 0x78, 0x00, 0x71, 0x01,
- 0x6b, 0x02, 0x66, 0x02, 0x61, 0x04, 0x5c, 0x04, 0x58, 0x05, 0x55, 0x07,
- 0x50, 0x07, 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0c,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x58, 0x23, 0x53, 0x23, 0x4d, 0x23,
- 0x49, 0x23, 0x45, 0x23, 0x41, 0x24, 0x3d, 0x24, 0x3b, 0x24, 0x38, 0x25,
- 0x35, 0x25, 0x33, 0x26, 0x31, 0x26, 0x2f, 0x27, 0x2d, 0x27, 0x2c, 0x28,
- 0x2a, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x26, 0x2a, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x3e, 0x38, 0x3d, 0x35, 0x3a, 0x32, 0x3b, 0x2e, 0x3b, 0x2c, 0x3a,
- 0x2a, 0x39, 0x27, 0x39, 0x26, 0x3a, 0x24, 0x3a, 0x23, 0x3b, 0x21, 0x39,
- 0x21, 0x39, 0x1f, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c,
- 0x1a, 0x3c, 0x19, 0x3c, 0xb0, 0x00, 0xa6, 0x00, 0x9d, 0x00, 0x93, 0x00,
- 0x8b, 0x00, 0x83, 0x00, 0x7c, 0x00, 0x75, 0x00, 0x6e, 0x01, 0x69, 0x02,
- 0x63, 0x03, 0x5f, 0x04, 0x5b, 0x05, 0x56, 0x05, 0x54, 0x07, 0x4f, 0x07,
- 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0a, 0x46, 0x0c, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x5d, 0x23, 0x58, 0x23, 0x53, 0x23, 0x4f, 0x23, 0x4a, 0x23, 0x46, 0x23,
- 0x43, 0x24, 0x3f, 0x24, 0x3c, 0x24, 0x39, 0x25, 0x36, 0x25, 0x34, 0x25,
- 0x33, 0x26, 0x30, 0x26, 0x2f, 0x27, 0x2d, 0x27, 0x2c, 0x28, 0x2a, 0x28,
- 0x28, 0x28, 0x28, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3e, 0x39, 0x3e,
- 0x35, 0x3a, 0x32, 0x3a, 0x2f, 0x3b, 0x2d, 0x3c, 0x2a, 0x39, 0x28, 0x39,
- 0x27, 0x3a, 0x24, 0x3a, 0x24, 0x3b, 0x22, 0x3b, 0x21, 0x39, 0x20, 0x39,
- 0x1f, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c,
- 0xb0, 0x00, 0xa7, 0x00, 0x9e, 0x00, 0x96, 0x00, 0x8d, 0x00, 0x86, 0x00,
- 0x7e, 0x00, 0x77, 0x00, 0x71, 0x01, 0x6b, 0x01, 0x66, 0x02, 0x62, 0x04,
- 0x5d, 0x04, 0x5a, 0x05, 0x55, 0x05, 0x53, 0x07, 0x4f, 0x07, 0x4e, 0x09,
- 0x4a, 0x0a, 0x47, 0x0a, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5d, 0x23, 0x58, 0x23,
- 0x54, 0x23, 0x50, 0x23, 0x4c, 0x23, 0x48, 0x23, 0x44, 0x23, 0x40, 0x24,
- 0x3d, 0x24, 0x3a, 0x24, 0x38, 0x25, 0x36, 0x25, 0x33, 0x25, 0x32, 0x26,
- 0x2f, 0x26, 0x2f, 0x27, 0x2c, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x28,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3e, 0x39, 0x3e, 0x35, 0x3b, 0x32, 0x3a,
- 0x30, 0x3b, 0x2e, 0x3c, 0x2b, 0x3a, 0x2a, 0x39, 0x27, 0x39, 0x26, 0x3a,
- 0x24, 0x3a, 0x23, 0x3b, 0x21, 0x3a, 0x21, 0x39, 0x1f, 0x39, 0x1f, 0x39,
- 0x1e, 0x3b, 0x1c, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0xb1, 0x00, 0xa7, 0x00,
- 0x9f, 0x00, 0x97, 0x00, 0x8f, 0x00, 0x87, 0x00, 0x80, 0x00, 0x79, 0x00,
- 0x73, 0x00, 0x6e, 0x01, 0x69, 0x02, 0x64, 0x02, 0x60, 0x04, 0x5c, 0x04,
- 0x59, 0x05, 0x55, 0x05, 0x53, 0x07, 0x4e, 0x07, 0x4e, 0x09, 0x4a, 0x0a,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47,
- 0x0a, 0x47, 0x0a, 0x47, 0x5d, 0x23, 0x58, 0x23, 0x54, 0x23, 0x50, 0x23,
- 0x4c, 0x23, 0x48, 0x23, 0x45, 0x23, 0x42, 0x24, 0x3f, 0x24, 0x3c, 0x24,
- 0x39, 0x25, 0x37, 0x25, 0x35, 0x25, 0x33, 0x25, 0x31, 0x26, 0x2f, 0x26,
- 0x2e, 0x27, 0x2c, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7f, 0x00, 0x94, 0x00, 0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xa9, 0x00,
- 0xab, 0x00, 0xac, 0x00, 0xad, 0x00, 0xae, 0x00, 0xae, 0x00, 0xaf, 0x00,
- 0xaf, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb1, 0x00,
- 0xb2, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x21, 0x00, 0x6e, 0x00,
- 0x8a, 0x00, 0x97, 0x00, 0x9e, 0x00, 0xa2, 0x00, 0xa6, 0x00, 0xa8, 0x00,
- 0xaa, 0x00, 0xaa, 0x00, 0xac, 0x00, 0xad, 0x00, 0xad, 0x00, 0xad, 0x00,
- 0xae, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb0, 0x00,
- 0x6c, 0x00, 0x92, 0x00, 0xa1, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xac, 0x00,
- 0xae, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb2, 0x00,
- 0xb2, 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00,
- 0xb3, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x04, 0x70, 0x01,
- 0x7f, 0x00, 0x88, 0x00, 0x90, 0x00, 0x95, 0x00, 0x99, 0x00, 0x9c, 0x00,
- 0x9f, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7, 0x00,
- 0xa7, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x1c, 0x3a, 0x03, 0x59, 0x00, 0x6c, 0x00,
- 0x79, 0x00, 0x84, 0x00, 0x8b, 0x00, 0x90, 0x00, 0x94, 0x00, 0x98, 0x00,
- 0x9b, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa3, 0x00,
- 0xa5, 0x00, 0xa6, 0x00, 0xa6, 0x00, 0xa7, 0x00, 0x60, 0x0e, 0x79, 0x01,
- 0x88, 0x00, 0x92, 0x00, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa3, 0x00,
- 0xa5, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xab, 0x00, 0xac, 0x00,
- 0xac, 0x00, 0xad, 0x00, 0xae, 0x00, 0xae, 0x00, 0xae, 0x00, 0xaf, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x4e, 0x0f, 0x60, 0x07, 0x6d, 0x03, 0x77, 0x01,
- 0x7f, 0x00, 0x85, 0x00, 0x8b, 0x00, 0x8f, 0x00, 0x92, 0x00, 0x94, 0x00,
- 0x97, 0x00, 0x9a, 0x00, 0x9c, 0x00, 0x9e, 0x00, 0xa0, 0x00, 0xa1, 0x00,
- 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa4, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0x0a, 0x29, 0x27, 0x0f, 0x40, 0x06, 0x52, 0x02, 0x61, 0x00, 0x6c, 0x00,
- 0x75, 0x00, 0x7c, 0x00, 0x82, 0x00, 0x87, 0x00, 0x8b, 0x00, 0x8e, 0x00,
- 0x91, 0x00, 0x94, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9b, 0x00,
- 0x9d, 0x00, 0x9e, 0x00, 0x60, 0x14, 0x6f, 0x07, 0x7b, 0x03, 0x84, 0x01,
- 0x8c, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9d, 0x00, 0x9f, 0x00,
- 0xa1, 0x00, 0xa2, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa7, 0x00, 0xa7, 0x00,
- 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x49, 0x17, 0x56, 0x0d, 0x62, 0x07, 0x6b, 0x04, 0x73, 0x02, 0x79, 0x01,
- 0x7e, 0x01, 0x83, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00,
- 0x92, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9c, 0x00,
- 0x9e, 0x00, 0x9f, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x31, 0x1e, 0x18,
- 0x32, 0x0d, 0x43, 0x07, 0x50, 0x04, 0x5a, 0x02, 0x63, 0x01, 0x6b, 0x00,
- 0x72, 0x00, 0x78, 0x00, 0x7c, 0x00, 0x81, 0x00, 0x85, 0x00, 0x88, 0x00,
- 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00,
- 0x60, 0x18, 0x6b, 0x0c, 0x74, 0x06, 0x7d, 0x03, 0x83, 0x02, 0x89, 0x01,
- 0x8d, 0x00, 0x91, 0x00, 0x95, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9c, 0x00,
- 0x9e, 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xa4, 0x00,
- 0xa5, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x1d, 0x51, 0x12,
- 0x5b, 0x0c, 0x63, 0x08, 0x6a, 0x05, 0x70, 0x03, 0x77, 0x02, 0x7b, 0x02,
- 0x7e, 0x01, 0x82, 0x00, 0x86, 0x00, 0x8a, 0x00, 0x8c, 0x00, 0x8e, 0x00,
- 0x90, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x97, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x36, 0x19, 0x1f, 0x2a, 0x12, 0x38, 0x0b,
- 0x44, 0x07, 0x4e, 0x05, 0x57, 0x02, 0x5f, 0x01, 0x65, 0x01, 0x6b, 0x00,
- 0x71, 0x00, 0x76, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x80, 0x00, 0x84, 0x00,
- 0x87, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d, 0x00, 0x60, 0x1b, 0x68, 0x0f,
- 0x70, 0x09, 0x77, 0x05, 0x7d, 0x03, 0x82, 0x02, 0x87, 0x01, 0x8b, 0x00,
- 0x8e, 0x00, 0x91, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00,
- 0x9b, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1, 0x00, 0xa2, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x45, 0x21, 0x4e, 0x16, 0x56, 0x10, 0x5d, 0x0b,
- 0x65, 0x08, 0x69, 0x06, 0x6f, 0x04, 0x74, 0x03, 0x78, 0x02, 0x7b, 0x02,
- 0x7e, 0x01, 0x81, 0x01, 0x85, 0x00, 0x88, 0x00, 0x8a, 0x00, 0x8c, 0x00,
- 0x8e, 0x00, 0x8f, 0x00, 0x90, 0x00, 0x92, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0x09, 0x3a, 0x17, 0x24, 0x24, 0x18, 0x30, 0x10, 0x3b, 0x0b, 0x45, 0x07,
- 0x4d, 0x05, 0x55, 0x04, 0x5b, 0x02, 0x61, 0x01, 0x67, 0x01, 0x6b, 0x00,
- 0x6f, 0x00, 0x74, 0x00, 0x77, 0x00, 0x7a, 0x00, 0x7e, 0x00, 0x80, 0x00,
- 0x83, 0x00, 0x86, 0x00, 0x60, 0x1d, 0x67, 0x12, 0x6d, 0x0c, 0x73, 0x08,
- 0x79, 0x05, 0x7e, 0x03, 0x82, 0x02, 0x86, 0x02, 0x89, 0x01, 0x8c, 0x00,
- 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x00, 0x99, 0x00,
- 0x9a, 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x44, 0x24, 0x4c, 0x1a, 0x53, 0x13, 0x59, 0x0e, 0x5f, 0x0b, 0x65, 0x08,
- 0x69, 0x06, 0x6d, 0x05, 0x73, 0x04, 0x76, 0x03, 0x79, 0x02, 0x7c, 0x02,
- 0x7e, 0x01, 0x81, 0x01, 0x84, 0x00, 0x87, 0x00, 0x89, 0x00, 0x8b, 0x00,
- 0x8c, 0x00, 0x8d, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x3b, 0x14, 0x28,
- 0x20, 0x1c, 0x2a, 0x14, 0x34, 0x0f, 0x3e, 0x0b, 0x45, 0x07, 0x4c, 0x05,
- 0x53, 0x04, 0x58, 0x03, 0x5e, 0x02, 0x63, 0x01, 0x67, 0x01, 0x6c, 0x00,
- 0x6f, 0x00, 0x72, 0x00, 0x76, 0x00, 0x78, 0x00, 0x7c, 0x00, 0x7e, 0x00,
- 0x60, 0x1d, 0x66, 0x14, 0x6b, 0x0e, 0x71, 0x0a, 0x76, 0x07, 0x7a, 0x05,
- 0x7e, 0x03, 0x81, 0x02, 0x85, 0x02, 0x88, 0x01, 0x8b, 0x01, 0x8d, 0x00,
- 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x96, 0x00, 0x98, 0x00,
- 0x99, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x27, 0x4a, 0x1d,
- 0x4f, 0x16, 0x57, 0x11, 0x5b, 0x0e, 0x61, 0x0b, 0x66, 0x08, 0x69, 0x07,
- 0x6d, 0x05, 0x71, 0x04, 0x75, 0x03, 0x77, 0x02, 0x7a, 0x02, 0x7c, 0x02,
- 0x7e, 0x01, 0x80, 0x01, 0x83, 0x01, 0x86, 0x00, 0x88, 0x00, 0x89, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x3d, 0x13, 0x2c, 0x1c, 0x20, 0x27, 0x18,
- 0x2f, 0x12, 0x38, 0x0e, 0x3e, 0x0a, 0x45, 0x07, 0x4b, 0x06, 0x51, 0x05,
- 0x57, 0x04, 0x5c, 0x02, 0x60, 0x02, 0x65, 0x01, 0x67, 0x01, 0x6c, 0x00,
- 0x6f, 0x00, 0x71, 0x00, 0x75, 0x00, 0x77, 0x00, 0x60, 0x1e, 0x65, 0x16,
- 0x6a, 0x10, 0x6f, 0x0c, 0x73, 0x09, 0x77, 0x07, 0x7b, 0x05, 0x7e, 0x03,
- 0x81, 0x03, 0x84, 0x02, 0x87, 0x02, 0x89, 0x01, 0x8b, 0x01, 0x8e, 0x00,
- 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00,
- 0x27, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x8f, 0x00, 0x96, 0x00, 0x99, 0x00,
- 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00,
- 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x2c, 0x14, 0x57, 0x00,
- 0x82, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x9c, 0x00,
- 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00,
- 0x9e, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x8c, 0x00, 0x63, 0x00, 0x7f, 0x00, 0x89, 0x00, 0x90, 0x00, 0x96, 0x00,
- 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00,
- 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x31, 0x11, 0x5f, 0x00,
- 0x85, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00,
- 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00,
- 0x9e, 0x00, 0x9e, 0x00, 0x43, 0x29, 0x48, 0x20, 0x4d, 0x19, 0x54, 0x14,
- 0x58, 0x10, 0x5c, 0x0d, 0x62, 0x0b, 0x66, 0x09, 0x69, 0x07, 0x6c, 0x06,
- 0x70, 0x05, 0x74, 0x04, 0x76, 0x03, 0x78, 0x02, 0x7a, 0x02, 0x7c, 0x02,
- 0x7e, 0x02, 0x80, 0x01, 0x82, 0x01, 0x85, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0x09, 0x3f, 0x11, 0x2f, 0x1b, 0x23, 0x23, 0x1b, 0x2b, 0x15, 0x32, 0x11,
- 0x39, 0x0d, 0x40, 0x0a, 0x45, 0x08, 0x4b, 0x07, 0x51, 0x05, 0x56, 0x04,
- 0x59, 0x03, 0x5e, 0x02, 0x61, 0x02, 0x65, 0x01, 0x68, 0x01, 0x6b, 0x00,
- 0x6e, 0x00, 0x71, 0x00, 0x60, 0x1f, 0x64, 0x17, 0x69, 0x11, 0x6d, 0x0d,
- 0x71, 0x0a, 0x75, 0x08, 0x78, 0x06, 0x7b, 0x05, 0x7e, 0x04, 0x81, 0x03,
- 0x84, 0x02, 0x86, 0x02, 0x88, 0x01, 0x8a, 0x01, 0x8c, 0x01, 0x8e, 0x00,
- 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x00, 0x00, 0x0d, 0x00,
- 0x4f, 0x00, 0x73, 0x00, 0x84, 0x00, 0x8d, 0x00, 0x92, 0x00, 0x95, 0x00,
- 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00,
- 0x9c, 0x00, 0x9d, 0x00, 0x01, 0x29, 0x16, 0x04, 0x57, 0x00, 0x78, 0x00,
- 0x87, 0x00, 0x8f, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00,
- 0x9b, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x4d, 0x00,
- 0x60, 0x00, 0x77, 0x00, 0x83, 0x00, 0x8c, 0x00, 0x92, 0x00, 0x95, 0x00,
- 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00,
- 0x9c, 0x00, 0x9d, 0x00, 0x03, 0x23, 0x20, 0x00, 0x5f, 0x00, 0x7c, 0x00,
- 0x8a, 0x00, 0x91, 0x00, 0x95, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a, 0x00,
- 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00,
- 0x43, 0x2b, 0x47, 0x22, 0x4c, 0x1b, 0x51, 0x16, 0x56, 0x12, 0x59, 0x0f,
- 0x5e, 0x0d, 0x63, 0x0b, 0x66, 0x09, 0x69, 0x07, 0x6b, 0x06, 0x6f, 0x05,
- 0x73, 0x05, 0x75, 0x03, 0x77, 0x03, 0x79, 0x02, 0x7a, 0x02, 0x7c, 0x02,
- 0x7e, 0x02, 0x7f, 0x01, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x40, 0x11, 0x31,
- 0x18, 0x26, 0x20, 0x1e, 0x28, 0x18, 0x2f, 0x13, 0x35, 0x0f, 0x3c, 0x0c,
- 0x41, 0x0a, 0x46, 0x08, 0x4b, 0x07, 0x50, 0x05, 0x54, 0x04, 0x58, 0x04,
- 0x5c, 0x02, 0x5f, 0x02, 0x62, 0x02, 0x66, 0x01, 0x69, 0x01, 0x6b, 0x00,
- 0x60, 0x20, 0x64, 0x18, 0x68, 0x13, 0x6b, 0x0f, 0x6f, 0x0c, 0x73, 0x09,
- 0x76, 0x07, 0x79, 0x06, 0x7c, 0x05, 0x7e, 0x04, 0x81, 0x03, 0x83, 0x02,
- 0x85, 0x02, 0x88, 0x02, 0x89, 0x01, 0x8b, 0x01, 0x8d, 0x01, 0x8e, 0x00,
- 0x90, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x38, 0x00,
- 0x5b, 0x00, 0x6f, 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e, 0x00,
- 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00,
- 0x00, 0x49, 0x00, 0x27, 0x12, 0x01, 0x43, 0x00, 0x61, 0x00, 0x74, 0x00,
- 0x7f, 0x00, 0x87, 0x00, 0x8c, 0x00, 0x90, 0x00, 0x93, 0x00, 0x95, 0x00,
- 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x60, 0x00, 0x24, 0x00, 0x48, 0x00,
- 0x60, 0x00, 0x70, 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e, 0x00,
- 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00,
- 0x00, 0x46, 0x00, 0x1f, 0x1f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x79, 0x00,
- 0x83, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x92, 0x00, 0x94, 0x00, 0x96, 0x00,
- 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x43, 0x2d, 0x46, 0x24,
- 0x4b, 0x1e, 0x4f, 0x19, 0x55, 0x14, 0x58, 0x11, 0x5b, 0x0e, 0x5f, 0x0c,
- 0x64, 0x0a, 0x66, 0x09, 0x68, 0x07, 0x6a, 0x06, 0x6e, 0x06, 0x72, 0x05,
- 0x74, 0x04, 0x76, 0x03, 0x78, 0x03, 0x79, 0x02, 0x7b, 0x02, 0x7c, 0x02,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x40, 0x10, 0x33, 0x17, 0x28, 0x1e, 0x20,
- 0x25, 0x1a, 0x2c, 0x16, 0x32, 0x12, 0x37, 0x0f, 0x3d, 0x0c, 0x42, 0x0a,
- 0x46, 0x08, 0x4b, 0x07, 0x4f, 0x05, 0x53, 0x05, 0x57, 0x04, 0x5a, 0x04,
- 0x5e, 0x02, 0x61, 0x02, 0x63, 0x01, 0x66, 0x01, 0x60, 0x20, 0x63, 0x19,
- 0x67, 0x14, 0x6a, 0x10, 0x6e, 0x0d, 0x71, 0x0b, 0x74, 0x09, 0x77, 0x07,
- 0x7a, 0x06, 0x7c, 0x05, 0x7f, 0x04, 0x81, 0x03, 0x83, 0x02, 0x85, 0x02,
- 0x87, 0x02, 0x88, 0x02, 0x8a, 0x01, 0x8c, 0x01, 0x8d, 0x00, 0x8e, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2a, 0x00, 0x48, 0x00,
- 0x5d, 0x00, 0x6c, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88, 0x00,
- 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x92, 0x00, 0x00, 0x54, 0x00, 0x41,
- 0x00, 0x17, 0x10, 0x00, 0x36, 0x00, 0x51, 0x00, 0x64, 0x00, 0x71, 0x00,
- 0x7a, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8a, 0x00, 0x8d, 0x00, 0x90, 0x00,
- 0x92, 0x00, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x89, 0x00, 0x77, 0x00, 0x48, 0x00, 0x0f, 0x00, 0x30, 0x00, 0x48, 0x00,
- 0x5d, 0x00, 0x6c, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88, 0x00,
- 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x92, 0x00, 0x00, 0x52, 0x00, 0x3c,
- 0x00, 0x0d, 0x1f, 0x00, 0x42, 0x00, 0x5a, 0x00, 0x6a, 0x00, 0x76, 0x00,
- 0x7e, 0x00, 0x84, 0x00, 0x89, 0x00, 0x8c, 0x00, 0x8f, 0x00, 0x91, 0x00,
- 0x93, 0x00, 0x95, 0x00, 0x42, 0x2e, 0x45, 0x26, 0x4b, 0x1f, 0x4d, 0x1a,
- 0x52, 0x16, 0x56, 0x13, 0x59, 0x10, 0x5c, 0x0e, 0x61, 0x0c, 0x64, 0x0a,
- 0x66, 0x09, 0x68, 0x07, 0x6a, 0x07, 0x6d, 0x06, 0x71, 0x05, 0x74, 0x05,
- 0x75, 0x03, 0x77, 0x03, 0x78, 0x02, 0x7a, 0x02, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0x09, 0x41, 0x0f, 0x34, 0x16, 0x2a, 0x1c, 0x23, 0x23, 0x1d, 0x29, 0x18,
- 0x2e, 0x14, 0x34, 0x11, 0x39, 0x0e, 0x3e, 0x0c, 0x42, 0x0a, 0x47, 0x08,
- 0x4b, 0x07, 0x4f, 0x05, 0x52, 0x05, 0x56, 0x04, 0x59, 0x04, 0x5c, 0x03,
- 0x5f, 0x02, 0x62, 0x02, 0x60, 0x20, 0x63, 0x1a, 0x66, 0x15, 0x6a, 0x11,
- 0x6d, 0x0e, 0x70, 0x0c, 0x73, 0x0a, 0x75, 0x08, 0x78, 0x07, 0x7a, 0x06,
- 0x7d, 0x05, 0x7f, 0x04, 0x81, 0x03, 0x83, 0x02, 0x85, 0x02, 0x86, 0x02,
- 0x88, 0x02, 0x89, 0x01, 0x8b, 0x01, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f, 0x00,
- 0x5e, 0x00, 0x69, 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83, 0x00,
- 0x86, 0x00, 0x89, 0x00, 0x00, 0x59, 0x00, 0x4d, 0x00, 0x2f, 0x00, 0x0e,
- 0x10, 0x00, 0x2e, 0x00, 0x46, 0x00, 0x57, 0x00, 0x64, 0x00, 0x6f, 0x00,
- 0x76, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x85, 0x00, 0x89, 0x00, 0x8b, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x83, 0x00,
- 0x60, 0x00, 0x30, 0x00, 0x02, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f, 0x00,
- 0x5e, 0x00, 0x69, 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83, 0x00,
- 0x86, 0x00, 0x89, 0x00, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x28, 0x00, 0x02,
- 0x1f, 0x00, 0x3b, 0x00, 0x4f, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x74, 0x00,
- 0x7b, 0x00, 0x80, 0x00, 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d, 0x00,
- 0x42, 0x2f, 0x44, 0x27, 0x4a, 0x22, 0x4c, 0x1c, 0x50, 0x18, 0x55, 0x14,
- 0x57, 0x12, 0x5a, 0x0f, 0x5d, 0x0d, 0x62, 0x0c, 0x64, 0x0a, 0x66, 0x09,
- 0x68, 0x08, 0x6a, 0x07, 0x6c, 0x06, 0x70, 0x05, 0x73, 0x05, 0x75, 0x04,
- 0x76, 0x03, 0x78, 0x03, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x42, 0x0f, 0x36,
- 0x15, 0x2c, 0x1b, 0x25, 0x21, 0x1f, 0x26, 0x1a, 0x2c, 0x16, 0x31, 0x12,
- 0x36, 0x0f, 0x3a, 0x0d, 0x3f, 0x0c, 0x43, 0x0a, 0x47, 0x08, 0x4b, 0x07,
- 0x4e, 0x05, 0x52, 0x05, 0x55, 0x04, 0x58, 0x04, 0x5b, 0x04, 0x5d, 0x02,
- 0x60, 0x21, 0x63, 0x1b, 0x66, 0x16, 0x69, 0x12, 0x6c, 0x0f, 0x6e, 0x0d,
- 0x71, 0x0b, 0x74, 0x09, 0x76, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7d, 0x05,
- 0x7f, 0x04, 0x81, 0x03, 0x82, 0x02, 0x84, 0x02, 0x86, 0x02, 0x87, 0x02,
- 0x89, 0x02, 0x8a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53, 0x00,
- 0x5e, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e, 0x00,
- 0x00, 0x5b, 0x00, 0x53, 0x00, 0x3e, 0x00, 0x23, 0x02, 0x0a, 0x10, 0x00,
- 0x29, 0x00, 0x3d, 0x00, 0x4e, 0x00, 0x5b, 0x00, 0x65, 0x00, 0x6d, 0x00,
- 0x74, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x8c, 0x00, 0x70, 0x00, 0x48, 0x00,
- 0x22, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53, 0x00,
- 0x5e, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e, 0x00,
- 0x00, 0x5a, 0x00, 0x51, 0x00, 0x39, 0x00, 0x1a, 0x04, 0x00, 0x1f, 0x00,
- 0x36, 0x00, 0x48, 0x00, 0x57, 0x00, 0x62, 0x00, 0x6b, 0x00, 0x73, 0x00,
- 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x85, 0x00, 0x42, 0x31, 0x44, 0x29,
- 0x49, 0x23, 0x4c, 0x1e, 0x4e, 0x1a, 0x53, 0x16, 0x56, 0x13, 0x58, 0x11,
- 0x5a, 0x0f, 0x5f, 0x0d, 0x63, 0x0b, 0x64, 0x0a, 0x66, 0x09, 0x68, 0x08,
- 0x6a, 0x07, 0x6b, 0x06, 0x6f, 0x06, 0x72, 0x05, 0x74, 0x05, 0x75, 0x03,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x43, 0x0f, 0x37, 0x14, 0x2e, 0x19, 0x27,
- 0x1f, 0x21, 0x24, 0x1c, 0x29, 0x18, 0x2e, 0x15, 0x33, 0x12, 0x37, 0x0f,
- 0x3b, 0x0c, 0x40, 0x0c, 0x43, 0x0a, 0x47, 0x08, 0x4b, 0x07, 0x4e, 0x06,
- 0x51, 0x05, 0x55, 0x05, 0x56, 0x04, 0x5a, 0x04, 0x60, 0x21, 0x63, 0x1b,
- 0x65, 0x17, 0x68, 0x13, 0x6b, 0x10, 0x6e, 0x0e, 0x70, 0x0c, 0x73, 0x0a,
- 0x75, 0x09, 0x77, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7d, 0x05, 0x7f, 0x04,
- 0x81, 0x03, 0x82, 0x03, 0x84, 0x02, 0x86, 0x02, 0x87, 0x02, 0x88, 0x02,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55, 0x00,
- 0x5f, 0x00, 0x66, 0x00, 0x6d, 0x00, 0x72, 0x00, 0x00, 0x5c, 0x00, 0x56,
- 0x00, 0x47, 0x00, 0x31, 0x00, 0x1a, 0x04, 0x08, 0x10, 0x00, 0x25, 0x00,
- 0x37, 0x00, 0x46, 0x00, 0x52, 0x00, 0x5d, 0x00, 0x65, 0x00, 0x6c, 0x00,
- 0x72, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9b, 0x00, 0x92, 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c, 0x00,
- 0x01, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55, 0x00,
- 0x5f, 0x00, 0x66, 0x00, 0x6d, 0x00, 0x72, 0x00, 0x00, 0x5c, 0x00, 0x55,
- 0x00, 0x43, 0x00, 0x2a, 0x00, 0x10, 0x09, 0x00, 0x1f, 0x00, 0x33, 0x00,
- 0x43, 0x00, 0x50, 0x00, 0x5b, 0x00, 0x64, 0x00, 0x6b, 0x00, 0x72, 0x00,
- 0x77, 0x00, 0x7b, 0x00, 0x42, 0x31, 0x44, 0x2a, 0x48, 0x24, 0x4b, 0x1f,
- 0x4d, 0x1b, 0x51, 0x18, 0x55, 0x15, 0x57, 0x12, 0x59, 0x10, 0x5b, 0x0e,
- 0x5f, 0x0c, 0x63, 0x0b, 0x65, 0x0a, 0x66, 0x09, 0x68, 0x08, 0x6a, 0x07,
- 0x6b, 0x06, 0x6e, 0x06, 0x71, 0x05, 0x73, 0x05, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0x0a, 0x43, 0x0e, 0x38, 0x13, 0x2f, 0x18, 0x28, 0x1d, 0x22, 0x22, 0x1d,
- 0x27, 0x19, 0x2b, 0x16, 0x30, 0x12, 0x35, 0x11, 0x39, 0x0f, 0x3c, 0x0c,
- 0x41, 0x0b, 0x44, 0x0a, 0x47, 0x09, 0x4a, 0x07, 0x4e, 0x07, 0x50, 0x05,
- 0x54, 0x05, 0x55, 0x04, 0x60, 0x21, 0x63, 0x1c, 0x65, 0x17, 0x68, 0x14,
- 0x6a, 0x11, 0x6c, 0x0e, 0x6f, 0x0c, 0x71, 0x0b, 0x73, 0x09, 0x76, 0x08,
- 0x78, 0x07, 0x79, 0x06, 0x7c, 0x05, 0x7d, 0x05, 0x7f, 0x04, 0x81, 0x03,
- 0x82, 0x03, 0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x14, 0x00, 0x26, 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57, 0x00,
- 0x5f, 0x00, 0x66, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4d, 0x00, 0x3b,
- 0x00, 0x27, 0x00, 0x13, 0x06, 0x07, 0x10, 0x00, 0x22, 0x00, 0x32, 0x00,
- 0x40, 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x65, 0x00, 0x6b, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x95, 0x00,
- 0x84, 0x00, 0x6c, 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x14, 0x00, 0x26, 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57, 0x00,
- 0x5f, 0x00, 0x66, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x36,
- 0x00, 0x1f, 0x00, 0x08, 0x0c, 0x00, 0x1f, 0x00, 0x30, 0x00, 0x3f, 0x00,
- 0x4b, 0x00, 0x55, 0x00, 0x5e, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x71, 0x00,
- 0x42, 0x32, 0x44, 0x2b, 0x47, 0x25, 0x4b, 0x21, 0x4c, 0x1d, 0x4f, 0x19,
- 0x54, 0x16, 0x56, 0x14, 0x58, 0x11, 0x5a, 0x10, 0x5d, 0x0e, 0x61, 0x0c,
- 0x63, 0x0b, 0x65, 0x0a, 0x66, 0x09, 0x68, 0x08, 0x69, 0x07, 0x6b, 0x07,
- 0x6d, 0x06, 0x71, 0x05, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x43, 0x0e, 0x39,
- 0x12, 0x31, 0x17, 0x2a, 0x1c, 0x24, 0x21, 0x1f, 0x26, 0x1b, 0x2a, 0x18,
- 0x2e, 0x16, 0x32, 0x12, 0x35, 0x0f, 0x3a, 0x0f, 0x3d, 0x0c, 0x41, 0x0b,
- 0x44, 0x0a, 0x47, 0x09, 0x4a, 0x07, 0x4e, 0x07, 0x4f, 0x05, 0x53, 0x05,
- 0x60, 0x21, 0x62, 0x1c, 0x65, 0x18, 0x67, 0x15, 0x6a, 0x12, 0x6c, 0x0f,
- 0x6e, 0x0d, 0x71, 0x0c, 0x73, 0x0b, 0x74, 0x09, 0x76, 0x07, 0x79, 0x07,
- 0x7a, 0x06, 0x7c, 0x05, 0x7d, 0x05, 0x7f, 0x04, 0x81, 0x03, 0x82, 0x03,
- 0x83, 0x02, 0x85, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00,
- 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58, 0x00,
- 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x51, 0x00, 0x42, 0x00, 0x32, 0x00, 0x20,
- 0x00, 0x0e, 0x07, 0x06, 0x10, 0x00, 0x20, 0x00, 0x2f, 0x00, 0x3b, 0x00,
- 0x46, 0x00, 0x50, 0x00, 0x58, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76, 0x00,
- 0x5e, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x00,
- 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58, 0x00,
- 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4e, 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x17,
- 0x00, 0x03, 0x0f, 0x00, 0x1f, 0x00, 0x2e, 0x00, 0x3b, 0x00, 0x46, 0x00,
- 0x50, 0x00, 0x59, 0x00, 0x60, 0x00, 0x66, 0x00, 0x42, 0x33, 0x43, 0x2c,
- 0x46, 0x27, 0x4a, 0x22, 0x4c, 0x1e, 0x4d, 0x1b, 0x52, 0x18, 0x55, 0x15,
- 0x57, 0x13, 0x58, 0x11, 0x5a, 0x0f, 0x5e, 0x0e, 0x62, 0x0c, 0x63, 0x0b,
- 0x65, 0x0a, 0x66, 0x09, 0x68, 0x08, 0x69, 0x07, 0x6b, 0x07, 0x6c, 0x06,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x44, 0x0d, 0x3a, 0x12, 0x32, 0x16, 0x2b,
- 0x1b, 0x26, 0x1f, 0x22, 0x24, 0x1d, 0x28, 0x19, 0x2b, 0x16, 0x30, 0x14,
- 0x34, 0x12, 0x37, 0x0f, 0x3b, 0x0e, 0x3e, 0x0c, 0x41, 0x0b, 0x45, 0x0a,
- 0x47, 0x09, 0x4a, 0x07, 0x4e, 0x07, 0x4f, 0x05, 0x60, 0x22, 0x62, 0x1d,
- 0x65, 0x19, 0x66, 0x15, 0x69, 0x13, 0x6b, 0x11, 0x6d, 0x0e, 0x6f, 0x0c,
- 0x71, 0x0b, 0x73, 0x0a, 0x76, 0x09, 0x77, 0x07, 0x79, 0x07, 0x7a, 0x06,
- 0x7c, 0x05, 0x7e, 0x05, 0x7f, 0x04, 0x80, 0x03, 0x82, 0x03, 0x83, 0x02,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
- 0x2c, 0x00, 0x37, 0x00, 0x41, 0x00, 0x4a, 0x00, 0x00, 0x5e, 0x00, 0x5b,
- 0x00, 0x53, 0x00, 0x48, 0x00, 0x3a, 0x00, 0x2a, 0x00, 0x1a, 0x00, 0x0b,
- 0x08, 0x05, 0x10, 0x00, 0x1e, 0x00, 0x2c, 0x00, 0x37, 0x00, 0x42, 0x00,
- 0x4b, 0x00, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53, 0x00,
- 0x3c, 0x00, 0x26, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
- 0x2c, 0x00, 0x37, 0x00, 0x41, 0x00, 0x4a, 0x00, 0x00, 0x5e, 0x00, 0x5b,
- 0x00, 0x52, 0x00, 0x45, 0x00, 0x34, 0x00, 0x22, 0x00, 0x10, 0x00, 0x00,
- 0x11, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x43, 0x00, 0x4c, 0x00,
- 0x54, 0x00, 0x5b, 0x00, 0x42, 0x33, 0x43, 0x2d, 0x45, 0x28, 0x49, 0x23,
- 0x4b, 0x1f, 0x4d, 0x1c, 0x50, 0x19, 0x55, 0x16, 0x56, 0x14, 0x58, 0x12,
- 0x59, 0x11, 0x5b, 0x0e, 0x5f, 0x0d, 0x62, 0x0c, 0x63, 0x0b, 0x65, 0x0a,
- 0x66, 0x09, 0x68, 0x09, 0x69, 0x07, 0x6b, 0x07, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0x0a, 0x44, 0x0d, 0x3a, 0x12, 0x33, 0x16, 0x2c, 0x19, 0x27, 0x1e, 0x22,
- 0x21, 0x1e, 0x26, 0x1a, 0x2b, 0x18, 0x2e, 0x16, 0x31, 0x12, 0x35, 0x11,
- 0x38, 0x0f, 0x3b, 0x0d, 0x3f, 0x0c, 0x41, 0x0a, 0x45, 0x0a, 0x47, 0x09,
- 0x4a, 0x07, 0x4e, 0x07, 0x60, 0x22, 0x62, 0x1d, 0x64, 0x19, 0x66, 0x16,
- 0x68, 0x13, 0x6a, 0x11, 0x6c, 0x0f, 0x6e, 0x0d, 0x71, 0x0c, 0x73, 0x0b,
- 0x74, 0x09, 0x76, 0x08, 0x78, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7c, 0x05,
- 0x7e, 0x05, 0x7f, 0x04, 0x80, 0x03, 0x82, 0x03, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28, 0x00,
- 0x33, 0x00, 0x3d, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4c,
- 0x00, 0x40, 0x00, 0x32, 0x00, 0x24, 0x00, 0x15, 0x02, 0x0a, 0x09, 0x04,
- 0x10, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x34, 0x00, 0x3e, 0x00, 0x46, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00,
- 0x91, 0x00, 0x83, 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36, 0x00,
- 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28, 0x00,
- 0x33, 0x00, 0x3d, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x49,
- 0x00, 0x3b, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x0b, 0x04, 0x00, 0x12, 0x00,
- 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x00, 0x40, 0x00, 0x49, 0x00, 0x50, 0x00,
- 0x42, 0x34, 0x43, 0x2e, 0x44, 0x29, 0x49, 0x24, 0x4b, 0x20, 0x4c, 0x1d,
- 0x4e, 0x1a, 0x53, 0x18, 0x55, 0x15, 0x56, 0x13, 0x58, 0x11, 0x5a, 0x10,
- 0x5c, 0x0e, 0x60, 0x0d, 0x63, 0x0c, 0x64, 0x0b, 0x65, 0x0a, 0x66, 0x09,
- 0x68, 0x09, 0x69, 0x07, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x44, 0x0c, 0x3b,
- 0x11, 0x34, 0x16, 0x2e, 0x19, 0x28, 0x1d, 0x23, 0x21, 0x20, 0x25, 0x1d,
- 0x29, 0x19, 0x2b, 0x16, 0x30, 0x14, 0x33, 0x12, 0x35, 0x0f, 0x3a, 0x0f,
- 0x3c, 0x0c, 0x40, 0x0c, 0x41, 0x0a, 0x45, 0x0a, 0x47, 0x09, 0x4a, 0x07,
- 0x60, 0x22, 0x62, 0x1d, 0x64, 0x1a, 0x66, 0x17, 0x68, 0x14, 0x6a, 0x11,
- 0x6c, 0x10, 0x6e, 0x0e, 0x70, 0x0c, 0x71, 0x0b, 0x73, 0x0a, 0x75, 0x09,
- 0x76, 0x07, 0x78, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7c, 0x05, 0x7e, 0x05,
- 0x7f, 0x04, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f, 0x00,
- 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38,
- 0x00, 0x2c, 0x00, 0x1f, 0x00, 0x12, 0x03, 0x09, 0x09, 0x04, 0x10, 0x00,
- 0x1c, 0x00, 0x27, 0x00, 0x31, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88, 0x00,
- 0x79, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00,
- 0x0f, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f, 0x00,
- 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x41, 0x00, 0x33,
- 0x00, 0x24, 0x00, 0x15, 0x00, 0x07, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00,
- 0x2a, 0x00, 0x34, 0x00, 0x3d, 0x00, 0x46, 0x00, 0x42, 0x34, 0x43, 0x2f,
- 0x44, 0x29, 0x49, 0x25, 0x4b, 0x21, 0x4c, 0x1e, 0x4d, 0x1b, 0x51, 0x18,
- 0x55, 0x16, 0x56, 0x14, 0x58, 0x13, 0x59, 0x11, 0x5a, 0x0f, 0x5d, 0x0e,
- 0x61, 0x0c, 0x63, 0x0c, 0x64, 0x0b, 0x65, 0x0a, 0x66, 0x09, 0x68, 0x09,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00,
- 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x44, 0x0c, 0x3c, 0x10, 0x35, 0x15, 0x2f,
- 0x19, 0x2a, 0x1c, 0x25, 0x20, 0x22, 0x23, 0x1d, 0x26, 0x1a, 0x2b, 0x18,
- 0x2e, 0x16, 0x30, 0x12, 0x35, 0x12, 0x37, 0x0f, 0x3b, 0x0f, 0x3d, 0x0c,
- 0x41, 0x0c, 0x42, 0x0a, 0x46, 0x0a, 0x47, 0x09, 0x60, 0x22, 0x62, 0x1e,
- 0x64, 0x1a, 0x66, 0x17, 0x68, 0x15, 0x6a, 0x12, 0x6b, 0x11, 0x6d, 0x0e,
- 0x6e, 0x0d, 0x71, 0x0c, 0x72, 0x0b, 0x74, 0x09, 0x76, 0x09, 0x77, 0x07,
- 0x79, 0x07, 0x7a, 0x06, 0x7c, 0x06, 0x7c, 0x05, 0x7e, 0x05, 0x7f, 0x04,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x22, 0x00, 0x00, 0x5e, 0x00, 0x5d,
- 0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x26,
- 0x00, 0x1a, 0x00, 0x0f, 0x04, 0x08, 0x0a, 0x04, 0x10, 0x00, 0x1b, 0x00,
- 0x25, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9e, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f, 0x00,
- 0x5f, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d, 0x00,
- 0x00, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x22, 0x00, 0x00, 0x5e, 0x00, 0x5d,
- 0x00, 0x57, 0x00, 0x4f, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x1e,
- 0x00, 0x10, 0x00, 0x03, 0x08, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x2a, 0x00,
- 0x33, 0x00, 0x3b, 0x00, 0x4f, 0x2a, 0x56, 0x28, 0x59, 0x27, 0x5a, 0x26,
- 0x5c, 0x26, 0x5c, 0x26, 0x5c, 0x26, 0x5d, 0x26, 0x5d, 0x26, 0x5d, 0x25,
- 0x5d, 0x25, 0x5d, 0x25, 0x5d, 0x25, 0x5d, 0x25, 0x5e, 0x25, 0x5e, 0x25,
- 0x5e, 0x24, 0x5e, 0x24, 0x5e, 0x24, 0x5e, 0x24, 0x92, 0x0e, 0x79, 0x14,
- 0x6f, 0x18, 0x6b, 0x1b, 0x68, 0x1d, 0x67, 0x1d, 0x66, 0x1e, 0x65, 0x1f,
- 0x64, 0x20, 0x64, 0x20, 0x63, 0x20, 0x63, 0x21, 0x63, 0x21, 0x63, 0x21,
- 0x63, 0x21, 0x62, 0x22, 0x62, 0x22, 0x62, 0x22, 0x62, 0x22, 0x62, 0x22,
- 0x16, 0x23, 0x3c, 0x23, 0x4a, 0x23, 0x50, 0x23, 0x54, 0x23, 0x56, 0x23,
- 0x58, 0x23, 0x59, 0x23, 0x5a, 0x23, 0x5a, 0x23, 0x5b, 0x23, 0x5b, 0x23,
- 0x5b, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23,
- 0x5d, 0x23, 0x5d, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0b, 0x00, 0x16, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53,
- 0x00, 0x4b, 0x00, 0x42, 0x00, 0x38, 0x00, 0x2d, 0x00, 0x22, 0x00, 0x17,
- 0x00, 0x0c, 0x05, 0x07, 0x0a, 0x03, 0x0f, 0x00, 0x1a, 0x00, 0x24, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
- 0x97, 0x00, 0x8e, 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57, 0x00,
- 0x47, 0x00, 0x37, 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00,
- 0x0b, 0x00, 0x16, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x52,
- 0x00, 0x49, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c,
- 0x00, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x31, 0x00,
- 0x48, 0x31, 0x4f, 0x2e, 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x29, 0x58, 0x29,
- 0x59, 0x28, 0x59, 0x27, 0x5a, 0x27, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x27,
- 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27,
- 0x5c, 0x27, 0x5c, 0x27, 0xa1, 0x01, 0x88, 0x07, 0x7b, 0x0c, 0x74, 0x0f,
- 0x70, 0x12, 0x6d, 0x14, 0x6b, 0x16, 0x6a, 0x17, 0x69, 0x18, 0x68, 0x19,
- 0x67, 0x1a, 0x66, 0x1b, 0x66, 0x1b, 0x65, 0x1c, 0x65, 0x1c, 0x65, 0x1d,
- 0x65, 0x1d, 0x64, 0x1d, 0x64, 0x1e, 0x64, 0x1e, 0x0a, 0x32, 0x22, 0x25,
- 0x31, 0x24, 0x3b, 0x23, 0x42, 0x23, 0x47, 0x23, 0x4a, 0x23, 0x4d, 0x23,
- 0x4f, 0x23, 0x51, 0x23, 0x52, 0x23, 0x53, 0x23, 0x54, 0x23, 0x55, 0x23,
- 0x56, 0x23, 0x56, 0x23, 0x57, 0x23, 0x58, 0x23, 0x58, 0x23, 0x58, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
- 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45,
- 0x00, 0x3c, 0x00, 0x32, 0x00, 0x28, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x0b,
- 0x06, 0x07, 0x0b, 0x03, 0x0f, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90, 0x00,
- 0x86, 0x00, 0x7a, 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41, 0x00,
- 0x33, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00,
- 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42,
- 0x00, 0x37, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x01, 0x00,
- 0x0c, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x28, 0x00, 0x45, 0x34, 0x4b, 0x31,
- 0x4f, 0x2f, 0x52, 0x2d, 0x54, 0x2c, 0x55, 0x2b, 0x57, 0x2a, 0x57, 0x2a,
- 0x57, 0x2a, 0x57, 0x29, 0x58, 0x29, 0x59, 0x28, 0x59, 0x27, 0x5a, 0x27,
- 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27,
- 0xa7, 0x00, 0x92, 0x03, 0x84, 0x06, 0x7d, 0x09, 0x77, 0x0c, 0x73, 0x0e,
- 0x71, 0x10, 0x6f, 0x11, 0x6d, 0x13, 0x6b, 0x14, 0x6a, 0x15, 0x6a, 0x16,
- 0x69, 0x17, 0x68, 0x17, 0x68, 0x18, 0x67, 0x19, 0x66, 0x19, 0x66, 0x1a,
- 0x66, 0x1a, 0x66, 0x1a, 0x0a, 0x38, 0x18, 0x2b, 0x25, 0x27, 0x2e, 0x25,
- 0x35, 0x24, 0x3b, 0x23, 0x3f, 0x23, 0x43, 0x23, 0x46, 0x23, 0x48, 0x23,
- 0x4a, 0x23, 0x4c, 0x23, 0x4e, 0x23, 0x4f, 0x23, 0x50, 0x23, 0x51, 0x23,
- 0x52, 0x23, 0x53, 0x23, 0x53, 0x23, 0x54, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e,
- 0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x48, 0x00, 0x40, 0x00, 0x37,
- 0x00, 0x2d, 0x00, 0x24, 0x00, 0x1a, 0x00, 0x11, 0x01, 0x0a, 0x06, 0x06,
- 0x0b, 0x03, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00,
- 0x72, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f, 0x00,
- 0x22, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d,
- 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x31,
- 0x00, 0x26, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x06, 0x03, 0x00, 0x0d, 0x00,
- 0x17, 0x00, 0x1f, 0x00, 0x44, 0x36, 0x49, 0x33, 0x4d, 0x31, 0x4f, 0x2f,
- 0x51, 0x2e, 0x53, 0x2d, 0x53, 0x2c, 0x55, 0x2b, 0x56, 0x2a, 0x57, 0x2a,
- 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x29, 0x58, 0x29,
- 0x59, 0x28, 0x5a, 0x27, 0x5b, 0x27, 0x5c, 0x27, 0xaa, 0x00, 0x98, 0x01,
- 0x8c, 0x03, 0x83, 0x05, 0x7d, 0x08, 0x79, 0x0a, 0x76, 0x0c, 0x73, 0x0d,
- 0x71, 0x0f, 0x6f, 0x10, 0x6e, 0x11, 0x6d, 0x12, 0x6c, 0x13, 0x6b, 0x14,
- 0x6a, 0x15, 0x6a, 0x15, 0x69, 0x16, 0x68, 0x17, 0x68, 0x17, 0x68, 0x18,
- 0x0a, 0x3c, 0x14, 0x30, 0x1e, 0x2a, 0x26, 0x27, 0x2d, 0x25, 0x32, 0x24,
- 0x36, 0x24, 0x3b, 0x24, 0x3e, 0x23, 0x41, 0x23, 0x43, 0x23, 0x45, 0x23,
- 0x47, 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23, 0x4d, 0x23, 0x4d, 0x23,
- 0x4f, 0x23, 0x50, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x31, 0x11, 0x5f, 0x00, 0x85, 0x00, 0x92, 0x00,
- 0x97, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00,
- 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x11, 0x03, 0x23,
- 0x00, 0x46, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5a, 0x00, 0x5c, 0x00, 0x5d,
- 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e,
- 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x43, 0x38, 0x48, 0x35, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x30, 0x50, 0x2e,
- 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2c, 0x54, 0x2b, 0x56, 0x2a, 0x57, 0x2a,
- 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a,
- 0x57, 0x2a, 0x58, 0x29, 0xac, 0x00, 0x9d, 0x00, 0x91, 0x02, 0x89, 0x03,
- 0x82, 0x05, 0x7e, 0x07, 0x7a, 0x09, 0x77, 0x0a, 0x75, 0x0c, 0x73, 0x0d,
- 0x71, 0x0e, 0x70, 0x0f, 0x6e, 0x10, 0x6e, 0x11, 0x6c, 0x12, 0x6c, 0x13,
- 0x6b, 0x13, 0x6a, 0x14, 0x6a, 0x15, 0x6a, 0x15, 0x09, 0x3f, 0x11, 0x33,
- 0x1a, 0x2d, 0x21, 0x29, 0x27, 0x27, 0x2c, 0x26, 0x30, 0x25, 0x34, 0x24,
- 0x37, 0x24, 0x3a, 0x24, 0x3d, 0x23, 0x40, 0x23, 0x42, 0x23, 0x44, 0x23,
- 0x45, 0x23, 0x47, 0x23, 0x48, 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x23, 0x20, 0x00, 0x5f, 0x00, 0x7c, 0x00, 0x8a, 0x00, 0x91, 0x00,
- 0x95, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00,
- 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x20, 0x00, 0x00, 0x1f, 0x00, 0x3c,
- 0x00, 0x4a, 0x00, 0x51, 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b,
- 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x39, 0x46, 0x36,
- 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e,
- 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x54, 0x2b, 0x55, 0x2a, 0x57, 0x2a,
- 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a,
- 0xae, 0x00, 0xa1, 0x00, 0x96, 0x01, 0x8d, 0x02, 0x87, 0x03, 0x82, 0x05,
- 0x7e, 0x07, 0x7b, 0x08, 0x78, 0x09, 0x76, 0x0b, 0x74, 0x0c, 0x73, 0x0d,
- 0x71, 0x0e, 0x70, 0x0e, 0x6f, 0x0f, 0x6e, 0x11, 0x6d, 0x11, 0x6c, 0x11,
- 0x6c, 0x12, 0x6b, 0x13, 0x09, 0x40, 0x10, 0x36, 0x17, 0x2f, 0x1d, 0x2c,
- 0x22, 0x29, 0x27, 0x27, 0x2b, 0x26, 0x2f, 0x25, 0x32, 0x25, 0x35, 0x24,
- 0x38, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3f, 0x23, 0x40, 0x23, 0x42, 0x23,
- 0x44, 0x23, 0x45, 0x23, 0x46, 0x23, 0x48, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x1f,
- 0x1f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x79, 0x00, 0x83, 0x00, 0x8a, 0x00,
- 0x8e, 0x00, 0x92, 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00,
- 0x99, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x85, 0x00, 0x5f, 0x00, 0x1f, 0x00, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x39,
- 0x00, 0x43, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x52, 0x00, 0x54, 0x00, 0x56,
- 0x00, 0x57, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x42, 0x39, 0x45, 0x37, 0x48, 0x35, 0x4a, 0x33,
- 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x52, 0x2e, 0x53, 0x2e,
- 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x54, 0x2c, 0x55, 0x2a, 0x57, 0x2a,
- 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0xaf, 0x00, 0xa3, 0x00,
- 0x99, 0x00, 0x91, 0x01, 0x8b, 0x02, 0x86, 0x03, 0x81, 0x05, 0x7e, 0x06,
- 0x7b, 0x07, 0x79, 0x09, 0x77, 0x0a, 0x75, 0x0b, 0x74, 0x0c, 0x73, 0x0c,
- 0x71, 0x0d, 0x71, 0x0e, 0x6f, 0x0f, 0x6e, 0x10, 0x6e, 0x11, 0x6d, 0x11,
- 0x09, 0x41, 0x0f, 0x38, 0x15, 0x32, 0x1a, 0x2e, 0x1f, 0x2b, 0x24, 0x29,
- 0x27, 0x27, 0x2b, 0x26, 0x2e, 0x25, 0x31, 0x25, 0x34, 0x25, 0x36, 0x24,
- 0x38, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3e, 0x23, 0x40, 0x23, 0x41, 0x23,
- 0x43, 0x23, 0x44, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x3c, 0x00, 0x0d, 0x1f, 0x00,
- 0x42, 0x00, 0x5a, 0x00, 0x6a, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x84, 0x00,
- 0x89, 0x00, 0x8c, 0x00, 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x7c, 0x00,
- 0x4d, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x2a, 0x00, 0x36,
- 0x00, 0x3e, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4d, 0x00, 0x4f, 0x00, 0x52,
- 0x00, 0x53, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x42, 0x3a, 0x45, 0x38, 0x47, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x2f, 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
- 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x53, 0x2c, 0x55, 0x2b, 0x57, 0x2a,
- 0x57, 0x2a, 0x57, 0x2a, 0xb0, 0x00, 0xa5, 0x00, 0x9d, 0x00, 0x95, 0x00,
- 0x8e, 0x02, 0x89, 0x02, 0x85, 0x03, 0x81, 0x05, 0x7e, 0x06, 0x7c, 0x07,
- 0x7a, 0x08, 0x78, 0x09, 0x76, 0x0a, 0x75, 0x0b, 0x73, 0x0c, 0x73, 0x0c,
- 0x71, 0x0d, 0x71, 0x0e, 0x70, 0x0e, 0x6e, 0x0f, 0x09, 0x42, 0x0e, 0x39,
- 0x13, 0x33, 0x18, 0x2f, 0x1c, 0x2d, 0x21, 0x2a, 0x24, 0x29, 0x28, 0x27,
- 0x2b, 0x26, 0x2e, 0x26, 0x30, 0x25, 0x33, 0x25, 0x35, 0x25, 0x37, 0x24,
- 0x39, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x3f, 0x23, 0x40, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x58, 0x00, 0x4a, 0x00, 0x28, 0x00, 0x02, 0x1f, 0x00, 0x3b, 0x00,
- 0x4f, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x74, 0x00, 0x7b, 0x00, 0x80, 0x00,
- 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x68, 0x00, 0x42, 0x00,
- 0x1f, 0x00, 0x04, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x34,
- 0x00, 0x3b, 0x00, 0x41, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4b, 0x00, 0x4e,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39,
- 0x46, 0x36, 0x49, 0x35, 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x2f, 0x51, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
- 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2c, 0x54, 0x2b, 0x56, 0x2a,
- 0xb1, 0x00, 0xa8, 0x00, 0x9f, 0x00, 0x98, 0x00, 0x91, 0x01, 0x8c, 0x02,
- 0x88, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7e, 0x06, 0x7c, 0x07, 0x7a, 0x07,
- 0x79, 0x09, 0x77, 0x09, 0x76, 0x0b, 0x74, 0x0b, 0x73, 0x0c, 0x73, 0x0c,
- 0x71, 0x0d, 0x71, 0x0e, 0x09, 0x43, 0x0e, 0x3b, 0x12, 0x35, 0x16, 0x31,
- 0x1a, 0x2e, 0x1e, 0x2c, 0x22, 0x2a, 0x25, 0x28, 0x28, 0x27, 0x2a, 0x27,
- 0x2d, 0x26, 0x30, 0x25, 0x32, 0x25, 0x34, 0x25, 0x35, 0x25, 0x37, 0x24,
- 0x39, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x51,
- 0x00, 0x39, 0x00, 0x1a, 0x04, 0x00, 0x1f, 0x00, 0x36, 0x00, 0x48, 0x00,
- 0x57, 0x00, 0x62, 0x00, 0x6b, 0x00, 0x73, 0x00, 0x79, 0x00, 0x7e, 0x00,
- 0x82, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9a, 0x00, 0x91, 0x00, 0x79, 0x00, 0x5a, 0x00, 0x3b, 0x00, 0x1f, 0x00,
- 0x09, 0x00, 0x00, 0x08, 0x00, 0x17, 0x00, 0x22, 0x00, 0x2c, 0x00, 0x33,
- 0x00, 0x39, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39, 0x46, 0x37, 0x48, 0x35,
- 0x4a, 0x35, 0x4a, 0x34, 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
- 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0xb1, 0x00, 0xa9, 0x00,
- 0xa1, 0x00, 0x9a, 0x00, 0x94, 0x00, 0x8f, 0x01, 0x8b, 0x02, 0x87, 0x03,
- 0x84, 0x04, 0x81, 0x05, 0x7f, 0x06, 0x7d, 0x06, 0x7b, 0x07, 0x79, 0x08,
- 0x78, 0x09, 0x76, 0x0a, 0x76, 0x0b, 0x74, 0x0b, 0x73, 0x0c, 0x72, 0x0c,
- 0x09, 0x44, 0x0d, 0x3c, 0x11, 0x36, 0x15, 0x33, 0x19, 0x30, 0x1c, 0x2d,
- 0x20, 0x2b, 0x23, 0x2a, 0x25, 0x28, 0x28, 0x27, 0x2a, 0x27, 0x2d, 0x26,
- 0x2f, 0x26, 0x31, 0x25, 0x33, 0x25, 0x34, 0x25, 0x36, 0x24, 0x38, 0x24,
- 0x39, 0x24, 0x3a, 0x24, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x43, 0x00, 0x2a,
- 0x00, 0x10, 0x09, 0x00, 0x1f, 0x00, 0x33, 0x00, 0x43, 0x00, 0x50, 0x00,
- 0x5b, 0x00, 0x64, 0x00, 0x6b, 0x00, 0x72, 0x00, 0x77, 0x00, 0x7b, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x95, 0x00,
- 0x83, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x0c, 0x00,
- 0x00, 0x03, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32,
- 0x00, 0x37, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x42, 0x3c, 0x43, 0x39, 0x46, 0x38, 0x46, 0x35, 0x4a, 0x35, 0x4a, 0x35,
- 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x30,
- 0x50, 0x2e, 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
- 0x53, 0x2e, 0x53, 0x2e, 0xb2, 0x00, 0xaa, 0x00, 0xa2, 0x00, 0x9c, 0x00,
- 0x96, 0x00, 0x91, 0x01, 0x8d, 0x02, 0x89, 0x02, 0x86, 0x03, 0x83, 0x04,
- 0x81, 0x05, 0x7f, 0x06, 0x7d, 0x06, 0x7b, 0x07, 0x79, 0x07, 0x79, 0x09,
- 0x77, 0x09, 0x76, 0x0a, 0x75, 0x0b, 0x74, 0x0b, 0x0a, 0x44, 0x0d, 0x3d,
- 0x10, 0x38, 0x14, 0x34, 0x17, 0x31, 0x1b, 0x2e, 0x1e, 0x2d, 0x21, 0x2b,
- 0x23, 0x2a, 0x26, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2d, 0x26, 0x2e, 0x26,
- 0x30, 0x25, 0x32, 0x25, 0x34, 0x25, 0x35, 0x25, 0x36, 0x24, 0x38, 0x24,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x08,
- 0x0c, 0x00, 0x1f, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x55, 0x00,
- 0x5e, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x76, 0x00,
- 0x5f, 0x00, 0x48, 0x00, 0x33, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00, 0x00,
- 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x25, 0x00, 0x2c, 0x00, 0x31,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3c, 0x43, 0x39,
- 0x46, 0x39, 0x46, 0x37, 0x49, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4b, 0x32,
- 0x4e, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x2f,
- 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
- 0xb2, 0x00, 0xab, 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x98, 0x00, 0x93, 0x00,
- 0x8f, 0x01, 0x8b, 0x02, 0x88, 0x02, 0x85, 0x03, 0x83, 0x04, 0x81, 0x05,
- 0x7f, 0x06, 0x7d, 0x06, 0x7c, 0x07, 0x7a, 0x07, 0x79, 0x08, 0x78, 0x09,
- 0x76, 0x09, 0x76, 0x0a, 0x0a, 0x44, 0x0c, 0x3e, 0x10, 0x39, 0x13, 0x35,
- 0x16, 0x32, 0x19, 0x30, 0x1c, 0x2e, 0x1f, 0x2c, 0x21, 0x2b, 0x24, 0x2a,
- 0x26, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x26, 0x2e, 0x26, 0x30, 0x25,
- 0x31, 0x25, 0x33, 0x25, 0x34, 0x25, 0x36, 0x25, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59,
- 0x00, 0x4e, 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x17, 0x00, 0x03, 0x0f, 0x00,
- 0x1f, 0x00, 0x2e, 0x00, 0x3b, 0x00, 0x46, 0x00, 0x50, 0x00, 0x59, 0x00,
- 0x60, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x6b, 0x00, 0x57, 0x00,
- 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x11, 0x00, 0x04, 0x00, 0x00, 0x07,
- 0x00, 0x10, 0x00, 0x19, 0x00, 0x20, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x39, 0x46, 0x39, 0x46, 0x38,
- 0x47, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x2f, 0x51, 0x2e,
- 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0xb2, 0x00, 0xac, 0x00,
- 0xa5, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x91, 0x01, 0x8e, 0x01,
- 0x8a, 0x02, 0x88, 0x02, 0x85, 0x03, 0x83, 0x04, 0x81, 0x05, 0x7f, 0x05,
- 0x7d, 0x06, 0x7c, 0x07, 0x7a, 0x07, 0x79, 0x07, 0x78, 0x09, 0x77, 0x09,
- 0x0a, 0x44, 0x0c, 0x3f, 0x0f, 0x3a, 0x12, 0x36, 0x15, 0x33, 0x18, 0x30,
- 0x1b, 0x2e, 0x1d, 0x2d, 0x20, 0x2b, 0x22, 0x2a, 0x24, 0x2a, 0x26, 0x28,
- 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x26, 0x2e, 0x26, 0x2f, 0x26, 0x31, 0x25,
- 0x33, 0x25, 0x33, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x52, 0x00, 0x45,
- 0x00, 0x34, 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x11, 0x00, 0x1f, 0x00,
- 0x2d, 0x00, 0x38, 0x00, 0x43, 0x00, 0x4c, 0x00, 0x54, 0x00, 0x5b, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00,
- 0x92, 0x00, 0x84, 0x00, 0x74, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f, 0x00,
- 0x2e, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0c,
- 0x00, 0x14, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x42, 0x3d, 0x42, 0x3a, 0x45, 0x39, 0x46, 0x39, 0x46, 0x36, 0x49, 0x35,
- 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e,
- 0x53, 0x2e, 0x53, 0x2e, 0xb3, 0x00, 0xac, 0x00, 0xa7, 0x00, 0xa1, 0x00,
- 0x9b, 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8c, 0x02, 0x89, 0x02,
- 0x87, 0x02, 0x85, 0x03, 0x82, 0x04, 0x81, 0x05, 0x7f, 0x05, 0x7d, 0x06,
- 0x7c, 0x06, 0x7b, 0x07, 0x79, 0x07, 0x79, 0x08, 0x0a, 0x45, 0x0c, 0x3f,
- 0x0f, 0x3a, 0x11, 0x37, 0x14, 0x34, 0x17, 0x32, 0x1a, 0x30, 0x1c, 0x2e,
- 0x1e, 0x2d, 0x21, 0x2b, 0x22, 0x2a, 0x25, 0x2a, 0x26, 0x28, 0x28, 0x28,
- 0x2a, 0x27, 0x2c, 0x27, 0x2d, 0x26, 0x2f, 0x26, 0x30, 0x25, 0x32, 0x25,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3b, 0x00, 0x2c,
- 0x00, 0x1b, 0x00, 0x0b, 0x04, 0x00, 0x12, 0x00, 0x1f, 0x00, 0x2b, 0x00,
- 0x36, 0x00, 0x40, 0x00, 0x49, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x94, 0x00, 0x89, 0x00,
- 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2d, 0x00,
- 0x1f, 0x00, 0x13, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3a,
- 0x44, 0x39, 0x46, 0x39, 0x46, 0x37, 0x48, 0x35, 0x4a, 0x35, 0x4a, 0x35,
- 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e, 0x53, 0x2e,
- 0xb3, 0x00, 0xad, 0x00, 0xa7, 0x00, 0xa3, 0x00, 0x9d, 0x00, 0x99, 0x00,
- 0x95, 0x00, 0x91, 0x01, 0x8e, 0x01, 0x8b, 0x02, 0x88, 0x02, 0x86, 0x02,
- 0x84, 0x03, 0x82, 0x04, 0x81, 0x05, 0x7f, 0x05, 0x7e, 0x06, 0x7c, 0x06,
- 0x7b, 0x07, 0x7a, 0x07, 0x0a, 0x45, 0x0c, 0x40, 0x0e, 0x3b, 0x11, 0x38,
- 0x13, 0x35, 0x16, 0x32, 0x18, 0x30, 0x1b, 0x2e, 0x1d, 0x2d, 0x1f, 0x2c,
- 0x21, 0x2b, 0x23, 0x2a, 0x25, 0x29, 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27,
- 0x2c, 0x27, 0x2d, 0x26, 0x2f, 0x26, 0x2f, 0x25, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c,
- 0x00, 0x56, 0x00, 0x4d, 0x00, 0x41, 0x00, 0x33, 0x00, 0x24, 0x00, 0x15,
- 0x00, 0x07, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x34, 0x00,
- 0x3d, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x73, 0x00,
- 0x64, 0x00, 0x55, 0x00, 0x46, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f, 0x00,
- 0x14, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3b, 0x44, 0x39, 0x46, 0x39,
- 0x46, 0x38, 0x47, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x34,
- 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2f, 0x52, 0x2e, 0xb3, 0x00, 0xae, 0x00,
- 0xa8, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x93, 0x00,
- 0x8f, 0x01, 0x8d, 0x02, 0x8a, 0x02, 0x88, 0x02, 0x86, 0x03, 0x84, 0x03,
- 0x82, 0x04, 0x81, 0x05, 0x7f, 0x05, 0x7e, 0x06, 0x7c, 0x06, 0x7c, 0x07,
- 0x0a, 0x45, 0x0c, 0x40, 0x0e, 0x3c, 0x11, 0x38, 0x13, 0x36, 0x15, 0x33,
- 0x18, 0x31, 0x1a, 0x30, 0x1c, 0x2e, 0x1e, 0x2d, 0x20, 0x2b, 0x22, 0x2b,
- 0x23, 0x2a, 0x25, 0x29, 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x27,
- 0x2d, 0x26, 0x2f, 0x26, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x57, 0x00, 0x4f,
- 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x1e, 0x00, 0x10, 0x00, 0x03,
- 0x08, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x33, 0x00, 0x3b, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
- 0x97, 0x00, 0x8f, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6b, 0x00, 0x5e, 0x00,
- 0x50, 0x00, 0x43, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x15, 0x00,
- 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x42, 0x3d, 0x42, 0x3c, 0x43, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x36,
- 0x49, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4c, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x2f, 0xb3, 0x00, 0xae, 0x00, 0xa9, 0x00, 0xa4, 0x00,
- 0xa0, 0x00, 0x9b, 0x00, 0x98, 0x00, 0x94, 0x00, 0x91, 0x01, 0x8e, 0x01,
- 0x8c, 0x02, 0x89, 0x02, 0x87, 0x02, 0x86, 0x03, 0x84, 0x03, 0x82, 0x04,
- 0x80, 0x05, 0x7f, 0x05, 0x7e, 0x06, 0x7c, 0x06, 0x0a, 0x45, 0x0b, 0x40,
- 0x0e, 0x3c, 0x10, 0x39, 0x12, 0x37, 0x14, 0x34, 0x17, 0x32, 0x19, 0x30,
- 0x1b, 0x2e, 0x1d, 0x2d, 0x1f, 0x2d, 0x20, 0x2b, 0x22, 0x2b, 0x24, 0x2a,
- 0x25, 0x29, 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x27, 0x2c, 0x26,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x52, 0x00, 0x49, 0x00, 0x3e,
- 0x00, 0x32, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x0a, 0x00,
- 0x15, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x91, 0x00,
- 0x88, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00,
- 0x40, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0d, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3c,
- 0x43, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x37, 0x48, 0x35, 0x4a, 0x35,
- 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0xb3, 0x00, 0xae, 0x00, 0xaa, 0x00, 0xa5, 0x00, 0xa1, 0x00, 0x9d, 0x00,
- 0x99, 0x00, 0x96, 0x00, 0x93, 0x00, 0x90, 0x01, 0x8d, 0x01, 0x8b, 0x02,
- 0x89, 0x02, 0x87, 0x02, 0x85, 0x03, 0x83, 0x03, 0x82, 0x04, 0x80, 0x05,
- 0x7f, 0x05, 0x7e, 0x06, 0x0a, 0x45, 0x0b, 0x41, 0x0e, 0x3d, 0x10, 0x3a,
- 0x11, 0x37, 0x14, 0x34, 0x16, 0x32, 0x18, 0x31, 0x1a, 0x30, 0x1c, 0x2e,
- 0x1d, 0x2d, 0x20, 0x2c, 0x21, 0x2b, 0x22, 0x2a, 0x24, 0x2a, 0x25, 0x29,
- 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x27, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d,
- 0x00, 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42, 0x00, 0x37, 0x00, 0x2c,
- 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x01, 0x00, 0x0c, 0x00, 0x16, 0x00,
- 0x1f, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82, 0x00,
- 0x77, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3d, 0x00,
- 0x33, 0x00, 0x29, 0x00, 0x1f, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x39, 0x46, 0x39,
- 0x46, 0x39, 0x46, 0x39, 0x46, 0x36, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35,
- 0x4a, 0x35, 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0xb4, 0x00, 0xaf, 0x00,
- 0xaa, 0x00, 0xa6, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x9a, 0x00, 0x97, 0x00,
- 0x94, 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8c, 0x02, 0x8a, 0x02, 0x88, 0x02,
- 0x86, 0x02, 0x85, 0x03, 0x83, 0x03, 0x82, 0x04, 0x80, 0x05, 0x7f, 0x05,
- 0x0a, 0x45, 0x0b, 0x41, 0x0d, 0x3e, 0x10, 0x3a, 0x11, 0x38, 0x13, 0x35,
- 0x16, 0x33, 0x17, 0x32, 0x19, 0x30, 0x1b, 0x2e, 0x1d, 0x2e, 0x1e, 0x2d,
- 0x20, 0x2b, 0x22, 0x2b, 0x23, 0x2a, 0x25, 0x2a, 0x25, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x2a, 0x27, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55,
- 0x00, 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x31, 0x00, 0x26, 0x00, 0x1b,
- 0x00, 0x11, 0x00, 0x06, 0x03, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x1f, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00,
- 0x9a, 0x00, 0x95, 0x00, 0x8d, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00,
- 0x66, 0x00, 0x5b, 0x00, 0x50, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x31, 0x00,
- 0x28, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3a, 0x45, 0x39, 0x46, 0x39, 0x46, 0x39,
- 0x46, 0x37, 0x49, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35,
- 0x4a, 0x34, 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31,
- 0x4f, 0x31, 0x4f, 0x31, 0xb4, 0x00, 0xaf, 0x00, 0xab, 0x00, 0xa7, 0x00,
- 0xa3, 0x00, 0x9f, 0x00, 0x9b, 0x00, 0x98, 0x00, 0x95, 0x00, 0x92, 0x00,
- 0x90, 0x01, 0x8d, 0x01, 0x8b, 0x02, 0x89, 0x02, 0x88, 0x02, 0x86, 0x02,
- 0x85, 0x03, 0x82, 0x03, 0x82, 0x04, 0x80, 0x05, 0x0a, 0x46, 0x0b, 0x42,
- 0x0d, 0x3e, 0x0f, 0x3b, 0x11, 0x38, 0x13, 0x36, 0x15, 0x34, 0x16, 0x32,
- 0x18, 0x30, 0x1a, 0x30, 0x1c, 0x2e, 0x1d, 0x2d, 0x20, 0x2d, 0x20, 0x2b,
- 0x22, 0x2b, 0x23, 0x2a, 0x25, 0x2a, 0x26, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23,
- 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x32, 0x74, 0x38, 0x57, 0x3a, 0x4f, 0x3c, 0x4b, 0x3c, 0x49, 0x3d, 0x47,
- 0x3d, 0x46, 0x3d, 0x45, 0x3d, 0x45, 0x3d, 0x44, 0x3d, 0x43, 0x3d, 0x43,
- 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42,
- 0x3d, 0x42, 0x3d, 0x42, 0x41, 0x09, 0x1b, 0x31, 0x27, 0x38, 0x2d, 0x3a,
- 0x31, 0x3b, 0x33, 0x3c, 0x35, 0x3c, 0x36, 0x3d, 0x37, 0x3d, 0x38, 0x3d,
- 0x38, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d,
- 0x3b, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x73, 0x00, 0x38, 0x31,
- 0x3a, 0x38, 0x3c, 0x3a, 0x3c, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, 0x3d,
- 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
- 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x0d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x2f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x3d, 0x28, 0x38, 0x30,
- 0x38, 0x34, 0x39, 0x36, 0x39, 0x38, 0x3a, 0x39, 0x3a, 0x39, 0x3b, 0x3a,
- 0x3b, 0x3b, 0x3c, 0x3b, 0x3c, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3e, 0x3c,
- 0x3e, 0x3c, 0x3e, 0x3c, 0x3e, 0x3c, 0x3e, 0x3d, 0x3e, 0x3d, 0x3e, 0x3d,
- 0x00, 0x7e, 0x05, 0x58, 0x0f, 0x4e, 0x17, 0x49, 0x1d, 0x47, 0x21, 0x45,
- 0x24, 0x44, 0x27, 0x43, 0x29, 0x43, 0x2b, 0x43, 0x2d, 0x43, 0x2e, 0x42,
- 0x2f, 0x42, 0x31, 0x42, 0x31, 0x42, 0x32, 0x42, 0x33, 0x42, 0x33, 0x42,
- 0x34, 0x42, 0x34, 0x42, 0x2b, 0x4e, 0x31, 0x47, 0x34, 0x45, 0x36, 0x44,
- 0x38, 0x43, 0x39, 0x42, 0x39, 0x42, 0x3a, 0x41, 0x3b, 0x41, 0x3b, 0x41,
- 0x3c, 0x41, 0x3c, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41,
- 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x4f, 0x00, 0x04, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x2f, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x16, 0x3a, 0x20, 0x39, 0x25, 0x39, 0x29,
- 0x39, 0x2d, 0x39, 0x2f, 0x3a, 0x31, 0x3a, 0x32, 0x3b, 0x33, 0x3a, 0x34,
- 0x3a, 0x35, 0x3a, 0x36, 0x3a, 0x36, 0x3b, 0x37, 0x3b, 0x37, 0x3c, 0x38,
- 0x3c, 0x38, 0x3d, 0x38, 0x3e, 0x39, 0x3e, 0x39, 0x00, 0x93, 0x01, 0x70,
- 0x06, 0x60, 0x0d, 0x56, 0x12, 0x52, 0x16, 0x4e, 0x1a, 0x4c, 0x1d, 0x4a,
- 0x20, 0x48, 0x22, 0x47, 0x24, 0x46, 0x26, 0x45, 0x27, 0x44, 0x29, 0x44,
- 0x2a, 0x44, 0x2b, 0x44, 0x2c, 0x43, 0x2d, 0x43, 0x2e, 0x43, 0x2f, 0x43,
- 0x28, 0x56, 0x2e, 0x4f, 0x31, 0x4b, 0x33, 0x49, 0x35, 0x48, 0x36, 0x46,
- 0x37, 0x45, 0x38, 0x45, 0x39, 0x44, 0x39, 0x44, 0x39, 0x43, 0x39, 0x43,
- 0x39, 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b, 0x42, 0x3c, 0x42, 0x3c, 0x42,
- 0x3d, 0x42, 0x3d, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x8f, 0x00, 0x73, 0x00, 0x38, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x45, 0x00, 0x22, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x43, 0x11, 0x3d, 0x18, 0x3b, 0x1e, 0x3a, 0x22, 0x39, 0x25, 0x39, 0x28,
- 0x39, 0x2a, 0x39, 0x2c, 0x39, 0x2d, 0x3a, 0x2f, 0x3b, 0x30, 0x3b, 0x31,
- 0x3b, 0x32, 0x3b, 0x33, 0x3a, 0x33, 0x3a, 0x34, 0x3a, 0x34, 0x3a, 0x35,
- 0x3a, 0x35, 0x3b, 0x35, 0x00, 0x9d, 0x00, 0x7f, 0x03, 0x6d, 0x07, 0x62,
- 0x0c, 0x5b, 0x10, 0x56, 0x13, 0x52, 0x16, 0x50, 0x19, 0x4d, 0x1c, 0x4c,
- 0x1e, 0x4b, 0x1f, 0x4b, 0x22, 0x4a, 0x23, 0x49, 0x24, 0x48, 0x25, 0x47,
- 0x27, 0x46, 0x28, 0x45, 0x29, 0x44, 0x29, 0x44, 0x27, 0x59, 0x2c, 0x53,
- 0x2f, 0x4f, 0x31, 0x4d, 0x32, 0x4b, 0x34, 0x4a, 0x35, 0x48, 0x35, 0x47,
- 0x36, 0x46, 0x37, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x45,
- 0x39, 0x44, 0x39, 0x44, 0x39, 0x43, 0x39, 0x43, 0x39, 0x42, 0x3a, 0x42,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x84,
- 0x00, 0x5b, 0x00, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x59, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x44, 0x0f, 0x3e, 0x14,
- 0x3c, 0x19, 0x3a, 0x1d, 0x3a, 0x20, 0x39, 0x23, 0x3a, 0x25, 0x3a, 0x27,
- 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2c, 0x3a, 0x2c, 0x3b, 0x2d, 0x3b, 0x2f,
- 0x3b, 0x2f, 0x3b, 0x30, 0x3b, 0x31, 0x3b, 0x32, 0x3a, 0x32, 0x3a, 0x33,
- 0x00, 0xa3, 0x00, 0x88, 0x01, 0x77, 0x04, 0x6b, 0x08, 0x63, 0x0b, 0x5d,
- 0x0e, 0x59, 0x11, 0x57, 0x14, 0x54, 0x16, 0x51, 0x19, 0x4f, 0x1a, 0x4d,
- 0x1c, 0x4c, 0x1e, 0x4c, 0x1f, 0x4b, 0x21, 0x4b, 0x22, 0x4a, 0x23, 0x49,
- 0x24, 0x49, 0x25, 0x49, 0x27, 0x5a, 0x2a, 0x55, 0x2d, 0x52, 0x2f, 0x4f,
- 0x31, 0x4e, 0x32, 0x4b, 0x33, 0x4a, 0x35, 0x4a, 0x35, 0x49, 0x35, 0x48,
- 0x35, 0x46, 0x37, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46,
- 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x45, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x8d, 0x00, 0x6f, 0x00, 0x48,
- 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x55, 0x00,
- 0x42, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x45, 0x0e, 0x40, 0x12, 0x3d, 0x16, 0x3b, 0x1a,
- 0x3b, 0x1d, 0x3a, 0x20, 0x39, 0x22, 0x39, 0x23, 0x3a, 0x25, 0x3a, 0x26,
- 0x3a, 0x28, 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2b, 0x3a, 0x2c, 0x3b, 0x2d,
- 0x3c, 0x2e, 0x3b, 0x2e, 0x3b, 0x2f, 0x3b, 0x30, 0x00, 0xa7, 0x00, 0x90,
- 0x00, 0x7e, 0x02, 0x73, 0x05, 0x6a, 0x08, 0x65, 0x0b, 0x5f, 0x0d, 0x5b,
- 0x10, 0x58, 0x12, 0x56, 0x14, 0x55, 0x16, 0x52, 0x18, 0x50, 0x1a, 0x4e,
- 0x1b, 0x4d, 0x1d, 0x4c, 0x1e, 0x4c, 0x1f, 0x4b, 0x20, 0x4b, 0x21, 0x4b,
- 0x26, 0x5b, 0x2a, 0x57, 0x2c, 0x54, 0x2e, 0x51, 0x30, 0x4f, 0x31, 0x4e,
- 0x31, 0x4c, 0x33, 0x4a, 0x34, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x49,
- 0x35, 0x47, 0x36, 0x46, 0x37, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46,
- 0x39, 0x46, 0x39, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x9b, 0x00, 0x92, 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x38, 0x00,
- 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x46, 0x0d, 0x41, 0x11, 0x3d, 0x14, 0x3d, 0x17, 0x3b, 0x1a, 0x3b, 0x1c,
- 0x3b, 0x1e, 0x39, 0x21, 0x39, 0x22, 0x3a, 0x23, 0x3a, 0x25, 0x3a, 0x26,
- 0x3a, 0x28, 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2a, 0x39, 0x2b, 0x3b, 0x2c,
- 0x3c, 0x2d, 0x3c, 0x2e, 0x00, 0xa9, 0x00, 0x95, 0x00, 0x85, 0x01, 0x79,
- 0x03, 0x70, 0x06, 0x69, 0x08, 0x65, 0x0b, 0x61, 0x0d, 0x5c, 0x0f, 0x59,
- 0x11, 0x58, 0x13, 0x56, 0x14, 0x55, 0x16, 0x53, 0x18, 0x51, 0x19, 0x4f,
- 0x1b, 0x4d, 0x1c, 0x4d, 0x1d, 0x4c, 0x1e, 0x4c, 0x26, 0x5c, 0x29, 0x58,
- 0x2b, 0x55, 0x2d, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4d,
- 0x32, 0x4b, 0x34, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x49,
- 0x35, 0x48, 0x35, 0x47, 0x36, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x95,
- 0x00, 0x84, 0x00, 0x6c, 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e, 0x00,
- 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x46, 0x0c, 0x42, 0x0f,
- 0x3f, 0x13, 0x3d, 0x15, 0x3c, 0x18, 0x3a, 0x1a, 0x3b, 0x1c, 0x3b, 0x1e,
- 0x39, 0x20, 0x39, 0x21, 0x39, 0x22, 0x3b, 0x24, 0x3a, 0x25, 0x3a, 0x26,
- 0x3a, 0x27, 0x39, 0x28, 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2a, 0x3a, 0x2b,
- 0x00, 0xab, 0x00, 0x99, 0x00, 0x8b, 0x01, 0x7e, 0x02, 0x77, 0x04, 0x6f,
- 0x06, 0x69, 0x08, 0x66, 0x0b, 0x62, 0x0d, 0x5e, 0x0e, 0x5b, 0x10, 0x59,
- 0x12, 0x57, 0x13, 0x56, 0x15, 0x55, 0x16, 0x54, 0x18, 0x52, 0x19, 0x50,
- 0x1a, 0x4e, 0x1b, 0x4d, 0x26, 0x5c, 0x28, 0x59, 0x2a, 0x57, 0x2c, 0x53,
- 0x2e, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4e, 0x31, 0x4c,
- 0x33, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
- 0x35, 0x49, 0x35, 0x48, 0x36, 0x46, 0x37, 0x46, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76,
- 0x00, 0x5e, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00,
- 0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29, 0x00, 0x1a, 0x00, 0x0c, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x46, 0x0c, 0x42, 0x0e, 0x40, 0x11, 0x3d, 0x13,
- 0x3d, 0x16, 0x3b, 0x18, 0x3b, 0x1a, 0x3c, 0x1c, 0x3b, 0x1e, 0x3a, 0x1f,
- 0x39, 0x21, 0x39, 0x21, 0x3a, 0x23, 0x3b, 0x24, 0x3a, 0x25, 0x3a, 0x26,
- 0x3a, 0x27, 0x39, 0x27, 0x39, 0x28, 0x39, 0x2a, 0x00, 0xac, 0x00, 0x9c,
- 0x00, 0x8f, 0x00, 0x83, 0x02, 0x7b, 0x03, 0x74, 0x05, 0x6d, 0x07, 0x69,
- 0x09, 0x66, 0x0b, 0x63, 0x0c, 0x5f, 0x0e, 0x5c, 0x0f, 0x5a, 0x11, 0x58,
- 0x12, 0x57, 0x14, 0x56, 0x15, 0x55, 0x16, 0x55, 0x18, 0x53, 0x18, 0x51,
- 0x26, 0x5d, 0x27, 0x59, 0x2a, 0x57, 0x2b, 0x55, 0x2e, 0x53, 0x2e, 0x53,
- 0x2f, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4d, 0x32, 0x4b,
- 0x34, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
- 0x35, 0x4a, 0x35, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53,
- 0x00, 0x3c, 0x00, 0x26, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x4b, 0x00,
- 0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x47, 0x0b, 0x42, 0x0d, 0x41, 0x10, 0x3e, 0x13, 0x3d, 0x15, 0x3c, 0x17,
- 0x3a, 0x19, 0x3b, 0x1a, 0x3c, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f, 0x39, 0x20,
- 0x39, 0x21, 0x3a, 0x22, 0x3b, 0x23, 0x3b, 0x24, 0x3a, 0x25, 0x3a, 0x26,
- 0x3a, 0x27, 0x39, 0x27, 0x00, 0xad, 0x00, 0x9f, 0x00, 0x92, 0x00, 0x88,
- 0x01, 0x7e, 0x02, 0x78, 0x04, 0x72, 0x05, 0x6d, 0x07, 0x69, 0x09, 0x66,
- 0x0a, 0x64, 0x0c, 0x61, 0x0d, 0x5d, 0x0f, 0x5a, 0x10, 0x59, 0x11, 0x58,
- 0x13, 0x57, 0x14, 0x56, 0x15, 0x55, 0x16, 0x55, 0x26, 0x5d, 0x27, 0x5a,
- 0x2a, 0x57, 0x2a, 0x56, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4e, 0x32, 0x4b, 0x33, 0x4a,
- 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a,
- 0x00, 0x91, 0x00, 0x83, 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36,
- 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38, 0x00,
- 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0b, 0x43, 0x0d,
- 0x41, 0x0f, 0x3f, 0x12, 0x3d, 0x13, 0x3e, 0x15, 0x3c, 0x17, 0x3a, 0x19,
- 0x3a, 0x1a, 0x3c, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f, 0x39, 0x1f, 0x39, 0x21,
- 0x39, 0x21, 0x3b, 0x22, 0x3b, 0x24, 0x3a, 0x24, 0x3a, 0x24, 0x3a, 0x26,
- 0x00, 0xae, 0x00, 0xa2, 0x00, 0x94, 0x00, 0x8b, 0x00, 0x82, 0x02, 0x7b,
- 0x03, 0x76, 0x05, 0x71, 0x06, 0x6c, 0x07, 0x69, 0x09, 0x66, 0x0a, 0x64,
- 0x0c, 0x62, 0x0d, 0x5f, 0x0e, 0x5b, 0x10, 0x5a, 0x10, 0x58, 0x12, 0x58,
- 0x13, 0x56, 0x14, 0x56, 0x25, 0x5d, 0x27, 0x5b, 0x29, 0x57, 0x2a, 0x57,
- 0x2b, 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4e, 0x31, 0x4d, 0x33, 0x4a, 0x34, 0x4a,
- 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88,
- 0x00, 0x79, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f,
- 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00,
- 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x28, 0x00,
- 0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0b, 0x43, 0x0d, 0x42, 0x0f, 0x40, 0x11,
- 0x3d, 0x13, 0x3e, 0x14, 0x3c, 0x16, 0x3b, 0x17, 0x3a, 0x19, 0x3b, 0x1a,
- 0x3c, 0x1c, 0x3b, 0x1d, 0x3b, 0x1f, 0x39, 0x1f, 0x39, 0x20, 0x39, 0x21,
- 0x3a, 0x21, 0x3b, 0x22, 0x3b, 0x24, 0x3a, 0x24, 0x00, 0xae, 0x00, 0xa3,
- 0x00, 0x97, 0x00, 0x8e, 0x00, 0x86, 0x01, 0x7e, 0x02, 0x79, 0x03, 0x75,
- 0x05, 0x70, 0x06, 0x6b, 0x07, 0x68, 0x09, 0x66, 0x0a, 0x64, 0x0b, 0x63,
- 0x0c, 0x5f, 0x0e, 0x5d, 0x0f, 0x5a, 0x10, 0x59, 0x11, 0x58, 0x13, 0x58,
- 0x25, 0x5d, 0x27, 0x5c, 0x29, 0x58, 0x2a, 0x57, 0x2a, 0x56, 0x2d, 0x53,
- 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x51, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4d, 0x32, 0x4b, 0x33, 0x4a, 0x35, 0x4a,
- 0x35, 0x4a, 0x35, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f,
- 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00,
- 0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e, 0x00, 0x24, 0x00, 0x1a, 0x00,
- 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x47, 0x0b, 0x44, 0x0d, 0x42, 0x0e, 0x41, 0x10, 0x3e, 0x12, 0x3d, 0x13,
- 0x3e, 0x15, 0x3c, 0x17, 0x3a, 0x18, 0x3b, 0x19, 0x3b, 0x1a, 0x3c, 0x1c,
- 0x3b, 0x1c, 0x3b, 0x1e, 0x39, 0x1f, 0x39, 0x20, 0x39, 0x21, 0x39, 0x21,
- 0x3b, 0x22, 0x3b, 0x23, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00, 0x90,
- 0x00, 0x8a, 0x01, 0x81, 0x02, 0x7c, 0x02, 0x77, 0x04, 0x74, 0x05, 0x6f,
- 0x06, 0x6a, 0x07, 0x68, 0x09, 0x66, 0x0a, 0x64, 0x0b, 0x63, 0x0c, 0x61,
- 0x0e, 0x5e, 0x0e, 0x5b, 0x10, 0x5a, 0x10, 0x59, 0x25, 0x5d, 0x27, 0x5c,
- 0x28, 0x59, 0x2a, 0x57, 0x2a, 0x57, 0x2b, 0x54, 0x2e, 0x53, 0x2e, 0x53,
- 0x2e, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x4e, 0x31, 0x4c, 0x33, 0x4a, 0x34, 0x4a, 0x35, 0x4a,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c,
- 0x00, 0x97, 0x00, 0x8e, 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57,
- 0x00, 0x47, 0x00, 0x37, 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x46, 0x00,
- 0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00,
- 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x44, 0x0d,
- 0x42, 0x0e, 0x41, 0x0f, 0x3f, 0x11, 0x3d, 0x13, 0x3e, 0x14, 0x3d, 0x15,
- 0x3c, 0x17, 0x3a, 0x18, 0x3a, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c,
- 0x3b, 0x1e, 0x39, 0x1f, 0x39, 0x1f, 0x39, 0x21, 0x39, 0x21, 0x3a, 0x21,
- 0x00, 0xaf, 0x00, 0xa6, 0x00, 0x9c, 0x00, 0x92, 0x00, 0x8c, 0x00, 0x85,
- 0x01, 0x7e, 0x02, 0x7a, 0x03, 0x76, 0x05, 0x73, 0x06, 0x6e, 0x07, 0x6a,
- 0x08, 0x68, 0x09, 0x66, 0x0a, 0x65, 0x0b, 0x63, 0x0c, 0x62, 0x0d, 0x5f,
- 0x0e, 0x5c, 0x0f, 0x5a, 0x25, 0x5d, 0x27, 0x5c, 0x27, 0x59, 0x2a, 0x57,
- 0x2a, 0x57, 0x2a, 0x55, 0x2d, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
- 0x2e, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x4d, 0x32, 0x4b, 0x34, 0x4a, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90,
- 0x00, 0x86, 0x00, 0x7a, 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41,
- 0x00, 0x33, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00,
- 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49, 0x00, 0x41, 0x00, 0x39, 0x00,
- 0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x07, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0d, 0x42, 0x0f,
- 0x40, 0x11, 0x3d, 0x12, 0x3d, 0x13, 0x3e, 0x15, 0x3c, 0x16, 0x3b, 0x17,
- 0x3a, 0x19, 0x3a, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1e,
- 0x3a, 0x1f, 0x39, 0x1f, 0x39, 0x20, 0x39, 0x21, 0x00, 0xb0, 0x00, 0xa7,
- 0x00, 0x9e, 0x00, 0x94, 0x00, 0x8e, 0x00, 0x88, 0x01, 0x81, 0x02, 0x7c,
- 0x02, 0x78, 0x03, 0x75, 0x05, 0x72, 0x06, 0x6d, 0x07, 0x6a, 0x08, 0x68,
- 0x09, 0x66, 0x0a, 0x65, 0x0b, 0x63, 0x0c, 0x62, 0x0d, 0x60, 0x0e, 0x5d,
- 0x25, 0x5d, 0x27, 0x5c, 0x27, 0x5a, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
- 0x2c, 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x31, 0x4e, 0x31, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e,
- 0x00, 0x72, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f,
- 0x00, 0x22, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x57, 0x00,
- 0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x2c, 0x00,
- 0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x10, 0x3e, 0x11,
- 0x3d, 0x13, 0x3e, 0x14, 0x3d, 0x15, 0x3c, 0x17, 0x3a, 0x17, 0x3a, 0x19,
- 0x3b, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f,
- 0x39, 0x1f, 0x39, 0x1f, 0x00, 0xb0, 0x00, 0xa7, 0x00, 0xa0, 0x00, 0x96,
- 0x00, 0x90, 0x00, 0x8a, 0x00, 0x84, 0x01, 0x7e, 0x02, 0x7a, 0x03, 0x77,
- 0x04, 0x74, 0x05, 0x71, 0x06, 0x6c, 0x07, 0x6a, 0x08, 0x68, 0x09, 0x66,
- 0x0a, 0x65, 0x0b, 0x63, 0x0c, 0x63, 0x0c, 0x61, 0x25, 0x5e, 0x27, 0x5c,
- 0x27, 0x5c, 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2d, 0x53,
- 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x00, 0x27, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x8f, 0x00, 0x96, 0x00, 0x99,
- 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e,
- 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x8c, 0x00, 0x63,
- 0x00, 0x7f, 0x00, 0x89, 0x00, 0x90, 0x00, 0x96, 0x00, 0x9b, 0x00, 0x9c,
- 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e,
- 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x14, 0x2c, 0x00, 0x57, 0x00, 0x82, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99,
- 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e,
- 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x11, 0x31, 0x00, 0x5f,
- 0x00, 0x85, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c,
- 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e,
- 0x00, 0x9e, 0x00, 0x9e, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x45, 0x0b,
- 0x42, 0x0d, 0x42, 0x0e, 0x41, 0x0f, 0x3f, 0x11, 0x3d, 0x12, 0x3d, 0x13,
- 0x3e, 0x15, 0x3c, 0x15, 0x3c, 0x17, 0x3a, 0x17, 0x3a, 0x19, 0x3b, 0x19,
- 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f, 0x39, 0x1f,
- 0x00, 0xb1, 0x00, 0xa8, 0x00, 0xa1, 0x00, 0x98, 0x00, 0x91, 0x00, 0x8c,
- 0x00, 0x87, 0x01, 0x80, 0x02, 0x7c, 0x02, 0x79, 0x03, 0x76, 0x05, 0x74,
- 0x05, 0x70, 0x06, 0x6b, 0x07, 0x6a, 0x08, 0x68, 0x09, 0x66, 0x0a, 0x65,
- 0x0b, 0x64, 0x0c, 0x63, 0x25, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x29, 0x58,
- 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53,
- 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x51, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x00, 0x00, 0x00, 0x0d,
- 0x00, 0x4f, 0x00, 0x73, 0x00, 0x84, 0x00, 0x8d, 0x00, 0x92, 0x00, 0x95,
- 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c,
- 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x63, 0x00, 0x4d, 0x00, 0x60, 0x00, 0x77,
- 0x00, 0x83, 0x00, 0x8c, 0x00, 0x92, 0x00, 0x95, 0x00, 0x98, 0x00, 0x99,
- 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x01, 0x04, 0x16,
- 0x00, 0x57, 0x00, 0x78, 0x00, 0x87, 0x00, 0x8f, 0x00, 0x94, 0x00, 0x96,
- 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c,
- 0x00, 0x9d, 0x00, 0x9d, 0x23, 0x03, 0x00, 0x20, 0x00, 0x5f, 0x00, 0x7c,
- 0x00, 0x8a, 0x00, 0x91, 0x00, 0x95, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a,
- 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d,
- 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x41, 0x0e,
- 0x42, 0x0f, 0x40, 0x11, 0x3d, 0x11, 0x3d, 0x13, 0x3f, 0x13, 0x3d, 0x15,
- 0x3c, 0x16, 0x3b, 0x17, 0x3a, 0x18, 0x3a, 0x19, 0x3b, 0x19, 0x3c, 0x1a,
- 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1d, 0x3b, 0x1e, 0x00, 0xb1, 0x00, 0xa9,
- 0x00, 0xa2, 0x00, 0x9a, 0x00, 0x93, 0x00, 0x8d, 0x00, 0x89, 0x01, 0x83,
- 0x02, 0x7e, 0x02, 0x7a, 0x03, 0x78, 0x03, 0x75, 0x05, 0x73, 0x06, 0x6f,
- 0x06, 0x6b, 0x07, 0x69, 0x08, 0x68, 0x09, 0x66, 0x0a, 0x66, 0x0b, 0x64,
- 0x24, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x28, 0x59, 0x2a, 0x57, 0x2a, 0x57,
- 0x2a, 0x57, 0x2b, 0x55, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
- 0x2e, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x38,
- 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e,
- 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99,
- 0x00, 0x7f, 0x00, 0x60, 0x00, 0x24, 0x00, 0x48, 0x00, 0x60, 0x00, 0x70,
- 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x91, 0x00, 0x93,
- 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x27, 0x00, 0x01, 0x12, 0x00, 0x43,
- 0x00, 0x61, 0x00, 0x74, 0x00, 0x7f, 0x00, 0x87, 0x00, 0x8c, 0x00, 0x90,
- 0x00, 0x93, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99,
- 0x46, 0x00, 0x1f, 0x00, 0x00, 0x1f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x79,
- 0x00, 0x83, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x92, 0x00, 0x94, 0x00, 0x96,
- 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x41, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x41, 0x0e, 0x42, 0x0f, 0x40, 0x10,
- 0x3e, 0x11, 0x3d, 0x13, 0x3d, 0x13, 0x3f, 0x15, 0x3c, 0x15, 0x3c, 0x17,
- 0x3a, 0x17, 0x3a, 0x18, 0x3b, 0x19, 0x3b, 0x19, 0x3c, 0x1a, 0x3c, 0x1c,
- 0x3b, 0x1c, 0x3b, 0x1c, 0x00, 0xb1, 0x00, 0xa9, 0x00, 0xa3, 0x00, 0x9c,
- 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8b, 0x00, 0x86, 0x01, 0x80, 0x02, 0x7c,
- 0x02, 0x79, 0x03, 0x77, 0x04, 0x75, 0x05, 0x72, 0x06, 0x6e, 0x07, 0x6b,
- 0x07, 0x69, 0x09, 0x68, 0x09, 0x66, 0x0a, 0x66, 0x24, 0x5e, 0x27, 0x5c,
- 0x27, 0x5c, 0x27, 0x5a, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
- 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
- 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2a, 0x00, 0x48,
- 0x00, 0x5d, 0x00, 0x6c, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88,
- 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x92, 0x00, 0x89, 0x00, 0x77,
- 0x00, 0x48, 0x00, 0x0f, 0x00, 0x30, 0x00, 0x48, 0x00, 0x5d, 0x00, 0x6c,
- 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e,
- 0x00, 0x90, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x54, 0x00, 0x41, 0x00, 0x17, 0x00, 0x00, 0x10, 0x00, 0x36, 0x00, 0x51,
- 0x00, 0x64, 0x00, 0x71, 0x00, 0x7a, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8a,
- 0x00, 0x8d, 0x00, 0x90, 0x00, 0x92, 0x00, 0x93, 0x52, 0x00, 0x3c, 0x00,
- 0x0d, 0x00, 0x00, 0x1f, 0x00, 0x42, 0x00, 0x5a, 0x00, 0x6a, 0x00, 0x76,
- 0x00, 0x7e, 0x00, 0x84, 0x00, 0x89, 0x00, 0x8c, 0x00, 0x8f, 0x00, 0x91,
- 0x00, 0x93, 0x00, 0x95, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d,
- 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x46, 0x0b,
- 0x44, 0x0d, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x0f, 0x40, 0x11, 0x3d, 0x11,
- 0x3d, 0x13, 0x3f, 0x13, 0x3e, 0x15, 0x3c, 0x15, 0x3c, 0x17, 0x3a, 0x17,
- 0x3a, 0x18, 0x3b, 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c,
- 0x00, 0xb2, 0x00, 0xaa, 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x95, 0x00, 0x90,
- 0x00, 0x8c, 0x00, 0x88, 0x01, 0x82, 0x02, 0x7e, 0x02, 0x7b, 0x02, 0x78,
- 0x03, 0x76, 0x05, 0x74, 0x05, 0x71, 0x06, 0x6d, 0x07, 0x6b, 0x07, 0x69,
- 0x09, 0x68, 0x09, 0x66, 0x24, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5b,
- 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2b, 0x54, 0x2e, 0x53,
- 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x50,
- 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f,
- 0x00, 0x5e, 0x00, 0x69, 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83,
- 0x00, 0x86, 0x00, 0x89, 0x00, 0x90, 0x00, 0x83, 0x00, 0x60, 0x00, 0x30,
- 0x00, 0x02, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x5e, 0x00, 0x69,
- 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x86, 0x00, 0x89,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x4d, 0x00,
- 0x2f, 0x00, 0x0e, 0x00, 0x00, 0x10, 0x00, 0x2e, 0x00, 0x46, 0x00, 0x57,
- 0x00, 0x64, 0x00, 0x6f, 0x00, 0x76, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x85,
- 0x00, 0x89, 0x00, 0x8b, 0x58, 0x00, 0x4a, 0x00, 0x28, 0x00, 0x02, 0x00,
- 0x00, 0x1f, 0x00, 0x3b, 0x00, 0x4f, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x74,
- 0x00, 0x7b, 0x00, 0x80, 0x00, 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d,
- 0x1b, 0x85, 0x05, 0x96, 0x01, 0x9e, 0x00, 0xa4, 0x00, 0xa7, 0x00, 0xa9,
- 0x00, 0xab, 0x00, 0xac, 0x00, 0xad, 0x00, 0xae, 0x00, 0xaf, 0x00, 0xaf,
- 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb2,
- 0x00, 0xb2, 0x00, 0xb2, 0x1c, 0x6e, 0x03, 0x8a, 0x00, 0x97, 0x00, 0x9e,
- 0x00, 0xa2, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xac,
- 0x00, 0xad, 0x00, 0xad, 0x00, 0xad, 0x00, 0xae, 0x00, 0xaf, 0x00, 0xaf,
- 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x0e, 0x92, 0x01, 0xa1, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xac, 0x00, 0xae,
- 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb2,
- 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3,
- 0x00, 0xb4, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53,
- 0x00, 0x5e, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e,
- 0x00, 0x96, 0x00, 0x8c, 0x00, 0x70, 0x00, 0x48, 0x00, 0x22, 0x00, 0x01,
- 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53, 0x00, 0x5e, 0x00, 0x68,
- 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x53, 0x00, 0x3e, 0x00, 0x23, 0x00,
- 0x0a, 0x02, 0x00, 0x10, 0x00, 0x29, 0x00, 0x3d, 0x00, 0x4e, 0x00, 0x5b,
- 0x00, 0x65, 0x00, 0x6d, 0x00, 0x74, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82,
- 0x5a, 0x00, 0x51, 0x00, 0x39, 0x00, 0x1a, 0x00, 0x00, 0x04, 0x00, 0x1f,
- 0x00, 0x36, 0x00, 0x48, 0x00, 0x57, 0x00, 0x62, 0x00, 0x6b, 0x00, 0x73,
- 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x85, 0x27, 0x60, 0x0f, 0x73,
- 0x07, 0x81, 0x03, 0x8a, 0x01, 0x91, 0x00, 0x95, 0x00, 0x99, 0x00, 0x9d,
- 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7,
- 0x00, 0xa7, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa,
- 0x29, 0x3a, 0x0f, 0x59, 0x06, 0x6c, 0x02, 0x79, 0x00, 0x84, 0x00, 0x8b,
- 0x00, 0x90, 0x00, 0x94, 0x00, 0x98, 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9f,
- 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa6,
- 0x00, 0xa7, 0x00, 0xa7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x14, 0x79, 0x07, 0x88,
- 0x03, 0x92, 0x01, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa5,
- 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xab, 0x00, 0xac, 0x00, 0xac,
- 0x00, 0xad, 0x00, 0xae, 0x00, 0xae, 0x00, 0xae, 0x00, 0xaf, 0x00, 0xaf,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55,
- 0x00, 0x5f, 0x00, 0x66, 0x00, 0x6d, 0x00, 0x72, 0x00, 0x9b, 0x00, 0x92,
- 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x18,
- 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55, 0x00, 0x5f, 0x00, 0x66,
- 0x00, 0x6d, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5c, 0x00, 0x56, 0x00, 0x47, 0x00, 0x31, 0x00, 0x1a, 0x00, 0x08, 0x04,
- 0x00, 0x10, 0x00, 0x25, 0x00, 0x37, 0x00, 0x46, 0x00, 0x52, 0x00, 0x5d,
- 0x00, 0x65, 0x00, 0x6c, 0x00, 0x72, 0x00, 0x77, 0x5c, 0x00, 0x55, 0x00,
- 0x43, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x09, 0x00, 0x1f, 0x00, 0x33,
- 0x00, 0x43, 0x00, 0x50, 0x00, 0x5b, 0x00, 0x64, 0x00, 0x6b, 0x00, 0x72,
- 0x00, 0x77, 0x00, 0x7b, 0x2d, 0x54, 0x17, 0x63, 0x0d, 0x6f, 0x07, 0x78,
- 0x04, 0x80, 0x02, 0x86, 0x01, 0x8b, 0x01, 0x8f, 0x00, 0x92, 0x00, 0x95,
- 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1,
- 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa4, 0x31, 0x27, 0x18, 0x40,
- 0x0d, 0x52, 0x07, 0x61, 0x04, 0x6c, 0x02, 0x75, 0x01, 0x7c, 0x00, 0x82,
- 0x00, 0x87, 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x91, 0x00, 0x94, 0x00, 0x97,
- 0x00, 0x98, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x18, 0x6f, 0x0c, 0x7b, 0x06, 0x84, 0x03, 0x8c,
- 0x02, 0x91, 0x01, 0x96, 0x00, 0x99, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa1,
- 0x00, 0xa2, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0xa8,
- 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xab, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x14, 0x00, 0x26, 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57,
- 0x00, 0x5f, 0x00, 0x66, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x84, 0x00, 0x6c,
- 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x26,
- 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57, 0x00, 0x5f, 0x00, 0x66,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00,
- 0x4d, 0x00, 0x3b, 0x00, 0x27, 0x00, 0x13, 0x00, 0x07, 0x06, 0x00, 0x10,
- 0x00, 0x22, 0x00, 0x32, 0x00, 0x40, 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5e,
- 0x00, 0x65, 0x00, 0x6b, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x36, 0x00,
- 0x1f, 0x00, 0x08, 0x00, 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x30, 0x00, 0x3f,
- 0x00, 0x4b, 0x00, 0x55, 0x00, 0x5e, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x71,
- 0x30, 0x4e, 0x1d, 0x5a, 0x12, 0x64, 0x0c, 0x6d, 0x08, 0x75, 0x05, 0x7a,
- 0x03, 0x7f, 0x02, 0x85, 0x02, 0x89, 0x01, 0x8b, 0x00, 0x8e, 0x00, 0x90,
- 0x00, 0x92, 0x00, 0x94, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x9c,
- 0x00, 0x9e, 0x00, 0x9f, 0x36, 0x1e, 0x1f, 0x32, 0x12, 0x43, 0x0b, 0x50,
- 0x07, 0x5a, 0x05, 0x63, 0x02, 0x6b, 0x01, 0x72, 0x01, 0x78, 0x00, 0x7c,
- 0x00, 0x81, 0x00, 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x90,
- 0x00, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x1b, 0x6b, 0x0f, 0x74, 0x09, 0x7d, 0x05, 0x83, 0x03, 0x89, 0x02, 0x8d,
- 0x01, 0x91, 0x00, 0x95, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9c, 0x00, 0x9e,
- 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5,
- 0x00, 0xa6, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
- 0x00, 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58,
- 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76, 0x00, 0x5e, 0x00, 0x45,
- 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x22, 0x00, 0x30,
- 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x51, 0x00, 0x42, 0x00,
- 0x32, 0x00, 0x20, 0x00, 0x0e, 0x00, 0x06, 0x07, 0x00, 0x10, 0x00, 0x20,
- 0x00, 0x2f, 0x00, 0x3b, 0x00, 0x46, 0x00, 0x50, 0x00, 0x58, 0x00, 0x5f,
- 0x5d, 0x00, 0x59, 0x00, 0x4e, 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x17, 0x00,
- 0x03, 0x00, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x2e, 0x00, 0x3b, 0x00, 0x46,
- 0x00, 0x50, 0x00, 0x59, 0x00, 0x60, 0x00, 0x66, 0x33, 0x4b, 0x21, 0x54,
- 0x16, 0x5d, 0x10, 0x65, 0x0b, 0x6c, 0x08, 0x72, 0x06, 0x77, 0x04, 0x7b,
- 0x03, 0x7f, 0x02, 0x83, 0x02, 0x87, 0x01, 0x8a, 0x01, 0x8c, 0x00, 0x8e,
- 0x00, 0x90, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x98,
- 0x3a, 0x19, 0x24, 0x2a, 0x18, 0x38, 0x10, 0x44, 0x0b, 0x4e, 0x07, 0x57,
- 0x05, 0x5f, 0x04, 0x65, 0x02, 0x6b, 0x01, 0x71, 0x01, 0x76, 0x00, 0x79,
- 0x00, 0x7e, 0x00, 0x80, 0x00, 0x84, 0x00, 0x87, 0x00, 0x88, 0x00, 0x8b,
- 0x00, 0x8d, 0x00, 0x8f, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x1d, 0x68, 0x12, 0x70,
- 0x0c, 0x77, 0x08, 0x7d, 0x05, 0x82, 0x03, 0x87, 0x02, 0x8b, 0x02, 0x8e,
- 0x01, 0x91, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9b,
- 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
- 0x00, 0x2c, 0x00, 0x37, 0x00, 0x41, 0x00, 0x4a, 0x00, 0x9d, 0x00, 0x99,
- 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53, 0x00, 0x3c, 0x00, 0x26,
- 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2c, 0x00, 0x37,
- 0x00, 0x41, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5e, 0x00, 0x5b, 0x00, 0x53, 0x00, 0x48, 0x00, 0x3a, 0x00, 0x2a, 0x00,
- 0x1a, 0x00, 0x0b, 0x00, 0x05, 0x08, 0x00, 0x10, 0x00, 0x1e, 0x00, 0x2c,
- 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x5e, 0x00, 0x5b, 0x00,
- 0x52, 0x00, 0x45, 0x00, 0x34, 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00,
- 0x00, 0x11, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x43, 0x00, 0x4c,
- 0x00, 0x54, 0x00, 0x5b, 0x34, 0x49, 0x25, 0x51, 0x1a, 0x58, 0x13, 0x60,
- 0x0e, 0x65, 0x0b, 0x6b, 0x08, 0x71, 0x06, 0x75, 0x05, 0x78, 0x04, 0x7b,
- 0x03, 0x7f, 0x02, 0x83, 0x02, 0x86, 0x01, 0x88, 0x01, 0x8a, 0x00, 0x8c,
- 0x00, 0x8d, 0x00, 0x8f, 0x00, 0x90, 0x00, 0x92, 0x3b, 0x17, 0x28, 0x24,
- 0x1c, 0x30, 0x14, 0x3b, 0x0f, 0x45, 0x0b, 0x4d, 0x07, 0x55, 0x05, 0x5b,
- 0x04, 0x61, 0x03, 0x67, 0x02, 0x6b, 0x01, 0x6f, 0x01, 0x74, 0x00, 0x77,
- 0x00, 0x7a, 0x00, 0x7e, 0x00, 0x80, 0x00, 0x83, 0x00, 0x86, 0x00, 0x87,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x1d, 0x67, 0x14, 0x6d, 0x0e, 0x73, 0x0a, 0x79,
- 0x07, 0x7e, 0x05, 0x82, 0x03, 0x86, 0x02, 0x89, 0x02, 0x8c, 0x01, 0x8f,
- 0x01, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a,
- 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28,
- 0x00, 0x33, 0x00, 0x3d, 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x91, 0x00, 0x83,
- 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36, 0x00, 0x22, 0x00, 0x10,
- 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x33, 0x00, 0x3d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00,
- 0x56, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x32, 0x00, 0x24, 0x00, 0x15, 0x00,
- 0x0a, 0x02, 0x04, 0x09, 0x00, 0x10, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x34,
- 0x00, 0x3e, 0x00, 0x46, 0x5e, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x49, 0x00,
- 0x3b, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x0b, 0x00, 0x00, 0x04, 0x00, 0x12,
- 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x00, 0x40, 0x00, 0x49, 0x00, 0x50,
- 0x36, 0x47, 0x27, 0x4e, 0x1d, 0x54, 0x16, 0x5b, 0x11, 0x61, 0x0e, 0x65,
- 0x0b, 0x6a, 0x08, 0x6f, 0x07, 0x73, 0x05, 0x76, 0x05, 0x79, 0x03, 0x7c,
- 0x02, 0x7e, 0x02, 0x82, 0x02, 0x85, 0x01, 0x88, 0x01, 0x89, 0x01, 0x8b,
- 0x00, 0x8c, 0x00, 0x8d, 0x3d, 0x14, 0x2c, 0x20, 0x20, 0x2a, 0x18, 0x34,
- 0x12, 0x3e, 0x0e, 0x45, 0x0a, 0x4c, 0x07, 0x53, 0x06, 0x58, 0x05, 0x5e,
- 0x04, 0x63, 0x02, 0x67, 0x02, 0x6c, 0x01, 0x6f, 0x01, 0x72, 0x00, 0x76,
- 0x00, 0x78, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x80, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x1e, 0x66, 0x16, 0x6b, 0x10, 0x71, 0x0c, 0x76, 0x09, 0x7a, 0x07, 0x7e,
- 0x05, 0x81, 0x03, 0x85, 0x03, 0x88, 0x02, 0x8b, 0x02, 0x8d, 0x01, 0x8f,
- 0x01, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x96, 0x00, 0x98, 0x00, 0x99,
- 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f,
- 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88, 0x00, 0x79, 0x00, 0x68,
- 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
- 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00,
- 0x44, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x09, 0x03,
- 0x04, 0x09, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x27, 0x00, 0x31, 0x00, 0x3a,
- 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x41, 0x00, 0x33, 0x00,
- 0x24, 0x00, 0x15, 0x00, 0x07, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x1f,
- 0x00, 0x2a, 0x00, 0x34, 0x00, 0x3d, 0x00, 0x46, 0x37, 0x46, 0x29, 0x4c,
- 0x20, 0x52, 0x19, 0x57, 0x14, 0x5d, 0x10, 0x62, 0x0d, 0x66, 0x0b, 0x69,
- 0x09, 0x6e, 0x07, 0x73, 0x06, 0x75, 0x05, 0x77, 0x04, 0x7a, 0x03, 0x7c,
- 0x02, 0x7e, 0x02, 0x82, 0x02, 0x84, 0x02, 0x87, 0x01, 0x88, 0x01, 0x89,
- 0x3f, 0x13, 0x2f, 0x1c, 0x23, 0x27, 0x1b, 0x2f, 0x15, 0x38, 0x10, 0x3e,
- 0x0d, 0x45, 0x0a, 0x4b, 0x08, 0x51, 0x07, 0x57, 0x05, 0x5c, 0x04, 0x60,
- 0x03, 0x65, 0x02, 0x67, 0x02, 0x6c, 0x01, 0x6f, 0x01, 0x71, 0x00, 0x75,
- 0x00, 0x77, 0x00, 0x79, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x1f, 0x65, 0x17, 0x6a,
- 0x11, 0x6f, 0x0d, 0x73, 0x0a, 0x77, 0x08, 0x7b, 0x06, 0x7e, 0x05, 0x81,
- 0x04, 0x84, 0x03, 0x87, 0x02, 0x89, 0x02, 0x8b, 0x01, 0x8e, 0x01, 0x8f,
- 0x01, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x22, 0x00, 0x9e, 0x00, 0x9c,
- 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f, 0x00, 0x5f, 0x00, 0x4e,
- 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c,
- 0x00, 0x18, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5e, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00,
- 0x32, 0x00, 0x26, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x08, 0x04, 0x04, 0x0a,
- 0x00, 0x10, 0x00, 0x1b, 0x00, 0x25, 0x00, 0x2f, 0x5e, 0x00, 0x5d, 0x00,
- 0x57, 0x00, 0x4f, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x1e, 0x00,
- 0x10, 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x2a,
- 0x00, 0x33, 0x00, 0x3b, 0x38, 0x45, 0x2b, 0x4a, 0x22, 0x50, 0x1c, 0x55,
- 0x16, 0x59, 0x12, 0x5f, 0x0f, 0x63, 0x0d, 0x66, 0x0b, 0x69, 0x09, 0x6e,
- 0x07, 0x71, 0x06, 0x74, 0x05, 0x76, 0x05, 0x78, 0x03, 0x7a, 0x03, 0x7c,
- 0x02, 0x7e, 0x02, 0x81, 0x02, 0x84, 0x02, 0x86, 0x40, 0x11, 0x31, 0x1b,
- 0x26, 0x23, 0x1e, 0x2b, 0x18, 0x33, 0x13, 0x39, 0x0f, 0x40, 0x0c, 0x45,
- 0x0a, 0x4b, 0x08, 0x51, 0x07, 0x56, 0x05, 0x59, 0x04, 0x5e, 0x04, 0x61,
- 0x02, 0x65, 0x02, 0x68, 0x02, 0x6b, 0x01, 0x6e, 0x01, 0x71, 0x00, 0x73,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x20, 0x64, 0x18, 0x69, 0x13, 0x6d, 0x0f, 0x71,
- 0x0c, 0x75, 0x09, 0x78, 0x07, 0x7b, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84,
- 0x03, 0x86, 0x02, 0x88, 0x02, 0x8a, 0x02, 0x8c, 0x01, 0x8e, 0x01, 0x8f,
- 0x01, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0b, 0x00, 0x16, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8e,
- 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57, 0x00, 0x47, 0x00, 0x37,
- 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x16,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00,
- 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42, 0x00, 0x38, 0x00, 0x2d, 0x00,
- 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00, 0x07, 0x05, 0x03, 0x0a, 0x00, 0x0f,
- 0x00, 0x1a, 0x00, 0x24, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x52, 0x00,
- 0x49, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c, 0x00,
- 0x00, 0x00, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x31,
- 0x38, 0x45, 0x2d, 0x49, 0x24, 0x4e, 0x1e, 0x53, 0x19, 0x56, 0x14, 0x5b,
- 0x11, 0x60, 0x0e, 0x63, 0x0c, 0x66, 0x0a, 0x69, 0x09, 0x6c, 0x07, 0x70,
- 0x06, 0x73, 0x06, 0x75, 0x05, 0x77, 0x04, 0x79, 0x03, 0x7a, 0x03, 0x7c,
- 0x02, 0x7e, 0x02, 0x80, 0x40, 0x11, 0x32, 0x18, 0x28, 0x20, 0x20, 0x28,
- 0x1a, 0x2f, 0x16, 0x35, 0x12, 0x3c, 0x0f, 0x41, 0x0c, 0x46, 0x0a, 0x4b,
- 0x08, 0x50, 0x07, 0x54, 0x05, 0x58, 0x05, 0x5c, 0x04, 0x5f, 0x04, 0x62,
- 0x02, 0x66, 0x02, 0x69, 0x01, 0x6b, 0x01, 0x6e, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x20, 0x64, 0x19, 0x68, 0x14, 0x6b, 0x10, 0x6f, 0x0d, 0x73, 0x0b, 0x76,
- 0x09, 0x79, 0x07, 0x7c, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85,
- 0x02, 0x88, 0x02, 0x89, 0x02, 0x8b, 0x02, 0x8d, 0x01, 0x8e, 0x01, 0x90,
- 0x00, 0x91, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
- 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90, 0x00, 0x86, 0x00, 0x7a,
- 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41, 0x00, 0x33, 0x00, 0x25,
- 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00,
- 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x32, 0x00, 0x28, 0x00, 0x1e, 0x00,
- 0x14, 0x00, 0x0b, 0x00, 0x07, 0x06, 0x03, 0x0b, 0x00, 0x0f, 0x00, 0x19,
- 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42, 0x00,
- 0x37, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x01,
- 0x00, 0x0c, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x28, 0x39, 0x44, 0x2e, 0x49,
- 0x26, 0x4c, 0x1f, 0x52, 0x1a, 0x55, 0x16, 0x58, 0x13, 0x5d, 0x10, 0x61,
- 0x0e, 0x64, 0x0c, 0x66, 0x0a, 0x68, 0x09, 0x6c, 0x07, 0x70, 0x07, 0x72,
- 0x06, 0x74, 0x05, 0x76, 0x05, 0x78, 0x03, 0x79, 0x03, 0x7b, 0x02, 0x7c,
- 0x41, 0x10, 0x34, 0x17, 0x2a, 0x1e, 0x23, 0x25, 0x1d, 0x2c, 0x18, 0x32,
- 0x14, 0x37, 0x10, 0x3d, 0x0e, 0x42, 0x0c, 0x46, 0x0a, 0x4b, 0x08, 0x4f,
- 0x07, 0x53, 0x05, 0x57, 0x05, 0x5a, 0x04, 0x5e, 0x04, 0x61, 0x03, 0x63,
- 0x02, 0x66, 0x02, 0x69, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x20, 0x63, 0x1a, 0x67,
- 0x15, 0x6a, 0x11, 0x6e, 0x0e, 0x71, 0x0c, 0x74, 0x0a, 0x77, 0x08, 0x7a,
- 0x07, 0x7c, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85, 0x02, 0x87,
- 0x02, 0x88, 0x02, 0x8a, 0x02, 0x8c, 0x01, 0x8d, 0x01, 0x8e, 0x01, 0x90,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d,
- 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x66,
- 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f, 0x00, 0x22, 0x00, 0x16,
- 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x48, 0x00,
- 0x40, 0x00, 0x37, 0x00, 0x2d, 0x00, 0x24, 0x00, 0x1a, 0x00, 0x11, 0x00,
- 0x0a, 0x01, 0x06, 0x06, 0x03, 0x0b, 0x00, 0x0f, 0x5f, 0x00, 0x5d, 0x00,
- 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x31, 0x00,
- 0x26, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0d,
- 0x00, 0x17, 0x00, 0x1f, 0x39, 0x43, 0x2f, 0x48, 0x27, 0x4b, 0x22, 0x4f,
- 0x1c, 0x54, 0x18, 0x56, 0x14, 0x59, 0x12, 0x5e, 0x0f, 0x62, 0x0d, 0x64,
- 0x0c, 0x66, 0x0a, 0x68, 0x09, 0x6b, 0x08, 0x6f, 0x07, 0x72, 0x06, 0x74,
- 0x05, 0x75, 0x05, 0x77, 0x04, 0x78, 0x03, 0x7a, 0x42, 0x0f, 0x36, 0x16,
- 0x2c, 0x1c, 0x25, 0x23, 0x1f, 0x29, 0x1a, 0x2e, 0x16, 0x34, 0x12, 0x39,
- 0x0f, 0x3e, 0x0d, 0x42, 0x0c, 0x47, 0x0a, 0x4b, 0x08, 0x4f, 0x07, 0x52,
- 0x05, 0x56, 0x05, 0x59, 0x04, 0x5c, 0x04, 0x5f, 0x04, 0x62, 0x02, 0x64,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x21, 0x63, 0x1b, 0x66, 0x16, 0x6a, 0x12, 0x6d,
- 0x0f, 0x70, 0x0d, 0x73, 0x0b, 0x75, 0x09, 0x78, 0x07, 0x7a, 0x06, 0x7d,
- 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85, 0x02, 0x86, 0x02, 0x88,
- 0x02, 0x89, 0x02, 0x8b, 0x02, 0x8c, 0x01, 0x8d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3a, 0x43, 0x31, 0x48, 0x29, 0x4a, 0x23, 0x4d, 0x1e, 0x53, 0x1a, 0x55,
- 0x16, 0x57, 0x13, 0x5b, 0x11, 0x60, 0x0f, 0x62, 0x0d, 0x64, 0x0b, 0x66,
- 0x0a, 0x68, 0x09, 0x6a, 0x08, 0x6e, 0x07, 0x71, 0x06, 0x73, 0x06, 0x75,
- 0x05, 0x76, 0x05, 0x78, 0x43, 0x0f, 0x37, 0x15, 0x2e, 0x1b, 0x27, 0x21,
- 0x21, 0x26, 0x1c, 0x2c, 0x18, 0x31, 0x15, 0x36, 0x12, 0x3a, 0x0f, 0x3f,
- 0x0c, 0x43, 0x0c, 0x47, 0x0a, 0x4b, 0x08, 0x4e, 0x07, 0x52, 0x06, 0x55,
- 0x05, 0x58, 0x05, 0x5b, 0x04, 0x5d, 0x04, 0x60, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x21, 0x63, 0x1b, 0x66, 0x17, 0x69, 0x13, 0x6c, 0x10, 0x6e, 0x0e, 0x71,
- 0x0c, 0x74, 0x0a, 0x76, 0x09, 0x79, 0x07, 0x7b, 0x06, 0x7d, 0x06, 0x7f,
- 0x05, 0x81, 0x04, 0x82, 0x03, 0x84, 0x03, 0x86, 0x02, 0x87, 0x02, 0x89,
- 0x02, 0x8a, 0x02, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x42, 0x31, 0x47,
- 0x2a, 0x49, 0x24, 0x4c, 0x1f, 0x51, 0x1b, 0x54, 0x18, 0x56, 0x15, 0x58,
- 0x12, 0x5c, 0x10, 0x61, 0x0e, 0x63, 0x0c, 0x64, 0x0b, 0x66, 0x0a, 0x68,
- 0x09, 0x6a, 0x08, 0x6d, 0x07, 0x71, 0x06, 0x72, 0x06, 0x74, 0x05, 0x75,
- 0x43, 0x0f, 0x38, 0x14, 0x2f, 0x19, 0x28, 0x1f, 0x22, 0x24, 0x1d, 0x29,
- 0x19, 0x2e, 0x16, 0x33, 0x12, 0x37, 0x11, 0x3b, 0x0f, 0x40, 0x0c, 0x43,
- 0x0b, 0x47, 0x0a, 0x4b, 0x09, 0x4e, 0x07, 0x51, 0x07, 0x55, 0x05, 0x56,
- 0x05, 0x5a, 0x04, 0x5c, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x21, 0x63, 0x1c, 0x65,
- 0x17, 0x68, 0x14, 0x6b, 0x11, 0x6e, 0x0e, 0x70, 0x0c, 0x73, 0x0b, 0x75,
- 0x09, 0x77, 0x08, 0x79, 0x07, 0x7b, 0x06, 0x7d, 0x05, 0x7f, 0x05, 0x81,
- 0x04, 0x82, 0x03, 0x84, 0x03, 0x86, 0x02, 0x87, 0x02, 0x88, 0x02, 0x89,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3a, 0x42, 0x32, 0x46, 0x2b, 0x49, 0x25, 0x4b,
- 0x21, 0x4f, 0x1d, 0x53, 0x19, 0x55, 0x16, 0x57, 0x14, 0x59, 0x11, 0x5e,
- 0x10, 0x61, 0x0e, 0x63, 0x0c, 0x65, 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x6a,
- 0x08, 0x6c, 0x07, 0x70, 0x07, 0x72, 0x06, 0x73, 0x43, 0x0e, 0x39, 0x13,
- 0x31, 0x18, 0x2a, 0x1d, 0x24, 0x22, 0x1f, 0x27, 0x1b, 0x2b, 0x18, 0x30,
- 0x16, 0x35, 0x12, 0x39, 0x0f, 0x3c, 0x0f, 0x41, 0x0c, 0x44, 0x0b, 0x47,
- 0x0a, 0x4a, 0x09, 0x4e, 0x07, 0x50, 0x07, 0x54, 0x05, 0x55, 0x05, 0x59,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x21, 0x63, 0x1c, 0x65, 0x18, 0x68, 0x15, 0x6a,
- 0x12, 0x6c, 0x0f, 0x6f, 0x0d, 0x71, 0x0c, 0x73, 0x0b, 0x76, 0x09, 0x78,
- 0x07, 0x79, 0x07, 0x7c, 0x06, 0x7d, 0x05, 0x7f, 0x05, 0x81, 0x04, 0x82,
- 0x03, 0x84, 0x03, 0x85, 0x02, 0x86, 0x02, 0x88, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3b, 0x42, 0x33, 0x45, 0x2c, 0x49, 0x27, 0x4b, 0x22, 0x4d, 0x1e, 0x52,
- 0x1b, 0x54, 0x18, 0x56, 0x15, 0x58, 0x13, 0x5b, 0x10, 0x5f, 0x0f, 0x61,
- 0x0e, 0x63, 0x0c, 0x65, 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x69, 0x08, 0x6c,
- 0x07, 0x6f, 0x07, 0x72, 0x44, 0x0e, 0x3a, 0x12, 0x32, 0x17, 0x2b, 0x1c,
- 0x26, 0x21, 0x21, 0x26, 0x1d, 0x2a, 0x19, 0x2e, 0x16, 0x32, 0x14, 0x35,
- 0x12, 0x3a, 0x0f, 0x3d, 0x0e, 0x41, 0x0c, 0x44, 0x0b, 0x47, 0x0a, 0x4a,
- 0x09, 0x4e, 0x07, 0x4f, 0x07, 0x53, 0x05, 0x55, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x22, 0x62, 0x1d, 0x65, 0x19, 0x67, 0x15, 0x6a, 0x13, 0x6c, 0x10, 0x6e,
- 0x0e, 0x71, 0x0c, 0x73, 0x0b, 0x74, 0x0a, 0x76, 0x09, 0x79, 0x07, 0x7a,
- 0x07, 0x7c, 0x06, 0x7d, 0x05, 0x7f, 0x05, 0x81, 0x04, 0x82, 0x03, 0x83,
- 0x03, 0x85, 0x02, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x42, 0x33, 0x44,
- 0x2d, 0x48, 0x28, 0x4a, 0x23, 0x4c, 0x1f, 0x50, 0x1c, 0x53, 0x19, 0x55,
- 0x16, 0x57, 0x14, 0x58, 0x12, 0x5c, 0x10, 0x60, 0x0e, 0x62, 0x0d, 0x63,
- 0x0c, 0x65, 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x69, 0x09, 0x6b, 0x07, 0x6e,
- 0x44, 0x0d, 0x3a, 0x12, 0x33, 0x16, 0x2c, 0x1b, 0x27, 0x1f, 0x21, 0x24,
- 0x1e, 0x28, 0x1a, 0x2b, 0x18, 0x30, 0x16, 0x34, 0x12, 0x37, 0x11, 0x3b,
- 0x0f, 0x3e, 0x0d, 0x41, 0x0c, 0x45, 0x0a, 0x47, 0x0a, 0x4a, 0x09, 0x4e,
- 0x07, 0x4f, 0x07, 0x53, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x22, 0x62, 0x1d, 0x65,
- 0x19, 0x66, 0x16, 0x69, 0x13, 0x6b, 0x10, 0x6d, 0x0f, 0x6f, 0x0d, 0x71,
- 0x0c, 0x73, 0x0b, 0x76, 0x09, 0x77, 0x08, 0x79, 0x07, 0x7a, 0x06, 0x7c,
- 0x06, 0x7e, 0x05, 0x7f, 0x05, 0x80, 0x04, 0x82, 0x03, 0x83, 0x03, 0x85,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3b, 0x42, 0x34, 0x44, 0x2e, 0x48, 0x29, 0x49,
- 0x24, 0x4b, 0x20, 0x4f, 0x1d, 0x53, 0x1a, 0x55, 0x18, 0x56, 0x15, 0x58,
- 0x13, 0x59, 0x11, 0x5d, 0x10, 0x61, 0x0e, 0x62, 0x0d, 0x63, 0x0c, 0x65,
- 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x69, 0x09, 0x6b, 0x44, 0x0d, 0x3b, 0x12,
- 0x34, 0x16, 0x2e, 0x19, 0x28, 0x1e, 0x23, 0x22, 0x20, 0x26, 0x1d, 0x2b,
- 0x19, 0x2e, 0x16, 0x31, 0x14, 0x35, 0x12, 0x38, 0x0f, 0x3b, 0x0f, 0x3f,
- 0x0c, 0x41, 0x0c, 0x45, 0x0a, 0x47, 0x0a, 0x4a, 0x09, 0x4e, 0x07, 0x4e,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x22, 0x62, 0x1d, 0x64, 0x1a, 0x66, 0x17, 0x68,
- 0x14, 0x6a, 0x11, 0x6c, 0x10, 0x6e, 0x0e, 0x71, 0x0c, 0x73, 0x0b, 0x74,
- 0x0a, 0x76, 0x09, 0x78, 0x07, 0x79, 0x07, 0x7b, 0x06, 0x7c, 0x06, 0x7e,
- 0x05, 0x7f, 0x05, 0x80, 0x04, 0x82, 0x03, 0x82, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3b, 0x42, 0x34, 0x43, 0x2f, 0x48, 0x29, 0x49, 0x25, 0x4b, 0x21, 0x4d,
- 0x1e, 0x51, 0x1b, 0x54, 0x18, 0x55, 0x16, 0x56, 0x14, 0x58, 0x13, 0x5b,
- 0x10, 0x5e, 0x0f, 0x61, 0x0e, 0x63, 0x0c, 0x64, 0x0c, 0x66, 0x0b, 0x66,
- 0x0a, 0x68, 0x09, 0x69, 0x44, 0x0c, 0x3c, 0x11, 0x35, 0x16, 0x2f, 0x19,
- 0x2a, 0x1d, 0x25, 0x22, 0x21, 0x25, 0x1d, 0x29, 0x1a, 0x2b, 0x18, 0x30,
- 0x16, 0x33, 0x12, 0x35, 0x12, 0x3a, 0x0f, 0x3c, 0x0f, 0x40, 0x0c, 0x41,
- 0x0c, 0x45, 0x0a, 0x47, 0x0a, 0x4a, 0x09, 0x4e, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x22, 0x62, 0x1e, 0x64, 0x1a, 0x66, 0x17, 0x68, 0x15, 0x6a, 0x12, 0x6c,
- 0x10, 0x6e, 0x0e, 0x70, 0x0d, 0x71, 0x0c, 0x73, 0x0b, 0x75, 0x09, 0x76,
- 0x09, 0x78, 0x07, 0x79, 0x07, 0x7b, 0x06, 0x7c, 0x06, 0x7e, 0x05, 0x7f,
- 0x05, 0x80, 0x04, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x42, 0x35, 0x43,
- 0x2f, 0x47, 0x2b, 0x49, 0x26, 0x4b, 0x22, 0x4c, 0x1f, 0x4f, 0x1c, 0x53,
- 0x1a, 0x55, 0x18, 0x56, 0x15, 0x58, 0x13, 0x59, 0x12, 0x5c, 0x10, 0x60,
- 0x0f, 0x61, 0x0e, 0x63, 0x0c, 0x64, 0x0c, 0x66, 0x0b, 0x66, 0x0a, 0x68,
- 0x44, 0x0c, 0x3c, 0x10, 0x35, 0x15, 0x30, 0x19, 0x2b, 0x1c, 0x26, 0x20,
- 0x21, 0x23, 0x1e, 0x26, 0x1c, 0x2b, 0x19, 0x2e, 0x16, 0x30, 0x15, 0x35,
- 0x12, 0x37, 0x11, 0x3b, 0x0f, 0x3d, 0x0f, 0x41, 0x0c, 0x42, 0x0c, 0x46,
- 0x0a, 0x47, 0x0a, 0x4a, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7,
- 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x22, 0x62, 0x1e, 0x64,
- 0x1a, 0x66, 0x18, 0x68, 0x15, 0x6a, 0x13, 0x6b, 0x10, 0x6d, 0x0f, 0x6e,
- 0x0e, 0x71, 0x0c, 0x72, 0x0b, 0x74, 0x0a, 0x76, 0x09, 0x77, 0x08, 0x79,
- 0x07, 0x7a, 0x07, 0x7c, 0x06, 0x7c, 0x06, 0x7e, 0x05, 0x7f, 0x05, 0x80,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x44, 0x09, 0x43, 0x09, 0x44, 0x09, 0x45, 0x09,
- 0x45, 0x09, 0x46, 0x09, 0x46, 0x09, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x00, 0x22, 0x1c, 0x0a, 0x29, 0x0a, 0x31, 0x09, 0x36, 0x09, 0x3a, 0x09,
- 0x3b, 0x09, 0x3d, 0x09, 0x3f, 0x09, 0x40, 0x09, 0x40, 0x09, 0x41, 0x09,
- 0x42, 0x09, 0x43, 0x09, 0x43, 0x0a, 0x43, 0x0a, 0x44, 0x0a, 0x44, 0x0a,
- 0x44, 0x0a, 0x44, 0x0a, 0x23, 0x16, 0x32, 0x0a, 0x38, 0x0a, 0x3c, 0x0a,
- 0x3f, 0x09, 0x40, 0x09, 0x41, 0x09, 0x42, 0x09, 0x43, 0x09, 0x44, 0x09,
- 0x44, 0x0a, 0x44, 0x0a, 0x44, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x45, 0x0a,
- 0x45, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x46, 0x0a, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3f, 0x16, 0x3e, 0x11, 0x3f, 0x0f, 0x40, 0x0d, 0x41, 0x0d, 0x41, 0x0c,
- 0x42, 0x0c, 0x43, 0x0b, 0x43, 0x0b, 0x43, 0x0b, 0x43, 0x0b, 0x44, 0x0a,
- 0x44, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x46, 0x0a, 0x46, 0x0a,
- 0x46, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0x6e, 0x03, 0x3a,
- 0x0f, 0x27, 0x18, 0x1e, 0x1f, 0x19, 0x24, 0x17, 0x28, 0x14, 0x2c, 0x13,
- 0x2f, 0x11, 0x31, 0x11, 0x32, 0x10, 0x34, 0x0f, 0x36, 0x0f, 0x37, 0x0f,
- 0x38, 0x0e, 0x39, 0x0e, 0x3a, 0x0d, 0x3a, 0x0d, 0x3b, 0x0c, 0x3c, 0x0c,
- 0x23, 0x3c, 0x25, 0x22, 0x2b, 0x18, 0x30, 0x14, 0x33, 0x11, 0x36, 0x10,
- 0x38, 0x0f, 0x39, 0x0e, 0x3b, 0x0e, 0x3c, 0x0d, 0x3d, 0x0d, 0x3e, 0x0c,
- 0x3f, 0x0c, 0x3f, 0x0c, 0x40, 0x0c, 0x40, 0x0c, 0x40, 0x0b, 0x41, 0x0b,
- 0x41, 0x0b, 0x42, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x1f, 0x3c, 0x18,
- 0x3c, 0x14, 0x3d, 0x11, 0x3e, 0x11, 0x3f, 0x0f, 0x3f, 0x0e, 0x40, 0x0e,
- 0x41, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0c, 0x42, 0x0c,
- 0x42, 0x0b, 0x42, 0x0b, 0x43, 0x0b, 0x43, 0x0b, 0x44, 0x0b, 0x44, 0x0b,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x00, 0x8a, 0x00, 0x59, 0x06, 0x40, 0x0d, 0x32,
- 0x12, 0x2a, 0x18, 0x24, 0x1c, 0x20, 0x20, 0x1c, 0x23, 0x1b, 0x26, 0x18,
- 0x28, 0x17, 0x2a, 0x16, 0x2c, 0x15, 0x2e, 0x14, 0x2f, 0x13, 0x31, 0x12,
- 0x32, 0x12, 0x33, 0x12, 0x34, 0x11, 0x35, 0x10, 0x23, 0x4a, 0x24, 0x31,
- 0x27, 0x25, 0x2a, 0x1e, 0x2d, 0x1a, 0x2f, 0x17, 0x32, 0x15, 0x33, 0x13,
- 0x35, 0x12, 0x36, 0x11, 0x38, 0x10, 0x39, 0x10, 0x3a, 0x0f, 0x3a, 0x0f,
- 0x3b, 0x0e, 0x3c, 0x0e, 0x3c, 0x0e, 0x3d, 0x0e, 0x3e, 0x0d, 0x3e, 0x0d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3e, 0x25, 0x3c, 0x1d, 0x3c, 0x19, 0x3c, 0x16,
- 0x3d, 0x14, 0x3d, 0x12, 0x3f, 0x11, 0x3f, 0x10, 0x3f, 0x0f, 0x3f, 0x0f,
- 0x40, 0x0e, 0x41, 0x0e, 0x41, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d,
- 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0c, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x00, 0x97, 0x00, 0x6c, 0x02, 0x52, 0x07, 0x43, 0x0b, 0x38, 0x10, 0x30,
- 0x14, 0x2a, 0x18, 0x27, 0x1b, 0x23, 0x1e, 0x20, 0x20, 0x1e, 0x23, 0x1c,
- 0x25, 0x1b, 0x27, 0x19, 0x28, 0x18, 0x2a, 0x17, 0x2b, 0x16, 0x2c, 0x16,
- 0x2e, 0x16, 0x2f, 0x15, 0x23, 0x50, 0x23, 0x3b, 0x25, 0x2e, 0x27, 0x26,
- 0x29, 0x21, 0x2c, 0x1d, 0x2e, 0x1a, 0x2f, 0x18, 0x31, 0x16, 0x33, 0x15,
- 0x34, 0x14, 0x35, 0x13, 0x36, 0x12, 0x37, 0x11, 0x38, 0x11, 0x38, 0x11,
- 0x39, 0x10, 0x3a, 0x10, 0x3a, 0x10, 0x3b, 0x0f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3e, 0x29, 0x3c, 0x22, 0x3b, 0x1d, 0x3b, 0x19, 0x3c, 0x17, 0x3c, 0x15,
- 0x3c, 0x13, 0x3d, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x10, 0x3e, 0x0f,
- 0x3f, 0x0f, 0x40, 0x0e, 0x40, 0x0e, 0x41, 0x0e, 0x42, 0x0e, 0x42, 0x0d,
- 0x42, 0x0d, 0x42, 0x0d, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0x9e, 0x00, 0x79,
- 0x00, 0x61, 0x04, 0x50, 0x07, 0x44, 0x0b, 0x3b, 0x0f, 0x34, 0x12, 0x2f,
- 0x15, 0x2b, 0x18, 0x28, 0x1a, 0x25, 0x1d, 0x23, 0x1f, 0x21, 0x21, 0x1f,
- 0x22, 0x1d, 0x24, 0x1c, 0x26, 0x1b, 0x27, 0x19, 0x28, 0x19, 0x2a, 0x19,
- 0x23, 0x54, 0x23, 0x42, 0x24, 0x35, 0x25, 0x2d, 0x27, 0x27, 0x29, 0x22,
- 0x2b, 0x1f, 0x2d, 0x1c, 0x2e, 0x1a, 0x30, 0x19, 0x31, 0x17, 0x32, 0x16,
- 0x33, 0x15, 0x34, 0x14, 0x35, 0x13, 0x36, 0x13, 0x37, 0x12, 0x37, 0x11,
- 0x38, 0x11, 0x38, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x2c, 0x3c, 0x25,
- 0x3b, 0x20, 0x3b, 0x1d, 0x3b, 0x1a, 0x3c, 0x17, 0x3c, 0x16, 0x3c, 0x14,
- 0x3c, 0x13, 0x3e, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3f, 0x11, 0x3d, 0x10,
- 0x3e, 0x0f, 0x3f, 0x0f, 0x40, 0x0f, 0x40, 0x0e, 0x40, 0x0e, 0x41, 0x0e,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xa2, 0x00, 0x84, 0x00, 0x6c, 0x02, 0x5a,
- 0x05, 0x4e, 0x07, 0x45, 0x0b, 0x3e, 0x0e, 0x38, 0x10, 0x33, 0x13, 0x2f,
- 0x16, 0x2c, 0x18, 0x29, 0x1a, 0x26, 0x1c, 0x24, 0x1d, 0x22, 0x1f, 0x21,
- 0x21, 0x1f, 0x21, 0x1e, 0x23, 0x1d, 0x25, 0x1c, 0x23, 0x56, 0x23, 0x47,
- 0x23, 0x3b, 0x24, 0x32, 0x26, 0x2c, 0x27, 0x27, 0x29, 0x24, 0x2a, 0x21,
- 0x2c, 0x1e, 0x2d, 0x1c, 0x2e, 0x1b, 0x30, 0x19, 0x30, 0x18, 0x32, 0x17,
- 0x32, 0x16, 0x33, 0x15, 0x34, 0x14, 0x34, 0x14, 0x35, 0x13, 0x36, 0x13,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3e, 0x2e, 0x3c, 0x27, 0x3b, 0x23, 0x3b, 0x1f,
- 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x18, 0x3c, 0x17, 0x3b, 0x15, 0x3c, 0x14,
- 0x3c, 0x13, 0x3e, 0x13, 0x3f, 0x11, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x11,
- 0x3d, 0x10, 0x3e, 0x0f, 0x3f, 0x0f, 0x40, 0x0f, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x00, 0xa6, 0x00, 0x8b, 0x00, 0x75, 0x01, 0x63, 0x02, 0x57, 0x05, 0x4d,
- 0x07, 0x45, 0x0a, 0x3e, 0x0d, 0x39, 0x0f, 0x35, 0x12, 0x32, 0x14, 0x2e,
- 0x16, 0x2c, 0x18, 0x29, 0x19, 0x27, 0x1b, 0x26, 0x1d, 0x24, 0x1e, 0x22,
- 0x20, 0x22, 0x21, 0x20, 0x23, 0x58, 0x23, 0x4a, 0x23, 0x3f, 0x24, 0x36,
- 0x25, 0x30, 0x26, 0x2b, 0x27, 0x27, 0x29, 0x24, 0x2a, 0x22, 0x2b, 0x20,
- 0x2d, 0x1e, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x30, 0x18, 0x31, 0x18,
- 0x32, 0x17, 0x32, 0x16, 0x33, 0x16, 0x34, 0x15, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3e, 0x30, 0x3c, 0x2a, 0x3c, 0x25, 0x3a, 0x21, 0x3b, 0x1e, 0x3a, 0x1c,
- 0x3b, 0x1a, 0x3c, 0x18, 0x3c, 0x17, 0x3c, 0x16, 0x3b, 0x15, 0x3c, 0x14,
- 0x3d, 0x13, 0x3e, 0x13, 0x3f, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x11,
- 0x3d, 0x10, 0x3e, 0x0f, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xa8, 0x00, 0x90,
- 0x00, 0x7c, 0x00, 0x6b, 0x01, 0x5f, 0x04, 0x55, 0x05, 0x4c, 0x07, 0x45,
- 0x0a, 0x40, 0x0c, 0x3c, 0x0f, 0x37, 0x10, 0x34, 0x12, 0x31, 0x15, 0x2e,
- 0x16, 0x2b, 0x18, 0x2a, 0x19, 0x28, 0x1a, 0x26, 0x1d, 0x25, 0x1d, 0x23,
- 0x23, 0x59, 0x23, 0x4d, 0x23, 0x43, 0x24, 0x3b, 0x24, 0x34, 0x25, 0x2f,
- 0x26, 0x2b, 0x27, 0x28, 0x28, 0x25, 0x2a, 0x23, 0x2b, 0x21, 0x2c, 0x1f,
- 0x2d, 0x1d, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x30, 0x19, 0x31, 0x18,
- 0x32, 0x17, 0x32, 0x16, 0x17, 0x00, 0x2f, 0x00, 0x4c, 0x00, 0x56, 0x00,
- 0x59, 0x00, 0x5b, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00,
- 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5f, 0x00,
- 0x14, 0x2c, 0x29, 0x01, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x5b, 0x00,
- 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00,
- 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x62, 0x00,
- 0x62, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00,
- 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5f, 0x00,
- 0x11, 0x31, 0x23, 0x03, 0x46, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5a, 0x00,
- 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00,
- 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x3e, 0x32, 0x3d, 0x2c,
- 0x3c, 0x26, 0x3b, 0x23, 0x3b, 0x20, 0x3b, 0x1e, 0x3a, 0x1c, 0x3b, 0x1a,
- 0x3c, 0x18, 0x3c, 0x17, 0x3c, 0x17, 0x3a, 0x15, 0x3c, 0x15, 0x3c, 0x14,
- 0x3d, 0x13, 0x3e, 0x13, 0x3f, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x11,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xaa, 0x00, 0x94, 0x00, 0x82, 0x00, 0x72,
- 0x01, 0x65, 0x02, 0x5b, 0x04, 0x53, 0x06, 0x4b, 0x08, 0x45, 0x0a, 0x41,
- 0x0c, 0x3d, 0x0e, 0x39, 0x0f, 0x36, 0x12, 0x33, 0x12, 0x30, 0x16, 0x2e,
- 0x16, 0x2b, 0x18, 0x2b, 0x19, 0x29, 0x1a, 0x26, 0x23, 0x5a, 0x23, 0x4f,
- 0x23, 0x46, 0x23, 0x3e, 0x24, 0x37, 0x25, 0x32, 0x25, 0x2e, 0x26, 0x2b,
- 0x27, 0x28, 0x28, 0x25, 0x2a, 0x23, 0x2b, 0x21, 0x2b, 0x20, 0x2d, 0x1e,
- 0x2d, 0x1d, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x30, 0x19, 0x30, 0x18,
- 0x00, 0x00, 0x07, 0x00, 0x2f, 0x00, 0x45, 0x00, 0x4f, 0x00, 0x55, 0x00,
- 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00,
- 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x00, 0x57, 0x04, 0x16,
- 0x27, 0x00, 0x41, 0x00, 0x4d, 0x00, 0x53, 0x00, 0x56, 0x00, 0x59, 0x00,
- 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00,
- 0x5d, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x4c, 0x00, 0x3b, 0x00, 0x48, 0x00, 0x55, 0x00, 0x58, 0x00, 0x57, 0x00,
- 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00,
- 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x00, 0x5f, 0x00, 0x20,
- 0x1f, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x51, 0x00, 0x55, 0x00, 0x58, 0x00,
- 0x59, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00,
- 0x5d, 0x00, 0x5d, 0x00, 0x3e, 0x33, 0x3d, 0x2d, 0x3c, 0x28, 0x3b, 0x25,
- 0x3a, 0x22, 0x3b, 0x1f, 0x3b, 0x1e, 0x3a, 0x1c, 0x3b, 0x1a, 0x3c, 0x19,
- 0x3c, 0x17, 0x3c, 0x17, 0x3b, 0x16, 0x3b, 0x15, 0x3c, 0x15, 0x3c, 0x13,
- 0x3d, 0x13, 0x3f, 0x13, 0x3f, 0x12, 0x3f, 0x11, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x00, 0xaa, 0x00, 0x98, 0x00, 0x87, 0x00, 0x78, 0x00, 0x6b, 0x01, 0x61,
- 0x03, 0x58, 0x05, 0x51, 0x07, 0x4b, 0x08, 0x46, 0x0a, 0x42, 0x0c, 0x3e,
- 0x0d, 0x3a, 0x0f, 0x37, 0x11, 0x35, 0x12, 0x32, 0x14, 0x30, 0x16, 0x2e,
- 0x16, 0x2b, 0x18, 0x2b, 0x23, 0x5a, 0x23, 0x51, 0x23, 0x48, 0x23, 0x41,
- 0x24, 0x3a, 0x24, 0x35, 0x25, 0x31, 0x26, 0x2e, 0x27, 0x2a, 0x27, 0x28,
- 0x28, 0x26, 0x2a, 0x24, 0x2a, 0x22, 0x2b, 0x21, 0x2c, 0x1f, 0x2d, 0x1e,
- 0x2d, 0x1d, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x22, 0x00, 0x36, 0x00, 0x42, 0x00, 0x4a, 0x00, 0x4f, 0x00,
- 0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
- 0x5b, 0x00, 0x5b, 0x00, 0x00, 0x82, 0x00, 0x57, 0x01, 0x12, 0x17, 0x00,
- 0x2f, 0x00, 0x3e, 0x00, 0x47, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x53, 0x00,
- 0x56, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x48, 0x00,
- 0x1b, 0x00, 0x34, 0x00, 0x40, 0x00, 0x44, 0x00, 0x4a, 0x00, 0x4f, 0x00,
- 0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
- 0x5b, 0x00, 0x5b, 0x00, 0x00, 0x85, 0x00, 0x5f, 0x00, 0x1f, 0x0d, 0x00,
- 0x28, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x52, 0x00,
- 0x54, 0x00, 0x56, 0x00, 0x57, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5a, 0x00,
- 0x3e, 0x34, 0x3d, 0x2f, 0x3b, 0x2a, 0x3c, 0x26, 0x3a, 0x23, 0x3b, 0x21,
- 0x3b, 0x1f, 0x3b, 0x1d, 0x3a, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x17,
- 0x3c, 0x17, 0x3b, 0x17, 0x3a, 0x15, 0x3c, 0x15, 0x3c, 0x15, 0x3c, 0x13,
- 0x3e, 0x13, 0x3f, 0x13, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xac, 0x00, 0x9b,
- 0x00, 0x8b, 0x00, 0x7c, 0x00, 0x71, 0x01, 0x67, 0x02, 0x5e, 0x04, 0x57,
- 0x05, 0x51, 0x07, 0x4b, 0x08, 0x46, 0x0a, 0x42, 0x0c, 0x3f, 0x0c, 0x3b,
- 0x0f, 0x39, 0x0f, 0x35, 0x12, 0x34, 0x12, 0x31, 0x14, 0x30, 0x16, 0x2e,
- 0x23, 0x5b, 0x23, 0x52, 0x23, 0x4a, 0x23, 0x43, 0x23, 0x3d, 0x24, 0x38,
- 0x25, 0x34, 0x25, 0x30, 0x26, 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x26,
- 0x2a, 0x24, 0x2a, 0x22, 0x2b, 0x21, 0x2b, 0x20, 0x2d, 0x1f, 0x2d, 0x1d,
- 0x2e, 0x1d, 0x2e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x19, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40, 0x00, 0x47, 0x00, 0x4b, 0x00,
- 0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
- 0x00, 0x91, 0x00, 0x78, 0x00, 0x43, 0x00, 0x10, 0x0e, 0x00, 0x23, 0x00,
- 0x31, 0x00, 0x3b, 0x00, 0x42, 0x00, 0x48, 0x00, 0x4c, 0x00, 0x4f, 0x00,
- 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x55, 0x00, 0x34, 0x00, 0x0b, 0x00,
- 0x1f, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40, 0x00, 0x47, 0x00, 0x4b, 0x00,
- 0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
- 0x00, 0x92, 0x00, 0x7c, 0x00, 0x4d, 0x00, 0x1f, 0x02, 0x00, 0x1a, 0x00,
- 0x2a, 0x00, 0x36, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4d, 0x00,
- 0x4f, 0x00, 0x52, 0x00, 0x53, 0x00, 0x55, 0x00, 0x3e, 0x35, 0x3e, 0x30,
- 0x3b, 0x2c, 0x3c, 0x28, 0x3b, 0x25, 0x3a, 0x22, 0x3b, 0x20, 0x3b, 0x1f,
- 0x3a, 0x1d, 0x3a, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x18, 0x3c, 0x17,
- 0x3c, 0x17, 0x3a, 0x16, 0x3b, 0x15, 0x3c, 0x15, 0x3c, 0x14, 0x3c, 0x13,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xad, 0x00, 0x9d, 0x00, 0x8e, 0x00, 0x81,
- 0x00, 0x76, 0x00, 0x6b, 0x01, 0x63, 0x02, 0x5c, 0x04, 0x56, 0x05, 0x50,
- 0x07, 0x4b, 0x08, 0x47, 0x0a, 0x43, 0x0c, 0x40, 0x0c, 0x3c, 0x0f, 0x3a,
- 0x0f, 0x37, 0x11, 0x35, 0x12, 0x33, 0x12, 0x30, 0x23, 0x5b, 0x23, 0x53,
- 0x23, 0x4c, 0x23, 0x45, 0x23, 0x40, 0x24, 0x3b, 0x24, 0x36, 0x25, 0x33,
- 0x25, 0x30, 0x26, 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x26, 0x2a, 0x25,
- 0x2a, 0x23, 0x2b, 0x22, 0x2b, 0x20, 0x2c, 0x20, 0x2d, 0x1e, 0x2d, 0x1d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00,
- 0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f, 0x00, 0x44, 0x00, 0x48, 0x00,
- 0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52, 0x00, 0x00, 0x96, 0x00, 0x87,
- 0x00, 0x61, 0x00, 0x36, 0x00, 0x10, 0x0a, 0x02, 0x1a, 0x00, 0x27, 0x00,
- 0x32, 0x00, 0x3a, 0x00, 0x40, 0x00, 0x44, 0x00, 0x48, 0x00, 0x4b, 0x00,
- 0x4e, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x62, 0x00, 0x58, 0x00, 0x40, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x14, 0x00,
- 0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f, 0x00, 0x44, 0x00, 0x48, 0x00,
- 0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52, 0x00, 0x00, 0x97, 0x00, 0x8a,
- 0x00, 0x68, 0x00, 0x42, 0x00, 0x1f, 0x00, 0x04, 0x10, 0x00, 0x1f, 0x00,
- 0x2b, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x41, 0x00, 0x45, 0x00, 0x49, 0x00,
- 0x4b, 0x00, 0x4e, 0x00, 0x3e, 0x36, 0x3e, 0x31, 0x3b, 0x2c, 0x3c, 0x29,
- 0x3c, 0x26, 0x3a, 0x24, 0x3a, 0x21, 0x3b, 0x20, 0x3b, 0x1f, 0x39, 0x1d,
- 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x18, 0x3c, 0x17, 0x3c, 0x17,
- 0x3a, 0x17, 0x3a, 0x15, 0x3c, 0x15, 0x3c, 0x15, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x00, 0xad, 0x00, 0x9f, 0x00, 0x91, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6f,
- 0x01, 0x67, 0x02, 0x60, 0x03, 0x59, 0x04, 0x54, 0x05, 0x4f, 0x07, 0x4b,
- 0x08, 0x47, 0x0a, 0x43, 0x0b, 0x41, 0x0c, 0x3d, 0x0e, 0x3b, 0x0f, 0x38,
- 0x0f, 0x35, 0x12, 0x35, 0x23, 0x5b, 0x23, 0x54, 0x23, 0x4e, 0x23, 0x47,
- 0x23, 0x42, 0x24, 0x3c, 0x24, 0x38, 0x25, 0x35, 0x25, 0x32, 0x26, 0x2f,
- 0x26, 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x26, 0x29, 0x25, 0x2a, 0x23,
- 0x2b, 0x22, 0x2b, 0x21, 0x2b, 0x20, 0x2d, 0x20, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1e, 0x00,
- 0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x46, 0x00,
- 0x49, 0x00, 0x4c, 0x00, 0x00, 0x99, 0x00, 0x8f, 0x00, 0x74, 0x00, 0x51,
- 0x00, 0x2e, 0x00, 0x10, 0x08, 0x04, 0x13, 0x00, 0x20, 0x00, 0x2a, 0x00,
- 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x48, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x57, 0x00,
- 0x44, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1e, 0x00,
- 0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x46, 0x00,
- 0x49, 0x00, 0x4c, 0x00, 0x00, 0x9a, 0x00, 0x91, 0x00, 0x79, 0x00, 0x5a,
- 0x00, 0x3b, 0x00, 0x1f, 0x00, 0x09, 0x08, 0x00, 0x17, 0x00, 0x22, 0x00,
- 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00,
- 0x3e, 0x36, 0x3e, 0x31, 0x3b, 0x2d, 0x3b, 0x2a, 0x3c, 0x27, 0x3a, 0x25,
- 0x3a, 0x23, 0x3b, 0x21, 0x3b, 0x1f, 0x3b, 0x1f, 0x39, 0x1c, 0x3b, 0x1c,
- 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x17, 0x3c, 0x17, 0x3b, 0x17,
- 0x3a, 0x16, 0x3b, 0x15, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xad, 0x00, 0xa0,
- 0x00, 0x94, 0x00, 0x88, 0x00, 0x7e, 0x00, 0x74, 0x00, 0x6c, 0x01, 0x65,
- 0x02, 0x5e, 0x04, 0x58, 0x05, 0x53, 0x05, 0x4f, 0x07, 0x4b, 0x08, 0x47,
- 0x0a, 0x44, 0x0b, 0x41, 0x0c, 0x3e, 0x0d, 0x3b, 0x0f, 0x3a, 0x0f, 0x37,
- 0x23, 0x5c, 0x23, 0x55, 0x23, 0x4f, 0x23, 0x49, 0x23, 0x44, 0x23, 0x3f,
- 0x24, 0x3b, 0x24, 0x37, 0x25, 0x34, 0x25, 0x31, 0x26, 0x2e, 0x26, 0x2c,
- 0x27, 0x2a, 0x28, 0x28, 0x28, 0x27, 0x29, 0x25, 0x2a, 0x24, 0x2a, 0x22,
- 0x2b, 0x22, 0x2b, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00,
- 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x41, 0x00, 0x44, 0x00,
- 0x00, 0x9b, 0x00, 0x94, 0x00, 0x7f, 0x00, 0x64, 0x00, 0x46, 0x00, 0x29,
- 0x00, 0x10, 0x07, 0x06, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00, 0x2c, 0x00,
- 0x32, 0x00, 0x38, 0x00, 0x3c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x38, 0x00,
- 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00,
- 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x41, 0x00, 0x44, 0x00,
- 0x00, 0x9b, 0x00, 0x95, 0x00, 0x83, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x36,
- 0x00, 0x1f, 0x00, 0x0c, 0x03, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x24, 0x00,
- 0x2c, 0x00, 0x32, 0x00, 0x37, 0x00, 0x3c, 0x00, 0x3e, 0x37, 0x3e, 0x32,
- 0x3c, 0x2f, 0x3b, 0x2b, 0x3c, 0x28, 0x3b, 0x26, 0x3a, 0x24, 0x3a, 0x22,
- 0x3b, 0x21, 0x3b, 0x1f, 0x3a, 0x1e, 0x39, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a,
- 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x17, 0x3c, 0x17, 0x3b, 0x17, 0x3a, 0x17,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xae, 0x00, 0xa2, 0x00, 0x97, 0x00, 0x8b,
- 0x00, 0x80, 0x00, 0x77, 0x00, 0x6f, 0x01, 0x67, 0x02, 0x61, 0x02, 0x5c,
- 0x04, 0x57, 0x05, 0x52, 0x05, 0x4e, 0x07, 0x4b, 0x09, 0x47, 0x0a, 0x44,
- 0x0b, 0x41, 0x0c, 0x3f, 0x0c, 0x3c, 0x0f, 0x3b, 0x23, 0x5c, 0x23, 0x56,
- 0x23, 0x50, 0x23, 0x4a, 0x23, 0x45, 0x23, 0x40, 0x24, 0x3c, 0x24, 0x39,
- 0x25, 0x35, 0x25, 0x33, 0x25, 0x30, 0x26, 0x2e, 0x26, 0x2c, 0x27, 0x2a,
- 0x28, 0x28, 0x28, 0x27, 0x29, 0x25, 0x2a, 0x24, 0x2a, 0x23, 0x2b, 0x22,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x20, 0x00, 0x28, 0x00,
- 0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x00, 0x9c, 0x00, 0x96,
- 0x00, 0x87, 0x00, 0x71, 0x00, 0x57, 0x00, 0x3d, 0x00, 0x25, 0x00, 0x10,
- 0x06, 0x07, 0x0b, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x26, 0x00, 0x2d, 0x00,
- 0x32, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e, 0x00,
- 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x20, 0x00, 0x28, 0x00,
- 0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x00, 0x9c, 0x00, 0x97,
- 0x00, 0x8a, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x48, 0x00, 0x33, 0x00, 0x1f,
- 0x00, 0x0f, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x25, 0x00,
- 0x2c, 0x00, 0x31, 0x00, 0x3e, 0x37, 0x3e, 0x33, 0x3c, 0x2f, 0x3b, 0x2c,
- 0x3c, 0x29, 0x3c, 0x27, 0x39, 0x25, 0x3a, 0x23, 0x3b, 0x21, 0x3b, 0x20,
- 0x3b, 0x1f, 0x3a, 0x1e, 0x39, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19,
- 0x3c, 0x19, 0x3c, 0x18, 0x3c, 0x17, 0x3b, 0x17, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x00, 0xaf, 0x00, 0xa3, 0x00, 0x98, 0x00, 0x8e, 0x00, 0x84, 0x00, 0x7a,
- 0x00, 0x72, 0x00, 0x6c, 0x01, 0x65, 0x02, 0x5f, 0x04, 0x5a, 0x04, 0x56,
- 0x05, 0x52, 0x06, 0x4e, 0x07, 0x4a, 0x09, 0x47, 0x0a, 0x45, 0x0a, 0x41,
- 0x0c, 0x40, 0x0c, 0x3d, 0x23, 0x5c, 0x23, 0x56, 0x23, 0x51, 0x23, 0x4c,
- 0x23, 0x47, 0x23, 0x42, 0x23, 0x3e, 0x24, 0x3b, 0x24, 0x37, 0x25, 0x34,
- 0x25, 0x32, 0x25, 0x30, 0x26, 0x2e, 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28,
- 0x28, 0x27, 0x29, 0x25, 0x2a, 0x25, 0x2a, 0x23, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d, 0x00, 0x24, 0x00, 0x2a, 0x00,
- 0x30, 0x00, 0x35, 0x00, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x7a,
- 0x00, 0x64, 0x00, 0x4e, 0x00, 0x37, 0x00, 0x22, 0x00, 0x10, 0x05, 0x08,
- 0x0a, 0x02, 0x12, 0x00, 0x1a, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2d, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00,
- 0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29, 0x00, 0x1a, 0x00, 0x0c, 0x00,
- 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d, 0x00, 0x24, 0x00, 0x2a, 0x00,
- 0x30, 0x00, 0x35, 0x00, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e,
- 0x00, 0x6b, 0x00, 0x57, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x11,
- 0x00, 0x04, 0x07, 0x00, 0x10, 0x00, 0x19, 0x00, 0x20, 0x00, 0x26, 0x00,
- 0x3e, 0x38, 0x3e, 0x33, 0x3d, 0x30, 0x3b, 0x2d, 0x3c, 0x2a, 0x3c, 0x27,
- 0x3a, 0x26, 0x3a, 0x24, 0x3a, 0x22, 0x3b, 0x21, 0x3b, 0x1f, 0x3b, 0x1f,
- 0x39, 0x1e, 0x3a, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19,
- 0x3c, 0x18, 0x3c, 0x17, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xaf, 0x00, 0xa5,
- 0x00, 0x99, 0x00, 0x90, 0x00, 0x87, 0x00, 0x7e, 0x00, 0x76, 0x00, 0x6f,
- 0x01, 0x68, 0x02, 0x62, 0x02, 0x5e, 0x04, 0x59, 0x04, 0x55, 0x05, 0x51,
- 0x07, 0x4e, 0x07, 0x4a, 0x09, 0x47, 0x0a, 0x45, 0x0a, 0x41, 0x0c, 0x41,
- 0x23, 0x5c, 0x23, 0x57, 0x23, 0x52, 0x23, 0x4d, 0x23, 0x48, 0x23, 0x44,
- 0x23, 0x40, 0x24, 0x3c, 0x24, 0x39, 0x24, 0x36, 0x25, 0x34, 0x25, 0x31,
- 0x26, 0x2f, 0x26, 0x2d, 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x27,
- 0x28, 0x25, 0x2a, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2c, 0x00,
- 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x90, 0x00, 0x81, 0x00, 0x6f, 0x00, 0x5b,
- 0x00, 0x46, 0x00, 0x32, 0x00, 0x20, 0x00, 0x10, 0x04, 0x09, 0x09, 0x03,
- 0x0f, 0x00, 0x17, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x4b, 0x00,
- 0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00, 0x00,
- 0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2c, 0x00,
- 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x92, 0x00, 0x84, 0x00, 0x74, 0x00, 0x62,
- 0x00, 0x50, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x06,
- 0x03, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x3e, 0x38, 0x3e, 0x34,
- 0x3e, 0x31, 0x3b, 0x2e, 0x3b, 0x2b, 0x3c, 0x29, 0x3c, 0x27, 0x39, 0x25,
- 0x3a, 0x24, 0x3a, 0x21, 0x3b, 0x21, 0x3b, 0x1f, 0x3b, 0x1f, 0x39, 0x1d,
- 0x3a, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x19,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xaf, 0x00, 0xa6, 0x00, 0x9b, 0x00, 0x91,
- 0x00, 0x88, 0x00, 0x80, 0x00, 0x78, 0x00, 0x71, 0x00, 0x6b, 0x01, 0x66,
- 0x02, 0x61, 0x03, 0x5c, 0x04, 0x58, 0x05, 0x55, 0x05, 0x50, 0x07, 0x4e,
- 0x07, 0x4a, 0x09, 0x47, 0x0a, 0x45, 0x0a, 0x42, 0x23, 0x5c, 0x23, 0x58,
- 0x23, 0x53, 0x23, 0x4d, 0x23, 0x49, 0x23, 0x45, 0x23, 0x41, 0x24, 0x3d,
- 0x24, 0x3b, 0x24, 0x38, 0x25, 0x35, 0x25, 0x33, 0x25, 0x31, 0x26, 0x2f,
- 0x26, 0x2d, 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x26,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x9d, 0x00, 0x9b,
- 0x00, 0x93, 0x00, 0x86, 0x00, 0x76, 0x00, 0x65, 0x00, 0x52, 0x00, 0x40,
- 0x00, 0x2f, 0x00, 0x1e, 0x00, 0x10, 0x04, 0x09, 0x08, 0x04, 0x0c, 0x00,
- 0x14, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38, 0x00,
- 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x9e, 0x00, 0x9b,
- 0x00, 0x94, 0x00, 0x89, 0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4b,
- 0x00, 0x3b, 0x00, 0x2d, 0x00, 0x1f, 0x00, 0x13, 0x00, 0x08, 0x00, 0x00,
- 0x09, 0x00, 0x11, 0x00, 0x3e, 0x38, 0x3e, 0x35, 0x3e, 0x32, 0x3b, 0x2e,
- 0x3b, 0x2c, 0x3c, 0x2a, 0x3c, 0x27, 0x3a, 0x26, 0x3a, 0x24, 0x3a, 0x23,
- 0x3b, 0x21, 0x3b, 0x20, 0x3b, 0x1f, 0x3a, 0x1f, 0x39, 0x1d, 0x3a, 0x1c,
- 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x00, 0xb0, 0x00, 0xa6, 0x00, 0x9d, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x83,
- 0x00, 0x7c, 0x00, 0x75, 0x00, 0x6e, 0x01, 0x69, 0x01, 0x63, 0x02, 0x5f,
- 0x04, 0x5b, 0x04, 0x56, 0x05, 0x54, 0x05, 0x4f, 0x07, 0x4e, 0x07, 0x4a,
- 0x09, 0x47, 0x0a, 0x46, 0x23, 0x5d, 0x23, 0x58, 0x23, 0x53, 0x23, 0x4f,
- 0x23, 0x4a, 0x23, 0x46, 0x23, 0x43, 0x23, 0x3f, 0x24, 0x3c, 0x24, 0x39,
- 0x24, 0x36, 0x25, 0x34, 0x25, 0x32, 0x25, 0x30, 0x26, 0x2f, 0x26, 0x2d,
- 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00,
- 0x16, 0x00, 0x1c, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x95, 0x00, 0x8a,
- 0x00, 0x7d, 0x00, 0x6d, 0x00, 0x5d, 0x00, 0x4c, 0x00, 0x3b, 0x00, 0x2c,
- 0x00, 0x1d, 0x00, 0x10, 0x04, 0x0a, 0x07, 0x05, 0x0b, 0x00, 0x11, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00,
- 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x28, 0x00,
- 0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00,
- 0x16, 0x00, 0x1c, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8c,
- 0x00, 0x80, 0x00, 0x73, 0x00, 0x64, 0x00, 0x55, 0x00, 0x46, 0x00, 0x38,
- 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x06, 0x00,
- 0x3e, 0x39, 0x3e, 0x35, 0x3e, 0x32, 0x3b, 0x2f, 0x3b, 0x2d, 0x3c, 0x2a,
- 0x3c, 0x28, 0x3b, 0x27, 0x39, 0x24, 0x3a, 0x24, 0x3a, 0x22, 0x3b, 0x21,
- 0x3b, 0x1f, 0x3b, 0x1f, 0x39, 0x1f, 0x39, 0x1d, 0x3b, 0x1c, 0x3b, 0x1c,
- 0x3b, 0x1a, 0x3c, 0x19, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a,
- 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xb0, 0x00, 0xa7,
- 0x00, 0x9e, 0x00, 0x96, 0x00, 0x8d, 0x00, 0x86, 0x00, 0x7e, 0x00, 0x77,
- 0x00, 0x71, 0x00, 0x6b, 0x01, 0x66, 0x02, 0x62, 0x02, 0x5d, 0x04, 0x5a,
- 0x04, 0x55, 0x05, 0x53, 0x05, 0x4f, 0x07, 0x4e, 0x07, 0x4a, 0x09, 0x47,
- 0x23, 0x5d, 0x23, 0x58, 0x23, 0x54, 0x23, 0x50, 0x23, 0x4c, 0x23, 0x48,
- 0x23, 0x44, 0x23, 0x40, 0x24, 0x3d, 0x24, 0x3a, 0x24, 0x38, 0x25, 0x36,
- 0x25, 0x33, 0x25, 0x32, 0x25, 0x2f, 0x26, 0x2f, 0x26, 0x2c, 0x27, 0x2c,
- 0x27, 0x2a, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x14, 0x00,
- 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8d, 0x00, 0x81, 0x00, 0x74,
- 0x00, 0x65, 0x00, 0x56, 0x00, 0x46, 0x00, 0x37, 0x00, 0x29, 0x00, 0x1c,
- 0x00, 0x10, 0x03, 0x0a, 0x07, 0x06, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00,
- 0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e, 0x00, 0x24, 0x00, 0x1a, 0x00,
- 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x14, 0x00,
- 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8f, 0x00, 0x85, 0x00, 0x79,
- 0x00, 0x6b, 0x00, 0x5e, 0x00, 0x50, 0x00, 0x43, 0x00, 0x36, 0x00, 0x2a,
- 0x00, 0x1f, 0x00, 0x15, 0x00, 0x0c, 0x00, 0x03, 0x32, 0x59, 0x2a, 0x5b,
- 0x28, 0x5c, 0x27, 0x5d, 0x27, 0x5d, 0x26, 0x5e, 0x26, 0x5e, 0x26, 0x5e,
- 0x26, 0x5e, 0x26, 0x5e, 0x25, 0x5e, 0x25, 0x5e, 0x25, 0x5f, 0x25, 0x5f,
- 0x25, 0x5f, 0x25, 0x5f, 0x25, 0x5f, 0x24, 0x5f, 0x24, 0x5f, 0x24, 0x60,
- 0x32, 0x3c, 0x25, 0x4a, 0x24, 0x50, 0x23, 0x54, 0x23, 0x56, 0x23, 0x58,
- 0x23, 0x59, 0x23, 0x5a, 0x23, 0x5a, 0x23, 0x5b, 0x23, 0x5b, 0x23, 0x5b,
- 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5d,
- 0x23, 0x5d, 0x23, 0x5d, 0x00, 0x6c, 0x0e, 0x60, 0x14, 0x60, 0x18, 0x60,
- 0x1b, 0x60, 0x1d, 0x60, 0x1d, 0x60, 0x1e, 0x60, 0x1f, 0x60, 0x20, 0x60,
- 0x20, 0x60, 0x20, 0x60, 0x21, 0x60, 0x21, 0x60, 0x21, 0x60, 0x21, 0x60,
- 0x22, 0x60, 0x22, 0x60, 0x22, 0x60, 0x22, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x9e, 0x00, 0x9c,
- 0x00, 0x97, 0x00, 0x90, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x5e,
- 0x00, 0x50, 0x00, 0x42, 0x00, 0x34, 0x00, 0x27, 0x00, 0x1b, 0x00, 0x0f,
- 0x03, 0x0b, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x46, 0x00,
- 0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00,
- 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x9e, 0x00, 0x9d,
- 0x00, 0x98, 0x00, 0x91, 0x00, 0x88, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65,
- 0x00, 0x59, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x1f,
- 0x00, 0x16, 0x00, 0x0d, 0x38, 0x4f, 0x31, 0x53, 0x2e, 0x56, 0x2c, 0x57,
- 0x2a, 0x59, 0x29, 0x5a, 0x29, 0x5a, 0x28, 0x5b, 0x27, 0x5c, 0x27, 0x5c,
- 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c,
- 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x38, 0x22, 0x2b, 0x31,
- 0x27, 0x3b, 0x25, 0x42, 0x24, 0x47, 0x23, 0x4a, 0x23, 0x4d, 0x23, 0x4f,
- 0x23, 0x51, 0x23, 0x52, 0x23, 0x53, 0x23, 0x54, 0x23, 0x55, 0x23, 0x56,
- 0x23, 0x56, 0x23, 0x57, 0x23, 0x58, 0x23, 0x58, 0x23, 0x58, 0x23, 0x58,
- 0x00, 0x92, 0x01, 0x79, 0x07, 0x6f, 0x0c, 0x6b, 0x0f, 0x68, 0x12, 0x67,
- 0x14, 0x66, 0x16, 0x65, 0x17, 0x64, 0x18, 0x64, 0x19, 0x63, 0x1a, 0x63,
- 0x1b, 0x63, 0x1b, 0x63, 0x1c, 0x63, 0x1c, 0x62, 0x1d, 0x62, 0x1d, 0x62,
- 0x1d, 0x62, 0x1e, 0x62, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x06, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x92,
- 0x00, 0x89, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x58, 0x00, 0x4b,
- 0x00, 0x3e, 0x00, 0x31, 0x00, 0x25, 0x00, 0x1a, 0x00, 0x0f, 0x03, 0x0b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00,
- 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49, 0x00, 0x41, 0x00, 0x39, 0x00,
- 0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x07, 0x00,
- 0x00, 0x00, 0x06, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93,
- 0x00, 0x8b, 0x00, 0x82, 0x00, 0x77, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54,
- 0x00, 0x49, 0x00, 0x3d, 0x00, 0x33, 0x00, 0x29, 0x00, 0x1f, 0x00, 0x17,
- 0x3a, 0x4b, 0x34, 0x4f, 0x31, 0x52, 0x2f, 0x54, 0x2d, 0x56, 0x2c, 0x57,
- 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x59, 0x29, 0x5a, 0x29, 0x5a,
- 0x28, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c,
- 0x27, 0x5c, 0x27, 0x5c, 0x3c, 0x18, 0x30, 0x25, 0x2a, 0x2e, 0x27, 0x35,
- 0x25, 0x3b, 0x24, 0x3f, 0x24, 0x43, 0x24, 0x46, 0x23, 0x48, 0x23, 0x4a,
- 0x23, 0x4c, 0x23, 0x4e, 0x23, 0x4f, 0x23, 0x50, 0x23, 0x51, 0x23, 0x52,
- 0x23, 0x53, 0x23, 0x53, 0x23, 0x54, 0x23, 0x54, 0x00, 0xa1, 0x00, 0x88,
- 0x03, 0x7b, 0x06, 0x74, 0x09, 0x70, 0x0c, 0x6d, 0x0e, 0x6b, 0x10, 0x6a,
- 0x11, 0x69, 0x13, 0x68, 0x14, 0x67, 0x15, 0x66, 0x16, 0x66, 0x17, 0x65,
- 0x17, 0x65, 0x18, 0x65, 0x19, 0x65, 0x19, 0x64, 0x1a, 0x64, 0x1a, 0x64,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82,
- 0x00, 0x77, 0x00, 0x6b, 0x00, 0x5f, 0x00, 0x53, 0x00, 0x46, 0x00, 0x3a,
- 0x00, 0x2f, 0x00, 0x24, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x57, 0x00,
- 0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x2c, 0x00,
- 0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00,
- 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x8d, 0x00, 0x85,
- 0x00, 0x7b, 0x00, 0x71, 0x00, 0x66, 0x00, 0x5b, 0x00, 0x50, 0x00, 0x46,
- 0x00, 0x3b, 0x00, 0x31, 0x00, 0x28, 0x00, 0x1f, 0x3b, 0x48, 0x36, 0x4c,
- 0x33, 0x4f, 0x31, 0x52, 0x2f, 0x53, 0x2e, 0x53, 0x2d, 0x55, 0x2c, 0x57,
- 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x58,
- 0x2a, 0x59, 0x29, 0x5a, 0x29, 0x5b, 0x28, 0x5b, 0x27, 0x5c, 0x27, 0x5c,
- 0x3f, 0x14, 0x33, 0x1e, 0x2d, 0x26, 0x29, 0x2d, 0x27, 0x32, 0x26, 0x36,
- 0x25, 0x3b, 0x24, 0x3e, 0x24, 0x41, 0x24, 0x43, 0x23, 0x45, 0x23, 0x47,
- 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23, 0x4d, 0x23, 0x4d, 0x23, 0x4f,
- 0x23, 0x50, 0x23, 0x50, 0x00, 0xa7, 0x00, 0x92, 0x01, 0x84, 0x03, 0x7d,
- 0x05, 0x77, 0x08, 0x73, 0x0a, 0x71, 0x0c, 0x6f, 0x0d, 0x6d, 0x0f, 0x6b,
- 0x10, 0x6a, 0x11, 0x6a, 0x12, 0x69, 0x13, 0x68, 0x14, 0x68, 0x15, 0x67,
- 0x15, 0x66, 0x16, 0x66, 0x17, 0x66, 0x17, 0x66, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x31, 0x23, 0x03,
- 0x46, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5a, 0x00, 0x5c, 0x00, 0x5d, 0x00,
- 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00,
- 0x5e, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x11, 0x31, 0x00, 0x5f, 0x00, 0x85, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9a,
- 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e,
- 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3c, 0x47, 0x38, 0x4b, 0x35, 0x4e, 0x32, 0x4f,
- 0x31, 0x51, 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x55, 0x2c, 0x56,
- 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
- 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x58, 0x2a, 0x59, 0x40, 0x11, 0x36, 0x1a,
- 0x2f, 0x21, 0x2c, 0x27, 0x29, 0x2c, 0x27, 0x30, 0x26, 0x34, 0x25, 0x37,
- 0x25, 0x3a, 0x24, 0x3d, 0x24, 0x40, 0x24, 0x42, 0x24, 0x44, 0x23, 0x45,
- 0x23, 0x47, 0x23, 0x48, 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23, 0x4c,
- 0x00, 0xaa, 0x00, 0x98, 0x00, 0x8c, 0x02, 0x83, 0x03, 0x7d, 0x05, 0x79,
- 0x07, 0x76, 0x09, 0x73, 0x0a, 0x71, 0x0c, 0x6f, 0x0d, 0x6e, 0x0e, 0x6d,
- 0x0f, 0x6c, 0x10, 0x6b, 0x11, 0x6a, 0x12, 0x6a, 0x13, 0x69, 0x13, 0x68,
- 0x14, 0x68, 0x15, 0x68, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x20, 0x1f, 0x00, 0x3c, 0x00,
- 0x4a, 0x00, 0x51, 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00,
- 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x03, 0x00, 0x20,
- 0x00, 0x5f, 0x00, 0x7c, 0x00, 0x8a, 0x00, 0x91, 0x00, 0x95, 0x00, 0x97,
- 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d,
- 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x46, 0x39, 0x4a, 0x36, 0x4b, 0x34, 0x4e, 0x32, 0x4f, 0x31, 0x50,
- 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x54, 0x2d, 0x56,
- 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
- 0x2a, 0x57, 0x2a, 0x57, 0x41, 0x10, 0x38, 0x17, 0x32, 0x1d, 0x2e, 0x22,
- 0x2b, 0x27, 0x29, 0x2b, 0x27, 0x2f, 0x26, 0x32, 0x25, 0x35, 0x25, 0x38,
- 0x25, 0x3b, 0x24, 0x3c, 0x24, 0x3f, 0x24, 0x40, 0x24, 0x42, 0x23, 0x44,
- 0x23, 0x45, 0x23, 0x46, 0x23, 0x48, 0x23, 0x48, 0x00, 0xac, 0x00, 0x9d,
- 0x00, 0x91, 0x01, 0x89, 0x02, 0x82, 0x03, 0x7e, 0x05, 0x7a, 0x07, 0x77,
- 0x08, 0x75, 0x09, 0x73, 0x0b, 0x71, 0x0c, 0x70, 0x0d, 0x6e, 0x0e, 0x6e,
- 0x0e, 0x6c, 0x0f, 0x6c, 0x10, 0x6b, 0x10, 0x6a, 0x11, 0x6a, 0x12, 0x6a,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x85, 0x00, 0x5f, 0x00, 0x1f, 0x0d, 0x00, 0x28, 0x00, 0x39, 0x00,
- 0x43, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x52, 0x00, 0x54, 0x00, 0x56, 0x00,
- 0x57, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x1f, 0x00, 0x00, 0x1f, 0x00, 0x4d,
- 0x00, 0x68, 0x00, 0x79, 0x00, 0x83, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x92,
- 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x39, 0x48,
- 0x37, 0x4a, 0x35, 0x4c, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x52,
- 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x54, 0x2d, 0x56,
- 0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57,
- 0x42, 0x0f, 0x39, 0x15, 0x33, 0x1a, 0x2f, 0x1f, 0x2d, 0x24, 0x2a, 0x27,
- 0x29, 0x2b, 0x27, 0x2e, 0x26, 0x31, 0x26, 0x34, 0x25, 0x36, 0x25, 0x38,
- 0x25, 0x3b, 0x24, 0x3c, 0x24, 0x3e, 0x24, 0x40, 0x24, 0x41, 0x24, 0x43,
- 0x23, 0x44, 0x23, 0x45, 0x00, 0xae, 0x00, 0xa1, 0x00, 0x96, 0x00, 0x8d,
- 0x01, 0x87, 0x02, 0x82, 0x03, 0x7e, 0x05, 0x7b, 0x06, 0x78, 0x07, 0x76,
- 0x09, 0x74, 0x0a, 0x73, 0x0b, 0x71, 0x0c, 0x70, 0x0c, 0x6f, 0x0d, 0x6e,
- 0x0e, 0x6d, 0x0f, 0x6c, 0x10, 0x6c, 0x10, 0x6b, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x7c,
- 0x00, 0x4d, 0x00, 0x1f, 0x02, 0x00, 0x1a, 0x00, 0x2a, 0x00, 0x36, 0x00,
- 0x3e, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4d, 0x00, 0x4f, 0x00, 0x52, 0x00,
- 0x53, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x52, 0x00, 0x3c, 0x00, 0x0d, 0x00, 0x00, 0x1f, 0x00, 0x42, 0x00, 0x5a,
- 0x00, 0x6a, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x84, 0x00, 0x89, 0x00, 0x8c,
- 0x00, 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x3a, 0x47, 0x38, 0x4a, 0x35, 0x4a,
- 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x52, 0x2f, 0x53,
- 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x55,
- 0x2c, 0x57, 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x43, 0x0e, 0x3b, 0x13,
- 0x35, 0x18, 0x31, 0x1c, 0x2e, 0x21, 0x2c, 0x24, 0x2a, 0x28, 0x28, 0x2b,
- 0x27, 0x2e, 0x27, 0x30, 0x26, 0x33, 0x25, 0x35, 0x25, 0x37, 0x25, 0x39,
- 0x25, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x3f, 0x24, 0x40, 0x24, 0x42,
- 0x00, 0xaf, 0x00, 0xa3, 0x00, 0x99, 0x00, 0x91, 0x00, 0x8b, 0x02, 0x86,
- 0x02, 0x81, 0x03, 0x7e, 0x05, 0x7b, 0x06, 0x79, 0x07, 0x77, 0x08, 0x75,
- 0x09, 0x74, 0x0a, 0x73, 0x0b, 0x71, 0x0c, 0x71, 0x0c, 0x6f, 0x0d, 0x6e,
- 0x0e, 0x6e, 0x0e, 0x6d, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x68, 0x00, 0x42,
- 0x00, 0x1f, 0x00, 0x04, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x34, 0x00,
- 0x3b, 0x00, 0x41, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4b, 0x00, 0x4e, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x4a, 0x00,
- 0x28, 0x00, 0x02, 0x00, 0x00, 0x1f, 0x00, 0x3b, 0x00, 0x4f, 0x00, 0x5f,
- 0x00, 0x6b, 0x00, 0x74, 0x00, 0x7b, 0x00, 0x80, 0x00, 0x85, 0x00, 0x88,
- 0x00, 0x8b, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x44, 0x3b, 0x46, 0x39, 0x49, 0x36, 0x4a, 0x35, 0x4b, 0x34, 0x4e,
- 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x51, 0x2f, 0x53, 0x2e, 0x53,
- 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x55,
- 0x2c, 0x56, 0x2b, 0x57, 0x44, 0x0e, 0x3c, 0x12, 0x36, 0x16, 0x33, 0x1a,
- 0x30, 0x1e, 0x2d, 0x22, 0x2b, 0x25, 0x2a, 0x28, 0x28, 0x2a, 0x27, 0x2d,
- 0x27, 0x30, 0x26, 0x32, 0x26, 0x34, 0x25, 0x35, 0x25, 0x37, 0x25, 0x39,
- 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x3f, 0x00, 0xb0, 0x00, 0xa5,
- 0x00, 0x9d, 0x00, 0x95, 0x00, 0x8e, 0x01, 0x89, 0x02, 0x85, 0x03, 0x81,
- 0x04, 0x7e, 0x05, 0x7c, 0x06, 0x7a, 0x07, 0x78, 0x07, 0x76, 0x09, 0x75,
- 0x09, 0x73, 0x0b, 0x73, 0x0b, 0x71, 0x0c, 0x71, 0x0c, 0x70, 0x0d, 0x6e,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x9a, 0x00, 0x91, 0x00, 0x79, 0x00, 0x5a, 0x00, 0x3b, 0x00, 0x1f,
- 0x00, 0x09, 0x08, 0x00, 0x17, 0x00, 0x22, 0x00, 0x2c, 0x00, 0x33, 0x00,
- 0x39, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x51, 0x00, 0x39, 0x00, 0x1a, 0x00,
- 0x00, 0x04, 0x00, 0x1f, 0x00, 0x36, 0x00, 0x48, 0x00, 0x57, 0x00, 0x62,
- 0x00, 0x6b, 0x00, 0x73, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x85,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x44, 0x3b, 0x46,
- 0x39, 0x48, 0x37, 0x4a, 0x35, 0x4a, 0x35, 0x4c, 0x34, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53,
- 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x55,
- 0x44, 0x0d, 0x3d, 0x11, 0x38, 0x15, 0x34, 0x19, 0x31, 0x1c, 0x2e, 0x20,
- 0x2d, 0x23, 0x2b, 0x25, 0x2a, 0x28, 0x28, 0x2a, 0x28, 0x2d, 0x27, 0x2f,
- 0x26, 0x31, 0x26, 0x33, 0x25, 0x34, 0x25, 0x36, 0x25, 0x38, 0x25, 0x39,
- 0x24, 0x3a, 0x24, 0x3c, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9f, 0x00, 0x98,
- 0x00, 0x91, 0x00, 0x8c, 0x01, 0x88, 0x02, 0x84, 0x03, 0x81, 0x04, 0x7e,
- 0x05, 0x7c, 0x06, 0x7a, 0x06, 0x79, 0x07, 0x77, 0x08, 0x76, 0x09, 0x74,
- 0x0a, 0x73, 0x0b, 0x73, 0x0b, 0x71, 0x0c, 0x71, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x95,
- 0x00, 0x83, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x0c,
- 0x03, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32, 0x00,
- 0x37, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5c, 0x00, 0x55, 0x00, 0x43, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x09,
- 0x00, 0x1f, 0x00, 0x33, 0x00, 0x43, 0x00, 0x50, 0x00, 0x5b, 0x00, 0x64,
- 0x00, 0x6b, 0x00, 0x72, 0x00, 0x77, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3d, 0x43, 0x3c, 0x46, 0x39, 0x46, 0x39, 0x4a,
- 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x50, 0x30, 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
- 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x44, 0x0d, 0x3e, 0x10,
- 0x39, 0x14, 0x35, 0x17, 0x32, 0x1b, 0x30, 0x1e, 0x2e, 0x21, 0x2c, 0x23,
- 0x2b, 0x26, 0x2a, 0x28, 0x28, 0x2a, 0x28, 0x2d, 0x27, 0x2e, 0x26, 0x30,
- 0x26, 0x32, 0x25, 0x34, 0x25, 0x35, 0x25, 0x36, 0x25, 0x38, 0x25, 0x39,
- 0x00, 0xb1, 0x00, 0xa9, 0x00, 0xa1, 0x00, 0x9a, 0x00, 0x94, 0x00, 0x8f,
- 0x01, 0x8b, 0x02, 0x87, 0x02, 0x84, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d,
- 0x06, 0x7b, 0x06, 0x79, 0x07, 0x78, 0x07, 0x76, 0x09, 0x76, 0x09, 0x74,
- 0x0a, 0x73, 0x0b, 0x72, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x76,
- 0x00, 0x5f, 0x00, 0x48, 0x00, 0x33, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
- 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x25, 0x00, 0x2c, 0x00, 0x31, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00,
- 0x4a, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x08, 0x00, 0x00, 0x0c, 0x00, 0x1f,
- 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x55, 0x00, 0x5e, 0x00, 0x65,
- 0x00, 0x6c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x42, 0x3c, 0x46, 0x39, 0x46, 0x39, 0x48, 0x37, 0x4a, 0x35, 0x4a,
- 0x35, 0x4b, 0x35, 0x4e, 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x52, 0x2f, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
- 0x2e, 0x53, 0x2e, 0x53, 0x44, 0x0c, 0x3f, 0x10, 0x3a, 0x13, 0x36, 0x16,
- 0x33, 0x19, 0x30, 0x1c, 0x2e, 0x1f, 0x2d, 0x21, 0x2b, 0x24, 0x2a, 0x26,
- 0x2a, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2e, 0x26, 0x30, 0x26, 0x31,
- 0x26, 0x33, 0x25, 0x34, 0x25, 0x36, 0x25, 0x37, 0x00, 0xb2, 0x00, 0xaa,
- 0x00, 0xa2, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x91, 0x00, 0x8d, 0x01, 0x89,
- 0x02, 0x86, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d, 0x06, 0x7b,
- 0x06, 0x79, 0x07, 0x79, 0x07, 0x77, 0x08, 0x76, 0x09, 0x75, 0x09, 0x74,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x6b, 0x00, 0x57,
- 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x11, 0x00, 0x04, 0x07, 0x00,
- 0x10, 0x00, 0x19, 0x00, 0x20, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4e, 0x00, 0x3e, 0x00,
- 0x2b, 0x00, 0x17, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x2e,
- 0x00, 0x3b, 0x00, 0x46, 0x00, 0x50, 0x00, 0x59, 0x00, 0x60, 0x00, 0x66,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x46,
- 0x39, 0x46, 0x39, 0x47, 0x38, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4b,
- 0x34, 0x4e, 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x31, 0x51, 0x2f, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53,
- 0x45, 0x0c, 0x3f, 0x0f, 0x3a, 0x12, 0x37, 0x15, 0x34, 0x18, 0x32, 0x1b,
- 0x30, 0x1d, 0x2e, 0x20, 0x2d, 0x22, 0x2b, 0x24, 0x2a, 0x26, 0x2a, 0x28,
- 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2e, 0x27, 0x2f, 0x26, 0x31, 0x26, 0x32,
- 0x25, 0x33, 0x25, 0x35, 0x00, 0xb2, 0x00, 0xab, 0x00, 0xa4, 0x00, 0x9e,
- 0x00, 0x98, 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8b, 0x01, 0x88, 0x02, 0x85,
- 0x02, 0x83, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d, 0x05, 0x7c, 0x06, 0x7a,
- 0x07, 0x79, 0x07, 0x78, 0x07, 0x76, 0x09, 0x76, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a,
- 0x00, 0x92, 0x00, 0x84, 0x00, 0x74, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f,
- 0x00, 0x2e, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x06, 0x03, 0x00, 0x0c, 0x00,
- 0x14, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5e, 0x00, 0x5b, 0x00, 0x52, 0x00, 0x45, 0x00, 0x34, 0x00, 0x22, 0x00,
- 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x38,
- 0x00, 0x43, 0x00, 0x4c, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x45, 0x3a, 0x46, 0x39, 0x46,
- 0x39, 0x49, 0x36, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4c, 0x33, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x51,
- 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x45, 0x0c, 0x40, 0x0f,
- 0x3b, 0x11, 0x38, 0x14, 0x35, 0x17, 0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1e,
- 0x2d, 0x21, 0x2c, 0x22, 0x2b, 0x25, 0x2a, 0x26, 0x29, 0x28, 0x28, 0x2a,
- 0x28, 0x2c, 0x27, 0x2d, 0x27, 0x2f, 0x26, 0x30, 0x26, 0x32, 0x25, 0x33,
- 0x00, 0xb2, 0x00, 0xac, 0x00, 0xa5, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x96,
- 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8a, 0x02, 0x88, 0x02, 0x85, 0x02, 0x83,
- 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d, 0x05, 0x7c, 0x06, 0x7a, 0x06, 0x79,
- 0x07, 0x78, 0x07, 0x77, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x94, 0x00, 0x89,
- 0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2d,
- 0x00, 0x1f, 0x00, 0x13, 0x00, 0x08, 0x00, 0x00, 0x09, 0x00, 0x11, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00,
- 0x54, 0x00, 0x49, 0x00, 0x3b, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x0b, 0x00,
- 0x00, 0x04, 0x00, 0x12, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x00, 0x40,
- 0x00, 0x49, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x42, 0x3d, 0x44, 0x3a, 0x46, 0x39, 0x46, 0x39, 0x48, 0x37, 0x4a,
- 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x53,
- 0x2e, 0x53, 0x2e, 0x53, 0x45, 0x0c, 0x40, 0x0e, 0x3c, 0x11, 0x38, 0x13,
- 0x36, 0x16, 0x33, 0x18, 0x31, 0x1b, 0x30, 0x1d, 0x2e, 0x1f, 0x2d, 0x21,
- 0x2b, 0x23, 0x2b, 0x25, 0x2a, 0x27, 0x29, 0x28, 0x28, 0x2a, 0x28, 0x2c,
- 0x27, 0x2d, 0x27, 0x2f, 0x26, 0x2f, 0x26, 0x31, 0x00, 0xb3, 0x00, 0xac,
- 0x00, 0xa7, 0x00, 0xa1, 0x00, 0x9b, 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f,
- 0x01, 0x8c, 0x01, 0x89, 0x02, 0x87, 0x02, 0x85, 0x02, 0x82, 0x03, 0x81,
- 0x04, 0x7f, 0x05, 0x7d, 0x05, 0x7c, 0x06, 0x7b, 0x06, 0x79, 0x07, 0x79,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x73,
- 0x00, 0x64, 0x00, 0x55, 0x00, 0x46, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f,
- 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4d, 0x00,
- 0x41, 0x00, 0x33, 0x00, 0x24, 0x00, 0x15, 0x00, 0x07, 0x00, 0x00, 0x06,
- 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x34, 0x00, 0x3d, 0x00, 0x46,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x44,
- 0x3b, 0x46, 0x39, 0x46, 0x39, 0x47, 0x38, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
- 0x35, 0x4a, 0x35, 0x4b, 0x34, 0x4e, 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x52, 0x2f, 0x53,
- 0x45, 0x0c, 0x40, 0x0e, 0x3c, 0x11, 0x39, 0x13, 0x37, 0x15, 0x34, 0x18,
- 0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1e, 0x2d, 0x20, 0x2d, 0x22, 0x2b, 0x23,
- 0x2b, 0x25, 0x2a, 0x27, 0x29, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2d,
- 0x27, 0x2f, 0x26, 0x2f, 0x00, 0xb3, 0x00, 0xad, 0x00, 0xa7, 0x00, 0xa3,
- 0x00, 0x9d, 0x00, 0x99, 0x00, 0x95, 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8b,
- 0x02, 0x88, 0x02, 0x86, 0x02, 0x84, 0x03, 0x82, 0x03, 0x81, 0x04, 0x7f,
- 0x05, 0x7e, 0x05, 0x7c, 0x06, 0x7b, 0x06, 0x7a, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c,
- 0x00, 0x97, 0x00, 0x8f, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6b, 0x00, 0x5e,
- 0x00, 0x50, 0x00, 0x43, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x15,
- 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5e, 0x00, 0x5d, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x45, 0x00, 0x39, 0x00,
- 0x2c, 0x00, 0x1e, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x14,
- 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x33, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x43, 0x3c, 0x46, 0x39, 0x46,
- 0x39, 0x46, 0x39, 0x49, 0x36, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
- 0x35, 0x4c, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x52, 0x45, 0x0b, 0x41, 0x0e,
- 0x3d, 0x10, 0x3a, 0x12, 0x37, 0x14, 0x34, 0x17, 0x32, 0x19, 0x31, 0x1b,
- 0x30, 0x1d, 0x2e, 0x1f, 0x2d, 0x20, 0x2c, 0x22, 0x2b, 0x24, 0x2a, 0x25,
- 0x2a, 0x27, 0x29, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2c, 0x27, 0x2e,
- 0x00, 0xb3, 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x9a,
- 0x00, 0x96, 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8d, 0x01, 0x8a, 0x02, 0x88,
- 0x02, 0x86, 0x02, 0x84, 0x03, 0x82, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7e,
- 0x05, 0x7c, 0x06, 0x7c, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x91,
- 0x00, 0x88, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c,
- 0x00, 0x40, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00,
- 0x59, 0x00, 0x52, 0x00, 0x49, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x25, 0x00,
- 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x1f,
- 0x00, 0x29, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3d, 0x42, 0x3d, 0x43, 0x3c, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x47,
- 0x38, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4d,
- 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x45, 0x0b, 0x41, 0x0e, 0x3e, 0x10, 0x3a, 0x11,
- 0x38, 0x14, 0x35, 0x16, 0x33, 0x18, 0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1d,
- 0x2e, 0x20, 0x2d, 0x21, 0x2b, 0x22, 0x2b, 0x24, 0x2a, 0x25, 0x2a, 0x27,
- 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2c, 0x00, 0xb3, 0x00, 0xae,
- 0x00, 0xa9, 0x00, 0xa4, 0x00, 0xa0, 0x00, 0x9b, 0x00, 0x98, 0x00, 0x94,
- 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8c, 0x01, 0x89, 0x02, 0x87, 0x02, 0x86,
- 0x02, 0x84, 0x03, 0x82, 0x03, 0x80, 0x04, 0x7f, 0x05, 0x7e, 0x05, 0x7c,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82,
- 0x00, 0x77, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3d,
- 0x00, 0x33, 0x00, 0x29, 0x00, 0x1f, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00,
- 0x4b, 0x00, 0x42, 0x00, 0x37, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00,
- 0x09, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x28,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x42,
- 0x3d, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x4a, 0x36, 0x4a,
- 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4b, 0x34, 0x4e, 0x32, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x46, 0x0b, 0x42, 0x0d, 0x3e, 0x10, 0x3b, 0x11, 0x38, 0x13, 0x36, 0x16,
- 0x34, 0x17, 0x32, 0x19, 0x30, 0x1b, 0x30, 0x1d, 0x2e, 0x1e, 0x2d, 0x20,
- 0x2d, 0x22, 0x2b, 0x23, 0x2b, 0x25, 0x2a, 0x25, 0x2a, 0x28, 0x28, 0x28,
- 0x28, 0x2a, 0x28, 0x2c, 0x00, 0xb3, 0x00, 0xae, 0x00, 0xaa, 0x00, 0xa5,
- 0x00, 0xa1, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x96, 0x00, 0x93, 0x00, 0x90,
- 0x00, 0x8d, 0x01, 0x8b, 0x02, 0x89, 0x02, 0x87, 0x02, 0x85, 0x02, 0x83,
- 0x03, 0x82, 0x03, 0x80, 0x04, 0x7f, 0x05, 0x7e, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d,
- 0x00, 0x9a, 0x00, 0x95, 0x00, 0x8d, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71,
- 0x00, 0x66, 0x00, 0x5b, 0x00, 0x50, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x31,
- 0x00, 0x28, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45, 0x00,
- 0x3c, 0x00, 0x31, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x06, 0x00,
- 0x00, 0x03, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x45, 0x3a, 0x46,
- 0x39, 0x46, 0x39, 0x46, 0x39, 0x48, 0x37, 0x4a, 0x35, 0x4a, 0x35, 0x4a,
- 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4c, 0x34, 0x4f, 0x31, 0x4f, 0x31, 0x4f,
- 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x46, 0x0b, 0x42, 0x0d,
- 0x3e, 0x0f, 0x3c, 0x11, 0x39, 0x13, 0x37, 0x15, 0x34, 0x16, 0x33, 0x18,
- 0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1d, 0x2e, 0x20, 0x2d, 0x20, 0x2c, 0x22,
- 0x2b, 0x23, 0x2b, 0x25, 0x2a, 0x26, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x2a,
- 0x00, 0xb4, 0x00, 0xaf, 0x00, 0xaa, 0x00, 0xa6, 0x00, 0xa2, 0x00, 0x9e,
- 0x00, 0x9a, 0x00, 0x97, 0x00, 0x94, 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8c,
- 0x01, 0x8a, 0x02, 0x88, 0x02, 0x86, 0x02, 0x85, 0x02, 0x83, 0x03, 0x82,
- 0x03, 0x80, 0x04, 0x7f, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60,
- 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x0f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xb2, 0x00, 0x6f, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0xa2, 0x00,
- 0x4f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x7f, 0x00, 0x3c, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c,
- 0x00, 0x16, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xd6, 0x00, 0xc6, 0x00, 0x9c, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12,
- 0x00, 0x0c, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x00, 0xcd, 0x00,
- 0xae, 0x00, 0x82, 0x00, 0x54, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a,
- 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97, 0x00,
- 0x6f, 0x00, 0x47, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e,
- 0x00, 0x1b, 0x00, 0x17, 0x00, 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xdb, 0x00, 0xd4, 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60, 0x00,
- 0x3d, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19,
- 0x00, 0x15, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00,
- 0xc7, 0x00, 0xb0, 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36, 0x00,
- 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12,
- 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8, 0x00,
- 0xa0, 0x00, 0x84, 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f,
- 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d,
- 0x00, 0x09, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xdd, 0x00, 0xd9, 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91, 0x00,
- 0x78, 0x00, 0x5d, 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b,
- 0x00, 0x19, 0x00, 0x16, 0x00, 0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08,
- 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00,
- 0xd1, 0x00, 0xc3, 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d, 0x00,
- 0x55, 0x00, 0x3e, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17,
- 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05,
- 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7, 0x00,
- 0xb7, 0x00, 0xa4, 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00,
- 0x39, 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f,
- 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13,
- 0x00, 0x10, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xdd, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab, 0x00,
- 0x99, 0x00, 0x85, 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34, 0x00,
- 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d,
- 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e,
- 0x00, 0x0c, 0x00, 0x09, 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00,
- 0xd6, 0x00, 0xcd, 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e, 0x00,
- 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00,
- 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x1c,
- 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
- 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
- 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x24,
- 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
- 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x4c, 0x04, 0x11, 0x09, 0x01, 0x11, 0x00, 0x17,
- 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e,
- 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
- 0x61, 0x01, 0x23, 0x03, 0x03, 0x09, 0x00, 0x13, 0x00, 0x18, 0x00, 0x1a,
- 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e,
- 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x17, 0x00, 0x1a, 0x00, 0x1c,
- 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f,
- 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x21,
- 0x00, 0x27, 0x00, 0x2b, 0x00, 0x28, 0x00, 0x21, 0x00, 0x1d, 0x00, 0x1e,
- 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
- 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x87, 0x00, 0x39, 0x01, 0x0f, 0x07, 0x02, 0x0c, 0x00, 0x12, 0x00, 0x17,
- 0x00, 0x19, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d,
- 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x9f, 0x00, 0x5f, 0x00,
- 0x1f, 0x00, 0x04, 0x01, 0x00, 0x0a, 0x00, 0x11, 0x00, 0x15, 0x00, 0x18,
- 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d,
- 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x0b, 0x00, 0x12, 0x00, 0x16, 0x00, 0x18, 0x00, 0x1a,
- 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e,
- 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x34, 0x00, 0x27, 0x00, 0x0f, 0x00, 0x1a,
- 0x00, 0x1c, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c,
- 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x87, 0x00,
- 0x32, 0x00, 0x19, 0x05, 0x0b, 0x09, 0x03, 0x0b, 0x00, 0x0e, 0x00, 0x12,
- 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1b,
- 0x00, 0x1c, 0x00, 0x1c, 0xc5, 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x32, 0x00,
- 0x16, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x12,
- 0x00, 0x14, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1a,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x08, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19,
- 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d,
- 0x00, 0x32, 0x00, 0x2b, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x0e,
- 0x00, 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b,
- 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xcd, 0x00, 0xaf, 0x00, 0x6e, 0x00, 0x31, 0x00,
- 0x1e, 0x04, 0x12, 0x07, 0x0a, 0x09, 0x04, 0x0a, 0x00, 0x0b, 0x00, 0x0f,
- 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19,
- 0xd2, 0x00, 0xbc, 0x00, 0x8d, 0x00, 0x5f, 0x00, 0x3d, 0x00, 0x25, 0x00,
- 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0d,
- 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
- 0x00, 0x0c, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18,
- 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x2c, 0x00, 0x28,
- 0x00, 0x1c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x0f,
- 0x00, 0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a,
- 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xd4, 0x00, 0xc1, 0x00, 0x93, 0x00, 0x5f, 0x00, 0x30, 0x00, 0x22, 0x03,
- 0x17, 0x06, 0x0f, 0x07, 0x0a, 0x09, 0x05, 0x0a, 0x02, 0x0b, 0x00, 0x0c,
- 0x00, 0x0f, 0x00, 0x11, 0x00, 0x13, 0x00, 0x15, 0xd7, 0x00, 0xc9, 0x00,
- 0xa8, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x44, 0x00, 0x2f, 0x00, 0x1f, 0x00,
- 0x14, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x09,
- 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a,
- 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17,
- 0x00, 0x18, 0x00, 0x19, 0x00, 0x24, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0e,
- 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10,
- 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0xcb, 0x00,
- 0xaa, 0x00, 0x7f, 0x00, 0x55, 0x00, 0x30, 0x00, 0x24, 0x02, 0x1b, 0x05,
- 0x14, 0x06, 0x0e, 0x08, 0x09, 0x09, 0x06, 0x0a, 0x03, 0x0b, 0x00, 0x0b,
- 0x00, 0x0d, 0x00, 0x0f, 0xda, 0x00, 0xd0, 0x00, 0xb8, 0x00, 0x99, 0x00,
- 0x7a, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x36, 0x00, 0x28, 0x00, 0x1c, 0x00,
- 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x05,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c,
- 0x00, 0x0e, 0x00, 0x11, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16,
- 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x05,
- 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x11,
- 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xb8, 0x00, 0x96, 0x00,
- 0x71, 0x00, 0x4e, 0x00, 0x30, 0x00, 0x26, 0x02, 0x1e, 0x04, 0x17, 0x06,
- 0x12, 0x07, 0x0d, 0x08, 0x09, 0x09, 0x06, 0x0a, 0x04, 0x0a, 0x01, 0x0b,
- 0xdb, 0x00, 0xd5, 0x00, 0xc3, 0x00, 0xaa, 0x00, 0x8f, 0x00, 0x76, 0x00,
- 0x5f, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x1b, 0x00,
- 0x13, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d,
- 0x00, 0x0f, 0x00, 0x11, 0x00, 0x13, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x1e,
- 0x00, 0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00,
- 0x00, 0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x11,
- 0x00, 0x13, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xdb, 0x00, 0xd4, 0x00, 0xc1, 0x00, 0xa6, 0x00, 0x87, 0x00, 0x67, 0x00,
- 0x4a, 0x00, 0x30, 0x00, 0x27, 0x02, 0x20, 0x03, 0x1a, 0x05, 0x14, 0x06,
- 0x10, 0x07, 0x0c, 0x08, 0x09, 0x09, 0x07, 0x0a, 0xdc, 0x00, 0xd7, 0x00,
- 0xc9, 0x00, 0xb6, 0x00, 0x9f, 0x00, 0x88, 0x00, 0x72, 0x00, 0x5f, 0x00,
- 0x4e, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00,
- 0x13, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e,
- 0x00, 0x10, 0x00, 0x11, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17,
- 0x00, 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03,
- 0x00, 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x11,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00,
- 0xc8, 0x00, 0xb2, 0x00, 0x97, 0x00, 0x7b, 0x00, 0x60, 0x00, 0x46, 0x00,
- 0x30, 0x00, 0x28, 0x01, 0x21, 0x03, 0x1c, 0x04, 0x17, 0x06, 0x13, 0x07,
- 0x0f, 0x08, 0x0c, 0x08, 0xdd, 0x00, 0xd9, 0x00, 0xce, 0x00, 0xbe, 0x00,
- 0xab, 0x00, 0x96, 0x00, 0x82, 0x00, 0x70, 0x00, 0x5f, 0x00, 0x50, 0x00,
- 0x43, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x26, 0x00, 0x1f, 0x00, 0x18, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x03, 0x00, 0x06, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e,
- 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x10,
- 0x00, 0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06,
- 0x00, 0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xba, 0x00,
- 0xa4, 0x00, 0x8b, 0x00, 0x72, 0x00, 0x5a, 0x00, 0x44, 0x00, 0x2f, 0x00,
- 0x29, 0x01, 0x23, 0x03, 0x1e, 0x04, 0x19, 0x05, 0x15, 0x06, 0x11, 0x07,
- 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc4, 0x00, 0xb4, 0x00, 0xa2, 0x00,
- 0x90, 0x00, 0x7e, 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x52, 0x00, 0x46, 0x00,
- 0x3c, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
- 0x00, 0x05, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x1e,
- 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x0a,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x08,
- 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xdd, 0x00, 0xd9, 0x00, 0xd0, 0x00, 0xc0, 0x00, 0xad, 0x00, 0x98, 0x00,
- 0x81, 0x00, 0x6b, 0x00, 0x56, 0x00, 0x42, 0x00, 0x2f, 0x00, 0x29, 0x01,
- 0x24, 0x02, 0x1f, 0x04, 0x1b, 0x05, 0x17, 0x06, 0xdd, 0x00, 0xdb, 0x00,
- 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xab, 0x00, 0x9b, 0x00, 0x8a, 0x00,
- 0x7b, 0x00, 0x6c, 0x00, 0x5f, 0x00, 0x53, 0x00, 0x48, 0x00, 0x3f, 0x00,
- 0x36, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05,
- 0x00, 0x07, 0x00, 0x09, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b,
- 0x00, 0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06,
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00,
- 0xd2, 0x00, 0xc5, 0x00, 0xb5, 0x00, 0xa2, 0x00, 0x8e, 0x00, 0x79, 0x00,
- 0x65, 0x00, 0x52, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x2a, 0x01, 0x25, 0x02,
- 0x20, 0x03, 0x1c, 0x04, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc, 0x00,
- 0xc0, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x95, 0x00, 0x86, 0x00, 0x78, 0x00,
- 0x6b, 0x00, 0x5f, 0x00, 0x54, 0x00, 0x4a, 0x00, 0x41, 0x00, 0x39, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06,
- 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16,
- 0x00, 0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9, 0x00,
- 0xbb, 0x00, 0xaa, 0x00, 0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x60, 0x00,
- 0x4f, 0x00, 0x3e, 0x00, 0x2f, 0x00, 0x2a, 0x01, 0x26, 0x02, 0x21, 0x03,
- 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xcf, 0x00, 0xc4, 0x00, 0xb8, 0x00,
- 0xab, 0x00, 0x9e, 0x00, 0x90, 0x00, 0x83, 0x00, 0x76, 0x00, 0x6a, 0x00,
- 0x5f, 0x00, 0x55, 0x00, 0x4c, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x1f,
- 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x14, 0x00, 0x11,
- 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00,
- 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb1, 0x00,
- 0xa0, 0x00, 0x8f, 0x00, 0x7e, 0x00, 0x6d, 0x00, 0x5c, 0x00, 0x4c, 0x00,
- 0x3d, 0x00, 0x2f, 0x00, 0x2b, 0x01, 0x26, 0x02, 0xde, 0x00, 0xdc, 0x00,
- 0xd8, 0x00, 0xd1, 0x00, 0xc8, 0x00, 0xbd, 0x00, 0xb1, 0x00, 0xa5, 0x00,
- 0x98, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5f, 0x00,
- 0x56, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c,
- 0x00, 0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d,
- 0x00, 0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00,
- 0xd7, 0x00, 0xce, 0x00, 0xc3, 0x00, 0xb6, 0x00, 0xa8, 0x00, 0x98, 0x00,
- 0x88, 0x00, 0x78, 0x00, 0x68, 0x00, 0x59, 0x00, 0x4a, 0x00, 0x3c, 0x00,
- 0x2f, 0x00, 0x2b, 0x01, 0xde, 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xd3, 0x00,
- 0xcb, 0x00, 0xc1, 0x00, 0xb7, 0x00, 0xab, 0x00, 0xa0, 0x00, 0x94, 0x00,
- 0x88, 0x00, 0x7d, 0x00, 0x73, 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19,
- 0x00, 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x09,
- 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd0, 0x00,
- 0xc7, 0x00, 0xbb, 0x00, 0xae, 0x00, 0xa0, 0x00, 0x91, 0x00, 0x82, 0x00,
- 0x73, 0x00, 0x64, 0x00, 0x56, 0x00, 0x48, 0x00, 0x3b, 0x00, 0x2f, 0x00,
- 0xde, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd4, 0x00, 0xcd, 0x00, 0xc5, 0x00,
- 0xbb, 0x00, 0xb1, 0x00, 0xa6, 0x00, 0x9b, 0x00, 0x90, 0x00, 0x85, 0x00,
- 0x7b, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x6f, 0x00,
- 0xb2, 0x00, 0xc8, 0x00, 0xd2, 0x00, 0xd6, 0x00, 0xd9, 0x00, 0xda, 0x00,
- 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xde, 0x00, 0x4c, 0x04, 0x87, 0x00, 0xbc, 0x00, 0xcd, 0x00,
- 0xd4, 0x00, 0xd8, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x76, 0x00,
- 0x9b, 0x00, 0xac, 0x00, 0xbc, 0x00, 0xcd, 0x00, 0xd9, 0x00, 0xda, 0x00,
- 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xde, 0x00, 0x61, 0x01, 0x9f, 0x00, 0xc5, 0x00, 0xd2, 0x00,
- 0xd7, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00,
- 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x6f, 0x00, 0xa2, 0x00,
- 0xb9, 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7, 0x00,
- 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc, 0x00,
- 0x11, 0x09, 0x39, 0x01, 0x87, 0x00, 0xaf, 0x00, 0xc1, 0x00, 0xcb, 0x00,
- 0xd1, 0x00, 0xd4, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00,
- 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x5b, 0x00, 0x75, 0x00, 0x96, 0x00,
- 0xab, 0x00, 0xc0, 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7, 0x00,
- 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc, 0x00,
- 0x23, 0x03, 0x5f, 0x00, 0x9f, 0x00, 0xbc, 0x00, 0xc9, 0x00, 0xd0, 0x00,
- 0xd5, 0x00, 0xd7, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00,
- 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x9c, 0x00,
- 0xae, 0x00, 0xb9, 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf, 0x00,
- 0xd1, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x01, 0x11, 0x0f, 0x07,
- 0x32, 0x00, 0x6e, 0x00, 0x93, 0x00, 0xaa, 0x00, 0xb8, 0x00, 0xc1, 0x00,
- 0xc8, 0x00, 0xcc, 0x00, 0xd0, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd6, 0x00,
- 0xd7, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9b, 0x00, 0x75, 0x00, 0x2b, 0x00, 0x5b, 0x00, 0x7f, 0x00, 0x9b, 0x00,
- 0xae, 0x00, 0xb9, 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf, 0x00,
- 0xd1, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x03, 0x09, 0x1f, 0x00,
- 0x5f, 0x00, 0x8d, 0x00, 0xa8, 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xc9, 0x00,
- 0xce, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00,
- 0xd9, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97, 0x00,
- 0xa5, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7, 0x00,
- 0xca, 0x00, 0xcd, 0x00, 0x00, 0x17, 0x02, 0x0c, 0x19, 0x05, 0x31, 0x00,
- 0x5f, 0x00, 0x7f, 0x00, 0x96, 0x00, 0xa6, 0x00, 0xb2, 0x00, 0xba, 0x00,
- 0xc0, 0x00, 0xc5, 0x00, 0xc9, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xd0, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x96, 0x00,
- 0x5b, 0x00, 0x13, 0x00, 0x41, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97, 0x00,
- 0xa5, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7, 0x00,
- 0xca, 0x00, 0xcd, 0x00, 0x00, 0x13, 0x04, 0x01, 0x32, 0x00, 0x5f, 0x00,
- 0x81, 0x00, 0x99, 0x00, 0xaa, 0x00, 0xb6, 0x00, 0xbe, 0x00, 0xc4, 0x00,
- 0xc9, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x2f, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93, 0x00,
- 0xa0, 0x00, 0xa9, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0, 0x00,
- 0x00, 0x1b, 0x00, 0x12, 0x0b, 0x09, 0x1e, 0x04, 0x30, 0x00, 0x55, 0x00,
- 0x71, 0x00, 0x87, 0x00, 0x97, 0x00, 0xa4, 0x00, 0xad, 0x00, 0xb5, 0x00,
- 0xbb, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xab, 0x00, 0x7f, 0x00, 0x41, 0x00,
- 0x03, 0x00, 0x2f, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93, 0x00,
- 0xa0, 0x00, 0xa9, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0, 0x00,
- 0x00, 0x18, 0x00, 0x0a, 0x16, 0x00, 0x3d, 0x00, 0x5f, 0x00, 0x7a, 0x00,
- 0x8f, 0x00, 0x9f, 0x00, 0xab, 0x00, 0xb4, 0x00, 0xbb, 0x00, 0xc0, 0x00,
- 0xc4, 0x00, 0xc8, 0x00, 0xcb, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x27, 0x00, 0x47, 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91, 0x00,
- 0x9c, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x1c, 0x00, 0x17,
- 0x03, 0x0b, 0x12, 0x07, 0x22, 0x03, 0x30, 0x00, 0x4e, 0x00, 0x67, 0x00,
- 0x7b, 0x00, 0x8b, 0x00, 0x98, 0x00, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00,
- 0xb6, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xcd, 0x00, 0xc0, 0x00, 0x9b, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x02, 0x00,
- 0x27, 0x00, 0x47, 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91, 0x00,
- 0x9c, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x1a, 0x00, 0x11,
- 0x06, 0x00, 0x25, 0x00, 0x44, 0x00, 0x5f, 0x00, 0x76, 0x00, 0x88, 0x00,
- 0x96, 0x00, 0xa2, 0x00, 0xab, 0x00, 0xb2, 0x00, 0xb8, 0x00, 0xbd, 0x00,
- 0xc1, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00,
- 0x3d, 0x00, 0x55, 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00,
- 0x99, 0x00, 0xa0, 0x00, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x0e, 0x0a, 0x09,
- 0x17, 0x06, 0x24, 0x02, 0x30, 0x00, 0x4a, 0x00, 0x60, 0x00, 0x72, 0x00,
- 0x81, 0x00, 0x8e, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa8, 0x00, 0xae, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x00, 0xcd, 0x00,
- 0xae, 0x00, 0x82, 0x00, 0x54, 0x00, 0x27, 0x00, 0x01, 0x00, 0x21, 0x00,
- 0x3d, 0x00, 0x55, 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00,
- 0x99, 0x00, 0xa0, 0x00, 0x00, 0x1c, 0x00, 0x15, 0x00, 0x03, 0x14, 0x00,
- 0x2f, 0x00, 0x49, 0x00, 0x5f, 0x00, 0x72, 0x00, 0x82, 0x00, 0x90, 0x00,
- 0x9b, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbb, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x36, 0x00,
- 0x4b, 0x00, 0x5d, 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e, 0x00,
- 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x04, 0x0a, 0x0f, 0x07, 0x1b, 0x05,
- 0x26, 0x02, 0x30, 0x00, 0x46, 0x00, 0x5a, 0x00, 0x6b, 0x00, 0x79, 0x00,
- 0x85, 0x00, 0x8f, 0x00, 0x98, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97, 0x00,
- 0x6f, 0x00, 0x47, 0x00, 0x21, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x36, 0x00,
- 0x4b, 0x00, 0x5d, 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e, 0x00,
- 0x00, 0x1d, 0x00, 0x18, 0x00, 0x0a, 0x09, 0x00, 0x1f, 0x00, 0x36, 0x00,
- 0x4c, 0x00, 0x5f, 0x00, 0x70, 0x00, 0x7e, 0x00, 0x8a, 0x00, 0x95, 0x00,
- 0x9e, 0x00, 0xa5, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44, 0x00,
- 0x55, 0x00, 0x64, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x00, 0x1e, 0x00, 0x1c,
- 0x00, 0x15, 0x00, 0x0b, 0x0a, 0x09, 0x14, 0x06, 0x1e, 0x04, 0x27, 0x02,
- 0x30, 0x00, 0x44, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x7e, 0x00,
- 0x88, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xdb, 0x00, 0xd4, 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60, 0x00,
- 0x3d, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44, 0x00,
- 0x55, 0x00, 0x64, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x00, 0x1d, 0x00, 0x1a,
- 0x00, 0x0f, 0x00, 0x00, 0x14, 0x00, 0x28, 0x00, 0x3c, 0x00, 0x4e, 0x00,
- 0x5f, 0x00, 0x6e, 0x00, 0x7b, 0x00, 0x86, 0x00, 0x90, 0x00, 0x98, 0x00,
- 0xa0, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e, 0x00,
- 0x5c, 0x00, 0x68, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x17, 0x00, 0x0f,
- 0x05, 0x0a, 0x0e, 0x08, 0x17, 0x06, 0x20, 0x03, 0x28, 0x01, 0x2f, 0x00,
- 0x42, 0x00, 0x52, 0x00, 0x60, 0x00, 0x6d, 0x00, 0x78, 0x00, 0x82, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00,
- 0xc7, 0x00, 0xb0, 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36, 0x00,
- 0x19, 0x00, 0x00, 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e, 0x00,
- 0x5c, 0x00, 0x68, 0x00, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x05,
- 0x0b, 0x00, 0x1c, 0x00, 0x2f, 0x00, 0x40, 0x00, 0x50, 0x00, 0x5f, 0x00,
- 0x6c, 0x00, 0x78, 0x00, 0x83, 0x00, 0x8c, 0x00, 0x94, 0x00, 0x9b, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x15, 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55, 0x00,
- 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x02, 0x0b, 0x09, 0x09,
- 0x12, 0x07, 0x1a, 0x05, 0x21, 0x03, 0x29, 0x01, 0x2f, 0x00, 0x40, 0x00,
- 0x4f, 0x00, 0x5c, 0x00, 0x68, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8, 0x00,
- 0xa0, 0x00, 0x84, 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17, 0x00,
- 0x00, 0x00, 0x15, 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55, 0x00,
- 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x09, 0x04, 0x00, 0x13, 0x00,
- 0x24, 0x00, 0x34, 0x00, 0x43, 0x00, 0x52, 0x00, 0x5f, 0x00, 0x6b, 0x00,
- 0x76, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x42, 0x00, 0x00, 0x1f, 0x00, 0x1d,
- 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x06, 0x0a, 0x0d, 0x08, 0x14, 0x06,
- 0x1c, 0x04, 0x23, 0x03, 0x29, 0x01, 0x2f, 0x00, 0x3e, 0x00, 0x4c, 0x00,
- 0x59, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xdd, 0x00, 0xd9, 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91, 0x00,
- 0x78, 0x00, 0x5d, 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00, 0x00,
- 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x42, 0x00, 0x00, 0x1e, 0x00, 0x1c,
- 0x00, 0x16, 0x00, 0x0d, 0x00, 0x01, 0x0c, 0x00, 0x1b, 0x00, 0x29, 0x00,
- 0x38, 0x00, 0x46, 0x00, 0x53, 0x00, 0x5f, 0x00, 0x6a, 0x00, 0x74, 0x00,
- 0x7d, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00,
- 0x22, 0x00, 0x30, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x16,
- 0x00, 0x0f, 0x03, 0x0b, 0x09, 0x09, 0x10, 0x07, 0x17, 0x06, 0x1e, 0x04,
- 0x24, 0x02, 0x2a, 0x01, 0x2f, 0x00, 0x3d, 0x00, 0x4a, 0x00, 0x56, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00,
- 0xd1, 0x00, 0xc3, 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d, 0x00,
- 0x55, 0x00, 0x3e, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x11, 0x00,
- 0x22, 0x00, 0x30, 0x00, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x10,
- 0x00, 0x05, 0x06, 0x00, 0x13, 0x00, 0x21, 0x00, 0x2e, 0x00, 0x3c, 0x00,
- 0x48, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x73, 0x00, 0x7b, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
- 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00, 0x11, 0x00, 0x0b,
- 0x06, 0x0a, 0x0c, 0x08, 0x13, 0x07, 0x19, 0x05, 0x1f, 0x04, 0x25, 0x02,
- 0x2a, 0x01, 0x2f, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7, 0x00,
- 0xb7, 0x00, 0xa4, 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00,
- 0x39, 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00,
- 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00, 0x09, 0x01, 0x00,
- 0x0d, 0x00, 0x19, 0x00, 0x26, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4a, 0x00,
- 0x55, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x1f, 0x00, 0x1e,
- 0x00, 0x1c, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x04, 0x0a, 0x09, 0x09,
- 0x0f, 0x08, 0x15, 0x06, 0x1b, 0x05, 0x20, 0x03, 0x26, 0x02, 0x2b, 0x01,
- 0x2f, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xdd, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab, 0x00,
- 0x99, 0x00, 0x85, 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34, 0x00,
- 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x1f, 0x00, 0x1d,
- 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x02, 0x08, 0x00, 0x13, 0x00,
- 0x1f, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x56, 0x00,
- 0x5f, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19,
- 0x00, 0x15, 0x00, 0x0f, 0x01, 0x0b, 0x07, 0x0a, 0x0c, 0x08, 0x11, 0x07,
- 0x17, 0x06, 0x1c, 0x04, 0x21, 0x03, 0x26, 0x02, 0x2b, 0x01, 0x2f, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00,
- 0xd6, 0x00, 0xcd, 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e, 0x00,
- 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00,
- 0x0f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15,
- 0x00, 0x0e, 0x00, 0x05, 0x03, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x23, 0x00,
- 0x2e, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x56, 0x00, 0x5f, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x61, 0x01, 0x9f, 0x00, 0xc5, 0x00, 0xd2, 0x00, 0xd7, 0x00, 0xda, 0x00,
- 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde, 0x00,
- 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x61, 0x01, 0x23, 0x03, 0x03, 0x09, 0x00, 0x13,
- 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e,
- 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x03, 0x5f, 0x00,
- 0x9f, 0x00, 0xbc, 0x00, 0xc9, 0x00, 0xd0, 0x00, 0xd5, 0x00, 0xd7, 0x00,
- 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc, 0x00,
- 0xdd, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9f, 0x00, 0x5f, 0x00, 0x1f, 0x00, 0x04, 0x01, 0x00, 0x0a, 0x00, 0x11,
- 0x00, 0x15, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c,
- 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x09, 0x1f, 0x00, 0x5f, 0x00, 0x8d, 0x00,
- 0xa8, 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xc9, 0x00, 0xce, 0x00, 0xd1, 0x00,
- 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x9f, 0x00,
- 0x5f, 0x00, 0x32, 0x00, 0x16, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0a,
- 0x00, 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19,
- 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x13, 0x04, 0x01, 0x32, 0x00, 0x5f, 0x00, 0x81, 0x00, 0x99, 0x00,
- 0xaa, 0x00, 0xb6, 0x00, 0xbe, 0x00, 0xc4, 0x00, 0xc9, 0x00, 0xcc, 0x00,
- 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xbc, 0x00, 0x8d, 0x00, 0x5f, 0x00,
- 0x3d, 0x00, 0x25, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x05,
- 0x00, 0x09, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x15,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x0a,
- 0x16, 0x00, 0x3d, 0x00, 0x5f, 0x00, 0x7a, 0x00, 0x8f, 0x00, 0x9f, 0x00,
- 0xab, 0x00, 0xb4, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc4, 0x00, 0xc8, 0x00,
- 0xcb, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xd7, 0x00, 0xc9, 0x00, 0xa8, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x44, 0x00,
- 0x2f, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x01,
- 0x00, 0x05, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x11, 0x06, 0x00, 0x25, 0x00,
- 0x44, 0x00, 0x5f, 0x00, 0x76, 0x00, 0x88, 0x00, 0x96, 0x00, 0xa2, 0x00,
- 0xab, 0x00, 0xb2, 0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc1, 0x00, 0xc5, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd0, 0x00,
- 0xb8, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x36, 0x00,
- 0x28, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x01, 0x00,
- 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x1c, 0x00, 0x15, 0x00, 0x03, 0x14, 0x00, 0x2f, 0x00, 0x49, 0x00,
- 0x5f, 0x00, 0x72, 0x00, 0x82, 0x00, 0x90, 0x00, 0x9b, 0x00, 0xa4, 0x00,
- 0xab, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xc3, 0x00, 0xaa, 0x00,
- 0x8f, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2f, 0x00,
- 0x24, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x18,
- 0x00, 0x0a, 0x09, 0x00, 0x1f, 0x00, 0x36, 0x00, 0x4c, 0x00, 0x5f, 0x00,
- 0x70, 0x00, 0x7e, 0x00, 0x8a, 0x00, 0x95, 0x00, 0x9e, 0x00, 0xa5, 0x00,
- 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xdc, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xb6, 0x00, 0x9f, 0x00, 0x88, 0x00,
- 0x72, 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00,
- 0x21, 0x00, 0x19, 0x00, 0x13, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x00,
- 0x14, 0x00, 0x28, 0x00, 0x3c, 0x00, 0x4e, 0x00, 0x5f, 0x00, 0x6e, 0x00,
- 0x7b, 0x00, 0x86, 0x00, 0x90, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa6, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xd9, 0x00,
- 0xce, 0x00, 0xbe, 0x00, 0xab, 0x00, 0x96, 0x00, 0x82, 0x00, 0x70, 0x00,
- 0x5f, 0x00, 0x50, 0x00, 0x43, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x26, 0x00,
- 0x1f, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x05, 0x0b, 0x00, 0x1c, 0x00,
- 0x2f, 0x00, 0x40, 0x00, 0x50, 0x00, 0x5f, 0x00, 0x6c, 0x00, 0x78, 0x00,
- 0x83, 0x00, 0x8c, 0x00, 0x94, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc4, 0x00,
- 0xb4, 0x00, 0xa2, 0x00, 0x90, 0x00, 0x7e, 0x00, 0x6e, 0x00, 0x5f, 0x00,
- 0x52, 0x00, 0x46, 0x00, 0x3c, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x23, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c,
- 0x00, 0x14, 0x00, 0x09, 0x04, 0x00, 0x13, 0x00, 0x24, 0x00, 0x34, 0x00,
- 0x43, 0x00, 0x52, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x76, 0x00, 0x80, 0x00,
- 0x88, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xab, 0x00,
- 0x9b, 0x00, 0x8a, 0x00, 0x7b, 0x00, 0x6c, 0x00, 0x5f, 0x00, 0x53, 0x00,
- 0x48, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x16, 0x00, 0x0d,
- 0x00, 0x01, 0x0c, 0x00, 0x1b, 0x00, 0x29, 0x00, 0x38, 0x00, 0x46, 0x00,
- 0x53, 0x00, 0x5f, 0x00, 0x6a, 0x00, 0x74, 0x00, 0x7d, 0x00, 0x85, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00,
- 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x95, 0x00,
- 0x86, 0x00, 0x78, 0x00, 0x6b, 0x00, 0x5f, 0x00, 0x54, 0x00, 0x4a, 0x00,
- 0x41, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x10, 0x00, 0x05, 0x06, 0x00,
- 0x13, 0x00, 0x21, 0x00, 0x2e, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x54, 0x00,
- 0x5f, 0x00, 0x69, 0x00, 0x73, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xcf, 0x00,
- 0xc4, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x9e, 0x00, 0x90, 0x00, 0x83, 0x00,
- 0x76, 0x00, 0x6a, 0x00, 0x5f, 0x00, 0x55, 0x00, 0x4c, 0x00, 0x43, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d,
- 0x00, 0x19, 0x00, 0x12, 0x00, 0x09, 0x01, 0x00, 0x0d, 0x00, 0x19, 0x00,
- 0x26, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x55, 0x00, 0x5f, 0x00,
- 0x69, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd1, 0x00, 0xc8, 0x00, 0xbd, 0x00,
- 0xb1, 0x00, 0xa5, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x74, 0x00,
- 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x14,
- 0x00, 0x0c, 0x00, 0x02, 0x08, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00,
- 0x36, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5f, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd, 0x00,
- 0xd9, 0x00, 0xd3, 0x00, 0xcb, 0x00, 0xc1, 0x00, 0xb7, 0x00, 0xab, 0x00,
- 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7d, 0x00, 0x73, 0x00, 0x69, 0x00,
- 0x5f, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15, 0x00, 0x0e, 0x00, 0x05,
- 0x03, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x23, 0x00, 0x2e, 0x00, 0x39, 0x00,
- 0x43, 0x00, 0x4d, 0x00, 0x56, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd4, 0x00,
- 0xcd, 0x00, 0xc5, 0x00, 0xbb, 0x00, 0xb1, 0x00, 0xa6, 0x00, 0x9b, 0x00,
- 0x90, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5f, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x02, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xb2, 0x00, 0x6f, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0xa2,
- 0x00, 0x4f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1c, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x7f, 0x00, 0x3c,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1a, 0x00,
- 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xd6, 0x00, 0xc6, 0x00, 0x9c, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x16, 0x00, 0x0e, 0x00,
- 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x00, 0xcd,
- 0x00, 0xae, 0x00, 0x82, 0x00, 0x54, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97,
- 0x00, 0x6f, 0x00, 0x47, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
- 0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60,
- 0x00, 0x3d, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00,
- 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7,
- 0x00, 0xc7, 0x00, 0xb0, 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36,
- 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x10, 0x00,
- 0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8,
- 0x00, 0xa0, 0x00, 0x84, 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
- 0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x0a, 0x00,
- 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91,
- 0x00, 0x78, 0x00, 0x5d, 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00,
- 0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda,
- 0x00, 0xd1, 0x00, 0xc3, 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d,
- 0x00, 0x55, 0x00, 0x3e, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16, 0x00,
- 0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7,
- 0x00, 0xb7, 0x00, 0xa4, 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e,
- 0x00, 0x39, 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00,
- 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x14, 0x00, 0x11, 0x00,
- 0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab,
- 0x00, 0x99, 0x00, 0x85, 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34,
- 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00,
- 0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0x00,
- 0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc,
- 0x00, 0xd6, 0x00, 0xcd, 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e,
- 0x00, 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f,
- 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00,
- 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x09, 0x00,
- 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x6f,
- 0x00, 0xb2, 0x00, 0xc8, 0x00, 0xd2, 0x00, 0xd6, 0x00, 0xd9, 0x00, 0xda,
- 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xde, 0x00, 0xa6, 0x00, 0x76, 0x00, 0x9b, 0x00, 0xac,
- 0x00, 0xbc, 0x00, 0xcd, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc,
- 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x4c, 0x00, 0x87,
- 0x00, 0xbc, 0x00, 0xcd, 0x00, 0xd4, 0x00, 0xd8, 0x00, 0xda, 0x00, 0xdb,
- 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde,
- 0x00, 0xde, 0x00, 0xde, 0x01, 0x61, 0x00, 0x9f, 0x00, 0xc5, 0x00, 0xd2,
- 0x00, 0xd7, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x6f, 0x00, 0xa2,
- 0x00, 0xb9, 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7,
- 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc,
- 0x00, 0x76, 0x00, 0x5b, 0x00, 0x75, 0x00, 0x96, 0x00, 0xab, 0x00, 0xc0,
- 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9,
- 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x09, 0x11, 0x01, 0x39, 0x00, 0x87, 0x00, 0xaf,
- 0x00, 0xc1, 0x00, 0xcb, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd7, 0x00, 0xd8,
- 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc,
- 0x03, 0x23, 0x00, 0x5f, 0x00, 0x9f, 0x00, 0xbc, 0x00, 0xc9, 0x00, 0xd0,
- 0x00, 0xd5, 0x00, 0xd7, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc,
- 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x9c,
- 0x00, 0xae, 0x00, 0xb9, 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf,
- 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x9b, 0x00, 0x75,
- 0x00, 0x2b, 0x00, 0x5b, 0x00, 0x7f, 0x00, 0x9b, 0x00, 0xae, 0x00, 0xb9,
- 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3,
- 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x11, 0x01, 0x07, 0x0f, 0x00, 0x32, 0x00, 0x6e, 0x00, 0x93, 0x00, 0xaa,
- 0x00, 0xb8, 0x00, 0xc1, 0x00, 0xc8, 0x00, 0xcc, 0x00, 0xd0, 0x00, 0xd2,
- 0x00, 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x09, 0x03, 0x00, 0x1f,
- 0x00, 0x5f, 0x00, 0x8d, 0x00, 0xa8, 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xc9,
- 0x00, 0xce, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8,
- 0x00, 0xd9, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97,
- 0x00, 0xa5, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7,
- 0x00, 0xca, 0x00, 0xcd, 0x00, 0xac, 0x00, 0x96, 0x00, 0x5b, 0x00, 0x13,
- 0x00, 0x41, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97, 0x00, 0xa5, 0x00, 0xb0,
- 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7, 0x00, 0xca, 0x00, 0xcd,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x0c, 0x02,
- 0x05, 0x19, 0x00, 0x31, 0x00, 0x5f, 0x00, 0x7f, 0x00, 0x96, 0x00, 0xa6,
- 0x00, 0xb2, 0x00, 0xba, 0x00, 0xc0, 0x00, 0xc5, 0x00, 0xc9, 0x00, 0xcc,
- 0x00, 0xce, 0x00, 0xd0, 0x13, 0x00, 0x01, 0x04, 0x00, 0x32, 0x00, 0x5f,
- 0x00, 0x81, 0x00, 0x99, 0x00, 0xaa, 0x00, 0xb6, 0x00, 0xbe, 0x00, 0xc4,
- 0x00, 0xc9, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x2f, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93,
- 0x00, 0xa0, 0x00, 0xa9, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0,
- 0x00, 0xbc, 0x00, 0xab, 0x00, 0x7f, 0x00, 0x41, 0x00, 0x03, 0x00, 0x2f,
- 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93, 0x00, 0xa0, 0x00, 0xa9,
- 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x09, 0x0b, 0x04, 0x1e,
- 0x00, 0x30, 0x00, 0x55, 0x00, 0x71, 0x00, 0x87, 0x00, 0x97, 0x00, 0xa4,
- 0x00, 0xad, 0x00, 0xb5, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc7,
- 0x18, 0x00, 0x0a, 0x00, 0x00, 0x16, 0x00, 0x3d, 0x00, 0x5f, 0x00, 0x7a,
- 0x00, 0x8f, 0x00, 0x9f, 0x00, 0xab, 0x00, 0xb4, 0x00, 0xbb, 0x00, 0xc0,
- 0x00, 0xc4, 0x00, 0xc8, 0x00, 0xcb, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x27, 0x00, 0x47, 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91,
- 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0xcd, 0x00, 0xc0,
- 0x00, 0x9b, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x02, 0x00, 0x27, 0x00, 0x47,
- 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91, 0x00, 0x9c, 0x00, 0xa4,
- 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1c, 0x00, 0x17, 0x00, 0x0b, 0x03, 0x07, 0x12, 0x03, 0x22, 0x00, 0x30,
- 0x00, 0x4e, 0x00, 0x67, 0x00, 0x7b, 0x00, 0x8b, 0x00, 0x98, 0x00, 0xa2,
- 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb6, 0x00, 0xbb, 0x1a, 0x00, 0x11, 0x00,
- 0x00, 0x06, 0x00, 0x25, 0x00, 0x44, 0x00, 0x5f, 0x00, 0x76, 0x00, 0x88,
- 0x00, 0x96, 0x00, 0xa2, 0x00, 0xab, 0x00, 0xb2, 0x00, 0xb8, 0x00, 0xbd,
- 0x00, 0xc1, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21,
- 0x00, 0x3d, 0x00, 0x55, 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90,
- 0x00, 0x99, 0x00, 0xa0, 0x00, 0xd9, 0x00, 0xcd, 0x00, 0xae, 0x00, 0x82,
- 0x00, 0x54, 0x00, 0x27, 0x00, 0x01, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x55,
- 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00, 0x99, 0x00, 0xa0,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x19, 0x00,
- 0x0e, 0x00, 0x09, 0x0a, 0x06, 0x17, 0x02, 0x24, 0x00, 0x30, 0x00, 0x4a,
- 0x00, 0x60, 0x00, 0x72, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x98, 0x00, 0xa0,
- 0x00, 0xa8, 0x00, 0xae, 0x1c, 0x00, 0x15, 0x00, 0x03, 0x00, 0x00, 0x14,
- 0x00, 0x2f, 0x00, 0x49, 0x00, 0x5f, 0x00, 0x72, 0x00, 0x82, 0x00, 0x90,
- 0x00, 0x9b, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbb,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x36,
- 0x00, 0x4b, 0x00, 0x5d, 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e,
- 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97, 0x00, 0x6f, 0x00, 0x47,
- 0x00, 0x21, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x36, 0x00, 0x4b, 0x00, 0x5d,
- 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x0a, 0x04,
- 0x07, 0x0f, 0x05, 0x1b, 0x02, 0x26, 0x00, 0x30, 0x00, 0x46, 0x00, 0x5a,
- 0x00, 0x6b, 0x00, 0x79, 0x00, 0x85, 0x00, 0x8f, 0x00, 0x98, 0x00, 0xa0,
- 0x1d, 0x00, 0x18, 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x1f, 0x00, 0x36,
- 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x70, 0x00, 0x7e, 0x00, 0x8a, 0x00, 0x95,
- 0x00, 0x9e, 0x00, 0xa5, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44,
- 0x00, 0x55, 0x00, 0x64, 0x00, 0x70, 0x00, 0x7b, 0x00, 0xdb, 0x00, 0xd4,
- 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60, 0x00, 0x3d, 0x00, 0x1d,
- 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44, 0x00, 0x55, 0x00, 0x64,
- 0x00, 0x70, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1e, 0x00, 0x1c, 0x00, 0x15, 0x00, 0x0b, 0x00, 0x09, 0x0a, 0x06, 0x14,
- 0x04, 0x1e, 0x02, 0x27, 0x00, 0x30, 0x00, 0x44, 0x00, 0x56, 0x00, 0x65,
- 0x00, 0x72, 0x00, 0x7e, 0x00, 0x88, 0x00, 0x91, 0x1d, 0x00, 0x1a, 0x00,
- 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x28, 0x00, 0x3c, 0x00, 0x4e,
- 0x00, 0x5f, 0x00, 0x6e, 0x00, 0x7b, 0x00, 0x86, 0x00, 0x90, 0x00, 0x98,
- 0x00, 0xa0, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e,
- 0x00, 0x5c, 0x00, 0x68, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc7, 0x00, 0xb0,
- 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36, 0x00, 0x19, 0x00, 0x00,
- 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e, 0x00, 0x5c, 0x00, 0x68,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00,
- 0x17, 0x00, 0x0f, 0x00, 0x0a, 0x05, 0x08, 0x0e, 0x06, 0x17, 0x03, 0x20,
- 0x01, 0x28, 0x00, 0x2f, 0x00, 0x42, 0x00, 0x52, 0x00, 0x60, 0x00, 0x6d,
- 0x00, 0x78, 0x00, 0x82, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x05, 0x00,
- 0x00, 0x0b, 0x00, 0x1c, 0x00, 0x2f, 0x00, 0x40, 0x00, 0x50, 0x00, 0x5f,
- 0x00, 0x6c, 0x00, 0x78, 0x00, 0x83, 0x00, 0x8c, 0x00, 0x94, 0x00, 0x9b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x15, 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55,
- 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8, 0x00, 0xa0, 0x00, 0x84,
- 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17, 0x00, 0x00, 0x00, 0x15,
- 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00,
- 0x0b, 0x02, 0x09, 0x09, 0x07, 0x12, 0x05, 0x1a, 0x03, 0x21, 0x01, 0x29,
- 0x00, 0x2f, 0x00, 0x40, 0x00, 0x4f, 0x00, 0x5c, 0x00, 0x68, 0x00, 0x73,
- 0x1e, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x04, 0x00, 0x13,
- 0x00, 0x24, 0x00, 0x34, 0x00, 0x43, 0x00, 0x52, 0x00, 0x5f, 0x00, 0x6b,
- 0x00, 0x76, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x42, 0x00, 0xdd, 0x00, 0xd9,
- 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91, 0x00, 0x78, 0x00, 0x5d,
- 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x24,
- 0x00, 0x34, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1f, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x0a, 0x06,
- 0x08, 0x0d, 0x06, 0x14, 0x04, 0x1c, 0x03, 0x23, 0x01, 0x29, 0x00, 0x2f,
- 0x00, 0x3e, 0x00, 0x4c, 0x00, 0x59, 0x00, 0x64, 0x1e, 0x00, 0x1c, 0x00,
- 0x16, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x29,
- 0x00, 0x38, 0x00, 0x46, 0x00, 0x53, 0x00, 0x5f, 0x00, 0x6a, 0x00, 0x74,
- 0x00, 0x7d, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
- 0x00, 0x22, 0x00, 0x30, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc3,
- 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d, 0x00, 0x55, 0x00, 0x3e,
- 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x30,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
- 0x1b, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x0b, 0x03, 0x09, 0x09, 0x07, 0x10,
- 0x06, 0x17, 0x04, 0x1e, 0x02, 0x24, 0x01, 0x2a, 0x00, 0x2f, 0x00, 0x3d,
- 0x00, 0x4a, 0x00, 0x56, 0x1e, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x10, 0x00,
- 0x05, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x21, 0x00, 0x2e, 0x00, 0x3c,
- 0x00, 0x48, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x73, 0x00, 0x7b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f,
- 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7, 0x00, 0xb7, 0x00, 0xa4,
- 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00, 0x39, 0x00, 0x24,
- 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00,
- 0x11, 0x00, 0x0b, 0x00, 0x0a, 0x06, 0x08, 0x0c, 0x07, 0x13, 0x05, 0x19,
- 0x04, 0x1f, 0x02, 0x25, 0x01, 0x2a, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x48,
- 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x01,
- 0x00, 0x0d, 0x00, 0x19, 0x00, 0x26, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4a,
- 0x00, 0x55, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xdd, 0x00, 0xdb,
- 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab, 0x00, 0x99, 0x00, 0x85,
- 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34, 0x00, 0x22, 0x00, 0x10,
- 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00,
- 0x0a, 0x04, 0x09, 0x09, 0x08, 0x0f, 0x06, 0x15, 0x05, 0x1b, 0x03, 0x20,
- 0x02, 0x26, 0x01, 0x2b, 0x00, 0x2f, 0x00, 0x3b, 0x1f, 0x00, 0x1d, 0x00,
- 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x08, 0x00, 0x13,
- 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x56,
- 0x00, 0x5f, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcd,
- 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e, 0x00, 0x7b, 0x00, 0x68,
- 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
- 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0b, 0x01, 0x0a, 0x07,
- 0x08, 0x0c, 0x07, 0x11, 0x06, 0x17, 0x04, 0x1c, 0x03, 0x21, 0x02, 0x26,
- 0x01, 0x2b, 0x00, 0x2f, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15, 0x00,
- 0x0e, 0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x23,
- 0x00, 0x2e, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x56, 0x00, 0x5f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x07, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x1e, 0x00,
- 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
- 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x04, 0x4c, 0x09, 0x11,
- 0x11, 0x01, 0x17, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00,
- 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
- 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3e, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x24, 0x00,
- 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
- 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x01, 0x61, 0x03, 0x23,
- 0x09, 0x03, 0x13, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00,
- 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00,
- 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
- 0x0f, 0x00, 0x17, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00,
- 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
- 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x87, 0x01, 0x39, 0x07, 0x0f, 0x0c, 0x02,
- 0x12, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00,
- 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x21, 0x00,
- 0x27, 0x00, 0x2b, 0x00, 0x28, 0x00, 0x21, 0x00, 0x1d, 0x00, 0x1e, 0x00,
- 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
- 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x1f, 0x01, 0x04,
- 0x0a, 0x00, 0x11, 0x00, 0x15, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00,
- 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00,
- 0x12, 0x00, 0x16, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00,
- 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00,
- 0x00, 0xbc, 0x00, 0x87, 0x00, 0x32, 0x05, 0x19, 0x09, 0x0b, 0x0b, 0x03,
- 0x0e, 0x00, 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00,
- 0x1b, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x27, 0x00, 0x0f, 0x00, 0x1a, 0x00,
- 0x1c, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00,
- 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00,
- 0x00, 0xc5, 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x32, 0x00, 0x16, 0x00, 0x06,
- 0x03, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00,
- 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0e, 0x00,
- 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00,
- 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x00, 0xcd, 0x00, 0xaf,
- 0x00, 0x6e, 0x00, 0x31, 0x04, 0x1e, 0x07, 0x12, 0x09, 0x0a, 0x0a, 0x04,
- 0x0b, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00,
- 0x18, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x32, 0x00, 0x2b, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x0e, 0x00,
- 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00,
- 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x00, 0xd2, 0x00, 0xbc,
- 0x00, 0x8d, 0x00, 0x5f, 0x00, 0x3d, 0x00, 0x25, 0x00, 0x14, 0x00, 0x09,
- 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00,
- 0x14, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x0f, 0x00,
- 0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00,
- 0x1a, 0x00, 0x1b, 0x00, 0x00, 0xd4, 0x00, 0xc1, 0x00, 0x93, 0x00, 0x5f,
- 0x00, 0x30, 0x03, 0x22, 0x06, 0x17, 0x07, 0x0f, 0x09, 0x0a, 0x0a, 0x05,
- 0x0b, 0x02, 0x0c, 0x00, 0x0f, 0x00, 0x11, 0x00, 0x13, 0x00, 0x15, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x28, 0x00,
- 0x1c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x0f, 0x00,
- 0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00,
- 0x1a, 0x00, 0x1b, 0x00, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xa8, 0x00, 0x81,
- 0x00, 0x5f, 0x00, 0x44, 0x00, 0x2f, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0b,
- 0x00, 0x04, 0x01, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10, 0x00,
- 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00,
- 0x00, 0xd8, 0x00, 0xcb, 0x00, 0xaa, 0x00, 0x7f, 0x00, 0x55, 0x00, 0x30,
- 0x02, 0x24, 0x05, 0x1b, 0x06, 0x14, 0x08, 0x0e, 0x09, 0x09, 0x0a, 0x06,
- 0x0b, 0x03, 0x0b, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0e, 0x00,
- 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10, 0x00,
- 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00,
- 0x00, 0xda, 0x00, 0xd0, 0x00, 0xb8, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5f,
- 0x00, 0x49, 0x00, 0x36, 0x00, 0x28, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0c,
- 0x00, 0x06, 0x00, 0x01, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x11, 0x00,
- 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0xda, 0x00, 0xd1,
- 0x00, 0xb8, 0x00, 0x96, 0x00, 0x71, 0x00, 0x4e, 0x00, 0x30, 0x02, 0x26,
- 0x04, 0x1e, 0x06, 0x17, 0x07, 0x12, 0x08, 0x0d, 0x09, 0x09, 0x0a, 0x06,
- 0x0a, 0x04, 0x0b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x11, 0x00,
- 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0xdb, 0x00, 0xd5,
- 0x00, 0xc3, 0x00, 0xaa, 0x00, 0x8f, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x4c,
- 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x0d,
- 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x11, 0x00,
- 0x13, 0x00, 0x14, 0x00, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc1, 0x00, 0xa6,
- 0x00, 0x87, 0x00, 0x67, 0x00, 0x4a, 0x00, 0x30, 0x02, 0x27, 0x03, 0x20,
- 0x05, 0x1a, 0x06, 0x14, 0x07, 0x10, 0x08, 0x0c, 0x09, 0x09, 0x0a, 0x07,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
- 0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x11, 0x00,
- 0x13, 0x00, 0x14, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xb6,
- 0x00, 0x9f, 0x00, 0x88, 0x00, 0x72, 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x40,
- 0x00, 0x34, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00, 0x13, 0x00, 0x0e,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
- 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x11, 0x00,
- 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc8, 0x00, 0xb2, 0x00, 0x97, 0x00, 0x7b,
- 0x00, 0x60, 0x00, 0x46, 0x00, 0x30, 0x01, 0x28, 0x03, 0x21, 0x04, 0x1c,
- 0x06, 0x17, 0x07, 0x13, 0x08, 0x0f, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00,
- 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00,
- 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x11, 0x00,
- 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xce, 0x00, 0xbe, 0x00, 0xab, 0x00, 0x96,
- 0x00, 0x82, 0x00, 0x70, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x43, 0x00, 0x38,
- 0x00, 0x2e, 0x00, 0x26, 0x00, 0x1f, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00,
- 0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x00, 0xdc, 0x00, 0xd8,
- 0x00, 0xcc, 0x00, 0xba, 0x00, 0xa4, 0x00, 0x8b, 0x00, 0x72, 0x00, 0x5a,
- 0x00, 0x44, 0x00, 0x2f, 0x01, 0x29, 0x03, 0x23, 0x04, 0x1e, 0x05, 0x19,
- 0x06, 0x15, 0x07, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x10, 0x00,
- 0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00,
- 0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x00, 0xdd, 0x00, 0xda,
- 0x00, 0xd1, 0x00, 0xc4, 0x00, 0xb4, 0x00, 0xa2, 0x00, 0x90, 0x00, 0x7e,
- 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x52, 0x00, 0x46, 0x00, 0x3c, 0x00, 0x32,
- 0x00, 0x2a, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x08, 0x00,
- 0x0a, 0x00, 0x0c, 0x00, 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xd0, 0x00, 0xc0,
- 0x00, 0xad, 0x00, 0x98, 0x00, 0x81, 0x00, 0x6b, 0x00, 0x56, 0x00, 0x42,
- 0x00, 0x2f, 0x01, 0x29, 0x02, 0x24, 0x04, 0x1f, 0x05, 0x1b, 0x06, 0x17,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
- 0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x0a, 0x00,
- 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x08, 0x00,
- 0x0a, 0x00, 0x0c, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9,
- 0x00, 0xbb, 0x00, 0xab, 0x00, 0x9b, 0x00, 0x8a, 0x00, 0x7b, 0x00, 0x6c,
- 0x00, 0x5f, 0x00, 0x53, 0x00, 0x48, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2e,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09, 0x00,
- 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xc5, 0x00, 0xb5, 0x00, 0xa2,
- 0x00, 0x8e, 0x00, 0x79, 0x00, 0x65, 0x00, 0x52, 0x00, 0x40, 0x00, 0x2f,
- 0x01, 0x2a, 0x02, 0x25, 0x03, 0x20, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00,
- 0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09, 0x00,
- 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb2,
- 0x00, 0xa4, 0x00, 0x95, 0x00, 0x86, 0x00, 0x78, 0x00, 0x6b, 0x00, 0x5f,
- 0x00, 0x54, 0x00, 0x4a, 0x00, 0x41, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0xdd, 0x00, 0xdb,
- 0x00, 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xaa, 0x00, 0x98, 0x00, 0x85,
- 0x00, 0x72, 0x00, 0x60, 0x00, 0x4f, 0x00, 0x3e, 0x00, 0x2f, 0x01, 0x2a,
- 0x02, 0x26, 0x03, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16, 0x00,
- 0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00,
- 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0xde, 0x00, 0xdc,
- 0x00, 0xd7, 0x00, 0xcf, 0x00, 0xc4, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x9e,
- 0x00, 0x90, 0x00, 0x83, 0x00, 0x76, 0x00, 0x6a, 0x00, 0x5f, 0x00, 0x55,
- 0x00, 0x4c, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x04, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc,
- 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8f, 0x00, 0x7e, 0x00, 0x6d,
- 0x00, 0x5c, 0x00, 0x4c, 0x00, 0x3d, 0x00, 0x2f, 0x01, 0x2b, 0x02, 0x26,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00,
- 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x14, 0x00, 0x11, 0x00,
- 0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x04, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd1,
- 0x00, 0xc8, 0x00, 0xbd, 0x00, 0xb1, 0x00, 0xa5, 0x00, 0x98, 0x00, 0x8c,
- 0x00, 0x80, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x4d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
- 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xce, 0x00, 0xc3, 0x00, 0xb6,
- 0x00, 0xa8, 0x00, 0x98, 0x00, 0x88, 0x00, 0x78, 0x00, 0x68, 0x00, 0x59,
- 0x00, 0x4a, 0x00, 0x3c, 0x00, 0x2f, 0x01, 0x2b, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00,
- 0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0x00,
- 0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
- 0x00, 0xde, 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcb, 0x00, 0xc1,
- 0x00, 0xb7, 0x00, 0xab, 0x00, 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7d,
- 0x00, 0x73, 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc,
- 0x00, 0xd8, 0x00, 0xd0, 0x00, 0xc7, 0x00, 0xbb, 0x00, 0xae, 0x00, 0xa0,
- 0x00, 0x91, 0x00, 0x82, 0x00, 0x73, 0x00, 0x64, 0x00, 0x56, 0x00, 0x48,
- 0x00, 0x3b, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00,
- 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x09, 0x00,
- 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd,
- 0x00, 0xda, 0x00, 0xd4, 0x00, 0xcd, 0x00, 0xc5, 0x00, 0xbb, 0x00, 0xb1,
- 0x00, 0xa6, 0x00, 0x9b, 0x00, 0x90, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71,
- 0x00, 0x68, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x61, 0x03, 0x23, 0x09, 0x03, 0x13, 0x00,
- 0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00,
- 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x9f,
- 0x00, 0xc5, 0x00, 0xd2, 0x00, 0xd7, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc,
- 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde,
- 0x00, 0xde, 0x00, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x1f, 0x01, 0x04, 0x0a, 0x00, 0x11, 0x00,
- 0x15, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00,
- 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, 0x5f, 0x00, 0x9f, 0x00, 0xbc,
- 0x00, 0xc9, 0x00, 0xd0, 0x00, 0xd5, 0x00, 0xd7, 0x00, 0xd9, 0x00, 0xda,
- 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x9f,
- 0x00, 0x5f, 0x00, 0x32, 0x00, 0x16, 0x00, 0x06, 0x03, 0x00, 0x0a, 0x00,
- 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00,
- 0x1a, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x09, 0x03, 0x00, 0x1f, 0x00, 0x5f, 0x00, 0x8d, 0x00, 0xa8, 0x00, 0xb8,
- 0x00, 0xc3, 0x00, 0xc9, 0x00, 0xce, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd6,
- 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xbc, 0x00, 0x8d, 0x00, 0x5f,
- 0x00, 0x3d, 0x00, 0x25, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x05, 0x00,
- 0x09, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x15, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x01, 0x04,
- 0x00, 0x32, 0x00, 0x5f, 0x00, 0x81, 0x00, 0x99, 0x00, 0xaa, 0x00, 0xb6,
- 0x00, 0xbe, 0x00, 0xc4, 0x00, 0xc9, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1,
- 0x00, 0xd3, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xa8, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x44,
- 0x00, 0x2f, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0b, 0x00, 0x04, 0x01, 0x00,
- 0x05, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x0a, 0x00, 0x00, 0x16, 0x00, 0x3d,
- 0x00, 0x5f, 0x00, 0x7a, 0x00, 0x8f, 0x00, 0x9f, 0x00, 0xab, 0x00, 0xb4,
- 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc4, 0x00, 0xc8, 0x00, 0xcb, 0x00, 0xcd,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd0,
- 0x00, 0xb8, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x36,
- 0x00, 0x28, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x01,
- 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1a, 0x00, 0x11, 0x00, 0x00, 0x06, 0x00, 0x25, 0x00, 0x44, 0x00, 0x5f,
- 0x00, 0x76, 0x00, 0x88, 0x00, 0x96, 0x00, 0xa2, 0x00, 0xab, 0x00, 0xb2,
- 0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc1, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xc3, 0x00, 0xaa,
- 0x00, 0x8f, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2f,
- 0x00, 0x24, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x15, 0x00,
- 0x03, 0x00, 0x00, 0x14, 0x00, 0x2f, 0x00, 0x49, 0x00, 0x5f, 0x00, 0x72,
- 0x00, 0x82, 0x00, 0x90, 0x00, 0x9b, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1,
- 0x00, 0xb7, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xb6, 0x00, 0x9f, 0x00, 0x88,
- 0x00, 0x72, 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29,
- 0x00, 0x21, 0x00, 0x19, 0x00, 0x13, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x0a, 0x00, 0x00, 0x09,
- 0x00, 0x1f, 0x00, 0x36, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x70, 0x00, 0x7e,
- 0x00, 0x8a, 0x00, 0x95, 0x00, 0x9e, 0x00, 0xa5, 0x00, 0xab, 0x00, 0xb1,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xd9,
- 0x00, 0xce, 0x00, 0xbe, 0x00, 0xab, 0x00, 0x96, 0x00, 0x82, 0x00, 0x70,
- 0x00, 0x5f, 0x00, 0x50, 0x00, 0x43, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x26,
- 0x00, 0x1f, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1d, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x28,
- 0x00, 0x3c, 0x00, 0x4e, 0x00, 0x5f, 0x00, 0x6e, 0x00, 0x7b, 0x00, 0x86,
- 0x00, 0x90, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc4,
- 0x00, 0xb4, 0x00, 0xa2, 0x00, 0x90, 0x00, 0x7e, 0x00, 0x6e, 0x00, 0x5f,
- 0x00, 0x52, 0x00, 0x46, 0x00, 0x3c, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x23,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1b, 0x00,
- 0x12, 0x00, 0x05, 0x00, 0x00, 0x0b, 0x00, 0x1c, 0x00, 0x2f, 0x00, 0x40,
- 0x00, 0x50, 0x00, 0x5f, 0x00, 0x6c, 0x00, 0x78, 0x00, 0x83, 0x00, 0x8c,
- 0x00, 0x94, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xab,
- 0x00, 0x9b, 0x00, 0x8a, 0x00, 0x7b, 0x00, 0x6c, 0x00, 0x5f, 0x00, 0x53,
- 0x00, 0x48, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x09, 0x00,
- 0x00, 0x04, 0x00, 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x43, 0x00, 0x52,
- 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x76, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc,
- 0x00, 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x95,
- 0x00, 0x86, 0x00, 0x78, 0x00, 0x6b, 0x00, 0x5f, 0x00, 0x54, 0x00, 0x4a,
- 0x00, 0x41, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1e, 0x00, 0x1c, 0x00, 0x16, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x0c,
- 0x00, 0x1b, 0x00, 0x29, 0x00, 0x38, 0x00, 0x46, 0x00, 0x53, 0x00, 0x5f,
- 0x00, 0x6a, 0x00, 0x74, 0x00, 0x7d, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xcf,
- 0x00, 0xc4, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x9e, 0x00, 0x90, 0x00, 0x83,
- 0x00, 0x76, 0x00, 0x6a, 0x00, 0x5f, 0x00, 0x55, 0x00, 0x4c, 0x00, 0x43,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1d, 0x00,
- 0x18, 0x00, 0x10, 0x00, 0x05, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x21,
- 0x00, 0x2e, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x69,
- 0x00, 0x73, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd1, 0x00, 0xc8, 0x00, 0xbd,
- 0x00, 0xb1, 0x00, 0xa5, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x74,
- 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00,
- 0x09, 0x00, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x26, 0x00, 0x32,
- 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x55, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x71,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd,
- 0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcb, 0x00, 0xc1, 0x00, 0xb7, 0x00, 0xab,
- 0x00, 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7d, 0x00, 0x73, 0x00, 0x69,
- 0x00, 0x5f, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1f, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x02, 0x00,
- 0x00, 0x08, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x41,
- 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5f, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd4,
- 0x00, 0xcd, 0x00, 0xc5, 0x00, 0xbb, 0x00, 0xb1, 0x00, 0xa6, 0x00, 0x9b,
- 0x00, 0x90, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00,
- 0x1a, 0x00, 0x15, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x0e,
- 0x00, 0x18, 0x00, 0x23, 0x00, 0x2e, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4d,
- 0x00, 0x56, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
-};
-
-/* clang-format on */
+extern const unsigned char areaTexBytes[];
#define SEARCHTEX_WIDTH 64
#define SEARCHTEX_HEIGHT 16
#define SEARCHTEX_PITCH SEARCHTEX_WIDTH
#define SEARCHTEX_SIZE (SEARCHTEX_HEIGHT * SEARCHTEX_PITCH)
-/* Don't re-wrap large data definitions. */
-/* clang-format off */
-
/**
* Stored in R8 format. Load it in the following format:
* - DX10: DXGI_FORMAT_R8_UNORM
*/
-static const unsigned char searchTexBytes[] = {
- 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00,
- 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0xfe, 0x7f, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe,
- 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
- 0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00,
- 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0xfe, 0x7f, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe,
- 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
- 0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f,
- 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
- 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
- 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00,
- 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f,
- 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
- 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
- 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00,
- 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-};
-
-/* clang-format off */
+extern const unsigned char searchTexBytes[];
diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc
index a9810b4cc77..6f4dc226c84 100644
--- a/source/blender/draw/tests/shaders_test.cc
+++ b/source/blender/draw/tests/shaders_test.cc
@@ -13,19 +13,20 @@
#include "intern/draw_manager_testing.h"
+#include "engines/basic/basic_private.h"
#include "engines/eevee/eevee_private.h"
#include "engines/gpencil/gpencil_engine.h"
-#include "engines/image/image_private.h"
+#include "engines/image/image_private.hh"
#include "engines/overlay/overlay_private.h"
#include "engines/workbench/workbench_private.h"
#include "intern/draw_shader.h"
namespace blender::draw {
+using namespace blender::draw::image_engine;
+
static void test_workbench_glsl_shaders()
{
- workbench_shader_library_ensure();
-
const int MAX_WPD = 6;
WORKBENCH_PrivateData wpds[MAX_WPD];
@@ -394,4 +395,17 @@ static void test_draw_glsl_shaders()
}
DRAW_TEST(draw_glsl_shaders)
+static void test_basic_glsl_shaders()
+{
+ for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) {
+ eGPUShaderConfig sh_cfg = static_cast<eGPUShaderConfig>(i);
+ BASIC_shaders_depth_sh_get(sh_cfg);
+ BASIC_shaders_pointcloud_depth_sh_get(sh_cfg);
+ BASIC_shaders_depth_conservative_sh_get(sh_cfg);
+ BASIC_shaders_pointcloud_depth_conservative_sh_get(sh_cfg);
+ }
+ BASIC_shaders_free();
+}
+DRAW_TEST(basic_glsl_shaders)
+
} // namespace blender::draw
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt
index d9f52d90766..6fa4d94df3a 100644
--- a/source/blender/editors/animation/CMakeLists.txt
+++ b/source/blender/editors/animation/CMakeLists.txt
@@ -70,3 +70,15 @@ endif()
blender_add_lib(bf_editor_animation "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_GTESTS)
+ set(TEST_SRC
+ keyframes_keylist_test.cc
+ )
+ set(TEST_INC
+ )
+ set(TEST_LIB
+ )
+ include(GTestTesting)
+ blender_add_test_lib(bf_editor_animation_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
+endif()
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index e5dc9a83ebb..2eaa42ee578 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -199,7 +199,7 @@ static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, floa
}
/* set color for normal channels
- * - use 3 shades of color group/standard color for 3 indention level
+ * - use 3 shades of color group/standard color for 3 indentation level
* - only use group colors if allowed to, and if actually feasible
*/
if (showGroupColors && (grp) && (grp->customCol)) {
@@ -4158,7 +4158,6 @@ static void ANIM_init_channel_typeinfo_data(void)
}
}
-/* Get type info from given channel type */
const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
{
/* Sanity checks. */
@@ -4179,7 +4178,6 @@ const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
/* --------------------------- */
-/* Print debug info string for the given channel */
void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
{
const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
@@ -4212,11 +4210,25 @@ void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
}
}
+bAction *ANIM_channel_action_get(const bAnimListElem *ale)
+{
+ if (ale->datatype == ALE_ACT) {
+ return (bAction *)ale->key_data;
+ }
+
+ if (ELEM(ale->type, ANIMTYPE_GROUP, ANIMTYPE_FCURVE)) {
+ ID *owner = ale->fcurve_owner_id;
+
+ if (owner && GS(owner->name) == ID_AC) {
+ return (bAction *)owner;
+ }
+ }
+
+ return NULL;
+}
+
/* --------------------------- */
-/* Check if some setting for a channel is enabled
- * Returns: 1 = On, 0 = Off, -1 = Invalid
- */
short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
{
const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
@@ -4299,10 +4311,6 @@ short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChanne
} \
(void)0
-/* Change value of some setting for a channel
- * - setting: eAnimChannel_Settings
- * - mode: eAnimChannels_SetFlag
- */
void ANIM_channel_setting_set(bAnimContext *ac,
bAnimListElem *ale,
eAnimChannel_Settings setting,
@@ -4376,7 +4384,6 @@ static bool achannel_is_being_renamed(const bAnimContext *ac,
return false;
}
-/* Draw the given channel */
void ANIM_channel_draw(
bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index)
{
@@ -5132,7 +5139,6 @@ static void draw_setting_widget(bAnimContext *ac,
}
}
-/* Draw UI widgets the given channel */
void ANIM_channel_draw_widgets(const bContext *C,
bAnimContext *ac,
bAnimListElem *ale,
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index afbd9b2c92d..b97837a76b9 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -51,6 +51,7 @@
#include "BKE_mask.h"
#include "BKE_nla.h"
#include "BKE_scene.h"
+#include "BKE_screen.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -73,8 +74,6 @@
/* -------------------------- Selection ------------------------------------- */
-/* Set the given animation-channel as the active one for the active context */
-/* TODO: extend for animdata types... */
void ANIM_set_active_channel(bAnimContext *ac,
void *data,
eAnimCont_Types datatype,
@@ -82,6 +81,8 @@ void ANIM_set_active_channel(bAnimContext *ac,
void *channel_data,
eAnim_ChannelType channel_type)
{
+ /* TODO: extend for animdata types. */
+
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -459,7 +460,6 @@ static void anim_channels_select_set(bAnimContext *ac,
}
}
-/* Set selection state of all animation channels in the context. */
void ANIM_anim_channels_select_set(bAnimContext *ac, eAnimChannels_SetFlag sel)
{
ListBase anim_data = anim_channels_for_selection(ac);
@@ -467,7 +467,6 @@ void ANIM_anim_channels_select_set(bAnimContext *ac, eAnimChannels_SetFlag sel)
ANIM_animdata_freelist(&anim_data);
}
-/* Toggle selection state of all animation channels in the context. */
void ANIM_anim_channels_select_toggle(bAnimContext *ac)
{
ListBase anim_data = anim_channels_for_selection(ac);
@@ -587,15 +586,6 @@ static void anim_flush_channel_setting_down(bAnimContext *ac,
}
}
-/* Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting
- * - anim_data: list of the all the anim channels that can be chosen
- * -> filtered using ANIMFILTER_CHANNELS only, since if we took VISIBLE too,
- * then the channels under closed expanders get ignored...
- * - ale_setting: the anim channel (not in the anim_data list directly, though occurring there)
- * with the new state of the setting that we want flushed up/down the hierarchy
- * - setting: type of setting to set
- * - on: whether the visibility setting has been enabled or disabled
- */
void ANIM_flush_setting_anim_channels(bAnimContext *ac,
ListBase *anim_data,
bAnimListElem *ale_setting,
@@ -651,7 +641,6 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac,
/* -------------------------- F-Curves ------------------------------------- */
-/* Delete the given F-Curve from its AnimData block */
void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *fcu)
{
/* - if no AnimData, we've got nowhere to remove the F-Curve from
@@ -707,8 +696,6 @@ void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *f
BKE_fcurve_free(fcu);
}
-/* If the action has no F-Curves, unlink it from AnimData if it did not
- * come from a NLA Strip being tweaked. */
bool ANIM_remove_empty_action_from_animdata(struct AnimData *adt)
{
if (adt->action != NULL) {
@@ -2522,10 +2509,10 @@ static void ANIM_OT_channels_fcurves_enable(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****************** Find / Set Filter Operator ******************** */
+/* ****************** Select Filter Textbox Operator ******************** */
/* XXX: make this generic? */
-static bool animchannels_find_poll(bContext *C)
+static bool animchannels_select_filter_poll(bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -2537,64 +2524,62 @@ static bool animchannels_find_poll(bContext *C)
return ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA);
}
-/* find_invoke() - Get initial channels */
-static int animchannels_find_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int animchannels_select_filter_invoke(struct bContext *C,
+ struct wmOperator *op,
+ const struct wmEvent *UNUSED(event))
{
- bAnimContext ac;
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region_ctx = CTX_wm_region(C);
+ ARegion *region_channels = BKE_area_find_region_type(area, RGN_TYPE_CHANNELS);
- /* get editor data */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return OPERATOR_CANCELLED;
+ CTX_wm_region_set(C, region_channels);
+
+ /* Show the channel region if it's hidden. This means that direct activation of the input field
+ * is impossible, as it may not exist yet. For that reason, the actual activation is deferred to
+ * the modal callback function; by the time it runs, the screen has been redrawn and the UI
+ * element is there to activate. */
+ if (region_channels->flag & RGN_FLAG_HIDDEN) {
+ ED_region_toggle_hidden(C, region_channels);
+ ED_region_tag_redraw(region_channels);
}
- /* set initial filter text, and enable filter */
- RNA_string_set(op->ptr, "query", ac.ads->searchstr);
+ WM_event_add_modal_handler(C, op);
- /* defer to popup */
- return WM_operator_props_popup(C, op, event);
+ CTX_wm_region_set(C, region_ctx);
+ return OPERATOR_RUNNING_MODAL;
}
-/* find_exec() - Called to set the value */
-static int animchannels_find_exec(bContext *C, wmOperator *op)
+static int animchannels_select_filter_modal(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *UNUSED(event))
{
bAnimContext ac;
-
- /* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0) {
return OPERATOR_CANCELLED;
}
- /* update filter text */
- RNA_string_get(op->ptr, "query", ac.ads->searchstr);
-
- /* redraw */
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ ARegion *region = CTX_wm_region(C);
+ if (UI_textbutton_activate_rna(C, region, ac.ads, "filter_text")) {
+ /* Redraw to make sure it shows the cursor after activating */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ }
return OPERATOR_FINISHED;
}
-static void ANIM_OT_channels_find(wmOperatorType *ot)
+static void ANIM_OT_channels_select_filter(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Find Channels";
- ot->idname = "ANIM_OT_channels_find";
- ot->description = "Filter the set of channels shown to only include those with matching names";
+ ot->name = "Filter Channels";
+ ot->idname = "ANIM_OT_channels_select_filter";
+ ot->description =
+ "Start entering text which filters the set of channels shown to only include those with "
+ "matching names";
/* callbacks */
- ot->invoke = animchannels_find_invoke;
- ot->exec = animchannels_find_exec;
- ot->poll = animchannels_find_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_string(ot->srna,
- "query",
- "Query",
- sizeof(((bDopeSheet *)NULL)->searchstr),
- "",
- "Text to search for in channel names");
+ ot->invoke = animchannels_select_filter_invoke;
+ ot->modal = animchannels_select_filter_modal;
+ ot->poll = animchannels_select_filter_poll;
}
/* ********************** Select All Operator *********************** */
@@ -3563,7 +3548,7 @@ void ED_operatortypes_animchannels(void)
WM_operatortype_append(ANIM_OT_channel_select_keys);
WM_operatortype_append(ANIM_OT_channels_rename);
- WM_operatortype_append(ANIM_OT_channels_find);
+ WM_operatortype_append(ANIM_OT_channels_select_filter);
WM_operatortype_append(ANIM_OT_channels_setting_enable);
WM_operatortype_append(ANIM_OT_channels_setting_disable);
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 088de80bb65..7a34d8b542a 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -56,9 +56,6 @@
/* **************************** depsgraph tagging ******************************** */
-/* tags the given anim list element for refreshes (if applicable)
- * due to Animation Editor editing
- */
void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
{
ID *id;
@@ -114,8 +111,6 @@ void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
}
}
-/* tags the given ID block for refreshes (if applicable) due to
- * Animation Editor editing */
void ANIM_id_update(Main *bmain, ID *id)
{
if (id) {
@@ -276,7 +271,6 @@ static void animchan_sync_gplayer(bAnimListElem *ale)
/* ---------------- */
-/* Main call to be exported to animation editors */
void ANIM_sync_animchannels_to_data(const bContext *C)
{
bAnimContext ac;
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 993d10cf303..6589756c526 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -63,7 +63,6 @@
/* *************************************************** */
/* CURRENT FRAME DRAWING */
-/* General call for drawing current frame indicator in animation editor */
void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
{
Scene *scene = CTX_data_scene(C);
@@ -92,7 +91,6 @@ void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
/* PREVIEW RANGE 'CURTAINS' */
/* NOTE: 'Preview Range' tools are defined in `anim_ops.c`. */
-/* Draw preview range 'curtains' for highlighting where the animation data is */
void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width)
{
Scene *scene = CTX_data_scene(C);
@@ -127,11 +125,6 @@ void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width)
/* *************************************************** */
/* SCENE FRAME RANGE */
-/**
- * Draw frame range guides (for scene frame range) in background.
- *
- * TODO: Should we still show these when preview range is enabled?
- */
void ANIM_draw_framerange(Scene *scene, View2D *v2d)
{
/* draw darkened area outside of active timeline frame range */
@@ -168,14 +161,73 @@ void ANIM_draw_framerange(Scene *scene, View2D *v2d)
immUnbindProgram();
}
+void ANIM_draw_action_framerange(
+ AnimData *adt, bAction *action, View2D *v2d, float ymin, float ymax)
+{
+ if ((action->flag & ACT_FRAME_RANGE) == 0) {
+ return;
+ }
+
+ /* Compute the dimensions. */
+ CLAMP_MIN(ymin, v2d->cur.ymin);
+ CLAMP_MAX(ymax, v2d->cur.ymax);
+
+ if (ymin > ymax) {
+ return;
+ }
+
+ const float sfra = BKE_nla_tweakedit_remap(adt, action->frame_start, NLATIME_CONVERT_MAP);
+ const float efra = BKE_nla_tweakedit_remap(adt, action->frame_end, NLATIME_CONVERT_MAP);
+
+ /* Diagonal stripe filled area outside of the frame range. */
+ GPU_blend(GPU_BLEND_ALPHA);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_DIAG_STRIPES);
+
+ float color[4];
+ UI_GetThemeColorShadeAlpha4fv(TH_BACK, -40, -50, color);
+
+ immUniform4f("color1", color[0], color[1], color[2], color[3]);
+ immUniform4f("color2", 0.0f, 0.0f, 0.0f, 0.0f);
+ immUniform1i("size1", 2 * U.dpi_fac);
+ immUniform1i("size2", 4 * U.dpi_fac);
+
+ if (sfra < efra) {
+ immRectf(pos, v2d->cur.xmin, ymin, sfra, ymax);
+ immRectf(pos, efra, ymin, v2d->cur.xmax, ymax);
+ }
+ else {
+ immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax, ymax);
+ }
+
+ immUnbindProgram();
+
+ GPU_blend(GPU_BLEND_NONE);
+
+ /* Thin lines where the actual frames are. */
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, -60);
+
+ GPU_line_width(1.0f);
+
+ immBegin(GPU_PRIM_LINES, 4);
+
+ immVertex2f(pos, sfra, ymin);
+ immVertex2f(pos, sfra, ymax);
+
+ immVertex2f(pos, efra, ymin);
+ immVertex2f(pos, efra, ymax);
+
+ immEnd();
+ immUnbindProgram();
+}
+
/* *************************************************** */
/* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes). */
-/**
- * Obtain the AnimData block providing NLA-mapping for the given channel (if applicable).
- *
- * TODO: do not supply return this if the animdata tells us that there is no mapping to perform.
- */
AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
{
/* sanity checks */
@@ -251,10 +303,6 @@ static short bezt_nlamapping_apply(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve
- * - restore = whether to map points back to non-mapped time
- * - only_keys = whether to only adjust the location of the center point of beztriples
- */
void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, bool only_keys)
{
KeyframeEditData ked = {{NULL}};
@@ -282,7 +330,6 @@ void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, boo
/* *************************************************** */
/* UNITS CONVERSION MAPPING (required for drawing and editing keyframes) */
-/* Get flags used for normalization in ANIM_unit_mapping_get_factor. */
short ANIM_get_normalization_flags(bAnimContext *ac)
{
if (ac->sl->spacetype == SPACE_GRAPH) {
@@ -450,7 +497,6 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo
return factor;
}
-/* Get unit conversion factor for given ID + F-Curve */
float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
{
if (flag & ANIM_UNITCONV_NORMALIZE) {
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index e1d046428a8..c1a09b9d21f 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -362,11 +362,6 @@ static bool nlaedit_get_context(bAnimContext *ac, SpaceNla *snla)
/* ----------- Public API --------------- */
-/* Obtain current anim-data context,
- * given that context info from Blender context has already been set:
- * - AnimContext to write to is provided as pointer to var on stack so that we don't have
- * allocation/freeing costs (which are not that avoidable with channels).
- */
bool ANIM_animdata_context_getdata(bAnimContext *ac)
{
SpaceLink *sl = ac->sl;
@@ -397,11 +392,6 @@ bool ANIM_animdata_context_getdata(bAnimContext *ac)
return (ok && ac->data);
}
-/* Obtain current anim-data context from Blender Context info
- * - AnimContext to write to is provided as pointer to var on stack so that we don't have
- * allocation/freeing costs (which are not that avoidable with channels).
- * - Clears data and sets the information from Blender Context which is useful
- */
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
{
Main *bmain = CTX_data_main(C);
@@ -1900,7 +1890,8 @@ static size_t animdata_filter_gpencil(bAnimContext *ac,
if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
/* Layer visibility - we check both object and base,
* since these may not be in sync yet. */
- if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0 ||
+ (base->flag & BASE_VISIBLE_VIEWLAYER) == 0) {
continue;
}
@@ -3459,14 +3450,6 @@ static size_t animdata_filter_remove_duplis(ListBase *anim_data)
/* ----------- Public API --------------- */
-/**
- * This function filters the active data source to leave only animation channels suitable for
- * usage by the caller. It will return the length of the list
- *
- * \param anim_data: Is a pointer to a #ListBase,
- * to which the filtered animation channels will be placed for use.
- * \param filter_mode: how should the data be filtered - bit-mapping accessed flags.
- */
size_t ANIM_animdata_filter(bAnimContext *ac,
ListBase *anim_data,
eAnimFilter_Flags filter_mode,
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index 33b4882927a..0315b93508b 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -43,14 +43,6 @@
/* ----------------------- Getter functions ----------------------- */
-/**
- * Write into "name" buffer, the name of the property
- * (retrieved using RNA from the curve's settings),
- * and return the icon used for the struct that this property refers to
- *
- * \warning name buffer we're writing to cannot exceed 256 chars
- * (check anim_channels_defines.c for details).
- */
int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
{
int icon = 0;
@@ -126,9 +118,10 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
structname = RNA_struct_ui_name(ptr.type);
}
- /* For the VSE, a strip's 'Transform' or 'Crop' is a nested (under Sequence) struct, but
- * displaying the struct name alone is no meaningful information (and also cannot be
- * filtered well), same for modifiers. So display strip name alongside as well. */
+ /* For the sequencer, a strip's 'Transform' or 'Crop' is a nested (under Sequence)
+ * struct, but displaying the struct name alone is no meaningful information
+ * (and also cannot be filtered well), same for modifiers.
+ * So display strip name alongside as well. */
if (GS(ptr.owner_id->name) == ID_SCE) {
char stripname[256];
if (BLI_str_quoted_substr(
@@ -144,6 +137,22 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
}
}
}
+ /* For node sockets, it is useful to include the node name as well (multiple similar nodes
+ * are not distinguishable otherwise). Unfortunately, the node label cannot be retrieved
+ * from the rna path, for this to work access to the underlying node is needed (but finding
+ * the node iterates all nodes & sockets which would result in bad performance in some
+ * circumstances). */
+ if (RNA_struct_is_a(ptr.type, &RNA_NodeSocket)) {
+ char nodename[256];
+ if (BLI_str_quoted_substr(fcu->rna_path, "nodes[", nodename, sizeof(nodename))) {
+ const char *structname_all = BLI_sprintfN("%s : %s", nodename, structname);
+ if (free_structname) {
+ MEM_freeN((void *)structname);
+ }
+ structname = structname_all;
+ free_structname = 1;
+ }
+ }
}
/* Property Name is straightforward */
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 0de3f429bc7..baf3eaae8e2 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -99,13 +99,11 @@ static ListBase *context_get_markers(Scene *scene, ScrArea *area)
/* ............. */
-/* public API for getting markers from context */
ListBase *ED_context_get_markers(const bContext *C)
{
return context_get_markers(CTX_data_scene(C), CTX_wm_area(C));
}
-/* public API for getting markers from "animation" context */
ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
{
if (ac) {
@@ -116,17 +114,6 @@ ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
/* --------------------------------- */
-/**
- * Apply some transformation to markers after the fact
- *
- * \param markers: List of markers to affect - this may or may not be the scene markers list,
- * so don't assume anything.
- * \param scene: Current scene (for getting current frame)
- * \param mode: (TfmMode) transform mode that this transform is for
- * \param value: From the transform code, this is `t->vec[0]`
- * (which is delta transform for grab/extend, and scale factor for scale)
- * \param side: (B/L/R) for 'extend' functionality, which side of current frame to use
- */
int ED_markers_post_apply_transform(
ListBase *markers, Scene *scene, int mode, float value, char side)
{
@@ -168,8 +155,6 @@ int ED_markers_post_apply_transform(
/* --------------------------------- */
-/* Get the marker that is closest to this point */
-/* XXX for select, the min_dist should be small */
TimeMarker *ED_markers_find_nearest_marker(ListBase *markers, float x)
{
TimeMarker *marker, *nearest = NULL;
@@ -189,7 +174,6 @@ TimeMarker *ED_markers_find_nearest_marker(ListBase *markers, float x)
return nearest;
}
-/* Return the time of the marker that occurs on a frame closest to the given time */
int ED_markers_find_nearest_marker_time(ListBase *markers, float x)
{
TimeMarker *nearest = ED_markers_find_nearest_marker(markers, x);
@@ -323,10 +307,6 @@ static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only
cen->sel = marker->flag;
}
-/* This function makes a list of all the markers. The only_sel
- * argument is used to specify whether only the selected markers
- * are added.
- */
void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
{
TimeMarker *marker;
@@ -375,7 +355,6 @@ void ED_markers_deselect_all(ListBase *markers, int action)
/* --------------------------------- */
-/* Get the first selected marker */
TimeMarker *ED_markers_get_first_selected(ListBase *markers)
{
TimeMarker *marker;
@@ -393,12 +372,11 @@ TimeMarker *ED_markers_get_first_selected(ListBase *markers)
/* --------------------------------- */
-/* Print debugging prints of list of markers
- * BSI's: do NOT make static or put in if-defs as "unused code".
- * That's too much trouble when we need to use for quick debugging!
- */
void debug_markers_print_list(ListBase *markers)
{
+ /* NOTE: do NOT make static or put in if-defs as "unused code".
+ * That's too much trouble when we need to use for quick debugging! */
+
TimeMarker *marker;
if (markers == NULL) {
@@ -564,7 +542,6 @@ static void get_marker_clip_frame_range(View2D *v2d, float xscale, int r_range[2
r_range[1] = v2d->cur.xmax + font_width_max;
}
-/* Draw Scene-Markers in time window */
void ED_markers_draw(const bContext *C, int flag)
{
ListBase *markers = ED_context_get_markers(C);
@@ -872,7 +849,7 @@ static int ed_marker_move_invoke(bContext *C, wmOperator *op, const wmEvent *eve
ARegion *region = CTX_wm_region(C);
View2D *v2d = &region->v2d;
ListBase *markers = ED_context_get_markers(C);
- if (!region_position_is_over_marker(v2d, markers, event->x - region->winrct.xmin)) {
+ if (!region_position_is_over_marker(v2d, markers, event->xy[0] - region->winrct.xmin)) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
}
@@ -880,8 +857,8 @@ static int ed_marker_move_invoke(bContext *C, wmOperator *op, const wmEvent *eve
if (ed_marker_move_init(C, op)) {
MarkerMove *mm = op->customdata;
- mm->evtx = event->x;
- mm->firstx = event->x;
+ mm->evtx = event->xy[0];
+ mm->firstx = event->xy[0];
mm->event_type = event->type;
/* add temp handler */
@@ -993,11 +970,11 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *even
dx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
- if (event->x != mm->evtx) { /* XXX maybe init for first time */
+ if (event->xy[0] != mm->evtx) { /* XXX maybe init for first time */
float fac;
- mm->evtx = event->x;
- fac = ((float)(event->x - mm->firstx) * dx);
+ mm->evtx = event->xy[0];
+ fac = ((float)(event->xy[0] - mm->firstx) * dx);
apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0);
@@ -1354,7 +1331,8 @@ static int ed_marker_box_select_invoke(bContext *C, wmOperator *op, const wmEven
View2D *v2d = &region->v2d;
ListBase *markers = ED_context_get_markers(C);
- bool over_marker = region_position_is_over_marker(v2d, markers, event->x - region->winrct.xmin);
+ bool over_marker = region_position_is_over_marker(
+ v2d, markers, event->xy[0] - region->winrct.xmin);
bool tweak = RNA_boolean_get(op->ptr, "tweak");
if (tweak && over_marker) {
@@ -1698,7 +1676,6 @@ static void MARKER_OT_camera_bind(wmOperatorType *ot)
/* ************************** registration **********************************/
-/* called in screen_ops.c:ED_operatortypes_screen() */
void ED_operatortypes_marker(void)
{
WM_operatortype_append(MARKER_OT_add);
@@ -1715,7 +1692,6 @@ void ED_operatortypes_marker(void)
#endif
}
-/* called in screen_ops.c:ED_keymap_screen() */
void ED_keymap_marker(wmKeyConfig *keyconf)
{
WM_keymap_ensure(keyconf, "Markers", 0, 0);
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index d130941b9bc..d4a8e7921d6 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -84,7 +84,7 @@ Depsgraph *animviz_depsgraph_build(Main *bmain,
/* Make a flat array of IDs for the DEG API. */
const int num_ids = BLI_listbase_count(targets);
- ID **ids = MEM_malloc_arrayN(sizeof(ID *), num_ids, "animviz IDS");
+ ID **ids = MEM_malloc_arrayN(num_ids, sizeof(ID *), "animviz IDS");
int current_id_index = 0;
for (MPathTarget *mpt = targets->first; mpt != NULL; mpt = mpt->next) {
ids[current_id_index++] = &mpt->ob->id;
@@ -99,12 +99,10 @@ Depsgraph *animviz_depsgraph_build(Main *bmain,
return depsgraph;
}
-/* get list of motion paths to be baked for the given object
- * - assumes the given list is ready to be used
- */
-/* TODO: it would be nice in future to be able to update objects dependent on these bones too? */
void animviz_get_object_motionpaths(Object *ob, ListBase *targets)
{
+ /* TODO: it would be nice in future to be able to update objects dependent on these bones too? */
+
MPathTarget *mpt;
/* object itself first */
@@ -176,11 +174,11 @@ static void motionpaths_calc_bake_targets(ListBase *targets, int cframe)
copy_v3_v3(mpv->co, pchan_eval->pose_tail);
}
- /* result must be in worldspace */
+ /* Result must be in world-space. */
mul_m4_v3(ob_eval->obmat, mpv->co);
}
else {
- /* worldspace object location */
+ /* World-space object location. */
copy_v3_v3(mpv->co, ob_eval->obmat[3]);
}
@@ -356,12 +354,6 @@ static void motionpath_free_free_tree_data(ListBase *targets)
}
}
-/* Perform baking of the given object's and/or its bones' transforms to motion paths
- * - scene: current scene
- * - ob: object whose flagged motion-paths should get calculated
- * - recalc: whether we need to
- */
-/* TODO: include reports pointer? */
void animviz_calc_motionpaths(Depsgraph *depsgraph,
Main *bmain,
Scene *scene,
@@ -369,6 +361,8 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
eAnimvizCalcRange range,
bool restore)
{
+ /* TODO: include reports pointer? */
+
/* Sanity check. */
if (ELEM(NULL, targets, targets->first)) {
return;
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 3958c7f9e34..1e60a129535 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -74,9 +74,17 @@ static bool change_frame_poll(bContext *C)
* this shouldn't show up in 3D editor (or others without 2D timeline view) via search
*/
if (area) {
- if (ELEM(area->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
+ if (ELEM(area->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_CLIP)) {
return true;
}
+ if (area->spacetype == SPACE_SEQ) {
+ /* Check the region type so tools (which are shared between preview/strip view)
+ * don't conflict with actions which can have the same key bound (2D cursor for example). */
+ const ARegion *region = CTX_wm_region(C);
+ if (region && region->regiontype == RGN_TYPE_WINDOW) {
+ return true;
+ }
+ }
if (area->spacetype == SPACE_GRAPH) {
const SpaceGraph *sipo = area->spacedata.first;
/* Driver Editor's X axis is not time. */
@@ -141,7 +149,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
bool do_snap = RNA_boolean_get(op->ptr, "snap");
if (do_snap) {
- if (CTX_wm_space_seq(C)) {
+ if (CTX_wm_space_seq(C) && SEQ_editing_get(scene) != NULL) {
frame = seq_frame_apply_snap(C, scene, frame);
}
else {
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index bfaa76b3bf9..bdcbac80699 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -61,9 +61,6 @@
/* ************************************************** */
/* Animation Data Validation */
-/* Get (or add relevant data to be able to do so) F-Curve from the driver stack,
- * for the given Animation Data block. This assumes that all the destinations are valid.
- */
FCurve *verify_driver_fcurve(ID *id,
const char rna_path[],
const int array_index,
@@ -295,17 +292,6 @@ static int add_driver_with_target(ReportList *UNUSED(reports),
return (fcu != NULL);
}
-/* Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block,
- * and make it be driven by the specified target.
- *
- * This is intended to be used in conjunction with a modal "eyedropper"
- * for picking the variable that is going to be used to drive this one.
- *
- * - flag: eCreateDriverFlags
- * - driver_type: eDriver_Types
- * - mapping_type: eCreateDriver_MappingTypes
- */
int ANIM_add_driver_with_target(ReportList *reports,
ID *dst_id,
const char dst_path[],
@@ -420,10 +406,6 @@ int ANIM_add_driver_with_target(ReportList *reports,
/* --------------------------------- */
-/**
- * Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block
- */
int ANIM_add_driver(
ReportList *reports, ID *id, const char rna_path[], int array_index, short flag, int type)
{
@@ -546,9 +528,6 @@ int ANIM_add_driver(
return done_tot;
}
-/* Main Driver Management API calls:
- * Remove the driver for the specified property on the given ID block (if available)
- */
bool ANIM_remove_driver(ReportList *UNUSED(reports),
ID *id,
const char rna_path[],
@@ -603,7 +582,6 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports),
/* Copy/Paste Buffer for Driver Data... */
static FCurve *channeldriver_copypaste_buf = NULL;
-/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ANIM_drivers_copybuf_free(void)
{
/* free the buffer F-Curve if it exists, as if it were just another F-Curve */
@@ -613,7 +591,6 @@ void ANIM_drivers_copybuf_free(void)
channeldriver_copypaste_buf = NULL;
}
-/* Checks if there is a driver in the copy/paste buffer */
bool ANIM_driver_can_paste(void)
{
return (channeldriver_copypaste_buf != NULL);
@@ -621,9 +598,6 @@ bool ANIM_driver_can_paste(void)
/* ------------------- */
-/* Main Driver Management API calls:
- * Make a copy of the driver for the specified property on the given ID block
- */
bool ANIM_copy_driver(
ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag))
{
@@ -672,10 +646,6 @@ bool ANIM_copy_driver(
return 0;
}
-/* Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block or replace an existing one
- * with the driver + driver-curve data from the buffer
- */
bool ANIM_paste_driver(
ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag))
{
@@ -733,7 +703,6 @@ bool ANIM_paste_driver(
/* Copy/Paste Buffer for Driver Variables... */
static ListBase driver_vars_copybuf = {NULL, NULL};
-/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ANIM_driver_vars_copybuf_free(void)
{
/* Free the driver variables kept in the buffer */
@@ -750,7 +719,6 @@ void ANIM_driver_vars_copybuf_free(void)
BLI_listbase_clear(&driver_vars_copybuf);
}
-/* Checks if there are driver variables in the copy/paste buffer */
bool ANIM_driver_vars_can_paste(void)
{
return (BLI_listbase_is_empty(&driver_vars_copybuf) == false);
@@ -758,7 +726,6 @@ bool ANIM_driver_vars_can_paste(void)
/* -------------------------------------------------- */
-/* Copy the given driver's variables to the buffer */
bool ANIM_driver_vars_copy(ReportList *reports, FCurve *fcu)
{
/* sanity checks */
@@ -781,7 +748,6 @@ bool ANIM_driver_vars_copy(ReportList *reports, FCurve *fcu)
return (BLI_listbase_is_empty(&driver_vars_copybuf) == false);
}
-/* Paste the variables in the buffer to the given FCurve */
bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
{
ChannelDriver *driver = (fcu) ? fcu->driver : NULL;
@@ -837,8 +803,6 @@ bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
/* -------------------------------------------------- */
-/* Create a driver & variable that reads the specified property,
- * and store it in the buffers for Paste Driver and Paste Variables. */
void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const char *var_name)
{
/* Clear copy/paste buffer first (for consistency with other copy/paste buffers). */
@@ -882,13 +846,8 @@ void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const ch
/* Add Driver - Enum Defines ------------------------- */
-/**
- * Mapping Types enum for operators.
- * \note Used by #ANIM_OT_driver_button_add and #UI_OT_eyedropper_driver.
- *
- * XXX: These names need reviewing.
- */
EnumPropertyItem prop_driver_create_mapping_types[] = {
+ /* XXX: These names need reviewing. */
{CREATEDRIVER_MAPPING_1_N,
"SINGLE_MANY",
0,
@@ -920,10 +879,10 @@ EnumPropertyItem prop_driver_create_mapping_types[] = {
};
/* Filtering callback for driver mapping types enum */
-static const EnumPropertyItem *driver_mapping_type_itemsf(bContext *C,
- PointerRNA *UNUSED(owner_ptr),
- PropertyRNA *UNUSED(owner_prop),
- bool *r_free)
+static const EnumPropertyItem *driver_mapping_type_itemf(bContext *C,
+ PointerRNA *UNUSED(owner_ptr),
+ PropertyRNA *UNUSED(owner_prop),
+ bool *r_free)
{
EnumPropertyItem *input = prop_driver_create_mapping_types;
EnumPropertyItem *item = NULL;
@@ -1002,7 +961,7 @@ static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_typ
}
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
if (path) {
@@ -1080,7 +1039,7 @@ static void UNUSED_FUNCTION(ANIM_OT_driver_button_add_menu)(wmOperatorType *ot)
0,
"Mapping Type",
"Method used to match target and driven properties");
- RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf);
+ RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemf);
}
/* Add Driver Button Operator ------------------------ */
@@ -1096,7 +1055,7 @@ static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
/* 1) Create a new "empty" driver for this property */
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
bool changed = false;
@@ -1115,7 +1074,7 @@ static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *
}
/* 2) Show editing panel for setting up this driver */
- /* TODO: Use a different one from the editing popever, so we can have the single/all toggle? */
+ /* TODO: Use a different one from the editing popover, so we can have the single/all toggle? */
UI_popover_panel_invoke(C, "GRAPH_PT_drivers_popover", true, op->reports);
}
@@ -1156,7 +1115,7 @@ static int remove_driver_button_exec(bContext *C, wmOperator *op)
}
if (ptr.owner_id && ptr.data && prop) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
changed = ANIM_remove_driver(op->reports, ptr.owner_id, path, index, 0);
@@ -1241,7 +1200,7 @@ static int copy_driver_button_exec(bContext *C, wmOperator *op)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
/* only copy the driver for the button that this was involved for */
@@ -1285,7 +1244,7 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
/* only copy the driver for the button that this was involved for */
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index 40871fba2be..c4d8484e6a8 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -187,7 +187,7 @@ static PanelType *fmodifier_panel_register(ARegionType *region_type,
/* Give the panel the special flag that says it was built here and corresponds to a
* modifier rather than a #PanelType. */
- panel_type->flag = PANEL_TYPE_HEADER_EXPAND | PANEL_TYPE_DRAW_BOX | PANEL_TYPE_INSTANCED;
+ panel_type->flag = PANEL_TYPE_HEADER_EXPAND | PANEL_TYPE_INSTANCED;
panel_type->reorder = fmodifier_reorder;
panel_type->get_list_data_expand_flag = get_fmodifier_expand_flag;
panel_type->set_list_data_expand_flag = set_fmodifier_expand_flag;
@@ -221,7 +221,7 @@ static PanelType *fmodifier_subpanel_register(ARegionType *region_type,
panel_type->draw_header = draw_header;
panel_type->draw = draw;
panel_type->poll = poll;
- panel_type->flag = PANEL_TYPE_DEFAULT_CLOSED | PANEL_TYPE_DRAW_BOX;
+ panel_type->flag = PANEL_TYPE_DEFAULT_CLOSED;
BLI_assert(parent != NULL);
BLI_strncpy(panel_type->parent_id, parent->idname, BKE_ST_MAXNAME);
@@ -403,10 +403,10 @@ static void generator_panel_draw(const bContext *C, Panel *panel)
char xval[32];
/* The first value gets a "Coefficient" label. */
- BLI_strncpy(xval, "Coefficient", sizeof(xval));
+ BLI_strncpy(xval, N_("Coefficient"), sizeof(xval));
for (int i = 0; i < data->arraysize; i++) {
- uiItemFullR(col, ptr, prop, i, 0, 0, N_(xval), ICON_NONE);
+ uiItemFullR(col, ptr, prop, i, 0, 0, IFACE_(xval), ICON_NONE);
BLI_snprintf(xval, sizeof(xval), "x^%d", i + 1);
}
break;
@@ -420,17 +420,17 @@ static void generator_panel_draw(const bContext *C, Panel *panel)
uiLayoutColumn(split, false);
uiLayout *title_col = uiLayoutColumn(split, false);
uiLayout *title_row = uiLayoutRow(title_col, true);
- uiItemL(title_row, N_("A"), ICON_NONE);
- uiItemL(title_row, N_("B"), ICON_NONE);
+ uiItemL(title_row, IFACE_("A"), ICON_NONE);
+ uiItemL(title_row, IFACE_("B"), ICON_NONE);
}
uiLayout *first_row = uiLayoutRow(col, true);
- uiItemFullR(first_row, ptr, prop, 0, 0, 0, N_("y = (Ax + B)"), ICON_NONE);
+ uiItemFullR(first_row, ptr, prop, 0, 0, 0, IFACE_("y = (Ax + B)"), ICON_NONE);
uiItemFullR(first_row, ptr, prop, 1, 0, 0, "", ICON_NONE);
for (int i = 2; i < data->arraysize - 1; i++) {
/* \u2715 is the multiplication symbol. */
uiLayout *row = uiLayoutRow(col, true);
- uiItemFullR(row, ptr, prop, i, 0, 0, N_("\u2715 (Ax + B)"), ICON_NONE);
+ uiItemFullR(row, ptr, prop, i, 0, 0, IFACE_("\u2715 (Ax + B)"), ICON_NONE);
uiItemFullR(row, ptr, prop, i + 1, 0, 0, "", ICON_NONE);
}
break;
@@ -891,9 +891,6 @@ static void panel_register_stepped(ARegionType *region_type,
/** \name Panel Creation
* \{ */
-/**
- * Checks if the panels match the active strip / curve, rebuilds them if they don't.
- */
void ANIM_fmodifier_panels(const bContext *C,
ID *owner_id,
ListBase *fmodifiers,
@@ -969,17 +966,12 @@ static ListBase fmodifier_copypaste_buf = {NULL, NULL};
/* ---------- */
-/* free the copy/paste buffer */
void ANIM_fmodifiers_copybuf_free(void)
{
/* just free the whole buffer */
free_fmodifiers(&fmodifier_copypaste_buf);
}
-/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
- * assuming that the buffer has been cleared already with ANIM_fmodifiers_copybuf_free()
- * - active: only copy the active modifier
- */
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
{
bool ok = true;
@@ -1009,9 +1001,6 @@ bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
return ok;
}
-/* 'Paste' the F-Modifier(s) from the buffer to the specified list
- * - replace: free all the existing modifiers to leave only the pasted ones
- */
bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, FCurve *curve)
{
FModifier *fcm;
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index e3ea8f0ab21..ae8d04f51d3 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -30,7 +30,6 @@
#include "BLI_dlrbTree.h"
#include "BLI_listbase.h"
#include "BLI_rect.h"
-#include "BLI_task.h"
#include "DNA_anim_types.h"
#include "DNA_gpencil_types.h"
@@ -497,7 +496,7 @@ static void ED_keylist_draw_list_elem_prepare_for_drawing(AnimKeylistDrawListEle
}
typedef struct AnimKeylistDrawList {
- ListBase /* AnimKeylistDrawListElem*/ channels;
+ ListBase /* AnimKeylistDrawListElem */ channels;
} AnimKeylistDrawList;
AnimKeylistDrawList *ED_keylist_draw_list_create(void)
@@ -505,25 +504,12 @@ AnimKeylistDrawList *ED_keylist_draw_list_create(void)
return MEM_callocN(sizeof(AnimKeylistDrawList), __func__);
}
-static void ED_keylist_draw_list_elem_build_task(void *__restrict UNUSED(userdata),
- void *item,
- int UNUSED(index),
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- AnimKeylistDrawListElem *elem = item;
- ED_keylist_draw_list_elem_build_keylist(elem);
- ED_keylist_draw_list_elem_prepare_for_drawing(elem);
-}
-
static void ED_keylist_draw_list_build_keylists(AnimKeylistDrawList *draw_list)
{
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- /* Create a task per item, a single item is complex enough to deserve its own task. */
- settings.min_iter_per_thread = 1;
-
- BLI_task_parallel_listbase(
- &draw_list->channels, NULL, ED_keylist_draw_list_elem_build_task, &settings);
+ LISTBASE_FOREACH (AnimKeylistDrawListElem *, elem, &draw_list->channels) {
+ ED_keylist_draw_list_elem_build_keylist(elem);
+ ED_keylist_draw_list_elem_prepare_for_drawing(elem);
+ }
}
static void ED_keylist_draw_list_draw_blocks(AnimKeylistDrawList *draw_list, View2D *v2d)
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 0923d490110..dfe6566df67 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -67,10 +67,6 @@
/* --------------------------- Base Functions ------------------------------------ */
-/* This function is used to loop over BezTriples in the given F-Curve, applying a given
- * operation on them, and optionally applies an F-Curve validation function afterwards.
- */
-/* TODO: make this function work on samples too. */
short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked,
FCurve *fcu,
KeyframeEditFunc key_ok,
@@ -378,7 +374,6 @@ static short summary_keyframes_loop(KeyframeEditData *ked,
/* --- */
-/* This function is used to apply operation to all keyframes, regardless of the type */
short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
bDopeSheet *ads,
bAnimListElem *ale,
@@ -416,8 +411,6 @@ short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
return 0;
}
-/* This function is used to apply operation to all keyframes,
- * regardless of the type without needed an AnimListElem wrapper */
short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked,
bDopeSheet *ads,
void *data,
@@ -477,8 +470,6 @@ void ANIM_animdata_keyframe_callback(bAnimContext *ac,
/* ************************************************************************** */
/* Keyframe Integrity Tools */
-/* Rearrange keyframes if some are out of order */
-/* used to be recalc_*_ipos() where * was object or action */
void ANIM_editkeyframes_refresh(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
@@ -620,9 +611,6 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/**
- * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso
- */
bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) {
@@ -683,9 +671,6 @@ static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/**
- * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle
- */
bool keyframe_region_circle_test(const KeyframeEdit_CircleData *data_circle, const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
@@ -787,10 +772,6 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
/* ******************************************* */
/* Assorted Utility Functions */
-/**
- * Helper callback for <animeditor>_cfrasnap_exec() ->
- * used to help get the average time of all selected beztriples
- */
short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
{
/* only if selected */
@@ -810,8 +791,6 @@ short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* helper callback for columnselect_<animeditor>_keys() -> populate
- * list CfraElems with frame numbers from selected beztriples */
short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
{
/* only if selected */
@@ -825,9 +804,6 @@ short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* used to remap times from one range to another
- * requires: ked->data = KeyframeEditCD_Remap
- */
void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt)
{
KeyframeEditCD_Remap *rmap = (KeyframeEditCD_Remap *)ked->data;
@@ -1024,8 +1000,6 @@ static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* NOTE: for markers and 'value', the values to use must be supplied as the first float value. */
-/* calchandles_fcurve */
KeyframeEditFunc ANIM_editkeyframes_mirror(short mode)
{
switch (mode) {
@@ -1183,8 +1157,6 @@ static short set_bezier_free(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
return 0;
}
-/* Set all selected Bezier Handles to a single type */
-/* calchandles_fcurve */
KeyframeEditFunc ANIM_editkeyframes_handles(short mode)
{
switch (mode) {
@@ -1311,8 +1283,61 @@ static short set_bezt_sine(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
return 0;
}
-/* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
-/* ANIM_editkeyframes_ipocurve_ipotype() ! */
+static void handle_flatten(float vec[3][3], const int idx, const float direction[2])
+{
+ BLI_assert_msg(idx == 0 || idx == 2, "handle_flatten() expects a handle index");
+
+ add_v2_v2v2(vec[idx], vec[1], direction);
+}
+
+static void handle_set_length(float vec[3][3], const int idx, const float handle_length)
+{
+ BLI_assert_msg(idx == 0 || idx == 2, "handle_set_length() expects a handle index");
+
+ float handle_direction[2];
+ sub_v2_v2v2(handle_direction, vec[idx], vec[1]);
+ normalize_v2_length(handle_direction, handle_length);
+ add_v2_v2v2(vec[idx], vec[1], handle_direction);
+}
+
+void ANIM_fcurve_equalize_keyframes_loop(FCurve *fcu,
+ const eEditKeyframes_Equalize mode,
+ const float handle_length,
+ const bool flatten)
+{
+ uint i;
+ BezTriple *bezt;
+ const float flat_direction_left[2] = {-handle_length, 0.f};
+ const float flat_direction_right[2] = {handle_length, 0.f};
+
+ /* Loop through an F-Curves keyframes. */
+ for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) {
+ if ((bezt->f2 & SELECT) == 0) {
+ continue;
+ }
+
+ /* Perform handle equalization if mode is 'Both' or 'Left'. */
+ if (mode & EQUALIZE_HANDLES_LEFT) {
+ if (flatten) {
+ handle_flatten(bezt->vec, 0, flat_direction_left);
+ }
+ else {
+ handle_set_length(bezt->vec, 0, handle_length);
+ }
+ }
+
+ /* Perform handle equalization if mode is 'Both' or 'Right'. */
+ if (mode & EQUALIZE_HANDLES_RIGHT) {
+ if (flatten) {
+ handle_flatten(bezt->vec, 2, flat_direction_right);
+ }
+ else {
+ handle_set_length(bezt->vec, 2, handle_length);
+ }
+ }
+ }
+}
+
KeyframeEditFunc ANIM_editkeyframes_ipo(short mode)
{
switch (mode) {
@@ -1391,7 +1416,6 @@ static short set_keytype_moving_hold(KeyframeEditData *UNUSED(ked), BezTriple *b
return 0;
}
-/* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
KeyframeEditFunc ANIM_editkeyframes_keytype(short mode)
{
switch (mode) {
@@ -1447,7 +1471,6 @@ static short set_easingtype_easeauto(KeyframeEditData *UNUSED(ked), BezTriple *b
return 0;
}
-/* Set the easing type of the selected BezTriples in each F-Curve to the specified one */
KeyframeEditFunc ANIM_editkeyframes_easing(short mode)
{
switch (mode) {
@@ -1638,7 +1661,6 @@ static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* Get callback for building selection map */
KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
{
switch (mode) {
@@ -1653,7 +1675,6 @@ KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
/* ----------- */
-/* flush selection map values to the given beztriple */
short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt)
{
const char *map = ked->data;
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index ec33a42af3b..92017c02858 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -63,11 +63,6 @@
/* **************************************************** */
-/**
- * Only delete the nominated keyframe from provided F-Curve.
- * Not recommended to be used many times successively. For that
- * there is #delete_fcurve_keys().
- */
void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc)
{
/* sanity check */
@@ -101,7 +96,6 @@ void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc)
}
}
-/* Delete selected keyframes in given F-Curve */
bool delete_fcurve_keys(FCurve *fcu)
{
bool changed = false;
@@ -140,7 +134,6 @@ void clear_fcurve_keys(FCurve *fcu)
/* ---------------- */
-/* duplicate selected keyframes for the given F-Curve */
void duplicate_fcurve_keys(FCurve *fcu)
{
/* this can only work when there is an F-Curve, and also when there are some BezTriples */
@@ -176,10 +169,6 @@ void duplicate_fcurve_keys(FCurve *fcu)
/* **************************************************** */
/* Various Tools */
-/**
- * Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on
- * linear-segments only optionally clears up curve if one keyframe with default value remains.
- */
void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault)
{
FCurve *fcu = (FCurve *)ale->key_data;
@@ -318,6 +307,107 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
}
}
+/**
+ * Find the first segment of consecutive selected curve points, starting from \a start_index.
+ * Keys that have BEZT_FLAG_IGNORE_TAG set are treated as unselected.
+ * \param r_segment_start_idx: returns the start index of the segment.
+ * \param r_segment_len: returns the number of curve points in the segment.
+ * \return whether such a segment was found or not.
+ */
+static bool find_fcurve_segment(FCurve *fcu,
+ const int start_index,
+ int *r_segment_start_idx,
+ int *r_segment_len)
+{
+ *r_segment_start_idx = 0;
+ *r_segment_len = 0;
+
+ bool in_segment = false;
+
+ for (int i = start_index; i < fcu->totvert; i++) {
+ const bool point_is_selected = fcu->bezt[i].f2 & SELECT;
+ const bool point_is_ignored = fcu->bezt[i].f2 & BEZT_FLAG_IGNORE_TAG;
+
+ if (point_is_selected && !point_is_ignored) {
+ if (!in_segment) {
+ *r_segment_start_idx = i;
+ in_segment = true;
+ }
+ (*r_segment_len)++;
+ }
+ else if (in_segment) {
+ /* If the curve point is not selected then we have reached the end of the selected curve
+ * segment. */
+ return true; /* Segment found. */
+ }
+ }
+
+ /* If the last curve point was in the segment, `r_segment_len` and `r_segment_start_idx`
+ * are already updated and true is returned. */
+ return in_segment;
+}
+
+ListBase find_fcurve_segments(FCurve *fcu)
+{
+ ListBase segments = {NULL, NULL};
+ int segment_start_idx = 0;
+ int segment_len = 0;
+ int current_index = 0;
+
+ while (find_fcurve_segment(fcu, current_index, &segment_start_idx, &segment_len)) {
+ FCurveSegment *segment;
+ segment = MEM_callocN(sizeof(*segment), "FCurveSegment");
+ segment->start_index = segment_start_idx;
+ segment->length = segment_len;
+ BLI_addtail(&segments, segment);
+ current_index = segment_start_idx + segment_len;
+ }
+ return segments;
+}
+
+static BezTriple fcurve_segment_start_get(FCurve *fcu, int index)
+{
+ BezTriple start_bezt = index - 1 >= 0 ? fcu->bezt[index - 1] : fcu->bezt[index];
+ return start_bezt;
+}
+
+static BezTriple fcurve_segment_end_get(FCurve *fcu, int index)
+{
+ BezTriple end_bezt = index < fcu->totvert ? fcu->bezt[index] : fcu->bezt[index - 1];
+ return end_bezt;
+}
+
+/* ---------------- */
+
+void blend_to_neighbor_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
+{
+ const float blend_factor = fabs(factor * 2 - 1);
+ BezTriple target_bezt;
+ /* Find which key to blend towards. */
+ if (factor < 0.5f) {
+ target_bezt = fcurve_segment_start_get(fcu, segment->start_index);
+ }
+ else {
+ target_bezt = fcurve_segment_end_get(fcu, segment->start_index + segment->length);
+ }
+ /* Blend each key individually. */
+ for (int i = segment->start_index; i < segment->start_index + segment->length; i++) {
+ fcu->bezt[i].vec[1][1] = interpf(target_bezt.vec[1][1], fcu->bezt[i].vec[1][1], blend_factor);
+ }
+}
+
+/* ---------------- */
+
+void breakdown_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
+{
+ BezTriple left_bezt = fcurve_segment_start_get(fcu, segment->start_index);
+ BezTriple right_bezt = fcurve_segment_end_get(fcu, segment->start_index + segment->length);
+
+ for (int i = segment->start_index; i < segment->start_index + segment->length; i++) {
+ fcu->bezt[i].vec[1][1] = interpf(right_bezt.vec[1][1], left_bezt.vec[1][1], factor);
+ }
+}
+
/* ---------------- */
/* Check if the keyframe interpolation type is supported */
@@ -391,17 +481,9 @@ static void decimate_fcurve_segment(FCurve *fcu,
target_fcurve_verts);
}
-/**
- * F-Curve 'decimate' function that removes a certain ratio of curve
- * points that will affect the curves overall shape the least.
- * If you want to remove based on a error margin, set remove_ratio to 1 and
- * simply specify the desired error_sq_max. Otherwise, set the error margin to
- * FLT_MAX.
- */
bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
{
FCurve *fcu = (FCurve *)ale->key_data;
-
/* Check if the curve actually has any points. */
if (fcu == NULL || fcu->bezt == NULL || fcu->totvert == 0) {
return true;
@@ -409,47 +491,24 @@ bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
BezTriple *old_bezts = fcu->bezt;
- /* Only decimate the individual selected curve segments. */
- int bezt_segment_start_idx = 0;
- int bezt_segment_len = 0;
-
- bool selected;
bool can_decimate_all_selected = true;
- bool in_segment = false;
for (int i = 0; i < fcu->totvert; i++) {
- selected = fcu->bezt[i].f2 & SELECT;
- /* Make sure that the temp flag is unset as we use it to determine what to remove. */
- fcu->bezt[i].f2 &= ~BEZT_FLAG_TEMP_TAG;
-
- if (selected && !prepare_for_decimate(fcu, i)) {
- /* This keyframe is not supported, treat them as if they were unselected. */
- selected = false;
+ /* Ignore keyframes that are not supported. */
+ if (!prepare_for_decimate(fcu, i)) {
can_decimate_all_selected = false;
+ fcu->bezt[i].f2 |= BEZT_FLAG_IGNORE_TAG;
}
-
- if (selected) {
- if (!in_segment) {
- bezt_segment_start_idx = i;
- in_segment = true;
- }
- bezt_segment_len++;
- }
- else if (in_segment) {
- /* If the curve point is not selected then we have reached the end of the selected curve
- * segment. */
- decimate_fcurve_segment(
- fcu, bezt_segment_start_idx, bezt_segment_len, remove_ratio, error_sq_max);
- in_segment = false;
- bezt_segment_len = 0;
- }
+ /* Make sure that the temp flag is unset as we use it to determine what to remove. */
+ fcu->bezt[i].f2 &= ~BEZT_FLAG_TEMP_TAG;
}
- /* Did the segment run to the end of the curve? */
- if (in_segment) {
+ ListBase segments = find_fcurve_segments(fcu);
+ LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
decimate_fcurve_segment(
- fcu, bezt_segment_start_idx, bezt_segment_len, remove_ratio, error_sq_max);
+ fcu, segment->start_index, segment->length, remove_ratio, error_sq_max);
}
+ BLI_freelistN(&segments);
uint old_totvert = fcu->totvert;
fcu->bezt = NULL;
@@ -457,6 +516,7 @@ bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
for (int i = 0; i < old_totvert; i++) {
BezTriple *bezt = (old_bezts + i);
+ bezt->f2 &= ~BEZT_FLAG_IGNORE_TAG;
if ((bezt->f2 & BEZT_FLAG_TEMP_TAG) == 0) {
insert_bezt_fcurve(fcu, bezt, 0);
}
@@ -477,8 +537,6 @@ typedef struct tSmooth_Bezt {
float y1, y2, y3; /* averaged before/new/after y-values */
} tSmooth_Bezt;
-/* Use a weighted moving-means method to reduce intensity of fluctuations */
-/* TODO: introduce scaling factor for weighting falloff */
void smooth_fcurve(FCurve *fcu)
{
int totSel = 0;
@@ -582,7 +640,6 @@ typedef struct TempFrameValCache {
float frame, val;
} TempFrameValCache;
-/* Evaluates the curves between each selected keyframe on each frame, and keys the value. */
void sample_fcurve(FCurve *fcu)
{
BezTriple *bezt, *start = NULL, *end = NULL;
@@ -691,7 +748,6 @@ typedef struct tAnimCopybufItem {
bool is_bone; /* special flag for armature bones */
} tAnimCopybufItem;
-/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ANIM_fcurves_copybuf_free(void)
{
tAnimCopybufItem *aci, *acn;
@@ -722,7 +778,6 @@ void ANIM_fcurves_copybuf_free(void)
/* ------------------- */
-/* This function adds data to the keyframes copy/paste buffer, freeing existing data first */
short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
{
bAnimListElem *ale;
@@ -1081,8 +1136,6 @@ static void paste_animedit_keys_fcurve(
calchandles_fcurve(fcu);
}
-/* ------------------- */
-
const EnumPropertyItem rna_enum_keyframe_paste_offset_items[] = {
{KEYFRAME_PASTE_OFFSET_CFRA_START,
"START",
@@ -1115,11 +1168,6 @@ const EnumPropertyItem rna_enum_keyframe_paste_merge_items[] = {
{0, NULL, 0, NULL, NULL},
};
-/**
- * This function pastes data from the keyframes copy/paste buffer
- *
- * \return Status code is whether the method FAILED to do anything
- */
short paste_animedit_keys(bAnimContext *ac,
ListBase *anim_data,
const eKeyPasteOffset offset_mode,
diff --git a/source/blender/editors/animation/keyframes_keylist.cc b/source/blender/editors/animation/keyframes_keylist.cc
index c1a18196a3a..aba73ec141b 100644
--- a/source/blender/editors/animation/keyframes_keylist.cc
+++ b/source/blender/editors/animation/keyframes_keylist.cc
@@ -80,7 +80,7 @@ struct AnimKeylist {
ListBase /* ActKeyColumn */ key_columns;
/* Last accessed column in the key_columns list base. Inserting columns are typically done in
* order. The last accessed column is used as starting point to search for a location to add or
- * update the next column.*/
+ * update the next column. */
std::optional<ActKeyColumn *> last_accessed_column = std::nullopt;
struct {
@@ -109,7 +109,7 @@ struct AnimKeylist {
#endif
};
-AnimKeylist *ED_keylist_create(void)
+AnimKeylist *ED_keylist_create()
{
AnimKeylist *keylist = new AnimKeylist();
return keylist;
@@ -564,9 +564,9 @@ static void nupdate_ak_masklayshape(ActKeyColumn *ak, void *data)
using KeylistCreateColumnFunction = std::function<ActKeyColumn *(void *userdata)>;
using KeylistUpdateColumnFunction = std::function<void(ActKeyColumn *, void *)>;
-/* `ED_keylist_find_neighbour_front_to_back` is called before the runtime can be initialized so we
+/* `ED_keylist_find_neighbor_front_to_back` is called before the runtime can be initialized so we
* cannot use bin searching. */
-static ActKeyColumn *ED_keylist_find_neighbour_front_to_back(ActKeyColumn *cursor, float cfra)
+static ActKeyColumn *ED_keylist_find_neighbor_front_to_back(ActKeyColumn *cursor, float cfra)
{
while (cursor->next && cursor->next->cfra <= cfra) {
cursor = cursor->next;
@@ -574,9 +574,9 @@ static ActKeyColumn *ED_keylist_find_neighbour_front_to_back(ActKeyColumn *curso
return cursor;
}
-/* `ED_keylist_find_neighbour_back_to_front` is called before the runtime can be initialized so we
+/* `ED_keylist_find_neighbor_back_to_front` is called before the runtime can be initialized so we
* cannot use bin searching. */
-static ActKeyColumn *ED_keylist_find_neighbour_back_to_front(ActKeyColumn *cursor, float cfra)
+static ActKeyColumn *ED_keylist_find_neighbor_back_to_front(ActKeyColumn *cursor, float cfra)
{
while (cursor->prev && cursor->prev->cfra >= cfra) {
cursor = cursor->prev;
@@ -585,14 +585,14 @@ static ActKeyColumn *ED_keylist_find_neighbour_back_to_front(ActKeyColumn *curso
}
/*
- * `ED_keylist_find_exact_or_neighbour_column` is called before the runtime can be initialized so
+ * `ED_keylist_find_exact_or_neighbor_column` is called before the runtime can be initialized so
* we cannot use bin searching.
*
* This function is called to add or update columns in the keylist.
* Typically columns are sorted by frame number so keeping track of the last_accessed_column
* reduces searching.
*/
-static ActKeyColumn *ED_keylist_find_exact_or_neighbour_column(AnimKeylist *keylist, float cfra)
+static ActKeyColumn *ED_keylist_find_exact_or_neighbor_column(AnimKeylist *keylist, float cfra)
{
BLI_assert(!keylist->is_runtime_initialized);
if (ED_keylist_is_empty(keylist)) {
@@ -604,10 +604,10 @@ static ActKeyColumn *ED_keylist_find_exact_or_neighbour_column(AnimKeylist *keyl
if (!is_cfra_eq(cursor->cfra, cfra)) {
const bool walking_direction_front_to_back = cursor->cfra <= cfra;
if (walking_direction_front_to_back) {
- cursor = ED_keylist_find_neighbour_front_to_back(cursor, cfra);
+ cursor = ED_keylist_find_neighbor_front_to_back(cursor, cfra);
}
else {
- cursor = ED_keylist_find_neighbour_back_to_front(cursor, cfra);
+ cursor = ED_keylist_find_neighbor_back_to_front(cursor, cfra);
}
}
@@ -633,7 +633,7 @@ static void ED_keylist_add_or_update_column(AnimKeylist *keylist,
return;
}
- ActKeyColumn *nearest = ED_keylist_find_exact_or_neighbour_column(keylist, cfra);
+ ActKeyColumn *nearest = ED_keylist_find_exact_or_neighbor_column(keylist, cfra);
if (is_cfra_eq(nearest->cfra, cfra)) {
update_func(nearest, userdata);
}
@@ -774,7 +774,7 @@ static void add_bezt_to_keyblocks_list(AnimKeylist *keylist, BezTriple *bezt, co
if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) {
/* Backtrack to find the right location. */
if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) {
- ActKeyColumn *newcol = ED_keylist_find_exact_or_neighbour_column(keylist, col->cfra);
+ ActKeyColumn *newcol = ED_keylist_find_exact_or_neighbor_column(keylist, col->cfra);
BLI_assert(newcol);
BLI_assert(newcol->cfra == col->cfra);
@@ -850,7 +850,6 @@ bool actkeyblock_is_valid(const ActKeyColumn *ac)
return ac != nullptr && ac->next != nullptr && ac->totblock > 0;
}
-/* Checks if ActKeyBlock should exist... */
int actkeyblock_get_valid_hold(const ActKeyColumn *ac)
{
/* check that block is valid */
diff --git a/source/blender/editors/animation/keyframes_keylist_test.cc b/source/blender/editors/animation/keyframes_keylist_test.cc
new file mode 100644
index 00000000000..914693842ca
--- /dev/null
+++ b/source/blender/editors/animation/keyframes_keylist_test.cc
@@ -0,0 +1,144 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "BLI_utildefines.h"
+
+#include "ED_keyframes_keylist.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_curve_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_fcurve.h"
+
+#include <functional>
+#include <optional>
+
+namespace blender::editor::animation::tests {
+
+const float KEYLIST_NEAR_ERROR = 0.1;
+const float FRAME_STEP = 0.005;
+
+static void build_fcurve(FCurve &fcurve)
+{
+ fcurve.totvert = 3;
+ fcurve.bezt = static_cast<BezTriple *>(
+ MEM_callocN(sizeof(BezTriple) * fcurve.totvert, "BezTriples"));
+ fcurve.bezt[0].vec[1][0] = 10.0f;
+ fcurve.bezt[0].vec[1][1] = 1.0f;
+ fcurve.bezt[1].vec[1][0] = 20.0f;
+ fcurve.bezt[1].vec[1][1] = 2.0f;
+ fcurve.bezt[2].vec[1][0] = 30.0f;
+ fcurve.bezt[2].vec[1][1] = 1.0f;
+}
+
+static AnimKeylist *create_test_keylist()
+{
+ FCurve *fcurve = BKE_fcurve_create();
+ build_fcurve(*fcurve);
+
+ AnimKeylist *keylist = ED_keylist_create();
+ fcurve_to_keylist(nullptr, fcurve, keylist, 0);
+ BKE_fcurve_free(fcurve);
+
+ ED_keylist_prepare_for_direct_access(keylist);
+ return keylist;
+}
+
+static void assert_act_key_column(const ActKeyColumn *column,
+ const std::optional<float> expected_frame)
+{
+ if (expected_frame.has_value()) {
+ EXPECT_NE(column, nullptr);
+ EXPECT_NEAR(column->cfra, *expected_frame, KEYLIST_NEAR_ERROR);
+ }
+ else {
+ EXPECT_EQ(column, nullptr);
+ }
+}
+
+using KeylistFindFunction = std::function<const ActKeyColumn *(const AnimKeylist *, float)>;
+
+static float check_keylist_find_range(const AnimKeylist *keylist,
+ KeylistFindFunction keylist_find_func,
+ const float frame_from,
+ const float frame_to,
+ const std::optional<float> expected_frame)
+{
+ float cfra = frame_from;
+ for (; cfra < frame_to; cfra += FRAME_STEP) {
+ const ActKeyColumn *found = keylist_find_func(keylist, cfra);
+ assert_act_key_column(found, expected_frame);
+ }
+ return cfra;
+}
+
+static float check_keylist_find_next_range(const AnimKeylist *keylist,
+ const float frame_from,
+ const float frame_to,
+ const std::optional<float> expected_frame)
+{
+ return check_keylist_find_range(
+ keylist, ED_keylist_find_next, frame_from, frame_to, expected_frame);
+}
+
+TEST(keylist, find_next)
+{
+ AnimKeylist *keylist = create_test_keylist();
+
+ float cfra = check_keylist_find_next_range(keylist, 0.0f, 9.99f, 10.0f);
+ cfra = check_keylist_find_next_range(keylist, cfra, 19.99f, 20.0f);
+ cfra = check_keylist_find_next_range(keylist, cfra, 29.99f, 30.0f);
+ cfra = check_keylist_find_next_range(keylist, cfra, 39.99f, std::nullopt);
+
+ ED_keylist_free(keylist);
+}
+
+static float check_keylist_find_prev_range(const AnimKeylist *keylist,
+ const float frame_from,
+ const float frame_to,
+ const std::optional<float> expected_frame)
+{
+ return check_keylist_find_range(
+ keylist, ED_keylist_find_prev, frame_from, frame_to, expected_frame);
+}
+
+TEST(keylist, find_prev)
+{
+ AnimKeylist *keylist = create_test_keylist();
+
+ float cfra = check_keylist_find_prev_range(keylist, 0.0f, 10.01f, std::nullopt);
+ cfra = check_keylist_find_prev_range(keylist, cfra, 20.01f, 10.0f);
+ cfra = check_keylist_find_prev_range(keylist, cfra, 30.01f, 20.0f);
+ cfra = check_keylist_find_prev_range(keylist, cfra, 49.99f, 30.0f);
+
+ ED_keylist_free(keylist);
+}
+
+static float check_keylist_find_exact_range(const AnimKeylist *keylist,
+ const float frame_from,
+ const float frame_to,
+ const std::optional<float> expected_frame)
+{
+ return check_keylist_find_range(
+ keylist, ED_keylist_find_exact, frame_from, frame_to, expected_frame);
+}
+
+TEST(keylist, find_exact)
+{
+ AnimKeylist *keylist = create_test_keylist();
+
+ float cfra = check_keylist_find_exact_range(keylist, 0.0f, 9.99f, std::nullopt);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 10.01f, 10.0f);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 19.99f, std::nullopt);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 20.01f, 20.0f);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 29.99f, std::nullopt);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 30.01f, 30.0f);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 49.99f, std::nullopt);
+
+ ED_keylist_free(keylist);
+}
+
+} // namespace blender::editor::animation::tests
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 1ef7ee755ea..0a435a9034a 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -35,6 +35,7 @@
#include "BLT_translation.h"
+#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
@@ -90,7 +91,6 @@ static int delete_key_using_keying_set(bContext *C, wmOperator *op, KeyingSet *k
/* ************************************************** */
/* Keyframing Setting Wrangling */
-/* Get the active settings for keyframing settings from context (specifically the given scene) */
eInsertKeyFlags ANIM_get_keyframing_flags(Scene *scene, const bool use_autokey_mode)
{
eInsertKeyFlags flag = INSERTKEY_NOFLAGS;
@@ -132,9 +132,6 @@ eInsertKeyFlags ANIM_get_keyframing_flags(Scene *scene, const bool use_autokey_m
/* ******************************************* */
/* Animation Data Validation */
-/* Get (or add relevant data to be able to do so) the Active Action for the given
- * Animation Data block, given an ID block where the Animation Data should reside.
- */
bAction *ED_id_action_ensure(Main *bmain, ID *id)
{
AnimData *adt;
@@ -176,10 +173,6 @@ bAction *ED_id_action_ensure(Main *bmain, ID *id)
return adt->action;
}
-/**
- * Find the F-Curve from the Active Action,
- * for the given Animation Data block. This assumes that all the destinations are valid.
- */
FCurve *ED_action_fcurve_find(struct bAction *act, const char rna_path[], const int array_index)
{
/* Sanity checks. */
@@ -189,10 +182,6 @@ FCurve *ED_action_fcurve_find(struct bAction *act, const char rna_path[], const
return BKE_fcurve_find(&act->curves, rna_path, array_index);
}
-/**
- * Get (or add relevant data to be able to do so) F-Curve from the Active Action,
- * for the given Animation Data block. This assumes that all the destinations are valid.
- */
FCurve *ED_action_fcurve_ensure(struct Main *bmain,
struct bAction *act,
const char group[],
@@ -294,9 +283,6 @@ static void update_autoflags_fcurve_direct(FCurve *fcu, PropertyRNA *prop)
}
}
-/* Update integer/discrete flags of the FCurve (used when creating/inserting keyframes,
- * but also through RNA when editing an ID prop, see T37103).
- */
void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, PointerRNA *ptr)
{
PointerRNA tmp_ptr;
@@ -375,6 +361,43 @@ static eFCU_Cycle_Type remap_cyclic_keyframe_location(FCurve *fcu, float *px, fl
return type;
}
+/* Used to make curves newly added to a cyclic Action cycle with the correct period. */
+static void make_new_fcurve_cyclic(const bAction *act, FCurve *fcu)
+{
+ /* The curve must contain one (newly-added) keyframe. */
+ if (fcu->totvert != 1 || !fcu->bezt) {
+ return;
+ }
+
+ const float period = act->frame_end - act->frame_start;
+
+ if (period < 0.1f) {
+ return;
+ }
+
+ /* Move the keyframe into the range. */
+ const float frame_offset = fcu->bezt[0].vec[1][0] - act->frame_start;
+ const float fix = floorf(frame_offset / period) * period;
+
+ fcu->bezt[0].vec[0][0] -= fix;
+ fcu->bezt[0].vec[1][0] -= fix;
+ fcu->bezt[0].vec[2][0] -= fix;
+
+ /* Duplicate and offset the keyframe. */
+ fcu->bezt = MEM_reallocN(fcu->bezt, sizeof(BezTriple) * 2);
+ fcu->totvert = 2;
+
+ fcu->bezt[1] = fcu->bezt[0];
+ fcu->bezt[1].vec[0][0] += period;
+ fcu->bezt[1].vec[1][0] += period;
+ fcu->bezt[1].vec[2][0] += period;
+
+ /* Add the cycles modifier. */
+ if (!fcu->modifiers.first) {
+ add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, fcu);
+ }
+}
+
/* -------------- BezTriple Insertion -------------------- */
/* Change the Y position of a keyframe to match the input, adjusting handles. */
@@ -395,13 +418,6 @@ static void replace_bezt_keyframe_ypos(BezTriple *dst, const BezTriple *bezt)
/* TODO: perform some other operations? */
}
-/* This function adds a given BezTriple to an F-Curve. It will allocate
- * memory for the array if needed, and will insert the BezTriple into a
- * suitable place in chronological order.
- *
- * NOTE: any recalculate of the F-Curve that needs to be done will need to
- * be done by the caller.
- */
int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
{
int i = 0;
@@ -425,7 +441,7 @@ int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
if (flag & INSERTKEY_CYCLE_AWARE) {
/* If replacing an end point of a cyclic curve without offset,
* modify the other end too. */
- if ((i == 0 || i == fcu->totvert - 1) &&
+ if (ELEM(i, 0, fcu->totvert - 1) &&
BKE_fcurve_get_cycle_type(fcu) == FCU_CYCLE_PERFECT) {
replace_bezt_keyframe_ypos(&fcu->bezt[i == 0 ? fcu->totvert - 1 : 0], bezt);
}
@@ -537,15 +553,6 @@ static void subdivide_nonauto_handles(const FCurve *fcu,
bezt->h1 = bezt->h2 = HD_ALIGN;
}
-/**
- * This function is a wrapper for #insert_bezt_fcurve(), and should be used when
- * adding a new keyframe to a curve, when the keyframe doesn't exist anywhere else yet.
- * It returns the index at which the keyframe was added.
- *
- * \param keyframe_type: The type of keyframe (#eBezTriple_KeyframeType).
- * \param flag: Optional flags (eInsertKeyFlags) for controlling how keys get added
- * and/or whether updates get done.
- */
int insert_vert_fcurve(
FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag)
{
@@ -573,7 +580,7 @@ int insert_vert_fcurve(
beztr.ipo = BEZT_IPO_BEZ;
}
else {
- /* for UI usage - defaults should come from the userprefs and/or toolsettings */
+ /* For UI usage - defaults should come from the user-preferences and/or tool-settings. */
beztr.h1 = beztr.h2 = U.keyhandles_new; /* use default handle type here */
/* use default interpolation mode, with exceptions for int/discrete values */
@@ -792,12 +799,12 @@ static float *setting_get_rna_values(
int *tmp_int;
if (length > buffer_size) {
- values = MEM_malloc_arrayN(sizeof(float), length, __func__);
+ values = MEM_malloc_arrayN(length, sizeof(float), __func__);
}
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
- tmp_bool = MEM_malloc_arrayN(sizeof(*tmp_bool), length, __func__);
+ tmp_bool = MEM_malloc_arrayN(length, sizeof(*tmp_bool), __func__);
RNA_property_boolean_get_array(ptr, prop, tmp_bool);
for (int i = 0; i < length; i++) {
values[i] = (float)tmp_bool[i];
@@ -805,7 +812,7 @@ static float *setting_get_rna_values(
MEM_freeN(tmp_bool);
break;
case PROP_INT:
- tmp_int = MEM_malloc_arrayN(sizeof(*tmp_int), length, __func__);
+ tmp_int = MEM_malloc_arrayN(length, sizeof(*tmp_int), __func__);
RNA_property_int_get_array(ptr, prop, tmp_int);
for (int i = 0; i < length; i++) {
values[i] = (float)tmp_int[i];
@@ -1235,19 +1242,6 @@ static bool insert_keyframe_value(ReportList *reports,
return insert_vert_fcurve(fcu, cfra, curval, keytype, flag) >= 0;
}
-/* Secondary Keyframing API call:
- * Use this when validation of necessary animation data is not necessary,
- * since an RNA-pointer to the necessary data being keyframed,
- * and a pointer to the F-Curve to use have both been provided.
- *
- * This function can't keyframe quaternion channels on some NLA strip types.
- *
- * keytype is the "keyframe type" (eBezTriple_KeyframeType), as shown in the Dope Sheet.
- *
- * The flag argument is used for special settings that alter the behavior of
- * the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
- * and extra keyframe filtering.
- */
bool insert_keyframe_direct(ReportList *reports,
PointerRNA ptr,
PropertyRNA *prop,
@@ -1352,8 +1346,10 @@ static bool insert_keyframe_fcurve_value(Main *bmain,
/* we may not have a F-Curve when we're replacing only... */
if (fcu) {
+ const bool is_new_curve = (fcu->totvert == 0);
+
/* set color mode if the F-Curve is new (i.e. without any keyframes) */
- if ((fcu->totvert == 0) && (flag & INSERTKEY_XYZ2RGB)) {
+ if (is_new_curve && (flag & INSERTKEY_XYZ2RGB)) {
/* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor,
* is determined by the array index for the F-Curve
*/
@@ -1366,12 +1362,26 @@ static bool insert_keyframe_fcurve_value(Main *bmain,
}
}
+ /* If the curve has only one key, make it cyclic if appropriate. */
+ const bool is_cyclic_action = (flag & INSERTKEY_CYCLE_AWARE) && BKE_action_is_cyclic(act);
+
+ if (is_cyclic_action && fcu->totvert == 1) {
+ make_new_fcurve_cyclic(act, fcu);
+ }
+
/* update F-Curve flags to ensure proper behavior for property type */
update_autoflags_fcurve_direct(fcu, prop);
/* insert keyframe */
- return insert_keyframe_value(
+ const bool success = insert_keyframe_value(
reports, ptr, prop, fcu, anim_eval_context, curval, keytype, flag);
+
+ /* If the curve is new, make it cyclic if appropriate. */
+ if (is_cyclic_action && is_new_curve) {
+ make_new_fcurve_cyclic(act, fcu);
+ }
+
+ return success;
}
return false;
@@ -1399,19 +1409,6 @@ static AnimationEvalContext nla_time_remap(const AnimationEvalContext *anim_eval
return *anim_eval_context;
}
-/**
- * Main Keyframing API call
- *
- * Use this when validation of necessary animation data is necessary, since it may not exist yet.
- *
- * The flag argument is used for special settings that alter the behavior of
- * the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
- * and extra keyframe filtering.
- *
- * index of -1 keys all array indices
- *
- * \return The number of key-frames inserted.
- */
int insert_keyframe(Main *bmain,
ReportList *reports,
ID *id,
@@ -1638,9 +1635,6 @@ static void deg_tag_after_keyframe_delete(Main *bmain, ID *id, AnimData *adt)
}
}
-/**
- * \return The number of key-frames deleted.
- */
int delete_keyframe(Main *bmain,
ReportList *reports,
ID *id,
@@ -1879,6 +1873,7 @@ static int insert_key_exec(bContext *C, wmOperator *op)
float cfra = (float)CFRA; /* XXX for now, don't bother about all the yucky offset crap */
int num_channels;
+ const bool confirm = op->flag & OP_IS_INVOKE;
KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene);
if (ks == NULL) {
@@ -1915,20 +1910,22 @@ static int insert_key_exec(bContext *C, wmOperator *op)
}
if (num_channels > 0) {
- /* if the appropriate properties have been set, make a note that we've inserted something */
- if (RNA_boolean_get(op->ptr, "confirm_success")) {
+ /* send notifiers that keyframes have been changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
+ }
+
+ if (confirm) {
+ /* if called by invoke (from the UI), make a note that we've inserted keyframes */
+ if (num_channels > 0) {
BKE_reportf(op->reports,
RPT_INFO,
"Successfully added %d keyframes for keying set '%s'",
num_channels,
ks->name);
}
-
- /* send notifiers that keyframes have been changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
- }
- else {
- BKE_report(op->reports, RPT_WARNING, "Keying set failed to insert any keyframes");
+ else {
+ BKE_report(op->reports, RPT_WARNING, "Keying set failed to insert any keyframes");
+ }
}
return OPERATOR_FINISHED;
@@ -1957,19 +1954,8 @@ void ANIM_OT_keyframe_insert(wmOperatorType *ot)
RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf);
RNA_def_property_flag(prop, PROP_HIDDEN);
ot->prop = prop;
-
- /* confirm whether a keyframe was added by showing a popup
- * - by default, this is enabled, since this operator is assumed to be called independently
- */
- prop = RNA_def_boolean(ot->srna,
- "confirm_success",
- 1,
- "Confirm Successful Insert",
- "Show a popup when the keyframes get successfully added");
- RNA_def_property_flag(prop, PROP_HIDDEN);
}
-/* Clone of 'ANIM_OT_keyframe_insert' which uses a name for the keying set instead of an enum. */
void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -1990,16 +1976,6 @@ void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot)
prop = RNA_def_string_file_path(ot->srna, "type", "Type", MAX_ID_NAME - 2, "", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
ot->prop = prop;
-
- /* confirm whether a keyframe was added by showing a popup
- * - by default, this is enabled, since this operator is assumed to be called independently
- */
- prop = RNA_def_boolean(ot->srna,
- "confirm_success",
- 1,
- "Confirm Successful Insert",
- "Show a popup when the keyframes get successfully added");
- RNA_def_property_flag(prop, PROP_HIDDEN);
}
/* Insert Key Operator (With Menu) ------------------------ */
@@ -2027,8 +2003,6 @@ static int insert_key_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UN
/* just call the exec() on the active keyingset */
RNA_enum_set(op->ptr, "type", 0);
- RNA_boolean_set(op->ptr, "confirm_success", true);
-
return op->type->exec(C, op);
}
@@ -2057,17 +2031,6 @@ void ANIM_OT_keyframe_insert_menu(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
ot->prop = prop;
- /* confirm whether a keyframe was added by showing a popup
- * - by default, this is disabled so that if a menu is shown, this doesn't come up too
- */
- /* XXX should this just be always on? */
- prop = RNA_def_boolean(ot->srna,
- "confirm_success",
- 0,
- "Confirm Successful Insert",
- "Show a popup when the keyframes get successfully added");
- RNA_def_property_flag(prop, PROP_HIDDEN);
-
/* whether the menu should always be shown
* - by default, the menu should only be shown when there is no active Keying Set (2.5 behavior),
* although in some cases it might be useful to always shown (pre 2.5 behavior)
@@ -2094,6 +2057,7 @@ static int delete_key_using_keying_set(bContext *C, wmOperator *op, KeyingSet *k
Scene *scene = CTX_data_scene(C);
float cfra = (float)CFRA; /* XXX for now, don't bother about all the yucky offset crap */
int num_channels;
+ const bool confirm = op->flag & OP_IS_INVOKE;
/* try to delete keyframes for the channels specified by KeyingSet */
num_channels = ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_DELETE, cfra);
@@ -2107,26 +2071,23 @@ static int delete_key_using_keying_set(bContext *C, wmOperator *op, KeyingSet *k
return OPERATOR_CANCELLED;
}
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, "confirm_success");
- bool confirm = (prop != NULL && RNA_property_boolean_get(op->ptr, prop));
-
if (num_channels > 0) {
- /* if the appropriate properties have been set, make a note that we've inserted something */
- if (confirm) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL);
+ }
+
+ if (confirm) {
+ /* if called by invoke (from the UI), make a note that we've removed keyframes */
+ if (num_channels > 0) {
BKE_reportf(op->reports,
RPT_INFO,
"Successfully removed %d keyframes for keying set '%s'",
num_channels,
ks->name);
}
-
- /* send notifiers that keyframes have been changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL);
- }
- else if (confirm) {
- BKE_report(op->reports, RPT_WARNING, "Keying set failed to remove any keyframes");
+ else {
+ BKE_report(op->reports, RPT_WARNING, "Keying set failed to remove any keyframes");
+ }
}
-
return OPERATOR_FINISHED;
}
@@ -2153,15 +2114,6 @@ void ANIM_OT_keyframe_delete(wmOperatorType *ot)
RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf);
RNA_def_property_flag(prop, PROP_HIDDEN);
ot->prop = prop;
-
- /* confirm whether a keyframe was added by showing a popup
- * - by default, this is enabled, since this operator is assumed to be called independently
- */
- RNA_def_boolean(ot->srna,
- "confirm_success",
- 1,
- "Confirm Successful Delete",
- "Show a popup when the keyframes get successfully removed");
}
void ANIM_OT_keyframe_delete_by_name(wmOperatorType *ot)
@@ -2184,15 +2136,6 @@ void ANIM_OT_keyframe_delete_by_name(wmOperatorType *ot)
prop = RNA_def_string_file_path(ot->srna, "type", "Type", MAX_ID_NAME - 2, "", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
ot->prop = prop;
-
- /* confirm whether a keyframe was added by showing a popup
- * - by default, this is enabled, since this operator is assumed to be called independently
- */
- RNA_def_boolean(ot->srna,
- "confirm_success",
- 1,
- "Confirm Successful Delete",
- "Show a popup when the keyframes get successfully removed");
}
/* Delete Key Operator ------------------------ */
@@ -2291,7 +2234,7 @@ static int delete_key_v3d_without_keying_set(bContext *C, wmOperator *op)
int selected_objects_success_len = 0;
int success_multi = 0;
- bool confirm = op->flag & OP_IS_INVOKE;
+ const bool confirm = op->flag & OP_IS_INVOKE;
CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
ID *id = &ob->id;
@@ -2372,21 +2315,24 @@ static int delete_key_v3d_without_keying_set(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- /* report success (or failure) */
if (selected_objects_success_len) {
- if (confirm) {
+ /* send updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL);
+ }
+
+ if (confirm) {
+ /* if called by invoke (from the UI), make a note that we've removed keyframes */
+ if (selected_objects_success_len) {
BKE_reportf(op->reports,
RPT_INFO,
"%d object(s) successfully had %d keyframes removed",
selected_objects_success_len,
success_multi);
}
- /* send updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL);
- }
- else if (confirm) {
- BKE_reportf(
- op->reports, RPT_ERROR, "No keyframes removed from %d object(s)", selected_objects_len);
+ else {
+ BKE_reportf(
+ op->reports, RPT_ERROR, "No keyframes removed from %d object(s)", selected_objects_len);
+ }
}
return OPERATOR_FINISHED;
}
@@ -2804,7 +2750,6 @@ bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
/* --------------- API/Per-Datablock Handling ------------------- */
-/* Checks if some F-Curve has a keyframe for a given frame */
bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame, short filter)
{
/* quick sanity check */
@@ -2831,7 +2776,6 @@ bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame, short filter)
return false;
}
-/* Returns whether the current value of a given property differs from the interpolated value. */
bool fcurve_is_changed(PointerRNA ptr,
PropertyRNA *prop,
FCurve *fcu,
@@ -2960,7 +2904,6 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter)
/* --------------- API ------------------- */
-/* Checks whether a keyframe exists for the given ID-block one the given frame */
bool id_frame_has_keyframe(ID *id, float frame, short filter)
{
/* sanity checks */
@@ -3036,9 +2979,6 @@ bool ED_autokeyframe_pchan(
return false;
}
-/**
- * Use for auto-keyframing from the UI.
- */
bool ED_autokeyframe_property(
bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra)
{
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index e1fd3b07f46..59bb60d8fa0 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -529,12 +529,10 @@ void ANIM_OT_keying_set_active_set(wmOperatorType *ot)
/* Keying Set Type Info declarations */
static ListBase keyingset_type_infos = {NULL, NULL};
-/* Built-In Keying Sets (referencing type information). */
ListBase builtin_keyingsets = {NULL, NULL};
/* --------------- */
-/* Find KeyingSet type info given a name. */
KeyingSetInfo *ANIM_keyingset_info_find_name(const char name[])
{
/* sanity checks */
@@ -546,7 +544,6 @@ KeyingSetInfo *ANIM_keyingset_info_find_name(const char name[])
return BLI_findstring(&keyingset_type_infos, name, offsetof(KeyingSetInfo, idname));
}
-/* Find builtin KeyingSet by name. */
KeyingSet *ANIM_builtin_keyingset_get_named(KeyingSet *prevKS, const char name[])
{
KeyingSet *ks, *first = NULL;
@@ -582,8 +579,6 @@ KeyingSet *ANIM_builtin_keyingset_get_named(KeyingSet *prevKS, const char name[]
/* --------------- */
-/* Add the given KeyingSetInfo to the list of type infos,
- * and create an appropriate builtin set too. */
void ANIM_keyingset_info_register(KeyingSetInfo *ksi)
{
KeyingSet *ks;
@@ -603,8 +598,6 @@ void ANIM_keyingset_info_register(KeyingSetInfo *ksi)
BLI_addtail(&keyingset_type_infos, ksi);
}
-/* Remove the given KeyingSetInfo from the list of type infos,
- * and also remove the builtin set if appropriate. */
void ANIM_keyingset_info_unregister(Main *bmain, KeyingSetInfo *ksi)
{
KeyingSet *ks, *ksn;
@@ -633,8 +626,6 @@ void ANIM_keyingset_info_unregister(Main *bmain, KeyingSetInfo *ksi)
BLI_freelinkN(&keyingset_type_infos, ksi);
}
-/* --------------- */
-
void ANIM_keyingset_infos_exit(void)
{
KeyingSetInfo *ksi, *next;
@@ -654,7 +645,6 @@ void ANIM_keyingset_infos_exit(void)
BKE_keyingsets_free(&builtin_keyingsets);
}
-/* Check if the ID appears in the paths specified by the KeyingSet */
bool ANIM_keyingset_find_id(KeyingSet *ks, ID *id)
{
/* sanity checks */
@@ -670,7 +660,6 @@ bool ANIM_keyingset_find_id(KeyingSet *ks, ID *id)
/* Getters for Active/Indices ----------------------------- */
-/* Get the active Keying Set for the Scene provided */
KeyingSet *ANIM_scene_get_active_keyingset(const Scene *scene)
{
/* if no scene, we've got no hope of finding the Keying Set */
@@ -689,7 +678,6 @@ KeyingSet *ANIM_scene_get_active_keyingset(const Scene *scene)
return BLI_findlink(&builtin_keyingsets, (-scene->active_keyingset) - 1);
}
-/* Get the index of the Keying Set provided, for the given Scene */
int ANIM_scene_get_keyingset_index(Scene *scene, KeyingSet *ks)
{
int index;
@@ -721,7 +709,6 @@ int ANIM_scene_get_keyingset_index(Scene *scene, KeyingSet *ks)
return 0;
}
-/* Get Keying Set to use for Auto-Keyframing some transforms */
KeyingSet *ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *transformKSName)
{
/* get KeyingSet to use
@@ -739,7 +726,6 @@ KeyingSet *ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *tra
/* Menu of All Keying Sets ----------------------------- */
-/* Dynamically populate an enum of Keying Sets */
const EnumPropertyItem *ANIM_keying_sets_enum_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -808,14 +794,6 @@ const EnumPropertyItem *ANIM_keying_sets_enum_itemf(bContext *C,
return item;
}
-/**
- * Get the keying set from enum values generated in #ANIM_keying_sets_enum_itemf.
- *
- * Type is the Keying Set the user specified to use when calling the operator:
- * - type == 0: use scene's active Keying Set
- * - type > 0: use a user-defined Keying Set from the active scene
- * - type < 0: use a builtin Keying Set
- */
KeyingSet *ANIM_keyingset_get_from_enum_type(Scene *scene, int type)
{
KeyingSet *ks = NULL;
@@ -847,7 +825,6 @@ KeyingSet *ANIM_keyingset_get_from_idname(Scene *scene, const char *idname)
/* Polling API ----------------------------------------------- */
-/* Check if KeyingSet can be used in the current context */
bool ANIM_keyingset_context_ok_poll(bContext *C, KeyingSet *ks)
{
if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
@@ -894,7 +871,6 @@ static void RKS_ITER_overrides_list(KeyingSetInfo *ksi,
}
}
-/* Add new data source for relative Keying Sets */
void ANIM_relative_keyingset_add_source(ListBase *dsources, ID *id, StructRNA *srna, void *data)
{
tRKS_DSource *ds;
@@ -925,14 +901,6 @@ void ANIM_relative_keyingset_add_source(ListBase *dsources, ID *id, StructRNA *s
/* KeyingSet Operations (Insert/Delete Keyframes) ------------ */
-/**
- * Given a KeyingSet and context info, validate Keying Set's paths.
- * This is only really necessary with relative/built-in KeyingSets
- * where their list of paths is dynamically generated based on the
- * current context info.
- *
- * Returns 0 if succeeded, otherwise an error code: eModifyKey_Returns
- */
eModifyKey_Returns ANIM_validate_keyingset(bContext *C, ListBase *dsources, KeyingSet *ks)
{
/* sanity check */
@@ -1017,14 +985,6 @@ static eInsertKeyFlags keyingset_apply_keying_flags(const eInsertKeyFlags base_f
return result;
}
-/**
- * Given a KeyingSet and context info (if required),
- * modify keyframes for the channels specified by the KeyingSet.
- * This takes into account many of the different combinations of using KeyingSets.
- *
- * \returns the number of channels that key-frames were added or
- * an #eModifyKey_Returns value (always a negative number).
- */
int ANIM_apply_keyingset(
bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra)
{
diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c
index b0eb014c5d9..2ddaa2c415e 100644
--- a/source/blender/editors/animation/time_scrub_ui.c
+++ b/source/blender/editors/animation/time_scrub_ui.c
@@ -101,6 +101,7 @@ static void draw_current_frame(const Scene *scene,
float text_width = UI_fontstyle_string_width(fstyle, frame_str);
float box_width = MAX2(text_width + 8 * UI_DPI_FAC, 24 * UI_DPI_FAC);
float box_padding = 3 * UI_DPI_FAC;
+ const int line_outline = max_ii(1, round_fl_to_int(1 * UI_DPI_FAC));
float bg_color[4];
UI_GetThemeColorShade4fv(TH_CFRAME, -5, bg_color);
@@ -109,7 +110,19 @@ static void draw_current_frame(const Scene *scene,
const float subframe_x = UI_view2d_view_to_region_x(v2d, BKE_scene_ctime_get(scene));
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ GPU_blend(GPU_BLEND_ALPHA);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ /* Outline. */
+ immUniformThemeColorShadeAlpha(TH_BACK, -25, -100);
+ immRectf(pos,
+ subframe_x - (line_outline + U.pixelsize),
+ scrub_region_rect->ymax - box_padding,
+ subframe_x + (line_outline + U.pixelsize),
+ 0.0f);
+
+ /* Line. */
immUniformThemeColor(TH_CFRAME);
immRectf(pos,
subframe_x - U.pixelsize,
@@ -117,6 +130,7 @@ static void draw_current_frame(const Scene *scene,
subframe_x + U.pixelsize,
0.0f);
immUnbindProgram();
+ GPU_blend(GPU_BLEND_NONE);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
@@ -194,7 +208,7 @@ bool ED_time_scrub_event_in_region(const ARegion *region, const wmEvent *event)
{
rcti rect = region->winrct;
rect.ymin = rect.ymax - UI_TIME_SCRUB_MARGIN_Y;
- return BLI_rcti_isect_pt(&rect, event->x, event->y);
+ return BLI_rcti_isect_pt_v(&rect, event->xy);
}
void ED_time_scrub_channel_search_draw(const bContext *C, ARegion *region, bDopeSheet *dopesheet)
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 21a5c6c2865..02ecfdb4ea6 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -64,8 +64,6 @@
/* *************** Adding stuff in editmode *************** */
-/* default bone add, returns it selected, but without tail set */
-/* XXX should be used everywhere, now it mallocs bones still locally in functions */
EditBone *ED_armature_ebone_add(bArmature *arm, const char *name)
{
EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone");
@@ -274,7 +272,6 @@ void ARMATURE_OT_click_extrude(wmOperatorType *ot)
/* props */
}
-/* adds an EditBone between the nominated locations (should be in the right space) */
EditBone *add_points_bone(Object *obedit, float head[3], float tail[3])
{
EditBone *ebo;
@@ -302,7 +299,6 @@ static EditBone *get_named_editbone(ListBase *edbo, const char *name)
return NULL;
}
-/* Call this before doing any duplications. */
void preEditBoneDuplicate(ListBase *editbones)
{
/* clear temp */
@@ -1317,9 +1313,10 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* following conventions from #MESH_OT_symmetrize */
void ARMATURE_OT_symmetrize(wmOperatorType *ot)
{
+ /* NOTE: following conventions from #MESH_OT_symmetrize */
+
/* subset of 'rna_enum_symmetrize_direction_items' */
static const EnumPropertyItem arm_symmetrize_direction_items[] = {
{-1, "NEGATIVE_X", 0, "-X to +X", ""},
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index fd5ae6c7099..b709980cabe 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -66,9 +66,6 @@
/* NOTE: these functions are exported to the Object module to be called from the tools there */
-/**
- * See #BKE_armature_transform for object-mode transform.
- */
void ED_armature_edit_transform(bArmature *arm, const float mat[4][4], const bool do_props)
{
EditBone *ebone;
@@ -116,8 +113,6 @@ void ED_armature_transform(bArmature *arm, const float mat[4][4], const bool do_
}
}
-/* exported for use in editors/object/ */
-/* 0 == do center, 1 == center new, 2 == center cursor */
void ED_armature_origin_set(
Main *bmain, Object *ob, const float cursor[3], int centermode, int around)
{
@@ -186,9 +181,6 @@ void ED_armature_origin_set(
/** \name Bone Roll Calculate Operator
* \{ */
-/* adjust bone roll to align Z axis with vector
- * vec is in local space and is normalized
- */
float ED_armature_ebone_roll_to_vector(const EditBone *bone,
const float align_axis[3],
const bool axis_only)
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 696355324e6..252cf806e34 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -39,8 +39,10 @@ struct bArmature;
struct LinkData;
struct ListBase;
-/* ******************************************************* */
-/* Armature EditMode Operators */
+/* -------------------------------------------------------------------- */
+/** \name Armature EditMode Operators
+ * \{ */
+
void ARMATURE_OT_bone_primitive_add(struct wmOperatorType *ot);
void ARMATURE_OT_align(struct wmOperatorType *ot);
@@ -82,8 +84,12 @@ void ARMATURE_OT_layers_show_all(struct wmOperatorType *ot);
void ARMATURE_OT_armature_layers(struct wmOperatorType *ot);
void ARMATURE_OT_bone_layers(struct wmOperatorType *ot);
-/* ******************************************************* */
-/* Pose-Mode Operators */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pose-Mode Operators
+ * \{ */
+
void POSE_OT_hide(struct wmOperatorType *ot);
void POSE_OT_reveal(struct wmOperatorType *ot);
@@ -131,8 +137,12 @@ void POSE_OT_quaternions_flip(struct wmOperatorType *ot);
void POSE_OT_bone_layers(struct wmOperatorType *ot);
-/* ******************************************************* */
-/* Pose Tool Utilities (for PoseLib, Pose Sliding, etc.) */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pose Tool Utilities (for PoseLib, Pose Sliding, etc.)
+ * \{ */
+
/* pose_utils.c */
/* Temporary data linking PoseChannels with the F-Curves they affect */
@@ -173,21 +183,39 @@ typedef struct tPChanFCurveLink {
/* ----------- */
+/** Returns a valid pose armature for this object, else returns NULL. */
struct Object *poseAnim_object_get(struct Object *ob_);
+/** Get sets of F-Curves providing transforms for the bones in the Pose. */
void poseAnim_mapping_get(struct bContext *C, ListBase *pfLinks);
+/** Free F-Curve <-> PoseChannel links. */
void poseAnim_mapping_free(ListBase *pfLinks);
+/**
+ * Helper for apply() / reset() - refresh the data.
+ */
void poseAnim_mapping_refresh(struct bContext *C, struct Scene *scene, struct Object *ob);
+/**
+ * Reset changes made to current pose.
+ */
void poseAnim_mapping_reset(ListBase *pfLinks);
+/** Perform auto-key-framing after changes were made + confirmed. */
void poseAnim_mapping_autoKeyframe(struct bContext *C,
struct Scene *scene,
ListBase *pfLinks,
float cframe);
+/**
+ * Find the next F-Curve for a PoseChannel with matching path...
+ * - path is not just the pfl rna_path, since that path doesn't have property info yet.
+ */
LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, const char *path);
-/* ******************************************************* */
-/* PoseLib */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name PoseLib
+ * \{ */
+
/* pose_lib.c */
void POSELIB_OT_new(struct wmOperatorType *ot);
@@ -207,8 +235,12 @@ void POSELIB_OT_apply_pose(struct wmOperatorType *ot);
void POSELIB_OT_apply_pose_asset(struct wmOperatorType *ot);
void POSELIB_OT_blend_pose_asset(struct wmOperatorType *ot);
-/* ******************************************************* */
-/* Pose Sliding Tools */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pose Sliding Tools
+ * \{ */
+
/* pose_slide.c */
void POSE_OT_push(struct wmOperatorType *ot);
@@ -216,12 +248,15 @@ void POSE_OT_relax(struct wmOperatorType *ot);
void POSE_OT_push_rest(struct wmOperatorType *ot);
void POSE_OT_relax_rest(struct wmOperatorType *ot);
void POSE_OT_breakdown(struct wmOperatorType *ot);
-void POSE_OT_blend_to_neighbours(struct wmOperatorType *ot);
+void POSE_OT_blend_to_neighbors(struct wmOperatorType *ot);
void POSE_OT_propagate(struct wmOperatorType *ot);
-/* ******************************************************* */
-/* Various Armature Edit/Pose Editing API's */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Various Armature Edit/Pose Editing API's
+ * \{ */
/* Ideally, many of these defines would not be needed as everything would be strictly
* self-contained within each file,
@@ -232,7 +267,9 @@ struct EditBone *make_boneList(struct ListBase *edbo,
struct ListBase *bones,
struct Bone *actBone);
-/* duplicate method */
+/* Duplicate method. */
+
+/** Call this before doing any duplications. */
void preEditBoneDuplicate(struct ListBase *editbones);
void postEditBoneDuplicate(struct ListBase *editbones, struct Object *ob);
struct EditBone *duplicateEditBone(struct EditBone *cur_bone,
@@ -240,22 +277,37 @@ struct EditBone *duplicateEditBone(struct EditBone *cur_bone,
struct ListBase *editbones,
struct Object *ob);
-/* duplicate method (cross objects) */
-/* editbones is the target list */
+/* Duplicate method (cross objects). */
+
+/**
+ * \param editbones: The target list.
+ */
struct EditBone *duplicateEditBoneObjects(struct EditBone *cur_bone,
const char *name,
struct ListBase *editbones,
struct Object *src_ob,
struct Object *dst_ob);
+/** Adds an EditBone between the nominated locations (should be in the right space). */
struct EditBone *add_points_bone(struct Object *obedit, float head[3], float tail[3]);
void bone_free(struct bArmature *arm, struct EditBone *bone);
void armature_tag_select_mirrored(struct bArmature *arm);
-void armature_select_mirrored_ex(struct bArmature *arm, const int flag);
+/**
+ * Helper function for tools to work on mirrored parts.
+ * it leaves mirrored bones selected then too, which is a good indication of what happened.
+ */
+void armature_select_mirrored_ex(struct bArmature *arm, int flag);
void armature_select_mirrored(struct bArmature *arm);
+/** Only works when tagged. */
void armature_tag_unselect(struct bArmature *arm);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Selection Picking
+ * \{ */
+
struct EditBone *ED_armature_pick_ebone(struct bContext *C,
const int xy[2],
bool findunsel,
@@ -291,7 +343,19 @@ struct Bone *ED_armature_pick_bone_from_selectbuffer(struct Base **bases,
bool do_nearest,
struct Base **r_base);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Iteration
+ * \{ */
+
+/**
+ * XXX: bone_looper is only to be used when we want to access settings
+ * (i.e. editability/visibility/selected) that context doesn't offer.
+ */
int bone_looper(struct Object *ob,
struct Bone *bone,
void *data,
int (*bone_func)(struct Object *, struct Bone *, void *));
+
+/** \} */
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 35bd30377c8..750c64d74a7 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -80,7 +80,6 @@ static bool editbone_unique_check(void *arg, const char *name)
return dupli && dupli != data->bone;
}
-/* If bone is already in list, pass it as param to ignore it. */
void ED_armature_ebone_unique_name(ListBase *ebones, char *name, EditBone *bone)
{
struct {
@@ -154,9 +153,6 @@ static void constraint_bone_name_fix(Object *ob,
}
}
-/* called by UI for renaming a bone */
-/* warning: make sure the original bone was not renamed yet! */
-/* seems messy, but that's what you get with not using pointers but channel names :) */
void ED_armature_bone_rename(Main *bmain,
bArmature *arm,
const char *oldnamep,
@@ -265,10 +261,11 @@ void ED_armature_bone_rename(Main *bmain,
}
}
- if (BKE_modifiers_uses_armature(ob, arm)) {
+ if (BKE_modifiers_uses_armature(ob, arm) && BKE_object_supports_vertex_groups(ob)) {
bDeformGroup *dg = BKE_object_defgroup_find_name(ob, oldname);
if (dg) {
BLI_strncpy(dg->name, newname, MAXBONENAME);
+ DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
}
}
@@ -325,6 +322,7 @@ void ED_armature_bone_rename(Main *bmain,
bDeformGroup *dg = BKE_object_defgroup_find_name(ob, oldname);
if (dg) {
BLI_strncpy(dg->name, newname, MAXBONENAME);
+ DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
}
}
break;
@@ -393,16 +391,6 @@ typedef struct BoneFlipNameData {
char name_flip[MAXBONENAME];
} BoneFlipNameData;
-/**
- * Renames (by flipping) all selected bones at once.
- *
- * This way if we are flipping related bones (e.g., Bone.L, Bone.R) at the same time
- * all the bones are safely renamed, without conflicting with each other.
- *
- * \param arm: Armature the bones belong to
- * \param bones_names: List of BoneConflict elems.
- * \param do_strip_numbers: if set, try to get rid of dot-numbers at end of bone names.
- */
void ED_armature_bones_flip_names(Main *bmain,
bArmature *arm,
ListBase *bones_names,
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index a1070a8823a..364e778fc2e 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -33,9 +33,10 @@
/* ************************** registration **********************************/
-/* Both operators ARMATURE_OT_xxx and POSE_OT_xxx here */
void ED_operatortypes_armature(void)
{
+ /* Both operators `ARMATURE_OT_*` and `POSE_OT_*` are registered here. */
+
/* EDIT ARMATURE */
WM_operatortype_append(ARMATURE_OT_bone_primitive_add);
@@ -150,7 +151,7 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(POSE_OT_push_rest);
WM_operatortype_append(POSE_OT_relax_rest);
WM_operatortype_append(POSE_OT_breakdown);
- WM_operatortype_append(POSE_OT_blend_to_neighbours);
+ WM_operatortype_append(POSE_OT_blend_to_neighbors);
}
void ED_operatormacros_armature(void)
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 32fd1c9ad41..eebe8a447f7 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -269,7 +269,6 @@ static void joined_armature_fix_links(
}
}
-/* join armature exec is exported for use in object->join objects operator... */
int ED_armature_join_objects_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -745,6 +744,10 @@ void ARMATURE_OT_separate(wmOperatorType *ot)
#define ARM_PAR_CONNECT 1
#define ARM_PAR_OFFSET 2
+/* armature un-parenting options */
+#define ARM_PAR_CLEAR 1
+#define ARM_PAR_CLEAR_DISCONNECT 2
+
/* check for null, before calling! */
static void bone_connect_to_existing_parent(EditBone *bone)
{
@@ -904,19 +907,29 @@ static int armature_parent_set_invoke(bContext *C,
wmOperator *UNUSED(op),
const wmEvent *UNUSED(event))
{
- bool all_childbones = false;
+ /* False when all selected bones are parented to the active bone. */
+ bool enable_offset = false;
+ /* False when all selected bones are connected to the active bone. */
+ bool enable_connect = false;
{
Object *ob = CTX_data_edit_object(C);
bArmature *arm = ob->data;
EditBone *actbone = arm->act_edbone;
LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
- if (EBONE_EDITABLE(ebone) && (ebone->flag & BONE_SELECTED)) {
- if (ebone != actbone) {
- if (ebone->parent != actbone) {
- all_childbones = true;
- break;
- }
- }
+ if (!EBONE_EDITABLE(ebone) || !(ebone->flag & BONE_SELECTED)) {
+ continue;
+ }
+ if (ebone == actbone) {
+ continue;
+ }
+
+ if (ebone->parent != actbone) {
+ enable_offset = true;
+ enable_connect = true;
+ break;
+ }
+ if (!(ebone->flag & BONE_CONNECTED)) {
+ enable_connect = true;
}
}
}
@@ -924,11 +937,14 @@ static int armature_parent_set_invoke(bContext *C,
uiPopupMenu *pup = UI_popup_menu_begin(
C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE);
uiLayout *layout = UI_popup_menu_layout(pup);
- uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT);
- if (all_childbones) {
- /* Object becomes parent, make the associated menus. */
- uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET);
- }
+
+ uiLayout *row_offset = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(row_offset, enable_offset);
+ uiItemEnumO(row_offset, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET);
+
+ uiLayout *row_connect = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(row_connect, enable_connect);
+ uiItemEnumO(row_connect, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT);
UI_popup_menu_end(C, pup);
@@ -955,8 +971,8 @@ void ARMATURE_OT_parent_set(wmOperatorType *ot)
}
static const EnumPropertyItem prop_editarm_clear_parent_types[] = {
- {1, "CLEAR", 0, "Clear Parent", ""},
- {2, "DISCONNECT", 0, "Disconnect Bone", ""},
+ {ARM_PAR_CLEAR, "CLEAR", 0, "Clear Parent", ""},
+ {ARM_PAR_CLEAR_DISCONNECT, "DISCONNECT", 0, "Disconnect Bone", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -1012,6 +1028,51 @@ static int armature_parent_clear_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static int armature_parent_clear_invoke(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *UNUSED(event))
+{
+ /* False when no selected bones are connected to the active bone. */
+ bool enable_disconnect = false;
+ /* False when no selected bones are parented to the active bone. */
+ bool enable_clear = false;
+ {
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm = ob->data;
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
+ if (!EBONE_EDITABLE(ebone) || !(ebone->flag & BONE_SELECTED)) {
+ continue;
+ }
+ if (ebone->parent == NULL) {
+ continue;
+ }
+ enable_clear = true;
+
+ if (ebone->flag & BONE_CONNECTED) {
+ enable_disconnect = true;
+ break;
+ }
+ }
+ }
+
+ uiPopupMenu *pup = UI_popup_menu_begin(
+ C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Parent"), ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+
+ uiLayout *row_clear = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(row_clear, enable_clear);
+ uiItemEnumO(row_clear, "ARMATURE_OT_parent_clear", NULL, 0, "type", ARM_PAR_CLEAR);
+
+ uiLayout *row_disconnect = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(row_disconnect, enable_disconnect);
+ uiItemEnumO(
+ row_disconnect, "ARMATURE_OT_parent_clear", NULL, 0, "type", ARM_PAR_CLEAR_DISCONNECT);
+
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
void ARMATURE_OT_parent_clear(wmOperatorType *ot)
{
/* identifiers */
@@ -1021,7 +1082,7 @@ void ARMATURE_OT_parent_clear(wmOperatorType *ot)
"Remove the parent-child relationship between selected bones and their parents";
/* api callbacks */
- ot->invoke = WM_menu_invoke;
+ ot->invoke = armature_parent_clear_invoke;
ot->exec = armature_parent_clear_exec;
ot->poll = ED_operator_editarmature;
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index bd799c00373..5e4cb813064 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -139,7 +139,6 @@ Base *ED_armature_base_and_pchan_from_select_buffer(Base **bases,
return base;
}
-/* For callers that don't need the pose channel. */
Base *ED_armature_base_and_bone_from_select_buffer(Base **bases,
uint bases_len,
int hit,
@@ -673,11 +672,7 @@ static EditBone *get_nearest_editbonepoint(
}
if (use_cycle) {
- static int last_mval[2] = {-100, -100};
- if ((len_manhattan_v2v2_int(vc->mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) == 0) {
- use_cycle = false;
- }
- copy_v2_v2_int(last_mval, vc->mval);
+ use_cycle = !WM_cursor_test_motion_and_update(vc->mval);
}
const bool do_nearest = !(XRAY_ACTIVE(vc->v3d) || use_cycle);
@@ -1084,7 +1079,6 @@ bool ED_armature_edit_select_pick_bone(bContext *C,
return true;
}
-/* context: editmode armature in view3d */
bool ED_armature_edit_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
@@ -1179,18 +1173,6 @@ static bool armature_edit_select_op_apply(bArmature *arm,
return changed;
}
-/**
- * Perform a selection operation on elements which have been 'touched',
- * use for lasso & border select but can be used elsewhere too.
- *
- * Tagging is done via #EditBone.temp.i using: #BONESEL_ROOT, #BONESEL_TIP, #BONESEL_BONE
- * And optionally ignoring end-points using the #BONESEL_ROOT, #BONESEL_TIP right shifted 16 bits.
- * (used when the values are clipped outside the view).
- *
- * \param sel_op: #eSelectOp type.
- *
- * \note Visibility checks must be done by the caller.
- */
bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
{
bool changed = false;
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 4fe4422e4e0..1c48285563d 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -45,10 +45,10 @@
#include "armature_intern.h"
-/* *************************************************************** */
-/* Validation */
+/* -------------------------------------------------------------------- */
+/** \name Validation
+ * \{ */
-/* Sync selection to parent for connected children */
void ED_armature_edit_sync_selection(ListBase *edbo)
{
EditBone *ebo;
@@ -86,10 +86,6 @@ void ED_armature_edit_validate_active(struct bArmature *arm)
}
}
-/* Update the layers_used variable after bones are moved between layer
- * NOTE: Used to be done in drawing code in 2.7, but that won't work with
- * Copy-on-Write, as drawing uses evaluated copies.
- */
void ED_armature_edit_refresh_layer_used(bArmature *arm)
{
arm->layer_used = 0;
@@ -98,11 +94,12 @@ void ED_armature_edit_refresh_layer_used(bArmature *arm)
}
}
-/* *************************************************************** */
-/* Bone Operations */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Operations
+ * \{ */
-/* XXX bone_looper is only to be used when we want to access settings
- * (i.e. editability/visibility/selected) that context doesn't offer */
int bone_looper(Object *ob, Bone *bone, void *data, int (*bone_func)(Object *, Bone *, void *))
{
/* We want to apply the function bone_func to every bone
@@ -129,8 +126,11 @@ int bone_looper(Object *ob, Bone *bone, void *data, int (*bone_func)(Object *, B
return count;
}
-/* *************************************************************** */
-/* Bone Removal */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Removal
+ * \{ */
void bone_free(bArmature *arm, EditBone *bone)
{
@@ -155,9 +155,6 @@ void bone_free(bArmature *arm, EditBone *bone)
BLI_freelinkN(arm->edbo, bone);
}
-/**
- * \param clear_connected: When false caller is responsible for keeping the flag in a valid state.
- */
void ED_armature_ebone_remove_ex(bArmature *arm, EditBone *exBone, bool clear_connected)
{
EditBone *curBone;
@@ -190,13 +187,6 @@ bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebon
return false;
}
-/**
- * Finds the first parent shared by \a ebone_child
- *
- * \param ebone_child: Children bones to search
- * \param ebone_child_tot: Size of the ebone_child array
- * \return The shared parent or NULL.
- */
EditBone *ED_armature_ebone_find_shared_parent(EditBone *ebone_child[], const uint ebone_child_tot)
{
#define EBONE_TEMP_UINT(ebone) (*((uint *)(&((ebone)->temp))))
@@ -284,20 +274,17 @@ void ED_armature_ebone_from_mat4(EditBone *ebone, const float mat[4][4])
ED_armature_ebone_from_mat3(ebone, mat3);
}
-/**
- * Return a pointer to the bone of the given name
- */
EditBone *ED_armature_ebone_find_name(const ListBase *edbo, const char *name)
{
return BLI_findstring(edbo, name, offsetof(EditBone, name));
}
-/* *************************************************************** */
-/* Mirroring */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mirroring
+ * \{ */
-/**
- * \see #BKE_pose_channel_get_mirrored (pose-mode, matching function)
- */
EditBone *ED_armature_ebone_get_mirrored(const ListBase *edbo, EditBone *ebo)
{
char name_flip[MAXBONENAME];
@@ -317,8 +304,6 @@ EditBone *ED_armature_ebone_get_mirrored(const ListBase *edbo, EditBone *ebo)
/* ------------------------------------- */
-/* helper function for tools to work on mirrored parts.
- * it leaves mirrored bones selected then too, which is a good indication of what happened */
void armature_select_mirrored_ex(bArmature *arm, const int flag)
{
BLI_assert((flag & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) == 0);
@@ -375,7 +360,6 @@ void armature_tag_select_mirrored(bArmature *arm)
}
}
-/* only works when tagged */
void armature_tag_unselect(bArmature *arm)
{
EditBone *curBone;
@@ -465,8 +449,6 @@ void ED_armature_ebone_transform_mirror_update(bArmature *arm, EditBone *ebo, bo
}
}
-/* if editbone (partial) selected, copy data */
-/* context; editmode armature, with mirror editing enabled */
void ED_armature_edit_transform_mirror_update(Object *obedit)
{
bArmature *arm = obedit->data;
@@ -475,8 +457,11 @@ void ED_armature_edit_transform_mirror_update(Object *obedit)
}
}
-/* *************************************************************** */
-/* Armature EditMode Conversions */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Armature EditMode Conversions
+ * \{ */
/* converts Bones to EditBone list, used for tools as well */
static EditBone *make_boneList_recursive(ListBase *edbo,
@@ -688,7 +673,6 @@ static void armature_finalize_restpose(ListBase *bonelist, ListBase *editbonelis
}
}
-/* put EditMode back in Object */
void ED_armature_from_edit(Main *bmain, bArmature *arm)
{
EditBone *eBone, *neBone;
@@ -838,7 +822,6 @@ void ED_armature_edit_free(struct bArmature *arm)
}
}
-/* Put armature in EditMode */
void ED_armature_to_edit(bArmature *arm)
{
ED_armature_edit_free(arm);
@@ -846,10 +829,11 @@ void ED_armature_to_edit(bArmature *arm)
arm->act_edbone = make_boneList(arm->edbo, &arm->bonebase, arm->act_bone);
}
-/* *************************************************************** */
-/* Used by Undo for Armature EditMode. */
+/** \} */
-/* free's bones and their properties */
+/* -------------------------------------------------------------------- */
+/** \name Used by Undo for Armature EditMode
+ * \{ */
void ED_armature_ebone_listbase_free(ListBase *lb, const bool do_id_user)
{
@@ -908,10 +892,14 @@ void ED_armature_ebone_listbase_temp_clear(ListBase *lb)
}
}
-/* *************************************************************** */
-/* Low level selection functions which hide connected-parent
- * flag behavior which gets tricky to handle in selection operators.
- * (no flushing in ED_armature_ebone_select.*, that should be explicit) */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Low Level Selection Functions
+ *
+ * which hide connected-parent flag behavior which gets tricky to handle in selection operators.
+ * (no flushing in `ED_armature_ebone_select.*`, that should be explicit).
+ * \{ */
int ED_armature_ebone_selectflag_get(const EditBone *ebone)
{
@@ -964,3 +952,5 @@ void ED_armature_ebone_select_set(EditBone *ebone, bool select)
}
ED_armature_ebone_selectflag_set(ebone, flag);
}
+
+/** \} */
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index 832e75b2a8b..9117dfe892f 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -244,7 +244,6 @@ static void armature_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_armature_undosys_type(UndoType *ut)
{
ut->name = "Edit Armature";
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 990e7589d9d..787d7cbaab0 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -1618,8 +1618,7 @@ static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBin
mdb->cagemesh_cache.mpoly = me->mpoly;
mdb->cagemesh_cache.mloop = me->mloop;
mdb->cagemesh_cache.looptri = BKE_mesh_runtime_looptri_ensure(me);
- /* can be NULL */
- mdb->cagemesh_cache.poly_nors = CustomData_get_layer(&me->pdata, CD_NORMAL);
+ mdb->cagemesh_cache.poly_nors = BKE_mesh_poly_normals_ensure(me);
}
/* make bounding box equal size in all directions, add padding, and compute
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 20d7baa39ed..8bd6c9f54fd 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -72,9 +72,10 @@
# include "PIL_time_utildefines.h"
#endif
-/* matches logic with ED_operator_posemode_context() */
Object *ED_pose_object_from_context(bContext *C)
{
+ /* NOTE: matches logic with #ED_operator_posemode_context(). */
+
ScrArea *area = CTX_wm_area(C);
Object *ob;
@@ -90,7 +91,6 @@ Object *ED_pose_object_from_context(bContext *C)
return ob;
}
-/* This function is used to process the necessary updates for */
bool ED_object_posemode_enter_ex(struct Main *bmain, Object *ob)
{
BLI_assert(!ID_IS_LINKED(ob));
@@ -160,7 +160,7 @@ static bool pose_has_protected_selected(Object *ob, short warn)
bArmature *arm = ob->data;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone && (pchan->bone->layer & arm->layer)) {
+ if (pchan->bone && BKE_pose_is_layer_visible(arm, pchan)) {
if (pchan->bone->layer & arm->layer_protected) {
if (pchan->bone->flag & BONE_SELECTED) {
break;
@@ -195,11 +195,6 @@ static eAnimvizCalcRange pose_path_convert_range(ePosePathCalcRange range)
return ANIMVIZ_CALC_RANGE_FULL;
}
-/* For the object with pose/action: update paths for those that have got them
- * This should selectively update paths that exist...
- *
- * To be called from various tools that do incremental updates
- */
void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, ePosePathCalcRange range)
{
/* Transform doesn't always have context available to do update. */
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 646356e7a45..dc96c777be0 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -1070,7 +1070,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld,
else if (pchan->bone) {
/* only ok if bone is visible and selected */
if ((pchan->bone->flag & BONE_SELECTED) && (pchan->bone->flag & BONE_HIDDEN_P) == 0 &&
- (pchan->bone->layer & arm->layer)) {
+ BKE_pose_is_layer_visible(arm, pchan)) {
ok = 1;
}
}
diff --git a/source/blender/editors/armature/pose_lib_2.c b/source/blender/editors/armature/pose_lib_2.c
index 91a5dc67a21..e7cbde0b239 100644
--- a/source/blender/editors/armature/pose_lib_2.c
+++ b/source/blender/editors/armature/pose_lib_2.c
@@ -25,6 +25,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_math.h"
#include "BLI_string.h"
#include "BLT_translation.h"
@@ -209,11 +210,11 @@ static void poselib_slide_mouse_update_blendfactor(PoseBlendData *pbd, const wmE
if (pbd->release_confirm_info.use_release_confirm) {
/* Release confirm calculates factor based on where the dragging was started from. */
const float range = 300 * U.pixelsize;
- const float new_factor = (event->x - pbd->release_confirm_info.drag_start_xy[0]) / range;
+ const float new_factor = (event->xy[0] - pbd->release_confirm_info.drag_start_xy[0]) / range;
poselib_blend_set_factor(pbd, new_factor);
}
else {
- const float new_factor = (event->x - pbd->area->v1->vec.x) / ((float)pbd->area->winx);
+ const float new_factor = (event->xy[0] - pbd->area->v1->vec.x) / ((float)pbd->area->winx);
poselib_blend_set_factor(pbd, new_factor);
}
}
@@ -379,8 +380,7 @@ static bool poselib_blend_init_data(bContext *C, wmOperator *op, const wmEvent *
if (pbd->release_confirm_info.use_release_confirm) {
BLI_assert(event != NULL);
- pbd->release_confirm_info.drag_start_xy[0] = event->x;
- pbd->release_confirm_info.drag_start_xy[1] = event->y;
+ copy_v2_v2_int(pbd->release_confirm_info.drag_start_xy, event->xy);
pbd->release_confirm_info.init_event_type = WM_userdef_event_type_from_keymap_type(
event->type);
}
@@ -562,7 +562,7 @@ static bool poselib_blend_poll(bContext *C)
void POSELIB_OT_apply_pose_asset(wmOperatorType *ot)
{
/* Identifiers: */
- ot->name = "Apply Pose Library Pose";
+ ot->name = "Apply Pose Asset";
ot->idname = "POSELIB_OT_apply_pose_asset";
ot->description = "Apply the given Pose Action to the rig";
@@ -595,7 +595,7 @@ void POSELIB_OT_blend_pose_asset(wmOperatorType *ot)
PropertyRNA *prop;
/* Identifiers: */
- ot->name = "Blend Pose Library Pose";
+ ot->name = "Blend Pose Asset";
ot->idname = "POSELIB_OT_blend_pose_asset";
ot->description = "Blend the given Pose Action to the rig";
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index e5b8983af93..0b889149f9d 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -108,7 +108,6 @@ void ED_pose_bone_select_tag_update(Object *ob)
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
}
-/* Utility method for changing the selection status of a bone */
void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
{
bArmature *arm;
@@ -238,10 +237,6 @@ void ED_armature_pose_select_pick_bone(ViewLayer *view_layer,
}
}
-/**
- * Called for mode-less pose selection.
- * assumes the active object is still on old situation.
- */
bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
View3D *v3d,
Base *base,
@@ -269,14 +264,6 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
return nearBone != NULL;
}
-/**
- * While in weight-paint mode, a single pose may be active as well.
- * While not common, it's possible we have multiple armatures deforming a mesh.
- *
- * This function de-selects all other objects, and selects the new base.
- * It can't be set to the active object because we need
- * to keep this set to the weight paint object.
- */
void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_select)
{
BLI_assert(base_select && (base_select->object->type == OB_ARMATURE));
@@ -323,9 +310,6 @@ void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_se
}
}
-/* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT.
- * When true, 'ignore_visibility' makes this func also affect invisible bones
- * (hidden or on hidden layers). */
bool ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibility)
{
bArmature *arm = ob->data;
@@ -762,7 +746,7 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
bool changed = false;
- pchan_act = BKE_pose_channel_active(ob);
+ pchan_act = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan_act == NULL) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index b273d3aac76..42211d847ff 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -613,11 +613,8 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
float quat_final[4];
/* Perform blending. */
- if (pso->mode == POSESLIDE_BREAKDOWN) {
- /* Just perform the interpolation between quat_prev and
- * quat_next using pso->factor as a guide. */
- float quat_prev[4];
- float quat_next[4];
+ if (ELEM(pso->mode, POSESLIDE_BREAKDOWN, POSESLIDE_PUSH, POSESLIDE_RELAX)) {
+ float quat_prev[4], quat_next[4];
quat_prev[0] = evaluate_fcurve(fcu_w, prevFrameF);
quat_prev[1] = evaluate_fcurve(fcu_x, prevFrameF);
@@ -632,29 +629,29 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
normalize_qt(quat_prev);
normalize_qt(quat_next);
- interp_qt_qtqt(quat_final, quat_prev, quat_next, ED_slider_factor_get(pso->slider));
- }
- else if (pso->mode == POSESLIDE_PUSH || pso->mode == POSESLIDE_RELAX) {
- float quat_breakdown[4];
- float quat_curr[4];
+ if (pso->mode == POSESLIDE_BREAKDOWN) {
+ /* Just perform the interpolation between quat_prev and
+ * quat_next using pso->factor as a guide. */
+ interp_qt_qtqt(quat_final, quat_prev, quat_next, ED_slider_factor_get(pso->slider));
+ }
+ else {
+ float quat_curr[4], quat_breakdown[4];
- copy_qt_qt(quat_curr, pchan->quat);
+ normalize_qt_qt(quat_curr, pchan->quat);
- quat_breakdown[0] = evaluate_fcurve(fcu_w, cframe);
- quat_breakdown[1] = evaluate_fcurve(fcu_x, cframe);
- quat_breakdown[2] = evaluate_fcurve(fcu_y, cframe);
- quat_breakdown[3] = evaluate_fcurve(fcu_z, cframe);
+ /* Compute breakdown based on actual frame range. */
+ const float factor = (cframe - pso->prevFrame) / (float)(pso->nextFrame - pso->prevFrame);
- normalize_qt(quat_breakdown);
- normalize_qt(quat_curr);
+ interp_qt_qtqt(quat_breakdown, quat_prev, quat_next, factor);
- if (pso->mode == POSESLIDE_PUSH) {
- interp_qt_qtqt(
- quat_final, quat_breakdown, quat_curr, 1.0f + ED_slider_factor_get(pso->slider));
- }
- else {
- BLI_assert(pso->mode == POSESLIDE_RELAX);
- interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, ED_slider_factor_get(pso->slider));
+ if (pso->mode == POSESLIDE_PUSH) {
+ interp_qt_qtqt(
+ quat_final, quat_breakdown, quat_curr, 1.0f + ED_slider_factor_get(pso->slider));
+ }
+ else {
+ BLI_assert(pso->mode == POSESLIDE_RELAX);
+ interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, ED_slider_factor_get(pso->slider));
+ }
}
}
else if (pso->mode == POSESLIDE_BLEND) {
@@ -914,7 +911,7 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
strcpy(mode_str, TIP_("Breakdown"));
break;
case POSESLIDE_BLEND:
- strcpy(mode_str, TIP_("Blend To Neighbour"));
+ strcpy(mode_str, TIP_("Blend To Neighbor"));
break;
default:
@@ -1042,7 +1039,7 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, const wmEvent *
const ActKeyColumn *nk = ED_keylist_find_next(pso->keylist, cframe);
/* New set the frames. */
- /* Prev frame. */
+ /* Previous frame. */
pso->prevFrame = (pk) ? (pk->cfra) : (pso->cframe - 1);
RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
/* Next frame. */
@@ -1051,7 +1048,7 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, const wmEvent *
}
else {
/* Current frame itself is a keyframe, so just take keyframes on either side. */
- /* Prev frame. */
+ /* Previous frame. */
pso->prevFrame = (ak->prev) ? (ak->prev->cfra) : (pso->cframe - 1);
RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
/* Next frame. */
@@ -1709,7 +1706,7 @@ void POSE_OT_breakdown(wmOperatorType *ot)
}
/* ........................ */
-static int pose_slide_blend_to_neighbours_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int pose_slide_blend_to_neighbors_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
/* Initialize data. */
if (pose_slide_init(C, op, POSESLIDE_BLEND) == 0) {
@@ -1721,7 +1718,7 @@ static int pose_slide_blend_to_neighbours_invoke(bContext *C, wmOperator *op, co
return pose_slide_invoke_common(C, op, event);
}
-static int pose_slide_blend_to_neighbours_exec(bContext *C, wmOperator *op)
+static int pose_slide_blend_to_neighbors_exec(bContext *C, wmOperator *op)
{
tPoseSlideOp *pso;
@@ -1737,16 +1734,16 @@ static int pose_slide_blend_to_neighbours_exec(bContext *C, wmOperator *op)
return pose_slide_exec_common(C, op, pso);
}
-void POSE_OT_blend_to_neighbours(wmOperatorType *ot)
+void POSE_OT_blend_to_neighbors(wmOperatorType *ot)
{
/* Identifiers. */
- ot->name = "Blend To Neighbour";
- ot->idname = "POSE_OT_blend_to_neighbour";
+ ot->name = "Blend To Neighbor";
+ ot->idname = "POSE_OT_blend_to_neighbor";
ot->description = "Blend from current position to previous or next keyframe";
/* Callbacks. */
- ot->exec = pose_slide_blend_to_neighbours_exec;
- ot->invoke = pose_slide_blend_to_neighbours_invoke;
+ ot->exec = pose_slide_blend_to_neighbors_exec;
+ ot->invoke = pose_slide_blend_to_neighbors_invoke;
ot->modal = pose_slide_modal;
ot->cancel = pose_slide_cancel;
ot->poll = ED_operator_posemode;
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 3798ca308ed..7c52e4fafdd 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -787,7 +787,7 @@ static int pose_copy_exec(bContext *C, wmOperator *op)
* any datablock expansion?
*/
Main *temp_bmain = BKE_main_new();
- STRNCPY(temp_bmain->name, BKE_main_blendfile_path_from_global());
+ STRNCPY(temp_bmain->filepath, BKE_main_blendfile_path_from_global());
Object ob_copy = *ob;
ob_copy.adt = NULL;
@@ -797,13 +797,13 @@ static int pose_copy_exec(bContext *C, wmOperator *op)
BLI_addtail(&temp_bmain->objects, &ob_copy);
BLI_addtail(&temp_bmain->armatures, &arm_copy);
/* begin copy buffer on a temp bmain. */
- BKE_copybuffer_begin(temp_bmain);
+ BKE_copybuffer_copy_begin(temp_bmain);
/* Store the whole object to the copy buffer because pose can't be
* existing on its own.
*/
- BKE_copybuffer_tag_ID(&ob_copy.id);
+ BKE_copybuffer_copy_tag_ID(&ob_copy.id);
BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend");
- BKE_copybuffer_save(temp_bmain, str, op->reports);
+ BKE_copybuffer_copy_end(temp_bmain, str, op->reports);
/* We clear the lists so no datablocks gets freed,
* This is required because objects in temp bmain shares same pointers
* as the real ones.
@@ -856,7 +856,7 @@ static int pose_paste_exec(bContext *C, wmOperator *op)
/* Read copy buffer .blend file. */
char str[FILE_MAX];
Main *tmp_bmain = BKE_main_new();
- STRNCPY(tmp_bmain->name, BKE_main_blendfile_path_from_global());
+ STRNCPY(tmp_bmain->filepath, BKE_main_blendfile_path_from_global());
BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend");
if (!BKE_copybuffer_read(tmp_bmain, str, op->reports, FILTER_ID_OB)) {
@@ -1184,7 +1184,7 @@ static int pose_clear_transform_generic_exec(bContext *C,
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob_iter) {
- /* XXX: UGLY HACK (for autokey + clear transforms) */
+ /* XXX: UGLY HACK (for auto-key + clear transforms). */
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter);
ListBase dsources = {NULL, NULL};
bool changed = false;
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index 500b9663a6c..19a5348dbc0 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -132,9 +132,6 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks,
}
}
-/**
- * Returns a valid pose armature for this object, else returns NULL.
- */
Object *poseAnim_object_get(Object *ob_)
{
Object *ob = BKE_object_pose_armature_get(ob_);
@@ -144,9 +141,6 @@ Object *poseAnim_object_get(Object *ob_)
return NULL;
}
-/**
- * Get sets of F-Curves providing transforms for the bones in the Pose.
- */
void poseAnim_mapping_get(bContext *C, ListBase *pfLinks)
{
/* for each Pose-Channel which gets affected, get the F-Curves for that channel
@@ -192,7 +186,6 @@ void poseAnim_mapping_get(bContext *C, ListBase *pfLinks)
}
}
-/* Free F-Curve <-> PoseChannel links. */
void poseAnim_mapping_free(ListBase *pfLinks)
{
tPChanFCurveLink *pfl, *pfln = NULL;
@@ -219,7 +212,6 @@ void poseAnim_mapping_free(ListBase *pfLinks)
/* ------------------------- */
-/* helper for apply() / reset() - refresh the data */
void poseAnim_mapping_refresh(bContext *C, Scene *UNUSED(scene), Object *ob)
{
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
@@ -231,7 +223,6 @@ void poseAnim_mapping_refresh(bContext *C, Scene *UNUSED(scene), Object *ob)
}
}
-/* reset changes made to current pose */
void poseAnim_mapping_reset(ListBase *pfLinks)
{
tPChanFCurveLink *pfl;
@@ -268,7 +259,6 @@ void poseAnim_mapping_reset(ListBase *pfLinks)
}
}
-/* perform auto-key-framing after changes were made + confirmed */
void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks, float cframe)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -337,9 +327,6 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks,
/* ------------------------- */
-/* find the next F-Curve for a PoseChannel with matching path...
- * - path is not just the pfl rna_path, since that path doesn't have property info yet
- */
LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, const char *path)
{
LinkData *first = (prev) ? prev->next : (fcuLinks) ? fcuLinks->first : NULL;
diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt
index 31c07580570..086fab4ab47 100644
--- a/source/blender/editors/asset/CMakeLists.txt
+++ b/source/blender/editors/asset/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/clog
../../../../intern/guardedalloc
)
@@ -31,22 +32,29 @@ set(INC_SYS
)
set(SRC
+ intern/asset_catalog.cc
intern/asset_filter.cc
intern/asset_handle.cc
+ intern/asset_indexer.cc
intern/asset_library_reference.cc
intern/asset_library_reference_enum.cc
intern/asset_list.cc
intern/asset_mark_clear.cc
intern/asset_ops.cc
intern/asset_temp_id_consumer.cc
+ intern/asset_type.cc
+ ED_asset_catalog.h
+ ED_asset_catalog.hh
ED_asset_filter.h
ED_asset_handle.h
+ ED_asset_indexer.h
ED_asset_library.h
ED_asset_list.h
ED_asset_list.hh
ED_asset_mark_clear.h
ED_asset_temp_id_consumer.h
+ ED_asset_type.h
intern/asset_library_reference.hh
)
diff --git a/source/blender/editors/asset/ED_asset_catalog.h b/source/blender/editors/asset/ED_asset_catalog.h
new file mode 100644
index 00000000000..acb0b67d9c0
--- /dev/null
+++ b/source/blender/editors/asset/ED_asset_catalog.h
@@ -0,0 +1,41 @@
+/*
+ * 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 edasset
+ *
+ * Supplement for `ED_asset_catalog.hh`. Part of the same API but usable in C.
+ */
+
+#pragma once
+
+#include "BLI_utildefines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AssetLibrary;
+struct Main;
+
+void ED_asset_catalogs_save_from_main_path(struct AssetLibrary *library, const struct Main *bmain);
+
+void ED_asset_catalogs_set_save_catalogs_when_file_is_saved(bool should_save);
+bool ED_asset_catalogs_get_save_catalogs_when_file_is_saved(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/asset/ED_asset_catalog.hh b/source/blender/editors/asset/ED_asset_catalog.hh
new file mode 100644
index 00000000000..d4df15561d0
--- /dev/null
+++ b/source/blender/editors/asset/ED_asset_catalog.hh
@@ -0,0 +1,61 @@
+/*
+ * 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 edasset
+ *
+ * UI/Editor level API for catalog operations, creating richer functionality than the BKE catalog
+ * API provides (which this uses internally).
+ *
+ * Note that `ED_asset_catalog.h` is part of this API.
+ */
+
+#pragma once
+
+#include <optional>
+
+#include "BKE_asset_catalog.hh"
+
+#include "BLI_string_ref.hh"
+
+struct AssetLibrary;
+namespace blender::bke {
+class AssetCatalog;
+} // namespace blender::bke
+
+blender::bke::AssetCatalog *ED_asset_catalog_add(AssetLibrary *library,
+ blender::StringRefNull name,
+ blender::StringRef parent_path = nullptr);
+void ED_asset_catalog_remove(AssetLibrary *library, const blender::bke::CatalogID &catalog_id);
+
+void ED_asset_catalog_rename(AssetLibrary *library,
+ blender::bke::CatalogID catalog_id,
+ blender::StringRefNull new_name);
+/**
+ * Reinsert catalog identified by \a src_catalog_id as child to catalog identified by \a
+ * dst_parent_catalog_id. If \a dst_parent_catalog_id is not set, the catalog is moved to the root
+ * level of the tree.
+ * The name of the reinserted catalog is made unique within the parent. Note that moving a catalog
+ * to the same level it was before will also change its name, since the name uniqueness check isn't
+ * smart enough to ignore the item to be reinserted. So the caller is expected to handle this case
+ * to avoid unwanted renames.
+ *
+ * Nothing is done (debug builds run into an assert) if the given catalog IDs can't be identified.
+ */
+void ED_asset_catalog_move(
+ AssetLibrary *library,
+ blender::bke::CatalogID src_catalog_id,
+ std::optional<blender::bke::CatalogID> dst_parent_catalog_id = std::nullopt);
diff --git a/source/blender/editors/asset/ED_asset_filter.h b/source/blender/editors/asset/ED_asset_filter.h
index 340c4c9dbe7..3b92baea117 100644
--- a/source/blender/editors/asset/ED_asset_filter.h
+++ b/source/blender/editors/asset/ED_asset_filter.h
@@ -16,6 +16,8 @@
/** \file
* \ingroup edasset
+ *
+ * Functions for filtering assets.
*/
#pragma once
@@ -27,6 +29,18 @@ extern "C" {
struct AssetFilterSettings;
struct AssetHandle;
+/**
+ * Compare \a asset against the settings of \a filter.
+ *
+ * Individual filter parameters are ORed with the asset properties. That means:
+ * * The asset type must be one of the ID types filtered by, and
+ * * The asset must contain at least one of the tags filtered by.
+ * However for an asset to be matching it must have one match in each of the parameters. I.e. one
+ * matching type __and__ at least one matching tag.
+ *
+ * \returns True if the asset should be visible with these filter settings (parameters match).
+ * Otherwise returns false (mismatch).
+ */
bool ED_asset_filter_matches_asset(const struct AssetFilterSettings *filter,
const struct AssetHandle *asset);
diff --git a/source/blender/editors/asset/ED_asset_handle.h b/source/blender/editors/asset/ED_asset_handle.h
index efb99410d3d..dce851164a5 100644
--- a/source/blender/editors/asset/ED_asset_handle.h
+++ b/source/blender/editors/asset/ED_asset_handle.h
@@ -16,6 +16,12 @@
/** \file
* \ingroup edasset
+ *
+ * Asset-handle is a temporary design, not part of the core asset system design.
+ *
+ * Currently asset-list items are just file directory items (#FileDirEntry). So an asset-handle
+ * just wraps a pointer to this. We try to abstract away the fact that it's just a file entry,
+ * although that doesn't always work (see #rna_def_asset_handle()).
*/
#pragma once
diff --git a/source/blender/editors/asset/ED_asset_indexer.h b/source/blender/editors/asset/ED_asset_indexer.h
new file mode 100644
index 00000000000..33558d8cda5
--- /dev/null
+++ b/source/blender/editors/asset/ED_asset_indexer.h
@@ -0,0 +1,50 @@
+/*
+ * 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 edasset
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ED_file_indexer.h"
+
+/**
+ * File Indexer Service for indexing asset files.
+ *
+ * Opening and parsing a large collection of asset files inside a library can take a lot of time.
+ * To reduce the time it takes the files are indexed.
+ *
+ * - Index files are created for each blend file in the asset library, even when the blend file
+ * doesn't contain any assets.
+ * - Indexes are stored in an persistent cache folder (`BKE_appdir_folder_caches` +
+ * `asset_library_indexes/{asset_library_dir}/{asset_index_file.json}`).
+ * - The content of the indexes are used when:
+ * - Index exists and can be opened
+ * - Last modification date is earlier than the file it represents.
+ * - The index file version is the latest.
+ * - Blend files without any assets can be determined by the size of the index file for some
+ * additional performance.
+ */
+extern const FileIndexerType file_indexer_asset;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/asset/ED_asset_library.h b/source/blender/editors/asset/ED_asset_library.h
index 905d097d223..62a7d6ffa9b 100644
--- a/source/blender/editors/asset/ED_asset_library.h
+++ b/source/blender/editors/asset/ED_asset_library.h
@@ -26,9 +26,27 @@
extern "C" {
#endif
+/**
+ * Return an index that can be used to uniquely identify \a library, assuming
+ * that all relevant indices were created with this function.
+ */
int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *library);
+/**
+ * Return an asset library reference matching the index returned by
+ * #ED_asset_library_reference_to_enum_value().
+ */
AssetLibraryReference ED_asset_library_reference_from_enum_value(int value);
-const struct EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(void);
+/**
+ * Translate all available asset libraries to an RNA enum, whereby the enum values match the result
+ * of #ED_asset_library_reference_to_enum_value() for any given library.
+ *
+ * Since this is meant for UI display, skips non-displayable libraries, that is, libraries with an
+ * empty name or path.
+ *
+ * \param include_local_library: Whether to include the "Current File" library or not.
+ */
+const struct EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(
+ bool include_local_library);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/asset/ED_asset_list.h b/source/blender/editors/asset/ED_asset_list.h
index 61d7729b651..669bb6dbe36 100644
--- a/source/blender/editors/asset/ED_asset_list.h
+++ b/source/blender/editors/asset/ED_asset_list.h
@@ -31,21 +31,47 @@ struct ID;
struct bContext;
struct wmNotifier;
+/**
+ * Invoke asset list reading, potentially in a parallel job. Won't wait until the job is done,
+ * and may return earlier.
+ */
void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference,
const struct bContext *C);
void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference,
struct bContext *C);
void ED_assetlist_clear(const struct AssetLibraryReference *library_reference, struct bContext *C);
bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *library_reference);
+/**
+ * Tag all asset lists in the storage that show main data as needing an update (re-fetch).
+ *
+ * This only tags the data. If the asset list is visible on screen, the space is still responsible
+ * for ensuring the necessary redraw. It can use #ED_assetlist_listen() to check if the asset-list
+ * needs a redraw for a given notifier.
+ */
void ED_assetlist_storage_tag_main_data_dirty(void);
+/**
+ * Remapping of ID pointers within the asset lists. Typically called when an ID is deleted to clear
+ * all references to it (\a id_new is null then).
+ */
void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new);
+/**
+ * Can't wait for static deallocation to run. There's nested data allocated with our guarded
+ * allocator, it will complain about unfreed memory on exit.
+ */
void ED_assetlist_storage_exit(void);
struct ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle);
const char *ED_assetlist_library_path(const struct AssetLibraryReference *library_reference);
+/**
+ * \return True if the region needs a UI redraw.
+ */
bool ED_assetlist_listen(const struct AssetLibraryReference *library_reference,
const struct wmNotifier *notifier);
+/**
+ * \return The number of assets stored in the asset list for \a library_reference, or -1 if there
+ * is no list fetched for it.
+ */
int ED_assetlist_size(const struct AssetLibraryReference *library_reference);
#ifdef __cplusplus
diff --git a/source/blender/editors/asset/ED_asset_list.hh b/source/blender/editors/asset/ED_asset_list.hh
index dcc07f54e75..24def2fb4ab 100644
--- a/source/blender/editors/asset/ED_asset_list.hh
+++ b/source/blender/editors/asset/ED_asset_list.hh
@@ -35,4 +35,4 @@ std::string ED_assetlist_asset_filepath_get(const bContext *C,
/* Can return false to stop iterating. */
using AssetListIterFn = blender::FunctionRef<bool(AssetHandle)>;
-void ED_assetlist_iterate(const AssetLibraryReference *library_reference, AssetListIterFn fn);
+void ED_assetlist_iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn);
diff --git a/source/blender/editors/asset/ED_asset_mark_clear.h b/source/blender/editors/asset/ED_asset_mark_clear.h
index d8b8f15a109..8f10e769c52 100644
--- a/source/blender/editors/asset/ED_asset_mark_clear.h
+++ b/source/blender/editors/asset/ED_asset_mark_clear.h
@@ -25,6 +25,7 @@ extern "C" {
#endif
struct ID;
+struct Main;
struct bContext;
/**
@@ -34,7 +35,14 @@ struct bContext;
*
* \return whether the datablock was marked as asset; false when it is not capable of becoming an
* asset, or when it already was an asset. */
-bool ED_asset_mark_id(const struct bContext *C, struct ID *id);
+bool ED_asset_mark_id(struct ID *id);
+
+/**
+ * Generate preview image for the given datablock.
+ *
+ * The preview image might be generated using a background thread.
+ */
+void ED_asset_generate_preview(const struct bContext *C, struct ID *id);
/**
* Remove the asset metadata, turning the ID into a "normal" ID.
@@ -42,9 +50,12 @@ bool ED_asset_mark_id(const struct bContext *C, struct ID *id);
* This clears the Fake User. If for some reason the datablock is meant to be saved anyway, the
* caller is responsible for explicitly setting the Fake User.
*
- * \return whether the asset metadata was actually removed; false when the ID was not an asset. */
+ * \return whether the asset metadata was actually removed; false when the ID was not an asset.
+ */
bool ED_asset_clear_id(struct ID *id);
+void ED_assets_pre_save(struct Main *bmain);
+
bool ED_asset_can_mark_single_from_context(const struct bContext *C);
#ifdef __cplusplus
diff --git a/source/blender/editors/asset/ED_asset_temp_id_consumer.h b/source/blender/editors/asset/ED_asset_temp_id_consumer.h
index 9a47e435612..0848f4225bd 100644
--- a/source/blender/editors/asset/ED_asset_temp_id_consumer.h
+++ b/source/blender/editors/asset/ED_asset_temp_id_consumer.h
@@ -16,6 +16,11 @@
/** \file
* \ingroup edasset
+ *
+ * API to abstract away details for temporary loading of an ID from an asset. If the ID is stored
+ * in the current file (or more precisely, in the #Main given when requesting an ID) no loading is
+ * performed and the ID is returned. Otherwise it's imported for temporary access using the
+ * `BLO_library_temp` API.
*/
#pragma once
diff --git a/source/blender/editors/asset/ED_asset_type.h b/source/blender/editors/asset/ED_asset_type.h
new file mode 100644
index 00000000000..e1c327808aa
--- /dev/null
+++ b/source/blender/editors/asset/ED_asset_type.h
@@ -0,0 +1,60 @@
+/*
+ * 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 edasset
+ */
+
+#pragma once
+
+#include "DNA_ID.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ID;
+
+bool ED_asset_type_id_is_non_experimental(const struct ID *id);
+#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS \
+ (FILTER_ID_MA | FILTER_ID_OB | FILTER_ID_AC | FILTER_ID_WO | FILTER_ID_NT)
+
+/**
+ * Check if the asset type for \a id (which doesn't need to be an asset right now) can be an asset,
+ * respecting the "Extended Asset Browser" experimental feature flag.
+ */
+bool ED_asset_type_is_supported(const ID *id);
+
+/**
+ * Get the filter flags (subset of #FILTER_ID_ALL) representing the asset ID types that may be
+ * turned into assets, respecting the "Extended Asset Browser" experimental feature flag.
+ * \note Does not check for #BKE_id_can_be_asset(), so may return filter flags for IDs that can
+ * never be assets.
+ */
+int64_t ED_asset_types_supported_as_filter_flags(void);
+
+/**
+ * Utility: A string enumerating the non-experimental asset types. This is useful info to
+ * the user, it should be displayed in tooltips or messages. Macro to support concatenating static
+ * strings with this (not all UI code supports dynamic strings nicely).
+ * Should start with a consonant, so usages can prefix it with "a" (not "an").
+ */
+#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING \
+ "Material, Object, Pose Action, Node Group or World"
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/asset/intern/asset_catalog.cc b/source/blender/editors/asset/intern/asset_catalog.cc
new file mode 100644
index 00000000000..f6c02f86f0a
--- /dev/null
+++ b/source/blender/editors/asset/intern/asset_catalog.cc
@@ -0,0 +1,187 @@
+/*
+ * 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 edasset
+ */
+
+#include "BKE_asset_catalog.hh"
+#include "BKE_asset_library.hh"
+#include "BKE_main.h"
+
+#include "BLI_string_utils.h"
+
+#include "ED_asset_catalog.h"
+#include "ED_asset_catalog.hh"
+
+#include "WM_api.h"
+
+using namespace blender;
+using namespace blender::bke;
+
+struct CatalogUniqueNameFnData {
+ const AssetCatalogService &catalog_service;
+ StringRef parent_path;
+};
+
+static bool catalog_name_exists_fn(void *arg, const char *name)
+{
+ CatalogUniqueNameFnData &fn_data = *static_cast<CatalogUniqueNameFnData *>(arg);
+ AssetCatalogPath fullpath = AssetCatalogPath(fn_data.parent_path) / name;
+ return fn_data.catalog_service.find_catalog_by_path(fullpath);
+}
+
+static std::string catalog_name_ensure_unique(AssetCatalogService &catalog_service,
+ StringRefNull name,
+ StringRef parent_path)
+{
+ CatalogUniqueNameFnData fn_data = {catalog_service, parent_path};
+
+ char unique_name[MAX_NAME] = "";
+ BLI_uniquename_cb(
+ catalog_name_exists_fn, &fn_data, name.c_str(), '.', unique_name, sizeof(unique_name));
+
+ return unique_name;
+}
+
+AssetCatalog *ED_asset_catalog_add(::AssetLibrary *library,
+ StringRefNull name,
+ StringRef parent_path)
+{
+ bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(library);
+ if (!catalog_service) {
+ return nullptr;
+ }
+
+ std::string unique_name = catalog_name_ensure_unique(*catalog_service, name, parent_path);
+ AssetCatalogPath fullpath = AssetCatalogPath(parent_path) / unique_name;
+
+ catalog_service->undo_push();
+ bke::AssetCatalog *new_catalog = catalog_service->create_catalog(fullpath);
+ if (!new_catalog) {
+ return nullptr;
+ }
+ catalog_service->tag_has_unsaved_changes(new_catalog);
+
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+ return new_catalog;
+}
+
+void ED_asset_catalog_remove(::AssetLibrary *library, const CatalogID &catalog_id)
+{
+ bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(library);
+ if (!catalog_service) {
+ BLI_assert_unreachable();
+ return;
+ }
+
+ catalog_service->undo_push();
+ catalog_service->tag_has_unsaved_changes(nullptr);
+ catalog_service->prune_catalogs_by_id(catalog_id);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+}
+
+void ED_asset_catalog_rename(::AssetLibrary *library,
+ const CatalogID catalog_id,
+ const StringRefNull new_name)
+{
+ bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(library);
+ if (!catalog_service) {
+ BLI_assert_unreachable();
+ return;
+ }
+
+ AssetCatalog *catalog = catalog_service->find_catalog(catalog_id);
+
+ const AssetCatalogPath new_path = catalog->path.parent() / StringRef(new_name);
+ const AssetCatalogPath clean_new_path = new_path.cleanup();
+
+ if (new_path == catalog->path || clean_new_path == catalog->path) {
+ /* Nothing changed, so don't bother renaming for nothing. */
+ return;
+ }
+
+ catalog_service->undo_push();
+ catalog_service->tag_has_unsaved_changes(catalog);
+ catalog_service->update_catalog_path(catalog_id, clean_new_path);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+}
+
+void ED_asset_catalog_move(::AssetLibrary *library,
+ const CatalogID src_catalog_id,
+ const std::optional<CatalogID> dst_parent_catalog_id)
+{
+ bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(library);
+ if (!catalog_service) {
+ BLI_assert_unreachable();
+ return;
+ }
+
+ AssetCatalog *src_catalog = catalog_service->find_catalog(src_catalog_id);
+ if (!src_catalog) {
+ BLI_assert_unreachable();
+ return;
+ }
+ AssetCatalog *dst_catalog = dst_parent_catalog_id ?
+ catalog_service->find_catalog(*dst_parent_catalog_id) :
+ nullptr;
+ if (!dst_catalog && dst_parent_catalog_id) {
+ BLI_assert_unreachable();
+ return;
+ }
+
+ std::string unique_name = catalog_name_ensure_unique(
+ *catalog_service, src_catalog->path.name(), dst_catalog ? dst_catalog->path.c_str() : "");
+ /* If a destination catalog was given, construct the path using that. Otherwise, the path is just
+ * the name of the catalog to be moved, which means it ends up at the root level. */
+ const AssetCatalogPath new_path = dst_catalog ? (dst_catalog->path / unique_name) :
+ AssetCatalogPath{unique_name};
+ const AssetCatalogPath clean_new_path = new_path.cleanup();
+
+ if (new_path == src_catalog->path || clean_new_path == src_catalog->path) {
+ /* Nothing changed, so don't bother renaming for nothing. */
+ return;
+ }
+
+ catalog_service->undo_push();
+ catalog_service->tag_has_unsaved_changes(src_catalog);
+ catalog_service->update_catalog_path(src_catalog_id, clean_new_path);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+}
+
+void ED_asset_catalogs_save_from_main_path(::AssetLibrary *library, const Main *bmain)
+{
+ bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(library);
+ if (!catalog_service) {
+ BLI_assert_unreachable();
+ return;
+ }
+
+ /* Since writing to disk also means loading any on-disk changes, it may be a good idea to store
+ * an undo step. */
+ catalog_service->undo_push();
+ catalog_service->write_to_disk(bmain->filepath);
+}
+
+void ED_asset_catalogs_set_save_catalogs_when_file_is_saved(const bool should_save)
+{
+ bke::AssetLibrary::save_catalogs_when_file_is_saved = should_save;
+}
+
+bool ED_asset_catalogs_get_save_catalogs_when_file_is_saved()
+{
+ return bke::AssetLibrary::save_catalogs_when_file_is_saved;
+}
diff --git a/source/blender/editors/asset/intern/asset_filter.cc b/source/blender/editors/asset/intern/asset_filter.cc
index 329342a30cd..70e3e2f55ea 100644
--- a/source/blender/editors/asset/intern/asset_filter.cc
+++ b/source/blender/editors/asset/intern/asset_filter.cc
@@ -22,24 +22,11 @@
#include "BLI_listbase.h"
-#include "DNA_ID.h"
#include "DNA_asset_types.h"
#include "ED_asset_filter.h"
#include "ED_asset_handle.h"
-/**
- * Compare \a asset against the settings of \a filter.
- *
- * Individual filter parameters are ORed with the asset properties. That means:
- * * The asset type must be one of the ID types filtered by, and
- * * The asset must contain at least one of the tags filtered by.
- * However for an asset to be matching it must have one match in each of the parameters. I.e. one
- * matching type __and__ at least one matching tag.
- *
- * \returns True if the asset should be visible with these filter settings (parameters match).
- * Otherwise returns false (mismatch).
- */
bool ED_asset_filter_matches_asset(const AssetFilterSettings *filter, const AssetHandle *asset)
{
ID_Type asset_type = ED_asset_handle_get_id_type(asset);
diff --git a/source/blender/editors/asset/intern/asset_handle.cc b/source/blender/editors/asset/intern/asset_handle.cc
index 5c8d0b1349c..a2029d3cc50 100644
--- a/source/blender/editors/asset/intern/asset_handle.cc
+++ b/source/blender/editors/asset/intern/asset_handle.cc
@@ -16,17 +16,10 @@
/** \file
* \ingroup edasset
- *
- * Asset-handle is a temporary design, not part of the core asset system design.
- *
- * Currently asset-list items are just file directory items (#FileDirEntry). So an asset-handle is
- * just wraps a pointer to this. We try to abstract away the fact that it's just a file entry,
- * although that doesn't always work (see #rna_def_asset_handle()).
*/
#include <string>
-#include "DNA_asset_types.h"
#include "DNA_space_types.h"
#include "BLO_readfile.h"
diff --git a/source/blender/editors/asset/intern/asset_indexer.cc b/source/blender/editors/asset/intern/asset_indexer.cc
new file mode 100644
index 00000000000..336ccff900c
--- /dev/null
+++ b/source/blender/editors/asset/intern/asset_indexer.cc
@@ -0,0 +1,812 @@
+/*
+ * 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 edasset
+ */
+
+#include <fstream>
+#include <iomanip>
+#include <optional>
+
+#include "ED_asset_indexer.h"
+
+#include "DNA_asset_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_fileops.h"
+#include "BLI_hash.hh"
+#include "BLI_linklist.h"
+#include "BLI_path_util.h"
+#include "BLI_serialize.hh"
+#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_uuid.h"
+
+#include "BKE_appdir.h"
+#include "BKE_asset.h"
+#include "BKE_asset_catalog.hh"
+#include "BKE_idprop.hh"
+#include "BKE_preferences.h"
+
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"ed.asset"};
+
+namespace blender::ed::asset::index {
+
+using namespace blender::io::serialize;
+using namespace blender::bke;
+using namespace blender::bke::idprop;
+
+/**
+ * \file asset_indexer.cc
+ * \brief Indexer for asset libraries.
+ *
+ * Indexes are stored per input file. Each index can contain zero to multiple asset entries.
+ * The indexes are grouped together per asset library. They are stored in
+ * #BKE_appdir_folder_caches +
+ * /asset-library-indices/<asset-library-hash>/<asset-index-hash>_<asset_file>.index.json.
+ *
+ * The structure of an index file is
+ * \code
+ * {
+ * "version": <file version number>,
+ * "entries": [{
+ * "name": "<asset name>",
+ * "catalog_id": "<catalog_id>",
+ * "catalog_name": "<catalog_name>",
+ * "description": "<description>",
+ * "author": "<author>",
+ * "tags": ["<tag>"],
+ * "properties": [..]
+ * }]
+ * }
+ * \endcode
+ *
+ * NOTE: entries, author, description, tags and properties are optional attributes.
+ *
+ * NOTE: File browser uses name and idcode separate. Inside the index they are joined together like
+ * #ID.name.
+ * NOTE: File browser group name isn't stored in the index as it is a translatable name.
+ */
+constexpr StringRef ATTRIBUTE_VERSION("version");
+constexpr StringRef ATTRIBUTE_ENTRIES("entries");
+constexpr StringRef ATTRIBUTE_ENTRIES_NAME("name");
+constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_ID("catalog_id");
+constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_NAME("catalog_name");
+constexpr StringRef ATTRIBUTE_ENTRIES_DESCRIPTION("description");
+constexpr StringRef ATTRIBUTE_ENTRIES_AUTHOR("author");
+constexpr StringRef ATTRIBUTE_ENTRIES_TAGS("tags");
+constexpr StringRef ATTRIBUTE_ENTRIES_PROPERTIES("properties");
+
+/** Abstract class for #BlendFile and #AssetIndexFile. */
+class AbstractFile {
+ public:
+ virtual ~AbstractFile() = default;
+
+ virtual const char *get_file_path() const = 0;
+
+ bool exists() const
+ {
+ return BLI_exists(get_file_path());
+ }
+
+ size_t get_file_size() const
+ {
+ return BLI_file_size(get_file_path());
+ }
+};
+
+/**
+ * \brief Reference to a blend file that can be indexed.
+ */
+class BlendFile : public AbstractFile {
+ StringRefNull file_path_;
+
+ public:
+ BlendFile(StringRefNull file_path) : file_path_(file_path)
+ {
+ }
+
+ uint64_t hash() const
+ {
+ DefaultHash<StringRefNull> hasher;
+ return hasher(file_path_);
+ }
+
+ std::string get_filename() const
+ {
+ char filename[FILE_MAX];
+ BLI_split_file_part(get_file_path(), filename, sizeof(filename));
+ return std::string(filename);
+ }
+
+ const char *get_file_path() const override
+ {
+ return file_path_.c_str();
+ }
+};
+
+/**
+ * \brief Single entry inside a #AssetIndexFile for reading.
+ */
+struct AssetEntryReader {
+ private:
+ /**
+ * \brief Lookup table containing the elements of the entry.
+ */
+ DictionaryValue::Lookup lookup;
+
+ StringRefNull get_name_with_idcode() const
+ {
+ return lookup.lookup(ATTRIBUTE_ENTRIES_NAME)->as_string_value()->value();
+ }
+
+ public:
+ AssetEntryReader(const DictionaryValue &entry) : lookup(entry.create_lookup())
+ {
+ }
+
+ ID_Type get_idcode() const
+ {
+ const StringRefNull name_with_idcode = get_name_with_idcode();
+ return GS(name_with_idcode.c_str());
+ }
+
+ StringRef get_name() const
+ {
+ const StringRefNull name_with_idcode = get_name_with_idcode();
+ return name_with_idcode.substr(2);
+ }
+
+ bool has_description() const
+ {
+ return lookup.contains(ATTRIBUTE_ENTRIES_DESCRIPTION);
+ }
+
+ StringRefNull get_description() const
+ {
+ return lookup.lookup(ATTRIBUTE_ENTRIES_DESCRIPTION)->as_string_value()->value();
+ }
+
+ bool has_author() const
+ {
+ return lookup.contains(ATTRIBUTE_ENTRIES_AUTHOR);
+ }
+
+ StringRefNull get_author() const
+ {
+ return lookup.lookup(ATTRIBUTE_ENTRIES_AUTHOR)->as_string_value()->value();
+ }
+
+ StringRefNull get_catalog_name() const
+ {
+ return lookup.lookup(ATTRIBUTE_ENTRIES_CATALOG_NAME)->as_string_value()->value();
+ }
+
+ CatalogID get_catalog_id() const
+ {
+ const std::string &catalog_id =
+ lookup.lookup(ATTRIBUTE_ENTRIES_CATALOG_ID)->as_string_value()->value();
+ CatalogID catalog_uuid(catalog_id);
+ return catalog_uuid;
+ }
+
+ void add_tags_to_meta_data(AssetMetaData *asset_data) const
+ {
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS);
+ if (value_ptr == nullptr) {
+ return;
+ }
+
+ const ArrayValue *array_value = (*value_ptr)->as_array_value();
+ const ArrayValue::Items &elements = array_value->elements();
+ for (const ArrayValue::Item &item : elements) {
+ const StringRefNull tag_name = item->as_string_value()->value();
+ BKE_asset_metadata_tag_add(asset_data, tag_name.c_str());
+ }
+ }
+
+ void add_properties_to_meta_data(AssetMetaData *asset_data) const
+ {
+ BLI_assert(asset_data->properties == nullptr);
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(
+ ATTRIBUTE_ENTRIES_PROPERTIES);
+ if (value_ptr == nullptr) {
+ return;
+ }
+
+ const Value &value = *(value_ptr->get());
+ IDProperty *properties = convert_from_serialize_value(value);
+ asset_data->properties = properties;
+ }
+};
+
+struct AssetEntryWriter {
+ private:
+ DictionaryValue::Items &attributes;
+
+ public:
+ AssetEntryWriter(DictionaryValue &entry) : attributes(entry.elements())
+ {
+ }
+
+ /**
+ * \brief add id + name to the attributes.
+ *
+ * NOTE: id and name are encoded like #ID.name
+ */
+ void add_id_name(const short idcode, const StringRefNull name)
+ {
+ char idcode_prefix[2];
+ /* Similar to `BKE_libblock_alloc`. */
+ *((short *)idcode_prefix) = idcode;
+ std::string name_with_idcode = std::string(idcode_prefix, sizeof(idcode_prefix)) + name;
+
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_NAME, new StringValue(name_with_idcode)));
+ }
+
+ void add_catalog_id(const CatalogID &catalog_id)
+ {
+ char catalog_id_str[UUID_STRING_LEN];
+ BLI_uuid_format(catalog_id_str, catalog_id);
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_CATALOG_ID, new StringValue(catalog_id_str)));
+ }
+
+ void add_catalog_name(const StringRefNull catalog_name)
+ {
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_CATALOG_NAME, new StringValue(catalog_name)));
+ }
+
+ void add_description(const StringRefNull description)
+ {
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_DESCRIPTION, new StringValue(description)));
+ }
+
+ void add_author(const StringRefNull author)
+ {
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_AUTHOR, new StringValue(author)));
+ }
+
+ void add_tags(const ListBase /* AssetTag */ *asset_tags)
+ {
+ ArrayValue *tags = new ArrayValue();
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_TAGS, tags));
+ ArrayValue::Items &tag_items = tags->elements();
+
+ LISTBASE_FOREACH (AssetTag *, tag, asset_tags) {
+ tag_items.append_as(new StringValue(tag->name));
+ }
+ }
+
+ void add_properties(const IDProperty *properties)
+ {
+ std::unique_ptr<Value> value = convert_to_serialize_values(properties);
+ if (value == nullptr) {
+ return;
+ }
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_PROPERTIES, value.release()));
+ }
+};
+
+static void init_value_from_file_indexer_entry(AssetEntryWriter &result,
+ const FileIndexerEntry *indexer_entry)
+{
+ const BLODataBlockInfo &datablock_info = indexer_entry->datablock_info;
+
+ result.add_id_name(indexer_entry->idcode, datablock_info.name);
+
+ const AssetMetaData &asset_data = *datablock_info.asset_data;
+ result.add_catalog_id(asset_data.catalog_id);
+ result.add_catalog_name(asset_data.catalog_simple_name);
+
+ if (asset_data.description != nullptr) {
+ result.add_description(asset_data.description);
+ }
+ if (asset_data.author != nullptr) {
+ result.add_author(asset_data.author);
+ }
+
+ if (!BLI_listbase_is_empty(&asset_data.tags)) {
+ result.add_tags(&asset_data.tags);
+ }
+
+ if (asset_data.properties != nullptr) {
+ result.add_properties(asset_data.properties);
+ }
+
+ /* TODO: asset_data.IDProperties */
+}
+
+static void init_value_from_file_indexer_entries(DictionaryValue &result,
+ const FileIndexerEntries &indexer_entries)
+{
+ ArrayValue *entries = new ArrayValue();
+ ArrayValue::Items &items = entries->elements();
+
+ for (LinkNode *ln = indexer_entries.entries; ln; ln = ln->next) {
+ const FileIndexerEntry *indexer_entry = static_cast<const FileIndexerEntry *>(ln->link);
+ /* We also get non asset types (brushes, workspaces), when browsing using the asset browser. */
+ if (indexer_entry->datablock_info.asset_data == nullptr) {
+ continue;
+ }
+ DictionaryValue *entry_value = new DictionaryValue();
+ AssetEntryWriter entry(*entry_value);
+ init_value_from_file_indexer_entry(entry, indexer_entry);
+ items.append_as(entry_value);
+ }
+
+ /* When no entries to index, we should not store the entries attribute as this would make the
+ * size bigger than the #MIN_FILE_SIZE_WITH_ENTRIES. */
+ if (items.is_empty()) {
+ delete entries;
+ return;
+ }
+
+ DictionaryValue::Items &attributes = result.elements();
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES, entries));
+}
+
+static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry,
+ const AssetEntryReader &entry)
+{
+ indexer_entry.idcode = entry.get_idcode();
+
+ const std::string &name = entry.get_name();
+ BLI_strncpy(
+ indexer_entry.datablock_info.name, name.c_str(), sizeof(indexer_entry.datablock_info.name));
+
+ AssetMetaData *asset_data = BKE_asset_metadata_create();
+ indexer_entry.datablock_info.asset_data = asset_data;
+
+ if (entry.has_description()) {
+ const std::string &description = entry.get_description();
+ char *description_c_str = static_cast<char *>(MEM_mallocN(description.length() + 1, __func__));
+ BLI_strncpy(description_c_str, description.c_str(), description.length() + 1);
+ asset_data->description = description_c_str;
+ }
+ if (entry.has_author()) {
+ const std::string &author = entry.get_author();
+ char *author_c_str = static_cast<char *>(MEM_mallocN(author.length() + 1, __func__));
+ BLI_strncpy(author_c_str, author.c_str(), author.length() + 1);
+ asset_data->author = author_c_str;
+ }
+
+ const std::string &catalog_name = entry.get_catalog_name();
+ BLI_strncpy(asset_data->catalog_simple_name,
+ catalog_name.c_str(),
+ sizeof(asset_data->catalog_simple_name));
+
+ asset_data->catalog_id = entry.get_catalog_id();
+
+ entry.add_tags_to_meta_data(asset_data);
+ entry.add_properties_to_meta_data(asset_data);
+}
+
+static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries,
+ const DictionaryValue &value)
+{
+ const DictionaryValue::Lookup attributes = value.create_lookup();
+ const DictionaryValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES);
+ BLI_assert(entries_value != nullptr);
+
+ if (entries_value == nullptr) {
+ return 0;
+ }
+
+ int num_entries_read = 0;
+ const ArrayValue::Items elements = (*entries_value)->as_array_value()->elements();
+ for (ArrayValue::Item element : elements) {
+ const AssetEntryReader asset_entry(*element->as_dictionary_value());
+
+ FileIndexerEntry *entry = static_cast<FileIndexerEntry *>(
+ MEM_callocN(sizeof(FileIndexerEntry), __func__));
+ init_indexer_entry_from_value(*entry, asset_entry);
+
+ BLI_linklist_prepend(&indexer_entries.entries, entry);
+ num_entries_read += 1;
+ }
+
+ return num_entries_read;
+}
+
+/**
+ * \brief References the asset library directory.
+ *
+ * The #AssetLibraryIndex instance is used to keep track of unused file indices. When reading any
+ * used indices are removed from the list and when reading is finished the unused
+ * indices are removed.
+ */
+struct AssetLibraryIndex {
+ /**
+ * Tracks indices that haven't been used yet.
+ *
+ * Contains absolute paths to the indices.
+ */
+ Set<std::string> unused_file_indices;
+
+ /**
+ * \brief Absolute path where the indices of `library` are stored.
+ *
+ * \NOTE: includes trailing directory separator.
+ */
+ std::string indices_base_path;
+
+ std::string library_path;
+
+ public:
+ AssetLibraryIndex(const StringRef library_path) : library_path(library_path)
+ {
+ init_indices_base_path();
+ }
+
+ uint64_t hash() const
+ {
+ DefaultHash<StringRefNull> hasher;
+ return hasher(get_library_file_path());
+ }
+
+ StringRefNull get_library_file_path() const
+ {
+ return library_path;
+ }
+
+ /**
+ * \brief Initializes #AssetLibraryIndex.indices_base_path.
+ *
+ * `BKE_appdir_folder_caches/asset-library-indices/<asset-library-name-hash>/`
+ */
+ void init_indices_base_path()
+ {
+ char index_path[FILE_MAX];
+ BKE_appdir_folder_caches(index_path, sizeof(index_path));
+
+ BLI_path_append(index_path, sizeof(index_path), "asset-library-indices");
+
+ std::stringstream ss;
+ ss << std::setfill('0') << std::setw(16) << std::hex << hash() << "/";
+ BLI_path_append(index_path, sizeof(index_path), ss.str().c_str());
+
+ indices_base_path = std::string(index_path);
+ }
+
+ /**
+ * \return absolute path to the index file of the given `asset_file`.
+ *
+ * `{indices_base_path}/{asset-file_hash}_{asset-file-filename}.index.json`.
+ */
+ std::string index_file_path(const BlendFile &asset_file) const
+ {
+ std::stringstream ss;
+ ss << indices_base_path;
+ ss << std::setfill('0') << std::setw(16) << std::hex << asset_file.hash() << "_"
+ << asset_file.get_filename() << ".index.json";
+ return ss.str();
+ }
+
+ /**
+ * Initialize to keep track of unused file indices.
+ */
+ void init_unused_index_files()
+ {
+ const char *index_path = indices_base_path.c_str();
+ if (!BLI_is_dir(index_path)) {
+ return;
+ }
+ struct direntry *dir_entries = nullptr;
+ int num_entries = BLI_filelist_dir_contents(index_path, &dir_entries);
+ for (int i = 0; i < num_entries; i++) {
+ struct direntry *entry = &dir_entries[i];
+ if (BLI_str_endswith(entry->relname, ".index.json")) {
+ unused_file_indices.add_as(std::string(entry->path));
+ }
+ }
+
+ BLI_filelist_free(dir_entries, num_entries);
+ }
+
+ void mark_as_used(const std::string &filename)
+ {
+ unused_file_indices.remove(filename);
+ }
+
+ int remove_unused_index_files() const
+ {
+ int num_files_deleted = 0;
+ for (const std::string &unused_index : unused_file_indices) {
+ const char *file_path = unused_index.c_str();
+ CLOG_INFO(&LOG, 2, "Remove unused index file [%s].", file_path);
+ BLI_delete(file_path, false, false);
+ num_files_deleted++;
+ }
+
+ return num_files_deleted;
+ }
+};
+
+/**
+ * Instance of this class represents the contents of an asset index file.
+ *
+ * \code
+ * {
+ * "version": {version},
+ * "entries": ...
+ * }
+ * \endcode
+ */
+struct AssetIndex {
+ /**
+ * \brief Version to store in new index files.
+ *
+ * Versions are written to each index file. When reading the version is checked against
+ * `CURRENT_VERSION` to make sure we can use the index. Developer should increase
+ * `CURRENT_VERSION` when changes are made to the structure of the stored index.
+ */
+ static const int CURRENT_VERSION = 1;
+
+ /**
+ * Version number to use when version couldn't be read from an index file.
+ */
+ const int UNKNOWN_VERSION = -1;
+
+ /**
+ * `blender::io::serialize::Value` representing the contents of an index file.
+ *
+ * Value is used over #DictionaryValue as the contents of the index could be corrupted and
+ * doesn't represent an object. In case corrupted files are detected the `get_version` would
+ * return `UNKNOWN_VERSION`.
+ */
+ std::unique_ptr<Value> contents;
+
+ /**
+ * Constructor for when creating/updating an asset index file.
+ * #AssetIndex.contents are filled from the given \p indexer_entries.
+ */
+ AssetIndex(const FileIndexerEntries &indexer_entries)
+ {
+ std::unique_ptr<DictionaryValue> root = std::make_unique<DictionaryValue>();
+ DictionaryValue::Items &root_attributes = root->elements();
+ root_attributes.append_as(std::pair(ATTRIBUTE_VERSION, new IntValue(CURRENT_VERSION)));
+ init_value_from_file_indexer_entries(*root, indexer_entries);
+
+ contents = std::move(root);
+ }
+
+ /**
+ * Constructor when reading an asset index file.
+ * #AssetIndex.contents are read from the given \p value.
+ */
+ AssetIndex(std::unique_ptr<Value> &value) : contents(std::move(value))
+ {
+ }
+
+ int get_version() const
+ {
+ const DictionaryValue *root = contents->as_dictionary_value();
+ if (root == nullptr) {
+ return UNKNOWN_VERSION;
+ }
+ const DictionaryValue::Lookup attributes = root->create_lookup();
+ const DictionaryValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION);
+ if (version_value == nullptr) {
+ return UNKNOWN_VERSION;
+ }
+ return (*version_value)->as_int_value()->value();
+ }
+
+ bool is_latest_version() const
+ {
+ return get_version() == CURRENT_VERSION;
+ }
+
+ /**
+ * Extract the contents of this index into the given \p indexer_entries.
+ *
+ * \return The number of entries read from the given entries.
+ */
+ int extract_into(FileIndexerEntries &indexer_entries) const
+ {
+ const DictionaryValue *root = contents->as_dictionary_value();
+ const int num_entries_read = init_indexer_entries_from_value(indexer_entries, *root);
+ return num_entries_read;
+ }
+};
+
+class AssetIndexFile : public AbstractFile {
+ public:
+ AssetLibraryIndex &library_index;
+ /**
+ * Asset index files with a size smaller than this attribute would be considered to not contain
+ * any entries.
+ */
+ const size_t MIN_FILE_SIZE_WITH_ENTRIES = 32;
+ std::string filename;
+
+ AssetIndexFile(AssetLibraryIndex &library_index, BlendFile &asset_filename)
+ : library_index(library_index), filename(library_index.index_file_path(asset_filename))
+ {
+ }
+
+ void mark_as_used()
+ {
+ library_index.mark_as_used(filename);
+ }
+
+ const char *get_file_path() const override
+ {
+ return filename.c_str();
+ }
+
+ /**
+ * Returns whether the index file is older than the given asset file.
+ */
+ bool is_older_than(BlendFile &asset_file) const
+ {
+ return BLI_file_older(get_file_path(), asset_file.get_file_path());
+ }
+
+ /**
+ * Check whether the index file contains entries without opening the file.
+ */
+ bool constains_entries() const
+ {
+ const size_t file_size = get_file_size();
+ return file_size >= MIN_FILE_SIZE_WITH_ENTRIES;
+ }
+
+ std::unique_ptr<AssetIndex> read_contents() const
+ {
+ JsonFormatter formatter;
+ std::ifstream is;
+ is.open(filename);
+ std::unique_ptr<Value> read_data = formatter.deserialize(is);
+ is.close();
+
+ return std::make_unique<AssetIndex>(read_data);
+ }
+
+ bool ensure_parent_path_exists() const
+ {
+ /* `BLI_make_existing_file` only ensures parent path, otherwise than expected from the name of
+ * the function. */
+ return BLI_make_existing_file(get_file_path());
+ }
+
+ void write_contents(AssetIndex &content)
+ {
+ JsonFormatter formatter;
+ if (!ensure_parent_path_exists()) {
+ CLOG_ERROR(&LOG, "Index not created: couldn't create folder [%s].", get_file_path());
+ return;
+ }
+
+ std::ofstream os;
+ os.open(filename, std::ios::out | std::ios::trunc);
+ formatter.serialize(os, *content.contents);
+ os.close();
+ }
+};
+
+static eFileIndexerResult read_index(const char *filename,
+ FileIndexerEntries *entries,
+ int *r_read_entries_len,
+ void *user_data)
+{
+ AssetLibraryIndex &library_index = *static_cast<AssetLibraryIndex *>(user_data);
+ BlendFile asset_file(filename);
+ AssetIndexFile asset_index_file(library_index, asset_file);
+
+ if (!asset_index_file.exists()) {
+ return FILE_INDEXER_NEEDS_UPDATE;
+ }
+
+ /* Mark index as used, even when it will be recreated. When not done it would remove the index
+ * when the indexing has finished (see `AssetLibraryIndex.remove_unused_index_files`), thereby
+ * removing the newly created index.
+ */
+ asset_index_file.mark_as_used();
+
+ if (asset_index_file.is_older_than(asset_file)) {
+ CLOG_INFO(
+ &LOG,
+ 3,
+ "Asset index file [%s] needs to be refreshed as it is older than the asset file [%s].",
+ asset_index_file.filename.c_str(),
+ filename);
+ return FILE_INDEXER_NEEDS_UPDATE;
+ }
+
+ if (!asset_index_file.constains_entries()) {
+ CLOG_INFO(&LOG,
+ 3,
+ "Asset file index is to small to contain any entries. [%s]",
+ asset_index_file.filename.c_str());
+ *r_read_entries_len = 0;
+ return FILE_INDEXER_ENTRIES_LOADED;
+ }
+
+ std::unique_ptr<AssetIndex> contents = asset_index_file.read_contents();
+ if (!contents->is_latest_version()) {
+ CLOG_INFO(&LOG,
+ 3,
+ "Asset file index is ignored; expected version %d but file is version %d [%s].",
+ AssetIndex::CURRENT_VERSION,
+ contents->get_version(),
+ asset_index_file.filename.c_str());
+ return FILE_INDEXER_NEEDS_UPDATE;
+ }
+
+ const int read_entries_len = contents->extract_into(*entries);
+ CLOG_INFO(&LOG, 1, "Read %d entries from asset index for [%s].", read_entries_len, filename);
+ *r_read_entries_len = read_entries_len;
+
+ return FILE_INDEXER_ENTRIES_LOADED;
+}
+
+static void update_index(const char *filename, FileIndexerEntries *entries, void *user_data)
+{
+ AssetLibraryIndex &library_index = *static_cast<AssetLibraryIndex *>(user_data);
+ BlendFile asset_file(filename);
+ AssetIndexFile asset_index_file(library_index, asset_file);
+ CLOG_INFO(&LOG,
+ 1,
+ "Update asset index for [%s] store index in [%s].",
+ asset_file.get_file_path(),
+ asset_index_file.get_file_path());
+
+ AssetIndex content(*entries);
+ asset_index_file.write_contents(content);
+}
+
+static void *init_user_data(const char *root_directory, size_t root_directory_maxlen)
+{
+ AssetLibraryIndex *library_index = MEM_new<AssetLibraryIndex>(
+ __func__, StringRef(root_directory, BLI_strnlen(root_directory, root_directory_maxlen)));
+ library_index->init_unused_index_files();
+ return library_index;
+}
+
+static void free_user_data(void *user_data)
+{
+ MEM_delete((AssetLibraryIndex *)user_data);
+}
+
+static void filelist_finished(void *user_data)
+{
+ AssetLibraryIndex &library_index = *static_cast<AssetLibraryIndex *>(user_data);
+ const int num_indices_removed = library_index.remove_unused_index_files();
+ if (num_indices_removed > 0) {
+ CLOG_INFO(&LOG, 1, "Removed %d unused indices.", num_indices_removed);
+ }
+}
+
+constexpr FileIndexerType asset_indexer()
+{
+ FileIndexerType indexer = {nullptr};
+ indexer.read_index = read_index;
+ indexer.update_index = update_index;
+ indexer.init_user_data = init_user_data;
+ indexer.free_user_data = free_user_data;
+ indexer.filelist_finished = filelist_finished;
+ return indexer;
+}
+
+} // namespace blender::ed::asset::index
+
+extern "C" {
+const FileIndexerType file_indexer_asset = blender::ed::asset::index::asset_indexer();
+}
diff --git a/source/blender/editors/asset/intern/asset_library_reference_enum.cc b/source/blender/editors/asset/intern/asset_library_reference_enum.cc
index 5a8fed6fea1..05526f222a5 100644
--- a/source/blender/editors/asset/intern/asset_library_reference_enum.cc
+++ b/source/blender/editors/asset/intern/asset_library_reference_enum.cc
@@ -27,7 +27,6 @@
#include "BKE_preferences.h"
-#include "DNA_asset_types.h"
#include "DNA_userdef_types.h"
#include "UI_resources.h"
@@ -36,10 +35,6 @@
#include "ED_asset_library.h"
-/**
- * Return an index that can be used to uniquely identify \a library, assuming
- * that all relevant indices were created with this function.
- */
int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *library)
{
/* Simple case: Predefined repository, just set the value. */
@@ -55,14 +50,9 @@ int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *librar
return ASSET_LIBRARY_CUSTOM + library->custom_library_index;
}
- BLI_assert_unreachable();
return ASSET_LIBRARY_LOCAL;
}
-/**
- * Return an asset library reference matching the index returned by
- * #ED_asset_library_reference_to_enum_value().
- */
AssetLibraryReference ED_asset_library_reference_from_enum_value(int value)
{
AssetLibraryReference library;
@@ -80,45 +70,45 @@ AssetLibraryReference ED_asset_library_reference_from_enum_value(int value)
/* Note that there is no check if the path exists here. If an invalid library path is used, the
* Asset Browser can give a nice hint on what's wrong. */
- const bool is_valid = (user_library->name[0] && user_library->path[0]);
if (!user_library) {
library.type = ASSET_LIBRARY_LOCAL;
library.custom_library_index = -1;
}
- else if (user_library && is_valid) {
- library.custom_library_index = value - ASSET_LIBRARY_CUSTOM;
- library.type = ASSET_LIBRARY_CUSTOM;
+ else {
+ const bool is_valid = (user_library->name[0] && user_library->path[0]);
+ if (is_valid) {
+ library.custom_library_index = value - ASSET_LIBRARY_CUSTOM;
+ library.type = ASSET_LIBRARY_CUSTOM;
+ }
}
return library;
}
-/**
- * Translate all available asset libraries to an RNA enum, whereby the enum values match the result
- * of #ED_asset_library_reference_to_enum_value() for any given library.
- *
- * Since this is meant for UI display, skips non-displayable libraries, that is, libraries with an
- * empty name or path.
- */
-const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf()
+const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(
+ const bool include_local_library)
{
- const EnumPropertyItem predefined_items[] = {
- /* For the future. */
- // {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"},
- {ASSET_LIBRARY_LOCAL,
- "LOCAL",
- ICON_BLENDER,
- "Current File",
- "Show the assets currently available in this Blender session"},
- {0, nullptr, 0, nullptr, nullptr},
- };
-
EnumPropertyItem *item = nullptr;
int totitem = 0;
+ if (include_local_library) {
+ const EnumPropertyItem predefined_items[] = {
+ /* For the future. */
+ // {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"},
+ {ASSET_LIBRARY_LOCAL,
+ "LOCAL",
+ ICON_CURRENT_FILE,
+ "Current File",
+ "Show the assets currently available in this Blender session"},
+ {0, nullptr, 0, nullptr, nullptr},
+ };
+
+ /* Add predefined items. */
+ RNA_enum_items_add(&item, &totitem, predefined_items);
+ }
+
/* Add separator if needed. */
if (!BLI_listbase_is_empty(&U.asset_libraries)) {
- const EnumPropertyItem sepr = {0, "", 0, "Custom", nullptr};
- RNA_enum_item_add(&item, &totitem, &sepr);
+ RNA_enum_item_add_separator(&item, &totitem);
}
int i = 0;
@@ -143,14 +133,6 @@ const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf()
RNA_enum_item_add(&item, &totitem, &tmp);
}
- if (totitem) {
- const EnumPropertyItem sepr = {0, "", 0, "Built-in", nullptr};
- RNA_enum_item_add(&item, &totitem, &sepr);
- }
-
- /* Add predefined items. */
- RNA_enum_items_add(&item, &totitem, predefined_items);
-
RNA_enum_item_end(&item, &totitem);
return item;
}
diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc
index cda117533cd..c075ae390d9 100644
--- a/source/blender/editors/asset/intern/asset_list.cc
+++ b/source/blender/editors/asset/intern/asset_list.cc
@@ -32,7 +32,6 @@
#include "BLI_path_util.h"
#include "BLI_utility_mixins.hh"
-#include "DNA_asset_types.h"
#include "DNA_space_types.h"
#include "BKE_preferences.h"
@@ -40,12 +39,12 @@
#include "ED_fileselect.h"
#include "WM_api.h"
-#include "WM_types.h"
/* XXX uses private header of file-space. */
#include "../space_file/filelist.h"
#include "ED_asset_handle.h"
+#include "ED_asset_indexer.h"
#include "ED_asset_list.h"
#include "ED_asset_list.hh"
#include "asset_library_reference.hh"
@@ -157,7 +156,7 @@ void AssetList::setup()
/* Relevant bits from file_refresh(). */
/* TODO pass options properly. */
- filelist_setrecursion(files, 1);
+ filelist_setrecursion(files, FILE_SELECT_MAX_RECURSIONS);
filelist_setsorting(files, FILE_SORT_ALPHA, false);
filelist_setlibrary(files, &library_ref_);
filelist_setfilter_options(
@@ -171,6 +170,8 @@ void AssetList::setup()
"",
"");
+ filelist_setindexer(files, &file_indexer_asset);
+
char path[FILE_MAXDIR] = "";
if (user_library) {
BLI_strncpy(path, user_library->path, sizeof(path));
@@ -187,7 +188,7 @@ void AssetList::fetch(const bContext &C)
if (filelist_needs_force_reset(files)) {
filelist_readjob_stop(files, CTX_wm_manager(&C));
- filelist_clear(files);
+ filelist_clear_from_reset_tag(files);
}
if (filelist_needs_reading(files)) {
@@ -295,9 +296,7 @@ int AssetList::size() const
void AssetList::tagMainDataDirty() const
{
if (filelist_needs_reset_on_main_changes(filelist_)) {
- /* Full refresh of the file list if local asset data was changed. Refreshing this view
- * is cheap and users expect this to be updated immediately. */
- filelist_tag_force_reset(filelist_);
+ filelist_tag_force_reset_mainfiles(filelist_);
}
}
@@ -313,6 +312,7 @@ StringRef AssetList::filepath() const
{
return filelist_dir(filelist_);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -429,10 +429,6 @@ AssetListStorage::AssetListMap &AssetListStorage::global_storage()
using namespace blender::ed::asset;
-/**
- * Invoke asset list reading, potentially in a parallel job. Won't wait until the job is done,
- * and may return earlier.
- */
void ED_assetlist_storage_fetch(const AssetLibraryReference *library_reference, const bContext *C)
{
AssetListStorage::fetch_library(*library_reference, *C);
@@ -460,9 +456,9 @@ bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *libr
return AssetListStorage::lookup_list(*library_reference) != nullptr;
}
-void ED_assetlist_iterate(const AssetLibraryReference *library_reference, AssetListIterFn fn)
+void ED_assetlist_iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn)
{
- AssetList *list = AssetListStorage::lookup_list(*library_reference);
+ AssetList *list = AssetListStorage::lookup_list(library_reference);
if (list) {
list->iterate(fn);
}
@@ -527,9 +523,6 @@ const char *ED_assetlist_library_path(const AssetLibraryReference *library_refer
return nullptr;
}
-/**
- * \return True if the region needs a UI redraw.
- */
bool ED_assetlist_listen(const AssetLibraryReference *library_reference,
const wmNotifier *notifier)
{
@@ -540,10 +533,6 @@ bool ED_assetlist_listen(const AssetLibraryReference *library_reference,
return false;
}
-/**
- * \return The number of assets stored in the asset list for \a library_reference, or -1 if there
- * is no list fetched for it.
- */
int ED_assetlist_size(const AssetLibraryReference *library_reference)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
@@ -553,31 +542,16 @@ int ED_assetlist_size(const AssetLibraryReference *library_reference)
return -1;
}
-/**
- * Tag all asset lists in the storage that show main data as needing an update (re-fetch).
- *
- * This only tags the data. If the asset list is visible on screen, the space is still responsible
- * for ensuring the necessary redraw. It can use #ED_assetlist_listen() to check if the asset-list
- * needs a redraw for a given notifier.
- */
void ED_assetlist_storage_tag_main_data_dirty()
{
AssetListStorage::tagMainDataDirty();
}
-/**
- * Remapping of ID pointers within the asset lists. Typically called when an ID is deleted to clear
- * all references to it (\a id_new is null then).
- */
void ED_assetlist_storage_id_remap(ID *id_old, ID *id_new)
{
AssetListStorage::remapID(id_old, id_new);
}
-/**
- * Can't wait for static deallocation to run. There's nested data allocated with our guarded
- * allocator, it will complain about unfreed memory on exit.
- */
void ED_assetlist_storage_exit()
{
AssetListStorage::destruct();
diff --git a/source/blender/editors/asset/intern/asset_mark_clear.cc b/source/blender/editors/asset/intern/asset_mark_clear.cc
index 8290124c209..2e5bdb63359 100644
--- a/source/blender/editors/asset/intern/asset_mark_clear.cc
+++ b/source/blender/editors/asset/intern/asset_mark_clear.cc
@@ -20,18 +20,14 @@
* Functions for marking and clearing assets.
*/
-#include <memory>
-#include <string>
+#include "DNA_ID.h"
#include "BKE_asset.h"
#include "BKE_context.h"
+#include "BKE_icons.h"
+#include "BKE_idtype.h"
#include "BKE_lib_id.h"
-
-#include "BLO_readfile.h"
-
-#include "DNA_ID.h"
-#include "DNA_asset_types.h"
-#include "DNA_space_types.h"
+#include "BKE_main.h"
#include "UI_interface_icons.h"
@@ -39,8 +35,9 @@
#include "ED_asset_list.h"
#include "ED_asset_mark_clear.h"
+#include "ED_asset_type.h"
-bool ED_asset_mark_id(const bContext *C, ID *id)
+bool ED_asset_mark_id(ID *id)
{
if (id->asset_data) {
return false;
@@ -51,9 +48,9 @@ bool ED_asset_mark_id(const bContext *C, ID *id)
id_fake_user_set(id);
+ const IDTypeInfo *id_type_info = BKE_idtype_get_info_from_id(id);
id->asset_data = BKE_asset_metadata_create();
-
- UI_icon_render_id(C, nullptr, id, ICON_SIZE_PREVIEW, true);
+ id->asset_data->local_type_info = id_type_info->asset_type_info;
/* Important for asset storage to update properly! */
ED_assetlist_storage_tag_main_data_dirty();
@@ -61,6 +58,16 @@ bool ED_asset_mark_id(const bContext *C, ID *id)
return true;
}
+void ED_asset_generate_preview(const bContext *C, ID *id)
+{
+ PreviewImage *preview = BKE_previewimg_id_get(id);
+ if (preview) {
+ BKE_previewimg_clear(preview);
+ }
+
+ UI_icon_render_id(C, nullptr, id, ICON_SIZE_PREVIEW, true);
+}
+
bool ED_asset_clear_id(ID *id)
{
if (!id->asset_data) {
@@ -75,8 +82,27 @@ bool ED_asset_clear_id(ID *id)
return true;
}
+void ED_assets_pre_save(struct Main *bmain)
+{
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (!id->asset_data || !id->asset_data->local_type_info) {
+ continue;
+ }
+
+ if (id->asset_data->local_type_info->pre_save_fn) {
+ id->asset_data->local_type_info->pre_save_fn(id, id->asset_data);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+}
+
bool ED_asset_can_mark_single_from_context(const bContext *C)
{
/* Context needs a "id" pointer to be set for #ASSET_OT_mark()/#ASSET_OT_clear() to use. */
- return CTX_data_pointer_get_type_silent(C, "id", &RNA_ID).data != nullptr;
+ const ID *id = static_cast<ID *>(CTX_data_pointer_get_type_silent(C, "id", &RNA_ID).data);
+ if (!id) {
+ return false;
+ }
+ return ED_asset_type_is_supported(id);
}
diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc
index a18b7649060..f7755aa9fea 100644
--- a/source/blender/editors/asset/intern/asset_ops.cc
+++ b/source/blender/editors/asset/intern/asset_ops.cc
@@ -18,47 +18,41 @@
* \ingroup edasset
*/
+#include "BKE_asset_library.hh"
+#include "BKE_bpath.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_preferences.h"
#include "BKE_report.h"
-#include "BLI_vector.hh"
+#include "BLI_fileops.h"
+#include "BLI_fnmatch.h"
+#include "BLI_path_util.h"
+#include "BLI_set.hh"
#include "ED_asset.h"
+#include "ED_asset_catalog.hh"
+#include "ED_screen.h"
+#include "ED_util.h"
+/* XXX needs access to the file list, should all be done via the asset system in future. */
+#include "ED_fileselect.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "WM_api.h"
-#include "WM_types.h"
-/* -------------------------------------------------------------------- */
-
-using PointerRNAVec = blender::Vector<PointerRNA>;
+#include "DNA_space_types.h"
-static PointerRNAVec asset_operation_get_ids_from_context(const bContext *C);
-static PointerRNAVec asset_operation_get_nonexperimental_ids_from_context(const bContext *C);
-static bool asset_type_is_nonexperimental(const ID_Type id_type);
+#include "BLO_writefile.h"
-static bool asset_operation_poll(bContext * /*C*/)
-{
- /* At this moment only the pose library is non-experimental. Still, directly marking arbitrary
- * Actions as asset is not part of the stable functionality; instead, the pose library "Create
- * Pose Asset" operator should be used. Actions can still be marked as asset via
- * `the_action.asset_mark()` (so a function call instead of this operator), which is what the
- * pose library uses internally. */
- return U.experimental.use_extended_asset_browser;
-}
+using namespace blender;
-static bool asset_clear_poll(bContext *C)
-{
- if (asset_operation_poll(C)) {
- return true;
- }
+/* -------------------------------------------------------------------- */
- PointerRNAVec pointers = asset_operation_get_nonexperimental_ids_from_context(C);
- return !pointers.is_empty();
-}
+using PointerRNAVec = blender::Vector<PointerRNA>;
/**
* Return the IDs to operate on as PointerRNA vector. Either a single one ("id" context member) or
@@ -85,26 +79,51 @@ static PointerRNAVec asset_operation_get_ids_from_context(const bContext *C)
return ids;
}
-static PointerRNAVec asset_operation_get_nonexperimental_ids_from_context(const bContext *C)
+/**
+ * Information about what's contained in a #PointerRNAVec, returned by
+ * #asset_operation_get_id_vec_stats_from_context().
+ */
+struct IDVecStats {
+ bool has_asset = false;
+ bool has_supported_type = false;
+ bool is_single = false;
+};
+
+/**
+ * Helper to report stats about the IDs in context. Operator polls use this, also to report a
+ * helpful disabled hint to the user.
+ */
+static IDVecStats asset_operation_get_id_vec_stats_from_context(const bContext *C)
{
- PointerRNAVec nonexperimental;
PointerRNAVec pointers = asset_operation_get_ids_from_context(C);
+ IDVecStats stats;
+
+ stats.is_single = pointers.size() == 1;
+
for (PointerRNA &ptr : pointers) {
BLI_assert(RNA_struct_is_ID(ptr.type));
ID *id = static_cast<ID *>(ptr.data);
- if (asset_type_is_nonexperimental(GS(id->name))) {
- nonexperimental.append(ptr);
+ if (ED_asset_type_is_supported(id)) {
+ stats.has_supported_type = true;
+ }
+ if (ID_IS_ASSET(id)) {
+ stats.has_asset = true;
}
}
- return nonexperimental;
+
+ return stats;
}
-static bool asset_type_is_nonexperimental(const ID_Type id_type)
+static const char *asset_operation_unsupported_type_msg(const bool is_single)
{
- /* At this moment only the pose library is non-experimental. For simplicity, allow asset
- * operations on all Action datablocks (even though pose assets are limited to single frames). */
- return ELEM(id_type, ID_AC);
+ const char *msg_single =
+ "Data-block does not support asset operations - must be "
+ "a " ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING;
+ const char *msg_multiple =
+ "No data-block selected that supports asset operations - select at least "
+ "one " ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING;
+ return is_single ? msg_single : msg_multiple;
}
/* -------------------------------------------------------------------- */
@@ -137,7 +156,9 @@ void AssetMarkHelper::operator()(const bContext &C, PointerRNAVec &ids)
continue;
}
- if (ED_asset_mark_id(&C, id)) {
+ if (ED_asset_mark_id(id)) {
+ ED_asset_generate_preview(&C, id);
+
stats.last_id = id;
stats.tot_created++;
}
@@ -192,6 +213,18 @@ static int asset_mark_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static bool asset_mark_poll(bContext *C)
+{
+ IDVecStats ctx_stats = asset_operation_get_id_vec_stats_from_context(C);
+
+ if (!ctx_stats.has_supported_type) {
+ CTX_wm_operator_poll_msg_set(C, asset_operation_unsupported_type_msg(ctx_stats.is_single));
+ return false;
+ }
+
+ return true;
+}
+
static void ASSET_OT_mark(wmOperatorType *ot)
{
ot->name = "Mark as Asset";
@@ -201,7 +234,7 @@ static void ASSET_OT_mark(wmOperatorType *ot)
ot->idname = "ASSET_OT_mark";
ot->exec = asset_mark_exec;
- ot->poll = asset_operation_poll;
+ ot->poll = asset_mark_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -304,6 +337,24 @@ static int asset_clear_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static bool asset_clear_poll(bContext *C)
+{
+ IDVecStats ctx_stats = asset_operation_get_id_vec_stats_from_context(C);
+
+ if (!ctx_stats.has_asset) {
+ const char *msg_single = "Data-block is not marked as asset";
+ const char *msg_multiple = "No data-block selected that is marked as asset";
+ CTX_wm_operator_poll_msg_set(C, ctx_stats.is_single ? msg_single : msg_multiple);
+ return false;
+ }
+ if (!ctx_stats.has_supported_type) {
+ CTX_wm_operator_poll_msg_set(C, asset_operation_unsupported_type_msg(ctx_stats.is_single));
+ return false;
+ }
+
+ return true;
+}
+
static char *asset_clear_get_description(struct bContext *UNUSED(C),
struct wmOperatorType *UNUSED(op),
struct PointerRNA *values)
@@ -341,8 +392,14 @@ static void ASSET_OT_clear(wmOperatorType *ot)
/* -------------------------------------------------------------------- */
-static bool asset_list_refresh_poll(bContext *C)
+static bool asset_library_refresh_poll(bContext *C)
{
+ if (ED_operator_asset_browsing_active(C)) {
+ return true;
+ }
+
+ /* While not inside an Asset Browser, check if there's a asset list stored for the active asset
+ * library (stored in the workspace, obtained via context). */
const AssetLibraryReference *library = CTX_wm_asset_library_ref(C);
if (!library) {
return false;
@@ -351,31 +408,556 @@ static bool asset_list_refresh_poll(bContext *C)
return ED_assetlist_storage_has_list_for_library(library);
}
-static int asset_list_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
+static int asset_library_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
{
- const AssetLibraryReference *library = CTX_wm_asset_library_ref(C);
- ED_assetlist_clear(library, C);
+ /* Execution mode #1: Inside the Asset Browser. */
+ if (ED_operator_asset_browsing_active(C)) {
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ ED_fileselect_clear(CTX_wm_manager(C), sfile);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, nullptr);
+ }
+ else {
+ /* Execution mode #2: Outside the Asset Browser, use the asset list. */
+ const AssetLibraryReference *library = CTX_wm_asset_library_ref(C);
+ ED_assetlist_clear(library, C);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+/**
+ * This operator currently covers both cases, the File/Asset Browser file list and the asset list
+ * used for the asset-view template. Once the asset list design is used by the Asset Browser, this
+ * can be simplified to just that case.
+ */
+static void ASSET_OT_library_refresh(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Refresh Asset Library";
+ ot->description = "Reread assets and asset catalogs from the asset library on disk";
+ ot->idname = "ASSET_OT_library_refresh";
+
+ /* api callbacks */
+ ot->exec = asset_library_refresh_exec;
+ ot->poll = asset_library_refresh_poll;
+}
+
+/* -------------------------------------------------------------------- */
+
+static bool asset_catalog_operator_poll(bContext *C)
+{
+ const SpaceFile *sfile = CTX_wm_space_file(C);
+ return sfile && ED_fileselect_active_asset_library_get(sfile);
+}
+
+static int asset_catalog_new_exec(bContext *C, wmOperator *op)
+{
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ struct AssetLibrary *asset_library = ED_fileselect_active_asset_library_get(sfile);
+ char *parent_path = RNA_string_get_alloc(op->ptr, "parent_path", nullptr, 0, nullptr);
+
+ blender::bke::AssetCatalog *new_catalog = ED_asset_catalog_add(
+ asset_library, "Catalog", parent_path);
+
+ if (sfile) {
+ ED_fileselect_activate_asset_catalog(sfile, new_catalog->catalog_id);
+ }
+
+ MEM_freeN(parent_path);
+
+ WM_event_add_notifier_ex(
+ CTX_wm_manager(C), CTX_wm_window(C), NC_ASSET | ND_ASSET_CATALOGS, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ASSET_OT_catalog_new(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Asset Catalog";
+ ot->description = "Create a new catalog to put assets in";
+ ot->idname = "ASSET_OT_catalog_new";
+
+ /* api callbacks */
+ ot->exec = asset_catalog_new_exec;
+ ot->poll = asset_catalog_operator_poll;
+
+ RNA_def_string(ot->srna,
+ "parent_path",
+ nullptr,
+ 0,
+ "Parent Path",
+ "Optional path defining the location to put the new catalog under");
+}
+
+static int asset_catalog_delete_exec(bContext *C, wmOperator *op)
+{
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ struct AssetLibrary *asset_library = ED_fileselect_active_asset_library_get(sfile);
+ char *catalog_id_str = RNA_string_get_alloc(op->ptr, "catalog_id", nullptr, 0, nullptr);
+ bke::CatalogID catalog_id;
+ if (!BLI_uuid_parse_string(&catalog_id, catalog_id_str)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_asset_catalog_remove(asset_library, catalog_id);
+
+ MEM_freeN(catalog_id_str);
+
+ WM_event_add_notifier_ex(
+ CTX_wm_manager(C), CTX_wm_window(C), NC_ASSET | ND_ASSET_CATALOGS, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ASSET_OT_catalog_delete(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Asset Catalog";
+ ot->description =
+ "Remove an asset catalog from the asset library (contained assets will not be affected and "
+ "show up as unassigned)";
+ ot->idname = "ASSET_OT_catalog_delete";
+
+ /* api callbacks */
+ ot->exec = asset_catalog_delete_exec;
+ ot->poll = asset_catalog_operator_poll;
+
+ RNA_def_string(ot->srna, "catalog_id", nullptr, 0, "Catalog ID", "ID of the catalog to delete");
+}
+
+static bke::AssetCatalogService *get_catalog_service(bContext *C)
+{
+ const SpaceFile *sfile = CTX_wm_space_file(C);
+ if (!sfile) {
+ return nullptr;
+ }
+
+ AssetLibrary *asset_lib = ED_fileselect_active_asset_library_get(sfile);
+ return BKE_asset_library_get_catalog_service(asset_lib);
+}
+
+static int asset_catalog_undo_exec(bContext *C, wmOperator * /*op*/)
+{
+ bke::AssetCatalogService *catalog_service = get_catalog_service(C);
+ if (!catalog_service) {
+ return OPERATOR_CANCELLED;
+ }
+
+ catalog_service->undo();
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+ return OPERATOR_FINISHED;
+}
+
+static bool asset_catalog_undo_poll(bContext *C)
+{
+ const bke::AssetCatalogService *catalog_service = get_catalog_service(C);
+ return catalog_service && catalog_service->is_undo_possbile();
+}
+
+static void ASSET_OT_catalog_undo(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Undo Catalog Edits";
+ ot->description = "Undo the last edit to the asset catalogs";
+ ot->idname = "ASSET_OT_catalog_undo";
+
+ /* api callbacks */
+ ot->exec = asset_catalog_undo_exec;
+ ot->poll = asset_catalog_undo_poll;
+}
+
+static int asset_catalog_redo_exec(bContext *C, wmOperator * /*op*/)
+{
+ bke::AssetCatalogService *catalog_service = get_catalog_service(C);
+ if (!catalog_service) {
+ return OPERATOR_CANCELLED;
+ }
+
+ catalog_service->redo();
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+ return OPERATOR_FINISHED;
+}
+
+static bool asset_catalog_redo_poll(bContext *C)
+{
+ const bke::AssetCatalogService *catalog_service = get_catalog_service(C);
+ return catalog_service && catalog_service->is_redo_possbile();
+}
+
+static void ASSET_OT_catalog_redo(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Redo Catalog Edits";
+ ot->description = "Redo the last undone edit to the asset catalogs";
+ ot->idname = "ASSET_OT_catalog_redo";
+
+ /* api callbacks */
+ ot->exec = asset_catalog_redo_exec;
+ ot->poll = asset_catalog_redo_poll;
+}
+
+static int asset_catalog_undo_push_exec(bContext *C, wmOperator * /*op*/)
+{
+ bke::AssetCatalogService *catalog_service = get_catalog_service(C);
+ if (!catalog_service) {
+ return OPERATOR_CANCELLED;
+ }
+
+ catalog_service->undo_push();
+ return OPERATOR_FINISHED;
+}
+
+static bool asset_catalog_undo_push_poll(bContext *C)
+{
+ return get_catalog_service(C) != nullptr;
+}
+
+static void ASSET_OT_catalog_undo_push(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Store undo snapshot for asset catalog edits";
+ ot->description = "Store the current state of the asset catalogs in the undo buffer";
+ ot->idname = "ASSET_OT_catalog_undo_push";
+
+ /* api callbacks */
+ ot->exec = asset_catalog_undo_push_exec;
+ ot->poll = asset_catalog_undo_push_poll;
+
+ /* Generally artists don't need to find & use this operator, it's meant for scripts only. */
+ ot->flag = OPTYPE_INTERNAL;
+}
+
+/* -------------------------------------------------------------------- */
+
+static bool asset_catalogs_save_poll(bContext *C)
+{
+ if (!asset_catalog_operator_poll(C)) {
+ return false;
+ }
+
+ const Main *bmain = CTX_data_main(C);
+ if (!bmain->filepath[0]) {
+ CTX_wm_operator_poll_msg_set(C, "Cannot save asset catalogs before the Blender file is saved");
+ return false;
+ }
+
+ if (!BKE_asset_library_has_any_unsaved_catalogs()) {
+ CTX_wm_operator_poll_msg_set(C, "No changes to be saved");
+ return false;
+ }
+
+ return true;
+}
+
+static int asset_catalogs_save_exec(bContext *C, wmOperator * /*op*/)
+{
+ const SpaceFile *sfile = CTX_wm_space_file(C);
+ ::AssetLibrary *asset_library = ED_fileselect_active_asset_library_get(sfile);
+
+ ED_asset_catalogs_save_from_main_path(asset_library, CTX_data_main(C));
+
+ WM_event_add_notifier_ex(
+ CTX_wm_manager(C), CTX_wm_window(C), NC_ASSET | ND_ASSET_CATALOGS, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ASSET_OT_catalogs_save(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Save Asset Catalogs";
+ ot->description =
+ "Make any edits to any catalogs permanent by writing the current set up to the asset "
+ "library";
+ ot->idname = "ASSET_OT_catalogs_save";
+
+ /* api callbacks */
+ ot->exec = asset_catalogs_save_exec;
+ ot->poll = asset_catalogs_save_poll;
+}
+
+/* -------------------------------------------------------------------- */
+
+static bool could_be_asset_bundle(const Main *bmain);
+static const bUserAssetLibrary *selected_asset_library(struct wmOperator *op);
+static bool is_contained_in_selected_asset_library(struct wmOperator *op, const char *filepath);
+static bool set_filepath_for_asset_lib(const Main *bmain, struct wmOperator *op);
+static bool has_external_files(Main *bmain, struct ReportList *reports);
+
+static bool asset_bundle_install_poll(bContext *C)
+{
+ /* This operator only works when the asset browser is set to Current File. */
+ const SpaceFile *sfile = CTX_wm_space_file(C);
+ if (sfile == nullptr) {
+ return false;
+ }
+ if (!ED_fileselect_is_local_asset_library(sfile)) {
+ return false;
+ }
+
+ const Main *bmain = CTX_data_main(C);
+ if (!could_be_asset_bundle(bmain)) {
+ return false;
+ }
+
+ /* Check whether this file is already located inside any asset library. */
+ const struct bUserAssetLibrary *asset_lib = BKE_preferences_asset_library_containing_path(
+ &U, bmain->filepath);
+ if (asset_lib) {
+ return false;
+ }
+
+ return true;
+}
+
+static int asset_bundle_install_invoke(struct bContext *C,
+ struct wmOperator *op,
+ const struct wmEvent * /*event*/)
+{
+ Main *bmain = CTX_data_main(C);
+ if (has_external_files(bmain, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_event_add_fileselect(C, op);
+
+ /* Make the "Save As" dialog box default to "${ASSET_LIB_ROOT}/${CURRENT_FILE}.blend". */
+ if (!set_filepath_for_asset_lib(bmain, op)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int asset_bundle_install_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ if (has_external_files(bmain, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Check file path, copied from #wm_file_write(). */
+ char filepath[PATH_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+ const size_t len = strlen(filepath);
+
+ if (len == 0) {
+ BKE_report(op->reports, RPT_ERROR, "Path is empty, cannot save");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (len >= FILE_MAX) {
+ BKE_report(op->reports, RPT_ERROR, "Path too long, cannot save");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Check that the destination is actually contained in the selected asset library. */
+ if (!is_contained_in_selected_asset_library(op, filepath)) {
+ BKE_reportf(op->reports, RPT_ERROR, "Selected path is outside of the selected asset library");
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_cursor_wait(true);
+ bke::AssetCatalogService *cat_service = get_catalog_service(C);
+ /* Store undo step, such that on a failed save the 'prepare_to_merge_on_write' call can be
+ * un-done. */
+ cat_service->undo_push();
+ cat_service->prepare_to_merge_on_write();
+
+ const int operator_result = WM_operator_name_call(
+ C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, op->ptr);
+ WM_cursor_wait(false);
+
+ if (operator_result != OPERATOR_FINISHED) {
+ cat_service->undo();
+ return operator_result;
+ }
+
+ const bUserAssetLibrary *lib = selected_asset_library(op);
+ BLI_assert_msg(lib, "If the asset library is not known, how did we get here?");
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ R"(Saved "%s" to asset library "%s")",
+ BLI_path_basename(bmain->filepath),
+ lib->name);
return OPERATOR_FINISHED;
}
-static void ASSET_OT_list_refresh(struct wmOperatorType *ot)
+static const EnumPropertyItem *rna_asset_library_reference_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ const EnumPropertyItem *items = ED_asset_library_reference_to_rna_enum_itemf(false);
+ if (!items) {
+ *r_free = false;
+ }
+
+ *r_free = true;
+ return items;
+}
+
+static void ASSET_OT_bundle_install(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Refresh Asset List";
- ot->description = "Trigger a reread of the assets";
- ot->idname = "ASSET_OT_list_refresh";
+ ot->name = "Copy to Asset Library";
+ ot->description =
+ "Copy the current .blend file into an Asset Library. Only works on standalone .blend files "
+ "(i.e. when no other files are referenced)";
+ ot->idname = "ASSET_OT_bundle_install";
/* api callbacks */
- ot->exec = asset_list_refresh_exec;
- ot->poll = asset_list_refresh_poll;
+ ot->exec = asset_bundle_install_exec;
+ ot->invoke = asset_bundle_install_invoke;
+ ot->poll = asset_bundle_install_poll;
+
+ ot->prop = RNA_def_property(ot->srna, "asset_library_ref", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN);
+ RNA_def_enum_funcs(ot->prop, rna_asset_library_reference_itemf);
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER | FILE_TYPE_BLENDER,
+ FILE_BLENDER,
+ FILE_SAVE,
+ WM_FILESEL_FILEPATH,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_DEFAULT);
+}
+
+/* Cheap check to see if this is an "asset bundle" just by checking main file name.
+ * A proper check will be done in the exec function, to ensure that no external files will be
+ * referenced. */
+static bool could_be_asset_bundle(const Main *bmain)
+{
+ return fnmatch("*_bundle.blend", bmain->filepath, FNM_CASEFOLD) == 0;
+}
+
+static const bUserAssetLibrary *selected_asset_library(struct wmOperator *op)
+{
+ const int enum_value = RNA_enum_get(op->ptr, "asset_library_ref");
+ const AssetLibraryReference lib_ref = ED_asset_library_reference_from_enum_value(enum_value);
+ const bUserAssetLibrary *lib = BKE_preferences_asset_library_find_from_index(
+ &U, lib_ref.custom_library_index);
+ return lib;
+}
+
+static bool is_contained_in_selected_asset_library(struct wmOperator *op, const char *filepath)
+{
+ const bUserAssetLibrary *lib = selected_asset_library(op);
+ if (!lib) {
+ return false;
+ }
+ return BLI_path_contains(lib->path, filepath);
+}
+
+/**
+ * Set the "filepath" RNA property based on selected "asset_library_ref".
+ * \return true if ok, false if error.
+ */
+static bool set_filepath_for_asset_lib(const Main *bmain, struct wmOperator *op)
+{
+ /* Find the directory path of the selected asset library. */
+ const bUserAssetLibrary *lib = selected_asset_library(op);
+ if (lib == nullptr) {
+ return false;
+ }
+
+ /* Concatenate the filename of the current blend file. */
+ const char *blend_filename = BLI_path_basename(bmain->filepath);
+ if (blend_filename == nullptr || blend_filename[0] == '\0') {
+ return false;
+ }
+
+ char file_path[PATH_MAX];
+ BLI_join_dirfile(file_path, sizeof(file_path), lib->path, blend_filename);
+ RNA_string_set(op->ptr, "filepath", file_path);
+
+ return true;
+}
+
+struct FileCheckCallbackInfo {
+ struct ReportList *reports;
+ Set<std::string> external_files;
+};
+
+static bool external_file_check_callback(BPathForeachPathData *bpath_data,
+ char * /*path_dst*/,
+ const char *path_src)
+{
+ FileCheckCallbackInfo *callback_info = static_cast<FileCheckCallbackInfo *>(
+ bpath_data->user_data);
+ callback_info->external_files.add(std::string(path_src));
+ return false;
+}
+
+/**
+ * Do a check on any external files (.blend, textures, etc.) being used.
+ * The ASSET_OT_bundle_install operator only works on standalone .blend files
+ * (catalog definition files are fine, though).
+ *
+ * \return true when there are external files, false otherwise.
+ */
+static bool has_external_files(Main *bmain, struct ReportList *reports)
+{
+ struct FileCheckCallbackInfo callback_info = {reports, Set<std::string>()};
+
+ eBPathForeachFlag flag = static_cast<eBPathForeachFlag>(
+ BKE_BPATH_FOREACH_PATH_SKIP_PACKED /* Packed files are fine. */
+ | BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE /* Only report multi-files once, it's enough. */
+ | BKE_BPATH_TRAVERSE_SKIP_WEAK_REFERENCES); /* Only care about actually used files. */
+
+ BPathForeachPathData bpath_data = {
+ /* bmain */ bmain,
+ /* callback_function */ &external_file_check_callback,
+ /* flag */ flag,
+ /* user_data */ &callback_info,
+ /* absolute_base_path */ nullptr,
+ };
+ BKE_bpath_foreach_path_main(&bpath_data);
+
+ if (callback_info.external_files.is_empty()) {
+ /* No external dependencies. */
+ return false;
+ }
+
+ if (callback_info.external_files.size() == 1) {
+ /* Only one external dependency, report it directly. */
+ BKE_reportf(callback_info.reports,
+ RPT_ERROR,
+ "Unable to copy bundle due to external dependency: \"%s\"",
+ callback_info.external_files.begin()->c_str());
+ return true;
+ }
+
+ /* Multiple external dependencies, report the aggregate and put details on console. */
+ BKE_reportf(
+ callback_info.reports,
+ RPT_ERROR,
+ "Unable to copy bundle due to %zu external dependencies; more details on the console",
+ (size_t)callback_info.external_files.size());
+ printf("Unable to copy bundle due to %zu external dependencies:\n",
+ (size_t)callback_info.external_files.size());
+ for (const std::string &path : callback_info.external_files) {
+ printf(" \"%s\"\n", path.c_str());
+ }
+ return true;
}
/* -------------------------------------------------------------------- */
-void ED_operatortypes_asset(void)
+void ED_operatortypes_asset()
{
WM_operatortype_append(ASSET_OT_mark);
WM_operatortype_append(ASSET_OT_clear);
- WM_operatortype_append(ASSET_OT_list_refresh);
+ WM_operatortype_append(ASSET_OT_catalog_new);
+ WM_operatortype_append(ASSET_OT_catalog_delete);
+ WM_operatortype_append(ASSET_OT_catalogs_save);
+ WM_operatortype_append(ASSET_OT_catalog_undo);
+ WM_operatortype_append(ASSET_OT_catalog_redo);
+ WM_operatortype_append(ASSET_OT_catalog_undo_push);
+ WM_operatortype_append(ASSET_OT_bundle_install);
+
+ WM_operatortype_append(ASSET_OT_library_refresh);
}
diff --git a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
index f664eab5cbb..8790c907f05 100644
--- a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
+++ b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
@@ -23,7 +23,6 @@
#include <new>
-#include "DNA_asset_types.h"
#include "DNA_space_types.h"
#include "BKE_report.h"
@@ -89,12 +88,13 @@ AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle)
}
BLI_assert(handle->file_data->asset_data != nullptr);
return reinterpret_cast<AssetTempIDConsumer *>(
- OBJECT_GUARDED_NEW(AssetTemporaryIDConsumer, *handle));
+ MEM_new<AssetTemporaryIDConsumer>(__func__, *handle));
}
void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer)
{
- OBJECT_GUARDED_SAFE_DELETE(*consumer, AssetTemporaryIDConsumer);
+ MEM_delete(reinterpret_cast<AssetTemporaryIDConsumer *>(*consumer));
+ *consumer = nullptr;
}
ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer_,
diff --git a/source/blender/editors/asset/intern/asset_type.cc b/source/blender/editors/asset/intern/asset_type.cc
new file mode 100644
index 00000000000..3d6ce3e3409
--- /dev/null
+++ b/source/blender/editors/asset/intern/asset_type.cc
@@ -0,0 +1,58 @@
+/*
+ * 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 edasset
+ */
+
+#include "BLI_utildefines.h"
+
+#include "DNA_userdef_types.h"
+
+#include "BKE_lib_id.h"
+
+#include "ED_asset_type.h"
+
+bool ED_asset_type_id_is_non_experimental(const ID *id)
+{
+ /* Remember to update #ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING and
+ * #ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS() with this! */
+ return ELEM(GS(id->name), ID_MA, ID_OB, ID_AC, ID_WO, ID_NT);
+}
+
+bool ED_asset_type_is_supported(const ID *id)
+{
+ if (!BKE_id_can_be_asset(id)) {
+ return false;
+ }
+
+ if (U.experimental.use_extended_asset_browser) {
+ /* The "Extended Asset Browser" experimental feature flag enables all asset types that can
+ * technically be assets. */
+ return true;
+ }
+
+ return ED_asset_type_id_is_non_experimental(id);
+}
+
+int64_t ED_asset_types_supported_as_filter_flags()
+{
+ if (U.experimental.use_extended_asset_browser) {
+ return FILTER_ID_ALL;
+ }
+
+ return ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS;
+}
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index 8ecf41162e9..0d17af1983d 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -71,7 +71,13 @@ typedef enum eCurveElem_Types {
} eCurveElem_Types;
/* internal select utils */
+/**
+ * Returns 1 in case (de)selection was successful.
+ */
bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Types hidden);
+/**
+ * Returns 1 in case (de)selection was successful.
+ */
bool select_bpoint(BPoint *bp, bool selstatus, uint8_t flag, bool hidden);
void FONT_OT_text_insert(struct wmOperatorType *ot);
@@ -146,7 +152,14 @@ void ed_editnurb_translate_flag(struct ListBase *editnurb,
uint8_t flag,
const float vec[3],
bool is_2d);
-bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, const uint8_t flag);
+/**
+ * Only for #OB_SURF.
+ */
+bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, uint8_t flag);
+/**
+ * \param axis: is in world-space.
+ * \param cent: is in object-space.
+ */
bool ed_editnurb_spin(float viewmat[4][4],
struct View3D *v3d,
struct Object *obedit,
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 9b43e23bd32..a70bc1c0350 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -1074,7 +1074,6 @@ static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
}
}
-/* return 0 if animation data wasn't changed, 1 otherwise */
int ED_curve_updateAnimPaths(Main *bmain, Curve *cu)
{
AnimData *adt = BKE_animdata_from_id(&cu->id);
@@ -1247,7 +1246,6 @@ static void remap_hooks_and_vertex_parents(Main *bmain, Object *obedit)
}
}
-/* load editNurb in object */
void ED_curve_editnurb_load(Main *bmain, Object *obedit)
{
ListBase *editnurb = object_editcurve_get(obedit);
@@ -1285,7 +1283,6 @@ void ED_curve_editnurb_load(Main *bmain, Object *obedit)
}
}
-/* make copy in cu->editnurb */
void ED_curve_editnurb_make(Object *obedit)
{
Curve *cu = (Curve *)obedit->data;
@@ -1437,20 +1434,13 @@ static int separate_exec(bContext *C, wmOperator *op)
/* Some curves changed, but some curves failed: don't explain why it failed. */
if (status.changed) {
- BKE_reportf(op->reports,
- RPT_INFO,
- tot_errors == 1 ? "%d curve could not be separated" :
- "%d curves could not be separated",
- tot_errors);
+ BKE_reportf(op->reports, RPT_INFO, "%d curve(s) could not be separated", tot_errors);
return OPERATOR_FINISHED;
}
/* All curves failed: If there is more than one error give a generic error report. */
if (((status.error_vertex_keys ? 1 : 0) + (status.error_generic ? 1 : 0)) > 1) {
- BKE_report(op->reports,
- RPT_ERROR,
- tot_errors == 1 ? "Could not separate selected curves" :
- "Could not separate selected curve");
+ BKE_report(op->reports, RPT_ERROR, "Could not separate selected curve(s)");
}
/* All curves failed due to the same error. */
@@ -1998,7 +1988,6 @@ static void ed_curve_delete_selected(Object *obedit, View3D *v3d)
}
}
-/* only for OB_SURF */
bool ed_editnurb_extrude_flag(EditNurb *editnurb, const uint8_t flag)
{
BPoint *bp, *bpn, *newbp;
@@ -3866,11 +3855,6 @@ static int set_spline_type_exec(bContext *C, wmOperator *op)
const bool use_handles = RNA_boolean_get(op->ptr, "use_handles");
const int type = RNA_enum_get(op->ptr, "type");
- if (ELEM(type, CU_CARDINAL, CU_BSPLINE)) {
- BKE_report(op->reports, RPT_ERROR, "Not yet implemented");
- continue;
- }
-
LISTBASE_FOREACH (Nurb *, nu, editnurb) {
if (ED_curve_nurb_select_check(v3d, nu)) {
const int pntsu_prev = nu->pntsu;
@@ -3914,8 +3898,6 @@ void CURVE_OT_spline_type_set(wmOperatorType *ot)
static const EnumPropertyItem type_items[] = {
{CU_POLY, "POLY", 0, "Poly", ""},
{CU_BEZIER, "BEZIER", 0, "Bezier", ""},
- // {CU_CARDINAL, "CARDINAL", 0, "Cardinal", ""},
- // {CU_BSPLINE, "B_SPLINE", 0, "B-Spline", ""},
{CU_NURBS, "NURBS", 0, "NURBS", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -4708,11 +4690,7 @@ static int make_segment_exec(bContext *C, wmOperator *op)
if (tot_errors > 0) {
/* Some curves changed, but some curves failed: don't explain why it failed. */
if (status.changed) {
- BKE_reportf(op->reports,
- RPT_INFO,
- tot_errors == 1 ? "%d curve could not make segments" :
- "%d curves could not make segments",
- tot_errors);
+ BKE_reportf(op->reports, RPT_INFO, "%d curves could not make segments", tot_errors);
return OPERATOR_FINISHED;
}
@@ -4920,8 +4898,6 @@ bool ED_curve_editnurb_select_pick(
/** \name Spin Operator
* \{ */
-/* 'cent' is in object space and 'dvec' in worldspace.
- */
bool ed_editnurb_spin(
float viewmat[4][4], View3D *v3d, Object *obedit, const float axis[3], const float cent[3])
{
@@ -4977,19 +4953,22 @@ bool ed_editnurb_spin(
if ((a & 1) == 0) {
rotateflagNurb(editnurb, SELECT, cent, scalemat1);
- weightflagNurb(editnurb, SELECT, 0.25 * M_SQRT2);
+ weightflagNurb(editnurb, SELECT, 0.5 * M_SQRT2);
}
else {
rotateflagNurb(editnurb, SELECT, cent, scalemat2);
- weightflagNurb(editnurb, SELECT, 4.0 / M_SQRT2);
+ weightflagNurb(editnurb, SELECT, 2.0 / M_SQRT2);
}
}
if (ok) {
LISTBASE_FOREACH (Nurb *, nu, editnurb) {
if (ED_curve_nurb_select_check(v3d, nu)) {
- nu->orderv = 4;
- nu->flagv |= CU_NURB_CYCLIC;
+ nu->orderv = 3;
+ /* It is challenging to create a good approximation of a circle with uniform knots vector
+ * (which is forced in Blender for cyclic NURBS curves). Here a NURBS circle is constructed
+ * by connecting four Bezier arcs. */
+ nu->flagv |= CU_NURB_CYCLIC | CU_NURB_BEZIER;
BKE_nurb_knot_calc_v(nu);
}
}
@@ -5409,7 +5388,7 @@ static int ed_editcurve_addvert(Curve *cu,
add_v3_v3(bezt->vec[1], ofs);
add_v3_v3(bezt->vec[2], ofs);
- if (((nu->flagu & CU_NURB_CYCLIC) == 0) && (i == 0 || i == nu->pntsu - 1)) {
+ if (((nu->flagu & CU_NURB_CYCLIC) == 0) && ELEM(i, 0, nu->pntsu - 1)) {
BKE_nurb_handle_calc_simple_auto(nu, bezt);
}
}
@@ -5561,12 +5540,14 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (use_proj) {
const float mval[2] = {UNPACK2(event->mval)};
- struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- vc.scene, 0, vc.region, vc.v3d);
+ struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create(vc.scene,
+ 0);
ED_transform_snap_object_project_view3d(
snap_context,
vc.depsgraph,
+ vc.region,
+ vc.v3d,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = (vc.obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL,
@@ -6811,10 +6792,6 @@ void CURVE_OT_shade_flat(wmOperatorType *ot)
/** \name Join Operator
* \{ */
-/**
- * This is used externally, by #OBJECT_OT_join.
- * TODO: shape keys - as with meshes.
- */
int ED_curve_join_objects_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -6863,9 +6840,9 @@ int ED_curve_join_objects_exec(bContext *C, wmOperator *op)
/* Compensate for different bevel depth. */
bool do_radius = false;
float compensate_radius = 0.0f;
- if (cu->ext2 != 0.0f && cu_active->ext2 != 0.0f) {
+ if (cu->bevel_radius != 0.0f && cu_active->bevel_radius != 0.0f) {
float compensate_scale = mat4_to_scale(cmat);
- compensate_radius = cu->ext2 / cu_active->ext2 * compensate_scale;
+ compensate_radius = cu->bevel_radius / cu_active->bevel_radius * compensate_scale;
do_radius = true;
}
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index 75fb17e8cc1..daef4a21692 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -306,9 +306,9 @@ Nurb *ED_curve_add_nurbs_primitive(
else if (cutype == CU_NURBS) { /* nurb */
nu->pntsu = 8;
nu->pntsv = 1;
- nu->orderu = 4;
+ nu->orderu = 3;
nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "addNurbprim6");
- nu->flagu = CU_NURB_CYCLIC;
+ nu->flagu = CU_NURB_CYCLIC | CU_NURB_BEZIER;
bp = nu->bp;
for (a = 0; a < 8; a++) {
@@ -322,7 +322,7 @@ Nurb *ED_curve_add_nurbs_primitive(
bp->vec[2] += 0.25f * nurbcircle[a][1] * grid;
}
if (a & 1) {
- bp->vec[3] = 0.25 * M_SQRT2;
+ bp->vec[3] = 0.5 * M_SQRT2;
}
else {
bp->vec[3] = 1.0;
@@ -356,7 +356,7 @@ Nurb *ED_curve_add_nurbs_primitive(
bp->vec[0] += fac * grid;
fac = (float)b - 1.5f;
bp->vec[1] += fac * grid;
- if ((a == 1 || a == 2) && (b == 1 || b == 2)) {
+ if ((ELEM(a, 1, 2)) && (ELEM(b, 1, 2))) {
bp->vec[2] += grid;
}
mul_m4_v3(mat, bp->vec);
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 26906b0ddcd..403ace56e3b 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -102,7 +102,7 @@ struct CurveDrawData {
/* offset projection by this value */
bool use_offset;
- float offset[3]; /* worldspace */
+ float offset[3]; /* world-space */
float surface_offset;
bool use_surface_offset_absolute;
} project;
@@ -144,7 +144,7 @@ static float stroke_elem_radius_from_pressure(const struct CurveDrawData *cdd,
const float pressure)
{
const Curve *cu = cdd->vc.obedit->data;
- return ((pressure * cdd->radius.range) + cdd->radius.min) * cu->ext2;
+ return ((pressure * cdd->radius.range) + cdd->radius.min) * cu->bevel_radius;
}
static float stroke_elem_radius(const struct CurveDrawData *cdd, const struct StrokeElem *selem)
@@ -364,7 +364,7 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C),
Object *obedit = cdd->vc.obedit;
Curve *cu = obedit->data;
- if (cu->ext2 > 0.0f) {
+ if (cu->bevel_radius > 0.0f) {
BLI_mempool_iter iter;
const struct StrokeElem *selem;
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index 721aa7afecc..1229b7eacc8 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -60,7 +60,6 @@
/** \name Utilities
* \{ */
-/* returns 1 in case (de)selection was successful */
bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Types hidden)
{
if ((bezt->hide == 0) || (hidden == HIDDEN)) {
@@ -80,7 +79,6 @@ bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Ty
return false;
}
-/* returns 1 in case (de)selection was successful */
bool select_bpoint(BPoint *bp, bool selstatus, uint8_t flag, bool hidden)
{
if ((bp->hide == 0) || (hidden == 1)) {
@@ -1464,15 +1462,10 @@ static int select_nth_exec(bContext *C, wmOperator *op)
if (!changed) {
if (obact->type == OB_SURF) {
- BKE_report(
- op->reports,
- RPT_ERROR,
- (objects_len == 1 ? "Surface has no active point" : "Surfaces have no active point"));
+ BKE_report(op->reports, RPT_ERROR, "Surface(s) have no active point");
}
else {
- BKE_report(op->reports,
- RPT_ERROR,
- (objects_len == 1 ? "Curve has no active point" : "Curves have no active point"));
+ BKE_report(op->reports, RPT_ERROR, "Curve(s) have no active point");
}
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 210411c6eb5..5619e2efc36 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -305,7 +305,6 @@ static void curve_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_curve_undosys_type(UndoType *ut)
{
ut->name = "Edit Curve";
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index d029bb539ba..6e0aeb87318 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -42,11 +42,11 @@
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_font.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "BKE_vfont.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -71,8 +71,6 @@
static int kill_selection(Object *obedit, int ins);
-/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
* \{ */
@@ -2155,8 +2153,8 @@ void FONT_OT_open(wmOperatorType *ot)
FILE_SPECIAL,
FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
- FILE_DEFAULTDISPLAY,
- FILE_SORT_DEFAULT);
+ FILE_IMGDISPLAY,
+ FILE_SORT_ALPHA);
}
/** \} */
@@ -2199,9 +2197,6 @@ void FONT_OT_unlink(wmOperatorType *ot)
ot->exec = font_unlink_exec;
}
-/**
- * TextBox selection
- */
bool ED_curve_editfont_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index 6eaf8971eb0..45448f18675 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -33,9 +33,9 @@
#include "DNA_scene_types.h"
#include "BKE_context.h"
-#include "BKE_font.h"
#include "BKE_main.h"
#include "BKE_undo_system.h"
+#include "BKE_vfont.h"
#include "DEG_depsgraph.h"
@@ -405,7 +405,6 @@ static void font_undosys_foreach_ID_ref(UndoStep *us_p,
foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
}
-/* Export for ED_undo_sys. */
void ED_font_undosys_type(UndoType *ut)
{
ut->name = "Edit Font";
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 702fd2e375a..8d32eba1766 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -619,6 +619,7 @@ set(ICON_NAMES
outliner_ob_volume
outliner_data_volume
volume_data
+ current_file
home
documents
temp
diff --git a/source/blender/editors/geometry/CMakeLists.txt b/source/blender/editors/geometry/CMakeLists.txt
index 75b334b9ec6..8c920915937 100644
--- a/source/blender/editors/geometry/CMakeLists.txt
+++ b/source/blender/editors/geometry/CMakeLists.txt
@@ -20,19 +20,21 @@ set(INC
../../blenkernel
../../blenlib
../../depsgraph
+ ../../functions
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/guardedalloc
)
set(INC_SYS
)
set(SRC
- geometry_attributes.c
- geometry_ops.c
+ geometry_attributes.cc
+ geometry_ops.cc
- geometry_intern.h
+ geometry_intern.hh
)
set(LIB
diff --git a/source/blender/editors/geometry/geometry_attributes.c b/source/blender/editors/geometry/geometry_attributes.c
deleted file mode 100644
index 5cb491f116a..00000000000
--- a/source/blender/editors/geometry/geometry_attributes.c
+++ /dev/null
@@ -1,182 +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) 2020 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup edgeometry
- */
-
-#include "BKE_attribute.h"
-#include "BKE_context.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-
-#include "DEG_depsgraph.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_object.h"
-
-#include "geometry_intern.h"
-
-/*********************** Attribute Operators ************************/
-
-static bool geometry_attributes_poll(bContext *C)
-{
- Object *ob = ED_object_context(C);
- ID *data = (ob) ? ob->data : NULL;
- return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data)) &&
- BKE_id_attributes_supported(data);
-}
-
-static bool geometry_attributes_remove_poll(bContext *C)
-{
- if (!geometry_attributes_poll(C)) {
- return false;
- }
-
- Object *ob = ED_object_context(C);
- ID *data = (ob) ? ob->data : NULL;
- if (BKE_id_attributes_active_get(data) != NULL) {
- return true;
- }
-
- return false;
-}
-
-static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C,
- PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop),
- bool *r_free)
-{
- if (C == NULL) {
- return DummyRNA_NULL_items;
- }
-
- Object *ob = ED_object_context(C);
- if (ob == NULL) {
- return DummyRNA_NULL_items;
- }
-
- return rna_enum_attribute_domain_itemf(ob->data, r_free);
-}
-
-static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_object_context(C);
- ID *id = ob->data;
-
- char name[MAX_NAME];
- RNA_string_get(op->ptr, "name", name);
- CustomDataType type = (CustomDataType)RNA_enum_get(op->ptr, "data_type");
- AttributeDomain domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain");
- CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports);
-
- if (layer == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- BKE_id_attributes_active_set(id, layer);
-
- DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_GEOM | ND_DATA, id);
-
- return OPERATOR_FINISHED;
-}
-
-void GEOMETRY_OT_attribute_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Geometry Attribute";
- ot->description = "Add attribute to geometry";
- ot->idname = "GEOMETRY_OT_attribute_add";
-
- /* api callbacks */
- ot->poll = geometry_attributes_poll;
- ot->exec = geometry_attribute_add_exec;
- ot->invoke = WM_operator_props_popup_confirm;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- PropertyRNA *prop;
-
- prop = RNA_def_string(ot->srna, "name", "Attribute", MAX_NAME, "Name", "Name of new attribute");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- prop = RNA_def_enum(ot->srna,
- "domain",
- rna_enum_attribute_domain_items,
- ATTR_DOMAIN_POINT,
- "Domain",
- "Type of element that attribute is stored on");
- RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- prop = RNA_def_enum(ot->srna,
- "data_type",
- rna_enum_attribute_type_items,
- CD_PROP_FLOAT,
- "Data Type",
- "Type of data stored in attribute");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-static int geometry_attribute_remove_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_object_context(C);
- ID *id = ob->data;
- CustomDataLayer *layer = BKE_id_attributes_active_get(id);
-
- if (layer == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- if (!BKE_id_attribute_remove(id, layer, op->reports)) {
- return OPERATOR_CANCELLED;
- }
-
- int *active_index = BKE_id_attributes_active_index_p(id);
- if (*active_index > 0) {
- *active_index -= 1;
- }
-
- DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_GEOM | ND_DATA, id);
-
- return OPERATOR_FINISHED;
-}
-
-void GEOMETRY_OT_attribute_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Geometry Attribute";
- ot->description = "Remove attribute from geometry";
- ot->idname = "GEOMETRY_OT_attribute_remove";
-
- /* api callbacks */
- ot->exec = geometry_attribute_remove_exec;
- ot->poll = geometry_attributes_remove_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
new file mode 100644
index 00000000000..56ecd108bba
--- /dev/null
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -0,0 +1,385 @@
+/*
+ * 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) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edgeometry
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_attribute.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_geometry_set.hh"
+#include "BKE_object_deform.h"
+#include "BKE_report.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "ED_object.h"
+
+#include "geometry_intern.hh"
+
+namespace blender::ed::geometry {
+
+using fn::CPPType;
+using fn::GArray;
+using fn::GVArray;
+
+/*********************** Attribute Operators ************************/
+
+static bool geometry_attributes_poll(bContext *C)
+{
+ Object *ob = ED_object_context(C);
+ ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr;
+ return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data)) &&
+ BKE_id_attributes_supported(data);
+}
+
+static bool geometry_attributes_remove_poll(bContext *C)
+{
+ if (!geometry_attributes_poll(C)) {
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr;
+ if (BKE_id_attributes_active_get(data) != nullptr) {
+ return true;
+ }
+
+ return false;
+}
+
+static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ if (C == nullptr) {
+ return DummyRNA_NULL_items;
+ }
+
+ Object *ob = ED_object_context(C);
+ if (ob == nullptr) {
+ return DummyRNA_NULL_items;
+ }
+
+ return rna_enum_attribute_domain_itemf(static_cast<ID *>(ob->data), false, r_free);
+}
+
+static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *id = static_cast<ID *>(ob->data);
+
+ char name[MAX_NAME];
+ RNA_string_get(op->ptr, "name", name);
+ CustomDataType type = (CustomDataType)RNA_enum_get(op->ptr, "data_type");
+ AttributeDomain domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain");
+ CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports);
+
+ if (layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_id_attributes_active_set(id, layer);
+
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ return OPERATOR_FINISHED;
+}
+
+void GEOMETRY_OT_attribute_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Geometry Attribute";
+ ot->description = "Add attribute to geometry";
+ ot->idname = "GEOMETRY_OT_attribute_add";
+
+ /* api callbacks */
+ ot->poll = geometry_attributes_poll;
+ ot->exec = geometry_attribute_add_exec;
+ ot->invoke = WM_operator_props_popup_confirm;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop;
+
+ prop = RNA_def_string(ot->srna, "name", "Attribute", MAX_NAME, "Name", "Name of new attribute");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_enum(ot->srna,
+ "domain",
+ rna_enum_attribute_domain_items,
+ ATTR_DOMAIN_POINT,
+ "Domain",
+ "Type of element that attribute is stored on");
+ RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_enum(ot->srna,
+ "data_type",
+ rna_enum_attribute_type_items,
+ CD_PROP_FLOAT,
+ "Data Type",
+ "Type of data stored in attribute");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+static int geometry_attribute_remove_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *id = static_cast<ID *>(ob->data);
+ CustomDataLayer *layer = BKE_id_attributes_active_get(id);
+
+ if (layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!BKE_id_attribute_remove(id, layer, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int *active_index = BKE_id_attributes_active_index_p(id);
+ if (*active_index > 0) {
+ *active_index -= 1;
+ }
+
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ return OPERATOR_FINISHED;
+}
+
+void GEOMETRY_OT_attribute_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Geometry Attribute";
+ ot->description = "Remove attribute from geometry";
+ ot->idname = "GEOMETRY_OT_attribute_remove";
+
+ /* api callbacks */
+ ot->exec = geometry_attribute_remove_exec;
+ ot->poll = geometry_attributes_remove_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+enum class ConvertAttributeMode {
+ Generic,
+ UVMap,
+ VertexGroup,
+ VertexColor,
+};
+
+static bool geometry_attribute_convert_poll(bContext *C)
+{
+ if (!geometry_attributes_poll(C)) {
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ ID *data = static_cast<ID *>(ob->data);
+ if (GS(data->name) != ID_ME) {
+ return false;
+ }
+ CustomDataLayer *layer = BKE_id_attributes_active_get(data);
+ if (layer == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *ob_data = static_cast<ID *>(ob->data);
+ CustomDataLayer *layer = BKE_id_attributes_active_get(ob_data);
+ const std::string name = layer->name;
+
+ const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>(
+ RNA_enum_get(op->ptr, "mode"));
+
+ Mesh *mesh = reinterpret_cast<Mesh *>(ob_data);
+ MeshComponent mesh_component;
+ mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+
+ /* General conversion steps are always the same:
+ * 1. Convert old data to right domain and data type.
+ * 2. Copy the data into a new array so that it does not depend on the old attribute anymore.
+ * 3. Delete the old attribute.
+ * 4. Create a new attribute based on the previously copied data. */
+ switch (mode) {
+ case ConvertAttributeMode::Generic: {
+ const AttributeDomain dst_domain = static_cast<AttributeDomain>(
+ RNA_enum_get(op->ptr, "domain"));
+ const CustomDataType dst_type = static_cast<CustomDataType>(
+ RNA_enum_get(op->ptr, "data_type"));
+
+ if (ELEM(dst_type, CD_PROP_STRING, CD_MLOOPCOL)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot convert to the selected type");
+ return OPERATOR_CANCELLED;
+ }
+
+ GVArray src_varray = mesh_component.attribute_get_for_read(name, dst_domain, dst_type);
+ const CPPType &cpp_type = src_varray.type();
+ void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__);
+ src_varray.materialize_to_uninitialized(new_data);
+ mesh_component.attribute_try_delete(name);
+ mesh_component.attribute_try_create(name, dst_domain, dst_type, AttributeInitMove(new_data));
+ break;
+ }
+ case ConvertAttributeMode::UVMap: {
+ MLoopUV *dst_uvs = static_cast<MLoopUV *>(
+ MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopUV), __func__));
+ VArray<float2> src_varray = mesh_component.attribute_get_for_read<float2>(
+ name, ATTR_DOMAIN_CORNER, {0.0f, 0.0f});
+ for (const int i : IndexRange(mesh->totloop)) {
+ copy_v2_v2(dst_uvs[i].uv, src_varray[i]);
+ }
+ mesh_component.attribute_try_delete(name);
+ CustomData_add_layer_named(
+ &mesh->ldata, CD_MLOOPUV, CD_ASSIGN, dst_uvs, mesh->totloop, name.c_str());
+ break;
+ }
+ case ConvertAttributeMode::VertexColor: {
+ MLoopCol *dst_colors = static_cast<MLoopCol *>(
+ MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopCol), __func__));
+ VArray<ColorGeometry4f> src_varray = mesh_component.attribute_get_for_read<ColorGeometry4f>(
+ name, ATTR_DOMAIN_CORNER, ColorGeometry4f{0.0f, 0.0f, 0.0f, 1.0f});
+ for (const int i : IndexRange(mesh->totloop)) {
+ ColorGeometry4b encoded_color = src_varray[i].encode();
+ copy_v4_v4_uchar(&dst_colors[i].r, &encoded_color.r);
+ }
+ mesh_component.attribute_try_delete(name);
+ CustomData_add_layer_named(
+ &mesh->ldata, CD_MLOOPCOL, CD_ASSIGN, dst_colors, mesh->totloop, name.c_str());
+ break;
+ }
+ case ConvertAttributeMode::VertexGroup: {
+ Array<float> src_weights(mesh->totvert);
+ VArray<float> src_varray = mesh_component.attribute_get_for_read<float>(
+ name, ATTR_DOMAIN_POINT, 0.0f);
+ src_varray.materialize(src_weights);
+ mesh_component.attribute_try_delete(name);
+
+ bDeformGroup *defgroup = BKE_object_defgroup_new(ob, name.c_str());
+ const int defgroup_index = BLI_findindex(BKE_id_defgroup_list_get(&mesh->id), defgroup);
+ MDeformVert *dverts = BKE_object_defgroup_data_create(&mesh->id);
+ for (const int i : IndexRange(mesh->totvert)) {
+ const float weight = src_weights[i];
+ if (weight > 0.0f) {
+ BKE_defvert_add_index_notest(dverts + i, defgroup_index, weight);
+ }
+ }
+ break;
+ }
+ }
+
+ int *active_index = BKE_id_attributes_active_index_p(&mesh->id);
+ if (*active_index > 0) {
+ *active_index -= 1;
+ }
+
+ DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id);
+
+ return OPERATOR_FINISHED;
+}
+
+static void geometry_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+
+ uiItemR(layout, op->ptr, "mode", 0, nullptr, ICON_NONE);
+
+ const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>(
+ RNA_enum_get(op->ptr, "mode"));
+
+ if (mode == ConvertAttributeMode::Generic) {
+ uiItemR(layout, op->ptr, "domain", 0, nullptr, ICON_NONE);
+ uiItemR(layout, op->ptr, "data_type", 0, nullptr, ICON_NONE);
+ }
+}
+
+static int geometry_attribute_convert_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ return WM_operator_props_dialog_popup(C, op, 300);
+}
+
+void GEOMETRY_OT_attribute_convert(wmOperatorType *ot)
+{
+ ot->name = "Convert Attribute";
+ ot->description = "Change how the attribute is stored";
+ ot->idname = "GEOMETRY_OT_attribute_convert";
+
+ ot->invoke = geometry_attribute_convert_invoke;
+ ot->exec = geometry_attribute_convert_exec;
+ ot->poll = geometry_attribute_convert_poll;
+ ot->ui = geometry_attribute_convert_ui;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ static EnumPropertyItem mode_items[] = {
+ {int(ConvertAttributeMode::Generic), "GENERIC", 0, "Generic", ""},
+ {int(ConvertAttributeMode::UVMap), "UV_MAP", 0, "UV Map", ""},
+ {int(ConvertAttributeMode::VertexGroup), "VERTEX_GROUP", 0, "Vertex Group", ""},
+ {int(ConvertAttributeMode::VertexColor), "VERTEX_COLOR", 0, "Vertex Color", ""},
+ {0, nullptr, 0, nullptr, nullptr},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_enum(
+ ot->srna, "mode", mode_items, static_cast<int>(ConvertAttributeMode::Generic), "Mode", "");
+
+ prop = RNA_def_enum(ot->srna,
+ "domain",
+ rna_enum_attribute_domain_items,
+ ATTR_DOMAIN_POINT,
+ "Domain",
+ "Which geometry element to move the attribute to");
+ RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf);
+
+ RNA_def_enum(
+ ot->srna, "data_type", rna_enum_attribute_type_items, CD_PROP_FLOAT, "Data Type", "");
+}
+
+} // namespace blender::ed::geometry
diff --git a/source/blender/editors/geometry/geometry_intern.h b/source/blender/editors/geometry/geometry_intern.hh
index 8a0f9294722..30a2a1d6eb1 100644
--- a/source/blender/editors/geometry/geometry_intern.h
+++ b/source/blender/editors/geometry/geometry_intern.hh
@@ -25,6 +25,11 @@
struct wmOperatorType;
-/* *** geometry_attributes.c *** */
+namespace blender::ed::geometry {
+
+/* *** geometry_attributes.cc *** */
void GEOMETRY_OT_attribute_add(struct wmOperatorType *ot);
void GEOMETRY_OT_attribute_remove(struct wmOperatorType *ot);
+void GEOMETRY_OT_attribute_convert(struct wmOperatorType *ot);
+
+} // namespace blender::ed::geometry
diff --git a/source/blender/editors/geometry/geometry_ops.c b/source/blender/editors/geometry/geometry_ops.cc
index ed0aeda731b..8933b2a7f00 100644
--- a/source/blender/editors/geometry/geometry_ops.c
+++ b/source/blender/editors/geometry/geometry_ops.cc
@@ -25,12 +25,15 @@
#include "ED_geometry.h"
-#include "geometry_intern.h"
+#include "geometry_intern.hh"
/**************************** registration **********************************/
void ED_operatortypes_geometry(void)
{
+ using namespace blender::ed::geometry;
+
WM_operatortype_append(GEOMETRY_OT_attribute_add);
WM_operatortype_append(GEOMETRY_OT_attribute_remove);
+ WM_operatortype_append(GEOMETRY_OT_attribute_convert);
}
diff --git a/source/blender/editors/gizmo_library/gizmo_draw_utils.c b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
index 2ec287a62e9..1179c9140e2 100644
--- a/source/blender/editors/gizmo_library/gizmo_draw_utils.c
+++ b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
@@ -44,9 +44,6 @@
/* own includes */
#include "gizmo_library_intern.h"
-/**
- * Main draw call for GizmoGeomInfo data
- */
void wm_gizmo_geometryinfo_draw(const GizmoGeomInfo *info,
const bool UNUSED(select),
const float color[4])
diff --git a/source/blender/editors/gizmo_library/gizmo_library_intern.h b/source/blender/editors/gizmo_library/gizmo_library_intern.h
index f3670708543..4a481f4bc59 100644
--- a/source/blender/editors/gizmo_library/gizmo_library_intern.h
+++ b/source/blender/editors/gizmo_library/gizmo_library_intern.h
@@ -52,22 +52,19 @@ typedef struct GizmoInteraction {
float precision_offset;
} GizmoInteraction;
-float gizmo_offset_from_value(GizmoCommonData *data,
- const float value,
- const bool constrained,
- const bool inverted);
+float gizmo_offset_from_value(GizmoCommonData *data, float value, bool constrained, bool inverted);
float gizmo_value_from_offset(GizmoCommonData *data,
GizmoInteraction *inter,
- const float offset,
- const bool constrained,
- const bool inverted,
- const bool use_precision);
+ float offset,
+ bool constrained,
+ bool inverted,
+ bool use_precision);
void gizmo_property_data_update(struct wmGizmo *gz,
GizmoCommonData *data,
wmGizmoProperty *gz_prop,
- const bool constrained,
- const bool inverted);
+ bool constrained,
+ bool inverted);
void gizmo_property_value_reset(bContext *C,
const struct wmGizmo *gz,
@@ -76,8 +73,12 @@ void gizmo_property_value_reset(bContext *C,
/* -------------------------------------------------------------------- */
-void gizmo_color_get(const struct wmGizmo *gz, const bool highlight, float r_color[4]);
+void gizmo_color_get(const struct wmGizmo *gz, bool highlight, float r_color[4]);
+/**
+ * Takes mouse coordinates and returns them in relation to the gizmo.
+ * Both 2D & 3D supported, use so we can use 2D gizmos in the 3D view.
+ */
bool gizmo_window_project_2d(bContext *C,
const struct wmGizmo *gz,
const float mval[2],
@@ -93,8 +94,11 @@ bool gizmo_window_project_3d(
#include "gizmo_geometry.h"
+/**
+ * Main draw call for #GizmoGeomInfo data
+ */
void wm_gizmo_geometryinfo_draw(const struct GizmoGeomInfo *info,
- const bool select,
+ bool select,
const float color[4]);
void wm_gizmo_vec_draw(
const float color[4], const float (*verts)[3], uint vert_count, uint pos, uint primitive_type);
diff --git a/source/blender/editors/gizmo_library/gizmo_library_utils.c b/source/blender/editors/gizmo_library/gizmo_library_utils.c
index a0db2a8e627..0237c6062d1 100644
--- a/source/blender/editors/gizmo_library/gizmo_library_utils.c
+++ b/source/blender/editors/gizmo_library/gizmo_library_utils.c
@@ -175,10 +175,6 @@ void gizmo_color_get(const wmGizmo *gz, const bool highlight, float r_col[4])
/* -------------------------------------------------------------------- */
-/**
- * Takes mouse coordinates and returns them in relation to the gizmo.
- * Both 2D & 3D supported, use so we can use 2D gizmos in the 3D view.
- */
bool gizmo_window_project_2d(bContext *C,
const struct wmGizmo *gz,
const float mval[2],
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
index d506af4450a..3362cf9732e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -448,11 +448,6 @@ static void gizmo_arrow_exit(bContext *C, wmGizmo *gz, const bool cancel)
/** \name Arrow Gizmo API
* \{ */
-/**
- * Define a custom property UI range
- *
- * \note Needs to be called before WM_gizmo_target_property_def_rna!
- */
void ED_gizmo_arrow3d_set_ui_range(wmGizmo *gz, const float min, const float max)
{
ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
@@ -467,11 +462,6 @@ void ED_gizmo_arrow3d_set_ui_range(wmGizmo *gz, const float min, const float max
arrow->data.is_custom_range_set = true;
}
-/**
- * Define a custom factor for arrow min/max distance
- *
- * \note Needs to be called before WM_gizmo_target_property_def_rna!
- */
void ED_gizmo_arrow3d_set_range_fac(wmGizmo *gz, const float range_fac)
{
ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
index f286d3930e2..553ea4bbb6e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -59,6 +59,10 @@
#include "../gizmo_geometry.h"
#include "../gizmo_library_intern.h"
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
typedef struct ButtonGizmo2D {
wmGizmo gizmo;
bool is_init;
@@ -69,7 +73,11 @@ typedef struct ButtonGizmo2D {
#define CIRCLE_RESOLUTION 32
+/** \} */
+
/* -------------------------------------------------------------------- */
+/** \name Internal API
+ * \{ */
static void button2d_geom_draw_backdrop(const wmGizmo *gz,
const float color[4],
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
index 6fd06b47656..34d3f737f58 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
@@ -98,65 +98,13 @@ static bool gizmo_calc_rect_view_margin(const wmGizmo *gz, const float dims[2],
zero_v2(margin);
return false;
}
+
margin[0] = ((handle_size * scale_xy[0]));
margin[1] = ((handle_size * scale_xy[1]));
return true;
}
/* -------------------------------------------------------------------- */
-
-static void gizmo_rect_pivot_from_scale_part(int part, float r_pt[2], bool r_constrain_axis[2])
-{
- bool x = true, y = true;
- switch (part) {
- case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X: {
- ARRAY_SET_ITEMS(r_pt, 0.5, 0.0);
- x = false;
- break;
- }
- case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X: {
- ARRAY_SET_ITEMS(r_pt, -0.5, 0.0);
- x = false;
- break;
- }
- case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y: {
- ARRAY_SET_ITEMS(r_pt, 0.0, 0.5);
- y = false;
- break;
- }
- case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y: {
- ARRAY_SET_ITEMS(r_pt, 0.0, -0.5);
- y = false;
- break;
- }
- case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y: {
- ARRAY_SET_ITEMS(r_pt, 0.5, 0.5);
- x = y = false;
- break;
- }
- case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y: {
- ARRAY_SET_ITEMS(r_pt, 0.5, -0.5);
- x = y = false;
- break;
- }
- case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y: {
- ARRAY_SET_ITEMS(r_pt, -0.5, 0.5);
- x = y = false;
- break;
- }
- case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y: {
- ARRAY_SET_ITEMS(r_pt, -0.5, -0.5);
- x = y = false;
- break;
- }
- default:
- BLI_assert(0);
- }
- r_constrain_axis[0] = x;
- r_constrain_axis[1] = y;
-}
-
-/* -------------------------------------------------------------------- */
/** \name Box Draw Style
*
* Useful for 3D views, see: #ED_GIZMO_CAGE2D_STYLE_BOX
@@ -400,6 +348,7 @@ static void cage2d_draw_box_interaction(const float color[4],
ARRAY_SET_ITEMS(verts[1], r_rotate.xmin, r_rotate.ymax);
ARRAY_SET_ITEMS(verts[2], r_rotate.xmax, r_rotate.ymax);
ARRAY_SET_ITEMS(verts[3], r_rotate.xmax, r_rotate.ymin);
+
verts_len = 4;
if (is_solid) {
prim_type = GPU_PRIM_TRI_FAN;
@@ -769,10 +718,10 @@ static int gizmo_cage2d_get_cursor(wmGizmo *gz)
return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X:
- return WM_CURSOR_X_MOVE;
+ return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y:
- return WM_CURSOR_Y_MOVE;
+ return WM_CURSOR_NSEW_SCROLL;
/* TODO: diagonal cursor. */
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y:
@@ -937,6 +886,57 @@ static int gizmo_cage2d_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
+static void gizmo_rect_pivot_from_scale_part(int part, float r_pt[2], bool r_constrain_axis[2])
+{
+ bool x = true, y = true;
+ switch (part) {
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X: {
+ ARRAY_SET_ITEMS(r_pt, 0.5, 0.0);
+ x = false;
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X: {
+ ARRAY_SET_ITEMS(r_pt, -0.5, 0.0);
+ x = false;
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y: {
+ ARRAY_SET_ITEMS(r_pt, 0.0, 0.5);
+ y = false;
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y: {
+ ARRAY_SET_ITEMS(r_pt, 0.0, -0.5);
+ y = false;
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y: {
+ ARRAY_SET_ITEMS(r_pt, 0.5, 0.5);
+ x = y = false;
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y: {
+ ARRAY_SET_ITEMS(r_pt, 0.5, -0.5);
+ x = y = false;
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y: {
+ ARRAY_SET_ITEMS(r_pt, -0.5, 0.5);
+ x = y = false;
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y: {
+ ARRAY_SET_ITEMS(r_pt, -0.5, -0.5);
+ x = y = false;
+ break;
+ }
+ default:
+ BLI_assert(0);
+ }
+ r_constrain_axis[0] = x;
+ r_constrain_axis[1] = y;
+}
+
static int gizmo_cage2d_modal(bContext *C,
wmGizmo *gz,
const wmEvent *event,
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
index 07117c0153b..aed58e31798 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
@@ -220,7 +220,7 @@ static void cage3d_draw_circle_wire(const float r[3],
immUniform2fv("viewportSize", &viewport[2]);
immUniform1f("lineWidth", line_width * U.pixelsize);
- imm_draw_cube_wire_3d(pos, (float[3]){0}, r);
+ imm_draw_cube_wire_3d(pos, (const float[3]){0}, r);
#if 0
if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE) {
diff --git a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
index 6345cd3525a..d4d4c889209 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
@@ -307,7 +307,7 @@ static void dial_ghostarc_get_angles(const wmGizmo *gz,
{
DialInteraction *inter = gz->interaction_data;
const RegionView3D *rv3d = region->regiondata;
- const float mval[2] = {event->x - region->winrct.xmin, event->y - region->winrct.ymin};
+ const float mval[2] = {event->xy[0] - region->winrct.xmin, event->xy[1] - region->winrct.ymin};
/* We might need to invert the direction of the angles. */
float view_vec[3], axis_vec[3];
diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
index 68322ed56af..ec4837aec3c 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -289,6 +289,8 @@ static int gizmo_move_modal(bContext *C,
if (ED_transform_snap_object_project_view3d(
inter->snap_context_v3d,
CTX_data_ensure_evaluated_depsgraph(C),
+ region,
+ CTX_wm_view3d(C),
(SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE),
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
@@ -381,8 +383,7 @@ static int gizmo_move_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
if (area) {
switch (area->spacetype) {
case SPACE_VIEW3D: {
- inter->snap_context_v3d = ED_transform_snap_object_context_create_view3d(
- CTX_data_scene(C), 0, CTX_wm_region(C), CTX_wm_view3d(C));
+ inter->snap_context_v3d = ED_transform_snap_object_context_create(CTX_data_scene(C), 0);
break;
}
default:
diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
index ae2cc05c01b..b618aa41f4c 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
@@ -27,422 +27,119 @@
* \brief Snap gizmo which exposes the location, normal and index in the props.
*/
+#include "MEM_guardedalloc.h"
+
#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "DNA_scene_types.h"
-
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
-#include "GPU_immediate.h"
-#include "GPU_state.h"
-
#include "ED_gizmo_library.h"
#include "ED_screen.h"
#include "ED_transform_snap_object_context.h"
#include "ED_view3d.h"
-#include "UI_resources.h" /* icons */
+#include "UI_resources.h"
#include "RNA_access.h"
#include "RNA_define.h"
-#include "DEG_depsgraph_query.h"
-
#include "WM_api.h"
-#include "WM_types.h"
/* own includes */
-#include "../gizmo_geometry.h"
#include "../gizmo_library_intern.h"
typedef struct SnapGizmo3D {
wmGizmo gizmo;
-
- /* We could have other snap contexts, for now only support 3D view. */
- SnapObjectContext *snap_context_v3d;
-
- /* Copy of the parameters of the last event state in order to detect updates. */
- struct {
- int x;
- int y;
-#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
- short shift, ctrl, alt, oskey;
-#endif
- } last_eventstate;
-
-#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
- wmKeyMap *keymap;
- int snap_on;
- bool invert_snap;
-#endif
-
- /* Setup. */
- eSnapGizmo flag;
- float *prevpoint;
- float prevpoint_stack[3];
- short snap_elem_force;
-
- /* Return values. */
- short snap_elem;
- float loc[3];
- float nor[3];
- int elem_index[3];
-
- /** Enabled when snap is activated, even if it didn't find anything. */
- bool is_enabled;
+ V3DSnapCursorState *snap_state;
} SnapGizmo3D;
-/* Checks if the current event is different from the one captured in the last update. */
-static bool eventstate_has_changed(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm)
-{
- if (wm && wm->winactive) {
- const wmEvent *event = wm->winactive->eventstate;
- if ((event->x != snap_gizmo->last_eventstate.x) ||
- (event->y != snap_gizmo->last_eventstate.y)) {
- return true;
- }
-#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
- if (!(snap_gizmo->flag & ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE)) {
- if ((event->ctrl != snap_gizmo->last_eventstate.ctrl) ||
- (event->shift != snap_gizmo->last_eventstate.shift) ||
- (event->alt != snap_gizmo->last_eventstate.alt) ||
- (event->oskey != snap_gizmo->last_eventstate.oskey)) {
- return true;
- }
- }
-#endif
- }
- return false;
-}
-
-/* Copies the current eventstate. */
-static void eventstate_save_xy(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm)
-{
- if (wm && wm->winactive) {
- const wmEvent *event = wm->winactive->eventstate;
- snap_gizmo->last_eventstate.x = event->x;
- snap_gizmo->last_eventstate.y = event->y;
- }
-}
-
-#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
-static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm)
-{
- if (!wm || !wm->winactive) {
- return false;
- }
-
- const wmEvent *event = wm->winactive->eventstate;
- if ((event->ctrl == snap_gizmo->last_eventstate.ctrl) &&
- (event->shift == snap_gizmo->last_eventstate.shift) &&
- (event->alt == snap_gizmo->last_eventstate.alt) &&
- (event->oskey == snap_gizmo->last_eventstate.oskey)) {
- /* Nothing has changed. */
- return snap_gizmo->invert_snap;
- }
-
- /* Save new eventstate. */
- snap_gizmo->last_eventstate.ctrl = event->ctrl;
- snap_gizmo->last_eventstate.shift = event->shift;
- snap_gizmo->last_eventstate.alt = event->alt;
- snap_gizmo->last_eventstate.oskey = event->oskey;
-
- const int snap_on = snap_gizmo->snap_on;
-
- wmKeyMap *keymap = WM_keymap_active(wm, snap_gizmo->keymap);
- for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
- if (kmi->flag & KMI_INACTIVE) {
- continue;
- }
-
- if (kmi->propvalue == snap_on) {
- if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) && event->ctrl) ||
- (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) && event->shift) ||
- (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && event->alt) ||
- ((kmi->type == EVT_OSKEY) && event->oskey)) {
- return true;
- }
- }
- }
- return false;
-}
-#endif
-
-static short snap_gizmo_snap_elements(SnapGizmo3D *snap_gizmo)
+static void snap_gizmo_snap_elements_update(SnapGizmo3D *snap_gizmo)
{
- int snap_elements = snap_gizmo->snap_elem_force;
+ wmGizmoProperty *gz_prop_snap;
+ gz_prop_snap = WM_gizmo_target_property_find(&snap_gizmo->gizmo, "snap_elements");
- wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(&snap_gizmo->gizmo, "snap_elements");
- if (gz_prop->prop) {
- snap_elements |= RNA_property_enum_get(&gz_prop->ptr, gz_prop->prop);
+ if (gz_prop_snap->prop) {
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ snap_state->snap_elem_force |= RNA_property_enum_get(&gz_prop_snap->ptr, gz_prop_snap->prop);
}
- snap_elements &= (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
- SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR);
- return (ushort)snap_elements;
}
/* -------------------------------------------------------------------- */
/** \name ED_gizmo_library specific API
* \{ */
-void ED_gizmotypes_snap_3d_draw_util(RegionView3D *rv3d,
- const float loc_prev[3],
- const float loc_curr[3],
- const float normal[3],
- const uchar color_line[4],
- const uchar color_point[4],
- const short snap_elem_type)
-{
- if (!loc_prev && !loc_curr) {
- return;
- }
-
- float view_inv[4][4];
- copy_m4_m4(view_inv, rv3d->viewinv);
-
- /* The size of the circle is larger than the vertex size.
- * This prevents a drawing overlaps the other. */
- float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
-
- if (loc_curr) {
- immUniformColor4ubv(color_point);
- imm_drawcircball(loc_curr, ED_view3d_pixel_size(rv3d, loc_curr) * radius, view_inv, pos);
-
- /* draw normal if needed */
- if (normal) {
- immBegin(GPU_PRIM_LINES, 2);
- immVertex3fv(pos, loc_curr);
- immVertex3f(pos, loc_curr[0] + normal[0], loc_curr[1] + normal[1], loc_curr[2] + normal[2]);
- immEnd();
- }
- }
-
- if (loc_prev) {
- /* Draw an "X" indicating where the previous snap point is.
- * This is useful for indicating perpendicular snap. */
-
- /* v1, v2, v3 and v4 indicate the coordinates of the ends of the "X". */
- float vx[3], vy[3], v1[3], v2[3], v3[3], v4[4];
-
- /* Multiply by 0.75f so that the final size of the "X" is close to that of
- * the circle.
- * (A closer value is 0.7071f, but we don't need to be exact here). */
- float x_size = 0.75f * radius * ED_view3d_pixel_size(rv3d, loc_prev);
-
- mul_v3_v3fl(vx, view_inv[0], x_size);
- mul_v3_v3fl(vy, view_inv[1], x_size);
-
- add_v3_v3v3(v1, vx, vy);
- sub_v3_v3v3(v2, vx, vy);
- negate_v3_v3(v3, v1);
- negate_v3_v3(v4, v2);
-
- add_v3_v3(v1, loc_prev);
- add_v3_v3(v2, loc_prev);
- add_v3_v3(v3, loc_prev);
- add_v3_v3(v4, loc_prev);
-
- immUniformColor4ubv(color_line);
- immBegin(GPU_PRIM_LINES, 4);
- immVertex3fv(pos, v3);
- immVertex3fv(pos, v1);
- immVertex3fv(pos, v4);
- immVertex3fv(pos, v2);
- immEnd();
-
- if (loc_curr && (snap_elem_type & SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
- /* Dashed line. */
- immUnbindProgram();
-
- immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- immUniform1f("dash_width", 6.0f * U.pixelsize);
- immUniform1f("dash_factor", 1.0f / 4.0f);
- immUniformColor4ubv(color_line);
-
- immBegin(GPU_PRIM_LINES, 2);
- immVertex3fv(pos, loc_prev);
- immVertex3fv(pos, loc_curr);
- immEnd();
- }
- }
-
- immUnbindProgram();
-}
-
-SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(Scene *scene,
- const ARegion *region,
- const View3D *v3d,
- wmGizmo *gz)
+SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(Scene *scene, wmGizmo *UNUSED(gz))
{
- SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz;
- if (snap_gizmo->snap_context_v3d == NULL) {
- snap_gizmo->snap_context_v3d = ED_transform_snap_object_context_create_view3d(
- scene, 0, region, v3d);
- }
- return snap_gizmo->snap_context_v3d;
+ return ED_view3d_cursor_snap_context_ensure(scene);
}
-void ED_gizmotypes_snap_3d_flag_set(struct wmGizmo *gz, eSnapGizmo flag)
+void ED_gizmotypes_snap_3d_flag_set(struct wmGizmo *UNUSED(gz), int flag)
{
- SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz;
- snap_gizmo->flag |= flag;
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ snap_state->flag |= flag;
}
-void ED_gizmotypes_snap_3d_flag_clear(struct wmGizmo *gz, eSnapGizmo flag)
+void ED_gizmotypes_snap_3d_flag_clear(struct wmGizmo *UNUSED(gz), int flag)
{
- SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz;
- snap_gizmo->flag &= ~flag;
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ snap_state->flag &= ~flag;
}
-bool ED_gizmotypes_snap_3d_flag_test(struct wmGizmo *gz, eSnapGizmo flag)
+bool ED_gizmotypes_snap_3d_flag_test(struct wmGizmo *UNUSED(gz), int flag)
{
- SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz;
- return (snap_gizmo->flag & flag) != 0;
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ return (snap_state->flag & flag) != 0;
}
-bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz)
+bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *UNUSED(gz))
{
-#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
- SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz;
- return snap_gizmo->invert_snap;
-#else
- return false;
-#endif
+ V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(NULL, NULL, 0, 0);
+ return snap_data->is_snap_invert;
}
-bool ED_gizmotypes_snap_3d_is_enabled(const wmGizmo *gz)
+bool ED_gizmotypes_snap_3d_is_enabled(const wmGizmo *UNUSED(gz))
{
- const SnapGizmo3D *snap_gizmo = (const SnapGizmo3D *)gz;
- return snap_gizmo->is_enabled;
+ V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(NULL, NULL, 0, 0);
+ return snap_data->is_enabled;
}
-short ED_gizmotypes_snap_3d_update(wmGizmo *gz,
- struct Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- const wmWindowManager *wm,
- const float mval_fl[2])
+void ED_gizmotypes_snap_3d_data_get(const struct bContext *C,
+ wmGizmo *UNUSED(gz),
+ float r_loc[3],
+ float r_nor[3],
+ int r_elem_index[3],
+ int *r_snap_elem)
{
- SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz;
- snap_gizmo->is_enabled = false;
-
- Scene *scene = DEG_get_input_scene(depsgraph);
-
-#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
- if (!(snap_gizmo->flag & ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE)) {
- snap_gizmo->invert_snap = invert_snap(snap_gizmo, wm);
-
- const ToolSettings *ts = scene->toolsettings;
- if (snap_gizmo->invert_snap != !(ts->snap_flag & SCE_SNAP)) {
- snap_gizmo->snap_elem = 0;
- return 0;
+ V3DSnapCursorData *snap_data = NULL;
+ if (C) {
+ /* Snap values are updated too late at the cursor. Be sure to update ahead of time. */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ const wmEvent *event = wm->winactive ? wm->winactive->eventstate : NULL;
+ if (event) {
+ ARegion *region = CTX_wm_region(C);
+ int x = event->xy[0] - region->winrct.xmin;
+ int y = event->xy[1] - region->winrct.ymin;
+ snap_data = ED_view3d_cursor_snap_data_get(NULL, C, x, y);
}
}
-#endif
- eventstate_save_xy(snap_gizmo, wm);
-
- snap_gizmo->is_enabled = true;
-
- float co[3], no[3];
- short snap_elem = 0;
- int snap_elem_index[3] = {-1, -1, -1};
- int index = -1;
-
- ushort snap_elements = snap_gizmo_snap_elements(snap_gizmo);
-
- if (snap_elements) {
- float prev_co[3] = {0.0f};
- if (snap_gizmo->prevpoint) {
- copy_v3_v3(prev_co, snap_gizmo->prevpoint);
- }
- else {
- snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR;
- }
-
- eSnapSelect snap_select = (snap_gizmo->flag & ED_SNAPGIZMO_SNAP_ONLY_ACTIVE) ?
- SNAP_ONLY_ACTIVE :
- SNAP_ALL;
-
- eSnapEditType edit_mode_type = (snap_gizmo->flag & ED_SNAPGIZMO_SNAP_EDIT_GEOM_FINAL) ?
- SNAP_GEOM_FINAL :
- (snap_gizmo->flag & ED_SNAPGIZMO_SNAP_EDIT_GEOM_CAGE) ?
- SNAP_GEOM_CAGE :
- SNAP_GEOM_EDIT;
-
- bool use_occlusion_test = (snap_gizmo->flag & ED_SNAPGIZMO_OCCLUSION_ALWAYS_TRUE) ? false :
- true;
-
- float dist_px = 12.0f * U.pixelsize;
-
- ED_gizmotypes_snap_3d_context_ensure(scene, region, v3d, gz);
- snap_elem = ED_transform_snap_object_project_view3d_ex(
- snap_gizmo->snap_context_v3d,
- depsgraph,
- snap_elements,
- &(const struct SnapObjectParams){
- .snap_select = snap_select,
- .edit_mode_type = edit_mode_type,
- .use_occlusion_test = use_occlusion_test,
- },
- mval_fl,
- prev_co,
- &dist_px,
- co,
- no,
- &index,
- NULL,
- NULL);
+ if (!snap_data) {
+ snap_data = ED_view3d_cursor_snap_data_get(NULL, NULL, 0, 0);
}
- if (snap_elem == 0) {
- RegionView3D *rv3d = region->regiondata;
- ED_view3d_win_to_3d(v3d, region, rv3d->ofs, mval_fl, co);
- zero_v3(no);
- }
- else if (snap_elem == SCE_SNAP_MODE_VERTEX) {
- snap_elem_index[0] = index;
- }
- else if (snap_elem &
- (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
- snap_elem_index[1] = index;
- }
- else if (snap_elem == SCE_SNAP_MODE_FACE) {
- snap_elem_index[2] = index;
- }
-
- snap_gizmo->snap_elem = snap_elem;
- copy_v3_v3(snap_gizmo->loc, co);
- copy_v3_v3(snap_gizmo->nor, no);
- copy_v3_v3_int(snap_gizmo->elem_index, snap_elem_index);
-
- return snap_elem;
-}
-
-void ED_gizmotypes_snap_3d_data_get(
- wmGizmo *gz, float r_loc[3], float r_nor[3], int r_elem_index[3], int *r_snap_elem)
-{
- SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz;
- BLI_assert(snap_gizmo->is_enabled);
if (r_loc) {
- copy_v3_v3(r_loc, snap_gizmo->loc);
+ copy_v3_v3(r_loc, snap_data->loc);
}
if (r_nor) {
- copy_v3_v3(r_nor, snap_gizmo->nor);
+ copy_v3_v3(r_nor, snap_data->nor);
}
if (r_elem_index) {
- copy_v3_v3_int(r_elem_index, snap_gizmo->elem_index);
+ copy_v3_v3_int(r_elem_index, snap_data->elem_index);
}
if (r_snap_elem) {
- *r_snap_elem = snap_gizmo->snap_elem;
+ *r_snap_elem = snap_data->snap_elem;
}
}
@@ -452,116 +149,69 @@ void ED_gizmotypes_snap_3d_data_get(
/** \name RNA callbacks
* \{ */
-/* Based on 'rna_GizmoProperties_find_operator'. */
-static struct SnapGizmo3D *gizmo_snap_rna_find_operator(PointerRNA *ptr)
-{
- IDProperty *properties = ptr->data;
- for (bScreen *screen = G_MAIN->screens.first; screen; screen = screen->id.next) {
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- if (area->spacetype != SPACE_VIEW3D) {
- continue;
- }
- LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
- if (region->regiontype == RGN_TYPE_WINDOW && region->gizmo_map) {
- wmGizmoMap *gzmap = region->gizmo_map;
- LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, WM_gizmomap_group_list(gzmap)) {
- LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
- if (gz->properties == properties) {
- return (SnapGizmo3D *)gz;
- }
- }
- }
- }
- }
- }
- }
- return NULL;
-}
-
-static int gizmo_snap_rna_snap_elements_force_get_fn(struct PointerRNA *ptr,
+static int gizmo_snap_rna_snap_elements_force_get_fn(struct PointerRNA *UNUSED(ptr),
struct PropertyRNA *UNUSED(prop))
{
- SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr);
- if (snap_gizmo) {
- return snap_gizmo->snap_elem_force;
- }
- return 0;
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ return snap_state->snap_elem_force;
}
-static void gizmo_snap_rna_snap_elements_force_set_fn(struct PointerRNA *ptr,
+static void gizmo_snap_rna_snap_elements_force_set_fn(struct PointerRNA *UNUSED(ptr),
struct PropertyRNA *UNUSED(prop),
int value)
{
- SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr);
- if (snap_gizmo) {
- snap_gizmo->snap_elem_force = (short)value;
- }
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ snap_state->snap_elem_force = (short)value;
}
-static void gizmo_snap_rna_prevpoint_get_fn(struct PointerRNA *ptr,
+static void gizmo_snap_rna_prevpoint_get_fn(struct PointerRNA *UNUSED(ptr),
struct PropertyRNA *UNUSED(prop),
float *values)
{
- SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr);
- if (snap_gizmo) {
- copy_v3_v3(values, snap_gizmo->prevpoint_stack);
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ if (snap_state->prevpoint) {
+ copy_v3_v3(values, snap_state->prevpoint);
}
}
-static void gizmo_snap_rna_prevpoint_set_fn(struct PointerRNA *ptr,
+static void gizmo_snap_rna_prevpoint_set_fn(struct PointerRNA *UNUSED(ptr),
struct PropertyRNA *UNUSED(prop),
const float *values)
{
- SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr);
- if (snap_gizmo) {
- if (values) {
- copy_v3_v3(snap_gizmo->prevpoint_stack, values);
- snap_gizmo->prevpoint = snap_gizmo->prevpoint_stack;
- }
- else {
- snap_gizmo->prevpoint = NULL;
- }
- }
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ ED_view3d_cursor_snap_prevpoint_set(snap_state, values);
}
-static void gizmo_snap_rna_location_get_fn(struct PointerRNA *ptr,
+static void gizmo_snap_rna_location_get_fn(struct PointerRNA *UNUSED(ptr),
struct PropertyRNA *UNUSED(prop),
float *values)
{
- SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr);
- if (snap_gizmo) {
- copy_v3_v3(values, snap_gizmo->loc);
- }
+ V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(NULL, NULL, 0, 0);
+ copy_v3_v3(values, snap_data->loc);
}
-static void gizmo_snap_rna_location_set_fn(struct PointerRNA *ptr,
+static void gizmo_snap_rna_location_set_fn(struct PointerRNA *UNUSED(ptr),
struct PropertyRNA *UNUSED(prop),
const float *values)
{
- SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr);
- if (snap_gizmo) {
- copy_v3_v3(snap_gizmo->loc, values);
- }
+ V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(NULL, NULL, 0, 0);
+ copy_v3_v3(snap_data->loc, values);
}
-static void gizmo_snap_rna_normal_get_fn(struct PointerRNA *ptr,
+static void gizmo_snap_rna_normal_get_fn(struct PointerRNA *UNUSED(ptr),
struct PropertyRNA *UNUSED(prop),
float *values)
{
- SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr);
- if (snap_gizmo) {
- copy_v3_v3(values, snap_gizmo->nor);
- }
+ V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(NULL, NULL, 0, 0);
+ copy_v3_v3(values, snap_data->nor);
}
-static void gizmo_snap_rna_snap_elem_index_get_fn(struct PointerRNA *ptr,
+static void gizmo_snap_rna_snap_elem_index_get_fn(struct PointerRNA *UNUSED(ptr),
struct PropertyRNA *UNUSED(prop),
int *values)
{
- SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr);
- if (snap_gizmo) {
- copy_v3_v3_int(values, snap_gizmo->elem_index);
- }
+ V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(NULL, NULL, 0, 0);
+ copy_v3_v3_int(values, snap_data->elem_index);
}
/** \} */
@@ -573,87 +223,49 @@ static void gizmo_snap_rna_snap_elem_index_get_fn(struct PointerRNA *ptr,
static void snap_gizmo_setup(wmGizmo *gz)
{
gz->flag |= WM_GIZMO_NO_TOOLTIP;
-
-#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
- SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz;
- snap_gizmo->keymap = WM_modalkeymap_find(gz->parent_gzgroup->type->keyconf,
- "Generic Gizmo Tweak Modal Map");
- RNA_enum_value_from_id(snap_gizmo->keymap->modal_items, "SNAP_ON", &snap_gizmo->snap_on);
-#endif
-}
-
-static void snap_gizmo_draw(const bContext *C, wmGizmo *gz)
-{
SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz;
- if (snap_gizmo->snap_elem == 0) {
- return;
- }
-
- wmWindowManager *wm = CTX_wm_manager(C);
- if (eventstate_has_changed(snap_gizmo, wm)) {
- /* The eventstate has changed but the snap has not been updated.
- * This means that the current position is no longer valid. */
- snap_gizmo->snap_elem = 0;
- return;
+ snap_gizmo->snap_state = ED_view3d_cursor_snap_active();
+ if (snap_gizmo->snap_state) {
+ snap_gizmo->snap_state->gzgrp_type = gz->parent_gzgroup->type;
+ snap_gizmo->snap_state->draw_point = true;
+ snap_gizmo->snap_state->draw_plane = false;
}
- RegionView3D *rv3d = CTX_wm_region_data(C);
- if (rv3d->rflag & RV3D_NAVIGATING) {
- /* Don't draw the gizmo while navigating. It can be distracting. */
- snap_gizmo->snap_elem = 0;
- return;
- }
-
- uchar color_line[4], color_point[4];
- UI_GetThemeColor3ubv(TH_TRANSFORM, color_line);
- color_line[3] = 128;
-
- rgba_float_to_uchar(color_point, gz->color);
-
- GPU_line_smooth(false);
-
- GPU_line_width(1.0f);
-
- const float *prev_point = (snap_gizmo_snap_elements(snap_gizmo) &
- SCE_SNAP_MODE_EDGE_PERPENDICULAR) ?
- snap_gizmo->prevpoint :
- NULL;
+ rgba_float_to_uchar(snap_gizmo->snap_state->color_point, gz->color);
+}
- ED_gizmotypes_snap_3d_draw_util(
- rv3d, prev_point, snap_gizmo->loc, NULL, color_line, color_point, snap_gizmo->snap_elem);
+static void snap_gizmo_draw(const bContext *UNUSED(C), wmGizmo *UNUSED(gz))
+{
+ /* All drawing is handled at the paint cursor. */
}
static int snap_gizmo_test_select(bContext *C, wmGizmo *gz, const int mval[2])
{
SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz;
- wmWindowManager *wm = CTX_wm_manager(C);
- ARegion *region = CTX_wm_region(C);
-
- /* FIXME: this hack is to ignore drag events, otherwise drag events
- * cause momentary snap gizmo re-positioning at the drag-start location, see: T87511. */
- if (wm && wm->winactive) {
- const wmEvent *event = wm->winactive->eventstate;
- int mval_compare[2] = {event->x - region->winrct.xmin, event->y - region->winrct.ymin};
- if (!equals_v2v2_int(mval_compare, mval)) {
- return snap_gizmo->snap_elem ? 0 : -1;
- }
- }
- if (!eventstate_has_changed(snap_gizmo, wm)) {
- /* Performance, do not update. */
- return snap_gizmo->snap_elem ? 0 : -1;
- }
+ /* Snap Elements can change while the gizmo is active. Need to be updated somewhere. */
+ snap_gizmo_snap_elements_update(snap_gizmo);
- View3D *v3d = CTX_wm_view3d(C);
- const float mval_fl[2] = {UNPACK2(mval)};
- short snap_elem = ED_gizmotypes_snap_3d_update(
- gz, CTX_data_ensure_evaluated_depsgraph(C), region, v3d, wm, mval_fl);
+ /* Snap values are updated too late at the cursor. Be sure to update ahead of time. */
+ int x, y;
+ {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ const wmEvent *event = wm->winactive ? wm->winactive->eventstate : NULL;
+ if (event) {
+ ARegion *region = CTX_wm_region(C);
+ x = event->xy[0] - region->winrct.xmin;
+ y = event->xy[1] - region->winrct.ymin;
+ }
+ else {
+ x = mval[0];
+ y = mval[1];
+ }
+ }
+ V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(snap_gizmo->snap_state, C, x, y);
- if (snap_elem) {
- ED_region_tag_redraw_editor_overlays(region);
+ if (snap_data->snap_elem) {
return 0;
}
-
return -1;
}
@@ -675,9 +287,8 @@ static int snap_gizmo_invoke(bContext *UNUSED(C),
static void snap_gizmo_free(wmGizmo *gz)
{
SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz;
- if (snap_gizmo->snap_context_v3d) {
- ED_transform_snap_object_context_destroy(snap_gizmo->snap_context_v3d);
- snap_gizmo->snap_context_v3d = NULL;
+ if (snap_gizmo->snap_state) {
+ ED_view3d_cursor_snap_deactive(snap_gizmo->snap_state);
}
}
@@ -717,7 +328,6 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE,
"Snap Elements",
"");
-
RNA_def_property_enum_funcs_runtime(prop,
gizmo_snap_rna_snap_elements_force_get_fn,
gizmo_snap_rna_snap_elements_force_set_fn,
@@ -733,7 +343,6 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
"Point that defines the location of the perpendicular snap",
FLT_MIN,
FLT_MAX);
-
RNA_def_property_float_array_funcs_runtime(
prop, gizmo_snap_rna_prevpoint_get_fn, gizmo_snap_rna_prevpoint_set_fn, NULL);
@@ -748,7 +357,6 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
"Snap Point Location",
FLT_MIN,
FLT_MAX);
-
RNA_def_property_float_array_funcs_runtime(
prop, gizmo_snap_rna_location_get_fn, gizmo_snap_rna_location_set_fn, NULL);
@@ -762,7 +370,6 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
"Snap Point Normal",
FLT_MIN,
FLT_MAX);
-
RNA_def_property_float_array_funcs_runtime(prop, gizmo_snap_rna_normal_get_fn, NULL, NULL);
prop = RNA_def_int_vector(gzt->srna,
@@ -775,7 +382,6 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
"Array index of face, edge and vert snapped",
INT_MIN,
INT_MAX);
-
RNA_def_property_int_array_funcs_runtime(
prop, gizmo_snap_rna_snap_elem_index_get_fn, NULL, NULL);
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index 7795eed7c21..ae00fc41f40 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -165,7 +165,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
immUniformColor3fvAlpha(ink, ink[3]);
immBegin(GPU_PRIM_POINTS, 1);
- immVertex2fv(pos, &pt->x);
+ immVertex2fv(pos, pt->m_xy);
}
else {
float oldpressure = points[0].pressure;
@@ -191,7 +191,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
if (fabsf(pt->pressure - oldpressure) > 0.2f) {
/* need to have 2 points to avoid immEnd assert error */
if (draw_points < 2) {
- immVertex2fv(pos, &(pt - 1)->x);
+ immVertex2fv(pos, (pt - 1)->m_xy);
}
immEnd();
@@ -202,7 +202,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
/* need to roll-back one point to ensure that there are no gaps in the stroke */
if (i != 0) {
- immVertex2fv(pos, &(pt - 1)->x);
+ immVertex2fv(pos, (pt - 1)->m_xy);
draw_points++;
}
@@ -210,12 +210,12 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
}
/* now the point we want */
- immVertex2fv(pos, &pt->x);
+ immVertex2fv(pos, pt->m_xy);
draw_points++;
}
/* need to have 2 points to avoid immEnd assert error */
if (draw_points < 2) {
- immVertex2fv(pos, &(pt - 1)->x);
+ immVertex2fv(pos, (pt - 1)->m_xy);
}
}
@@ -227,14 +227,14 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
if ((sflag & GP_STROKE_USE_ARROW_END) &&
(runtime.arrow_end_style != GP_STROKE_ARROWSTYLE_NONE)) {
float end[2];
- copy_v2_fl2(end, points[1].x, points[1].y);
+ copy_v2_v2(end, points[1].m_xy);
annotation_draw_stroke_arrow_buffer(pos, end, runtime.arrow_end, runtime.arrow_end_style);
}
/* Draw starting arrow stroke. */
if ((sflag & GP_STROKE_USE_ARROW_START) &&
(runtime.arrow_start_style != GP_STROKE_ARROWSTYLE_NONE)) {
float start[2];
- copy_v2_fl2(start, points[0].x, points[0].y);
+ copy_v2_v2(start, points[0].m_xy);
annotation_draw_stroke_arrow_buffer(
pos, start, runtime.arrow_start, runtime.arrow_start_style);
}
@@ -788,7 +788,6 @@ static void annotation_draw_data_all(Scene *scene,
/* ----- Annotation Sketches Drawing API ------ */
-/* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
void ED_annotation_draw_2dimage(const bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -857,13 +856,6 @@ void ED_annotation_draw_2dimage(const bContext *C)
annotation_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, area->spacetype);
}
-/**
- * Draw grease-pencil sketches to specified 2d-view
- * assuming that matrices are already set correctly.
- *
- * \note This gets called twice - first time with onlyv2d=true to draw 'canvas' strokes,
- * second time with onlyv2d=false for screen-aligned strokes.
- */
void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -900,9 +892,6 @@ void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
scene, gpd, 0, 0, region->winx, region->winy, CFRA, dflag, area->spacetype);
}
-/* draw annotations sketches to specified 3d-view assuming that matrices are already set
- * correctly NOTE: this gets called twice - first time with only3d=true to draw 3d-strokes,
- * second time with only3d=false for screen-aligned strokes */
void ED_annotation_draw_view3d(
Scene *scene, struct Depsgraph *depsgraph, View3D *v3d, ARegion *region, bool only3d)
{
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 59ea105fbbb..e75e9314659 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -78,6 +78,8 @@
/* ******************************************* */
/* 'Globals' and Defines */
+#define DEPTH_INVALID 1.0f
+
/* values for tGPsdata->status */
typedef enum eGPencil_PaintStatus {
GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */
@@ -123,6 +125,8 @@ typedef struct tGPsdata {
ARegion *region;
/** needed for GP_STROKE_2DSPACE. */
View2D *v2d;
+ /** For operations that require occlusion testing. */
+ ViewDepths *depths;
/** for using the camera rect within the 3d view. */
rctf *subrect;
rctf subrect_data;
@@ -322,6 +326,9 @@ static void annotation_stroke_convertcoords(tGPsdata *p,
float *depth)
{
bGPdata *gpd = p->gpd;
+ if (depth && (*depth == DEPTH_INVALID)) {
+ depth = NULL;
+ }
/* in 3d-space - pt->x/y/z are 3 side-by-side floats */
if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
@@ -419,25 +426,25 @@ static void annotation_smooth_buffer(tGPsdata *p, float inf, int idx)
/* Compute smoothed coordinate by taking the ones nearby */
if (pta) {
- copy_v2_v2(a, &pta->x);
+ copy_v2_v2(a, pta->m_xy);
madd_v2_v2fl(sco, a, average_fac);
}
if (ptb) {
- copy_v2_v2(b, &ptb->x);
+ copy_v2_v2(b, ptb->m_xy);
madd_v2_v2fl(sco, b, average_fac);
}
if (ptc) {
- copy_v2_v2(c, &ptc->x);
+ copy_v2_v2(c, ptc->m_xy);
madd_v2_v2fl(sco, c, average_fac);
}
if (ptd) {
- copy_v2_v2(d, &ptd->x);
+ copy_v2_v2(d, ptd->m_xy);
madd_v2_v2fl(sco, d, average_fac);
}
/* Based on influence factor, blend between original and optimal smoothed coordinate */
interp_v2_v2v2(c, c, sco, inf);
- copy_v2_v2(&ptc->x, c);
+ copy_v2_v2(ptc->m_xy, c);
}
static void annotation_stroke_arrow_calc_points_segment(float stroke_points[8],
@@ -485,8 +492,8 @@ static void annotation_stroke_arrow_calc_points(tGPspoint *point,
case GP_STROKE_ARROWSTYLE_CLOSED:
mul_v2_fl(norm_dir, arrow_length);
if (point != NULL) {
- add_v2_v2(&point->x, norm_dir);
- copy_v2_v2(corner, &point->x);
+ add_v2_v2(point->m_xy, norm_dir);
+ copy_v2_v2(corner, point->m_xy);
}
annotation_stroke_arrow_calc_points_segment(stroke_points,
corner,
@@ -500,8 +507,8 @@ static void annotation_stroke_arrow_calc_points(tGPspoint *point,
case GP_STROKE_ARROWSTYLE_SQUARE:
mul_v2_fl(norm_dir, arrow_length * 1.5f);
if (point != NULL) {
- add_v2_v2(&point->x, norm_dir);
- copy_v2_v2(corner, &point->x);
+ add_v2_v2(point->m_xy, norm_dir);
+ copy_v2_v2(corner, point->m_xy);
}
annotation_stroke_arrow_calc_points_segment(stroke_points,
corner,
@@ -537,7 +544,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = (tGPspoint *)(gpd->runtime.sbuffer);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -553,7 +560,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -566,10 +573,10 @@ static short annotation_stroke_addpoint(tGPsdata *p,
if (gpd->runtime.sbuffer_sflag & (GP_STROKE_USE_ARROW_START | GP_STROKE_USE_ARROW_END)) {
/* Store start and end point coords for arrows. */
float end[2];
- copy_v2_v2(end, &pt->x);
+ copy_v2_v2(end, pt->m_xy);
pt = ((tGPspoint *)(gpd->runtime.sbuffer));
float start[2];
- copy_v2_v2(start, &pt->x);
+ copy_v2_v2(start, pt->m_xy);
/* Arrow end corner. */
if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) {
@@ -602,7 +609,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
pt->pressure = pressure;
/* Unused for annotations, but initialize for easier conversions to GP Object. */
pt->strength = 1.0f;
@@ -629,7 +636,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = (tGPspoint *)gpd->runtime.sbuffer;
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -671,7 +678,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
}
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
+ annotation_stroke_convertcoords(p, pt->m_xy, &pts->x, NULL);
/* copy pressure and time */
pts->pressure = pt->pressure;
@@ -710,8 +717,8 @@ static void annotation_stroke_arrow_init_point(
{
/* NOTE: provided co_idx should be always pair number as it's [x1, y1, x2, y2, x3, y3]. */
const float real_co[2] = {co[co_idx], co[co_idx + 1]};
- copy_v2_v2(&ptc->x, real_co);
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ copy_v2_v2(ptc->m_xy, real_co);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
annotation_stroke_arrow_init_point_default(pt);
}
@@ -878,7 +885,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
@@ -896,7 +903,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1);
/* Convert screen-coordinates to appropriate coordinates (and store them). */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* Copy pressure and time. */
pt->pressure = ptc->pressure;
@@ -919,7 +926,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
/* End point. */
ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1);
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
annotation_stroke_arrow_init_point_default(pt);
/* Fill and convert arrow points to create arrow shape. */
@@ -940,7 +947,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
/* Start point. */
ptc = runtime.sbuffer;
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
annotation_stroke_arrow_init_point_default(pt);
/* Fill and convert arrow points to create arrow shape. */
@@ -954,7 +961,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
@@ -972,12 +979,13 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_used, "depth_points");
+ const ViewDepths *depths = p->depths;
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) {
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
- if ((ED_view3d_autodist_depth(p->region, mval_i, depth_margin, depth_arr + i) == 0) &&
- (i && (ED_view3d_autodist_depth_seg(
- p->region, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) {
+ if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) &&
+ (i && (ED_view3d_depth_read_cached_seg(
+ depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) {
interp_depth = true;
}
else {
@@ -1000,14 +1008,14 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
int last_valid = 0;
for (i = 0; i < gpd->runtime.sbuffer_used; i++) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
first_valid = i;
for (i = gpd->runtime.sbuffer_used - 1; i >= 0; i--) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -1015,14 +1023,14 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
/* invalidate non-endpoints, so only blend between first and last */
for (i = first_valid + 1; i < last_valid; i++) {
- depth_arr[i] = FLT_MAX;
+ depth_arr[i] = DEPTH_INVALID;
}
interp_depth = true;
}
if (interp_depth) {
- interp_sparse_array(depth_arr, gpd->runtime.sbuffer_used, FLT_MAX);
+ interp_sparse_array(depth_arr, gpd->runtime.sbuffer_used, DEPTH_INVALID);
}
}
}
@@ -1033,7 +1041,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc;
i++, ptc++, pt++) {
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, depth_arr ? depth_arr + i : NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
@@ -1086,7 +1094,10 @@ static bool annotation_stroke_eraser_is_occluded(tGPsdata *p,
const int mval_i[2] = {x, y};
float mval_3d[3];
- if (ED_view3d_autodist_simple(p->region, mval_i, mval_3d, 0, NULL)) {
+ float p_depth;
+ if (ED_view3d_depth_read_cached(p->depths, mval_i, 0, &p_depth)) {
+ ED_view3d_depth_unproject_v3(p->region, mval_i, (double)p_depth, mval_3d);
+
const float depth_mval = ED_view3d_calc_depth_for_comparison(rv3d, mval_3d);
const float depth_pt = ED_view3d_calc_depth_for_comparison(rv3d, &pt->x);
@@ -1121,7 +1132,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p,
if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
gpencil_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
if (len_v2v2_int(mval_i, pc1) <= radius) {
@@ -1163,7 +1174,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p,
gpencil_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
gpencil_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
- /* Check that point segment of the boundbox of the eraser stroke */
+ /* Check that point segment of the bound-box of the eraser stroke. */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
@@ -1189,7 +1200,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p,
/* Second Pass: Remove any points that are tagged */
if (do_cull) {
BKE_gpencil_stroke_delete_tagged_points(
- p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
+ p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, false, 0);
}
}
}
@@ -1211,7 +1222,8 @@ static void annotation_stroke_doeraser(tGPsdata *p)
if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) {
View3D *v3d = p->area->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->region);
- ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL);
+ ED_view3d_depth_override(
+ p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, &p->depths);
}
}
@@ -1311,7 +1323,7 @@ static bool annotation_session_initdata(bContext *C, tGPsdata *p)
p->align_flag = &ts->gpencil_v2d_align;
/* check that gpencil data is allowed to be drawn */
- if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
+ if (!((sseq->mainb == SEQ_DRAW_IMG_IMBUF) && (region->regiontype == RGN_TYPE_PREVIEW))) {
p->status = GP_STATUS_ERROR;
return 0;
}
@@ -1461,7 +1473,7 @@ static tGPsdata *annotation_session_initpaint(bContext *C)
return NULL;
}
- /* Radius for eraser circle is defined in userprefs */
+ /* Radius for eraser circle is defined in user-preferences. */
/* NOTE: we do this here, so that if we exit immediately,
* erase size won't get lost
*/
@@ -1499,6 +1511,9 @@ static void annotation_session_cleanup(tGPsdata *p)
static void annotation_session_free(tGPsdata *p)
{
+ if (p->depths) {
+ ED_view3d_depths_free(p->depths);
+ }
MEM_freeN(p);
}
@@ -1651,6 +1666,7 @@ static void annotation_paint_initstroke(tGPsdata *p,
static void annotation_paint_strokeend(tGPsdata *p)
{
ToolSettings *ts = p->scene->toolsettings;
+ const bool is_eraser = (p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) != 0;
/* for surface sketching, need to set the right OpenGL context stuff so that
* the conversions will project the values correctly...
*/
@@ -1666,11 +1682,11 @@ static void annotation_paint_strokeend(tGPsdata *p)
(ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ?
V3D_DEPTH_GPENCIL_ONLY :
V3D_DEPTH_NO_GPENCIL,
- NULL);
+ is_eraser ? NULL : &p->depths);
}
/* check if doing eraser or not */
- if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
+ if (!is_eraser) {
/* transfer stroke to frame */
annotation_stroke_newfrombuffer(p);
}
@@ -1795,7 +1811,7 @@ static void annotation_draw_stabilizer(bContext *C, int x, int y, void *p_ptr)
/* Rope Simple. */
immUniformColor4f(color[0], color[1], color[2], 0.8f);
immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, pt->x + region->winrct.xmin, pt->y + region->winrct.ymin);
+ immVertex2f(pos, pt->m_xy[0] + region->winrct.xmin, pt->m_xy[1] + region->winrct.ymin);
immVertex2f(pos, x, y);
immEnd();
@@ -2559,8 +2575,7 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve
*/
if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) {
/* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(
- p->area, RGN_TYPE_ANY, event->x, event->y);
+ ARegion *current_region = BKE_area_find_region_xy(p->area, RGN_TYPE_ANY, event->xy);
if (current_region) {
/* Assume that since we found the cursor in here, it is in bounds
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 2160aaf705f..23b579b94f1 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -61,9 +61,12 @@
#include "WM_api.h"
+#include "GPU_batch.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
+#include "GPU_shader_shared.h"
#include "GPU_state.h"
+#include "GPU_uniform_buffer.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
@@ -189,21 +192,27 @@ static void gpencil_draw_stroke_3d(tGPDdraw *tgpw,
};
immBindBuiltinProgram(GPU_SHADER_GPENCIL_STROKE);
- immUniform2fv("Viewport", viewport);
- immUniform1f("pixsize", tgpw->rv3d->pixsize);
+
float obj_scale = tgpw->ob ?
(tgpw->ob->scale[0] + tgpw->ob->scale[1] + tgpw->ob->scale[2]) / 3.0f :
1.0f;
- immUniform1f("objscale", obj_scale);
+ struct GPencilStrokeData gpencil_stroke_data;
+ copy_v2_v2(gpencil_stroke_data.viewport, viewport);
+ gpencil_stroke_data.pixsize = tgpw->rv3d->pixsize;
+ gpencil_stroke_data.objscale = obj_scale;
int keep_size = (int)((tgpw->gpd) && (tgpw->gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
- immUniform1i("keep_size", keep_size);
- immUniform1f("pixfactor", tgpw->gpd->pixfactor);
+ gpencil_stroke_data.keep_size = keep_size;
+ gpencil_stroke_data.pixfactor = tgpw->gpd->pixfactor;
/* xray mode always to 3D space to avoid wrong zdepth calculation (T60051) */
- immUniform1i("xraymode", GP_XRAY_3DSPACE);
- immUniform1i("caps_start", (int)tgpw->gps->caps[0]);
- immUniform1i("caps_end", (int)tgpw->gps->caps[1]);
- immUniform1i("fill_stroke", (int)tgpw->is_fill_stroke);
+ gpencil_stroke_data.xraymode = GP_XRAY_3DSPACE;
+ gpencil_stroke_data.caps_start = tgpw->gps->caps[0];
+ gpencil_stroke_data.caps_end = tgpw->gps->caps[1];
+ gpencil_stroke_data.fill_stroke = tgpw->is_fill_stroke;
+
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
+ sizeof(struct GPencilStrokeData), &gpencil_stroke_data, __func__);
+ immBindUniformBuf("gpencil_stroke_data", ubo);
/* draw stroke curve */
immBeginAtMost(GPU_PRIM_LINE_STRIP_ADJ, totpoints + cyclic_add + 2);
@@ -255,6 +264,8 @@ static void gpencil_draw_stroke_3d(tGPDdraw *tgpw,
immEnd();
immUnbindProgram();
+
+ GPU_uniformbuf_free(ubo);
}
/* ----- Strokes Drawing ------ */
@@ -412,7 +423,6 @@ static void gpencil_draw_strokes(tGPDdraw *tgpw)
/* ----- General Drawing ------ */
-/* wrapper to draw strokes for filling operator */
void ED_gpencil_draw_fill(tGPDdraw *tgpw)
{
gpencil_draw_strokes(tgpw);
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index fbdb7c8e520..3cc47198cbc 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -46,6 +46,8 @@
#include "WM_api.h"
+#include "DEG_depsgraph.h"
+
/* ***************************************** */
/* NOTE ABOUT THIS FILE:
* This file contains code for editing Grease Pencil data in the Action Editor
@@ -55,7 +57,6 @@
/* ***************************************** */
/* Generics - Loopers */
-/* Loops over the gp-frames for a gp-layer, and applies the given callback */
bool ED_gpencil_layer_frames_looper(bGPDlayer *gpl,
Scene *scene,
bool (*gpf_cb)(bGPDframe *, Scene *))
@@ -80,7 +81,6 @@ bool ED_gpencil_layer_frames_looper(bGPDlayer *gpl,
/* ****************************************** */
/* Data Conversion Tools */
-/* make a listing all the gp-frames in a layer as cfraelems */
void ED_gpencil_layer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel)
{
CfraElem *ce;
@@ -106,7 +106,6 @@ void ED_gpencil_layer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlys
/* ***************************************** */
/* Selection Tools */
-/* check if one of the frames in this layer is selected */
bool ED_gpencil_layer_frame_select_check(const bGPDlayer *gpl)
{
/* error checking */
@@ -145,7 +144,6 @@ static void gpencil_frame_select(bGPDframe *gpf, short select_mode)
}
}
-/* set all/none/invert select (like above, but with SELECT_* modes) */
void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
{
/* error checking */
@@ -159,7 +157,6 @@ void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
}
}
-/* set all/none/invert select */
void ED_gpencil_layer_frame_select_set(bGPDlayer *gpl, short mode)
{
/* error checking */
@@ -171,7 +168,6 @@ void ED_gpencil_layer_frame_select_set(bGPDlayer *gpl, short mode)
ED_gpencil_select_frames(gpl, mode);
}
-/* select the frame in this layer that occurs on this frame (there should only be one at most) */
void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
{
bGPDframe *gpf;
@@ -187,7 +183,6 @@ void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
}
}
-/* select the frames in this layer that occur within the bounds specified */
void ED_gpencil_layer_frames_select_box(bGPDlayer *gpl, float min, float max, short select_mode)
{
if (gpl == NULL) {
@@ -202,7 +197,6 @@ void ED_gpencil_layer_frames_select_box(bGPDlayer *gpl, float min, float max, sh
}
}
-/* select the frames in this layer that occur within the lasso/circle region specified */
void ED_gpencil_layer_frames_select_region(KeyframeEditData *ked,
bGPDlayer *gpl,
short tool,
@@ -239,7 +233,6 @@ void ED_gpencil_layer_frames_select_region(KeyframeEditData *ked,
/* ***************************************** */
/* Frame Editing Tools */
-/* Delete selected frames */
bool ED_gpencil_layer_frames_delete(bGPDlayer *gpl)
{
bool changed = false;
@@ -260,7 +253,6 @@ bool ED_gpencil_layer_frames_delete(bGPDlayer *gpl)
return changed;
}
-/* Duplicate selected frames from given gp-layer */
void ED_gpencil_layer_frames_duplicate(bGPDlayer *gpl)
{
/* error checking */
@@ -284,11 +276,6 @@ void ED_gpencil_layer_frames_duplicate(bGPDlayer *gpl)
}
}
-/**
- * Set keyframe type for selected frames from given gp-layer
- *
- * \param type: The type of keyframe (#eBezTriple_KeyframeType) to set selected frames to.
- */
void ED_gpencil_layer_frames_keytype_set(bGPDlayer *gpl, short type)
{
if (gpl == NULL) {
@@ -320,7 +307,6 @@ static int gpencil_anim_copy_firstframe = 999999999;
static int gpencil_anim_copy_lastframe = -999999999;
static int gpencil_anim_copy_cfra = 0;
-/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ED_gpencil_anim_copybuf_free(void)
{
BKE_gpencil_free_layers(&gpencil_anim_copybuf);
@@ -331,11 +317,6 @@ void ED_gpencil_anim_copybuf_free(void)
gpencil_anim_copy_cfra = 0;
}
-/* This function adds data to the copy/paste buffer, freeing existing data first
- * Only the selected GP-layers get their selected keyframes copied.
- *
- * Returns whether the copy operation was successful or not
- */
bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
@@ -404,7 +385,6 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
return true;
}
-/* Pastes keyframes from buffer, and reports success */
bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
{
ListBase anim_data = {NULL, NULL};
@@ -475,6 +455,9 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* get frame to copy data into (if no frame returned, then just ignore) */
gpf = BKE_gpencil_layer_frame_get(gpld, gpfs->framenum, GP_GETFRAME_ADD_NEW);
if (gpf) {
+ /* Ensure to use same keyframe type. */
+ gpf->key_type = gpfs->key_type;
+
bGPDstroke *gps, *gpsn;
/* This should be the right frame... as it may be a pre-existing frame,
@@ -501,6 +484,9 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* unapply offset from buffer-frame */
gpfs->framenum -= offset;
}
+
+ /* Tag destination datablock. */
+ DEG_id_tag_update(ale->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
/* clean up */
@@ -547,7 +533,6 @@ static bool gpencil_frame_snap_nearmarker(bGPDframe *gpf, Scene *scene)
return false;
}
-/* snap selected frames to ... */
void ED_gpencil_layer_snap_frames(bGPDlayer *gpl, Scene *scene, short mode)
{
switch (mode) {
@@ -648,8 +633,6 @@ static bool gpencil_frame_mirror_marker(bGPDframe *gpf, Scene *scene)
return false;
}
-/* mirror selected gp-frames on... */
-/* TODO: mirror over a specific time */
void ED_gpencil_layer_mirror_frames(bGPDlayer *gpl, Scene *scene, short mode)
{
switch (mode) {
diff --git a/source/blender/editors/gpencil/gpencil_add_blank.c b/source/blender/editors/gpencil/gpencil_add_blank.c
index 3aa16e54597..4e4650e575c 100644
--- a/source/blender/editors/gpencil/gpencil_add_blank.c
+++ b/source/blender/editors/gpencil/gpencil_add_blank.c
@@ -76,7 +76,6 @@ static const ColorTemplate gp_stroke_material_black = {
/* ***************************************************************** */
/* Blank API */
-/* Add a Simple empty object with one layer and one color. */
void ED_gpencil_create_blank(bContext *C, Object *ob, float UNUSED(mat[4][4]))
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/gpencil/gpencil_add_lineart.c b/source/blender/editors/gpencil/gpencil_add_lineart.c
index ac0da0ad1db..aad2d978bfb 100644
--- a/source/blender/editors/gpencil/gpencil_add_lineart.c
+++ b/source/blender/editors/gpencil/gpencil_add_lineart.c
@@ -83,7 +83,6 @@ static const ColorTemplate gp_stroke_material_black = {
/* ***************************************************************** */
/* LineArt API */
-/* Add a Simple LineArt setup. */
void ED_gpencil_create_lineart(bContext *C, Object *ob)
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c
index 8d60ef3ed12..3b952dbe7da 100644
--- a/source/blender/editors/gpencil/gpencil_add_monkey.c
+++ b/source/blender/editors/gpencil/gpencil_add_monkey.c
@@ -39,13 +39,6 @@
#include "ED_gpencil.h"
-/**
- * Populate stroke with point data from data buffers.
- * \param gps: Grease pencil stroke
- * \param array: Flat array of point data values. Each entry has #GP_PRIM_DATABUF_SIZE values.
- * \param totpoints: Total of points
- * \param mat: 4x4 transform matrix to transform points into the right coordinate space.
- */
void ED_gpencil_stroke_init_data(bGPDstroke *gps,
const float *array,
const int totpoints,
@@ -842,7 +835,6 @@ static const ColorTemplate gp_monkey_pct_pupils = {
/* ***************************************************************** */
/* Monkey API */
-/* add a 2D Suzanne (original model created by Matias Mendiola) */
void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4])
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c
index 73c4e64dd9a..d9e652392b4 100644
--- a/source/blender/editors/gpencil/gpencil_add_stroke.c
+++ b/source/blender/editors/gpencil/gpencil_add_stroke.c
@@ -204,8 +204,6 @@ static const ColorTemplate gp_stroke_material_grey = {
/* ***************************************************************** */
/* Stroke API */
-/* Add a Simple stroke with colors
- * (original design created by Daniel M. Lara and Matias Mendiola). */
void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4])
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/gpencil/gpencil_bake_animation.c b/source/blender/editors/gpencil/gpencil_bake_animation.c
index 2d299230124..4467e6202b4 100644
--- a/source/blender/editors/gpencil/gpencil_bake_animation.c
+++ b/source/blender/editors/gpencil/gpencil_bake_animation.c
@@ -102,7 +102,7 @@ static bool gpencil_bake_grease_pencil_animation_poll(bContext *C)
}
/* Check if grease pencil or empty for dupli groups. */
- if ((obact == NULL) || ((obact->type != OB_GPENCIL) && (obact->type != OB_EMPTY))) {
+ if ((obact == NULL) || (!ELEM(obact->type, OB_GPENCIL, OB_EMPTY))) {
return false;
}
@@ -213,7 +213,6 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
Main *bmain = CTX_data_main(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
- ARegion *region = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
ListBase ob_selected_list = {NULL, NULL};
@@ -256,7 +255,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
gsc.ob = ob_gpencil;
/* Init snap context for geometry projection. */
- sctx = ED_transform_snap_object_context_create_view3d(scene, 0, region, CTX_wm_view3d(C));
+ sctx = ED_transform_snap_object_context_create(scene, 0);
}
/* Loop all frame range. */
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 406a7ac77fc..bf414851aed 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -1324,7 +1324,7 @@ static void gpencil_layer_to_curve(bContext *C,
cu->flag |= CU_3D;
cu->bevresol = gtd->bevel_resolution;
- cu->ext2 = gtd->bevel_depth;
+ cu->bevel_radius = gtd->bevel_depth;
gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime;
@@ -1834,7 +1834,7 @@ static int image_to_gpencil_exec(bContext *C, wmOperator *op)
/* Delete any selected point. */
LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
BKE_gpencil_stroke_delete_tagged_points(
- gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
+ gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0);
}
BKE_reportf(op->reports, RPT_INFO, "Object created");
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index a77d3bee025..916aa8184aa 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -1321,78 +1321,102 @@ void GPENCIL_OT_layer_isolate(wmOperatorType *ot)
}
/* ********************** Merge Layer with the next layer **************************** */
+enum {
+ GP_LAYER_MERGE_ACTIVE = 0,
+ GP_LAYER_MERGE_ALL = 1,
+};
-static int gpencil_merge_layer_exec(bContext *C, wmOperator *op)
+static void apply_layer_settings(bGPDlayer *gpl)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl_src = BKE_gpencil_layer_active_get(gpd);
- bGPDlayer *gpl_dst = gpl_src->prev;
+ /* Apply layer attributes. */
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ gps->fill_opacity_fac *= gpl->opacity;
+ gps->vert_color_fill[3] *= gpl->opacity;
+ for (int p = 0; p < gps->totpoints; p++) {
+ bGPDspoint *pt = &gps->points[p];
+ float factor = (((float)gps->thickness * pt->pressure) + (float)gpl->line_change) /
+ ((float)gps->thickness * pt->pressure);
+ pt->pressure *= factor;
+ pt->strength *= gpl->opacity;
- if (ELEM(NULL, gpd, gpl_dst, gpl_src)) {
- BKE_report(op->reports, RPT_ERROR, "No layers to merge");
- return OPERATOR_CANCELLED;
+ /* Layer transformation. */
+ mul_v3_m4v3(&pt->x, gpl->layer_mat, &pt->x);
+ zero_v3(gpl->location);
+ zero_v3(gpl->rotation);
+ copy_v3_fl(gpl->scale, 1.0f);
+ }
+ }
}
- /* Collect frames of gpl_dst in hash table to avoid O(n^2) lookups. */
- GHash *gh_frames_dst = BLI_ghash_int_new_ex(__func__, 64);
- LISTBASE_FOREACH (bGPDframe *, gpf_dst, &gpl_dst->frames) {
- BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_dst->framenum), gpf_dst);
- }
+ gpl->line_change = 0;
+ gpl->opacity = 1.0f;
+ unit_m4(gpl->layer_mat);
+ invert_m4_m4(gpl->layer_invmat, gpl->layer_mat);
+}
- /* Read all frames from merge layer and add any missing in destination layer,
- * copying all previous strokes to keep the image equals.
- * Need to do it in a separated loop to avoid strokes accumulation. */
- LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
- /* Try to find frame in destination layer hash table. */
- bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum));
- if (!gpf_dst) {
- gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf_src->framenum, GP_GETFRAME_ADD_COPY);
- /* Use same frame type. */
- gpf_dst->key_type = gpf_src->key_type;
- BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst);
- }
- }
+static int gpencil_merge_layer_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd);
+ bGPDlayer *gpl_dst = gpl_active->prev;
+ const int mode = RNA_enum_get(op->ptr, "mode");
- /* Read all frames from merge layer and add strokes. */
- LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
- /* Try to find frame in destination layer hash table. */
- bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum));
- /* Apply layer transformation. */
- LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
- for (int p = 0; p < gps_src->totpoints; p++) {
- bGPDspoint *pt = &gps_src->points[p];
- mul_v3_m4v3(&pt->x, gpl_src->layer_mat, &pt->x);
- }
+ if (mode == GP_LAYER_MERGE_ACTIVE) {
+ if (ELEM(NULL, gpd, gpl_dst, gpl_active)) {
+ BKE_report(op->reports, RPT_ERROR, "No layers to merge");
+ return OPERATOR_CANCELLED;
}
-
- /* Add to tail all strokes. */
- if (gpf_dst) {
- BLI_movelisttolist(&gpf_dst->strokes, &gpf_src->strokes);
+ }
+ else {
+ if (ELEM(NULL, gpd, gpl_active)) {
+ BKE_report(op->reports, RPT_ERROR, "No layers to flatten");
+ return OPERATOR_CANCELLED;
}
}
- /* Add Masks to destination layer. */
- LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl_src->mask_layers) {
- /* Don't add merged layers or missing layer names. */
- if (!BKE_gpencil_layer_named_get(gpd, mask->name) || STREQ(mask->name, gpl_src->info) ||
- STREQ(mask->name, gpl_dst->info)) {
- continue;
+ if (mode == GP_LAYER_MERGE_ACTIVE) {
+ /* Apply destination layer attributes. */
+ apply_layer_settings(gpl_active);
+ ED_gpencil_layer_merge(gpd, gpl_active, gpl_dst, false);
+ }
+ else if (mode == GP_LAYER_MERGE_ALL) {
+ /* Apply layer attributes to all layers. */
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ apply_layer_settings(gpl);
+ }
+ gpl_dst = gpl_active;
+ /* Merge layers on top of active layer. */
+ if (gpd->layers.last != gpl_dst) {
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bGPDlayer *, gpl, &gpd->layers) {
+ if (gpl == gpl_dst) {
+ break;
+ }
+ ED_gpencil_layer_merge(gpd, gpl, gpl->prev, false);
+ }
}
- if (!BKE_gpencil_layer_mask_named_get(gpl_dst, mask->name)) {
- bGPDlayer_Mask *mask_new = MEM_dupallocN(mask);
- BLI_addtail(&gpl_dst->mask_layers, mask_new);
- gpl_dst->act_mask++;
+ /* Merge layers below active layer. */
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bGPDlayer *, gpl, &gpd->layers) {
+ if (gpl == gpl_dst) {
+ continue;
+ }
+ ED_gpencil_layer_merge(gpd, gpl, gpl_dst, true);
}
+ /* Set general layers settings to default values. */
+ gpl_active->blend_mode = eGplBlendMode_Regular;
+ gpl_active->flag &= ~GP_LAYER_LOCKED;
+ gpl_active->flag &= ~GP_LAYER_HIDE;
+ gpl_active->flag |= GP_LAYER_USE_LIGHTS;
+ gpl_active->onion_flag |= GP_LAYER_ONIONSKIN;
+ }
+ else {
+ return OPERATOR_CANCELLED;
}
- /* Set destination layer as active. */
- BKE_gpencil_layer_active_set(gpd, gpl_dst);
-
- /* Now delete next layer */
- BKE_gpencil_layer_delete(gpd, gpl_src);
- BLI_ghash_free(gh_frames_dst, NULL, NULL);
- /* Reorder masking. */
- BKE_gpencil_layer_mask_sort(gpd, gpl_dst);
+ /* Clear any invalid mask. Some other layer could be using the merged layer. */
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ BKE_gpencil_layer_mask_cleanup(gpd, gpl);
+ }
/* notifiers */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
@@ -1404,10 +1428,16 @@ static int gpencil_merge_layer_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_layer_merge(wmOperatorType *ot)
{
+ static const EnumPropertyItem merge_modes[] = {
+ {GP_LAYER_MERGE_ACTIVE, "ACTIVE", 0, "Active", "Combine active layer into the layer below"},
+ {GP_LAYER_MERGE_ALL, "ALL", 0, "All", "Combine all layers into the active layer"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
/* identifiers */
ot->name = "Merge Down";
ot->idname = "GPENCIL_OT_layer_merge";
- ot->description = "Merge the current layer with the layer below";
+ ot->description = "Combine Layers";
/* callbacks */
ot->exec = gpencil_merge_layer_exec;
@@ -1415,6 +1445,8 @@ void GPENCIL_OT_layer_merge(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "mode", merge_modes, GP_LAYER_MERGE_ACTIVE, "Mode", "");
}
/* ********************** Change Layer ***************************** */
@@ -1436,6 +1468,10 @@ static int gpencil_layer_change_invoke(bContext *C, wmOperator *op, const wmEven
static int gpencil_layer_change_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = CTX_data_gpencil_data(C);
+ if (gpd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
bGPDlayer *gpl = NULL;
int layer_num = RNA_enum_get(op->ptr, "layer");
@@ -2777,7 +2813,6 @@ static void gpencil_joined_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
}
}
-/* join objects called from OBJECT_OT_join */
int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -3665,7 +3700,6 @@ void GPENCIL_OT_materials_copy_to_object(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* Parent GPencil object to Lattice */
bool ED_gpencil_add_lattice_modifier(const bContext *C,
ReportList *reports,
Object *ob,
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 1f31c60367e..e71a56894d0 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -51,6 +51,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_deform.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_curve.h"
@@ -1381,11 +1382,6 @@ void GPENCIL_OT_extrude(wmOperatorType *ot)
* from several different layers into a single layer.
* \{ */
-/**
- * list of #bGPDstroke instances
- *
- * \note is exposed within the editors/gpencil module so that other tools can use it too.
- */
ListBase gpencil_strokes_copypastebuf = {NULL, NULL};
/* Hash for hanging on to all the colors used by strokes in the buffer
@@ -1429,7 +1425,6 @@ static void gpencil_strokes_copypastebuf_colors_name_to_material_free(GHash *nam
BLI_ghash_free(name_to_ma, MEM_freeN, NULL);
}
-/* Free copy/paste buffer data */
void ED_gpencil_strokes_copybuf_free(void)
{
bGPDstroke *gps, *gpsn;
@@ -1462,10 +1457,6 @@ void ED_gpencil_strokes_copybuf_free(void)
gpencil_strokes_copypastebuf.first = gpencil_strokes_copypastebuf.last = NULL;
}
-/**
- * Ensure that destination datablock has all the colors the pasted strokes need.
- * Helper function for copy-pasting strokes
- */
GHash *gpencil_copybuf_validate_colormap(bContext *C)
{
Main *bmain = CTX_data_main(C);
@@ -2635,7 +2626,7 @@ static int gpencil_delete_selected_points(bContext *C)
else {
/* delete unwanted points by splitting stroke into several smaller ones */
BKE_gpencil_stroke_delete_tagged_points(
- gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
+ gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0);
}
changed = true;
@@ -2654,7 +2645,6 @@ static int gpencil_delete_selected_points(bContext *C)
return OPERATOR_CANCELLED;
}
-/* simple wrapper to external call */
int gpencil_delete_selected_point_wrap(bContext *C)
{
return gpencil_delete_selected_points(C);
@@ -3319,10 +3309,6 @@ static bool gpencil_cyclical_set_curve_edit_poll_property(const bContext *C,
return true;
}
-/**
- * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with
- * option to force opened/closed strokes instead of just toggle behavior.
- */
void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -3434,9 +3420,6 @@ static int gpencil_stroke_caps_set_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/**
- * Change Stroke caps mode Rounded or Flat
- */
void GPENCIL_OT_stroke_caps_set(wmOperatorType *ot)
{
static const EnumPropertyItem toggle_type[] = {
@@ -3556,7 +3539,7 @@ static int gpencil_stroke_join_exec(bContext *C, wmOperator *op)
int tot_strokes = 0;
/** Alloc memory. */
- tJoinStrokes *strokes_list = MEM_malloc_arrayN(sizeof(tJoinStrokes), max_join_strokes, __func__);
+ tJoinStrokes *strokes_list = MEM_malloc_arrayN(max_join_strokes, sizeof(tJoinStrokes), __func__);
tJoinStrokes *elem = NULL;
/* Read all selected strokes to create a list. */
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
@@ -3758,7 +3741,6 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ARegion *region = CTX_wm_region(C);
int oldframe = (int)DEG_get_ctime(depsgraph);
const eGP_ReprojectModes mode = RNA_enum_get(op->ptr, "type");
const bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
@@ -3767,7 +3749,7 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
/* Init snap context for geometry projection. */
SnapObjectContext *sctx = NULL;
- sctx = ED_transform_snap_object_context_create_view3d(scene, 0, region, CTX_wm_view3d(C));
+ sctx = ED_transform_snap_object_context_create(scene, 0);
bool changed = false;
/* Init space conversion stuff. */
@@ -3967,15 +3949,15 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op)
/* perform smoothing */
if (smooth_position) {
- BKE_gpencil_stroke_smooth_point(gps, i, factor);
+ BKE_gpencil_stroke_smooth_point(gps, i, factor, false);
}
if (smooth_strength) {
BKE_gpencil_stroke_smooth_strength(gps, i, factor);
}
if (smooth_thickness) {
/* thickness need to repeat process several times */
- for (int r2 = 0; r2 < 20; r2++) {
- BKE_gpencil_stroke_smooth_thickness(gps, i, factor);
+ for (int r2 = 0; r2 < repeat * 2; r2++) {
+ BKE_gpencil_stroke_smooth_thickness(gps, i, 1.0f - factor);
}
}
if (smooth_uv) {
@@ -4588,6 +4570,9 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op)
id_us_min(ob_dst->data);
ob_dst->data = (bGPdata *)gpd_dst;
+ BKE_defgroup_copy_list(&gpd_dst->vertex_group_names, &gpd_src->vertex_group_names);
+ gpd_dst->vertex_group_active_index = gpd_src->vertex_group_active_index;
+
/* Loop old data-block and separate parts. */
if (ELEM(mode, GP_SEPARATE_POINT, GP_SEPARATE_STROKE)) {
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
@@ -4657,11 +4642,11 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op)
/* delete selected points from destination stroke */
BKE_gpencil_stroke_delete_tagged_points(
- gpd_dst, gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, 0);
+ gpd_dst, gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, false, 0);
/* delete selected points from origin stroke */
BKE_gpencil_stroke_delete_tagged_points(
- gpd_src, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
+ gpd_src, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0);
}
}
/* selected strokes mode */
@@ -4840,11 +4825,11 @@ static int gpencil_stroke_split_exec(bContext *C, wmOperator *op)
/* delete selected points from destination stroke */
BKE_gpencil_stroke_delete_tagged_points(
- gpd, gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, 0);
+ gpd, gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, false, 0);
/* delete selected points from origin stroke */
BKE_gpencil_stroke_delete_tagged_points(
- gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
+ gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0);
}
}
}
@@ -5040,7 +5025,7 @@ static void gpencil_cutter_dissolve(bGPdata *gpd,
}
BKE_gpencil_stroke_delete_tagged_points(
- gpd, hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, 1);
+ gpd, hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, flat_caps, 1);
}
}
@@ -5352,6 +5337,7 @@ void GPENCIL_OT_stroke_merge_by_distance(wmOperatorType *ot)
ot->srna, "use_unselected", 0, "Unselected", "Use whole stroke, not only selected points");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/gpencil/gpencil_edit_curve.c b/source/blender/editors/gpencil/gpencil_edit_curve.c
index e766a410889..2d7497357f2 100644
--- a/source/blender/editors/gpencil/gpencil_edit_curve.c
+++ b/source/blender/editors/gpencil/gpencil_edit_curve.c
@@ -51,6 +51,10 @@
#include "gpencil_intern.h"
+/* -------------------------------------------------------------------- */
+/** \name Enter Edit-Mode
+ * \{ */
+
/* Poll callback for checking if there is an active layer and we are in curve edit mode. */
static bool gpencil_curve_edit_mode_poll(bContext *C)
{
@@ -135,6 +139,12 @@ void GPENCIL_OT_stroke_enter_editcurve_mode(wmOperatorType *ot)
RNA_def_property_ui_range(prop, FLT_MIN, 10.0f, 0.1f, 5);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Handle Type
+ * \{ */
+
static int gpencil_editcurve_set_handle_type_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index f5474a7cdc3..541b6673cb6 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -127,6 +127,8 @@ typedef struct tGPDfill {
struct bGPDstroke *gps_mouse;
/** Pointer to report messages. */
struct ReportList *reports;
+ /** For operations that require occlusion testing. */
+ struct ViewDepths *depths;
/** flags */
short flag;
/** avoid too fast events */
@@ -1070,7 +1072,7 @@ static void gpencil_erase_processed_area(tGPDfill *tgpf)
/* First set in blue the perimeter. */
for (int i = 0; i < tgpf->sbuffer_used && point2D; i++, point2D++) {
- int image_idx = ibuf->x * (int)point2D->y + (int)point2D->x;
+ int image_idx = ibuf->x * (int)point2D->m_xy[1] + (int)point2D->m_xy[0];
set_pixel(ibuf, image_idx, blue_col);
}
@@ -1374,7 +1376,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf)
/* need to restore the original projection settings before packing up */
view3d_region_operator_needs_opengl(tgpf->win, tgpf->region);
ED_view3d_depth_override(
- tgpf->depsgraph, tgpf->region, tgpf->v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL);
+ tgpf->depsgraph, tgpf->region, tgpf->v3d, NULL, V3D_DEPTH_NO_GPENCIL, &tgpf->depths);
/* Since strokes are so fine, when using their depth we need a margin
* otherwise they might get missed. */
@@ -1385,18 +1387,17 @@ static void gpencil_get_depth_array(tGPDfill *tgpf)
int interp_depth = 0;
int found_depth = 0;
+ const ViewDepths *depths = tgpf->depths;
tgpf->depth_arr = MEM_mallocN(sizeof(float) * totpoints, "depth_points");
for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) {
int mval_i[2];
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
- if ((ED_view3d_autodist_depth(tgpf->region, mval_i, depth_margin, tgpf->depth_arr + i) ==
- 0) &&
- (i &&
- (ED_view3d_autodist_depth_seg(
- tgpf->region, mval_i, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0))) {
+ if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, tgpf->depth_arr + i) == 0) &&
+ (i && (ED_view3d_depth_read_cached_seg(
+ depths, mval_i, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0))) {
interp_depth = true;
}
else {
@@ -1414,7 +1415,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf)
}
else {
if (interp_depth) {
- interp_sparse_array(tgpf->depth_arr, totpoints, FLT_MAX);
+ interp_sparse_array(tgpf->depth_arr, totpoints, DEPTH_INVALID);
}
}
}
@@ -1436,9 +1437,9 @@ static int gpencil_points_from_stack(tGPDfill *tgpf)
while (!BLI_stack_is_empty(tgpf->stack)) {
int v[2];
BLI_stack_pop(tgpf->stack, &v);
- copy_v2fl_v2i(&point2D->x, v);
+ copy_v2fl_v2i(point2D->m_xy, v);
/* shift points to center of pixel */
- add_v2_fl(&point2D->x, 0.5f);
+ add_v2_fl(point2D->m_xy, 0.5f);
point2D->pressure = 1.0f;
point2D->strength = 1.0f;
point2D->time = 0.0f;
@@ -1569,7 +1570,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
float smoothfac = 1.0f;
for (int r = 0; r < 1; r++) {
for (int i = 0; i < gps->totpoints; i++) {
- BKE_gpencil_stroke_smooth_point(gps, i, smoothfac - reduce);
+ BKE_gpencil_stroke_smooth_point(gps, i, smoothfac - reduce, false);
}
reduce += 0.25f; /* reduce the factor */
}
@@ -1771,6 +1772,11 @@ static void gpencil_fill_exit(bContext *C, wmOperator *op)
ED_region_draw_cb_exit(tgpf->region->type, tgpf->draw_handle_3d);
}
+ /* Remove depth buffer in cache. */
+ if (tgpf->depths) {
+ ED_view3d_depths_free(tgpf->depths);
+ }
+
/* finally, free memory used by temp data */
MEM_freeN(tgpf);
}
@@ -2102,12 +2108,11 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* first time the event is not enabled to show help lines. */
if ((tgpf->oldkey != -1) || (!help_lines)) {
- ARegion *region = BKE_area_find_region_xy(
- CTX_wm_area(C), RGN_TYPE_ANY, event->x, event->y);
+ ARegion *region = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->xy);
if (region) {
bool in_bounds = false;
/* Perform bounds check */
- in_bounds = BLI_rcti_isect_pt(&region->winrct, event->x, event->y);
+ in_bounds = BLI_rcti_isect_pt_v(&region->winrct, event->xy);
if ((in_bounds) && (region->regiontype == RGN_TYPE_WINDOW)) {
tgpf->mouse[0] = event->mval[0];
@@ -2120,7 +2125,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
tgpf->gps_mouse = BKE_gpencil_stroke_new(0, 1, 10.0f);
tGPspoint point2D;
bGPDspoint *pt = &tgpf->gps_mouse->points[0];
- copy_v2fl_v2i(&point2D.x, tgpf->mouse);
+ copy_v2fl_v2i(point2D.m_xy, tgpf->mouse);
gpencil_stroke_convertcoords_tpoint(
tgpf->scene, tgpf->region, tgpf->ob, &point2D, NULL, &pt->x);
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index b6730cb123b..0802b806060 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -27,6 +27,8 @@
#include "ED_numinput.h"
+#define DEPTH_INVALID 1.0f
+
/* internal exports only */
struct Material;
struct bGPDspoint;
@@ -104,6 +106,10 @@ typedef struct tGPDdraw {
} tGPDdraw;
/* Modal Operator Drawing Callbacks ------------------------ */
+
+/**
+ * Wrapper to draw strokes for filling operator.
+ */
void ED_gpencil_draw_fill(struct tGPDdraw *tgpw);
/* ***************************************************** */
@@ -155,6 +161,8 @@ typedef struct tGPDprimitive {
struct Material *material;
/** current brush */
struct Brush *brush;
+ /** For operations that require occlusion testing. */
+ struct ViewDepths *depths;
/** Settings to pass to gp_points_to_xy(). */
GP_SpaceConversion gsc;
@@ -227,28 +235,74 @@ typedef struct tGPDprimitive {
} tGPDprimitive;
+/**
+ * Check whether a given stroke segment is inside a circular brush
+ *
+ * \param mval: The current screen-space coordinates (midpoint) of the brush
+ * \param rad: The radius of the brush
+ *
+ * \param x0, y0: The screen-space x and y coordinates of the start of the stroke segment
+ * \param x1, y1: The screen-space x and y coordinates of the end of the stroke segment
+ */
bool gpencil_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1);
+/**
+ * Init settings for stroke point space conversions
+ *
+ * \param r_gsc: [out] The space conversion settings struct, populated with necessary params
+ */
void gpencil_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
+/**
+ * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screen-space (2D)
+ *
+ * \param[out] r_x: The screen-space x-coordinate of the point
+ * \param[out] r_y: The screen-space y-coordinate of the point
+ *
+ * \warning This assumes that the caller has already checked
+ * whether the stroke in question can be drawn.
+ */
void gpencil_point_to_xy(const GP_SpaceConversion *gsc,
const struct bGPDstroke *gps,
const struct bGPDspoint *pt,
int *r_x,
int *r_y);
+/**
+ * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screen-space (2D).
+ *
+ * Just like #gpencil_point_to_xy(), except the resulting coordinates are floats not ints.
+ * Use this version to solve "stair-step" artifacts which may arise when
+ * round-tripping the calculations.
+ *
+ * \param r_x: The screen-space x-coordinate of the point.
+ * \param r_y: The screen-space y-coordinate of the point.
+ *
+ * \warning This assumes that the caller has already checked
+ * whether the stroke in question can be drawn.
+ */
void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc,
const bGPDstroke *gps,
const bGPDspoint *pt,
float *r_x,
float *r_y);
+/**
+ * Convert point to parent space
+ *
+ * \param pt: Original point
+ * \param diff_mat: Matrix with the difference between original parent matrix
+ * \param[out] r_pt: Pointer to new point after apply matrix
+ */
void gpencil_point_to_parent_space(const bGPDspoint *pt,
const float diff_mat[4][4],
bGPDspoint *r_pt);
/**
* Change points position relative to parent object
*/
+/**
+ * Change position relative to parent object
+ */
void gpencil_apply_parent(struct Depsgraph *depsgraph,
struct Object *obact,
bGPDlayer *gpl,
@@ -256,61 +310,127 @@ void gpencil_apply_parent(struct Depsgraph *depsgraph,
/**
* Change point position relative to parent object
*/
+/**
+ * Change point position relative to parent object
+ */
void gpencil_apply_parent_point(struct Depsgraph *depsgraph,
struct Object *obact,
bGPDlayer *gpl,
bGPDspoint *pt);
+/**
+ * generic based on gpencil_point_to_xy_fl
+ */
void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc,
- const short flag,
+ short flag,
const float pt[3],
float xy[2]);
+/**
+ * Project screen-space coordinates to 3D-space
+ *
+ * For use with editing tools where it is easier to perform the operations in 2D,
+ * and then later convert the transformed points back to 3D.
+ *
+ * \param screen_co: The screen-space 2D coordinates to convert to
+ * \param r_out: The resulting 3D coordinates of the input point
+ *
+ * \note We include this as a utility function, since the standard method
+ * involves quite a few steps, which are invariably always the same
+ * for all GPencil operations. So, it's nicer to just centralize these.
+ *
+ * \warning Assumes that it is getting called in a 3D view only.
+ */
bool gpencil_point_xy_to_3d(const GP_SpaceConversion *gsc,
struct Scene *scene,
const float screen_co[2],
float r_out[3]);
/* helper to convert 2d to 3d */
+
+/**
+ * Convert #tGPspoint (temporary 2D/screen-space point data used by GP modal operators)
+ * to 3D coordinates.
+ *
+ * \param point2D: The screen-space 2D point data to convert.
+ * \param depth: Depth array (via #ED_view3d_depth_read_cached()).
+ * \param r_out: The resulting 2D point data.
+ */
void gpencil_stroke_convertcoords_tpoint(struct Scene *scene,
struct ARegion *region,
struct Object *ob,
const struct tGPspoint *point2D,
float *depth,
- float out[3]);
+ float r_out[3]);
/* Poll Callbacks ------------------------------------ */
/* gpencil_utils.c */
+/**
+ * Poll callback for adding data/layers - special.
+ */
bool gpencil_add_poll(struct bContext *C);
+/**
+ * Poll callback for checking if there is an active layer.
+ */
bool gpencil_active_layer_poll(struct bContext *C);
+/**
+ * Poll callback for checking if there is an active brush.
+ */
bool gpencil_active_brush_poll(struct bContext *C);
bool gpencil_brush_create_presets_poll(bContext *C);
/* Copy/Paste Buffer --------------------------------- */
/* gpencil_edit.c */
+/**
+ * list of #bGPDstroke instances
+ *
+ * \note is exposed within the editors/gpencil module so that other tools can use it too.
+ */
extern ListBase gpencil_strokes_copypastebuf;
/* Build a map for converting between old color-names and destination-color-refs. */
+/**
+ * Ensure that destination datablock has all the colors the pasted strokes need.
+ * Helper function for copy-pasting strokes
+ */
struct GHash *gpencil_copybuf_validate_colormap(struct bContext *C);
/* Stroke Editing ------------------------------------ */
+/**
+ * Simple wrapper to external call.
+ */
int gpencil_delete_selected_point_wrap(bContext *C);
-void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide);
+/**
+ * Subdivide a stroke once, by adding a point half way between each pair of existing points
+ * \param gpd: Datablock
+ * \param gps: Stroke data
+ * \param subdivide: Number of times to subdivide
+ */
+void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, int subdivide);
/* Layers Enums -------------------------------------- */
+/**
+ * Just existing layers.
+ */
const struct EnumPropertyItem *ED_gpencil_layers_enum_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free);
+/**
+ * Existing + Option to add/use new layer.
+ */
const struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free);
+/**
+ * Just existing Materials.
+ */
const struct EnumPropertyItem *ED_gpencil_material_enum_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
@@ -403,6 +523,9 @@ void GPENCIL_OT_stroke_editcurve_set_handle_type(struct wmOperatorType *ot);
/* stroke sculpting -- */
+/**
+ * Also used for weight paint.
+ */
void GPENCIL_OT_sculpt_paint(struct wmOperatorType *ot);
void GPENCIL_OT_weight_paint(struct wmOperatorType *ot);
@@ -472,7 +595,14 @@ enum {
void GPENCIL_OT_stroke_arrange(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_change_color(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_apply_thickness(struct wmOperatorType *ot);
+/**
+ * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with
+ * option to force opened/closed strokes instead of just toggle behavior.
+ */
void GPENCIL_OT_stroke_cyclical_set(struct wmOperatorType *ot);
+/**
+ * Change Stroke caps mode Rounded or Flat
+ */
void GPENCIL_OT_stroke_caps_set(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_join(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_flip(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index d7cab85abad..2023ae5fe27 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -336,7 +336,7 @@ static void gpencil_interpolate_smooth_stroke(bGPDstroke *gps,
float reduce = 0.0f;
for (int r = 0; r < smooth_steps; r++) {
for (int i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth_point(gps, i, smooth_factor - reduce);
+ BKE_gpencil_stroke_smooth_point(gps, i, smooth_factor - reduce, false);
BKE_gpencil_stroke_smooth_strength(gps, i, smooth_factor);
}
reduce += 0.25f; /* reduce the factor */
@@ -586,7 +586,7 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, const wmEvent *event)
{
float mid = (float)(tgpi->region->winx - tgpi->region->winrct.xmin) / 2.0f;
- float mpos = event->x - tgpi->region->winrct.xmin;
+ float mpos = event->xy[0] - tgpi->region->winrct.xmin;
if (mpos >= mid) {
tgpi->shift = ((mpos - mid) * tgpi->high_limit) / mid;
diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c
index 259b2882589..925c2e1cd7f 100644
--- a/source/blender/editors/gpencil/gpencil_merge.c
+++ b/source/blender/editors/gpencil/gpencil_merge.c
@@ -182,7 +182,8 @@ static void gpencil_dissolve_points(bContext *C)
}
LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
- BKE_gpencil_stroke_delete_tagged_points(gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
+ BKE_gpencil_stroke_delete_tagged_points(
+ gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, false, 0);
}
}
CTX_DATA_END;
diff --git a/source/blender/editors/gpencil/gpencil_mesh.c b/source/blender/editors/gpencil/gpencil_mesh.c
index 079089786d0..efe29e852f2 100644
--- a/source/blender/editors/gpencil/gpencil_mesh.c
+++ b/source/blender/editors/gpencil/gpencil_mesh.c
@@ -142,6 +142,9 @@ static bool gpencil_bake_ob_list(bContext *C, Depsgraph *depsgraph, Scene *scene
/* Add active object. In some files this could not be in selected array. */
Object *obact = CTX_data_active_object(C);
+ if (obact == NULL) {
+ return false;
+ }
if (obact->type == OB_MESH) {
elem = MEM_callocN(sizeof(GpBakeOb), __func__);
@@ -188,7 +191,6 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
- ARegion *region = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
ListBase ob_selected_list = {NULL, NULL};
@@ -262,7 +264,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
gsc.ob = ob_gpencil;
/* Init snap context for geometry projection. */
- sctx = ED_transform_snap_object_context_create_view3d(scene, 0, region, CTX_wm_view3d(C));
+ sctx = ED_transform_snap_object_context_create(scene, 0);
/* Tag all existing strokes to avoid reprojections. */
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 9b157224178..79dda480a0a 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -54,6 +54,7 @@
#include "BKE_deform.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_curve.h"
#include "BKE_gpencil_geom.h"
#include "BKE_layer.h"
#include "BKE_main.h"
@@ -109,7 +110,6 @@ typedef enum eGP_StrokeAdd_Result {
/* Runtime flags */
typedef enum eGPencil_PaintFlags {
GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
- GP_PAINTFLAG_STROKEADDED = (1 << 1),
GP_PAINTFLAG_SELECTMASK = (1 << 3),
GP_PAINTFLAG_HARD_ERASER = (1 << 4),
GP_PAINTFLAG_STROKE_ERASER = (1 << 5),
@@ -162,6 +162,8 @@ typedef struct tGPsdata {
ARegion *region;
/** needed for GP_STROKE_2DSPACE. */
View2D *v2d;
+ /** For operations that require occlusion testing. */
+ ViewDepths *depths;
/** for using the camera rect within the 3d view. */
rctf *subrect;
rctf subrect_data;
@@ -282,15 +284,6 @@ static void gpencil_update_cache(bGPdata *gpd)
}
}
-static void gpencil_stroke_added_enable(tGPsdata *p)
-{
- BLI_assert(p->gpf->strokes.last != NULL);
- p->flags |= GP_PAINTFLAG_STROKEADDED;
-
- /* drawing batch cache is dirty now */
- gpencil_update_cache(p->gpd);
-}
-
/* ------ */
/* Forward defines for some functions... */
@@ -437,6 +430,9 @@ static void gpencil_stroke_convertcoords(tGPsdata *p,
float *depth)
{
bGPdata *gpd = p->gpd;
+ if (depth && (*depth == DEPTH_INVALID)) {
+ depth = NULL;
+ }
/* in 3d-space - pt->x/y/z are 3 side-by-side floats */
if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
@@ -498,7 +494,7 @@ static void gpencil_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplit
/* Mouse movement in ints -> floats. */
if (gpd->runtime.sbuffer_used > 1) {
tGPspoint *pt_prev = pt - 1;
- sub_v2_v2v2(mvec, &pt->x, &pt_prev->x);
+ sub_v2_v2v2(mvec, pt->m_xy, pt_prev->m_xy);
normalize_v2(mvec);
/* Rotate mvec by 90 degrees... */
float angle = angle_v2v2(mvec, axis);
@@ -507,7 +503,7 @@ static void gpencil_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplit
mvec[1] *= sin(angle);
/* Scale by displacement amount, and apply. */
- madd_v2_v2fl(&pt->x, mvec, amplitude * 10.0f);
+ madd_v2_v2fl(pt->m_xy, mvec, amplitude * 10.0f);
}
}
@@ -525,8 +521,7 @@ static void gpencil_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const
/* Apply to first point (only if there are 2 points because before no data to do it ) */
if (gpd->runtime.sbuffer_used == 1) {
- mvec[0] = (mval[0] - (pt - 1)->x);
- mvec[1] = (mval[1] - (pt - 1)->y);
+ sub_v2_v2v2(mvec, mval, (pt - 1)->m_xy);
normalize_v2(mvec);
/* uses > 1.0f to get a smooth transition in first point */
@@ -538,8 +533,7 @@ static void gpencil_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const
/* apply from second point */
if (gpd->runtime.sbuffer_used >= 1) {
- mvec[0] = (mval[0] - (pt - 1)->x);
- mvec[1] = (mval[1] - (pt - 1)->y);
+ sub_v2_v2v2(mvec, mval, (pt - 1)->m_xy);
normalize_v2(mvec);
fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
@@ -586,25 +580,25 @@ static void gpencil_smooth_buffer(tGPsdata *p, float inf, int idx)
/* Compute smoothed coordinate by taking the ones nearby */
if (pta) {
- copy_v2_v2(a, &pta->x);
+ copy_v2_v2(a, pta->m_xy);
madd_v2_v2fl(sco, a, average_fac);
pressure += pta->pressure * average_fac;
strength += pta->strength * average_fac;
}
if (ptb) {
- copy_v2_v2(b, &ptb->x);
+ copy_v2_v2(b, ptb->m_xy);
madd_v2_v2fl(sco, b, average_fac);
pressure += ptb->pressure * average_fac;
strength += ptb->strength * average_fac;
}
if (ptc) {
- copy_v2_v2(c, &ptc->x);
+ copy_v2_v2(c, ptc->m_xy);
madd_v2_v2fl(sco, c, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
}
if (ptd) {
- copy_v2_v2(d, &ptd->x);
+ copy_v2_v2(d, ptd->m_xy);
madd_v2_v2fl(sco, d, average_fac);
pressure += ptd->pressure * average_fac;
strength += ptd->strength * average_fac;
@@ -614,7 +608,7 @@ static void gpencil_smooth_buffer(tGPsdata *p, float inf, int idx)
* for Guide mode. */
if (!guide->use_guide) {
interp_v2_v2v2(c, c, sco, inf);
- copy_v2_v2(&ptc->x, c);
+ copy_v2_v2(ptc->m_xy, c);
}
/* Interpolate pressure. */
ptc->pressure = interpf(ptc->pressure, pressure, inf);
@@ -651,37 +645,37 @@ static void gpencil_smooth_segment(bGPdata *gpd, const float inf, int from_idx,
/* Compute smoothed coordinate by taking the ones nearby */
if (pta) {
- madd_v2_v2fl(sco, &pta->x, average_fac);
+ madd_v2_v2fl(sco, pta->m_xy, average_fac);
pressure += pta->pressure * average_fac;
strength += pta->strength * average_fac;
}
else {
- madd_v2_v2fl(sco, &ptc->x, average_fac);
+ madd_v2_v2fl(sco, ptc->m_xy, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
}
if (ptb) {
- madd_v2_v2fl(sco, &ptb->x, average_fac);
+ madd_v2_v2fl(sco, ptb->m_xy, average_fac);
pressure += ptb->pressure * average_fac;
strength += ptb->strength * average_fac;
}
else {
- madd_v2_v2fl(sco, &ptc->x, average_fac);
+ madd_v2_v2fl(sco, ptc->m_xy, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
}
- madd_v2_v2fl(sco, &ptc->x, average_fac);
+ madd_v2_v2fl(sco, ptc->m_xy, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
- madd_v2_v2fl(sco, &ptd->x, average_fac);
+ madd_v2_v2fl(sco, ptd->m_xy, average_fac);
pressure += ptd->pressure * average_fac;
strength += ptd->strength * average_fac;
/* Based on influence factor, blend between original and optimal smoothed coordinate. */
- interp_v2_v2v2(&ptc->x, &ptc->x, sco, inf);
+ interp_v2_v2v2(ptc->m_xy, ptc->m_xy, sco, inf);
/* Interpolate pressure. */
ptc->pressure = interpf(ptc->pressure, pressure, inf);
@@ -743,7 +737,8 @@ static void gpencil_apply_randomness(tGPsdata *p,
/* Apply randomness to uv texture rotation. */
if ((brush_settings->uv_random > 0.0f) && (uv)) {
if ((brush_settings->flag2 & GP_BRUSH_USE_UV_AT_STROKE) == 0) {
- float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->x, gpd->runtime.sbuffer_used)) * 2.0f -
+ float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->m_xy[0], gpd->runtime.sbuffer_used)) *
+ 2.0f -
1.0f;
value = rand * M_PI_2 * brush_settings->uv_random;
}
@@ -783,7 +778,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
pt = (tGPspoint *)(gpd->runtime.sbuffer);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -799,7 +794,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -830,7 +825,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
pt->strength = brush_settings->draw_strength;
pt->pressure = 1.0f;
pt->uv_rot = 0.0f;
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* pressure */
if (brush_settings->flag & GP_BRUSH_USE_PRESSURE) {
@@ -840,7 +835,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
/* color strength */
if (brush_settings->flag & GP_BRUSH_USE_STRENGTH_PRESSURE) {
pt->strength *= BKE_curvemapping_evaluateF(brush_settings->curve_strength, 0, pressure);
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f);
}
/* Set vertex colors for buffer. */
@@ -879,7 +874,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
pt->time = (float)(curtime - p->inittime);
/* point uv (only 3d view) */
- if ((p->area->spacetype == SPACE_VIEW3D) && (gpd->runtime.sbuffer_used > 0)) {
+ if (gpd->runtime.sbuffer_used > 0) {
tGPspoint *ptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
bGPDspoint spt, spt2;
@@ -924,6 +919,19 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
return GP_STROKEADD_INVALID;
}
+static void gpencil_stroke_unselect(bGPdata *gpd, bGPDstroke *gps)
+{
+ gps->flag &= ~GP_STROKE_SELECT;
+ BKE_gpencil_stroke_select_index_reset(gps);
+ for (int i = 0; i < gps->totpoints; i++) {
+ gps->points[i].flag &= ~GP_SPOINT_SELECT;
+ }
+ /* Update the selection from the stroke to the curve. */
+ if (gps->editcurve) {
+ BKE_gpencil_editcurve_stroke_sync_selection(gpd, gps, gps->editcurve);
+ }
+}
+
/* make a new stroke from the buffer data */
static void gpencil_stroke_newfrombuffer(tGPsdata *p)
{
@@ -934,6 +942,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
tGPspoint *ptc;
MDeformVert *dvert = NULL;
Brush *brush = p->brush;
+ BrushGpencilSettings *brush_settings = brush->gpencil_settings;
ToolSettings *ts = p->scene->toolsettings;
Depsgraph *depsgraph = p->depsgraph;
Object *obact = (Object *)p->ownerPtr.data;
@@ -1001,8 +1010,6 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
gps->dvert = NULL;
- /* drawing batch cache is dirty now */
- gpencil_update_cache(p->gpd);
/* set pointer to first non-initialized point */
pt = gps->points + (gps->totpoints - totelem);
if (gps->dvert != NULL) {
@@ -1020,11 +1027,11 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
- gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f);
copy_v4_v4(pt->vert_color, ptc->vert_color);
pt->time = ptc->time;
/* Apply the vertex color to point. */
@@ -1054,11 +1061,11 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_used - 1);
/* convert screen-coordinates to appropriate coordinates (and store them) */
- gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f);
pt->time = ptc->time;
/* Apply the vertex color to point. */
ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc);
@@ -1102,14 +1109,16 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
int found_depth = 0;
depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_used, "depth_points");
+
+ const ViewDepths *depths = p->depths;
int i;
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) {
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
- if ((ED_view3d_autodist_depth(p->region, mval_i, depth_margin, depth_arr + i) == 0) &&
- (i && (ED_view3d_autodist_depth_seg(
- p->region, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) {
+ if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) &&
+ (i && (ED_view3d_depth_read_cached_seg(
+ depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) {
interp_depth = true;
}
else {
@@ -1134,7 +1143,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
/* find first valid contact point */
for (i = 0; i < gpd->runtime.sbuffer_used; i++) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -1146,7 +1155,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
}
else {
for (i = gpd->runtime.sbuffer_used - 1; i >= 0; i--) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -1156,14 +1165,14 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
* first and last contact in an imaginary line between them */
for (i = 0; i < gpd->runtime.sbuffer_used; i++) {
if (!ELEM(i, first_valid, last_valid)) {
- depth_arr[i] = FLT_MAX;
+ depth_arr[i] = DEPTH_INVALID;
}
}
interp_depth = true;
}
if (interp_depth) {
- interp_sparse_array(depth_arr, gpd->runtime.sbuffer_used, FLT_MAX);
+ interp_sparse_array(depth_arr, gpd->runtime.sbuffer_used, DEPTH_INVALID);
}
}
}
@@ -1176,12 +1185,12 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc;
i++, ptc++, pt++) {
/* convert screen-coordinates to appropriate coordinates (and store them) */
- gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
+ gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, depth_arr ? depth_arr + i : NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f);
copy_v4_v4(pt->vert_color, ptc->vert_color);
pt->time = ptc->time;
pt->uv_fac = ptc->uv_fac;
@@ -1210,7 +1219,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
for (int r = 0; r < brush->gpencil_settings->draw_smoothlvl; r++) {
for (i = 0; i < gps->totpoints - 1; i++) {
BKE_gpencil_stroke_smooth_point(
- gps, i, brush->gpencil_settings->draw_smoothfac - reduce);
+ gps, i, brush->gpencil_settings->draw_smoothfac - reduce, false);
BKE_gpencil_stroke_smooth_strength(gps, i, brush->gpencil_settings->draw_smoothfac);
}
reduce += 0.25f; /* reduce the factor */
@@ -1222,7 +1231,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
float ifac = (float)brush->gpencil_settings->input_samples / 10.0f;
float sfac = interpf(1.0f, 0.2f, ifac);
for (i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth_point(gps, i, sfac);
+ BKE_gpencil_stroke_smooth_point(gps, i, sfac, false);
BKE_gpencil_stroke_smooth_strength(gps, i, sfac);
}
}
@@ -1288,7 +1297,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
/* Join with existing strokes. */
if (ts->gpencil_flags & GP_TOOL_FLAG_AUTOMERGE_STROKE) {
- if (gps->prev != NULL) {
+ if ((gps->prev != NULL) || (gps->next != NULL)) {
BKE_gpencil_stroke_boundingbox_calc(gps);
float diff_mat[4][4], ctrl1[2], ctrl2[2];
BKE_gpencil_layer_transform_matrix_get(depsgraph, p->ob, gpl, diff_mat);
@@ -1306,7 +1315,12 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
ctrl2,
GPENCIL_MINIMUM_JOIN_DIST,
&pt_index);
+
if (gps_target != NULL) {
+ /* Unselect all points of source and destination strokes. This is required to avoid
+ * a change in the resolution of the original strokes during the join. */
+ gpencil_stroke_unselect(gpd, gps);
+ gpencil_stroke_unselect(gpd, gps_target);
gps = ED_gpencil_stroke_join_and_trim(p->gpd, p->gpf, gps, gps_target, pt_index);
}
else {
@@ -1326,7 +1340,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
BKE_gpencil_stroke_copy_to_keyframes(gpd, gpl, p->gpf, gps, tail);
}
- gpencil_stroke_added_enable(p);
+ gpencil_update_cache(p->gpd);
}
/* --- 'Eraser' for 'Paint' Tool ------ */
@@ -1347,8 +1361,7 @@ static bool gpencil_stroke_eraser_is_occluded(
gp_settings = eraser->gpencil_settings;
}
- if ((gp_settings != NULL) && (p->area->spacetype == SPACE_VIEW3D) &&
- (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) {
+ if ((gp_settings != NULL) && (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) {
RegionView3D *rv3d = p->region->regiondata;
const int mval_i[2] = {x, y};
@@ -1359,7 +1372,10 @@ static bool gpencil_stroke_eraser_is_occluded(
/* calculate difference matrix if parent object */
BKE_gpencil_layer_transform_matrix_get(p->depsgraph, obact, gpl, diff_mat);
- if (ED_view3d_autodist_simple(p->region, mval_i, mval_3d, 0, NULL)) {
+ float p_depth;
+ if (ED_view3d_depth_read_cached(p->depths, mval_i, 0, &p_depth)) {
+ ED_view3d_depth_unproject_v3(p->region, mval_i, (double)p_depth, mval_3d);
+
const float depth_mval = ED_view3d_calc_depth_for_comparison(rv3d, mval_3d);
mul_v3_m4v3(fpt, diff_mat, &pt->x);
@@ -1490,7 +1506,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
bGPDspoint pt_temp;
gpencil_point_to_parent_space(gps->points, p->diff_mat, &pt_temp);
gpencil_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
if (len_v2v2_int(mval_i, pc1) <= radius) {
@@ -1515,7 +1531,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
gpencil_point_to_parent_space(pt1, p->diff_mat, &npt);
gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
if (len_v2v2_int(mval_i, pc1) <= radius) {
@@ -1570,6 +1586,12 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
}
bGPDspoint npt;
+ gpencil_point_to_parent_space(pt1, p->diff_mat, &npt);
+ gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
+
+ gpencil_point_to_parent_space(pt2, p->diff_mat, &npt);
+ gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
+
if (pt0) {
gpencil_point_to_parent_space(pt0, p->diff_mat, &npt);
gpencil_point_to_xy(&p->gsc, gps, &npt, &pc0[0], &pc0[1]);
@@ -1579,13 +1601,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
copy_v2_v2_int(pc0, pc1);
}
- gpencil_point_to_parent_space(pt1, p->diff_mat, &npt);
- gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
-
- gpencil_point_to_parent_space(pt2, p->diff_mat, &npt);
- gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
-
- /* Check that point segment of the boundbox of the eraser stroke */
+ /* Check that point segment of the bound-box of the eraser stroke. */
if (((!ELEM(V2D_IS_CLIPPED, pc0[0], pc0[1])) && BLI_rcti_isect_pt(rect, pc0[0], pc0[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
@@ -1595,10 +1611,12 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
*/
if (gpencil_stroke_inside_circle(mval, radius, pc0[0], pc0[1], pc2[0], pc2[1])) {
- bool is_occluded_pt0, is_occluded_pt1, is_occluded_pt2 = true;
- is_occluded_pt0 = (pt0 && ((pt0->flag & GP_SPOINT_TEMP_TAG) != 0)) ?
- ((pt0->flag & GP_SPOINT_TEMP_TAG2) != 0) :
- gpencil_stroke_eraser_is_occluded(p, gpl, pt0, pc0[0], pc0[1]);
+ bool is_occluded_pt0 = true, is_occluded_pt1 = true, is_occluded_pt2 = true;
+ if (pt0) {
+ is_occluded_pt0 = ((pt0->flag & GP_SPOINT_TEMP_TAG) != 0) ?
+ ((pt0->flag & GP_SPOINT_TEMP_TAG2) != 0) :
+ gpencil_stroke_eraser_is_occluded(p, gpl, pt0, pc0[0], pc0[1]);
+ }
if (is_occluded_pt0) {
is_occluded_pt1 = ((pt1->flag & GP_SPOINT_TEMP_TAG) != 0) ?
((pt1->flag & GP_SPOINT_TEMP_TAG2) != 0) :
@@ -1703,7 +1721,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
}
BKE_gpencil_stroke_delete_tagged_points(
- p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
+ p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, false, 0);
}
gpencil_update_cache(p->gpd);
}
@@ -1741,12 +1759,10 @@ static void gpencil_stroke_doeraser(tGPsdata *p)
rect.xmax = p->mval[0] + calc_radius;
rect.ymax = p->mval[1] + calc_radius;
- if (p->area->spacetype == SPACE_VIEW3D) {
- if ((gp_settings != NULL) && (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) {
- View3D *v3d = p->area->spacedata.first;
- view3d_region_operator_needs_opengl(p->win, p->region);
- ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL);
- }
+ if ((gp_settings != NULL) && (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) {
+ View3D *v3d = p->area->spacedata.first;
+ view3d_region_operator_needs_opengl(p->win, p->region);
+ ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, &p->depths);
}
/* loop over all layers too, since while it's easy to restrict editing to
@@ -1973,47 +1989,34 @@ static bool gpencil_session_initdata(bContext *C, wmOperator *op, tGPsdata *p)
unit_m4(p->imat);
unit_m4(p->mat);
- switch (curarea->spacetype) {
- /* supported views first */
- case SPACE_VIEW3D: {
- /* set current area
- * - must verify that region data is 3D-view (and not something else)
- */
- /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
- p->area = curarea;
- p->region = region;
- p->align_flag = &ts->gpencil_v3d_align;
-
- if (region->regiondata == NULL) {
- p->status = GP_STATUS_ERROR;
- return 0;
- }
-
- if ((!obact) || (obact->type != OB_GPENCIL)) {
- View3D *v3d = p->area->spacedata.first;
- /* if active object doesn't exist or isn't a GP Object, create one */
- const float *cur = p->scene->cursor.location;
+ /* set current area
+ * - must verify that region data is 3D-view (and not something else)
+ */
+ /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
+ p->area = curarea;
+ p->region = region;
+ p->align_flag = &ts->gpencil_v3d_align;
- ushort local_view_bits = 0;
- if (v3d->localvd) {
- local_view_bits = v3d->local_view_uuid;
- }
- /* create new default object */
- obact = ED_gpencil_add_object(C, cur, local_view_bits);
- }
- /* assign object after all checks to be sure we have one active */
- p->ob = obact;
- p->ob_eval = (Object *)DEG_get_evaluated_object(p->depsgraph, p->ob);
+ if (region->regiondata == NULL) {
+ p->status = GP_STATUS_ERROR;
+ return 0;
+ }
- break;
- }
+ if ((!obact) || (obact->type != OB_GPENCIL)) {
+ View3D *v3d = p->area->spacedata.first;
+ /* if active object doesn't exist or isn't a GP Object, create one */
+ const float *cur = p->scene->cursor.location;
- /* unsupported views */
- default: {
- p->status = GP_STATUS_ERROR;
- return 0;
+ ushort local_view_bits = 0;
+ if (v3d->localvd) {
+ local_view_bits = v3d->local_view_uuid;
}
+ /* create new default object */
+ obact = ED_gpencil_add_object(C, cur, local_view_bits);
}
+ /* assign object after all checks to be sure we have one active */
+ p->ob = obact;
+ p->ob_eval = (Object *)DEG_get_evaluated_object(p->depsgraph, p->ob);
/* get gp-data */
gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr);
@@ -2113,6 +2116,9 @@ static void gpencil_session_free(tGPsdata *p)
if (p->rng != NULL) {
BLI_rng_free(p->rng);
}
+ if (p->depths != NULL) {
+ ED_view3d_depths_free(p->depths);
+ }
MEM_freeN(p);
}
@@ -2250,17 +2256,15 @@ static void gpencil_paint_initstroke(tGPsdata *p,
/* when drawing in the camera view, in 2D space, set the subrect */
p->subrect = NULL;
if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
- if (p->area->spacetype == SPACE_VIEW3D) {
- View3D *v3d = p->area->spacedata.first;
- RegionView3D *rv3d = p->region->regiondata;
+ View3D *v3d = p->area->spacedata.first;
+ RegionView3D *rv3d = p->region->regiondata;
- /* for camera view set the subrect */
- if (rv3d->persp == RV3D_CAMOB) {
- /* no shift */
- ED_view3d_calc_camera_border(
- p->scene, depsgraph, p->region, v3d, rv3d, &p->subrect_data, true);
- p->subrect = &p->subrect_data;
- }
+ /* for camera view set the subrect */
+ if (rv3d->persp == RV3D_CAMOB) {
+ /* no shift */
+ ED_view3d_calc_camera_border(
+ p->scene, depsgraph, p->region, v3d, rv3d, &p->subrect_data, true);
+ p->subrect = &p->subrect_data;
}
}
@@ -2279,12 +2283,7 @@ static void gpencil_paint_initstroke(tGPsdata *p,
/* check if points will need to be made in view-aligned space */
if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
- switch (p->area->spacetype) {
- case SPACE_VIEW3D: {
- p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
- break;
- }
- }
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
}
if (!changed) {
/* Copy the brush to avoid a full tag (very slow). */
@@ -2300,8 +2299,9 @@ static void gpencil_paint_initstroke(tGPsdata *p,
static void gpencil_paint_strokeend(tGPsdata *p)
{
ToolSettings *ts = p->scene->toolsettings;
- /* for surface sketching, need to set the right OpenGL context stuff so that
- * the conversions will project the values correctly...
+ const bool is_eraser = (p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) != 0;
+ /* for surface sketching, need to set the right OpenGL context stuff so
+ * that the conversions will project the values correctly...
*/
if (gpencil_project_check(p)) {
View3D *v3d = p->area->spacedata.first;
@@ -2315,11 +2315,11 @@ static void gpencil_paint_strokeend(tGPsdata *p)
(ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ?
V3D_DEPTH_GPENCIL_ONLY :
V3D_DEPTH_NO_GPENCIL,
- NULL);
+ is_eraser ? NULL : &p->depths);
}
/* check if doing eraser or not */
- if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
+ if (!is_eraser) {
/* transfer stroke to frame */
gpencil_stroke_newfrombuffer(p);
}
@@ -2437,15 +2437,9 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
p->eraser->size = p->radius;
}
- /* restore cursor to indicate end of drawing */
- if (p->area->spacetype != SPACE_VIEW3D) {
- WM_cursor_modal_restore(CTX_wm_window(C));
- }
- else {
- /* drawing batch cache is dirty now */
- bGPdata *gpd = CTX_data_gpencil_data(C);
- gpencil_update_cache(gpd);
- }
+ /* drawing batch cache is dirty now */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ gpencil_update_cache(gpd);
/* clear undo stack */
gpencil_undo_finish();
@@ -2823,14 +2817,14 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra
pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
if (p->paintmode != GP_PAINTMODE_ERASER) {
- ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
+ ED_gpencil_toggle_brush_cursor(C, true, pt->m_xy);
}
}
else if ((p->brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) &&
(gpd->runtime.sbuffer_used > 0)) {
pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
if (p->paintmode != GP_PAINTMODE_ERASER) {
- ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
+ ED_gpencil_toggle_brush_cursor(C, true, pt->m_xy);
}
}
}
@@ -3328,8 +3322,7 @@ static void gpencil_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoi
/* angle vector of the brush with full thickness */
const float v0[2] = {cos(angle), sin(angle)};
- mvec[0] = pt->x - pt_prev->x;
- mvec[1] = pt->y - pt_prev->y;
+ sub_v2_v2v2(mvec, pt->m_xy, pt_prev->m_xy);
normalize_v2(mvec);
fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
/* interpolate with previous point for smoother transitions */
@@ -3380,11 +3373,11 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment
* for arc curve.
*/
float v_prev[2], v_cur[2], v_half[2];
- sub_v2_v2v2(v_cur, mval, &pt_prev->x);
+ sub_v2_v2v2(v_cur, mval, pt_prev->m_xy);
- sub_v2_v2v2(v_prev, &pt_prev->x, &pt_before->x);
- interp_v2_v2v2(v_half, &pt_prev->x, mval, 0.5f);
- sub_v2_v2(v_half, &pt_prev->x);
+ sub_v2_v2v2(v_prev, pt_prev->m_xy, pt_before->m_xy);
+ interp_v2_v2v2(v_half, pt_prev->m_xy, mval, 0.5f);
+ sub_v2_v2(v_half, pt_prev->m_xy);
/* If angle is too sharp undo all changes and return. */
const float min_angle = DEG2RADF(120.0f);
@@ -3403,14 +3396,14 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment
/* Calc the position of the control point. */
float ctl[2];
- add_v2_v2v2(ctl, &pt_prev->x, v_prev);
+ add_v2_v2v2(ctl, pt_prev->m_xy, v_prev);
float step = M_PI_2 / (float)(segments + 1);
float a = step;
float midpoint[2], start[2], end[2], cp1[2], corner[2];
- mid_v2_v2v2(midpoint, &pt_prev->x, mval);
- copy_v2_v2(start, &pt_prev->x);
+ mid_v2_v2v2(midpoint, pt_prev->m_xy, mval);
+ copy_v2_v2(start, pt_prev->m_xy);
copy_v2_v2(end, mval);
copy_v2_v2(cp1, ctl);
@@ -3421,8 +3414,8 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment
tGPspoint *pt_step = pt_prev;
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
- pt->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
- pt->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
+ pt->m_xy[0] = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
+ pt->m_xy[1] = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
/* Set pressure and strength equals to previous. It will be smoothed later. */
pt->pressure = pt_prev->pressure;
@@ -3485,8 +3478,8 @@ static void gpencil_add_guide_points(const tGPsdata *p,
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
- gpencil_rotate_v2_v2v2fl(&pt->x, start, p->guide.origin, -a);
- gpencil_snap_to_guide(p, guide, &pt->x);
+ gpencil_rotate_v2_v2v2fl(pt->m_xy, start, p->guide.origin, -a);
+ gpencil_snap_to_guide(p, guide, pt->m_xy);
a += step;
/* Set pressure and strength equals to previous. It will be smoothed later. */
@@ -3502,8 +3495,8 @@ static void gpencil_add_guide_points(const tGPsdata *p,
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
- interp_v2_v2v2(&pt->x, start, end, a);
- gpencil_snap_to_guide(p, guide, &pt->x);
+ interp_v2_v2v2(pt->m_xy, start, end, a);
+ gpencil_snap_to_guide(p, guide, pt->m_xy);
a += step;
/* Set pressure and strength equals to previous. It will be smoothed later. */
@@ -3706,8 +3699,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
*/
if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) {
/* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(
- p->area, RGN_TYPE_ANY, event->x, event->y);
+ ARegion *current_region = BKE_area_find_region_xy(p->area, RGN_TYPE_ANY, event->xy);
if (current_region) {
/* Assume that since we found the cursor in here, it is in bounds
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index f8cfc130e35..2715491414a 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -423,6 +423,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
Scene *scene = tgpi->scene;
char status_str[UI_MAX_DRAW_STR];
char msg_str[UI_MAX_DRAW_STR];
+ const int cur_subdiv = tgpi->type == GP_STROKE_BOX ? tgpi->tot_edges - 1 : tgpi->tot_edges - 2;
if (tgpi->type == GP_STROKE_LINE) {
BLI_strncpy(msg_str,
@@ -480,7 +481,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
sizeof(status_str),
"%s: %d (%d, %d) (%d, %d)",
msg_str,
- tgpi->tot_edges,
+ cur_subdiv,
(int)tgpi->start[0],
(int)tgpi->start[1],
(int)tgpi->end[0],
@@ -491,7 +492,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
sizeof(status_str),
"%s: %d (%d, %d)",
msg_str,
- tgpi->tot_edges,
+ cur_subdiv,
(int)tgpi->end[0],
(int)tgpi->end[1]);
}
@@ -503,7 +504,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
sizeof(status_str),
"%s: %d (%d, %d) (%d, %d)",
msg_str,
- tgpi->tot_edges,
+ cur_subdiv,
(int)tgpi->start[0],
(int)tgpi->start[1],
(int)tgpi->end[0],
@@ -540,7 +541,7 @@ static void gpencil_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D
if (tgpi->tot_edges == 1) {
for (int j = 0; j < 4; j++) {
tGPspoint *p2d = &points2D[j];
- copy_v2_v2(&p2d->x, coords[j]);
+ copy_v2_v2(p2d->m_xy, coords[j]);
}
}
else {
@@ -550,7 +551,7 @@ static void gpencil_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D
float a = 0.0f;
for (int k = 0; k < tgpi->tot_edges; k++) {
tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2(&p2d->x, coords[j], coords[j + 1], a);
+ interp_v2_v2v2(p2d->m_xy, coords[j], coords[j + 1], a);
a += step;
i++;
}
@@ -581,7 +582,7 @@ static void gpencil_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D, boo
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2(&p2d->x, tgpi->start, tgpi->end, a);
+ interp_v2_v2v2(p2d->m_xy, tgpi->start, tgpi->end, a);
a += step;
}
@@ -627,8 +628,8 @@ static void gpencil_primitive_arc(tGPDprimitive *tgpi, tGPspoint *points2D)
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- p2d->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
- p2d->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
+ p2d->m_xy[0] = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
+ p2d->m_xy[1] = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
a += step;
}
float color[4];
@@ -663,7 +664,7 @@ static void gpencil_primitive_bezier(tGPDprimitive *tgpi, tGPspoint *points2D)
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2v2v2_cubic(&p2d->x, bcp1, bcp2, bcp3, bcp4, a);
+ interp_v2_v2v2v2v2_cubic(p2d->m_xy, bcp1, bcp2, bcp3, bcp4, a);
a += step;
}
float color[4];
@@ -697,8 +698,8 @@ static void gpencil_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D)
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- p2d->x = (center[0] + cosf(a) * radius[0]);
- p2d->y = (center[1] + sinf(a) * radius[1]);
+ p2d->m_xy[0] = (center[0] + cosf(a) * radius[0]);
+ p2d->m_xy[1] = (center[1] + sinf(a) * radius[1]);
a += step;
}
float color[4];
@@ -726,7 +727,6 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
const bool is_camera = is_lock_axis_view && (tgpi->rv3d->persp == RV3D_CAMOB) && (!is_depth);
if (tgpi->type == GP_STROKE_BOX) {
- tgpi->tot_edges--;
gps->totpoints = (tgpi->tot_edges * 4 + tgpi->tot_stored_edges);
}
else {
@@ -795,15 +795,16 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
(ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ?
V3D_DEPTH_GPENCIL_ONLY :
V3D_DEPTH_NO_GPENCIL,
- NULL);
+ &tgpi->depths);
depth_arr = MEM_mallocN(sizeof(float) * gps->totpoints, "depth_points");
+ const ViewDepths *depths = tgpi->depths;
tGPspoint *ptc = &points2D[0];
for (int i = 0; i < gps->totpoints; i++, ptc++) {
- round_v2i_v2fl(mval_i, &ptc->x);
- if ((ED_view3d_autodist_depth(tgpi->region, mval_i, depth_margin, depth_arr + i) == 0) &&
- (i && (ED_view3d_autodist_depth_seg(
- tgpi->region, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) {
+ round_v2i_v2fl(mval_i, ptc->m_xy);
+ if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) &&
+ (i && (ED_view3d_depth_read_cached_seg(
+ depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) {
interp_depth = true;
}
else {
@@ -840,7 +841,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* find first valid contact point */
int i;
for (i = 0; i < gps->totpoints; i++) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -852,7 +853,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
else {
for (i = gps->totpoints - 1; i >= 0; i--) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -863,14 +864,14 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
* first and last contact in an imaginary line between them */
for (i = 0; i < gps->totpoints; i++) {
if (!ELEM(i, first_valid, last_valid)) {
- depth_arr[i] = FLT_MAX;
+ depth_arr[i] = DEPTH_INVALID;
}
}
interp_depth = true;
}
if (interp_depth) {
- interp_sparse_array(depth_arr, gps->totpoints, FLT_MAX);
+ interp_sparse_array(depth_arr, gps->totpoints, DEPTH_INVALID);
}
}
}
@@ -893,7 +894,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* Store original points */
float tmp_xyp[2];
- copy_v2_v2(tmp_xyp, &p2d->x);
+ copy_v2_v2(tmp_xyp, p2d->m_xy);
/* calc pressure */
float curve_pressure = 1.0;
@@ -925,8 +926,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* vector */
float mvec[2], svec[2];
if (i > 0) {
- mvec[0] = (p2d->x - (p2d - 1)->x);
- mvec[1] = (p2d->y - (p2d - 1)->y);
+ sub_v2_v2v2(mvec, p2d->m_xy, (p2d - 1)->m_xy);
normalize_v2(mvec);
}
else {
@@ -941,7 +941,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
else {
mul_v2_fl(svec, fac);
}
- add_v2_v2(&p2d->x, svec);
+ add_v2_v2(p2d->m_xy, svec);
}
/* color strength */
@@ -991,7 +991,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
}
- copy_v2_v2(&tpt->x, &p2d->x);
+ copy_v2_v2(tpt->m_xy, p2d->m_xy);
tpt->pressure = pressure;
tpt->strength = strength;
@@ -1040,7 +1040,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
gpd->runtime.sbuffer, &gpd->runtime.sbuffer_size, &gpd->runtime.sbuffer_used, false);
/* add small offset to keep stroke over the surface */
- if ((depth_arr) && (gpd->zdepth_offset > 0.0f)) {
+ if ((depth_arr) && (gpd->zdepth_offset > 0.0f) && (depth_arr[i] != DEPTH_INVALID)) {
depth_arr[i] *= (1.0f - (gpd->zdepth_offset / 1000.0f));
}
@@ -1063,7 +1063,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
/* Restore original points */
- copy_v2_v2(&p2d->x, tmp_xyp);
+ copy_v2_v2(p2d->m_xy, tmp_xyp);
}
/* store cps and convert coords */
@@ -1154,6 +1154,11 @@ static void gpencil_primitive_exit(bContext *C, wmOperator *op)
BLI_rng_free(tgpi->rng);
}
+ /* Remove depth buffer in cache. */
+ if (tgpi->depths) {
+ ED_view3d_depths_free(tgpi->depths);
+ }
+
MEM_freeN(tgpi);
}
@@ -1248,7 +1253,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
tgpi->tot_stored_edges = 0;
tgpi->subdiv = RNA_int_get(op->ptr, "subdivision");
- RNA_int_set(op->ptr, "edges", tgpi->subdiv + 2);
+ RNA_int_set(op->ptr, "edges", tgpi->type == GP_STROKE_BOX ? tgpi->subdiv + 1 : tgpi->subdiv + 2);
tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
tgpi->flag = IDLE;
tgpi->lock_axis = ts->gp_sculpt.lock_axis;
@@ -1611,7 +1616,7 @@ static void gpencil_primitive_move(tGPDprimitive *tgpi, bool reset)
for (int i = 0; i < gps->totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- add_v2_v2(&p2d->x, move);
+ add_v2_v2(p2d->m_xy, move);
}
add_v2_v2(tgpi->start, move);
@@ -1714,7 +1719,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELUPMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges + 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
gpencil_primitive_update(C, op, tgpi);
}
@@ -1724,7 +1729,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELDOWNMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges - 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
gpencil_primitive_update(C, op, tgpi);
}
@@ -1880,7 +1885,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELUPMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges + 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
/* update screen */
@@ -1892,7 +1897,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELDOWNMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges - 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
/* update screen */
@@ -2032,15 +2037,8 @@ static void gpencil_primitive_common_props(wmOperatorType *ot, int subdiv, int t
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
/* Internal prop. */
- prop = RNA_def_int(ot->srna,
- "edges",
- MIN_EDGES,
- MIN_EDGES,
- MAX_EDGES,
- "Edges",
- "Number of points by edge",
- MIN_EDGES,
- MAX_EDGES);
+ prop = RNA_def_int(
+ ot->srna, "edges", 1, 1, MAX_EDGES, "Edges", "Number of points by edge", 1, MAX_EDGES);
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
RNA_def_enum(ot->srna, "type", gpencil_primitive_type, type, "Type", "Type of shape");
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index e9a6beab798..50c7202599a 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -337,7 +337,7 @@ static bool gpencil_brush_smooth_apply(tGP_BrushEditData *gso,
/* perform smoothing */
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
- BKE_gpencil_stroke_smooth_point(gps, pt_index, inf);
+ BKE_gpencil_stroke_smooth_point(gps, pt_index, inf, false);
}
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
BKE_gpencil_stroke_smooth_strength(gps, pt_index, inf);
@@ -1454,7 +1454,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
int mval_i[2];
@@ -1492,7 +1492,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
gpencil_point_to_parent_space(pt2, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
- /* Check that point segment of the boundbox of the selection stroke */
+ /* Check that point segment of the bound-box of the selection stroke. */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
@@ -2134,7 +2134,6 @@ static int gpencil_sculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_RUNNING_MODAL;
}
-/* Also used for weight paint. */
void GPENCIL_OT_sculpt_paint(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 6ad2fffc773..ed8d2996b6a 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -248,6 +248,7 @@ static void select_all_curve_points(bGPdata *gpd, bGPDstroke *gps, bGPDcurve *gp
/* -------------------------------------------------------------------- */
/** \name Select All Operator
* \{ */
+
static bool gpencil_select_all_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
diff --git a/source/blender/editors/gpencil/gpencil_trace.h b/source/blender/editors/gpencil/gpencil_trace.h
index 25d8dac2734..77fb823b3b6 100644
--- a/source/blender/editors/gpencil/gpencil_trace.h
+++ b/source/blender/editors/gpencil/gpencil_trace.h
@@ -59,22 +59,54 @@ struct bGPDframe;
#define GPENCIL_TRACE_MODE_SINGLE 0
#define GPENCIL_TRACE_MODE_SEQUENCE 1
+/**
+ * Print trace bitmap for debugging.
+ * \param f: Output handle. Use `stderr` for printing
+ * \param bm: Trace bitmap
+ */
void ED_gpencil_trace_bitmap_print(FILE *f, const potrace_bitmap_t *bm);
+/**
+ * Return new un-initialized trace bitmap
+ * \param w: Width in pixels
+ * \param h: Height in pixels
+ * \return Trace bitmap
+ */
potrace_bitmap_t *ED_gpencil_trace_bitmap_new(int32_t w, int32_t h);
+/**
+ * Free a trace bitmap
+ * \param bm: Trace bitmap
+ */
void ED_gpencil_trace_bitmap_free(const potrace_bitmap_t *bm);
+/**
+ * Invert the given bitmap (Black to White)
+ * \param bm: Trace bitmap
+ */
void ED_gpencil_trace_bitmap_invert(const potrace_bitmap_t *bm);
+/**
+ * Convert image to BW bitmap for tracing
+ * \param ibuf: ImBuf of the image
+ * \param bm: Trace bitmap
+ */
void ED_gpencil_trace_image_to_bitmap(struct ImBuf *ibuf,
const potrace_bitmap_t *bm,
- const float threshold);
+ float threshold);
+/**
+ * Convert Potrace Bitmap to Grease Pencil strokes
+ * \param st: Data with traced data
+ * \param ob: Target grease pencil object
+ * \param offset: Offset to center
+ * \param scale: Scale of the output
+ * \param sample: Sample distance to distribute points
+ */
void ED_gpencil_trace_data_to_strokes(struct Main *bmain,
potrace_state_t *st,
struct Object *ob,
struct bGPDframe *gpf,
int32_t offset[2],
- const float scale,
- const float sample,
- const int32_t resolution,
- const int32_t thickness);
+ float scale,
+ float sample,
+ int32_t resolution,
+ int32_t thickness);
diff --git a/source/blender/editors/gpencil/gpencil_trace_utils.c b/source/blender/editors/gpencil/gpencil_trace_utils.c
index 970afc3ff6b..f5690904fcf 100644
--- a/source/blender/editors/gpencil/gpencil_trace_utils.c
+++ b/source/blender/editors/gpencil/gpencil_trace_utils.c
@@ -46,11 +46,6 @@
#include "gpencil_trace.h"
-/**
- * Print trace bitmap for debugging.
- * \param f: Output handle. Use `stderr` for printing
- * \param bm: Trace bitmap
- */
void ED_gpencil_trace_bitmap_print(FILE *f, const potrace_bitmap_t *bm)
{
int32_t x, y;
@@ -77,12 +72,6 @@ void ED_gpencil_trace_bitmap_print(FILE *f, const potrace_bitmap_t *bm)
}
}
-/**
- * Return new un-initialized trace bitmap
- * \param w: Width in pixels
- * \param h: Height in pixels
- * \return Trace bitmap
- */
potrace_bitmap_t *ED_gpencil_trace_bitmap_new(int32_t w, int32_t h)
{
potrace_bitmap_t *bm;
@@ -104,10 +93,6 @@ potrace_bitmap_t *ED_gpencil_trace_bitmap_new(int32_t w, int32_t h)
return bm;
}
-/**
- * Free a trace bitmap
- * \param bm: Trace bitmap
- */
void ED_gpencil_trace_bitmap_free(const potrace_bitmap_t *bm)
{
if (bm != NULL) {
@@ -116,10 +101,6 @@ void ED_gpencil_trace_bitmap_free(const potrace_bitmap_t *bm)
MEM_SAFE_FREE(bm);
}
-/**
- * Invert the given bitmap (Black to White)
- * \param bm: Trace bitmap
- */
void ED_gpencil_trace_bitmap_invert(const potrace_bitmap_t *bm)
{
int32_t dy = bm->dy;
@@ -162,11 +143,6 @@ static void pixel_at_index(const ImBuf *ibuf, const int32_t idx, float r_col[4])
}
}
-/**
- * Convert image to BW bitmap for tracing
- * \param ibuf: ImBuf of the image
- * \param bm: Trace bitmap
- */
void ED_gpencil_trace_image_to_bitmap(ImBuf *ibuf,
const potrace_bitmap_t *bm,
const float threshold)
@@ -231,14 +207,6 @@ static void add_bezier(bGPDstroke *gps,
}
}
-/**
- * Convert Potrace Bitmap to Grease Pencil strokes
- * \param st: Data with traced data
- * \param ob: Target grease pencil object
- * \param offset: Offset to center
- * \param scale: Scale of the output
- * \param sample: Sample distance to distribute points
- */
void ED_gpencil_trace_data_to_strokes(Main *bmain,
potrace_state_t *st,
Object *ob,
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index 99b8b672327..ec70febc80c 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -62,9 +62,6 @@ int ED_gpencil_session_active(void)
return (BLI_listbase_is_empty(&undo_nodes) == false);
}
-/**
- * \param step: eUndoStepDir.
- */
int ED_undo_gpencil_step(bContext *C, const int step)
{
bGPdata **gpd_ptr = NULL, *new_gpd = NULL;
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index bb05b93ad81..81a844cf6e1 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -96,11 +96,6 @@
/* ******************************************************** */
/* Context Wrangling... */
-/**
- * Get pointer to active Grease Pencil data-block,
- * and an RNA-pointer to trace back to whatever owns it,
- * when context info is not available.
- */
bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *area, Object *ob, PointerRNA *r_ptr)
{
/* if there's an active area, check if the particular editor may
@@ -130,11 +125,6 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *area, Object *ob, Pointer
return NULL;
}
-/**
- * Get pointer to active Grease Pencil data-block for annotations,
- * and an RNA-pointer to trace back to whatever owns it,
- * when context info is not available.
- */
bGPdata **ED_annotation_data_get_pointers_direct(ID *screen_id,
ScrArea *area,
Scene *scene,
@@ -233,10 +223,6 @@ bGPdata **ED_annotation_data_get_pointers_direct(ID *screen_id,
return NULL;
}
-/**
- * Get pointer to active Grease Pencil data-block,
- * and an RNA-pointer to trace back to whatever owns it.
- */
bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
{
ScrArea *area = CTX_wm_area(C);
@@ -245,10 +231,6 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
return ED_gpencil_data_get_pointers_direct(area, ob, r_ptr);
}
-/**
- * Get pointer to active Grease Pencil data-block,
- * and an RNA-pointer to trace back to whatever owns it.
- */
bGPdata **ED_annotation_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
{
ID *screen_id = (ID *)CTX_wm_screen(C);
@@ -259,23 +241,18 @@ bGPdata **ED_annotation_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
}
/* -------------------------------------------------------- */
-/* Get the active Grease Pencil data-block, when context is not available */
bGPdata *ED_gpencil_data_get_active_direct(ScrArea *area, Object *ob)
{
bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(area, ob, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
-/* Get the active Grease Pencil data-block, when context is not available */
bGPdata *ED_annotation_data_get_active_direct(ID *screen_id, ScrArea *area, Scene *scene)
{
bGPdata **gpd_ptr = ED_annotation_data_get_pointers_direct(screen_id, area, scene, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
-/**
- * Get the active Grease Pencil data-block
- */
bGPdata *ED_gpencil_data_get_active(const bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -285,24 +262,12 @@ bGPdata *ED_gpencil_data_get_active(const bContext *C)
return ob->data;
}
-/**
- * Get the active Grease Pencil data-block
- * \note This is the original (#G.main) copy of the data-block, stored in files.
- * Do not use for reading evaluated copies of GP Objects data.
- */
bGPdata *ED_annotation_data_get_active(const bContext *C)
{
bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
-/**
- * Get the evaluated copy of the active Grease Pencil data-block (where applicable)
- * - For the 3D View (i.e. "GP Objects"), this gives the evaluated copy of the GP data-block
- * (i.e. a copy of the active GP data-block for the active object, where modifiers have been
- * applied). This is needed to correctly work with "Copy-on-Write".
- * - For all other editors (i.e. "GP Annotations"), this just gives the active data-block
- * like for #ED_gpencil_data_get_active()
- */
+
bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -316,10 +281,6 @@ bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C)
/* -------------------------------------------------------- */
-/**
- * Utility to check whether the r_ptr output of ED_gpencil_data_get_pointers()
- * is for annotation usage.
- */
bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr)
{
/* Key Assumption: If the pointer is an object, we're dealing with a GP Object's data.
@@ -330,7 +291,6 @@ bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr)
/* ******************************************************** */
/* Keyframe Indicator Checks */
-/* Check whether there's an active GP keyframe on the current frame */
bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
{
if (ob && ob->data && (ob->type == OB_GPENCIL)) {
@@ -351,7 +311,6 @@ bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
/* ******************************************************** */
/* Poll Callbacks */
-/* poll callback for adding data/layers - special */
bool gpencil_add_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -363,7 +322,6 @@ bool gpencil_add_poll(bContext *C)
return (gpd != NULL);
}
-/* poll callback for checking if there is an active layer */
bool gpencil_active_layer_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -376,7 +334,6 @@ bool gpencil_active_layer_poll(bContext *C)
return (gpl != NULL);
}
-/* poll callback for checking if there is an active brush */
bool gpencil_active_brush_poll(bContext *C)
{
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -391,7 +348,6 @@ bool gpencil_active_brush_poll(bContext *C)
/* Dynamic Enums of GP Layers */
/* NOTE: These include an option to create a new layer and use that... */
-/* Just existing layers */
const EnumPropertyItem *ED_gpencil_layers_enum_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -429,7 +385,6 @@ const EnumPropertyItem *ED_gpencil_layers_enum_itemf(bContext *C,
return item;
}
-/* Existing + Option to add/use new layer */
const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -482,7 +437,6 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
return item;
}
-/* Just existing Materials */
const EnumPropertyItem *ED_gpencil_material_enum_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -519,15 +473,6 @@ const EnumPropertyItem *ED_gpencil_material_enum_itemf(bContext *C,
/* ******************************************************** */
/* Brush Tool Core */
-/**
- * Check whether a given stroke segment is inside a circular brush
- *
- * \param mval: The current screen-space coordinates (midpoint) of the brush
- * \param rad: The radius of the brush
- *
- * \param x0, y0: The screen-space x and y coordinates of the start of the stroke segment
- * \param x1, y1: The screen-space x and y coordinates of the end of the stroke segment
- */
bool gpencil_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1)
{
/* simple within-radius check for now */
@@ -577,8 +522,6 @@ bool ED_gpencil_layer_has_selected_stroke(const bGPDlayer *gpl, const bool is_mu
/* ******************************************************** */
/* Stroke Validity Testing */
-/* Check whether given stroke can be edited given the supplied context */
-/* TODO: do we need additional flags for screenspace vs dataspace? */
bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps)
{
/* sanity check */
@@ -603,14 +546,12 @@ bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps
return true;
}
-/* Check whether given stroke can be edited in the current context */
bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
{
ScrArea *area = CTX_wm_area(C);
return ED_gpencil_stroke_can_use_direct(area, gps);
}
-/* Check whether given stroke can be edited for the current color */
bool ED_gpencil_stroke_material_editable(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps)
{
/* check if the color is editable */
@@ -628,7 +569,6 @@ bool ED_gpencil_stroke_material_editable(Object *ob, const bGPDlayer *gpl, const
return true;
}
-/* Check whether given stroke is visible for the current material. */
bool ED_gpencil_stroke_material_visible(Object *ob, const bGPDstroke *gps)
{
/* check if the color is editable */
@@ -646,11 +586,6 @@ bool ED_gpencil_stroke_material_visible(Object *ob, const bGPDstroke *gps)
/* ******************************************************** */
/* Space Conversion */
-/**
- * Init settings for stroke point space conversions
- *
- * \param r_gsc: [out] The space conversion settings struct, populated with necessary params
- */
void gpencil_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
{
ScrArea *area = CTX_wm_area(C);
@@ -691,13 +626,6 @@ void gpencil_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
}
}
-/**
- * Convert point to parent space
- *
- * \param pt: Original point
- * \param diff_mat: Matrix with the difference between original parent matrix
- * \param[out] r_pt: Pointer to new point after apply matrix
- */
void gpencil_point_to_parent_space(const bGPDspoint *pt,
const float diff_mat[4][4],
bGPDspoint *r_pt)
@@ -708,9 +636,6 @@ void gpencil_point_to_parent_space(const bGPDspoint *pt,
copy_v3_v3(&r_pt->x, fpt);
}
-/**
- * Change position relative to parent object
- */
void gpencil_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, bGPDstroke *gps)
{
bGPDspoint *pt;
@@ -731,9 +656,6 @@ void gpencil_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, b
}
}
-/**
- * Change point position relative to parent object
- */
void gpencil_apply_parent_point(Depsgraph *depsgraph,
Object *obact,
bGPDlayer *gpl,
@@ -752,15 +674,6 @@ void gpencil_apply_parent_point(Depsgraph *depsgraph,
copy_v3_v3(&pt->x, fpt);
}
-/**
- * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
- *
- * \param[out] r_x: The screen-space x-coordinate of the point
- * \param[out] r_y: The screen-space y-coordinate of the point
- *
- * \warning This assumes that the caller has already checked
- * whether the stroke in question can be drawn.
- */
void gpencil_point_to_xy(
const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt, int *r_x, int *r_y)
{
@@ -803,19 +716,6 @@ void gpencil_point_to_xy(
}
}
-/**
- * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D).
- *
- * Just like #gpencil_point_to_xy(), except the resulting coordinates are floats not ints.
- * Use this version to solve "stair-step" artifacts which may arise when
- * roundtripping the calculations.
- *
- * \param r_x: The screen-space x-coordinate of the point.
- * \param r_y: The screen-space y-coordinate of the point.
- *
- * \warning This assumes that the caller has already checked
- * whether the stroke in question can be drawn.
- */
void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc,
const bGPDstroke *gps,
const bGPDspoint *pt,
@@ -873,9 +773,6 @@ void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc,
}
}
-/**
- * generic based on gpencil_point_to_xy_fl
- */
void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc,
const short flag,
const float pt[3],
@@ -930,21 +827,6 @@ void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc,
}
}
-/**
- * Project screenspace coordinates to 3D-space
- *
- * For use with editing tools where it is easier to perform the operations in 2D,
- * and then later convert the transformed points back to 3D.
- *
- * \param screen_co: The screenspace 2D coordinates to convert to
- * \param r_out: The resulting 3D coordinates of the input point
- *
- * \note We include this as a utility function, since the standard method
- * involves quite a few steps, which are invariably always the same
- * for all GPencil operations. So, it's nicer to just centralize these.
- *
- * \warning Assumes that it is getting called in a 3D view only.
- */
bool gpencil_point_xy_to_3d(const GP_SpaceConversion *gsc,
Scene *scene,
const float screen_co[2],
@@ -974,14 +856,6 @@ bool gpencil_point_xy_to_3d(const GP_SpaceConversion *gsc,
return false;
}
-/**
- * Convert tGPspoint (temporary 2D/screenspace point data used by GP modal operators)
- * to 3D coordinates.
- *
- * \param point2D: The screen-space 2D point data to convert.
- * \param depth: Depth array (via #ED_view3d_autodist_depth()).
- * \param r_out: The resulting 2D point data.
- */
void gpencil_stroke_convertcoords_tpoint(Scene *scene,
ARegion *region,
Object *ob,
@@ -991,8 +865,12 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene,
{
ToolSettings *ts = scene->toolsettings;
+ if (depth && (*depth == DEPTH_INVALID)) {
+ depth = NULL;
+ }
+
int mval_i[2];
- round_v2i_v2fl(mval_i, &point2D->x);
+ round_v2i_v2fl(mval_i, point2D->m_xy);
if ((depth != NULL) && (ED_view3d_autodist_simple(region, mval_i, r_out, 0, depth))) {
/* projecting onto 3D-Geometry
@@ -1000,7 +878,7 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene,
*/
}
else {
- float mval_f[2] = {point2D->x, point2D->y};
+ float mval_f[2] = {UNPACK2(point2D->m_xy)};
float mval_prj[2];
float rvec[3], dvec[3];
float zfac;
@@ -1023,10 +901,6 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene,
}
}
-/**
- * Get drawing reference point for conversion or projection of the stroke
- * \param r_vec: Reference point found
- */
void ED_gpencil_drawing_reference_get(const Scene *scene,
const Object *ob,
char align_flag,
@@ -1094,9 +968,6 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke *
}
}
-/**
- * Reproject all points of the stroke to a plane locked to axis to avoid stroke offset
- */
void ED_gpencil_project_stroke_to_plane(const Scene *scene,
const Object *ob,
const RegionView3D *rv3d,
@@ -1175,7 +1046,6 @@ void ED_gpencil_project_stroke_to_plane(const Scene *scene,
}
}
-/* Reproject selected strokes */
void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
const GP_SpaceConversion *gsc,
SnapObjectContext *sctx,
@@ -1292,6 +1162,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
depsgraph, region, v3d, xy, &ray_start[0], &ray_normal[0], true);
if (ED_transform_snap_object_project_ray(sctx,
depsgraph,
+ v3d,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
},
@@ -1315,10 +1186,6 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
}
}
-/**
- * Reproject given point to a plane locked to axis to avoid stroke offset
- * \param pt: Point to affect (used for input & output).
- */
void ED_gpencil_project_point_to_plane(const Scene *scene,
const Object *ob,
bGPDlayer *gpl,
@@ -1401,12 +1268,6 @@ void ED_gpencil_project_point_to_plane(const Scene *scene,
/* XXX: Check if these functions duplicate stuff in blenkernel,
* and/or whether we should just deduplicate. */
-/**
- * Subdivide a stroke once, by adding a point half way between each pair of existing points
- * \param gpd: Datablock
- * \param gps: Stroke data
- * \param subdivide: Number of times to subdivide
- */
void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide)
{
bGPDspoint *temp_points;
@@ -1500,7 +1361,6 @@ void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide
BKE_gpencil_stroke_geometry_update(gpd, gps);
}
-/* Reset parent matrix for all layers. */
void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd)
{
bGPDspoint *pt;
@@ -1550,7 +1410,6 @@ void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata
/* ******************************************************** */
/* GP Object Stuff */
-/* Helper function to create new OB_GPENCIL Object */
Object *ED_gpencil_add_object(bContext *C, const float loc[3], ushort local_view_bits)
{
const float rot[3] = {0.0f};
@@ -1563,7 +1422,6 @@ Object *ED_gpencil_add_object(bContext *C, const float loc[3], ushort local_view
return ob;
}
-/* Helper function to create default colors and drawing brushes */
void ED_gpencil_add_defaults(bContext *C, Object *ob)
{
Main *bmain = CTX_data_main(C);
@@ -1595,7 +1453,6 @@ void ED_gpencil_add_defaults(bContext *C, Object *ob)
/* ******************************************************** */
/* Vertex Groups */
-/* assign points to vertex group */
void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -1649,7 +1506,6 @@ void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
CTX_DATA_END;
}
-/* remove points from vertex group */
void ED_gpencil_vgroup_remove(bContext *C, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -1702,7 +1558,6 @@ void ED_gpencil_vgroup_remove(bContext *C, Object *ob)
CTX_DATA_END;
}
-/* select points of vertex group */
void ED_gpencil_vgroup_select(bContext *C, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -1757,7 +1612,6 @@ void ED_gpencil_vgroup_select(bContext *C, Object *ob)
CTX_DATA_END;
}
-/* unselect points of vertex group */
void ED_gpencil_vgroup_deselect(bContext *C, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -1838,7 +1692,6 @@ static bool gpencil_check_cursor_region(bContext *C, const int mval_i[2])
return false;
}
-/* draw eraser cursor */
void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y)
{
short radius = (short)brush->size;
@@ -2074,7 +1927,6 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat
immUnbindProgram();
}
-/* Turn brush cursor in on/off */
void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
{
Scene *scene = CTX_data_scene(C);
@@ -2102,7 +1954,6 @@ void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
}
}
-/* set object modes */
void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
{
if (!gpd) {
@@ -2169,7 +2020,7 @@ static void gpencil_stroke_convertcoords(ARegion *region,
const float origin[3],
float out[3])
{
- float mval_f[2] = {(float)point2D->x, (float)point2D->y};
+ float mval_f[2] = {UNPACK2(point2D->m_xy)};
float mval_prj[2];
float rvec[3], dvec[3];
float zfac;
@@ -2189,9 +2040,6 @@ static void gpencil_stroke_convertcoords(ARegion *region,
}
}
-/**
- * Convert 2d #tGPspoint to 3d #bGPDspoint.
- */
void ED_gpencil_tpoint_to_point(ARegion *region,
float origin[3],
const tGPspoint *tpt,
@@ -2209,9 +2057,6 @@ void ED_gpencil_tpoint_to_point(ARegion *region,
pt->uv_rot = tpt->uv_rot;
}
-/**
- * Recalculate UV for any stroke using the material.
- */
void ED_gpencil_update_color_uv(Main *bmain, Material *mat)
{
Material *gps_ma = NULL;
@@ -2419,7 +2264,6 @@ static float gpencil_calc_factor(const float p2d_a1[2],
return f;
}
-/* extend selection to stroke intersections */
int ED_gpencil_select_stroke_segment(bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
@@ -2800,10 +2644,6 @@ void ED_gpencil_select_curve_toggle_all(bContext *C, int action)
}
}
-/**
- * Ensure the #tGPspoint buffer (while drawing stroke)
- * size is enough to save all points of the stroke.
- */
tGPspoint *ED_gpencil_sbuffer_ensure(tGPspoint *buffer_array,
int *buffer_size,
int *buffer_used,
@@ -2854,9 +2694,6 @@ void ED_gpencil_sbuffer_update_eval(bGPdata *gpd, Object *ob_eval)
gpd_eval->runtime.cp_points = gpd->runtime.cp_points;
}
-/**
- * Tag all scene grease pencil object to update.
- */
void ED_gpencil_tag_scene_gpencil(Scene *scene)
{
/* Mark all grease pencil data-blocks of the scene. */
@@ -2971,8 +2808,8 @@ static void gpencil_sbuffer_vertex_color_random(
if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
- int ix = (int)(tpt->x * seed);
- int iy = (int)(tpt->y * seed);
+ int ix = (int)(tpt->m_xy[0] * seed);
+ int iy = (int)(tpt->m_xy[1] * seed);
int iz = ix + iy * seed;
float hsv[3];
float factor_value[3];
@@ -3105,7 +2942,6 @@ void ED_gpencil_sbuffer_vertex_color_set(Depsgraph *depsgraph,
}
}
-/* Get the bigger 2D bound box points. */
void ED_gpencil_projected_2d_bound_box(const GP_SpaceConversion *gsc,
const bGPDstroke *gps,
const float diff_mat[4][4],
@@ -3139,7 +2975,6 @@ void ED_gpencil_projected_2d_bound_box(const GP_SpaceConversion *gsc,
}
}
-/* Check if the stroke collides with brush. */
bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
bGPDstroke *gps,
const float mouse[2],
@@ -3166,15 +3001,6 @@ bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
return BLI_rcti_isect(&rect_stroke, &rect_mouse, NULL);
}
-/**
- * Check if a point is inside of the stroke.
- *
- * \param gps: Stroke to check.
- * \param gsc: Space conversion data.
- * \param mouse: Mouse position.
- * \param diff_mat: View matrix.
- * \return True if the point is inside.
- */
bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
const GP_SpaceConversion *gsc,
const int mouse[2],
@@ -3213,7 +3039,6 @@ bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
return hit;
}
-/* Get extremes of stroke in 2D using current view. */
void ED_gpencil_stroke_extremes_to2d(const GP_SpaceConversion *gsc,
const float diff_mat[4][4],
bGPDstroke *gps,
@@ -3328,7 +3153,6 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
return gps_rtn;
}
-/* Join two stroke using a contact point index and trimming the rest. */
bGPDstroke *ED_gpencil_stroke_join_and_trim(
bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *gps_dst, const int pt_index)
{
@@ -3371,7 +3195,7 @@ bGPDstroke *ED_gpencil_stroke_join_and_trim(
}
/* Remove tagged points to trim stroke. */
gps_final = BKE_gpencil_stroke_delete_tagged_points(
- gpd, gpf, gps_dst, gps_dst->next, GP_SPOINT_TAG, false, 0);
+ gpd, gpf, gps_dst, gps_dst->next, GP_SPOINT_TAG, false, false, 0);
}
/* Join both strokes. */
@@ -3398,7 +3222,6 @@ bGPDstroke *ED_gpencil_stroke_join_and_trim(
return gps_final;
}
-/* Close if the distance between extremes is below threshold. */
void ED_gpencil_stroke_close_by_distance(bGPDstroke *gps, const float threshold)
{
if (gps == NULL) {
@@ -3414,3 +3237,70 @@ void ED_gpencil_stroke_close_by_distance(bGPDstroke *gps, const float threshold)
BKE_gpencil_stroke_close(gps);
}
}
+
+void ED_gpencil_layer_merge(bGPdata *gpd,
+ bGPDlayer *gpl_src,
+ bGPDlayer *gpl_dst,
+ const bool reverse)
+{
+ /* Collect frames of gpl_dst in hash table to avoid O(n^2) lookups. */
+ GHash *gh_frames_dst = BLI_ghash_int_new_ex(__func__, 64);
+ LISTBASE_FOREACH (bGPDframe *, gpf_dst, &gpl_dst->frames) {
+ BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_dst->framenum), gpf_dst);
+ }
+
+ /* Read all frames from merge layer and add any missing in destination layer,
+ * copying all previous strokes to keep the image equals.
+ * Need to do it in a separated loop to avoid strokes accumulation. */
+ LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
+ /* Try to find frame in destination layer hash table. */
+ bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum));
+ if (!gpf_dst) {
+ gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf_src->framenum, GP_GETFRAME_ADD_COPY);
+ /* Use same frame type. */
+ gpf_dst->key_type = gpf_src->key_type;
+ BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst);
+ }
+ }
+
+ /* Read all frames from merge layer and add strokes. */
+ LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
+ /* Try to find frame in destination layer hash table. */
+ bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum));
+ /* Add to tail all strokes. */
+ if (gpf_dst) {
+ if (reverse) {
+ BLI_movelisttolist_reverse(&gpf_dst->strokes, &gpf_src->strokes);
+ }
+ else {
+ BLI_movelisttolist(&gpf_dst->strokes, &gpf_src->strokes);
+ }
+ }
+ }
+
+ /* Add Masks to destination layer. */
+ LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl_src->mask_layers) {
+ /* Don't add merged layers or missing layer names. */
+ if (!BKE_gpencil_layer_named_get(gpd, mask->name) || STREQ(mask->name, gpl_src->info) ||
+ STREQ(mask->name, gpl_dst->info)) {
+ continue;
+ }
+ if (!BKE_gpencil_layer_mask_named_get(gpl_dst, mask->name)) {
+ bGPDlayer_Mask *mask_new = MEM_dupallocN(mask);
+ BLI_addtail(&gpl_dst->mask_layers, mask_new);
+ gpl_dst->act_mask++;
+ }
+ }
+
+ /* Set destination layer as active. */
+ BKE_gpencil_layer_active_set(gpd, gpl_dst);
+
+ /* Now delete merged layer. */
+ BKE_gpencil_layer_delete(gpd, gpl_src);
+ BLI_ghash_free(gh_frames_dst, NULL, NULL);
+
+ /* Reorder masking. */
+ if (gpl_dst->mask_layers.first) {
+ BKE_gpencil_layer_mask_sort(gpd, gpl_dst);
+ }
+}
diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c
index 5c3a7cf9e6f..891bd3ca5ec 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_ops.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c
@@ -54,7 +54,7 @@
static const EnumPropertyItem gpencil_modesEnumPropertyItem_mode[] = {
{GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", ""},
{GPPAINT_MODE_FILL, "FILL", 0, "Fill", ""},
- {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", ""},
+ {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -1142,7 +1142,7 @@ void GPENCIL_OT_stroke_reset_vertex_color(wmOperatorType *ot)
static EnumPropertyItem mode_types_items[] = {
{GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Reset Vertex Color to Stroke only"},
{GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Reset Vertex Color to Fill only"},
- {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Reset Vertex Color to Stroke and Fill"},
+ {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", "Reset Vertex Color to Stroke and Fill"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c
index 633e371cbd1..05304f9914f 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_paint.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c
@@ -441,12 +441,12 @@ static bool brush_tint_apply(tGP_BrushVertexpaintData *gso,
CLAMP_MIN(pt->vert_color[3], 0.0f);
}
else {
- /* Premult. */
+ /* Pre-multiply. */
mul_v3_fl(pt->vert_color, pt->vert_color[3]);
/* "Alpha over" blending. */
interp_v3_v3v3(pt->vert_color, pt->vert_color, gso->linear_color, inf);
pt->vert_color[3] = pt->vert_color[3] * (1.0 - inf) + inf;
- /* Un-premult. */
+ /* Un pre-multiply. */
if (pt->vert_color[3] > 0.0f) {
mul_v3_fl(pt->vert_color, 1.0f / pt->vert_color[3]);
}
@@ -460,12 +460,12 @@ static bool brush_tint_apply(tGP_BrushVertexpaintData *gso,
CLAMP_MIN(gps->vert_color_fill[3], 0.0f);
}
else {
- /* Premult. */
+ /* Pre-multiply. */
mul_v3_fl(gps->vert_color_fill, gps->vert_color_fill[3]);
/* "Alpha over" blending. */
interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, gso->linear_color, inf_fill);
gps->vert_color_fill[3] = gps->vert_color_fill[3] * (1.0 - inf_fill) + inf_fill;
- /* Un-premult. */
+ /* Un pre-multiply. */
if (gps->vert_color_fill[3] > 0.0f) {
mul_v3_fl(gps->vert_color_fill, 1.0f / gps->vert_color_fill[3]);
}
@@ -865,7 +865,7 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
int mval_i[2];
@@ -905,7 +905,7 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
gpencil_point_to_parent_space(pt2, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
- /* Check that point segment of the boundbox of the selection stroke */
+ /* Check that point segment of the bound-box of the selection stroke. */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c
index d14322e12b5..15f99d83f6d 100644
--- a/source/blender/editors/gpencil/gpencil_weight_paint.c
+++ b/source/blender/editors/gpencil/gpencil_weight_paint.c
@@ -29,15 +29,18 @@
#include "BLT_translation.h"
+#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_gpencil_types.h"
+#include "BKE_action.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
#include "BKE_main.h"
+#include "BKE_modifier.h"
#include "BKE_object_deform.h"
#include "BKE_report.h"
#include "DNA_meshdata_types.h"
@@ -246,7 +249,22 @@ static bool brush_draw_apply(tGP_BrushWeightpaintData *gso,
/* need a vertex group */
if (gso->vrgroup == -1) {
if (gso->object) {
- BKE_object_defgroup_add(gso->object);
+ Object *ob_armature = BKE_modifiers_is_deformed_by_armature(gso->object);
+ if ((ob_armature != NULL)) {
+ Bone *actbone = ((bArmature *)ob_armature->data)->act_bone;
+ if (actbone != NULL) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob_armature->pose, actbone->name);
+ if (pchan != NULL) {
+ bDeformGroup *dg = BKE_object_defgroup_find_name(gso->object, pchan->name);
+ if (dg == NULL) {
+ dg = BKE_object_defgroup_add_name(gso->object, pchan->name);
+ }
+ }
+ }
+ }
+ else {
+ BKE_object_defgroup_add(gso->object);
+ }
DEG_relations_tag_update(gso->bmain);
gso->vrgroup = 0;
}
@@ -414,7 +432,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso,
gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
int mval_i[2];
@@ -443,7 +461,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso,
gpencil_point_to_parent_space(pt2, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
- /* Check that point segment of the boundbox of the selection stroke */
+ /* Check that point segment of the bound-box of the selection stroke */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 0a1cf643f37..61dd0adc84d 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -46,9 +46,45 @@ typedef struct IMMDrawPixelsTexState {
/* To be used before calling immDrawPixelsTex
* Default shader is GPU_SHADER_2D_IMAGE_COLOR
* Returns a shader to be able to set uniforms */
+/**
+ * To be used before calling #immDrawPixelsTex
+ * Default shader is #GPU_SHADER_2D_IMAGE_COLOR
+ * You can still set uniforms with:
+ * `GPU_shader_uniform_int(shader, GPU_shader_get_uniform(shader, "name"), 0);`
+ */
IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin);
/**
+ * Unlike the `immDrawPixelsTexTiled` functions, this doesn't do tiled drawing, but draws into a
+ * full texture.
+ *
+ * Use the currently bound shader.
+ *
+ * Use #immDrawPixelsTexSetup to bind the shader you want before calling #immDrawPixelsTex.
+ *
+ * If using a special shader double check it uses the same attributes "pos" "texCoord" and uniform
+ * "image".
+ *
+ * If color is NULL then use white by default
+ *
+ * Unless <em>state->do_shader_unbind<em> is explicitly set to `false`, the shader is unbound when
+ * finished.
+ */
+void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state,
+ const float x,
+ const float y,
+ const int img_w,
+ const int img_h,
+ const eGPUTextureFormat gpu_format,
+ const bool use_filter,
+ const void *rect,
+ const float scaleX,
+ const float scaleY,
+ const float xzoom,
+ const float yzoom,
+ const float color[4]);
+
+/**
* #immDrawPixelsTex - Functions like a limited #glDrawPixels, but actually draws the
* image using textures, which can be tremendously faster on low-end
* cards, and also avoids problems with the raster position being
@@ -62,62 +98,76 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin);
* model-view and projection matrices are assumed to define a
* 1-to-1 mapping to screen space.
*/
-void immDrawPixelsTex(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float xzoom,
- float yzoom,
- const float color[4]);
-void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float clip_min_x,
- float clip_min_y,
- float clip_max_x,
- float clip_max_y,
- float xzoom,
- float yzoom,
- const float color[4]);
-void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float scaleX,
- float scaleY,
- float xzoom,
- float yzoom,
- const float color[4]);
-void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float scaleX,
- float scaleY,
- float clip_min_x,
- float clip_min_y,
- float clip_max_x,
- float clip_max_y,
- float xzoom,
- float yzoom,
- const float color[4]);
+void immDrawPixelsTexTiled(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float xzoom,
+ float yzoom,
+ const float color[4]);
+void immDrawPixelsTexTiled_clipping(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float clip_min_x,
+ float clip_min_y,
+ float clip_max_x,
+ float clip_max_y,
+ float xzoom,
+ float yzoom,
+ const float color[4]);
+void immDrawPixelsTexTiled_scaling(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float scaleX,
+ float scaleY,
+ float xzoom,
+ float yzoom,
+ const float color[4]);
+/**
+ * Use the currently bound shader.
+ *
+ * Use #immDrawPixelsTexSetup to bind the shader you
+ * want before calling #immDrawPixelsTex.
+ *
+ * If using a special shader double check it uses the same
+ * attributes "pos" "texCoord" and uniform "image".
+ *
+ * If color is NULL then use white by default
+ *
+ * Unless <em>state->do_shader_unbind<em> is explicitly set to `false`, the shader is unbound when
+ * finished.
+ */
+void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float scaleX,
+ float scaleY,
+ float clip_min_x,
+ float clip_min_y,
+ float clip_max_x,
+ float clip_max_y,
+ float xzoom,
+ float yzoom,
+ const float color[4]);
/* Image buffer drawing functions, with display transform
*
@@ -135,6 +185,9 @@ void ED_draw_imbuf(struct ImBuf *ibuf,
struct ColorManagedDisplaySettings *display_settings,
float zoom_x,
float zoom_y);
+/**
+ * Draw given image buffer on a screen using GLSL for display transform.
+ */
void ED_draw_imbuf_clipping(struct ImBuf *ibuf,
float x,
float y,
@@ -169,6 +222,9 @@ void ED_draw_imbuf_ctx_clipping(const struct bContext *C,
int ED_draw_imbuf_method(struct ImBuf *ibuf);
+/**
+ * Don't move to `GPU_immediate_util.h` because this uses user-prefs and isn't very low level.
+ */
void immDrawBorderCorners(unsigned int pos, const struct rcti *border, float zoomx, float zoomy);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index e9601220f2e..3294316f880 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -63,7 +63,9 @@ struct PropertyRNA;
/* ANIMATION CHANNEL FILTERING */
/* anim_filter.c */
-/* --------------- Context --------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Context
+ * \{ */
/* This struct defines a structure used for animation-specific
* 'context' information
@@ -126,7 +128,11 @@ typedef enum eAnimCont_Types {
ANIMCONT_TIMELINE = 10, /* "timeline" editor (bDopeSheet) */
} eAnimCont_Types;
-/* --------------- Channels -------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Channels
+ * \{ */
/* This struct defines a structure used for quick and uniform access for
* channels of animation data
@@ -281,7 +287,11 @@ typedef enum eAnim_Update_Flags {
#define ANIM_UPDATE_DEFAULT (ANIM_UPDATE_DEPS | ANIM_UPDATE_ORDER | ANIM_UPDATE_HANDLES)
#define ANIM_UPDATE_DEFAULT_NOHANDLES (ANIM_UPDATE_DEFAULT & ~ANIM_UPDATE_HANDLES)
-/* ----------------- Filtering -------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Filtering
+ * \{ */
/* filtering flags - under what circumstances should a channel be returned */
typedef enum eAnimFilter_Flags {
@@ -334,7 +344,12 @@ typedef enum eAnimFilter_Flags {
ANIMFILTER_TMP_IGNORE_ONLYSEL = (1u << 31),
} eAnimFilter_Flags;
-/* ---------- Flag Checking Macros ------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flag Checking Macros
+ * \{ */
+
/* XXX check on all of these flags again. */
/* Dopesheet only */
@@ -421,7 +436,11 @@ typedef enum eAnimFilter_Flags {
/* AnimData - NLA mostly... */
#define SEL_ANIMDATA(adt) (adt->flag & ADT_UI_SELECTED)
-/* -------------- Channel Defines -------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Channel Defines
+ * \{ */
/* channel heights */
#define ACHANNEL_FIRST_TOP(ac) \
@@ -439,7 +458,11 @@ typedef enum eAnimFilter_Flags {
/* channel toggle-buttons */
#define ACHANNEL_BUTTON_WIDTH (0.8f * U.widget_unit)
-/* -------------- NLA Channel Defines -------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NLA Channel Defines
+ * \{ */
/* NLA channel heights */
#define NLACHANNEL_FIRST_TOP(ac) \
@@ -459,10 +482,19 @@ typedef enum eAnimFilter_Flags {
/* channel toggle-buttons */
#define NLACHANNEL_BUTTON_WIDTH (0.8f * U.widget_unit)
-/* ---------------- API -------------------- */
+/** \} */
-/* Obtain list of filtered Animation channels to operate on.
- * Returns the number of channels in the list
+/* -------------------------------------------------------------------- */
+/** \name Public API
+ * \{ */
+
+/**
+ * This function filters the active data source to leave only animation channels suitable for
+ * usage by the caller. It will return the length of the list
+ *
+ * \param anim_data: Is a pointer to a #ListBase,
+ * to which the filtered animation channels will be placed for use.
+ * \param filter_mode: how should the data be filtered - bit-mapping accessed flags.
*/
size_t ANIM_animdata_filter(bAnimContext *ac,
ListBase *anim_data,
@@ -470,18 +502,27 @@ size_t ANIM_animdata_filter(bAnimContext *ac,
void *data,
eAnimCont_Types datatype);
-/* Obtain current anim-data context from Blender Context info.
- * Returns whether the operation was successful.
+/**
+ * Obtain current anim-data context from Blender Context info
+ * - AnimContext to write to is provided as pointer to var on stack so that we don't have
+ * allocation/freeing costs (which are not that avoidable with channels).
+ * - Clears data and sets the information from Blender Context which is useful
+ * \return whether the operation was successful.
*/
bool ANIM_animdata_get_context(const struct bContext *C, bAnimContext *ac);
-/* Obtain current anim-data context (from Animation Editor) given
- * that Blender Context info has already been set.
- * Returns whether the operation was successful.
+/**
+ * Obtain current anim-data context,
+ * given that context info from Blender context has already been set:
+ * - AnimContext to write to is provided as pointer to var on stack so that we don't have
+ * allocation/freeing costs (which are not that avoidable with channels).
+ * \return whether the operation was successful.
*/
bool ANIM_animdata_context_getdata(bAnimContext *ac);
-/* Acts on bAnimListElem eAnim_Update_Flags */
+/**
+ * Acts on bAnimListElem eAnim_Update_Flags.
+ */
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data);
void ANIM_animdata_freelist(ListBase *anim_data);
@@ -490,7 +531,11 @@ void ANIM_animdata_freelist(ListBase *anim_data);
/* ANIMATION CHANNELS LIST */
/* anim_channels_*.c */
-/* ------------------------ Drawing TypeInfo -------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing TypeInfo
+ * \{ */
/* role or level of animchannel in the hierarchy */
typedef enum eAnimChannel_Role {
@@ -569,18 +614,35 @@ typedef struct bAnimChannelType {
void *(*setting_ptr)(bAnimListElem *ale, eAnimChannel_Settings setting, short *type);
} bAnimChannelType;
-/* ------------------------ Drawing API -------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing API
+ * \{ */
-/* Get typeinfo for the given channel */
+/**
+ * Get type info from given channel type.
+ */
const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale);
-/* Print debugging info about a given channel */
+/**
+ * Print debug info string for the given channel.
+ */
void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level);
-/* Draw the given channel */
+/**
+ * Retrieves the Action associated with this animation channel.
+ */
+bAction *ANIM_channel_action_get(const bAnimListElem *ale);
+
+/**
+ * Draw the given channel.
+ */
void ANIM_channel_draw(
bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index);
-/* Draw the widgets for the given channel */
+/**
+ * Draw UI widgets the given channel.
+ */
void ANIM_channel_draw_widgets(const struct bContext *C,
bAnimContext *ac,
bAnimListElem *ale,
@@ -588,27 +650,30 @@ void ANIM_channel_draw_widgets(const struct bContext *C,
rctf *rect,
size_t channel_index);
-/* ------------------------ Editing API -------------------------- */
+/** \} */
-/* Check if some setting for a channel is enabled
- * Returns: 1 = On, 0 = Off, -1 = Invalid
- *
- * - setting: eAnimChannel_Settings
+/* -------------------------------------------------------------------- */
+/** \name Editing API
+ * \{ */
+
+/**
+ * Check if some setting for a channel is enabled
+ * Returns: 1 = On, 0 = Off, -1 = Invalid.
*/
short ANIM_channel_setting_get(bAnimContext *ac,
bAnimListElem *ale,
eAnimChannel_Settings setting);
-/* Change value of some setting for a channel
- * - setting: eAnimChannel_Settings
- * - mode: eAnimChannels_SetFlag
+/**
+ * Change value of some setting for a channel.
*/
void ANIM_channel_setting_set(bAnimContext *ac,
bAnimListElem *ale,
eAnimChannel_Settings setting,
eAnimChannels_SetFlag mode);
-/* Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting
+/**
+ * Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting
* - anim_data: list of the all the anim channels that can be chosen
* -> filtered using ANIMFILTER_CHANNELS only, since if we took VISIBLE too,
* then the channels under closed expanders get ignored...
@@ -623,13 +688,19 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac,
eAnimChannel_Settings setting,
eAnimChannels_SetFlag mode);
-/* Select or deselect animation channels */
+/**
+ * Set selection state of all animation channels in the context.
+ */
void ANIM_anim_channels_select_set(bAnimContext *ac, eAnimChannels_SetFlag sel);
-/* Toggle selection of animation channels */
+/**
+ * Toggle selection state of all animation channels in the context.
+ */
void ANIM_anim_channels_select_toggle(bAnimContext *ac);
-/* Set the 'active' channel of type channel_type, in the given action */
+/**
+ * Set the given animation-channel as the active one for the active context.
+ */
void ANIM_set_active_channel(bAnimContext *ac,
void *data,
eAnimCont_Types datatype,
@@ -637,18 +708,31 @@ void ANIM_set_active_channel(bAnimContext *ac,
void *channel_data,
eAnim_ChannelType channel_type);
-/* Delete the F-Curve from the given AnimData block (if possible),
- * as appropriate according to animation context */
+/**
+ * Delete the F-Curve from the given AnimData block (if possible),
+ * as appropriate according to animation context.
+ */
void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, struct AnimData *adt, struct FCurve *fcu);
-/* Unlink the action from animdata if it's empty. */
+/**
+ * Unlink the action from animdata if it's empty.
+ *
+ * If the action has no F-Curves, unlink it from AnimData if it did not
+ * come from a NLA Strip being tweaked.
+ */
bool ANIM_remove_empty_action_from_animdata(struct AnimData *adt);
/* ************************************************ */
/* DRAWING API */
/* anim_draw.c */
-/* ---------- Current Frame Drawing ---------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Current Frame Drawing
+ *
+ * Main call to draw current-frame indicator in an Animation Editor.
+ * \{ */
/* flags for Current Frame Drawing */
typedef enum eAnimEditDraw_CurrentFrame {
@@ -660,23 +744,54 @@ typedef enum eAnimEditDraw_CurrentFrame {
DRAWCFRA_WIDE = (1 << 1),
} eAnimEditDraw_CurrentFrame;
-/* main call to draw current-frame indicator in an Animation Editor */
+/**
+ * General call for drawing current frame indicator in animation editor.
+ */
void ANIM_draw_cfra(const struct bContext *C, struct View2D *v2d, short flag);
-/* ------------- Preview Range Drawing -------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Preview Range Drawing
+ *
+ * Main call to draw preview range curtains.
+ * \{ */
-/* main call to draw preview range curtains */
+/**
+ * Draw preview range 'curtains' for highlighting where the animation data is.
+ */
void ANIM_draw_previewrange(const struct bContext *C, struct View2D *v2d, int end_frame_width);
-/* -------------- Frame Range Drawing --------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Frame Range Drawing
+ *
+ * Main call to draw normal frame range indicators.
+ * \{ */
-/* main call to draw normal frame range indicators */
+/**
+ * Draw frame range guides (for scene frame range) in background.
+ *
+ * TODO: Should we still show these when preview range is enabled?
+ */
void ANIM_draw_framerange(struct Scene *scene, struct View2D *v2d);
+/**
+ * Draw manually set intended playback frame range guides for the action in the background.
+ * Allows specifying a subset of the Y range of the view.
+ */
+void ANIM_draw_action_framerange(
+ struct AnimData *adt, struct bAction *action, struct View2D *v2d, float ymin, float ymax);
+
/* ************************************************* */
/* F-MODIFIER TOOLS */
-/* ------------- UI Panel Drawing -------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UI Panel Drawing
+ * \{ */
bool ANIM_nla_context_track_ptr(const struct bContext *C, struct PointerRNA *r_ptr);
bool ANIM_nla_context_strip_ptr(const struct bContext *C, struct PointerRNA *r_ptr);
@@ -690,6 +805,9 @@ typedef bool (*PanelTypePollFn)(const struct bContext *C, struct PanelType *pt);
/* Avoid including "UI_interface.h" here. */
typedef void (*uiListPanelIDFromDataFunc)(void *data_link, char *r_idname);
+/**
+ * Checks if the panels match the active strip / curve, rebuilds them if they don't.
+ */
void ANIM_fmodifier_panels(const struct bContext *C,
struct ID *owner_id,
struct ListBase *fmodifiers,
@@ -702,49 +820,93 @@ void ANIM_modifier_panels_register_graph_only(struct ARegionType *region_type,
const char *modifier_panel_prefix,
PanelTypePollFn poll_function);
-/* ------------- Copy/Paste Buffer -------------- */
+/** \} */
-/* free the copy/paste buffer */
+/* -------------------------------------------------------------------- */
+/** \name Copy/Paste Buffer
+ * \{ */
+
+/**
+ * Free the copy/paste buffer.
+ */
void ANIM_fmodifiers_copybuf_free(void);
-/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
- * assuming that the buffer has been cleared already with ANIM_fmodifiers_copybuf_free()
- * - active: only copy the active modifier
+/**
+ * Copy the given F-Modifiers to the buffer, returning whether anything was copied or not
+ * assuming that the buffer has been cleared already with #ANIM_fmodifiers_copybuf_free()
+ * \param active: Only copy the active modifier.
*/
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active);
-/* 'Paste' the F-Modifier(s) from the buffer to the specified list
- * - replace: free all the existing modifiers to leave only the pasted ones
+/**
+ * 'Paste' the F-Modifier(s) from the buffer to the specified list
+ * \param replace: Free all the existing modifiers to leave only the pasted ones.
*/
bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, struct FCurve *curve);
/* ************************************************* */
/* ASSORTED TOOLS */
-/* ------------ Animation F-Curves <-> Icons/Names Mapping ------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation F-Curves <-> Icons/Names Mapping
+ * \{ */
+
/* anim_ipo_utils.c */
-/* Get icon + name for channel-list displays for F-Curve */
+/**
+ * Get icon + name for channel-list displays for F-Curve.
+ *
+ * Write into "name" buffer, the name of the property
+ * (retrieved using RNA from the curve's settings),
+ * and return the icon used for the struct that this property refers to
+ *
+ * \warning name buffer we're writing to cannot exceed 256 chars
+ * (check anim_channels_defines.c for details).
+ */
int getname_anim_fcurve(char *name, struct ID *id, struct FCurve *fcu);
-/* Automatically determine a color for the nth F-Curve */
+/**
+ * Automatically determine a color for the nth F-Curve.
+ */
void getcolor_fcurve_rainbow(int cur, int tot, float out[3]);
-/* ----------------- NLA Drawing ----------------------- */
-/* NOTE: Technically, this is not in the animation module (it's in space_nla)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NLA Drawing
+ *
+ * \note Technically, this is not in the animation module (it's in space_nla)
* but these are sometimes needed by various animation API's.
- */
+ * \{ */
-/* Get color to use for NLA Action channel's background */
+/**
+ * Get color to use for NLA Action channel's background.
+ * \note color returned includes fine-tuned alpha!
+ */
void nla_action_get_color(struct AnimData *adt, struct bAction *act, float color[4]);
-/* ----------------- NLA-Mapping ----------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NLA-Mapping
+ * \{ */
+
/* anim_draw.c */
-/* Obtain the AnimData block providing NLA-scaling for the given channel if applicable */
+/**
+ * Obtain the AnimData block providing NLA-mapping for the given channel (if applicable).
+ *
+ * TODO: do not supply return this if the animdata tells us that there is no mapping to perform.
+ */
struct AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale);
-/* Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve */
+/**
+ * Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve
+ * \param restore: Whether to map points back to non-mapped time.
+ * \param only_keys: Whether to only adjust the location of the center point of beztriples.
+ */
void ANIM_nla_mapping_apply_fcurve(struct AnimData *adt,
struct FCurve *fcu,
bool restore,
@@ -752,11 +914,18 @@ void ANIM_nla_mapping_apply_fcurve(struct AnimData *adt,
/* ..... */
-/* Perform auto-blending/extend refreshes after some operations */
-/* NOTE: defined in space_nla/nla_edit.c, not in animation/ */
+/**
+ * Perform validation & auto-blending/extend refreshes after some operations
+ * \note defined in space_nla/nla_edit.c, not in animation/
+ */
void ED_nla_postop_refresh(bAnimContext *ac);
-/* ------------- Unit Conversion Mappings ------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Unit Conversion Mappings
+ * \{ */
+
/* anim_draw.c */
/* flags for conversion mapping */
@@ -778,16 +947,24 @@ typedef enum eAnimUnitConv_Flags {
ANIM_UNITCONV_NORMALIZE_FREEZE = (1 << 6),
} eAnimUnitConv_Flags;
-/* Normalization flags from Space Graph passing to ANIM_unit_mapping_get_factor */
+/**
+ * Get flags used for normalization in ANIM_unit_mapping_get_factor.
+ */
short ANIM_get_normalization_flags(bAnimContext *ac);
-
-/* Get unit conversion factor for given ID + F-Curve */
+/**
+ * Get unit conversion factor for given ID + F-Curve.
+ */
float ANIM_unit_mapping_get_factor(
struct Scene *scene, struct ID *id, struct FCurve *fcu, short flag, float *r_offset);
-/* ------------- Utility macros ----------------------- */
+/** \} */
-/* provide access to Keyframe Type info in BezTriple
+/* -------------------------------------------------------------------- */
+/** \name Utility macros
+ * \{ */
+
+/**
+ * Provide access to Keyframe Type info in #BezTriple.
* NOTE: this is so that we can change it from being stored in 'hide'
*/
#define BEZKEYTYPE(bezt) ((bezt)->hide)
@@ -830,18 +1007,37 @@ float ANIM_unit_mapping_get_factor(
} \
((void)0)
-/* --------- anim_deps.c, animation updates -------- */
+/** \} */
+/* anim_deps.c */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Updates
+ * \{ */
+
+/**
+ * Tags the given ID block for refreshes (if applicable) due to Animation Editor editing.
+ */
void ANIM_id_update(struct Main *bmain, struct ID *id);
+/**
+ * Tags the given anim list element for refreshes (if applicable) due to Animation Editor editing.
+ */
void ANIM_list_elem_update(struct Main *bmain, struct Scene *scene, bAnimListElem *ale);
/* data -> channels syncing */
+
+/**
+ * Main call to be exported to animation editors.
+ */
void ANIM_sync_animchannels_to_data(const struct bContext *C);
void ANIM_center_frame(struct bContext *C, int smooth_viewtx);
-/* ************************************************* */
-/* OPERATORS */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operators
+ * \{ */
/* generic animation channels */
void ED_operatortypes_animchannels(void);
@@ -856,12 +1052,20 @@ void ED_operatormacros_graph(void);
/* space_action */
void ED_operatormacros_action(void);
-/* ************************************************ */
-/* Animation Editor Exports */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Editor Exports
+ * \{ */
+
/* XXX: Should we be doing these here, or at all? */
-/* Action Editor - Action Management */
-struct AnimData *ED_actedit_animdata_from_context(struct bContext *C, struct ID **r_adt_id_owner);
+/**
+ * Action Editor - Action Management.
+ * Helper function to find the active AnimData block from the Action Editor context.
+ */
+struct AnimData *ED_actedit_animdata_from_context(const struct bContext *C,
+ struct ID **r_adt_id_owner);
void ED_animedit_unlink_action(struct bContext *C,
struct ID *id,
struct AnimData *adt,
@@ -869,7 +1073,11 @@ void ED_animedit_unlink_action(struct bContext *C,
struct ReportList *reports,
bool force_delete);
-/* Drivers Editor - Utility to set up UI correctly */
+/**
+ * Set up UI configuration for Drivers Editor
+ * (drivers editor window) and RNA (mode switching).
+ * \note Currently called from window-manager.
+ */
void ED_drivers_editor_init(struct bContext *C, struct ScrArea *area);
/* ************************************************ */
@@ -897,8 +1105,14 @@ void animviz_calc_motionpaths(struct Depsgraph *depsgraph,
eAnimvizCalcRange range,
bool restore);
+/**
+ * Get list of motion paths to be baked for the given object.
+ * - assumes the given list is ready to be used.
+ */
void animviz_get_object_motionpaths(struct Object *ob, ListBase *targets);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 868235c36e5..7631bd35e79 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -70,45 +70,91 @@ struct wmOperator;
(CHECK_TYPE_INLINE(ebone, EditBone *), \
(((ebone)->flag & BONE_SELECTED) && !((ebone)->flag & BONE_EDITMODE_LOCKED)))
-/* used in armature_select.c and pose_select.c */
+/* Used in `armature_select.c` and `pose_select.c`. */
+
#define BONE_SELECT_PARENT 0
#define BONE_SELECT_CHILD 1
/* armature_add.c */
+
+/**
+ * Default bone add, returns it selected, but without tail set.
+ *
+ * \note should be used everywhere, now it allocates bones still locally in functions.
+ */
struct EditBone *ED_armature_ebone_add(struct bArmature *arm, const char *name);
struct EditBone *ED_armature_ebone_add_primitive(struct Object *obedit_arm,
float length,
bool view_aligned);
/* armature_edit.c */
+
+/**
+ * Adjust bone roll to align Z axis with vector `align_axis` is in local space and is normalized.
+ */
float ED_armature_ebone_roll_to_vector(const struct EditBone *bone,
const float align_axis[3],
- const bool axis_only);
+ bool axis_only);
+/**
+ * \param centermode: 0 == do center, 1 == center new, 2 == center cursor.
+ *
+ * \note Exported for use in `editors/object/`.
+ */
void ED_armature_origin_set(
struct Main *bmain, struct Object *ob, const float cursor[3], int centermode, int around);
-void ED_armature_edit_transform(struct bArmature *arm, const float mat[4][4], const bool do_props);
-void ED_armature_transform(struct bArmature *arm, const float mat[4][4], const bool do_props);
+/**
+ * See #BKE_armature_transform for object-mode transform.
+ */
+void ED_armature_edit_transform(struct bArmature *arm, const float mat[4][4], bool do_props);
+void ED_armature_transform(struct bArmature *arm, const float mat[4][4], bool do_props);
/* armature_naming.c */
+
+/**
+ * Ensure the bone name is unique.
+ * If bone is already in list, pass it as argument to ignore it.
+ */
void ED_armature_ebone_unique_name(struct ListBase *ebones, char *name, struct EditBone *bone);
+
+/**
+ * Bone Rename (called by UI for renaming a bone).
+ * Seems messy, but that's what you get with not using pointers but channel names :).
+ * \warning make sure the original bone was not renamed yet!
+ */
void ED_armature_bone_rename(struct Main *bmain,
struct bArmature *arm,
const char *oldnamep,
const char *newnamep);
+/**
+ * Renames (by flipping) all selected bones at once.
+ *
+ * This way if we are flipping related bones (e.g., Bone.L, Bone.R) at the same time
+ * all the bones are safely renamed, without conflicting with each other.
+ *
+ * \param arm: Armature the bones belong to
+ * \param bones_names: List of bone conflict elements (#LinkData pointing to names).
+ * \param do_strip_numbers: if set, try to get rid of dot-numbers at end of bone names.
+ */
void ED_armature_bones_flip_names(struct Main *bmain,
struct bArmature *arm,
struct ListBase *bones_names,
- const bool do_strip_numbers);
+ bool do_strip_numbers);
/* armature_ops.c */
+
void ED_operatortypes_armature(void);
void ED_operatormacros_armature(void);
void ED_keymap_armature(struct wmKeyConfig *keyconf);
/* armature_relations.c */
+
+/**
+ * Join armature exec is exported for use in object->join objects operator.
+ */
int ED_armature_join_objects_exec(struct bContext *C, struct wmOperator *op);
/* armature_select.c */
+
struct Base *ED_armature_base_and_ebone_from_select_buffer(struct Base **bases,
uint bases_len,
int hit,
@@ -121,6 +167,9 @@ struct Base *ED_armature_base_and_pchan_from_select_buffer(struct Base **bases,
uint bases_len,
int hit,
struct bPoseChannel **r_pchan);
+/**
+ * For callers that don't need the pose channel.
+ */
struct Base *ED_armature_base_and_bone_from_select_buffer(struct Base **bases,
uint bases_len,
int hit,
@@ -137,11 +186,27 @@ bool ED_armature_edit_select_pick_bone(struct bContext *C,
bool extend,
bool deselect,
bool toggle);
+/**
+ * Bone selection picking for armature edit-mode in the view3d.
+ */
bool ED_armature_edit_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
-bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, const int sel_op);
+/**
+ * Perform a selection operation on elements which have been 'touched',
+ * use for lasso & border select but can be used elsewhere too.
+ *
+ * Tagging is done via #EditBone.temp.i using: #BONESEL_ROOT, #BONESEL_TIP, #BONESEL_BONE
+ * And optionally ignoring end-points using the #BONESEL_ROOT, #BONESEL_TIP right shifted 16 bits.
+ * (used when the values are clipped outside the view).
+ *
+ * \param sel_op: #eSelectOp type.
+ *
+ * \note Visibility checks must be done by the caller.
+ */
+bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, int sel_op);
/* armature_skinning.c */
+
#define ARM_GROUPS_NAME 1
#define ARM_GROUPS_ENVELOPE 2
#define ARM_GROUPS_AUTO 3
@@ -150,44 +215,78 @@ void ED_object_vgroup_calc_from_armature(struct ReportList *reports,
struct Scene *scene,
struct Object *ob,
struct Object *par,
- const int mode,
- const bool mirror);
+ int mode,
+ bool mirror);
/* editarmature_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_armature_undosys_type(struct UndoType *ut);
/* armature_utils.c */
+
+/** Sync selection to parent for connected children. */
void ED_armature_edit_sync_selection(struct ListBase *edbo);
void ED_armature_edit_validate_active(struct bArmature *arm);
+/**
+ * Update the layers_used variable after bones are moved between layer
+ * \note Used to be done in drawing code in 2.7, but that won't work with
+ * Copy-on-Write, as drawing uses evaluated copies.
+ */
void ED_armature_edit_refresh_layer_used(struct bArmature *arm);
+/**
+ * \param clear_connected: When false caller is responsible for keeping the flag in a valid state.
+ */
void ED_armature_ebone_remove_ex(struct bArmature *arm,
struct EditBone *exBone,
bool clear_connected);
void ED_armature_ebone_remove(struct bArmature *arm, struct EditBone *exBone);
bool ED_armature_ebone_is_child_recursive(struct EditBone *ebone_parent,
struct EditBone *ebone_child);
+/**
+ * Finds the first parent shared by \a ebone_child
+ *
+ * \param ebone_child: Children bones to search
+ * \param ebone_child_tot: Size of the ebone_child array
+ * \return The shared parent or NULL.
+ */
struct EditBone *ED_armature_ebone_find_shared_parent(struct EditBone *ebone_child[],
- const unsigned int ebone_child_tot);
+ unsigned int ebone_child_tot);
void ED_armature_ebone_to_mat3(struct EditBone *ebone, float r_mat[3][3]);
void ED_armature_ebone_to_mat4(struct EditBone *ebone, float r_mat[4][4]);
void ED_armature_ebone_from_mat3(struct EditBone *ebone, const float mat[3][3]);
void ED_armature_ebone_from_mat4(struct EditBone *ebone, const float mat[4][4]);
+/**
+ * Return a pointer to the bone of the given name
+ */
struct EditBone *ED_armature_ebone_find_name(const struct ListBase *edbo, const char *name);
+/**
+ * \see #BKE_pose_channel_get_mirrored (pose-mode, matching function)
+ */
struct EditBone *ED_armature_ebone_get_mirrored(const struct ListBase *edbo, struct EditBone *ebo);
void ED_armature_ebone_transform_mirror_update(struct bArmature *arm,
struct EditBone *ebo,
bool check_select);
+/**
+ * If edit-bone (partial) selected, copy data.
+ * context; edit-mode armature, with mirror editing enabled.
+ */
void ED_armature_edit_transform_mirror_update(struct Object *obedit);
+/** Put edit-mode back in Object. */
void ED_armature_from_edit(struct Main *bmain, struct bArmature *arm);
+/** Put armature in edit-mode. */
void ED_armature_to_edit(struct bArmature *arm);
void ED_armature_edit_free(struct bArmature *arm);
void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb);
-void ED_armature_ebone_listbase_free(struct ListBase *lb, const bool do_id_user);
+
+/**
+ * Free's bones and their properties.
+ */
+void ED_armature_ebone_listbase_free(struct ListBase *lb, bool do_id_user);
void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst,
struct ListBase *lb_src,
- const bool do_id_user);
+ bool do_id_user);
-/* low level selection functions which handle */
int ED_armature_ebone_selectflag_get(const struct EditBone *ebone);
void ED_armature_ebone_selectflag_set(struct EditBone *ebone, int flag);
void ED_armature_ebone_select_set(struct EditBone *ebone, bool select);
@@ -198,21 +297,29 @@ void ED_armature_ebone_selectflag_disable(struct EditBone *ebone, int flag);
struct Object *ED_pose_object_from_context(struct bContext *C);
bool ED_object_posemode_exit_ex(struct Main *bmain, struct Object *ob);
bool ED_object_posemode_exit(struct bContext *C, struct Object *ob);
+/** This function is used to process the necessary updates for. */
bool ED_object_posemode_enter_ex(struct Main *bmain, struct Object *ob);
bool ED_object_posemode_enter(struct bContext *C, struct Object *ob);
-/* Corresponds to eAnimvizCalcRange. */
+/** Corresponds to #eAnimvizCalcRange. */
typedef enum ePosePathCalcRange {
POSE_PATH_CALC_RANGE_CURRENT_FRAME,
POSE_PATH_CALC_RANGE_CHANGED,
POSE_PATH_CALC_RANGE_FULL,
} ePosePathCalcRange;
+/**
+ * For the object with pose/action: update paths for those that have got them
+ * This should selectively update paths that exist...
+ *
+ * To be called from various tools that do incremental updates.
+ */
void ED_pose_recalculate_paths(struct bContext *C,
struct Scene *scene,
struct Object *ob,
ePosePathCalcRange range);
/* pose_select.c */
+
void ED_armature_pose_select_pick_bone(struct ViewLayer *view_layer,
struct View3D *v3d,
struct Object *ob,
@@ -220,6 +327,10 @@ void ED_armature_pose_select_pick_bone(struct ViewLayer *view_layer,
bool extend,
bool deselect,
bool toggle);
+/**
+ * Called for mode-less pose selection.
+ * assumes the active object is still on old situation.
+ */
bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer,
struct View3D *v3d,
struct Base *base,
@@ -229,15 +340,31 @@ bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer,
bool deselect,
bool toggle,
bool do_nearest);
+/**
+ * While in weight-paint mode, a single pose may be active as well.
+ * While not common, it's possible we have multiple armatures deforming a mesh.
+ *
+ * This function de-selects all other objects, and selects the new base.
+ * It can't be set to the active object because we need
+ * to keep this set to the weight paint object.
+ */
void ED_armature_pose_select_in_wpaint_mode(struct ViewLayer *view_layer,
struct Base *base_select);
bool ED_pose_deselect_all_multi_ex(struct Base **bases,
uint bases_len,
int select_mode,
- const bool ignore_visibility);
-bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool ignore_visibility);
-bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility);
+ bool ignore_visibility);
+bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, bool ignore_visibility);
+/**
+ * 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT.
+ * When true, 'ignore_visibility' makes this func also affect invisible bones
+ * (hidden or on hidden layers).
+ */
+bool ED_pose_deselect_all(struct Object *ob, int select_mode, bool ignore_visibility);
void ED_pose_bone_select_tag_update(struct Object *ob);
+/**
+ * Utility method for changing the selection status of a bone.
+ */
void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
/* meshlaplacian.c */
@@ -249,7 +376,9 @@ void ED_mesh_deform_bind_callback(struct MeshDeformModifierData *mmd,
/* Pose backups, pose_backup.c */
struct PoseBackup;
-/* Create a backup of those bones that are animated in the given action. */
+/**
+ * Create a backup of those bones that are animated in the given action.
+ */
struct PoseBackup *ED_pose_backup_create_selected_bones(
const struct Object *ob, const struct bAction *action) ATTR_WARN_UNUSED_RESULT;
struct PoseBackup *ED_pose_backup_create_all_bones(
diff --git a/source/blender/editors/include/ED_asset.h b/source/blender/editors/include/ED_asset.h
index 8f19c97e671..3b1d87e8ff7 100644
--- a/source/blender/editors/include/ED_asset.h
+++ b/source/blender/editors/include/ED_asset.h
@@ -36,14 +36,17 @@ void ED_operatortypes_asset(void);
}
#endif
+#include "../asset/ED_asset_catalog.h"
#include "../asset/ED_asset_filter.h"
#include "../asset/ED_asset_handle.h"
#include "../asset/ED_asset_library.h"
#include "../asset/ED_asset_list.h"
#include "../asset/ED_asset_mark_clear.h"
#include "../asset/ED_asset_temp_id_consumer.h"
+#include "../asset/ED_asset_type.h"
/* C++ only headers. */
#ifdef __cplusplus
+# include "../asset/ED_asset_catalog.hh"
# include "../asset/ED_asset_list.hh"
#endif
diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h
index af0643f0d64..c3479c10d58 100644
--- a/source/blender/editors/include/ED_buttons.h
+++ b/source/blender/editors/include/ED_buttons.h
@@ -30,8 +30,13 @@ struct ScrArea;
struct SpaceProperties;
struct bContext;
+/**
+ * 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(struct SpaceProperties *sbuts, short *context_tabs_array);
-bool ED_buttons_tab_has_search_result(struct SpaceProperties *sbuts, const int index);
+bool ED_buttons_tab_has_search_result(struct SpaceProperties *sbuts, int index);
void ED_buttons_search_string_set(struct SpaceProperties *sbuts, const char *value);
int ED_buttons_search_string_length(struct SpaceProperties *sbuts);
@@ -43,7 +48,7 @@ bool ED_buttons_should_sync_with_outliner(const struct bContext *C,
void ED_buttons_set_context(const struct bContext *C,
struct SpaceProperties *sbuts,
PointerRNA *ptr,
- const int context);
+ int context);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h
index 21d8a28e2c9..6167ae3aee6 100644
--- a/source/blender/editors/include/ED_clip.h
+++ b/source/blender/editors/include/ED_clip.h
@@ -56,6 +56,9 @@ void ED_space_clip_get_zoom(struct SpaceClip *sc,
void ED_space_clip_get_aspect(struct SpaceClip *sc, float *aspx, float *aspy);
void ED_space_clip_get_aspect_dimension_aware(struct SpaceClip *sc, float *aspx, float *aspy);
+/**
+ * Return current frame number in clip space.
+ */
int ED_space_clip_get_clip_frame_number(struct SpaceClip *sc);
struct ImBuf *ED_space_clip_get_buffer(struct SpaceClip *sc);
@@ -65,9 +68,12 @@ struct ImBuf *ED_space_clip_get_stable_buffer(struct SpaceClip *sc,
float *angle);
bool ED_space_clip_get_position(struct SpaceClip *sc,
- struct ARegion *ar,
+ struct ARegion *region,
int mval[2],
float fpos[2]);
+/**
+ * Returns color in linear space, matching #ED_space_image_color_sample().
+ */
bool ED_space_clip_color_sample(struct SpaceClip *sc,
struct ARegion *region,
int mval[2],
@@ -82,10 +88,17 @@ bool ED_clip_can_select(struct bContext *C);
void ED_clip_point_undistorted_pos(struct SpaceClip *sc, const float co[2], float r_co[2]);
void ED_clip_point_stable_pos(
struct SpaceClip *sc, struct ARegion *region, float x, float y, float *xr, float *yr);
+/**
+ * \brief the reverse of #ED_clip_point_stable_pos(), gets the marker region coords.
+ * better name here? view_to_track / track_to_view or so?
+ */
void ED_clip_point_stable_pos__reverse(struct SpaceClip *sc,
struct ARegion *region,
const float co[2],
float r_co[2]);
+/**
+ * Takes `event->mval`.
+ */
void ED_clip_mouse_pos(struct SpaceClip *sc,
struct ARegion *region,
const int mval[2],
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 44c5897d3a3..a9225a5db60 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -43,14 +43,22 @@ struct wmKeyConfig;
struct wmOperator;
/* curve_ops.c */
+
void ED_operatortypes_curve(void);
void ED_operatormacros_curve(void);
void ED_keymap_curve(struct wmKeyConfig *keyconf);
/* editcurve.c */
+
struct ListBase *object_editcurve_get(struct Object *ob);
+/**
+ * Load editNurb in object.
+ */
void ED_curve_editnurb_load(struct Main *bmain, struct Object *obedit);
+/**
+ * Make copy in `cu->editnurb`.
+ */
void ED_curve_editnurb_make(struct Object *obedit);
void ED_curve_editnurb_free(struct Object *obedit);
@@ -65,9 +73,14 @@ int ED_curve_nurb_select_count(const struct View3D *v3d, const struct Nurb *nu);
bool ED_curve_nurb_select_all(const struct Nurb *nu);
bool ED_curve_nurb_deselect_all(const struct Nurb *nu);
+/**
+ * This is used externally, by #OBJECT_OT_join.
+ * TODO: shape keys - as with meshes.
+ */
int ED_curve_join_objects_exec(struct bContext *C, struct wmOperator *op);
/* editcurve_select.c */
+
bool ED_curve_select_check(const struct View3D *v3d, const struct EditNurb *editnurb);
bool ED_curve_deselect_all(struct EditNurb *editnurb);
bool ED_curve_deselect_all_multi_ex(struct Base **bases, int bases_len);
@@ -77,14 +90,17 @@ bool ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles);
int ED_curve_select_count(const struct View3D *v3d, const struct EditNurb *editnurb);
/* editcurve_undo.c */
+
+/** Export for ED_undo_sys */
void ED_curve_undosys_type(struct UndoType *ut);
/* editfont.c */
+
void ED_curve_editfont_load(struct Object *obedit);
void ED_curve_editfont_make(struct Object *obedit);
void ED_curve_editfont_free(struct Object *obedit);
-void ED_text_to_object(struct bContext *C, const struct Text *text, const bool split_lines);
+void ED_text_to_object(struct bContext *C, const struct Text *text, bool split_lines);
void ED_curve_beztcpy(struct EditNurb *editnurb,
struct BezTriple *dst,
@@ -92,14 +108,22 @@ void ED_curve_beztcpy(struct EditNurb *editnurb,
int count);
void ED_curve_bpcpy(struct EditNurb *editnurb, struct BPoint *dst, struct BPoint *src, int count);
+/**
+ * Return 0 if animation data wasn't changed, 1 otherwise.
+ */
int ED_curve_updateAnimPaths(struct Main *bmain, struct Curve *cu);
bool ED_curve_active_center(struct Curve *cu, float center[3]);
+/**
+ * TextBox selection
+ */
bool ED_curve_editfont_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
/* editfont_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_font_undosys_type(struct UndoType *ut);
#if 0
diff --git a/source/blender/editors/include/ED_file_indexer.h b/source/blender/editors/include/ED_file_indexer.h
new file mode 100644
index 00000000000..3b19a738b90
--- /dev/null
+++ b/source/blender/editors/include/ED_file_indexer.h
@@ -0,0 +1,153 @@
+/*
+ * 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 edfile
+ */
+
+#pragma once
+
+#include "BLO_readfile.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * File indexing for the file/asset browser.
+ *
+ * This file contains an API to create indexing functionality when listing blend files in
+ * the file browser.
+ *
+ * To implement a custom indexer a `FileIndexerType` struct should be made and passed to the
+ * `filelist_setindexer` function.
+ */
+
+struct AssetLibraryReference;
+struct LinkNode;
+
+/**
+ * Result code of the `read_index` callback.
+ */
+typedef enum eFileIndexerResult {
+ /**
+ * File listing entries are loaded from the index. Reading entries from the blend file itself
+ * should be skipped.
+ */
+ FILE_INDEXER_ENTRIES_LOADED,
+
+ /**
+ * Index isn't available or not up to date. Entries should be read from the blend file and
+ * `update_index` must be called to update the index.
+ */
+ FILE_INDEXER_NEEDS_UPDATE,
+} eFileIndexerResult;
+
+/**
+ * FileIndexerEntry contains all data that is required to create a file listing entry.
+ */
+typedef struct FileIndexerEntry {
+ struct BLODataBlockInfo datablock_info;
+ short idcode;
+} FileIndexerEntry;
+
+/**
+ * Contains all entries of a blend file.
+ */
+typedef struct FileIndexerEntries {
+ struct LinkNode /* FileIndexerEntry */ *entries;
+} FileIndexerEntries;
+
+typedef void *(*FileIndexerInitUserDataFunc)(const char *root_directory,
+ size_t root_directory_maxlen);
+typedef void (*FileIndexerFreeUserDataFunc)(void *);
+typedef void (*FileIndexerFinishedFunc)(void *);
+typedef eFileIndexerResult (*FileIndexerReadIndexFunc)(const char *file_name,
+ FileIndexerEntries *entries,
+ int *r_read_entries_len,
+ void *user_data);
+typedef void (*FileIndexerUpdateIndexFunc)(const char *file_name,
+ FileIndexerEntries *entries,
+ void *user_data);
+
+typedef struct FileIndexerType {
+ /**
+ * Is called at the beginning of the file listing process. An indexer can
+ * setup needed data. The result of this function will be passed around as `user_data` parameter.
+ *
+ * This is an optional callback.
+ */
+ FileIndexerInitUserDataFunc init_user_data;
+
+ /**
+ * Is called at the end of the file listing process. An indexer can free the data that it created
+ * during the file listing process.
+ *
+ * This is an optional callback */
+ FileIndexerFreeUserDataFunc free_user_data;
+
+ /**
+ * Is called at the end of the file listing process (before the `free_user_data`) where indexes
+ * can perform clean-ups.
+ *
+ * This is an optional callback. Called when listing files completed.
+ */
+ FileIndexerFinishedFunc filelist_finished;
+
+ /**
+ * Is called for each blend file being listed to read data from the index.
+ *
+ * Read entries should be added to given `entries` parameter (type: `FileIndexerEntries`).
+ * `*r_read_entries_len` must be set to the number of read entries.
+ * and the function must return `eFileIndexerResult::FILE_INDEXER_ENTRIES_LOADED`.
+ * In this case the blend file will not be opened and the FileIndexerEntry added to `entries`
+ * will be used as the content of the file.
+ *
+ * When the index isn't available or could not be used no entries must be added to the
+ * entries field, `r_read_entries_len` must be set to `0` and the function must return
+ * `eFileIndexerResult::FILE_INDEXER_NEEDS_UPDATE`. In this case the blend file will read from
+ * the blend file and the `update_index` function will be called.
+ */
+ FileIndexerReadIndexFunc read_index;
+
+ /**
+ * Update an index of a blend file.
+ *
+ * Is called after reading entries from the file when the result of `read_index` was
+ * `eFileIndexerResult::FILE_INDEXER_NEED_UPDATE`. The callback should update the index so the
+ * next time that read_index is called it will read the entries from the index.
+ */
+ FileIndexerUpdateIndexFunc update_index;
+} FileIndexerType;
+
+/* file_indexer.cc */
+
+/** Removes all entries inside the given `indexer_entries`. */
+void ED_file_indexer_entries_clear(FileIndexerEntries *indexer_entries);
+
+/**
+ * Adds all entries from the given `datablock_infos` to the `indexer_entries`.
+ * The datablock_infos must only contain data for a single IDType. The specific IDType must be
+ * passed in the `idcode` parameter.
+ */
+void ED_file_indexer_entries_extend_from_datablock_infos(
+ FileIndexerEntries *indexer_entries,
+ const LinkNode * /* BLODataBlockInfo */ datablock_infos,
+ int idcode);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 82057c726a5..0528057fb54 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -23,6 +23,8 @@
#pragma once
+#include "DNA_uuid_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -103,15 +105,29 @@ typedef struct FileSelection {
struct View2D;
struct rcti;
+/**
+ * If needed, create and return the file select parameters for the active browse mode.
+ */
struct FileSelectParams *ED_fileselect_ensure_active_params(struct SpaceFile *sfile);
+/**
+ * Get the file select parameters for the active browse mode.
+ */
struct FileSelectParams *ED_fileselect_get_active_params(const struct SpaceFile *sfile);
struct FileSelectParams *ED_fileselect_get_file_params(const struct SpaceFile *sfile);
struct FileAssetSelectParams *ED_fileselect_get_asset_params(const struct SpaceFile *sfile);
+bool ED_fileselect_is_local_asset_library(const struct SpaceFile *sfile);
void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile);
+/**
+ * Update the user-preference data for the file space. In fact, this also contains some
+ * non-FileSelectParams data, but we can safely ignore this.
+ *
+ * \param temp_win_size: If the browser was opened in a temporary window,
+ * pass its size here so we can store that in the preferences. Otherwise NULL.
+ */
void ED_fileselect_params_to_userdef(struct SpaceFile *sfile,
const int temp_win_size[2],
- const bool is_maximized);
+ bool is_maximized);
void ED_fileselect_init_layout(struct SpaceFile *sfile, struct ARegion *region);
@@ -121,6 +137,10 @@ int ED_fileselect_layout_numfiles(FileLayout *layout, struct ARegion *region);
int ED_fileselect_layout_offset(FileLayout *layout, int x, int y);
FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const struct rcti *rect);
+/**
+ * Get the currently visible bounds of the layout in screen space. Matches View2D.mask minus the
+ * top column-header row.
+ */
void ED_fileselect_layout_maskrect(const FileLayout *layout,
const struct View2D *v2d,
struct rcti *r_rect);
@@ -142,13 +162,19 @@ void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile);
bool ED_fileselect_is_file_browser(const struct SpaceFile *sfile);
bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile);
+struct AssetLibrary *ED_fileselect_active_asset_library_get(const struct SpaceFile *sfile);
struct ID *ED_fileselect_active_asset_get(const struct SpaceFile *sfile);
-/* Activate the file that corresponds to the given ID.
- * Pass deferred=true to wait for the next refresh before activating. */
-void ED_fileselect_activate_by_id(struct SpaceFile *sfile,
- struct ID *asset_id,
- const bool deferred);
+void ED_fileselect_activate_asset_catalog(const struct SpaceFile *sfile, bUUID catalog_id);
+
+/**
+ * Activate and select the file that corresponds to the given ID.
+ * Pass deferred=true to wait for the next refresh before activating.
+ */
+void ED_fileselect_activate_by_id(struct SpaceFile *sfile, struct ID *asset_id, bool deferred);
+
+void ED_fileselect_deselect_all(struct SpaceFile *sfile);
+void ED_fileselect_activate_by_relpath(struct SpaceFile *sfile, const char *relative_path);
void ED_fileselect_window_params_get(const struct wmWindow *win,
int win_size[2],
@@ -157,12 +183,18 @@ void ED_fileselect_window_params_get(const struct wmWindow *win,
struct ScrArea *ED_fileselect_handler_area_find(const struct wmWindow *win,
const struct wmOperator *file_operator);
+/* TODO: Maybe we should move this to BLI?
+ * On the other hand, it's using defines from space-file area, so not sure... */
int ED_path_extension_type(const char *path);
int ED_file_extension_icon(const char *path);
int ED_file_icon(const struct FileDirEntry *file);
void ED_file_read_bookmarks(void);
+/**
+ * Support updating the directory even when this isn't the active space
+ * needed so RNA properties update function isn't context sensitive, see T70255.
+ */
void ED_file_change_dir_ex(struct bContext *C, struct ScrArea *area);
void ED_file_change_dir(struct bContext *C);
@@ -222,7 +254,7 @@ char *ED_fsmenu_entry_get_name(struct FSMenuEntry *fsentry);
void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name);
int ED_fsmenu_entry_get_icon(struct FSMenuEntry *fsentry);
-void ED_fsmenu_entry_set_icon(struct FSMenuEntry *fsentry, const int icon);
+void ED_fsmenu_entry_set_icon(struct FSMenuEntry *fsentry, int icon);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 357d5e10fa7..8d4177faa0c 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -41,11 +41,7 @@ void ED_gizmotypes_primitive_3d(void);
void ED_gizmotypes_blank_3d(void);
void ED_gizmotypes_snap_3d(void);
-struct ARegion;
-struct Depsgraph;
struct Object;
-struct SnapObjectContext;
-struct View3D;
struct bContext;
struct wmGizmo;
struct wmWindowManager;
@@ -69,7 +65,7 @@ void ED_gizmo_draw_preset_circle(const struct wmGizmo *gz,
void ED_gizmo_draw_preset_facemap(const struct bContext *C,
const struct wmGizmo *gz,
struct Object *ob,
- const int facemap,
+ int facemap,
int select_id);
/* -------------------------------------------------------------------- */
@@ -96,8 +92,18 @@ enum {
ED_GIZMO_ARROW_DRAW_FLAG_STEM = (1 << 0),
};
-void ED_gizmo_arrow3d_set_ui_range(struct wmGizmo *gz, const float min, const float max);
-void ED_gizmo_arrow3d_set_range_fac(struct wmGizmo *gz, const float range_fac);
+/**
+ * Define a custom property UI range.
+ *
+ * \note Needs to be called before #WM_gizmo_target_property_def_rna!
+ */
+void ED_gizmo_arrow3d_set_ui_range(struct wmGizmo *gz, float min, float max);
+/**
+ * Define a custom factor for arrow min/max distance.
+ *
+ * \note Needs to be called before #WM_gizmo_target_property_def_rna!
+ */
+void ED_gizmo_arrow3d_set_range_fac(struct wmGizmo *gz, float range_fac);
/* -------------------------------------------------------------------- */
/* Cage Gizmo */
@@ -242,49 +248,28 @@ struct Dial3dParams {
};
void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4],
const float matrix_final[4][4],
- const float line_width,
+ float line_width,
const float color[4],
- const bool select,
+ bool select,
struct Dial3dParams *params);
/* snap3d_gizmo.c */
-#define USE_SNAP_DETECT_FROM_KEYMAP_HACK
-void ED_gizmotypes_snap_3d_draw_util(struct RegionView3D *rv3d,
- const float loc_prev[3],
- const float loc_curr[3],
- const float normal[3],
- const uchar color_line[4],
- const uchar color_point[4],
- const short snap_elem_type);
struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *scene,
- const struct ARegion *region,
- const struct View3D *v3d,
struct wmGizmo *gz);
-typedef enum {
- ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE = 1 << 0,
- ED_SNAPGIZMO_OCCLUSION_ALWAYS_TRUE = 1 << 1,
- ED_SNAPGIZMO_OCCLUSION_ALWAYS_FALSE = 1 << 2, /* TODO. */
- ED_SNAPGIZMO_SNAP_ONLY_ACTIVE = 1 << 3,
- ED_SNAPGIZMO_SNAP_EDIT_GEOM_FINAL = 1 << 4,
- ED_SNAPGIZMO_SNAP_EDIT_GEOM_CAGE = 1 << 5,
-} eSnapGizmo;
-
-void ED_gizmotypes_snap_3d_flag_set(struct wmGizmo *gz, eSnapGizmo flag);
-void ED_gizmotypes_snap_3d_flag_clear(struct wmGizmo *gz, eSnapGizmo flag);
-bool ED_gizmotypes_snap_3d_flag_test(struct wmGizmo *gz, eSnapGizmo flag);
+void ED_gizmotypes_snap_3d_flag_set(struct wmGizmo *gz, int flag);
+void ED_gizmotypes_snap_3d_flag_clear(struct wmGizmo *gz, int flag);
+bool ED_gizmotypes_snap_3d_flag_test(struct wmGizmo *gz, int flag);
bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz);
bool ED_gizmotypes_snap_3d_is_enabled(const struct wmGizmo *gz);
-short ED_gizmotypes_snap_3d_update(struct wmGizmo *gz,
- struct Depsgraph *depsgraph,
- const struct ARegion *region,
- const struct View3D *v3d,
- const struct wmWindowManager *wm,
- const float mval_fl[2]);
-void ED_gizmotypes_snap_3d_data_get(
- struct wmGizmo *gz, float r_loc[3], float r_nor[3], int r_elem_index[3], int *r_snap_elem);
+void ED_gizmotypes_snap_3d_data_get(const struct bContext *C,
+ struct wmGizmo *gz,
+ float r_loc[3],
+ float r_nor[3],
+ int r_elem_index[3],
+ int *r_snap_elem);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index c760b661373..919ea3e4a6b 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -94,7 +94,7 @@ typedef enum eGP_TargetObjectMode {
*/
typedef struct tGPspoint {
/** Coordinates x and y of cursor (in relative to area). */
- float x, y;
+ float m_xy[2];
/** Pressure of tablet at this point. */
float pressure;
/** Pressure of tablet at this point for alpha factor. */
@@ -116,42 +116,97 @@ typedef struct tGPspoint {
/* ----------- Grease Pencil Tools/Context ------------- */
/* Context-dependent */
+
+/**
+ * Get pointer to active Grease Pencil data-block,
+ * and an RNA-pointer to trace back to whatever owns it.
+ */
struct bGPdata **ED_gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *r_ptr);
+/**
+ * Get the active Grease Pencil data-block
+ */
struct bGPdata *ED_gpencil_data_get_active(const struct bContext *C);
+/**
+ * Get the evaluated copy of the active Grease Pencil data-block (where applicable)
+ * - For the 3D View (i.e. "GP Objects"), this gives the evaluated copy of the GP data-block
+ * (i.e. a copy of the active GP data-block for the active object, where modifiers have been
+ * applied). This is needed to correctly work with "Copy-on-Write".
+ * - For all other editors (i.e. "GP Annotations"), this just gives the active data-block
+ * like for #ED_gpencil_data_get_active()
+ */
struct bGPdata *ED_gpencil_data_get_active_evaluated(const struct bContext *C);
-/* Context independent (i.e. each required part is passed in instead) */
+/**
+ * Context independent (i.e. each required part is passed in instead).
+ *
+ * Get pointer to active Grease Pencil data-block,
+ * and an RNA-pointer to trace back to whatever owns it,
+ * when context info is not available.
+ */
struct bGPdata **ED_gpencil_data_get_pointers_direct(struct ScrArea *area,
struct Object *ob,
struct PointerRNA *r_ptr);
+/* Get the active Grease Pencil data-block, when context is not available */
struct bGPdata *ED_gpencil_data_get_active_direct(struct ScrArea *area, struct Object *ob);
+/**
+ * Get the active Grease Pencil data-block
+ * \note This is the original (#G.main) copy of the data-block, stored in files.
+ * Do not use for reading evaluated copies of GP Objects data.
+ */
struct bGPdata *ED_annotation_data_get_active(const struct bContext *C);
+/**
+ * Get pointer to active Grease Pencil data-block,
+ * and an RNA-pointer to trace back to whatever owns it.
+ */
struct bGPdata **ED_annotation_data_get_pointers(const struct bContext *C,
struct PointerRNA *r_ptr);
+/**
+ * Get pointer to active Grease Pencil data-block for annotations,
+ * and an RNA-pointer to trace back to whatever owns it,
+ * when context info is not available.
+ */
struct bGPdata **ED_annotation_data_get_pointers_direct(struct ID *screen_id,
struct ScrArea *area,
struct Scene *scene,
struct PointerRNA *r_ptr);
+/**
+ * Get the active Grease Pencil data-block, when context is not available.
+ */
struct bGPdata *ED_annotation_data_get_active_direct(struct ID *screen_id,
struct ScrArea *area,
struct Scene *scene);
+/**
+ * Utility to check whether the r_ptr output of ED_gpencil_data_get_pointers()
+ * is for annotation usage.
+ */
bool ED_gpencil_data_owner_is_annotation(struct PointerRNA *owner_ptr);
/* 3D View */
+
+/**
+ * Check whether there's an active GP keyframe on the current frame.
+ */
bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfra);
/* ----------- Stroke Editing Utilities ---------------- */
bool ED_gpencil_frame_has_selected_stroke(const struct bGPDframe *gpf);
-bool ED_gpencil_layer_has_selected_stroke(const struct bGPDlayer *gpl, const bool is_multiedit);
+bool ED_gpencil_layer_has_selected_stroke(const struct bGPDlayer *gpl, bool is_multiedit);
+/**
+ * Check whether given stroke can be edited given the supplied context.
+ * TODO: do we need additional flags for screen-space vs data-space?.
+ */
bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *area, const struct bGPDstroke *gps);
+/* Check whether given stroke can be edited in the current context */
bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps);
+/* Check whether given stroke can be edited for the current color */
bool ED_gpencil_stroke_material_editable(struct Object *ob,
const struct bGPDlayer *gpl,
const struct bGPDstroke *gps);
+/* Check whether given stroke is visible for the current material. */
bool ED_gpencil_stroke_material_visible(struct Object *ob, const struct bGPDstroke *gps);
/* ----------- Grease Pencil Operators ----------------- */
@@ -164,59 +219,139 @@ void ED_operatormacros_gpencil(void);
/* ------------- Copy-Paste Buffers -------------------- */
/* Strokes copybuf */
+
+/**
+ * Free copy/paste buffer data.
+ */
void ED_gpencil_strokes_copybuf_free(void);
/* ------------ Grease-Pencil Drawing API ------------------ */
/* drawgpencil.c */
+/**
+ * Draw grease-pencil sketches to specified 2d-view that uses ibuf corrections.
+ */
void ED_annotation_draw_2dimage(const struct bContext *C);
+/**
+ * Draw grease-pencil sketches to specified 2d-view
+ * assuming that matrices are already set correctly.
+ *
+ * \note This gets called twice - first time with onlyv2d=true to draw 'canvas' strokes,
+ * second time with onlyv2d=false for screen-aligned strokes.
+ */
void ED_annotation_draw_view2d(const struct bContext *C, bool onlyv2d);
+/**
+ * Draw annotations sketches to specified 3d-view assuming that matrices are already set correctly.
+ * NOTE: this gets called twice - first time with only3d=true to draw 3d-strokes,
+ * second time with only3d=false for screen-aligned strokes.
+ */
void ED_annotation_draw_view3d(struct Scene *scene,
struct Depsgraph *depsgraph,
struct View3D *v3d,
struct ARegion *region,
bool only3d);
-void ED_annotation_draw_ex(struct Scene *scene,
- struct bGPdata *gpd,
- int winx,
- int winy,
- const int cfra,
- const char spacetype);
+void ED_annotation_draw_ex(
+ struct Scene *scene, struct bGPdata *gpd, int winx, int winy, int cfra, char spacetype);
/* ----------- Grease-Pencil AnimEdit API ------------------ */
+/**
+ * Loops over the gp-frames for a gp-layer, and applies the given callback.
+ */
bool ED_gpencil_layer_frames_looper(struct bGPDlayer *gpl,
struct Scene *scene,
bool (*gpf_cb)(struct bGPDframe *, struct Scene *));
+/**
+ * Make a listing all the gp-frames in a layer as cfraelems.
+ */
void ED_gpencil_layer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool onlysel);
+/**
+ * Check if one of the frames in this layer is selected.
+ */
bool ED_gpencil_layer_frame_select_check(const struct bGPDlayer *gpl);
+/**
+ * Set all/none/invert select.
+ */
void ED_gpencil_layer_frame_select_set(struct bGPDlayer *gpl, short mode);
+/**
+ * Select the frames in this layer that occur within the bounds specified.
+ */
void ED_gpencil_layer_frames_select_box(struct bGPDlayer *gpl,
float min,
float max,
short select_mode);
+/**
+ * Select the frames in this layer that occur within the lasso/circle region specified.
+ */
void ED_gpencil_layer_frames_select_region(struct KeyframeEditData *ked,
struct bGPDlayer *gpl,
short tool,
short select_mode);
+/**
+ * Set all/none/invert select (like above, but with SELECT_* modes).
+ */
void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
+/**
+ * Select the frame in this layer that occurs on this frame (there should only be one at most).
+ */
void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode);
+/**
+ * Delete selected frames.
+ */
bool ED_gpencil_layer_frames_delete(struct bGPDlayer *gpl);
+/**
+ * Duplicate selected frames from given gp-layer.
+ */
void ED_gpencil_layer_frames_duplicate(struct bGPDlayer *gpl);
-void ED_gpencil_layer_frames_keytype_set(struct bGPDlayer *gpl, short type);
+/**
+ * Merge two layers.
+ */
+void ED_gpencil_layer_merge(struct bGPdata *gpd,
+ struct bGPDlayer *gpl_src,
+ struct bGPDlayer *gpl_dst,
+ bool reverse);
+/**
+ * Set keyframe type for selected frames from given gp-layer
+ *
+ * \param type: The type of keyframe (#eBezTriple_KeyframeType) to set selected frames to.
+ */
+void ED_gpencil_layer_frames_keytype_set(struct bGPDlayer *gpl, short type);
+/**
+ * Snap selected frames to ....
+ */
void ED_gpencil_layer_snap_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode);
+
+/**
+ * Mirror selected gp-frames on...
+ * TODO: mirror over a specific time.
+ */
void ED_gpencil_layer_mirror_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode);
+/**
+ * This function frees any MEM_calloc'ed copy/paste buffer data.
+ */
void ED_gpencil_anim_copybuf_free(void);
+/**
+ * This function adds data to the copy/paste buffer, freeing existing data first
+ * Only the selected GP-layers get their selected keyframes copied.
+ *
+ * Returns whether the copy operation was successful or not.
+ */
bool ED_gpencil_anim_copybuf_copy(struct bAnimContext *ac);
-bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, const short copy_mode);
+/**
+ * Pastes keyframes from buffer, and reports success.
+ */
+bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, short copy_mode);
/* ------------ Grease-Pencil Undo System ------------------ */
int ED_gpencil_session_active(void);
-int ED_undo_gpencil_step(struct bContext *C, const int step); /* eUndoStepDir. */
+/**
+ * \param step: eUndoStepDir.
+ */
+int ED_undo_gpencil_step(struct bContext *C, int step); /* eUndoStepDir. */
/* ------------ Grease-Pencil Armature ------------------ */
bool ED_gpencil_add_armature(const struct bContext *C,
@@ -229,7 +364,10 @@ bool ED_gpencil_add_armature_weights(const struct bContext *C,
struct Object *ob_arm,
int mode);
-/* Add Lattice modifier using Parent operator */
+/**
+ * Add Lattice modifier using Parent operator.
+ * Parent GPencil object to Lattice.
+ */
bool ED_gpencil_add_lattice_modifier(const struct bContext *C,
struct ReportList *reports,
struct Object *ob,
@@ -241,89 +379,164 @@ bool ED_gpencil_add_lattice_modifier(const struct bContext *C,
/* ------------ Transformation Utilities ------------ */
-/* reset parent matrix for all layers */
+/**
+ * Reset parent matrix for all layers.
+ */
void ED_gpencil_reset_layers_parent(struct Depsgraph *depsgraph,
struct Object *obact,
struct bGPdata *gpd);
-/* cursor utilities */
+/* Cursor utilities. */
+
+/**
+ * Draw eraser cursor.
+ */
void ED_gpencil_brush_draw_eraser(struct Brush *brush, int x, int y);
/* ----------- Add Primitive Utilities -------------- */
-/* Number of values defining each point in the built-in data buffers for primitives. */
+/** Number of values defining each point in the built-in data buffers for primitives. */
#define GP_PRIM_DATABUF_SIZE 5
+/**
+ * Populate stroke with point data from data buffers.
+ * \param gps: Grease pencil stroke
+ * \param array: Flat array of point data values. Each entry has #GP_PRIM_DATABUF_SIZE values.
+ * \param totpoints: Total of points
+ * \param mat: 4x4 transform matrix to transform points into the right coordinate space.
+ */
void ED_gpencil_stroke_init_data(struct bGPDstroke *gps,
const float *array,
- const int totpoints,
+ int totpoints,
const float mat[4][4]);
+/**
+ * Add a Simple empty object with one layer and one color.
+ */
void ED_gpencil_create_blank(struct bContext *C, struct Object *ob, float mat[4][4]);
+/**
+ * Add a 2D Suzanne (original model created by Matias Mendiola).
+ */
void ED_gpencil_create_monkey(struct bContext *C, struct Object *ob, float mat[4][4]);
+/**
+ * Add a Simple stroke with colors
+ * (original design created by Daniel M. Lara and Matias Mendiola).
+ */
void ED_gpencil_create_stroke(struct bContext *C, struct Object *ob, float mat[4][4]);
+/**
+ * Add a Simple LineArt setup.
+ */
void ED_gpencil_create_lineart(struct bContext *C, struct Object *ob);
/* ------------ Object Utilities ------------ */
+/**
+ * Helper function to create new #OB_GPENCIL Object.
+ */
struct Object *ED_gpencil_add_object(struct bContext *C,
const float loc[3],
unsigned short local_view_bits);
+/**
+ * Helper function to create default colors and drawing brushes.
+ */
void ED_gpencil_add_defaults(struct bContext *C, struct Object *ob);
-/* set object modes */
+/**
+ * Set object modes.
+ */
void ED_gpencil_setup_modes(struct bContext *C, struct bGPdata *gpd, int newmode);
bool ED_object_gpencil_exit(struct Main *bmain, struct Object *ob);
+/**
+ * Reproject all points of the stroke to a plane locked to axis to avoid stroke offset
+ */
void ED_gpencil_project_stroke_to_plane(const struct Scene *scene,
const struct Object *ob,
const struct RegionView3D *rv3d,
struct bGPDlayer *gpl,
struct bGPDstroke *gps,
const float origin[3],
- const int axis);
+ int axis);
+/**
+ * Reproject given point to a plane locked to axis to avoid stroke offset
+ * \param pt: Point to affect (used for input & output).
+ */
void ED_gpencil_project_point_to_plane(const struct Scene *scene,
const struct Object *ob,
struct bGPDlayer *gpl,
const struct RegionView3D *rv3d,
const float origin[3],
- const int axis,
+ int axis,
struct bGPDspoint *pt);
+/**
+ * Get drawing reference point for conversion or projection of the stroke
+ * \param r_vec: Reference point found
+ */
void ED_gpencil_drawing_reference_get(const struct Scene *scene,
const struct Object *ob,
char align_flag,
- float vec[3]);
+ float r_vec[3]);
void ED_gpencil_project_stroke_to_view(struct bContext *C,
struct bGPDlayer *gpl,
struct bGPDstroke *gps);
+/**
+ * Reproject selected strokes.
+ */
void ED_gpencil_stroke_reproject(struct Depsgraph *depsgraph,
const struct GP_SpaceConversion *gsc,
struct SnapObjectContext *sctx,
struct bGPDlayer *gpl,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
- const eGP_ReprojectModes mode,
- const bool keep_original);
+ eGP_ReprojectModes mode,
+ bool keep_original);
-/* set sculpt cursor */
+/**
+ * Turn brush cursor in on/off.
+ */
void ED_gpencil_toggle_brush_cursor(struct bContext *C, bool enable, void *customdata);
/* vertex groups */
+
+/**
+ * Assign points to vertex group.
+ */
void ED_gpencil_vgroup_assign(struct bContext *C, struct Object *ob, float weight);
+/**
+ * Remove points from vertex group.
+ */
void ED_gpencil_vgroup_remove(struct bContext *C, struct Object *ob);
+/**
+ * Select points of vertex group.
+ */
void ED_gpencil_vgroup_select(struct bContext *C, struct Object *ob);
+/**
+ * Un-select points of vertex group.
+ */
void ED_gpencil_vgroup_deselect(struct bContext *C, struct Object *ob);
/* join objects */
+
+/**
+ * Join objects called from OBJECT_OT_join.
+ */
int ED_gpencil_join_objects_exec(struct bContext *C, struct wmOperator *op);
/* texture coordinate utilities */
+
+/**
+ * Convert 2d #tGPspoint to 3d #bGPDspoint.
+ */
void ED_gpencil_tpoint_to_point(struct ARegion *region,
float origin[3],
const struct tGPspoint *tpt,
struct bGPDspoint *pt);
+/**
+ * Recalculate UV for any stroke using the material.
+ */
void ED_gpencil_update_color_uv(struct Main *bmain, struct Material *mat);
-/* extend selection to stroke intersections
- * returns:
+/**
+ * Extend selection to stroke intersections:
+ * \returns:
* 0 - No hit
* 1 - Hit in point A
* 2 - Hit in point B
@@ -335,24 +548,30 @@ int ED_gpencil_select_stroke_segment(struct bGPdata *gpd,
struct bGPDspoint *pt,
bool select,
bool insert,
- const float scale,
+ float scale,
float r_hita[3],
float r_hitb[3]);
void ED_gpencil_select_toggle_all(struct bContext *C, int action);
void ED_gpencil_select_curve_toggle_all(struct bContext *C, int action);
-/* Ensure stroke sbuffer size is enough */
+/**
+ * Ensure the #tGPspoint buffer (while drawing stroke)
+ * size is enough to save all points of the stroke.
+ */
struct tGPspoint *ED_gpencil_sbuffer_ensure(struct tGPspoint *buffer_array,
int *buffer_size,
int *buffer_used,
- const bool clear);
+ bool clear);
void ED_gpencil_sbuffer_update_eval(struct bGPdata *gpd, struct Object *ob_eval);
-/* Tag all scene grease pencil object to update. */
+/**
+ * Tag all scene grease pencil object to update.
+ */
void ED_gpencil_tag_scene_gpencil(struct Scene *scene);
/* Vertex color set. */
+
void ED_gpencil_fill_vertex_color_set(struct ToolSettings *ts,
struct Brush *brush,
struct bGPDstroke *gps);
@@ -371,15 +590,30 @@ void ED_gpencil_init_random_settings(struct Brush *brush,
const int mval[2],
struct GpRandomSettings *random_settings);
+/**
+ * Check if the stroke collides with brush.
+ */
bool ED_gpencil_stroke_check_collision(const struct GP_SpaceConversion *gsc,
struct bGPDstroke *gps,
const float mouse[2],
- const int radius,
+ int radius,
const float diff_mat[4][4]);
+/**
+ * Check if a point is inside of the stroke.
+ *
+ * \param gps: Stroke to check.
+ * \param gsc: Space conversion data.
+ * \param mouse: Mouse position.
+ * \param diff_mat: View matrix.
+ * \return True if the point is inside.
+ */
bool ED_gpencil_stroke_point_is_inside(const struct bGPDstroke *gps,
const struct GP_SpaceConversion *gsc,
const int mouse[2],
const float diff_mat[4][4]);
+/**
+ * Get the bigger 2D bound box points.
+ */
void ED_gpencil_projected_2d_bound_box(const struct GP_SpaceConversion *gsc,
const struct bGPDstroke *gps,
const float diff_mat[4][4],
@@ -393,21 +627,30 @@ struct bGPDstroke *ED_gpencil_stroke_nearest_to_ends(struct bContext *C,
struct bGPDstroke *gps,
const float ctrl1[2],
const float ctrl2[2],
- const float radius,
+ float radius,
int *r_index);
+/**
+ * Get extremes of stroke in 2D using current view.
+ */
void ED_gpencil_stroke_extremes_to2d(const struct GP_SpaceConversion *gsc,
const float diff_mat[4][4],
struct bGPDstroke *gps,
float r_ctrl1[2],
float r_ctrl2[2]);
+/**
+ * Join two stroke using a contact point index and trimming the rest.
+ */
struct bGPDstroke *ED_gpencil_stroke_join_and_trim(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
struct bGPDstroke *gps_dst,
- const int pt_index);
+ int pt_index);
-void ED_gpencil_stroke_close_by_distance(struct bGPDstroke *gps, const float threshold);
+/**
+ * Close if the distance between extremes is below threshold.
+ */
+void ED_gpencil_stroke_close_by_distance(struct bGPDstroke *gps, float threshold);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 9532035a1cd..3c1b8e4ecc1 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -38,37 +38,52 @@ struct Main;
struct ReportList;
struct Scene;
struct SpaceImage;
+struct View2D;
struct bContext;
struct wmOperator;
struct wmWindowManager;
-struct View2D;
/* image_draw.c */
-float ED_space_image_zoom_level(const struct View2D *v2d, const int grid_dimension);
+float ED_space_image_zoom_level(const struct View2D *v2d, int grid_dimension);
void ED_space_image_grid_steps(struct SpaceImage *sima,
float grid_steps[SI_GRID_STEPS_LEN],
- const int grid_dimension);
-float ED_space_image_increment_snap_value(const int grid_dimesnions,
+ int grid_dimension);
+/**
+ * Calculate the increment snapping value for UV/image editor based on the zoom factor
+ * The code in here (except the offset part) is used in `grid_frag.glsl` (see `grid_res`) for
+ * drawing the grid overlay for the UV/Image editor.
+ */
+float ED_space_image_increment_snap_value(int grid_dimesnions,
const float grid_steps[SI_GRID_STEPS_LEN],
- const float zoom_factor);
+ float zoom_factor);
+
+/* image_edit.c, exported for transform. */
-/* image_edit.c, exported for transform */
-struct Image *ED_space_image(struct SpaceImage *sima);
+struct Image *ED_space_image(const struct SpaceImage *sima);
void ED_space_image_set(struct Main *bmain,
struct SpaceImage *sima,
struct Image *ima,
bool automatic);
void ED_space_image_auto_set(const struct bContext *C, struct SpaceImage *sima);
-struct Mask *ED_space_image_get_mask(struct SpaceImage *sima);
+struct Mask *ED_space_image_get_mask(const struct SpaceImage *sima);
void ED_space_image_set_mask(struct bContext *C, struct SpaceImage *sima, struct Mask *mask);
+/**
+ * Returns mouse position in image space.
+ */
bool ED_space_image_get_position(struct SpaceImage *sima,
struct ARegion *region,
int mval[2],
float fpos[2]);
+/**
+ * Returns color in linear space, matching #ED_space_node_color_sample().
+ */
bool ED_space_image_color_sample(
struct SpaceImage *sima, struct ARegion *region, int mval[2], float r_col[3], bool *r_is_data);
struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock, int tile);
+/**
+ * Get the #SpaceImage flag that is valid for the given ibuf.
+ */
int ED_space_image_get_display_channel_mask(struct ImBuf *ibuf);
void ED_space_image_release_buffer(struct SpaceImage *sima, struct ImBuf *ibuf, void *lock);
bool ED_space_image_has_buffer(struct SpaceImage *sima);
@@ -87,6 +102,12 @@ void ED_space_image_scopes_update(const struct bContext *C,
struct ImBuf *ibuf,
bool use_view_settings);
+/**
+ * Enable the paint cursor if it isn't already.
+ *
+ * purpose is to make sure the paint cursor is shown if paint mode is enabled in the image editor.
+ * The paint poll will ensure that the cursor is hidden when not in paint mode.
+ */
void ED_space_image_paint_update(struct Main *bmain,
struct wmWindowManager *wm,
struct Scene *scene);
@@ -95,6 +116,7 @@ void ED_image_get_uv_aspect(struct Image *ima,
struct ImageUser *iuser,
float *r_aspx,
float *r_aspy);
+/** Takes `event->mval`. */
void ED_image_mouse_pos(struct SpaceImage *sima,
const struct ARegion *region,
const int mval[2],
@@ -110,19 +132,29 @@ void ED_image_point_pos__reverse(struct SpaceImage *sima,
const struct ARegion *region,
const float co[2],
float r_co[2]);
+/**
+ * This is more a user-level functionality, for going to `next/prev` used slot,
+ * Stepping onto the last unused slot too.
+ */
bool ED_image_slot_cycle(struct Image *image, int direction);
-bool ED_space_image_show_render(struct SpaceImage *sima);
-bool ED_space_image_show_paint(struct SpaceImage *sima);
-bool ED_space_image_show_uvedit(struct SpaceImage *sima, struct Object *obedit);
+bool ED_space_image_show_render(const struct SpaceImage *sima);
+bool ED_space_image_show_paint(const struct SpaceImage *sima);
+bool ED_space_image_show_uvedit(const struct SpaceImage *sima, struct Object *obedit);
bool ED_space_image_paint_curve(const struct bContext *C);
+/**
+ * Matches clip function.
+ */
bool ED_space_image_check_show_maskedit(struct SpaceImage *sima, struct Object *obedit);
bool ED_space_image_maskedit_poll(struct bContext *C);
bool ED_space_image_maskedit_mask_poll(struct bContext *C);
bool ED_space_image_cursor_poll(struct bContext *C);
+/**
+ * Used by node view too.
+ */
void ED_image_draw_info(struct Scene *scene,
struct ARegion *region,
bool color_manage,
@@ -136,7 +168,10 @@ void ED_image_draw_info(struct Scene *scene,
const int *zp,
const float *zpf);
-bool ED_space_image_show_cache(struct SpaceImage *sima);
+bool ED_space_image_show_cache(const struct SpaceImage *sima);
+bool ED_space_image_show_cache_and_mval_over(const struct SpaceImage *sima,
+ struct ARegion *region,
+ const int mval[2]);
bool ED_image_should_save_modified(const struct Main *bmain);
int ED_image_save_all_modified_info(const struct Main *bmain, struct ReportList *reports);
@@ -158,9 +193,12 @@ typedef struct ImageFrameRange {
ListBase frames;
} ImageFrameRange;
+/**
+ * Used for both images and volume file loading.
+ */
ListBase ED_image_filesel_detect_sequences(struct Main *bmain,
struct wmOperator *op,
- const bool detect_udim);
+ bool detect_udim);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_info.h b/source/blender/editors/include/ED_info.h
index dde26c072d0..caf76841bcd 100644
--- a/source/blender/editors/include/ED_info.h
+++ b/source/blender/editors/include/ED_info.h
@@ -39,6 +39,11 @@ const char *ED_info_statistics_string(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
+/**
+ * \param v3d_local: Pass this argument to calculate view-port local statistics.
+ * Note that this must only be used for local-view, otherwise report specific statistics
+ * will be written into the global scene statistics giving incorrect results.
+ */
void ED_info_draw_stats(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index e29ff3ed890..f006378658b 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -39,7 +39,9 @@ struct bDopeSheet;
/* ************************************************ */
/* Common Macros and Defines */
-/* --------- Tool Flags ------------ */
+/* -------------------------------------------------------------------- */
+/** \name Tool Flags
+ * \{ */
/* bezt validation */
typedef enum eEditKeyframes_Validate {
@@ -60,7 +62,7 @@ typedef enum eEditKeyframes_Validate {
BEZT_OK_CHANNEL_CIRCLE,
} eEditKeyframes_Validate;
-/* ------------ */
+/** \} */
/* select modes */
typedef enum eEditKeyframes_Select {
@@ -91,6 +93,13 @@ typedef enum eEditKeyframes_Snap {
SNAP_KEYS_TIME,
} eEditKeyframes_Snap;
+/* equalizing tools */
+typedef enum eEditKeyframes_Equalize {
+ EQUALIZE_HANDLES_LEFT = (1 << 0),
+ EQUALIZE_HANDLES_RIGHT = (1 << 1),
+ EQUALIZE_HANDLES_BOTH = (EQUALIZE_HANDLES_LEFT | EQUALIZE_HANDLES_RIGHT),
+} eEditKeyframes_Equalize;
+
/* mirroring tools */
typedef enum eEditKeyframes_Mirror {
MIRROR_KEYS_CURFRAME = 1,
@@ -120,7 +129,9 @@ typedef struct KeyframeEdit_CircleData {
/* ************************************************ */
/* Non-Destructive Editing API (keyframes_edit.c) */
-/* --- Defines for 'OK' polls + KeyframeEditData Flags --------- */
+/* -------------------------------------------------------------------- */
+/** \name Defines for 'OK' polls + KeyframeEditData Flags
+ * \{ */
/* which verts of a keyframe is active (after polling) */
typedef enum eKeyframeVertOk {
@@ -154,7 +165,11 @@ typedef enum eKeyframeIterFlags {
KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE = (1 << 3),
} eKeyframeIterFlags;
-/* --- Generic Properties for Keyframe Edit Tools ----- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generic Properties for Keyframe Edit Tools
+ * \{ */
typedef struct KeyframeEditData {
/* generic properties/data access */
@@ -184,14 +199,22 @@ typedef struct KeyframeEditData {
eKeyframeIterFlags iterflags;
} KeyframeEditData;
-/* ------- Function Pointer Typedefs ---------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Function Pointer Typedefs
+ * \{ */
/* callback function that refreshes the F-Curve after use */
typedef void (*FcuEditFunc)(struct FCurve *fcu);
/* callback function that operates on the given BezTriple */
typedef short (*KeyframeEditFunc)(KeyframeEditData *ked, struct BezTriple *bezt);
-/* ------- Custom Data Type Defines ------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom Data Type Defines
+ * \{ */
/* Custom data for remapping one range to another in a fixed way */
typedef struct KeyframeEditCD_Remap {
@@ -222,18 +245,40 @@ typedef enum eKeyMergeMode {
KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL,
} eKeyMergeMode;
-/* ---------------- Looping API --------------------- */
+/** \} */
-/* functions for looping over keyframes */
-/* function for working with F-Curve data only
- * (i.e. when filters have been chosen to explicitly use this) */
+/* -------------------------------------------------------------------- */
+/** \name Looping API
+ *
+ * Functions for looping over keyframes.
+ * \{ */
+
+/**
+ * This function is used to loop over BezTriples in the given F-Curve, applying a given
+ * operation on them, and optionally applies an F-Curve validation function afterwards.
+ *
+ * function for working with F-Curve data only
+ * (i.e. when filters have been chosen to explicitly use this).
+ */
short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked,
struct FCurve *fcu,
KeyframeEditFunc key_ok,
KeyframeEditFunc key_cb,
FcuEditFunc fcu_cb);
-/* function for working with any type (i.e. one of the known types) of animation channel
- * - filterflag is bDopeSheet->flag (DOPESHEET_FILTERFLAG)
+/**
+ * Sets selected keyframes' bezier handles to an equal length and optionally makes
+ * the keyframes' handles horizontal.
+ * \param handle_length: Desired handle length, must be positive.
+ * \param flatten: Makes the keyframes' handles the same value as the keyframe,
+ * flattening the curve at that point.
+ */
+void ANIM_fcurve_equalize_keyframes_loop(struct FCurve *fcu,
+ eEditKeyframes_Equalize mode,
+ float handle_length,
+ bool flatten);
+
+/**
+ * Function for working with any type (i.e. one of the known types) of animation channel.
*/
short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
struct bDopeSheet *ads,
@@ -241,8 +286,9 @@ short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
KeyframeEditFunc key_ok,
KeyframeEditFunc key_cb,
FcuEditFunc fcu_cb);
-/* same as above, except bAnimListElem wrapper is not needed...
- * - keytype is eAnim_KeyType
+/**
+ * Same as above, except bAnimListElem wrapper is not needed.
+ * \param keytype: is #eAnim_KeyType.
*/
short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked,
struct bDopeSheet *ads,
@@ -252,55 +298,92 @@ short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked,
KeyframeEditFunc key_cb,
FcuEditFunc fcu_cb);
-/* Calls callback_fn() for each keyframe in each fcurve in the filtered animation context.
- * Assumes the callback updates keys. */
+/**
+ * Calls callback_fn() for each keyframe in each fcurve in the filtered animation context.
+ * Assumes the callback updates keys.
+ */
void ANIM_animdata_keyframe_callback(struct bAnimContext *ac,
eAnimFilter_Flags filter,
KeyframeEditFunc callback_fn);
-/* functions for making sure all keyframes are in good order */
+/**
+ * Functions for making sure all keyframes are in good order.
+ */
void ANIM_editkeyframes_refresh(struct bAnimContext *ac);
-/* ----------- BezTriple Callback Getters ---------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BezTriple Callback Getters
+ * \{ */
/* accessories */
KeyframeEditFunc ANIM_editkeyframes_ok(short mode);
/* edit */
KeyframeEditFunc ANIM_editkeyframes_snap(short mode);
+/**
+ * \note for markers and 'value', the values to use must be supplied as the first float value.
+ */
KeyframeEditFunc ANIM_editkeyframes_mirror(short mode);
KeyframeEditFunc ANIM_editkeyframes_select(short mode);
+/**
+ * Set all selected Bezier Handles to a single type.
+ */
KeyframeEditFunc ANIM_editkeyframes_handles(short mode);
+/**
+ * Set the interpolation type of the selected BezTriples in each F-Curve to the specified one.
+ */
KeyframeEditFunc ANIM_editkeyframes_ipo(short mode);
KeyframeEditFunc ANIM_editkeyframes_keytype(short mode);
KeyframeEditFunc ANIM_editkeyframes_easing(short mode);
-/* -------- BezTriple Callbacks (Selection Map) ---------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BezTriple Callbacks (Selection Map)
+ * \{ */
-/* Get a callback to populate the selection settings map
- * requires: ked->custom = char[] of length fcurve->totvert
+/**
+ * Get a callback to populate the selection settings map
+ * requires: `ked->custom = char[]` of length `fcurve->totvert`.
*/
KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode);
-/* Change the selection status of the keyframe based on the map entry for this vert
- * requires: ked->custom = char[] of length fcurve->totvert
+/**
+ * Change the selection status of the keyframe based on the map entry for this vert
+ * requires: `ked->custom = char[]` of length `fcurve->totvert`.
*/
short bezt_selmap_flush(KeyframeEditData *ked, struct BezTriple *bezt);
-/* ----------- BezTriple Callback (Assorted Utilities) ---------- */
+/** \} */
-/* used to calculate the average location of all relevant BezTriples by summing their locations */
+/* -------------------------------------------------------------------- */
+/** \name BezTriple Callback (Assorted Utilities)
+ * \{ */
+
+/**
+ * Used to calculate the average location of all relevant BezTriples by summing their locations.
+ */
short bezt_calc_average(KeyframeEditData *ked, struct BezTriple *bezt);
-/* used to extract a set of cfra-elems from the keyframes */
+/**
+ * Used to extract a set of cfra-elems from the keyframes.
+ */
short bezt_to_cfraelem(KeyframeEditData *ked, struct BezTriple *bezt);
-/* used to remap times from one range to another
- * requires: ked->custom = KeyframeEditCD_Remap
+/**
+ * Used to remap times from one range to another.
+ * requires: `ked->custom = KeyframeEditCD_Remap`.
*/
void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt);
-/* ------ 1.5-D Region Testing Utilities (Lasso/Circle Select) ------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name 1.5-D Region Testing Utilities (Lasso/Circle Select)
+ * \{ */
+
/* XXX: These are temporary,
* until we can unify GP/Mask Keyframe handling and standard FCurve Keyframe handling */
@@ -316,11 +399,30 @@ bool delete_fcurve_keys(struct FCurve *fcu);
void clear_fcurve_keys(struct FCurve *fcu);
void duplicate_fcurve_keys(struct FCurve *fcu);
+typedef struct FCurveSegment {
+ struct FCurveSegment *next, *prev;
+ int start_index, length;
+} FCurveSegment;
+
+/**
+ * Return a list of #FCurveSegment with a start index and a length.
+ * A segment is a continuous selection of keyframes.
+ * Keys that have BEZT_FLAG_IGNORE_TAG set are treated as unselected.
+ * The caller is responsible for freeing the memory.
+ */
+ListBase find_fcurve_segments(struct FCurve *fcu);
void clean_fcurve(struct bAnimContext *ac,
struct bAnimListElem *ale,
float thresh,
bool cleardefault);
+void blend_to_neighbor_fcurve_segment(struct FCurve *fcu,
+ struct FCurveSegment *segment,
+ float factor);
+void breakdown_fcurve_segment(struct FCurve *fcu, struct FCurveSegment *segment, float factor);
bool decimate_fcurve(struct bAnimListElem *ale, float remove_ratio, float error_sq_max);
+/**
+ * Use a weighted moving-means method to reduce intensity of fluctuations.
+ */
void smooth_fcurve(struct FCurve *fcu);
void sample_fcurve(struct FCurve *fcu);
@@ -330,12 +432,14 @@ void ANIM_fcurves_copybuf_free(void);
short copy_animedit_keys(struct bAnimContext *ac, ListBase *anim_data);
short paste_animedit_keys(struct bAnimContext *ac,
ListBase *anim_data,
- const eKeyPasteOffset offset_mode,
- const eKeyMergeMode merge_mode,
+ eKeyPasteOffset offset_mode,
+ eKeyMergeMode merge_mode,
bool flip);
/* ************************************************ */
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_keyframes_keylist.h b/source/blender/editors/include/ED_keyframes_keylist.h
index 4194444ca0f..36a30bd5ee6 100644
--- a/source/blender/editors/include/ED_keyframes_keylist.h
+++ b/source/blender/editors/include/ED_keyframes_keylist.h
@@ -140,12 +140,9 @@ typedef enum eKeyframeExtremeDrawOpts {
struct AnimKeylist *ED_keylist_create(void);
void ED_keylist_free(struct AnimKeylist *keylist);
void ED_keylist_prepare_for_direct_access(struct AnimKeylist *keylist);
-const struct ActKeyColumn *ED_keylist_find_exact(const struct AnimKeylist *keylist,
- const float cfra);
-const struct ActKeyColumn *ED_keylist_find_next(const struct AnimKeylist *keylist,
- const float cfra);
-const struct ActKeyColumn *ED_keylist_find_prev(const struct AnimKeylist *keylist,
- const float cfra);
+const struct ActKeyColumn *ED_keylist_find_exact(const struct AnimKeylist *keylist, float cfra);
+const struct ActKeyColumn *ED_keylist_find_next(const struct AnimKeylist *keylist, float cfra);
+const struct ActKeyColumn *ED_keylist_find_prev(const struct AnimKeylist *keylist, float cfra);
const struct ActKeyColumn *ED_keylist_find_any_between(const struct AnimKeylist *keylist,
const Range2f frame_range);
bool ED_keylist_is_empty(const struct AnimKeylist *keylist);
@@ -160,41 +157,39 @@ int64_t ED_keylist_array_len(const struct AnimKeylist *keylist);
void fcurve_to_keylist(struct AnimData *adt,
struct FCurve *fcu,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Action Group */
void agroup_to_keylist(struct AnimData *adt,
struct bActionGroup *agrp,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Action */
void action_to_keylist(struct AnimData *adt,
struct bAction *act,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Object */
void ob_to_keylist(struct bDopeSheet *ads,
struct Object *ob,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Cache File */
void cachefile_to_keylist(struct bDopeSheet *ads,
struct CacheFile *cache_file,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Scene */
void scene_to_keylist(struct bDopeSheet *ads,
struct Scene *sce,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* DopeSheet Summary */
-void summary_to_keylist(struct bAnimContext *ac,
- struct AnimKeylist *keylist,
- const int saction_flag);
+void summary_to_keylist(struct bAnimContext *ac, struct AnimKeylist *keylist, int saction_flag);
/* Grease Pencil datablock summary */
void gpencil_to_keylist(struct bDopeSheet *ads,
struct bGPdata *gpd,
struct AnimKeylist *keylist,
- const bool active);
+ bool active);
/* Grease Pencil Layer */
void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct AnimKeylist *keylist);
/* Mask */
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 673f629d6ef..8d89555c732 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -53,39 +53,49 @@ struct PropertyRNA;
struct NlaKeyframingContext;
-/* ************ Keyframing Management **************** */
+/* -------------------------------------------------------------------- */
+/** \name Key-Framing Management
+ * \{ */
-/* Get the active settings for keyframing settings from context (specifically the given scene)
- * - use_autokey_mode: include settings from keyframing mode in the result (i.e. replace only).
+/**
+ * Get the active settings for key-framing settings from context (specifically the given scene)
+ * \param use_autokey_mode: include settings from key-framing mode in the result
+ * (i.e. replace only).
*/
-eInsertKeyFlags ANIM_get_keyframing_flags(struct Scene *scene, const bool use_autokey_mode);
+eInsertKeyFlags ANIM_get_keyframing_flags(struct Scene *scene, bool use_autokey_mode);
/* -------- */
-/* Get (or add relevant data to be able to do so) the Active Action for the given
+/**
+ * Get (or add relevant data to be able to do so) the Active Action for the given
* Animation Data block, given an ID block where the Animation Data should reside.
*/
struct bAction *ED_id_action_ensure(struct Main *bmain, struct ID *id);
-/* Get (or add relevant data to be able to do so) F-Curve from the given Action.
- * This assumes that all the destinations are valid.
+/**
+ * Get (or add relevant data to be able to do so) F-Curve from the Active Action,
+ * for the given Animation Data block. This assumes that all the destinations are valid.
*/
struct FCurve *ED_action_fcurve_ensure(struct Main *bmain,
struct bAction *act,
const char group[],
struct PointerRNA *ptr,
const char rna_path[],
- const int array_index);
+ int array_index);
-struct FCurve *ED_action_fcurve_find(struct bAction *act,
- const char rna_path[],
- const int array_index);
+/**
+ * Find the F-Curve from the Active Action,
+ * for the given Animation Data block. This assumes that all the destinations are valid.
+ */
+struct FCurve *ED_action_fcurve_find(struct bAction *act, const char rna_path[], int array_index);
/* -------- */
-/* Lesser Keyframing API call:
- * Update integer/discrete flags of the FCurve (used when creating/inserting keyframes,
- * but also through RNA when editing an ID prop, see T37103).
+/**
+ * \brief Lesser Key-framing API call.
+ *
+ * Update integer/discrete flags of the FCurve (used when creating/inserting keyframes,
+ * but also through RNA when editing an ID prop, see T37103).
*/
void update_autoflags_fcurve(struct FCurve *fcu,
struct bContext *C,
@@ -94,16 +104,34 @@ void update_autoflags_fcurve(struct FCurve *fcu,
/* -------- */
-/* Lesser Keyframing API call:
- * Use this when validation of necessary animation data isn't necessary as it already
- * exists, and there is a beztriple that can be directly copied into the array.
+/**
+ * \brief Lesser Key-framing API call.
+ *
+ * Use this when validation of necessary animation data isn't necessary as it already
+ * exists, and there is a #BezTriple that can be directly copied into the array.
+ *
+ * This function adds a given #BezTriple to an F-Curve. It will allocate
+ * memory for the array if needed, and will insert the #BezTriple into a
+ * suitable place in chronological order.
+ *
+ * \note any recalculate of the F-Curve that needs to be done will need to be done by the caller.
*/
int insert_bezt_fcurve(struct FCurve *fcu, const struct BezTriple *bezt, eInsertKeyFlags flag);
-/* Main Keyframing API call:
- * Use this when validation of necessary animation data isn't necessary as it
- * already exists. It will insert a keyframe using the current value being keyframed.
- * Returns the index at which a keyframe was added (or -1 if failed)
+/**
+ * \brief Main Key-framing API call.
+ *
+ * Use this when validation of necessary animation data isn't necessary as it
+ * already exists. It will insert a keyframe using the current value being keyframed.
+ * Returns the index at which a keyframe was added (or -1 if failed).
+ *
+ * This function is a wrapper for #insert_bezt_fcurve(), and should be used when
+ * adding a new keyframe to a curve, when the keyframe doesn't exist anywhere else yet.
+ * It returns the index at which the keyframe was added.
+ *
+ * \param keyframe_type: The type of keyframe (#eBezTriple_KeyframeType).
+ * \param flag: Optional flags (#eInsertKeyFlags) for controlling how keys get added
+ * and/or whether updates get done.
*/
int insert_vert_fcurve(struct FCurve *fcu,
float x,
@@ -113,9 +141,21 @@ int insert_vert_fcurve(struct FCurve *fcu,
/* -------- */
-/* Secondary Keyframing API calls:
- * Use this to insert a keyframe using the current value being keyframed, in the
- * nominated F-Curve (no creation of animation data performed). Returns success.
+/**
+ * \brief Secondary Insert Key-framing API call.
+ *
+ * Use this when validation of necessary animation data is not necessary,
+ * since an RNA-pointer to the necessary data being keyframed,
+ * and a pointer to the F-Curve to use have both been provided.
+ *
+ * This function can't keyframe quaternion channels on some NLA strip types.
+ *
+ * \param keytype: The "keyframe type" (eBezTriple_KeyframeType), as shown in the Dope Sheet.
+ *
+ * \param flag: Used for special settings that alter the behavior of the keyframe insertion.
+ * These include the 'visual' key-framing modes, quick refresh,
+ * and extra keyframe filtering.
+ * \return Success.
*/
bool insert_keyframe_direct(struct ReportList *reports,
struct PointerRNA ptr,
@@ -128,9 +168,17 @@ bool insert_keyframe_direct(struct ReportList *reports,
/* -------- */
-/* Main Keyframing API calls:
+/**
+ * \brief Main Insert Key-framing API call.
+ *
* Use this to create any necessary animation data, and then insert a keyframe
- * using the current value being keyframed, in the relevant place. Returns success.
+ * using the current value being keyframed, in the relevant place.
+ *
+ * \param flag: Used for special settings that alter the behavior of the keyframe insertion.
+ * These include the 'visual' key-framing modes, quick refresh, and extra keyframe filtering.
+ *
+ * \param array_index: The index to key or -1 keys all array indices.
+ * \return The number of key-frames inserted.
*/
int insert_keyframe(struct Main *bmain,
struct ReportList *reports,
@@ -144,9 +192,13 @@ int insert_keyframe(struct Main *bmain,
struct ListBase *nla_cache,
eInsertKeyFlags flag);
-/* Main Keyframing API call:
+/**
+ * \brief Main Delete Key-Framing API call.
+ *
* Use this to delete keyframe on current frame for relevant channel.
- * Will perform checks just in case. */
+ * Will perform checks just in case.
+ * \return The number of key-frames deleted.
+ */
int delete_keyframe(struct Main *bmain,
struct ReportList *reports,
struct ID *id,
@@ -155,7 +207,11 @@ int delete_keyframe(struct Main *bmain,
int array_index,
float cfra);
-/* ************ Keying Sets ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Keying Sets
+ * \{ */
/* forward decl. for this struct which is declared a bit later... */
struct ExtensionRNA;
@@ -206,7 +262,9 @@ typedef struct KeyingSetInfo {
/* -------- */
-/* Add another data source for Relative Keying Sets to be evaluated with */
+/**
+ * Add another data source for Relative Keying Sets to be evaluated with.
+ */
void ANIM_relative_keyingset_add_source(ListBase *dsources,
struct ID *id,
struct StructRNA *srna,
@@ -226,13 +284,28 @@ typedef enum eModifyKey_Returns {
MODIFYKEY_MISSING_TYPEINFO = -2,
} eModifyKey_Returns;
-/* poll the current KeyingSet, updating its set of paths
- * (if "builtin"/"relative") for context changes */
+/**
+ * Given a #KeyingSet and context info, validate Keying Set's paths.
+ * This is only really necessary with relative/built-in KeyingSets
+ * where their list of paths is dynamically generated based on the
+ * current context info.
+ *
+ * \return 0 if succeeded, otherwise an error code: #eModifyKey_Returns.
+ */
eModifyKey_Returns ANIM_validate_keyingset(struct bContext *C,
ListBase *dsources,
struct KeyingSet *ks);
-/* use the specified KeyingSet to add/remove various Keyframes on the specified frame */
+/**
+ * Use the specified #KeyingSet and context info (if required)
+ * to add/remove various Keyframes on the specified frame.
+ *
+ * Modify keyframes for the channels specified by the KeyingSet.
+ * This takes into account many of the different combinations of using KeyingSets.
+ *
+ * \returns the number of channels that key-frames were added or
+ * an #eModifyKey_Returns value (always a negative number).
+ */
int ANIM_apply_keyingset(struct bContext *C,
ListBase *dsources,
struct bAction *act,
@@ -242,49 +315,88 @@ int ANIM_apply_keyingset(struct bContext *C,
/* -------- */
-/* Get the first builtin KeyingSet with the given name, which occurs after the given one
- * (or start of list if none given) */
+/**
+ * Find builtin #KeyingSet by name.
+ *
+ * \return The first builtin #KeyingSet with the given name, which occurs after the given one
+ * (or start of list if none given).
+ */
struct KeyingSet *ANIM_builtin_keyingset_get_named(struct KeyingSet *prevKS, const char name[]);
-/* Find KeyingSet type info given a name */
+/**
+ * Find KeyingSet type info given a name.
+ */
KeyingSetInfo *ANIM_keyingset_info_find_name(const char name[]);
-/* Find a given ID in the KeyingSet */
+/**
+ * Check if the ID appears in the paths specified by the #KeyingSet.
+ */
bool ANIM_keyingset_find_id(struct KeyingSet *ks, ID *id);
-/* for RNA type registrations... */
+/**
+ * Add the given KeyingSetInfo to the list of type infos,
+ * and create an appropriate builtin set too.
+ */
void ANIM_keyingset_info_register(KeyingSetInfo *ksi);
+/**
+ * Remove the given #KeyingSetInfo from the list of type infos,
+ * and also remove the builtin set if appropriate.
+ */
void ANIM_keyingset_info_unregister(struct Main *bmain, KeyingSetInfo *ksi);
/* cleanup on exit */
+/* --------------- */
+
void ANIM_keyingset_infos_exit(void);
/* -------- */
-/* Get the active KeyingSet for the given scene */
+/**
+ * Get the active Keying Set for the given scene.
+ */
struct KeyingSet *ANIM_scene_get_active_keyingset(const struct Scene *scene);
-/* Get the index of the Keying Set provided, for the given Scene */
+/**
+ * Get the index of the Keying Set provided, for the given Scene.
+ */
int ANIM_scene_get_keyingset_index(struct Scene *scene, struct KeyingSet *ks);
-/* Get Keying Set to use for Auto-Keyframing some transforms */
+/**
+ * Get Keying Set to use for Auto-Key-Framing some transforms.
+ */
struct KeyingSet *ANIM_get_keyingset_for_autokeying(const struct Scene *scene,
const char *transformKSName);
-/* Dynamically populate an enum of Keying Sets */
+/**
+ * Dynamically populate an enum of Keying Sets.
+ */
const struct EnumPropertyItem *ANIM_keying_sets_enum_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free);
-/* Use to get the keying set from the int value used by enums. */
+/**
+ * Get the keying set from enum values generated in #ANIM_keying_sets_enum_itemf.
+ *
+ * Type is the Keying Set the user specified to use when calling the operator:
+ * \param type:
+ * - == 0: use scene's active Keying Set.
+ * - > 0: use a user-defined Keying Set from the active scene.
+ * - < 0: use a builtin Keying Set.
+ */
KeyingSet *ANIM_keyingset_get_from_enum_type(struct Scene *scene, int type);
KeyingSet *ANIM_keyingset_get_from_idname(struct Scene *scene, const char *idname);
-/* Check if KeyingSet can be used in the current context */
+/**
+ * Check if #KeyingSet can be used in the current context.
+ */
bool ANIM_keyingset_context_ok_poll(struct bContext *C, struct KeyingSet *ks);
-/* ************ Drivers ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drivers
+ * \{ */
/* Flags for use by driver creation calls */
typedef enum eCreateDriverFlags {
@@ -311,7 +423,10 @@ typedef enum eCreateDriver_MappingTypes {
CREATEDRIVER_MAPPING_NONE_ALL = 4,
} eCreateDriver_MappingTypes;
-/* RNA Enum of eCreateDriver_MappingTypes, for use by the appropriate operators */
+/**
+ * Mapping Types enum for operators.
+ * \note Used by #ANIM_OT_driver_button_add and #UI_OT_eyedropper_driver.
+ */
extern EnumPropertyItem prop_driver_create_mapping_types[];
/* -------- */
@@ -323,30 +438,36 @@ typedef enum eDriverFCurveCreationMode {
DRIVER_FCURVE_EMPTY = 3 /* Add without data, for pasting. */
} eDriverFCurveCreationMode;
-/* Low-level call to add a new driver F-Curve. This shouldn't be used directly for most tools,
+/**
+ * Get (or add relevant data to be able to do so) F-Curve from the driver stack,
+ * for the given Animation Data block. This assumes that all the destinations are valid.
+ *
+ * \note This low-level function shouldn't be used directly for most tools,
* although there are special cases where this approach is preferable.
*/
struct FCurve *verify_driver_fcurve(struct ID *id,
const char rna_path[],
- const int array_index,
+ int array_index,
eDriverFCurveCreationMode creation_mode);
struct FCurve *alloc_driver_fcurve(const char rna_path[],
- const int array_index,
+ int array_index,
eDriverFCurveCreationMode creation_mode);
/* -------- */
-/* Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block,
- * and make it be driven by the specified target.
+/**
+ * \brief Main Driver Management API calls
+ *
+ * Add a new driver for the specified property on the given ID block,
+ * and make it be driven by the specified target.
*
* This is intended to be used in conjunction with a modal "eyedropper"
* for picking the variable that is going to be used to drive this one.
*
- * - flag: eCreateDriverFlags
- * - driver_type: eDriver_Types
- * - mapping_type: eCreateDriver_MappingTypes
+ * \param flag: eCreateDriverFlags
+ * \param driver_type: eDriver_Types
+ * \param mapping_type: eCreateDriver_MappingTypes
*/
int ANIM_add_driver_with_target(struct ReportList *reports,
struct ID *dst_id,
@@ -361,8 +482,10 @@ int ANIM_add_driver_with_target(struct ReportList *reports,
/* -------- */
-/* Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block
+/**
+ * \brief Main Driver Management API calls.
+ *
+ * Add a new driver for the specified property on the given ID block
*/
int ANIM_add_driver(struct ReportList *reports,
struct ID *id,
@@ -371,90 +494,128 @@ int ANIM_add_driver(struct ReportList *reports,
short flag,
int type);
-/* Main Driver Management API calls:
- * Remove the driver for the specified property on the given ID block (if available)
+/**
+ * \brief Main Driver Management API calls.
+ *
+ * Remove the driver for the specified property on the given ID block (if available).
*/
bool ANIM_remove_driver(
struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag);
/* -------- */
-/* Clear copy-paste buffer for drivers */
+/**
+ * Clear copy-paste buffer for drivers.
+ * \note This function frees any MEM_calloc'ed copy/paste buffer data.
+ */
void ANIM_drivers_copybuf_free(void);
-/* Clear copy-paste buffer for driver variable sets */
+/**
+ * Clear copy-paste buffer for driver variable sets.
+ * \note This function frees any MEM_calloc'ed copy/paste buffer data.
+ */
void ANIM_driver_vars_copybuf_free(void);
/* -------- */
-/* Returns whether there is a driver in the copy/paste buffer to paste */
+/**
+ * Returns whether there is a driver in the copy/paste buffer to paste.
+ */
bool ANIM_driver_can_paste(void);
-/* Main Driver Management API calls:
- * Make a copy of the driver for the specified property on the given ID block
+/**
+ * \brief Main Driver Management API calls.
+ *
+ * Make a copy of the driver for the specified property on the given ID block.
*/
bool ANIM_copy_driver(
struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag);
-/* Main Driver Management API calls:
+/**
+ * \brief Main Driver Management API calls.
+ *
* Add a new driver for the specified property on the given ID block or replace an existing one
- * with the driver + driver-curve data from the buffer
+ * with the driver + driver-curve data from the buffer.
*/
bool ANIM_paste_driver(
struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag);
/* -------- */
-/* Checks if there are driver variables in the copy/paste buffer */
+/**
+ * Checks if there are driver variables in the copy/paste buffer.
+ */
bool ANIM_driver_vars_can_paste(void);
-/* Copy the given driver's variables to the buffer */
+/**
+ * Copy the given driver's variables to the buffer.
+ */
bool ANIM_driver_vars_copy(struct ReportList *reports, struct FCurve *fcu);
-/* Paste the variables in the buffer to the given FCurve */
+/**
+ * Paste the variables in the buffer to the given FCurve.
+ */
bool ANIM_driver_vars_paste(struct ReportList *reports, struct FCurve *fcu, bool replace);
/* -------- */
-/* Create a driver & variable that reads the specified property,
- * and store it in the buffers for Paste Driver and Paste Variables. */
+/**
+ * Create a driver & variable that reads the specified property,
+ * and store it in the buffers for Paste Driver and Paste Variables.
+ */
void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const char *var_name);
-/* ************ Auto-Keyframing ********************** */
-/* Notes:
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-Key-Framing
+ *
+ * Notes:
* - All the defines for this (User-Pref settings and Per-Scene settings)
* are defined in DNA_userdef_types.h
- * - Scene settings take precedence over those for userprefs, with old files
- * inheriting userpref settings for the scene settings
- * - "On/Off + Mode" are stored per Scene, but "settings" are currently stored
- * as userprefs
- */
+ * - Scene settings take precedence over those for user-preferences, with old files
+ * inheriting user-preferences settings for the scene settings
+ * - "On/Off + Mode" are stored per Scene, but "settings" are currently stored as user-preferences.
+ * \{ */
-/* Auto-Keying macros for use by various tools */
-/* check if auto-keyframing is enabled (per scene takes precedence) */
+/* Auto-Keying macros for use by various tools. */
+
+/** Check if auto-key-framing is enabled (per scene takes precedence).
+ */
#define IS_AUTOKEY_ON(scene) \
((scene) ? ((scene)->toolsettings->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON))
-/* Check the mode for auto-keyframing (per scene takes precedence). */
+/** Check the mode for auto-keyframing (per scene takes precedence). */
#define IS_AUTOKEY_MODE(scene, mode) \
((scene) ? ((scene)->toolsettings->autokey_mode == AUTOKEY_MODE_##mode) : \
(U.autokey_mode == AUTOKEY_MODE_##mode))
-/* check if a flag is set for auto-keyframing (per scene takes precedence) */
+/** Check if a flag is set for auto-key-framing (per scene takes precedence). */
#define IS_AUTOKEY_FLAG(scene, flag) \
((scene) ? (((scene)->toolsettings->autokey_flag & AUTOKEY_FLAG_##flag) || \
(U.autokey_flag & AUTOKEY_FLAG_##flag)) : \
(U.autokey_flag & AUTOKEY_FLAG_##flag))
-/* auto-keyframing feature - checks for whether anything should be done for the current frame */
+/**
+ * Auto-keyframing feature - checks for whether anything should be done for the current frame.
+ */
bool autokeyframe_cfra_can_key(const struct Scene *scene, struct ID *id);
-/* ************ Keyframe Checking ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Keyframe Checking
+ * \{ */
-/* Lesser Keyframe Checking API call:
- * - Used for the buttons to check for keyframes...
+/**
+ * \brief Lesser Keyframe Checking API call.
+ *
+ * Checks if some F-Curve has a keyframe for a given frame.
+ * \note Used for the buttons to check for keyframes.
*/
bool fcurve_frame_has_keyframe(const struct FCurve *fcu, float frame, short filter);
-/* Lesser Keyframe Checking API call:
+/**
+ * \brief Lesser Keyframe Checking API call.
+ *
* - Returns whether the current value of a given property differs from the interpolated value.
* - Used for button drawing.
*/
@@ -464,18 +625,19 @@ bool fcurve_is_changed(struct PointerRNA ptr,
const struct AnimationEvalContext *anim_eval_context);
/**
- * Main Keyframe Checking API call:
+ * \brief Main Keyframe Checking API call.
+ *
* Checks whether a keyframe exists for the given ID-block one the given frame.
- * - It is recommended to call this method over the other keyframe-checkers directly,
- * in case some detail of the implementation changes...
- * - frame: the value of this is quite often result of #BKE_scene_ctime_get()
+ * It is recommended to call this method over the other keyframe-checkers directly,
+ * in case some detail of the implementation changes...
+ * \param frame: The value of this is quite often result of #BKE_scene_ctime_get()
*/
bool id_frame_has_keyframe(struct ID *id, float frame, short filter);
-/* filter flags for id_cfra_has_keyframe
+/**
+ * Filter flags for #id_frame_has_keyframe.
*
- * WARNING: do not alter order of these, as also stored in files
- * (for v3d->keyflags)
+ * \warning do not alter order of these, as also stored in files (for `v3d->keyflags`).
*/
typedef enum eAnimFilterFlags {
/* general */
@@ -488,7 +650,8 @@ typedef enum eAnimFilterFlags {
ANIMFILTER_KEYS_NOSKEY = (1 << 10), /* don't include shape keys (for geometry) */
} eAnimFilterFlags;
-/* utility funcs for auto keyframe */
+/* Utility functions for auto key-frame. */
+
bool ED_autokeyframe_object(struct bContext *C,
struct Scene *scene,
struct Object *ob,
@@ -498,6 +661,9 @@ bool ED_autokeyframe_pchan(struct bContext *C,
struct Object *ob,
struct bPoseChannel *pchan,
struct KeyingSet *ks);
+/**
+ * Use for auto-key-framing from the UI.
+ */
bool ED_autokeyframe_property(struct bContext *C,
struct Scene *scene,
PointerRNA *ptr,
@@ -506,7 +672,8 @@ bool ED_autokeyframe_property(struct bContext *C,
float cfra);
/* Names for builtin keying sets so we don't confuse these with labels/text,
- * defined in python script: keyingsets_builtins.py */
+ * defined in python script: `keyingsets_builtins.py`. */
+
#define ANIM_KS_LOCATION_ID "Location"
#define ANIM_KS_ROTATION_ID "Rotation"
#define ANIM_KS_SCALING_ID "Scaling"
@@ -516,6 +683,8 @@ bool ED_autokeyframe_property(struct bContext *C,
#define ANIM_KS_WHOLE_CHARACTER_ID "WholeCharacter"
#define ANIM_KS_WHOLE_CHARACTER_SELECTED_ID "WholeCharacterSelected"
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h
index 6982ad20f07..3d779fd14ef 100644
--- a/source/blender/editors/include/ED_lattice.h
+++ b/source/blender/editors/include/ED_lattice.h
@@ -33,18 +33,22 @@ struct UndoType;
struct wmKeyConfig;
/* lattice_ops.c */
+
void ED_operatortypes_lattice(void);
void ED_keymap_lattice(struct wmKeyConfig *keyconf);
/* editlattice_select.c */
+
bool ED_lattice_flags_set(struct Object *obedit, int flag);
bool ED_lattice_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
-bool ED_lattice_deselect_all_multi_ex(struct Base **bases, const uint bases_len);
+bool ED_lattice_deselect_all_multi_ex(struct Base **bases, uint bases_len);
bool ED_lattice_deselect_all_multi(struct bContext *C);
/* editlattice_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_lattice_undosys_type(struct UndoType *ut);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_markers.h b/source/blender/editors/include/ED_markers.h
index 8c10a8e36fd..8e6961ffd6f 100644
--- a/source/blender/editors/include/ED_markers.h
+++ b/source/blender/editors/include/ED_markers.h
@@ -33,7 +33,9 @@ struct bAnimContext;
struct bContext;
struct wmKeyConfig;
-/* Drawing API ------------------------------ */
+/* -------------------------------------------------------------------- */
+/** \name Drawing API
+ * \{ */
/* flags for drawing markers */
enum {
@@ -42,37 +44,86 @@ enum {
DRAW_MARKERS_MARGIN = (1 << 2),
};
+/* Draw Scene-Markers in time window */
void ED_markers_draw(const struct bContext *C, int flag);
-/* Backend API ----------------------------- */
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Backend API
+ * \{ */
+
+/**
+ * Public API for getting markers from context.
+ */
ListBase *ED_context_get_markers(const struct bContext *C);
+/**
+ * Public API for getting markers from "animation" context.
+ */
ListBase *ED_animcontext_get_markers(const struct bAnimContext *ac);
+/**
+ * Apply some transformation to markers after the fact
+ *
+ * \param markers: List of markers to affect - this may or may not be the scene markers list,
+ * so don't assume anything.
+ * \param scene: Current scene (for getting current frame)
+ * \param mode: (TfmMode) transform mode that this transform is for
+ * \param value: From the transform code, this is `t->vec[0]`
+ * (which is delta transform for grab/extend, and scale factor for scale)
+ * \param side: (B/L/R) for 'extend' functionality, which side of current frame to use
+ */
int ED_markers_post_apply_transform(
ListBase *markers, struct Scene *scene, int mode, float value, char side);
+/**
+ * Get the marker that is closest to this point.
+ * XXX: for select, the min_dist should be small.
+ */
struct TimeMarker *ED_markers_find_nearest_marker(ListBase *markers, float x);
+/**
+ * Return the time of the marker that occurs on a frame closest to the given time.
+ */
int ED_markers_find_nearest_marker_time(ListBase *markers, float x);
void ED_markers_get_minmax(ListBase *markers, short sel, float *first, float *last);
+/**
+ * This function makes a list of all the markers. The only_sel
+ * argument is used to specify whether only the selected markers
+ * are added.
+ */
void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short sel);
void ED_markers_deselect_all(ListBase *markers, int action);
+/**
+ * Get the first selected marker.
+ */
struct TimeMarker *ED_markers_get_first_selected(ListBase *markers);
-/* Operators ------------------------------ */
+/** \} */
-/* called in screen_ops.c:ED_operatortypes_screen() */
+/* -------------------------------------------------------------------- */
+/** \name Operators
+ * \{ */
+
+/**
+ * Called in screen_ops.c:ED_operatortypes_screen().
+ */
void ED_operatortypes_marker(void);
-/* called in screen_ops.c:ED_keymap_screen() */
+/**
+ * Called in screen_ops.c:ED_keymap_screen().
+ */
void ED_keymap_marker(struct wmKeyConfig *keyconf);
-/* debugging only */
+/**
+ * Debugging only: print debugging prints of list of markers.
+ */
void debug_markers_print_list(struct ListBase *markers);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index c2fdbc160de..1a4c36acff9 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -37,6 +37,7 @@ struct bContext;
struct wmKeyConfig;
/* mask_edit.c */
+
void ED_mask_deselect_all(const struct bContext *C);
void ED_operatortypes_mask(void);
@@ -44,6 +45,7 @@ void ED_keymap_mask(struct wmKeyConfig *keyconf);
void ED_operatormacros_mask(void);
/* mask_query.c */
+
void ED_mask_get_size(struct ScrArea *area, int *width, int *height);
void ED_mask_zoom(struct ScrArea *area, struct ARegion *region, float *zoomx, float *zoomy);
void ED_mask_get_aspect(struct ScrArea *area, struct ARegion *region, float *aspx, float *aspy);
@@ -52,11 +54,18 @@ void ED_mask_pixelspace_factor(struct ScrArea *area,
struct ARegion *region,
float *scalex,
float *scaley);
+/**
+ * Takes `event->mval`.
+ */
void ED_mask_mouse_pos(struct ScrArea *area,
struct ARegion *region,
const int mval[2],
float co[2]);
+/**
+ * \param x/y: input, mval space.
+ * \param xr/yr: output, mask point space.
+ */
void ED_mask_point_pos(
struct ScrArea *area, struct ARegion *region, float x, float y, float *xr, float *yr);
void ED_mask_point_pos__reverse(
@@ -69,53 +78,92 @@ bool ED_mask_selected_minmax(const struct bContext *C,
bool handles_as_control_point);
/* mask_draw.c */
-void ED_mask_draw(const struct bContext *C, const char draw_flag, const char draw_type);
+
+void ED_mask_draw(const struct bContext *C, char draw_flag, char draw_type);
+/**
+ * Sets up the opengl context.
+ * width, height are to match the values from #ED_mask_get_size().
+ */
void ED_mask_draw_region(struct Depsgraph *depsgraph,
struct Mask *mask,
struct ARegion *region,
- const char draw_flag,
- const char draw_type,
- const eMaskOverlayMode overlay_mode,
- const int width_i,
- const int height_i,
- const float aspx,
- const float aspy,
- const bool do_scale_applied,
- const bool do_draw_cb,
+ char draw_flag,
+ char draw_type,
+ eMaskOverlayMode overlay_mode,
+ int width_i,
+ int height_i,
+ float aspx,
+ float aspy,
+ bool do_scale_applied,
+ bool do_draw_cb,
float stabmat[4][4],
const struct bContext *C);
-void ED_mask_draw_frames(
- struct Mask *mask, struct ARegion *region, const int cfra, const int sfra, const int efra);
+void ED_mask_draw_frames(struct Mask *mask, struct ARegion *region, int cfra, int sfra, int efra);
/* mask_shapekey.c */
-void ED_mask_layer_shape_auto_key(struct MaskLayer *mask_layer, const int frame);
-bool ED_mask_layer_shape_auto_key_all(struct Mask *mask, const int frame);
-bool ED_mask_layer_shape_auto_key_select(struct Mask *mask, const int frame);
+
+void ED_mask_layer_shape_auto_key(struct MaskLayer *mask_layer, int frame);
+bool ED_mask_layer_shape_auto_key_all(struct Mask *mask, int frame);
+bool ED_mask_layer_shape_auto_key_select(struct Mask *mask, int frame);
/* ----------- Mask AnimEdit API ------------------ */
+
+/**
+ * Loops over the mask-frames for a mask-layer, and applies the given callback.
+ */
bool ED_masklayer_frames_looper(struct MaskLayer *mask_layer,
struct Scene *scene,
bool (*mask_layer_shape_cb)(struct MaskLayerShape *,
struct Scene *));
+/**
+ * Make a listing all the mask-frames in a layer as cfraelems.
+ */
void ED_masklayer_make_cfra_list(struct MaskLayer *mask_layer, ListBase *elems, bool onlysel);
+/**
+ * Check if one of the frames in this layer is selected.
+ */
bool ED_masklayer_frame_select_check(const struct MaskLayer *mask_layer);
+/**
+ * Set all/none/invert select.
+ */
void ED_masklayer_frame_select_set(struct MaskLayer *mask_layer, short mode);
+/**
+ * Select the frames in this layer that occur within the bounds specified.
+ */
void ED_masklayer_frames_select_box(struct MaskLayer *mask_layer,
float min,
float max,
short select_mode);
+/**
+ * Select the frames in this layer that occur within the lasso/circle region specified.
+ */
void ED_masklayer_frames_select_region(struct KeyframeEditData *ked,
struct MaskLayer *mask_layer,
short tool,
short select_mode);
+/**
+ * Set all/none/invert select (like above, but with SELECT_* modes).
+ */
void ED_mask_select_frames(struct MaskLayer *mask_layer, short select_mode);
+/**
+ * Select the frame in this layer that occurs on this frame (there should only be one at most).
+ */
void ED_mask_select_frame(struct MaskLayer *mask_layer, int selx, short select_mode);
+/**
+ * Delete selected frames.
+ */
bool ED_masklayer_frames_delete(struct MaskLayer *mask_layer);
+/**
+ * Duplicate selected frames from given mask-layer.
+ */
void ED_masklayer_frames_duplicate(struct MaskLayer *mask_layer);
+/**
+ * Snap selected frames to ...
+ */
void ED_masklayer_snap_frames(struct MaskLayer *mask_layer, struct Scene *scene, short mode);
#if 0
diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h
index 7648af159c9..1afd7f06a5a 100644
--- a/source/blender/editors/include/ED_mball.h
+++ b/source/blender/editors/include/ED_mball.h
@@ -37,6 +37,9 @@ void ED_operatortypes_metaball(void);
void ED_operatormacros_metaball(void);
void ED_keymap_metaball(struct wmKeyConfig *keyconf);
+/**
+ * Add meta-element primitive to meta-ball object (which is in edit mode).
+ */
struct MetaElem *ED_mball_add_primitive(struct bContext *C,
struct Object *obedit,
bool obedit_is_new,
@@ -44,17 +47,32 @@ struct MetaElem *ED_mball_add_primitive(struct bContext *C,
float dia,
int type);
+/**
+ * Select MetaElement with mouse click (user can select radius circle or stiffness circle).
+ */
bool ED_mball_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
bool ED_mball_deselect_all_multi_ex(struct Base **bases, uint bases_len);
bool ED_mball_deselect_all_multi(struct bContext *C);
+/**
+ * This function is used to free all MetaElems from MetaBall.
+ */
void ED_mball_editmball_free(struct Object *obedit);
+/**
+ * This function is called, when MetaBall Object is switched from object mode to edit mode.
+ */
void ED_mball_editmball_make(struct Object *obedit);
+/**
+ * This function is called, when MetaBall Object switched from edit mode to object mode.
+ * List of MetaElements is copied from object->data->edit_elems to object->data->elems.
+ */
void ED_mball_editmball_load(struct Object *obedit);
/* editmball_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_mball_undosys_type(struct UndoType *ut);
#define MBALLSEL_STIFF (1u << 30)
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 2b73194afb2..0721aa21a16 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -58,21 +58,32 @@ struct wmKeyConfig;
struct wmOperator;
/* editmesh_utils.c */
+
+/**
+ * \param em: Edit-mesh used for generating mirror data.
+ * \param use_self: Allow a vertex to point to itself (middle verts).
+ * \param use_select: Restrict to selected verts.
+ * \param respecthide: Skip hidden vertices.
+ * \param use_topology: Use topology mirror.
+ * \param maxdist: Distance for close point test.
+ * \param r_index: Optional array to write into, as an alternative to a custom-data layer
+ * (length of total verts).
+ */
void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em,
- const int axis,
- const bool use_self,
- const bool use_select,
- const bool respecthide,
- const bool use_topology,
+ int axis,
+ bool use_self,
+ bool use_select,
+ bool respecthide,
+ bool use_topology,
float maxdist,
int *r_index);
void EDBM_verts_mirror_cache_begin(struct BMEditMesh *em,
- const int axis,
- const bool use_self,
- const bool use_select,
- const bool respecthide,
- const bool use_topology);
-void EDBM_verts_mirror_apply(struct BMEditMesh *em, const int sel_from, const int sel_to);
+ int axis,
+ bool use_self,
+ bool use_select,
+ bool respecthide,
+ bool use_topology);
+void EDBM_verts_mirror_apply(struct BMEditMesh *em, int sel_from, int sel_to);
struct BMVert *EDBM_verts_mirror_get(struct BMEditMesh *em, struct BMVert *v);
struct BMEdge *EDBM_verts_mirror_get_edge(struct BMEditMesh *em, struct BMEdge *e);
struct BMFace *EDBM_verts_mirror_get_face(struct BMEditMesh *em, struct BMFace *f);
@@ -85,19 +96,29 @@ void EDBM_mesh_normals_update(struct BMEditMesh *em);
void EDBM_mesh_clear(struct BMEditMesh *em);
void EDBM_selectmode_to_scene(struct bContext *C);
-void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool add_key_index);
+void EDBM_mesh_make(struct Object *ob, int select_mode, bool add_key_index);
+/**
+ * Should only be called on the active edit-mesh, otherwise call #BKE_editmesh_free_data.
+ */
void EDBM_mesh_free_data(struct BMEditMesh *em);
+/**
+ * \warning This can invalidate the #Mesh runtime cache of other objects (for linked duplicates).
+ * Most callers should run #DEG_id_tag_update on `ob->data`, see: T46738, T46913.
+ * This ensures #BKE_object_free_derived_caches runs on all objects that use this mesh.
+ */
void EDBM_mesh_load_ex(struct Main *bmain, struct Object *ob, bool free_data);
void EDBM_mesh_load(struct Main *bmain, struct Object *ob);
-/* flushes based on the current select mode. if in vertex select mode,
+/**
+ * flushes based on the current select mode. If in vertex select mode,
* verts select/deselect edges and faces, if in edge select mode,
* edges select/deselect faces and vertices, and in face select mode faces select/deselect
- * edges and vertices. */
-void EDBM_select_more(struct BMEditMesh *em, const bool use_face_step);
-void EDBM_select_less(struct BMEditMesh *em, const bool use_face_step);
+ * edges and vertices.
+ */
+void EDBM_select_more(struct BMEditMesh *em, bool use_face_step);
+void EDBM_select_less(struct BMEditMesh *em, bool use_face_step);
-void EDBM_selectmode_flush_ex(struct BMEditMesh *em, const short selectmode);
+void EDBM_selectmode_flush_ex(struct BMEditMesh *em, short selectmode);
void EDBM_selectmode_flush(struct BMEditMesh *em);
void EDBM_deselect_flush(struct BMEditMesh *em);
@@ -105,6 +126,9 @@ void EDBM_select_flush(struct BMEditMesh *em);
bool EDBM_vert_color_check(struct BMEditMesh *em);
+/**
+ * Swap is 0 or 1, if 1 it hides not selected.
+ */
bool EDBM_mesh_hide(struct BMEditMesh *em, bool swap);
bool EDBM_mesh_reveal(struct BMEditMesh *em, bool select);
@@ -114,33 +138,48 @@ struct EDBMUpdate_Params {
uint is_destructive : 1;
};
+/**
+ * So many tools call these that we better make it a generic function.
+ */
void EDBM_update(struct Mesh *me, const struct EDBMUpdate_Params *params);
-void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool is_destructive);
+/**
+ * Bad level call from Python API.
+ */
+void EDBM_update_extern(struct Mesh *me, bool do_tessellation, bool is_destructive);
+/**
+ * A specialized vert map used by stitch operator.
+ */
struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm,
const struct Scene *scene,
- const bool face_selected,
- const bool uv_selected,
- const bool use_winding,
- const bool do_islands);
+ bool face_selected,
+ bool uv_selected,
+ bool use_winding,
+ bool do_islands);
void BM_uv_element_map_free(struct UvElementMap *element_map);
struct UvElement *BM_uv_element_get(struct UvElementMap *map,
struct BMFace *efa,
struct BMLoop *l);
+/**
+ * Can we edit UV's for this mesh?
+ */
bool EDBM_uv_check(struct BMEditMesh *em);
-struct BMFace *EDBM_uv_active_face_get(struct BMEditMesh *em,
- const bool sloppy,
- const bool selected);
+/**
+ * last_sel, use em->act_face otherwise get the last selected face in the editselections
+ * at the moment, last_sel is mainly useful for making sure the space image doesn't flicker.
+ */
+struct BMFace *EDBM_uv_active_face_get(struct BMEditMesh *em, bool sloppy, bool selected);
void BM_uv_vert_map_free(struct UvVertMap *vmap);
struct UvMapVert *BM_uv_vert_map_at_index(struct UvVertMap *vmap, unsigned int v);
-struct UvVertMap *BM_uv_vert_map_create(struct BMesh *bm,
- const bool use_select,
- const bool use_winding);
+/**
+ * Return a new #UvVertMap from the edit-mesh.
+ */
+struct UvVertMap *BM_uv_vert_map_create(struct BMesh *bm, bool use_select, bool use_winding);
-void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag);
-void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag);
+void EDBM_flag_enable_all(struct BMEditMesh *em, char hflag);
+void EDBM_flag_disable_all(struct BMEditMesh *em, char hflag);
bool BMBVH_EdgeVisible(struct BMBVHTree *tree,
struct BMEdge *e,
@@ -156,28 +195,39 @@ void EDBM_project_snap_verts(struct bContext *C,
struct BMEditMesh *em);
/* editmesh_automerge.c */
-void EDBM_automerge(struct Object *ob, bool update, const char hflag, const float dist);
-void EDBM_automerge_and_split(struct Object *ob,
- const bool split_edges,
- const bool split_faces,
- const bool update,
- const char hflag,
- const float dist);
+
+void EDBM_automerge(struct Object *ob, bool update, char hflag, float dist);
+void EDBM_automerge_and_split(
+ struct Object *ob, bool split_edges, bool split_faces, bool update, char hflag, float dist);
/* editmesh_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_mesh_undosys_type(struct UndoType *ut);
/* editmesh_select.c */
+
void EDBM_select_mirrored(struct BMEditMesh *em,
const struct Mesh *me,
- const int axis,
- const bool extend,
+ int axis,
+ bool extend,
int *r_totmirr,
int *r_totfail);
+/**
+ * Nearest vertex under the cursor.
+ *
+ * \param dist_px_manhattan_p: (in/out), minimal distance to the nearest and at the end,
+ * actual distance.
+ * \param use_select_bias:
+ * - When true, selected vertices are given a 5 pixel bias
+ * to make them further than unselected vertices.
+ * - When false, unselected vertices are given the bias.
+ * \param use_cycle: Cycle over elements within #FIND_NEAR_CYCLE_THRESHOLD_MIN in order of index.
+ */
struct BMVert *EDBM_vert_find_nearest_ex(struct ViewContext *vc,
float *dist_px_manhattan_p,
- const bool use_select_bias,
+ bool use_select_bias,
bool use_cycle,
struct Base **bases,
uint bases_len,
@@ -187,7 +237,7 @@ struct BMVert *EDBM_vert_find_nearest(struct ViewContext *vc, float *dist_px_man
struct BMEdge *EDBM_edge_find_nearest_ex(struct ViewContext *vc,
float *dist_px_manhattan,
float *r_dist_center,
- const bool use_select_bias,
+ bool use_select_bias,
bool use_cycle,
struct BMEdge **r_eed_zbuf,
struct Base **bases,
@@ -195,11 +245,18 @@ struct BMEdge *EDBM_edge_find_nearest_ex(struct ViewContext *vc,
uint *r_base_index);
struct BMEdge *EDBM_edge_find_nearest(struct ViewContext *vc, float *dist_px_manhattan_p);
+/**
+ * \param use_zbuf_single_px: Special case, when using the back-buffer selection,
+ * only use the pixel at `vc->mval` instead of using `dist_px_manhattan_p` to search over a larger
+ * region. This is needed because historically selection worked this way for a long time, however
+ * it's reasonable that some callers might want to expand the region too. So add an argument to do
+ * this,
+ */
struct BMFace *EDBM_face_find_nearest_ex(struct ViewContext *vc,
float *dist_px_manhattan,
float *r_dist_center,
- const bool use_zbuf_single_px,
- const bool use_select_bias,
+ bool use_zbuf_single_px,
+ bool use_select_bias,
bool use_cycle,
struct BMFace **r_efa_zbuf,
struct Base **bases,
@@ -209,7 +266,7 @@ struct BMFace *EDBM_face_find_nearest(struct ViewContext *vc, float *dist_px_man
bool EDBM_unified_findnearest(struct ViewContext *vc,
struct Base **bases,
- const uint bases_len,
+ uint bases_len,
int *r_base_index,
struct BMVert **r_eve,
struct BMEdge **r_eed,
@@ -217,7 +274,7 @@ bool EDBM_unified_findnearest(struct ViewContext *vc,
bool EDBM_unified_findnearest_from_raycast(struct ViewContext *vc,
struct Base **bases,
- const uint bases_len,
+ uint bases_len,
bool use_boundary_vertices,
bool use_boundary_edges,
int *r_base_index_vert,
@@ -230,25 +287,49 @@ bool EDBM_unified_findnearest_from_raycast(struct ViewContext *vc,
bool EDBM_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+/**
+ * When switching select mode, makes sure selection is consistent for editing
+ * also for paranoia checks to make sure edge or face mode works.
+ */
void EDBM_selectmode_set(struct BMEditMesh *em);
-void EDBM_selectmode_convert(struct BMEditMesh *em,
- const short selectmode_old,
- const short selectmode_new);
-
-/* user access this */
-bool EDBM_selectmode_set_multi(struct bContext *C, const short selectmode);
-bool EDBM_selectmode_toggle_multi(struct bContext *C,
- const short selectmode_new,
- const int action,
- const bool use_extend,
- const bool use_expand);
+/**
+ * Expand & Contract the Selection
+ * (used when changing modes and Ctrl key held)
+ *
+ * Flush the selection up:
+ * - vert -> edge
+ * - vert -> face
+ * - edge -> face
+ *
+ * Flush the selection down:
+ * - face -> edge
+ * - face -> vert
+ * - edge -> vert
+ */
+void EDBM_selectmode_convert(struct BMEditMesh *em, short selectmode_old, short selectmode_new);
+/**
+ * User access this.
+ */
+bool EDBM_selectmode_set_multi(struct bContext *C, short selectmode);
+/**
+ * User facing function, does notification.
+ */
+bool EDBM_selectmode_toggle_multi(
+ struct bContext *C, short selectmode_new, int action, bool use_extend, bool use_expand);
+
+/**
+ * Use to disable a select-mode if its enabled, Using another mode as a fallback
+ * if the disabled mode is the only mode set.
+ *
+ * \return true if the mode is changed.
+ */
bool EDBM_selectmode_disable(struct Scene *scene,
struct BMEditMesh *em,
- const short selectmode_disable,
- const short selectmode_fallback);
+ short selectmode_disable,
+ short selectmode_fallback);
-bool EDBM_deselect_by_material(struct BMEditMesh *em, const short index, const bool select);
+bool EDBM_deselect_by_material(struct BMEditMesh *em, short index, bool select);
void EDBM_select_toggle_all(struct BMEditMesh *em);
@@ -256,16 +337,16 @@ void EDBM_select_swap(struct BMEditMesh *em); /* exported for UV */
bool EDBM_select_interior_faces(struct BMEditMesh *em);
void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc); /* rename? */
-bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len);
+bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, uint bases_len);
bool EDBM_mesh_deselect_all_multi(struct bContext *C);
bool EDBM_selectmode_disable_multi_ex(struct Scene *scene,
struct Base **bases,
- const uint bases_len,
- const short selectmode_disable,
- const short selectmode_fallback);
+ uint bases_len,
+ short selectmode_disable,
+ short selectmode_fallback);
bool EDBM_selectmode_disable_multi(struct bContext *C,
- const short selectmode_disable,
- const short selectmode_fallback);
+ short selectmode_disable,
+ short selectmode_fallback);
/* editmesh_preselect_edgering.c */
struct EditMesh_PreSelEdgeRing;
@@ -305,12 +386,22 @@ void EDBM_preselect_elem_update_preview(struct EditMesh_PreSelElem *psel,
void EDBM_preselect_action_set(struct EditMesh_PreSelElem *psel,
eEditMesh_PreSelPreviewAction action);
eEditMesh_PreSelPreviewAction EDBM_preselect_action_get(struct EditMesh_PreSelElem *psel);
+
/* mesh_ops.c */
+
void ED_operatortypes_mesh(void);
void ED_operatormacros_mesh(void);
+/**
+ * Note mesh keymap also for other space?
+ */
void ED_keymap_mesh(struct wmKeyConfig *keyconf);
/* editface.c */
+
+/**
+ * Copy the face flags, most importantly selection from the mesh to the final derived mesh,
+ * use in object mode when selecting faces (while painting).
+ */
void paintface_flush_flags(struct bContext *C, struct Object *ob, short flag);
bool paintface_mouse_select(struct bContext *C,
struct Object *ob,
@@ -325,14 +416,23 @@ bool paintface_deselect_all_visible(struct bContext *C,
void paintface_select_linked(struct bContext *C,
struct Object *ob,
const int mval[2],
- const bool select);
+ bool select);
bool paintface_minmax(struct Object *ob, float r_min[3], float r_max[3]);
-void paintface_hide(struct bContext *C, struct Object *ob, const bool unselected);
-void paintface_reveal(struct bContext *C, struct Object *ob, const bool select);
+void paintface_hide(struct bContext *C, struct Object *ob, bool unselected);
+void paintface_reveal(struct bContext *C, struct Object *ob, bool select);
+/**
+ * \note if the caller passes false to flush_flags,
+ * then they will need to run #paintvert_flush_flags(ob) themselves.
+ */
bool paintvert_deselect_all_visible(struct Object *ob, int action, bool flush_flags);
void paintvert_select_ungrouped(struct Object *ob, bool extend, bool flush_flags);
+/**
+ * (similar to void `paintface_flush_flags(Object *ob)`)
+ * copy the vertex flags, most importantly selection from the mesh to the final derived mesh,
+ * use in object mode when selecting vertices (while painting).
+ */
void paintvert_flush_flags(struct Object *ob);
void paintvert_tag_select_update(struct bContext *C, struct Object *ob);
@@ -350,7 +450,7 @@ bool ED_mesh_mirrtopo_recalc_check(struct BMEditMesh *em,
void ED_mesh_mirrtopo_init(struct BMEditMesh *em,
struct Mesh *me,
MirrTopoStore_t *mesh_topo_store,
- const bool skip_em_vert_array_init);
+ bool skip_em_vert_array_init);
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store);
/* object_vgroup.c */
@@ -360,50 +460,78 @@ void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store);
bool ED_vgroup_sync_from_pose(struct Object *ob);
void ED_vgroup_select_by_name(struct Object *ob, const char *name);
-void ED_vgroup_data_clamp_range(struct ID *id, const int total);
+/**
+ * Removes out of range #MDeformWeights
+ */
+void ED_vgroup_data_clamp_range(struct ID *id, int total);
+/**
+ * Matching index only.
+ */
bool ED_vgroup_array_copy(struct Object *ob, struct Object *ob_from);
bool ED_vgroup_parray_alloc(struct ID *id,
struct MDeformVert ***dvert_arr,
int *dvert_tot,
- const bool use_vert_sel);
+ bool use_vert_sel);
+/**
+ * For use with tools that use ED_vgroup_parray_alloc with \a use_vert_sel == true.
+ * This finds the unselected mirror deform verts and copies the weights to them from the selected.
+ *
+ * \note \a dvert_array has mirrored weights filled in,
+ * in case cleanup operations are needed on both.
+ */
void ED_vgroup_parray_mirror_sync(struct Object *ob,
struct MDeformVert **dvert_array,
- const int dvert_tot,
+ int dvert_tot,
const bool *vgroup_validmap,
- const int vgroup_tot);
+ int vgroup_tot);
+/**
+ * Fill in the pointers for mirror verts (as if all mirror verts were selected too).
+ *
+ * similar to #ED_vgroup_parray_mirror_sync but only fill in mirror points.
+ */
void ED_vgroup_parray_mirror_assign(struct Object *ob,
struct MDeformVert **dvert_array,
- const int dvert_tot);
+ int dvert_tot);
void ED_vgroup_parray_remove_zero(struct MDeformVert **dvert_array,
- const int dvert_tot,
+ int dvert_tot,
const bool *vgroup_validmap,
- const int vgroup_tot,
- const float epsilon,
- const bool keep_single);
+ int vgroup_tot,
+ float epsilon,
+ bool keep_single);
void ED_vgroup_parray_to_weight_array(const struct MDeformVert **dvert_array,
- const int dvert_tot,
+ int dvert_tot,
float *dvert_weights,
- const int def_nr);
+ int def_nr);
void ED_vgroup_parray_from_weight_array(struct MDeformVert **dvert_array,
- const int dvert_tot,
+ int dvert_tot,
const float *dvert_weights,
- const int def_nr,
- const bool remove_zero);
+ int def_nr,
+ bool remove_zero);
void ED_vgroup_mirror(struct Object *ob,
- const bool mirror_weights,
- const bool flip_vgroups,
- const bool all_vgroups,
- const bool use_topology,
+ bool mirror_weights,
+ bool flip_vgroups,
+ bool all_vgroups,
+ bool use_topology,
int *r_totmirr,
int *r_totfail);
+/**
+ * Called while not in editmode.
+ */
void ED_vgroup_vert_add(
struct Object *ob, struct bDeformGroup *dg, int vertnum, float weight, int assignmode);
+/**
+ * Mesh object mode, lattice can be in edit-mode.
+ */
void ED_vgroup_vert_remove(struct Object *ob, struct bDeformGroup *dg, int vertnum);
float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertnum);
+/**
+ * Use when adjusting the active vertex weight and apply to mirror vertices.
+ */
void ED_vgroup_vert_active_mirror(struct Object *ob, int def_nr);
/* mesh_data.c */
+
void ED_mesh_verts_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_loops_add(struct Mesh *mesh, struct ReportList *reports, int count);
@@ -419,37 +547,36 @@ void ED_mesh_geometry_clear(struct Mesh *mesh);
void ED_mesh_update(struct Mesh *mesh, struct bContext *C, bool calc_edges, bool calc_edges_loose);
void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name);
-int ED_mesh_uv_texture_add(struct Mesh *me,
- const char *name,
- const bool active_set,
- const bool do_init);
-bool ED_mesh_uv_texture_remove_index(struct Mesh *me, const int n);
+int ED_mesh_uv_texture_add(
+ struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports);
+bool ED_mesh_uv_texture_remove_index(struct Mesh *me, int n);
bool ED_mesh_uv_texture_remove_active(struct Mesh *me);
bool ED_mesh_uv_texture_remove_named(struct Mesh *me, const char *name);
void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me);
-void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum);
+/**
+ * Without a #bContext, called when UV-editing.
+ */
+void ED_mesh_uv_loop_reset_ex(struct Mesh *me, int layernum);
bool ED_mesh_color_ensure(struct Mesh *me, const char *name);
-int ED_mesh_color_add(struct Mesh *me,
- const char *name,
- const bool active_set,
- const bool do_init);
-bool ED_mesh_color_remove_index(struct Mesh *me, const int n);
+int ED_mesh_color_add(
+ struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports);
+bool ED_mesh_color_remove_index(struct Mesh *me, int n);
bool ED_mesh_color_remove_active(struct Mesh *me);
bool ED_mesh_color_remove_named(struct Mesh *me, const char *name);
bool ED_mesh_sculpt_color_ensure(struct Mesh *me, const char *name);
-int ED_mesh_sculpt_color_add(struct Mesh *me,
- const char *name,
- const bool active_set,
- const bool do_init);
-bool ED_mesh_sculpt_color_remove_index(struct Mesh *me, const int n);
+int ED_mesh_sculpt_color_add(
+ struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports);
+bool ED_mesh_sculpt_color_remove_index(struct Mesh *me, int n);
bool ED_mesh_sculpt_color_remove_active(struct Mesh *me);
bool ED_mesh_sculpt_color_remove_named(struct Mesh *me, const char *name);
void ED_mesh_report_mirror(struct wmOperator *op, int totmirr, int totfail);
void ED_mesh_report_mirror_ex(struct wmOperator *op, int totmirr, int totfail, char selectmode);
-/* Returns the pinned mesh, the mesh from the pinned object, or the mesh from the active object. */
+/**
+ * Returns the pinned mesh, the mesh from the pinned object, or the mesh from the active object.
+ */
struct Mesh *ED_mesh_context(struct bContext *C);
/* mesh backup */
@@ -457,20 +584,30 @@ typedef struct BMBackup {
struct BMesh *bmcopy;
} BMBackup;
+/**
+ * Save a copy of the #BMesh for restoring later.
+ */
struct BMBackup EDBM_redo_state_store(struct BMEditMesh *em);
-/* restore a bmesh from backup */
+/**
+ * Restore a BMesh from backup.
+ */
void EDBM_redo_state_restore(struct BMBackup *backup, struct BMEditMesh *em, bool recalc_looptri)
ATTR_NONNULL(1, 2);
+/**
+ * Delete the backup, flushing it to an edit-mesh.
+ */
void EDBM_redo_state_restore_and_free(struct BMBackup *backup,
struct BMEditMesh *em,
bool recalc_looptri) ATTR_NONNULL(1, 2);
void EDBM_redo_state_free(struct BMBackup *backup) ATTR_NONNULL(1);
/* *** meshtools.c *** */
+
int ED_mesh_join_objects_exec(struct bContext *C, struct wmOperator *op);
int ED_mesh_shapes_join_objects_exec(struct bContext *C, struct wmOperator *op);
/* mirror lookup api */
+
/* Spatial Mirror */
void ED_mesh_mirror_spatial_table_begin(struct Object *ob,
struct BMEditMesh *em,
@@ -482,23 +619,36 @@ int ED_mesh_mirror_spatial_table_lookup(struct Object *ob,
const float co[3]);
/* Topology Mirror */
+
+/**
+ * Mode is 's' start, or 'e' end, or 'u' use if end, ob can be NULL.
+ * \note This is supposed return -1 on error,
+ * which callers are currently checking for, but is not used so far.
+ */
void ED_mesh_mirror_topo_table_begin(struct Object *ob, struct Mesh *me_eval);
void ED_mesh_mirror_topo_table_end(struct Object *ob);
-/* Retrieves mirrored cache vert, or NULL if there isn't one.
- * NOTE: calling this without ensuring the mirror cache state is bad. */
-int mesh_get_x_mirror_vert(struct Object *ob,
- struct Mesh *me_eval,
- int index,
- const bool use_topology);
+/**
+ * Retrieves mirrored cache vert, or NULL if there isn't one.
+ * \note calling this without ensuring the mirror cache state is bad.
+ */
+int mesh_get_x_mirror_vert(struct Object *ob, struct Mesh *me_eval, int index, bool use_topology);
struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob,
struct BMEditMesh *em,
struct BMVert *eve,
const float co[3],
int index,
- const bool use_topology);
+ bool use_topology);
+/**
+ * This is a Mesh-based copy of #mesh_get_x_mirror_faces().
+ */
int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em, struct Mesh *me_eval);
+/**
+ * Wrapper for object-mode/edit-mode.
+ *
+ * call #BM_mesh_elem_table_ensure first for edit-mesh.
+ */
int ED_mesh_mirror_get_vert(struct Object *ob, int index);
bool ED_mesh_pick_vert(struct bContext *C,
@@ -507,8 +657,18 @@ bool ED_mesh_pick_vert(struct bContext *C,
uint dist_px,
bool use_zbuf,
uint *r_index);
+/**
+ * Face selection in object mode,
+ * currently only weight-paint and vertex-paint use this.
+ *
+ * \return boolean true == Found
+ */
bool ED_mesh_pick_face(
struct bContext *C, struct Object *ob, const int mval[2], uint dist_px, uint *r_index);
+/**
+ * Use when the back buffer stores face index values. but we want a vert.
+ * This gets the face then finds the closest vertex to mval.
+ */
bool ED_mesh_pick_face_vert(
struct bContext *C, struct Object *ob, const int mval[2], uint dist_px, uint *r_index);
@@ -517,12 +677,10 @@ struct MDeformVert *ED_mesh_active_dvert_get_ob(struct Object *ob, int *r_index)
struct MDeformVert *ED_mesh_active_dvert_get_only(struct Object *ob);
void EDBM_mesh_stats_multi(struct Object **objects,
- const uint objects_len,
+ uint objects_len,
int totelem[3],
int totelem_sel[3]);
-void EDBM_mesh_elem_index_ensure_multi(struct Object **objects,
- const uint objects_len,
- const char htype);
+void EDBM_mesh_elem_index_ensure_multi(struct Object **objects, uint objects_len, char htype);
#define ED_MESH_PICK_DEFAULT_VERT_DIST 25
#define ED_MESH_PICK_DEFAULT_FACE_DIST 1
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 1d51a3e77cf..181b6848ac7 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -49,7 +49,7 @@ typedef enum {
NODE_RIGHT = 8,
} NodeBorder;
-#define NODE_GRID_STEPS 5
+#define NODE_GRID_STEP_SIZE 10
#define NODE_EDGE_PAN_INSIDE_PAD 2
#define NODE_EDGE_PAN_OUTSIDE_PAD 0 /* Disable clamping for node panning, use whole screen. */
#define NODE_EDGE_PAN_SPEED_RAMP 1
@@ -64,7 +64,6 @@ void ED_node_cursor_location_set(struct SpaceNode *snode, const float value[2]);
int ED_node_tree_path_length(struct SpaceNode *snode);
void ED_node_tree_path_get(struct SpaceNode *snode, char *value);
-void ED_node_tree_path_get_fixedbuf(struct SpaceNode *snode, char *value, int max_length);
void ED_node_tree_start(struct SpaceNode *snode,
struct bNodeTree *ntree,
@@ -78,6 +77,7 @@ struct bNodeTree *ED_node_tree_get(struct SpaceNode *snode, int level);
void ED_node_set_active_viewer_key(struct SpaceNode *snode);
/* drawnode.c */
+
void ED_node_init_butfuncs(void);
void ED_init_custom_node_type(struct bNodeType *ntype);
void ED_init_custom_node_socket_type(struct bNodeSocketType *stype);
@@ -88,32 +88,55 @@ void ED_node_draw_snap(
struct View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned int pos);
/* node_draw.cc */
+
+/**
+ * Draw a single node socket at default size.
+ * \note this is only called from external code, internally #node_socket_draw_nested() is used for
+ * optimized drawing of multiple/all sockets of a node.
+ */
void ED_node_socket_draw(struct bNodeSocket *sock,
const struct rcti *rect,
const float color[4],
float scale);
void ED_node_tree_update(const struct bContext *C);
void ED_node_tag_update_id(struct ID *id);
-void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
-void ED_node_sort(struct bNodeTree *ntree);
+
float ED_node_grid_size(void);
/* node_relationships.c */
+
+/**
+ * Test == 0, clear all intersect flags.
+ */
void ED_node_link_intersect_test(struct ScrArea *area, int test);
+/**
+ * Assumes link with #NODE_LINKFLAG_HILITE set.
+ */
void ED_node_link_insert(struct Main *bmain, struct ScrArea *area);
/* node_edit.c */
+
void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo);
bool ED_node_is_compositor(struct SpaceNode *snode);
bool ED_node_is_shader(struct SpaceNode *snode);
bool ED_node_is_texture(struct SpaceNode *snode);
bool ED_node_is_geometry(struct SpaceNode *snode);
+/**
+ * Assumes nothing being done in ntree yet, sets the default in/out node.
+ * Called from shading buttons or header.
+ */
void ED_node_shader_default(const struct bContext *C, struct ID *id);
+/**
+ * Assumes nothing being done in ntree yet, sets the default in/out node.
+ * Called from shading buttons or header.
+ */
void ED_node_composit_default(const struct bContext *C, struct Scene *scene);
+/**
+ * Assumes nothing being done in ntree yet, sets the default in/out node.
+ * Called from shading buttons or header.
+ */
void ED_node_texture_default(const struct bContext *C, struct Tex *tex);
-bool ED_node_select_check(const ListBase *lb);
-void ED_node_select_all(ListBase *lb, int action);
void ED_node_post_apply_transform(struct bContext *C, struct bNodeTree *ntree);
void ED_node_set_active(struct Main *bmain,
struct SpaceNode *snode,
@@ -121,19 +144,54 @@ void ED_node_set_active(struct Main *bmain,
struct bNode *node,
bool *r_active_texture_changed);
+/**
+ * Call after one or more node trees have been changed and tagged accordingly.
+ *
+ * This function will make sure that other parts of Blender update accordingly. For example, if the
+ * node group interface changed, parent node groups have to be updated as well.
+ *
+ * Additionally, this will send notifiers and tag the depsgraph based on the changes. Depsgraph
+ * relation updates have to be triggered by the caller.
+ *
+ * \param C: Context if available. This can be null.
+ * \param bmain: Main whose data-blocks should be updated based on the changes.
+ * \param ntree: Under some circumstances the caller knows that only one node tree has
+ * changed since the last update. In this case the function may be able to skip scanning #bmain
+ * for other things that have to be changed. It may still scan #bmain if the interface of the
+ * node tree has changed.
+ */
+void ED_node_tree_propagate_change(const struct bContext *C,
+ struct Main *bmain,
+ struct bNodeTree *ntree);
+
+/**
+ * \param scene_owner: is the owner of the job,
+ * we don't use it for anything else currently so could also be a void pointer,
+ * but for now keep it an 'Scene' for consistency.
+ *
+ * \note only call from spaces `refresh` callbacks, not direct! - use with care.
+ */
void ED_node_composite_job(const struct bContext *C,
struct bNodeTree *nodetree,
struct Scene *scene_owner);
/* node_ops.c */
+
void ED_operatormacros_node(void);
/* node_view.c */
+/**
+ * Returns mouse position in image space.
+ */
bool ED_space_node_get_position(struct Main *bmain,
struct SpaceNode *snode,
struct ARegion *region,
const int mval[2],
float fpos[2]);
+/**
+ * Returns color in linear space, matching #ED_space_image_color_sample().
+ * And here we've got recursion in the comments tips...
+ */
bool ED_space_node_color_sample(struct Main *bmain,
struct SpaceNode *snode,
struct ARegion *region,
diff --git a/source/blender/editors/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h
index d5685788ce1..9fd77fa858e 100644
--- a/source/blender/editors/include/ED_numinput.h
+++ b/source/blender/editors/include/ED_numinput.h
@@ -94,8 +94,14 @@ struct UnitSettings;
*/
void initNumInput(NumInput *n);
+/**
+ * \param str: Must be NUM_STR_REP_LEN * (idx_max + 1) length.
+ */
void outputNumInput(NumInput *n, char *str, struct UnitSettings *unit_settings);
bool hasNumInput(const NumInput *n);
+/**
+ * \warning \a vec must be set beforehand otherwise we risk uninitialized vars.
+ */
bool applyNumInput(NumInput *n, float *vec);
bool handleNumInput(struct bContext *C, NumInput *n, const struct wmEvent *event);
@@ -108,7 +114,7 @@ bool user_string_to_number(bContext *C,
const struct UnitSettings *unit,
int type,
double *r_value,
- const bool use_single_line_error,
+ bool use_single_line_error,
char **r_error);
/** \} */
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 5397cd95ace..805b48d9195 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -56,12 +56,24 @@ struct wmOperator;
struct wmOperatorType;
/* object_edit.c */
-/* context.object */
+
+/** `context.object` */
struct Object *ED_object_context(const struct bContext *C);
-/* context.object or context.active_object */
+/**
+ * Find the correct active object per context (`context.object` or `context.active_object`)
+ * \note context can be NULL when called from a enum with #PROP_ENUM_NO_CONTEXT.
+ */
struct Object *ED_object_active_context(const struct bContext *C);
void ED_collection_hide_menu_draw(const struct bContext *C, struct uiLayout *layout);
+/**
+ * Return an array of objects:
+ * - When in the property space, return the pinned or active object.
+ * - When in edit-mode/pose-mode, return an array of objects in the mode.
+ * - Otherwise return selected objects,
+ * the callers \a filter_fn needs to check of they are editable
+ * (assuming they need to be modified).
+ */
Object **ED_object_array_in_mode_or_selected(struct bContext *C,
bool (*filter_fn)(const struct Object *ob,
void *user_data),
@@ -70,17 +82,21 @@ Object **ED_object_array_in_mode_or_selected(struct bContext *C,
/* object_utils.c */
bool ED_object_calc_active_center_for_editmode(struct Object *obedit,
- const bool select_only,
+ bool select_only,
float r_center[3]);
bool ED_object_calc_active_center_for_posemode(struct Object *ob,
- const bool select_only,
+ bool select_only,
float r_center[3]);
-bool ED_object_calc_active_center(struct Object *ob, const bool select_only, float r_center[3]);
+bool ED_object_calc_active_center(struct Object *ob, bool select_only, float r_center[3]);
/* Object Data Container helper API. */
struct XFormObjectData_Container;
struct XFormObjectData_Container *ED_object_data_xform_container_create(void);
void ED_object_data_xform_container_destroy(struct XFormObjectData_Container *xds);
+/**
+ * This may be called multiple times with the same data.
+ * Each time, the original transformations are re-applied, instead of accumulating the changes.
+ */
void ED_object_data_xform_container_update_all(struct XFormObjectData_Container *xds,
struct Main *bmain,
struct Depsgraph *depsgraph);
@@ -122,12 +138,15 @@ void ED_object_xform_skip_child_container_item_ensure(struct XFormObjectSkipChil
struct Object *ob_parent_recurse,
int mode);
+void ED_object_xform_array_m4(struct Object **objects, uint objects_len, const float matrix[4][4]);
+
/* object_ops.c */
void ED_operatortypes_object(void);
void ED_operatormacros_object(void);
void ED_keymap_object(struct wmKeyConfig *keyconf);
/* object_relations.c */
+
typedef enum eParentType {
PAR_OBJECT,
PAR_ARMATURE,
@@ -161,25 +180,49 @@ extern struct EnumPropertyItem prop_clear_parent_types[];
extern struct EnumPropertyItem prop_make_parent_types[];
#endif
-/* Set the object's parent, return true if successful. */
+/**
+ * Set the object's parent, return true if successful.
+ */
bool ED_object_parent_set(struct ReportList *reports,
const struct bContext *C,
struct Scene *scene,
struct Object *const ob,
struct Object *const par,
int partype,
- const bool xmirror,
- const bool keep_transform,
+ bool xmirror,
+ bool keep_transform,
const int vert_par[3]);
-void ED_object_parent_clear(struct Object *ob, const int type);
+void ED_object_parent_clear(struct Object *ob, int type);
+/**
+ * Simple API for object selection, rather than just using the flag
+ * this takes into account the 'restrict selection in 3d view' flag.
+ * deselect works always, the restriction just prevents selection
+ *
+ * \note Caller must send a `NC_SCENE | ND_OB_SELECT` notifier
+ * (or a `NC_SCENE | ND_OB_VISIBLE` in case of visibility toggling).
+ */
void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode);
+/**
+ * Change active base, it includes the notifier
+ */
void ED_object_base_activate(struct bContext *C, struct Base *base);
void ED_object_base_activate_with_mode_exit_if_needed(struct bContext *C, struct Base *base);
+/**
+ * Call when the active base has changed.
+ */
void ED_object_base_active_refresh(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
+/**
+ * Remove base from a specific scene.
+ * \note now unlinks constraints as well.
+ */
void ED_object_base_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Object *ob);
+/**
+ * Remove base from a specific scene.
+ * `ob` must not be indirectly used.
+ */
void ED_object_base_free_and_unlink_no_indirect_check(struct Main *bmain,
struct Scene *scene,
struct Object *ob);
@@ -189,32 +232,44 @@ bool ED_object_base_deselect_all_ex(struct ViewLayer *view_layer,
bool *r_any_visible);
bool ED_object_base_deselect_all(struct ViewLayer *view_layer, struct View3D *v3d, int action);
-/* single object duplicate, if (dupflag == 0), fully linked, else it uses the flags given */
+/**
+ * Single object duplicate, if `dupflag == 0`, fully linked, else it uses the flags given.
+ * Leaves selection of base/object unaltered.
+ * \note don't call this within a loop since clear_* funcs loop over the entire database.
+ * \note caller must do `DAG_relations_tag_update(bmain);`
+ * this is not done automatic since we may duplicate many objects in a batch.
+ */
struct Base *ED_object_add_duplicate(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct Base *base,
- const eDupli_ID_Flags dupflag);
+ eDupli_ID_Flags dupflag);
-void ED_object_parent(struct Object *ob,
- struct Object *parent,
- const int type,
- const char *substr);
+void ED_object_parent(struct Object *ob, struct Object *parent, int type, const char *substr);
char *ED_object_ot_drop_named_material_tooltip(struct bContext *C,
struct PointerRNA *properties,
- const struct wmEvent *event);
+ const int mval[2]);
/* bitflags for enter/exit editmode */
enum {
EM_FREEDATA = (1 << 0),
EM_NO_CONTEXT = (1 << 1),
};
+/**
+ * \param flag:
+ * - If #EM_FREEDATA isn't in the flag, use ED_object_editmode_load directly.
+ */
bool ED_object_editmode_exit_ex(struct Main *bmain,
struct Scene *scene,
struct Object *obedit,
int flag);
bool ED_object_editmode_exit(struct bContext *C, int flag);
+/**
+ * Support freeing edit-mode data without flushing it back to the object.
+ *
+ * \return true if data was freed.
+ */
bool ED_object_editmode_free_ex(struct Main *bmain, struct Object *obedit);
bool ED_object_editmode_exit_multi_ex(struct Main *bmain,
@@ -265,7 +320,7 @@ void ED_object_sculptmode_enter_ex(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
- const bool force_dyntopo,
+ bool force_dyntopo,
struct ReportList *reports);
void ED_object_sculptmode_enter(struct bContext *C,
struct Depsgraph *depsgraph,
@@ -277,11 +332,15 @@ void ED_object_sculptmode_exit_ex(struct Main *bmain,
void ED_object_sculptmode_exit(struct bContext *C, struct Depsgraph *depsgraph);
void ED_object_location_from_view(struct bContext *C, float loc[3]);
-void ED_object_rotation_from_quat(float rot[3], const float quat[4], const char align_axis);
-void ED_object_rotation_from_view(struct bContext *C, float rot[3], const char align_axis);
+void ED_object_rotation_from_quat(float rot[3], const float quat[4], char align_axis);
+void ED_object_rotation_from_view(struct bContext *C, float rot[3], char align_axis);
void ED_object_base_init_transform_on_add(struct Object *object,
const float loc[3],
const float rot[3]);
+/**
+ * Uses context to figure out transform for primitive.
+ * Returns standard diameter.
+ */
float ED_object_new_primitive_matrix(struct bContext *C,
struct Object *obedit,
const float loc[3],
@@ -289,8 +348,9 @@ float ED_object_new_primitive_matrix(struct bContext *C,
const float scale[3],
float primmat[4][4]);
-/* Avoid allowing too much insane values even by typing
- * (typos can hang/crash Blender otherwise). */
+/**
+ * Avoid allowing too much insane values even by typing (typos can hang/crash Blender otherwise).
+ */
#define OBJECT_ADD_SIZE_MAXF 1.0e12f
void ED_object_add_unit_props_size(struct wmOperatorType *ot);
@@ -300,7 +360,7 @@ void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode);
void ED_object_add_mesh_props(struct wmOperatorType *ot);
bool ED_object_add_generic_get_opts(struct bContext *C,
struct wmOperator *op,
- const char view_align_axis,
+ char view_align_axis,
float r_loc[3],
float r_rot[3],
float r_scale[3],
@@ -308,26 +368,39 @@ bool ED_object_add_generic_get_opts(struct bContext *C,
unsigned short *r_local_view_bits,
bool *r_is_view_aligned);
+/**
+ * For object add primitive operators, or for object creation when `obdata != NULL`.
+ * \param obdata: Assigned to #Object.data, with increased user count.
+ *
+ * \note Do not call undo push in this function (users of this function have to).
+ */
struct Object *ED_object_add_type_with_obdata(struct bContext *C,
- const int type,
+ int type,
const char *name,
const float loc[3],
const float rot[3],
- const bool enter_editmode,
- const ushort local_view_bits,
+ bool enter_editmode,
+ ushort local_view_bits,
struct ID *obdata);
struct Object *ED_object_add_type(struct bContext *C,
- const int type,
+ int type,
const char *name,
const float loc[3],
const float rot[3],
- const bool enter_editmode,
- const unsigned short local_view_bits)
+ bool enter_editmode,
+ unsigned short local_view_bits)
ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
+/**
+ * Not an especially efficient function, only added so the single user button can be functional.
+ */
void ED_object_single_user(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* object motion paths */
+
+/**
+ * Clear motion paths for all objects.
+ */
void ED_objects_clear_paths(struct bContext *C, bool only_selected);
/* Corresponds to eAnimvizCalcRange. */
@@ -337,16 +410,46 @@ typedef enum eObjectPathCalcRange {
OBJECT_PATH_CALC_RANGE_FULL,
} eObjectPathCalcRange;
+/**
+ * For the objects with animation: update paths for those that have got them
+ * This should selectively update paths that exist.
+ *
+ * To be called from various tools that do incremental updates
+ */
void ED_objects_recalculate_paths(struct bContext *C,
struct Scene *scene,
- eObjectPathCalcRange range);
+ eObjectPathCalcRange range,
+ struct ListBase *ld_objects);
+
+void ED_objects_recalculate_paths_selected(struct bContext *C,
+ struct Scene *scene,
+ eObjectPathCalcRange range);
+
+void ED_objects_recalculate_paths_visible(struct bContext *C,
+ struct Scene *scene,
+ eObjectPathCalcRange range);
/* constraints */
+/**
+ * If object is in pose-mode, return active bone constraints, else object constraints.
+ * No constraints are returned for a bone on an inactive bone-layer.
+ */
struct ListBase *ED_object_constraint_active_list(struct Object *ob);
+/**
+ * Get the constraints for the active pose bone. Bone may be on an inactive bone-layer
+ * (unlike #ED_object_constraint_active_list, such constraints are not excluded here).
+ */
struct ListBase *ED_object_pose_constraint_list(const struct bContext *C);
+/**
+ * Find the list that a given constraint belongs to,
+ * and/or also get the posechannel this is from (if applicable).
+ */
struct ListBase *ED_object_constraint_list_from_constraint(struct Object *ob,
struct bConstraint *con,
struct bPoseChannel **r_pchan);
+/**
+ * Single constraint.
+ */
struct bConstraint *ED_object_constraint_active_get(struct Object *ob);
void object_test_constraints(struct Main *bmain, struct Object *ob);
@@ -362,9 +465,7 @@ void ED_object_constraint_dependency_tag_update(struct Main *bmain,
struct Object *ob,
struct bConstraint *con);
-bool ED_object_constraint_move_to_index(struct Object *ob,
- struct bConstraint *con,
- const int index);
+bool ED_object_constraint_move_to_index(struct Object *ob, struct bConstraint *con, int index);
void ED_object_constraint_link(struct Main *bmain,
struct Object *ob_dst,
struct ListBase *dst,
@@ -378,7 +479,17 @@ void ED_object_constraint_copy_for_pose(struct Main *bmain,
struct bConstraint *con);
/* object_modes.c */
+
+/**
+ * Checks the mode to be set is compatible with the object
+ * should be made into a generic function
+ */
bool ED_object_mode_compat_test(const struct Object *ob, eObjectMode mode);
+/**
+ * Sets the mode to a compatible state (use before entering the mode).
+ *
+ * This is so each mode's exec function can call
+ */
bool ED_object_mode_compat_set(struct bContext *C,
struct Object *ob,
eObjectMode mode,
@@ -398,14 +509,21 @@ bool ED_object_mode_generic_has_data(struct Depsgraph *depsgraph, const struct O
void ED_object_posemode_set_for_weight_paint(struct bContext *C,
struct Main *bmain,
struct Object *ob,
- const bool is_mode_set);
+ bool is_mode_set);
/* object_modifier.c */
+
enum {
MODIFIER_APPLY_DATA = 1,
MODIFIER_APPLY_SHAPE,
};
+/**
+ * Add a modifier to given object, including relevant extra processing needed by some physics types
+ * (particles, simulations...).
+ *
+ * \param scene: is only used to set current frame in some cases, and may be NULL.
+ */
struct ModifierData *ED_object_modifier_add(struct ReportList *reports,
struct Main *bmain,
struct Scene *scene,
@@ -427,7 +545,7 @@ bool ED_object_modifier_move_up(struct ReportList *reports,
bool ED_object_modifier_move_to_index(struct ReportList *reports,
struct Object *ob,
struct ModifierData *md,
- const int index);
+ int index);
bool ED_object_modifier_convert(struct ReportList *reports,
struct Main *bmain,
@@ -454,12 +572,25 @@ void ED_object_modifier_copy_to_object(struct bContext *C,
struct Object *ob_src,
struct ModifierData *md);
+/**
+ * If the object data of 'orig_ob' has other users, run 'callback' on
+ * each of them.
+ *
+ * If include_orig is true, the callback will run on 'orig_ob' too.
+ *
+ * If the callback ever returns true, iteration will stop and the
+ * function value will be true. Otherwise the function returns false.
+ */
bool ED_object_iter_other(struct Main *bmain,
struct Object *orig_ob,
- const bool include_orig,
+ bool include_orig,
bool (*callback)(struct Object *ob, void *callback_data),
void *callback_data);
+/**
+ * Use with #ED_object_iter_other(). Sets the total number of levels
+ * for any multi-res modifiers on the object to the int pointed to by callback_data.
+ */
bool ED_object_multires_update_totlevels_cb(struct Object *ob, void *totlevel_v);
/* object_greasepencil_modifier.c */
@@ -483,7 +614,7 @@ bool ED_object_gpencil_modifier_move_up(struct ReportList *reports,
bool ED_object_gpencil_modifier_move_to_index(struct ReportList *reports,
struct Object *ob,
struct GpencilModifierData *md,
- const int index);
+ int index);
bool ED_object_gpencil_modifier_apply(struct Main *bmain,
struct ReportList *reports,
struct Depsgraph *depsgraph,
@@ -517,7 +648,7 @@ int ED_object_shaderfx_move_up(struct ReportList *reports,
bool ED_object_shaderfx_move_to_index(struct ReportList *reports,
struct Object *ob,
struct ShaderFxData *fx,
- const int index);
+ int index);
void ED_object_shaderfx_link(struct Object *dst, struct Object *src);
void ED_object_shaderfx_copy(struct Object *dst, struct ShaderFxData *fx);
@@ -529,22 +660,46 @@ const struct EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free,
- const unsigned int selection_mask);
+ unsigned int selection_mask);
void ED_object_check_force_modifiers(struct Main *bmain,
struct Scene *scene,
struct Object *object);
+/**
+ * If id is not already an Object, try to find an object that uses it as data.
+ * Prefers active, then selected, then visible/selectable.
+ */
struct Base *ED_object_find_first_by_data_id(struct ViewLayer *view_layer, struct ID *id);
-bool ED_object_jump_to_object(struct bContext *C, struct Object *ob, const bool reveal_hidden);
+/**
+ * Select and make the target object active in the view layer.
+ * If already selected, selection isn't changed.
+ *
+ * \returns false if not found in current view layer
+ */
+bool ED_object_jump_to_object(struct bContext *C, struct Object *ob, bool reveal_hidden);
+/**
+ * Select and make the target object and bone active.
+ * Switches to Pose mode if in Object mode so the selection is visible.
+ * Un-hides the target bone and bone layer if necessary.
+ *
+ * \returns false if object not in layer, bone not found, or other error
+ */
bool ED_object_jump_to_bone(struct bContext *C,
struct Object *ob,
const char *bone_name,
- const bool reveal_hidden);
+ bool reveal_hidden);
/* object_facemap_ops.c */
+
+/**
+ * Called while not in edit-mode.
+ */
void ED_object_facemap_face_add(struct Object *ob, struct bFaceMap *fmap, int facenum);
+/**
+ * Called while not in edit-mode.
+ */
void ED_object_facemap_face_remove(struct Object *ob, struct bFaceMap *fmap, int facenum);
/* object_data_transform.c */
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
index 1d1471f0be6..99f65010595 100644
--- a/source/blender/editors/include/ED_outliner.h
+++ b/source/blender/editors/include/ED_outliner.h
@@ -33,10 +33,21 @@ struct bContext;
bool ED_outliner_collections_editor_poll(struct bContext *C);
+/**
+ * Populates the \param objects: ListBase with all the outliner selected objects
+ * We store it as (Object *)LinkData->data
+ * \param objects: expected to be empty
+ */
void ED_outliner_selected_objects_get(const struct bContext *C, struct ListBase *objects);
+/**
+ * Get base of object under cursor. Used for eyedropper tool.
+ */
struct Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]);
+/**
+ * Functions for tagging outliner selection syncing is dirty from operators.
+ */
void ED_outliner_select_sync_from_object_tag(struct bContext *C);
void ED_outliner_select_sync_from_edit_bone_tag(struct bContext *C);
void ED_outliner_select_sync_from_pose_bone_tag(struct bContext *C);
@@ -45,9 +56,15 @@ void ED_outliner_select_sync_from_all_tag(struct bContext *C);
bool ED_outliner_select_sync_is_dirty(const struct bContext *C);
+/**
+ * Set clean outliner and mark other outliners for syncing.
+ */
void ED_outliner_select_sync_from_outliner(struct bContext *C,
struct SpaceOutliner *space_outliner);
+/**
+ * Copy sync select dirty flag from window manager to all outliners to be synced lazily on draw.
+ */
void ED_outliner_select_sync_flag_outliners(const struct bContext *C);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index 6a28baa4ca1..1d1ba264de5 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -54,11 +54,21 @@ void ED_imapaint_bucket_fill(struct bContext *C,
const int mouse[2]);
/* paint_image_proj.c */
+
void ED_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool tex, bool stencil);
+/**
+ * Make sure that active object has a material,
+ * and assign UVs and image layers if they do not exist.
+ */
bool ED_paint_proj_mesh_data_check(
struct Scene *scene, struct Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil);
/* image_undo.c */
+
+/**
+ * The caller is responsible for running #ED_image_undo_push_end,
+ * failure to do so causes an invalid state for the undo system.
+ */
void ED_image_undo_push_begin(const char *name, int paint_mode);
void ED_image_undo_push_begin_with_image(const char *name,
struct Image *image,
@@ -66,8 +76,12 @@ void ED_image_undo_push_begin_with_image(const char *name,
struct ImageUser *iuser);
void ED_image_undo_push_end(void);
+/**
+ * Restore painting image to previous state. Used for anchored and drag-dot style brushes.
+ */
void ED_image_undo_restore(struct UndoStep *us);
+/** Export for ED_undo_sys. */
void ED_image_undosys_type(struct UndoType *ut);
void *ED_image_paint_tile_find(struct ListBase *paint_tiles,
@@ -100,9 +114,11 @@ struct ListBase *ED_image_paint_tile_list_get(void);
(((size) + ED_IMAGE_UNDO_TILE_SIZE - 1) >> ED_IMAGE_UNDO_TILE_BITS)
/* paint_curve_undo.c */
+
void ED_paintcurve_undo_push_begin(const char *name);
void ED_paintcurve_undo_push_end(struct bContext *C);
+/** Export for ED_undo_sys. */
void ED_paintcurve_undosys_type(struct UndoType *ut);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index 5318c653b6d..9671f5b2b09 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -39,10 +39,12 @@ struct rcti;
struct wmGenericUserData;
/* particle edit mode */
+
void PE_free_ptcache_edit(struct PTCacheEdit *edit);
int PE_start_edit(struct PTCacheEdit *edit);
/* access */
+
struct PTCacheEdit *PE_get_current_from_psys(struct ParticleSystem *psys);
struct PTCacheEdit *PE_get_current(struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -59,6 +61,7 @@ int PE_minmax(struct Depsgraph *depsgraph,
struct ParticleEditSettings *PE_settings(struct Scene *scene);
/* update calls */
+
void PE_hide_keys_time(struct Scene *scene, struct PTCacheEdit *edit, float cfra);
void PE_update_object(struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -66,22 +69,22 @@ void PE_update_object(struct Depsgraph *depsgraph,
int useflag);
/* selection tools */
+
bool PE_mouse_particles(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
-bool PE_box_select(struct bContext *C, const struct rcti *rect, const int sel_op);
+bool PE_box_select(struct bContext *C, const struct rcti *rect, int sel_op);
bool PE_circle_select(struct bContext *C,
struct wmGenericUserData *wm_userdata,
- const int sel_op,
+ int sel_op,
const int mval[2],
float rad);
-int PE_lasso_select(struct bContext *C,
- const int mcoords[][2],
- const int mcoords_len,
- const int sel_op);
+int PE_lasso_select(struct bContext *C, const int mcoords[][2], int mcoords_len, int sel_op);
bool PE_deselect_all_visible_ex(struct PTCacheEdit *edit);
bool PE_deselect_all_visible(struct bContext *C);
/* particle_edit_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_particle_undosys_type(struct UndoType *ut);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index 5cdcbbab42a..dabf8fb838b 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -23,6 +23,7 @@
#pragma once
+#include "DNA_ID_enums.h"
#include "DNA_vec_types.h"
#ifdef __cplusplus
@@ -48,18 +49,25 @@ void ED_operatortypes_render(void);
/* render_update.c */
-void ED_render_engine_changed(struct Main *bmain, const bool update_scene_data);
+void ED_render_engine_changed(struct Main *bmain, bool update_scene_data);
void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *area);
void ED_render_view_layer_changed(struct Main *bmain, struct bScreen *screen);
/* Callbacks handling data update events coming from depsgraph. */
void ED_render_id_flush_update(const struct DEGEditorUpdateContext *update_ctx, struct ID *id);
-void ED_render_scene_update(const struct DEGEditorUpdateContext *update_ctx, const bool updated);
+/**
+ * Update all 3D viewport render and draw engines on changes to the scene.
+ * This is called by the dependency graph when it detects changes.
+ */
+void ED_render_scene_update(const struct DEGEditorUpdateContext *update_ctx, bool updated);
+/**
+ * Update 3D viewport render or draw engine on changes to the scene or view settings.
+ */
void ED_render_view3d_update(struct Depsgraph *depsgraph,
struct wmWindow *window,
struct ScrArea *area,
- const bool updated);
+ bool updated);
struct Scene *ED_render_job_get_scene(const struct bContext *C);
struct Scene *ED_render_job_get_current_scene(const struct bContext *C);
@@ -69,19 +77,22 @@ struct Scene *ED_render_job_get_current_scene(const struct bContext *C);
* pr_method:
* - PR_BUTS_RENDER: preview is rendered for buttons window
* - PR_ICON_RENDER: preview is rendered for icons. hopefully fast enough for at least 32x32
- * - PR_NODE_RENDER: preview is rendered for node editor
* - PR_ICON_DEFERRED: No render, we just ensure deferred icon data gets generated.
*/
typedef enum ePreviewRenderMethod {
PR_BUTS_RENDER = 0,
PR_ICON_RENDER = 1,
- PR_NODE_RENDER = 2,
- PR_ICON_DEFERRED = 3,
+ PR_ICON_DEFERRED = 2,
} ePreviewRenderMethod;
void ED_preview_ensure_dbase(void);
void ED_preview_free_dbase(void);
+/**
+ * Check if \a id is supported by the automatic preview render.
+ */
+bool ED_preview_id_is_supported(const struct ID *id);
+
void ED_preview_shader_job(const struct bContext *C,
void *owner,
struct ID *id,
@@ -89,7 +100,7 @@ void ED_preview_shader_job(const struct bContext *C,
struct MTex *slot,
int sizex,
int sizey,
- int method);
+ ePreviewRenderMethod method);
void ED_preview_icon_render(const struct bContext *C,
struct Scene *scene,
struct ID *id,
@@ -102,7 +113,12 @@ void ED_preview_icon_job(const struct bContext *C,
unsigned int *rect,
int sizex,
int sizey,
- const bool delay);
+ bool delay);
+
+void ED_preview_restart_queue_free(void);
+void ED_preview_restart_queue_add(struct ID *id, enum eIconSizes size);
+void ED_preview_restart_queue_work(const struct bContext *C);
+
void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain);
void ED_preview_draw(const struct bContext *C, void *idp, void *parentp, void *slot, rcti *rect);
diff --git a/source/blender/editors/include/ED_scene.h b/source/blender/editors/include/ED_scene.h
index e3abd26a4cd..e4e7a4bdfce 100644
--- a/source/blender/editors/include/ED_scene.h
+++ b/source/blender/editors/include/ED_scene.h
@@ -32,7 +32,14 @@ struct Scene *ED_scene_add(struct Main *bmain,
struct bContext *C,
struct wmWindow *win,
enum eSceneCopyMethod method) ATTR_NONNULL();
+/**
+ * \note Only call outside of area/region loops.
+ * \return true if successful.
+ */
bool ED_scene_delete(struct bContext *C, struct Main *bmain, struct Scene *scene) ATTR_NONNULL();
+/**
+ * Depsgraph updates after scene becomes active in a window.
+ */
void ED_scene_change_update(struct Main *bmain, struct Scene *scene, struct ViewLayer *layer)
ATTR_NONNULL();
bool ED_scene_view_layer_delete(struct Main *bmain,
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 60ef3e740c6..651ae1de8be 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -31,6 +31,8 @@
#include "DNA_object_enums.h"
+#include "WM_types.h"
+
#include "BLI_compiler_attrs.h"
#ifdef __cplusplus
@@ -63,33 +65,65 @@ struct wmWindow;
struct wmWindowManager;
/* regions */
+/** Only exported for WM. */
void ED_region_do_listen(struct wmRegionListenerParams *params);
+/** Only exported for WM. */
void ED_region_do_layout(struct bContext *C, struct ARegion *region);
+/** Only exported for WM. */
void ED_region_do_draw(struct bContext *C, struct ARegion *region);
void ED_region_exit(struct bContext *C, struct ARegion *region);
+/**
+ * Utility to exit and free an area-region. Screen level regions (menus/popups) need to be treated
+ * slightly differently, see #ui_region_temp_remove().
+ */
void ED_region_remove(struct bContext *C, struct ScrArea *area, struct ARegion *region);
-void ED_region_pixelspace(struct ARegion *region);
+void ED_region_pixelspace(const struct ARegion *region);
+/**
+ * Call to move a popup window (keep OpenGL context free!)
+ */
void ED_region_update_rect(struct ARegion *region);
+/**
+ * Externally called for floating regions like menus.
+ */
void ED_region_floating_init(struct ARegion *region);
void ED_region_tag_redraw(struct ARegion *region);
void ED_region_tag_redraw_partial(struct ARegion *region, const struct rcti *rct, bool rebuild);
void ED_region_tag_redraw_cursor(struct ARegion *region);
void ED_region_tag_redraw_no_rebuild(struct ARegion *region);
void ED_region_tag_refresh_ui(struct ARegion *region);
+/**
+ * Tag editor overlays to be redrawn. If in doubt about which parts need to be redrawn (partial
+ * clipping rectangle set), redraw everything.
+ */
void ED_region_tag_redraw_editor_overlays(struct ARegion *region);
+/**
+ * Set the temporary update flag for property search.
+ */
void ED_region_search_filter_update(const struct ScrArea *area, struct ARegion *region);
+/**
+ * Returns the search string if the space type and region type support property search.
+ */
const char *ED_area_region_search_filter_get(const struct ScrArea *area,
const struct ARegion *region);
void ED_region_panels_init(struct wmWindowManager *wm, struct ARegion *region);
void ED_region_panels_ex(const struct bContext *C, struct ARegion *region, const char *contexts[]);
void ED_region_panels(const struct bContext *C, struct ARegion *region);
+/**
+ * \param contexts: A NULL terminated array of context strings to match against.
+ * Matching against any of these strings will draw the panel.
+ * Can be NULL to skip context checks.
+ */
void ED_region_panels_layout_ex(const struct bContext *C,
struct ARegion *region,
struct ListBase *paneltypes,
const char *contexts[],
const char *category_override);
+/**
+ * Build the same panel list as #ED_region_panels_layout_ex and checks whether any
+ * of the panels contain a search result based on the area / region's search filter.
+ */
bool ED_region_property_search(const struct bContext *C,
struct ARegion *region,
struct ListBase *paneltypes,
@@ -105,11 +139,20 @@ void ED_region_header_layout(const struct bContext *C, struct ARegion *region);
void ED_region_header_draw(const struct bContext *C, struct ARegion *region);
void ED_region_cursor_set(struct wmWindow *win, struct ScrArea *area, struct ARegion *region);
+/**
+ * Exported to all editors, uses fading default.
+ */
void ED_region_toggle_hidden(struct bContext *C, struct ARegion *region);
+/**
+ * For use after changing visibility of regions.
+ */
void ED_region_visibility_change_update(struct bContext *C,
struct ScrArea *area,
struct ARegion *region);
/* screen_ops.c */
+/**
+ * \note Assumes that \a region itself is not a split version from previous region.
+ */
void ED_region_visibility_change_update_animated(struct bContext *C,
struct ScrArea *area,
struct ARegion *region);
@@ -117,16 +160,19 @@ void ED_region_visibility_change_update_animated(struct bContext *C,
void ED_region_info_draw(struct ARegion *region,
const char *text,
float fill_color[4],
- const bool full_redraw);
+ bool full_redraw);
void ED_region_info_draw_multiline(ARegion *region,
const char *text_array[],
float fill_color[4],
- const bool full_redraw);
+ bool full_redraw);
void ED_region_image_metadata_panel_draw(struct ImBuf *ibuf, struct uiLayout *layout);
void ED_region_grid_draw(struct ARegion *region, float zoomx, float zoomy, float x0, float y0);
float ED_region_blend_alpha(struct ARegion *region);
void ED_region_visible_rect_calc(struct ARegion *region, struct rcti *rect);
const rcti *ED_region_visible_rect(ARegion *region);
+/**
+ * Overlapping regions only in the following restricted cases.
+ */
bool ED_region_is_overlap(int spacetype, int regiontype);
int ED_region_snap_size_test(const struct ARegion *region);
@@ -140,44 +186,85 @@ void ED_area_do_msg_notify_tag_refresh(struct bContext *C,
struct wmMsgSubscribeKey *msg_key,
struct wmMsgSubscribeValue *msg_val);
+/**
+ * Follow #ARegionType.message_subscribe.
+ */
void ED_area_do_mgs_subscribe_for_tool_header(const struct wmRegionMessageSubscribeParams *params);
void ED_area_do_mgs_subscribe_for_tool_ui(const struct wmRegionMessageSubscribeParams *params);
/* message bus */
+
+/**
+ * Generate subscriptions for this region.
+ */
void ED_region_message_subscribe(struct wmRegionMessageSubscribeParams *params);
/* spaces */
+
+/**
+ * \note Keymap definitions are registered only once per WM initialize,
+ * usually on file read, using the keymap the actual areas/regions add the handlers.
+ * \note Called in wm.c. */
void ED_spacetypes_keymap(struct wmKeyConfig *keyconf);
+/**
+ * Returns offset for next button in header.
+ */
int ED_area_header_switchbutton(const struct bContext *C, struct uiBlock *block, int yco);
/* areas */
+/**
+ * Called in screen_refresh, or screens_init, also area size changes.
+ */
void ED_area_init(struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *area);
void ED_area_exit(struct bContext *C, struct ScrArea *area);
int ED_screen_area_active(const struct bContext *C);
void ED_screen_global_areas_refresh(struct wmWindow *win);
void ED_screen_global_areas_sync(struct wmWindow *win);
+/** Only exported for WM. */
void ED_area_do_listen(struct wmSpaceTypeListenerParams *params);
void ED_area_tag_redraw(ScrArea *area);
void ED_area_tag_redraw_no_rebuild(ScrArea *area);
void ED_area_tag_redraw_regiontype(ScrArea *area, int type);
void ED_area_tag_refresh(ScrArea *area);
+/**
+ * Only exported for WM.
+ */
void ED_area_do_refresh(struct bContext *C, ScrArea *area);
struct AZone *ED_area_azones_update(ScrArea *area, const int mouse_xy[2]);
+/**
+ * Use NULL to disable it.
+ */
void ED_area_status_text(ScrArea *area, const char *str);
-void ED_area_newspace(struct bContext *C, ScrArea *area, int type, const bool skip_region_exit);
+/**
+ * \param skip_region_exit: Skip calling area exit callback. Set for opening temp spaces.
+ */
+void ED_area_newspace(struct bContext *C, ScrArea *area, int type, bool skip_region_exit);
void ED_area_prevspace(struct bContext *C, ScrArea *area);
void ED_area_swapspace(struct bContext *C, ScrArea *sa1, ScrArea *sa2);
int ED_area_headersize(void);
int ED_area_footersize(void);
+/**
+ * \return the final height of a global \a area, accounting for DPI.
+ */
int ED_area_global_size_y(const ScrArea *area);
int ED_area_global_min_size_y(const ScrArea *area);
int ED_area_global_max_size_y(const ScrArea *area);
bool ED_area_is_global(const ScrArea *area);
+/**
+ * For now we just assume all global areas are made up out of horizontal bars
+ * with the same size. A fixed size could be stored in ARegion instead if needed.
+ *
+ * \return the DPI aware height of a single bar/region in global areas.
+ */
int ED_region_global_size_y(void);
void ED_area_update_region_sizes(struct wmWindowManager *wm,
struct wmWindow *win,
struct ScrArea *area);
bool ED_area_has_shared_border(struct ScrArea *a, struct ScrArea *b);
+ScrArea *ED_area_offscreen_create(struct wmWindow *win, eSpace_Type space_type);
+void ED_area_offscreen_free(struct wmWindowManager *wm,
+ struct wmWindow *win,
+ struct ScrArea *area);
ScrArea *ED_screen_areas_iter_first(const struct wmWindow *win, const bScreen *screen);
ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area);
@@ -198,28 +285,90 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area);
vert_name->next)
/* screens */
+
+/**
+ * File read, set all screens, ....
+ */
void ED_screens_init(struct Main *bmain, struct wmWindowManager *wm);
+/**
+ * Only for edge lines between areas.
+ */
void ED_screen_draw_edges(struct wmWindow *win);
+
+/**
+ * Make this screen usable.
+ * for file read and first use, for scaling window, area moves.
+ */
void ED_screen_refresh(struct wmWindowManager *wm, struct wmWindow *win);
void ED_screen_ensure_updated(struct wmWindowManager *wm,
struct wmWindow *win,
struct bScreen *screen);
void ED_screen_do_listen(struct bContext *C, struct wmNotifier *note);
+/**
+ * \brief Change the active screen.
+ *
+ * Operator call, WM + Window + screen already existed before
+ *
+ * \warning Do NOT call in area/region queues!
+ * \returns if screen changing was successful.
+ */
bool ED_screen_change(struct bContext *C, struct bScreen *screen);
-void ED_screen_scene_change(struct bContext *C, struct wmWindow *win, struct Scene *scene);
+void ED_screen_scene_change(struct bContext *C,
+ struct wmWindow *win,
+ struct Scene *scene,
+ bool refresh_toolsystem);
+/**
+ * Called in wm_event_system.c. sets state vars in screen, cursors.
+ * event type is mouse move.
+ */
void ED_screen_set_active_region(struct bContext *C, struct wmWindow *win, const int xy[2]);
void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen);
+/**
+ * redraws: uses defines from `stime->redraws`
+ * \param enable: 1 - forward on, -1 - backwards on, 0 - off.
+ */
void ED_screen_animation_timer(struct bContext *C, int redraws, int sync, int enable);
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws);
void ED_screen_restore_temp_type(struct bContext *C, ScrArea *area);
ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *area, int type);
+/**
+ * \a was_prev_temp for the case previous space was a temporary full-screen as well
+ */
void ED_screen_full_prevspace(struct bContext *C, ScrArea *area);
+/**
+ * Restore a screen / area back to default operation, after temp full-screen modes.
+ */
void ED_screen_full_restore(struct bContext *C, ScrArea *area);
+/**
+ * Create a new temporary screen with a maximized, empty area.
+ * This can be closed with #ED_screen_state_toggle().
+ *
+ * Use this to just create a new maximized screen/area, rather than maximizing an existing one.
+ * Otherwise, maximize with #ED_screen_state_toggle().
+ */
bScreen *ED_screen_state_maximized_create(struct bContext *C);
+/**
+ * This function toggles: if area is maximized/full then the parent will be restored.
+ *
+ * Use #ED_screen_state_maximized_create() if you do not want the toggle behavior when changing to
+ * a maximized area. I.e. if you just want to open a new maximized screen/area, not maximize a
+ * specific area. In the former case, space data of the maximized and non-maximized area should be
+ * independent, in the latter it should be the same.
+ *
+ * \warning \a area may be freed.
+ */
struct ScrArea *ED_screen_state_toggle(struct bContext *C,
struct wmWindow *win,
struct ScrArea *area,
- const short state);
+ short state);
+/**
+ * Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined
+ * by \a display_type.
+ *
+ * \param title: Title to set for the window, if a window is spawned.
+ * \param x, y: Position of the window, if a window is spawned.
+ * \param sizex, sizey: Dimensions of the window, if a window is spawned.
+ */
ScrArea *ED_screen_temp_space_open(struct bContext *C,
const char *title,
int x,
@@ -234,41 +383,81 @@ void ED_screens_footer_tools_menu_create(struct bContext *C, struct uiLayout *la
void ED_screens_navigation_bar_tools_menu_create(struct bContext *C,
struct uiLayout *layout,
void *arg);
+/**
+ * \return true if any active area requires to see in 3D.
+ */
bool ED_screen_stereo3d_required(const struct bScreen *screen, const struct Scene *scene);
Scene *ED_screen_scene_find(const struct bScreen *screen, const struct wmWindowManager *wm);
+/**
+ * Find the scene displayed in \a screen.
+ * \note Assumes \a screen to be visible/active!
+ */
Scene *ED_screen_scene_find_with_window(const struct bScreen *screen,
const struct wmWindowManager *wm,
struct wmWindow **r_window);
ScrArea *ED_screen_area_find_with_spacedata(const bScreen *screen,
const struct SpaceLink *sl,
- const bool only_visible);
+ bool only_visible);
struct wmWindow *ED_screen_window_find(const struct bScreen *screen,
const struct wmWindowManager *wm);
+/**
+ * Render the preview for a screen layout in \a screen.
+ */
void ED_screen_preview_render(const struct bScreen *screen,
int size_x,
int size_y,
unsigned int *r_rect) ATTR_NONNULL();
/* workspaces */
+
struct WorkSpace *ED_workspace_add(struct Main *bmain, const char *name) ATTR_NONNULL();
+/**
+ * \brief Change the active workspace.
+ *
+ * Operator call, WM + Window + screen already existed before
+ * Pretty similar to #ED_screen_change since changing workspace also changes screen.
+ *
+ * \warning Do NOT call in area/region queues!
+ * \returns if workspace changing was successful.
+ */
bool ED_workspace_change(struct WorkSpace *workspace_new,
struct bContext *C,
struct wmWindowManager *wm,
struct wmWindow *win) ATTR_NONNULL();
+/**
+ * Duplicate a workspace including its layouts. Does not activate the workspace, but
+ * it stores the screen-layout to be activated (BKE_workspace_temp_layout_store)
+ */
struct WorkSpace *ED_workspace_duplicate(struct WorkSpace *workspace_old,
struct Main *bmain,
struct wmWindow *win);
+/**
+ * \return if succeeded.
+ */
bool ED_workspace_delete(struct WorkSpace *workspace,
struct Main *bmain,
struct bContext *C,
struct wmWindowManager *wm) ATTR_NONNULL();
+/**
+ * Some editor data may need to be synced with scene data (3D View camera and layers).
+ * This function ensures data is synced for editors in active layout of \a workspace.
+ */
void ED_workspace_scene_data_sync(struct WorkSpaceInstanceHook *hook, Scene *scene) ATTR_NONNULL();
+/**
+ * Make sure there is a non-full-screen layout to switch to that isn't used yet by an other window.
+ * Needed for workspace or screen switching to ensure valid screens.
+ *
+ * \param layout_fallback_base: As last resort, this layout is duplicated and returned.
+ */
struct WorkSpaceLayout *ED_workspace_screen_change_ensure_unused_layout(
struct Main *bmain,
struct WorkSpace *workspace,
struct WorkSpaceLayout *layout_new,
const struct WorkSpaceLayout *layout_fallback_base,
struct wmWindow *win) ATTR_NONNULL();
+/**
+ * Empty screen, with 1 dummy area without space-data. Uses window size.
+ */
struct WorkSpaceLayout *ED_workspace_layout_add(struct Main *bmain,
struct WorkSpace *workspace,
struct wmWindow *win,
@@ -277,32 +466,55 @@ struct WorkSpaceLayout *ED_workspace_layout_duplicate(struct Main *bmain,
struct WorkSpace *workspace,
const struct WorkSpaceLayout *layout_old,
struct wmWindow *win) ATTR_NONNULL();
+/**
+ * \warning Only call outside of area/region loops!
+ * \return true if succeeded.
+ */
bool ED_workspace_layout_delete(struct WorkSpace *workspace,
struct WorkSpaceLayout *layout_old,
struct bContext *C) ATTR_NONNULL();
-bool ED_workspace_layout_cycle(struct WorkSpace *workspace,
- const short direction,
- struct bContext *C) ATTR_NONNULL();
+bool ED_workspace_layout_cycle(struct WorkSpace *workspace, short direction, struct bContext *C)
+ ATTR_NONNULL();
void ED_workspace_status_text(struct bContext *C, const char *str);
/* anim */
+/**
+ * Results in fully updated anim system.
+ */
void ED_update_for_newframe(struct Main *bmain, struct Depsgraph *depsgraph);
+/**
+ * Update frame rate info for viewport drawing.
+ */
void ED_refresh_viewport_fps(struct bContext *C);
+/**
+ * Toggle operator.
+ */
int ED_screen_animation_play(struct bContext *C, int sync, int mode);
+/**
+ * Find window that owns the animation timer.
+ */
bScreen *ED_screen_animation_playing(const struct wmWindowManager *wm);
bScreen *ED_screen_animation_no_scrub(const struct wmWindowManager *wm);
/* screen keymaps */
+/* called in spacetypes.c */
void ED_operatortypes_screen(void);
+/* called in spacetypes.c */
void ED_keymap_screen(struct wmKeyConfig *keyconf);
-/* workspace keymaps */
+/**
+ * Workspace key-maps.
+ */
void ED_operatortypes_workspace(void);
/* operators; context poll callbacks */
+
bool ED_operator_screenactive(struct bContext *C);
bool ED_operator_screenactive_nobackground(struct bContext *C);
+/**
+ * When mouse is over area-edge.
+ */
bool ED_operator_screen_mainwinactive(struct bContext *C);
bool ED_operator_areaactive(struct bContext *C);
bool ED_operator_regionactive(struct bContext *C);
@@ -310,13 +522,31 @@ bool ED_operator_regionactive(struct bContext *C);
bool ED_operator_scene(struct bContext *C);
bool ED_operator_scene_editable(struct bContext *C);
bool ED_operator_objectmode(struct bContext *C);
+/**
+ * Same as #ED_operator_objectmode() but additionally sets a "disabled hint". That is, a message
+ * to be displayed to the user explaining why the operator can't be used in current context.
+ */
+bool ED_operator_objectmode_poll_msg(struct bContext *C);
bool ED_operator_view3d_active(struct bContext *C);
bool ED_operator_region_view3d_active(struct bContext *C);
+/**
+ * Generic for any view2d which uses anim_ops.
+ */
bool ED_operator_animview_active(struct bContext *C);
bool ED_operator_outliner_active(struct bContext *C);
bool ED_operator_outliner_active_no_editobject(struct bContext *C);
+/**
+ * \note Will return true for file spaces in either file or asset browsing mode! See
+ * #ED_operator_file_browsing_active() (file browsing only) and
+ * #ED_operator_asset_browsing_active() (asset browsing only).
+ */
bool ED_operator_file_active(struct bContext *C);
+/**
+ * \note Will only return true if the file space is in file browsing mode, not asset browsing! See
+ * #ED_operator_file_active() (file or asset browsing) and
+ * #ED_operator_asset_browsing_active() (asset browsing only).
+ */
bool ED_operator_file_browsing_active(struct bContext *C);
bool ED_operator_asset_browsing_active(struct bContext *C);
bool ED_operator_spreadsheet_active(struct bContext *C);
@@ -335,6 +565,9 @@ bool ED_operator_console_active(struct bContext *C);
bool ED_operator_object_active(struct bContext *C);
bool ED_operator_object_active_editable_ex(struct bContext *C, const Object *ob);
bool ED_operator_object_active_editable(struct bContext *C);
+/**
+ * Object must be editable and fully local (i.e. not an override).
+ */
bool ED_operator_object_active_local_editable_ex(struct bContext *C, const Object *ob);
bool ED_operator_object_active_local_editable(struct bContext *C);
bool ED_operator_object_active_editable_mesh(struct bContext *C);
@@ -353,11 +586,21 @@ bool ED_operator_editsurfcurve_region_view3d(struct bContext *C);
bool ED_operator_editfont(struct bContext *C);
bool ED_operator_editlattice(struct bContext *C);
bool ED_operator_editmball(struct bContext *C);
+/**
+ * Wrapper for #ED_space_image_show_uvedit.
+ */
bool ED_operator_uvedit(struct bContext *C);
bool ED_operator_uvedit_space_image(struct bContext *C);
bool ED_operator_uvmap(struct bContext *C);
bool ED_operator_posemode_exclusive(struct bContext *C);
+/**
+ * Object must be editable, fully local (i.e. not an override), and exclusively in Pose mode.
+ */
bool ED_operator_object_active_local_editable_posemode_exclusive(struct bContext *C);
+/**
+ * Allows for pinned pose objects to be used in the object buttons
+ * and the non-active pose object to be used in the 3D view.
+ */
bool ED_operator_posemode_context(struct bContext *C);
bool ED_operator_posemode(struct bContext *C);
bool ED_operator_posemode_local(struct bContext *C);
@@ -372,7 +615,7 @@ struct bUserMenu *ED_screen_user_menu_ensure(struct bContext *C);
struct bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(struct ListBase *lb,
const struct wmOperatorType *ot,
struct IDProperty *prop,
- short opcontext);
+ wmOperatorCallContext opcontext);
struct bUserMenuItem_Menu *ED_screen_user_menu_item_find_menu(struct ListBase *lb,
const struct MenuType *mt);
struct bUserMenuItem_Prop *ED_screen_user_menu_item_find_prop(struct ListBase *lb,
@@ -384,7 +627,7 @@ void ED_screen_user_menu_item_add_operator(struct ListBase *lb,
const char *ui_name,
const struct wmOperatorType *ot,
const struct IDProperty *prop,
- short opcontext);
+ wmOperatorCallContext opcontext);
void ED_screen_user_menu_item_add_menu(struct ListBase *lb,
const char *ui_name,
const struct MenuType *mt);
@@ -400,44 +643,59 @@ void ED_screen_user_menu_register(void);
/* Cache display helpers */
void ED_region_cache_draw_background(struct ARegion *region);
-void ED_region_cache_draw_curfra_label(const int framenr, const float x, const float y);
-void ED_region_cache_draw_cached_segments(struct ARegion *region,
- const int num_segments,
- const int *points,
- const int sfra,
- const int efra);
+void ED_region_cache_draw_curfra_label(int framenr, float x, float y);
+void ED_region_cache_draw_cached_segments(
+ struct ARegion *region, int num_segments, const int *points, int sfra, int efra);
/* area_utils.c */
+
+/**
+ * Callback for #ARegionType.message_subscribe
+ */
void ED_region_generic_tools_region_message_subscribe(
const struct wmRegionMessageSubscribeParams *params);
+/**
+ * Callback for #ARegionType.snap_size
+ */
int ED_region_generic_tools_region_snap_size(const struct ARegion *region, int size, int axis);
/* area_query.c */
-bool ED_region_overlap_isect_x(const ARegion *region, const int event_x);
-bool ED_region_overlap_isect_y(const ARegion *region, const int event_y);
+bool ED_region_overlap_isect_x(const ARegion *region, int event_x);
+bool ED_region_overlap_isect_y(const ARegion *region, int event_y);
bool ED_region_overlap_isect_xy(const ARegion *region, const int event_xy[2]);
bool ED_region_overlap_isect_any_xy(const ScrArea *area, const int event_xy[2]);
-bool ED_region_overlap_isect_x_with_margin(const ARegion *region,
- const int event_x,
- const int margin);
-bool ED_region_overlap_isect_y_with_margin(const ARegion *region,
- const int event_y,
- const int margin);
+bool ED_region_overlap_isect_x_with_margin(const ARegion *region, int event_x, int margin);
+bool ED_region_overlap_isect_y_with_margin(const ARegion *region, int event_y, int margin);
bool ED_region_overlap_isect_xy_with_margin(const ARegion *region,
const int event_xy[2],
- const int margin);
+ int margin);
bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_region_gutter);
bool ED_region_panel_category_gutter_isect_xy(const ARegion *region, const int event_xy[2]);
+/**
+ * \note: This may return true for multiple overlapping regions.
+ * If it matters, check overlapped regions first (#ARegion.overlap).
+ */
bool ED_region_contains_xy(const struct ARegion *region, const int event_xy[2]);
+/**
+ * Similar to #BKE_area_find_region_xy() but when \a event_xy intersects an overlapping region,
+ * this returns the region that is visually under the cursor. E.g. when over the
+ * transparent part of the region, it returns the region underneath.
+ *
+ * The overlapping region is determined using the #ED_region_contains_xy() query.
+ */
+ARegion *ED_area_find_region_xy_visual(const ScrArea *area, int regiontype, const int event_xy[2]);
/* interface_region_hud.c */
+
struct ARegionType *ED_area_type_hud(int space_type);
void ED_area_type_hud_clear(struct wmWindowManager *wm, ScrArea *area_keep);
void ED_area_type_hud_ensure(struct bContext *C, struct ScrArea *area);
-/* default keymaps, bitflags (matches order of evaluation). */
+/**
+ * Default key-maps, bit-flags (matches order of evaluation).
+ */
enum {
ED_KEYMAP_UI = (1 << 1),
ED_KEYMAP_GIZMO = (1 << 2),
@@ -451,7 +709,7 @@ enum {
ED_KEYMAP_NAVBAR = (1 << 11),
};
-/* SCREEN_OT_space_context_cycle direction */
+/** #SCREEN_OT_space_context_cycle direction. */
typedef enum eScreenCycle {
SPACE_CONTEXT_CYCLE_PREV,
SPACE_CONTEXT_CYCLE_NEXT,
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 348ea503372..7c1124d705f 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -35,6 +35,7 @@ struct bContext;
struct rcti;
/* sculpt.c */
+
void ED_operatortypes_sculpt(void);
void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *region, struct Object *ob);
bool ED_sculpt_mask_box_select(struct bContext *C,
@@ -42,27 +43,31 @@ bool ED_sculpt_mask_box_select(struct bContext *C,
const struct rcti *rect,
bool select);
-/* transform */
+/* sculpt_transform.c */
+
void ED_sculpt_update_modal_transform(struct bContext *C, struct Object *ob);
void ED_sculpt_init_transform(struct bContext *C, struct Object *ob);
void ED_sculpt_end_transform(struct bContext *C, struct Object *ob);
/* sculpt_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_sculpt_undosys_type(struct UndoType *ut);
void ED_sculpt_undo_geometry_begin(struct Object *ob, const char *name);
void ED_sculpt_undo_geometry_end(struct Object *ob);
/* Face sets. */
+
int ED_sculpt_face_sets_find_next_available_id(struct Mesh *mesh);
-void ED_sculpt_face_sets_initialize_none_to_id(struct Mesh *mesh, const int new_id);
+void ED_sculpt_face_sets_initialize_none_to_id(struct Mesh *mesh, int new_id);
int ED_sculpt_face_sets_active_update_and_get(struct bContext *C,
struct Object *ob,
const float mval[2]);
/* Undo for changes happening on a base mesh for multires sculpting.
- * if there is no multires sculpt active regular undo is used. */
+ * if there is no multi-res sculpt active regular undo is used. */
void ED_sculpt_undo_push_multires_mesh_begin(struct bContext *C, const char *str);
void ED_sculpt_undo_push_multires_mesh_end(struct bContext *C, const char *str);
diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h
index 049ea7a092f..295268c7719 100644
--- a/source/blender/editors/include/ED_select_utils.h
+++ b/source/blender/editors/include/ED_select_utils.h
@@ -60,19 +60,29 @@ enum {
#define SEL_OP_USE_PRE_DESELECT(sel_op) (ELEM(sel_op, SEL_OP_SET))
#define SEL_OP_CAN_DESELECT(sel_op) (!ELEM(sel_op, SEL_OP_ADD))
-/* Use when we've de-selected all first for 'SEL_OP_SET' */
-int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside);
-int ED_select_op_action_deselected(const eSelectOp sel_op,
- const bool is_select,
- const bool is_inside);
+/**
+ * Use when we've de-selected all first for 'SEL_OP_SET'.
+ * 1: select, 0: deselect, -1: pass.
+ */
+int ED_select_op_action(eSelectOp sel_op, bool is_select, bool is_inside);
+/**
+ * Use when we've de-selected all items first (for modes that need it).
+ *
+ * \note In some cases changing selection needs to perform other checks,
+ * so it's more straightforward to deselect all, then select.
+ */
+int ED_select_op_action_deselected(eSelectOp sel_op, bool is_select, bool is_inside);
-int ED_select_similar_compare_float(const float delta, const float thresh, const int compare);
+int ED_select_similar_compare_float(float delta, float thresh, int compare);
bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree,
- const float length,
- const float thresh,
- const int compare);
+ float length,
+ float thresh,
+ int compare);
-eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first);
+/**
+ * Utility to use for selection operations that run multiple times (circle select).
+ */
+eSelectOp ED_select_op_modal(eSelectOp sel_op, bool is_first);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_sequencer.h b/source/blender/editors/include/ED_sequencer.h
index 606b4c9cad0..843b94cea00 100644
--- a/source/blender/editors/include/ED_sequencer.h
+++ b/source/blender/editors/include/ED_sequencer.h
@@ -40,8 +40,18 @@ bool ED_space_sequencer_maskedit_mask_poll(struct bContext *C);
bool ED_space_sequencer_check_show_maskedit(struct SpaceSeq *sseq, struct Scene *scene);
bool ED_space_sequencer_maskedit_poll(struct bContext *C);
+/**
+ * Are we displaying the seq output (not channels or histogram).
+ */
bool ED_space_sequencer_check_show_imbuf(struct SpaceSeq *sseq);
+
bool ED_space_sequencer_check_show_strip(struct SpaceSeq *sseq);
+/**
+ * Check if there is animation shown during playback.
+ *
+ * - Colors of color strips are displayed on the strip itself.
+ * - Backdrop is drawn.
+ */
bool ED_space_sequencer_has_playback_animation(const struct SpaceSeq *sseq,
const struct Scene *scene);
diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h
index 1a3aa7e5496..fb76b36baef 100644
--- a/source/blender/editors/include/ED_space_api.h
+++ b/source/blender/editors/include/ED_space_api.h
@@ -30,12 +30,18 @@ extern "C" {
struct ARegionType;
struct bContext;
+/* Only called once on startup. storage is global in BKE kernel listbase. */
void ED_spacetypes_init(void);
void ED_spacemacros_init(void);
/* the pluginnable API for export to editors */
-/* calls for registering default spaces */
+/* -------------------------------------------------------------------- */
+/** \name Calls for registering default spaces
+ *
+ * Calls for registering default spaces, only called once, from #ED_spacetypes_init
+ * \{ */
+
void ED_spacetype_outliner(void);
void ED_spacetype_view3d(void);
void ED_spacetype_ipo(void);
@@ -57,12 +63,18 @@ void ED_spacetype_statusbar(void);
void ED_spacetype_topbar(void);
void ED_spacetype_spreadsheet(void);
-/* calls for instancing and freeing spacetype static data
- * called in WM_init_exit */
-/* in space_file.c */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Spacetype Static Data
+ * Calls for instancing and freeing space-type static data called in #WM_init_exit
+ * \{ */
+
void ED_file_init(void);
void ED_file_exit(void);
+/** \} */
+
#define REGION_DRAW_POST_VIEW 0
#define REGION_DRAW_POST_PIXEL 1
#define REGION_DRAW_PRE_VIEW 2
@@ -72,8 +84,9 @@ void *ED_region_draw_cb_activate(struct ARegionType *art,
void (*draw)(const struct bContext *, struct ARegion *, void *),
void *customdata,
int type);
-void ED_region_draw_cb_draw(const struct bContext *, struct ARegion *, int);
-void ED_region_draw_cb_exit(struct ARegionType *, void *);
+void ED_region_draw_cb_draw(const struct bContext *C, struct ARegion *region, int type);
+void ED_region_surface_draw_cb_draw(struct ARegionType *art, int type);
+bool ED_region_draw_cb_exit(struct ARegionType *art, void *handle);
void ED_region_draw_cb_remove_by_type(struct ARegionType *art,
void *draw_fn,
void (*free)(void *));
diff --git a/source/blender/editors/include/ED_text.h b/source/blender/editors/include/ED_text.h
index 6e012ec1a91..33ca3ea03a6 100644
--- a/source/blender/editors/include/ED_text.h
+++ b/source/blender/editors/include/ED_text.h
@@ -36,16 +36,25 @@ struct bContext;
bool ED_text_activate_in_screen(struct bContext *C, struct Text *text);
+/**
+ * Moves the view to the cursor location, also used to make sure the view isn't outside the file.
+ */
void ED_text_scroll_to_cursor(struct SpaceText *st, struct ARegion *region, bool center);
+/**
+ * Takes a cursor (row, character) and returns x,y pixel coords.
+ */
bool ED_text_region_location_from_cursor(struct SpaceText *st,
struct ARegion *region,
const int cursor_co[2],
int r_pixel_co[2]);
/* text_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_text_undosys_type(struct UndoType *ut);
+/** Use operator system to finish the undo step. */
struct UndoStep *ED_text_undo_push_init(struct bContext *C);
/* text_format.c */
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index bedd0e2fa35..573f9b4939b 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -54,7 +54,8 @@ typedef enum {
TFM_TILT,
TFM_TRACKBALL,
TFM_PUSHPULL,
- TFM_CREASE,
+ TFM_EDGE_CREASE,
+ TFM_VERT_CREASE,
TFM_MIRROR,
TFM_BONESIZE,
TFM_BONE_ENVELOPE,
@@ -104,16 +105,16 @@ void BIF_removeTransformOrientationIndex(struct bContext *C, int index);
bool BIF_createTransformOrientation(struct bContext *C,
struct ReportList *reports,
const char *name,
- const bool use_view,
- const bool activate,
- const bool overwrite);
+ bool use_view,
+ bool activate,
+ bool overwrite);
void BIF_selectTransformOrientation(struct bContext *C, struct TransformOrientation *target);
void ED_getTransformOrientationMatrix(struct ViewLayer *view_layer,
const struct View3D *v3d,
struct Object *ob,
struct Object *obedit,
- const short around,
+ short around,
float r_orientation_mat[3][3]);
int BIF_countTransformOrientation(const struct bContext *C);
@@ -146,19 +147,31 @@ void Transform_Properties(struct wmOperatorType *ot, int flags);
/* *** transform_orientations.c *** */
void ED_transform_calc_orientation_from_type(const struct bContext *C, float r_mat[3][3]);
+/**
+ * \note The resulting matrix may not be orthogonal,
+ * callers that depend on `r_mat` to be orthogonal should use #orthogonalize_m3.
+ *
+ * A non orthogonal matrix may be returned when:
+ * - #V3D_ORIENT_GIMBAL the result won't be orthogonal unless the object has no rotation.
+ * - #V3D_ORIENT_LOCAL may contain shear from non-uniform scale in parent/child relationships.
+ * - #V3D_ORIENT_CUSTOM may have been created from #V3D_ORIENT_LOCAL.
+ */
short ED_transform_calc_orientation_from_type_ex(const struct Scene *scene,
struct ViewLayer *view_layer,
const struct View3D *v3d,
const struct RegionView3D *rv3d,
struct Object *ob,
struct Object *obedit,
- const short orientation_index,
- const int pivot_point,
+ short orientation_index,
+ int pivot_point,
float r_mat[3][3]);
/* transform gizmos */
void VIEW3D_GGT_xform_gizmo(struct wmGizmoGroupType *gzgt);
+/**
+ * Only poll, flag & gzmap_params differ.
+ */
void VIEW3D_GGT_xform_gizmo_context(struct wmGizmoGroupType *gzgt);
void VIEW3D_GGT_xform_cage(struct wmGizmoGroupType *gzgt);
void VIEW3D_GGT_xform_shear(struct wmGizmoGroupType *gzgt);
@@ -176,11 +189,18 @@ void ED_widgetgroup_gizmo2d_rotate_callbacks_set(struct wmGizmoGroupType *gzgt);
struct TransformBounds {
float center[3]; /* Center for transform widget. */
- float min[3], max[3]; /* Boundbox of selection for transform widget. */
+ float min[3], max[3]; /* Bounding-box of selection for transform widget. */
/* Normalized axis */
float axis[3][3];
float axis_min[3], axis_max[3];
+
+ /**
+ * When #TransformCalcParams.use_local_axis is used.
+ * This is the local space matrix the caller may need to access.
+ */
+ bool use_matrix_space;
+ float matrix_space[4][4];
};
struct TransformCalcParams {
@@ -189,6 +209,11 @@ struct TransformCalcParams {
/* Use 'Scene.orientation_type' when zero, otherwise subtract one and use. */
ushort orientation_index;
};
+/**
+ * Centroid, bound-box, of selection.
+ *
+ * Returns total items selected.
+ */
int ED_transform_calc_gizmo_stats(const struct bContext *C,
const struct TransformCalcParams *params,
struct TransformBounds *tbounds);
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index 42e73bbf744..fd65d8f3663 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -44,6 +44,7 @@ typedef enum {
SNAP_NOT_SELECTED = 1,
SNAP_NOT_ACTIVE = 2,
SNAP_ONLY_ACTIVE = 3,
+ SNAP_SELECTABLE = 4,
} eSnapSelect;
typedef enum {
@@ -83,11 +84,6 @@ struct SnapObjectParams {
typedef struct SnapObjectContext SnapObjectContext;
SnapObjectContext *ED_transform_snap_object_context_create(struct Scene *scene, int flag);
-SnapObjectContext *ED_transform_snap_object_context_create_view3d(struct Scene *scene,
- int flag,
- /* extra args for view3d */
- const struct ARegion *region,
- const struct View3D *v3d);
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx);
/* callbacks to filter how snap works */
@@ -100,6 +96,7 @@ void ED_transform_snap_object_context_set_editmesh_callbacks(
bool ED_transform_snap_object_project_ray_ex(struct SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
+ const View3D *v3d,
const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_normal[3],
@@ -112,6 +109,7 @@ bool ED_transform_snap_object_project_ray_ex(struct SnapObjectContext *sctx,
float r_obmat[4][4]);
bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
+ const View3D *v3d,
const struct SnapObjectParams *params,
const float ray_origin[3],
const float ray_direction[3],
@@ -119,8 +117,16 @@ bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
float r_co[3],
float r_no[3]);
+/**
+ * Fill in a list of all hits.
+ *
+ * \param ray_depth: Only depths in this range are considered, -1.0 for maximum.
+ * \param sort: Optionally sort the hits by depth.
+ * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
+ */
bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
+ const View3D *v3d,
const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_normal[3],
@@ -130,7 +136,9 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
- const unsigned short snap_to,
+ const ARegion *region,
+ const View3D *v3d,
+ unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2],
const float prev_co[3],
@@ -139,20 +147,41 @@ short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx,
float r_no[3],
int *r_index,
struct Object **r_ob,
- float r_obmat[4][4]);
-bool ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx,
- struct Depsgraph *depsgraph,
- const unsigned short snap_to,
- const struct SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3]);
-
+ float r_obmat[4][4],
+ float r_face_nor[3]);
+/**
+ * Convenience function for performing snapping.
+ *
+ * Given a 2D region value, snap to vert/edge/face.
+ *
+ * \param sctx: Snap context.
+ * \param mval: Screenspace coordinate.
+ * \param prev_co: Coordinate for perpendicular point calculation (optional).
+ * \param dist_px: Maximum distance to snap (in pixels).
+ * \param r_loc: hit location.
+ * \param r_no: hit normal (optional).
+ * \return Snap success.
+ */
+short ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx,
+ struct Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ unsigned short snap_to,
+ const struct SnapObjectParams *params,
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3]);
+
+/**
+ * see: #ED_transform_snap_object_project_ray_all
+ */
bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
const struct SnapObjectParams *params,
const float mval[2],
float ray_depth,
diff --git a/source/blender/editors/include/ED_transverts.h b/source/blender/editors/include/ED_transverts.h
index 28955da6ef1..cbcf28d53d5 100644
--- a/source/blender/editors/include/ED_transverts.h
+++ b/source/blender/editors/include/ED_transverts.h
@@ -42,7 +42,7 @@ typedef struct TransVertStore {
int mode;
} TransVertStore;
-void ED_transverts_create_from_obedit(TransVertStore *tvs, struct Object *obedit, const int mode);
+void ED_transverts_create_from_obedit(TransVertStore *tvs, struct Object *obedit, int mode);
void ED_transverts_update_obedit(TransVertStore *tvs, struct Object *obedit);
void ED_transverts_free(TransVertStore *tvs);
bool ED_transverts_check_obedit(Object *obedit);
diff --git a/source/blender/editors/include/ED_undo.h b/source/blender/editors/include/ED_undo.h
index 059277e1466..dceecc6aab5 100644
--- a/source/blender/editors/include/ED_undo.h
+++ b/source/blender/editors/include/ED_undo.h
@@ -36,6 +36,9 @@ struct wmOperator;
struct wmOperatorType;
/* undo.c */
+/**
+ * Run from the main event loop, basic checks that undo is left in a correct state.
+ */
bool ED_undo_is_state_valid(struct bContext *C);
void ED_undo_group_begin(struct bContext *C);
void ED_undo_group_end(struct bContext *C);
@@ -52,18 +55,38 @@ void ED_OT_redo(struct wmOperatorType *ot);
void ED_OT_undo_redo(struct wmOperatorType *ot);
void ED_OT_undo_history(struct wmOperatorType *ot);
+/**
+ * UI callbacks should call this rather than calling WM_operator_repeat() themselves.
+ */
int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op);
-/* Convenience since UI callbacks use this mostly. */
+/**
+ * Convenience since UI callbacks use this mostly.
+ */
void ED_undo_operator_repeat_cb(struct bContext *C, void *arg_op, void *arg_unused);
void ED_undo_operator_repeat_cb_evt(struct bContext *C, void *arg_op, int arg_unused);
+/**
+ * Name optionally, function used to check for operator redo panel.
+ */
bool ED_undo_is_valid(const struct bContext *C, const char *undoname);
bool ED_undo_is_memfile_compatible(const struct bContext *C);
/* Unfortunate workaround for limits mixing undo systems. */
+
+/**
+ * When a property of ID changes, return false.
+ *
+ * This is to avoid changes to a property making undo pushes
+ * which are ignored by the undo-system.
+ * For example, changing a brush property isn't stored by sculpt-mode undo steps.
+ * This workaround is needed until the limitation is removed, see: T61948.
+ */
bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, struct ID *id);
+/**
+ * Load all our objects from `object_array` into edit-mode, clear everything else.
+ */
void ED_undo_object_editmode_restore_helper(struct bContext *C,
struct Object **object_array,
uint object_array_len,
@@ -73,6 +96,13 @@ struct Object **ED_undo_editmode_objects_from_view_layer(struct ViewLayer *view_
uint *r_len);
struct Base **ED_undo_editmode_bases_from_view_layer(struct ViewLayer *view_layer, uint *r_len);
+/**
+ * Ideally we won't access the stack directly,
+ * this is needed for modes which handle undo themselves (bypassing #ED_undo_push).
+ *
+ * Using global isn't great, this just avoids doing inline,
+ * causing 'BKE_global.h' & 'BKE_main.h' includes.
+ */
struct UndoStack *ED_undo_stack_get(void);
/* helpers */
@@ -83,11 +113,28 @@ void ED_undo_object_set_active_or_warn(struct Scene *scene,
struct CLG_LogRef *log);
/* undo_system_types.c */
+
void ED_undosys_type_init(void);
void ED_undosys_type_free(void);
/* memfile_undo.c */
+
struct MemFile *ED_undosys_stack_memfile_get_active(struct UndoStack *ustack);
+/**
+ * If the last undo step is a memfile one, find the first #MemFileChunk matching given ID
+ * (using its session UUID), and tag it as "changed in the future".
+ *
+ * Since non-memfile undo-steps cannot automatically set this flag in the previous step as done
+ * with memfile ones, this has to be called manually by relevant undo code.
+ *
+ * \note Only current known case for this is undoing a switch from Object to Sculpt mode (see
+ * T82388).
+ *
+ * \note Calling this ID by ID is not optimal, as it will loop over all #MemFile.chunks until it
+ * finds the expected one. If this becomes an issue we'll have to add a mapping from session UUID
+ * to first #MemFileChunk in #MemFile itself
+ * (currently we only do that in #MemFileWriteData when writing a new step).
+ */
void ED_undosys_stack_memfile_id_changed_tag(struct UndoStack *ustack, struct ID *id);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 0105af843bb..4e794838b2f 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -30,12 +30,18 @@
extern "C" {
#endif
+struct GPUBatch;
struct Main;
struct bContext;
+struct IDRemapper;
/* ed_util.c */
+
void ED_editors_init_for_undo(struct Main *bmain);
void ED_editors_init(struct bContext *C);
+/**
+ * Frees all edit-mode stuff.
+ */
void ED_editors_exit(struct Main *bmain, bool do_undo_system);
bool ED_editors_flush_edits_for_object_ex(struct Main *bmain,
@@ -44,44 +50,77 @@ bool ED_editors_flush_edits_for_object_ex(struct Main *bmain,
bool check_needs_flush);
bool ED_editors_flush_edits_for_object(struct Main *bmain, struct Object *ob);
+/**
+ * Flush any temp data from object editing to DNA before writing files, rendering, copying, etc.
+ */
bool ED_editors_flush_edits_ex(struct Main *bmain, bool for_render, bool check_needs_flush);
bool ED_editors_flush_edits(struct Main *bmain);
+/**
+ * Use to free ID references within runtime data (stored outside of DNA)
+ *
+ * \param new_id: may be NULL to unlink \a old_id.
+ */
+void ED_spacedata_id_remap_single(struct ScrArea *area,
+ struct SpaceLink *sl,
+ struct ID *old_id,
+ struct ID *new_id);
void ED_spacedata_id_remap(struct ScrArea *area,
struct SpaceLink *sl,
- struct ID *old_id,
- struct ID *new_id);
+ const struct IDRemapper *mappings);
void ED_operatortypes_edutils(void);
/* Drawing */
+
+/**
+ * Callback that draws a line between the mouse and a position given as the initial argument.
+ */
void ED_region_draw_mouse_line_cb(const struct bContext *C,
struct ARegion *region,
void *arg_info);
+/**
+ * \note Keep in sync with #BKE_image_stamp_buf.
+ */
void ED_region_image_metadata_draw(
int x, int y, struct ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy);
/* Slider */
+
struct tSlider;
struct tSlider *ED_slider_create(struct bContext *C);
+/**
+ * For modal operations so the percentage doesn't pop on the first mouse movement.
+ */
void ED_slider_init(struct tSlider *slider, const struct wmEvent *event);
+/**
+ * Calculate slider factor based on mouse position.
+ */
bool ED_slider_modal(struct tSlider *slider, const struct wmEvent *event);
void ED_slider_destroy(struct bContext *C, struct tSlider *slider);
+/**
+ * Return string based on the current state of the slider.
+ */
void ED_slider_status_string_get(const struct tSlider *slider,
char *status_string,
- const size_t size_of_status_string);
+ size_t size_of_status_string);
float ED_slider_factor_get(struct tSlider *slider);
void ED_slider_factor_set(struct tSlider *slider, float factor);
bool ED_slider_allow_overshoot_get(struct tSlider *slider);
-void ED_slider_allow_overshoot_set(struct tSlider *slider, const bool value);
+void ED_slider_allow_overshoot_set(struct tSlider *slider, bool value);
/* ************** XXX OLD CRUFT WARNING ************* */
+/**
+ * Now only used in 2D spaces, like time, f-curve, NLA, image, etc.
+ *
+ * \note Shift/Control are not configurable key-bindings.
+ */
void apply_keyb_grid(
int shift, int ctrl, float *val, float fac1, float fac2, float fac3, int invert);
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 516239a7176..0af98fc367f 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -46,6 +46,7 @@ struct bNodeTree;
struct wmKeyConfig;
/* uvedit_ops.c */
+
void ED_operatortypes_uvedit(void);
void ED_operatormacros_uvedit(void);
void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
@@ -54,6 +55,9 @@ bool ED_uvedit_minmax(const struct Scene *scene,
struct Object *obedit,
float min[2],
float max[2]);
+/**
+ * Be careful when using this, it bypasses all synchronization options.
+ */
void ED_uvedit_select_all(struct BMesh *bm);
bool ED_uvedit_minmax_multi(const struct Scene *scene,
@@ -96,93 +100,87 @@ bool ED_uvedit_test(struct Object *obedit);
bool uvedit_face_visible_test_ex(const struct ToolSettings *ts, struct BMFace *efa);
bool uvedit_face_select_test_ex(const struct ToolSettings *ts,
struct BMFace *efa,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
bool uvedit_edge_select_test_ex(const struct ToolSettings *ts,
struct BMLoop *l,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
bool uvedit_uv_select_test_ex(const struct ToolSettings *ts,
struct BMLoop *l,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
bool uvedit_face_visible_test(const struct Scene *scene, struct BMFace *efa);
-bool uvedit_face_select_test(const struct Scene *scene,
- struct BMFace *efa,
- const int cd_loop_uv_offset);
-bool uvedit_edge_select_test(const struct Scene *scene,
- struct BMLoop *l,
- const int cd_loop_uv_offset);
-bool uvedit_uv_select_test(const struct Scene *scene,
- struct BMLoop *l,
- const int cd_loop_uv_offset);
+bool uvedit_face_select_test(const struct Scene *scene, struct BMFace *efa, int cd_loop_uv_offset);
+bool uvedit_edge_select_test(const struct Scene *scene, struct BMLoop *l, int cd_loop_uv_offset);
+bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, int cd_loop_uv_offset);
/* uv face */
void uvedit_face_select_set_with_sticky(const struct SpaceImage *sima,
const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_face_select_set(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_face_select_enable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_face_select_disable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
/* uv edge */
void uvedit_edge_select_set_with_sticky(const struct SpaceImage *sima,
const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool select,
- const bool do_history,
- const uint cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ uint cd_loop_uv_offset);
void uvedit_edge_select_set(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_edge_select_enable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_edge_select_disable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
/* uv vert */
void uvedit_uv_select_set_with_sticky(const struct SpaceImage *sima,
const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool select,
- const bool do_history,
- const uint cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ uint cd_loop_uv_offset);
void uvedit_uv_select_set(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_uv_select_enable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_uv_select_disable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
bool ED_uvedit_nearest_uv(const struct Scene *scene,
struct Object *obedit,
@@ -191,7 +189,7 @@ bool ED_uvedit_nearest_uv(const struct Scene *scene,
float r_uv[2]);
bool ED_uvedit_nearest_uv_multi(const struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
float *dist_sq,
float r_uv[2]);
@@ -217,12 +215,17 @@ struct BMLoop *ED_uvedit_active_vert_loop_get(struct BMesh *bm);
void ED_uvedit_active_edge_loop_set(struct BMesh *bm, struct BMLoop *l);
struct BMLoop *ED_uvedit_active_edge_loop_get(struct BMesh *bm);
+/**
+ * Intentionally don't return #UV_SELECT_ISLAND as it's not an element type.
+ * In this case return #UV_SELECT_VERTEX as a fallback.
+ */
char ED_uvedit_select_mode_get(const struct Scene *scene);
void ED_uvedit_select_sync_flush(const struct ToolSettings *ts,
struct BMEditMesh *em,
- const bool select);
+ bool select);
/* uvedit_unwrap_ops.c */
+
void ED_uvedit_live_unwrap_begin(struct Scene *scene, struct Object *obedit);
void ED_uvedit_live_unwrap_re_solve(void);
void ED_uvedit_live_unwrap_end(short cancel);
@@ -231,12 +234,26 @@ void ED_uvedit_live_unwrap(const struct Scene *scene, struct Object **objects, i
void ED_uvedit_add_simple_uvs(struct Main *bmain, const struct Scene *scene, struct Object *ob);
/* uvedit_draw.c */
+
void ED_image_draw_cursor(struct ARegion *region, const float cursor[2]);
/* uvedit_buttons.c */
+
void ED_uvedit_buttons_register(struct ARegionType *art);
/* uvedit_islands.c */
+
+struct UVMapUDIM_Params {
+ const struct Image *image;
+ /** Copied from #SpaceImage.tile_grid_shape */
+ int grid_shape[2];
+ bool use_target_udim;
+ int target_udim;
+};
+bool ED_uvedit_udim_params_from_image_space(const struct SpaceImage *sima,
+ bool use_active,
+ struct UVMapUDIM_Params *udim_params);
+
struct UVPackIsland_Params {
uint rotate : 1;
/** -1 not to align to axis, otherwise 0,1 for X,Y. */
@@ -247,13 +264,16 @@ struct UVPackIsland_Params {
uint correct_aspect : 1;
};
-bool uv_coords_isect_udim(const struct Image *image, const int udim_grid[2], float coords[2]);
+/**
+ * Returns true if UV coordinates lie on a valid tile in UDIM grid or tiled image.
+ */
+bool uv_coords_isect_udim(const struct Image *image,
+ const int udim_grid[2],
+ const float coords[2]);
void ED_uvedit_pack_islands_multi(const struct Scene *scene,
- const struct SpaceImage *sima,
Object **objects,
- const uint objects_len,
- const bool use_target_udim,
- int target_udim,
+ uint objects_len,
+ const struct UVMapUDIM_Params *udim_params,
const struct UVPackIsland_Params *params);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index cf8dcbd7995..0398c209c68 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -52,6 +52,7 @@ struct RegionView3D;
struct RenderEngineType;
struct Scene;
struct ScrArea;
+struct SnapObjectContext;
struct View3D;
struct ViewContext;
struct ViewLayer;
@@ -106,47 +107,95 @@ void ED_view3d_background_color_get(const struct Scene *scene,
bool ED_view3d_has_workbench_in_texture_color(const struct Scene *scene,
const struct Object *ob,
const struct View3D *v3d);
+/**
+ * Cursor position in `r_cursor_co`, result in `r_cursor_co`, `mval` in region coords.
+ *
+ * \note cannot use `event->mval` here, called by #object_add().
+ */
void ED_view3d_cursor3d_position(struct bContext *C,
const int mval[2],
- const bool use_depth,
+ bool use_depth,
float r_cursor_co[3]);
void ED_view3d_cursor3d_position_rotation(struct bContext *C,
const int mval[2],
- const bool use_depth,
+ bool use_depth,
enum eV3DCursorOrient orientation,
float r_cursor_co[3],
float r_cursor_quat[4]);
void ED_view3d_cursor3d_update(struct bContext *C,
const int mval[2],
- const bool use_depth,
+ bool use_depth,
enum eV3DCursorOrient orientation);
struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d);
-void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist);
+/**
+ * Calculate the view transformation matrix from RegionView3D input.
+ * The resulting matrix is equivalent to #RegionView3D.viewinv
+ * \param mat: The view 4x4 transformation matrix to calculate.
+ * \param ofs: The view offset, normally from #RegionView3D.ofs.
+ * \param quat: The view rotation, quaternion normally from #RegionView3D.viewquat.
+ * \param dist: The view distance from ofs, normally from #RegionView3D.dist.
+ */
+void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], float dist);
+/**
+ * Set the view transformation from a 4x4 matrix.
+ *
+ * \param mat: The view 4x4 transformation matrix to assign.
+ * \param ofs: The view offset, normally from #RegionView3D.ofs.
+ * \param quat: The view rotation, quaternion normally from #RegionView3D.viewquat.
+ * \param dist: The view distance from `ofs`, normally from #RegionView3D.dist.
+ */
void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const float *dist);
+/**
+ * Set the #RegionView3D members from an objects transformation and optionally lens.
+ * \param ob: The object to set the view to.
+ * \param ofs: The view offset to be set, normally from #RegionView3D.ofs.
+ * \param quat: The view rotation to be set, quaternion normally from #RegionView3D.viewquat.
+ * \param dist: The view distance from `ofs `to be set, normally from #RegionView3D.dist.
+ * \param lens: The view lens angle set for cameras and lights, normally from View3D.lens.
+ */
void ED_view3d_from_object(
const struct Object *ob, float ofs[3], float quat[4], float *dist, float *lens);
+/**
+ * Set the object transformation from #RegionView3D members.
+ * \param depsgraph: The depsgraph to get the evaluated object parent
+ * for the transformation calculation.
+ * \param ob: The object which has the transformation assigned.
+ * \param ofs: The view offset, normally from #RegionView3D.ofs.
+ * \param quat: The view rotation, quaternion normally from #RegionView3D.viewquat.
+ * \param dist: The view distance from `ofs`, normally from #RegionView3D.dist.
+ */
void ED_view3d_to_object(const struct Depsgraph *depsgraph,
struct Object *ob,
const float ofs[3],
const float quat[4],
- const float dist);
+ float dist);
bool ED_view3d_camera_to_view_selected(struct Main *bmain,
struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Object *camera_ob);
+/**
+ * Use to store the last view, before entering camera view.
+ */
void ED_view3d_lastview_store(struct RegionView3D *rv3d);
/* Depth buffer */
typedef enum {
+ /** Redraw viewport without Grease Pencil and Annotations. */
V3D_DEPTH_NO_GPENCIL = 0,
+ /** Redraw viewport with Grease Pencil and Annotations only. */
V3D_DEPTH_GPENCIL_ONLY,
+ /** Redraw viewport with active object only. */
V3D_DEPTH_OBJECT_ONLY,
+
} eV3DDepthOverrideMode;
+/**
+ * Redraw the viewport depth buffer.
+ */
void ED_view3d_depth_override(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -164,7 +213,7 @@ bool ED_view3d_depth_read_cached_normal(const struct ARegion *region,
float r_normal[3]);
bool ED_view3d_depth_unproject_v3(const struct ARegion *region,
const int mval[2],
- const double depth,
+ double depth,
float r_location_world[3]);
/* Projection */
@@ -228,19 +277,97 @@ typedef enum {
(V3D_PROJ_TEST_CLIP_CONTENT | V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_FAR | \
V3D_PROJ_TEST_CLIP_WIN)
+/* view3d_snap.c */
+bool ED_view3d_snap_selected_to_location(struct bContext *C,
+ const float snap_target_global[3],
+ int pivot_point);
+
+/* view3d_cursor_snap.c */
+#define USE_SNAP_DETECT_FROM_KEYMAP_HACK
+typedef enum {
+ V3D_SNAPCURSOR_TOGGLE_ALWAYS_TRUE = 1 << 0,
+ V3D_SNAPCURSOR_OCCLUSION_ALWAYS_TRUE = 1 << 1,
+ V3D_SNAPCURSOR_OCCLUSION_ALWAYS_FALSE = 1 << 2, /* TODO. */
+ V3D_SNAPCURSOR_SNAP_ONLY_ACTIVE = 1 << 3,
+ V3D_SNAPCURSOR_SNAP_EDIT_GEOM_FINAL = 1 << 4,
+ V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE = 1 << 5,
+} eV3DSnapCursor;
+
+typedef enum {
+ V3D_PLACE_DEPTH_SURFACE = 0,
+ V3D_PLACE_DEPTH_CURSOR_PLANE = 1,
+ V3D_PLACE_DEPTH_CURSOR_VIEW = 2,
+} eV3DPlaceDepth;
+
+typedef enum {
+ V3D_PLACE_ORIENT_SURFACE = 0,
+ V3D_PLACE_ORIENT_DEFAULT = 1,
+} eV3DPlaceOrient;
+
+typedef struct V3DSnapCursorData {
+ short snap_elem;
+ float loc[3];
+ float nor[3];
+ float obmat[4][4];
+ int elem_index[3];
+ float plane_omat[3][3];
+ bool is_snap_invert;
+
+ /** Enabled when snap is activated, even if it didn't find anything. */
+ bool is_enabled;
+} V3DSnapCursorData;
+
+typedef struct V3DSnapCursorState {
+ /* Setup. */
+ eV3DSnapCursor flag;
+ eV3DPlaceDepth plane_depth;
+ eV3DPlaceOrient plane_orient;
+ uchar color_line[4];
+ uchar color_point[4];
+ uchar color_box[4];
+ struct wmGizmoGroupType *gzgrp_type; /* Force cursor to be drawn only when gizmo is available. */
+ float *prevpoint;
+ float box_dimensions[3];
+ short snap_elem_force; /* If zero, use scene settings. */
+ short plane_axis;
+ bool use_plane_axis_auto;
+ bool draw_point;
+ bool draw_plane;
+ bool draw_box;
+} V3DSnapCursorState;
+
+void ED_view3d_cursor_snap_state_default_set(V3DSnapCursorState *state);
+V3DSnapCursorState *ED_view3d_cursor_snap_state_get(void);
+V3DSnapCursorState *ED_view3d_cursor_snap_active(void);
+void ED_view3d_cursor_snap_deactive(V3DSnapCursorState *state);
+void ED_view3d_cursor_snap_prevpoint_set(V3DSnapCursorState *state, const float prev_point[3]);
+V3DSnapCursorData *ED_view3d_cursor_snap_data_get(V3DSnapCursorState *state,
+ const struct bContext *C,
+ int x,
+ int y);
+struct SnapObjectContext *ED_view3d_cursor_snap_context_ensure(struct Scene *scene);
+void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d,
+ const float loc_prev[3],
+ const float loc_curr[3],
+ const float normal[3],
+ const uchar color_line[4],
+ const uchar color_point[4],
+ short snap_elem_type);
+
/* view3d_iterators.c */
/* foreach iterators */
+
void meshobject_foreachScreenVert(
struct ViewContext *vc,
void (*func)(void *userData, struct MVert *eve, const float screen_co[2], int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void mesh_foreachScreenVert(
struct ViewContext *vc,
void (*func)(void *userData, struct BMVert *eve, const float screen_co[2], int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void mesh_foreachScreenEdge(struct ViewContext *vc,
void (*func)(void *userData,
struct BMEdge *eed,
@@ -248,8 +375,12 @@ void mesh_foreachScreenEdge(struct ViewContext *vc,
const float screen_co_b[2],
int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
+/**
+ * A version of #mesh_foreachScreenEdge that clips the segment when
+ * there is a clipping bounding box.
+ */
void mesh_foreachScreenEdge_clip_bb_segment(struct ViewContext *vc,
void (*func)(void *userData,
struct BMEdge *eed,
@@ -257,13 +388,13 @@ void mesh_foreachScreenEdge_clip_bb_segment(struct ViewContext *vc,
const float screen_co_b[2],
int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void mesh_foreachScreenFace(
struct ViewContext *vc,
void (*func)(void *userData, struct BMFace *efa, const float screen_co[2], int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void nurbs_foreachScreenVert(struct ViewContext *vc,
void (*func)(void *userData,
struct Nurb *nu,
@@ -273,40 +404,57 @@ void nurbs_foreachScreenVert(struct ViewContext *vc,
bool handle_visible,
const float screen_co[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
+/**
+ * #ED_view3d_init_mats_rv3d must be called first.
+ */
void mball_foreachScreenElem(struct ViewContext *vc,
void (*func)(void *userData,
struct MetaElem *ml,
const float screen_co[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void lattice_foreachScreenVert(struct ViewContext *vc,
void (*func)(void *userData,
struct BPoint *bp,
const float screen_co[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
+/**
+ * #ED_view3d_init_mats_rv3d must be called first.
+ */
void armature_foreachScreenBone(struct ViewContext *vc,
void (*func)(void *userData,
struct EditBone *ebone,
const float screen_co_a[2],
const float screen_co_b[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
+
+/**
+ * ED_view3d_init_mats_rv3d must be called first.
+ */
void pose_foreachScreenBone(struct ViewContext *vc,
void (*func)(void *userData,
struct bPoseChannel *pchan,
const float screen_co_a[2],
const float screen_co_b[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
/* *** end iterators *** */
/* view3d_project.c */
+
+/**
+ * \note use #ED_view3d_ob_project_mat_get to get the projection matrix
+ */
void ED_view3d_project_float_v2_m4(const struct ARegion *region,
const float co[3],
float r_co[2],
float mat[4][4]);
+/**
+ * \note use #ED_view3d_ob_project_mat_get to get projecting mat
+ */
void ED_view3d_project_float_v3_m4(const struct ARegion *region,
const float co[3],
float r_co[3],
@@ -317,65 +465,108 @@ eV3DProjStatus ED_view3d_project_base(const struct ARegion *region, struct Base
/* *** short *** */
eV3DProjStatus ED_view3d_project_short_ex(const struct ARegion *region,
float perspmat[4][4],
- const bool is_local,
+ bool is_local,
const float co[3],
short r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
+/* --- short --- */
eV3DProjStatus ED_view3d_project_short_global(const struct ARegion *region,
const float co[3],
short r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
+/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_short_object(const struct ARegion *region,
const float co[3],
short r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/* *** int *** */
eV3DProjStatus ED_view3d_project_int_ex(const struct ARegion *region,
float perspmat[4][4],
- const bool is_local,
+ bool is_local,
const float co[3],
int r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
+/* --- int --- */
eV3DProjStatus ED_view3d_project_int_global(const struct ARegion *region,
const float co[3],
int r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
+/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_int_object(const struct ARegion *region,
const float co[3],
int r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/* *** float *** */
eV3DProjStatus ED_view3d_project_float_ex(const struct ARegion *region,
float perspmat[4][4],
- const bool is_local,
+ bool is_local,
const float co[3],
float r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
+/* --- float --- */
eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *region,
const float co[3],
float r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
+/**
+ * Object space, use #ED_view3d_init_mats_rv3d before calling.
+ */
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region,
const float co[3],
float r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]);
float ED_view3d_pixel_size_no_ui_scale(const struct RegionView3D *rv3d, const float co[3]);
+/**
+ * Calculate a depth value from \a co, use with #ED_view3d_win_to_delta
+ */
float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip);
+/**
+ * Calculate a depth value from `co` (result should only be used for comparison).
+ */
float ED_view3d_calc_depth_for_comparison(const struct RegionView3D *rv3d, const float co[3]);
bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float ray_start[3], float ray_end[3]);
+/**
+ * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
+ * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
+ * ray_start is clipped by the view near limit so points in front of it are always in view.
+ * In orthographic view the resulting ray_normal will match the view vector.
+ * \param region: The region (used for the window width and height).
+ * \param v3d: The 3d viewport (used for near clipping value).
+ * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
+ * \param r_ray_start: The world-space point where the ray intersects the window plane.
+ * \param r_ray_normal: The normalized world-space direction of towards mval.
+ * \param do_clip_planes: Optionally clip the start of the ray by the view clipping planes.
+ * \return success, false if the ray is totally clipped.
+ */
bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph,
const struct ARegion *region,
const struct View3D *v3d,
const float mval[2],
- float ray_start[3],
- float ray_normal[3],
- const bool do_clip);
+ float r_ray_start[3],
+ float r_ray_normal[3],
+ bool do_clip_planes);
+/**
+ * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
+ * This ray_start is located at the viewpoint, ray_normal is the direction towards `mval`.
+ * ray_start is clipped by the view near limit so points in front of it are always in view.
+ * In orthographic view the resulting ray_normal will match the view vector.
+ * This version also returns the ray_co point of the ray on window plane, useful to fix precision
+ * issues especially with orthographic view, where default ray_start is set rather far away.
+ * \param region: The region (used for the window width and height).
+ * \param v3d: The 3d viewport (used for near clipping value).
+ * \param mval: The area relative 2d location (such as `event->mval`, converted into float[2]).
+ * \param r_ray_co: The world-space point where the ray intersects the window plane.
+ * \param r_ray_normal: The normalized world-space direction of towards mval.
+ * \param r_ray_start: The world-space starting point of the ray.
+ * \param do_clip_planes: Optionally clip the start of the ray by the view clipping planes.
+ * \return success, false if the ray is totally clipped.
+ */
bool ED_view3d_win_to_ray_clipped_ex(struct Depsgraph *depsgraph,
const struct ARegion *region,
const struct View3D *v3d,
@@ -383,14 +574,39 @@ bool ED_view3d_win_to_ray_clipped_ex(struct Depsgraph *depsgraph,
float r_ray_co[3],
float r_ray_normal[3],
float r_ray_start[3],
- bool do_clip);
+ bool do_clip_planes);
+/**
+ * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
+ * This ray_start is located at the viewpoint, ray_normal is the direction towards `mval`.
+ * \param region: The region (used for the window width and height).
+ * \param mval: The area relative 2d location (such as `event->mval`, converted into float[2]).
+ * \param r_ray_start: The world-space point where the ray intersects the window plane.
+ * \param r_ray_normal: The normalized world-space direction of towards mval.
+ *
+ * \note Ignores view near/far clipping,
+ * to take this into account use #ED_view3d_win_to_ray_clipped.
+ */
void ED_view3d_win_to_ray(const struct ARegion *region,
const float mval[2],
float r_ray_start[3],
float r_ray_normal[3]);
+/**
+ * Calculate a normalized 3d direction vector from the viewpoint towards a global location.
+ * In orthographic view the resulting vector will match the view vector.
+ * \param rv3d: The region (used for the window width and height).
+ * \param coord: The world-space location.
+ * \param vec: The resulting normalized vector.
+ */
void ED_view3d_global_to_vector(const struct RegionView3D *rv3d,
const float coord[3],
float vec[3]);
+/**
+ * Calculate a 3d location from 2d window coordinates.
+ * \param region: The region (used for the window width and height).
+ * \param depth_pt: The reference location used to calculate the Z depth.
+ * \param mval: The area relative location (such as `event->mval` converted to floats).
+ * \param r_out: The resulting world-space location.
+ */
void ED_view3d_win_to_3d(const struct View3D *v3d,
const struct ARegion *region,
const float depth_pt[3],
@@ -404,32 +620,84 @@ void ED_view3d_win_to_3d_int(const struct View3D *v3d,
bool ED_view3d_win_to_3d_on_plane(const struct ARegion *region,
const float plane[4],
const float mval[2],
- const bool do_clip,
+ bool do_clip,
float r_out[3]);
+/**
+ * A wrapper for #ED_view3d_win_to_3d_on_plane that projects onto \a plane_fallback
+ * then maps this back to \a plane.
+ *
+ * This is intended to be used when \a plane is orthogonal to the views Z axis where
+ * projecting the \a mval doesn't work well (or fail completely when exactly aligned).
+ */
bool ED_view3d_win_to_3d_on_plane_with_fallback(const struct ARegion *region,
const float plane[4],
const float mval[2],
- const bool do_clip,
+ bool do_clip,
const float plane_fallback[4],
float r_out[3]);
bool ED_view3d_win_to_3d_on_plane_int(const struct ARegion *region,
const float plane[4],
const int mval[2],
- const bool do_clip,
+ bool do_clip,
float r_out[3]);
+/**
+ * Calculate a 3d difference vector from 2d window offset.
+ * note that #ED_view3d_calc_zfac() must be called first to determine
+ * the depth used to calculate the delta.
+ * \param region: The region (used for the window width and height).
+ * \param mval: The area relative 2d difference (such as `event->mval[0] - other_x`).
+ * \param out: The resulting world-space delta.
+ */
void ED_view3d_win_to_delta(const struct ARegion *region,
const float mval[2],
float out[3],
- const float zfac);
+ float zfac);
+/**
+ * Calculate a 3d origin from 2d window coordinates.
+ * \note Orthographic views have a less obvious origin,
+ * Since far clip can be a very large value resulting in numeric precision issues,
+ * the origin in this case is close to zero coordinate.
+ *
+ * \param region: The region (used for the window width and height).
+ * \param mval: The area relative 2d location (such as event->mval converted to floats).
+ * \param out: The resulting normalized world-space direction vector.
+ */
void ED_view3d_win_to_origin(const struct ARegion *region, const float mval[2], float out[3]);
+/**
+ * Calculate a 3d direction vector from 2d window coordinates.
+ * This direction vector starts and the view in the direction of the 2d window coordinates.
+ * In orthographic view all window coordinates yield the same vector.
+ *
+ * \note doesn't rely on ED_view3d_calc_zfac
+ * for perspective view, get the vector direction to
+ * the mouse cursor as a normalized vector.
+ *
+ * \param region: The region (used for the window width and height).
+ * \param mval: The area relative 2d location (such as event->mval converted to floats).
+ * \param out: The resulting normalized world-space direction vector.
+ */
void ED_view3d_win_to_vector(const struct ARegion *region, const float mval[2], float out[3]);
+/**
+ * Calculate a 3d segment from 2d window coordinates.
+ * This ray_start is located at the viewpoint, ray_end is a far point.
+ * ray_start and ray_end are clipped by the view near and far limits
+ * so points along this line are always in view.
+ * In orthographic view all resulting segments will be parallel.
+ * \param region: The region (used for the window width and height).
+ * \param v3d: The 3d viewport (used for near and far clipping range).
+ * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
+ * \param r_ray_start: The world-space starting point of the segment.
+ * \param r_ray_end: The world-space end point of the segment.
+ * \param do_clip_planes: Optionally clip the ray by the view clipping planes.
+ * \return success, false if the segment is totally clipped.
+ */
bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph,
const struct ARegion *region,
struct View3D *v3d,
const float mval[2],
float r_ray_start[3],
float r_ray_end[3],
- const bool do_clip);
+ bool do_clip_planes);
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d,
const struct Object *ob,
float r_pmat[4][4]);
@@ -437,6 +705,10 @@ void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d,
const float obmat[4][4],
float r_pmat[4][4]);
+/**
+ * Convert between region relative coordinates (x,y) and depth component z and
+ * a point in world space.
+ */
void ED_view3d_project_v3(const struct ARegion *region,
const float world[3],
float r_region_co[3]);
@@ -449,12 +721,15 @@ bool ED_view3d_unproject_v3(
/* end */
void ED_view3d_dist_range_get(const struct View3D *v3d, float r_dist_range[2]);
+/**
+ * \note copies logic of #ED_view3d_viewplane_get(), keep in sync.
+ */
bool ED_view3d_clip_range_get(struct Depsgraph *depsgraph,
const struct View3D *v3d,
const struct RegionView3D *rv3d,
float *r_clipsta,
float *r_clipend,
- const bool use_ortho_factor);
+ bool use_ortho_factor);
bool ED_view3d_viewplane_get(struct Depsgraph *depsgraph,
const struct View3D *v3d,
const struct RegionView3D *rv3d,
@@ -465,7 +740,10 @@ bool ED_view3d_viewplane_get(struct Depsgraph *depsgraph,
float *r_clipend,
float *r_pixsize);
-void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, const float dist);
+/**
+ * Use instead of: `GPU_polygon_offset(rv3d->dist, ...)` see bug T37727.
+ */
+void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, float dist);
void ED_view3d_calc_camera_border(const struct Scene *scene,
struct Depsgraph *depsgraph,
@@ -473,7 +751,7 @@ void ED_view3d_calc_camera_border(const struct Scene *scene,
const struct View3D *v3d,
const struct RegionView3D *rv3d,
struct rctf *r_viewborder,
- const bool no_shift);
+ bool no_shift);
void ED_view3d_calc_camera_border_size(const struct Scene *scene,
struct Depsgraph *depsgraph,
const struct ARegion *region,
@@ -488,55 +766,110 @@ bool ED_view3d_calc_render_border(const struct Scene *scene,
void ED_view3d_clipping_calc_from_boundbox(float clip[4][4],
const struct BoundBox *clipbb,
- const bool is_flip);
+ bool is_flip);
void ED_view3d_clipping_calc(struct BoundBox *bb,
float planes[4][4],
const struct ARegion *region,
const struct Object *ob,
const struct rcti *rect);
+/**
+ * Clamp min/max by the viewport clipping.
+ *
+ * \note This is an approximation, with the limitation that the bounding box from the (mix, max)
+ * calculation might not have any geometry inside the clipped region.
+ * Performing a clipping test on each vertex would work well enough for most cases,
+ * although it's not perfect either as edges/faces may intersect the clipping without having any
+ * of their vertices inside it.
+ * A more accurate result would be quite involved.
+ *
+ * \return True when the arguments were clamped.
+ */
bool ED_view3d_clipping_clamp_minmax(const struct RegionView3D *rv3d, float min[3], float max[3]);
void ED_view3d_clipping_local(struct RegionView3D *rv3d, const float mat[4][4]);
-bool ED_view3d_clipping_test(const struct RegionView3D *rv3d,
- const float co[3],
- const bool is_local);
+/**
+ * Return true when `co` is hidden by the 3D views clipping planes.
+ *
+ * \param is_local: When true use local (object-space) #ED_view3d_clipping_local must run first,
+ * then all comparisons can be done in local-space.
+ * \return True when `co` is outside all clipping planes.
+ *
+ * \note Callers should check #RV3D_CLIPPING_ENABLED first.
+ */
+bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], bool is_local);
-float ED_view3d_radius_to_dist_persp(const float angle, const float radius);
-float ED_view3d_radius_to_dist_ortho(const float lens, const float radius);
+float ED_view3d_radius_to_dist_persp(float angle, float radius);
+float ED_view3d_radius_to_dist_ortho(float lens, float radius);
+/**
+ * Return a new #RegionView3D.dist value to fit the \a radius.
+ *
+ * \note Depth isn't taken into account, this will fit a flat plane exactly,
+ * but points towards the view (with a perspective projection),
+ * may be within the radius but outside the view. eg:
+ *
+ * <pre>
+ * +
+ * pt --> + /^ radius
+ * / |
+ * / |
+ * view + +
+ * \ |
+ * \ |
+ * \|
+ * +
+ * </pre>
+ *
+ * \param region: Can be NULL if \a use_aspect is false.
+ * \param persp: Allow the caller to tell what kind of perspective to use (ortho/view/camera)
+ * \param use_aspect: Increase the distance to account for non 1:1 view aspect.
+ * \param radius: The radius will be fitted exactly,
+ * typically pre-scaled by a margin (#VIEW3D_MARGIN).
+ */
float ED_view3d_radius_to_dist(const struct View3D *v3d,
const struct ARegion *region,
const struct Depsgraph *depsgraph,
- const char persp,
- const bool use_aspect,
- const float radius);
-
-void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned int pos);
+ char persp,
+ bool use_aspect,
+ float radius);
-/* Back-buffer select and draw support. */
+/**
+ * Back-buffer select and draw support.
+ */
void ED_view3d_backbuf_depth_validate(struct ViewContext *vc);
-int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, const float dist);
+/**
+ * allow for small values [0.5 - 2.5],
+ * and large values, FLT_MAX by clamping by the area size
+ */
+int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, float dist);
void ED_view3d_select_id_validate(struct ViewContext *vc);
+/**
+ * Get the world-space 3d location from a screen-space 2d point.
+ * TODO: Implement #alphaoverride. We don't want to zoom into billboards.
+ *
+ * \param mval: Input screen-space pixel location.
+ * \param mouse_worldloc: Output world-space location.
+ * \param fallback_depth_pt: Use this points depth when no depth can be found.
+ */
bool ED_view3d_autodist(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const int mval[2],
float mouse_worldloc[3],
- const bool alphaoverride,
+ bool alphaoverride,
const float fallback_depth_pt[3]);
+/**
+ * No 4x4 sampling, run #ED_view3d_depth_override first.
+ */
bool ED_view3d_autodist_simple(struct ARegion *region,
const int mval[2],
float mouse_worldloc[3],
int margin,
const float *force_depth);
-bool ED_view3d_autodist_depth(struct ARegion *region, const int mval[2], int margin, float *depth);
-bool ED_view3d_autodist_depth_seg(struct ARegion *region,
- const int mval_sta[2],
- const int mval_end[2],
- int margin,
- float *depth);
+bool ED_view3d_depth_read_cached_seg(
+ const ViewDepths *vd, const int mval_sta[2], const int mval_end[2], int margin, float *depth);
/* select */
#define MAXPICKELEMS 2500
@@ -563,16 +896,28 @@ typedef enum {
eV3DSelectObjectFilter ED_view3d_select_filter_from_mode(const struct Scene *scene,
const struct Object *obact);
+/**
+ * Optionally cache data for multiple calls to #view3d_opengl_select
+ *
+ * just avoid GPU_select headers outside this file
+ */
void view3d_opengl_select_cache_begin(void);
void view3d_opengl_select_cache_end(void);
+/**
+ * \warning be sure to account for a negative return value
+ * This is an error, "Too many objects in select buffer"
+ * and no action should be taken (can crash blender) if this happens
+ *
+ * \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
+ */
int view3d_opengl_select_ex(struct ViewContext *vc,
unsigned int *buffer,
unsigned int bufsize,
const struct rcti *input,
eV3DSelectMode select_mode,
eV3DSelectObjectFilter select_filter,
- const bool do_material_slot_selection);
+ bool do_material_slot_selection);
int view3d_opengl_select(struct ViewContext *vc,
unsigned int *buffer,
unsigned int bufsize,
@@ -593,28 +938,57 @@ void ED_view3d_viewcontext_init(struct bContext *C,
struct ViewContext *vc,
struct Depsgraph *depsgraph);
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
+/**
+ * Use this call when executing an operator,
+ * event system doesn't set for each event the OpenGL drawing context.
+ */
void view3d_operator_needs_opengl(const struct bContext *C);
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *region);
-/* XXX should move to BLI_math */
+/** XXX: should move to BLI_math */
bool edge_inside_circle(const float cent[2],
float radius,
const float screen_co_a[2],
const float screen_co_b[2]);
-/* get 3d region from context, also if mouse is in header or toolbar */
+/**
+ * Get 3D region from context, also if mouse is in header or toolbar.
+ */
struct RegionView3D *ED_view3d_context_rv3d(struct bContext *C);
+/**
+ * Ideally would return an rv3d but in some cases the region is needed too
+ * so return that, the caller can then access the `region->regiondata`.
+ */
bool ED_view3d_context_user_region(struct bContext *C,
struct View3D **r_v3d,
struct ARegion **r_region);
+/**
+ * Similar to #ED_view3d_context_user_region() but does not use context. Always performs a lookup.
+ * Also works if \a v3d is not the active space.
+ */
bool ED_view3d_area_user_region(const struct ScrArea *area,
const struct View3D *v3d,
struct ARegion **r_region);
bool ED_operator_rv3d_user_region_poll(struct bContext *C);
+/**
+ * Most of the time this isn't needed since you could assume the view matrix was
+ * set while drawing, however when functions like mesh_foreachScreenVert are
+ * called by selection tools, we can't be sure this object was the last.
+ *
+ * for example, transparent objects are drawn after edit-mode and will cause
+ * the rv3d mat's to change and break selection.
+ *
+ * 'ED_view3d_init_mats_rv3d' should be called before
+ * view3d_project_short_clip and view3d_project_short_noclip in cases where
+ * these functions are not used during draw_object
+ */
void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d);
void ED_view3d_init_mats_rv3d_gl(const struct Object *ob, struct RegionView3D *rv3d);
#ifdef DEBUG
+/**
+ * Ensure we correctly initialize.
+ */
void ED_view3d_clear_mats_rv3d(struct RegionView3D *rv3d);
void ED_view3d_check_mats_rv3d(struct RegionView3D *rv3d);
#else
@@ -628,11 +1002,14 @@ void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixSto
void ED_draw_object_facemap(struct Depsgraph *depsgraph,
struct Object *ob,
const float col[4],
- const int facemap);
+ int facemap);
struct RenderEngineType *ED_view3d_engine_type(const struct Scene *scene, int drawtype);
bool ED_view3d_context_activate(struct bContext *C);
+/**
+ * Set the correct matrices
+ */
void ED_view3d_draw_setup_view(const struct wmWindowManager *wm,
struct wmWindow *win,
struct Depsgraph *depsgraph,
@@ -643,13 +1020,22 @@ void ED_view3d_draw_setup_view(const struct wmWindowManager *wm,
const float winmat[4][4],
const struct rcti *rect);
+/**
+ * `mval` comes from event->mval, only use within region handlers.
+ */
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
struct Object *ED_view3d_give_object_under_cursor(struct bContext *C, const int mval[2]);
struct Object *ED_view3d_give_material_slot_under_cursor(struct bContext *C,
const int mval[2],
int *r_material_slot);
bool ED_view3d_is_object_under_cursor(struct bContext *C, const int mval[2]);
+/**
+ * 'clip' is used to know if our clip setting has changed.
+ */
void ED_view3d_quadview_update(struct ScrArea *area, struct ARegion *region, bool do_clip);
+/**
+ * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
+ */
void ED_view3d_update_viewmat(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct View3D *v3d,
@@ -658,9 +1044,9 @@ void ED_view3d_update_viewmat(struct Depsgraph *depsgraph,
const float winmat[4][4],
const struct rcti *rect,
bool offscreen);
-bool ED_view3d_quat_from_axis_view(const char view, const char view_axis_roll, float r_quat[4]);
+bool ED_view3d_quat_from_axis_view(char view, char view_axis_roll, float r_quat[4]);
bool ED_view3d_quat_to_axis_view(const float viewquat[4],
- const float epsilon,
+ float epsilon,
char *r_view,
char *r_view_axis_rotation);
@@ -672,31 +1058,62 @@ void ED_view3d_datamask(const struct bContext *C,
const struct Scene *scene,
const struct View3D *v3d,
struct CustomData_MeshMasks *r_cddata_masks);
+/**
+ * Goes over all modes and view3d settings.
+ */
void ED_view3d_screen_datamask(const struct bContext *C,
const struct Scene *scene,
const struct bScreen *screen,
struct CustomData_MeshMasks *r_cddata_masks);
bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
+/**
+ * For viewport operators that exit camera perspective.
+ *
+ * \note This differs from simply setting `rv3d->persp = persp` because it
+ * sets the `ofs` and `dist` values of the viewport so it matches the camera,
+ * otherwise switching out of camera view may jump to a different part of the scene.
+ */
void ED_view3d_persp_switch_from_camera(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d,
- const char persp);
+ char persp);
+/**
+ * Action to take when rotating the view,
+ * handle auto-perspective and logic for switching out of views.
+ *
+ * shared with NDOF.
+ */
bool ED_view3d_persp_ensure(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct ARegion *region);
-/* camera lock functions */
+/* Camera lock functions */
+
+/**
+ * \return true when the 3D Viewport is locked to its camera.
+ */
bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
-/* copy the camera to the view before starting a view transformation */
+/**
+ * Copy the camera to the view before starting a view transformation.
+ *
+ * Apply the camera object transformation to the 3D Viewport.
+ * (needed so we can use regular 3D Viewport manipulation operators, that sync back to the camera).
+ */
void ED_view3d_camera_lock_init_ex(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d,
- const bool calc_dist);
+ bool calc_dist);
void ED_view3d_camera_lock_init(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d);
-/* copy the view to the camera, return true if */
+/**
+ * Copy the view to the camera, return true if.
+ *
+ * Apply the 3D Viewport transformation back to the camera object.
+ *
+ * \return true if the camera is moved.
+ */
bool ED_view3d_camera_lock_sync(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d);
@@ -704,27 +1121,58 @@ bool ED_view3d_camera_lock_sync(const struct Depsgraph *depsgraph,
bool ED_view3d_camera_autokey(const struct Scene *scene,
struct ID *id_key,
struct bContext *C,
- const bool do_rotate,
- const bool do_translate);
+ bool do_rotate,
+ bool do_translate);
+/**
+ * Call after modifying a locked view.
+ *
+ * \note Not every view edit currently auto-keys (numeric-pad for eg),
+ * this is complicated because of smooth-view.
+ */
bool ED_view3d_camera_lock_autokey(struct View3D *v3d,
struct RegionView3D *rv3d,
struct bContext *C,
- const bool do_rotate,
- const bool do_translate);
+ bool do_rotate,
+ bool do_translate);
void ED_view3d_lock_clear(struct View3D *v3d);
#define VIEW3D_MARGIN 1.4f
#define VIEW3D_DIST_FALLBACK 1.0f
-float ED_view3d_offset_distance(const float mat[4][4],
- const float ofs[3],
- const float fallback_dist);
-void ED_view3d_distance_set(struct RegionView3D *rv3d, const float dist);
+/**
+ * This function solves the problem of having to switch between camera and non-camera views.
+ *
+ * When viewing from the perspective of \a mat, and having the view center \a ofs,
+ * this calculates a distance from \a ofs to the matrix \a mat.
+ * Using \a fallback_dist when the distance would be too small.
+ *
+ * \param mat: A matrix use for the view-point (typically the camera objects matrix).
+ * \param ofs: Orbit center (negated), matching #RegionView3D.ofs, which is typically passed in.
+ * \param fallback_dist: The distance to use if the object is too near or in front of \a ofs.
+ * \returns A newly calculated distance or the fallback.
+ */
+float ED_view3d_offset_distance(const float mat[4][4], const float ofs[3], float fallback_dist);
+/**
+ * Set the dist without moving the view (compensate with #RegionView3D.ofs)
+ *
+ * \note take care that #RegionView3d.viewinv is up to date, #ED_view3d_update_viewmat first.
+ */
+void ED_view3d_distance_set(struct RegionView3D *rv3d, float dist);
+/**
+ * Change the distance & offset to match the depth of \a dist_co along the view axis.
+ *
+ * \param dist_co: A world-space location to use for the new depth.
+ * \param dist_min: Resulting distances below this will be ignored.
+ * \return Success if the distance was set.
+ */
bool ED_view3d_distance_set_from_location(struct RegionView3D *rv3d,
const float dist_co[3],
- const float dist_min);
+ float dist_min);
+/**
+ * Could move this elsewhere, but tied into #ED_view3d_grid_scale
+ */
float ED_scene_grid_scale(const struct Scene *scene, const char **r_grid_unit);
float ED_view3d_grid_scale(const struct Scene *scene,
struct View3D *v3d,
@@ -733,14 +1181,24 @@ void ED_view3d_grid_steps(const struct Scene *scene,
struct View3D *v3d,
struct RegionView3D *rv3d,
float r_grid_steps[8]);
+/**
+ * Simulates the grid scale that is actually viewed.
+ * The actual code is seen in `object_grid_frag.glsl` (see `grid_res`).
+ * Currently the simulation is only done when RV3D_VIEW_IS_AXIS.
+ */
float ED_view3d_grid_view_scale(struct Scene *scene,
struct View3D *v3d,
struct ARegion *region,
const char **r_grid_unit);
+/**
+ * \note The info that this uses is updated in #ED_refresh_viewport_fps,
+ * which currently gets called during #SCREEN_OT_animation_step.
+ */
void ED_scene_draw_fps(const struct Scene *scene, int xoffset, int *yoffset);
-/* render */
+/* Render */
+
void ED_view3d_stop_render_preview(struct wmWindowManager *wm, struct ARegion *region);
void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *area);
@@ -753,33 +1211,42 @@ void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrAr
#define XRAY_ACTIVE(v3d) (XRAY_ENABLED(v3d) && ((v3d)->shading.type < OB_MATERIAL))
/* view3d_draw_legacy.c */
-/* Try avoid using these more move out of legacy. */
+
+/**
+ * Try avoid using these more move out of legacy.
+ */
void ED_view3d_draw_bgpic_test(const struct Scene *scene,
struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
- const bool do_foreground,
- const bool do_camera_frame);
+ bool do_foreground,
+ bool do_camera_frame);
/* view3d_gizmo_preselect_type.c */
+
void ED_view3d_gizmo_mesh_preselect_get_active(struct bContext *C,
struct wmGizmo *gz,
struct Base **r_base,
struct BMElem **r_ele);
+void ED_view3d_gizmo_mesh_preselect_clear(struct wmGizmo *gz);
/* space_view3d.c */
+
void ED_view3d_buttons_region_layout_ex(const struct bContext *C,
struct ARegion *region,
const char *category_override);
/* view3d_view.c */
+
+/**
+ * See if current UUID is valid, otherwise set a valid UUID to v3d,
+ * Try to keep the same UUID previously used to allow users to quickly toggle back and forth.
+ */
bool ED_view3d_local_collections_set(struct Main *bmain, struct View3D *v3d);
-void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all);
+void ED_view3d_local_collections_reset(struct bContext *C, bool reset_all);
#ifdef WITH_XR_OPENXR
-void ED_view3d_xr_mirror_update(const struct ScrArea *area,
- const struct View3D *v3d,
- const bool enable);
+void ED_view3d_xr_mirror_update(const struct ScrArea *area, const struct View3D *v3d, bool enable);
void ED_view3d_xr_shading_update(struct wmWindowManager *wm,
const View3D *v3d,
const struct Scene *scene);
diff --git a/source/blender/editors/include/ED_view3d_offscreen.h b/source/blender/editors/include/ED_view3d_offscreen.h
index c490e96031f..ae2329c457b 100644
--- a/source/blender/editors/include/ED_view3d_offscreen.h
+++ b/source/blender/editors/include/ED_view3d_offscreen.h
@@ -53,14 +53,18 @@ void ED_view3d_draw_offscreen(struct Depsgraph *depsgraph,
bool is_image_render,
bool draw_background,
const char *viewname,
- const bool do_color_management,
- const bool restore_rv3d_mats,
+ bool do_color_management,
+ bool restore_rv3d_mats,
struct GPUOffScreen *ofs,
struct GPUViewport *viewport);
+/**
+ * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen). Similar too
+ * #ED_view_draw_offscreen_imbuf_simple, but takes view/projection matrices as arguments.
+ */
void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph,
struct Scene *scene,
struct View3DShading *shading_override,
- int drawtype,
+ eDrawType drawtype,
int winx,
int winy,
unsigned int draw_flags,
@@ -68,13 +72,20 @@ void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph,
const float winmat[4][4],
float clip_start,
float clip_end,
+ bool is_xr_surface,
bool is_image_render,
bool draw_background,
const char *viewname,
- const bool do_color_management,
+ bool do_color_management,
struct GPUOffScreen *ofs,
struct GPUViewport *viewport);
+/**
+ * Utility func for ED_view3d_draw_offscreen
+ *
+ * \param ofs: Optional off-screen buffer, can be NULL.
+ * (avoids re-creating when doing multiple GL renders).
+ */
struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph,
struct Scene *scene,
eDrawType drawtype,
@@ -85,9 +96,17 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph,
eImBufFlags imbuf_flag,
int alpha_mode,
const char *viewname,
- const bool restore_rv3d_mats,
+ bool restore_rv3d_mats,
struct GPUOffScreen *ofs,
char err_out[256]);
+/**
+ * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf)
+ *
+ * \param ofs: Optional off-screen buffer can be NULL.
+ * (avoids re-creating when doing multiple GL renders).
+ *
+ * \note used by the sequencer
+ */
struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Depsgraph *depsgraph,
struct Scene *scene,
struct View3DShading *shading_override,
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 8a7df5b54ff..4cf606bf98d 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -774,7 +774,7 @@ DEF_ICON_BLANK(276)
DEF_ICON_BLANK(277)
DEF_ICON_BLANK(772)
DEF_ICON_BLANK(773)
-DEF_ICON_BLANK(774)
+DEF_ICON(CURRENT_FILE)
DEF_ICON(HOME)
DEF_ICON(DOCUMENTS)
DEF_ICON(TEMP)
@@ -944,9 +944,7 @@ DEF_ICON_COLOR(GPBRUSH_ERASE_SOFT)
DEF_ICON_COLOR(GPBRUSH_ERASE_HARD)
DEF_ICON_COLOR(GPBRUSH_ERASE_STROKE)
-/* Vector Icons */
-DEF_ICON_VECTOR(SMALL_TRI_RIGHT_VEC)
-
+/* Vector icons. */
DEF_ICON_VECTOR(KEYTYPE_KEYFRAME_VEC)
DEF_ICON_VECTOR(KEYTYPE_BREAKDOWN_VEC)
DEF_ICON_VECTOR(KEYTYPE_EXTREME_VEC)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index f7842270746..3796fa51499 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -27,6 +27,7 @@
#include "BLI_sys_types.h" /* size_t */
#include "BLI_utildefines.h"
#include "UI_interface_icons.h"
+#include "WM_types.h"
#ifdef __cplusplus
extern "C" {
@@ -37,6 +38,7 @@ extern "C" {
struct ARegion;
struct AssetFilterSettings;
struct AssetHandle;
+struct AssetMetaData;
struct AutoComplete;
struct EnumPropertyItem;
struct FileDirEntry;
@@ -82,6 +84,7 @@ struct wmWindow;
typedef struct uiBlock uiBlock;
typedef struct uiBut uiBut;
+typedef struct uiButExtraOpIcon uiButExtraOpIcon;
typedef struct uiLayout uiLayout;
typedef struct uiPopupBlockHandle uiPopupBlockHandle;
/* C handle for C++ #ui::AbstractTreeView type. */
@@ -95,6 +98,10 @@ typedef struct uiTreeViewItemHandle uiTreeViewItemHandle;
#define UI_SEP_CHAR '|'
#define UI_SEP_CHAR_S "|"
+/* Separator for text in search menus (right pointing arrow).
+ * keep in sync with `string_search.cc`. */
+#define UI_MENU_ARROW_SEP "\xe2\x96\xb6"
+
/* names */
#define UI_MAX_DRAW_STR 400
#define UI_MAX_NAME_STR 128
@@ -238,10 +245,10 @@ enum {
};
/* Default font size for normal text. */
-#define UI_DEFAULT_TEXT_POINTS 11
+#define UI_DEFAULT_TEXT_POINTS 11.0f
/* Larger size used for title text. */
-#define UI_DEFAULT_TITLE_POINTS 12
+#define UI_DEFAULT_TITLE_POINTS 11.0f
#define UI_PANEL_WIDTH 340
#define UI_COMPACT_PANEL_WIDTH 160
@@ -251,7 +258,10 @@ enum {
#define UI_PANEL_CATEGORY_MARGIN_WIDTH (U.widget_unit * 1.0f)
-#define UI_PANEL_BOX_STYLE_MARGIN (U.widget_unit * 0.2f)
+/* Both these margins should be ignored if the panel doesn't show a background (check
+ * #UI_panel_should_show_background()). */
+#define UI_PANEL_MARGIN_X (U.widget_unit * 0.4f)
+#define UI_PANEL_MARGIN_Y (U.widget_unit * 0.1f)
/* but->drawflag - these flags should only affect how the button is drawn. */
/* NOTE: currently, these flags *are not passed* to the widget's state() or draw() functions
@@ -392,9 +402,8 @@ typedef enum {
/** Resize handle (resize uilist). */
UI_BTYPE_GRIP = 57 << 9,
UI_BTYPE_DECORATOR = 58 << 9,
- UI_BTYPE_DATASETROW = 59 << 9,
/* An item in a tree view. Parent items may be collapsible. */
- UI_BTYPE_TREEROW = 60 << 9,
+ UI_BTYPE_TREEROW = 59 << 9,
} eButType;
#define BUTTYPE (63 << 9)
@@ -417,10 +426,6 @@ typedef enum eButGradientType {
* Functions to draw various shapes, taking theme settings into account.
* Used for code that draws its own UI style elements. */
-void UI_draw_anti_tria(
- float x1, float y1, float x2, float y2, float x3, float y3, const float color[4]);
-void UI_draw_anti_fan(float tri_array[][2], unsigned int length, const float color[4]);
-
void UI_draw_roundbox_corner_set(int type);
void UI_draw_roundbox_aa(const struct rctf *rect, bool filled, float rad, const float color[4]);
void UI_draw_roundbox_4fv(const struct rctf *rect, bool filled, float rad, const float col[4]);
@@ -431,12 +436,6 @@ void UI_draw_roundbox_3ub_alpha(const struct rctf *rect,
unsigned char alpha);
void UI_draw_roundbox_3fv_alpha(
const struct rctf *rect, bool filled, float rad, const float col[3], float alpha);
-void UI_draw_roundbox_shade_x(const struct rctf *rect,
- bool filled,
- float rad,
- float shadetop,
- float shadedown,
- const float col[4]);
void UI_draw_roundbox_4fv_ex(const struct rctf *rect,
const float inner1[4],
const float inner2[4],
@@ -452,6 +451,14 @@ int UI_draw_roundbox_corner_get(void);
void UI_draw_box_shadow(const struct rctf *rect, unsigned char alpha);
void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4]);
+/**
+ * Draw title and text safe areas.
+ *
+ * \note This function is to be used with the 2D dashed shader enabled.
+ *
+ * \param pos: is a #PRIM_FLOAT, 2, #GPU_FETCH_FLOAT vertex attribute.
+ * \param rect: The offsets for the view, not the zones.
+ */
void UI_draw_safe_areas(uint pos,
const struct rctf *rect,
const float title_aspect[2],
@@ -463,18 +470,33 @@ enum {
UI_SCROLL_ARROWS = 1 << 1,
UI_SCROLL_NO_OUTLINE = 1 << 2,
};
+/**
+ * Function in use for buttons and for view2d sliders.
+ */
void UI_draw_widget_scroll(struct uiWidgetColors *wcol,
const struct rcti *rect,
const struct rcti *slider,
int state);
-/* Shortening string helper. */
+/**
+ * Shortening string helper.
+ *
+ * Cut off the middle of the text to fit into the given width.
+ *
+ * \note in case this middle clipping would just remove a few chars,
+ * it rather clips right, which is more readable.
+ *
+ * If rpart_sep is not Null, the part of str starting to first occurrence of rpart_sep
+ * is preserved at all cost.
+ * Useful for strings with shortcuts
+ * (like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
+ */
float UI_text_clip_middle_ex(const struct uiFontStyle *fstyle,
char *str,
float okwidth,
- const float minwidth,
- const size_t max_len,
- const char rpart_sep);
+ float minwidth,
+ size_t max_len,
+ char rpart_sep);
/**
* Callbacks
@@ -504,14 +526,13 @@ typedef int (*uiButCompleteFunc)(struct bContext *C, char *str, void *arg);
typedef struct ARegion *(*uiButSearchCreateFn)(struct bContext *C,
struct ARegion *butregion,
struct uiButSearch *search_but);
-/* `is_first` is typically used to ignore search filtering when the menu is first opened in order
+/**
+ * `is_first` is typically used to ignore search filtering when the menu is first opened in order
* to display the full list of options. The value will be false after the button's text is edited
- * (for every call except the first). */
-typedef void (*uiButSearchUpdateFn)(const struct bContext *C,
- void *arg,
- const char *str,
- uiSearchItems *items,
- const bool is_first);
+ * (for every call except the first).
+ */
+typedef void (*uiButSearchUpdateFn)(
+ const struct bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first);
typedef bool (*uiButSearchContextMenuFn)(struct bContext *C,
void *arg,
void *active,
@@ -593,10 +614,11 @@ typedef void (*uiFreeArgFunc)(void *arg);
/* interface_query.c */
bool UI_but_has_tooltip_label(const uiBut *but);
bool UI_but_is_tool(const uiBut *but);
+/* file selectors are exempt from utf-8 checks */
bool UI_but_is_utf8(const uiBut *but);
#define UI_but_is_decorator(but) ((but)->type == UI_BTYPE_DECORATOR)
-bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title);
+bool UI_block_is_empty_ex(const uiBlock *block, bool skip_title);
bool UI_block_is_empty(const uiBlock *block);
bool UI_block_can_add_separator(const uiBlock *block);
@@ -614,10 +636,17 @@ struct uiList *UI_list_find_mouse_over(const struct ARegion *region, const struc
typedef struct uiPopupMenu uiPopupMenu;
uiPopupMenu *UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL();
+/**
+ * Only return handler, and set optional title.
+ * \param block_name: Assigned to uiBlock.name (useful info for debugging).
+ */
uiPopupMenu *UI_popup_menu_begin_ex(struct bContext *C,
const char *title,
const char *block_name,
int icon) ATTR_NONNULL();
+/**
+ * Set the whole structure to work.
+ */
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *pup);
bool UI_popup_menu_end_or_cancel(struct bContext *C, struct uiPopupMenu *head);
struct uiLayout *UI_popup_menu_layout(uiPopupMenu *pup);
@@ -626,7 +655,14 @@ void UI_popup_menu_reports(struct bContext *C, struct ReportList *reports) ATTR_
int UI_popup_menu_invoke(struct bContext *C, const char *idname, struct ReportList *reports)
ATTR_NONNULL(1, 2);
-void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable);
+/**
+ * Allow setting menu return value from externals.
+ * E.g. WM might need to do this for exiting files correctly.
+ */
+void UI_popup_menu_retval_set(const uiBlock *block, int retval, bool enable);
+/**
+ * Setting the button makes the popup open from the button instead of the cursor.
+ */
void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *but);
/* interface_region_popover.c */
@@ -638,8 +674,17 @@ int UI_popover_panel_invoke(struct bContext *C,
bool keep_open,
struct ReportList *reports);
+/**
+ * Only return handler, and set optional title.
+ *
+ * \param from_active_button: Use the active button for positioning,
+ * use when the popover is activated from an operator instead of directly from the button.
+ */
uiPopover *UI_popover_begin(struct bContext *C, int menu_width, bool from_active_button)
ATTR_NONNULL(1);
+/**
+ * Set the whole structure to work.
+ */
void UI_popover_end(struct bContext *C, struct uiPopover *pup, struct wmKeyMap *keymap);
struct uiLayout *UI_popover_layout(uiPopover *pup);
void UI_popover_once_clear(uiPopover *pup);
@@ -694,7 +739,7 @@ void UI_popup_block_ex(struct bContext *C,
void uiPupBlockOperator(struct bContext *C,
uiBlockCreateFunc func,
struct wmOperator *op,
- int opcontext);
+ wmOperatorCallContext opcontext);
#endif
void UI_popup_block_close(struct bContext *C, struct wmWindow *win, uiBlock *block);
@@ -717,6 +762,9 @@ uiBlock *UI_block_begin(const struct bContext *C,
eUIEmbossType 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);
+/**
+ * Uses local copy of style, to scale things down, and allow widgets to change stuff.
+ */
void UI_block_draw(const struct bContext *C, struct uiBlock *block);
void UI_blocklist_update_window_matrix(const struct bContext *C, const struct ListBase *lb);
void UI_blocklist_update_view_for_buttons(const struct bContext *C, const struct ListBase *lb);
@@ -731,19 +779,36 @@ void UI_block_theme_style_set(uiBlock *block, char theme_style);
eUIEmbossType UI_block_emboss_get(uiBlock *block);
void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss);
bool UI_block_is_search_only(const uiBlock *block);
+/**
+ * Use when a block must be searched to give accurate results
+ * for the whole region but shouldn't be displayed.
+ */
void UI_block_set_search_only(uiBlock *block, bool search_only);
+/**
+ * Can be called with C==NULL.
+ */
void UI_block_free(const struct bContext *C, uiBlock *block);
-void UI_blocklist_free(const struct bContext *C, struct ListBase *lb);
-void UI_blocklist_free_inactive(const struct bContext *C, struct ListBase *lb);
-void UI_screen_free_active_but(const struct bContext *C, struct bScreen *screen);
+/**
+ * Can be called with C==NULL.
+ */
+void UI_blocklist_free(const struct bContext *C, struct ARegion *region);
+void UI_blocklist_free_inactive(const struct bContext *C, struct ARegion *region);
+
+/**
+ * Is called by notifier.
+ */
+void UI_screen_free_active_but_highlight(const struct bContext *C, struct bScreen *screen);
+void UI_region_free_active_but_all(struct bContext *context, struct ARegion *region);
void UI_block_region_set(uiBlock *block, struct ARegion *region);
void UI_block_lock_set(uiBlock *block, bool val, const char *lockstr);
void UI_block_lock_clear(uiBlock *block);
-/* Automatic aligning, horizontal or vertical. */
+/**
+ * Automatic aligning, horizontal or vertical.
+ */
void UI_block_align_begin(uiBlock *block);
void UI_block_align_end(uiBlock *block);
@@ -758,16 +823,34 @@ typedef enum {
UI_BLOCK_BOUNDS_PIE_CENTER,
} eBlockBoundsCalc;
+/**
+ * Used for various cases.
+ */
void UI_block_bounds_set_normal(struct uiBlock *block, int addval);
+/**
+ * Used for pull-downs.
+ */
void UI_block_bounds_set_text(uiBlock *block, int addval);
+/**
+ * Used for block popups.
+ */
void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offset[2]);
+/**
+ * Used for menu popups.
+ */
void UI_block_bounds_set_menu(uiBlock *block, int addval, const int bounds_offset[2]);
+/**
+ * Used for centered popups, i.e. splash.
+ */
void UI_block_bounds_set_centered(uiBlock *block, int addval);
void UI_block_bounds_set_explicit(uiBlock *block, int minx, int miny, int maxx, int maxy);
int UI_blocklist_min_y_get(struct ListBase *lb);
void UI_block_direction_set(uiBlock *block, char direction);
+/**
+ * This call escapes if there's alignment flags.
+ */
void UI_block_order_flip(uiBlock *block);
void UI_block_flag_enable(uiBlock *block, int flag);
void UI_block_flag_disable(uiBlock *block, int flag);
@@ -776,21 +859,38 @@ void UI_block_translate(uiBlock *block, int x, int y);
int UI_but_return_value_get(uiBut *but);
void UI_but_drag_set_id(uiBut *but, struct ID *id);
+/**
+ * Set an image to display while dragging. This works for any drag type (`WM_DRAG_XXX`).
+ * Not to be confused with #UI_but_drag_set_image(), which sets up dragging of an image.
+ */
+void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, float scale);
+/**
+ * \param asset: May be passed from a temporary variable, drag data only stores a copy of this.
+ */
void UI_but_drag_set_asset(uiBut *but,
const struct AssetHandle *asset,
const char *path,
+ struct AssetMetaData *metadata,
int import_type, /* eFileAssetImportType */
int icon,
struct ImBuf *imb,
float scale);
void UI_but_drag_set_rna(uiBut *but, struct PointerRNA *ptr);
-void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free);
+void UI_but_drag_set_path(uiBut *but, const char *path, bool use_free);
void UI_but_drag_set_name(uiBut *but, const char *name);
+/**
+ * Value from button itself.
+ */
void UI_but_drag_set_value(uiBut *but);
void UI_but_drag_set_image(
- uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free);
+ uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, bool use_free);
-bool UI_but_active_drop_name(struct bContext *C);
+uiBut *UI_but_active_drop_name_button(const struct bContext *C);
+/**
+ * Returns true if highlighted button allows drop of names.
+ * called in region context.
+ */
+bool UI_but_active_drop_name(const struct bContext *C);
bool UI_but_active_drop_color(struct bContext *C);
void UI_but_flag_enable(uiBut *but, int flag);
@@ -804,20 +904,33 @@ void UI_but_disable(uiBut *but, const char *disabled_hint);
void UI_but_type_set_menu_from_pulldown(uiBut *but);
-/* special button case, only draw it when used actively, for outliner etc */
+/**
+ * Special button case, only draw it when used actively, for outliner etc.
+ *
+ * Needed for temporarily rename buttons, such as in outliner or file-select,
+ * they should keep calling #uiDefBut to keep them alive.
+ * \return false when button removed.
+ */
bool UI_but_active_only_ex(const struct bContext *C,
struct ARegion *region,
uiBlock *block,
uiBut *but,
- const bool remove_on_failure);
+ bool remove_on_failure);
bool UI_but_active_only(const struct bContext *C,
struct ARegion *region,
uiBlock *block,
uiBut *but);
+/**
+ * \warning This must run after other handlers have been added,
+ * otherwise the handler won't be removed, see: T71112.
+ */
bool UI_block_active_only_flagged_buttons(const struct bContext *C,
struct ARegion *region,
struct uiBlock *block);
+/**
+ * Simulate button click.
+ */
void UI_but_execute(const struct bContext *C, struct ARegion *region, uiBut *but);
bool UI_but_online_manual_id(const uiBut *but,
@@ -866,21 +979,6 @@ uiBut *uiDefButF(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefButI(uiBlock *block,
int type,
int retval,
@@ -1003,7 +1101,7 @@ uiBut *uiDefButR_prop(uiBlock *block,
uiBut *uiDefButO(uiBlock *block,
int type,
const char *opname,
- int opcontext,
+ wmOperatorCallContext opcontext,
const char *str,
int x,
int y,
@@ -1013,7 +1111,7 @@ uiBut *uiDefButO(uiBlock *block,
uiBut *uiDefButO_ptr(uiBlock *block,
int type,
struct wmOperatorType *ot,
- int opcontext,
+ wmOperatorCallContext opcontext,
const char *str,
int x,
int y,
@@ -1021,6 +1119,9 @@ uiBut *uiDefButO_ptr(uiBlock *block,
short height,
const char *tip);
+/**
+ * If a1==1.0 then a2 is an extra icon blending factor (alpha 0.0 - 1.0).
+ */
uiBut *uiDefIconBut(uiBlock *block,
int type,
int retval,
@@ -1035,35 +1136,6 @@ uiBut *uiDefIconBut(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconButF(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconButI(uiBlock *block,
int type,
int retval,
@@ -1122,20 +1194,6 @@ uiBut *uiDefIconButBitS(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconButBitC(uiBlock *block,
int type,
int bit,
@@ -1186,7 +1244,7 @@ uiBut *uiDefIconButR_prop(uiBlock *block,
uiBut *uiDefIconButO(uiBlock *block,
int type,
const char *opname,
- int opcontext,
+ wmOperatorCallContext opcontext,
int icon,
int x,
int y,
@@ -1196,7 +1254,7 @@ uiBut *uiDefIconButO(uiBlock *block,
uiBut *uiDefIconButO_ptr(uiBlock *block,
int type,
struct wmOperatorType *ot,
- int opcontext,
+ wmOperatorCallContext opcontext,
int icon,
int x,
int y,
@@ -1206,6 +1264,7 @@ uiBut *uiDefIconButO_ptr(uiBlock *block,
uiBut *uiDefButImage(
uiBlock *block, void *imbuf, int x, int y, short width, short height, const uchar color[4]);
uiBut *uiDefButAlert(uiBlock *block, int icon, int x, int y, short width, short height);
+/* Button containing both string label and icon */
uiBut *uiDefIconTextBut(uiBlock *block,
int type,
int retval,
@@ -1236,22 +1295,6 @@ uiBut *uiDefIconTextButF(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconTextButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconTextButI(uiBlock *block,
int type,
int retval,
@@ -1267,84 +1310,6 @@ uiBut *uiDefIconTextButI(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconTextButBitI(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- int *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButS(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButBitS(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButBitC(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconTextButR(uiBlock *block,
int type,
int retval,
@@ -1382,7 +1347,7 @@ uiBut *uiDefIconTextButR_prop(uiBlock *block,
uiBut *uiDefIconTextButO(uiBlock *block,
int type,
const char *opname,
- int opcontext,
+ wmOperatorCallContext opcontext,
int icon,
const char *str,
int x,
@@ -1393,7 +1358,7 @@ uiBut *uiDefIconTextButO(uiBlock *block,
uiBut *uiDefIconTextButO_ptr(uiBlock *block,
int type,
struct wmOperatorType *ot,
- int opcontext,
+ wmOperatorCallContext opcontext,
int icon,
const char *str,
int x,
@@ -1405,7 +1370,7 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block,
/* for passing inputs to ButO buttons */
struct PointerRNA *UI_but_operator_ptr_get(uiBut *but);
-void UI_but_unit_type_set(uiBut *but, const int unit_type);
+void UI_but_unit_type_set(uiBut *but, int unit_type);
int UI_but_unit_type_get(const uiBut *but);
typedef enum uiStringInfoType {
@@ -1432,6 +1397,8 @@ typedef struct uiStringInfo {
* Will fill them with translated strings, when possible.
* Strings in uiStringInfo must be MEM_freeN'ed by caller. */
void UI_but_string_info_get(struct bContext *C, uiBut *but, ...) ATTR_SENTINEL(0);
+void UI_but_extra_icon_string_info_get(struct bContext *C, uiButExtraOpIcon *extra_icon, ...)
+ ATTR_SENTINEL(0);
/* Edit i18n stuff. */
/* Name of the main py op from i18n addon. */
@@ -1474,7 +1441,10 @@ enum {
UI_TEMPLATE_ID_FILTER_AVAILABLE = 1,
};
+/***************************** ID Utilities *******************************/
+
int UI_icon_from_id(const struct ID *id);
+/** See: #BKE_report_type_str */
int UI_icon_from_report_type(int type);
int UI_icon_colorid_from_report_type(int type);
int UI_text_colorid_from_report_type(int type);
@@ -1539,6 +1509,9 @@ uiBut *uiDefBlockButN(uiBlock *block,
short height,
const char *tip);
+/**
+ * Block button containing icon.
+ */
uiBut *uiDefIconBlockBut(uiBlock *block,
uiBlockCreateFunc func,
void *arg,
@@ -1549,6 +1522,9 @@ uiBut *uiDefIconBlockBut(uiBlock *block,
short width,
short height,
const char *tip);
+/**
+ * Block button containing both string label and icon.
+ */
uiBut *uiDefIconTextBlockBut(uiBlock *block,
uiBlockCreateFunc func,
void *arg,
@@ -1569,6 +1545,11 @@ uiBut *uiDefKeyevtButS(uiBlock *block,
short height,
short *spoin,
const char *tip);
+
+/**
+ * Short pointers hard-coded.
+ * \param modkeypoin: will be set to #KM_SHIFT, #KM_ALT, #KM_CTRL, #KM_OSKEY bits.
+ */
uiBut *uiDefHotKeyevtButS(uiBlock *block,
int retval,
const char *str,
@@ -1580,6 +1561,10 @@ uiBut *uiDefHotKeyevtButS(uiBlock *block,
const short *modkeypoin,
const char *tip);
+/**
+ * \param arg: A pointer to string/name, use #UI_but_func_search_set() below to make this work.
+ * here `a1` and `a2`, if set, control thumbnail preview rows/cols.
+ */
uiBut *uiDefSearchBut(uiBlock *block,
void *arg,
int retval,
@@ -1592,6 +1577,10 @@ uiBut *uiDefSearchBut(uiBlock *block,
float a1,
float a2,
const char *tip);
+/**
+ * Same parameters as for #uiDefSearchBut, with additional operator type and properties,
+ * used by callback to call again the right op with the right options (properties values).
+ */
uiBut *uiDefSearchButO_ptr(uiBlock *block,
struct wmOperatorType *ot,
struct IDProperty *properties,
@@ -1635,6 +1624,12 @@ uiBut *uiDefAutoButR(uiBlock *block,
int y,
int width,
int height);
+/**
+ * \a check_prop callback filters functions to avoid drawing certain properties,
+ * in cases where PROP_HIDDEN flag can't be used for a property.
+ *
+ * \param prop_activate_init: Property to activate on initial popup (#UI_BUT_ACTIVATE_ON_INIT).
+ */
eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
struct PointerRNA *ptr,
bool (*check_prop)(struct PointerRNA *ptr,
@@ -1643,41 +1638,75 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
void *user_data,
struct PropertyRNA *prop_activate_init,
eButLabelAlign label_align,
- const bool compact);
+ bool compact);
-/* use inside searchfunc to add items */
+/**
+ * Public function exported for functions that use #UI_BTYPE_SEARCH_MENU.
+ *
+ * Use inside searchfunc to add items.
+ *
+ * \param items: Stores the items.
+ * \param name: Text to display for the item.
+ * \param poin: Opaque pointer (for use by the caller).
+ * \param iconid: The icon, #ICON_NONE for no icon.
+ * \param state: The buttons state flag, compatible with #uiBut.flag,
+ * typically #UI_BUT_DISABLED / #UI_BUT_INACTIVE.
+ * \return false if there is nothing to add.
+ */
bool UI_search_item_add(uiSearchItems *items,
const char *name,
void *poin,
int iconid,
int state,
- const uint8_t name_prefix_offset);
+ uint8_t name_prefix_offset);
+/**
+ * \note The item-pointer (referred to below) is a per search item user pointer
+ * passed to #UI_search_item_add (stored in #uiSearchItems.pointers).
+ *
+ * \param search_create_fn: Function to create the menu.
+ * \param search_update_fn: Function to refresh search content after the search text has changed.
+ * \param arg: user value.
+ * \param free_arg: Set to true if the argument is newly allocated memory for every redraw and
+ * should be freed when the button is destroyed.
+ * \param search_arg_free_fn: When non-null, use this function to free \a arg.
+ * \param search_exec_fn: Function that executes the action, gets \a arg as the first argument.
+ * The second argument as the active item-pointer
+ * \param active: When non-null, this item-pointer item will be visible and selected,
+ * otherwise the first item will be selected.
+ */
void UI_but_func_search_set(uiBut *but,
uiButSearchCreateFn search_create_fn,
uiButSearchUpdateFn search_update_fn,
void *arg,
- const bool free_arg,
+ bool free_arg,
uiFreeArgFunc search_arg_free_fn,
uiButHandleFunc search_exec_fn,
void *active);
void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn);
void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn);
+/**
+ * \param search_sep_string: when not NULL, this string is used as a separator,
+ * showing the icon and highlighted text after the last instance of this string.
+ */
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string);
-void UI_but_func_search_set_results_are_suggestions(uiBut *but, const bool value);
+void UI_but_func_search_set_results_are_suggestions(uiBut *but, bool value);
-/* height in pixels, it's using hardcoded values still */
+/**
+ * Height in pixels, it's using hard-coded values still.
+ */
int UI_searchbox_size_y(void);
int UI_searchbox_size_x(void);
-/* check if a string is in an existing search box */
+/**
+ * Check if a string is in an existing search box.
+ */
int UI_search_items_find_index(uiSearchItems *items, const char *name);
+/**
+ * Adds a hint to the button which draws right aligned, grayed out and never clipped.
+ */
void UI_but_hint_drawstr_set(uiBut *but, const char *string);
-void UI_but_datasetrow_indentation_set(uiBut *but, int indentation);
-void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type);
-void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain);
-uint8_t UI_but_datasetrow_component_get(uiBut *but);
-uint8_t UI_but_datasetrow_domain_get(uiBut *but);
+
void UI_but_treerow_indentation_set(uiBut *but, int indentation);
void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]);
@@ -1705,7 +1734,14 @@ void UI_but_func_drawextra_set(
void UI_but_func_menu_step_set(uiBut *but, uiMenuStepFunc func);
void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *arg, uiFreeArgFunc free_arg);
+/**
+ * Recreate tool-tip (use to update dynamic tips)
+ */
void UI_but_tooltip_refresh(struct bContext *C, uiBut *but);
+/**
+ * Removes tool-tip timer from active but
+ * (meaning tool-tip is disabled until it's re-enabled again).
+ */
void UI_but_tooltip_timer_remove(struct bContext *C, uiBut *but);
bool UI_textbutton_activate_rna(const struct bContext *C,
@@ -1714,6 +1750,10 @@ bool UI_textbutton_activate_rna(const struct bContext *C,
const char *rna_prop_id);
bool UI_textbutton_activate_but(const struct bContext *C, uiBut *but);
+/**
+ * push a new event onto event queue to activate the given button
+ * (usually a text-field) upon entering a popup
+ */
void UI_but_focus_on_enter_event(struct wmWindow *win, uiBut *but);
void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN);
@@ -1722,8 +1762,10 @@ void UI_but_func_pushed_state_set(uiBut *but, uiButPushedStateFunc func, const v
struct PointerRNA *UI_but_extra_operator_icon_add(uiBut *but,
const char *opname,
- short opcontext,
+ wmOperatorCallContext opcontext,
int icon);
+struct wmOperatorType *UI_but_extra_operator_icon_optype_get(struct uiButExtraOpIcon *extra_icon);
+struct PointerRNA *UI_but_extra_operator_icon_opptr_get(struct uiButExtraOpIcon *extra_icon);
/* Autocomplete
*
@@ -1749,25 +1791,60 @@ int UI_autocomplete_end(AutoComplete *autocpl, char *autoname);
void UI_panels_begin(const struct bContext *C, struct ARegion *region);
void UI_panels_end(const struct bContext *C, struct ARegion *region, int *r_x, int *r_y);
+/**
+ * Draw panels, selected (panels currently being dragged) on top.
+ */
void UI_panels_draw(const struct bContext *C, struct ARegion *region);
struct Panel *UI_panel_find_by_type(struct ListBase *lb, const struct PanelType *pt);
+/**
+ * \note \a panel should be return value from #UI_panel_find_by_type and can be NULL.
+ */
struct Panel *UI_panel_begin(struct ARegion *region,
struct ListBase *lb,
uiBlock *block,
struct PanelType *pt,
struct Panel *panel,
bool *r_open);
+/**
+ * Create the panel header button group, used to mark which buttons are part of
+ * panel headers for the panel search process that happens later. This Should be
+ * called before adding buttons for the panel's header layout.
+ */
void UI_panel_header_buttons_begin(struct Panel *panel);
+/**
+ * Finish the button group for the panel header to avoid putting panel body buttons in it.
+ */
void UI_panel_header_buttons_end(struct Panel *panel);
void UI_panel_end(struct Panel *panel, int width, int height);
+/**
+ * Set a context for this entire panel and its current layout. This should be used whenever panel
+ * callbacks that are called outside of regular drawing might require context. Currently it affects
+ * the #PanelType.reorder callback only.
+ */
+void UI_panel_context_pointer_set(struct Panel *panel, const char *name, struct PointerRNA *ptr);
+
+/**
+ * Get the panel's expansion state, taking into account
+ * expansion set from property search if it applies.
+ */
bool UI_panel_is_closed(const struct Panel *panel);
bool UI_panel_is_active(const struct Panel *panel);
+/**
+ * For button layout next to label.
+ */
void UI_panel_label_offset(const struct uiBlock *block, int *r_x, int *r_y);
+bool UI_panel_should_show_background(const struct ARegion *region,
+ const struct PanelType *panel_type);
int UI_panel_size_y(const struct Panel *panel);
bool UI_panel_is_dragging(const struct Panel *panel);
+/**
+ * Find whether a panel or any of its sub-panels contain a property that matches the search filter,
+ * depending on the search process running in #UI_block_apply_search_filter earlier.
+ */
bool UI_panel_matches_search_filter(const struct Panel *panel);
+bool UI_panel_can_be_pinned(const struct Panel *panel);
bool UI_panel_category_is_visible(const struct ARegion *region);
void UI_panel_category_add(struct ARegion *region, const char *name);
@@ -1778,6 +1855,9 @@ const char *UI_panel_category_active_get(struct ARegion *region, bool set_fallba
void UI_panel_category_active_set(struct ARegion *region, const char *idname);
void UI_panel_category_active_set_default(struct ARegion *region, const char *idname);
void UI_panel_category_clear_all(struct ARegion *region);
+/**
+ * Draw vertical tabs on the left side of the region, one tab per category.
+ */
void UI_panel_category_draw_all(struct ARegion *region, const char *category_id_active);
/* Panel custom data. */
@@ -1787,17 +1867,40 @@ struct PointerRNA *UI_region_panel_custom_data_under_cursor(const struct bContex
void UI_panel_custom_data_set(struct Panel *panel, struct PointerRNA *custom_data);
/* Polyinstantiated panels for representing a list of data. */
+/**
+ * Called in situations where panels need to be added dynamically rather than
+ * having only one panel corresponding to each #PanelType.
+ */
struct Panel *UI_panel_add_instanced(const struct bContext *C,
struct ARegion *region,
struct ListBase *panels,
const char *panel_idname,
struct PointerRNA *custom_data);
+/**
+ * Remove instanced panels from the region's panel list.
+ *
+ * \note Can be called with NULL \a C, but it should be avoided because
+ * handlers might not be removed.
+ */
void UI_panels_free_instanced(const struct bContext *C, struct ARegion *region);
#define INSTANCED_PANEL_UNIQUE_STR_LEN 16
+/**
+ * Find a unique key to append to the #PanelType.idname for the lookup to the panel's #uiBlock.
+ * Needed for instanced panels, where there can be multiple with the same type and identifier.
+ */
void UI_list_panel_unique_str(struct Panel *panel, char *r_name);
typedef void (*uiListPanelIDFromDataFunc)(void *data_link, char *r_idname);
+/**
+ * Check if the instanced panels in the region's panels correspond to the list of data the panels
+ * represent. Returns false if the panels have been reordered or if the types from the list data
+ * don't match in any way.
+ *
+ * \param data: The list of data to check against the instanced panels.
+ * \param panel_idname_func: Function to find the #PanelType.idname for each item in the data list.
+ * For a readability and generality, this lookup happens separately for each type of panel list.
+ */
bool UI_panel_list_matches_data(struct ARegion *region,
struct ListBase *data,
uiListPanelIDFromDataFunc panel_idname_func);
@@ -1812,7 +1915,7 @@ void UI_region_handlers_add(struct ListBase *handlers);
void UI_popup_handlers_add(struct bContext *C,
struct ListBase *handlers,
uiPopupBlockHandle *popup,
- const char flag);
+ char flag);
void UI_popup_handlers_remove(struct ListBase *handlers, uiPopupBlockHandle *popup);
void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers);
@@ -1822,6 +1925,7 @@ void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers)
* be used to reinitialize some internal state if user preferences change. */
void UI_init(void);
+/* after reading userdef file */
void UI_init_userdef(void);
void UI_reinit_font(void);
void UI_exit(void);
@@ -1937,8 +2041,19 @@ uiLayout *UI_block_layout(uiBlock *block,
const struct uiStyle *style);
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout);
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y);
+bool UI_block_layout_needs_resolving(const uiBlock *block);
+/**
+ * Used for property search when the layout process needs to be cancelled in order to avoid
+ * computing the locations for buttons, but the layout items created while adding the buttons
+ * must still be freed.
+ */
void UI_block_layout_free(uiBlock *block);
+/**
+ * Apply property search behavior, setting panel flags and deactivating buttons that don't match.
+ *
+ * \note Must not be run after #UI_block_layout_resolve.
+ */
bool UI_block_apply_search_filter(uiBlock *block, const char *search_filter);
void UI_region_message_subscribe(struct ARegion *region, struct wmMsgBus *mbus);
@@ -1949,17 +2064,29 @@ void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv);
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, struct PointerRNA *ptr);
struct bContextStore *uiLayoutGetContextStore(uiLayout *layout);
void uiLayoutContextCopy(uiLayout *layout, struct bContextStore *context);
+/**
+ * This is a bit of a hack but best keep it in one place at least.
+ */
struct wmOperatorType *UI_but_operatortype_get_from_enum_menu(struct uiBut *but,
struct PropertyRNA **r_prop);
+/**
+ * This is a bit of a hack but best keep it in one place at least.
+ */
struct MenuType *UI_but_menutype_get(uiBut *but);
+/**
+ * This is a bit of a hack but best keep it in one place at least.
+ */
struct PanelType *UI_but_paneltype_get(uiBut *but);
void UI_menutype_draw(struct bContext *C, struct MenuType *mt, struct uiLayout *layout);
+/**
+ * Used for popup panels only.
+ */
void UI_paneltype_draw(struct bContext *C, struct PanelType *pt, struct uiLayout *layout);
/* Only for convenience. */
void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but);
-void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext);
+void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext);
void uiLayoutSetActive(uiLayout *layout, bool active);
void uiLayoutSetActiveDefault(uiLayout *layout, bool active_default);
void uiLayoutSetActivateInit(uiLayout *layout, bool activate_init);
@@ -1995,10 +2122,20 @@ eUIEmbossType uiLayoutGetEmboss(uiLayout *layout);
bool uiLayoutGetPropSep(uiLayout *layout);
bool uiLayoutGetPropDecorate(uiLayout *layout);
-/* layout specifiers */
+/* Layout create functions. */
+
uiLayout *uiLayoutRow(uiLayout *layout, bool align);
+/**
+ * See #uiLayoutColumnWithHeading().
+ */
uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading);
uiLayout *uiLayoutColumn(uiLayout *layout, bool align);
+/**
+ * Variant of #uiLayoutColumn() that sets a heading label for the layout if the first item is
+ * added through #uiItemFullR(). If split layout is used and the item has no string to add to the
+ * first split-column, the heading is added there instead. Otherwise the heading inserted with a
+ * new row.
+ */
uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading);
uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align);
uiLayout *uiLayoutGridFlow(uiLayout *layout,
@@ -2028,7 +2165,7 @@ void uiTemplateID(uiLayout *layout,
const char *openop,
const char *unlinkop,
int filter,
- const bool live_icon,
+ bool live_icon,
const char *text);
void uiTemplateIDBrowse(uiLayout *layout,
struct bContext *C,
@@ -2049,7 +2186,10 @@ void uiTemplateIDPreview(uiLayout *layout,
int rows,
int cols,
int filter,
- const bool hide_buttons);
+ bool hide_buttons);
+/**
+ * Version of #uiTemplateID using tabs.
+ */
void uiTemplateIDTabs(uiLayout *layout,
struct bContext *C,
struct PointerRNA *ptr,
@@ -2057,11 +2197,23 @@ void uiTemplateIDTabs(uiLayout *layout,
const char *newop,
const char *menu,
int filter);
+/**
+ * This is for selecting the type of ID-block to use,
+ * and then from the relevant type choosing the block to use.
+ *
+ * \param propname: property identifier for property that ID-pointer gets stored to.
+ * \param proptypename: property identifier for property
+ * used to determine the type of ID-pointer that can be used.
+ */
void uiTemplateAnyID(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
const char *proptypename,
const char *text);
+/**
+ * Search menu to pick an item from a collection.
+ * A version of uiTemplateID that works for non-ID types.
+ */
void uiTemplateSearch(uiLayout *layout,
struct bContext *C,
struct PointerRNA *ptr,
@@ -2078,8 +2230,15 @@ void uiTemplateSearchPreview(uiLayout *layout,
const char *searchpropname,
const char *newop,
const char *unlinkop,
- const int rows,
- const int cols);
+ int rows,
+ int cols);
+/**
+ * This is creating/editing RNA-Paths
+ *
+ * - ptr: struct which holds the path property
+ * - propname: property identifier for property that path gets stored to
+ * - root_ptr: struct that path gets built from
+ */
void uiTemplatePathBuilder(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
@@ -2087,7 +2246,13 @@ void uiTemplatePathBuilder(uiLayout *layout,
const char *text);
void uiTemplateModifiers(uiLayout *layout, struct bContext *C);
void uiTemplateGpencilModifiers(uiLayout *layout, struct bContext *C);
+/**
+ * Check if the shader effect panels don't match the data and rebuild the panels if so.
+ */
void uiTemplateShaderFx(uiLayout *layout, struct bContext *C);
+/**
+ * Check if the constraint panels don't match the data and rebuild the panels if so.
+ */
void uiTemplateConstraints(uiLayout *layout, struct bContext *C, bool use_bone_constraints);
uiLayout *uiTemplateGpencilModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
@@ -2114,7 +2279,13 @@ void uiTemplateColorRamp(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
bool expand);
+/**
+ * \param icon_scale: Scale of the icon, 1x == button height.
+ */
void uiTemplateIcon(uiLayout *layout, int icon_value, float icon_scale);
+/**
+ * \param icon_scale: Scale of the icon, 1x == button height.
+ */
void uiTemplateIconView(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
@@ -2132,7 +2303,14 @@ void uiTemplateCurveMapping(uiLayout *layout,
bool brush,
bool neg_slope,
bool tone);
+/**
+ * Template for a path creation widget intended for custom bevel profiles.
+ * This section is quite similar to #uiTemplateCurveMapping, but with reduced complexity.
+ */
void uiTemplateCurveProfile(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
+/**
+ * This template now follows User Preference for type - name is not correct anymore.
+ */
void uiTemplateColorPicker(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
@@ -2148,6 +2326,10 @@ void uiTemplateCryptoPicker(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
int icon);
+/**
+ * \todo for now, grouping of layers is determined by dividing up the length of
+ * the array of layer bitflags
+ */
void uiTemplateLayers(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
@@ -2182,6 +2364,11 @@ void uiTemplateOperatorSearch(uiLayout *layout);
void UI_but_func_menu_search(uiBut *but);
void uiTemplateMenuSearch(uiLayout *layout);
+/**
+ * Draw Operator property buttons for redoing execution with different settings.
+ * This function does not initialize the layout,
+ * functions can be called on the layout before and after.
+ */
void uiTemplateOperatorPropertyButs(const struct bContext *C,
uiLayout *layout,
struct wmOperator *op,
@@ -2203,11 +2390,49 @@ void uiTemplateComponentMenu(uiLayout *layout,
const char *propname,
const char *name);
void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float color[4]);
+
+/**
+ * Draw the main CacheFile properties and operators (file path, scale, etc.), that is those which
+ * do not have their own dedicated template functions.
+ */
void uiTemplateCacheFile(uiLayout *layout,
const struct bContext *C,
struct PointerRNA *ptr,
const char *propname);
+/**
+ * Lookup the CacheFile PointerRNA of the given pointer and return it in the output parameter.
+ * Returns true if `ptr` has a RNACacheFile, false otherwise. If false, the output parameter is not
+ * initialized.
+ */
+bool uiTemplateCacheFilePointer(struct PointerRNA *ptr,
+ const char *propname,
+ struct PointerRNA *r_file_ptr);
+
+/**
+ * Draw the velocity related properties of the CacheFile.
+ */
+void uiTemplateCacheFileVelocity(uiLayout *layout, struct PointerRNA *fileptr);
+
+/**
+ * Draw the render procedural related properties of the CacheFile.
+ */
+void uiTemplateCacheFileProcedural(uiLayout *layout,
+ const struct bContext *C,
+ struct PointerRNA *fileptr);
+
+/**
+ * Draw the time related properties of the CacheFile.
+ */
+void uiTemplateCacheFileTimeSettings(uiLayout *layout, struct PointerRNA *fileptr);
+
+/**
+ * Draw the override layers related properties of the CacheFile.
+ */
+void uiTemplateCacheFileLayers(uiLayout *layout,
+ const struct bContext *C,
+ struct PointerRNA *fileptr);
+
/* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
enum uiTemplateListFlags {
@@ -2267,6 +2492,9 @@ void uiTemplateNodeView(uiLayout *layout,
struct bNode *node,
struct bNodeSocket *input);
void uiTemplateTextureUser(uiLayout *layout, struct bContext *C);
+/**
+ * Button to quickly show texture in Properties Editor texture tab.
+ */
void uiTemplateTextureShow(uiLayout *layout,
const struct bContext *C,
struct PointerRNA *ptr,
@@ -2317,15 +2545,21 @@ void uiTemplateAssetView(struct uiLayout *layout,
struct PointerRNA *active_dataptr,
const char *active_propname,
const struct AssetFilterSettings *filter_settings,
- const int display_flags,
+ int display_flags,
const char *activate_opname,
struct PointerRNA *r_activate_op_properties,
const char *drag_opname,
struct PointerRNA *r_drag_op_properties);
+/**
+ * \return: A RNA pointer for the operator properties.
+ */
struct PointerRNA *UI_list_custom_activate_operator_set(struct uiList *ui_list,
const char *opname,
bool create_properties);
+/**
+ * \return: A RNA pointer for the operator properties.
+ */
struct PointerRNA *UI_list_custom_drag_operator_set(struct uiList *ui_list,
const char *opname,
bool create_properties);
@@ -2344,6 +2578,9 @@ void uiItemEnumO(uiLayout *layout,
int icon,
const char *propname,
int value);
+/**
+ * For use in cases where we have.
+ */
void uiItemEnumO_value(uiLayout *layout,
const char *name,
int icon,
@@ -2387,7 +2624,7 @@ void uiItemFullO_ptr(uiLayout *layout,
const char *name,
int icon,
struct IDProperty *properties,
- int context,
+ wmOperatorCallContext context,
int flag,
struct PointerRNA *r_opptr);
void uiItemFullO(uiLayout *layout,
@@ -2395,7 +2632,7 @@ void uiItemFullO(uiLayout *layout,
const char *name,
int icon,
struct IDProperty *properties,
- int context,
+ wmOperatorCallContext context,
int flag,
struct PointerRNA *r_opptr);
void uiItemFullOMenuHold_ptr(uiLayout *layout,
@@ -2403,7 +2640,7 @@ void uiItemFullOMenuHold_ptr(uiLayout *layout,
const char *name,
int icon,
struct IDProperty *properties,
- int context,
+ wmOperatorCallContext context,
int flag,
const char *menu_id, /* extra menu arg. */
struct PointerRNA *r_opptr);
@@ -2422,6 +2659,9 @@ void uiItemFullR(uiLayout *layout,
int flag,
const char *name,
int icon);
+/**
+ * Use a wrapper function since re-implementing all the logic in this function would be messy.
+ */
void uiItemFullR_with_popover(uiLayout *layout,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
@@ -2483,14 +2723,19 @@ void uiItemsFullEnumO(uiLayout *layout,
const char *opname,
const char *propname,
struct IDProperty *properties,
- int context,
+ wmOperatorCallContext context,
int flag);
+/**
+ * Create UI items for enum items in \a item_array.
+ *
+ * A version of #uiItemsFullEnumO that takes pre-calculated item array.
+ */
void uiItemsFullEnumO_items(uiLayout *layout,
struct wmOperatorType *ot,
struct PointerRNA ptr,
struct PropertyRNA *prop,
struct IDProperty *properties,
- int context,
+ wmOperatorCallContext context,
int flag,
const struct EnumPropertyItem *item_array,
int totitem);
@@ -2501,33 +2746,58 @@ typedef struct uiPropertySplitWrapper {
uiLayout *decorate_column;
} uiPropertySplitWrapper;
+/**
+ * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where the
+ * logic is needed. Ideally, #uiItemFullR() could just call this, but it currently has too many
+ * special needs.
+ */
uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout);
void uiItemL(uiLayout *layout, const char *name, int icon); /* label */
-void uiItemL_ex(
- uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert);
+void uiItemL_ex(uiLayout *layout, const char *name, int icon, bool highlight, bool redalert);
+/**
+ * Helper to add a label and creates a property split layout if needed.
+ */
uiLayout *uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon);
-/* label icon for dragging */
+/**
+ * Label icon for dragging.
+ */
void uiItemLDrag(uiLayout *layout, struct PointerRNA *ptr, const char *name, int icon);
-/* menu */
+/**
+ * Menu.
+ */
void uiItemM_ptr(uiLayout *layout, struct MenuType *mt, const char *name, int icon);
void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon);
-/* menu contents */
+/**
+ * Menu contents.
+ */
void uiItemMContents(uiLayout *layout, const char *menuname);
-/* Decorators */
+
+/* Decorators. */
+
+/**
+ * Insert a decorator item for a button with the same property as \a prop.
+ * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a prop.
+ */
void uiItemDecoratorR_prop(uiLayout *layout,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
int index);
+/**
+ * Insert a decorator item for a button with the same property as \a prop.
+ * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a propname.
+ */
void uiItemDecoratorR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int index);
-/* value */
+/** Value item */
void uiItemV(uiLayout *layout, const char *name, int icon, int argval);
-/* separator */
+/** Separator item */
void uiItemS(uiLayout *layout);
+/** Separator item */
void uiItemS_ex(uiLayout *layout, float factor);
-/* Special separator. */
+/** Flexible spacing. */
void uiItemSpacer(uiLayout *layout);
+/* popover */
void uiItemPopoverPanel_ptr(
uiLayout *layout, const struct bContext *C, struct PanelType *pt, const char *name, int icon);
void uiItemPopoverPanel(uiLayout *layout,
@@ -2542,7 +2812,13 @@ void uiItemPopoverPanelFromGroup(uiLayout *layout,
const char *context,
const char *category);
+/**
+ * Level items.
+ */
void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg);
+/**
+ * Version of #uiItemMenuF that free's `argN`.
+ */
void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *argN);
void uiItemMenuEnumFullO_ptr(uiLayout *layout,
struct bContext *C,
@@ -2580,10 +2856,16 @@ void uiItemTabsEnumR_prop(uiLayout *layout,
bool icon_only);
/* Only for testing, inspecting layouts. */
+/**
+ * Evaluate layout items as a Python dictionary.
+ */
const char *UI_layout_introspect(uiLayout *layout);
-/* Helper to add a big icon and create a split layout for alert boxes. */
-uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon);
+/**
+ * Helper to add a big icon and create a split layout for alert popups.
+ * Returns the layout to place further items into the alert box.
+ */
+uiLayout *uiItemsAlertBox(uiBlock *block, int size, eAlertIcon icon);
/* UI Operators */
typedef struct uiDragColorHandle {
@@ -2592,7 +2874,11 @@ typedef struct uiDragColorHandle {
} uiDragColorHandle;
void ED_operatortypes_ui(void);
+/**
+ * \brief User Interface Keymap
+ */
void ED_keymap_ui(struct wmKeyConfig *keyconf);
+void ED_dropboxes_ui(void);
void ED_uilisttypes_ui(void);
void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop);
@@ -2604,10 +2890,28 @@ bool UI_context_copy_to_selected_list(struct bContext *C,
struct ListBase *r_lb,
bool *r_use_path_from_id,
char **r_path);
+bool UI_context_copy_to_selected_check(struct PointerRNA *ptr,
+ struct PointerRNA *ptr_link,
+ struct PropertyRNA *prop,
+ const char *path,
+ bool use_path_from_id,
+ struct PointerRNA *r_ptr,
+ struct PropertyRNA **r_prop);
/* Helpers for Operators */
uiBut *UI_context_active_but_get(const struct bContext *C);
+/**
+ * Version of #UI_context_active_get() that uses the result of #CTX_wm_menu()
+ * if set. Does not traverse into parent menus, which may be wanted in some
+ * cases.
+ */
uiBut *UI_context_active_but_get_respect_menu(const struct bContext *C);
+/**
+ * Version of #UI_context_active_but_get that also returns RNA property info.
+ * Helper function for insert keyframe, reset to default, etc operators.
+ *
+ * \return active button, NULL if none found or if it doesn't contain valid RNA data.
+ */
uiBut *UI_context_active_but_prop_get(const struct bContext *C,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop,
@@ -2616,12 +2920,18 @@ void UI_context_active_but_prop_handle(struct bContext *C);
void UI_context_active_but_clear(struct bContext *C, struct wmWindow *win, struct ARegion *region);
struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
+/**
+ * Helper function for insert keyframe, reset to default, etc operators.
+ */
void UI_context_update_anim_flag(const struct bContext *C);
void UI_context_active_but_prop_get_filebrowser(const struct bContext *C,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop,
bool *r_is_undo,
bool *r_is_userdef);
+/**
+ * For new/open operators.
+ */
void UI_context_active_but_prop_get_templateID(struct bContext *C,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop);
@@ -2632,6 +2942,9 @@ uiBut *UI_region_but_find_rect_over(const struct ARegion *region, const struct r
uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region,
const int xy[2],
bool only_clip);
+/**
+ * Try to find a search-box region opened from a button in \a button_region.
+ */
struct ARegion *UI_region_searchbox_region_get(const struct ARegion *button_region);
/* uiFontStyle.align */
@@ -2651,23 +2964,37 @@ void UI_fontstyle_set(const struct uiFontStyle *fs);
void UI_fontstyle_draw_ex(const struct uiFontStyle *fs,
const struct rcti *rect,
const char *str,
+ size_t str_len,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params,
- size_t len,
int *r_xofs,
int *r_yofs,
struct ResultBLF *r_info);
+
void UI_fontstyle_draw(const struct uiFontStyle *fs,
const struct rcti *rect,
const char *str,
+ size_t str_len,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params);
+/**
+ * Drawn same as above, but at 90 degree angle.
+ */
void UI_fontstyle_draw_rotated(const struct uiFontStyle *fs,
const struct rcti *rect,
const char *str,
const uchar col[4]);
+/**
+ * Similar to #UI_fontstyle_draw
+ * but ignore alignment, shadow & no clipping rect.
+ *
+ * For drawing on-screen labels.
+ */
void UI_fontstyle_draw_simple(
const struct uiFontStyle *fs, float x, float y, const char *str, const uchar col[4]);
+/**
+ * Same as #UI_fontstyle_draw but draw a colored backdrop.
+ */
void UI_fontstyle_draw_simple_backdrop(const struct uiFontStyle *fs,
float x,
float y,
@@ -2675,12 +3002,32 @@ void UI_fontstyle_draw_simple_backdrop(const struct uiFontStyle *fs,
const float col_fg[4],
const float col_bg[4]);
-int UI_fontstyle_string_width(const struct uiFontStyle *fs, const char *str);
+int UI_fontstyle_string_width(const struct uiFontStyle *fs,
+ const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+/**
+ * Return the width of `str` with the spacing & kerning of `fs` with `aspect`
+ * (representing #uiBlock.aspect) applied.
+ *
+ * When calculating text width, the UI layout logic calculate widths without scale,
+ * only applying scale when drawing. This causes problems for fonts since kerning at
+ * smaller sizes often makes them wider than a scaled down version of the larger text.
+ * Resolve this by calculating the text at the on-screen size,
+ * returning the result scaled back to 1:1. See T92361.
+ */
+int UI_fontstyle_string_width_with_block_aspect(const struct uiFontStyle *fs,
+ const char *str,
+ float aspect) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL(1, 2);
int UI_fontstyle_height_max(const struct uiFontStyle *fs);
+/**
+ * Triangle 'icon' for panel header and other cases.
+ */
void UI_draw_icon_tri(float x, float y, char dir, const float[4]);
-const struct uiStyle *UI_style_get(void); /* use for fonts etc */
+/* XXX: read a style configure */
+const struct uiStyle *UI_style_get(void); /* use for fonts etc */
+/* for drawing, scaled with DPI setting */
const struct uiStyle *UI_style_get_dpi(void); /* DPI scaled settings for drawing */
/* linker workaround ack! */
@@ -2689,29 +3036,65 @@ void UI_template_fix_linking(void);
/* UI_OT_editsource helpers */
bool UI_editsource_enable_check(void);
void UI_editsource_active_but_test(uiBut *but);
+/**
+ * Remove the editsource data for \a old_but and reinsert it for \a new_but. Use when the button
+ * was reallocated, e.g. to have a new type (#ui_but_change_type()).
+ */
void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but);
+/**
+ * Adjust the view so the rectangle of \a but is in view, with some extra margin.
+ *
+ * It's important that this is only executed after buttons received their final #uiBut.rect. E.g.
+ * #UI_panels_end() modifies them, so if that is executed, this function must not be called before
+ * it.
+ *
+ * \param region: The region the button is placed in. Make sure this is actually the one the button
+ * is placed in, not just the context region.
+ */
void UI_but_ensure_in_view(const struct bContext *C, struct ARegion *region, const uiBut *but);
/* UI_butstore_ helpers */
typedef struct uiButStore uiButStore;
typedef struct uiButStoreElem uiButStoreElem;
+/**
+ * Create a new button store, the caller must manage and run #UI_butstore_free
+ */
uiButStore *UI_butstore_create(uiBlock *block);
+/**
+ * NULL all pointers, don't free since the owner needs to be able to inspect.
+ */
void UI_butstore_clear(uiBlock *block);
+/**
+ * Map freed buttons from the old block and update pointers.
+ */
void UI_butstore_update(uiBlock *block);
void UI_butstore_free(uiBlock *block, uiButStore *bs);
bool UI_butstore_is_valid(uiButStore *bs);
bool UI_butstore_is_registered(uiBlock *block, uiBut *but);
void UI_butstore_register(uiButStore *bs_handle, uiBut **but_p);
+/**
+ * Update the pointer for a registered button.
+ */
bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src);
void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p);
/* ui_interface_region_tooltip.c */
+
+/**
+ * \param is_label: When true, show a small tip that only shows the name, otherwise show the full
+ * tooltip.
+ */
struct ARegion *UI_tooltip_create_from_button(struct bContext *C,
struct ARegion *butregion,
uiBut *but,
bool is_label);
+struct ARegion *UI_tooltip_create_from_button_or_extra_icon(struct bContext *C,
+ struct ARegion *butregion,
+ uiBut *but,
+ uiButExtraOpIcon *extra_icon,
+ bool is_label);
struct ARegion *UI_tooltip_create_from_gizmo(struct bContext *C, struct wmGizmo *gz);
void UI_tooltip_free(struct bContext *C, struct bScreen *screen, struct ARegion *region);
@@ -2724,6 +3107,13 @@ typedef struct {
char hint[UI_MAX_DRAW_STR];
} uiSearchItemTooltipData;
+/**
+ * Create a tooltip from search-item tooltip data \a item_tooltip data.
+ * To be called from a callback set with #UI_but_func_search_set_tooltip().
+ *
+ * \param item_rect: Rectangle of the search item in search region space (#ui_searchbox_butrect())
+ * which is passed to the tooltip callback.
+ */
struct ARegion *UI_tooltip_create_from_search_item_generic(
struct bContext *C,
const struct ARegion *searchbox_region,
@@ -2742,6 +3132,10 @@ struct ARegion *UI_tooltip_create_from_search_item_generic(
/* Typical UI text */
#define UI_FSTYLE_WIDGET (const uiFontStyle *)&(UI_style_get()->widget)
+/**
+ * Returns the best "UI" precision for given floating value,
+ * so that e.g. 10.000001 rather gets drawn as '10'...
+ */
int UI_calc_float_precision(int prec, double value);
/* widget batched drawing */
@@ -2750,6 +3144,12 @@ void UI_widgetbase_draw_cache_flush(void);
void UI_widgetbase_draw_cache_end(void);
/* Use for resetting the theme. */
+/**
+ * Initialize default theme.
+ *
+ * \note When you add new colors, created & saved themes need initialized
+ * use function below, #init_userdef_do_versions.
+ */
void UI_theme_init_default(void);
void UI_style_init_default(void);
@@ -2761,7 +3161,43 @@ void UI_interface_tag_script_reload(void);
/* Support click-drag motion which presses the button and closes a popover (like a menu). */
#define USE_UI_POPOVER_ONCE
-bool UI_tree_view_item_is_active(uiTreeViewItemHandle *item_);
+bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item);
+bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a, const uiTreeViewItemHandle *b);
+/**
+ * Attempt to start dragging the tree-item \a item_. This will not work if the tree item doesn't
+ * support dragging, i.e. it won't create a drag-controller upon request.
+ * \return True if dragging started successfully, otherwise false.
+ */
+bool UI_tree_view_item_drag_start(struct bContext *C, uiTreeViewItemHandle *item_);
+bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
+ const struct wmDrag *drag,
+ const char **r_disabled_hint);
+char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item, const struct wmDrag *drag);
+/**
+ * Let a tree-view item handle a drop event.
+ * \return True if the drop was handled by the tree-view item.
+ */
+bool UI_tree_view_item_drop_handle(struct bContext *C,
+ const uiTreeViewItemHandle *item_,
+ const struct ListBase *drags);
+/**
+ * Can \a item_handle be renamed right now? Not that this isn't just a mere wrapper around
+ * #AbstractTreeViewItem::can_rename(). This also checks if there is another item being renamed,
+ * and returns false if so.
+ */
+bool UI_tree_view_item_can_rename(const uiTreeViewItemHandle *item_handle);
+void UI_tree_view_item_begin_rename(uiTreeViewItemHandle *item_handle);
+
+void UI_tree_view_item_context_menu_build(struct bContext *C,
+ const uiTreeViewItemHandle *item,
+ uiLayout *column);
+
+/**
+ * \param xy: Coordinate to find a tree-row item at, in window space.
+ */
+uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const struct ARegion *region,
+ const int xy[2]) ATTR_NONNULL(1, 2);
+uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const struct ARegion *region);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh
index 4a583d0225e..8d1ca54b7a1 100644
--- a/source/blender/editors/include/UI_interface.hh
+++ b/source/blender/editors/include/UI_interface.hh
@@ -23,12 +23,52 @@
#include <memory>
#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+#include "UI_resources.h"
+
+namespace blender::nodes::geometry_nodes_eval_log {
+struct GeometryAttributeInfo;
+}
+
+struct StructRNA;
struct uiBlock;
+struct uiSearchItems;
+
namespace blender::ui {
+
class AbstractTreeView;
-}
+/**
+ * An item in a breadcrumb-like context. Currently this struct is very simple, but more
+ * could be added to it in the future, to support interactivity or tooltips, for example.
+ */
+struct ContextPathItem {
+ /* Text to display in the UI. */
+ std::string name;
+ /* #BIFIconID */
+ int icon;
+};
+
+void context_path_add_generic(Vector<ContextPathItem> &path,
+ StructRNA &rna_type,
+ void *ptr,
+ const BIFIconID icon_override = ICON_NONE);
+
+void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path);
+
+void attribute_search_add_items(
+ StringRefNull str,
+ bool is_output,
+ Span<const nodes::geometry_nodes_eval_log::GeometryAttributeInfo *> infos,
+ uiSearchItems *items,
+ bool is_first);
+
+} // namespace blender::ui
+
+/**
+ * Override this for all available tree types.
+ */
blender::ui::AbstractTreeView *UI_block_add_view(
uiBlock &block,
blender::StringRef idname,
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index 37cf7229ffb..1009ae5cd3f 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -64,23 +64,53 @@ typedef enum eAlertIcon {
struct ImBuf *UI_icon_alert_imbuf_get(eAlertIcon icon);
-/*
+/**
* Resizable Icons for Blender
*/
void UI_icons_init(void);
+/**
+ * Reload the textures for internal icons.
+ * This function will release the previous textures.
+ */
void UI_icons_reload_internal_textures(void);
+/**
+ * NOTE: returns unscaled by DPI.
+ */
int UI_icon_get_width(int icon_id);
int UI_icon_get_height(int icon_id);
bool UI_icon_get_theme_color(int icon_id, unsigned char color[4]);
+/**
+ * Render a #PreviewImage for the data block.
+ *
+ * Note that if an ID doesn't support jobs for preview creation, \a use_job will be ignored.
+ */
void UI_icon_render_id(const struct bContext *C,
struct Scene *scene,
struct ID *id,
- const enum eIconSizes size,
- const bool use_job);
+ enum eIconSizes size,
+ bool use_job);
+
+/**
+ * Render the data block into the provided #PreviewImage.
+ */
+void UI_icon_render_id_ex(const struct bContext *C,
+ struct Scene *scene,
+ struct ID *id_to_render,
+ const enum eIconSizes size,
+ const bool use_job,
+ struct PreviewImage *r_preview_image);
+
+
+/**
+ * Render size for preview images and icons
+ */
int UI_icon_preview_to_render_size(enum eIconSizes size);
+/**
+ * Draws icon with dpi scale factor.
+ */
void UI_icon_draw(float x, float y, int icon_id);
void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha);
void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size);
@@ -92,7 +122,7 @@ void UI_icon_draw_ex(float x,
float alpha,
float desaturate,
const uchar mono_color[4],
- const bool mono_border);
+ bool mono_border);
void UI_icons_free(void);
void UI_icons_free_drawinfo(void *drawinfo);
@@ -105,13 +135,10 @@ int UI_iconfile_get_index(const char *filename);
struct PreviewImage *UI_icon_to_preview(int icon_id);
-int UI_icon_from_rnaptr(const struct bContext *C,
- struct PointerRNA *ptr,
- int rnaicon,
- const bool big);
-int UI_icon_from_idcode(const int idcode);
+int UI_icon_from_rnaptr(const struct bContext *C, struct PointerRNA *ptr, int rnaicon, bool big);
+int UI_icon_from_idcode(int idcode);
int UI_icon_from_library(const struct ID *id);
-int UI_icon_from_object_mode(const int mode);
+int UI_icon_from_object_mode(int mode);
int UI_icon_color_from_collection(const struct Collection *collection);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index dde8a637e05..40e4d8cee9c 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -64,7 +64,7 @@ typedef enum ThemeColorID {
TH_TAB_OUTLINE,
TH_HEADER,
- TH_HEADERDESEL,
+ TH_HEADER_ACTIVE,
TH_HEADER_TEXT,
TH_HEADER_TEXT_HI,
@@ -351,7 +351,7 @@ typedef enum ThemeColorID {
TH_VERTEX_BEVEL,
} ThemeColorID;
-/* specific defines per space should have higher define values */
+/* Specific defines per space should have higher define values. */
struct bTheme;
@@ -362,96 +362,147 @@ struct bThemeState {
/* THE CODERS API FOR THEMES: */
-/* returns one value, not scaled */
+/**
+ * Get individual values, not scaled.
+ */
float UI_GetThemeValuef(int colorid);
+/**
+ * Get individual values, not scaled.
+ */
int UI_GetThemeValue(int colorid);
+/* Versions of #UI_GetThemeValue & #UI_GetThemeValuef, which take a space-type */
+
float UI_GetThemeValueTypef(int colorid, int spacetype);
int UI_GetThemeValueType(int colorid, int spacetype);
-/* get three color values, scaled to 0.0-1.0 range */
+/**
+ * Get three color values, scaled to 0.0-1.0 range.
+ */
void UI_GetThemeColor3fv(int colorid, float col[3]);
void UI_GetThemeColorBlend3ubv(int colorid1, int colorid2, float fac, unsigned char col[3]);
void UI_GetThemeColorBlend3f(int colorid1, int colorid2, float fac, float r_col[3]);
void UI_GetThemeColorBlend4f(int colorid1, int colorid2, float fac, float r_col[4]);
-/* get the color, range 0.0-1.0, complete with shading offset */
+/**
+ * Get the color, range 0.0-1.0, complete with shading offset.
+ */
void UI_GetThemeColorShade3fv(int colorid, int offset, float col[3]);
void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3]);
void UI_GetThemeColorShade4ubv(int colorid, int offset, unsigned char col[4]);
-/* get three color values, range 0-255,
- * complete with shading offset for the RGB components and blending. */
+/**
+ * Get three color values, range 0-255,
+ * complete with shading offset for the RGB components and blending.
+ */
void UI_GetThemeColorBlendShade3ubv(
int colorid1, int colorid2, float fac, int offset, unsigned char col[3]);
-/* get four color values, scaled to 0.0-1.0 range */
+/**
+ * Get four color values, scaled to 0.0-1.0 range.
+ */
void UI_GetThemeColor4fv(int colorid, float col[4]);
-/* get four color values from specified space type, scaled to 0.0-1.0 range */
+/**
+ * Get four color values from specified space type, scaled to 0.0-1.0 range.
+ */
void UI_GetThemeColorType4fv(int colorid, int spacetype, float col[4]);
-/* get four color values, range 0.0-1.0, complete with shading offset for the RGB components */
+/**
+ * Get four color values, range 0.0-1.0, complete with shading offset for the RGB components.
+ */
void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4]);
void UI_GetThemeColorShadeAlpha4fv(int colorid, int coloffset, int alphaoffset, float col[4]);
-/* get four color values ranged between 0 and 255; includes the alpha channel */
+/**
+ * Get four color values ranged between 0 and 255; includes the alpha channel.
+ */
void UI_GetThemeColorShadeAlpha4ubv(int colorid,
int coloffset,
int alphaoffset,
unsigned char col[4]);
-/* get four color values, range 0.0-1.0,
- * complete with shading offset for the RGB components and blending. */
+/**
+ * Get four color values, range 0.0-1.0,
+ * complete with shading offset for the RGB components and blending.
+ */
void UI_GetThemeColorBlendShade3fv(
int colorid1, int colorid2, float fac, int offset, float col[3]);
void UI_GetThemeColorBlendShade4fv(
int colorid1, int colorid2, float fac, int offset, float col[4]);
-/* get the 3 or 4 byte values */
+/**
+ * Get the 3 or 4 byte values.
+ */
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3]);
+/**
+ * Get the color, in char pointer.
+ */
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4]);
-/* get a theme color from specified space type */
+/**
+ * Get a theme color from specified space type.
+ */
void UI_GetThemeColorType3fv(int colorid, int spacetype, float col[3]);
void UI_GetThemeColorType3ubv(int colorid, int spacetype, unsigned char col[3]);
void UI_GetThemeColorType4ubv(int colorid, int spacetype, unsigned char col[4]);
-/* get theme color for coloring monochrome icons */
+/**
+ * Get theme color for coloring monochrome icons.
+ */
bool UI_GetIconThemeColor4ubv(int colorid, unsigned char col[4]);
-/* shade a 3 byte color (same as UI_GetColorPtrBlendShade3ubv with 0.0 factor) */
+/**
+ * Shade a 3 byte color (same as UI_GetColorPtrBlendShade3ubv with 0.0 factor).
+ */
void UI_GetColorPtrShade3ubv(const unsigned char cp1[3], unsigned char col[3], int offset);
-/* get a 3 byte color, blended and shaded between two other char color pointers */
+/**
+ * Get a 3 byte color, blended and shaded between two other char color pointers.
+ */
void UI_GetColorPtrBlendShade3ubv(const unsigned char cp1[3],
const unsigned char cp2[3],
unsigned char col[3],
float fac,
int offset);
-/* sets the font color
- * (for anything fancy use UI_GetThemeColor[Fancy] then BLF_color) */
+/**
+ * Sets the font color
+ * (for anything fancy use UI_GetThemeColor[Fancy] then BLF_color).
+ */
void UI_FontThemeColor(int fontid, int colorid);
-/* Clear the frame-buffer using the input colorid. */
+/**
+ * Clear the frame-buffer using the input colorid.
+ */
void UI_ThemeClearColor(int colorid);
-/* internal (blender) usage only, for init and set active */
+/**
+ * Internal (blender) usage only, for init and set active.
+ */
void UI_SetTheme(int spacetype, int regionid);
-/* get current theme */
+/**
+ * Get current theme.
+ */
struct bTheme *UI_GetTheme(void);
+/**
+ * For the rare case we need to temp swap in a different theme (off-screen render).
+ */
void UI_Theme_Store(struct bThemeState *theme_state);
void UI_Theme_Restore(struct bThemeState *theme_state);
-/* return shadow width outside menus and popups */
+/**
+ * Return shadow width outside menus and popups.
+ */
int UI_ThemeMenuShadowWidth(void);
-/* only for buttons in theme editor! */
+/**
+ * Only for buttons in theme editor!
+ */
const unsigned char *UI_ThemeGetColorPtr(struct bTheme *btheme, int spacetype, int colorid);
-void UI_make_axis_color(const unsigned char src_col[3], unsigned char dst_col[3], const char axis);
+void UI_make_axis_color(const unsigned char src_col[3], unsigned char dst_col[3], char axis);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index fac880a0a67..8dee88defb3 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -16,40 +16,53 @@
/** \file
* \ingroup editorui
+ *
+ * API for simple creation of tree UIs supporting typically needed features.
+ * https://wiki.blender.org/wiki/Source/Interface/Views/Tree_Views
*/
#pragma once
+#include <array>
#include <functional>
#include <memory>
#include <string>
+#include "DNA_defs.h"
+
#include "BLI_function_ref.hh"
#include "BLI_vector.hh"
#include "UI_resources.h"
-struct PointerRNA;
+struct bContext;
struct uiBlock;
struct uiBut;
struct uiButTreeRow;
struct uiLayout;
+struct wmDrag;
+struct wmEvent;
namespace blender::ui {
class AbstractTreeView;
class AbstractTreeViewItem;
+class AbstractTreeViewItemDropController;
+class AbstractTreeViewItemDragController;
/* ---------------------------------------------------------------------- */
/** \name Tree-View Item Container
+ *
+ * Base class for tree-view and tree-view items, so both can contain children.
* \{ */
/**
- * Helper base class to expose common child-item data and functionality to both #AbstractTreeView
- * and #AbstractTreeViewItem.
+ * Both the tree-view (as the root of the tree) and the items can have children. This is the base
+ * class for both, to store and manage child items. Children are owned by their parent container
+ * (tree-view or item).
*
- * That means this type can be used whenever either a #AbstractTreeView or a
- * #AbstractTreeViewItem is needed.
+ * That means this type can be used whenever either an #AbstractTreeView or an
+ * #AbstractTreeViewItem is needed, but the #TreeViewOrItem alias is a better name to use then.
*/
class TreeViewItemContainer {
friend class AbstractTreeView;
@@ -75,18 +88,23 @@ class TreeViewItemContainer {
using ItemIterFn = FunctionRef<void(AbstractTreeViewItem &)>;
/**
- * Convenience wrapper taking the arguments needed to construct an item of type \a ItemT. Calls
- * the version just below.
+ * Convenience wrapper constructing the item by forwarding given arguments to the constructor of
+ * the type (\a ItemT).
+ *
+ * E.g. if your tree-item type has the following constructor:
+ * \code{.cpp}
+ * MyTreeItem(std::string str, int i);
+ * \endcode
+ * You can add an item like this:
+ * \code
+ * add_tree_item<MyTreeItem>("blabla", 42);
+ * \endcode
+ */
+ template<class ItemT, typename... Args> inline ItemT &add_tree_item(Args &&...args);
+ /**
+ * Add an already constructed tree item to this parent. Ownership is moved to it.
+ * All tree items must be added through this, it handles important invariants!
*/
- template<class ItemT, typename... Args> ItemT &add_tree_item(Args &&...args)
- {
- static_assert(std::is_base_of<AbstractTreeViewItem, ItemT>::value,
- "Type must derive from and implement the AbstractTreeViewItem interface");
-
- return dynamic_cast<ItemT &>(
- add_tree_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
- }
-
AbstractTreeViewItem &add_tree_item(std::unique_ptr<AbstractTreeViewItem> item);
protected:
@@ -96,35 +114,10 @@ class TreeViewItemContainer {
ENUM_OPERATORS(TreeViewItemContainer::IterOptions,
TreeViewItemContainer::IterOptions::SkipCollapsed);
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Tree-View Builders
- * \{ */
-
-class TreeViewBuilder {
- uiBlock &block_;
-
- public:
- TreeViewBuilder(uiBlock &block);
-
- void build_tree_view(AbstractTreeView &tree_view);
-};
-
-class TreeViewLayoutBuilder {
- uiBlock &block_;
-
- friend TreeViewBuilder;
-
- public:
- void build_row(AbstractTreeViewItem &item) const;
- uiBlock &block() const;
- uiLayout *current_layout() const;
-
- private:
- /* Created through #TreeViewBuilder. */
- TreeViewLayoutBuilder(uiBlock &block);
-};
+/** The container class is the base for both the tree-view and the items. This alias gives it a
+ * clearer name for handles that accept both. Use whenever something wants to act on child-items,
+ * irrespective of if they are stored at root level or as children of some other item. */
+using TreeViewOrItem = TreeViewItemContainer;
/** \} */
@@ -133,27 +126,52 @@ class TreeViewLayoutBuilder {
* \{ */
class AbstractTreeView : public TreeViewItemContainer {
- friend TreeViewBuilder;
- friend TreeViewLayoutBuilder;
+ friend class AbstractTreeViewItem;
+ friend class TreeViewBuilder;
+
+ /**
+ * Only one item can be renamed at a time. So the tree is informed about the renaming state to
+ * enforce that.
+ */
+ std::unique_ptr<std::array<char, MAX_NAME>> rename_buffer_;
+
+ bool is_reconstructed_ = false;
public:
virtual ~AbstractTreeView() = default;
void foreach_item(ItemIterFn iter_fn, IterOptions options = IterOptions::None) const;
+ /** Only one item can be renamed at a time. */
+ bool is_renaming() const;
+
protected:
virtual void build_tree() = 0;
+ /**
+ * Check if the tree is fully (re-)constructed. That means, both #build_tree() and
+ * #update_from_old() have finished.
+ */
+ bool is_reconstructed() const;
+
private:
- /** Match the tree-view against an earlier version of itself (if any) and copy the old UI state
- * (e.g. collapsed, active, selected) to the new one. See
- * #AbstractTreeViewItem.update_from_old(). */
+ /**
+ * Match the tree-view against an earlier version of itself (if any) and copy the old UI state
+ * (e.g. collapsed, active, selected, renaming, etc.) to the new one. See
+ * #AbstractTreeViewItem.update_from_old().
+ */
void update_from_old(uiBlock &new_block);
- static void update_children_from_old_recursive(const TreeViewItemContainer &new_items,
- const TreeViewItemContainer &old_items);
+ static void update_children_from_old_recursive(const TreeViewOrItem &new_items,
+ const TreeViewOrItem &old_items);
static AbstractTreeViewItem *find_matching_child(const AbstractTreeViewItem &lookup_item,
- const TreeViewItemContainer &items);
- void build_layout_from_tree(const TreeViewLayoutBuilder &builder);
+ const TreeViewOrItem &items);
+
+ /**
+ * Items may want to do additional work when state changes. But these state changes can only be
+ * reliably detected after the tree has completed reconstruction (see #is_reconstructed()). So
+ * the actual state changes are done in a delayed manner through this function.
+ */
+ void change_state_delayed();
};
/** \} */
@@ -171,34 +189,207 @@ class AbstractTreeView : public TreeViewItemContainer {
*/
class AbstractTreeViewItem : public TreeViewItemContainer {
friend class AbstractTreeView;
+ friend class TreeViewLayoutBuilder;
+ /* Higher-level API. */
+ friend class TreeViewItemAPIWrapper;
+ private:
bool is_open_ = false;
bool is_active_ = false;
+ bool is_renaming_ = false;
protected:
- /** This label is used for identifying an item (together with its parent's labels). */
+ /** This label is used for identifying an item within its parent. */
std::string label_{};
+ /** Every visible item gets a button of type #UI_BTYPE_TREEROW during the layout building. */
+ uiButTreeRow *tree_row_but_ = nullptr;
public:
virtual ~AbstractTreeViewItem() = default;
virtual void build_row(uiLayout &row) = 0;
+ virtual void build_context_menu(bContext &C, uiLayout &column) const;
+
+ AbstractTreeView &get_tree_view() const;
+ void begin_renaming();
+ void toggle_collapsed();
+ void set_collapsed(bool collapsed);
+ /**
+ * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
+ * can't be sure about the item state.
+ */
+ bool is_collapsed() const;
+ /**
+ * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
+ * can't be sure about the item state.
+ */
+ bool is_active() const;
+
+ protected:
+ /**
+ * Called when the items state changes from inactive to active.
+ */
virtual void on_activate();
+ /**
+ * If the result is not empty, it controls whether the item should be active or not,
+ * usually depending on the data that the view represents.
+ */
+ virtual std::optional<bool> should_be_active() const;
+
+ /**
+ * Queries if the tree-view item supports renaming in principle. Renaming may still fail, e.g. if
+ * another item is already being renamed.
+ */
+ virtual bool supports_renaming() const;
+ /**
+ * Try renaming the item, or the data it represents. Can assume
+ * #AbstractTreeViewItem::supports_renaming() returned true. Sub-classes that override this
+ * should usually call this, unless they have a custom #AbstractTreeViewItem.matches().
+ *
+ * \return True if the renaming was successful.
+ */
+ virtual bool rename(StringRefNull new_name);
+
+ /**
+ * Return whether the item can be collapsed. Used to disable collapsing for items with children.
+ */
+ virtual bool supports_collapsing() const;
- /** Copy persistent state (e.g. is-collapsed flag, selection, etc.) from a matching item of the
- * last redraw to this item. If sub-classes introduce more advanced state they should override
- * this and make it update their state accordingly. */
+ /**
+ * Copy persistent state (e.g. is-collapsed flag, selection, etc.) from a matching item of
+ * the last redraw to this item. If sub-classes introduce more advanced state they should
+ * override this and make it update their state accordingly.
+ */
virtual void update_from_old(const AbstractTreeViewItem &old);
- const AbstractTreeView &get_tree_view() const;
- int count_parents() const;
- void set_active(bool value = true);
- bool is_active() const;
- void toggle_collapsed();
- bool is_collapsed() const;
- void set_collapsed(bool collapsed);
+ /**
+ * Compare this item to \a other to check if they represent the same data.
+ * Used to recognize an item from a previous redraw, to be able to keep its state (e.g.
+ * open/closed, active, etc.). Items are only matched if their parents also match.
+ * By default this just matches the item's label (if the parents match!). If that isn't
+ * good enough for a sub-class, that can override it.
+ */
+ virtual bool matches(const AbstractTreeViewItem &other) const;
+
+ /**
+ * If an item wants to support being dragged, it has to return a drag controller here.
+ * That is an object implementing #AbstractTreeViewItemDragController.
+ */
+ virtual std::unique_ptr<AbstractTreeViewItemDragController> create_drag_controller() const;
+ /**
+ * If an item wants to support dropping data into it, it has to return a drop controller here.
+ * That is an object implementing #AbstractTreeViewItemDropController.
+ *
+ * \note This drop controller may be requested for each event. The tree-view doesn't keep a drop
+ * controller around currently. So it can not contain persistent state.
+ */
+ virtual std::unique_ptr<AbstractTreeViewItemDropController> create_drop_controller() const;
+
+ /**
+ * Activates this item, deactivates other items, calls the #AbstractTreeViewItem::on_activate()
+ * function and ensures this item's parents are not collapsed (so the item is visible).
+ * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise the
+ * actual item state is unknown, possibly calling state-change update functions incorrectly.
+ */
+ void activate();
+ void deactivate();
+
+ /**
+ * Can be called from the #AbstractTreeViewItem::build_row() implementation, but not earlier. The
+ * hovered state can't be queried reliably otherwise.
+ * Note that this does a linear lookup in the old block, so isn't too great performance-wise.
+ */
+ bool is_hovered() const;
bool is_collapsible() const;
+ bool is_renaming() const;
+
+ void ensure_parents_uncollapsed();
+
+ uiButTreeRow *tree_row_button();
+
+ private:
+ static void rename_button_fn(bContext *, void *, char *);
+ static AbstractTreeViewItem *find_tree_item_from_rename_button(const uiBut &but);
+ static void tree_row_click_fn(struct bContext *, void *, void *);
+ static void collapse_chevron_click_fn(bContext *, void *but_arg1, void *);
+ static bool is_collapse_chevron_but(const uiBut *but);
+
+ /** See #AbstractTreeView::change_state_delayed() */
+ void change_state_delayed();
+ void end_renaming();
+
+ void add_treerow_button(uiBlock &block);
+ void add_indent(uiLayout &row) const;
+ void add_collapse_chevron(uiBlock &block) const;
+ void add_rename_button(uiLayout &row);
+
+ bool matches_including_parents(const AbstractTreeViewItem &other) const;
+ bool has_active_child() const;
+ int count_parents() const;
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Drag 'n Drop
+ * \{ */
+
+/**
+ * Class to enable dragging a tree-item. An item can return a drop controller for itself via a
+ * custom implementation of #AbstractTreeViewItem::create_drag_controller().
+ */
+class AbstractTreeViewItemDragController {
+ protected:
+ AbstractTreeView &tree_view_;
+
+ public:
+ AbstractTreeViewItemDragController(AbstractTreeView &tree_view);
+ virtual ~AbstractTreeViewItemDragController() = default;
+
+ virtual int get_drag_type() const = 0;
+ virtual void *create_drag_data() const = 0;
+ virtual void on_drag_start();
+
+ template<class TreeViewType> inline TreeViewType &tree_view() const;
+};
+
+/**
+ * Class to customize the drop behavior of a tree-item, plus the behavior when dragging over this
+ * item. An item can return a drop controller for itself via a custom implementation of
+ * #AbstractTreeViewItem::create_drop_controller().
+ */
+class AbstractTreeViewItemDropController {
+ protected:
+ AbstractTreeView &tree_view_;
+
+ public:
+ AbstractTreeViewItemDropController(AbstractTreeView &tree_view);
+ virtual ~AbstractTreeViewItemDropController() = default;
+
+ /**
+ * Check if the data dragged with \a drag can be dropped on the item this controller is for.
+ * \param r_disabled_hint: Return a static string to display to the user, explaining why dropping
+ * isn't possible on this item. Shouldn't be done too aggressively, e.g.
+ * don't set this if the drag-type can't be dropped here; only if it can
+ * but there's another reason it can't be dropped.
+ * Can assume this is a non-null pointer.
+ */
+ virtual bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const = 0;
+ /**
+ * Custom text to display when dragging over a tree item. Should explain what happens when
+ * dropping the data onto this item. Will only be used if #AbstractTreeViewItem::can_drop()
+ * returns true, so the implementing override doesn't have to check that again.
+ * The returned value must be a translated string.
+ */
+ virtual std::string drop_tooltip(const wmDrag &drag) const = 0;
+ /**
+ * Execute the logic to apply a drop of the data dragged with \a drag onto/into the item this
+ * controller is for.
+ */
+ virtual bool on_drop(struct bContext *C, const wmDrag &drag) = 0;
+
+ template<class TreeViewType> inline TreeViewType &tree_view() const;
};
/** \} */
@@ -214,26 +405,78 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
*/
class BasicTreeViewItem : public AbstractTreeViewItem {
public:
+ using IsActiveFn = std::function<bool()>;
using ActivateFn = std::function<void(BasicTreeViewItem &new_active)>;
BIFIconID icon;
- BasicTreeViewItem(StringRef label, BIFIconID icon = ICON_NONE, ActivateFn activate_fn = nullptr);
+ explicit BasicTreeViewItem(StringRef label, BIFIconID icon = ICON_NONE);
void build_row(uiLayout &row) override;
- void on_activate() override;
+ void add_label(uiLayout &layout, StringRefNull label_override = "");
+ void set_on_activate_fn(ActivateFn fn);
+ /**
+ * Set a custom callback to check if this item should be active.
+ */
+ void set_is_active_fn(IsActiveFn fn);
protected:
- /** Created in the #build() function. */
- uiButTreeRow *tree_row_but_ = nullptr;
- /** Optionally passed to the #BasicTreeViewItem constructor. Called when activating this tree
+ /**
+ * Optionally passed to the #BasicTreeViewItem constructor. Called when activating this tree
* view item. This way users don't have to sub-class #BasicTreeViewItem, just to implement
- * custom activation behavior (a common thing to do). */
+ * custom activation behavior (a common thing to do).
+ */
ActivateFn activate_fn_;
- uiBut *button();
- BIFIconID get_draw_icon() const;
+ IsActiveFn is_active_fn_;
+
+ private:
+ static void tree_row_click_fn(struct bContext *C, void *arg1, void *arg2);
+
+ std::optional<bool> should_be_active() const override;
+ void on_activate() override;
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Tree-View Builder
+ * \{ */
+
+class TreeViewBuilder {
+ uiBlock &block_;
+
+ public:
+ TreeViewBuilder(uiBlock &block);
+
+ void build_tree_view(AbstractTreeView &tree_view);
};
/** \} */
+/* ---------------------------------------------------------------------- */
+
+template<class ItemT, typename... Args>
+inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args)
+{
+ static_assert(std::is_base_of<AbstractTreeViewItem, ItemT>::value,
+ "Type must derive from and implement the AbstractTreeViewItem interface");
+
+ return dynamic_cast<ItemT &>(
+ add_tree_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
+}
+
+template<class TreeViewType> TreeViewType &AbstractTreeViewItemDragController::tree_view() const
+{
+ static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value,
+ "Type must derive from and implement the AbstractTreeView interface");
+ return static_cast<TreeViewType &>(tree_view_);
+}
+
+template<class TreeViewType> TreeViewType &AbstractTreeViewItemDropController::tree_view() const
+{
+ static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value,
+ "Type must derive from and implement the AbstractTreeView interface");
+ return static_cast<TreeViewType &>(tree_view_);
+}
+
} // namespace blender::ui
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index fdfa07a7e02..a3f39e1286e 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -118,21 +118,46 @@ typedef struct View2DScrollers View2DScrollers;
/* ----------------------------------------- */
/* Prototypes: */
-/* refresh and validation (of view rects) */
+/**
+ * Refresh and validation (of view rects).
+ *
+ * Initialize all relevant View2D data (including view rects if first time)
+ * and/or refresh mask sizes after view resize.
+ *
+ * - For some of these presets, it is expected that the region will have defined some
+ * additional settings necessary for the customization of the 2D viewport to its requirements
+ * - This function should only be called from region init() callbacks, where it is expected that
+ * this is called before #UI_view2d_size_update(),
+ * as this one checks that the rects are properly initialized.
+ */
void UI_view2d_region_reinit(struct View2D *v2d, short type, int winx, int winy);
void UI_view2d_curRect_validate(struct View2D *v2d);
+/**
+ * Restore 'cur' rect to standard orientation (i.e. optimal maximum view of tot).
+ * This does not take into account if zooming the view on an axis
+ * will improve the view (if allowed).
+ */
void UI_view2d_curRect_reset(struct View2D *v2d);
bool UI_view2d_area_supports_sync(struct ScrArea *area);
+/**
+ * Called by menus to activate it, or by view2d operators
+ * to make sure 'related' views stay in synchrony.
+ */
void UI_view2d_sync(struct bScreen *screen, struct ScrArea *area, struct View2D *v2dcur, int flag);
-/* Perform all required updates after `v2d->cur` as been modified.
+/**
+ * Perform all required updates after `v2d->cur` as been modified.
* This includes like validation view validation (#UI_view2d_curRect_validate).
*
- * Current intent is to use it from user code, such as view navigation and zoom operations. */
+ * Current intent is to use it from user code, such as view navigation and zoom operations.
+ */
void UI_view2d_curRect_changed(const struct bContext *C, struct View2D *v2d);
void UI_view2d_totRect_set(struct View2D *v2d, int width, int height);
+/**
+ * Change the size of the maximum viewable area (i.e. 'tot' rect).
+ */
void UI_view2d_totRect_set_resize(struct View2D *v2d, int width, int height, bool resize);
void UI_view2d_mask_from_win(const struct View2D *v2d, struct rcti *r_mask);
@@ -140,13 +165,41 @@ void UI_view2d_mask_from_win(const struct View2D *v2d, struct rcti *r_mask);
void UI_view2d_zoom_cache_reset(void);
/* view matrix operations */
+/**
+ * Set view matrices to use 'cur' rect as viewing frame for View2D drawing.
+ */
void UI_view2d_view_ortho(const struct View2D *v2d);
-void UI_view2d_view_orthoSpecial(struct ARegion *region, struct View2D *v2d, const bool xaxis);
+/**
+ * Set view matrices to only use one axis of 'cur' only
+ *
+ * \param xaxis: if non-zero, only use cur x-axis,
+ * otherwise use cur-yaxis (mostly this will be used for x).
+ */
+void UI_view2d_view_orthoSpecial(struct ARegion *region, struct View2D *v2d, bool xaxis);
+/**
+ * Restore view matrices after drawing.
+ */
void UI_view2d_view_restore(const struct bContext *C);
/* grid drawing */
+
+/**
+ * Draw a multi-level grid in given 2d-region.
+ */
void UI_view2d_multi_grid_draw(
const struct View2D *v2d, int colorid, float step, int level_size, int totlevels);
+/**
+ * Draw a multi-level grid of dots, with a dynamic number of levels based on the fading.
+ *
+ * \param grid_color_id: The theme color used for the points. Faded dynamically based on zoom.
+ * \param min_step: The base size of the grid. At different zoom levels, the visible grid may have
+ * a larger step size.
+ * \param grid_levels: The maximum grid depth. Larger grid levels will subdivide the grid more.
+ */
+void UI_view2d_dot_grid_draw(const struct View2D *v2d,
+ int grid_color_id,
+ float min_step,
+ int grid_levels);
void UI_view2d_draw_lines_y__values(const struct View2D *v2d);
void UI_view2d_draw_lines_x__values(const struct View2D *v2d);
@@ -167,7 +220,9 @@ float UI_view2d_grid_resolution_x__frames_or_seconds(const struct View2D *v2d,
bool display_seconds);
float UI_view2d_grid_resolution_y__values(const struct View2D *v2d);
-/* scale indicator text drawing */
+/**
+ * Scale indicator text drawing.
+ */
void UI_view2d_draw_scale_y__values(const struct ARegion *region,
const struct View2D *v2d,
const struct rcti *rect,
@@ -189,25 +244,52 @@ void UI_view2d_draw_scale_x__frames_or_seconds(const struct ARegion *region,
bool display_seconds,
int colorid);
-/* scrollbar drawing */
+/* Scroll-bar drawing. */
+
+/**
+ * Calculate relevant scroller properties.
+ */
void UI_view2d_scrollers_calc(struct View2D *v2d,
const struct rcti *mask_custom,
struct View2DScrollers *r_scrollers);
+/**
+ * Draw scroll-bars in the given 2D-region.
+ */
void UI_view2d_scrollers_draw(struct View2D *v2d, const struct rcti *mask_custom);
-/* list view tools */
+/* List view tools. */
+
+/**
+ * Get the 'cell' (row, column) that the given 2D-view coordinates
+ * (i.e. in 'tot' rect space) lie in.
+ *
+ * \param columnwidth, rowheight: size of each 'cell'
+ * \param startx, starty: coordinates (in 'tot' rect space) that the list starts from.
+ * This should be (0,0) for most views. However, for those where the starting row was offsetted
+ * (like for Animation Editor channel lists, to make the first entry more visible), these will be
+ * the min-coordinates of the first item.
+ * \param viewx, viewy: 2D-coordinates (in 2D-view / 'tot' rect space) to get the cell for
+ * \param r_column, r_row: The 'coordinates' of the relevant 'cell'.
+ */
void UI_view2d_listview_view_to_cell(float columnwidth,
float rowheight,
float startx,
float starty,
float viewx,
float viewy,
- int *column,
- int *row);
+ int *r_column,
+ int *r_row);
+
+/* Coordinate conversion. */
-/* coordinate conversion */
float UI_view2d_region_to_view_x(const struct View2D *v2d, float x);
float UI_view2d_region_to_view_y(const struct View2D *v2d, float y);
+/**
+ * Convert from screen/region space to 2d-View space
+ *
+ * \param x, y: coordinates to convert
+ * \param r_view_x, r_view_y: resultant coordinates
+ */
void UI_view2d_region_to_view(
const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL();
void UI_view2d_region_to_view_rctf(const struct View2D *v2d,
@@ -216,9 +298,24 @@ void UI_view2d_region_to_view_rctf(const struct View2D *v2d,
float UI_view2d_view_to_region_x(const struct View2D *v2d, float x);
float UI_view2d_view_to_region_y(const struct View2D *v2d, float y);
+/**
+ * Convert from 2d-View space to screen/region space
+ * \note Coordinates are clamped to lie within bounds of region
+ *
+ * \param x, y: Coordinates to convert.
+ * \param r_region_x, r_region_y: Resultant coordinates.
+ */
bool UI_view2d_view_to_region_clip(
const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
+/**
+ * Convert from 2d-view space to screen/region space
+ *
+ * \note Coordinates are NOT clamped to lie within bounds of region.
+ *
+ * \param x, y: Coordinates to convert.
+ * \param r_region_x, r_region_y: Resultant coordinates.
+ */
void UI_view2d_view_to_region(
const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
void UI_view2d_view_to_region_fl(const struct View2D *v2d,
@@ -234,42 +331,91 @@ bool UI_view2d_view_to_region_rcti_clip(const struct View2D *v2d,
const struct rctf *rect_src,
struct rcti *rect_dst) ATTR_NONNULL();
-/* utilities */
+/* Utilities. */
+
+/**
+ * View2D data by default resides in region, so get from region stored in context.
+ */
struct View2D *UI_view2d_fromcontext(const struct bContext *C);
+/**
+ * Same as above, but it returns region-window. Utility for pull-downs or buttons.
+ */
struct View2D *UI_view2d_fromcontext_rwin(const struct bContext *C);
+/**
+ * Get scrollbar sizes of the current 2D view.
+ * The size will be zero if the view has its scrollbars disabled.
+ */
void UI_view2d_scroller_size_get(const struct View2D *v2d, float *r_x, float *r_y);
+/**
+ * Calculate the scale per-axis of the drawing-area
+ *
+ * Is used to inverse correct drawing of icons, etc. that need to follow view
+ * but not be affected by scale
+ *
+ * \param r_x, r_y: scale on each axis
+ */
void UI_view2d_scale_get(const struct View2D *v2d, float *r_x, float *r_y);
float UI_view2d_scale_get_x(const struct View2D *v2d);
float UI_view2d_scale_get_y(const struct View2D *v2d);
+/**
+ * Same as `UI_view2d_scale_get() - 1.0f / x, y`.
+ */
void UI_view2d_scale_get_inverse(const struct View2D *v2d, float *r_x, float *r_y);
+/**
+ * Simple functions for consistent center offset access.
+ * Used by node editor to shift view center for each individual node tree.
+ */
void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y);
void UI_view2d_center_set(struct View2D *v2d, float x, float y);
+/**
+ * Simple pan function
+ * (0.0, 0.0) bottom left
+ * (0.5, 0.5) center
+ * (1.0, 1.0) top right.
+ */
void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac);
-char UI_view2d_mouse_in_scrollers_ex(
- const struct ARegion *region, const struct View2D *v2d, int x, int y, int *r_scroll);
+/**
+ * Check if mouse is within scrollers
+ *
+ * \param xy: Mouse coordinates in screen (not region) space.
+ * \param r_scroll: Return argument for the mapped view2d scroll flag.
+ *
+ * \return appropriate code for match.
+ * - 'h' = in horizontal scroller.
+ * - 'v' = in vertical scroller.
+ * - 0 = not in scroller.
+ */
+char UI_view2d_mouse_in_scrollers_ex(const struct ARegion *region,
+ const struct View2D *v2d,
+ const int xy[2],
+ int *r_scroll) ATTR_NONNULL(1, 2, 3, 4);
char UI_view2d_mouse_in_scrollers(const struct ARegion *region,
const struct View2D *v2d,
- int x,
- int y);
+ const int xy[2]) ATTR_NONNULL(1, 2, 3);
char UI_view2d_rect_in_scrollers_ex(const struct ARegion *region,
const struct View2D *v2d,
const struct rcti *rect,
- int *r_scroll);
+ int *r_scroll) ATTR_NONNULL(1, 2, 3);
char UI_view2d_rect_in_scrollers(const struct ARegion *region,
const struct View2D *v2d,
- const struct rcti *rect);
+ const struct rcti *rect) ATTR_NONNULL(1, 2, 3);
-/* cached text drawing in v2d, to allow pixel-aligned draw as post process */
+/**
+ * Cached text drawing in v2d, to allow pixel-aligned draw as post process.
+ */
void UI_view2d_text_cache_add(struct View2D *v2d,
float x,
float y,
const char *str,
size_t str_len,
const unsigned char col[4]);
+/**
+ * No clip (yet).
+ */
void UI_view2d_text_cache_add_rectf(struct View2D *v2d,
const struct rctf *rect_view,
const char *str,
@@ -277,25 +423,33 @@ void UI_view2d_text_cache_add_rectf(struct View2D *v2d,
const unsigned char col[4]);
void UI_view2d_text_cache_draw(struct ARegion *region);
-/* operators */
+/* Operators. */
+
void ED_operatortypes_view2d(void);
void ED_keymap_view2d(struct wmKeyConfig *keyconf);
+/**
+ * Will start timer if appropriate.
+ * the arguments are the desired situation.
+ */
void UI_view2d_smooth_view(struct bContext *C,
struct ARegion *region,
const struct rctf *cur,
- const int smooth_viewtx);
+ int smooth_viewtx);
#define UI_MARKER_MARGIN_Y (42 * UI_DPI_FAC)
#define UI_TIME_SCRUB_MARGIN_Y (23 * UI_DPI_FAC)
-/* Gizmo Types */
+/* Gizmo Types. */
/* view2d_gizmo_navigate.c */
-/* Caller passes in own idname. */
+
+/**
+ * Caller defines the name for gizmo group.
+ */
void VIEW2D_GGT_navigate_impl(struct wmGizmoGroupType *gzgt, const char *idname);
-/* Edge pan */
+/* Edge pan. */
/**
* Custom-data for view panning operators.
@@ -310,6 +464,9 @@ typedef struct View2DEdgePanData {
/** View2d we're operating in. */
struct View2D *v2d;
+ /** Panning should only start once being in the inside rect once (e.g. adding nodes can happen
+ * outside). */
+ bool enabled;
/** Inside distance in UI units from the edge of the region within which to start panning. */
float inside_pad;
/** Outside distance in UI units from the edge of the region at which to stop panning. */
@@ -353,10 +510,15 @@ void UI_view2d_edge_pan_init(struct bContext *C,
void UI_view2d_edge_pan_reset(struct View2DEdgePanData *vpd);
-/* Apply transform to view (i.e. adjust 'cur' rect). */
-void UI_view2d_edge_pan_apply(struct bContext *C, struct View2DEdgePanData *vpd, int x, int y);
+/**
+ * Apply transform to view (i.e. adjust 'cur' rect).
+ */
+void UI_view2d_edge_pan_apply(struct bContext *C, struct View2DEdgePanData *vpd, const int xy[2])
+ ATTR_NONNULL(1, 2, 3);
-/* Apply transform to view using mouse events. */
+/**
+ * Apply transform to view using mouse events.
+ */
void UI_view2d_edge_pan_apply_event(struct bContext *C,
struct View2DEdgePanData *vpd,
const struct wmEvent *event);
@@ -373,7 +535,9 @@ void UI_view2d_edge_pan_operator_properties_ex(struct wmOperatorType *ot,
float delay,
float zoom_influence);
-/* Initialize panning data with operator settings. */
+/**
+ * Initialize panning data with operator settings.
+ */
void UI_view2d_edge_pan_operator_init(struct bContext *C,
struct View2DEdgePanData *vpd,
struct wmOperator *op);
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 79e08f46292..95c9f7cc8b2 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -24,10 +24,12 @@ set(INC
../../blentranslation
../../depsgraph
../../draw
+ ../../functions
../../gpu
../../imbuf
../../makesdna
../../makesrna
+ ../../nodes
../../python
../../render
../../windowmanager
@@ -41,7 +43,9 @@ set(SRC
interface_anim.c
interface_button_group.c
interface_context_menu.c
+ interface_context_path.cc
interface_draw.c
+ interface_dropboxes.cc
interface_eyedropper.c
interface_eyedropper_color.c
interface_eyedropper_colorband.c
@@ -62,13 +66,14 @@ set(SRC
interface_region_menu_popup.c
interface_region_popover.c
interface_region_popup.c
- interface_region_search.c
+ interface_region_search.cc
interface_region_tooltip.c
interface_regions.c
interface_style.c
interface_template_asset_view.cc
+ interface_template_attribute_search.cc
interface_template_list.cc
- interface_template_search_menu.c
+ interface_template_search_menu.cc
interface_template_search_operator.c
interface_templates.c
interface_undo.c
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index beee622673c..636281ba373 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -25,7 +25,7 @@
#include <float.h>
#include <limits.h>
#include <math.h>
-#include <stddef.h> /* offsetof() */
+#include <stddef.h> /* `offsetof()` */
#include <string.h>
#include "MEM_guardedalloc.h"
@@ -37,6 +37,7 @@
#include "DNA_workspace_types.h"
#include "BLI_alloca.h"
+#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
@@ -201,7 +202,6 @@ float ui_block_to_window_scale(const ARegion *region, uiBlock *block)
return max_y - min_y;
}
-/* for mouse cursor */
void ui_window_to_block_fl(const ARegion *region, uiBlock *block, float *r_x, float *r_y)
{
const int getsizex = BLI_rcti_size_x(&region->winrct) + 1;
@@ -355,10 +355,6 @@ static void ui_update_window_matrix(const wmWindow *window, const ARegion *regio
}
}
-/**
- * Popups will add a margin to #ARegion.winrct for shadow,
- * for interactivity (point-inside tests for eg), we want the winrct without the margin added.
- */
void ui_region_winrct_get_no_margin(const struct ARegion *region, struct rcti *r_rect)
{
uiBlock *block = region->uiblocks.first;
@@ -599,7 +595,6 @@ static void ui_block_bounds_calc_popup(
}
}
-/* used for various cases */
void UI_block_bounds_set_normal(uiBlock *block, int addval)
{
if (block == NULL) {
@@ -610,14 +605,12 @@ void UI_block_bounds_set_normal(uiBlock *block, int addval)
block->bounds_type = UI_BLOCK_BOUNDS;
}
-/* Used for pull-downs. */
void UI_block_bounds_set_text(uiBlock *block, int addval)
{
block->bounds = addval;
block->bounds_type = UI_BLOCK_BOUNDS_TEXT;
}
-/* used for block popups */
void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offset[2])
{
block->bounds = addval;
@@ -632,7 +625,6 @@ void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offs
}
}
-/* used for menu popups */
void UI_block_bounds_set_menu(uiBlock *block, int addval, const int bounds_offset[2])
{
block->bounds = addval;
@@ -645,7 +637,6 @@ void UI_block_bounds_set_menu(uiBlock *block, int addval, const int bounds_offse
}
}
-/* used for centered popups, i.e. splash */
void UI_block_bounds_set_centered(uiBlock *block, int addval)
{
block->bounds = addval;
@@ -670,8 +661,43 @@ static float ui_but_get_float_precision(uiBut *but)
return but->a2;
}
+static float ui_but_get_float_step_size(uiBut *but)
+{
+ if (but->type == UI_BTYPE_NUM) {
+ return ((uiButNumber *)but)->step_size;
+ }
+
+ return but->a1;
+}
+
+static bool ui_but_hide_fraction(uiBut *but, double value)
+{
+ /* Hide the fraction if both the value and the step are exact integers. */
+ if (floor(value) == value) {
+ const float step = ui_but_get_float_step_size(but) * UI_PRECISION_FLOAT_SCALE;
+
+ if (floorf(step) == step) {
+ /* Don't hide if it has any unit except frame count. */
+ switch (UI_but_unit_type_get(but)) {
+ case PROP_UNIT_NONE:
+ case PROP_UNIT_TIME:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ }
+
+ return false;
+}
+
static int ui_but_calc_float_precision(uiBut *but, double value)
{
+ if (ui_but_hide_fraction(but, value)) {
+ return 0;
+ }
+
int prec = (int)ui_but_get_float_precision(but);
/* first check for various special cases:
@@ -742,6 +768,18 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
if (but->optype != oldbut->optype) {
return false;
}
+ if (but->dragtype != oldbut->dragtype) {
+ return false;
+ }
+
+ if ((but->type == UI_BTYPE_TREEROW) && (oldbut->type == UI_BTYPE_TREEROW)) {
+ uiButTreeRow *but_treerow = (uiButTreeRow *)but;
+ uiButTreeRow *oldbut_treerow = (uiButTreeRow *)oldbut;
+ if (!but_treerow->tree_item || !oldbut_treerow->tree_item ||
+ !UI_tree_view_item_matches(but_treerow->tree_item, oldbut_treerow->tree_item)) {
+ return false;
+ }
+ }
return true;
}
@@ -956,7 +994,13 @@ static bool ui_but_update_from_old_block(const bContext *C,
found_active = true;
}
else {
- const int flag_copy = UI_BUT_DRAG_MULTI;
+ int flag_copy = UI_BUT_DRAG_MULTI;
+
+ /* Stupid special case: The active button may be inside (as in, overlapped on top) a tree-row
+ * button which we also want to keep highlighted then. */
+ if (but->type == UI_BTYPE_TREEROW) {
+ flag_copy |= UI_ACTIVE;
+ }
but->flag = (but->flag & ~flag_copy) | (oldbut->flag & flag_copy);
@@ -969,11 +1013,6 @@ static bool ui_but_update_from_old_block(const bContext *C,
return found_active;
}
-/**
- * Needed for temporarily rename buttons, such as in outliner or file-select,
- * they should keep calling #uiDefBut to keep them alive.
- * \return false when button removed.
- */
bool UI_but_active_only_ex(
const bContext *C, ARegion *region, uiBlock *block, uiBut *but, const bool remove_on_failure)
{
@@ -1005,6 +1044,9 @@ bool UI_but_active_only_ex(
else if ((found == true) && (isactive == false)) {
if (remove_on_failure) {
BLI_remlink(&block->buttons, but);
+ if (but->layout) {
+ ui_layout_remove_but(but->layout, but);
+ }
ui_but_free(C, but);
}
return false;
@@ -1018,10 +1060,6 @@ bool UI_but_active_only(const bContext *C, ARegion *region, uiBlock *block, uiBu
return UI_but_active_only_ex(C, region, block, but, true);
}
-/**
- * \warning This must run after other handlers have been added,
- * otherwise the handler won't be removed, see: T71112.
- */
bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *region, uiBlock *block)
{
/* Running this command before end-block has run, means buttons that open menus
@@ -1052,7 +1090,6 @@ bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *region, ui
return done;
}
-/* simulate button click */
void UI_but_execute(const bContext *C, ARegion *region, uiBut *but)
{
void *active_back;
@@ -1165,9 +1202,6 @@ static void ui_menu_block_set_keyaccels(uiBlock *block)
}
}
-/* XXX, this code will shorten any allocated string to 'UI_MAX_NAME_STR'
- * since this is really long its unlikely to be an issue,
- * but this could be supported */
void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_strip)
{
if (do_strip && (but->flag & UI_BUT_HAS_SEP_CHAR)) {
@@ -1206,16 +1240,21 @@ void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_str
* \{ */
static bool ui_but_event_operator_string_from_operator(const bContext *C,
- uiBut *but,
+ wmOperatorCallParams *op_call_params,
char *buf,
const size_t buf_len)
{
- BLI_assert(but->optype != NULL);
+ BLI_assert(op_call_params->optype != NULL);
bool found = false;
- IDProperty *prop = (but->opptr) ? but->opptr->data : NULL;
-
- if (WM_key_event_operator_string(
- C, but->optype->idname, but->opcontext, prop, true, buf, buf_len)) {
+ IDProperty *prop = (op_call_params->opptr) ? op_call_params->opptr->data : NULL;
+
+ if (WM_key_event_operator_string(C,
+ op_call_params->optype->idname,
+ op_call_params->opcontext,
+ prop,
+ true,
+ buf,
+ buf_len)) {
found = true;
}
return found;
@@ -1300,7 +1339,12 @@ static bool ui_but_event_operator_string(const bContext *C,
bool found = false;
if (but->optype != NULL) {
- found = ui_but_event_operator_string_from_operator(C, but, buf, buf_len);
+ found = ui_but_event_operator_string_from_operator(
+ C,
+ &(wmOperatorCallParams){
+ .optype = but->optype, .opptr = but->opptr, .opcontext = but->opcontext},
+ buf,
+ buf_len);
}
else if (UI_but_menutype_get(but) != NULL) {
found = ui_but_event_operator_string_from_menu(C, but, buf, buf_len);
@@ -1312,6 +1356,20 @@ static bool ui_but_event_operator_string(const bContext *C,
return found;
}
+static bool ui_but_extra_icon_event_operator_string(const bContext *C,
+ uiButExtraOpIcon *extra_icon,
+ char *buf,
+ const size_t buf_len)
+{
+ wmOperatorType *extra_icon_optype = UI_but_extra_operator_icon_optype_get(extra_icon);
+
+ if (extra_icon_optype) {
+ return ui_but_event_operator_string_from_operator(C, extra_icon->optype_params, buf, buf_len);
+ }
+
+ return false;
+}
+
static bool ui_but_event_property_operator_string(const bContext *C,
uiBut *but,
char *buf,
@@ -1350,6 +1408,7 @@ static bool ui_but_event_property_operator_string(const bContext *C,
const char *prop_enum_value_id = "value";
PointerRNA *ptr = &but->rnapoin;
PropertyRNA *prop = but->rnaprop;
+ int prop_index = but->rnaindex;
if ((but->type == UI_BTYPE_BUT_MENU) && (but->block->handle != NULL)) {
uiBut *but_parent = but->block->handle->popup_create_vars.but;
if ((but->type == UI_BTYPE_BUT_MENU) && (but_parent && but_parent->rnaprop) &&
@@ -1374,28 +1433,15 @@ static bool ui_but_event_property_operator_string(const bContext *C,
return false;
}
- /* this version is only for finding hotkeys for properties
- * (which get set via context using operators) */
- /* to avoid massive slowdowns on property panels, for now, we only check the
- * hotkeys for Editor / Scene settings...
- *
- * TODO: userpref settings?
- */
- char *data_path = NULL;
+ /* This version is only for finding hotkeys for properties.
+ * These are set set via a data-path which is appended to the context,
+ * manipulated using operators (see #ctx_toggle_opnames). */
if (ptr->owner_id) {
ID *id = ptr->owner_id;
if (GS(id->name) == ID_SCR) {
- /* screen/editor property
- * NOTE: in most cases, there is actually no info for backwards tracing
- * how to get back to ID from the editor data we may be dealing with
- */
- if (RNA_struct_is_a(ptr->type, &RNA_Space)) {
- /* data should be directly on here... */
- data_path = BLI_sprintfN("space_data.%s", RNA_property_identifier(prop));
- }
- else if (RNA_struct_is_a(ptr->type, &RNA_Area)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_Area)) {
/* data should be directly on here... */
const char *prop_id = RNA_property_identifier(prop);
/* Hack since keys access 'type', UI shows 'ui_type'. */
@@ -1403,58 +1449,19 @@ static bool ui_but_event_property_operator_string(const bContext *C,
prop_id = "type";
prop_enum_value >>= 16;
prop = RNA_struct_find_property(ptr, prop_id);
+ prop_index = -1;
opnames = ctx_enum_opnames_for_Area_ui_type;
opnames_len = ARRAY_SIZE(ctx_enum_opnames_for_Area_ui_type);
prop_enum_value_id = "space_type";
prop_enum_value_is_int = true;
}
- else {
- data_path = BLI_sprintfN("area.%s", prop_id);
- }
- }
- else {
- /* special exceptions for common nested data in editors... */
- if (RNA_struct_is_a(ptr->type, &RNA_DopeSheet)) {
- /* Dope-sheet filtering options. */
- data_path = BLI_sprintfN("space_data.dopesheet.%s", RNA_property_identifier(prop));
- }
- else if (RNA_struct_is_a(ptr->type, &RNA_FileSelectParams)) {
- /* File-browser options. */
- data_path = BLI_sprintfN("space_data.params.%s", RNA_property_identifier(prop));
- }
- }
- }
- else if (GS(id->name) == ID_SCE) {
- if (RNA_struct_is_a(ptr->type, &RNA_ToolSettings)) {
- /* Tool-settings property:
- * NOTE: tool-settings is usually accessed directly (i.e. not through scene). */
- data_path = RNA_path_from_ID_to_property(ptr, prop);
- }
- else {
- /* scene property */
- char *path = RNA_path_from_ID_to_property(ptr, prop);
-
- if (path) {
- data_path = BLI_sprintfN("scene.%s", path);
- MEM_freeN(path);
- }
-#if 0
- else {
- printf("ERROR in %s(): Couldn't get path for scene property - %s\n",
- __func__,
- RNA_property_identifier(prop));
- }
-#endif
}
}
- else {
- // puts("other id");
- }
-
- // printf("prop shortcut: '%s' (%s)\n", RNA_property_identifier(prop), data_path);
}
+ char *data_path = WM_context_path_resolve_property_full(C, ptr, prop, prop_index);
+
/* We have a data-path! */
bool found = false;
if (data_path || (prop_enum_value_ok && prop_enum_value_id)) {
@@ -1644,7 +1651,7 @@ typedef enum PredefinedExtraOpIconType {
static PointerRNA *ui_but_extra_operator_icon_add_ptr(uiBut *but,
wmOperatorType *optype,
- short opcontext,
+ wmOperatorCallContext opcontext,
int icon)
{
uiButExtraOpIcon *extra_op_icon = MEM_mallocN(sizeof(*extra_op_icon), __func__);
@@ -1659,6 +1666,7 @@ static PointerRNA *ui_but_extra_operator_icon_add_ptr(uiBut *but,
extra_op_icon->optype_params->optype);
extra_op_icon->optype_params->opcontext = opcontext;
extra_op_icon->highlighted = false;
+ extra_op_icon->disabled = false;
BLI_addtail(&but->extra_op_icons, extra_op_icon);
@@ -1683,7 +1691,7 @@ void ui_but_extra_operator_icons_free(uiBut *but)
PointerRNA *UI_but_extra_operator_icon_add(uiBut *but,
const char *opname,
- short opcontext,
+ wmOperatorCallContext opcontext,
int icon)
{
wmOperatorType *optype = WM_operatortype_find(opname, false);
@@ -1695,6 +1703,16 @@ PointerRNA *UI_but_extra_operator_icon_add(uiBut *but,
return NULL;
}
+wmOperatorType *UI_but_extra_operator_icon_optype_get(uiButExtraOpIcon *extra_icon)
+{
+ return extra_icon ? extra_icon->optype_params->optype : NULL;
+}
+
+PointerRNA *UI_but_extra_operator_icon_opptr_get(uiButExtraOpIcon *extra_icon)
+{
+ return extra_icon->optype_params->opptr;
+}
+
static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but)
{
BLI_assert(but->type == UI_BTYPE_TEXT);
@@ -1850,21 +1868,17 @@ static void ui_but_validate(const uiBut *but)
}
#endif
-/**
- * Check if the operator \a ot poll is successful with the context given by \a but (optionally).
- * \param but: The button that might store context. Can be NULL for convenience (e.g. if there is
- * no button to take context from, but we still want to poll the operator).
- */
-bool ui_but_context_poll_operator(bContext *C, wmOperatorType *ot, const uiBut *but)
+bool ui_but_context_poll_operator_ex(bContext *C,
+ const uiBut *but,
+ const wmOperatorCallParams *optype_params)
{
bool result;
- int opcontext = but ? but->opcontext : WM_OP_INVOKE_DEFAULT;
if (but && but->context) {
CTX_store_set(C, but->context);
}
- result = WM_operator_poll_context(C, ot, opcontext);
+ result = WM_operator_poll_context(C, optype_params->optype, optype_params->opcontext);
if (but && but->context) {
CTX_store_set(C, NULL);
@@ -1873,6 +1887,13 @@ bool ui_but_context_poll_operator(bContext *C, wmOperatorType *ot, const uiBut *
return result;
}
+bool ui_but_context_poll_operator(bContext *C, wmOperatorType *ot, const uiBut *but)
+{
+ const wmOperatorCallContext opcontext = but ? but->opcontext : WM_OP_INVOKE_DEFAULT;
+ return ui_but_context_poll_operator_ex(
+ C, but, &(wmOperatorCallParams){.optype = ot, .opcontext = opcontext});
+}
+
void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_xy[2])
{
wmWindow *window = CTX_wm_window(C);
@@ -1903,6 +1924,12 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x
}
}
+ LISTBASE_FOREACH (uiButExtraOpIcon *, op_icon, &but->extra_op_icons) {
+ if (!ui_but_context_poll_operator_ex((bContext *)C, but, op_icon->optype_params)) {
+ op_icon->disabled = true;
+ }
+ }
+
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
depsgraph, (scene) ? scene->r.cfra : 0.0f);
ui_but_anim_flag(but, &anim_eval_context);
@@ -1969,28 +1996,14 @@ void UI_block_end(const bContext *C, uiBlock *block)
{
wmWindow *window = CTX_wm_window(C);
- UI_block_end_ex(C, block, &window->eventstate->x, NULL);
+ UI_block_end_ex(C, block, window->eventstate->xy, NULL);
}
/* ************** BLOCK DRAWING FUNCTION ************* */
-void ui_fontscale(short *points, float aspect)
+void ui_fontscale(float *points, float aspect)
{
- if (aspect < 0.9f || aspect > 1.1f) {
- float pointsf = *points;
-
- /* For some reason scaling fonts goes too fast compared to widget size. */
- /* XXX(ton): not true anymore? */
- // aspect = sqrt(aspect);
- pointsf /= aspect;
-
- if (aspect > 1.0f) {
- *points = ceilf(pointsf);
- }
- else {
- *points = floorf(pointsf);
- }
- }
+ *points /= aspect;
}
/* Project button or block (but==NULL) to pixels in region-space. */
@@ -2003,7 +2016,13 @@ static void ui_but_to_pixelrect(rcti *rect, const ARegion *region, uiBlock *bloc
BLI_rcti_translate(rect, -region->winrct.xmin, -region->winrct.ymin);
}
-/* uses local copy of style, to scale things down, and allow widgets to change stuff */
+static bool ui_but_pixelrect_in_view(const ARegion *region, const rcti *rect)
+{
+ rcti rect_winspace = *rect;
+ BLI_rcti_translate(&rect_winspace, region->winrct.xmin, region->winrct.ymin);
+ return BLI_rcti_isect(&region->winrct, &rect_winspace, NULL);
+}
+
void UI_block_draw(const bContext *C, uiBlock *block)
{
uiStyle style = *UI_style_get_dpi(); /* XXX pass on as arg */
@@ -2049,24 +2068,11 @@ void UI_block_draw(const bContext *C, uiBlock *block)
ui_draw_menu_back(&style, block, &rect);
}
else if (block->panel) {
- bool show_background = region->alignment != RGN_ALIGN_FLOAT;
- if (show_background) {
- if (block->panel->type && (block->panel->type->flag & PANEL_TYPE_NO_HEADER)) {
- if (region->regiontype == RGN_TYPE_TOOLS) {
- /* We never want a background around active tools. */
- show_background = false;
- }
- else {
- /* Without a header there is no background except for region overlap. */
- show_background = region->overlap != 0;
- }
- }
- }
ui_draw_aligned_panel(&style,
block,
&rect,
UI_panel_category_is_visible(region),
- show_background,
+ UI_panel_should_show_background(region, block->panel->type),
region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE);
}
@@ -2076,14 +2082,20 @@ void UI_block_draw(const bContext *C, uiBlock *block)
/* widgets */
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
- if (!(but->flag & (UI_HIDDEN | UI_SCROLLED))) {
- ui_but_to_pixelrect(&rect, region, block, but);
+ if (but->flag & (UI_HIDDEN | UI_SCROLLED)) {
+ continue;
+ }
- /* XXX: figure out why invalid coordinates happen when closing render window */
- /* and material preview is redrawn in main window (temp fix for bug T23848) */
- if (rect.xmin < rect.xmax && rect.ymin < rect.ymax) {
- ui_draw_but(C, region, &style, but, &rect);
- }
+ ui_but_to_pixelrect(&rect, region, block, but);
+ /* Optimization: Don't draw buttons that are not visible (outside view bounds). */
+ if (!ui_but_pixelrect_in_view(region, &rect)) {
+ continue;
+ }
+
+ /* XXX: figure out why invalid coordinates happen when closing render window */
+ /* and material preview is redrawn in main window (temp fix for bug T23848) */
+ if (rect.xmin < rect.xmax && rect.ymin < rect.ymax) {
+ ui_draw_but(C, region, &style, but, &rect);
}
}
@@ -2132,11 +2144,6 @@ void UI_region_message_subscribe(ARegion *region, struct wmMsgBus *mbus)
/* ************* EVENTS ************* */
-/**
- * Check if the button is pushed, this is only meaningful for some button types.
- *
- * \return (0 == UNSELECT), (1 == SELECT), (-1 == DO-NOTHING)
- */
int ui_but_is_pushed_ex(uiBut *but, double *value)
{
int is_push = 0;
@@ -2272,7 +2279,6 @@ void UI_block_lock_clear(uiBlock *block)
* this either works with the pointed to data, or can work with
* an edit override pointer while dragging for example */
-/* for buttons pointing to color for example */
void ui_but_v3_get(uiBut *but, float vec[3])
{
if (but->editvec) {
@@ -2320,7 +2326,6 @@ void ui_but_v3_get(uiBut *but, float vec[3])
}
}
-/* for buttons pointing to color for example */
void ui_but_v3_set(uiBut *but, const float vec[3])
{
if (but->editvec) {
@@ -2432,9 +2437,6 @@ bool ui_but_is_unit(const uiBut *but)
return true;
}
-/**
- * Check if this button is similar enough to be grouped with another.
- */
bool ui_but_is_compatible(const uiBut *but_a, const uiBut *but_b)
{
if (but_a->type != but_b->type) {
@@ -2470,9 +2472,6 @@ bool ui_but_is_rna_valid(uiBut *but)
return false;
}
-/**
- * Checks if the button supports cycling next/previous menu items (ctrl+mouse-wheel).
- */
bool ui_but_supports_cycling(const uiBut *but)
{
return (ELEM(but->type, UI_BTYPE_ROW, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER, UI_BTYPE_LISTBOX) ||
@@ -2548,7 +2547,7 @@ double ui_but_value_get(uiBut *but)
void ui_but_value_set(uiBut *but, double value)
{
- /* value is a hsv value: convert to rgb */
+ /* Value is a HSV value: convert to RGB. */
if (but->rnaprop) {
PropertyRNA *prop = but->rnaprop;
@@ -2679,7 +2678,6 @@ static double ui_get_but_scale_unit(uiBut *but, double value)
return BKE_scene_unit_scale(unit, RNA_SUBTYPE_UNIT_VALUE(unit_type), value);
}
-/* str will be overwritten */
void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen)
{
if (!ui_but_is_unit(but)) {
@@ -2771,12 +2769,6 @@ static float ui_get_but_step_unit(uiBut *but, float step_default)
return (float)step_final;
}
-/**
- * \param float_precision: For number buttons the precision
- * to use or -1 to fallback to the button default.
- * \param use_exp_float: Use exponent representation of floats
- * when out of reasonable range (outside of 1e3/1e-3).
- */
void ui_but_string_get_ex(uiBut *but,
char *str,
const size_t maxlen,
@@ -2856,8 +2848,14 @@ void ui_but_string_get_ex(uiBut *but,
}
if (ui_but_is_float(but)) {
- int prec = (float_precision == -1) ? ui_but_calc_float_precision(but, value) :
- float_precision;
+ int prec = float_precision;
+
+ if (float_precision == -1) {
+ prec = ui_but_calc_float_precision(but, value);
+ }
+ else if (!use_exp_float && ui_but_hide_fraction(but, value)) {
+ prec = 0;
+ }
if (ui_but_is_unit(but)) {
ui_get_but_string_unit(but, str, maxlen, value, false, prec);
@@ -2902,12 +2900,6 @@ void ui_but_string_get(uiBut *but, char *str, const size_t maxlen)
ui_but_string_get_ex(but, str, maxlen, -1, false, NULL);
}
-/**
- * A version of #ui_but_string_get_ex for dynamic buffer sizes
- * (where #ui_but_string_get_max_length returns 0).
- *
- * \param r_str_size: size of the returned string (including terminator).
- */
char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size)
{
char *str = NULL;
@@ -3266,9 +3258,10 @@ void ui_but_range_set_hard(uiBut *but)
}
}
-/* NOTE: this could be split up into functions which handle arrays and not. */
void ui_but_range_set_soft(uiBut *but)
{
+ /* This could be split up into functions which handle arrays and not. */
+
/* Ideally we would not limit this, but practically it's more than
* enough. Worst case is very long vectors won't use a smart soft-range,
* which isn't so bad. */
@@ -3443,7 +3436,6 @@ static void ui_but_free(const bContext *C, uiBut *but)
MEM_freeN(but);
}
-/* can be called with C==NULL */
void UI_block_free(const bContext *C, uiBlock *block)
{
UI_butstore_clear(block);
@@ -3502,23 +3494,35 @@ void UI_blocklist_draw(const bContext *C, const ListBase *lb)
}
}
-/* can be called with C==NULL */
-void UI_blocklist_free(const bContext *C, ListBase *lb)
+void UI_blocklist_free(const bContext *C, ARegion *region)
{
+ ListBase *lb = &region->uiblocks;
uiBlock *block;
while ((block = BLI_pophead(lb))) {
UI_block_free(C, block);
}
+ if (region->runtime.block_name_map != NULL) {
+ BLI_ghash_free(region->runtime.block_name_map, NULL, NULL);
+ region->runtime.block_name_map = NULL;
+ }
}
-void UI_blocklist_free_inactive(const bContext *C, ListBase *lb)
+void UI_blocklist_free_inactive(const bContext *C, ARegion *region)
{
+ ListBase *lb = &region->uiblocks;
+
LISTBASE_FOREACH_MUTABLE (uiBlock *, block, lb) {
if (!block->handle) {
if (block->active) {
block->active = false;
}
else {
+ if (region->runtime.block_name_map != NULL) {
+ uiBlock *b = BLI_ghash_lookup(region->runtime.block_name_map, block->name);
+ if (b == block) {
+ BLI_ghash_remove(region->runtime.block_name_map, b->name, NULL, NULL);
+ }
+ }
BLI_remlink(lb, block);
UI_block_free(C, block);
}
@@ -3534,7 +3538,10 @@ void UI_block_region_set(uiBlock *block, ARegion *region)
/* each listbase only has one block with this name, free block
* if is already there so it can be rebuilt from scratch */
if (lb) {
- oldblock = BLI_findstring(lb, block->name, offsetof(uiBlock, name));
+ if (region->runtime.block_name_map == NULL) {
+ region->runtime.block_name_map = BLI_ghash_str_new(__func__);
+ }
+ oldblock = (uiBlock *)BLI_ghash_lookup(region->runtime.block_name_map, block->name);
if (oldblock) {
oldblock->active = false;
@@ -3544,6 +3551,7 @@ void UI_block_region_set(uiBlock *block, ARegion *region)
/* at the beginning of the list! for dynamical menus/blocks */
BLI_addhead(lb, block);
+ BLI_ghash_reinsert(region->runtime.block_name_map, block->name, block, NULL, NULL);
}
block->oldblock = oldblock;
@@ -3615,10 +3623,6 @@ bool UI_block_is_search_only(const uiBlock *block)
return block->flag & UI_BLOCK_SEARCH_ONLY;
}
-/**
- * Use when a block must be searched to give accurate results
- * for the whole region but shouldn't be displayed.
- */
void UI_block_set_search_only(uiBlock *block, bool search_only)
{
SET_FLAG_FROM_TEST(block->flag, search_only, UI_BLOCK_SEARCH_ONLY);
@@ -3959,10 +3963,6 @@ static void ui_but_alloc_info(const eButType type,
alloc_size = sizeof(uiButCurveProfile);
alloc_str = "uiButCurveProfile";
break;
- case UI_BTYPE_DATASETROW:
- alloc_size = sizeof(uiButDatasetRow);
- alloc_str = "uiButDatasetRow";
- break;
case UI_BTYPE_TREEROW:
alloc_size = sizeof(uiButTreeRow);
alloc_str = "uiButTreeRow";
@@ -3994,13 +3994,6 @@ static uiBut *ui_but_alloc(const eButType type)
return MEM_callocN(alloc_size, alloc_str);
}
-/**
- * Reallocate the button (new address is returned) for a new button type.
- * This should generally be avoided and instead the correct type be created right away.
- *
- * \note Only the #uiBut data can be kept. If the old button used a derived type (e.g. #uiButTab),
- * the data that is not inside #uiBut will be lost.
- */
uiBut *ui_but_change_type(uiBut *but, eButType new_type)
{
if (but->type == new_type) {
@@ -4165,7 +4158,6 @@ static uiBut *ui_def_but(uiBlock *block,
UI_BTYPE_BLOCK,
UI_BTYPE_BUT_MENU,
UI_BTYPE_SEARCH_MENU,
- UI_BTYPE_DATASETROW,
UI_BTYPE_TREEROW,
UI_BTYPE_POPOVER)) {
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
@@ -4235,9 +4227,6 @@ void ui_def_but_icon(uiBut *but, const int icon, const int flag)
}
}
-/**
- * Avoid using this where possible since it's better not to ask for an icon in the first place.
- */
void ui_def_but_icon_clear(uiBut *but)
{
but->icon = ICON_NONE;
@@ -4431,7 +4420,7 @@ static void ui_def_but_rna__panel_type(bContext *C, uiLayout *layout, void *but_
}
else {
char msg[256];
- SNPRINTF(msg, "Missing Panel: %s", panel_type);
+ SNPRINTF(msg, TIP_("Missing Panel: %s"), panel_type);
uiItemL(layout, msg, ICON_NONE);
}
}
@@ -4460,7 +4449,7 @@ static void ui_def_but_rna__menu_type(bContext *C, uiLayout *layout, void *but_p
}
else {
char msg[256];
- SNPRINTF(msg, "Missing Menu: %s", menu_type);
+ SNPRINTF(msg, TIP_("Missing Menu: %s"), menu_type);
uiItemL(layout, msg, ICON_NONE);
}
}
@@ -4723,7 +4712,7 @@ static uiBut *ui_def_but_rna_propname(uiBlock *block,
static uiBut *ui_def_but_operator_ptr(uiBlock *block,
int type,
wmOperatorType *ot,
- int opcontext,
+ wmOperatorCallContext opcontext,
const char *str,
int x,
int y,
@@ -4911,7 +4900,7 @@ int UI_autocomplete_end(AutoComplete *autocpl, char *autoname)
BLI_strncpy(autoname, autocpl->truncate, autocpl->maxlen);
}
else {
- if (autoname != autocpl->startname) { /* don't copy a string over its self */
+ if (autoname != autocpl->startname) { /* don't copy a string over itself */
BLI_strncpy(autoname, autocpl->startname, autocpl->maxlen);
}
}
@@ -4995,38 +4984,6 @@ uiBut *uiDefButF(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefButBit(block,
- type | UI_BUT_POIN_FLOAT,
- bit,
- retval,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefButI(uiBlock *block,
int type,
int retval,
@@ -5261,7 +5218,7 @@ uiBut *uiDefButR_prop(uiBlock *block,
uiBut *uiDefButO_ptr(uiBlock *block,
int type,
wmOperatorType *ot,
- int opcontext,
+ wmOperatorCallContext opcontext,
const char *str,
int x,
int y,
@@ -5276,7 +5233,7 @@ uiBut *uiDefButO_ptr(uiBlock *block,
uiBut *uiDefButO(uiBlock *block,
int type,
const char *opname,
- int opcontext,
+ wmOperatorCallContext opcontext,
const char *str,
int x,
int y,
@@ -5291,7 +5248,6 @@ uiBut *uiDefButO(uiBlock *block,
return uiDefButO_ptr(block, type, ot, opcontext, str, x, y, width, height, tip);
}
-/* if a1==1.0 then a2 is an extra icon blending factor (alpha 0.0 - 1.0) */
uiBut *uiDefIconBut(uiBlock *block,
int type,
int retval,
@@ -5348,68 +5304,6 @@ static uiBut *uiDefIconButBit(uiBlock *block,
tip);
}
-uiBut *uiDefIconButF(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconBut(block,
- type | UI_BUT_POIN_FLOAT,
- retval,
- icon,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconButBit(block,
- type | UI_BUT_POIN_FLOAT,
- bit,
- retval,
- icon,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconButI(uiBlock *block,
int type,
int retval,
@@ -5534,36 +5428,6 @@ uiBut *uiDefIconButBitS(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefIconButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconBut(block,
- type | UI_BUT_POIN_CHAR,
- retval,
- icon,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconButBitC(uiBlock *block,
int type,
int bit,
@@ -5644,7 +5508,7 @@ uiBut *uiDefIconButR_prop(uiBlock *block,
uiBut *uiDefIconButO_ptr(uiBlock *block,
int type,
wmOperatorType *ot,
- int opcontext,
+ wmOperatorCallContext opcontext,
int icon,
int x,
int y,
@@ -5659,7 +5523,7 @@ uiBut *uiDefIconButO_ptr(uiBlock *block,
uiBut *uiDefIconButO(uiBlock *block,
int type,
const char *opname,
- int opcontext,
+ wmOperatorCallContext opcontext,
int icon,
int x,
int y,
@@ -5671,7 +5535,6 @@ uiBut *uiDefIconButO(uiBlock *block,
return uiDefIconButO_ptr(block, type, ot, opcontext, icon, x, y, width, height, tip);
}
-/* Button containing both string label and icon */
uiBut *uiDefIconTextBut(uiBlock *block,
int type,
int retval,
@@ -5694,44 +5557,6 @@ uiBut *uiDefIconTextBut(uiBlock *block,
but->drawflag |= UI_BUT_ICON_LEFT;
return but;
}
-static uiBut *uiDefIconTextButBit(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- void *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- const int bitIdx = findBitIndex(bit);
- if (bitIdx == -1) {
- return NULL;
- }
- return uiDefIconTextBut(block,
- type | UI_BUT_POIN_BIT | bitIdx,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-
uiBut *uiDefIconTextButF(uiBlock *block,
int type,
int retval,
@@ -5764,40 +5589,6 @@ uiBut *uiDefIconTextButF(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefIconTextButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_FLOAT,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconTextButI(uiBlock *block,
int type,
int retval,
@@ -5830,172 +5621,6 @@ uiBut *uiDefIconTextButI(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefIconTextButBitI(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- int *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_INT,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButS(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextBut(block,
- type | UI_BUT_POIN_SHORT,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButBitS(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_SHORT,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextBut(block,
- type | UI_BUT_POIN_CHAR,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButBitC(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_CHAR,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconTextButR(uiBlock *block,
int type,
int retval,
@@ -6047,7 +5672,7 @@ uiBut *uiDefIconTextButR_prop(uiBlock *block,
uiBut *uiDefIconTextButO_ptr(uiBlock *block,
int type,
wmOperatorType *ot,
- int opcontext,
+ wmOperatorCallContext opcontext,
int icon,
const char *str,
int x,
@@ -6064,7 +5689,7 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block,
uiBut *uiDefIconTextButO(uiBlock *block,
int type,
const char *opname,
- int opcontext,
+ wmOperatorCallContext opcontext,
int icon,
const char *str,
int x,
@@ -6102,7 +5727,6 @@ void UI_block_direction_set(uiBlock *block, char direction)
block->direction = direction;
}
-/* this call escapes if there's alignment flags */
void UI_block_order_flip(uiBlock *block)
{
float centy, miny = 10000, maxy = -10000;
@@ -6206,23 +5830,29 @@ void UI_but_drag_set_id(uiBut *but, ID *id)
but->dragpoin = (void *)id;
}
-/**
- * \param asset: May be passed from a temporary variable, drag data only stores a copy of this.
- */
+void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale)
+{
+ but->imb = imb;
+ but->imb_scale = scale;
+}
+
void UI_but_drag_set_asset(uiBut *but,
const AssetHandle *asset,
const char *path,
+ struct AssetMetaData *metadata,
int import_type,
int icon,
struct ImBuf *imb,
float scale)
{
- wmDragAsset *asset_drag = MEM_mallocN(sizeof(*asset_drag), "wmDragAsset");
+ wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type);
- BLI_strncpy(asset_drag->name, ED_asset_handle_get_name(asset), sizeof(asset_drag->name));
- asset_drag->path = path;
- asset_drag->id_type = ED_asset_handle_get_id_type(asset);
- asset_drag->import_type = import_type;
+ /* FIXME: This is temporary evil solution to get scene/viewlayer/etc in the copy callback of the
+ * #wmDropBox.
+ * TODO: Handle link/append in operator called at the end of the drop process, and NOT in its
+ * copy callback.
+ * */
+ asset_drag->evil_C = but->block->evil_C;
but->dragtype = WM_DRAG_ASSET;
ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
@@ -6231,8 +5861,7 @@ void UI_but_drag_set_asset(uiBut *but,
}
but->dragpoin = asset_drag;
but->dragflag |= UI_BUT_DRAGPOIN_FREE;
- but->imb = imb;
- but->imb_scale = scale;
+ UI_but_drag_attach_image(but, imb, scale);
}
void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr)
@@ -6268,7 +5897,6 @@ void UI_but_drag_set_name(uiBut *but, const char *name)
but->dragpoin = (void *)name;
}
-/* value from button itself */
void UI_but_drag_set_value(uiBut *but)
{
but->dragtype = WM_DRAG_VALUE;
@@ -6287,8 +5915,7 @@ void UI_but_drag_set_image(
if (use_free) {
but->dragflag |= UI_BUT_DRAGPOIN_FREE;
}
- but->imb = imb;
- but->imb_scale = scale;
+ UI_but_drag_attach_image(but, imb, scale);
}
PointerRNA *UI_but_operator_ptr_get(uiBut *but)
@@ -6532,7 +6159,6 @@ uiBut *uiDefIconMenuBut(uiBlock *block,
return but;
}
-/* Block button containing both string label and icon */
uiBut *uiDefIconTextBlockBut(uiBlock *block,
uiBlockCreateFunc func,
void *arg,
@@ -6561,7 +6187,6 @@ uiBut *uiDefIconTextBlockBut(uiBlock *block,
return but;
}
-/* Block button containing icon */
uiBut *uiDefIconBlockBut(uiBlock *block,
uiBlockCreateFunc func,
void *arg,
@@ -6614,8 +6239,6 @@ uiBut *uiDefKeyevtButS(uiBlock *block,
return but;
}
-/* short pointers hardcoded */
-/* modkeypoin will be set to KM_SHIFT, KM_ALT, KM_CTRL, KM_OSKEY bits */
uiBut *uiDefHotKeyevtButS(uiBlock *block,
int retval,
const char *str,
@@ -6646,8 +6269,6 @@ uiBut *uiDefHotKeyevtButS(uiBlock *block,
return but;
}
-/* arg is pointer to string/name, use UI_but_func_search_set() below to make this work */
-/* here a1 and a2, if set, control thumbnail preview rows/cols */
uiBut *uiDefSearchBut(uiBlock *block,
void *arg,
int retval,
@@ -6673,21 +6294,6 @@ uiBut *uiDefSearchBut(uiBlock *block,
return but;
}
-/**
- * \note The item-pointer (referred to below) is a per search item user pointer
- * passed to #UI_search_item_add (stored in #uiSearchItems.pointers).
- *
- * \param search_create_fn: Function to create the menu.
- * \param search_update_fn: Function to refresh search content after the search text has changed.
- * \param arg: user value.
- * \param free_arg: Set to true if the argument is newly allocated memory for every redraw and
- * should be freed when the button is destroyed.
- * \param search_arg_free_fn: When non-null, use this function to free \a arg.
- * \param search_exec_fn: Function that executes the action, gets \a arg as the first argument.
- * The second argument as the active item-pointer
- * \param active: When non-null, this item-pointer item will be visible and selected,
- * otherwise the first item will be selected.
- */
void UI_but_func_search_set(uiBut *but,
uiButSearchCreateFn search_create_fn,
uiButSearchUpdateFn search_update_fn,
@@ -6754,10 +6360,6 @@ void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn co
but_search->item_context_menu_fn = context_menu_fn;
}
-/**
- * \param search_sep_string: when not NULL, this string is used as a separator,
- * showing the icon and highlighted text after the last instance of this string.
- */
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
{
uiButSearch *but_search = (uiButSearch *)but;
@@ -6810,7 +6412,7 @@ static void operator_enum_search_update_fn(const struct bContext *C,
StringSearch *search = BLI_string_search_new();
for (const EnumPropertyItem *item = all_items; item->identifier; item++) {
- BLI_string_search_add(search, item->name, (void *)item);
+ BLI_string_search_add(search, item->name, (void *)item, 0);
}
const EnumPropertyItem **filtered_items;
@@ -6854,10 +6456,6 @@ static void operator_enum_search_exec_fn(struct bContext *UNUSED(C), void *but,
}
}
-/**
- * Same parameters as for uiDefSearchBut, with additional operator type and properties,
- * used by callback to call again the right op with the right options (properties values).
- */
uiBut *uiDefSearchButO_ptr(uiBlock *block,
wmOperatorType *ot,
IDProperty *properties,
@@ -6895,15 +6493,6 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block,
return but;
}
-void UI_but_datasetrow_indentation_set(uiBut *but, int indentation)
-{
- uiButDatasetRow *but_dataset = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- but_dataset->indentation = indentation;
- BLI_assert(indentation >= 0);
-}
-
void UI_but_treerow_indentation_set(uiBut *but, int indentation)
{
uiButTreeRow *but_row = (uiButTreeRow *)but;
@@ -6913,46 +6502,11 @@ void UI_but_treerow_indentation_set(uiBut *but, int indentation)
BLI_assert(indentation >= 0);
}
-/**
- * Adds a hint to the button which draws right aligned, grayed out and never clipped.
- */
void UI_but_hint_drawstr_set(uiBut *but, const char *string)
{
ui_but_add_shortcut(but, string, false);
}
-void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type)
-{
- uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- but_dataset_row->geometry_component_type = geometry_component_type;
-}
-
-void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain)
-{
- uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- but_dataset_row->attribute_domain = attribute_domain;
-}
-
-uint8_t UI_but_datasetrow_component_get(uiBut *but)
-{
- uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- return but_dataset_row->geometry_component_type;
-}
-
-uint8_t UI_but_datasetrow_domain_get(uiBut *but)
-{
- uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- return but_dataset_row->attribute_domain;
-}
-
void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4])
{
but->flag |= UI_BUT_NODE_LINK;
@@ -6979,10 +6533,6 @@ void UI_but_number_precision_set(uiBut *but, float precision)
BLI_assert(precision > -2);
}
-/**
- * push a new event onto event queue to activate the given button
- * (usually a text-field) upon entering a popup
- */
void UI_but_focus_on_enter_event(wmWindow *win, uiBut *but)
{
wmEvent event;
@@ -6992,7 +6542,7 @@ void UI_but_focus_on_enter_event(wmWindow *win, uiBut *but)
event.val = KM_PRESS;
event.is_repeat = false;
event.customdata = but;
- event.customdatafree = false;
+ event.customdata_free = false;
wm_event_add(win, &event);
}
@@ -7242,6 +6792,42 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
}
}
+void UI_but_extra_icon_string_info_get(struct bContext *C, uiButExtraOpIcon *extra_icon, ...)
+{
+ va_list args;
+ uiStringInfo *si;
+
+ wmOperatorType *optype = UI_but_extra_operator_icon_optype_get(extra_icon);
+ PointerRNA *opptr = UI_but_extra_operator_icon_opptr_get(extra_icon);
+
+ va_start(args, extra_icon);
+ while ((si = (uiStringInfo *)va_arg(args, void *))) {
+ char *tmp = NULL;
+
+ switch (si->type) {
+ case BUT_GET_LABEL:
+ tmp = BLI_strdup(WM_operatortype_name(optype, opptr));
+ break;
+ case BUT_GET_TIP:
+ tmp = WM_operatortype_description(C, optype, opptr);
+ break;
+ case BUT_GET_OP_KEYMAP: {
+ char buf[128];
+ if (ui_but_extra_icon_event_operator_string(C, extra_icon, buf, sizeof(buf))) {
+ tmp = BLI_strdup(buf);
+ }
+ }
+ /* Other types not supported. The caller should expect that outcome, no need to message or
+ * assert here. */
+ default:
+ break;
+ }
+
+ si->strinfo = tmp;
+ }
+ va_end(args);
+}
+
/* Program Init/Exit */
void UI_init(void)
@@ -7249,7 +6835,6 @@ void UI_init(void)
ui_resources_init();
}
-/* after reading userdef file */
void UI_init_userdef(void)
{
/* Initialize UI variables from values set in the preferences. */
diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c
index 3149675ac04..35af557a560 100644
--- a/source/blender/editors/interface/interface_align.c
+++ b/source/blender/editors/interface/interface_align.c
@@ -377,13 +377,6 @@ static void ui_block_align_but_to_region(uiBut *but, const ARegion *region)
}
}
-/**
- * Compute the alignment of all 'align groups' of buttons in given block.
- *
- * This is using an order-independent algorithm,
- * i.e. alignment of buttons should be OK regardless of order in which
- * they are added to the block.
- */
void ui_block_align_calc(uiBlock *block, const ARegion *region)
{
int num_buttons = 0;
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 3101b3222c4..1d6623f3490 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -180,10 +180,6 @@ void ui_but_anim_decorate_update_from_flag(uiButDecorator *decorator_but)
but->flag = (but->flag & ~flag_copy) | (flag & flag_copy);
}
-/**
- * \a str can be NULL to only perform check if \a but has an expression at all.
- * \return if button has an expression.
- */
bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen)
{
FCurve *fcu;
@@ -241,7 +237,6 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str)
return false;
}
-/* create new expression for button (i.e. a "scripted driver"), if it can be created... */
bool ui_but_anim_expression_create(uiBut *but, const char *str)
{
bContext *C = but->block->evil_C;
diff --git a/source/blender/editors/interface/interface_button_group.c b/source/blender/editors/interface/interface_button_group.c
index 4e7da4ada33..6449e1eb329 100644
--- a/source/blender/editors/interface/interface_button_group.c
+++ b/source/blender/editors/interface/interface_button_group.c
@@ -28,10 +28,6 @@
/** \name Button Groups
* \{ */
-/**
- * Every function that adds a set of buttons must create another group,
- * then #ui_def_but adds buttons to the current group (the last).
- */
void ui_block_new_button_group(uiBlock *block, uiButtonGroupFlag flag)
{
/* Don't create a new group if there is a "lock" on new groups. */
@@ -57,7 +53,7 @@ void ui_button_group_add_but(uiBlock *block, uiBut *but)
uiButtonGroup *current_button_group = block->button_groups.last;
/* We can't use the button directly because adding it to
- * this list would mess with its prev and next pointers. */
+ * this list would mess with its `prev` and `next` pointers. */
LinkData *button_link = BLI_genericNodeN(but);
BLI_addtail(&current_button_group->buttons, button_link);
}
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index bb9e813ea50..190b2d12ed9 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -925,8 +925,19 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev
}
}
+ {
+ const ARegion *region = CTX_wm_menu(C) ? CTX_wm_menu(C) : CTX_wm_region(C);
+ uiButTreeRow *treerow_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(region, event->xy);
+ if (treerow_but) {
+ BLI_assert(treerow_but->but.type == UI_BTYPE_TREEROW);
+ UI_tree_view_item_context_menu_build(
+ C, treerow_but->tree_item, uiLayoutColumn(layout, false));
+ uiItemS(layout);
+ }
+ }
+
/* If the button represents an id, it can set the "id" context pointer. */
- if (U.experimental.use_extended_asset_browser && ED_asset_can_mark_single_from_context(C)) {
+ if (ED_asset_can_mark_single_from_context(C)) {
ID *id = CTX_data_pointer_get_type(C, "id", &RNA_ID).data;
/* Gray out items depending on if data-block is an asset. Preferably this could be done via
@@ -1201,11 +1212,10 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev
}
/* UI List item context menu. Scripts can add items to it, by default there's nothing shown. */
- ARegion *region = CTX_wm_region(C);
+ const ARegion *region = CTX_wm_menu(C) ? CTX_wm_menu(C) : CTX_wm_region(C);
const bool is_inside_listbox = ui_list_find_mouse_over(region, event) != NULL;
const bool is_inside_listrow = is_inside_listbox ?
- ui_list_row_find_mouse_over(region, event->x, event->y) !=
- NULL :
+ ui_list_row_find_mouse_over(region, event->xy) != NULL :
false;
if (is_inside_listrow) {
MenuType *mt = WM_menutype_find("UI_MT_list_item_context_menu", true);
@@ -1232,9 +1242,6 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev
/** \name Panel Context Menu
* \{ */
-/**
- * menu to show when right clicking on the panel header
- */
void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *panel)
{
bScreen *screen = CTX_wm_screen(C);
@@ -1247,6 +1254,9 @@ void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *panel)
if (panel->type->parent != NULL) {
return;
}
+ if (!UI_panel_can_be_pinned(panel)) {
+ return;
+ }
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_Panel, panel, &ptr);
diff --git a/source/blender/editors/interface/interface_context_path.cc b/source/blender/editors/interface/interface_context_path.cc
new file mode 100644
index 00000000000..0b774b79a5c
--- /dev/null
+++ b/source/blender/editors/interface/interface_context_path.cc
@@ -0,0 +1,85 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edinterface
+ */
+
+#include "BLI_vector.hh"
+
+#include "BKE_screen.h"
+
+#include "RNA_access.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_interface.hh"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+
+namespace blender::ui {
+
+void context_path_add_generic(Vector<ContextPathItem> &path,
+ StructRNA &rna_type,
+ void *ptr,
+ const BIFIconID icon_override)
+{
+ /* Add the null check here to make calling functions less verbose. */
+ if (!ptr) {
+ return;
+ }
+
+ PointerRNA rna_ptr;
+ RNA_pointer_create(nullptr, &rna_type, ptr, &rna_ptr);
+ char name[128];
+ RNA_struct_name_get_alloc(&rna_ptr, name, sizeof(name), nullptr);
+
+ /* Use a blank icon by default to check whether to retrieve it automatically from the type. */
+ const BIFIconID icon = icon_override == ICON_NONE ?
+ static_cast<BIFIconID>(RNA_struct_ui_icon(rna_ptr.type)) :
+ icon_override;
+
+ path.append({name, static_cast<int>(icon)});
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Breadcrumb Template
+ * \{ */
+
+void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path)
+{
+ uiLayout *row = uiLayoutRow(&layout, true);
+ uiLayoutSetAlignment(&layout, UI_LAYOUT_ALIGN_LEFT);
+
+ for (const int i : context_path.index_range()) {
+ uiLayout *sub_row = uiLayoutRow(row, true);
+ uiLayoutSetAlignment(sub_row, UI_LAYOUT_ALIGN_LEFT);
+
+ if (i > 0) {
+ uiItemL(sub_row, "", ICON_RIGHTARROW_THIN);
+ }
+ uiItemL(sub_row, context_path[i].name.c_str(), context_path[i].icon);
+ }
+}
+
+/** \} */
+
+} // namespace blender::ui
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index ebebf69bc11..f7492e56b62 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -57,6 +57,7 @@
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
+#include "GPU_shader_shared.h"
#include "GPU_state.h"
#include "UI_interface.h"
@@ -178,35 +179,6 @@ void UI_draw_roundbox_4fv(const rctf *rect, bool filled, float rad, const float
UI_draw_roundbox_4fv_ex(rect, (filled) ? col : NULL, NULL, 1.0f, col, U.pixelsize, rad);
}
-/* linear horizontal shade within button or in outline */
-/* view2d scrollers use it */
-void UI_draw_roundbox_shade_x(
- const rctf *rect, bool filled, float rad, float shadetop, float shadedown, const float col[4])
-{
- float inner1[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- float inner2[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- float outline[4];
-
- if (filled) {
- inner1[0] = min_ff(1.0f, col[0] + shadetop);
- inner1[1] = min_ff(1.0f, col[1] + shadetop);
- inner1[2] = min_ff(1.0f, col[2] + shadetop);
- inner1[3] = 1.0f;
- inner2[0] = max_ff(0.0f, col[0] + shadedown);
- inner2[1] = max_ff(0.0f, col[1] + shadedown);
- inner2[2] = max_ff(0.0f, col[2] + shadedown);
- inner2[3] = 1.0f;
- }
-
- /* TODO: non-filled box don't have gradients. Just use middle color. */
- outline[0] = clamp_f(col[0] + shadetop + shadedown, 0.0f, 1.0f);
- outline[1] = clamp_f(col[1] + shadetop + shadedown, 0.0f, 1.0f);
- outline[2] = clamp_f(col[2] + shadetop + shadedown, 0.0f, 1.0f);
- outline[3] = clamp_f(col[3] + shadetop + shadedown, 0.0f, 1.0f);
-
- UI_draw_roundbox_4fv_ex(rect, inner1, inner2, 1.0f, outline, U.pixelsize, rad);
-}
-
void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4])
{
const int ofs_y = 4 * U.pixelsize;
@@ -223,8 +195,6 @@ void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const flo
/* ************** SPECIAL BUTTON DRAWING FUNCTIONS ************* */
-/* based on UI_draw_roundbox_gl_mode,
- * check on making a version which allows us to skip some sides */
void ui_draw_but_TAB_outline(const rcti *rect,
float rad,
uchar highlight[3],
@@ -355,17 +325,17 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region),
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(&state,
- (float)rect->xmin,
- (float)rect->ymin,
- ibuf->x,
- ibuf->y,
- GPU_RGBA8,
- false,
- ibuf->rect,
- 1.0f,
- 1.0f,
- col);
+ immDrawPixelsTexTiled(&state,
+ (float)rect->xmin,
+ (float)rect->ymin,
+ ibuf->x,
+ ibuf->y,
+ GPU_RGBA8,
+ false,
+ ibuf->rect,
+ 1.0f,
+ 1.0f,
+ col);
GPU_blend(GPU_BLEND_NONE);
@@ -377,14 +347,6 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region),
#endif
}
-/**
- * Draw title and text safe areas.
- *
- * \note This function is to be used with the 2D dashed shader enabled.
- *
- * \param pos: is a #PRIM_FLOAT, 2, #GPU_FETCH_FLOAT vertex attribute.
- * \param x1, x2, y1, y2: The offsets for the view, not the zones.
- */
void UI_draw_safe_areas(uint pos,
const rctf *rect,
const float title_aspect[2],
@@ -1380,7 +1342,10 @@ void ui_draw_but_COLORBAND(uiBut *but, const uiWidgetColors *UNUSED(wcol), const
immUnbindProgram();
}
-void ui_draw_but_UNITVEC(uiBut *but, const uiWidgetColors *wcol, const rcti *rect)
+void ui_draw_but_UNITVEC(uiBut *but,
+ const uiWidgetColors *wcol,
+ const rcti *rect,
+ const float radius)
{
/* sphere color */
const float diffuse[3] = {1.0f, 1.0f, 1.0f};
@@ -1397,7 +1362,7 @@ void ui_draw_but_UNITVEC(uiBut *but, const uiWidgetColors *wcol, const rcti *rec
.ymax = rect->ymax,
},
true,
- 5.0f,
+ radius,
wcol->inner,
255);
@@ -1420,10 +1385,16 @@ void ui_draw_but_UNITVEC(uiBut *but, const uiWidgetColors *wcol, const rcti *rec
GPU_matrix_scale_1f(size);
GPUBatch *sphere = GPU_batch_preset_sphere(2);
+ struct SimpleLightingData simple_lighting_data;
+ copy_v4_fl4(simple_lighting_data.color, diffuse[0], diffuse[1], diffuse[2], 1.0f);
+ copy_v3_v3(simple_lighting_data.light, light);
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
+ sizeof(struct SimpleLightingData), &simple_lighting_data, __func__);
+
GPU_batch_program_set_builtin(sphere, GPU_SHADER_SIMPLE_LIGHTING);
- GPU_batch_uniform_4f(sphere, "color", diffuse[0], diffuse[1], diffuse[2], 1.0f);
- GPU_batch_uniform_3fv(sphere, "light", light);
+ GPU_batch_uniformbuf_bind(sphere, "simple_lighting_data", ubo);
GPU_batch_draw(sphere);
+ GPU_uniformbuf_free(ubo);
/* Restore. */
GPU_face_culling(GPU_CULL_NONE);
@@ -1779,9 +1750,6 @@ static bool point_draw_handles(CurveProfilePoint *point)
ELEM(point->flag, PROF_H1_SELECT, PROF_H2_SELECT);
}
-/**
- * Draws the curve profile widget. Somewhat similar to ui_draw_but_CURVE.
- */
void ui_draw_but_CURVEPROFILE(ARegion *region,
uiBut *but,
const uiWidgetColors *wcol,
@@ -1860,13 +1828,13 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
/* Also add the last points on the right and bottom edges to close off the fill polygon. */
const bool add_left_tri = profile->view_rect.xmin < 0.0f;
const bool add_bottom_tri = profile->view_rect.ymin < 0.0f;
- uint tot_points = (uint)PROF_TABLE_LEN(profile->path_len) + 1 + add_left_tri + add_bottom_tri;
+ int tot_points = BKE_curveprofile_table_size(profile) + 1 + add_left_tri + add_bottom_tri;
const 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 (uint i = 0; i < (uint)PROF_TABLE_LEN(profile->path_len);
- i++) { /* Only add the points from the table here. */
+ for (uint i = 0; i < (uint)BKE_curveprofile_table_size(profile); i++) {
+ /* Only add the points from the table here. */
table_coords[i][0] = pts[i].x;
table_coords[i][1] = pts[i].y;
}
@@ -1903,44 +1871,50 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
}
/* Calculate the table point indices of the triangles for the profile's fill. */
- uint(*tri_indices)[3] = MEM_mallocN(sizeof(*tri_indices) * tot_triangles, "return tri indices");
- BLI_polyfill_calc(table_coords, tot_points, -1, tri_indices);
+ if (tot_triangles > 0) {
+ uint(*tri_indices)[3] = MEM_mallocN(sizeof(*tri_indices) * tot_triangles, __func__);
+ BLI_polyfill_calc(table_coords, tot_points, -1, tri_indices);
- /* Draw the triangles for the profile fill. */
- immUniformColor3ubvAlpha((const uchar *)wcol->item, 128);
- GPU_blend(GPU_BLEND_ALPHA);
- GPU_polygon_smooth(false);
- immBegin(GPU_PRIM_TRIS, 3 * tot_triangles);
- for (uint i = 0; i < tot_triangles; i++) {
- for (uint j = 0; j < 3; j++) {
- uint *tri = tri_indices[i];
- fx = rect->xmin + zoomx * (table_coords[tri[j]][0] - offsx);
- fy = rect->ymin + zoomy * (table_coords[tri[j]][1] - offsy);
- immVertex2f(pos, fx, fy);
+ /* Draw the triangles for the profile fill. */
+ immUniformColor3ubvAlpha((const uchar *)wcol->item, 128);
+ GPU_blend(GPU_BLEND_ALPHA);
+ GPU_polygon_smooth(false);
+ immBegin(GPU_PRIM_TRIS, 3 * tot_triangles);
+ for (uint i = 0; i < tot_triangles; i++) {
+ for (uint j = 0; j < 3; j++) {
+ uint *tri = tri_indices[i];
+ fx = rect->xmin + zoomx * (table_coords[tri[j]][0] - offsx);
+ fy = rect->ymin + zoomy * (table_coords[tri[j]][1] - offsy);
+ immVertex2f(pos, fx, fy);
+ }
}
+ immEnd();
+ MEM_freeN(tri_indices);
}
- immEnd();
- MEM_freeN(tri_indices);
/* Draw the profile's path so the edge stands out a bit. */
tot_points -= (add_left_tri + add_left_tri);
- GPU_line_width(1.0f);
- immUniformColor3ubvAlpha((const uchar *)wcol->item, 255);
- GPU_line_smooth(true);
- immBegin(GPU_PRIM_LINE_STRIP, tot_points - 1);
- for (uint i = 0; i < tot_points - 1; i++) {
- fx = rect->xmin + zoomx * (table_coords[i][0] - offsx);
- fy = rect->ymin + zoomy * (table_coords[i][1] - offsy);
- immVertex2f(pos, fx, fy);
+ const int edges_len = tot_points - 1;
+ if (edges_len > 0) {
+ GPU_line_width(1.0f);
+ immUniformColor3ubvAlpha((const uchar *)wcol->item, 255);
+ GPU_line_smooth(true);
+ immBegin(GPU_PRIM_LINE_STRIP, tot_points);
+ for (int i = 0; i < tot_points; i++) {
+ fx = rect->xmin + zoomx * (table_coords[i][0] - offsx);
+ fy = rect->ymin + zoomy * (table_coords[i][1] - offsy);
+ immVertex2f(pos, fx, fy);
+ }
+ immEnd();
}
- immEnd();
- MEM_freeN(table_coords);
+
+ MEM_SAFE_FREE(table_coords);
/* Draw the handles for the selected control points. */
pts = profile->path;
- tot_points = (uint)profile->path_len;
+ const int path_len = tot_points = (uint)profile->path_len;
int selected_free_points = 0;
- for (uint i = 0; i < tot_points; i++) {
+ for (int i = 0; i < path_len; i++) {
if (point_draw_handles(&pts[i])) {
selected_free_points++;
}
@@ -1952,7 +1926,7 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
GPU_line_smooth(true);
immBegin(GPU_PRIM_LINES, selected_free_points * 4);
float ptx, pty;
- for (uint i = 0; i < tot_points; i++) {
+ for (int i = 0; i < path_len; i++) {
if (point_draw_handles(&pts[i])) {
ptx = rect->xmin + zoomx * (pts[i].x - offsx);
pty = rect->ymin + zoomy * (pts[i].y - offsy);
@@ -1996,16 +1970,18 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
/* Draw the control points. */
GPU_line_smooth(false);
- GPU_blend(GPU_BLEND_NONE);
- GPU_point_size(max_ff(3.0f, min_ff(UI_DPI_FAC / but->block->aspect * 5.0f, 5.0f)));
- immBegin(GPU_PRIM_POINTS, tot_points);
- for (uint i = 0; i < tot_points; i++) {
- fx = rect->xmin + zoomx * (pts[i].x - offsx);
- fy = rect->ymin + zoomy * (pts[i].y - offsy);
- immAttr4fv(col, (pts[i].flag & PROF_SELECT) ? color_vert_select : color_vert);
- immVertex2f(pos, fx, fy);
+ if (path_len > 0) {
+ GPU_blend(GPU_BLEND_NONE);
+ GPU_point_size(max_ff(3.0f, min_ff(UI_DPI_FAC / but->block->aspect * 5.0f, 5.0f)));
+ immBegin(GPU_PRIM_POINTS, path_len);
+ for (int i = 0; i < path_len; i++) {
+ fx = rect->xmin + zoomx * (pts[i].x - offsx);
+ fy = rect->ymin + zoomy * (pts[i].y - offsy);
+ immAttr4fv(col, (pts[i].flag & PROF_SELECT) ? color_vert_select : color_vert);
+ immVertex2f(pos, fx, fy);
+ }
+ immEnd();
}
- immEnd();
/* Draw the handle points. */
if (selected_free_points > 0) {
@@ -2013,7 +1989,7 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
GPU_blend(GPU_BLEND_NONE);
GPU_point_size(max_ff(2.0f, min_ff(UI_DPI_FAC / but->block->aspect * 4.0f, 4.0f)));
immBegin(GPU_PRIM_POINTS, selected_free_points * 2);
- for (uint i = 0; i < tot_points; i++) {
+ for (int i = 0; i < path_len; i++) {
if (point_draw_handles(&pts[i])) {
fx = rect->xmin + zoomx * (pts[i].h1_loc[0] - offsx);
fy = rect->ymin + zoomy * (pts[i].h1_loc[1] - offsy);
@@ -2031,11 +2007,11 @@ void ui_draw_but_CURVEPROFILE(ARegion *region,
/* Draw the sampled points in addition to the control points if they have been created */
pts = profile->segments;
- tot_points = (uint)profile->segments_len;
- if (tot_points > 0 && pts) {
+ const int segments_len = (uint)profile->segments_len;
+ if (segments_len > 0 && pts) {
GPU_point_size(max_ff(2.0f, min_ff(UI_DPI_FAC / but->block->aspect * 3.0f, 3.0f)));
- immBegin(GPU_PRIM_POINTS, tot_points);
- for (uint i = 0; i < tot_points; i++) {
+ immBegin(GPU_PRIM_POINTS, segments_len);
+ for (int i = 0; i < segments_len; i++) {
fx = rect->xmin + zoomx * (pts[i].x - offsx);
fy = rect->ymin + zoomy * (pts[i].y - offsy);
immAttr4fv(col, color_sample);
@@ -2159,17 +2135,17 @@ void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(region),
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(&state,
- rect.xmin,
- rect.ymin + 1,
- drawibuf->x,
- drawibuf->y,
- GPU_RGBA8,
- true,
- drawibuf->rect,
- 1.0f,
- 1.0f,
- NULL);
+ immDrawPixelsTexTiled(&state,
+ rect.xmin,
+ rect.ymin + 1,
+ drawibuf->x,
+ drawibuf->y,
+ GPU_RGBA8,
+ true,
+ drawibuf->rect,
+ 1.0f,
+ 1.0f,
+ NULL);
/* draw cross for pixel position */
GPU_matrix_translate_2f(rect.xmin + scopes->track_pos[0], rect.ymin + scopes->track_pos[1]);
diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc
new file mode 100644
index 00000000000..369efa7c52e
--- /dev/null
+++ b/source/blender/editors/interface/interface_dropboxes.cc
@@ -0,0 +1,95 @@
+/*
+ * 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 edinterface
+ */
+
+#include "BKE_context.h"
+
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+
+#include "UI_interface.h"
+
+static bool ui_tree_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
+{
+ const ARegion *region = CTX_wm_region(C);
+ const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region,
+ event->xy);
+ if (!hovered_tree_item) {
+ return false;
+ }
+
+ if (drag->drop_state.free_disabled_info) {
+ MEM_SAFE_FREE(drag->drop_state.disabled_info);
+ }
+
+ drag->drop_state.free_disabled_info = false;
+ return UI_tree_view_item_can_drop(hovered_tree_item, drag, &drag->drop_state.disabled_info);
+}
+
+static char *ui_tree_view_drop_tooltip(bContext *C,
+ wmDrag *drag,
+ const int xy[2],
+ wmDropBox *UNUSED(drop))
+{
+ const ARegion *region = CTX_wm_region(C);
+ const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region, xy);
+ if (!hovered_tree_item) {
+ return nullptr;
+ }
+
+ return UI_tree_view_item_drop_tooltip(hovered_tree_item, drag);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static bool ui_drop_name_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(event))
+{
+ return UI_but_active_drop_name(C) && (drag->type == WM_DRAG_ID);
+}
+
+static void ui_drop_name_copy(wmDrag *drag, wmDropBox *drop)
+{
+ const ID *id = WM_drag_get_local_ID(drag, 0);
+ RNA_string_set(drop->ptr, "string", id->name + 2);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void ED_dropboxes_ui()
+{
+ ListBase *lb = WM_dropboxmap_find("User Interface", SPACE_EMPTY, 0);
+
+ WM_dropbox_add(lb,
+ "UI_OT_tree_view_drop",
+ ui_tree_view_drop_poll,
+ nullptr,
+ nullptr,
+ ui_tree_view_drop_tooltip);
+ WM_dropbox_add(lb,
+ "UI_OT_drop_name",
+ ui_drop_name_poll,
+ ui_drop_name_copy,
+ WM_drag_free_imported_drag_ID,
+ nullptr);
+}
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 58a9f362488..fd03cc5e12c 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -103,8 +103,10 @@ wmKeyMap *eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf)
/* -------------------------------------------------------------------- */
/* Utility Functions
*/
+
/** \name Generic Shared Functions
* \{ */
+
static void eyedropper_draw_cursor_text_ex(const int x, const int y, const char *name)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
@@ -126,8 +128,8 @@ void eyedropper_draw_cursor_text_window(const struct wmWindow *window, const cha
return;
}
- const int x = window->eventstate->x;
- const int y = window->eventstate->y;
+ const int x = window->eventstate->xy[0];
+ const int y = window->eventstate->xy[1];
eyedropper_draw_cursor_text_ex(x, y, name);
}
@@ -141,20 +143,11 @@ void eyedropper_draw_cursor_text_region(const int x, const int y, const char *na
eyedropper_draw_cursor_text_ex(x, y, name);
}
-/**
- * Utility to retrieve a button representing a RNA property that is currently under the cursor.
- *
- * This is to be used by any eyedroppers which fetch properties (e.g. UI_OT_eyedropper_driver).
- * Especially during modal operations (e.g. as with the eyedroppers), context cannot be relied
- * upon to provide this information, as it is not updated until the operator finishes.
- *
- * \return A button under the mouse which relates to some RNA Property, or NULL
- */
uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
- const ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, event->x, event->y);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
+ const ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, event->xy);
uiBut *but = ui_but_find_mouse_over(region, event);
@@ -170,13 +163,13 @@ void datadropper_win_area_find(
bScreen *screen = CTX_wm_screen(C);
*r_win = CTX_wm_window(C);
- *r_area = BKE_screen_find_area_xy(screen, -1, mval[0], mval[1]);
+ *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mval);
if (*r_area == NULL) {
wmWindowManager *wm = CTX_wm_manager(C);
*r_win = WM_window_find_under_cursor(wm, NULL, *r_win, mval, r_mval);
if (*r_win) {
screen = WM_window_get_active_screen(*r_win);
- *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, r_mval[0], r_mval[1]);
+ *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, r_mval);
}
}
else if (mval != r_mval) {
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 9d06fb2b27a..05840175fab 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -42,6 +42,8 @@
#include "BKE_node.h"
#include "BKE_screen.h"
+#include "NOD_composite.h"
+
#include "RNA_access.h"
#include "UI_interface.h"
@@ -263,33 +265,33 @@ static bool eyedropper_cryptomatte_sample_fl(
}
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
- if (!sa || !ELEM(sa->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) {
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, (const int[2]){mx, my});
+ if (!area || !ELEM(area->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) {
return false;
}
- ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
- if (!ar) {
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my});
+ if (!region) {
return false;
}
- int mval[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin};
+ int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
float fpos[2] = {-1.0f, -1.0};
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
- ED_space_image_get_position(sima, ar, mval, fpos);
+ SpaceImage *sima = area->spacedata.first;
+ ED_space_image_get_position(sima, region, mval, fpos);
break;
}
case SPACE_NODE: {
Main *bmain = CTX_data_main(C);
- SpaceNode *snode = sa->spacedata.first;
- ED_space_node_get_position(bmain, snode, ar, mval, fpos);
+ SpaceNode *snode = area->spacedata.first;
+ ED_space_node_get_position(bmain, snode, region, mval, fpos);
break;
}
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
- ED_space_clip_get_position(sc, ar, mval, fpos);
+ SpaceClip *sc = area->spacedata.first;
+ ED_space_clip_get_position(sc, region, mval, fpos);
break;
}
default: {
@@ -322,13 +324,6 @@ static bool eyedropper_cryptomatte_sample_fl(
return false;
}
-/**
- * \brief get the color from the screen.
- *
- * Special check for image or nodes where we MAY have HDR pixels which don't display.
- *
- * \note Exposed by 'interface_eyedropper_intern.h' for use with color band picking.
- */
void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
{
/* we could use some clever */
@@ -344,7 +339,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
if (area) {
if (area->spacetype == SPACE_IMAGE) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceImage *sima = area->spacedata.first;
int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
@@ -355,7 +350,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
}
}
else if (area->spacetype == SPACE_NODE) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceNode *snode = area->spacedata.first;
int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
@@ -366,7 +361,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
}
}
else if (area->spacetype == SPACE_CLIP) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceClip *sc = area->spacedata.first;
int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
@@ -481,7 +476,7 @@ static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
case EYE_MODAL_SAMPLE_CONFIRM: {
const bool is_undo = eye->is_undo;
if (eye->accum_tot == 0) {
- eyedropper_color_sample(C, eye, event->x, event->y);
+ eyedropper_color_sample(C, eye, event->xy[0], event->xy[1]);
}
eyedropper_exit(C, op);
/* Could support finished & undo-skip. */
@@ -490,23 +485,23 @@ static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
case EYE_MODAL_SAMPLE_BEGIN:
/* enable accum and make first sample */
eye->accum_start = true;
- eyedropper_color_sample(C, eye, event->x, event->y);
+ eyedropper_color_sample(C, eye, event->xy[0], event->xy[1]);
break;
case EYE_MODAL_SAMPLE_RESET:
eye->accum_tot = 0;
zero_v3(eye->accum_col);
- eyedropper_color_sample(C, eye, event->x, event->y);
+ eyedropper_color_sample(C, eye, event->xy[0], event->xy[1]);
break;
}
}
else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
if (eye->accum_start) {
/* button is pressed so keep sampling */
- eyedropper_color_sample(C, eye, event->x, event->y);
+ eyedropper_color_sample(C, eye, event->xy[0], event->xy[1]);
}
if (eye->draw_handle_sample_text) {
- eyedropper_color_sample_text_update(C, eye, event->x, event->y);
+ eyedropper_color_sample_text_update(C, eye, event->xy[0], event->xy[1]);
ED_region_tag_redraw(CTX_wm_region(C));
}
}
diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c
index d32eb415b19..22320282766 100644
--- a/source/blender/editors/interface/interface_eyedropper_colorband.c
+++ b/source/blender/editors/interface/interface_eyedropper_colorband.c
@@ -233,7 +233,7 @@ static int eyedropper_colorband_modal(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
case EYE_MODAL_SAMPLE_CONFIRM: {
const bool is_undo = eye->is_undo;
- eyedropper_colorband_sample_segment(C, eye, event->x, event->y);
+ eyedropper_colorband_sample_segment(C, eye, event->xy[0], event->xy[1]);
eyedropper_colorband_apply(C, op);
eyedropper_colorband_exit(C, op);
/* Could support finished & undo-skip. */
@@ -242,10 +242,10 @@ static int eyedropper_colorband_modal(bContext *C, wmOperator *op, const wmEvent
case EYE_MODAL_SAMPLE_BEGIN:
/* enable accum and make first sample */
eye->sample_start = true;
- eyedropper_colorband_sample_point(C, eye, event->x, event->y);
+ eyedropper_colorband_sample_point(C, eye, event->xy[0], event->xy[1]);
eyedropper_colorband_apply(C, op);
- eye->last_x = event->x;
- eye->last_y = event->y;
+ eye->last_x = event->xy[0];
+ eye->last_y = event->xy[1];
break;
case EYE_MODAL_SAMPLE_RESET:
break;
@@ -253,7 +253,7 @@ static int eyedropper_colorband_modal(bContext *C, wmOperator *op, const wmEvent
}
else if (event->type == MOUSEMOVE) {
if (eye->sample_start) {
- eyedropper_colorband_sample_segment(C, eye, event->x, event->y);
+ eyedropper_colorband_sample_segment(C, eye, event->xy[0], event->xy[1]);
eyedropper_colorband_apply(C, op);
}
}
@@ -280,7 +280,7 @@ static int eyedropper_colorband_point_modal(bContext *C, wmOperator *op, const w
}
break;
case EYE_MODAL_POINT_SAMPLE:
- eyedropper_colorband_sample_point(C, eye, event->x, event->y);
+ eyedropper_colorband_sample_point(C, eye, event->xy[0], event->xy[1]);
eyedropper_colorband_apply(C, op);
if (eye->color_buffer_len == MAXCOLORBAND) {
eyedropper_colorband_exit(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index 4996c803dfe..cf53ef0ec75 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -162,7 +162,7 @@ static void datadropper_id_sample_pt(
if (area) {
if (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my});
if (region) {
const int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
Base *base;
@@ -292,7 +292,7 @@ static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
case EYE_MODAL_SAMPLE_CONFIRM: {
const bool is_undo = ddr->is_undo;
- const bool success = datadropper_id_sample(C, ddr, event->x, event->y);
+ const bool success = datadropper_id_sample(C, ddr, event->xy[0], event->xy[1]);
datadropper_exit(C, op);
if (success) {
/* Could support finished & undo-skip. */
@@ -309,7 +309,7 @@ static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmWindow *win;
ScrArea *area;
- int mval[] = {event->x, event->y};
+ int mval[] = {event->xy[0], event->xy[1]};
datadropper_win_area_find(C, mval, mval, &win, &area);
/* Set the region for eyedropper cursor text drawing */
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index 311f718d950..8c6b0ac9cfe 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -157,7 +157,7 @@ static void depthdropper_depth_sample_pt(
{
/* we could use some clever */
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, (const int[2]){mx, my});
Scene *scene = CTX_data_scene(C);
ScrArea *area_prev = CTX_wm_area(C);
@@ -167,7 +167,7 @@ static void depthdropper_depth_sample_pt(
if (area) {
if (area->spacetype == SPACE_VIEW3D) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my});
if (region) {
struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
View3D *v3d = area->spacedata.first;
@@ -276,7 +276,7 @@ static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
case EYE_MODAL_SAMPLE_CONFIRM: {
const bool is_undo = ddr->is_undo;
if (ddr->accum_tot == 0) {
- depthdropper_depth_sample(C, ddr, event->x, event->y);
+ depthdropper_depth_sample(C, ddr, event->xy[0], event->xy[1]);
}
else {
depthdropper_depth_set_accum(C, ddr);
@@ -288,12 +288,12 @@ static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
case EYE_MODAL_SAMPLE_BEGIN:
/* enable accum and make first sample */
ddr->accum_start = true;
- depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
+ depthdropper_depth_sample_accum(C, ddr, event->xy[0], event->xy[1]);
break;
case EYE_MODAL_SAMPLE_RESET:
ddr->accum_tot = 0;
ddr->accum_depth = 0.0f;
- depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
+ depthdropper_depth_sample_accum(C, ddr, event->xy[0], event->xy[1]);
depthdropper_depth_set_accum(C, ddr);
break;
}
@@ -301,7 +301,7 @@ static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
else if (event->type == MOUSEMOVE) {
if (ddr->accum_start) {
/* button is pressed so keep sampling */
- depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
+ depthdropper_depth_sample_accum(C, ddr, event->xy[0], event->xy[1]);
depthdropper_depth_set_accum(C, ddr);
}
}
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c
index ccf0e727da8..6fe930b74d2 100644
--- a/source/blender/editors/interface/interface_eyedropper_driver.c
+++ b/source/blender/editors/interface/interface_eyedropper_driver.c
@@ -107,7 +107,7 @@ static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *eve
char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop);
/* ... and destination */
- char *dst_path = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL);
+ char *dst_path = RNA_path_from_ID_to_property(&ddr->ptr, ddr->prop);
/* Now create driver(s) */
if (target_path && dst_path) {
diff --git a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
index 417807afff1..d76ff84bcad 100644
--- a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
@@ -292,7 +292,7 @@ static int eyedropper_gpencil_modal(bContext *C, wmOperator *op, const wmEvent *
return OPERATOR_CANCELLED;
}
case EYE_MODAL_SAMPLE_CONFIRM: {
- eyedropper_gpencil_color_sample(C, eye, event->x, event->y);
+ eyedropper_gpencil_color_sample(C, eye, event->xy[0], event->xy[1]);
/* Create material. */
eyedropper_gpencil_color_set(C, event, eye);
@@ -309,7 +309,7 @@ static int eyedropper_gpencil_modal(bContext *C, wmOperator *op, const wmEvent *
}
case MOUSEMOVE:
case INBETWEEN_MOUSEMOVE: {
- eyedropper_gpencil_color_sample(C, eye, event->x, event->y);
+ eyedropper_gpencil_color_sample(C, eye, event->xy[0], event->xy[1]);
break;
}
default: {
diff --git a/source/blender/editors/interface/interface_eyedropper_intern.h b/source/blender/editors/interface/interface_eyedropper_intern.h
index f9f3fcfb5d1..ec448ef9b9f 100644
--- a/source/blender/editors/interface/interface_eyedropper_intern.h
+++ b/source/blender/editors/interface/interface_eyedropper_intern.h
@@ -23,8 +23,18 @@
#pragma once
/* interface_eyedropper.c */
+
void eyedropper_draw_cursor_text_window(const struct wmWindow *window, const char *name);
-void eyedropper_draw_cursor_text_region(const int x, const int y, const char *name);
+void eyedropper_draw_cursor_text_region(int x, int y, const char *name);
+/**
+ * Utility to retrieve a button representing a RNA property that is currently under the cursor.
+ *
+ * This is to be used by any eyedroppers which fetch properties (e.g. UI_OT_eyedropper_driver).
+ * Especially during modal operations (e.g. as with the eyedroppers), context cannot be relied
+ * upon to provide this information, as it is not updated until the operator finishes.
+ *
+ * \return A button under the mouse which relates to some RNA Property, or NULL
+ */
uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event);
void datadropper_win_area_find(const struct bContext *C,
const int mval[2],
@@ -33,6 +43,14 @@ void datadropper_win_area_find(const struct bContext *C,
struct ScrArea **r_area);
/* interface_eyedropper_color.c (expose for color-band picker) */
+
+/**
+ * \brief get the color from the screen.
+ *
+ * Special check for image or nodes where we MAY have HDR pixels which don't display.
+ *
+ * \note Exposed by 'interface_eyedropper_intern.h' for use with color band picking.
+ */
void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]);
/* Used for most eye-dropper operators. */
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index aee66ec3a93..905fd452b6c 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -358,7 +358,7 @@ typedef struct uiHandleButtonMulti {
* here so we can tell if this is a vertical motion or not. */
float drag_dir[2];
- /* values copied direct from event->x,y
+ /* values copied direct from event->xy
* used to detect buttons between the current and initial mouse position */
int drag_start[2];
@@ -395,13 +395,10 @@ typedef struct uiHandleButtonData {
char *origstr;
double value, origvalue, startvalue;
float vec[3], origvec[3];
-#if 0 /* UNUSED */
- int togdual, togonly;
-#endif
ColorBand *coba;
- /* Tool-tip. */
- uint tooltip_force : 1;
+ /* True when alt is held and the preference for displaying tooltips should be ignored. */
+ bool tooltip_force;
/* auto open */
bool used_mouse;
@@ -442,11 +439,11 @@ typedef struct uiHandleButtonData {
float ungrab_mval[2];
#endif
- /* menu open (watch UI_screen_free_active_but) */
+ /* Menu open, see: #UI_screen_free_active_but_highlight. */
uiPopupBlockHandle *menu;
int menuretval;
- /* search box (watch UI_screen_free_active_but) */
+ /* Search box see: #UI_screen_free_active_but_highlight. */
ARegion *searchbox;
#ifdef USE_KEYNAV_LIMIT
struct uiKeyNavLock searchbox_keynav_state;
@@ -495,7 +492,7 @@ typedef struct uiAfterFunc {
wmOperator *popup_op;
wmOperatorType *optype;
- int opcontext;
+ wmOperatorCallContext opcontext;
PointerRNA *opptr;
PointerRNA rnapoin;
@@ -558,7 +555,6 @@ bool ui_but_is_editing(const uiBut *but)
return (data && ELEM(data->state, BUTTON_STATE_TEXT_EDITING, BUTTON_STATE_NUM_EDITING));
}
-/* assumes event type is MOUSEPAN */
void ui_pan_to_scroll(const wmEvent *event, int *type, int *val)
{
static int lastdy = 0;
@@ -597,11 +593,6 @@ static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but
(but_a->rnaprop == but_b->rnaprop));
}
-/**
- * Finds the pressed button in an aligned row (typically an expanded enum).
- *
- * \param direction: Use when there may be multiple buttons pressed.
- */
uiBut *ui_but_find_select_in_enum(uiBut *but, int direction)
{
uiBut *but_iter = but;
@@ -778,7 +769,7 @@ static uiAfterFunc *ui_afterfunc_new(void)
*/
static void ui_handle_afterfunc_add_operator_ex(wmOperatorType *ot,
PointerRNA **properties,
- int opcontext,
+ wmOperatorCallContext opcontext,
const uiBut *context_but)
{
uiAfterFunc *after = ui_afterfunc_new();
@@ -799,7 +790,7 @@ static void ui_handle_afterfunc_add_operator_ex(wmOperatorType *ot,
}
}
-void ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext)
+void ui_handle_afterfunc_add_operator(wmOperatorType *ot, wmOperatorCallContext opcontext)
{
ui_handle_afterfunc_add_operator_ex(ot, NULL, opcontext, NULL);
}
@@ -1269,12 +1260,22 @@ static void ui_apply_but_TAB(bContext *C, uiBut *but, uiHandleButtonData *data)
static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data)
{
if (data->str) {
+ /* This is intended to avoid unnecessary updates when the value stays the same, however there
+ * are issues with the current implementation. It does not work with multi-button editing
+ * (T89996) or operator popups where a number button requires an update even if the value is
+ * unchanged (T89996).
+ *
+ * Trying to detect changes at this level is not reliable. Instead it could be done at the
+ * level of RNA update/set, skipping RNA update if RNA set did not change anything, instead
+ * of skipping all button updates. */
+#if 0
double value;
/* Check if the string value is a number and cancel if it's equal to the startvalue. */
if (ui_but_string_eval_number(C, but, data->str, &value) && (value == data->startvalue)) {
data->cancel = true;
return;
}
+#endif
if (ui_but_string_set(C, but, data->str)) {
data->value = ui_but_value_get(but);
@@ -1426,8 +1427,8 @@ static bool ui_multibut_states_tag(uiBut *but_active,
seg[0][0] = data->multi_data.drag_start[0];
seg[0][1] = data->multi_data.drag_start[1];
- seg[1][0] = event->x;
- seg[1][1] = event->y;
+ seg[1][0] = event->xy[0];
+ seg[1][1] = event->xy[1];
BLI_assert(data->multi_data.init == BUTTON_MULTI_INIT_SETUP);
@@ -1684,7 +1685,7 @@ static void ui_drag_toggle_set(bContext *C, uiDragToggleHandle *drag_info, const
*/
if (drag_info->is_xy_lock_init == false) {
/* first store the buttons original coords */
- uiBut *but = ui_but_find_mouse_over_ex(region, xy_input[0], xy_input[1], true, NULL, NULL);
+ uiBut *but = ui_but_find_mouse_over_ex(region, xy_input, true, NULL, NULL);
if (but) {
if (but->flag & UI_BUT_DRAG_LOCK) {
@@ -1746,7 +1747,7 @@ static int ui_handler_region_drag_toggle(bContext *C, const wmEvent *event, void
break;
}
case MOUSEMOVE: {
- ui_drag_toggle_set(C, drag_info, &event->x);
+ ui_drag_toggle_set(C, drag_info, event->xy);
break;
}
}
@@ -1754,8 +1755,7 @@ static int ui_handler_region_drag_toggle(bContext *C, const wmEvent *event, void
if (done) {
wmWindow *win = CTX_wm_window(C);
const ARegion *region = CTX_wm_region(C);
- uiBut *but = ui_but_find_mouse_over_ex(
- region, drag_info->xy_init[0], drag_info->xy_init[1], true, NULL, NULL);
+ uiBut *but = ui_but_find_mouse_over_ex(region, drag_info->xy_init, true, NULL, NULL);
if (but) {
ui_apply_but_undo(but);
@@ -1787,7 +1787,7 @@ static bool ui_but_is_drag_toggle(const uiBut *but)
static bool ui_selectcontext_begin(bContext *C, uiBut *but, uiSelectContextStore *selctx_data)
{
- PointerRNA lptr, idptr;
+ PointerRNA lptr;
PropertyRNA *lprop;
bool success = false;
@@ -1821,68 +1821,48 @@ static bool ui_selectcontext_begin(bContext *C, uiBut *but, uiSelectContextStore
if (i >= selctx_data->elems_len) {
break;
}
+
+ if (!UI_context_copy_to_selected_check(
+ &ptr, &link->ptr, prop, path, use_path_from_id, &lptr, &lprop)) {
+ selctx_data->elems_len -= 1;
+ i -= 1;
+ continue;
+ }
+
uiSelectContextElem *other = &selctx_data->elems[i];
- /* TODO: de-duplicate copy_to_selected_button. */
- if (link->ptr.data != ptr.data) {
- if (use_path_from_id) {
- /* Path relative to ID. */
- lprop = NULL;
- RNA_id_pointer_create(link->ptr.owner_id, &idptr);
- RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
- }
- else if (path) {
- /* Path relative to elements from list. */
- lprop = NULL;
- RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
+ other->ptr = lptr;
+ if (is_array) {
+ if (rna_type == PROP_FLOAT) {
+ other->val_f = RNA_property_float_get_index(&lptr, lprop, index);
}
- else {
- lptr = link->ptr;
- lprop = prop;
+ else if (rna_type == PROP_INT) {
+ other->val_i = RNA_property_int_get_index(&lptr, lprop, index);
}
-
- /* lptr might not be the same as link->ptr! */
- if ((lptr.data != ptr.data) && (lprop == prop) && RNA_property_editable(&lptr, lprop)) {
- other->ptr = lptr;
- if (is_array) {
- if (rna_type == PROP_FLOAT) {
- other->val_f = RNA_property_float_get_index(&lptr, lprop, index);
- }
- else if (rna_type == PROP_INT) {
- other->val_i = RNA_property_int_get_index(&lptr, lprop, index);
- }
- /* ignored for now */
+ /* ignored for now */
# if 0
- else if (rna_type == PROP_BOOLEAN) {
- other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index);
- }
-# endif
+ else if (rna_type == PROP_BOOLEAN) {
+ other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index);
}
- else {
- if (rna_type == PROP_FLOAT) {
- other->val_f = RNA_property_float_get(&lptr, lprop);
- }
- else if (rna_type == PROP_INT) {
- other->val_i = RNA_property_int_get(&lptr, lprop);
- }
- /* ignored for now */
-# if 0
- else if (rna_type == PROP_BOOLEAN) {
- other->val_b = RNA_property_boolean_get(&lptr, lprop);
- }
- else if (rna_type == PROP_ENUM) {
- other->val_i = RNA_property_enum_get(&lptr, lprop);
- }
# endif
- }
-
- continue;
+ }
+ else {
+ if (rna_type == PROP_FLOAT) {
+ other->val_f = RNA_property_float_get(&lptr, lprop);
+ }
+ else if (rna_type == PROP_INT) {
+ other->val_i = RNA_property_int_get(&lptr, lprop);
}
+ /* ignored for now */
+# if 0
+ else if (rna_type == PROP_BOOLEAN) {
+ other->val_b = RNA_property_boolean_get(&lptr, lprop);
+ }
+ else if (rna_type == PROP_ENUM) {
+ other->val_i = RNA_property_enum_get(&lptr, lprop);
+ }
+# endif
}
-
- selctx_data->elems_len -= 1;
- i -= 1;
}
-
success = (selctx_data->elems_len != 0);
}
}
@@ -2064,7 +2044,8 @@ static bool ui_but_drag_init(bContext *C,
WM_event_drag_threshold(event),
(int)((UI_UNIT_Y / 2) * ui_block_to_window_scale(data->region, but->block)));
- if (abs(data->dragstartx - event->x) + abs(data->dragstarty - event->y) > drag_threshold) {
+ if (abs(data->dragstartx - event->xy[0]) + abs(data->dragstarty - event->xy[1]) >
+ drag_threshold) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
data->cancel = true;
#ifdef USE_DRAG_TOGGLE
@@ -2079,8 +2060,8 @@ static bool ui_but_drag_init(bContext *C,
drag_info->pushed_state = ui_drag_toggle_but_pushed_state(but);
drag_info->but_cent_start[0] = BLI_rctf_cent_x(&but->rect);
drag_info->but_cent_start[1] = BLI_rctf_cent_y(&but->rect);
- copy_v2_v2_int(drag_info->xy_init, &event->x);
- copy_v2_v2_int(drag_info->xy_last, &event->x);
+ copy_v2_v2_int(drag_info->xy_init, event->xy);
+ copy_v2_v2_int(drag_info->xy_last, event->xy);
/* needed for toggle drag on popups */
region_prev = CTX_wm_region(C);
@@ -2148,6 +2129,12 @@ static bool ui_but_drag_init(bContext *C,
return false;
}
}
+ else if (but->type == UI_BTYPE_TREEROW) {
+ uiButTreeRow *tree_row_but = (uiButTreeRow *)but;
+ if (tree_row_but->tree_item) {
+ UI_tree_view_item_drag_start(C, tree_row_but->tree_item);
+ }
+ }
else {
wmDrag *drag = WM_event_start_drag(
C,
@@ -2166,6 +2153,12 @@ static bool ui_but_drag_init(bContext *C,
BLI_rctf_size_x(&but->rect),
BLI_rctf_size_y(&but->rect));
}
+
+ /* Special feature for assets: We add another drag item that supports multiple assets. It
+ * gets the assets from context. */
+ if (ELEM(but->dragtype, WM_DRAG_ASSET, WM_DRAG_ID)) {
+ WM_event_start_drag(C, ICON_NONE, WM_DRAG_ASSET_LIST, NULL, 0, WM_DRAG_NOP);
+ }
}
return true;
}
@@ -2325,9 +2318,6 @@ static void ui_apply_but(
case UI_BTYPE_LISTROW:
ui_apply_but_LISTROW(C, block, but, data);
break;
- case UI_BTYPE_DATASETROW:
- ui_apply_but_ROW(C, block, but, data);
- break;
case UI_BTYPE_TAB:
ui_apply_but_TAB(C, but, data);
break;
@@ -2434,39 +2424,6 @@ static void ui_apply_but(
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Button Drop Event
- * \{ */
-
-/* only call if event type is EVT_DROP */
-static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleButtonData *data)
-{
- ListBase *drags = event->customdata; /* drop event type has listbase customdata by default */
-
- LISTBASE_FOREACH (wmDrag *, wmd, drags) {
- /* TODO: asset dropping. */
- if (wmd->type == WM_DRAG_ID) {
- /* align these types with UI_but_active_drop_name */
- if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
- ID *id = WM_drag_get_local_ID(wmd, 0);
-
- button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
-
- ui_textedit_string_set(but, data, id->name + 2);
-
- if (ELEM(but->type, UI_BTYPE_SEARCH_MENU)) {
- but->changed = true;
- ui_searchbox_update(C, data->searchbox, but, true);
- }
-
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
- }
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Button Copy & Paste
* \{ */
@@ -2663,15 +2620,9 @@ static void ui_but_copy_text(uiBut *but, char *output, int output_len_max)
static void ui_but_paste_text(bContext *C, uiBut *but, uiHandleButtonData *data, char *buf_paste)
{
- button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
- ui_textedit_string_set(but, but->active, buf_paste);
-
- if (but->type == UI_BTYPE_SEARCH_MENU) {
- but->changed = true;
- ui_searchbox_update(C, data->searchbox, but, true);
- }
-
- button_activate_state(C, but, BUTTON_STATE_EXIT);
+ BLI_assert(but->active == data);
+ UNUSED_VARS_NDEBUG(data);
+ ui_but_set_string_interactive(C, but, buf_paste);
}
static void ui_but_copy_colorband(uiBut *but)
@@ -3015,6 +2966,19 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR],
/** \name Button Text Selection/Editing
* \{ */
+void ui_but_set_string_interactive(bContext *C, uiBut *but, const char *value)
+{
+ button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
+ ui_textedit_string_set(but, but->active, value);
+
+ if (but->type == UI_BTYPE_SEARCH_MENU && but->active) {
+ but->changed = true;
+ ui_searchbox_update(C, but->active->searchbox, but, true);
+ }
+
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+}
+
void ui_but_active_string_clear_and_exit(bContext *C, uiBut *but)
{
if (!but->active) {
@@ -3415,9 +3379,9 @@ static void ui_textedit_ime_begin(wmWindow *win, uiBut *UNUSED(but))
BLI_assert(win->ime_data == NULL);
/* enable IME and position to cursor, it's a trick */
- x = win->eventstate->x;
+ x = win->eventstate->xy[0];
/* flip y and move down a bit, prevent the IME panel cover the edit button */
- y = win->eventstate->y - 12;
+ y = win->eventstate->xy[1] - 12;
wm_window_IME_begin(win, x, y, 0, 0, true);
}
@@ -3531,8 +3495,17 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
ui_but_update(but);
- /* Popup blocks don't support moving after creation, so don't change the view for them. */
- if (!data->searchbox) {
+ /* Make sure the edited button is in view. */
+ if (data->searchbox) {
+ /* Popup blocks don't support moving after creation, so don't change the view for them. */
+ }
+ else if (UI_block_layout_needs_resolving(but->block)) {
+ /* Layout isn't resolved yet (may happen when activating while drawing through
+ * #UI_but_active_only()), so can't move it into view yet. This causes
+ * #ui_but_update_view_for_active() to run after the layout is resolved. */
+ but->changed = true;
+ }
+ else {
UI_but_ensure_in_view(C, data->region, but);
}
@@ -3567,6 +3540,12 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
if ((ui_searchbox_apply(but, data->searchbox) == false) &&
(ui_searchbox_find_index(data->searchbox, but->editstr) == -1) &&
!but_search->results_are_suggestions) {
+
+ if (but->flag & UI_BUT_VALUE_CLEAR) {
+ /* It is valid for _VALUE_CLEAR flavor to have no active element
+ * (it's a valid way to unlink). */
+ but->editstr[0] = '\0';
+ }
data->cancel = true;
/* ensure menu (popup) too is closed! */
@@ -3731,18 +3710,18 @@ static void ui_do_but_textedit(
/* exit on LMB only on RELEASE for searchbox, to mimic other popups,
* and allow multiple menu levels */
if (data->searchbox) {
- inbox = ui_searchbox_inside(data->searchbox, event->x, event->y);
+ inbox = ui_searchbox_inside(data->searchbox, event->xy);
}
/* for double click: we do a press again for when you first click on button
* (selects all text, no cursor pos) */
if (ELEM(event->val, KM_PRESS, KM_DBL_CLICK)) {
- float mx = event->x;
- float my = event->y;
+ float mx = event->xy[0];
+ float my = event->xy[1];
ui_window_to_block_fl(data->region, block, &mx, &my);
if (ui_but_contains_pt(but, mx, my)) {
- ui_textedit_set_cursor_pos(but, data, event->x);
+ ui_textedit_set_cursor_pos(but, data, event->xy[0]);
but->selsta = but->selend = but->pos;
data->sel_pos_init = but->pos;
@@ -3783,7 +3762,12 @@ static void ui_do_but_textedit(
case EVT_VKEY:
case EVT_XKEY:
case EVT_CKEY:
- if (IS_EVENT_MOD(event, ctrl, oskey)) {
+#if defined(__APPLE__)
+ if ((event->oskey && !IS_EVENT_MOD(event, shift, alt, ctrl)) ||
+ (event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey))) {
+#else
+ if (event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey)) {
+#endif
if (event->type == EVT_VKEY) {
changed = ui_textedit_copypaste(but, data, UI_TEXTEDIT_PASTE);
}
@@ -4013,11 +3997,11 @@ static void ui_do_but_textedit_select(
switch (event->type) {
case MOUSEMOVE: {
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(data->region, block, &mx, &my);
- ui_textedit_set_cursor_select(but, data, event->x);
+ ui_textedit_set_cursor_select(but, data, event->xy[0]);
retval = WM_UI_HANDLER_BREAK;
break;
}
@@ -4353,7 +4337,7 @@ static uiBut *ui_but_list_row_text_activate(bContext *C,
uiButtonActivateType activate_type)
{
ARegion *region = CTX_wm_region(C);
- uiBut *labelbut = ui_but_find_mouse_over_ex(region, event->x, event->y, true, NULL, NULL);
+ uiBut *labelbut = ui_but_find_mouse_over_ex(region, event->xy, true, NULL, NULL);
if (labelbut && labelbut->type == UI_BTYPE_TEXT && !(labelbut->flag & UI_BUT_DISABLED)) {
/* exit listrow */
@@ -4380,7 +4364,7 @@ static uiButExtraOpIcon *ui_but_extra_operator_icon_mouse_over_get(uiBut *but,
{
float xmax = but->rect.xmax;
const float icon_size = 0.8f * BLI_rctf_size_y(&but->rect); /* ICON_SIZE_FROM_BUTRECT */
- int x = event->x, y = event->y;
+ int x = event->xy[0], y = event->xy[1];
ui_window_to_block(data->region, but->block, &x, &y);
if (!BLI_rctf_isect_pt(&but->rect, x, y)) {
@@ -4464,14 +4448,10 @@ static bool ui_do_but_ANY_drag_toggle(
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->type == LEFTMOUSE && event->val == KM_PRESS && ui_but_is_drag_toggle(but)) {
-# if 0 /* UNUSED */
- data->togdual = event->ctrl;
- data->togonly = !event->shift;
-# endif
ui_apply_but(C, but->block, but, data, true);
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
- data->dragstartx = event->x;
- data->dragstarty = event->y;
+ data->dragstartx = event->xy[0];
+ data->dragstarty = event->xy[1];
*r_retval = WM_UI_HANDLER_BREAK;
return true;
}
@@ -4557,7 +4537,7 @@ static int ui_do_but_HOTKEYEVT(bContext *C,
if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
/* only cancel if click outside the button */
- if (ui_but_contains_point_px(but, but->active->region, event->x, event->y) == false) {
+ if (ui_but_contains_point_px(but, but->active->region, event->xy) == false) {
/* data->cancel doesn't work, this button opens immediate */
if (but->flag & UI_BUT_IMMEDIATE) {
ui_but_value_set(but, 0);
@@ -4761,10 +4741,6 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
}
if (do_activate) {
-#if 0 /* UNUSED */
- data->togdual = event->ctrl;
- data->togonly = !event->shift;
-#endif
button_activate_state(C, but, BUTTON_STATE_EXIT);
return WM_UI_HANDLER_BREAK;
}
@@ -4816,6 +4792,47 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
return WM_UI_HANDLER_CONTINUE;
}
+static int ui_do_but_TREEROW(bContext *C,
+ uiBut *but,
+ uiHandleButtonData *data,
+ const wmEvent *event)
+{
+ uiButTreeRow *tree_row_but = (uiButTreeRow *)but;
+ BLI_assert(tree_row_but->but.type == UI_BTYPE_TREEROW);
+
+ if (data->state == BUTTON_STATE_HIGHLIGHT) {
+ if (event->type == LEFTMOUSE) {
+ switch (event->val) {
+ case KM_PRESS:
+ /* Extra icons have priority, don't mess with them. */
+ if (ui_but_extra_operator_icon_mouse_over_get(but, data, event)) {
+ return WM_UI_HANDLER_BREAK;
+ }
+ button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+ data->dragstartx = event->xy[0];
+ data->dragstarty = event->xy[1];
+ return WM_UI_HANDLER_CONTINUE;
+
+ case KM_CLICK:
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ return WM_UI_HANDLER_BREAK;
+
+ case KM_DBL_CLICK:
+ data->cancel = true;
+ UI_tree_view_item_begin_rename(tree_row_but->tree_item);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return WM_UI_HANDLER_BREAK;
+ }
+ }
+ }
+ else if (data->state == BUTTON_STATE_WAIT_DRAG) {
+ /* Let "default" button handling take care of the drag logic. */
+ return ui_do_but_EXIT(C, but, data, event);
+ }
+
+ return WM_UI_HANDLER_CONTINUE;
+}
+
static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -4827,16 +4844,16 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
/* tell the button to wait and keep checking further events to
* see if it should start dragging */
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
- data->dragstartx = event->x;
- data->dragstarty = event->y;
+ data->dragstartx = event->xy[0];
+ data->dragstarty = event->xy[1];
return WM_UI_HANDLER_CONTINUE;
}
}
#ifdef USE_DRAG_TOGGLE
if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && ui_but_is_drag_toggle(but)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
- data->dragstartx = event->x;
- data->dragstarty = event->y;
+ data->dragstartx = event->xy[0];
+ data->dragstarty = event->xy[1];
return WM_UI_HANDLER_CONTINUE;
}
#endif
@@ -5258,8 +5275,8 @@ static void ui_numedit_set_active(uiBut *but)
BLI_rctf_size_y(&but->rect) * 0.7f);
/* we can click on the side arrows to increment/decrement,
* or click inside to edit the value directly */
- int mx = data->window->eventstate->x;
- int my = data->window->eventstate->y;
+ int mx = data->window->eventstate->xy[0];
+ int my = data->window->eventstate->xy[1];
ui_window_to_block(data->region, but->block, &mx, &my);
if (mx < (but->rect.xmin + handle_width)) {
@@ -5299,10 +5316,10 @@ static int ui_do_but_NUM(
int retval = WM_UI_HANDLER_CONTINUE;
/* mouse location scaled to fit the UI */
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
/* mouse location kept at screen pixel coords */
- const int screen_mx = event->x;
+ const int screen_mx = event->xy[0];
BLI_assert(but->type == UI_BTYPE_NUM);
@@ -5354,7 +5371,7 @@ static int ui_do_but_NUM(
}
#ifdef USE_DRAG_MULTINUM
- copy_v2_v2_int(data->multi_data.drag_start, &event->x);
+ copy_v2_v2_int(data->multi_data.drag_start, event->xy);
#endif
}
}
@@ -5467,7 +5484,7 @@ static int ui_do_but_NUM(
log10f(number_but->step_size));
}
else {
- value_step = (double)number_but->step_size * UI_PRECISION_FLOAT_SCALE;
+ value_step = (double)(number_but->step_size * UI_PRECISION_FLOAT_SCALE);
}
BLI_assert(value_step > 0.0f);
const double value_test = (but->drawflag & UI_BUT_ACTIVE_LEFT) ?
@@ -5648,8 +5665,8 @@ static int ui_do_but_SLI(
int click = 0;
int retval = WM_UI_HANDLER_CONTINUE;
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(data->region, block, &mx, &my);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -5708,7 +5725,7 @@ static int ui_do_but_SLI(
}
}
#ifdef USE_DRAG_MULTINUM
- copy_v2_v2_int(data->multi_data.drag_start, &event->x);
+ copy_v2_v2_int(data->multi_data.drag_start, event->xy);
#endif
}
else if (data->state == BUTTON_STATE_NUM_EDITING) {
@@ -5868,8 +5885,8 @@ static int ui_do_but_SCROLL(
int retval = WM_UI_HANDLER_CONTINUE;
const bool horizontal = (BLI_rctf_size_x(&but->rect) > BLI_rctf_size_y(&but->rect));
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(data->region, block, &mx, &my);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -5925,15 +5942,15 @@ static int ui_do_but_GRIP(
* See T37739.
*/
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(data->region, block, &mx, &my);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->val == KM_PRESS) {
if (event->type == LEFTMOUSE) {
- data->dragstartx = event->x;
- data->dragstarty = event->y;
+ data->dragstartx = event->xy[0];
+ data->dragstarty = event->xy[1];
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
retval = WM_UI_HANDLER_BREAK;
}
@@ -5996,16 +6013,16 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) {
if (ui_but_contains_point_px_icon(but, data->region, event)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
- data->dragstartx = event->x;
- data->dragstarty = event->y;
+ data->dragstartx = event->xy[0];
+ data->dragstarty = event->xy[1];
return WM_UI_HANDLER_BREAK;
}
}
#ifdef USE_DRAG_TOGGLE
if (event->type == LEFTMOUSE && event->val == KM_PRESS && (ui_but_is_drag_toggle(but))) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
- data->dragstartx = event->x;
- data->dragstarty = event->y;
+ data->dragstartx = event->xy[0];
+ data->dragstarty = event->xy[1];
return WM_UI_HANDLER_BREAK;
}
#endif
@@ -6182,8 +6199,8 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
ui_palette_set_active(color_but);
if (ui_but_contains_point_px_icon(but, data->region, event)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
- data->dragstartx = event->x;
- data->dragstarty = event->y;
+ data->dragstartx = event->xy[0];
+ data->dragstarty = event->xy[1];
return WM_UI_HANDLER_BREAK;
}
}
@@ -6191,8 +6208,8 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
ui_palette_set_active(color_but);
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
- data->dragstartx = event->x;
- data->dragstarty = event->y;
+ data->dragstartx = event->xy[0];
+ data->dragstarty = event->xy[1];
return WM_UI_HANDLER_BREAK;
}
#endif
@@ -6218,7 +6235,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
hsv[2] = clamp_f(hsv[2] + 0.05f, 0.0f, 1.0f);
}
else {
- const float fac = 0.005 * (event->y - event->prevy);
+ const float fac = 0.005 * (event->xy[1] - event->prev_xy[1]);
hsv[2] = clamp_f(hsv[2] + fac, 0.0f, 1.0f);
}
@@ -6322,8 +6339,8 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
static int ui_do_but_UNITVEC(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(data->region, block, &mx, &my);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -6616,8 +6633,8 @@ static int ui_do_but_HSVCUBE(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
uiButHSVCube *hsv_but = (uiButHSVCube *)but;
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(data->region, block, &mx, &my);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -6892,8 +6909,8 @@ static int ui_do_but_HSVCIRCLE(
{
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->hsv_perceptual;
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(data->region, block, &mx, &my);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -7021,8 +7038,8 @@ static bool ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int m
static int ui_do_but_COLORBAND(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(data->region, block, &mx, &my);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -7217,8 +7234,8 @@ static int ui_do_but_CURVE(
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(data->region, block, &mx, &my);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -7310,10 +7327,10 @@ static int ui_do_but_CURVE(
data->dragsel = sel;
- data->dragstartx = event->x;
- data->dragstarty = event->y;
- data->draglastx = event->x;
- data->draglasty = event->y;
+ data->dragstartx = event->xy[0];
+ data->dragstarty = event->xy[1];
+ data->draglastx = event->xy[0];
+ data->draglasty = event->xy[1];
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
return WM_UI_HANDLER_BREAK;
@@ -7321,10 +7338,15 @@ static int ui_do_but_CURVE(
}
else if (data->state == BUTTON_STATE_NUM_EDITING) {
if (event->type == MOUSEMOVE) {
- if (event->x != data->draglastx || event->y != data->draglasty) {
-
- if (ui_numedit_but_CURVE(
- block, but, data, event->x, event->y, event->ctrl != 0, event->shift != 0)) {
+ if (event->xy[0] != data->draglastx || event->xy[1] != data->draglasty) {
+
+ if (ui_numedit_but_CURVE(block,
+ but,
+ data,
+ event->xy[0],
+ event->xy[1],
+ event->ctrl != 0,
+ event->shift != 0)) {
ui_numedit_apply(C, block, but, data);
}
}
@@ -7498,8 +7520,8 @@ static int ui_do_but_CURVEPROFILE(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
CurveProfile *profile = (CurveProfile *)but->poin;
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(data->region, block, &mx, &my);
@@ -7581,7 +7603,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_TABLE_LEN(profile->path_len); i++) {
+ for (int i = 1; i <= BKE_curveprofile_table_size(profile); i++) {
copy_v2_v2(f_xy_prev, f_xy);
BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &table[i].x);
@@ -7681,8 +7703,8 @@ static bool ui_numedit_but_HISTOGRAM(uiBut *but, uiHandleButtonData *data, int m
static int ui_do_but_HISTOGRAM(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(data->region, block, &mx, &my);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -7754,8 +7776,8 @@ static bool ui_numedit_but_WAVEFORM(uiBut *but, uiHandleButtonData *data, int mx
static int ui_do_but_WAVEFORM(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(data->region, block, &mx, &my);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -7845,8 +7867,8 @@ static bool ui_numedit_but_TRACKPREVIEW(
static int ui_do_but_TRACKPREVIEW(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(data->region, block, &mx, &my);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -7902,7 +7924,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
/* Only hard-coded stuff here, button interactions with configurable
* keymaps are handled using operators (see #ED_keymap_ui). */
- if ((data->state == BUTTON_STATE_HIGHLIGHT) || (event->type == EVT_DROP)) {
+ if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* handle copy and paste */
bool is_press_ctrl_but_no_shift = event->val == KM_PRESS && IS_EVENT_MOD(event, ctrl, oskey) &&
@@ -7910,7 +7932,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
const bool do_copy = event->type == EVT_CKEY && is_press_ctrl_but_no_shift;
const bool do_paste = event->type == EVT_VKEY && is_press_ctrl_but_no_shift;
- /* Specific handling for listrows, we try to find their overlapping tex button. */
+ /* Specific handling for list-rows, we try to find their overlapping text button. */
if ((do_copy || do_paste) && but->type == UI_BTYPE_LISTROW) {
uiBut *labelbut = ui_but_list_row_text_activate(C, but, data, event, BUTTON_ACTIVATE_OVER);
if (labelbut) {
@@ -7928,6 +7950,14 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
/* handle menu */
if ((event->type == RIGHTMOUSE) && !IS_EVENT_MOD(event, shift, ctrl, alt, oskey) &&
(event->val == KM_PRESS)) {
+ /* For some button types that are typically representing entire sets of data, right-clicking
+ * to spawn the context menu should also activate the item. This makes it clear which item
+ * will be operated on.
+ * Apply the button immediately, so context menu polls get the right active item. */
+ if (ELEM(but->type, UI_BTYPE_TREEROW)) {
+ ui_apply_but(C, but->block, but, but->active, true);
+ }
+
/* RMB has two options now */
if (ui_popup_context_menu_for_button(C, but, event)) {
return WM_UI_HANDLER_BREAK;
@@ -7943,11 +7973,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
return WM_UI_HANDLER_BREAK;
}
- /* handle drop */
- if (event->type == EVT_DROP) {
- ui_but_drop(C, event, but, data);
- }
-
if ((data->state == BUTTON_STATE_HIGHLIGHT) &&
ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, EVT_PADENTER, EVT_RETKEY) &&
(event->val == KM_RELEASE) &&
@@ -7983,10 +8008,11 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_CHECKBOX:
case UI_BTYPE_CHECKBOX_N:
case UI_BTYPE_ROW:
- case UI_BTYPE_TREEROW:
- case UI_BTYPE_DATASETROW:
retval = ui_do_but_TOG(C, but, data, event);
break;
+ case UI_BTYPE_TREEROW:
+ retval = ui_do_but_TREEROW(C, but, data, event);
+ break;
case UI_BTYPE_SCROLL:
retval = ui_do_but_SCROLL(C, block, but, data, event);
break;
@@ -8097,7 +8123,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
if (fabsf(dot_v2v2(dir_nor_drag, dir_nor_y)) > DRAG_MULTINUM_THRESHOLD_VERTICAL) {
data->multi_data.init = BUTTON_MULTI_INIT_SETUP;
- data->multi_data.drag_lock_x = event->x;
+ data->multi_data.drag_lock_x = event->xy[0];
}
else {
data->multi_data.init = BUTTON_MULTI_INIT_DISABLE;
@@ -8110,9 +8136,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
/* Check if we're don't setting buttons. */
if ((data->str &&
ELEM(data->state, BUTTON_STATE_TEXT_EDITING, BUTTON_STATE_NUM_EDITING)) ||
- ((abs(data->multi_data.drag_lock_x - event->x) > margin_x) &&
+ ((abs(data->multi_data.drag_lock_x - event->xy[0]) > margin_x) &&
/* Just to be sure, check we're dragging more horizontally then vertically. */
- abs(event->prevx - event->x) > abs(event->prevy - event->y))) {
+ abs(event->prev_xy[0] - event->xy[0]) > abs(event->prev_xy[1] - event->xy[1]))) {
if (data->multi_data.has_mbuts) {
ui_multibut_states_create(but, data);
data->multi_data.init = BUTTON_MULTI_INIT_ENABLE;
@@ -8154,9 +8180,6 @@ static void ui_blocks_set_tooltips(ARegion *region, const bool enable)
}
}
-/**
- * Recreate tool-tip (use to update dynamic tips)
- */
void UI_but_tooltip_refresh(bContext *C, uiBut *but)
{
uiHandleButtonData *data = but->active;
@@ -8168,10 +8191,6 @@ void UI_but_tooltip_refresh(bContext *C, uiBut *but)
}
}
-/**
- * Removes tool-tip timer from active but
- * (meaning tool-tip is disabled until it's re-enabled again).
- */
void UI_but_tooltip_timer_remove(bContext *C, uiBut *but)
{
uiHandleButtonData *data = but->active;
@@ -8200,7 +8219,11 @@ static ARegion *ui_but_tooltip_init(
uiBut *but = UI_region_active_but_get(region);
*r_exit_on_event = false;
if (but) {
- return UI_tooltip_create_from_button(C, region, but, is_label);
+ const wmWindow *win = CTX_wm_window(C);
+ uiButExtraOpIcon *extra_icon = ui_but_extra_operator_icon_mouse_over_get(
+ but, but->active, win->eventstate);
+
+ return UI_tooltip_create_from_button_or_extra_icon(C, region, but, extra_icon, is_label);
}
return NULL;
}
@@ -8735,11 +8758,6 @@ uiBut *UI_context_active_but_get(const bContext *C)
return ui_context_button_active(CTX_wm_region(C), NULL);
}
-/*
- * Version of #UI_context_active_get() that uses the result of #CTX_wm_menu()
- * if set. Does not traverse into parent menus, which may be wanted in some
- * cases.
- */
uiBut *UI_context_active_but_get_respect_menu(const bContext *C)
{
ARegion *region_menu = CTX_wm_menu(C);
@@ -8760,15 +8778,9 @@ uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region,
const int xy[2],
bool only_clip)
{
- return ui_block_find_mouse_over_ex(region, xy[0], xy[1], only_clip);
+ return ui_block_find_mouse_over_ex(region, xy, only_clip);
}
-/**
- * Version of #UI_context_active_but_get that also returns RNA property info.
- * Helper function for insert keyframe, reset to default, etc operators.
- *
- * \return active button, NULL if none found or if it doesn't contain valid RNA data.
- */
uiBut *UI_context_active_but_prop_get(const bContext *C,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop,
@@ -8844,16 +8856,12 @@ wmOperator *UI_context_active_operator_get(const struct bContext *C)
return NULL;
}
-/**
- * Try to find a search-box region opened from a button in \a button_region.
- */
ARegion *UI_region_searchbox_region_get(const ARegion *button_region)
{
uiBut *but = UI_region_active_but_get(button_region);
return (but != NULL) ? but->active->searchbox : NULL;
}
-/* helper function for insert keyframe, reset to default, etc operators */
void UI_context_update_anim_flag(const bContext *C)
{
Scene *scene = CTX_data_scene(C);
@@ -8902,10 +8910,6 @@ void UI_context_update_anim_flag(const bContext *C)
}
}
-/**
- * In some cases we may want to update the view (#View2D) in-between layout definition and drawing.
- * E.g. to make sure a button is visible while editing.
- */
void ui_but_update_view_for_active(const bContext *C, const uiBlock *block)
{
uiBut *active_but = ui_block_active_but_get(block);
@@ -8965,11 +8969,6 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *reg
return WM_UI_HANDLER_CONTINUE;
}
-/**
- * Exported to interface.c: #UI_but_active_only()
- * \note The region is only for the button.
- * The context needs to be set by the caller.
- */
void ui_but_activate_event(bContext *C, ARegion *region, uiBut *but)
{
wmWindow *win = CTX_wm_window(C);
@@ -8982,17 +8981,11 @@ void ui_but_activate_event(bContext *C, ARegion *region, uiBut *but)
event.val = KM_PRESS;
event.is_repeat = false;
event.customdata = but;
- event.customdatafree = false;
+ event.customdata_free = false;
ui_do_button(C, but->block, but, &event);
}
-/**
- * Simulate moving the mouse over a button (or navigating to it with arrow keys).
- *
- * exported so menus can start with a highlighted button,
- * even if the mouse isn't over it
- */
void ui_but_activate_over(bContext *C, ARegion *region, uiBut *but)
{
button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER);
@@ -9159,7 +9152,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
/* always deactivate button for pie menus,
* else moving to blank space will leave activated */
if ((!ui_block_is_menu(block) || ui_block_is_pie_menu(block)) &&
- !ui_but_contains_point_px(but, region, event->x, event->y)) {
+ !ui_but_contains_point_px(but, region, event->xy)) {
exit = true;
}
else if (but_other && ui_but_is_editable(but_other) && (but_other != but)) {
@@ -9170,7 +9163,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
data->cancel = true;
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
- else if (event->x != event->prevx || event->y != event->prevy) {
+ else if (event->xy[0] != event->prev_xy[0] || event->xy[1] != event->prev_xy[1]) {
/* Re-enable tool-tip on mouse move. */
ui_blocks_set_tooltips(region, true);
button_tooltip_timer_reset(C, but);
@@ -9187,7 +9180,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
WM_event_remove_timer(data->wm, data->window, data->autoopentimer);
data->autoopentimer = NULL;
- if (ui_but_contains_point_px(but, region, event->x, event->y) || but->active) {
+ if (ui_but_contains_point_px(but, region, event->xy) || but->active) {
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
}
}
@@ -9237,12 +9230,12 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
case MOUSEMOVE: {
/* deselect the button when moving the mouse away */
/* also de-activate for buttons that only show highlights */
- if (ui_but_contains_point_px(but, region, event->x, event->y)) {
+ if (ui_but_contains_point_px(but, region, event->xy)) {
/* Drag on a hold button (used in the toolbar) now opens it immediately. */
if (data->hold_action_timer) {
if (but->flag & UI_SELECT) {
- if (len_manhattan_v2v2_int(&event->x, &event->prevx) <=
+ if (len_manhattan_v2v2_int(event->xy, event->prev_xy) <=
WM_EVENT_CURSOR_MOTION_THRESHOLD) {
/* pass */
}
@@ -9295,7 +9288,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
uiBut *bt;
if (data->menu && data->menu->region) {
- if (ui_region_contains_point_px(data->menu->region, event->x, event->y)) {
+ if (ui_region_contains_point_px(data->menu->region, event->xy)) {
break;
}
}
@@ -9410,8 +9403,8 @@ static int ui_list_activate_hovered_row(bContext *C,
}
}
- const int *mouse_xy = ISTWEAK(event->type) ? &event->prevclickx : &event->x;
- uiBut *listrow = ui_list_row_find_mouse_over(region, mouse_xy[0], mouse_xy[1]);
+ const int *mouse_xy = ISTWEAK(event->type) ? event->prev_click_xy : event->xy;
+ uiBut *listrow = ui_list_row_find_mouse_over(region, mouse_xy);
if (listrow) {
wmOperatorType *custom_activate_optype = ui_list->dyn_data->custom_activate_optype;
@@ -9437,9 +9430,8 @@ static bool ui_list_is_hovering_draggable_but(bContext *C,
const wmEvent *event)
{
/* On a tweak event, uses the coordinates from where tweaking was started. */
- const int *mouse_xy = ISTWEAK(event->type) ? &event->prevclickx : &event->x;
- const uiBut *hovered_but = ui_but_find_mouse_over_ex(
- region, mouse_xy[0], mouse_xy[1], false, NULL, NULL);
+ const int *mouse_xy = ISTWEAK(event->type) ? event->prev_click_xy : event->xy;
+ const uiBut *hovered_but = ui_but_find_mouse_over_ex(region, mouse_xy, false, NULL, NULL);
if (list->dyn_data->custom_drag_optype) {
if (ui_but_context_poll_operator(C, list->dyn_data->custom_drag_optype, hovered_but)) {
@@ -9542,8 +9534,8 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *regi
}
uiListDyn *dyn_data = ui_list->dyn_data;
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(region, listbox->block, &mx, &my);
/* Convert pan to scroll-wheel. */
@@ -9657,6 +9649,38 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *regi
return retval;
}
+static int ui_handle_tree_hover(const wmEvent *event, const ARegion *region)
+{
+ bool has_treerows = false;
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ /* Avoid unnecessary work: Tree-rows are assumed to be inside tree-views. */
+ if (BLI_listbase_is_empty(&block->views)) {
+ continue;
+ }
+
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ if (but->type == UI_BTYPE_TREEROW) {
+ but->flag &= ~UI_ACTIVE;
+ has_treerows = true;
+ }
+ }
+ }
+
+ if (!has_treerows) {
+ /* Avoid unnecessary lookup. */
+ return WM_UI_HANDLER_CONTINUE;
+ }
+
+ /* Always highlight the hovered tree-row, even if the mouse hovers another button inside of it.
+ */
+ uiBut *hovered_row_but = ui_tree_row_find_mouse_over(region, event->xy);
+ if (hovered_row_but) {
+ hovered_row_but->flag |= UI_ACTIVE;
+ }
+
+ return WM_UI_HANDLER_CONTINUE;
+}
+
static void ui_handle_button_return_submenu(bContext *C, const wmEvent *event, uiBut *but)
{
uiHandleButtonData *data = but->active;
@@ -9692,8 +9716,7 @@ static void ui_handle_button_return_submenu(bContext *C, const wmEvent *event, u
button_activate_exit(C, but, data, true, false);
}
else if (menu->menuretval & UI_RETURN_OUT) {
- if (event->type == MOUSEMOVE &&
- ui_but_contains_point_px(but, data->region, event->x, event->y)) {
+ if (event->type == MOUSEMOVE && ui_but_contains_point_px(but, data->region, event->xy)) {
button_activate_state(C, but, BUTTON_STATE_HIGHLIGHT);
}
else {
@@ -9833,7 +9856,7 @@ static bool ui_mouse_motion_towards_check(uiBlock *block,
static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEvent *event)
{
keynav->is_keynav = true;
- copy_v2_v2_int(keynav->event_xy, &event->x);
+ copy_v2_v2_int(keynav->event_xy, event->xy);
}
/**
* Return true if key-input isn't blocking mouse-motion,
@@ -9842,7 +9865,7 @@ static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEve
static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEvent *event)
{
if (keynav->is_keynav &&
- (len_manhattan_v2v2_int(keynav->event_xy, &event->x) > BUTTON_KEYNAV_PX_LIMIT)) {
+ (len_manhattan_v2v2_int(keynav->event_xy, event->xy) > BUTTON_KEYNAV_PX_LIMIT)) {
keynav->is_keynav = false;
}
@@ -10032,13 +10055,13 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock
else if (!ui_block_is_menu(but->block) || ui_block_is_pie_menu(but->block)) {
/* pass, skip for dialogs */
}
- else if (!ui_region_contains_point_px(but->active->region, event->x, event->y)) {
+ else if (!ui_region_contains_point_px(but->active->region, event->xy)) {
/* Pass, needed to click-exit outside of non-floating menus. */
ui_region_auto_open_clear(but->active->region);
}
else if ((!ELEM(event->type, MOUSEMOVE, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN)) &&
ISMOUSE(event->type)) {
- if (!ui_but_contains_point_px(but, but->active->region, event->x, event->y)) {
+ if (!ui_but_contains_point_px(but, but->active->region, event->xy)) {
but = NULL;
}
}
@@ -10112,8 +10135,8 @@ static int ui_handle_menu_event(bContext *C,
int retval = WM_UI_HANDLER_CONTINUE;
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(region, block, &mx, &my);
/* check if mouse is inside block */
@@ -10134,8 +10157,8 @@ static int ui_handle_menu_event(bContext *C,
if (event->type == MOUSEMOVE) {
int mdiff[2];
- sub_v2_v2v2_int(mdiff, &event->x, menu->grab_xy_prev);
- copy_v2_v2_int(menu->grab_xy_prev, &event->x);
+ sub_v2_v2v2_int(mdiff, event->xy, menu->grab_xy_prev);
+ copy_v2_v2_int(menu->grab_xy_prev, event->xy);
add_v2_v2v2_int(menu->popup_create_vars.event_xy, menu->popup_create_vars.event_xy, mdiff);
@@ -10152,7 +10175,7 @@ static int ui_handle_menu_event(bContext *C,
/* if a button is activated modal, always reset the start mouse
* position of the towards mechanism to avoid losing focus,
* and don't handle events */
- ui_mouse_motion_towards_reinit(menu, &event->x);
+ ui_mouse_motion_towards_reinit(menu, event->xy);
}
}
else if (event->type == TIMER) {
@@ -10164,7 +10187,7 @@ static int ui_handle_menu_event(bContext *C,
/* for ui_mouse_motion_towards_block */
if (event->type == MOUSEMOVE) {
if (block->flag & (UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_POPOVER)) {
- ui_mouse_motion_towards_init(menu, &event->x);
+ ui_mouse_motion_towards_init(menu, event->xy);
}
/* add menu scroll timer, if needed */
@@ -10254,7 +10277,7 @@ static int ui_handle_menu_event(bContext *C,
}
else if (!ui_block_is_menu(block)) {
if (block->flag & (UI_BLOCK_CLIPTOP | UI_BLOCK_CLIPBOTTOM)) {
- const float dy = event->y - event->prevy;
+ const float dy = event->xy[1] - event->prev_xy[1];
if (dy != 0.0f) {
ui_menu_scroll_apply_offset_y(region, block, dy);
@@ -10577,7 +10600,8 @@ static int ui_handle_menu_event(bContext *C,
menu->menuretval = UI_RETURN_OUT;
}
}
- else if (saferct && !BLI_rctf_isect_pt(&saferct->parent, event->x, event->y)) {
+ else if (saferct && !BLI_rctf_isect_pt(
+ &saferct->parent, (float)event->xy[0], (float)event->xy[1])) {
if (block->flag & UI_BLOCK_OUT_1) {
menu->menuretval = UI_RETURN_OK;
}
@@ -10636,13 +10660,13 @@ static int ui_handle_menu_event(bContext *C,
#ifdef USE_DRAG_POPUP
else if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) &&
(inside && is_floating && inside_title)) {
- if (!but || !ui_but_contains_point_px(but, region, event->x, event->y)) {
+ if (!but || !ui_but_contains_point_px(but, region, event->xy)) {
if (but) {
UI_but_tooltip_timer_remove(C, but);
}
menu->is_grab = true;
- copy_v2_v2_int(menu->grab_xy_prev, &event->x);
+ copy_v2_v2_int(menu->grab_xy_prev, event->xy);
retval = WM_UI_HANDLER_BREAK;
}
}
@@ -10653,7 +10677,7 @@ static int ui_handle_menu_event(bContext *C,
if (inside == false && (block->flag & (UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_POPOVER))) {
uiSafetyRct *saferct;
- ui_mouse_motion_towards_check(block, menu, &event->x, is_parent_inside == false);
+ ui_mouse_motion_towards_check(block, menu, event->xy, is_parent_inside == false);
/* Check for all parent rects, enables arrow-keys to be used. */
for (saferct = block->saferct.first; saferct; saferct = saferct->next) {
@@ -10661,10 +10685,10 @@ static int ui_handle_menu_event(bContext *C,
* events we check all preceding block rects too to make
* arrow keys navigation work */
if (event->type != MOUSEMOVE || saferct == block->saferct.first) {
- if (BLI_rctf_isect_pt(&saferct->parent, (float)event->x, (float)event->y)) {
+ if (BLI_rctf_isect_pt(&saferct->parent, (float)event->xy[0], (float)event->xy[1])) {
break;
}
- if (BLI_rctf_isect_pt(&saferct->safety, (float)event->x, (float)event->y)) {
+ if (BLI_rctf_isect_pt(&saferct->safety, (float)event->xy[0], (float)event->xy[1])) {
break;
}
}
@@ -10708,7 +10732,7 @@ static int ui_handle_menu_event(bContext *C,
}
#endif
- /* Don't handle double click events, rehandle as regular press/release. */
+ /* Don't handle double click events, re-handle as regular press/release. */
if (retval == WM_UI_HANDLER_CONTINUE && event->val == KM_DBL_CLICK) {
return retval;
}
@@ -10765,7 +10789,7 @@ static int ui_handle_menu_return_submenu(bContext *C,
if (block->flag & (UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_POPOVER)) {
/* for cases where close does not cascade, allow the user to
* move the mouse back towards the menu without closing */
- ui_mouse_motion_towards_reinit(menu, &event->x);
+ ui_mouse_motion_towards_reinit(menu, event->xy);
}
if (menu->menuretval) {
@@ -10873,7 +10897,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
const double duration = menu->scrolltimer->duration;
- float event_xy[2] = {event->x, event->y};
+ float event_xy[2] = {UNPACK2(event->xy)};
ui_window_to_block_fl(region, block, &event_xy[0], &event_xy[1]);
@@ -11050,7 +11074,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
case EVT_XKEY:
case EVT_YKEY:
case EVT_ZKEY: {
- if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) &&
+ if ((ELEM(event->val, KM_PRESS, KM_DBL_CLICK)) &&
!IS_EVENT_MOD(event, shift, ctrl, oskey)) {
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (but->menu_key == event->type) {
@@ -11128,8 +11152,8 @@ static int ui_handle_menus_recursive(bContext *C,
if (do_recursion) {
if (is_parent_inside == false) {
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(menu->region, block, &mx, &my);
inside = BLI_rctf_isect_pt(&block->rect, mx, my);
}
@@ -11195,16 +11219,12 @@ static int ui_handle_menus_recursive(bContext *C,
}
if (do_towards_reinit) {
- ui_mouse_motion_towards_reinit(menu, &event->x);
+ ui_mouse_motion_towards_reinit(menu, event->xy);
}
return retval;
}
-/**
- * Allow setting menu return value from externals.
- * E.g. WM might need to do this for exiting files correctly.
- */
void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable)
{
uiPopupBlockHandle *menu = block->handle;
@@ -11256,10 +11276,15 @@ static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(use
}
/* Re-enable tool-tips. */
- if (event->type == MOUSEMOVE && (event->x != event->prevx || event->y != event->prevy)) {
+ if (event->type == MOUSEMOVE &&
+ (event->xy[0] != event->prev_xy[0] || event->xy[1] != event->prev_xy[1])) {
ui_blocks_set_tooltips(region, true);
}
+ /* Always do this, to reliably update tree-row highlighting, even if the mouse hovers a button
+ * inside the row (it's an overlapping layout). */
+ ui_handle_tree_hover(event, region);
+
/* delayed apply callbacks */
ui_apply_but_funcs_after(C);
@@ -11273,8 +11298,7 @@ static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata))
return;
}
- UI_blocklist_free(C, &region->uiblocks);
-
+ UI_blocklist_free(C, region);
bScreen *screen = CTX_wm_screen(C);
if (screen == NULL) {
return;
@@ -11353,7 +11377,8 @@ static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSE
}
/* Re-enable tool-tips. */
- if (event->type == MOUSEMOVE && (event->x != event->prevx || event->y != event->prevy)) {
+ if (event->type == MOUSEMOVE &&
+ (event->xy[0] != event->prev_xy[0] || event->xy[1] != event->prev_xy[1])) {
ui_blocks_set_tooltips(region, true);
}
@@ -11447,7 +11472,8 @@ static int ui_popup_handler(bContext *C, const wmEvent *event, void *userdata)
}
else {
/* Re-enable tool-tips */
- if (event->type == MOUSEMOVE && (event->x != event->prevx || event->y != event->prevy)) {
+ if (event->type == MOUSEMOVE &&
+ (event->xy[0] != event->prev_xy[0] || event->xy[1] != event->prev_xy[1])) {
ui_blocks_set_tooltips(menu->region, true);
}
}
@@ -11596,8 +11622,19 @@ bool UI_textbutton_activate_but(const bContext *C, uiBut *actbut)
/** \name Public Utilities
* \{ */
-/* is called by notifier */
-void UI_screen_free_active_but(const bContext *C, bScreen *screen)
+void UI_region_free_active_but_all(bContext *C, ARegion *region)
+{
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ if (but->active == NULL) {
+ continue;
+ }
+ ui_but_active_free(C, but);
+ }
+ }
+}
+
+void UI_screen_free_active_but_highlight(const bContext *C, bScreen *screen)
{
wmWindow *win = CTX_wm_window(C);
@@ -11617,20 +11654,23 @@ void UI_screen_free_active_but(const bContext *C, bScreen *screen)
}
}
-/* returns true if highlighted button allows drop of names */
-/* called in region context */
-bool UI_but_active_drop_name(bContext *C)
+uiBut *UI_but_active_drop_name_button(const bContext *C)
{
ARegion *region = CTX_wm_region(C);
uiBut *but = ui_region_find_active_but(region);
if (but) {
if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
- return true;
+ return but;
}
}
- return false;
+ return NULL;
+}
+
+bool UI_but_active_drop_name(const bContext *C)
+{
+ return UI_but_active_drop_name_button(C) != NULL;
}
bool UI_but_active_drop_color(bContext *C)
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index c20129b4184..c0d6b8a1a6c 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -31,6 +31,7 @@
#include "GPU_batch_presets.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
+#include "GPU_shader_shared.h"
#include "GPU_state.h"
#include "GPU_texture.h"
@@ -253,37 +254,6 @@ static void def_internal_vicon(int icon_id, VectorDrawFunc drawFunc)
/* Utilities */
-static void viconutil_set_point(int pt[2], int x, int y)
-{
- pt[0] = x;
- pt[1] = y;
-}
-
-static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float alpha)
-{
- int pts[3][2];
- const int cx = x + w / 2 - 4;
- const int cy = y + w / 2;
- const int d = w / 5, d2 = w / 7;
-
- viconutil_set_point(pts[0], cx - d2, cy + d);
- viconutil_set_point(pts[1], cx - d2, cy - d);
- viconutil_set_point(pts[2], cx + d2, cy);
-
- uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4f(0.2f, 0.2f, 0.2f, alpha);
-
- immBegin(GPU_PRIM_TRIS, 3);
- immVertex2iv(pos, pts[0]);
- immVertex2iv(pos, pts[1]);
- immVertex2iv(pos, pts[2]);
- immEnd();
-
- immUnbindProgram();
-}
-
static void vicon_keytype_draw_wrapper(
int x, int y, int w, int h, float alpha, short key_type, short handle_type)
{
@@ -861,8 +831,6 @@ static void free_icons_textures(void)
}
}
-/* Reload the textures for internal icons.
- * This function will release the previous textures. */
void UI_icons_reload_internal_textures(void)
{
bTheme *btheme = UI_GetTheme();
@@ -982,8 +950,6 @@ static void init_internal_icons(void)
}
}
- def_internal_vicon(ICON_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw);
-
def_internal_vicon(ICON_KEYTYPE_KEYFRAME_VEC, vicon_keytype_keyframe_draw);
def_internal_vicon(ICON_KEYTYPE_BREAKDOWN_VEC, vicon_keytype_breakdown_draw);
def_internal_vicon(ICON_KEYTYPE_EXTREME_VEC, vicon_keytype_extreme_draw);
@@ -1215,7 +1181,6 @@ static DrawInfo *icon_ensure_drawinfo(Icon *icon)
return di;
}
-/* NOTE:, returns unscaled by DPI. */
int UI_icon_get_width(int icon_id)
{
Icon *icon = BKE_icon_get(icon_id);
@@ -1275,8 +1240,6 @@ void UI_icons_init()
#endif
}
-/* Render size for preview images and icons
- */
int UI_icon_preview_to_render_size(enum eIconSizes size)
{
switch (size) {
@@ -1303,7 +1266,7 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size)
else if (!prv_img->rect[size]) {
prv_img->w[size] = render_size;
prv_img->h[size] = render_size;
- prv_img->flag[size] |= (PRV_CHANGED | PRV_UNFINISHED);
+ prv_img->flag[size] |= PRV_CHANGED;
prv_img->changed_timestamp[size] = 0;
prv_img->rect[size] = MEM_callocN(render_size * render_size * sizeof(uint), "prv_rect");
}
@@ -1452,6 +1415,7 @@ static void icon_set_image(const bContext *C,
const bool delay = prv_img->rect[size] != NULL;
icon_create_rect(prv_img, size);
+ prv_img->flag[size] |= PRV_RENDERING;
if (use_job && (!id || BKE_previewimg_id_supports_jobs(id))) {
/* Job (background) version */
@@ -1526,11 +1490,11 @@ static void icon_draw_rect(float x,
float alpha,
const float desaturate)
{
- ImBuf *ima = NULL;
int draw_w = w;
int draw_h = h;
int draw_x = x;
- int draw_y = y;
+ /* We need to round y, to avoid the icon jittering in some cases. */
+ int draw_y = round_fl_to_int(y);
/* sanity check */
if (w <= 0 || h <= 0 || w > 2000 || h > 2000) {
@@ -1541,6 +1505,8 @@ static void icon_draw_rect(float x,
/* modulate color */
const float col[4] = {alpha, alpha, alpha, alpha};
+ float scale_x = 1.0f;
+ float scale_y = 1.0f;
/* rect contains image in 'rendersize', we only scale if needed */
if (rw != w || rh != h) {
/* preserve aspect ratio and center */
@@ -1554,13 +1520,9 @@ static void icon_draw_rect(float x,
draw_h = h;
draw_x += (w - draw_w) / 2;
}
+ scale_x = draw_w / (float)rw;
+ scale_y = draw_h / (float)rh;
/* If the image is squared, the `draw_*` initialization values are good. */
-
- /* first allocate imbuf for scaling and copy preview into it */
- ima = IMB_allocImBuf(rw, rh, 32, IB_rect);
- memcpy(ima->rect, rect, rw * rh * sizeof(uint));
- IMB_scaleImBuf(ima, draw_w, draw_h); /* scale it */
- rect = ima->rect;
}
/* draw */
@@ -1577,12 +1539,8 @@ static void icon_draw_rect(float x,
immUniform1f("factor", desaturate);
}
- immDrawPixelsTex(
- &state, draw_x, draw_y, draw_w, draw_h, GPU_RGBA8, false, rect, 1.0f, 1.0f, col);
-
- if (ima) {
- IMB_freeImBuf(ima);
- }
+ immDrawPixelsTexScaledFullSize(
+ &state, draw_x, draw_y, rw, rh, GPU_RGBA8, true, rect, scale_x, scale_y, 1.0f, 1.0f, col);
}
/* High enough to make a difference, low enough so that
@@ -1625,18 +1583,21 @@ static void icon_draw_cache_texture_flush_ex(GPUTexture *texture,
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR);
GPU_shader_bind(shader);
- const int img_binding = GPU_shader_get_texture_binding(shader, "image");
- const int data_loc = GPU_shader_get_uniform(shader, "calls_data");
+ const int data_loc = GPU_shader_get_uniform_block(shader, "multi_rect_data");
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
+ sizeof(struct MultiRectCallData), texture_draw_calls->drawcall_cache, __func__);
+ GPU_uniformbuf_bind(ubo, data_loc);
+ const int img_binding = GPU_shader_get_texture_binding(shader, "image");
GPU_texture_bind_ex(texture, GPU_SAMPLER_ICON, img_binding, false);
- GPU_shader_uniform_vector(
- shader, data_loc, 4, ICON_DRAW_CACHE_SIZE * 3, (float *)texture_draw_calls->drawcall_cache);
GPUBatch *quad = GPU_batch_preset_quad();
GPU_batch_set_shader(quad, shader);
GPU_batch_draw_instanced(quad, texture_draw_calls->calls);
GPU_texture_unbind(texture);
+ GPU_uniformbuf_unbind(ubo);
+ GPU_uniformbuf_free(ubo);
texture_draw_calls->calls = 0;
}
@@ -1988,19 +1949,39 @@ static void ui_id_preview_image_render_size(
}
}
-/**
- * Note that if an ID doesn't support jobs for preview creation, \a use_job will be ignored.
- */
+void UI_icon_render_id_ex(const bContext *C,
+ Scene *scene,
+ ID *id_to_render,
+ const enum eIconSizes size,
+ const bool use_job,
+ PreviewImage *r_preview_image)
+{
+ ui_id_preview_image_render_size(C, scene, id_to_render, r_preview_image, size, use_job);
+}
+
void UI_icon_render_id(
const bContext *C, Scene *scene, ID *id, const enum eIconSizes size, const bool use_job)
{
PreviewImage *pi = BKE_previewimg_id_ensure(id);
-
if (pi == NULL) {
return;
}
- ui_id_preview_image_render_size(C, scene, id, pi, size, use_job);
+ ID *id_to_render = id;
+
+ /* For objects, first try if a preview can created via the object data. */
+ if (GS(id->name) == ID_OB) {
+ Object *ob = (Object *)id;
+ if (ED_preview_id_is_supported(ob->data)) {
+ id_to_render = ob->data;
+ }
+ }
+
+ if (!ED_preview_id_is_supported(id_to_render)) {
+ return;
+ }
+
+ UI_icon_render_id_ex(C, scene, id_to_render, size, use_job, pi);
}
static void ui_id_icon_render(const bContext *C, ID *id, bool use_jobs)
@@ -2419,7 +2400,6 @@ int UI_icon_color_from_collection(const Collection *collection)
return icon;
}
-/* draws icon with dpi scale factor */
void UI_icon_draw(float x, float y, int icon_id)
{
UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false);
diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c
index 3962ff6a702..577db6a0338 100644
--- a/source/blender/editors/interface/interface_icons_event.c
+++ b/source/blender/editors/interface/interface_icons_event.c
@@ -77,7 +77,7 @@
static void icon_draw_rect_input_text(const rctf *rect,
const float color[4],
const char *str,
- int font_size)
+ float font_size)
{
BLF_batch_draw_flush();
const int font_id = BLF_default();
@@ -97,7 +97,7 @@ static void icon_draw_rect_input_symbol(const rctf *rect, const float color[4],
BLF_batch_draw_flush();
const int font_id = blf_mono_font;
BLF_color4fv(font_id, color);
- BLF_size(font_id, 19 * U.pixelsize, U.dpi);
+ BLF_size(font_id, 19.0f * U.pixelsize, U.dpi);
const float x = rect->xmin + (2.0f * U.pixelsize);
const float y = rect->ymin + (1.0f * U.pixelsize);
BLF_position(font_id, x, y, 0.0f);
@@ -152,12 +152,12 @@ void icon_draw_rect_input(float x,
if ((event_type >= EVT_AKEY) && (event_type <= EVT_ZKEY)) {
const char str[2] = {'A' + (event_type - EVT_AKEY), '\0'};
- icon_draw_rect_input_text(&rect, color, str, 13);
+ icon_draw_rect_input_text(&rect, color, str, 13.0f);
}
else if ((event_type >= EVT_F1KEY) && (event_type <= EVT_F12KEY)) {
char str[4];
SNPRINTF(str, "F%d", 1 + (event_type - EVT_F1KEY));
- icon_draw_rect_input_text(&rect, color, str, event_type > EVT_F9KEY ? 8 : 10);
+ icon_draw_rect_input_text(&rect, color, str, event_type > EVT_F9KEY ? 8.0f : 10.0f);
}
else if (event_type == EVT_LEFTSHIFTKEY) {
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x87, 0xa7, 0x0});
@@ -167,7 +167,7 @@ void icon_draw_rect_input(float x,
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0x83, 0x0});
}
else {
- icon_draw_rect_input_text(&rect, color, "Ctrl", 9);
+ icon_draw_rect_input_text(&rect, color, "Ctrl", 9.0f);
}
}
else if (event_type == EVT_LEFTALTKEY) {
@@ -175,7 +175,7 @@ void icon_draw_rect_input(float x,
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0xa5, 0x0});
}
else {
- icon_draw_rect_input_text(&rect, color, "Alt", 10);
+ icon_draw_rect_input_text(&rect, color, "Alt", 10.0f);
}
}
else if (event_type == EVT_OSKEY) {
@@ -186,20 +186,20 @@ void icon_draw_rect_input(float x,
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x9d, 0x96, 0x0});
}
else {
- icon_draw_rect_input_text(&rect, color, "OS", 10);
+ icon_draw_rect_input_text(&rect, color, "OS", 10.0f);
}
}
else if (event_type == EVT_DELKEY) {
- icon_draw_rect_input_text(&rect, color, "Del", 9);
+ icon_draw_rect_input_text(&rect, color, "Del", 9.0f);
}
else if (event_type == EVT_TABKEY) {
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0xad, 0xbe, 0x0});
}
else if (event_type == EVT_HOMEKEY) {
- icon_draw_rect_input_text(&rect, color, "Home", 6);
+ icon_draw_rect_input_text(&rect, color, "Home", 6.0f);
}
else if (event_type == EVT_ENDKEY) {
- icon_draw_rect_input_text(&rect, color, "End", 8);
+ icon_draw_rect_input_text(&rect, color, "End", 8.0f);
}
else if (event_type == EVT_RETKEY) {
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8f, 0x8e, 0x0});
@@ -209,14 +209,14 @@ void icon_draw_rect_input(float x,
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8e, 0x8b, 0x0});
}
else {
- icon_draw_rect_input_text(&rect, color, "Esc", 8);
+ icon_draw_rect_input_text(&rect, color, "Esc", 8.0f);
}
}
else if (event_type == EVT_PAGEUPKEY) {
- icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 8);
+ icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 8.0f);
}
else if (event_type == EVT_PAGEDOWNKEY) {
- icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 8);
+ icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 8.0f);
}
else if (event_type == EVT_LEFTARROWKEY) {
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x90, 0x0});
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 95e6791b359..2d1138b46a7 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -116,7 +116,7 @@ extern const char ui_radial_dir_to_numpad[8];
extern const short ui_radial_dir_to_angle[8];
/* internal panel drawing defines */
-#define PNL_HEADER (UI_UNIT_Y * 1.2) /* 24 default */
+#define PNL_HEADER (UI_UNIT_Y * 1.25) /* 24 default */
/* bit button defines */
/* Bit operations */
@@ -255,7 +255,7 @@ struct uiBut {
/* Operator data */
struct wmOperatorType *optype;
struct PointerRNA *opptr;
- short opcontext;
+ wmOperatorCallContext opcontext;
/** When non-zero, this is the key used to activate a menu items (`a-z` always lower case). */
uchar menu_key;
@@ -351,15 +351,6 @@ typedef struct uiButProgressbar {
float progress;
} uiButProgressbar;
-/** Derived struct for #UI_BTYPE_DATASETROW. */
-typedef struct uiButDatasetRow {
- uiBut but;
-
- uint8_t geometry_component_type;
- uint8_t attribute_domain;
- int indentation;
-} uiButDatasetRow;
-
/** Derived struct for #UI_BTYPE_TREEROW. */
typedef struct uiButTreeRow {
uiBut but;
@@ -407,6 +398,7 @@ typedef struct uiButExtraOpIcon {
struct wmOperatorCallParams *optype_params;
bool highlighted;
+ bool disabled;
} uiButExtraOpIcon;
typedef struct ColorPicker {
@@ -608,7 +600,7 @@ typedef struct uiSafetyRct {
/* interface.c */
-void ui_fontscale(short *points, float aspect);
+void ui_fontscale(float *points, float aspect);
extern void ui_block_to_region_fl(const struct ARegion *region,
uiBlock *block,
@@ -628,6 +620,9 @@ extern void ui_block_to_window_rctf(const struct ARegion *region,
rctf *rct_dst,
const rctf *rct_src);
extern float ui_block_to_window_scale(const struct ARegion *region, uiBlock *block);
+/**
+ * For mouse cursor.
+ */
extern void ui_window_to_block_fl(const struct ARegion *region,
uiBlock *block,
float *x,
@@ -645,31 +640,69 @@ extern void ui_window_to_region_rctf(const struct ARegion *region,
rctf *rect_dst,
const rctf *rct_src);
extern void ui_region_to_window(const struct ARegion *region, int *x, int *y);
+/**
+ * Popups will add a margin to #ARegion.winrct for shadow,
+ * for interactivity (point-inside tests for eg), we want the winrct without the margin added.
+ */
extern void ui_region_winrct_get_no_margin(const struct ARegion *region, struct rcti *r_rect);
+/**
+ * Reallocate the button (new address is returned) for a new button type.
+ * This should generally be avoided and instead the correct type be created right away.
+ *
+ * \note Only the #uiBut data can be kept. If the old button used a derived type (e.g. #uiButTab),
+ * the data that is not inside #uiBut will be lost.
+ */
uiBut *ui_but_change_type(uiBut *but, eButType new_type);
extern double ui_but_value_get(uiBut *but);
extern void ui_but_value_set(uiBut *but, double value);
+/**
+ * For picker, while editing HSV.
+ */
extern void ui_but_hsv_set(uiBut *but);
+/**
+ * For buttons pointing to color for example.
+ */
extern void ui_but_v3_get(uiBut *but, float vec[3]);
+/**
+ * For buttons pointing to color for example.
+ */
extern void ui_but_v3_set(uiBut *but, const float vec[3]);
extern void ui_hsvcircle_vals_from_pos(
- const rcti *rect, const float mx, const float my, float *r_val_rad, float *r_val_dist);
+ const rcti *rect, float mx, float my, float *r_val_rad, float *r_val_dist);
+/**
+ * Cursor in HSV circle, in float units -1 to 1, to map on radius.
+ */
extern void ui_hsvcircle_pos_from_vals(
const ColorPicker *cpicker, const rcti *rect, const float *hsv, float *xpos, float *ypos);
extern void ui_hsvcube_pos_from_vals(
const struct uiButHSVCube *hsv_but, const rcti *rect, const float *hsv, float *xp, float *yp);
+/**
+ * \param float_precision: For number buttons the precision
+ * to use or -1 to fallback to the button default.
+ * \param use_exp_float: Use exponent representation of floats
+ * when out of reasonable range (outside of 1e3/1e-3).
+ */
extern void ui_but_string_get_ex(uiBut *but,
char *str,
- const size_t maxlen,
- const int float_precision,
- const bool use_exp_float,
+ size_t maxlen,
+ int float_precision,
+ bool use_exp_float,
bool *r_use_exp_float) ATTR_NONNULL(1, 2);
-extern void ui_but_string_get(uiBut *but, char *str, const size_t maxlen) ATTR_NONNULL();
+extern void ui_but_string_get(uiBut *but, char *str, size_t maxlen) ATTR_NONNULL();
+/**
+ * A version of #ui_but_string_get_ex for dynamic buffer sizes
+ * (where #ui_but_string_get_max_length returns 0).
+ *
+ * \param r_str_size: size of the returned string (including terminator).
+ */
extern char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size);
+/**
+ * \param str: will be overwritten.
+ */
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_eval_number(struct bContext *C,
@@ -677,11 +710,22 @@ extern bool ui_but_string_eval_number(struct bContext *C,
const char *str,
double *value) ATTR_NONNULL();
extern int ui_but_string_get_max_length(uiBut *but);
-/* Clear & exit the active button's string. */
+/**
+ * Clear & exit the active button's string..
+ */
extern void ui_but_active_string_clear_and_exit(struct bContext *C, uiBut *but) ATTR_NONNULL();
+/**
+ * Use handling code to set a string for the button. Handles the case where the string is set for a
+ * search button while the search menu is open, so the results are updated accordingly.
+ * This is basically the same as pasting the string into the button.
+ */
+extern void ui_but_set_string_interactive(struct bContext *C, uiBut *but, const char *value);
extern uiBut *ui_but_drag_multi_edit_get(uiBut *but);
-void ui_def_but_icon(uiBut *but, const int icon, const int flag);
+void ui_def_but_icon(uiBut *but, int icon, int flag);
+/**
+ * Avoid using this where possible since it's better not to ask for an icon in the first place.
+ */
void ui_def_but_icon_clear(uiBut *but);
void ui_but_extra_operator_icons_free(uiBut *but);
@@ -694,6 +738,14 @@ void ui_but_range_set_hard(uiBut *but);
void ui_but_range_set_soft(uiBut *but);
bool ui_but_context_poll_operator(struct bContext *C, struct wmOperatorType *ot, const uiBut *but);
+/**
+ * Check if the operator \a ot poll is successful with the context given by \a but (optionally).
+ * \param but: The button that might store context. Can be NULL for convenience (e.g. if there is
+ * no button to take context from, but we still want to poll the operator).
+ */
+bool ui_but_context_poll_operator_ex(struct bContext *C,
+ const uiBut *but,
+ const struct wmOperatorCallParams *optype_params);
extern void ui_but_update(uiBut *but);
extern void ui_but_update_edited(uiBut *but);
@@ -701,10 +753,21 @@ extern PropertyScaleType ui_but_scale_type(const uiBut *but) ATTR_WARN_UNUSED_RE
extern bool ui_but_is_float(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_bool(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_unit(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Check if this button is similar enough to be grouped with another.
+ */
extern bool ui_but_is_compatible(const uiBut *but_a, const uiBut *but_b) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_rna_valid(uiBut *but) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Checks if the button supports cycling next/previous menu items (ctrl+mouse-wheel).
+ */
extern bool ui_but_supports_cycling(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Check if the button is pushed, this is only meaningful for some button types.
+ *
+ * \return (0 == UNSELECT), (1 == SELECT), (-1 == DO-NOTHING)
+ */
extern int ui_but_is_pushed_ex(uiBut *but, double *value) ATTR_WARN_UNUSED_RESULT;
extern int ui_but_is_pushed(uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -799,6 +862,7 @@ struct uiPopupBlockHandle {
/* interface_region_*.c */
/* interface_region_tooltip.c */
+
/* exposed as public API in UI_interface.h */
/* interface_region_color_picker.c */
@@ -806,6 +870,10 @@ void ui_color_picker_rgb_to_hsv_compat(const float rgb[3], float r_cp[3]);
void ui_color_picker_rgb_to_hsv(const float rgb[3], float r_cp[3]);
void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3]);
+/**
+ * Returns true if the button is for a color with gamma baked in,
+ * or if it's a color picker for such a button.
+ */
bool ui_but_is_color_gamma(uiBut *but);
void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3]);
@@ -815,7 +883,10 @@ uiBlock *ui_block_func_COLOR(struct bContext *C, uiPopupBlockHandle *handle, voi
ColorPicker *ui_block_colorpicker_create(struct uiBlock *block);
/* interface_region_search.c */
-/* Search-box for string button. */
+
+/**
+ * Search-box for string button.
+ */
struct ARegion *ui_searchbox_create_generic(struct bContext *C,
struct ARegion *butregion,
uiButSearch *search_but);
@@ -826,25 +897,41 @@ struct ARegion *ui_searchbox_create_menu(struct bContext *C,
struct ARegion *butregion,
uiButSearch *search_but);
-bool ui_searchbox_inside(struct ARegion *region, int x, int y);
+/**
+ * x and y in screen-coords.
+ */
+bool ui_searchbox_inside(struct ARegion *region, const int xy[2]) ATTR_NONNULL(1, 2);
int ui_searchbox_find_index(struct ARegion *region, const char *name);
-void ui_searchbox_update(struct bContext *C, struct ARegion *region, uiBut *but, const bool reset);
+/**
+ * Region is the search box itself.
+ */
+void ui_searchbox_update(struct bContext *C, struct ARegion *region, uiBut *but, bool reset);
int ui_searchbox_autocomplete(struct bContext *C, struct ARegion *region, uiBut *but, char *str);
bool ui_searchbox_event(struct bContext *C,
struct ARegion *region,
uiBut *but,
struct ARegion *butregion,
const struct wmEvent *event);
+/**
+ * String validated to be of correct length (but->hardmax).
+ */
bool ui_searchbox_apply(uiBut *but, struct ARegion *region);
void ui_searchbox_free(struct bContext *C, struct ARegion *region);
+/**
+ * XXX weak: search_func adds all partial matches.
+ */
void ui_but_search_refresh(uiButSearch *but);
/* interface_region_menu_popup.c */
+
int ui_but_menu_step(uiBut *but, int direction);
bool ui_but_menu_step_poll(const uiBut *but);
uiBut *ui_popup_menu_memory_get(struct uiBlock *block);
void ui_popup_menu_memory_set(uiBlock *block, struct uiBut *but);
+/**
+ * Called for creating new popups and refreshing existing ones.
+ */
uiBlock *ui_popup_block_refresh(struct bContext *C,
uiPopupBlockHandle *handle,
struct ARegion *butregion,
@@ -864,6 +951,7 @@ uiPopupBlockHandle *ui_popup_menu_create(struct bContext *C,
void *arg);
/* interface_region_popover.c */
+
uiPopupBlockHandle *ui_popover_panel_create(struct bContext *C,
struct ARegion *butregion,
uiBut *but,
@@ -871,16 +959,24 @@ uiPopupBlockHandle *ui_popover_panel_create(struct bContext *C,
void *arg);
/* interface_region_menu_pie.c */
+
+/**
+ * Set up data for defining a new pie menu level and add button that invokes it.
+ */
void ui_pie_menu_level_create(uiBlock *block,
struct wmOperatorType *ot,
const char *propname,
struct IDProperty *properties,
const EnumPropertyItem *items,
int totitem,
- int context,
+ wmOperatorCallContext context,
int flag);
/* interface_region_popup.c */
+
+/**
+ * Translate any popup regions (so we can drag them).
+ */
void ui_popup_translate(struct ARegion *region, const int mdiff[2]);
void ui_popup_block_free(struct bContext *C, uiPopupBlockHandle *handle);
void ui_popup_block_scrolltest(struct uiBlock *block);
@@ -888,27 +984,39 @@ void ui_popup_block_scrolltest(struct uiBlock *block);
/* end interface_region_*.c */
/* interface_panel.c */
+
+/**
+ * Handle region panel events like opening and closing panels, changing categories, etc.
+ *
+ * \note Could become a modal key-map.
+ */
extern int ui_handler_panel_region(struct bContext *C,
const struct wmEvent *event,
struct ARegion *region,
const uiBut *active_but);
+/**
+ * Draw a panel integrated in buttons-window, tool/property lists etc.
+ */
extern void ui_draw_aligned_panel(const struct uiStyle *style,
const uiBlock *block,
const rcti *rect,
- const bool show_pin,
- const bool show_background,
- const bool region_search_filter_active);
+ bool show_pin,
+ bool show_background,
+ bool region_search_filter_active);
void ui_panel_tag_search_filter_match(struct Panel *panel);
/* interface_draw.c */
+
extern void ui_draw_dropshadow(
const rctf *rct, float radius, float aspect, float alpha, int select);
-void ui_draw_gradient(const rcti *rect,
- const float hsv[3],
- const eButGradientType type,
- const float alpha);
+/**
+ * Draws in resolution of 48x4 colors.
+ */
+void ui_draw_gradient(const rcti *rect, const float hsv[3], eButGradientType type, float alpha);
+/* based on UI_draw_roundbox_gl_mode,
+ * check on making a version which allows us to skip some sides */
void ui_draw_but_TAB_outline(const rcti *rect,
float rad,
uchar highlight[3],
@@ -926,11 +1034,17 @@ void ui_draw_but_VECTORSCOPE(struct ARegion *region,
const struct uiWidgetColors *wcol,
const rcti *rect);
void ui_draw_but_COLORBAND(uiBut *but, const struct uiWidgetColors *wcol, const rcti *rect);
-void ui_draw_but_UNITVEC(uiBut *but, const struct uiWidgetColors *wcol, const rcti *rect);
+void ui_draw_but_UNITVEC(uiBut *but,
+ const struct uiWidgetColors *wcol,
+ const rcti *rect,
+ float radius);
void ui_draw_but_CURVE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
+/**
+ * Draws the curve profile widget. Somewhat similar to ui_draw_but_CURVE.
+ */
void ui_draw_but_CURVEPROFILE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
@@ -945,8 +1059,19 @@ void ui_draw_but_TRACKPREVIEW(struct ARegion *region,
const rcti *rect);
/* interface_undo.c */
+
+/**
+ * Start the undo stack.
+ *
+ * \note The current state should be pushed immediately after calling this.
+ */
struct uiUndoStack_Text *ui_textedit_undo_stack_create(void);
void ui_textedit_undo_stack_destroy(struct uiUndoStack_Text *undo_stack);
+/**
+ * Push the information in the arguments to a new state in the undo stack.
+ *
+ * \note Currently the total length of the undo stack is not limited.
+ */
void ui_textedit_undo_push(struct uiUndoStack_Text *undo_stack,
const char *text,
int cursor_index);
@@ -955,9 +1080,25 @@ const char *ui_textedit_undo(struct uiUndoStack_Text *undo_stack,
int *r_cursor_index);
/* interface_handlers.c */
-extern void ui_handle_afterfunc_add_operator(struct wmOperatorType *ot, int opcontext);
+
+extern void ui_handle_afterfunc_add_operator(struct wmOperatorType *ot,
+ wmOperatorCallContext opcontext);
+/**
+ * Assumes event type is MOUSEPAN.
+ */
extern void ui_pan_to_scroll(const struct wmEvent *event, int *type, int *val);
+/**
+ * Exported to interface.c: #UI_but_active_only()
+ * \note The region is only for the button.
+ * The context needs to be set by the caller.
+ */
extern void ui_but_activate_event(struct bContext *C, struct ARegion *region, uiBut *but);
+/**
+ * Simulate moving the mouse over a button (or navigating to it with arrow keys).
+ *
+ * exported so menus can start with a highlighted button,
+ * even if the mouse isn't over it
+ */
extern void ui_but_activate_over(struct bContext *C, struct ARegion *region, uiBut *but);
extern void ui_but_execute_begin(struct bContext *C,
struct ARegion *region,
@@ -968,14 +1109,26 @@ extern void ui_but_execute_end(struct bContext *C,
uiBut *but,
void *active_back);
extern void ui_but_active_free(const struct bContext *C, uiBut *but);
+/**
+ * In some cases we may want to update the view (#View2D) in-between layout definition and drawing.
+ * E.g. to make sure a button is visible while editing.
+ */
extern void ui_but_update_view_for_active(const struct bContext *C, const uiBlock *block);
extern int ui_but_menu_direction(uiBut *but);
-extern void ui_but_text_password_hide(char password_str[128], uiBut *but, const bool restore);
+extern void ui_but_text_password_hide(char password_str[128], uiBut *but, bool restore);
+/**
+ * Finds the pressed button in an aligned row (typically an expanded enum).
+ *
+ * \param direction: Use when there may be multiple buttons pressed.
+ */
extern uiBut *ui_but_find_select_in_enum(uiBut *but, int direction);
bool ui_but_is_editing(const uiBut *but);
float ui_block_calc_pie_segment(struct uiBlock *block, const float event_xy[2]);
-void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_strip);
+/* XXX, this code will shorten any allocated string to 'UI_MAX_NAME_STR'
+ * since this is really long its unlikely to be an issue,
+ * but this could be supported */
+void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, bool do_strip);
void ui_but_clipboard_free(void);
bool ui_but_rna_equals(const uiBut *a, const uiBut *b);
bool ui_but_rna_equals_ex(const uiBut *but,
@@ -1027,9 +1180,7 @@ enum {
struct GPUBatch *ui_batch_roundbox_widget_get(void);
struct GPUBatch *ui_batch_roundbox_shadow_get(void);
-void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4]);
void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect);
-void ui_draw_box_opaque(rcti *rect, int roundboxalign);
void ui_draw_popover_back(struct ARegion *region,
struct uiStyle *style,
uiBlock *block,
@@ -1041,6 +1192,9 @@ void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const flo
void ui_draw_widget_menu_back(const rcti *rect, bool use_shadow);
void ui_draw_tooltip_background(const struct uiStyle *style, uiBlock *block, rcti *rect);
+/**
+ * Conversion from old to new buttons, so still messy.
+ */
extern void ui_draw_but(const struct bContext *C,
struct ARegion *region,
struct uiStyle *style,
@@ -1061,6 +1215,15 @@ typedef enum {
* get clipped before the normal text. */
UI_MENU_ITEM_SEPARATOR_HINT,
} uiMenuItemSeparatorType;
+/**
+ * Helper call to draw a menu item without a button.
+ *
+ * \param state: The state of the button,
+ * typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
+ * \param separator_type: The kind of separator which controls if and how the string is clipped.
+ * \param r_xmax: The right hand position of the text, this takes into the icon,
+ * padding and text clipping when there is not enough room to display the full text.
+ */
void ui_draw_menu_item(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
@@ -1074,6 +1237,10 @@ void ui_draw_preview_item(const struct uiFontStyle *fstyle,
int iconid,
int state,
eFontStyle_Align text_align);
+/**
+ * Version of #ui_draw_preview_item() that does not draw the menu background and item text based on
+ * state. It just draws the preview and text directly.
+ */
void ui_draw_preview_item_stateless(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
@@ -1083,58 +1250,102 @@ void ui_draw_preview_item_stateless(const struct uiFontStyle *fstyle,
#define UI_TEXT_MARGIN_X 0.4f
#define UI_POPUP_MARGIN (UI_DPI_FAC * 12)
-/* Margin at top of screen for popups. Note this value must be sufficient
- * to draw a popover arrow to avoid cropping it. */
+/**
+ * Margin at top of screen for popups.
+ * Note this value must be sufficient to draw a popover arrow to avoid cropping it.
+ */
#define UI_POPUP_MENU_TOP (int)(10 * UI_DPI_FAC)
#define UI_PIXEL_AA_JITTER 8
extern const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2];
/* interface_style.c */
+
+/**
+ * Called on each startup.blend read,
+ * reading without #uiFont will create one.
+ */
void uiStyleInit(void);
/* interface_icons.c */
-void ui_icon_ensure_deferred(const struct bContext *C, const int icon_id, const bool big);
-int ui_id_icon_get(const struct bContext *C, struct ID *id, const bool big);
+
+void ui_icon_ensure_deferred(const struct bContext *C, int icon_id, bool big);
+int ui_id_icon_get(const struct bContext *C, struct ID *id, bool big);
/* interface_icons_event.c */
+
void icon_draw_rect_input(
float x, float y, int w, int h, float alpha, short event_type, short event_value);
/* resources.c */
+
void ui_resources_init(void);
void ui_resources_free(void);
/* interface_layout.c */
+
void ui_layout_add_but(uiLayout *layout, uiBut *but);
+void ui_layout_remove_but(uiLayout *layout, const uiBut *but);
+/**
+ * \return true if the button was successfully replaced.
+ */
bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but);
+/**
+ * \note May reallocate \a but, so the possibly new address is returned.
+ */
uiBut *ui_but_add_search(uiBut *but,
PointerRNA *ptr,
PropertyRNA *prop,
PointerRNA *searchptr,
PropertyRNA *searchprop);
+/**
+ * Check all buttons defined in this layout,
+ * and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
+ * Needed to handle correctly text colors of active (selected) list item.
+ */
void ui_layout_list_set_labels_active(uiLayout *layout);
/* menu callback */
void ui_item_menutype_func(struct bContext *C, struct uiLayout *layout, void *arg_mt);
void ui_item_paneltype_func(struct bContext *C, struct uiLayout *layout, void *arg_pt);
/* interface_button_group.c */
+
+/**
+ * Every function that adds a set of buttons must create another group,
+ * then #ui_def_but adds buttons to the current group (the last).
+ */
void ui_block_new_button_group(uiBlock *block, uiButtonGroupFlag flag);
void ui_button_group_add_but(uiBlock *block, uiBut *but);
void ui_button_group_replace_but_ptr(uiBlock *block, const void *old_but_ptr, uiBut *new_but);
void ui_block_free_button_groups(uiBlock *block);
/* interface_align.c */
+
bool ui_but_can_align(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
int ui_but_align_opposite_to_area_align_get(const struct ARegion *region) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Compute the alignment of all 'align groups' of buttons in given block.
+ *
+ * This is using an order-independent algorithm,
+ * i.e. alignment of buttons should be OK regardless of order in which
+ * they are added to the block.
+ */
void ui_block_align_calc(uiBlock *block, const struct ARegion *region);
/* interface_anim.c */
+
void ui_but_anim_flag(uiBut *but, const struct AnimationEvalContext *anim_eval_context);
void ui_but_anim_copy_driver(struct bContext *C);
void ui_but_anim_paste_driver(struct bContext *C);
+/**
+ * \a str can be NULL to only perform check if \a but has an expression at all.
+ * \return if button has an expression.
+ */
bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen);
bool ui_but_anim_expression_set(uiBut *but, const char *str);
+/**
+ * Create new expression for button (i.e. a "scripted driver"), if it can be created.
+ */
bool ui_but_anim_expression_create(uiBut *but, const char *str);
void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, float cfra);
@@ -1142,10 +1353,16 @@ void ui_but_anim_decorate_cb(struct bContext *C, void *arg_but, void *arg_dummy)
void ui_but_anim_decorate_update_from_flag(uiButDecorator *but);
/* interface_query.c */
+
bool ui_but_is_editable(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_editable_as_text(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
-bool ui_but_is_interactive(const uiBut *but, const bool labeledit) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Can we mouse over the button or is it hidden/disabled/layout.
+ * \note ctrl is kind of a hack currently,
+ * so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
+ */
+bool ui_but_is_interactive(const uiBut *but, bool labeledit) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_popover_once_compat(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_has_array_value(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
int ui_but_icon(const uiBut *but);
@@ -1158,35 +1375,39 @@ bool ui_but_contains_rect(const uiBut *but, const rctf *rect);
bool ui_but_contains_point_px_icon(const uiBut *but,
struct ARegion *region,
const struct wmEvent *event) ATTR_WARN_UNUSED_RESULT;
-bool ui_but_contains_point_px(const uiBut *but, const struct ARegion *region, int x, int y)
- ATTR_WARN_UNUSED_RESULT;
+bool ui_but_contains_point_px(const uiBut *but, const struct ARegion *region, const int xy[2])
+ ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_list_find_mouse_over(const struct ARegion *region,
const struct wmEvent *event) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_list_find_from_row(const struct ARegion *region,
const uiBut *row_but) ATTR_WARN_UNUSED_RESULT;
-uiBut *ui_list_row_find_mouse_over(const struct ARegion *region,
- int x,
- int y) ATTR_WARN_UNUSED_RESULT;
+uiBut *ui_list_row_find_mouse_over(const struct ARegion *region, const int xy[2])
+ ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_list_row_find_from_index(const struct ARegion *region,
- const int index,
+ int index,
uiBut *listbox) ATTR_WARN_UNUSED_RESULT;
+uiBut *ui_tree_row_find_mouse_over(const struct ARegion *region, const int xy[2])
+ ATTR_NONNULL(1, 2);
+uiBut *ui_tree_row_find_active(const struct ARegion *region);
typedef bool (*uiButFindPollFn)(const uiBut *but, const void *customdata);
+/**
+ * x and y are only used in case event is NULL.
+ */
uiBut *ui_but_find_mouse_over_ex(const struct ARegion *region,
- const int x,
- const int y,
- const bool labeledit,
+ const int xy[2],
+ bool labeledit,
const uiButFindPollFn find_poll,
- const void *find_custom_data) ATTR_WARN_UNUSED_RESULT;
+ const void *find_custom_data)
+ ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_but_find_mouse_over(const struct ARegion *region,
const struct wmEvent *event) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_but_find_rect_over(const struct ARegion *region,
const rcti *rect_px) ATTR_WARN_UNUSED_RESULT;
-uiBut *ui_list_find_mouse_over_ex(const struct ARegion *region,
- int x,
- int y) ATTR_WARN_UNUSED_RESULT;
+uiBut *ui_list_find_mouse_over_ex(const struct ARegion *region, const int xy[2])
+ ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
bool ui_but_contains_password(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -1206,10 +1427,8 @@ bool ui_block_is_popover(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
bool ui_block_is_popup_any(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
-uiBlock *ui_block_find_mouse_over_ex(const struct ARegion *region,
- const int x,
- const int y,
- bool only_clip);
+uiBlock *ui_block_find_mouse_over_ex(const struct ARegion *region, const int xy[2], bool only_clip)
+ ATTR_NONNULL(1, 2);
uiBlock *ui_block_find_mouse_over(const struct ARegion *region,
const struct wmEvent *event,
bool only_clip);
@@ -1218,45 +1437,60 @@ uiBut *ui_region_find_first_but_test_flag(struct ARegion *region,
int flag_include,
int flag_exclude);
uiBut *ui_region_find_active_but(struct ARegion *region) ATTR_WARN_UNUSED_RESULT;
-bool ui_region_contains_point_px(const struct ARegion *region,
- int x,
- int y) ATTR_WARN_UNUSED_RESULT;
+bool ui_region_contains_point_px(const struct ARegion *region, const int xy[2])
+ ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
bool ui_region_contains_rect_px(const struct ARegion *region, const rcti *rect_px);
-struct ARegion *ui_screen_region_find_mouse_over_ex(struct bScreen *screen, int x, int y);
+/**
+ * Check if the cursor is over any popups.
+ */
+struct ARegion *ui_screen_region_find_mouse_over_ex(struct bScreen *screen, const int xy[2])
+ ATTR_NONNULL(1, 2);
struct ARegion *ui_screen_region_find_mouse_over(struct bScreen *screen,
const struct wmEvent *event);
/* interface_context_menu.c */
+
bool ui_popup_context_menu_for_button(struct bContext *C, uiBut *but, const struct wmEvent *event);
+/**
+ * menu to show when right clicking on the panel header
+ */
void ui_popup_context_menu_for_panel(struct bContext *C,
struct ARegion *region,
struct Panel *panel);
/* interface_eyedropper.c */
+
struct wmKeyMap *eyedropper_modal_keymap(struct wmKeyConfig *keyconf);
struct wmKeyMap *eyedropper_colorband_modal_keymap(struct wmKeyConfig *keyconf);
/* interface_eyedropper_color.c */
+
void UI_OT_eyedropper_color(struct wmOperatorType *ot);
/* interface_eyedropper_colorband.c */
+
void UI_OT_eyedropper_colorramp(struct wmOperatorType *ot);
void UI_OT_eyedropper_colorramp_point(struct wmOperatorType *ot);
/* interface_eyedropper_datablock.c */
+
void UI_OT_eyedropper_id(struct wmOperatorType *ot);
/* interface_eyedropper_depth.c */
+
void UI_OT_eyedropper_depth(struct wmOperatorType *ot);
/* interface_eyedropper_driver.c */
+
void UI_OT_eyedropper_driver(struct wmOperatorType *ot);
/* interface_eyedropper_gpencil_color.c */
+
void UI_OT_eyedropper_gpencil_color(struct wmOperatorType *ot);
/* interface_template_asset_view.cc */
+
struct uiListType *UI_UL_asset_view(void);
/**
@@ -1275,22 +1509,27 @@ typedef struct uiRNACollectionSearch {
/* Block has to be stored for freeing butstore (uiBut.block doesn't work with undo). */
uiBlock *butstore_block;
} uiRNACollectionSearch;
-void ui_rna_collection_search_update_fn(const struct bContext *C,
- void *arg,
- const char *str,
- uiSearchItems *items,
- const bool is_first);
+void ui_rna_collection_search_update_fn(
+ const struct bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first);
/* interface_ops.c */
+
bool ui_jump_to_target_button_poll(struct bContext *C);
/* interface_queries.c */
+
void ui_interface_tag_script_reload_queries(void);
/* interface_view.cc */
+
void ui_block_free_views(struct uiBlock *block);
uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
const uiTreeViewHandle *new_view);
+uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
+ const uiTreeViewItemHandle *new_item_handle);
+
+/* interface_templates.c */
+struct uiListType *UI_UL_cache_file_layers(void);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index c10ba3894ea..98fcb36b778 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -82,7 +82,7 @@ typedef struct uiLayoutRoot {
struct uiLayoutRoot *next, *prev;
int type;
- int opcontext;
+ wmOperatorCallContext opcontext;
int emw, emh;
int padding;
@@ -295,6 +295,7 @@ static bool ui_layout_variable_size(uiLayout *layout)
struct uiTextIconPadFactor {
float text;
float icon;
+ float icon_only;
};
/**
@@ -309,18 +310,21 @@ struct uiTextIconPadFactor {
static const struct uiTextIconPadFactor ui_text_pad_default = {
.text = 1.50f,
.icon = 0.25f,
+ .icon_only = 0.0f,
};
/** #ui_text_pad_default scaled down. */
static const struct uiTextIconPadFactor ui_text_pad_compact = {
.text = 1.25f,
- .icon = 0.35,
+ .icon = 0.35f,
+ .icon_only = 0.0f,
};
/** Least amount of padding not to clip the text or icon. */
static const struct uiTextIconPadFactor ui_text_pad_none = {
- .text = 0.25,
+ .text = 0.25f,
.icon = 1.50f,
+ .icon_only = 0.0f,
};
/**
@@ -333,23 +337,30 @@ static int ui_text_icon_width_ex(uiLayout *layout,
{
const int unit_x = UI_UNIT_X * (layout->scale[0] ? layout->scale[0] : 1.0f);
+ /* When there is no text, always behave as if this is an icon-only button
+ * since it's not useful to return empty space. */
if (icon && !name[0]) {
- return unit_x; /* icon only */
+ return unit_x * (1.0f + pad_factor->icon_only);
}
if (ui_layout_variable_size(layout)) {
if (!icon && !name[0]) {
- return unit_x; /* No icon or name. */
+ return unit_x * (1.0f + pad_factor->icon_only);
}
+
if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) {
layout->item.flag |= UI_ITEM_FIXED_SIZE;
}
- const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+
float margin = pad_factor->text;
if (icon) {
margin += pad_factor->icon;
}
- return UI_fontstyle_string_width(fstyle, name) + (unit_x * margin);
+
+ const float aspect = layout->root->block->aspect;
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+ return UI_fontstyle_string_width_with_block_aspect(fstyle, name, aspect) +
+ (int)ceilf(unit_x * margin);
}
return unit_x * 10;
}
@@ -1207,7 +1218,7 @@ static uiBut *uiItemFullO_ptr_ex(uiLayout *layout,
const char *name,
int icon,
IDProperty *properties,
- int context,
+ wmOperatorCallContext context,
int flag,
PointerRNA *r_opptr)
{
@@ -1328,7 +1339,7 @@ static void ui_item_menu_hold(struct bContext *C, ARegion *butregion, uiBut *but
UI_menutype_draw(C, mt, layout);
}
else {
- uiItemL(layout, "Menu Missing:", ICON_NONE);
+ uiItemL(layout, TIP_("Menu Missing:"), ICON_NONE);
uiItemL(layout, menu_id, ICON_NONE);
}
UI_popup_menu_end(C, pup);
@@ -1339,7 +1350,7 @@ void uiItemFullO_ptr(uiLayout *layout,
const char *name,
int icon,
IDProperty *properties,
- int context,
+ wmOperatorCallContext context,
int flag,
PointerRNA *r_opptr)
{
@@ -1351,7 +1362,7 @@ void uiItemFullOMenuHold_ptr(uiLayout *layout,
const char *name,
int icon,
IDProperty *properties,
- int context,
+ wmOperatorCallContext context,
int flag,
const char *menu_id,
PointerRNA *r_opptr)
@@ -1365,7 +1376,7 @@ void uiItemFullO(uiLayout *layout,
const char *name,
int icon,
IDProperty *properties,
- int context,
+ wmOperatorCallContext context,
int flag,
PointerRNA *r_opptr)
{
@@ -1453,17 +1464,12 @@ BLI_INLINE bool ui_layout_is_radial(const uiLayout *layout)
((layout->item.type == ITEM_LAYOUT_ROOT) && (layout->root->type == UI_LAYOUT_PIEMENU));
}
-/**
- * Create UI items for enum items in \a item_array.
- *
- * A version of #uiItemsFullEnumO that takes pre-calculated item array.
- */
void uiItemsFullEnumO_items(uiLayout *layout,
wmOperatorType *ot,
PointerRNA ptr,
PropertyRNA *prop,
IDProperty *properties,
- int context,
+ wmOperatorCallContext context,
int flag,
const EnumPropertyItem *item_array,
int totitem)
@@ -1612,7 +1618,7 @@ void uiItemsFullEnumO(uiLayout *layout,
const char *opname,
const char *propname,
IDProperty *properties,
- int context,
+ wmOperatorCallContext context,
int flag)
{
wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
@@ -1680,7 +1686,6 @@ void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
uiItemsFullEnumO(layout, opname, propname, NULL, layout->root->opcontext, 0);
}
-/* for use in cases where we have */
void uiItemEnumO_value(uiLayout *layout,
const char *name,
int icon,
@@ -2455,9 +2460,6 @@ void uiItemR(
uiItemFullR(layout, ptr, prop, RNA_NO_INDEX, 0, flag, name, icon);
}
-/**
- * Use a wrapper function since re-implementing all the logic in this function would be messy.
- */
void uiItemFullR_with_popover(uiLayout *layout,
PointerRNA *ptr,
PropertyRNA *prop,
@@ -2711,9 +2713,6 @@ static void ui_rna_collection_search_arg_free_fn(void *ptr)
MEM_freeN(ptr);
}
-/**
- * \note May reallocate \a but, so the possibly new address is returned.
- */
uiBut *ui_but_add_search(
uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop)
{
@@ -2858,7 +2857,6 @@ void uiItemPointerR(uiLayout *layout,
uiItemPointerR_prop(layout, ptr, prop, searchptr, searchprop, name, icon);
}
-/* menu item */
void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
{
MenuType *mt = (MenuType *)arg_mt;
@@ -2907,11 +2905,10 @@ static uiBut *ui_item_menu(uiLayout *layout,
}
else if (force_menu) {
pad_factor.text = 1.85;
+ pad_factor.icon_only = 0.6f;
}
else {
- if (name[0]) {
- pad_factor.text = 0.75;
- }
+ pad_factor.text = 0.75f;
}
}
@@ -3005,10 +3002,6 @@ void uiItemMContents(uiLayout *layout, const char *menuname)
UI_menutype_draw(C, mt, layout);
}
-/**
- * Insert a decorator item for a button with the same property as \a prop.
- * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a prop.
- */
void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index)
{
uiBlock *block = layout->root->block;
@@ -3067,10 +3060,6 @@ void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop,
}
}
-/**
- * Insert a decorator item for a button with the same property as \a prop.
- * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a propname.
- */
void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index)
{
PropertyRNA *prop = NULL;
@@ -3089,7 +3078,6 @@ void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, i
uiItemDecoratorR_prop(layout, ptr, prop, index);
}
-/* popover */
void uiItemPopoverPanel_ptr(
uiLayout *layout, const bContext *C, PanelType *pt, const char *name, int icon)
{
@@ -3231,11 +3219,6 @@ void uiItemL(uiLayout *layout, const char *name, int icon)
uiItemL_(layout, name, icon);
}
-/**
- * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where the
- * logic is needed. Ideally, #uiItemFullR() could just call this, but it currently has too many
- * special needs.
- */
uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)
{
uiPropertySplitWrapper split_wrapper = {NULL};
@@ -3251,9 +3234,6 @@ uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)
return split_wrapper;
}
-/*
- * Helper to add a label and creates a property split layout if needed.
- */
uiLayout *uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon)
{
if (layout->item.flag & UI_ITEM_PROP_SEP) {
@@ -3287,7 +3267,6 @@ void uiItemLDrag(uiLayout *layout, PointerRNA *ptr, const char *name, int icon)
}
}
-/* value item */
void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
{
/* label */
@@ -3332,7 +3311,6 @@ void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
}
}
-/* separator item */
void uiItemS_ex(uiLayout *layout, float factor)
{
uiBlock *block = layout->root->block;
@@ -3360,13 +3338,11 @@ void uiItemS_ex(uiLayout *layout, float factor)
"");
}
-/* separator item */
void uiItemS(uiLayout *layout)
{
uiItemS_ex(layout, 1.0f);
}
-/* Flexible spacing. */
void uiItemSpacer(uiLayout *layout)
{
uiBlock *block = layout->root->block;
@@ -3399,7 +3375,6 @@ void uiItemSpacer(uiLayout *layout)
"");
}
-/* level items */
void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg)
{
if (!func) {
@@ -3409,9 +3384,6 @@ void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc
ui_item_menu(layout, name, icon, func, arg, NULL, "", false);
}
-/**
- * Version of #uiItemMenuF that free's `argN`.
- */
void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *argN)
{
if (!func) {
@@ -3423,7 +3395,7 @@ void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc
}
typedef struct MenuItemLevel {
- int opcontext;
+ wmOperatorCallContext opcontext;
/* don't use pointers to the strings because python can dynamically
* allocate strings and free before the menu draws, see T27304. */
char opname[OP_MAX_TYPENAME];
@@ -4720,7 +4692,6 @@ static void ui_layout_heading_set(uiLayout *layout, const char *heading)
}
}
-/* layout create functions */
uiLayout *uiLayoutRow(uiLayout *layout, bool align)
{
uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
@@ -4734,9 +4705,6 @@ uiLayout *uiLayoutRow(uiLayout *layout, bool align)
return litem;
}
-/**
- * See #uiLayoutColumnWithHeading().
- */
uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
{
uiLayout *litem = uiLayoutRow(layout, align);
@@ -4757,12 +4725,6 @@ uiLayout *uiLayoutColumn(uiLayout *layout, bool align)
return litem;
}
-/**
- * Variant of #uiLayoutColumn() that sets a heading label for the layout if the first item is
- * added through #uiItemFullR(). If split layout is used and the item has no string to add to the
- * first split-column, the heading is added there instead. Otherwise the heading inserted with a
- * new row.
- */
uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading)
{
uiLayout *litem = uiLayoutColumn(layout, align);
@@ -4852,11 +4814,6 @@ uiLayout *uiLayoutBox(uiLayout *layout)
return (uiLayout *)ui_layout_box(layout, UI_BTYPE_ROUNDBOX);
}
-/**
- * Check all buttons defined in this layout,
- * and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
- * Needed to handle correctly text colors of active (selected) list item.
- */
void ui_layout_list_set_labels_active(uiLayout *layout)
{
LISTBASE_FOREACH (uiButtonItem *, bitem, &layout->items) {
@@ -5204,11 +5161,6 @@ static bool block_search_filter_tag_buttons(uiBlock *block, const char *search_f
return has_result;
}
-/**
- * Apply property search behavior, setting panel flags and deactivating buttons that don't match.
- *
- * \note Must not be run after #UI_block_layout_resolve.
- */
bool UI_block_apply_search_filter(uiBlock *block, const char *search_filter)
{
if (search_filter == NULL || search_filter[0] == '\0') {
@@ -5599,28 +5551,49 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
ui_button_group_add_but(uiLayoutGetBlock(layout), but);
}
-bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but)
+static uiButtonItem *ui_layout_find_button_item(const uiLayout *layout, const uiBut *but)
{
- ListBase *child_list = layout->child_items_layout ? &layout->child_items_layout->items :
- &layout->items;
+ const ListBase *child_list = layout->child_items_layout ? &layout->child_items_layout->items :
+ &layout->items;
LISTBASE_FOREACH (uiItem *, item, child_list) {
if (item->type == ITEM_BUTTON) {
uiButtonItem *bitem = (uiButtonItem *)item;
- if (bitem->but == old_but_ptr) {
- bitem->but = new_but;
- return true;
+ if (bitem->but == but) {
+ return bitem;
}
}
else {
- if (ui_layout_replace_but_ptr((uiLayout *)item, old_but_ptr, new_but)) {
- return true;
+ uiButtonItem *nested_item = ui_layout_find_button_item((uiLayout *)item, but);
+ if (nested_item) {
+ return nested_item;
}
}
}
- return false;
+ return NULL;
+}
+
+void ui_layout_remove_but(uiLayout *layout, const uiBut *but)
+{
+ uiButtonItem *bitem = ui_layout_find_button_item(layout, but);
+ if (!bitem) {
+ return;
+ }
+
+ BLI_freelinkN(&layout->items, bitem);
+}
+
+bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but)
+{
+ uiButtonItem *bitem = ui_layout_find_button_item(layout, old_but_ptr);
+ if (!bitem) {
+ return false;
+ }
+
+ bitem->but = new_but;
+ return true;
}
void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size)
@@ -5638,7 +5611,7 @@ bool uiLayoutGetFixedSize(uiLayout *layout)
return (layout->item.flag & UI_ITEM_FIXED_SIZE) != 0;
}
-void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
+void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
{
layout->root->opcontext = opcontext;
}
@@ -5649,11 +5622,6 @@ void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
layout->root->argv = argv;
}
-/**
- * Used for property search when the layout process needs to be cancelled in order to avoid
- * computing the locations for buttons, but the layout items created while adding the buttons
- * must still be freed.
- */
void UI_block_layout_free(uiBlock *block)
{
LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
@@ -5693,6 +5661,11 @@ void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
}
}
+bool UI_block_layout_needs_resolving(const uiBlock *block)
+{
+ return !BLI_listbase_is_empty(&block->layouts);
+}
+
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr)
{
uiBlock *block = layout->root->block;
@@ -5725,7 +5698,6 @@ void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but)
}
}
-/* this is a bit of a hack but best keep it in one place at least */
wmOperatorType *UI_but_operatortype_get_from_enum_menu(uiBut *but, PropertyRNA **r_prop)
{
if (r_prop != NULL) {
@@ -5743,7 +5715,6 @@ wmOperatorType *UI_but_operatortype_get_from_enum_menu(uiBut *but, PropertyRNA *
return NULL;
}
-/* this is a bit of a hack but best keep it in one place at least */
MenuType *UI_but_menutype_get(uiBut *but)
{
if (but->menu_create_func == ui_item_menutype_func) {
@@ -5752,7 +5723,6 @@ MenuType *UI_but_menutype_get(uiBut *but)
return NULL;
}
-/* this is a bit of a hack but best keep it in one place at least */
PanelType *UI_but_paneltype_get(uiBut *but)
{
if (but->menu_create_func == ui_item_paneltype_func) {
@@ -5852,9 +5822,6 @@ static void ui_paneltype_draw_impl(bContext *C, PanelType *pt, uiLayout *layout,
}
}
-/**
- * Used for popup panels only.
- */
void UI_paneltype_draw(bContext *C, PanelType *pt, uiLayout *layout)
{
if (layout->context) {
@@ -5975,9 +5942,6 @@ static void ui_layout_introspect_items(DynStr *ds, ListBase *lb)
BLI_dynstr_append(ds, "]");
}
-/**
- * Evaluate layout items as a Python dictionary.
- */
const char *UI_layout_introspect(uiLayout *layout)
{
DynStr *ds = BLI_dynstr_new();
@@ -5997,10 +5961,6 @@ const char *UI_layout_introspect(uiLayout *layout)
/** \name Alert Box with Big Icon
* \{ */
-/**
- * Helper to add a big icon and create a split layout for alert popups.
- * Returns the layout to place further items into the alert box.
- */
uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon)
{
const uiStyle *style = UI_style_get_dpi();
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 7b59a6f7263..f7424066ad8 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -26,7 +26,8 @@
#include "MEM_guardedalloc.h"
#include "DNA_armature_types.h"
-#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
+#include "DNA_modifier_types.h" /* for handling geometry nodes properties */
+#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
#include "DNA_screen_types.h"
#include "DNA_text_types.h"
@@ -846,9 +847,15 @@ bool UI_context_copy_to_selected_list(bContext *C,
else if (RNA_struct_is_a(ptr->type, &RNA_Keyframe)) {
*r_lb = CTX_data_collection_get(C, "selected_editable_keyframes");
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_Action)) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_actions");
+ }
else if (RNA_struct_is_a(ptr->type, &RNA_NlaStrip)) {
*r_lb = CTX_data_collection_get(C, "selected_nla_strips");
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_MovieTrackingTrack)) {
+ *r_lb = CTX_data_collection_get(C, "selected_movieclip_tracks");
+ }
else if (RNA_struct_is_a(ptr->type, &RNA_Constraint) &&
(path_from_bone = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_PoseBone)) !=
NULL) {
@@ -979,6 +986,97 @@ bool UI_context_copy_to_selected_list(bContext *C,
return true;
}
+bool UI_context_copy_to_selected_check(PointerRNA *ptr,
+ PointerRNA *ptr_link,
+ PropertyRNA *prop,
+ const char *path,
+ bool use_path_from_id,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop)
+{
+ PointerRNA idptr;
+ PropertyRNA *lprop;
+ PointerRNA lptr;
+
+ if (ptr_link->data == ptr->data) {
+ return false;
+ }
+
+ if (use_path_from_id) {
+ /* Path relative to ID. */
+ lprop = NULL;
+ RNA_id_pointer_create(ptr_link->owner_id, &idptr);
+ RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
+ }
+ else if (path) {
+ /* Path relative to elements from list. */
+ lprop = NULL;
+ RNA_path_resolve_property(ptr_link, path, &lptr, &lprop);
+ }
+ else {
+ lptr = *ptr_link;
+ lprop = prop;
+ }
+
+ if (lptr.data == ptr->data) {
+ /* temp_ptr might not be the same as ptr_link! */
+ return false;
+ }
+
+ /* Skip non-existing properties on link. This was previously covered with the `lprop != prop`
+ * check but we are now more permissive when it comes to ID properties, see below. */
+ if (lprop == NULL) {
+ return false;
+ }
+
+ if (RNA_property_type(lprop) != RNA_property_type(prop)) {
+ return false;
+ }
+
+ /* Check property pointers matching.
+ * For ID properties, these pointers match:
+ * - If the property is API defined on an existing class (and they are equally named).
+ * - Never for ID properties on specific ID (even if they are equally named).
+ * - Never for NodesModifierSettings properties (even if they are equally named).
+ *
+ * Be permissive on ID properties in the following cases:
+ * - #NodesModifierSettings properties
+ * - (special check: only if the node-group matches, since the 'Input_n' properties are name
+ * based and similar on potentially very different node-groups).
+ * - ID properties on specific ID
+ * - (no special check, copying seems OK [even if type does not match -- does not do anything
+ * then])
+ */
+ bool ignore_prop_eq = RNA_property_is_idprop(lprop) && RNA_property_is_idprop(prop);
+ if (RNA_struct_is_a(lptr.type, &RNA_NodesModifier) &&
+ RNA_struct_is_a(ptr->type, &RNA_NodesModifier)) {
+ ignore_prop_eq = false;
+
+ NodesModifierData *nmd_link = (NodesModifierData *)lptr.data;
+ NodesModifierData *nmd_src = (NodesModifierData *)ptr->data;
+ if (nmd_link->node_group == nmd_src->node_group) {
+ ignore_prop_eq = true;
+ }
+ }
+
+ if ((lprop != prop) && !ignore_prop_eq) {
+ return false;
+ }
+
+ if (!RNA_property_editable(&lptr, lprop)) {
+ return false;
+ }
+
+ if (r_ptr) {
+ *r_ptr = lptr;
+ }
+ if (r_prop) {
+ *r_prop = lprop;
+ }
+
+ return true;
+}
+
/**
* Called from both exec & poll.
*
@@ -989,7 +1087,7 @@ bool UI_context_copy_to_selected_list(bContext *C,
static bool copy_to_selected_button(bContext *C, bool all, bool poll)
{
Main *bmain = CTX_data_main(C);
- PointerRNA ptr, lptr, idptr;
+ PointerRNA ptr, lptr;
PropertyRNA *prop, *lprop;
bool success = false;
int index;
@@ -1019,32 +1117,8 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll)
continue;
}
- if (use_path_from_id) {
- /* Path relative to ID. */
- lprop = NULL;
- RNA_id_pointer_create(link->ptr.owner_id, &idptr);
- RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
- }
- else if (path) {
- /* Path relative to elements from list. */
- lprop = NULL;
- RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
- }
- else {
- lptr = link->ptr;
- lprop = prop;
- }
-
- if (lptr.data == ptr.data) {
- /* lptr might not be the same as link->ptr! */
- continue;
- }
-
- if (lprop != prop) {
- continue;
- }
-
- if (!RNA_property_editable(&lptr, lprop)) {
+ if (!UI_context_copy_to_selected_check(
+ &ptr, &link->ptr, prop, path, use_path_from_id, &lptr, &lprop)) {
continue;
}
@@ -1337,10 +1411,6 @@ void UI_editsource_active_but_test(uiBut *but)
BLI_ghash_insert(ui_editsource_info->hash, but, but_store);
}
-/**
- * Remove the editsource data for \a old_but and reinsert it for \a new_but. Use when the button
- * was reallocated, e.g. to have a new type (#ui_but_change_type()).
- */
void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but)
{
uiEditSourceButStore *but_store = BLI_ghash_lookup(ui_editsource_info->hash, old_but);
@@ -1402,7 +1472,7 @@ static int editsource_exec(bContext *C, wmOperator *op)
int ret;
/* needed else the active button does not get tested */
- UI_screen_free_active_but(C, CTX_wm_screen(C));
+ UI_screen_free_active_but_highlight(C, CTX_wm_screen(C));
// printf("%s: begin\n", __func__);
@@ -1683,8 +1753,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev
bScreen *screen = CTX_wm_screen(C);
const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed");
ARegion *region_prev = CTX_wm_region(C);
- ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->x, event->y) :
- NULL;
+ ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : NULL;
if (region == NULL) {
region = region_prev;
@@ -1860,6 +1929,39 @@ static void UI_OT_drop_color(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Drop Name Operator
+ * \{ */
+
+static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ uiBut *but = UI_but_active_drop_name_button(C);
+ char *str = RNA_string_get_alloc(op->ptr, "string", NULL, 0, NULL);
+
+ if (str) {
+ ui_but_set_string_interactive(C, but, str);
+ MEM_freeN(str);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_drop_name(wmOperatorType *ot)
+{
+ ot->name = "Drop Name";
+ ot->idname = "UI_OT_drop_name";
+ ot->description = "Drop name to button";
+
+ ot->poll = ED_operator_regionactive;
+ ot->invoke = drop_name_invoke;
+ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ RNA_def_string(
+ ot->srna, "string", NULL, 0, "String", "The string value to drop into the button");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name UI List Search Operator
* \{ */
@@ -1918,6 +2020,93 @@ static void UI_OT_list_start_filter(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name UI Tree-View Drop Operator
+ * \{ */
+
+static bool ui_tree_view_drop_poll(bContext *C)
+{
+ const wmWindow *win = CTX_wm_window(C);
+ const ARegion *region = CTX_wm_region(C);
+ const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(
+ region, win->eventstate->xy);
+
+ return hovered_tree_item != NULL;
+}
+
+static int ui_tree_view_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ if (event->custom != EVT_DATA_DRAGDROP) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ }
+
+ const ARegion *region = CTX_wm_region(C);
+ uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region, event->xy);
+
+ if (!UI_tree_view_item_drop_handle(C, hovered_tree_item, event->customdata)) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_tree_view_drop(wmOperatorType *ot)
+{
+ ot->name = "Tree View drop";
+ ot->idname = "UI_OT_tree_view_drop";
+ ot->description = "Drag and drop items onto a tree item";
+
+ ot->invoke = ui_tree_view_drop_invoke;
+ ot->poll = ui_tree_view_drop_poll;
+
+ ot->flag = OPTYPE_INTERNAL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UI Tree-View Item Rename Operator
+ *
+ * General purpose renaming operator for tree-views. Thanks to this, to add a rename button to
+ * context menus for example, tree-view API users don't have to implement own renaming operators
+ * with the same logic as they already have for their #ui::AbstractTreeViewItem::rename() override.
+ *
+ * \{ */
+
+static bool ui_tree_view_item_rename_poll(bContext *C)
+{
+ const ARegion *region = CTX_wm_region(C);
+ const uiTreeViewItemHandle *active_item = UI_block_tree_view_find_active_item(region);
+ return active_item != NULL && UI_tree_view_item_can_rename(active_item);
+}
+
+static int ui_tree_view_item_rename_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ARegion *region = CTX_wm_region(C);
+ uiTreeViewItemHandle *active_item = UI_block_tree_view_find_active_item(region);
+
+ UI_tree_view_item_begin_rename(active_item);
+ ED_region_tag_redraw(region);
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_tree_view_item_rename(wmOperatorType *ot)
+{
+ ot->name = "Rename Tree-View Item";
+ ot->idname = "UI_OT_tree_view_item_rename";
+ ot->description = "Rename the active item in the tree";
+
+ ot->exec = ui_tree_view_item_rename_exec;
+ ot->poll = ui_tree_view_item_rename_poll;
+ /* Could get a custom tooltip via the `get_description()` callback and another overridable
+ * function of the tree-view. */
+
+ ot->flag = OPTYPE_INTERNAL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Operator & Keymap Registration
* \{ */
@@ -1934,6 +2123,7 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_copy_to_selected_button);
WM_operatortype_append(UI_OT_jump_to_target_button);
WM_operatortype_append(UI_OT_drop_color);
+ WM_operatortype_append(UI_OT_drop_name);
#ifdef WITH_PYTHON
WM_operatortype_append(UI_OT_editsource);
WM_operatortype_append(UI_OT_edittranslation_init);
@@ -1944,6 +2134,9 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_list_start_filter);
+ WM_operatortype_append(UI_OT_tree_view_drop);
+ WM_operatortype_append(UI_OT_tree_view_item_rename);
+
/* external */
WM_operatortype_append(UI_OT_eyedropper_color);
WM_operatortype_append(UI_OT_eyedropper_colorramp);
@@ -1954,9 +2147,6 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_eyedropper_gpencil_color);
}
-/**
- * \brief User Interface Keymap
- */
void ED_keymap_ui(wmKeyConfig *keyconf)
{
WM_keymap_ensure(keyconf, "User Interface", 0, 0);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index a64797af24f..135cef5fe53 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -273,10 +273,6 @@ static Panel *panel_add_instanced(ARegion *region,
return panel;
}
-/**
- * Called in situations where panels need to be added dynamically rather than
- * having only one panel corresponding to each #PanelType.
- */
Panel *UI_panel_add_instanced(const bContext *C,
ARegion *region,
ListBase *panels,
@@ -301,10 +297,6 @@ Panel *UI_panel_add_instanced(const bContext *C,
return new_panel;
}
-/**
- * Find a unique key to append to the #PanelType.idname for the lookup to the panel's #uiBlock.
- * Needed for instanced panels, where there can be multiple with the same type and identifier.
- */
void UI_list_panel_unique_str(Panel *panel, char *r_name)
{
/* The panel sort-order will be unique for a specific panel type because the instanced
@@ -334,12 +326,6 @@ static void panel_delete(const bContext *C, ARegion *region, ListBase *panels, P
MEM_freeN(panel);
}
-/**
- * Remove instanced panels from the region's panel list.
- *
- * \note Can be called with NULL \a C, but it should be avoided because
- * handlers might not be removed.
- */
void UI_panels_free_instanced(const bContext *C, ARegion *region)
{
/* Delete panels with the instanced flag. */
@@ -361,15 +347,6 @@ void UI_panels_free_instanced(const bContext *C, ARegion *region)
}
}
-/**
- * Check if the instanced panels in the region's panels correspond to the list of data the panels
- * represent. Returns false if the panels have been reordered or if the types from the list data
- * don't match in any way.
- *
- * \param data: The list of data to check against the instanced panels.
- * \param panel_idname_func: Function to find the #PanelType.idname for each item in the data list.
- * For a readability and generality, this lookup happens separately for each type of panel list.
- */
bool UI_panel_list_matches_data(ARegion *region,
ListBase *data,
uiListPanelIDFromDataFunc panel_idname_func)
@@ -486,8 +463,12 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr
/* Set the bit to tell the interface to instanced the list. */
drag_panel->flag |= PNL_INSTANCED_LIST_ORDER_CHANGED;
+ CTX_store_set(C, drag_panel->runtime.context);
+
/* Finally, move this panel's list item to the new index in its list. */
drag_panel->type->reorder(C, drag_panel, move_to_index);
+
+ CTX_store_set(C, NULL);
}
/**
@@ -697,9 +678,6 @@ Panel *UI_panel_find_by_type(ListBase *lb, const PanelType *pt)
return NULL;
}
-/**
- * \note \a panel should be return value from #UI_panel_find_by_type and can be NULL.
- */
Panel *UI_panel_begin(
ARegion *region, ListBase *lb, uiBlock *block, PanelType *pt, Panel *panel, bool *r_open)
{
@@ -779,11 +757,6 @@ Panel *UI_panel_begin(
return panel;
}
-/**
- * Create the panel header button group, used to mark which buttons are part of
- * panel headers for the panel search process that happens later. This Should be
- * called before adding buttons for the panel's header layout.
- */
void UI_panel_header_buttons_begin(Panel *panel)
{
uiBlock *block = panel->runtime.block;
@@ -791,9 +764,6 @@ void UI_panel_header_buttons_begin(Panel *panel)
ui_block_new_button_group(block, UI_BUTTON_GROUP_LOCK | UI_BUTTON_GROUP_PANEL_HEADER);
}
-/**
- * Finish the button group for the panel header to avoid putting panel body buttons in it.
- */
void UI_panel_header_buttons_end(Panel *panel)
{
uiBlock *block = panel->runtime.block;
@@ -923,10 +893,6 @@ static void panel_matches_search_filter_recursive(const Panel *panel, bool *filt
}
}
-/**
- * Find whether a panel or any of its sub-panels contain a property that matches the search filter,
- * depending on the search process running in #UI_block_apply_search_filter earlier.
- */
bool UI_panel_matches_search_filter(const Panel *panel)
{
bool search_filter_matches = false;
@@ -1018,10 +984,6 @@ static void region_panels_remove_invisible_layouts(ARegion *region)
}
}
-/**
- * Get the panel's expansion state, taking into account
- * expansion set from property search if it applies.
- */
bool UI_panel_is_closed(const Panel *panel)
{
/* Header-less panels can never be closed, otherwise they could disappear. */
@@ -1047,9 +1009,6 @@ bool UI_panel_is_active(const Panel *panel)
/** \name Drawing
* \{ */
-/**
- * Draw panels, selected (panels currently being dragged) on top.
- */
void UI_panels_draw(const bContext *C, ARegion *region)
{
/* Draw in reverse order, because #uiBlocks are added in reverse order
@@ -1071,7 +1030,6 @@ void UI_panels_draw(const bContext *C, ARegion *region)
#define PNL_ICON UI_UNIT_X /* Could be UI_UNIT_Y too. */
-/* For button layout next to label. */
void UI_panel_label_offset(const uiBlock *block, int *r_x, int *r_y)
{
Panel *panel = block->panel;
@@ -1112,23 +1070,15 @@ static void panel_draw_highlight_border(const Panel *panel,
const rcti *rect,
const rcti *header_rect)
{
- const bool draw_box_style = panel->type->flag & PANEL_TYPE_DRAW_BOX;
const bool is_subpanel = panel->type->parent != NULL;
if (is_subpanel) {
return;
}
- float radius;
- if (draw_box_style) {
- /* Use the theme for box widgets. */
- const uiWidgetColors *box_wcol = &UI_GetTheme()->tui.wcol_box;
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- radius = box_wcol->roundness * U.widget_unit;
- }
- else {
- UI_draw_roundbox_corner_set(UI_CNR_NONE);
- radius = 0.0f;
- }
+ const bTheme *btheme = UI_GetTheme();
+ const float aspect = panel->runtime.block->aspect;
+ const float radius = (btheme->tui.panel_roundness * U.widget_unit * 0.5f) / aspect;
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
float color[4];
UI_GetThemeColor4fv(TH_SELECT_ACTIVE, color);
@@ -1172,18 +1122,17 @@ static void panel_draw_aligned_widgets(const uiStyle *style,
/* Draw collapse icon. */
{
- rctf collapse_rect = {
- .xmin = widget_rect.xmin,
- .xmax = widget_rect.xmin + header_height,
- .ymin = widget_rect.ymin,
- .ymax = widget_rect.ymax,
- };
- BLI_rctf_scale(&collapse_rect, 0.25f);
-
- float triangle_color[4];
- rgba_uchar_to_float(triangle_color, title_color);
-
- ui_draw_anti_tria_rect(&collapse_rect, UI_panel_is_closed(panel) ? 'h' : 'v', triangle_color);
+ const float size_y = BLI_rcti_size_y(&widget_rect);
+ GPU_blend(GPU_BLEND_ALPHA);
+ UI_icon_draw_ex(widget_rect.xmin + size_y * 0.2f,
+ widget_rect.ymin + size_y * 0.2f,
+ UI_panel_is_closed(panel) ? ICON_RIGHTARROW : ICON_DOWNARROW_HLT,
+ aspect * U.inv_dpi_fac,
+ 0.7f,
+ 0.0f,
+ title_color,
+ false);
+ GPU_blend(GPU_BLEND_NONE);
}
/* Draw text label. */
@@ -1197,6 +1146,7 @@ static void panel_draw_aligned_widgets(const uiStyle *style,
UI_fontstyle_draw(fontstyle,
&title_rect,
panel->drawname,
+ sizeof(panel->drawname),
title_color,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_LEFT,
@@ -1243,7 +1193,6 @@ static void panel_draw_aligned_backdrop(const Panel *panel,
const rcti *rect,
const rcti *header_rect)
{
- const bool draw_box_style = panel->type->flag & PANEL_TYPE_DRAW_BOX;
const bool is_subpanel = panel->type->parent != NULL;
const bool is_open = !UI_panel_is_closed(panel);
@@ -1251,95 +1200,55 @@ static void panel_draw_aligned_backdrop(const Panel *panel,
return;
}
- const uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- /* Draw with an opaque box backdrop for box style panels. */
- if (draw_box_style) {
- /* Use the theme for box widgets. */
- const uiWidgetColors *box_wcol = &UI_GetTheme()->tui.wcol_box;
-
- if (is_subpanel) {
- /* Use rounded bottom corners for the last subpanel. */
- if (panel->next == NULL) {
- UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
- float color[4];
- UI_GetThemeColor4fv(TH_PANEL_SUB_BACK, color);
- /* Change the width a little bit to line up with sides. */
- UI_draw_roundbox_aa(
- &(const rctf){
- .xmin = rect->xmin + U.pixelsize,
- .xmax = rect->xmax - U.pixelsize,
- .ymin = rect->ymin + U.pixelsize,
- .ymax = rect->ymax,
- },
- true,
- box_wcol->roundness * U.widget_unit,
- color);
- }
- else {
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformThemeColor(TH_PANEL_SUB_BACK);
- immRectf(pos, rect->xmin + U.pixelsize, rect->ymin, rect->xmax - U.pixelsize, rect->ymax);
- immUnbindProgram();
- }
- }
- else {
- /* Expand the top a tiny bit to give header buttons equal size above and below. */
- rcti box_rect = {
- .xmin = rect->xmin,
- .xmax = rect->xmax,
- .ymin = is_open ? rect->ymin : header_rect->ymin,
- .ymax = header_rect->ymax + U.pixelsize,
- };
- ui_draw_box_opaque(&box_rect, UI_CNR_ALL);
-
- /* Mimic the border between aligned box widgets for the bottom of the header. */
- if (is_open) {
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- GPU_blend(GPU_BLEND_ALPHA);
-
- /* Top line. */
- immUniformColor4ubv(box_wcol->outline);
- immRectf(pos, rect->xmin, header_rect->ymin - U.pixelsize, rect->xmax, header_rect->ymin);
-
- /* Bottom "shadow" line. */
- immUniformThemeColor(TH_WIDGET_EMBOSS);
- immRectf(pos,
- rect->xmin,
- header_rect->ymin - U.pixelsize,
- rect->xmax,
- header_rect->ymin - U.pixelsize - 1);
-
- GPU_blend(GPU_BLEND_NONE);
- immUnbindProgram();
- }
- }
- }
- else {
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- GPU_blend(GPU_BLEND_ALPHA);
-
- /* Panel backdrop. */
- if (is_open || panel->type->flag & PANEL_TYPE_NO_HEADER) {
- immUniformThemeColor(is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK);
- immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- }
-
- /* Panel header backdrops for non sub-panels. */
- if (!is_subpanel) {
- immUniformThemeColor(UI_panel_matches_search_filter(panel) ? TH_MATCH : TH_PANEL_HEADER);
- immRectf(pos, rect->xmin, header_rect->ymin, rect->xmax, header_rect->ymax);
- }
+ const bTheme *btheme = UI_GetTheme();
+ const float aspect = panel->runtime.block->aspect;
+ const float radius = btheme->tui.panel_roundness * U.widget_unit * 0.5f / aspect;
- GPU_blend(GPU_BLEND_NONE);
- immUnbindProgram();
- }
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_blend(GPU_BLEND_ALPHA);
+
+ /* Panel backdrop. */
+ if (is_open || panel->type->flag & PANEL_TYPE_NO_HEADER) {
+ float panel_backcolor[4];
+ UI_draw_roundbox_corner_set(is_open ? UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT : UI_CNR_ALL);
+ UI_GetThemeColor4fv((is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK), panel_backcolor);
+
+ UI_draw_roundbox_4fv(
+ &(const rctf){
+ .xmin = rect->xmin,
+ .xmax = rect->xmax,
+ .ymin = rect->ymin,
+ .ymax = rect->ymax,
+ },
+ true,
+ radius,
+ panel_backcolor);
+ }
+
+ /* Panel header backdrops for non sub-panels. */
+ if (!is_subpanel) {
+ float panel_headercolor[4];
+ UI_GetThemeColor4fv(UI_panel_matches_search_filter(panel) ? TH_MATCH : TH_PANEL_HEADER,
+ panel_headercolor);
+ UI_draw_roundbox_corner_set(is_open ? UI_CNR_TOP_RIGHT | UI_CNR_TOP_LEFT : UI_CNR_ALL);
+
+ /* Change the width a little bit to line up with the sides. */
+ UI_draw_roundbox_4fv(
+ &(const rctf){
+ .xmin = rect->xmin,
+ .xmax = rect->xmax,
+ .ymin = header_rect->ymin,
+ .ymax = header_rect->ymax,
+ },
+ true,
+ radius,
+ panel_headercolor);
+ }
+
+ GPU_blend(GPU_BLEND_NONE);
+ immUnbindProgram();
}
-/**
- * Draw a panel integrated in buttons-window, tool/property lists etc.
- */
void ui_draw_aligned_panel(const uiStyle *style,
const uiBlock *block,
const rcti *rect,
@@ -1377,6 +1286,24 @@ void ui_draw_aligned_panel(const uiStyle *style,
}
}
+bool UI_panel_should_show_background(const ARegion *region, const PanelType *panel_type)
+{
+ if (region->alignment == RGN_ALIGN_FLOAT) {
+ return false;
+ }
+
+ if (panel_type && panel_type->flag & PANEL_TYPE_NO_HEADER) {
+ if (region->regiontype == RGN_TYPE_TOOLS) {
+ /* We never want a background around active tools. */
+ return false;
+ }
+ /* Without a header there is no background except for region overlap. */
+ return region->overlap != 0;
+ }
+
+ return true;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1386,9 +1313,6 @@ void ui_draw_aligned_panel(const uiStyle *style,
#define TABS_PADDING_BETWEEN_FACTOR 4.0f
#define TABS_PADDING_TEXT_FACTOR 6.0f
-/**
- * Draw vertical tabs on the left side of the region, one tab per category.
- */
void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
{
// #define USE_FLAT_INACTIVE
@@ -1397,7 +1321,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
const uiStyle *style = UI_style_get();
const uiFontStyle *fstyle = &style->widget;
const int fontid = fstyle->uifont_id;
- short fstyle_points = fstyle->points;
+ float fstyle_points = fstyle->points;
const float aspect = ((uiBlock *)region->uiblocks.first)->aspect;
const float zoom = 1.0f / aspect;
const int px = U.pixelsize;
@@ -1599,7 +1523,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
}
BLF_position(fontid, rct->xmax - text_v_ofs, rct->ymin + tab_v_pad_text, 0.0f);
- BLF_color3ubv(fontid, theme_col_text);
+ BLF_color3ubv(fontid, is_active ? theme_col_text_hi : theme_col_text);
BLF_draw(fontid, category_id_draw, category_draw_len);
GPU_blend(GPU_BLEND_NONE);
@@ -1789,19 +1713,21 @@ static bool uiAlignPanelStep(ARegion *region, const float factor, const bool dra
const int region_offset_x = panel_region_offset_x_get(region);
for (int i = 0; i < active_panels_len; i++) {
PanelSort *ps = &panel_sort[i];
- const bool use_box = ps->panel->type->flag & PANEL_TYPE_DRAW_BOX;
+ const bool show_background = UI_panel_should_show_background(region, ps->panel->type);
ps->panel->runtime.region_ofsx = region_offset_x;
- ps->new_offset_x = region_offset_x + ((use_box) ? UI_PANEL_BOX_STYLE_MARGIN : 0);
+ ps->new_offset_x = region_offset_x + (show_background ? UI_PANEL_MARGIN_X : 0);
}
/* Y offset. */
for (int i = 0, y = 0; i < active_panels_len; i++) {
PanelSort *ps = &panel_sort[i];
+ const bool show_background = UI_panel_should_show_background(region, ps->panel->type);
+
y -= get_panel_real_size_y(ps->panel);
- const bool use_box = ps->panel->type->flag & PANEL_TYPE_DRAW_BOX;
- if (use_box) {
- y -= UI_PANEL_BOX_STYLE_MARGIN;
+ /* Separate panel boxes a bit further (if they are drawn). */
+ if (show_background) {
+ y -= UI_PANEL_MARGIN_Y;
}
ps->new_offset_y = y;
/* The header still draws offset by the size of closed panels, so apply the offset here. */
@@ -1848,6 +1774,7 @@ static void ui_panels_size(ARegion *region, int *r_x, int *r_y)
{
int sizex = 0;
int sizey = 0;
+ bool has_panel_with_background = false;
/* Compute size taken up by panels, for setting in view2d. */
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
@@ -1857,6 +1784,9 @@ static void ui_panels_size(ARegion *region, int *r_x, int *r_y)
sizex = max_ii(sizex, pa_sizex);
sizey = min_ii(sizey, pa_sizey);
+ if (UI_panel_should_show_background(region, panel->type)) {
+ has_panel_with_background = true;
+ }
}
}
@@ -1866,6 +1796,11 @@ static void ui_panels_size(ARegion *region, int *r_x, int *r_y)
if (sizey == 0) {
sizey = -UI_PANEL_WIDTH;
}
+ /* Extra margin after the list so the view scrolls a few pixels further than the panel border.
+ * Also makes the bottom match the top margin. */
+ if (has_panel_with_background) {
+ sizey -= UI_PANEL_MARGIN_Y;
+ }
*r_x = sizex;
*r_y = sizey;
@@ -1978,7 +1913,7 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
ARegion *region = CTX_wm_region(C);
/* Keep the drag position in the region with a small pad to keep the panel visible. */
- const int y = clamp_i(event->y, region->winrct.ymin, region->winrct.ymax + DRAG_REGION_PAD);
+ const int y = clamp_i(event->xy[1], region->winrct.ymin, region->winrct.ymax + DRAG_REGION_PAD);
float dy = (float)(y - data->starty);
@@ -2093,7 +2028,7 @@ static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, voi
switch (event->type) {
case MOUSEMOVE:
- ui_panel_drag_collapse(C, dragcol_data, &event->x);
+ ui_panel_drag_collapse(C, dragcol_data, event->xy);
retval = WM_UI_HANDLER_BREAK;
break;
@@ -2122,7 +2057,7 @@ static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was
uiPanelDragCollapseHandle *dragcol_data = MEM_mallocN(sizeof(*dragcol_data), __func__);
dragcol_data->was_first_open = was_open;
- copy_v2_v2_int(dragcol_data->xy_init, &event->x);
+ copy_v2_v2_int(dragcol_data->xy_init, event->xy);
WM_event_add_ui_handler(C,
&win->modalhandlers,
@@ -2152,7 +2087,7 @@ static void ui_handle_panel_header(const bContext *C,
BLI_assert(!(panel->type->flag & PANEL_TYPE_NO_HEADER));
const bool is_subpanel = (panel->type->parent != NULL);
- const bool use_pin = UI_panel_category_is_visible(region) && !is_subpanel;
+ const bool use_pin = UI_panel_category_is_visible(region) && UI_panel_can_be_pinned(panel);
const bool show_pin = use_pin && (panel->flag & PNL_PIN);
const bool show_drag = !is_subpanel;
@@ -2394,11 +2329,6 @@ static int ui_handle_panel_category_cycling(const wmEvent *event,
return WM_UI_HANDLER_CONTINUE;
}
-/**
- * Handle region panel events like opening and closing panels, changing categories, etc.
- *
- * \note Could become a modal key-map.
- */
int ui_handler_panel_region(bContext *C,
const wmEvent *event,
ARegion *region,
@@ -2415,7 +2345,7 @@ int ui_handler_panel_region(bContext *C,
}
/* Scroll-bars can overlap panels now, they have handling priority. */
- if (UI_view2d_mouse_in_scrollers(region, &region->v2d, event->x, event->y)) {
+ if (UI_view2d_mouse_in_scrollers(region, &region->v2d, event->xy)) {
return WM_UI_HANDLER_CONTINUE;
}
@@ -2458,8 +2388,8 @@ int ui_handler_panel_region(bContext *C,
continue;
}
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(region, block, &mx, &my);
const uiPanelMouseState mouse_state = ui_panel_mouse_state_get(block, panel, mx, my);
@@ -2510,6 +2440,12 @@ static void ui_panel_custom_data_set_recursive(Panel *panel, PointerRNA *custom_
}
}
+void UI_panel_context_pointer_set(Panel *panel, const char *name, PointerRNA *ptr)
+{
+ uiLayoutSetContextPointer(panel->layout, name, ptr);
+ panel->runtime.context = uiLayoutGetContextStore(panel->layout);
+}
+
void UI_panel_custom_data_set(Panel *panel, PointerRNA *custom_data)
{
BLI_assert(panel->type != NULL);
@@ -2537,8 +2473,8 @@ PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wm
continue;
}
- int mx = event->x;
- int my = event->y;
+ int mx = event->xy[0];
+ int my = event->xy[1];
ui_window_to_block(region, block, &mx, &my);
const int mouse_state = ui_panel_mouse_state_get(block, panel, mx, my);
if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) {
@@ -2549,6 +2485,11 @@ PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wm
return NULL;
}
+bool UI_panel_can_be_pinned(const Panel *panel)
+{
+ return (panel->type->parent == NULL) && !(panel->type->flag & PANEL_TYPE_INSTANCED);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2611,8 +2552,8 @@ static void panel_handle_data_ensure(const bContext *C,
data->animtimer = WM_event_add_timer(CTX_wm_manager(C), win, TIMER, ANIMATION_INTERVAL);
data->state = state;
- data->startx = win->eventstate->x;
- data->starty = win->eventstate->y;
+ data->startx = win->eventstate->xy[0];
+ data->starty = win->eventstate->xy[1];
data->startofsx = panel->ofsx;
data->startofsy = panel->ofsy;
data->start_cur_xmin = region->v2d.cur.xmin;
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index 15d1d2f2eec..b486ceb8dca 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -69,15 +69,9 @@ bool ui_but_is_toggle(const uiBut *but)
UI_BTYPE_CHECKBOX,
UI_BTYPE_CHECKBOX_N,
UI_BTYPE_ROW,
- UI_BTYPE_DATASETROW,
UI_BTYPE_TREEROW);
}
-/**
- * Can we mouse over the button or is it hidden/disabled/layout.
- * \note ctrl is kind of a hack currently,
- * so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
- */
bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
{
/* NOTE: #UI_BTYPE_LABEL is included for highlights, this allows drags. */
@@ -104,7 +98,6 @@ bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
return true;
}
-/* file selectors are exempt from utf-8 checks */
bool UI_but_is_utf8(const uiBut *but)
{
if (but->rnaprop) {
@@ -222,14 +215,14 @@ bool ui_but_contains_rect(const uiBut *but, const rctf *rect)
return BLI_rctf_isect(&but->rect, rect, NULL);
}
-bool ui_but_contains_point_px(const uiBut *but, const ARegion *region, int x, int y)
+bool ui_but_contains_point_px(const uiBut *but, const ARegion *region, const int xy[2])
{
uiBlock *block = but->block;
- if (!ui_region_contains_point_px(region, x, y)) {
+ if (!ui_region_contains_point_px(region, xy)) {
return false;
}
- float mx = x, my = y;
+ float mx = xy[0], my = xy[1];
ui_window_to_block_fl(region, block, &mx, &my);
if (but->pie_dir != UI_RADIAL_NONE) {
@@ -247,7 +240,7 @@ bool ui_but_contains_point_px(const uiBut *but, const ARegion *region, int x, in
bool ui_but_contains_point_px_icon(const uiBut *but, ARegion *region, const wmEvent *event)
{
rcti rect;
- int x = event->x, y = event->y;
+ int x = event->xy[0], y = event->xy[1];
ui_window_to_block(region, but->block, &x, &y);
@@ -284,21 +277,19 @@ static uiBut *ui_but_find(const ARegion *region,
return NULL;
}
-/* x and y are only used in case event is NULL... */
uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
- const int x,
- const int y,
+ const int xy[2],
const bool labeledit,
const uiButFindPollFn find_poll,
const void *find_custom_data)
{
uiBut *butover = NULL;
- if (!ui_region_contains_point_px(region, x, y)) {
+ if (!ui_region_contains_point_px(region, xy)) {
return NULL;
}
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
- float mx = x, my = y;
+ float mx = xy[0], my = xy[1];
ui_window_to_block_fl(region, block, &mx, &my);
LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
@@ -333,7 +324,7 @@ uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
uiBut *ui_but_find_mouse_over(const ARegion *region, const wmEvent *event)
{
- return ui_but_find_mouse_over_ex(region, event->x, event->y, event->ctrl != 0, NULL, NULL);
+ return ui_but_find_mouse_over_ex(region, event->xy, event->ctrl != 0, NULL, NULL);
}
uiBut *ui_but_find_rect_over(const struct ARegion *region, const rcti *rect_px)
@@ -374,13 +365,13 @@ uiBut *ui_but_find_rect_over(const struct ARegion *region, const rcti *rect_px)
return butover;
}
-uiBut *ui_list_find_mouse_over_ex(const ARegion *region, int x, int y)
+uiBut *ui_list_find_mouse_over_ex(const ARegion *region, const int xy[2])
{
- if (!ui_region_contains_point_px(region, x, y)) {
+ if (!ui_region_contains_point_px(region, xy)) {
return NULL;
}
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
- float mx = x, my = y;
+ float mx = xy[0], my = xy[1];
ui_window_to_block_fl(region, block, &mx, &my);
LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
if (but->type == UI_BTYPE_LISTBOX && ui_but_contains_pt(but, mx, my)) {
@@ -398,7 +389,7 @@ uiBut *ui_list_find_mouse_over(const ARegion *region, const wmEvent *event)
/* If there is no info about the mouse, just act as if there is nothing underneath it. */
return NULL;
}
- return ui_list_find_mouse_over_ex(region, event->x, event->y);
+ return ui_list_find_mouse_over_ex(region, event->xy);
}
uiList *UI_list_find_mouse_over(const ARegion *region, const wmEvent *event)
@@ -435,9 +426,9 @@ static bool ui_but_is_listrow(const uiBut *but, const void *UNUSED(customdata))
return but->type == UI_BTYPE_LISTROW;
}
-uiBut *ui_list_row_find_mouse_over(const ARegion *region, const int x, const int y)
+uiBut *ui_list_row_find_mouse_over(const ARegion *region, const int xy[2])
{
- return ui_but_find_mouse_over_ex(region, x, y, false, ui_but_is_listrow, NULL);
+ return ui_but_find_mouse_over_ex(region, xy, false, ui_but_is_listrow, NULL);
}
struct ListRowFindIndexData {
@@ -463,6 +454,31 @@ uiBut *ui_list_row_find_from_index(const ARegion *region, const int index, uiBut
return ui_but_find(region, ui_but_is_listrow_at_index, &data);
}
+static bool ui_but_is_treerow(const uiBut *but, const void *UNUSED(customdata))
+{
+ return but->type == UI_BTYPE_TREEROW;
+}
+
+uiBut *ui_tree_row_find_mouse_over(const ARegion *region, const int xy[2])
+{
+ return ui_but_find_mouse_over_ex(region, xy, false, ui_but_is_treerow, NULL);
+}
+
+static bool ui_but_is_active_treerow(const uiBut *but, const void *customdata)
+{
+ if (!ui_but_is_treerow(but, customdata)) {
+ return false;
+ }
+
+ const uiButTreeRow *treerow_but = (const uiButTreeRow *)but;
+ return UI_tree_view_item_is_active(treerow_but->tree_item);
+}
+
+uiBut *ui_tree_row_find_active(const ARegion *region)
+{
+ return ui_but_find(region, ui_but_is_active_treerow, NULL);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -657,12 +673,9 @@ bool UI_block_can_add_separator(const uiBlock *block)
/** \name Block (#uiBlock) Spatial
* \{ */
-uiBlock *ui_block_find_mouse_over_ex(const ARegion *region,
- const int x,
- const int y,
- bool only_clip)
+uiBlock *ui_block_find_mouse_over_ex(const ARegion *region, const int xy[2], bool only_clip)
{
- if (!ui_region_contains_point_px(region, x, y)) {
+ if (!ui_region_contains_point_px(region, xy)) {
return NULL;
}
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
@@ -671,7 +684,7 @@ uiBlock *ui_block_find_mouse_over_ex(const ARegion *region,
continue;
}
}
- float mx = x, my = y;
+ float mx = xy[0], my = xy[1];
ui_window_to_block_fl(region, block, &mx, &my);
if (BLI_rctf_isect_pt(&block->rect, mx, my)) {
return block;
@@ -682,7 +695,7 @@ uiBlock *ui_block_find_mouse_over_ex(const ARegion *region,
uiBlock *ui_block_find_mouse_over(const ARegion *region, const wmEvent *event, bool only_clip)
{
- return ui_block_find_mouse_over_ex(region, event->x, event->y, only_clip);
+ return ui_block_find_mouse_over_ex(region, event->xy, only_clip);
}
/** \} */
@@ -722,11 +735,11 @@ uiBut *ui_region_find_first_but_test_flag(ARegion *region, int flag_include, int
/** \name Region (#ARegion) Spatial
* \{ */
-bool ui_region_contains_point_px(const ARegion *region, int x, int y)
+bool ui_region_contains_point_px(const ARegion *region, const int xy[2])
{
rcti winrct;
ui_region_winrct_get_no_margin(region, &winrct);
- if (!BLI_rcti_isect_pt(&winrct, x, y)) {
+ if (!BLI_rcti_isect_pt_v(&winrct, xy)) {
return false;
}
@@ -737,11 +750,11 @@ bool ui_region_contains_point_px(const ARegion *region, int x, int y)
*/
if (region->v2d.mask.xmin != region->v2d.mask.xmax) {
const View2D *v2d = &region->v2d;
- int mx = x, my = y;
+ int mx = xy[0], my = xy[1];
ui_window_to_region(region, &mx, &my);
if (!BLI_rcti_isect_pt(&v2d->mask, mx, my) ||
- UI_view2d_mouse_in_scrollers(region, &region->v2d, x, y)) {
+ UI_view2d_mouse_in_scrollers(region, &region->v2d, xy)) {
return false;
}
}
@@ -777,15 +790,14 @@ bool ui_region_contains_rect_px(const ARegion *region, const rcti *rect_px)
/** \name Screen (#bScreen) Spatial
* \{ */
-/** Check if the cursor is over any popups. */
-ARegion *ui_screen_region_find_mouse_over_ex(bScreen *screen, int x, int y)
+ARegion *ui_screen_region_find_mouse_over_ex(bScreen *screen, const int xy[2])
{
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
rcti winrct;
ui_region_winrct_get_no_margin(region, &winrct);
- if (BLI_rcti_isect_pt(&winrct, x, y)) {
+ if (BLI_rcti_isect_pt_v(&winrct, xy)) {
return region;
}
}
@@ -794,7 +806,7 @@ ARegion *ui_screen_region_find_mouse_over_ex(bScreen *screen, int x, int y)
ARegion *ui_screen_region_find_mouse_over(bScreen *screen, const wmEvent *event)
{
- return ui_screen_region_find_mouse_over_ex(screen, event->x, event->y);
+ return ui_screen_region_find_mouse_over_ex(screen, event->xy);
}
/** \} */
diff --git a/source/blender/editors/interface/interface_region_color_picker.c b/source/blender/editors/interface/interface_region_color_picker.c
index 48952c4f121..2b167c56186 100644
--- a/source/blender/editors/interface/interface_region_color_picker.c
+++ b/source/blender/editors/interface/interface_region_color_picker.c
@@ -115,8 +115,6 @@ void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3])
}
}
-/* Returns true if the button is for a color with gamma baked in,
- * or if it's a color picker for such a button. */
bool ui_but_is_color_gamma(uiBut *but)
{
if (but->rnaprop) {
@@ -183,7 +181,6 @@ static void ui_color_picker_update_hsv(ColorPicker *cpicker,
cpicker->is_init = true;
}
-/* for picker, while editing hsv */
void ui_but_hsv_set(uiBut *but)
{
float rgb_perceptual[3];
diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c
index b50daa0df21..fc4ce6180c3 100644
--- a/source/blender/editors/interface/interface_region_hud.c
+++ b/source/blender/editors/interface/interface_region_hud.c
@@ -57,6 +57,7 @@
/* -------------------------------------------------------------------- */
/** \name Utilities
* \{ */
+
struct HudRegionData {
short regionid;
};
diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c
index 05aa139e055..677da07d53d 100644
--- a/source/blender/editors/interface/interface_region_menu_pie.c
+++ b/source/blender/editors/interface/interface_region_menu_pie.c
@@ -147,9 +147,9 @@ uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, co
pie->layout = UI_block_layout(
pie->block_radial, UI_LAYOUT_VERTICAL, UI_LAYOUT_PIEMENU, 0, 0, 200, 0, 0, style);
- /* Note event->x/y is where we started dragging in case of KM_CLICK_DRAG. */
- pie->mx = event->x;
- pie->my = event->y;
+ /* NOTE: #wmEvent.xy is where we started dragging in case of #KM_CLICK_DRAG. */
+ pie->mx = event->xy[0];
+ pie->my = event->xy[1];
/* create title button */
if (title[0]) {
@@ -305,8 +305,7 @@ int UI_pie_menu_invoke_from_rna_enum(struct bContext *C,
/** \} */
/* -------------------------------------------------------------------- */
-/**
- * \name Pie Menu Levels
+/** \name Pie Menu Levels
*
* Pie menus can't contain more than 8 items (yet).
* When using #uiItemsFullEnumO, a "More" button is created that calls
@@ -318,7 +317,6 @@ int UI_pie_menu_invoke_from_rna_enum(struct bContext *C,
* Ideally we'd have some way of handling this for all kinds of pie items, but that's tricky.
*
* - Julian (Feb 2016)
- *
* \{ */
typedef struct PieMenuLevelData {
@@ -330,7 +328,7 @@ typedef struct PieMenuLevelData {
wmOperatorType *ot;
const char *propname;
IDProperty *properties;
- int context, flag;
+ wmOperatorCallContext context, flag;
} PieMenuLevelData;
/**
@@ -372,16 +370,13 @@ static void ui_pie_menu_level_invoke(bContext *C, void *argN, void *arg2)
UI_pie_menu_end(C, pie);
}
-/**
- * Set up data for defining a new pie menu level and add button that invokes it.
- */
void ui_pie_menu_level_create(uiBlock *block,
wmOperatorType *ot,
const char *propname,
IDProperty *properties,
const EnumPropertyItem *items,
int totitem,
- int context,
+ wmOperatorCallContext context,
int flag)
{
const int totitem_parent = PIE_MAX_ITEMS - 1;
diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c
index d3c1a97e957..a8980b8b122 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.c
+++ b/source/blender/editors/interface/interface_region_menu_popup.c
@@ -338,8 +338,8 @@ uiPopupBlockHandle *ui_popup_menu_create(
if (!but) {
/* no button to start from, means we are a popup */
- pup->mx = window->eventstate->x;
- pup->my = window->eventstate->y;
+ pup->mx = window->eventstate->xy[0];
+ pup->my = window->eventstate->xy[1];
pup->popup = true;
pup->block->flag |= UI_BLOCK_NO_FLIP;
}
@@ -384,10 +384,6 @@ uiPopupBlockHandle *ui_popup_menu_create(
/** \name Popup Menu API with begin & end
* \{ */
-/**
- * Only return handler, and set optional title.
- * \param block_name: Assigned to uiBlock.name (useful info for debugging).
- */
uiPopupMenu *UI_popup_menu_begin_ex(bContext *C,
const char *title,
const char *block_name,
@@ -450,16 +446,12 @@ uiPopupMenu *UI_popup_menu_begin(bContext *C, const char *title, int icon)
return UI_popup_menu_begin_ex(C, title, __func__, icon);
}
-/**
- * Setting the button makes the popup open from the button instead of the cursor.
- */
void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *but)
{
pup->but = but;
pup->butregion = butregion;
}
-/* set the whole structure to work */
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
{
wmWindow *window = CTX_wm_window(C);
@@ -468,8 +460,8 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
ARegion *butregion = NULL;
pup->popup = true;
- pup->mx = window->eventstate->x;
- pup->my = window->eventstate->y;
+ pup->mx = window->eventstate->xy[0];
+ pup->my = window->eventstate->xy[1];
if (pup->but) {
but = pup->but;
@@ -640,7 +632,7 @@ void UI_popup_block_ex(bContext *C,
}
#if 0 /* UNUSED */
-void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, int opcontext)
+void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, wmOperatorCallContext opcontext)
{
wmWindow *window = CTX_wm_window(C);
uiPopupBlockHandle *handle;
diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c
index f8f19c2e43d..1bb589d99fb 100644
--- a/source/blender/editors/interface/interface_region_popover.c
+++ b/source/blender/editors/interface/interface_region_popover.c
@@ -90,7 +90,7 @@ struct uiPopover {
#endif
};
-static void ui_popover_create_block(bContext *C, uiPopover *pup, int opcontext)
+static void ui_popover_create_block(bContext *C, uiPopover *pup, wmOperatorCallContext opcontext)
{
BLI_assert(pup->ui_size_x != 0);
@@ -340,12 +340,6 @@ int UI_popover_panel_invoke(bContext *C, const char *idname, bool keep_open, Rep
/** \name Popup Menu API with begin & end
* \{ */
-/**
- * Only return handler, and set optional title.
- *
- * \param from_active_button: Use the active button for positioning,
- * use when the popover is activated from an operator instead of directly from the button.
- */
uiPopover *UI_popover_begin(bContext *C, int ui_menu_width, bool from_active_button)
{
uiPopover *pup = MEM_callocN(sizeof(uiPopover), "popover menu");
@@ -383,7 +377,6 @@ static void popover_keymap_fn(wmKeyMap *UNUSED(keymap), wmKeyMapItem *UNUSED(kmi
pup->block->handle->menuretval = UI_RETURN_OK;
}
-/* set the whole structure to work */
void UI_popover_end(bContext *C, uiPopover *pup, wmKeyMap *keymap)
{
wmWindow *window = CTX_wm_window(C);
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c
index 55a162c883a..33ce47b281b 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -53,9 +53,6 @@
/** \name Utility Functions
* \{ */
-/**
- * Translate any popup regions (so we can drag them).
- */
void ui_popup_translate(ARegion *region, const int mdiff[2])
{
BLI_rcti_translate(&region->winrct, UNPACK2(mdiff));
@@ -184,10 +181,10 @@ static void ui_popup_block_position(wmWindow *window,
dir1 &= (UI_DIR_UP | UI_DIR_DOWN);
}
- if ((dir2 == 0) && (dir1 == UI_DIR_LEFT || dir1 == UI_DIR_RIGHT)) {
+ if ((dir2 == 0) && (ELEM(dir1, UI_DIR_LEFT, UI_DIR_RIGHT))) {
dir2 = UI_DIR_DOWN;
}
- if ((dir2 == 0) && (dir1 == UI_DIR_UP || dir1 == UI_DIR_DOWN)) {
+ if ((dir2 == 0) && (ELEM(dir1, UI_DIR_UP, UI_DIR_DOWN))) {
dir2 = UI_DIR_LEFT;
}
@@ -554,9 +551,6 @@ static void ui_popup_block_remove(bContext *C, uiPopupBlockHandle *handle)
}
}
-/**
- * Called for creating new popups and refreshing existing ones.
- */
uiBlock *ui_popup_block_refresh(bContext *C,
uiPopupBlockHandle *handle,
ARegion *butregion,
@@ -743,7 +737,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
if (block_old) {
block->oldblock = block_old;
UI_block_update_from_old(C, block);
- UI_blocklist_free_inactive(C, &region->uiblocks);
+ UI_blocklist_free_inactive(C, region);
}
/* checks which buttons are visible, sets flags to prevent draw (do after region init) */
@@ -803,7 +797,7 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C,
handle->popup_create_vars.arg_free = arg_free;
handle->popup_create_vars.but = but;
handle->popup_create_vars.butregion = but ? butregion : NULL;
- copy_v2_v2_int(handle->popup_create_vars.event_xy, &window->eventstate->x);
+ copy_v2_v2_int(handle->popup_create_vars.event_xy, window->eventstate->xy);
/* don't allow by default, only if popup type explicitly supports it */
handle->can_refresh = false;
diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.cc
index c863b1f8bdf..e27dd2a7981 100644
--- a/source/blender/editors/interface/interface_region_search.c
+++ b/source/blender/editors/interface/interface_region_search.cc
@@ -23,9 +23,9 @@
* Search Box Region & Interaction
*/
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cstdarg>
+#include <cstdlib>
+#include <cstring>
#include "DNA_ID.h"
#include "MEM_guardedalloc.h"
@@ -84,7 +84,7 @@ struct uiSearchItems {
void *active;
};
-typedef struct uiSearchboxData {
+struct uiSearchboxData {
rcti bbox;
uiFontStyle fstyle;
uiSearchItems items;
@@ -102,21 +102,10 @@ typedef struct uiSearchboxData {
* Used so we can show leading text to menu items less prominently (not related to 'use_sep').
*/
const char *sep_string;
-} uiSearchboxData;
+};
#define SEARCH_ITEMS 10
-/**
- * Public function exported for functions that use #UI_BTYPE_SEARCH_MENU.
- *
- * \param items: Stores the items.
- * \param name: Text to display for the item.
- * \param poin: Opaque pointer (for use by the caller).
- * \param iconid: The icon, #ICON_NONE for no icon.
- * \param state: The buttons state flag, compatible with #uiBut.flag,
- * typically #UI_BUT_DISABLED / #UI_BUT_INACTIVE.
- * \return false if there is nothing to add.
- */
bool UI_search_item_add(uiSearchItems *items,
const char *name,
void *poin,
@@ -126,7 +115,7 @@ bool UI_search_item_add(uiSearchItems *items,
{
/* hijack for autocomplete */
if (items->autocpl) {
- UI_autocomplete_update_name(items->autocpl, name);
+ UI_autocomplete_update_name(items->autocpl, name + name_prefix_offset);
return true;
}
@@ -166,9 +155,9 @@ bool UI_search_item_add(uiSearchItems *items,
if (name_prefix_offset != 0) {
/* Lazy initialize, as this isn't used often. */
- if (items->name_prefix_offsets == NULL) {
- items->name_prefix_offsets = MEM_callocN(
- items->maxitem * sizeof(*items->name_prefix_offsets), "search name prefix offsets");
+ if (items->name_prefix_offsets == nullptr) {
+ items->name_prefix_offsets = (uint8_t *)MEM_callocN(
+ items->maxitem * sizeof(*items->name_prefix_offsets), __func__);
}
items->name_prefix_offsets[items->totitem] = name_prefix_offset;
}
@@ -186,19 +175,19 @@ bool UI_search_item_add(uiSearchItems *items,
return true;
}
-int UI_searchbox_size_y(void)
+int UI_searchbox_size_y()
{
return SEARCH_ITEMS * UI_UNIT_Y + 2 * UI_POPUP_MENU_TOP;
}
-int UI_searchbox_size_x(void)
+int UI_searchbox_size_x()
{
return 12 * UI_UNIT_X;
}
int UI_search_items_find_index(uiSearchItems *items, const char *name)
{
- if (items->name_prefix_offsets != NULL) {
+ if (items->name_prefix_offsets != nullptr) {
for (int i = 0; i < items->totitem; i++) {
if (STREQ(name, items->names[i] + items->name_prefix_offsets[i])) {
return i;
@@ -218,7 +207,7 @@ int UI_search_items_find_index(uiSearchItems *items, const char *name)
/* region is the search box itself */
static void ui_searchbox_select(bContext *C, ARegion *region, uiBut *but, int step)
{
- uiSearchboxData *data = region->regiondata;
+ uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata);
/* apply step */
data->active += step;
@@ -285,27 +274,25 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr
int ui_searchbox_find_index(ARegion *region, const char *name)
{
- uiSearchboxData *data = region->regiondata;
+ uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata);
return UI_search_items_find_index(&data->items, name);
}
-/* x and y in screen-coords. */
-bool ui_searchbox_inside(ARegion *region, int x, int y)
+bool ui_searchbox_inside(ARegion *region, const int xy[2])
{
- uiSearchboxData *data = region->regiondata;
+ uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata);
- return BLI_rcti_isect_pt(&data->bbox, x - region->winrct.xmin, y - region->winrct.ymin);
+ return BLI_rcti_isect_pt(&data->bbox, xy[0] - region->winrct.xmin, xy[1] - region->winrct.ymin);
}
-/* string validated to be of correct length (but->hardmax) */
bool ui_searchbox_apply(uiBut *but, ARegion *region)
{
- uiSearchboxData *data = region->regiondata;
+ uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata);
uiButSearch *search_but = (uiButSearch *)but;
BLI_assert(but->type == UI_BTYPE_SEARCH_MENU);
- search_but->item_active = NULL;
+ search_but->item_active = nullptr;
if (data->active != -1) {
const char *name = data->items.names[data->active] +
@@ -314,21 +301,18 @@ bool ui_searchbox_apply(uiBut *but, ARegion *region)
data->items.name_prefix_offsets[data->active] :
0);
- const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : NULL;
+ const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : nullptr;
- BLI_strncpy(but->editstr, name, name_sep ? (name_sep - name) + 1 : data->items.maxstrlen);
+ /* Search button with dynamic string properties may have their own method of applying
+ * the search results, so only copy the result if there is a proper space for it. */
+ if (but->hardmax != 0) {
+ BLI_strncpy(but->editstr, name, name_sep ? (name_sep - name) + 1 : data->items.maxstrlen);
+ }
search_but->item_active = data->items.pointers[data->active];
return true;
}
- if (but->flag & UI_BUT_VALUE_CLEAR) {
- /* It is valid for _VALUE_CLEAR flavor to have no active element
- * (it's a valid way to unlink). */
- but->editstr[0] = '\0';
-
- return true;
- }
return false;
}
@@ -352,7 +336,7 @@ static struct ARegion *wm_searchbox_tooltip_init(struct bContext *C,
}
ARegion *searchbox_region = UI_region_searchbox_region_get(region);
- uiSearchboxData *data = searchbox_region->regiondata;
+ uiSearchboxData *data = static_cast<uiSearchboxData *>(searchbox_region->regiondata);
BLI_assert(data->items.pointers[data->active] == search_but->item_active);
@@ -363,13 +347,13 @@ static struct ARegion *wm_searchbox_tooltip_init(struct bContext *C,
C, region, &rect, search_but->arg, search_but->item_active);
}
}
- return NULL;
+ return nullptr;
}
bool ui_searchbox_event(
bContext *C, ARegion *region, uiBut *but, ARegion *butregion, const wmEvent *event)
{
- uiSearchboxData *data = region->regiondata;
+ uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata);
uiButSearch *search_but = (uiButSearch *)but;
int type = event->type, val = event->val;
bool handled = false;
@@ -400,8 +384,9 @@ bool ui_searchbox_event(
* (a little confusing if this isn't the case, although it does work). */
rcti rect;
ui_searchbox_butrect(&rect, data, data->active);
- if (BLI_rcti_isect_pt(
- &rect, event->x - region->winrct.xmin, event->y - region->winrct.ymin)) {
+ if (BLI_rcti_isect_pt(&rect,
+ event->xy[0] - region->winrct.xmin,
+ event->xy[1] - region->winrct.ymin)) {
void *active = data->items.pointers[data->active];
if (search_but->item_context_menu_fn(C, search_but->arg, active, event)) {
@@ -415,14 +400,14 @@ bool ui_searchbox_event(
case MOUSEMOVE: {
bool is_inside = false;
- if (BLI_rcti_isect_pt(&region->winrct, event->x, event->y)) {
+ if (BLI_rcti_isect_pt(&region->winrct, event->xy[0], event->xy[1])) {
rcti rect;
int a;
for (a = 0; a < data->items.totitem; a++) {
ui_searchbox_butrect(&rect, data, a);
if (BLI_rcti_isect_pt(
- &rect, event->x - region->winrct.xmin, event->y - region->winrct.ymin)) {
+ &rect, event->xy[0] - region->winrct.xmin, event->xy[1] - region->winrct.ymin)) {
is_inside = true;
if (data->active != a) {
data->active = a;
@@ -472,11 +457,10 @@ static void ui_searchbox_update_fn(bContext *C,
search_but->items_update_fn(C, search_but->arg, str, items, is_first_search);
}
-/* region is the search box itself */
void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool reset)
{
uiButSearch *search_but = (uiButSearch *)but;
- uiSearchboxData *data = region->regiondata;
+ uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata);
BLI_assert(but->type == UI_BTYPE_SEARCH_MENU);
@@ -494,7 +478,7 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re
if (search_but->items_update_fn && search_but->item_active) {
data->items.active = search_but->item_active;
ui_searchbox_update_fn(C, search_but, but->editstr, &data->items);
- data->items.active = NULL;
+ data->items.active = nullptr;
/* found active item, calculate real offset by centering it */
if (data->items.totitem) {
@@ -528,14 +512,12 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re
/* handle case where editstr is equal to one of items */
if (reset && data->active == -1) {
- int a;
-
- for (a = 0; a < data->items.totitem; a++) {
+ for (int a = 0; a < data->items.totitem; a++) {
const char *name = data->items.names[a] +
/* Never include the prefix in the button. */
(data->items.name_prefix_offsets ? data->items.name_prefix_offsets[a] :
0);
- const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : NULL;
+ const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : nullptr;
if (STREQLEN(but->editstr, name, name_sep ? (name_sep - name) : data->items.maxstrlen)) {
data->active = a;
break;
@@ -555,7 +537,7 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re
int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *str)
{
uiButSearch *search_but = (uiButSearch *)but;
- uiSearchboxData *data = region->regiondata;
+ uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata);
int match = AUTOCOMPLETE_NO_MATCH;
BLI_assert(but->type == UI_BTYPE_SEARCH_MENU);
@@ -566,15 +548,15 @@ int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *st
ui_searchbox_update_fn(C, search_but, but->editstr, &data->items);
match = UI_autocomplete_end(data->items.autocpl, str);
- data->items.autocpl = NULL;
+ data->items.autocpl = nullptr;
}
return match;
}
-static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region)
+static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region)
{
- uiSearchboxData *data = region->regiondata;
+ uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata);
/* pixel space */
wmOrtho2_region_pixelspace(region);
@@ -586,11 +568,10 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region)
/* draw text */
if (data->items.totitem) {
rcti rect;
- int a;
if (data->preview) {
/* draw items */
- for (a = 0; a < data->items.totitem; a++) {
+ for (int a = 0; a < data->items.totitem; a++) {
const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a];
/* ensure icon is up-to-date */
@@ -624,11 +605,11 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region)
else {
const int search_sep_len = data->sep_string ? strlen(data->sep_string) : 0;
/* draw items */
- for (a = 0; a < data->items.totitem; a++) {
+ for (int a = 0; a < data->items.totitem; a++) {
const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a];
char *name = data->items.names[a];
int icon = data->items.icons[a];
- char *name_sep_test = NULL;
+ char *name_sep_test = nullptr;
uiMenuItemSeparatorType separator_type = UI_MENU_ITEM_SEPARATOR_NONE;
if (data->use_shortcut_sep) {
@@ -650,15 +631,15 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region)
}
/* Simple menu item. */
- ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, separator_type, NULL);
+ ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, separator_type, nullptr);
}
else {
/* Split menu item, faded text before the separator. */
- char *name_sep = NULL;
+ char *name_sep = nullptr;
do {
name_sep = name_sep_test;
name_sep_test = strstr(name_sep + search_sep_len, data->sep_string);
- } while (name_sep_test != NULL);
+ } while (name_sep_test != nullptr);
name_sep += search_sep_len;
const char name_sep_prev = *name_sep;
@@ -681,7 +662,7 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region)
}
/* The previous menu item draws the active selection. */
- ui_draw_menu_item(&data->fstyle, &rect, name_sep, icon, state, separator_type, NULL);
+ ui_draw_menu_item(&data->fstyle, &rect, name_sep, icon, state, separator_type, nullptr);
}
}
/* indicate more */
@@ -701,13 +682,12 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region)
}
}
-static void ui_searchbox_region_free_cb(ARegion *region)
+static void ui_searchbox_region_free_fn(ARegion *region)
{
- uiSearchboxData *data = region->regiondata;
- int a;
+ uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata);
/* free search data */
- for (a = 0; a < data->items.maxitem; a++) {
+ for (int a = 0; a < data->items.maxitem; a++) {
MEM_freeN(data->items.names[a]);
}
MEM_freeN(data->items.names);
@@ -715,12 +695,12 @@ static void ui_searchbox_region_free_cb(ARegion *region)
MEM_freeN(data->items.icons);
MEM_freeN(data->items.states);
- if (data->items.name_prefix_offsets != NULL) {
+ if (data->items.name_prefix_offsets != nullptr) {
MEM_freeN(data->items.name_prefix_offsets);
}
MEM_freeN(data);
- region->regiondata = NULL;
+ region->regiondata = nullptr;
}
static ARegion *ui_searchbox_create_generic_ex(bContext *C,
@@ -739,13 +719,13 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C,
static ARegionType type;
memset(&type, 0, sizeof(ARegionType));
- type.draw = ui_searchbox_region_draw_cb;
- type.free = ui_searchbox_region_free_cb;
+ type.draw = ui_searchbox_region_draw_fn;
+ type.free = ui_searchbox_region_free_fn;
type.regionid = RGN_TYPE_TEMPORARY;
region->type = &type;
/* create searchbox data */
- uiSearchboxData *data = MEM_callocN(sizeof(uiSearchboxData), "uiSearchboxData");
+ uiSearchboxData *data = MEM_cnew<uiSearchboxData>(__func__);
/* set font, get bb */
data->fstyle = style->widget; /* copy struct */
@@ -766,7 +746,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C,
data->prv_cols = but->a2;
}
- if (but->optype != NULL || use_shortcut_sep) {
+ if (but->optype != nullptr || use_shortcut_sep) {
data->use_shortcut_sep = true;
}
data->sep_string = search_but->item_sep_string;
@@ -877,15 +857,16 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C,
else {
data->items.maxitem = SEARCH_ITEMS;
}
- data->items.maxstrlen = but->hardmax;
+ /* In case the button's string is dynamic, make sure there are buffers available. */
+ data->items.maxstrlen = but->hardmax == 0 ? UI_MAX_NAME_STR : but->hardmax;
data->items.totitem = 0;
- data->items.names = MEM_callocN(data->items.maxitem * sizeof(void *), "search names");
- data->items.pointers = MEM_callocN(data->items.maxitem * sizeof(void *), "search pointers");
- data->items.icons = MEM_callocN(data->items.maxitem * sizeof(int), "search icons");
- data->items.states = MEM_callocN(data->items.maxitem * sizeof(int), "search flags");
- data->items.name_prefix_offsets = NULL; /* Lazy initialized as needed. */
+ data->items.names = (char **)MEM_callocN(data->items.maxitem * sizeof(void *), __func__);
+ data->items.pointers = (void **)MEM_callocN(data->items.maxitem * sizeof(void *), __func__);
+ data->items.icons = (int *)MEM_callocN(data->items.maxitem * sizeof(int), __func__);
+ data->items.states = (int *)MEM_callocN(data->items.maxitem * sizeof(int), __func__);
+ data->items.name_prefix_offsets = nullptr; /* Lazy initialized as needed. */
for (int i = 0; i < data->items.maxitem; i++) {
- data->items.names[i] = MEM_callocN(but->hardmax + 1, "search pointers");
+ data->items.names[i] = (char *)MEM_callocN(data->items.maxstrlen + 1, __func__);
}
return region;
@@ -904,10 +885,9 @@ ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiButSearc
*/
static void str_tolower_titlecaps_ascii(char *str, const size_t len)
{
- size_t i;
bool prev_delim = true;
- for (i = 0; (i < len) && str[i]; i++) {
+ for (size_t i = 0; (i < len) && str[i]; i++) {
if (str[i] >= 'A' && str[i] <= 'Z') {
if (prev_delim == false) {
str[i] += 'a' - 'A';
@@ -923,7 +903,7 @@ static void str_tolower_titlecaps_ascii(char *str, const size_t len)
static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARegion *region)
{
- uiSearchboxData *data = region->regiondata;
+ uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata);
/* pixel space */
wmOrtho2_region_pixelspace(region);
@@ -935,10 +915,9 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
/* draw text */
if (data->items.totitem) {
rcti rect;
- int a;
/* draw items */
- for (a = 0; a < data->items.totitem; a++) {
+ for (int a = 0; a < data->items.totitem; a++) {
rcti rect_pre, rect_post;
ui_searchbox_butrect(&rect, data, a);
@@ -952,10 +931,10 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
{
const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a];
- wmOperatorType *ot = data->items.pointers[a];
+ wmOperatorType *ot = static_cast<wmOperatorType *>(data->items.pointers[a]);
char text_pre[128];
- char *text_pre_p = strstr(ot->idname, "_OT_");
- if (text_pre_p == NULL) {
+ const char *text_pre_p = strstr(ot->idname, "_OT_");
+ if (text_pre_p == nullptr) {
text_pre[0] = '\0';
}
else {
@@ -975,7 +954,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
data->items.icons[a],
state,
UI_MENU_ITEM_SEPARATOR_NONE,
- NULL);
+ nullptr);
ui_draw_menu_item(&data->fstyle,
&rect_post,
data->items.names[a],
@@ -983,7 +962,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
state,
data->use_shortcut_sep ? UI_MENU_ITEM_SEPARATOR_SHORTCUT :
UI_MENU_ITEM_SEPARATOR_NONE,
- NULL);
+ nullptr);
}
}
/* indicate more */
@@ -1032,13 +1011,9 @@ ARegion *ui_searchbox_create_menu(bContext *C, ARegion *butregion, uiButSearch *
return region;
}
-/* sets red alert if button holds a string it can't find */
-/* XXX weak: search_func adds all partial matches... */
void ui_but_search_refresh(uiButSearch *search_but)
{
uiBut *but = &search_but->but;
- uiSearchItems *items;
- int x1;
/* possibly very large lists (such as ID datablocks) only
* only validate string RNA buts (not pointers) */
@@ -1046,17 +1021,17 @@ void ui_but_search_refresh(uiButSearch *search_but)
return;
}
- items = MEM_callocN(sizeof(uiSearchItems), "search items");
+ uiSearchItems *items = MEM_cnew<uiSearchItems>(__func__);
/* setup search struct */
items->maxitem = 10;
items->maxstrlen = 256;
- items->names = MEM_callocN(items->maxitem * sizeof(void *), "search names");
- for (x1 = 0; x1 < items->maxitem; x1++) {
- items->names[x1] = MEM_callocN(but->hardmax + 1, "search names");
+ items->names = (char **)MEM_callocN(items->maxitem * sizeof(void *), __func__);
+ for (int i = 0; i < items->maxitem; i++) {
+ items->names[i] = (char *)MEM_callocN(but->hardmax + 1, __func__);
}
- ui_searchbox_update_fn(but->block->evil_C, search_but, but->drawstr, items);
+ ui_searchbox_update_fn((bContext *)but->block->evil_C, search_but, but->drawstr, items);
if (!search_but->results_are_suggestions) {
/* Only red-alert when we are sure of it, this can miss cases when >10 matches. */
@@ -1070,8 +1045,8 @@ void ui_but_search_refresh(uiButSearch *search_but)
}
}
- for (x1 = 0; x1 < items->maxitem; x1++) {
- MEM_freeN(items->names[x1]);
+ for (int i = 0; i < items->maxitem; i++) {
+ MEM_freeN(items->names[i]);
}
MEM_freeN(items->names);
MEM_freeN(items);
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index a8f289702f8..fe58a6a05ae 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -74,6 +74,8 @@
#define UI_TIP_PADDING (int)(UI_TIP_PAD_FAC * UI_UNIT_Y)
#define UI_TIP_MAXWIDTH 600
+#define UI_TIP_STR_MAX 1024
+
typedef struct uiTooltipFormat {
enum {
UI_TIP_STYLE_NORMAL = 0,
@@ -214,7 +216,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
/* draw header and active data (is done here to be able to change color) */
rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_MAIN]);
UI_fontstyle_set(&data->fstyle);
- UI_fontstyle_draw(&data->fstyle, &bbox, field->text, drawcol, &fs_params);
+ UI_fontstyle_draw(&data->fstyle, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params);
/* offset to the end of the last line */
if (field->text_suffix) {
@@ -224,7 +226,8 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
bbox.ymax -= yofs;
rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_ACTIVE]);
- UI_fontstyle_draw(&data->fstyle, &bbox, field->text_suffix, drawcol, &fs_params);
+ UI_fontstyle_draw(
+ &data->fstyle, &bbox, field->text_suffix, UI_TIP_STR_MAX, drawcol, &fs_params);
/* undo offset */
bbox.xmin -= xofs;
@@ -243,7 +246,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
/* XXX, needed because we don't have mono in 'U.uifonts' */
BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * U.pixelsize, U.dpi);
rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]);
- UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, drawcol, &fs_params);
+ UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params);
}
else {
BLI_assert(field->format.style == UI_TIP_STYLE_NORMAL);
@@ -255,7 +258,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
/* draw remaining data */
rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]);
UI_fontstyle_set(&data->fstyle);
- UI_fontstyle_draw(&data->fstyle, &bbox, field->text, drawcol, &fs_params);
+ UI_fontstyle_draw(&data->fstyle, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params);
}
bbox.ymax -= data->lineh * field->geom.lines;
@@ -761,7 +764,9 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
return data;
}
-static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
+static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
+ uiBut *but,
+ uiButExtraOpIcon *extra_icon)
{
uiStringInfo but_label = {BUT_GET_LABEL, NULL};
uiStringInfo but_tip = {BUT_GET_TIP, NULL};
@@ -774,20 +779,29 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
char buf[512];
+ wmOperatorType *optype = extra_icon ? UI_but_extra_operator_icon_optype_get(extra_icon) :
+ but->optype;
+ PropertyRNA *rnaprop = extra_icon ? NULL : but->rnaprop;
+
/* create tooltip data */
uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
- UI_but_string_info_get(C,
- but,
- &but_label,
- &but_tip,
- &enum_label,
- &enum_tip,
- &op_keymap,
- &prop_keymap,
- &rna_struct,
- &rna_prop,
- NULL);
+ if (extra_icon) {
+ UI_but_extra_icon_string_info_get(C, extra_icon, &but_label, &but_tip, &op_keymap, NULL);
+ }
+ else {
+ UI_but_string_info_get(C,
+ but,
+ &but_label,
+ &but_tip,
+ &enum_label,
+ &enum_tip,
+ &op_keymap,
+ &prop_keymap,
+ &rna_struct,
+ &rna_prop,
+ NULL);
+ }
/* Tip Label (only for buttons not already showing the label).
* Check prefix instead of comparing because the button may include the shortcut. */
@@ -818,8 +832,7 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
}
/* special case enum rna buttons */
- if ((but->type & UI_BTYPE_ROW) && but->rnaprop &&
- RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG) {
+ if ((but->type & UI_BTYPE_ROW) && rnaprop && RNA_property_flag(rnaprop) & PROP_ENUM_FLAG) {
uiTooltipField *field = text_field_add(data,
&(uiTooltipFormat){
.style = UI_TIP_STYLE_NORMAL,
@@ -863,7 +876,7 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
/* better not show the value of a password */
- if ((but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD)) == 0) {
+ if ((rnaprop && (RNA_property_subtype(rnaprop) == PROP_PASSWORD)) == 0) {
/* full string */
ui_but_string_get(but, buf, sizeof(buf));
if (buf[0]) {
@@ -878,15 +891,14 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
}
}
- if (but->rnaprop) {
+ if (rnaprop) {
const int unit_type = UI_but_unit_type_get(but);
if (unit_type == PROP_UNIT_ROTATION) {
- if (RNA_property_type(but->rnaprop) == PROP_FLOAT) {
- float value = RNA_property_array_check(but->rnaprop) ?
- RNA_property_float_get_index(
- &but->rnapoin, but->rnaprop, but->rnaindex) :
- RNA_property_float_get(&but->rnapoin, but->rnaprop);
+ if (RNA_property_type(rnaprop) == PROP_FLOAT) {
+ float value = RNA_property_array_check(rnaprop) ?
+ RNA_property_float_get_index(&but->rnapoin, rnaprop, but->rnaindex) :
+ RNA_property_float_get(&but->rnapoin, rnaprop);
uiTooltipField *field = text_field_add(data,
&(uiTooltipFormat){
@@ -920,15 +932,15 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
}
}
}
- else if (but->optype) {
- PointerRNA *opptr;
- char *str;
- opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */
+ else if (optype) {
+ PointerRNA *opptr = extra_icon ? UI_but_extra_operator_icon_opptr_get(extra_icon) :
+ /* allocated when needed, the button owns it */
+ UI_but_operator_ptr_get(but);
/* so the context is passed to fieldf functions (some py fieldf functions use it) */
WM_operator_properties_sanitize(opptr, false);
- str = ui_tooltip_text_python_from_op(C, but->optype, opptr);
+ char *str = ui_tooltip_text_python_from_op(C, optype, opptr);
/* operator info */
if (U.flag & USER_TOOLTIPS_PYTHON) {
@@ -945,18 +957,21 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
}
/* button is disabled, we may be able to tell user why */
- if (but->flag & UI_BUT_DISABLED) {
+ if ((but->flag & UI_BUT_DISABLED) || extra_icon) {
const char *disabled_msg = NULL;
bool disabled_msg_free = false;
/* if operator poll check failed, it can give pretty precise info why */
- if (but->optype) {
+ if (optype) {
+ const wmOperatorCallContext opcontext = extra_icon ? extra_icon->optype_params->opcontext :
+ but->opcontext;
CTX_wm_operator_poll_msg_clear(C);
- WM_operator_poll_context(C, but->optype, but->opcontext);
+ ui_but_context_poll_operator_ex(
+ C, but, &(wmOperatorCallParams){.optype = optype, .opcontext = opcontext});
disabled_msg = CTX_wm_operator_poll_msg_get(C, &disabled_msg_free);
}
/* alternatively, buttons can store some reasoning too */
- else if (but->disabled_info) {
+ else if (!extra_icon && but->disabled_info) {
disabled_msg = TIP_(but->disabled_info);
}
@@ -973,7 +988,7 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
}
}
- if ((U.flag & USER_TOOLTIPS_PYTHON) && !but->optype && rna_struct.strinfo) {
+ if ((U.flag & USER_TOOLTIPS_PYTHON) && !optype && rna_struct.strinfo) {
{
uiTooltipField *field = text_field_add(data,
&(uiTooltipFormat){
@@ -1002,9 +1017,9 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
/* never fails */
/* move ownership (no need for re-alloc) */
- if (but->rnaprop) {
+ if (rnaprop) {
field->text = RNA_path_full_property_py_ex(
- CTX_data_main(C), &but->rnapoin, but->rnaprop, but->rnaindex, true);
+ CTX_data_main(C), &but->rnapoin, rnaprop, but->rnaindex, true);
}
else {
field->text = RNA_path_full_struct_py(CTX_data_main(C), &but->rnapoin);
@@ -1203,12 +1218,12 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
BLI_assert(ELEM(field->format.style, UI_TIP_STYLE_NORMAL, UI_TIP_STYLE_HEADER));
font_id = data->fstyle.uifont_id;
}
- w = BLF_width_ex(font_id, field->text, BLF_DRAW_STR_DUMMY_MAX, &info);
+ w = BLF_width_ex(font_id, field->text, UI_TIP_STR_MAX, &info);
/* check for suffix (enum label) */
if (field->text_suffix && field->text_suffix[0]) {
x_pos = info.width;
- w = max_ii(w, x_pos + BLF_width(font_id, field->text_suffix, BLF_DRAW_STR_DUMMY_MAX));
+ w = max_ii(w, x_pos + BLF_width(font_id, field->text_suffix, UI_TIP_STR_MAX));
}
fontw = max_ii(fontw, w);
@@ -1394,11 +1409,8 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
/** \name ToolTip Public API
* \{ */
-/**
- * \param is_label: When true, show a small tip that only shows the name,
- * otherwise show the full tooltip.
- */
-ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label)
+ARegion *UI_tooltip_create_from_button_or_extra_icon(
+ bContext *C, ARegion *butregion, uiBut *but, uiButExtraOpIcon *extra_icon, bool is_label)
{
wmWindow *win = CTX_wm_window(C);
/* aspect values that shrink text are likely unreadable */
@@ -1415,7 +1427,11 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b
}
if (data == NULL) {
- data = ui_tooltip_data_from_button(C, but);
+ data = ui_tooltip_data_from_button_or_extra_icon(C, but, extra_icon);
+ }
+
+ if (data == NULL) {
+ data = ui_tooltip_data_from_button_or_extra_icon(C, but, NULL);
}
if (data == NULL) {
@@ -1442,7 +1458,7 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b
init_position[1] = but->rect.ymin;
if (butregion) {
ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]);
- init_position[0] = win->eventstate->x;
+ init_position[0] = win->eventstate->xy[0];
}
init_position[1] -= (UI_POPUP_MARGIN / 2);
}
@@ -1453,11 +1469,16 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b
return region;
}
+ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label)
+{
+ return UI_tooltip_create_from_button_or_extra_icon(C, butregion, but, NULL, is_label);
+}
+
ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz)
{
wmWindow *win = CTX_wm_window(C);
const float aspect = 1.0f;
- float init_position[2] = {win->eventstate->x, win->eventstate->y};
+ float init_position[2] = {win->eventstate->xy[0], win->eventstate->xy[1]};
uiTooltipData *data = ui_tooltip_data_from_gizmo(C, gz);
if (data == NULL) {
@@ -1520,13 +1541,6 @@ static uiTooltipData *ui_tooltip_data_from_search_item_tooltip_data(
return data;
}
-/**
- * Create a tooltip from search-item tooltip data \a item_tooltip data.
- * To be called from a callback set with #UI_but_func_search_set_tooltip().
- *
- * \param item_rect: Rectangle of the search item in search region space (#ui_searchbox_butrect())
- * which is passed to the tooltip callback.
- */
ARegion *UI_tooltip_create_from_search_item_generic(
bContext *C,
const ARegion *searchbox_region,
@@ -1541,7 +1555,7 @@ ARegion *UI_tooltip_create_from_search_item_generic(
const float aspect = 1.0f;
const wmWindow *win = CTX_wm_window(C);
float init_position[2];
- init_position[0] = win->eventstate->x;
+ init_position[0] = win->eventstate->xy[0];
init_position[1] = item_rect->ymin + searchbox_region->winrct.ymin - (UI_POPUP_MARGIN / 2);
return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect);
diff --git a/source/blender/editors/interface/interface_regions_intern.h b/source/blender/editors/interface/interface_regions_intern.h
index 0cb1fee9a92..ce938852520 100644
--- a/source/blender/editors/interface/interface_regions_intern.h
+++ b/source/blender/editors/interface/interface_regions_intern.h
@@ -22,9 +22,17 @@
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* interface_region_menu_popup.c */
uint ui_popup_menu_hash(const char *str);
/* interface_regions_intern.h */
ARegion *ui_region_temp_add(bScreen *screen);
void ui_region_temp_remove(struct bContext *C, bScreen *screen, ARegion *region);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 6b1ff92a855..44942d508ca 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -140,9 +140,9 @@ static uiFont *uifont_to_blfont(int id)
void UI_fontstyle_draw_ex(const uiFontStyle *fs,
const rcti *rect,
const char *str,
+ const size_t str_len,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params,
- size_t len,
int *r_xofs,
int *r_yofs,
struct ResultBLF *r_info)
@@ -173,20 +173,20 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs,
BLF_enable(fs->uifont_id, font_flag);
if (fs_params->word_wrap == 1) {
- /* draw from boundbox top */
+ /* Draw from bound-box top. */
yofs = BLI_rcti_size_y(rect) - BLF_height_max(fs->uifont_id);
}
else {
- /* draw from boundbox center */
+ /* Draw from bound-box center. */
const float height = BLF_ascender(fs->uifont_id) + BLF_descender(fs->uifont_id);
yofs = ceil(0.5f * (BLI_rcti_size_y(rect) - height));
}
if (fs_params->align == UI_STYLE_TEXT_CENTER) {
- xofs = floor(0.5f * (BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, len)));
+ xofs = floor(0.5f * (BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, str_len)));
}
else if (fs_params->align == UI_STYLE_TEXT_RIGHT) {
- xofs = BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, len);
+ xofs = BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, str_len);
}
yofs = MAX2(0, yofs);
@@ -196,7 +196,7 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs,
BLF_position(fs->uifont_id, rect->xmin + xofs, rect->ymin + yofs, 0.0f);
BLF_color4ubv(fs->uifont_id, col);
- BLF_draw_ex(fs->uifont_id, str, len, r_info);
+ BLF_draw_ex(fs->uifont_id, str, str_len, r_info);
BLF_disable(fs->uifont_id, font_flag);
@@ -211,15 +211,13 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs,
void UI_fontstyle_draw(const uiFontStyle *fs,
const rcti *rect,
const char *str,
+ const size_t str_len,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params)
{
- int xofs, yofs;
-
- UI_fontstyle_draw_ex(fs, rect, str, col, fs_params, BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs, NULL);
+ UI_fontstyle_draw_ex(fs, rect, str, str_len, col, fs_params, NULL, NULL, NULL);
}
-/* drawn same as above, but at 90 degree angle */
void UI_fontstyle_draw_rotated(const uiFontStyle *fs,
const rcti *rect,
const char *str,
@@ -279,12 +277,6 @@ void UI_fontstyle_draw_rotated(const uiFontStyle *fs,
}
}
-/**
- * Similar to #UI_fontstyle_draw
- * but ignore alignment, shadow & no clipping rect.
- *
- * For drawing on-screen labels.
- */
void UI_fontstyle_draw_simple(
const uiFontStyle *fs, float x, float y, const char *str, const uchar col[4])
{
@@ -294,9 +286,6 @@ void UI_fontstyle_draw_simple(
BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
}
-/**
- * Same as #UI_fontstyle_draw but draw a colored backdrop.
- */
void UI_fontstyle_draw_simple_backdrop(const uiFontStyle *fs,
float x,
float y,
@@ -331,7 +320,7 @@ void UI_fontstyle_draw_simple_backdrop(const uiFontStyle *fs,
}
/* ************** helpers ************************ */
-/* XXX: read a style configure */
+
const uiStyle *UI_style_get(void)
{
#if 0
@@ -344,7 +333,6 @@ const uiStyle *UI_style_get(void)
#endif
}
-/* for drawing, scaled with DPI setting */
const uiStyle *UI_style_get_dpi(void)
{
const uiStyle *style = UI_style_get();
@@ -376,6 +364,27 @@ int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str)
return (int)BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
}
+int UI_fontstyle_string_width_with_block_aspect(const uiFontStyle *fs,
+ const char *str,
+ const float aspect)
+{
+ uiFontStyle fs_buf;
+ if (aspect != 1.0f) {
+ fs_buf = *fs;
+ ui_fontscale(&fs_buf.points, aspect);
+ fs = &fs_buf;
+ }
+
+ int width = UI_fontstyle_string_width(fs, str);
+
+ if (aspect != 1.0f) {
+ /* While in most cases rounding up isn't important, it can make a difference
+ * with small fonts (3px or less), zooming out in the node-editor for e.g. */
+ width = (int)ceilf(width * aspect);
+ }
+ return width;
+}
+
int UI_fontstyle_height_max(const uiFontStyle *fs)
{
UI_fontstyle_set(fs);
@@ -384,11 +393,9 @@ int UI_fontstyle_height_max(const uiFontStyle *fs)
/* ************** init exit ************************ */
-/* called on each startup.blend read */
-/* reading without uifont will create one */
void uiStyleInit(void)
{
- uiStyle *style = U.uistyles.first;
+ const uiStyle *style = U.uistyles.first;
/* recover from uninitialized dpi */
if (U.dpi == 0) {
@@ -419,11 +426,11 @@ void uiStyleInit(void)
}
if (U.font_path_ui[0]) {
- BLI_strncpy(font_first->filename, U.font_path_ui, sizeof(font_first->filename));
+ BLI_strncpy(font_first->filepath, U.font_path_ui, sizeof(font_first->filepath));
font_first->uifont_id = UIFONT_CUSTOM1;
}
else {
- BLI_strncpy(font_first->filename, "default", sizeof(font_first->filename));
+ BLI_strncpy(font_first->filepath, "default", sizeof(font_first->filepath));
font_first->uifont_id = UIFONT_DEFAULT;
}
@@ -434,7 +441,7 @@ void uiStyleInit(void)
font->blf_id = BLF_load_default(unique);
}
else {
- font->blf_id = BLF_load(font->filename);
+ font->blf_id = BLF_load(font->filepath);
if (font->blf_id == -1) {
font->blf_id = BLF_load_default(unique);
}
@@ -452,16 +459,20 @@ void uiStyleInit(void)
* Yes, this build the glyph cache and create
* the texture.
*/
- BLF_size(font->blf_id, 11 * U.pixelsize, U.dpi);
- BLF_size(font->blf_id, 12 * U.pixelsize, U.dpi);
- BLF_size(font->blf_id, 14 * U.pixelsize, U.dpi);
+ BLF_size(font->blf_id, 11.0f * U.pixelsize, U.dpi);
+ BLF_size(font->blf_id, 12.0f * U.pixelsize, U.dpi);
+ BLF_size(font->blf_id, 14.0f * U.pixelsize, U.dpi);
}
}
if (style == NULL) {
- ui_style_new(&U.uistyles, "Default Style", UIFONT_DEFAULT);
+ style = ui_style_new(&U.uistyles, "Default Style", UIFONT_DEFAULT);
}
+ BLF_cache_flush_set_fn(UI_widgetbase_draw_cache_flush);
+
+ BLF_default_size(style->widgetlabel.points);
+
/* XXX, this should be moved into a style,
* but for now best only load the monospaced font once. */
BLI_assert(blf_mono_font == -1);
@@ -475,7 +486,7 @@ void uiStyleInit(void)
blf_mono_font = BLF_load_mono_default(unique);
}
- BLF_size(blf_mono_font, 12 * U.pixelsize, 72);
+ BLF_size(blf_mono_font, 12.0f * U.pixelsize, 72);
/* Set default flags based on UI preferences (not render fonts) */
{
@@ -520,7 +531,7 @@ void uiStyleInit(void)
blf_mono_font_render = BLF_load_mono_default(unique);
}
- BLF_size(blf_mono_font_render, 12 * U.pixelsize, 72);
+ BLF_size(blf_mono_font_render, 12.0f * U.pixelsize, 72);
}
void UI_fontstyle_set(const uiFontStyle *fs)
diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc
index f27b37a27de..0a3cff5fa98 100644
--- a/source/blender/editors/interface/interface_template_asset_view.cc
+++ b/source/blender/editors/interface/interface_template_asset_view.cc
@@ -70,6 +70,7 @@ static void asset_view_item_but_drag_set(uiBut *but,
UI_but_drag_set_asset(but,
asset_handle,
BLI_strdup(blend_path),
+ ED_asset_handle_get_metadata(asset_handle),
FILE_ASSET_IMPORT_APPEND,
ED_asset_handle_get_preview_icon_id(asset_handle),
imbuf,
@@ -177,7 +178,7 @@ static void asset_view_template_refresh_asset_collection(
RNA_property_collection_clear(&assets_dataptr, assets_prop);
- ED_assetlist_iterate(&asset_library_ref, [&](AssetHandle asset) {
+ ED_assetlist_iterate(asset_library_ref, [&](AssetHandle asset) {
if (!ED_asset_filter_matches_asset(&filter_settings, &asset)) {
/* Don't do anything else, but return true to continue iterating. */
return true;
@@ -226,7 +227,7 @@ void uiTemplateAssetView(uiLayout *layout,
if ((display_flags & UI_TEMPLATE_ASSET_DRAW_NO_LIBRARY) == 0) {
uiItemFullR(row, asset_library_dataptr, asset_library_prop, RNA_NO_INDEX, 0, 0, "", 0);
if (asset_library_ref.type != ASSET_LIBRARY_LOCAL) {
- uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_list_refresh");
+ uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_library_refresh");
}
}
diff --git a/source/blender/editors/interface/interface_template_attribute_search.cc b/source/blender/editors/interface/interface_template_attribute_search.cc
new file mode 100644
index 00000000000..6d4b7a37bff
--- /dev/null
+++ b/source/blender/editors/interface/interface_template_attribute_search.cc
@@ -0,0 +1,126 @@
+/*
+ * 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 edinterface
+ */
+
+#include "BLI_string_ref.hh"
+#include "BLI_string_search.h"
+
+#include "DNA_customdata_types.h"
+
+#include "RNA_access.h"
+#include "RNA_enum_types.h"
+
+#include "BLT_translation.h"
+
+#include "NOD_geometry_nodes_eval_log.hh"
+
+#include "UI_interface.h"
+#include "UI_interface.hh"
+#include "UI_resources.h"
+
+using blender::nodes::geometry_nodes_eval_log::GeometryAttributeInfo;
+
+namespace blender::ui {
+
+static StringRef attribute_data_type_string(const CustomDataType type)
+{
+ const char *name = nullptr;
+ RNA_enum_name_from_value(rna_enum_attribute_type_items, type, &name);
+ return StringRef(IFACE_(name));
+}
+
+static StringRef attribute_domain_string(const AttributeDomain domain)
+{
+ const char *name = nullptr;
+ RNA_enum_name_from_value(rna_enum_attribute_domain_items, domain, &name);
+ return StringRef(IFACE_(name));
+}
+
+static bool attribute_search_item_add(uiSearchItems *items, const GeometryAttributeInfo &item)
+{
+ const StringRef data_type_name = attribute_data_type_string(item.data_type);
+ const StringRef domain_name = attribute_domain_string(item.domain);
+ std::string search_item_text = domain_name + " " + UI_MENU_ARROW_SEP + item.name + UI_SEP_CHAR +
+ data_type_name;
+
+ return UI_search_item_add(
+ items, search_item_text.c_str(), (void *)&item, ICON_NONE, UI_BUT_HAS_SEP_CHAR, 0);
+}
+
+void attribute_search_add_items(StringRefNull str,
+ const bool is_output,
+ Span<const GeometryAttributeInfo *> infos,
+ uiSearchItems *seach_items,
+ const bool is_first)
+{
+ static GeometryAttributeInfo dummy_info;
+
+ /* Any string may be valid, so add the current search string along with the hints. */
+ if (str[0] != '\0') {
+ bool contained = false;
+ for (const GeometryAttributeInfo *attribute_info : infos) {
+ if (attribute_info->name == str) {
+ contained = true;
+ break;
+ }
+ }
+ if (!contained) {
+ dummy_info.name = str;
+ UI_search_item_add(
+ seach_items, str.c_str(), &dummy_info, is_output ? ICON_ADD : ICON_NONE, 0, 0);
+ }
+ }
+
+ if (str[0] == '\0' && !is_first) {
+ /* Allow clearing the text field when the string is empty, but not on the first pass,
+ * or opening an attribute field for the first time would show this search item. */
+ dummy_info.name = str;
+ UI_search_item_add(seach_items, str.c_str(), &dummy_info, ICON_X, 0, 0);
+ }
+
+ /* Don't filter when the menu is first opened, but still run the search
+ * so the items are in the same order they will appear in while searching. */
+ const char *string = is_first ? "" : str.c_str();
+
+ StringSearch *search = BLI_string_search_new();
+ for (const GeometryAttributeInfo *item : infos) {
+
+ /* Don't show the legacy "normal" attribute. */
+ if (item->name == "normal" && item->domain == ATTR_DOMAIN_FACE) {
+ continue;
+ }
+
+ BLI_string_search_add(search, item->name.c_str(), (void *)item, 0);
+ }
+
+ GeometryAttributeInfo **filtered_items;
+ const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items);
+
+ for (const int i : IndexRange(filtered_amount)) {
+ const GeometryAttributeInfo *item = filtered_items[i];
+ if (!attribute_search_item_add(seach_items, *item)) {
+ break;
+ }
+ }
+
+ MEM_freeN(filtered_items);
+ BLI_string_search_free(search);
+}
+
+} // namespace blender::ui
diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc
index 845a7813da2..817599605a9 100644
--- a/source/blender/editors/interface/interface_template_list.cc
+++ b/source/blender/editors/interface/interface_template_list.cc
@@ -1276,9 +1276,6 @@ void uiTemplateList(uiLayout *layout,
nullptr);
}
-/**
- * \return: A RNA pointer for the operator properties.
- */
PointerRNA *UI_list_custom_activate_operator_set(uiList *ui_list,
const char *opname,
bool create_properties)
@@ -1298,9 +1295,6 @@ PointerRNA *UI_list_custom_activate_operator_set(uiList *ui_list,
return dyn_data->custom_activate_opptr;
}
-/**
- * \return: A RNA pointer for the operator properties.
- */
PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list,
const char *opname,
bool create_properties)
@@ -1325,9 +1319,10 @@ PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list,
/** \name List-types Registration
* \{ */
-void ED_uilisttypes_ui(void)
+void ED_uilisttypes_ui()
{
WM_uilisttype_add(UI_UL_asset_view());
+ WM_uilisttype_add(UI_UL_cache_file_layers());
}
/** \} */
diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.cc
index 3a5d65475f7..0ce3a0d8af1 100644
--- a/source/blender/editors/interface/interface_template_search_menu.c
+++ b/source/blender/editors/interface/interface_template_search_menu.cc
@@ -21,8 +21,8 @@
* Accessed via the #WM_OT_search_menu operator.
*/
-#include <stdio.h>
-#include <string.h>
+#include <cstdio>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -69,9 +69,6 @@
/** \name Menu Search Template Implementation
* \{ */
-/* Unicode arrow. */
-#define MENU_SEP "\xe2\x96\xb6"
-
/**
* Use when #menu_items_from_ui_create is called with `include_all_areas`.
* so we can run the menu item in the area it was extracted from.
@@ -88,16 +85,16 @@ struct MenuSearch_Context {
};
struct MenuSearch_Parent {
- struct MenuSearch_Parent *parent;
+ MenuSearch_Parent *parent;
MenuType *parent_mt;
const char *drawstr;
/** Set while writing menu items only. */
- struct MenuSearch_Parent *temp_child;
+ MenuSearch_Parent *temp_child;
};
struct MenuSearch_Item {
- struct MenuSearch_Item *next, *prev;
+ MenuSearch_Item *next, *prev;
const char *drawstr;
const char *drawwstr_full;
/** Support a single level sub-menu nesting (for operator buttons that expand). */
@@ -105,12 +102,12 @@ struct MenuSearch_Item {
int icon;
int state;
- struct MenuSearch_Parent *menu_parent;
+ MenuSearch_Parent *menu_parent;
MenuType *mt;
- enum {
- MENU_SEARCH_TYPE_OP = 1,
- MENU_SEARCH_TYPE_RNA = 2,
+ enum Type {
+ Operator = 1,
+ RNA = 2,
} type;
union {
@@ -118,7 +115,7 @@ struct MenuSearch_Item {
struct {
wmOperatorType *type;
PointerRNA *opptr;
- short opcontext;
+ wmOperatorCallContext opcontext;
bContextStore *context;
} op;
@@ -132,8 +129,8 @@ struct MenuSearch_Item {
} rna;
};
- /** Set when we need each menu item to be able to set its own context. may be NULL. */
- struct MenuSearch_Context *wm_context;
+ /** Set when we need each menu item to be able to set its own context. may be nullptr. */
+ MenuSearch_Context *wm_context;
};
struct MenuSearch_Data {
@@ -151,15 +148,15 @@ struct MenuSearch_Data {
static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v)
{
- const struct MenuSearch_Item *menu_item_a = menu_item_a_v;
- const struct MenuSearch_Item *menu_item_b = menu_item_b_v;
+ const MenuSearch_Item *menu_item_a = (MenuSearch_Item *)menu_item_a_v;
+ const MenuSearch_Item *menu_item_b = (MenuSearch_Item *)menu_item_b_v;
return strcmp(menu_item_a->drawwstr_full, menu_item_b->drawwstr_full);
}
static const char *strdup_memarena(MemArena *memarena, const char *str)
{
const uint str_size = strlen(str) + 1;
- char *str_dst = BLI_memarena_alloc(memarena, str_size);
+ char *str_dst = (char *)BLI_memarena_alloc(memarena, str_size);
memcpy(str_dst, str, str_size);
return str_dst;
}
@@ -167,50 +164,53 @@ static const char *strdup_memarena(MemArena *memarena, const char *str)
static const char *strdup_memarena_from_dynstr(MemArena *memarena, DynStr *dyn_str)
{
const uint str_size = BLI_dynstr_get_len(dyn_str) + 1;
- char *str_dst = BLI_memarena_alloc(memarena, str_size);
+ char *str_dst = (char *)BLI_memarena_alloc(memarena, str_size);
BLI_dynstr_get_cstring_ex(dyn_str, str_dst);
return str_dst;
}
-static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *data,
+static bool menu_items_from_ui_create_item_from_button(MenuSearch_Data *data,
MemArena *memarena,
struct MenuType *mt,
const char *drawstr_submenu,
uiBut *but,
- struct MenuSearch_Context *wm_context)
+ MenuSearch_Context *wm_context)
{
- struct MenuSearch_Item *item = NULL;
+ MenuSearch_Item *item = nullptr;
/* Use override if the name is empty, this can happen with popovers. */
- const char *drawstr_override = NULL;
+ const char *drawstr_override = nullptr;
const char *drawstr_sep = (but->flag & UI_BUT_HAS_SEP_CHAR) ?
strrchr(but->drawstr, UI_SEP_CHAR) :
- NULL;
+ nullptr;
const bool drawstr_is_empty = (drawstr_sep == but->drawstr) || (but->drawstr[0] == '\0');
- if (but->optype != NULL) {
+ if (but->optype != nullptr) {
if (drawstr_is_empty) {
drawstr_override = WM_operatortype_name(but->optype, but->opptr);
}
- item = BLI_memarena_calloc(memarena, sizeof(*item));
- item->type = MENU_SEARCH_TYPE_OP;
+ item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MenuSearch_Item::Type::Operator;
item->op.type = but->optype;
item->op.opcontext = but->opcontext;
item->op.context = but->context;
item->op.opptr = but->opptr;
- but->opptr = NULL;
+ but->opptr = nullptr;
}
- else if (but->rnaprop != NULL) {
+ else if (but->rnaprop != nullptr) {
const int prop_type = RNA_property_type(but->rnaprop);
if (drawstr_is_empty) {
if (prop_type == PROP_ENUM) {
const int value_enum = (int)but->hardmax;
EnumPropertyItem enum_item;
- if (RNA_property_enum_item_from_value_gettexted(
- but->block->evil_C, &but->rnapoin, but->rnaprop, value_enum, &enum_item)) {
+ if (RNA_property_enum_item_from_value_gettexted((bContext *)but->block->evil_C,
+ &but->rnapoin,
+ but->rnaprop,
+ value_enum,
+ &enum_item)) {
drawstr_override = enum_item.name;
}
else {
@@ -232,8 +232,8 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
prop_type);
}
else {
- item = BLI_memarena_calloc(memarena, sizeof(*item));
- item->type = MENU_SEARCH_TYPE_RNA;
+ item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MenuSearch_Item::Type::RNA;
item->rna.ptr = but->rnapoin;
item->rna.prop = but->rnaprop;
@@ -245,13 +245,12 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
}
}
- if (item != NULL) {
+ if (item != nullptr) {
/* Handle shared settings. */
- if (drawstr_override != NULL) {
+ if (drawstr_override != nullptr) {
const char *drawstr_suffix = drawstr_sep ? drawstr_sep : "";
- char *drawstr_alloc = BLI_string_joinN("(", drawstr_override, ")", drawstr_suffix);
- item->drawstr = strdup_memarena(memarena, drawstr_alloc);
- MEM_freeN(drawstr_alloc);
+ std::string drawstr = std::string("(") + drawstr_override + ")" + drawstr_suffix;
+ item->drawstr = strdup_memarena(memarena, drawstr.c_str());
}
else {
item->drawstr = strdup_memarena(memarena, but->drawstr);
@@ -261,7 +260,7 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
item->state = (but->flag &
(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR));
item->mt = mt;
- item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : NULL;
+ item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : nullptr;
item->wm_context = wm_context;
@@ -275,11 +274,11 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
/**
* Populate a fake button from a menu item (use for context menu).
*/
-static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but)
+static bool menu_items_to_ui_button(MenuSearch_Item *item, uiBut *but)
{
bool changed = false;
switch (item->type) {
- case MENU_SEARCH_TYPE_OP: {
+ case MenuSearch_Item::Type::Operator: {
but->optype = item->op.type;
but->opcontext = item->op.opcontext;
but->context = item->op.context;
@@ -287,7 +286,7 @@ static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but)
changed = true;
break;
}
- case MENU_SEARCH_TYPE_RNA: {
+ case MenuSearch_Item::Type::RNA: {
const int prop_type = RNA_property_type(item->rna.prop);
but->rnapoin = item->rna.ptr;
@@ -305,12 +304,12 @@ static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but)
if (changed) {
STRNCPY(but->drawstr, item->drawstr);
char *drawstr_sep = (item->state & UI_BUT_HAS_SEP_CHAR) ? strrchr(but->drawstr, UI_SEP_CHAR) :
- NULL;
+ nullptr;
if (drawstr_sep) {
*drawstr_sep = '\0';
}
- but->icon = item->icon;
+ but->icon = (BIFIconID)item->icon;
but->str = but->strdata;
}
@@ -330,13 +329,13 @@ static void menu_types_add_from_keymap_items(bContext *C,
{
wmWindowManager *wm = CTX_wm_manager(C);
ListBase *handlers[] = {
- region ? &region->handlers : NULL,
- area ? &area->handlers : NULL,
+ region ? &region->handlers : nullptr,
+ area ? &area->handlers : nullptr,
&win->handlers,
};
for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
- if (handlers[handler_index] == NULL) {
+ if (handlers[handler_index] == nullptr) {
continue;
}
LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers[handler_index]) {
@@ -348,10 +347,10 @@ static void menu_types_add_from_keymap_items(bContext *C,
continue;
}
- if (handler_base->poll == NULL || handler_base->poll(region, win->eventstate)) {
+ if (handler_base->poll == nullptr || handler_base->poll(region, win->eventstate)) {
wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
wmEventHandler_KeymapResult km_result;
- WM_event_get_keymaps_from_handler(wm, handler, &km_result);
+ WM_event_get_keymaps_from_handler(wm, win, handler, &km_result);
for (int km_index = 0; km_index < km_result.keymaps_len; km_index++) {
wmKeyMap *keymap = km_result.keymaps[km_index];
if (keymap && WM_keymap_poll(C, keymap)) {
@@ -385,16 +384,16 @@ static void menu_types_add_from_keymap_items(bContext *C,
/**
* Display all operators (last). Developer-only convenience feature.
*/
-static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *data)
+static void menu_items_from_all_operators(bContext *C, MenuSearch_Data *data)
{
/* Add to temporary list so we can sort them separately. */
- ListBase operator_items = {NULL, NULL};
+ ListBase operator_items = {nullptr, nullptr};
MemArena *memarena = data->memarena;
GHashIterator iter;
for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter);
BLI_ghashIterator_step(&iter)) {
- wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
+ wmOperatorType *ot = (wmOperatorType *)BLI_ghashIterator_getValue(&iter);
if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) {
continue;
@@ -403,24 +402,24 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d
if (WM_operator_poll((bContext *)C, ot)) {
const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
- struct MenuSearch_Item *item = NULL;
- item = BLI_memarena_calloc(memarena, sizeof(*item));
- item->type = MENU_SEARCH_TYPE_OP;
+ MenuSearch_Item *item = nullptr;
+ item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MenuSearch_Item::Type::Operator;
item->op.type = ot;
item->op.opcontext = WM_OP_INVOKE_DEFAULT;
- item->op.context = NULL;
+ item->op.context = nullptr;
char idname_as_py[OP_MAX_TYPENAME];
char uiname[256];
WM_operator_py_idname(idname_as_py, ot->idname);
- SNPRINTF(uiname, "%s " MENU_SEP "%s", idname_as_py, ot_ui_name);
+ SNPRINTF(uiname, "%s " UI_MENU_ARROW_SEP "%s", idname_as_py, ot_ui_name);
item->drawwstr_full = strdup_memarena(memarena, uiname);
item->drawstr = ot_ui_name;
- item->wm_context = NULL;
+ item->wm_context = nullptr;
BLI_addtail(&operator_items, item);
}
@@ -437,7 +436,7 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d
* - Look up predefined editor-menus.
* - Look up key-map items which call menus.
*/
-static struct MenuSearch_Data *menu_items_from_ui_create(
+static MenuSearch_Data *menu_items_from_ui_create(
bContext *C, wmWindow *win, ScrArea *area_init, ARegion *region_init, bool include_all_areas)
{
MemArena *memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
@@ -447,12 +446,12 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
const uiStyle *style = UI_style_get_dpi();
/* Convert into non-ui structure. */
- struct MenuSearch_Data *data = MEM_callocN(sizeof(*data), __func__);
+ MenuSearch_Data *data = (MenuSearch_Data *)MEM_callocN(sizeof(*data), __func__);
DynStr *dyn_str = BLI_dynstr_new_memarena();
/* Use a stack of menus to handle and discover new menus in passes. */
- LinkNode *menu_stack = NULL;
+ LinkNode *menu_stack = nullptr;
/* Tag menu types not to add, either because they have already been added
* or they have been blacklisted.
@@ -466,10 +465,13 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
const char *idname_array[] = {
/* While we could include this, it's just showing filenames to load. */
"TOPBAR_MT_file_open_recent",
+ /* Showing undo history is not helpful since users may accidentally undo
+ * an action they intend to run. */
+ "TOPBAR_MT_undo_history",
};
for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
MenuType *mt = WM_menutype_find(idname_array[i], false);
- if (mt != NULL) {
+ if (mt != nullptr) {
BLI_gset_add(menu_tagged, mt);
}
}
@@ -486,7 +488,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
for (WM_menutype_iter(&iter); (!BLI_ghashIterator_done(&iter));
(BLI_ghashIterator_step(&iter))) {
- MenuType *mt = BLI_ghashIterator_getValue(&iter);
+ MenuType *mt = (MenuType *)BLI_ghashIterator_getValue(&iter);
if (BLI_str_endswith(mt->idname, "_context_menu")) {
BLI_gset_add(menu_tagged, mt);
}
@@ -497,34 +499,33 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
};
for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
MenuType *mt = WM_menutype_find(idname_array[i], false);
- if (mt != NULL) {
- BLI_gset_remove(menu_tagged, mt, NULL);
+ if (mt != nullptr) {
+ BLI_gset_remove(menu_tagged, mt, nullptr);
}
}
}
/* Collect contexts, one for each 'ui_type'. */
- struct MenuSearch_Context *wm_contexts = NULL;
+ MenuSearch_Context *wm_contexts = nullptr;
- const EnumPropertyItem *space_type_ui_items = NULL;
+ const EnumPropertyItem *space_type_ui_items = nullptr;
int space_type_ui_items_len = 0;
bool space_type_ui_items_free = false;
/* Text used as prefix for top-bar menu items. */
- const char *global_menu_prefix = NULL;
+ const char *global_menu_prefix = nullptr;
if (include_all_areas) {
bScreen *screen = WM_window_get_active_screen(win);
/* First create arrays for ui_type. */
- PropertyRNA *prop_ui_type = NULL;
+ PropertyRNA *prop_ui_type = nullptr;
{
/* This must be a valid pointer, with only it's type checked. */
- ScrArea area_dummy = {
- /* Anything besides #SPACE_EMPTY is fine,
- * as this value is only included in the enum when set. */
- .spacetype = SPACE_TOPBAR,
- };
+ ScrArea area_dummy = {nullptr};
+ /* Anything besides #SPACE_EMPTY is fine,
+ * as this value is only included in the enum when set. */
+ area_dummy.spacetype = SPACE_TOPBAR;
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_Area, &area_dummy, &ptr);
prop_ui_type = RNA_struct_find_property(&ptr, "ui_type");
@@ -535,7 +536,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
&space_type_ui_items_len,
&space_type_ui_items_free);
- wm_contexts = BLI_memarena_calloc(memarena, sizeof(*wm_contexts) * space_type_ui_items_len);
+ wm_contexts = (MenuSearch_Context *)BLI_memarena_calloc(
+ memarena, sizeof(*wm_contexts) * space_type_ui_items_len);
for (int i = 0; i < space_type_ui_items_len; i++) {
wm_contexts[i].space_type_ui_index = -1;
}
@@ -543,7 +545,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
- if (region != NULL) {
+ if (region != nullptr) {
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_Area, area, &ptr);
const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type);
@@ -576,16 +578,16 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
for (int space_type_ui_index = -1; space_type_ui_index < space_type_ui_items_len;
space_type_ui_index += 1) {
- ScrArea *area = NULL;
- ARegion *region = NULL;
- struct MenuSearch_Context *wm_context = NULL;
+ ScrArea *area = nullptr;
+ ARegion *region = nullptr;
+ MenuSearch_Context *wm_context = nullptr;
if (include_all_areas) {
if (space_type_ui_index == -1) {
/* First run without any context, to populate the top-bar without. */
- wm_context = NULL;
- area = NULL;
- region = NULL;
+ wm_context = nullptr;
+ area = nullptr;
+ region = nullptr;
}
else {
wm_context = &wm_contexts[space_type_ui_index];
@@ -610,7 +612,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
* from the buttons, however this is quite involved and can be avoided as by convention
* each space-type has a single root-menu that headers use. */
{
- const char *idname_array[2] = {NULL};
+ const char *idname_array[2] = {nullptr};
int idname_array_len = 0;
/* Use negative for global (no area) context, populate the top-bar. */
@@ -626,8 +628,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
case space_type: \
break
- if (area != NULL) {
- SpaceLink *sl = area->spacedata.first;
+ if (area != nullptr) {
+ SpaceLink *sl = (SpaceLink *)area->spacedata.first;
switch ((eSpace_Type)area->spacetype) {
SPACE_MENU_MAP(SPACE_VIEW3D, "VIEW3D_MT_editor_menus");
SPACE_MENU_MAP(SPACE_GRAPH, "GRAPH_MT_editor_menus");
@@ -659,7 +661,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
for (int i = 0; i < idname_array_len; i++) {
MenuType *mt = WM_menutype_find(idname_array[i], false);
- if (mt != NULL) {
+ if (mt != nullptr) {
/* Check if this exists because of 'include_all_areas'. */
if (BLI_gset_add(menu_tagged, mt)) {
BLI_linklist_prepend(&menu_stack, mt);
@@ -672,8 +674,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
bool has_keymap_menu_items = false;
- while (menu_stack != NULL) {
- MenuType *mt = BLI_linklist_pop(&menu_stack);
+ while (menu_stack != nullptr) {
+ MenuType *mt = (MenuType *)BLI_linklist_pop(&menu_stack);
if (!WM_menutype_poll(C, mt)) {
continue;
}
@@ -690,7 +692,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
UI_block_end(C, block);
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
- MenuType *mt_from_but = NULL;
+ MenuType *mt_from_but = nullptr;
/* Support menu titles with dynamic from initial labels
* (used by edit-mesh context menu). */
if (but->type == UI_BTYPE_LABEL) {
@@ -701,13 +703,13 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
but_test = but_test->prev;
}
- if (but_test == NULL) {
+ if (but_test == nullptr) {
BLI_ghash_insert(
menu_display_name_map, mt, (void *)strdup_memarena(memarena, but->drawstr));
}
}
else if (menu_items_from_ui_create_item_from_button(
- data, memarena, mt, NULL, but, wm_context)) {
+ data, memarena, mt, nullptr, but, wm_context)) {
/* pass */
}
else if ((mt_from_but = UI_but_menutype_get(but))) {
@@ -717,8 +719,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
if (!BLI_ghash_haskey(menu_parent_map, mt_from_but)) {
- struct MenuSearch_Parent *menu_parent = BLI_memarena_calloc(memarena,
- sizeof(*menu_parent));
+ MenuSearch_Parent *menu_parent = (MenuSearch_Parent *)BLI_memarena_calloc(
+ memarena, sizeof(*menu_parent));
/* Use brackets for menu key shortcuts,
* converting "Text|Some-Shortcut" to "Text (Some-Shortcut)".
* This is needed so we don't right align sub-menu contents
@@ -726,9 +728,9 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
*/
const char *drawstr_sep = but->flag & UI_BUT_HAS_SEP_CHAR ?
strrchr(but->drawstr, UI_SEP_CHAR) :
- NULL;
+ nullptr;
bool drawstr_is_empty = false;
- if (drawstr_sep != NULL) {
+ if (drawstr_sep != nullptr) {
BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
/* Detect empty string, fallback to menu name. */
const char *drawstr = but->drawstr;
@@ -763,7 +765,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
}
}
- else if (but->menu_create_func != NULL) {
+ else if (but->menu_create_func != nullptr) {
/* A non 'MenuType' menu button. */
/* Only expand one level deep, this is mainly for expanding operator menus. */
@@ -788,19 +790,21 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
if (region) {
+ BLI_ghash_remove(region->runtime.block_name_map, sub_block->name, nullptr, nullptr);
BLI_remlink(&region->uiblocks, sub_block);
}
- UI_block_free(NULL, sub_block);
+ UI_block_free(nullptr, sub_block);
}
}
if (region) {
+ BLI_ghash_remove(region->runtime.block_name_map, block->name, nullptr, nullptr);
BLI_remlink(&region->uiblocks, block);
}
- UI_block_free(NULL, block);
+ UI_block_free(nullptr, block);
/* Add key-map items as a second pass,
* so all menus are accessed from the header & top-bar before key shortcuts are expanded. */
- if ((menu_stack == NULL) && (has_keymap_menu_items == false)) {
+ if ((menu_stack == nullptr) && (has_keymap_menu_items == false)) {
has_keymap_menu_items = true;
menu_types_add_from_keymap_items(
C, win, area, region, &menu_stack, menu_to_kmi, menu_tagged);
@@ -808,64 +812,65 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
}
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
- item->menu_parent = BLI_ghash_lookup(menu_parent_map, item->mt);
+ LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
+ item->menu_parent = (MenuSearch_Parent *)BLI_ghash_lookup(menu_parent_map, item->mt);
}
GHASH_ITER (iter, menu_parent_map) {
- struct MenuSearch_Parent *menu_parent = BLI_ghashIterator_getValue(&iter);
- menu_parent->parent = BLI_ghash_lookup(menu_parent_map, menu_parent->parent_mt);
+ MenuSearch_Parent *menu_parent = (MenuSearch_Parent *)BLI_ghashIterator_getValue(&iter);
+ menu_parent->parent = (MenuSearch_Parent *)BLI_ghash_lookup(menu_parent_map,
+ menu_parent->parent_mt);
}
/* NOTE: currently this builds the full path for each menu item,
* that could be moved into the parent menu. */
/* Set names as full paths. */
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
+ LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
if (include_all_areas) {
BLI_dynstr_appendf(dyn_str,
"%s: ",
- (item->wm_context != NULL) ?
+ (item->wm_context != nullptr) ?
space_type_ui_items[item->wm_context->space_type_ui_index].name :
global_menu_prefix);
}
- if (item->menu_parent != NULL) {
- struct MenuSearch_Parent *menu_parent = item->menu_parent;
- menu_parent->temp_child = NULL;
+ if (item->menu_parent != nullptr) {
+ MenuSearch_Parent *menu_parent = item->menu_parent;
+ menu_parent->temp_child = nullptr;
while (menu_parent && menu_parent->parent) {
menu_parent->parent->temp_child = menu_parent;
menu_parent = menu_parent->parent;
}
while (menu_parent) {
BLI_dynstr_append(dyn_str, menu_parent->drawstr);
- BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
+ BLI_dynstr_append(dyn_str, " " UI_MENU_ARROW_SEP " ");
menu_parent = menu_parent->temp_child;
}
}
else {
- const char *drawstr = BLI_ghash_lookup(menu_display_name_map, item->mt);
- if (drawstr == NULL) {
+ const char *drawstr = (const char *)BLI_ghash_lookup(menu_display_name_map, item->mt);
+ if (drawstr == nullptr) {
drawstr = CTX_IFACE_(item->mt->translation_context, item->mt->label);
}
BLI_dynstr_append(dyn_str, drawstr);
- wmKeyMapItem *kmi = BLI_ghash_lookup(menu_to_kmi, item->mt);
- if (kmi != NULL) {
+ wmKeyMapItem *kmi = (wmKeyMapItem *)BLI_ghash_lookup(menu_to_kmi, item->mt);
+ if (kmi != nullptr) {
char kmi_str[128];
WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str));
BLI_dynstr_appendf(dyn_str, " (%s)", kmi_str);
}
- BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
+ BLI_dynstr_append(dyn_str, " " UI_MENU_ARROW_SEP " ");
}
/* Optional nested menu. */
- if (item->drawstr_submenu != NULL) {
+ if (item->drawstr_submenu != nullptr) {
BLI_dynstr_append(dyn_str, item->drawstr_submenu);
- BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
+ BLI_dynstr_append(dyn_str, " " UI_MENU_ARROW_SEP " ");
}
BLI_dynstr_append(dyn_str, item->drawstr);
@@ -880,12 +885,12 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
* NOTE: we might want to keep the in-menu order, for now sort all. */
BLI_listbase_sort(&data->items, menu_item_sort_by_drawstr_full);
- BLI_ghash_free(menu_parent_map, NULL, NULL);
- BLI_ghash_free(menu_display_name_map, NULL, NULL);
+ BLI_ghash_free(menu_parent_map, nullptr, nullptr);
+ BLI_ghash_free(menu_display_name_map, nullptr, nullptr);
- BLI_ghash_free(menu_to_kmi, NULL, NULL);
+ BLI_ghash_free(menu_to_kmi, nullptr, nullptr);
- BLI_gset_free(menu_tagged, NULL);
+ BLI_gset_free(menu_tagged, nullptr);
data->memarena = memarena;
@@ -918,16 +923,16 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
static void menu_search_arg_free_fn(void *data_v)
{
- struct MenuSearch_Data *data = data_v;
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
+ MenuSearch_Data *data = (MenuSearch_Data *)data_v;
+ LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
switch (item->type) {
- case MENU_SEARCH_TYPE_OP: {
- if (item->op.opptr != NULL) {
+ case MenuSearch_Item::Type::Operator: {
+ if (item->op.opptr != nullptr) {
WM_operator_properties_free(item->op.opptr);
MEM_freeN(item->op.opptr);
}
}
- case MENU_SEARCH_TYPE_RNA: {
+ case MenuSearch_Item::Type::RNA: {
break;
}
}
@@ -940,8 +945,8 @@ static void menu_search_arg_free_fn(void *data_v)
static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
{
- struct MenuSearch_Item *item = arg2;
- if (item == NULL) {
+ MenuSearch_Item *item = (MenuSearch_Item *)arg2;
+ if (item == nullptr) {
return;
}
if (item->state & UI_BUT_DISABLED) {
@@ -951,20 +956,20 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, item->wm_context->area);
CTX_wm_region_set(C, item->wm_context->region);
}
switch (item->type) {
- case MENU_SEARCH_TYPE_OP: {
+ case MenuSearch_Item::Type::Operator: {
CTX_store_set(C, item->op.context);
WM_operator_name_call_ptr_with_depends_on_cursor(
C, item->op.type, item->op.opcontext, item->op.opptr, item->drawstr);
- CTX_store_set(C, NULL);
+ CTX_store_set(C, nullptr);
break;
}
- case MENU_SEARCH_TYPE_RNA: {
+ case MenuSearch_Item::Type::RNA: {
PointerRNA *ptr = &item->rna.ptr;
PropertyRNA *prop = item->rna.prop;
const int index = item->rna.index;
@@ -995,7 +1000,7 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
}
}
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, area_prev);
CTX_wm_region_set(C, region_prev);
}
@@ -1007,19 +1012,19 @@ static void menu_search_update_fn(const bContext *UNUSED(C),
uiSearchItems *items,
const bool UNUSED(is_first))
{
- struct MenuSearch_Data *data = arg;
+ MenuSearch_Data *data = (MenuSearch_Data *)arg;
StringSearch *search = BLI_string_search_new();
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
- BLI_string_search_add(search, item->drawwstr_full, item);
+ LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
+ BLI_string_search_add(search, item->drawwstr_full, item, 0);
}
- struct MenuSearch_Item **filtered_items;
+ MenuSearch_Item **filtered_items;
const int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_items);
for (int i = 0; i < filtered_amount; i++) {
- struct MenuSearch_Item *item = filtered_items[i];
+ MenuSearch_Item *item = filtered_items[i];
if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state, 0)) {
break;
}
@@ -1044,8 +1049,8 @@ static bool ui_search_menu_create_context_menu(struct bContext *C,
void *active,
const struct wmEvent *event)
{
- struct MenuSearch_Data *data = arg;
- struct MenuSearch_Item *item = active;
+ MenuSearch_Data *data = (MenuSearch_Data *)arg;
+ MenuSearch_Item *item = (MenuSearch_Item *)active;
bool has_menu = false;
memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
@@ -1058,7 +1063,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C,
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, item->wm_context->area);
CTX_wm_region_set(C, item->wm_context->region);
}
@@ -1067,7 +1072,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C,
has_menu = true;
}
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, area_prev);
CTX_wm_region_set(C, region_prev);
}
@@ -1088,8 +1093,8 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
void *arg,
void *active)
{
- struct MenuSearch_Data *data = arg;
- struct MenuSearch_Item *item = active;
+ MenuSearch_Data *data = (MenuSearch_Data *)arg;
+ MenuSearch_Item *item = (MenuSearch_Item *)active;
memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
uiBut *but = &data->context_menu_data.but;
@@ -1102,8 +1107,8 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
/* Place the fake button at the cursor so the tool-tip is places properly. */
float tip_init[2];
const wmEvent *event = CTX_wm_window(C)->eventstate;
- tip_init[0] = event->x;
- tip_init[1] = event->y - (UI_UNIT_Y / 2);
+ tip_init[0] = event->xy[0];
+ tip_init[1] = event->xy[1] - (UI_UNIT_Y / 2);
ui_window_to_block_fl(region, block, &tip_init[0], &tip_init[1]);
but->rect.xmin = tip_init[0];
@@ -1115,21 +1120,21 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, item->wm_context->area);
CTX_wm_region_set(C, item->wm_context->region);
}
ARegion *region_tip = UI_tooltip_create_from_button(C, region, but, false);
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, area_prev);
CTX_wm_region_set(C, region_prev);
}
return region_tip;
}
- return NULL;
+ return nullptr;
}
/** \} */
@@ -1140,14 +1145,13 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
void UI_but_func_menu_search(uiBut *but)
{
- bContext *C = but->block->evil_C;
+ bContext *C = (bContext *)but->block->evil_C;
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
/* When run from top-bar scan all areas in the current window. */
const bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR));
- struct MenuSearch_Data *data = menu_items_from_ui_create(
- C, win, area, region, include_all_areas);
+ MenuSearch_Data *data = menu_items_from_ui_create(C, win, area, region, include_all_areas);
UI_but_func_search_set(but,
/* Generic callback. */
ui_searchbox_create_menu,
@@ -1156,11 +1160,11 @@ void UI_but_func_menu_search(uiBut *but)
false,
menu_search_arg_free_fn,
menu_search_exec_fn,
- NULL);
+ nullptr);
UI_but_func_search_set_context_menu(but, ui_search_menu_create_context_menu);
UI_but_func_search_set_tooltip(but, ui_search_menu_create_tooltip);
- UI_but_func_search_set_sep_string(but, MENU_SEP);
+ UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP);
}
void uiTemplateMenuSearch(uiLayout *layout)
@@ -1177,6 +1181,4 @@ void uiTemplateMenuSearch(uiLayout *layout)
UI_but_func_menu_search(but);
}
-#undef MENU_SEP
-
/** \} */
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 320371ad9ea..8330f8c0db7 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -435,7 +435,7 @@ static void id_search_cb(const bContext *C,
/* ID listbase */
LISTBASE_FOREACH (ID *, id, lb) {
if (id_search_allows_id(template_ui, flag, id, str)) {
- BLI_string_search_add(search, id->name + 2, id);
+ BLI_string_search_add(search, id->name + 2, id, 0);
}
}
@@ -470,7 +470,7 @@ static void id_search_cb_tagged(const bContext *C,
LISTBASE_FOREACH (ID *, id, lb) {
if (id->tag & LIB_TAG_DOIT) {
if (id_search_allows_id(template_ui, flag, id, str)) {
- BLI_string_search_add(search, id->name + 2, id);
+ BLI_string_search_add(search, id->name + 2, id, 0);
}
id->tag &= ~LIB_TAG_DOIT;
}
@@ -585,7 +585,6 @@ static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem)
/* This is for browsing and editing the ID-blocks used */
-/* for new/open operators */
void UI_context_active_but_prop_get_templateID(bContext *C,
PointerRNA *r_ptr,
PropertyRNA **r_prop)
@@ -1112,24 +1111,41 @@ static void template_ID(const bContext *C,
UI_but_flag_enable(but, UI_BUT_REDALERT);
}
- if (!ID_IS_LINKED(id) && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_OB, ID_WS)) &&
- (hide_buttons == false)) {
- uiDefIconButR(block,
- UI_BTYPE_ICON_TOGGLE,
- 0,
- ICON_FAKE_USER_OFF,
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- &idptr,
- "use_fake_user",
- -1,
- 0,
- 0,
- -1,
- -1,
- NULL);
+ if (!ID_IS_LINKED(id)) {
+ if (ID_IS_ASSET(id)) {
+ uiDefIconButO(block,
+ /* Using `_N` version allows us to get the 'active' state by default. */
+ UI_BTYPE_ICON_TOGGLE_N,
+ "ASSET_OT_clear",
+ WM_OP_INVOKE_DEFAULT,
+ /* 'active' state of a toggle button uses icon + 1, so to get proper asset
+ * icon we need to pass its value - 1 here. */
+ ICON_ASSET_MANAGER - 1,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL);
+ }
+ else if (!(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_OB, ID_WS)) &&
+ (hide_buttons == false)) {
+ uiDefIconButR(block,
+ UI_BTYPE_ICON_TOGGLE,
+ 0,
+ ICON_FAKE_USER_OFF,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ &idptr,
+ "use_fake_user",
+ -1,
+ 0,
+ 0,
+ -1,
+ -1,
+ NULL);
+ }
}
}
@@ -1539,9 +1555,6 @@ void uiTemplateGpencilColorPreview(uiLayout *layout,
false);
}
-/**
- * Version of #uiTemplateID using tabs.
- */
void uiTemplateIDTabs(uiLayout *layout,
bContext *C,
PointerRNA *ptr,
@@ -1575,14 +1588,6 @@ void uiTemplateIDTabs(uiLayout *layout,
/** \name ID Chooser Template
* \{ */
-/**
- * This is for selecting the type of ID-block to use,
- * and then from the relevant type choosing the block to use.
- *
- * \param propname: property identifier for property that ID-pointer gets stored to.
- * \param proptypename: property identifier for property
- * used to determine the type of ID-pointer that can be used.
- */
void uiTemplateAnyID(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -1724,7 +1729,7 @@ static void template_search_add_button_name(uiBlock *block,
static void template_search_add_button_operator(uiBlock *block,
const char *const operator_name,
- const int opcontext,
+ const wmOperatorCallContext opcontext,
const int icon,
const bool editable)
{
@@ -1838,10 +1843,6 @@ static TemplateSearch *template_search_setup(PointerRNA *ptr,
return template_search;
}
-/**
- * Search menu to pick an item from a collection.
- * A version of uiTemplateID that works for non-ID types.
- */
void uiTemplateSearch(uiLayout *layout,
bContext *C,
PointerRNA *ptr,
@@ -1892,13 +1893,6 @@ void uiTemplateSearchPreview(uiLayout *layout,
/* ---------- */
-/**
- * This is creating/editing RNA-Paths
- *
- * - ptr: struct which holds the path property
- * - propname: property identifier for property that path gets stored to
- * - root_ptr: struct that path gets built from
- */
void uiTemplatePathBuilder(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -2085,9 +2079,6 @@ static void bone_constraint_panel_id(void *md_link, char *r_name)
strcat(r_name, cti->structName);
}
-/**
- * Check if the constraint panels don't match the data and rebuild the panels if so.
- */
void uiTemplateConstraints(uiLayout *UNUSED(layout), bContext *C, bool use_bone_constraints)
{
ARegion *region = CTX_wm_region(C);
@@ -2243,8 +2234,6 @@ void uiTemplateGpencilModifiers(uiLayout *UNUSED(layout), bContext *C)
/** \} */
-/** \} */
-
#define ERROR_LIBDATA_MESSAGE TIP_("Can't edit external library data")
/* -------------------------------------------------------------------- */
@@ -2263,9 +2252,6 @@ static void shaderfx_panel_id(void *fx_v, char *r_idname)
BKE_shaderfxType_panel_id(fx->type, r_idname);
}
-/**
- * Check if the shader effect panels don't match the data and rebuild the panels if so.
- */
void uiTemplateShaderFx(uiLayout *UNUSED(layout), bContext *C)
{
ARegion *region = CTX_wm_region(C);
@@ -2364,7 +2350,7 @@ static eAutoPropButsReturn template_operator_property_buts_draw_single(
/* poll() on this operator may still fail,
* at the moment there is no nice feedback when this happens just fails silently. */
if (!WM_operator_repeat_check(C, op)) {
- UI_block_lock_set(block, true, "Operator can't' redo");
+ UI_block_lock_set(block, true, "Operator can't redo");
return return_info;
}
@@ -2547,11 +2533,6 @@ static bool ui_layout_operator_properties_only_booleans(const bContext *C,
return true;
}
-/**
- * Draw Operator property buttons for redoing execution with different settings.
- * This function does not initialize the layout,
- * functions can be called on the layout before and after.
- */
void uiTemplateOperatorPropertyButs(
const bContext *C, uiLayout *layout, wmOperator *op, eButLabelAlign label_align, short flag)
{
@@ -2691,7 +2672,7 @@ static void constraint_ops_extra_draw(bContext *C, uiLayout *layout, void *con_v
static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *con)
{
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
short proxy_protected, xco = 0, yco = 0;
// int rb_col; // UNUSED
@@ -2710,7 +2691,12 @@ static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *co
PointerRNA ptr;
RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
- uiLayoutSetContextPointer(layout, "constraint", &ptr);
+ if (block->panel) {
+ UI_panel_context_pointer_set(block->panel, "constraint", &ptr);
+ }
+ else {
+ uiLayoutSetContextPointer(layout, "constraint", &ptr);
+ }
/* Constraint type icon. */
uiLayout *sub = uiLayoutRow(layout, false);
@@ -2726,7 +2712,7 @@ static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *co
uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
}
else {
- uiItemL(row, con->name, ICON_NONE);
+ uiItemL(row, IFACE_(con->name), ICON_NONE);
}
/* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
@@ -3515,9 +3501,6 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname
/** \name Icon Template
* \{ */
-/**
- * \param icon_scale: Scale of the icon, 1x == button height.
- */
void uiTemplateIcon(uiLayout *layout, int icon_value, float icon_scale)
{
uiBlock *block = uiLayoutAbsoluteBlock(layout);
@@ -3626,9 +3609,6 @@ static uiBlock *ui_icon_view_menu_cb(bContext *C, ARegion *region, void *arg_lit
return block;
}
-/**
- * \param icon_scale: Scale of the icon, 1x == button height.
- */
void uiTemplateIconView(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -4135,51 +4115,6 @@ static uiBlock *curvemap_tools_func(
0,
UICURVE_FUNC_RESET_VIEW,
"");
- uiDefIconTextBut(block,
- UI_BTYPE_BUT_MENU,
- 1,
- ICON_BLANK1,
- IFACE_("Vector Handle"),
- 0,
- yco -= UI_UNIT_Y,
- menuwidth,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0,
- UICURVE_FUNC_HANDLE_VECTOR,
- "");
- uiDefIconTextBut(block,
- UI_BTYPE_BUT_MENU,
- 1,
- ICON_BLANK1,
- IFACE_("Auto Handle"),
- 0,
- yco -= UI_UNIT_Y,
- menuwidth,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0,
- UICURVE_FUNC_HANDLE_AUTO,
- "");
- uiDefIconTextBut(block,
- UI_BTYPE_BUT_MENU,
- 1,
- ICON_BLANK1,
- IFACE_("Auto Clamped Handle"),
- 0,
- yco -= UI_UNIT_Y,
- menuwidth,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0,
- UICURVE_FUNC_HANDLE_AUTO_ANIM,
- "");
}
if (show_extend) {
@@ -4259,6 +4194,21 @@ static uiBlock *curvemap_brush_tools_negslope_func(bContext *C, ARegion *region,
return curvemap_tools_func(C, region, cumap_v, false, UICURVE_FUNC_RESET_POS);
}
+static void curvemap_tools_handle_vector(bContext *C, void *cumap_v, void *UNUSED(arg))
+{
+ curvemap_tools_dofunc(C, cumap_v, UICURVE_FUNC_HANDLE_VECTOR);
+}
+
+static void curvemap_tools_handle_auto(bContext *C, void *cumap_v, void *UNUSED(arg))
+{
+ curvemap_tools_dofunc(C, cumap_v, UICURVE_FUNC_HANDLE_AUTO);
+}
+
+static void curvemap_tools_handle_auto_clamped(bContext *C, void *cumap_v, void *UNUSED(arg))
+{
+ curvemap_tools_dofunc(C, cumap_v, UICURVE_FUNC_HANDLE_AUTO_ANIM);
+}
+
static void curvemap_buttons_redraw(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
{
ED_region_tag_redraw(CTX_wm_region(C));
@@ -4310,6 +4260,8 @@ static void curvemap_buttons_layout(uiLayout *layout,
uiBlock *block = uiLayoutGetBlock(layout);
+ UI_block_emboss_set(block, UI_EMBOSS);
+
if (tone) {
uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
uiItemR(uiLayoutRow(split, false), ptr, "tone", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
@@ -4395,10 +4347,11 @@ static void curvemap_buttons_layout(uiLayout *layout,
}
/* operation buttons */
- uiLayoutRow(row, true);
-
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ /* (Right aligned) */
+ uiLayout *sub = uiLayoutRow(row, true);
+ uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
+ /* Zoom in */
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
@@ -4415,6 +4368,7 @@ static void curvemap_buttons_layout(uiLayout *layout,
TIP_("Zoom in"));
UI_but_func_set(bt, curvemap_buttons_zoom_in, cumap, NULL);
+ /* Zoom out */
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
@@ -4431,97 +4385,53 @@ static void curvemap_buttons_layout(uiLayout *layout,
TIP_("Zoom out"));
UI_but_func_set(bt, curvemap_buttons_zoom_out, cumap, NULL);
+ /* Clippoing button. */
+ const int icon = (cumap->flag & CUMA_DO_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
+ bt = uiDefIconBlockBut(
+ block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, TIP_("Clipping Options"));
+ bt->drawflag &= ~UI_BUT_ICON_LEFT;
+ UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
+
if (brush && neg_slope) {
- bt = uiDefIconBlockBut(block,
- curvemap_brush_tools_negslope_func,
- cumap,
- 0,
- ICON_DOWNARROW_HLT,
- 0,
- 0,
- dx,
- dx,
- TIP_("Tools"));
+ bt = uiDefIconBlockBut(
+ block, curvemap_brush_tools_negslope_func, cumap, 0, 0, 0, 0, dx, dx, TIP_("Tools"));
}
else if (brush) {
- bt = uiDefIconBlockBut(block,
- curvemap_brush_tools_func,
- cumap,
- 0,
- ICON_DOWNARROW_HLT,
- 0,
- 0,
- dx,
- dx,
- TIP_("Tools"));
+ bt = uiDefIconBlockBut(
+ block, curvemap_brush_tools_func, cumap, 0, 0, 0, 0, dx, dx, TIP_("Tools"));
}
else if (neg_slope) {
- bt = uiDefIconBlockBut(block,
- curvemap_tools_negslope_func,
- cumap,
- 0,
- ICON_DOWNARROW_HLT,
- 0,
- 0,
- dx,
- dx,
- TIP_("Tools"));
+ bt = uiDefIconBlockBut(
+ block, curvemap_tools_negslope_func, cumap, 0, 0, 0, 0, dx, dx, TIP_("Tools"));
}
else {
- bt = uiDefIconBlockBut(block,
- curvemap_tools_posslope_func,
- cumap,
- 0,
- ICON_DOWNARROW_HLT,
- 0,
- 0,
- dx,
- dx,
- TIP_("Tools"));
+ bt = uiDefIconBlockBut(
+ block, curvemap_tools_posslope_func, cumap, 0, 0, 0, 0, dx, dx, TIP_("Tools"));
}
-
UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
- const int icon = (cumap->flag & CUMA_DO_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
- bt = uiDefIconBlockBut(
- block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, TIP_("Clipping Options"));
- UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
-
- bt = uiDefIconBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_X,
- 0,
- 0,
- dx,
- dx,
- NULL,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- TIP_("Delete points"));
- UI_but_funcN_set(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
-
- UI_block_emboss_set(block, UI_EMBOSS);
-
UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL);
- /* curve itself */
+ /* Curve itself. */
const int size = max_ii(uiLayoutGetWidth(layout), UI_UNIT_X);
row = uiLayoutRow(layout, false);
uiButCurveMapping *curve_but = (uiButCurveMapping *)uiDefBut(
- block, UI_BTYPE_CURVE, 0, "", 0, 0, size, 8.0f * UI_UNIT_X, cumap, 0.0f, 1.0f, 0, 0, "");
+ block, UI_BTYPE_CURVE, 0, "", 0, 0, size, 8.0f * UI_UNIT_X, cumap, 0.0f, 1.0f, -1, 0, "");
curve_but->gradient_type = bg;
- /* sliders for selected point */
+ /* Sliders for selected curve point. */
+ int i;
CurveMapPoint *cmp = NULL;
- for (int i = 0; i < cm->totpoint; i++) {
+ bool point_last_or_first = false;
+ for (i = 0; i < cm->totpoint; i++) {
if (cm->curve[i].flag & CUMA_SELECT) {
cmp = &cm->curve[i];
break;
}
}
+ if (ELEM(i, 0, cm->totpoint - 1)) {
+ point_last_or_first = true;
+ }
if (cmp) {
rctf bounds;
@@ -4533,12 +4443,75 @@ static void curvemap_buttons_layout(uiLayout *layout,
bounds.xmax = bounds.ymax = 1000.0;
}
+ UI_block_emboss_set(block, UI_EMBOSS);
+
uiLayoutRow(layout, true);
+
+ /* Curve handle buttons. */
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 1,
+ ICON_HANDLE_AUTO,
+ 0,
+ UI_UNIT_Y,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Auto Handle"));
+ UI_but_func_set(bt, curvemap_tools_handle_auto, cumap, NULL);
+ if (((cmp->flag & CUMA_HANDLE_AUTO_ANIM) == false) &&
+ ((cmp->flag & CUMA_HANDLE_VECTOR) == false)) {
+ bt->flag |= UI_SELECT_DRAW;
+ }
+
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 1,
+ ICON_HANDLE_VECTOR,
+ 0,
+ UI_UNIT_Y,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Vector Handle"));
+ UI_but_func_set(bt, curvemap_tools_handle_vector, cumap, NULL);
+ if (cmp->flag & CUMA_HANDLE_VECTOR) {
+ bt->flag |= UI_SELECT_DRAW;
+ }
+
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 1,
+ ICON_HANDLE_AUTOCLAMPED,
+ 0,
+ UI_UNIT_Y,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Auto Clamped"));
+ UI_but_func_set(bt, curvemap_tools_handle_auto_clamped, cumap, NULL);
+ if (cmp->flag & CUMA_HANDLE_AUTO_ANIM) {
+ bt->flag |= UI_SELECT_DRAW;
+ }
+
+ /* Curve handle position */
UI_block_funcN_set(block, curvemap_buttons_update, MEM_dupallocN(cb), cumap);
bt = uiDefButF(block,
UI_BTYPE_NUM,
0,
- "X",
+ "X:",
0,
2 * UI_UNIT_Y,
UI_UNIT_X * 10,
@@ -4554,7 +4527,7 @@ static void curvemap_buttons_layout(uiLayout *layout,
bt = uiDefButF(block,
UI_BTYPE_NUM,
0,
- "Y",
+ "Y:",
0,
1 * UI_UNIT_Y,
UI_UNIT_X * 10,
@@ -4567,6 +4540,26 @@ static void curvemap_buttons_layout(uiLayout *layout,
"");
UI_but_number_step_size_set(bt, 1);
UI_but_number_precision_set(bt, 5);
+
+ /* Curve handle delete point */
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_X,
+ 0,
+ 0,
+ dx,
+ dx,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Delete points"));
+ UI_but_funcN_set(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
+ if (point_last_or_first) {
+ UI_but_flag_enable(bt, UI_BUT_DISABLED);
+ }
}
/* black/white levels */
@@ -5013,11 +5006,6 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
sub = uiLayoutRow(row, true);
uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
- /* Reset view, reset curve */
- bt = uiDefIconBlockBut(
- block, CurveProfile_buttons_tools, profile, 0, 0, 0, 0, UI_UNIT_X, UI_UNIT_X, TIP_("Tools"));
- UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
-
/* Flip path */
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
@@ -5053,6 +5041,11 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
TIP_("Toggle Profile Clipping"));
UI_but_funcN_set(bt, CurveProfile_clipping_toggle, MEM_dupallocN(cb), profile);
+ /* Reset view, reset curve */
+ bt = uiDefIconBlockBut(
+ block, CurveProfile_buttons_tools, profile, 0, 0, 0, 0, UI_UNIT_X, UI_UNIT_X, TIP_("Tools"));
+ UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
+
UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL);
/* The path itself */
@@ -5196,10 +5189,6 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
UI_block_funcN_set(block, NULL, NULL, NULL);
}
-/**
- * Template for a path creation widget intended for custom bevel profiles.
- * This section is quite similar to #uiTemplateCurveMapping, but with reduced complexity.
- */
void uiTemplateCurveProfile(uiLayout *layout, PointerRNA *ptr, const char *propname)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
@@ -5246,7 +5235,6 @@ void uiTemplateCurveProfile(uiLayout *layout, PointerRNA *ptr, const char *propn
#define WHEEL_SIZE (5 * U.widget_unit)
-/* This template now follows User Preference for type - name is not correct anymore... */
void uiTemplateColorPicker(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -5637,10 +5625,6 @@ static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
/* see view3d_header.c */
}
-/**
- * \todo for now, grouping of layers is determined by dividing up the length of
- * the array of layer bitflags
- */
void uiTemplateLayers(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -6125,8 +6109,8 @@ void uiTemplateInputStatus(uiLayout *layout, struct bContext *C)
uiLayout *row = uiLayoutRow(col, true);
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
- const char *msg = WM_window_cursor_keymap_status_get(win, i, 0);
- const char *msg_drag = WM_window_cursor_keymap_status_get(win, i, 1);
+ const char *msg = TIP_(WM_window_cursor_keymap_status_get(win, i, 0));
+ const char *msg_drag = TIP_(WM_window_cursor_keymap_status_get(win, i, 1));
if (msg || (msg_drag == NULL)) {
uiItemL(row, msg ? msg : "", (ICON_MOUSE_LMB + i));
@@ -6411,21 +6395,154 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float color[4])
/** \name Cache File Template
* \{ */
-void uiTemplateCacheFile(uiLayout *layout,
- const bContext *C,
- PointerRNA *ptr,
- const char *propname)
+void uiTemplateCacheFileVelocity(uiLayout *layout, PointerRNA *fileptr)
{
- if (!ptr->data) {
- return;
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiItemR(layout, fileptr, "velocity_name", 0, NULL, ICON_NONE);
+ uiItemR(layout, fileptr, "velocity_unit", 0, NULL, ICON_NONE);
+}
+
+void uiTemplateCacheFileProcedural(uiLayout *layout, const bContext *C, PointerRNA *fileptr)
+{
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiLayout *row, *sub;
+
+ /* Only enable render procedural option if the active engine supports it. */
+ const struct RenderEngineType *engine_type = CTX_data_engine_type(C);
+
+ Scene *scene = CTX_data_scene(C);
+ const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type,
+ scene);
+
+ if (!engine_supports_procedural) {
+ row = uiLayoutRow(layout, false);
+ /* For Cycles, verify that experimental features are enabled. */
+ if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) {
+ uiItemL(
+ row,
+ TIP_(
+ "The Cycles Alembic Procedural is only available with the experimental feature set"),
+ ICON_INFO);
+ }
+ else {
+ uiItemL(
+ row, TIP_("The active render engine does not have an Alembic Procedural"), ICON_INFO);
+ }
}
+ row = uiLayoutRow(layout, false);
+ uiLayoutSetActive(row, engine_supports_procedural);
+ uiItemR(row, fileptr, "use_render_procedural", 0, NULL, ICON_NONE);
+
+ const bool use_render_procedural = RNA_boolean_get(fileptr, "use_render_procedural");
+ const bool use_prefetch = RNA_boolean_get(fileptr, "use_prefetch");
+
+ row = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(row, use_render_procedural);
+ uiItemR(row, fileptr, "use_prefetch", 0, NULL, ICON_NONE);
+
+ sub = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(sub, use_prefetch && use_render_procedural);
+ uiItemR(sub, fileptr, "prefetch_cache_size", 0, NULL, ICON_NONE);
+}
+
+void uiTemplateCacheFileTimeSettings(uiLayout *layout, PointerRNA *fileptr)
+{
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiLayout *row, *sub, *subsub;
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, fileptr, "is_sequence", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame"));
+ sub = uiLayoutRow(row, true);
+ uiLayoutSetPropDecorate(sub, false);
+ uiItemR(sub, fileptr, "override_frame", 0, "", ICON_NONE);
+ subsub = uiLayoutRow(sub, true);
+ uiLayoutSetActive(subsub, RNA_boolean_get(fileptr, "override_frame"));
+ uiItemR(subsub, fileptr, "frame", 0, "", ICON_NONE);
+ uiItemDecoratorR(row, fileptr, "frame", 0);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, fileptr, "frame_offset", 0, NULL, ICON_NONE);
+ uiLayoutSetActive(row, !RNA_boolean_get(fileptr, "is_sequence"));
+}
+
+static void cache_file_layer_item(uiList *UNUSED(ui_list),
+ bContext *UNUSED(C),
+ uiLayout *layout,
+ PointerRNA *UNUSED(dataptr),
+ PointerRNA *itemptr,
+ int UNUSED(icon),
+ PointerRNA *UNUSED(active_dataptr),
+ const char *UNUSED(active_propname),
+ int UNUSED(index),
+ int UNUSED(flt_flag))
+{
+ uiLayout *row = uiLayoutRow(layout, true);
+ uiItemR(row, itemptr, "hide_layer", UI_ITEM_R_NO_BG, "", ICON_NONE);
+ uiItemR(row, itemptr, "filepath", UI_ITEM_R_NO_BG, "", ICON_NONE);
+}
+
+uiListType *UI_UL_cache_file_layers()
+{
+ uiListType *list_type = (uiListType *)MEM_callocN(sizeof(*list_type), __func__);
+
+ BLI_strncpy(list_type->idname, "UI_UL_cache_file_layers", sizeof(list_type->idname));
+ list_type->draw_item = cache_file_layer_item;
+
+ return list_type;
+}
+
+void uiTemplateCacheFileLayers(uiLayout *layout, const bContext *C, PointerRNA *fileptr)
+{
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayout *col = uiLayoutColumn(row, true);
+
+ uiTemplateList(col,
+ (bContext *)C,
+ "UI_UL_cache_file_layers",
+ "cache_file_layers",
+ fileptr,
+ "layers",
+ fileptr,
+ "active_index",
+ "",
+ 1,
+ 5,
+ UILST_LAYOUT_DEFAULT,
+ 1,
+ UI_TEMPLATE_LIST_FLAG_NONE);
+
+ col = uiLayoutColumn(row, true);
+ uiItemO(col, "", ICON_ADD, "cachefile.layer_add");
+ uiItemO(col, "", ICON_REMOVE, "cachefile.layer_remove");
+
+ CacheFile *file = fileptr->data;
+ if (BLI_listbase_count(&file->layers) > 1) {
+ uiItemS_ex(col, 1.0f);
+ uiItemO(col, "", ICON_TRIA_UP, "cachefile.layer_move");
+ uiItemO(col, "", ICON_TRIA_DOWN, "cachefile.layer_move");
+ }
+}
+
+bool uiTemplateCacheFilePointer(PointerRNA *ptr, const char *propname, PointerRNA *r_file_ptr)
+{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
if (!prop) {
printf(
"%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname);
- return;
+ return false;
}
if (RNA_property_type(prop) != PROP_POINTER) {
@@ -6433,10 +6550,27 @@ void uiTemplateCacheFile(uiLayout *layout,
__func__,
RNA_struct_identifier(ptr->type),
propname);
+ return false;
+ }
+
+ *r_file_ptr = RNA_property_pointer_get(ptr, prop);
+ return true;
+}
+
+void uiTemplateCacheFile(uiLayout *layout,
+ const bContext *C,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ if (!ptr->data) {
+ return;
+ }
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
return;
}
- PointerRNA fileptr = RNA_property_pointer_get(ptr, prop);
CacheFile *file = fileptr.data;
uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr);
@@ -6458,7 +6592,7 @@ void uiTemplateCacheFile(uiLayout *layout,
SpaceProperties *sbuts = CTX_wm_space_properties(C);
- uiLayout *row, *sub, *subsub;
+ uiLayout *row, *sub;
uiLayoutSetPropSep(layout, true);
@@ -6467,65 +6601,11 @@ void uiTemplateCacheFile(uiLayout *layout,
sub = uiLayoutRow(row, true);
uiItemO(sub, "", ICON_FILE_REFRESH, "cachefile.reload");
- row = uiLayoutRow(layout, false);
- uiItemR(row, &fileptr, "is_sequence", 0, NULL, ICON_NONE);
-
- /* Only enable render procedural option if the active engine supports it. */
- const struct RenderEngineType *engine_type = CTX_data_engine_type(C);
-
- Scene *scene = CTX_data_scene(C);
- const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type,
- scene);
-
- if (!engine_supports_procedural) {
- row = uiLayoutRow(layout, false);
- /* For Cycles, verify that experimental features are enabled. */
- if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) {
- uiItemL(row,
- "The Cycles Alembic Procedural is only available with the experimental feature set",
- ICON_INFO);
- }
- else {
- uiItemL(row, "The active render engine does not have an Alembic Procedural", ICON_INFO);
- }
- }
-
- row = uiLayoutRow(layout, false);
- uiLayoutSetActive(row, engine_supports_procedural);
- uiItemR(row, &fileptr, "use_render_procedural", 0, NULL, ICON_NONE);
-
- const bool use_render_procedural = RNA_boolean_get(&fileptr, "use_render_procedural");
- const bool use_prefetch = RNA_boolean_get(&fileptr, "use_prefetch");
-
- row = uiLayoutRow(layout, false);
- uiLayoutSetEnabled(row, use_render_procedural);
- uiItemR(row, &fileptr, "use_prefetch", 0, NULL, ICON_NONE);
-
- sub = uiLayoutRow(layout, false);
- uiLayoutSetEnabled(sub, use_prefetch && use_render_procedural);
- uiItemR(sub, &fileptr, "prefetch_cache_size", 0, NULL, ICON_NONE);
-
- row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame"));
- sub = uiLayoutRow(row, true);
- uiLayoutSetPropDecorate(sub, false);
- uiItemR(sub, &fileptr, "override_frame", 0, "", ICON_NONE);
- subsub = uiLayoutRow(sub, true);
- uiLayoutSetActive(subsub, RNA_boolean_get(&fileptr, "override_frame"));
- uiItemR(subsub, &fileptr, "frame", 0, "", ICON_NONE);
- uiItemDecoratorR(row, &fileptr, "frame", 0);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, &fileptr, "frame_offset", 0, NULL, ICON_NONE);
- uiLayoutSetActive(row, !RNA_boolean_get(&fileptr, "is_sequence"));
-
if (sbuts->mainb == BCONTEXT_CONSTRAINT) {
row = uiLayoutRow(layout, false);
uiItemR(row, &fileptr, "scale", 0, IFACE_("Manual Scale"), ICON_NONE);
}
- uiItemR(layout, &fileptr, "velocity_name", 0, NULL, ICON_NONE);
- uiItemR(layout, &fileptr, "velocity_unit", 0, NULL, ICON_NONE);
-
/* TODO: unused for now, so no need to expose. */
#if 0
row = uiLayoutRow(layout, false);
diff --git a/source/blender/editors/interface/interface_undo.c b/source/blender/editors/interface/interface_undo.c
index 40f196d9b45..6916e1080b6 100644
--- a/source/blender/editors/interface/interface_undo.c
+++ b/source/blender/editors/interface/interface_undo.c
@@ -91,11 +91,6 @@ const char *ui_textedit_undo(uiUndoStack_Text *stack, int direction, int *r_curs
return ui_textedit_redo_impl(stack, r_cursor_index);
}
-/**
- * Push the information in the arguments to a new state in the undo stack.
- *
- * \note Currently the total length of the undo stack is not limited.
- */
void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor_index)
{
/* Clear all redo actions from the current state. */
@@ -114,11 +109,7 @@ void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor
memcpy(stack->current->text, text, text_size);
BLI_addtail(&stack->states, stack->current);
}
-/**
- * Start the undo stack.
- *
- * \note The current state should be pushed immediately after calling this.
- */
+
uiUndoStack_Text *ui_textedit_undo_stack_create(void)
{
uiUndoStack_Text *stack = MEM_mallocN(sizeof(uiUndoStack_Text), __func__);
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 1a41dc8e9fb..84ec5f939d2 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -354,12 +354,6 @@ uiBut *uiDefAutoButR(uiBlock *block,
return but;
}
-/**
- * \a check_prop callback filters functions to avoid drawing certain properties,
- * in cases where PROP_HIDDEN flag can't be used for a property.
- *
- * \param prop_activate_init: Property to activate on initial popup (#UI_BUT_ACTIVATE_ON_INIT).
- */
eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
PointerRNA *ptr,
bool (*check_prop)(PointerRNA *ptr,
@@ -552,7 +546,7 @@ void ui_rna_collection_search_update_fn(const struct bContext *C,
cis->name_prefix_offset = name_prefix_offset;
cis->has_sep_char = has_sep_char;
if (!skip_filter) {
- BLI_string_search_add(search, name, cis);
+ BLI_string_search_add(search, name, cis, 0);
}
BLI_addtail(items_list, cis);
if (name != name_buf) {
@@ -593,7 +587,6 @@ void ui_rna_collection_search_update_fn(const struct bContext *C,
MEM_freeN(items_list);
}
-/***************************** ID Utilities *******************************/
int UI_icon_from_id(const ID *id)
{
if (id == NULL) {
@@ -618,7 +611,6 @@ int UI_icon_from_id(const ID *id)
return (ptr.type) ? RNA_struct_ui_icon(ptr.type) : ICON_NONE;
}
-/* see: report_type_str */
int UI_icon_from_report_type(int type)
{
if (type & RPT_ERROR_ALL) {
@@ -690,10 +682,6 @@ int UI_text_colorid_from_report_type(int type)
/********************************** Misc **************************************/
-/**
- * Returns the best "UI" precision for given floating value,
- * so that e.g. 10.000001 rather gets drawn as '10'...
- */
int UI_calc_float_precision(int prec, double value)
{
static const double pow10_neg[UI_PRECISION_FLOAT_MAX + 1] = {
@@ -839,16 +827,6 @@ static bool ui_view2d_cur_ensure_rect_in_view(View2D *v2d, const rctf *rect)
return changed;
}
-/**
- * Adjust the view so the rectangle of \a but is in view, with some extra margin.
- *
- * It's important that this is only executed after buttons received their final #uiBut.rect. E.g.
- * #UI_panels_end() modifies them, so if that is executed, this function must not be called before
- * it.
- *
- * \param region: The region the button is placed in. Make sure this is actually the one the button
- * is placed in, not just the context region.
- */
void UI_but_ensure_in_view(const bContext *C, ARegion *region, const uiBut *but)
{
View2D *v2d = &region->v2d;
@@ -892,9 +870,6 @@ struct uiButStoreElem {
uiBut **but_p;
};
-/**
- * Create a new button store, the caller must manage and run #UI_butstore_free
- */
uiButStore *UI_butstore_create(uiBlock *block)
{
uiButStore *bs_handle = MEM_callocN(sizeof(uiButStore), __func__);
@@ -966,9 +941,6 @@ void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p)
BLI_assert(0);
}
-/**
- * Update the pointer for a registered button.
- */
bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src)
{
bool found = false;
@@ -985,9 +957,6 @@ bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *bu
return found;
}
-/**
- * NULL all pointers, don't free since the owner needs to be able to inspect.
- */
void UI_butstore_clear(uiBlock *block)
{
LISTBASE_FOREACH (uiButStore *, bs_handle, &block->butstore) {
@@ -998,9 +967,6 @@ void UI_butstore_clear(uiBlock *block)
}
}
-/**
- * Map freed buttons from the old block and update pointers.
- */
void UI_butstore_update(uiBlock *block)
{
/* move this list to the new block */
diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc
index 7419f21cbc6..81b24c75020 100644
--- a/source/blender/editors/interface/interface_view.cc
+++ b/source/blender/editors/interface/interface_view.cc
@@ -26,6 +26,8 @@
#include <memory>
#include <variant>
+#include "DNA_screen_types.h"
+
#include "BLI_listbase.h"
#include "interface_intern.h"
@@ -44,7 +46,7 @@ struct ViewLink : public Link {
using TreeViewPtr = std::unique_ptr<AbstractTreeView>;
std::string idname;
- /* Note: Can't use std::get() on this until minimum macOS deployment target is 10.14. */
+ /* NOTE: Can't use std::get() on this until minimum macOS deployment target is 10.14. */
std::variant<TreeViewPtr> view;
};
@@ -54,14 +56,11 @@ template<class T> T *get_view_from_link(ViewLink &link)
return t_uptr ? t_uptr->get() : nullptr;
}
-/**
- * Override this for all available tree types.
- */
AbstractTreeView *UI_block_add_view(uiBlock &block,
StringRef idname,
std::unique_ptr<AbstractTreeView> tree_view)
{
- ViewLink *view_link = OBJECT_GUARDED_NEW(ViewLink);
+ ViewLink *view_link = MEM_new<ViewLink>(__func__);
BLI_addtail(&block.views, view_link);
view_link->view = std::move(tree_view);
@@ -73,10 +72,30 @@ AbstractTreeView *UI_block_add_view(uiBlock &block,
void ui_block_free_views(uiBlock *block)
{
LISTBASE_FOREACH_MUTABLE (ViewLink *, link, &block->views) {
- OBJECT_GUARDED_DELETE(link, ViewLink);
+ MEM_delete(link);
}
}
+uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const ARegion *region, const int xy[2])
+{
+ uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(region, xy);
+ if (!tree_row_but) {
+ return nullptr;
+ }
+
+ return tree_row_but->tree_item;
+}
+
+uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const ARegion *region)
+{
+ uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_active(region);
+ if (!tree_row_but) {
+ return nullptr;
+ }
+
+ return tree_row_but->tree_item;
+}
+
static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractTreeView &view)
{
/* First get the idname the of the view we're looking for. */
@@ -89,26 +108,71 @@ static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractT
return {};
}
+static AbstractTreeView *ui_block_view_find_matching_in_old_block(const uiBlock &new_block,
+ const AbstractTreeView &new_view)
+{
+ uiBlock *old_block = new_block.oldblock;
+ if (!old_block) {
+ return nullptr;
+ }
+
+ StringRef idname = ui_block_view_find_idname(new_block, new_view);
+ if (idname.is_empty()) {
+ return nullptr;
+ }
+
+ LISTBASE_FOREACH (ViewLink *, old_view_link, &old_block->views) {
+ if (old_view_link->idname == idname) {
+ return get_view_from_link<AbstractTreeView>(*old_view_link);
+ }
+ }
+
+ return nullptr;
+}
+
uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
const uiTreeViewHandle *new_view_handle)
{
- const AbstractTreeView &needle_view = reinterpret_cast<const AbstractTreeView &>(
- *new_view_handle);
+ BLI_assert(new_block && new_view_handle);
+ const AbstractTreeView &new_view = reinterpret_cast<const AbstractTreeView &>(*new_view_handle);
+ AbstractTreeView *old_view = ui_block_view_find_matching_in_old_block(*new_block, new_view);
+ return reinterpret_cast<uiTreeViewHandle *>(old_view);
+}
+
+uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
+ const uiTreeViewItemHandle *new_item_handle)
+{
uiBlock *old_block = new_block->oldblock;
if (!old_block) {
return nullptr;
}
- StringRef idname = ui_block_view_find_idname(*new_block, needle_view);
- if (idname.is_empty()) {
+ const AbstractTreeViewItem &new_item = *reinterpret_cast<const AbstractTreeViewItem *>(
+ new_item_handle);
+ const AbstractTreeView *old_tree_view = ui_block_view_find_matching_in_old_block(
+ *new_block, new_item.get_tree_view());
+ if (!old_tree_view) {
return nullptr;
}
- LISTBASE_FOREACH (ViewLink *, old_view_link, &old_block->views) {
- if (old_view_link->idname == idname) {
- return reinterpret_cast<uiTreeViewHandle *>(
- get_view_from_link<AbstractTreeView>(*old_view_link));
+ LISTBASE_FOREACH (uiBut *, old_but, &old_block->buttons) {
+ if (old_but->type != UI_BTYPE_TREEROW) {
+ continue;
+ }
+ uiButTreeRow *old_treerow_but = (uiButTreeRow *)old_but;
+ if (!old_treerow_but->tree_item) {
+ continue;
+ }
+ AbstractTreeViewItem &old_item = *reinterpret_cast<AbstractTreeViewItem *>(
+ old_treerow_but->tree_item);
+ /* Check if the row is from the expected tree-view. */
+ if (&old_item.get_tree_view() != old_tree_view) {
+ continue;
+ }
+
+ if (UI_tree_view_item_matches(new_item_handle, old_treerow_but->tree_item)) {
+ return old_treerow_but;
}
}
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 375206cab44..b44496731f7 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -26,6 +26,7 @@
#include <string.h>
#include "DNA_brush_types.h"
+#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "BLI_listbase.h"
@@ -45,6 +46,7 @@
#include "UI_interface.h"
#include "UI_interface_icons.h"
+#include "UI_view2d.h"
#include "interface_intern.h"
@@ -99,6 +101,10 @@ typedef enum {
UI_WTYPE_PULLDOWN,
UI_WTYPE_MENU_ITEM,
+ /* Same as #UI_WTYPE_MENU_ITEM, but doesn't add padding to sides for text & icon inside the
+ * widget. To be used when multiple menu items should be displayed close to each other
+ * horizontally. */
+ UI_WTYPE_MENU_ITEM_UNPADDED,
UI_WTYPE_MENU_ITEM_RADIAL,
UI_WTYPE_MENU_BACK,
@@ -114,7 +120,6 @@ typedef enum {
UI_WTYPE_LISTITEM,
UI_WTYPE_PROGRESSBAR,
UI_WTYPE_NODESOCKET,
- UI_WTYPE_DATASETROW,
UI_WTYPE_TREEROW,
} uiWidgetTypeEnum;
@@ -268,8 +273,9 @@ typedef struct uiWidgetType {
uiWidgetColors wcol;
void (*state)(struct uiWidgetType *, int state, int drawflag, eUIEmbossType emboss);
- void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign);
- void (*custom)(uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign);
+ void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign, const float zoom);
+ void (*custom)(
+ uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign, const float zoom);
void (*text)(const uiFontStyle *, const uiWidgetColors *, uiBut *, rcti *);
} uiWidgetType;
@@ -518,7 +524,7 @@ GPUBatch *ui_batch_roundbox_shadow_get(void)
/** \name Draw Triangle Arrow
* \{ */
-void UI_draw_anti_tria(
+static void draw_anti_tria(
float x1, float y1, float x2, float y2, float x3, float y3, const float color[4])
{
const float tri_arr[3][2] = {{x1, y1}, {x2, y2}, {x3, y3}};
@@ -551,7 +557,6 @@ void UI_draw_anti_tria(
GPU_blend(GPU_BLEND_NONE);
}
-/* Triangle 'icon' for panel header and other cases. */
void UI_draw_icon_tri(float x, float y, char dir, const float color[4])
{
const float f3 = 0.05 * U.widget_unit;
@@ -559,66 +564,31 @@ void UI_draw_icon_tri(float x, float y, char dir, const float color[4])
const float f7 = 0.25 * U.widget_unit;
if (dir == 'h') {
- UI_draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color);
+ draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color);
}
else if (dir == 't') {
- UI_draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3, color);
+ draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3, color);
}
else { /* 'v' = vertical, down. */
- UI_draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7, color);
+ draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7, color);
}
}
/* triangle 'icon' inside rect */
-void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4])
+static void draw_anti_tria_rect(const rctf *rect, char dir, const float color[4])
{
if (dir == 'h') {
const float half = 0.5f * BLI_rctf_size_y(rect);
- UI_draw_anti_tria(
+ draw_anti_tria(
rect->xmin, rect->ymin, rect->xmin, rect->ymax, rect->xmax, rect->ymin + half, color);
}
else {
const float half = 0.5f * BLI_rctf_size_x(rect);
- UI_draw_anti_tria(
+ draw_anti_tria(
rect->xmin, rect->ymax, rect->xmax, rect->ymax, rect->xmin + half, rect->ymin, color);
}
}
-void UI_draw_anti_fan(float tri_array[][2], uint length, const float color[4])
-{
- float draw_color[4];
-
- copy_v4_v4(draw_color, color);
- draw_color[3] *= 2.0f / WIDGET_AA_JITTER;
-
- GPU_blend(GPU_BLEND_ALPHA);
-
- const uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- immUniformColor4fv(draw_color);
-
- /* for each AA step */
- for (int j = 0; j < WIDGET_AA_JITTER; j++) {
- immBegin(GPU_PRIM_TRI_FAN, length);
- immVertex2f(pos, tri_array[0][0], tri_array[0][1]);
- immVertex2f(pos, tri_array[1][0], tri_array[1][1]);
-
- /* We jitter only the middle of the fan, the extremes are pinned. */
- for (int i = 2; i < length - 1; i++) {
- immVertex2f(pos, tri_array[i][0] + jit[j][0], tri_array[i][1] + jit[j][1]);
- }
-
- immVertex2f(pos, tri_array[length - 1][0], tri_array[length - 1][1]);
- immEnd();
- }
-
- immUnbindProgram();
-
- GPU_blend(GPU_BLEND_NONE);
-}
-
static void widget_init(uiWidgetBase *wtb)
{
wtb->totvert = wtb->halfwayvert = 0;
@@ -1442,8 +1412,8 @@ static void widget_draw_icon(
/* force positions to integers, for zoom levels near 1. draws icons crisp. */
if (aspect > 0.95f && aspect < 1.05f) {
- xs = (int)(xs + 0.1f);
- ys = (int)(ys + 0.1f);
+ xs = roundf(xs);
+ ys = roundf(ys);
}
/* Get theme color. */
@@ -1494,7 +1464,7 @@ static void widget_draw_submenu_tria(const uiBut *but,
GPU_blend(GPU_BLEND_ALPHA);
UI_widgetbase_draw_cache_flush();
GPU_blend(GPU_BLEND_NONE);
- ui_draw_anti_tria_rect(&tria_rect, 'h', col);
+ draw_anti_tria_rect(&tria_rect, 'h', col);
}
static void ui_text_clip_give_prev_off(uiBut *but, const char *str)
@@ -1549,17 +1519,6 @@ static void ui_text_clip_right_ex(const uiFontStyle *fstyle,
}
}
-/**
- * Cut off the middle of the text to fit into the given width.
- *
- * \note in case this middle clipping would just remove a few chars,
- * it rather clips right, which is more readable.
- *
- * If rpart_sep is not Null, the part of str starting to first occurrence of rpart_sep
- * is preserved at all cost.
- * Useful for strings with shortcuts
- * (like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
- */
float UI_text_clip_middle_ex(const uiFontStyle *fstyle,
char *str,
float okwidth,
@@ -2171,11 +2130,11 @@ static void widget_draw_text(const uiFontStyle *fstyle,
UI_fontstyle_draw_ex(fstyle,
rect,
drawstr + but->ofs,
+ drawlen,
wcol->text,
&(struct uiFontStyleDraw_Params){
.align = align,
},
- drawlen,
&font_xofs,
&font_yofs,
NULL);
@@ -2235,6 +2194,7 @@ static void widget_draw_text(const uiFontStyle *fstyle,
UI_fontstyle_draw(fstyle,
rect,
drawstr_right,
+ UI_MAX_DRAW_STR,
col,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_RIGHT,
@@ -2263,7 +2223,10 @@ static void widget_draw_extra_icons(const uiWidgetColors *wcol,
temp.xmin = temp.xmax - icon_size;
- if (!op_icon->highlighted) {
+ if (op_icon->disabled) {
+ alpha_this *= 0.4f;
+ }
+ else if (!op_icon->highlighted) {
alpha_this *= 0.75f;
}
@@ -2558,7 +2521,7 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossTyp
{
uiWidgetStateColors *wcol_state = wt->wcol_state;
- if ((state & UI_BUT_LIST_ITEM) && !(state & UI_STATE_TEXT_INPUT)) {
+ if (state & UI_BUT_LIST_ITEM) {
/* Override default widget's colors. */
bTheme *btheme = UI_GetTheme();
wt->wcol_theme = &btheme->tui.wcol_list_item;
@@ -2628,6 +2591,27 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossTyp
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Widget Corner Radius Calculation
+ *
+ * A lot of places of the UI like the Node Editor or panels are zoomable. In most cases we can
+ * get the zoom factor from the aspect, but in some cases like popups we need to fall back to
+ * using the the size of the element. The latter method relies on the element always being the same
+ * size.
+ * \{ */
+
+static float widget_radius_from_zoom(const float zoom, const uiWidgetColors *wcol)
+{
+ return wcol->roundness * U.widget_unit * zoom;
+}
+
+static float widget_radius_from_rcti(const rcti *rect, const uiWidgetColors *wcol)
+{
+ return wcol->roundness * BLI_rcti_size_y(rect);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Widget Types
* \{ */
@@ -2818,7 +2802,8 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r
immUnbindProgram();
}
-static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction)
+static void widget_menu_back(
+ uiWidgetColors *wcol, rcti *rect, int flag, int direction, const float zoom)
{
uiWidgetBase wtb;
int roundboxalign = UI_CNR_ALL;
@@ -2840,29 +2825,31 @@ static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int dir
}
GPU_blend(GPU_BLEND_ALPHA);
- widget_softshadow(rect, roundboxalign, wcol->roundness * U.widget_unit);
+ const float radius = widget_radius_from_zoom(zoom, wcol);
+ widget_softshadow(rect, roundboxalign, radius);
- round_box_edges(&wtb, roundboxalign, rect, wcol->roundness * U.widget_unit);
+ round_box_edges(&wtb, roundboxalign, rect, radius);
wtb.draw_emboss = false;
widgetbase_draw(&wtb, wcol);
GPU_blend(GPU_BLEND_NONE);
}
-static void ui_hsv_cursor(float x, float y)
+static void ui_hsv_cursor(const float x, const float y, const float zoom)
{
+ const float radius = zoom * 3.0f * U.pixelsize;
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3f(1.0f, 1.0f, 1.0f);
- imm_draw_circle_fill_2d(pos, x, y, 3.0f * U.pixelsize, 8);
+ imm_draw_circle_fill_2d(pos, x, y, radius, 8);
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_smooth(true);
immUniformColor3f(0.0f, 0.0f, 0.0f);
- imm_draw_circle_wire_2d(pos, x, y, 3.0f * U.pixelsize, 12);
+ imm_draw_circle_wire_2d(pos, x, y, radius, 12);
GPU_blend(GPU_BLEND_NONE);
GPU_line_smooth(false);
@@ -2883,7 +2870,6 @@ void ui_hsvcircle_vals_from_pos(
*r_val_rad = atan2f(m_delta[0], m_delta[1]) / (2.0f * (float)M_PI) + 0.5f;
}
-/* cursor in hsv circle, in float units -1 to 1, to map on radius */
void ui_hsvcircle_pos_from_vals(
const ColorPicker *cpicker, const rcti *rect, const float *hsv, float *r_xpos, float *r_ypos)
{
@@ -3010,7 +2996,8 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const
float xpos, ypos;
ui_hsvcircle_pos_from_vals(cpicker, rect, hsv, &xpos, &ypos);
- ui_hsv_cursor(xpos, ypos);
+ const float zoom = 1.0f / but->block->aspect;
+ ui_hsv_cursor(xpos, ypos, zoom);
}
/** \} */
@@ -3019,7 +3006,6 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const
/** \name Draw Custom Buttons
* \{ */
-/* draws in resolution of 48x4 colors */
void ui_draw_gradient(const rcti *rect,
const float hsv[3],
const eButGradientType type,
@@ -3244,7 +3230,9 @@ static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
CLAMP(x, rect->xmin + 3.0f, rect->xmax - 3.0f);
CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
- ui_hsv_cursor(x, y);
+ const float zoom = 1.0f / but->block->aspect;
+
+ ui_hsv_cursor(x, y, zoom);
/* outline */
const uint pos = GPU_vertformat_attr_add(
@@ -3307,8 +3295,9 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
x = rect->xmin + 0.5f * BLI_rcti_size_x(rect);
y = rect->ymin + v * BLI_rcti_size_y(rect);
CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
+ const float zoom = 1.0f / but->block->aspect;
- ui_hsv_cursor(x, y);
+ ui_hsv_cursor(x, y, zoom);
}
/** Separator for menus. */
@@ -3347,9 +3336,9 @@ static void ui_draw_separator(const rcti *rect, const uiWidgetColors *wcol)
* \{ */
static void widget_numbut_draw(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, bool emboss)
+ uiWidgetColors *wcol, rcti *rect, const float zoom, int state, int roundboxalign, bool emboss)
{
- const float rad = wcol->roundness * BLI_rcti_size_y(rect);
+ const float rad = widget_radius_from_zoom(zoom, wcol);
const int handle_width = min_ii(BLI_rcti_size_x(rect) / 3, BLI_rcti_size_y(rect) * 0.7f);
if (state & UI_SELECT) {
@@ -3448,17 +3437,19 @@ static void widget_numbut_draw(
}
}
-static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_numbut(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
- widget_numbut_draw(wcol, rect, state, roundboxalign, false);
+ widget_numbut_draw(wcol, rect, zoom, state, roundboxalign, false);
}
-static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_menubut(
+ uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
/* decoration */
@@ -3497,13 +3488,16 @@ static void widget_menubut_embossn(const uiBut *UNUSED(but),
/**
* Draw number buttons still with triangles when field is not embossed
*/
-static void widget_numbut_embossn(
- const uiBut *UNUSED(but), uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_numbut_embossn(const uiBut *UNUSED(but),
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int state,
+ int roundboxalign,
+ const float zoom)
{
- widget_numbut_draw(wcol, rect, state, roundboxalign, true);
+ widget_numbut_draw(wcol, rect, zoom, state, roundboxalign, true);
}
-/* function in use for buttons and for view2d sliders */
void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
{
uiWidgetBase wtb;
@@ -3591,8 +3585,12 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
}
}
-static void widget_scroll(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
+static void widget_scroll(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int state,
+ int UNUSED(roundboxalign),
+ const float UNUSED(zoom))
{
/* calculate slider part */
const float value = (float)ui_but_value_get(but);
@@ -3649,8 +3647,12 @@ static void widget_scroll(
UI_draw_widget_scroll(wcol, rect, &rect1, state);
}
-static void widget_progressbar(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_progressbar(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int roundboxalign,
+ const float zoom)
{
uiButProgressbar *but_progressbar = (uiButProgressbar *)but;
rcti rect_prog = *rect, rect_bar = *rect;
@@ -3661,7 +3663,7 @@ static void widget_progressbar(
/* round corners */
const float value = but_progressbar->progress;
- const float ofs = wcol->roundness * BLI_rcti_size_y(&rect_prog);
+ const float ofs = widget_radius_from_zoom(zoom, wcol);
float w = value * BLI_rcti_size_x(&rect_prog);
/* Ensure minimum size. */
@@ -3680,15 +3682,19 @@ static void widget_progressbar(
widgetbase_draw(&wtb_bar, wcol);
}
-static void widget_treerow_exec(
- uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign), int indentation)
+static void widget_treerow_exec(uiWidgetColors *wcol,
+ rcti *rect,
+ int state,
+ int UNUSED(roundboxalign),
+ int indentation,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
/* no outline */
wtb.draw_outline = false;
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
if ((state & UI_ACTIVE) || (state & UI_SELECT)) {
@@ -3700,25 +3706,21 @@ static void widget_treerow_exec(
}
static void widget_treerow(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+ uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
uiButTreeRow *tree_row = (uiButTreeRow *)but;
BLI_assert(but->type == UI_BTYPE_TREEROW);
- widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation);
-}
-
-static void widget_datasetrow(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
-{
- uiButDatasetRow *dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
- widget_treerow_exec(wcol, rect, state, roundboxalign, dataset_row->indentation);
+ widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation, zoom);
}
-static void widget_nodesocket(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+static void widget_nodesocket(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float UNUSED(zoom))
{
- const int radi = 5;
+ const int radi = 0.25f * BLI_rcti_size_y(rect);
uiWidgetBase wtb;
widget_init(&wtb);
@@ -3751,14 +3753,14 @@ static void widget_nodesocket(
}
static void widget_numslider(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+ uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
uiWidgetBase wtb, wtb1;
widget_init(&wtb);
widget_init(&wtb1);
/* Backdrop first. */
- const float ofs = wcol->roundness * BLI_rcti_size_y(rect);
+ const float ofs = widget_radius_from_zoom(zoom, wcol);
const float toffs = ofs * 0.75f;
round_box_edges(&wtb, roundboxalign, rect, ofs);
@@ -3861,7 +3863,7 @@ static void widget_numslider(
#define SWATCH_KEYED_BORDER 3
static void widget_swatch(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+ uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
BLI_assert(but->type == UI_BTYPE_COLOR);
uiButColor *color_but = (uiButColor *)but;
@@ -3880,7 +3882,7 @@ static void widget_swatch(
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
ui_but_v3_get(but, col);
@@ -3945,14 +3947,19 @@ static void widget_swatch(
}
}
-static void widget_unitvec(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+static void widget_unitvec(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float zoom)
{
- ui_draw_but_UNITVEC(but, wcol, rect);
+ const float rad = widget_radius_from_zoom(zoom, wcol);
+ ui_draw_but_UNITVEC(but, wcol, rect, rad);
}
static void widget_icon_has_anim(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+ uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT) &&
but->emboss != UI_EMBOSS_NONE) {
@@ -3960,14 +3967,14 @@ static void widget_icon_has_anim(
widget_init(&wtb);
wtb.draw_outline = false;
- const float rad = wcol->roundness * BLI_rcti_size_y(rect);
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
}
else if (but->type == UI_BTYPE_NUM) {
/* Draw number buttons still with left/right
* triangles when field is not embossed */
- widget_numbut_embossn(but, wcol, rect, state, roundboxalign);
+ widget_numbut_embossn(but, wcol, rect, state, roundboxalign, zoom);
}
else if (but->type == UI_BTYPE_MENU) {
/* Draw menu buttons still with down arrow. */
@@ -3975,7 +3982,8 @@ static void widget_icon_has_anim(
}
}
-static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_textbut(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
if (state & UI_SELECT) {
SWAP(short, wcol->shadetop, wcol->shadedown);
@@ -3984,43 +3992,46 @@ static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roun
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
-static void widget_preview_tile(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+static void widget_preview_tile(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float UNUSED(zoom))
{
const uiStyle *style = UI_style_get();
ui_draw_preview_item_stateless(
&style->widget, rect, but->drawstr, but->icon, wcol->text, UI_STYLE_TEXT_CENTER);
}
-static void widget_menuiconbut(uiWidgetColors *wcol,
- rcti *rect,
- int UNUSED(state),
- int roundboxalign)
+static void widget_menuiconbut(
+ uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
/* decoration */
widgetbase_draw(&wtb, wcol);
}
-static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_pulldownbut(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
float back[4];
UI_GetThemeColor4fv(TH_BACK, back);
if ((state & UI_ACTIVE) || (back[3] < 1.0f)) {
uiWidgetBase wtb;
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
if (state & UI_ACTIVE) {
copy_v4_v4_uchar(wcol->inner, wcol->inner_sel);
@@ -4044,20 +4055,54 @@ static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int
static void widget_menu_itembut(uiWidgetColors *wcol,
rcti *rect,
int UNUSED(state),
- int UNUSED(roundboxalign))
+ int UNUSED(roundboxalign),
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- /* not rounded, no outline */
+ /* Padding on the sides. */
+ const float padding = zoom * 0.125f * U.widget_unit;
+ rect->xmin += padding;
+ rect->xmax -= padding;
+
+ /* No outline. */
wtb.draw_outline = false;
- round_box_edges(&wtb, 0, rect, 0.0f);
+
+ const float rad = widget_radius_from_zoom(zoom, wcol);
+
+ round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
}
-static void widget_menu_radial_itembut(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+static void widget_menu_itembut_unpadded(uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float zoom)
+{
+ /* This function is used for menu items placed close to each other horizontally, e.g. the matcap
+ * preview popup or the row of collection color icons in the Outliner context menu. Don't use
+ * padding on the sides like the normal menu item. */
+
+ uiWidgetBase wtb;
+ widget_init(&wtb);
+
+ /* No outline. */
+ wtb.draw_outline = false;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
+ round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
+
+ widgetbase_draw(&wtb, wcol);
+}
+
+static void widget_menu_radial_itembut(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float zoom)
{
const float fac = but->block->pie_data.alphafac;
@@ -4066,7 +4111,7 @@ static void widget_menu_radial_itembut(
wtb.draw_emboss = false;
- const float rad = wcol->roundness * BLI_rcti_size_y(rect);
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
wcol->inner[3] *= fac;
@@ -4082,14 +4127,15 @@ static void widget_menu_radial_itembut(
static void widget_list_itembut(uiWidgetColors *wcol,
rcti *rect,
int UNUSED(state),
- int UNUSED(roundboxalign))
+ int UNUSED(roundboxalign),
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
/* no outline */
wtb.draw_outline = false;
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
@@ -4098,7 +4144,8 @@ static void widget_list_itembut(uiWidgetColors *wcol,
static void widget_optionbut(uiWidgetColors *wcol,
rcti *rect,
int state,
- int UNUSED(roundboxalign))
+ int UNUSED(roundboxalign),
+ const float UNUSED(zoom))
{
const bool text_before_widget = (state & UI_STATE_TEXT_BEFORE_WIDGET);
rcti recttemp = *rect;
@@ -4121,7 +4168,7 @@ static void widget_optionbut(uiWidgetColors *wcol,
/* Keep one edge in place. */
BLI_rcti_translate(&recttemp, text_before_widget ? delta : -delta, 0);
- const float rad = wcol->roundness * BLI_rcti_size_y(&recttemp);
+ const float rad = widget_radius_from_rcti(&recttemp, wcol);
round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
/* decoration */
@@ -4168,19 +4215,24 @@ static void widget_state_label(uiWidgetType *wt, int state, int drawflag, eUIEmb
}
}
-static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_radiobut(
+ uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
-static void widget_box(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_box(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4196,7 +4248,7 @@ static void widget_box(
wcol->inner[3] = but->col[3];
}
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
@@ -4204,12 +4256,13 @@ static void widget_box(
copy_v3_v3_uchar(wcol->inner, old_col);
}
-static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_but(
+ uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
@@ -4230,10 +4283,9 @@ static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state),
}
#endif
-static void widget_roundbut_exec(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_roundbut_exec(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
- const float rad = wcol->roundness * U.widget_unit;
-
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4242,15 +4294,18 @@ static void widget_roundbut_exec(uiWidgetColors *wcol, rcti *rect, int state, in
shape_preset_init_hold_action(&wtb.tria1, rect, 0.75f, 'r');
}
+ const float rad = widget_radius_from_zoom(zoom, wcol);
+
/* half rounded */
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
-static void widget_tab(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_tab(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
const bool is_active = (state & UI_SELECT);
/* Draw shaded outline - Disabled for now,
@@ -4447,6 +4502,12 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.state = widget_state_menu_item;
break;
+ case UI_WTYPE_MENU_ITEM_UNPADDED:
+ wt.wcol_theme = &btheme->tui.wcol_menu_item;
+ wt.draw = widget_menu_itembut_unpadded;
+ wt.state = widget_state_menu_item;
+ break;
+
case UI_WTYPE_MENU_BACK:
wt.wcol_theme = &btheme->tui.wcol_menu_back;
wt.draw = widget_menu_back;
@@ -4502,10 +4563,6 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.custom = widget_progressbar;
break;
- case UI_WTYPE_DATASETROW:
- wt.custom = widget_datasetrow;
- break;
-
case UI_WTYPE_TREEROW:
wt.custom = widget_treerow;
break;
@@ -4591,11 +4648,12 @@ static int widget_roundbox_set(uiBut *but, rcti *rect)
return roundbox;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Public API
* \{ */
-/* conversion from old to new buttons, so still messy */
void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBut *but, rcti *rect)
{
bTheme *btheme = UI_GetTheme();
@@ -4612,9 +4670,12 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
case UI_BTYPE_SEPR_LINE:
ui_draw_separator(rect, &tui->wcol_menu_item);
break;
- default:
- wt = widget_type(UI_WTYPE_MENU_ITEM);
+ default: {
+ const bool use_unpadded = (but->flag & UI_BUT_ICON_PREVIEW) ||
+ ((but->flag & UI_HAS_ICON) && !but->drawstr[0]);
+ wt = widget_type(use_unpadded ? UI_WTYPE_MENU_ITEM_UNPADDED : UI_WTYPE_MENU_ITEM);
break;
+ }
}
}
else if (ELEM(but->emboss, UI_EMBOSS_NONE, UI_EMBOSS_NONE_OR_STATUS)) {
@@ -4623,6 +4684,9 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
switch (but->type) {
case UI_BTYPE_LABEL:
wt = widget_type(UI_WTYPE_ICON_LABEL);
+ if (!(but->flag & UI_HAS_ICON)) {
+ but->drawflag |= UI_BUT_NO_TEXT_PADDING;
+ }
break;
default:
wt = widget_type(UI_WTYPE_ICON);
@@ -4822,9 +4886,6 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
break;
case UI_BTYPE_CURVE:
- /* do not draw right to edge of rect */
- rect->xmin += (0.2f * UI_UNIT_X);
- rect->xmax -= (0.2f * UI_UNIT_X);
ui_draw_but_CURVE(region, but, &tui->wcol_regular, rect);
break;
@@ -4837,11 +4898,6 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
fstyle = &style->widgetlabel;
break;
- case UI_BTYPE_DATASETROW:
- wt = widget_type(UI_WTYPE_DATASETROW);
- fstyle = &style->widgetlabel;
- break;
-
case UI_BTYPE_TREEROW:
wt = widget_type(UI_WTYPE_TREEROW);
fstyle = &style->widgetlabel;
@@ -4923,12 +4979,13 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
}
#endif
+ const float zoom = 1.0f / but->block->aspect;
wt->state(wt, state, drawflag, but->emboss);
if (wt->custom) {
- wt->custom(but, &wt->wcol, rect, state, roundboxalign);
+ wt->custom(but, &wt->wcol, rect, state, roundboxalign, zoom);
}
else if (wt->draw) {
- wt->draw(&wt->wcol, rect, state, roundboxalign);
+ wt->draw(&wt->wcol, rect, state, roundboxalign, zoom);
}
if (wt->text) {
@@ -4971,40 +5028,17 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
if (block) {
- wt->draw(&wt->wcol, rect, block->flag, block->direction);
+ const float zoom = 1.0f / block->aspect;
+ wt->draw(&wt->wcol, rect, block->flag, block->direction, zoom);
}
else {
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
}
ui_draw_clip_tri(block, rect, wt);
}
/**
- * Uses the widget base drawing and colors from the box widget, but ensures an opaque
- * inner color.
- */
-void ui_draw_box_opaque(rcti *rect, int roundboxalign)
-{
- uiWidgetType *wt = widget_type(UI_WTYPE_BOX);
-
- /* Alpha blend with the region's background color to force an opaque background. */
- uiWidgetColors *wcol = &wt->wcol;
- wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
- float background[4];
- UI_GetThemeColor4fv(TH_BACK, background);
- float new_inner[4];
- rgba_uchar_to_float(new_inner, wcol->inner);
- new_inner[0] = (new_inner[0] * new_inner[3]) + (background[0] * (1.0f - new_inner[3]));
- new_inner[1] = (new_inner[1] * new_inner[3]) + (background[1] * (1.0f - new_inner[3]));
- new_inner[2] = (new_inner[2] * new_inner[3]) + (background[2] * (1.0f - new_inner[3]));
- new_inner[3] = 1.0f;
- rgba_float_to_uchar(wcol->inner, new_inner);
-
- wt->custom(NULL, wcol, rect, 0, roundboxalign);
-}
-
-/**
* Similar to 'widget_menu_back', however we can't use the widget preset system
* because we need to pass in the original location so we know where to show the arrow.
*/
@@ -5092,8 +5126,9 @@ void ui_draw_popover_back(struct ARegion *region,
wt->wcol_theme, rect, block->direction, U.widget_unit / block->aspect, mval_origin);
}
else {
+ const float zoom = 1.0f / block->aspect;
wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, zoom);
}
ui_draw_clip_tri(block, rect, wt);
@@ -5285,7 +5320,7 @@ static void ui_draw_widget_back_color(uiWidgetTypeEnum type,
if (color) {
rgba_float_to_uchar(wt->wcol.inner, color);
}
- wt->draw(&wt->wcol, &rect_copy, 0, UI_CNR_ALL);
+ wt->draw(&wt->wcol, &rect_copy, 0, UI_CNR_ALL, 1.0f);
}
void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const float color[4])
{
@@ -5302,18 +5337,9 @@ void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(bl
uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP);
wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
/* wt->draw ends up using same function to draw the tooltip as menu_back */
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
}
-/**
- * Helper call to draw a menu item without a button.
- *
- * \param state: The state of the button,
- * typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
- * \param separator_type: The kind of separator which controls if and how the string is clipped.
- * \param r_xmax: The right hand position of the text, this takes into the icon,
- * padding and text clipping when there is not enough room to display the full text.
- */
void ui_draw_menu_item(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
@@ -5330,7 +5356,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
char *cpoin = NULL;
wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
UI_fontstyle_set(fstyle);
@@ -5371,7 +5397,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
}
}
else {
- BLI_assert_msg(0, "Unknwon menu item separator type");
+ BLI_assert_msg(0, "Unknown menu item separator type");
}
}
}
@@ -5392,11 +5418,11 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
UI_fontstyle_draw_ex(fstyle,
rect,
drawstr,
+ sizeof(drawstr),
wt->wcol.text,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_LEFT,
},
- BLF_DRAW_STR_DUMMY_MAX,
&xofs,
&yofs,
&info);
@@ -5443,6 +5469,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
UI_fontstyle_draw(fstyle,
rect,
hint_drawstr,
+ sizeof(hint_drawstr),
wt->wcol.text,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_RIGHT,
@@ -5452,10 +5479,6 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
}
}
-/**
- * Version of #ui_draw_preview_item() that does not draw the menu background and item text based on
- * state. It just draws the preview and text directly.
- */
void ui_draw_preview_item_stateless(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
@@ -5502,6 +5525,7 @@ void ui_draw_preview_item_stateless(const uiFontStyle *fstyle,
UI_fontstyle_draw(fstyle,
&trect,
drawstr,
+ sizeof(drawstr),
text_col,
&(struct uiFontStyleDraw_Params){
.align = text_align,
@@ -5516,11 +5540,11 @@ void ui_draw_preview_item(const uiFontStyle *fstyle,
int state,
eFontStyle_Align text_align)
{
- uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
+ uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM_UNPADDED);
/* drawing button background */
wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
ui_draw_preview_item_stateless(fstyle, rect, name, iconid, wt->wcol.text, text_align);
}
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index e13b69a9763..3b511e23384 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -85,7 +85,7 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
ThemeSpace *ts = NULL;
static uchar error[4] = {240, 0, 240, 255};
static uchar alert[4] = {240, 60, 60, 255};
- static uchar headerdesel[4] = {0, 0, 0, 255};
+ static uchar header_active[4] = {0, 0, 0, 255};
static uchar back[4] = {0, 0, 0, 255};
static uchar setting = 0;
const uchar *cp = error;
@@ -249,15 +249,18 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_HEADER:
cp = ts->header;
break;
- case TH_HEADERDESEL:
- /* We calculate a dynamic builtin header deselect color, also for pull-downs. */
+
+ case TH_HEADER_ACTIVE:
cp = ts->header;
- headerdesel[0] = cp[0] > 10 ? cp[0] - 10 : 0;
- headerdesel[1] = cp[1] > 10 ? cp[1] - 10 : 0;
- headerdesel[2] = cp[2] > 10 ? cp[2] - 10 : 0;
- headerdesel[3] = cp[3];
- cp = headerdesel;
+ const int factor = 5;
+ /* Lighten the header color when editor is active. */
+ header_active[0] = cp[0] > 245 ? cp[0] - factor : cp[0] + factor;
+ header_active[1] = cp[1] > 245 ? cp[1] - factor : cp[1] + factor;
+ header_active[2] = cp[2] > 245 ? cp[2] - factor : cp[2] + factor;
+ header_active[3] = cp[3];
+ cp = header_active;
break;
+
case TH_HEADER_TEXT:
cp = ts->header_text;
break;
@@ -1032,12 +1035,6 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
return (const uchar *)cp;
}
-/**
- * Initialize default theme.
- *
- * \note When you add new colors, created & saved themes need initialized
- * use function below, #init_userdef_do_versions.
- */
void UI_theme_init_default(void)
{
/* we search for the theme with name Default */
@@ -1088,9 +1085,6 @@ bTheme *UI_GetTheme(void)
return U.themes.first;
}
-/**
- * For the rare case we need to temp swap in a different theme (off-screen render).
- */
void UI_Theme_Store(struct bThemeState *theme_state)
{
*theme_state = g_theme_state;
@@ -1160,21 +1154,18 @@ void UI_FontThemeColor(int fontid, int colorid)
BLF_color4ubv(fontid, color);
}
-/* get individual values, not scaled */
float UI_GetThemeValuef(int colorid)
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
return ((float)cp[0]);
}
-/* get individual values, not scaled */
int UI_GetThemeValue(int colorid)
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
return ((int)cp[0]);
}
-/* versions of the function above, which take a space-type */
float UI_GetThemeValueTypef(int colorid, int spacetype)
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, spacetype, colorid);
@@ -1187,7 +1178,6 @@ int UI_GetThemeValueType(int colorid, int spacetype)
return ((int)cp[0]);
}
-/* get the color, range 0.0-1.0 */
void UI_GetThemeColor3fv(int colorid, float col[3])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1214,7 +1204,6 @@ void UI_GetThemeColorType4fv(int colorid, int spacetype, float col[4])
col[3] = ((float)cp[3]) / 255.0f;
}
-/* get the color, range 0.0-1.0, complete with shading offset */
void UI_GetThemeColorShade3fv(int colorid, int offset, float col[3])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1337,7 +1326,8 @@ void UI_GetThemeColorBlendShade4fv(int colorid1, int colorid2, float fac, int of
CLAMP(g, 0, 255);
b = offset + floorf((1.0f - fac) * cp1[2] + fac * cp2[2]);
CLAMP(b, 0, 255);
- a = offset + floorf((1.0f - fac) * cp1[3] + fac * cp2[3]);
+
+ a = floorf((1.0f - fac) * cp1[3] + fac * cp2[3]); /* No shading offset. */
CLAMP(a, 0, 255);
col[0] = ((float)r) / 255.0f;
@@ -1346,7 +1336,6 @@ void UI_GetThemeColorBlendShade4fv(int colorid1, int colorid2, float fac, int of
col[3] = ((float)a) / 255.0f;
}
-/* get the color, in char pointer */
void UI_GetThemeColor3ubv(int colorid, uchar col[3])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1355,7 +1344,6 @@ void UI_GetThemeColor3ubv(int colorid, uchar col[3])
col[2] = cp[2];
}
-/* get the color, range 0.0-1.0, complete with shading offset */
void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1377,7 +1365,6 @@ void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4])
col[3] = ((float)a) / 255.0f;
}
-/* get the color, in char pointer */
void UI_GetThemeColor4ubv(int colorid, uchar col[4])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1455,7 +1442,6 @@ void UI_GetColorPtrShade3ubv(const uchar cp[3], uchar col[3], int offset)
col[2] = b;
}
-/* get a 3 byte color, blended and shaded between two other char color pointers */
void UI_GetColorPtrBlendShade3ubv(
const uchar cp1[3], const uchar cp2[3], uchar col[3], float fac, int offset)
{
diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc
index ee50126f974..3010aaba5a3 100644
--- a/source/blender/editors/interface/tree_view.cc
+++ b/source/blender/editors/interface/tree_view.cc
@@ -19,11 +19,19 @@
*/
#include "DNA_userdef_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_context.h"
+
+#include "BLT_translation.h"
#include "interface_intern.h"
#include "UI_interface.h"
+#include "WM_api.h"
+#include "WM_types.h"
+
#include "UI_tree_view.hh"
namespace blender::ui {
@@ -31,8 +39,8 @@ namespace blender::ui {
/* ---------------------------------------------------------------------- */
/**
- * Add a tree-item to the container. This is the only place where items should be added, it handles
- * important invariants!
+ * Add a tree-item to the container. This is the only place where items should be added, it
+ * handles important invariants!
*/
AbstractTreeViewItem &TreeViewItemContainer::add_tree_item(
std::unique_ptr<AbstractTreeViewItem> item)
@@ -74,37 +82,43 @@ void AbstractTreeView::foreach_item(ItemIterFn iter_fn, IterOptions options) con
foreach_item_recursive(iter_fn, options);
}
-void AbstractTreeView::build_layout_from_tree(const TreeViewLayoutBuilder &builder)
+bool AbstractTreeView::is_renaming() const
{
- uiLayout *prev_layout = builder.current_layout();
-
- uiLayoutColumn(prev_layout, true);
-
- foreach_item([&builder](AbstractTreeViewItem &item) { builder.build_row(item); },
- IterOptions::SkipCollapsed);
-
- UI_block_layout_set_current(&builder.block(), prev_layout);
+ return rename_buffer_ != nullptr;
}
void AbstractTreeView::update_from_old(uiBlock &new_block)
{
uiBlock *old_block = new_block.oldblock;
if (!old_block) {
+ /* Initial construction, nothing to update. */
+ is_reconstructed_ = true;
return;
}
uiTreeViewHandle *old_view_handle = ui_block_view_find_matching_in_old_block(
&new_block, reinterpret_cast<uiTreeViewHandle *>(this));
- if (!old_view_handle) {
+ if (old_view_handle == nullptr) {
+ is_reconstructed_ = true;
return;
}
AbstractTreeView &old_view = reinterpret_cast<AbstractTreeView &>(*old_view_handle);
+
+ /* Update own persistent data. */
+ /* Keep the rename buffer persistent while renaming! The rename button uses the buffer's
+ * pointer to identify itself over redraws. */
+ rename_buffer_ = std::move(old_view.rename_buffer_);
+ old_view.rename_buffer_ = nullptr;
+
update_children_from_old_recursive(*this, old_view);
+
+ /* Finished (re-)constructing the tree. */
+ is_reconstructed_ = true;
}
-void AbstractTreeView::update_children_from_old_recursive(const TreeViewItemContainer &new_items,
- const TreeViewItemContainer &old_items)
+void AbstractTreeView::update_children_from_old_recursive(const TreeViewOrItem &new_items,
+ const TreeViewOrItem &old_items)
{
for (const auto &new_item : new_items.children_) {
AbstractTreeViewItem *matching_old_item = find_matching_child(*new_item, old_items);
@@ -120,10 +134,10 @@ void AbstractTreeView::update_children_from_old_recursive(const TreeViewItemCont
}
AbstractTreeViewItem *AbstractTreeView::find_matching_child(
- const AbstractTreeViewItem &lookup_item, const TreeViewItemContainer &items)
+ const AbstractTreeViewItem &lookup_item, const TreeViewOrItem &items)
{
for (const auto &iter_item : items.children_) {
- if (lookup_item.label_ == iter_item->label_) {
+ if (lookup_item.matches(*iter_item)) {
/* We have a matching item! */
return iter_item.get();
}
@@ -132,20 +146,284 @@ AbstractTreeViewItem *AbstractTreeView::find_matching_child(
return nullptr;
}
+bool AbstractTreeView::is_reconstructed() const
+{
+ return is_reconstructed_;
+}
+
+void AbstractTreeView::change_state_delayed()
+{
+ BLI_assert_msg(
+ is_reconstructed(),
+ "These state changes are supposed to be delayed until reconstruction is completed");
+ foreach_item([](AbstractTreeViewItem &item) { item.change_state_delayed(); });
+}
+
/* ---------------------------------------------------------------------- */
+void AbstractTreeViewItem::tree_row_click_fn(struct bContext * /*C*/,
+ void *but_arg1,
+ void * /*arg2*/)
+{
+ uiButTreeRow *tree_row_but = (uiButTreeRow *)but_arg1;
+ AbstractTreeViewItem &tree_item = reinterpret_cast<AbstractTreeViewItem &>(
+ *tree_row_but->tree_item);
+
+ tree_item.activate();
+ /* Not only activate the item, also show its children. Maybe this should be optional, or
+ * controlled by the specific tree-view. */
+ tree_item.set_collapsed(false);
+}
+
+void AbstractTreeViewItem::add_treerow_button(uiBlock &block)
+{
+ /* For some reason a width > (UI_UNIT_X * 2) make the layout system use all available width. */
+ tree_row_but_ = (uiButTreeRow *)uiDefBut(
+ &block, UI_BTYPE_TREEROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, nullptr, 0, 0, 0, 0, "");
+
+ tree_row_but_->tree_item = reinterpret_cast<uiTreeViewItemHandle *>(this);
+ UI_but_func_set(&tree_row_but_->but, tree_row_click_fn, tree_row_but_, nullptr);
+}
+
+void AbstractTreeViewItem::add_indent(uiLayout &row) const
+{
+ uiBlock *block = uiLayoutGetBlock(&row);
+ uiLayout *subrow = uiLayoutRow(&row, true);
+ uiLayoutSetFixedSize(subrow, true);
+
+ const float indent_size = count_parents() * UI_DPI_ICON_SIZE;
+ uiDefBut(block, UI_BTYPE_SEPR, 0, "", 0, 0, indent_size, 0, nullptr, 0.0, 0.0, 0, 0, "");
+
+ /* Indent items without collapsing icon some more within their parent. Makes it clear that they
+ * are actually nested and not just a row at the same level without a chevron. */
+ if (!is_collapsible() && parent_) {
+ uiDefBut(block, UI_BTYPE_SEPR, 0, "", 0, 0, 0.2f * UI_UNIT_X, 0, nullptr, 0.0, 0.0, 0, 0, "");
+ }
+
+ /* Restore. */
+ UI_block_layout_set_current(block, &row);
+}
+
+void AbstractTreeViewItem::collapse_chevron_click_fn(struct bContext *C,
+ void * /*but_arg1*/,
+ void * /*arg2*/)
+{
+ /* There's no data we could pass to this callback. It must be either the button itself or a
+ * consistent address to match buttons over redraws. So instead of passing it somehow, just
+ * lookup the hovered item via context here. */
+
+ const wmWindow *win = CTX_wm_window(C);
+ const ARegion *region = CTX_wm_region(C);
+ uiTreeViewItemHandle *hovered_item_handle = UI_block_tree_view_find_item_at(region,
+ win->eventstate->xy);
+ AbstractTreeViewItem *hovered_item = reinterpret_cast<AbstractTreeViewItem *>(
+ hovered_item_handle);
+ BLI_assert(hovered_item != nullptr);
+
+ hovered_item->toggle_collapsed();
+ /* When collapsing an item with an active child, make this collapsed item active instead so the
+ * active item stays visible. */
+ if (hovered_item->has_active_child()) {
+ hovered_item->activate();
+ }
+}
+
+bool AbstractTreeViewItem::is_collapse_chevron_but(const uiBut *but)
+{
+ return but->type == UI_BTYPE_BUT_TOGGLE && ELEM(but->icon, ICON_TRIA_RIGHT, ICON_TRIA_DOWN) &&
+ (but->func == collapse_chevron_click_fn);
+}
+
+void AbstractTreeViewItem::add_collapse_chevron(uiBlock &block) const
+{
+ if (!is_collapsible()) {
+ return;
+ }
+
+ const BIFIconID icon = is_collapsed() ? ICON_TRIA_RIGHT : ICON_TRIA_DOWN;
+ uiBut *but = uiDefIconBut(
+ &block, UI_BTYPE_BUT_TOGGLE, 0, icon, 0, 0, UI_UNIT_X, UI_UNIT_Y, nullptr, 0, 0, 0, 0, "");
+ /* Note that we're passing the tree-row button here, not the chevron one. */
+ UI_but_func_set(but, collapse_chevron_click_fn, nullptr, nullptr);
+ UI_but_flag_disable(but, UI_BUT_UNDO);
+
+ /* Check if the query for the button matches the created button. */
+ BLI_assert(is_collapse_chevron_but(but));
+}
+
+AbstractTreeViewItem *AbstractTreeViewItem::find_tree_item_from_rename_button(
+ const uiBut &rename_but)
+{
+ /* A minimal sanity check, can't do much more here. */
+ BLI_assert(rename_but.type == UI_BTYPE_TEXT && rename_but.poin);
+
+ LISTBASE_FOREACH (uiBut *, but, &rename_but.block->buttons) {
+ if (but->type != UI_BTYPE_TREEROW) {
+ continue;
+ }
+
+ uiButTreeRow *tree_row_but = (uiButTreeRow *)but;
+ AbstractTreeViewItem *item = reinterpret_cast<AbstractTreeViewItem *>(tree_row_but->tree_item);
+ const AbstractTreeView &tree_view = item->get_tree_view();
+
+ if (item->is_renaming() && (tree_view.rename_buffer_->data() == rename_but.poin)) {
+ return item;
+ }
+ }
+
+ return nullptr;
+}
+
+void AbstractTreeViewItem::rename_button_fn(bContext *UNUSED(C), void *arg, char *UNUSED(origstr))
+{
+ const uiBut *rename_but = static_cast<uiBut *>(arg);
+ AbstractTreeViewItem *item = find_tree_item_from_rename_button(*rename_but);
+ BLI_assert(item);
+
+ const AbstractTreeView &tree_view = item->get_tree_view();
+ item->rename(tree_view.rename_buffer_->data());
+ item->end_renaming();
+}
+
+void AbstractTreeViewItem::add_rename_button(uiLayout &row)
+{
+ uiBlock *block = uiLayoutGetBlock(&row);
+ eUIEmbossType previous_emboss = UI_block_emboss_get(block);
+
+ uiLayoutRow(&row, false);
+ /* Enable emboss for the text button. */
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ AbstractTreeView &tree_view = get_tree_view();
+ uiBut *rename_but = uiDefBut(block,
+ UI_BTYPE_TEXT,
+ 1,
+ "",
+ 0,
+ 0,
+ UI_UNIT_X * 10,
+ UI_UNIT_Y,
+ tree_view.rename_buffer_->data(),
+ 1.0f,
+ tree_view.rename_buffer_->max_size(),
+ 0,
+ 0,
+ "");
+
+ /* Gotta be careful with what's passed to the `arg1` here. Any tree data will be freed once the
+ * callback is executed. */
+ UI_but_func_rename_set(rename_but, AbstractTreeViewItem::rename_button_fn, rename_but);
+ UI_but_flag_disable(rename_but, UI_BUT_UNDO);
+
+ const bContext *evil_C = static_cast<bContext *>(block->evil_C);
+ ARegion *region = CTX_wm_region(evil_C);
+ /* Returns false if the button was removed. */
+ if (UI_but_active_only(evil_C, region, block, rename_but) == false) {
+ end_renaming();
+ }
+
+ UI_block_emboss_set(block, previous_emboss);
+ UI_block_layout_set_current(block, &row);
+}
+
+bool AbstractTreeViewItem::has_active_child() const
+{
+ bool found = false;
+ foreach_item_recursive([&found](const AbstractTreeViewItem &item) {
+ if (item.is_active()) {
+ found = true;
+ }
+ });
+
+ return found;
+}
+
void AbstractTreeViewItem::on_activate()
{
/* Do nothing by default. */
}
+std::optional<bool> AbstractTreeViewItem::should_be_active() const
+{
+ return std::nullopt;
+}
+
+bool AbstractTreeViewItem::supports_collapsing() const
+{
+ return true;
+}
+
+std::unique_ptr<AbstractTreeViewItemDragController> AbstractTreeViewItem::create_drag_controller()
+ const
+{
+ /* There's no drag controller (and hence no drag support) by default. */
+ return nullptr;
+}
+
+std::unique_ptr<AbstractTreeViewItemDropController> AbstractTreeViewItem::create_drop_controller()
+ const
+{
+ /* There's no drop controller (and hence no drop support) by default. */
+ return nullptr;
+}
+
+bool AbstractTreeViewItem::supports_renaming() const
+{
+ /* No renaming by default. */
+ return false;
+}
+
+bool AbstractTreeViewItem::rename(StringRefNull new_name)
+{
+ /* It is important to update the label after renaming, so #AbstractTreeViewItem::matches()
+ * recognizes the item. (It only compares labels by default.) */
+ label_ = new_name;
+ return true;
+}
+
+void AbstractTreeViewItem::build_context_menu(bContext & /*C*/, uiLayout & /*column*/) const
+{
+ /* No context menu by default. */
+}
+
void AbstractTreeViewItem::update_from_old(const AbstractTreeViewItem &old)
{
is_open_ = old.is_open_;
is_active_ = old.is_active_;
+ is_renaming_ = old.is_renaming_;
+}
+
+bool AbstractTreeViewItem::matches(const AbstractTreeViewItem &other) const
+{
+ return label_ == other.label_;
}
-const AbstractTreeView &AbstractTreeViewItem::get_tree_view() const
+void AbstractTreeViewItem::begin_renaming()
+{
+ AbstractTreeView &tree_view = get_tree_view();
+ if (tree_view.is_renaming() || !supports_renaming()) {
+ return;
+ }
+
+ is_renaming_ = true;
+
+ tree_view.rename_buffer_ = std::make_unique<decltype(tree_view.rename_buffer_)::element_type>();
+ std::copy(std::begin(label_), std::end(label_), std::begin(*tree_view.rename_buffer_));
+}
+
+void AbstractTreeViewItem::end_renaming()
+{
+ if (!is_renaming()) {
+ return;
+ }
+
+ is_renaming_ = false;
+
+ AbstractTreeView &tree_view = get_tree_view();
+ tree_view.rename_buffer_ = nullptr;
+}
+
+AbstractTreeView &AbstractTreeViewItem::get_tree_view() const
{
return static_cast<AbstractTreeView &>(*root_);
}
@@ -153,29 +431,62 @@ const AbstractTreeView &AbstractTreeViewItem::get_tree_view() const
int AbstractTreeViewItem::count_parents() const
{
int i = 0;
- for (TreeViewItemContainer *parent = parent_; parent; parent = parent->parent_) {
+ for (AbstractTreeViewItem *parent = parent_; parent; parent = parent->parent_) {
i++;
}
return i;
}
-void AbstractTreeViewItem::set_active(bool value)
+void AbstractTreeViewItem::activate()
{
- if (value && !is_active()) {
- /* Deactivate other items in the tree. */
- get_tree_view().foreach_item([](auto &item) { item.set_active(false); });
- on_activate();
+ BLI_assert_msg(get_tree_view().is_reconstructed(),
+ "Item activation can't be done until reconstruction is completed");
+
+ if (is_active()) {
+ return;
}
- is_active_ = value;
+
+ /* Deactivate other items in the tree. */
+ get_tree_view().foreach_item([](auto &item) { item.deactivate(); });
+
+ on_activate();
+ /* Make sure the active item is always visible. */
+ ensure_parents_uncollapsed();
+
+ is_active_ = true;
+}
+
+void AbstractTreeViewItem::deactivate()
+{
+ is_active_ = false;
}
bool AbstractTreeViewItem::is_active() const
{
+ BLI_assert_msg(get_tree_view().is_reconstructed(),
+ "State can't be queried until reconstruction is completed");
return is_active_;
}
+bool AbstractTreeViewItem::is_hovered() const
+{
+ BLI_assert_msg(get_tree_view().is_reconstructed(),
+ "State can't be queried until reconstruction is completed");
+ BLI_assert_msg(tree_row_but_ != nullptr,
+ "Hovered state can't be queried before the tree row is being built");
+
+ const uiTreeViewItemHandle *this_handle = reinterpret_cast<const uiTreeViewItemHandle *>(this);
+ /* The new layout hasn't finished construction yet, so the final state of the button is unknown.
+ * Get the matching button from the previous redraw instead. */
+ uiButTreeRow *old_treerow_but = ui_block_view_find_treerow_in_old_block(tree_row_but_->but.block,
+ this_handle);
+ return old_treerow_but && (old_treerow_but->but.flag & UI_ACTIVE);
+}
+
bool AbstractTreeViewItem::is_collapsed() const
{
+ BLI_assert_msg(get_tree_view().is_reconstructed(),
+ "State can't be queried until reconstruction is completed");
return is_collapsible() && !is_open_;
}
@@ -191,38 +502,161 @@ void AbstractTreeViewItem::set_collapsed(bool collapsed)
bool AbstractTreeViewItem::is_collapsible() const
{
- return !children_.is_empty();
+ if (children_.is_empty()) {
+ return false;
+ }
+ return this->supports_collapsing();
+}
+
+bool AbstractTreeViewItem::is_renaming() const
+{
+ return is_renaming_;
+}
+
+void AbstractTreeViewItem::ensure_parents_uncollapsed()
+{
+ for (AbstractTreeViewItem *parent = parent_; parent; parent = parent->parent_) {
+ parent->set_collapsed(false);
+ }
+}
+
+bool AbstractTreeViewItem::matches_including_parents(const AbstractTreeViewItem &other) const
+{
+ if (!matches(other)) {
+ return false;
+ }
+ if (count_parents() != other.count_parents()) {
+ return false;
+ }
+
+ for (AbstractTreeViewItem *parent = parent_, *other_parent = other.parent_;
+ parent && other_parent;
+ parent = parent->parent_, other_parent = other_parent->parent_) {
+ if (!parent->matches(*other_parent)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+uiButTreeRow *AbstractTreeViewItem::tree_row_button()
+{
+ return tree_row_but_;
+}
+
+void AbstractTreeViewItem::change_state_delayed()
+{
+ const std::optional<bool> should_be_active = this->should_be_active();
+ if (should_be_active.has_value() && *should_be_active) {
+ activate();
+ }
}
/* ---------------------------------------------------------------------- */
-TreeViewBuilder::TreeViewBuilder(uiBlock &block) : block_(block)
+AbstractTreeViewItemDragController::AbstractTreeViewItemDragController(AbstractTreeView &tree_view)
+ : tree_view_(tree_view)
{
}
-void TreeViewBuilder::build_tree_view(AbstractTreeView &tree_view)
+void AbstractTreeViewItemDragController::on_drag_start()
+{
+ /* Do nothing by default. */
+}
+
+/* ---------------------------------------------------------------------- */
+
+AbstractTreeViewItemDropController::AbstractTreeViewItemDropController(AbstractTreeView &tree_view)
+ : tree_view_(tree_view)
{
- tree_view.build_tree();
- tree_view.update_from_old(block_);
- tree_view.build_layout_from_tree(TreeViewLayoutBuilder(block_));
}
/* ---------------------------------------------------------------------- */
+class TreeViewLayoutBuilder {
+ uiBlock &block_;
+
+ friend TreeViewBuilder;
+
+ public:
+ void build_from_tree(const AbstractTreeView &tree_view);
+ void build_row(AbstractTreeViewItem &item) const;
+
+ uiBlock &block() const;
+ uiLayout *current_layout() const;
+
+ private:
+ /* Created through #TreeViewBuilder. */
+ TreeViewLayoutBuilder(uiBlock &block);
+
+ static void polish_layout(const uiBlock &block);
+};
+
TreeViewLayoutBuilder::TreeViewLayoutBuilder(uiBlock &block) : block_(block)
{
}
-void TreeViewLayoutBuilder::build_row(AbstractTreeViewItem &item) const
+void TreeViewLayoutBuilder::build_from_tree(const AbstractTreeView &tree_view)
{
uiLayout *prev_layout = current_layout();
- uiLayout *row = uiLayoutRow(prev_layout, false);
- item.build_row(*row);
+ uiLayout *box = uiLayoutBox(prev_layout);
+ uiLayoutColumn(box, false);
+
+ tree_view.foreach_item([this](AbstractTreeViewItem &item) { build_row(item); },
+ AbstractTreeView::IterOptions::SkipCollapsed);
UI_block_layout_set_current(&block(), prev_layout);
}
+void TreeViewLayoutBuilder::polish_layout(const uiBlock &block)
+{
+ LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block.buttons) {
+ if (AbstractTreeViewItem::is_collapse_chevron_but(but) && but->next &&
+ /* Embossed buttons with padding-less text padding look weird, so don't touch them. */
+ ELEM(but->next->emboss, UI_EMBOSS_NONE, UI_EMBOSS_NONE_OR_STATUS)) {
+ UI_but_drawflag_enable(static_cast<uiBut *>(but->next), UI_BUT_NO_TEXT_PADDING);
+ }
+
+ if (but->type == UI_BTYPE_TREEROW) {
+ break;
+ }
+ }
+}
+
+void TreeViewLayoutBuilder::build_row(AbstractTreeViewItem &item) const
+{
+ uiBlock &block_ = block();
+
+ uiLayout *prev_layout = current_layout();
+ eUIEmbossType previous_emboss = UI_block_emboss_get(&block_);
+
+ uiLayout *overlap = uiLayoutOverlap(prev_layout);
+
+ uiLayoutRow(overlap, false);
+ /* Every item gets one! Other buttons can be overlapped on top. */
+ item.add_treerow_button(block_);
+
+ /* After adding tree-row button (would disable hover highlighting). */
+ UI_block_emboss_set(&block_, UI_EMBOSS_NONE);
+
+ uiLayout *row = uiLayoutRow(overlap, true);
+ item.add_indent(*row);
+ item.add_collapse_chevron(block_);
+
+ if (item.is_renaming()) {
+ item.add_rename_button(*row);
+ }
+ else {
+ item.build_row(*row);
+ }
+ polish_layout(block_);
+
+ UI_block_emboss_set(&block_, previous_emboss);
+ UI_block_layout_set_current(&block_, prev_layout);
+}
+
uiBlock &TreeViewLayoutBuilder::block() const
{
return block_;
@@ -235,49 +669,41 @@ uiLayout *TreeViewLayoutBuilder::current_layout() const
/* ---------------------------------------------------------------------- */
-BasicTreeViewItem::BasicTreeViewItem(StringRef label, BIFIconID icon_, ActivateFn activate_fn)
- : icon(icon_), activate_fn_(activate_fn)
+TreeViewBuilder::TreeViewBuilder(uiBlock &block) : block_(block)
{
- label_ = label;
}
-static void tree_row_click_fn(struct bContext *UNUSED(C), void *but_arg1, void *UNUSED(arg2))
+void TreeViewBuilder::build_tree_view(AbstractTreeView &tree_view)
{
- uiButTreeRow *tree_row_but = (uiButTreeRow *)but_arg1;
- AbstractTreeViewItem &tree_item = reinterpret_cast<AbstractTreeViewItem &>(
- *tree_row_but->tree_item);
+ tree_view.build_tree();
+ tree_view.update_from_old(block_);
+ tree_view.change_state_delayed();
- /* Let a click on an opened item activate it, a second click will close it then.
- * TODO Should this be for asset catalogs only? */
- if (tree_item.is_collapsed() || tree_item.is_active()) {
- tree_item.toggle_collapsed();
- }
- tree_item.set_active();
+ TreeViewLayoutBuilder builder(block_);
+ builder.build_from_tree(tree_view);
+}
+
+/* ---------------------------------------------------------------------- */
+
+BasicTreeViewItem::BasicTreeViewItem(StringRef label, BIFIconID icon_) : icon(icon_)
+{
+ label_ = label;
}
void BasicTreeViewItem::build_row(uiLayout &row)
{
- uiBlock *block = uiLayoutGetBlock(&row);
- tree_row_but_ = (uiButTreeRow *)uiDefIconTextBut(block,
- UI_BTYPE_TREEROW,
- 0,
- /* TODO allow icon besides the chevron icon? */
- get_draw_icon(),
- label_.data(),
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
+ add_label(row);
+}
- tree_row_but_->tree_item = reinterpret_cast<uiTreeViewItemHandle *>(this);
- UI_but_func_set(&tree_row_but_->but, tree_row_click_fn, tree_row_but_, nullptr);
- UI_but_treerow_indentation_set(&tree_row_but_->but, count_parents());
+void BasicTreeViewItem::add_label(uiLayout &layout, StringRefNull label_override)
+{
+ const StringRefNull label = label_override.is_empty() ? StringRefNull(label_) : label_override;
+
+ /* Some padding for labels without collapse chevron and no icon. Looks weird without. */
+ if (icon == ICON_NONE && !is_collapsible()) {
+ uiItemS_ex(&layout, 0.8f);
+ }
+ uiItemL(&layout, IFACE_(label.c_str()), icon);
}
void BasicTreeViewItem::on_activate()
@@ -287,30 +713,172 @@ void BasicTreeViewItem::on_activate()
}
}
-BIFIconID BasicTreeViewItem::get_draw_icon() const
+void BasicTreeViewItem::set_on_activate_fn(ActivateFn fn)
{
- if (icon) {
- return icon;
- }
-
- if (is_collapsible()) {
- return is_collapsed() ? ICON_TRIA_RIGHT : ICON_TRIA_DOWN;
- }
+ activate_fn_ = fn;
+}
- return ICON_NONE;
+void BasicTreeViewItem::set_is_active_fn(IsActiveFn is_active_fn)
+{
+ is_active_fn_ = is_active_fn;
}
-uiBut *BasicTreeViewItem::button()
+std::optional<bool> BasicTreeViewItem::should_be_active() const
{
- return &tree_row_but_->but;
+ if (is_active_fn_) {
+ return is_active_fn_();
+ }
+ return std::nullopt;
}
+/* ---------------------------------------------------------------------- */
+
+/**
+ * Helper for a public (C-)API, presenting higher level functionality. Has access to internal
+ * data/functionality (friend of #AbstractTreeViewItem), which is sometimes needed when
+ * functionality of the API needs to be constructed from multiple internal conditions and/or
+ * functions that on their own shouldn't be part of the API.
+ */
+class TreeViewItemAPIWrapper {
+ public:
+ static bool matches(const AbstractTreeViewItem &a, const AbstractTreeViewItem &b)
+ {
+ /* TODO should match the tree-view as well. */
+ return a.matches_including_parents(b);
+ }
+
+ static bool drag_start(bContext &C, const AbstractTreeViewItem &item)
+ {
+ const std::unique_ptr<AbstractTreeViewItemDragController> drag_controller =
+ item.create_drag_controller();
+ if (!drag_controller) {
+ return false;
+ }
+
+ WM_event_start_drag(&C,
+ ICON_NONE,
+ drag_controller->get_drag_type(),
+ drag_controller->create_drag_data(),
+ 0,
+ WM_DRAG_FREE_DATA);
+ drag_controller->on_drag_start();
+
+ return true;
+ }
+
+ static bool can_drop(const AbstractTreeViewItem &item,
+ const wmDrag &drag,
+ const char **r_disabled_hint)
+ {
+ const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
+ item.create_drop_controller();
+ if (!drop_controller) {
+ return false;
+ }
+
+ return drop_controller->can_drop(drag, r_disabled_hint);
+ }
+
+ static std::string drop_tooltip(const AbstractTreeViewItem &item, const wmDrag &drag)
+ {
+ const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
+ item.create_drop_controller();
+ if (!drop_controller) {
+ return {};
+ }
+
+ return drop_controller->drop_tooltip(drag);
+ }
+
+ static bool drop_handle(bContext &C, const AbstractTreeViewItem &item, const ListBase &drags)
+ {
+ std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
+ item.create_drop_controller();
+
+ const char *disabled_hint_dummy = nullptr;
+ LISTBASE_FOREACH (const wmDrag *, drag, &drags) {
+ if (drop_controller->can_drop(*drag, &disabled_hint_dummy)) {
+ return drop_controller->on_drop(&C, *drag);
+ }
+ }
+
+ return false;
+ }
+
+ static bool can_rename(const AbstractTreeViewItem &item)
+ {
+ const AbstractTreeView &tree_view = item.get_tree_view();
+ return !tree_view.is_renaming() && item.supports_renaming();
+ }
+};
+
} // namespace blender::ui
+/* ---------------------------------------------------------------------- */
+/* C-API */
+
using namespace blender::ui;
-bool UI_tree_view_item_is_active(uiTreeViewItemHandle *item_)
+bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item_handle)
{
- AbstractTreeViewItem &item = reinterpret_cast<AbstractTreeViewItem &>(*item_);
+ const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle);
return item.is_active();
}
+
+bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a_handle,
+ const uiTreeViewItemHandle *b_handle)
+{
+ const AbstractTreeViewItem &a = reinterpret_cast<const AbstractTreeViewItem &>(*a_handle);
+ const AbstractTreeViewItem &b = reinterpret_cast<const AbstractTreeViewItem &>(*b_handle);
+ return TreeViewItemAPIWrapper::matches(a, b);
+}
+
+bool UI_tree_view_item_drag_start(bContext *C, uiTreeViewItemHandle *item_)
+{
+ const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
+ return TreeViewItemAPIWrapper::drag_start(*C, item);
+}
+
+bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
+ const wmDrag *drag,
+ const char **r_disabled_hint)
+{
+ const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
+ return TreeViewItemAPIWrapper::can_drop(item, *drag, r_disabled_hint);
+}
+
+char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item_, const wmDrag *drag)
+{
+ const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
+
+ const std::string tooltip = TreeViewItemAPIWrapper::drop_tooltip(item, *drag);
+ return tooltip.empty() ? nullptr : BLI_strdup(tooltip.c_str());
+}
+
+bool UI_tree_view_item_drop_handle(bContext *C,
+ const uiTreeViewItemHandle *item_,
+ const ListBase *drags)
+{
+ const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
+ return TreeViewItemAPIWrapper::drop_handle(*C, item, *drags);
+}
+
+bool UI_tree_view_item_can_rename(const uiTreeViewItemHandle *item_handle)
+{
+ const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle);
+ return TreeViewItemAPIWrapper::can_rename(item);
+}
+
+void UI_tree_view_item_begin_rename(uiTreeViewItemHandle *item_handle)
+{
+ AbstractTreeViewItem &item = reinterpret_cast<AbstractTreeViewItem &>(*item_handle);
+ item.begin_renaming();
+}
+
+void UI_tree_view_item_context_menu_build(bContext *C,
+ const uiTreeViewItemHandle *item_handle,
+ uiLayout *column)
+{
+ const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle);
+ item.build_context_menu(*C, *column);
+}
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index 0036a812a87..b530693a7e5 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -32,6 +32,7 @@
#include "DNA_userdef_types.h"
#include "BLI_array.h"
+#include "BLI_easing.h"
#include "BLI_link_utils.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -166,7 +167,7 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
scroll = view2d_scroll_mapped(v2d->scroll);
- /* scrollers are based off regionsize
+ /* Scrollers are based off region-size:
* - they can only be on one to two edges of the region they define
* - if they overlap, they must not occupy the corners (which are reserved for other widgets)
*/
@@ -227,16 +228,6 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
/** \name View2D Refresh and Validation (Spatial)
* \{ */
-/**
- * Initialize all relevant View2D data (including view rects if first time)
- * and/or refresh mask sizes after view resize.
- *
- * - For some of these presets, it is expected that the region will have defined some
- * additional settings necessary for the customization of the 2D viewport to its requirements
- * - This function should only be called from region init() callbacks, where it is expected that
- * this is called before #UI_view2d_size_update(),
- * as this one checks that the rects are properly initialized.
- */
void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
{
bool tot_changed = false, do_init;
@@ -871,8 +862,6 @@ bool UI_view2d_area_supports_sync(ScrArea *area)
return ELEM(area->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP, SPACE_GRAPH);
}
-/* Called by menus to activate it, or by view2d operators
- * to make sure 'related' views stay in synchrony */
void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
{
/* don't continue if no view syncing to be done */
@@ -936,11 +925,6 @@ void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
}
}
-/**
- * Restore 'cur' rect to standard orientation (i.e. optimal maximum view of tot).
- * This does not take into account if zooming the view on an axis
- * will improve the view (if allowed).
- */
void UI_view2d_curRect_reset(View2D *v2d)
{
float width, height;
@@ -990,7 +974,6 @@ void UI_view2d_curRect_reset(View2D *v2d)
/* ------------------ */
-/* Change the size of the maximum viewable area (i.e. 'tot' rect) */
void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, bool resize)
{
/* don't do anything if either value is 0 */
@@ -1109,7 +1092,6 @@ static void view2d_map_cur_using_mask(const View2D *v2d, rctf *r_curmasked)
}
}
-/* Set view matrices to use 'cur' rect as viewing frame for View2D drawing */
void UI_view2d_view_ortho(const View2D *v2d)
{
rctf curmasked;
@@ -1151,12 +1133,6 @@ void UI_view2d_view_ortho(const View2D *v2d)
wmOrtho2(curmasked.xmin, curmasked.xmax, curmasked.ymin, curmasked.ymax);
}
-/**
- * Set view matrices to only use one axis of 'cur' only
- *
- * \param xaxis: if non-zero, only use cur x-axis,
- * otherwise use cur-yaxis (mostly this will be used for x).
- */
void UI_view2d_view_orthoSpecial(ARegion *region, View2D *v2d, const bool xaxis)
{
rctf curmasked;
@@ -1183,7 +1159,6 @@ void UI_view2d_view_orthoSpecial(ARegion *region, View2D *v2d, const bool xaxis)
}
}
-/* Restore view matrices after drawing */
void UI_view2d_view_restore(const bContext *C)
{
ARegion *region = CTX_wm_region(C);
@@ -1202,7 +1177,6 @@ void UI_view2d_view_restore(const bContext *C)
/** \name Grid-Line Drawing
* \{ */
-/* Draw a multi-level grid in given 2d-region */
void UI_view2d_multi_grid_draw(
const View2D *v2d, int colorid, float step, int level_size, int totlevels)
{
@@ -1291,6 +1265,107 @@ void UI_view2d_multi_grid_draw(
immUnbindProgram();
}
+static void grid_axis_start_and_count(
+ const float step, const float min, const float max, float *r_start, int *r_count)
+{
+ *r_start = min;
+ if (*r_start < 0.0f) {
+ *r_start += -(float)fmod(min, step);
+ }
+ else {
+ *r_start += step - (float)fabs(fmod(min, step));
+ }
+
+ if (*r_start > max) {
+ *r_count = 0;
+ }
+ else {
+ *r_count = (max - *r_start) / step + 1;
+ }
+}
+
+typedef struct DotGridLevelInfo {
+ /* The factor applied to the #min_step argument. This could be easily computed in runtime,
+ * but seeing it together with the other values is helpful. */
+ float step_factor;
+ /* The normalized zoom level at which the grid level starts to fade in.
+ * At lower zoom levels, the points will not be visible and the level will be skipped. */
+ float fade_in_start_zoom;
+ /* The normalized zoom level at which the grid finishes fading in.
+ * At higher zoom levels, the points will be opaque. */
+ float fade_in_end_zoom;
+} DotGridLevelInfo;
+
+static const DotGridLevelInfo level_info[9] = {
+ {6.4f, -0.1f, 0.01f},
+ {3.2f, 0.0f, 0.025f},
+ {1.6f, 0.025f, 0.15f},
+ {0.8f, 0.05f, 0.2f},
+ {0.4f, 0.1f, 0.25f},
+ {0.2f, 0.125f, 0.3f},
+ {0.1f, 0.25f, 0.5f},
+ {0.05f, 0.7f, 0.9f},
+ {0.025f, 0.6f, 0.9f},
+};
+
+void UI_view2d_dot_grid_draw(const View2D *v2d,
+ const int grid_color_id,
+ const float min_step,
+ const int grid_levels)
+{
+ BLI_assert(grid_levels >= 0 && grid_levels < 10);
+ const float zoom_x = (float)(BLI_rcti_size_x(&v2d->mask) + 1) / BLI_rctf_size_x(&v2d->cur);
+ const float zoom_normalized = (zoom_x - v2d->minzoom) / (v2d->maxzoom - v2d->minzoom);
+
+ GPUVertFormat *format = immVertexFormat();
+ const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ const uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ GPU_point_size(3.0f * UI_DPI_FAC);
+
+ float color[4];
+ UI_GetThemeColor3fv(grid_color_id, color);
+
+ for (int level = 0; level < grid_levels; level++) {
+ const DotGridLevelInfo *info = &level_info[level];
+ const float step = min_step * info->step_factor * U.widget_unit;
+
+ const float alpha_factor = (zoom_normalized - info->fade_in_start_zoom) /
+ (info->fade_in_end_zoom - info->fade_in_start_zoom);
+ color[3] = clamp_f(BLI_easing_cubic_ease_in_out(alpha_factor, 0.0f, 1.0f, 1.0f), 0.0f, 1.0f);
+ if (color[3] == 0.0f) {
+ break;
+ }
+
+ int count_x;
+ float start_x;
+ grid_axis_start_and_count(step, v2d->cur.xmin, v2d->cur.xmax, &start_x, &count_x);
+ int count_y;
+ float start_y;
+ grid_axis_start_and_count(step, v2d->cur.ymin, v2d->cur.ymax, &start_y, &count_y);
+ if (count_x == 0 || count_y == 0) {
+ continue;
+ }
+
+ immBegin(GPU_PRIM_POINTS, count_x * count_y);
+
+ /* Theoretically drawing on top of lower grid levels could be avoided, but it would also
+ * increase the complexity of this loop, which isn't worth the time at the moment. */
+ for (int i_y = 0; i_y < count_y; i_y++) {
+ const float y = start_y + step * i_y;
+ for (int i_x = 0; i_x < count_x; i_x++) {
+ const float x = start_x + step * i_x;
+ immAttr4fv(color_id, color);
+ immVertex2f(pos, x, y);
+ }
+ }
+
+ immEnd();
+ }
+
+ immUnbindProgram();
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1305,6 +1380,8 @@ void UI_view2d_multi_grid_draw(
*/
struct View2DScrollers {
/* focus bubbles */
+ /* focus bubbles */
+ /* focus bubbles */
int vert_min, vert_max; /* vertical scrollbar */
int hor_min, hor_max; /* horizontal scrollbar */
@@ -1314,7 +1391,6 @@ struct View2DScrollers {
/* int horfull, vertfull; */ /* UNUSED */
};
-/* Calculate relevant scroller properties */
void UI_view2d_scrollers_calc(View2D *v2d,
const rcti *mask_custom,
struct View2DScrollers *r_scrollers)
@@ -1441,7 +1517,6 @@ void UI_view2d_scrollers_calc(View2D *v2d,
}
}
-/* Draw scrollbars in the given 2d-region */
void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
{
View2DScrollers scrollers;
@@ -1537,18 +1612,6 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
/** \name List View Utilities
* \{ */
-/**
- * Get the 'cell' (row, column) that the given 2D-view coordinates
- * (i.e. in 'tot' rect space) lie in.
- *
- * \param columnwidth, rowheight: size of each 'cell'
- * \param startx, starty: coordinates (in 'tot' rect space) that the list starts from.
- * This should be (0,0) for most views. However, for those where the starting row was offsetted
- * (like for Animation Editor channel lists, to make the first entry more visible), these will be
- * the min-coordinates of the first item.
- * \param viewx, viewy: 2D-coordinates (in 2D-view / 'tot' rect space) to get the cell for
- * \param r_column, r_row: the 'coordinates' of the relevant 'cell'
- */
void UI_view2d_listview_view_to_cell(float columnwidth,
float rowheight,
float startx,
@@ -1596,12 +1659,6 @@ float UI_view2d_region_to_view_y(const struct View2D *v2d, float y)
(BLI_rctf_size_y(&v2d->cur) * (y - v2d->mask.ymin) / BLI_rcti_size_y(&v2d->mask)));
}
-/**
- * Convert from screen/region space to 2d-View space
- *
- * \param x, y: coordinates to convert
- * \param r_view_x, r_view_y: resultant coordinates
- */
void UI_view2d_region_to_view(
const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y)
{
@@ -1635,13 +1692,6 @@ float UI_view2d_view_to_region_y(const View2D *v2d, float y)
(((y - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur)) * BLI_rcti_size_y(&v2d->mask)));
}
-/**
- * Convert from 2d-View space to screen/region space
- * \note Coordinates are clamped to lie within bounds of region
- *
- * \param x, y: Coordinates to convert.
- * \param r_region_x, r_region_y: Resultant coordinates.
- */
bool UI_view2d_view_to_region_clip(
const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
@@ -1663,14 +1713,6 @@ bool UI_view2d_view_to_region_clip(
return false;
}
-/**
- * Convert from 2d-view space to screen/region space
- *
- * \note Coordinates are NOT clamped to lie within bounds of region.
- *
- * \param x, y: Coordinates to convert.
- * \param r_region_x, r_region_y: Resultant coordinates.
- */
void UI_view2d_view_to_region(
const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
@@ -1765,7 +1807,6 @@ bool UI_view2d_view_to_region_rcti_clip(const View2D *v2d, const rctf *rect_src,
/** \name Utilities
* \{ */
-/* View2D data by default resides in region, so get from region stored in context */
View2D *UI_view2d_fromcontext(const bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -1780,7 +1821,6 @@ View2D *UI_view2d_fromcontext(const bContext *C)
return &(region->v2d);
}
-/* Same as above, but it returns region-window. Utility for pull-downs or buttons. */
View2D *UI_view2d_fromcontext_rwin(const bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -1799,8 +1839,6 @@ View2D *UI_view2d_fromcontext_rwin(const bContext *C)
return &(region->v2d);
}
-/* Get scrollbar sizes of the current 2D view. The size will be zero if the view has its scrollbars
- * disabled. */
void UI_view2d_scroller_size_get(const View2D *v2d, float *r_x, float *r_y)
{
const int scroll = view2d_scroll_mapped(v2d->scroll);
@@ -1824,14 +1862,6 @@ void UI_view2d_scroller_size_get(const View2D *v2d, float *r_x, float *r_y)
}
}
-/**
- * Calculate the scale per-axis of the drawing-area
- *
- * Is used to inverse correct drawing of icons, etc. that need to follow view
- * but not be affected by scale
- *
- * \param r_x, r_y: scale on each axis
- */
void UI_view2d_scale_get(const View2D *v2d, float *r_x, float *r_y)
{
if (r_x) {
@@ -1849,9 +1879,6 @@ float UI_view2d_scale_get_y(const View2D *v2d)
{
return BLI_rcti_size_y(&v2d->mask) / BLI_rctf_size_y(&v2d->cur);
}
-/**
- * Same as `UI_view2d_scale_get() - 1.0f / x, y`.
- */
void UI_view2d_scale_get_inverse(const View2D *v2d, float *r_x, float *r_y)
{
if (r_x) {
@@ -1862,10 +1889,6 @@ void UI_view2d_scale_get_inverse(const View2D *v2d, float *r_x, float *r_y)
}
}
-/**
- * Simple functions for consistent center offset access.
- * Used by node editor to shift view center for each individual node tree.
- */
void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y)
{
/* get center */
@@ -1884,12 +1907,6 @@ void UI_view2d_center_set(struct View2D *v2d, float x, float y)
UI_view2d_curRect_validate(v2d);
}
-/**
- * Simple pan function
- * (0.0, 0.0) bottom left
- * (0.5, 0.5) center
- * (1.0, 1.0) top right.
- */
void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac)
{
if (xfac != -1.0f) {
@@ -1913,19 +1930,10 @@ void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac)
UI_view2d_curRect_validate(v2d);
}
-/**
- * Check if mouse is within scrollers
- *
- * \param x, y: Mouse coordinates in screen (not region) space.
- * \param r_scroll: Mapped view2d scroll flag.
- *
- * \return appropriate code for match.
- * - 'h' = in horizontal scroller.
- * - 'v' = in vertical scroller.
- * - 0 = not in scroller.
- */
-char UI_view2d_mouse_in_scrollers_ex(
- const ARegion *region, const View2D *v2d, int x, int y, int *r_scroll)
+char UI_view2d_mouse_in_scrollers_ex(const ARegion *region,
+ const View2D *v2d,
+ const int xy[2],
+ int *r_scroll)
{
const int scroll = view2d_scroll_mapped(v2d->scroll);
*r_scroll = scroll;
@@ -1933,8 +1941,8 @@ char UI_view2d_mouse_in_scrollers_ex(
if (scroll) {
/* Move to region-coordinates. */
const int co[2] = {
- x - region->winrct.xmin,
- y - region->winrct.ymin,
+ xy[0] - region->winrct.xmin,
+ xy[1] - region->winrct.ymin,
};
if (scroll & V2D_SCROLL_HORIZONTAL) {
if (IN_2D_HORIZ_SCROLL(v2d, co)) {
@@ -1978,10 +1986,10 @@ char UI_view2d_rect_in_scrollers_ex(const ARegion *region,
return 0;
}
-char UI_view2d_mouse_in_scrollers(const ARegion *region, const View2D *v2d, int x, int y)
+char UI_view2d_mouse_in_scrollers(const ARegion *region, const View2D *v2d, const int xy[2])
{
int scroll_dummy = 0;
- return UI_view2d_mouse_in_scrollers_ex(region, v2d, x, y, &scroll_dummy);
+ return UI_view2d_mouse_in_scrollers_ex(region, v2d, xy, &scroll_dummy);
}
char UI_view2d_rect_in_scrollers(const ARegion *region, const View2D *v2d, const rcti *rect)
@@ -2043,7 +2051,6 @@ void UI_view2d_text_cache_add(
}
}
-/* no clip (yet) */
void UI_view2d_text_cache_add_rectf(
View2D *v2d, const rctf *rect_view, const char *str, size_t str_len, const uchar col[4])
{
diff --git a/source/blender/editors/interface/view2d_draw.c b/source/blender/editors/interface/view2d_draw.c
index fd4dba30c1c..b1869fbf2f9 100644
--- a/source/blender/editors/interface/view2d_draw.c
+++ b/source/blender/editors/interface/view2d_draw.c
@@ -394,29 +394,33 @@ static void draw_vertical_scale_indicators(const ARegion *region,
const int font_id = BLF_default();
UI_FontThemeColor(font_id, colorid);
- BLF_enable(font_id, BLF_ROTATION);
- BLF_rotation(font_id, M_PI_2);
-
BLF_batch_draw_begin();
- const float xpos = rect->xmax - 2.0f * UI_DPI_FAC;
+ BLF_enable(font_id, BLF_SHADOW);
+ const float shadow_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ BLF_shadow(font_id, 5, shadow_color);
+ BLF_shadow_offset(font_id, 1, -1);
+
+ const float x_offset = 8.0f;
+ const float xpos = (rect->xmin + x_offset) * UI_DPI_FAC;
const float ymin = rect->ymin;
const float ymax = rect->ymax;
+ const float y_offset = (BLF_height(font_id, "0", 1) / 2.0f) - U.pixelsize;
for (uint i = 0; i < steps; i++) {
const float ypos_view = start + i * distance;
const float ypos_region = UI_view2d_view_to_region_y(v2d, ypos_view + display_offset);
char text[32];
to_string(to_string_data, ypos_view, distance, sizeof(text), text);
- const float text_width = BLF_width(font_id, text, strlen(text));
- if (ypos_region - text_width / 2.0f >= ymin && ypos_region + text_width / 2.0f <= ymax) {
- BLF_draw_default(xpos, ypos_region - text_width / 2.0f, 0.0f, text, sizeof(text));
+ if (ypos_region - y_offset >= ymin && ypos_region + y_offset <= ymax) {
+ BLF_draw_default(xpos, ypos_region - y_offset, 0.0f, text, sizeof(text));
}
}
+ BLF_disable(font_id, BLF_SHADOW);
+
BLF_batch_draw_end();
- BLF_disable(font_id, BLF_ROTATION);
GPU_matrix_pop_projection();
}
diff --git a/source/blender/editors/interface/view2d_edge_pan.c b/source/blender/editors/interface/view2d_edge_pan.c
index 54e0d8f40ea..8d8b9a4fe48 100644
--- a/source/blender/editors/interface/view2d_edge_pan.c
+++ b/source/blender/editors/interface/view2d_edge_pan.c
@@ -92,6 +92,8 @@ void UI_view2d_edge_pan_init(bContext *C,
vpd->delay = delay;
vpd->zoom_influence = zoom_influence;
+ vpd->enabled = false;
+
/* Calculate translation factor, based on size of view. */
const float winx = (float)(BLI_rcti_size_x(&vpd->region->winrct) + 1);
const float winy = (float)(BLI_rcti_size_y(&vpd->region->winrct) + 1);
@@ -217,7 +219,7 @@ static void edge_pan_apply_delta(bContext *C, View2DEdgePanData *vpd, float dx,
UI_view2d_sync(vpd->screen, vpd->area, v2d, V2D_LOCK_COPY);
}
-void UI_view2d_edge_pan_apply(bContext *C, View2DEdgePanData *vpd, int x, int y)
+void UI_view2d_edge_pan_apply(bContext *C, View2DEdgePanData *vpd, const int xy[2])
{
ARegion *region = vpd->region;
@@ -227,20 +229,27 @@ void UI_view2d_edge_pan_apply(bContext *C, View2DEdgePanData *vpd, int x, int y)
BLI_rcti_pad(&inside_rect, -vpd->inside_pad * U.widget_unit, -vpd->inside_pad * U.widget_unit);
BLI_rcti_pad(&outside_rect, vpd->outside_pad * U.widget_unit, vpd->outside_pad * U.widget_unit);
+ /* Check if we can actually start the edge pan (e.g. adding nodes outside the view will start
+ * disabled). */
+ if (BLI_rcti_isect_pt_v(&inside_rect, xy)) {
+ /* We are inside once, can start. */
+ vpd->enabled = true;
+ }
+
int pan_dir_x = 0;
int pan_dir_y = 0;
- if ((vpd->outside_pad == 0) || BLI_rcti_isect_pt(&outside_rect, x, y)) {
+ if (vpd->enabled && ((vpd->outside_pad == 0) || BLI_rcti_isect_pt_v(&outside_rect, xy))) {
/* Find whether the mouse is beyond X and Y edges. */
- if (x > inside_rect.xmax) {
+ if (xy[0] > inside_rect.xmax) {
pan_dir_x = 1;
}
- else if (x < inside_rect.xmin) {
+ else if (xy[0] < inside_rect.xmin) {
pan_dir_x = -1;
}
- if (y > inside_rect.ymax) {
+ if (xy[1] > inside_rect.ymax) {
pan_dir_y = 1;
}
- else if (y < inside_rect.ymin) {
+ else if (xy[1] < inside_rect.ymin) {
pan_dir_y = -1;
}
}
@@ -252,11 +261,11 @@ void UI_view2d_edge_pan_apply(bContext *C, View2DEdgePanData *vpd, int x, int y)
const float dtime = (float)(current_time - vpd->edge_pan_last_time);
float dx = 0.0f, dy = 0.0f;
if (pan_dir_x != 0) {
- const float speed = edge_pan_speed(vpd, x, true, current_time);
+ const float speed = edge_pan_speed(vpd, xy[0], true, current_time);
dx = dtime * speed * (float)pan_dir_x;
}
if (pan_dir_y != 0) {
- const float speed = edge_pan_speed(vpd, y, false, current_time);
+ const float speed = edge_pan_speed(vpd, xy[1], false, current_time);
dy = dtime * speed * (float)pan_dir_y;
}
vpd->edge_pan_last_time = current_time;
@@ -272,7 +281,7 @@ void UI_view2d_edge_pan_apply_event(bContext *C, View2DEdgePanData *vpd, const w
return;
}
- UI_view2d_edge_pan_apply(C, vpd, event->x, event->y);
+ UI_view2d_edge_pan_apply(C, vpd, event->xy);
}
void UI_view2d_edge_pan_cancel(bContext *C, View2DEdgePanData *vpd)
diff --git a/source/blender/editors/interface/view2d_gizmo_navigate.c b/source/blender/editors/interface/view2d_gizmo_navigate.c
index 30b4a7c097a..2497081b412 100644
--- a/source/blender/editors/interface/view2d_gizmo_navigate.c
+++ b/source/blender/editors/interface/view2d_gizmo_navigate.c
@@ -127,11 +127,24 @@ struct NavigateWidgetGroup {
int region_size[2];
};
-static bool WIDGETGROUP_navigate_poll(const bContext *UNUSED(C), wmGizmoGroupType *UNUSED(gzgt))
+static bool WIDGETGROUP_navigate_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
{
if ((U.uiflag & USER_SHOW_GIZMO_NAVIGATE) == 0) {
return false;
}
+ ScrArea *area = CTX_wm_area(C);
+ if (area == NULL) {
+ return false;
+ }
+ switch (area->spacetype) {
+ case SPACE_SEQ: {
+ const SpaceSeq *sseq = area->spacedata.first;
+ if (sseq->gizmo_flag & (SEQ_GIZMO_HIDE | SEQ_GIZMO_HIDE_NAVIGATE)) {
+ return false;
+ }
+ break;
+ }
+ }
return true;
}
@@ -238,7 +251,6 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
-/* Caller defines the name for gizmo group. */
void VIEW2D_GGT_navigate_impl(wmGizmoGroupType *gzgt, const char *idname)
{
gzgt->name = "View2D Navigate";
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 4ef4c3dbc6d..0d3c427bf39 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -224,13 +224,13 @@ static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
View2D *v2d = vpd->v2d;
/* set initial settings */
- vpd->startx = vpd->lastx = event->x;
- vpd->starty = vpd->lasty = event->y;
+ vpd->startx = vpd->lastx = event->xy[0];
+ vpd->starty = vpd->lasty = event->xy[1];
vpd->invoke_event = event->type;
if (event->type == MOUSEPAN) {
- RNA_int_set(op->ptr, "deltax", event->prevx - event->x);
- RNA_int_set(op->ptr, "deltay", event->prevy - event->y);
+ RNA_int_set(op->ptr, "deltax", event->prev_xy[0] - event->xy[0]);
+ RNA_int_set(op->ptr, "deltay", event->prev_xy[1] - event->xy[1]);
view_pan_apply(C, op);
view_pan_exit(op);
@@ -266,11 +266,11 @@ static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE: {
/* calculate new delta transform, then store mouse-coordinates for next-time */
- RNA_int_set(op->ptr, "deltax", (vpd->lastx - event->x));
- RNA_int_set(op->ptr, "deltay", (vpd->lasty - event->y));
+ RNA_int_set(op->ptr, "deltax", (vpd->lastx - event->xy[0]));
+ RNA_int_set(op->ptr, "deltay", (vpd->lasty - event->xy[1]));
- vpd->lastx = event->x;
- vpd->lasty = event->y;
+ vpd->lastx = event->xy[0];
+ vpd->lasty = event->xy[1];
view_pan_apply(C, op);
break;
@@ -1097,8 +1097,8 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *even
}
if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
- vzd->lastx = event->prevx;
- vzd->lasty = event->prevy;
+ vzd->lastx = event->prev_xy[0];
+ vzd->lasty = event->prev_xy[1];
float facx, facy;
float zoomfac = 0.01f;
@@ -1156,8 +1156,8 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *even
}
/* set initial settings */
- vzd->lastx = event->x;
- vzd->lasty = event->y;
+ vzd->lastx = event->xy[0];
+ vzd->lasty = event->xy[1];
RNA_float_set(op->ptr, "deltax", 0);
RNA_float_set(op->ptr, "deltay", 0);
@@ -1216,12 +1216,12 @@ static int view_zoomdrag_modal(bContext *C, wmOperator *op, const wmEvent *event
/* x-axis transform */
dist = BLI_rcti_size_x(&v2d->mask) / 2.0f;
len_old[0] = zoomfac * fabsf(vzd->lastx - vzd->region->winrct.xmin - dist);
- len_new[0] = zoomfac * fabsf(event->x - vzd->region->winrct.xmin - dist);
+ len_new[0] = zoomfac * fabsf(event->xy[0] - vzd->region->winrct.xmin - dist);
/* y-axis transform */
dist = BLI_rcti_size_y(&v2d->mask) / 2.0f;
len_old[1] = zoomfac * fabsf(vzd->lasty - vzd->region->winrct.ymin - dist);
- len_new[1] = zoomfac * fabsf(event->y - vzd->region->winrct.ymin - dist);
+ len_new[1] = zoomfac * fabsf(event->xy[1] - vzd->region->winrct.ymin - dist);
/* Calculate distance */
if (v2d->keepzoom & V2D_KEEPASPECT) {
@@ -1237,8 +1237,8 @@ static int view_zoomdrag_modal(bContext *C, wmOperator *op, const wmEvent *event
dy *= BLI_rctf_size_y(&v2d->cur);
}
else { /* USER_ZOOM_CONTINUE or USER_ZOOM_DOLLY */
- float facx = zoomfac * (event->x - vzd->lastx);
- float facy = zoomfac * (event->y - vzd->lasty);
+ float facx = zoomfac * (event->xy[0] - vzd->lastx);
+ float facy = zoomfac * (event->xy[1] - vzd->lasty);
/* Only respect user setting zoom axis if the view does not have any zoom restrictions
* any will be scaled uniformly */
@@ -1284,8 +1284,8 @@ static int view_zoomdrag_modal(bContext *C, wmOperator *op, const wmEvent *event
* to starting point to determine rate of change.
*/
if (U.viewzoom != USER_ZOOM_CONTINUE) { /* XXX store this setting as RNA prop? */
- vzd->lastx = event->x;
- vzd->lasty = event->y;
+ vzd->lastx = event->xy[0];
+ vzd->lasty = event->xy[1];
}
/* apply zooming */
@@ -1570,8 +1570,6 @@ static float smooth_view_rect_to_fac(const rctf *rect_a, const rctf *rect_b)
return min_ff(fac_max, 1.0f);
}
-/* will start timer if appropriate */
-/* the arguments are the desired situation */
void UI_view2d_smooth_view(bContext *C, ARegion *region, const rctf *cur, const int smooth_viewtx)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1761,7 +1759,6 @@ typedef struct v2dScrollerMove {
* For now, we don't need to have a separate (internal) header for structs like this...
*/
struct View2DScrollers {
- /* focus bubbles */
int vert_min, vert_max; /* vertical scrollbar */
int hor_min, hor_max; /* horizontal scrollbar */
@@ -1846,7 +1843,7 @@ static bool scroller_activate_poll(bContext *C)
wmEvent *event = win->eventstate;
/* check if mouse in scrollbars, if they're enabled */
- return (UI_view2d_mouse_in_scrollers(region, v2d, event->x, event->y) != 0);
+ return (UI_view2d_mouse_in_scrollers(region, v2d, event->xy) != 0);
}
/* initialize customdata for scroller manipulation operator */
@@ -1868,8 +1865,8 @@ static void scroller_activate_init(bContext *C,
vsm->scroller = in_scroller;
/* store mouse-coordinates, and convert mouse/screen coordinates to region coordinates */
- vsm->lastx = event->x;
- vsm->lasty = event->y;
+ vsm->lastx = event->xy[0];
+ vsm->lasty = event->xy[1];
/* 'zone' depends on where mouse is relative to bubble
* - zooming must be allowed on this axis, otherwise, default to pan
*/
@@ -2024,11 +2021,11 @@ static int scroller_activate_modal(bContext *C, wmOperator *op, const wmEvent *e
switch (vsm->scroller) {
case 'h': /* horizontal scroller - so only horizontal movement
* ('cur' moves opposite to mouse) */
- vsm->delta = (float)(event->x - vsm->lastx);
+ vsm->delta = (float)(event->xy[0] - vsm->lastx);
break;
case 'v': /* vertical scroller - so only vertical movement
* ('cur' moves opposite to mouse) */
- vsm->delta = (float)(event->y - vsm->lasty);
+ vsm->delta = (float)(event->xy[1] - vsm->lasty);
break;
}
}
@@ -2037,18 +2034,18 @@ static int scroller_activate_modal(bContext *C, wmOperator *op, const wmEvent *e
switch (vsm->scroller) {
case 'h': /* horizontal scroller - so only horizontal movement
* ('cur' moves with mouse) */
- vsm->delta = (float)(vsm->lastx - event->x);
+ vsm->delta = (float)(vsm->lastx - event->xy[0]);
break;
case 'v': /* vertical scroller - so only vertical movement
* ('cur' moves with to mouse) */
- vsm->delta = (float)(vsm->lasty - event->y);
+ vsm->delta = (float)(vsm->lasty - event->xy[1]);
break;
}
}
/* store previous coordinates */
- vsm->lastx = event->x;
- vsm->lasty = event->y;
+ vsm->lastx = event->xy[0];
+ vsm->lasty = event->xy[1];
scroller_activate_apply(C, op);
break;
@@ -2090,7 +2087,7 @@ static int scroller_activate_invoke(bContext *C, wmOperator *op, const wmEvent *
View2D *v2d = &region->v2d;
/* check if mouse in scrollbars, if they're enabled */
- const char in_scroller = UI_view2d_mouse_in_scrollers(region, v2d, event->x, event->y);
+ const char in_scroller = UI_view2d_mouse_in_scrollers(region, v2d, event->xy);
/* if in a scroller, init customdata then set modal handler which will
* catch mouse-down to start doing useful stuff */
@@ -2104,11 +2101,11 @@ static int scroller_activate_invoke(bContext *C, wmOperator *op, const wmEvent *
switch (vsm->scroller) {
case 'h': /* horizontal scroller - so only horizontal movement
* ('cur' moves opposite to mouse) */
- vsm->delta = (float)(event->x - vsm->scrollbar_orig);
+ vsm->delta = (float)(event->xy[0] - vsm->scrollbar_orig);
break;
case 'v': /* vertical scroller - so only vertical movement
* ('cur' moves opposite to mouse) */
- vsm->delta = (float)(event->y - vsm->scrollbar_orig);
+ vsm->delta = (float)(event->xy[1] - vsm->scrollbar_orig);
break;
}
scroller_activate_apply(C, op);
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index 44b5f85050f..cb1c3cedf8e 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -26,6 +26,7 @@ set(INC
../../io/collada
../../io/gpencil
../../io/usd
+ ../../io/wavefront_obj
../../makesdna
../../makesrna
../../windowmanager
@@ -43,6 +44,7 @@ set(SRC
io_gpencil_export.c
io_gpencil_import.c
io_gpencil_utils.c
+ io_obj.c
io_ops.c
io_usd.c
@@ -50,6 +52,7 @@ set(SRC
io_cache.h
io_collada.h
io_gpencil.h
+ io_obj.h
io_ops.h
io_usd.h
)
@@ -57,6 +60,7 @@ set(SRC
set(LIB
bf_blenkernel
bf_blenlib
+ bf_wavefront_obj
)
if(WITH_OPENCOLLADA)
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
index bf20c1f6438..4f71a804986 100644
--- a/source/blender/editors/io/io_cache.c
+++ b/source/blender/editors/io/io_cache.c
@@ -26,6 +26,7 @@
#include "DNA_cachefile_types.h"
#include "DNA_space_types.h"
+#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
@@ -36,6 +37,7 @@
#include "BKE_report.h"
#include "RNA_access.h"
+#include "RNA_define.h"
#include "DEG_depsgraph.h"
@@ -46,6 +48,12 @@
#include "io_cache.h"
+static void reload_cachefile(bContext *C, CacheFile *cache_file)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ BKE_cachefile_reload(depsgraph, cache_file);
+}
+
static void cachefile_init(bContext *C, wmOperator *op)
{
PropertyPointerRNA *pprop;
@@ -146,8 +154,7 @@ static int cachefile_reload_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- BKE_cachefile_reload(depsgraph, cache_file);
+ reload_cachefile(C, cache_file);
return OPERATOR_FINISHED;
}
@@ -164,3 +171,160 @@ void CACHEFILE_OT_reload(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/* ***************************** Add Layer Operator **************************** */
+
+static int cachefile_layer_open_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ char filepath[FILE_MAX];
+ Main *bmain = CTX_data_main(C);
+
+ BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
+ BLI_path_extension_replace(filepath, sizeof(filepath), ".abc");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+
+ /* There is no more CacheFile set when returning from the file selector, so store it here. */
+ op->customdata = CTX_data_edit_cachefile(C);
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+
+ UNUSED_VARS(event);
+}
+
+static int cachefile_layer_add_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ CacheFile *cache_file = op->customdata;
+
+ if (!cache_file) {
+ return OPERATOR_CANCELLED;
+ }
+
+ char filename[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filename);
+
+ CacheFileLayer *layer = BKE_cachefile_add_layer(cache_file, filename);
+
+ if (!layer) {
+ WM_report(RPT_ERROR, "Could not add a layer to the cache file");
+ return OPERATOR_CANCELLED;
+ }
+
+ reload_cachefile(C, cache_file);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void CACHEFILE_OT_layer_add(wmOperatorType *ot)
+{
+ ot->name = "Add layer";
+ ot->description = "Add an override layer to the archive";
+ ot->idname = "CACHEFILE_OT_layer_add";
+
+ /* api callbacks */
+ ot->invoke = cachefile_layer_open_invoke;
+ ot->exec = cachefile_layer_add_exec;
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER,
+ FILE_BLENDER,
+ FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_DEFAULT);
+}
+
+/* ***************************** Remove Layer Operator **************************** */
+
+static int cachefile_layer_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ CacheFile *cache_file = CTX_data_edit_cachefile(C);
+
+ if (!cache_file) {
+ return OPERATOR_CANCELLED;
+ }
+
+ CacheFileLayer *layer = BKE_cachefile_get_active_layer(cache_file);
+ BKE_cachefile_remove_layer(cache_file, layer);
+
+ reload_cachefile(C, cache_file);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void CACHEFILE_OT_layer_remove(wmOperatorType *ot)
+{
+ ot->name = "Add layer";
+ ot->description = "Remove an override layer to the archive";
+ ot->idname = "CACHEFILE_OT_layer_remove";
+
+ /* api callbacks */
+ ot->exec = cachefile_layer_remove_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ***************************** Move Layer Operator **************************** */
+
+static int cachefile_layer_move_exec(bContext *C, wmOperator *op)
+{
+ CacheFile *cache_file = CTX_data_edit_cachefile(C);
+
+ if (!cache_file) {
+ return OPERATOR_CANCELLED;
+ }
+
+ CacheFileLayer *layer = BKE_cachefile_get_active_layer(cache_file);
+
+ if (!layer) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const int dir = RNA_enum_get(op->ptr, "direction");
+
+ if (BLI_listbase_link_move(&cache_file->layers, layer, dir)) {
+ cache_file->active_layer = BLI_findindex(&cache_file->layers, layer) + 1;
+ /* Only reload if something moved, might be expensive. */
+ reload_cachefile(C, cache_file);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CACHEFILE_OT_layer_move(wmOperatorType *ot)
+{
+ static const EnumPropertyItem layer_slot_move[] = {
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ ot->name = "Move layer";
+ ot->description =
+ "Move layer in the list, layers further down the list will overwrite data from the layers "
+ "higher up";
+ ot->idname = "CACHEFILE_OT_layer_move";
+
+ /* api callbacks */
+ ot->exec = cachefile_layer_move_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna,
+ "direction",
+ layer_slot_move,
+ 0,
+ "Direction",
+ "Direction to move the active vertex group towards");
+}
diff --git a/source/blender/editors/io/io_cache.h b/source/blender/editors/io/io_cache.h
index be6e31842af..297e065434f 100644
--- a/source/blender/editors/io/io_cache.h
+++ b/source/blender/editors/io/io_cache.h
@@ -27,3 +27,7 @@ struct wmOperatorType;
void CACHEFILE_OT_open(struct wmOperatorType *ot);
void CACHEFILE_OT_reload(struct wmOperatorType *ot);
+
+void CACHEFILE_OT_layer_add(struct wmOperatorType *ot);
+void CACHEFILE_OT_layer_remove(struct wmOperatorType *ot);
+void CACHEFILE_OT_layer_move(struct wmOperatorType *ot);
diff --git a/source/blender/editors/io/io_gpencil_export.c b/source/blender/editors/io/io_gpencil_export.c
index b49be324372..556fae70828 100644
--- a/source/blender/editors/io/io_gpencil_export.c
+++ b/source/blender/editors/io/io_gpencil_export.c
@@ -410,6 +410,7 @@ void WM_OT_gpencil_export_pdf(wmOperatorType *ot)
static const EnumPropertyItem gpencil_export_frame_items[] = {
{GP_EXPORT_FRAME_ACTIVE, "ACTIVE", 0, "Active", "Include only active frame"},
{GP_EXPORT_FRAME_SELECTED, "SELECTED", 0, "Selected", "Include selected frames"},
+ {GP_EXPORT_FRAME_SCENE, "SCENE", 0, "Scene", "Include all scene frames"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
new file mode 100644
index 00000000000..2bc2a832d20
--- /dev/null
+++ b/source/blender/editors/io/io_obj.c
@@ -0,0 +1,369 @@
+/*
+ * 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 editor/io
+ */
+
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "IO_wavefront_obj.h"
+#include "io_obj.h"
+
+static const EnumPropertyItem io_obj_transform_axis_forward[] = {
+ {OBJ_AXIS_X_FORWARD, "X_FORWARD", 0, "X", "Positive X axis"},
+ {OBJ_AXIS_Y_FORWARD, "Y_FORWARD", 0, "Y", "Positive Y axis"},
+ {OBJ_AXIS_Z_FORWARD, "Z_FORWARD", 0, "Z", "Positive Z axis"},
+ {OBJ_AXIS_NEGATIVE_X_FORWARD, "NEGATIVE_X_FORWARD", 0, "-X", "Negative X axis"},
+ {OBJ_AXIS_NEGATIVE_Y_FORWARD, "NEGATIVE_Y_FORWARD", 0, "-Y", "Negative Y axis"},
+ {OBJ_AXIS_NEGATIVE_Z_FORWARD, "NEGATIVE_Z_FORWARD", 0, "-Z (Default)", "Negative Z axis"},
+ {0, NULL, 0, NULL, NULL}};
+
+static const EnumPropertyItem io_obj_transform_axis_up[] = {
+ {OBJ_AXIS_X_UP, "X_UP", 0, "X", "Positive X axis"},
+ {OBJ_AXIS_Y_UP, "Y_UP", 0, "Y (Default)", "Positive Y axis"},
+ {OBJ_AXIS_Z_UP, "Z_UP", 0, "Z", "Positive Z axis"},
+ {OBJ_AXIS_NEGATIVE_X_UP, "NEGATIVE_X_UP", 0, "-X", "Negative X axis"},
+ {OBJ_AXIS_NEGATIVE_Y_UP, "NEGATIVE_Y_UP", 0, "-Y", "Negative Y axis"},
+ {OBJ_AXIS_NEGATIVE_Z_UP, "NEGATIVE_Z_UP", 0, "-Z", "Negative Z axis"},
+ {0, NULL, 0, NULL, NULL}};
+
+static const EnumPropertyItem io_obj_export_evaluation_mode[] = {
+ {DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"},
+ {DAG_EVAL_VIEWPORT,
+ "DAG_EVAL_VIEWPORT",
+ 0,
+ "Viewport (Default)",
+ "Export objects as they appear in the viewport"},
+ {0, NULL, 0, NULL, NULL}};
+
+static int wm_obj_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ Main *bmain = CTX_data_main(C);
+ char filepath[FILE_MAX];
+
+ if (BKE_main_blendfile_path(bmain)[0] == '\0') {
+ BLI_strncpy(filepath, "untitled", sizeof(filepath));
+ }
+ else {
+ BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
+ }
+
+ BLI_path_extension_replace(filepath, sizeof(filepath), ".obj");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+
+ WM_event_add_fileselect(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_obj_export_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+ struct OBJExportParams export_params;
+ RNA_string_get(op->ptr, "filepath", export_params.filepath);
+ export_params.blen_filepath = CTX_data_main(C)->filepath;
+ export_params.export_animation = RNA_boolean_get(op->ptr, "export_animation");
+ export_params.start_frame = RNA_int_get(op->ptr, "start_frame");
+ export_params.end_frame = RNA_int_get(op->ptr, "end_frame");
+
+ export_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis");
+ export_params.up_axis = RNA_enum_get(op->ptr, "up_axis");
+ export_params.scaling_factor = RNA_float_get(op->ptr, "scaling_factor");
+ export_params.export_eval_mode = RNA_enum_get(op->ptr, "export_eval_mode");
+
+ export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects");
+ export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv");
+ export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals");
+ export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials");
+ export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh");
+ export_params.export_curves_as_nurbs = RNA_boolean_get(op->ptr, "export_curves_as_nurbs");
+
+ export_params.export_object_groups = RNA_boolean_get(op->ptr, "export_object_groups");
+ export_params.export_material_groups = RNA_boolean_get(op->ptr, "export_material_groups");
+ export_params.export_vertex_groups = RNA_boolean_get(op->ptr, "export_vertex_groups");
+ export_params.export_smooth_groups = RNA_boolean_get(op->ptr, "export_smooth_groups");
+ export_params.smooth_groups_bitflags = RNA_boolean_get(op->ptr, "smooth_group_bitflags");
+
+ OBJ_export(C, &export_params);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
+{
+
+ const bool export_animation = RNA_boolean_get(imfptr, "export_animation");
+ const bool export_smooth_groups = RNA_boolean_get(imfptr, "export_smooth_groups");
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+
+ /* Animation options. */
+ uiLayout *box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Animation"), ICON_ANIM);
+ uiLayout *col = uiLayoutColumn(box, false);
+ uiLayout *sub = uiLayoutColumn(col, false);
+ uiItemR(sub, imfptr, "export_animation", 0, NULL, ICON_NONE);
+ sub = uiLayoutColumn(sub, true);
+ uiItemR(sub, imfptr, "start_frame", 0, IFACE_("Frame Start"), ICON_NONE);
+ uiItemR(sub, imfptr, "end_frame", 0, IFACE_("End"), ICON_NONE);
+ uiLayoutSetEnabled(sub, export_animation);
+
+ /* Object Transform options. */
+ box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Object Properties"), ICON_OBJECT_DATA);
+ col = uiLayoutColumn(box, false);
+ sub = uiLayoutColumn(col, false);
+ uiItemR(sub, imfptr, "forward_axis", 0, IFACE_("Axis Forward"), ICON_NONE);
+ uiItemR(sub, imfptr, "up_axis", 0, IFACE_("Up"), ICON_NONE);
+ sub = uiLayoutColumn(col, false);
+ uiItemR(sub, imfptr, "scaling_factor", 0, NULL, ICON_NONE);
+ sub = uiLayoutColumnWithHeading(col, false, IFACE_("Objects"));
+ uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_eval_mode", 0, IFACE_("Properties"), ICON_NONE);
+
+ /* Options for what to write. */
+ box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Geometry Export"), ICON_EXPORT);
+ col = uiLayoutColumn(box, false);
+ sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export"));
+ uiItemR(sub, imfptr, "export_uv", 0, IFACE_("UV Coordinates"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_normals", 0, IFACE_("Normals"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_materials", 0, IFACE_("Materials"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_triangulated_mesh", 0, IFACE_("Triangulated Mesh"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_curves_as_nurbs", 0, IFACE_("Curves as NURBS"), ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Grouping"), ICON_GROUP);
+ col = uiLayoutColumn(box, false);
+ sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export"));
+ uiItemR(sub, imfptr, "export_object_groups", 0, IFACE_("Object Groups"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_material_groups", 0, IFACE_("Material Groups"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_vertex_groups", 0, IFACE_("Vertex Groups"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_smooth_groups", 0, IFACE_("Smooth Groups"), ICON_NONE);
+ sub = uiLayoutColumn(sub, false);
+ uiLayoutSetEnabled(sub, export_smooth_groups);
+ uiItemR(sub, imfptr, "smooth_group_bitflags", 0, IFACE_("Smooth Group Bitflags"), ICON_NONE);
+}
+
+static void wm_obj_export_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+ ui_obj_export_settings(op->layout, &ptr);
+}
+
+/**
+ * Return true if any property in the UI is changed.
+ */
+static bool wm_obj_export_check(bContext *C, wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ Scene *scene = CTX_data_scene(C);
+ bool changed = false;
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ if (!BLI_path_extension_check(filepath, ".obj")) {
+ BLI_path_extension_ensure(filepath, FILE_MAX, ".obj");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ changed = true;
+ }
+
+ {
+ int start = RNA_int_get(op->ptr, "start_frame");
+ int end = RNA_int_get(op->ptr, "end_frame");
+ /* Set the defaults. */
+ if (start == INT_MIN) {
+ start = SFRA;
+ changed = true;
+ }
+ if (end == INT_MAX) {
+ end = EFRA;
+ changed = true;
+ }
+ /* Fix user errors. */
+ if (end < start) {
+ end = start;
+ changed = true;
+ }
+ RNA_int_set(op->ptr, "start_frame", start);
+ RNA_int_set(op->ptr, "end_frame", end);
+ }
+
+ /* Both forward and up axes cannot be the same (or same except opposite sign). */
+ if (RNA_enum_get(op->ptr, "forward_axis") % TOTAL_AXES ==
+ (RNA_enum_get(op->ptr, "up_axis") % TOTAL_AXES)) {
+ /* TODO(@ankitm): Show a warning here. */
+ RNA_enum_set(op->ptr, "up_axis", RNA_enum_get(op->ptr, "up_axis") % TOTAL_AXES + 1);
+ changed = true;
+ }
+ return changed;
+}
+
+void WM_OT_obj_export(struct wmOperatorType *ot)
+{
+ ot->name = "Export Wavefront OBJ";
+ ot->description = "Save the scene to a Wavefront OBJ file";
+ ot->idname = "WM_OT_obj_export";
+
+ ot->invoke = wm_obj_export_invoke;
+ ot->exec = wm_obj_export_exec;
+ ot->poll = WM_operator_winactive;
+ ot->ui = wm_obj_export_draw;
+ ot->check = wm_obj_export_check;
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO,
+ FILE_BLENDER,
+ FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_ALPHA);
+
+ /* Animation options. */
+ RNA_def_boolean(ot->srna,
+ "export_animation",
+ false,
+ "Export Animation",
+ "Export multiple frames instead of the current frame only");
+ RNA_def_int(ot->srna,
+ "start_frame",
+ INT_MIN, /* wm_obj_export_check uses this to set SFRA. */
+ INT_MIN,
+ INT_MAX,
+ "Start Frame",
+ "The first frame to be exported",
+ INT_MIN,
+ INT_MAX);
+ RNA_def_int(ot->srna,
+ "end_frame",
+ INT_MAX, /* wm_obj_export_check uses this to set EFRA. */
+ INT_MIN,
+ INT_MAX,
+ "End Frame",
+ "The last frame to be exported",
+ INT_MIN,
+ INT_MAX);
+ /* Object transform options. */
+ RNA_def_enum(ot->srna,
+ "forward_axis",
+ io_obj_transform_axis_forward,
+ OBJ_AXIS_NEGATIVE_Z_FORWARD,
+ "Forward Axis",
+ "");
+ RNA_def_enum(ot->srna, "up_axis", io_obj_transform_axis_up, OBJ_AXIS_Y_UP, "Up Axis", "");
+ RNA_def_float(ot->srna,
+ "scaling_factor",
+ 1.0f,
+ 0.001f,
+ 10000.0f,
+ "Scale",
+ "Upscale the object by this factor",
+ 0.01,
+ 1000.0f);
+ /* File Writer options. */
+ RNA_def_enum(ot->srna,
+ "export_eval_mode",
+ io_obj_export_evaluation_mode,
+ DAG_EVAL_VIEWPORT,
+ "Object Properties",
+ "Determines properties like object visibility, modifiers etc., where they differ "
+ "for Render and Viewport");
+ RNA_def_boolean(ot->srna,
+ "export_selected_objects",
+ false,
+ "Export Selected Objects",
+ "Export only selected objects instead of all supported objects");
+ RNA_def_boolean(ot->srna, "export_uv", true, "Export UVs", "");
+ RNA_def_boolean(ot->srna,
+ "export_normals",
+ true,
+ "Export Normals",
+ "Export per-face normals if the face is flat-shaded, per-face-per-loop "
+ "normals if smooth-shaded");
+ RNA_def_boolean(ot->srna,
+ "export_materials",
+ true,
+ "Export Materials",
+ "Export MTL library. There must be a Principled-BSDF node for image textures to "
+ "be exported to the MTL file");
+ RNA_def_boolean(ot->srna,
+ "export_triangulated_mesh",
+ false,
+ "Export Triangulated Mesh",
+ "All ngons with four or more vertices will be triangulated. Meshes in "
+ "the scene will not be affected. Behaves like Triangulate Modifier with "
+ "ngon-method: \"Beauty\", quad-method: \"Shortest Diagonal\", min vertices: 4");
+ RNA_def_boolean(ot->srna,
+ "export_curves_as_nurbs",
+ false,
+ "Export Curves as NURBS",
+ "Export curves in parametric form instead of exporting as mesh");
+
+ RNA_def_boolean(ot->srna,
+ "export_object_groups",
+ false,
+ "Export Object Groups",
+ "Append mesh name to object name, separated by a '_'");
+ RNA_def_boolean(ot->srna,
+ "export_material_groups",
+ false,
+ "Export Material Groups",
+ "Append mesh name and material name to object name, separated by a '_'");
+ RNA_def_boolean(
+ ot->srna,
+ "export_vertex_groups",
+ false,
+ "Export Vertex Groups",
+ "Export the name of the vertex group of a face. It is approximated "
+ "by choosing the vertex group with the most members among the vertices of a face");
+ RNA_def_boolean(
+ ot->srna,
+ "export_smooth_groups",
+ false,
+ "Export Smooth Groups",
+ "Every smooth-shaded face is assigned group \"1\" and every flat-shaded face \"off\"");
+ RNA_def_boolean(
+ ot->srna, "smooth_group_bitflags", false, "Generate Bitflags for Smooth Groups", "");
+}
diff --git a/source/blender/editors/io/io_obj.h b/source/blender/editors/io/io_obj.h
new file mode 100644
index 00000000000..5a0e6971edd
--- /dev/null
+++ b/source/blender/editors/io/io_obj.h
@@ -0,0 +1,25 @@
+/*
+ * 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 editor/io
+ */
+
+#pragma once
+
+struct wmOperatorType;
+
+void WM_OT_obj_export(struct wmOperatorType *ot);
diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c
index b2788ee49a2..d9bbd7d8692 100644
--- a/source/blender/editors/io/io_ops.c
+++ b/source/blender/editors/io/io_ops.c
@@ -39,6 +39,7 @@
#include "io_cache.h"
#include "io_gpencil.h"
+#include "io_obj.h"
void ED_operatortypes_io(void)
{
@@ -68,4 +69,10 @@ void ED_operatortypes_io(void)
WM_operatortype_append(CACHEFILE_OT_open);
WM_operatortype_append(CACHEFILE_OT_reload);
+
+ WM_operatortype_append(CACHEFILE_OT_layer_add);
+ WM_operatortype_append(CACHEFILE_OT_layer_remove);
+ WM_operatortype_append(CACHEFILE_OT_layer_move);
+
+ WM_operatortype_append(WM_OT_obj_export);
}
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index d0007d9e5be..4e2ccea36ab 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -57,7 +57,7 @@
# include "io_usd.h"
# include "usd.h"
-# include "stdio.h"
+# include <stdio.h>
const EnumPropertyItem rna_enum_usd_export_evaluation_mode_items[] = {
{DAG_EVAL_RENDER,
diff --git a/source/blender/editors/lattice/editlattice_select.c b/source/blender/editors/lattice/editlattice_select.c
index e6f190f335b..5ea2b68d901 100644
--- a/source/blender/editors/lattice/editlattice_select.c
+++ b/source/blender/editors/lattice/editlattice_select.c
@@ -540,10 +540,7 @@ static int lattice_select_ungrouped_exec(bContext *C, wmOperator *op)
MEM_freeN(objects);
if (!changed) {
- BKE_report(op->reports,
- RPT_ERROR,
- objects_len > 1 ? "No weights/vertex groups on objects" :
- "No weights/vertex groups on object");
+ BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object(s)");
return OPERATOR_CANCELLED;
}
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/lattice/editlattice_tools.c b/source/blender/editors/lattice/editlattice_tools.c
index d503cbc87b8..15325c7648c 100644
--- a/source/blender/editors/lattice/editlattice_tools.c
+++ b/source/blender/editors/lattice/editlattice_tools.c
@@ -47,8 +47,6 @@
#include "lattice_intern.h"
-/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Make Regular Operator
* \{ */
diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c
index 23eaf991fd3..6d79d063a2f 100644
--- a/source/blender/editors/lattice/editlattice_undo.c
+++ b/source/blender/editors/lattice/editlattice_undo.c
@@ -278,7 +278,6 @@ static void lattice_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_lattice_undosys_type(UndoType *ut)
{
ut->name = "Edit Lattice";
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 22232e9c87e..0e207df7f94 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -587,6 +587,35 @@ static void draw_spline_curve(const bContext *C,
}
}
+static void draw_layer_splines(const bContext *C,
+ MaskLayer *layer,
+ const char draw_flag,
+ const char draw_type,
+ const int width,
+ const int height,
+ const bool is_active)
+{
+ LISTBASE_FOREACH (MaskSpline *, spline, &layer->splines) {
+ /* draw curve itself first... */
+ draw_spline_curve(C, layer, spline, draw_flag, draw_type, is_active, width, height);
+
+ if (!(layer->visibility_flag & MASK_HIDE_SELECT)) {
+ /* ...and then handles over the curve so they're nicely visible */
+ draw_spline_points(C, layer, spline, draw_flag, draw_type);
+ }
+
+ /* show undeform for testing */
+ if (0) {
+ void *back = spline->points_deform;
+
+ spline->points_deform = NULL;
+ draw_spline_curve(C, layer, spline, draw_flag, draw_type, is_active, width, height);
+ draw_spline_points(C, layer, spline, draw_flag, draw_type);
+ spline->points_deform = back;
+ }
+ }
+}
+
static void draw_mask_layers(const bContext *C,
Mask *mask,
const char draw_flag,
@@ -600,6 +629,7 @@ static void draw_mask_layers(const bContext *C,
MaskLayer *mask_layer;
int i;
+ MaskLayer *active = NULL;
for (mask_layer = mask->masklayers.first, i = 0; mask_layer != NULL;
mask_layer = mask_layer->next, i++) {
const bool is_active = (i == mask->masklay_act);
@@ -608,26 +638,16 @@ static void draw_mask_layers(const bContext *C,
continue;
}
- LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
-
- /* draw curve itself first... */
- draw_spline_curve(C, mask_layer, spline, draw_flag, draw_type, is_active, width, height);
-
- if (!(mask_layer->visibility_flag & MASK_HIDE_SELECT)) {
- /* ...and then handles over the curve so they're nicely visible */
- draw_spline_points(C, mask_layer, spline, draw_flag, draw_type);
- }
+ if (is_active) {
+ active = mask_layer;
+ continue;
+ }
- /* show undeform for testing */
- if (0) {
- void *back = spline->points_deform;
+ draw_layer_splines(C, mask_layer, draw_flag, draw_type, width, height, is_active);
+ }
- spline->points_deform = NULL;
- draw_spline_curve(C, mask_layer, spline, draw_flag, draw_type, is_active, width, height);
- draw_spline_points(C, mask_layer, spline, draw_flag, draw_type);
- spline->points_deform = back;
- }
- }
+ if (active != NULL) {
+ draw_layer_splines(C, active, draw_flag, draw_type, width, height, true);
}
GPU_program_point_size(false);
@@ -666,8 +686,6 @@ static float *mask_rasterize(Mask *mask, const int width, const int height)
return buffer;
}
-/* sets up the opengl context.
- * width, height are to match the values from ED_mask_get_size() */
void ED_mask_draw_region(
Depsgraph *depsgraph,
Mask *mask_,
@@ -704,8 +722,8 @@ void ED_mask_draw_region(
/* find window pixel coordinates of origin */
UI_view2d_view_to_region(&region->v2d, 0.0f, 0.0f, &x, &y);
- /* w = BLI_rctf_size_x(&v2d->tot); */
- /* h = BLI_rctf_size_y(&v2d->tot); */
+ // w = BLI_rctf_size_x(&v2d->tot);
+ // h = BLI_rctf_size_y(&v2d->tot);
zoomx = (float)(BLI_rcti_size_x(&region->winrct) + 1) / BLI_rctf_size_x(&region->v2d.cur);
zoomy = (float)(BLI_rcti_size_y(&region->winrct) + 1) / BLI_rctf_size_y(&region->v2d.cur);
@@ -750,7 +768,8 @@ 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, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL);
+ immDrawPixelsTexTiled(
+ &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL);
GPU_matrix_pop();
@@ -817,7 +836,7 @@ void ED_mask_draw_frames(
mask_layer_shape = mask_layer_shape->next) {
int frame = mask_layer_shape->frame;
- /* draw_keyframe(i, CFRA, sfra, framelen, 1); */
+ // draw_keyframe(i, CFRA, sfra, framelen, 1);
int height = (frame == cfra) ? 22 : 10;
int x = (frame - sfra) * framelen;
immVertex2i(pos, x, region_bottom);
diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c
index d9efbef4b42..3668f3bb34e 100644
--- a/source/blender/editors/mask/mask_editaction.c
+++ b/source/blender/editors/mask/mask_editaction.c
@@ -52,7 +52,6 @@
/* ***************************************** */
/* Generics - Loopers */
-/* Loops over the mask-frames for a mask-layer, and applies the given callback */
bool ED_masklayer_frames_looper(MaskLayer *mask_layer,
Scene *scene,
bool (*mask_layer_shape_cb)(MaskLayerShape *, Scene *))
@@ -80,7 +79,6 @@ bool ED_masklayer_frames_looper(MaskLayer *mask_layer,
/* ****************************************** */
/* Data Conversion Tools */
-/* make a listing all the mask-frames in a layer as cfraelems */
void ED_masklayer_make_cfra_list(MaskLayer *mask_layer, ListBase *elems, bool onlysel)
{
MaskLayerShape *mask_layer_shape;
@@ -108,7 +106,6 @@ void ED_masklayer_make_cfra_list(MaskLayer *mask_layer, ListBase *elems, bool on
/* ***************************************** */
/* Selection Tools */
-/* check if one of the frames in this layer is selected */
bool ED_masklayer_frame_select_check(const MaskLayer *mask_layer)
{
MaskLayerShape *mask_layer_shape;
@@ -150,7 +147,6 @@ static void mask_layer_shape_select(MaskLayerShape *mask_layer_shape, short sele
}
}
-/* set all/none/invert select (like above, but with SELECT_* modes) */
void ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
{
MaskLayerShape *mask_layer_shape;
@@ -167,7 +163,6 @@ void ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
}
}
-/* set all/none/invert select */
void ED_masklayer_frame_select_set(MaskLayer *mask_layer, short mode)
{
/* error checking */
@@ -179,7 +174,6 @@ void ED_masklayer_frame_select_set(MaskLayer *mask_layer, short mode)
ED_mask_select_frames(mask_layer, mode);
}
-/* select the frame in this layer that occurs on this frame (there should only be one at most) */
void ED_mask_select_frame(MaskLayer *mask_layer, int selx, short select_mode)
{
MaskLayerShape *mask_layer_shape;
@@ -195,7 +189,6 @@ void ED_mask_select_frame(MaskLayer *mask_layer, int selx, short select_mode)
}
}
-/* select the frames in this layer that occur within the bounds specified */
void ED_masklayer_frames_select_box(MaskLayer *mask_layer, float min, float max, short select_mode)
{
MaskLayerShape *mask_layer_shape;
@@ -213,7 +206,6 @@ void ED_masklayer_frames_select_box(MaskLayer *mask_layer, float min, float max,
}
}
-/* select the frames in this layer that occur within the lasso/circle region specified */
void ED_masklayer_frames_select_region(KeyframeEditData *ked,
MaskLayer *mask_layer,
short tool,
@@ -253,7 +245,6 @@ void ED_masklayer_frames_select_region(KeyframeEditData *ked,
/* ***************************************** */
/* Frame Editing Tools */
-/* Delete selected frames */
bool ED_masklayer_frames_delete(MaskLayer *mask_layer)
{
MaskLayerShape *mask_layer_shape, *mask_layer_shape_next;
@@ -278,7 +269,6 @@ bool ED_masklayer_frames_delete(MaskLayer *mask_layer)
return changed;
}
-/* Duplicate selected frames from given mask-layer */
void ED_masklayer_frames_duplicate(MaskLayer *mask_layer)
{
MaskLayerShape *mask_layer_shape, *gpfn;
@@ -344,7 +334,6 @@ static bool snap_mask_layer_nearmarker(MaskLayerShape *mask_layer_shape, Scene *
return false;
}
-/* snap selected frames to ... */
void ED_masklayer_snap_frames(MaskLayer *mask_layer, Scene *scene, short mode)
{
switch (mode) {
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index ee1784011ea..19a3b3966a1 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -32,13 +32,18 @@ struct wmOperatorType;
/* internal exports only */
/* mask_add.c */
+
void MASK_OT_add_vertex(struct wmOperatorType *ot);
void MASK_OT_add_feather_vertex(struct wmOperatorType *ot);
void MASK_OT_primitive_circle_add(struct wmOperatorType *ot);
void MASK_OT_primitive_square_add(struct wmOperatorType *ot);
/* mask_ops.c */
+
struct Mask *ED_mask_new(struct bContext *C, const char *name);
+/**
+ * Get active layer. Will create mask/layer to be sure there's an active layer.
+ */
struct MaskLayer *ED_mask_layer_ensure(struct bContext *C, bool *r_added_mask);
void MASK_OT_new(struct wmOperatorType *ot);
@@ -55,6 +60,7 @@ void MASK_OT_hide_view_clear(struct wmOperatorType *ot);
void MASK_OT_hide_view_set(struct wmOperatorType *ot);
void MASK_OT_feather_weight_clear(struct wmOperatorType *ot);
void MASK_OT_switch_direction(struct wmOperatorType *ot);
+/* Named to match mesh recalculate normals. */
void MASK_OT_normals_make_consistent(struct wmOperatorType *ot);
void MASK_OT_handle_type_set(struct wmOperatorType *ot);
@@ -66,10 +72,13 @@ void MASK_OT_copy_splines(struct wmOperatorType *ot);
void MASK_OT_paste_splines(struct wmOperatorType *ot);
/* mask_relationships.c */
+
+/** based on #OBJECT_OT_parent_set */
void MASK_OT_parent_set(struct wmOperatorType *ot);
void MASK_OT_parent_clear(struct wmOperatorType *ot);
/* mask_select.c */
+
void MASK_OT_select(struct wmOperatorType *ot);
void MASK_OT_select_all(struct wmOperatorType *ot);
@@ -81,16 +90,18 @@ void MASK_OT_select_linked(struct wmOperatorType *ot);
void MASK_OT_select_more(struct wmOperatorType *ot);
void MASK_OT_select_less(struct wmOperatorType *ot);
+/* 'check' select */
bool ED_mask_spline_select_check(const struct MaskSpline *spline);
bool ED_mask_layer_select_check(const struct MaskLayer *mask_layer);
bool ED_mask_select_check(const struct Mask *mask);
-void ED_mask_spline_select_set(struct MaskSpline *spline, const bool do_select);
-void ED_mask_layer_select_set(struct MaskLayer *mask_layer, const bool do_select);
+void ED_mask_spline_select_set(struct MaskSpline *spline, bool do_select);
+void ED_mask_layer_select_set(struct MaskLayer *mask_layer, bool do_select);
void ED_mask_select_toggle_all(struct Mask *mask, int action);
void ED_mask_select_flush_all(struct Mask *mask);
/* mask_editor.c */
+
bool ED_maskedit_poll(struct bContext *C);
bool ED_maskedit_mask_poll(struct bContext *C);
@@ -108,14 +119,15 @@ void ED_mask_view_lock_state_restore_no_jump(const struct bContext *C,
const MaskViewLockState *state);
/* mask_query.c */
+
bool ED_mask_find_nearest_diff_point(const struct bContext *C,
struct Mask *mask,
const float normal_co[2],
int threshold,
bool feather,
float tangent[2],
- const bool use_deform,
- const bool use_project,
+ bool use_deform,
+ bool use_project,
struct MaskLayer **r_mask_layer,
struct MaskSpline **r_spline,
struct MaskSplinePoint **r_point,
@@ -124,7 +136,7 @@ bool ED_mask_find_nearest_diff_point(const struct bContext *C,
bool ED_mask_feather_find_nearest(const struct bContext *C,
struct Mask *mask,
const float normal_co[2],
- const float threshold,
+ float threshold,
struct MaskLayer **r_mask_layer,
struct MaskSpline **r_spline,
struct MaskSplinePoint **r_point,
@@ -133,7 +145,7 @@ bool ED_mask_feather_find_nearest(const struct bContext *C,
struct MaskSplinePoint *ED_mask_point_find_nearest(const struct bContext *C,
struct Mask *mask,
const float normal_co[2],
- const float threshold,
+ float threshold,
struct MaskLayer **r_mask_layer,
struct MaskSpline **r_spline,
eMaskWhichHandle *r_which_handle,
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index fd5925bbd0c..8feb526c8d5 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -83,9 +83,6 @@ Mask *ED_mask_new(bContext *C, const char *name)
return mask;
}
-/**
- * Get active layer. Will create mask/layer to be sure there's an active layer.
- */
MaskLayer *ED_mask_layer_ensure(bContext *C, bool *r_added_mask)
{
Mask *mask = CTX_data_edit_mask(C);
@@ -1616,7 +1613,6 @@ static int mask_normals_make_consistent_exec(bContext *C, wmOperator *UNUSED(op)
return OPERATOR_CANCELLED;
}
-/* Named to match mesh recalculate normals. */
void MASK_OT_normals_make_consistent(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c
index e66c4e45e27..de80d9f04bd 100644
--- a/source/blender/editors/mask/mask_query.c
+++ b/source/blender/editors/mask/mask_query.c
@@ -489,7 +489,6 @@ bool ED_mask_feather_find_nearest(const bContext *C,
return false;
}
-/* takes event->mval */
void ED_mask_mouse_pos(ScrArea *area, ARegion *region, const int mval[2], float co[2])
{
if (area) {
@@ -523,8 +522,6 @@ void ED_mask_mouse_pos(ScrArea *area, ARegion *region, const int mval[2], float
}
}
-/* input: x/y - mval space
- * output: xr/yr - mask point space */
void ED_mask_point_pos(ScrArea *area, ARegion *region, float x, float y, float *xr, float *yr)
{
float co[2];
diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c
index 9c4740b3087..259402efbf1 100644
--- a/source/blender/editors/mask/mask_relationships.c
+++ b/source/blender/editors/mask/mask_relationships.c
@@ -168,7 +168,6 @@ static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-/** based on #OBJECT_OT_parent_set */
void MASK_OT_parent_set(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index fe6acac7d29..dd4a557f449 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -52,7 +52,6 @@
/** \name Public Mask Selection API
* \{ */
-/* 'check' select */
bool ED_mask_spline_select_check(const MaskSpline *spline)
{
for (int i = 0; i < spline->tot_point; i++) {
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 648008a4779..06547c94992 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -50,8 +50,6 @@
/* own include */
-/* copy the face flags, most importantly selection from the mesh to the final derived mesh,
- * use in object mode when selecting faces (while painting) */
void paintface_flush_flags(struct bContext *C, Object *ob, short flag)
{
Mesh *me = BKE_mesh_from_object(ob);
@@ -369,7 +367,7 @@ bool paintface_minmax(Object *ob, float r_min[3], float r_max[3])
continue;
}
- ml = me->mloop + mp->totloop;
+ ml = me->mloop + mp->loopstart;
for (b = 0; b < mp->totloop; b++, ml++) {
mul_v3_m3v3(vec, bmat, mvert[ml->v].co);
add_v3_v3v3(vec, vec, ob->obmat[3]);
@@ -437,9 +435,6 @@ bool paintface_mouse_select(
return true;
}
-/* (similar to void paintface_flush_flags(Object *ob))
- * copy the vertex flags, most importantly selection from the mesh to the final derived mesh,
- * use in object mode when selecting vertices (while painting) */
void paintvert_flush_flags(Object *ob)
{
Mesh *me = BKE_mesh_from_object(ob);
@@ -492,10 +487,6 @@ void paintvert_tag_select_update(struct bContext *C, struct Object *ob)
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
}
-/**
- * \note if the caller passes false to flush_flags,
- * then they will need to run #paintvert_flush_flags(ob) themselves.
- */
bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
{
Mesh *me;
diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c
index 9efcf0963b4..e2c75435af4 100644
--- a/source/blender/editors/mesh/editmesh_add_gizmo.c
+++ b/source/blender/editors/mesh/editmesh_add_gizmo.c
@@ -220,8 +220,8 @@ static void gizmo_mesh_placement_modal_from_setup(const bContext *C, wmGizmoGrou
float location[3];
calc_initial_placement_point_from_view((bContext *)C,
(float[2]){
- win->eventstate->x - region->winrct.xmin,
- win->eventstate->y - region->winrct.ymin,
+ win->eventstate->xy[0] - region->winrct.xmin,
+ win->eventstate->xy[1] - region->winrct.ymin,
},
location,
mat3);
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 0d74187b50e..332f1f98d81 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -705,7 +705,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (etype == MOUSEPAN) {
- float delta = 0.02f * (event->y - event->prevy);
+ float delta = 0.02f * (event->xy[1] - event->prev_xy[1]);
if (opdata->segments >= 1 && opdata->segments + delta < 1) {
opdata->segments = 1;
}
@@ -764,8 +764,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
/* Update offset accordingly to new offset_type. */
- if (!has_numinput &&
- (opdata->value_mode == OFFSET_VALUE || opdata->value_mode == OFFSET_VALUE_PERCENT)) {
+ if (!has_numinput && (ELEM(opdata->value_mode, OFFSET_VALUE, OFFSET_VALUE_PERCENT))) {
edbm_bevel_mouse_set_value(op, event);
}
edbm_bevel_calc(op);
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index e4cd48d95bb..913be7d69bb 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -144,7 +144,6 @@ static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const ch
return true;
}
-/* extrudes individual edges */
bool edbm_extrude_edges_indiv(BMEditMesh *em,
wmOperator *op,
const char hflag,
@@ -821,8 +820,8 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
float view_vec[3], cross[3];
/* convert the 2D normal into 3D */
- mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */
- mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */
+ mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* World-space. */
+ mul_mat3_m4_v3(vc.obedit->imat, nor); /* Local-space. */
/* correct the normal to be aligned on the view plane */
mul_v3_mat3_m4v3(view_vec, vc.obedit->imat, vc.rv3d->viewinv[2]);
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c
index 2146207308c..d7eaf58653f 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin.c
@@ -80,7 +80,7 @@ static int edbm_spin_exec(bContext *C, wmOperator *op)
BMesh *bm = em->bm;
BMOperator spinop;
- /* keep the values in worldspace since we're passing the obmat */
+ /* Keep the values in world-space since we're passing the `obmat`. */
if (!EDBM_op_init(em,
&spinop,
op,
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
index 5faafa77bba..7c289744eeb 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
@@ -941,7 +941,7 @@ static void gizmo_mesh_spin_redo_setup(const bContext *C, wmGizmoGroup *gzgroup)
/* Use cursor as fallback if it's not set by the 'ortho_axis_active'. */
if (is_zero_v3(ggd->data.orient_axis_relative)) {
float cursor_co[3];
- const int mval[2] = {event->x - region->winrct.xmin, event->y - region->winrct.ymin};
+ const int mval[2] = {event->xy[0] - region->winrct.xmin, event->xy[1] - region->winrct.ymin};
float plane[4];
plane_from_point_normal_v3(plane, plane_co, plane_no);
if (UNLIKELY(!ED_view3d_win_to_3d_on_plane_int(region, plane, mval, false, cursor_co))) {
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index f2691580a9d..81dc34f894f 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -57,7 +57,7 @@
#define USE_NET_ISLAND_CONNECT
/**
- * Compare selected with its self.
+ * Compare selected with itself.
*/
static int bm_face_isect_self(BMFace *f, void *UNUSED(user_data))
{
@@ -114,6 +114,7 @@ static void edbm_intersect_select(BMEditMesh *em, struct Mesh *me, bool do_selec
}
}
}
+ EDBM_select_flush(em);
}
EDBM_update(me,
@@ -480,7 +481,8 @@ void MESH_OT_intersect_boolean(struct wmOperatorType *ot)
false,
"Swap",
"Use with difference intersection to swap which side is kept");
- RNA_def_boolean(ot->srna, "use_self", false, "Self", "Do self-union or self-intersection");
+ RNA_def_boolean(
+ ot->srna, "use_self", false, "Self Intersection", "Do self-union or self-intersection");
RNA_def_float_distance(
ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge Threshold", "", 0.0, 0.001);
RNA_def_enum(ot->srna,
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 64c008acf8e..cae781327d5 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -97,7 +97,7 @@
#define KNIFE_DEFAULT_ANGLE_SNAPPING_INCREMENT 30.0f
#define KNIFE_MIN_ANGLE_SNAPPING_INCREMENT 0.0f
-#define KNIFE_MAX_ANGLE_SNAPPING_INCREMENT 90.0f
+#define KNIFE_MAX_ANGLE_SNAPPING_INCREMENT 180.0f
typedef struct KnifeColors {
uchar line[3];
@@ -184,8 +184,6 @@ typedef struct KnifeMeasureData {
float cage[3];
float mval[2];
bool is_stored;
- float corr_prev_cage[3]; /* "knife_start_cut" updates prev.cage breaking angle calculations,
- * store correct version. */
} KnifeMeasureData;
typedef struct KnifeUndoFrame {
@@ -212,7 +210,7 @@ typedef struct KnifeBVH {
typedef struct KnifeTool_OpData {
ARegion *region; /* Region that knifetool was activated in. */
void *draw_handle; /* For drawing preview loop. */
- ViewContext vc; /* Note: _don't_ use 'mval', instead use the one we define below. */
+ ViewContext vc; /* NOTE: _don't_ use 'mval', instead use the one we define below. */
float mval[2]; /* Mouse value with snapping applied. */
Scene *scene;
@@ -242,6 +240,7 @@ typedef struct KnifeTool_OpData {
BLI_mempool *kverts;
BLI_mempool *kedges;
+ bool no_cuts; /* A cut has not been made yet. */
BLI_Stack *undostack;
BLI_Stack *splitstack; /* Store edge splits by #knife_split_edge. */
@@ -492,11 +491,11 @@ static void knifetool_draw_visible_distances(const KnifeTool_OpData *kcd)
float numstr_size[2];
float posit[2];
const float bg_margin = 4.0f * U.dpi_fac;
- const int font_size = 14.0f * U.pixelsize;
+ const float font_size = 14.0f * U.pixelsize;
const int distance_precision = 4;
/* Calculate distance and convert to string. */
- const float cut_len = len_v3v3(kcd->mdata.corr_prev_cage, kcd->curr.cage);
+ const float cut_len = len_v3v3(kcd->prev.cage, kcd->curr.cage);
UnitSettings *unit = &kcd->scene->unit;
if (unit->system == USER_UNIT_NONE) {
@@ -562,7 +561,7 @@ static void knifetool_draw_angle(const KnifeTool_OpData *kcd,
const float arc_size = 64.0f * U.dpi_fac;
const float bg_margin = 4.0f * U.dpi_fac;
const float cap_size = 4.0f * U.dpi_fac;
- const int font_size = 14 * U.pixelsize;
+ const float font_size = 14.0f * U.pixelsize;
const int angle_precision = 3;
/* Angle arc in 3d space. */
@@ -703,7 +702,7 @@ static void knifetool_draw_visible_angles(const KnifeTool_OpData *kcd)
else {
tempkfv = tempkfe->v2;
}
- angle = angle_v3v3v3(kcd->mdata.corr_prev_cage, kcd->curr.cage, tempkfv->cageco);
+ angle = angle_v3v3v3(kcd->prev.cage, kcd->curr.cage, tempkfv->cageco);
if (angle < min_angle) {
min_angle = angle;
kfe = tempkfe;
@@ -717,7 +716,7 @@ static void knifetool_draw_visible_angles(const KnifeTool_OpData *kcd)
ED_view3d_project_float_global(kcd->region, end, end_ss, V3D_PROJ_TEST_NOP);
knifetool_draw_angle(kcd,
- kcd->mdata.corr_prev_cage,
+ kcd->prev.cage,
kcd->curr.cage,
end,
kcd->prev.mval,
@@ -730,11 +729,11 @@ static void knifetool_draw_visible_angles(const KnifeTool_OpData *kcd)
kfe = kcd->curr.edge;
/* Check for most recent cut (if cage is part of previous cut). */
- if (!compare_v3v3(kfe->v1->cageco, kcd->mdata.corr_prev_cage, KNIFE_FLT_EPSBIG) &&
- !compare_v3v3(kfe->v2->cageco, kcd->mdata.corr_prev_cage, KNIFE_FLT_EPSBIG)) {
+ if (!compare_v3v3(kfe->v1->cageco, kcd->prev.cage, KNIFE_FLT_EPSBIG) &&
+ !compare_v3v3(kfe->v2->cageco, kcd->prev.cage, KNIFE_FLT_EPSBIG)) {
/* Determine acute angle. */
- float angle1 = angle_v3v3v3(kcd->mdata.corr_prev_cage, kcd->curr.cage, kfe->v1->cageco);
- float angle2 = angle_v3v3v3(kcd->mdata.corr_prev_cage, kcd->curr.cage, kfe->v2->cageco);
+ float angle1 = angle_v3v3v3(kcd->prev.cage, kcd->curr.cage, kfe->v1->cageco);
+ float angle2 = angle_v3v3v3(kcd->prev.cage, kcd->curr.cage, kfe->v2->cageco);
float angle;
float *end;
@@ -751,14 +750,8 @@ static void knifetool_draw_visible_angles(const KnifeTool_OpData *kcd)
float end_ss[2];
ED_view3d_project_float_global(kcd->region, end, end_ss, V3D_PROJ_TEST_NOP);
- knifetool_draw_angle(kcd,
- kcd->mdata.corr_prev_cage,
- kcd->curr.cage,
- end,
- kcd->prev.mval,
- kcd->curr.mval,
- end_ss,
- angle);
+ knifetool_draw_angle(
+ kcd, kcd->prev.cage, kcd->curr.cage, end, kcd->prev.mval, kcd->curr.mval, end_ss, angle);
}
}
@@ -852,10 +845,10 @@ static void knifetool_draw_visible_angles(const KnifeTool_OpData *kcd)
kcd, kcd->curr.cage, kcd->prev.cage, end, kcd->curr.mval, kcd->prev.mval, end_ss, angle);
}
else if (kcd->mdata.is_stored && !kcd->prev.is_space) {
- float angle = angle_v3v3v3(kcd->curr.cage, kcd->mdata.corr_prev_cage, kcd->mdata.cage);
+ float angle = angle_v3v3v3(kcd->curr.cage, kcd->prev.cage, kcd->mdata.cage);
knifetool_draw_angle(kcd,
kcd->curr.cage,
- kcd->mdata.corr_prev_cage,
+ kcd->prev.cage,
kcd->mdata.cage,
kcd->curr.mval,
kcd->prev.mval,
@@ -1124,7 +1117,7 @@ static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *k
WM_MODALKEY(KNF_MODAL_ANGLE_SNAP_TOGGLE),
(kcd->angle >= 0.0f) ? RAD2DEGF(kcd->angle) : 360.0f + RAD2DEGF(kcd->angle),
(kcd->angle_snapping_increment > KNIFE_MIN_ANGLE_SNAPPING_INCREMENT &&
- kcd->angle_snapping_increment < KNIFE_MAX_ANGLE_SNAPPING_INCREMENT) ?
+ kcd->angle_snapping_increment <= KNIFE_MAX_ANGLE_SNAPPING_INCREMENT) ?
kcd->angle_snapping_increment :
KNIFE_DEFAULT_ANGLE_SNAPPING_INCREMENT,
kcd->angle_snapping ?
@@ -1468,7 +1461,10 @@ static void knife_input_ray_segment(KnifeTool_OpData *kcd,
ED_view3d_unproject_v3(kcd->vc.region, mval[0], mval[1], ofs, r_origin_ofs);
}
-static void knifetool_recast_cageco(KnifeTool_OpData *kcd, float mval[3], float r_cage[3])
+/* No longer used, but may be useful in the future. */
+static void UNUSED_FUNCTION(knifetool_recast_cageco)(KnifeTool_OpData *kcd,
+ float mval[3],
+ float r_cage[3])
{
float origin[3];
float origin_ofs[3];
@@ -2396,7 +2392,7 @@ static void knife_add_cut(KnifeTool_OpData *kcd)
}
/* Save values for angle drawing calculations. */
- copy_v3_v3(kcd->mdata.cage, kcd->mdata.corr_prev_cage);
+ copy_v3_v3(kcd->mdata.cage, kcd->prev.cage);
copy_v2_v2(kcd->mdata.mval, kcd->prev.mval);
kcd->mdata.is_stored = true;
@@ -2609,6 +2605,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
/**
* Calculate the center and maximum excursion of mesh.
+ * (Considers all meshes in multi-object edit mode)
*/
static void calc_ortho_extent(KnifeTool_OpData *kcd)
{
@@ -2617,6 +2614,7 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
BMIter iter;
BMVert *v;
float min[3], max[3];
+ float ws[3];
INIT_MINMAX(min, max);
for (uint b = 0; b < kcd->objects_len; b++) {
@@ -2624,11 +2622,17 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
em = BKE_editmesh_from_object(ob);
if (kcd->cagecos[b]) {
- minmax_v3v3_v3_array(min, max, kcd->cagecos[b], em->bm->totvert);
+ for (int i = 0; i < em->bm->totvert; i++) {
+ copy_v3_v3(ws, kcd->cagecos[b][i]);
+ mul_m4_v3(ob->obmat, ws);
+ minmax_v3v3_v3(min, max, ws);
+ }
}
else {
BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- minmax_v3v3_v3(min, max, v->co);
+ copy_v3_v3(ws, v->co);
+ mul_m4_v3(ob->obmat, ws);
+ minmax_v3v3_v3(min, max, ws);
}
}
}
@@ -3013,6 +3017,12 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
for (val = BLI_smallhash_iternew(&kfes, &hiter, (uintptr_t *)&kfe); val;
val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&kfe)) {
+ /* If we intersect any of the vertices, don't attempt to intersect the edge. */
+ if (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v1) ||
+ BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v2)) {
+ continue;
+ }
+
knife_project_v2(kcd, kfe->v1->cageco, se1);
knife_project_v2(kcd, kfe->v2->cageco, se2);
int isect_kind = 1;
@@ -3532,9 +3542,9 @@ static bool knife_snap_angle_screen(KnifeTool_OpData *kcd)
float dvec[2], dvec_snap[2];
float snap_step;
- /* Currently user can input any float between 0 and 90. */
+ /* Currently user can input any float between 0 and 180. */
if (kcd->angle_snapping_increment > KNIFE_MIN_ANGLE_SNAPPING_INCREMENT &&
- kcd->angle_snapping_increment < KNIFE_MAX_ANGLE_SNAPPING_INCREMENT) {
+ kcd->angle_snapping_increment <= KNIFE_MAX_ANGLE_SNAPPING_INCREMENT) {
snap_step = DEG2RADF(kcd->angle_snapping_increment);
}
else {
@@ -3688,7 +3698,7 @@ static bool knife_snap_angle_relative(KnifeTool_OpData *kcd)
/* Calculate snap step. */
float snap_step;
if (kcd->angle_snapping_increment > KNIFE_MIN_ANGLE_SNAPPING_INCREMENT &&
- kcd->angle_snapping_increment < KNIFE_MAX_ANGLE_SNAPPING_INCREMENT) {
+ kcd->angle_snapping_increment <= KNIFE_MAX_ANGLE_SNAPPING_INCREMENT) {
snap_step = DEG2RADF(kcd->angle_snapping_increment);
}
else {
@@ -4094,6 +4104,8 @@ static void knifetool_init(bContext *C,
knife_init_colors(&kcd->colors);
}
+ kcd->no_cuts = true;
+
kcd->axis_string[0] = ' ';
kcd->axis_string[1] = '\0';
@@ -4145,7 +4157,7 @@ static void knifetool_exit_ex(KnifeTool_OpData *kcd)
for (int i = 0; i < kcd->objects_len; i++) {
knifetool_free_cagecos(kcd, i);
}
- MEM_freeN(kcd->cagecos);
+ MEM_freeN((void *)kcd->cagecos);
knife_bvh_free(kcd);
/* Line-hits cleanup. */
@@ -4363,7 +4375,8 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
float snapping_increment_temp;
if (kcd->angle_snapping) {
- if (kcd->num.str_cur >= 2) {
+ if (kcd->num.str_cur >= 3 ||
+ kcd->angle_snapping_increment > KNIFE_MAX_ANGLE_SNAPPING_INCREMENT / 10) {
knife_reset_snap_angle_input(kcd);
}
knife_update_header(C, op, kcd); /* Update the angle multiple. */
@@ -4371,9 +4384,9 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->val == KM_PRESS && hasNumInput(&kcd->num) && handleNumInput(C, &kcd->num, event)) {
handled = true;
applyNumInput(&kcd->num, &snapping_increment_temp);
- /* Restrict number key input to 0 - 90 degree range. */
+ /* Restrict number key input to 0 - 180 degree range. */
if (snapping_increment_temp > KNIFE_MIN_ANGLE_SNAPPING_INCREMENT &&
- snapping_increment_temp < KNIFE_MAX_ANGLE_SNAPPING_INCREMENT) {
+ snapping_increment_temp <= KNIFE_MAX_ANGLE_SNAPPING_INCREMENT) {
kcd->angle_snapping_increment = snapping_increment_temp;
}
knife_update_active(C, kcd);
@@ -4505,16 +4518,27 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
handled = true;
break;
case KNF_MODAL_NEW_CUT:
+ /* If no cuts have been made, exit.
+ * Preserves right click cancel workflow which most tools use,
+ * but stops accidentally deleting entire cuts with right click.
+ */
+ if (kcd->no_cuts) {
+ ED_region_tag_redraw(kcd->region);
+ knifetool_exit(op);
+ ED_workspace_status_text(C, NULL);
+ return OPERATOR_CANCELLED;
+ }
ED_region_tag_redraw(kcd->region);
knife_finish_cut(kcd);
kcd->mode = MODE_IDLE;
handled = true;
break;
case KNF_MODAL_ADD_CUT:
+ kcd->no_cuts = false;
knife_recalc_ortho(kcd);
/* Get the value of the event which triggered this one. */
- if (event->prevval != KM_RELEASE) {
+ if (event->prev_val != KM_RELEASE) {
if (kcd->mode == MODE_DRAGGING) {
knife_add_cut(kcd);
}
@@ -4524,16 +4548,6 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
kcd->init = kcd->curr;
}
- /* Preserve correct prev.cage for angle drawing calculations. */
- if (kcd->prev.edge == NULL && kcd->prev.vert == NULL) {
- /* "knife_start_cut" moves prev.cage so needs to be recalculated. */
- /* Only occurs if prev was started on a face. */
- knifetool_recast_cageco(kcd, kcd->prev.mval, kcd->mdata.corr_prev_cage);
- }
- else {
- copy_v3_v3(kcd->mdata.corr_prev_cage, kcd->prev.cage);
- }
-
/* Freehand drawing is incompatible with cut-through. */
if (kcd->cut_through == false) {
kcd->is_drag_hold = true;
@@ -4617,16 +4631,17 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (kcd->angle_snapping) {
- if (kcd->num.str_cur >= 2) {
+ if (kcd->num.str_cur >= 3 ||
+ kcd->angle_snapping_increment > KNIFE_MAX_ANGLE_SNAPPING_INCREMENT / 10) {
knife_reset_snap_angle_input(kcd);
}
if (event->type != EVT_MODAL_MAP) {
/* Modal number-input inactive, try to handle numeric inputs last. */
if (!handled && event->val == KM_PRESS && handleNumInput(C, &kcd->num, event)) {
applyNumInput(&kcd->num, &snapping_increment_temp);
- /* Restrict number key input to 0 - 90 degree range. */
+ /* Restrict number key input to 0 - 180 degree range. */
if (snapping_increment_temp > KNIFE_MIN_ANGLE_SNAPPING_INCREMENT &&
- snapping_increment_temp < KNIFE_MAX_ANGLE_SNAPPING_INCREMENT) {
+ snapping_increment_temp <= KNIFE_MAX_ANGLE_SNAPPING_INCREMENT) {
kcd->angle_snapping_increment = snapping_increment_temp;
}
knife_update_active(C, kcd);
@@ -4752,7 +4767,7 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (wait_for_input == false) {
/* Avoid copy-paste logic. */
wmEvent event_modal = {
- .prevval = KM_NOTHING,
+ .prev_val = KM_NOTHING,
.type = EVT_MODAL_MAP,
.val = KNF_MODAL_ADD_CUT,
};
@@ -4809,7 +4824,7 @@ void MESH_OT_knife_tool(wmOperatorType *ot)
"Occlude Geometry",
"Only cut the front most geometry");
RNA_def_boolean(ot->srna, "only_selected", false, "Only Selected", "Only cut selected geometry");
- RNA_def_boolean(ot->srna, "xray", true, "X-Ray", "Show cuts through geometry");
+ RNA_def_boolean(ot->srna, "xray", true, "X-Ray", "Show cuts hidden by geometry");
RNA_def_enum(ot->srna,
"visible_measurements",
@@ -4865,9 +4880,6 @@ static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
return false;
}
-/**
- * \param use_tag: When set, tag all faces inside the polylines.
- */
void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_through)
{
KnifeTool_OpData *kcd;
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 8b78b091fd2..24825ef1e3a 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -598,13 +598,13 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
case MOUSEPAN:
if (event->alt == 0) {
- cuts += 0.02f * (event->y - event->prevy);
+ cuts += 0.02f * (event->xy[1] - event->prev_xy[1]);
if (cuts < 1 && lcd->cuts >= 1) {
cuts = 1;
}
}
else {
- smoothness += 0.002f * (event->y - event->prevy);
+ smoothness += 0.002f * (event->xy[1] - event->prev_xy[1]);
}
handled = true;
break;
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index cccfc7e934c..a1a7dfac282 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -388,14 +388,14 @@ static int face_set_extract_modal(bContext *C, wmOperator *op, const wmEvent *ev
* that the mouse clicked in a viewport region and its coordinates can be used to ray-cast
* the PBVH and update the active Face Set ID. */
bScreen *screen = CTX_wm_screen(C);
- ARegion *region = BKE_screen_find_main_region_at_xy(
- screen, SPACE_VIEW3D, event->x, event->y);
+ ARegion *region = BKE_screen_find_main_region_at_xy(screen, SPACE_VIEW3D, event->xy);
if (!region) {
return OPERATOR_CANCELLED;
}
- const float mval[2] = {event->x - region->winrct.xmin, event->y - region->winrct.ymin};
+ const float mval[2] = {event->xy[0] - region->winrct.xmin,
+ event->xy[1] - region->winrct.ymin};
Object *ob = CTX_data_active_object(C);
const int face_set_id = ED_sculpt_face_sets_active_update_and_get(C, ob, mval);
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 30a453a32ee..e48b5d8255e 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -377,7 +377,7 @@ static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode)
}
}
-/* mesh shortest path select, uses prev-selected edge */
+/* Mesh shortest path select, uses previously-selected edge. */
/* since you want to create paths with multiple selects, it doesn't have extend option */
static void mouse_mesh_shortest_path_edge(Scene *scene,
diff --git a/source/blender/editors/mesh/editmesh_preselect_elem.c b/source/blender/editors/mesh/editmesh_preselect_elem.c
index dfd646c767f..ab268251061 100644
--- a/source/blender/editors/mesh/editmesh_preselect_elem.c
+++ b/source/blender/editors/mesh/editmesh_preselect_elem.c
@@ -411,4 +411,5 @@ void EDBM_preselect_elem_update_preview(struct EditMesh_PreSelElem *psel,
BLI_assert(0);
}
}
+
/** \} */
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index d1df063d9d0..07ec8e184ba 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -930,7 +930,7 @@ static int edbm_rip_invoke__edge(bContext *C, const wmEvent *event, Object *obed
/* NOTE: if the case of 3 edges has one change in loop stepping,
* if this becomes more involved we may be better off splitting
* the 3 edge case into its own else-if branch */
- if ((totedge_manifold == 4 || totedge_manifold == 3) || (all_manifold == false)) {
+ if ((ELEM(totedge_manifold, 4, 3)) || (all_manifold == false)) {
BMLoop *l_a = e_best->l;
BMLoop *l_b = l_a->radial_next;
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 2fcf8fa6f8f..7e05209f79e 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -267,17 +267,6 @@ static void findnearestvert__doClosest(void *userData,
}
}
-/**
- * Nearest vertex under the cursor.
- *
- * \param dist_px_manhattan_p: (in/out), minimal distance to the nearest and at the end,
- * actual distance.
- * \param use_select_bias:
- * - When true, selected vertices are given a 5 pixel bias
- * to make them further than unselect verts.
- * - When false, unselected vertices are given the bias.
- * \param use_cycle: Cycle over elements within #FIND_NEAR_CYCLE_THRESHOLD_MIN in order of index.
- */
BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc,
float *dist_px_manhattan_p,
const bool use_select_bias,
@@ -713,13 +702,6 @@ static void findnearestface__doClosest(void *userData,
}
}
-/**
- * \param use_zbuf_single_px: Special case, when using the back-buffer selection,
- * only use the pixel at `vc->mval` instead of using `dist_px_manhattan_p` to search over a larger
- * region. This is needed because historically selection worked this way for a long time, however
- * it's reasonable that some callers might want to expand the region too. So add an argument to do
- * this,
- */
BMFace *EDBM_face_find_nearest_ex(ViewContext *vc,
float *dist_px_manhattan_p,
float *r_dist_center,
@@ -884,9 +866,8 @@ static bool unified_findnearest(ViewContext *vc,
BMFace **r_efa)
{
BMEditMesh *em = vc->em;
- static short mval_prev[2] = {-1, -1};
- /* only cycle while the mouse remains still */
- const bool use_cycle = ((mval_prev[0] == vc->mval[0]) && (mval_prev[1] == vc->mval[1]));
+
+ const bool use_cycle = !WM_cursor_test_motion_and_update(vc->mval);
const float dist_init = ED_view3d_select_dist_px();
/* since edges select lines, we give dots advantage of ~20 pix */
const float dist_margin = (dist_init / 2);
@@ -988,9 +969,6 @@ static bool unified_findnearest(ViewContext *vc,
}
}
- mval_prev[0] = vc->mval[0];
- mval_prev[1] = vc->mval[1];
-
/* Only one element type will be non-null. */
BLI_assert(((hit.v.ele != NULL) + (hit.e.ele != NULL) + (hit.f.ele != NULL)) <= 1);
@@ -2221,8 +2199,6 @@ static void edbm_strip_selections(BMEditMesh *em)
}
}
-/* when switching select mode, makes sure selection is consistent for editing */
-/* also for paranoia checks to make sure edge or face mode works */
void EDBM_selectmode_set(BMEditMesh *em)
{
BMVert *eve;
@@ -2277,20 +2253,6 @@ void EDBM_selectmode_set(BMEditMesh *em)
}
}
-/**
- * Expand & Contract the Selection
- * (used when changing modes and Ctrl key held)
- *
- * Flush the selection up:
- * - vert -> edge
- * - vert -> face
- * - edge -> face
- *
- * Flush the selection down:
- * - face -> edge
- * - face -> vert
- * - edge -> vert
- */
void EDBM_selectmode_convert(BMEditMesh *em,
const short selectmode_old,
const short selectmode_new)
@@ -2397,7 +2359,6 @@ void EDBM_selectmode_convert(BMEditMesh *em,
}
}
-/* user facing function, does notification */
bool EDBM_selectmode_toggle_multi(bContext *C,
const short selectmode_new,
const int action,
@@ -2573,12 +2534,6 @@ bool EDBM_selectmode_set_multi(bContext *C, const short selectmode)
return changed;
}
-/**
- * Use to disable a selectmode if its enabled, Using another mode as a fallback
- * if the disabled mode is the only mode set.
- *
- * \return true if the mode is changed.
- */
bool EDBM_selectmode_disable(Scene *scene,
BMEditMesh *em,
const short selectmode_disable,
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index c452f7a7487..949b12f9a65 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -974,6 +974,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1255,6 +1256,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1332,6 +1334,33 @@ static const EnumPropertyItem *select_similar_type_itemf(bContext *C,
return prop_similar_types;
}
+static bool edbm_select_similar_poll_property(const bContext *UNUSED(C),
+ wmOperator *op,
+ const PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ /* Only show threshold when it is used. */
+ if (STREQ(prop_id, "threshold")) {
+ if (!ELEM(type,
+ SIMVERT_NORMAL,
+ SIMEDGE_BEVEL,
+ SIMEDGE_CREASE,
+ SIMEDGE_DIR,
+ SIMEDGE_LENGTH,
+ SIMEDGE_FACE_ANGLE,
+ SIMFACE_AREA,
+ SIMFACE_PERIMETER,
+ SIMFACE_NORMAL,
+ SIMFACE_COPLANAR)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
void MESH_OT_select_similar(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -1345,6 +1374,7 @@ void MESH_OT_select_similar(wmOperatorType *ot)
ot->invoke = WM_menu_invoke;
ot->exec = edbm_select_similar_exec;
ot->poll = ED_operator_editmesh;
+ ot->poll_property = edbm_select_similar_poll_property;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 122214b87d5..633e8183eb3 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -3706,10 +3706,7 @@ static int edbm_shape_propagate_to_all_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
if (tot_shapekeys == 0) {
- BKE_report(op->reports,
- RPT_ERROR,
- objects_len > 1 ? "Meshes do not have shape keys" :
- "Mesh does not have shape keys");
+ BKE_report(op->reports, RPT_ERROR, "Mesh(es) do not have shape keys");
return OPERATOR_CANCELLED;
}
@@ -8229,7 +8226,6 @@ enum {
EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED = 114,
};
-/* Called in transform_ops.c, on each regeneration of key-maps. */
wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index f52cd94b8dc..59c357aa416 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -104,7 +104,7 @@ typedef struct UndoMesh {
int selectmode;
/** \note
- * this isn't a prefect solution, if you edit keys and change shapes this works well
+ * This isn't a perfect solution, if you edit keys and change shapes this works well
* (fixing T32442), but editing shape keys, going into object mode, removing or changing their
* order, then go back into editmode and undo will give issues - where the old index will be
* out of sync with the new object index.
@@ -690,12 +690,12 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key *
em_tmp = BKE_editmesh_create(bm);
*em = *em_tmp;
- /* Calculate face normals and tessellation at once since it's multi-threaded.
- * The vertex normals are stored in the undo-mesh, so this doesn't need to be updated. */
- BKE_editmesh_looptri_calc_ex(em,
- &(const struct BMeshCalcTessellation_Params){
- .face_normals = true,
- });
+ /* Normals should not be stored in the undo mesh, so recalculate them. The edit
+ * mesh is expected to have valid normals and there is no tracked dirty state. */
+ BLI_assert(BKE_mesh_vertex_normals_are_dirty(&um->me));
+
+ /* Calculate face normals and tessellation at once since it's multi-threaded. */
+ BKE_editmesh_looptri_and_normals_calc(em);
em->selectmode = um->selectmode;
bm->selectmode = um->selectmode;
@@ -915,7 +915,6 @@ static void mesh_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_mesh_undosys_type(UndoType *ut)
{
ut->name = "Edit Mesh";
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index c6a8e771362..f3db8f1f0d2 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -68,9 +68,6 @@
* just as the undo stack would.
* So leaving this as an interface for further work */
-/**
- * Save a copy of the #BMesh for restoring later.
- */
BMBackup EDBM_redo_state_store(BMEditMesh *em)
{
BMBackup backup;
@@ -93,9 +90,6 @@ void EDBM_redo_state_restore(BMBackup *backup, BMEditMesh *em, bool recalc_loopt
}
}
-/**
- * Delete the backup, flushing it to an edit-mesh.
- */
void EDBM_redo_state_restore_and_free(BMBackup *backup, BMEditMesh *em, bool recalc_looptri)
{
BM_mesh_data_free(em->bm);
@@ -139,11 +133,6 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *
return true;
}
-/**
- * The return value:
- * - False on error (the mesh must not be changed).
- * - True on success, executes and finishes a #BMesh operator.
- */
bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report)
{
const char *errmsg;
@@ -166,7 +155,7 @@ bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool
eBMOpErrorLevel level;
while (BMO_error_pop(em->bm, &errmsg, NULL, &level)) {
- ReportType type = RPT_INFO;
+ eReportType type = RPT_INFO;
switch (level) {
case BMO_ERROR_CANCEL: {
changed_was_set = true;
@@ -320,11 +309,6 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
EDBM_selectmode_flush(me->edit_mesh);
}
-/**
- * \warning This can invalidate the #Mesh runtime cache of other objects (for linked duplicates).
- * Most callers should run #DEG_id_tag_update on `ob->data`, see: T46738, T46913.
- * This ensures #BKE_object_free_derived_caches runs on all objects that use this mesh.
- */
void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
{
Mesh *me = ob->data;
@@ -350,9 +334,6 @@ void EDBM_mesh_clear(BMEditMesh *em)
/* clear bmesh */
BM_mesh_clear(em->bm);
- /* Free evaluated meshes & cache. */
- BKE_editmesh_free_derived_caches(em);
-
/* free tessellation data */
em->tottri = 0;
MEM_SAFE_FREE(em->looptris);
@@ -363,9 +344,6 @@ void EDBM_mesh_load(Main *bmain, Object *ob)
EDBM_mesh_load_ex(bmain, ob, true);
}
-/**
- * Should only be called on the active edit-mesh, otherwise call #BKE_editmesh_free_data.
- */
void EDBM_mesh_free_data(BMEditMesh *em)
{
/* These tables aren't used yet, so it's not strictly necessary
@@ -486,9 +464,6 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
/** \name UV Vertex Map API
* \{ */
-/**
- * Return a new #UvVertMap from the edit-mesh.
- */
UvVertMap *BM_uv_vert_map_create(BMesh *bm, const bool use_select, const bool use_winding)
{
BMVert *ev;
@@ -632,7 +607,6 @@ UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, uint v)
return vmap->vert[v];
}
-/* A specialized vert map used by stitch operator */
UvElementMap *BM_uv_element_map_create(BMesh *bm,
const Scene *scene,
const bool face_selected,
@@ -953,10 +927,6 @@ UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l)
/** \name Data Layer Checks
* \{ */
-/**
- * last_sel, use em->act_face otherwise get the last selected face in the editselections
- * at the moment, last_sel is mainly useful for making sure the space image doesn't flicker.
- */
BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected)
{
BMFace *efa = NULL;
@@ -974,7 +944,6 @@ BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool se
return NULL;
}
-/* Can we edit UV's for this mesh? */
bool EDBM_uv_check(BMEditMesh *em)
{
/* some of these checks could be a touch overkill */
@@ -1015,20 +984,10 @@ static BMVert *cache_mirr_intptr_as_bmvert(const intptr_t *index_lookup, int ind
* \endcode
*/
-/* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a
- * preference */
+/* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a preference. */
#define BM_SEARCH_MAXDIST_MIRR 0.00002f
#define BM_CD_LAYER_ID "__mirror_index"
-/**
- * \param em: Editmesh.
- * \param use_self: Allow a vertex to point to its self (middle verts).
- * \param use_select: Restrict to selected verts.
- * \param respecthide: Skip hidden vertices.
- * \param use_topology: Use topology mirror.
- * \param maxdist: Distance for close point test.
- * \param r_index: Optional array to write into, as an alternative to a customdata layer
- * (length of total verts).
- */
+
void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em,
const int axis,
const bool use_self,
@@ -1255,7 +1214,6 @@ void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_t
/** \name Hide/Reveal API
* \{ */
-/* swap is 0 or 1, if 1 it hides not selected */
bool EDBM_mesh_hide(BMEditMesh *em, bool swap)
{
BMIter iter;
@@ -1410,9 +1368,6 @@ void EDBM_stats_update(BMEditMesh *em)
}
}
-/**
- * So many tools call these that we better make it a generic function.
- */
void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
{
BMEditMesh *em = mesh->edit_mesh;
@@ -1446,8 +1401,6 @@ void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
BM_lnorspace_invalidate(em->bm, false);
em->bm->spacearr_dirty &= ~BM_SPACEARR_BMO_SET;
}
- /* Don't keep stale evaluated mesh data around, see: T38872. */
- BKE_editmesh_free_derived_caches(em);
#ifdef DEBUG
{
@@ -1459,7 +1412,6 @@ void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
#endif
}
-/* Bad level call from Python API. */
void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool is_destructive)
{
EDBM_update(me,
@@ -1476,7 +1428,6 @@ void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool
/** \name Operator Helpers
* \{ */
-/* poll call for mesh operators requiring a view3d context */
bool EDBM_view3d_poll(bContext *C)
{
if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) {
@@ -1509,11 +1460,6 @@ BMElem *EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFa
return ele;
}
-/**
- * Used when we want to store a single index for any vert/edge/face.
- *
- * Intended for use with operators.
- */
int EDBM_elem_to_index_any(BMEditMesh *em, BMElem *ele)
{
BMesh *bm = em->bm;
@@ -1701,8 +1647,8 @@ void EDBM_project_snap_verts(
ED_view3d_init_mats_rv3d(obedit, region->regiondata);
- struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_scene(C), 0, region, CTX_wm_view3d(C));
+ struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create(
+ CTX_data_scene(C), 0);
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
@@ -1711,6 +1657,8 @@ void EDBM_project_snap_verts(
V3D_PROJ_RET_OK) {
if (ED_transform_snap_object_project_view3d(snap_context,
depsgraph,
+ region,
+ CTX_wm_view3d(C),
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_NOT_ACTIVE,
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index c075d2550cb..0f58752f323 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -208,7 +208,6 @@ static void mesh_uv_reset_mface(MPoly *mp, MLoopUV *mloopuv)
mesh_uv_reset_array(fuv, mp->totloop);
}
-/* without bContext, called in uvedit */
void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum)
{
BMEditMesh *em = me->edit_mesh;
@@ -253,9 +252,11 @@ void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me)
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
}
-/* NOTE: keep in sync with #ED_mesh_color_add. */
-int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set, const bool do_init)
+int ED_mesh_uv_texture_add(
+ Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
+ /* NOTE: keep in sync with #ED_mesh_color_add. */
+
BMEditMesh *em;
int layernum_dst;
@@ -266,6 +267,7 @@ int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set, co
layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV);
if (layernum_dst >= MAX_MTFACE) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i UV maps", MAX_MTFACE);
return -1;
}
@@ -285,6 +287,7 @@ int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set, co
else {
layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
if (layernum_dst >= MAX_MTFACE) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i UV maps", MAX_MTFACE);
return -1;
}
@@ -325,13 +328,13 @@ void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name)
layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV);
if (layernum_dst == 0) {
- ED_mesh_uv_texture_add(me, name, true, true);
+ ED_mesh_uv_texture_add(me, name, true, true, NULL);
}
}
else {
layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
if (layernum_dst == 0) {
- ED_mesh_uv_texture_add(me, name, true, true);
+ ED_mesh_uv_texture_add(me, name, true, true, NULL);
}
}
}
@@ -378,9 +381,11 @@ bool ED_mesh_uv_texture_remove_named(Mesh *me, const char *name)
return false;
}
-/* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
-int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set, const bool do_init)
+int ED_mesh_color_add(
+ Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
+ /* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
+
BMEditMesh *em;
int layernum;
@@ -389,6 +394,7 @@ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set, const b
layernum = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL);
if (layernum >= MAX_MCOL) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i vertex color layers", MAX_MCOL);
return -1;
}
@@ -406,6 +412,7 @@ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set, const b
else {
layernum = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
if (layernum >= MAX_MCOL) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i vertex color layers", MAX_MCOL);
return -1;
}
@@ -510,9 +517,11 @@ static bool sculpt_vertex_color_remove_poll(bContext *C)
return false;
}
-/* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
-int ED_mesh_sculpt_color_add(Mesh *me, const char *name, const bool active_set, const bool do_init)
+int ED_mesh_sculpt_color_add(
+ Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
+ /* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
+
BMEditMesh *em;
int layernum;
@@ -521,6 +530,8 @@ int ED_mesh_sculpt_color_add(Mesh *me, const char *name, const bool active_set,
layernum = CustomData_number_of_layers(&em->bm->vdata, CD_PROP_COLOR);
if (layernum >= MAX_MCOL) {
+ BKE_reportf(
+ reports, RPT_WARNING, "Cannot add more than %i sculpt vertex color layers", MAX_MCOL);
return -1;
}
@@ -538,6 +549,8 @@ int ED_mesh_sculpt_color_add(Mesh *me, const char *name, const bool active_set,
else {
layernum = CustomData_number_of_layers(&me->vdata, CD_PROP_COLOR);
if (layernum >= MAX_MCOL) {
+ BKE_reportf(
+ reports, RPT_WARNING, "Cannot add more than %i sculpt vertex color layers", MAX_MCOL);
return -1;
}
@@ -634,12 +647,12 @@ static bool uv_texture_remove_poll(bContext *C)
return false;
}
-static int mesh_uv_texture_add_exec(bContext *C, wmOperator *UNUSED(op))
+static int mesh_uv_texture_add_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
Mesh *me = ob->data;
- if (ED_mesh_uv_texture_add(me, NULL, true, true) == -1) {
+ if (ED_mesh_uv_texture_add(me, NULL, true, true, op->reports) == -1) {
return OPERATOR_CANCELLED;
}
@@ -719,12 +732,12 @@ static bool vertex_color_remove_poll(bContext *C)
return false;
}
-static int mesh_vertex_color_add_exec(bContext *C, wmOperator *UNUSED(op))
+static int mesh_vertex_color_add_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
Mesh *me = ob->data;
- if (ED_mesh_color_add(me, NULL, true, true) == -1) {
+ if (ED_mesh_color_add(me, NULL, true, true, op->reports) == -1) {
return OPERATOR_CANCELLED;
}
@@ -775,12 +788,12 @@ void MESH_OT_vertex_color_remove(wmOperatorType *ot)
/*********************** Sculpt Vertex Color Operators ************************/
-static int mesh_sculpt_vertex_color_add_exec(bContext *C, wmOperator *UNUSED(op))
+static int mesh_sculpt_vertex_color_add_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
Mesh *me = ob->data;
- if (ED_mesh_sculpt_color_add(me, NULL, true, true) == -1) {
+ if (ED_mesh_sculpt_color_add(me, NULL, true, true, op->reports) == -1) {
return OPERATOR_CANCELLED;
}
@@ -894,6 +907,7 @@ static int mesh_customdata_mask_clear_exec(bContext *C, wmOperator *UNUSED(op))
void MESH_OT_customdata_mask_clear(wmOperatorType *ot)
{
+ /* NOTE: no create_mask yet */
/* identifiers */
ot->name = "Clear Sculpt Mask Data";
@@ -1005,11 +1019,6 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
/* Tag edges as sharp according to smooth threshold if needed,
* to preserve autosmooth shading. */
if (me->flag & ME_AUTOSMOOTH) {
- float(*polynors)[3] = MEM_mallocN(sizeof(*polynors) * (size_t)me->totpoly, __func__);
-
- BKE_mesh_calc_normals_poly(
- me->mvert, me->totvert, me->mloop, me->totloop, me->mpoly, me->totpoly, polynors);
-
BKE_edges_sharp_from_angle_set(me->mvert,
me->totvert,
me->medge,
@@ -1017,11 +1026,9 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
me->mloop,
me->totloop,
me->mpoly,
- polynors,
+ BKE_mesh_poly_normals_ensure(me),
me->totpoly,
me->smoothresh);
-
- MEM_freeN(polynors);
}
CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop);
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index abff3c70e67..575e6d66ccd 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -43,32 +43,44 @@ struct wmOperatorType;
* BMEdit module is for code shared with blenkernel that concerns
* the BMEditMesh structure. */
-/* Calls a bmesh op, reporting errors to the user, etc */
+/** Calls a bmesh op, reporting errors to the user, etc. */
bool EDBM_op_callf(struct BMEditMesh *em, struct wmOperator *op, const char *fmt, ...);
bool EDBM_op_call_and_selectf(struct BMEditMesh *em,
struct wmOperator *op,
const char *select_slot,
- const bool select_replace,
+ bool select_replace,
const char *fmt,
...);
-/* Same as above, but doesn't report errors. */
+/**
+ * Same as above, but doesn't report errors.
+ */
bool EDBM_op_call_silentf(struct BMEditMesh *em, const char *fmt, ...);
-/* these next two functions are the split version of EDBM_op_callf, so you can
- * do stuff with a bmesh operator, after initializing it but before executing
- * it.
+/**
+ * These next two functions are the split version of EDBM_op_callf, so you can
+ * do stuff with a bmesh operator, after initializing it but before executing it.
*
* execute the operator with BM_Exec_Op */
bool EDBM_op_init(
struct BMEditMesh *em, struct BMOperator *bmop, struct wmOperator *op, const char *fmt, ...);
-/* Cleans up after a bmesh operator */
+
+/**
+ * Cleans up after a bmesh operator.
+ *
+ * The return value:
+ * - False on error (the mesh must not be changed).
+ * - True on success, executes and finishes a #BMesh operator.
+ */
bool EDBM_op_finish(struct BMEditMesh *em,
struct BMOperator *bmop,
struct wmOperator *op,
- const bool do_report);
+ bool do_report);
void EDBM_stats_update(struct BMEditMesh *em);
+/**
+ * Poll call for mesh operators requiring a view3d context.
+ */
bool EDBM_view3d_poll(struct bContext *C);
struct BMElem *EDBM_elem_from_selectmode(struct BMEditMesh *em,
@@ -76,6 +88,11 @@ struct BMElem *EDBM_elem_from_selectmode(struct BMEditMesh *em,
struct BMEdge *eed,
struct BMFace *efa);
+/**
+ * Used when we want to store a single index for any vert/edge/face.
+ *
+ * Intended for use with operators.
+ */
int EDBM_elem_to_index_any(struct BMEditMesh *em, struct BMElem *ele);
struct BMElem *EDBM_elem_from_index_any(struct BMEditMesh *em, uint index);
@@ -88,12 +105,16 @@ struct BMElem *EDBM_elem_from_index_any_multi(struct ViewLayer *view_layer,
uint elem_index,
struct Object **r_obedit);
+/**
+ * Extrudes individual edges.
+ */
bool edbm_extrude_edges_indiv(struct BMEditMesh *em,
struct wmOperator *op,
- const char hflag,
- const bool use_normal_flip);
+ char hflag,
+ bool use_normal_flip);
/* *** editmesh_add.c *** */
+
void MESH_OT_primitive_plane_add(struct wmOperatorType *ot);
void MESH_OT_primitive_cube_add(struct wmOperatorType *ot);
void MESH_OT_primitive_circle_add(struct wmOperatorType *ot);
@@ -105,16 +126,20 @@ void MESH_OT_primitive_uv_sphere_add(struct wmOperatorType *ot);
void MESH_OT_primitive_ico_sphere_add(struct wmOperatorType *ot);
/* *** editmesh_add_gizmo.c *** */
+
void MESH_OT_primitive_cube_add_gizmo(struct wmOperatorType *ot);
/* *** editmesh_bevel.c *** */
+
void MESH_OT_bevel(struct wmOperatorType *ot);
struct wmKeyMap *bevel_modal_keymap(struct wmKeyConfig *keyconf);
/* *** editmesh_bisect.c *** */
+
void MESH_OT_bisect(struct wmOperatorType *ot);
/* *** editmesh_extrude.c *** */
+
void MESH_OT_extrude_repeat(struct wmOperatorType *ot);
void MESH_OT_extrude_region(struct wmOperatorType *ot);
void MESH_OT_extrude_context(struct wmOperatorType *ot);
@@ -124,15 +149,20 @@ void MESH_OT_extrude_faces_indiv(struct wmOperatorType *ot);
void MESH_OT_dupli_extrude_cursor(struct wmOperatorType *ot);
/* *** editmesh_extrude_screw.c *** */
+
void MESH_OT_screw(struct wmOperatorType *ot);
/* *** editmesh_extrude_spin.c *** */
+
void MESH_OT_spin(struct wmOperatorType *ot);
+
/* *** editmesh_extrude_spin_gizmo.c *** */
+
void MESH_GGT_spin(struct wmGizmoGroupType *gzgt);
void MESH_GGT_spin_redo(struct wmGizmoGroupType *gzgt);
/* *** editmesh_polybuild.c *** */
+
void MESH_OT_polybuild_face_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_split_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_dissolve_at_cursor(struct wmOperatorType *ot);
@@ -140,16 +170,22 @@ void MESH_OT_polybuild_transform_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_delete_at_cursor(struct wmOperatorType *ot);
/* *** editmesh_inset.c *** */
+
void MESH_OT_inset(struct wmOperatorType *ot);
/* *** editmesh_intersect.c *** */
+
void MESH_OT_intersect(struct wmOperatorType *ot);
void MESH_OT_intersect_boolean(struct wmOperatorType *ot);
void MESH_OT_face_split_by_edges(struct wmOperatorType *ot);
/* *** editmesh_knife.c *** */
+
void MESH_OT_knife_tool(struct wmOperatorType *ot);
void MESH_OT_knife_project(struct wmOperatorType *ot);
+/**
+ * \param use_tag: When set, tag all faces inside the polylines.
+ */
void EDBM_mesh_knife(struct bContext *C,
struct ViewContext *vc,
struct LinkNode *polys,
@@ -159,13 +195,16 @@ void EDBM_mesh_knife(struct bContext *C,
struct wmKeyMap *knifetool_modal_keymap(struct wmKeyConfig *keyconf);
/* *** editmesh_loopcut.c *** */
+
void MESH_OT_loopcut(struct wmOperatorType *ot);
/* *** editmesh_rip.c *** */
+
void MESH_OT_rip(struct wmOperatorType *ot);
void MESH_OT_rip_edge(struct wmOperatorType *ot);
/* *** editmesh_select.c *** */
+
void MESH_OT_select_similar(struct wmOperatorType *ot);
void MESH_OT_select_similar_region(struct wmOperatorType *ot);
void MESH_OT_select_mode(struct wmOperatorType *ot);
@@ -265,10 +304,12 @@ void MESH_OT_smooth_normals(struct wmOperatorType *ot);
void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot);
/* *** editmesh_mask_extract.c *** */
+
void MESH_OT_paint_mask_extract(struct wmOperatorType *ot);
void MESH_OT_face_set_extract(struct wmOperatorType *ot);
void MESH_OT_paint_mask_slice(struct wmOperatorType *ot);
+/** Called in transform_ops.c, on each regeneration of key-maps. */
struct wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf);
#if defined(WITH_FREESTYLE)
@@ -277,13 +318,13 @@ void MESH_OT_mark_freestyle_face(struct wmOperatorType *ot);
#endif
/* *** mesh_data.c *** */
+
void MESH_OT_uv_texture_add(struct wmOperatorType *ot);
void MESH_OT_uv_texture_remove(struct wmOperatorType *ot);
void MESH_OT_vertex_color_add(struct wmOperatorType *ot);
void MESH_OT_vertex_color_remove(struct wmOperatorType *ot);
void MESH_OT_sculpt_vertex_color_add(struct wmOperatorType *ot);
void MESH_OT_sculpt_vertex_color_remove(struct wmOperatorType *ot);
-/* no create_mask yet */
void MESH_OT_customdata_mask_clear(struct wmOperatorType *ot);
void MESH_OT_customdata_skin_add(struct wmOperatorType *ot);
void MESH_OT_customdata_skin_clear(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 94823b92c44..d616dd3bb63 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -372,7 +372,6 @@ void ED_operatormacros_mesh(void)
RNA_boolean_set(otmacro->ptr, "mirror", false);
}
-/* note mesh keymap also for other space? */
void ED_keymap_mesh(wmKeyConfig *keyconf)
{
wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Mesh", 0, 0);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 1b720f2c14d..c9615698c46 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -755,11 +755,10 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
/* -------------------------------------------------------------------- */
/** \name Join as Shapes
+ *
+ * Append selected meshes vertex locations as shapes of the active mesh.
* \{ */
-/* Append selected meshes vertex locations as shapes of the active mesh,
- * return 0 if no join is made (error) and 1 of the join is done */
-
int ED_mesh_shapes_join_objects_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -876,12 +875,6 @@ BLI_INLINE void mesh_mirror_topo_table_get_meshes(Object *ob,
*r_em_mirror = em_mirror;
}
-/**
- * Mode is 's' start, or 'e' end, or 'u' use
- * if end, ob can be NULL.
- * \note This is supposed return -1 on error,
- * which callers are currently checking for, but is not used so far.
- */
void ED_mesh_mirror_topo_table_begin(Object *ob, Mesh *me_eval)
{
Mesh *me_mirror;
@@ -1012,11 +1005,6 @@ BMVert *editbmesh_get_x_mirror_vert(Object *ob,
return editbmesh_get_x_mirror_vert_spatial(ob, em, co);
}
-/**
- * Wrapper for object-mode/edit-mode.
- *
- * call #BM_mesh_elem_table_ensure first for editmesh.
- */
int ED_mesh_mirror_get_vert(Object *ob, int index)
{
Mesh *me = ob->data;
@@ -1146,7 +1134,6 @@ static bool mirror_facecmp(const void *a, const void *b)
return (mirror_facerotation((MFace *)a, (MFace *)b) == -1);
}
-/* This is a Mesh-based copy of mesh_get_x_mirror_faces() */
int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
{
Mesh *me = ob->data;
@@ -1209,15 +1196,8 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
return mirrorfaces;
}
-/* selection, vertex and face */
-/* returns 0 if not found, otherwise 1 */
+/* Selection (vertex and face). */
-/**
- * Face selection in object mode,
- * currently only weight-paint and vertex-paint use this.
- *
- * \return boolean true == Found
- */
bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
{
ViewContext vc;
@@ -1280,10 +1260,6 @@ static void ed_mesh_pick_face_vert__mpoly_find(
}
}
}
-/**
- * Use when the back buffer stores face index values. but we want a vert.
- * This gets the face then finds the closest vertex to mval.
- */
bool ED_mesh_pick_face_vert(
bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
{
@@ -1387,8 +1363,7 @@ typedef struct VertPickData {
static void ed_mesh_pick_vert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
VertPickData *data = userData;
if ((data->mvert[index].flag & ME_HIDE) == 0) {
diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c
index f7b53b5513f..5c724ac2d01 100644
--- a/source/blender/editors/metaball/editmball_undo.c
+++ b/source/blender/editors/metaball/editmball_undo.c
@@ -253,7 +253,6 @@ static void mball_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_mball_undosys_type(UndoType *ut)
{
ut->name = "Edit MBall";
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 292052b778a..bedb9d4f4f4 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -62,7 +62,6 @@
/** \name Edit Mode Functions
* \{ */
-/* This function is used to free all MetaElems from MetaBall */
void ED_mball_editmball_free(Object *obedit)
{
MetaBall *mb = (MetaBall *)obedit->data;
@@ -71,8 +70,6 @@ void ED_mball_editmball_free(Object *obedit)
mb->lastelem = NULL;
}
-/* This function is called, when MetaBall Object is
- * switched from object mode to edit mode */
void ED_mball_editmball_make(Object *obedit)
{
MetaBall *mb = (MetaBall *)obedit->data;
@@ -90,9 +87,6 @@ void ED_mball_editmball_make(Object *obedit)
mb->editelems = &mb->elems;
}
-/* This function is called, when MetaBall Object switched from
- * edit mode to object mode. List of MetaElements is copied
- * from object->data->edit_elems to object->data->elems. */
void ED_mball_editmball_load(Object *UNUSED(obedit))
{
}
@@ -122,9 +116,6 @@ bool ED_mball_deselect_all_multi(bContext *C)
/** \name Add Meta Primitive Utility
* \{ */
-/**
- * Add meta-element primitive to meta-ball object (which is in edit mode).
- */
MetaElem *ED_mball_add_primitive(
bContext *UNUSED(C), Object *obedit, bool obedit_is_new, float mat[4][4], float dia, int type)
{
@@ -759,8 +750,6 @@ void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
/** \name Select Pick Utility
* \{ */
-/* Select MetaElement with mouse click (user can select radius circle or
- * stiffness circle) */
bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index cc4f2acc346..06e21f91d04 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -65,7 +65,6 @@
#include "BKE_displist.h"
#include "BKE_duplilist.h"
#include "BKE_effect.h"
-#include "BKE_font.h"
#include "BKE_geometry_set.h"
#include "BKE_gpencil_curve.h"
#include "BKE_gpencil_geom.h"
@@ -92,6 +91,7 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_speaker.h"
+#include "BKE_vfont.h"
#include "BKE_volume.h"
#include "DEG_depsgraph.h"
@@ -130,7 +130,7 @@
/** \name Local Enum Declarations
* \{ */
-/* this is an exact copy of the define in rna_light.c
+/* This is an exact copy of the define in `rna_light.c`
* kept here because of linking order.
* Icons are only defined here */
const EnumPropertyItem rna_enum_light_type_items[] = {
@@ -259,8 +259,8 @@ static bool object_add_drop_xy_get(bContext *C, wmOperator *op, int (*r_mval)[2]
static int object_add_drop_xy_generic_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (!object_add_drop_xy_is_set(op)) {
- RNA_int_set(op->ptr, "drop_x", event->x);
- RNA_int_set(op->ptr, "drop_y", event->y);
+ RNA_int_set(op->ptr, "drop_x", event->xy[0]);
+ RNA_int_set(op->ptr, "drop_y", event->xy[1]);
}
return op->type->exec(C, op);
}
@@ -331,8 +331,6 @@ void ED_object_base_init_transform_on_add(Object *object, const float loc[3], co
BKE_object_to_mat4(object, object->obmat);
}
-/* Uses context to figure out transform for primitive.
- * Returns standard diameter. */
float ED_object_new_primitive_matrix(bContext *C,
Object *obedit,
const float loc[3],
@@ -603,12 +601,6 @@ bool ED_object_add_generic_get_opts(bContext *C,
return true;
}
-/**
- * For object add primitive operators, or for object creation when `obdata != NULL`.
- * \param obdata: Assigned to #Object.data, with increased user count.
- *
- * \note Do not call undo push in this function (users of this function have to).
- */
Object *ED_object_add_type_with_obdata(bContext *C,
const int type,
const char *name,
@@ -1323,6 +1315,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
const bool use_in_front = RNA_boolean_get(op->ptr, "use_in_front");
const bool use_lights = RNA_boolean_get(op->ptr, "use_lights");
const int stroke_depth_order = RNA_enum_get(op->ptr, "stroke_depth_order");
+ const float stroke_depth_offset = RNA_float_get(op->ptr, "stroke_depth_offset");
ushort local_view_bits;
float loc[3], rot[3];
@@ -1454,6 +1447,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
if (stroke_depth_order == GP_DRAWMODE_3D) {
gpd->draw_mode = GP_DRAWMODE_3D;
}
+ md->stroke_depth_offset = stroke_depth_offset;
}
break;
@@ -1487,13 +1481,14 @@ static void object_add_ui(bContext *UNUSED(C), wmOperator *op)
uiItemR(layout, op->ptr, "type", 0, NULL, ICON_NONE);
int type = RNA_enum_get(op->ptr, "type");
- if (type == GP_LRT_COLLECTION || type == GP_LRT_OBJECT || type == GP_LRT_SCENE) {
+ if (ELEM(type, GP_LRT_COLLECTION, GP_LRT_OBJECT, GP_LRT_SCENE)) {
uiItemR(layout, op->ptr, "use_lights", 0, NULL, ICON_NONE);
uiItemR(layout, op->ptr, "use_in_front", 0, NULL, ICON_NONE);
bool in_front = RNA_boolean_get(op->ptr, "use_in_front");
- uiLayout *row = uiLayoutRow(layout, false);
- uiLayoutSetActive(row, !in_front);
- uiItemR(row, op->ptr, "stroke_depth_order", 0, NULL, ICON_NONE);
+ uiLayout *col = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(col, !in_front);
+ uiItemR(col, op->ptr, "stroke_depth_offset", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "stroke_depth_order", 0, NULL, ICON_NONE);
}
}
@@ -1532,9 +1527,18 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", "");
RNA_def_boolean(ot->srna,
"use_in_front",
- false,
- "In Front",
+ true,
+ "Show In Front",
"Show line art grease pencil in front of everything");
+ RNA_def_float(ot->srna,
+ "stroke_depth_offset",
+ 0.05f,
+ 0.0f,
+ FLT_MAX,
+ "Stroke Offset",
+ "Stroke offset for the line art modifier",
+ 0.0f,
+ 0.5f);
RNA_def_boolean(
ot->srna, "use_lights", false, "Use Lights", "Use lights for this grease pencil object");
RNA_def_enum(
@@ -1543,7 +1547,7 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot)
rna_enum_gpencil_add_stroke_depth_order_items,
GP_DRAWMODE_3D,
"Stroke Depth Order",
- "Defines how the strokes are ordered in 3D space for objects not displayed 'In Front'");
+ "Defines how the strokes are ordered in 3D space for objects not displayed 'In Front')");
}
/** \} */
@@ -1645,12 +1649,25 @@ static int collection_instance_add_exec(bContext *C, wmOperator *op)
PropertyRNA *prop_name = RNA_struct_find_property(op->ptr, "name");
PropertyRNA *prop_location = RNA_struct_find_property(op->ptr, "location");
+ PropertyRNA *prop_session_uuid = RNA_struct_find_property(op->ptr, "session_uuid");
+ bool update_location_if_necessary = false;
if (RNA_property_is_set(op->ptr, prop_name)) {
char name[MAX_ID_NAME - 2];
RNA_property_string_get(op->ptr, prop_name, name);
collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, name);
+ update_location_if_necessary = true;
+ }
+ else if (RNA_property_is_set(op->ptr, prop_session_uuid)) {
+ const uint32_t session_uuid = (uint32_t)RNA_property_int_get(op->ptr, prop_session_uuid);
+ collection = (Collection *)BKE_libblock_find_session_uuid(bmain, ID_GR, session_uuid);
+ update_location_if_necessary = true;
+ }
+ else {
+ collection = BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection"));
+ }
+ if (update_location_if_necessary) {
int mval[2];
if (!RNA_property_is_set(op->ptr, prop_location) && object_add_drop_xy_get(C, op, &mval)) {
ED_object_location_from_view(C, loc);
@@ -1658,9 +1675,6 @@ static int collection_instance_add_exec(bContext *C, wmOperator *op)
RNA_property_float_set_array(op->ptr, prop_location, loc);
}
}
- else {
- collection = BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection"));
- }
if (collection == NULL) {
return OPERATOR_CANCELLED;
@@ -1691,17 +1705,17 @@ static int collection_instance_add_exec(bContext *C, wmOperator *op)
static int object_instance_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (!object_add_drop_xy_is_set(op)) {
- RNA_int_set(op->ptr, "drop_x", event->x);
- RNA_int_set(op->ptr, "drop_y", event->y);
+ RNA_int_set(op->ptr, "drop_x", event->xy[0]);
+ RNA_int_set(op->ptr, "drop_y", event->xy[1]);
}
- if (!RNA_struct_property_is_set(op->ptr, "name")) {
+ if (!RNA_struct_property_is_set(op->ptr, "name") &&
+ !RNA_struct_property_is_set(op->ptr, "session_uuid")) {
return WM_enum_search_invoke(C, op, event);
}
return op->type->exec(C, op);
}
-/* only used as menu */
void OBJECT_OT_collection_instance_add(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -1728,6 +1742,17 @@ void OBJECT_OT_collection_instance_add(wmOperatorType *ot)
ot->prop = prop;
ED_object_add_generic_props(ot, false);
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the collection to add",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+
object_add_drop_xy_props(ot);
}
@@ -1961,8 +1986,7 @@ void OBJECT_OT_pointcloud_add(wmOperatorType *ot)
/* -------------------------------------------------------------------- */
/** \name Delete Object Operator
* \{ */
-/* remove base from a specific scene */
-/* NOTE: now unlinks constraints as well. */
+
void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob)
{
if (ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0 &&
@@ -1980,10 +2004,6 @@ void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob)
BKE_scene_collections_object_remove(bmain, scene, ob, true);
}
-/**
- * Remove base from a specific scene.
- * `ob` must not be indirectly used.
- */
void ED_object_base_free_and_unlink_no_indirect_check(Main *bmain, Scene *scene, Object *ob)
{
BLI_assert(!BKE_library_ID_is_indirectly_used(bmain, ob));
@@ -1997,6 +2017,7 @@ static int object_delete_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
const bool use_global = RNA_boolean_get(op->ptr, "use_global");
+ const bool confirm = op->flag & OP_IS_INVOKE;
uint changed_count = 0;
uint tagged_count = 0;
@@ -2075,7 +2096,9 @@ static int object_delete_exec(bContext *C, wmOperator *op)
BKE_id_multi_tagged_delete(bmain);
}
- BKE_reportf(op->reports, RPT_INFO, "Deleted %u object(s)", (changed_count + tagged_count));
+ if (confirm) {
+ BKE_reportf(op->reports, RPT_INFO, "Deleted %u object(s)", (changed_count + tagged_count));
+ }
/* delete has to handle all open scenes */
BKE_main_id_tag_listbase(&bmain->scenes, LIB_TAG_DOIT, true);
@@ -2130,7 +2153,7 @@ static void copy_object_set_idnew(bContext *C)
Main *bmain = CTX_data_main(C);
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
- BKE_libblock_relink_to_newid(&ob->id);
+ BKE_libblock_relink_to_newid(bmain, &ob->id, 0);
}
CTX_DATA_END;
@@ -2363,7 +2386,7 @@ static void make_object_duplilist_real(bContext *C,
Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob);
/* Remap new object to itself, and clear again newid pointer of orig object. */
- BKE_libblock_relink_to_newid(&ob_dst->id);
+ BKE_libblock_relink_to_newid(bmain, &ob_dst->id, 0);
DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY);
@@ -3079,11 +3102,11 @@ static int object_convert_exec(bContext *C, wmOperator *op)
basen = duplibase_for_convert(bmain, depsgraph, scene, view_layer, base, NULL);
newob = basen->object;
- /* Decrement original point-cloud's usage count. */
+ /* Decrement original point cloud's usage count. */
PointCloud *pointcloud = newob->data;
id_us_min(&pointcloud->id);
- /* Make a new copy of the point-cloud. */
+ /* Make a new copy of the point cloud. */
newob->data = BKE_id_copy(bmain, &pointcloud->id);
}
else {
@@ -3335,11 +3358,6 @@ static Base *object_add_duplicate_internal(Main *bmain,
return basen;
}
-/* single object duplicate, if dupflag==0, fully linked, else it uses the flags given */
-/* leaves selection of base/object unaltered.
- * NOTE: don't call this within a loop since clear_* funcs loop over the entire database.
- * NOTE: caller must do DAG_relations_tag_update(bmain);
- * this is not done automatic since we may duplicate many objects in a batch */
Base *ED_object_add_duplicate(
Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, const eDupli_ID_Flags dupflag)
{
@@ -3359,8 +3377,11 @@ Base *ED_object_add_duplicate(
ob = basen->object;
- /* link own references to the newly duplicated data T26816. */
- BKE_libblock_relink_to_newid(&ob->id);
+ /* Link own references to the newly duplicated data T26816.
+ * Note that this function can be called from edit-mode code, in which case we may have to
+ * enforce remapping obdata (by default this is forbidden in edit mode). */
+ const int remap_flag = BKE_object_is_in_editmode(ob) ? ID_REMAP_FORCE_OBDATA_IN_EDITMODE : 0;
+ BKE_libblock_relink_to_newid(bmain, &ob->id, remap_flag);
/* DAG_relations_tag_update(bmain); */ /* caller must do */
@@ -3466,19 +3487,6 @@ void OBJECT_OT_duplicate(wmOperatorType *ot)
* Use for drag & drop.
* \{ */
-static Base *object_add_ensure_in_view_layer(Main *bmain, ViewLayer *view_layer, Object *ob)
-{
- Base *base = BKE_view_layer_base_find(view_layer, ob);
-
- if (!base) {
- LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
- BKE_collection_object_add(bmain, layer_collection->collection, ob);
- base = BKE_view_layer_base_find(view_layer, ob);
- }
-
- return base;
-}
-
static int object_add_named_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -3486,8 +3494,7 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
Base *basen;
Object *ob;
- const bool duplicate = RNA_boolean_get(op->ptr, "duplicate");
- const bool linked = duplicate && RNA_boolean_get(op->ptr, "linked");
+ const bool linked = RNA_boolean_get(op->ptr, "linked");
const eDupli_ID_Flags dupflag = (linked) ? 0 : (eDupli_ID_Flags)U.dupflag;
char name[MAX_ID_NAME - 2];
@@ -3501,40 +3508,27 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
}
/* prepare dupli */
- if (duplicate) {
- basen = object_add_duplicate_internal(
- bmain,
- scene,
- view_layer,
- ob,
- dupflag,
- /* Sub-process flag because the new-ID remapping (#BKE_libblock_relink_to_newid()) in this
- * function will only work if the object is already linked in the view layer, which is not
- * the case here. So we have to do the new-ID relinking ourselves
- * (#copy_object_set_idnew()).
- */
- LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID);
- }
- else {
- /* basen is actually not a new base in this case. */
- basen = object_add_ensure_in_view_layer(bmain, view_layer, ob);
- }
+ basen = object_add_duplicate_internal(
+ bmain,
+ scene,
+ view_layer,
+ ob,
+ dupflag,
+ /* Sub-process flag because the new-ID remapping (#BKE_libblock_relink_to_newid()) in this
+ * function will only work if the object is already linked in the view layer, which is not
+ * the case here. So we have to do the new-ID relinking ourselves
+ * (#copy_object_set_idnew()).
+ */
+ LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID);
if (basen == NULL) {
- BKE_report(op->reports,
- RPT_ERROR,
- duplicate ? "Object could not be duplicated" :
- "Object could not be linked to the view layer");
+ BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated");
return OPERATOR_CANCELLED;
}
basen->object->visibility_flag &= ~OB_HIDE_VIEWPORT;
-
- int mval[2];
- if (object_add_drop_xy_get(C, op, &mval)) {
- ED_object_location_from_view(C, basen->object->loc);
- ED_view3d_cursor3d_position(C, mval, false, basen->object->loc);
- }
+ /* Do immediately, as #copy_object_set_idnew() below operates on visible objects. */
+ BKE_base_eval_flags(basen);
/* object_add_duplicate_internal() doesn't deselect other objects, unlike object_add_common() or
* BKE_view_layer_base_deselect_all(). */
@@ -3553,44 +3547,164 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
ED_outliner_select_sync_from_object_tag(C);
+ PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix");
+ if (RNA_property_is_set(op->ptr, prop_matrix)) {
+ Object *ob_add = basen->object;
+ RNA_property_float_get_array(op->ptr, prop_matrix, &ob_add->obmat[0][0]);
+ BKE_object_apply_mat4(ob_add, ob_add->obmat, true, true);
+
+ DEG_id_tag_update(&ob_add->id, ID_RECALC_TRANSFORM);
+ }
+ else {
+ int mval[2];
+ if (object_add_drop_xy_get(C, op, &mval)) {
+ ED_object_location_from_view(C, basen->object->loc);
+ ED_view3d_cursor3d_position(C, mval, false, basen->object->loc);
+ }
+ }
+
return OPERATOR_FINISHED;
}
void OBJECT_OT_add_named(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Named Object";
+ ot->name = "Add Object";
ot->description = "Add named object";
ot->idname = "OBJECT_OT_add_named";
/* api callbacks */
ot->invoke = object_add_drop_xy_generic_invoke;
ot->exec = object_add_named_exec;
- ot->poll = ED_operator_objectmode;
+ ot->poll = ED_operator_objectmode_poll_msg;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
PropertyRNA *prop;
-
- prop = RNA_def_boolean(
- ot->srna,
- "duplicate",
- true,
- "Duplicate",
- "Create a duplicate of the object. If not set, only ensures the object is linked into the "
- "active view layer, positions and selects/activates it (deselecting others)");
- RNA_def_property_flag(prop, PROP_HIDDEN);
-
RNA_def_boolean(ot->srna,
"linked",
false,
"Linked",
- "Duplicate object but not object data, linking to the original data (ignored if "
- "'duplicate' is false)");
+ "Duplicate object but not object data, linking to the original data");
RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Object name to add");
+ prop = RNA_def_float_matrix(
+ ot->srna, "matrix", 4, 4, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ object_add_drop_xy_props(ot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Object to Mouse Operator
+ * \{ */
+
+/**
+ * Alternate behavior for dropping an asset that positions the appended object(s).
+ */
+static int object_transform_to_mouse_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob;
+
+ if (RNA_struct_property_is_set(op->ptr, "name")) {
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "name", name);
+ ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name);
+ }
+ else {
+ ob = OBACT(view_layer);
+ }
+
+ if (ob == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Object not found");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Don't transform a linked object. There's just nothing to do here in this case, so return
+ * #OPERATOR_FINISHED. */
+ if (ID_IS_LINKED(ob)) {
+ return OPERATOR_FINISHED;
+ }
+
+ /* Ensure the locations are updated so snap reads the evaluated active location. */
+ CTX_data_ensure_evaluated_depsgraph(C);
+
+ PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix");
+ if (RNA_property_is_set(op->ptr, prop_matrix)) {
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_selected_objects(view_layer, NULL, &objects_len, {0});
+
+ float matrix[4][4];
+ RNA_property_float_get_array(op->ptr, prop_matrix, &matrix[0][0]);
+
+ float mat_src_unit[4][4];
+ float mat_dst_unit[4][4];
+ float final_delta[4][4];
+
+ normalize_m4_m4(mat_src_unit, ob->obmat);
+ normalize_m4_m4(mat_dst_unit, matrix);
+ invert_m4(mat_src_unit);
+ mul_m4_m4m4(final_delta, mat_dst_unit, mat_src_unit);
+
+ ED_object_xform_array_m4(objects, objects_len, final_delta);
+
+ MEM_freeN(objects);
+ }
+ else {
+ int mval[2];
+ if (object_add_drop_xy_get(C, op, &mval)) {
+ float cursor[3];
+ ED_object_location_from_view(C, cursor);
+ ED_view3d_cursor3d_position(C, mval, false, cursor);
+
+ /* Use the active objects location since this is the ID which the user selected to drop.
+ *
+ * This transforms all selected objects, so that dropping a single object which links in
+ * other objects will have their relative transformation preserved.
+ * For example a child/parent relationship or other objects used with a boolean modifier.
+ *
+ * The caller is responsible for ensuring the selection state gives useful results.
+ * Link/append does this using #FILE_AUTOSELECT. */
+ ED_view3d_snap_selected_to_location(C, cursor, V3D_AROUND_ACTIVE);
+ }
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_transform_to_mouse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Place Object Under Mouse";
+ ot->description = "Snap selected item(s) to the mouse location";
+ ot->idname = "OBJECT_OT_transform_to_mouse";
+
+ /* api callbacks */
+ ot->invoke = object_add_drop_xy_generic_invoke;
+ ot->exec = object_transform_to_mouse_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ PropertyRNA *prop;
+ RNA_def_string(ot->srna,
+ "name",
+ NULL,
+ MAX_ID_NAME - 2,
+ "Name",
+ "Object name to place (when unset use the active object)");
+
+ prop = RNA_def_float_matrix(
+ ot->srna, "matrix", 4, 4, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
object_add_drop_xy_props(ot);
}
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 3a10a423e91..b903d664c9b 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -108,8 +108,10 @@ typedef struct {
ListBase data;
/** Clear the images before baking */
bool bake_clear;
- /** Bake-filter, aka margin */
- int bake_filter;
+ /** Margin size in pixels. */
+ int bake_margin;
+ /** margin type */
+ char bake_margin_type;
/** mode of baking (displacement, normals, AO) */
short mode;
/** Use low-resolution mesh when baking displacement maps */
@@ -198,7 +200,7 @@ static bool multiresbake_check(bContext *C, wmOperator *op)
ok = false;
}
- if (ibuf->rect_float && !(ibuf->channels == 0 || ibuf->channels == 4)) {
+ if (ibuf->rect_float && !(ELEM(ibuf->channels, 0, 4))) {
ok = false;
}
@@ -372,7 +374,8 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
/* copy data stored in job descriptor */
bkr.scene = scene;
- bkr.bake_filter = scene->r.bake_filter;
+ bkr.bake_margin = scene->r.bake_margin;
+ bkr.bake_margin_type = scene->r.bake_margin_type;
bkr.mode = scene->r.bake_mode;
bkr.use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH;
bkr.bias = scene->r.bake_biasdist;
@@ -416,7 +419,8 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj)
/* backup scene settings, so their changing in UI would take no effect on baker */
bkj->scene = scene;
- bkj->bake_filter = scene->r.bake_filter;
+ bkj->bake_margin = scene->r.bake_margin;
+ bkj->bake_margin_type = scene->r.bake_margin_type;
bkj->mode = scene->r.bake_mode;
bkj->use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH;
bkj->bake_clear = scene->r.bake_flag & R_BAKE_CLEAR;
@@ -477,7 +481,8 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa
/* copy data stored in job descriptor */
bkr.scene = bkj->scene;
- bkr.bake_filter = bkj->bake_filter;
+ bkr.bake_margin = bkj->bake_margin;
+ bkr.bake_margin_type = bkj->bake_margin_type;
bkr.mode = bkj->mode;
bkr.use_lores_mesh = bkj->use_lores_mesh;
bkr.user_scale = bkj->user_scale;
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 26f5b21a311..d56d0edd5a2 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -89,6 +89,7 @@ typedef struct BakeAPIRender {
eScenePassType pass_type;
int pass_filter;
int margin;
+ eBakeMarginType margin_type;
bool is_clear;
bool is_selected_to_active;
@@ -184,8 +185,11 @@ static bool write_internal_bake_pixels(Image *image,
const int width,
const int height,
const int margin,
+ const char margin_type,
const bool is_clear,
- const bool is_noncolor)
+ const bool is_noncolor,
+ Mesh const *mesh,
+ char const *uv_layer)
{
ImBuf *ibuf;
void *lock;
@@ -281,7 +285,7 @@ static bool write_internal_bake_pixels(Image *image,
/* margins */
if (margin > 0) {
- RE_bake_margin(ibuf, mask_buffer, margin);
+ RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh, uv_layer);
}
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
@@ -314,11 +318,8 @@ static void bake_targets_refresh(BakeTargets *targets)
if (ima) {
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- if (tile->ok == IMA_OK_LOADED) {
- BKE_image_free_gputextures(ima);
- DEG_id_tag_update(&ima->id, 0);
- break;
- }
+ BKE_image_free_gputextures(ima);
+ DEG_id_tag_update(&ima->id, 0);
}
}
}
@@ -330,8 +331,11 @@ static bool write_external_bake_pixels(const char *filepath,
const int width,
const int height,
const int margin,
+ const int margin_type,
ImageFormatData *im_format,
- const bool is_noncolor)
+ const bool is_noncolor,
+ Mesh const *mesh,
+ char const *uv_layer)
{
ImBuf *ibuf = NULL;
bool ok = false;
@@ -388,7 +392,7 @@ static bool write_external_bake_pixels(const char *filepath,
mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask");
RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer);
- RE_bake_margin(ibuf, mask_buffer, margin);
+ RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh, uv_layer);
if (mask_buffer) {
MEM_freeN(mask_buffer);
@@ -697,7 +701,7 @@ static bool bake_targets_init_image_textures(const BakeAPIRender *bkr,
}
}
- /* Overallocate in case there is more materials than images. */
+ /* Over-allocate in case there is more materials than images. */
targets->num_materials = num_materials;
targets->images = MEM_callocN(sizeof(BakeImage) * targets->num_materials, "BakeTargets.images");
targets->material_to_image = MEM_callocN(sizeof(int) * targets->num_materials,
@@ -773,6 +777,7 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr,
ReportList *reports)
{
bool all_ok = true;
+ const Mesh *me = (Mesh *)ob->data;
for (int i = 0; i < targets->num_images; i++) {
BakeImage *bk_image = &targets->images[i];
@@ -783,8 +788,11 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr,
bk_image->width,
bk_image->height,
bkr->margin,
+ bkr->margin_type,
bkr->is_clear,
- targets->is_noncolor);
+ targets->is_noncolor,
+ me,
+ bkr->uv_layer);
/* might be read by UI to set active image for display */
bake_update_image(bkr->area, bk_image->image);
@@ -898,8 +906,11 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr,
bk_image->width,
bk_image->height,
bkr->margin,
+ bkr->margin_type,
&bake->im_format,
- targets->is_noncolor);
+ targets->is_noncolor,
+ me,
+ bkr->uv_layer);
if (!ok) {
BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name);
@@ -1532,22 +1543,22 @@ static int bake(const BakeAPIRender *bkr,
if (md) {
mode = md->mode;
md->mode &= ~eModifierMode_Render;
- }
- /* Evaluate modifiers again. */
- me_nores = BKE_mesh_new_from_object(NULL, ob_low_eval, false, false);
- bake_targets_populate_pixels(bkr, &targets, ob_low, me_nores, pixel_array_low);
+ /* Evaluate modifiers again. */
+ me_nores = BKE_mesh_new_from_object(NULL, ob_low_eval, false, false);
+ bake_targets_populate_pixels(bkr, &targets, ob_low, me_nores, pixel_array_low);
+ }
RE_bake_normal_world_to_tangent(pixel_array_low,
targets.num_pixels,
targets.num_channels,
targets.result,
- me_nores,
+ (me_nores) ? me_nores : me_low_eval,
bkr->normal_swizzle,
ob_low_eval->obmat);
- BKE_id_free(NULL, &me_nores->id);
if (md) {
+ BKE_id_free(NULL, &me_nores->id);
md->mode = mode;
}
}
@@ -1628,6 +1639,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
bkr->pass_type = RNA_enum_get(op->ptr, "type");
bkr->pass_filter = RNA_enum_get(op->ptr, "pass_filter");
bkr->margin = RNA_int_get(op->ptr, "margin");
+ bkr->margin_type = RNA_enum_get(op->ptr, "margin_type");
bkr->save_mode = (eBakeSaveMode)RNA_enum_get(op->ptr, "save_mode");
bkr->target = (eBakeTarget)RNA_enum_get(op->ptr, "target");
@@ -1821,6 +1833,11 @@ static void bake_set_props(wmOperator *op, Scene *scene)
RNA_property_int_set(op->ptr, prop, bake->margin);
}
+ prop = RNA_struct_find_property(op->ptr, "margin_type");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_enum_set(op->ptr, prop, bake->margin_type);
+ }
+
prop = RNA_struct_find_property(op->ptr, "use_selected_to_active");
if (!RNA_property_is_set(op->ptr, prop)) {
RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE) != 0);
@@ -2011,6 +2028,12 @@ void OBJECT_OT_bake(wmOperatorType *ot)
"Extends the baked result as a post process filter",
0,
64);
+ RNA_def_enum(ot->srna,
+ "margin_type",
+ rna_enum_bake_margin_type_items,
+ R_BAKE_EXTEND,
+ "Margin Type",
+ "Which algorithm to use to generate the margin");
RNA_def_boolean(ot->srna,
"use_selected_to_active",
false,
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 8702b18a46f..91a512ae8e9 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -80,10 +80,6 @@
/** \name Constraint Data Accessors
* \{ */
-/**
- * If object is in pose-mode, return active bone constraints, else object constraints.
- * No constraints are returned for a bone on an inactive bone-layer.
- */
ListBase *ED_object_constraint_active_list(Object *ob)
{
if (ob == NULL) {
@@ -93,7 +89,7 @@ ListBase *ED_object_constraint_active_list(Object *ob)
if (ob->mode & OB_MODE_POSE) {
bPoseChannel *pchan;
- pchan = BKE_pose_channel_active(ob);
+ pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan) {
return &pchan->constraints;
}
@@ -105,10 +101,6 @@ ListBase *ED_object_constraint_active_list(Object *ob)
return NULL;
}
-/**
- * Get the constraints for the active pose bone. Bone may be on an inactive bone-layer
- * (unlike #ED_object_constraint_active_list, such constraints are not excluded here).
- */
ListBase *ED_object_pose_constraint_list(const bContext *C)
{
bPoseChannel *pose_bone = CTX_data_pointer_get(C, "pose_bone").data;
@@ -122,8 +114,6 @@ ListBase *ED_object_pose_constraint_list(const bContext *C)
return &pose_bone->constraints;
}
-/* Find the list that a given constraint belongs to,
- * and/or also get the posechannel this is from (if applicable) */
ListBase *ED_object_constraint_list_from_constraint(Object *ob,
bConstraint *con,
bPoseChannel **r_pchan)
@@ -164,7 +154,6 @@ ListBase *ED_object_constraint_list_from_constraint(Object *ob,
return NULL;
}
-/* single constraint */
bConstraint *ED_object_constraint_active_get(Object *ob)
{
return BKE_constraints_active_get(ED_object_constraint_active_list(ob));
@@ -1449,7 +1438,9 @@ void ED_object_constraint_link(Main *bmain, Object *ob_dst, ListBase *dst, ListB
void ED_object_constraint_copy_for_object(Main *bmain, Object *ob_dst, bConstraint *con)
{
- BKE_constraint_copy_for_object(ob_dst, con);
+ bConstraint *copy_con = BKE_constraint_copy_for_object(ob_dst, con);
+ copy_con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL;
+
ED_object_constraint_dependency_tag_update(bmain, ob_dst, con);
WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, ob_dst);
}
@@ -1459,7 +1450,9 @@ void ED_object_constraint_copy_for_pose(Main *bmain,
bPoseChannel *pchan,
bConstraint *con)
{
- BKE_constraint_copy_for_pose(ob_dst, pchan, con);
+ bConstraint *copy_con = BKE_constraint_copy_for_pose(ob_dst, pchan, con);
+ copy_con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL;
+
ED_object_constraint_dependency_tag_update(bmain, ob_dst, con);
WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, ob_dst);
}
@@ -1654,6 +1647,8 @@ static int constraint_copy_exec(bContext *C, wmOperator *op)
/* Couldn't remove due to some invalid data. */
return OPERATOR_CANCELLED;
}
+ copy_con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL;
+
/* Move constraint to correct position. */
const int new_index = BLI_findindex(constraints, con) + 1;
const int current_index = BLI_findindex(constraints, copy_con);
@@ -1731,7 +1726,9 @@ static int constraint_copy_to_selected_exec(bContext *C, wmOperator *op)
continue;
}
- BKE_constraint_copy_for_pose(ob, chan, con);
+ bConstraint *copy_con = BKE_constraint_copy_for_pose(ob, chan, con);
+ copy_con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL;
+
/* Update flags (need to add here, not just copy). */
chan->constflag |= pchan->constflag;
@@ -1753,7 +1750,9 @@ static int constraint_copy_to_selected_exec(bContext *C, wmOperator *op)
continue;
}
- BKE_constraint_copy_for_object(ob, con);
+ bConstraint *copy_con = BKE_constraint_copy_for_object(ob, con);
+ copy_con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL;
+
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM);
}
CTX_DATA_END;
@@ -2216,7 +2215,7 @@ static bool get_new_constraint_target(
bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add)
{
Object *obact = ED_object_active_context(C);
- bPoseChannel *pchanact = BKE_pose_channel_active(obact);
+ bPoseChannel *pchanact = BKE_pose_channel_active_if_layer_visible(obact);
bool only_curve = false, only_mesh = false, only_ob = false;
bool found = false;
@@ -2371,7 +2370,7 @@ static int constraint_add_exec(
pchan = NULL;
}
else {
- pchan = BKE_pose_channel_active(ob);
+ pchan = BKE_pose_channel_active_if_layer_visible(ob);
/* ensure not to confuse object/pose adding */
if (pchan == NULL) {
@@ -2651,7 +2650,7 @@ void POSE_OT_constraint_add_with_targets(wmOperatorType *ot)
static int pose_ik_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
bConstraint *con = NULL;
uiPopupMenu *pup;
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index 6251fb799c5..49149a5152f 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -603,7 +603,6 @@ static bool data_transfer_poll_property(const bContext *UNUSED(C),
return true;
}
-/* Transfer mesh data from active to selected objects. */
void OBJECT_OT_data_transfer(wmOperatorType *ot)
{
PropertyRNA *prop;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 5697c2c973d..38d0a044cb4 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -134,8 +134,6 @@ Object *ED_object_context(const bContext *C)
return CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
}
-/* Find the correct active object per context.
- * NOTE: context can be NULL when called from a enum with #PROP_ENUM_NO_CONTEXT. */
Object *ED_object_active_context(const bContext *C)
{
Object *ob = NULL;
@@ -148,14 +146,6 @@ Object *ED_object_active_context(const bContext *C)
return ob;
}
-/**
- * Return an array of objects:
- * - When in the property space, return the pinned or active object.
- * - When in edit-mode/pose-mode, return an array of objects in the mode.
- * - Otherwise return selected objects,
- * the callers \a filter_fn needs to check of they are editable
- * (assuming they need to be modified).
- */
Object **ED_object_array_in_mode_or_selected(bContext *C,
bool (*filter_fn)(const Object *ob, void *user_data),
void *filter_user_data,
@@ -669,10 +659,6 @@ bool ED_object_editmode_load(Main *bmain, Object *obedit)
return ED_object_editmode_load_free_ex(bmain, obedit, true, false);
}
-/**
- * \param flag:
- * - If #EM_FREEDATA isn't in the flag, use ED_object_editmode_load directly.
- */
bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int flag)
{
const bool free_data = (flag & EM_FREEDATA) != 0;
@@ -723,11 +709,6 @@ bool ED_object_editmode_exit(bContext *C, int flag)
return ED_object_editmode_exit_ex(bmain, scene, obedit, flag);
}
-/**
- * Support freeing edit-mode data without flushing it back to the object.
- *
- * \return true if data was freed.
- */
bool ED_object_editmode_free_ex(Main *bmain, Object *obedit)
{
return ED_object_editmode_load_free_ex(bmain, obedit, false, true);
@@ -1125,12 +1106,46 @@ static eAnimvizCalcRange object_path_convert_range(eObjectPathCalcRange range)
return ANIMVIZ_CALC_RANGE_FULL;
}
-/* For the objects with animation: update paths for those that have got them
- * This should selectively update paths that exist...
- *
- * To be called from various tools that do incremental updates
- */
-void ED_objects_recalculate_paths(bContext *C, Scene *scene, eObjectPathCalcRange range)
+void ED_objects_recalculate_paths_selected(bContext *C, Scene *scene, eObjectPathCalcRange range)
+{
+ ListBase selected_objects = {NULL, NULL};
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
+ BLI_addtail(&selected_objects, BLI_genericNodeN(ob));
+ }
+ CTX_DATA_END;
+
+ ED_objects_recalculate_paths(C, scene, range, &selected_objects);
+
+ BLI_freelistN(&selected_objects);
+}
+
+void ED_objects_recalculate_paths_visible(bContext *C, Scene *scene, eObjectPathCalcRange range)
+{
+ ListBase visible_objects = {NULL, NULL};
+ CTX_DATA_BEGIN (C, Object *, ob, visible_objects) {
+ BLI_addtail(&visible_objects, BLI_genericNodeN(ob));
+ }
+ CTX_DATA_END;
+
+ ED_objects_recalculate_paths(C, scene, range, &visible_objects);
+
+ BLI_freelistN(&visible_objects);
+}
+
+static bool has_object_motion_paths(Object *ob)
+{
+ return (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
+}
+
+static bool has_pose_motion_paths(Object *ob)
+{
+ return ob->pose && (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
+}
+
+void ED_objects_recalculate_paths(bContext *C,
+ Scene *scene,
+ eObjectPathCalcRange range,
+ ListBase *ld_objects)
{
/* Transform doesn't always have context available to do update. */
if (C == NULL) {
@@ -1141,13 +1156,20 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, eObjectPathCalcRang
ViewLayer *view_layer = CTX_data_view_layer(C);
ListBase targets = {NULL, NULL};
- /* loop over objects in scene */
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
+ LISTBASE_FOREACH (LinkData *, link, ld_objects) {
+ Object *ob = link->data;
+
/* set flag to force recalc, then grab path(s) from object */
- ob->avs.recalc |= ANIMVIZ_RECALC_PATHS;
+ if (has_object_motion_paths(ob)) {
+ ob->avs.recalc |= ANIMVIZ_RECALC_PATHS;
+ }
+
+ if (has_pose_motion_paths(ob)) {
+ ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS;
+ }
+
animviz_get_object_motionpaths(ob, &targets);
}
- CTX_DATA_END;
Depsgraph *depsgraph;
bool free_depsgraph = false;
@@ -1172,12 +1194,13 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, eObjectPathCalcRang
if (range != OBJECT_PATH_CALC_RANGE_CURRENT_FRAME) {
/* Tag objects for copy on write - so paths will draw/redraw
* For currently frame only we update evaluated object directly. */
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
- if (ob->mpath) {
+ LISTBASE_FOREACH (LinkData *, link, ld_objects) {
+ Object *ob = link->data;
+
+ if (has_object_motion_paths(ob) || has_pose_motion_paths(ob)) {
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
}
- CTX_DATA_END;
}
/* Free temporary depsgraph. */
@@ -1229,10 +1252,10 @@ static int object_calculate_paths_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* calculate the paths for objects that have them (and are tagged to get refreshed) */
- ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
+ ED_objects_recalculate_paths_selected(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM | ND_POSE, NULL);
return OPERATOR_FINISHED;
}
@@ -1298,10 +1321,10 @@ static int object_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
}
/* calculate the paths for objects that have them (and are tagged to get refreshed) */
- ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
+ ED_objects_recalculate_paths_selected(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM | ND_POSE, NULL);
return OPERATOR_FINISHED;
}
@@ -1311,7 +1334,7 @@ void OBJECT_OT_paths_update(wmOperatorType *ot)
/* identifiers */
ot->name = "Update Object Paths";
ot->idname = "OBJECT_OT_paths_update";
- ot->description = "Recalculate paths for selected objects";
+ ot->description = "Recalculate motion paths for selected objects";
/* api callbacks */
ot->exec = object_update_paths_exec;
@@ -1324,6 +1347,47 @@ void OBJECT_OT_paths_update(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Update All Motion Paths Operator
+ * \{ */
+
+static bool object_update_all_paths_poll(bContext *UNUSED(C))
+{
+ return true;
+}
+
+static int object_update_all_paths_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+
+ if (scene == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_objects_recalculate_paths_visible(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE | ND_TRANSFORM, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_paths_update_visible(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Update All Object Paths";
+ ot->idname = "OBJECT_OT_paths_update_visible";
+ ot->description = "Recalculate all visible motion paths for objects and poses";
+
+ /* api callbacks */
+ ot->exec = object_update_all_paths_exec;
+ ot->poll = object_update_all_paths_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Clear Motion Paths Operator
* \{ */
@@ -1340,7 +1404,6 @@ static void object_clear_mpath(Object *ob)
}
}
-/* Clear motion paths for all objects */
void ED_objects_clear_paths(bContext *C, bool only_selected)
{
if (only_selected) {
@@ -1575,10 +1638,10 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot)
/** \name Object Mode Set Operator
* \{ */
-static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
- PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop),
- bool *r_free)
+static const EnumPropertyItem *object_mode_set_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
{
const EnumPropertyItem *input = rna_enum_object_mode_items;
EnumPropertyItem *item = NULL;
@@ -1727,7 +1790,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
ot->prop = RNA_def_enum(
ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", "");
- RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf);
+ RNA_def_enum_funcs(ot->prop, object_mode_set_itemf);
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
@@ -1739,7 +1802,7 @@ void OBJECT_OT_mode_set_with_submode(wmOperatorType *ot)
OBJECT_OT_mode_set(ot);
/* identifiers */
- ot->name = "Set Object Mode with Submode";
+ ot->name = "Set Object Mode with Sub-mode";
ot->idname = "OBJECT_OT_mode_set_with_submode";
/* properties */
diff --git a/source/blender/editors/object/object_facemap_ops.c b/source/blender/editors/object/object_facemap_ops.c
index 92f3d28878c..f5127bd5228 100644
--- a/source/blender/editors/object/object_facemap_ops.c
+++ b/source/blender/editors/object/object_facemap_ops.c
@@ -53,7 +53,6 @@
#include "object_intern.h"
-/* called while not in editmode */
void ED_object_facemap_face_add(Object *ob, bFaceMap *fmap, int facenum)
{
int fmap_nr;
@@ -77,7 +76,6 @@ void ED_object_facemap_face_add(Object *ob, bFaceMap *fmap, int facenum)
}
}
-/* called while not in editmode */
void ED_object_facemap_face_remove(Object *ob, bFaceMap *fmap, int facenum)
{
int fmap_nr;
diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c
index e3c2932e17a..5a6c25caacc 100644
--- a/source/blender/editors/object/object_gpencil_modifier.c
+++ b/source/blender/editors/object/object_gpencil_modifier.c
@@ -533,6 +533,10 @@ static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op,
Object *ob,
int type)
{
+ if (ob == NULL) {
+ return NULL;
+ }
+
char modifier_name[MAX_NAME];
GpencilModifierData *md;
RNA_string_get(op->ptr, "modifier", modifier_name);
@@ -968,6 +972,9 @@ static int dash_segment_add_exec(bContext *C, wmOperator *op)
DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
op, ob, eGpencilModifierType_Dash);
+ if (dmd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
const int new_active_index = dmd->segment_active_index + 1;
DashGpencilModifierSegment *new_segments = MEM_malloc_arrayN(
dmd->segments_len + 1, sizeof(DashGpencilModifierSegment), __func__);
@@ -1032,6 +1039,10 @@ static int dash_segment_remove_exec(bContext *C, wmOperator *op)
DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
op, ob, eGpencilModifierType_Dash);
+ if (dmd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
if (dmd->segment_active_index < 0 || dmd->segment_active_index >= dmd->segments_len) {
return OPERATOR_CANCELLED;
}
@@ -1108,6 +1119,10 @@ static int dash_segment_move_exec(bContext *C, wmOperator *op)
DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
op, ob, eGpencilModifierType_Dash);
+ if (dmd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
if (dmd->segments_len < 2) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 5065a2c00f0..51967ff35c7 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -582,7 +582,7 @@ static int add_hook_object(const bContext *C,
BLI_strncpy(hmd->subtarget, arm->act_bone->name, sizeof(hmd->subtarget));
- pchan_act = BKE_pose_channel_active(ob);
+ pchan_act = BKE_pose_channel_active_if_layer_visible(ob);
if (LIKELY(pchan_act)) {
invert_m4_m4(pose_mat, pchan_act->pose_mat);
mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]);
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index d00e6efeb29..d517d68f1fc 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -45,6 +45,7 @@ enum eObject_Hook_Add_Mode {
/* internal exports only */
/* object_transform.c */
+
void OBJECT_OT_location_clear(struct wmOperatorType *ot);
void OBJECT_OT_rotation_clear(struct wmOperatorType *ot);
void OBJECT_OT_scale_clear(struct wmOperatorType *ot);
@@ -55,6 +56,7 @@ void OBJECT_OT_transform_axis_target(struct wmOperatorType *ot);
void OBJECT_OT_origin_set(struct wmOperatorType *ot);
/* object_relations.c */
+
void OBJECT_OT_parent_set(struct wmOperatorType *ot);
void OBJECT_OT_parent_no_inverse_set(struct wmOperatorType *ot);
void OBJECT_OT_parent_clear(struct wmOperatorType *ot);
@@ -67,10 +69,18 @@ void OBJECT_OT_convert_proxy_to_override(struct wmOperatorType *ot);
void OBJECT_OT_make_single_user(struct wmOperatorType *ot);
void OBJECT_OT_make_links_scene(struct wmOperatorType *ot);
void OBJECT_OT_make_links_data(struct wmOperatorType *ot);
+/**
+ * Used for drop-box.
+ * Assigns to object under cursor, only first material slot.
+ */
void OBJECT_OT_drop_named_material(struct wmOperatorType *ot);
+/**
+ * \note Only for empty-image objects, this operator is needed
+ */
void OBJECT_OT_unlink_data(struct wmOperatorType *ot);
/* object_edit.c */
+
void OBJECT_OT_hide_view_set(struct wmOperatorType *ot);
void OBJECT_OT_hide_view_clear(struct wmOperatorType *ot);
void OBJECT_OT_hide_collection(struct wmOperatorType *ot);
@@ -84,6 +94,7 @@ void OBJECT_OT_paths_calculate(struct wmOperatorType *ot);
void OBJECT_OT_paths_update(struct wmOperatorType *ot);
void OBJECT_OT_paths_clear(struct wmOperatorType *ot);
void OBJECT_OT_paths_range_update(struct wmOperatorType *ot);
+void OBJECT_OT_paths_update_visible(struct wmOperatorType *ot);
void OBJECT_OT_forcefield_toggle(struct wmOperatorType *ot);
void OBJECT_OT_move_to_collection(struct wmOperatorType *ot);
@@ -92,6 +103,7 @@ void OBJECT_OT_link_to_collection(struct wmOperatorType *ot);
void OBJECT_OT_transfer_mode(struct wmOperatorType *ot);
/* object_select.c */
+
void OBJECT_OT_select_all(struct wmOperatorType *ot);
void OBJECT_OT_select_random(struct wmOperatorType *ot);
void OBJECT_OT_select_by_type(struct wmOperatorType *ot);
@@ -103,8 +115,10 @@ void OBJECT_OT_select_less(struct wmOperatorType *ot);
void OBJECT_OT_select_same_collection(struct wmOperatorType *ot);
/* object_add.c */
+
void OBJECT_OT_add(struct wmOperatorType *ot);
void OBJECT_OT_add_named(struct wmOperatorType *ot);
+void OBJECT_OT_transform_to_mouse(struct wmOperatorType *ot);
void OBJECT_OT_metaball_add(struct wmOperatorType *ot);
void OBJECT_OT_text_add(struct wmOperatorType *ot);
void OBJECT_OT_armature_add(struct wmOperatorType *ot);
@@ -118,6 +132,9 @@ void OBJECT_OT_camera_add(struct wmOperatorType *ot);
void OBJECT_OT_speaker_add(struct wmOperatorType *ot);
void OBJECT_OT_hair_add(struct wmOperatorType *ot);
void OBJECT_OT_pointcloud_add(struct wmOperatorType *ot);
+/**
+ * Only used as menu.
+ */
void OBJECT_OT_collection_instance_add(struct wmOperatorType *ot);
void OBJECT_OT_data_instance_add(struct wmOperatorType *ot);
@@ -129,10 +146,15 @@ void OBJECT_OT_join_shapes(struct wmOperatorType *ot);
void OBJECT_OT_convert(struct wmOperatorType *ot);
/* object_volume.c */
+
void OBJECT_OT_volume_add(struct wmOperatorType *ot);
+/**
+ * Called by other space types too.
+ */
void OBJECT_OT_volume_import(struct wmOperatorType *ot);
/* object_hook.c */
+
void OBJECT_OT_hook_add_selob(struct wmOperatorType *ot);
void OBJECT_OT_hook_add_newob(struct wmOperatorType *ot);
void OBJECT_OT_hook_remove(struct wmOperatorType *ot);
@@ -142,6 +164,7 @@ void OBJECT_OT_hook_reset(struct wmOperatorType *ot);
void OBJECT_OT_hook_recenter(struct wmOperatorType *ot);
/* object_collection.c */
+
void COLLECTION_OT_create(struct wmOperatorType *ot);
void COLLECTION_OT_objects_remove_all(struct wmOperatorType *ot);
void COLLECTION_OT_objects_remove(struct wmOperatorType *ot);
@@ -149,11 +172,12 @@ void COLLECTION_OT_objects_add_active(struct wmOperatorType *ot);
void COLLECTION_OT_objects_remove_active(struct wmOperatorType *ot);
/* object_modifier.c */
+
bool edit_modifier_poll_generic(struct bContext *C,
struct StructRNA *rna_type,
int obtype_flag,
- const bool is_editmode_allowed,
- const bool is_liboverride_allowed);
+ bool is_editmode_allowed,
+ bool is_liboverride_allowed);
void edit_modifier_properties(struct wmOperatorType *ot);
bool edit_modifier_invoke_properties(struct bContext *C, struct wmOperator *op);
@@ -247,6 +271,7 @@ void CONSTRAINT_OT_objectsolver_clear_inverse(struct wmOperatorType *ot);
void CONSTRAINT_OT_followpath_path_animate(struct wmOperatorType *ot);
/* object_vgroup.c */
+
void OBJECT_OT_vertex_group_add(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_remove(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_assign(struct wmOperatorType *ot);
@@ -277,6 +302,7 @@ void OBJECT_OT_vertex_weight_normalize_active_vertex(struct wmOperatorType *ot);
void OBJECT_OT_vertex_weight_copy(struct wmOperatorType *ot);
/* object_facemap_ops.c */
+
void OBJECT_OT_face_map_add(struct wmOperatorType *ot);
void OBJECT_OT_face_map_remove(struct wmOperatorType *ot);
void OBJECT_OT_face_map_assign(struct wmOperatorType *ot);
@@ -286,9 +312,11 @@ void OBJECT_OT_face_map_deselect(struct wmOperatorType *ot);
void OBJECT_OT_face_map_move(struct wmOperatorType *ot);
/* object_warp.c */
+
void TRANSFORM_OT_vertex_warp(struct wmOperatorType *ot);
/* object_shapekey.c */
+
void OBJECT_OT_shape_key_add(struct wmOperatorType *ot);
void OBJECT_OT_shape_key_remove(struct wmOperatorType *ot);
void OBJECT_OT_shape_key_clear(struct wmOperatorType *ot);
@@ -297,6 +325,7 @@ void OBJECT_OT_shape_key_mirror(struct wmOperatorType *ot);
void OBJECT_OT_shape_key_move(struct wmOperatorType *ot);
/* object_collection.c */
+
void OBJECT_OT_collection_add(struct wmOperatorType *ot);
void OBJECT_OT_collection_link(struct wmOperatorType *ot);
void OBJECT_OT_collection_remove(struct wmOperatorType *ot);
@@ -304,18 +333,25 @@ void OBJECT_OT_collection_unlink(struct wmOperatorType *ot);
void OBJECT_OT_collection_objects_select(struct wmOperatorType *ot);
/* object_bake.c */
+
void OBJECT_OT_bake_image(wmOperatorType *ot);
void OBJECT_OT_bake(wmOperatorType *ot);
/* object_random.c */
+
void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
/* object_remesh.cc */
+
void OBJECT_OT_voxel_remesh(struct wmOperatorType *ot);
void OBJECT_OT_voxel_size_edit(struct wmOperatorType *ot);
void OBJECT_OT_quadriflow_remesh(struct wmOperatorType *ot);
/* object_transfer_data.c */
+
+/**
+ * Transfer mesh data from active to selected objects.
+ */
void OBJECT_OT_data_transfer(struct wmOperatorType *ot);
void OBJECT_OT_datalayout_transfer(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index 2c58ef02486..d3f72b91366 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -111,10 +111,6 @@ static const char *object_mode_op_string(eObjectMode mode)
return NULL;
}
-/**
- * Checks the mode to be set is compatible with the object
- * should be made into a generic function
- */
bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
{
if (mode == OB_MODE_OBJECT) {
@@ -162,11 +158,6 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
return false;
}
-/**
- * Sets the mode to a compatible state (use before entering the mode).
- *
- * This is so each mode's exec function can call
- */
bool ED_object_mode_compat_set(bContext *C, Object *ob, eObjectMode mode, ReportList *reports)
{
bool ok;
@@ -497,51 +488,8 @@ static bool object_transfer_mode_to_base(bContext *C, wmOperator *op, Base *base
return mode_transfered;
}
-static int object_transfer_mode_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- switch (event->type) {
- case LEFTMOUSE:
- if (event->val == KM_PRESS) {
- WM_cursor_modal_restore(CTX_wm_window(C));
- ED_workspace_status_text(C, NULL);
-
- /* This ensures that the click was done in an viewport region. */
- bScreen *screen = CTX_wm_screen(C);
- ARegion *region = BKE_screen_find_main_region_at_xy(
- screen, SPACE_VIEW3D, event->x, event->y);
- if (!region) {
- return OPERATOR_CANCELLED;
- }
-
- const int mval[2] = {event->x - region->winrct.xmin, event->y - region->winrct.ymin};
- Base *base_dst = ED_view3d_give_base_under_cursor(C, mval);
- const bool mode_transfered = object_transfer_mode_to_base(C, op, base_dst);
- if (!mode_transfered) {
- return OPERATOR_CANCELLED;
- }
-
- return OPERATOR_FINISHED;
- }
- break;
- case RIGHTMOUSE: {
- WM_cursor_modal_restore(CTX_wm_window(C));
- ED_workspace_status_text(C, NULL);
- return OPERATOR_CANCELLED;
- }
- }
- return OPERATOR_RUNNING_MODAL;
-}
-
static int object_transfer_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- const bool use_eyedropper = RNA_boolean_get(op->ptr, "use_eyedropper");
- if (use_eyedropper) {
- ED_workspace_status_text(C, TIP_("Click in the viewport to select an object"));
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
- WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
- }
-
Object *ob_src = CTX_data_active_object(C);
const eObjectMode src_mode = (eObjectMode)ob_src->mode;
@@ -569,17 +517,12 @@ void OBJECT_OT_transfer_mode(wmOperatorType *ot)
/* api callbacks */
ot->invoke = object_transfer_mode_invoke;
- ot->modal = object_transfer_mode_modal;
ot->poll = object_transfer_mode_poll;
/* Undo push is handled by the operator. */
- ot->flag = OPTYPE_REGISTER;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_DEPENDS_ON_CURSOR;
- RNA_def_boolean(ot->srna,
- "use_eyedropper",
- false,
- "Use Eyedropper",
- "Pick the object to switch to using an eyedropper");
+ ot->cursor_pending = WM_CURSOR_EYEDROPPER;
RNA_def_boolean(ot->srna,
"use_flash_on_transfer",
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 125cd65631a..71ad54383a6 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -152,12 +152,6 @@ static void object_force_modifier_bind_simple_options(Depsgraph *depsgraph,
md_eval->mode = mode;
}
-/**
- * Add a modifier to given object, including relevant extra processing needed by some physics types
- * (particles, simulations...).
- *
- * \param scene: is only used to set current frame in some cases, and may be NULL.
- */
ModifierData *ED_object_modifier_add(
ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
{
@@ -264,14 +258,6 @@ static bool object_has_modifier(const Object *ob, const ModifierData *exclude, M
return false;
}
-/* If the object data of 'orig_ob' has other users, run 'callback' on
- * each of them.
- *
- * If include_orig is true, the callback will run on 'orig_ob' too.
- *
- * If the callback ever returns true, iteration will stop and the
- * function value will be true. Otherwise the function returns false.
- */
bool ED_object_iter_other(Main *bmain,
Object *orig_ob,
const bool include_orig,
@@ -314,9 +300,6 @@ static bool object_has_modifier_cb(Object *ob, void *data)
return object_has_modifier(ob, NULL, type);
}
-/* Use with ED_object_iter_other(). Sets the total number of levels
- * for any multires modifiers on the object to the int pointed to by
- * callback_data. */
bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v)
{
int totlevel = *((char *)totlevel_v);
@@ -666,12 +649,13 @@ bool ED_object_modifier_convert(ReportList *UNUSED(reports),
static Mesh *modifier_apply_create_mesh_for_modifier(Depsgraph *depsgraph,
Object *object,
ModifierData *md_eval,
+ bool use_virtual_modifiers,
bool build_shapekey_layers)
{
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
Mesh *mesh_applied = BKE_mesh_create_derived_for_modifier(
- depsgraph, scene_eval, object_eval, md_eval, build_shapekey_layers);
+ depsgraph, scene_eval, object_eval, md_eval, use_virtual_modifiers, build_shapekey_layers);
return mesh_applied;
}
@@ -708,7 +692,8 @@ static bool modifier_apply_shape(Main *bmain,
return false;
}
- Mesh *mesh_applied = modifier_apply_create_mesh_for_modifier(depsgraph, ob, md_eval, false);
+ Mesh *mesh_applied = modifier_apply_create_mesh_for_modifier(
+ depsgraph, ob, md_eval, true, false);
if (!mesh_applied) {
BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply");
return false;
@@ -729,7 +714,7 @@ static bool modifier_apply_shape(Main *bmain,
BKE_id_free(NULL, mesh_applied);
}
else {
- /* TODO: implement for hair, point-clouds and volumes. */
+ /* TODO: implement for hair, point clouds and volumes. */
BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
return false;
}
@@ -767,7 +752,8 @@ static bool modifier_apply_obdata(
}
}
else {
- Mesh *mesh_applied = modifier_apply_create_mesh_for_modifier(depsgraph, ob, md_eval, true);
+ Mesh *mesh_applied = modifier_apply_create_mesh_for_modifier(
+ depsgraph, ob, md_eval, true, true);
if (!mesh_applied) {
BKE_report(reports, RPT_ERROR, "Modifier returned error, skipping apply");
return false;
@@ -827,7 +813,7 @@ static bool modifier_apply_obdata(
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
else {
- /* TODO: implement for hair, point-clouds and volumes. */
+ /* TODO: implement for hair, point clouds and volumes. */
BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
return false;
}
@@ -1693,6 +1679,8 @@ void OBJECT_OT_modifier_set_active(wmOperatorType *ot)
}
/** \} */
+
+/* ------------------------------------------------------------------- */
/** \name Copy Modifier To Selected Operator
* \{ */
@@ -1927,8 +1915,8 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- const eMultiresSubdivideModeType subdivide_mode = (eMultiresSubdivideModeType)(
- RNA_enum_get(op->ptr, "mode"));
+ const eMultiresSubdivideModeType subdivide_mode = (eMultiresSubdivideModeType)(RNA_enum_get(
+ op->ptr, "mode"));
multiresModifier_subdivide(object, mmd, subdivide_mode);
ED_object_iter_other(
@@ -2692,6 +2680,7 @@ void OBJECT_OT_skin_armature_create(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
}
+
/** \} */
/* ------------------------------------------------------------------- */
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index fa0208a7022..b171da42522 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -62,6 +62,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_paths_update);
WM_operatortype_append(OBJECT_OT_paths_clear);
WM_operatortype_append(OBJECT_OT_paths_range_update);
+ WM_operatortype_append(OBJECT_OT_paths_update_visible);
WM_operatortype_append(OBJECT_OT_forcefield_toggle);
WM_operatortype_append(OBJECT_OT_transfer_mode);
@@ -111,6 +112,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_volume_import);
WM_operatortype_append(OBJECT_OT_add);
WM_operatortype_append(OBJECT_OT_add_named);
+ WM_operatortype_append(OBJECT_OT_transform_to_mouse);
WM_operatortype_append(OBJECT_OT_effector_add);
WM_operatortype_append(OBJECT_OT_collection_instance_add);
WM_operatortype_append(OBJECT_OT_data_instance_add);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 5c7e1e1fa01..a6eb35d49b9 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -583,8 +583,8 @@ bool ED_object_parent_set(ReportList *reports,
}
case PAR_BONE:
case PAR_BONE_RELATIVE:
- pchan = BKE_pose_channel_active(par);
- pchan_eval = BKE_pose_channel_active(parent_eval);
+ pchan = BKE_pose_channel_active_if_layer_visible(par);
+ pchan_eval = BKE_pose_channel_active_if_layer_visible(parent_eval);
if (pchan == NULL) {
BKE_report(reports, RPT_ERROR, "No active bone");
@@ -1677,18 +1677,28 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
/** \name Make Single User Operator
* \{ */
-static void libblock_relink_collection(Collection *collection, const bool do_collection)
+static bool single_data_needs_duplication(ID *id)
+{
+ /* NOTE: When dealing with linked data, we always make a local copy of it.
+ * While in theory we could rather make it local when it only has one user, this is difficult
+ * in practice with current code of this function. */
+ return (id != NULL && (id->us > 1 || ID_IS_LINKED(id)));
+}
+
+static void libblock_relink_collection(Main *bmain,
+ Collection *collection,
+ const bool do_collection)
{
if (do_collection) {
- BKE_libblock_relink_to_newid(&collection->id);
+ BKE_libblock_relink_to_newid(bmain, &collection->id, 0);
}
for (CollectionObject *cob = collection->gobject.first; cob != NULL; cob = cob->next) {
- BKE_libblock_relink_to_newid(&cob->ob->id);
+ BKE_libblock_relink_to_newid(bmain, &cob->ob->id, 0);
}
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
- libblock_relink_collection(child->collection, true);
+ libblock_relink_collection(bmain, child->collection, true);
}
}
@@ -1702,7 +1712,8 @@ static Collection *single_object_users_collection(Main *bmain,
/* Generate new copies for objects in given collection and all its children,
* and optionally also copy collections themselves. */
if (copy_collections && !is_master_collection) {
- Collection *collection_new = (Collection *)BKE_id_copy(bmain, &collection->id);
+ Collection *collection_new = (Collection *)BKE_id_copy_ex(
+ bmain, &collection->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
id_us_min(&collection_new->id);
collection = ID_NEW_SET(collection, collection_new);
}
@@ -1713,7 +1724,8 @@ static Collection *single_object_users_collection(Main *bmain,
/* an object may be in more than one collection */
if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) {
if (!ID_IS_LINKED(ob) && BKE_object_scenes_users_get(bmain, ob) > 1) {
- ID_NEW_SET(ob, BKE_id_copy(bmain, &ob->id));
+ ID_NEW_SET(
+ ob, BKE_id_copy_ex(bmain, &ob->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
id_us_min(ob->id.newid);
}
}
@@ -1756,10 +1768,10 @@ static void single_object_users(
single_object_users_collection(bmain, scene, master_collection, flag, copy_collections, true);
/* Will also handle the master collection. */
- BKE_libblock_relink_to_newid(&scene->id);
+ BKE_libblock_relink_to_newid(bmain, &scene->id, 0);
/* Collection and object pointers in collections */
- libblock_relink_collection(scene->master_collection, false);
+ libblock_relink_collection(bmain, scene->master_collection, false);
/* We also have to handle runtime things in UI. */
if (v3d) {
@@ -1771,8 +1783,6 @@ static void single_object_users(
BKE_main_collection_sync_remap(bmain);
}
-/* not an especially efficient function, only added so the single user
- * button can be functional. */
void ED_object_single_user(Main *bmain, Scene *scene, Object *ob)
{
FOREACH_SCENE_OBJECT_BEGIN (scene, ob_iter) {
@@ -1800,66 +1810,82 @@ static void single_obdata_users(
FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) {
if (!ID_IS_LINKED(ob)) {
id = ob->data;
-
- if (id && id->us > 1 && !ID_IS_LINKED(id)) {
+ if (single_data_needs_duplication(id)) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
switch (ob->type) {
case OB_LAMP:
- ob->data = la = ID_NEW_SET(ob->data, BKE_id_copy(bmain, ob->data));
+ ob->data = la = ID_NEW_SET(
+ ob->data,
+ BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
break;
case OB_CAMERA:
- cam = ob->data = ID_NEW_SET(ob->data, BKE_id_copy(bmain, ob->data));
+ cam = ob->data = ID_NEW_SET(
+ ob->data,
+ BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
ID_NEW_REMAP(cam->dof.focus_object);
break;
case OB_MESH:
/* Needed to remap texcomesh below. */
- me = ob->data = ID_NEW_SET(ob->data, BKE_id_copy(bmain, ob->data));
- if (me->key) { /* We do not need to set me->key->id.newid here... */
- BKE_animdata_copy_id_action(bmain, (ID *)me->key);
- }
+ me = ob->data = ID_NEW_SET(
+ ob->data,
+ BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
break;
case OB_MBALL:
- ob->data = ID_NEW_SET(ob->data, BKE_id_copy(bmain, ob->data));
+ ob->data = ID_NEW_SET(
+ ob->data,
+ BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
break;
case OB_CURVE:
case OB_SURF:
case OB_FONT:
- ob->data = cu = ID_NEW_SET(ob->data, BKE_id_copy(bmain, ob->data));
+ ob->data = cu = ID_NEW_SET(
+ ob->data,
+ BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
ID_NEW_REMAP(cu->bevobj);
ID_NEW_REMAP(cu->taperobj);
- if (cu->key) { /* We do not need to set cu->key->id.newid here... */
- BKE_animdata_copy_id_action(bmain, (ID *)cu->key);
- }
break;
case OB_LATTICE:
- ob->data = lat = ID_NEW_SET(ob->data, BKE_id_copy(bmain, ob->data));
- if (lat->key) { /* We do not need to set lat->key->id.newid here... */
- BKE_animdata_copy_id_action(bmain, (ID *)lat->key);
- }
+ ob->data = lat = ID_NEW_SET(
+ ob->data,
+ BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
break;
case OB_ARMATURE:
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- ob->data = ID_NEW_SET(ob->data, BKE_id_copy(bmain, ob->data));
+ ob->data = ID_NEW_SET(
+ ob->data,
+ BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
BKE_pose_rebuild(bmain, ob, ob->data, true);
break;
case OB_SPEAKER:
- ob->data = ID_NEW_SET(ob->data, BKE_id_copy(bmain, ob->data));
+ ob->data = ID_NEW_SET(
+ ob->data,
+ BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
break;
case OB_LIGHTPROBE:
- ob->data = ID_NEW_SET(ob->data, BKE_id_copy(bmain, ob->data));
+ ob->data = ID_NEW_SET(
+ ob->data,
+ BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
break;
case OB_GPENCIL:
- ob->data = ID_NEW_SET(ob->data, BKE_id_copy(bmain, ob->data));
+ ob->data = ID_NEW_SET(
+ ob->data,
+ BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
break;
case OB_HAIR:
- ob->data = ID_NEW_SET(ob->data, BKE_id_copy(bmain, ob->data));
+ ob->data = ID_NEW_SET(
+ ob->data,
+ BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
break;
case OB_POINTCLOUD:
- ob->data = ID_NEW_SET(ob->data, BKE_id_copy(bmain, ob->data));
+ ob->data = ID_NEW_SET(
+ ob->data,
+ BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
break;
case OB_VOLUME:
- ob->data = ID_NEW_SET(ob->data, BKE_id_copy(bmain, ob->data));
+ ob->data = ID_NEW_SET(
+ ob->data,
+ BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
break;
default:
printf("ERROR %s: can't copy %s\n", __func__, id->name);
@@ -1870,13 +1896,6 @@ static void single_obdata_users(
return;
}
- /* Copy animation data after object data became local,
- * otherwise old and new object data will share the same
- * AnimData structure, which is not what we want.
- * (sergey)
- */
- BKE_animdata_copy_id_action(bmain, (ID *)ob->data);
-
id_us_min(id);
}
}
@@ -1895,8 +1914,16 @@ static void single_object_action_users(
{
FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) {
if (!ID_IS_LINKED(ob)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- BKE_animdata_copy_id_action(bmain, &ob->id);
+ AnimData *adt = BKE_animdata_from_id(&ob->id);
+ if (adt == NULL) {
+ continue;
+ }
+
+ ID *id_act = (ID *)adt->action;
+ if (single_data_needs_duplication(id_act)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ BKE_animdata_duplicate_id_action(bmain, &ob->id, USER_DUP_ACT | USER_DUP_LINKED_ID);
+ }
}
}
FOREACH_OBJECT_FLAG_END;
@@ -1909,10 +1936,14 @@ static void single_objectdata_action_users(
if (!ID_IS_LINKED(ob) && ob->data != NULL) {
ID *id_obdata = (ID *)ob->data;
AnimData *adt = BKE_animdata_from_id(id_obdata);
+ if (adt == NULL) {
+ continue;
+ }
+
ID *id_act = (ID *)adt->action;
- if (id_act && id_act->us > 1) {
+ if (single_data_needs_duplication(id_act)) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- BKE_animdata_copy_id_action(bmain, id_obdata);
+ BKE_animdata_duplicate_id_action(bmain, &ob->id, USER_DUP_ACT | USER_DUP_LINKED_ID);
}
}
}
@@ -1928,18 +1959,12 @@ static void single_mat_users(
FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) {
if (!ID_IS_LINKED(ob)) {
for (a = 1; a <= ob->totcol; a++) {
- ma = BKE_object_material_get(ob, a);
- if (ma) {
- /* do not test for LIB_TAG_NEW or use newid:
- * this functions guaranteed delivers single_users! */
-
- if (ma->id.us > 1) {
- man = (Material *)BKE_id_copy(bmain, &ma->id);
- BKE_animdata_copy_id_action(bmain, &man->id);
-
- man->id.us = 0;
- BKE_object_material_assign(bmain, ob, man, a, BKE_MAT_ASSIGN_USERPREF);
- }
+ ma = BKE_object_material_get(ob, (short)a);
+ if (single_data_needs_duplication(&ma->id)) {
+ man = (Material *)BKE_id_copy_ex(
+ bmain, &ma->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
+ man->id.us = 0;
+ BKE_object_material_assign(bmain, ob, man, (short)a, BKE_MAT_ASSIGN_USERPREF);
}
}
}
@@ -1982,9 +2007,7 @@ static void tag_localizable_objects(bContext *C, const int mode)
CTX_DATA_BEGIN (C, Object *, object, selected_objects) {
object->id.tag |= LIB_TAG_DOIT;
- /* If data is also gonna to become local, mark data we're interested in
- * as gonna-to-be-local.
- */
+ /* If obdata is also going to become local, mark it as such too. */
if (mode == MAKE_LOCAL_SELECT_OBDATA && object->data) {
ID *data_id = (ID *)object->data;
data_id->tag |= LIB_TAG_DOIT;
@@ -2332,7 +2355,8 @@ static bool make_override_library_poll(bContext *C)
/* Object must be directly linked to be overridable. */
return (ED_operator_objectmode(C) && obact != NULL &&
(ID_IS_LINKED(obact) || (obact->instance_collection != NULL &&
- ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection))));
+ ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection) &&
+ !ID_IS_OVERRIDE_LIBRARY(obact))));
}
static const EnumPropertyItem *make_override_collections_of_linked_object_itemf(
@@ -2566,10 +2590,10 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
char *ED_object_ot_drop_named_material_tooltip(bContext *C,
PointerRNA *properties,
- const wmEvent *event)
+ const int mval[2])
{
int mat_slot = 0;
- Object *ob = ED_view3d_give_material_slot_under_cursor(C, event->mval, &mat_slot);
+ Object *ob = ED_view3d_give_material_slot_under_cursor(C, mval, &mat_slot);
if (ob == NULL) {
return BLI_strdup("");
}
@@ -2619,8 +2643,6 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_FINISHED;
}
-/* used for dropbox */
-/* assigns to object under cursor, only first material slot */
void OBJECT_OT_drop_named_material(wmOperatorType *ot)
{
/* identifiers */
@@ -2629,7 +2651,7 @@ void OBJECT_OT_drop_named_material(wmOperatorType *ot)
/* api callbacks */
ot->invoke = drop_named_material_invoke;
- ot->poll = ED_operator_objectmode;
+ ot->poll = ED_operator_objectmode_poll_msg;
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
@@ -2679,9 +2701,6 @@ static int object_unlink_data_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/**
- * \note Only for empty-image objects, this operator is needed
- */
void OBJECT_OT_unlink_data(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc
index d56cb3c7548..e4103db8e21 100644
--- a/source/blender/editors/object/object_remesh.cc
+++ b/source/blender/editors/object/object_remesh.cc
@@ -168,8 +168,6 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
new_mesh = mesh_fixed_poles;
}
- BKE_mesh_calc_normals(new_mesh);
-
if (mesh->flag & ME_REMESH_REPROJECT_VOLUME || mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK ||
mesh->flag & ME_REMESH_REPROJECT_SCULPT_FACE_SETS) {
BKE_mesh_runtime_clear_geometry(mesh);
@@ -463,8 +461,8 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev
Object *active_object = CTX_data_active_object(C);
Mesh *mesh = (Mesh *)active_object->data;
- VoxelSizeEditCustomData *cd = (VoxelSizeEditCustomData *)MEM_callocN(
- sizeof(VoxelSizeEditCustomData), "Voxel Size Edit OP Custom Data");
+ VoxelSizeEditCustomData *cd = MEM_cnew<VoxelSizeEditCustomData>(
+ "Voxel Size Edit OP Custom Data");
/* Initial operator Custom Data setup. */
cd->draw_handle = ED_region_draw_cb_activate(
@@ -708,12 +706,19 @@ static bool mesh_is_manifold_consistent(Mesh *mesh)
}
if (is_manifold_consistent) {
- /* check for wire edges */
for (uint i = 0; i < mesh->totedge; i++) {
+ /* Check for wire edges. */
if (edge_faces[i] == 0) {
is_manifold_consistent = false;
break;
}
+ /* Check for zero length edges */
+ MVert *v1 = &mesh->mvert[mesh->medge[i].v1];
+ MVert *v2 = &mesh->mvert[mesh->medge[i].v2];
+ if (compare_v3v3(v1->co, v2->co, 1e-4f)) {
+ is_manifold_consistent = false;
+ break;
+ }
}
}
@@ -814,7 +819,8 @@ static Mesh *remesh_symmetry_mirror(Object *ob, Mesh *mesh, eSymmetryAxes symmet
mmd.flag = 0;
mmd.flag &= MOD_MIR_AXIS_X << i;
mesh_mirror_temp = mesh_mirror;
- mesh_mirror = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(&mmd, ob, mesh_mirror, axis);
+ mesh_mirror = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(
+ &mmd, ob, mesh_mirror, axis, true);
if (mesh_mirror_temp != mesh_mirror) {
BKE_id_free(nullptr, mesh_mirror_temp);
}
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index eb37aebcff2..a86dba15469 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -89,14 +89,6 @@
/** \name Public Object Selection API
* \{ */
-/**
- * Simple API for object selection, rather than just using the flag
- * this takes into account the 'restrict selection in 3d view' flag.
- * deselect works always, the restriction just prevents selection
- *
- * \note Caller must send a `NC_SCENE | ND_OB_SELECT` notifier
- * (or a `NC_SCENE | ND_OB_VISIBLE` in case of visibility toggling).
- */
void ED_object_base_select(Base *base, eObjectSelect_Mode mode)
{
if (mode == BA_INVERT) {
@@ -121,9 +113,6 @@ void ED_object_base_select(Base *base, eObjectSelect_Mode mode)
}
}
-/**
- * Call when the active base has changed.
- */
void ED_object_base_active_refresh(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
WM_main_add_notifier(NC_SCENE | ND_OB_ACTIVE, scene);
@@ -134,9 +123,6 @@ void ED_object_base_active_refresh(Main *bmain, Scene *scene, ViewLayer *view_la
}
}
-/**
- * Change active base, it includes the notifier
- */
void ED_object_base_activate(bContext *C, Base *base)
{
Scene *scene = CTX_data_scene(C);
@@ -242,10 +228,6 @@ static int get_base_select_priority(Base *base)
return 1;
}
-/**
- * If id is not already an Object, try to find an object that uses it as data.
- * Prefers active, then selected, then visible/selectable.
- */
Base *ED_object_find_first_by_data_id(ViewLayer *view_layer, ID *id)
{
BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
@@ -279,12 +261,6 @@ Base *ED_object_find_first_by_data_id(ViewLayer *view_layer, ID *id)
return base_best;
}
-/**
- * Select and make the target object active in the view layer.
- * If already selected, selection isn't changed.
- *
- * \returns false if not found in current view layer
- */
bool ED_object_jump_to_object(bContext *C, Object *ob, const bool UNUSED(reveal_hidden))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -316,13 +292,6 @@ bool ED_object_jump_to_object(bContext *C, Object *ob, const bool UNUSED(reveal_
return true;
}
-/**
- * Select and make the target object and bone active.
- * Switches to Pose mode if in Object mode so the selection is visible.
- * Un-hides the target bone and bone layer if necessary.
- *
- * \returns false if object not in layer, bone not found, or other error
- */
bool ED_object_jump_to_bone(bContext *C,
Object *ob,
const char *bone_name,
diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c
index 2723d7ad1e3..043a679a0c0 100644
--- a/source/blender/editors/object/object_shader_fx.c
+++ b/source/blender/editors/object/object_shader_fx.c
@@ -402,6 +402,8 @@ void OBJECT_OT_shaderfx_add(wmOperatorType *ot)
RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ID);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Generic Functions for Operators Using Names and Data Context
* \{ */
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index fd649854d8f..a871ddea48c 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -43,13 +43,16 @@
#include "DNA_object_types.h"
#include "BKE_context.h"
+#include "BKE_crazyspace.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_object.h"
+#include "BKE_report.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "BLI_sys_types.h" /* for intptr_t support */
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 4c4727f51ee..c9114c7a925 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -811,8 +811,8 @@ static int apply_objects_internal(bContext *C,
/* adjust data */
BKE_mesh_transform(me, mat, true);
- /* update normals */
- BKE_mesh_calc_normals(me);
+ /* If normal layers exist, they are now dirty. */
+ BKE_mesh_normals_tag_dirty(me);
}
else if (ob->type == OB_ARMATURE) {
bArmature *arm = ob->data;
@@ -1408,6 +1408,19 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
sub_v3_v3(mpt, offset_local);
mul_v3_m4v3(&pt->x, diff_mat, mpt);
}
+
+ /* Apply transform to edit-curve. */
+ if (gps->editcurve != NULL) {
+ for (i = 0; i < gps->editcurve->tot_curve_points; i++) {
+ BezTriple *bezt = &gps->editcurve->curve_points[i].bezt;
+ for (int j = 0; j < 3; j++) {
+ float mpt[3];
+ mul_v3_m4v3(mpt, inverse_diff_mat, bezt->vec[j]);
+ sub_v3_v3(mpt, offset_local);
+ mul_v3_m4v3(bezt->vec[j], diff_mat, mpt);
+ }
+ }
+ }
}
}
}
diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c
index 66390f6f165..df44d840ad3 100644
--- a/source/blender/editors/object/object_utils.c
+++ b/source/blender/editors/object/object_utils.c
@@ -36,6 +36,7 @@
#include "BKE_armature.h"
#include "BKE_editmesh.h"
#include "BKE_lattice.h"
+#include "BKE_object.h"
#include "BKE_scene.h"
#include "DEG_depsgraph_query.h"
@@ -114,7 +115,7 @@ bool ED_object_calc_active_center_for_posemode(Object *ob,
const bool select_only,
float r_center[3])
{
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) {
copy_v3_v3(r_center, pchan->pose_head);
return true;
@@ -368,10 +369,6 @@ void ED_object_data_xform_container_item_ensure(struct XFormObjectData_Container
}
}
-/**
- * This may be called multiple times with the same data.
- * Each time, the original transformations are re-applied, instead of accumulating the changes.
- */
void ED_object_data_xform_container_update_all(struct XFormObjectData_Container *xds,
struct Main *bmain,
Depsgraph *depsgraph)
@@ -430,3 +427,70 @@ void ED_object_data_xform_container_destroy(struct XFormObjectData_Container *xd
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Object Array
+ *
+ * Low level object transform function, transforming objects by `matrix`.
+ * Simple alternative to full transform logic.
+ * \{ */
+
+static bool object_parent_in_set(GSet *objects_set, Object *ob)
+{
+ for (Object *parent = ob->parent; parent; parent = parent->parent) {
+ if (BLI_gset_lookup(objects_set, parent)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void ED_object_xform_array_m4(Object **objects, uint objects_len, const float matrix[4][4])
+{
+ /* Filter out objects that have parents in `objects_set`. */
+ {
+ GSet *objects_set = BLI_gset_ptr_new_ex(__func__, objects_len);
+ for (uint i = 0; i < objects_len; i++) {
+ BLI_gset_add(objects_set, objects[i]);
+ }
+ for (uint i = 0; i < objects_len;) {
+ if (object_parent_in_set(objects_set, objects[i])) {
+ objects[i] = objects[--objects_len];
+ }
+ else {
+ i++;
+ }
+ }
+ BLI_gset_free(objects_set, NULL);
+ }
+
+ /* Detect translation only matrix, prevent rotation/scale channels from being touched at all. */
+ bool is_translation_only;
+ {
+ float test_m4_a[4][4], test_m4_b[4][4];
+ unit_m4(test_m4_a);
+ copy_m4_m4(test_m4_b, matrix);
+ zero_v3(test_m4_b[3]);
+ is_translation_only = equals_m4m4(test_m4_a, test_m4_b);
+ }
+
+ if (is_translation_only) {
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ add_v3_v3(ob->loc, matrix[3]);
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ }
+ }
+ else {
+ for (uint i = 0; i < objects_len; i++) {
+ float m4[4][4];
+ Object *ob = objects[i];
+ BKE_object_to_mat4(ob, m4);
+ mul_m4_m4m4(m4, matrix, m4);
+ BKE_object_apply_mat4(ob, m4, true, true);
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index f0ab082cd9c..3e74aaeeb10 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -140,9 +140,6 @@ bool ED_vgroup_sync_from_pose(Object *ob)
return false;
}
-/**
- * Removes out of range MDeformWeights
- */
void ED_vgroup_data_clamp_range(ID *id, const int total)
{
MDeformVert **dvert_arr;
@@ -264,13 +261,6 @@ bool ED_vgroup_parray_alloc(ID *id,
return false;
}
-/**
- * For use with tools that use ED_vgroup_parray_alloc with \a use_vert_sel == true.
- * This finds the unselected mirror deform verts and copies the weights to them from the selected.
- *
- * \note \a dvert_array has mirrored weights filled in,
- * in case cleanup operations are needed on both.
- */
void ED_vgroup_parray_mirror_sync(Object *ob,
MDeformVert **dvert_array,
const int dvert_tot,
@@ -314,11 +304,6 @@ void ED_vgroup_parray_mirror_sync(Object *ob,
MEM_freeN(dvert_array_all);
}
-/**
- * Fill in the pointers for mirror verts (as if all mirror verts were selected too).
- *
- * similar to #ED_vgroup_parray_mirror_sync but only fill in mirror points.
- */
void ED_vgroup_parray_mirror_assign(Object *ob, MDeformVert **dvert_array, const int dvert_tot)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
@@ -383,7 +368,6 @@ void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array,
}
}
-/* matching index only */
bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
{
MDeformVert **dvert_array_from = NULL, **dvf;
@@ -575,9 +559,6 @@ static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx)
}
}
-/**
- * Use when adjusting the active vertex weight and apply to mirror vertices.
- */
void ED_vgroup_vert_active_mirror(Object *ob, int def_nr)
{
Mesh *me = ob->data;
@@ -883,7 +864,6 @@ static void ED_vgroup_nr_vert_add(
}
}
-/* called while not in editmode */
void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
{
/* add the vert to the deform group with the
@@ -912,7 +892,6 @@ void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight,
}
}
-/* mesh object mode, lattice can be in editmode */
void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
{
/* This routine removes the vertex from the specified
@@ -2369,8 +2348,6 @@ static void dvert_mirror_op(MDeformVert *dvert,
}
}
-/* TODO: vgroup locking. */
-/* TODO: face masking. */
void ED_vgroup_mirror(Object *ob,
const bool mirror_weights,
const bool flip_vgroups,
@@ -2379,6 +2356,8 @@ void ED_vgroup_mirror(Object *ob,
int *r_totmirr,
int *r_totfail)
{
+ /* TODO: vgroup locking.
+ * TODO: face masking. */
#define VGROUP_MIRR_OP \
dvert_mirror_op(dvert, \
diff --git a/source/blender/editors/object/object_volume.c b/source/blender/editors/object/object_volume.c
index fbdee00c29c..6c92814abc0 100644
--- a/source/blender/editors/object/object_volume.c
+++ b/source/blender/editors/object/object_volume.c
@@ -158,7 +158,6 @@ static int volume_import_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
return OPERATOR_RUNNING_MODAL;
}
-/* called by other space types too */
void OBJECT_OT_volume_import(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 56f32ff603c..3214180309b 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -92,7 +92,6 @@ static int surface_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-/* add surface slot */
void DPAINT_OT_surface_slot_add(wmOperatorType *ot)
{
/* identifiers */
@@ -141,7 +140,6 @@ static int surface_slot_remove_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-/* remove surface slot */
void DPAINT_OT_surface_slot_remove(wmOperatorType *ot)
{
/* identifiers */
@@ -246,7 +244,7 @@ static int output_toggle_exec(bContext *C, wmOperator *op)
/* Vertex Color Layer */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
if (!exists) {
- ED_mesh_color_add(ob->data, name, true, true);
+ ED_mesh_color_add(ob->data, name, true, true, op->reports);
}
else {
ED_mesh_color_remove_named(ob->data, name);
@@ -375,7 +373,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
/* Show progress bar. */
*(job->do_update) = true;
- /* Set frame to start point (also inits modifier data) */
+ /* Set frame to start point (also initializes modifier data). */
frame = surface->start_frame;
orig_frame = input_scene->r.cfra;
input_scene->r.cfra = (int)frame;
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 8afc5c583e0..1407ca598a7 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -1000,7 +1000,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
tree = BLI_kdtree_3d_new(totpart);
- /* insert particles into kd tree */
+ /* Insert particles into KD-tree. */
LOOP_PARTICLES
{
key = pa->hair;
@@ -1419,7 +1419,6 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
BLI_task_parallel_range(0, edit->totpoint, &iter_data, iterate_lengths_iter, &settings);
}
-/* set current distances to be kept between neighboring keys */
void recalc_lengths(PTCacheEdit *edit)
{
POINT_P;
@@ -1437,13 +1436,12 @@ void recalc_lengths(PTCacheEdit *edit)
}
}
-/* calculate a tree for finding nearest emitter's vertice */
void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), ParticleSystem *psys)
{
PTCacheEdit *edit = psys->edit;
Mesh *mesh = edit->psmd_eval->mesh_final;
float *vec, *nor;
- int i, totface /*, totvert*/;
+ int i, totface;
if (!mesh) {
return;
@@ -1456,7 +1454,7 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part
BLI_kdtree_3d_free(edit->emitter_field);
totface = mesh->totface;
- // totvert = dm->getNumVerts(dm); /* UNUSED */
+ // int totvert = dm->getNumVerts(dm); /* UNUSED */
edit->emitter_cosnos = MEM_callocN(sizeof(float[6]) * totface, "emitter cosnos");
@@ -1465,26 +1463,28 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part
vec = edit->emitter_cosnos;
nor = vec + 3;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+
for (i = 0; i < totface; i++, vec += 6, nor += 6) {
MFace *mface = &mesh->mface[i];
MVert *mvert;
mvert = &mesh->mvert[mface->v1];
copy_v3_v3(vec, mvert->co);
- copy_v3fl_v3s(nor, mvert->no);
+ copy_v3_v3(nor, vert_normals[mface->v1]);
mvert = &mesh->mvert[mface->v2];
add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ add_v3_v3(nor, vert_normals[mface->v2]);
mvert = &mesh->mvert[mface->v3];
add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ add_v3_v3(nor, vert_normals[mface->v3]);
if (mface->v4) {
mvert = &mesh->mvert[mface->v4];
add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ add_v3_v3(nor, vert_normals[mface->v4]);
mul_v3_fl(vec, 0.25);
}
@@ -3903,8 +3903,8 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance)
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
- /* use 'kco' as the object space version of worldspace 'co',
- * ob->imat is set before calling */
+ /* Use `kco` as the object space version of world-space `co`,
+ * `ob->imat` is set before calling. */
mul_v3_m4v3(kco, data->ob->imat, co);
point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL);
@@ -3993,15 +3993,15 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance)
copy_v3_v3(oco, key->co);
mul_m4_v3(mat, oco);
- /* use 'kco' as the object space version of worldspace 'co',
- * ob->imat is set before calling */
+ /* Use `kco` as the object space version of world-space `co`,
+ * `ob->imat` is set before calling. */
mul_v3_m4v3(kco, data->ob->imat, oco);
point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL);
if (point_index != -1) {
copy_v3_v3(onor, &edit->emitter_cosnos[point_index * 6 + 3]);
- mul_mat3_m4_v3(data->ob->obmat, onor); /* normal into worldspace */
- mul_mat3_m4_v3(imat, onor); /* worldspace into particle space */
+ mul_mat3_m4_v3(data->ob->obmat, onor); /* Normal into world-space. */
+ mul_mat3_m4_v3(imat, onor); /* World-space into particle-space. */
normalize_v3(onor);
}
else {
@@ -5261,7 +5261,6 @@ void PARTICLE_OT_shape_cut(wmOperatorType *ot)
/** \name Particle Edit Toggle Operator
* \{ */
-/* initialize needed data for bake edit */
void PE_create_particle_edit(
Depsgraph *depsgraph, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
{
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index 601a8385a24..804ab614c09 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -298,7 +298,6 @@ static void particle_undosys_foreach_ID_ref(UndoStep *us_p,
foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->object_ref));
}
-/* Export for ED_undo_sys. */
void ED_particle_undosys_type(UndoType *ut)
{
ut->name = "Edit Particle";
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 3ac6dca3044..987b9e49057 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -743,8 +743,10 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
invert_m4_m4(from_imat, from_mat);
invert_m4_m4(to_imat, to_mat);
- if (target_psmd->mesh_final->runtime.deformed_only) {
- /* we don't want to mess up target_psmd->dm when converting to global coordinates below */
+ const bool use_dm_final_indices = (target_psys->part->use_modifier_stack &&
+ !target_psmd->mesh_final->runtime.deformed_only);
+
+ if (use_dm_final_indices || !target_psmd->mesh_original) {
mesh = target_psmd->mesh_final;
}
else {
@@ -755,6 +757,7 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
return false;
}
/* don't modify the original vertices */
+ /* we don't want to mess up target_psmd->dm when converting to global coordinates below */
mesh = (Mesh *)BKE_id_copy_ex(NULL, &mesh->id, NULL, LIB_ID_COPY_LOCALIZE);
/* BMESH_ONLY, deform dm may not have tessface */
@@ -825,7 +828,13 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
tpa->foffset = 0.0f;
tpa->num = nearest.index;
- tpa->num_dmcache = psys_particle_dm_face_lookup(target_mesh, mesh, tpa->num, tpa->fuv, NULL);
+ if (use_dm_final_indices) {
+ tpa->num_dmcache = DMCACHE_ISCHILD;
+ }
+ else {
+ tpa->num_dmcache = psys_particle_dm_face_lookup(
+ target_psmd->mesh_final, target_psmd->mesh_original, tpa->num, tpa->fuv, NULL);
+ }
}
else {
me = &medge[nearest.index];
@@ -930,7 +939,9 @@ static bool connect_hair(Depsgraph *depsgraph, Scene *scene, Object *ob, Particl
ob->obmat,
psys->flag & PSYS_GLOBAL_HAIR,
false);
- psys->flag &= ~PSYS_GLOBAL_HAIR;
+ if (ok) {
+ psys->flag &= ~PSYS_GLOBAL_HAIR;
+ }
return ok;
}
@@ -1235,9 +1246,15 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op)
const bool use_active = RNA_boolean_get(op->ptr, "use_active");
Scene *scene = CTX_data_scene(C);
Object *ob_from = ED_object_active_context(C);
- ParticleSystem *psys_from =
- use_active ? CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data :
- NULL;
+
+ ParticleSystem *psys_from = NULL;
+ if (use_active) {
+ psys_from = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
+ if (psys_from == NULL) {
+ /* Particle System context pointer is only valid in the Properties Editor. */
+ psys_from = psys_get_current(ob_from);
+ }
+ }
int changed_tot = 0;
int fail = 0;
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index ef07d73826a..e8270c7a4aa 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -32,6 +32,7 @@ struct Scene;
struct wmOperatorType;
/* particle_edit.c */
+
void PARTICLE_OT_select_all(struct wmOperatorType *ot);
void PARTICLE_OT_select_roots(struct wmOperatorType *ot);
void PARTICLE_OT_select_tips(struct wmOperatorType *ot);
@@ -60,18 +61,28 @@ void PARTICLE_OT_edited_clear(struct wmOperatorType *ot);
void PARTICLE_OT_unify_length(struct wmOperatorType *ot);
+/**
+ * Initialize needed data for bake edit.
+ */
void PE_create_particle_edit(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct PointCache *cache,
struct ParticleSystem *psys);
+/**
+ * Set current distances to be kept between neighboring keys.
+ */
void recalc_lengths(struct PTCacheEdit *edit);
+/**
+ * Calculate a tree for finding nearest emitter's vertice.
+ */
void recalc_emitter_field(struct Depsgraph *depsgraph,
struct Object *ob,
struct ParticleSystem *psys);
void update_world_cos(struct Object *ob, struct PTCacheEdit *edit);
/* particle_object.c */
+
void OBJECT_OT_particle_system_add(struct wmOperatorType *ot);
void OBJECT_OT_particle_system_remove(struct wmOperatorType *ot);
@@ -92,6 +103,7 @@ void PARTICLE_OT_dupliob_move_down(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_refresh(struct wmOperatorType *ot);
/* particle_boids.c */
+
void BOID_OT_rule_add(struct wmOperatorType *ot);
void BOID_OT_rule_del(struct wmOperatorType *ot);
void BOID_OT_rule_move_up(struct wmOperatorType *ot);
@@ -103,6 +115,7 @@ void BOID_OT_state_move_up(struct wmOperatorType *ot);
void BOID_OT_state_move_down(struct wmOperatorType *ot);
/* physics_fluid.c */
+
void FLUID_OT_bake_all(struct wmOperatorType *ot);
void FLUID_OT_free_all(struct wmOperatorType *ot);
void FLUID_OT_bake_data(struct wmOperatorType *ot);
@@ -118,13 +131,21 @@ void FLUID_OT_free_guides(struct wmOperatorType *ot);
void FLUID_OT_pause_bake(struct wmOperatorType *ot);
/* dynamicpaint.c */
+
void DPAINT_OT_bake(struct wmOperatorType *ot);
+/**
+ * Add surface slot.
+ */
void DPAINT_OT_surface_slot_add(struct wmOperatorType *ot);
+/**
+ * Remove surface slot.
+ */
void DPAINT_OT_surface_slot_remove(struct wmOperatorType *ot);
void DPAINT_OT_type_toggle(struct wmOperatorType *ot);
void DPAINT_OT_output_toggle(struct wmOperatorType *ot);
/* physics_pointcache.c */
+
void PTCACHE_OT_bake_all(struct wmOperatorType *ot);
void PTCACHE_OT_free_bake_all(struct wmOperatorType *ot);
void PTCACHE_OT_bake(struct wmOperatorType *ot);
@@ -134,6 +155,7 @@ void PTCACHE_OT_add(struct wmOperatorType *ot);
void PTCACHE_OT_remove(struct wmOperatorType *ot);
/* rigidbody_object.c */
+
void RIGIDBODY_OT_object_add(struct wmOperatorType *ot);
void RIGIDBODY_OT_object_remove(struct wmOperatorType *ot);
@@ -144,10 +166,12 @@ void RIGIDBODY_OT_shape_change(struct wmOperatorType *ot);
void RIGIDBODY_OT_mass_calculate(struct wmOperatorType *ot);
/* rigidbody_constraint.c */
+
void RIGIDBODY_OT_constraint_add(struct wmOperatorType *ot);
void RIGIDBODY_OT_constraint_remove(struct wmOperatorType *ot);
/* rigidbody_world.c */
+
void RIGIDBODY_OT_world_add(struct wmOperatorType *ot);
void RIGIDBODY_OT_world_remove(struct wmOperatorType *ot);
void RIGIDBODY_OT_world_export(struct wmOperatorType *ot);
diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt
index 46afa390997..1f867c6f1f7 100644
--- a/source/blender/editors/render/CMakeLists.txt
+++ b/source/blender/editors/render/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../../imbuf
../../makesdna
../../makesrna
+ ../../nodes
../../render
../../sequencer
../../windowmanager
@@ -36,15 +37,15 @@ set(INC
)
set(SRC
- render_internal.c
- render_opengl.c
- render_ops.c
- render_preview.c
- render_shading.c
- render_update.c
- render_view.c
+ render_internal.cc
+ render_opengl.cc
+ render_ops.cc
+ render_preview.cc
+ render_shading.cc
+ render_update.cc
+ render_view.cc
- render_intern.h
+ render_intern.hh
)
set(LIB
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.hh
index e1d03e6f3be..d374717664b 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.hh
@@ -28,6 +28,7 @@ struct bContext;
struct wmOperatorType;
/* render_shading.c */
+
void OBJECT_OT_material_slot_add(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_remove(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_assign(struct wmOperatorType *ot);
@@ -80,10 +81,18 @@ void TEXTURE_OT_slot_paste(struct wmOperatorType *ot);
void TEXTURE_OT_slot_move(struct wmOperatorType *ot);
/* render_internal.c */
+
+/**
+ * Contextual render, using current scene, view3d?
+ */
void RENDER_OT_render(struct wmOperatorType *ot);
void RENDER_OT_shutter_curve_preset(struct wmOperatorType *ot);
/* render_view.c */
+
+/**
+ * New window uses x,y to set position.
+ */
struct ScrArea *render_view_open(struct bContext *C, int mx, int my, struct ReportList *reports);
void RENDER_OT_view_show(struct wmOperatorType *ot);
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.cc
index d5ad5a5eb84..a156b9234dc 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.cc
@@ -21,9 +21,9 @@
* \ingroup edrend
*/
-#include <math.h>
-#include <stddef.h>
-#include <string.h>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -50,11 +50,14 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "NOD_composite.h"
+
#include "DEG_depsgraph.h"
#include "WM_api.h"
@@ -77,12 +80,12 @@
#include "SEQ_relations.h"
-#include "render_intern.h"
+#include "render_intern.hh"
/* Render Callbacks */
static int render_break(void *rjv);
-typedef struct RenderJob {
+struct RenderJob {
Main *main;
Scene *scene;
ViewLayer *single_layer;
@@ -109,7 +112,7 @@ typedef struct RenderJob {
ColorManagedDisplaySettings display_settings;
bool supports_glsl_draw;
bool interface_locked;
-} RenderJob;
+};
/* called inside thread! */
static bool image_buffer_calc_tile_rect(const RenderResult *rr,
@@ -121,15 +124,15 @@ static bool image_buffer_calc_tile_rect(const RenderResult *rr,
{
int tile_y, tile_height, tile_x, tile_width;
- /* When `renrect` argument is not NULL, we only refresh scan-lines. */
+ /* When `renrect` argument is not nullptr, we only refresh scan-lines. */
if (renrect) {
- /* if (tile_height == recty), rendering of layer is ready,
+ /* `if (tile_height == recty)`, rendering of layer is ready,
* we should not draw, other things happen... */
- if (rr->renlay == NULL || renrect->ymax >= rr->recty) {
+ if (rr->renlay == nullptr || renrect->ymax >= rr->recty) {
return false;
}
- /* tile_x here is first subrect x coord, tile_width defines subrect width */
+ /* `tile_x` here is first sub-rectangle x coord, tile_width defines sub-rectangle width. */
tile_x = renrect->xmin;
tile_width = renrect->xmax - tile_x;
if (tile_width < 2) {
@@ -189,7 +192,7 @@ static void image_buffer_rect_update(RenderJob *rj,
const char *viewname)
{
Scene *scene = rj->scene;
- const float *rectf = NULL;
+ const float *rectf = nullptr;
int linear_stride, linear_offset_x, linear_offset_y;
ColorManagedViewSettings *view_settings;
ColorManagedDisplaySettings *display_settings;
@@ -230,12 +233,12 @@ static void image_buffer_rect_update(RenderJob *rj,
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
return;
}
- if (rr->renlay == NULL) {
+ if (rr->renlay == nullptr) {
return;
}
rectf = RE_RenderLayerGetPass(rr->renlay, RE_PASSNAME_COMBINED, viewname);
}
- if (rectf == NULL) {
+ if (rectf == nullptr) {
return;
}
@@ -256,7 +259,7 @@ static void image_buffer_rect_update(RenderJob *rj,
IMB_partial_display_buffer_update(ibuf,
rectf,
- NULL,
+ nullptr,
linear_stride,
linear_offset_x,
linear_offset_y,
@@ -315,17 +318,17 @@ static int screen_render_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
RenderEngineType *re_type = RE_engines_find(scene->r.engine);
ViewLayer *active_layer = CTX_data_view_layer(C);
- ViewLayer *single_layer = NULL;
+ ViewLayer *single_layer = nullptr;
Render *re;
Image *ima;
View3D *v3d = CTX_wm_view3d(C);
Main *mainp = CTX_data_main(C);
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
- struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
+ struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : nullptr;
/* Cannot do render if there is not this function. */
- if (re_type->render == NULL) {
+ if (re_type->render == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -342,11 +345,11 @@ static int screen_render_exec(bContext *C, wmOperator *op)
G.is_break = false;
- RE_draw_lock_cb(re, NULL, NULL);
- RE_test_break_cb(re, NULL, render_break);
+ RE_draw_lock_cb(re, nullptr, nullptr);
+ RE_test_break_cb(re, nullptr, render_break);
ima = BKE_image_ensure_viewer(mainp, IMA_TYPE_R_RESULT, "Render Result");
- BKE_image_signal(mainp, ima, NULL, IMA_SIGNAL_FREE);
+ BKE_image_signal(mainp, ima, nullptr, IMA_SIGNAL_FREE);
BKE_image_backup_render(scene, ima, true);
/* cleanup sequencer caches before starting user triggered render.
@@ -371,7 +374,7 @@ static int screen_render_exec(bContext *C, wmOperator *op)
RE_RenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still);
}
- RE_SetReports(re, NULL);
+ RE_SetReports(re, nullptr);
/* No redraw needed, we leave state as we entered it. */
ED_update_for_newframe(mainp, CTX_data_depsgraph_pointer(C));
@@ -383,7 +386,7 @@ static int screen_render_exec(bContext *C, wmOperator *op)
static void render_freejob(void *rjv)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
BKE_color_managed_view_settings_free(&rj->view_settings);
MEM_freeN(rj);
@@ -471,15 +474,15 @@ static void make_renderinfo_string(const RenderStats *rs,
static void image_renderinfo_cb(void *rjv, RenderStats *rs)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
RenderResult *rr;
rr = RE_AcquireResultRead(rj->re);
if (rr) {
/* malloc OK here, stats_draw is not in tile threads */
- if (rr->text == NULL) {
- rr->text = MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext");
+ if (rr->text == nullptr) {
+ rr->text = static_cast<char *>(MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext"));
}
make_renderinfo_string(rs, rj->scene, rj->v3d_override, rr->error, rr->text);
@@ -493,7 +496,7 @@ static void image_renderinfo_cb(void *rjv, RenderStats *rs)
static void render_progress_update(void *rjv, float progress)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
if (rj->progress && *rj->progress != progress) {
*rj->progress = progress;
@@ -511,20 +514,22 @@ static void render_progress_update(void *rjv, float progress)
static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, ImageUser *iuser)
{
wmWindowManager *wm;
- ScrArea *first_area = NULL, *matched_area = NULL;
+ ScrArea *first_area = nullptr, *matched_area = nullptr;
/* image window, compo node users */
- for (wm = rj->main->wm.first; wm && matched_area == NULL; wm = wm->id.next) { /* only 1 wm */
+ for (wm = static_cast<wmWindowManager *>(rj->main->wm.first); wm && matched_area == nullptr;
+ wm = static_cast<wmWindowManager *>(wm->id.next)) { /* only 1 wm */
wmWindow *win;
- for (win = wm->windows.first; win && matched_area == NULL; win = win->next) {
+ for (win = static_cast<wmWindow *>(wm->windows.first); win && matched_area == nullptr;
+ win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
/* area->spacedata might be empty when toggling full-screen mode. */
- if (sima != NULL && sima->image == rj->image) {
- if (first_area == NULL) {
+ if (sima != nullptr && sima->image == rj->image) {
+ if (first_area == nullptr) {
first_area = area;
}
if (area == rj->area) {
@@ -537,12 +542,12 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
}
}
- if (matched_area == NULL) {
+ if (matched_area == nullptr) {
matched_area = first_area;
}
if (matched_area) {
- SpaceImage *sima = matched_area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(matched_area->spacedata.first);
RenderResult *main_rr = RE_AcquireResultRead(rj->re);
/* TODO(sergey): is there faster way to get the layer index? */
@@ -562,7 +567,7 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
Image *ima = rj->image;
ImBuf *ibuf;
void *lock;
@@ -584,7 +589,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
return;
}
- if (rr == NULL) {
+ if (rr == nullptr) {
return;
}
@@ -622,14 +627,14 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
static void current_scene_update(void *rjv, Scene *scene)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
rj->current_scene = scene;
rj->iuser.scene = scene;
}
static void render_startjob(void *rjv, short *stop, short *do_update, float *progress)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
rj->stop = stop;
rj->do_update = do_update;
@@ -657,7 +662,7 @@ static void render_startjob(void *rjv, short *stop, short *do_update, float *pro
rj->write_still);
}
- RE_SetReports(rj->re, NULL);
+ RE_SetReports(rj->re, nullptr);
}
static void render_image_restore_layer(RenderJob *rj)
@@ -665,15 +670,16 @@ static void render_image_restore_layer(RenderJob *rj)
wmWindowManager *wm;
/* image window, compo node users */
- for (wm = rj->main->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
+ for (wm = static_cast<wmWindowManager *>(rj->main->wm.first); wm;
+ wm = static_cast<wmWindowManager *>(wm->id.next)) { /* only 1 wm */
wmWindow *win;
- for (win = wm->windows.first; win; win = win->next) {
+ for (win = static_cast<wmWindow *>(wm->windows.first); win; win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area == rj->area) {
if (area->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
if (RE_HasSingleLayer(rj->re)) {
/* For single layer renders keep the active layer
@@ -699,11 +705,11 @@ static void render_image_restore_layer(RenderJob *rj)
static void render_endjob(void *rjv)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
- /* this render may be used again by the sequencer without the active
+ /* This render may be used again by the sequencer without the active
* 'Render' where the callbacks would be re-assigned. assign dummy callbacks
- * to avoid referencing freed renderjobs bug T24508. */
+ * to avoid referencing freed render-jobs bug T24508. */
RE_InitRenderCB(rj->re);
if (rj->main != G_MAIN) {
@@ -725,7 +731,8 @@ static void render_endjob(void *rjv)
rj->scene->r.scemode &= ~R_NO_FRAME_UPDATE;
if (rj->single_layer) {
- nodeUpdateID(rj->scene->nodetree, &rj->scene->id);
+ BKE_ntree_update_tag_id_changed(rj->main, &rj->scene->id);
+ BKE_ntree_update_main(rj->main, nullptr);
WM_main_add_notifier(NC_NODE | NA_EDITED, rj->scene);
}
@@ -735,7 +742,7 @@ static void render_endjob(void *rjv)
/* XXX render stability hack */
G.is_rendering = false;
- WM_main_add_notifier(NC_SCENE | ND_RENDER_RESULT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_RENDER_RESULT, nullptr);
/* Partial render result will always update display buffer
* for first render layer only. This is nice because you'll
@@ -772,7 +779,7 @@ static void render_endjob(void *rjv)
* and using one from Global will unlock exactly the same manager as
* was locked before running the job.
*/
- WM_set_locked_interface(G_MAIN->wm.first, false);
+ WM_set_locked_interface(static_cast<wmWindowManager *>(G_MAIN->wm.first), false);
DEG_tag_on_visible_update(G_MAIN, false);
}
}
@@ -780,7 +787,7 @@ static void render_endjob(void *rjv)
/* called by render, check job 'stop' value or the global */
static int render_breakjob(void *rjv)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
if (G.is_break) {
return 1;
@@ -807,7 +814,7 @@ static int render_break(void *UNUSED(rjv))
/* maybe need a way to get job send notifier? */
static void render_drawlock(void *rjv, bool lock)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
/* If interface is locked, renderer callback shall do nothing. */
if (!rj->interface_locked) {
@@ -869,11 +876,12 @@ static void clean_viewport_memory(Main *bmain, Scene *scene)
BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, true);
/* Go over all the visible objects. */
- for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ for (wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); wm;
+ wm = static_cast<wmWindowManager *>(wm->id.next)) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- for (base = view_layer->object_bases.first; base; base = base->next) {
+ for (base = static_cast<Base *>(view_layer->object_bases.first); base; base = base->next) {
clean_viewport_memory_base(base);
}
}
@@ -891,7 +899,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *active_layer = CTX_data_view_layer(C);
- ViewLayer *single_layer = NULL;
+ ViewLayer *single_layer = nullptr;
RenderEngineType *re_type = RE_engines_find(scene->r.engine);
Render *re;
wmJob *wm_job;
@@ -900,13 +908,13 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
const bool use_viewport = RNA_boolean_get(op->ptr, "use_viewport");
- View3D *v3d = use_viewport ? CTX_wm_view3d(C) : NULL;
- struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
+ View3D *v3d = use_viewport ? CTX_wm_view3d(C) : nullptr;
+ struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : nullptr;
const char *name;
ScrArea *area;
/* Cannot do render if there is not this function. */
- if (re_type->render == NULL) {
+ if (re_type->render == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -959,10 +967,10 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
* store spare */
/* ensure at least 1 area shows result */
- area = render_view_open(C, event->x, event->y, op->reports);
+ area = render_view_open(C, event->xy[0], event->xy[1], op->reports);
/* job custom data */
- rj = MEM_callocN(sizeof(RenderJob), "render job");
+ rj = MEM_cnew<RenderJob>("render job");
rj->main = bmain;
rj->scene = scene;
rj->current_scene = rj->scene;
@@ -976,7 +984,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
rj->anim = is_animation;
rj->write_still = is_write_still && !is_animation;
rj->iuser.scene = scene;
- rj->iuser.ok = 1;
rj->reports = op->reports;
rj->orig_layer = 0;
rj->last_layer = 0;
@@ -987,7 +994,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
BKE_color_managed_view_settings_copy(&rj->view_settings, &scene->view_settings);
if (area) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
rj->orig_layer = sima->iuser.layer;
}
@@ -1031,7 +1038,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
WM_JOB_TYPE_RENDER);
WM_jobs_customdata_set(wm_job, rj, render_freejob);
WM_jobs_timer(wm_job, 0.2, NC_SCENE | ND_RENDER_RESULT, 0);
- WM_jobs_callbacks(wm_job, render_startjob, NULL, NULL, render_endjob);
+ WM_jobs_callbacks(wm_job, render_startjob, nullptr, nullptr, render_endjob);
if (RNA_struct_property_is_set(op->ptr, "layer")) {
WM_jobs_delay_start(wm_job, 0.2);
@@ -1039,7 +1046,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
/* get a render result image, and make sure it is empty */
ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
- BKE_image_signal(rj->main, ima, NULL, IMA_SIGNAL_FREE);
+ BKE_image_signal(rj->main, ima, nullptr, IMA_SIGNAL_FREE);
BKE_image_backup_render(rj->scene, ima, true);
rj->image = ima;
@@ -1077,7 +1084,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
return OPERATOR_RUNNING_MODAL;
}
-/* contextual render, using current scene, view3d? */
void RENDER_OT_render(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -1100,32 +1106,32 @@ void RENDER_OT_render(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna,
"animation",
- 0,
+ false,
"Animation",
"Render files from the animation range of this scene");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_boolean(
ot->srna,
"write_still",
- 0,
+ false,
"Write Image",
"Save rendered the image to the output path (used only when animation is disabled)");
prop = RNA_def_boolean(ot->srna,
"use_viewport",
- 0,
+ false,
"Use 3D Viewport",
"When inside a 3D viewport, use layers and camera of the viewport");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_string(ot->srna,
"layer",
- NULL,
+ nullptr,
RE_MAXNAME,
"Render Layer",
"Single render layer to re-render (used only when animation is disabled)");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_string(ot->srna,
"scene",
- NULL,
+ nullptr,
MAX_ID_NAME - 2,
"Scene",
"Scene to render, current scene if not specified");
@@ -1141,7 +1147,7 @@ Scene *ED_render_job_get_scene(const bContext *C)
return rj->scene;
}
- return NULL;
+ return nullptr;
}
Scene *ED_render_job_get_current_scene(const bContext *C)
@@ -1151,7 +1157,7 @@ Scene *ED_render_job_get_current_scene(const bContext *C)
if (rj) {
return rj->current_scene;
}
- return NULL;
+ return nullptr;
}
/* Motion blur curve preset */
@@ -1182,7 +1188,7 @@ void RENDER_OT_shutter_curve_preset(wmOperatorType *ot)
{CURVE_PRESET_LINE, "LINE", 0, "Line", ""},
{CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""},
{CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
ot->name = "Shutter Curve Preset";
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.cc
index e4bbbfb0f57..8bd0244c899 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.cc
@@ -21,9 +21,9 @@
* \ingroup render
*/
-#include <math.h>
-#include <stddef.h>
-#include <string.h>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -82,7 +82,7 @@
#include "GPU_framebuffer.h"
#include "GPU_matrix.h"
-#include "render_intern.h"
+#include "render_intern.hh"
/* Define this to get timing information. */
// #define DEBUG_TIME
@@ -92,10 +92,10 @@
#endif
/* TODO(sergey): Find better approximation of the scheduled frames.
- * For really highres renders it might fail still. */
+ * For really high-resolution renders it might fail still. */
#define MAX_SCHEDULED_FRAMES 8
-typedef struct OGLRender {
+struct OGLRender {
Main *bmain;
Render *re;
Scene *scene;
@@ -141,7 +141,7 @@ typedef struct OGLRender {
wmWindowManager *wm;
wmWindow *win;
- /** Use to check if running modal or not (invoke'd or exec'd). */
+ /** Use to check if running modal or not (invoked or executed). */
wmTimer *timer;
void **movie_ctx_arr;
@@ -159,7 +159,7 @@ typedef struct OGLRender {
#ifdef DEBUG_TIME
double time_start;
#endif
-} OGLRender;
+};
static bool screen_opengl_is_multiview(OGLRender *oglrender)
{
@@ -167,12 +167,12 @@ static bool screen_opengl_is_multiview(OGLRender *oglrender)
RegionView3D *rv3d = oglrender->rv3d;
RenderData *rd = &oglrender->scene->r;
- if ((rd == NULL) || ((v3d != NULL) && (rv3d == NULL))) {
+ if ((rd == nullptr) || ((v3d != nullptr) && (rv3d == nullptr))) {
return false;
}
return (rd->scemode & R_MULTIVIEW) &&
- ((v3d == NULL) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
+ ((v3d == nullptr) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
}
static void screen_opengl_views_setup(OGLRender *oglrender)
@@ -192,10 +192,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
if (!is_multiview) {
/* we only have one view when multiview is off */
- rv = rr->views.first;
+ rv = static_cast<RenderView *>(rr->views.first);
- if (rv == NULL) {
- rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
+ if (rv == nullptr) {
+ rv = MEM_cnew<RenderView>("new opengl render view");
BLI_addtail(&rr->views, rv);
}
@@ -224,9 +224,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
}
/* remove all the views that are not needed */
- rv = rr->views.last;
+ rv = static_cast<RenderView *>(rr->views.last);
while (rv) {
- srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name));
+ srv = static_cast<SceneRenderView *>(
+ BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name)));
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
rv = rv->prev;
}
@@ -253,15 +254,16 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
}
/* create all the views that are needed */
- for (srv = rd->views.first; srv; srv = srv->next) {
+ for (srv = static_cast<SceneRenderView *>(rd->views.first); srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) {
continue;
}
- rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name));
+ rv = static_cast<RenderView *>(
+ BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name)));
- if (rv == NULL) {
- rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
+ if (rv == nullptr) {
+ rv = MEM_cnew<RenderView>("new opengl render view");
BLI_strncpy(rv->name, srv->name, sizeof(rv->name));
BLI_addtail(&rr->views, rv);
}
@@ -291,19 +293,19 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
ARegion *region = oglrender->region;
View3D *v3d = oglrender->v3d;
RegionView3D *rv3d = oglrender->rv3d;
- Object *camera = NULL;
+ Object *camera = nullptr;
int sizex = oglrender->sizex;
int sizey = oglrender->sizey;
- const short view_context = (v3d != NULL);
+ const short view_context = (v3d != nullptr);
bool draw_sky = (scene->r.alphamode == R_ADDSKY);
- float *rectf = NULL;
- uchar *rect = NULL;
+ float *rectf = nullptr;
+ uchar *rect = nullptr;
const char *viewname = RE_GetActiveRenderView(oglrender->re);
- ImBuf *ibuf_result = NULL;
+ ImBuf *ibuf_result = nullptr;
if (oglrender->is_sequencer) {
SpaceSeq *sseq = oglrender->sseq;
- struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : NULL;
+ struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : nullptr;
/* use pre-calculated ImBuf (avoids deadlock), see: */
ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id];
@@ -318,7 +320,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
* TODO(sergey): In the case of output to float container (EXR)
* it actually makes sense to keep float buffer instead.
*/
- if (out->rect_float != NULL) {
+ if (out->rect_float != nullptr) {
IMB_rect_from_float(out);
imb_freerectfloatImBuf(out);
}
@@ -352,7 +354,8 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
ED_annotation_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
G.f &= ~G_FLAG_RENDER_VIEWPORT;
- gp_rect = MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect");
+ gp_rect = static_cast<uchar *>(
+ MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect"));
GPU_offscreen_read_pixels(oglrender->ofs, GPU_DATA_UBYTE, gp_rect);
for (i = 0; i < sizex * sizey * 4; i += 4) {
@@ -372,7 +375,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
if (view_context) {
ibuf_view = ED_view3d_draw_offscreen_imbuf(depsgraph,
scene,
- v3d->shading.type,
+ static_cast<eDrawType>(v3d->shading.type),
v3d,
region,
sizex,
@@ -392,7 +395,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
else {
ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(depsgraph,
scene,
- NULL,
+ nullptr,
OB_SOLID,
scene->camera,
oglrender->sizex,
@@ -420,9 +423,9 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
}
}
- if (ibuf_result != NULL) {
+ if (ibuf_result != nullptr) {
if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
- BKE_image_stamp_buf(scene, camera, NULL, rect, rectf, rr->rectx, rr->recty, 4);
+ BKE_image_stamp_buf(scene, camera, nullptr, rect, rectf, rr->rectx, rr->recty, 4);
}
RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id);
IMB_freeImBuf(ibuf_result);
@@ -445,7 +448,7 @@ static void screen_opengl_render_write(OGLRender *oglrender)
&scene->r.im_format,
(scene->r.scemode & R_EXTENSION) != 0,
false,
- NULL);
+ nullptr);
/* write images as individual images or stereo */
BKE_render_result_stamp_info(scene, scene->camera, rr, false);
@@ -506,7 +509,8 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
}
rr = RE_AcquireResultRead(oglrender->re);
- for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) {
+ for (rv = static_cast<RenderView *>(rr->views.first), view_id = 0; rv;
+ rv = rv->next, view_id++) {
BLI_assert(view_id < oglrender->views_len);
RE_SetActiveRenderView(oglrender->re, rv->name);
oglrender->view_id = view_id;
@@ -530,7 +534,7 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const AnimData *adt)
{
- if (adt == NULL || adt->action == NULL) {
+ if (adt == nullptr || adt->action == nullptr) {
return;
}
@@ -539,7 +543,7 @@ static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const An
int frame_end = PEFRA;
LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
- if (fcu->driver != NULL || fcu->fpt != NULL) {
+ if (fcu->driver != nullptr || fcu->fpt != nullptr) {
/* Drivers have values for any point in time, so to get "the keyed frames" they are
* useless. Same for baked FCurves, they also have keys for every frame, which is not
* useful for rendering the keyed subset of the frames. */
@@ -568,7 +572,7 @@ static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const An
static void gather_frames_to_render_for_grease_pencil(const OGLRender *oglrender,
const bGPdata *gp)
{
- if (gp == NULL) {
+ if (gp == nullptr) {
return;
}
@@ -589,7 +593,7 @@ static void gather_frames_to_render_for_grease_pencil(const OGLRender *oglrender
static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data)
{
ID **id_p = cb_data->id_pointer;
- if (*id_p == NULL) {
+ if (*id_p == nullptr) {
return IDWALK_RET_NOP;
}
ID *id = *id_p;
@@ -602,7 +606,7 @@ static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_STOP_RECURSION;
}
- OGLRender *oglrender = cb_data->user_data;
+ OGLRender *oglrender = static_cast<OGLRender *>(cb_data->user_data);
/* Whitelist of datablocks to follow pointers into. */
const ID_Type id_type = GS(id->name);
@@ -699,7 +703,7 @@ static void gather_frames_to_render(bContext *C, OGLRender *oglrender)
/* Gather the frames from linked data-blocks (materials, shape-keys, etc.). */
BKE_library_foreach_ID_link(
- NULL, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE);
+ nullptr, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE);
}
CTX_DATA_END;
}
@@ -722,8 +726,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
const bool is_render_keyed_only = RNA_boolean_get(op->ptr, "render_keyed_only");
const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
- const eImageFormatDepth color_depth = (is_animation) ? scene->r.im_format.depth :
- R_IMF_CHAN_DEPTH_32;
+ const eImageFormatDepth color_depth = static_cast<eImageFormatDepth>(
+ (is_animation) ? (eImageFormatDepth)scene->r.im_format.depth : R_IMF_CHAN_DEPTH_32);
char err_out[256] = "unknown";
if (G.background) {
@@ -747,7 +751,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
is_view_context = false;
}
- if (!is_view_context && scene->camera == NULL) {
+ if (!is_view_context && scene->camera == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Scene has no camera");
return false;
}
@@ -777,7 +781,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
}
/* allocate opengl render */
- oglrender = MEM_callocN(sizeof(OGLRender), "OGLRender");
+ oglrender = MEM_new<OGLRender>("OGLRender");
op->customdata = oglrender;
oglrender->ofs = ofs;
@@ -801,7 +805,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->is_sequencer = is_sequencer;
if (is_sequencer) {
oglrender->sseq = CTX_wm_space_seq(C);
- ImBuf **ibufs_arr = MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__);
+ ImBuf **ibufs_arr = static_cast<ImBuf **>(
+ MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__));
oglrender->seq_data.ibufs_arr = ibufs_arr;
}
@@ -812,7 +817,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* so quad view renders camera */
ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->region);
- oglrender->rv3d = oglrender->region->regiondata;
+ oglrender->rv3d = static_cast<RegionView3D *>(oglrender->region->regiondata);
/* MUST be cleared on exit */
memset(&oglrender->scene->customdata_mask_modal,
@@ -832,14 +837,14 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* create image and image user */
oglrender->ima = BKE_image_ensure_viewer(oglrender->bmain, IMA_TYPE_R_RESULT, "Render Result");
- BKE_image_signal(oglrender->bmain, oglrender->ima, NULL, IMA_SIGNAL_FREE);
+ BKE_image_signal(oglrender->bmain, oglrender->ima, nullptr, IMA_SIGNAL_FREE);
BKE_image_backup_render(oglrender->scene, oglrender->ima, true);
oglrender->iuser.scene = scene;
- oglrender->iuser.ok = 1;
/* create render result */
- RE_InitState(oglrender->re, NULL, &scene->r, &scene->view_layers, NULL, sizex, sizey, NULL);
+ RE_InitState(
+ oglrender->re, nullptr, &scene->r, &scene->view_layers, nullptr, sizex, sizey, nullptr);
/* create render views */
screen_opengl_views_setup(oglrender);
@@ -849,8 +854,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->win = win;
oglrender->totvideos = 0;
- oglrender->mh = NULL;
- oglrender->movie_ctx_arr = NULL;
+ oglrender->mh = nullptr;
+ oglrender->movie_ctx_arr = nullptr;
if (is_animation) {
if (is_render_keyed_only) {
@@ -867,7 +872,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
BLI_spin_init(&oglrender->reports_lock);
}
else {
- oglrender->task_pool = NULL;
+ oglrender->task_pool = nullptr;
}
oglrender->num_scheduled_frames = 0;
BLI_mutex_init(&oglrender->task_mutex);
@@ -955,12 +960,12 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
CTX_wm_area_set(C, oglrender->prevsa);
CTX_wm_region_set(C, oglrender->prevar);
- MEM_freeN(oglrender);
+ MEM_delete(oglrender);
}
static void screen_opengl_render_cancel(bContext *C, wmOperator *op)
{
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
}
/* share between invoke and exec */
@@ -970,7 +975,7 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op)
OGLRender *oglrender;
Scene *scene;
- oglrender = op->customdata;
+ oglrender = static_cast<OGLRender *>(op->customdata);
scene = oglrender->scene;
oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r);
@@ -984,13 +989,14 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op)
&scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
- if (oglrender->mh == NULL) {
+ if (oglrender->mh == nullptr) {
BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported");
screen_opengl_render_end(C, oglrender);
return false;
}
- oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies");
+ oglrender->movie_ctx_arr = static_cast<void **>(
+ MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies"));
for (i = 0; i < oglrender->totvideos; i++) {
Scene *scene_eval = DEG_get_evaluated_scene(oglrender->depsgraph);
@@ -1018,10 +1024,10 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op)
return true;
}
-typedef struct WriteTaskData {
+struct WriteTaskData {
RenderResult *rr;
Scene tmp_scene;
-} WriteTaskData;
+};
static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
{
@@ -1074,18 +1080,19 @@ static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
&scene->r.im_format,
(scene->r.scemode & R_EXTENSION) != 0,
true,
- NULL);
+ nullptr);
BKE_render_result_stamp_info(scene, scene->camera, rr, false);
- ok = RE_WriteRenderViewsImage(NULL, rr, scene, true, name);
+ ok = RE_WriteRenderViewsImage(nullptr, rr, scene, true, name);
if (!ok) {
BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", name);
}
}
- if (reports.list.first != NULL) {
+ if (reports.list.first != nullptr) {
BLI_spin_lock(&oglrender->reports_lock);
- for (Report *report = reports.list.first; report != NULL; report = report->next) {
- BKE_report(oglrender->reports, report->type, report->message);
+ for (Report *report = static_cast<Report *>(reports.list.first); report != nullptr;
+ report = report->next) {
+ BKE_report(oglrender->reports, static_cast<eReportType>(report->type), report->message);
}
BLI_spin_unlock(&oglrender->reports_lock);
}
@@ -1106,27 +1113,27 @@ static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
return false;
}
Scene *scene = oglrender->scene;
- WriteTaskData *task_data = MEM_mallocN(sizeof(WriteTaskData), "write task data");
+ WriteTaskData *task_data = MEM_new<WriteTaskData>("write task data");
task_data->rr = rr;
- task_data->tmp_scene = *scene;
+ memcpy(&task_data->tmp_scene, scene, sizeof(task_data->tmp_scene));
BLI_mutex_lock(&oglrender->task_mutex);
oglrender->num_scheduled_frames++;
if (oglrender->num_scheduled_frames > MAX_SCHEDULED_FRAMES) {
BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex);
}
BLI_mutex_unlock(&oglrender->task_mutex);
- BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, NULL);
+ BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, nullptr);
return true;
}
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
{
- OGLRender *oglrender = op->customdata;
+ OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
Scene *scene = oglrender->scene;
Depsgraph *depsgraph = oglrender->depsgraph;
char name[FILE_MAX];
bool ok = false;
- const bool view_context = (oglrender->v3d != NULL);
+ const bool view_context = (oglrender->v3d != nullptr);
bool is_movie;
RenderResult *rr;
@@ -1149,7 +1156,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
&scene->r.im_format,
(scene->r.scemode & R_EXTENSION) != 0,
true,
- NULL);
+ nullptr);
if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
BLI_spin_lock(&oglrender->reports_lock);
@@ -1178,7 +1185,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
BKE_scene_camera_switch_update(scene);
}
- if (oglrender->render_frames == NULL ||
+ if (oglrender->render_frames == nullptr ||
BLI_BITMAP_TEST_BOOL(oglrender->render_frames, CFRA - PSFRA)) {
/* render into offscreen buffer */
screen_opengl_render_apply(C, oglrender);
@@ -1186,10 +1193,12 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
/* save to disk */
rr = RE_AcquireResultRead(oglrender->re);
- RenderResult *new_rr = RE_DuplicateRenderResult(rr);
- RE_ReleaseResult(oglrender->re);
+ {
+ RenderResult *new_rr = RE_DuplicateRenderResult(rr);
+ RE_ReleaseResult(oglrender->re);
- ok = schedule_write_result(oglrender, new_rr);
+ ok = schedule_write_result(oglrender, new_rr);
+ }
finally: /* Step the frame and bail early if needed */
@@ -1198,16 +1207,16 @@ finally: /* Step the frame and bail early if needed */
/* stop at the end or on error */
if (CFRA >= PEFRA || !ok) {
- screen_opengl_render_end(C, op->customdata);
- return 0;
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
+ return false;
}
- return 1;
+ return true;
}
static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- OGLRender *oglrender = op->customdata;
+ OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
const bool anim = RNA_boolean_get(op->ptr, "animation");
bool ret;
@@ -1215,7 +1224,7 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent
case EVT_ESCKEY:
/* cancel */
oglrender->pool_ok = false; /* Flag pool for cancel. */
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
return OPERATOR_FINISHED;
case TIMER:
/* render frame? */
@@ -1232,8 +1241,8 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene);
if (anim == 0) {
- screen_opengl_render_apply(C, op->customdata);
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata));
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
return OPERATOR_FINISHED;
}
@@ -1262,8 +1271,8 @@ static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEven
}
}
- oglrender = op->customdata;
- render_view_open(C, event->x, event->y, op->reports);
+ oglrender = static_cast<OGLRender *>(op->customdata);
+ render_view_open(C, event->xy[0], event->xy[1], op->reports);
/* View may be changed above #USER_RENDER_DISPLAY_WINDOW. */
oglrender->win = CTX_wm_window(C);
@@ -1285,8 +1294,8 @@ static int screen_opengl_render_exec(bContext *C, wmOperator *op)
if (!is_animation) { /* same as invoke */
/* render image */
- screen_opengl_render_apply(C, op->customdata);
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata));
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
return OPERATOR_FINISHED;
}
@@ -1313,7 +1322,7 @@ static char *screen_opengl_render_description(struct bContext *UNUSED(C),
struct PointerRNA *ptr)
{
if (!RNA_boolean_get(ptr, "animation")) {
- return NULL;
+ return nullptr;
}
if (RNA_boolean_get(ptr, "render_keyed_only")) {
@@ -1345,32 +1354,32 @@ void RENDER_OT_opengl(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna,
"animation",
- 0,
+ false,
"Animation",
"Render files from the animation range of this scene");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"render_keyed_only",
- 0,
+ false,
"Render Keyframes Only",
"Render only those frames where selected objects have a key in their "
"animation data. Only used when rendering animation");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(
- ot->srna, "sequencer", 0, "Sequencer", "Render using the sequencer's OpenGL display");
+ ot->srna, "sequencer", false, "Sequencer", "Render using the sequencer's OpenGL display");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(
ot->srna,
"write_still",
- 0,
+ false,
"Write Image",
"Save rendered the image to the output path (used only when animation is disabled)");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"view_context",
- 1,
+ true,
"View Context",
"Use the current 3D view for rendering, else use scene settings");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.cc
index e0aa02b354d..0f10d186e6e 100644
--- a/source/blender/editors/render/render_ops.c
+++ b/source/blender/editors/render/render_ops.cc
@@ -21,7 +21,7 @@
* \ingroup edrend
*/
-#include <stdlib.h>
+#include <cstdlib>
#include "BLI_utildefines.h"
@@ -29,11 +29,11 @@
#include "WM_api.h"
-#include "render_intern.h" /* own include */
+#include "render_intern.hh" /* own include */
/***************************** render ***********************************/
-void ED_operatortypes_render(void)
+void ED_operatortypes_render()
{
WM_operatortype_append(OBJECT_OT_material_slot_add);
WM_operatortype_append(OBJECT_OT_material_slot_remove);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.cc
index 81aecfdf788..79c3b2f7ac6 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.cc
@@ -23,9 +23,9 @@
/* global includes */
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
#ifndef WIN32
# include <unistd.h>
@@ -103,6 +103,8 @@
#include "ED_view3d.h"
#include "ED_view3d_offscreen.h"
+#include "UI_interface_icons.h"
+
#ifndef NDEBUG
/* Used for database init assert(). */
# include "BLI_threads.h"
@@ -114,7 +116,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect);
/** \name Local Structs
* \{ */
-typedef struct ShaderPreview {
+struct ShaderPreview {
/* from wmJob */
void *owner;
short *stop, *do_update;
@@ -135,31 +137,32 @@ typedef struct ShaderPreview {
int sizex, sizey;
uint *pr_rect;
- int pr_method;
+ ePreviewRenderMethod pr_method;
bool own_id_copy;
Main *bmain;
Main *pr_main;
-} ShaderPreview;
+};
-typedef struct IconPreviewSize {
+struct IconPreviewSize {
struct IconPreviewSize *next, *prev;
int sizex, sizey;
uint *rect;
-} IconPreviewSize;
+};
-typedef struct IconPreview {
+struct IconPreview {
Main *bmain;
- Depsgraph *depsgraph; /* May be NULL (see #WM_OT_previews_ensure). */
+ Depsgraph *depsgraph; /* May be nullptr (see #WM_OT_previews_ensure). */
Scene *scene;
void *owner;
- ID *id, *id_copy; /* May be NULL! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */
+ ID *id,
+ *id_copy; /* May be nullptr! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */
ListBase sizes;
- /* May be NULL, is used for rendering IDs that require some other object for it to be applied on
- * before the ID can be represented as an image, for example when rendering an Action. */
+ /* May be nullptr, is used for rendering IDs that require some other object for it to be applied
+ * on before the ID can be represented as an image, for example when rendering an Action. */
struct Object *active_object;
-} IconPreview;
+};
/** \} */
@@ -167,18 +170,18 @@ typedef struct IconPreview {
/** \name Preview for Buttons
* \{ */
-static Main *G_pr_main = NULL;
-static Main *G_pr_main_grease_pencil = NULL;
+static Main *G_pr_main = nullptr;
+static Main *G_pr_main_grease_pencil = nullptr;
#ifndef WITH_HEADLESS
static Main *load_main_from_memory(const void *blend, int blend_size)
{
const int fileflags = G.fileflags;
- Main *bmain = NULL;
+ Main *bmain = nullptr;
BlendFileData *bfd;
G.fileflags |= G_FILE_NO_UI;
- bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, NULL);
+ bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, nullptr);
if (bfd) {
bmain = bfd->main;
@@ -190,7 +193,7 @@ static Main *load_main_from_memory(const void *blend, int blend_size)
}
#endif
-void ED_preview_ensure_dbase(void)
+void ED_preview_ensure_dbase()
{
#ifndef WITH_HEADLESS
static bool base_initialized = false;
@@ -210,12 +213,12 @@ static bool check_engine_supports_preview(Scene *scene)
return (type->flag & RE_USE_PREVIEW) != 0;
}
-static bool preview_method_is_render(int pr_method)
+static bool preview_method_is_render(const ePreviewRenderMethod pr_method)
{
- return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER, PR_NODE_RENDER);
+ return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER);
}
-void ED_preview_free_dbase(void)
+void ED_preview_free_dbase()
{
if (G_pr_main) {
BKE_main_free(G_pr_main);
@@ -228,11 +231,11 @@ void ED_preview_free_dbase(void)
static Scene *preview_get_scene(Main *pr_main)
{
- if (pr_main == NULL) {
- return NULL;
+ if (pr_main == nullptr) {
+ return nullptr;
}
- return pr_main->scenes.first;
+ return static_cast<Scene *>(pr_main->scenes.first);
}
static const char *preview_collection_name(const ePreviewType pr_type)
@@ -274,10 +277,10 @@ static bool render_engine_supports_ray_visibility(const Scene *sce)
static void switch_preview_collection_visibilty(ViewLayer *view_layer, const ePreviewType pr_type)
{
/* Set appropriate layer as visible. */
- LayerCollection *lc = view_layer->layer_collections.first;
+ LayerCollection *lc = static_cast<LayerCollection *>(view_layer->layer_collections.first);
const char *collection_name = preview_collection_name(pr_type);
- for (lc = lc->layer_collections.first; lc; lc = lc->next) {
+ for (lc = static_cast<LayerCollection *>(lc->layer_collections.first); lc; lc = lc->next) {
if (STREQ(lc->collection->id.name + 2, collection_name)) {
lc->collection->flag &= ~COLLECTION_HIDE_RENDER;
}
@@ -306,7 +309,8 @@ static void switch_preview_floor_material(Main *pr_main,
}
const char *material_name = preview_floor_material_name(scene, pr_method);
- Material *mat = BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2);
+ Material *mat = static_cast<Material *>(
+ BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2));
if (mat) {
me->mat[0] = mat;
}
@@ -327,7 +331,8 @@ static void switch_preview_floor_visibility(Main *pr_main,
}
}
if (base->object->type == OB_MESH) {
- switch_preview_floor_material(pr_main, base->object->data, scene, pr_method);
+ switch_preview_floor_material(
+ pr_main, static_cast<Mesh *>(base->object->data), scene, pr_method);
}
}
}
@@ -346,16 +351,16 @@ static void set_preview_visibility(Main *pr_main,
static World *preview_get_localized_world(ShaderPreview *sp, World *world)
{
- if (world == NULL) {
- return NULL;
+ if (world == nullptr) {
+ return nullptr;
}
- if (sp->worldcopy != NULL) {
+ if (sp->worldcopy != nullptr) {
return sp->worldcopy;
}
- ID *id_copy = BKE_id_copy_ex(NULL,
+ ID *id_copy = BKE_id_copy_ex(nullptr,
&world->id,
- NULL,
+ nullptr,
LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE |
LIB_ID_COPY_NO_ANIMDATA);
sp->worldcopy = (World *)id_copy;
@@ -365,9 +370,9 @@ static World *preview_get_localized_world(ShaderPreview *sp, World *world)
static ID *duplicate_ids(ID *id, const bool allow_failure)
{
- if (id == NULL) {
+ if (id == nullptr) {
/* Non-ID preview render. */
- return NULL;
+ return nullptr;
}
switch (GS(id->name)) {
@@ -377,20 +382,23 @@ static ID *duplicate_ids(ID *id, const bool allow_failure)
case ID_LA:
case ID_WO: {
BLI_assert(BKE_previewimg_id_supports_jobs(id));
- ID *id_copy = BKE_id_copy_ex(
- NULL, id, NULL, LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA);
+ ID *id_copy = BKE_id_copy_ex(nullptr,
+ id,
+ nullptr,
+ LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE |
+ LIB_ID_COPY_NO_ANIMDATA);
return id_copy;
}
/* These support threading, but don't need duplicating. */
case ID_IM:
case ID_BR:
BLI_assert(BKE_previewimg_id_supports_jobs(id));
- return NULL;
+ return nullptr;
default:
if (!allow_failure) {
BLI_assert_msg(0, "ID type preview not supported.");
}
- return NULL;
+ return nullptr;
}
}
@@ -402,8 +410,8 @@ static const char *preview_world_name(const Scene *sce,
* material trick to show the floor in the reflections, but hide the floor for camera rays. For
* Eevee we use a transparent world that has a projected grid.
*
- * In the future when Eevee supports vulkan raytracing we can re-evaluate and perhaps remove this
- * approximation.
+ * In the future when Eevee supports VULKAN ray-tracing we can re-evaluate and perhaps remove
+ * this approximation.
*/
if (id_type == ID_MA && pr_method == PR_ICON_RENDER &&
!render_engine_supports_ray_visibility(sce)) {
@@ -417,13 +425,14 @@ static World *preview_get_world(Main *pr_main,
const ID_Type id_type,
const ePreviewRenderMethod pr_method)
{
- World *result = NULL;
+ World *result = nullptr;
const char *world_name = preview_world_name(sce, id_type, pr_method);
- result = BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2);
+ result = static_cast<World *>(
+ BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2));
/* No world found return first world. */
- if (result == NULL) {
- result = pr_main->worlds.first;
+ if (result == nullptr) {
+ result = static_cast<World *>(pr_main->worlds.first);
}
BLI_assert_msg(result, "Preview file has no world.");
@@ -452,18 +461,18 @@ static World *preview_prepare_world(Main *pr_main,
}
/* call this with a pointer to initialize preview scene */
-/* call this with NULL to restore assigned ID pointers in preview scene */
+/* call this with nullptr to restore assigned ID pointers in preview scene */
static Scene *preview_prepare_scene(
Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp)
{
Scene *sce;
Main *pr_main = sp->pr_main;
- memcpy(pr_main->name, BKE_main_blendfile_path(bmain), sizeof(pr_main->name));
+ memcpy(pr_main->filepath, BKE_main_blendfile_path(bmain), sizeof(pr_main->filepath));
sce = preview_get_scene(pr_main);
if (sce) {
- ViewLayer *view_layer = sce->view_layers.first;
+ ViewLayer *view_layer = static_cast<ViewLayer *>(sce->view_layers.first);
/* Only enable the combined renderpass */
view_layer->passflag = SCE_PASS_COMBINED;
@@ -489,7 +498,8 @@ static Scene *preview_prepare_scene(
sce->r.cfra = scene->r.cfra;
/* Setup the world. */
- sce->world = preview_prepare_world(pr_main, sce, scene->world, id_type, sp->pr_method);
+ sce->world = preview_prepare_world(
+ pr_main, sce, scene->world, static_cast<ID_Type>(id_type), sp->pr_method);
if (id_type == ID_TE) {
/* Texture is not actually rendered with engine, just set dummy value. */
@@ -497,13 +507,13 @@ static Scene *preview_prepare_scene(
}
if (id_type == ID_MA) {
- Material *mat = NULL, *origmat = (Material *)id;
+ Material *mat = nullptr, *origmat = (Material *)id;
if (origmat) {
/* work on a copy */
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
mat = sp->matcopy = (Material *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->materials, mat);
/* Use current scene world for lighting. */
@@ -521,20 +531,11 @@ static Scene *preview_prepare_scene(
}
/* For grease pencil, always use sphere for icon renders. */
- const ePreviewType preview_type = (sp->pr_method == PR_ICON_RENDER &&
- sp->pr_main == G_pr_main_grease_pencil) ?
- MA_SPHERE_A :
- mat->pr_type;
+ const ePreviewType preview_type = static_cast<ePreviewType>(
+ (sp->pr_method == PR_ICON_RENDER && sp->pr_main == G_pr_main_grease_pencil) ?
+ MA_SPHERE_A :
+ (ePreviewType)mat->pr_type);
set_preview_visibility(pr_main, sce, view_layer, preview_type, sp->pr_method);
-
- if (sp->pr_method != PR_ICON_RENDER) {
- if (mat->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(mat->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origmat is not safe! */
- BKE_node_preview_init_tree(origmat->nodetree, sp->sizex, sp->sizey, true);
- }
- }
}
else {
sce->display.render_aa = SCE_DISPLAY_AA_OFF;
@@ -562,30 +563,23 @@ static Scene *preview_prepare_scene(
}
}
else if (id_type == ID_TE) {
- Tex *tex = NULL, *origtex = (Tex *)id;
+ Tex *tex = nullptr, *origtex = (Tex *)id;
if (origtex) {
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
tex = sp->texcopy = (Tex *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->textures, tex);
}
-
- if (tex && tex->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(tex->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origtex is not safe! */
- BKE_node_preview_init_tree(origtex->nodetree, sp->sizex, sp->sizey, true);
- }
}
else if (id_type == ID_LA) {
- Light *la = NULL, *origla = (Light *)id;
+ Light *la = nullptr, *origla = (Light *)id;
/* work on a copy */
if (origla) {
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
la = sp->lampcopy = (Light *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->lights, la);
}
@@ -606,39 +600,25 @@ static Scene *preview_prepare_scene(
}
}
}
-
- if (la && la->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(la->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origla is not safe! */
- BKE_node_preview_init_tree(origla->nodetree, sp->sizex, sp->sizey, true);
- }
}
else if (id_type == ID_WO) {
- World *wrld = NULL, *origwrld = (World *)id;
+ World *wrld = nullptr, *origwrld = (World *)id;
if (origwrld) {
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
wrld = sp->worldcopy = (World *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->worlds, wrld);
}
set_preview_visibility(pr_main, sce, view_layer, MA_SKY, sp->pr_method);
sce->world = wrld;
-
- if (wrld && wrld->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(wrld->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origwrld is not safe! */
- BKE_node_preview_init_tree(origwrld->nodetree, sp->sizex, sp->sizey, true);
- }
}
return sce;
}
- return NULL;
+ return nullptr;
}
/* new UI convention: draw is in pixel space already. */
@@ -675,7 +655,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
/* test if something rendered ok */
re = RE_GetRender(name);
- if (re == NULL) {
+ if (re == nullptr) {
return false;
}
@@ -687,7 +667,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
}
else {
/* possible the job clears the views but we're still drawing T45496 */
- rv = NULL;
+ rv = nullptr;
}
if (rv && rv->rectf) {
@@ -698,8 +678,8 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty);
if (rres.rectx && rres.recty) {
- uchar *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int),
- "ed_preview_draw_rect");
+ uchar *rect_byte = static_cast<uchar *>(
+ MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect"));
float fx = rect->xmin + offx;
float fy = rect->ymin;
@@ -707,12 +687,21 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
RE_AcquiredResultGet32(re, &rres, (uint *)rect_byte, 0);
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(
- &state, fx, fy, rres.rectx, rres.recty, GPU_RGBA8, false, rect_byte, 1.0f, 1.0f, NULL);
+ immDrawPixelsTexTiled(&state,
+ fx,
+ fy,
+ rres.rectx,
+ rres.recty,
+ GPU_RGBA8,
+ false,
+ rect_byte,
+ 1.0f,
+ 1.0f,
+ nullptr);
MEM_freeN(rect_byte);
- ok = 1;
+ ok = true;
}
}
}
@@ -731,9 +720,9 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
ID *parent = (ID *)parentp;
MTex *slot = (MTex *)slotp;
SpaceProperties *sbuts = CTX_wm_space_properties(C);
- ShaderPreview *sp = WM_jobs_customdata(wm, area);
+ ShaderPreview *sp = static_cast<ShaderPreview *>(WM_jobs_customdata(wm, area));
rcti newrect;
- int ok;
+ bool ok;
int newx = BLI_rcti_size_x(rect);
int newy = BLI_rcti_size_y(rect);
@@ -757,10 +746,10 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
/* start a new preview render job if signaled through sbuts->preview,
* if no render result was found and no preview render job is running,
* or if the job is running and the size of preview changed */
- if ((sbuts != NULL && sbuts->preview) ||
+ if ((sbuts != nullptr && sbuts->preview) ||
(!ok && !WM_jobs_test(wm, area, WM_JOB_TYPE_RENDER_PREVIEW)) ||
(sp && (abs(sp->sizex - newx) >= 2 || abs(sp->sizey - newy) > 2))) {
- if (sbuts != NULL) {
+ if (sbuts != nullptr) {
sbuts->preview = 0;
}
ED_preview_shader_job(C, area, id, parent, slot, newx, newy, PR_BUTS_RENDER);
@@ -786,6 +775,11 @@ struct ObjectPreviewData {
int sizey;
};
+static bool object_preview_is_type_supported(const Object *ob)
+{
+ return OB_TYPE_IS_GEOMETRY(ob->type);
+}
+
static Object *object_preview_camera_create(Main *preview_main,
ViewLayer *view_layer,
Object *preview_object)
@@ -819,11 +813,11 @@ static Scene *object_preview_scene_create(const struct ObjectPreviewData *previe
* viewport displays. */
CFRA = preview_data->cfra;
- ViewLayer *view_layer = scene->view_layers.first;
+ ViewLayer *view_layer = static_cast<ViewLayer *>(scene->view_layers.first);
Depsgraph *depsgraph = DEG_graph_new(
preview_data->pr_main, scene, view_layer, DAG_EVAL_VIEWPORT);
- BLI_assert(preview_data->object != NULL);
+ BLI_assert(preview_data->object != nullptr);
BLI_addtail(&preview_data->pr_main->objects, preview_data->object);
BKE_collection_object_add(preview_data->pr_main, scene->master_collection, preview_data->object);
@@ -854,26 +848,23 @@ static Scene *object_preview_scene_create(const struct ObjectPreviewData *previe
static void object_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
{
Main *preview_main = BKE_main_new();
- const float pixelsize_old = U.pixelsize;
char err_out[256] = "unknown";
BLI_assert(preview->id_copy && (preview->id_copy != preview->id));
- struct ObjectPreviewData preview_data = {
- .pr_main = preview_main,
- /* Act on a copy. */
- .object = (Object *)preview->id_copy,
- .cfra = preview->scene->r.cfra,
- .sizex = preview_sized->sizex,
- .sizey = preview_sized->sizey,
- };
+ struct ObjectPreviewData preview_data = {};
+ preview_data.pr_main = preview_main;
+ /* Act on a copy. */
+ preview_data.object = (Object *)preview->id_copy;
+ preview_data.cfra = preview->scene->r.cfra;
+ preview_data.sizex = preview_sized->sizex;
+ preview_data.sizey = preview_sized->sizey;
+
Depsgraph *depsgraph;
Scene *scene = object_preview_scene_create(&preview_data, &depsgraph);
/* Ownership is now ours. */
- preview->id_copy = NULL;
-
- U.pixelsize = 2.0f;
+ preview->id_copy = nullptr;
View3DShading shading;
BKE_screen_view3d_shading_init(&shading);
@@ -891,13 +882,11 @@ static void object_preview_render(IconPreview *preview, IconPreviewSize *preview
IB_rect,
V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS,
R_ALPHAPREMUL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
err_out);
/* TODO: color-management? */
- U.pixelsize = pixelsize_old;
-
if (ibuf) {
icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect);
IMB_freeImBuf(ibuf);
@@ -916,15 +905,15 @@ static void object_preview_render(IconPreview *preview, IconPreviewSize *preview
static struct PoseBackup *action_preview_render_prepare(IconPreview *preview)
{
Object *object = preview->active_object;
- if (object == NULL) {
+ if (object == nullptr) {
WM_report(RPT_WARNING, "No active object, unable to apply the Action before rendering");
- return NULL;
+ return nullptr;
}
- if (object->pose == NULL) {
+ if (object->pose == nullptr) {
WM_reportf(RPT_WARNING,
"Object %s has no pose, unable to apply the Action before rendering",
object->id.name + 2);
- return NULL;
+ return nullptr;
}
/* Create a backup of the current pose. */
@@ -945,7 +934,7 @@ static struct PoseBackup *action_preview_render_prepare(IconPreview *preview)
static void action_preview_render_cleanup(IconPreview *preview, struct PoseBackup *pose_backup)
{
- if (pose_backup == NULL) {
+ if (pose_backup == nullptr) {
return;
}
ED_pose_backup_restore(pose_backup);
@@ -965,7 +954,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
/* Not all code paths that lead to this function actually provide a depsgraph.
* The "Refresh Asset Preview" button (ED_OT_lib_id_generate_preview) does,
* but WM_OT_previews_ensure does not. */
- BLI_assert(depsgraph != NULL);
+ BLI_assert(depsgraph != nullptr);
BLI_assert(preview->scene == DEG_get_input_scene(depsgraph));
/* Apply the pose before getting the evaluated scene, so that the new pose is evaluated. */
@@ -973,7 +962,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *camera_eval = scene_eval->camera;
- if (camera_eval == NULL) {
+ if (camera_eval == nullptr) {
printf("Scene has no camera, unable to render preview of %s without it.\n",
preview->id->name + 2);
return;
@@ -982,16 +971,16 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
/* This renders with the Workbench engine settings stored on the Scene. */
ImBuf *ibuf = ED_view3d_draw_offscreen_imbuf_simple(depsgraph,
scene_eval,
- NULL,
+ nullptr,
OB_SOLID,
camera_eval,
preview_sized->sizex,
preview_sized->sizey,
IB_rect,
V3D_OFSDRAW_NONE,
- R_ALPHAPREMUL,
- NULL,
- NULL,
+ R_ADDSKY,
+ nullptr,
+ nullptr,
err_out);
action_preview_render_cleanup(preview, pose_backup);
@@ -1017,7 +1006,7 @@ static void shader_preview_update(void *spv,
RenderResult *UNUSED(rr),
volatile struct rcti *UNUSED(rect))
{
- ShaderPreview *sp = spv;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
*(sp->do_update) = true;
}
@@ -1025,46 +1014,13 @@ static void shader_preview_update(void *spv,
/* called by renderer, checks job value */
static int shader_preview_break(void *spv)
{
- ShaderPreview *sp = spv;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
return *(sp->stop);
}
-/* outside thread, called before redraw notifiers, it moves finished preview over */
-static void shader_preview_updatejob(void *spv)
+static void shader_preview_updatejob(void *UNUSED(spv))
{
- ShaderPreview *sp = spv;
-
- if (sp->pr_method == PR_NODE_RENDER) {
- if (GS(sp->id->name) == ID_MA) {
- Material *mat = (Material *)sp->id;
-
- if (sp->matcopy && mat->nodetree && sp->matcopy->nodetree) {
- ntreeLocalSync(sp->matcopy->nodetree, mat->nodetree);
- }
- }
- else if (GS(sp->id->name) == ID_TE) {
- Tex *tex = (Tex *)sp->id;
-
- if (sp->texcopy && tex->nodetree && sp->texcopy->nodetree) {
- ntreeLocalSync(sp->texcopy->nodetree, tex->nodetree);
- }
- }
- else if (GS(sp->id->name) == ID_WO) {
- World *wrld = (World *)sp->id;
-
- if (sp->worldcopy && wrld->nodetree && sp->worldcopy->nodetree) {
- ntreeLocalSync(sp->worldcopy->nodetree, wrld->nodetree);
- }
- }
- else if (GS(sp->id->name) == ID_LA) {
- Light *la = (Light *)sp->id;
-
- if (sp->lampcopy && la->nodetree && sp->lampcopy->nodetree) {
- ntreeLocalSync(sp->lampcopy->nodetree, la->nodetree);
- }
- }
- }
}
/* Renders texture directly to render buffer. */
@@ -1076,13 +1032,14 @@ static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Rend
/* This is needed otherwise no RenderResult is created. */
sce->r.scemode &= ~R_BUTS_PREVIEW;
- RE_InitState(re, NULL, &sce->r, &sce->view_layers, NULL, width, height, NULL);
+ RE_InitState(re, nullptr, &sce->r, &sce->view_layers, nullptr, width, height, nullptr);
RE_SetScene(re, sce);
/* Create buffer in empty RenderView created in the init step. */
RenderResult *rr = RE_AcquireResultWrite(re);
RenderView *rv = (RenderView *)rr->views.first;
- rv->rectf = MEM_callocN(sizeof(float[4]) * width * height, "texture render result");
+ rv->rectf = static_cast<float *>(
+ MEM_callocN(sizeof(float[4]) * width * height, "texture render result"));
RE_ReleaseResult(re);
/* Get texture image pool (if any) */
@@ -1155,7 +1112,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
/* get the stuff from the builtin preview dbase */
sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp);
- if (sce == NULL) {
+ if (sce == nullptr) {
return;
}
@@ -1168,7 +1125,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
re = RE_GetRender(name);
/* full refreshed render from first tile */
- if (re == NULL) {
+ if (re == nullptr) {
re = RE_NewRender(name);
}
@@ -1180,21 +1137,12 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
sce->r.scemode |= R_NO_IMAGE_LOAD;
sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8;
}
- else if (sp->pr_method == PR_NODE_RENDER) {
- if (idtype == ID_MA) {
- sce->r.scemode |= R_MATNODE_PREVIEW;
- }
- else if (idtype == ID_TE) {
- sce->r.scemode |= R_TEXNODE_PREVIEW;
- }
- sce->display.render_aa = SCE_DISPLAY_AA_OFF;
- }
else { /* PR_BUTS_RENDER */
sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8;
}
/* Callbacks are cleared on GetRender(). */
- if (ELEM(sp->pr_method, PR_BUTS_RENDER, PR_NODE_RENDER)) {
+ if (sp->pr_method == PR_BUTS_RENDER) {
RE_display_update_cb(re, sp, shader_preview_update);
}
/* set this for all previews, default is react to G.is_break still */
@@ -1227,7 +1175,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
}
/* unassign the pointers, reset vars */
- preview_prepare_scene(sp->bmain, sp->scene, NULL, GS(id->name), sp);
+ preview_prepare_scene(sp->bmain, sp->scene, nullptr, GS(id->name), sp);
/* XXX bad exception, end-exec is not being called in render, because it uses local main. */
#if 0
@@ -1242,7 +1190,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
/* runs inside thread for material and icons */
static void shader_preview_startjob(void *customdata, short *stop, short *do_update)
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
sp->stop = stop;
sp->do_update = do_update;
@@ -1273,17 +1221,17 @@ static void preview_id_copy_free(ID *id)
static void shader_preview_free(void *customdata)
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
Main *pr_main = sp->pr_main;
- ID *main_id_copy = NULL;
- ID *sub_id_copy = NULL;
+ ID *main_id_copy = nullptr;
+ ID *sub_id_copy = nullptr;
if (sp->matcopy) {
main_id_copy = (ID *)sp->matcopy;
BLI_remlink(&pr_main->materials, sp->matcopy);
}
if (sp->texcopy) {
- BLI_assert(main_id_copy == NULL);
+ BLI_assert(main_id_copy == nullptr);
main_id_copy = (ID *)sp->texcopy;
BLI_remlink(&pr_main->textures, sp->texcopy);
}
@@ -1298,14 +1246,10 @@ static void shader_preview_free(void *customdata)
BLI_remlink(&pr_main->worlds, sp->worldcopy);
}
if (sp->lampcopy) {
- BLI_assert(main_id_copy == NULL);
+ BLI_assert(main_id_copy == nullptr);
main_id_copy = (ID *)sp->lampcopy;
BLI_remlink(&pr_main->lights, sp->lampcopy);
}
- if (main_id_copy || sp->id_copy) {
- /* node previews */
- shader_preview_updatejob(sp);
- }
if (sp->own_id_copy) {
if (sp->id_copy) {
preview_id_copy_free(sp->id_copy);
@@ -1343,8 +1287,8 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
BLI_strncpy(path, brush->icon_filepath, sizeof(brush->icon_filepath));
BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&brush->id));
- /* use default colorspaces for brushes */
- brush->icon_imbuf = IMB_loadiffname(path, flags, NULL);
+ /* Use default color-spaces for brushes. */
+ brush->icon_imbuf = IMB_loadiffname(path, flags, nullptr);
/* otherwise lets try to find it in other directories */
if (!(brush->icon_imbuf)) {
@@ -1355,7 +1299,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
if (path[0]) {
/* Use default color spaces. */
- brush->icon_imbuf = IMB_loadiffname(path, flags, NULL);
+ brush->icon_imbuf = IMB_loadiffname(path, flags, nullptr);
}
}
@@ -1381,7 +1325,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect)
short ex, ey, dx, dy;
/* paranoia test */
- if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
+ if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) {
return;
}
@@ -1411,7 +1355,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect)
IMB_scalefastImBuf(ima, ex, ey);
/* if needed, convert to 32 bits */
- if (ima->rect == NULL) {
+ if (ima->rect == nullptr) {
IMB_rect_from_float(ima);
}
@@ -1439,13 +1383,13 @@ static void set_alpha(char *cp, int sizex, int sizey, char alpha)
static void icon_preview_startjob(void *customdata, short *stop, short *do_update)
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
if (sp->pr_method == PR_ICON_DEFERRED) {
- PreviewImage *prv = sp->owner;
+ PreviewImage *prv = static_cast<PreviewImage *>(sp->owner);
ImBuf *thumb;
- char *deferred_data = PRV_DEFERRED_DATA(prv);
- int source = deferred_data[0];
+ char *deferred_data = static_cast<char *>(PRV_DEFERRED_DATA(prv));
+ ThumbSource source = static_cast<ThumbSource>(deferred_data[0]);
char *path = &deferred_data[1];
// printf("generating deferred %d×%d preview for %s\n", sp->sizex, sp->sizey, path);
@@ -1464,34 +1408,28 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
ID *id = sp->id;
short idtype = GS(id->name);
- BLI_assert(id != NULL);
+ BLI_assert(id != nullptr);
if (idtype == ID_IM) {
Image *ima = (Image *)id;
- ImBuf *ibuf = NULL;
+ ImBuf *ibuf = nullptr;
ImageUser iuser;
BKE_imageuser_default(&iuser);
- if (ima == NULL) {
- return;
- }
-
- ImageTile *tile = BKE_image_get_tile(ima, 0);
- /* tile->ok is zero when Image cannot load */
- if (tile->ok == 0) {
+ if (ima == nullptr) {
return;
}
/* setup dummy image user */
- iuser.ok = iuser.framenr = 1;
+ iuser.framenr = 1;
iuser.scene = sp->scene;
- /* elubie: this needs to be changed: here image is always loaded if not
+ /* NOTE(@elubie): this needs to be changed: here image is always loaded if not
* already there. Very expensive for large images. Need to find a way to
- * only get existing ibuf */
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ * only get existing `ibuf`. */
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
+ if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) {
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
return;
}
@@ -1499,7 +1437,7 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
*do_update = true;
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
}
else if (idtype == ID_BR) {
Brush *br = (Brush *)id;
@@ -1543,7 +1481,7 @@ static void common_preview_startjob(void *customdata,
short *do_update,
float *UNUSED(progress))
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
if (ELEM(sp->pr_method, PR_ICON_RENDER, PR_ICON_DEFERRED)) {
icon_preview_startjob(customdata, stop, do_update);
@@ -1559,17 +1497,17 @@ static void common_preview_startjob(void *customdata,
*/
static void other_id_types_preview_render(IconPreview *ip,
IconPreviewSize *cur_size,
- const int pr_method,
+ const ePreviewRenderMethod pr_method,
short *stop,
short *do_update,
float *progress)
{
- ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
+ ShaderPreview *sp = MEM_cnew<ShaderPreview>("Icon ShaderPreview");
/* These types don't use the ShaderPreview mess, they have their own types and functions. */
BLI_assert(!ip->id || !ELEM(GS(ip->id->name), ID_OB));
- /* construct shader preview from image size and previewcustomdata */
+ /* Construct shader preview from image size and preview custom-data. */
sp->scene = ip->scene;
sp->owner = ip->owner;
sp->sizex = cur_size->sizex;
@@ -1580,7 +1518,7 @@ static void other_id_types_preview_render(IconPreview *ip,
sp->id_copy = ip->id_copy;
sp->bmain = ip->bmain;
sp->own_id_copy = false;
- Material *ma = NULL;
+ Material *ma = nullptr;
if (sp->pr_method == PR_ICON_RENDER) {
BLI_assert(ip->id);
@@ -1590,7 +1528,7 @@ static void other_id_types_preview_render(IconPreview *ip,
ma = (Material *)ip->id;
}
- if ((ma == NULL) || (ma->gp_style == NULL)) {
+ if ((ma == nullptr) || (ma->gp_style == nullptr)) {
sp->pr_main = G_pr_main;
}
else {
@@ -1628,10 +1566,12 @@ static void icon_preview_startjob_all_sizes(void *customdata,
IconPreview *ip = (IconPreview *)customdata;
IconPreviewSize *cur_size;
- for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) {
- PreviewImage *prv = ip->owner;
+ for (cur_size = static_cast<IconPreviewSize *>(ip->sizes.first); cur_size;
+ cur_size = cur_size->next) {
+ PreviewImage *prv = static_cast<PreviewImage *>(ip->owner);
/* Is this a render job or a deferred loading job? */
- const int pr_method = (prv->tag & PRV_TAG_DEFFERED) ? PR_ICON_DEFERRED : PR_ICON_RENDER;
+ const ePreviewRenderMethod pr_method = (prv->tag & PRV_TAG_DEFFERED) ? PR_ICON_DEFERRED :
+ PR_ICON_RENDER;
if (*stop) {
break;
@@ -1648,7 +1588,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
* they can skip this test. */
/* TODO: Decouple the ID-type-specific render functions from this function, so that it's not
* necessary to know here what happens inside lower-level functions. */
- const bool use_solid_render_mode = (ip->id != NULL) && ELEM(GS(ip->id->name), ID_OB, ID_AC);
+ const bool use_solid_render_mode = (ip->id != nullptr) && ELEM(GS(ip->id->name), ID_OB, ID_AC);
if (!use_solid_render_mode && preview_method_is_render(pr_method) &&
!check_engine_supports_preview(ip->scene)) {
continue;
@@ -1661,17 +1601,20 @@ static void icon_preview_startjob_all_sizes(void *customdata,
}
#endif
- if (ip->id != NULL) {
+ if (ip->id != nullptr) {
switch (GS(ip->id->name)) {
case ID_OB:
- /* Much simpler than the ShaderPreview mess used for other ID types. */
- object_preview_render(ip, cur_size);
- continue;
+ if (object_preview_is_type_supported((Object *)ip->id)) {
+ /* Much simpler than the ShaderPreview mess used for other ID types. */
+ object_preview_render(ip, cur_size);
+ continue;
+ }
+ break;
case ID_AC:
action_preview_render(ip, cur_size);
continue;
default:
- /* Fall through to the same code as the `ip->id == NULL` case. */
+ /* Fall through to the same code as the `ip->id == nullptr` case. */
break;
}
}
@@ -1681,7 +1624,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey)
{
- IconPreviewSize *cur_size = ip->sizes.first, *new_size;
+ IconPreviewSize *cur_size = static_cast<IconPreviewSize *>(ip->sizes.first);
while (cur_size) {
if (cur_size->sizex == sizex && cur_size->sizey == sizey) {
@@ -1692,7 +1635,7 @@ static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int si
cur_size = cur_size->next;
}
- new_size = MEM_callocN(sizeof(IconPreviewSize), "IconPreviewSize");
+ IconPreviewSize *new_size = MEM_cnew<IconPreviewSize>("IconPreviewSize");
new_size->sizex = sizex;
new_size->sizey = sizey;
new_size->rect = rect;
@@ -1702,7 +1645,7 @@ static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int si
static void icon_preview_endjob(void *customdata)
{
- IconPreview *ip = customdata;
+ IconPreview *ip = static_cast<IconPreview *>(customdata);
if (ip->id) {
@@ -1719,7 +1662,7 @@ static void icon_preview_endjob(void *customdata)
for (i = 0; i < NUM_ICON_SIZES; i++) {
if (prv_img->gputexture[i]) {
GPU_texture_free(prv_img->gputexture[i]);
- prv_img->gputexture[i] = NULL;
+ prv_img->gputexture[i] = nullptr;
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, ip->id);
}
}
@@ -1728,7 +1671,7 @@ static void icon_preview_endjob(void *customdata)
}
if (ip->owner) {
- PreviewImage *prv_img = ip->owner;
+ PreviewImage *prv_img = static_cast<PreviewImage *>(ip->owner);
prv_img->tag &= ~PRV_TAG_DEFFERED_RENDERING;
LISTBASE_FOREACH (IconPreviewSize *, icon_size, &ip->sizes) {
@@ -1755,10 +1698,25 @@ static void icon_preview_free(void *customdata)
MEM_freeN(ip);
}
+bool ED_preview_id_is_supported(const ID *id)
+{
+ if (id == nullptr) {
+ return false;
+ }
+ if (GS(id->name) == ID_NT) {
+ /* Node groups don't support standard preview generation. */
+ return false;
+ }
+ if (GS(id->name) == ID_OB) {
+ return object_preview_is_type_supported((const Object *)id);
+ }
+ return BKE_previewimg_id_get_p(id) != nullptr;
+}
+
void ED_preview_icon_render(
const bContext *C, Scene *scene, ID *id, uint *rect, int sizex, int sizey)
{
- IconPreview ip = {NULL};
+ IconPreview ip = {nullptr};
short stop = false, update = false;
float progress = 0.0f;
@@ -1781,7 +1739,7 @@ void ED_preview_icon_render(
icon_preview_endjob(&ip);
BLI_freelistN(&ip.sizes);
- if (ip.id_copy != NULL) {
+ if (ip.id_copy != nullptr) {
preview_id_copy_free(ip.id_copy);
}
}
@@ -1802,10 +1760,10 @@ void ED_preview_icon_job(
WM_JOB_EXCL_RENDER,
WM_JOB_TYPE_RENDER_PREVIEW);
- ip = MEM_callocN(sizeof(IconPreview), "icon preview");
+ ip = MEM_cnew<IconPreview>("icon preview");
/* render all resolutions from suspended job too */
- old_ip = WM_jobs_customdata_get(wm_job);
+ old_ip = static_cast<IconPreview *>(WM_jobs_customdata_get(wm_job));
if (old_ip) {
BLI_movelisttolist(&ip->sizes, &old_ip->sizes);
}
@@ -1824,7 +1782,7 @@ void ED_preview_icon_job(
/* Special threading hack:
* warn main code that this preview is being rendered and cannot be freed... */
{
- PreviewImage *prv_img = owner;
+ PreviewImage *prv_img = static_cast<PreviewImage *>(owner);
if (prv_img->tag & PRV_TAG_DEFFERED) {
prv_img->tag |= PRV_TAG_DEFFERED_RENDERING;
}
@@ -1837,7 +1795,8 @@ void ED_preview_icon_job(
* Particularly important for heavy scenes and Eevee using OpenGL that blocks
* the user interface drawing. */
WM_jobs_delay_start(wm_job, (delay) ? 2.0 : 0.0);
- WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob);
+ WM_jobs_callbacks(
+ wm_job, icon_preview_startjob_all_sizes, nullptr, nullptr, icon_preview_endjob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
@@ -1849,13 +1808,13 @@ void ED_preview_shader_job(const bContext *C,
MTex *slot,
int sizex,
int sizey,
- int method)
+ ePreviewRenderMethod method)
{
Object *ob = CTX_data_active_object(C);
wmJob *wm_job;
ShaderPreview *sp;
Scene *scene = CTX_data_scene(C);
- short id_type = GS(id->name);
+ const ID_Type id_type = GS(id->name);
BLI_assert(BKE_previewimg_id_supports_jobs(id));
@@ -1866,11 +1825,6 @@ void ED_preview_shader_job(const bContext *C,
return;
}
- /* Only texture node preview is supported with Cycles. */
- if (method == PR_NODE_RENDER && id_type != ID_TE) {
- return;
- }
-
ED_preview_ensure_dbase();
wm_job = WM_jobs_get(CTX_wm_manager(C),
@@ -1879,7 +1833,7 @@ void ED_preview_shader_job(const bContext *C,
"Shader Preview",
WM_JOB_EXCL_RENDER,
WM_JOB_TYPE_RENDER_PREVIEW);
- sp = MEM_callocN(sizeof(ShaderPreview), "shader preview");
+ sp = MEM_cnew<ShaderPreview>("shader preview");
/* customdata for preview thread */
sp->scene = scene;
@@ -1893,17 +1847,17 @@ void ED_preview_shader_job(const bContext *C,
sp->parent = parent;
sp->slot = slot;
sp->bmain = CTX_data_main(C);
- Material *ma = NULL;
+ Material *ma = nullptr;
/* hardcoded preview .blend for Eevee + Cycles, this should be solved
* once with custom preview .blend path for external engines */
/* grease pencil use its own preview file */
- if (GS(id->name) == ID_MA) {
+ if (id_type == ID_MA) {
ma = (Material *)id;
}
- if ((ma == NULL) || (ma->gp_style == NULL)) {
+ if ((ma == nullptr) || (ma->gp_style == nullptr)) {
sp->pr_main = G_pr_main;
}
else {
@@ -1920,7 +1874,7 @@ void ED_preview_shader_job(const bContext *C,
/* setup job */
WM_jobs_customdata_set(wm_job, sp, shader_preview_free);
WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL);
- WM_jobs_callbacks(wm_job, common_preview_startjob, NULL, shader_preview_updatejob, NULL);
+ WM_jobs_callbacks(wm_job, common_preview_startjob, nullptr, shader_preview_updatejob, nullptr);
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
@@ -1930,8 +1884,49 @@ void ED_preview_kill_jobs(wmWindowManager *wm, Main *UNUSED(bmain))
if (wm) {
/* This is called to stop all preview jobs before scene data changes, to
* avoid invalid memory access. */
- WM_jobs_kill(wm, NULL, common_preview_startjob);
- WM_jobs_kill(wm, NULL, icon_preview_startjob_all_sizes);
+ WM_jobs_kill(wm, nullptr, common_preview_startjob);
+ WM_jobs_kill(wm, nullptr, icon_preview_startjob_all_sizes);
+ }
+}
+
+struct PreviewRestartQueueEntry {
+ struct PreviewRestartQueueEntry *next, *prev;
+
+ enum eIconSizes size;
+ ID *id;
+};
+
+static ListBase /* #PreviewRestartQueueEntry */ G_restart_previews_queue;
+
+void ED_preview_restart_queue_free()
+{
+ BLI_freelistN(&G_restart_previews_queue);
+}
+
+void ED_preview_restart_queue_add(ID *id, enum eIconSizes size)
+{
+ PreviewRestartQueueEntry *queue_entry = MEM_new<PreviewRestartQueueEntry>(__func__);
+ queue_entry->size = size;
+ queue_entry->id = id;
+ BLI_addtail(&G_restart_previews_queue, queue_entry);
+}
+
+void ED_preview_restart_queue_work(const bContext *C)
+{
+ LISTBASE_FOREACH_MUTABLE (PreviewRestartQueueEntry *, queue_entry, &G_restart_previews_queue) {
+ PreviewImage *preview = BKE_previewimg_id_get(queue_entry->id);
+ if (!preview) {
+ continue;
+ }
+ if (preview->flag[queue_entry->size] & PRV_USER_EDITED) {
+ /* Don't touch custom previews. */
+ continue;
+ }
+
+ BKE_previewimg_clear_single(preview, queue_entry->size);
+ UI_icon_render_id(C, nullptr, queue_entry->id, queue_entry->size, true);
+
+ BLI_freelinkN(&G_restart_previews_queue, queue_entry);
}
}
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.cc
index 7b2667905ff..19ab6841e22 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.cc
@@ -20,8 +20,8 @@
* \ingroup edrend
*/
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -48,7 +48,6 @@
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_editmesh.h"
-#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_layer.h"
@@ -61,9 +60,12 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
+#include "BKE_vfont.h"
#include "BKE_workspace.h"
#include "BKE_world.h"
+#include "NOD_composite.h"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -96,7 +98,7 @@
#include "engines/eevee/eevee_lightcache.h"
-#include "render_intern.h" /* own include */
+#include "render_intern.hh" /* own include */
static bool object_materials_supported_poll_ex(bContext *C, const Object *ob);
@@ -106,7 +108,7 @@ static bool object_materials_supported_poll_ex(bContext *C, const Object *ob);
static bool object_array_for_shading_edit_mode_enabled_filter(const Object *ob, void *user_data)
{
- bContext *C = user_data;
+ bContext *C = static_cast<bContext *>(user_data);
if (object_materials_supported_poll_ex(C, ob)) {
if (BKE_object_is_in_editmode(ob) == true) {
return true;
@@ -123,7 +125,7 @@ static Object **object_array_for_shading_edit_mode_enabled(bContext *C, uint *r_
static bool object_array_for_shading_edit_mode_disabled_filter(const Object *ob, void *user_data)
{
- bContext *C = user_data;
+ bContext *C = static_cast<bContext *>(user_data);
if (object_materials_supported_poll_ex(C, ob)) {
if (BKE_object_is_in_editmode(ob) == false) {
return true;
@@ -159,7 +161,7 @@ static bool object_materials_supported_poll_ex(bContext *C, const Object *ob)
}
/* Material linked to obdata. */
- const ID *data = ob->data;
+ const ID *data = static_cast<ID *>(ob->data);
return (data && !ID_IS_LINKED(data) && !ID_IS_OVERRIDE_LIBRARY(data));
}
@@ -188,8 +190,8 @@ static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
- ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr);
}
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@@ -238,8 +240,8 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op)
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
- ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr);
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
@@ -277,7 +279,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
bool changed_multi = false;
Object *obact = CTX_data_active_object(C);
- const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL;
+ const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : nullptr;
uint objects_len = 0;
Object **objects = object_array_for_shading_edit_mode_enabled(C, &objects_len);
@@ -328,7 +330,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
ListBase *nurbs = BKE_curve_editNurbs_get((Curve *)ob->data);
if (nurbs) {
- for (nu = nurbs->first; nu; nu = nu->next) {
+ for (nu = static_cast<Nurb *>(nurbs->first); nu; nu = nu->next) {
if (ED_curve_nurb_select_check(v3d, nu)) {
changed = true;
nu->mat_nr = mat_nr_active;
@@ -384,7 +386,7 @@ static int material_slot_de_select(bContext *C, bool select)
{
bool changed_multi = false;
Object *obact = CTX_data_active_object(C);
- const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL;
+ const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : nullptr;
uint objects_len = 0;
Object **objects = object_array_for_shading_edit_mode_enabled(C, &objects_len);
@@ -432,7 +434,7 @@ static int material_slot_de_select(bContext *C, bool select)
int a;
if (nurbs) {
- for (nu = nurbs->first; nu; nu = nu->next) {
+ for (nu = static_cast<Nurb *>(nurbs->first); nu; nu = nu->next) {
if (nu->mat_nr == mat_nr_active) {
if (nu->bezt) {
a = nu->pntsu;
@@ -477,7 +479,7 @@ static int material_slot_de_select(bContext *C, bool select)
if (changed) {
changed_multi = true;
- DEG_id_tag_update(ob->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
}
}
@@ -545,7 +547,8 @@ static int material_slot_copy_exec(bContext *C, wmOperator *UNUSED(op))
Material ***matar_object = &ob->mat;
- Material **matar = MEM_callocN(sizeof(*matar) * (size_t)ob->totcol, __func__);
+ Material **matar = static_cast<Material **>(
+ MEM_callocN(sizeof(*matar) * (size_t)ob->totcol, __func__));
for (int i = ob->totcol; i--;) {
matar[i] = ob->matbits[i] ? (*matar_object)[i] : (*matar_obdata)[i];
}
@@ -620,7 +623,7 @@ static int material_slot_move_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- slot_remap = MEM_mallocN(sizeof(uint) * ob->totcol, __func__);
+ slot_remap = static_cast<uint *>(MEM_mallocN(sizeof(uint) * ob->totcol, __func__));
range_vn_u(slot_remap, ob->totcol, 0);
@@ -643,7 +646,7 @@ void OBJECT_OT_material_slot_move(wmOperatorType *ot)
static const EnumPropertyItem material_slot_move[] = {
{1, "UP", 0, "Up", ""},
{-1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -715,8 +718,8 @@ static int material_slot_remove_unused_exec(bContext *C, wmOperator *op)
if (ob_active->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
- ED_paint_proj_mesh_data_check(scene, ob_active, NULL, NULL, NULL, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob_active, nullptr, nullptr, nullptr, nullptr);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr);
}
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_active);
@@ -749,7 +752,8 @@ void OBJECT_OT_material_slot_remove_unused(wmOperatorType *ot)
static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
{
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
Main *bmain = CTX_data_main(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
@@ -757,17 +761,18 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
/* hook into UI */
UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
- Object *ob = (prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : NULL;
+ Object *ob = static_cast<Object *>((prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data :
+ nullptr);
/* add or copy material */
if (ma) {
Material *new_ma = (Material *)BKE_id_copy_ex(
- bmain, &ma->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
+ bmain, &ma->id, nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
ma = new_ma;
}
else {
const char *name = DATA_("Material");
- if (!(ob != NULL && ob->type == OB_GPENCIL)) {
+ if (!(ob != nullptr && ob->type == OB_GPENCIL)) {
ma = BKE_material_add(bmain, name);
}
else {
@@ -778,10 +783,10 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
}
if (prop) {
- if (ob != NULL) {
+ if (ob != nullptr) {
/* Add slot follows user-preferences for creating new slots,
* RNA pointer assignment doesn't, see: T60014. */
- if (BKE_object_material_get_p(ob, ob->actcol) == NULL) {
+ if (BKE_object_material_get_p(ob, ob->actcol) == nullptr) {
BKE_object_material_slot_add(bmain, ob);
}
}
@@ -791,7 +796,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
id_us_min(&ma->id);
RNA_id_pointer_create(&ma->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr, NULL);
+ RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
RNA_property_update(C, &ptr, prop);
}
@@ -823,7 +828,7 @@ void MATERIAL_OT_new(wmOperatorType *ot)
static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
{
- Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
+ Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data);
Main *bmain = CTX_data_main(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
@@ -845,7 +850,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
id_us_min(&tex->id);
RNA_id_pointer_create(&tex->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr, NULL);
+ RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
RNA_property_update(C, &ptr, prop);
}
@@ -876,7 +881,7 @@ void TEXTURE_OT_new(wmOperatorType *ot)
static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
{
- World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data;
+ World *wo = static_cast<World *>(CTX_data_pointer_get_type(C, "world", &RNA_World).data);
Main *bmain = CTX_data_main(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
@@ -884,7 +889,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
/* add or copy world */
if (wo) {
World *new_wo = (World *)BKE_id_copy_ex(
- bmain, &wo->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
+ bmain, &wo->id, nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
wo = new_wo;
}
else {
@@ -902,7 +907,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
id_us_min(&wo->id);
RNA_id_pointer_create(&wo->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr, NULL);
+ RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
RNA_property_update(C, &ptr, prop);
}
@@ -960,7 +965,7 @@ void SCENE_OT_view_layer_add(wmOperatorType *ot)
0,
"Blank",
"Add a new view layer with all collections disabled"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -997,7 +1002,7 @@ static int view_layer_remove_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- if (!ED_scene_view_layer_delete(bmain, scene, view_layer, NULL)) {
+ if (!ED_scene_view_layer_delete(bmain, scene, view_layer, nullptr)) {
return OPERATOR_CANCELLED;
}
@@ -1041,7 +1046,7 @@ static int view_layer_add_aov_exec(bContext *C, wmOperator *UNUSED(op))
BKE_view_layer_verify_aov(engine, scene, view_layer);
}
RE_engine_free(engine);
- engine = NULL;
+ engine = nullptr;
}
if (scene->nodetree) {
@@ -1080,7 +1085,7 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- if (view_layer->active_aov == NULL) {
+ if (view_layer->active_aov == nullptr) {
return OPERATOR_FINISHED;
}
@@ -1093,7 +1098,7 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op))
BKE_view_layer_verify_aov(engine, scene, view_layer);
}
RE_engine_free(engine);
- engine = NULL;
+ engine = nullptr;
}
if (scene->nodetree) {
@@ -1135,7 +1140,7 @@ enum {
static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op)
{
- if (scene->eevee.light_cache_data != NULL) {
+ if (scene->eevee.light_cache_data != nullptr) {
int subset = RNA_enum_get(op->ptr, "subset");
switch (subset) {
case LIGHTCACHE_SUBSET_ALL:
@@ -1261,7 +1266,7 @@ void SCENE_OT_light_cache_bake(wmOperatorType *ot)
0,
"Cubemaps Only",
"Try to only bake reflection cubemaps if irradiance grids are up to date"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -1317,7 +1322,7 @@ static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op))
}
EEVEE_lightcache_free(scene->eevee.light_cache_data);
- scene->eevee.light_cache_data = NULL;
+ scene->eevee.light_cache_data = nullptr;
EEVEE_lightcache_info_update(&scene->eevee);
@@ -1358,7 +1363,7 @@ static int render_view_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- BKE_scene_add_render_view(scene, NULL);
+ BKE_scene_add_render_view(scene, nullptr);
scene->r.actview = BLI_listbase_count(&scene->r.views) - 1;
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
@@ -1389,7 +1394,8 @@ void SCENE_OT_render_view_add(wmOperatorType *ot)
static int render_view_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- SceneRenderView *rv = BLI_findlink(&scene->r.views, scene->r.actview);
+ SceneRenderView *rv = static_cast<SceneRenderView *>(
+ BLI_findlink(&scene->r.views, scene->r.actview));
if (!BKE_scene_remove_render_view(scene, rv)) {
return OPERATOR_CANCELLED;
@@ -1444,9 +1450,9 @@ static bool freestyle_linestyle_check_report(FreestyleLineSet *lineset, ReportLi
static bool freestyle_active_module_poll(bContext *C)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
- FreestyleModuleConfig *module = ptr.data;
+ FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data);
- return module != NULL;
+ return module != nullptr;
}
static int freestyle_module_add_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1486,7 +1492,7 @@ static int freestyle_module_remove_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
- FreestyleModuleConfig *module = ptr.data;
+ FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data);
BKE_freestyle_module_delete(&view_layer->freestyle_config, module);
@@ -1516,7 +1522,7 @@ static int freestyle_module_move_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
- FreestyleModuleConfig *module = ptr.data;
+ FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data);
int dir = RNA_enum_get(op->ptr, "direction");
if (BKE_freestyle_module_move(&view_layer->freestyle_config, module, dir)) {
@@ -1538,7 +1544,7 @@ void SCENE_OT_freestyle_module_move(wmOperatorType *ot)
static const EnumPropertyItem direction_items[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -1574,7 +1580,7 @@ static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, NULL);
+ BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, nullptr);
DEG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
@@ -1610,7 +1616,7 @@ static bool freestyle_active_lineset_poll(bContext *C)
return false;
}
- return BKE_freestyle_lineset_get_active(&view_layer->freestyle_config) != NULL;
+ return BKE_freestyle_lineset_get_active(&view_layer->freestyle_config) != nullptr;
}
static int freestyle_lineset_copy_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1730,7 +1736,7 @@ void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot)
static const EnumPropertyItem direction_items[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -1814,7 +1820,7 @@ static int freestyle_color_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_color_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_color_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown line color modifier type");
return OPERATOR_CANCELLED;
}
@@ -1861,7 +1867,7 @@ static int freestyle_alpha_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown alpha transparency modifier type");
return OPERATOR_CANCELLED;
}
@@ -1908,7 +1914,7 @@ static int freestyle_thickness_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown line thickness modifier type");
return OPERATOR_CANCELLED;
}
@@ -1955,7 +1961,7 @@ static int freestyle_geometry_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown stroke geometry modifier type");
return OPERATOR_CANCELLED;
}
@@ -2014,7 +2020,7 @@ static int freestyle_modifier_remove_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
- LineStyleModifier *modifier = ptr.data;
+ LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data);
if (!freestyle_linestyle_check_report(lineset, op->reports)) {
return OPERATOR_CANCELLED;
@@ -2070,7 +2076,7 @@ static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
- LineStyleModifier *modifier = ptr.data;
+ LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data);
if (!freestyle_linestyle_check_report(lineset, op->reports)) {
return OPERATOR_CANCELLED;
@@ -2126,7 +2132,7 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
- LineStyleModifier *modifier = ptr.data;
+ LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data);
int dir = RNA_enum_get(op->ptr, "direction");
bool changed = false;
@@ -2166,7 +2172,7 @@ void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot)
static const EnumPropertyItem direction_items[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -2226,10 +2232,10 @@ void SCENE_OT_freestyle_stroke_material_create(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-#endif /* WITH_FREESTYLE */
-
/** \} */
+#endif /* WITH_FREESTYLE */
+
/* -------------------------------------------------------------------- */
/** \name Texture Slot Move Operator
* \{ */
@@ -2252,9 +2258,12 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op)
mtex_ar[act] = mtex_ar[act - 1];
mtex_ar[act - 1] = mtexswap;
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act - 1, -1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act - 1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act - 1, -1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act, act - 1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, -1, act, false);
set_active_mtex(id, act - 1);
}
@@ -2265,9 +2274,12 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op)
mtex_ar[act] = mtex_ar[act + 1];
mtex_ar[act + 1] = mtexswap;
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act + 1, -1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act + 1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act + 1, -1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act, act + 1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, -1, act, false);
set_active_mtex(id, act + 1);
}
@@ -2285,7 +2297,7 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot)
static const EnumPropertyItem slot_move[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -2311,9 +2323,10 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot)
/* material copy/paste */
static int copy_material_exec(bContext *C, wmOperator *UNUSED(op))
{
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
- if (ma == NULL) {
+ if (ma == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2345,9 +2358,10 @@ void MATERIAL_OT_copy(wmOperatorType *ot)
static int paste_material_exec(bContext *C, wmOperator *UNUSED(op))
{
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
- if (ma == NULL) {
+ if (ma == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2382,14 +2396,14 @@ void MATERIAL_OT_paste(wmOperatorType *ot)
static short mtexcopied = 0; /* must be reset on file load */
static MTex mtexcopybuf;
-void ED_render_clear_mtex_copybuf(void)
+void ED_render_clear_mtex_copybuf()
{ /* use for file reload */
mtexcopied = 0;
}
static void copy_mtex_copybuf(ID *id)
{
- MTex **mtex = NULL;
+ MTex **mtex = nullptr;
switch (GS(id->name)) {
case ID_PA:
@@ -2413,9 +2427,9 @@ static void copy_mtex_copybuf(ID *id)
static void paste_mtex_copybuf(ID *id)
{
- MTex **mtex = NULL;
+ MTex **mtex = nullptr;
- if (mtexcopied == 0 || mtexcopybuf.tex == NULL) {
+ if (mtexcopied == 0 || mtexcopybuf.tex == nullptr) {
return;
}
@@ -2432,8 +2446,8 @@ static void paste_mtex_copybuf(ID *id)
}
if (mtex) {
- if (*mtex == NULL) {
- *mtex = MEM_mallocN(sizeof(MTex), "mtex copy");
+ if (*mtex == nullptr) {
+ *mtex = MEM_new<MTex>("mtex copy");
}
else if ((*mtex)->tex) {
id_us_min(&(*mtex)->tex->id);
@@ -2455,7 +2469,7 @@ static int copy_mtex_exec(bContext *C, wmOperator *UNUSED(op))
{
ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id;
- if (id == NULL) {
+ if (id == nullptr) {
/* copying empty slot */
ED_render_clear_mtex_copybuf();
return OPERATOR_CANCELLED;
@@ -2470,7 +2484,7 @@ static bool copy_mtex_poll(bContext *C)
{
ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id;
- return (id != NULL);
+ return (id != nullptr);
}
void TEXTURE_OT_slot_copy(wmOperatorType *ot)
@@ -2499,14 +2513,15 @@ static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op))
{
ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id;
- if (id == NULL) {
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
- Light *la = CTX_data_pointer_get_type(C, "light", &RNA_Light).data;
- World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data;
- ParticleSystem *psys =
- CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
- FreestyleLineStyle *linestyle =
- CTX_data_pointer_get_type(C, "line_style", &RNA_FreestyleLineStyle).data;
+ if (id == nullptr) {
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
+ Light *la = static_cast<Light *>(CTX_data_pointer_get_type(C, "light", &RNA_Light).data);
+ World *wo = static_cast<World *>(CTX_data_pointer_get_type(C, "world", &RNA_World).data);
+ ParticleSystem *psys = static_cast<ParticleSystem *>(
+ CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data);
+ FreestyleLineStyle *linestyle = static_cast<FreestyleLineStyle *>(
+ CTX_data_pointer_get_type(C, "line_style", &RNA_FreestyleLineStyle).data);
if (ma) {
id = &ma->id;
@@ -2524,14 +2539,14 @@ static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op))
id = &linestyle->id;
}
- if (id == NULL) {
+ if (id == nullptr) {
return OPERATOR_CANCELLED;
}
}
paste_mtex_copybuf(id);
- WM_event_add_notifier(C, NC_TEXTURE | ND_SHADING_LINKS, NULL);
+ WM_event_add_notifier(C, NC_TEXTURE | ND_SHADING_LINKS, nullptr);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.cc
index 8bc2281db73..b1e8e3927ef 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.cc
@@ -20,8 +20,8 @@
* \ingroup edrend
*/
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
#include "DNA_cachefile_types.h"
#include "DNA_light_types.h"
@@ -49,6 +49,8 @@
#include "BKE_paint.h"
#include "BKE_scene.h"
+#include "NOD_composite.h"
+
#include "RE_engine.h"
#include "RE_pipeline.h"
@@ -62,13 +64,12 @@
#include "WM_api.h"
-#include <stdio.h>
+#include <cstdio>
/* -------------------------------------------------------------------- */
/** \name Render Engines
* \{ */
-/* Update 3D viewport render or draw engine on changes to the scene or view settings. */
void ED_render_view3d_update(Depsgraph *depsgraph,
wmWindow *window,
ScrArea *area,
@@ -83,8 +84,8 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
continue;
}
- View3D *v3d = area->spacedata.first;
- RegionView3D *rv3d = region->regiondata;
+ View3D *v3d = static_cast<View3D *>(area->spacedata.first);
+ RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
RenderEngine *engine = rv3d->render_engine;
/* call update if the scene changed, or if the render engine
@@ -95,7 +96,7 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
bContext *C = CTX_create();
CTX_data_main_set(C, bmain);
CTX_data_scene_set(C, scene);
- CTX_wm_manager_set(C, bmain->wm.first);
+ CTX_wm_manager_set(C, static_cast<wmWindowManager *>(bmain->wm.first));
CTX_wm_window_set(C, window);
CTX_wm_screen_set(C, WM_window_get_active_screen(window));
CTX_wm_area_set(C, area);
@@ -112,22 +113,20 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
else {
RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
if (updated) {
- DRW_notify_view_update((&(DRWUpdateContext){
- .bmain = bmain,
- .depsgraph = depsgraph,
- .scene = scene,
- .view_layer = view_layer,
- .region = region,
- .v3d = v3d,
- .engine_type = engine_type,
- }));
+ DRWUpdateContext drw_context = {nullptr};
+ drw_context.bmain = bmain;
+ drw_context.depsgraph = depsgraph;
+ drw_context.scene = scene;
+ drw_context.view_layer = view_layer;
+ drw_context.region = region;
+ drw_context.v3d = v3d;
+ drw_context.engine_type = engine_type;
+ DRW_notify_view_update(&drw_context);
}
}
}
}
-/* Update all 3D viewport render and draw engines on changes to the scene.
- * This is called by the dependency graph when it detects changes. */
void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, const bool updated)
{
Main *bmain = update_ctx->bmain;
@@ -151,7 +150,7 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, const bool
recursive_check = true;
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(window);
@@ -169,13 +168,13 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *area)
{
/* clear all render engines in this area */
ARegion *region;
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
if (area->spacetype != SPACE_VIEW3D) {
return;
}
- for (region = area->regionbase.first; region; region = region->next) {
+ for (region = static_cast<ARegion *>(area->regionbase.first); region; region = region->next) {
if (region->regiontype != RGN_TYPE_WINDOW || !(region->regiondata)) {
continue;
}
@@ -186,16 +185,18 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *area)
void ED_render_engine_changed(Main *bmain, const bool update_scene_data)
{
/* on changing the render engine type, clear all running render engines */
- for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = static_cast<bScreen *>(bmain->screens.first); screen;
+ screen = static_cast<bScreen *>(screen->id.next)) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
ED_render_engine_area_exit(bmain, area);
}
}
- RE_FreePersistentData(NULL);
+ RE_FreePersistentData(nullptr);
/* Inform all render engines and draw managers. */
- DEGEditorUpdateContext update_ctx = {NULL};
+ DEGEditorUpdateContext update_ctx = {nullptr};
update_ctx.bmain = bmain;
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ for (Scene *scene = static_cast<Scene *>(bmain->scenes.first); scene;
+ scene = static_cast<Scene *>(scene->id.next)) {
update_ctx.scene = scene;
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
/* TDODO(sergey): Iterate over depsgraphs instead? */
@@ -261,14 +262,16 @@ static void texture_changed(Main *bmain, Tex *tex)
/* icons */
BKE_icon_changed(BKE_icon_id_ensure(&tex->id));
- for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ for (scene = static_cast<Scene *>(bmain->scenes.first); scene;
+ scene = static_cast<Scene *>(scene->id.next)) {
/* paint overlays */
- for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (view_layer = static_cast<ViewLayer *>(scene->view_layers.first); view_layer;
+ view_layer = view_layer->next) {
BKE_paint_invalidate_overlay_tex(scene, view_layer, tex);
}
/* find compositing nodes */
if (scene->use_nodes && scene->nodetree) {
- for (node = scene->nodetree->nodes.first; node; node = node->next) {
+ for (node = static_cast<bNode *>(scene->nodetree->nodes.first); node; node = node->next) {
if (node->id == &tex->id) {
ED_node_tag_update_id(&scene->id);
}
@@ -291,7 +294,8 @@ static void image_changed(Main *bmain, Image *ima)
BKE_icon_changed(BKE_icon_id_ensure(&ima->id));
/* textures */
- for (tex = bmain->textures.first; tex; tex = tex->id.next) {
+ for (tex = static_cast<Tex *>(bmain->textures.first); tex;
+ tex = static_cast<Tex *>(tex->id.next)) {
if (tex->type == TEX_IMAGE && tex->ima == ima) {
texture_changed(bmain, tex);
}
@@ -303,10 +307,11 @@ static void scene_changed(Main *bmain, Scene *scene)
Object *ob;
/* glsl */
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ for (ob = static_cast<Object *>(bmain->objects.first); ob;
+ ob = static_cast<Object *>(ob->id.next)) {
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
BKE_texpaint_slots_refresh_object(scene, ob);
- ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr);
}
}
}
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.cc
index 97ecb67d6cc..980cd899120 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.cc
@@ -21,8 +21,8 @@
* \ingroup edrend
*/
-#include <stddef.h>
-#include <string.h>
+#include <cstddef>
+#include <cstring>
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -47,7 +47,7 @@
#include "wm_window.h"
-#include "render_intern.h"
+#include "render_intern.hh"
/*********************** utilities for finding areas *************************/
@@ -59,11 +59,11 @@
static ScrArea *biggest_non_image_area(bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area, *big = NULL;
+ ScrArea *area, *big = nullptr;
int size, maxsize = 0, bwmaxsize = 0;
short foundwin = 0;
- for (area = screen->areabase.first; area; area = area->next) {
+ for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) {
if (area->winx > 30 && area->winy > 30) {
size = area->winx * area->winy;
if (!area->full && area->spacetype == SPACE_PROPERTIES) {
@@ -86,17 +86,17 @@ static ScrArea *biggest_non_image_area(bContext *C)
static ScrArea *find_area_showing_r_result(bContext *C, Scene *scene, wmWindow **win)
{
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *area = NULL;
+ ScrArea *area = nullptr;
SpaceImage *sima;
/* find an imagewindow showing render result */
- for (*win = wm->windows.first; *win; *win = (*win)->next) {
+ for (*win = static_cast<wmWindow *>(wm->windows.first); *win; *win = (*win)->next) {
if (WM_window_get_active_scene(*win) == scene) {
const bScreen *screen = WM_window_get_active_screen(*win);
- for (area = screen->areabase.first; area; area = area->next) {
+ for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) {
if (area->spacetype == SPACE_IMAGE) {
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) {
break;
}
@@ -118,9 +118,9 @@ static ScrArea *find_area_image_empty(bContext *C)
SpaceImage *sima;
/* find an imagewindow showing render result */
- for (area = screen->areabase.first; area; area = area->next) {
+ for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) {
if (area->spacetype == SPACE_IMAGE) {
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
if ((sima->mode == SI_MODE_VIEW) && !sima->image) {
break;
}
@@ -132,18 +132,17 @@ static ScrArea *find_area_image_empty(bContext *C)
/********************** open image editor for render *************************/
-/* new window uses x,y to set position */
ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- wmWindow *win = NULL;
- ScrArea *area = NULL;
+ wmWindow *win = nullptr;
+ ScrArea *area = nullptr;
SpaceImage *sima;
bool area_was_image = false;
if (U.render_display_type == USER_RENDER_DISPLAY_NONE) {
- return NULL;
+ return nullptr;
}
if (U.render_display_type == USER_RENDER_DISPLAY_WINDOW) {
@@ -169,24 +168,24 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
true,
false,
true,
- WIN_ALIGN_LOCATION_CENTER) == NULL) {
+ WIN_ALIGN_LOCATION_CENTER) == nullptr) {
BKE_report(reports, RPT_ERROR, "Failed to open window!");
- return NULL;
+ return nullptr;
}
area = CTX_wm_area(C);
if (BLI_listbase_is_single(&area->spacedata) == false) {
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
sima->flag |= SI_PREVSPACE;
}
}
else if (U.render_display_type == USER_RENDER_DISPLAY_SCREEN) {
area = CTX_wm_area(C);
- /* if the active screen is already in fullscreen mode, skip this and
- * unset the area, so that the fullscreen area is just changed later */
+ /* If the active screen is already in full-screen mode, skip this and
+ * unset the area, so that the full-screen area is just changed later. */
if (area && area->full) {
- area = NULL;
+ area = nullptr;
}
else {
if (area && area->spacetype == SPACE_IMAGE) {
@@ -200,7 +199,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
if (!area) {
area = find_area_showing_r_result(C, scene, &win);
- if (area == NULL) {
+ if (area == nullptr) {
area = find_area_image_empty(C);
}
@@ -209,17 +208,17 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
wm_window_raise(win);
}
- if (area == NULL) {
+ if (area == nullptr) {
/* find largest open non-image area */
area = biggest_non_image_area(C);
if (area) {
ED_area_newspace(C, area, SPACE_IMAGE, true);
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
- /* makes ESC go back to prev space */
+ /* Makes "Escape" go back to previous space. */
sima->flag |= SI_PREVSPACE;
- /* we already had a fullscreen here -> mark new space as a stacked fullscreen */
+ /* We already had a full-screen here -> mark new space as a stacked full-screen. */
if (area->full) {
area->flag |= AREA_FLAG_STACKED_FULLSCREEN;
}
@@ -229,15 +228,15 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0);
if (area->spacetype != SPACE_IMAGE) {
// XXX newspace(area, SPACE_IMAGE);
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
- /* makes ESC go back to prev space */
+ /* Makes "Escape" go back to previous space. */
sima->flag |= SI_PREVSPACE;
}
}
}
}
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
sima->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
/* get the correct image, and scale it */
@@ -273,9 +272,9 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
- /* ensure image editor fullscreen and area fullscreen states are in sync */
+ /* ensure image editor full-screen and area full-screen states are in sync */
if ((sima->flag & SI_FULLWINDOW) && !area->full) {
sima->flag &= ~SI_FULLWINDOW;
}
@@ -334,7 +333,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
ScrArea *area = find_area_showing_r_result(C, CTX_data_scene(C), &winshow);
/* is there another window on current scene showing result? */
- for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) {
+ for (win = static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first); win; win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
if ((WM_window_is_temp_screen(win) &&
@@ -349,7 +348,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
if (area) {
/* but don't close it when rendering */
if (G.is_rendering == false) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
if (sima->flag & SI_PREVSPACE) {
sima->flag &= ~SI_PREVSPACE;
@@ -365,7 +364,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
}
}
else {
- render_view_open(C, event->x, event->y, op->reports);
+ render_view_open(C, event->xy[0], event->xy[1], op->reports);
}
}
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index 5195bc8303a..555ffbfd5e7 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -77,10 +77,6 @@ Scene *ED_scene_add(Main *bmain, bContext *C, wmWindow *win, eSceneCopyMethod me
return scene_new;
}
-/**
- * \note Only call outside of area/region loops
- * \return true if successful
- */
bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene)
{
Scene *scene_new;
@@ -113,7 +109,6 @@ bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene)
return true;
}
-/* Depsgraph updates after scene becomes active in a window. */
void ED_scene_change_update(Main *bmain, Scene *scene, ViewLayer *layer)
{
Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, layer);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index d791c0717be..c6834c84794 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -134,13 +134,12 @@ static void region_draw_emboss(const ARegion *region, const rcti *scirct, int si
GPU_blend(GPU_BLEND_NONE);
}
-void ED_region_pixelspace(ARegion *region)
+void ED_region_pixelspace(const ARegion *region)
{
wmOrtho2_region_pixelspace(region);
GPU_matrix_identity_set();
}
-/* only exported for WM */
void ED_region_do_listen(wmRegionListenerParams *params)
{
ARegion *region = params->region;
@@ -169,7 +168,6 @@ void ED_region_do_listen(wmRegionListenerParams *params)
}
}
-/* only exported for WM */
void ED_area_do_listen(wmSpaceTypeListenerParams *params)
{
/* no generic notes? */
@@ -178,7 +176,6 @@ void ED_area_do_listen(wmSpaceTypeListenerParams *params)
}
}
-/* only exported for WM */
void ED_area_do_refresh(bContext *C, ScrArea *area)
{
/* no generic notes? */
@@ -443,7 +440,6 @@ void ED_area_do_msg_notify_tag_refresh(
ED_area_tag_refresh(area);
}
-/* Follow ARegionType.message_subscribe */
void ED_area_do_mgs_subscribe_for_tool_header(const wmRegionMessageSubscribeParams *params)
{
struct wmMsgBus *mbus = params->message_bus;
@@ -507,7 +503,6 @@ static bool area_is_pseudo_minimized(const ScrArea *area)
return (area->winx < 3) || (area->winy < 3);
}
-/* only exported for WM */
void ED_region_do_layout(bContext *C, ARegion *region)
{
/* This is optional, only needed for dynamically sized regions. */
@@ -531,7 +526,6 @@ void ED_region_do_layout(bContext *C, ARegion *region)
region->flag &= ~RGN_FLAG_SEARCH_FILTER_UPDATE;
}
-/* only exported for WM */
void ED_region_do_draw(bContext *C, ARegion *region)
{
wmWindow *win = CTX_wm_window(C);
@@ -594,7 +588,7 @@ void ED_region_do_draw(bContext *C, ARegion *region)
memset(&region->drawrct, 0, sizeof(region->drawrct));
- UI_blocklist_free_inactive(C, &region->uiblocks);
+ UI_blocklist_free_inactive(C, region);
if (area) {
const bScreen *screen = WM_window_get_active_screen(win);
@@ -705,10 +699,6 @@ void ED_region_tag_refresh_ui(ARegion *region)
}
}
-/**
- * Tag editor overlays to be redrawn. If in doubt about which parts need to be redrawn (partial
- * clipping rectangle set), redraw everything.
- */
void ED_region_tag_redraw_editor_overlays(struct ARegion *region)
{
if (region && !(region->do_draw & (RGN_DRAWING | RGN_DRAW))) {
@@ -786,9 +776,6 @@ void ED_area_tag_refresh(ScrArea *area)
/* *************************************************************** */
-/**
- * Returns the search string if the space type and region type support property search.
- */
const char *ED_area_region_search_filter_get(const ScrArea *area, const ARegion *region)
{
/* Only the properties editor has a search string for now. */
@@ -802,9 +789,6 @@ const char *ED_area_region_search_filter_get(const ScrArea *area, const ARegion
return NULL;
}
-/**
- * Set the temporary update flag for property search.
- */
void ED_region_search_filter_update(const ScrArea *area, ARegion *region)
{
region->flag |= RGN_FLAG_SEARCH_FILTER_UPDATE;
@@ -817,7 +801,6 @@ void ED_region_search_filter_update(const ScrArea *area, ARegion *region)
/* *************************************************************** */
-/* use NULL to disable it */
void ED_area_status_text(ScrArea *area, const char *str)
{
/* happens when running transform operators in background mode */
@@ -972,29 +955,33 @@ static void fullscreen_azone_init(ScrArea *area, ARegion *region)
#define AZONEPAD_ICON (0.45f * U.widget_unit)
static void region_azone_edge(AZone *az, ARegion *region)
{
+ /* If region is overlapped (transparent background), move #AZone to content.
+ * Note this is an arbitrary amount that matches nicely with numbers elsewhere. */
+ int overlap_padding = (region->overlap) ? (int)(0.4f * U.widget_unit) : 0;
+
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
az->x1 = region->winrct.xmin;
- az->y1 = region->winrct.ymax - AZONEPAD_EDGE;
+ az->y1 = region->winrct.ymax - AZONEPAD_EDGE - overlap_padding;
az->x2 = region->winrct.xmax;
- az->y2 = region->winrct.ymax + AZONEPAD_EDGE;
+ az->y2 = region->winrct.ymax + AZONEPAD_EDGE - overlap_padding;
break;
case AE_BOTTOM_TO_TOPLEFT:
az->x1 = region->winrct.xmin;
- az->y1 = region->winrct.ymin + AZONEPAD_EDGE;
+ az->y1 = region->winrct.ymin + AZONEPAD_EDGE + overlap_padding;
az->x2 = region->winrct.xmax;
- az->y2 = region->winrct.ymin - AZONEPAD_EDGE;
+ az->y2 = region->winrct.ymin - AZONEPAD_EDGE + overlap_padding;
break;
case AE_LEFT_TO_TOPRIGHT:
- az->x1 = region->winrct.xmin - AZONEPAD_EDGE;
+ az->x1 = region->winrct.xmin - AZONEPAD_EDGE + overlap_padding;
az->y1 = region->winrct.ymin;
- az->x2 = region->winrct.xmin + AZONEPAD_EDGE;
+ az->x2 = region->winrct.xmin + AZONEPAD_EDGE + overlap_padding;
az->y2 = region->winrct.ymax;
break;
case AE_RIGHT_TO_TOPLEFT:
- az->x1 = region->winrct.xmax + AZONEPAD_EDGE;
+ az->x1 = region->winrct.xmax + AZONEPAD_EDGE - overlap_padding;
az->y1 = region->winrct.ymin;
- az->x2 = region->winrct.xmax - AZONEPAD_EDGE;
+ az->x2 = region->winrct.xmax - AZONEPAD_EDGE - overlap_padding;
az->y2 = region->winrct.ymax;
break;
}
@@ -1267,7 +1254,6 @@ static void region_overlap_fix(ScrArea *area, ARegion *region)
}
}
-/* overlapping regions only in the following restricted cases */
bool ED_region_is_overlap(int spacetype, int regiontype)
{
if (regiontype == RGN_TYPE_HUD) {
@@ -1373,7 +1359,7 @@ static void region_rect_recursive(
else if (alignment == RGN_ALIGN_FLOAT) {
/**
* \note Currently this window type is only used for #RGN_TYPE_HUD,
- * We expect the panel to resize it's self to be larger.
+ * We expect the panel to resize itself to be larger.
*
* This aligns to the lower left of the area.
*/
@@ -1681,7 +1667,7 @@ static bool event_in_markers_region(const ARegion *region, const wmEvent *event)
{
rcti rect = region->winrct;
rect.ymax = rect.ymin + UI_MARKER_MARGIN_Y;
- return BLI_rcti_isect_pt(&rect, event->x, event->y);
+ return BLI_rcti_isect_pt_v(&rect, event->xy);
}
/**
@@ -1694,11 +1680,14 @@ static void ed_default_handlers(
/* NOTE: add-handler checks if it already exists. */
- /* XXX it would be good to have boundbox checks for some of these... */
+ /* XXX: it would be good to have bound-box checks for some of these. */
if (flag & ED_KEYMAP_UI) {
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "User Interface", 0, 0);
WM_event_add_keymap_handler(handlers, keymap);
+ ListBase *dropboxes = WM_dropboxmap_find("User Interface", 0, 0);
+ WM_event_add_dropbox_handler(handlers, dropboxes);
+
/* user interface widgets */
UI_region_handlers_add(handlers);
}
@@ -1737,7 +1726,7 @@ static void ed_default_handlers(
if (flag & ED_KEYMAP_TOOL) {
if (flag & ED_KEYMAP_GIZMO) {
WM_event_add_keymap_handler_dynamic(
- &region->handlers, WM_event_get_keymap_from_toolsystem_fallback, area);
+ &region->handlers, WM_event_get_keymap_from_toolsystem_with_gizmos, area);
}
else {
WM_event_add_keymap_handler_dynamic(
@@ -1909,7 +1898,7 @@ void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *ar
/* Some AZones use View2D data which is only updated in region init, so call that first! */
region_azones_add(screen, area, region);
}
- ED_area_azones_update(area, &win->eventstate->x);
+ ED_area_azones_update(area, win->eventstate->xy);
area->flag &= ~AREA_FLAG_REGION_SIZE_UPDATE;
}
@@ -1919,7 +1908,6 @@ bool ED_area_has_shared_border(struct ScrArea *a, struct ScrArea *b)
return area_getorientation(a, b) != -1;
}
-/* called in screen_refresh, or screens_init, also area size changes */
void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
{
WorkSpace *workspace = WM_window_get_active_workspace(win);
@@ -1933,7 +1921,7 @@ void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
rcti window_rect;
WM_window_rect_calc(win, &window_rect);
- /* set typedefinitions */
+ /* Set type-definitions. */
area->type = BKE_spacetype_from_id(area->spacetype);
if (area->type == NULL) {
@@ -1978,7 +1966,7 @@ void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
}
else {
/* prevent uiblocks to run */
- UI_blocklist_free(NULL, &region->uiblocks);
+ UI_blocklist_free(NULL, region);
}
/* Some AZones use View2D data which is only updated in region init, so call that first! */
@@ -1998,6 +1986,68 @@ void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
}
}
+static void area_offscreen_init(ScrArea *area)
+{
+ area->type = BKE_spacetype_from_id(area->spacetype);
+
+ if (area->type == NULL) {
+ area->spacetype = SPACE_VIEW3D;
+ area->type = BKE_spacetype_from_id(area->spacetype);
+ }
+
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
+ region->type = BKE_regiontype_from_id_or_first(area->type, region->regiontype);
+ }
+}
+
+ScrArea *ED_area_offscreen_create(wmWindow *win, eSpace_Type space_type)
+{
+ ScrArea *area = MEM_callocN(sizeof(*area), __func__);
+ area->spacetype = space_type;
+
+ screen_area_spacelink_add(WM_window_get_active_scene(win), area, space_type);
+ area_offscreen_init(area);
+
+ return area;
+}
+
+static void area_offscreen_exit(wmWindowManager *wm, wmWindow *win, ScrArea *area)
+{
+ if (area->type && area->type->exit) {
+ area->type->exit(wm, area);
+ }
+
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
+ if (region->type && region->type->exit) {
+ region->type->exit(wm, region);
+ }
+
+ WM_event_modal_handler_region_replace(win, region, NULL);
+ WM_draw_region_free(region, true);
+
+ MEM_SAFE_FREE(region->headerstr);
+
+ if (region->regiontimer) {
+ WM_event_remove_timer(wm, win, region->regiontimer);
+ region->regiontimer = NULL;
+ }
+
+ if (wm->message_bus) {
+ WM_msgbus_clear_by_owner(wm->message_bus, region);
+ }
+ }
+
+ WM_event_modal_handler_area_replace(win, area, NULL);
+}
+
+void ED_area_offscreen_free(wmWindowManager *wm, wmWindow *win, ScrArea *area)
+{
+ area_offscreen_exit(wm, win, area);
+
+ BKE_screen_area_free(area);
+ MEM_freeN(area);
+}
+
static void region_update_rect(ARegion *region)
{
region->winx = BLI_rcti_size_x(&region->winrct) + 1;
@@ -2007,15 +2057,11 @@ static void region_update_rect(ARegion *region)
BLI_rcti_init(&region->v2d.mask, 0, region->winx - 1, 0, region->winy - 1);
}
-/**
- * Call to move a popup window (keep OpenGL context free!)
- */
void ED_region_update_rect(ARegion *region)
{
region_update_rect(region);
}
-/* externally called for floating regions like menus */
void ED_region_floating_init(ARegion *region)
{
BLI_assert(region->alignment == RGN_ALIGN_FLOAT);
@@ -2045,18 +2091,22 @@ void ED_region_cursor_set(wmWindow *win, ScrArea *area, ARegion *region)
WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
-/* for use after changing visibility of regions */
void ED_region_visibility_change_update(bContext *C, ScrArea *area, ARegion *region)
{
if (region->flag & RGN_FLAG_HIDDEN) {
WM_event_remove_handlers(C, &region->handlers);
+ /* Needed to close any open pop-overs which would otherwise remain open,
+ * crashing on attempting to refresh. See: T93410.
+ *
+ * When #ED_area_init frees buttons via #UI_blocklist_free a NULL context
+ * is passed, causing the free not to remove menus or their handlers. */
+ UI_region_free_active_but_all(C, region);
}
ED_area_init(CTX_wm_manager(C), CTX_wm_window(C), area);
ED_area_tag_redraw(area);
}
-/* for quick toggle, can skip fades */
void region_toggle_hidden(bContext *C, ARegion *region, const bool do_fade)
{
ScrArea *area = CTX_wm_area(C);
@@ -2072,15 +2122,11 @@ void region_toggle_hidden(bContext *C, ARegion *region, const bool do_fade)
}
}
-/* exported to all editors, uses fading default */
void ED_region_toggle_hidden(bContext *C, ARegion *region)
{
region_toggle_hidden(C, region, true);
}
-/**
- * we swap spaces for fullscreen to keep all allocated data area vertices were set
- */
void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free)
{
const char spacetype = area_dst->spacetype;
@@ -2386,9 +2432,6 @@ void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
ED_area_tag_refresh(sa2);
}
-/**
- * \param skip_region_exit: Skip calling area exit callback. Set for opening temp spaces.
- */
void ED_area_newspace(bContext *C, ScrArea *area, int type, const bool skip_region_exit)
{
wmWindow *win = CTX_wm_window(C);
@@ -2553,7 +2596,6 @@ void ED_area_prevspace(bContext *C, ScrArea *area)
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CHANGED, area);
}
-/* returns offset for next button in header */
int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
{
ScrArea *area = CTX_wm_area(C);
@@ -2593,10 +2635,10 @@ static ThemeColorID region_background_color_id(const bContext *C, const ARegion
case RGN_TYPE_HEADER:
case RGN_TYPE_TOOL_HEADER:
if (ED_screen_area_active(C) || ED_area_is_global(area)) {
- return TH_HEADER;
+ return TH_HEADER_ACTIVE;
}
else {
- return TH_HEADERDESEL;
+ return TH_HEADER;
}
case RGN_TYPE_PREVIEW:
return TH_PREVIEW_BACK;
@@ -2865,11 +2907,16 @@ static const char *region_panels_collect_categories(ARegion *region,
return NULL;
}
-/**
- * \param contexts: A NULL terminated array of context strings to match against.
- * Matching against any of these strings will draw the panel.
- * Can be NULL to skip context checks.
- */
+static int panel_draw_width_from_max_width_get(const ARegion *region,
+ const PanelType *panel_type,
+ const int max_width)
+{
+ /* With a background, we want some extra padding. */
+ return UI_panel_should_show_background(region, panel_type) ?
+ max_width - UI_PANEL_MARGIN_X * 2.0f :
+ max_width;
+}
+
void ED_region_panels_layout_ex(const bContext *C,
ARegion *region,
ListBase *paneltypes,
@@ -2912,12 +2959,10 @@ void ED_region_panels_layout_ex(const bContext *C,
margin_x = category_tabs_width;
}
- const int w = BLI_rctf_size_x(&v2d->cur) - margin_x;
+ const int width_no_header = BLI_rctf_size_x(&v2d->cur) - margin_x;
/* Works out to 10 * UI_UNIT_X or 20 * UI_UNIT_X. */
const int em = (region->type->prefsizex) ? 10 : 20;
- const int w_box_panel = w - UI_PANEL_BOX_STYLE_MARGIN * 2.0f;
-
/* create panels */
UI_panels_begin(C, region);
@@ -2942,6 +2987,7 @@ void ED_region_panels_layout_ex(const bContext *C,
continue;
}
}
+ const int width = panel_draw_width_from_max_width_get(region, pt, width_no_header);
if (panel && UI_panel_is_dragging(panel)) {
/* Prevent View2d.tot rectangle size changes while dragging panels. */
@@ -2953,13 +2999,13 @@ void ED_region_panels_layout_ex(const bContext *C,
&region->panels,
pt,
panel,
- (pt->flag & PANEL_TYPE_DRAW_BOX) ? w_box_panel : w,
+ (pt->flag & PANEL_TYPE_NO_HEADER) ? width_no_header : width,
em,
NULL,
search_filter);
}
- /* Draw "polyinstantaited" panels that don't have a 1 to 1 correspondence with their types. */
+ /* Draw "poly-instantiated" panels that don't have a 1 to 1 correspondence with their types. */
if (has_instanced_panel) {
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
if (panel->type == NULL) {
@@ -2972,6 +3018,7 @@ void ED_region_panels_layout_ex(const bContext *C,
!STREQ(category, panel->type->category)) {
continue;
}
+ const int width = panel_draw_width_from_max_width_get(region, panel->type, width_no_header);
if (panel && UI_panel_is_dragging(panel)) {
/* Prevent View2d.tot rectangle size changes while dragging panels. */
@@ -2987,7 +3034,7 @@ void ED_region_panels_layout_ex(const bContext *C,
&region->panels,
panel->type,
panel,
- (panel->type->flag & PANEL_TYPE_DRAW_BOX) ? w_box_panel : w,
+ (panel->type->flag & PANEL_TYPE_NO_HEADER) ? width_no_header : width,
em,
unique_panel_str,
search_filter);
@@ -3181,10 +3228,6 @@ static bool panel_property_search(const bContext *C,
return false;
}
-/**
- * Build the same panel list as #ED_region_panels_layout_ex and checks whether any
- * of the panels contain a search result based on the area / region's search filter.
- */
bool ED_region_property_search(const bContext *C,
ARegion *region,
ListBase *paneltypes,
@@ -3255,7 +3298,7 @@ bool ED_region_property_search(const bContext *C,
}
/* Free the panels and blocks, as they are only used for search. */
- UI_blocklist_free(C, &region->uiblocks);
+ UI_blocklist_free(C, region);
UI_panels_free_instanced(C, region);
BKE_area_region_panels_free(&region->panels);
@@ -3390,9 +3433,6 @@ int ED_area_footersize(void)
return ED_area_headersize();
}
-/**
- * \return the final height of a global \a area, accounting for DPI.
- */
int ED_area_global_size_y(const ScrArea *area)
{
BLI_assert(ED_area_is_global(area));
@@ -3442,12 +3482,6 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area)
return screen->areabase.first;
}
-/**
- * For now we just assume all global areas are made up out of horizontal bars
- * with the same size. A fixed size could be stored in ARegion instead if needed.
- *
- * \return the DPI aware height of a single bar/region in global areas.
- */
int ED_region_global_size_y(void)
{
return ED_area_headersize(); /* same size as header */
@@ -3773,9 +3807,6 @@ void ED_region_cache_draw_cached_segments(
}
}
-/**
- * Generate subscriptions for this region.
- */
void ED_region_message_subscribe(wmRegionMessageSubscribeParams *params)
{
ARegion *region = params->region;
diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c
index fd4f3964398..022f8620b0b 100644
--- a/source/blender/editors/screen/area_query.c
+++ b/source/blender/editors/screen/area_query.c
@@ -188,3 +188,37 @@ bool ED_region_contains_xy(const ARegion *region, const int event_xy[2])
}
return false;
}
+
+ARegion *ED_area_find_region_xy_visual(const ScrArea *area,
+ const int regiontype,
+ const int event_xy[2])
+{
+ if (!area) {
+ return NULL;
+ }
+
+ /* Check overlapped regions first. */
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
+ if (!region->overlap) {
+ continue;
+ }
+ if (ELEM(regiontype, RGN_TYPE_ANY, region->regiontype)) {
+ if (ED_region_contains_xy(region, event_xy)) {
+ return region;
+ }
+ }
+ }
+ /* Now non-overlapping ones. */
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
+ if (region->overlap) {
+ continue;
+ }
+ if (ELEM(regiontype, RGN_TYPE_ANY, region->regiontype)) {
+ if (ED_region_contains_xy(region, event_xy)) {
+ return region;
+ }
+ }
+ }
+
+ return NULL;
+}
diff --git a/source/blender/editors/screen/area_utils.c b/source/blender/editors/screen/area_utils.c
index 30553bb7f07..9a688ac0b05 100644
--- a/source/blender/editors/screen/area_utils.c
+++ b/source/blender/editors/screen/area_utils.c
@@ -40,9 +40,6 @@
/** \name Generic Tool System Region Callbacks
* \{ */
-/**
- * Callback for #ARegionType.message_subscribe
- */
void ED_region_generic_tools_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
struct wmMsgBus *mbus = params->message_bus;
@@ -56,9 +53,6 @@ void ED_region_generic_tools_region_message_subscribe(const wmRegionMessageSubsc
WM_msg_subscribe_rna_anon_prop(mbus, WorkSpace, tools, &msg_sub_value_region_tag_redraw);
}
-/**
- * Callback for #ARegionType.snap_size
- */
int ED_region_generic_tools_region_snap_size(const ARegion *region, int size, int axis)
{
if (axis == 0) {
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index f651fd4fb61..63b7fbc14a7 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -57,12 +57,6 @@ static void immDrawPixelsTexSetupAttributes(IMMDrawPixelsTexState *state)
vert_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
}
-/**
- * To be used before calling #immDrawPixelsTex
- * Default shader is #GPU_SHADER_2D_IMAGE_COLOR
- * You can still set uniforms with:
- * `GPU_shader_uniform_int(shader, GPU_shader_get_uniform(shader, "name"), 0);`
- */
IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
{
IMMDrawPixelsTexState state;
@@ -70,7 +64,7 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
state.shader = GPU_shader_get_builtin_shader(builtin);
- /* Shader will be unbind by immUnbindProgram in immDrawPixelsTexScaled_clipping */
+ /* Shader will be unbind by immUnbindProgram in a `immDrawPixelsTex` function. */
immBindBuiltinProgram(builtin);
immUniform1i("image", 0);
state.do_shader_unbind = true;
@@ -78,37 +72,92 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
return state;
}
-/**
- * Use the currently bound shader.
- *
- * Use #immDrawPixelsTexSetup to bind the shader you
- * want before calling #immDrawPixelsTex.
- *
- * If using a special shader double check it uses the same
- * attributes "pos" "texCoord" and uniform "image".
- *
- * If color is NULL then use white by default
- *
- * Be also aware that this function unbinds the shader when
- * it's finished.
- */
-void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float scaleX,
- float scaleY,
- float clip_min_x,
- float clip_min_y,
- float clip_max_x,
- float clip_max_y,
- float xzoom,
- float yzoom,
- const float color[4])
+void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state,
+ const float x,
+ const float y,
+ const int img_w,
+ const int img_h,
+ const eGPUTextureFormat gpu_format,
+ const bool use_filter,
+ const void *rect,
+ const float scaleX,
+ const float scaleY,
+ const float xzoom,
+ const float yzoom,
+ const float color[4])
+{
+ static const float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ const float draw_width = img_w * scaleX * xzoom;
+ const float draw_height = img_h * scaleY * yzoom;
+ /* Down-scaling with regular bi-linear interpolation (i.e. #GL_LINEAR) doesn't give good
+ * filtering results. Mipmaps can be used to get better results (i.e. #GL_LINEAR_MIPMAP_LINEAR),
+ * so always use mipmaps when filtering. */
+ const bool use_mipmap = use_filter && ((draw_width < img_w) || (draw_height < img_h));
+
+ GPUTexture *tex = GPU_texture_create_2d("immDrawPixels", img_w, img_h, 1, gpu_format, NULL);
+
+ const bool use_float_data = ELEM(gpu_format, GPU_RGBA16F, GPU_RGB16F, GPU_R16F);
+ eGPUDataFormat gpu_data_format = (use_float_data) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
+ GPU_texture_update(tex, gpu_data_format, rect);
+
+ GPU_texture_filter_mode(tex, use_filter);
+ if (use_mipmap) {
+ GPU_texture_generate_mipmap(tex);
+ GPU_texture_mipmap_mode(tex, true, true);
+ }
+ GPU_texture_wrap_mode(tex, false, true);
+
+ GPU_texture_bind(tex, 0);
+
+ /* optional */
+ /* NOTE: Shader could be null for GLSL OCIO drawing, it is fine, since
+ * it does not need color.
+ */
+ if (state->shader != NULL && GPU_shader_get_uniform(state->shader, "color") != -1) {
+ immUniformColor4fv((color) ? color : white);
+ }
+
+ uint pos = state->pos, texco = state->texco;
+
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+ immAttr2f(texco, 0.0f, 0.0f);
+ immVertex2f(pos, x, y);
+
+ immAttr2f(texco, 1.0f, 0.0f);
+ immVertex2f(pos, x + draw_width, y);
+
+ immAttr2f(texco, 1.0f, 1.0f);
+ immVertex2f(pos, x + draw_width, y + draw_height);
+
+ immAttr2f(texco, 0.0f, 1.0f);
+ immVertex2f(pos, x, y + draw_height);
+ immEnd();
+
+ if (state->do_shader_unbind) {
+ immUnbindProgram();
+ }
+
+ GPU_texture_unbind(tex);
+ GPU_texture_free(tex);
+}
+
+void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float scaleX,
+ float scaleY,
+ float clip_min_x,
+ float clip_min_y,
+ float clip_max_x,
+ float clip_max_y,
+ float xzoom,
+ float yzoom,
+ const float color[4])
{
int subpart_x, subpart_y, tex_w = 256, tex_h = 256;
int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y;
@@ -262,108 +311,107 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
GPU_unpack_row_length_set(0);
}
-void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float scaleX,
- float scaleY,
- float xzoom,
- float yzoom,
- const float color[4])
+void immDrawPixelsTexTiled_scaling(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float scaleX,
+ float scaleY,
+ float xzoom,
+ float yzoom,
+ const float color[4])
{
- immDrawPixelsTexScaled_clipping(state,
- x,
- y,
- img_w,
- img_h,
- gpu_format,
- use_filter,
- rect,
- scaleX,
- scaleY,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- xzoom,
- yzoom,
- color);
+ immDrawPixelsTexTiled_scaling_clipping(state,
+ x,
+ y,
+ img_w,
+ img_h,
+ gpu_format,
+ use_filter,
+ rect,
+ scaleX,
+ scaleY,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ xzoom,
+ yzoom,
+ color);
}
-void immDrawPixelsTex(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float xzoom,
- float yzoom,
- const float color[4])
+void immDrawPixelsTexTiled(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float xzoom,
+ float yzoom,
+ const float color[4])
{
- immDrawPixelsTexScaled_clipping(state,
- x,
- y,
- img_w,
- img_h,
- gpu_format,
- use_filter,
- rect,
- 1.0f,
- 1.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- xzoom,
- yzoom,
- color);
+ immDrawPixelsTexTiled_scaling_clipping(state,
+ x,
+ y,
+ img_w,
+ img_h,
+ gpu_format,
+ use_filter,
+ rect,
+ 1.0f,
+ 1.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ xzoom,
+ yzoom,
+ color);
}
-void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float clip_min_x,
- float clip_min_y,
- float clip_max_x,
- float clip_max_y,
- float xzoom,
- float yzoom,
- const float color[4])
+void immDrawPixelsTexTiled_clipping(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float clip_min_x,
+ float clip_min_y,
+ float clip_max_x,
+ float clip_max_y,
+ float xzoom,
+ float yzoom,
+ const float color[4])
{
- immDrawPixelsTexScaled_clipping(state,
- x,
- y,
- img_w,
- img_h,
- gpu_format,
- use_filter,
- rect,
- 1.0f,
- 1.0f,
- clip_min_x,
- clip_min_y,
- clip_max_x,
- clip_max_y,
- xzoom,
- yzoom,
- color);
+ immDrawPixelsTexTiled_scaling_clipping(state,
+ x,
+ y,
+ img_w,
+ img_h,
+ gpu_format,
+ use_filter,
+ rect,
+ 1.0f,
+ 1.0f,
+ clip_min_x,
+ clip_min_y,
+ clip_max_x,
+ clip_max_y,
+ xzoom,
+ yzoom,
+ color);
}
/* **** Color management helper functions for GLSL display/transform ***** */
-/* Draw given image buffer on a screen using GLSL for display transform */
void ED_draw_imbuf_clipping(ImBuf *ibuf,
float x,
float y,
@@ -430,40 +478,40 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf,
}
if (format != 0) {
- immDrawPixelsTex_clipping(&state,
- x,
- y,
- ibuf->x,
- ibuf->y,
- format,
- use_filter,
- ibuf->rect_float,
- clip_min_x,
- clip_min_y,
- clip_max_x,
- clip_max_y,
- zoom_x,
- zoom_y,
- NULL);
+ immDrawPixelsTexTiled_clipping(&state,
+ x,
+ y,
+ ibuf->x,
+ ibuf->y,
+ format,
+ use_filter,
+ ibuf->rect_float,
+ clip_min_x,
+ clip_min_y,
+ clip_max_x,
+ clip_max_y,
+ zoom_x,
+ zoom_y,
+ NULL);
}
}
else if (ibuf->rect) {
/* ibuf->rect is always RGBA */
- immDrawPixelsTex_clipping(&state,
- x,
- y,
- ibuf->x,
- ibuf->y,
- GPU_RGBA8,
- use_filter,
- ibuf->rect,
- clip_min_x,
- clip_min_y,
- clip_max_x,
- clip_max_y,
- zoom_x,
- zoom_y,
- NULL);
+ immDrawPixelsTexTiled_clipping(&state,
+ x,
+ y,
+ ibuf->x,
+ ibuf->y,
+ GPU_RGBA8,
+ use_filter,
+ ibuf->rect,
+ clip_min_x,
+ clip_min_y,
+ clip_max_x,
+ clip_max_y,
+ zoom_x,
+ zoom_y,
+ NULL);
}
IMB_colormanagement_finish_glsl_draw();
@@ -482,21 +530,21 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf,
if (display_buffer) {
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex_clipping(&state,
- x,
- y,
- ibuf->x,
- ibuf->y,
- GPU_RGBA8,
- use_filter,
- display_buffer,
- clip_min_x,
- clip_min_y,
- clip_max_x,
- clip_max_y,
- zoom_x,
- zoom_y,
- NULL);
+ immDrawPixelsTexTiled_clipping(&state,
+ x,
+ y,
+ ibuf->x,
+ ibuf->y,
+ GPU_RGBA8,
+ use_filter,
+ display_buffer,
+ clip_min_x,
+ clip_min_y,
+ clip_max_x,
+ clip_max_y,
+ zoom_x,
+ zoom_y,
+ NULL);
}
IMB_display_buffer_release(cache_handle);
@@ -577,8 +625,6 @@ int ED_draw_imbuf_method(ImBuf *ibuf)
return U.image_draw_method;
}
-/* don't move to GPU_immediate_util.h because this uses user-prefs
- * and isn't very low level */
void immDrawBorderCorners(uint pos, const rcti *border, float zoomx, float zoomy)
{
float delta_x = 4.0f * UI_DPI_FAC / zoomx;
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 3d447d90626..04df90bf912 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -49,11 +49,13 @@
#include "BKE_gpencil.h"
#include "BKE_layer.h"
#include "BKE_object.h"
+#include "BKE_tracking.h"
#include "RNA_access.h"
#include "ED_anim_api.h"
#include "ED_armature.h"
+#include "ED_clip.h"
#include "ED_gpencil.h"
#include "SEQ_select.h"
@@ -99,6 +101,7 @@ const char *screen_context_dir[] = {
"active_nla_track",
"active_nla_strip",
"selected_nla_strips", /* nla editor */
+ "selected_movieclip_tracks",
"gpencil_data",
"gpencil_data_owner", /* grease pencil data */
"annotation_data",
@@ -110,6 +113,8 @@ const char *screen_context_dir[] = {
"active_gpencil_frame",
"active_annotation_layer",
"active_operator",
+ "selected_visible_actions",
+ "selected_editable_actions",
"visible_fcurves",
"editable_fcurves",
"selected_visible_fcurves",
@@ -496,7 +501,7 @@ static eContextResult screen_ctx_active_pose_bone(const bContext *C, bContextDat
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
Object *obpose = BKE_object_pose_armature_get(obact);
- bPoseChannel *pchan = BKE_pose_channel_active(obpose);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(obpose);
if (pchan) {
CTX_data_pointer_set(result, &obpose->id, &RNA_PoseBone, pchan);
return CTX_RESULT_OK;
@@ -709,6 +714,33 @@ static eContextResult screen_ctx_selected_nla_strips(const bContext *C, bContext
}
return CTX_RESULT_NO_DATA;
}
+static eContextResult screen_ctx_selected_movieclip_tracks(const bContext *C,
+ bContextDataResult *result)
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ if (space_clip == NULL) {
+ return CTX_RESULT_NO_DATA;
+ }
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+ if (clip == NULL) {
+ return CTX_RESULT_NO_DATA;
+ }
+ MovieTracking *tracking = &clip->tracking;
+ if (tracking == NULL) {
+ return CTX_RESULT_NO_DATA;
+ }
+
+ ListBase *tracks_list = BKE_tracking_get_active_tracks(tracking);
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, tracks_list) {
+ if (!TRACK_SELECTED(track)) {
+ continue;
+ }
+ CTX_data_list_add(result, &clip->id, &RNA_MovieTrackingTrack, track);
+ }
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return CTX_RESULT_OK;
+}
static eContextResult screen_ctx_gpencil_data(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
@@ -945,6 +977,90 @@ static eContextResult screen_ctx_active_operator(const bContext *C, bContextData
}
return CTX_RESULT_NO_DATA;
}
+static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
+ bContextDataResult *result,
+ bool editable)
+{
+ bAnimContext ac;
+ if (ANIM_animdata_get_context(C, &ac) && ELEM(ac.spacetype, SPACE_ACTION, SPACE_GRAPH)) {
+ /* In the Action and Shape Key editor always use the action field at the top. */
+ if (ac.spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)ac.sl;
+
+ if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY)) {
+ if (saction->action && !(editable && ID_IS_LINKED(saction->action))) {
+ CTX_data_id_list_add(result, &saction->action->id);
+ }
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return CTX_RESULT_OK;
+ }
+ }
+
+ /* Search for selected animation data items. */
+ ListBase anim_data = {NULL, NULL};
+
+ int filter = ANIMFILTER_DATA_VISIBLE;
+ bool check_selected = false;
+
+ switch (ac.spacetype) {
+ case SPACE_GRAPH:
+ filter |= ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL;
+ break;
+
+ case SPACE_ACTION:
+ filter |= ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS;
+ check_selected = true;
+ break;
+ }
+
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ GSet *seen_set = BLI_gset_ptr_new("seen actions");
+
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
+ /* In dopesheet check selection status of individual items, skipping
+ * if not selected or has no selection flag. This is needed so that
+ * selecting action or group rows without any channels works. */
+ if (check_selected && ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_SELECT) <= 0) {
+ continue;
+ }
+
+ bAction *action = ANIM_channel_action_get(ale);
+
+ if (action) {
+ if (editable && ID_IS_LINKED(action)) {
+ continue;
+ }
+
+ /* Add the action to the output list if not already added. */
+ if (!BLI_gset_haskey(seen_set, action)) {
+ CTX_data_id_list_add(result, &action->id);
+ BLI_gset_add(seen_set, action);
+ }
+ }
+ }
+
+ BLI_gset_free(seen_set, NULL);
+
+ ANIM_animdata_freelist(&anim_data);
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return CTX_RESULT_OK;
+ }
+ return CTX_RESULT_NO_DATA;
+}
+
+static eContextResult screen_ctx_selected_visible_actions(const bContext *C,
+ bContextDataResult *result)
+{
+ return screen_ctx_sel_actions_impl(C, result, false);
+}
+static eContextResult screen_ctx_selected_editable_actions(const bContext *C,
+ bContextDataResult *result)
+{
+ return screen_ctx_sel_actions_impl(C, result, true);
+}
static eContextResult screen_ctx_sel_edit_fcurves_(const bContext *C,
bContextDataResult *result,
const int extra_filter)
@@ -1143,6 +1259,7 @@ static void ensure_ed_screen_context_functions(void)
register_context_function("active_nla_track", screen_ctx_active_nla_track);
register_context_function("active_nla_strip", screen_ctx_active_nla_strip);
register_context_function("selected_nla_strips", screen_ctx_selected_nla_strips);
+ register_context_function("selected_movieclip_tracks", screen_ctx_selected_movieclip_tracks);
register_context_function("gpencil_data", screen_ctx_gpencil_data);
register_context_function("gpencil_data_owner", screen_ctx_gpencil_data_owner);
register_context_function("annotation_data", screen_ctx_annotation_data);
@@ -1154,6 +1271,8 @@ static void ensure_ed_screen_context_functions(void)
register_context_function("editable_gpencil_layers", screen_ctx_editable_gpencil_layers);
register_context_function("editable_gpencil_strokes", screen_ctx_editable_gpencil_strokes);
register_context_function("active_operator", screen_ctx_active_operator);
+ register_context_function("selected_visible_actions", screen_ctx_selected_visible_actions);
+ register_context_function("selected_editable_actions", screen_ctx_selected_editable_actions);
register_context_function("editable_fcurves", screen_ctx_editable_fcurves);
register_context_function("visible_fcurves", screen_ctx_visible_fcurves);
register_context_function("selected_editable_fcurves", screen_ctx_selected_editable_fcurves);
@@ -1164,7 +1283,6 @@ static void ensure_ed_screen_context_functions(void)
register_context_function("ui_list", screen_ctx_ui_list);
}
-/* Entry point for the screen context. */
int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result)
{
if (CTX_data_dir(member)) {
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index ab50e327de3..01730b3c9aa 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -144,7 +144,7 @@ static void drawscredge_area_draw(
}
GPUBatch *batch = batch_screen_edges_get(NULL);
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_EDGES);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_BORDERS);
GPU_batch_uniform_4fv(batch, "rect", (float *)&rect);
GPU_batch_draw(batch);
}
@@ -162,9 +162,6 @@ static void drawscredge_area(ScrArea *area, int sizex, int sizey, float edge_thi
drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, edge_thickness);
}
-/**
- * Only for edge lines between areas.
- */
void ED_screen_draw_edges(wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
@@ -215,7 +212,7 @@ void ED_screen_draw_edges(wmWindow *win)
GPU_blend(GPU_BLEND_ALPHA);
GPUBatch *batch = batch_screen_edges_get(&verts_per_corner);
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_EDGES);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_BORDERS);
GPU_batch_uniform_1i(batch, "cornerLen", verts_per_corner);
GPU_batch_uniform_1f(batch, "scale", corner_scale);
GPU_batch_uniform_4fv(batch, "color", col);
@@ -231,12 +228,6 @@ void ED_screen_draw_edges(wmWindow *win)
}
}
-/**
- * Visual indication of the two areas involved in a proposed join.
- *
- * \param sa1: Area from which the resultant originates.
- * \param sa2: Target area that will be replaced.
- */
void screen_draw_join_highlight(ScrArea *sa1, ScrArea *sa2)
{
const eScreenDir dir = area_getorientation(sa1, sa2);
@@ -445,9 +436,6 @@ static void screen_preview_draw(const bScreen *screen, int size_x, int size_y)
GPU_matrix_pop();
}
-/**
- * Render the preview for a screen layout in \a screen.
- */
void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, uint *r_rect)
{
char err_out[256] = "unknown";
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 1c068fdd6e4..5a2b53163b8 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -57,6 +57,7 @@
#include "UI_interface.h"
#include "WM_message.h"
+#include "WM_toolsystem.h"
#include "DEG_depsgraph_query.h"
@@ -202,9 +203,6 @@ ScrArea *area_split(const wmWindow *win,
return newa;
}
-/**
- * Empty screen, with 1 dummy area without spacedata. Uses window size.
- */
bScreen *screen_add(Main *bmain, const char *name, const rcti *rect)
{
bScreen *screen = BKE_libblock_alloc(bmain, ID_SCR, name, 0);
@@ -273,9 +271,6 @@ void screen_data_copy(bScreen *to, bScreen *from)
}
}
-/**
- * Prepare a newly created screen for initializing it as active screen.
- */
void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
{
screen_new->winid = win->winid;
@@ -283,11 +278,6 @@ void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
screen_new->do_draw = true;
}
-/**
- * with `sa_a` as center, `sa_b` is located at: 0=W, 1=N, 2=E, 3=S
- * -1 = not valid check.
- * used with join operator.
- */
eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b)
{
if (sa_a == NULL || sa_b == NULL || sa_a == sa_b) {
@@ -328,9 +318,6 @@ eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b)
return -1;
}
-/**
- * Get alignment offset of adjacent areas. 'dir' value is like #area_getorientation().
- */
void area_getoffsets(
ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2)
{
@@ -535,13 +522,11 @@ static bool screen_area_join_ex(
return true;
}
-/* Join any two neighboring areas. Might involve complex changes. */
int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
{
return screen_area_join_ex(C, screen, sa1, sa2, false);
}
-/* Close a screen area, allowing most-aligned neighbor to take its place. */
bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area)
{
if (area == NULL) {
@@ -574,6 +559,17 @@ bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area)
return screen_area_join_ex(C, screen, sa2, area, true);
}
+void screen_area_spacelink_add(Scene *scene, ScrArea *area, eSpace_Type space_type)
+{
+ SpaceType *stype = BKE_spacetype_from_id(space_type);
+ SpaceLink *slink = stype->create(area, scene);
+
+ area->regionbase = slink->regionbase;
+
+ BLI_addhead(&area->spacedata, slink);
+ BLI_listbase_clear(&slink->regionbase);
+}
+
/* ****************** EXPORTED API TO OTHER MODULES *************************** */
/* screen sets cursor based on active region */
@@ -628,16 +624,18 @@ void ED_screen_do_listen(bContext *C, wmNotifier *note)
}
}
-/* make this screen usable */
-/* for file read and first use, for scaling window, area moves */
void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
- /* exception for bg mode, we only need the screen context */
+ /* Exception for background mode, we only need the screen context. */
if (!G.background) {
- /* header size depends on DPI, let's verify */
- WM_window_set_dpi(win);
+
+ /* Called even when creating the ghost window fails in #WM_window_open. */
+ if (win->ghostwin) {
+ /* Header size depends on DPI, let's verify. */
+ WM_window_set_dpi(win);
+ }
ED_screen_global_areas_refresh(win);
@@ -665,7 +663,6 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
screen->context = ed_screen_context;
}
-/* file read, set all screens, ... */
void ED_screens_init(Main *bmain, wmWindowManager *wm)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
@@ -675,7 +672,7 @@ void ED_screens_init(Main *bmain, wmWindowManager *wm)
ED_screen_refresh(wm, win);
if (win->eventstate) {
- ED_screen_set_active_region(NULL, win, &win->eventstate->x);
+ ED_screen_set_active_region(NULL, win, win->eventstate->xy);
}
}
@@ -693,10 +690,6 @@ void ED_screen_ensure_updated(wmWindowManager *wm, wmWindow *win, bScreen *scree
}
}
-/**
- * Utility to exit and free an area-region. Screen level regions (menus/popups) need to be treated
- * slightly differently, see #ui_region_temp_remove().
- */
void ED_region_remove(bContext *C, ScrArea *area, ARegion *region)
{
ED_region_exit(C, region);
@@ -846,10 +839,6 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
}
}
-/**
- * Called in wm_event_system.c. sets state vars in screen, cursors.
- * event type is mouse move.
- */
void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
{
bScreen *screen = WM_window_get_active_screen(win);
@@ -919,6 +908,10 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
}
}
}
+
+ /* Ensure test-motion values are never shared between regions. */
+ const bool use_cycle = !WM_cursor_test_motion_and_update((const int[2]){-1, -1});
+ UNUSED_VARS(use_cycle);
}
/* Cursors, for time being set always on edges,
@@ -935,7 +928,7 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
* because it can undo setting the right button as active due
* to delayed notifier handling. */
if (C) {
- UI_screen_free_active_but(C, screen);
+ UI_screen_free_active_but_highlight(C, screen);
}
}
}
@@ -948,7 +941,7 @@ int ED_screen_area_active(const bContext *C)
ScrArea *area = CTX_wm_area(C);
if (win && screen && area) {
- AZone *az = ED_area_actionzone_find_xy(area, &win->eventstate->x);
+ AZone *az = ED_area_actionzone_find_xy(area, win->eventstate->xy);
if (az && az->type == AZONE_REGION) {
return 1;
@@ -1023,13 +1016,7 @@ static void screen_global_area_refresh(wmWindow *win,
}
else {
area = screen_area_create_with_geometry(&win->global_areas, rect, space_type);
- SpaceType *stype = BKE_spacetype_from_id(space_type);
- SpaceLink *slink = stype->create(area, WM_window_get_active_scene(win));
-
- area->regionbase = slink->regionbase;
-
- BLI_addhead(&area->spacedata, slink);
- BLI_listbase_clear(&slink->regionbase);
+ screen_area_spacelink_add(WM_window_get_active_scene(win), area, space_type);
/* Data specific to global areas. */
area->global = MEM_callocN(sizeof(*area->global), __func__);
@@ -1112,10 +1099,6 @@ void ED_screen_global_areas_refresh(wmWindow *win)
/* -------------------------------------------------------------------- */
/* Screen changing */
-/**
- * \return the screen to activate.
- * \warning The returned screen may not always equal \a screen_new!
- */
void screen_change_prepare(
bScreen *screen_old, bScreen *screen_new, Main *bmain, bContext *C, wmWindow *win)
{
@@ -1162,14 +1145,6 @@ void screen_change_update(bContext *C, wmWindow *win, bScreen *screen)
WM_event_add_mousemove(win);
}
-/**
- * \brief Change the active screen.
- *
- * Operator call, WM + Window + screen already existed before
- *
- * \warning Do NOT call in area/region queues!
- * \returns if screen changing was successful.
- */
bool ED_screen_change(bContext *C, bScreen *screen)
{
Main *bmain = CTX_data_main(C);
@@ -1230,7 +1205,10 @@ static void screen_set_3dview_camera(Scene *scene,
}
}
-void ED_screen_scene_change(bContext *C, wmWindow *win, Scene *scene)
+void ED_screen_scene_change(bContext *C,
+ wmWindow *win,
+ Scene *scene,
+ const bool refresh_toolsystem)
{
#if 0
ViewLayer *view_layer_old = WM_window_get_active_view_layer(win);
@@ -1268,6 +1246,10 @@ void ED_screen_scene_change(bContext *C, wmWindow *win, Scene *scene)
}
}
}
+
+ if (refresh_toolsystem) {
+ WM_toolsystem_refresh_screen_window(win);
+ }
}
ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type)
@@ -1303,9 +1285,6 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type)
return newsa;
}
-/**
- * \a was_prev_temp for the case previous space was a temporary fullscreen as well
- */
void ED_screen_full_prevspace(bContext *C, ScrArea *area)
{
BLI_assert(area->full);
@@ -1335,7 +1314,6 @@ void ED_screen_restore_temp_type(bContext *C, ScrArea *area)
}
}
-/* restore a screen / area back to default operation, after temp fullscreen modes */
void ED_screen_full_restore(bContext *C, ScrArea *area)
{
wmWindow *win = CTX_wm_window(C);
@@ -1442,28 +1420,11 @@ static bScreen *screen_state_to_nonnormal(bContext *C,
return screen;
}
-/**
- * Create a new temporary screen with a maximized, empty area.
- * This can be closed with #ED_screen_state_toggle().
- *
- * Use this to just create a new maximized screen/area, rather than maximizing an existing one.
- * Otherwise, maximize with #ED_screen_state_toggle().
- */
bScreen *ED_screen_state_maximized_create(bContext *C)
{
return screen_state_to_nonnormal(C, CTX_wm_window(C), NULL, SCREENMAXIMIZED);
}
-/**
- * This function toggles: if area is maximized/full then the parent will be restored.
- *
- * Use #ED_screen_state_maximized_create() if you do not want the toggle behavior when changing to
- * a maximized area. I.e. if you just want to open a new maximized screen/area, not maximize a
- * specific area. In the former case, space data of the maximized and non-maximized area should be
- * independent, in the latter it should be the same.
- *
- * \warning \a area may be freed.
- */
ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const short state)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1474,8 +1435,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const
* switching screens with tooltip open because region and tooltip
* are no longer in the same screen */
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
- UI_blocklist_free(C, &region->uiblocks);
-
+ UI_blocklist_free(C, region);
if (region->regiontimer) {
WM_event_remove_timer(wm, NULL, region->regiontimer);
region->regiontimer = NULL;
@@ -1572,14 +1532,6 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const
return screen->areabase.first;
}
-/**
- * Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined
- * by \a display_type.
- *
- * \param title: Title to set for the window, if a window is spawned.
- * \param x, y: Position of the window, if a window is spawned.
- * \param sizex, sizey: Dimensions of the window, if a window is spawned.
- */
ScrArea *ED_screen_temp_space_open(bContext *C,
const char *title,
int x,
@@ -1628,7 +1580,6 @@ ScrArea *ED_screen_temp_space_open(bContext *C,
return area;
}
-/* update frame rate info for viewport drawing */
void ED_refresh_viewport_fps(bContext *C)
{
wmTimer *animtimer = CTX_wm_screen(C)->animtimer;
@@ -1654,9 +1605,6 @@ void ED_refresh_viewport_fps(bContext *C)
}
}
-/* redraws: uses defines from stime->redraws
- * enable: 1 - forward on, -1 - backwards on, 0 - off
- */
void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
{
bScreen *screen = CTX_wm_screen(C);
@@ -1756,7 +1704,6 @@ void ED_screen_animation_timer_update(bScreen *screen, int redraws)
}
}
-/* results in fully updated anim system */
void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
{
Scene *scene = DEG_get_input_scene(depsgraph);
@@ -1781,9 +1728,6 @@ void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
BKE_scene_graph_update_for_newframe(depsgraph);
}
-/*
- * return true if any active area requires to see in 3D
- */
bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
{
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
@@ -1859,11 +1803,6 @@ bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
return false;
}
-/**
- * Find the scene displayed in \a screen.
- * \note Assumes \a screen to be visible/active!
- */
-
Scene *ED_screen_scene_find_with_window(const bScreen *screen,
const wmWindowManager *wm,
struct wmWindow **r_window)
diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c
index e67c933cb8e..394a7fd7350 100644
--- a/source/blender/editors/screen/screen_geometry.c
+++ b/source/blender/editors/screen/screen_geometry.c
@@ -83,10 +83,6 @@ bool screen_geom_edge_is_horizontal(ScrEdge *se)
return (se->v1->vec.y == se->v2->vec.y);
}
-/**
- * \param bounds_rect: Either window or screen bounds.
- * Used to exclude edges along window/screen edges.
- */
ScrEdge *screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map,
const rcti *bounds_rect,
const int mx,
@@ -124,7 +120,6 @@ ScrEdge *screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map,
return NULL;
}
-/* need win size to make sure not to include edges along screen edge */
ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
const bScreen *screen,
const int mx,
@@ -249,13 +244,6 @@ static bool screen_geom_vertices_scale_pass(const wmWindow *win,
return needs_another_pass;
}
-/**
- * \brief Main screen-layout calculation function.
- *
- * * Scale areas nicely on window size and DPI changes.
- * * Ensure areas have a minimum height.
- * * Correctly set global areas to their fixed height.
- */
void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen)
{
rcti window_rect, screen_rect;
@@ -303,9 +291,6 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen)
}
}
-/**
- * \return 0 if no split is possible, otherwise the screen-coordinate at which to split.
- */
short screen_geom_find_area_split_point(const ScrArea *area,
const rcti *window_rect,
const eScreenAxis dir_axis,
@@ -374,9 +359,6 @@ short screen_geom_find_area_split_point(const ScrArea *area,
return x;
}
-/**
- * Select all edges that are directly or indirectly connected to \a edge.
- */
void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
{
bScreen *screen = WM_window_get_active_screen(win);
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index 4016ef84bfd..e42c891b0ba 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -61,23 +61,48 @@ typedef enum eScreenAxis {
#define AREAJOINTOLERANCEX (AREAMINX * U.dpi_fac)
#define AREAJOINTOLERANCEY (HEADERY * U.dpi_fac)
-/* Expanded interaction influence of area borders. */
-#define BORDERPADDING (U.dpi_fac + U.pixelsize)
+/**
+ * Expanded interaction influence of area borders.
+ */
+#define BORDERPADDING ((2.0f * U.dpi_fac) + U.pixelsize)
/* area.c */
-void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free);
+
+/**
+ * we swap spaces for fullscreen to keep all allocated data area vertices were set
+ */
+void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, bool do_free);
void ED_area_data_swap(ScrArea *area_dst, ScrArea *area_src);
-void region_toggle_hidden(struct bContext *C, ARegion *region, const bool do_fade);
+/* for quick toggle, can skip fades */
+void region_toggle_hidden(struct bContext *C, ARegion *region, bool do_fade);
/* screen_draw.c */
+
+/**
+ * Visual indication of the two areas involved in a proposed join.
+ *
+ * \param sa1: Area from which the resultant originates.
+ * \param sa2: Target area that will be replaced.
+ */
void screen_draw_join_highlight(struct ScrArea *sa1, struct ScrArea *sa2);
-void screen_draw_split_preview(struct ScrArea *area, const eScreenAxis dir_axis, const float fac);
+void screen_draw_split_preview(struct ScrArea *area, eScreenAxis dir_axis, float fac);
/* screen_edit.c */
+
+/**
+ * Empty screen, with 1 dummy area without space-data. Uses window size.
+ */
bScreen *screen_add(struct Main *bmain, const char *name, const rcti *rect);
void screen_data_copy(bScreen *to, bScreen *from);
+/**
+ * Prepare a newly created screen for initializing it as active screen.
+ */
void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new);
void screen_change_update(struct bContext *C, wmWindow *win, bScreen *screen);
+/**
+ * \return the screen to activate.
+ * \warning The returned screen may not always equal \a screen_new!
+ */
void screen_change_prepare(bScreen *screen_old,
bScreen *screen_new,
struct Main *bmain,
@@ -86,14 +111,28 @@ void screen_change_prepare(bScreen *screen_old,
ScrArea *area_split(const wmWindow *win,
bScreen *screen,
ScrArea *area,
- const eScreenAxis dir_axis,
- const float fac,
- const bool merge);
+ eScreenAxis dir_axis,
+ float fac,
+ bool merge);
+/**
+ * Join any two neighboring areas. Might involve complex changes.
+ */
int screen_area_join(struct bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2);
+/**
+ * with `sa_a` as center, `sa_b` is located at: 0=W, 1=N, 2=E, 3=S
+ * -1 = not valid check.
+ * used with join operator.
+ */
eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b);
-void area_getoffsets(
- ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2);
+/**
+ * Get alignment offset of adjacent areas. 'dir' value is like #area_getorientation().
+ */
+void area_getoffsets(ScrArea *sa_a, ScrArea *sa_b, eScreenDir dir, int *r_offset1, int *r_offset2);
+/**
+ * Close a screen area, allowing most-aligned neighbor to take its place.
+ */
bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area);
+void screen_area_spacelink_add(struct Scene *scene, ScrArea *area, eSpace_Type space_type);
struct AZone *ED_area_actionzone_find_xy(ScrArea *area, const int xy[2]);
/* screen_geometry.c */
@@ -104,22 +143,46 @@ ScrVert *screen_geom_vertex_add(bScreen *screen, short x, short y);
ScrEdge *screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2);
ScrEdge *screen_geom_edge_add(bScreen *screen, ScrVert *v1, ScrVert *v2);
bool screen_geom_edge_is_horizontal(ScrEdge *se);
+/**
+ * \param bounds_rect: Either window or screen bounds.
+ * Used to exclude edges along window/screen edges.
+ */
ScrEdge *screen_geom_area_map_find_active_scredge(const struct ScrAreaMap *area_map,
const rcti *bounds_rect,
- const int mx,
- const int my);
+ int mx,
+ int my);
+/**
+ * Need win size to make sure not to include edges along screen edge.
+ */
ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
const bScreen *screen,
- const int mx,
- const int my);
+ int mx,
+ int my);
+/**
+ * \brief Main screen-layout calculation function.
+ *
+ * * Scale areas nicely on window size and DPI changes.
+ * * Ensure areas have a minimum height.
+ * * Correctly set global areas to their fixed height.
+ */
void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen);
+/**
+ * \return 0 if no split is possible, otherwise the screen-coordinate at which to split.
+ */
short screen_geom_find_area_split_point(const ScrArea *area,
const rcti *window_rect,
- const eScreenAxis dir_axis,
+ eScreenAxis dir_axis,
float fac);
+/**
+ * Select all edges that are directly or indirectly connected to \a edge.
+ */
void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge);
/* screen_context.c */
+
+/**
+ * Entry point for the screen context.
+ */
int ed_screen_context(const struct bContext *C,
const char *member,
struct bContextDataResult *result);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 674a2deb929..6581bffb6bd 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -165,7 +165,6 @@ static bool ED_operator_screenactive_norender(bContext *C)
return true;
}
-/* when mouse is over area-edge */
bool ED_operator_screen_mainwinactive(bContext *C)
{
if (CTX_wm_window(C) == NULL) {
@@ -219,6 +218,16 @@ bool ED_operator_objectmode(bContext *C)
return true;
}
+bool ED_operator_objectmode_poll_msg(bContext *C)
+{
+ if (!ED_operator_objectmode(C)) {
+ CTX_wm_operator_poll_msg_set(C, "Only supported in object mode");
+ return false;
+ }
+
+ return true;
+}
+
static bool ed_spacetype_test(bContext *C, int type)
{
if (ED_operator_areaactive(C)) {
@@ -243,7 +252,6 @@ bool ED_operator_region_view3d_active(bContext *C)
return false;
}
-/* generic for any view2d which uses anim_ops */
bool ED_operator_animview_active(bContext *C)
{
if (ED_operator_areaactive(C)) {
@@ -275,21 +283,11 @@ bool ED_operator_outliner_active_no_editobject(bContext *C)
return false;
}
-/**
- * \note Will return true for file spaces in either file or asset browsing mode! See
- * #ED_operator_file_browsing_active() (file browsing only) and
- * #ED_operator_asset_browsing_active() (asset browsing only).
- */
bool ED_operator_file_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_FILE);
}
-/**
- * \note Will only return true if the file space is in file browsing mode, not asset browsing! See
- * #ED_operator_file_active() (file or asset browsing) and
- * #ED_operator_asset_browsing_active() (asset browsing only).
- */
bool ED_operator_file_browsing_active(bContext *C)
{
if (ed_spacetype_test(C, SPACE_FILE)) {
@@ -416,7 +414,6 @@ bool ED_operator_object_active_editable(bContext *C)
return ED_operator_object_active_editable_ex(C, ob);
}
-/** Object must be editable and fully local (i.e. not an override). */
bool ED_operator_object_active_local_editable_ex(bContext *C, const Object *ob)
{
return ED_operator_object_active_editable_ex(C, ob) && !ID_IS_OVERRIDE_LIBRARY(ob);
@@ -516,7 +513,6 @@ bool ED_operator_posemode_exclusive(bContext *C)
return ed_operator_posemode_exclusive_ex(C, obact);
}
-/** Object must be editable, fully local (i.e. not an override), and exclusively in Pose mode. */
bool ED_operator_object_active_local_editable_posemode_exclusive(bContext *C)
{
Object *obact = ED_object_active_context(C);
@@ -533,8 +529,6 @@ bool ED_operator_object_active_local_editable_posemode_exclusive(bContext *C)
return true;
}
-/* allows for pinned pose objects to be used in the object buttons
- * and the non-active pose object to be used in the 3D view */
bool ED_operator_posemode_context(bContext *C)
{
Object *obpose = ED_pose_object_from_context(C);
@@ -574,7 +568,6 @@ bool ED_operator_posemode_local(bContext *C)
return false;
}
-/* wrapper for ED_space_image_show_uvedit */
bool ED_operator_uvedit(bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -773,7 +766,7 @@ static bool actionzone_area_poll(bContext *C)
bScreen *screen = WM_window_get_active_screen(win);
if (screen && win && win->eventstate) {
- const int *xy = &win->eventstate->x;
+ const int *xy = &win->eventstate->xy[0];
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (AZone *, az, &area->actionzones) {
@@ -900,8 +893,7 @@ static AZone *area_actionzone_refresh_xy(ScrArea *area, const int xy[2], const b
ARegion *region = az->region;
View2D *v2d = &region->v2d;
int scroll_flag = 0;
- const int isect_value = UI_view2d_mouse_in_scrollers_ex(
- region, v2d, xy[0], xy[1], &scroll_flag);
+ const int isect_value = UI_view2d_mouse_in_scrollers_ex(region, v2d, xy, &scroll_flag);
/* Check if we even have scroll bars. */
if (((az->direction == AZ_SCROLL_HOR) && !(scroll_flag & V2D_SCROLL_HORIZONTAL)) ||
@@ -1052,7 +1044,7 @@ static void actionzone_apply(bContext *C, wmOperator *op, int type)
event.val = KM_NOTHING;
event.is_repeat = false;
event.customdata = op->customdata;
- event.customdatafree = true;
+ event.customdata_free = true;
op->customdata = NULL;
wm_event_add(win, &event);
@@ -1061,7 +1053,7 @@ static void actionzone_apply(bContext *C, wmOperator *op, int type)
static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
- AZone *az = screen_actionzone_find_xy(screen, &event->x);
+ AZone *az = screen_actionzone_find_xy(screen, event->xy);
/* Quick escape - Scroll azones only hide/unhide the scroll-bars,
* they have their own handling. */
@@ -1073,8 +1065,8 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
sActionzoneData *sad = op->customdata = MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
sad->sa1 = screen_actionzone_area(screen, az);
sad->az = az;
- sad->x = event->x;
- sad->y = event->y;
+ sad->x = event->xy[0];
+ sad->y = event->xy[1];
/* region azone directly reacts on mouse clicks */
if (ELEM(sad->az->type, AZONE_REGION, AZONE_FULLSCREEN)) {
@@ -1098,8 +1090,8 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE: {
- const int delta_x = (event->x - sad->x);
- const int delta_y = (event->y - sad->y);
+ const int delta_x = (event->xy[0] - sad->x);
+ const int delta_y = (event->xy[1] - sad->y);
/* Movement in dominant direction. */
const int delta_max = max_ii(abs(delta_x), abs(delta_y));
@@ -1131,12 +1123,12 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
WM_window_screen_rect_calc(win, &screen_rect);
/* Have we dragged off the zone and are not on an edge? */
- if ((ED_area_actionzone_find_xy(sad->sa1, &event->x) != sad->az) &&
+ if ((ED_area_actionzone_find_xy(sad->sa1, event->xy) != sad->az) &&
(screen_geom_area_map_find_active_scredge(
- AREAMAP_FROM_SCREEN(screen), &screen_rect, event->x, event->y) == NULL)) {
+ AREAMAP_FROM_SCREEN(screen), &screen_rect, event->xy[0], event->xy[1]) == NULL)) {
/* What area are we now in? */
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
if (area == sad->sa1) {
/* Same area, so possible split. */
@@ -1180,7 +1172,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* gesture is large enough? */
if (is_gesture) {
/* second area, for join when (sa1 != sa2) */
- sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
+ sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
/* apply sends event */
actionzone_apply(C, op, sad->az->type);
actionzone_exit(op);
@@ -1248,12 +1240,16 @@ static ScrEdge *screen_area_edge_from_cursor(const bContext *C,
int borderwidth = (4 * UI_DPI_FAC);
ScrArea *sa1, *sa2;
if (screen_geom_edge_is_horizontal(actedge)) {
- sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] + borderwidth);
- sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] - borderwidth);
+ sa1 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0], cursor[1] + borderwidth});
+ sa2 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0], cursor[1] - borderwidth});
}
else {
- sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] + borderwidth, cursor[1]);
- sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] - borderwidth, cursor[1]);
+ sa1 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0] + borderwidth, cursor[1]});
+ sa2 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0] - borderwidth, cursor[1]});
}
bool isGlobal = ((sa1 && ED_area_is_global(sa1)) || (sa2 && ED_area_is_global(sa2)));
if (!isGlobal) {
@@ -1283,7 +1279,7 @@ static ScrEdge *screen_area_edge_from_cursor(const bContext *C,
*
* callbacks:
*
- * invoke() gets called on shift+lmb drag in action-zone
+ * invoke() gets called on Shift-LMB drag in action-zone
* exec() execute without any user interaction, based on properties
* call init(), add handler
*
@@ -1341,7 +1337,7 @@ static int area_swap_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE:
/* second area, for join */
- sad->sa2 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y);
+ sad->sa2 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy);
break;
case LEFTMOUSE: /* release LMB */
if (event->val == KM_RELEASE) {
@@ -1942,8 +1938,8 @@ static int area_move_exec(bContext *C, wmOperator *op)
/* interaction callback */
static int area_move_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- RNA_int_set(op->ptr, "x", event->x);
- RNA_int_set(op->ptr, "y", event->y);
+ RNA_int_set(op->ptr, "x", event->xy[0]);
+ RNA_int_set(op->ptr, "y", event->xy[1]);
if (!area_move_init(C, op)) {
return OPERATOR_PASS_THROUGH;
@@ -1975,7 +1971,7 @@ static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
int x = RNA_int_get(op->ptr, "x");
int y = RNA_int_get(op->ptr, "y");
- const int delta = (md->dir_axis == SCREEN_AXIS_V) ? event->x - x : event->y - y;
+ const int delta = (md->dir_axis == SCREEN_AXIS_V) ? event->xy[0] - x : event->xy[1] - y;
RNA_int_set(op->ptr, "delta", delta);
area_move_apply(C, op);
@@ -2077,7 +2073,7 @@ typedef struct sAreaSplitData {
int bigger, smaller; /* constraints for moving new edge */
int delta; /* delta move edge */
int origmin, origsize; /* to calculate fac, for property storage */
- int previewmode; /* draw previewline, then split */
+ int previewmode; /* draw preview-line, then split. */
void *draw_callback; /* call `screen_draw_split_preview` */
bool do_snap;
@@ -2087,15 +2083,31 @@ typedef struct sAreaSplitData {
} sAreaSplitData;
+static bool area_split_allowed(const ScrArea *area, const eScreenAxis dir_axis)
+{
+ if (!area || area->global) {
+ /* Must be a non-global area. */
+ return false;
+ }
+
+ if ((dir_axis == SCREEN_AXIS_V && area->winx <= 2 * AREAMINX) ||
+ (dir_axis == SCREEN_AXIS_H && area->winy <= 2 * ED_area_headersize())) {
+ /* Must be at least double minimum sizes to split into two. */
+ return false;
+ }
+
+ return true;
+}
+
static void area_split_draw_cb(const struct wmWindow *UNUSED(win), void *userdata)
{
const wmOperator *op = userdata;
sAreaSplitData *sd = op->customdata;
- if (sd->sarea) {
- const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
- float fac = RNA_float_get(op->ptr, "factor");
+ const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
+ if (area_split_allowed(sd->sarea, dir_axis)) {
+ float fac = RNA_float_get(op->ptr, "factor");
screen_draw_split_preview(sd->sarea, dir_axis, fac);
}
}
@@ -2125,18 +2137,6 @@ static bool area_split_init(bContext *C, wmOperator *op)
/* required properties */
const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
- /* minimal size */
- if (dir_axis == SCREEN_AXIS_V) {
- if (area->winx < 2 * AREAMINX) {
- return false;
- }
- }
- else {
- if (area->winy < 2 * ED_area_headersize()) {
- return false;
- }
- }
-
/* custom data */
sAreaSplitData *sd = (sAreaSplitData *)MEM_callocN(sizeof(sAreaSplitData), "op_area_split");
op->customdata = sd;
@@ -2193,6 +2193,10 @@ static bool area_split_apply(bContext *C, wmOperator *op)
float fac = RNA_float_get(op->ptr, "factor");
const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
+ if (!area_split_allowed(sd->sarea, dir_axis)) {
+ return false;
+ }
+
sd->narea = area_split(win, screen, sd->sarea, dir_axis, fac, false); /* false = no merge */
if (sd->narea == NULL) {
@@ -2258,9 +2262,15 @@ static void area_split_exit(bContext *C, wmOperator *op)
static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
{
- wmWindow *win = CTX_wm_window(C);
+ sAreaSplitData *sd = (sAreaSplitData *)op->customdata;
const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
- WM_cursor_set(win, (dir_axis == SCREEN_AXIS_H) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
+ if (area_split_allowed(sd->sarea, dir_axis)) {
+ WM_cursor_set(CTX_wm_window(C),
+ (dir_axis == SCREEN_AXIS_H) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
+ }
+ else {
+ WM_cursor_set(CTX_wm_window(C), WM_CURSOR_STOP);
+ }
}
/* UI callback, adds new handler */
@@ -2295,8 +2305,8 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
/* The factor will be close to 1.0f when near the top-left and the bottom-right corners. */
- const float factor_v = ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy;
- const float factor_h = ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx;
+ const float factor_v = ((float)(event->xy[1] - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy;
+ const float factor_h = ((float)(event->xy[0] - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx;
const bool is_left = factor_v < 0.5f;
const bool is_bottom = factor_h < 0.5f;
const bool is_right = !is_left;
@@ -2334,11 +2344,11 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
dir_axis = RNA_property_enum_get(op->ptr, prop_dir);
if (dir_axis == SCREEN_AXIS_H) {
RNA_property_float_set(
- op->ptr, prop_factor, ((float)(event->x - area->v1->vec.x)) / (float)area->winx);
+ op->ptr, prop_factor, ((float)(event->xy[0] - area->v1->vec.x)) / (float)area->winx);
}
else {
RNA_property_float_set(
- op->ptr, prop_factor, ((float)(event->y - area->v1->vec.y)) / (float)area->winy);
+ op->ptr, prop_factor, ((float)(event->xy[1] - area->v1->vec.y)) / (float)area->winy);
}
if (!area_split_init(C, op)) {
@@ -2353,7 +2363,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
RNA_property_int_get_array(op->ptr, prop_cursor, event_co);
}
else {
- copy_v2_v2_int(event_co, &event->x);
+ copy_v2_v2_int(event_co, event->xy);
}
rcti window_rect;
@@ -2493,7 +2503,8 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (update_factor) {
const eScreenAxis dir_axis = RNA_property_enum_get(op->ptr, prop_dir);
- sd->delta = (dir_axis == SCREEN_AXIS_V) ? event->x - sd->origval : event->y - sd->origval;
+ sd->delta = (dir_axis == SCREEN_AXIS_V) ? event->xy[0] - sd->origval :
+ event->xy[1] - sd->origval;
if (sd->previewmode == 0) {
if (sd->do_snap) {
@@ -2512,8 +2523,11 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (sd->sarea) {
ED_area_tag_redraw(sd->sarea);
}
+
+ area_split_preview_update_cursor(C, op);
+
/* area context not set */
- sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y);
+ sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy);
if (sd->sarea) {
ScrArea *area = sd->sarea;
@@ -2625,8 +2639,8 @@ static int area_max_regionsize(ScrArea *area, ARegion *scalear, AZEdge edge)
dist = BLI_rcti_size_y(&area->totrct);
}
- /* subtractwidth of regions on opposite side
- * prevents dragging regions into other opposite regions */
+ /* Subtract the width of regions on opposite side
+ * prevents dragging regions into other opposite regions. */
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region == scalear) {
continue;
@@ -2702,8 +2716,8 @@ static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event
}
rmd->area = sad->sa1;
rmd->edge = az->edge;
- rmd->origx = event->x;
- rmd->origy = event->y;
+ rmd->origx = event->xy[0];
+ rmd->origy = event->xy[1];
rmd->maxsize = area_max_regionsize(rmd->area, rmd->region, rmd->edge);
/* if not set we do now, otherwise it uses type */
@@ -2790,7 +2804,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
(BLI_rcti_size_x(&rmd->region->v2d.mask) + 1);
const int snap_size_threshold = (U.widget_unit * 2) / aspect;
if (ELEM(rmd->edge, AE_LEFT_TO_TOPRIGHT, AE_RIGHT_TO_TOPLEFT)) {
- delta = event->x - rmd->origx;
+ delta = event->xy[0] - rmd->origx;
if (rmd->edge == AE_LEFT_TO_TOPRIGHT) {
delta = -delta;
}
@@ -2823,7 +2837,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else {
- delta = event->y - rmd->origy;
+ delta = event->xy[1] - rmd->origy;
if (rmd->edge == AE_BOTTOM_TO_TOPLEFT) {
delta = -delta;
}
@@ -2865,7 +2879,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
case LEFTMOUSE:
if (event->val == KM_RELEASE) {
- if (len_manhattan_v2v2_int(&event->x, &rmd->origx) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) {
+ if (len_manhattan_v2v2_int(event->xy, &rmd->origx) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) {
if (rmd->region->flag & RGN_FLAG_HIDDEN) {
region_scale_toggle_hidden(C, rmd);
}
@@ -3079,12 +3093,12 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
float cfra = (float)(CFRA);
- /* init binarytree-list for getting keyframes */
+ /* Initialize binary-tree-list for getting keyframes. */
struct AnimKeylist *keylist = ED_keylist_create();
- /* seed up dummy dopesheet context with flags to perform necessary filtering */
+ /* Speed up dummy dope-sheet context with flags to perform necessary filtering. */
if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) {
- /* only selected channels are included */
+ /* Only selected channels are included. */
ads.filterflag |= ADS_FILTER_ONLYSEL;
}
@@ -3521,7 +3535,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE: {
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
jd->dir = area_getorientation(jd->sa1, jd->sa2);
if (area == jd->sa1) {
@@ -3611,7 +3625,7 @@ static void SCREEN_OT_area_join(wmOperatorType *ot)
static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ScrArea *sa1, *sa2;
- if (screen_area_edge_from_cursor(C, &event->x, &sa1, &sa2) == NULL) {
+ if (screen_area_edge_from_cursor(C, event->xy, &sa1, &sa2) == NULL) {
return OPERATOR_CANCELLED;
}
@@ -3629,7 +3643,7 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent
0,
&ptr);
/* store initial mouse cursor position. */
- RNA_int_set_array(&ptr, "cursor", &event->x);
+ RNA_int_set_array(&ptr, "cursor", event->xy);
RNA_enum_set(&ptr, "direction", SCREEN_AXIS_V);
/* Horizontal Split */
@@ -3642,7 +3656,7 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent
0,
&ptr);
/* store initial mouse cursor position. */
- RNA_int_set_array(&ptr, "cursor", &event->x);
+ RNA_int_set_array(&ptr, "cursor", event->xy);
RNA_enum_set(&ptr, "direction", SCREEN_AXIS_H);
if (sa1 && sa2) {
@@ -3659,7 +3673,7 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent
WM_OP_INVOKE_DEFAULT,
0,
&ptr);
- RNA_int_set_array(&ptr, "cursor", &event->x);
+ RNA_int_set_array(&ptr, "cursor", event->xy);
}
/* Swap just needs two areas. */
@@ -3672,7 +3686,7 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent
WM_OP_EXEC_DEFAULT,
0,
&ptr);
- RNA_int_set_array(&ptr, "cursor", &event->x);
+ RNA_int_set_array(&ptr, "cursor", event->xy);
}
UI_popup_menu_end(C, pup);
@@ -4203,7 +4217,7 @@ static void SCREEN_OT_header_toggle_menus(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Region Context Menu Operator (Header/Footer/Navbar)
+/** \name Region Context Menu Operator (Header/Footer/Navigation-Bar)
* \{ */
static void screen_area_menu_items(ScrArea *area, uiLayout *layout)
@@ -4409,8 +4423,9 @@ static void SCREEN_OT_region_context_menu(wmOperatorType *ot)
*
* Animation Step.
* \{ */
+
static bool screen_animation_region_supports_time_follow(eSpace_Type spacetype,
- eRegionType regiontype)
+ eRegion_Type regiontype)
{
return (regiontype == RGN_TYPE_WINDOW &&
ELEM(spacetype, SPACE_SEQ, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) ||
@@ -4418,7 +4433,7 @@ static bool screen_animation_region_supports_time_follow(eSpace_Type spacetype,
}
static bool match_region_with_redraws(const ScrArea *area,
- eRegionType regiontype,
+ eRegion_Type regiontype,
eScreen_Redraws_Flag redraws,
bool from_anim_edit)
{
@@ -4795,7 +4810,6 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot)
* Animation Playback with Timer.
* \{ */
-/* find window that owns the animation timer */
bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
@@ -4822,7 +4836,6 @@ bScreen *ED_screen_animation_no_scrub(const wmWindowManager *wm)
return NULL;
}
-/* toggle operator */
int ED_screen_animation_play(bContext *C, int sync, int mode)
{
bScreen *screen = CTX_wm_screen(C);
@@ -5055,11 +5068,23 @@ static int userpref_show_exec(bContext *C, wmOperator *op)
int sizex = (500 + UI_NAVIGATION_REGION_WIDTH) * UI_DPI_FAC;
int sizey = 520 * UI_DPI_FAC;
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "section");
+ if (prop && RNA_property_is_set(op->ptr, prop)) {
+ /* Set active section via RNA, so it can fail properly. */
+
+ PointerRNA pref_ptr;
+ RNA_pointer_create(NULL, &RNA_Preferences, &U, &pref_ptr);
+ PropertyRNA *active_section_prop = RNA_struct_find_property(&pref_ptr, "active_section");
+
+ RNA_property_enum_set(&pref_ptr, active_section_prop, RNA_property_enum_get(op->ptr, prop));
+ RNA_property_update(C, &pref_ptr, active_section_prop);
+ }
+
/* changes context! */
if (WM_window_open(C,
IFACE_("Blender Preferences"),
- event->x,
- event->y,
+ event->xy[0],
+ event->xy[1],
sizex,
sizey,
SPACE_USERPREF,
@@ -5088,14 +5113,24 @@ static int userpref_show_exec(bContext *C, wmOperator *op)
static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
- ot->name = "Show Preferences";
+ ot->name = "Open Preferences...";
ot->description = "Edit user preferences and system settings";
ot->idname = "SCREEN_OT_userpref_show";
/* api callbacks */
ot->exec = userpref_show_exec;
ot->poll = ED_operator_screenactive_nobackground; /* Not in background as this opens a window. */
+
+ prop = RNA_def_enum(ot->srna,
+ "section",
+ rna_enum_preference_section_items,
+ 0,
+ "",
+ "Section to activate in the Preferences");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/** \} */
@@ -5125,8 +5160,8 @@ static int drivers_editor_show_exec(bContext *C, wmOperator *op)
/* changes context! */
if (WM_window_open(C,
IFACE_("Blender Drivers Editor"),
- event->x,
- event->y,
+ event->xy[0],
+ event->xy[1],
sizex,
sizey,
SPACE_GRAPH,
@@ -5194,8 +5229,8 @@ static int info_log_show_exec(bContext *C, wmOperator *op)
/* changes context! */
if (WM_window_open(C,
IFACE_("Blender Info Log"),
- event->x,
- event->y + shift_y,
+ event->xy[0],
+ event->xy[1] + shift_y,
sizex,
sizey,
SPACE_INFO,
@@ -5352,9 +5387,6 @@ static void region_blend_end(bContext *C, ARegion *region, const bool is_running
WM_event_remove_timer(CTX_wm_manager(C), NULL, region->regiontimer); /* frees rgi */
region->regiontimer = NULL;
}
-/**
- * \note Assumes that \a region itself is not a split version from previous region.
- */
void ED_region_visibility_change_update_animated(bContext *C, ScrArea *area, ARegion *region)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -5662,7 +5694,6 @@ static void SCREEN_OT_workspace_cycle(wmOperatorType *ot)
/** \name Assigning Operator Types
* \{ */
-/* called in spacetypes.c */
void ED_operatortypes_screen(void)
{
/* Generic UI stuff. */
@@ -5739,7 +5770,7 @@ static void keymap_modal_set(wmKeyConfig *keyconf)
static bool blend_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_PATH) {
- if (drag->icon == ICON_FILE_BLEND) {
+ if (ELEM(drag->icon, ICON_FILE_BLEND, ICON_BLENDER)) {
return true;
}
}
@@ -5752,7 +5783,6 @@ static void blend_file_drop_copy(wmDrag *drag, wmDropBox *drop)
RNA_string_set(drop->ptr, "filepath", drag->path);
}
-/* called in spacetypes.c */
void ED_keymap_screen(wmKeyConfig *keyconf)
{
/* Screen Editing ------------------------------------------------ */
diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c
index 733e8b694a6..4cad97652dd 100644
--- a/source/blender/editors/screen/screen_user_menu.c
+++ b/source/blender/editors/screen/screen_user_menu.c
@@ -111,7 +111,7 @@ bUserMenu *ED_screen_user_menu_ensure(bContext *C)
bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(ListBase *lb,
const wmOperatorType *ot,
IDProperty *prop,
- short opcontext)
+ wmOperatorCallContext opcontext)
{
LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
if (umi->type == USER_MENU_TYPE_OPERATOR) {
@@ -160,7 +160,7 @@ void ED_screen_user_menu_item_add_operator(ListBase *lb,
const char *ui_name,
const wmOperatorType *ot,
const IDProperty *prop,
- short opcontext)
+ wmOperatorCallContext opcontext)
{
bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)BKE_blender_user_menu_item_add(
lb, USER_MENU_TYPE_OPERATOR);
@@ -234,7 +234,7 @@ static void screen_user_menu_draw(const bContext *C, Menu *menu)
}
else {
if (show_missing) {
- SNPRINTF(label, "Missing: %s", umi_op->op_idname);
+ SNPRINTF(label, TIP_("Missing: %s"), umi_op->op_idname);
uiItemL(menu->layout, label, ICON_NONE);
}
}
@@ -248,7 +248,7 @@ static void screen_user_menu_draw(const bContext *C, Menu *menu)
}
else {
if (show_missing) {
- SNPRINTF(label, "Missing: %s", umi_mt->mt_idname);
+ SNPRINTF(label, TIP_("Missing: %s"), umi_mt->mt_idname);
uiItemL(menu->layout, label, ICON_NONE);
}
}
@@ -290,7 +290,7 @@ static void screen_user_menu_draw(const bContext *C, Menu *menu)
}
if (!ok) {
if (show_missing) {
- SNPRINTF(label, "Missing: %s.%s", umi_pr->context_data_path, umi_pr->prop_id);
+ SNPRINTF(label, TIP_("Missing: %s.%s"), umi_pr->context_data_path, umi_pr->prop_id);
uiItemL(menu->layout, label, ICON_NONE);
}
}
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index bc1c15abb96..4bc9f1e2565 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -166,7 +166,7 @@ static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (use_crop) {
area = CTX_wm_area(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area_test = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
+ ScrArea *area_test = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
if (area_test != NULL) {
area = area_test;
}
@@ -179,8 +179,9 @@ static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* extension is added by 'screenshot_check' after */
char filepath[FILE_MAX] = "//screen";
- if (G.relbase_valid) {
- BLI_strncpy(filepath, BKE_main_blendfile_path_from_global(), sizeof(filepath));
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] != '\0') {
+ BLI_strncpy(filepath, blendfile_path, sizeof(filepath));
BLI_path_extension_replace(filepath, sizeof(filepath), ""); /* strip '.blend' */
}
RNA_string_set(op->ptr, "filepath", filepath);
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 4b81e713080..6e69c82ba67 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -112,15 +112,6 @@ static WorkSpaceLayout *workspace_change_get_new_layout(Main *bmain,
bmain, workspace_new, layout_new, layout_old, win);
}
-/**
- * \brief Change the active workspace.
- *
- * Operator call, WM + Window + screen already existed before
- * Pretty similar to #ED_screen_change since changing workspace also changes screen.
- *
- * \warning Do NOT call in area/region queues!
- * \returns if workspace changing was successful.
- */
bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager *wm, wmWindow *win)
{
Main *bmain = CTX_data_main(C);
@@ -160,10 +151,6 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager
return true;
}
-/**
- * Duplicate a workspace including its layouts. Does not activate the workspace, but
- * it stores the screen-layout to be activated (BKE_workspace_temp_layout_store)
- */
WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindow *win)
{
WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook);
@@ -187,9 +174,6 @@ WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindo
return workspace_new;
}
-/**
- * \return if succeeded.
- */
bool ED_workspace_delete(WorkSpace *workspace, Main *bmain, bContext *C, wmWindowManager *wm)
{
if (BLI_listbase_is_single(&bmain->workspaces)) {
@@ -220,10 +204,6 @@ bool ED_workspace_delete(WorkSpace *workspace, Main *bmain, bContext *C, wmWindo
return true;
}
-/**
- * Some editor data may need to be synced with scene data (3D View camera and layers).
- * This function ensures data is synced for editors in active layout of \a workspace.
- */
void ED_workspace_scene_data_sync(WorkSpaceInstanceHook *hook, Scene *scene)
{
bScreen *screen = BKE_workspace_active_screen_get(hook);
@@ -393,7 +373,7 @@ static void workspace_append_button(uiLayout *layout,
const Main *from_main)
{
const ID *id = (ID *)workspace;
- const char *filepath = from_main->name;
+ const char *filepath = from_main->filepath;
if (strlen(filepath) == 0) {
filepath = BLO_EMBEDDED_STARTUP_BLEND;
@@ -515,7 +495,7 @@ static void WORKSPACE_OT_reorder_to_back(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Workspace Reorder to Back";
- ot->description = "Reorder workspace to be first in the list";
+ ot->description = "Reorder workspace to be last in the list";
ot->idname = "WORKSPACE_OT_reorder_to_back";
/* api callbacks */
diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c
index 0ec32da0404..e34c4f96aa3 100644
--- a/source/blender/editors/screen/workspace_layout_edit.c
+++ b/source/blender/editors/screen/workspace_layout_edit.c
@@ -37,9 +37,6 @@
#include "screen_intern.h"
-/**
- * Empty screen, with 1 dummy area without space-data. Uses window size.
- */
WorkSpaceLayout *ED_workspace_layout_add(Main *bmain,
WorkSpace *workspace,
wmWindow *win,
@@ -129,10 +126,6 @@ static WorkSpaceLayout *workspace_layout_delete_find_new(const WorkSpaceLayout *
return NULL;
}
-/**
- * \warning Only call outside of area/region loops!
- * \return true if succeeded.
- */
bool ED_workspace_layout_delete(WorkSpace *workspace, WorkSpaceLayout *layout_old, bContext *C)
{
const bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old);
@@ -183,12 +176,6 @@ static bool screen_is_used_by_other_window(const wmWindow *win, const bScreen *s
return BKE_screen_is_used(screen) && (screen->winid != win->winid);
}
-/**
- * Make sure there is a non-fullscreen layout to switch to that is not used yet by an other window.
- * Needed for workspace or screen switching to ensure valid screens.
- *
- * \param layout_fallback_base: As last resort, this layout is duplicated and returned.
- */
WorkSpaceLayout *ED_workspace_screen_change_ensure_unused_layout(
Main *bmain,
WorkSpace *workspace,
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 3b668a1bd4c..b15b6784d34 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../gpu
../../imbuf
../../makesdna
+ ../../nodes
../../makesrna
../../render
../../windowmanager
@@ -44,6 +45,7 @@ set(SRC
paint_hide.c
paint_image.c
paint_image_2d.c
+ paint_image_2d_curve_mask.cc
paint_image_proj.c
paint_mask.c
paint_ops.c
@@ -58,6 +60,7 @@ set(SRC
sculpt.c
sculpt_automasking.c
sculpt_boundary.c
+ sculpt_brush_types.c
sculpt_cloth.c
sculpt_detail.c
sculpt_dyntopo.c
@@ -70,6 +73,7 @@ set(SRC
sculpt_mask_expand.c
sculpt_mask_init.c
sculpt_multiplane_scrape.c
+ sculpt_ops.c
sculpt_paint_color.c
sculpt_pose.c
sculpt_smooth.c
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index ab2b2f4b16b..4010b87a2ed 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -47,6 +47,8 @@
#include "BKE_object.h"
#include "BKE_paint.h"
+#include "NOD_texture.h"
+
#include "WM_api.h"
#include "wm_cursors.h"
@@ -98,7 +100,6 @@ static TexSnapshot primary_snap = {0};
static TexSnapshot secondary_snap = {0};
static CursorSnapshot cursor_snap = {0};
-/* Delete overlay cursor textures to preserve memory and invalidate all overlay flags. */
void paint_cursor_delete_textures(void)
{
if (primary_snap.overlay_texture) {
@@ -1103,7 +1104,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr,
float location[3], symm_rot_mat[4][4];
for (int i = 0; i <= symm; i++) {
- if (i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
+ if (i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (!ELEM(i, 3, 5))))) {
/* Axis Symmetry. */
flip_v3_v3(location, true_location, (char)i);
diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c
index dbe522bf304..0b59e519f70 100644
--- a/source/blender/editors/sculpt_paint/paint_curve_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c
@@ -147,7 +147,6 @@ static void paintcurve_undosys_foreach_ID_ref(UndoStep *us_p,
foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->pc_ref));
}
-/* Export for ED_undo_sys. */
void ED_paintcurve_undosys_type(UndoType *ut)
{
ut->name = "Paint Curve";
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index b5113681955..a912bb5cf3b 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -56,6 +56,8 @@
#include "BKE_paint.h"
#include "BKE_undo_system.h"
+#include "NOD_texture.h"
+
#include "DEG_depsgraph.h"
#include "UI_interface.h"
@@ -87,7 +89,7 @@
* Maybe it should be exposed as part of the paint operation,
* but for now just give a public interface.
*/
-static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
+static ImagePaintPartialRedraw imapaintpartial = {{0}};
ImagePaintPartialRedraw *get_imapaintpartial(void)
{
@@ -103,7 +105,7 @@ void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr)
void ED_imapaint_clear_partial_redraw(void)
{
- memset(&imapaintpartial, 0, sizeof(imapaintpartial));
+ BLI_rcti_init_minmax(&imapaintpartial.dirty_region);
}
void imapaint_region_tiles(
@@ -132,19 +134,9 @@ void ED_imapaint_dirty_region(
return;
}
- if (!imapaintpartial.enabled) {
- imapaintpartial.x1 = x;
- imapaintpartial.y1 = y;
- imapaintpartial.x2 = x + w;
- imapaintpartial.y2 = y + h;
- imapaintpartial.enabled = 1;
- }
- else {
- imapaintpartial.x1 = min_ii(imapaintpartial.x1, x);
- imapaintpartial.y1 = min_ii(imapaintpartial.y1, y);
- imapaintpartial.x2 = max_ii(imapaintpartial.x2, x + w);
- imapaintpartial.y2 = max_ii(imapaintpartial.y2, y + h);
- }
+ rcti rect_to_merge;
+ BLI_rcti_init(&rect_to_merge, x, x + w, y, y + h);
+ BLI_rcti_do_minmax_rcti(&imapaintpartial.dirty_region, &rect_to_merge);
imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
@@ -167,27 +159,30 @@ void ED_imapaint_dirty_region(
void imapaint_image_update(
SpaceImage *sima, Image *image, ImBuf *ibuf, ImageUser *iuser, short texpaint)
{
- if (imapaintpartial.x1 != imapaintpartial.x2 && imapaintpartial.y1 != imapaintpartial.y2) {
- IMB_partial_display_buffer_update_delayed(
- ibuf, imapaintpartial.x1, imapaintpartial.y1, imapaintpartial.x2, imapaintpartial.y2);
+ if (BLI_rcti_is_empty(&imapaintpartial.dirty_region)) {
+ return;
}
if (ibuf->mipmap[0]) {
ibuf->userflags |= IB_MIPMAP_INVALID;
}
+ IMB_partial_display_buffer_update_delayed(ibuf,
+ imapaintpartial.dirty_region.xmin,
+ imapaintpartial.dirty_region.ymin,
+ imapaintpartial.dirty_region.xmax,
+ imapaintpartial.dirty_region.ymax);
+
/* TODO: should set_tpage create ->rect? */
if (texpaint || (sima && sima->lock)) {
- int w = imapaintpartial.x2 - imapaintpartial.x1;
- int h = imapaintpartial.y2 - imapaintpartial.y1;
- if (w && h) {
- /* Testing with partial update in uv editor too */
- BKE_image_update_gputexture(image, iuser, imapaintpartial.x1, imapaintpartial.y1, w, h);
- }
+ const int w = BLI_rcti_size_x(&imapaintpartial.dirty_region);
+ const int h = BLI_rcti_size_y(&imapaintpartial.dirty_region);
+ /* Testing with partial update in uv editor too */
+ BKE_image_update_gputexture(
+ image, iuser, imapaintpartial.dirty_region.xmin, imapaintpartial.dirty_region.ymin, w, h);
}
}
-/* paint blur kernels. Projective painting enforces use of a 2x2 kernel due to lagging */
BlurKernel *paint_new_blur_kernel(Brush *br, bool proj)
{
int i, j;
@@ -799,11 +794,6 @@ static void toggle_paint_cursor(Scene *scene, bool enable)
}
}
-/* enable the paint cursor if it isn't already.
- *
- * purpose is to make sure the paint cursor is shown if paint
- * mode is enabled in the image editor. the paint poll will
- * ensure that the cursor is hidden when not in paint mode */
void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
{
ToolSettings *settings = scene->toolsettings;
@@ -863,8 +853,8 @@ static int grab_clone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
cmv = MEM_callocN(sizeof(GrabClone), "GrabClone");
copy_v2_v2(cmv->startoffset, brush->clone.offset);
- cmv->startx = event->x;
- cmv->starty = event->y;
+ cmv->startx = event->xy[0];
+ cmv->starty = event->xy[1];
op->customdata = cmv;
WM_event_add_modal_handler(C, op);
@@ -890,7 +880,7 @@ static int grab_clone_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* mouse moved, so move the clone image */
UI_view2d_region_to_view(
&region->v2d, cmv->startx - xmin, cmv->starty - ymin, &startfx, &startfy);
- UI_view2d_region_to_view(&region->v2d, event->x - xmin, event->y - ymin, &fx, &fy);
+ UI_view2d_region_to_view(&region->v2d, event->xy[0] - xmin, event->xy[1] - ymin, &fx, &fy);
delta[0] = fx - startfx;
delta[1] = fy - startfy;
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index a35e248a78c..4c54d3b3b5e 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -78,12 +78,13 @@ typedef struct BrushPainterCache {
ImBuf *ibuf;
ImBuf *texibuf;
- ushort *curve_mask;
ushort *tex_mask;
ushort *tex_mask_old;
uint tex_mask_old_w;
uint tex_mask_old_h;
+ CurveMaskCache curve_mask_cache;
+
int image_size[2];
} BrushPainterCache;
@@ -169,9 +170,6 @@ static void brush_painter_2d_require_imbuf(
if (cache->ibuf) {
IMB_freeImBuf(cache->ibuf);
}
- if (cache->curve_mask) {
- MEM_freeN(cache->curve_mask);
- }
if (cache->tex_mask) {
MEM_freeN(cache->tex_mask);
}
@@ -179,7 +177,6 @@ static void brush_painter_2d_require_imbuf(
MEM_freeN(cache->tex_mask_old);
}
cache->ibuf = NULL;
- cache->curve_mask = NULL;
cache->tex_mask = NULL;
cache->lastdiameter = -1; /* force ibuf create in refresh */
cache->invert = invert;
@@ -200,9 +197,7 @@ static void brush_painter_cache_2d_free(BrushPainterCache *cache)
if (cache->texibuf) {
IMB_freeImBuf(cache->texibuf);
}
- if (cache->curve_mask) {
- MEM_freeN(cache->curve_mask);
- }
+ paint_curve_mask_cache_free_data(&cache->curve_mask_cache);
if (cache->tex_mask) {
MEM_freeN(cache->tex_mask);
}
@@ -380,79 +375,6 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
cache->tex_mask_old_h = diameter;
}
-/* create a mask with the falloff strength */
-static ushort *brush_painter_curve_mask_new(BrushPainter *painter,
- int diameter,
- float radius,
- const float pos[2])
-{
- Brush *brush = painter->brush;
-
- int offset = (int)floorf(diameter / 2.0f);
-
- ushort *mask, *m;
-
- mask = MEM_mallocN(sizeof(ushort) * diameter * diameter, "brush_painter_mask");
- m = mask;
-
- int aa_samples = 1.0f / (radius * 0.20f);
- if (brush->sampling_flag & BRUSH_PAINT_ANTIALIASING) {
- aa_samples = clamp_i(aa_samples, 3, 16);
- }
- else {
- aa_samples = 1;
- }
-
- /* Temporal until we have the brush properties */
- const float hardness = 1.0f;
- const float rotation = 0.0f;
-
- float aa_offset = 1.0f / (2.0f * (float)aa_samples);
- float aa_step = 1.0f / (float)aa_samples;
-
- float bpos[2];
- bpos[0] = pos[0] - floorf(pos[0]) + offset - aa_offset;
- bpos[1] = pos[1] - floorf(pos[1]) + offset - aa_offset;
-
- const float co = cosf(DEG2RADF(rotation));
- const float si = sinf(DEG2RADF(rotation));
-
- float norm_factor = 65535.0f / (float)(aa_samples * aa_samples);
-
- for (int y = 0; y < diameter; y++) {
- for (int x = 0; x < diameter; x++, m++) {
- float total_samples = 0;
- for (int i = 0; i < aa_samples; i++) {
- for (int j = 0; j < aa_samples; j++) {
- float pixel_xy[2] = {x + (aa_step * i), y + (aa_step * j)};
- float xy_rot[2];
- sub_v2_v2(pixel_xy, bpos);
-
- xy_rot[0] = co * pixel_xy[0] - si * pixel_xy[1];
- xy_rot[1] = si * pixel_xy[0] + co * pixel_xy[1];
-
- float len = len_v2(xy_rot);
- float p = len / radius;
- if (hardness < 1.0f) {
- p = (p - hardness) / (1.0f - hardness);
- p = 1.0f - p;
- CLAMP(p, 0.0f, 1.0f);
- }
- else {
- p = 1.0;
- }
- float hardness_factor = 3.0f * p * p - 2.0f * p * p * p;
- float curve = BKE_brush_curve_strength_clamped(brush, len, radius);
- total_samples += curve * hardness_factor;
- }
- }
- *m = (ushort)(total_samples * norm_factor);
- }
- }
-
- return mask;
-}
-
/* create imbuf with brush color */
static ImBuf *brush_painter_imbuf_new(
BrushPainter *painter, ImagePaintTile *tile, const int size, float pressure, float distance)
@@ -858,10 +780,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
}
}
- /* curve mask can only change if the size changes */
- MEM_SAFE_FREE(cache->curve_mask);
-
- cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size, pos);
+ /* Re-initialize the curve mask. Mask is always recreated due to the change of position. */
+ paint_curve_mask_cache_update(&cache->curve_mask_cache, brush, diameter, size, pos);
/* detect if we need to recreate image brush buffer */
if (diameter != cache->lastdiameter || (tex_rotation != cache->last_tex_rotation) || do_random ||
@@ -916,8 +836,6 @@ static bool paint_2d_ensure_tile_canvas(ImagePaintState *s, int i)
s->tiles[i].cache.lastdiameter = -1;
- s->tiles[i].iuser.ok = true;
-
ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, &s->tiles[i].iuser, NULL);
if (ibuf != NULL) {
if (ibuf->channels != 4) {
@@ -1327,7 +1245,7 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
&tmpbuf,
frombuf,
mask,
- tile->cache.curve_mask,
+ tile->cache.curve_mask_cache.curve_mask,
tile->cache.tex_mask,
mask_max,
region->destx,
@@ -1476,7 +1394,7 @@ static int paint_2d_op(void *state,
canvas,
frombuf,
NULL,
- tile->cache.curve_mask,
+ tile->cache.curve_mask_cache.curve_mask,
tile->cache.tex_mask,
mask_max,
region[a].destx,
@@ -1683,7 +1601,6 @@ void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
for (int i = 0; i < s->num_tiles; i++) {
s->tiles[i].iuser = sima->iuser;
}
- s->tiles[0].iuser.ok = true;
zero_v2(s->tiles[0].uv_origin);
@@ -1860,7 +1777,6 @@ static ImageUser *paint_2d_get_tile_iuser(ImagePaintState *s, int tile_number)
return iuser;
}
-/* this function expects linear space color values */
void paint_2d_bucket_fill(const bContext *C,
const float color[3],
Brush *br,
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc b/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc
new file mode 100644
index 00000000000..8d57a3d9152
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc
@@ -0,0 +1,188 @@
+/*
+ * 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 ed
+ */
+
+#include "BLI_math.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_brush_types.h"
+
+#include "BKE_brush.h"
+
+#include "paint_intern.h"
+
+namespace blender::ed::sculpt_paint {
+
+constexpr int AntiAliasingSamplesPerTexelAxisMin = 3;
+constexpr int AntiAliasingSamplesPerTexelAxisMax = 16;
+/**
+ * \brief Number of samples to use between 0..1.
+ */
+constexpr int CurveSamplesBaseLen = 1024;
+/**
+ * \brief Number of samples to store in the cache.
+ *
+ * M_SQRT2 is used as brushes are circles and the curve_mask is square.
+ * + 1 to fix floating rounding issues.
+ */
+constexpr int CurveSamplesLen = M_SQRT2 * CurveSamplesBaseLen + 1;
+
+static int aa_samples_per_texel_axis(const Brush *brush, const float radius)
+{
+ int aa_samples = 1.0f / (radius * 0.20f);
+ if (brush->sampling_flag & BRUSH_PAINT_ANTIALIASING) {
+ aa_samples = clamp_i(
+ aa_samples, AntiAliasingSamplesPerTexelAxisMin, AntiAliasingSamplesPerTexelAxisMax);
+ }
+ else {
+ aa_samples = 1;
+ }
+ return aa_samples;
+}
+
+/* create a mask with the falloff strength */
+static void update_curve_mask(CurveMaskCache *curve_mask_cache,
+ const Brush *brush,
+ const int diameter,
+ const float radius,
+ const float cursor_position[2])
+{
+ BLI_assert(curve_mask_cache->curve_mask != nullptr);
+ int offset = (int)floorf(diameter / 2.0f);
+
+ unsigned short *m = curve_mask_cache->curve_mask;
+
+ const int aa_samples = aa_samples_per_texel_axis(brush, radius);
+ const float aa_offset = 1.0f / (2.0f * (float)aa_samples);
+ const float aa_step = 1.0f / (float)aa_samples;
+
+ float bpos[2];
+ bpos[0] = cursor_position[0] - floorf(cursor_position[0]) + offset;
+ bpos[1] = cursor_position[1] - floorf(cursor_position[1]) + offset;
+
+ float weight_factor = 65535.0f / (float)(aa_samples * aa_samples);
+
+ for (int y = 0; y < diameter; y++) {
+ for (int x = 0; x < diameter; x++, m++) {
+ float pixel_xy[2];
+ pixel_xy[0] = static_cast<float>(x) + aa_offset;
+ float total_weight = 0;
+
+ for (int i = 0; i < aa_samples; i++) {
+ pixel_xy[1] = static_cast<float>(y) + aa_offset;
+ for (int j = 0; j < aa_samples; j++) {
+ const float len = len_v2v2(pixel_xy, bpos);
+ const int sample_index = min_ii((len / radius) * CurveSamplesBaseLen,
+ CurveSamplesLen - 1);
+ const float sample_weight = curve_mask_cache->sampled_curve[sample_index];
+
+ total_weight += sample_weight;
+
+ pixel_xy[1] += aa_step;
+ }
+ pixel_xy[0] += aa_step;
+ }
+ *m = (unsigned short)(total_weight * weight_factor);
+ }
+ }
+}
+
+static bool is_sampled_curve_valid(const CurveMaskCache *curve_mask_cache, const Brush *brush)
+{
+ if (curve_mask_cache->sampled_curve == nullptr) {
+ return false;
+ }
+ return curve_mask_cache->last_curve_timestamp == brush->curve->changed_timestamp;
+}
+
+static void sampled_curve_free(CurveMaskCache *curve_mask_cache)
+{
+ MEM_SAFE_FREE(curve_mask_cache->sampled_curve);
+ curve_mask_cache->last_curve_timestamp = 0;
+}
+
+static void update_sampled_curve(CurveMaskCache *curve_mask_cache, const Brush *brush)
+{
+ if (curve_mask_cache->sampled_curve == nullptr) {
+ curve_mask_cache->sampled_curve = static_cast<float *>(
+ MEM_mallocN(CurveSamplesLen * sizeof(float), __func__));
+ }
+
+ for (int i = 0; i < CurveSamplesLen; i++) {
+ const float len = i / float(CurveSamplesBaseLen);
+ const float sample_weight = BKE_brush_curve_strength_clamped(brush, len, 1.0f);
+ curve_mask_cache->sampled_curve[i] = sample_weight;
+ }
+ curve_mask_cache->last_curve_timestamp = brush->curve->changed_timestamp;
+}
+
+static size_t diameter_to_curve_mask_size(const int diameter)
+{
+ return diameter * diameter * sizeof(ushort);
+}
+
+static bool is_curve_mask_size_valid(const CurveMaskCache *curve_mask_cache, const int diameter)
+{
+ return curve_mask_cache->curve_mask_size == diameter_to_curve_mask_size(diameter);
+}
+
+static void curve_mask_free(CurveMaskCache *curve_mask_cache)
+{
+ curve_mask_cache->curve_mask_size = 0;
+ MEM_SAFE_FREE(curve_mask_cache->curve_mask);
+}
+
+static void curve_mask_allocate(CurveMaskCache *curve_mask_cache, const int diameter)
+{
+ const size_t curve_mask_size = diameter_to_curve_mask_size(diameter);
+ curve_mask_cache->curve_mask = static_cast<unsigned short *>(
+ MEM_mallocN(curve_mask_size, __func__));
+ curve_mask_cache->curve_mask_size = curve_mask_size;
+}
+
+} // namespace blender::ed::sculpt_paint
+
+using namespace blender::ed::sculpt_paint;
+
+void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache)
+{
+ sampled_curve_free(curve_mask_cache);
+ curve_mask_free(curve_mask_cache);
+}
+
+void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache,
+ const Brush *brush,
+ const int diameter,
+ const float radius,
+ const float cursor_position[2])
+{
+ if (!is_sampled_curve_valid(curve_mask_cache, brush)) {
+ update_sampled_curve(curve_mask_cache, brush);
+ }
+
+ if (!is_curve_mask_size_valid(curve_mask_cache, diameter)) {
+ curve_mask_free(curve_mask_cache);
+ curve_mask_allocate(curve_mask_cache, diameter);
+ }
+ update_curve_mask(curve_mask_cache, brush, diameter, radius, cursor_position);
+}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 0176b4a1b13..ca012f20f01 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -414,6 +414,7 @@ typedef struct ProjPaintState {
int totvert_eval;
const MVert *mvert_eval;
+ const float (*vert_normals)[3];
const MEdge *medge_eval;
const MPoly *mpoly_eval;
const MLoop *mloop_eval;
@@ -1718,10 +1719,10 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
float no[3], angle_cos;
if (mp->flag & ME_SMOOTH) {
- const short *no1, *no2, *no3;
- no1 = ps->mvert_eval[lt_vtri[0]].no;
- no2 = ps->mvert_eval[lt_vtri[1]].no;
- no3 = ps->mvert_eval[lt_vtri[2]].no;
+ const float *no1, *no2, *no3;
+ no1 = ps->vert_normals[lt_vtri[0]];
+ no2 = ps->vert_normals[lt_vtri[1]];
+ no3 = ps->vert_normals[lt_vtri[2]];
no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0];
no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1];
@@ -3125,7 +3126,8 @@ static void project_paint_face_init(const ProjPaintState *ps,
uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
}
- /* a pity we need to get the worldspace pixel location here */
+ /* A pity we need to get the world-space pixel location here
+ * because it is a relatively expensive operation. */
if (do_clip || do_3d_mapping) {
interp_v3_v3v3v3(wco,
ps->mvert_eval[lt_vtri[0]].co,
@@ -3208,7 +3210,10 @@ static void project_paint_face_init(const ProjPaintState *ps,
else {
/* we have a seam - deal with it! */
- /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in perspective view */
+ /* Inset face coords.
+ * - screen-space in orthographic view.
+ * - world-space in perspective view.
+ */
float insetCos[3][3];
/* Vertex screen-space coords. */
@@ -3373,8 +3378,8 @@ static void project_paint_face_init(const ProjPaintState *ps,
if ((ps->do_occlude == false) ||
!project_bucket_point_occluded(
ps, bucketFaceNodes, tri_index, pixel_on_edge)) {
- /* a pity we need to get the worldspace
- * pixel location here */
+ /* A pity we need to get the world-space pixel location here
+ * because it is a relatively expensive operation. */
if (do_clip || do_3d_mapping) {
interp_v3_v3v3v3(wco, vCo[0], vCo[1], vCo[2], w);
@@ -3867,7 +3872,6 @@ static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int di
static void proj_paint_state_cavity_init(ProjPaintState *ps)
{
- const MVert *mv;
const MEdge *me;
float *cavities;
int a;
@@ -3887,13 +3891,11 @@ static void proj_paint_state_cavity_init(ProjPaintState *ps)
sub_v3_v3(edges[me->v1], e);
counter[me->v1]++;
}
- for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
+ for (a = 0; a < ps->totvert_eval; a++) {
if (counter[a] > 0) {
- float no[3];
mul_v3_fl(edges[a], 1.0f / counter[a]);
- normal_short_to_float_v3(no, mv->no);
/* Augment the difference. */
- cavities[a] = saacos(10.0f * dot_v3v3(no, edges[a])) * (float)M_1_PI;
+ cavities[a] = saacos(10.0f * dot_v3v3(ps->vert_normals[a], edges[a])) * (float)M_1_PI;
}
else {
cavities[a] = 0.0;
@@ -3960,7 +3962,7 @@ static void proj_paint_state_vert_flags_init(ProjPaintState *ps)
ps->vertFlags = MEM_callocN(sizeof(char) * ps->totvert_eval, "paint-vertFlags");
for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
- normal_short_to_float_v3(no, mv->no);
+ copy_v3_v3(no, ps->vert_normals[a]);
if (UNLIKELY(ps->is_flip_object)) {
negate_v3(no);
}
@@ -4060,6 +4062,7 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p
ps->mat_array[totmat - 1] = NULL;
ps->mvert_eval = ps->me_eval->mvert;
+ ps->vert_normals = BKE_mesh_vertex_normals_ensure(ps->me_eval);
if (ps->do_mask_cavity) {
ps->medge_eval = ps->me_eval->medge;
}
@@ -4130,8 +4133,9 @@ static bool project_paint_clone_face_skip(ProjPaintState *ps,
if (ps->do_material_slots) {
if (lc->slot_clone != lc->slot_last_clone) {
- if (!slot->uvname || !(lc->mloopuv_clone_base = CustomData_get_layer_named(
- &ps->me_eval->ldata, CD_MLOOPUV, lc->slot_clone->uvname))) {
+ if (!lc->slot_clone->uvname ||
+ !(lc->mloopuv_clone_base = CustomData_get_layer_named(
+ &ps->me_eval->ldata, CD_MLOOPUV, lc->slot_clone->uvname))) {
lc->mloopuv_clone_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
}
lc->slot_last_clone = lc->slot_clone;
@@ -4644,13 +4648,7 @@ static void project_paint_end(ProjPaintState *ps)
/* 1 = an undo, -1 is a redo. */
static void partial_redraw_single_init(ImagePaintPartialRedraw *pr)
{
- pr->x1 = INT_MAX;
- pr->y1 = INT_MAX;
-
- pr->x2 = -1;
- pr->y2 = -1;
-
- pr->enabled = 1;
+ BLI_rcti_init_minmax(&pr->dirty_region);
}
static void partial_redraw_array_init(ImagePaintPartialRedraw *pr)
@@ -4666,16 +4664,11 @@ static bool partial_redraw_array_merge(ImagePaintPartialRedraw *pr,
ImagePaintPartialRedraw *pr_other,
int tot)
{
- bool touch = 0;
+ bool touch = false;
while (tot--) {
- pr->x1 = min_ii(pr->x1, pr_other->x1);
- pr->y1 = min_ii(pr->y1, pr_other->y1);
-
- pr->x2 = max_ii(pr->x2, pr_other->x2);
- pr->y2 = max_ii(pr->y2, pr_other->y2);
-
- if (pr->x2 != -1) {
- touch = 1;
+ BLI_rcti_do_minmax_rcti(&pr->dirty_region, &pr_other->dirty_region);
+ if (!BLI_rcti_is_empty(&pr->dirty_region)) {
+ touch = true;
}
pr++;
@@ -4698,7 +4691,7 @@ static bool project_image_refresh_tagged(ProjPaintState *ps)
/* look over each bound cell */
for (i = 0; i < PROJ_BOUNDBOX_SQUARED; i++) {
pr = &(projIma->partRedrawRect[i]);
- if (pr->x2 != -1) { /* TODO: use 'enabled' ? */
+ if (BLI_rcti_is_valid(&pr->dirty_region)) {
set_imapaintpartial(pr);
imapaint_image_update(NULL, projIma->ima, projIma->ibuf, &projIma->iuser, true);
redraw = 1;
@@ -5112,11 +5105,10 @@ static void do_projectpaint_mask_f(ProjPaintState *ps, ProjPixel *projPixel, flo
static void image_paint_partial_redraw_expand(ImagePaintPartialRedraw *cell,
const ProjPixel *projPixel)
{
- cell->x1 = min_ii(cell->x1, (int)projPixel->x_px);
- cell->y1 = min_ii(cell->y1, (int)projPixel->y_px);
-
- cell->x2 = max_ii(cell->x2, (int)projPixel->x_px + 1);
- cell->y2 = max_ii(cell->y2, (int)projPixel->y_px + 1);
+ rcti rect_to_add;
+ BLI_rcti_init(
+ &rect_to_add, projPixel->x_px, projPixel->x_px + 1, projPixel->y_px, projPixel->y_px + 1);
+ BLI_rcti_do_minmax_rcti(&cell->dirty_region, &rect_to_add);
}
static void copy_original_alpha_channel(ProjPixel *pixel, bool is_floatbuf)
@@ -5262,7 +5254,7 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v
color_f[3] *= ((float)projPixel->mask) * (1.0f / 65535.0f) * brush_alpha;
if (is_floatbuf) {
- /* convert to premultipied */
+ /* Convert to premutliplied. */
mul_v3_fl(color_f, color_f[3]);
IMB_blend_color_float(
projPixel->pixel.f_pt, projPixel->origColor.f_pt, color_f, ps->blend);
@@ -6331,8 +6323,6 @@ void ED_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool
!stencil ? " Stencil," : "");
}
-/* Make sure that active object has a material,
- * and assign UVs and image layers if they do not exist */
bool ED_paint_proj_mesh_data_check(
Scene *scene, Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil)
{
@@ -6576,7 +6566,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
nodeSetActive(ntree, imanode);
- /* Connect to first available principled bsdf node. */
+ /* Connect to first available principled BSDF node. */
bNode *in_node = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
bNode *out_node = imanode;
@@ -6632,7 +6622,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
}
}
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ ED_node_tree_propagate_change(C, bmain, ntree);
/* In case we added more than one node, position them too. */
nodePositionPropagate(out_node);
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 7341d984c91..d31390bbb42 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -23,6 +23,18 @@
#pragma once
+#include "BKE_paint.h"
+
+#include "BLI_compiler_compat.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "DNA_scene_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct ARegion;
struct Brush;
struct ColorManagedDisplay;
@@ -38,13 +50,10 @@ struct Scene;
struct VPaint;
struct ViewContext;
struct bContext;
-struct rcti;
struct wmEvent;
struct wmKeyConfig;
struct wmOperator;
struct wmOperatorType;
-enum ePaintMode;
-enum ePaintSymmetryFlags;
typedef struct CoNo {
float co[3];
@@ -52,6 +61,7 @@ typedef struct CoNo {
} CoNo;
/* paint_stroke.c */
+
typedef bool (*StrokeGetLocation)(struct bContext *C, float location[3], const float mouse[2]);
typedef bool (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, const float mouse[2]);
typedef void (*StrokeUpdateStep)(struct bContext *C,
@@ -70,13 +80,25 @@ struct PaintStroke *paint_stroke_new(struct bContext *C,
int event_type);
void paint_stroke_free(struct bContext *C, struct wmOperator *op);
+/**
+ * Returns zero if the stroke dots should not be spaced, non-zero otherwise.
+ */
bool paint_space_stroke_enabled(struct Brush *br, enum ePaintMode mode);
+/**
+ * Return true if the brush size can change during paint (normally used for pressure).
+ */
bool paint_supports_dynamic_size(struct Brush *br, enum ePaintMode mode);
+/**
+ * Return true if the brush size can change during paint (normally used for pressure).
+ */
bool paint_supports_dynamic_tex_coords(struct Brush *br, enum ePaintMode mode);
bool paint_supports_smooth_stroke(struct Brush *br, enum ePaintMode mode);
bool paint_supports_texture(enum ePaintMode mode);
bool paint_supports_jitter(enum ePaintMode mode);
+/**
+ * Called in paint_ops.c, on each regeneration of key-maps.
+ */
struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf);
int paint_stroke_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int paint_stroke_exec(struct bContext *C, struct wmOperator *op);
@@ -89,14 +111,21 @@ float paint_stroke_distance_get(struct PaintStroke *stroke);
void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data);
bool PAINT_brush_tool_poll(struct bContext *C);
void paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C));
+/**
+ * Delete overlay cursor textures to preserve memory and invalidate all overlay flags.
+ */
void paint_cursor_delete_textures(void);
/* paint_vertex.c */
+
bool weight_paint_poll(struct bContext *C);
bool weight_paint_poll_ignore_tool(bContext *C);
bool weight_paint_mode_poll(struct bContext *C);
bool vertex_paint_poll(struct bContext *C);
bool vertex_paint_poll_ignore_tool(struct bContext *C);
+/**
+ * Returns true if vertex paint mode is active.
+ */
bool vertex_paint_mode_poll(struct bContext *C);
typedef void (*VPaintTransform_Callback)(const float col[3],
@@ -119,19 +148,29 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp, bool secondary);
/* paint_vertex_color_utils.c */
-unsigned int ED_vpaint_blend_tool(const int tool,
- const uint col,
- const uint paintcol,
- const int alpha_i);
+
+/**
+ * \note weight-paint has an equivalent function: #ED_wpaint_blend_tool
+ */
+unsigned int ED_vpaint_blend_tool(int tool, uint col, uint paintcol, int alpha_i);
+/**
+ * Apply callback to each vertex of the active vertex color layer.
+ */
bool ED_vpaint_color_transform(struct Object *ob,
VPaintTransform_Callback vpaint_tx_fn,
const void *user_data);
/* paint_vertex_weight_utils.c */
-float ED_wpaint_blend_tool(const int tool,
- const float weight,
- const float paintval,
- const float alpha);
+
+/**
+ * \param weight: Typically the current weight: #MDeformWeight.weight
+ *
+ * \return The final weight, note that this is _not_ clamped from [0-1].
+ * Clamping must be done on the final #MDeformWeight.weight
+ *
+ * \note vertex-paint has an equivalent function: #ED_vpaint_blend_tool
+ */
+float ED_wpaint_blend_tool(int tool, float weight, float paintval, float alpha);
/* Utility for tools to ensure vertex groups exist before they begin. */
enum eWPaintFlag {
WPAINT_ENSURE_MIRROR = (1 << 0),
@@ -140,13 +179,18 @@ struct WPaintVGroupIndex {
int active;
int mirror;
};
+/**
+ * Ensure we have data on wpaint start, add if needed.
+ */
bool ED_wpaint_ensure_data(struct bContext *C,
struct ReportList *reports,
enum eWPaintFlag flag,
struct WPaintVGroupIndex *vgroup_index);
-int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, const int vgroup_active);
+/** Return -1 when invalid. */
+int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, int vgroup_active);
/* paint_vertex_color_ops.c */
+
void PAINT_OT_vertex_color_set(struct wmOperatorType *ot);
void PAINT_OT_vertex_color_from_weight(struct wmOperatorType *ot);
void PAINT_OT_vertex_color_smooth(struct wmOperatorType *ot);
@@ -156,6 +200,7 @@ void PAINT_OT_vertex_color_invert(struct wmOperatorType *ot);
void PAINT_OT_vertex_color_levels(struct wmOperatorType *ot);
/* paint_vertex_weight_ops.c */
+
void PAINT_OT_weight_from_bones(struct wmOperatorType *ot);
void PAINT_OT_weight_sample(struct wmOperatorType *ot);
void PAINT_OT_weight_sample_group(struct wmOperatorType *ot);
@@ -175,8 +220,7 @@ void ED_vpaint_proj_handle_free(struct VertProjHandle *vp_handle);
/* paint_image.c */
typedef struct ImagePaintPartialRedraw {
- int x1, y1, x2, y2; /* XXX, could use 'rcti' */
- int enabled;
+ rcti dirty_region;
} ImagePaintPartialRedraw;
bool image_texture_paint_poll(struct bContext *C);
@@ -196,10 +240,13 @@ void paint_2d_stroke_done(void *ps);
void paint_2d_stroke(void *ps,
const float prev_mval[2],
const float mval[2],
- const bool eraser,
+ bool eraser,
float pressure,
float distance,
float size);
+/**
+ * This function expects linear space color values.
+ */
void paint_2d_bucket_fill(const struct bContext *C,
const float color[3],
struct Brush *br,
@@ -216,7 +263,7 @@ void paint_proj_stroke(const struct bContext *C,
void *ps_handle_p,
const float prev_pos[2],
const float pos[2],
- const bool eraser,
+ bool eraser,
float pressure,
float distance,
float size);
@@ -245,14 +292,56 @@ void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_image_paint(struct wmOperatorType *ot);
void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
+/* paint_image_2d_curve_mask.cc */
+/**
+ * \brief Caching structure for curve mask.
+ *
+ * When 2d painting images the curve mask is used as an input.
+ */
+typedef struct CurveMaskCache {
+ /**
+ * \brief Last #CurveMapping.changed_timestamp being read.
+ *
+ * When different the input cache needs to be recalculated.
+ */
+ int last_curve_timestamp;
+
+ /**
+ * \brief sampled version of the brush curve-mapping.
+ */
+ float *sampled_curve;
+
+ /**
+ * \brief Size in bytes of the curve_mask field.
+ *
+ * Used to determine if the curve_mask needs to be re-allocated.
+ */
+ size_t curve_mask_size;
+
+ /**
+ * \brief Curve mask that can be passed as curve_mask parameter when.
+ */
+ ushort *curve_mask;
+} CurveMaskCache;
+
+void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache);
+void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache,
+ const struct Brush *brush,
+ int diameter,
+ float radius,
+ const float cursor_position[2]);
+
/* sculpt_uv.c */
+
void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot);
/* paint_utils.c */
-/* Convert the object-space axis-aligned bounding box (expressed as
+/**
+ * Convert the object-space axis-aligned bounding box (expressed as
* its minimum and maximum corners) into a screen-space rectangle,
- * returns zero if the result is empty */
+ * returns zero if the result is empty.
+ */
bool paint_convert_bb_to_rect(struct rcti *rect,
const float bb_min[3],
const float bb_max[3],
@@ -260,9 +349,11 @@ bool paint_convert_bb_to_rect(struct rcti *rect,
struct RegionView3D *rv3d,
struct Object *ob);
-/* Get four planes in object-space that describe the projection of
+/**
+ * Get four planes in object-space that describe the projection of
* screen_rect from screen into object-space (essentially converting a
- * 2D screens-space bounding box into four 3D planes) */
+ * 2D screens-space bounding box into four 3D planes).
+ */
void paint_calc_redraw_planes(float planes[4][4],
const struct ARegion *region,
struct Object *ob,
@@ -282,6 +373,9 @@ void paint_get_tex_pixel_col(const struct MTex *mtex,
bool convert,
struct ColorSpace *colorspace);
+/**
+ * Used for both 3D view and image window.
+ */
void paint_sample_color(
struct bContext *C, struct ARegion *region, int x, int y, bool texpaint_proj, bool palette);
@@ -303,8 +397,64 @@ bool mask_paint_poll(struct bContext *C);
bool paint_curve_poll(struct bContext *C);
bool facemask_paint_poll(struct bContext *C);
-void flip_v3_v3(float out[3], const float in[3], const enum ePaintSymmetryFlags symm);
-void flip_qt_qt(float out[4], const float in[4], const enum ePaintSymmetryFlags symm);
+/**
+ * Uses symm to selectively flip any axis of a coordinate.
+ */
+
+BLI_INLINE void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm)
+{
+ if (symm & PAINT_SYMM_X) {
+ out[0] = -in[0];
+ }
+ else {
+ out[0] = in[0];
+ }
+ if (symm & PAINT_SYMM_Y) {
+ out[1] = -in[1];
+ }
+ else {
+ out[1] = in[1];
+ }
+ if (symm & PAINT_SYMM_Z) {
+ out[2] = -in[2];
+ }
+ else {
+ out[2] = in[2];
+ }
+}
+
+BLI_INLINE void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
+{
+ float axis[3], angle;
+
+ quat_to_axis_angle(axis, &angle, in);
+ normalize_v3(axis);
+
+ if (symm & PAINT_SYMM_X) {
+ axis[0] *= -1.0f;
+ angle *= -1.0f;
+ }
+ if (symm & PAINT_SYMM_Y) {
+ axis[1] *= -1.0f;
+ angle *= -1.0f;
+ }
+ if (symm & PAINT_SYMM_Z) {
+ axis[2] *= -1.0f;
+ angle *= -1.0f;
+ }
+
+ axis_angle_normalized_to_quat(out, axis, angle);
+}
+
+BLI_INLINE void flip_v3(float v[3], const ePaintSymmetryFlags symm)
+{
+ flip_v3_v3(v, v, symm);
+}
+
+BLI_INLINE void flip_qt(float quat[4], const ePaintSymmetryFlags symm)
+{
+ flip_qt_qt(quat, quat, symm);
+}
/* stroke operator */
typedef enum BrushStrokeMode {
@@ -360,9 +510,16 @@ typedef struct {
} BlurKernel;
enum eBlurKernelType;
-/* can be extended to other blur kernels later */
+/**
+ * Paint blur kernels. Projective painting enforces use of a 2x2 kernel due to lagging.
+ * Can be extended to other blur kernels later,
+ */
BlurKernel *paint_new_blur_kernel(struct Brush *br, bool proj);
void paint_delete_blur_kernel(BlurKernel *);
/* paint curve defines */
#define PAINT_CURVE_NUM_SEGMENTS 40
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index f08771292a8..c6b519f711f 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -233,7 +233,8 @@ static bool palette_poll(bContext *C)
{
Paint *paint = BKE_paint_get_active_from_context(C);
- if (paint && paint->palette != NULL) {
+ if (paint && paint->palette != NULL && !ID_IS_LINKED(paint->palette) &&
+ !ID_IS_OVERRIDE_LIBRARY(paint->palette)) {
return true;
}
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index de01bc3a474..c87f4e0aeec 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -1007,7 +1007,6 @@ static void stroke_done(bContext *C, wmOperator *op)
paint_stroke_free(C, op);
}
-/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
bool paint_space_stroke_enabled(Brush *br, ePaintMode mode)
{
if ((br->flag & BRUSH_SPACE) == 0) {
@@ -1041,7 +1040,6 @@ static bool sculpt_is_grab_tool(Brush *br)
SCULPT_TOOL_SNAKE_HOOK);
}
-/* return true if the brush size can change during paint (normally used for pressure) */
bool paint_supports_dynamic_size(Brush *br, ePaintMode mode)
{
if (br->flag & BRUSH_ANCHORED) {
@@ -1094,7 +1092,6 @@ bool paint_supports_texture(ePaintMode mode)
mode, PAINT_MODE_SCULPT, PAINT_MODE_VERTEX, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D);
}
-/* return true if the brush size can change during paint (normally used for pressure) */
bool paint_supports_dynamic_tex_coords(Brush *br, ePaintMode mode)
{
if (br->flag & BRUSH_ANCHORED) {
@@ -1115,7 +1112,6 @@ bool paint_supports_dynamic_tex_coords(Brush *br, ePaintMode mode)
#define PAINT_STROKE_MODAL_CANCEL 1
-/* Called in paint_ops.c, on each regeneration of key-maps. */
struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf)
{
static struct EnumPropertyItem modal_items[] = {
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 709e04d807d..95a0aba1ffb 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -80,9 +80,6 @@
#include "paint_intern.h"
-/* Convert the object-space axis-aligned bounding box (expressed as
- * its minimum and maximum corners) into a screen-space rectangle,
- * returns zero if the result is empty */
bool paint_convert_bb_to_rect(rcti *rect,
const float bb_min[3],
const float bb_max[3],
@@ -127,9 +124,6 @@ bool paint_convert_bb_to_rect(rcti *rect,
return rect->xmin < rect->xmax && rect->ymin < rect->ymax;
}
-/* Get four planes in object-space that describe the projection of
- * screen_rect from screen into object-space (essentially converting a
- * 2D screens-space bounding box into four 3D planes) */
void paint_calc_redraw_planes(float planes[4][4],
const ARegion *region,
Object *ob,
@@ -403,53 +397,6 @@ static Image *imapaint_face_image(Object *ob, Mesh *me, int face_index)
return ima;
}
-/* Uses symm to selectively flip any axis of a coordinate. */
-void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm)
-{
- if (symm & PAINT_SYMM_X) {
- out[0] = -in[0];
- }
- else {
- out[0] = in[0];
- }
- if (symm & PAINT_SYMM_Y) {
- out[1] = -in[1];
- }
- else {
- out[1] = in[1];
- }
- if (symm & PAINT_SYMM_Z) {
- out[2] = -in[2];
- }
- else {
- out[2] = in[2];
- }
-}
-
-void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
-{
- float axis[3], angle;
-
- quat_to_axis_angle(axis, &angle, in);
- normalize_v3(axis);
-
- if (symm & PAINT_SYMM_X) {
- axis[0] *= -1.0f;
- angle *= -1.0f;
- }
- if (symm & PAINT_SYMM_Y) {
- axis[1] *= -1.0f;
- angle *= -1.0f;
- }
- if (symm & PAINT_SYMM_Z) {
- axis[2] *= -1.0f;
- angle *= -1.0f;
- }
-
- axis_angle_normalized_to_quat(out, axis, angle);
-}
-
-/* used for both 3d view and image window */
void paint_sample_color(
bContext *C, ARegion *region, int x, int y, bool texpaint_proj, bool use_palette)
{
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 9387b84f437..75d4237d157 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -32,6 +32,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
+#include "BLI_string.h"
#include "BLI_task.h"
#include "DNA_brush_types.h"
@@ -43,9 +44,11 @@
#include "RNA_access.h"
#include "BKE_brush.h"
+#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_layer.h"
+#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
@@ -199,9 +202,6 @@ static void paint_last_stroke_update(Scene *scene, const float location[3])
ups->last_stroke_valid = true;
}
-/* polling - retrieve whether cursor should be set or operator should be done */
-
-/* Returns true if vertex paint mode is active */
bool vertex_paint_mode_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -295,7 +295,7 @@ static uint vpaint_blend(const VPaint *vp,
uint color_blend = ED_vpaint_blend_tool(blend, color_curr, color_paint, alpha_i);
- /* if no accumulate, clip color adding with colorig & orig alpha */
+ /* If no accumulate, clip color adding with `color_orig` & `color_test`. */
if (!brush_use_accumulate(vp)) {
uint color_test, a;
char *cp, *ct, *co;
@@ -1473,14 +1473,48 @@ struct WPaintData {
bool precomputed_weight_ready;
};
+static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache)
+{
+ Scene *scene = CTX_data_scene(C);
+ Brush *brush = paint->brush;
+ int cur_brush_size = BKE_brush_size_get(scene, brush);
+
+ BLI_strncpy(
+ cache->saved_active_brush_name, brush->id.name + 2, sizeof(cache->saved_active_brush_name));
+
+ /* Switch to the blur (smooth) brush. */
+ brush = BKE_paint_toolslots_brush_get(paint, WPAINT_TOOL_BLUR);
+ if (brush) {
+ BKE_paint_brush_set(paint, brush);
+ cache->saved_smooth_size = BKE_brush_size_get(scene, brush);
+ BKE_brush_size_set(scene, brush, cur_brush_size);
+ BKE_curvemapping_init(brush->curve);
+ }
+}
+
+static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Brush *brush = BKE_paint_brush(paint);
+ /* The current brush should match with what we have stored in the cache. */
+ BLI_assert(brush == cache->brush);
+
+ /* Try to switch back to the saved/previous brush. */
+ BKE_brush_size_set(scene, brush, cache->saved_smooth_size);
+ brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, cache->saved_active_brush_name);
+ if (brush) {
+ BKE_paint_brush_set(paint, brush);
+ }
+}
+
/* Initialize the stroke cache invariants from operator properties */
static void vwpaint_update_cache_invariants(
- bContext *C, const VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2])
+ bContext *C, VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2])
{
StrokeCache *cache;
Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
- const Brush *brush = vp->paint.brush;
ViewContext *vc = paint_stroke_view_context(op->customdata);
Object *ob = CTX_data_active_object(C);
float mat[3][3];
@@ -1516,7 +1550,12 @@ static void vwpaint_update_cache_invariants(
ups->draw_inverted = false;
}
+ if (cache->alt_smooth) {
+ smooth_brush_toggle_on(C, &vp->paint, cache);
+ }
+
copy_v2_v2(cache->mouse, cache->initial_mouse);
+ Brush *brush = vp->paint.brush;
/* Truly temporary data that isn't stored in properties */
cache->vc = vc;
cache->brush = brush;
@@ -1718,15 +1757,15 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
wpd->mirror.lock = tmpflags;
}
- if (ELEM(vp->paint.brush->weightpaint_tool, WPAINT_TOOL_SMEAR, WPAINT_TOOL_BLUR)) {
- wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__);
- }
-
/* If not previously created, create vertex/weight paint mode session data */
vertex_paint_init_stroke(depsgraph, ob);
vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
vertex_paint_init_session_data(ts, ob);
+ if (ELEM(vp->paint.brush->weightpaint_tool, WPAINT_TOOL_SMEAR, WPAINT_TOOL_BLUR)) {
+ wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__);
+ }
+
if (ob->sculpt->mode.wpaint.dvert_prev != NULL) {
MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
for (int i = 0; i < me->totvert; i++, dv++) {
@@ -1738,13 +1777,6 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
return true;
}
-static float dot_vf3vs3(const float brushNormal[3], const short vertexNormal[3])
-{
- float normal[3];
- normal_short_to_float_v3(normal, vertexNormal);
- return dot_v3v3(brushNormal, normal);
-}
-
static void get_brush_alpha_data(const Scene *scene,
const SculptSession *ss,
const Brush *brush,
@@ -1871,7 +1903,7 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata,
if (total_hit_loops != 0) {
float brush_strength = cache->bstrength;
const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
@@ -1951,7 +1983,7 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
if (!(use_face_sel || use_vert_sel) || mv_curr->flag & SELECT) {
float brush_strength = cache->bstrength;
const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
@@ -2057,9 +2089,8 @@ static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
/* If the vertex is selected */
if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
- 1.0f;
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
view_angle_limits_apply_falloff(
@@ -2114,7 +2145,7 @@ static void do_wpaint_brush_calc_average_weight_cb_ex(
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
/* Test to see if the vertex coordinates are within the spherical brush region. */
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float angle_cos = (use_normal && vd.no) ? dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (angle_cos > 0.0 &&
BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) {
@@ -2332,7 +2363,7 @@ static void wpaint_do_symmetrical_brush_actions(
/* symm is a bit combination of XYZ - 1 is mirror
* X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
for (i = 1; i <= symm; i++) {
- if ((symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
+ if ((symm & i && (symm != 5 || i != 3) && (symm != 6 || (!ELEM(i, 3, 5))))) {
cache->mirror_symmetry_pass = i;
cache->radial_symmetry_pass = 0;
SCULPT_cache_calc_brushdata_symm(cache, i, 0, 0);
@@ -2406,7 +2437,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
wpi.vgroup_validmap = wpd->vgroup_validmap;
wpi.vgroup_locked = wpd->vgroup_locked;
wpi.vgroup_unlocked = wpd->vgroup_unlocked;
- wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip");
+ wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip") || ss->cache->invert;
wpi.do_multipaint = wpd->do_multipaint;
wpi.do_auto_normalize = ((ts->auto_normalize != 0) && (wpi.vgroup_validmap != NULL) &&
(wpi.do_multipaint || wpi.vgroup_validmap[wpi.active.index]));
@@ -2491,6 +2522,14 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
MEM_freeN(wpd);
}
+ SculptSession *ss = ob->sculpt;
+
+ if (ss->cache->alt_smooth) {
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ VPaint *vp = ts->wpaint;
+ smooth_brush_toggle_off(C, &vp->paint, ss->cache);
+ }
+
/* and particles too */
if (ob->particlesystem.first) {
ParticleSystem *psys;
@@ -2898,9 +2937,8 @@ static void do_vpaint_brush_draw_task_cb_ex(void *__restrict userdata,
/* Calc the dot prod. between ray norm on surf and current vert
* (ie splash prevention factor), and only paint front facing verts. */
float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
- 1.0f;
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
view_angle_limits_apply_falloff(
@@ -2993,9 +3031,8 @@ static void do_vpaint_brush_blur_task_cb_ex(void *__restrict userdata,
/* If the vertex is selected for painting. */
if (!use_vert_sel || mv->flag & SELECT) {
float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
- 1.0f;
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
view_angle_limits_apply_falloff(
@@ -3119,7 +3156,7 @@ static void do_vpaint_brush_smear_task_cb_ex(void *__restrict userdata,
* (ie splash prevention factor), and only paint front facing verts. */
float brush_strength = cache->bstrength;
const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
@@ -3350,7 +3387,7 @@ static void vpaint_do_symmetrical_brush_actions(
/* symm is a bit combination of XYZ - 1 is mirror
* X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
for (i = 1; i <= symm; i++) {
- if (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5))) {
+ if (symm & i && (symm != 5 || i != 3) && (symm != 6 || (!ELEM(i, 3, 5)))) {
cache->mirror_symmetry_pass = i;
cache->radial_symmetry_pass = 0;
SCULPT_cache_calc_brushdata_symm(cache, i, 0, 0);
@@ -3446,6 +3483,14 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
MEM_freeN(vpd->smear.color_curr);
}
+ SculptSession *ss = ob->sculpt;
+
+ if (ss->cache->alt_smooth) {
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ VPaint *vp = ts->vpaint;
+ smooth_brush_toggle_off(C, &vp->paint, ss->cache);
+ }
+
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
MEM_freeN(vpd);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
index 9f023dd6e63..f62d91acddf 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
@@ -48,7 +48,7 @@ static bool vertex_weight_paint_mode_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
Mesh *me = BKE_mesh_from_object(ob);
- return (ob && (ob->mode == OB_MODE_VERTEX_PAINT || ob->mode == OB_MODE_WEIGHT_PAINT)) &&
+ return (ob && (ELEM(ob->mode, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT))) &&
(me && me->totpoly && me->dvert);
}
@@ -210,9 +210,6 @@ static void vertex_color_smooth_looptag(Mesh *me, const bool *mlooptag)
int(*scol)[4];
bool has_shared = false;
- /* if no mloopcol: do not do */
- /* if mtexpoly: only the involved faces, otherwise all */
-
if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) {
return;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
index dbc6044d2d8..a083af14c89 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
@@ -41,9 +41,6 @@
#define EPS_SATURATION 0.0005f
-/**
- * Apply callback to each vertex of the active vertex color layer.
- */
bool ED_vpaint_color_transform(struct Object *ob,
VPaintTransform_Callback vpaint_tx_fn,
const void *user_data)
@@ -610,9 +607,6 @@ BLI_INLINE uint mcol_alpha_sub(uint col_src, int fac)
return col_mix;
}
-/**
- * \note weight-paint has an equivalent function: #ED_wpaint_blend_tool
- */
uint ED_vpaint_blend_tool(const int tool, const uint col, const uint paintcol, const int alpha_i)
{
switch ((IMB_BlendMode)tool) {
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_proj.c b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
index 85cd211367a..9d5fffdcfcc 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
@@ -72,8 +72,10 @@ struct VertProjUpdate {
/* -------------------------------------------------------------------- */
/* Internal Init */
-static void vpaint_proj_dm_map_cosnos_init__map_cb(
- void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
+static void vpaint_proj_dm_map_cosnos_init__map_cb(void *userData,
+ int index,
+ const float co[3],
+ const float no[3])
{
struct VertProjHandle *vp_handle = userData;
CoNo *co_no = &vp_handle->vcosnos[index];
@@ -86,12 +88,7 @@ static void vpaint_proj_dm_map_cosnos_init__map_cb(
}
copy_v3_v3(co_no->co, co);
- if (no_f) {
- copy_v3_v3(co_no->no, no_f);
- }
- else {
- normal_short_to_float_v3(co_no->no, no_s);
- }
+ copy_v3_v3(co_no->no, no);
}
static void vpaint_proj_dm_map_cosnos_init(struct Depsgraph *depsgraph,
@@ -116,8 +113,10 @@ static void vpaint_proj_dm_map_cosnos_init(struct Depsgraph *depsgraph,
/* Same as init but take mouse location into account */
-static void vpaint_proj_dm_map_cosnos_update__map_cb(
- void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
+static void vpaint_proj_dm_map_cosnos_update__map_cb(void *userData,
+ int index,
+ const float co[3],
+ const float no[3])
{
struct VertProjUpdate *vp_update = userData;
struct VertProjHandle *vp_handle = vp_update->vp_handle;
@@ -148,12 +147,7 @@ static void vpaint_proj_dm_map_cosnos_update__map_cb(
/* continue with regular functionality */
copy_v3_v3(co_no->co, co);
- if (no_f) {
- copy_v3_v3(co_no->no, no_f);
- }
- else {
- normal_short_to_float_v3(co_no->no, no_s);
- }
+ copy_v3_v3(co_no->no, no);
}
static void vpaint_proj_dm_map_cosnos_update(struct Depsgraph *depsgraph,
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index cb8dc838422..1dfc4db6ac3 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -339,8 +339,8 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C,
uint index;
const int mval[2] = {
- win->eventstate->x - vc.region->winrct.xmin,
- win->eventstate->y - vc.region->winrct.ymin,
+ win->eventstate->xy[0] - vc.region->winrct.xmin,
+ win->eventstate->xy[1] - vc.region->winrct.ymin,
};
view3d_operator_needs_opengl(C);
@@ -408,10 +408,11 @@ static int weight_sample_group_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* TODO: we could make this a menu into OBJECT_OT_vertex_group_set_active
- * rather than its own operator */
void PAINT_OT_weight_sample_group(wmOperatorType *ot)
{
+ /* TODO: we could make this a menu into #OBJECT_OT_vertex_group_set_active
+ * rather than its own operator */
+
PropertyRNA *prop = NULL;
/* identifiers */
@@ -664,8 +665,7 @@ static void gradientVert_update(WPGradient_userData *grad_data, int index)
static void gradientVertUpdate__mapFunc(void *userData,
int index,
const float UNUSED(co[3]),
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
WPGradient_userData *grad_data = userData;
WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
@@ -680,8 +680,7 @@ static void gradientVertUpdate__mapFunc(void *userData,
static void gradientVertInit__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
WPGradient_userData *grad_data = userData;
Mesh *me = grad_data->me;
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
index 19ffa0c952d..34a27d5a5c2 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
@@ -51,7 +51,6 @@
/** \name Weight Paint Sanity Checks
* \{ */
-/* ensure we have data on wpaint start, add if needed */
bool ED_wpaint_ensure_data(bContext *C,
struct ReportList *reports,
enum eWPaintFlag flag,
@@ -131,9 +130,9 @@ bool ED_wpaint_ensure_data(bContext *C,
return true;
}
+
/** \} */
-/* mirror_vgroup is set to -1 when invalid */
int ED_wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
{
const ListBase *defbase = BKE_object_defgroup_list(ob);
@@ -277,14 +276,6 @@ BLI_INLINE float wval_exclusion(float weight, float paintval, float fac)
return temp * fac + weight * mfac;
}
-/**
- * \param weight: Typically the current weight: #MDeformWeight.weight
- *
- * \return The final weight, note that this is _not_ clamped from [0-1].
- * Clamping must be done on the final #MDeformWeight.weight
- *
- * \note vertex-paint has an equivalent function: #ED_vpaint_blend_tool
- */
float ED_wpaint_blend_tool(const int tool,
const float weight,
const float paintval,
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 7bde864e73f..2725fc1eae4 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -30,6 +30,7 @@
#include "BLI_gsqueue.h"
#include "BLI_hash.h"
#include "BLI_math.h"
+#include "BLI_math_color.h"
#include "BLI_math_color_blend.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -72,6 +73,8 @@
#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
+#include "NOD_texture.h"
+
#include "DEG_depsgraph.h"
#include "IMB_colormanagement.h"
@@ -101,13 +104,15 @@
#include <stdlib.h>
#include <string.h>
-/* Sculpt PBVH abstraction API
+/* -------------------------------------------------------------------- */
+/** \name Sculpt PBVH Abstraction API
*
* This is read-only, for writing use PBVH vertex iterators. There vd.index matches
* the indices used here.
*
* For multi-resolution, the same vertex in multiple grids is counted multiple times, with
- * different index for each grid. */
+ * different index for each grid.
+ * \{ */
void SCULPT_vertex_random_access_ensure(SculptSession *ss)
{
@@ -174,11 +179,11 @@ void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
if (ss->shapekey_active || ss->deform_modifiers_active) {
- const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh);
- normal_short_to_float_v3(no, mverts[index].no);
+ const float(*vert_normals)[3] = BKE_pbvh_get_vert_normals(ss->pbvh);
+ copy_v3_v3(no, vert_normals[index]);
}
else {
- normal_short_to_float_v3(no, ss->mvert[index].no);
+ copy_v3_v3(no, ss->vert_normals[index]);
}
break;
}
@@ -910,32 +915,18 @@ bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index)
/* Utilities */
-/**
- * Returns true when the step belongs to the stroke that is directly performed by the brush and
- * not by one of the symmetry passes.
- */
bool SCULPT_stroke_is_main_symmetry_pass(StrokeCache *cache)
{
return cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0 &&
cache->tile_pass == 0;
}
-/**
- * Return true only once per stroke on the first symmetry pass, regardless of the symmetry passes
- * enabled.
- *
- * This should be used for functionality that needs to be computed once per stroke of a particular
- * tool (allocating memory, updating random seeds...).
- */
bool SCULPT_stroke_is_first_brush_step(StrokeCache *cache)
{
return cache->first_time && cache->mirror_symmetry_pass == 0 &&
cache->radial_symmetry_pass == 0 && cache->tile_pass == 0;
}
-/**
- * Returns true on the first brush step of each symmetry pass.
- */
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(StrokeCache *cache)
{
return cache->first_time;
@@ -1045,10 +1036,9 @@ int SCULPT_nearest_vertex_get(
bool SCULPT_is_symmetry_iteration_valid(char i, char symm)
{
- return i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)));
+ return i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (!ELEM(i, 3, 5))));
}
-/* Checks if a vertex is inside the brush radius from any of its mirrored axis. */
bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3],
const float br_co[3],
float radius,
@@ -1082,9 +1072,13 @@ void SCULPT_tag_update_overlays(bContext *C)
}
}
-/* Sculpt Flood Fill API
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Flood Fill API
*
- * Iterate over connected vertices, starting from one or more initial vertices. */
+ * Iterate over connected vertices, starting from one or more initial vertices.
+ * \{ */
void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
{
@@ -1195,12 +1189,13 @@ void SCULPT_floodfill_free(SculptFloodFill *flood)
flood->queue = NULL;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Tool Capabilities
*
* Avoid duplicate checks, internal logic only,
* share logic with #rna_def_sculpt_capabilities where possible.
- *
* \{ */
static bool sculpt_tool_needs_original(const char sculpt_tool)
@@ -1260,23 +1255,24 @@ static int sculpt_brush_needs_normal(const SculptSession *ss, const Brush *brush
(brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)) ||
sculpt_brush_use_topology_rake(ss, brush);
}
-/** \} */
static bool sculpt_brush_needs_rake_rotation(const Brush *brush)
{
return SCULPT_TOOL_HAS_RAKE(brush->sculpt_tool) && (brush->rake_factor != 0.0f);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Init/Update
+ * \{ */
+
typedef enum StrokeFlags {
CLIP_X = 1,
CLIP_Y = 2,
CLIP_Z = 4,
} StrokeFlags;
-/**
- * Initialize a #SculptOrigVertData for accessing original vertex data;
- * handles #BMesh, #Mesh, and multi-resolution.
- */
void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, SculptUndoNode *unode)
{
SculptSession *ss = ob->sculpt;
@@ -1296,10 +1292,6 @@ void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, Scul
}
}
-/**
- * Initialize a #SculptOrigVertData for accessing original vertex data;
- * handles #BMesh, #Mesh, and multi-resolution.
- */
void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node)
{
SculptUndoNode *unode;
@@ -1307,9 +1299,6 @@ void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *
SCULPT_orig_vert_data_unode_init(data, ob, unode);
}
-/**
- * Update a #SculptOrigVertData for a particular vertex from the PBVH iterator.
- */
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter)
{
if (orig_data->unode->type == SCULPT_UNDO_COORDS) {
@@ -1342,112 +1331,12 @@ static void sculpt_rake_data_update(struct SculptRakeData *srd, const float co[3
}
}
-static void sculpt_rake_rotate(const SculptSession *ss,
- const float sculpt_co[3],
- const float v_co[3],
- float factor,
- float r_delta[3])
-{
- float vec_rot[3];
-
-#if 0
- /* lerp */
- sub_v3_v3v3(vec_rot, v_co, sculpt_co);
- mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot);
- add_v3_v3(vec_rot, sculpt_co);
- sub_v3_v3v3(r_delta, vec_rot, v_co);
- mul_v3_fl(r_delta, factor);
-#else
- /* slerp */
- float q_interp[4];
- sub_v3_v3v3(vec_rot, v_co, sculpt_co);
-
- copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry);
- pow_qt_fl_normalized(q_interp, factor);
- mul_qt_v3(q_interp, vec_rot);
-
- add_v3_v3(vec_rot, sculpt_co);
- sub_v3_v3v3(r_delta, vec_rot, v_co);
-#endif
-}
-
-/**
- * Align the grab delta to the brush normal.
- *
- * \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`.
- */
-static void sculpt_project_v3_normal_align(SculptSession *ss,
- const float normal_weight,
- float grab_delta[3])
-{
- /* Signed to support grabbing in (to make a hole) as well as out. */
- const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta);
-
- /* This scale effectively projects the offset so dragging follows the cursor,
- * as the normal points towards the view, the scale increases. */
- float len_view_scale;
- {
- float view_aligned_normal[3];
- project_plane_v3_v3v3(
- view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal);
- len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm));
- len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f;
- }
-
- mul_v3_fl(grab_delta, 1.0f - normal_weight);
- madd_v3_v3fl(
- grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
-}
+/** \} */
/* -------------------------------------------------------------------- */
-/** \name SculptProjectVector
- *
- * Fast-path for #project_plane_v3_v3v3
- *
+/** \name Sculpt Dynamic Topology
* \{ */
-typedef struct SculptProjectVector {
- float plane[3];
- float len_sq;
- float len_sq_inv_neg;
- bool is_valid;
-
-} SculptProjectVector;
-
-/**
- * \param plane: Direction, can be any length.
- */
-static void sculpt_project_v3_cache_init(SculptProjectVector *spvc, const float plane[3])
-{
- copy_v3_v3(spvc->plane, plane);
- spvc->len_sq = len_squared_v3(spvc->plane);
- spvc->is_valid = (spvc->len_sq > FLT_EPSILON);
- spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f;
-}
-
-/**
- * Calculate the projection.
- */
-static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3], float r_vec[3])
-{
-#if 0
- project_plane_v3_v3v3(r_vec, vec, spvc->plane);
-#else
- /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */
- madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg);
-#endif
-}
-
-/** \} */
-
-/**********************************************************************/
-
-/* Returns true if the stroke will use dynamic topology, false
- * otherwise.
- *
- * Factors: some brushes like grab cannot do dynamic topology.
- * Others, like smooth, are better without.
- * Same goes for alt-key smoothing. */
bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush)
{
return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
@@ -1461,7 +1350,11 @@ bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *bru
SCULPT_TOOL_HAS_DYNTOPO(brush->sculpt_tool));
}
-/*** paint mesh ***/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Paint Mesh
+ * \{ */
static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
const int n,
@@ -1496,10 +1389,10 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
copy_v3_v3(vd.co, orig_data.co);
if (vd.no) {
- copy_v3_v3_short(vd.no, orig_data.no);
+ copy_v3_v3(vd.no, orig_data.no);
}
else {
- normal_short_to_float_v3(vd.fno, orig_data.no);
+ copy_v3_v3(vd.fno, orig_data.no);
}
}
else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
@@ -1572,7 +1465,6 @@ static void sculpt_extend_redraw_rect_previous(Object *ob, rcti *rect)
BLI_rcti_union(rect, &ss->cache->previous_r);
}
-/* Get a screen-space rectangle of the modified area. */
bool SCULPT_get_redraw_rect(ARegion *region, RegionView3D *rv3d, Object *ob, rcti *rect)
{
PBVH *pbvh = ob->sculpt->pbvh;
@@ -1799,7 +1691,7 @@ const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
static float frontface(const Brush *br,
const float sculpt_normal[3],
- const short no[3],
+ const float no[3],
const float fno[3])
{
if (!(br->flag & BRUSH_FRONTFACE)) {
@@ -1808,10 +1700,7 @@ static float frontface(const Brush *br,
float dot;
if (no) {
- float tmp[3];
-
- normal_short_to_float_v3(tmp, no);
- dot = dot_v3v3(tmp, sculpt_normal);
+ dot = dot_v3v3(no, sculpt_normal);
}
else {
dot = dot_v3v3(fno, sculpt_normal);
@@ -1848,15 +1737,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test,
/* ===== Sculpting =====
*/
-static void flip_v3(float v[3], const ePaintSymmetryFlags symm)
-{
- flip_v3_v3(v, v, symm);
-}
-
-static void flip_qt(float quat[4], const ePaintSymmetryFlags symm)
-{
- flip_qt_qt(quat, quat, symm);
-}
static float calc_overlap(StrokeCache *cache, const char symm, const char axis, const float angle)
{
@@ -1917,6 +1797,8 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
return 1.0f / overlap;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Calculate Normal and Center
*
@@ -1924,9 +1806,9 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
* (optionally using original coordinates).
*
* Functions are:
- * - #calc_area_center
- * - #calc_area_normal
- * - #calc_area_normal_and_center
+ * - #SCULPT_calc_area_center
+ * - #SCULPT_calc_area_normal
+ * - #SCULPT_calc_area_normal_and_center
*
* \note These are all _very_ similar, when changing one, check others.
* \{ */
@@ -2055,19 +1937,19 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
float co[3];
/* For bm_vert only. */
- short no_s[3];
+ float no_s[3];
if (use_original) {
if (unode->bm_entry) {
const float *temp_co;
- const short *temp_no_s;
+ const float *temp_no_s;
BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &temp_co, &temp_no_s);
copy_v3_v3(co, temp_co);
- copy_v3_v3_short(no_s, temp_no_s);
+ copy_v3_v3(no_s, temp_no_s);
}
else {
copy_v3_v3(co, unode->co[vd.i]);
- copy_v3_v3_short(no_s, unode->no[vd.i]);
+ copy_v3_v3(no_s, unode->no[vd.i]);
}
}
else {
@@ -2087,11 +1969,11 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
data->any_vertex_sampled = true;
if (use_original) {
- normal_short_to_float_v3(no, no_s);
+ copy_v3_v3(no, no_s);
}
else {
if (vd.no) {
- normal_short_to_float_v3(no, vd.no);
+ copy_v3_v3(no, vd.no);
}
else {
copy_v3_v3(no, vd.fno);
@@ -2148,7 +2030,7 @@ static void calc_area_normal_and_center_reduce(const void *__restrict UNUSED(use
add_v2_v2_int(join->count_co, anctd->count_co);
}
-static void calc_area_center(
+void SCULPT_calc_area_center(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
@@ -2204,7 +2086,6 @@ void SCULPT_calc_area_normal(
SCULPT_pbvh_calc_area_normal(brush, ob, nodes, totnode, true, r_area_no);
}
-/* Expose 'calc_area_normal' externally. */
bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
Object *ob,
PBVHNode **nodes,
@@ -2246,9 +2127,7 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
return data.any_vertex_sampled;
}
-/* This calculates flatten center and area normal together,
- * amortizing the memory bandwidth and loop overhead to calculate both at the same time. */
-static void calc_area_normal_and_center(
+void SCULPT_calc_area_normal_and_center(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
@@ -2307,6 +2186,10 @@ static void calc_area_normal_and_center(
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Generic Brush Utilities
+ * \{ */
+
/**
* Return modified brush strength. Includes the direction of the brush, positive
* values pull vertices, negative values push. Uses tablet pressure and a
@@ -2462,12 +2345,11 @@ static float brush_strength(const Sculpt *sd,
}
}
-/* Return a multiplier for brush strength on a particular vertex. */
float SCULPT_brush_strength_factor(SculptSession *ss,
const Brush *br,
const float brush_point[3],
const float len,
- const short vno[3],
+ const float vno[3],
const float fno[3],
const float mask,
const int vertex_index,
@@ -2560,7 +2442,6 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
return avg;
}
-/* Test AABB against sphere. */
bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v)
{
SculptSearchSphereData *data = data_v;
@@ -2607,7 +2488,6 @@ bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v)
return len_squared_v3(t) < data->radius_squared;
}
-/* 2D projection (distance to line). */
bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v)
{
SculptSearchCircleData *data = data_v;
@@ -2635,9 +2515,6 @@ bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v)
return dist_sq < data->radius_squared || true;
}
-/**
- * Handles clipping against a mirror modifier and #SCULPT_LOCK_X/Y/Z axis flags.
- */
void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3])
{
for (int i = 0; i < 3; i++) {
@@ -2645,9 +2522,23 @@ void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3])
continue;
}
- if (ss->cache && (ss->cache->flag & (CLIP_X << i)) &&
- (fabsf(co[i]) <= ss->cache->clip_tolerance[i])) {
- co[i] = 0.0f;
+ bool do_clip = false;
+ float co_clip[3];
+ if (ss->cache && (ss->cache->flag & (CLIP_X << i))) {
+ /* Take possible mirror object into account. */
+ mul_v3_m4v3(co_clip, ss->cache->clip_mirror_mtx, co);
+
+ if (fabsf(co_clip[i]) <= ss->cache->clip_tolerance[i]) {
+ co_clip[i] = 0.0f;
+ float imtx[4][4];
+ invert_m4_m4(imtx, ss->cache->clip_mirror_mtx);
+ mul_m4_v3(imtx, co_clip);
+ do_clip = true;
+ }
+ }
+
+ if (do_clip) {
+ co[i] = co_clip[i];
}
else {
co[i] = val[i];
@@ -2866,6 +2757,8 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
}
}
+/** \} */
+
typedef struct {
SculptSession *ss;
const float *ray_start;
@@ -2891,1276 +2784,6 @@ typedef struct {
bool original;
} SculptFindNearestToRayData;
-static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
-
- float direction[3];
- copy_v3_v3(direction, ss->cache->grab_delta_symmetry);
-
- float tmp[3];
- mul_v3_v3fl(
- tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
- sub_v3_v3(direction, tmp);
- normalize_v3(direction);
-
- /* Cancel if there's no grab data. */
- if (is_zero_v3(direction)) {
- return;
- }
-
- const float bstrength = clamp_f(data->strength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade =
- bstrength *
- SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) *
- ss->cache->pressure;
-
- float avg[3], val[3];
-
- SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
-
- sub_v3_v3v3(val, avg, vd.co);
-
- madd_v3_v3v3fl(val, vd.co, val, fade);
-
- SCULPT_clip(sd, ss, vd.co, val);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void bmesh_topology_rake(
- Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- const float strength = clamp_f(bstrength, 0.0f, 1.0f);
-
- /* Interactions increase both strength and quality. */
- const int iterations = 3;
-
- int iteration;
- const int count = iterations * strength + 1;
- const float factor = iterations * strength / count;
-
- for (iteration = 0; iteration <= count; iteration++) {
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .strength = factor,
- };
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
-
- BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
- }
-}
-
-static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- const float fade = SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
-
- if (bstrength > 0.0f) {
- (*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
- }
- else {
- (*vd.mask) += fade * bstrength * (*vd.mask);
- }
- *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- BKE_pbvh_vertex_iter_end;
- }
-}
-
-static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
-}
-
-static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- switch ((BrushMaskTool)brush->mask_tool) {
- case BRUSH_MASK_DRAW:
- do_mask_brush_draw(sd, ob, nodes, totnode);
- break;
- case BRUSH_MASK_SMOOTH:
- SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true);
- break;
- }
-}
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Multires Displacement Eraser Brush
- * \{ */
-
-static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
-
- float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- float limit_co[3];
- float disp[3];
- SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co);
- sub_v3_v3v3(disp, limit_co, vd.co);
- mul_v3_v3fl(proxy[vd.i], disp, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- BKE_curvemapping_init(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_displacement_eraser_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/** \name Sculpt Multires Displacement Smear Brush
- * \{ */
-
-static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- float current_disp[3];
- float current_disp_norm[3];
- float interp_limit_surface_disp[3];
-
- copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]);
-
- switch (brush->smear_deform_type) {
- case BRUSH_SMEAR_DEFORM_DRAG:
- sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
- break;
- case BRUSH_SMEAR_DEFORM_PINCH:
- sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
- break;
- case BRUSH_SMEAR_DEFORM_EXPAND:
- sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
- break;
- }
-
- normalize_v3_v3(current_disp_norm, current_disp);
- mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
-
- float weights_accum = 1.0f;
-
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
- float vertex_disp[3];
- float vertex_disp_norm[3];
- float neighbor_limit_co[3];
- SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co);
- sub_v3_v3v3(vertex_disp,
- ss->cache->limit_surface_co[ni.index],
- ss->cache->limit_surface_co[vd.index]);
- const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index];
- normalize_v3_v3(vertex_disp_norm, vertex_disp);
-
- if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) {
- continue;
- }
-
- const float disp_interp = clamp_f(
- -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f);
- madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp);
- weights_accum += disp_interp;
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
-
- mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum);
-
- float new_co[3];
- add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp);
- interp_v3_v3v3(vd.co, vd.co, new_co, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_displacement_smear_store_prev_disp_task_cb_ex(
- void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- sub_v3_v3v3(ss->cache->prev_displacement[vd.index],
- SCULPT_vertex_co_get(ss, vd.index),
- ss->cache->limit_surface_co[vd.index]);
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
-
- BKE_curvemapping_init(brush->curve);
-
- const int totvert = SCULPT_vertex_count_get(ss);
- if (!ss->cache->prev_displacement) {
- ss->cache->prev_displacement = MEM_malloc_arrayN(
- totvert, sizeof(float[3]), "prev displacement");
- ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co");
- for (int i = 0; i < totvert; i++) {
- SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]);
- sub_v3_v3v3(ss->cache->prev_displacement[i],
- SCULPT_vertex_co_get(ss, i),
- ss->cache->limit_surface_co[i]);
- }
- }
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(
- 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings);
- BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-static void do_draw_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *offset = data->offset;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- /* Offset vertex. */
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], offset, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- const float bstrength = ss->cache->bstrength;
-
- /* Offset with as much as possible factored in already. */
- float effective_normal[3];
- SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
- mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
- mul_v3_v3(offset, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
-
- /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
- * initialize before threads so they can do curve mapping. */
- BKE_curvemapping_init(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .offset = offset,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
-}
-
-static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *offset = data->offset;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- /* Offset vertex. */
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], offset, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- const float bstrength = ss->cache->bstrength;
-
- /* Offset with as much as possible factored in already. */
- float effective_normal[3];
- SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
- mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
- mul_v3_v3(offset, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
-
- /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
- * initialize before threads so they can do curve mapping. */
- BKE_curvemapping_init(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .offset = offset,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
-}
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Topology Brush
- * \{ */
-
-static void do_topology_slide_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float current_disp[3];
- float current_disp_norm[3];
- float final_disp[3] = {0.0f, 0.0f, 0.0f};
-
- switch (brush->slide_deform_type) {
- case BRUSH_SLIDE_DEFORM_DRAG:
- sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
- break;
- case BRUSH_SLIDE_DEFORM_PINCH:
- sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
- break;
- case BRUSH_SLIDE_DEFORM_EXPAND:
- sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
- break;
- }
-
- normalize_v3_v3(current_disp_norm, current_disp);
- mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
-
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
- float vertex_disp[3];
- float vertex_disp_norm[3];
- sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
- normalize_v3_v3(vertex_disp_norm, vertex_disp);
- if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) {
- madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp));
- }
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
-
- mul_v3_v3fl(proxy[vd.i], final_disp, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-void SCULPT_relax_vertex(SculptSession *ss,
- PBVHVertexIter *vd,
- float factor,
- bool filter_boundary_face_sets,
- float *r_final_pos)
-{
- float smooth_pos[3];
- float final_disp[3];
- float boundary_normal[3];
- int avg_count = 0;
- int neighbor_count = 0;
- zero_v3(smooth_pos);
- zero_v3(boundary_normal);
- const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index);
-
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
- neighbor_count++;
- if (!filter_boundary_face_sets ||
- (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) {
-
- /* When the vertex to relax is boundary, use only connected boundary vertices for the average
- * position. */
- if (is_boundary) {
- if (!SCULPT_vertex_is_boundary(ss, ni.index)) {
- continue;
- }
- add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
- avg_count++;
-
- /* Calculate a normal for the constraint plane using the edges of the boundary. */
- float to_neighbor[3];
- sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co);
- normalize_v3(to_neighbor);
- add_v3_v3(boundary_normal, to_neighbor);
- }
- else {
- add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
- avg_count++;
- }
- }
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
-
- /* Don't modify corner vertices. */
- if (neighbor_count <= 2) {
- copy_v3_v3(r_final_pos, vd->co);
- return;
- }
-
- if (avg_count > 0) {
- mul_v3_fl(smooth_pos, 1.0f / avg_count);
- }
- else {
- copy_v3_v3(r_final_pos, vd->co);
- return;
- }
-
- float plane[4];
- float smooth_closest_plane[3];
- float vno[3];
-
- if (is_boundary && avg_count == 2) {
- normalize_v3_v3(vno, boundary_normal);
- }
- else {
- SCULPT_vertex_normal_get(ss, vd->index, vno);
- }
-
- if (is_zero_v3(vno)) {
- copy_v3_v3(r_final_pos, vd->co);
- return;
- }
-
- plane_from_point_normal_v3(plane, vd->co, vno);
- closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos);
- sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co);
-
- mul_v3_fl(final_disp, factor);
- add_v3_v3v3(r_final_pos, vd->co, final_disp);
-}
-
-static void do_topology_relax_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- return;
- }
-
- BKE_curvemapping_init(brush->curve);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- if (ss->cache->alt_smooth) {
- SCULPT_boundary_info_ensure(ob);
- for (int i = 0; i < 4; i++) {
- BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
- }
- }
- else {
- BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
- }
-}
-
-static void calc_sculpt_plane(
- Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (SCULPT_stroke_is_main_symmetry_pass(ss->cache) &&
- (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache) ||
- !(brush->flag & BRUSH_ORIGINAL_PLANE) || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
- switch (brush->sculpt_plane) {
- case SCULPT_DISP_DIR_VIEW:
- copy_v3_v3(r_area_no, ss->cache->true_view_normal);
- break;
-
- case SCULPT_DISP_DIR_X:
- ARRAY_SET_ITEMS(r_area_no, 1.0f, 0.0f, 0.0f);
- break;
-
- case SCULPT_DISP_DIR_Y:
- ARRAY_SET_ITEMS(r_area_no, 0.0f, 1.0f, 0.0f);
- break;
-
- case SCULPT_DISP_DIR_Z:
- ARRAY_SET_ITEMS(r_area_no, 0.0f, 0.0f, 1.0f);
- break;
-
- case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
- normalize_v3(r_area_no);
- }
- break;
-
- default:
- break;
- }
-
- /* For flatten center. */
- /* Flatten center has not been calculated yet if we are not using the area normal. */
- if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) {
- calc_area_center(sd, ob, nodes, totnode, r_area_co);
- }
-
- /* For area normal. */
- if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
- (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
- copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
- }
- else {
- copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
- }
-
- /* For flatten center. */
- if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
- (brush->flag & BRUSH_ORIGINAL_PLANE)) {
- copy_v3_v3(r_area_co, ss->cache->last_center);
- }
- else {
- copy_v3_v3(ss->cache->last_center, r_area_co);
- }
- }
- else {
- /* For area normal. */
- copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
-
- /* For flatten center. */
- copy_v3_v3(r_area_co, ss->cache->last_center);
-
- /* For area normal. */
- flip_v3(r_area_no, ss->cache->mirror_symmetry_pass);
-
- /* For flatten center. */
- flip_v3(r_area_co, ss->cache->mirror_symmetry_pass);
-
- /* For area normal. */
- mul_m4_v3(ss->cache->symm_rot_mat, r_area_no);
-
- /* For flatten center. */
- mul_m4_v3(ss->cache->symm_rot_mat, r_area_co);
-
- /* Shift the plane for the current tile. */
- add_v3_v3(r_area_co, ss->cache->plane_offset);
- }
-}
-
-/** \} */
-
-/**
- * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
- */
-static void do_crease_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- SculptProjectVector *spvc = data->spvc;
- const float flippedbstrength = data->flippedbstrength;
- const float *offset = data->offset;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- /* Offset vertex. */
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float val1[3];
- float val2[3];
-
- /* First we pinch. */
- sub_v3_v3v3(val1, test.location, vd.co);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(val1, val1, ss->cache->view_normal);
- }
-
- mul_v3_fl(val1, fade * flippedbstrength);
-
- sculpt_project_v3(spvc, val1, val1);
-
- /* Then we draw. */
- mul_v3_v3fl(val2, offset, fade);
-
- add_v3_v3v3(proxy[vd.i], val1, val2);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- const Scene *scene = ss->cache->vc->scene;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- float bstrength = ss->cache->bstrength;
- float flippedbstrength, crease_correction;
- float brush_alpha;
-
- SculptProjectVector spvc;
-
- /* Offset with as much as possible factored in already. */
- mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
- mul_v3_v3(offset, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
-
- /* We divide out the squared alpha and multiply by the squared crease
- * to give us the pinch strength. */
- crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor;
- brush_alpha = BKE_brush_alpha_get(scene, brush);
- if (brush_alpha > 0.0f) {
- crease_correction /= brush_alpha * brush_alpha;
- }
-
- /* We always want crease to pinch or blob to relax even when draw is negative. */
- flippedbstrength = (bstrength < 0.0f) ? -crease_correction * bstrength :
- crease_correction * bstrength;
-
- if (brush->sculpt_tool == SCULPT_TOOL_BLOB) {
- flippedbstrength *= -1.0f;
- }
-
- /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single
- * point. Without this we get a 'flat' surface surrounding the pinch. */
- sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .spvc = &spvc,
- .offset = offset,
- .flippedbstrength = flippedbstrength,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
-}
-
-static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float(*stroke_xz)[3] = data->stroke_xz;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- float x_object_space[3];
- float z_object_space[3];
- copy_v3_v3(x_object_space, stroke_xz[0]);
- copy_v3_v3(z_object_space, stroke_xz[1]);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float disp_center[3];
- float x_disp[3];
- float z_disp[3];
- /* Calculate displacement from the vertex to the brush center. */
- sub_v3_v3v3(disp_center, test.location, vd.co);
-
- /* Project the displacement into the X vector (aligned to the stroke). */
- mul_v3_v3fl(x_disp, x_object_space, dot_v3v3(disp_center, x_object_space));
-
- /* Project the displacement into the Z vector (aligned to the surface normal). */
- mul_v3_v3fl(z_disp, z_object_space, dot_v3v3(disp_center, z_object_space));
-
- /* Add the two projected vectors to calculate the final displacement.
- * The Y component is removed. */
- add_v3_v3v3(disp_center, x_disp, z_disp);
-
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(disp_center, disp_center, ss->cache->view_normal);
- }
- mul_v3_v3fl(proxy[vd.i], disp_center, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- float area_no[3];
- float area_co[3];
-
- float mat[4][4];
- calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- /* delay the first daub because grab delta is not setup */
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- return;
- }
-
- if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
- return;
- }
-
- /* Initialize `mat`. */
- cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
- mat[0][3] = 0.0f;
- cross_v3_v3v3(mat[1], area_no, mat[0]);
- mat[1][3] = 0.0f;
- copy_v3_v3(mat[2], area_no);
- mat[2][3] = 0.0f;
- copy_v3_v3(mat[3], ss->cache->location);
- mat[3][3] = 1.0f;
- normalize_m4(mat);
-
- float stroke_xz[2][3];
- normalize_v3_v3(stroke_xz[0], mat[0]);
- normalize_v3_v3(stroke_xz[1], mat[2]);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .stroke_xz = stroke_xz,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
-}
-
-static void do_grab_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *grab_delta = data->grab_delta;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE;
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- if (grab_silhouette) {
- float silhouette_test_dir[3];
- normalize_v3_v3(silhouette_test_dir, grab_delta);
- if (dot_v3v3(ss->cache->initial_normal, ss->cache->grab_delta_symmetry) < 0.0f) {
- mul_v3_fl(silhouette_test_dir, -1.0f);
- }
- float vno[3];
- normal_short_to_float_v3(vno, orig_data.no);
- fade *= max_ff(dot_v3v3(vno, silhouette_test_dir), 0.0f);
- }
-
- mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- if (ss->cache->normal_weight > 0.0f) {
- sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .grab_delta = grab_delta,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
-}
-
-static void do_elastic_deform_brush_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;
- const float *grab_delta = data->grab_delta;
- const float *location = ss->cache->location;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
-
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- float dir;
- if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) {
- dir = 1.0f;
- }
- else {
- dir = -1.0f;
- }
-
- if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) {
- int symm = ss->cache->mirror_symmetry_pass;
- if (ELEM(symm, 1, 2, 4, 7)) {
- dir = -dir;
- }
- }
-
- KelvinletParams params;
- float force = len_v3(grab_delta) * dir * bstrength;
- BKE_kelvinlet_init_params(
- &params, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- float final_disp[3];
- switch (brush->elastic_deform_type) {
- case BRUSH_ELASTIC_DEFORM_GRAB:
- BKE_kelvinlet_grab(final_disp, &params, orig_data.co, location, grab_delta);
- mul_v3_fl(final_disp, bstrength * 20.0f);
- break;
- case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: {
- BKE_kelvinlet_grab_biscale(final_disp, &params, orig_data.co, location, grab_delta);
- mul_v3_fl(final_disp, bstrength * 20.0f);
- break;
- }
- case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: {
- BKE_kelvinlet_grab_triscale(final_disp, &params, orig_data.co, location, grab_delta);
- mul_v3_fl(final_disp, bstrength * 20.0f);
- break;
- }
- case BRUSH_ELASTIC_DEFORM_SCALE:
- BKE_kelvinlet_scale(
- final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
- break;
- case BRUSH_ELASTIC_DEFORM_TWIST:
- BKE_kelvinlet_twist(
- final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
- break;
- }
-
- if (vd.mask) {
- mul_v3_fl(final_disp, 1.0f - *vd.mask);
- }
-
- mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
-
- copy_v3_v3(proxy[vd.i], final_disp);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- if (ss->cache->normal_weight > 0.0f) {
- sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .grab_delta = grab_delta,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
-}
-
ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3])
{
ePaintSymmetryAreas symm_area = PAINT_SYMM_AREA_DEFAULT;
@@ -4244,7 +2867,7 @@ void SCULPT_calc_brush_plane(
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
+ SCULPT_calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
normalize_v3(r_area_no);
@@ -4258,7 +2881,7 @@ void SCULPT_calc_brush_plane(
/* For flatten center. */
/* Flatten center has not been calculated yet if we are not using the area normal. */
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) {
- calc_area_center(sd, ob, nodes, totnode, r_area_co);
+ SCULPT_calc_area_center(sd, ob, nodes, totnode, r_area_co);
}
/* For area normal. */
@@ -4303,564 +2926,12 @@ void SCULPT_calc_brush_plane(
}
}
-static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *cono = data->cono;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], cono, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
- float tmp[3], cono[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
- cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .cono = cono,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
-}
-
-static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- SculptProjectVector *spvc = data->spvc;
- const float *grab_delta = data->grab_delta;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
- const bool do_rake_rotation = ss->cache->is_rake_rotation_valid;
- const bool do_pinch = (brush->crease_pinch_factor != 0.5f);
- const float pinch = do_pinch ? (2.0f * (0.5f - brush->crease_pinch_factor) *
- (len_v3(grab_delta) / ss->cache->radius)) :
- 0.0f;
-
- const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- KelvinletParams params;
- BKE_kelvinlet_init_params(&params, ss->cache->radius, bstrength, 1.0f, 0.4f);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- float fade;
- if (do_elastic) {
- fade = 1.0f;
- }
- else {
- fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- }
-
- mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
-
- /* Negative pinch will inflate, helps maintain volume. */
- if (do_pinch) {
- float delta_pinch_init[3], delta_pinch[3];
-
- sub_v3_v3v3(delta_pinch, vd.co, test.location);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal);
- }
-
- /* Important to calculate based on the grabbed location
- * (intentionally ignore fade here). */
- add_v3_v3(delta_pinch, grab_delta);
-
- sculpt_project_v3(spvc, delta_pinch, delta_pinch);
-
- copy_v3_v3(delta_pinch_init, delta_pinch);
-
- float pinch_fade = pinch * fade;
- /* When reducing, scale reduction back by how close to the center we are,
- * so we don't pinch into nothingness. */
- if (pinch > 0.0f) {
- /* Square to have even less impact for close vertices. */
- pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius));
- }
- mul_v3_fl(delta_pinch, 1.0f + pinch_fade);
- sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch);
- add_v3_v3(proxy[vd.i], delta_pinch);
- }
-
- if (do_rake_rotation) {
- float delta_rotate[3];
- sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate);
- add_v3_v3(proxy[vd.i], delta_rotate);
- }
-
- if (do_elastic) {
- float disp[3];
- BKE_kelvinlet_grab_triscale(disp, &params, vd.co, ss->cache->location, proxy[vd.i]);
- mul_v3_fl(disp, bstrength * 20.0f);
- if (vd.mask) {
- mul_v3_fl(disp, 1.0f - *vd.mask);
- }
- mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
- copy_v3_v3(proxy[vd.i], disp);
- }
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- const float bstrength = ss->cache->bstrength;
- float grab_delta[3];
-
- SculptProjectVector spvc;
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- if (bstrength < 0.0f) {
- negate_v3(grab_delta);
- }
-
- if (ss->cache->normal_weight > 0.0f) {
- sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
- }
-
- /* Optionally pinch while painting. */
- if (brush->crease_pinch_factor != 0.5f) {
- sculpt_project_v3_cache_init(&spvc, grab_delta);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .spvc = &spvc,
- .grab_delta = grab_delta,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
-}
-
-static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *cono = data->cono;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], cono, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
- float tmp[3], cono[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
- cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .cono = cono,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
-}
-
-static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float angle = data->angle;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- float vec[3], rot[3][3];
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
- axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
- mul_v3_m3v3(proxy[vd.i], rot, vec);
- add_v3_v3(proxy[vd.i], ss->cache->location);
- sub_v3_v3(proxy[vd.i], orig_data.co);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- static const int flip[8] = {1, -1, -1, 1, -1, 1, 1, -1};
- const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .angle = angle,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
-}
-
-static void do_layer_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
-
- const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- const int vi = vd.index;
- float *disp_factor;
- if (use_persistent_base) {
- disp_factor = &ss->persistent_base[vi].disp;
- }
- else {
- disp_factor = &ss->cache->layer_displacement_factor[vi];
- }
-
- /* When using persistent base, the layer brush (holding Control) invert mode resets the
- * height of the layer to 0. This makes possible to clean edges of previously added layers
- * on top of the base. */
- /* The main direction of the layers is inverted using the regular brush strength with the
- * brush direction property. */
- if (use_persistent_base && ss->cache->invert) {
- (*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) *
- ((*disp_factor) > 0.0f ? -1.0f : 1.0f);
- }
- else {
- (*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor));
- }
- if (vd.mask) {
- const float clamp_mask = 1.0f - *vd.mask;
- *disp_factor = clamp_f(*disp_factor, -clamp_mask, clamp_mask);
- }
- else {
- *disp_factor = clamp_f(*disp_factor, -1.0f, 1.0f);
- }
-
- float final_co[3];
- float normal[3];
-
- if (use_persistent_base) {
- 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);
- }
- else {
- normal_short_to_float_v3(normal, orig_data.no);
- mul_v3_fl(normal, brush->height);
- madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor);
- }
-
- float vdisp[3];
- sub_v3_v3v3(vdisp, final_co, vd.co);
- mul_v3_fl(vdisp, fabsf(fade));
- add_v3_v3v3(final_co, vd.co, vdisp);
-
- SCULPT_clip(sd, ss, vd.co, final_co);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (ss->cache->layer_displacement_factor == NULL) {
- ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
- "layer displacement factor");
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
-}
-
-static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float val[3];
-
- if (vd.fno) {
- copy_v3_v3(val, vd.fno);
- }
- else {
- normal_short_to_float_v3(val, vd.no);
- }
-
- mul_v3_fl(val, fade * ss->cache->radius);
- mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
-}
-
int SCULPT_plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3])
{
return (!(brush->flag & BRUSH_PLANE_TRIM) ||
((dot_v3v3(val, val) <= cache->radius_squared * cache->plane_trim_squared)));
}
-static bool plane_point_side_flip(const float co[3], const float plane[4], const bool flip)
-{
- float d = plane_point_side_v3(plane, co);
- if (flip) {
- d = -d;
- }
- return d <= 0.0f;
-}
-
int SCULPT_plane_point_side(const float co[3], const float plane[4])
{
float d = plane_point_side_v3(plane, co);
@@ -4880,805 +2951,12 @@ float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss)
return rv;
}
-static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- float intr[3];
- float val[3];
-
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
-
- sub_v3_v3v3(val, intr, vd.co);
-
- if (SCULPT_plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
-
- float area_no[3];
- float area_co[3];
-
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
- float displace;
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
-
- displace = radius * offset;
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
-}
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Clay Brush
- * \{ */
-
-typedef struct ClaySampleData {
- float plane_dist[2];
-} ClaySampleData;
-
-static void calc_clay_surface_task_cb(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- ClaySampleData *csd = tls->userdata_chunk;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
- float plane[4];
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, brush->falloff_shape);
-
- /* Apply the brush normal radius to the test before sampling. */
- float test_radius = sqrtf(test.radius_squared);
- test_radius *= brush->normal_radius_factor;
- test.radius_squared = test_radius * test_radius;
- plane_from_point_normal_v3(plane, area_co, area_no);
-
- if (is_zero_v4(plane)) {
- return;
- }
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- float plane_dist = dist_signed_to_plane_v3(vd.co, plane);
- float plane_dist_abs = fabsf(plane_dist);
- if (plane_dist > 0.0f) {
- csd->plane_dist[0] = MIN2(csd->plane_dist[0], plane_dist_abs);
- }
- else {
- csd->plane_dist[1] = MIN2(csd->plane_dist[1], plane_dist_abs);
- }
- BKE_pbvh_vertex_iter_end;
- }
-}
-
-static void calc_clay_surface_reduce(const void *__restrict UNUSED(userdata),
- void *__restrict chunk_join,
- void *__restrict chunk)
-{
- ClaySampleData *join = chunk_join;
- ClaySampleData *csd = chunk;
- join->plane_dist[0] = MIN2(csd->plane_dist[0], join->plane_dist[0]);
- join->plane_dist[1] = MIN2(csd->plane_dist[1], join->plane_dist[1]);
-}
-
-static void do_clay_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = fabsf(ss->cache->bstrength);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
-
- sub_v3_v3v3(val, intr, vd.co);
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = fabsf(ss->cache->radius);
- const float initial_radius = fabsf(ss->cache->initial_radius);
- bool flip = ss->cache->bstrength < 0.0f;
-
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
- float displace;
-
- float area_no[3];
- float area_co[3];
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SculptThreadedTaskData sample_data = {
- .sd = NULL,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .totnode = totnode,
- .area_no = area_no,
- .area_co = ss->cache->location,
- };
-
- ClaySampleData csd = {{0}};
-
- TaskParallelSettings sample_settings;
- BKE_pbvh_parallel_range_settings(&sample_settings, true, totnode);
- sample_settings.func_reduce = calc_clay_surface_reduce;
- sample_settings.userdata_chunk = &csd;
- sample_settings.userdata_chunk_size = sizeof(ClaySampleData);
-
- BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
-
- float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]);
- d_offset = min_ff(radius, d_offset);
- d_offset = d_offset / radius;
- d_offset = 1.0f - d_offset;
- displace = fabsf(initial_radius * (0.25f + offset + (d_offset * 0.15f)));
- if (flip) {
- displace = -displace;
- }
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- copy_v3_v3(area_co, ss->cache->location);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
-}
-
-static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float(*mat)[4] = data->mat;
- const float *area_no_sp = data->area_no_sp;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- SculptBrushTest test;
- float(*proxy)[3];
- const bool flip = (ss->cache->bstrength < 0.0f);
- const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SCULPT_brush_test_init(ss, &test);
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) {
- continue;
- }
-
- if (!plane_point_side_flip(vd.co, test.plane_tool, flip)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
-
- if (!SCULPT_plane_trim(ss->cache, brush, val)) {
- continue;
- }
- /* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- ss->cache->radius * test.dist,
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const bool flip = (ss->cache->bstrength < 0.0f);
- const float radius = flip ? -ss->cache->radius : ss->cache->radius;
- const float offset = SCULPT_brush_plane_offset_get(sd, ss);
- const float displace = radius * (0.18f + offset);
-
- /* The sculpt-plane normal (whatever its set to). */
- float area_no_sp[3];
-
- /* Geometry normal */
- float area_no[3];
- float area_co[3];
-
- float temp[3];
- float mat[4][4];
- float scale[4][4];
- float tmat[4][4];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
- SCULPT_tilt_apply_to_normal(area_no_sp, ss->cache, brush->tilt_strength_factor);
-
- if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
- SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
- }
- else {
- copy_v3_v3(area_no, area_no_sp);
- }
-
- /* Delay the first daub because grab delta is not setup. */
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- return;
- }
-
- if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
- return;
- }
-
- mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- /* Clay Strips uses a cube test with falloff in the XY axis (not in Z) and a plane to deform the
- * vertices. When in Add mode, vertices that are below the plane and inside the cube are move
- * towards the plane. In this situation, there may be cases where a vertex is outside the cube
- * but below the plane, so won't be deformed, causing artifacts. In order to prevent these
- * artifacts, this displaces the test cube space in relation to the plane in order to
- * deform more vertices that may be below it. */
- /* The 0.7 and 1.25 factors are arbitrary and don't have any relation between them, they were set
- * by doing multiple tests using the default "Clay Strips" brush preset. */
- float area_co_displaced[3];
- madd_v3_v3v3fl(area_co_displaced, area_co, area_no, -radius * 0.7f);
-
- /* Initialize brush local-space matrix. */
- cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
- mat[0][3] = 0.0f;
- cross_v3_v3v3(mat[1], area_no, mat[0]);
- mat[1][3] = 0.0f;
- copy_v3_v3(mat[2], area_no);
- mat[2][3] = 0.0f;
- copy_v3_v3(mat[3], area_co_displaced);
- mat[3][3] = 1.0f;
- normalize_m4(mat);
-
- /* Scale brush local space matrix. */
- scale_m4_fl(scale, ss->cache->radius);
- mul_m4_m4m4(tmat, mat, scale);
-
- /* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in
- * Z this does not produce artifacts in the falloff cube and allows to deform extra vertices
- * during big deformation while keeping the surface as uniform as possible. */
- mul_v3_fl(tmat[2], 1.25f);
-
- invert_m4_m4(mat, tmat);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no_sp = area_no_sp,
- .area_co = area_co,
- .mat = mat,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
-}
-
-static void do_fill_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- if (!SCULPT_plane_point_side(vd.co, test.plane_tool)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
-
- if (!SCULPT_plane_trim(ss->cache, brush, val)) {
- continue;
- }
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
-
- float area_no[3];
- float area_co[3];
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
-
- float displace;
-
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
-
- displace = radius * offset;
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
-}
-
-static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- if (SCULPT_plane_point_side(vd.co, test.plane_tool)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
-
- if (!SCULPT_plane_trim(ss->cache, brush, val)) {
- continue;
- }
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
-
- float area_no[3];
- float area_co[3];
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
-
- float displace;
-
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
-
- displace = -radius * offset;
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
-}
+/** \} */
/* -------------------------------------------------------------------- */
-/** \name Sculpt Clay Thumb Brush
+/** \name Sculpt Gravity Brush
* \{ */
-static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float(*mat)[4] = data->mat;
- const float *area_no_sp = data->area_no_sp;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = data->clay_strength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- float plane_tilt[4];
- float normal_tilt[3];
- float imat[4][4];
-
- invert_m4_m4(imat, mat);
- rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss->cache->clay_thumb_front_angle));
-
- /* Plane aligned to the geometry normal (back part of the brush). */
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
- /* Tilted plane (front part of the brush). */
- plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- float local_co[3];
- mul_v3_m4v3(local_co, mat, vd.co);
- float intr[3], intr_tilt[3];
- float val[3];
-
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- closest_to_plane_normalized_v3(intr_tilt, plane_tilt, vd.co);
-
- /* Mix the deformation of the aligned and the tilted plane based on the brush space vertex
- * coordinates. */
- /* We can also control the mix with a curve if it produces noticeable artifacts in the center
- * of the brush. */
- const float tilt_mix = local_co[1] > 0.0f ? 0.0f : 1.0f;
- interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix);
- sub_v3_v3v3(val, intr_tilt, vd.co);
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static float sculpt_clay_thumb_get_stabilized_pressure(StrokeCache *cache)
-{
- float final_pressure = 0.0f;
- for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) {
- final_pressure += cache->clay_pressure_stabilizer[i];
- }
- return final_pressure / SCULPT_CLAY_STABILIZER_LEN;
-}
-
-static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
- const float offset = SCULPT_brush_plane_offset_get(sd, ss);
- const float displace = radius * (0.25f + offset);
-
- /* Sampled geometry normal and area center. */
- float area_no_sp[3];
- float area_no[3];
- float area_co[3];
-
- float temp[3];
- float mat[4][4];
- float scale[4][4];
- float tmat[4][4];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
-
- if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
- SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
- }
- else {
- copy_v3_v3(area_no, area_no_sp);
- }
-
- /* Delay the first daub because grab delta is not setup. */
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- ss->cache->clay_thumb_front_angle = 0.0f;
- return;
- }
-
- /* Simulate the clay accumulation by increasing the plane angle as more samples are added to the
- * stroke. */
- if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) {
- ss->cache->clay_thumb_front_angle += 0.8f;
- ss->cache->clay_thumb_front_angle = clamp_f(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f);
- }
-
- if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
- return;
- }
-
- /* Displace the brush planes. */
- copy_v3_v3(area_co, ss->cache->location);
- mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- /* Initialize brush local-space matrix. */
- cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
- mat[0][3] = 0.0f;
- cross_v3_v3v3(mat[1], area_no, mat[0]);
- mat[1][3] = 0.0f;
- copy_v3_v3(mat[2], area_no);
- mat[2][3] = 0.0f;
- copy_v3_v3(mat[3], ss->cache->location);
- mat[3][3] = 1.0f;
- normalize_m4(mat);
-
- /* Scale brush local space matrix. */
- scale_m4_fl(scale, ss->cache->radius);
- mul_m4_m4m4(tmat, mat, scale);
- invert_m4_m4(mat, tmat);
-
- float clay_strength = ss->cache->bstrength *
- sculpt_clay_thumb_get_stabilized_pressure(ss->cache);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no_sp = area_no_sp,
- .area_co = ss->cache->location,
- .mat = mat,
- .clay_strength = clay_strength,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
static void do_gravity_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -5749,6 +3027,12 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Brush Utilities
+ * \{ */
+
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
{
Mesh *me = (Mesh *)ob->data;
@@ -5953,14 +3237,22 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
}
- /* Initialize automasking cache. For anchored brushes with spherical falloff, we start off with
- * zero radius, thus we have no pbvh nodes on the first brush step. */
+ /* For anchored brushes with spherical falloff, we start off with zero radius, thus we have no
+ * PBVH nodes on the first brush step. */
if (totnode ||
((brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) && (brush->flag & BRUSH_ANCHORED))) {
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
+ /* Initialize auto-masking cache. */
if (SCULPT_is_automasking_enabled(sd, ss, brush)) {
ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob);
}
+ /* Initialize surface smooth cache. */
+ if ((brush->sculpt_tool == SCULPT_TOOL_SMOOTH) &&
+ (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_SURFACE)) {
+ BLI_assert(ss->cache->surface_smooth_laplacian_disp == NULL);
+ ss->cache->surface_smooth_laplacian_disp = MEM_callocN(
+ sizeof(float[3]) * SCULPT_vertex_count_get(ss), "HC smooth laplacian b");
+ }
}
}
@@ -6009,7 +3301,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
/* Apply one type of brush action. */
switch (brush->sculpt_tool) {
case SCULPT_TOOL_DRAW:
- do_draw_brush(sd, ob, nodes, totnode);
+ SCULPT_do_draw_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SMOOTH:
if (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_LAPLACIAN) {
@@ -6020,80 +3312,80 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
break;
case SCULPT_TOOL_CREASE:
- do_crease_brush(sd, ob, nodes, totnode);
+ SCULPT_do_crease_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_BLOB:
- do_crease_brush(sd, ob, nodes, totnode);
+ SCULPT_do_crease_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_PINCH:
- do_pinch_brush(sd, ob, nodes, totnode);
+ SCULPT_do_pinch_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_INFLATE:
- do_inflate_brush(sd, ob, nodes, totnode);
+ SCULPT_do_inflate_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_GRAB:
- do_grab_brush(sd, ob, nodes, totnode);
+ SCULPT_do_grab_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_ROTATE:
- do_rotate_brush(sd, ob, nodes, totnode);
+ SCULPT_do_rotate_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SNAKE_HOOK:
- do_snake_hook_brush(sd, ob, nodes, totnode);
+ SCULPT_do_snake_hook_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_NUDGE:
- do_nudge_brush(sd, ob, nodes, totnode);
+ SCULPT_do_nudge_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_THUMB:
- do_thumb_brush(sd, ob, nodes, totnode);
+ SCULPT_do_thumb_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_LAYER:
- do_layer_brush(sd, ob, nodes, totnode);
+ SCULPT_do_layer_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_FLATTEN:
- do_flatten_brush(sd, ob, nodes, totnode);
+ SCULPT_do_flatten_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY:
- do_clay_brush(sd, ob, nodes, totnode);
+ SCULPT_do_clay_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY_STRIPS:
- do_clay_strips_brush(sd, ob, nodes, totnode);
+ SCULPT_do_clay_strips_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_MULTIPLANE_SCRAPE:
SCULPT_do_multiplane_scrape_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY_THUMB:
- do_clay_thumb_brush(sd, ob, nodes, totnode);
+ SCULPT_do_clay_thumb_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_FILL:
if (invert && brush->flag & BRUSH_INVERT_TO_SCRAPE_FILL) {
- do_scrape_brush(sd, ob, nodes, totnode);
+ SCULPT_do_scrape_brush(sd, ob, nodes, totnode);
}
else {
- do_fill_brush(sd, ob, nodes, totnode);
+ SCULPT_do_fill_brush(sd, ob, nodes, totnode);
}
break;
case SCULPT_TOOL_SCRAPE:
if (invert && brush->flag & BRUSH_INVERT_TO_SCRAPE_FILL) {
- do_fill_brush(sd, ob, nodes, totnode);
+ SCULPT_do_fill_brush(sd, ob, nodes, totnode);
}
else {
- do_scrape_brush(sd, ob, nodes, totnode);
+ SCULPT_do_scrape_brush(sd, ob, nodes, totnode);
}
break;
case SCULPT_TOOL_MASK:
- do_mask_brush(sd, ob, nodes, totnode);
+ SCULPT_do_mask_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_POSE:
SCULPT_do_pose_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DRAW_SHARP:
- do_draw_sharp_brush(sd, ob, nodes, totnode);
+ SCULPT_do_draw_sharp_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_ELASTIC_DEFORM:
- do_elastic_deform_brush(sd, ob, nodes, totnode);
+ SCULPT_do_elastic_deform_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SLIDE_RELAX:
- do_slide_relax_brush(sd, ob, nodes, totnode);
+ SCULPT_do_slide_relax_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_BOUNDARY:
SCULPT_do_boundary_brush(sd, ob, nodes, totnode);
@@ -6105,10 +3397,10 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
SCULPT_do_draw_face_sets_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DISPLACEMENT_ERASER:
- do_displacement_eraser_brush(sd, ob, nodes, totnode);
+ SCULPT_do_displacement_eraser_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DISPLACEMENT_SMEAR:
- do_displacement_smear_brush(sd, ob, nodes, totnode);
+ SCULPT_do_displacement_smear_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_PAINT:
SCULPT_do_paint_brush(sd, ob, nodes, totnode);
@@ -6130,7 +3422,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
if (sculpt_brush_use_topology_rake(ss, brush)) {
- bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor);
+ SCULPT_bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor);
}
/* The cloth brush adds the gravity as a regular force and it is processed in the solver. */
@@ -6317,7 +3609,6 @@ static void SCULPT_flush_stroke_deform_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-/* Flush displacement from deformed PBVH to original layer. */
void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
{
SculptSession *ss = ob->sculpt;
@@ -6360,21 +3651,12 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
}
MEM_SAFE_FREE(nodes);
-
- /* Modifiers could depend on mesh normals, so we should update them.
- * NOTE: then if sculpting happens on locked key, normals should be re-calculate after applying
- * coords from key-block on base mesh. */
- BKE_mesh_calc_normals(me);
}
else if (ss->shapekey_active) {
sculpt_update_keyblock(ob);
}
}
-/**
- * Flip all the edit-data across the axis/axes specified by \a symm.
- * Used to calculate multiple modifications to the mesh when symmetry is enabled.
- */
void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,
const char symm,
const char axis,
@@ -6679,8 +3961,7 @@ static const char *sculpt_tool_name(Sculpt *sd)
return "Sculpting";
}
-/**
- * Operator for applying a stroke (various attributes including mouse path)
+/* Operator for applying a stroke (various attributes including mouse path)
* using the current brush. */
void SCULPT_cache_free(StrokeCache *cache)
@@ -6715,6 +3996,8 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
{
ModifierData *md;
+ unit_m4(ss->cache->clip_mirror_mtx);
+
for (md = ob->modifiers.first; md; md = md->next) {
if (!(md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime))) {
continue;
@@ -6736,6 +4019,73 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
if (mmd->tolerance > ss->cache->clip_tolerance[i]) {
ss->cache->clip_tolerance[i] = mmd->tolerance;
}
+
+ /* Store matrix for mirror object clipping. */
+ if (mmd->mirror_ob) {
+ float imtx_mirror_ob[4][4];
+ invert_m4_m4(imtx_mirror_ob, mmd->mirror_ob->obmat);
+ mul_m4_m4m4(ss->cache->clip_mirror_mtx, imtx_mirror_ob, ob->obmat);
+ }
+ }
+ }
+}
+
+static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache)
+{
+ Scene *scene = CTX_data_scene(C);
+ Brush *brush = paint->brush;
+
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ cache->saved_mask_brush_tool = brush->mask_tool;
+ brush->mask_tool = BRUSH_MASK_SMOOTH;
+ }
+ else if (ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_SLIDE_RELAX,
+ SCULPT_TOOL_DRAW_FACE_SETS,
+ SCULPT_TOOL_PAINT,
+ SCULPT_TOOL_SMEAR)) {
+ /* Do nothing, this tool has its own smooth mode. */
+ }
+ else {
+ int cur_brush_size = BKE_brush_size_get(scene, brush);
+
+ BLI_strncpy(cache->saved_active_brush_name,
+ brush->id.name + 2,
+ sizeof(cache->saved_active_brush_name));
+
+ /* Switch to the smooth brush. */
+ brush = BKE_paint_toolslots_brush_get(paint, SCULPT_TOOL_SMOOTH);
+ if (brush) {
+ BKE_paint_brush_set(paint, brush);
+ cache->saved_smooth_size = BKE_brush_size_get(scene, brush);
+ BKE_brush_size_set(scene, brush, cur_brush_size);
+ BKE_curvemapping_init(brush->curve);
+ }
+ }
+}
+
+static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Brush *brush = BKE_paint_brush(paint);
+
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ brush->mask_tool = cache->saved_mask_brush_tool;
+ }
+ else if (ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_SLIDE_RELAX,
+ SCULPT_TOOL_DRAW_FACE_SETS,
+ SCULPT_TOOL_PAINT,
+ SCULPT_TOOL_SMEAR)) {
+ /* Do nothing. */
+ }
+ else {
+ /* Try to switch back to the saved/previous brush. */
+ BKE_brush_size_set(scene, brush, cache->saved_smooth_size);
+ brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, cache->saved_active_brush_name);
+ if (brush) {
+ BKE_paint_brush_set(paint, brush);
}
}
}
@@ -6745,8 +4095,6 @@ static void sculpt_update_cache_invariants(
bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2])
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
Brush *brush = BKE_paint_brush(&sd->paint);
ViewContext *vc = paint_stroke_view_context(op->customdata);
@@ -6811,35 +4159,9 @@ static void sculpt_update_cache_invariants(
/* Alt-Smooth. */
if (cache->alt_smooth) {
- if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
- cache->saved_mask_brush_tool = brush->mask_tool;
- brush->mask_tool = BRUSH_MASK_SMOOTH;
- }
- else if (ELEM(brush->sculpt_tool,
- SCULPT_TOOL_SLIDE_RELAX,
- SCULPT_TOOL_DRAW_FACE_SETS,
- SCULPT_TOOL_PAINT,
- SCULPT_TOOL_SMEAR)) {
- /* Do nothing, this tool has its own smooth mode. */
- }
- else {
- Paint *p = &sd->paint;
- Brush *br;
- int size = BKE_brush_size_get(scene, brush);
-
- BLI_strncpy(cache->saved_active_brush_name,
- brush->id.name + 2,
- sizeof(cache->saved_active_brush_name));
-
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Smooth");
- if (br) {
- BKE_paint_brush_set(p, br);
- brush = br;
- cache->saved_smooth_size = BKE_brush_size_get(scene, brush);
- BKE_brush_size_set(scene, brush, size);
- BKE_curvemapping_init(brush->curve);
- }
- }
+ smooth_brush_toggle_on(C, &sd->paint, cache);
+ /* Refresh the brush pointer in case we switched brush in the toggle function. */
+ brush = BKE_paint_brush(&sd->paint);
}
copy_v2_v2(cache->mouse, cache->initial_mouse);
@@ -6847,9 +4169,7 @@ static void sculpt_update_cache_invariants(
copy_v2_v2(ups->tex_mouse, cache->initial_mouse);
/* Truly temporary data that isn't stored in properties. */
-
cache->vc = vc;
-
cache->brush = brush;
/* Cache projection matrix. */
@@ -6924,7 +4244,7 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo
case SCULPT_TOOL_CLAY_STRIPS:
return max_ff(initial_size * 0.30f, initial_size * powf(cache->pressure, 1.5f));
case SCULPT_TOOL_CLAY_THUMB: {
- float clay_stabilized_pressure = sculpt_clay_thumb_get_stabilized_pressure(cache);
+ float clay_stabilized_pressure = SCULPT_clay_thumb_get_stabilized_pressure(cache);
return initial_size * clay_stabilized_pressure;
}
default:
@@ -7415,9 +4735,6 @@ float SCULPT_raycast_init(ViewContext *vc,
return dist;
}
-/* Gets the normal, location and active vertex location of the geometry under the cursor. This also
- * updates the active vertex and cursor related data of the SculptSession using the mouse position
- */
bool SCULPT_cursor_geometry_info_update(bContext *C,
SculptCursorGeometryInfo *out,
const float mouse[2],
@@ -7547,9 +4864,6 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
return true;
}
-/* Do a raycast in the tree to find the 3d brush location
- * (This allows us to ignore the GL depth buffer)
- * Returns 0 if the ray doesn't hit the mesh, non-zero otherwise. */
bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -7694,8 +5008,7 @@ static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
/* Restore the mesh before continuing with anchored stroke. */
if ((brush->flag & BRUSH_ANCHORED) ||
- ((brush->sculpt_tool == SCULPT_TOOL_GRAB ||
- brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) &&
+ ((ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ELASTIC_DEFORM)) &&
BKE_brush_use_size_pressure(brush)) ||
(brush->flag & BRUSH_DRAG_DOT)) {
@@ -7714,7 +5027,6 @@ static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
}
}
-/* Copy the PBVH bounding box into the object's bounding box. */
void SCULPT_update_object_bounding_box(Object *ob)
{
if (ob->runtime.bb) {
@@ -7975,9 +5287,7 @@ static void sculpt_brush_exit_tex(Sculpt *sd)
static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(stroke))
{
- Main *bmain = CTX_data_main(C);
Object *ob = CTX_data_active_object(C);
- Scene *scene = CTX_data_scene(C);
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -7995,23 +5305,9 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
/* Alt-Smooth. */
if (ss->cache->alt_smooth) {
- if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
- brush->mask_tool = ss->cache->saved_mask_brush_tool;
- }
- else if (ELEM(brush->sculpt_tool,
- SCULPT_TOOL_SLIDE_RELAX,
- SCULPT_TOOL_DRAW_FACE_SETS,
- SCULPT_TOOL_PAINT,
- SCULPT_TOOL_SMEAR)) {
- /* Do nothing. */
- }
- else {
- BKE_brush_size_set(scene, brush, ss->cache->saved_smooth_size);
- brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, ss->cache->saved_active_brush_name);
- if (brush) {
- BKE_paint_brush_set(&sd->paint, brush);
- }
- }
+ smooth_brush_toggle_off(C, &sd->paint, ss->cache);
+ /* Refresh the brush pointer in case we switched brush in the toggle function. */
+ brush = BKE_paint_brush(&sd->paint);
}
if (SCULPT_is_automasking_enabled(sd, ss, brush)) {
@@ -8057,7 +5353,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
/* For tablet rotation. */
ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
- if (ignore_background_click && !over_mesh(C, op, event->x, event->y)) {
+ if (ignore_background_click && !over_mesh(C, op, event->xy[0], event->xy[1])) {
paint_stroke_free(C, op);
return OPERATOR_PASS_THROUGH;
}
@@ -8117,7 +5413,7 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
sculpt_brush_exit_tex(sd);
}
-static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
+void SCULPT_OT_brush_stroke(wmOperatorType *ot)
{
/* Identifiers. */
ot->name = "Sculpt";
@@ -8145,674 +5441,6 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
"Clicks on the background do not start the stroke");
}
-/* Reset the copy of the mesh that is being sculpted on (currently just for the layer brush). */
-
-static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
-
- if (!ss) {
- return OPERATOR_FINISHED;
- }
- SCULPT_vertex_random_access_ensure(ss);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
-
- MEM_SAFE_FREE(ss->persistent_base);
-
- const int totvert = SCULPT_vertex_count_get(ss);
- ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert,
- "layer persistent base");
-
- for (int i = 0; i < totvert; i++) {
- copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i));
- SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no);
- ss->persistent_base[i].disp = 0.0f;
- }
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Set Persistent Base";
- ot->idname = "SCULPT_OT_set_persistent_base";
- ot->description = "Reset the copy of the mesh that is being sculpted on";
-
- /* API callbacks. */
- ot->exec = sculpt_set_persistent_base_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/************************* SCULPT_OT_optimize *************************/
-
-static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
-
- SCULPT_pbvh_clear(ob);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-/* The BVH gets less optimal more quickly with dynamic topology than
- * regular sculpting. There is no doubt more clever stuff we can do to
- * optimize it on the fly, but for now this gives the user a nicer way
- * to recalculate it than toggling modes. */
-static void SCULPT_OT_optimize(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Rebuild BVH";
- ot->idname = "SCULPT_OT_optimize";
- ot->description = "Recalculate the sculpt BVH to improve performance";
-
- /* API callbacks. */
- ot->exec = sculpt_optimize_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/********************* Dynamic topology symmetrize ********************/
-
-static bool sculpt_no_multires_poll(bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- if (SCULPT_mode_poll(C) && ob->sculpt && ob->sculpt->pbvh) {
- return BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_GRIDS;
- }
- return false;
-}
-
-static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- Object *ob = CTX_data_active_object(C);
- const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- SculptSession *ss = ob->sculpt;
- PBVH *pbvh = ss->pbvh;
- const float dist = RNA_float_get(op->ptr, "merge_tolerance");
-
- if (!pbvh) {
- return OPERATOR_CANCELLED;
- }
-
- switch (BKE_pbvh_type(pbvh)) {
- case PBVH_BMESH:
- /* Dyntopo Symmetrize. */
-
- /* To simplify undo for symmetrize, all BMesh elements are logged
- * as deleted, then after symmetrize operation all BMesh elements
- * are logged as added (as opposed to attempting to store just the
- * parts that symmetrize modifies). */
- SCULPT_undo_push_begin(ob, "Dynamic topology symmetrize");
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
- BM_log_before_all_removed(ss->bm, ss->bm_log);
-
- BM_mesh_toolflags_set(ss->bm, true);
-
- /* Symmetrize and re-triangulate. */
- BMO_op_callf(ss->bm,
- (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
- "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b",
- sd->symmetrize_direction,
- dist,
- true);
- SCULPT_dynamic_topology_triangulate(ss->bm);
-
- /* Bisect operator flags edges (keep tags clean for edge queue). */
- BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
-
- BM_mesh_toolflags_set(ss->bm, false);
-
- /* Finish undo. */
- BM_log_all_added(ss->bm, ss->bm_log);
- SCULPT_undo_push_end();
-
- break;
- case PBVH_FACES:
- /* Mesh Symmetrize. */
- ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize");
- Mesh *mesh = ob->data;
-
- BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist);
-
- ED_sculpt_undo_geometry_end(ob);
- BKE_mesh_calc_normals(ob->data);
- BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
-
- break;
- case PBVH_GRIDS:
- return OPERATOR_CANCELLED;
- }
-
- /* Redraw. */
- SCULPT_pbvh_clear(ob);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_symmetrize(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Symmetrize";
- ot->idname = "SCULPT_OT_symmetrize";
- ot->description = "Symmetrize the topology modifications";
-
- /* API callbacks. */
- ot->exec = sculpt_symmetrize_exec;
- ot->poll = sculpt_no_multires_poll;
-
- RNA_def_float(ot->srna,
- "merge_tolerance",
- 0.001f,
- 0.0f,
- FLT_MAX,
- "Merge Distance",
- "Distance within which symmetrical vertices are merged",
- 0.0f,
- 1.0f);
-}
-
-/**** Toggle operator for turning sculpt mode on or off ****/
-
-static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
-{
- /* Create persistent sculpt mode data. */
- BKE_sculpt_toolsettings_data_ensure(scene);
-
- /* Create sculpt mode session data. */
- if (ob->sculpt != NULL) {
- BKE_sculptsession_free(ob);
- }
- ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
- ob->sculpt->mode_type = OB_MODE_SCULPT;
-
- BKE_sculpt_ensure_orig_mesh_data(scene, ob);
-
- BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
-
- /* This function expects a fully evaluated depsgraph. */
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
-
- /* Here we can detect geometry that was just added to Sculpt Mode as it has the
- * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */
- /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not
- * initialized, which is used is some operators that modify the mesh topology to perform certain
- * actions in the new polys. After these operations are finished, all polys should have a valid
- * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility
- * correctly. */
- /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new
- * objects, like moving the transform pivot position to the new area or masking existing
- * geometry. */
- SculptSession *ss = ob->sculpt;
- const int new_face_set = SCULPT_face_set_next_available_get(ss);
- for (int i = 0; i < ss->totfaces; i++) {
- if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) {
- ss->face_sets[i] = new_face_set;
- }
- }
-}
-
-void ED_object_sculptmode_enter_ex(Main *bmain,
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- const bool force_dyntopo,
- ReportList *reports)
-{
- const int mode_flag = OB_MODE_SCULPT;
- Mesh *me = BKE_mesh_from_object(ob);
-
- /* Enter sculpt mode. */
- ob->mode |= mode_flag;
-
- sculpt_init_session(bmain, depsgraph, scene, ob);
-
- if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f &&
- fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) {
- BKE_report(
- reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable");
- }
- else if (is_negative_m4(ob->obmat)) {
- BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable");
- }
-
- Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT);
- BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT);
-
- paint_cursor_start(paint, SCULPT_mode_poll_view3d);
-
- /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
- * As long as no data was added that is not supported. */
- if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
-
- const char *message_unsupported = NULL;
- if (me->totloop != me->totpoly * 3) {
- message_unsupported = TIP_("non-triangle face");
- }
- else if (mmd != NULL) {
- message_unsupported = TIP_("multi-res modifier");
- }
- else {
- enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob);
- if (flag == 0) {
- /* pass */
- }
- else if (flag & DYNTOPO_WARN_VDATA) {
- message_unsupported = TIP_("vertex data");
- }
- else if (flag & DYNTOPO_WARN_EDATA) {
- message_unsupported = TIP_("edge data");
- }
- else if (flag & DYNTOPO_WARN_LDATA) {
- message_unsupported = TIP_("face data");
- }
- else if (flag & DYNTOPO_WARN_MODIFIER) {
- message_unsupported = TIP_("constructive modifier");
- }
- else {
- BLI_assert(0);
- }
- }
-
- if ((message_unsupported == NULL) || force_dyntopo) {
- /* Needed because we may be entering this mode before the undo system loads. */
- wmWindowManager *wm = bmain->wm.first;
- bool has_undo = wm->undo_stack != NULL;
- /* Undo push is needed to prevent memory leak. */
- if (has_undo) {
- SCULPT_undo_push_begin(ob, "Dynamic topology enable");
- }
- SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
- if (has_undo) {
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
- SCULPT_undo_push_end();
- }
- }
- else {
- BKE_reportf(
- reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported);
- me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
- }
- }
-
- /* Flush object mode. */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
-}
-
-void ED_object_sculptmode_enter(struct bContext *C, Depsgraph *depsgraph, ReportList *reports)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports);
-}
-
-void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
-{
- const int mode_flag = OB_MODE_SCULPT;
- Mesh *me = BKE_mesh_from_object(ob);
-
- multires_flush_sculpt_updates(ob);
-
- /* Not needed for now. */
-#if 0
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
-#endif
-
- /* Always for now, so leaving sculpt mode always ensures scene is in
- * a consistent state. */
- if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
-
- if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
- /* Dynamic topology must be disabled before exiting sculpt
- * mode to ensure the undo stack stays in a consistent
- * state. */
- sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob);
-
- /* Store so we know to re-enable when entering sculpt mode. */
- me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
- }
-
- /* Leave sculpt mode. */
- ob->mode &= ~mode_flag;
-
- BKE_sculptsession_free(ob);
-
- paint_cursor_delete_textures();
-
- /* Never leave derived meshes behind. */
- BKE_object_free_derived_caches(ob);
-
- /* Flush object mode. */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
-}
-
-void ED_object_sculptmode_exit(bContext *C, Depsgraph *depsgraph)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
-}
-
-static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
-{
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- const int mode_flag = OB_MODE_SCULPT;
- const bool is_mode_set = (ob->mode & mode_flag) != 0;
-
- if (!is_mode_set) {
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
- return OPERATOR_CANCELLED;
- }
- }
-
- if (is_mode_set) {
- ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
- }
- else {
- if (depsgraph) {
- depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- }
- ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports);
- BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint);
-
- if (ob->mode & mode_flag) {
- Mesh *me = ob->data;
- /* Dyntopo adds its own undo step. */
- if ((me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) {
- /* Without this the memfile undo step is used,
- * while it works it causes lag when undoing the first undo step, see T71564. */
- wmWindowManager *wm = CTX_wm_manager(C);
- if (wm->op_undo_depth <= 1) {
- SCULPT_undo_push_begin(ob, op->type->name);
- }
- }
- }
- }
-
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
-
- WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
-
- WM_toolsystem_update_from_context_view3d(C);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Sculpt Mode";
- ot->idname = "SCULPT_OT_sculptmode_toggle";
- ot->description = "Toggle sculpt mode in 3D view";
-
- /* API callbacks. */
- ot->exec = sculpt_mode_toggle_exec;
- ot->poll = ED_operator_object_active_editable_mesh;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
-
- ss->preview_vert_index_count = 0;
- int totpoints = 0;
-
- /* This function is called from the cursor drawing code, so the PBVH may not be build yet. */
- if (!ss->pbvh) {
- return;
- }
-
- if (!ss->deform_modifiers_active) {
- return;
- }
-
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return;
- }
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
-
- if (!ss->pmap) {
- return;
- }
-
- float brush_co[3];
- copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss));
-
- BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
-
- /* Assuming an average of 6 edges per vertex in a triangulated mesh. */
- const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2;
-
- if (ss->preview_vert_index_list == NULL) {
- ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
- }
-
- GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
- int active_v = SCULPT_active_vertex_get(ss);
- BLI_gsqueue_push(not_visited_vertices, &active_v);
-
- while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
- int from_v;
- BLI_gsqueue_pop(not_visited_vertices, &from_v);
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
- if (totpoints + (ni.size * 2) < max_preview_vertices) {
- int to_v = ni.index;
- ss->preview_vert_index_list[totpoints] = from_v;
- totpoints++;
- ss->preview_vert_index_list[totpoints] = to_v;
- totpoints++;
- if (BLI_BITMAP_TEST(visited_vertices, to_v)) {
- continue;
- }
- BLI_BITMAP_ENABLE(visited_vertices, to_v);
- const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v);
- if (len_squared_v3v3(brush_co, co) < radius * radius) {
- BLI_gsqueue_push(not_visited_vertices, &to_v);
- }
- }
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
- }
-
- BLI_gsqueue_free(not_visited_vertices);
-
- MEM_freeN(visited_vertices);
-
- ss->preview_vert_index_count = totpoints;
-}
-
-static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
-
- ID *data;
- data = ob->data;
- if (data && ID_IS_LINKED(data)) {
- return OPERATOR_CANCELLED;
- }
-
- if (ob->type != OB_MESH) {
- return OPERATOR_CANCELLED;
- }
-
- Mesh *mesh = ob->data;
-
- const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
- if (mloopcol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
-
- const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
- if (MPropCol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
-
- MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
- MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
-
- for (int i = 0; i < mesh->totpoly; i++) {
- MPoly *c_poly = &polys[i];
- for (int j = 0; j < c_poly->totloop; j++) {
- int loop_index = c_poly->loopstart + j;
- MLoop *c_loop = &loops[c_poly->loopstart + j];
- loopcols[loop_index].r = (char)(vertcols[c_loop->v].color[0] * 255);
- loopcols[loop_index].g = (char)(vertcols[c_loop->v].color[1] * 255);
- loopcols[loop_index].b = (char)(vertcols[c_loop->v].color[2] * 255);
- loopcols[loop_index].a = (char)(vertcols[c_loop->v].color[3] * 255);
- }
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Sculpt Vertex Color to Vertex Color";
- ot->description = "Copy the Sculpt Vertex Color to a regular color layer";
- ot->idname = "SCULPT_OT_vertex_to_loop_colors";
-
- /* api callbacks */
- ot->poll = SCULPT_vertex_colors_poll;
- ot->exec = vertex_to_loop_colors_exec;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
-
- ID *data;
- data = ob->data;
- if (data && ID_IS_LINKED(data)) {
- return OPERATOR_CANCELLED;
- }
-
- if (ob->type != OB_MESH) {
- return OPERATOR_CANCELLED;
- }
-
- Mesh *mesh = ob->data;
-
- const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
- if (mloopcol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
-
- const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
- if (MPropCol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
-
- MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
- MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
-
- for (int i = 0; i < mesh->totpoly; i++) {
- MPoly *c_poly = &polys[i];
- for (int j = 0; j < c_poly->totloop; j++) {
- int loop_index = c_poly->loopstart + j;
- MLoop *c_loop = &loops[c_poly->loopstart + j];
- vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f);
- vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f);
- vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f);
- vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f);
- }
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Vertex Color to Sculpt Vertex Color";
- ot->description = "Copy the active loop color layer to the vertex color";
- ot->idname = "SCULPT_OT_loop_to_vertex_colors";
-
- /* api callbacks */
- ot->poll = SCULPT_vertex_colors_poll;
- ot->exec = loop_to_vertex_colors_exec;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int sculpt_sample_color_invoke(bContext *C,
- wmOperator *UNUSED(op),
- const wmEvent *UNUSED(e))
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
- int active_vertex = SCULPT_active_vertex_get(ss);
- const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex);
- if (!active_vertex_color) {
- return OPERATOR_CANCELLED;
- }
-
- float color_srgb[3];
- copy_v3_v3(color_srgb, active_vertex_color);
- IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb);
- BKE_brush_color_set(scene, brush, color_srgb);
-
- WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_sample_color(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Sample Color";
- ot->idname = "SCULPT_OT_sample_color";
- ot->description = "Sample the vertex color of the active vertex";
-
- /* api callbacks */
- ot->invoke = sculpt_sample_color_invoke;
- ot->poll = SCULPT_vertex_colors_poll;
-
- ot->flag = OPTYPE_REGISTER;
-}
-
/* Fake Neighbors. */
/* This allows the sculpt tools to work on meshes with multiple connected components as they had
* only one connected component. When initialized and enabled, the sculpt API will return extra
@@ -9088,348 +5716,10 @@ void SCULPT_fake_neighbors_free(Object *ob)
sculpt_pose_fake_neighbors_free(ss);
}
-/**
- * #sculpt_mask_by_color_delta_get returns values in the (0,1) range that are used to generate the
- * mask based on the difference between two colors (the active color and the color of any other
- * vertex). Ideally, a threshold of 0 should mask only the colors that are equal to the active
- * color and threshold of 1 should mask all colors. In order to avoid artifacts and produce softer
- * falloffs in the mask, the MASK_BY_COLOR_SLOPE defines the size of the transition values between
- * masked and unmasked vertices. The smaller this value is, the sharper the generated mask is going
- * to be.
- */
-#define MASK_BY_COLOR_SLOPE 0.25f
-
-static float sculpt_mask_by_color_delta_get(const float *color_a,
- const float *color_b,
- const float threshold,
- const bool invert)
-{
- float len = len_v3v3(color_a, color_b);
- /* Normalize len to the (0, 1) range. */
- len = len / M_SQRT3;
-
- if (len < threshold - MASK_BY_COLOR_SLOPE) {
- len = 1.0f;
- }
- else if (len >= threshold) {
- len = 0.0f;
- }
- else {
- len = (-len + threshold) / MASK_BY_COLOR_SLOPE;
- }
-
- if (invert) {
- return 1.0f - len;
- }
- return len;
-}
-
-static float sculpt_mask_by_color_final_mask_get(const float current_mask,
- const float new_mask,
- const bool invert,
- const bool preserve_mask)
-{
- if (preserve_mask) {
- if (invert) {
- return min_ff(current_mask, new_mask);
- }
- return max_ff(current_mask, new_mask);
- }
- return new_mask;
-}
-
-typedef struct MaskByColorContiguousFloodFillData {
- float threshold;
- bool invert;
- float *new_mask;
- float initial_color[3];
-} MaskByColorContiguousFloodFillData;
-
-static void do_mask_by_color_contiguous_update_nodes_cb(
- void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
-
- SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
- bool update_node = false;
-
- const bool invert = data->mask_by_color_invert;
- const bool preserve_mask = data->mask_by_color_preserve_mask;
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- const float current_mask = *vd.mask;
- const float new_mask = data->mask_by_color_floodfill[vd.index];
- *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
- if (current_mask == *vd.mask) {
- continue;
- }
- update_node = true;
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
- if (update_node) {
- BKE_pbvh_node_mark_redraw(data->nodes[n]);
- }
-}
-
-static bool sculpt_mask_by_color_contiguous_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
-{
- MaskByColorContiguousFloodFillData *data = userdata;
- const float *current_color = SCULPT_vertex_color_get(ss, to_v);
- float new_vertex_mask = sculpt_mask_by_color_delta_get(
- current_color, data->initial_color, data->threshold, data->invert);
- data->new_mask[to_v] = new_vertex_mask;
-
- if (is_duplicate) {
- data->new_mask[to_v] = data->new_mask[from_v];
- }
-
- float len = len_v3v3(current_color, data->initial_color);
- len = len / M_SQRT3;
- return len <= data->threshold;
-}
-
-static void sculpt_mask_by_color_contiguous(Object *object,
- const int vertex,
- const float threshold,
- const bool invert,
- const bool preserve_mask)
-{
- SculptSession *ss = object->sculpt;
- const int totvert = SCULPT_vertex_count_get(ss);
-
- float *new_mask = MEM_calloc_arrayN(totvert, sizeof(float), "new mask");
-
- if (invert) {
- for (int i = 0; i < totvert; i++) {
- new_mask[i] = 1.0f;
- }
- }
-
- SculptFloodFill flood;
- SCULPT_floodfill_init(ss, &flood);
- SCULPT_floodfill_add_initial(&flood, vertex);
-
- MaskByColorContiguousFloodFillData ffd;
- ffd.threshold = threshold;
- ffd.invert = invert;
- ffd.new_mask = new_mask;
- copy_v3_v3(ffd.initial_color, SCULPT_vertex_color_get(ss, vertex));
-
- SCULPT_floodfill_execute(ss, &flood, sculpt_mask_by_color_contiguous_floodfill_cb, &ffd);
- SCULPT_floodfill_free(&flood);
-
- int totnode;
- PBVHNode **nodes;
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-
- SculptThreadedTaskData data = {
- .ob = object,
- .nodes = nodes,
- .mask_by_color_floodfill = new_mask,
- .mask_by_color_vertex = vertex,
- .mask_by_color_threshold = threshold,
- .mask_by_color_invert = invert,
- .mask_by_color_preserve_mask = preserve_mask,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(
- 0, totnode, &data, do_mask_by_color_contiguous_update_nodes_cb, &settings);
-
- MEM_SAFE_FREE(nodes);
-
- MEM_freeN(new_mask);
-}
-
-static void do_mask_by_color_task_cb(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
-
- SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
- bool update_node = false;
-
- const float threshold = data->mask_by_color_threshold;
- const bool invert = data->mask_by_color_invert;
- const bool preserve_mask = data->mask_by_color_preserve_mask;
- const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- const float current_mask = *vd.mask;
- const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert);
- *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
-
- if (current_mask == *vd.mask) {
- continue;
- }
- update_node = true;
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
- if (update_node) {
- BKE_pbvh_node_mark_redraw(data->nodes[n]);
- }
-}
-
-static void sculpt_mask_by_color_full_mesh(Object *object,
- const int vertex,
- const float threshold,
- const bool invert,
- const bool preserve_mask)
-{
- SculptSession *ss = object->sculpt;
-
- int totnode;
- PBVHNode **nodes;
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-
- SculptThreadedTaskData data = {
- .ob = object,
- .nodes = nodes,
- .mask_by_color_vertex = vertex,
- .mask_by_color_threshold = threshold,
- .mask_by_color_invert = invert,
- .mask_by_color_preserve_mask = preserve_mask,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_mask_by_color_task_cb, &settings);
-
- MEM_SAFE_FREE(nodes);
-}
-
-static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
-
- /* Color data is not available in Multires. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
- return OPERATOR_CANCELLED;
- }
-
- if (!ss->vcol) {
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_vertex_random_access_ensure(ss);
-
- /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move,
- * so it needs to be updated here. */
- SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
-
- SCULPT_undo_push_begin(ob, "Mask by color");
-
- const int active_vertex = SCULPT_active_vertex_get(ss);
- const float threshold = RNA_float_get(op->ptr, "threshold");
- const bool invert = RNA_boolean_get(op->ptr, "invert");
- const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask");
-
- if (RNA_boolean_get(op->ptr, "contiguous")) {
- sculpt_mask_by_color_contiguous(ob, active_vertex, threshold, invert, preserve_mask);
- }
- else {
- sculpt_mask_by_color_full_mesh(ob, active_vertex, threshold, invert, preserve_mask);
- }
-
- BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
- SCULPT_undo_push_end();
-
- SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+/** \} */
- return OPERATOR_FINISHED;
-}
+/* -------------------------------------------------------------------- */
+/** \name Operator Registration
+ * \{ */
-static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Mask by Color";
- ot->idname = "SCULPT_OT_mask_by_color";
- ot->description = "Creates a mask based on the sculpt vertex colors";
-
- /* api callbacks */
- ot->invoke = sculpt_mask_by_color_invoke;
- ot->poll = SCULPT_vertex_colors_poll;
-
- ot->flag = OPTYPE_REGISTER;
-
- ot->prop = RNA_def_boolean(
- ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas");
-
- ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask");
- ot->prop = RNA_def_boolean(
- ot->srna,
- "preserve_previous_mask",
- false,
- "Preserve Previous Mask",
- "Preserve the previous mask and add or subtract the new one generated by the colors");
-
- RNA_def_float(ot->srna,
- "threshold",
- 0.35f,
- 0.0f,
- 1.0f,
- "Threshold",
- "How much changes in color affect the mask generation",
- 0.0f,
- 1.0f);
-}
-
-void ED_operatortypes_sculpt(void)
-{
- WM_operatortype_append(SCULPT_OT_brush_stroke);
- WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
- WM_operatortype_append(SCULPT_OT_set_persistent_base);
- WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle);
- WM_operatortype_append(SCULPT_OT_optimize);
- WM_operatortype_append(SCULPT_OT_symmetrize);
- WM_operatortype_append(SCULPT_OT_detail_flood_fill);
- WM_operatortype_append(SCULPT_OT_sample_detail_size);
- WM_operatortype_append(SCULPT_OT_set_detail_size);
- WM_operatortype_append(SCULPT_OT_mesh_filter);
- WM_operatortype_append(SCULPT_OT_mask_filter);
- WM_operatortype_append(SCULPT_OT_dirty_mask);
- WM_operatortype_append(SCULPT_OT_mask_expand);
- WM_operatortype_append(SCULPT_OT_set_pivot_position);
- WM_operatortype_append(SCULPT_OT_face_sets_create);
- WM_operatortype_append(SCULPT_OT_face_sets_change_visibility);
- WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors);
- WM_operatortype_append(SCULPT_OT_face_sets_init);
- WM_operatortype_append(SCULPT_OT_cloth_filter);
- WM_operatortype_append(SCULPT_OT_face_sets_edit);
- WM_operatortype_append(SCULPT_OT_face_set_lasso_gesture);
- WM_operatortype_append(SCULPT_OT_face_set_box_gesture);
- WM_operatortype_append(SCULPT_OT_trim_box_gesture);
- WM_operatortype_append(SCULPT_OT_trim_lasso_gesture);
- WM_operatortype_append(SCULPT_OT_project_line_gesture);
-
- WM_operatortype_append(SCULPT_OT_sample_color);
- WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors);
- WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors);
- WM_operatortype_append(SCULPT_OT_color_filter);
- WM_operatortype_append(SCULPT_OT_mask_by_color);
- WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit);
- WM_operatortype_append(SCULPT_OT_mask_init);
-
- WM_operatortype_append(SCULPT_OT_expand);
-}
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index 37678ec276a..1e41c5cdbdf 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -487,8 +487,6 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
}
}
-/* Main function to get SculptBoundary data both for brush deformation and viewport preview. Can
- * return NULL if there is no boundary from the given vertex using the given radius. */
SculptBoundary *SCULPT_boundary_data_init(Object *object,
Brush *brush,
const int initial_vertex,
@@ -774,12 +772,10 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
- float normal[3];
- normal_short_to_float_v3(normal, orig_data.no);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
- normal,
+ orig_data.no,
boundary->edit_info[vd.index].strength_factor * disp * mask * automask *
strength);
@@ -946,7 +942,6 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-/* Main Brush Function. */
void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
new file mode 100644
index 00000000000..c2acc361a79
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
@@ -0,0 +1,2847 @@
+/*
+ * 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) 2006 by Nicholas Bishop
+ * All rights reserved.
+ * Implements the Sculpt Mode tools
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_dial_2d.h"
+#include "BLI_ghash.h"
+#include "BLI_gsqueue.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_math_color.h"
+#include "BLI_math_color_blend.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "PIL_time.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_ccg.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_kelvinlet.h"
+#include "BKE_key.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_mirror.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_pbvh.h"
+#include "BKE_pointcache.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_subdiv_ccg.h"
+#include "BKE_subsurf.h"
+
+#include "DEG_depsgraph.h"
+
+#include "IMB_colormanagement.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* -------------------------------------------------------------------- */
+/** \name SculptProjectVector
+ *
+ * Fast-path for #project_plane_v3_v3v3
+ * \{ */
+
+typedef struct SculptProjectVector {
+ float plane[3];
+ float len_sq;
+ float len_sq_inv_neg;
+ bool is_valid;
+
+} SculptProjectVector;
+
+static bool plane_point_side_flip(const float co[3], const float plane[4], const bool flip)
+{
+ float d = plane_point_side_v3(plane, co);
+ if (flip) {
+ d = -d;
+ }
+ return d <= 0.0f;
+}
+
+/**
+ * \param plane: Direction, can be any length.
+ */
+static void sculpt_project_v3_cache_init(SculptProjectVector *spvc, const float plane[3])
+{
+ copy_v3_v3(spvc->plane, plane);
+ spvc->len_sq = len_squared_v3(spvc->plane);
+ spvc->is_valid = (spvc->len_sq > FLT_EPSILON);
+ spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f;
+}
+
+/**
+ * Calculate the projection.
+ */
+static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3], float r_vec[3])
+{
+#if 0
+ project_plane_v3_v3v3(r_vec, vec, spvc->plane);
+#else
+ /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */
+ madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg);
+#endif
+}
+
+static void calc_sculpt_plane(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (SCULPT_stroke_is_main_symmetry_pass(ss->cache) &&
+ (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache) ||
+ !(brush->flag & BRUSH_ORIGINAL_PLANE) || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
+ switch (brush->sculpt_plane) {
+ case SCULPT_DISP_DIR_VIEW:
+ copy_v3_v3(r_area_no, ss->cache->true_view_normal);
+ break;
+
+ case SCULPT_DISP_DIR_X:
+ ARRAY_SET_ITEMS(r_area_no, 1.0f, 0.0f, 0.0f);
+ break;
+
+ case SCULPT_DISP_DIR_Y:
+ ARRAY_SET_ITEMS(r_area_no, 0.0f, 1.0f, 0.0f);
+ break;
+
+ case SCULPT_DISP_DIR_Z:
+ ARRAY_SET_ITEMS(r_area_no, 0.0f, 0.0f, 1.0f);
+ break;
+
+ case SCULPT_DISP_DIR_AREA:
+ SCULPT_calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
+ normalize_v3(r_area_no);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* For flatten center. */
+ /* Flatten center has not been calculated yet if we are not using the area normal. */
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) {
+ SCULPT_calc_area_center(sd, ob, nodes, totnode, r_area_co);
+ }
+
+ /* For area normal. */
+ if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
+ (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
+ }
+ else {
+ copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
+ }
+
+ /* For flatten center. */
+ if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
+ (brush->flag & BRUSH_ORIGINAL_PLANE)) {
+ copy_v3_v3(r_area_co, ss->cache->last_center);
+ }
+ else {
+ copy_v3_v3(ss->cache->last_center, r_area_co);
+ }
+ }
+ else {
+ /* For area normal. */
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
+
+ /* For flatten center. */
+ copy_v3_v3(r_area_co, ss->cache->last_center);
+
+ /* For area normal. */
+ flip_v3(r_area_no, ss->cache->mirror_symmetry_pass);
+
+ /* For flatten center. */
+ flip_v3(r_area_co, ss->cache->mirror_symmetry_pass);
+
+ /* For area normal. */
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_no);
+
+ /* For flatten center. */
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_co);
+
+ /* Shift the plane for the current tile. */
+ add_v3_v3(r_area_co, ss->cache->plane_offset);
+ }
+}
+
+static void sculpt_rake_rotate(const SculptSession *ss,
+ const float sculpt_co[3],
+ const float v_co[3],
+ float factor,
+ float r_delta[3])
+{
+ float vec_rot[3];
+
+#if 0
+ /* lerp */
+ sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+ mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot);
+ add_v3_v3(vec_rot, sculpt_co);
+ sub_v3_v3v3(r_delta, vec_rot, v_co);
+ mul_v3_fl(r_delta, factor);
+#else
+ /* slerp */
+ float q_interp[4];
+ sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+
+ copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry);
+ pow_qt_fl_normalized(q_interp, factor);
+ mul_qt_v3(q_interp, vec_rot);
+
+ add_v3_v3(vec_rot, sculpt_co);
+ sub_v3_v3v3(r_delta, vec_rot, v_co);
+#endif
+}
+
+/**
+ * Align the grab delta to the brush normal.
+ *
+ * \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`.
+ */
+static void sculpt_project_v3_normal_align(SculptSession *ss,
+ const float normal_weight,
+ float grab_delta[3])
+{
+ /* Signed to support grabbing in (to make a hole) as well as out. */
+ const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta);
+
+ /* This scale effectively projects the offset so dragging follows the cursor,
+ * as the normal points towards the view, the scale increases. */
+ float len_view_scale;
+ {
+ float view_aligned_normal[3];
+ project_plane_v3_v3v3(
+ view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal);
+ len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm));
+ len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f;
+ }
+
+ mul_v3_fl(grab_delta, 1.0f - normal_weight);
+ madd_v3_v3fl(
+ grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Draw Brush
+ * \{ */
+
+static void do_draw_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ /* Offset vertex. */
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ const float bstrength = ss->cache->bstrength;
+
+ /* Offset with as much as possible factored in already. */
+ float effective_normal[3];
+ SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
+ mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
+ * initialize before threads so they can do curve mapping. */
+ BKE_curvemapping_init(brush->curve);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .offset = offset,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+static void do_fill_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ if (!SCULPT_plane_point_side(vd.co, test.plane_tool)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (!SCULPT_plane_trim(ss->cache, brush, val)) {
+ continue;
+ }
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+
+ float area_no[3];
+ float area_co[3];
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+
+ float displace;
+
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
+
+ displace = radius * offset;
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
+}
+
+static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ if (SCULPT_plane_point_side(vd.co, test.plane_tool)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (!SCULPT_plane_trim(ss->cache, brush, val)) {
+ continue;
+ }
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+
+ float area_no[3];
+ float area_co[3];
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+
+ float displace;
+
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
+
+ displace = -radius * offset;
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Clay Thumb Brush
+ * \{ */
+
+static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float(*mat)[4] = data->mat;
+ const float *area_no_sp = data->area_no_sp;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = data->clay_strength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ float plane_tilt[4];
+ float normal_tilt[3];
+ float imat[4][4];
+
+ invert_m4_m4(imat, mat);
+ rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss->cache->clay_thumb_front_angle));
+
+ /* Plane aligned to the geometry normal (back part of the brush). */
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
+ /* Tilted plane (front part of the brush). */
+ plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ float local_co[3];
+ mul_v3_m4v3(local_co, mat, vd.co);
+ float intr[3], intr_tilt[3];
+ float val[3];
+
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ closest_to_plane_normalized_v3(intr_tilt, plane_tilt, vd.co);
+
+ /* Mix the deformation of the aligned and the tilted plane based on the brush space vertex
+ * coordinates. */
+ /* We can also control the mix with a curve if it produces noticeable artifacts in the center
+ * of the brush. */
+ const float tilt_mix = local_co[1] > 0.0f ? 0.0f : 1.0f;
+ interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix);
+ sub_v3_v3v3(val, intr_tilt, vd.co);
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+float SCULPT_clay_thumb_get_stabilized_pressure(StrokeCache *cache)
+{
+ float final_pressure = 0.0f;
+ for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) {
+ final_pressure += cache->clay_pressure_stabilizer[i];
+ }
+ return final_pressure / SCULPT_CLAY_STABILIZER_LEN;
+}
+
+void SCULPT_do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+ const float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ const float displace = radius * (0.25f + offset);
+
+ /* Sampled geometry normal and area center. */
+ float area_no_sp[3];
+ float area_no[3];
+ float area_co[3];
+
+ float temp[3];
+ float mat[4][4];
+ float scale[4][4];
+ float tmat[4][4];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
+
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
+ }
+ else {
+ copy_v3_v3(area_no, area_no_sp);
+ }
+
+ /* Delay the first daub because grab delta is not setup. */
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ ss->cache->clay_thumb_front_angle = 0.0f;
+ return;
+ }
+
+ /* Simulate the clay accumulation by increasing the plane angle as more samples are added to the
+ * stroke. */
+ if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) {
+ ss->cache->clay_thumb_front_angle += 0.8f;
+ ss->cache->clay_thumb_front_angle = clamp_f(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f);
+ }
+
+ if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
+ return;
+ }
+
+ /* Displace the brush planes. */
+ copy_v3_v3(area_co, ss->cache->location);
+ mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ /* Initialize brush local-space matrix. */
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
+ mat[0][3] = 0.0f;
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
+ mat[1][3] = 0.0f;
+ copy_v3_v3(mat[2], area_no);
+ mat[2][3] = 0.0f;
+ copy_v3_v3(mat[3], ss->cache->location);
+ mat[3][3] = 1.0f;
+ normalize_m4(mat);
+
+ /* Scale brush local space matrix. */
+ scale_m4_fl(scale, ss->cache->radius);
+ mul_m4_m4m4(tmat, mat, scale);
+ invert_m4_m4(mat, tmat);
+
+ float clay_strength = ss->cache->bstrength *
+ SCULPT_clay_thumb_get_stabilized_pressure(ss->cache);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no_sp = area_no_sp,
+ .area_co = ss->cache->location,
+ .mat = mat,
+ .clay_strength = clay_strength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ float intr[3];
+ float val[3];
+
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (SCULPT_plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+
+ float area_no[3];
+ float area_co[3];
+
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ float displace;
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
+
+ displace = radius * offset;
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Clay Brush
+ * \{ */
+
+typedef struct ClaySampleData {
+ float plane_dist[2];
+} ClaySampleData;
+
+static void calc_clay_surface_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ ClaySampleData *csd = tls->userdata_chunk;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+ float plane[4];
+
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, brush->falloff_shape);
+
+ /* Apply the brush normal radius to the test before sampling. */
+ float test_radius = sqrtf(test.radius_squared);
+ test_radius *= brush->normal_radius_factor;
+ test.radius_squared = test_radius * test_radius;
+ plane_from_point_normal_v3(plane, area_co, area_no);
+
+ if (is_zero_v4(plane)) {
+ return;
+ }
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ float plane_dist = dist_signed_to_plane_v3(vd.co, plane);
+ float plane_dist_abs = fabsf(plane_dist);
+ if (plane_dist > 0.0f) {
+ csd->plane_dist[0] = MIN2(csd->plane_dist[0], plane_dist_abs);
+ }
+ else {
+ csd->plane_dist[1] = MIN2(csd->plane_dist[1], plane_dist_abs);
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+}
+
+static void calc_clay_surface_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ ClaySampleData *join = chunk_join;
+ ClaySampleData *csd = chunk;
+ join->plane_dist[0] = MIN2(csd->plane_dist[0], join->plane_dist[0]);
+ join->plane_dist[1] = MIN2(csd->plane_dist[1], join->plane_dist[1]);
+}
+
+static void do_clay_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = fabsf(ss->cache->bstrength);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = fabsf(ss->cache->radius);
+ const float initial_radius = fabsf(ss->cache->initial_radius);
+ bool flip = ss->cache->bstrength < 0.0f;
+
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ float displace;
+
+ float area_no[3];
+ float area_co[3];
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SculptThreadedTaskData sample_data = {
+ .sd = NULL,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .totnode = totnode,
+ .area_no = area_no,
+ .area_co = ss->cache->location,
+ };
+
+ ClaySampleData csd = {{0}};
+
+ TaskParallelSettings sample_settings;
+ BKE_pbvh_parallel_range_settings(&sample_settings, true, totnode);
+ sample_settings.func_reduce = calc_clay_surface_reduce;
+ sample_settings.userdata_chunk = &csd;
+ sample_settings.userdata_chunk_size = sizeof(ClaySampleData);
+
+ BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
+
+ float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]);
+ d_offset = min_ff(radius, d_offset);
+ d_offset = d_offset / radius;
+ d_offset = 1.0f - d_offset;
+ displace = fabsf(initial_radius * (0.25f + offset + (d_offset * 0.15f)));
+ if (flip) {
+ displace = -displace;
+ }
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ copy_v3_v3(area_co, ss->cache->location);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
+}
+
+static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float(*mat)[4] = data->mat;
+ const float *area_no_sp = data->area_no_sp;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float(*proxy)[3];
+ const bool flip = (ss->cache->bstrength < 0.0f);
+ const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SCULPT_brush_test_init(ss, &test);
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) {
+ continue;
+ }
+
+ if (!plane_point_side_flip(vd.co, test.plane_tool, flip)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (!SCULPT_plane_trim(ss->cache, brush, val)) {
+ continue;
+ }
+ /* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ ss->cache->radius * test.dist,
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const bool flip = (ss->cache->bstrength < 0.0f);
+ const float radius = flip ? -ss->cache->radius : ss->cache->radius;
+ const float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ const float displace = radius * (0.18f + offset);
+
+ /* The sculpt-plane normal (whatever its set to). */
+ float area_no_sp[3];
+
+ /* Geometry normal */
+ float area_no[3];
+ float area_co[3];
+
+ float temp[3];
+ float mat[4][4];
+ float scale[4][4];
+ float tmat[4][4];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
+ SCULPT_tilt_apply_to_normal(area_no_sp, ss->cache, brush->tilt_strength_factor);
+
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
+ }
+ else {
+ copy_v3_v3(area_no, area_no_sp);
+ }
+
+ /* Delay the first daub because grab delta is not setup. */
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ return;
+ }
+
+ if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
+ return;
+ }
+
+ mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ /* Clay Strips uses a cube test with falloff in the XY axis (not in Z) and a plane to deform the
+ * vertices. When in Add mode, vertices that are below the plane and inside the cube are move
+ * towards the plane. In this situation, there may be cases where a vertex is outside the cube
+ * but below the plane, so won't be deformed, causing artifacts. In order to prevent these
+ * artifacts, this displaces the test cube space in relation to the plane in order to
+ * deform more vertices that may be below it. */
+ /* The 0.7 and 1.25 factors are arbitrary and don't have any relation between them, they were set
+ * by doing multiple tests using the default "Clay Strips" brush preset. */
+ float area_co_displaced[3];
+ madd_v3_v3v3fl(area_co_displaced, area_co, area_no, -radius * 0.7f);
+
+ /* Initialize brush local-space matrix. */
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
+ mat[0][3] = 0.0f;
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
+ mat[1][3] = 0.0f;
+ copy_v3_v3(mat[2], area_no);
+ mat[2][3] = 0.0f;
+ copy_v3_v3(mat[3], area_co_displaced);
+ mat[3][3] = 1.0f;
+ normalize_m4(mat);
+
+ /* Scale brush local space matrix. */
+ scale_m4_fl(scale, ss->cache->radius);
+ mul_m4_m4m4(tmat, mat, scale);
+
+ /* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in
+ * Z this does not produce artifacts in the falloff cube and allows to deform extra vertices
+ * during big deformation while keeping the surface as uniform as possible. */
+ mul_v3_fl(tmat[2], 1.25f);
+
+ invert_m4_m4(mat, tmat);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no_sp = area_no_sp,
+ .area_co = area_co,
+ .mat = mat,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
+}
+
+static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ SculptProjectVector *spvc = data->spvc;
+ const float *grab_delta = data->grab_delta;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+ const bool do_rake_rotation = ss->cache->is_rake_rotation_valid;
+ const bool do_pinch = (brush->crease_pinch_factor != 0.5f);
+ const float pinch = do_pinch ? (2.0f * (0.5f - brush->crease_pinch_factor) *
+ (len_v3(grab_delta) / ss->cache->radius)) :
+ 0.0f;
+
+ const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ KelvinletParams params;
+ BKE_kelvinlet_init_params(&params, ss->cache->radius, bstrength, 1.0f, 0.4f);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ float fade;
+ if (do_elastic) {
+ fade = 1.0f;
+ }
+ else {
+ fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ }
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ /* Negative pinch will inflate, helps maintain volume. */
+ if (do_pinch) {
+ float delta_pinch_init[3], delta_pinch[3];
+
+ sub_v3_v3v3(delta_pinch, vd.co, test.location);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal);
+ }
+
+ /* Important to calculate based on the grabbed location
+ * (intentionally ignore fade here). */
+ add_v3_v3(delta_pinch, grab_delta);
+
+ sculpt_project_v3(spvc, delta_pinch, delta_pinch);
+
+ copy_v3_v3(delta_pinch_init, delta_pinch);
+
+ float pinch_fade = pinch * fade;
+ /* When reducing, scale reduction back by how close to the center we are,
+ * so we don't pinch into nothingness. */
+ if (pinch > 0.0f) {
+ /* Square to have even less impact for close vertices. */
+ pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius));
+ }
+ mul_v3_fl(delta_pinch, 1.0f + pinch_fade);
+ sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch);
+ add_v3_v3(proxy[vd.i], delta_pinch);
+ }
+
+ if (do_rake_rotation) {
+ float delta_rotate[3];
+ sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate);
+ add_v3_v3(proxy[vd.i], delta_rotate);
+ }
+
+ if (do_elastic) {
+ float disp[3];
+ BKE_kelvinlet_grab_triscale(disp, &params, vd.co, ss->cache->location, proxy[vd.i]);
+ mul_v3_fl(disp, bstrength * 20.0f);
+ if (vd.mask) {
+ mul_v3_fl(disp, 1.0f - *vd.mask);
+ }
+ mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
+ copy_v3_v3(proxy[vd.i], disp);
+ }
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ const float bstrength = ss->cache->bstrength;
+ float grab_delta[3];
+
+ SculptProjectVector spvc;
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ if (bstrength < 0.0f) {
+ negate_v3(grab_delta);
+ }
+
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
+
+ /* Optionally pinch while painting. */
+ if (brush->crease_pinch_factor != 0.5f) {
+ sculpt_project_v3_cache_init(&spvc, grab_delta);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .spvc = &spvc,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
+}
+
+static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *cono = data->cono;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+ float tmp[3], cono[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
+ cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .cono = cono,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
+}
+
+static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float angle = data->angle;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ float vec[3], rot[3][3];
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
+ axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
+ mul_v3_m3v3(proxy[vd.i], rot, vec);
+ add_v3_v3(proxy[vd.i], ss->cache->location);
+ sub_v3_v3(proxy[vd.i], orig_data.co);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ static const int flip[8] = {1, -1, -1, 1, -1, 1, 1, -1};
+ const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .angle = angle,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
+}
+
+static void do_layer_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+
+ const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ const float bstrength = ss->cache->bstrength;
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ const int vi = vd.index;
+ float *disp_factor;
+ if (use_persistent_base) {
+ disp_factor = &ss->persistent_base[vi].disp;
+ }
+ else {
+ disp_factor = &ss->cache->layer_displacement_factor[vi];
+ }
+
+ /* When using persistent base, the layer brush (holding Control) invert mode resets the
+ * height of the layer to 0. This makes possible to clean edges of previously added layers
+ * on top of the base. */
+ /* The main direction of the layers is inverted using the regular brush strength with the
+ * brush direction property. */
+ if (use_persistent_base && ss->cache->invert) {
+ (*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) *
+ ((*disp_factor) > 0.0f ? -1.0f : 1.0f);
+ }
+ else {
+ (*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor));
+ }
+ if (vd.mask) {
+ const float clamp_mask = 1.0f - *vd.mask;
+ *disp_factor = clamp_f(*disp_factor, -clamp_mask, clamp_mask);
+ }
+ else {
+ *disp_factor = clamp_f(*disp_factor, -1.0f, 1.0f);
+ }
+
+ float final_co[3];
+ float normal[3];
+
+ if (use_persistent_base) {
+ 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);
+ }
+ else {
+ copy_v3_v3(normal, orig_data.no);
+ mul_v3_fl(normal, brush->height);
+ madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor);
+ }
+
+ float vdisp[3];
+ sub_v3_v3v3(vdisp, final_co, vd.co);
+ mul_v3_fl(vdisp, fabsf(fade));
+ add_v3_v3v3(final_co, vd.co, vdisp);
+
+ SCULPT_clip(sd, ss, vd.co, final_co);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (ss->cache->layer_displacement_factor == NULL) {
+ ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
+ "layer displacement factor");
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
+}
+
+static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float val[3];
+
+ if (vd.fno) {
+ copy_v3_v3(val, vd.fno);
+ }
+ else {
+ copy_v3_v3(val, vd.no);
+ }
+
+ mul_v3_fl(val, fade * ss->cache->radius);
+ mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
+}
+
+static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *cono = data->cono;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+ float tmp[3], cono[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
+ cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .cono = cono,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Crease & Blob Brush
+ * \{ */
+
+/**
+ * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
+ */
+static void do_crease_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ SculptProjectVector *spvc = data->spvc;
+ const float flippedbstrength = data->flippedbstrength;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ /* Offset vertex. */
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float val1[3];
+ float val2[3];
+
+ /* First we pinch. */
+ sub_v3_v3v3(val1, test.location, vd.co);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(val1, val1, ss->cache->view_normal);
+ }
+
+ mul_v3_fl(val1, fade * flippedbstrength);
+
+ sculpt_project_v3(spvc, val1, val1);
+
+ /* Then we draw. */
+ mul_v3_v3fl(val2, offset, fade);
+
+ add_v3_v3v3(proxy[vd.i], val1, val2);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ const Scene *scene = ss->cache->vc->scene;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ float bstrength = ss->cache->bstrength;
+ float flippedbstrength, crease_correction;
+ float brush_alpha;
+
+ SculptProjectVector spvc;
+
+ /* Offset with as much as possible factored in already. */
+ mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* We divide out the squared alpha and multiply by the squared crease
+ * to give us the pinch strength. */
+ crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor;
+ brush_alpha = BKE_brush_alpha_get(scene, brush);
+ if (brush_alpha > 0.0f) {
+ crease_correction /= brush_alpha * brush_alpha;
+ }
+
+ /* We always want crease to pinch or blob to relax even when draw is negative. */
+ flippedbstrength = (bstrength < 0.0f) ? -crease_correction * bstrength :
+ crease_correction * bstrength;
+
+ if (brush->sculpt_tool == SCULPT_TOOL_BLOB) {
+ flippedbstrength *= -1.0f;
+ }
+
+ /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single
+ * point. Without this we get a 'flat' surface surrounding the pinch. */
+ sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .spvc = &spvc,
+ .offset = offset,
+ .flippedbstrength = flippedbstrength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
+}
+
+static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float(*stroke_xz)[3] = data->stroke_xz;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ float x_object_space[3];
+ float z_object_space[3];
+ copy_v3_v3(x_object_space, stroke_xz[0]);
+ copy_v3_v3(z_object_space, stroke_xz[1]);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float disp_center[3];
+ float x_disp[3];
+ float z_disp[3];
+ /* Calculate displacement from the vertex to the brush center. */
+ sub_v3_v3v3(disp_center, test.location, vd.co);
+
+ /* Project the displacement into the X vector (aligned to the stroke). */
+ mul_v3_v3fl(x_disp, x_object_space, dot_v3v3(disp_center, x_object_space));
+
+ /* Project the displacement into the Z vector (aligned to the surface normal). */
+ mul_v3_v3fl(z_disp, z_object_space, dot_v3v3(disp_center, z_object_space));
+
+ /* Add the two projected vectors to calculate the final displacement.
+ * The Y component is removed. */
+ add_v3_v3v3(disp_center, x_disp, z_disp);
+
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(disp_center, disp_center, ss->cache->view_normal);
+ }
+ mul_v3_v3fl(proxy[vd.i], disp_center, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ float area_no[3];
+ float area_co[3];
+
+ float mat[4][4];
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ /* delay the first daub because grab delta is not setup */
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ return;
+ }
+
+ if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
+ return;
+ }
+
+ /* Initialize `mat`. */
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
+ mat[0][3] = 0.0f;
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
+ mat[1][3] = 0.0f;
+ copy_v3_v3(mat[2], area_no);
+ mat[2][3] = 0.0f;
+ copy_v3_v3(mat[3], ss->cache->location);
+ mat[3][3] = 1.0f;
+ normalize_m4(mat);
+
+ float stroke_xz[2][3];
+ normalize_v3_v3(stroke_xz[0], mat[0]);
+ normalize_v3_v3(stroke_xz[1], mat[2]);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .stroke_xz = stroke_xz,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
+}
+
+static void do_grab_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *grab_delta = data->grab_delta;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE;
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ if (grab_silhouette) {
+ float silhouette_test_dir[3];
+ normalize_v3_v3(silhouette_test_dir, grab_delta);
+ if (dot_v3v3(ss->cache->initial_normal, ss->cache->grab_delta_symmetry) < 0.0f) {
+ mul_v3_fl(silhouette_test_dir, -1.0f);
+ }
+ float vno[3];
+ copy_v3_v3(vno, orig_data.no);
+ fade *= max_ff(dot_v3v3(vno, silhouette_test_dir), 0.0f);
+ }
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
+}
+
+static void do_elastic_deform_brush_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;
+ const float *grab_delta = data->grab_delta;
+ const float *location = ss->cache->location;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ float dir;
+ if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) {
+ dir = 1.0f;
+ }
+ else {
+ dir = -1.0f;
+ }
+
+ if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) {
+ int symm = ss->cache->mirror_symmetry_pass;
+ if (ELEM(symm, 1, 2, 4, 7)) {
+ dir = -dir;
+ }
+ }
+
+ KelvinletParams params;
+ float force = len_v3(grab_delta) * dir * bstrength;
+ BKE_kelvinlet_init_params(
+ &params, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ float final_disp[3];
+ switch (brush->elastic_deform_type) {
+ case BRUSH_ELASTIC_DEFORM_GRAB:
+ BKE_kelvinlet_grab(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
+ break;
+ case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: {
+ BKE_kelvinlet_grab_biscale(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
+ break;
+ }
+ case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: {
+ BKE_kelvinlet_grab_triscale(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
+ break;
+ }
+ case BRUSH_ELASTIC_DEFORM_SCALE:
+ BKE_kelvinlet_scale(
+ final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
+ break;
+ case BRUSH_ELASTIC_DEFORM_TWIST:
+ BKE_kelvinlet_twist(
+ final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
+ break;
+ }
+
+ if (vd.mask) {
+ mul_v3_fl(final_disp, 1.0f - *vd.mask);
+ }
+
+ mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
+
+ copy_v3_v3(proxy[vd.i], final_disp);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
+}
+/** \} */
+
+static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ /* Offset vertex. */
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ const float bstrength = ss->cache->bstrength;
+
+ /* Offset with as much as possible factored in already. */
+ float effective_normal[3];
+ SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
+ mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
+ * initialize before threads so they can do curve mapping. */
+ BKE_curvemapping_init(brush->curve);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .offset = offset,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Topology Brush
+ * \{ */
+
+static void do_topology_slide_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float current_disp[3];
+ float current_disp_norm[3];
+ float final_disp[3] = {0.0f, 0.0f, 0.0f};
+
+ switch (brush->slide_deform_type) {
+ case BRUSH_SLIDE_DEFORM_DRAG:
+ sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ break;
+ case BRUSH_SLIDE_DEFORM_PINCH:
+ sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
+ break;
+ case BRUSH_SLIDE_DEFORM_EXPAND:
+ sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
+ break;
+ }
+
+ normalize_v3_v3(current_disp_norm, current_disp);
+ mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float vertex_disp[3];
+ float vertex_disp_norm[3];
+ sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
+ normalize_v3_v3(vertex_disp_norm, vertex_disp);
+ if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) {
+ madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp));
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ mul_v3_v3fl(proxy[vd.i], final_disp, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_relax_vertex(SculptSession *ss,
+ PBVHVertexIter *vd,
+ float factor,
+ bool filter_boundary_face_sets,
+ float *r_final_pos)
+{
+ float smooth_pos[3];
+ float final_disp[3];
+ float boundary_normal[3];
+ int avg_count = 0;
+ int neighbor_count = 0;
+ zero_v3(smooth_pos);
+ zero_v3(boundary_normal);
+ const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index);
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
+ neighbor_count++;
+ if (!filter_boundary_face_sets ||
+ (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) {
+
+ /* When the vertex to relax is boundary, use only connected boundary vertices for the average
+ * position. */
+ if (is_boundary) {
+ if (!SCULPT_vertex_is_boundary(ss, ni.index)) {
+ continue;
+ }
+ add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
+ avg_count++;
+
+ /* Calculate a normal for the constraint plane using the edges of the boundary. */
+ float to_neighbor[3];
+ sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co);
+ normalize_v3(to_neighbor);
+ add_v3_v3(boundary_normal, to_neighbor);
+ }
+ else {
+ add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
+ avg_count++;
+ }
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ /* Don't modify corner vertices. */
+ if (neighbor_count <= 2) {
+ copy_v3_v3(r_final_pos, vd->co);
+ return;
+ }
+
+ if (avg_count > 0) {
+ mul_v3_fl(smooth_pos, 1.0f / avg_count);
+ }
+ else {
+ copy_v3_v3(r_final_pos, vd->co);
+ return;
+ }
+
+ float plane[4];
+ float smooth_closest_plane[3];
+ float vno[3];
+
+ if (is_boundary && avg_count == 2) {
+ normalize_v3_v3(vno, boundary_normal);
+ }
+ else {
+ SCULPT_vertex_normal_get(ss, vd->index, vno);
+ }
+
+ if (is_zero_v3(vno)) {
+ copy_v3_v3(r_final_pos, vd->co);
+ return;
+ }
+
+ plane_from_point_normal_v3(plane, vd->co, vno);
+ closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos);
+ sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co);
+
+ mul_v3_fl(final_disp, factor);
+ add_v3_v3v3(r_final_pos, vd->co, final_disp);
+}
+
+static void do_topology_relax_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ return;
+ }
+
+ BKE_curvemapping_init(brush->curve);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ if (ss->cache->alt_smooth) {
+ SCULPT_boundary_info_ensure(ob);
+ for (int i = 0; i < 4; i++) {
+ BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
+ }
+ }
+ else {
+ BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
+ }
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Multires Displacement Eraser Brush
+ * \{ */
+
+static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
+
+ float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ float limit_co[3];
+ float disp[3];
+ SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co);
+ sub_v3_v3v3(disp, limit_co, vd.co);
+ mul_v3_v3fl(proxy[vd.i], disp, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ BKE_curvemapping_init(brush->curve);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_displacement_eraser_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Multires Displacement Smear Brush
+ * \{ */
+
+static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ float current_disp[3];
+ float current_disp_norm[3];
+ float interp_limit_surface_disp[3];
+
+ copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]);
+
+ switch (brush->smear_deform_type) {
+ case BRUSH_SMEAR_DEFORM_DRAG:
+ sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ break;
+ case BRUSH_SMEAR_DEFORM_PINCH:
+ sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
+ break;
+ case BRUSH_SMEAR_DEFORM_EXPAND:
+ sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
+ break;
+ }
+
+ normalize_v3_v3(current_disp_norm, current_disp);
+ mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
+
+ float weights_accum = 1.0f;
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float vertex_disp[3];
+ float vertex_disp_norm[3];
+ float neighbor_limit_co[3];
+ SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co);
+ sub_v3_v3v3(vertex_disp,
+ ss->cache->limit_surface_co[ni.index],
+ ss->cache->limit_surface_co[vd.index]);
+ const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index];
+ normalize_v3_v3(vertex_disp_norm, vertex_disp);
+
+ if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) {
+ continue;
+ }
+
+ const float disp_interp = clamp_f(
+ -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f);
+ madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp);
+ weights_accum += disp_interp;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum);
+
+ float new_co[3];
+ add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp);
+ interp_v3_v3v3(vd.co, vd.co, new_co, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_displacement_smear_store_prev_disp_task_cb_ex(
+ void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ sub_v3_v3v3(ss->cache->prev_displacement[vd.index],
+ SCULPT_vertex_co_get(ss, vd.index),
+ ss->cache->limit_surface_co[vd.index]);
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+
+ BKE_curvemapping_init(brush->curve);
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ if (!ss->cache->prev_displacement) {
+ ss->cache->prev_displacement = MEM_malloc_arrayN(
+ totvert, sizeof(float[3]), "prev displacement");
+ ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co");
+ for (int i = 0; i < totvert; i++) {
+ SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]);
+ sub_v3_v3v3(ss->cache->prev_displacement[i],
+ SCULPT_vertex_co_get(ss, i),
+ ss->cache->limit_surface_co[i]);
+ }
+ }
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(
+ 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Topology Rake (Shared Utility)
+ * \{ */
+
+static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+
+ float direction[3];
+ copy_v3_v3(direction, ss->cache->grab_delta_symmetry);
+
+ float tmp[3];
+ mul_v3_v3fl(
+ tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
+ sub_v3_v3(direction, tmp);
+ normalize_v3(direction);
+
+ /* Cancel if there's no grab data. */
+ if (is_zero_v3(direction)) {
+ return;
+ }
+
+ const float bstrength = clamp_f(data->strength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade =
+ bstrength *
+ SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) *
+ ss->cache->pressure;
+
+ float avg[3], val[3];
+
+ SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
+
+ sub_v3_v3v3(val, avg, vd.co);
+
+ madd_v3_v3v3fl(val, vd.co, val, fade);
+
+ SCULPT_clip(sd, ss, vd.co, val);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_bmesh_topology_rake(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ const float strength = clamp_f(bstrength, 0.0f, 1.0f);
+
+ /* Interactions increase both strength and quality. */
+ const int iterations = 3;
+
+ int iteration;
+ const int count = iterations * strength + 1;
+ const float factor = iterations * strength / count;
+
+ for (iteration = 0; iteration <= count; iteration++) {
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .strength = factor,
+ };
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+
+ BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Mask Brush
+ * \{ */
+
+static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
+
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ const float fade = SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
+
+ if (bstrength > 0.0f) {
+ (*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
+ }
+ else {
+ (*vd.mask) += fade * bstrength * (*vd.mask);
+ }
+ *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+}
+
+void SCULPT_do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
+}
+
+void SCULPT_do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ switch ((BrushMaskTool)brush->mask_tool) {
+ case BRUSH_MASK_DRAW:
+ SCULPT_do_mask_brush_draw(sd, ob, nodes, totnode);
+ break;
+ case BRUSH_MASK_SMOOTH:
+ SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true);
+ break;
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index a53a2126af4..3ac57d73d37 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -560,13 +560,6 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
thread_id);
float brush_disp[3];
- float normal[3];
- if (vd.no) {
- normal_short_to_float_v3(normal, vd.no);
- }
- else {
- copy_v3_v3(normal, vd.fno);
- }
switch (brush->cloth_deform_type) {
case BRUSH_CLOTH_DEFORM_DRAG:
@@ -621,7 +614,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(force, disp_center, fade);
} break;
case BRUSH_CLOTH_DEFORM_INFLATE:
- mul_v3_v3fl(force, normal, fade);
+ mul_v3_v3fl(force, vd.no ? vd.no : vd.fno, fade);
break;
case BRUSH_CLOTH_DEFORM_EXPAND:
cloth_sim->length_constraint_tweak[vd.index] += fade * 0.1f;
@@ -1052,7 +1045,6 @@ static void cloth_sim_initialize_default_node_state(SculptSession *ss,
MEM_SAFE_FREE(nodes);
}
-/* Public functions. */
SculptClothSimulation *SCULPT_cloth_brush_simulation_create(SculptSession *ss,
const float cloth_mass,
const float cloth_damping,
@@ -1195,7 +1187,6 @@ static void sculpt_cloth_ensure_constraints_in_simulation_area(Sculpt *sd,
sd, ob, nodes, totnode, ss->cache->cloth_sim, sim_location, limit);
}
-/* Main Brush Function. */
void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
@@ -1271,7 +1262,6 @@ void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim)
MEM_SAFE_FREE(cloth_sim);
}
-/* Cursor drawing function. */
void SCULPT_cloth_simulation_limits_draw(const uint gpuattr,
const Brush *brush,
const float location[3],
@@ -1528,7 +1518,7 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_RUNNING_MODAL;
}
- const float len = event->prevclickx - event->x;
+ const float len = event->prev_click_xy[0] - event->xy[0];
filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC;
SCULPT_vertex_random_access_ensure(ss);
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
index 188bb0a88eb..f00b24d690a 100644
--- a/source/blender/editors/sculpt_paint/sculpt_detail.c
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -57,6 +57,10 @@
#include <math.h>
#include <stdlib.h>
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
typedef struct {
const float *ray_start;
bool hit;
@@ -82,6 +86,12 @@ static bool sculpt_and_dynamic_topology_poll(bContext *C)
return SCULPT_mode_poll(C) && ob->sculpt->bm;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Detail Flood Fill
+ * \{ */
+
static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -147,6 +157,12 @@ void SCULPT_OT_detail_flood_fill(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample Detail Size
+ * \{ */
+
typedef enum eSculptSampleDetailModeTypes {
SAMPLE_DETAIL_DYNTOPO = 0,
SAMPLE_DETAIL_VOXEL = 1,
@@ -232,8 +248,10 @@ static int sample_detail(bContext *C, int mx, int my, int mode)
{
/* Find 3D view to pick from. */
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my);
- ARegion *region = (area) ? BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my) : NULL;
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, (const int[2]){mx, my});
+ ARegion *region = (area) ?
+ BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}) :
+ NULL;
if (region == NULL) {
return OPERATOR_CANCELLED;
}
@@ -306,7 +324,7 @@ static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wm
switch (event->type) {
case LEFTMOUSE:
if (event->val == KM_PRESS) {
- const int ss_co[2] = {event->x, event->y};
+ const int ss_co[2] = {event->xy[0], event->xy[1]};
int mode = RNA_enum_get(op->ptr, "mode");
sample_detail(C, ss_co[0], ss_co[1], mode);
@@ -364,13 +382,17 @@ void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
"Target sculpting workflow that is going to use the sampled size");
}
-/* Dynamic-topology detail size.
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dynamic-topology detail size
*
* Currently, there are two operators editing the detail size:
- * - SCULPT_OT_set_detail_size uses radial control for all methods
- * - SCULPT_OT_dyntopo_detail_size_edit shows a triangle grid representation of the detail
- * resolution (for constant detail method, falls back to radial control for the remaining methods).
- */
+ * - #SCULPT_OT_set_detail_size uses radial control for all methods
+ * - #SCULPT_OT_dyntopo_detail_size_edit shows a triangle grid representation of the detail
+ * resolution (for constant detail method,
+ * falls back to radial control for the remaining methods).
+ * \{ */
static void set_brush_rc_props(PointerRNA *ptr, const char *prop)
{
@@ -429,6 +451,8 @@ void SCULPT_OT_set_detail_size(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Dyntopo Detail Size Edit Operator
* \{ */
@@ -759,3 +783,5 @@ void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c
index 40874375772..2ba03969f38 100644
--- a/source/blender/editors/sculpt_paint/sculpt_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_expand.c
@@ -465,7 +465,7 @@ static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, cons
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
- float *dists = MEM_calloc_arrayN(sizeof(float), totvert, "topology dist");
+ float *dists = MEM_calloc_arrayN(totvert, sizeof(float), "topology dist");
SculptFloodFill flood;
SCULPT_floodfill_init(ss, &flood);
@@ -515,7 +515,7 @@ static float *sculpt_expand_normal_falloff_create(Sculpt *sd,
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
- float *dists = MEM_malloc_arrayN(sizeof(float), totvert, "normal dist");
+ float *dists = MEM_malloc_arrayN(totvert, sizeof(float), "normal dist");
float *edge_factor = MEM_callocN(sizeof(float) * totvert, "mask edge factor");
for (int i = 0; i < totvert; i++) {
edge_factor[i] = 1.0f;
@@ -560,7 +560,7 @@ static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v)
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
- float *dists = MEM_malloc_arrayN(sizeof(float), totvert, "spherical dist");
+ float *dists = MEM_malloc_arrayN(totvert, sizeof(float), "spherical dist");
for (int i = 0; i < totvert; i++) {
dists[i] = FLT_MAX;
}
@@ -591,7 +591,7 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
- float *dists = MEM_calloc_arrayN(sizeof(float), totvert, "spherical dist");
+ float *dists = MEM_calloc_arrayN(totvert, sizeof(float), "spherical dist");
BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(totvert, "visited vertices");
GSQueue *queue = BLI_gsqueue_new(sizeof(int));
@@ -652,7 +652,7 @@ static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
- float *dists = MEM_calloc_arrayN(sizeof(float), totvert, "spherical dist");
+ float *dists = MEM_calloc_arrayN(totvert, sizeof(float), "spherical dist");
/* This algorithm uses mesh data (polys and loops), so this falloff type can't be initialized for
* Multires. It also does not make sense to implement it for dyntopo as the result will be the
@@ -863,7 +863,7 @@ static void sculpt_expand_topology_from_state_boundary(Object *ob,
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
- float *dists = MEM_calloc_arrayN(sizeof(float), totvert, "topology dist");
+ float *dists = MEM_calloc_arrayN(totvert, sizeof(float), "topology dist");
BLI_bitmap *boundary_vertices = sculpt_expand_boundary_from_enabled(ss, enabled_vertices, false);
SculptFloodFill flood;
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index bdbdb75732a..dc8cda964ea 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -73,6 +73,7 @@
#include <stdlib.h>
/* Utils. */
+
int ED_sculpt_face_sets_find_next_available_id(struct Mesh *mesh)
{
int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
@@ -1233,7 +1234,7 @@ static void sculpt_face_set_edit_fair_face_set(Object *ob,
const int totvert = SCULPT_vertex_count_get(ss);
Mesh *mesh = ob->data;
- bool *fair_vertices = MEM_malloc_arrayN(sizeof(bool), totvert, "fair vertices");
+ bool *fair_vertices = MEM_malloc_arrayN(totvert, sizeof(bool), "fair vertices");
SCULPT_boundary_info_ensure(ob);
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index 4b49bf2cefb..a0062a98194 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -231,7 +231,7 @@ static int sculpt_color_filter_modal(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_RUNNING_MODAL;
}
- const float len = event->prevclickx - event->x;
+ const float len = event->prev_click_xy[0] - event->xy[0];
filter_strength = filter_strength * -len * 0.001f;
float fill_color[3];
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
index 10f141e2311..cf45e25142b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
@@ -334,14 +334,7 @@ static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd)
if (total > 0) {
mul_v3_fl(avg, 1.0f / total);
- float normal[3];
- if (vd->no) {
- normal_short_to_float_v3(normal, vd->no);
- }
- else {
- copy_v3_v3(normal, vd->fno);
- }
- float dot = dot_v3v3(avg, normal);
+ float dot = dot_v3v3(avg, vd->no ? vd->no : vd->fno);
float angle = max_ff(saacosf(dot), 0.0f);
return angle;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index 3fc1a7674f7..2d8bdc4e4ac 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -64,7 +64,6 @@
#include <math.h>
#include <stdlib.h>
-/* Filter orientation utils. */
void SCULPT_filter_to_orientation_space(float r_v[3], struct FilterCache *filter_cache)
{
switch (filter_cache->orientation) {
@@ -304,7 +303,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
- float orig_co[3], val[3], avg[3], normal[3], disp[3], disp2[3], transform[3][3], final_pos[3];
+ float orig_co[3], val[3], avg[3], disp[3], disp2[3], transform[3][3], final_pos[3];
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
@@ -340,8 +339,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
sub_v3_v3v3(disp, val, orig_co);
break;
case MESH_FILTER_INFLATE:
- normal_short_to_float_v3(normal, orig_data.no);
- mul_v3_v3fl(disp, normal, fade);
+ mul_v3_v3fl(disp, orig_data.no, fade);
break;
case MESH_FILTER_SCALE:
unit_m3(transform);
@@ -373,7 +371,8 @@ static void mesh_filter_task_cb(void *__restrict userdata,
mid_v3_v3v3(disp, disp, disp2);
break;
case MESH_FILTER_RANDOM: {
- normal_short_to_float_v3(normal, orig_data.no);
+ float normal[3];
+ copy_v3_v3(normal, orig_data.no);
/* Index is not unique for multires, so hash by vertex coordinates. */
const uint *hash_co = (const uint *)orig_co;
const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^
@@ -433,7 +432,6 @@ static void mesh_filter_task_cb(void *__restrict userdata,
/* Intensify details. */
if (ss->filter_cache->sharpen_intensify_detail_strength > 0.0f) {
float detail_strength[3];
- normal_short_to_float_v3(detail_strength, orig_data.no);
copy_v3_v3(detail_strength, ss->filter_cache->detail_directions[vd.index]);
madd_v3_v3fl(disp,
detail_strength,
@@ -511,7 +509,7 @@ static void mesh_filter_init_limit_surface_co(SculptSession *ss)
FilterCache *filter_cache = ss->filter_cache;
filter_cache->limit_surface_co = MEM_malloc_arrayN(
- sizeof(float[3]), totvert, "limit surface co");
+ totvert, sizeof(float[3]), "limit surface co");
for (int i = 0; i < totvert; i++) {
SCULPT_vertex_limit_surface_get(ss, i, filter_cache->limit_surface_co[i]);
}
@@ -528,7 +526,7 @@ static void mesh_filter_sharpen_init(SculptSession *ss,
filter_cache->sharpen_smooth_ratio = smooth_ratio;
filter_cache->sharpen_intensify_detail_strength = intensify_detail_strength;
filter_cache->sharpen_curvature_smooth_iterations = curvature_smooth_iterations;
- filter_cache->sharpen_factor = MEM_malloc_arrayN(sizeof(float), totvert, "sharpen factor");
+ filter_cache->sharpen_factor = MEM_malloc_arrayN(totvert, sizeof(float), "sharpen factor");
filter_cache->detail_directions = MEM_malloc_arrayN(
totvert, sizeof(float[3]), "sharpen detail direction");
@@ -624,7 +622,7 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *
return OPERATOR_RUNNING_MODAL;
}
- const float len = event->prevclickx - event->x;
+ const float len = event->prev_click_xy[0] - event->xy[0];
filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC;
SCULPT_vertex_random_access_ensure(ss);
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 696c3332a2b..8de9fa3763b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -29,13 +29,13 @@
#include "DNA_meshdata_types.h"
#include "DNA_vec_types.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
#include "BLI_bitmap.h"
+#include "BLI_compiler_compat.h"
#include "BLI_gsqueue.h"
#include "BLI_threads.h"
-#include "BKE_paint.h"
-#include "BKE_pbvh.h"
-
struct AutomaskingCache;
struct KeyBlock;
struct Object;
@@ -44,16 +44,12 @@ struct bContext;
enum ePaintSymmetryFlags;
-bool SCULPT_mode_poll(struct bContext *C);
-bool SCULPT_mode_poll_view3d(struct bContext *C);
-/* checks for a brush, not just sculpt mode */
-bool SCULPT_poll(struct bContext *C);
-bool SCULPT_poll_view3d(struct bContext *C);
-
-bool SCULPT_vertex_colors_poll(struct bContext *C);
-
/* Updates */
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Types
+ * \{ */
+
typedef enum SculptUpdateType {
SCULPT_UPDATE_COORDS = 1 << 0,
SCULPT_UPDATE_MASK = 1 << 1,
@@ -61,65 +57,14 @@ typedef enum SculptUpdateType {
SCULPT_UPDATE_COLOR = 1 << 3,
} SculptUpdateType;
-void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags);
-void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags);
-void SCULPT_flush_stroke_deform(struct Sculpt *sd, Object *ob, bool is_proxy_used);
-
-/* Should be used after modifying the mask or Face Sets IDs. */
-void SCULPT_tag_update_overlays(bContext *C);
-
-/* Stroke */
-
typedef struct SculptCursorGeometryInfo {
float location[3];
float normal[3];
float active_vertex_co[3];
} SculptCursorGeometryInfo;
-bool SCULPT_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]);
-bool SCULPT_cursor_geometry_info_update(bContext *C,
- SculptCursorGeometryInfo *out,
- const float mouse[2],
- bool use_sampled_normal);
-void SCULPT_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius);
-
-void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush);
-float SCULPT_raycast_init(struct ViewContext *vc,
- const float mouse[2],
- float ray_start[3],
- float ray_end[3],
- float ray_normal[3],
- bool original);
-
-/* Symmetry */
-char SCULPT_mesh_symmetry_xyz_get(Object *object);
-
-/* Sculpt PBVH abstraction API */
-void SCULPT_vertex_random_access_ensure(struct SculptSession *ss);
-
-int SCULPT_vertex_count_get(struct SculptSession *ss);
-const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index);
-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]);
-
-/* Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled. */
-const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index);
-
-/* Returns the info of the limit surface when Multires is available, otherwise it returns the
- * current coordinate of the vertex. */
-void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]);
-
-/* Returns the pointer to the coordinates that should be edited from a brush tool iterator
- * depending on the given deformation target. */
-float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss,
- const int deform_target,
- PBVHVertexIter *iter);
-
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
+
typedef struct SculptVertexNeighborIter {
/* Storage */
int *neighbors;
@@ -136,456 +81,33 @@ typedef struct SculptVertexNeighborIter {
bool is_duplicate;
} SculptVertexNeighborIter;
-void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
- const int index,
- const bool include_duplicates,
- SculptVertexNeighborIter *iter);
-
-/* Iterator over neighboring vertices. */
-#define SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
- SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
- for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
- neighbor_iterator.i++) { \
- neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i];
-
-/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
- * first since they are nearest for floodfill. */
-#define SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
- SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
- for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
- neighbor_iterator.i--) { \
- neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \
- neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
- neighbor_iterator.size - neighbor_iterator.num_duplicates);
-
-#define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \
- } \
- if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
- MEM_freeN(neighbor_iterator.neighbors); \
- } \
- ((void)0)
-
-int SCULPT_active_vertex_get(SculptSession *ss);
-const float *SCULPT_active_vertex_co_get(SculptSession *ss);
-void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]);
-
-/* Returns PBVH deformed vertices array if shape keys or deform modifiers are used, otherwise
- * returns mesh original vertices array. */
-struct MVert *SCULPT_mesh_deformed_mverts_get(SculptSession *ss);
-
-/* Fake Neighbors */
-
-#define FAKE_NEIGHBOR_NONE -1
-
-void SCULPT_fake_neighbors_ensure(struct Sculpt *sd, Object *ob, const float max_dist);
-void SCULPT_fake_neighbors_enable(Object *ob);
-void SCULPT_fake_neighbors_disable(Object *ob);
-void SCULPT_fake_neighbors_free(struct Object *ob);
-
-/* Vertex Info. */
-void SCULPT_boundary_info_ensure(Object *object);
-/* Boundary Info needs to be initialized in order to use this function. */
-bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index);
-
-void SCULPT_connected_components_ensure(Object *ob);
-
-/* Sculpt Visibility API */
-
-void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible);
-bool SCULPT_vertex_visible_get(SculptSession *ss, int index);
-
-void SCULPT_visibility_sync_all_face_sets_to_vertices(struct Object *ob);
-void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
-
-/* Face Sets API */
-
-int SCULPT_active_face_set_get(SculptSession *ss);
-int SCULPT_vertex_face_set_get(SculptSession *ss, int index);
-void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set);
-
-bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set);
-bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index);
-
-int SCULPT_face_set_next_available_get(SculptSession *ss);
-
-void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible);
-bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index);
-bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index);
-
-void SCULPT_face_sets_visibility_invert(SculptSession *ss);
-void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
-
-bool SCULPT_stroke_is_main_symmetry_pass(struct StrokeCache *cache);
-bool SCULPT_stroke_is_first_brush_step(struct StrokeCache *cache);
-bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(struct StrokeCache *cache);
-
/* Sculpt Original Data */
typedef struct {
struct BMLog *bm_log;
struct SculptUndoNode *unode;
float (*coords)[3];
- short (*normals)[3];
+ float (*normals)[3];
const float *vmasks;
float (*colors)[4];
/* Original coordinate, normal, and mask. */
const float *co;
- const short *no;
+ const float *no;
float mask;
const float *col;
} SculptOrigVertData;
-void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node);
-void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter);
-void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data,
- Object *ob,
- struct SculptUndoNode *unode);
-
-/* Utils. */
-void SCULPT_calc_brush_plane(struct Sculpt *sd,
- struct Object *ob,
- struct PBVHNode **nodes,
- int totnode,
- float r_area_no[3],
- float r_area_co[3]);
-
-void SCULPT_calc_area_normal(
- Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]);
-
-int SCULPT_nearest_vertex_get(struct Sculpt *sd,
- struct Object *ob,
- const float co[3],
- float max_distance,
- bool use_original);
-
-int SCULPT_plane_point_side(const float co[3], const float plane[4]);
-int SCULPT_plane_trim(const struct StrokeCache *cache,
- const struct Brush *brush,
- const float val[3]);
-void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3]);
-
-float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss);
-
-ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]);
-bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm);
-bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3],
- const float br_co[3],
- float radius,
- char symm);
-bool SCULPT_is_symmetry_iteration_valid(char i, char symm);
-void SCULPT_flip_v3_by_symm_area(float v[3],
- const ePaintSymmetryFlags symm,
- const ePaintSymmetryAreas symmarea,
- const float pivot[3]);
-void SCULPT_flip_quat_by_symm_area(float quat[4],
- const ePaintSymmetryFlags symm,
- const ePaintSymmetryAreas symmarea,
- const float pivot[3]);
-
/* Flood Fill. */
typedef struct {
GSQueue *queue;
BLI_bitmap *visited_vertices;
} SculptFloodFill;
-void SCULPT_floodfill_init(struct SculptSession *ss, SculptFloodFill *flood);
-void SCULPT_floodfill_add_active(struct Sculpt *sd,
- struct Object *ob,
- struct SculptSession *ss,
- SculptFloodFill *flood,
- float radius);
-void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd,
- struct Object *ob,
- struct SculptSession *ss,
- SculptFloodFill *flood,
- int index,
- float radius);
-void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index);
-void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index);
-void SCULPT_floodfill_execute(
- struct SculptSession *ss,
- SculptFloodFill *flood,
- bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
- void *userdata);
-void SCULPT_floodfill_free(SculptFloodFill *flood);
-
-/* Dynamic topology */
-
-enum eDynTopoWarnFlag {
- DYNTOPO_WARN_VDATA = (1 << 0),
- DYNTOPO_WARN_EDATA = (1 << 1),
- DYNTOPO_WARN_LDATA = (1 << 2),
- DYNTOPO_WARN_MODIFIER = (1 << 3),
-};
-
-void SCULPT_dynamic_topology_enable_ex(struct Main *bmain,
- struct Depsgraph *depsgraph,
- Scene *scene,
- Object *ob);
-void SCULPT_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode);
-void sculpt_dynamic_topology_disable_with_undo(struct Main *bmain,
- struct Depsgraph *depsgraph,
- Scene *scene,
- Object *ob);
-
-bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush);
-
-void SCULPT_dynamic_topology_triangulate(struct BMesh *bm);
-void SCULPT_dyntopo_node_layers_add(struct SculptSession *ss);
-
-enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob);
-
-void SCULPT_pbvh_clear(Object *ob);
-
-/* Auto-masking. */
-float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking,
- SculptSession *ss,
- int vert);
-
-/* Returns the automasking cache depending on the active tool. Used for code that can run both for
- * brushes and filter. */
-struct AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss);
-
-struct AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob);
-void SCULPT_automasking_cache_free(struct AutomaskingCache *automasking);
-
-bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd,
- const Brush *br,
- const eAutomasking_flag mode);
-bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br);
-
typedef enum eBoundaryAutomaskMode {
AUTOMASK_INIT_BOUNDARY_EDGES = 1,
AUTOMASK_INIT_BOUNDARY_FACE_SETS = 2,
} eBoundaryAutomaskMode;
-float *SCULPT_boundary_automasking_init(Object *ob,
- eBoundaryAutomaskMode mode,
- int propagation_steps,
- float *automask_factor);
-
-/* Geodesic distances. */
-
-/* Returns an array indexed by vertex index containing the geodesic distance to the closest vertex
-in the initial vertex set. The caller is responsible for freeing the array.
-Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will
-fallback to euclidean distances to one of the initial vertices in the set. */
-float *SCULPT_geodesic_distances_create(struct Object *ob,
- struct GSet *initial_vertices,
- const float limit_radius);
-float *SCULPT_geodesic_from_vertex_and_symm(struct Sculpt *sd,
- struct Object *ob,
- const int vertex,
- const float limit_radius);
-float *SCULPT_geodesic_from_vertex(Object *ob, const int vertex, const float limit_radius);
-
-/* Filters. */
-void SCULPT_filter_cache_init(struct bContext *C, Object *ob, Sculpt *sd, const int undo_type);
-void SCULPT_filter_cache_free(SculptSession *ss);
-
-void SCULPT_mask_filter_smooth_apply(
- Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, const int smooth_iterations);
-
-/* Brushes. */
-
-/* Cloth Brush. */
-void SCULPT_do_cloth_brush(struct Sculpt *sd,
- struct Object *ob,
- struct PBVHNode **nodes,
- int totnode);
-
-void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim);
-
-struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create(
- struct SculptSession *ss,
- const float cloth_mass,
- const float cloth_damping,
- const float cloth_softbody_strength,
- const bool use_collisions,
- const bool needs_deform_coords);
-void SCULPT_cloth_brush_simulation_init(struct SculptSession *ss,
- struct SculptClothSimulation *cloth_sim);
-
-void SCULPT_cloth_sim_activate_nodes(struct SculptClothSimulation *cloth_sim,
- PBVHNode **nodes,
- int totnode);
-
-void SCULPT_cloth_brush_store_simulation_state(struct SculptSession *ss,
- struct SculptClothSimulation *cloth_sim);
-
-void SCULPT_cloth_brush_do_simulation_step(struct Sculpt *sd,
- struct Object *ob,
- struct SculptClothSimulation *cloth_sim,
- struct PBVHNode **nodes,
- int totnode);
-
-void SCULPT_cloth_brush_ensure_nodes_constraints(struct Sculpt *sd,
- struct Object *ob,
- struct PBVHNode **nodes,
- int totnode,
- struct SculptClothSimulation *cloth_sim,
- float initial_location[3],
- const float radius);
-
-void SCULPT_cloth_simulation_limits_draw(const uint gpuattr,
- const struct Brush *brush,
- const float location[3],
- const float normal[3],
- const float rds,
- const float line_width,
- const float outline_col[3],
- const float alpha);
-void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr,
- struct SculptSession *ss,
- const float outline_col[3],
- float outline_alpha);
-
-PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss,
- Brush *brush,
- int *r_totnode);
-
-BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush)
-{
- return (brush->sculpt_tool == SCULPT_TOOL_CLOTH && ELEM(brush->cloth_deform_type,
- BRUSH_CLOTH_DEFORM_GRAB,
- BRUSH_CLOTH_DEFORM_SNAKE_HOOK)) ||
- /* All brushes that are not the cloth brush deform the simulation using softbody
- * constraints instead of applying forces. */
- (brush->sculpt_tool != SCULPT_TOOL_CLOTH &&
- brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM);
-}
-
-BLI_INLINE bool SCULPT_tool_needs_all_pbvh_nodes(const Brush *brush)
-{
- if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) {
- /* Elastic deformations in any brush need all nodes to avoid artifacts as the effect
- * of the Kelvinlet is not constrained by the radius. */
- return true;
- }
-
- if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
- /* Pose needs all nodes because it applies all symmetry iterations at the same time
- * and the IK chain can grow to any area of the model. */
- /* TODO: This can be optimized by filtering the nodes after calculating the chain. */
- return true;
- }
-
- if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) {
- /* Boundary needs all nodes because it is not possible to know where the boundary
- * deformation is going to be propagated before calculating it. */
- /* TODO: after calculating the boundary info in the first iteration, it should be
- * possible to get the nodes that have vertices included in any boundary deformation
- * and cache them. */
- return true;
- }
-
- if (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK &&
- brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC) {
- /* Snake hook in elastic deform type has same requirements as the elastic deform tool. */
- return true;
- }
- return false;
-}
-
-/* Pose Brush. */
-void SCULPT_do_pose_brush(struct Sculpt *sd,
- struct Object *ob,
- struct PBVHNode **nodes,
- int totnode);
-void SCULPT_pose_calc_pose_data(struct Sculpt *sd,
- struct Object *ob,
- struct SculptSession *ss,
- float initial_location[3],
- float radius,
- float pose_offset,
- float *r_pose_origin,
- float *r_pose_factor);
-void SCULPT_pose_brush_init(struct Sculpt *sd,
- struct Object *ob,
- struct SculptSession *ss,
- struct Brush *br);
-struct SculptPoseIKChain *SCULPT_pose_ik_chain_init(struct Sculpt *sd,
- struct Object *ob,
- struct SculptSession *ss,
- struct Brush *br,
- const float initial_location[3],
- const float radius);
-void SCULPT_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain);
-
-/* Boundary Brush. */
-struct SculptBoundary *SCULPT_boundary_data_init(Object *object,
- Brush *brush,
- const int initial_vertex,
- const float radius);
-void SCULPT_boundary_data_free(struct SculptBoundary *boundary);
-void SCULPT_do_boundary_brush(struct Sculpt *sd,
- struct Object *ob,
- struct PBVHNode **nodes,
- int totnode);
-
-void SCULPT_boundary_edges_preview_draw(const uint gpuattr,
- struct SculptSession *ss,
- const float outline_col[3],
- const float outline_alpha);
-void SCULPT_boundary_pivot_line_preview_draw(const uint gpuattr, struct SculptSession *ss);
-
-/* Multi-plane Scrape Brush. */
-void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr,
- Brush *brush,
- SculptSession *ss,
- const float outline_col[3],
- const float outline_alpha);
-/* Draw Face Sets Brush. */
-void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-
-/* Paint Brush. */
-void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-
-/* Smear Brush. */
-void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-
-/* Smooth Brush. */
-void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v);
-
-void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index);
-float SCULPT_neighbor_mask_average(SculptSession *ss, int index);
-void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index);
-
-/* Mask the mesh boundaries smoothing only the mesh surface without using automasking. */
-void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index);
-
-void SCULPT_smooth(Sculpt *sd,
- Object *ob,
- PBVHNode **nodes,
- const int totnode,
- float bstrength,
- const bool smooth_mask);
-void SCULPT_do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-
-/* Surface Smooth Brush. */
-
-void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
- float *disp,
- const float co[3],
- float (*laplacian_disp)[3],
- const int v_index,
- const float origco[3],
- const float alpha);
-void SCULPT_surface_smooth_displace_step(SculptSession *ss,
- float *co,
- float (*laplacian_disp)[3],
- const int v_index,
- const float beta,
- const float fade);
-void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-
-/* Slide/Relax */
-void SCULPT_relax_vertex(struct SculptSession *ss,
- struct PBVHVertexIter *vd,
- float factor,
- bool filter_boundary_face_sets,
- float *r_final_pos);
/* Undo */
@@ -628,7 +150,7 @@ typedef struct SculptUndoNode {
float (*co)[3];
float (*orig_co)[3];
- short (*no)[3];
+ float (*no)[3];
float (*col)[4];
float *mask;
int totvert;
@@ -684,7 +206,13 @@ struct SculptRakeData {
float follow_co[3];
};
-/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */
+/*
+Generic thread data. The size of this struct
+has gotten a little out of hand; normally we would
+split it up, but it might be better to see if we can't
+eliminate it altogether after moving to C++ (where
+we'll be able to use lambdas).
+*/
typedef struct SculptThreadedTaskData {
struct bContext *C;
struct Sculpt *sd;
@@ -841,55 +369,12 @@ typedef struct {
struct DistRayAABB_Precalc *dist_ray_to_aabb_precalc;
} SculptSearchCircleData;
-void SCULPT_brush_test_init(struct SculptSession *ss, SculptBrushTest *test);
-bool SCULPT_brush_test_sphere(SculptBrushTest *test, const float co[3]);
-bool SCULPT_brush_test_sphere_sq(SculptBrushTest *test, const float co[3]);
-bool SCULPT_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3]);
-bool SCULPT_brush_test_cube(SculptBrushTest *test,
- const float co[3],
- const float local[4][4],
- const float roundness);
-bool SCULPT_brush_test_circle_sq(SculptBrushTest *test, const float co[3]);
-bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v);
-bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v);
-
-SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss,
- SculptBrushTest *test,
- char falloff_shape);
-const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
- char falloff_shape);
-
-float SCULPT_brush_strength_factor(struct SculptSession *ss,
- const struct Brush *br,
- const float point[3],
- const float len,
- const short vno[3],
- const float fno[3],
- const float mask,
- const int vertex_index,
- const int thread_id);
-
-/* Tilts a normal by the x and y tilt values using the view axis. */
-void SCULPT_tilt_apply_to_normal(float r_normal[3],
- struct StrokeCache *cache,
- const float tilt_strength);
-
-/* Get effective surface normal with pen tilt and tilt strength applied to it. */
-void SCULPT_tilt_effective_normal_get(const SculptSession *ss, const Brush *brush, float r_no[3]);
-
-/* just for vertex paint. */
-bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush,
- Object *ob,
- PBVHNode **nodes,
- int totnode,
- bool use_threading,
- float r_area_no[3]);
-
-/* Cache stroke properties. Used because
- * RNA property lookup isn't particularly fast.
- *
- * For descriptions of these settings, check the operator properties.
- */
+/* Sculpt Filters */
+typedef enum SculptFilterOrientation {
+ SCULPT_FILTER_ORIENTATION_LOCAL = 0,
+ SCULPT_FILTER_ORIENTATION_WORLD = 1,
+ SCULPT_FILTER_ORIENTATION_VIEW = 2,
+} SculptFilterOrientation;
#define SCULPT_CLAY_STABILIZER_LEN 10
@@ -906,12 +391,74 @@ typedef struct AutomaskingCache {
float *factor;
} AutomaskingCache;
+typedef struct FilterCache {
+ bool enabled_axis[3];
+ bool enabled_force_axis[3];
+ int random_seed;
+
+ /* Used for alternating between filter operations in filters that need to apply different ones to
+ * achieve certain effects. */
+ int iteration_count;
+
+ /* Stores the displacement produced by the laplacian step of HC smooth. */
+ float (*surface_smooth_laplacian_disp)[3];
+ float surface_smooth_shape_preservation;
+ float surface_smooth_current_vertex;
+
+ /* Sharpen mesh filter. */
+ float sharpen_smooth_ratio;
+ float sharpen_intensify_detail_strength;
+ int sharpen_curvature_smooth_iterations;
+ float *sharpen_factor;
+ float (*detail_directions)[3];
+
+ /* Filter orientation. */
+ SculptFilterOrientation orientation;
+ float obmat[4][4];
+ float obmat_inv[4][4];
+ float viewmat[4][4];
+ float viewmat_inv[4][4];
+
+ /* Displacement eraser. */
+ float (*limit_surface_co)[3];
+
+ /* unmasked nodes */
+ PBVHNode **nodes;
+ int totnode;
+
+ /* Cloth filter. */
+ SculptClothSimulation *cloth_sim;
+ float cloth_sim_pinch_point[3];
+
+ /* mask expand iteration caches */
+ int mask_update_current_it;
+ int mask_update_last_it;
+ int *mask_update_it;
+ float *normal_factor;
+ float *edge_factor;
+ float *prev_mask;
+ float mask_expand_initial_co[3];
+
+ int new_face_set;
+ int *prev_face_set;
+
+ int active_face_set;
+
+ /* Auto-masking. */
+ AutomaskingCache *automasking;
+} FilterCache;
+
+/**
+ * This structure contains all the temporary data
+ * needed for individual brush strokes.
+ */
typedef struct StrokeCache {
/* Invariants */
float initial_radius;
float scale[3];
int flag;
float clip_tolerance[3];
+ float clip_mirror_mtx[4][4];
float initial_mouse[2];
/* Variants */
@@ -1068,26 +615,10 @@ typedef struct StrokeCache {
} StrokeCache;
-/* Sculpt Filters */
-typedef enum SculptFilterOrientation {
- SCULPT_FILTER_ORIENTATION_LOCAL = 0,
- SCULPT_FILTER_ORIENTATION_WORLD = 1,
- SCULPT_FILTER_ORIENTATION_VIEW = 2,
-} SculptFilterOrientation;
-
-/* Defines how transform tools are going to apply its displacement. */
-typedef enum SculptTransformDisplacementMode {
- /* Displaces the elements from their original coordinates. */
- SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL = 0,
- /* Displaces the elements incrementally from their previous position. */
- SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL = 1,
-} SculptTransformDisplacementMode;
-
-void SCULPT_filter_to_orientation_space(float r_v[3], struct FilterCache *filter_cache);
-void SCULPT_filter_to_object_space(float r_v[3], struct FilterCache *filter_cache);
-void SCULPT_filter_zero_disabled_axis_components(float r_v[3], struct FilterCache *filter_cache);
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Expand
+ * \{ */
-/* Sculpt Expand. */
typedef enum eSculptExpandFalloffType {
SCULPT_EXPAND_FALLOFF_GEODESIC,
SCULPT_EXPAND_FALLOFF_TOPOLOGY,
@@ -1235,84 +766,687 @@ typedef struct ExpandCache {
int *original_face_sets;
float (*original_colors)[4];
} ExpandCache;
+/** \} */
-typedef struct FilterCache {
- bool enabled_axis[3];
- bool enabled_force_axis[3];
- int random_seed;
+/** \} */
- /* Used for alternating between filter operations in filters that need to apply different ones to
- * achieve certain effects. */
- int iteration_count;
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Poll Functions
+ * \{ */
- /* Stores the displacement produced by the laplacian step of HC smooth. */
- float (*surface_smooth_laplacian_disp)[3];
- float surface_smooth_shape_preservation;
- float surface_smooth_current_vertex;
+bool SCULPT_mode_poll(struct bContext *C);
+bool SCULPT_mode_poll_view3d(struct bContext *C);
+/**
+ * Checks for a brush, not just sculpt mode.
+ */
+bool SCULPT_poll(struct bContext *C);
+bool SCULPT_poll_view3d(struct bContext *C);
- /* Sharpen mesh filter. */
- float sharpen_smooth_ratio;
- float sharpen_intensify_detail_strength;
- int sharpen_curvature_smooth_iterations;
- float *sharpen_factor;
- float (*detail_directions)[3];
+bool SCULPT_vertex_colors_poll(struct bContext *C);
- /* Filter orientation. */
- SculptFilterOrientation orientation;
- float obmat[4][4];
- float obmat_inv[4][4];
- float viewmat[4][4];
- float viewmat_inv[4][4];
+/** \} */
- /* Displacement eraser. */
- float (*limit_surface_co)[3];
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Update Functions
+ * \{ */
- /* unmasked nodes */
- PBVHNode **nodes;
- int totnode;
+void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags);
+void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags);
- /* Cloth filter. */
- SculptClothSimulation *cloth_sim;
- float cloth_sim_pinch_point[3];
+void SCULPT_pbvh_clear(Object *ob);
- /* mask expand iteration caches */
- int mask_update_current_it;
- int mask_update_last_it;
- int *mask_update_it;
- float *normal_factor;
- float *edge_factor;
- float *prev_mask;
- float mask_expand_initial_co[3];
+/**
+ * Flush displacement from deformed PBVH to original layer.
+ */
+void SCULPT_flush_stroke_deform(struct Sculpt *sd, Object *ob, bool is_proxy_used);
- int new_face_set;
- int *prev_face_set;
+/**
+ * Should be used after modifying the mask or Face Sets IDs.
+ */
+void SCULPT_tag_update_overlays(bContext *C);
+/** \} */
- int active_face_set;
+/* -------------------------------------------------------------------- */
+/** \name Stroke Functions
+ * \{ */
- /* Transform. */
- SculptTransformDisplacementMode transform_displacement_mode;
+/* Stroke */
- /* Auto-masking. */
- AutomaskingCache *automasking;
-} FilterCache;
+/**
+ * Do a ray-cast in the tree to find the 3d brush location
+ * (This allows us to ignore the GL depth buffer)
+ * Returns 0 if the ray doesn't hit the mesh, non-zero otherwise.
+ */
+bool SCULPT_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]);
+/**
+ * Gets the normal, location and active vertex location of the geometry under the cursor. This also
+ * updates the active vertex and cursor related data of the SculptSession using the mouse position
+ */
+bool SCULPT_cursor_geometry_info_update(bContext *C,
+ SculptCursorGeometryInfo *out,
+ const float mouse[2],
+ bool use_sampled_normal);
+void SCULPT_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius);
+
+void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush);
+float SCULPT_raycast_init(struct ViewContext *vc,
+ const float mouse[2],
+ float ray_start[3],
+ float ray_end[3],
+ float ray_normal[3],
+ bool original);
+
+/* Symmetry */
+char SCULPT_mesh_symmetry_xyz_get(Object *object);
+
+/**
+ * Returns true when the step belongs to the stroke that is directly performed by the brush and
+ * not by one of the symmetry passes.
+ */
+bool SCULPT_stroke_is_main_symmetry_pass(struct StrokeCache *cache);
+/**
+ * Return true only once per stroke on the first symmetry pass, regardless of the symmetry passes
+ * enabled.
+ *
+ * This should be used for functionality that needs to be computed once per stroke of a particular
+ * tool (allocating memory, updating random seeds...).
+ */
+bool SCULPT_stroke_is_first_brush_step(struct StrokeCache *cache);
+/**
+ * Returns true on the first brush step of each symmetry pass.
+ */
+bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(struct StrokeCache *cache);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt mesh accessor API
+ * \{ */
+
+/** Ensure random access; required for PBVH_BMESH */
+void SCULPT_vertex_random_access_ensure(struct SculptSession *ss);
+
+int SCULPT_vertex_count_get(struct SculptSession *ss);
+const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index);
+
+/** Get the normal for a given sculpt vertex; do not modify the result */
+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]);
+
+/**
+ * Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled.
+ */
+const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index);
+
+/**
+ * Returns the info of the limit surface when multi-res is available,
+ * otherwise it returns the current coordinate of the vertex.
+ */
+void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]);
+
+/**
+ * Returns the pointer to the coordinates that should be edited from a brush tool iterator
+ * depending on the given deformation target.
+ */
+float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss,
+ int deform_target,
+ PBVHVertexIter *iter);
+
+void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
+ int index,
+ bool include_duplicates,
+ SculptVertexNeighborIter *iter);
+
+/** Iterator over neighboring vertices. */
+#define SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
+ SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
+ for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
+ neighbor_iterator.i++) { \
+ neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i];
+
+/** Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
+ * first since they are nearest for floodfill. */
+#define SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
+ SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
+ for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
+ neighbor_iterator.i--) { \
+ neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \
+ neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
+ neighbor_iterator.size - neighbor_iterator.num_duplicates);
+
+#define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \
+ } \
+ if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
+ MEM_freeN(neighbor_iterator.neighbors); \
+ } \
+ ((void)0)
+
+int SCULPT_active_vertex_get(SculptSession *ss);
+const float *SCULPT_active_vertex_co_get(SculptSession *ss);
+void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]);
+
+/* Returns PBVH deformed vertices array if shape keys or deform modifiers are used, otherwise
+ * returns mesh original vertices array. */
+struct MVert *SCULPT_mesh_deformed_mverts_get(SculptSession *ss);
+
+/* Fake Neighbors */
+
+#define FAKE_NEIGHBOR_NONE -1
+
+void SCULPT_fake_neighbors_ensure(struct Sculpt *sd, Object *ob, float max_dist);
+void SCULPT_fake_neighbors_enable(Object *ob);
+void SCULPT_fake_neighbors_disable(Object *ob);
+void SCULPT_fake_neighbors_free(struct Object *ob);
+
+/* Vertex Info. */
+void SCULPT_boundary_info_ensure(Object *object);
+/* Boundary Info needs to be initialized in order to use this function. */
+bool SCULPT_vertex_is_boundary(const SculptSession *ss, int index);
+
+void SCULPT_connected_components_ensure(Object *ob);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Visibility API
+ * \{ */
+
+void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible);
+bool SCULPT_vertex_visible_get(SculptSession *ss, int index);
+
+void SCULPT_visibility_sync_all_face_sets_to_vertices(struct Object *ob);
+void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Face Sets API
+ * \{ */
+
+int SCULPT_active_face_set_get(SculptSession *ss);
+int SCULPT_vertex_face_set_get(SculptSession *ss, int index);
+void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set);
+
+bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set);
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index);
+
+int SCULPT_face_set_next_available_get(SculptSession *ss);
+
+void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible);
+bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index);
+bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index);
+
+void SCULPT_face_sets_visibility_invert(SculptSession *ss);
+void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Original Data API
+ * \{ */
+
+/**
+ * Initialize a #SculptOrigVertData for accessing original vertex data;
+ * handles #BMesh, #Mesh, and multi-resolution.
+ */
+void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node);
+/**
+ * Update a #SculptOrigVertData for a particular vertex from the PBVH iterator.
+ */
+void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter);
+/**
+ * Initialize a #SculptOrigVertData for accessing original vertex data;
+ * handles #BMesh, #Mesh, and multi-resolution.
+ */
+void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data,
+ Object *ob,
+ struct SculptUndoNode *unode);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Brush Utilities.
+ * \{ */
+
+BLI_INLINE bool SCULPT_tool_needs_all_pbvh_nodes(const Brush *brush)
+{
+ if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) {
+ /* Elastic deformations in any brush need all nodes to avoid artifacts as the effect
+ * of the Kelvinlet is not constrained by the radius. */
+ return true;
+ }
+
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
+ /* Pose needs all nodes because it applies all symmetry iterations at the same time
+ * and the IK chain can grow to any area of the model. */
+ /* TODO: This can be optimized by filtering the nodes after calculating the chain. */
+ return true;
+ }
+
+ if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) {
+ /* Boundary needs all nodes because it is not possible to know where the boundary
+ * deformation is going to be propagated before calculating it. */
+ /* TODO: after calculating the boundary info in the first iteration, it should be
+ * possible to get the nodes that have vertices included in any boundary deformation
+ * and cache them. */
+ return true;
+ }
+
+ if (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK &&
+ brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC) {
+ /* Snake hook in elastic deform type has same requirements as the elastic deform tool. */
+ return true;
+ }
+ return false;
+}
+
+void SCULPT_calc_brush_plane(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode,
+ float r_area_no[3],
+ float r_area_co[3]);
+
+void SCULPT_calc_area_normal(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]);
+/**
+ * This calculates flatten center and area normal together,
+ * amortizing the memory bandwidth and loop overhead to calculate both at the same time.
+ */
+void SCULPT_calc_area_normal_and_center(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3]);
+void SCULPT_calc_area_center(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3]);
+
+int SCULPT_nearest_vertex_get(struct Sculpt *sd,
+ struct Object *ob,
+ const float co[3],
+ float max_distance,
+ bool use_original);
+
+int SCULPT_plane_point_side(const float co[3], const float plane[4]);
+int SCULPT_plane_trim(const struct StrokeCache *cache,
+ const struct Brush *brush,
+ const float val[3]);
+/**
+ * Handles clipping against a mirror modifier and #SCULPT_LOCK_X/Y/Z axis flags.
+ */
+void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3]);
+
+float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss);
+
+ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]);
+bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], char symm);
+/**
+ * Checks if a vertex is inside the brush radius from any of its mirrored axis.
+ */
+bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3],
+ const float br_co[3],
+ float radius,
+ char symm);
+bool SCULPT_is_symmetry_iteration_valid(char i, char symm);
+void SCULPT_flip_v3_by_symm_area(float v[3],
+ ePaintSymmetryFlags symm,
+ ePaintSymmetryAreas symmarea,
+ const float pivot[3]);
+void SCULPT_flip_quat_by_symm_area(float quat[4],
+ ePaintSymmetryFlags symm,
+ ePaintSymmetryAreas symmarea,
+ const float pivot[3]);
+
+/**
+ * Initialize a point-in-brush test
+ */
+void SCULPT_brush_test_init(struct SculptSession *ss, SculptBrushTest *test);
+
+bool SCULPT_brush_test_sphere(SculptBrushTest *test, const float co[3]);
+bool SCULPT_brush_test_sphere_sq(SculptBrushTest *test, const float co[3]);
+bool SCULPT_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3]);
+bool SCULPT_brush_test_cube(SculptBrushTest *test,
+ const float co[3],
+ const float local[4][4],
+ float roundness);
+bool SCULPT_brush_test_circle_sq(SculptBrushTest *test, const float co[3]);
+/**
+ * Test AABB against sphere.
+ */
+bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v);
+/**
+ * 2D projection (distance to line).
+ */
+bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v);
+
+/**
+ * Initialize a point-in-brush test with a given falloff shape
+ *
+ * \param falloff_shape PAINT_FALLOFF_SHAPE_SPHERE or PAINT_FALLOFF_SHAPE_TUBE
+ * \return The brush falloff function
+ */
+SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss,
+ SculptBrushTest *test,
+ char falloff_shape);
+const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
+ char falloff_shape);
+
+/**
+ * Return a multiplier for brush strength on a particular vertex.
+ */
+float SCULPT_brush_strength_factor(struct SculptSession *ss,
+ const struct Brush *br,
+ const float point[3],
+ float len,
+ const float vno[3],
+ const float fno[3],
+ float mask,
+ int vertex_index,
+ int thread_id);
+
+/**
+ * Tilts a normal by the x and y tilt values using the view axis.
+ */
+void SCULPT_tilt_apply_to_normal(float r_normal[3],
+ struct StrokeCache *cache,
+ float tilt_strength);
+
+/**
+ * Get effective surface normal with pen tilt and tilt strength applied to it.
+ */
+void SCULPT_tilt_effective_normal_get(const SculptSession *ss, const Brush *brush, float r_no[3]);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flood Fill
+ * \{ */
+
+void SCULPT_floodfill_init(struct SculptSession *ss, SculptFloodFill *flood);
+void SCULPT_floodfill_add_active(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ SculptFloodFill *flood,
+ float radius);
+void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ SculptFloodFill *flood,
+ int index,
+ float radius);
+void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index);
+void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index);
+void SCULPT_floodfill_execute(
+ struct SculptSession *ss,
+ SculptFloodFill *flood,
+ bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
+ void *userdata);
+void SCULPT_floodfill_free(SculptFloodFill *flood);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dynamic topology
+ * \{ */
-void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,
- const char symm,
- const char axis,
- const float angle);
+enum eDynTopoWarnFlag {
+ DYNTOPO_WARN_VDATA = (1 << 0),
+ DYNTOPO_WARN_EDATA = (1 << 1),
+ DYNTOPO_WARN_LDATA = (1 << 2),
+ DYNTOPO_WARN_MODIFIER = (1 << 3),
+};
+
+/** Enable dynamic topology; mesh will be triangulated */
+void SCULPT_dynamic_topology_enable_ex(struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob);
+void SCULPT_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode);
+void sculpt_dynamic_topology_disable_with_undo(struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob);
+
+/**
+ * Returns true if the stroke will use dynamic topology, false
+ * otherwise.
+ *
+ * Factors: some brushes like grab cannot do dynamic topology.
+ * Others, like smooth, are better without.
+ * Same goes for alt-key smoothing.
+ */
+bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush);
+
+void SCULPT_dynamic_topology_triangulate(struct BMesh *bm);
+void SCULPT_dyntopo_node_layers_add(struct SculptSession *ss);
+
+enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-masking.
+ * \{ */
+
+float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking,
+ SculptSession *ss,
+ int vert);
+
+/* Returns the automasking cache depending on the active tool. Used for code that can run both for
+ * brushes and filter. */
+struct AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss);
+
+struct AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob);
+void SCULPT_automasking_cache_free(struct AutomaskingCache *automasking);
+
+bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd, const Brush *br, eAutomasking_flag mode);
+bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br);
+
+float *SCULPT_boundary_automasking_init(Object *ob,
+ eBoundaryAutomaskMode mode,
+ int propagation_steps,
+ float *automask_factor);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Geodesic distances.
+ * \{ */
+
+/**
+ * Returns an array indexed by vertex index containing the geodesic distance to the closest vertex
+ * in the initial vertex set. The caller is responsible for freeing the array.
+ * Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will
+ * fallback to euclidean distances to one of the initial vertices in the set.
+ */
+float *SCULPT_geodesic_distances_create(struct Object *ob,
+ struct GSet *initial_vertices,
+ float limit_radius);
+float *SCULPT_geodesic_from_vertex_and_symm(struct Sculpt *sd,
+ struct Object *ob,
+ int vertex,
+ float limit_radius);
+float *SCULPT_geodesic_from_vertex(Object *ob, int vertex, float limit_radius);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Filter API
+ * \{ */
+
+void SCULPT_filter_cache_init(struct bContext *C, Object *ob, Sculpt *sd, int undo_type);
+void SCULPT_filter_cache_free(SculptSession *ss);
+
+void SCULPT_mask_filter_smooth_apply(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, int smooth_iterations);
+
+/* Filter orientation utils. */
+void SCULPT_filter_to_orientation_space(float r_v[3], struct FilterCache *filter_cache);
+void SCULPT_filter_to_object_space(float r_v[3], struct FilterCache *filter_cache);
+void SCULPT_filter_zero_disabled_axis_components(float r_v[3], struct FilterCache *filter_cache);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cloth Simulation.
+ * \{ */
+
+/* Main cloth brush function */
+void SCULPT_do_cloth_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim);
+
+/* Public functions. */
+
+struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create(struct SculptSession *ss,
+ float cloth_mass,
+ float cloth_damping,
+ float cloth_softbody_strength,
+ bool use_collisions,
+ bool needs_deform_coords);
+void SCULPT_cloth_brush_simulation_init(struct SculptSession *ss,
+ struct SculptClothSimulation *cloth_sim);
+
+void SCULPT_cloth_sim_activate_nodes(struct SculptClothSimulation *cloth_sim,
+ PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_cloth_brush_store_simulation_state(struct SculptSession *ss,
+ struct SculptClothSimulation *cloth_sim);
+
+void SCULPT_cloth_brush_do_simulation_step(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptClothSimulation *cloth_sim,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_cloth_brush_ensure_nodes_constraints(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode,
+ struct SculptClothSimulation *cloth_sim,
+ float initial_location[3],
+ float radius);
+
+/**
+ * Cursor drawing function.
+ */
+void SCULPT_cloth_simulation_limits_draw(uint gpuattr,
+ const struct Brush *brush,
+ const float location[3],
+ const float normal[3],
+ float rds,
+ float line_width,
+ const float outline_col[3],
+ float alpha);
+void SCULPT_cloth_plane_falloff_preview_draw(uint gpuattr,
+ struct SculptSession *ss,
+ const float outline_col[3],
+ float outline_alpha);
+
+PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss,
+ Brush *brush,
+ int *r_totnode);
+
+BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush)
+{
+ return (brush->sculpt_tool == SCULPT_TOOL_CLOTH && ELEM(brush->cloth_deform_type,
+ BRUSH_CLOTH_DEFORM_GRAB,
+ BRUSH_CLOTH_DEFORM_SNAKE_HOOK)) ||
+ /* All brushes that are not the cloth brush deform the simulation using softbody
+ * constraints instead of applying forces. */
+ (brush->sculpt_tool != SCULPT_TOOL_CLOTH &&
+ brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM);
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smoothing API
+ * \{ */
+
+/**
+ * For bmesh: Average surrounding verts based on an orthogonality measure.
+ * Naturally converges to a quad-like structure.
+ */
+void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v);
+
+void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index);
+float SCULPT_neighbor_mask_average(SculptSession *ss, int index);
+void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index);
+
+/**
+ * Mask the mesh boundaries smoothing only the mesh surface without using auto-masking.
+ */
+void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index);
+
+void SCULPT_smooth(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float bstrength, bool smooth_mask);
+void SCULPT_do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Surface Smooth Brush. */
+
+void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
+ float *disp,
+ const float co[3],
+ float (*laplacian_disp)[3],
+ int v_index,
+ const float origco[3],
+ float alpha);
+void SCULPT_surface_smooth_displace_step(
+ SculptSession *ss, float *co, float (*laplacian_disp)[3], int v_index, float beta, float fade);
+void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Slide/Relax */
+void SCULPT_relax_vertex(struct SculptSession *ss,
+ struct PBVHVertexIter *vd,
+ float factor,
+ bool filter_boundary_face_sets,
+ float *r_final_pos);
+
+/** \} */
+
+/**
+ * Expose 'calc_area_normal' externally (just for vertex paint).
+ */
+bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush,
+ Object *ob,
+ PBVHNode **nodes,
+ int totnode,
+ bool use_threading,
+ float r_area_no[3]);
+
+/**
+ * Flip all the edit-data across the axis/axes specified by \a symm.
+ * Used to calculate multiple modifications to the mesh when symmetry is enabled.
+ */
+void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache, char symm, char axis, float angle);
void SCULPT_cache_free(StrokeCache *cache);
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Undo
+ * \{ */
+
SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type);
SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node);
SculptUndoNode *SCULPT_undo_get_first_node(void);
void SCULPT_undo_push_begin(struct Object *ob, const char *name);
void SCULPT_undo_push_end(void);
-void SCULPT_undo_push_end_ex(const bool use_nested_undo);
+void SCULPT_undo_push_end_ex(bool use_nested_undo);
+
+/** \} */
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]);
+/**
+ * Copy the PBVH bounding box into the object's bounding box.
+ */
void SCULPT_update_object_bounding_box(struct Object *ob);
+/**
+ * Get a screen-space rectangle of the modified area.
+ */
bool SCULPT_get_redraw_rect(struct ARegion *region,
struct RegionView3D *rv3d,
Object *ob,
@@ -1320,11 +1454,18 @@ bool SCULPT_get_redraw_rect(struct ARegion *region,
/* Operators. */
-/* Expand. */
+/* -------------------------------------------------------------------- */
+/** \name Expand Operator
+ * \{ */
+
void SCULPT_OT_expand(struct wmOperatorType *ot);
void sculpt_expand_modal_keymap(struct wmKeyConfig *keyconf);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Gesture Operators
+ * \{ */
-/* Gestures. */
void SCULPT_OT_face_set_lasso_gesture(struct wmOperatorType *ot);
void SCULPT_OT_face_set_box_gesture(struct wmOperatorType *ot);
@@ -1332,41 +1473,265 @@ void SCULPT_OT_trim_lasso_gesture(struct wmOperatorType *ot);
void SCULPT_OT_trim_box_gesture(struct wmOperatorType *ot);
void SCULPT_OT_project_line_gesture(struct wmOperatorType *ot);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Face Set Operators
+ * \{ */
-/* Face Sets. */
void SCULPT_OT_face_sets_randomize_colors(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_change_visibility(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_init(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_create(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot);
-/* Transform. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Operators
+ * \{ */
+
void SCULPT_OT_set_pivot_position(struct wmOperatorType *ot);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Filter Operators
+ * \{ */
/* Mesh Filter. */
+
void SCULPT_OT_mesh_filter(struct wmOperatorType *ot);
/* Cloth Filter. */
+
void SCULPT_OT_cloth_filter(struct wmOperatorType *ot);
/* Color Filter. */
+
void SCULPT_OT_color_filter(struct wmOperatorType *ot);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Interactive Mask Operators
+ * \{ */
+
/* Mask filter and Dirty Mask. */
+
void SCULPT_OT_mask_filter(struct wmOperatorType *ot);
void SCULPT_OT_dirty_mask(struct wmOperatorType *ot);
/* Mask and Face Sets Expand. */
+
void SCULPT_OT_mask_expand(struct wmOperatorType *ot);
/* Mask Init. */
+
void SCULPT_OT_mask_init(struct wmOperatorType *ot);
+/** \} */
/* Detail size. */
+
+/* -------------------------------------------------------------------- */
+/** \name Dyntopo/Retopology Operators
+ * \{ */
+
void SCULPT_OT_detail_flood_fill(struct wmOperatorType *ot);
void SCULPT_OT_sample_detail_size(struct wmOperatorType *ot);
void SCULPT_OT_set_detail_size(struct wmOperatorType *ot);
void SCULPT_OT_dyntopo_detail_size_edit(struct wmOperatorType *ot);
+/** \} */
/* Dyntopo. */
+
void SCULPT_OT_dynamic_topology_toggle(struct wmOperatorType *ot);
+
+/* sculpt_brush_types.c */
+
+/* -------------------------------------------------------------------- */
+/** \name Brushes
+ * \{ */
+
+/* Pose Brush. */
+
+/**
+ * Main Brush Function.
+ */
+void SCULPT_do_pose_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+/**
+ * Calculate the pose origin and (Optionally the pose factor)
+ * that is used when using the pose brush.
+ *
+ * \param r_pose_origin: Must be a valid pointer.
+ * \param r_pose_factor: Optional, when set to NULL it won't be calculated.
+ */
+void SCULPT_pose_calc_pose_data(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ float initial_location[3],
+ float radius,
+ float pose_offset,
+ float *r_pose_origin,
+ float *r_pose_factor);
+void SCULPT_pose_brush_init(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ struct Brush *br);
+struct SculptPoseIKChain *SCULPT_pose_ik_chain_init(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ struct Brush *br,
+ const float initial_location[3],
+ float radius);
+void SCULPT_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain);
+
+/* Boundary Brush. */
+
+/**
+ * Main function to get #SculptBoundary data both for brush deformation and viewport preview.
+ * Can return NULL if there is no boundary from the given vertex using the given radius.
+ */
+struct SculptBoundary *SCULPT_boundary_data_init(Object *object,
+ Brush *brush,
+ int initial_vertex,
+ float radius);
+void SCULPT_boundary_data_free(struct SculptBoundary *boundary);
+/* Main Brush Function. */
+void SCULPT_do_boundary_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_boundary_edges_preview_draw(uint gpuattr,
+ struct SculptSession *ss,
+ const float outline_col[3],
+ float outline_alpha);
+void SCULPT_boundary_pivot_line_preview_draw(uint gpuattr, struct SculptSession *ss);
+
+/* Multi-plane Scrape Brush. */
+/* Main Brush Function. */
+void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+void SCULPT_multiplane_scrape_preview_draw(uint gpuattr,
+ Brush *brush,
+ SculptSession *ss,
+ const float outline_col[3],
+ float outline_alpha);
+/* Draw Face Sets Brush. */
+void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Paint Brush. */
+void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Smear Brush. */
+void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+float SCULPT_clay_thumb_get_stabilized_pressure(struct StrokeCache *cache);
+
+void SCULPT_do_draw_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_do_fill_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_scrape_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_clay_thumb_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_flatten_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_clay_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_clay_strips_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_snake_hook_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_thumb_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_rotate_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_layer_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_inflate_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_nudge_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_crease_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_pinch_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_grab_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_elastic_deform_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_draw_sharp_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_slide_relax_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_do_displacement_smear_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_displacement_eraser_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_mask_brush_draw(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_mask_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+/** \} */
+
+void SCULPT_bmesh_topology_rake(
+ struct Sculpt *sd, struct Object *ob, struct PBVHNode **nodes, int totnode, float bstrength);
+
+/* end sculpt_brush_types.c */
+
+/* sculpt_ops.c */
+void SCULPT_OT_brush_stroke(struct wmOperatorType *ot);
+
+/* end sculpt_ops.c */
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
index 9b06b2ee5d5..b59d461bab5 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
@@ -170,10 +170,10 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
ARegion *region = CTX_wm_region(C);
- float prevclick_f[2];
- copy_v2_v2(prevclick_f, op->customdata);
- const int prevclick[2] = {(int)prevclick_f[0], (int)prevclick_f[1]};
- int len = (int)len_v2v2_int(prevclick, event->mval);
+ float prev_click_f[2];
+ copy_v2_v2(prev_click_f, op->customdata);
+ const int prev_click[2] = {(int)prev_click_f[0], (int)prev_click_f[1]};
+ int len = (int)len_v2v2_int(prev_click, event->mval);
len = abs(len);
int mask_speed = RNA_int_get(op->ptr, "mask_speed");
int mask_expand_update_it = len / mask_speed;
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index f78f30a2cfd..0fec7a9c4bd 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -92,12 +92,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
}
float local_co[3];
float normal[3];
- if (vd.no) {
- normal_short_to_float_v3(normal, vd.no);
- }
- else {
- copy_v3_v3(normal, vd.fno);
- }
+ copy_v3_v3(normal, vd.no ? vd.no : vd.fno);
mul_v3_m4v3(local_co, mat, vd.co);
/* Use the brush falloff to weight the sampled normals. */
const float fade = SCULPT_brush_strength_factor(ss,
@@ -229,7 +224,6 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
/* Public functions. */
-/* Main Brush Function. */
void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
new file mode 100644
index 00000000000..119d246a770
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -0,0 +1,1141 @@
+/*
+ * 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) 2006 by Nicholas Bishop
+ * All rights reserved.
+ * Implements the Sculpt Mode tools
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_array.h"
+#include "BLI_blenlib.h"
+#include "BLI_dial_2d.h"
+#include "BLI_ghash.h"
+#include "BLI_gsqueue.h"
+#include "BLI_hash.h"
+#include "BLI_link_utils.h"
+#include "BLI_linklist.h"
+#include "BLI_linklist_stack.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_color_blend.h"
+#include "BLI_memarena.h"
+#include "BLI_rand.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+#include "atomic_ops.h"
+
+#include "BLT_translation.h"
+
+#include "PIL_time.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_listBase.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_attribute.h"
+#include "BKE_brush.h"
+#include "BKE_ccg.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_kelvinlet.h"
+#include "BKE_key.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_fair.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_mirror.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_pbvh.h"
+#include "BKE_pointcache.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_subdiv_ccg.h"
+#include "BKE_subsurf.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "IMB_colormanagement.h"
+
+#include "GPU_batch.h"
+#include "GPU_batch_presets.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_space_api.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Reset the copy of the mesh that is being sculpted on (currently just for the layer brush). */
+
+static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ if (!ss) {
+ return OPERATOR_FINISHED;
+ }
+ SCULPT_vertex_random_access_ensure(ss);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
+
+ MEM_SAFE_FREE(ss->persistent_base);
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert,
+ "layer persistent base");
+
+ for (int i = 0; i < totvert; i++) {
+ copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i));
+ SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no);
+ ss->persistent_base[i].disp = 0.0f;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Set Persistent Base";
+ ot->idname = "SCULPT_OT_set_persistent_base";
+ ot->description = "Reset the copy of the mesh that is being sculpted on";
+
+ /* API callbacks. */
+ ot->exec = sculpt_set_persistent_base_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/************************* SCULPT_OT_optimize *************************/
+
+static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ SCULPT_pbvh_clear(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+/* The BVH gets less optimal more quickly with dynamic topology than
+ * regular sculpting. There is no doubt more clever stuff we can do to
+ * optimize it on the fly, but for now this gives the user a nicer way
+ * to recalculate it than toggling modes. */
+static void SCULPT_OT_optimize(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Rebuild BVH";
+ ot->idname = "SCULPT_OT_optimize";
+ ot->description = "Recalculate the sculpt BVH to improve performance";
+
+ /* API callbacks. */
+ ot->exec = sculpt_optimize_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************* Dynamic topology symmetrize ********************/
+
+static bool sculpt_no_multires_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if (SCULPT_mode_poll(C) && ob->sculpt && ob->sculpt->pbvh) {
+ return BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_GRIDS;
+ }
+ return false;
+}
+
+static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ SculptSession *ss = ob->sculpt;
+ PBVH *pbvh = ss->pbvh;
+ const float dist = RNA_float_get(op->ptr, "merge_tolerance");
+
+ if (!pbvh) {
+ return OPERATOR_CANCELLED;
+ }
+
+ switch (BKE_pbvh_type(pbvh)) {
+ case PBVH_BMESH:
+ /* Dyntopo Symmetrize. */
+
+ /* To simplify undo for symmetrize, all BMesh elements are logged
+ * as deleted, then after symmetrize operation all BMesh elements
+ * are logged as added (as opposed to attempting to store just the
+ * parts that symmetrize modifies). */
+ SCULPT_undo_push_begin(ob, "Dynamic topology symmetrize");
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
+ BM_log_before_all_removed(ss->bm, ss->bm_log);
+
+ BM_mesh_toolflags_set(ss->bm, true);
+
+ /* Symmetrize and re-triangulate. */
+ BMO_op_callf(ss->bm,
+ (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
+ "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b",
+ sd->symmetrize_direction,
+ dist,
+ true);
+ SCULPT_dynamic_topology_triangulate(ss->bm);
+
+ /* Bisect operator flags edges (keep tags clean for edge queue). */
+ BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
+
+ BM_mesh_toolflags_set(ss->bm, false);
+
+ /* Finish undo. */
+ BM_log_all_added(ss->bm, ss->bm_log);
+ SCULPT_undo_push_end();
+
+ break;
+ case PBVH_FACES:
+ /* Mesh Symmetrize. */
+ ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize");
+ Mesh *mesh = ob->data;
+
+ BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist);
+
+ ED_sculpt_undo_geometry_end(ob);
+ BKE_mesh_calc_normals(ob->data);
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+
+ break;
+ case PBVH_GRIDS:
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Redraw. */
+ SCULPT_pbvh_clear(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_symmetrize(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Symmetrize";
+ ot->idname = "SCULPT_OT_symmetrize";
+ ot->description = "Symmetrize the topology modifications";
+
+ /* API callbacks. */
+ ot->exec = sculpt_symmetrize_exec;
+ ot->poll = sculpt_no_multires_poll;
+
+ RNA_def_float(ot->srna,
+ "merge_tolerance",
+ 0.001f,
+ 0.0f,
+ FLT_MAX,
+ "Merge Distance",
+ "Distance within which symmetrical vertices are merged",
+ 0.0f,
+ 1.0f);
+}
+
+/**** Toggle operator for turning sculpt mode on or off ****/
+
+static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+ /* Create persistent sculpt mode data. */
+ BKE_sculpt_toolsettings_data_ensure(scene);
+
+ /* Create sculpt mode session data. */
+ if (ob->sculpt != NULL) {
+ BKE_sculptsession_free(ob);
+ }
+ ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+ ob->sculpt->mode_type = OB_MODE_SCULPT;
+
+ BKE_sculpt_ensure_orig_mesh_data(scene, ob);
+
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+
+ /* This function expects a fully evaluated depsgraph. */
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
+
+ /* Here we can detect geometry that was just added to Sculpt Mode as it has the
+ * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */
+ /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not
+ * initialized, which is used is some operators that modify the mesh topology to perform certain
+ * actions in the new polys. After these operations are finished, all polys should have a valid
+ * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility
+ * correctly. */
+ /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new
+ * objects, like moving the transform pivot position to the new area or masking existing
+ * geometry. */
+ SculptSession *ss = ob->sculpt;
+ const int new_face_set = SCULPT_face_set_next_available_get(ss);
+ for (int i = 0; i < ss->totfaces; i++) {
+ if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) {
+ ss->face_sets[i] = new_face_set;
+ }
+ }
+}
+
+void ED_object_sculptmode_enter_ex(Main *bmain,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const bool force_dyntopo,
+ ReportList *reports)
+{
+ const int mode_flag = OB_MODE_SCULPT;
+ Mesh *me = BKE_mesh_from_object(ob);
+
+ /* Enter sculpt mode. */
+ ob->mode |= mode_flag;
+
+ sculpt_init_session(bmain, depsgraph, scene, ob);
+
+ if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f &&
+ fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) {
+ BKE_report(
+ reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable");
+ }
+ else if (is_negative_m4(ob->obmat)) {
+ BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable");
+ }
+
+ Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT);
+ BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT);
+
+ paint_cursor_start(paint, SCULPT_mode_poll_view3d);
+
+ /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
+ * As long as no data was added that is not supported. */
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+
+ const char *message_unsupported = NULL;
+ if (me->totloop != me->totpoly * 3) {
+ message_unsupported = TIP_("non-triangle face");
+ }
+ else if (mmd != NULL) {
+ message_unsupported = TIP_("multi-res modifier");
+ }
+ else {
+ enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob);
+ if (flag == 0) {
+ /* pass */
+ }
+ else if (flag & DYNTOPO_WARN_VDATA) {
+ message_unsupported = TIP_("vertex data");
+ }
+ else if (flag & DYNTOPO_WARN_EDATA) {
+ message_unsupported = TIP_("edge data");
+ }
+ else if (flag & DYNTOPO_WARN_LDATA) {
+ message_unsupported = TIP_("face data");
+ }
+ else if (flag & DYNTOPO_WARN_MODIFIER) {
+ message_unsupported = TIP_("constructive modifier");
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ if ((message_unsupported == NULL) || force_dyntopo) {
+ /* Needed because we may be entering this mode before the undo system loads. */
+ wmWindowManager *wm = bmain->wm.first;
+ bool has_undo = wm->undo_stack != NULL;
+ /* Undo push is needed to prevent memory leak. */
+ if (has_undo) {
+ SCULPT_undo_push_begin(ob, "Dynamic topology enable");
+ }
+ SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
+ if (has_undo) {
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
+ SCULPT_undo_push_end();
+ }
+ }
+ else {
+ BKE_reportf(
+ reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported);
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+ }
+ }
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+}
+
+void ED_object_sculptmode_enter(struct bContext *C, Depsgraph *depsgraph, ReportList *reports)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports);
+}
+
+void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+ const int mode_flag = OB_MODE_SCULPT;
+ Mesh *me = BKE_mesh_from_object(ob);
+
+ multires_flush_sculpt_updates(ob);
+
+ /* Not needed for now. */
+#if 0
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+ const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
+#endif
+
+ /* Always for now, so leaving sculpt mode always ensures scene is in
+ * a consistent state. */
+ if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ /* Dynamic topology must be disabled before exiting sculpt
+ * mode to ensure the undo stack stays in a consistent
+ * state. */
+ sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob);
+
+ /* Store so we know to re-enable when entering sculpt mode. */
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+ }
+
+ /* Leave sculpt mode. */
+ ob->mode &= ~mode_flag;
+
+ BKE_sculptsession_free(ob);
+
+ paint_cursor_delete_textures();
+
+ /* Never leave derived meshes behind. */
+ BKE_object_free_derived_caches(ob);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+}
+
+void ED_object_sculptmode_exit(bContext *C, Depsgraph *depsgraph)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
+}
+
+static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
+{
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ const int mode_flag = OB_MODE_SCULPT;
+ const bool is_mode_set = (ob->mode & mode_flag) != 0;
+
+ if (!is_mode_set) {
+ if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (is_mode_set) {
+ ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
+ }
+ else {
+ if (depsgraph) {
+ depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ }
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports);
+ BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint);
+
+ if (ob->mode & mode_flag) {
+ Mesh *me = ob->data;
+ /* Dyntopo adds its own undo step. */
+ if ((me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) {
+ /* Without this the memfile undo step is used,
+ * while it works it causes lag when undoing the first undo step, see T71564. */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (wm->op_undo_depth <= 1) {
+ SCULPT_undo_push_begin(ob, op->type->name);
+ }
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
+
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+
+ WM_toolsystem_update_from_context_view3d(C);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Sculpt Mode";
+ ot->idname = "SCULPT_OT_sculptmode_toggle";
+ ot->description = "Toggle sculpt mode in 3D view";
+
+ /* API callbacks. */
+ ot->exec = sculpt_mode_toggle_exec;
+ ot->poll = ED_operator_object_active_editable_mesh;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+
+ ss->preview_vert_index_count = 0;
+ int totpoints = 0;
+
+ /* This function is called from the cursor drawing code, so the PBVH may not be build yet. */
+ if (!ss->pbvh) {
+ return;
+ }
+
+ if (!ss->deform_modifiers_active) {
+ return;
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
+
+ if (!ss->pmap) {
+ return;
+ }
+
+ float brush_co[3];
+ copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss));
+
+ BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
+
+ /* Assuming an average of 6 edges per vertex in a triangulated mesh. */
+ const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2;
+
+ if (ss->preview_vert_index_list == NULL) {
+ ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
+ }
+
+ GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
+ int active_v = SCULPT_active_vertex_get(ss);
+ BLI_gsqueue_push(not_visited_vertices, &active_v);
+
+ while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
+ int from_v;
+ BLI_gsqueue_pop(not_visited_vertices, &from_v);
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
+ if (totpoints + (ni.size * 2) < max_preview_vertices) {
+ int to_v = ni.index;
+ ss->preview_vert_index_list[totpoints] = from_v;
+ totpoints++;
+ ss->preview_vert_index_list[totpoints] = to_v;
+ totpoints++;
+ if (BLI_BITMAP_TEST(visited_vertices, to_v)) {
+ continue;
+ }
+ BLI_BITMAP_ENABLE(visited_vertices, to_v);
+ const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v);
+ if (len_squared_v3v3(brush_co, co) < radius * radius) {
+ BLI_gsqueue_push(not_visited_vertices, &to_v);
+ }
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ }
+
+ BLI_gsqueue_free(not_visited_vertices);
+
+ MEM_freeN(visited_vertices);
+
+ ss->preview_vert_index_count = totpoints;
+}
+
+static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ ID *data;
+ data = ob->data;
+ if (data && ID_IS_LINKED(data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (ob->type != OB_MESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Mesh *mesh = ob->data;
+
+ const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
+ if (mloopcol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
+
+ const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
+ if (MPropCol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
+
+ MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
+ MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
+
+ for (int i = 0; i < mesh->totpoly; i++) {
+ MPoly *c_poly = &polys[i];
+ for (int j = 0; j < c_poly->totloop; j++) {
+ int loop_index = c_poly->loopstart + j;
+ MLoop *c_loop = &loops[c_poly->loopstart + j];
+ float srgb_color[4];
+ linearrgb_to_srgb_v4(srgb_color, vertcols[c_loop->v].color);
+ loopcols[loop_index].r = (char)(srgb_color[0] * 255);
+ loopcols[loop_index].g = (char)(srgb_color[1] * 255);
+ loopcols[loop_index].b = (char)(srgb_color[2] * 255);
+ loopcols[loop_index].a = (char)(srgb_color[3] * 255);
+ }
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Sculpt Vertex Color to Vertex Color";
+ ot->description = "Copy the Sculpt Vertex Color to a regular color layer";
+ ot->idname = "SCULPT_OT_vertex_to_loop_colors";
+
+ /* api callbacks */
+ ot->poll = SCULPT_vertex_colors_poll;
+ ot->exec = vertex_to_loop_colors_exec;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ ID *data;
+ data = ob->data;
+ if (data && ID_IS_LINKED(data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (ob->type != OB_MESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Mesh *mesh = ob->data;
+
+ const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
+ if (mloopcol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
+
+ const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
+ if (MPropCol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
+
+ MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
+ MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
+
+ for (int i = 0; i < mesh->totpoly; i++) {
+ MPoly *c_poly = &polys[i];
+ for (int j = 0; j < c_poly->totloop; j++) {
+ int loop_index = c_poly->loopstart + j;
+ MLoop *c_loop = &loops[c_poly->loopstart + j];
+ vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f);
+ vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f);
+ vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f);
+ vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f);
+ srgb_to_linearrgb_v4(vertcols[c_loop->v].color, vertcols[c_loop->v].color);
+ }
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Color to Sculpt Vertex Color";
+ ot->description = "Copy the active loop color layer to the vertex color";
+ ot->idname = "SCULPT_OT_loop_to_vertex_colors";
+
+ /* api callbacks */
+ ot->poll = SCULPT_vertex_colors_poll;
+ ot->exec = loop_to_vertex_colors_exec;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int sculpt_sample_color_invoke(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *UNUSED(e))
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ int active_vertex = SCULPT_active_vertex_get(ss);
+ const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex);
+ if (!active_vertex_color) {
+ return OPERATOR_CANCELLED;
+ }
+
+ float color_srgb[3];
+ copy_v3_v3(color_srgb, active_vertex_color);
+ IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb);
+ BKE_brush_color_set(scene, brush, color_srgb);
+
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_sample_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Sample Color";
+ ot->idname = "SCULPT_OT_sample_color";
+ ot->description = "Sample the vertex color of the active vertex";
+
+ /* api callbacks */
+ ot->invoke = sculpt_sample_color_invoke;
+ ot->poll = SCULPT_vertex_colors_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/**
+ * #sculpt_mask_by_color_delta_get returns values in the (0,1) range that are used to generate the
+ * mask based on the difference between two colors (the active color and the color of any other
+ * vertex). Ideally, a threshold of 0 should mask only the colors that are equal to the active
+ * color and threshold of 1 should mask all colors. In order to avoid artifacts and produce softer
+ * falloffs in the mask, the MASK_BY_COLOR_SLOPE defines the size of the transition values between
+ * masked and unmasked vertices. The smaller this value is, the sharper the generated mask is going
+ * to be.
+ */
+#define MASK_BY_COLOR_SLOPE 0.25f
+
+static float sculpt_mask_by_color_delta_get(const float *color_a,
+ const float *color_b,
+ const float threshold,
+ const bool invert)
+{
+ float len = len_v3v3(color_a, color_b);
+ /* Normalize len to the (0, 1) range. */
+ len = len / M_SQRT3;
+
+ if (len < threshold - MASK_BY_COLOR_SLOPE) {
+ len = 1.0f;
+ }
+ else if (len >= threshold) {
+ len = 0.0f;
+ }
+ else {
+ len = (-len + threshold) / MASK_BY_COLOR_SLOPE;
+ }
+
+ if (invert) {
+ return 1.0f - len;
+ }
+ return len;
+}
+
+static float sculpt_mask_by_color_final_mask_get(const float current_mask,
+ const float new_mask,
+ const bool invert,
+ const bool preserve_mask)
+{
+ if (preserve_mask) {
+ if (invert) {
+ return min_ff(current_mask, new_mask);
+ }
+ return max_ff(current_mask, new_mask);
+ }
+ return new_mask;
+}
+
+typedef struct MaskByColorContiguousFloodFillData {
+ float threshold;
+ bool invert;
+ float *new_mask;
+ float initial_color[3];
+} MaskByColorContiguousFloodFillData;
+
+static void do_mask_by_color_contiguous_update_nodes_cb(
+ void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
+ bool update_node = false;
+
+ const bool invert = data->mask_by_color_invert;
+ const bool preserve_mask = data->mask_by_color_preserve_mask;
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ const float current_mask = *vd.mask;
+ const float new_mask = data->mask_by_color_floodfill[vd.index];
+ *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
+ if (current_mask == *vd.mask) {
+ continue;
+ }
+ update_node = true;
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ if (update_node) {
+ BKE_pbvh_node_mark_redraw(data->nodes[n]);
+ }
+}
+
+static bool sculpt_mask_by_color_contiguous_floodfill_cb(
+ SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+{
+ MaskByColorContiguousFloodFillData *data = userdata;
+ const float *current_color = SCULPT_vertex_color_get(ss, to_v);
+ float new_vertex_mask = sculpt_mask_by_color_delta_get(
+ current_color, data->initial_color, data->threshold, data->invert);
+ data->new_mask[to_v] = new_vertex_mask;
+
+ if (is_duplicate) {
+ data->new_mask[to_v] = data->new_mask[from_v];
+ }
+
+ float len = len_v3v3(current_color, data->initial_color);
+ len = len / M_SQRT3;
+ return len <= data->threshold;
+}
+
+static void sculpt_mask_by_color_contiguous(Object *object,
+ const int vertex,
+ const float threshold,
+ const bool invert,
+ const bool preserve_mask)
+{
+ SculptSession *ss = object->sculpt;
+ const int totvert = SCULPT_vertex_count_get(ss);
+
+ float *new_mask = MEM_calloc_arrayN(totvert, sizeof(float), "new mask");
+
+ if (invert) {
+ for (int i = 0; i < totvert; i++) {
+ new_mask[i] = 1.0f;
+ }
+ }
+
+ SculptFloodFill flood;
+ SCULPT_floodfill_init(ss, &flood);
+ SCULPT_floodfill_add_initial(&flood, vertex);
+
+ MaskByColorContiguousFloodFillData ffd;
+ ffd.threshold = threshold;
+ ffd.invert = invert;
+ ffd.new_mask = new_mask;
+ copy_v3_v3(ffd.initial_color, SCULPT_vertex_color_get(ss, vertex));
+
+ SCULPT_floodfill_execute(ss, &flood, sculpt_mask_by_color_contiguous_floodfill_cb, &ffd);
+ SCULPT_floodfill_free(&flood);
+
+ int totnode;
+ PBVHNode **nodes;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ SculptThreadedTaskData data = {
+ .ob = object,
+ .nodes = nodes,
+ .mask_by_color_floodfill = new_mask,
+ .mask_by_color_vertex = vertex,
+ .mask_by_color_threshold = threshold,
+ .mask_by_color_invert = invert,
+ .mask_by_color_preserve_mask = preserve_mask,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(
+ 0, totnode, &data, do_mask_by_color_contiguous_update_nodes_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+
+ MEM_freeN(new_mask);
+}
+
+static void do_mask_by_color_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
+ bool update_node = false;
+
+ const float threshold = data->mask_by_color_threshold;
+ const bool invert = data->mask_by_color_invert;
+ const bool preserve_mask = data->mask_by_color_preserve_mask;
+ const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ const float current_mask = *vd.mask;
+ const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert);
+ *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
+
+ if (current_mask == *vd.mask) {
+ continue;
+ }
+ update_node = true;
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ if (update_node) {
+ BKE_pbvh_node_mark_redraw(data->nodes[n]);
+ }
+}
+
+static void sculpt_mask_by_color_full_mesh(Object *object,
+ const int vertex,
+ const float threshold,
+ const bool invert,
+ const bool preserve_mask)
+{
+ SculptSession *ss = object->sculpt;
+
+ int totnode;
+ PBVHNode **nodes;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ SculptThreadedTaskData data = {
+ .ob = object,
+ .nodes = nodes,
+ .mask_by_color_vertex = vertex,
+ .mask_by_color_threshold = threshold,
+ .mask_by_color_invert = invert,
+ .mask_by_color_preserve_mask = preserve_mask,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_mask_by_color_task_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+}
+
+static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
+
+ /* Color data is not available in Multires. */
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!ss->vcol) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SCULPT_vertex_random_access_ensure(ss);
+
+ /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move,
+ * so it needs to be updated here. */
+ SculptCursorGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+
+ SCULPT_undo_push_begin(ob, "Mask by color");
+
+ const int active_vertex = SCULPT_active_vertex_get(ss);
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const bool invert = RNA_boolean_get(op->ptr, "invert");
+ const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask");
+
+ if (RNA_boolean_get(op->ptr, "contiguous")) {
+ sculpt_mask_by_color_contiguous(ob, active_vertex, threshold, invert, preserve_mask);
+ }
+ else {
+ sculpt_mask_by_color_full_mesh(ob, active_vertex, threshold, invert, preserve_mask);
+ }
+
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
+ SCULPT_undo_push_end();
+
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Mask by Color";
+ ot->idname = "SCULPT_OT_mask_by_color";
+ ot->description = "Creates a mask based on the sculpt vertex colors";
+
+ /* api callbacks */
+ ot->invoke = sculpt_mask_by_color_invoke;
+ ot->poll = SCULPT_vertex_colors_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ ot->prop = RNA_def_boolean(
+ ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas");
+
+ ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask");
+ ot->prop = RNA_def_boolean(
+ ot->srna,
+ "preserve_previous_mask",
+ false,
+ "Preserve Previous Mask",
+ "Preserve the previous mask and add or subtract the new one generated by the colors");
+
+ RNA_def_float(ot->srna,
+ "threshold",
+ 0.35f,
+ 0.0f,
+ 1.0f,
+ "Threshold",
+ "How much changes in color affect the mask generation",
+ 0.0f,
+ 1.0f);
+}
+
+void ED_operatortypes_sculpt(void)
+{
+ WM_operatortype_append(SCULPT_OT_brush_stroke);
+ WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
+ WM_operatortype_append(SCULPT_OT_set_persistent_base);
+ WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle);
+ WM_operatortype_append(SCULPT_OT_optimize);
+ WM_operatortype_append(SCULPT_OT_symmetrize);
+ WM_operatortype_append(SCULPT_OT_detail_flood_fill);
+ WM_operatortype_append(SCULPT_OT_sample_detail_size);
+ WM_operatortype_append(SCULPT_OT_set_detail_size);
+ WM_operatortype_append(SCULPT_OT_mesh_filter);
+ WM_operatortype_append(SCULPT_OT_mask_filter);
+ WM_operatortype_append(SCULPT_OT_dirty_mask);
+ WM_operatortype_append(SCULPT_OT_mask_expand);
+ WM_operatortype_append(SCULPT_OT_set_pivot_position);
+ WM_operatortype_append(SCULPT_OT_face_sets_create);
+ WM_operatortype_append(SCULPT_OT_face_sets_change_visibility);
+ WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors);
+ WM_operatortype_append(SCULPT_OT_face_sets_init);
+ WM_operatortype_append(SCULPT_OT_cloth_filter);
+ WM_operatortype_append(SCULPT_OT_face_sets_edit);
+ WM_operatortype_append(SCULPT_OT_face_set_lasso_gesture);
+ WM_operatortype_append(SCULPT_OT_face_set_box_gesture);
+ WM_operatortype_append(SCULPT_OT_trim_box_gesture);
+ WM_operatortype_append(SCULPT_OT_trim_lasso_gesture);
+ WM_operatortype_append(SCULPT_OT_project_line_gesture);
+
+ WM_operatortype_append(SCULPT_OT_sample_color);
+ WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors);
+ WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors);
+ WM_operatortype_append(SCULPT_OT_color_filter);
+ WM_operatortype_append(SCULPT_OT_mask_by_color);
+ WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit);
+ WM_operatortype_append(SCULPT_OT_mask_init);
+
+ WM_operatortype_append(SCULPT_OT_expand);
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index 587ce346428..3b939279bf9 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -540,13 +540,6 @@ static bool pose_face_sets_floodfill_cb(
/* Public functions. */
-/**
- * Calculate the pose origin and (Optionally the pose factor)
- * that is used when using the pose brush.
- *
- * \param r_pose_origin: Must be a valid pointer.
- * \param r_pose_factor: Optional, when set to NULL it won't be calculated.
- */
void SCULPT_pose_calc_pose_data(Sculpt *sd,
Object *ob,
SculptSession *ss,
@@ -1132,7 +1125,6 @@ static void sculpt_pose_align_pivot_local_space(float r_mat[4][4],
ortho_basis_v3v3_v3(r_mat[0], r_mat[1], r_mat[2]);
}
-/* Main Brush Function. */
void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index 1bfe8e1cbf1..c65489548b7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -102,8 +102,6 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3],
mul_v3_v3fl(result, avg, 1.0f / total);
}
-/* For bmesh: Average surrounding verts based on an orthogonality measure.
- * Naturally converges to a quad-like structure. */
void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v)
{
@@ -540,13 +538,6 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
-
- if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
- BLI_assert(ss->cache->surface_smooth_laplacian_disp == NULL);
- ss->cache->surface_smooth_laplacian_disp = MEM_callocN(
- sizeof(float[3]) * SCULPT_vertex_count_get(ss), "HC smooth laplacian b");
- }
/* Threaded loop over nodes. */
SculptThreadedTaskData data = {
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
index 3c0a591e8a7..b91e05f226e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_transform.c
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -70,10 +70,6 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob)
copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot);
copy_v3_v3(ss->init_pivot_scale, ss->pivot_scale);
- copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos);
- copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot);
- copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale);
-
SCULPT_undo_push_begin(ob, "Transform");
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
@@ -81,13 +77,10 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob)
SCULPT_vertex_random_access_ensure(ss);
SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS);
-
- ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL;
}
static void sculpt_transform_matrices_init(SculptSession *ss,
const char symm,
- const SculptTransformDisplacementMode t_mode,
float r_transform_mats[8][4][4])
{
@@ -96,18 +89,9 @@ static void sculpt_transform_matrices_init(SculptSession *ss,
transform_mat[4][4];
float start_pivot_pos[3], start_pivot_rot[4], start_pivot_scale[3];
- switch (t_mode) {
- case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL:
- copy_v3_v3(start_pivot_pos, ss->init_pivot_pos);
- copy_v4_v4(start_pivot_rot, ss->init_pivot_rot);
- copy_v3_v3(start_pivot_scale, ss->init_pivot_scale);
- break;
- case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL:
- copy_v3_v3(start_pivot_pos, ss->prev_pivot_pos);
- copy_v4_v4(start_pivot_rot, ss->prev_pivot_rot);
- copy_v3_v3(start_pivot_scale, ss->prev_pivot_scale);
- break;
- }
+ copy_v3_v3(start_pivot_pos, ss->init_pivot_pos);
+ copy_v4_v4(start_pivot_rot, ss->init_pivot_rot);
+ copy_v3_v3(start_pivot_scale, ss->init_pivot_scale);
for (int i = 0; i < PAINT_SYMM_AREAS; i++) {
ePaintSymmetryAreas v_symm = i;
@@ -167,25 +151,15 @@ static void sculpt_transform_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
float transformed_co[3], orig_co[3], disp[3];
- float *start_co;
float fade = vd.mask ? *vd.mask : 0.0f;
copy_v3_v3(orig_co, orig_data.co);
char symm_area = SCULPT_get_vertex_symm_area(orig_co);
- switch (ss->filter_cache->transform_displacement_mode) {
- case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL:
- start_co = orig_co;
- break;
- case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL:
- start_co = vd.co;
- break;
- }
-
- copy_v3_v3(transformed_co, start_co);
+ copy_v3_v3(transformed_co, orig_co);
mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co);
- sub_v3_v3v3(disp, transformed_co, start_co);
+ sub_v3_v3v3(disp, transformed_co, orig_co);
mul_v3_fl(disp, 1.0f - fade);
- add_v3_v3v3(vd.co, start_co, disp);
+ add_v3_v3v3(vd.co, orig_co, disp);
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
@@ -207,8 +181,7 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob)
.nodes = ss->filter_cache->nodes,
};
- sculpt_transform_matrices_init(
- ss, symm, ss->filter_cache->transform_displacement_mode, data.transform_mats);
+ sculpt_transform_matrices_init(ss, symm, data.transform_mats);
/* Regular transform applies all symmetry passes at once as it is split by symmetry areas
* (each vertex can only be transformed once by the transform matrix of its area). */
@@ -229,10 +202,6 @@ void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob)
sculpt_transform_all_vertices(sd, ob);
- copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos);
- copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot);
- copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale);
-
if (ss->deform_modifiers_active || ss->shapekey_active) {
SCULPT_flush_stroke_deform(sd, ob, true);
}
@@ -311,7 +280,7 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
else if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) {
copy_v3_v3(ss->pivot_pos, SCULPT_active_vertex_co_get(ss));
}
- /* Pivot to raycast surface. */
+ /* Pivot to ray-cast surface. */
else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
float stroke_location[3];
float mouse[2];
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 501a1e53276..8819496c168 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -1107,10 +1107,10 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) {
copy_v3_v3(unode->co[vd.i], vd.co);
if (vd.no) {
- copy_v3_v3_short(unode->no[vd.i], vd.no);
+ copy_v3_v3(unode->no[vd.i], vd.no);
}
else {
- normal_float_to_short_v3(unode->no[vd.i], vd.fno);
+ copy_v3_v3(unode->no[vd.i], vd.fno);
}
if (ss->deform_modifiers_active) {
@@ -1598,7 +1598,6 @@ void ED_sculpt_undo_geometry_end(struct Object *ob)
SCULPT_undo_push_end();
}
-/* Export for ED_undo_sys. */
void ED_sculpt_undosys_type(UndoType *ut)
{
ut->name = "Sculpt";
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index a4fd2d81778..daa973edfbf 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -70,8 +70,7 @@
/* ************************************************************************** */
/* ACTION CREATION */
-/* Helper function to find the active AnimData block from the Action Editor context */
-AnimData *ED_actedit_animdata_from_context(bContext *C, ID **r_adt_id_owner)
+AnimData *ED_actedit_animdata_from_context(const bContext *C, ID **r_adt_id_owner)
{
SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
Object *ob = CTX_data_active_object(C);
@@ -702,6 +701,9 @@ void ACTION_OT_unlink(wmOperatorType *ot)
"Clear Fake User and remove "
"copy stashed in this data-block's NLA stack");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ************************************************************************** */
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 6f1a90e56a5..0ed55ca5191 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -63,7 +63,6 @@
/* ************************************************************************* */
/* Channel List */
-/* left hand part */
void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region)
{
ListBase anim_data = {NULL, NULL};
@@ -131,7 +130,54 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region)
/* extra padding for lengths (to go under scrollers) */
#define EXTRA_SCROLL_PAD 100.0f
-/* draw keyframes in each channel */
+/* Draw manually set intended playback frame ranges for actions. */
+static void draw_channel_action_ranges(bAnimContext *ac, ListBase *anim_data, View2D *v2d)
+{
+ /* Variables for coalescing the Y region of one action. */
+ bAction *cur_action = NULL;
+ AnimData *cur_adt = NULL;
+ float cur_ymax;
+
+ /* Walk through channels, grouping contiguous spans referencing the same action. */
+ float ymax = ACHANNEL_FIRST_TOP(ac) + ACHANNEL_SKIP / 2;
+ float ystep = ACHANNEL_STEP(ac);
+ float ymin = ymax - ystep;
+
+ for (bAnimListElem *ale = anim_data->first; ale; ale = ale->next, ymax = ymin, ymin -= ystep) {
+ bAction *action = NULL;
+ AnimData *adt = NULL;
+
+ /* check if visible */
+ if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
+ IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) {
+ /* check if anything to show for this channel */
+ if (ale->datatype != ALE_NONE) {
+ action = ANIM_channel_action_get(ale);
+
+ if (action) {
+ adt = ale->adt;
+ }
+ }
+ }
+
+ /* Extend the current region, or flush and restart. */
+ if (action != cur_action || adt != cur_adt) {
+ if (cur_action) {
+ ANIM_draw_action_framerange(cur_adt, cur_action, v2d, ymax, cur_ymax);
+ }
+
+ cur_action = action;
+ cur_adt = adt;
+ cur_ymax = ymax;
+ }
+ }
+
+ /* Flush the last region. */
+ if (cur_action) {
+ ANIM_draw_action_framerange(cur_adt, cur_action, v2d, ymax, cur_ymax);
+ }
+}
+
void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region)
{
ListBase anim_data = {NULL, NULL};
@@ -166,6 +212,13 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region
int height = ACHANNEL_TOT_HEIGHT(ac, items);
v2d->tot.ymin = -height;
+ /* Draw the manual frame ranges for actions in the background of the dopesheet.
+ * The action editor has already drawn the range for its action so it's not needed. */
+ if (ac->datatype == ANIMCONT_DOPESHEET) {
+ draw_channel_action_ranges(ac, &anim_data, v2d);
+ }
+
+ /* Draw the background strips. */
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 3e38be243c9..184d715a347 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -276,7 +276,7 @@ static int actkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
scene = ac.scene;
/* set the range directly */
- get_keyframe_extents(&ac, &min, &max, false);
+ get_keyframe_extents(&ac, &min, &max, true);
scene->r.flag |= SCER_PRV_RANGE;
scene->r.psfra = floorf(min);
scene->r.pefra = ceilf(max);
@@ -295,7 +295,7 @@ static int actkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
void ACTION_OT_previewrange_set(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Auto-Set Preview Range";
+ ot->name = "Set Preview Range to Selected";
ot->idname = "ACTION_OT_previewrange_set";
ot->description = "Set Preview Range based on extents of selected Keyframes";
@@ -642,6 +642,10 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
}
}
+ /* Grease Pencil needs extra update to refresh the added keyframes. */
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ }
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h
index ffe0606c98f..581356a89d0 100644
--- a/source/blender/editors/space_action/action_intern.h
+++ b/source/blender/editors/space_action/action_intern.h
@@ -41,7 +41,14 @@ void action_buttons_register(struct ARegionType *art);
/* ***************************************** */
/* action_draw.c */
+
+/**
+ * Left hand part.
+ */
void draw_channel_names(struct bContext *C, struct bAnimContext *ac, struct ARegion *region);
+/**
+ * Draw keyframes in each channel.
+ */
void draw_channel_strips(struct bAnimContext *ac,
struct SpaceAction *saction,
struct ARegion *region);
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 738eeb21e2e..ba96ac52f1f 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -25,6 +25,7 @@
#include <string.h>
#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
#include "DNA_collection_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -35,6 +36,8 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_lib_remap.h"
+#include "BKE_nla.h"
#include "BKE_screen.h"
#include "RNA_access.h"
@@ -204,6 +207,13 @@ static void action_main_region_draw(const bContext *C, ARegion *region)
/* start and end frame */
ANIM_draw_framerange(scene, v2d);
+ /* Draw the manually set intended playback frame range highlight in the Action editor. */
+ if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) && saction->action) {
+ AnimData *adt = ED_actedit_animdata_from_context(C, NULL);
+
+ ANIM_draw_action_framerange(adt, saction->action, v2d, -FLT_MAX, FLT_MAX);
+ }
+
/* data */
if (ANIM_animdata_get_context(C, &ac)) {
draw_channel_strips(&ac, saction, region);
@@ -805,20 +815,15 @@ static void action_refresh(const bContext *C, ScrArea *area)
/* XXX re-sizing y-extents of tot should go here? */
}
-static void action_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void action_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceAction *sact = (SpaceAction *)slink;
- if ((ID *)sact->action == old_id) {
- sact->action = (bAction *)new_id;
- }
-
- if ((ID *)sact->ads.filter_grp == old_id) {
- sact->ads.filter_grp = (Collection *)new_id;
- }
- if ((ID *)sact->ads.source == old_id) {
- sact->ads.source = new_id;
- }
+ BKE_id_remapper_apply(mappings, (ID **)&sact->action, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, (ID **)&sact->ads.filter_grp, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, &sact->ads.source, ID_REMAP_APPLY_DEFAULT);
}
/**
@@ -853,7 +858,6 @@ static void action_space_subtype_item_extend(bContext *UNUSED(C),
RNA_enum_items_add(item, totitem, rna_enum_space_action_mode_items);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_action(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype action");
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index b3b3eafb6e7..f8adba30547 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -70,10 +70,9 @@
#include "io_ops.h"
-/* Only called once on startup. storage is global in BKE kernel listbase. */
void ED_spacetypes_init(void)
{
- /* UI unit is a variable, may be used in some space type inits. */
+ /* UI unit is a variable, may be used in some space type initialization. */
U.widget_unit = 20;
/* Create space types. */
@@ -177,6 +176,7 @@ void ED_spacemacros_init(void)
ED_operatormacros_gpencil();
/* Register dropboxes (can use macros). */
+ ED_dropboxes_ui();
const ListBase *spacetypes = BKE_spacetypes_list();
LISTBASE_FOREACH (const SpaceType *, type, spacetypes) {
if (type->dropboxes) {
@@ -185,10 +185,6 @@ void ED_spacemacros_init(void)
}
}
-/**
- * \note Keymap definitions are registered only once per WM initialize,
- * usually on file read, using the keymap the actual areas/regions add the handlers.
- * \note Called in wm.c. */
void ED_spacetypes_keymap(wmKeyConfig *keyconf)
{
ED_keymap_screen(keyconf);
@@ -252,20 +248,21 @@ void *ED_region_draw_cb_activate(ARegionType *art,
return rdc;
}
-void ED_region_draw_cb_exit(ARegionType *art, void *handle)
+bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
{
LISTBASE_FOREACH (RegionDrawCB *, rdc, &art->drawcalls) {
if (rdc == (RegionDrawCB *)handle) {
BLI_remlink(&art->drawcalls, rdc);
MEM_freeN(rdc);
- return;
+ return true;
}
}
+ return false;
}
-void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
+static void ed_region_draw_cb_draw(const bContext *C, ARegion *region, ARegionType *art, int type)
{
- LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, &region->type->drawcalls) {
+ LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, &art->drawcalls) {
if (rdc->type == type) {
rdc->draw(C, region, rdc->customdata);
@@ -275,6 +272,16 @@ void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
}
}
+void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
+{
+ ed_region_draw_cb_draw(C, region, region->type, type);
+}
+
+void ED_region_surface_draw_cb_draw(ARegionType *art, int type)
+{
+ ed_region_draw_cb_draw(NULL, NULL, art, type);
+}
+
void ED_region_draw_cb_remove_by_type(ARegionType *art, void *draw_fn, void (*free)(void *))
{
LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, &art->drawcalls) {
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 91b0677ebaa..f5107cb13fd 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -242,55 +242,55 @@ static bool buttons_context_path_data(ButsContextPath *path, int type)
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)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_Mesh) && (ELEM(type, -1, OB_MESH))) {
return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_Curve) &&
(type == -1 || ELEM(type, OB_CURVE, OB_SURF, OB_FONT))) {
return true;
}
- if (RNA_struct_is_a(ptr->type, &RNA_Armature) && (type == -1 || type == OB_ARMATURE)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_Armature) && (ELEM(type, -1, OB_ARMATURE))) {
return true;
}
- if (RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (type == -1 || type == OB_MBALL)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (ELEM(type, -1, OB_MBALL))) {
return true;
}
- if (RNA_struct_is_a(ptr->type, &RNA_Lattice) && (type == -1 || type == OB_LATTICE)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_Lattice) && (ELEM(type, -1, OB_LATTICE))) {
return true;
}
- if (RNA_struct_is_a(ptr->type, &RNA_Camera) && (type == -1 || type == OB_CAMERA)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_Camera) && (ELEM(type, -1, OB_CAMERA))) {
return true;
}
- if (RNA_struct_is_a(ptr->type, &RNA_Light) && (type == -1 || type == OB_LAMP)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_Light) && (ELEM(type, -1, OB_LAMP))) {
return true;
}
- if (RNA_struct_is_a(ptr->type, &RNA_Speaker) && (type == -1 || type == OB_SPEAKER)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_Speaker) && (ELEM(type, -1, OB_SPEAKER))) {
return true;
}
- if (RNA_struct_is_a(ptr->type, &RNA_LightProbe) && (type == -1 || type == OB_LIGHTPROBE)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_LightProbe) && (ELEM(type, -1, OB_LIGHTPROBE))) {
return true;
}
- if (RNA_struct_is_a(ptr->type, &RNA_GreasePencil) && (type == -1 || type == OB_GPENCIL)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_GreasePencil) && (ELEM(type, -1, OB_GPENCIL))) {
return true;
}
#ifdef WITH_HAIR_NODES
- if (RNA_struct_is_a(ptr->type, &RNA_Hair) && (type == -1 || type == OB_HAIR)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_Hair) && (ELEM(type, -1, OB_HAIR))) {
return true;
}
#endif
#ifdef WITH_POINT_CLOUD
- if (RNA_struct_is_a(ptr->type, &RNA_PointCloud) && (type == -1 || type == OB_POINTCLOUD)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_PointCloud) && (ELEM(type, -1, OB_POINTCLOUD))) {
return true;
}
#endif
- if (RNA_struct_is_a(ptr->type, &RNA_Volume) && (type == -1 || type == OB_VOLUME)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_Volume) && (ELEM(type, -1, OB_VOLUME))) {
return true;
}
/* try to get an object in the path, no pinning supported here */
if (buttons_context_path_object(path)) {
Object *ob = path->ptr[path->len - 1].data;
- if (ob && (type == -1 || type == ob->type)) {
+ if (ob && (ELEM(type, -1, ob->type))) {
RNA_id_pointer_create(ob->data, &path->ptr[path->len]);
path->len++;
@@ -1225,7 +1225,7 @@ static void buttons_panel_context_draw(const bContext *C, Panel *panel)
/* Add > triangle. */
if (!first) {
- uiItemL(row, "", ICON_SMALL_TRI_RIGHT_VEC);
+ uiItemL(row, "", ICON_RIGHTARROW);
}
if (ptr->data == NULL) {
diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h
index 9cb363ff0c9..5eddea2cc40 100644
--- a/source/blender/editors/space_buttons/buttons_intern.h
+++ b/source/blender/editors/space_buttons/buttons_intern.h
@@ -88,6 +88,7 @@ typedef struct ButsContextTexture {
/* internal exports only */
/* buttons_context.c */
+
void buttons_context_compute(const struct bContext *C, struct SpaceProperties *sbuts);
int buttons_context(const struct bContext *C,
const char *member,
@@ -98,12 +99,17 @@ struct ID *buttons_context_id_path(const struct bContext *C);
extern const char *buttons_context_dir[]; /* doc access */
/* buttons_texture.c */
+
void buttons_texture_context_compute(const struct bContext *C, struct SpaceProperties *sbuts);
/* buttons_ops.c */
+
void BUTTONS_OT_start_filter(struct wmOperatorType *ot);
void BUTTONS_OT_clear_filter(struct wmOperatorType *ot);
void BUTTONS_OT_toggle_pin(struct wmOperatorType *ot);
void BUTTONS_OT_file_browse(struct wmOperatorType *ot);
+/**
+ * Second operator, only difference from #BUTTONS_OT_file_browse is #WM_FILESEL_DIRECTORY.
+ */
void BUTTONS_OT_directory_browse(struct wmOperatorType *ot);
void BUTTONS_OT_context_menu(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index 798f4898aaa..46d6df7c69c 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -383,7 +383,6 @@ void BUTTONS_OT_file_browse(wmOperatorType *ot)
FILE_SORT_DEFAULT);
}
-/* Second operator, only difference from BUTTONS_OT_file_browse is WM_FILESEL_DIRECTORY. */
void BUTTONS_OT_directory_browse(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index f1debcef5a9..5dd7c3d240e 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -155,10 +155,10 @@ static void buttons_texture_users_find_nodetree(ListBase *users,
for (node = ntree->nodes.first; node; node = node->next) {
if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
PointerRNA ptr;
- /* PropertyRNA *prop; */ /* UNUSED */
+ // PropertyRNA *prop; /* UNUSED */
RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
- /* prop = RNA_struct_find_property(&ptr, "texture"); */ /* UNUSED */
+ // prop = RNA_struct_find_property(&ptr, "texture"); /* UNUSED */
buttons_texture_user_node_add(
users, id, ntree, node, category, RNA_struct_ui_icon(ptr.type), node->name);
@@ -667,7 +667,6 @@ static void template_texture_show(bContext *C, void *data_p, void *prop_p)
}
}
-/* Button to quickly show texture in Properties Editor texture tab. */
void uiTemplateTextureShow(uiLayout *layout, const bContext *C, PointerRNA *ptr, PropertyRNA *prop)
{
/* Only show the button if there is actually a texture assigned. */
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index b04291b7ab4..cf1e7788ff8 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -32,6 +32,7 @@
#include "BKE_context.h"
#include "BKE_gpencil_modifier.h" /* Types for registering panels. */
+#include "BKE_lib_remap.h"
#include "BKE_modifier.h"
#include "BKE_screen.h"
#include "BKE_shader_fx.h"
@@ -166,11 +167,6 @@ static void buttons_main_region_init(wmWindowManager *wm, ARegion *region)
/** \name Property Editor Layout
* \{ */
-/**
- * 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, short *context_tabs_array)
{
int length = 0;
@@ -445,7 +441,7 @@ static void property_search_all_tabs(const bContext *C,
i,
property_search_for_context(C, region_copy, &sbuts_copy));
- UI_blocklist_free(C, &region_copy->uiblocks);
+ UI_blocklist_free(C, region_copy);
}
BKE_area_region_free(area_copy.type, region_copy);
@@ -865,54 +861,53 @@ static void buttons_area_listener(const wmSpaceTypeListenerParams *params)
}
}
-static void buttons_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void buttons_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceProperties *sbuts = (SpaceProperties *)slink;
- if (sbuts->pinid == old_id) {
- sbuts->pinid = new_id;
- if (new_id == NULL) {
- sbuts->flag &= ~SB_PIN_CONTEXT;
- }
+ if (BKE_id_remapper_apply(mappings, &sbuts->pinid, ID_REMAP_APPLY_DEFAULT) ==
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
+ sbuts->flag &= ~SB_PIN_CONTEXT;
}
if (sbuts->path) {
ButsContextPath *path = sbuts->path;
+ for (int i = 0; i < path->len; i++) {
+ switch (BKE_id_remapper_apply(mappings, &path->ptr[i].owner_id, ID_REMAP_APPLY_DEFAULT)) {
+ case ID_REMAP_RESULT_SOURCE_UNASSIGNED: {
+ if (i == 0) {
+ MEM_SAFE_FREE(sbuts->path);
+ }
+ else {
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ }
+ break;
+ }
+ case ID_REMAP_RESULT_SOURCE_REMAPPED: {
+ RNA_id_pointer_create(path->ptr[i].owner_id, &path->ptr[i]);
+ /* There is no easy way to check/make path downwards valid, just nullify it.
+ * Next redraw will rebuild this anyway. */
+ i++;
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ break;
+ }
- int i;
- for (i = 0; i < path->len; i++) {
- if (path->ptr[i].owner_id == old_id) {
- break;
- }
- }
-
- if (i == path->len) {
- /* pass */
- }
- else if (new_id == NULL) {
- if (i == 0) {
- MEM_SAFE_FREE(sbuts->path);
- }
- else {
- memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
- path->len = i;
+ case ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE:
+ case ID_REMAP_RESULT_SOURCE_UNAVAILABLE: {
+ /* Nothing to do. */
+ break;
+ }
}
}
- else {
- RNA_id_pointer_create(new_id, &path->ptr[i]);
- /* There is no easy way to check/make path downwards valid, just nullify it.
- * Next redraw will rebuild this anyway. */
- i++;
- memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
- path->len = i;
- }
}
if (sbuts->texuser) {
ButsContextTexture *ct = sbuts->texuser;
- if ((ID *)ct->texture == old_id) {
- ct->texture = (Tex *)new_id;
- }
+ BKE_id_remapper_apply(mappings, (ID **)&ct->texture, ID_REMAP_APPLY_DEFAULT);
BLI_freelistN(&ct->users);
ct->user = NULL;
}
@@ -924,7 +919,6 @@ static void buttons_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id
/** \name Space Type Initialization
* \{ */
-/* only called once, from space/spacetypes.c */
void ED_spacetype_buttons(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype buttons");
diff --git a/source/blender/editors/space_clip/CMakeLists.txt b/source/blender/editors/space_clip/CMakeLists.txt
index 8c7f59d61dd..db881dafa6b 100644
--- a/source/blender/editors/space_clip/CMakeLists.txt
+++ b/source/blender/editors/space_clip/CMakeLists.txt
@@ -31,6 +31,9 @@ set(INC
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern
)
set(SRC
@@ -69,4 +72,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+
blender_add_lib(bf_editor_space_clip "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+# Needed so we can use dna_type_offsets.h for defaults initialization.
+add_dependencies(bf_editor_space_clip bf_dna)
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 471b4a4bf5b..68444cc0313 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -1219,10 +1219,11 @@ static void draw_plane_marker_image(Scene *scene,
uint texCoord = GPU_vertformat_attr_add(
imm_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
+ /* Use 3D image for correct display of planar tracked images. */
+ immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA);
immBindTexture("image", texture);
- immUniformColor4f(1.0f, 1.0f, 1.0f, plane_track->image_opacity);
+ immUniform1f("alpha", plane_track->image_opacity);
immBegin(GPU_PRIM_TRI_FAN, 4);
@@ -1980,7 +1981,6 @@ void clip_draw_cache_and_notes(const bContext *C, SpaceClip *sc, ARegion *region
}
}
-/* draw grease pencil */
void clip_draw_grease_pencil(bContext *C, int onlyv2d)
{
SpaceClip *sc = CTX_wm_space_clip(C);
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 834ef847069..d22e4864ecf 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_defaults.h"
#include "DNA_mask_types.h"
#include "BLI_fileops.h"
@@ -223,7 +224,6 @@ void ED_space_clip_get_aspect_dimension_aware(SpaceClip *sc, float *aspx, float
}
}
-/* return current frame number in clip space */
int ED_space_clip_get_clip_frame_number(SpaceClip *sc)
{
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -272,7 +272,7 @@ ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale
}
bool ED_space_clip_get_position(struct SpaceClip *sc,
- struct ARegion *ar,
+ struct ARegion *region,
int mval[2],
float fpos[2])
{
@@ -282,13 +282,12 @@ bool ED_space_clip_get_position(struct SpaceClip *sc,
}
/* map the mouse coords to the backdrop image space */
- ED_clip_mouse_pos(sc, ar, mval, fpos);
+ ED_clip_mouse_pos(sc, region, mval, fpos);
IMB_freeImBuf(ibuf);
return true;
}
-/* Returns color in linear space, matching ED_space_image_color_sample(). */
bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, int mval[2], float r_col[3])
{
ImBuf *ibuf;
@@ -511,10 +510,6 @@ void ED_clip_point_stable_pos(
}
}
-/**
- * \brief the reverse of #ED_clip_point_stable_pos(), gets the marker region coords.
- * better name here? view_to_track / track_to_view or so?
- */
void ED_clip_point_stable_pos__reverse(SpaceClip *sc,
ARegion *region,
const float co[2],
@@ -539,7 +534,6 @@ void ED_clip_point_stable_pos__reverse(SpaceClip *sc,
r_co[1] = (pos[1] * height * zoomy) + (float)sy;
}
-/* takes event->mval */
void ED_clip_mouse_pos(SpaceClip *sc, ARegion *region, const int mval[2], float co[2])
{
ED_clip_point_stable_pos(sc, region, mval[0], mval[1], &co[0], &co[1]);
@@ -653,7 +647,7 @@ void ED_space_clip_set_mask(bContext *C, SpaceClip *sc, Mask *mask)
* \{ */
typedef struct PrefetchJob {
- /* Clip into which cache the frames will be prefetched into. */
+ /** Clip into which cache the frames will be pre-fetched into. */
MovieClip *clip;
/* Local copy of the clip which is used to decouple reading in a way which does not require
@@ -693,7 +687,7 @@ static bool check_prefetch_break(void)
static uchar *prefetch_read_file_to_memory(
MovieClip *clip, int current_frame, short render_size, short render_flag, size_t *r_size)
{
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
user.framenr = current_frame;
user.render_size = render_size;
user.render_flag = render_flag;
@@ -740,7 +734,7 @@ static int prefetch_find_uncached_frame(MovieClip *clip,
short direction)
{
int current_frame;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
user.render_size = render_size;
user.render_flag = render_flag;
@@ -840,7 +834,7 @@ static void prefetch_task_func(TaskPool *__restrict pool, void *task_data)
while ((mem = prefetch_thread_next_frame(queue, clip, &size, &current_frame))) {
ImBuf *ibuf;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
int flag = IB_rect | IB_multilayer | IB_alphamode_detect | IB_metadata;
int result;
char *colorspace_name = NULL;
@@ -922,7 +916,7 @@ static bool prefetch_movie_frame(MovieClip *clip,
short render_flag,
short *stop)
{
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
if (check_prefetch_break() || *stop) {
return false;
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 202dc00e365..15f905f3157 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -50,25 +50,34 @@ struct wmOperatorType;
/* internal exports only */
/* clip_buttons.c */
+
void ED_clip_buttons_register(struct ARegionType *art);
/* clip_dopesheet_draw.c */
+
void clip_draw_dopesheet_main(struct SpaceClip *sc, struct ARegion *region, struct Scene *scene);
void clip_draw_dopesheet_channels(const struct bContext *C, struct ARegion *region);
/* clip_dopesheet_ops.c */
+
void CLIP_OT_dopesheet_select_channel(struct wmOperatorType *ot);
void CLIP_OT_dopesheet_view_all(struct wmOperatorType *ot);
/* clip_draw.c */
+
void clip_draw_main(const struct bContext *C, struct SpaceClip *sc, struct ARegion *region);
+
+/* draw grease pencil */
+
void clip_draw_grease_pencil(struct bContext *C, int onlyv2d);
void clip_draw_cache_and_notes(const bContext *C, SpaceClip *sc, ARegion *region);
/* clip_editor.c */
+
void clip_start_prefetch_job(const struct bContext *C);
/* clip_graph_draw.c */
+
void clip_draw_graph(struct SpaceClip *sc, struct ARegion *region, struct Scene *scene);
/* clip_graph_ops.c */
@@ -171,13 +180,20 @@ void clip_delete_plane_track(struct bContext *C,
struct MovieClip *clip,
struct MovieTrackingPlaneTrack *plane_track);
+/**
+ * Calculate space clip offset to be centered at the given point.
+ */
void clip_view_offset_for_center_to_point(
- SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y);
+ SpaceClip *sc, float x, float y, float *r_offset_x, float *r_offset_y);
void clip_view_center_to_point(SpaceClip *sc, float x, float y);
bool clip_view_calculate_view_selection(
const struct bContext *C, bool fit, float *r_offset_x, float *r_offset_y, float *r_zoom);
+/**
+ * Returns truth if lock-to-selection is enabled and possible.
+ * Locking to selection is not possible if there is no selection.
+ */
bool clip_view_has_locked_selection(const struct bContext *C);
void clip_draw_sfra_efra(struct View2D *v2d, struct Scene *scene);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index f5e4c4d55d9..03b6d8c7381 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -33,6 +33,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_defaults.h"
#include "DNA_scene_types.h" /* min/max frames */
#include "DNA_userdef_types.h"
@@ -209,7 +210,7 @@ static int open_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "directory", dir_only);
if (relative) {
- BLI_path_rel(dir_only, bmain->name);
+ BLI_path_rel(dir_only, bmain->filepath);
}
prop = RNA_struct_find_property(op->ptr, "files");
@@ -285,7 +286,7 @@ static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
if (clip) {
BLI_strncpy(path, clip->filepath, sizeof(path));
- BLI_path_abs(path, CTX_data_main(C)->name);
+ BLI_path_abs(path, CTX_data_main(C)->filepath);
BLI_path_parent_dir(path);
}
else {
@@ -393,8 +394,8 @@ static void view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
- vpd->x = event->x;
- vpd->y = event->y;
+ vpd->x = event->xy[0];
+ vpd->y = event->xy[1];
if (clip_view_has_locked_selection(C)) {
vpd->vec = &sc->xlockof;
@@ -454,8 +455,8 @@ static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
SpaceClip *sc = CTX_wm_space_clip(C);
float offset[2];
- offset[0] = (event->prevx - event->x) / sc->zoom;
- offset[1] = (event->prevy - event->y) / sc->zoom;
+ offset[0] = (event->prev_xy[0] - event->xy[0]) / sc->zoom;
+ offset[1] = (event->prev_xy[1] - event->xy[1]) / sc->zoom;
RNA_float_set_array(op->ptr, "offset", offset);
@@ -478,8 +479,8 @@ static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE:
copy_v2_v2(vpd->vec, &vpd->xorig);
- offset[0] = (vpd->x - event->x) / sc->zoom;
- offset[1] = (vpd->y - event->y) / sc->zoom;
+ offset[0] = (vpd->x - event->xy[0]) / sc->zoom;
+ offset[1] = (vpd->y - event->xy[1]) / sc->zoom;
RNA_float_set_array(op->ptr, "offset", offset);
view_pan_exec(C, op);
break;
@@ -575,8 +576,8 @@ static void view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
vpd->timer_lastdraw = PIL_check_seconds_timer();
}
- vpd->x = event->x;
- vpd->y = event->y;
+ vpd->x = event->xy[0];
+ vpd->y = event->xy[1];
vpd->zoom = sc->zoom;
vpd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
@@ -619,7 +620,7 @@ static int view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
float delta, factor;
- delta = event->prevx - event->x + event->prevy - event->y;
+ delta = event->prev_xy[0] - event->xy[0] + event->prev_xy[1] - event->xy[1];
if (U.uiflag & USER_ZOOM_INVERT) {
delta *= -1;
@@ -646,14 +647,14 @@ static void view_zoom_apply(
if (U.viewzoom != USER_ZOOM_SCALE) {
if (U.uiflag & USER_ZOOM_HORIZ) {
- delta = (float)(event->x - vpd->x);
+ delta = (float)(event->xy[0] - vpd->x);
}
else {
- delta = (float)(event->y - vpd->y);
+ delta = (float)(event->xy[1] - vpd->y);
}
}
else {
- delta = event->x - vpd->x + event->y - vpd->y;
+ delta = event->xy[0] - vpd->x + event->xy[1] - vpd->y;
}
delta /= U.pixelsize;
@@ -911,6 +912,7 @@ void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
-FLT_MAX,
FLT_MAX);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -988,6 +990,7 @@ void CLIP_OT_view_all(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1052,6 +1055,7 @@ void CLIP_OT_view_selected(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1172,6 +1176,7 @@ void CLIP_OT_change_frame(wmOperatorType *ot)
/* rna */
RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1317,7 +1322,7 @@ static uchar *proxy_thread_next_frame(ProxyQueue *queue,
BLI_spin_lock(&queue->spin);
if (!*queue->stop && queue->cfra <= queue->efra) {
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
char name[FILE_MAX];
size_t size;
int file;
@@ -1555,7 +1560,8 @@ static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
clip->proxy.build_size_flag,
clip->proxy.quality,
true,
- NULL);
+ NULL,
+ false);
}
WM_jobs_customdata_set(wm_job, pj, proxy_freejob);
@@ -1584,6 +1590,7 @@ void CLIP_OT_rebuild_proxy(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1623,10 +1630,10 @@ void CLIP_OT_mode_set(wmOperatorType *ot)
RNA_def_enum(ot->srna, "mode", rna_enum_clip_editor_mode_items, SC_MODE_TRACKING, "Mode", "");
}
-#ifdef WITH_INPUT_NDOF
-
/** \} */
+#ifdef WITH_INPUT_NDOF
+
/* -------------------------------------------------------------------- */
/** \name NDOF Operator
* \{ */
@@ -1725,6 +1732,7 @@ void CLIP_OT_prefetch(wmOperatorType *ot)
ot->invoke = clip_prefetch_invoke;
ot->modal = clip_prefetch_modal;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1764,6 +1772,7 @@ void CLIP_OT_set_scene_frames(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
ot->exec = clip_set_scene_frames_exec;
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 23dd290e13f..5f5a24a9407 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -398,7 +398,6 @@ void clip_delete_plane_track(bContext *C, MovieClip *clip, MovieTrackingPlaneTra
DEG_id_tag_update(&clip->id, 0);
}
-/* Calculate space clip offset to be centered at the given point. */
void clip_view_offset_for_center_to_point(
SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y)
{
@@ -608,8 +607,6 @@ bool clip_view_calculate_view_selection(
return true;
}
-/* Returns truth if lock-to-selection is enabled and possible.
- * Locking to selection is not possible if there is no selection. */
bool clip_view_has_locked_selection(const bContext *C)
{
SpaceClip *space_clip = CTX_wm_space_clip(C);
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index e2fbb4a5a59..da1d2dea653 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -24,6 +24,8 @@
#include <stdio.h>
#include <string.h>
+#include "DNA_defaults.h"
+
#include "DNA_mask_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_scene_types.h"
@@ -37,6 +39,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_movieclip.h"
#include "BKE_screen.h"
#include "BKE_tracking.h"
@@ -239,14 +242,7 @@ static SpaceLink *clip_create(const ScrArea *area, const Scene *scene)
ARegion *region;
SpaceClip *sc;
- sc = MEM_callocN(sizeof(SpaceClip), "initclip");
- sc->spacetype = SPACE_CLIP;
- sc->flag = SC_SHOW_MARKER_PATTERN | SC_SHOW_TRACK_PATH | SC_SHOW_GRAPH_TRACKS_MOTION |
- SC_SHOW_GRAPH_FRAMES | SC_SHOW_ANNOTATION;
- sc->zoom = 1.0f;
- sc->path_length = 20;
- sc->scopes.track_preview_height = 120;
- sc->around = V3D_AROUND_CENTER_MEDIAN;
+ sc = DNA_struct_default_alloc(SpaceClip);
/* header */
region = MEM_callocN(sizeof(ARegion), "header for clip");
@@ -1079,6 +1075,9 @@ static void graph_region_draw(const bContext *C, ARegion *region)
/* time-scrubbing */
ED_time_scrub_draw(region, scene, sc->flag & SC_SHOW_SECONDS, true);
+ /* current frame indicator */
+ ED_time_scrub_draw_current_frame(region, scene, sc->flag & SC_SHOW_SECONDS);
+
/* scrollers */
UI_view2d_scrollers_draw(v2d, NULL);
@@ -1126,6 +1125,9 @@ static void dopesheet_region_draw(const bContext *C, ARegion *region)
/* time-scrubbing */
ED_time_scrub_draw(region, scene, sc->flag & SC_SHOW_SECONDS, true);
+ /* current frame indicator */
+ ED_time_scrub_draw_current_frame(region, scene, sc->flag & SC_SHOW_SECONDS);
+
/* scrollers */
UI_view2d_scrollers_draw(v2d, NULL);
}
@@ -1316,26 +1318,20 @@ static void clip_properties_region_listener(const wmRegionListenerParams *params
/********************* registration ********************/
-static void clip_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void clip_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceClip *sclip = (SpaceClip *)slink;
- if (!ELEM(GS(old_id->name), ID_MC, ID_MSK)) {
+ if (!BKE_id_remapper_has_mapping_for(mappings, FILTER_ID_MC | FILTER_ID_MSK)) {
return;
}
- if ((ID *)sclip->clip == old_id) {
- sclip->clip = (MovieClip *)new_id;
- id_us_ensure_real(new_id);
- }
-
- if ((ID *)sclip->mask_info.mask == old_id) {
- sclip->mask_info.mask = (Mask *)new_id;
- id_us_ensure_real(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&sclip->clip, ID_REMAP_APPLY_ENSURE_REAL);
+ BKE_id_remapper_apply(mappings, (ID **)&sclip->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_clip(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype clip");
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index ff62bcf0cfa..ee0406cde30 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -181,8 +181,8 @@ static int add_marker_at_click_modal(bContext *C, wmOperator *UNUSED(op), const
ED_clip_point_stable_pos(sc,
region,
- event->x - region->winrct.xmin,
- event->y - region->winrct.ymin,
+ event->xy[0] - region->winrct.xmin,
+ event->xy[1] - region->winrct.ymin,
&pos[0],
&pos[1]);
@@ -417,7 +417,7 @@ static SlideMarkerData *create_slide_marker_data(SpaceClip *sc,
data->pos = marker->pos;
data->offset = track->offset;
data->old_markers = MEM_callocN(sizeof(*data->old_markers) * track->markersnr,
- "slide marekrs");
+ "slide markers");
for (int a = 0; a < track->markersnr; a++) {
copy_v2_v2(data->old_markers[a], track->markers[a].pos);
}
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index 47d15efb6ca..e66c3898d04 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -149,7 +149,7 @@ static void console_cursor(wmWindow *win, ScrArea *UNUSED(area), ARegion *region
{
int wmcursor = WM_CURSOR_TEXT_EDIT;
const wmEvent *event = win->eventstate;
- if (UI_view2d_mouse_in_scrollers(region, &region->v2d, event->x, event->y)) {
+ if (UI_view2d_mouse_in_scrollers(region, &region->v2d, event->xy)) {
wmcursor = WM_CURSOR_DEFAULT;
}
@@ -293,7 +293,6 @@ static void console_main_region_listener(const wmRegionListenerParams *params)
}
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_console(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype console");
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index b60f9df82f6..cbeb2e6f529 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -16,6 +16,7 @@
# ***** END GPL LICENSE BLOCK *****
set(INC
+ ../asset
../include
../../blenfont
../../blenkernel
@@ -34,7 +35,9 @@ set(INC
)
set(SRC
+ asset_catalog_tree_view.cc
file_draw.c
+ file_indexer.cc
file_ops.c
file_panels.c
file_utils.c
@@ -43,6 +46,7 @@ set(SRC
fsmenu.c
space_file.c
+ file_indexer.h
file_intern.h
filelist.h
fsmenu.h
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc
new file mode 100644
index 00000000000..4107669630f
--- /dev/null
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -0,0 +1,773 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup spfile
+ */
+
+#include "DNA_space_types.h"
+
+#include "BKE_asset.h"
+#include "BKE_asset_catalog.hh"
+#include "BKE_asset_library.hh"
+
+#include "BLI_string_ref.hh"
+
+#include "BLT_translation.h"
+
+#include "ED_asset.h"
+#include "ED_fileselect.h"
+#include "ED_undo.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_interface.hh"
+#include "UI_resources.h"
+#include "UI_tree_view.hh"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "file_intern.h"
+#include "filelist.h"
+
+using namespace blender;
+using namespace blender::bke;
+
+namespace blender::ed::asset_browser {
+
+class AssetCatalogTreeViewAllItem;
+
+class AssetCatalogTreeView : public ui::AbstractTreeView {
+ ::AssetLibrary *asset_library_;
+ /** The asset catalog tree this tree-view represents. */
+ bke::AssetCatalogTree *catalog_tree_;
+ FileAssetSelectParams *params_;
+ SpaceFile &space_file_;
+
+ friend class AssetCatalogTreeViewItem;
+ friend class AssetCatalogDropController;
+ friend class AssetCatalogTreeViewAllItem;
+
+ public:
+ AssetCatalogTreeView(::AssetLibrary *library,
+ FileAssetSelectParams *params,
+ SpaceFile &space_file);
+
+ void build_tree() override;
+
+ void activate_catalog_by_id(CatalogID catalog_id);
+
+ private:
+ ui::BasicTreeViewItem &build_catalog_items_recursive(ui::TreeViewOrItem &view_parent_item,
+ AssetCatalogTreeItem &catalog);
+
+ AssetCatalogTreeViewAllItem &add_all_item();
+ void add_unassigned_item();
+ bool is_active_catalog(CatalogID catalog_id) const;
+};
+
+/* ---------------------------------------------------------------------- */
+
+class AssetCatalogTreeViewItem : public ui::BasicTreeViewItem {
+ /** The catalog tree item this tree view item represents. */
+ AssetCatalogTreeItem &catalog_item_;
+
+ public:
+ AssetCatalogTreeViewItem(AssetCatalogTreeItem *catalog_item);
+
+ void on_activate() override;
+
+ void build_row(uiLayout &row) override;
+ void build_context_menu(bContext &C, uiLayout &column) const override;
+
+ bool supports_renaming() const override;
+ bool rename(StringRefNull new_name) override;
+
+ /** Add drag support for catalog items. */
+ std::unique_ptr<ui::AbstractTreeViewItemDragController> create_drag_controller() const override;
+ /** Add dropping support for catalog items. */
+ std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
+};
+
+class AssetCatalogDragController : public ui::AbstractTreeViewItemDragController {
+ AssetCatalogTreeItem &catalog_item_;
+
+ public:
+ explicit AssetCatalogDragController(AssetCatalogTreeView &tree_view,
+ AssetCatalogTreeItem &catalog_item);
+
+ int get_drag_type() const override;
+ void *create_drag_data() const override;
+ void on_drag_start() override;
+};
+
+class AssetCatalogDropController : public ui::AbstractTreeViewItemDropController {
+ AssetCatalogTreeItem &catalog_item_;
+
+ public:
+ AssetCatalogDropController(AssetCatalogTreeView &tree_view, AssetCatalogTreeItem &catalog_item);
+
+ bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
+ std::string drop_tooltip(const wmDrag &drag) const override;
+ bool on_drop(struct bContext *C, const wmDrag &drag) override;
+
+ ::AssetLibrary &get_asset_library() const;
+
+ static AssetCatalog *get_drag_catalog(const wmDrag &drag, const ::AssetLibrary &asset_library);
+ static bool has_droppable_asset(const wmDrag &drag, const char **r_disabled_hint);
+ static bool drop_assets_into_catalog(struct bContext *C,
+ const AssetCatalogTreeView &tree_view,
+ const wmDrag &drag,
+ CatalogID catalog_id,
+ StringRefNull simple_name = "");
+ /**
+ * \param drop_catalog_id: Can be unset to drop into the root level of the tree.
+ */
+ static bool drop_asset_catalog_into_catalog(
+ const wmDrag &drag,
+ AssetCatalogTreeView &tree_view,
+ const std::optional<CatalogID> drop_catalog_id = std::nullopt);
+
+ private:
+ std::string drop_tooltip_asset_list(const wmDrag &drag) const;
+ std::string drop_tooltip_asset_catalog(const wmDrag &drag) const;
+};
+
+/** Only reason this isn't just `BasicTreeViewItem` is to add a '+' icon for adding a root level
+ * catalog. */
+class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
+ using BasicTreeViewItem::BasicTreeViewItem;
+
+ void build_row(uiLayout &row) override;
+
+ struct DropController : public ui::AbstractTreeViewItemDropController {
+ DropController(AssetCatalogTreeView &tree_view);
+
+ bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
+ std::string drop_tooltip(const wmDrag &drag) const override;
+ bool on_drop(struct bContext *C, const wmDrag &drag) override;
+ };
+
+ std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
+};
+
+class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
+ using BasicTreeViewItem::BasicTreeViewItem;
+
+ struct DropController : public ui::AbstractTreeViewItemDropController {
+ DropController(AssetCatalogTreeView &tree_view);
+
+ bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
+ std::string drop_tooltip(const wmDrag &drag) const override;
+ bool on_drop(struct bContext *C, const wmDrag &drag) override;
+ };
+
+ std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
+};
+
+/* ---------------------------------------------------------------------- */
+
+AssetCatalogTreeView::AssetCatalogTreeView(::AssetLibrary *library,
+ FileAssetSelectParams *params,
+ SpaceFile &space_file)
+ : asset_library_(library),
+ catalog_tree_(BKE_asset_library_get_catalog_tree(library)),
+ params_(params),
+ space_file_(space_file)
+{
+}
+
+void AssetCatalogTreeView::build_tree()
+{
+ AssetCatalogTreeViewAllItem &all_item = add_all_item();
+ all_item.set_collapsed(false);
+
+ if (catalog_tree_) {
+ /* Pass the "All" item on as parent of the actual catalog items. */
+ catalog_tree_->foreach_root_item([this, &all_item](AssetCatalogTreeItem &item) {
+ build_catalog_items_recursive(all_item, item);
+ });
+ }
+
+ add_unassigned_item();
+}
+
+ui::BasicTreeViewItem &AssetCatalogTreeView::build_catalog_items_recursive(
+ ui::TreeViewOrItem &view_parent_item, AssetCatalogTreeItem &catalog)
+{
+ ui::BasicTreeViewItem &view_item = view_parent_item.add_tree_item<AssetCatalogTreeViewItem>(
+ &catalog);
+ view_item.set_is_active_fn(
+ [this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); });
+
+ catalog.foreach_child([&view_item, this](AssetCatalogTreeItem &child) {
+ build_catalog_items_recursive(view_item, child);
+ });
+ return view_item;
+}
+
+AssetCatalogTreeViewAllItem &AssetCatalogTreeView::add_all_item()
+{
+ FileAssetSelectParams *params = params_;
+
+ AssetCatalogTreeViewAllItem &item = add_tree_item<AssetCatalogTreeViewAllItem>(IFACE_("All"));
+ item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) {
+ params->asset_catalog_visibility = FILE_SHOW_ASSETS_ALL_CATALOGS;
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+ });
+ item.set_is_active_fn(
+ [params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_ALL_CATALOGS; });
+ return item;
+}
+
+void AssetCatalogTreeView::add_unassigned_item()
+{
+ FileAssetSelectParams *params = params_;
+
+ AssetCatalogTreeViewUnassignedItem &item = add_tree_item<AssetCatalogTreeViewUnassignedItem>(
+ IFACE_("Unassigned"), ICON_FILE_HIDDEN);
+
+ item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) {
+ params->asset_catalog_visibility = FILE_SHOW_ASSETS_WITHOUT_CATALOG;
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+ });
+ item.set_is_active_fn(
+ [params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_WITHOUT_CATALOG; });
+}
+
+void AssetCatalogTreeView::activate_catalog_by_id(CatalogID catalog_id)
+{
+ params_->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG;
+ params_->catalog_id = catalog_id;
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+}
+
+bool AssetCatalogTreeView::is_active_catalog(CatalogID catalog_id) const
+{
+ return (params_->asset_catalog_visibility == FILE_SHOW_ASSETS_FROM_CATALOG) &&
+ (params_->catalog_id == catalog_id);
+}
+
+/* ---------------------------------------------------------------------- */
+
+AssetCatalogTreeViewItem::AssetCatalogTreeViewItem(AssetCatalogTreeItem *catalog_item)
+ : BasicTreeViewItem(catalog_item->get_name()), catalog_item_(*catalog_item)
+{
+}
+
+void AssetCatalogTreeViewItem::on_activate()
+{
+ AssetCatalogTreeView &tree_view = static_cast<AssetCatalogTreeView &>(get_tree_view());
+ tree_view.activate_catalog_by_id(catalog_item_.get_catalog_id());
+}
+
+void AssetCatalogTreeViewItem::build_row(uiLayout &row)
+{
+ const std::string label_override = catalog_item_.has_unsaved_changes() ? (label_ + "*") : label_;
+ add_label(row, label_override);
+
+ if (!is_hovered()) {
+ return;
+ }
+
+ uiButTreeRow *tree_row_but = tree_row_button();
+ PointerRNA *props;
+
+ props = UI_but_extra_operator_icon_add(
+ (uiBut *)tree_row_but, "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
+ RNA_string_set(props, "parent_path", catalog_item_.catalog_path().c_str());
+}
+
+void AssetCatalogTreeViewItem::build_context_menu(bContext &C, uiLayout &column) const
+{
+ PointerRNA props;
+
+ uiItemFullO(&column,
+ "ASSET_OT_catalog_new",
+ "New Catalog",
+ ICON_NONE,
+ nullptr,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ &props);
+ RNA_string_set(&props, "parent_path", catalog_item_.catalog_path().c_str());
+
+ char catalog_id_str_buffer[UUID_STRING_LEN] = "";
+ BLI_uuid_format(catalog_id_str_buffer, catalog_item_.get_catalog_id());
+ uiItemFullO(&column,
+ "ASSET_OT_catalog_delete",
+ "Delete Catalog",
+ ICON_NONE,
+ nullptr,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ &props);
+ RNA_string_set(&props, "catalog_id", catalog_id_str_buffer);
+ uiItemO(&column, "Rename", ICON_NONE, "UI_OT_tree_view_item_rename");
+
+ /* Doesn't actually exist right now, but could be defined in Python. Reason that this isn't done
+ * in Python yet is that catalogs are not exposed in BPY, and we'd somehow pass the clicked on
+ * catalog to the menu draw callback (via context probably). */
+ MenuType *mt = WM_menutype_find("ASSETBROWSER_MT_catalog_context_menu", true);
+ if (!mt) {
+ return;
+ }
+ UI_menutype_draw(&C, mt, &column);
+}
+
+bool AssetCatalogTreeViewItem::supports_renaming() const
+{
+ return true;
+}
+
+bool AssetCatalogTreeViewItem::rename(StringRefNull new_name)
+{
+ /* Important to keep state. */
+ BasicTreeViewItem::rename(new_name);
+
+ const AssetCatalogTreeView &tree_view = static_cast<const AssetCatalogTreeView &>(
+ get_tree_view());
+ ED_asset_catalog_rename(tree_view.asset_library_, catalog_item_.get_catalog_id(), new_name);
+ return true;
+}
+
+std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewItem::
+ create_drop_controller() const
+{
+ return std::make_unique<AssetCatalogDropController>(
+ static_cast<AssetCatalogTreeView &>(get_tree_view()), catalog_item_);
+}
+
+std::unique_ptr<ui::AbstractTreeViewItemDragController> AssetCatalogTreeViewItem::
+ create_drag_controller() const
+{
+ return std::make_unique<AssetCatalogDragController>(
+ static_cast<AssetCatalogTreeView &>(get_tree_view()), catalog_item_);
+}
+
+/* ---------------------------------------------------------------------- */
+
+AssetCatalogDropController::AssetCatalogDropController(AssetCatalogTreeView &tree_view,
+ AssetCatalogTreeItem &catalog_item)
+ : ui::AbstractTreeViewItemDropController(tree_view), catalog_item_(catalog_item)
+{
+}
+
+bool AssetCatalogDropController::can_drop(const wmDrag &drag, const char **r_disabled_hint) const
+{
+ if (drag.type == WM_DRAG_ASSET_CATALOG) {
+ const AssetCatalog *drag_catalog = get_drag_catalog(drag, get_asset_library());
+ /* NOTE: Technically it's not an issue to allow this (the catalog will just receive a new
+ * path and the catalog system will generate missing parents from the path). But it does
+ * appear broken to users, so disabling entirely. */
+ if (catalog_item_.catalog_path().is_contained_in(drag_catalog->path)) {
+ *r_disabled_hint = "Catalog cannot be dropped into itself";
+ return false;
+ }
+ if (catalog_item_.catalog_path() == drag_catalog->path.parent()) {
+ *r_disabled_hint = "Catalog is already placed inside this catalog";
+ return false;
+ }
+ return true;
+ }
+ if (drag.type == WM_DRAG_ASSET_LIST) {
+ return has_droppable_asset(drag, r_disabled_hint);
+ }
+ return false;
+}
+
+std::string AssetCatalogDropController::drop_tooltip(const wmDrag &drag) const
+{
+ if (drag.type == WM_DRAG_ASSET_CATALOG) {
+ return drop_tooltip_asset_catalog(drag);
+ }
+ return drop_tooltip_asset_list(drag);
+}
+
+std::string AssetCatalogDropController::drop_tooltip_asset_catalog(const wmDrag &drag) const
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
+ const AssetCatalog *src_catalog = get_drag_catalog(drag, get_asset_library());
+
+ return std::string(TIP_("Move Catalog")) + " '" + src_catalog->path.name() + "' " +
+ TIP_("into") + " '" + catalog_item_.get_name() + "'";
+}
+
+std::string AssetCatalogDropController::drop_tooltip_asset_list(const wmDrag &drag) const
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_LIST);
+
+ const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
+ const bool is_multiple_assets = !BLI_listbase_is_single(asset_drags);
+
+ /* Don't try to be smart by dynamically adding the 's' for the plural. Just makes translation
+ * harder, so use full literals. */
+ std::string basic_tip = is_multiple_assets ? TIP_("Move assets to catalog") :
+ TIP_("Move asset to catalog");
+
+ return basic_tip + ": " + catalog_item_.get_name() + " (" + catalog_item_.catalog_path().str() +
+ ")";
+}
+
+bool AssetCatalogDropController::on_drop(struct bContext *C, const wmDrag &drag)
+{
+ if (drag.type == WM_DRAG_ASSET_CATALOG) {
+ return drop_asset_catalog_into_catalog(
+ drag, tree_view<AssetCatalogTreeView>(), catalog_item_.get_catalog_id());
+ }
+ return drop_assets_into_catalog(C,
+ tree_view<AssetCatalogTreeView>(),
+ drag,
+ catalog_item_.get_catalog_id(),
+ catalog_item_.get_simple_name());
+}
+
+bool AssetCatalogDropController::drop_asset_catalog_into_catalog(
+ const wmDrag &drag,
+ AssetCatalogTreeView &tree_view,
+ const std::optional<CatalogID> drop_catalog_id)
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
+ wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag);
+ ED_asset_catalog_move(tree_view.asset_library_, catalog_drag->drag_catalog_id, drop_catalog_id);
+ tree_view.activate_catalog_by_id(catalog_drag->drag_catalog_id);
+
+ WM_main_add_notifier(NC_ASSET | ND_ASSET_CATALOGS, nullptr);
+ return true;
+}
+
+bool AssetCatalogDropController::drop_assets_into_catalog(struct bContext *C,
+ const AssetCatalogTreeView &tree_view,
+ const wmDrag &drag,
+ CatalogID catalog_id,
+ StringRefNull simple_name)
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_LIST);
+ const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
+ if (!asset_drags) {
+ return false;
+ }
+
+ bool did_update = false;
+ LISTBASE_FOREACH (wmDragAssetListItem *, asset_item, asset_drags) {
+ if (asset_item->is_external) {
+ /* Only internal assets can be modified! */
+ continue;
+ }
+
+ did_update = true;
+ BKE_asset_metadata_catalog_id_set(
+ asset_item->asset_data.local_id->asset_data, catalog_id, simple_name.c_str());
+
+ /* Trigger re-run of filtering to update visible assets. */
+ filelist_tag_needs_filtering(tree_view.space_file_.files);
+ file_select_deselect_all(&tree_view.space_file_, FILE_SEL_SELECTED | FILE_SEL_HIGHLIGHTED);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, nullptr);
+ }
+
+ if (did_update) {
+ ED_undo_push(C, "Assign Asset Catalog");
+ }
+ return true;
+}
+
+AssetCatalog *AssetCatalogDropController::get_drag_catalog(const wmDrag &drag,
+ const ::AssetLibrary &asset_library)
+{
+ if (drag.type != WM_DRAG_ASSET_CATALOG) {
+ return nullptr;
+ }
+ const bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(
+ &asset_library);
+ const wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag);
+
+ return catalog_service->find_catalog(catalog_drag->drag_catalog_id);
+}
+
+bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag,
+ const char **r_disabled_hint)
+{
+ const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
+
+ *r_disabled_hint = nullptr;
+ /* There needs to be at least one asset from the current file. */
+ LISTBASE_FOREACH (const wmDragAssetListItem *, asset_item, asset_drags) {
+ if (!asset_item->is_external) {
+ return true;
+ }
+ }
+
+ *r_disabled_hint = TIP_("Only assets from this current file can be moved between catalogs");
+ return false;
+}
+
+::AssetLibrary &AssetCatalogDropController::get_asset_library() const
+{
+ return *tree_view<AssetCatalogTreeView>().asset_library_;
+}
+
+/* ---------------------------------------------------------------------- */
+
+AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeView &tree_view,
+ AssetCatalogTreeItem &catalog_item)
+ : ui::AbstractTreeViewItemDragController(tree_view), catalog_item_(catalog_item)
+{
+}
+
+int AssetCatalogDragController::get_drag_type() const
+{
+ return WM_DRAG_ASSET_CATALOG;
+}
+
+void *AssetCatalogDragController::create_drag_data() const
+{
+ wmDragAssetCatalog *drag_catalog = (wmDragAssetCatalog *)MEM_callocN(sizeof(*drag_catalog),
+ __func__);
+ drag_catalog->drag_catalog_id = catalog_item_.get_catalog_id();
+ return drag_catalog;
+}
+
+void AssetCatalogDragController::on_drag_start()
+{
+ AssetCatalogTreeView &tree_view_ = tree_view<AssetCatalogTreeView>();
+ tree_view_.activate_catalog_by_id(catalog_item_.get_catalog_id());
+}
+
+/* ---------------------------------------------------------------------- */
+
+void AssetCatalogTreeViewAllItem::build_row(uiLayout &row)
+{
+ ui::BasicTreeViewItem::build_row(row);
+
+ PointerRNA *props;
+
+ UI_but_extra_operator_icon_add(
+ (uiBut *)tree_row_button(), "ASSET_OT_catalogs_save", WM_OP_INVOKE_DEFAULT, ICON_FILE_TICK);
+
+ props = UI_but_extra_operator_icon_add(
+ (uiBut *)tree_row_button(), "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
+ /* No parent path to use the root level. */
+ RNA_string_set(props, "parent_path", nullptr);
+}
+
+std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewAllItem::
+ create_drop_controller() const
+{
+ return std::make_unique<AssetCatalogTreeViewAllItem::DropController>(
+ static_cast<AssetCatalogTreeView &>(get_tree_view()));
+}
+
+AssetCatalogTreeViewAllItem::DropController::DropController(AssetCatalogTreeView &tree_view)
+ : ui::AbstractTreeViewItemDropController(tree_view)
+{
+}
+
+bool AssetCatalogTreeViewAllItem::DropController::can_drop(const wmDrag &drag,
+ const char **r_disabled_hint) const
+{
+ if (drag.type != WM_DRAG_ASSET_CATALOG) {
+ return false;
+ }
+
+ const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
+ drag, *tree_view<AssetCatalogTreeView>().asset_library_);
+ if (drag_catalog->path.parent() == "") {
+ *r_disabled_hint = "Catalog is already placed at the highest level";
+ return false;
+ }
+
+ return true;
+}
+
+std::string AssetCatalogTreeViewAllItem::DropController::drop_tooltip(const wmDrag &drag) const
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
+ const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
+ drag, *tree_view<AssetCatalogTreeView>().asset_library_);
+
+ return std::string(TIP_("Move Catalog")) + " '" + drag_catalog->path.name() + "' " +
+ TIP_("to the top level of the tree");
+}
+
+bool AssetCatalogTreeViewAllItem::DropController::on_drop(struct bContext *UNUSED(C),
+ const wmDrag &drag)
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
+ return AssetCatalogDropController::drop_asset_catalog_into_catalog(
+ drag,
+ tree_view<AssetCatalogTreeView>(),
+ /* No value to drop into the root level. */
+ std::nullopt);
+}
+
+/* ---------------------------------------------------------------------- */
+
+std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewUnassignedItem::
+ create_drop_controller() const
+{
+ return std::make_unique<AssetCatalogTreeViewUnassignedItem::DropController>(
+ static_cast<AssetCatalogTreeView &>(get_tree_view()));
+}
+
+AssetCatalogTreeViewUnassignedItem::DropController::DropController(AssetCatalogTreeView &tree_view)
+ : ui::AbstractTreeViewItemDropController(tree_view)
+{
+}
+
+bool AssetCatalogTreeViewUnassignedItem::DropController::can_drop(
+ const wmDrag &drag, const char **r_disabled_hint) const
+{
+ if (drag.type != WM_DRAG_ASSET_LIST) {
+ return false;
+ }
+ return AssetCatalogDropController::has_droppable_asset(drag, r_disabled_hint);
+}
+
+std::string AssetCatalogTreeViewUnassignedItem::DropController::drop_tooltip(
+ const wmDrag &drag) const
+{
+ const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
+ const bool is_multiple_assets = !BLI_listbase_is_single(asset_drags);
+
+ return is_multiple_assets ? TIP_("Move assets out of any catalog") :
+ TIP_("Move asset out of any catalog");
+}
+
+bool AssetCatalogTreeViewUnassignedItem::DropController::on_drop(struct bContext *C,
+ const wmDrag &drag)
+{
+ /* Assign to nil catalog ID. */
+ return AssetCatalogDropController::drop_assets_into_catalog(
+ C, tree_view<AssetCatalogTreeView>(), drag, CatalogID{});
+}
+
+} // namespace blender::ed::asset_browser
+
+/* ---------------------------------------------------------------------- */
+
+namespace blender::ed::asset_browser {
+
+class AssetCatalogFilterSettings {
+ public:
+ eFileSel_Params_AssetCatalogVisibility asset_catalog_visibility;
+ bUUID asset_catalog_id;
+
+ std::unique_ptr<AssetCatalogFilter> catalog_filter;
+};
+
+} // namespace blender::ed::asset_browser
+
+using namespace blender::ed::asset_browser;
+
+FileAssetCatalogFilterSettingsHandle *file_create_asset_catalog_filter_settings()
+{
+ AssetCatalogFilterSettings *filter_settings = MEM_new<AssetCatalogFilterSettings>(__func__);
+ return reinterpret_cast<FileAssetCatalogFilterSettingsHandle *>(filter_settings);
+}
+
+void file_delete_asset_catalog_filter_settings(
+ FileAssetCatalogFilterSettingsHandle **filter_settings_handle)
+{
+ AssetCatalogFilterSettings **filter_settings = reinterpret_cast<AssetCatalogFilterSettings **>(
+ filter_settings_handle);
+ MEM_delete(*filter_settings);
+ *filter_settings = nullptr;
+}
+
+bool file_set_asset_catalog_filter_settings(
+ FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
+ eFileSel_Params_AssetCatalogVisibility catalog_visibility,
+ ::bUUID catalog_id)
+{
+ AssetCatalogFilterSettings *filter_settings = reinterpret_cast<AssetCatalogFilterSettings *>(
+ filter_settings_handle);
+ bool needs_update = false;
+
+ if (filter_settings->asset_catalog_visibility != catalog_visibility) {
+ filter_settings->asset_catalog_visibility = catalog_visibility;
+ needs_update = true;
+ }
+
+ if (filter_settings->asset_catalog_visibility == FILE_SHOW_ASSETS_FROM_CATALOG &&
+ !BLI_uuid_equal(filter_settings->asset_catalog_id, catalog_id)) {
+ filter_settings->asset_catalog_id = catalog_id;
+ needs_update = true;
+ }
+
+ return needs_update;
+}
+
+void file_ensure_updated_catalog_filter_data(
+ FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
+ const ::AssetLibrary *asset_library)
+{
+ AssetCatalogFilterSettings *filter_settings = reinterpret_cast<AssetCatalogFilterSettings *>(
+ filter_settings_handle);
+ const AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(
+ asset_library);
+
+ if (filter_settings->asset_catalog_visibility != FILE_SHOW_ASSETS_ALL_CATALOGS) {
+ filter_settings->catalog_filter = std::make_unique<AssetCatalogFilter>(
+ catalog_service->create_catalog_filter(filter_settings->asset_catalog_id));
+ }
+}
+
+bool file_is_asset_visible_in_catalog_filter_settings(
+ const FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
+ const AssetMetaData *asset_data)
+{
+ const AssetCatalogFilterSettings *filter_settings =
+ reinterpret_cast<const AssetCatalogFilterSettings *>(filter_settings_handle);
+
+ switch (filter_settings->asset_catalog_visibility) {
+ case FILE_SHOW_ASSETS_WITHOUT_CATALOG:
+ return !filter_settings->catalog_filter->is_known(asset_data->catalog_id);
+ case FILE_SHOW_ASSETS_FROM_CATALOG:
+ return filter_settings->catalog_filter->contains(asset_data->catalog_id);
+ case FILE_SHOW_ASSETS_ALL_CATALOGS:
+ /* All asset files should be visible. */
+ return true;
+ }
+
+ BLI_assert_unreachable();
+ return false;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void file_create_asset_catalog_tree_view_in_layout(::AssetLibrary *asset_library,
+ uiLayout *layout,
+ SpaceFile *space_file,
+ FileAssetSelectParams *params)
+{
+ uiBlock *block = uiLayoutGetBlock(layout);
+
+ UI_block_layout_set_current(block, layout);
+
+ ui::AbstractTreeView *tree_view = UI_block_add_view(
+ *block,
+ "asset catalog tree view",
+ std::make_unique<ed::asset_browser::AssetCatalogTreeView>(
+ asset_library, params, *space_file));
+
+ ui::TreeViewBuilder builder(*block);
+ builder.build_tree_view(*tree_view);
+}
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 9a46579780e..14c786e5dea 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -178,6 +178,10 @@ static void file_draw_icon(const SpaceFile *sfile,
if ((id = filelist_file_get_id(file))) {
UI_but_drag_set_id(but, id);
+ ImBuf *preview_image = filelist_file_getimage(file);
+ if (preview_image) {
+ UI_but_drag_attach_image(but, preview_image, UI_DPI_FAC);
+ }
}
else if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS &&
(file->typeflag & FILE_TYPE_ASSET) != 0) {
@@ -190,6 +194,7 @@ static void file_draw_icon(const SpaceFile *sfile,
UI_but_drag_set_asset(but,
&(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
+ file->asset_data,
asset_params->import_type,
icon,
preview_image,
@@ -235,6 +240,7 @@ static void file_draw_string(int sx,
UI_fontstyle_draw(&fs,
&rect,
fname,
+ sizeof(fname),
col,
&(struct uiFontStyleDraw_Params){
.align = align,
@@ -242,8 +248,9 @@ static void file_draw_string(int sx,
}
/**
- * \param r_sx, r_sy: The lower right corner of the last line drawn. AKA the cursor position on
- * completion.
+ * \param r_sx, r_sy: The lower right corner of the last line drawn, plus the height of the last
+ * line. This is the cursor position on completion to allow drawing more text
+ * behind that.
*/
static void file_draw_string_multiline(int sx,
int sy,
@@ -283,12 +290,12 @@ static void file_draw_string_multiline(int sx,
UI_fontstyle_draw_ex(&style->widget,
&rect,
string,
+ len,
text_col,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_LEFT,
.word_wrap = true,
},
- len,
NULL,
NULL,
&result);
@@ -396,19 +403,19 @@ static void file_draw_preview(const SpaceFile *sfile,
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTexScaled(&state,
- (float)xco,
- (float)yco,
- imb->x,
- imb->y,
- GPU_RGBA8,
- true,
- imb->rect,
- scale,
- scale,
- 1.0f,
- 1.0f,
- col);
+ immDrawPixelsTexTiled_scaling(&state,
+ (float)xco,
+ (float)yco,
+ imb->x,
+ imb->y,
+ GPU_RGBA8,
+ true,
+ imb->rect,
+ scale,
+ scale,
+ 1.0f,
+ 1.0f,
+ col);
GPU_blend(GPU_BLEND_ALPHA);
@@ -465,6 +472,17 @@ static void file_draw_preview(const SpaceFile *sfile,
UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
}
+ const bool is_current_main_data = filelist_file_get_id(file) != NULL;
+ if (is_current_main_data) {
+ /* Smaller, fainter icon at the top-right indicating that the file represents data from the
+ * current file (from current #Main in fact). */
+ float icon_x, icon_y;
+ const uchar light[4] = {255, 255, 255, 255};
+ icon_x = xco + ex - UI_UNIT_X;
+ icon_y = yco + ey - UI_UNIT_Y;
+ UI_icon_draw_ex(icon_x, icon_y, ICON_CURRENT_FILE, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ }
+
/* Contrasting outline around some preview types. */
if (show_outline) {
GPUVertFormat *format = immVertexFormat();
@@ -491,6 +509,7 @@ static void file_draw_preview(const SpaceFile *sfile,
if ((id = filelist_file_get_id(file))) {
UI_but_drag_set_id(but, id);
+ UI_but_drag_attach_image(but, imb, scale);
}
/* path is no more static, cannot give it directly to but... */
else if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS &&
@@ -504,6 +523,7 @@ static void file_draw_preview(const SpaceFile *sfile,
UI_but_drag_set_asset(but,
&(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
+ file->asset_data,
asset_params->import_type,
icon,
imb,
@@ -886,7 +906,8 @@ void file_draw_list(const bContext *C, ARegion *region)
* since it's filelist_file_cache_block() and filelist_cache_previews_update()
* which controls previews task. */
{
- const bool previews_running = filelist_cache_previews_running(files);
+ const bool previews_running = filelist_cache_previews_running(files) &&
+ !filelist_cache_previews_done(files);
// printf("%s: preview task: %d\n", __func__, previews_running);
if (previews_running && !sfile->previews_timer) {
sfile->previews_timer = WM_event_add_timer_notifier(
@@ -1053,7 +1074,9 @@ void file_draw_list(const bContext *C, ARegion *region)
layout->curr_size = params->thumbnail_size;
}
-static void file_draw_invalid_library_hint(const SpaceFile *sfile, const ARegion *region)
+static void file_draw_invalid_library_hint(const bContext *C,
+ const SpaceFile *sfile,
+ ARegion *region)
{
const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
@@ -1061,9 +1084,7 @@ static void file_draw_invalid_library_hint(const SpaceFile *sfile, const ARegion
file_path_to_ui_path(asset_params->base_params.dir, library_ui_path, sizeof(library_ui_path));
uchar text_col[4];
- uchar text_alert_col[4];
UI_GetThemeColor4ubv(TH_TEXT, text_col);
- UI_GetThemeColor4ubv(TH_REDALERT, text_alert_col);
const View2D *v2d = &region->v2d;
const int pad = sfile->layout->tile_border_x;
@@ -1074,31 +1095,46 @@ static void file_draw_invalid_library_hint(const SpaceFile *sfile, const ARegion
int sy = v2d->tot.ymax;
{
- const char *message = TIP_("Library not found");
- const int draw_string_str_len = strlen(message) + 2 + sizeof(library_ui_path);
- char *draw_string = alloca(draw_string_str_len);
- BLI_snprintf(draw_string, draw_string_str_len, "%s: %s", message, library_ui_path);
- file_draw_string_multiline(sx, sy, draw_string, width, line_height, text_alert_col, NULL, &sy);
+ const char *message = TIP_("Path to asset library does not exist:");
+ file_draw_string_multiline(sx, sy, message, width, line_height, text_col, NULL, &sy);
+
+ sy -= line_height;
+ file_draw_string(sx, sy, library_ui_path, width, line_height, UI_STYLE_TEXT_LEFT, text_col);
}
- /* Next line, but separate it a bit further. */
- sy -= line_height;
+ /* Separate a bit further. */
+ sy -= line_height * 2.2f;
{
UI_icon_draw(sx, sy - UI_UNIT_Y, ICON_INFO);
const char *suggestion = TIP_(
- "Set up the library or edit libraries in the Preferences, File Paths section");
+ "Asset Libraries are local directories that can contain .blend files with assets inside.\n"
+ "Manage Asset Libraries from the File Paths section in Preferences");
file_draw_string_multiline(
- sx + UI_UNIT_X, sy, suggestion, width - UI_UNIT_X, line_height, text_col, NULL, NULL);
+ sx + UI_UNIT_X, sy, suggestion, width - UI_UNIT_X, line_height, text_col, NULL, &sy);
+
+ uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
+ uiBut *but = uiDefIconTextButO(block,
+ UI_BTYPE_BUT,
+ "SCREEN_OT_userpref_show",
+ WM_OP_INVOKE_DEFAULT,
+ ICON_PREFERENCES,
+ NULL,
+ sx + UI_UNIT_X,
+ sy - line_height - UI_UNIT_Y * 1.2f,
+ UI_UNIT_X * 8,
+ UI_UNIT_Y,
+ NULL);
+ PointerRNA *but_opptr = UI_but_operator_ptr_get(but);
+ RNA_enum_set(but_opptr, "section", USER_SECTION_FILE_PATHS);
+
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
}
}
-/**
- * Draw a string hint if the file list is invalid.
- * \return true if the list is invalid and a hint was drawn.
- */
-bool file_draw_hint_if_invalid(const SpaceFile *sfile, const ARegion *region)
+bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region)
{
FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
/* Only for asset browser. */
@@ -1111,7 +1147,7 @@ bool file_draw_hint_if_invalid(const SpaceFile *sfile, const ARegion *region)
return false;
}
- file_draw_invalid_library_hint(sfile, region);
+ file_draw_invalid_library_hint(C, sfile, region);
return true;
}
diff --git a/source/blender/editors/space_file/file_indexer.cc b/source/blender/editors/space_file/file_indexer.cc
new file mode 100644
index 00000000000..95e0afd7a1e
--- /dev/null
+++ b/source/blender/editors/space_file/file_indexer.cc
@@ -0,0 +1,96 @@
+/*
+ * 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 edfile
+ *
+ * This file implements the default file browser indexer and has some helper function to work with
+ * `FileIndexerEntries`.
+ */
+#include "file_indexer.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+namespace blender::ed::file::indexer {
+
+static eFileIndexerResult read_index(const char *UNUSED(file_name),
+ FileIndexerEntries *UNUSED(entries),
+ int *UNUSED(r_read_entries_len),
+ void *UNUSED(user_data))
+{
+ return FILE_INDEXER_NEEDS_UPDATE;
+}
+
+static void update_index(const char *UNUSED(file_name),
+ FileIndexerEntries *UNUSED(entries),
+ void *UNUSED(user_data))
+{
+}
+
+constexpr FileIndexerType default_indexer()
+{
+ FileIndexerType indexer = {nullptr};
+ indexer.read_index = read_index;
+ indexer.update_index = update_index;
+ return indexer;
+}
+
+static FileIndexerEntry *file_indexer_entry_create_from_datablock_info(
+ const BLODataBlockInfo *datablock_info, const int idcode)
+{
+ FileIndexerEntry *entry = static_cast<FileIndexerEntry *>(
+ MEM_mallocN(sizeof(FileIndexerEntry), __func__));
+ entry->datablock_info = *datablock_info;
+ entry->idcode = idcode;
+ return entry;
+}
+
+} // namespace blender::ed::file::indexer
+
+extern "C" {
+
+void ED_file_indexer_entries_extend_from_datablock_infos(
+ FileIndexerEntries *indexer_entries,
+ const LinkNode * /* BLODataBlockInfo */ datablock_infos,
+ const int idcode)
+{
+ for (const LinkNode *ln = datablock_infos; ln; ln = ln->next) {
+ const BLODataBlockInfo *datablock_info = static_cast<const BLODataBlockInfo *>(ln->link);
+ FileIndexerEntry *file_indexer_entry =
+ blender::ed::file::indexer::file_indexer_entry_create_from_datablock_info(datablock_info,
+ idcode);
+ BLI_linklist_prepend(&indexer_entries->entries, file_indexer_entry);
+ }
+}
+
+static void ED_file_indexer_entry_free(void *indexer_entry)
+{
+ MEM_freeN(indexer_entry);
+}
+
+void ED_file_indexer_entries_clear(FileIndexerEntries *indexer_entries)
+{
+ BLI_linklist_free(indexer_entries->entries, ED_file_indexer_entry_free);
+ indexer_entries->entries = nullptr;
+}
+
+const FileIndexerType file_indexer_noop = blender::ed::file::indexer::default_indexer();
+}
diff --git a/source/blender/editors/space_file/file_indexer.h b/source/blender/editors/space_file/file_indexer.h
new file mode 100644
index 00000000000..ea42f10498b
--- /dev/null
+++ b/source/blender/editors/space_file/file_indexer.h
@@ -0,0 +1,36 @@
+/*
+ * 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 edfile
+ */
+#pragma once
+
+#include "ED_file_indexer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Default indexer to use when listing files. The implementation is a no-operation indexing. When
+ * set it won't use indexing. It is added to increase the code clarity.
+ */
+extern const FileIndexerType file_indexer_noop;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 905c0aeb8e0..bd55e6f78ab 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -23,29 +23,48 @@
#pragma once
+#include "DNA_space_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* internal exports only */
struct ARegion;
struct ARegionType;
+struct AssetLibrary;
+struct FileAssetSelectParams;
struct FileSelectParams;
struct SpaceFile;
struct View2D;
+struct uiLayout;
/* file_draw.c */
+
#define ATTRIBUTE_COLUMN_PADDING (0.5f * UI_UNIT_X)
-#define SMALL_SIZE_CHECK(_size) ((_size) < 64) /* Related to FileSelectParams.thumbnail_size. */
+/** Related to #FileSelectParams.thumbnail_size. */
+#define SMALL_SIZE_CHECK(_size) ((_size) < 64)
void file_calc_previews(const bContext *C, ARegion *region);
void file_draw_list(const bContext *C, ARegion *region);
-bool file_draw_hint_if_invalid(const SpaceFile *sfile, const ARegion *region);
+/**
+ * Draw a string hint if the file list is invalid.
+ * \return true if the list is invalid and a hint was drawn.
+ */
+bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region);
void file_draw_check_ex(bContext *C, struct ScrArea *area);
void file_draw_check(bContext *C);
+/**
+ * For use with; #UI_block_func_set.
+ */
void file_draw_check_cb(bContext *C, void *arg1, void *arg2);
bool file_draw_check_exists(SpaceFile *sfile);
/* file_ops.h */
+
struct wmOperator;
struct wmOperatorType;
@@ -63,6 +82,10 @@ void FILE_OT_bookmark_move(struct wmOperatorType *ot);
void FILE_OT_reset_recent(wmOperatorType *ot);
void FILE_OT_hidedot(struct wmOperatorType *ot);
void FILE_OT_execute(struct wmOperatorType *ot);
+/**
+ * Variation of #FILE_OT_execute that accounts for some mouse specific handling.
+ * Otherwise calls the same logic.
+ */
void FILE_OT_mouse_execute(struct wmOperatorType *ot);
void FILE_OT_cancel(struct wmOperatorType *ot);
void FILE_OT_parent(struct wmOperatorType *ot);
@@ -83,6 +106,9 @@ void file_filename_enter_handle(bContext *C, void *arg_unused, void *arg_but);
int file_highlight_set(struct SpaceFile *sfile, struct ARegion *region, int mx, int my);
+/**
+ * Use to set the file selector path from some arbitrary source.
+ */
void file_sfile_filepath_set(struct SpaceFile *sfile, const char *filepath);
void file_sfile_to_operator_ex(struct Main *bmain,
struct wmOperator *op,
@@ -93,17 +119,28 @@ void file_sfile_to_operator(struct Main *bmain, struct wmOperator *op, struct Sp
void file_operator_to_sfile(struct Main *bmain, struct SpaceFile *sfile, struct wmOperator *op);
/* space_file.c */
+
extern const char *file_context_dir[]; /* doc access */
/* filesel.c */
+
void fileselect_refresh_params(struct SpaceFile *sfile);
-void fileselect_file_set(SpaceFile *sfile, const int index);
+/**
+ * Sets #FileSelectParams.file (name of selected file)
+ */
+void fileselect_file_set(SpaceFile *sfile, int index);
bool file_attribute_column_type_enabled(const FileSelectParams *params,
FileAttributeColumnType column);
+/**
+ * Check if the region coordinate defined by \a x and \a y are inside the column header.
+ */
bool file_attribute_column_header_is_inside(const struct View2D *v2d,
const FileLayout *layout,
int x,
int y);
+/**
+ * Find the column type at region coordinate given by \a x (y doesn't matter for this).
+ */
FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d,
const FileSelectParams *params,
FileLayout *layout,
@@ -120,13 +157,26 @@ void file_params_smoothscroll_timer_clear(struct wmWindowManager *wm,
struct wmWindow *win,
SpaceFile *sfile);
void file_params_renamefile_clear(struct FileSelectParams *params);
+/**
+ * Set the renaming-state to #FILE_PARAMS_RENAME_POSTSCROLL_PENDING and trigger the smooth-scroll
+ * timer. To be used right after a file was renamed.
+ * Note that the caller is responsible for setting the correct rename-file info
+ * (#FileSelectParams.renamefile or #FileSelectParams.rename_id).
+ */
void file_params_invoke_rename_postscroll(struct wmWindowManager *wm,
struct wmWindow *win,
SpaceFile *sfile);
+/**
+ * To be executed whenever renaming ends (successfully or not).
+ */
void file_params_rename_end(struct wmWindowManager *wm,
struct wmWindow *win,
SpaceFile *sfile,
struct FileDirEntry *rename_file);
+/**
+ * Helper used by both main update code, and smooth-scroll timer,
+ * to try to enable rename editing from #FileSelectParams.renamefile name.
+ */
void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params);
typedef void *onReloadFnData;
@@ -138,17 +188,57 @@ typedef struct SpaceFile_Runtime {
onReloadFnData on_reload_custom_data;
} SpaceFile_Runtime;
-/* Register an on-reload callback function. Note that there can only be one such function at a
- * time; registering a new one will overwrite the previous one. */
+/**
+ * Register an on-reload callback function. Note that there can only be one such function at a
+ * time; registering a new one will overwrite the previous one.
+ */
void file_on_reload_callback_register(struct SpaceFile *sfile,
onReloadFn callback,
onReloadFnData custom_data);
/* file_panels.c */
+
void file_tool_props_region_panels_register(struct ARegionType *art);
void file_execute_region_panels_register(struct ARegionType *art);
+void file_tools_region_panels_register(struct ARegionType *art);
/* file_utils.c */
-void file_tile_boundbox(const ARegion *region, FileLayout *layout, const int file, rcti *r_bounds);
+void file_tile_boundbox(const ARegion *region, FileLayout *layout, int file, rcti *r_bounds);
+
+/**
+ * If \a path leads to a .blend, remove the trailing slash (if needed).
+ */
void file_path_to_ui_path(const char *path, char *r_pathi, int max_size);
+
+/* asset_catalog_tree_view.cc */
+
+/* C-handle for #ed::asset_browser::AssetCatalogFilterSettings. */
+typedef struct FileAssetCatalogFilterSettingsHandle FileAssetCatalogFilterSettingsHandle;
+
+FileAssetCatalogFilterSettingsHandle *file_create_asset_catalog_filter_settings(void);
+void file_delete_asset_catalog_filter_settings(
+ FileAssetCatalogFilterSettingsHandle **filter_settings_handle);
+/**
+ * \return True if the file list should update its filtered results
+ * (e.g. because filtering parameters changed).
+ */
+bool file_set_asset_catalog_filter_settings(
+ FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
+ eFileSel_Params_AssetCatalogVisibility catalog_visibility,
+ bUUID catalog_id);
+void file_ensure_updated_catalog_filter_data(
+ FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
+ const struct AssetLibrary *asset_library);
+bool file_is_asset_visible_in_catalog_filter_settings(
+ const FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
+ const AssetMetaData *asset_data);
+
+void file_create_asset_catalog_tree_view_in_layout(struct AssetLibrary *asset_library,
+ struct uiLayout *layout,
+ struct SpaceFile *space_file,
+ struct FileAssetSelectParams *params);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index d0f2a4fdc4c..a1472a2c1b3 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -211,6 +211,11 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
filelist_setrecursion(sfile->files, params->recursion_level);
}
}
+ else if (file->redirection_path) {
+ BLI_strncpy(params->dir, file->redirection_path, sizeof(params->dir));
+ BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir);
+ BLI_path_slash_ensure(params->dir);
+ }
else {
BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir);
strcat(params->dir, file->relpath);
@@ -1413,8 +1418,13 @@ int file_highlight_set(SpaceFile *sfile, ARegion *region, int mx, int my)
return 0;
}
- numfiles = filelist_files_ensure(sfile->files);
params = ED_fileselect_get_active_params(sfile);
+ /* In case #SpaceFile.browse_mode just changed, the area may be pending a refresh still, which is
+ * what creates the params for the current browse mode. See T93508. */
+ if (!params) {
+ return false;
+ }
+ numfiles = filelist_files_ensure(sfile->files);
origfile = params->highlight_file;
@@ -1449,7 +1459,7 @@ static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), const wmEv
ARegion *region = CTX_wm_region(C);
SpaceFile *sfile = CTX_wm_space_file(C);
- if (!file_highlight_set(sfile, region, event->x, event->y)) {
+ if (!file_highlight_set(sfile, region, event->xy[0], event->xy[1])) {
return OPERATOR_PASS_THROUGH;
}
@@ -1684,9 +1694,6 @@ void file_operator_to_sfile(Main *bmain, SpaceFile *sfile, wmOperator *op)
/* XXX, files and dirs updates missing, not really so important though */
}
-/**
- * Use to set the file selector path from some arbitrary source.
- */
void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath)
{
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
@@ -1736,7 +1743,6 @@ void file_draw_check(bContext *C)
file_draw_check_ex(C, area);
}
-/* for use with; UI_block_func_set */
void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
{
file_draw_check(C);
@@ -1897,10 +1903,6 @@ static int file_execute_mouse_invoke(bContext *C, wmOperator *UNUSED(op), const
return OPERATOR_FINISHED;
}
-/**
- * Variation of #FILE_OT_execute that accounts for some mouse specific handling. Otherwise calls
- * the same logic.
- */
void FILE_OT_mouse_execute(wmOperatorType *ot)
{
/* identifiers */
@@ -1950,8 +1952,7 @@ void FILE_OT_refresh(struct wmOperatorType *ot)
/* api callbacks */
ot->exec = file_refresh_exec;
- /* Operator works for file or asset browsing */
- ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
+ ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
}
/** \} */
@@ -2462,13 +2463,16 @@ static void file_expand_directory(bContext *C)
if (params) {
if (BLI_path_is_rel(params->dir)) {
/* Use of 'default' folder here is just to avoid an error message on '//' prefix. */
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
BLI_path_abs(params->dir,
- G.relbase_valid ? BKE_main_blendfile_path(bmain) : BKE_appdir_folder_default());
+ (blendfile_path[0] != '\0') ? blendfile_path :
+ BKE_appdir_folder_default_or_root());
}
else if (params->dir[0] == '~') {
char tmpstr[sizeof(params->dir) - 1];
BLI_strncpy(tmpstr, params->dir + 1, sizeof(tmpstr));
- BLI_join_dirfile(params->dir, sizeof(params->dir), BKE_appdir_folder_default(), tmpstr);
+ BLI_path_join(
+ params->dir, sizeof(params->dir), BKE_appdir_folder_default_or_root(), tmpstr, NULL);
}
else if (params->dir[0] == '\0')
@@ -2620,7 +2624,8 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
matches = file_select_match(sfile, params->file, matched_file);
/* *After* file_select_match! */
- BLI_filename_make_safe(params->file);
+ const bool allow_tokens = (params->flag & FILE_PATH_TOKENS_ALLOW) != 0;
+ BLI_filename_make_safe_ex(params->file, allow_tokens);
if (matches) {
/* replace the pattern (or filename that the user typed in,
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index 7032d55b331..7da9f65a1a2 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -41,12 +41,14 @@
#include "ED_fileselect.h"
#include "UI_interface.h"
+#include "UI_interface_icons.h"
#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
#include "file_intern.h"
+#include "filelist.h"
#include "fsmenu.h"
#include <string.h>
@@ -57,6 +59,12 @@ static bool file_panel_operator_poll(const bContext *C, PanelType *UNUSED(pt))
return (sfile && sfile->op);
}
+static bool file_panel_asset_browsing_poll(const bContext *C, PanelType *UNUSED(pt))
+{
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ return sfile && sfile->files && ED_fileselect_is_asset_browser(sfile);
+}
+
static void file_panel_operator_header(const bContext *C, Panel *panel)
{
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -222,3 +230,55 @@ void file_execute_region_panels_register(ARegionType *art)
pt->draw = file_panel_execution_buttons_draw;
BLI_addtail(&art->paneltypes, pt);
}
+
+static void file_panel_asset_catalog_buttons_draw(const bContext *C, Panel *panel)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ /* May be null if the library wasn't loaded yet. */
+ struct AssetLibrary *asset_library = filelist_asset_library(sfile->files);
+ FileAssetSelectParams *params = ED_fileselect_get_asset_params(sfile);
+ BLI_assert(params != NULL);
+
+ uiLayout *col = uiLayoutColumn(panel->layout, false);
+ uiLayout *row = uiLayoutRow(col, true);
+
+ PointerRNA params_ptr;
+ RNA_pointer_create(&screen->id, &RNA_FileAssetSelectParams, params, &params_ptr);
+
+ uiItemR(row, &params_ptr, "asset_library_ref", 0, "", ICON_NONE);
+ if (params->asset_library_ref.type == ASSET_LIBRARY_LOCAL) {
+ bContext *mutable_ctx = CTX_copy(C);
+ if (WM_operator_name_poll(mutable_ctx, "asset.bundle_install")) {
+ uiItemS(col);
+ uiItemMenuEnumO(col,
+ mutable_ctx,
+ "asset.bundle_install",
+ "asset_library_ref",
+ "Copy Bundle to Asset Library...",
+ ICON_IMPORT);
+ }
+ CTX_free(mutable_ctx);
+ }
+ else {
+ uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_library_refresh");
+ }
+
+ uiItemS(col);
+
+ file_create_asset_catalog_tree_view_in_layout(asset_library, col, sfile, params);
+}
+
+void file_tools_region_panels_register(ARegionType *art)
+{
+ PanelType *pt;
+
+ pt = MEM_callocN(sizeof(PanelType), "spacetype file asset catalog buttons");
+ strcpy(pt->idname, "FILE_PT_asset_catalog_buttons");
+ strcpy(pt->label, N_("Asset Catalogs"));
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->flag = PANEL_TYPE_NO_HEADER;
+ pt->poll = file_panel_asset_browsing_poll;
+ pt->draw = file_panel_asset_catalog_buttons_draw;
+ BLI_addtail(&art->paneltypes, pt);
+}
diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c
index 186bc04fafe..fbe2426021b 100644
--- a/source/blender/editors/space_file/file_utils.c
+++ b/source/blender/editors/space_file/file_utils.c
@@ -46,9 +46,6 @@ void file_tile_boundbox(const ARegion *region, FileLayout *layout, const int fil
ymax);
}
-/**
- * If \a path leads to a .blend, remove the trailing slash (if needed).
- */
void file_path_to_ui_path(const char *path, char *r_path, int max_size)
{
char tmp_path[PATH_MAX];
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 60fe5364aba..2d31e8030a4 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -50,6 +50,7 @@
#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLI_uuid.h"
#ifdef WIN32
# include "BLI_winstuff.h"
@@ -88,6 +89,8 @@
#include "atomic_ops.h"
+#include "file_indexer.h"
+#include "file_intern.h"
#include "filelist.h"
#define FILEDIR_NBR_ENTRIES_UNSET -1
@@ -176,7 +179,6 @@ int folderlist_clear_next(struct SpaceFile *sfile)
return 1;
}
-/* not listbase itself */
void folderlist_free(ListBase *folderlist)
{
if (folderlist) {
@@ -337,7 +339,10 @@ typedef struct FileListEntryCache {
/* Previews handling. */
TaskPool *previews_pool;
ThreadQueue *previews_done;
- size_t previews_todo_count;
+ /** Counter for previews that are not fully loaded and ready to display yet. So includes all
+ * previews either in `previews_pool` or `previews_done`. #filelist_cache_previews_update() makes
+ * previews in `preview_done` ready for display, so the counter is decremented there. */
+ int previews_todo_count;
} FileListEntryCache;
/* FileListCache.flags */
@@ -350,9 +355,6 @@ typedef struct FileListEntryPreview {
char path[FILE_MAX];
uint flags;
int index;
- /* Some file types load the memory from runtime data, not from disk. We just wait until it's done
- * generating (BKE_previewimg_is_finished()). */
- PreviewImage *in_memory_preview;
int icon_id;
} FileListEntryPreview;
@@ -369,6 +371,8 @@ typedef struct FileListFilter {
char filter_glob[FILE_MAXFILE];
char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */
short flags;
+
+ FileAssetCatalogFilterSettingsHandle *asset_catalog_filter;
} FileListFilter;
/* FileListFilter.flags */
@@ -387,7 +391,7 @@ typedef struct FileList {
eFileSelectType type;
/* The library this list was created for. Stored here so we know when to re-read. */
AssetLibraryReference *asset_library_ref;
- struct AssetLibrary *asset_library;
+ struct AssetLibrary *asset_library; /* Non-owning pointer. */
short flags;
@@ -395,6 +399,11 @@ typedef struct FileList {
FileListFilter filter_data;
+ /**
+ * File indexer to use. Attribute is always set.
+ */
+ const struct FileIndexerType *indexer;
+
struct FileListIntern filelist_intern;
struct FileListEntryCache filelist_cache;
@@ -422,6 +431,8 @@ typedef struct FileList {
/* Filter an entry of current filelist. */
bool (*filter_fn)(struct FileListInternEntry *, const char *, FileListFilter *);
+ /* Executed before filtering individual items, to set up additional filter data. */
+ void (*prepare_filter_fn)(const struct FileList *, FileListFilter *);
short tags; /* FileListTags */
} FileList;
@@ -429,11 +440,14 @@ typedef struct FileList {
/* FileList.flags */
enum {
FL_FORCE_RESET = 1 << 0,
- FL_IS_READY = 1 << 1,
- FL_IS_PENDING = 1 << 2,
- FL_NEED_SORTING = 1 << 3,
- FL_NEED_FILTERING = 1 << 4,
- FL_SORT_INVERT = 1 << 5,
+ /* Don't do a full reset (unless #FL_FORCE_RESET is also set), only reset files representing main
+ * data (assets from the current file/#Main). */
+ FL_FORCE_RESET_MAIN_FILES = 1 << 1,
+ FL_IS_READY = 1 << 2,
+ FL_IS_PENDING = 1 << 3,
+ FL_NEED_SORTING = 1 << 4,
+ FL_NEED_FILTERING = 1 << 5,
+ FL_SORT_INVERT = 1 << 6,
};
/* FileList.tags */
@@ -486,7 +500,6 @@ static void filelist_readjob_main_assets(struct FileListReadJob *job_params,
static int groupname_to_code(const char *group);
static uint64_t groupname_to_filter_id(const char *group);
-static void filelist_filter_clear(FileList *filelist);
static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size);
/* ********** Sort helpers ********** */
@@ -501,6 +514,53 @@ static int compare_apply_inverted(int val, const struct FileSortData *sort_data)
}
/**
+ * If all relevant characteristics match (e.g. the file type when sorting by file types), this
+ * should be used as tiebreaker. It makes sure there's a well defined sorting even in such cases.
+ *
+ * Multiple files with the same name can appear with recursive file loading and/or when displaying
+ * IDs of different types, so these cases need to be handled.
+ *
+ * 1) Sort files by name using natural sorting.
+ * 2) If not possible (file names match) and both represent local IDs, sort by ID-type.
+ * 3) If not possible and only one is a local ID, place files representing local IDs first.
+ *
+ * TODO (not actually implemented, but should be):
+ * 4) If no file represents a local ID, sort by file path, so that files higher up the file system
+ * hierarchy are placed first.
+ */
+static int compare_tiebreaker(const FileListInternEntry *entry1, const FileListInternEntry *entry2)
+{
+ /* Case 1. */
+ {
+ const int order = BLI_strcasecmp_natural(entry1->name, entry2->name);
+ if (order) {
+ return order;
+ }
+ }
+
+ /* Case 2. */
+ if (entry1->local_data.id && entry2->local_data.id) {
+ if (entry1->blentype < entry2->blentype) {
+ return -1;
+ }
+ if (entry1->blentype > entry2->blentype) {
+ return 1;
+ }
+ }
+ /* Case 3. */
+ {
+ if (entry1->local_data.id && !entry2->local_data.id) {
+ return -1;
+ }
+ if (!entry1->local_data.id && entry2->local_data.id) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
* Handles inverted sorting itself (currently there's nothing to invert), so if this returns non-0,
* it should be used as-is and not inverted.
*/
@@ -560,17 +620,13 @@ static int compare_name(void *user_data, const void *a1, const void *a2)
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
const struct FileSortData *sort_data = user_data;
- char *name1, *name2;
- int ret;
+ int ret;
if ((ret = compare_direntry_generic(entry1, entry2))) {
return ret;
}
- name1 = entry1->name;
- name2 = entry2->name;
-
- return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
+ return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
}
static int compare_date(void *user_data, const void *a1, const void *a2)
@@ -578,10 +634,9 @@ static int compare_date(void *user_data, const void *a1, const void *a2)
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
const struct FileSortData *sort_data = user_data;
- char *name1, *name2;
int64_t time1, time2;
- int ret;
+ int ret;
if ((ret = compare_direntry_generic(entry1, entry2))) {
return ret;
}
@@ -595,10 +650,7 @@ static int compare_date(void *user_data, const void *a1, const void *a2)
return compare_apply_inverted(-1, sort_data);
}
- name1 = entry1->name;
- name2 = entry2->name;
-
- return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
+ return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
}
static int compare_size(void *user_data, const void *a1, const void *a2)
@@ -606,7 +658,6 @@ static int compare_size(void *user_data, const void *a1, const void *a2)
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
const struct FileSortData *sort_data = user_data;
- char *name1, *name2;
uint64_t size1, size2;
int ret;
@@ -623,10 +674,7 @@ static int compare_size(void *user_data, const void *a1, const void *a2)
return compare_apply_inverted(-1, sort_data);
}
- name1 = entry1->name;
- name2 = entry2->name;
-
- return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
+ return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
}
static int compare_extension(void *user_data, const void *a1, const void *a2)
@@ -634,7 +682,6 @@ static int compare_extension(void *user_data, const void *a1, const void *a2)
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
const struct FileSortData *sort_data = user_data;
- char *name1, *name2;
int ret;
if ((ret = compare_direntry_generic(entry1, entry2))) {
@@ -682,10 +729,7 @@ static int compare_extension(void *user_data, const void *a1, const void *a2)
}
}
- name1 = entry1->name;
- name2 = entry2->name;
-
- return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
+ return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
}
void filelist_sort(struct FileList *filelist)
@@ -716,7 +760,7 @@ void filelist_sort(struct FileList *filelist)
sort_cb,
&(struct FileSortData){.inverted = (filelist->flags & FL_SORT_INVERT) != 0});
- filelist_filter_clear(filelist);
+ filelist_tag_needs_filtering(filelist);
filelist->flags &= ~FL_NEED_SORTING;
}
}
@@ -809,105 +853,184 @@ static bool is_filtered_hidden(const char *filename,
return false;
}
-static bool is_filtered_file(FileListInternEntry *file,
- const char *UNUSED(root),
- FileListFilter *filter)
+/**
+ * Apply the filter string as file path matching pattern.
+ * \return true when the file should be in the result set, false if it should be filtered out.
+ */
+static bool is_filtered_file_relpath(const FileListInternEntry *file, const FileListFilter *filter)
{
- bool is_filtered = !is_filtered_hidden(file->relpath, filter, file);
+ if (filter->filter_search[0] == '\0') {
+ return true;
+ }
- if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) {
- /* We only check for types if some type are enabled in filtering. */
- if (filter->filter && (filter->flags & FLF_DO_FILTER)) {
- if (file->typeflag & FILE_TYPE_DIR) {
- if (file->typeflag &
- (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
- if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
- is_filtered = false;
- }
- }
- else {
- if (!(filter->filter & FILE_TYPE_FOLDER)) {
- is_filtered = false;
- }
+ /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
+ return fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) == 0;
+}
+
+/** \return true when the file should be in the result set, false if it should be filtered out. */
+static bool is_filtered_file_type(const FileListInternEntry *file, const FileListFilter *filter)
+{
+ if (is_filtered_hidden(file->relpath, filter, file)) {
+ return false;
+ }
+
+ if (FILENAME_IS_CURRPAR(file->relpath)) {
+ return false;
+ }
+
+ /* We only check for types if some type are enabled in filtering. */
+ if (filter->filter && (filter->flags & FLF_DO_FILTER)) {
+ if (file->typeflag & FILE_TYPE_DIR) {
+ if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
+ if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
+ return false;
}
}
else {
- if (!(file->typeflag & filter->filter)) {
- is_filtered = false;
+ if (!(filter->filter & FILE_TYPE_FOLDER)) {
+ return false;
}
}
}
- /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
- if (is_filtered && (filter->filter_search[0] != '\0')) {
- if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
- is_filtered = false;
+ else {
+ if (!(file->typeflag & filter->filter)) {
+ return false;
}
}
}
+ return true;
+}
- return is_filtered;
+/** \return true when the file should be in the result set, false if it should be filtered out. */
+static bool is_filtered_file(FileListInternEntry *file,
+ const char *UNUSED(root),
+ FileListFilter *filter)
+{
+ return is_filtered_file_type(file, filter) && is_filtered_file_relpath(file, filter);
}
-static bool is_filtered_id_file(const FileListInternEntry *file,
- const char *id_group,
- const char *name,
- const FileListFilter *filter)
+static bool is_filtered_id_file_type(const FileListInternEntry *file,
+ const char *id_group,
+ const char *name,
+ const FileListFilter *filter)
{
- bool is_filtered = !is_filtered_hidden(file->relpath, filter, file);
- if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) {
- /* We only check for types if some type are enabled in filtering. */
- if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) {
- if (file->typeflag & FILE_TYPE_DIR) {
- if (file->typeflag &
- (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
- if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
- is_filtered = false;
- }
- }
- else {
- if (!(filter->filter & FILE_TYPE_FOLDER)) {
- is_filtered = false;
- }
- }
+ if (!is_filtered_file_type(file, filter)) {
+ return false;
+ }
+
+ /* We only check for types if some type are enabled in filtering. */
+ if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) {
+ if (id_group) {
+ if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) {
+ return false;
}
- if (is_filtered && id_group) {
- if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) {
- is_filtered = false;
- }
- else {
- uint64_t filter_id = groupname_to_filter_id(id_group);
- if (!(filter_id & filter->filter_id)) {
- is_filtered = false;
- }
- }
+
+ uint64_t filter_id = groupname_to_filter_id(id_group);
+ if (!(filter_id & filter->filter_id)) {
+ return false;
}
}
- /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
- if (is_filtered && (filter->filter_search[0] != '\0')) {
- if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
- is_filtered = false;
- }
+ }
+
+ return true;
+}
+
+/**
+ * Get the asset metadata of a file, if it represents an asset. This may either be of a local ID
+ * (ID in the current #Main) or read from an external asset library.
+ */
+static AssetMetaData *filelist_file_internal_get_asset_data(const FileListInternEntry *file)
+{
+ const ID *local_id = file->local_data.id;
+ return local_id ? local_id->asset_data : file->imported_asset_data;
+}
+
+static void prepare_filter_asset_library(const FileList *filelist, FileListFilter *filter)
+{
+ /* Not used yet for the asset view template. */
+ if (!filter->asset_catalog_filter) {
+ return;
+ }
+ BLI_assert_msg(filelist->asset_library,
+ "prepare_filter_asset_library() should only be called when the file browser is "
+ "in asset browser mode");
+
+ file_ensure_updated_catalog_filter_data(filter->asset_catalog_filter, filelist->asset_library);
+}
+
+/**
+ * Return whether at least one tag matches the search filter.
+ * Tags are searched as "entire words", so instead of searching for "tag" in the
+ * filter string, this function searches for " tag ". Assumes the search filter
+ * starts and ends with a space.
+ *
+ * Here the tags on the asset are written in set notation:
+ *
+ * `asset_tag_matches_filter(" some tags ", {"some", "blue"})` -> true
+ * `asset_tag_matches_filter(" some tags ", {"som", "tag"})` -> false
+ * `asset_tag_matches_filter(" some tags ", {})` -> false
+ */
+static bool asset_tag_matches_filter(const char *filter_search, const AssetMetaData *asset_data)
+{
+ LISTBASE_FOREACH (const AssetTag *, asset_tag, &asset_data->tags) {
+ if (BLI_strcasestr(asset_tag->name, filter_search) != NULL) {
+ return true;
}
}
+ return false;
+}
- return is_filtered;
+static bool is_filtered_asset(FileListInternEntry *file, FileListFilter *filter)
+{
+ const AssetMetaData *asset_data = filelist_file_internal_get_asset_data(file);
+
+ /* Not used yet for the asset view template. */
+ if (filter->asset_catalog_filter && !file_is_asset_visible_in_catalog_filter_settings(
+ filter->asset_catalog_filter, asset_data)) {
+ return false;
+ }
+
+ if (filter->filter_search[0] == '\0') {
+ /* If there is no filter text, everything matches. */
+ return true;
+ }
+
+ /* filter->filter_search contains "*the search text*". */
+ char filter_search[66]; /* sizeof(FileListFilter::filter_search) */
+ const size_t string_length = STRNCPY_RLEN(filter_search, filter->filter_search);
+
+ /* When doing a name comparison, get rid of the leading/trailing asterisks. */
+ filter_search[string_length - 1] = '\0';
+ if (BLI_strcasestr(file->name, filter_search + 1) != NULL) {
+ return true;
+ }
+ return asset_tag_matches_filter(filter_search + 1, asset_data);
}
-static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
+static bool is_filtered_lib_type(FileListInternEntry *file,
+ const char *root,
+ FileListFilter *filter)
{
- bool is_filtered;
char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
BLI_join_dirfile(path, sizeof(path), root, file->relpath);
if (BLO_library_path_explode(path, dir, &group, &name)) {
- is_filtered = is_filtered_id_file(file, group, name, filter);
- }
- else {
- is_filtered = is_filtered_file(file, root, filter);
+ return is_filtered_id_file_type(file, group, name, filter);
}
+ return is_filtered_file_type(file, filter);
+}
+
+static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
+{
+ return is_filtered_lib_type(file, root, filter) && is_filtered_file_relpath(file, filter);
+}
- return is_filtered;
+static bool is_filtered_asset_library(FileListInternEntry *file,
+ const char *root,
+ FileListFilter *filter)
+{
+ return is_filtered_lib_type(file, root, filter) && is_filtered_asset(file, filter);
}
static bool is_filtered_main(FileListInternEntry *file,
@@ -922,10 +1045,11 @@ static bool is_filtered_main_assets(FileListInternEntry *file,
FileListFilter *filter)
{
/* "Filtered" means *not* being filtered out... So return true if the file should be visible. */
- return is_filtered_id_file(file, file->relpath, file->name, filter);
+ return is_filtered_id_file_type(file, file->relpath, file->name, filter) &&
+ is_filtered_asset(file, filter);
}
-static void filelist_filter_clear(FileList *filelist)
+void filelist_tag_needs_filtering(FileList *filelist)
{
filelist->flags |= FL_NEED_FILTERING;
}
@@ -955,6 +1079,10 @@ void filelist_filter(FileList *filelist)
}
}
+ if (filelist->prepare_filter_fn) {
+ filelist->prepare_filter_fn(filelist, &filelist->filter_data);
+ }
+
filtered_tmp = MEM_mallocN(sizeof(*filtered_tmp) * (size_t)num_files, __func__);
/* Filter remap & count how many files are left after filter in a single loop. */
@@ -1033,7 +1161,33 @@ void filelist_setfilter_options(FileList *filelist,
if (update) {
/* And now, free filtered data so that we know we have to filter again. */
- filelist_filter_clear(filelist);
+ filelist_tag_needs_filtering(filelist);
+ }
+}
+
+void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
+{
+ BLI_assert(filelist);
+ BLI_assert(indexer);
+
+ filelist->indexer = indexer;
+}
+
+void filelist_set_asset_catalog_filter_options(
+ FileList *filelist,
+ eFileSel_Params_AssetCatalogVisibility catalog_visibility,
+ const bUUID *catalog_id)
+{
+ if (!filelist->filter_data.asset_catalog_filter) {
+ /* There's no filter data yet. */
+ filelist->filter_data.asset_catalog_filter = file_create_asset_catalog_filter_settings();
+ }
+
+ const bool needs_update = file_set_asset_catalog_filter_settings(
+ filelist->filter_data.asset_catalog_filter, catalog_visibility, *catalog_id);
+
+ if (needs_update) {
+ filelist_tag_needs_filtering(filelist);
}
}
@@ -1058,9 +1212,6 @@ static bool filelist_compare_asset_libraries(const AssetLibraryReference *librar
return true;
}
-/**
- * \param asset_library_ref: May be NULL to unset the library.
- */
void filelist_setlibrary(FileList *filelist, const AssetLibraryReference *asset_library_ref)
{
/* Unset if needed. */
@@ -1238,7 +1389,7 @@ static int filelist_geticon_ex(const FileDirEntry *file,
}
if (typeflag & FILE_TYPE_BLENDER) {
- return ICON_FILE_BLEND;
+ return (is_main || file->preview_icon_id) ? ICON_FILE_BLEND : ICON_BLENDER;
}
if (typeflag & FILE_TYPE_BLENDER_BACKUP) {
return ICON_FILE_BACKUP;
@@ -1304,6 +1455,11 @@ int ED_file_icon(const FileDirEntry *file)
filelist_geticon_ex(file, NULL, false, false);
}
+static bool filelist_intern_entry_is_main_file(const FileListInternEntry *intern_entry)
+{
+ return intern_entry->local_data.id != NULL;
+}
+
/* ********** Main ********** */
static void parent_dir_until_exists_or_default_root(char *dir)
@@ -1399,8 +1555,6 @@ static void filelist_direntryarr_free(FileDirEntryArr *array)
#endif
array->nbr_entries = FILEDIR_NBR_ENTRIES_UNSET;
array->nbr_entries_filtered = FILEDIR_NBR_ENTRIES_UNSET;
- array->entry_idx_start = -1;
- array->entry_idx_end = -1;
}
static void filelist_intern_entry_free(FileListInternEntry *entry)
@@ -1434,6 +1588,26 @@ static void filelist_intern_free(FileListIntern *filelist_intern)
MEM_SAFE_FREE(filelist_intern->filtered);
}
+/**
+ * \return the number of main files removed.
+ */
+static int filelist_intern_free_main_files(FileListIntern *filelist_intern)
+{
+ int removed_counter = 0;
+ LISTBASE_FOREACH_MUTABLE (FileListInternEntry *, entry, &filelist_intern->entries) {
+ if (!filelist_intern_entry_is_main_file(entry)) {
+ continue;
+ }
+
+ BLI_remlink(&filelist_intern->entries, entry);
+ filelist_intern_entry_free(entry);
+ removed_counter++;
+ }
+
+ MEM_SAFE_FREE(filelist_intern->filtered);
+ return removed_counter;
+}
+
static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata)
{
FileListEntryCache *cache = BLI_task_pool_user_data(pool);
@@ -1441,74 +1615,54 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat
FileListEntryPreview *preview = preview_taskdata->preview;
ThumbSource source = 0;
- bool done = false;
// printf("%s: Start (%d)...\n", __func__, threadid);
- if (preview->in_memory_preview) {
- if (BKE_previewimg_is_finished(preview->in_memory_preview, ICON_SIZE_PREVIEW)) {
- ImBuf *imbuf = BKE_previewimg_to_imbuf(preview->in_memory_preview, ICON_SIZE_PREVIEW);
- if (imbuf) {
- preview->icon_id = BKE_icon_imbuf_create(imbuf);
- }
- done = true;
- }
- }
- else {
- // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
- BLI_assert(preview->flags &
- (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER |
- FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
-
- if (preview->flags & FILE_TYPE_IMAGE) {
- source = THB_SOURCE_IMAGE;
- }
- else if (preview->flags &
- (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
- source = THB_SOURCE_BLEND;
- }
- else if (preview->flags & FILE_TYPE_MOVIE) {
- source = THB_SOURCE_MOVIE;
- }
- else if (preview->flags & FILE_TYPE_FTFONT) {
- source = THB_SOURCE_FONT;
- }
+ // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
+ BLI_assert(preview->flags &
+ (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER |
+ FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
- IMB_thumb_path_lock(preview->path);
- /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate
- * in case user switch to a bigger preview size. */
- ImBuf *imbuf = IMB_thumb_manage(preview->path, THB_LARGE, source);
- IMB_thumb_path_unlock(preview->path);
- if (imbuf) {
- preview->icon_id = BKE_icon_imbuf_create(imbuf);
- }
-
- done = true;
+ if (preview->flags & FILE_TYPE_IMAGE) {
+ source = THB_SOURCE_IMAGE;
+ }
+ else if (preview->flags &
+ (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
+ source = THB_SOURCE_BLEND;
+ }
+ else if (preview->flags & FILE_TYPE_MOVIE) {
+ source = THB_SOURCE_MOVIE;
+ }
+ else if (preview->flags & FILE_TYPE_FTFONT) {
+ source = THB_SOURCE_FONT;
}
- if (done) {
- /* That way task freeing function won't free th preview, since it does not own it anymore. */
- atomic_cas_ptr((void **)&preview_taskdata->preview, preview, NULL);
- BLI_thread_queue_push(cache->previews_done, preview);
- atomic_fetch_and_sub_z(&cache->previews_todo_count, 1);
+ IMB_thumb_path_lock(preview->path);
+ /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate
+ * in case user switch to a bigger preview size. */
+ ImBuf *imbuf = IMB_thumb_manage(preview->path, THB_LARGE, source);
+ IMB_thumb_path_unlock(preview->path);
+ if (imbuf) {
+ preview->icon_id = BKE_icon_imbuf_create(imbuf);
}
+ /* Move ownership to the done queue. */
+ preview_taskdata->preview = NULL;
+
+ BLI_thread_queue_push(cache->previews_done, preview);
+
// printf("%s: End (%d)...\n", __func__, threadid);
}
static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
FileListEntryPreviewTaskData *preview_taskdata = taskdata;
- FileListEntryPreview *preview = preview_taskdata->preview;
- /* preview_taskdata->preview is atomically set to NULL once preview has been processed and sent
- * to previews_done queue. */
- if (preview != NULL) {
- if (preview->icon_id) {
- BKE_icon_delete(preview->icon_id);
- }
- MEM_freeN(preview);
+ /* In case the preview wasn't moved to the "done" queue yet. */
+ if (preview_taskdata->preview) {
+ MEM_freeN(preview_taskdata->preview);
}
+
MEM_freeN(preview_taskdata);
}
@@ -1537,6 +1691,7 @@ static void filelist_cache_previews_clear(FileListEntryCache *cache)
}
MEM_freeN(preview);
}
+ cache->previews_todo_count = 0;
}
}
@@ -1574,7 +1729,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
return;
}
- if (entry->flags & FILE_ENTRY_INVALID_PREVIEW) {
+ if (entry->flags & (FILE_ENTRY_INVALID_PREVIEW | FILE_ENTRY_PREVIEW_LOADING)) {
return;
}
@@ -1583,33 +1738,51 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
return;
}
- FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__);
FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
-
- if (entry->redirection_path) {
- BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR);
- }
- else {
- BLI_join_dirfile(
- preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
+ PreviewImage *preview_in_memory = intern_entry->local_data.preview_image;
+ if (preview_in_memory && !BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW)) {
+ /* Nothing to set yet. Wait for next call. */
+ return;
}
+ filelist_cache_preview_ensure_running(cache);
+ entry->flags |= FILE_ENTRY_PREVIEW_LOADING;
+
+ FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__);
preview->index = index;
preview->flags = entry->typeflag;
- preview->in_memory_preview = intern_entry->local_data.preview_image;
preview->icon_id = 0;
- // printf("%s: %d - %s\n", __func__, preview->index, preview->path);
- filelist_cache_preview_ensure_running(cache);
+ if (preview_in_memory) {
+ /* TODO(mano-wii): No need to use the thread API here. */
+ BLI_assert(BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW));
+ preview->path[0] = '\0';
+ ImBuf *imbuf = BKE_previewimg_to_imbuf(preview_in_memory, ICON_SIZE_PREVIEW);
+ if (imbuf) {
+ preview->icon_id = BKE_icon_imbuf_create(imbuf);
+ }
+ BLI_thread_queue_push(cache->previews_done, preview);
+ }
+ else {
+ if (entry->redirection_path) {
+ BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR);
+ }
+ else {
+ BLI_join_dirfile(
+ preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
+ }
+ // printf("%s: %d - %s\n", __func__, preview->index, preview->path);
- FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata),
- __func__);
- preview_taskdata->preview = preview;
- BLI_task_pool_push(cache->previews_pool,
- filelist_cache_preview_runf,
- preview_taskdata,
- true,
- filelist_cache_preview_freef);
+ FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata),
+ __func__);
+ preview_taskdata->preview = preview;
+ BLI_task_pool_push(cache->previews_pool,
+ filelist_cache_preview_runf,
+ preview_taskdata,
+ true,
+ filelist_cache_preview_freef);
+ }
+ cache->previews_todo_count++;
}
static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size)
@@ -1718,31 +1891,38 @@ void filelist_settype(FileList *filelist, short type)
filelist->type = type;
filelist->tags = 0;
+ filelist->indexer = &file_indexer_noop;
switch (filelist->type) {
case FILE_MAIN:
filelist->check_dir_fn = filelist_checkdir_main;
filelist->read_job_fn = filelist_readjob_main;
+ filelist->prepare_filter_fn = NULL;
filelist->filter_fn = is_filtered_main;
break;
case FILE_LOADLIB:
filelist->check_dir_fn = filelist_checkdir_lib;
filelist->read_job_fn = filelist_readjob_lib;
+ filelist->prepare_filter_fn = NULL;
filelist->filter_fn = is_filtered_lib;
break;
case FILE_ASSET_LIBRARY:
filelist->check_dir_fn = filelist_checkdir_lib;
filelist->read_job_fn = filelist_readjob_asset_library;
- filelist->filter_fn = is_filtered_lib;
+ filelist->prepare_filter_fn = prepare_filter_asset_library;
+ filelist->filter_fn = is_filtered_asset_library;
+ filelist->tags |= FILELIST_TAGS_USES_MAIN_DATA;
break;
case FILE_MAIN_ASSET:
filelist->check_dir_fn = filelist_checkdir_main_assets;
filelist->read_job_fn = filelist_readjob_main_assets;
+ filelist->prepare_filter_fn = prepare_filter_asset_library;
filelist->filter_fn = is_filtered_main_assets;
filelist->tags |= FILELIST_TAGS_USES_MAIN_DATA | FILELIST_TAGS_NO_THREADS;
break;
default:
filelist->check_dir_fn = filelist_checkdir_dir;
filelist->read_job_fn = filelist_readjob_dir;
+ filelist->prepare_filter_fn = NULL;
filelist->filter_fn = is_filtered_file;
break;
}
@@ -1750,6 +1930,13 @@ void filelist_settype(FileList *filelist, short type)
filelist->flags |= FL_FORCE_RESET;
}
+static void filelist_clear_asset_library(FileList *filelist)
+{
+ /* The AssetLibraryService owns the AssetLibrary pointer, so no need for us to free it. */
+ filelist->asset_library = NULL;
+ file_delete_asset_catalog_filter_settings(&filelist->filter_data.asset_catalog_filter);
+}
+
void filelist_clear_ex(struct FileList *filelist,
const bool do_asset_library,
const bool do_cache,
@@ -1759,7 +1946,7 @@ void filelist_clear_ex(struct FileList *filelist,
return;
}
- filelist_filter_clear(filelist);
+ filelist_tag_needs_filtering(filelist);
if (do_cache) {
filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
@@ -1773,19 +1960,60 @@ void filelist_clear_ex(struct FileList *filelist,
BLI_ghash_clear(filelist->selection_state, NULL, NULL);
}
- if (do_asset_library && (filelist->asset_library != NULL)) {
- /* There is no way to refresh the catalogs stored by the AssetLibrary struct, so instead of
- * "clearing" it, the entire struct is freed. It will be reallocated when needed. */
- BKE_asset_library_free(filelist->asset_library);
- filelist->asset_library = NULL;
+ if (do_asset_library) {
+ filelist_clear_asset_library(filelist);
+ }
+}
+
+static void filelist_clear_main_files(FileList *filelist,
+ const bool do_asset_library,
+ const bool do_cache,
+ const bool do_selection)
+{
+ if (!filelist || !(filelist->tags & FILELIST_TAGS_USES_MAIN_DATA)) {
+ return;
+ }
+
+ filelist_tag_needs_filtering(filelist);
+
+ if (do_cache) {
+ filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
+ }
+
+ const int removed_files = filelist_intern_free_main_files(&filelist->filelist_intern);
+
+ filelist->filelist.nbr_entries -= removed_files;
+ filelist->filelist.nbr_entries_filtered = FILEDIR_NBR_ENTRIES_UNSET;
+ BLI_assert(filelist->filelist.nbr_entries > FILEDIR_NBR_ENTRIES_UNSET);
+
+ if (do_selection && filelist->selection_state) {
+ BLI_ghash_clear(filelist->selection_state, NULL, NULL);
+ }
+
+ if (do_asset_library) {
+ filelist_clear_asset_library(filelist);
}
}
-void filelist_clear(struct FileList *filelist)
+void filelist_clear(FileList *filelist)
{
filelist_clear_ex(filelist, true, true, true);
}
+void filelist_clear_from_reset_tag(FileList *filelist)
+{
+ /* Do a full clear if needed. */
+ if (filelist->flags & FL_FORCE_RESET) {
+ filelist_clear(filelist);
+ return;
+ }
+
+ if (filelist->flags & FL_FORCE_RESET_MAIN_FILES) {
+ filelist_clear_main_files(filelist, false, true, false);
+ return;
+ }
+}
+
void filelist_free(struct FileList *filelist)
{
if (!filelist) {
@@ -1809,6 +2037,11 @@ void filelist_free(struct FileList *filelist)
filelist->flags &= ~(FL_NEED_SORTING | FL_NEED_FILTERING);
}
+AssetLibrary *filelist_asset_library(FileList *filelist)
+{
+ return filelist->asset_library;
+}
+
void filelist_freelib(struct FileList *filelist)
{
if (filelist->libfiledata) {
@@ -1834,7 +2067,7 @@ static char *fileentry_uiname(const char *root,
BLI_join_dirfile(abspath, sizeof(abspath), root, relpath);
name = BLF_display_name_from_file(abspath);
if (name) {
- /* Allocated string, so no need to BLI_strdup.*/
+ /* Allocated string, so no need to #BLI_strdup. */
return name;
}
}
@@ -1873,9 +2106,6 @@ bool filelist_is_dir(struct FileList *filelist, const char *path)
return filelist->check_dir_fn(filelist, (char *)path, false);
}
-/**
- * May modify in place given r_dir, which is expected to be FILE_MAX_LIBEXTRA length.
- */
void filelist_setdir(struct FileList *filelist, char *r_dir)
{
const bool allow_invalid = filelist->asset_library_ref != NULL;
@@ -1902,7 +2132,7 @@ void filelist_setrecursion(struct FileList *filelist, const int recursion_level)
bool filelist_needs_force_reset(FileList *filelist)
{
- return (filelist->flags & FL_FORCE_RESET) != 0;
+ return (filelist->flags & (FL_FORCE_RESET | FL_FORCE_RESET_MAIN_FILES)) != 0;
}
void filelist_tag_force_reset(FileList *filelist)
@@ -1910,6 +2140,14 @@ void filelist_tag_force_reset(FileList *filelist)
filelist->flags |= FL_FORCE_RESET;
}
+void filelist_tag_force_reset_mainfiles(FileList *filelist)
+{
+ if (!(filelist->tags & FILELIST_TAGS_USES_MAIN_DATA)) {
+ return;
+ }
+ filelist->flags |= FL_FORCE_RESET_MAIN_FILES;
+}
+
bool filelist_is_ready(struct FileList *filelist)
{
return (filelist->flags & FL_IS_READY) != 0;
@@ -1925,12 +2163,6 @@ bool filelist_needs_reset_on_main_changes(const FileList *filelist)
return (filelist->tags & FILELIST_TAGS_USES_MAIN_DATA) != 0;
}
-/**
- * Limited version of full update done by space_file's file_refresh(),
- * to be used by operators and such.
- * Ensures given filelist is ready to be used (i.e. it is filtered and sorted),
- * unless it is tagged for a full refresh.
- */
int filelist_files_ensure(FileList *filelist)
{
if (!filelist_needs_force_reset(filelist) || !filelist_needs_reading(filelist)) {
@@ -2043,10 +2275,6 @@ FileDirEntry *filelist_file(struct FileList *filelist, int index)
return filelist_file_ex(filelist, index, true);
}
-/**
- * Find a file from a file name, or more precisely, its file-list relative path, inside the
- * filtered items. \return The index of the found file or -1.
- */
int filelist_file_find_path(struct FileList *filelist, const char *filename)
{
if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) {
@@ -2067,10 +2295,6 @@ int filelist_file_find_path(struct FileList *filelist, const char *filename)
return -1;
}
-/**
- * Find a file representing \a id.
- * \return The index of the found file or -1.
- */
int filelist_file_find_id(const FileList *filelist, const ID *id)
{
if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) {
@@ -2087,9 +2311,6 @@ int filelist_file_find_id(const FileList *filelist, const ID *id)
return -1;
}
-/**
- * Get the ID a file represents (if any). For #FILE_MAIN, #FILE_MAIN_ASSET.
- */
ID *filelist_file_get_id(const FileDirEntry *file)
{
return file->id;
@@ -2185,7 +2406,6 @@ static void filelist_file_cache_block_release(struct FileList *filelist,
}
}
-/* Load in cache all entries "around" given index (as much as block cache may hold). */
bool filelist_file_cache_block(struct FileList *filelist, const int index)
{
FileListEntryCache *cache = &filelist->filelist_cache;
@@ -2452,27 +2672,31 @@ bool filelist_cache_previews_update(FileList *filelist)
// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
- if (preview->icon_id) {
- /* Due to asynchronous process, a preview for a given image may be generated several times,
- * i.e. entry->image may already be set at this point. */
- if (entry && !entry->preview_icon_id) {
+ if (entry) {
+ if (preview->icon_id) {
+ /* The FILE_ENTRY_PREVIEW_LOADING flag should have prevented any other asynchronous
+ * process from trying to generate the same preview icon. */
+ BLI_assert_msg(!entry->preview_icon_id, "Preview icon should not have been generated yet");
+
/* Move ownership over icon. */
entry->preview_icon_id = preview->icon_id;
preview->icon_id = 0;
changed = true;
}
else {
- BKE_icon_delete(preview->icon_id);
+ /* We want to avoid re-processing this entry continuously!
+ * Note that, since entries only live in cache,
+ * preview will be retried quite often anyway. */
+ entry->flags |= FILE_ENTRY_INVALID_PREVIEW;
}
+ entry->flags &= ~FILE_ENTRY_PREVIEW_LOADING;
}
- else if (entry) {
- /* We want to avoid re-processing this entry continuously!
- * Note that, since entries only live in cache,
- * preview will be retried quite often anyway. */
- entry->flags |= FILE_ENTRY_INVALID_PREVIEW;
+ else {
+ BKE_icon_delete(preview->icon_id);
}
MEM_freeN(preview);
+ cache->previews_todo_count--;
}
return changed;
@@ -2494,7 +2718,7 @@ bool filelist_cache_previews_done(FileList *filelist)
}
return (cache->previews_pool == NULL) || (cache->previews_done == NULL) ||
- (cache->previews_todo_count == (size_t)BLI_thread_queue_len(cache->previews_done));
+ (cache->previews_todo_count == 0);
}
/* would recognize .blend as well */
@@ -2525,8 +2749,6 @@ static bool file_is_blend_backup(const char *str)
return retval;
}
-/* TODO: Maybe we should move this to BLI?
- * On the other hand, it's using defines from space-file area, so not sure... */
int ED_path_extension_type(const char *path)
{
if (BLO_has_bfile_extension(path)) {
@@ -2639,9 +2861,10 @@ int ED_file_extension_icon(const char *path)
}
}
-int filelist_needs_reading(struct FileList *filelist)
+int filelist_needs_reading(FileList *filelist)
{
- return (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET);
+ return (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET) ||
+ filelist_needs_force_reset(filelist);
}
uint filelist_entry_select_set(const FileList *filelist,
@@ -2753,9 +2976,6 @@ bool filelist_entry_is_selected(FileList *filelist, const int index)
return selection_state != 0;
}
-/**
- * Set selection of the '..' parent entry, but only if it's actually visible.
- */
void filelist_entry_parent_select_set(FileList *filelist,
FileSelType select,
uint flag,
@@ -2766,7 +2986,6 @@ void filelist_entry_parent_select_set(FileList *filelist,
}
}
-/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group)
{
return BLO_library_path_explode(filelist->filelist.root, dir, r_group, NULL);
@@ -2922,6 +3141,29 @@ static FileListInternEntry *filelist_readjob_list_lib_group_create(const int idc
return entry;
}
+static void filelist_readjob_list_lib_add_datablock(ListBase *entries,
+ const BLODataBlockInfo *datablock_info,
+ const bool prefix_relpath_with_group_name,
+ const int idcode,
+ const char *group_name)
+{
+ FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
+ if (prefix_relpath_with_group_name) {
+ entry->relpath = BLI_sprintfN("%s/%s", group_name, datablock_info->name);
+ }
+ else {
+ entry->relpath = BLI_strdup(datablock_info->name);
+ }
+ entry->typeflag |= FILE_TYPE_BLENDERLIB;
+ if (datablock_info && datablock_info->asset_data) {
+ entry->typeflag |= FILE_TYPE_ASSET;
+ /* Moves ownership! */
+ entry->imported_asset_data = datablock_info->asset_data;
+ }
+ entry->blentype = idcode;
+ BLI_addtail(entries, entry);
+}
+
static void filelist_readjob_list_lib_add_datablocks(ListBase *entries,
LinkNode *datablock_infos,
const bool prefix_relpath_with_group_name,
@@ -2929,29 +3171,71 @@ static void filelist_readjob_list_lib_add_datablocks(ListBase *entries,
const char *group_name)
{
for (LinkNode *ln = datablock_infos; ln; ln = ln->next) {
- struct BLODataBlockInfo *info = ln->link;
- FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
- if (prefix_relpath_with_group_name) {
- entry->relpath = BLI_sprintfN("%s/%s", group_name, info->name);
- }
- else {
- entry->relpath = BLI_strdup(info->name);
- }
- entry->typeflag |= FILE_TYPE_BLENDERLIB;
- if (info && info->asset_data) {
- entry->typeflag |= FILE_TYPE_ASSET;
- /* Moves ownership! */
- entry->imported_asset_data = info->asset_data;
- }
- entry->blentype = idcode;
+ struct BLODataBlockInfo *datablock_info = ln->link;
+ filelist_readjob_list_lib_add_datablock(
+ entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name);
+ }
+}
+
+static void filelist_readjob_list_lib_add_from_indexer_entries(
+ ListBase *entries,
+ const FileIndexerEntries *indexer_entries,
+ const bool prefix_relpath_with_group_name)
+{
+ for (const LinkNode *ln = indexer_entries->entries; ln; ln = ln->next) {
+ const FileIndexerEntry *indexer_entry = (const FileIndexerEntry *)ln->link;
+ const char *group_name = BKE_idtype_idcode_to_name(indexer_entry->idcode);
+ filelist_readjob_list_lib_add_datablock(entries,
+ &indexer_entry->datablock_info,
+ prefix_relpath_with_group_name,
+ indexer_entry->idcode,
+ group_name);
+ }
+}
+
+static FileListInternEntry *filelist_readjob_list_lib_navigate_to_parent_entry_create(void)
+{
+ FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
+ entry->relpath = BLI_strdup(FILENAME_PARENT);
+ entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR);
+ return entry;
+}
+
+/**
+ * Structure to keep the file indexer and its user data together.
+ */
+typedef struct FileIndexer {
+ const FileIndexerType *callbacks;
+
+ /**
+ * User data. Contains the result of `callbacks.init_user_data`.
+ */
+ void *user_data;
+} FileIndexer;
+
+static int filelist_readjob_list_lib_populate_from_index(ListBase *entries,
+ const ListLibOptions options,
+ const int read_from_index,
+ const FileIndexerEntries *indexer_entries)
+{
+ int navigate_to_parent_len = 0;
+ if (options & LIST_LIB_ADD_PARENT) {
+ FileListInternEntry *entry = filelist_readjob_list_lib_navigate_to_parent_entry_create();
BLI_addtail(entries, entry);
+ navigate_to_parent_len = 1;
}
+
+ filelist_readjob_list_lib_add_from_indexer_entries(entries, indexer_entries, true);
+ return read_from_index + navigate_to_parent_len;
}
static int filelist_readjob_list_lib(const char *root,
ListBase *entries,
- const ListLibOptions options)
+ const ListLibOptions options,
+ FileIndexer *indexer_runtime)
{
+ BLI_assert(indexer_runtime);
+
char dir[FILE_MAX_LIBEXTRA], *group;
struct BlendHandle *libfiledata = NULL;
@@ -2959,13 +3243,37 @@ static int filelist_readjob_list_lib(const char *root,
/* Check if the given root is actually a library. All folders are passed to
* `filelist_readjob_list_lib` and based on the number of found entries `filelist_readjob_do`
* will do a dir listing only when this function does not return any entries. */
- /* TODO: We should consider introducing its own function to detect if it is a lib and
+ /* TODO(jbakker): We should consider introducing its own function to detect if it is a lib and
* call it directly from `filelist_readjob_do` to increase readability. */
const bool is_lib = BLO_library_path_explode(root, dir, &group, NULL);
if (!is_lib) {
return 0;
}
+ const bool group_came_from_path = group != NULL;
+
+ /* Try read from indexer_runtime. */
+ /* Indexing returns all entries in a blend file. We should ignore the index when listing a group
+ * inside a blend file, so the `entries` isn't filled with undesired entries.
+ * This happens when linking or appending data-blocks, where you can navigate into a group (ie
+ * Materials/Objects) where you only want to work with partial indexes.
+ *
+ * Adding support for partial reading/updating indexes would increase the complexity.
+ */
+ const bool use_indexer = !group_came_from_path;
+ FileIndexerEntries indexer_entries = {NULL};
+ if (use_indexer) {
+ int read_from_index = 0;
+ eFileIndexerResult indexer_result = indexer_runtime->callbacks->read_index(
+ dir, &indexer_entries, &read_from_index, indexer_runtime->user_data);
+ if (indexer_result == FILE_INDEXER_ENTRIES_LOADED) {
+ int entries_read = filelist_readjob_list_lib_populate_from_index(
+ entries, options, read_from_index, &indexer_entries);
+ ED_file_indexer_entries_clear(&indexer_entries);
+ return entries_read;
+ }
+ }
+
/* Open the library file. */
BlendFileReadReport bf_reports = {.reports = NULL};
libfiledata = BLO_blendhandle_from_file(dir, &bf_reports);
@@ -2974,18 +3282,18 @@ static int filelist_readjob_list_lib(const char *root,
}
/* Add current parent when requested. */
- int parent_len = 0;
+ /* Is the navigate to previous level added to the list of entries. When added the return value
+ * should be increased to match the actual number of entries added. It is introduced to keep
+ * the code clean and readable and not counting in a single variable. */
+ int navigate_to_parent_len = 0;
if (options & LIST_LIB_ADD_PARENT) {
- FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
- entry->relpath = BLI_strdup(FILENAME_PARENT);
- entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR);
+ FileListInternEntry *entry = filelist_readjob_list_lib_navigate_to_parent_entry_create();
BLI_addtail(entries, entry);
- parent_len = 1;
+ navigate_to_parent_len = 1;
}
int group_len = 0;
int datablock_len = 0;
- const bool group_came_from_path = group != NULL;
if (group_came_from_path) {
const int idcode = groupname_to_code(group);
LinkNode *datablock_infos = BLO_blendhandle_get_datablock_info(
@@ -3010,6 +3318,10 @@ static int filelist_readjob_list_lib(const char *root,
libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &group_datablock_len);
filelist_readjob_list_lib_add_datablocks(
entries, group_datablock_infos, true, idcode, group_name);
+ if (use_indexer) {
+ ED_file_indexer_entries_extend_from_datablock_infos(
+ &indexer_entries, group_datablock_infos, idcode);
+ }
BLI_linklist_freeN(group_datablock_infos);
datablock_len += group_datablock_len;
}
@@ -3020,8 +3332,14 @@ static int filelist_readjob_list_lib(const char *root,
BLO_blendhandle_close(libfiledata);
+ /* Update the index. */
+ if (use_indexer) {
+ indexer_runtime->callbacks->update_index(dir, &indexer_entries, indexer_runtime->user_data);
+ ED_file_indexer_entries_clear(&indexer_entries);
+ }
+
/* Return the number of items added to entries. */
- int added_entries_len = group_len + datablock_len + parent_len;
+ int added_entries_len = group_len + datablock_len + navigate_to_parent_len;
return added_entries_len;
}
@@ -3204,21 +3522,45 @@ typedef struct FileListReadJob {
char main_name[FILE_MAX];
Main *current_main;
struct FileList *filelist;
+ /** Set to request a partial read that only adds files representing #Main data (IDs). Used when
+ * #Main may have received changes of interest (e.g. asset removed or renamed). */
+ bool only_main_data;
/** Shallow copy of #filelist for thread-safe access.
*
* The job system calls #filelist_readjob_update which moves any read file from #tmp_filelist
* into #filelist in a thread-safe way.
*
- * #tmp_filelist also keeps an `AssetLibrary *` so that it can be loaded in the same thread, and
- * moved to #filelist once all categories are loaded.
+ * #tmp_filelist also keeps an `AssetLibrary *` so that it can be loaded in the same thread,
+ * and moved to #filelist once all categories are loaded.
*
- * NOTE: #tmp_filelist is freed in #filelist_readjob_free, so any copied pointers need to be set
- * to NULL to avoid double-freeing them. */
+ * NOTE: #tmp_filelist is freed in #filelist_readjob_free, so any copied pointers need to be
+ * set to NULL to avoid double-freeing them. */
struct FileList *tmp_filelist;
} FileListReadJob;
+static void filelist_readjob_append_entries(FileListReadJob *job_params,
+ ListBase *from_entries,
+ int nbr_from_entries,
+ short *do_update)
+{
+ BLI_assert(BLI_listbase_count(from_entries) == nbr_from_entries);
+ if (nbr_from_entries <= 0) {
+ *do_update = false;
+ return;
+ }
+
+ FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
+ BLI_mutex_lock(&job_params->lock);
+ BLI_movelisttolist(&filelist->filelist.entries, from_entries);
+ filelist->filelist.nbr_entries += nbr_from_entries;
+ BLI_mutex_unlock(&job_params->lock);
+
+ *do_update = true;
+}
+
static bool filelist_readjob_should_recurse_into_entry(const int max_recursion,
+ const bool is_lib,
const int current_recursion_level,
FileListInternEntry *entry)
{
@@ -3226,10 +3568,16 @@ static bool filelist_readjob_should_recurse_into_entry(const int max_recursion,
/* Recursive loading is disabled. */
return false;
}
- if (current_recursion_level >= max_recursion) {
+ if (!is_lib && current_recursion_level > max_recursion) {
/* No more levels of recursion left. */
return false;
}
+ /* Show entries when recursion is set to `Blend file` even when `current_recursion_level`
+ * exceeds `max_recursion`. */
+ if (!is_lib && (current_recursion_level >= max_recursion) &&
+ ((entry->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) == 0)) {
+ return false;
+ }
if (entry->typeflag & FILE_TYPE_BLENDERLIB) {
/* Libraries are already loaded recursively when recursive loaded is used. No need to add
* them another time. This loading is done with the `LIST_LIB_RECURSIVE` option. */
@@ -3247,11 +3595,11 @@ static bool filelist_readjob_should_recurse_into_entry(const int max_recursion,
return true;
}
-static void filelist_readjob_do(const bool do_lib,
- FileListReadJob *job_params,
- const short *stop,
- short *do_update,
- float *progress)
+static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
+ FileListReadJob *job_params,
+ const short *stop,
+ short *do_update,
+ float *progress)
{
FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
ListBase entries = {0};
@@ -3263,13 +3611,6 @@ static void filelist_readjob_do(const bool do_lib,
const int max_recursion = filelist->max_recursion;
int nbr_done_dirs = 0, nbr_todo_dirs = 1;
- // BLI_assert(filelist->filtered == NULL);
- BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) &&
- (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET));
-
- /* A valid, but empty directory from now. */
- filelist->filelist.nbr_entries = 0;
-
todo_dirs = BLI_stack_new(sizeof(*td_dir), __func__);
td_dir = BLI_stack_push_r(todo_dirs);
td_dir->level = 1;
@@ -3280,6 +3621,12 @@ static void filelist_readjob_do(const bool do_lib,
BLI_path_normalize_dir(job_params->main_name, dir);
td_dir->dir = BLI_strdup(dir);
+ /* Init the file indexer. */
+ FileIndexer indexer_runtime = {.callbacks = filelist->indexer};
+ if (indexer_runtime.callbacks->init_user_data) {
+ indexer_runtime.user_data = indexer_runtime.callbacks->init_user_data(dir, sizeof(dir));
+ }
+
while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) {
FileListInternEntry *entry;
int nbr_entries = 0;
@@ -3318,11 +3665,12 @@ static void filelist_readjob_do(const bool do_lib,
list_lib_options |= LIST_LIB_RECURSIVE;
}
/* Only load assets when browsing an asset library. For normal file browsing we return all
- * entries. `FLF_ASSETS_ONLY` filter can be enabled/disabled by the user.*/
+ * entries. `FLF_ASSETS_ONLY` filter can be enabled/disabled by the user. */
if (filelist->asset_library_ref) {
list_lib_options |= LIST_LIB_ASSETS_ONLY;
}
- nbr_entries = filelist_readjob_list_lib(subdir, &entries, list_lib_options);
+ nbr_entries = filelist_readjob_list_lib(
+ subdir, &entries, list_lib_options, &indexer_runtime);
if (nbr_entries > 0) {
is_lib = true;
}
@@ -3345,7 +3693,8 @@ static void filelist_readjob_do(const bool do_lib,
entry->name = fileentry_uiname(root, entry->relpath, entry->typeflag, dir);
entry->free_name = true;
- if (filelist_readjob_should_recurse_into_entry(max_recursion, recursion_level, entry)) {
+ if (filelist_readjob_should_recurse_into_entry(
+ max_recursion, is_lib, recursion_level, entry)) {
/* We have a directory we want to list, add it to todo list! */
BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath);
BLI_path_normalize_dir(job_params->main_name, dir);
@@ -3356,22 +3705,22 @@ static void filelist_readjob_do(const bool do_lib,
}
}
- if (nbr_entries) {
- BLI_mutex_lock(&job_params->lock);
-
- *do_update = true;
-
- BLI_movelisttolist(&filelist->filelist.entries, &entries);
- filelist->filelist.nbr_entries += nbr_entries;
-
- BLI_mutex_unlock(&job_params->lock);
- }
+ filelist_readjob_append_entries(job_params, &entries, nbr_entries, do_update);
nbr_done_dirs++;
*progress = (float)nbr_done_dirs / (float)nbr_todo_dirs;
MEM_freeN(subdir);
}
+ /* Finalize and free indexer. */
+ if (indexer_runtime.callbacks->filelist_finished && BLI_stack_is_empty(todo_dirs)) {
+ indexer_runtime.callbacks->filelist_finished(indexer_runtime.user_data);
+ }
+ if (indexer_runtime.callbacks->free_user_data && indexer_runtime.user_data) {
+ indexer_runtime.callbacks->free_user_data(indexer_runtime.user_data);
+ indexer_runtime.user_data = NULL;
+ }
+
/* If we were interrupted by stop, stack may not be empty and we need to free
* pending dir paths. */
while (!BLI_stack_is_empty(todo_dirs)) {
@@ -3382,6 +3731,24 @@ static void filelist_readjob_do(const bool do_lib,
BLI_stack_free(todo_dirs);
}
+static void filelist_readjob_do(const bool do_lib,
+ FileListReadJob *job_params,
+ const short *stop,
+ short *do_update,
+ float *progress)
+{
+ FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
+
+ // BLI_assert(filelist->filtered == NULL);
+ BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) &&
+ (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET));
+
+ /* A valid, but empty directory from now. */
+ filelist->filelist.nbr_entries = 0;
+
+ filelist_readjob_recursive_dir_add_items(do_lib, job_params, stop, do_update, progress);
+}
+
static void filelist_readjob_dir(FileListReadJob *job_params,
short *stop,
short *do_update,
@@ -3419,59 +3786,43 @@ static void filelist_readjob_load_asset_library_data(FileListReadJob *job_params
{
FileList *tmp_filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
- if (job_params->filelist->asset_library_ref != NULL) {
- char library_root_path[FILE_MAX];
- filelist_asset_library_path(job_params, library_root_path);
+ *do_update = false;
- /* Load asset catalogs, into the temp filelist for thread-safety.
- * #filelist_readjob_endjob() will move it into the real filelist. */
- tmp_filelist->asset_library = BKE_asset_library_load(library_root_path);
- *do_update = true;
+ if (job_params->filelist->asset_library_ref == NULL) {
+ return;
+ }
+ if (tmp_filelist->asset_library != NULL) {
+ /* Asset library already loaded. */
+ return;
}
-}
-static void filelist_readjob_asset_library(FileListReadJob *job_params,
- short *stop,
- short *do_update,
- float *progress)
-{
- filelist_readjob_load_asset_library_data(job_params, do_update);
- filelist_readjob_lib(job_params, stop, do_update, progress);
-}
+ char library_root_path[FILE_MAX];
+ filelist_asset_library_path(job_params, library_root_path);
-static void filelist_readjob_main(FileListReadJob *job_params,
- short *stop,
- short *do_update,
- float *progress)
-{
- /* TODO! */
- filelist_readjob_dir(job_params, stop, do_update, progress);
+ /* Load asset catalogs, into the temp filelist for thread-safety.
+ * #filelist_readjob_endjob() will move it into the real filelist. */
+ tmp_filelist->asset_library = BKE_asset_library_load(library_root_path);
+ *do_update = true;
}
-/**
- * \warning Acts on main, so NOT thread-safe!
- */
-static void filelist_readjob_main_assets(FileListReadJob *job_params,
- short *UNUSED(stop),
- short *do_update,
- float *UNUSED(progress))
+static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params,
+ short *UNUSED(stop),
+ short *do_update,
+ float *UNUSED(progress))
{
FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
- BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) &&
- (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET));
-
- filelist_readjob_load_asset_library_data(job_params, do_update);
-
- /* A valid, but empty directory from now. */
- filelist->filelist.nbr_entries = 0;
FileListInternEntry *entry;
ListBase tmp_entries = {0};
ID *id_iter;
int nbr_entries = 0;
+ /* Make sure no IDs are added/removed/reallocated in the main thread while this is running in
+ * parallel. */
+ BKE_main_lock(job_params->current_main);
+
FOREACH_MAIN_ID_BEGIN (job_params->current_main, id_iter) {
- if (!id_iter->asset_data) {
+ if (!id_iter->asset_data || ID_IS_LINKED(id_iter)) {
continue;
}
@@ -3492,16 +3843,93 @@ static void filelist_readjob_main_assets(FileListReadJob *job_params,
}
FOREACH_MAIN_ID_END;
+ BKE_main_unlock(job_params->current_main);
+
if (nbr_entries) {
*do_update = true;
BLI_movelisttolist(&filelist->filelist.entries, &tmp_entries);
filelist->filelist.nbr_entries += nbr_entries;
- filelist->filelist.nbr_entries_filtered = filelist->filelist.entry_idx_start =
- filelist->filelist.entry_idx_end = -1;
+ filelist->filelist.nbr_entries_filtered = -1;
}
}
+/**
+ * Check if \a bmain is stored within the root path of \a filelist. This means either directly or
+ * in some nested directory. In other words, it checks if the \a filelist root path is contained in
+ * the path to \a bmain.
+ * This is irrespective of the recursion level displayed, it basically assumes unlimited recursion
+ * levels.
+ */
+static bool filelist_contains_main(const FileList *filelist, const Main *bmain)
+{
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
+ return blendfile_path[0] && BLI_path_contains(filelist->filelist.root, blendfile_path);
+}
+
+static void filelist_readjob_asset_library(FileListReadJob *job_params,
+ short *stop,
+ short *do_update,
+ float *progress)
+{
+ FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
+
+ BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) &&
+ (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET));
+
+ /* A valid, but empty file-list from now. */
+ filelist->filelist.nbr_entries = 0;
+
+ /* NOP if already read. */
+ filelist_readjob_load_asset_library_data(job_params, do_update);
+
+ if (filelist_contains_main(filelist, job_params->current_main)) {
+ filelist_readjob_main_assets_add_items(job_params, stop, do_update, progress);
+ }
+ if (!job_params->only_main_data) {
+ filelist_readjob_recursive_dir_add_items(true, job_params, stop, do_update, progress);
+ }
+}
+
+static void filelist_readjob_main(FileListReadJob *job_params,
+ short *stop,
+ short *do_update,
+ float *progress)
+{
+ /* TODO! */
+ filelist_readjob_dir(job_params, stop, do_update, progress);
+}
+
+static void filelist_readjob_main_assets(FileListReadJob *job_params,
+ short *stop,
+ short *do_update,
+ float *progress)
+{
+ FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
+ BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) &&
+ (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET));
+
+ filelist_readjob_load_asset_library_data(job_params, do_update);
+
+ /* A valid, but empty file-list from now. */
+ filelist->filelist.nbr_entries = 0;
+
+ filelist_readjob_main_assets_add_items(job_params, stop, do_update, progress);
+}
+
+/**
+ * Check if the read-job is requesting a partial reread of the file list only.
+ */
+static bool filelist_readjob_is_partial_read(const FileListReadJob *read_job)
+{
+ return read_job->only_main_data;
+}
+
+/**
+ * \note This may trigger partial filelist reading. If the #FL_FORCE_RESET_MAIN_FILES flag is set,
+ * some current entries are kept and we just call the readjob to update the main files (see
+ * #FileListReadJob.only_main_data).
+ */
static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update, float *progress)
{
FileListReadJob *flrj = flrjv;
@@ -3512,8 +3940,6 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update
BLI_mutex_lock(&flrj->lock);
BLI_assert((flrj->tmp_filelist == NULL) && flrj->filelist);
- BLI_assert_msg(flrj->filelist->asset_library == NULL,
- "Asset library should not yet be assigned at start of read job");
flrj->tmp_filelist = MEM_dupallocN(flrj->filelist);
@@ -3522,18 +3948,29 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update
flrj->tmp_filelist->filelist_intern.filtered = NULL;
BLI_listbase_clear(&flrj->tmp_filelist->filelist_intern.entries);
- filelist_uid_unset(&flrj->tmp_filelist->filelist_intern.curr_uid);
+ if (filelist_readjob_is_partial_read(flrj)) {
+ /* Don't unset the current UID on partial read, would give duplicates otherwise. */
+ }
+ else {
+ filelist_uid_unset(&flrj->tmp_filelist->filelist_intern.curr_uid);
+ }
flrj->tmp_filelist->libfiledata = NULL;
memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache));
flrj->tmp_filelist->selection_state = NULL;
flrj->tmp_filelist->asset_library_ref = NULL;
+ flrj->tmp_filelist->filter_data.asset_catalog_filter = NULL;
BLI_mutex_unlock(&flrj->lock);
flrj->tmp_filelist->read_job_fn(flrj, stop, do_update, progress);
}
+/**
+ * \note This may update for a partial filelist reading job. If the #FL_FORCE_RESET_MAIN_FILES flag
+ * is set, some current entries are kept and we just call the readjob to update the main
+ * files (see #FileListReadJob.only_main_data).
+ */
static void filelist_readjob_update(void *flrjv)
{
FileListReadJob *flrj = flrjv;
@@ -3555,7 +3992,11 @@ static void filelist_readjob_update(void *flrjv)
if (flrj->tmp_filelist->asset_library) {
flrj->filelist->asset_library = flrj->tmp_filelist->asset_library;
- flrj->tmp_filelist->asset_library = NULL; /* MUST be NULL to avoid double-free. */
+ }
+
+ /* Important for partial reads: Copy increased UID counter back to the real list. */
+ if (flrj->tmp_filelist->filelist_intern.curr_uid > fl_intern->curr_uid) {
+ fl_intern->curr_uid = flrj->tmp_filelist->filelist_intern.curr_uid;
}
BLI_mutex_unlock(&flrj->lock);
@@ -3620,14 +4061,23 @@ void filelist_readjob_start(FileList *filelist, const int space_notifier, const
flrj->filelist = filelist;
flrj->current_main = bmain;
BLI_strncpy(flrj->main_name, BKE_main_blendfile_path(bmain), sizeof(flrj->main_name));
+ if ((filelist->flags & FL_FORCE_RESET_MAIN_FILES) && !(filelist->flags & FL_FORCE_RESET)) {
+ flrj->only_main_data = true;
+ }
- filelist->flags &= ~(FL_FORCE_RESET | FL_IS_READY);
+ filelist->flags &= ~(FL_FORCE_RESET | FL_FORCE_RESET_MAIN_FILES | FL_IS_READY);
filelist->flags |= FL_IS_PENDING;
/* Init even for single threaded execution. Called functions use it. */
BLI_mutex_init(&flrj->lock);
- if (filelist->tags & FILELIST_TAGS_NO_THREADS) {
+ /* The file list type may not support threading so execute immediately. Same when only rereading
+ * #Main data (which we do quite often on changes to #Main, since it's the easiest and safest way
+ * to ensure the displayed data is up to date), because some operations executing right after
+ * main data changed may need access to the ID files (see T93691). */
+ const bool no_threads = (filelist->tags & FILELIST_TAGS_NO_THREADS) || flrj->only_main_data;
+
+ if (no_threads) {
short dummy_stop = false;
short dummy_do_update = false;
float dummy_progress = 0.0f;
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index b51ceee4aa0..696986d4660 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -29,8 +29,10 @@ extern "C" {
struct AssetLibraryReference;
struct BlendHandle;
+struct FileIndexerType;
struct FileList;
struct FileSelection;
+struct bUUID;
struct wmWindowManager;
struct FileDirEntry;
@@ -49,6 +51,7 @@ typedef enum FileCheckType {
CHECK_ALL = 3,
} FileCheckType;
+/* not listbase itself */
void folderlist_free(struct ListBase *folderlist);
void folderlist_popdir(struct ListBase *folderlist, char *dir);
void folderlist_pushdir(struct ListBase *folderlist, const char *dir);
@@ -59,58 +62,105 @@ void folder_history_list_ensure_for_active_browse_mode(struct SpaceFile *sfile);
void folder_history_list_free(struct SpaceFile *sfile);
struct ListBase folder_history_list_duplicate(struct ListBase *listbase);
-void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort);
+void filelist_setsorting(struct FileList *filelist, short sort, bool invert_sort);
void filelist_sort(struct FileList *filelist);
void filelist_setfilter_options(struct FileList *filelist,
- const bool do_filter,
- const bool hide_dot,
- const bool hide_parent,
- const uint64_t filter,
- const uint64_t filter_id,
- const bool filter_assets_only,
+ bool do_filter,
+ bool hide_dot,
+ bool hide_parent,
+ uint64_t filter,
+ uint64_t filter_id,
+ bool filter_assets_only,
const char *filter_glob,
const char *filter_search);
+/**
+ * Set the indexer to be used by the filelist.
+ *
+ * The given indexer allocation should be handled by the caller or defined statically.
+ */
+void filelist_setindexer(struct FileList *filelist, const struct FileIndexerType *indexer);
+/**
+ * \param catalog_id: The catalog that should be filtered by if \a catalog_visibility is
+ * #FILE_SHOW_ASSETS_FROM_CATALOG. May be NULL otherwise.
+ */
+void filelist_set_asset_catalog_filter_options(
+ struct FileList *filelist,
+ eFileSel_Params_AssetCatalogVisibility catalog_visibility,
+ const struct bUUID *catalog_id);
+void filelist_tag_needs_filtering(struct FileList *filelist);
void filelist_filter(struct FileList *filelist);
+/**
+ * \param asset_library_ref: May be NULL to unset the library.
+ */
void filelist_setlibrary(struct FileList *filelist,
const struct AssetLibraryReference *asset_library_ref);
void filelist_init_icons(void);
void filelist_free_icons(void);
-struct ImBuf *filelist_getimage(struct FileList *filelist, const int index);
+struct ImBuf *filelist_getimage(struct FileList *filelist, int index);
struct ImBuf *filelist_file_getimage(const FileDirEntry *file);
struct ImBuf *filelist_geticon_image_ex(const FileDirEntry *file);
-struct ImBuf *filelist_geticon_image(struct FileList *filelist, const int index);
-int filelist_geticon(struct FileList *filelist, const int index, const bool is_main);
+struct ImBuf *filelist_geticon_image(struct FileList *filelist, int index);
+int filelist_geticon(struct FileList *filelist, int index, bool is_main);
struct FileList *filelist_new(short type);
void filelist_settype(struct FileList *filelist, short type);
void filelist_clear(struct FileList *filelist);
void filelist_clear_ex(struct FileList *filelist,
- const bool do_asset_library,
- const bool do_cache,
- const bool do_selection);
+ bool do_asset_library,
+ bool do_cache,
+ bool do_selection);
+/**
+ * A "smarter" version of #filelist_clear() that calls partial clearing based on the filelist
+ * force-reset flags.
+ */
+void filelist_clear_from_reset_tag(struct FileList *filelist);
void filelist_free(struct FileList *filelist);
const char *filelist_dir(struct FileList *filelist);
bool filelist_is_dir(struct FileList *filelist, const char *path);
+/**
+ * May modify in place given r_dir, which is expected to be FILE_MAX_LIBEXTRA length.
+ */
void filelist_setdir(struct FileList *filelist, char *r_dir);
+/**
+ * Limited version of full update done by space_file's file_refresh(),
+ * to be used by operators and such.
+ * Ensures given filelist is ready to be used (i.e. it is filtered and sorted),
+ * unless it is tagged for a full refresh.
+ */
int filelist_files_ensure(struct FileList *filelist);
int filelist_needs_reading(struct FileList *filelist);
FileDirEntry *filelist_file(struct FileList *filelist, int index);
FileDirEntry *filelist_file_ex(struct FileList *filelist, int index, bool use_request);
+/**
+ * Find a file from a file name, or more precisely, its file-list relative path, inside the
+ * filtered items. \return The index of the found file or -1.
+ */
int filelist_file_find_path(struct FileList *filelist, const char *file);
+/**
+ * Find a file representing \a id.
+ * \return The index of the found file or -1.
+ */
int filelist_file_find_id(const struct FileList *filelist, const struct ID *id);
+/**
+ * Get the ID a file represents (if any). For #FILE_MAIN, #FILE_MAIN_ASSET.
+ */
struct ID *filelist_file_get_id(const struct FileDirEntry *file);
bool filelist_uid_is_set(const FileUID uid);
void filelist_uid_unset(FileUID *r_uid);
void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t window_size);
-bool filelist_file_cache_block(struct FileList *filelist, const int index);
+/**
+ * Load in cache all entries "around" given index (as much as block cache may hold).
+ */
+bool filelist_file_cache_block(struct FileList *filelist, int index);
bool filelist_needs_force_reset(struct FileList *filelist);
void filelist_tag_force_reset(struct FileList *filelist);
+void filelist_tag_force_reset_mainfiles(struct FileList *filelist);
bool filelist_pending(struct FileList *filelist);
bool filelist_needs_reset_on_main_changes(const struct FileList *filelist);
bool filelist_is_ready(struct FileList *filelist);
@@ -121,7 +171,7 @@ unsigned int filelist_entry_select_set(const struct FileList *filelist,
unsigned int flag,
FileCheckType check);
void filelist_entry_select_index_set(struct FileList *filelist,
- const int index,
+ int index,
FileSelType select,
unsigned int flag,
FileCheckType check);
@@ -134,17 +184,25 @@ unsigned int filelist_entry_select_get(struct FileList *filelist,
struct FileDirEntry *entry,
FileCheckType check);
unsigned int filelist_entry_select_index_get(struct FileList *filelist,
- const int index,
+ int index,
FileCheckType check);
-bool filelist_entry_is_selected(struct FileList *filelist, const int index);
+bool filelist_entry_is_selected(struct FileList *filelist, int index);
+/**
+ * Set selection of the '..' parent entry, but only if it's actually visible.
+ */
void filelist_entry_parent_select_set(struct FileList *filelist,
FileSelType select,
unsigned int flag,
FileCheckType check);
-void filelist_setrecursion(struct FileList *filelist, const int recursion_level);
+void filelist_setrecursion(struct FileList *filelist, int recursion_level);
+
+struct AssetLibrary *filelist_asset_library(struct FileList *filelist);
struct BlendHandle *filelist_lib(struct FileList *filelist);
+/**
+ * \param dir: Must be #FILE_MAX_LIBEXTRA long!
+ */
bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group);
void filelist_freelib(struct FileList *filelist);
@@ -155,7 +213,7 @@ void filelist_readjob_stop(struct FileList *filelist, struct wmWindowManager *wm
int filelist_readjob_running(struct FileList *filelist, struct wmWindowManager *wm);
bool filelist_cache_previews_update(struct FileList *filelist);
-void filelist_cache_previews_set(struct FileList *filelist, const bool use_previews);
+void filelist_cache_previews_set(struct FileList *filelist, bool use_previews);
bool filelist_cache_previews_running(struct FileList *filelist);
bool filelist_cache_previews_done(struct FileList *filelist);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 2ca08a3105c..f9783d1b19f 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -126,13 +126,10 @@ static void fileselect_ensure_updated_asset_params(SpaceFile *sfile)
FileSelectParams *base_params = &asset_params->base_params;
base_params->file[0] = '\0';
base_params->filter_glob[0] = '\0';
- /* TODO: this way of using filters to form categories is notably slower than specifying a
- * "group" to read. That's because all types are read and filtering is applied afterwards. Would
- * be nice if we could lazy-read individual groups. */
base_params->flag |= U_default.file_space_data.flag | FILE_ASSETS_ONLY | FILE_FILTER;
base_params->flag &= ~FILE_DIRSEL_ONLY;
base_params->filter |= FILE_TYPE_BLENDERLIB;
- base_params->filter_id = FILTER_ID_OB | FILTER_ID_GR;
+ base_params->filter_id = FILTER_ID_ALL;
base_params->display = FILE_IMGDISPLAY;
base_params->sort = FILE_SORT_ALPHA;
/* Asset libraries include all sub-directories, so enable maximal recursion. */
@@ -278,6 +275,9 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile)
if ((prop = RNA_struct_find_property(op->ptr, "filter_usd"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_USD : 0;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "filter_obj"))) {
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_OBJECT_IO : 0;
+ }
if ((prop = RNA_struct_find_property(op->ptr, "filter_volume"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_VOLUME : 0;
}
@@ -321,6 +321,10 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile)
params->flag |= RNA_boolean_get(op->ptr, "active_collection") ? FILE_ACTIVE_COLLECTION : 0;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "allow_path_tokens"))) {
+ params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_PATH_TOKENS_ALLOW : 0;
+ }
+
if ((prop = RNA_struct_find_property(op->ptr, "display_type"))) {
params->display = RNA_property_enum_get(op->ptr, prop);
}
@@ -361,9 +365,6 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile)
return params;
}
-/**
- * If needed, create and return the file select parameters for the active browse mode.
- */
FileSelectParams *ED_fileselect_ensure_active_params(SpaceFile *sfile)
{
switch ((eFileBrowse_Mode)sfile->browse_mode) {
@@ -383,9 +384,6 @@ FileSelectParams *ED_fileselect_ensure_active_params(SpaceFile *sfile)
return NULL;
}
-/**
- * Get the file select parameters for the active browse mode.
- */
FileSelectParams *ED_fileselect_get_active_params(const SpaceFile *sfile)
{
if (!sfile) {
@@ -414,6 +412,15 @@ FileAssetSelectParams *ED_fileselect_get_asset_params(const SpaceFile *sfile)
return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) ? sfile->asset_params : NULL;
}
+bool ED_fileselect_is_local_asset_library(const SpaceFile *sfile)
+{
+ const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
+ if (asset_params == NULL) {
+ return false;
+ }
+ return asset_params->asset_library_ref.type == ASSET_LIBRARY_LOCAL;
+}
+
static void fileselect_refresh_asset_params(FileAssetSelectParams *asset_params)
{
AssetLibraryReference *library = &asset_params->asset_library_ref;
@@ -462,6 +469,15 @@ bool ED_fileselect_is_asset_browser(const SpaceFile *sfile)
return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS);
}
+struct AssetLibrary *ED_fileselect_active_asset_library_get(const SpaceFile *sfile)
+{
+ if (!ED_fileselect_is_asset_browser(sfile) || !sfile->files) {
+ return NULL;
+ }
+
+ return filelist_asset_library(sfile->files);
+}
+
struct ID *ED_fileselect_active_asset_get(const SpaceFile *sfile)
{
if (!ED_fileselect_is_asset_browser(sfile)) {
@@ -477,6 +493,18 @@ struct ID *ED_fileselect_active_asset_get(const SpaceFile *sfile)
return filelist_file_get_id(file);
}
+void ED_fileselect_activate_asset_catalog(const SpaceFile *sfile, const bUUID catalog_id)
+{
+ if (!ED_fileselect_is_asset_browser(sfile)) {
+ return;
+ }
+
+ FileAssetSelectParams *params = ED_fileselect_get_asset_params(sfile);
+ params->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG;
+ params->catalog_id = catalog_id;
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, NULL);
+}
+
static void on_reload_activate_by_id(SpaceFile *sfile, onReloadFnData custom_data)
{
ID *asset_id = (ID *)custom_data;
@@ -508,20 +536,57 @@ void ED_fileselect_activate_by_id(SpaceFile *sfile, ID *asset_id, const bool def
const FileDirEntry *file = filelist_file_ex(files, file_index, false);
if (filelist_file_get_id(file) != asset_id) {
- filelist_entry_select_set(files, file, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
continue;
}
params->active_file = file_index;
filelist_entry_select_set(files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
-
- /* Keep looping to deselect the other files. */
+ break;
}
WM_main_add_notifier(NC_ASSET | NA_ACTIVATED, NULL);
WM_main_add_notifier(NC_ASSET | NA_SELECTED, NULL);
}
+static void on_reload_select_by_relpath(SpaceFile *sfile, onReloadFnData custom_data)
+{
+ const char *relative_path = custom_data;
+ ED_fileselect_activate_by_relpath(sfile, relative_path);
+}
+
+void ED_fileselect_activate_by_relpath(SpaceFile *sfile, const char *relative_path)
+{
+ /* If there are filelist operations running now ("pending" true) or soon ("force reset" true),
+ * there is a fair chance that the to-be-activated file at relative_path will only be present
+ * after these operations have completed. Defer activation until then. */
+ struct FileList *files = sfile->files;
+ if (files == NULL || filelist_pending(files) || filelist_needs_force_reset(files)) {
+ /* Casting away the constness of `relative_path` is safe here, because eventually it just ends
+ * up in another call to this function, and then it's a const char* again. */
+ file_on_reload_callback_register(sfile, on_reload_select_by_relpath, (char *)relative_path);
+ return;
+ }
+
+ FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+ const int num_files_filtered = filelist_files_ensure(files);
+
+ for (int file_index = 0; file_index < num_files_filtered; ++file_index) {
+ const FileDirEntry *file = filelist_file(files, file_index);
+
+ if (STREQ(file->relpath, relative_path)) {
+ params->active_file = file_index;
+ filelist_entry_select_set(files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
+ }
+ }
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+}
+
+void ED_fileselect_deselect_all(SpaceFile *sfile)
+{
+ file_select_deselect_all(sfile, FILE_SEL_SELECTED);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+}
+
/* The subset of FileSelectParams.flag items we store into preferences. Note that FILE_SORT_ALPHA
* may also be remembered, but only conditionally. */
#define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT)
@@ -583,13 +648,6 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile)
}
}
-/**
- * Update the user-preference data for the file space. In fact, this also contains some
- * non-FileSelectParams data, but we can safely ignore this.
- *
- * \param temp_win_size: If the browser was opened in a temporary window,
- * pass its size here so we can store that in the preferences. Otherwise NULL.
- */
void ED_fileselect_params_to_userdef(SpaceFile *sfile,
const int temp_win_size[2],
const bool is_maximized)
@@ -627,9 +685,6 @@ void ED_fileselect_params_to_userdef(SpaceFile *sfile,
}
}
-/**
- * Sets FileSelectParams->file (name of selected file)
- */
void fileselect_file_set(SpaceFile *sfile, const int index)
{
const struct FileDirEntry *file = filelist_file(sfile->files, index);
@@ -750,10 +805,6 @@ int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
return active_file;
}
-/**
- * Get the currently visible bounds of the layout in screen space. Matches View2D.mask minus the
- * top column-header row.
- */
void ED_fileselect_layout_maskrect(const FileLayout *layout, const View2D *v2d, rcti *r_rect)
{
*r_rect = v2d->mask;
@@ -793,9 +844,6 @@ void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y)
}
}
-/**
- * Check if the region coordinate defined by \a x and \a y are inside the column header.
- */
bool file_attribute_column_header_is_inside(const View2D *v2d,
const FileLayout *layout,
int x,
@@ -822,9 +870,6 @@ bool file_attribute_column_type_enabled(const FileSelectParams *params,
}
}
-/**
- * Find the column type at region coordinate given by \a x (y doesn't matter for this).
- */
FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d,
const FileSelectParams *params,
FileLayout *layout,
@@ -936,6 +981,8 @@ static void file_attribute_columns_init(const FileSelectParams *params, FileLayo
void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region)
{
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+ /* Request a slightly more compact layout for asset browsing. */
+ const bool compact = ED_fileselect_is_asset_browser(sfile);
FileLayout *layout = NULL;
View2D *v2d = &region->v2d;
int numfiles;
@@ -955,12 +1002,13 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region)
layout->textheight = textheight;
if (params->display == FILE_IMGDISPLAY) {
+ const float pad_fac = compact ? 0.15f : 0.3f;
layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
- layout->tile_border_x = 0.3f * UI_UNIT_X;
- layout->tile_border_y = 0.3f * UI_UNIT_X;
- layout->prv_border_x = 0.3f * UI_UNIT_X;
- layout->prv_border_y = 0.3f * UI_UNIT_Y;
+ layout->tile_border_x = pad_fac * UI_UNIT_X;
+ layout->tile_border_y = pad_fac * UI_UNIT_X;
+ layout->prv_border_x = pad_fac * UI_UNIT_X;
+ layout->prv_border_y = pad_fac * UI_UNIT_Y;
layout->tile_w = layout->prv_w + 2 * layout->prv_border_x;
layout->tile_h = layout->prv_h + 2 * layout->prv_border_y + textheight;
layout->width = (int)(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x);
@@ -1038,10 +1086,6 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *region)
return sfile->layout;
}
-/**
- * Support updating the directory even when this isn't the active space
- * needed so RNA properties update function isn't context sensitive, see T70255.
- */
void ED_file_change_dir_ex(bContext *C, ScrArea *area)
{
/* May happen when manipulating non-active spaces. */
@@ -1237,12 +1281,6 @@ void file_params_smoothscroll_timer_clear(wmWindowManager *wm, wmWindow *win, Sp
sfile->smoothscroll_timer = NULL;
}
-/**
- * Set the renaming-state to #FILE_PARAMS_RENAME_POSTSCROLL_PENDING and trigger the smooth-scroll
- * timer. To be used right after a file was renamed.
- * Note that the caller is responsible for setting the correct rename-file info
- * (#FileSelectParams.renamefile or #FileSelectParams.rename_id).
- */
void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile)
{
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
@@ -1256,9 +1294,6 @@ void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, Sp
sfile->scroll_offset = 0;
}
-/**
- * To be executed whenever renaming ends (successfully or not).
- */
void file_params_rename_end(wmWindowManager *wm,
wmWindow *win,
SpaceFile *sfile,
@@ -1290,10 +1325,6 @@ static int file_params_find_renamed(const FileSelectParams *params, struct FileL
filelist_file_find_path(filelist, params->renamefile);
}
-/**
- * Helper used by both main update code, and smooth-scroll timer,
- * to try to enable rename editing from #FileSelectParams.renamefile name.
- */
void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
{
BLI_assert(params->rename_flag != 0);
@@ -1305,7 +1336,7 @@ void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
BLI_assert(params->renamefile[0] != '\0' || params->rename_id != NULL);
- const int idx = file_params_find_renamed(params, sfile->files);
+ int idx = file_params_find_renamed(params, sfile->files);
if (idx >= 0) {
FileDirEntry *file = filelist_file(sfile->files, idx);
BLI_assert(file != NULL);
@@ -1318,7 +1349,11 @@ void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
params->rename_flag = FILE_PARAMS_RENAME_ACTIVE;
}
else if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_PENDING) != 0) {
+ /* file_select_deselect_all() will resort and re-filter, so `idx` will probably have changed.
+ * Need to get the correct #FileDirEntry again. */
file_select_deselect_all(sfile, FILE_SEL_SELECTED);
+ idx = file_params_find_renamed(params, sfile->files);
+ file = filelist_file(sfile->files, idx);
filelist_entry_select_set(
sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED | FILE_SEL_HIGHLIGHTED, CHECK_ALL);
params->active_file = idx;
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 776bb0b3bb7..14f596ae7bf 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -185,8 +185,8 @@ static void fsmenu_xdg_user_dirs_free(GHash *xdg_map)
/**
* Add fsmenu entry for system folders on linux.
- * - Check if a path is stored in the GHash generated from user-dirs.dirs
- * - If not, check for a default path in $HOME
+ * - Check if a path is stored in the #GHash generated from `user-dirs.dirs`.
+ * - If not, check for a default path in `$HOME`.
*
* \param key: Use `user-dirs.dirs` format "XDG_EXAMPLE_DIR"
* \param default_path: Directory name to check in $HOME, also used for the menu entry name.
@@ -769,21 +769,22 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
FS_INSERT_LAST);
const char *home = BLI_getenv("HOME");
-
+ if (home) {
# define FS_MACOS_PATH(path, name, icon) \
BLI_snprintf(line, sizeof(line), path, home); \
fsmenu_insert_entry(fsmenu, FS_CATEGORY_OTHER, line, name, icon, FS_INSERT_LAST);
- FS_MACOS_PATH("%s/", NULL, ICON_HOME)
- FS_MACOS_PATH("%s/Desktop/", N_("Desktop"), ICON_DESKTOP)
- FS_MACOS_PATH("%s/Documents/", N_("Documents"), ICON_DOCUMENTS)
- FS_MACOS_PATH("%s/Downloads/", N_("Downloads"), ICON_IMPORT)
- FS_MACOS_PATH("%s/Movies/", N_("Movies"), ICON_FILE_MOVIE)
- FS_MACOS_PATH("%s/Music/", N_("Music"), ICON_FILE_SOUND)
- FS_MACOS_PATH("%s/Pictures/", N_("Pictures"), ICON_FILE_IMAGE)
- FS_MACOS_PATH("%s/Library/Fonts/", N_("Fonts"), ICON_FILE_FONT)
+ FS_MACOS_PATH("%s/", NULL, ICON_HOME)
+ FS_MACOS_PATH("%s/Desktop/", N_("Desktop"), ICON_DESKTOP)
+ FS_MACOS_PATH("%s/Documents/", N_("Documents"), ICON_DOCUMENTS)
+ FS_MACOS_PATH("%s/Downloads/", N_("Downloads"), ICON_IMPORT)
+ FS_MACOS_PATH("%s/Movies/", N_("Movies"), ICON_FILE_MOVIE)
+ FS_MACOS_PATH("%s/Music/", N_("Music"), ICON_FILE_SOUND)
+ FS_MACOS_PATH("%s/Pictures/", N_("Pictures"), ICON_FILE_IMAGE)
+ FS_MACOS_PATH("%s/Library/Fonts/", N_("Fonts"), ICON_FILE_FONT)
# undef FS_MACOS_PATH
+ }
/* Get mounted volumes better method OSX 10.6 and higher, see:
* https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFURLRef/Reference/reference.html
@@ -958,7 +959,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
found = 1;
}
if (endmntent(fp) == 0) {
- fprintf(stderr, "could not close the list of mounted filesystems\n");
+ fprintf(stderr, "could not close the list of mounted file-systems\n");
}
}
/* Check gvfs shares. */
diff --git a/source/blender/editors/space_file/fsmenu.h b/source/blender/editors/space_file/fsmenu.h
index 6296314d40a..0915c9a5a2f 100644
--- a/source/blender/editors/space_file/fsmenu.h
+++ b/source/blender/editors/space_file/fsmenu.h
@@ -42,7 +42,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu,
const char *path,
const char *name,
int icon,
- const enum FSMenuInsert flag);
+ enum FSMenuInsert flag);
/** Refresh 'valid' status of given menu entry */
void fsmenu_entry_refresh_valid(struct FSMenuEntry *fsentry);
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index ac23767f933..470128f61bd 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -27,11 +27,13 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
#include "BLI_utildefines.h"
#include "BKE_appdir.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_screen.h"
@@ -43,6 +45,8 @@
#include "WM_message.h"
#include "WM_types.h"
+#include "ED_asset.h"
+#include "ED_asset_indexer.h"
#include "ED_fileselect.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -54,6 +58,7 @@
#include "UI_view2d.h"
#include "GPU_framebuffer.h"
+#include "file_indexer.h"
#include "file_intern.h" /* own include */
#include "filelist.h"
#include "fsmenu.h"
@@ -303,15 +308,6 @@ static void file_ensure_valid_region_state(bContext *C,
}
}
-/**
- * Tag the space to recreate the file-list.
- */
-static void file_tag_reset_list(ScrArea *area, SpaceFile *sfile)
-{
- filelist_tag_force_reset(sfile->files);
- ED_area_tag_refresh(area);
-}
-
static void file_refresh(const bContext *C, ScrArea *area)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -326,7 +322,7 @@ static void file_refresh(const bContext *C, ScrArea *area)
if (sfile->files && (sfile->tags & FILE_TAG_REBUILD_MAIN_FILES) &&
filelist_needs_reset_on_main_changes(sfile->files)) {
- filelist_tag_force_reset(sfile->files);
+ filelist_tag_force_reset_mainfiles(sfile->files);
}
sfile->tags &= ~FILE_TAG_REBUILD_MAIN_FILES;
@@ -335,9 +331,10 @@ static void file_refresh(const bContext *C, ScrArea *area)
params->highlight_file = -1; /* added this so it opens nicer (ton) */
}
- if (!U.experimental.use_extended_asset_browser && ED_fileselect_is_asset_browser(sfile)) {
- /* Only poses supported as non-experimental right now. */
- params->filter_id = FILTER_ID_AC;
+ if (ED_fileselect_is_asset_browser(sfile)) {
+ /* Ask the asset code for appropriate ID filter flags for the supported assets, and mask others
+ * out. */
+ params->filter_id &= ED_asset_types_supported_as_filter_flags();
}
filelist_settype(sfile->files, params->type);
@@ -355,6 +352,16 @@ static void file_refresh(const bContext *C, ScrArea *area)
(params->flag & FILE_ASSETS_ONLY) != 0,
params->filter_glob,
params->filter_search);
+ if (asset_params) {
+ filelist_set_asset_catalog_filter_options(
+ sfile->files, asset_params->asset_catalog_visibility, &asset_params->catalog_id);
+ }
+
+ if (ED_fileselect_is_asset_browser(sfile)) {
+ const bool use_asset_indexer = !USER_EXPERIMENTAL_TEST(&U, no_asset_indexing);
+ filelist_setindexer(sfile->files,
+ use_asset_indexer ? &file_indexer_asset : &file_indexer_noop);
+ }
/* Update the active indices of bookmarks & co. */
sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir);
@@ -365,7 +372,7 @@ static void file_refresh(const bContext *C, ScrArea *area)
if (filelist_needs_force_reset(sfile->files)) {
filelist_readjob_stop(sfile->files, wm);
- filelist_clear(sfile->files);
+ filelist_clear_from_reset_tag(sfile->files);
}
if (filelist_needs_reading(sfile->files)) {
@@ -427,9 +434,8 @@ static void file_on_reload_callback_call(SpaceFile *sfile)
static void file_reset_filelist_showing_main_data(ScrArea *area, SpaceFile *sfile)
{
if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) {
- /* Full refresh of the file list if local asset data was changed. Refreshing this view
- * is cheap and users expect this to be updated immediately. */
- file_tag_reset_list(area, sfile);
+ filelist_tag_force_reset_mainfiles(sfile->files);
+ ED_area_tag_refresh(area);
}
}
@@ -660,10 +666,10 @@ static void file_main_region_draw(const bContext *C, ARegion *region)
/* on first read, find active file */
if (params->highlight_file == -1) {
wmEvent *event = CTX_wm_window(C)->eventstate;
- file_highlight_set(sfile, region, event->x, event->y);
+ file_highlight_set(sfile, region, event->xy[0], event->xy[1]);
}
- if (!file_draw_hint_if_invalid(sfile, region)) {
+ if (!file_draw_hint_if_invalid(C, sfile, region)) {
file_draw_list(C, region);
}
@@ -890,6 +896,7 @@ const char *file_context_dir[] = {
"active_file",
"selected_files",
"asset_library_ref",
+ "selected_asset_files",
"id",
NULL,
};
@@ -947,6 +954,24 @@ static int /*eContextResult*/ file_context(const bContext *C,
result, &screen->id, &RNA_AssetLibraryReference, &asset_params->asset_library_ref);
return CTX_RESULT_OK;
}
+ /** TODO temporary AssetHandle design: For now this returns the file entry. Would be better if it
+ * was `"selected_assets"` and returned the assets (e.g. as `AssetHandle`) directly. See comment
+ * for #AssetHandle for more info. */
+ if (CTX_data_equals(member, "selected_asset_files")) {
+ const int num_files_filtered = filelist_files_ensure(sfile->files);
+
+ for (int file_index = 0; file_index < num_files_filtered; file_index++) {
+ if (filelist_entry_is_selected(sfile->files, file_index)) {
+ FileDirEntry *entry = filelist_file(sfile->files, file_index);
+ if (entry->asset_data) {
+ CTX_data_list_add(result, &screen->id, &RNA_FileSelectEntry, entry);
+ }
+ }
+ }
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return CTX_RESULT_OK;
+ }
if (CTX_data_equals(member, "id")) {
const FileDirEntry *file = filelist_file(sfile->files, params->active_file);
if (file == NULL) {
@@ -965,7 +990,7 @@ static int /*eContextResult*/ file_context(const bContext *C,
return CTX_RESULT_MEMBER_NOT_FOUND;
}
-static void file_id_remap(ScrArea *area, SpaceLink *sl, ID *UNUSED(old_id), ID *UNUSED(new_id))
+static void file_id_remap(ScrArea *area, SpaceLink *sl, const struct IDRemapper *UNUSED(mappings))
{
SpaceFile *sfile = (SpaceFile *)sl;
@@ -976,7 +1001,6 @@ static void file_id_remap(ScrArea *area, SpaceLink *sl, ID *UNUSED(old_id), ID *
file_reset_filelist_showing_main_data(area, sfile);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_file(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype file");
@@ -1050,6 +1074,7 @@ void ED_spacetype_file(void)
art->init = file_tools_region_init;
art->draw = file_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
+ file_tools_region_panels_register(art);
/* regions: tool properties */
art = MEM_callocN(sizeof(ARegionType), "spacetype file operator region");
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index f4c4b6cafcd..41f74b6ade9 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -19,6 +19,8 @@
/** \file
* \ingroup spgraph
+ *
+ * Graph editor space & buttons.
*/
#include <float.h>
@@ -66,11 +68,11 @@
#include "graph_intern.h" /* own include */
-/* ******************* graph editor space & buttons ************** */
-
#define B_REDR 1
-/* -------------- */
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
static bool graph_panel_context(const bContext *C, bAnimListElem **ale, FCurve **fcu)
{
@@ -120,7 +122,11 @@ static bool graph_panel_poll(const bContext *C, PanelType *UNUSED(pt))
return graph_panel_context(C, NULL, NULL);
}
-/* -------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cursor Header
+ * \{ */
static void graph_panel_cursor_header(const bContext *C, Panel *panel)
{
@@ -174,7 +180,11 @@ static void graph_panel_cursor(const bContext *C, Panel *panel)
uiItemO(sub, IFACE_("Cursor Value to Selection"), ICON_NONE, "GRAPH_OT_snap_cursor_value");
}
-/* ******************* active F-Curve ************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Active F-Curve
+ * \{ */
static void graph_panel_properties(const bContext *C, Panel *panel)
{
@@ -243,7 +253,11 @@ static void graph_panel_properties(const bContext *C, Panel *panel)
MEM_freeN(ale);
}
-/* ******************* active Keyframe ************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Active Keyframe
+ * \{ */
/* get 'active' keyframe for panel editing */
static bool get_active_fcurve_keyframe_edit(const FCurve *fcu,
@@ -593,24 +607,28 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
else {
if ((fcu->bezt == NULL) && (fcu->modifiers.first)) {
/* modifiers only - so no keyframes to be active */
- uiItemL(layout, IFACE_("F-Curve only has F-Modifiers"), ICON_NONE);
- uiItemL(layout, IFACE_("See Modifiers panel below"), ICON_INFO);
+ uiItemL(layout, TIP_("F-Curve only has F-Modifiers"), ICON_NONE);
+ uiItemL(layout, TIP_("See Modifiers panel below"), ICON_INFO);
}
else if (fcu->fpt) {
/* samples only */
uiItemL(layout,
- IFACE_("F-Curve doesn't have any keyframes as it only contains sampled points"),
+ TIP_("F-Curve doesn't have any keyframes as it only contains sampled points"),
ICON_NONE);
}
else {
- uiItemL(layout, IFACE_("No active keyframe on F-Curve"), ICON_NONE);
+ uiItemL(layout, TIP_("No active keyframe on F-Curve"), ICON_NONE);
}
}
MEM_freeN(ale);
}
-/* ******************* drivers ******************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drivers
+ * \{ */
#define B_IPO_DEPCHANGE 10
@@ -688,28 +706,30 @@ static void driver_dvar_invalid_name_query_cb(bContext *C, void *dvar_v, void *U
DriverVar *dvar = (DriverVar *)dvar_v;
if (dvar->flag & DVAR_FLAG_INVALID_EMPTY) {
- uiItemL(layout, "It cannot be left blank", ICON_ERROR);
+ uiItemL(layout, TIP_("It cannot be left blank"), ICON_ERROR);
}
if (dvar->flag & DVAR_FLAG_INVALID_START_NUM) {
- uiItemL(layout, "It cannot start with a number", ICON_ERROR);
+ uiItemL(layout, TIP_("It cannot start with a number"), ICON_ERROR);
}
if (dvar->flag & DVAR_FLAG_INVALID_START_CHAR) {
uiItemL(layout,
- "It cannot start with a special character,"
- " including '$', '@', '!', '~', '+', '-', '_', '.', or ' '",
+ TIP_("It cannot start with a special character,"
+ " including '$', '@', '!', '~', '+', '-', '_', '.', or ' '"),
ICON_NONE);
}
if (dvar->flag & DVAR_FLAG_INVALID_HAS_SPACE) {
- uiItemL(layout, "It cannot contain spaces (e.g. 'a space')", ICON_ERROR);
+ uiItemL(layout, TIP_("It cannot contain spaces (e.g. 'a space')"), ICON_ERROR);
}
if (dvar->flag & DVAR_FLAG_INVALID_HAS_DOT) {
- uiItemL(layout, "It cannot contain dots (e.g. 'a.dot')", ICON_ERROR);
+ uiItemL(layout, TIP_("It cannot contain dots (e.g. 'a.dot')"), ICON_ERROR);
}
if (dvar->flag & DVAR_FLAG_INVALID_HAS_SPECIAL) {
- uiItemL(layout, "It cannot contain special (non-alphabetical/numeric) characters", ICON_ERROR);
+ uiItemL(layout,
+ TIP_("It cannot contain special (non-alphabetical/numeric) characters"),
+ ICON_ERROR);
}
if (dvar->flag & DVAR_FLAG_INVALID_PY_KEYWORD) {
- uiItemL(layout, "It cannot be a reserved keyword in Python", ICON_INFO);
+ uiItemL(layout, TIP_("It cannot be a reserved keyword in Python"), ICON_INFO);
}
UI_popup_menu_end(C, pup);
@@ -922,7 +942,7 @@ static void graph_draw_driven_property_panel(uiLayout *layout, ID *id, FCurve *f
uiItemL(row, id->name + 2, icon);
/* -> user friendly 'name' for F-Curve/driver target */
- uiItemL(row, "", ICON_SMALL_TRI_RIGHT_VEC);
+ uiItemL(row, "", ICON_RIGHTARROW);
uiItemL(row, name, ICON_RNA);
}
@@ -1318,8 +1338,13 @@ static void graph_panel_drivers_popover(const bContext *C, Panel *panel)
uiItemO(layout, IFACE_("Show in Drivers Editor"), ICON_DRIVER, "SCREEN_OT_drivers_editor_show");
}
-/* ******************* F-Modifiers ******************************** */
-/* All the drawing code is in editors/animation/fmodifier_ui.c */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name F-Curve Modifiers
+ *
+ * \note All the drawing code is in `editors/animation/fmodifier_ui.c`
+ * \{ */
#define B_FMODIFIER_REDRAW 20
/** The start of FModifier panels registered for the graph editor. */
@@ -1378,7 +1403,11 @@ static void graph_panel_modifiers(const bContext *C, Panel *panel)
MEM_freeN(ale);
}
-/* ******************* general ******************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Registration
+ * \{ */
void graph_buttons_register(ARegionType *art)
{
@@ -1454,3 +1483,5 @@ void graph_buttons_register(ARegionType *art)
pt->draw_header = graph_panel_cursor_header;
BLI_addtail(&art->paneltypes, pt);
}
+
+/** \} */
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index af88bbced9c..ed5993c77a7 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -1060,21 +1060,21 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
-
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
-
- immUniform1i("colors_len", 0); /* Simple dashes. */
if (BKE_fcurve_is_protected(fcu)) {
- /* protected curves (non editable) are drawn with dotted lines */
+ /* Protected curves (non editable) are drawn with dotted lines. */
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+ immUniform1i("colors_len", 0); /* Simple dashes. */
immUniform1f("dash_width", 4.0f);
immUniform1f("dash_factor", 0.5f);
}
else {
- immUniform1f("dash_factor", 2.0f); /* solid line */
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniform2fv("viewportSize", &viewport_size[2]);
+ immUniform1f("lineWidth", GPU_line_width_get());
}
if (((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) || (fcu->flag & FCURVE_MUTED)) {
@@ -1314,9 +1314,6 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
/* Public Curve-Drawing API ---------------- */
-/* Draw the 'ghost' F-Curves (i.e. snapshots of the curve)
- * NOTE: unit mapping has already been applied to the values, so do not try and apply again
- */
void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region)
{
FCurve *fcu;
@@ -1364,9 +1361,6 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region
GPU_blend(GPU_BLEND_NONE);
}
-/* This is called twice from space_graph.c -> graph_main_region_draw()
- * Unselected then selected F-Curves are drawn so that they do not occlude each other.
- */
void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, short sel)
{
ListBase anim_data = {NULL, NULL};
@@ -1408,7 +1402,6 @@ void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, shor
/** \name Channel List
* \{ */
-/* left hand part */
void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region)
{
ListBase anim_data = {NULL, NULL};
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 872b17372de..9675901ead3 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -19,6 +19,8 @@
/** \file
* \ingroup spgraph
+ *
+ * Insert duplicate and bake keyframes.
*/
#include <float.h>
@@ -69,9 +71,6 @@
#include "graph_intern.h"
-/* ************************************************************************** */
-/* INSERT DUPLICATE AND BAKE KEYFRAMES */
-
/* -------------------------------------------------------------------- */
/** \name Insert Keyframes Operator
* \{ */
@@ -403,8 +402,8 @@ static int graphkeys_click_insert_invoke(bContext *C, wmOperator *op, const wmEv
region = ac.region;
v2d = &region->v2d;
- mval[0] = (event->x - region->winrct.xmin);
- mval[1] = (event->y - region->winrct.ymin);
+ mval[0] = (event->xy[0] - region->winrct.xmin);
+ mval[1] = (event->xy[1] - region->winrct.ymin);
UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
@@ -1880,7 +1879,7 @@ static bool euler_filter_single_channel(FCurve *fcu)
return false;
}
- /* Prev follows bezt, bezt = "current" point to be fixed. */
+ /* `prev` follows bezt, bezt = "current" point to be fixed. */
/* Our method depends on determining a "difference" from the previous vert. */
bool is_modified = false;
for (i = 1, prev = fcu->bezt, bezt = fcu->bezt + 1; i < fcu->totvert; i++, prev = bezt++) {
@@ -2354,6 +2353,103 @@ void GRAPH_OT_snap(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Equalize Handles Operator
+ * \{ */
+
+/* Defines for equalize handles tool. */
+static const EnumPropertyItem prop_graphkeys_equalize_handles_sides[] = {
+ {GRAPHKEYS_EQUALIZE_LEFT, "LEFT", 0, "Left", "Equalize selected keyframes' left handles"},
+ {GRAPHKEYS_EQUALIZE_RIGHT, "RIGHT", 0, "Right", "Equalize selected keyframes' right handles"},
+ {GRAPHKEYS_EQUALIZE_BOTH, "BOTH", 0, "Both", "Equalize both of a keyframe's handles"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+/* ------------------- */
+
+/* Equalize selected keyframes' bezier handles. */
+static void equalize_graph_keys(bAnimContext *ac, int mode, float handle_length, bool flatten)
+{
+ /* Filter data. */
+ const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_NODUPLIS);
+ ListBase anim_data = {NULL, NULL};
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* Equalize keyframes. */
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
+ ANIM_fcurve_equalize_keyframes_loop(ale->key_data, mode, handle_length, flatten);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
+static int graphkeys_equalize_handles_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ /* Get editor data. */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Get equalize mode. */
+ int mode = RNA_enum_get(op->ptr, "side");
+ float handle_length = RNA_float_get(op->ptr, "handle_length");
+ bool flatten = RNA_boolean_get(op->ptr, "flatten");
+
+ /* Equalize graph keyframes. */
+ equalize_graph_keys(&ac, mode, handle_length, flatten);
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GRAPH_OT_equalize_handles(wmOperatorType *ot)
+{
+ /* Identifiers */
+ ot->name = "Equalize Handles";
+ ot->idname = "GRAPH_OT_equalize_handles";
+ ot->description =
+ "Ensure selected keyframes' handles have equal length, optionally making them horizontal";
+
+ /* API callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = graphkeys_equalize_handles_exec;
+ ot->poll = graphop_editable_keyframes_poll;
+
+ /* Flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Properties */
+ ot->prop = RNA_def_enum(ot->srna,
+ "side",
+ prop_graphkeys_equalize_handles_sides,
+ 0,
+ "Side",
+ "Side of the keyframes' bezier handles to affect");
+ RNA_def_float(ot->srna,
+ "handle_length",
+ 5.0f,
+ 0.1f,
+ FLT_MAX,
+ "Handle Length",
+ "Length to make selected keyframes' bezier handles",
+ 1.0f,
+ 50.0f);
+ RNA_def_boolean(
+ ot->srna,
+ "flatten",
+ false,
+ "Flatten",
+ "Make the values of the selected keyframes' handles the same as their respective keyframes");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Mirror Keyframes Operator
* \{ */
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index 7add2f7cbb8..a59fb63dd22 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -34,12 +34,23 @@ struct bContext;
/* ***************************************** */
/* graph_draw.c */
+/**
+ * Left hand part.
+ */
void graph_draw_channel_names(struct bContext *C, struct bAnimContext *ac, struct ARegion *region);
+/**
+ * This is called twice from space_graph.c -> graph_main_region_draw()
+ * Unselected then selected F-Curves are drawn so that they do not occlude each other.
+ */
void graph_draw_curves(struct bAnimContext *ac,
struct SpaceGraph *sipo,
struct ARegion *region,
short sel);
+/**
+ * Draw the 'ghost' F-Curves (i.e. snapshots of the curve)
+ * \note unit mapping has already been applied to the values, so do not try and apply again.
+ */
void graph_draw_ghost_curves(struct bAnimContext *ac,
struct SpaceGraph *sipo,
struct ARegion *region);
@@ -47,6 +58,17 @@ void graph_draw_ghost_curves(struct bAnimContext *ac,
/* ***************************************** */
/* graph_select.c */
+/**
+ * Deselects keyframes in the Graph Editor
+ * - This is called by the deselect all operator, as well as other ones!
+ *
+ * - test: check if select or deselect all
+ * - sel: how to select keyframes
+ * 0 = deselect
+ * 1 = select
+ * 2 = invert
+ * - do_channels: whether to affect selection status of channels
+ */
void deselect_graph_keys(struct bAnimContext *ac, bool test, short sel, bool do_channels);
void GRAPH_OT_select_all(struct wmOperatorType *ot);
@@ -78,13 +100,17 @@ enum eGraphKeys_ColumnSelect_Mode {
/* ***************************************** */
/* graph_edit.c */
+/**
+ * Get the min/max keyframes.
+ * \note it should return total bound-box, filter for selection only can be argument.
+ */
void get_graph_keyframe_extents(struct bAnimContext *ac,
float *xmin,
float *xmax,
float *ymin,
float *ymax,
- const bool do_sel_only,
- const bool include_handles);
+ bool do_sel_only,
+ bool include_handles);
void GRAPH_OT_previewrange_set(struct wmOperatorType *ot);
void GRAPH_OT_view_all(struct wmOperatorType *ot);
@@ -100,6 +126,8 @@ void GRAPH_OT_paste(struct wmOperatorType *ot);
void GRAPH_OT_duplicate(struct wmOperatorType *ot);
void GRAPH_OT_delete(struct wmOperatorType *ot);
void GRAPH_OT_clean(struct wmOperatorType *ot);
+void GRAPH_OT_blend_to_neighbor(struct wmOperatorType *ot);
+void GRAPH_OT_breakdown(struct wmOperatorType *ot);
void GRAPH_OT_decimate(struct wmOperatorType *ot);
void GRAPH_OT_sample(struct wmOperatorType *ot);
void GRAPH_OT_bake(struct wmOperatorType *ot);
@@ -116,6 +144,7 @@ void GRAPH_OT_easing_type(struct wmOperatorType *ot);
void GRAPH_OT_frame_jump(struct wmOperatorType *ot);
void GRAPH_OT_snap_cursor_value(struct wmOperatorType *ot);
void GRAPH_OT_snap(struct wmOperatorType *ot);
+void GRAPH_OT_equalize_handles(struct wmOperatorType *ot);
void GRAPH_OT_mirror(struct wmOperatorType *ot);
/* defines for snap keyframes
@@ -130,6 +159,15 @@ enum eGraphKeys_Snap_Mode {
GRAPHKEYS_SNAP_VALUE,
};
+/* Defines for equalize keyframe handles.
+ * NOTE: Keep in sync with eEditKeyframes_Equalize (in ED_keyframes_edit.h).
+ */
+enum eGraphKeys_Equalize_Mode {
+ GRAPHKEYS_EQUALIZE_LEFT = 1,
+ GRAPHKEYS_EQUALIZE_RIGHT,
+ GRAPHKEYS_EQUALIZE_BOTH,
+};
+
/* defines for mirror keyframes
* NOTE: keep in sync with eEditKeyframes_Mirror (in ED_keyframes_edit.h)
*/
@@ -166,12 +204,36 @@ void graph_buttons_register(struct ARegionType *art);
/* ***************************************** */
/* graph_utils.c */
+/**
+ * Find 'active' F-Curve.
+ * It must be editable, since that's the purpose of these buttons (subject to change).
+ * We return the 'wrapper' since it contains valuable context info (about hierarchy),
+ * which will need to be freed when the caller is done with it.
+ *
+ * \note curve-visible flag isn't included,
+ * otherwise selecting a curve via list to edit is too cumbersome.
+ */
struct bAnimListElem *get_active_fcurve_channel(struct bAnimContext *ac);
+/**
+ * Check if there are any visible keyframes (for selection tools).
+ */
bool graphop_visible_keyframes_poll(struct bContext *C);
+/**
+ * Check if there are any visible + editable keyframes (for editing tools).
+ */
bool graphop_editable_keyframes_poll(struct bContext *C);
+/**
+ * Has active F-Curve that's editable.
+ */
bool graphop_active_fcurve_poll(struct bContext *C);
+/**
+ * Has active F-Curve in the context that's editable.
+ */
bool graphop_active_editable_fcurve_ctx_poll(struct bContext *C);
+/**
+ * Has selected F-Curve that's editable.
+ */
bool graphop_selected_fcurve_poll(struct bContext *C);
/* ***************************************** */
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 32396a70cce..7606dcc60cf 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -52,11 +52,13 @@
/* ************************** view-based operators **********************************/
/* XXX should these really be here? */
-/* Set Cursor --------------------------------------------------------------------- */
-/* The 'cursor' in the Graph Editor consists of two parts:
+/* -------------------------------------------------------------------- */
+/** \name Set Cursor
+ *
+ * The 'cursor' in the Graph Editor consists of two parts:
* 1) Current Frame Indicator (as per ANIM_OT_change_frame)
* 2) Value Indicator (stored per Graph Editor instance)
- */
+ * \{ */
static bool graphview_cursor_poll(bContext *C)
{
@@ -225,7 +227,11 @@ static void GRAPH_OT_cursor_set(wmOperatorType *ot)
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Value", "", -100.0f, 100.0f);
}
-/* Hide/Reveal ------------------------------------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hide/Reveal
+ * \{ */
static int graphview_curves_hide_exec(bContext *C, wmOperator *op)
{
@@ -413,7 +419,11 @@ static void GRAPH_OT_reveal(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "select", true, "Select", "");
}
-/* ************************** registration - operator types **********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Registration: operator types
+ * \{ */
void graphedit_operatortypes(void)
{
@@ -446,6 +456,7 @@ void graphedit_operatortypes(void)
/* editing */
WM_operatortype_append(GRAPH_OT_snap);
+ WM_operatortype_append(GRAPH_OT_equalize_handles);
WM_operatortype_append(GRAPH_OT_mirror);
WM_operatortype_append(GRAPH_OT_frame_jump);
WM_operatortype_append(GRAPH_OT_snap_cursor_value);
@@ -460,6 +471,8 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_smooth);
WM_operatortype_append(GRAPH_OT_clean);
WM_operatortype_append(GRAPH_OT_decimate);
+ WM_operatortype_append(GRAPH_OT_blend_to_neighbor);
+ WM_operatortype_append(GRAPH_OT_breakdown);
WM_operatortype_append(GRAPH_OT_euler_filter);
WM_operatortype_append(GRAPH_OT_delete);
WM_operatortype_append(GRAPH_OT_duplicate);
@@ -496,7 +509,11 @@ void ED_operatormacros_graph(void)
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
}
-/* ************************** registration - keymaps **********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Registration: Key-Maps
+ * \{ */
void graphedit_keymap(wmKeyConfig *keyconf)
{
@@ -514,3 +531,5 @@ void graphedit_keymap(wmKeyConfig *keyconf)
/* keyframes */
WM_keymap_ensure(keyconf, "Graph Editor", SPACE_GRAPH, 0);
}
+
+/** \} */
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index ffe74e20bdf..29eb5b43e6c 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -56,8 +56,9 @@
#include "graph_intern.h"
-/* ************************************************************************** */
-/* KEYFRAMES STUFF */
+/* -------------------------------------------------------------------- */
+/** \name Internal Keyframe Utilities
+ * \{ */
/* temp info for caching handle vertices close */
typedef struct tNearestVertInfo {
@@ -334,23 +335,17 @@ static tNearestVertInfo *find_nearest_fcurve_vert(bAnimContext *ac, const int mv
return nvi;
}
-/* ******************** Deselect All Operator ***************************** */
-/* This operator works in one of three ways:
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Deselect All Operator
+ *
+ * This operator works in one of three ways:
* 1) (de)select all (AKEY) - test if select all or deselect all
* 2) invert all (CTRL-IKEY) - invert selection of all keyframes
* 3) (de)select all - no testing is done; only for use internal tools as normal function...
- */
+ * \{ */
-/* Deselects keyframes in the Graph Editor
- * - This is called by the deselect all operator, as well as other ones!
- *
- * - test: check if select or deselect all
- * - sel: how to select keyframes
- * 0 = deselect
- * 1 = select
- * 2 = invert
- * - do_channels: whether to affect selection status of channels
- */
void deselect_graph_keys(bAnimContext *ac, bool test, short sel, bool do_channels)
{
ListBase anim_data = {NULL, NULL};
@@ -490,8 +485,12 @@ void GRAPH_OT_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
-/* ******************** Box Select Operator **************************** */
-/* This operator currently works in one of three ways:
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Box Select Operator
+ *
+ * This operator currently works in one of three ways:
* -> BKEY - 1) all keyframes within region are selected (validation with BEZT_OK_REGION)
* -> ALT-BKEY - depending on which axis of the region was larger...
* -> 2) x-axis, so select all frames within frame range (validation with BEZT_OK_FRAMERANGE)
@@ -499,7 +498,7 @@ void GRAPH_OT_select_all(wmOperatorType *ot)
* (validation with BEZT_OK_VALUERANGE).
*
* The selection backend is also reused for the Lasso and Circle select operators.
- */
+ * \{ */
static rctf initialize_box_select_coords(const bAnimContext *ac, const rctf *rectf_view)
{
@@ -572,7 +571,8 @@ static void initialize_box_select_key_editing_data(const SpaceGraph *sipo,
*r_mapping_flag |= ANIM_get_normalization_flags(ac);
}
-/* Box Select only selects keyframes, as overshooting handles often get caught too,
+/**
+ * Box Select only selects keyframes, as overshooting handles often get caught too,
* which means that they may be inadvertently moved as well. However, incl_handles overrides
* this, and allow handles to be considered independently too.
* Also, for convenience, handles should get same status as keyframe (if it was within bounds).
@@ -667,7 +667,8 @@ static bool box_select_graphkeys(bAnimContext *ac,
return any_key_selection_changed;
}
-/* This function is used to set all the keyframes of a given curve as selectable
+/**
+ * This function is used to set all the keyframes of a given curve as selectable
* by the "select_cb" function inside of "box_select_graphcurves".
*/
static short ok_bezier_always_ok(KeyframeEditData *UNUSED(ked), BezTriple *UNUSED(bezt))
@@ -732,11 +733,12 @@ static bool rectf_curve_intersection(
#undef INSIDE
#undef BELOW
-/* Perform a box selection of the curves themselves. This means this function tries
+/**
+ * Perform a box selection of the curves themselves. This means this function tries
* to select a curve by sampling it at various points instead of trying to select the
* keyframes directly.
* The selection actions done to a curve are actually done on all the keyframes of the curve.
- * NOTE: This function is only called if no keyframe is in the selection area.
+ * \note This function is only called if no keyframe is in the selection area.
*/
static void box_select_graphcurves(bAnimContext *ac,
const rctf *rectf_view,
@@ -1107,13 +1109,17 @@ void GRAPH_OT_select_circle(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ******************** Column Select Operator **************************** */
-/* This operator works in one of four ways:
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Column Select Operator
+ *
+ * This operator works in one of four ways:
* - 1) select all keyframes in the same frame as a selected one (KKEY)
* - 2) select all keyframes in the same frame as the current frame marker (CTRL-KKEY)
* - 3) select all keyframes in the same frame as a selected markers (SHIFT-KKEY)
* - 4) select all keyframes that occur between selected markers (ALT-KKEY)
- */
+ * \{ */
/* defines for column-select mode */
static const EnumPropertyItem prop_column_select_types[] = {
@@ -1297,7 +1303,11 @@ void GRAPH_OT_select_column(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", "");
}
-/* ******************** Select Linked Operator *********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Operator
+ * \{ */
static int graphkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1353,7 +1363,11 @@ void GRAPH_OT_select_linked(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************** Select More/Less Operators *********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More/Less Operators
+ * \{ */
/* Common code to perform selection */
static void select_moreless_graph_keys(bAnimContext *ac, short mode)
@@ -1467,8 +1481,13 @@ void GRAPH_OT_select_less(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************** Select Left/Right Operator ************************* */
-/* Select keyframes left/right of the current frame indicator */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Left/Right Operator
+ *
+ * Select keyframes left/right of the current frame indicator.
+ * \{ */
/* defines for left-right select tool */
static const EnumPropertyItem prop_graphkeys_leftright_select_types[] = {
@@ -1628,15 +1647,19 @@ void GRAPH_OT_select_leftright(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ******************** Mouse-Click Select Operator *********************** */
-/* This operator works in one of three ways:
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mouse-Click Select Operator
+ *
+ * This operator works in one of three ways:
* - 1) keyframe under mouse - no special modifiers
* - 2) all keyframes on the same side of current frame indicator as mouse - ALT modifier
* - 3) column select all keyframes in frame under mouse - CTRL modifier
*
* In addition to these basic options, the SHIFT modifier can be used to toggle the
* selection mode between replacing the selection (without) and inverting the selection (with).
- */
+ * \{ */
/* option 1) select keyframe directly under mouse */
static int mouse_graph_keys(bAnimContext *ac,
@@ -1888,9 +1911,12 @@ static int graphkeys_mselect_column(bAnimContext *ac,
return run_modal ? OPERATOR_RUNNING_MODAL : OPERATOR_FINISHED;
}
-/* ------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Click Select Operator
+ * \{ */
-/* handle clicking */
static int graphkeys_clickselect_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
@@ -1988,4 +2014,4 @@ void GRAPH_OT_clickselect(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ************************************************************************** */
+/** \} */
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index f04336cab84..4b8c983a761 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -17,6 +17,16 @@
* All rights reserved.
*/
+/** \file
+ * \ingroup spgraph
+ *
+ * Graph Slider Operators
+ *
+ * This file contains a collection of operators to modify keyframes in the graph editor.
+ * All operators are modal and use a slider that allows the user to define a percentage
+ * to modify the operator.
+ */
+
#include <float.h>
#include <string.h>
@@ -48,85 +58,103 @@
#include "graph_intern.h"
-/* ******************** GRAPH SLIDER OPERATORS ************************* */
-/* This file contains a collection of operators to modify keyframes in the graph editor. All
- * operators are modal and use a slider that allows the user to define a percentage to modify the
- * operator. */
-
-/* ******************** Decimate Keyframes Operator ************************* */
-
-static void decimate_graph_keys(bAnimContext *ac, float remove_ratio, float error_sq_max)
-{
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- /* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
- ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
-
- /* Loop through filtered data and clean curves. */
- for (ale = anim_data.first; ale; ale = ale->next) {
- if (!decimate_fcurve(ale, remove_ratio, error_sq_max)) {
- /* The selection contains unsupported keyframe types! */
- WM_report(RPT_WARNING, "Decimate: Skipping non linear/bezier keyframes!");
- }
-
- ale->update |= ANIM_UPDATE_DEFAULT;
- }
-
- ANIM_animdata_update(ac, &anim_data);
- ANIM_animdata_freelist(&anim_data);
-}
+/* -------------------------------------------------------------------- */
+/** \name Internal Struct & Defines
+ * \{ */
-/* ------------------- */
+/* Used to obtain a list of animation channels for the operators to work on. */
+#define OPERATOR_DATA_FILTER \
+ (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL | \
+ ANIMFILTER_NODUPLIS)
/* This data type is only used for modal operation. */
-typedef struct tDecimateGraphOp {
+typedef struct tGraphSliderOp {
bAnimContext ac;
Scene *scene;
ScrArea *area;
ARegion *region;
/** A 0-1 value for determining how much we should decimate. */
- PropertyRNA *percentage_prop;
+ PropertyRNA *factor_prop;
/** The original bezt curve data (used for restoring fcurves). */
ListBase bezt_arr_list;
struct tSlider *slider;
+ /* Each operator has a specific update function. */
+ void (*modal_update)(struct bContext *, struct wmOperator *);
+
NumInput num;
-} tDecimateGraphOp;
+} tGraphSliderOp;
typedef struct tBeztCopyData {
int tot_vert;
BezTriple *bezt;
} tBeztCopyData;
-typedef enum tDecimModes {
- DECIM_RATIO = 1,
- DECIM_ERROR,
-} tDecimModes;
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utility Functions
+ * \{ */
+
+/**
+ * Construct a list with the original bezt arrays so we can restore them during modal operation.
+ * The data is stored on the struct that is passed.
+ */
+static void store_original_bezt_arrays(tGraphSliderOp *gso)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimContext *ac = &gso->ac;
+ bAnimListElem *ale;
+
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
+
+ /* Loop through filtered data and copy the curves. */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ if (fcu->bezt == NULL) {
+ /* This curve is baked, skip it. */
+ continue;
+ }
+
+ const int arr_size = sizeof(BezTriple) * fcu->totvert;
+
+ tBeztCopyData *copy = MEM_mallocN(sizeof(tBeztCopyData), "bezts_copy");
+ BezTriple *bezts_copy = MEM_mallocN(arr_size, "bezts_copy_array");
+
+ copy->tot_vert = fcu->totvert;
+ memcpy(bezts_copy, fcu->bezt, arr_size);
+
+ copy->bezt = bezts_copy;
+
+ LinkData *link = NULL;
+
+ link = MEM_callocN(sizeof(LinkData), "Bezt Link");
+ link->data = copy;
+
+ BLI_addtail(&gso->bezt_arr_list, link);
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+}
/* Overwrite the current bezts arrays with the original data. */
-static void decimate_reset_bezts(tDecimateGraphOp *dgo)
+static void reset_bezts(tGraphSliderOp *gso)
{
ListBase anim_data = {NULL, NULL};
LinkData *link_bezt;
bAnimListElem *ale;
- int filter;
- bAnimContext *ac = &dgo->ac;
+ bAnimContext *ac = &gso->ac;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
- ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
/* Loop through filtered data and reset bezts. */
- for (ale = anim_data.first, link_bezt = dgo->bezt_arr_list.first; ale; ale = ale->next) {
+ for (ale = anim_data.first, link_bezt = gso->bezt_arr_list.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->key_data;
if (fcu->bezt == NULL) {
@@ -151,241 +179,246 @@ static void decimate_reset_bezts(tDecimateGraphOp *dgo)
ANIM_animdata_freelist(&anim_data);
}
-static void decimate_exit(bContext *C, wmOperator *op)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Common Modal Functions
+ * \{ */
+
+static void graph_slider_exit(bContext *C, wmOperator *op)
{
- tDecimateGraphOp *dgo = op->customdata;
+ tGraphSliderOp *gso = op->customdata;
wmWindow *win = CTX_wm_window(C);
/* If data exists, clear its data and exit. */
- if (dgo == NULL) {
+ if (gso == NULL) {
return;
}
- ScrArea *area = dgo->area;
+ ScrArea *area = gso->area;
LinkData *link;
- ED_slider_destroy(C, dgo->slider);
+ ED_slider_destroy(C, gso->slider);
- for (link = dgo->bezt_arr_list.first; link != NULL; link = link->next) {
+ for (link = gso->bezt_arr_list.first; link != NULL; link = link->next) {
tBeztCopyData *copy = link->data;
MEM_freeN(copy->bezt);
MEM_freeN(link->data);
}
- BLI_freelistN(&dgo->bezt_arr_list);
- MEM_freeN(dgo);
+ BLI_freelistN(&gso->bezt_arr_list);
+ MEM_freeN(gso);
/* Return to normal cursor and header status. */
WM_cursor_modal_restore(win);
ED_area_status_text(area, NULL);
- /* Cleanup. */
+ /* cleanup */
op->customdata = NULL;
}
-/* Draw a percentage indicator in workspace footer. */
-static void decimate_draw_status(bContext *C, tDecimateGraphOp *dgo)
+static int graph_slider_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- char status_str[UI_MAX_DRAW_STR];
- char mode_str[32];
- char slider_string[UI_MAX_DRAW_STR];
+ tGraphSliderOp *gso = op->customdata;
- ED_slider_status_string_get(dgo->slider, slider_string, UI_MAX_DRAW_STR);
+ const bool has_numinput = hasNumInput(&gso->num);
- strcpy(mode_str, TIP_("Decimate Keyframes"));
+ ED_slider_modal(gso->slider, event);
- if (hasNumInput(&dgo->num)) {
- char str_ofs[NUM_STR_REP_LEN];
+ switch (event->type) {
+ /* Confirm */
+ case LEFTMOUSE:
+ case EVT_RETKEY:
+ case EVT_PADENTER: {
+ if (event->val == KM_PRESS) {
+ graph_slider_exit(C, op);
- outputNumInput(&dgo->num, str_ofs, &dgo->scene->unit);
+ return OPERATOR_FINISHED;
+ }
+ break;
+ }
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
- }
- else {
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
+ /* Cancel */
+ case EVT_ESCKEY:
+ case RIGHTMOUSE: {
+ if (event->val == KM_PRESS) {
+ reset_bezts(gso);
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ graph_slider_exit(C, op);
+
+ return OPERATOR_CANCELLED;
+ }
+ break;
+ }
+
+ /* When the mouse is moved, the percentage and the keyframes update. */
+ case MOUSEMOVE: {
+ if (has_numinput == false) {
+ /* Do the update as specified by the operator. */
+ gso->modal_update(C, op);
+ }
+ break;
+ }
+ default: {
+ if ((event->val == KM_PRESS) && handleNumInput(C, &gso->num, event)) {
+ float value;
+ float percentage = RNA_property_float_get(op->ptr, gso->factor_prop);
+
+ /* Grab percentage from numeric input, and store this new value for redo
+ * NOTE: users see ints, while internally we use a 0-1 float.
+ */
+ value = percentage * 100.0f;
+ applyNumInput(&gso->num, &value);
+
+ percentage = value / 100.0f;
+ ED_slider_factor_set(gso->slider, percentage);
+ RNA_property_float_set(op->ptr, gso->factor_prop, percentage);
+
+ gso->modal_update(C, op);
+ break;
+ }
+
+ /* Unhandled event - maybe it was some view manipulation? */
+ /* Allow to pass through. */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
}
- ED_workspace_status_text(C, status_str);
+ return OPERATOR_RUNNING_MODAL;
}
-static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+/* Allocate tGraphSliderOp and assign to op->customdata. */
+static int graph_slider_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tDecimateGraphOp *dgo;
+ tGraphSliderOp *gso;
WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EW_SCROLL);
/* Init slide-op data. */
- dgo = op->customdata = MEM_callocN(sizeof(tDecimateGraphOp), "tDecimateGraphOp");
+ gso = op->customdata = MEM_callocN(sizeof(tGraphSliderOp), "tGraphSliderOp");
/* Get editor data. */
- if (ANIM_animdata_get_context(C, &dgo->ac) == 0) {
- decimate_exit(C, op);
+ if (ANIM_animdata_get_context(C, &gso->ac) == 0) {
+ graph_slider_exit(C, op);
return OPERATOR_CANCELLED;
}
- dgo->percentage_prop = RNA_struct_find_property(op->ptr, "remove_ratio");
+ gso->scene = CTX_data_scene(C);
+ gso->area = CTX_wm_area(C);
+ gso->region = CTX_wm_region(C);
+
+ store_original_bezt_arrays(gso);
- dgo->scene = CTX_data_scene(C);
- dgo->area = CTX_wm_area(C);
- dgo->region = CTX_wm_region(C);
+ gso->slider = ED_slider_create(C);
+ ED_slider_init(gso->slider, event);
- dgo->slider = ED_slider_create(C);
- ED_slider_init(dgo->slider, event);
- ED_slider_allow_overshoot_set(dgo->slider, false);
+ if (gso->bezt_arr_list.first == NULL) {
+ WM_report(RPT_ERROR, "Cannot find keys to operate on.");
+ graph_slider_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
- decimate_draw_status(C, dgo);
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
- /* Construct a list with the original bezt arrays so we can restore them during modal operation.
- */
- {
- ListBase anim_data = {NULL, NULL};
- bAnimContext *ac = &dgo->ac;
- bAnimListElem *ale;
+/** \} */
- int filter;
+/* -------------------------------------------------------------------- */
+/** \name Decimate Keyframes Operator
+ * \{ */
- /* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
- ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+typedef enum tDecimModes {
+ DECIM_RATIO = 1,
+ DECIM_ERROR,
+} tDecimModes;
+
+static void decimate_graph_keys(bAnimContext *ac, float factor, float error_sq_max)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
- /* Loop through filtered data and copy the curves. */
- for (ale = anim_data.first; ale; ale = ale->next) {
- FCurve *fcu = (FCurve *)ale->key_data;
+ /* Filter data. */
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
- if (fcu->bezt == NULL) {
- /* This curve is baked, skip it. */
- continue;
- }
+ /* Loop through filtered data and clean curves. */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ if (!decimate_fcurve(ale, factor, error_sq_max)) {
+ /* The selection contains unsupported keyframe types! */
+ WM_report(RPT_WARNING, "Decimate: Skipping non linear/bezier keyframes!");
+ }
- const int arr_size = sizeof(BezTriple) * fcu->totvert;
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
- tBeztCopyData *copy = MEM_mallocN(sizeof(tBeztCopyData), "bezts_copy");
- BezTriple *bezts_copy = MEM_mallocN(arr_size, "bezts_copy_array");
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
- copy->tot_vert = fcu->totvert;
- memcpy(bezts_copy, fcu->bezt, arr_size);
+/* Draw a percentage indicator in workspace footer. */
+static void decimate_draw_status(bContext *C, tGraphSliderOp *gso)
+{
+ char status_str[UI_MAX_DRAW_STR];
+ char mode_str[32];
+ char slider_string[UI_MAX_DRAW_STR];
- copy->bezt = bezts_copy;
+ ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
- LinkData *link = NULL;
+ strcpy(mode_str, TIP_("Decimate Keyframes"));
- link = MEM_callocN(sizeof(LinkData), "Bezt Link");
- link->data = copy;
+ if (hasNumInput(&gso->num)) {
+ char str_ofs[NUM_STR_REP_LEN];
- BLI_addtail(&dgo->bezt_arr_list, link);
- }
+ outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
- ANIM_animdata_freelist(&anim_data);
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
}
-
- if (dgo->bezt_arr_list.first == NULL) {
- WM_report(RPT_WARNING,
- "Fcurve Decimate: Can't decimate baked channels. Unbake them and try again.");
- decimate_exit(C, op);
- return OPERATOR_CANCELLED;
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
}
- WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
+ ED_workspace_status_text(C, status_str);
}
-static void graphkeys_decimate_modal_update(bContext *C, wmOperator *op)
+static void decimate_modal_update(bContext *C, wmOperator *op)
{
/* Perform decimate updates - in response to some user action
* (e.g. pressing a key or moving the mouse). */
- tDecimateGraphOp *dgo = op->customdata;
+ tGraphSliderOp *gso = op->customdata;
- decimate_draw_status(C, dgo);
+ decimate_draw_status(C, gso);
/* Reset keyframe data (so we get back to the original state). */
- decimate_reset_bezts(dgo);
+ reset_bezts(gso);
/* Apply... */
- float remove_ratio = ED_slider_factor_get(dgo->slider);
- RNA_property_float_set(op->ptr, dgo->percentage_prop, remove_ratio);
+ float factor = ED_slider_factor_get(gso->slider);
+ RNA_property_float_set(op->ptr, gso->factor_prop, factor);
/* We don't want to limit the decimation to a certain error margin. */
const float error_sq_max = FLT_MAX;
- decimate_graph_keys(&dgo->ac, remove_ratio, error_sq_max);
+ decimate_graph_keys(&gso->ac, factor, error_sq_max);
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
-static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent *event)
+static int decimate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- /* This assumes that we are in "DECIM_RATIO" mode. This is because the error margin is very hard
- * and finicky to control with this modal mouse grab method. Therefore, it is expected that the
- * error margin mode is not adjusted by the modal operator but instead tweaked via the redo
- * panel. */
- tDecimateGraphOp *dgo = op->customdata;
-
- const bool has_numinput = hasNumInput(&dgo->num);
-
- ED_slider_modal(dgo->slider, event);
-
- switch (event->type) {
- case LEFTMOUSE: /* Confirm */
- case EVT_RETKEY:
- case EVT_PADENTER: {
- if (event->val == KM_PRESS) {
- decimate_exit(C, op);
-
- return OPERATOR_FINISHED;
- }
- break;
- }
-
- case EVT_ESCKEY: /* Cancel */
- case RIGHTMOUSE: {
- if (event->val == KM_PRESS) {
- decimate_reset_bezts(dgo);
-
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
-
- decimate_exit(C, op);
-
- return OPERATOR_CANCELLED;
- }
- break;
- }
-
- /* Percentage Change... */
- case MOUSEMOVE: /* Calculate new position. */
- {
- if (has_numinput == false) {
- /* Update pose to reflect the new values. */
- graphkeys_decimate_modal_update(C, op);
- }
- break;
- }
- default: {
- if ((event->val == KM_PRESS) && handleNumInput(C, &dgo->num, event)) {
- float value;
- float percentage = RNA_property_float_get(op->ptr, dgo->percentage_prop);
-
- /* Grab percentage from numeric input, and store this new value for redo
- * NOTE: users see ints, while internally we use a 0-1 float.
- */
- value = percentage * 100.0f;
- applyNumInput(&dgo->num, &value);
-
- percentage = value / 100.0f;
- RNA_property_float_set(op->ptr, dgo->percentage_prop, percentage);
-
- /* Update decimate output to reflect the new values. */
- graphkeys_decimate_modal_update(C, op);
- break;
- }
+ const int invoke_result = graph_slider_invoke(C, op, event);
- /* Unhandled event - maybe it was some view manipulation? */
- /* Allow to pass through. */
- return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
- }
+ if (invoke_result == OPERATOR_CANCELLED) {
+ return OPERATOR_CANCELLED;
}
- return OPERATOR_RUNNING_MODAL;
+ tGraphSliderOp *gso = op->customdata;
+ gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
+ gso->modal_update = decimate_modal_update;
+ ED_slider_allow_overshoot_set(gso->slider, false);
+
+ return invoke_result;
}
-static int graphkeys_decimate_exec(bContext *C, wmOperator *op)
+static int decimate_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
@@ -396,13 +429,13 @@ static int graphkeys_decimate_exec(bContext *C, wmOperator *op)
tDecimModes mode = RNA_enum_get(op->ptr, "mode");
/* We want to be able to work on all available keyframes. */
- float remove_ratio = 1.0f;
+ float factor = 1.0f;
/* We don't want to limit the decimation to a certain error margin. */
float error_sq_max = FLT_MAX;
switch (mode) {
case DECIM_RATIO:
- remove_ratio = RNA_float_get(op->ptr, "remove_ratio");
+ factor = RNA_float_get(op->ptr, "factor");
break;
case DECIM_ERROR:
error_sq_max = RNA_float_get(op->ptr, "remove_error_margin");
@@ -412,12 +445,12 @@ static int graphkeys_decimate_exec(bContext *C, wmOperator *op)
break;
}
- if (remove_ratio == 0.0f || error_sq_max == 0.0f) {
+ if (factor == 0.0f || error_sq_max == 0.0f) {
/* Nothing to remove. */
return OPERATOR_FINISHED;
}
- decimate_graph_keys(&ac, remove_ratio, error_sq_max);
+ decimate_graph_keys(&ac, factor, error_sq_max);
/* Set notifier that keyframes have changed. */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -425,16 +458,16 @@ static int graphkeys_decimate_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static bool graphkeys_decimate_poll_property(const bContext *UNUSED(C),
- wmOperator *op,
- const PropertyRNA *prop)
+static bool decimate_poll_property(const bContext *UNUSED(C),
+ wmOperator *op,
+ const PropertyRNA *prop)
{
const char *prop_id = RNA_property_identifier(prop);
if (STRPREFIX(prop_id, "remove")) {
int mode = RNA_enum_get(op->ptr, "mode");
- if (STREQ(prop_id, "remove_ratio") && mode != DECIM_RATIO) {
+ if (STREQ(prop_id, "factor") && mode != DECIM_RATIO) {
return false;
}
if (STREQ(prop_id, "remove_error_margin") && mode != DECIM_ERROR) {
@@ -445,9 +478,7 @@ static bool graphkeys_decimate_poll_property(const bContext *UNUSED(C),
return true;
}
-static char *graphkeys_decimate_desc(bContext *UNUSED(C),
- wmOperatorType *UNUSED(op),
- PointerRNA *ptr)
+static char *decimate_desc(bContext *UNUSED(C), wmOperatorType *UNUSED(op), PointerRNA *ptr)
{
if (RNA_enum_get(ptr, "mode") == DECIM_ERROR) {
@@ -483,11 +514,11 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
"Decimate F-Curves by removing keyframes that influence the curve shape the least";
/* API callbacks */
- ot->poll_property = graphkeys_decimate_poll_property;
- ot->get_description = graphkeys_decimate_desc;
- ot->invoke = graphkeys_decimate_invoke;
- ot->modal = graphkeys_decimate_modal;
- ot->exec = graphkeys_decimate_exec;
+ ot->poll_property = decimate_poll_property;
+ ot->get_description = decimate_desc;
+ ot->invoke = decimate_invoke;
+ ot->modal = graph_slider_modal;
+ ot->exec = decimate_exec;
ot->poll = graphop_editable_keyframes_poll;
/* Flags */
@@ -502,7 +533,7 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
"Which mode to use for decimation");
RNA_def_float_factor(ot->srna,
- "remove_ratio",
+ "factor",
1.0f / 3.0f,
0.0f,
1.0f,
@@ -520,3 +551,258 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
0.0f,
10.0f);
}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend To Neighbor Operator
+ * \{ */
+
+static void blend_to_neighbor_graph_keys(bAnimContext *ac, float factor)
+{
+ ListBase anim_data = {NULL, NULL};
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
+
+ bAnimListElem *ale;
+
+ /* Loop through filtered data and blend keys. */
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ ListBase segments = find_fcurve_segments(fcu);
+ LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
+ blend_to_neighbor_fcurve_segment(fcu, segment, factor);
+ }
+ BLI_freelistN(&segments);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
+static void blend_to_neighbor_draw_status_header(bContext *C, tGraphSliderOp *gso)
+{
+ char status_str[UI_MAX_DRAW_STR];
+ char mode_str[32];
+ char slider_string[UI_MAX_DRAW_STR];
+
+ ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
+
+ strcpy(mode_str, TIP_("Blend To Neighbor"));
+
+ if (hasNumInput(&gso->num)) {
+ char str_ofs[NUM_STR_REP_LEN];
+
+ outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
+
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
+ }
+
+ ED_workspace_status_text(C, status_str);
+}
+
+static void blend_to_neighbor_modal_update(bContext *C, wmOperator *op)
+{
+ tGraphSliderOp *gso = op->customdata;
+
+ blend_to_neighbor_draw_status_header(C, gso);
+
+ /* Reset keyframe data to the state at invoke. */
+ reset_bezts(gso);
+
+ const float factor = ED_slider_factor_get(gso->slider);
+ RNA_property_float_set(op->ptr, gso->factor_prop, factor);
+ blend_to_neighbor_graph_keys(&gso->ac, factor);
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+}
+
+static int blend_to_neighbor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const int invoke_result = graph_slider_invoke(C, op, event);
+
+ if (invoke_result == OPERATOR_CANCELLED) {
+ return invoke_result;
+ }
+
+ tGraphSliderOp *gso = op->customdata;
+ gso->modal_update = blend_to_neighbor_modal_update;
+ gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
+ blend_to_neighbor_draw_status_header(C, gso);
+
+ return invoke_result;
+}
+
+static int blend_to_neighbor_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const float factor = RNA_float_get(op->ptr, "factor");
+
+ blend_to_neighbor_graph_keys(&ac, factor);
+
+ /* Set notifier that keyframes have changed. */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GRAPH_OT_blend_to_neighbor(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Blend To Neighbor";
+ ot->idname = "GRAPH_OT_blend_to_neighbor";
+ ot->description = "Blend selected keyframes to their left or right neighbor";
+
+ /* API callbacks. */
+ ot->invoke = blend_to_neighbor_invoke;
+ ot->modal = graph_slider_modal;
+ ot->exec = blend_to_neighbor_exec;
+ ot->poll = graphop_editable_keyframes_poll;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_float_factor(ot->srna,
+ "factor",
+ 1.0f / 3.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Blend",
+ "The blend factor with 0.5 being the current frame",
+ 0.0f,
+ 1.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Breakdown Operator
+ * \{ */
+
+static void breakdown_graph_keys(bAnimContext *ac, float factor)
+{
+ ListBase anim_data = {NULL, NULL};
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
+
+ bAnimListElem *ale;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ ListBase segments = find_fcurve_segments(fcu);
+ LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
+ breakdown_fcurve_segment(fcu, segment, factor);
+ }
+ BLI_freelistN(&segments);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
+static void breakdown_draw_status_header(bContext *C, tGraphSliderOp *gso)
+{
+ char status_str[UI_MAX_DRAW_STR];
+ char mode_str[32];
+ char slider_string[UI_MAX_DRAW_STR];
+
+ ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
+
+ strcpy(mode_str, TIP_("Breakdown"));
+
+ if (hasNumInput(&gso->num)) {
+ char str_ofs[NUM_STR_REP_LEN];
+
+ outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
+
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
+ }
+
+ ED_workspace_status_text(C, status_str);
+}
+
+static void breakdown_modal_update(bContext *C, wmOperator *op)
+{
+ tGraphSliderOp *gso = op->customdata;
+
+ breakdown_draw_status_header(C, gso);
+
+ /* Reset keyframe data to the state at invoke. */
+ reset_bezts(gso);
+ breakdown_graph_keys(&gso->ac, ED_slider_factor_get(gso->slider));
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+}
+
+static int breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const int invoke_result = graph_slider_invoke(C, op, event);
+
+ if (invoke_result == OPERATOR_CANCELLED) {
+ return invoke_result;
+ }
+
+ tGraphSliderOp *gso = op->customdata;
+ gso->modal_update = breakdown_modal_update;
+ breakdown_draw_status_header(C, gso);
+
+ return invoke_result;
+}
+
+static int breakdown_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const float factor = RNA_float_get(op->ptr, "factor");
+
+ breakdown_graph_keys(&ac, factor);
+
+ /* Set notifier that keyframes have changed. */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GRAPH_OT_breakdown(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Breakdown";
+ ot->idname = "GRAPH_OT_breakdown";
+ ot->description = "Move selected keyframes to an inbetween position relative to adjacent keys";
+
+ /* API callbacks. */
+ ot->invoke = breakdown_invoke;
+ ot->modal = graph_slider_modal;
+ ot->exec = breakdown_exec;
+ ot->poll = graphop_editable_keyframes_poll;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_float_factor(ot->srna,
+ "factor",
+ 1.0f / 3.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Factor",
+ "Favor either the left or the right key",
+ 0.0f,
+ 1.0f);
+}
+
+/** \} */
diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c
index c37d9f42c12..d78af4c4bcf 100644
--- a/source/blender/editors/space_graph/graph_utils.c
+++ b/source/blender/editors/space_graph/graph_utils.c
@@ -46,12 +46,10 @@
#include "graph_intern.h" /* own include */
-/* ************************************************************** */
-/* Set Up Drivers Editor */
+/* -------------------------------------------------------------------- */
+/** \name Set Up Drivers Editor
+ * \{ */
-/* Set up UI configuration for Drivers Editor */
-/* NOTE: Currently called from window-manager
- * (new drivers editor window) and RNA (mode switching) */
void ED_drivers_editor_init(bContext *C, ScrArea *area)
{
SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
@@ -89,18 +87,12 @@ void ED_drivers_editor_init(bContext *C, ScrArea *area)
}
}
-/* ************************************************************** */
-/* Active F-Curve */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Active F-Curve
+ * \{ */
-/**
- * Find 'active' F-Curve.
- * It must be editable, since that's the purpose of these buttons (subject to change).
- * We return the 'wrapper' since it contains valuable context info (about hierarchy),
- * which will need to be freed when the caller is done with it.
- *
- * \note curve-visible flag isn't included,
- * otherwise selecting a curve via list to edit is too cumbersome.
- */
bAnimListElem *get_active_fcurve_channel(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
@@ -124,10 +116,12 @@ bAnimListElem *get_active_fcurve_channel(bAnimContext *ac)
return NULL;
}
-/* ************************************************************** */
-/* Operator Polling Callbacks */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Polling Callbacks
+ * \{ */
-/* Check if there are any visible keyframes (for selection tools) */
bool graphop_visible_keyframes_poll(bContext *C)
{
bAnimContext ac;
@@ -180,7 +174,6 @@ bool graphop_visible_keyframes_poll(bContext *C)
return found;
}
-/* Check if there are any visible + editable keyframes (for editing tools) */
bool graphop_editable_keyframes_poll(bContext *C)
{
bAnimContext ac;
@@ -235,7 +228,6 @@ bool graphop_editable_keyframes_poll(bContext *C)
return found;
}
-/* has active F-Curve that's editable */
bool graphop_active_fcurve_poll(bContext *C)
{
bAnimContext ac;
@@ -279,7 +271,6 @@ bool graphop_active_fcurve_poll(bContext *C)
return has_fcurve;
}
-/* has active F-Curve in the context that's editable */
bool graphop_active_editable_fcurve_ctx_poll(bContext *C)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "active_editable_fcurve", &RNA_FCurve);
@@ -287,7 +278,6 @@ bool graphop_active_editable_fcurve_ctx_poll(bContext *C)
return ptr.data != NULL;
}
-/* has selected F-Curve that's editable */
bool graphop_selected_fcurve_poll(bContext *C)
{
bAnimContext ac;
@@ -321,4 +311,4 @@ bool graphop_selected_fcurve_poll(bContext *C)
return true;
}
-/* ************************************************************** */
+/** \} */
diff --git a/source/blender/editors/space_graph/graph_view.c b/source/blender/editors/space_graph/graph_view.c
index c38c5f09a2a..a2f31a01a70 100644
--- a/source/blender/editors/space_graph/graph_view.c
+++ b/source/blender/editors/space_graph/graph_view.c
@@ -17,6 +17,10 @@
* All rights reserved.
*/
+/** \file
+ * \ingroup spgraph
+ */
+
#include <math.h>
#include "MEM_guardedalloc.h"
@@ -48,10 +52,10 @@
#include "graph_intern.h"
-/* *************************** Calculate Range ************************** */
+/* -------------------------------------------------------------------- */
+/** \name Calculate Range
+ * \{ */
-/* Get the min/max keyframes. */
-/* NOTE: it should return total boundbox, filter for selection only can be argument... */
void get_graph_keyframe_extents(bAnimContext *ac,
float *xmin,
float *xmax,
@@ -194,7 +198,11 @@ void get_graph_keyframe_extents(bAnimContext *ac,
}
}
-/* ****************** Automatic Preview-Range Operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Automatic Preview-Range Operator
+ * \{ */
static int graphkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -213,7 +221,7 @@ static int graphkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
scene = ac.scene;
/* Set the range directly. */
- get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL, false, false);
+ get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL, true, false);
scene->r.flag |= SCER_PRV_RANGE;
scene->r.psfra = round_fl_to_int(min);
scene->r.pefra = round_fl_to_int(max);
@@ -228,9 +236,9 @@ static int graphkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
void GRAPH_OT_previewrange_set(wmOperatorType *ot)
{
/* Identifiers */
- ot->name = "Auto-Set Preview Range";
+ ot->name = "Set Preview Range to Selected";
ot->idname = "GRAPH_OT_previewrange_set";
- ot->description = "Automatically set Preview Range based on range of keyframes";
+ ot->description = "Set Preview Range based on range of selected keyframes";
/* API callbacks */
ot->exec = graphkeys_previewrange_exec;
@@ -241,7 +249,11 @@ void GRAPH_OT_previewrange_set(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****************** View-All Operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View-All Operator
+ * \{ */
static int graphkeys_viewall(bContext *C,
const bool do_sel_only,
@@ -347,7 +359,11 @@ void GRAPH_OT_view_selected(wmOperatorType *ot)
"Include handles of keyframes when calculating extents");
}
-/* ********************** View Frame Operator ****************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Frame Operator
+ * \{ */
static int graphkeys_view_frame_exec(bContext *C, wmOperator *op)
{
@@ -371,10 +387,14 @@ void GRAPH_OT_view_frame(wmOperatorType *ot)
ot->flag = 0;
}
-/* ******************** Create Ghost-Curves Operator *********************** */
-/* This operator samples the data of the selected F-Curves to F-Points, storing them
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Create Ghost-Curves Operator
+ *
+ * This operator samples the data of the selected F-Curves to F-Points, storing them
* as 'ghost curves' in the active Graph Editor.
- */
+ * \{ */
/* Bake each F-Curve into a set of samples, and store as a ghost curve. */
static void create_ghost_curves(bAnimContext *ac, int start, int end)
@@ -493,8 +513,13 @@ void GRAPH_OT_ghost_curves_create(wmOperatorType *ot)
/* TODO: add props for start/end frames */
}
-/* ******************** Clear Ghost-Curves Operator *********************** */
-/* This operator clears the 'ghost curves' for the active Graph Editor */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Ghost-Curves Operator
+ *
+ * This operator clears the 'ghost curves' for the active Graph Editor.
+ * \{ */
static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -534,3 +559,5 @@ void GRAPH_OT_ghost_curves_clear(wmOperatorType *ot)
/* Flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \} */
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 0e2c9b85bc6..7d5e8836490 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -36,6 +36,7 @@
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_anim_api.h"
@@ -796,18 +797,17 @@ static void graph_refresh(const bContext *C, ScrArea *area)
graph_refresh_fcurve_colors(C);
}
-static void graph_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void graph_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceGraph *sgraph = (SpaceGraph *)slink;
-
- if (sgraph->ads) {
- if ((ID *)sgraph->ads->filter_grp == old_id) {
- sgraph->ads->filter_grp = (Collection *)new_id;
- }
- if ((ID *)sgraph->ads->source == old_id) {
- sgraph->ads->source = new_id;
- }
+ if (!sgraph->ads) {
+ return;
}
+
+ BKE_id_remapper_apply(mappings, (ID **)&sgraph->ads->filter_grp, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, (ID **)&sgraph->ads->source, ID_REMAP_APPLY_DEFAULT);
}
static int graph_space_subtype_get(ScrArea *area)
@@ -829,7 +829,6 @@ static void graph_space_subtype_item_extend(bContext *UNUSED(C),
RNA_enum_items_add(item, totitem, rna_enum_space_graph_mode_items);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_ipo(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype ipo");
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 86349a64681..4b8388a0002 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -63,7 +63,6 @@
#define B_NOP -1
#define MAX_IMAGE_INFO_LEN 128
-/* gets active viewer user */
struct ImageUser *ntree_get_active_iuser(bNodeTree *ntree)
{
bNode *node;
@@ -729,10 +728,6 @@ static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg))
{
RNAUpdateCb *cb = (RNAUpdateCb *)arg_cb;
- /* ideally this would be done by RNA itself, but there we have
- * no image user available, so we just update this flag here */
- cb->iuser->ok = 1;
-
/* we call update here on the pointer property, this way the
* owner of the image pointer can still define its own update
* and notifier */
@@ -1060,7 +1055,7 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma
if (imf->imtype == R_IMF_IMTYPE_CINEON) {
#if 1
- uiItemL(col, IFACE_("Hard coded Non-Linear, Gamma:1.7"), ICON_NONE);
+ uiItemL(col, TIP_("Hard coded Non-Linear, Gamma:1.7"), ICON_NONE);
#else
uiItemR(col, imfptr, "use_cineon_log", 0, NULL, ICON_NONE);
uiItemR(col, imfptr, "cineon_black", 0, NULL, ICON_NONE);
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index fc04ec1fe02..8858df3323f 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -112,13 +112,6 @@ static void draw_render_info(
GPU_matrix_translate_2f(x, y);
GPU_matrix_scale_2f(zoomx, zoomy);
- RenderData *rd = RE_engine_get_render_data(re);
- if (rd->mode & R_BORDER) {
- /* TODO: round or floor instead of casting to int */
- GPU_matrix_translate_2f((int)(-rd->border.xmin * rd->xsch * rd->size * 0.01f),
- (int)(-rd->border.ymin * rd->ysch * rd->size * 0.01f));
- }
-
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
@@ -142,7 +135,6 @@ static void draw_render_info(
}
}
-/* used by node view too */
void ED_image_draw_info(Scene *scene,
ARegion *region,
bool color_manage,
@@ -192,7 +184,7 @@ void ED_image_draw_info(Scene *scene,
GPU_blend(GPU_BLEND_NONE);
- BLF_size(blf_mono_font, 11 * U.pixelsize, U.dpi);
+ BLF_size(blf_mono_font, 11.0f * U.pixelsize, U.dpi);
BLF_color3ub(blf_mono_font, 255, 255, 255);
SNPRINTF(str, "X:%-4d Y:%-4d |", x, y);
@@ -507,7 +499,7 @@ void draw_image_main_helpers(const bContext *C, ARegion *region)
}
}
-bool ED_space_image_show_cache(SpaceImage *sima)
+bool ED_space_image_show_cache(const SpaceImage *sima)
{
Image *image = ED_space_image(sima);
Mask *mask = NULL;
@@ -523,6 +515,17 @@ bool ED_space_image_show_cache(SpaceImage *sima)
return true;
}
+bool ED_space_image_show_cache_and_mval_over(const SpaceImage *sima,
+ ARegion *region,
+ const int mval[2])
+{
+ const rcti *rect_visible = ED_region_visible_rect(region);
+ if (mval[1] > rect_visible->ymin + (16 * UI_DPI_FAC)) {
+ return false;
+ }
+ return ED_space_image_show_cache(sima);
+}
+
void draw_image_cache(const bContext *C, ARegion *region)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -588,7 +591,7 @@ float ED_space_image_zoom_level(const View2D *v2d, const int grid_dimension)
* - Default grid size on startup, which is 256x256 pixels
* - How blend factor for grid lines is set up in the fragment shader `grid_frag.glsl`. */
float zoom_factor;
- zoom_factor = (xzoom + yzoom) / 2.0f; /* Average for accuracy. */
+ zoom_factor = (xzoom + yzoom) / 2.0f; /* Average for accuracy. */
zoom_factor *= 256.0f / (powf(grid_dimension, 2));
return zoom_factor;
}
@@ -610,11 +613,6 @@ void ED_space_image_grid_steps(SpaceImage *sima,
}
}
-/**
- * Calculate the increment snapping value for UV/image editor based on the zoom factor
- * The code in here (except the offset part) is used in `grid_frag.glsl` (see `grid_res`) for
- * drawing the grid overlay for the UV/Image editor.
- */
float ED_space_image_increment_snap_value(const int grid_dimesnions,
const float grid_steps[SI_GRID_STEPS_LEN],
const float zoom_factor)
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index 2174a4b9dc1..470cff20718 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -52,7 +52,7 @@
#include "WM_types.h"
/* NOTE: image_panel_properties() uses pointer to sima->image directly. */
-Image *ED_space_image(SpaceImage *sima)
+Image *ED_space_image(const SpaceImage *sima)
{
return sima->image;
}
@@ -113,7 +113,7 @@ void ED_space_image_auto_set(const bContext *C, SpaceImage *sima)
}
}
-Mask *ED_space_image_get_mask(SpaceImage *sima)
+Mask *ED_space_image_get_mask(const SpaceImage *sima)
{
return sima->mask_info.mask;
}
@@ -177,7 +177,6 @@ void ED_space_image_release_buffer(SpaceImage *sima, ImBuf *ibuf, void *lock)
}
}
-/* Get the SpaceImage flag that is valid for the given ibuf. */
int ED_space_image_get_display_channel_mask(ImBuf *ibuf)
{
int result = (SI_USE_ALPHA | SI_SHOW_ALPHA | SI_SHOW_ZBUF | SI_SHOW_R | SI_SHOW_G | SI_SHOW_B);
@@ -318,7 +317,6 @@ void ED_image_get_uv_aspect(Image *ima, ImageUser *iuser, float *r_aspx, float *
}
}
-/* takes event->mval */
void ED_image_mouse_pos(SpaceImage *sima, const ARegion *region, const int mval[2], float co[2])
{
int sx, sy, width, height;
@@ -377,10 +375,6 @@ void ED_image_point_pos__reverse(SpaceImage *sima,
r_co[1] = (co[1] * height * zoomy) + (float)sy;
}
-/**
- * This is more a user-level functionality, for going to next/prev used slot,
- * Stepping onto the last unused slot too.
- */
bool ED_image_slot_cycle(struct Image *image, int direction)
{
const int cur = image->render_slot;
@@ -434,7 +428,7 @@ void ED_space_image_scopes_update(const struct bContext *C,
/* We also don't update scopes of render result during render. */
if (G.is_rendering) {
const Image *image = sima->image;
- if (image != NULL && (image->type == IMA_TYPE_R_RESULT || image->type == IMA_TYPE_COMPOSITE)) {
+ if (image != NULL && (ELEM(image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE))) {
return;
}
}
@@ -445,12 +439,12 @@ void ED_space_image_scopes_update(const struct bContext *C,
&scene->display_settings);
}
-bool ED_space_image_show_render(SpaceImage *sima)
+bool ED_space_image_show_render(const SpaceImage *sima)
{
return (sima->image && ELEM(sima->image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE));
}
-bool ED_space_image_show_paint(SpaceImage *sima)
+bool ED_space_image_show_paint(const SpaceImage *sima)
{
if (ED_space_image_show_render(sima)) {
return false;
@@ -459,7 +453,7 @@ bool ED_space_image_show_paint(SpaceImage *sima)
return (sima->mode == SI_MODE_PAINT);
}
-bool ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit)
+bool ED_space_image_show_uvedit(const SpaceImage *sima, Object *obedit)
{
if (sima) {
if (ED_space_image_show_render(sima)) {
@@ -482,7 +476,6 @@ bool ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit)
return false;
}
-/* matches clip function */
bool ED_space_image_check_show_maskedit(SpaceImage *sima, Object *obedit)
{
/* check editmode - this is reserved for UV editing */
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 6af0f3a416b..63c537467f7 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -36,11 +36,13 @@ struct wmOperatorType;
extern const char *image_context_dir[]; /* doc access */
/* image_draw.c */
+
void draw_image_main_helpers(const struct bContext *C, struct ARegion *region);
void draw_image_cache(const struct bContext *C, struct ARegion *region);
void draw_image_sample_line(struct SpaceImage *sima);
/* image_ops.c */
+
bool space_image_main_region_poll(struct bContext *C);
bool space_image_view_center_cursor_poll(struct bContext *C);
@@ -59,7 +61,13 @@ void IMAGE_OT_view_ndof(struct wmOperatorType *ot);
#endif
void IMAGE_OT_new(struct wmOperatorType *ot);
+/**
+ * Called by other space types too.
+ */
void IMAGE_OT_open(struct wmOperatorType *ot);
+/**
+ * Called by other space types too.
+ */
void IMAGE_OT_match_movie_length(struct wmOperatorType *ot);
void IMAGE_OT_replace(struct wmOperatorType *ot);
void IMAGE_OT_reload(struct wmOperatorType *ot);
@@ -94,5 +102,9 @@ void IMAGE_OT_tile_remove(struct wmOperatorType *ot);
void IMAGE_OT_tile_fill(struct wmOperatorType *ot);
/* image_panels.c */
+
+/**
+ * Gets active viewer user.
+ */
struct ImageUser *ntree_get_active_iuser(struct bNodeTree *ntree);
void image_buttons_register(struct ARegionType *art);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 94d44e047a4..23d07c9b45b 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -360,8 +360,8 @@ static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *even
WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
- vpd->x = event->x;
- vpd->y = event->y;
+ vpd->x = event->xy[0];
+ vpd->y = event->xy[1];
vpd->xof = sima->xof;
vpd->yof = sima->yof;
vpd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
@@ -406,8 +406,8 @@ static int image_view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *eve
SpaceImage *sima = CTX_wm_space_image(C);
float offset[2];
- offset[0] = (event->prevx - event->x) / sima->zoom;
- offset[1] = (event->prevy - event->y) / sima->zoom;
+ offset[0] = (event->prev_xy[0] - event->xy[0]) / sima->zoom;
+ offset[1] = (event->prev_xy[1] - event->xy[1]) / sima->zoom;
RNA_float_set_array(op->ptr, "offset", offset);
image_view_pan_exec(C, op);
@@ -428,8 +428,8 @@ static int image_view_pan_modal(bContext *C, wmOperator *op, const wmEvent *even
case MOUSEMOVE:
sima->xof = vpd->xof;
sima->yof = vpd->yof;
- offset[0] = (vpd->x - event->x) / sima->zoom;
- offset[1] = (vpd->y - event->y) / sima->zoom;
+ offset[0] = (vpd->x - event->xy[0]) / sima->zoom;
+ offset[1] = (vpd->y - event->xy[1]) / sima->zoom;
RNA_float_set_array(op->ptr, "offset", offset);
image_view_pan_exec(C, op);
break;
@@ -516,8 +516,8 @@ static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *eve
WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
- vpd->origx = event->x;
- vpd->origy = event->y;
+ vpd->origx = event->xy[0];
+ vpd->origy = event->xy[1];
vpd->zoom = sima->zoom;
vpd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
@@ -584,7 +584,7 @@ static int image_view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
UI_view2d_region_to_view(
&region->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
- delta = event->prevx - event->x + event->prevy - event->y;
+ delta = event->prev_xy[0] - event->xy[0] + event->prev_xy[1] - event->xy[1];
if (U.uiflag & USER_ZOOM_INVERT) {
delta *= -1;
@@ -675,8 +675,8 @@ static int image_view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *eve
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
image_zoom_apply(vpd,
op,
- event->x,
- event->y,
+ event->xy[0],
+ event->xy[1],
U.viewzoom,
(U.uiflag & USER_ZOOM_INVERT) != 0,
(use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
@@ -728,10 +728,10 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
WM_operator_properties_use_cursor_init(ot);
}
-#ifdef WITH_INPUT_NDOF
-
/** \} */
+#ifdef WITH_INPUT_NDOF
+
/* -------------------------------------------------------------------- */
/** \name NDOF Operator
* \{ */
@@ -1499,7 +1499,13 @@ static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
}
}
-/* called by other space types too */
+static void image_operator_prop_allow_tokens(wmOperatorType *ot)
+{
+ PropertyRNA *prop = RNA_def_boolean(
+ ot->srna, "allow_path_tokens", true, "", "Allow the path to contain substitution tokens");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+}
+
void IMAGE_OT_open(wmOperatorType *ot)
{
/* identifiers */
@@ -1517,6 +1523,7 @@ void IMAGE_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
+ image_operator_prop_allow_tokens(ot);
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
@@ -1574,7 +1581,6 @@ static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-/* called by other space types too */
void IMAGE_OT_match_movie_length(wmOperatorType *ot)
{
/* identifiers */
@@ -1769,7 +1775,13 @@ static int image_save_options_init(Main *bmain,
opts->im_format.views_format = ima->views_format;
}
- BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath));
+ if (ima->source == IMA_SRC_TILED) {
+ BLI_strncpy(opts->filepath, ima->filepath, sizeof(opts->filepath));
+ BLI_path_abs(opts->filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
+ }
+ else {
+ BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath));
+ }
/* sanitize all settings */
@@ -1806,14 +1818,10 @@ static int image_save_options_init(Main *bmain,
BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
}
- /* append UDIM numbering if not present */
- if (ima->source == IMA_SRC_TILED) {
- char udim[6];
- ImageTile *tile = ima->tiles.first;
- BLI_snprintf(udim, sizeof(udim), ".%d", tile->tile_number);
-
+ /* append UDIM marker if not present */
+ if (ima->source == IMA_SRC_TILED && strstr(opts->filepath, "<UDIM>") == NULL) {
int len = strlen(opts->filepath);
- STR_CONCAT(opts->filepath, len, udim);
+ STR_CONCAT(opts->filepath, len, ".<UDIM>");
}
}
@@ -2072,6 +2080,7 @@ void IMAGE_OT_save_as(wmOperatorType *ot)
"Copy",
"Create a new image file without modifying the current image in blender");
+ image_operator_prop_allow_tokens(ot);
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
@@ -2227,7 +2236,7 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op)
iter = IMB_moviecacheIter_new(image->cache);
while (!IMB_moviecacheIter_done(iter)) {
ibuf = IMB_moviecacheIter_getImBuf(iter);
- if (ibuf->userflags & IB_BITMAPDIRTY) {
+ if (ibuf != NULL && ibuf->userflags & IB_BITMAPDIRTY) {
if (first_ibuf == NULL) {
first_ibuf = ibuf;
}
@@ -2251,7 +2260,7 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op)
while (!IMB_moviecacheIter_done(iter)) {
ibuf = IMB_moviecacheIter_getImBuf(iter);
- if (ibuf->userflags & IB_BITMAPDIRTY) {
+ if (ibuf != NULL && ibuf->userflags & IB_BITMAPDIRTY) {
char name[FILE_MAX];
BLI_strncpy(name, ibuf->name, sizeof(name));
@@ -2586,6 +2595,11 @@ static int image_new_exec(bContext *C, wmOperator *op)
else if (sima) {
ED_space_image_set(bmain, sima, ima, false);
}
+ else {
+ /* #BKE_image_add_generated creates one user by default, remove it if image is not linked to
+ * anything. ref. T94599. */
+ id_us_min(&ima->id);
+ }
BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
@@ -3190,8 +3204,10 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
/** \name Sample Image Operator
* \{ */
-/* Returns mouse position in image space. */
-bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[2], float fpos[2])
+bool ED_space_image_get_position(SpaceImage *sima,
+ struct ARegion *region,
+ int mval[2],
+ float fpos[2])
{
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
@@ -3201,13 +3217,12 @@ bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[
return false;
}
- UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fpos[0], &fpos[1]);
+ UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &fpos[0], &fpos[1]);
ED_space_image_release_buffer(sima, ibuf, lock);
return true;
}
-/* Returns color in linear space, matching ED_space_node_color_sample(). */
bool ED_space_image_color_sample(
SpaceImage *sima, ARegion *region, int mval[2], float r_col[3], bool *r_is_data)
{
@@ -3628,13 +3643,8 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event
ARegion *region = CTX_wm_region(C);
if (region->regiontype == RGN_TYPE_WINDOW) {
- SpaceImage *sima = CTX_wm_space_image(C);
-
- /* Local coordinate visible rect inside region, to accommodate overlapping ui. */
- const rcti *rect_visible = ED_region_visible_rect(region);
- const int region_bottom = rect_visible->ymin;
-
- if (event->mval[1] > (region_bottom + 16 * UI_DPI_FAC) || !ED_space_image_show_cache(sima)) {
+ const SpaceImage *sima = CTX_wm_space_image(C);
+ if (!ED_space_image_show_cache_and_mval_over(sima, region, event->mval)) {
return OPERATOR_PASS_THROUGH;
}
}
@@ -4142,3 +4152,5 @@ void IMAGE_OT_tile_fill(wmOperatorType *ot)
def_fill_tile(ot->srna);
}
+
+/** \} */
diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c
index c4f111264a3..84b85b396fe 100644
--- a/source/blender/editors/space_image/image_sequence.c
+++ b/source/blender/editors/space_image/image_sequence.c
@@ -115,79 +115,17 @@ static int image_cmp_frame(const void *a, const void *b)
return 0;
}
-/*
- * Checks whether the given filepath refers to a UDIM texture.
- * If yes, the range from 1001 to the highest tile is returned, otherwise 0.
- *
- * If the result is positive, the filepath will be overwritten with that of
- * the 1001 tile.
- *
- * udim_tiles may get filled even if the result ultimately is false!
- */
-static bool image_get_udim(char *filepath, ListBase *udim_tiles, int *udim_start, int *udim_range)
-{
- char filename[FILE_MAX], dirname[FILE_MAXDIR];
- BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
-
- ushort digits;
- char base_head[FILE_MAX], base_tail[FILE_MAX];
- int id = BLI_path_sequence_decode(filename, base_head, base_tail, &digits);
-
- if (id < 1001 || id > IMA_UDIM_MAX) {
- return false;
- }
-
- bool is_udim = true;
- int min_udim = IMA_UDIM_MAX + 1;
- int max_udim = 0;
-
- struct direntry *dir;
- uint totfile = BLI_filelist_dir_contents(dirname, &dir);
- for (int i = 0; i < totfile; i++) {
- if (!(dir[i].type & S_IFREG)) {
- continue;
- }
- char head[FILE_MAX], tail[FILE_MAX];
- id = BLI_path_sequence_decode(dir[i].relname, head, tail, &digits);
-
- if (digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) ||
- !(STREQLEN(base_tail, tail, FILE_MAX))) {
- continue;
- }
-
- if (id < 1001 || id > IMA_UDIM_MAX) {
- is_udim = false;
- break;
- }
-
- BLI_addtail(udim_tiles, BLI_genericNodeN(POINTER_FROM_INT(id)));
- min_udim = min_ii(min_udim, id);
- max_udim = max_ii(max_udim, id);
- }
- BLI_filelist_free(dir, totfile);
-
- if (is_udim && min_udim <= IMA_UDIM_MAX) {
- char primary_filename[FILE_MAX];
- BLI_path_sequence_encode(primary_filename, base_head, base_tail, digits, min_udim);
- BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename);
-
- *udim_start = min_udim;
- *udim_range = max_udim - min_udim + 1;
- return true;
- }
- return false;
-}
-
/**
* From a list of frames, compute the start (offset) and length of the sequence
- * of contiguous frames. If UDIM is detect, it will return UDIM tiles as well.
+ * of contiguous frames. If `detect_udim` is set, it will return UDIM tiles as well.
*/
static void image_detect_frame_range(ImageFrameRange *range, const bool detect_udim)
{
/* UDIM */
if (detect_udim) {
int udim_start, udim_range;
- bool result = image_get_udim(range->filepath, &range->udim_tiles, &udim_start, &udim_range);
+ bool result = BKE_image_get_tile_info(
+ range->filepath, &range->udim_tiles, &udim_start, &udim_range);
if (result) {
range->offset = udim_start;
@@ -217,7 +155,6 @@ static void image_detect_frame_range(ImageFrameRange *range, const bool detect_u
}
}
-/* Used for both images and volume file loading. */
ListBase ED_image_filesel_detect_sequences(Main *bmain, wmOperator *op, const bool detect_udim)
{
ListBase ranges;
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index cc6effd0f71..e81f3b6a490 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -668,7 +668,6 @@ static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image, ImageU
uh->image_ref.ptr = image;
uh->iuser = *iuser;
uh->iuser.scene = NULL;
- uh->iuser.ok = 1;
BLI_addtail(undo_handles, uh);
return uh;
}
@@ -990,7 +989,6 @@ static void image_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_image_undosys_type(UndoType *ut)
{
ut->name = "Image";
@@ -1041,7 +1039,6 @@ ListBase *ED_image_paint_tile_list_get(void)
return &us->paint_tiles;
}
-/* Restore painting image to previous state. Used for anchored and drag-dot style brushes. */
void ED_image_undo_restore(UndoStep *us)
{
ListBase *paint_tiles = &((ImageUndoStep *)us)->paint_tiles;
@@ -1060,10 +1057,6 @@ static ImageUndoStep *image_undo_push_begin(const char *name, int paint_mode)
return us;
}
-/**
- * The caller is responsible for running #ED_image_undo_push_end,
- * failure to do so causes an invalid state for the undo system.
- */
void ED_image_undo_push_begin(const char *name, int paint_mode)
{
image_undo_push_begin(name, paint_mode);
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index f14a8266cdd..eb5b6104a79 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -37,6 +37,7 @@
#include "BKE_context.h"
#include "BKE_image.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "RNA_access.h"
@@ -258,7 +259,7 @@ static void image_keymap(struct wmKeyConfig *keyconf)
static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
ScrArea *area = CTX_wm_area(C);
- if (ED_region_overlap_isect_any_xy(area, &event->x)) {
+ if (ED_region_overlap_isect_any_xy(area, event->xy)) {
return false;
}
if (drag->type == WM_DRAG_PATH) {
@@ -297,7 +298,7 @@ static void image_refresh(const bContext *C, ScrArea *area)
ima = ED_space_image(sima);
BKE_image_user_frame_calc(ima, &sima->iuser, scene->r.cfra);
- /* check if we have to set the image from the editmesh */
+ /* Check if we have to set the image from the edit-mesh. */
if (ima && (ima->source == IMA_SRC_VIEWER && sima->mode == SI_MODE_MASK)) {
if (scene->nodetree) {
Mask *mask = ED_space_image_get_mask(sima);
@@ -983,29 +984,19 @@ static void image_header_region_listener(const wmRegionListenerParams *params)
}
}
-static void image_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void image_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceImage *simg = (SpaceImage *)slink;
- if (!ELEM(GS(old_id->name), ID_IM, ID_GD, ID_MSK)) {
+ if (!BKE_id_remapper_has_mapping_for(mappings, FILTER_ID_IM | FILTER_ID_GD | FILTER_ID_MSK)) {
return;
}
- if ((ID *)simg->image == old_id) {
- simg->image = (Image *)new_id;
- id_us_ensure_real(new_id);
- }
-
- if ((ID *)simg->gpd == old_id) {
- simg->gpd = (bGPdata *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
- }
-
- if ((ID *)simg->mask_info.mask == old_id) {
- simg->mask_info.mask = (Mask *)new_id;
- id_us_ensure_real(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&simg->image, ID_REMAP_APPLY_ENSURE_REAL);
+ BKE_id_remapper_apply(mappings, (ID **)&simg->gpd, ID_REMAP_APPLY_UPDATE_REFCOUNT);
+ BKE_id_remapper_apply(mappings, (ID **)&simg->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL);
}
/**
@@ -1042,7 +1033,6 @@ static void image_space_subtype_item_extend(bContext *UNUSED(C),
/**************************** spacetype *****************************/
-/* only called once, from space/spacetypes.c */
void ED_spacetype_image(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype image");
diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt
index b6df07eec4e..144b21fb9b8 100644
--- a/source/blender/editors/space_info/CMakeLists.txt
+++ b/source/blender/editors/space_info/CMakeLists.txt
@@ -37,7 +37,7 @@ set(SRC
info_draw.c
info_ops.c
info_report.c
- info_stats.c
+ info_stats.cc
space_info.c
textview.c
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index a99396ecdf0..2a797fd1a78 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -408,13 +408,14 @@ void FILE_OT_unpack_item(wmOperatorType *ot)
static int make_paths_relative_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
- if (!G.relbase_valid) {
+ if (blendfile_path[0] == '\0') {
BKE_report(op->reports, RPT_WARNING, "Cannot set relative paths with an unsaved blend file");
return OPERATOR_CANCELLED;
}
- BKE_bpath_relative_convert(bmain, BKE_main_blendfile_path(bmain), op->reports);
+ BKE_bpath_relative_convert(bmain, blendfile_path, op->reports);
/* redraw everything so any changed paths register */
WM_main_add_notifier(NC_WINDOW, NULL);
@@ -445,13 +446,14 @@ void FILE_OT_make_paths_relative(wmOperatorType *ot)
static int make_paths_absolute_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
- if (!G.relbase_valid) {
+ if (blendfile_path[0] == '\0') {
BKE_report(op->reports, RPT_WARNING, "Cannot set absolute paths with an unsaved blend file");
return OPERATOR_CANCELLED;
}
- BKE_bpath_absolute_convert(bmain, BKE_main_blendfile_path(bmain), op->reports);
+ BKE_bpath_absolute_convert(bmain, blendfile_path, op->reports);
/* redraw everything so any changed paths register */
WM_main_add_notifier(NC_WINDOW, NULL);
@@ -564,7 +566,7 @@ void FILE_OT_find_missing_files(wmOperatorType *ot)
/** \name Report Box Operator
* \{ */
-/* NOTE(matt): Hard to decide whether to keep this as an operator,
+/* NOTE(@broken): Hard to decide whether to keep this as an operator,
* or turn it into a hard_coded UI control feature,
* handling TIMER events for all regions in `interface_handlers.c`.
* Not sure how good that is to be accessing UI data from
diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c
index 1062b76b1df..ce17450549e 100644
--- a/source/blender/editors/space_info/info_report.c
+++ b/source/blender/editors/space_info/info_report.c
@@ -299,6 +299,7 @@ static int box_select_exec(bContext *C, wmOperator *op)
}
/* ****** Box Select ****** */
+
void INFO_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.cc
index e749e1a7947..005ae0214cd 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.cc
@@ -18,8 +18,8 @@
* \ingroup spinfo
*/
-#include <stdio.h>
-#include <string.h>
+#include <cstdio>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -43,6 +43,7 @@
#include "BLT_translation.h"
+#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_blender_version.h"
#include "BKE_context.h"
@@ -70,9 +71,11 @@
#include "GPU_capabilities.h"
+ENUM_OPERATORS(eUserpref_StatusBar_Flag, STATUSBAR_SHOW_VERSION)
+
#define MAX_INFO_NUM_LEN 16
-typedef struct SceneStats {
+struct SceneStats {
uint64_t totvert, totvertsel, totvertsculpt;
uint64_t totedge, totedgesel;
uint64_t totface, totfacesel, totfacesculpt;
@@ -81,9 +84,9 @@ typedef struct SceneStats {
uint64_t totlamp, totlampsel;
uint64_t tottri;
uint64_t totgplayer, totgpframe, totgpstroke, totgppoint;
-} SceneStats;
+};
-typedef struct SceneStatsFmt {
+struct SceneStatsFmt {
/* Totals */
char totvert[MAX_INFO_NUM_LEN], totvertsel[MAX_INFO_NUM_LEN], totvertsculpt[MAX_INFO_NUM_LEN];
char totface[MAX_INFO_NUM_LEN], totfacesel[MAX_INFO_NUM_LEN];
@@ -94,16 +97,16 @@ typedef struct SceneStatsFmt {
char tottri[MAX_INFO_NUM_LEN];
char totgplayer[MAX_INFO_NUM_LEN], totgpframe[MAX_INFO_NUM_LEN];
char totgpstroke[MAX_INFO_NUM_LEN], totgppoint[MAX_INFO_NUM_LEN];
-} SceneStatsFmt;
+};
static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *stats)
{
- if (me_eval == NULL) {
+ if (me_eval == nullptr) {
return false;
}
int totvert, totedge, totface, totloop;
- if (me_eval->runtime.subdiv_ccg != NULL) {
+ if (me_eval->runtime.subdiv_ccg != nullptr) {
const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop);
}
@@ -166,14 +169,14 @@ static void stats_object(Object *ob,
case OB_CURVE:
case OB_FONT: {
const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob);
- if ((me_eval != NULL) && !BLI_gset_add(objects_gset, (void *)me_eval)) {
+ if ((me_eval != nullptr) && !BLI_gset_add(objects_gset, (void *)me_eval)) {
break;
}
if (stats_mesheval(me_eval, is_selected, stats)) {
break;
}
- ATTR_FALLTHROUGH; /* Fallthrough to displist. */
+ ATTR_FALLTHROUGH; /* Fall-through to displist. */
}
case OB_MBALL: {
int totv = 0, totf = 0, tottri = 0;
@@ -242,10 +245,9 @@ static void stats_object_edit(Object *obedit, SceneStats *stats)
}
else if (obedit->type == OB_ARMATURE) {
/* Armature Edit */
- bArmature *arm = obedit->data;
- EditBone *ebo;
+ bArmature *arm = static_cast<bArmature *>(obedit->data);
- for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
stats->totbone++;
if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
@@ -274,14 +276,13 @@ static void stats_object_edit(Object *obedit, SceneStats *stats)
}
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { /* OB_FONT has no cu->editnurb */
/* Curve Edit */
- Curve *cu = obedit->data;
- Nurb *nu;
+ Curve *cu = static_cast<Curve *>(obedit->data);
BezTriple *bezt;
BPoint *bp;
int a;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- for (nu = nurbs->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, nurbs) {
if (nu->type == CU_BEZIER) {
bezt = nu->bezt;
a = nu->pntsu;
@@ -314,10 +315,9 @@ static void stats_object_edit(Object *obedit, SceneStats *stats)
}
else if (obedit->type == OB_MBALL) {
/* MetaBall Edit */
- MetaBall *mball = obedit->data;
- MetaElem *ml;
+ MetaBall *mball = static_cast<MetaBall *>(obedit->data);
- for (ml = mball->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, mball->editelems) {
stats->totvert++;
if (ml->flag & SELECT) {
stats->totvertsel++;
@@ -326,7 +326,7 @@ static void stats_object_edit(Object *obedit, SceneStats *stats)
}
else if (obedit->type == OB_LATTICE) {
/* Lattice Edit */
- Lattice *lt = obedit->data;
+ Lattice *lt = static_cast<Lattice *>(obedit->data);
Lattice *editlatt = lt->editlatt->latt;
BPoint *bp;
int a;
@@ -347,13 +347,12 @@ static void stats_object_edit(Object *obedit, SceneStats *stats)
static void stats_object_pose(const Object *ob, SceneStats *stats)
{
if (ob->pose) {
- bArmature *arm = ob->data;
- bPoseChannel *pchan;
+ bArmature *arm = static_cast<bArmature *>(ob->data);
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
stats->totbone++;
if (pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
- if (pchan->bone->layer & arm->layer) {
+ if (BKE_pose_is_layer_visible(arm, pchan)) {
stats->totbonesel++;
}
}
@@ -372,7 +371,7 @@ static void stats_object_sculpt(const Object *ob, SceneStats *stats)
SculptSession *ss = ob->sculpt;
- if (!ss) {
+ if (ss == nullptr || ss->pbvh == nullptr) {
return;
}
@@ -460,7 +459,7 @@ static void stats_update(Depsgraph *depsgraph,
stats_object(ob_iter, v3d_local, stats, objects_gset);
}
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END;
- BLI_gset_free(objects_gset, NULL);
+ BLI_gset_free(objects_gset, nullptr);
}
}
@@ -476,7 +475,7 @@ void ED_info_stats_clear(wmWindowManager *wm, ViewLayer *view_layer)
const bScreen *screen = WM_window_get_active_screen(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area->spacetype == SPACE_VIEW3D) {
- View3D *v3d = area->spacedata.first;
+ View3D *v3d = (View3D *)area->spacedata.first;
if (v3d->localvd) {
MEM_SAFE_FREE(v3d->runtime.local_stats);
}
@@ -490,14 +489,14 @@ static bool format_stats(
{
/* Create stats if they don't already exist. */
SceneStats **stats_p = (v3d_local) ? &v3d_local->runtime.local_stats : &view_layer->stats;
- if (*stats_p == NULL) {
+ if (*stats_p == nullptr) {
/* Don't access dependency graph if interface is marked as locked. */
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
if (wm->is_interface_locked) {
return false;
}
Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
- *stats_p = MEM_mallocN(sizeof(SceneStats), __func__);
+ *stats_p = (SceneStats *)MEM_mallocN(sizeof(SceneStats), __func__);
stats_update(depsgraph, view_layer, v3d_local, *stats_p);
}
@@ -542,7 +541,7 @@ static void get_stats_string(
{
Object *ob = OBACT(view_layer);
Object *obedit = OBEDIT_FROM_OBACT(ob);
- eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT;
+ eObjectMode object_mode = ob ? (eObjectMode)ob->mode : OB_MODE_OBJECT;
LayerCollection *layer_collection = view_layer->active_collection;
if (object_mode == OB_MODE_OBJECT) {
@@ -646,7 +645,7 @@ static const char *info_statusbar_string(Main *bmain,
/* Scene statistics. */
if (statusbar_flag & STATUSBAR_SHOW_STATS) {
SceneStatsFmt stats_fmt;
- if (format_stats(bmain, scene, view_layer, NULL, &stats_fmt)) {
+ if (format_stats(bmain, scene, view_layer, nullptr, &stats_fmt)) {
get_stats_string(info + ofs, len, &ofs, view_layer, &stats_fmt);
}
}
@@ -723,15 +722,10 @@ static void stats_row(int col1,
BLF_draw_default(col2, *y, 0.0f, values, sizeof(values));
}
-/**
- * \param v3d_local: Pass this argument to calculate view-port local statistics.
- * Note that this must only be used for local-view, otherwise report specific statistics
- * will be written into the global scene statistics giving incorrect results.
- */
void ED_info_draw_stats(
Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, int x, int *y, int height)
{
- BLI_assert(v3d_local == NULL || v3d_local->localvd != NULL);
+ BLI_assert(v3d_local == nullptr || v3d_local->localvd != nullptr);
SceneStatsFmt stats_fmt;
if (!format_stats(bmain, scene, view_layer, v3d_local, &stats_fmt)) {
return;
@@ -739,7 +733,7 @@ void ED_info_draw_stats(
Object *ob = OBACT(view_layer);
Object *obedit = OBEDIT_FROM_OBACT(ob);
- eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT;
+ eObjectMode object_mode = ob ? (eObjectMode)ob->mode : OB_MODE_OBJECT;
const int font_id = BLF_set_default();
UI_FontThemeColor(font_id, TH_TEXT_HI);
@@ -801,7 +795,7 @@ void ED_info_draw_stats(
stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height);
stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height);
- stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
+ stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height);
}
else if (obedit->type == OB_ARMATURE) {
stats_row(col1, labels[JOINTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
@@ -816,15 +810,15 @@ void ED_info_draw_stats(
stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
}
else if ((ob) && (ob->type == OB_GPENCIL)) {
- stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, NULL, y, height);
- stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, NULL, y, height);
- stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, NULL, y, height);
- stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, NULL, y, height);
+ stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, nullptr, y, height);
+ stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, nullptr, y, height);
+ stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, nullptr, y, height);
+ stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, nullptr, y, height);
}
else if (ob && (object_mode & OB_MODE_SCULPT)) {
if (stats_is_object_dynamic_topology_sculpt(ob)) {
- stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, NULL, y, height);
- stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, nullptr, y, height);
+ stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height);
}
else {
stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, stats_fmt.totvert, y, height);
@@ -835,10 +829,10 @@ void ED_info_draw_stats(
stats_row(col1, labels[LIGHTS], col2, stats_fmt.totlampsel, stats_fmt.totlamp, y, height);
}
else {
- stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height);
- stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, NULL, y, height);
- stats_row(col1, labels[FACES], col2, stats_fmt.totface, NULL, y, height);
- stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, nullptr, y, height);
+ stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, nullptr, y, height);
+ stats_row(col1, labels[FACES], col2, stats_fmt.totface, nullptr, y, height);
+ stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height);
}
BLF_disable(font_id, BLF_SHADOW);
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index e56bb44b1e6..1d28aace7f2 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -264,7 +264,6 @@ static void info_header_region_message_subscribe(const wmRegionMessageSubscribeP
WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_info(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype info");
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index e656155fb13..cc14abd8bb3 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -303,13 +303,6 @@ static bool textview_draw_string(TextViewDrawState *tds,
return true;
}
-/**
- * \param r_mval_pick_item: The resulting item clicked on using \a mval_init.
- * Set from the void pointer which holds the current iterator.
- * Its type depends on the data being iterated over.
- * \param r_mval_pick_offset: The offset in bytes of the \a mval_init.
- * Use for selection.
- */
int textview_draw(TextViewContext *tvc,
const bool do_draw,
const int mval_init[2],
diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h
index 7520dbce191..38c073a328a 100644
--- a/source/blender/editors/space_info/textview.h
+++ b/source/blender/editors/space_info/textview.h
@@ -73,8 +73,15 @@ typedef struct TextViewContext {
} TextViewContext;
+/**
+ * \param r_mval_pick_item: The resulting item clicked on using \a mval_init.
+ * Set from the void pointer which holds the current iterator.
+ * Its type depends on the data being iterated over.
+ * \param r_mval_pick_offset: The offset in bytes of the \a mval_init.
+ * Use for selection.
+ */
int textview_draw(struct TextViewContext *tvc,
- const bool do_draw,
+ bool do_draw,
const int mval_init[2],
void **r_mval_pick_item,
int *r_mval_pick_offset);
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 215e865d194..81932589663 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -312,7 +312,7 @@ static void nla_panel_animdata(const bContext *C, Panel *panel)
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
uiItemL(row, id->name + 2, RNA_struct_ui_icon(id_ptr.type)); /* id-block (src) */
- uiItemL(row, "", ICON_SMALL_TRI_RIGHT_VEC); /* expander */
+ uiItemL(row, "", ICON_RIGHTARROW); /* expander */
uiItemL(row, IFACE_("Animation Data"), ICON_ANIM_DATA); /* animdata */
uiItemS(layout);
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 1b87a8c6b9d..47af7a66f6f 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -629,7 +629,6 @@ void NLA_OT_action_unlink(wmOperatorType *ot)
/* ******************** Add Tracks Operator ***************************** */
/* Add NLA Tracks to the same AnimData block as a selected track, or above the selected tracks */
-/* helper - add NLA Tracks alongside existing ones */
bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel)
{
ListBase anim_data = {NULL, NULL};
@@ -678,7 +677,6 @@ bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel)
return added;
}
-/* helper - add NLA Tracks to empty (and selected) AnimData blocks */
bool nlaedit_add_tracks_empty(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 4694d8652f6..7dfe0e89e90 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -65,9 +65,6 @@
/* Action-Line ---------------------- */
-/* get colors for drawing Action-Line
- * NOTE: color returned includes fine-tuned alpha!
- */
void nla_action_get_color(AnimData *adt, bAction *act, float color[4])
{
if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
@@ -111,11 +108,11 @@ static void nla_action_draw_keyframes(
/* draw a darkened region behind the strips
* - get and reset the background color, this time without the alpha to stand out better
- * (amplified alpha is used instead)
+ * (amplified alpha is used instead, but clamped to avoid 100% opacity)
*/
float color[4];
nla_action_get_color(adt, act, color);
- color[3] *= 2.5f;
+ color[3] = min_ff(0.7f, color[3] * 2.5f);
GPUVertFormat *format = immVertexFormat();
uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -323,12 +320,19 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, uin
{
const float yheight = ymaxc - yminc;
- immUniformColor3f(0.7f, 0.7f, 0.7f);
-
/* draw with AA'd line */
GPU_line_smooth(true);
GPU_blend(GPU_BLEND_ALPHA);
+ /* Fully opaque line on selected strips. */
+ if (strip->flag & NLASTRIP_FLAG_SELECT) {
+ /* TODO: Use theme setting. */
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+ }
+ else {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
+ }
+
/* influence -------------------------- */
if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
FCurve *fcu = BKE_fcurve_find(&strip->fcurves, "influence", 0);
@@ -501,7 +505,7 @@ static void nla_draw_strip(SpaceNla *snla,
/* strip is in normal track */
UI_draw_roundbox_corner_set(UI_CNR_ALL); /* all corners rounded */
- UI_draw_roundbox_shade_x(
+ UI_draw_roundbox_4fv(
&(const rctf){
.xmin = strip->start,
.xmax = strip->end,
@@ -509,9 +513,7 @@ static void nla_draw_strip(SpaceNla *snla,
.ymax = ymaxc,
},
true,
- 0.0,
- 0.5,
- 0.1,
+ 0.0f,
color);
/* restore current vertex format & program (roundbox trashes it) */
@@ -545,11 +547,9 @@ static void nla_draw_strip(SpaceNla *snla,
/* draw strip outline
* - color used here is to indicate active vs non-active
*/
- if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
+ if (strip->flag & (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT)) {
/* strip should appear 'sunken', so draw a light border around it */
- color[0] = 0.9f; /* FIXME: hardcoded temp-hack colors */
- color[1] = 1.0f;
- color[2] = 0.9f;
+ color[0] = color[1] = color[2] = 1.0f; /* FIXME: hardcoded temp-hack colors */
}
else {
/* strip should appear to stand out, so draw a dark border around it */
@@ -566,7 +566,7 @@ static void nla_draw_strip(SpaceNla *snla,
}
else {
/* non-muted - draw solid, rounded outline */
- UI_draw_roundbox_shade_x(
+ UI_draw_roundbox_4fv(
&(const rctf){
.xmin = strip->start,
.xmax = strip->end,
@@ -574,9 +574,7 @@ static void nla_draw_strip(SpaceNla *snla,
.ymax = ymaxc,
},
false,
- 0.0,
- 0.0,
- 0.1,
+ 0.0f,
color);
/* restore current vertex format & program (roundbox trashes it) */
@@ -661,7 +659,7 @@ static void nla_draw_strip_text(AnimData *adt,
}
/* set text color - if colors (see above) are light, draw black text, otherwise draw white */
- if (strip->flag & (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_TWEAKUSER)) {
+ if (strip->flag & (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_TWEAKUSER)) {
col[0] = col[1] = col[2] = 0;
}
else {
@@ -785,6 +783,11 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
case ANIMTYPE_NLAACTION: {
AnimData *adt = ale->adt;
+ /* Draw the manually set intended playback frame range highlight. */
+ if (ale->data) {
+ ANIM_draw_action_framerange(adt, ale->data, v2d, ymin, ymax);
+ }
+
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
@@ -805,29 +808,6 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
immRectf(
pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP, v2d->cur.xmax, ymax - NLACHANNEL_SKIP);
- /* draw 'embossed' lines above and below the strip for effect */
- /* white base-lines */
- GPU_line_width(2.0f);
- immUniformColor4f(1.0f, 1.0f, 1.0f, 0.3f);
- immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP);
- immVertex2f(pos, v2d->cur.xmax, ymin + NLACHANNEL_SKIP);
- immVertex2f(pos, v2d->cur.xmin, ymax - NLACHANNEL_SKIP);
- immVertex2f(pos, v2d->cur.xmax, ymax - NLACHANNEL_SKIP);
- immEnd();
-
- /* black top-lines */
- GPU_line_width(1.0f);
- immUniformColor3f(0.0f, 0.0f, 0.0f);
- immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP);
- immVertex2f(pos, v2d->cur.xmax, ymin + NLACHANNEL_SKIP);
- immVertex2f(pos, v2d->cur.xmin, ymax - NLACHANNEL_SKIP);
- immVertex2f(pos, v2d->cur.xmax, ymax - NLACHANNEL_SKIP);
- immEnd();
-
- /* TODO: these lines but better --^ */
-
immUnbindProgram();
/* draw keyframes in the action */
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index c75b874833a..1376dade659 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -71,7 +71,6 @@
/** \name Public Utilities
* \{ */
-/* Perform validation for blending/extend settings */
void ED_nla_postop_refresh(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
@@ -205,7 +204,6 @@ void NLA_OT_tweakmode_enter(wmOperatorType *ot)
/** \name Disable Tweak-Mode Operator
* \{ */
-/* NLA Editor internal API function for exiting tweak-mode. */
bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
{
ListBase anim_data = {NULL, NULL};
@@ -402,9 +400,9 @@ static int nlaedit_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
void NLA_OT_previewrange_set(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Auto-Set Preview Range";
+ ot->name = "Set Preview Range to Selected";
ot->idname = "NLA_OT_previewrange_set";
- ot->description = "Automatically set Preview Range based on range of keyframes";
+ ot->description = "Set Preview Range based on extends of selected strips";
/* api callbacks */
ot->exec = nlaedit_previewrange_exec;
@@ -2193,8 +2191,19 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
* and recalculate the extents of the action now that it has been scaled
* but leave everything else alone
*/
+ const float start = nlastrip_get_frame(strip, strip->actstart, NLATIME_CONVERT_MAP);
+ const float end = nlastrip_get_frame(strip, strip->actend, NLATIME_CONVERT_MAP);
+
+ if (strip->act->flag & ACT_FRAME_RANGE) {
+ strip->act->frame_start = nlastrip_get_frame(
+ strip, strip->act->frame_start, NLATIME_CONVERT_MAP);
+ strip->act->frame_end = nlastrip_get_frame(
+ strip, strip->act->frame_end, NLATIME_CONVERT_MAP);
+ }
+
strip->scale = 1.0f;
- calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+ strip->actstart = start;
+ strip->actend = end;
ale->update |= ANIM_UPDATE_DEPS;
}
diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h
index 9a9ea161f56..dd322dd2ad1 100644
--- a/source/blender/editors/space_nla/nla_intern.h
+++ b/source/blender/editors/space_nla/nla_intern.h
@@ -75,6 +75,9 @@ enum eNlaEdit_Snap_Mode {
/* --- */
+/**
+ * NLA Editor internal API function for exiting tweak-mode.
+ */
bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo);
void NLA_OT_tweakmode_enter(wmOperatorType *ot);
@@ -121,7 +124,13 @@ void NLA_OT_fmodifier_paste(wmOperatorType *ot);
/* **************************************** */
/* nla_channels.c */
+/**
+ * Helper - add NLA Tracks alongside existing ones.
+ */
bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel);
+/**
+ * helper - add NLA Tracks to empty (and selected) AnimData blocks.
+ */
bool nlaedit_add_tracks_empty(bAnimContext *ac);
/* --- */
@@ -139,9 +148,18 @@ void NLA_OT_selected_objects_add(wmOperatorType *ot);
/* **************************************** */
/* nla_ops.c */
+/**
+ * Tweak-mode is NOT enabled.
+ */
bool nlaop_poll_tweakmode_off(bContext *C);
+/**
+ * Tweak-mode IS enabled.
+ */
bool nlaop_poll_tweakmode_on(bContext *C);
+/**
+ * Is tweak-mode enabled - for use in NLA operator code.
+ */
bool nlaedit_is_tweakmode_on(bAnimContext *ac);
/* --- */
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index 28f194877fa..33449bed798 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -39,7 +39,6 @@
/* ************************** poll callbacks for operators **********************************/
-/* Tweak-mode is NOT enabled. */
bool nlaop_poll_tweakmode_off(bContext *C)
{
Scene *scene;
@@ -62,7 +61,6 @@ bool nlaop_poll_tweakmode_off(bContext *C)
return 1;
}
-/* Tweak-mode IS enabled. */
bool nlaop_poll_tweakmode_on(bContext *C)
{
Scene *scene;
@@ -85,7 +83,6 @@ bool nlaop_poll_tweakmode_on(bContext *C)
return 1;
}
-/* is tweak-mode enabled - for use in NLA operator code */
bool nlaedit_is_tweakmode_on(bAnimContext *ac)
{
if (ac && ac->scene) {
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index 8b44c26f07c..962b5151661 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -33,6 +33,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_anim_api.h"
@@ -577,21 +578,19 @@ static void nla_listener(const wmSpaceTypeListenerParams *params)
}
}
-static void nla_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void nla_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceNla *snla = (SpaceNla *)slink;
- if (snla->ads) {
- if ((ID *)snla->ads->filter_grp == old_id) {
- snla->ads->filter_grp = (Collection *)new_id;
- }
- if ((ID *)snla->ads->source == old_id) {
- snla->ads->source = new_id;
- }
+ if (snla->ads == NULL) {
+ return;
}
+ BKE_id_remapper_apply(mappings, (ID **)&snla->ads->filter_grp, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, (ID **)&snla->ads->source, ID_REMAP_APPLY_DEFAULT);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_nla(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype nla");
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index 80d3b43bf6b..41d6388c947 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -39,21 +39,22 @@ set(INC
set(SRC
drawnode.cc
+ link_drag_search.cc
node_add.cc
+ node_context_path.cc
node_draw.cc
node_edit.cc
node_geometry_attribute_search.cc
- node_gizmo.c
+ node_gizmo.cc
node_group.cc
- node_ops.c
+ node_ops.cc
node_relationships.cc
node_select.cc
node_templates.cc
- node_toolbar.cc
node_view.cc
- space_node.c
+ space_node.cc
- node_intern.h
+ node_intern.hh
)
set(LIB
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index b4a9b90434c..94da7d55e5d 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -22,8 +22,6 @@
* \brief lower level node drawing for nodes (boarders, headers etc), also node layout.
*/
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
#include "BLI_system.h"
#include "BLI_threads.h"
@@ -31,7 +29,6 @@
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
-#include "DNA_text_types.h"
#include "DNA_userdef_types.h"
#include "BKE_context.h"
@@ -39,6 +36,8 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
+#include "BKE_scene.h"
#include "BKE_tracking.h"
#include "BLF_api.h"
@@ -52,7 +51,9 @@
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_platform.h"
+#include "GPU_shader_shared.h"
#include "GPU_state.h"
+#include "GPU_uniform_buffer.h"
#include "DRW_engine.h"
@@ -73,9 +74,12 @@
#include "NOD_composite.h"
#include "NOD_geometry.h"
+#include "NOD_node_declaration.hh"
#include "NOD_shader.h"
#include "NOD_texture.h"
-#include "node_intern.h" /* own include */
+#include "node_intern.hh" /* own include */
+
+namespace blender::ed::space_node {
/* Default flags for uiItemR(). Name is kept short since this is used a lot in this file. */
#define DEFAULT_FLAGS UI_ITEM_R_SPLIT_EMPTY_NAME
@@ -134,24 +138,11 @@ static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA
static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
-#if 0
- /* XXX no context access here. */
- bNode *node = (bNode*)ptr->data;
- CurveMapping *cumap = node->storage;
-
- if (cumap) {
- cumap->flag |= CUMA_DRAW_CFRA;
- if (node->custom1 < node->custom2) {
- cumap->sample[0] = (float)(CFRA - node->custom1) / (float)(node->custom2 - node->custom1);
- }
- }
-#endif
-
uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false);
- uiLayout *row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Sta"), ICON_NONE);
- uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE);
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Start"), ICON_NONE);
+ uiItemR(col, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE);
}
static void node_buts_colorramp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -164,6 +155,13 @@ static void node_buts_curvevec(uiLayout *layout, bContext *UNUSED(C), PointerRNA
uiTemplateCurveMapping(layout, ptr, "mapping", 'v', false, false, false, false);
}
+static void node_buts_curvefloat(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiTemplateCurveMapping(layout, ptr, "mapping", 0, false, false, false, false);
+}
+
+} // namespace blender::ed::space_node
+
#define SAMPLE_FLT_ISNONE FLT_MAX
/* Bad bad, 2.5 will do better? ... no it won't! */
static float _sample_col[4] = {SAMPLE_FLT_ISNONE};
@@ -177,6 +175,8 @@ void ED_node_sample_set(const float col[4])
}
}
+namespace blender::ed::space_node {
+
static void node_buts_curvecol(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
@@ -222,43 +222,56 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA
}
}
-static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "clamp_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "interpolation_type", DEFAULT_FLAGS, "", ICON_NONE);
- if (!ELEM(RNA_enum_get(ptr, "interpolation_type"),
- NODE_MAP_RANGE_SMOOTHSTEP,
- NODE_MAP_RANGE_SMOOTHERSTEP)) {
- uiItemR(layout, ptr, "clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
uiItemR(layout, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
}
-static int node_resize_area_default(bNode *node, int x, int y)
+NodeResizeDirection node_get_resize_direction(const bNode *node, const int x, const int y)
{
+ if (node->type == NODE_FRAME) {
+ const float size = 10.0f;
+ NodeFrame *data = (NodeFrame *)node->storage;
+
+ /* shrinking frame size is determined by child nodes */
+ if (!(data->flag & NODE_FRAME_RESIZEABLE)) {
+ return NODE_RESIZE_NONE;
+ }
+
+ NodeResizeDirection dir = NODE_RESIZE_NONE;
+
+ const rctf &totr = node->totr;
+ if (x >= totr.xmax - size && x < totr.xmax && y >= totr.ymin && y < totr.ymax) {
+ dir |= NODE_RESIZE_RIGHT;
+ }
+ if (x >= totr.xmin && x < totr.xmin + size && y >= totr.ymin && y < totr.ymax) {
+ dir |= NODE_RESIZE_LEFT;
+ }
+ if (x >= totr.xmin && x < totr.xmax && y >= totr.ymax - size && y < totr.ymax) {
+ dir |= NODE_RESIZE_TOP;
+ }
+ if (x >= totr.xmin && x < totr.xmax && y >= totr.ymin && y < totr.ymin + size) {
+ dir |= NODE_RESIZE_BOTTOM;
+ }
+
+ return dir;
+ }
+
if (node->flag & NODE_HIDDEN) {
- rctf totr = node->totr;
/* right part of node */
- totr.xmin = node->totr.xmax - 20.0f;
+ rctf totr = node->totr;
+ totr.xmin = node->totr.xmax - 1.0f * U.widget_unit;
if (BLI_rctf_isect_pt(&totr, x, y)) {
return NODE_RESIZE_RIGHT;
}
- return 0;
+ return NODE_RESIZE_NONE;
}
const float size = NODE_RESIZE_MARGIN;
- rctf totr = node->totr;
- int dir = 0;
+ const rctf &totr = node->totr;
+ NodeResizeDirection dir = NODE_RESIZE_NONE;
if (x >= totr.xmax - size && x < totr.xmax && y >= totr.ymin && y < totr.ymax) {
dir |= NODE_RESIZE_RIGHT;
@@ -277,225 +290,6 @@ static void node_draw_buttons_group(uiLayout *layout, bContext *C, PointerRNA *p
layout, C, ptr, "node_tree", nullptr, nullptr, nullptr, UI_TEMPLATE_ID_FILTER_ALL, nullptr);
}
-/* XXX Does a bounding box update by iterating over all children.
- * Not ideal to do this in every draw call, but doing as transform callback doesn't work,
- * since the child node totr rects are not updated properly at that point.
- */
-static void node_draw_frame_prepare(const bContext *UNUSED(C), bNodeTree *ntree, bNode *node)
-{
- const float margin = 1.5f * U.widget_unit;
- NodeFrame *data = (NodeFrame *)node->storage;
-
- /* init rect from current frame size */
- rctf rect;
- node_to_view(node, node->offsetx, node->offsety, &rect.xmin, &rect.ymax);
- node_to_view(
- node, node->offsetx + node->width, node->offsety - node->height, &rect.xmax, &rect.ymin);
-
- /* frame can be resized manually only if shrinking is disabled or no children are attached */
- data->flag |= NODE_FRAME_RESIZEABLE;
- /* for shrinking bbox, initialize the rect from first child node */
- bool bbinit = (data->flag & NODE_FRAME_SHRINK);
- /* fit bounding box to all children */
- LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) {
- if (tnode->parent != node) {
- continue;
- }
-
- /* add margin to node rect */
- rctf noderect = tnode->totr;
- noderect.xmin -= margin;
- noderect.xmax += margin;
- noderect.ymin -= margin;
- noderect.ymax += margin;
-
- /* first child initializes frame */
- if (bbinit) {
- bbinit = false;
- rect = noderect;
- data->flag &= ~NODE_FRAME_RESIZEABLE;
- }
- else {
- BLI_rctf_union(&rect, &noderect);
- }
- }
-
- /* now adjust the frame size from view-space bounding box */
- node_from_view(node, rect.xmin, rect.ymax, &node->offsetx, &node->offsety);
- float xmax, ymax;
- node_from_view(node, rect.xmax, rect.ymin, &xmax, &ymax);
- node->width = xmax - node->offsetx;
- node->height = -ymax + node->offsety;
-
- node->totr = rect;
-}
-
-static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float aspect)
-{
- /* XXX font id is crap design */
- const int fontid = UI_style_get()->widgetlabel.uifont_id;
- NodeFrame *data = (NodeFrame *)node->storage;
- const int font_size = data->label_size / aspect;
-
- char label[MAX_NAME];
- nodeLabel(ntree, node, label, sizeof(label));
-
- BLF_enable(fontid, BLF_ASPECT);
- BLF_aspect(fontid, aspect, aspect, 1.0f);
- /* clamp otherwise it can suck up a LOT of memory */
- BLF_size(fontid, MIN2(24, font_size), U.dpi);
-
- /* title color */
- int color_id = node_get_colorid(node);
- uchar color[3];
- UI_GetThemeColorBlendShade3ubv(TH_TEXT, color_id, 0.4f, 10, color);
- BLF_color3ubv(fontid, color);
-
- const float margin = (float)(NODE_DY / 4);
- const float width = BLF_width(fontid, label, sizeof(label));
- const float ascender = BLF_ascender(fontid);
- const int label_height = ((margin / aspect) + (ascender * aspect));
-
- /* 'x' doesn't need aspect correction */
- rctf *rct = &node->totr;
- /* XXX a bit hacky, should use separate align values for x and y */
- float x = BLI_rctf_cent_x(rct) - (0.5f * width);
- float y = rct->ymax - label_height;
-
- /* label */
- const bool has_label = node->label[0] != '\0';
- if (has_label) {
- BLF_position(fontid, x, y, 0);
- BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX);
- }
-
- /* draw text body */
- if (node->id) {
- Text *text = (Text *)node->id;
- const int line_height_max = BLF_height_max(fontid);
- const float line_spacing = (line_height_max * aspect);
- const float line_width = (BLI_rctf_size_x(rct) - margin) / aspect;
-
- /* 'x' doesn't need aspect correction */
- x = rct->xmin + margin;
- y = rct->ymax - label_height - (has_label ? line_spacing : 0);
-
- /* early exit */
- int y_min = y + ((margin * 2) - (y - rct->ymin));
-
- BLF_enable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
- BLF_clipping(fontid,
- rct->xmin,
- /* round to avoid clipping half-way through a line */
- y - (floorf(((y - rct->ymin) - (margin * 2)) / line_spacing) * line_spacing),
- rct->xmin + line_width,
- rct->ymax);
-
- BLF_wordwrap(fontid, line_width);
-
- LISTBASE_FOREACH (TextLine *, line, &text->lines) {
- struct ResultBLF info;
- if (line->line[0]) {
- BLF_position(fontid, x, y, 0);
- BLF_draw_ex(fontid, line->line, line->len, &info);
- y -= line_spacing * info.lines;
- }
- else {
- y -= line_spacing;
- }
- if (y < y_min) {
- break;
- }
- }
-
- BLF_disable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
- }
-
- BLF_disable(fontid, BLF_ASPECT);
-}
-
-static void node_draw_frame(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey UNUSED(key))
-{
-
- /* skip if out of view */
- if (BLI_rctf_isect(&node->totr, &region->v2d.cur, nullptr) == false) {
- UI_block_end(C, node->block);
- node->block = nullptr;
- return;
- }
-
- float color[4];
- UI_GetThemeColor4fv(TH_NODE_FRAME, color);
- const float alpha = color[3];
-
- /* shadow */
- node_draw_shadow(snode, node, BASIS_RAD, alpha);
-
- /* body */
- if (node->flag & NODE_CUSTOM_COLOR) {
- rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], alpha);
- }
- else {
- UI_GetThemeColor4fv(TH_NODE_FRAME, color);
- }
-
- const rctf *rct = &node->totr;
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(rct, true, BASIS_RAD, color);
-
- /* outline active and selected emphasis */
- if (node->flag & SELECT) {
- if (node->flag & NODE_ACTIVE) {
- UI_GetThemeColorShadeAlpha4fv(TH_ACTIVE, 0, -40, color);
- }
- else {
- UI_GetThemeColorShadeAlpha4fv(TH_SELECT, 0, -40, color);
- }
-
- UI_draw_roundbox_aa(rct, false, BASIS_RAD, color);
- }
-
- /* label and text */
- node_draw_frame_label(ntree, node, snode->runtime->aspect);
-
- UI_block_end(C, node->block);
- UI_block_draw(C, node->block);
- node->block = nullptr;
-}
-
-static int node_resize_area_frame(bNode *node, int x, int y)
-{
- const float size = 10.0f;
- NodeFrame *data = (NodeFrame *)node->storage;
- rctf totr = node->totr;
- int dir = 0;
-
- /* shrinking frame size is determined by child nodes */
- if (!(data->flag & NODE_FRAME_RESIZEABLE)) {
- return 0;
- }
-
- if (x >= totr.xmax - size && x < totr.xmax && y >= totr.ymin && y < totr.ymax) {
- dir |= NODE_RESIZE_RIGHT;
- }
- if (x >= totr.xmin && x < totr.xmin + size && y >= totr.ymin && y < totr.ymax) {
- dir |= NODE_RESIZE_LEFT;
- }
- if (x >= totr.xmin && x < totr.xmax && y >= totr.ymax - size && y < totr.ymax) {
- dir |= NODE_RESIZE_TOP;
- }
- if (x >= totr.xmin && x < totr.xmax && y >= totr.ymin && y < totr.ymin + size) {
- dir |= NODE_RESIZE_BOTTOM;
- }
-
- return dir;
-}
-
static void node_buts_frame_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "label_size", DEFAULT_FLAGS, IFACE_("Label Size"), ICON_NONE);
@@ -503,124 +297,6 @@ static void node_buts_frame_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA
uiItemR(layout, ptr, "text", DEFAULT_FLAGS, nullptr, ICON_NONE);
}
-#define NODE_REROUTE_SIZE 8.0f
-
-static void node_draw_reroute_prepare(const bContext *UNUSED(C),
- bNodeTree *UNUSED(ntree),
- bNode *node)
-{
- /* get "global" coords */
- float locx, locy;
- node_to_view(node, 0.0f, 0.0f, &locx, &locy);
-
- /* reroute node has exactly one input and one output, both in the same place */
- bNodeSocket *nsock = (bNodeSocket *)node->outputs.first;
- nsock->locx = locx;
- nsock->locy = locy;
-
- nsock = (bNodeSocket *)node->inputs.first;
- nsock->locx = locx;
- nsock->locy = locy;
-
- const float size = NODE_REROUTE_SIZE;
- node->width = size * 2;
- node->totr.xmin = locx - size;
- node->totr.xmax = locx + size;
- node->totr.ymax = locy + size;
- node->totr.ymin = locy - size;
-}
-
-static void node_draw_reroute(const bContext *C,
- ARegion *region,
- SpaceNode *UNUSED(snode),
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey UNUSED(key))
-{
- char showname[128]; /* 128 used below */
- rctf *rct = &node->totr;
-
- /* skip if out of view */
- if (node->totr.xmax < region->v2d.cur.xmin || node->totr.xmin > region->v2d.cur.xmax ||
- node->totr.ymax < region->v2d.cur.ymin || node->totr.ymin > region->v2d.cur.ymax) {
- UI_block_end(C, node->block);
- node->block = nullptr;
- return;
- }
-
- /* XXX only kept for debugging
- * selection state is indicated by socket outline below!
- */
-#if 0
- float size = NODE_REROUTE_SIZE;
-
- /* body */
- float debug_color[4];
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_GetThemeColor4fv(TH_NODE, debug_color);
- UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax, size, debug_color);
-
- /* outline active and selected emphasis */
- if (node->flag & SELECT) {
- GPU_blend(GPU_BLEND_ALPHA);
- GPU_line_smooth(true);
- /* Using different shades of #TH_TEXT_HI for the emphasis, like triangle. */
- if (node->flag & NODE_ACTIVE) {
- UI_GetThemeColorShadeAlpha4fv(TH_TEXT_HI, 0, -40, debug_color);
- }
- else {
- UI_GetThemeColorShadeAlpha4fv(TH_TEXT_HI, -20, -120, debug_color);
- }
- UI_draw_roundbox_4fv(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, size, debug_color);
-
- GPU_line_smooth(false);
- GPU_blend(GPU_BLEND_NONE);
- }
-#endif
-
- if (node->label[0] != '\0') {
- /* draw title (node label) */
- BLI_strncpy(showname, node->label, sizeof(showname));
- uiDefBut(node->block,
- UI_BTYPE_LABEL,
- 0,
- showname,
- (int)(rct->xmin - NODE_DYS),
- (int)(rct->ymax),
- (short)512,
- (short)NODE_DY,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
- }
-
- /* only draw input socket. as they all are placed on the same position.
- * highlight also if node itself is selected, since we don't display the node body separately!
- */
- node_draw_sockets(&region->v2d, C, ntree, node, false, node->flag & SELECT);
-
- UI_block_end(C, node->block);
- UI_block_draw(C, node->block);
- node->block = nullptr;
-}
-
-/* Special tweak area for reroute node.
- * Since this node is quite small, we use a larger tweak area for grabbing than for selection.
- */
-static int node_tweak_area_reroute(bNode *node, int x, int y)
-{
- /* square of tweak radius */
- const float tweak_radius_sq = square_f(24.0f);
-
- bNodeSocket *sock = (bNodeSocket *)node->inputs.first;
- float dx = sock->locx - x;
- float dy = sock->locy - y;
- return (dx * dx + dy * dy <= tweak_radius_sq);
-}
-
static void node_common_set_butfunc(bNodeType *ntype)
{
switch (ntype->type) {
@@ -628,15 +304,7 @@ static void node_common_set_butfunc(bNodeType *ntype)
ntype->draw_buttons = node_draw_buttons_group;
break;
case NODE_FRAME:
- ntype->draw_nodetype = node_draw_frame;
- ntype->draw_nodetype_prepare = node_draw_frame_prepare;
ntype->draw_buttons_ex = node_buts_frame_ex;
- ntype->resize_area_func = node_resize_area_frame;
- break;
- case NODE_REROUTE:
- ntype->draw_nodetype = node_draw_reroute;
- ntype->draw_nodetype_prepare = node_draw_reroute_prepare;
- ntype->tweak_area_func = node_tweak_area_reroute;
break;
}
}
@@ -702,40 +370,6 @@ static void node_buts_image_user(uiLayout *layout,
}
}
-static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_vector_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "rotation_type", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, nullptr, 0);
-}
-
-static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_vect_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "convert_from", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "convert_to", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "attribute_type", DEFAULT_FLAGS, IFACE_("Type"), ICON_NONE);
- uiItemR(layout, ptr, "attribute_name", DEFAULT_FLAGS, IFACE_("Name"), ICON_NONE);
-}
-
-static void node_shader_buts_wireframe(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_pixel_size", DEFAULT_FLAGS, nullptr, 0);
-}
-
static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
PointerRNA imaptr = RNA_pointer_get(ptr, "image");
@@ -805,371 +439,21 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P
uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, IFACE_("Projection"), ICON_NONE);
}
-static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "sky_type", DEFAULT_FLAGS, "", ICON_NONE);
-
- if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_PREETHAM) {
- uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_HOSEK) {
- uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "ground_albedo", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NISHITA) {
- uiItemR(layout, ptr, "sun_disc", DEFAULT_FLAGS, nullptr, 0);
-
- uiLayout *col;
- if (RNA_boolean_get(ptr, "sun_disc")) {
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "sun_size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "sun_intensity", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "sun_elevation", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "sun_rotation", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "altitude", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "air_density", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "dust_density", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "ozone_density", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "gradient_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_tex_magic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "turbulence_depth", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
- uiItemR(col, ptr, "offset_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "squash", DEFAULT_FLAGS, IFACE_("Squash"), ICON_NONE);
- uiItemR(col, ptr, "squash_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
-}
-
-static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "wave_type", DEFAULT_FLAGS, "", ICON_NONE);
- int type = RNA_enum_get(ptr, "wave_type");
- if (type == SHD_WAVE_BANDS) {
- uiItemR(layout, ptr, "bands_direction", DEFAULT_FLAGS, "", ICON_NONE);
- }
- else { /* SHD_WAVE_RINGS */
- uiItemR(layout, ptr, "rings_direction", DEFAULT_FLAGS, "", ICON_NONE);
- }
-
- uiItemR(layout, ptr, "wave_profile", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "musgrave_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "musgrave_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "voronoi_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "feature", DEFAULT_FLAGS, "", ICON_NONE);
- int feature = RNA_enum_get(ptr, "feature");
- if (!ELEM(feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS) &&
- RNA_enum_get(ptr, "voronoi_dimensions") != 1) {
- uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, "", ICON_NONE);
- }
-}
-
-static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_tex_pointdensity(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- NodeShaderTexPointDensity *shader_point_density = (NodeShaderTexPointDensity *)node->storage;
- Object *ob = (Object *)node->id;
-
- PointerRNA ob_ptr, obdata_ptr;
- RNA_id_pointer_create((ID *)ob, &ob_ptr);
- RNA_id_pointer_create(ob ? (ID *)ob->data : nullptr, &obdata_ptr);
-
- uiItemR(layout, ptr, "point_source", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "object", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (node->id && shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
- PointerRNA dataptr;
- RNA_id_pointer_create((ID *)node->id, &dataptr);
- uiItemPointerR(
- layout, ptr, "particle_system", &dataptr, "particle_systems", nullptr, ICON_NONE);
- }
-
- uiItemR(layout, ptr, "space", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "radius", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "resolution", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
- uiItemR(layout, ptr, "particle_color_source", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
- uiItemR(layout, ptr, "vertex_color_source", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTWEIGHT) {
- if (ob_ptr.data) {
- uiItemPointerR(
- layout, ptr, "vertex_attribute_name", &ob_ptr, "vertex_groups", "", ICON_NONE);
- }
- }
- if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTCOL) {
- if (obdata_ptr.data) {
- uiItemPointerR(
- layout, ptr, "vertex_attribute_name", &obdata_ptr, "vertex_colors", "", ICON_NONE);
- }
- }
- }
-}
-
-static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "object", DEFAULT_FLAGS, nullptr, 0);
- uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, nullptr, 0);
-}
-
-static void node_shader_buts_bump(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, nullptr, 0);
-}
-
-static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, nullptr, 0);
-
- if (!RNA_boolean_get(ptr, "from_instancer")) {
- PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
-
- if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
- PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
- uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
- }
- }
-}
-
-static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
- if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
- PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
-
- if (U.experimental.use_sculpt_vertex_colors &&
- RNA_collection_length(&dataptr, "sculpt_vertex_colors")) {
- uiItemPointerR(
- layout, ptr, "layer_name", &dataptr, "sculpt_vertex_colors", "", ICON_GROUP_VCOL);
- }
- else {
- uiItemPointerR(layout, ptr, "layer_name", &dataptr, "vertex_colors", "", ICON_GROUP_VCOL);
- }
- }
- else {
- uiItemL(layout, "No mesh in active object.", ICON_ERROR);
- }
-}
-
-static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_tips", DEFAULT_FLAGS, nullptr, 0);
-}
-
-static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0);
-
- if (RNA_enum_get(ptr, "space") == SHD_SPACE_TANGENT) {
- PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
-
- if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
- PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
- uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
- }
- else {
- uiItemR(layout, ptr, "uv_map", DEFAULT_FLAGS, "", 0);
- }
- }
-}
-
static void node_shader_buts_displacement(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0);
}
-static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiLayout *split, *row;
-
- split = uiLayoutSplit(layout, 0.0f, false);
-
- uiItemR(split, ptr, "direction_type", DEFAULT_FLAGS, "", 0);
-
- row = uiLayoutRow(split, false);
-
- if (RNA_enum_get(ptr, "direction_type") == SHD_TANGENT_UVMAP) {
- PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
-
- if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
- PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
- uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
- }
- else {
- uiItemR(row, ptr, "uv_map", DEFAULT_FLAGS, "", 0);
- }
- }
- else {
- uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, 0);
- }
-}
-
static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
}
-static void node_shader_buts_principled(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "subsurface_method", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_subsurface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_principled_hair(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "parametrization", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, true);
-
- if (RNA_enum_get(ptr, "mode") == NODE_IES_INTERNAL) {
- uiItemR(row, ptr, "ies", DEFAULT_FLAGS, "", ICON_NONE);
- }
- else {
- uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
- }
-}
-
-static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, true);
-
- if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_INTERNAL) {
- uiItemR(row, ptr, "script", DEFAULT_FLAGS, "", ICON_NONE);
- }
- else {
- uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
- }
-
- uiItemO(row, "", ICON_FILE_REFRESH, "node.shader_script_update");
-}
-
-static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiItemS(layout);
-
- node_shader_buts_script(layout, C, ptr);
-
-#if 0 /* not implemented yet */
- if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_EXTERNAL) {
- uiItemR(layout, ptr, "use_auto_update", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-#endif
-}
-
static void node_buts_output_shader(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "target", DEFAULT_FLAGS, "", ICON_NONE);
}
-static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row, *col;
-
- col = uiLayoutColumn(layout, false);
- row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_ambient_occlusion(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "inside", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "only_local", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_output_aov(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "name", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
/* only once called */
static void node_shader_set_butfunc(bNodeType *ntype)
{
@@ -1183,8 +467,8 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_CURVE_RGB:
ntype->draw_buttons = node_buts_curvecol;
break;
- case SH_NODE_MAPPING:
- ntype->draw_buttons = node_shader_buts_mapping;
+ case SH_NODE_CURVE_FLOAT:
+ ntype->draw_buttons = node_buts_curvefloat;
break;
case SH_NODE_VALUE:
ntype->draw_buttons = node_buts_value;
@@ -1198,33 +482,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_VALTORGB:
ntype->draw_buttons = node_buts_colorramp;
break;
- case SH_NODE_CLAMP:
- ntype->draw_buttons = node_shader_buts_clamp;
- break;
- case SH_NODE_MAP_RANGE:
- ntype->draw_buttons = node_shader_buts_map_range;
- break;
case SH_NODE_MATH:
ntype->draw_buttons = node_buts_math;
break;
- case SH_NODE_VECTOR_MATH:
- ntype->draw_buttons = node_shader_buts_vect_math;
- break;
- case SH_NODE_VECTOR_ROTATE:
- ntype->draw_buttons = node_shader_buts_vector_rotate;
- break;
- case SH_NODE_VECT_TRANSFORM:
- ntype->draw_buttons = node_shader_buts_vect_transform;
- break;
- case SH_NODE_ATTRIBUTE:
- ntype->draw_buttons = node_shader_buts_attribute;
- break;
- case SH_NODE_WIREFRAME:
- ntype->draw_buttons = node_shader_buts_wireframe;
- break;
- case SH_NODE_TEX_SKY:
- ntype->draw_buttons = node_shader_buts_tex_sky;
- break;
case SH_NODE_TEX_IMAGE:
ntype->draw_buttons = node_shader_buts_tex_image;
ntype->draw_buttons_ex = node_shader_buts_tex_image_ex;
@@ -1233,105 +493,20 @@ static void node_shader_set_butfunc(bNodeType *ntype)
ntype->draw_buttons = node_shader_buts_tex_environment;
ntype->draw_buttons_ex = node_shader_buts_tex_environment_ex;
break;
- case SH_NODE_TEX_GRADIENT:
- ntype->draw_buttons = node_shader_buts_tex_gradient;
- break;
- case SH_NODE_TEX_MAGIC:
- ntype->draw_buttons = node_shader_buts_tex_magic;
- break;
- case SH_NODE_TEX_BRICK:
- ntype->draw_buttons = node_shader_buts_tex_brick;
- break;
- case SH_NODE_TEX_WAVE:
- ntype->draw_buttons = node_shader_buts_tex_wave;
- break;
- case SH_NODE_TEX_MUSGRAVE:
- ntype->draw_buttons = node_shader_buts_tex_musgrave;
- break;
- case SH_NODE_TEX_VORONOI:
- ntype->draw_buttons = node_shader_buts_tex_voronoi;
- break;
- case SH_NODE_TEX_NOISE:
- ntype->draw_buttons = node_shader_buts_tex_noise;
- break;
- case SH_NODE_TEX_POINTDENSITY:
- ntype->draw_buttons = node_shader_buts_tex_pointdensity;
- break;
- case SH_NODE_TEX_COORD:
- ntype->draw_buttons = node_shader_buts_tex_coord;
- break;
- case SH_NODE_BUMP:
- ntype->draw_buttons = node_shader_buts_bump;
- break;
- case SH_NODE_NORMAL_MAP:
- ntype->draw_buttons = node_shader_buts_normal_map;
- break;
case SH_NODE_DISPLACEMENT:
case SH_NODE_VECTOR_DISPLACEMENT:
ntype->draw_buttons = node_shader_buts_displacement;
break;
- case SH_NODE_TANGENT:
- ntype->draw_buttons = node_shader_buts_tangent;
- break;
case SH_NODE_BSDF_GLOSSY:
case SH_NODE_BSDF_GLASS:
case SH_NODE_BSDF_REFRACTION:
ntype->draw_buttons = node_shader_buts_glossy;
break;
- case SH_NODE_BSDF_PRINCIPLED:
- ntype->draw_buttons = node_shader_buts_principled;
- break;
- case SH_NODE_BSDF_ANISOTROPIC:
- ntype->draw_buttons = node_shader_buts_anisotropic;
- break;
- case SH_NODE_SUBSURFACE_SCATTERING:
- ntype->draw_buttons = node_shader_buts_subsurface;
- break;
- case SH_NODE_BSDF_TOON:
- ntype->draw_buttons = node_shader_buts_toon;
- break;
- case SH_NODE_BSDF_HAIR:
- ntype->draw_buttons = node_shader_buts_hair;
- break;
- case SH_NODE_BSDF_HAIR_PRINCIPLED:
- ntype->draw_buttons = node_shader_buts_principled_hair;
- break;
- case SH_NODE_SCRIPT:
- ntype->draw_buttons = node_shader_buts_script;
- ntype->draw_buttons_ex = node_shader_buts_script_ex;
- break;
- case SH_NODE_UVMAP:
- ntype->draw_buttons = node_shader_buts_uvmap;
- break;
- case SH_NODE_VERTEX_COLOR:
- ntype->draw_buttons = node_shader_buts_vertex_color;
- break;
- case SH_NODE_UVALONGSTROKE:
- ntype->draw_buttons = node_shader_buts_uvalongstroke;
- break;
case SH_NODE_OUTPUT_MATERIAL:
case SH_NODE_OUTPUT_LIGHT:
case SH_NODE_OUTPUT_WORLD:
ntype->draw_buttons = node_buts_output_shader;
break;
- case SH_NODE_OUTPUT_LINESTYLE:
- ntype->draw_buttons = node_buts_output_linestyle;
- break;
- case SH_NODE_TEX_IES:
- ntype->draw_buttons = node_shader_buts_ies;
- break;
- case SH_NODE_BEVEL:
- ntype->draw_buttons = node_shader_buts_bevel;
- break;
- case SH_NODE_AMBIENT_OCCLUSION:
- ntype->draw_buttons = node_shader_buts_ambient_occlusion;
- break;
- case SH_NODE_TEX_WHITE_NOISE:
- ntype->draw_buttons = node_shader_buts_white_noise;
- break;
- case SH_NODE_OUTPUT_AOV:
- ntype->draw_buttons = node_shader_buts_output_aov;
- break;
}
}
@@ -1398,763 +573,6 @@ static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRN
uiTemplateImage(layout, C, ptr, "image", &iuserptr, false, true);
}
-static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- uiLayout *col, *row;
-
- uiTemplateID(layout,
- C,
- ptr,
- "scene",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- col = uiLayoutColumn(layout, false);
- row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "layer", DEFAULT_FLAGS, "", ICON_NONE);
-
- PropertyRNA *prop = RNA_struct_find_property(ptr, "layer");
- const char *layer_name;
- if (!(RNA_property_enum_identifier(
- C, ptr, prop, RNA_property_enum_get(ptr, prop), &layer_name))) {
- return;
- }
-
- PointerRNA scn_ptr;
- char scene_name[MAX_ID_NAME - 2];
- scn_ptr = RNA_pointer_get(ptr, "scene");
- RNA_string_get(&scn_ptr, "name", scene_name);
-
- PointerRNA op_ptr;
- uiItemFullO(
- row, "RENDER_OT_render", "", ICON_RENDER_STILL, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_string_set(&op_ptr, "layer", layer_name);
- RNA_string_set(&op_ptr, "scene", scene_name);
-}
-
-static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col, *row;
-
- col = uiLayoutColumn(layout, false);
- const int filter = RNA_enum_get(ptr, "filter_type");
- const int reference = RNA_boolean_get(ptr, "use_variable_size");
-
- uiItemR(col, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
- if (filter != R_FILTER_FAST_GAUSS) {
- uiItemR(col, ptr, "use_variable_size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (!reference) {
- uiItemR(col, ptr, "use_bokeh", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- uiItemR(col, ptr, "use_gamma_correction", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- uiItemR(col, ptr, "use_relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_boolean_get(ptr, "use_relative")) {
- uiItemL(col, IFACE_("Aspect Correction"), ICON_NONE);
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "aspect_correction", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "factor_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "factor_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
- }
- else {
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "size_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "size_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
- }
- uiItemR(col, ptr, "use_extended_bounds", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_wrap", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Center:"), ICON_NONE);
- uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
-
- uiItemS(layout);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemS(layout);
-
- uiItemR(layout, ptr, "spin", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "zoom", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_bilateralblur(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "iterations", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "sigma_color", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "sigma_space", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiLayout *sub, *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemL(col, IFACE_("Bokeh Type:"), ICON_NONE);
- uiItemR(col, ptr, "bokeh", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(col, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "use_gamma_correction", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == true);
- uiItemR(col, ptr, "f_stop", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_preview", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateID(layout,
- C,
- ptr,
- "scene",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_zbuffer", DEFAULT_FLAGS, nullptr, ICON_NONE);
- sub = uiLayoutColumn(col, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == false);
- uiItemR(sub, ptr, "z_scale", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_antialiasing(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
-
- uiItemR(col, ptr, "threshold", 0, nullptr, ICON_NONE);
- uiItemR(col, ptr, "contrast_limit", 0, nullptr, ICON_NONE);
- uiItemR(col, ptr, "corner_rounding", 0, nullptr, ICON_NONE);
-}
-
-/* glare node */
-static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "glare_type", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "quality", DEFAULT_FLAGS, "", ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") != 1) {
- uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") != 0) {
- uiItemR(
- layout, ptr, "color_modulation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- }
- }
-
- uiItemR(layout, ptr, "mix", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") == 2) {
- uiItemR(layout, ptr, "streaks", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "angle_offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- if (RNA_enum_get(ptr, "glare_type") == 0 || RNA_enum_get(ptr, "glare_type") == 2) {
- uiItemR(layout, ptr, "fade", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") == 0) {
- uiItemR(layout, ptr, "use_rotate_45", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- }
- if (RNA_enum_get(ptr, "glare_type") == 1) {
- uiItemR(layout, ptr, "size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "tonemap_type", DEFAULT_FLAGS, "", ICON_NONE);
- if (RNA_enum_get(ptr, "tonemap_type") == 0) {
- uiItemR(col, ptr, "key", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
- uiItemR(col, ptr, "intensity", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "adaptation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "correction", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_projector", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(col, false);
- uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false);
- uiItemR(col, ptr, "use_jitter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "use_fit", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "factor", DEFAULT_FLAGS, IFACE_("Blur"), ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Speed:"), ICON_NONE);
- uiItemR(col, ptr, "speed_min", DEFAULT_FLAGS, IFACE_("Min"), ICON_NONE);
- uiItemR(col, ptr, "speed_max", DEFAULT_FLAGS, IFACE_("Max"), ICON_NONE);
-
- uiItemR(layout, ptr, "use_curved", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_flip(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "axis", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- uiItemR(layout, ptr, "use_crop_size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- if (RNA_boolean_get(ptr, "relative")) {
- uiItemR(col, ptr, "rel_min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE);
- uiItemR(col, ptr, "rel_max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE);
- uiItemR(col, ptr, "rel_min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE);
- uiItemR(col, ptr, "rel_max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE);
- }
- else {
- uiItemR(col, ptr, "min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE);
- uiItemR(col, ptr, "max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE);
- uiItemR(col, ptr, "min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE);
- uiItemR(col, ptr, "max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE);
- }
-}
-
-static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row, *col;
-
- col = uiLayoutColumn(layout, false);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- uiItemR(col, ptr, "factor", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_double_edge_mask(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
-
- uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE);
- uiItemR(col, ptr, "inner_mode", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemL(col, IFACE_("Buffer Edge:"), ICON_NONE);
- uiItemR(col, ptr, "edge_mode", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *sub, *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "size", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_min", DEFAULT_FLAGS, nullptr, ICON_NONE);
- sub = uiLayoutColumn(col, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
- uiItemR(sub, ptr, "min", DEFAULT_FLAGS, "", ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_max", DEFAULT_FLAGS, nullptr, ICON_NONE);
- sub = uiLayoutColumn(col, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
- uiItemR(sub, ptr, "max", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_premultiply", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "premul", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "use_antialias_z", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- switch (RNA_enum_get(ptr, "mode")) {
- case CMP_NODE_DILATEERODE_DISTANCE_THRESH:
- uiItemR(layout, ptr, "edge", DEFAULT_FLAGS, nullptr, ICON_NONE);
- break;
- case CMP_NODE_DILATEERODE_DISTANCE_FEATHER:
- uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, nullptr, ICON_NONE);
- break;
- }
-}
-
-static void node_composit_buts_inpaint(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "threshold_neighbor", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_distance_matte(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col, *row;
-
- col = uiLayoutColumn(layout, true);
-
- uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row, *col;
-
- uiItemL(layout, IFACE_("Despill Channel:"), ICON_NONE);
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "limit_method") == 0) {
- uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- }
-
- uiItemR(col, ptr, "ratio", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "use_unspill", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (RNA_boolean_get(ptr, "use_unspill") == true) {
- uiItemR(col, ptr, "unspill_red", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "unspill_green", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "unspill_blue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- /* Removed for now. */
- // uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- /* Removed for now. */
- // uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "color_hue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "color_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "color_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_channel_matte(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col, *row;
-
- uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "color_space", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiItemL(col, IFACE_("Key Channel:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "matte_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
-
- uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (RNA_enum_get(ptr, "limit_method") == 0) {
- uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- }
-
- uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "index", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_antialiasing", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- PointerRNA imfptr = RNA_pointer_get(ptr, "format");
- const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
-
- if (multilayer) {
- uiItemL(layout, IFACE_("Path:"), ICON_NONE);
- }
- else {
- uiItemL(layout, IFACE_("Base Path:"), ICON_NONE);
- }
- uiItemR(layout, ptr, "base_path", DEFAULT_FLAGS, "", ICON_NONE);
-}
-static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- Scene *scene = CTX_data_scene(C);
- PointerRNA imfptr = RNA_pointer_get(ptr, "format");
- PointerRNA active_input_ptr, op_ptr;
- uiLayout *row, *col;
- const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
- const bool is_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
- const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
-
- node_composit_buts_file_output(layout, C, ptr);
- uiTemplateImageSettings(layout, &imfptr, false);
-
- /* disable stereo output for multilayer, too much work for something that no one will use */
- /* if someone asks for that we can implement it */
- if (is_multiview) {
- uiTemplateImageFormatViews(layout, &imfptr, nullptr);
- }
-
- uiItemS(layout);
-
- uiItemO(layout, IFACE_("Add Input"), ICON_ADD, "NODE_OT_output_file_add_socket");
-
- row = uiLayoutRow(layout, false);
- col = uiLayoutColumn(row, true);
-
- const int active_index = RNA_int_get(ptr, "active_input_index");
- /* using different collection properties if multilayer format is enabled */
- if (multilayer) {
- uiTemplateList(col,
- C,
- "UI_UL_list",
- "file_output_node",
- ptr,
- "layer_slots",
- ptr,
- "active_input_index",
- nullptr,
- 0,
- 0,
- 0,
- 0,
- UI_TEMPLATE_LIST_FLAG_NONE);
- RNA_property_collection_lookup_int(
- ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr);
- }
- else {
- uiTemplateList(col,
- C,
- "UI_UL_list",
- "file_output_node",
- ptr,
- "file_slots",
- ptr,
- "active_input_index",
- nullptr,
- 0,
- 0,
- 0,
- 0,
- UI_TEMPLATE_LIST_FLAG_NONE);
- RNA_property_collection_lookup_int(
- ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr);
- }
- /* XXX collection lookup does not return the ID part of the pointer,
- * setting this manually here */
- active_input_ptr.owner_id = ptr->owner_id;
-
- col = uiLayoutColumn(row, true);
- wmOperatorType *ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false);
- uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_enum_set(&op_ptr, "direction", 1);
- uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_enum_set(&op_ptr, "direction", 2);
-
- if (active_input_ptr.data) {
- if (multilayer) {
- col = uiLayoutColumn(layout, true);
-
- uiItemL(col, IFACE_("Layer:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, &active_input_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemFullO(row,
- "NODE_OT_output_file_remove_active_socket",
- "",
- ICON_X,
- nullptr,
- WM_OP_EXEC_DEFAULT,
- UI_ITEM_R_ICON_ONLY,
- nullptr);
- }
- else {
- col = uiLayoutColumn(layout, true);
-
- uiItemL(col, IFACE_("File Subpath:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, &active_input_ptr, "path", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemFullO(row,
- "NODE_OT_output_file_remove_active_socket",
- "",
- ICON_X,
- nullptr,
- WM_OP_EXEC_DEFAULT,
- UI_ITEM_R_ICON_ONLY,
- nullptr);
-
- /* format details for individual files */
- imfptr = RNA_pointer_get(&active_input_ptr, "format");
-
- col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Format:"), ICON_NONE);
- uiItemR(col, &active_input_ptr, "use_node_format", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- const bool is_socket_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
- const bool use_node_format = RNA_boolean_get(&active_input_ptr, "use_node_format");
-
- if ((!is_exr && use_node_format) || (!is_socket_exr && !use_node_format)) {
- uiItemR(col, &active_input_ptr, "save_as_render", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, use_node_format == false);
- uiTemplateImageSettings(col, &imfptr, false);
-
- if (is_multiview) {
- uiTemplateImageFormatViews(layout, &imfptr, nullptr);
- }
- }
- }
-}
-
-static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", ICON_NONE);
-
- if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) {
- uiLayout *row;
- uiItemR(layout, ptr, "frame_method", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "offset_x", DEFAULT_FLAGS, "X", ICON_NONE);
- uiItemR(row, ptr, "offset_y", DEFAULT_FLAGS, "Y", ICON_NONE);
- }
-}
-
-static void node_composit_buts_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "invert_rgb", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "invert_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "mapping", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_view_levels(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "channel", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *split, *col, *row;
-
- uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "correction_method") == 0) {
-
- split = uiLayoutSplit(layout, 0.0f, false);
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "lift", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "lift", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "gamma", true, true, true, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "gain", true, true, true, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gain", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
-
- split = uiLayoutSplit(layout, 0.0f, false);
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "offset", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "offset_basis", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "power", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "power", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "slope", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "slope", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-static void node_composit_buts_colorbalance_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "correction_method") == 0) {
-
- uiTemplateColorPicker(layout, ptr, "lift", true, true, false, true);
- uiItemR(layout, ptr, "lift", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "gamma", true, true, true, true);
- uiItemR(layout, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "gain", true, true, true, true);
- uiItemR(layout, ptr, "gain", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
- uiTemplateColorPicker(layout, ptr, "offset", true, true, false, true);
- uiItemR(layout, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "power", true, true, false, true);
- uiItemR(layout, ptr, "power", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "slope", true, true, false, true);
- uiItemR(layout, ptr, "slope", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
static void node_composit_buts_huecorrect(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
@@ -2176,260 +594,6 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe
uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
}
-static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-}
-
-static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- PointerRNA clipptr;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- clipptr = RNA_pointer_get(ptr, "clip");
-
- uiTemplateColorspaceSettings(layout, &clipptr, "colorspace_settings");
-}
-
-static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "wrap_axis", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- uiItemR(layout, ptr, "distortion_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_colorcorrection(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "red", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "green", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "blue", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, "", ICON_NONE);
- uiItemL(row, IFACE_("Saturation"), ICON_NONE);
- uiItemL(row, IFACE_("Contrast"), ICON_NONE);
- uiItemL(row, IFACE_("Gamma"), ICON_NONE);
- uiItemL(row, IFACE_("Gain"), ICON_NONE);
- uiItemL(row, IFACE_("Lift"), ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_("Master"), ICON_NONE);
- uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_("Highlights"), ICON_NONE);
- uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_("Midtones"), ICON_NONE);
- uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_("Shadows"), ICON_NONE);
- uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_colorcorrection_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "red", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "green", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "blue", DEFAULT_FLAGS, nullptr, ICON_NONE);
- row = layout;
- uiItemL(row, IFACE_("Saturation"), ICON_NONE);
- uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Contrast"), ICON_NONE);
- uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Gamma"), ICON_NONE);
- uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Gain"), ICON_NONE);
- uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Lift"), ICON_NONE);
- uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_set_alpha(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "check", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_switch_view_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *UNUSED(ptr))
-{
- uiItemFullO(layout,
- "NODE_OT_switch_view_update",
- "Update Views",
- ICON_FILE_REFRESH,
- nullptr,
- WM_OP_INVOKE_DEFAULT,
- 0,
- nullptr);
-}
-
-static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "y", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "flaps", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "rounding", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "catadioptric", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "shift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_variable_size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- // uiItemR(layout, ptr, "f_stop", DEFAULT_FLAGS, nullptr, ICON_NONE); /* UNUSED */
- uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_extended_bounds", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
static void node_composit_backdrop_viewer(
SpaceNode *snode, ImBuf *backdrop, bNode *node, int x, int y)
{
@@ -2549,227 +713,6 @@ static void node_composit_backdrop_ellipsemask(
immUnbindProgram();
}
-static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row;
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "y", DEFAULT_FLAGS, nullptr, ICON_NONE);
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_composite(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_viewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_viewer_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "tile_order", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (RNA_enum_get(ptr, "tile_order") == 0) {
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "mask",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
- uiItemR(layout, ptr, "use_feather", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "size_source", DEFAULT_FLAGS, "", ICON_NONE);
-
- if (node->custom1 & (CMP_NODEFLAG_MASK_FIXED | CMP_NODEFLAG_MASK_FIXED_SCENE)) {
- uiItemR(layout, ptr, "size_x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "size_y", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) {
- uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (node->id) {
- MovieClip *clip = (MovieClip *)node->id;
- uiLayout *col;
- PointerRNA tracking_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTracking, &clip->tracking, &tracking_ptr);
-
- col = uiLayoutColumn(layout, true);
- uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
- }
-}
-
-static void node_composit_buts_keying(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- /* bNode *node = (bNode*)ptr->data; */ /* UNUSED */
-
- uiItemR(layout, ptr, "blur_pre", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "screen_balance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "despill_factor", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "despill_balance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "edge_kernel_radius", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "edge_kernel_tolerance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "clip_black", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "clip_white", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "dilate_distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "feather_falloff", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "feather_distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "blur_post", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (node->id) {
- MovieClip *clip = (MovieClip *)node->id;
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
- uiLayout *col;
- PointerRNA tracking_ptr;
- NodeTrackPosData *data = (NodeTrackPosData *)node->storage;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
-
- col = uiLayoutColumn(layout, false);
- uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
-
- object = BKE_tracking_object_get_named(tracking, data->tracking_object);
- if (object) {
- PointerRNA object_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
-
- uiItemPointerR(col, ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA);
- }
- else {
- uiItemR(layout, ptr, "track_name", DEFAULT_FLAGS, "", ICON_ANIM_DATA);
- }
-
- uiItemR(layout, ptr, "position", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) {
- uiItemR(layout, ptr, "frame_relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- }
-}
-
-static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)node->storage;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (node->id) {
- MovieClip *clip = (MovieClip *)node->id;
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
- uiLayout *col;
- PointerRNA tracking_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
-
- col = uiLayoutColumn(layout, false);
- uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
-
- object = BKE_tracking_object_get_named(tracking, data->tracking_object);
- if (object) {
- PointerRNA object_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
-
- uiItemPointerR(
- col, ptr, "plane_track_name", &object_ptr, "plane_tracks", "", ICON_ANIM_DATA);
- }
- else {
- uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA);
- }
- }
-
- uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
- uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout),
- bContext *UNUSED(C),
- PointerRNA *UNUSED(ptr))
-{
-}
-
-static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "source", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, "", ICON_NONE);
- uiItemR(layout, ptr, "ray_length", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
static void node_composit_buts_cryptomatte_legacy(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
@@ -2845,31 +788,6 @@ static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *C, Pointe
uiTemplateCryptoPicker(row, ptr, "remove", ICON_REMOVE);
}
-static void node_composit_buts_brightcontrast(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_premultiply", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
-#ifndef WITH_OPENIMAGEDENOISE
- uiItemL(layout, IFACE_("Disabled, built without OpenImageDenoise"), ICON_ERROR);
-#else
- /* Always supported through Accelerate framework BNNS on macOS. */
-# ifndef __APPLE__
- if (!BLI_cpu_support_sse41()) {
- uiItemL(layout, IFACE_("Disabled, CPU with SSE4.1 is required"), ICON_ERROR);
- }
-# endif
-#endif
-
- uiItemL(layout, IFACE_("Prefilter:"), ICON_NONE);
- uiItemR(layout, ptr, "prefilter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_hdr", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
/* only once called */
static void node_composit_set_butfunc(bNodeType *ntype)
{
@@ -2878,15 +796,6 @@ static void node_composit_set_butfunc(bNodeType *ntype)
ntype->draw_buttons = node_composit_buts_image;
ntype->draw_buttons_ex = node_composit_buts_image_ex;
break;
- case CMP_NODE_R_LAYERS:
- ntype->draw_buttons = node_composit_buts_viewlayers;
- break;
- case CMP_NODE_NORMAL:
- ntype->draw_buttons = node_buts_normal;
- break;
- case CMP_NODE_CURVE_VEC:
- ntype->draw_buttons = node_buts_curvevec;
- break;
case CMP_NODE_CURVE_RGB:
ntype->draw_buttons = node_buts_curvecol;
break;
@@ -2896,213 +805,34 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_RGB:
ntype->draw_buttons = node_buts_rgb;
break;
- case CMP_NODE_FLIP:
- ntype->draw_buttons = node_composit_buts_flip;
- break;
- case CMP_NODE_SPLITVIEWER:
- ntype->draw_buttons = node_composit_buts_splitviewer;
- break;
case CMP_NODE_MIX_RGB:
ntype->draw_buttons = node_buts_mix_rgb;
break;
case CMP_NODE_VALTORGB:
ntype->draw_buttons = node_buts_colorramp;
break;
- case CMP_NODE_CROP:
- ntype->draw_buttons = node_composit_buts_crop;
- break;
- case CMP_NODE_BLUR:
- ntype->draw_buttons = node_composit_buts_blur;
- break;
- case CMP_NODE_DBLUR:
- ntype->draw_buttons = node_composit_buts_dblur;
- break;
- case CMP_NODE_BILATERALBLUR:
- ntype->draw_buttons = node_composit_buts_bilateralblur;
- break;
- case CMP_NODE_DEFOCUS:
- ntype->draw_buttons = node_composit_buts_defocus;
- break;
- case CMP_NODE_ANTIALIASING:
- ntype->draw_buttons = node_composit_buts_antialiasing;
- break;
- case CMP_NODE_GLARE:
- ntype->draw_buttons = node_composit_buts_glare;
- break;
- case CMP_NODE_TONEMAP:
- ntype->draw_buttons = node_composit_buts_tonemap;
- break;
- case CMP_NODE_LENSDIST:
- ntype->draw_buttons = node_composit_buts_lensdist;
- break;
- case CMP_NODE_VECBLUR:
- ntype->draw_buttons = node_composit_buts_vecblur;
- break;
- case CMP_NODE_FILTER:
- ntype->draw_buttons = node_composit_buts_filter;
- break;
- case CMP_NODE_MAP_VALUE:
- ntype->draw_buttons = node_composit_buts_map_value;
- break;
- case CMP_NODE_MAP_RANGE:
- ntype->draw_buttons = node_composit_buts_map_range;
- break;
case CMP_NODE_TIME:
ntype->draw_buttons = node_buts_time;
break;
- case CMP_NODE_ALPHAOVER:
- ntype->draw_buttons = node_composit_buts_alphaover;
- break;
case CMP_NODE_TEXTURE:
ntype->draw_buttons = node_buts_texture;
break;
- case CMP_NODE_DILATEERODE:
- ntype->draw_buttons = node_composit_buts_dilateerode;
- break;
- case CMP_NODE_INPAINT:
- ntype->draw_buttons = node_composit_buts_inpaint;
- break;
- case CMP_NODE_DESPECKLE:
- ntype->draw_buttons = node_composit_buts_despeckle;
- break;
- case CMP_NODE_OUTPUT_FILE:
- ntype->draw_buttons = node_composit_buts_file_output;
- ntype->draw_buttons_ex = node_composit_buts_file_output_ex;
- break;
- case CMP_NODE_DIFF_MATTE:
- ntype->draw_buttons = node_composit_buts_diff_matte;
- break;
- case CMP_NODE_DIST_MATTE:
- ntype->draw_buttons = node_composit_buts_distance_matte;
- break;
- case CMP_NODE_COLOR_SPILL:
- ntype->draw_buttons = node_composit_buts_color_spill;
- break;
- case CMP_NODE_CHROMA_MATTE:
- ntype->draw_buttons = node_composit_buts_chroma_matte;
- break;
- case CMP_NODE_COLOR_MATTE:
- ntype->draw_buttons = node_composit_buts_color_matte;
- break;
- case CMP_NODE_SCALE:
- ntype->draw_buttons = node_composit_buts_scale;
- break;
- case CMP_NODE_ROTATE:
- ntype->draw_buttons = node_composit_buts_rotate;
- break;
- case CMP_NODE_CHANNEL_MATTE:
- ntype->draw_buttons = node_composit_buts_channel_matte;
- break;
- case CMP_NODE_LUMA_MATTE:
- ntype->draw_buttons = node_composit_buts_luma_matte;
- break;
- case CMP_NODE_MAP_UV:
- ntype->draw_buttons = node_composit_buts_map_uv;
- break;
- case CMP_NODE_ID_MASK:
- ntype->draw_buttons = node_composit_buts_id_mask;
- break;
- case CMP_NODE_DOUBLEEDGEMASK:
- ntype->draw_buttons = node_composit_buts_double_edge_mask;
- break;
case CMP_NODE_MATH:
ntype->draw_buttons = node_buts_math;
break;
- case CMP_NODE_INVERT:
- ntype->draw_buttons = node_composit_buts_invert;
- break;
- case CMP_NODE_PREMULKEY:
- ntype->draw_buttons = node_composit_buts_premulkey;
- break;
- case CMP_NODE_VIEW_LEVELS:
- ntype->draw_buttons = node_composit_buts_view_levels;
- break;
- case CMP_NODE_COLORBALANCE:
- ntype->draw_buttons = node_composit_buts_colorbalance;
- ntype->draw_buttons_ex = node_composit_buts_colorbalance_ex;
- break;
case CMP_NODE_HUECORRECT:
ntype->draw_buttons = node_composit_buts_huecorrect;
break;
- case CMP_NODE_ZCOMBINE:
- ntype->draw_buttons = node_composit_buts_zcombine;
- break;
case CMP_NODE_COMBYCCA:
case CMP_NODE_SEPYCCA:
ntype->draw_buttons = node_composit_buts_ycc;
break;
- case CMP_NODE_MOVIECLIP:
- ntype->draw_buttons = node_composit_buts_movieclip;
- ntype->draw_buttons_ex = node_composit_buts_movieclip_ex;
- break;
- case CMP_NODE_STABILIZE2D:
- ntype->draw_buttons = node_composit_buts_stabilize2d;
- break;
- case CMP_NODE_TRANSFORM:
- ntype->draw_buttons = node_composit_buts_transform;
- break;
- case CMP_NODE_TRANSLATE:
- ntype->draw_buttons = node_composit_buts_translate;
- break;
- case CMP_NODE_MOVIEDISTORTION:
- ntype->draw_buttons = node_composit_buts_moviedistortion;
- break;
- case CMP_NODE_COLORCORRECTION:
- ntype->draw_buttons = node_composit_buts_colorcorrection;
- ntype->draw_buttons_ex = node_composit_buts_colorcorrection_ex;
- break;
- case CMP_NODE_SETALPHA:
- ntype->draw_buttons = node_composit_buts_set_alpha;
- break;
- case CMP_NODE_SWITCH:
- ntype->draw_buttons = node_composit_buts_switch;
- break;
- case CMP_NODE_SWITCH_VIEW:
- ntype->draw_buttons_ex = node_composit_buts_switch_view_ex;
- break;
case CMP_NODE_MASK_BOX:
- ntype->draw_buttons = node_composit_buts_boxmask;
ntype->draw_backdrop = node_composit_backdrop_boxmask;
break;
case CMP_NODE_MASK_ELLIPSE:
- ntype->draw_buttons = node_composit_buts_ellipsemask;
ntype->draw_backdrop = node_composit_backdrop_ellipsemask;
break;
- case CMP_NODE_BOKEHIMAGE:
- ntype->draw_buttons = node_composit_buts_bokehimage;
- break;
- case CMP_NODE_BOKEHBLUR:
- ntype->draw_buttons = node_composit_buts_bokehblur;
- break;
- case CMP_NODE_VIEWER:
- ntype->draw_buttons = node_composit_buts_viewer;
- ntype->draw_buttons_ex = node_composit_buts_viewer_ex;
- ntype->draw_backdrop = node_composit_backdrop_viewer;
- break;
- case CMP_NODE_COMPOSITE:
- ntype->draw_buttons = node_composit_buts_composite;
- break;
- case CMP_NODE_MASK:
- ntype->draw_buttons = node_composit_buts_mask;
- break;
- case CMP_NODE_KEYINGSCREEN:
- ntype->draw_buttons = node_composit_buts_keyingscreen;
- break;
- case CMP_NODE_KEYING:
- ntype->draw_buttons = node_composit_buts_keying;
- break;
- case CMP_NODE_TRACKPOS:
- ntype->draw_buttons = node_composit_buts_trackpos;
- break;
- case CMP_NODE_PLANETRACKDEFORM:
- ntype->draw_buttons = node_composit_buts_planetrackdeform;
- break;
- case CMP_NODE_CORNERPIN:
- ntype->draw_buttons = node_composit_buts_cornerpin;
- break;
- case CMP_NODE_SUNBEAMS:
- ntype->draw_buttons = node_composit_buts_sunbeams;
- break;
case CMP_NODE_CRYPTOMATTE:
ntype->draw_buttons = node_composit_buts_cryptomatte;
break;
@@ -3110,11 +840,8 @@ static void node_composit_set_butfunc(bNodeType *ntype)
ntype->draw_buttons = node_composit_buts_cryptomatte_legacy;
ntype->draw_buttons_ex = node_composit_buts_cryptomatte_legacy_ex;
break;
- case CMP_NODE_BRIGHTCONTRAST:
- ntype->draw_buttons = node_composit_buts_brightcontrast;
- break;
- case CMP_NODE_DENOISE:
- ntype->draw_buttons = node_composit_buts_denoise;
+ case CMP_NODE_VIEWER:
+ ntype->draw_backdrop = node_composit_backdrop_viewer;
break;
}
}
@@ -3309,7 +1036,8 @@ static void node_property_update_default(Main *bmain, Scene *UNUSED(scene), Poin
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
static void node_socket_template_properties_update(bNodeType *ntype, bNodeSocketTemplate *stemp)
@@ -3377,20 +1105,18 @@ static void node_socket_undefined_interface_draw_color(bContext *UNUSED(C),
/** \} */
-void ED_node_init_butfuncs(void)
+} // namespace blender::ed::space_node
+
+void ED_node_init_butfuncs()
{
+ using namespace blender::ed::space_node;
+
/* Fallback types for undefined tree, nodes, sockets
* Defined in blenkernel, but not registered in type hashes.
*/
- /* default ui functions */
- NodeTypeUndefined.draw_nodetype = node_draw_default;
- NodeTypeUndefined.draw_nodetype_prepare = node_update_default;
- NodeTypeUndefined.select_area_func = node_select_area_default;
- NodeTypeUndefined.tweak_area_func = node_tweak_area_default;
NodeTypeUndefined.draw_buttons = nullptr;
NodeTypeUndefined.draw_buttons_ex = nullptr;
- NodeTypeUndefined.resize_area_func = node_resize_area_default;
NodeSocketTypeUndefined.draw = node_socket_undefined_draw;
NodeSocketTypeUndefined.draw_color = node_socket_undefined_draw_color;
@@ -3399,13 +1125,6 @@ void ED_node_init_butfuncs(void)
/* node type ui functions */
NODE_TYPES_BEGIN (ntype) {
- /* default ui functions */
- ntype->draw_nodetype = node_draw_default;
- ntype->draw_nodetype_prepare = node_update_default;
- ntype->select_area_func = node_select_area_default;
- ntype->tweak_area_func = node_tweak_area_default;
- ntype->resize_area_func = node_resize_area_default;
-
node_common_set_butfunc(ntype);
node_composit_set_butfunc(ntype);
@@ -3416,30 +1135,19 @@ void ED_node_init_butfuncs(void)
node_template_properties_update(ntype);
}
NODE_TYPES_END;
-
- /* tree type icons */
- ntreeType_Composite->ui_icon = ICON_NODE_COMPOSITING;
- ntreeType_Shader->ui_icon = ICON_NODE_MATERIAL;
- ntreeType_Texture->ui_icon = ICON_NODE_TEXTURE;
- ntreeType_Geometry->ui_icon = ICON_NODETREE;
}
-void ED_init_custom_node_type(bNodeType *ntype)
+void ED_init_custom_node_type(bNodeType *UNUSED(ntype))
{
- /* default ui functions */
- ntype->draw_nodetype = node_draw_default;
- ntype->draw_nodetype_prepare = node_update_default;
- ntype->resize_area_func = node_resize_area_default;
- ntype->select_area_func = node_select_area_default;
- ntype->tweak_area_func = node_tweak_area_default;
}
void ED_init_custom_node_socket_type(bNodeSocketType *stype)
{
- /* default ui functions */
- stype->draw = node_socket_button_label;
+ stype->draw = blender::ed::space_node::node_socket_button_label;
}
+namespace blender::ed::space_node {
+
static const float virtual_node_socket_color[4] = {0.2, 0.2, 0.2, 1.0};
/* maps standard socket integer type to a color */
@@ -3527,6 +1235,18 @@ static void node_file_output_socket_draw(bContext *C,
}
}
+static bool socket_needs_attribute_search(bNode &node, bNodeSocket &socket)
+{
+ if (node.declaration == nullptr) {
+ return false;
+ }
+ if (socket.in_out == SOCK_OUT) {
+ return false;
+ }
+ const int socket_index = BLI_findindex(&node.inputs, &socket);
+ return node.declaration->inputs()[socket_index]->is_attribute_name();
+}
+
static void std_node_socket_draw(
bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *node_ptr, const char *text)
{
@@ -3569,18 +1289,23 @@ static void std_node_socket_draw(
}
break;
case SOCK_RGBA: {
- uiLayout *row = uiLayoutSplit(layout, 0.4f, false);
- uiItemL(row, text, 0);
- uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0);
+ if (text[0] == '\0') {
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, "", 0);
+ }
+ else {
+ uiLayout *row = uiLayoutSplit(layout, 0.4f, false);
+ uiItemL(row, text, 0);
+ uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0);
+ }
break;
}
case SOCK_STRING: {
uiLayout *row = uiLayoutSplit(layout, 0.4f, false);
uiItemL(row, text, 0);
- const bNodeTree *node_tree = (const bNodeTree *)node_ptr->owner_id;
- if (node_tree->type == NTREE_GEOMETRY) {
- node_geometry_add_attribute_search_button(C, node_tree, node, ptr, row);
+ if (socket_needs_attribute_search(*node, *sock)) {
+ const bNodeTree *node_tree = (const bNodeTree *)node_ptr->owner_id;
+ node_geometry_add_attribute_search_button(*C, *node_tree, *node, *ptr, *row);
}
else {
uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0);
@@ -3593,7 +1318,39 @@ static void std_node_socket_draw(
break;
}
case SOCK_IMAGE: {
- uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
+ const bNodeTree *node_tree = (const bNodeTree *)node_ptr->owner_id;
+ if (node_tree->type == NTREE_GEOMETRY) {
+ if (text[0] == '\0') {
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "default_value",
+ "image.new",
+ "image.open",
+ nullptr,
+ 0,
+ ICON_NONE,
+ nullptr);
+ }
+ else {
+ /* 0.3 split ratio is inconsistent, but use it here because the "New" button is large. */
+ uiLayout *row = uiLayoutSplit(layout, 0.3f, false);
+ uiItemL(row, text, 0);
+ uiTemplateID(row,
+ C,
+ ptr,
+ "default_value",
+ "image.new",
+ "image.open",
+ nullptr,
+ 0,
+ ICON_NONE,
+ nullptr);
+ }
+ }
+ else {
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
+ }
break;
}
case SOCK_COLLECTION: {
@@ -3673,14 +1430,6 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout
uiItemR(layout, ptr, "hide_value", DEFAULT_FLAGS, nullptr, 0);
}
-void ED_init_standard_node_socket_type(bNodeSocketType *stype)
-{
- stype->draw = std_node_socket_draw;
- stype->draw_color = std_node_socket_draw_color;
- stype->interface_draw = std_node_socket_interface_draw;
- stype->interface_draw_color = std_node_socket_interface_draw_color;
-}
-
static void node_socket_virtual_draw_color(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PointerRNA *UNUSED(node_ptr),
@@ -3689,31 +1438,45 @@ static void node_socket_virtual_draw_color(bContext *UNUSED(C),
copy_v4_v4(r_color, virtual_node_socket_color);
}
+} // namespace blender::ed::space_node
+
+void ED_init_standard_node_socket_type(bNodeSocketType *stype)
+{
+ using namespace blender::ed::space_node;
+ stype->draw = std_node_socket_draw;
+ stype->draw_color = std_node_socket_draw_color;
+ stype->interface_draw = std_node_socket_interface_draw;
+ stype->interface_draw_color = std_node_socket_interface_draw_color;
+}
+
void ED_init_node_socket_type_virtual(bNodeSocketType *stype)
{
+ using namespace blender::ed::space_node;
stype->draw = node_socket_button_label;
stype->draw_color = node_socket_virtual_draw_color;
}
+namespace blender::ed::space_node {
+
/* ************** Generic drawing ************** */
-void draw_nodespace_back_pix(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
+void draw_nodespace_back_pix(const bContext &C,
+ ARegion &region,
+ SpaceNode &snode,
bNodeInstanceKey parent_key)
{
- Main *bmain = CTX_data_main(C);
- bNodeInstanceKey active_viewer_key = (snode->nodetree ? snode->nodetree->active_viewer_key :
- NODE_INSTANCE_KEY_NONE);
+ Main *bmain = CTX_data_main(&C);
+ bNodeInstanceKey active_viewer_key = (snode.nodetree ? snode.nodetree->active_viewer_key :
+ NODE_INSTANCE_KEY_NONE);
GPU_matrix_push_projection();
GPU_matrix_push();
- wmOrtho2_region_pixelspace(region);
+ wmOrtho2_region_pixelspace(&region);
GPU_matrix_identity_set();
- ED_region_draw_cb_draw(C, region, REGION_DRAW_BACKDROP);
+ ED_region_draw_cb_draw(&C, &region, REGION_DRAW_BACKDROP);
GPU_matrix_pop_projection();
GPU_matrix_pop();
- if (!(snode->flag & SNODE_BACKDRAW) || !ED_node_is_compositor(snode)) {
+ if (!(snode.flag & SNODE_BACKDRAW) || !ED_node_is_compositor(&snode)) {
return;
}
@@ -3728,7 +1491,7 @@ void draw_nodespace_back_pix(const bContext *C,
GPUFrameBuffer *old_fb = GPU_framebuffer_active_get();
GPU_framebuffer_restore();
BLI_thread_lock(LOCK_DRAW_IMAGE);
- DRW_draw_view(C);
+ DRW_draw_view(&C);
BLI_thread_unlock(LOCK_DRAW_IMAGE);
GPU_framebuffer_bind_no_srgb(old_fb);
/* Draw manager changes the depth state. Set it back to NONE. Without this the node preview
@@ -3740,31 +1503,31 @@ void draw_nodespace_back_pix(const bContext *C,
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
if (ibuf) {
/* somehow the offset has to be calculated inverse */
- wmOrtho2_region_pixelspace(region);
- const float x = (region->winx - snode->zoom * ibuf->x) / 2 + snode->xof;
- const float y = (region->winy - snode->zoom * ibuf->y) / 2 + snode->yof;
+ wmOrtho2_region_pixelspace(&region);
+ const float x = (region.winx - snode.zoom * ibuf->x) / 2 + snode.xof;
+ const float y = (region.winy - snode.zoom * ibuf->y) / 2 + snode.yof;
/** \note draw selected info on backdrop */
- if (snode->edittree) {
- bNode *node = (bNode *)snode->edittree->nodes.first;
- rctf *viewer_border = &snode->nodetree->viewer_border;
+ if (snode.edittree) {
+ bNode *node = (bNode *)snode.edittree->nodes.first;
+ rctf *viewer_border = &snode.nodetree->viewer_border;
while (node) {
if (node->flag & NODE_SELECT) {
if (node->typeinfo->draw_backdrop) {
- node->typeinfo->draw_backdrop(snode, ibuf, node, x, y);
+ node->typeinfo->draw_backdrop(&snode, ibuf, node, x, y);
}
}
node = node->next;
}
- if ((snode->nodetree->flag & NTREE_VIEWER_BORDER) &&
+ if ((snode.nodetree->flag & NTREE_VIEWER_BORDER) &&
viewer_border->xmin < viewer_border->xmax && viewer_border->ymin < viewer_border->ymax) {
rcti pixel_border;
BLI_rcti_init(&pixel_border,
- x + snode->zoom * viewer_border->xmin * ibuf->x,
- x + snode->zoom * viewer_border->xmax * ibuf->x,
- y + snode->zoom * viewer_border->ymin * ibuf->y,
- y + snode->zoom * viewer_border->ymax * ibuf->y);
+ x + snode.zoom * viewer_border->xmin * ibuf->x,
+ x + snode.zoom * viewer_border->xmax * ibuf->x,
+ y + snode.zoom * viewer_border->ymin * ibuf->y,
+ y + snode.zoom * viewer_border->ymax * ibuf->y);
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -3783,10 +1546,9 @@ void draw_nodespace_back_pix(const bContext *C,
GPU_matrix_pop();
}
-/* return quadratic beziers points for a given nodelink and clip if v2d is not nullptr. */
bool node_link_bezier_handles(const View2D *v2d,
const SpaceNode *snode,
- const bNodeLink *link,
+ const bNodeLink &link,
float vec[4][2])
{
float cursor[2] = {0.0f, 0.0f};
@@ -3800,17 +1562,17 @@ bool node_link_bezier_handles(const View2D *v2d,
/* in v0 and v3 we put begin/end points */
int toreroute, fromreroute;
- if (link->fromsock) {
- vec[0][0] = link->fromsock->locx;
- vec[0][1] = link->fromsock->locy;
- if (link->fromsock->flag & SOCK_MULTI_INPUT) {
- node_link_calculate_multi_input_position(link->fromsock->locx,
- link->fromsock->locy,
- link->fromsock->total_inputs - 1,
- link->fromsock->total_inputs,
- vec[0]);
- }
- fromreroute = (link->fromnode && link->fromnode->type == NODE_REROUTE);
+ if (link.fromsock) {
+ vec[0][0] = link.fromsock->locx;
+ vec[0][1] = link.fromsock->locy;
+ if (link.fromsock->flag & SOCK_MULTI_INPUT) {
+ const float2 position = node_link_calculate_multi_input_position(
+ {link.fromsock->locx, link.fromsock->locy},
+ link.fromsock->total_inputs - 1,
+ link.fromsock->total_inputs);
+ copy_v2_v2(vec[0], position);
+ }
+ fromreroute = (link.fromnode && link.fromnode->type == NODE_REROUTE);
}
else {
if (snode == nullptr) {
@@ -3819,17 +1581,17 @@ bool node_link_bezier_handles(const View2D *v2d,
copy_v2_v2(vec[0], cursor);
fromreroute = 0;
}
- if (link->tosock) {
- vec[3][0] = link->tosock->locx;
- vec[3][1] = link->tosock->locy;
- if (!(link->tonode->flag & NODE_HIDDEN) && link->tosock->flag & SOCK_MULTI_INPUT) {
- node_link_calculate_multi_input_position(link->tosock->locx,
- link->tosock->locy,
- link->multi_input_socket_index,
- link->tosock->total_inputs,
- vec[3]);
+ if (link.tosock) {
+ vec[3][0] = link.tosock->locx;
+ vec[3][1] = link.tosock->locy;
+ if (!(link.tonode->flag & NODE_HIDDEN) && link.tosock->flag & SOCK_MULTI_INPUT) {
+ const float2 position = node_link_calculate_multi_input_position(
+ {link.tosock->locx, link.tosock->locy},
+ link.multi_input_socket_index,
+ link.tosock->total_inputs);
+ copy_v2_v2(vec[3], position);
}
- toreroute = (link->tonode && link->tonode->type == NODE_REROUTE);
+ toreroute = (link.tonode && link.tonode->type == NODE_REROUTE);
}
else {
if (snode == nullptr) {
@@ -3892,10 +1654,9 @@ bool node_link_bezier_handles(const View2D *v2d,
return true;
}
-/* if v2d not nullptr, it clips and returns 0 if not visible */
bool node_link_bezier_points(const View2D *v2d,
const SpaceNode *snode,
- const bNodeLink *link,
+ const bNodeLink &link,
float coord_array[][2],
const int resol)
{
@@ -3931,15 +1692,17 @@ static struct {
GPUBatch *batch_single; /* for single line */
GPUVertBuf *inst_vbo;
uint p0_id, p1_id, p2_id, p3_id;
- uint colid_id, muted_id;
+ uint colid_id, muted_id, start_color_id, end_color_id;
uint dim_factor_id;
uint thickness_id;
uint dash_factor_id;
+ uint dash_alpha_id;
GPUVertBufRaw p0_step, p1_step, p2_step, p3_step;
- GPUVertBufRaw colid_step, muted_step;
+ GPUVertBufRaw colid_step, muted_step, start_color_step, end_color_step;
GPUVertBufRaw dim_factor_step;
GPUVertBufRaw thickness_step;
GPUVertBufRaw dash_factor_step;
+ GPUVertBufRaw dash_alpha_step;
uint count;
bool enabled;
} g_batch_link;
@@ -3960,6 +1723,12 @@ static void nodelink_batch_reset()
g_batch_link.inst_vbo, g_batch_link.thickness_id, &g_batch_link.thickness_step);
GPU_vertbuf_attr_get_raw_data(
g_batch_link.inst_vbo, g_batch_link.dash_factor_id, &g_batch_link.dash_factor_step);
+ GPU_vertbuf_attr_get_raw_data(
+ g_batch_link.inst_vbo, g_batch_link.dash_alpha_id, &g_batch_link.dash_alpha_step);
+ GPU_vertbuf_attr_get_raw_data(
+ g_batch_link.inst_vbo, g_batch_link.start_color_id, &g_batch_link.start_color_step);
+ GPU_vertbuf_attr_get_raw_data(
+ g_batch_link.inst_vbo, g_batch_link.end_color_id, &g_batch_link.end_color_step);
g_batch_link.count = 0;
}
@@ -4075,6 +1844,10 @@ static void nodelink_batch_init()
&format_inst, "P3", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
g_batch_link.colid_id = GPU_vertformat_attr_add(
&format_inst, "colid_doarrow", GPU_COMP_U8, 4, GPU_FETCH_INT);
+ g_batch_link.start_color_id = GPU_vertformat_attr_add(
+ &format_inst, "start_color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ g_batch_link.end_color_id = GPU_vertformat_attr_add(
+ &format_inst, "end_color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
g_batch_link.muted_id = GPU_vertformat_attr_add(
&format_inst, "domuted", GPU_COMP_U8, 2, GPU_FETCH_INT);
g_batch_link.dim_factor_id = GPU_vertformat_attr_add(
@@ -4083,6 +1856,8 @@ static void nodelink_batch_init()
&format_inst, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
g_batch_link.dash_factor_id = GPU_vertformat_attr_add(
&format_inst, "dash_factor", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ g_batch_link.dash_alpha_id = GPU_vertformat_attr_add(
+ &format_inst, "dash_alpha", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
g_batch_link.inst_vbo = GPU_vertbuf_create_with_format_ex(&format_inst, GPU_USAGE_STREAM);
/* Alloc max count but only draw the range we need. */
GPU_vertbuf_data_alloc(g_batch_link.inst_vbo, NODELINK_GROUP_SIZE);
@@ -4109,59 +1884,68 @@ static char nodelink_get_color_id(int th_col)
return 0;
}
-static void nodelink_batch_draw(const SpaceNode *snode)
+static void nodelink_batch_draw(const SpaceNode &snode)
{
if (g_batch_link.count == 0) {
return;
}
GPU_blend(GPU_BLEND_ALPHA);
+ NodeLinkInstanceData node_link_data;
+
+ UI_GetThemeColor4fv(TH_WIRE_INNER, node_link_data.colors[nodelink_get_color_id(TH_WIRE_INNER)]);
+ UI_GetThemeColor4fv(TH_WIRE, node_link_data.colors[nodelink_get_color_id(TH_WIRE)]);
+ UI_GetThemeColor4fv(TH_ACTIVE, node_link_data.colors[nodelink_get_color_id(TH_ACTIVE)]);
+ UI_GetThemeColor4fv(TH_EDGE_SELECT,
+ node_link_data.colors[nodelink_get_color_id(TH_EDGE_SELECT)]);
+ UI_GetThemeColor4fv(TH_REDALERT, node_link_data.colors[nodelink_get_color_id(TH_REDALERT)]);
+ node_link_data.expandSize = snode.runtime->aspect * LINK_WIDTH;
+ node_link_data.arrowSize = ARROW_SIZE;
- float colors[6][4] = {{0.0f}};
- UI_GetThemeColor4fv(TH_WIRE_INNER, colors[nodelink_get_color_id(TH_WIRE_INNER)]);
- UI_GetThemeColor4fv(TH_WIRE, colors[nodelink_get_color_id(TH_WIRE)]);
- UI_GetThemeColor4fv(TH_ACTIVE, colors[nodelink_get_color_id(TH_ACTIVE)]);
- UI_GetThemeColor4fv(TH_EDGE_SELECT, colors[nodelink_get_color_id(TH_EDGE_SELECT)]);
- UI_GetThemeColor4fv(TH_REDALERT, colors[nodelink_get_color_id(TH_REDALERT)]);
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(sizeof(node_link_data), &node_link_data, __func__);
GPU_vertbuf_data_len_set(g_batch_link.inst_vbo, g_batch_link.count);
GPU_vertbuf_use(g_batch_link.inst_vbo); /* force update. */
GPU_batch_program_set_builtin(g_batch_link.batch, GPU_SHADER_2D_NODELINK_INST);
- GPU_batch_uniform_4fv_array(g_batch_link.batch, "colors", 6, colors);
- GPU_batch_uniform_1f(g_batch_link.batch, "expandSize", snode->runtime->aspect * LINK_WIDTH);
- GPU_batch_uniform_1f(g_batch_link.batch, "arrowSize", ARROW_SIZE);
+ GPU_batch_uniformbuf_bind(g_batch_link.batch, "node_link_data", ubo);
GPU_batch_draw(g_batch_link.batch);
+ GPU_uniformbuf_unbind(ubo);
+ GPU_uniformbuf_free(ubo);
+
nodelink_batch_reset();
GPU_blend(GPU_BLEND_NONE);
}
-void nodelink_batch_start(SpaceNode *UNUSED(snode))
+void nodelink_batch_start(SpaceNode &UNUSED(snode))
{
g_batch_link.enabled = true;
}
-void nodelink_batch_end(SpaceNode *snode)
+void nodelink_batch_end(SpaceNode &snode)
{
nodelink_batch_draw(snode);
g_batch_link.enabled = false;
}
-static void nodelink_batch_add_link(const SpaceNode *snode,
- const float p0[2],
- const float p1[2],
- const float p2[2],
- const float p3[2],
+static void nodelink_batch_add_link(const SpaceNode &snode,
+ const float2 &p0,
+ const float2 &p1,
+ const float2 &p2,
+ const float2 &p3,
int th_col1,
int th_col2,
int th_col3,
+ const float start_color[4],
+ const float end_color[4],
bool drawarrow,
bool drawmuted,
float dim_factor,
float thickness,
- float dash_factor)
+ float dash_factor,
+ float dash_alpha)
{
/* Only allow these colors. If more is needed, you need to modify the shader accordingly. */
BLI_assert(ELEM(th_col1, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT));
@@ -4178,30 +1962,37 @@ static void nodelink_batch_add_link(const SpaceNode *snode,
colid[1] = nodelink_get_color_id(th_col2);
colid[2] = nodelink_get_color_id(th_col3);
colid[3] = drawarrow;
+ copy_v4_v4((float *)GPU_vertbuf_raw_step(&g_batch_link.start_color_step), start_color);
+ copy_v4_v4((float *)GPU_vertbuf_raw_step(&g_batch_link.end_color_step), end_color);
char *muted = (char *)GPU_vertbuf_raw_step(&g_batch_link.muted_step);
muted[0] = drawmuted;
*(float *)GPU_vertbuf_raw_step(&g_batch_link.dim_factor_step) = dim_factor;
*(float *)GPU_vertbuf_raw_step(&g_batch_link.thickness_step) = thickness;
*(float *)GPU_vertbuf_raw_step(&g_batch_link.dash_factor_step) = dash_factor;
+ *(float *)GPU_vertbuf_raw_step(&g_batch_link.dash_alpha_step) = dash_alpha;
if (g_batch_link.count == NODELINK_GROUP_SIZE) {
nodelink_batch_draw(snode);
}
}
-/* don't do shadows if th_col3 is -1. */
-void node_draw_link_bezier(const View2D *v2d,
- const SpaceNode *snode,
- const bNodeLink *link,
- int th_col1,
- int th_col2,
- int th_col3)
+void node_draw_link_bezier(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link,
+ const int th_col1,
+ const int th_col2,
+ const int th_col3)
{
const float dim_factor = node_link_dim_factor(v2d, link);
float thickness = 1.5f;
float dash_factor = 1.0f;
- if (snode->edittree->type == NTREE_GEOMETRY) {
- if (link->fromsock && link->fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) {
+
+ bTheme *btheme = UI_GetTheme();
+ const float dash_alpha = btheme->space_node.dash_alpha;
+
+ if (snode.edittree->type == NTREE_GEOMETRY) {
+ if (link.fromsock && link.fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) {
/* Make field links a bit thinner. */
thickness = 1.0f;
/* Draw field as dashes. */
@@ -4210,14 +2001,62 @@ void node_draw_link_bezier(const View2D *v2d,
}
float vec[4][2];
- const bool highlighted = link->flag & NODE_LINK_TEMP_HIGHLIGHT;
- if (node_link_bezier_handles(v2d, snode, link, vec)) {
- int drawarrow = ((link->tonode && (link->tonode->type == NODE_REROUTE)) &&
- (link->fromnode && (link->fromnode->type == NODE_REROUTE)));
- int drawmuted = (link->flag & NODE_LINK_MUTED);
+ const bool highlighted = link.flag & NODE_LINK_TEMP_HIGHLIGHT;
+ if (node_link_bezier_handles(&v2d, &snode, link, vec)) {
+ int drawarrow = ((link.tonode && (link.tonode->type == NODE_REROUTE)) &&
+ (link.fromnode && (link.fromnode->type == NODE_REROUTE)));
+ int drawmuted = (link.flag & NODE_LINK_MUTED);
if (g_batch_link.batch == nullptr) {
nodelink_batch_init();
}
+ /* Draw single link. */
+ float colors[3][4] = {{0.0f}};
+ if (th_col3 != -1) {
+ UI_GetThemeColor4fv(th_col3, colors[0]);
+ }
+
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS &&
+ snode.overlay.flag & SN_OVERLAY_SHOW_WIRE_COLORS) {
+ PointerRNA from_node_ptr, to_node_ptr;
+ RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.fromnode, &from_node_ptr);
+ RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.tonode, &to_node_ptr);
+ if (link.fromsock) {
+ node_socket_color_get(C, *snode.edittree, from_node_ptr, *link.fromsock, colors[1]);
+ }
+ else {
+ node_socket_color_get(C, *snode.edittree, to_node_ptr, *link.tosock, colors[1]);
+ }
+
+ if (link.tosock) {
+ node_socket_color_get(C, *snode.edittree, to_node_ptr, *link.tosock, colors[2]);
+ }
+ else {
+ node_socket_color_get(C, *snode.edittree, from_node_ptr, *link.fromsock, colors[2]);
+ }
+ }
+ else {
+ UI_GetThemeColor4fv(th_col1, colors[1]);
+ UI_GetThemeColor4fv(th_col2, colors[2]);
+ }
+
+ /* Highlight links connected to selected nodes. */
+ const bool is_fromnode_selected = link.fromnode && link.fromnode->flag & SELECT;
+ const bool is_tonode_selected = link.tonode && link.tonode->flag & SELECT;
+ if (is_fromnode_selected || is_tonode_selected) {
+ float color_selected[4];
+ UI_GetThemeColor4fv(TH_EDGE_SELECT, color_selected);
+ const float alpha = color_selected[3];
+
+ /* Interpolate color if highlight color is not fully transparent. */
+ if (alpha != 0.0) {
+ if (is_fromnode_selected) {
+ interp_v3_v3v3(colors[1], colors[1], color_selected, alpha);
+ }
+ if (is_tonode_selected) {
+ interp_v3_v3v3(colors[2], colors[2], color_selected, alpha);
+ }
+ }
+ }
if (g_batch_link.enabled && !highlighted) {
/* Add link to batch. */
@@ -4229,82 +2068,84 @@ void node_draw_link_bezier(const View2D *v2d,
th_col1,
th_col2,
th_col3,
+ colors[1],
+ colors[2],
drawarrow,
drawmuted,
dim_factor,
thickness,
- dash_factor);
+ dash_factor,
+ dash_alpha);
}
else {
- /* Draw single link. */
- float colors[3][4] = {{0.0f}};
- if (th_col3 != -1) {
- UI_GetThemeColor4fv(th_col3, colors[0]);
- }
- UI_GetThemeColor4fv(th_col1, colors[1]);
- UI_GetThemeColor4fv(th_col2, colors[2]);
-
if (highlighted) {
float link_preselection_highlight_color[4];
UI_GetThemeColor4fv(TH_SELECT, link_preselection_highlight_color);
copy_v4_v4(colors[2], link_preselection_highlight_color);
}
+ NodeLinkData node_link_data;
+ for (int i = 0; i < 4; i++) {
+ copy_v2_v2(node_link_data.bezierPts[i], vec[i]);
+ }
+ for (int i = 0; i < 3; i++) {
+ copy_v4_v4(node_link_data.colors[i], colors[i]);
+ }
+ node_link_data.doArrow = drawarrow;
+ node_link_data.doMuted = drawmuted;
+ node_link_data.dim_factor = dim_factor;
+ node_link_data.thickness = thickness;
+ node_link_data.dash_factor = dash_factor;
+ node_link_data.dash_alpha = dash_alpha;
+ node_link_data.expandSize = snode.runtime->aspect * LINK_WIDTH;
+ node_link_data.arrowSize = ARROW_SIZE;
+
GPUBatch *batch = g_batch_link.batch_single;
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
+ sizeof(NodeLinkData), &node_link_data, __func__);
+
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK);
- GPU_batch_uniform_2fv_array(batch, "bezierPts", 4, vec);
- GPU_batch_uniform_4fv_array(batch, "colors", 3, colors);
- GPU_batch_uniform_1f(batch, "expandSize", snode->runtime->aspect * LINK_WIDTH);
- GPU_batch_uniform_1f(batch, "arrowSize", ARROW_SIZE);
- GPU_batch_uniform_1i(batch, "doArrow", drawarrow);
- GPU_batch_uniform_1i(batch, "doMuted", drawmuted);
- GPU_batch_uniform_1f(batch, "dim_factor", dim_factor);
- GPU_batch_uniform_1f(batch, "thickness", thickness);
- GPU_batch_uniform_1f(batch, "dash_factor", dash_factor);
+ GPU_batch_uniformbuf_bind(batch, "node_link_data", ubo);
GPU_batch_draw(batch);
+
+ GPU_uniformbuf_unbind(ubo);
+ GPU_uniformbuf_free(ubo);
}
}
}
-/* NOTE: this is used for fake links in groups too. */
-void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
+void node_draw_link(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link)
{
int th_col1 = TH_WIRE_INNER, th_col2 = TH_WIRE_INNER, th_col3 = TH_WIRE;
- if (link->fromsock == nullptr && link->tosock == nullptr) {
+ if (link.fromsock == nullptr && link.tosock == nullptr) {
return;
}
/* new connection */
- if (!link->fromsock || !link->tosock) {
+ if (!link.fromsock || !link.tosock) {
th_col1 = th_col2 = TH_ACTIVE;
}
else {
/* going to give issues once... */
- if (link->tosock->flag & SOCK_UNAVAIL) {
+ if (link.tosock->flag & SOCK_UNAVAIL) {
return;
}
- if (link->fromsock->flag & SOCK_UNAVAIL) {
+ if (link.fromsock->flag & SOCK_UNAVAIL) {
return;
}
- if (link->flag & NODE_LINK_VALID) {
+ if (link.flag & NODE_LINK_VALID) {
/* special indicated link, on drop-node */
- if (link->flag & NODE_LINKFLAG_HILITE) {
+ if (link.flag & NODE_LINKFLAG_HILITE) {
th_col1 = th_col2 = TH_ACTIVE;
}
- else if (link->flag & NODE_LINK_MUTED) {
+ else if (link.flag & NODE_LINK_MUTED) {
th_col1 = th_col2 = TH_REDALERT;
}
- else {
- /* Regular link, highlight if connected to selected node. */
- if (link->fromnode && link->fromnode->flag & SELECT) {
- th_col1 = TH_EDGE_SELECT;
- }
- if (link->tonode && link->tonode->flag & SELECT) {
- th_col2 = TH_EDGE_SELECT;
- }
- }
}
else {
/* Invalid link. */
@@ -4313,16 +2154,18 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
}
}
/* Links from field to non-field sockets are not allowed. */
- if (snode->edittree->type == NTREE_GEOMETRY && !(link->flag & NODE_LINK_DRAGGED)) {
- if ((link->fromsock && link->fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) &&
- (link->tosock && link->tosock->display_shape == SOCK_DISPLAY_SHAPE_CIRCLE)) {
+ if (snode.edittree->type == NTREE_GEOMETRY && !(link.flag & NODE_LINK_DRAGGED)) {
+ if ((link.fromsock && link.fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) &&
+ (link.tosock && link.tosock->display_shape == SOCK_DISPLAY_SHAPE_CIRCLE)) {
th_col1 = th_col2 = th_col3 = TH_REDALERT;
}
}
- node_draw_link_bezier(v2d, snode, link, th_col1, th_col2, th_col3);
+ node_draw_link_bezier(C, v2d, snode, link, th_col1, th_col2, th_col3);
}
+} // namespace blender::ed::space_node
+
void ED_node_draw_snap(View2D *v2d, const float cent[2], float size, NodeBorder border, uint pos)
{
immBegin(GPU_PRIM_LINES, 4);
diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc
new file mode 100644
index 00000000000..45126e9cee0
--- /dev/null
+++ b/source/blender/editors/space_node/link_drag_search.cc
@@ -0,0 +1,327 @@
+/*
+ * 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 "BLI_listbase.h"
+#include "BLI_string_search.h"
+
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+
+#include "NOD_socket_search_link.hh"
+
+#include "BLT_translation.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+
+#include "ED_node.h"
+
+#include "node_intern.hh"
+
+using blender::nodes::SocketLinkOperation;
+
+namespace blender::ed::space_node {
+
+struct LinkDragSearchStorage {
+ bNode &from_node;
+ bNodeSocket &from_socket;
+ float2 cursor;
+ Vector<SocketLinkOperation> search_link_ops;
+ char search[256];
+
+ eNodeSocketInOut in_out() const
+ {
+ return static_cast<eNodeSocketInOut>(from_socket.in_out);
+ }
+};
+
+static void add_reroute_node_fn(nodes::LinkSearchOpParams &params)
+{
+ bNode &reroute = params.add_node("NodeReroute");
+ if (params.socket.in_out == SOCK_IN) {
+ nodeAddLink(&params.node_tree,
+ &reroute,
+ static_cast<bNodeSocket *>(reroute.outputs.first),
+ &params.node,
+ &params.socket);
+ }
+ else {
+ nodeAddLink(&params.node_tree,
+ &params.node,
+ &params.socket,
+ &reroute,
+ static_cast<bNodeSocket *>(reroute.inputs.first));
+ }
+}
+
+static void add_group_input_node_fn(nodes::LinkSearchOpParams &params)
+{
+ /* Add a group input based on the connected socket, and add a new group input node. */
+ bNodeSocket *interface_socket = ntreeAddSocketInterfaceFromSocket(
+ &params.node_tree, &params.node, &params.socket);
+ const int group_input_index = BLI_findindex(&params.node_tree.inputs, interface_socket);
+
+ bNode &group_input = params.add_node("NodeGroupInput");
+
+ /* This is necessary to create the new sockets in the other input nodes. */
+ ED_node_tree_propagate_change(&params.C, CTX_data_main(&params.C), &params.node_tree);
+
+ /* Hide the new input in all other group input nodes, to avoid making them taller. */
+ LISTBASE_FOREACH (bNode *, node, &params.node_tree.nodes) {
+ if (node->type == NODE_GROUP_INPUT) {
+ bNodeSocket *new_group_input_socket = (bNodeSocket *)BLI_findlink(&node->outputs,
+ group_input_index);
+ new_group_input_socket->flag |= SOCK_HIDDEN;
+ }
+ }
+
+ /* Hide all existing inputs in the new group input node, to only display the new one. */
+ LISTBASE_FOREACH (bNodeSocket *, socket, &group_input.outputs) {
+ socket->flag |= SOCK_HIDDEN;
+ }
+
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&group_input.outputs, group_input_index);
+ if (socket == nullptr) {
+ /* Adding sockets can fail in some cases. There's no good reason not to be safe here. */
+ return;
+ }
+ /* Unhide the socket for the new input in the new node and make a connection to it. */
+ socket->flag &= ~SOCK_HIDDEN;
+ nodeAddLink(&params.node_tree, &group_input, socket, &params.node, &params.socket);
+}
+
+static void add_existing_group_input_fn(nodes::LinkSearchOpParams &params,
+ const bNodeSocket &interface_socket)
+{
+ const int group_input_index = BLI_findindex(&params.node_tree.inputs, &interface_socket);
+ bNode &group_input = params.add_node("NodeGroupInput");
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &group_input.outputs) {
+ socket->flag |= SOCK_HIDDEN;
+ }
+
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&group_input.outputs, group_input_index);
+ if (socket == nullptr) {
+ /* Adding sockets can fail in some cases. There's no good reason not to be safe here. */
+ return;
+ }
+
+ socket->flag &= ~SOCK_HIDDEN;
+ nodeAddLink(&params.node_tree, &group_input, socket, &params.node, &params.socket);
+}
+
+/**
+ * Call the callback to gather compatible socket connections for all node types, and the operations
+ * that will actually make the connections. Also add some custom operations like connecting a group
+ * output node.
+ */
+static void gather_socket_link_operations(bNodeTree &node_tree,
+ const bNodeSocket &socket,
+ Vector<SocketLinkOperation> &search_link_ops)
+{
+ NODE_TYPES_BEGIN (node_type) {
+ if (StringRef(node_type->idname).find("Legacy") != StringRef::not_found) {
+ continue;
+ }
+ const char *disabled_hint;
+ if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) {
+ continue;
+ }
+
+ if (node_type->gather_link_search_ops) {
+ nodes::GatherLinkSearchOpParams params{*node_type, node_tree, socket, search_link_ops};
+ node_type->gather_link_search_ops(params);
+ }
+ }
+ NODE_TYPES_END;
+
+ search_link_ops.append({IFACE_("Reroute"), add_reroute_node_fn});
+
+ const bool is_node_group = !(node_tree.id.flag & LIB_EMBEDDED_DATA);
+
+ if (is_node_group && socket.in_out == SOCK_IN) {
+ search_link_ops.append({IFACE_("Group Input"), add_group_input_node_fn});
+
+ int weight = -1;
+ LISTBASE_FOREACH (const bNodeSocket *, interface_socket, &node_tree.inputs) {
+ eNodeSocketDatatype from = (eNodeSocketDatatype)interface_socket->type;
+ eNodeSocketDatatype to = (eNodeSocketDatatype)socket.type;
+ if (node_tree.typeinfo->validate_link && !node_tree.typeinfo->validate_link(from, to)) {
+ continue;
+ }
+ search_link_ops.append(
+ {std::string(IFACE_("Group Input ")) + UI_MENU_ARROW_SEP + interface_socket->name,
+ [interface_socket](nodes::LinkSearchOpParams &params) {
+ add_existing_group_input_fn(params, *interface_socket);
+ },
+ weight});
+ weight--;
+ }
+ }
+}
+
+static void link_drag_search_update_fn(const bContext *UNUSED(C),
+ void *arg,
+ const char *str,
+ uiSearchItems *items,
+ const bool is_first)
+{
+ LinkDragSearchStorage &storage = *static_cast<LinkDragSearchStorage *>(arg);
+
+ StringSearch *search = BLI_string_search_new();
+
+ for (SocketLinkOperation &op : storage.search_link_ops) {
+ BLI_string_search_add(search, op.name.c_str(), &op, op.weight);
+ }
+
+ /* Don't filter when the menu is first opened, but still run the search
+ * so the items are in the same order they will appear in while searching. */
+ const char *string = is_first ? "" : str;
+ SocketLinkOperation **filtered_items;
+ const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items);
+
+ for (const int i : IndexRange(filtered_amount)) {
+ SocketLinkOperation &item = *filtered_items[i];
+ if (!UI_search_item_add(items, item.name.c_str(), &item, ICON_NONE, 0, 0)) {
+ break;
+ }
+ }
+
+ MEM_freeN(filtered_items);
+ BLI_string_search_free(search);
+}
+
+static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2)
+{
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ LinkDragSearchStorage &storage = *static_cast<LinkDragSearchStorage *>(arg1);
+ SocketLinkOperation *item = static_cast<SocketLinkOperation *>(arg2);
+ if (item == nullptr) {
+ return;
+ }
+
+ node_deselect_all(snode);
+
+ Vector<bNode *> new_nodes;
+ nodes::LinkSearchOpParams params{
+ *C, *snode.edittree, storage.from_node, storage.from_socket, new_nodes};
+ item->fn(params);
+ if (new_nodes.is_empty()) {
+ return;
+ }
+
+ /* For now, assume that only one node is created by the callback. */
+ BLI_assert(new_nodes.size() == 1);
+ bNode *new_node = new_nodes.first();
+
+ new_node->locx = storage.cursor.x / UI_DPI_FAC;
+ new_node->locy = storage.cursor.y / UI_DPI_FAC + 20 * UI_DPI_FAC;
+ if (storage.in_out() == SOCK_IN) {
+ new_node->locx -= new_node->width;
+ }
+
+ nodeSetSelected(new_node, true);
+ nodeSetActive(snode.edittree, new_node);
+
+ /* Ideally it would be possible to tag the node tree in some way so it updates only after the
+ * translate operation is finished, but normally moving nodes around doesn't cause updates. */
+ ED_node_tree_propagate_change(C, &bmain, snode.edittree);
+
+ /* Start translation operator with the new node. */
+ wmOperatorType *ot = WM_operatortype_find("TRANSFORM_OT_translate", true);
+ BLI_assert(ot);
+ PointerRNA ptr;
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_boolean_set(&ptr, "view2d_edge_pan", true);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
+ WM_operator_properties_free(&ptr);
+}
+
+static void link_drag_search_free_fn(void *arg)
+{
+ LinkDragSearchStorage *storage = static_cast<LinkDragSearchStorage *>(arg);
+ delete storage;
+}
+
+static uiBlock *create_search_popup_block(bContext *C, ARegion *region, void *arg_op)
+{
+ LinkDragSearchStorage &storage = *(LinkDragSearchStorage *)arg_op;
+
+ bNodeTree *node_tree = CTX_wm_space_node(C)->nodetree;
+ gather_socket_link_operations(*node_tree, storage.from_socket, storage.search_link_ops);
+
+ uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
+ UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
+ UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
+
+ uiBut *but = uiDefSearchBut(block,
+ storage.search,
+ 0,
+ ICON_VIEWZOOM,
+ sizeof(storage.search),
+ storage.in_out() == SOCK_OUT ? 10 : 10 - UI_searchbox_size_x(),
+ 10,
+ UI_searchbox_size_x(),
+ UI_UNIT_Y,
+ 0,
+ 0,
+ "");
+ UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP);
+ UI_but_func_search_set(but,
+ nullptr,
+ link_drag_search_update_fn,
+ &storage,
+ false,
+ link_drag_search_free_fn,
+ link_drag_search_exec_fn,
+ nullptr);
+ UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
+
+ /* Fake button to hold space for the search items. */
+ uiDefBut(block,
+ UI_BTYPE_LABEL,
+ 0,
+ "",
+ storage.in_out() == SOCK_OUT ? 10 : 10 - UI_searchbox_size_x(),
+ 10 - UI_searchbox_size_y(),
+ UI_searchbox_size_x(),
+ UI_searchbox_size_y(),
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+
+ const int offset[2] = {0, -UI_UNIT_Y};
+ UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, offset);
+ return block;
+}
+
+void invoke_node_link_drag_add_menu(bContext &C,
+ bNode &node,
+ bNodeSocket &socket,
+ const float2 &cursor)
+{
+ LinkDragSearchStorage *storage = new LinkDragSearchStorage{node, socket, cursor};
+ /* Use the "_ex" variant with `can_refresh` false to avoid a double free when closing Blender. */
+ UI_popup_block_invoke_ex(&C, create_search_popup_block, storage, nullptr, false);
+}
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index 7b6ca5e6e61..8e88f1fad5a 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -28,7 +28,6 @@
#include "DNA_texture_types.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLT_translation.h"
@@ -37,6 +36,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
@@ -56,30 +56,27 @@
#include "UI_view2d.h"
-#include "node_intern.h" /* own include */
+#include "node_intern.hh" /* own include */
/* -------------------------------------------------------------------- */
/** \name Utilities
* \{ */
-/**
- * XXX Does some additional initialization on top of #nodeAddNode
- * Can be used with both custom and static nodes,
- * if `idname == nullptr` the static int type will be used instead.
- */
-bNode *node_add_node(const bContext *C, const char *idname, int type, float locx, float locy)
+namespace blender::ed::space_node {
+
+bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- Main *bmain = CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ Main &bmain = *CTX_data_main(&C);
bNode *node = nullptr;
node_deselect_all(snode);
if (idname) {
- node = nodeAddNode(C, snode->edittree, idname);
+ node = nodeAddNode(&C, snode.edittree, idname);
}
else {
- node = nodeAddStaticNode(C, snode->edittree, type);
+ node = nodeAddStaticNode(&C, snode.edittree, type);
}
BLI_assert(node && node->typeinfo);
@@ -89,15 +86,8 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx
nodeSetSelected(node, true);
- ntreeUpdateTree(bmain, snode->edittree);
- ED_node_set_active(bmain, snode, snode->edittree, node, nullptr);
-
- snode_update(snode, node);
-
- if (snode->nodetree->type == NTREE_TEXTURE) {
- ntreeTexCheckCyclics(snode->edittree);
- }
-
+ ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr);
+ ED_node_tree_propagate_change(&C, &bmain, snode.edittree);
return node;
}
@@ -107,7 +97,7 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx
/** \name Add Reroute Operator
* \{ */
-static bool add_reroute_intersect_check(bNodeLink *link,
+static bool add_reroute_intersect_check(const bNodeLink &link,
float mcoords[][2],
int tot,
float result[2])
@@ -142,7 +132,7 @@ static bNodeSocketLink *add_reroute_insert_socket_link(ListBase *lb,
{
bNodeSocketLink *socklink, *prev;
- socklink = (bNodeSocketLink *)MEM_callocN(sizeof(bNodeSocketLink), "socket link");
+ socklink = MEM_cnew<bNodeSocketLink>("socket link");
socklink->sock = sock;
socklink->link = link;
copy_v2_v2(socklink->point, point);
@@ -224,9 +214,9 @@ static bNodeSocketLink *add_reroute_do_socket_section(bContext *C,
static int add_reroute_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
+ bNodeTree &ntree = *snode.edittree;
float mcoords[256][2];
int i = 0;
@@ -236,7 +226,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
RNA_float_get_array(&itemptr, "loc", loc);
UI_view2d_region_to_view(
- &region->v2d, (short)loc[0], (short)loc[1], &mcoords[i][0], &mcoords[i][1]);
+ &region.v2d, (short)loc[0], (short)loc[1], &mcoords[i][0], &mcoords[i][1]);
i++;
if (i >= 256) {
break;
@@ -246,7 +236,6 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
if (i > 1) {
ListBase output_links, input_links;
- bNodeLink *link;
bNodeSocketLink *socklink;
float insert_point[2];
@@ -259,11 +248,11 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
BLI_listbase_clear(&output_links);
BLI_listbase_clear(&input_links);
- for (link = (bNodeLink *)ntree->links.first; link; link = link->next) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
continue;
}
- if (add_reroute_intersect_check(link, mcoords, i, insert_point)) {
+ if (add_reroute_intersect_check(*link, mcoords, i, insert_point)) {
add_reroute_insert_socket_link(&output_links, link->fromsock, link, insert_point);
add_reroute_insert_socket_link(&input_links, link->tosock, link, insert_point);
@@ -288,10 +277,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
BLI_freelistN(&input_links);
/* always last */
- ntreeUpdateTree(CTX_data_main(C), ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
-
+ ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree);
return OPERATOR_FINISHED;
}
@@ -377,7 +363,7 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- bNode *group_node = node_add_node(C,
+ bNode *group_node = node_add_node(*C,
node_group_idname(C),
(node_group->type == NTREE_CUSTOM) ? NODE_CUSTOM_GROUP :
NODE_GROUP,
@@ -390,14 +376,10 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
group_node->id = &node_group->id;
id_us_plus(group_node->id);
+ BKE_ntree_update_tag_node_property(snode->edittree, group_node);
nodeSetActive(ntree, group_node);
- ntreeUpdateTree(bmain, node_group);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
-
+ ED_node_tree_propagate_change(C, bmain, nullptr);
return OPERATOR_FINISHED;
}
@@ -445,15 +427,14 @@ void NODE_OT_add_group(wmOperatorType *ot)
static Object *node_add_object_get_and_poll_object_node_tree(Main *bmain, wmOperator *op)
{
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
-
- Object *object = (Object *)BKE_libblock_find_name(bmain, ID_OB, name);
- if (!object) {
- return nullptr;
+ if (RNA_struct_property_is_set(op->ptr, "session_uuid")) {
+ const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid");
+ return (Object *)BKE_libblock_find_session_uuid(bmain, ID_OB, session_uuid);
}
- return object;
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "name", name);
+ return (Object *)BKE_libblock_find_name(bmain, ID_OB, name);
}
static int node_add_object_exec(bContext *C, wmOperator *op)
@@ -470,7 +451,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
bNode *object_node = node_add_node(
- C, nullptr, GEO_NODE_OBJECT_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ *C, nullptr, GEO_NODE_OBJECT_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]);
if (!object_node) {
BKE_report(op->reports, RPT_WARNING, "Could not add node object");
return OPERATOR_CANCELLED;
@@ -487,12 +468,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op)
id_us_plus(&object->id);
nodeSetActive(ntree, object_node);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
-
- ED_node_tag_update_nodetree(bmain, ntree, object_node);
+ ED_node_tree_propagate_change(C, bmain, ntree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
@@ -525,6 +501,8 @@ static bool node_add_object_poll(bContext *C)
void NODE_OT_add_object(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add Node Object";
ot->description = "Add an object info node to the current node editor";
@@ -539,6 +517,16 @@ void NODE_OT_add_object(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
RNA_def_string(ot->srna, "name", "Object", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the data-block to assign",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
}
/** \} */
@@ -549,15 +537,14 @@ void NODE_OT_add_object(wmOperatorType *ot)
static Tex *node_add_texture_get_and_poll_texture_node_tree(Main *bmain, wmOperator *op)
{
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
-
- Tex *texture = (Tex *)BKE_libblock_find_name(bmain, ID_TE, name);
- if (!texture) {
- return nullptr;
+ if (RNA_struct_property_is_set(op->ptr, "session_uuid")) {
+ const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid");
+ return (Tex *)BKE_libblock_find_session_uuid(bmain, ID_TE, session_uuid);
}
- return texture;
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "name", name);
+ return (Tex *)BKE_libblock_find_name(bmain, ID_TE, name);
}
static int node_add_texture_exec(bContext *C, wmOperator *op)
@@ -573,7 +560,7 @@ static int node_add_texture_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- bNode *texture_node = node_add_node(C,
+ bNode *texture_node = node_add_node(*C,
nullptr,
GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE,
snode->runtime->cursor[0],
@@ -587,14 +574,9 @@ static int node_add_texture_exec(bContext *C, wmOperator *op)
id_us_plus(&texture->id);
nodeSetActive(ntree, texture_node);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, bmain, ntree);
DEG_relations_tag_update(bmain);
- ED_node_tag_update_nodetree(bmain, ntree, texture_node);
-
return OPERATOR_FINISHED;
}
@@ -625,6 +607,8 @@ static bool node_add_texture_poll(bContext *C)
void NODE_OT_add_texture(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add Node Texture";
ot->description = "Add a texture to the current node editor";
@@ -640,6 +624,16 @@ void NODE_OT_add_texture(wmOperatorType *ot)
RNA_def_string(
ot->srna, "name", "Texture", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the data-block to assign",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
}
/** \} */
@@ -651,22 +645,21 @@ void NODE_OT_add_texture(wmOperatorType *ot)
static Collection *node_add_collection_get_and_poll_collection_node_tree(Main *bmain,
wmOperator *op)
{
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
-
- Collection *collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, name);
- if (!collection) {
- return nullptr;
+ if (RNA_struct_property_is_set(op->ptr, "session_uuid")) {
+ const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid");
+ return (Collection *)BKE_libblock_find_session_uuid(bmain, ID_GR, session_uuid);
}
- return collection;
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "name", name);
+ return (Collection *)BKE_libblock_find_name(bmain, ID_GR, name);
}
static int node_add_collection_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree *ntree = snode.edittree;
Collection *collection;
if (!(collection = node_add_collection_get_and_poll_collection_node_tree(bmain, op))) {
@@ -676,7 +669,7 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
bNode *collection_node = node_add_node(
- C, nullptr, GEO_NODE_COLLECTION_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ *C, nullptr, GEO_NODE_COLLECTION_INFO, snode.runtime->cursor[0], snode.runtime->cursor[1]);
if (!collection_node) {
BKE_report(op->reports, RPT_WARNING, "Could not add node collection");
return OPERATOR_CANCELLED;
@@ -693,14 +686,9 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
id_us_plus(&collection->id);
nodeSetActive(ntree, collection_node);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, bmain, ntree);
DEG_relations_tag_update(bmain);
- ED_node_tag_update_nodetree(bmain, ntree, collection_node);
-
return OPERATOR_FINISHED;
}
@@ -731,6 +719,8 @@ static bool node_add_collection_poll(bContext *C)
void NODE_OT_add_collection(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add Node Collection";
ot->description = "Add an collection info node to the current node editor";
@@ -746,6 +736,16 @@ void NODE_OT_add_collection(wmOperatorType *ot)
RNA_def_string(
ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the data-block to assign",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
}
/** \} */
@@ -758,13 +758,13 @@ static bool node_add_file_poll(bContext *C)
{
const SpaceNode *snode = CTX_wm_space_node(C);
return ED_operator_node_editable(C) &&
- ELEM(snode->nodetree->type, NTREE_SHADER, NTREE_TEXTURE, NTREE_COMPOSIT);
+ ELEM(snode->nodetree->type, NTREE_SHADER, NTREE_TEXTURE, NTREE_COMPOSIT, NTREE_GEOMETRY);
}
static int node_add_file_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
bNode *node;
Image *ima;
int type = 0;
@@ -774,7 +774,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- switch (snode->nodetree->type) {
+ switch (snode.nodetree->type) {
case NTREE_SHADER:
type = SH_NODE_TEX_IMAGE;
break;
@@ -784,20 +784,30 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
case NTREE_COMPOSIT:
type = CMP_NODE_IMAGE;
break;
+ case NTREE_GEOMETRY:
+ type = GEO_NODE_IMAGE_TEXTURE;
+ break;
default:
return OPERATOR_CANCELLED;
}
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- node = node_add_node(C, nullptr, type, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ node = node_add_node(*C, nullptr, type, snode.runtime->cursor[0], snode.runtime->cursor[1]);
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add an image node");
return OPERATOR_CANCELLED;
}
- node->id = (ID *)ima;
+ if (type == GEO_NODE_IMAGE_TEXTURE) {
+ bNodeSocket *image_socket = (bNodeSocket *)node->inputs.first;
+ bNodeSocketValueImage *socket_value = (bNodeSocketValueImage *)image_socket->default_value;
+ socket_value->value = ima;
+ }
+ else {
+ node->id = (ID *)ima;
+ }
/* When adding new image file via drag-drop we need to load imbuf in order
* to get proper image source.
@@ -807,8 +817,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
}
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, bmain, snode.edittree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
@@ -867,6 +876,18 @@ void NODE_OT_add_file(wmOperatorType *ot)
/** \name Add Mask Node Operator
* \{ */
+static ID *node_add_mask_get_and_poll_mask(Main *bmain, wmOperator *op)
+{
+ if (RNA_struct_property_is_set(op->ptr, "session_uuid")) {
+ const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid");
+ return BKE_libblock_find_session_uuid(bmain, ID_MSK, session_uuid);
+ }
+
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "name", name);
+ return BKE_libblock_find_name(bmain, ID_MSK, name);
+}
+
static bool node_add_mask_poll(bContext *C)
{
SpaceNode *snode = CTX_wm_space_node(C);
@@ -877,23 +898,18 @@ static bool node_add_mask_poll(bContext *C)
static int node_add_mask_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
bNode *node;
- ID *mask = nullptr;
- /* check input variables */
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
- mask = BKE_libblock_find_name(bmain, ID_MSK, name);
+ ID *mask = node_add_mask_get_and_poll_mask(bmain, op);
if (!mask) {
- BKE_reportf(op->reports, RPT_ERROR, "Mask '%s' not found", name);
return OPERATOR_CANCELLED;
}
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
node = node_add_node(
- C, nullptr, CMP_NODE_MASK, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ *C, nullptr, CMP_NODE_MASK, snode.runtime->cursor[0], snode.runtime->cursor[1]);
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add a mask node");
@@ -903,8 +919,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
node->id = mask;
id_us_plus(mask);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, bmain, snode.edittree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
@@ -912,6 +927,8 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
void NODE_OT_add_mask(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add Mask Node";
ot->description = "Add a mask node to the current node editor";
@@ -925,6 +942,16 @@ void NODE_OT_add_mask(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
RNA_def_string(ot->srna, "name", "Mask", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the data-block to assign",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
}
/** \} */
@@ -1021,3 +1048,5 @@ void NODE_OT_new_node_tree(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_context_path.cc b/source/blender/editors/space_node/node_context_path.cc
new file mode 100644
index 00000000000..cab7cbf10be
--- /dev/null
+++ b/source/blender/editors/space_node/node_context_path.cc
@@ -0,0 +1,184 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup spnode
+ * \brief Node breadcrumbs drawing
+ */
+
+#include "BLI_vector.hh"
+
+#include "DNA_node_types.h"
+
+#include "BKE_context.h"
+#include "BKE_material.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BKE_screen.h"
+
+#include "RNA_access.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_interface.hh"
+#include "UI_resources.h"
+
+#include "UI_interface.hh"
+
+#include "node_intern.hh"
+
+struct Curve;
+struct Light;
+struct Material;
+struct Mesh;
+struct World;
+
+namespace blender::ed::space_node {
+
+static void context_path_add_object_data(Vector<ui::ContextPathItem> &path, Object &object)
+{
+ if (object.type == OB_MESH && object.data) {
+ Mesh *mesh = (Mesh *)object.data;
+ ui::context_path_add_generic(path, RNA_Mesh, mesh);
+ }
+ if (object.type == OB_LAMP && object.data) {
+ Light *light = (Light *)object.data;
+ ui::context_path_add_generic(path, RNA_Light, light);
+ }
+ if (ELEM(object.type, OB_CURVE, OB_FONT, OB_SURF) && object.data) {
+ Curve *curve = (Curve *)object.data;
+ ui::context_path_add_generic(path, RNA_Curve, curve);
+ }
+}
+
+static void context_path_add_node_tree_and_node_groups(const SpaceNode &snode,
+ Vector<ui::ContextPathItem> &path,
+ const bool skip_base = false)
+{
+ Vector<const bNodeTreePath *> tree_path = snode.treepath;
+ for (const bNodeTreePath *path_item : tree_path.as_span().drop_front(int(skip_base))) {
+ ui::context_path_add_generic(path, RNA_NodeTree, path_item->nodetree, ICON_NODETREE);
+ }
+}
+
+static void get_context_path_node_shader(const bContext &C,
+ SpaceNode &snode,
+ Vector<ui::ContextPathItem> &path)
+{
+ if (snode.flag & SNODE_PIN) {
+ if (snode.shaderfrom == SNODE_SHADER_WORLD) {
+ Scene *scene = CTX_data_scene(&C);
+ ui::context_path_add_generic(path, RNA_Scene, scene);
+ if (scene != nullptr) {
+ World *world = scene->world;
+ ui::context_path_add_generic(path, RNA_World, world);
+ }
+ /* Skip the base node tree here, because the world contains a node tree already. */
+ context_path_add_node_tree_and_node_groups(snode, path, true);
+ }
+ else {
+ context_path_add_node_tree_and_node_groups(snode, path);
+ }
+ }
+ else {
+ Object *object = CTX_data_active_object(&C);
+ if (snode.shaderfrom == SNODE_SHADER_OBJECT && object != nullptr) {
+ ui::context_path_add_generic(path, RNA_Object, object);
+ if (!(object->matbits && object->matbits[object->actcol - 1])) {
+ context_path_add_object_data(path, *object);
+ }
+ Material *material = BKE_object_material_get(object, object->actcol);
+ ui::context_path_add_generic(path, RNA_Material, material);
+ }
+ else if (snode.shaderfrom == SNODE_SHADER_WORLD) {
+ Scene *scene = CTX_data_scene(&C);
+ ui::context_path_add_generic(path, RNA_Scene, scene);
+ if (scene != nullptr) {
+ World *world = scene->world;
+ ui::context_path_add_generic(path, RNA_World, world);
+ }
+ }
+#ifdef WITH_FREESTYLE
+ else if (snode.shaderfrom == SNODE_SHADER_LINESTYLE) {
+ ViewLayer *viewlayer = CTX_data_view_layer(&C);
+ FreestyleLineStyle *linestyle = BKE_linestyle_active_from_view_layer(viewlayer);
+ ui::context_path_add_generic(path, RNA_ViewLayer, viewlayer);
+ Material *mat = BKE_object_material_get(object, object->actcol);
+ ui::context_path_add_generic(path, RNA_Material, mat);
+ }
+#endif
+ context_path_add_node_tree_and_node_groups(snode, path, true);
+ }
+}
+
+static void get_context_path_node_compositor(const bContext &C,
+ SpaceNode &snode,
+ Vector<ui::ContextPathItem> &path)
+{
+ if (snode.flag & SNODE_PIN) {
+ context_path_add_node_tree_and_node_groups(snode, path);
+ }
+ else {
+ Scene *scene = CTX_data_scene(&C);
+ ui::context_path_add_generic(path, RNA_Scene, scene);
+ context_path_add_node_tree_and_node_groups(snode, path);
+ }
+}
+
+static void get_context_path_node_geometry(const bContext &C,
+ SpaceNode &snode,
+ Vector<ui::ContextPathItem> &path)
+{
+ if (snode.flag & SNODE_PIN) {
+ context_path_add_node_tree_and_node_groups(snode, path);
+ }
+ else {
+ Object *object = CTX_data_active_object(&C);
+ ui::context_path_add_generic(path, RNA_Object, object);
+ ModifierData *modifier = BKE_object_active_modifier(object);
+ ui::context_path_add_generic(path, RNA_Modifier, modifier, ICON_MODIFIER);
+ context_path_add_node_tree_and_node_groups(snode, path);
+ }
+}
+
+Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C)
+{
+ SpaceNode *snode = CTX_wm_space_node(&C);
+ if (snode == nullptr) {
+ return {};
+ }
+
+ Vector<ui::ContextPathItem> context_path;
+
+ if (snode->edittree->type == NTREE_GEOMETRY) {
+ get_context_path_node_geometry(C, *snode, context_path);
+ }
+ else if (snode->edittree->type == NTREE_SHADER) {
+ get_context_path_node_shader(C, *snode, context_path);
+ }
+ else if (snode->edittree->type == NTREE_COMPOSIT) {
+ get_context_path_node_compositor(C, *snode, context_path);
+ }
+
+ return context_path;
+}
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 499ccb8a889..82da890fa9b 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -22,21 +22,22 @@
* \brief higher level node drawing for the node editor.
*/
+#include <iomanip>
+
#include "MEM_guardedalloc.h"
#include "DNA_light_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
-#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "DNA_text_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
-#include "BLI_blenlib.h"
+#include "BLI_array.hh"
#include "BLI_map.hh"
-#include "BLI_math.h"
#include "BLI_set.hh"
#include "BLI_span.hh"
#include "BLI_string_ref.hh"
@@ -71,8 +72,10 @@
#include "ED_gpencil.h"
#include "ED_node.h"
+#include "ED_screen.h"
#include "ED_space_api.h"
+#include "UI_interface.hh"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -83,17 +86,8 @@
#include "FN_field_cpp_type.hh"
-#include "node_intern.h" /* own include */
-
-#ifdef WITH_COMPOSITOR
-# include "COM_compositor.h"
-#endif
+#include "node_intern.hh" /* own include */
-using blender::Map;
-using blender::Set;
-using blender::Span;
-using blender::Vector;
-using blender::VectorSet;
using blender::fn::CPPType;
using blender::fn::FieldCPPType;
using blender::fn::FieldInput;
@@ -107,16 +101,18 @@ extern void ui_draw_dropshadow(
const rctf *rct, float radius, float aspect, float alpha, int select);
}
-float ED_node_grid_size(void)
+float ED_node_grid_size()
{
return U.widget_unit;
}
void ED_node_tree_update(const bContext *C)
{
+ using namespace blender::ed::space_node;
+
SpaceNode *snode = CTX_wm_space_node(C);
if (snode) {
- snode_set_context(C);
+ snode_set_context(*C);
id_us_ensure_real(&snode->nodetree->id);
}
@@ -175,34 +171,7 @@ void ED_node_tag_update_id(ID *id)
}
}
-void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree, bNode *node)
-{
- if (!ntree) {
- return;
- }
-
- bool do_tag_update = true;
- if (node != nullptr) {
- if (!node_connected_to_output(bmain, ntree, node)) {
- do_tag_update = false;
- }
- }
-
- /* Look through all datablocks to support groups. */
- if (do_tag_update) {
- FOREACH_NODETREE_BEGIN (bmain, tntree, id) {
- /* Check if nodetree uses the group. */
- if (ntreeHasTree(tntree, ntree)) {
- ED_node_tag_update_id(id);
- }
- }
- FOREACH_NODETREE_END;
- }
-
- if (ntree->type == NTREE_TEXTURE) {
- ntreeTexCheckCyclics(ntree);
- }
-}
+namespace blender::ed::space_node {
static bool compare_nodes(const bNode *a, const bNode *b)
{
@@ -260,18 +229,14 @@ static bool compare_nodes(const bNode *a, const bNode *b)
return false;
}
-/**
- * Sort nodes by selection: unselected nodes first, then selected,
- * then the active node at the very end. Relative order is kept intact.
- */
-void ED_node_sort(bNodeTree *ntree)
+void node_sort(bNodeTree &ntree)
{
/* Merge sort is the algorithm of choice here. */
- int totnodes = BLI_listbase_count(&ntree->nodes);
+ int totnodes = BLI_listbase_count(&ntree.nodes);
int k = 1;
while (k < totnodes) {
- bNode *first_a = (bNode *)ntree->nodes.first;
+ bNode *first_a = (bNode *)ntree.nodes.first;
bNode *first_b = first_a;
do {
@@ -298,8 +263,8 @@ void ED_node_sort(bNodeTree *ntree)
bNode *tmp = node_b;
node_b = node_b->next;
b++;
- BLI_remlink(&ntree->nodes, tmp);
- BLI_insertlinkbefore(&ntree->nodes, node_a, tmp);
+ BLI_remlink(&ntree.nodes, tmp);
+ BLI_insertlinkbefore(&ntree.nodes, node_a, tmp);
}
}
@@ -319,67 +284,72 @@ void ED_node_sort(bNodeTree *ntree)
}
}
-static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
+static Array<uiBlock *> node_uiblocks_init(const bContext &C, Span<bNode *> nodes)
{
+ Array<uiBlock *> blocks(nodes.size());
/* Add node uiBlocks in drawing order - prevents events going to overlapping nodes. */
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- /* ui block */
- char uiblockstr[32];
- BLI_snprintf(uiblockstr, sizeof(uiblockstr), "node buttons %p", (void *)node);
- node->block = UI_block_begin(C, CTX_wm_region(C), uiblockstr, UI_EMBOSS);
-
+ for (const int i : nodes.index_range()) {
+ const std::string block_name = "node_" + std::string(nodes[i]->name);
+ blocks[i] = UI_block_begin(&C, CTX_wm_region(&C), block_name.c_str(), UI_EMBOSS);
/* this cancels events for background nodes */
- UI_block_flag_enable(node->block, UI_BLOCK_CLIP_EVENTS);
+ UI_block_flag_enable(blocks[i], UI_BLOCK_CLIP_EVENTS);
}
+
+ return blocks;
}
-void node_to_view(const bNode *node, float x, float y, float *rx, float *ry)
+float2 node_to_view(const bNode &node, const float2 &co)
{
- nodeToView(node, x, y, rx, ry);
- *rx *= UI_DPI_FAC;
- *ry *= UI_DPI_FAC;
+ float2 result;
+ nodeToView(&node, co.x, co.y, &result.x, &result.y);
+ return result * UI_DPI_FAC;
}
-void node_to_updated_rect(const bNode *node, rctf *r_rect)
+void node_to_updated_rect(const bNode &node, rctf &r_rect)
{
- node_to_view(node, node->offsetx, node->offsety, &r_rect->xmin, &r_rect->ymax);
- node_to_view(node,
- node->offsetx + node->width,
- node->offsety - node->height,
- &r_rect->xmax,
- &r_rect->ymin);
+ const float2 xmin_ymax = node_to_view(node, {node.offsetx, node.offsety});
+ r_rect.xmin = xmin_ymax.x;
+ r_rect.ymax = xmin_ymax.y;
+ const float2 xmax_ymin = node_to_view(node,
+ {node.offsetx + node.width, node.offsety - node.height});
+ r_rect.xmax = xmax_ymin.x;
+ r_rect.ymin = xmax_ymin.y;
}
-void node_from_view(const bNode *node, float x, float y, float *rx, float *ry)
+float2 node_from_view(const bNode &node, const float2 &co)
{
- x /= UI_DPI_FAC;
- y /= UI_DPI_FAC;
- nodeFromView(node, x, y, rx, ry);
+ const float x = co.x / UI_DPI_FAC;
+ const float y = co.y / UI_DPI_FAC;
+ float2 result;
+ nodeFromView(&node, x, y, &result.x, &result.y);
+ return result;
}
/**
* Based on settings and sockets in node, set drawing rect info.
*/
-static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
+static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, uiBlock &block)
{
PointerRNA nodeptr;
- RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
+ RNA_pointer_create(&ntree.id, &RNA_Node, &node, &nodeptr);
+
+ const bool node_options = node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS);
+ const bool inputs_first = node.inputs.first &&
+ !(node.outputs.first || (node.flag & NODE_PREVIEW) || node_options);
/* Get "global" coordinates. */
- float locx, locy;
- node_to_view(node, 0.0f, 0.0f, &locx, &locy);
+ float2 loc = node_to_view(node, float2(0));
/* Round the node origin because text contents are always pixel-aligned. */
- locx = round(locx);
- locy = round(locy);
+ loc.x = round(loc.x);
+ loc.y = round(loc.y);
- int dy = locy;
+ int dy = loc.y;
/* Header. */
dy -= NODE_DY;
- /* Little bit of space in top. */
- if (node->outputs.first) {
+ /* Add a little bit of padding above the top socket. */
+ if (node.outputs.first || inputs_first) {
dy -= NODE_DYS / 2;
}
@@ -387,25 +357,25 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
bool add_output_space = false;
int buty;
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
if (nodeSocketIsHidden(nsock)) {
continue;
}
PointerRNA sockptr;
- RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
+ RNA_pointer_create(&ntree.id, &RNA_NodeSocket, nsock, &sockptr);
- uiLayout *layout = UI_block_layout(node->block,
+ uiLayout *layout = UI_block_layout(&block,
UI_LAYOUT_VERTICAL,
UI_LAYOUT_PANEL,
- locx + NODE_DYS,
+ loc.x + NODE_DYS,
dy,
NODE_WIDTH(node) - NODE_DY,
NODE_DY,
0,
UI_style_get_dpi());
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
uiLayoutSetActive(layout, false);
}
@@ -417,16 +387,16 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
uiLayout *row = uiLayoutRow(layout, true);
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
const char *socket_label = nodeSocketLabel(nsock);
- nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(socket_label));
+ nsock->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
- UI_block_align_end(node->block);
- UI_block_layout_resolve(node->block, nullptr, &buty);
+ UI_block_align_end(&block);
+ UI_block_layout_resolve(&block, nullptr, &buty);
/* Ensure minimum socket height in case layout is empty. */
buty = min_ii(buty, dy - NODE_DY);
/* Round the socket location to stop it from jiggling. */
- nsock->locx = round(locx + NODE_WIDTH(node));
+ nsock->locx = round(loc.x + NODE_WIDTH(node));
nsock->locy = round(0.5f * (dy + buty));
dy = buty;
@@ -441,86 +411,80 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
dy -= NODE_DY / 4;
}
- node->prvr.xmin = locx + NODE_DYS;
- node->prvr.xmax = locx + NODE_WIDTH(node) - NODE_DYS;
+ node.prvr.xmin = loc.x + NODE_DYS;
+ node.prvr.xmax = loc.x + NODE_WIDTH(node) - NODE_DYS;
/* preview rect? */
- if (node->flag & NODE_PREVIEW) {
+ if (node.flag & NODE_PREVIEW) {
float aspect = 1.0f;
- if (node->preview_xsize && node->preview_ysize) {
- aspect = (float)node->preview_ysize / (float)node->preview_xsize;
+ if (node.preview_xsize && node.preview_ysize) {
+ aspect = (float)node.preview_ysize / (float)node.preview_xsize;
}
dy -= NODE_DYS / 2;
- node->prvr.ymax = dy;
+ node.prvr.ymax = dy;
if (aspect <= 1.0f) {
- node->prvr.ymin = dy - aspect * (NODE_WIDTH(node) - NODE_DY);
+ node.prvr.ymin = dy - aspect * (NODE_WIDTH(node) - NODE_DY);
}
else {
/* Width correction of image. XXX huh? (ton) */
float dx = (NODE_WIDTH(node) - NODE_DYS) - (NODE_WIDTH(node) - NODE_DYS) / aspect;
- node->prvr.ymin = dy - (NODE_WIDTH(node) - NODE_DY);
+ node.prvr.ymin = dy - (NODE_WIDTH(node) - NODE_DY);
- node->prvr.xmin += 0.5f * dx;
- node->prvr.xmax -= 0.5f * dx;
+ node.prvr.xmin += 0.5f * dx;
+ node.prvr.xmax -= 0.5f * dx;
}
- dy = node->prvr.ymin - NODE_DYS / 2;
+ dy = node.prvr.ymin - NODE_DYS / 2;
/* Make sure that maximums are bigger or equal to minimums. */
- if (node->prvr.xmax < node->prvr.xmin) {
- SWAP(float, node->prvr.xmax, node->prvr.xmin);
+ if (node.prvr.xmax < node.prvr.xmin) {
+ SWAP(float, node.prvr.xmax, node.prvr.xmin);
}
- if (node->prvr.ymax < node->prvr.ymin) {
- SWAP(float, node->prvr.ymax, node->prvr.ymin);
+ if (node.prvr.ymax < node.prvr.ymin) {
+ SWAP(float, node.prvr.ymax, node.prvr.ymin);
}
}
/* Buttons rect? */
- if (node->typeinfo->draw_buttons && (node->flag & NODE_OPTIONS)) {
+ if (node_options) {
dy -= NODE_DYS / 2;
- /* Set this for `uifunc()` that don't use layout engine yet. */
- node->butr.xmin = 0;
- node->butr.xmax = NODE_WIDTH(node) - 2 * NODE_DYS;
- node->butr.ymin = 0;
- node->butr.ymax = 0;
-
- uiLayout *layout = UI_block_layout(node->block,
+ uiLayout *layout = UI_block_layout(&block,
UI_LAYOUT_VERTICAL,
UI_LAYOUT_PANEL,
- locx + NODE_DYS,
+ loc.x + NODE_DYS,
dy,
- node->butr.xmax,
+ NODE_WIDTH(node) - NODE_DY,
0,
0,
UI_style_get_dpi());
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
uiLayoutSetActive(layout, false);
}
uiLayoutSetContextPointer(layout, "node", &nodeptr);
- node->typeinfo->draw_buttons(layout, (bContext *)C, &nodeptr);
+ node.typeinfo->draw_buttons(layout, (bContext *)&C, &nodeptr);
- UI_block_align_end(node->block);
- UI_block_layout_resolve(node->block, nullptr, &buty);
+ UI_block_align_end(&block);
+ UI_block_layout_resolve(&block, nullptr, &buty);
dy = buty - NODE_DYS / 2;
}
/* Input sockets. */
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
if (nodeSocketIsHidden(nsock)) {
continue;
}
PointerRNA sockptr;
- RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
+ RNA_pointer_create(&ntree.id, &RNA_NodeSocket, nsock, &sockptr);
/* Add the half the height of a multi-input socket to cursor Y
* to account for the increased height of the taller sockets. */
@@ -532,17 +496,17 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
}
dy -= multi_input_socket_offset * 0.5f;
- uiLayout *layout = UI_block_layout(node->block,
+ uiLayout *layout = UI_block_layout(&block,
UI_LAYOUT_VERTICAL,
UI_LAYOUT_PANEL,
- locx + NODE_DYS,
+ loc.x + NODE_DYS,
dy,
NODE_WIDTH(node) - NODE_DY,
NODE_DY,
0,
UI_style_get_dpi());
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
uiLayoutSetActive(layout, false);
}
@@ -553,15 +517,15 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
uiLayout *row = uiLayoutRow(layout, true);
const char *socket_label = nodeSocketLabel(nsock);
- nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(socket_label));
+ nsock->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
- UI_block_align_end(node->block);
- UI_block_layout_resolve(node->block, nullptr, &buty);
+ UI_block_align_end(&block);
+ UI_block_layout_resolve(&block, nullptr, &buty);
/* Ensure minimum socket height in case layout is empty. */
buty = min_ii(buty, dy - NODE_DY);
- nsock->locx = locx;
+ nsock->locx = loc.x;
/* Round the socket vertical position to stop it from jiggling. */
nsock->locy = round(0.5f * (dy + buty));
@@ -572,45 +536,44 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
}
/* Little bit of space in end. */
- if (node->inputs.first || (node->flag & (NODE_OPTIONS | NODE_PREVIEW)) == 0) {
+ if (node.inputs.first || (node.flag & (NODE_OPTIONS | NODE_PREVIEW)) == 0) {
dy -= NODE_DYS / 2;
}
- node->totr.xmin = locx;
- node->totr.xmax = locx + NODE_WIDTH(node);
- node->totr.ymax = locy;
- node->totr.ymin = min_ff(dy, locy - 2 * NODE_DY);
+ node.totr.xmin = loc.x;
+ node.totr.xmax = loc.x + NODE_WIDTH(node);
+ node.totr.ymax = loc.y;
+ node.totr.ymin = min_ff(dy, loc.y - 2 * NODE_DY);
/* Set the block bounds to clip mouse events from underlying nodes.
* Add a margin for sockets on each side. */
- UI_block_bounds_set_explicit(node->block,
- node->totr.xmin - NODE_SOCKSIZE,
- node->totr.ymin,
- node->totr.xmax + NODE_SOCKSIZE,
- node->totr.ymax);
+ UI_block_bounds_set_explicit(&block,
+ node.totr.xmin - NODE_SOCKSIZE,
+ node.totr.ymin,
+ node.totr.xmax + NODE_SOCKSIZE,
+ node.totr.ymax);
}
/**
* Based on settings in node, sets drawing rect info.
*/
-static void node_update_hidden(bNode *node)
+static void node_update_hidden(bNode &node, uiBlock &block)
{
int totin = 0, totout = 0;
- /* Get "global" coords. */
- float locx, locy;
- node_to_view(node, 0.0f, 0.0f, &locx, &locy);
+ /* Get "global" coordinates. */
+ float2 loc = node_to_view(node, float2(0));
/* Round the node origin because text contents are always pixel-aligned. */
- locx = round(locx);
- locy = round(locy);
+ loc.x = round(loc.x);
+ loc.y = round(loc.y);
/* Calculate minimal radius. */
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
if (!nodeSocketIsHidden(nsock)) {
totin++;
}
}
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
if (!nodeSocketIsHidden(nsock)) {
totout++;
}
@@ -622,20 +585,20 @@ static void node_update_hidden(bNode *node)
hiddenrad += 5.0f * (float)(tot - 4);
}
- node->totr.xmin = locx;
- node->totr.xmax = locx + max_ff(NODE_WIDTH(node), 2 * hiddenrad);
- node->totr.ymax = locy + (hiddenrad - 0.5f * NODE_DY);
- node->totr.ymin = node->totr.ymax - 2 * hiddenrad;
+ node.totr.xmin = loc.x;
+ node.totr.xmax = loc.x + max_ff(NODE_WIDTH(node), 2 * hiddenrad);
+ node.totr.ymax = loc.y + (hiddenrad - 0.5f * NODE_DY);
+ node.totr.ymin = node.totr.ymax - 2 * hiddenrad;
/* Output sockets. */
float rad = (float)M_PI / (1.0f + (float)totout);
float drad = rad;
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
if (!nodeSocketIsHidden(nsock)) {
/* Round the socket location to stop it from jiggling. */
- nsock->locx = round(node->totr.xmax - hiddenrad + sinf(rad) * hiddenrad);
- nsock->locy = round(node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
+ nsock->locx = round(node.totr.xmax - hiddenrad + sinf(rad) * hiddenrad);
+ nsock->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
rad += drad;
}
}
@@ -643,51 +606,31 @@ static void node_update_hidden(bNode *node)
/* Input sockets. */
rad = drad = -(float)M_PI / (1.0f + (float)totin);
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
if (!nodeSocketIsHidden(nsock)) {
/* Round the socket location to stop it from jiggling. */
- nsock->locx = round(node->totr.xmin + hiddenrad + sinf(rad) * hiddenrad);
- nsock->locy = round(node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
+ nsock->locx = round(node.totr.xmin + hiddenrad + sinf(rad) * hiddenrad);
+ nsock->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
rad += drad;
}
}
/* Set the block bounds to clip mouse events from underlying nodes.
* Add a margin for sockets on each side. */
- UI_block_bounds_set_explicit(node->block,
- node->totr.xmin - NODE_SOCKSIZE,
- node->totr.ymin,
- node->totr.xmax + NODE_SOCKSIZE,
- node->totr.ymax);
+ UI_block_bounds_set_explicit(&block,
+ node.totr.xmin - NODE_SOCKSIZE,
+ node.totr.ymin,
+ node.totr.xmax + NODE_SOCKSIZE,
+ node.totr.ymax);
}
-void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node)
+static int node_get_colorid(const bNode &node)
{
- if (node->flag & NODE_HIDDEN) {
- node_update_hidden(node);
- }
- else {
- node_update_basis(C, ntree, node);
- }
-}
-
-int node_select_area_default(bNode *node, int x, int y)
-{
- return BLI_rctf_isect_pt(&node->totr, x, y);
-}
-
-int node_tweak_area_default(bNode *node, int x, int y)
-{
- return BLI_rctf_isect_pt(&node->totr, x, y);
-}
-
-int node_get_colorid(bNode *node)
-{
- switch (node->typeinfo->nclass) {
+ switch (node.typeinfo->nclass) {
case NODE_CLASS_INPUT:
return TH_NODE_INPUT;
case NODE_CLASS_OUTPUT:
- return (node->flag & NODE_DO_OUTPUT) ? TH_NODE_OUTPUT : TH_NODE;
+ return (node.flag & NODE_DO_OUTPUT) ? TH_NODE_OUTPUT : TH_NODE;
case NODE_CLASS_CONVERTER:
return TH_NODE_CONVERTER;
case NODE_CLASS_OP_COLOR:
@@ -723,18 +666,21 @@ int node_get_colorid(bNode *node)
}
}
-static void node_draw_mute_line(const View2D *v2d, const SpaceNode *snode, const bNode *node)
+static void node_draw_mute_line(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNode &node)
{
GPU_blend(GPU_BLEND_ALPHA);
- LISTBASE_FOREACH (const bNodeLink *, link, &node->internal_links) {
- node_draw_link_bezier(v2d, snode, link, TH_REDALERT, TH_REDALERT, -1);
+ LISTBASE_FOREACH (const bNodeLink *, link, &node.internal_links) {
+ node_draw_link_bezier(C, v2d, snode, *link, TH_WIRE_INNER, TH_WIRE_INNER, TH_WIRE);
}
GPU_blend(GPU_BLEND_NONE);
}
-static void node_socket_draw(const bNodeSocket *sock,
+static void node_socket_draw(const bNodeSocket &sock,
const float color[4],
const float color_outline[4],
float size,
@@ -749,7 +695,7 @@ static void node_socket_draw(const bNodeSocket *sock,
int flags;
/* Set shape flags. */
- switch (sock->display_shape) {
+ switch (sock.display_shape) {
case SOCK_DISPLAY_SHAPE_DIAMOND:
case SOCK_DISPLAY_SHAPE_DIAMOND_DOT:
flags = GPU_KEYFRAME_SHAPE_DIAMOND;
@@ -765,7 +711,7 @@ static void node_socket_draw(const bNodeSocket *sock,
break;
}
- if (ELEM(sock->display_shape,
+ if (ELEM(sock.display_shape,
SOCK_DISPLAY_SHAPE_DIAMOND_DOT,
SOCK_DISPLAY_SHAPE_SQUARE_DOT,
SOCK_DISPLAY_SHAPE_CIRCLE_DOT)) {
@@ -807,12 +753,10 @@ static void node_socket_outline_color_get(const bool selected,
float r_outline_color[4])
{
if (selected) {
- UI_GetThemeColor4fv(TH_TEXT_HI, r_outline_color);
- r_outline_color[3] = 0.9f;
+ UI_GetThemeColor4fv(TH_ACTIVE, r_outline_color);
}
else {
- copy_v4_fl(r_outline_color, 0.0f);
- r_outline_color[3] = 0.6f;
+ UI_GetThemeColor4fv(TH_WIRE, r_outline_color);
}
/* Until there is a better place for per socket color,
@@ -822,21 +766,17 @@ static void node_socket_outline_color_get(const bool selected,
}
}
-/* Usual convention here would be node_socket_get_color(), but that's already used (for setting a
- * color property socket). */
-void node_socket_color_get(
- bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, bNodeSocket *sock, float r_color[4])
+void node_socket_color_get(const bContext &C,
+ const bNodeTree &ntree,
+ PointerRNA &node_ptr,
+ const bNodeSocket &sock,
+ float r_color[4])
{
PointerRNA ptr;
- BLI_assert(RNA_struct_is_a(node_ptr->type, &RNA_Node));
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
-
- sock->typeinfo->draw_color(C, &ptr, node_ptr, r_color);
+ BLI_assert(RNA_struct_is_a(node_ptr.type, &RNA_Node));
+ RNA_pointer_create((ID *)&ntree, &RNA_NodeSocket, &const_cast<bNodeSocket &>(sock), &ptr);
- bNode *node = (bNode *)node_ptr->data;
- if (node->flag & NODE_MUTED) {
- r_color[3] *= 0.25f;
- }
+ sock.typeinfo->draw_color((bContext *)&C, &ptr, &node_ptr, r_color);
}
struct SocketTooltipData {
@@ -845,79 +785,94 @@ struct SocketTooltipData {
bNodeSocket *socket;
};
-static void create_inspection_string_for_generic_value(const geo_log::GenericValueLog &value_log,
- std::stringstream &ss)
+static void create_inspection_string_for_generic_value(const GPointer value, std::stringstream &ss)
{
auto id_to_inspection_string = [&](ID *id, short idcode) {
ss << (id ? id->name + 2 : TIP_("None")) << " (" << BKE_idtype_idcode_to_name(idcode) << ")";
};
- const GPointer value = value_log.value();
const CPPType &type = *value.type();
- if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) {
- const CPPType &base_type = field_type->field_type();
- BUFFER_FOR_CPP_TYPE_VALUE(base_type, buffer);
- const GField &field = field_type->get_gfield(value.get());
- if (field.node().depends_on_input()) {
- if (base_type.is<int>()) {
- ss << TIP_("Integer Field");
- }
- else if (base_type.is<float>()) {
- ss << TIP_("Float Field");
- }
- else if (base_type.is<blender::float3>()) {
- ss << TIP_("Vector Field");
- }
- else if (base_type.is<bool>()) {
- ss << TIP_("Boolean Field");
- }
- else if (base_type.is<std::string>()) {
- ss << TIP_("String Field");
- }
- ss << TIP_(" based on:\n");
-
- /* Use vector set to deduplicate inputs. */
- VectorSet<std::reference_wrapper<const FieldInput>> field_inputs;
- field.node().foreach_field_input(
- [&](const FieldInput &field_input) { field_inputs.add(field_input); });
- for (const FieldInput &field_input : field_inputs) {
- ss << "\u2022 " << field_input.socket_inspection_name();
- if (field_input != field_inputs.as_span().last().get()) {
- ss << ".\n";
- }
- }
- }
- else {
- blender::fn::evaluate_constant_field(field, buffer);
- if (base_type.is<int>()) {
- ss << *(int *)buffer << TIP_(" (Integer)");
- }
- else if (base_type.is<float>()) {
- ss << *(float *)buffer << TIP_(" (Float)");
- }
- else if (base_type.is<blender::float3>()) {
- ss << *(blender::float3 *)buffer << TIP_(" (Vector)");
- }
- else if (base_type.is<bool>()) {
- ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
- }
- else if (base_type.is<std::string>()) {
- ss << *(std::string *)buffer << TIP_(" (String)");
- }
- base_type.destruct(buffer);
- }
- }
- else if (type.is<Object *>()) {
- id_to_inspection_string((ID *)*value.get<Object *>(), ID_OB);
+ const void *buffer = value.get();
+ if (type.is<Object *>()) {
+ id_to_inspection_string((ID *)buffer, ID_OB);
}
else if (type.is<Material *>()) {
- id_to_inspection_string((ID *)*value.get<Material *>(), ID_MA);
+ id_to_inspection_string((ID *)buffer, ID_MA);
}
else if (type.is<Tex *>()) {
- id_to_inspection_string((ID *)*value.get<Tex *>(), ID_TE);
+ id_to_inspection_string((ID *)buffer, ID_TE);
+ }
+ else if (type.is<Image *>()) {
+ id_to_inspection_string((ID *)buffer, ID_IM);
}
else if (type.is<Collection *>()) {
- id_to_inspection_string((ID *)*value.get<Collection *>(), ID_GR);
+ id_to_inspection_string((ID *)buffer, ID_GR);
+ }
+ else if (type.is<int>()) {
+ ss << *(int *)buffer << TIP_(" (Integer)");
+ }
+ else if (type.is<float>()) {
+ ss << *(float *)buffer << TIP_(" (Float)");
+ }
+ else if (type.is<blender::float3>()) {
+ ss << *(blender::float3 *)buffer << TIP_(" (Vector)");
+ }
+ else if (type.is<bool>()) {
+ ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
+ }
+ else if (type.is<std::string>()) {
+ ss << *(std::string *)buffer << TIP_(" (String)");
+ }
+}
+
+static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &value_log,
+ std::stringstream &ss)
+{
+ const CPPType &type = value_log.type();
+ const GField &field = value_log.field();
+ const Span<std::string> input_tooltips = value_log.input_tooltips();
+
+ if (input_tooltips.is_empty()) {
+ if (field) {
+ BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
+ blender::fn::evaluate_constant_field(field, buffer);
+ create_inspection_string_for_generic_value({type, buffer}, ss);
+ type.destruct(buffer);
+ }
+ else {
+ /* Constant values should always be logged. */
+ BLI_assert_unreachable();
+ ss << "Value has not been logged";
+ }
+ }
+ else {
+ if (type.is<int>()) {
+ ss << TIP_("Integer field");
+ }
+ else if (type.is<float>()) {
+ ss << TIP_("Float field");
+ }
+ else if (type.is<blender::float3>()) {
+ ss << TIP_("Vector field");
+ }
+ else if (type.is<bool>()) {
+ ss << TIP_("Boolean field");
+ }
+ else if (type.is<std::string>()) {
+ ss << TIP_("String field");
+ }
+ else if (type.is<blender::ColorGeometry4f>()) {
+ ss << TIP_("Color field");
+ }
+ ss << TIP_(" based on:\n");
+
+ for (const int i : input_tooltips.index_range()) {
+ const blender::StringRef tooltip = input_tooltips[i];
+ ss << "\u2022 " << tooltip;
+ if (i < input_tooltips.size() - 1) {
+ ss << ".\n";
+ }
+ }
}
}
@@ -992,7 +947,6 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo
}
static std::optional<std::string> create_socket_inspection_string(bContext *C,
- bNodeTree &UNUSED(ntree),
bNode &node,
bNodeSocket &socket)
{
@@ -1010,7 +964,11 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C,
std::stringstream ss;
if (const geo_log::GenericValueLog *generic_value_log =
dynamic_cast<const geo_log::GenericValueLog *>(value_log)) {
- create_inspection_string_for_generic_value(*generic_value_log, ss);
+ create_inspection_string_for_generic_value(generic_value_log->value(), ss);
+ }
+ if (const geo_log::GFieldValueLog *gfield_value_log =
+ dynamic_cast<const geo_log::GFieldValueLog *>(value_log)) {
+ create_inspection_string_for_gfield(*gfield_value_log, ss);
}
else if (const geo_log::GeometryValueLog *geo_value_log =
dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) {
@@ -1020,54 +978,52 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C,
return ss.str();
}
-static void node_socket_draw_nested(const bContext *C,
- bNodeTree *ntree,
- PointerRNA *node_ptr,
- bNodeSocket *sock,
- uint pos_id,
- uint col_id,
- uint shape_id,
- uint size_id,
- uint outline_col_id,
- float size,
- bool selected)
+static void node_socket_draw_nested(const bContext &C,
+ bNodeTree &ntree,
+ PointerRNA &node_ptr,
+ uiBlock &block,
+ bNodeSocket &sock,
+ const uint pos_id,
+ const uint col_id,
+ const uint shape_id,
+ const uint size_id,
+ const uint outline_col_id,
+ const float size,
+ const bool selected)
{
float color[4];
float outline_color[4];
- node_socket_color_get((bContext *)C, ntree, node_ptr, sock, color);
- node_socket_outline_color_get(selected, sock->type, outline_color);
+ node_socket_color_get(C, ntree, node_ptr, sock, color);
+ node_socket_outline_color_get(selected, sock.type, outline_color);
node_socket_draw(sock,
color,
outline_color,
size,
- sock->locx,
- sock->locy,
+ sock.locx,
+ sock.locy,
pos_id,
col_id,
shape_id,
size_id,
outline_col_id);
- if (ntree->type != NTREE_GEOMETRY) {
+ if (ntree.type != NTREE_GEOMETRY) {
/* Only geometry nodes has socket value tooltips currently. */
return;
}
- bNode *node = (bNode *)node_ptr->data;
- uiBlock *block = node->block;
-
/* Ideally sockets themselves should be buttons, but they aren't currently. So add an invisible
* button on top of them for the tooltip. */
- const eUIEmbossType old_emboss = UI_block_emboss_get(block);
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(block,
+ const eUIEmbossType old_emboss = UI_block_emboss_get(&block);
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT,
0,
ICON_NONE,
- sock->locx - size / 2,
- sock->locy - size / 2,
+ sock.locx - size / 2,
+ sock.locy - size / 2,
size,
size,
nullptr,
@@ -1078,60 +1034,46 @@ static void node_socket_draw_nested(const bContext *C,
nullptr);
SocketTooltipData *data = (SocketTooltipData *)MEM_mallocN(sizeof(SocketTooltipData), __func__);
- data->ntree = ntree;
- data->node = (bNode *)node_ptr->data;
- data->socket = sock;
+ data->ntree = &ntree;
+ data->node = (bNode *)node_ptr.data;
+ data->socket = &sock;
UI_but_func_tooltip_set(
but,
[](bContext *C, void *argN, const char *UNUSED(tip)) {
SocketTooltipData *data = (SocketTooltipData *)argN;
std::optional<std::string> socket_inspection_str = create_socket_inspection_string(
- C, *data->ntree, *data->node, *data->socket);
+ C, *data->node, *data->socket);
std::stringstream output;
- if (data->node->declaration != nullptr) {
- ListBase *list;
- Span<blender::nodes::SocketDeclarationPtr> decl_list;
-
- if (data->socket->in_out == SOCK_IN) {
- list = &data->node->inputs;
- decl_list = data->node->declaration->inputs();
- }
- else {
- list = &data->node->outputs;
- decl_list = data->node->declaration->outputs();
- }
-
- const int socket_index = BLI_findindex(list, data->socket);
- const blender::nodes::SocketDeclaration &socket_decl = *decl_list[socket_index];
+ if (data->socket->declaration != nullptr) {
+ const blender::nodes::SocketDeclaration &socket_decl = *data->socket->declaration;
blender::StringRef description = socket_decl.description();
if (!description.is_empty()) {
output << TIP_(description.data()) << ".\n\n";
}
-
- if (socket_inspection_str.has_value()) {
- output << *socket_inspection_str;
- return BLI_strdup(output.str().c_str());
- }
}
- output << TIP_("The socket value has not been computed yet");
+ if (socket_inspection_str.has_value()) {
+ output << *socket_inspection_str;
+ }
+ else {
+ output << TIP_("The socket value has not been computed yet");
+ }
return BLI_strdup(output.str().c_str());
},
data,
MEM_freeN);
/* Disable the button so that clicks on it are ignored the the link operator still works. */
UI_but_flag_enable(but, UI_BUT_DISABLED);
- UI_block_emboss_set(block, old_emboss);
+ UI_block_emboss_set(&block, old_emboss);
}
-/**
- * Draw a single node socket at default size.
- * \note this is only called from external code, internally #node_socket_draw_nested() is used for
- * optimized drawing of multiple/all sockets of a node.
- */
+} // namespace blender::ed::space_node
+
void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale)
{
+ using namespace blender::ed::space_node;
+
const float size = 2.25f * NODE_SOCKSIZE * scale;
rcti draw_rect = *rect;
float outline_color[4] = {0};
@@ -1153,12 +1095,12 @@ void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[
GPU_program_point_size(true);
immBindBuiltinProgram(GPU_SHADER_KEYFRAME_SHAPE);
- immUniform1f("outline_scale", 0.7f);
+ immUniform1f("outline_scale", 1.0f);
immUniform2f("ViewportSize", -1.0f, -1.0f);
/* Single point. */
immBegin(GPU_PRIM_POINTS, 1);
- node_socket_draw(sock,
+ node_socket_draw(*sock,
color,
outline_color,
BLI_rcti_size_y(&draw_rect),
@@ -1178,6 +1120,8 @@ void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[
GPU_blend(state);
}
+namespace blender::ed::space_node {
+
/* ************** Socket callbacks *********** */
static void node_draw_preview_background(rctf *rect)
@@ -1228,17 +1172,17 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv)
GPU_blend(GPU_BLEND_ALPHA);
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(&state,
- draw_rect.xmin,
- draw_rect.ymin,
- preview->xsize,
- preview->ysize,
- GPU_RGBA8,
- true,
- preview->rect,
- scale,
- scale,
- nullptr);
+ immDrawPixelsTexTiled(&state,
+ draw_rect.xmin,
+ draw_rect.ymin,
+ preview->xsize,
+ preview->ysize,
+ GPU_RGBA8,
+ true,
+ preview->rect,
+ scale,
+ scale,
+ nullptr);
GPU_blend(GPU_BLEND_NONE);
@@ -1256,34 +1200,38 @@ static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_
const char *opname = (const char *)op_argv;
/* Select & activate only the button's node. */
- node_select_single(C, node);
+ node_select_single(*C, *node);
WM_operator_name_call(C, opname, WM_OP_INVOKE_DEFAULT, nullptr);
}
-void node_draw_shadow(const SpaceNode *snode, const bNode *node, float radius, float alpha)
+static void node_draw_shadow(const SpaceNode &snode,
+ const bNode &node,
+ const float radius,
+ const float alpha)
{
- const rctf *rct = &node->totr;
+ const rctf &rct = node.totr;
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- ui_draw_dropshadow(rct, radius, snode->runtime->aspect, alpha, node->flag & SELECT);
+ ui_draw_dropshadow(&rct, radius, snode.runtime->aspect, alpha, node.flag & SELECT);
}
-void node_draw_sockets(const View2D *v2d,
- const bContext *C,
- bNodeTree *ntree,
- bNode *node,
- bool draw_outputs,
- bool select_all)
+static void node_draw_sockets(const View2D &v2d,
+ const bContext &C,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block,
+ const bool draw_outputs,
+ const bool select_all)
{
- const uint total_input_len = BLI_listbase_count(&node->inputs);
- const uint total_output_len = BLI_listbase_count(&node->outputs);
+ const uint total_input_len = BLI_listbase_count(&node.inputs);
+ const uint total_output_len = BLI_listbase_count(&node.outputs);
if (total_input_len + total_output_len == 0) {
return;
}
PointerRNA node_ptr;
- RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
+ RNA_pointer_create((ID *)&ntree, &RNA_Node, &node, &node_ptr);
bool selected = false;
@@ -1298,12 +1246,12 @@ void node_draw_sockets(const View2D *v2d,
GPU_blend(GPU_BLEND_ALPHA);
GPU_program_point_size(true);
immBindBuiltinProgram(GPU_SHADER_KEYFRAME_SHAPE);
- immUniform1f("outline_scale", 0.7f);
+ immUniform1f("outline_scale", 1.0f);
immUniform2f("ViewportSize", -1.0f, -1.0f);
/* Set handle size. */
float scale;
- UI_view2d_scale_get(v2d, &scale, nullptr);
+ UI_view2d_scale_get(&v2d, &scale, nullptr);
scale *= 2.25f * NODE_SOCKSIZE;
if (!select_all) {
@@ -1312,7 +1260,7 @@ void node_draw_sockets(const View2D *v2d,
/* Socket inputs. */
short selected_input_len = 0;
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node.inputs) {
if (nodeSocketIsHidden(sock)) {
continue;
}
@@ -1327,8 +1275,9 @@ void node_draw_sockets(const View2D *v2d,
node_socket_draw_nested(C,
ntree,
- &node_ptr,
- sock,
+ node_ptr,
+ block,
+ *sock,
pos_id,
col_id,
shape_id,
@@ -1341,7 +1290,7 @@ void node_draw_sockets(const View2D *v2d,
/* Socket outputs. */
short selected_output_len = 0;
if (draw_outputs) {
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node.outputs) {
if (nodeSocketIsHidden(sock)) {
continue;
}
@@ -1352,8 +1301,9 @@ void node_draw_sockets(const View2D *v2d,
node_socket_draw_nested(C,
ntree,
- &node_ptr,
- sock,
+ node_ptr,
+ block,
+ *sock,
pos_id,
col_id,
shape_id,
@@ -1378,15 +1328,16 @@ void node_draw_sockets(const View2D *v2d,
if (selected_input_len) {
/* Socket inputs. */
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node.inputs) {
if (nodeSocketIsHidden(sock)) {
continue;
}
if (select_all || (sock->flag & SELECT)) {
node_socket_draw_nested(C,
ntree,
- &node_ptr,
- sock,
+ node_ptr,
+ block,
+ *sock,
pos_id,
col_id,
shape_id,
@@ -1403,15 +1354,16 @@ void node_draw_sockets(const View2D *v2d,
if (selected_output_len) {
/* Socket outputs. */
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node.outputs) {
if (nodeSocketIsHidden(sock)) {
continue;
}
if (select_all || (sock->flag & SELECT)) {
node_socket_draw_nested(C,
ntree,
- &node_ptr,
- sock,
+ node_ptr,
+ block,
+ *sock,
pos_id,
col_id,
shape_id,
@@ -1436,7 +1388,7 @@ void node_draw_sockets(const View2D *v2d,
/* Draw multi-input sockets after the others because they are drawn with `UI_draw_roundbox`
* rather than with `GL_POINT`. */
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
if (nodeSocketIsHidden(socket)) {
continue;
}
@@ -1444,13 +1396,13 @@ void node_draw_sockets(const View2D *v2d,
continue;
}
- const bool is_node_hidden = (node->flag & NODE_HIDDEN);
+ const bool is_node_hidden = (node.flag & NODE_HIDDEN);
const float width = NODE_SOCKSIZE;
- float height = is_node_hidden ? width : node_socket_calculate_height(socket) - width;
+ float height = is_node_hidden ? width : node_socket_calculate_height(*socket) - width;
float color[4];
float outline_color[4];
- node_socket_color_get((bContext *)C, ntree, &node_ptr, socket, color);
+ node_socket_color_get(C, ntree, node_ptr, *socket, color);
node_socket_outline_color_get(selected, socket->type, outline_color);
node_socket_draw_multi_input(color, outline_color, width, height, socket->locx, socket->locy);
@@ -1532,9 +1484,9 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char
#define NODE_HEADER_ICON_SIZE (0.8f * U.widget_unit)
static void node_add_error_message_button(
- const bContext *C, bNodeTree &UNUSED(ntree), bNode &node, const rctf &rect, float &icon_offset)
+ const bContext &C, bNode &node, uiBlock &block, const rctf &rect, float &icon_offset)
{
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(*snode,
node);
if (node_log == nullptr) {
@@ -1554,8 +1506,8 @@ static void node_add_error_message_button(
const geo_log::NodeWarningType display_type = node_error_highest_priority(warnings);
icon_offset -= NODE_HEADER_ICON_SIZE;
- UI_block_emboss_set(node.block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(node.block,
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT,
0,
node_error_type_to_icon(display_type),
@@ -1570,69 +1522,311 @@ static void node_add_error_message_button(
0,
nullptr);
UI_but_func_tooltip_set(but, node_errors_tooltip_fn, tooltip_data, MEM_freeN);
- UI_block_emboss_set(node.block, UI_EMBOSS);
+ UI_block_emboss_set(&block, UI_EMBOSS);
+}
+
+static void get_exec_time_other_nodes(const bNode &node,
+ const SpaceNode &snode,
+ std::chrono::microseconds &exec_time,
+ int &node_count)
+{
+ if (node.type == NODE_GROUP) {
+ const geo_log::TreeLog *root_tree_log = geo_log::ModifierLog::find_tree_by_node_editor_context(
+ snode);
+ if (root_tree_log == nullptr) {
+ return;
+ }
+ const geo_log::TreeLog *tree_log = root_tree_log->lookup_child_log(node.name);
+ if (tree_log == nullptr) {
+ return;
+ }
+ tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) {
+ exec_time += node_log.execution_time();
+ node_count++;
+ });
+ }
+ else {
+ const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(
+ snode, node);
+ if (node_log) {
+ exec_time += node_log->execution_time();
+ node_count++;
+ }
+ }
+}
+
+static std::chrono::microseconds node_get_execution_time(const bNodeTree &ntree,
+ const bNode &node,
+ const SpaceNode &snode,
+ int &node_count)
+{
+ std::chrono::microseconds exec_time = std::chrono::microseconds::zero();
+ if (node.type == NODE_GROUP_OUTPUT) {
+ const geo_log::TreeLog *tree_log = geo_log::ModifierLog::find_tree_by_node_editor_context(
+ snode);
+
+ if (tree_log == nullptr) {
+ return exec_time;
+ }
+ tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) {
+ exec_time += node_log.execution_time();
+ node_count++;
+ });
+ }
+ else if (node.type == NODE_FRAME) {
+ /* Could be cached in the future if this recursive code turns out to be slow. */
+ LISTBASE_FOREACH (bNode *, tnode, &ntree.nodes) {
+ if (tnode->parent != &node) {
+ continue;
+ }
+
+ if (tnode->type == NODE_FRAME) {
+ exec_time += node_get_execution_time(ntree, *tnode, snode, node_count);
+ }
+ else {
+ get_exec_time_other_nodes(*tnode, snode, exec_time, node_count);
+ }
+ }
+ }
+ else {
+ get_exec_time_other_nodes(node, snode, exec_time, node_count);
+ }
+ return exec_time;
+}
+
+static std::string node_get_execution_time_label(const SpaceNode &snode, const bNode &node)
+{
+ int node_count = 0;
+ std::chrono::microseconds exec_time = node_get_execution_time(
+ *snode.nodetree, node, snode, node_count);
+
+ if (node_count == 0) {
+ return std::string("");
+ }
+
+ uint64_t exec_time_us = exec_time.count();
+
+ /* Don't show time if execution time is 0 microseconds. */
+ if (exec_time_us == 0) {
+ return std::string("-");
+ }
+ if (exec_time_us < 100) {
+ return std::string("< 0.1 ms");
+ }
+
+ int precision = 0;
+ /* Show decimal if value is below 1ms */
+ if (exec_time_us < 1000) {
+ precision = 2;
+ }
+ else if (exec_time_us < 10000) {
+ precision = 1;
+ }
+
+ std::stringstream stream;
+ stream << std::fixed << std::setprecision(precision) << (exec_time_us / 1000.0f);
+ return stream.str() + " ms";
+}
+
+struct NodeExtraInfoRow {
+ std::string text;
+ const char *tooltip;
+ int icon;
+};
+
+static Vector<NodeExtraInfoRow> node_get_extra_info(const SpaceNode &snode, const bNode &node)
+{
+ Vector<NodeExtraInfoRow> rows;
+ if (!(snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS)) {
+ return rows;
+ }
+
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_TIMINGS && snode.edittree->type == NTREE_GEOMETRY &&
+ (ELEM(node.typeinfo->nclass, NODE_CLASS_GEOMETRY, NODE_CLASS_GROUP, NODE_CLASS_ATTRIBUTE) ||
+ ELEM(node.type, NODE_FRAME, NODE_GROUP_OUTPUT))) {
+ NodeExtraInfoRow row;
+ row.text = node_get_execution_time_label(snode, node);
+ if (!row.text.empty()) {
+ row.tooltip = TIP_(
+ "The execution time from the node tree's latest evaluation. For frame and group nodes, "
+ "the time for all sub-nodes");
+ row.icon = ICON_PREVIEW_RANGE;
+ rows.append(std::move(row));
+ }
+ }
+ const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(snode,
+ node);
+ if (node_log != nullptr) {
+ for (const std::string &message : node_log->debug_messages()) {
+ NodeExtraInfoRow row;
+ row.text = message;
+ row.icon = ICON_INFO;
+ rows.append(std::move(row));
+ }
+ }
+ return rows;
+}
+
+static void node_draw_extra_info_row(const bNode &node,
+ uiBlock &block,
+ const rctf &rect,
+ const int row,
+ const NodeExtraInfoRow &extra_info_row)
+{
+ uiBut *but_timing = uiDefBut(&block,
+ UI_BTYPE_LABEL,
+ 0,
+ extra_info_row.text.c_str(),
+ (int)(rect.xmin + 4.0f * U.dpi_fac + NODE_MARGIN_X + 0.4f),
+ (int)(rect.ymin + row * (20.0f * U.dpi_fac)),
+ (short)(rect.xmax - rect.xmin),
+ (short)NODE_DY,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but_icon = uiDefIconBut(&block,
+ UI_BTYPE_BUT,
+ 0,
+ extra_info_row.icon,
+ (int)(rect.xmin + 6.0f * U.dpi_fac),
+ (int)(rect.ymin + row * (20.0f * U.dpi_fac)),
+ NODE_HEADER_ICON_SIZE * 0.8f,
+ UI_UNIT_Y,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ extra_info_row.tooltip);
+ UI_block_emboss_set(&block, UI_EMBOSS);
+ if (node.flag & NODE_MUTED) {
+ UI_but_flag_enable(but_timing, UI_BUT_INACTIVE);
+ UI_but_flag_enable(but_icon, UI_BUT_INACTIVE);
+ }
+}
+
+static void node_draw_extra_info_panel(const SpaceNode &snode, const bNode &node, uiBlock &block)
+{
+ Vector<NodeExtraInfoRow> extra_info_rows = node_get_extra_info(snode, node);
+
+ if (extra_info_rows.size() == 0) {
+ return;
+ }
+
+ const rctf &rct = node.totr;
+ float color[4];
+ rctf extra_info_rect;
+
+ if (node.type == NODE_FRAME) {
+ extra_info_rect.xmin = rct.xmin;
+ extra_info_rect.xmax = rct.xmin + 95.0f * U.dpi_fac;
+ extra_info_rect.ymin = rct.ymin + 2.0f * U.dpi_fac;
+ extra_info_rect.ymax = rct.ymin + 2.0f * U.dpi_fac;
+ }
+ else {
+ extra_info_rect.xmin = rct.xmin + 3.0f * U.dpi_fac;
+ extra_info_rect.xmax = rct.xmin + 95.0f * U.dpi_fac;
+ extra_info_rect.ymin = rct.ymax;
+ extra_info_rect.ymax = rct.ymax + extra_info_rows.size() * (20.0f * U.dpi_fac);
+
+ if (node.flag & NODE_MUTED) {
+ UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.2f, color);
+ }
+ else {
+ UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.75f, color);
+ }
+ color[3] -= 0.35f;
+ UI_draw_roundbox_corner_set(
+ UI_CNR_ALL & ~UI_CNR_BOTTOM_LEFT &
+ ((rct.xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL));
+ UI_draw_roundbox_4fv(&extra_info_rect, true, BASIS_RAD, color);
+
+ /* Draw outline. */
+ const float outline_width = 1.0f;
+ extra_info_rect.xmin = rct.xmin + 3.0f * U.dpi_fac - outline_width;
+ extra_info_rect.xmax = rct.xmin + 95.0f * U.dpi_fac + outline_width;
+ extra_info_rect.ymin = rct.ymax - outline_width;
+ extra_info_rect.ymax = rct.ymax + outline_width + extra_info_rows.size() * (20.0f * U.dpi_fac);
+
+ UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color);
+ UI_draw_roundbox_corner_set(
+ UI_CNR_ALL & ~UI_CNR_BOTTOM_LEFT &
+ ((rct.xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL));
+ UI_draw_roundbox_4fv(&extra_info_rect, false, BASIS_RAD, color);
+ }
+
+ for (int row : extra_info_rows.index_range()) {
+ node_draw_extra_info_row(node, block, extra_info_rect, row, extra_info_rows[row]);
+ }
}
-static void node_draw_basis(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
+static void node_draw_basis(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block,
bNodeInstanceKey key)
{
const float iconbutw = NODE_HEADER_ICON_SIZE;
/* Skip if out of view. */
- if (BLI_rctf_isect(&node->totr, &v2d->cur, nullptr) == false) {
- UI_block_end(C, node->block);
- node->block = nullptr;
+ if (BLI_rctf_isect(&node.totr, &v2d.cur, nullptr) == false) {
+ UI_block_end(&C, &block);
return;
}
/* Shadow. */
node_draw_shadow(snode, node, BASIS_RAD, 1.0f);
+ const rctf &rct = node.totr;
float color[4];
int color_id = node_get_colorid(node);
- if (node->flag & NODE_MUTED) {
- /* Muted nodes are semi-transparent and colorless. */
- UI_GetThemeColor3fv(TH_NODE, color);
- color[3] = 0.25f;
- }
- else {
- /* Opaque headers for regular nodes. */
- UI_GetThemeColor3fv(color_id, color);
- color[3] = 1.0f;
- }
GPU_line_width(1.0f);
- rctf *rct = &node->totr;
- UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
+ node_draw_extra_info_panel(snode, node, block);
+ /* Header. */
{
const rctf rect = {
- rct->xmin,
- rct->xmax,
- rct->ymax - NODE_DY,
- rct->ymax,
+ rct.xmin,
+ rct.xmax,
+ rct.ymax - NODE_DY,
+ rct.ymax,
};
- UI_draw_roundbox_aa(&rect, true, BASIS_RAD, color);
+
+ float color_header[4];
+
+ /* Muted nodes get a mix of the background with the node color. */
+ if (node.flag & NODE_MUTED) {
+ UI_GetThemeColorBlend4f(TH_BACK, color_id, 0.1f, color_header);
+ }
+ else {
+ UI_GetThemeColorBlend4f(TH_NODE, color_id, 0.4f, color_header);
+ }
+
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
+ UI_draw_roundbox_4fv(&rect, true, BASIS_RAD, color_header);
}
/* Show/hide icons. */
- float iconofs = rct->xmax - 0.35f * U.widget_unit;
+ float iconofs = rct.xmax - 0.35f * U.widget_unit;
/* Preview. */
- if (node->typeinfo->flag & NODE_PREVIEW) {
+ if (node.typeinfo->flag & NODE_PREVIEW) {
iconofs -= iconbutw;
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(node->block,
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT_TOGGLE,
0,
ICON_MATERIAL,
iconofs,
- rct->ymax - NODE_DY,
+ rct.ymax - NODE_DY,
iconbutw,
UI_UNIT_Y,
nullptr,
@@ -1641,24 +1835,24 @@ static void node_draw_basis(const bContext *C,
0,
0,
"");
- UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_preview_toggle");
+ UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_preview_toggle");
/* XXX this does not work when node is activated and the operator called right afterwards,
* since active ID is not updated yet (needs to process the notifier).
* This can only work as visual indicator! */
- // if (!(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)))
+ // if (!(node.flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)))
// UI_but_flag_enable(but, UI_BUT_DISABLED);
- UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
/* Group edit. */
- if (node->type == NODE_GROUP) {
+ if (node.type == NODE_GROUP) {
iconofs -= iconbutw;
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(node->block,
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT_TOGGLE,
0,
ICON_NODETREE,
iconofs,
- rct->ymax - NODE_DY,
+ rct.ymax - NODE_DY,
iconbutw,
UI_UNIT_Y,
nullptr,
@@ -1667,18 +1861,18 @@ static void node_draw_basis(const bContext *C,
0,
0,
"");
- UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_group_edit");
- UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_group_edit");
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
- if (node->type == NODE_CUSTOM && node->typeinfo->ui_icon != ICON_NONE) {
+ if (node.type == NODE_CUSTOM && node.typeinfo->ui_icon != ICON_NONE) {
iconofs -= iconbutw;
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
- uiDefIconBut(node->block,
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiDefIconBut(&block,
UI_BTYPE_BUT,
0,
- node->typeinfo->ui_icon,
+ node.typeinfo->ui_icon,
iconofs,
- rct->ymax - NODE_DY,
+ rct.ymax - NODE_DY,
iconbutw,
UI_UNIT_Y,
nullptr,
@@ -1687,56 +1881,53 @@ static void node_draw_basis(const bContext *C,
0,
0,
"");
- UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
- node_add_error_message_button(C, *ntree, *node, *rct, iconofs);
+ node_add_error_message_button(C, node, block, rct, iconofs);
/* Title. */
- if (node->flag & SELECT) {
+ if (node.flag & SELECT) {
UI_GetThemeColor4fv(TH_SELECT, color);
}
else {
UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color);
}
- /* Open/close entirely. */
+ /* Collapse/expand icon. */
{
- int but_size = U.widget_unit * 0.8f;
- /* XXX button uses a custom triangle draw below, so make it invisible without icon. */
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
- uiBut *but = uiDefBut(node->block,
- UI_BTYPE_BUT_TOGGLE,
- 0,
- "",
- rct->xmin + 0.35f * U.widget_unit,
- rct->ymax - NODE_DY / 2.2f - but_size / 2,
- but_size,
- but_size,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- "");
- UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
- UI_block_emboss_set(node->block, UI_EMBOSS);
-
- UI_GetThemeColor4fv(TH_TEXT, color);
- /* Custom draw function for this button. */
- UI_draw_icon_tri(rct->xmin + 0.65f * U.widget_unit, rct->ymax - NODE_DY / 2.2f, 'v', color);
+ const int but_size = U.widget_unit * 0.8f;
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+
+ uiBut *but = uiDefIconBut(&block,
+ UI_BTYPE_BUT_TOGGLE,
+ 0,
+ ICON_DOWNARROW_HLT,
+ rct.xmin + (NODE_MARGIN_X / 3),
+ rct.ymax - NODE_DY / 2.2f - but_size / 2,
+ but_size,
+ but_size,
+ nullptr,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ "");
+
+ UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_hide_toggle");
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
char showname[128];
- nodeLabel(ntree, node, showname, sizeof(showname));
+ nodeLabel(&ntree, &node, showname, sizeof(showname));
- uiBut *but = uiDefBut(node->block,
+ uiBut *but = uiDefBut(&block,
UI_BTYPE_LABEL,
0,
showname,
- (int)(rct->xmin + NODE_MARGIN_X),
- (int)(rct->ymax - NODE_DY),
- (short)(iconofs - rct->xmin - (18.0f * U.dpi_fac)),
+ (int)(rct.xmin + NODE_MARGIN_X + 0.4f),
+ (int)(rct.ymax - NODE_DY),
+ (short)(iconofs - rct.xmin - (18.0f * U.dpi_fac)),
(short)NODE_DY,
nullptr,
0,
@@ -1744,179 +1935,223 @@ static void node_draw_basis(const bContext *C,
0,
0,
"");
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
UI_but_flag_enable(but, UI_BUT_INACTIVE);
}
+ /* Wire across the node when muted/disabled. */
+ if (node.flag & NODE_MUTED) {
+ node_draw_mute_line(C, v2d, snode, node);
+ }
+
/* Body. */
- if (nodeTypeUndefined(node)) {
+ const float outline_width = 1.0f;
+ {
/* Use warning color to indicate undefined types. */
- UI_GetThemeColor4fv(TH_REDALERT, color);
- }
- else if (node->flag & NODE_MUTED) {
- /* Muted nodes are semi-transparent and colorless. */
- UI_GetThemeColor4fv(TH_NODE, color);
- }
- else if (node->flag & NODE_CUSTOM_COLOR) {
- rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f);
- }
- else {
- UI_GetThemeColor4fv(TH_NODE, color);
- }
+ if (nodeTypeUndefined(&node)) {
+ UI_GetThemeColorBlend4f(TH_REDALERT, TH_NODE, 0.4f, color);
+ }
+ /* Muted nodes get a mix of the background with the node color. */
+ else if (node.flag & NODE_MUTED) {
+ UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.2f, color);
+ }
+ else if (node.flag & NODE_CUSTOM_COLOR) {
+ rgba_float_args_set(color, node.color[0], node.color[1], node.color[2], 1.0f);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_NODE, color);
+ }
+
+ /* Draw selected nodes fully opaque. */
+ if (node.flag & SELECT) {
+ color[3] = 1.0f;
+ }
+
+ /* Draw muted nodes slightly transparent so the wires inside are visible. */
+ if (node.flag & NODE_MUTED) {
+ color[3] -= 0.2f;
+ }
+
+ const rctf rect = {
+ rct.xmin,
+ rct.xmax,
+ rct.ymin,
+ rct.ymax - (NODE_DY + outline_width),
+ };
- if (node->flag & NODE_MUTED) {
- color[3] = 0.5f;
+ UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
+ UI_draw_roundbox_4fv(&rect, true, BASIS_RAD, color);
}
+ /* Header underline. */
{
- UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
+ float color_underline[4];
+
+ if (node.flag & NODE_MUTED) {
+ UI_GetThemeColor4fv(TH_WIRE, color_underline);
+ }
+ else {
+ UI_GetThemeColorBlend4f(TH_BACK, color_id, 0.2f, color_underline);
+ }
+
const rctf rect = {
- rct->xmin,
- rct->xmax,
- rct->ymin,
- rct->ymax - NODE_DY,
+ rct.xmin,
+ rct.xmax,
+ rct.ymax - (NODE_DY + outline_width),
+ rct.ymax - NODE_DY,
};
- UI_draw_roundbox_aa(&rect, true, BASIS_RAD, color);
+
+ UI_draw_roundbox_corner_set(UI_CNR_NONE);
+ UI_draw_roundbox_4fv(&rect, true, 0.0f, color_underline);
}
- /* Outline active and selected emphasis. */
- if (node->flag & SELECT) {
- UI_GetThemeColorShadeAlpha4fv(
- (node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
+ /* Outline. */
+ {
+ const rctf rect = {
+ rct.xmin - outline_width,
+ rct.xmax + outline_width,
+ rct.ymin - outline_width,
+ rct.ymax + outline_width,
+ };
+
+ /* Color the outline according to active, selected, or undefined status. */
+ float color_outline[4];
+
+ if (node.flag & SELECT) {
+ UI_GetThemeColor4fv((node.flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, color_outline);
+ }
+ else if (nodeTypeUndefined(&node)) {
+ UI_GetThemeColor4fv(TH_REDALERT, color_outline);
+ }
+ else {
+ UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color_outline);
+ }
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(rct, false, BASIS_RAD, color);
+ UI_draw_roundbox_4fv(&rect, false, BASIS_RAD, color_outline);
}
- /* Disable lines. */
- if (node->flag & NODE_MUTED) {
- node_draw_mute_line(v2d, snode, node);
- }
+ float scale;
+ UI_view2d_scale_get(&v2d, &scale, nullptr);
- node_draw_sockets(v2d, C, ntree, node, true, false);
+ /* Skip slow socket drawing if zoom is small. */
+ if (scale > 0.2f) {
+ node_draw_sockets(v2d, C, ntree, node, block, true, false);
+ }
/* Preview. */
- bNodeInstanceHash *previews = (bNodeInstanceHash *)CTX_data_pointer_get(C, "node_previews").data;
- if (node->flag & NODE_PREVIEW && previews) {
+ bNodeInstanceHash *previews =
+ (bNodeInstanceHash *)CTX_data_pointer_get(&C, "node_previews").data;
+ if (node.flag & NODE_PREVIEW && previews) {
bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key);
if (preview && (preview->xsize && preview->ysize)) {
- if (preview->rect && !BLI_rctf_is_empty(&node->prvr)) {
- node_draw_preview(preview, &node->prvr);
+ if (preview->rect && !BLI_rctf_is_empty(&node.prvr)) {
+ node_draw_preview(preview, &node.prvr);
}
}
}
- UI_block_end(C, node->block);
- UI_block_draw(C, node->block);
- node->block = nullptr;
+ UI_block_end(&C, &block);
+ UI_block_draw(&C, &block);
}
-static void node_draw_hidden(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey UNUSED(key))
+static void node_draw_hidden(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block)
{
- rctf *rct = &node->totr;
- float centy = BLI_rctf_cent_y(rct);
- float hiddenrad = BLI_rctf_size_y(rct) / 2.0f;
+ const rctf &rct = node.totr;
+ float centy = BLI_rctf_cent_y(&rct);
+ float hiddenrad = BLI_rctf_size_y(&rct) / 2.0f;
float scale;
- UI_view2d_scale_get(v2d, &scale, nullptr);
+ UI_view2d_scale_get(&v2d, &scale, nullptr);
+
+ const int color_id = node_get_colorid(node);
/* Shadow. */
node_draw_shadow(snode, node, hiddenrad, 1.0f);
- /* Body. */
- float color[4];
- int color_id = node_get_colorid(node);
- if (node->flag & NODE_MUTED) {
- /* Muted nodes are semi-transparent and colorless. */
- UI_GetThemeColor4fv(TH_NODE, color);
- color[3] = 0.25f;
- }
- else {
- UI_GetThemeColor4fv(color_id, color);
+ /* Wire across the node when muted/disabled. */
+ if (node.flag & NODE_MUTED) {
+ node_draw_mute_line(C, v2d, snode, node);
}
- UI_draw_roundbox_aa(rct, true, hiddenrad, color);
-
- /* Outline active and selected emphasis. */
- if (node->flag & SELECT) {
- UI_GetThemeColorShadeAlpha4fv(
- (node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
-
- UI_draw_roundbox_aa(rct, false, hiddenrad, color);
- }
+ /* Body. */
+ float color[4];
+ {
+ if (nodeTypeUndefined(&node)) {
+ /* Use warning color to indicate undefined types. */
+ UI_GetThemeColorBlend4f(TH_REDALERT, TH_NODE, 0.4f, color);
+ }
+ else if (node.flag & NODE_MUTED) {
+ /* Muted nodes get a mix of the background with the node color. */
+ UI_GetThemeColorBlendShade4fv(TH_BACK, color_id, 0.1f, 0, color);
+ }
+ else if (node.flag & NODE_CUSTOM_COLOR) {
+ rgba_float_args_set(color, node.color[0], node.color[1], node.color[2], 1.0f);
+ }
+ else {
+ UI_GetThemeColorBlend4f(TH_NODE, color_id, 0.4f, color);
+ }
- /* Custom color inline. */
- if (node->flag & NODE_CUSTOM_COLOR) {
- GPU_blend(GPU_BLEND_ALPHA);
- GPU_line_smooth(true);
+ /* Draw selected nodes fully opaque. */
+ if (node.flag & SELECT) {
+ color[3] = 1.0f;
+ }
- const rctf rect = {
- rct->xmin + 1,
- rct->xmax - 1,
- rct->ymin + 1,
- rct->ymax - 1,
- };
- UI_draw_roundbox_3fv_alpha(&rect, false, hiddenrad, node->color, 1.0f);
+ /* Draw muted nodes slightly transparent so the wires inside are visible. */
+ if (node.flag & NODE_MUTED) {
+ color[3] -= 0.2f;
+ }
- GPU_line_smooth(false);
- GPU_blend(GPU_BLEND_NONE);
+ UI_draw_roundbox_4fv(&rct, true, hiddenrad, color);
}
/* Title. */
- if (node->flag & SELECT) {
+ if (node.flag & SELECT) {
UI_GetThemeColor4fv(TH_SELECT, color);
}
else {
UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color);
}
- /* Open / collapse icon. */
+ /* Collapse/expand icon. */
{
- int but_size = U.widget_unit * 0.8f;
- /* XXX button uses a custom triangle draw below, so make it invisible without icon */
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
- uiBut *but = uiDefBut(node->block,
- UI_BTYPE_BUT_TOGGLE,
- 0,
- "",
- rct->xmin + 0.35f * U.widget_unit,
- centy - but_size / 2,
- but_size,
- but_size,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- "");
- UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
- UI_block_emboss_set(node->block, UI_EMBOSS);
-
- UI_GetThemeColor4fv(TH_TEXT, color);
- /* Custom draw function for this button. */
- UI_draw_icon_tri(rct->xmin + 0.65f * U.widget_unit, centy, 'h', color);
- }
-
- /* Disable lines. */
- if (node->flag & NODE_MUTED) {
- node_draw_mute_line(v2d, snode, node);
+ const int but_size = U.widget_unit * 1.0f;
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+
+ uiBut *but = uiDefIconBut(&block,
+ UI_BTYPE_BUT_TOGGLE,
+ 0,
+ ICON_RIGHTARROW,
+ rct.xmin + (NODE_MARGIN_X / 3),
+ centy - but_size / 2,
+ but_size,
+ but_size,
+ nullptr,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ "");
+
+ UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_hide_toggle");
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
char showname[128];
- nodeLabel(ntree, node, showname, sizeof(showname));
+ nodeLabel(&ntree, &node, showname, sizeof(showname));
- uiBut *but = uiDefBut(node->block,
+ uiBut *but = uiDefBut(&block,
UI_BTYPE_LABEL,
0,
showname,
- round_fl_to_int(rct->xmin + NODE_MARGIN_X),
+ round_fl_to_int(rct.xmin + NODE_MARGIN_X),
round_fl_to_int(centy - NODE_DY * 0.5f),
- (short)(BLI_rctf_size_x(rct) - ((18.0f + 12.0f) * U.dpi_fac)),
+ (short)(BLI_rctf_size_x(&rct) - ((18.0f + 12.0f) * U.dpi_fac)),
(short)NODE_DY,
nullptr,
0,
@@ -1924,46 +2159,77 @@ static void node_draw_hidden(const bContext *C,
0,
0,
"");
- if (node->flag & NODE_MUTED) {
+
+ /* Outline. */
+ {
+ const float outline_width = 1.0f;
+ const rctf rect = {
+ rct.xmin - outline_width,
+ rct.xmax + outline_width,
+ rct.ymin - outline_width,
+ rct.ymax + outline_width,
+ };
+
+ /* Color the outline according to active, selected, or undefined status. */
+ float color_outline[4];
+
+ if (node.flag & SELECT) {
+ UI_GetThemeColor4fv((node.flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, color_outline);
+ }
+ else if (nodeTypeUndefined(&node)) {
+ UI_GetThemeColor4fv(TH_REDALERT, color_outline);
+ }
+ else {
+ UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color_outline);
+ }
+
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_4fv(&rect, false, hiddenrad, color_outline);
+ }
+
+ if (node.flag & NODE_MUTED) {
UI_but_flag_enable(but, UI_BUT_INACTIVE);
}
/* Scale widget thing. */
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPU_blend(GPU_BLEND_ALPHA);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformThemeColorShade(color_id, -10);
- float dx = 10.0f;
+ immUniformThemeColorShadeAlpha(TH_TEXT, -40, -180);
+ float dx = 0.5f * U.widget_unit;
+ const float dx2 = 0.15f * U.widget_unit * snode.runtime->aspect;
+ const float dy = 0.2f * U.widget_unit;
immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, rct->xmax - dx, centy - 4.0f);
- immVertex2f(pos, rct->xmax - dx, centy + 4.0f);
+ immVertex2f(pos, rct.xmax - dx, centy - dy);
+ immVertex2f(pos, rct.xmax - dx, centy + dy);
- immVertex2f(pos, rct->xmax - dx - 3.0f * snode->runtime->aspect, centy - 4.0f);
- immVertex2f(pos, rct->xmax - dx - 3.0f * snode->runtime->aspect, centy + 4.0f);
+ immVertex2f(pos, rct.xmax - dx - dx2, centy - dy);
+ immVertex2f(pos, rct.xmax - dx - dx2, centy + dy);
immEnd();
- immUniformThemeColorShade(color_id, 30);
- dx -= snode->runtime->aspect;
+ immUniformThemeColorShadeAlpha(TH_TEXT, 0, -180);
+ dx -= snode.runtime->aspect;
immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, rct->xmax - dx, centy - 4.0f);
- immVertex2f(pos, rct->xmax - dx, centy + 4.0f);
+ immVertex2f(pos, rct.xmax - dx, centy - dy);
+ immVertex2f(pos, rct.xmax - dx, centy + dy);
- immVertex2f(pos, rct->xmax - dx - 3.0f * snode->runtime->aspect, centy - 4.0f);
- immVertex2f(pos, rct->xmax - dx - 3.0f * snode->runtime->aspect, centy + 4.0f);
+ immVertex2f(pos, rct.xmax - dx - dx2, centy - dy);
+ immVertex2f(pos, rct.xmax - dx - dx2, centy + dy);
immEnd();
immUnbindProgram();
+ GPU_blend(GPU_BLEND_NONE);
- node_draw_sockets(v2d, C, ntree, node, true, false);
+ node_draw_sockets(v2d, C, ntree, node, block, true, false);
- UI_block_end(C, node->block);
- UI_block_draw(C, node->block);
- node->block = nullptr;
+ UI_block_end(&C, &block);
+ UI_block_draw(&C, &block);
}
-int node_get_resize_cursor(int directions)
+int node_get_resize_cursor(NodeResizeDirection directions)
{
if (directions == 0) {
return WM_CURSOR_DEFAULT;
@@ -1977,77 +2243,58 @@ int node_get_resize_cursor(int directions)
return WM_CURSOR_EDIT;
}
-void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2])
+void node_set_cursor(wmWindow &win, SpaceNode &snode, const float2 &cursor)
{
- bNodeTree *ntree = snode->edittree;
+ const bNodeTree *ntree = snode.edittree;
+ if (ntree == nullptr) {
+ WM_cursor_set(&win, WM_CURSOR_DEFAULT);
+ return;
+ }
+
bNode *node;
bNodeSocket *sock;
int wmcursor = WM_CURSOR_DEFAULT;
- if (ntree) {
- if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN | SOCK_OUT)) {
- /* Pass. */
- }
- else {
- /* Check nodes front to back. */
- for (node = (bNode *)ntree->nodes.last; node; node = node->prev) {
- if (BLI_rctf_isect_pt(&node->totr, cursor[0], cursor[1])) {
- break; /* First hit on node stops. */
- }
- }
- if (node) {
- int dir = node->typeinfo->resize_area_func(node, cursor[0], cursor[1]);
- wmcursor = node_get_resize_cursor(dir);
- }
- }
+ if (node_find_indicated_socket(
+ snode, &node, &sock, cursor, (eNodeSocketInOut)(SOCK_IN | SOCK_OUT))) {
+ WM_cursor_set(&win, WM_CURSOR_DEFAULT);
+ return;
}
- WM_cursor_set(win, wmcursor);
-}
-
-void node_draw_default(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey key)
-{
- const View2D *v2d = &region->v2d;
- if (node->flag & NODE_HIDDEN) {
- node_draw_hidden(C, v2d, snode, ntree, node, key);
+ /* Check nodes front to back. */
+ for (node = (bNode *)ntree->nodes.last; node; node = node->prev) {
+ if (BLI_rctf_isect_pt(&node->totr, cursor[0], cursor[1])) {
+ break; /* First hit on node stops. */
+ }
}
- else {
- node_draw_basis(C, v2d, snode, ntree, node, key);
+ if (node) {
+ NodeResizeDirection dir = node_get_resize_direction(node, cursor[0], cursor[1]);
+ wmcursor = node_get_resize_cursor(dir);
}
-}
-static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
-{
- if (node->typeinfo->draw_nodetype_prepare) {
- node->typeinfo->draw_nodetype_prepare(C, ntree, node);
- }
+ WM_cursor_set(&win, wmcursor);
}
-static void count_multi_input_socket_links(bNodeTree *ntree, SpaceNode *snode)
+static void count_multi_input_socket_links(bNodeTree &ntree, SpaceNode &snode)
{
Map<bNodeSocket *, int> counts;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
if (link->tosock->flag & SOCK_MULTI_INPUT) {
int &count = counts.lookup_or_add(link->tosock, 0);
count++;
}
}
/* Count temporary links going into this socket. */
- LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
+ if (snode.runtime->linkdrag) {
+ for (const bNodeLink *link : snode.runtime->linkdrag->links) {
if (link->tosock && (link->tosock->flag & SOCK_MULTI_INPUT)) {
int &count = counts.lookup_or_add(link->tosock, 0);
count++;
}
}
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
if (socket->flag & SOCK_MULTI_INPUT) {
socket->total_inputs = counts.lookup_default(socket, 0);
@@ -2056,178 +2303,485 @@ static void count_multi_input_socket_links(bNodeTree *ntree, SpaceNode *snode)
}
}
-void node_update_nodetree(const bContext *C, bNodeTree *ntree)
+/* XXX Does a bounding box update by iterating over all children.
+ * Not ideal to do this in every draw call, but doing as transform callback doesn't work,
+ * since the child node totr rects are not updated properly at that point. */
+static void frame_node_prepare_for_draw(bNode &node, Span<bNode *> nodes)
+{
+ const float margin = 1.5f * U.widget_unit;
+ NodeFrame *data = (NodeFrame *)node.storage;
+
+ /* init rect from current frame size */
+ rctf rect;
+ node_to_updated_rect(node, rect);
+
+ /* frame can be resized manually only if shrinking is disabled or no children are attached */
+ data->flag |= NODE_FRAME_RESIZEABLE;
+ /* for shrinking bbox, initialize the rect from first child node */
+ bool bbinit = (data->flag & NODE_FRAME_SHRINK);
+ /* fit bounding box to all children */
+ for (const bNode *tnode : nodes) {
+ if (tnode->parent != &node) {
+ continue;
+ }
+
+ /* add margin to node rect */
+ rctf noderect = tnode->totr;
+ noderect.xmin -= margin;
+ noderect.xmax += margin;
+ noderect.ymin -= margin;
+ noderect.ymax += margin;
+
+ /* first child initializes frame */
+ if (bbinit) {
+ bbinit = false;
+ rect = noderect;
+ data->flag &= ~NODE_FRAME_RESIZEABLE;
+ }
+ else {
+ BLI_rctf_union(&rect, &noderect);
+ }
+ }
+
+ /* now adjust the frame size from view-space bounding box */
+ const float2 offset = node_from_view(node, {rect.xmin, rect.ymax});
+ node.offsetx = offset.x;
+ node.offsety = offset.y;
+ const float2 max = node_from_view(node, {rect.xmax, rect.ymin});
+ node.width = max.x - node.offsetx;
+ node.height = -max.y + node.offsety;
+
+ node.totr = rect;
+}
+
+static void reroute_node_prepare_for_draw(bNode &node)
+{
+ /* get "global" coords */
+ const float2 loc = node_to_view(node, float2(0));
+
+ /* reroute node has exactly one input and one output, both in the same place */
+ bNodeSocket *nsock = (bNodeSocket *)node.outputs.first;
+ nsock->locx = loc.x;
+ nsock->locy = loc.y;
+
+ nsock = (bNodeSocket *)node.inputs.first;
+ nsock->locx = loc.x;
+ nsock->locy = loc.y;
+
+ const float size = 8.0f;
+ node.width = size * 2;
+ node.totr.xmin = loc.x - size;
+ node.totr.xmax = loc.x + size;
+ node.totr.ymax = loc.y + size;
+ node.totr.ymin = loc.y - size;
+}
+
+static void node_update_nodetree(const bContext &C,
+ bNodeTree &ntree,
+ Span<bNode *> nodes,
+ Span<uiBlock *> blocks)
{
/* Make sure socket "used" tags are correct, for displaying value buttons. */
- SpaceNode *snode = CTX_wm_space_node(C);
- ntreeTagUsedSockets(ntree);
+ SpaceNode *snode = CTX_wm_space_node(&C);
- count_multi_input_socket_links(ntree, snode);
+ count_multi_input_socket_links(ntree, *snode);
/* Update nodes front to back, so children sizes get updated before parents. */
- LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree->nodes) {
- node_update(C, ntree, node);
+ for (const int i : nodes.index_range()) {
+ bNode &node = *nodes[i];
+ uiBlock &block = *blocks[i];
+ if (node.type == NODE_FRAME) {
+ /* Frame sizes are calculated after all other nodes have calculating their #totr. */
+ continue;
+ }
+
+ if (node.type == NODE_REROUTE) {
+ reroute_node_prepare_for_draw(node);
+ }
+ else {
+ if (node.flag & NODE_HIDDEN) {
+ node_update_hidden(node, block);
+ }
+ else {
+ node_update_basis(C, ntree, node, block);
+ }
+ }
+ }
+
+ /* Now calculate the size of frame nodes, which can depend on the size of other nodes. */
+ for (const int i : nodes.index_range()) {
+ if (nodes[i]->type == NODE_FRAME) {
+ frame_node_prepare_for_draw(*nodes[i], nodes);
+ }
}
}
-static void node_draw(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey key)
+static void frame_node_draw_label(const bNodeTree &ntree,
+ const bNode &node,
+ const SpaceNode &snode)
{
- if (node->typeinfo->draw_nodetype) {
- node->typeinfo->draw_nodetype(C, region, snode, ntree, node, key);
+ const float aspect = snode.runtime->aspect;
+ /* XXX font id is crap design */
+ const int fontid = UI_style_get()->widgetlabel.uifont_id;
+ const NodeFrame *data = (const NodeFrame *)node.storage;
+ const float font_size = data->label_size / aspect;
+
+ char label[MAX_NAME];
+ nodeLabel(&ntree, &node, label, sizeof(label));
+
+ BLF_enable(fontid, BLF_ASPECT);
+ BLF_aspect(fontid, aspect, aspect, 1.0f);
+ /* clamp otherwise it can suck up a LOT of memory */
+ BLF_size(fontid, MIN2(24.0f, font_size), U.dpi);
+
+ /* title color */
+ int color_id = node_get_colorid(node);
+ uchar color[3];
+ UI_GetThemeColorBlendShade3ubv(TH_TEXT, color_id, 0.4f, 10, color);
+ BLF_color3ubv(fontid, color);
+
+ const float margin = (float)(NODE_DY / 4);
+ const float width = BLF_width(fontid, label, sizeof(label));
+ const float ascender = BLF_ascender(fontid);
+ const int label_height = ((margin / aspect) + (ascender * aspect));
+
+ /* 'x' doesn't need aspect correction */
+ const rctf &rct = node.totr;
+ /* XXX a bit hacky, should use separate align values for x and y */
+ float x = BLI_rctf_cent_x(&rct) - (0.5f * width);
+ float y = rct.ymax - label_height;
+
+ /* label */
+ const bool has_label = node.label[0] != '\0';
+ if (has_label) {
+ BLF_position(fontid, x, y, 0);
+ BLF_draw(fontid, label, sizeof(label));
+ }
+
+ /* draw text body */
+ if (node.id) {
+ const Text *text = (const Text *)node.id;
+ const int line_height_max = BLF_height_max(fontid);
+ const float line_spacing = (line_height_max * aspect);
+ const float line_width = (BLI_rctf_size_x(&rct) - margin) / aspect;
+
+ /* 'x' doesn't need aspect correction */
+ x = rct.xmin + margin;
+ y = rct.ymax - label_height - (has_label ? line_spacing : 0);
+
+ /* early exit */
+ int y_min = y + ((margin * 2) - (y - rct.ymin));
+
+ BLF_enable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
+ BLF_clipping(fontid,
+ rct.xmin,
+ /* round to avoid clipping half-way through a line */
+ y - (floorf(((y - rct.ymin) - (margin * 2)) / line_spacing) * line_spacing),
+ rct.xmin + line_width,
+ rct.ymax);
+
+ BLF_wordwrap(fontid, line_width);
+
+ LISTBASE_FOREACH (const TextLine *, line, &text->lines) {
+ struct ResultBLF info;
+ if (line->line[0]) {
+ BLF_position(fontid, x, y, 0);
+ BLF_draw_ex(fontid, line->line, line->len, &info);
+ y -= line_spacing * info.lines;
+ }
+ else {
+ y -= line_spacing;
+ }
+ if (y < y_min) {
+ break;
+ }
+ }
+
+ BLF_disable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
}
+
+ BLF_disable(fontid, BLF_ASPECT);
}
-#define USE_DRAW_TOT_UPDATE
+static void frame_node_draw(const bContext &C,
+ const ARegion &region,
+ const SpaceNode &snode,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block)
+{
+ /* skip if out of view */
+ if (BLI_rctf_isect(&node.totr, &region.v2d.cur, nullptr) == false) {
+ UI_block_end(&C, &block);
+ return;
+ }
+
+ float color[4];
+ UI_GetThemeColor4fv(TH_NODE_FRAME, color);
+ const float alpha = color[3];
+
+ /* shadow */
+ node_draw_shadow(snode, node, BASIS_RAD, alpha);
+
+ /* body */
+ if (node.flag & NODE_CUSTOM_COLOR) {
+ rgba_float_args_set(color, node.color[0], node.color[1], node.color[2], alpha);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_NODE_FRAME, color);
+ }
+
+ const rctf &rct = node.totr;
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_4fv(&rct, true, BASIS_RAD, color);
+
+ /* outline active and selected emphasis */
+ if (node.flag & SELECT) {
+ if (node.flag & NODE_ACTIVE) {
+ UI_GetThemeColorShadeAlpha4fv(TH_ACTIVE, 0, -40, color);
+ }
+ else {
+ UI_GetThemeColorShadeAlpha4fv(TH_SELECT, 0, -40, color);
+ }
+
+ UI_draw_roundbox_aa(&rct, false, BASIS_RAD, color);
+ }
+
+ /* label and text */
+ frame_node_draw_label(ntree, node, snode);
+
+ node_draw_extra_info_panel(snode, node, block);
+
+ UI_block_end(&C, &block);
+ UI_block_draw(&C, &block);
+}
-void node_draw_nodetree(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNodeInstanceKey parent_key)
+static void reroute_node_draw(
+ const bContext &C, ARegion &region, bNodeTree &ntree, bNode &node, uiBlock &block)
{
- if (ntree == nullptr) {
- return; /* Groups. */
+ char showname[128]; /* 128 used below */
+ const rctf &rct = node.totr;
+
+ /* skip if out of view */
+ if (rct.xmax < region.v2d.cur.xmin || rct.xmin > region.v2d.cur.xmax ||
+ rct.ymax < region.v2d.cur.ymin || node.totr.ymin > region.v2d.cur.ymax) {
+ UI_block_end(&C, &block);
+ return;
}
-#ifdef USE_DRAW_TOT_UPDATE
- if (ntree->nodes.first) {
- BLI_rctf_init_minmax(&region->v2d.tot);
+ if (node.label[0] != '\0') {
+ /* draw title (node label) */
+ BLI_strncpy(showname, node.label, sizeof(showname));
+ uiDefBut(&block,
+ UI_BTYPE_LABEL,
+ 0,
+ showname,
+ (int)(rct.xmin - NODE_DYS),
+ (int)(rct.ymax),
+ (short)512,
+ (short)NODE_DY,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ }
+
+ /* only draw input socket. as they all are placed on the same position.
+ * highlight also if node itself is selected, since we don't display the node body separately!
+ */
+ node_draw_sockets(region.v2d, C, ntree, node, block, false, node.flag & SELECT);
+
+ UI_block_end(&C, &block);
+ UI_block_draw(&C, &block);
+}
+
+static void node_draw(const bContext &C,
+ ARegion &region,
+ const SpaceNode &snode,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block,
+ bNodeInstanceKey key)
+{
+ if (node.type == NODE_FRAME) {
+ frame_node_draw(C, region, snode, ntree, node, block);
+ }
+ else if (node.type == NODE_REROUTE) {
+ reroute_node_draw(C, region, ntree, node, block);
+ }
+ else {
+ const View2D &v2d = region.v2d;
+ if (node.flag & NODE_HIDDEN) {
+ node_draw_hidden(C, v2d, snode, ntree, node, block);
+ }
+ else {
+ node_draw_basis(C, v2d, snode, ntree, node, block, key);
+ }
}
+}
+
+#define USE_DRAW_TOT_UPDATE
+
+static void node_draw_nodetree(const bContext &C,
+ ARegion &region,
+ SpaceNode &snode,
+ bNodeTree &ntree,
+ Span<bNode *> nodes,
+ Span<uiBlock *> blocks,
+ bNodeInstanceKey parent_key)
+{
+#ifdef USE_DRAW_TOT_UPDATE
+ BLI_rctf_init_minmax(&region.v2d.tot);
#endif
/* Draw background nodes, last nodes in front. */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ for (const int i : nodes.index_range()) {
#ifdef USE_DRAW_TOT_UPDATE
/* Unrelated to background nodes, update the v2d->tot,
* can be anywhere before we draw the scroll bars. */
- BLI_rctf_union(&region->v2d.tot, &node->totr);
+ BLI_rctf_union(&region.v2d.tot, &nodes[i]->totr);
#endif
- if (!(node->flag & NODE_BACKGROUND)) {
+ if (!(nodes[i]->flag & NODE_BACKGROUND)) {
continue;
}
- bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
- node_draw(C, region, snode, ntree, node, key);
+ bNodeInstanceKey key = BKE_node_instance_key(parent_key, &ntree, nodes[i]);
+ node_draw(C, region, snode, ntree, *nodes[i], *blocks[i], key);
}
/* Node lines. */
GPU_blend(GPU_BLEND_ALPHA);
nodelink_batch_start(snode);
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
if (!nodeLinkIsHidden(link)) {
- node_draw_link(&region->v2d, snode, link);
+ node_draw_link(C, region.v2d, snode, *link);
}
}
nodelink_batch_end(snode);
GPU_blend(GPU_BLEND_NONE);
/* Draw foreground nodes, last nodes in front. */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->flag & NODE_BACKGROUND) {
+ for (const int i : nodes.index_range()) {
+ if (nodes[i]->flag & NODE_BACKGROUND) {
continue;
}
- bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
- node_draw(C, region, snode, ntree, node, key);
+ bNodeInstanceKey key = BKE_node_instance_key(parent_key, &ntree, nodes[i]);
+ node_draw(C, region, snode, ntree, *nodes[i], *blocks[i], key);
}
}
-/* Draw tree path info in lower left corner. */
-static void draw_tree_path(SpaceNode *snode)
+/* Draw the breadcrumb on the bottom of the editor. */
+static void draw_tree_path(const bContext &C, ARegion &region)
{
- char info[256];
+ using namespace blender;
- ED_node_tree_path_get_fixedbuf(snode, info, sizeof(info));
+ GPU_matrix_push_projection();
+ wmOrtho2_region_pixelspace(&region);
- UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
- BLF_draw_default(1.5f * UI_UNIT_X, 1.5f * UI_UNIT_Y, 0.0f, info, sizeof(info));
+ const rcti *rect = ED_region_visible_rect(&region);
+
+ const uiStyle *style = UI_style_get_dpi();
+ const float padding_x = 16 * UI_DPI_FAC;
+ const int x = rect->xmin + padding_x;
+ const int y = region.winy - UI_UNIT_Y * 0.6f;
+ const int width = BLI_rcti_size_x(rect) - 2 * padding_x;
+
+ uiBlock *block = UI_block_begin(&C, &region, __func__, UI_EMBOSS_NONE);
+ uiLayout *layout = UI_block_layout(
+ block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, x, y, width, 1, 0, style);
+
+ Vector<ui::ContextPathItem> context_path = ed::space_node::context_path_for_space_node(C);
+ ui::template_breadcrumbs(*layout, context_path);
+
+ UI_block_layout_resolve(block, nullptr, nullptr);
+ UI_block_end(&C, block);
+ UI_block_draw(&C, block);
+
+ GPU_matrix_pop_projection();
}
-static void snode_setup_v2d(SpaceNode *snode, ARegion *region, const float center[2])
+static void snode_setup_v2d(SpaceNode &snode, ARegion &region, const float2 &center)
{
- View2D *v2d = &region->v2d;
+ View2D &v2d = region.v2d;
/* Shift view to node tree center. */
- UI_view2d_center_set(v2d, center[0], center[1]);
- UI_view2d_view_ortho(v2d);
+ UI_view2d_center_set(&v2d, center[0], center[1]);
+ UI_view2d_view_ortho(&v2d);
/* Aspect + font, set each time. */
- snode->runtime->aspect = BLI_rctf_size_x(&v2d->cur) / (float)region->winx;
+ snode.runtime->aspect = BLI_rctf_size_x(&v2d.cur) / (float)region.winx;
// XXX snode->curfont = uiSetCurFont_ext(snode->aspect);
}
-static void draw_nodetree(const bContext *C,
- ARegion *region,
- bNodeTree *ntree,
+static void draw_nodetree(const bContext &C,
+ ARegion &region,
+ bNodeTree &ntree,
bNodeInstanceKey parent_key)
{
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
- node_uiblocks_init(C, ntree);
+ Vector<bNode *> nodes = ntree.nodes;
- node_update_nodetree(C, ntree);
- node_draw_nodetree(C, region, snode, ntree, parent_key);
+ Array<uiBlock *> blocks = node_uiblocks_init(C, nodes);
+
+ node_update_nodetree(C, ntree, nodes, blocks);
+ node_draw_nodetree(C, region, *snode, ntree, nodes, blocks, parent_key);
}
-/* Shade the parent node group and add a `uiBlock` to clip mouse events. */
-static void draw_group_overlay(const bContext *C, ARegion *region)
+/**
+ * Make the background slightly brighter to indicate that users are inside a node-group.
+ */
+static void draw_background_color(const SpaceNode &snode)
{
- const View2D *v2d = &region->v2d;
- const rctf rect = v2d->cur;
- float color[4];
-
- /* Shade node groups to separate them visually. */
- GPU_blend(GPU_BLEND_ALPHA);
-
- UI_GetThemeColorShadeAlpha4fv(TH_NODE_GROUP, 0, 0, color);
- UI_draw_roundbox_corner_set(UI_CNR_NONE);
- UI_draw_roundbox_4fv(&rect, true, 0, color);
- GPU_blend(GPU_BLEND_NONE);
-
- /* Set the block bounds to clip mouse events from underlying nodes. */
- uiBlock *block = UI_block_begin(C, region, "node tree bounds block", UI_EMBOSS);
- UI_block_bounds_set_explicit(block, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
- UI_block_flag_enable(block, UI_BLOCK_CLIP_EVENTS);
- UI_block_end(C, block);
+ const int max_tree_length = 3;
+ const float bright_factor = 0.25f;
+
+ /* We ignore the first element of the path since it is the top-most tree and it doesn't need to
+ * be brighter. We also set a cap to how many levels we want to set apart, to avoid the
+ * background from getting too bright. */
+ const int clamped_tree_path_length = BLI_listbase_count_at_most(&snode.treepath,
+ max_tree_length);
+ const int depth = max_ii(0, clamped_tree_path_length - 1);
+
+ float color[3];
+ UI_GetThemeColor3fv(TH_BACK, color);
+ mul_v3_fl(color, 1.0f + bright_factor * depth);
+ GPU_clear_color(color[0], color[1], color[2], 1.0);
}
-void node_draw_space(const bContext *C, ARegion *region)
+void node_draw_space(const bContext &C, ARegion &region)
{
- wmWindow *win = CTX_wm_window(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- View2D *v2d = &region->v2d;
+ wmWindow *win = CTX_wm_window(&C);
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ View2D &v2d = region.v2d;
/* Setup off-screen buffers. */
- GPUViewport *viewport = WM_draw_region_get_viewport(region);
+ GPUViewport *viewport = WM_draw_region_get_viewport(&region);
GPUFrameBuffer *framebuffer_overlay = GPU_viewport_framebuffer_overlay_get(viewport);
GPU_framebuffer_bind_no_srgb(framebuffer_overlay);
- UI_view2d_view_ortho(v2d);
- UI_ThemeClearColor(TH_BACK);
+ UI_view2d_view_ortho(&v2d);
+ draw_background_color(snode);
GPU_depth_test(GPU_DEPTH_NONE);
GPU_scissor_test(true);
/* XXX `snode->runtime->cursor` set in coordinate-space for placing new nodes,
* used for drawing noodles too. */
- UI_view2d_region_to_view(&region->v2d,
- win->eventstate->x - region->winrct.xmin,
- win->eventstate->y - region->winrct.ymin,
- &snode->runtime->cursor[0],
- &snode->runtime->cursor[1]);
- snode->runtime->cursor[0] /= UI_DPI_FAC;
- snode->runtime->cursor[1] /= UI_DPI_FAC;
+ UI_view2d_region_to_view(&region.v2d,
+ win->eventstate->xy[0] - region.winrct.xmin,
+ win->eventstate->xy[1] - region.winrct.ymin,
+ &snode.runtime->cursor[0],
+ &snode.runtime->cursor[1]);
+ snode.runtime->cursor[0] /= UI_DPI_FAC;
+ snode.runtime->cursor[1] /= UI_DPI_FAC;
- int grid_levels = UI_GetThemeValueType(TH_NODE_GRID_LEVELS, SPACE_NODE);
-
- ED_region_draw_cb_draw(C, region, REGION_DRAW_PRE_VIEW);
+ ED_region_draw_cb_draw(&C, &region, REGION_DRAW_PRE_VIEW);
/* Only set once. */
GPU_blend(GPU_BLEND_ALPHA);
@@ -2235,15 +2789,16 @@ void node_draw_space(const bContext *C, ARegion *region)
/* Nodes. */
snode_set_context(C);
- /* Draw parent node trees. */
- if (snode->treepath.last) {
- static const int max_depth = 2;
+ const int grid_levels = UI_GetThemeValueType(TH_NODE_GRID_LEVELS, SPACE_NODE);
+ UI_view2d_dot_grid_draw(&v2d, TH_GRID, NODE_GRID_STEP_SIZE, grid_levels);
- bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
+ /* Draw parent node trees. */
+ if (snode.treepath.last) {
+ bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
/* Update tree path name (drawn in the bottom left). */
- ID *name_id = (path->nodetree && path->nodetree != snode->nodetree) ? &path->nodetree->id :
- snode->id;
+ ID *name_id = (path->nodetree && path->nodetree != snode.nodetree) ? &path->nodetree->id :
+ snode.id;
if (name_id && UNLIKELY(!STREQ(path->display_name, name_id->name + 2))) {
BLI_strncpy(path->display_name, name_id->name + 2, sizeof(path->display_name));
@@ -2251,30 +2806,12 @@ void node_draw_space(const bContext *C, ARegion *region)
/* Current View2D center, will be set temporarily for parent node trees. */
float center[2];
- UI_view2d_center_get(v2d, &center[0], &center[1]);
+ UI_view2d_center_get(&v2d, &center[0], &center[1]);
/* Store new view center in path and current edit tree. */
copy_v2_v2(path->view_center, center);
- if (snode->edittree) {
- copy_v2_v2(snode->edittree->view_center, center);
- }
-
- int depth = 0;
- while (path->prev && depth < max_depth) {
- path = path->prev;
- depth++;
- }
-
- /* Parent node trees in the background. */
- for (int curdepth = depth; curdepth > 0; path = path->next, curdepth--) {
- bNodeTree *ntree = path->nodetree;
- if (ntree) {
- snode_setup_v2d(snode, region, path->view_center);
-
- draw_nodetree(C, region, ntree, path->parent_key);
-
- draw_group_overlay(C, region);
- }
+ if (snode.edittree) {
+ copy_v2_v2(snode.edittree->view_center, center);
}
/* Top-level edit tree. */
@@ -2282,13 +2819,6 @@ void node_draw_space(const bContext *C, ARegion *region)
if (ntree) {
snode_setup_v2d(snode, region, center);
- /* Grid, uses theme color based on node path depth. */
- UI_view2d_multi_grid_draw(v2d,
- (depth > 0 ? TH_NODE_GROUP : TH_GRID),
- ED_node_grid_size(),
- NODE_GRID_STEPS,
- grid_levels);
-
/* Backdrop. */
draw_nodespace_back_pix(C, region, snode, path->parent_key);
@@ -2299,56 +2829,58 @@ void node_draw_space(const bContext *C, ARegion *region)
GPU_matrix_push();
GPU_matrix_identity_set();
- wmOrtho2_pixelspace(region->winx, region->winy);
+ wmOrtho2_pixelspace(region.winx, region.winy);
- WM_gizmomap_draw(region->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D);
+ WM_gizmomap_draw(region.gizmo_map, &C, WM_GIZMOMAP_DRAWSTEP_2D);
GPU_matrix_pop();
GPU_matrix_projection_set(original_proj);
}
- draw_nodetree(C, region, ntree, path->parent_key);
+ draw_nodetree(C, region, *ntree, path->parent_key);
}
/* Temporary links. */
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_smooth(true);
- LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- node_draw_link(v2d, snode, (bNodeLink *)linkdata->data);
+ if (snode.runtime->linkdrag) {
+ for (const bNodeLink *link : snode.runtime->linkdrag->links) {
+ node_draw_link(C, v2d, snode, *link);
}
}
GPU_line_smooth(false);
GPU_blend(GPU_BLEND_NONE);
- if (snode->flag & SNODE_SHOW_GPENCIL) {
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS && snode.flag & SNODE_SHOW_GPENCIL) {
/* Draw grease-pencil annotations. */
- ED_annotation_draw_view2d(C, true);
+ ED_annotation_draw_view2d(&C, true);
}
}
else {
- /* Default grid. */
- UI_view2d_multi_grid_draw(v2d, TH_GRID, ED_node_grid_size(), NODE_GRID_STEPS, grid_levels);
/* Backdrop. */
draw_nodespace_back_pix(C, region, snode, NODE_INSTANCE_KEY_NONE);
}
- ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW);
+ ED_region_draw_cb_draw(&C, &region, REGION_DRAW_POST_VIEW);
/* Reset view matrix. */
- UI_view2d_view_restore(C);
+ UI_view2d_view_restore(&C);
- if (snode->treepath.last) {
- if (snode->flag & SNODE_SHOW_GPENCIL) {
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS) {
+ if (snode.flag & SNODE_SHOW_GPENCIL && snode.treepath.last) {
/* Draw grease-pencil (screen strokes, and also paint-buffer). */
- ED_annotation_draw_view2d(C, false);
+ ED_annotation_draw_view2d(&C, false);
}
- }
- /* Tree path info. */
- draw_tree_path(snode);
+ /* Draw context path. */
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_PATH && snode.edittree) {
+ draw_tree_path(C, region);
+ }
+ }
/* Scrollers. */
- UI_view2d_scrollers_draw(v2d, nullptr);
+ UI_view2d_scrollers_draw(&v2d, nullptr);
}
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index 030d1672a08..6275e7e4656 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -31,9 +31,6 @@
#include "DNA_text_types.h"
#include "DNA_world_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -41,6 +38,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_workspace.h"
@@ -76,7 +74,9 @@
#include "NOD_geometry.h"
#include "NOD_shader.h"
#include "NOD_texture.h"
-#include "node_intern.h" /* own include */
+#include "node_intern.hh" /* own include */
+
+namespace blender::ed::space_node {
#define USE_ESC_COMPO
@@ -103,24 +103,23 @@ struct CompoJob {
float *progress;
};
-float node_socket_calculate_height(const bNodeSocket *socket)
+float node_socket_calculate_height(const bNodeSocket &socket)
{
float sock_height = NODE_SOCKSIZE * 2.0f;
- if (socket->flag & SOCK_MULTI_INPUT) {
- sock_height += max_ii(NODE_MULTI_INPUT_LINK_GAP * 0.5f * socket->total_inputs, NODE_SOCKSIZE);
+ if (socket.flag & SOCK_MULTI_INPUT) {
+ sock_height += max_ii(NODE_MULTI_INPUT_LINK_GAP * 0.5f * socket.total_inputs, NODE_SOCKSIZE);
}
return sock_height;
}
-void node_link_calculate_multi_input_position(const float socket_x,
- const float socket_y,
- const int index,
- const int total_inputs,
- float r[2])
+float2 node_link_calculate_multi_input_position(const float2 &socket_position,
+ const int index,
+ const int total_inputs)
{
- float offset = (total_inputs * NODE_MULTI_INPUT_LINK_GAP - NODE_MULTI_INPUT_LINK_GAP) * 0.5;
- r[0] = socket_x - NODE_SOCKSIZE * 0.5f;
- r[1] = socket_y - offset + (index * NODE_MULTI_INPUT_LINK_GAP);
+ const float offset = (total_inputs * NODE_MULTI_INPUT_LINK_GAP - NODE_MULTI_INPUT_LINK_GAP) *
+ 0.5f;
+ return {socket_position.x - NODE_SOCKSIZE * 0.5f,
+ socket_position.y - offset + index * NODE_MULTI_INPUT_LINK_GAP};
}
static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags)
@@ -320,15 +319,12 @@ static void compo_startjob(void *cjv,
ntree->progress = nullptr;
}
-/**
- * \param scene_owner: is the owner of the job,
- * we don't use it for anything else currently so could also be a void pointer,
- * but for now keep it an 'Scene' for consistency.
- *
- * \note only call from spaces `refresh` callbacks, not direct! - use with care.
- */
+} // namespace blender::ed::space_node
+
void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene *scene_owner)
{
+ using namespace blender::ed::space_node;
+
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -351,7 +347,7 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
"Compositing",
WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS,
WM_JOB_TYPE_COMPOSITE);
- CompoJob *cj = (CompoJob *)MEM_callocN(sizeof(CompoJob), "compo job");
+ CompoJob *cj = MEM_cnew<CompoJob>("compo job");
/* customdata for preview thread */
cj->bmain = bmain;
@@ -368,9 +364,10 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
+namespace blender::ed::space_node {
+
/* ***************************************** */
-/* operator poll callback */
bool composite_node_active(bContext *C)
{
if (ED_operator_node_active(C)) {
@@ -382,7 +379,6 @@ bool composite_node_active(bContext *C)
return false;
}
-/* operator poll callback */
bool composite_node_editable(bContext *C)
{
if (ED_operator_node_editable(C)) {
@@ -394,31 +390,11 @@ bool composite_node_editable(bContext *C)
return false;
}
-void snode_dag_update(bContext *C, SpaceNode *snode)
+static void send_notifiers_after_tree_change(ID *id, bNodeTree *ntree)
{
- Main *bmain = CTX_data_main(C);
+ WM_main_add_notifier(NC_NODE | NA_EDITED, nullptr);
- /* for groups, update all ID's using this */
- if ((snode->edittree->id.flag & LIB_EMBEDDED_DATA) == 0) {
- FOREACH_NODETREE_BEGIN (bmain, tntree, id) {
- if (ntreeHasTree(tntree, snode->edittree)) {
- DEG_id_tag_update(id, 0);
- }
- }
- FOREACH_NODETREE_END;
- }
-
- DEG_id_tag_update(snode->id, 0);
- DEG_id_tag_update(&snode->nodetree->id, 0);
-}
-
-void snode_notify(bContext *C, SpaceNode *snode)
-{
- ID *id = snode->id;
-
- WM_event_add_notifier(C, NC_NODE | NA_EDITED, nullptr);
-
- if (ED_node_is_shader(snode)) {
+ if (ntree->type == NTREE_SHADER) {
if (GS(id->name) == ID_MA) {
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
}
@@ -429,17 +405,40 @@ void snode_notify(bContext *C, SpaceNode *snode)
WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
}
}
- else if (ED_node_is_compositor(snode)) {
- WM_event_add_notifier(C, NC_SCENE | ND_NODES, id);
+ else if (ntree->type == NTREE_COMPOSIT) {
+ WM_main_add_notifier(NC_SCENE | ND_NODES, id);
}
- else if (ED_node_is_texture(snode)) {
- WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, id);
+ else if (ntree->type == NTREE_TEXTURE) {
+ WM_main_add_notifier(NC_TEXTURE | ND_NODES, id);
}
- else if (ED_node_is_geometry(snode)) {
+ else if (ntree->type == NTREE_GEOMETRY) {
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id);
}
}
+} // namespace blender::ed::space_node
+
+void ED_node_tree_propagate_change(const bContext *C, Main *bmain, bNodeTree *root_ntree)
+{
+ if (C != nullptr) {
+ SpaceNode *snode = CTX_wm_space_node(C);
+ if (snode != nullptr && root_ntree != nullptr) {
+ blender::ed::space_node::send_notifiers_after_tree_change(snode->id, root_ntree);
+ }
+ }
+
+ NodeTreeUpdateExtraParams params = {nullptr};
+ params.tree_changed_fn = [](ID *id, bNodeTree *ntree, void *UNUSED(user_data)) {
+ blender::ed::space_node::send_notifiers_after_tree_change(id, ntree);
+ DEG_id_tag_update(&ntree->id, ID_RECALC_COPY_ON_WRITE);
+ };
+ params.tree_output_changed_fn = [](ID *UNUSED(id), bNodeTree *ntree, void *UNUSED(user_data)) {
+ DEG_id_tag_update(&ntree->id, ID_RECALC_NTREE_OUTPUT);
+ };
+
+ BKE_ntree_update_main_tree(bmain, root_ntree, &params);
+}
+
void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo)
{
if (typeinfo) {
@@ -470,8 +469,6 @@ bool ED_node_is_geometry(struct SpaceNode *snode)
return STREQ(snode->tree_idname, ntreeType_Geometry->idname);
}
-/* assumes nothing being done in ntree yet, sets the default in/out node */
-/* called from shading buttons or header */
void ED_node_shader_default(const bContext *C, ID *id)
{
Main *bmain = CTX_data_main(C);
@@ -490,7 +487,7 @@ void ED_node_shader_default(const bContext *C, ID *id)
}
ma->nodetree = ntreeCopyTree(bmain, ma_default->nodetree);
- ntreeUpdateTree(bmain, ma->nodetree);
+ BKE_ntree_update_main_tree(bmain, ma->nodetree, nullptr);
}
else if (ELEM(GS(id->name), ID_WO, ID_LA)) {
/* Emission */
@@ -530,7 +527,7 @@ void ED_node_shader_default(const bContext *C, ID *id)
output->locx = 300.0f;
output->locy = 300.0f;
nodeSetActive(ntree, output);
- ntreeUpdateTree(bmain, ntree);
+ BKE_ntree_update_main_tree(bmain, ntree, nullptr);
}
else {
printf("ED_node_shader_default called on wrong ID type.\n");
@@ -538,8 +535,6 @@ void ED_node_shader_default(const bContext *C, ID *id)
}
}
-/* assumes nothing being done in ntree yet, sets the default in/out node */
-/* called from shading buttons or header */
void ED_node_composit_default(const bContext *C, struct Scene *sce)
{
/* but lets check it anyway */
@@ -570,11 +565,9 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce)
bNodeSocket *tosock = (bNodeSocket *)out->inputs.first;
nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
- ntreeUpdateTree(CTX_data_main(C), sce->nodetree);
+ BKE_ntree_update_main_tree(CTX_data_main(C), sce->nodetree, nullptr);
}
-/* assumes nothing being done in ntree yet, sets the default in/out node */
-/* called from shading buttons or header */
void ED_node_texture_default(const bContext *C, Tex *tex)
{
/* but lets check it anyway */
@@ -600,19 +593,23 @@ void ED_node_texture_default(const bContext *C, Tex *tex)
bNodeSocket *tosock = (bNodeSocket *)out->inputs.first;
nodeAddLink(tex->nodetree, in, fromsock, out, tosock);
- ntreeUpdateTree(CTX_data_main(C), tex->nodetree);
+ BKE_ntree_update_main_tree(CTX_data_main(C), tex->nodetree, nullptr);
}
-/* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
-void snode_set_context(const bContext *C)
+namespace blender::ed::space_node {
+
+/**
+ * Here we set the active tree(s), even called for each redraw now, so keep it fast :)
+ */
+void snode_set_context(const bContext &C)
{
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
bNodeTreeType *treetype = ntreeTypeFind(snode->tree_idname);
bNodeTree *ntree = snode->nodetree;
ID *id = snode->id, *from = snode->from;
/* check the tree type */
- if (!treetype || (treetype->poll && !treetype->poll(C, treetype))) {
+ if (!treetype || (treetype->poll && !treetype->poll(&C, treetype))) {
/* invalid tree type, skip
* NOTE: not resetting the node path here, invalid #bNodeTreeType
* may still be registered at a later point. */
@@ -633,7 +630,7 @@ void snode_set_context(const bContext *C)
id = nullptr;
from = nullptr;
- treetype->get_from_context(C, treetype, &ntree, &id, &from);
+ treetype->get_from_context(&C, treetype, &ntree, &id, &from);
}
}
@@ -643,27 +640,7 @@ void snode_set_context(const bContext *C)
}
}
-void snode_update(SpaceNode *snode, bNode *node)
-{
- /* XXX this only updates nodes in the current node space tree path.
- * The function supposedly should update any potential group node linking to changed tree,
- * this really requires a working depsgraph ...
- */
-
- /* update all edited group nodes */
- bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
- if (path) {
- bNodeTree *ngroup = path->nodetree;
- for (path = path->prev; path; path = path->prev) {
- nodeUpdateID(path->nodetree, (ID *)ngroup);
- ngroup = path->nodetree;
- }
- }
-
- if (node) {
- nodeUpdate(snode->edittree, node);
- }
-}
+} // namespace blender::ed::space_node
void ED_node_set_active(
Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
@@ -695,11 +672,6 @@ void ED_node_set_active(
/* tree specific activate calls */
if (ntree->type == NTREE_SHADER) {
- /* when we select a material, active texture is cleared, for buttons */
- if (node->id && ELEM(GS(node->id->name), ID_MA, ID_LA, ID_WO)) {
- nodeClearActiveID(ntree, ID_TE);
- }
-
if (ELEM(node->type,
SH_NODE_OUTPUT_MATERIAL,
SH_NODE_OUTPUT_WORLD,
@@ -712,14 +684,10 @@ void ED_node_set_active(
}
node->flag |= NODE_DO_OUTPUT;
- if (was_output == 0) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
- }
- }
- else if (do_update) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
}
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
+
if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
/* If active texture changed, free glsl materials. */
LISTBASE_FOREACH (Material *, ma, &bmain->materials) {
@@ -765,7 +733,7 @@ void ED_node_set_active(
if (r_active_texture_changed) {
*r_active_texture_changed = true;
}
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
WM_main_add_notifier(NC_IMAGE, nullptr);
}
@@ -782,7 +750,7 @@ void ED_node_set_active(
node->flag |= NODE_DO_OUTPUT;
if (was_output == 0) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/* Adding a node doesn't link this yet. */
@@ -797,11 +765,11 @@ void ED_node_set_active(
}
node->flag |= NODE_DO_OUTPUT;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
}
else if (do_update) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
}
else if (ntree->type == NTREE_TEXTURE) {
@@ -839,6 +807,8 @@ void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree))
// node_update_nodetree(C, ntree, 0.0f, 0.0f);
}
+namespace blender::ed::space_node {
+
/* ***************** generic operator functions for nodes ***************** */
#if 0 /* UNUSED */
@@ -918,10 +888,10 @@ static void edit_node_properties_get(
/* ************************** Node generic ************** */
/* is rct in visible part of node? */
-static bNode *visible_node(SpaceNode *snode, const rctf *rct)
+static bNode *visible_node(SpaceNode &snode, const rctf &rct)
{
- LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode->edittree->nodes) {
- if (BLI_rctf_isect(&node->totr, rct, nullptr)) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode.edittree->nodes) {
+ if (BLI_rctf_isect(&node->totr, &rct, nullptr)) {
return node;
}
}
@@ -938,13 +908,15 @@ struct NodeSizeWidget {
int directions;
};
-static void node_resize_init(
- bContext *C, wmOperator *op, const wmEvent *UNUSED(event), bNode *node, int dir)
+static void node_resize_init(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event),
+ const bNode *node,
+ NodeResizeDirection dir)
{
SpaceNode *snode = CTX_wm_space_node(C);
- NodeSizeWidget *nsw = (NodeSizeWidget *)MEM_callocN(sizeof(NodeSizeWidget),
- "size widget op data");
+ NodeSizeWidget *nsw = MEM_cnew<NodeSizeWidget>(__func__);
op->customdata = nsw;
nsw->mxstart = snode->runtime->cursor[0] * UI_DPI_FAC;
@@ -1089,21 +1061,22 @@ static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
- bNode *node = nodeGetActive(snode->edittree);
- int dir;
+ const bNode *node = nodeGetActive(snode->edittree);
- if (node) {
- float cursor[2];
+ if (node == nullptr) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ }
- /* convert mouse coordinates to v2d space */
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
- dir = node->typeinfo->resize_area_func(node, cursor[0], cursor[1]);
- if (dir != 0) {
- node_resize_init(C, op, event, node, dir);
- return OPERATOR_RUNNING_MODAL;
- }
+ /* convert mouse coordinates to v2d space */
+ float cursor[2];
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
+ const NodeResizeDirection dir = node_get_resize_direction(node, cursor[0], cursor[1]);
+ if (dir == NODE_RESIZE_NONE) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
- return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+
+ node_resize_init(C, op, event, node, dir);
+ return OPERATOR_RUNNING_MODAL;
}
static void node_resize_cancel(bContext *C, wmOperator *op)
@@ -1171,7 +1144,7 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set)
}
/* checks snode->mouse position, and returns found node/socket */
-static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSocket *socket)
+static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSocket &socket)
{
const float node_socket_height = node_socket_calculate_height(socket);
rctf multi_socket_rect;
@@ -1181,19 +1154,21 @@ static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSo
* sometimes want to drag the link to the other side, if you may
* accidentally pick the wrong link otherwise. */
BLI_rctf_init(&multi_socket_rect,
- socket->locx - NODE_SOCKSIZE * 4.0f,
- socket->locx + NODE_SOCKSIZE * 2.0f,
- socket->locy - node_socket_height,
- socket->locy + node_socket_height);
+ socket.locx - NODE_SOCKSIZE * 4.0f,
+ socket.locx + NODE_SOCKSIZE * 2.0f,
+ socket.locy - node_socket_height,
+ socket.locy + node_socket_height);
if (BLI_rctf_isect_pt(&multi_socket_rect, cursor[0], cursor[1])) {
return true;
}
return false;
}
-/* type is SOCK_IN and/or SOCK_OUT */
-int node_find_indicated_socket(
- SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, const float cursor[2], int in_out)
+bool node_find_indicated_socket(SpaceNode &snode,
+ bNode **nodep,
+ bNodeSocket **sockp,
+ const float2 &cursor,
+ const eNodeSocketInOut in_out)
{
rctf rect;
@@ -1201,7 +1176,7 @@ int node_find_indicated_socket(
*sockp = nullptr;
/* check if we click in a socket */
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) {
BLI_rctf_init_pt_radius(&rect, cursor, NODE_SOCKSIZE + 4);
if (!(node->flag & NODE_HIDDEN)) {
@@ -1220,19 +1195,19 @@ int node_find_indicated_socket(
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (!nodeSocketIsHidden(sock)) {
if (sock->flag & SOCK_MULTI_INPUT && !(node->flag & NODE_HIDDEN)) {
- if (cursor_isect_multi_input_socket(cursor, sock)) {
- if (node == visible_node(snode, &rect)) {
+ if (cursor_isect_multi_input_socket(cursor, *sock)) {
+ if (node == visible_node(snode, rect)) {
*nodep = node;
*sockp = sock;
- return 1;
+ return true;
}
}
}
else if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) {
- if (node == visible_node(snode, &rect)) {
+ if (node == visible_node(snode, rect)) {
*nodep = node;
*sockp = sock;
- return 1;
+ return true;
}
}
}
@@ -1242,10 +1217,10 @@ int node_find_indicated_socket(
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
if (!nodeSocketIsHidden(sock)) {
if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) {
- if (node == visible_node(snode, &rect)) {
+ if (node == visible_node(snode, rect)) {
*nodep = node;
*sockp = sock;
- return 1;
+ return true;
}
}
}
@@ -1253,38 +1228,39 @@ int node_find_indicated_socket(
}
}
- return 0;
+ return false;
}
/* ****************** Link Dimming *********************** */
-float node_link_dim_factor(const View2D *v2d, const bNodeLink *link)
+float node_link_dim_factor(const View2D &v2d, const bNodeLink &link)
{
- if (link->fromsock == nullptr || link->tosock == nullptr) {
+ if (link.fromsock == nullptr || link.tosock == nullptr) {
return 1.0f;
}
const float min_endpoint_distance = std::min(
- std::max(BLI_rctf_length_x(&v2d->cur, link->fromsock->locx),
- BLI_rctf_length_y(&v2d->cur, link->fromsock->locy)),
- std::max(BLI_rctf_length_x(&v2d->cur, link->tosock->locx),
- BLI_rctf_length_y(&v2d->cur, link->tosock->locy)));
+ std::max(BLI_rctf_length_x(&v2d.cur, link.fromsock->locx),
+ BLI_rctf_length_y(&v2d.cur, link.fromsock->locy)),
+ std::max(BLI_rctf_length_x(&v2d.cur, link.tosock->locx),
+ BLI_rctf_length_y(&v2d.cur, link.tosock->locy)));
if (min_endpoint_distance == 0.0f) {
return 1.0f;
}
- const float viewport_width = BLI_rctf_size_x(&v2d->cur);
+ const float viewport_width = BLI_rctf_size_x(&v2d.cur);
return std::clamp(1.0f - min_endpoint_distance / viewport_width * 10.0f, 0.05f, 1.0f);
}
-bool node_link_is_hidden_or_dimmed(const View2D *v2d, const bNodeLink *link)
+bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link)
{
- return nodeLinkIsHidden(link) || node_link_dim_factor(v2d, link) < 0.5f;
+ return nodeLinkIsHidden(&link) || node_link_dim_factor(v2d, link) < 0.5f;
}
/* ****************** Duplicate *********************** */
-static void node_duplicate_reparent_recursive(bNode *node)
+static void node_duplicate_reparent_recursive(const Map<const bNode *, bNode *> &node_map,
+ bNode *node)
{
bNode *parent;
@@ -1294,15 +1270,15 @@ static void node_duplicate_reparent_recursive(bNode *node)
for (parent = node->parent; parent; parent = parent->parent) {
if (parent->flag & SELECT) {
if (!(parent->flag & NODE_TEST)) {
- node_duplicate_reparent_recursive(parent);
+ node_duplicate_reparent_recursive(node_map, parent);
}
break;
}
}
/* reparent node copy to parent copy */
if (parent) {
- nodeDetachNode(node->new_node);
- nodeAttachNode(node->new_node, parent->new_node);
+ nodeDetachNode(node_map.lookup(node));
+ nodeAttachNode(node_map.lookup(node), node_map.lookup(parent));
}
}
@@ -1312,17 +1288,18 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = snode->edittree;
const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
- bool do_tag_update = false;
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
bNode *lastnode = (bNode *)ntree->nodes.last;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & SELECT) {
- BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT);
-
- /* To ensure redraws or re-renders happen. */
- ED_node_tag_update_id(snode->id);
+ bNode *new_node = blender::bke::node_copy_with_mapping(
+ ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
+ node_map.add_new(node, new_node);
}
/* make sure we don't copy new nodes again! */
@@ -1331,8 +1308,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
}
}
- /* Copy links between selected nodes.
- * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */
+ /* Copy links between selected nodes. */
bNodeLink *lastlink = (bNodeLink *)ntree->links.last;
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
/* This creates new links between copied nodes.
@@ -1340,13 +1316,13 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
*/
if (link->tonode && (link->tonode->flag & NODE_SELECT) &&
(keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT)))) {
- bNodeLink *newlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "bNodeLink");
+ bNodeLink *newlink = MEM_cnew<bNodeLink>("bNodeLink");
newlink->flag = link->flag;
- newlink->tonode = link->tonode->new_node;
- newlink->tosock = link->tosock->new_sock;
+ newlink->tonode = node_map.lookup(link->tonode);
+ newlink->tosock = socket_map.lookup(link->tosock);
if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) {
- newlink->fromnode = link->fromnode->new_node;
- newlink->fromsock = link->fromsock->new_sock;
+ newlink->fromnode = node_map.lookup(link->fromnode);
+ newlink->fromsock = socket_map.lookup(link->fromsock);
}
else {
/* input node not copied, this keeps the original input linked */
@@ -1370,7 +1346,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
/* reparent copied nodes */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if ((node->flag & SELECT) && !(node->flag & NODE_TEST)) {
- node_duplicate_reparent_recursive(node);
+ node_duplicate_reparent_recursive(node_map, node);
}
/* only has to check old nodes */
@@ -1383,13 +1359,11 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & SELECT) {
/* has been set during copy above */
- bNode *newnode = node->new_node;
+ bNode *newnode = node_map.lookup(node);
nodeSetSelected(node, false);
node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE);
nodeSetSelected(newnode, true);
-
- do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, newnode));
}
/* make sure we don't copy new nodes again! */
@@ -1398,13 +1372,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(C, snode);
- if (do_tag_update) {
- snode_dag_update(C, snode);
- }
-
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1426,7 +1394,7 @@ void NODE_OT_duplicate(wmOperatorType *ot)
ot->srna, "keep_inputs", false, "Keep Inputs", "Keep the input links to duplicated nodes");
}
-bool ED_node_select_check(const ListBase *lb)
+static bool node_select_check(const ListBase *lb)
{
LISTBASE_FOREACH (const bNode *, node, lb) {
if (node->flag & NODE_SELECT) {
@@ -1437,10 +1405,10 @@ bool ED_node_select_check(const ListBase *lb)
return false;
}
-void ED_node_select_all(ListBase *lb, int action)
+void node_select_all(ListBase *lb, int action)
{
if (action == SEL_TOGGLE) {
- if (ED_node_select_check(lb)) {
+ if (node_select_check(lb)) {
action = SEL_DESELECT;
}
else {
@@ -1495,8 +1463,7 @@ static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1663,7 +1630,7 @@ static int node_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op))
node_flag_toggle_exec(snode, NODE_PREVIEW);
- snode_notify(C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1742,7 +1709,7 @@ static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -1770,23 +1737,17 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
- bool do_tag_update = false;
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
- /* Only allow muting of nodes having a mute func! */
- if ((node->flag & SELECT) && node->typeinfo->update_internal_links) {
+ if ((node->flag & SELECT) && !node->typeinfo->no_muting) {
node->flag ^= NODE_MUTED;
- snode_update(snode, node);
- do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node));
+ BKE_ntree_update_tag_node_mute(snode->edittree, node);
}
}
- snode_notify(C, snode);
- if (do_tag_update) {
- snode_dag_update(C, snode);
- }
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1812,23 +1773,16 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
- bool do_tag_update = false;
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) {
if (node->flag & SELECT) {
- do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node));
nodeRemoveNode(bmain, snode->edittree, node, true);
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(C, snode);
- if (do_tag_update) {
- snode_dag_update(C, snode);
- }
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1872,10 +1826,7 @@ static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1910,10 +1861,7 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1960,7 +1908,7 @@ static int node_output_file_add_socket_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "file_path", file_path);
ntreeCompositOutputFileAddSocket(ntree, node, file_path, &scene->r.im_format);
- snode_notify(C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -2009,7 +1957,7 @@ static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *U
return OPERATOR_CANCELLED;
}
- snode_notify(C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
return OPERATOR_FINISHED;
}
@@ -2076,7 +2024,7 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op)
nimf->active_input++;
}
- snode_notify(C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -2105,18 +2053,15 @@ void NODE_OT_output_file_move_active_socket(wmOperatorType *ot)
static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
- if (!ntree) {
- return OPERATOR_CANCELLED;
- }
- bNode *node = nodeGetActive(ntree);
+ bNode *node = nodeGetActive(&ntree);
if (!node) {
return OPERATOR_CANCELLED;
}
- LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node_iter, &ntree.nodes) {
if (node_iter->flag & NODE_SELECT && node_iter != node) {
if (node->flag & NODE_CUSTOM_COLOR) {
node_iter->flag |= NODE_CUSTOM_COLOR;
@@ -2128,7 +2073,7 @@ static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ED_node_sort(ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -2162,47 +2107,48 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op))
BKE_node_clipboard_clear();
BKE_node_clipboard_init(ntree);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & SELECT) {
/* No ID refcounting, this node is virtual,
* detached from any actual Blender data currently. */
- bNode *new_node = BKE_node_copy_store_new_pointers(
- nullptr, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN);
- BKE_node_clipboard_add_node(new_node);
+ bNode *new_node = blender::bke::node_copy_with_mapping(nullptr,
+ *node,
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_MAIN,
+ false,
+ socket_map);
+ node_map.add_new(node, new_node);
}
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->flag & SELECT) {
- bNode *new_node = node->new_node;
-
- /* ensure valid pointers */
- if (new_node->parent) {
- /* parent pointer must be redirected to new node or detached if parent is
- * not copied */
- if (new_node->parent->flag & NODE_SELECT) {
- new_node->parent = new_node->parent->new_node;
- }
- else {
- nodeDetachNode(new_node);
- }
+ for (bNode *new_node : node_map.values()) {
+ BKE_node_clipboard_add_node(new_node);
+
+ /* Parent pointer must be redirected to new node or detached if parent is not copied. */
+ if (new_node->parent) {
+ if (node_map.contains(new_node->parent)) {
+ new_node->parent = node_map.lookup(new_node->parent);
+ }
+ else {
+ nodeDetachNode(new_node);
}
}
}
- /* Copy links between selected nodes.
- * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */
-
+ /* Copy links between selected nodes. */
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- /* This creates new links between copied nodes. */
- if (link->tonode && (link->tonode->flag & NODE_SELECT) && link->fromnode &&
- (link->fromnode->flag & NODE_SELECT)) {
- bNodeLink *newlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "bNodeLink");
+ BLI_assert(link->tonode);
+ BLI_assert(link->fromnode);
+ if (link->tonode->flag & NODE_SELECT && link->fromnode->flag & NODE_SELECT) {
+ bNodeLink *newlink = MEM_cnew<bNodeLink>(__func__);
newlink->flag = link->flag;
- newlink->tonode = link->tonode->new_node;
- newlink->tosock = link->tosock->new_sock;
- newlink->fromnode = link->fromnode->new_node;
- newlink->fromsock = link->fromsock->new_sock;
+ newlink->tonode = node_map.lookup(link->tonode);
+ newlink->tosock = socket_map.lookup(link->tosock);
+ newlink->fromnode = node_map.lookup(link->fromnode);
+ newlink->fromsock = socket_map.lookup(link->fromsock);
BKE_node_clipboard_add_link(newlink);
}
@@ -2286,7 +2232,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
/* deselect old nodes */
- node_deselect_all(snode);
+ node_deselect_all(*snode);
/* calculate "barycenter" for placing on mouse cursor */
float center[2] = {0.0f, 0.0f};
@@ -2297,35 +2243,38 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
}
mul_v2_fl(center, 1.0 / num_nodes);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
/* copy nodes from clipboard */
LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) {
- bNode *new_node = BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT);
+ bNode *new_node = blender::bke::node_copy_with_mapping(
+ ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
+ node_map.add_new(node, new_node);
+ }
+ for (bNode *new_node : node_map.values()) {
/* pasted nodes are selected */
nodeSetSelected(new_node, true);
- }
- /* reparent copied nodes */
- LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) {
- bNode *new_node = node->new_node;
+ /* The parent pointer must be redirected to new node. */
if (new_node->parent) {
- new_node->parent = new_node->parent->new_node;
+ if (node_map.contains(new_node->parent)) {
+ new_node->parent = node_map.lookup(new_node->parent);
+ }
}
}
LISTBASE_FOREACH (bNodeLink *, link, clipboard_links_lb) {
nodeAddLink(ntree,
- link->fromnode->new_node,
- link->fromsock->new_sock,
- link->tonode->new_node,
- link->tosock->new_sock);
+ node_map.lookup(link->fromnode),
+ socket_map.lookup(link->fromsock),
+ node_map.lookup(link->tonode),
+ socket_map.lookup(link->tosock));
}
Main *bmain = CTX_data_main(C);
- ntreeUpdateTree(bmain, snode->edittree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
/* Pasting nodes can create arbitrary new relations, because nodes can reference IDs. */
DEG_relations_tag_update(bmain);
@@ -2393,10 +2342,7 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op)
/* make the new socket active */
sock->flag |= SELECT;
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2443,10 +2389,7 @@ static int ntree_socket_remove_exec(bContext *C, wmOperator *op)
active_sock->flag |= SELECT;
}
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2497,7 +2440,7 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op)
/* Need the extra update here because the loop above does not check for valid links in the node
* group we're currently editing. */
- ntree->update |= NTREE_UPDATE_GROUP | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_interface(ntree);
/* Deactivate sockets. */
LISTBASE_FOREACH (bNodeSocket *, socket_iter, sockets) {
@@ -2506,10 +2449,7 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op)
/* Make the new socket active. */
iosock->flag |= SELECT;
- ntreeUpdateTree(main, ntree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, main, ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2620,11 +2560,8 @@ static int ntree_socket_move_exec(bContext *C, wmOperator *op)
}
}
- ntree->update |= NTREE_UPDATE_GROUP;
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ BKE_ntree_update_tag_interface(ntree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2855,7 +2792,7 @@ static int viewer_border_exec(bContext *C, wmOperator *op)
btree->flag |= NTREE_VIEWER_BORDER;
}
- snode_notify(C, snode);
+ ED_node_tree_propagate_change(C, bmain, btree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
}
else {
@@ -2895,7 +2832,7 @@ static int clear_viewer_border_exec(bContext *C, wmOperator *UNUSED(op))
bNodeTree *btree = snode->nodetree;
btree->flag &= ~NTREE_VIEWER_BORDER;
- snode_notify(C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), btree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -2940,7 +2877,7 @@ static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op))
ntreeCompositCryptomatteAddSocket(ntree, node);
- snode_notify(C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
return OPERATOR_FINISHED;
}
@@ -2986,7 +2923,7 @@ static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(o
return OPERATOR_CANCELLED;
}
- snode_notify(C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
return OPERATOR_FINISHED;
}
@@ -3005,3 +2942,4 @@ void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc
index 411719cf6c0..542e6fd748f 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -33,24 +33,24 @@
#include "RNA_access.h"
#include "RNA_enum_types.h"
+#include "ED_screen.h"
#include "ED_undo.h"
#include "BLT_translation.h"
#include "UI_interface.h"
+#include "UI_interface.hh"
#include "UI_resources.h"
#include "NOD_geometry_nodes_eval_log.hh"
-#include "node_intern.h"
+#include "node_intern.hh"
-using blender::IndexRange;
-using blender::Map;
-using blender::Set;
-using blender::StringRef;
namespace geo_log = blender::nodes::geometry_nodes_eval_log;
using geo_log::GeometryAttributeInfo;
+namespace blender::ed::space_node {
+
struct AttributeSearchData {
const bNodeTree *tree;
const bNode *node;
@@ -60,43 +60,13 @@ struct AttributeSearchData {
/* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */
BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, "");
-static StringRef attribute_data_type_string(const CustomDataType type)
-{
- const char *name = nullptr;
- RNA_enum_name_from_value(rna_enum_attribute_type_items, type, &name);
- return StringRef(IFACE_(name));
-}
-
-static StringRef attribute_domain_string(const AttributeDomain domain)
-{
- const char *name = nullptr;
- RNA_enum_name_from_value(rna_enum_attribute_domain_items, domain, &name);
- return StringRef(IFACE_(name));
-}
-
-/* Unicode arrow. */
-#define MENU_SEP "\xe2\x96\xb6"
-
-static bool attribute_search_item_add(uiSearchItems *items, const GeometryAttributeInfo &item)
-{
- const StringRef data_type_name = attribute_data_type_string(item.data_type);
- const StringRef domain_name = attribute_domain_string(item.domain);
- std::string search_item_text = domain_name + " " + MENU_SEP + item.name + UI_SEP_CHAR +
- data_type_name;
-
- return UI_search_item_add(
- items, search_item_text.c_str(), (void *)&item, ICON_NONE, UI_BUT_HAS_SEP_CHAR, 0);
-}
-
-static GeometryAttributeInfo &get_dummy_item_info()
-{
- static GeometryAttributeInfo info;
- return info;
-}
-
static void attribute_search_update_fn(
const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
{
+ if (ED_screen_animation_playing(CTX_wm_manager(C))) {
+ return;
+ }
+
AttributeSearchData *data = static_cast<AttributeSearchData *>(arg);
SpaceNode *snode = CTX_wm_space_node(C);
@@ -107,55 +77,14 @@ static void attribute_search_update_fn(
}
blender::Vector<const GeometryAttributeInfo *> infos = node_log->lookup_available_attributes();
- GeometryAttributeInfo &dummy_info = get_dummy_item_info();
-
- /* Any string may be valid, so add the current search string along with the hints. */
- if (str[0] != '\0') {
- bool contained = false;
- for (const GeometryAttributeInfo *attribute_info : infos) {
- if (attribute_info->name == str) {
- contained = true;
- break;
- }
- }
- if (!contained) {
- dummy_info.name = str;
- UI_search_item_add(items, str, &dummy_info, ICON_ADD, 0, 0);
- }
- }
-
- if (str[0] == '\0' && !is_first) {
- /* Allow clearing the text field when the string is empty, but not on the first pass,
- * or opening an attribute field for the first time would show this search item. */
- dummy_info.name = str;
- UI_search_item_add(items, str, &dummy_info, ICON_X, 0, 0);
- }
-
- /* Don't filter when the menu is first opened, but still run the search
- * so the items are in the same order they will appear in while searching. */
- const char *string = is_first ? "" : str;
-
- StringSearch *search = BLI_string_search_new();
- for (const GeometryAttributeInfo *item : infos) {
- BLI_string_search_add(search, item->name.c_str(), (void *)item);
- }
-
- GeometryAttributeInfo **filtered_items;
- const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items);
-
- for (const int i : IndexRange(filtered_amount)) {
- const GeometryAttributeInfo *item = filtered_items[i];
- if (!attribute_search_item_add(items, *item)) {
- break;
- }
- }
-
- MEM_freeN(filtered_items);
- BLI_string_search_free(search);
+ blender::ui::attribute_search_add_items(str, true, infos, items, is_first);
}
static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
{
+ if (ED_screen_animation_playing(CTX_wm_manager(C))) {
+ return;
+ }
if (item_v == nullptr) {
return;
}
@@ -169,13 +98,13 @@ static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
ED_undo_push(C, "Assign Attribute Name");
}
-void node_geometry_add_attribute_search_button(const bContext *UNUSED(C),
- const bNodeTree *node_tree,
- const bNode *node,
- PointerRNA *socket_ptr,
- uiLayout *layout)
+void node_geometry_add_attribute_search_button(const bContext &UNUSED(C),
+ const bNodeTree &node_tree,
+ const bNode &node,
+ PointerRNA &socket_ptr,
+ uiLayout &layout)
{
- uiBlock *block = uiLayoutGetBlock(layout);
+ uiBlock *block = uiLayoutGetBlock(&layout);
uiBut *but = uiDefIconTextButR(block,
UI_BTYPE_SEARCH_MENU,
0,
@@ -185,7 +114,7 @@ void node_geometry_add_attribute_search_button(const bContext *UNUSED(C),
0,
10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */
UI_UNIT_Y,
- socket_ptr,
+ &socket_ptr,
"default_value",
0,
0.0f,
@@ -194,11 +123,11 @@ void node_geometry_add_attribute_search_button(const bContext *UNUSED(C),
0.0f,
"");
- AttributeSearchData *data = OBJECT_GUARDED_NEW(
- AttributeSearchData, {node_tree, node, (bNodeSocket *)socket_ptr->data});
+ AttributeSearchData *data = MEM_new<AttributeSearchData>(
+ __func__, AttributeSearchData{&node_tree, &node, (bNodeSocket *)socket_ptr.data});
UI_but_func_search_set_results_are_suggestions(but, true);
- UI_but_func_search_set_sep_string(but, MENU_SEP);
+ UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP);
UI_but_func_search_set(but,
nullptr,
attribute_search_update_fn,
@@ -208,3 +137,5 @@ void node_geometry_add_attribute_search_button(const bContext *UNUSED(C),
attribute_search_exec_fn,
nullptr);
}
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_gizmo.c b/source/blender/editors/space_node/node_gizmo.cc
index e1deca54890..8c60d100b26 100644
--- a/source/blender/editors/space_node/node_gizmo.c
+++ b/source/blender/editors/space_node/node_gizmo.cc
@@ -18,7 +18,7 @@
* \ingroup spnode
*/
-#include <math.h>
+#include <cmath>
#include "BLI_math_matrix.h"
#include "BLI_math_vector.h"
@@ -41,7 +41,9 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "node_intern.h"
+#include "node_intern.hh"
+
+namespace blender::ed::space_node {
/* -------------------------------------------------------------------- */
/** \name Local Utilities
@@ -80,9 +82,9 @@ static void gizmo_node_backdrop_prop_matrix_get(const wmGizmo *UNUSED(gz),
wmGizmoProperty *gz_prop,
void *value_p)
{
- float(*matrix)[4] = value_p;
+ float(*matrix)[4] = (float(*)[4])value_p;
BLI_assert(gz_prop->type->array_length == 16);
- const SpaceNode *snode = gz_prop->custom_func.user_data;
+ const SpaceNode *snode = (const SpaceNode *)gz_prop->custom_func.user_data;
matrix[0][0] = snode->zoom;
matrix[1][1] = snode->zoom;
matrix[3][0] = snode->xof;
@@ -93,9 +95,9 @@ static void gizmo_node_backdrop_prop_matrix_set(const wmGizmo *UNUSED(gz),
wmGizmoProperty *gz_prop,
const void *value_p)
{
- const float(*matrix)[4] = value_p;
+ const float(*matrix)[4] = (const float(*)[4])value_p;
BLI_assert(gz_prop->type->array_length == 16);
- SpaceNode *snode = gz_prop->custom_func.user_data;
+ SpaceNode *snode = (SpaceNode *)gz_prop->custom_func.user_data;
snode->zoom = matrix[0][0];
snode->xof = matrix[3][0];
snode->yof = matrix[3][1];
@@ -122,9 +124,9 @@ static bool WIDGETGROUP_node_transform_poll(const bContext *C, wmGizmoGroupType
static void WIDGETGROUP_node_transform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
{
- wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__);
+ wmGizmoWrapper *wwrapper = (wmGizmoWrapper *)MEM_mallocN(sizeof(wmGizmoWrapper), __func__);
- wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL);
+ wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr);
RNA_enum_set(wwrapper->gizmo->ptr,
"transform",
@@ -139,11 +141,11 @@ static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmGizmoGroup *
wmGizmo *cage = ((wmGizmoWrapper *)gzgroup->customdata)->gizmo;
const ARegion *region = CTX_wm_region(C);
/* center is always at the origin */
- const float origin[3] = {region->winx / 2, region->winy / 2};
+ const float origin[3] = {float(region->winx / 2), float(region->winy / 2), 0.0f};
void *lock;
Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
if (ibuf) {
const float dims[2] = {
@@ -164,14 +166,12 @@ static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmGizmoGroup *
WM_gizmo_target_property_def_rna(cage, "scale", &nodeptr, "backdrop_zoom", -1);
#endif
- WM_gizmo_target_property_def_func(cage,
- "matrix",
- &(const struct wmGizmoPropertyFnParams){
- .value_get_fn = gizmo_node_backdrop_prop_matrix_get,
- .value_set_fn = gizmo_node_backdrop_prop_matrix_set,
- .range_get_fn = NULL,
- .user_data = snode,
- });
+ wmGizmoPropertyFnParams params{};
+ params.value_get_fn = gizmo_node_backdrop_prop_matrix_get;
+ params.value_set_fn = gizmo_node_backdrop_prop_matrix_set;
+ params.range_get_fn = nullptr;
+ params.user_data = snode;
+ WM_gizmo_target_property_def_func(cage, "matrix", &params);
}
else {
WM_gizmo_set_flag(cage, WM_GIZMO_HIDDEN, true);
@@ -262,12 +262,12 @@ static void gizmo_node_crop_prop_matrix_get(const wmGizmo *gz,
wmGizmoProperty *gz_prop,
void *value_p)
{
- float(*matrix)[4] = value_p;
+ float(*matrix)[4] = (float(*)[4])value_p;
BLI_assert(gz_prop->type->array_length == 16);
- struct NodeCropWidgetGroup *crop_group = gz->parent_gzgroup->customdata;
+ NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)gz->parent_gzgroup->customdata;
const float *dims = crop_group->state.dims;
- const bNode *node = gz_prop->custom_func.user_data;
- const NodeTwoXYs *nxy = node->storage;
+ const bNode *node = (const bNode *)gz_prop->custom_func.user_data;
+ const NodeTwoXYs *nxy = (const NodeTwoXYs *)node->storage;
bool is_relative = (bool)node->custom2;
rctf rct;
two_xy_to_rect(nxy, &rct, dims, is_relative);
@@ -281,12 +281,12 @@ static void gizmo_node_crop_prop_matrix_set(const wmGizmo *gz,
wmGizmoProperty *gz_prop,
const void *value_p)
{
- const float(*matrix)[4] = value_p;
+ const float(*matrix)[4] = (const float(*)[4])value_p;
BLI_assert(gz_prop->type->array_length == 16);
- struct NodeCropWidgetGroup *crop_group = gz->parent_gzgroup->customdata;
+ NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)gz->parent_gzgroup->customdata;
const float *dims = crop_group->state.dims;
- bNode *node = gz_prop->custom_func.user_data;
- NodeTwoXYs *nxy = node->storage;
+ bNode *node = (bNode *)gz_prop->custom_func.user_data;
+ NodeTwoXYs *nxy = (NodeTwoXYs *)node->storage;
bool is_relative = (bool)node->custom2;
rctf rct;
two_xy_to_rect(nxy, &rct, dims, is_relative);
@@ -294,15 +294,12 @@ static void gizmo_node_crop_prop_matrix_set(const wmGizmo *gz,
const bool ny = rct.ymin > rct.ymax;
BLI_rctf_resize(&rct, fabsf(matrix[0][0]), fabsf(matrix[1][1]));
BLI_rctf_recenter(&rct, (matrix[3][0] / dims[0]) + 0.5f, (matrix[3][1] / dims[1]) + 0.5f);
- BLI_rctf_isect(
- &(rctf){
- .xmin = 0,
- .ymin = 0,
- .xmax = 1,
- .ymax = 1,
- },
- &rct,
- &rct);
+ rctf rct_isect{};
+ rct_isect.xmin = 0;
+ rct_isect.xmax = 1;
+ rct_isect.ymin = 0;
+ rct_isect.ymax = 1;
+ BLI_rctf_isect(&rct_isect, &rct, &rct);
if (nx) {
SWAP(float, rct.xmin, rct.xmax);
}
@@ -337,10 +334,10 @@ static bool WIDGETGROUP_node_crop_poll(const bContext *C, wmGizmoGroupType *UNUS
static void WIDGETGROUP_node_crop_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
{
- struct NodeCropWidgetGroup *crop_group = MEM_mallocN(sizeof(struct NodeCropWidgetGroup),
- __func__);
+ struct NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)MEM_mallocN(
+ sizeof(struct NodeCropWidgetGroup), __func__);
- crop_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL);
+ crop_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr);
RNA_enum_set(crop_group->border->ptr,
"transform",
@@ -352,7 +349,7 @@ static void WIDGETGROUP_node_crop_setup(const bContext *UNUSED(C), wmGizmoGroup
static void WIDGETGROUP_node_crop_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
ARegion *region = CTX_wm_region(C);
- wmGizmo *gz = gzgroup->gizmos.first;
+ wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first;
SpaceNode *snode = CTX_wm_space_node(C);
@@ -362,12 +359,12 @@ static void WIDGETGROUP_node_crop_draw_prepare(const bContext *C, wmGizmoGroup *
static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
Main *bmain = CTX_data_main(C);
- struct NodeCropWidgetGroup *crop_group = gzgroup->customdata;
+ NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)gzgroup->customdata;
wmGizmo *gz = crop_group->border;
void *lock;
Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
if (ibuf) {
crop_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f;
@@ -385,14 +382,12 @@ static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmGizmoGroup *gzgro
crop_group->update_data.prop = RNA_struct_find_property(&crop_group->update_data.ptr,
"relative");
- WM_gizmo_target_property_def_func(gz,
- "matrix",
- &(const struct wmGizmoPropertyFnParams){
- .value_get_fn = gizmo_node_crop_prop_matrix_get,
- .value_set_fn = gizmo_node_crop_prop_matrix_set,
- .range_get_fn = NULL,
- .user_data = node,
- });
+ wmGizmoPropertyFnParams params{};
+ params.value_get_fn = gizmo_node_crop_prop_matrix_get;
+ params.value_set_fn = gizmo_node_crop_prop_matrix_set;
+ params.range_get_fn = nullptr;
+ params.user_data = node;
+ WM_gizmo_target_property_def_func(gz, "matrix", &params);
}
else {
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
@@ -450,10 +445,10 @@ static bool WIDGETGROUP_node_sbeam_poll(const bContext *C, wmGizmoGroupType *UNU
static void WIDGETGROUP_node_sbeam_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
{
- struct NodeSunBeamsWidgetGroup *sbeam_group = MEM_mallocN(sizeof(struct NodeSunBeamsWidgetGroup),
- __func__);
+ NodeSunBeamsWidgetGroup *sbeam_group = (NodeSunBeamsWidgetGroup *)MEM_mallocN(
+ sizeof(NodeSunBeamsWidgetGroup), __func__);
- sbeam_group->gizmo = WM_gizmo_new("GIZMO_GT_move_3d", gzgroup, NULL);
+ sbeam_group->gizmo = WM_gizmo_new("GIZMO_GT_move_3d", gzgroup, nullptr);
wmGizmo *gz = sbeam_group->gizmo;
RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_CROSS_2D);
@@ -465,9 +460,9 @@ static void WIDGETGROUP_node_sbeam_setup(const bContext *UNUSED(C), wmGizmoGroup
static void WIDGETGROUP_node_sbeam_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
- struct NodeSunBeamsWidgetGroup *sbeam_group = gzgroup->customdata;
+ NodeSunBeamsWidgetGroup *sbeam_group = (NodeSunBeamsWidgetGroup *)gzgroup->customdata;
ARegion *region = CTX_wm_region(C);
- wmGizmo *gz = gzgroup->gizmos.first;
+ wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first;
SpaceNode *snode = CTX_wm_space_node(C);
@@ -478,12 +473,12 @@ static void WIDGETGROUP_node_sbeam_draw_prepare(const bContext *C, wmGizmoGroup
static void WIDGETGROUP_node_sbeam_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
Main *bmain = CTX_data_main(C);
- struct NodeSunBeamsWidgetGroup *sbeam_group = gzgroup->customdata;
+ NodeSunBeamsWidgetGroup *sbeam_group = (NodeSunBeamsWidgetGroup *)gzgroup->customdata;
wmGizmo *gz = sbeam_group->gizmo;
void *lock;
Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
if (ibuf) {
sbeam_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f;
@@ -555,12 +550,12 @@ static bool WIDGETGROUP_node_corner_pin_poll(const bContext *C, wmGizmoGroupType
static void WIDGETGROUP_node_corner_pin_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
{
- struct NodeCornerPinWidgetGroup *cpin_group = MEM_mallocN(
- sizeof(struct NodeCornerPinWidgetGroup), __func__);
+ NodeCornerPinWidgetGroup *cpin_group = (NodeCornerPinWidgetGroup *)MEM_mallocN(
+ sizeof(NodeCornerPinWidgetGroup), __func__);
const wmGizmoType *gzt_move_3d = WM_gizmotype_find("GIZMO_GT_move_3d", false);
for (int i = 0; i < 4; i++) {
- cpin_group->gizmos[i] = WM_gizmo_new_ptr(gzt_move_3d, gzgroup, NULL);
+ cpin_group->gizmos[i] = WM_gizmo_new_ptr(gzt_move_3d, gzgroup, nullptr);
wmGizmo *gz = cpin_group->gizmos[i];
RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_CROSS_2D);
@@ -573,7 +568,7 @@ static void WIDGETGROUP_node_corner_pin_setup(const bContext *UNUSED(C), wmGizmo
static void WIDGETGROUP_node_corner_pin_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
- struct NodeCornerPinWidgetGroup *cpin_group = gzgroup->customdata;
+ NodeCornerPinWidgetGroup *cpin_group = (NodeCornerPinWidgetGroup *)gzgroup->customdata;
ARegion *region = CTX_wm_region(C);
SpaceNode *snode = CTX_wm_space_node(C);
@@ -591,11 +586,11 @@ static void WIDGETGROUP_node_corner_pin_draw_prepare(const bContext *C, wmGizmoG
static void WIDGETGROUP_node_corner_pin_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
Main *bmain = CTX_data_main(C);
- struct NodeCornerPinWidgetGroup *cpin_group = gzgroup->customdata;
+ NodeCornerPinWidgetGroup *cpin_group = (NodeCornerPinWidgetGroup *)gzgroup->customdata;
void *lock;
Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
if (ibuf) {
cpin_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f;
@@ -606,7 +601,7 @@ static void WIDGETGROUP_node_corner_pin_refresh(const bContext *C, wmGizmoGroup
/* need to set property here for undo. TODO: would prefer to do this in _init. */
int i = 0;
- for (bNodeSocket *sock = node->inputs.first; sock && i < 4; sock = sock->next) {
+ for (bNodeSocket *sock = (bNodeSocket *)node->inputs.first; sock && i < 4; sock = sock->next) {
if (sock->type == SOCK_VECTOR) {
wmGizmo *gz = cpin_group->gizmos[i++];
@@ -643,3 +638,5 @@ void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc
index d7541d8f512..73e419d667a 100644
--- a/source/blender/editors/space_node/node_group.cc
+++ b/source/blender/editors/space_node/node_group.cc
@@ -30,8 +30,9 @@
#include "BLI_linklist.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_string.h"
+#include "BLI_vector.hh"
#include "BLT_translation.h"
@@ -40,6 +41,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "DEG_depsgraph_build.h"
@@ -58,7 +60,9 @@
#include "NOD_common.h"
#include "NOD_socket.h"
-#include "node_intern.h" /* own include */
+#include "node_intern.hh" /* own include */
+
+namespace blender::ed::space_node {
/* -------------------------------------------------------------------- */
/** \name Local Utilities
@@ -214,38 +218,34 @@ static void animation_basepath_change_free(AnimationBasePathChange *basepath_cha
MEM_freeN(basepath_change);
}
-/* returns 1 if its OK */
-static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
+/**
+ * \return True if successful.
+ */
+static bool node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
{
- /* Clear new pointers, set in #ntreeCopyTree_ex_new_pointers. */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- node->new_node = nullptr;
- }
-
ListBase anim_basepaths = {nullptr, nullptr};
- LinkNode *nodes_delayed_free = nullptr;
- bNodeTree *ngroup = (bNodeTree *)gnode->id;
+ Vector<bNode *> nodes_delayed_free;
+ const bNodeTree *ngroup = reinterpret_cast<const bNodeTree *>(gnode->id);
- /* wgroup is a temporary copy of the NodeTree we're merging in
- * - all of wgroup's nodes are copied across to their new home
- * - ngroup (i.e. the source NodeTree) is left unscathed
- * - temp copy. do change ID usercount for the copies
+ /* `wgroup` is a temporary copy of the #NodeTree we're merging in
+ * - All of wgroup's nodes are copied across to their new home.
+ * - `ngroup` (i.e. the source NodeTree) is left unscathed.
+ * - Temp copy. do change ID user-count for the copies.
*/
- bNodeTree *wgroup = ntreeCopyTree_ex_new_pointers(ngroup, bmain, true);
+ bNodeTree *wgroup = ntreeCopyTree(bmain, ngroup);
- /* Add the nodes into the ntree */
+ /* Add the nodes into the `ntree`. */
LISTBASE_FOREACH_MUTABLE (bNode *, node, &wgroup->nodes) {
/* Remove interface nodes.
* This also removes remaining links to and from interface nodes.
*/
if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
/* We must delay removal since sockets will reference this node. see: T52092 */
- BLI_linklist_prepend(&nodes_delayed_free, node);
+ nodes_delayed_free.append(node);
}
- /* keep track of this node's RNA "base" path (the part of the path identifying the node)
- * if the old nodetree has animation data which potentially covers this node
- */
+ /* Keep track of this node's RNA "base" path (the part of the path identifying the node)
+ * if the old node-tree has animation data which potentially covers this node. */
const char *old_animation_basepath = nullptr;
if (wgroup->adt) {
PointerRNA ptr;
@@ -256,6 +256,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
/* migrate node */
BLI_remlink(&wgroup->nodes, node);
BLI_addtail(&ntree->nodes, node);
+ BKE_ntree_update_tag_node_new(ntree, node);
/* ensure unique node name in the node tree */
nodeUniqueName(ntree, node);
@@ -282,6 +283,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &wgroup->links) {
BLI_remlink(&wgroup->links, link);
BLI_addtail(&ntree->links, link);
+ BKE_ntree_update_tag_link_added(ntree, link);
}
bNodeLink *glinks_last = (bNodeLink *)ntree->links.last;
@@ -383,17 +385,14 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
}
}
- while (nodes_delayed_free) {
- bNode *node = (bNode *)BLI_linklist_pop(&nodes_delayed_free);
+ for (bNode *node : nodes_delayed_free) {
nodeRemoveNode(bmain, ntree, node, false);
}
/* delete the group instance and dereference group tree */
nodeRemoveNode(bmain, ntree, gnode, true);
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
-
- return 1;
+ return true;
}
static int node_group_ungroup_exec(bContext *C, wmOperator *op)
@@ -410,16 +409,13 @@ static int node_group_ungroup_exec(bContext *C, wmOperator *op)
}
if (gnode->id && node_group_ungroup(bmain, snode->edittree, gnode)) {
- ntreeUpdateTree(bmain, snode->nodetree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), nullptr);
}
else {
BKE_report(op->reports, RPT_WARNING, "Cannot ungroup");
return OPERATOR_CANCELLED;
}
- snode_notify(C, snode);
- snode_dag_update(C, snode);
-
return OPERATOR_FINISHED;
}
@@ -444,24 +440,24 @@ void NODE_OT_group_ungroup(wmOperatorType *ot)
/** \name Separate Operator
* \{ */
-/* returns 1 if its OK */
-static int node_group_separate_selected(
- Main *bmain, bNodeTree *ntree, bNodeTree *ngroup, float offx, float offy, int make_copy)
+/**
+ * \return True if successful.
+ */
+static bool node_group_separate_selected(
+ Main &bmain, bNodeTree &ntree, bNodeTree &ngroup, const float2 &offset, const bool make_copy)
{
/* deselect all nodes in the target tree */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
nodeSetSelected(node, false);
}
- /* clear new pointers, set in BKE_node_copy_ex(). */
- LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
- node->new_node = nullptr;
- }
-
ListBase anim_basepaths = {nullptr, nullptr};
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
/* add selected nodes into the ntree */
- LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup->nodes) {
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup.nodes) {
if (!(node->flag & NODE_SELECT)) {
continue;
}
@@ -475,21 +471,22 @@ static int node_group_separate_selected(
bNode *newnode;
if (make_copy) {
/* make a copy */
- newnode = BKE_node_copy_store_new_pointers(ngroup, node, LIB_ID_COPY_DEFAULT);
+ newnode = blender::bke::node_copy_with_mapping(
+ &ngroup, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
+ node_map.add_new(node, newnode);
}
else {
/* use the existing node */
newnode = node;
}
- /* keep track of this node's RNA "base" path (the part of the path identifying the node)
- * if the old nodetree has animation data which potentially covers this node
- */
- if (ngroup->adt) {
+ /* Keep track of this node's RNA "base" path (the part of the path identifying the node)
+ * if the old node-tree has animation data which potentially covers this node. */
+ if (ngroup.adt) {
PointerRNA ptr;
char *path;
- RNA_pointer_create(&ngroup->id, &RNA_Node, newnode, &ptr);
+ RNA_pointer_create(&ngroup.id, &RNA_Node, newnode, &ptr);
path = RNA_path_from_ID_to_struct(&ptr);
if (path) {
@@ -503,50 +500,50 @@ static int node_group_separate_selected(
}
/* migrate node */
- BLI_remlink(&ngroup->nodes, newnode);
- BLI_addtail(&ntree->nodes, newnode);
+ BLI_remlink(&ngroup.nodes, newnode);
+ BLI_addtail(&ntree.nodes, newnode);
/* ensure unique node name in the node tree */
- nodeUniqueName(ntree, newnode);
+ nodeUniqueName(&ntree, newnode);
if (!newnode->parent) {
- newnode->locx += offx;
- newnode->locy += offy;
+ newnode->locx += offset.x;
+ newnode->locy += offset.y;
}
}
/* add internal links to the ntree */
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ngroup->links) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ngroup.links) {
const bool fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT));
const bool toselect = (link->tonode && (link->tonode->flag & NODE_SELECT));
if (make_copy) {
/* make a copy of internal links */
if (fromselect && toselect) {
- nodeAddLink(ntree,
- link->fromnode->new_node,
- link->fromsock->new_sock,
- link->tonode->new_node,
- link->tosock->new_sock);
+ nodeAddLink(&ntree,
+ node_map.lookup(link->fromnode),
+ socket_map.lookup(link->fromsock),
+ node_map.lookup(link->tonode),
+ socket_map.lookup(link->tosock));
}
}
else {
/* move valid links over, delete broken links */
if (fromselect && toselect) {
- BLI_remlink(&ngroup->links, link);
- BLI_addtail(&ntree->links, link);
+ BLI_remlink(&ngroup.links, link);
+ BLI_addtail(&ntree.links, link);
}
else if (fromselect || toselect) {
- nodeRemLink(ngroup, link);
+ nodeRemLink(&ngroup, link);
}
}
}
/* and copy across the animation,
* note that the animation data's action can be nullptr here */
- if (ngroup->adt) {
+ if (ngroup.adt) {
/* now perform the moving */
- BKE_animdata_transfer_by_basepath(bmain, &ngroup->id, &ntree->id, &anim_basepaths);
+ BKE_animdata_transfer_by_basepath(&bmain, &ngroup.id, &ntree.id, &anim_basepaths);
/* paths + their wrappers need to be freed */
LISTBASE_FOREACH_MUTABLE (AnimationBasePathChange *, basepath_change, &anim_basepaths) {
@@ -554,12 +551,12 @@ static int node_group_separate_selected(
}
}
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_all(&ntree);
if (!make_copy) {
- ngroup->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_all(&ngroup);
}
- return 1;
+ return true;
}
enum eNodeGroupSeparateType {
@@ -590,18 +587,17 @@ static int node_group_separate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* get node tree offset */
- float offx, offy;
- space_node_group_offset(snode, &offx, &offy);
+ const float2 offset = space_node_group_offset(*snode);
switch (type) {
case NODE_GS_COPY:
- if (!node_group_separate_selected(bmain, nparent, ngroup, offx, offy, true)) {
+ if (!node_group_separate_selected(*bmain, *nparent, *ngroup, offset, true)) {
BKE_report(op->reports, RPT_WARNING, "Cannot separate nodes");
return OPERATOR_CANCELLED;
}
break;
case NODE_GS_MOVE:
- if (!node_group_separate_selected(bmain, nparent, ngroup, offx, offy, false)) {
+ if (!node_group_separate_selected(*bmain, *nparent, *ngroup, offset, false)) {
BKE_report(op->reports, RPT_WARNING, "Cannot separate nodes");
return OPERATOR_CANCELLED;
}
@@ -611,10 +607,7 @@ static int node_group_separate_exec(bContext *C, wmOperator *op)
/* switch to parent tree */
ED_node_tree_pop(snode);
- ntreeUpdateTree(CTX_data_main(C), snode->nodetree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), nullptr);
return OPERATOR_FINISHED;
}
@@ -660,16 +653,16 @@ void NODE_OT_group_separate(wmOperatorType *ot)
/** \name Make Group Operator
* \{ */
-static bool node_group_make_use_node(bNode *node, bNode *gnode)
+static bool node_group_make_use_node(bNode &node, bNode *gnode)
{
- return (node != gnode && !ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT) &&
- (node->flag & NODE_SELECT));
+ return (&node != gnode && !ELEM(node.type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT) &&
+ (node.flag & NODE_SELECT));
}
-static bool node_group_make_test_selected(bNodeTree *ntree,
+static bool node_group_make_test_selected(bNodeTree &ntree,
bNode *gnode,
const char *ntree_idname,
- struct ReportList *reports)
+ struct ReportList &reports)
{
int ok = true;
@@ -677,20 +670,20 @@ static bool node_group_make_test_selected(bNodeTree *ntree,
bNodeTree *ngroup = ntreeAddTree(nullptr, "Pseudo Node Group", ntree_idname);
/* check poll functions for selected nodes */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node_group_make_use_node(node, gnode)) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
+ if (node_group_make_use_node(*node, gnode)) {
const char *disabled_hint = nullptr;
if (node->typeinfo->poll_instance &&
!node->typeinfo->poll_instance(node, ngroup, &disabled_hint)) {
if (disabled_hint) {
- BKE_reportf(reports,
+ BKE_reportf(&reports,
RPT_WARNING,
"Can not add node '%s' in a group:\n %s",
node->name,
disabled_hint);
}
else {
- BKE_reportf(reports, RPT_WARNING, "Can not add node '%s' in a group", node->name);
+ BKE_reportf(&reports, RPT_WARNING, "Can not add node '%s' in a group", node->name);
}
ok = false;
break;
@@ -709,15 +702,15 @@ static bool node_group_make_test_selected(bNodeTree *ntree,
/* check if all connections are OK, no unselected node has both
* inputs and outputs to a selection */
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- if (node_group_make_use_node(link->fromnode, gnode)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (node_group_make_use_node(*link->fromnode, gnode)) {
link->tonode->done |= 1;
}
- if (node_group_make_use_node(link->tonode, gnode)) {
+ if (node_group_make_use_node(*link->tonode, gnode)) {
link->fromnode->done |= 2;
}
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (!(node->flag & NODE_SELECT) && node != gnode && node->done == 3) {
return false;
}
@@ -726,13 +719,13 @@ static bool node_group_make_test_selected(bNodeTree *ntree,
}
static int node_get_selected_minmax(
- bNodeTree *ntree, bNode *gnode, float *min, float *max, bool use_size)
+ bNodeTree &ntree, bNode *gnode, float2 &min, float2 &max, bool use_size)
{
int totselect = 0;
INIT_MINMAX2(min, max);
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node_group_make_use_node(node, gnode)) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
+ if (node_group_make_use_node(*node, gnode)) {
float loc[2];
nodeToView(node, node->offsetx, node->offsety, &loc[0], &loc[1]);
minmax_v2v2_v2(min, max, loc);
@@ -753,9 +746,9 @@ static int node_get_selected_minmax(
return totselect;
}
-static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, bNode *gnode)
+static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, bNode *gnode)
{
- Main *bmain = CTX_data_main(C);
+ Main *bmain = CTX_data_main(&C);
bNodeTree *ngroup = (bNodeTree *)gnode->id;
bool expose_visible = false;
@@ -768,12 +761,12 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
nodeSetSelected(node, false);
}
- float center[2], min[2], max[2];
+ float2 center, min, max;
const int totselect = node_get_selected_minmax(ntree, gnode, min, max, false);
add_v2_v2v2(center, min, max);
mul_v2_fl(center, 0.5f);
- float real_min[2], real_max[2];
+ float2 real_min, real_max;
node_get_selected_minmax(ntree, gnode, real_min, real_max, true);
/* auto-add interface for "solo" nodes */
@@ -784,16 +777,15 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
ListBase anim_basepaths = {nullptr, nullptr};
/* move nodes over */
- LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
- if (node_group_make_use_node(node, gnode)) {
- /* keep track of this node's RNA "base" path (the part of the pat identifying the node)
- * if the old nodetree has animation data which potentially covers this node
- */
- if (ntree->adt) {
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree.nodes) {
+ if (node_group_make_use_node(*node, gnode)) {
+ /* Keep track of this node's RNA "base" path (the part of the pat identifying the node)
+ * if the old node-tree has animation data which potentially covers this node. */
+ if (ntree.adt) {
PointerRNA ptr;
char *path;
- RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
+ RNA_pointer_create(&ntree.id, &RNA_Node, node, &ptr);
path = RNA_path_from_ID_to_struct(&ptr);
if (path) {
@@ -807,8 +799,10 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
}
/* change node-collection membership */
- BLI_remlink(&ntree->nodes, node);
+ BLI_remlink(&ntree.nodes, node);
BLI_addtail(&ngroup->nodes, node);
+ BKE_ntree_update_tag_node_removed(&ntree);
+ BKE_ntree_update_tag_node_new(ngroup, node);
/* ensure unique node name in the ngroup */
nodeUniqueName(ngroup, node);
@@ -816,8 +810,8 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
}
/* move animation data over */
- if (ntree->adt) {
- BKE_animdata_transfer_by_basepath(bmain, &ntree->id, &ngroup->id, &anim_basepaths);
+ if (ntree.adt) {
+ BKE_animdata_transfer_by_basepath(bmain, &ntree.id, &ngroup->id, &anim_basepaths);
/* paths + their wrappers need to be freed */
LISTBASE_FOREACH_MUTABLE (AnimationBasePathChange *, basepath_change, &anim_basepaths) {
@@ -829,36 +823,36 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
ntreeFreeCache(ngroup);
/* create input node */
- bNode *input_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_INPUT);
+ bNode *input_node = nodeAddStaticNode(&C, ngroup, NODE_GROUP_INPUT);
input_node->locx = real_min[0] - center[0] - offsetx;
input_node->locy = -offsety;
/* create output node */
- bNode *output_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_OUTPUT);
+ bNode *output_node = nodeAddStaticNode(&C, ngroup, NODE_GROUP_OUTPUT);
output_node->locx = real_max[0] - center[0] + offsetx * 0.25f;
output_node->locy = -offsety;
/* relink external sockets */
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
- int fromselect = node_group_make_use_node(link->fromnode, gnode);
- int toselect = node_group_make_use_node(link->tonode, gnode);
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
+ int fromselect = node_group_make_use_node(*link->fromnode, gnode);
+ int toselect = node_group_make_use_node(*link->tonode, gnode);
if ((fromselect && link->tonode == gnode) || (toselect && link->fromnode == gnode)) {
/* remove all links to/from the gnode.
* this can remove link information, but there's no general way to preserve it.
*/
- nodeRemLink(ntree, link);
+ nodeRemLink(&ntree, link);
}
else if (toselect && !fromselect) {
bNodeSocket *link_sock;
bNode *link_node;
- node_socket_skip_reroutes(&ntree->links, link->tonode, link->tosock, &link_node, &link_sock);
+ node_socket_skip_reroutes(&ntree.links, link->tonode, link->tosock, &link_node, &link_sock);
bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link_node, link_sock);
/* update the group node and interface node sockets,
* so the new interface socket can be linked.
*/
- node_group_update(ntree, gnode);
+ node_group_update(&ntree, gnode);
node_group_input_update(ngroup, input_node);
/* create new internal link */
@@ -887,13 +881,13 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
bNodeSocket *link_sock;
bNode *link_node;
node_socket_skip_reroutes(
- &ntree->links, link->fromnode, link->fromsock, &link_node, &link_sock);
+ &ntree.links, link->fromnode, link->fromsock, &link_node, &link_sock);
bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link_node, link_sock);
/* update the group node and interface node sockets,
* so the new interface socket can be linked.
*/
- node_group_update(ntree, gnode);
+ node_group_update(&ntree, gnode);
node_group_output_update(ngroup, output_node);
/* create new internal link */
@@ -908,19 +902,19 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
}
/* move internal links */
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
- int fromselect = node_group_make_use_node(link->fromnode, gnode);
- int toselect = node_group_make_use_node(link->tonode, gnode);
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
+ int fromselect = node_group_make_use_node(*link->fromnode, gnode);
+ int toselect = node_group_make_use_node(*link->tonode, gnode);
if (fromselect && toselect) {
- BLI_remlink(&ntree->links, link);
+ BLI_remlink(&ntree.links, link);
BLI_addtail(&ngroup->links, link);
}
}
/* move nodes in the group to the center */
LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
- if (node_group_make_use_node(node, gnode) && !node->parent) {
+ if (node_group_make_use_node(*node, gnode) && !node->parent) {
node->locx -= center[0];
node->locy -= center[1];
}
@@ -929,7 +923,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
/* Expose all unlinked sockets too but only the visible ones. */
if (expose_visible) {
LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
- if (node_group_make_use_node(node, gnode)) {
+ if (node_group_make_use_node(*node, gnode)) {
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
bool skip = false;
LISTBASE_FOREACH (bNodeLink *, link, &ngroup->links) {
@@ -980,32 +974,27 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
}
}
}
-
- /* update of the group tree */
- ngroup->update |= NTREE_UPDATE | NTREE_UPDATE_LINKS;
- /* update of the tree containing the group instance node */
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
}
-static bNode *node_group_make_from_selected(const bContext *C,
- bNodeTree *ntree,
+static bNode *node_group_make_from_selected(const bContext &C,
+ bNodeTree &ntree,
const char *ntype,
const char *ntreetype)
{
- Main *bmain = CTX_data_main(C);
+ Main *bmain = CTX_data_main(&C);
- float min[2], max[2];
+ float2 min, max;
const int totselect = node_get_selected_minmax(ntree, nullptr, min, max, false);
/* don't make empty group */
if (totselect == 0) {
return nullptr;
}
- /* new nodetree */
+ /* New node-tree. */
bNodeTree *ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype);
/* make group node */
- bNode *gnode = nodeAddNode(C, ntree, ntype);
+ bNode *gnode = nodeAddNode(&C, &ntree, ntype);
gnode->id = (ID *)ngroup;
gnode->locx = 0.5f * (min[0] + max[0]);
@@ -1013,45 +1002,38 @@ static bNode *node_group_make_from_selected(const bContext *C,
node_group_make_insert_selected(C, ntree, gnode);
- /* update of the tree containing the group instance node */
- ntree->update |= NTREE_UPDATE_NODES;
-
return gnode;
}
static int node_group_make_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
const char *ntree_idname = group_ntree_idname(C);
const char *node_idname = node_group_idname(C);
Main *bmain = CTX_data_main(C);
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- if (!node_group_make_test_selected(ntree, nullptr, ntree_idname, op->reports)) {
+ if (!node_group_make_test_selected(ntree, nullptr, ntree_idname, *op->reports)) {
return OPERATOR_CANCELLED;
}
- bNode *gnode = node_group_make_from_selected(C, ntree, node_idname, ntree_idname);
+ bNode *gnode = node_group_make_from_selected(*C, ntree, node_idname, ntree_idname);
if (gnode) {
bNodeTree *ngroup = (bNodeTree *)gnode->id;
- nodeSetActive(ntree, gnode);
+ nodeSetActive(&ntree, gnode);
if (ngroup) {
- ED_node_tree_push(snode, ngroup, gnode);
+ ED_node_tree_push(&snode, ngroup, gnode);
LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
- sort_multi_input_socket_links(snode, node, nullptr, nullptr);
+ sort_multi_input_socket_links(snode, *node, nullptr, nullptr);
}
- ntreeUpdateTree(bmain, ngroup);
}
}
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, bmain, nullptr);
/* We broke relations in node tree, need to rebuild them in the graphs. */
DEG_relations_tag_update(bmain);
@@ -1096,20 +1078,15 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
}
bNodeTree *ngroup = (bNodeTree *)gnode->id;
- if (!node_group_make_test_selected(ntree, gnode, ngroup->idname, op->reports)) {
+ if (!node_group_make_test_selected(*ntree, gnode, ngroup->idname, *op->reports)) {
return OPERATOR_CANCELLED;
}
- node_group_make_insert_selected(C, ntree, gnode);
+ node_group_make_insert_selected(*C, *ntree, gnode);
nodeSetActive(ntree, gnode);
ED_node_tree_push(snode, ngroup, gnode);
- ntreeUpdateTree(bmain, ngroup);
-
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, bmain, nullptr);
return OPERATOR_FINISHED;
}
@@ -1130,3 +1107,5 @@ void NODE_OT_group_insert(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
deleted file mode 100644
index f069038cc09..00000000000
--- a/source/blender/editors/space_node/node_intern.h
+++ /dev/null
@@ -1,343 +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) 2008 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup spnode
- */
-
-#pragma once
-
-#include "BKE_node.h"
-#include "UI_interface.h"
-#include "UI_view2d.h"
-#include <stddef.h> /* for size_t */
-
-/* internal exports only */
-
-struct ARegion;
-struct ARegionType;
-struct Main;
-struct NodeInsertOfsData;
-struct View2D;
-struct bContext;
-struct bNode;
-struct bNodeLink;
-struct bNodeSocket;
-struct wmGizmoGroupType;
-struct wmKeyConfig;
-struct wmWindow;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* temp data to pass on to modal */
-typedef struct bNodeLinkDrag {
- struct bNodeLinkDrag *next, *prev;
-
- /* List of links dragged by the operator.
- * NOTE: This is a list of LinkData structs on top of the actual bNodeLinks.
- * This way the links can be added to the node tree while being stored in this list.
- */
- ListBase links;
- bool from_multi_input_socket;
- int in_out;
-
- /** Temporarily stores the last picked link from multi-input socket operator. */
- struct bNodeLink *last_picked_multi_input_socket_link;
-
- /** Temporarily stores the last hovered socket for multi-input socket operator.
- * Store it to recalculate sorting after it is no longer hovered. */
- struct bNode *last_node_hovered_while_dragging_a_link;
-
- /* Data for edge panning */
- View2DEdgePanData pan_data;
-} bNodeLinkDrag;
-
-typedef struct SpaceNode_Runtime {
- float aspect;
-
- /** Mouse position for drawing socket-less links and adding nodes. */
- float cursor[2];
-
- /** For auto compositing. */
- bool recalc;
-
- /** Temporary data for modal linking operator. */
- struct ListBase linkdrag;
-
- /* XXX hack for translate_attach op-macros to pass data from transform op to insert_offset op */
- /** Temporary data for node insert offset (in UI called Auto-offset). */
- struct NodeInsertOfsData *iofsd;
-} SpaceNode_Runtime;
-
-/* space_node.c */
-
-/* transform between View2Ds in the tree path */
-void space_node_group_offset(struct SpaceNode *snode, float *x, float *y);
-
-/* node_draw.cc */
-float node_socket_calculate_height(const bNodeSocket *socket);
-void node_link_calculate_multi_input_position(const float socket_x,
- const float socket_y,
- const int index,
- const int total_inputs,
- float r[2]);
-
-int node_get_colorid(struct bNode *node);
-int node_get_resize_cursor(int directions);
-void node_draw_shadow(const struct SpaceNode *snode,
- const struct bNode *node,
- float radius,
- float alpha);
-void node_draw_default(const struct bContext *C,
- struct ARegion *region,
- struct SpaceNode *snode,
- struct bNodeTree *ntree,
- struct bNode *node,
- bNodeInstanceKey key);
-void node_draw_sockets(const struct View2D *v2d,
- const struct bContext *C,
- struct bNodeTree *ntree,
- struct bNode *node,
- bool draw_outputs,
- bool select_all);
-void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node);
-int node_select_area_default(struct bNode *node, int x, int y);
-int node_tweak_area_default(struct bNode *node, int x, int y);
-void node_socket_color_get(struct bContext *C,
- struct bNodeTree *ntree,
- struct PointerRNA *node_ptr,
- struct bNodeSocket *sock,
- float r_color[4]);
-void node_update_nodetree(const struct bContext *C, struct bNodeTree *ntree);
-void node_draw_nodetree(const struct bContext *C,
- struct ARegion *region,
- struct SpaceNode *snode,
- struct bNodeTree *ntree,
- bNodeInstanceKey parent_key);
-void node_draw_space(const bContext *C, ARegion *region);
-
-void node_set_cursor(struct wmWindow *win, struct SpaceNode *snode, float cursor[2]);
-/* DPI scaled coords */
-void node_to_view(const struct bNode *node, float x, float y, float *rx, float *ry);
-void node_to_updated_rect(const struct bNode *node, rctf *r_rect);
-void node_from_view(const struct bNode *node, float x, float y, float *rx, float *ry);
-
-/* node_toolbar.c */
-void node_toolbar_register(struct ARegionType *art);
-
-/* node_ops.c */
-void node_operatortypes(void);
-void node_keymap(struct wmKeyConfig *keyconf);
-
-/* node_select.c */
-void node_deselect_all(struct SpaceNode *snode);
-void node_socket_select(struct bNode *node, struct bNodeSocket *sock);
-void node_socket_deselect(struct bNode *node, struct bNodeSocket *sock, const bool deselect_node);
-void node_deselect_all_input_sockets(struct SpaceNode *snode, const bool deselect_nodes);
-void node_deselect_all_output_sockets(struct SpaceNode *snode, const bool deselect_nodes);
-void node_select_single(struct bContext *C, struct bNode *node);
-
-void NODE_OT_select(struct wmOperatorType *ot);
-void NODE_OT_select_all(struct wmOperatorType *ot);
-void NODE_OT_select_linked_to(struct wmOperatorType *ot);
-void NODE_OT_select_linked_from(struct wmOperatorType *ot);
-void NODE_OT_select_box(struct wmOperatorType *ot);
-void NODE_OT_select_circle(struct wmOperatorType *ot);
-void NODE_OT_select_lasso(struct wmOperatorType *ot);
-void NODE_OT_select_grouped(struct wmOperatorType *ot);
-void NODE_OT_select_same_type_step(struct wmOperatorType *ot);
-void NODE_OT_find_node(struct wmOperatorType *ot);
-
-/* node_view.c */
-int space_node_view_flag(struct bContext *C,
- struct SpaceNode *snode,
- ARegion *region,
- const int node_flag,
- const int smooth_viewtx);
-
-void NODE_OT_view_all(struct wmOperatorType *ot);
-void NODE_OT_view_selected(struct wmOperatorType *ot);
-void NODE_OT_geometry_node_view_legacy(struct wmOperatorType *ot);
-
-void NODE_OT_backimage_move(struct wmOperatorType *ot);
-void NODE_OT_backimage_zoom(struct wmOperatorType *ot);
-void NODE_OT_backimage_fit(struct wmOperatorType *ot);
-void NODE_OT_backimage_sample(struct wmOperatorType *ot);
-
-/* drawnode.c */
-void nodelink_batch_start(struct SpaceNode *snode);
-void nodelink_batch_end(struct SpaceNode *snode);
-
-void node_draw_link(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link);
-void node_draw_link_bezier(const struct View2D *v2d,
- const struct SpaceNode *snode,
- const struct bNodeLink *link,
- int th_col1,
- int th_col2,
- int th_col3);
-bool node_link_bezier_points(const struct View2D *v2d,
- const struct SpaceNode *snode,
- const struct bNodeLink *link,
- float coord_array[][2],
- const int resol);
-bool node_link_bezier_handles(const struct View2D *v2d,
- const struct SpaceNode *snode,
- const struct bNodeLink *link,
- float vec[4][2]);
-void draw_nodespace_back_pix(const struct bContext *C,
- struct ARegion *region,
- struct SpaceNode *snode,
- bNodeInstanceKey parent_key);
-
-/* node_add.c */
-bNode *node_add_node(
- const struct bContext *C, const char *idname, int type, float locx, float locy);
-void NODE_OT_add_reroute(struct wmOperatorType *ot);
-void NODE_OT_add_group(struct wmOperatorType *ot);
-void NODE_OT_add_object(struct wmOperatorType *ot);
-void NODE_OT_add_collection(struct wmOperatorType *ot);
-void NODE_OT_add_texture(struct wmOperatorType *ot);
-void NODE_OT_add_file(struct wmOperatorType *ot);
-void NODE_OT_add_mask(struct wmOperatorType *ot);
-void NODE_OT_new_node_tree(struct wmOperatorType *ot);
-
-/* node_group.c */
-const char *node_group_idname(struct bContext *C);
-void NODE_OT_group_make(struct wmOperatorType *ot);
-void NODE_OT_group_insert(struct wmOperatorType *ot);
-void NODE_OT_group_ungroup(struct wmOperatorType *ot);
-void NODE_OT_group_separate(struct wmOperatorType *ot);
-void NODE_OT_group_edit(struct wmOperatorType *ot);
-
-/* node_relationships.c */
-void sort_multi_input_socket_links(struct SpaceNode *snode,
- struct bNode *node,
- struct bNodeLink *drag_link,
- float cursor[2]);
-bool node_connected_to_output(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
-
-void NODE_OT_link(struct wmOperatorType *ot);
-void NODE_OT_link_make(struct wmOperatorType *ot);
-void NODE_OT_links_cut(struct wmOperatorType *ot);
-void NODE_OT_links_detach(struct wmOperatorType *ot);
-void NODE_OT_links_mute(struct wmOperatorType *ot);
-
-void NODE_OT_parent_set(struct wmOperatorType *ot);
-void NODE_OT_join(struct wmOperatorType *ot);
-void NODE_OT_attach(struct wmOperatorType *ot);
-void NODE_OT_detach(struct wmOperatorType *ot);
-
-void NODE_OT_link_viewer(struct wmOperatorType *ot);
-
-void NODE_OT_insert_offset(struct wmOperatorType *ot);
-
-/* node_edit.c */
-void snode_notify(struct bContext *C, struct SpaceNode *snode);
-void snode_dag_update(struct bContext *C, struct SpaceNode *snode);
-void snode_set_context(const struct bContext *C);
-
-void snode_update(struct SpaceNode *snode, struct bNode *node);
-bool composite_node_active(struct bContext *C);
-bool composite_node_editable(struct bContext *C);
-
-bool node_has_hidden_sockets(struct bNode *node);
-void node_set_hidden_sockets(struct SpaceNode *snode, bNode *node, int set);
-int node_render_changed_exec(bContext *, struct wmOperator *);
-int node_find_indicated_socket(struct SpaceNode *snode,
- struct bNode **nodep,
- struct bNodeSocket **sockp,
- const float cursor[2],
- int in_out);
-float node_link_dim_factor(const struct View2D *v2d, const struct bNodeLink *link);
-bool node_link_is_hidden_or_dimmed(const struct View2D *v2d, const struct bNodeLink *link);
-
-void NODE_OT_duplicate(struct wmOperatorType *ot);
-void NODE_OT_delete(struct wmOperatorType *ot);
-void NODE_OT_delete_reconnect(struct wmOperatorType *ot);
-void NODE_OT_resize(struct wmOperatorType *ot);
-
-void NODE_OT_mute_toggle(struct wmOperatorType *ot);
-void NODE_OT_hide_toggle(struct wmOperatorType *ot);
-void NODE_OT_hide_socket_toggle(struct wmOperatorType *ot);
-void NODE_OT_preview_toggle(struct wmOperatorType *ot);
-void NODE_OT_options_toggle(struct wmOperatorType *ot);
-void NODE_OT_node_copy_color(struct wmOperatorType *ot);
-
-void NODE_OT_read_viewlayers(struct wmOperatorType *ot);
-void NODE_OT_render_changed(struct wmOperatorType *ot);
-
-void NODE_OT_output_file_add_socket(struct wmOperatorType *ot);
-void NODE_OT_output_file_remove_active_socket(struct wmOperatorType *ot);
-void NODE_OT_output_file_move_active_socket(struct wmOperatorType *ot);
-
-void NODE_OT_switch_view_update(struct wmOperatorType *ot);
-
-/* NOTE: clipboard_cut is a simple macro of copy + delete. */
-void NODE_OT_clipboard_copy(struct wmOperatorType *ot);
-void NODE_OT_clipboard_paste(struct wmOperatorType *ot);
-
-void NODE_OT_tree_socket_add(struct wmOperatorType *ot);
-void NODE_OT_tree_socket_remove(struct wmOperatorType *ot);
-void NODE_OT_tree_socket_change_type(struct wmOperatorType *ot);
-void NODE_OT_tree_socket_move(struct wmOperatorType *ot);
-
-void NODE_OT_shader_script_update(struct wmOperatorType *ot);
-
-void NODE_OT_viewer_border(struct wmOperatorType *ot);
-void NODE_OT_clear_viewer_border(struct wmOperatorType *ot);
-
-/* node_widgets.c */
-void NODE_GGT_backdrop_transform(struct wmGizmoGroupType *gzgt);
-void NODE_GGT_backdrop_crop(struct wmGizmoGroupType *gzgt);
-void NODE_GGT_backdrop_sun_beams(struct wmGizmoGroupType *gzgt);
-void NODE_GGT_backdrop_corner_pin(struct wmGizmoGroupType *gzgt);
-
-void NODE_OT_cryptomatte_layer_add(struct wmOperatorType *ot);
-void NODE_OT_cryptomatte_layer_remove(struct wmOperatorType *ot);
-
-/* node_geometry_attribute_search.cc */
-void node_geometry_add_attribute_search_button(const struct bContext *C,
- const struct bNodeTree *node_tree,
- const struct bNode *node,
- struct PointerRNA *socket_ptr,
- struct uiLayout *layout);
-
-extern const char *node_context_dir[];
-
-/* XXXXXX */
-
-/* Nodes draw without dpi - the view zoom is flexible. */
-#define HIDDEN_RAD (0.75f * U.widget_unit)
-#define BASIS_RAD (0.2f * U.widget_unit)
-#define NODE_DYS (U.widget_unit / 2)
-#define NODE_DY U.widget_unit
-#define NODE_SOCKDY (0.1f * U.widget_unit)
-#define NODE_WIDTH(node) (node->width * UI_DPI_FAC)
-#define NODE_HEIGHT(node) (node->height * UI_DPI_FAC)
-#define NODE_MARGIN_X (1.10f * U.widget_unit)
-#define NODE_SOCKSIZE (0.25f * U.widget_unit)
-#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit)
-#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit)
-#define NODE_LINK_RESOL 12
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
new file mode 100644
index 00000000000..c161fc70402
--- /dev/null
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -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.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup spnode
+ */
+
+#pragma once
+
+#include "BLI_math_vec_types.hh"
+#include "BLI_vector.hh"
+
+#include "BKE_node.h"
+
+#include "UI_interface.h"
+#include "UI_interface.hh"
+#include "UI_view2d.h"
+
+struct ARegion;
+struct ARegionType;
+struct Main;
+struct NodeInsertOfsData;
+struct View2D;
+struct bContext;
+struct bNode;
+struct bNodeLink;
+struct bNodeSocket;
+struct wmGizmoGroupType;
+struct wmKeyConfig;
+struct wmWindow;
+
+/* Outside of blender namespace to avoid Python documentation build error with `ctypes`. */
+extern const char *node_context_dir[];
+
+namespace blender::ed::space_node {
+
+/** Temporary data used in node link drag modal operator. */
+struct bNodeLinkDrag {
+ /** Links dragged by the operator. */
+ Vector<bNodeLink *> links;
+ bool from_multi_input_socket;
+ eNodeSocketInOut in_out;
+
+ /** Draw handler for the "+" icon when dragging a link in empty space. */
+ void *draw_handle;
+
+ /** Temporarily stores the last picked link from multi-input socket operator. */
+ bNodeLink *last_picked_multi_input_socket_link;
+
+ /**
+ * Temporarily stores the last hovered socket for multi-input socket operator.
+ * Store it to recalculate sorting after it is no longer hovered.
+ */
+ bNode *last_node_hovered_while_dragging_a_link;
+
+ /* The cursor position, used for drawing a + icon when dragging a node link. */
+ std::array<int, 2> cursor;
+
+ /** The node the drag started at. */
+ bNode *start_node;
+ /** The socket the drag started at. */
+ bNodeSocket *start_socket;
+ /** The number of links connected to the #start_socket when the drag started. */
+ int start_link_count;
+
+ /* Data for edge panning */
+ View2DEdgePanData pan_data;
+};
+
+struct SpaceNode_Runtime {
+ float aspect;
+
+ /** Mouse position for drawing socket-less links and adding nodes. */
+ float2 cursor;
+
+ /** For auto compositing. */
+ bool recalc;
+
+ /** Temporary data for modal linking operator. */
+ std::unique_ptr<bNodeLinkDrag> linkdrag;
+
+ /* XXX hack for translate_attach op-macros to pass data from transform op to insert_offset op */
+ /** Temporary data for node insert offset (in UI called Auto-offset). */
+ struct NodeInsertOfsData *iofsd;
+};
+
+enum NodeResizeDirection {
+ NODE_RESIZE_NONE = 0,
+ NODE_RESIZE_TOP = (1 << 0),
+ NODE_RESIZE_BOTTOM = (1 << 1),
+ NODE_RESIZE_RIGHT = (1 << 2),
+ NODE_RESIZE_LEFT = (1 << 3),
+};
+ENUM_OPERATORS(NodeResizeDirection, NODE_RESIZE_LEFT);
+
+/**
+ * Transform between View2Ds in the tree path.
+ */
+float2 space_node_group_offset(const SpaceNode &snode);
+
+float node_socket_calculate_height(const bNodeSocket &socket);
+float2 node_link_calculate_multi_input_position(const float2 &socket_position,
+ int index,
+ int total_inputs);
+
+int node_get_resize_cursor(NodeResizeDirection directions);
+NodeResizeDirection node_get_resize_direction(const bNode *node, int x, int y);
+/**
+ * Usual convention here would be #node_socket_get_color(),
+ * but that's already used (for setting a color property socket).
+ */
+void node_socket_color_get(const bContext &C,
+ const bNodeTree &ntree,
+ PointerRNA &node_ptr,
+ const bNodeSocket &sock,
+ float r_color[4]);
+void node_draw_space(const bContext &C, ARegion &region);
+
+/**
+ * Sort nodes by selection: unselected nodes first, then selected,
+ * then the active node at the very end. Relative order is kept intact.
+ */
+void node_sort(bNodeTree &ntree);
+
+void node_set_cursor(wmWindow &win, SpaceNode &snode, const float2 &cursor);
+/* DPI scaled coords */
+float2 node_to_view(const bNode &node, const float2 &co);
+void node_to_updated_rect(const bNode &node, rctf &r_rect);
+float2 node_from_view(const bNode &node, const float2 &co);
+
+void node_operatortypes();
+void node_keymap(wmKeyConfig *keyconf);
+
+void node_deselect_all(SpaceNode &snode);
+void node_socket_select(bNode *node, bNodeSocket &sock);
+void node_socket_deselect(bNode *node, bNodeSocket &sock, bool deselect_node);
+void node_deselect_all_input_sockets(SpaceNode &snode, bool deselect_nodes);
+void node_deselect_all_output_sockets(SpaceNode &snode, bool deselect_nodes);
+void node_select_single(bContext &C, bNode &node);
+
+void NODE_OT_select(wmOperatorType *ot);
+void NODE_OT_select_all(wmOperatorType *ot);
+void NODE_OT_select_linked_to(wmOperatorType *ot);
+void NODE_OT_select_linked_from(wmOperatorType *ot);
+void NODE_OT_select_box(wmOperatorType *ot);
+void NODE_OT_select_circle(wmOperatorType *ot);
+void NODE_OT_select_lasso(wmOperatorType *ot);
+void NODE_OT_select_grouped(wmOperatorType *ot);
+void NODE_OT_select_same_type_step(wmOperatorType *ot);
+void NODE_OT_find_node(wmOperatorType *ot);
+
+bool space_node_view_flag(
+ bContext &C, SpaceNode &snode, ARegion &region, int node_flag, int smooth_viewtx);
+
+void NODE_OT_view_all(wmOperatorType *ot);
+void NODE_OT_view_selected(wmOperatorType *ot);
+void NODE_OT_geometry_node_view_legacy(wmOperatorType *ot);
+
+void NODE_OT_backimage_move(wmOperatorType *ot);
+void NODE_OT_backimage_zoom(wmOperatorType *ot);
+void NODE_OT_backimage_fit(wmOperatorType *ot);
+void NODE_OT_backimage_sample(wmOperatorType *ot);
+
+void nodelink_batch_start(SpaceNode &snode);
+void nodelink_batch_end(SpaceNode &snode);
+
+/**
+ * \note this is used for fake links in groups too.
+ */
+void node_draw_link(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link);
+/**
+ * Don't do shadows if th_col3 is -1.
+ */
+void node_draw_link_bezier(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link,
+ int th_col1,
+ int th_col2,
+ int th_col3);
+/** If v2d not nullptr, it clips and returns 0 if not visible. */
+bool node_link_bezier_points(const View2D *v2d,
+ const SpaceNode *snode,
+ const bNodeLink &link,
+ float coord_array[][2],
+ int resol);
+/**
+ * Return quadratic beziers points for a given nodelink and clip if v2d is not nullptr.
+ */
+bool node_link_bezier_handles(const View2D *v2d,
+ const SpaceNode *snode,
+ const bNodeLink &ink,
+ float vec[4][2]);
+void draw_nodespace_back_pix(const bContext &C,
+ ARegion &region,
+ SpaceNode &snode,
+ bNodeInstanceKey parent_key);
+
+void node_select_all(ListBase *lb, int action);
+
+/**
+ * XXX Does some additional initialization on top of #nodeAddNode
+ * Can be used with both custom and static nodes,
+ * if `idname == nullptr` the static int type will be used instead.
+ */
+bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy);
+void NODE_OT_add_reroute(wmOperatorType *ot);
+void NODE_OT_add_group(wmOperatorType *ot);
+void NODE_OT_add_object(wmOperatorType *ot);
+void NODE_OT_add_collection(wmOperatorType *ot);
+void NODE_OT_add_texture(wmOperatorType *ot);
+void NODE_OT_add_file(wmOperatorType *ot);
+void NODE_OT_add_mask(wmOperatorType *ot);
+void NODE_OT_new_node_tree(wmOperatorType *ot);
+
+const char *node_group_idname(bContext *C);
+void NODE_OT_group_make(wmOperatorType *ot);
+void NODE_OT_group_insert(wmOperatorType *ot);
+void NODE_OT_group_ungroup(wmOperatorType *ot);
+void NODE_OT_group_separate(wmOperatorType *ot);
+void NODE_OT_group_edit(wmOperatorType *ot);
+
+void sort_multi_input_socket_links(SpaceNode &snode,
+ bNode &node,
+ bNodeLink *drag_link,
+ const float2 *cursor);
+
+void NODE_OT_link(wmOperatorType *ot);
+void NODE_OT_link_make(wmOperatorType *ot);
+void NODE_OT_links_cut(wmOperatorType *ot);
+void NODE_OT_links_detach(wmOperatorType *ot);
+void NODE_OT_links_mute(wmOperatorType *ot);
+
+void NODE_OT_parent_set(wmOperatorType *ot);
+void NODE_OT_join(wmOperatorType *ot);
+void NODE_OT_attach(wmOperatorType *ot);
+void NODE_OT_detach(wmOperatorType *ot);
+
+void NODE_OT_link_viewer(wmOperatorType *ot);
+
+void NODE_OT_insert_offset(wmOperatorType *ot);
+
+void snode_set_context(const bContext &C);
+
+bool composite_node_active(bContext *C);
+/** Operator poll callback. */
+bool composite_node_editable(bContext *C);
+
+bool node_has_hidden_sockets(bNode *node);
+void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set);
+int node_render_changed_exec(bContext *, wmOperator *);
+/** Type is #SOCK_IN and/or #SOCK_OUT. */
+bool node_find_indicated_socket(SpaceNode &snode,
+ bNode **nodep,
+ bNodeSocket **sockp,
+ const float2 &cursor,
+ eNodeSocketInOut in_out);
+float node_link_dim_factor(const View2D &v2d, const bNodeLink &link);
+bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link);
+
+void NODE_OT_duplicate(wmOperatorType *ot);
+void NODE_OT_delete(wmOperatorType *ot);
+void NODE_OT_delete_reconnect(wmOperatorType *ot);
+void NODE_OT_resize(wmOperatorType *ot);
+
+void NODE_OT_mute_toggle(wmOperatorType *ot);
+void NODE_OT_hide_toggle(wmOperatorType *ot);
+void NODE_OT_hide_socket_toggle(wmOperatorType *ot);
+void NODE_OT_preview_toggle(wmOperatorType *ot);
+void NODE_OT_options_toggle(wmOperatorType *ot);
+void NODE_OT_node_copy_color(wmOperatorType *ot);
+
+void NODE_OT_read_viewlayers(wmOperatorType *ot);
+void NODE_OT_render_changed(wmOperatorType *ot);
+
+void NODE_OT_output_file_add_socket(wmOperatorType *ot);
+void NODE_OT_output_file_remove_active_socket(wmOperatorType *ot);
+void NODE_OT_output_file_move_active_socket(wmOperatorType *ot);
+
+void NODE_OT_switch_view_update(wmOperatorType *ot);
+
+/**
+ * \note clipboard_cut is a simple macro of copy + delete.
+ */
+void NODE_OT_clipboard_copy(wmOperatorType *ot);
+void NODE_OT_clipboard_paste(wmOperatorType *ot);
+
+void NODE_OT_tree_socket_add(wmOperatorType *ot);
+void NODE_OT_tree_socket_remove(wmOperatorType *ot);
+void NODE_OT_tree_socket_change_type(wmOperatorType *ot);
+void NODE_OT_tree_socket_move(wmOperatorType *ot);
+
+void NODE_OT_shader_script_update(wmOperatorType *ot);
+
+void NODE_OT_viewer_border(wmOperatorType *ot);
+void NODE_OT_clear_viewer_border(wmOperatorType *ot);
+
+void NODE_GGT_backdrop_transform(wmGizmoGroupType *gzgt);
+void NODE_GGT_backdrop_crop(wmGizmoGroupType *gzgt);
+void NODE_GGT_backdrop_sun_beams(wmGizmoGroupType *gzgt);
+void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt);
+
+void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot);
+void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot);
+
+void node_geometry_add_attribute_search_button(const bContext &C,
+ const bNodeTree &node_tree,
+ const bNode &node,
+ PointerRNA &socket_ptr,
+ uiLayout &layout);
+
+/* Nodes draw without dpi - the view zoom is flexible. */
+#define HIDDEN_RAD (0.75f * U.widget_unit)
+#define BASIS_RAD (0.2f * U.widget_unit)
+#define NODE_DYS (U.widget_unit / 2)
+#define NODE_DY U.widget_unit
+#define NODE_SOCKDY (0.1f * U.widget_unit)
+#define NODE_WIDTH(node) (node.width * UI_DPI_FAC)
+#define NODE_HEIGHT(node) (node.height * UI_DPI_FAC)
+#define NODE_MARGIN_X (1.2f * U.widget_unit)
+#define NODE_SOCKSIZE (0.25f * U.widget_unit)
+#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit)
+#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit)
+#define NODE_LINK_RESOL 12
+
+Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C);
+
+void invoke_node_link_drag_add_menu(bContext &C,
+ bNode &node,
+ bNodeSocket &socket,
+ const float2 &cursor);
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.cc
index df4f63af20b..2ca475f6948 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.cc
@@ -33,9 +33,11 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "node_intern.h" /* own include */
+#include "node_intern.hh" /* own include */
-void node_operatortypes(void)
+namespace blender::ed::space_node {
+
+void node_operatortypes()
{
WM_operatortype_append(NODE_OT_select);
WM_operatortype_append(NODE_OT_select_all);
@@ -127,7 +129,18 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_cryptomatte_layer_remove);
}
-void ED_operatormacros_node(void)
+void node_keymap(struct wmKeyConfig *keyconf)
+{
+ /* Entire Editor only ----------------- */
+ WM_keymap_ensure(keyconf, "Node Generic", SPACE_NODE, 0);
+
+ /* Main Region only ----------------- */
+ WM_keymap_ensure(keyconf, "Node Editor", SPACE_NODE, 0);
+}
+
+} // namespace blender::ed::space_node
+
+void ED_operatormacros_node()
{
wmOperatorType *ot;
wmOperatorTypeMacro *mot;
@@ -156,6 +169,7 @@ void ED_operatormacros_node(void)
OPTYPE_UNDO | OPTYPE_REGISTER);
mot = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_boolean_set(mot->ptr, "remove_on_cancel", true);
+ RNA_boolean_set(mot->ptr, "view2d_edge_pan", true);
WM_operatortype_macro_define(ot, "NODE_OT_attach");
WM_operatortype_macro_define(ot, "NODE_OT_insert_offset");
@@ -202,12 +216,3 @@ void ED_operatormacros_node(void)
WM_operatortype_macro_define(ot, "NODE_OT_links_detach");
WM_operatortype_macro_define(ot, "NODE_OT_translate_attach");
}
-
-void node_keymap(struct wmKeyConfig *keyconf)
-{
- /* Entire Editor only ----------------- */
- WM_keymap_ensure(keyconf, "Node Generic", SPACE_NODE, 0);
-
- /* Main Region only ----------------- */
- WM_keymap_ensure(keyconf, "Node Editor", SPACE_NODE, 0);
-}
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index b69e7e98bca..fd9420b173d 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -26,9 +26,7 @@
#include "DNA_anim_types.h"
#include "DNA_node_types.h"
-#include "BLI_blenlib.h"
#include "BLI_easing.h"
-#include "BLI_math.h"
#include "BKE_anim_data.h"
#include "BKE_context.h"
@@ -36,11 +34,13 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_screen.h"
#include "ED_node.h" /* own include */
#include "ED_render.h"
#include "ED_screen.h"
+#include "ED_space_api.h"
#include "ED_spreadsheet.h"
#include "ED_util.h"
@@ -52,128 +52,22 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "GPU_state.h"
+
+#include "UI_interface_icons.h"
#include "UI_resources.h"
#include "UI_view2d.h"
#include "BLT_translation.h"
-#include "node_intern.h" /* own include */
-
-/* -------------------------------------------------------------------- */
-/** \name Relations Helpers
- * \{ */
+#include "NOD_node_declaration.hh"
+#include "NOD_node_tree_ref.hh"
+#include "NOD_socket_declarations.hh"
+#include "NOD_socket_declarations_geometry.hh"
-static bool ntree_has_drivers(bNodeTree *ntree)
-{
- const AnimData *adt = BKE_animdata_from_id(&ntree->id);
- if (adt == nullptr) {
- return false;
- }
- return !BLI_listbase_is_empty(&adt->drivers);
-}
+#include "node_intern.hh" /* own include */
-static bool ntree_check_nodes_connected_dfs(bNodeTree *ntree, bNode *from, bNode *to)
-{
- if (from->flag & NODE_TEST) {
- return false;
- }
- from->flag |= NODE_TEST;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- if (link->fromnode == from) {
- if (link->tonode == to) {
- return true;
- }
-
- if (ntree_check_nodes_connected_dfs(ntree, link->tonode, to)) {
- return true;
- }
- }
- }
- return false;
-}
-
-static bool ntree_check_nodes_connected(bNodeTree *ntree, bNode *from, bNode *to)
-{
- if (from == to) {
- return true;
- }
- ntreeNodeFlagSet(ntree, NODE_TEST, false);
- return ntree_check_nodes_connected_dfs(ntree, from, to);
-}
-
-static bool node_group_has_output_dfs(bNode *node)
-{
- bNodeTree *ntree = (bNodeTree *)node->id;
- if (ntree->id.tag & LIB_TAG_DOIT) {
- return false;
- }
- ntree->id.tag |= LIB_TAG_DOIT;
- for (bNode *current_node = (bNode *)ntree->nodes.first; current_node != nullptr;
- current_node = current_node->next) {
- if (current_node->type == NODE_GROUP) {
- if (current_node->id && node_group_has_output_dfs(current_node)) {
- return true;
- }
- }
- if (current_node->flag & NODE_DO_OUTPUT && current_node->type != NODE_GROUP_OUTPUT) {
- return true;
- }
- }
- return false;
-}
-
-static bool node_group_has_output(Main *bmain, bNode *node)
-{
- BLI_assert(ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP));
- bNodeTree *ntree = (bNodeTree *)node->id;
- if (ntree == nullptr) {
- return false;
- }
- BKE_main_id_tag_listbase(&bmain->nodetrees, LIB_TAG_DOIT, false);
- return node_group_has_output_dfs(node);
-}
-
-bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node)
-{
- /* Special case for drivers: if node tree has any drivers we assume it is
- * always to be tagged for update when node changes. Otherwise we will be
- * doomed to do some deep and nasty deep search of indirect dependencies,
- * which will be too complicated without real benefit.
- */
- if (ntree_has_drivers(ntree)) {
- return true;
- }
- LISTBASE_FOREACH (bNode *, current_node, &ntree->nodes) {
- /* Special case for group nodes -- if modified node connected to a group
- * with active output inside we consider refresh is needed.
- *
- * We could make check more grained here by taking which socket the node
- * is connected to and so eventually.
- */
- if (ELEM(current_node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
- if (current_node->id != nullptr && ntree_has_drivers((bNodeTree *)current_node->id)) {
- return true;
- }
- if (ntree_check_nodes_connected(ntree, node, current_node) &&
- node_group_has_output(bmain, current_node)) {
- return true;
- }
- }
- if (current_node->flag & NODE_DO_OUTPUT) {
- if (ntree_check_nodes_connected(ntree, node, current_node)) {
- return true;
- }
- }
- if (current_node->type == GEO_NODE_VIEWER) {
- if (ntree_check_nodes_connected(ntree, node, current_node)) {
- return true;
- }
- }
- }
- return false;
-}
-
-/** \} */
+using namespace blender::nodes::node_tree_ref_types;
/* -------------------------------------------------------------------- */
/** \name Add Node
@@ -202,70 +96,60 @@ static void clear_picking_highlight(ListBase *links)
}
}
-static LinkData *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bNodeSocket *sock)
+namespace blender::ed::space_node {
+
+static bNodeLink *create_drag_link(bNode &node, bNodeSocket &sock)
{
- LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data");
- bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
- linkdata->data = oplink;
- if (sock->in_out == SOCK_OUT) {
- oplink->fromnode = node;
- oplink->fromsock = sock;
+ bNodeLink *oplink = MEM_cnew<bNodeLink>(__func__);
+ if (sock.in_out == SOCK_OUT) {
+ oplink->fromnode = &node;
+ oplink->fromsock = &sock;
}
else {
- oplink->tonode = node;
- oplink->tosock = sock;
+ oplink->tonode = &node;
+ oplink->tosock = &sock;
}
oplink->flag |= NODE_LINK_VALID;
- oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, snode->edittree, node)) {
- oplink->flag |= NODE_LINK_TEST;
- }
oplink->flag |= NODE_LINK_DRAGGED;
- return linkdata;
+ return oplink;
}
-static void pick_link(const bContext *C,
- wmOperator *op,
- bNodeLinkDrag *nldrag,
- SpaceNode *snode,
- bNode *node,
- bNodeLink *link_to_pick)
+static void pick_link(
+ wmOperator &op, bNodeLinkDrag &nldrag, SpaceNode &snode, bNode *node, bNodeLink &link_to_pick)
{
- clear_picking_highlight(&snode->edittree->links);
- RNA_boolean_set(op->ptr, "has_link_picked", true);
+ clear_picking_highlight(&snode.edittree->links);
+ RNA_boolean_set(op.ptr, "has_link_picked", true);
- Main *bmain = CTX_data_main(C);
- LinkData *linkdata = create_drag_link(
- bmain, snode, link_to_pick->fromnode, link_to_pick->fromsock);
+ bNodeLink *link = create_drag_link(*link_to_pick.fromnode, *link_to_pick.fromsock);
- BLI_addtail(&nldrag->links, linkdata);
- nodeRemLink(snode->edittree, link_to_pick);
+ nldrag.links.append(link);
+ nodeRemLink(snode.edittree, &link_to_pick);
- BLI_assert(nldrag->last_node_hovered_while_dragging_a_link != nullptr);
+ BLI_assert(nldrag.last_node_hovered_while_dragging_a_link != nullptr);
sort_multi_input_socket_links(
- snode, nldrag->last_node_hovered_while_dragging_a_link, nullptr, nullptr);
+ snode, *nldrag.last_node_hovered_while_dragging_a_link, nullptr, nullptr);
/* Send changed event to original link->tonode. */
if (node) {
- snode_update(snode, node);
+ BKE_ntree_update_tag_node_property(snode.edittree, node);
}
}
-static void pick_input_link_by_link_intersect(const bContext *C,
- wmOperator *op,
- bNodeLinkDrag *nldrag,
- const float *cursor)
+static void pick_input_link_by_link_intersect(const bContext &C,
+ wmOperator &op,
+ bNodeLinkDrag &nldrag,
+ const float2 &cursor)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- const ARegion *region = CTX_wm_region(C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
+ const ARegion *region = CTX_wm_region(&C);
const View2D *v2d = &region->v2d;
float drag_start[2];
- RNA_float_get_array(op->ptr, "drag_start", drag_start);
+ RNA_float_get_array(op.ptr, "drag_start", drag_start);
bNode *node;
bNodeSocket *socket;
- node_find_indicated_socket(snode, &node, &socket, drag_start, SOCK_IN);
+ node_find_indicated_socket(*snode, &node, &socket, drag_start, SOCK_IN);
/* Distance to test overlapping of cursor on link. */
const float cursor_link_touch_distance = 12.5f * UI_DPI_FAC;
@@ -278,7 +162,7 @@ static void pick_input_link_by_link_intersect(const bContext *C,
if (link->tosock == socket) {
/* Test if the cursor is near a link. */
float vec[4][2];
- node_link_bezier_handles(v2d, snode, link, vec);
+ node_link_bezier_handles(v2d, snode, *link, vec);
float data[NODE_LINK_RESOL * 2 + 2];
BKE_curve_forward_diff_bezier(
@@ -292,7 +176,7 @@ static void pick_input_link_by_link_intersect(const bContext *C,
float distance = dist_squared_to_line_segment_v2(cursor, l1, l2);
if (distance < cursor_link_touch_distance) {
link_to_pick = link;
- nldrag->last_picked_multi_input_socket_link = link_to_pick;
+ nldrag.last_picked_multi_input_socket_link = link_to_pick;
}
}
}
@@ -302,7 +186,7 @@ static void pick_input_link_by_link_intersect(const bContext *C,
* Not essential for the basic behavior, but can make interaction feel a bit better if
* the mouse moves to the right and loses the "selection." */
if (!link_to_pick) {
- bNodeLink *last_picked_link = nldrag->last_picked_multi_input_socket_link;
+ bNodeLink *last_picked_link = nldrag.last_picked_multi_input_socket_link;
if (last_picked_link) {
link_to_pick = last_picked_link;
}
@@ -311,27 +195,14 @@ static void pick_input_link_by_link_intersect(const bContext *C,
if (link_to_pick) {
/* Highlight is set here and cleared in the next iteration or if the operation finishes. */
link_to_pick->flag |= NODE_LINK_TEMP_HIGHLIGHT;
- ED_area_tag_redraw(CTX_wm_area(C));
+ ED_area_tag_redraw(CTX_wm_area(&C));
- if (!node_find_indicated_socket(snode, &node, &socket, cursor, SOCK_IN)) {
- pick_link(C, op, nldrag, snode, node, link_to_pick);
+ if (!node_find_indicated_socket(*snode, &node, &socket, cursor, SOCK_IN)) {
+ pick_link(op, nldrag, *snode, node, *link_to_pick);
}
}
}
-static int sort_nodes_locx(const void *a, const void *b)
-{
- const bNodeListItem *nli1 = (const bNodeListItem *)a;
- const bNodeListItem *nli2 = (const bNodeListItem *)b;
- const bNode *node1 = nli1->node;
- const bNode *node2 = nli2->node;
-
- if (node1->locx > node2->locx) {
- return 1;
- }
- return 0;
-}
-
static bool socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, const bool allow_used)
{
if (nodeSocketIsHidden(sock)) {
@@ -339,7 +210,10 @@ static bool socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, con
}
if (!allow_used && (sock->flag & SOCK_IN_USE)) {
- return false;
+ /* Multi input sockets are available (even if used). */
+ if (!(sock->flag & SOCK_MULTI_INPUT)) {
+ return false;
+ }
}
return true;
@@ -428,14 +302,14 @@ static bNodeSocket *best_socket_input(bNodeTree *ntree, bNode *node, int num, in
return nullptr;
}
-static bool snode_autoconnect_input(SpaceNode *snode,
+static bool snode_autoconnect_input(SpaceNode &snode,
bNode *node_fr,
bNodeSocket *sock_fr,
bNode *node_to,
bNodeSocket *sock_to,
int replace)
{
- bNodeTree *ntree = snode->edittree;
+ bNodeTree *ntree = snode.edittree;
/* then we can connect */
if (replace) {
@@ -447,105 +321,75 @@ static bool snode_autoconnect_input(SpaceNode *snode,
}
struct LinkAndPosition {
- struct bNodeLink *link;
- float multi_socket_position[2];
+ bNodeLink *link;
+ float2 multi_socket_position;
};
-static int compare_link_by_y_position(const void *a, const void *b)
-{
- const LinkAndPosition *link_and_position_a = *(const LinkAndPosition **)a;
- const LinkAndPosition *link_and_position_b = *(const LinkAndPosition **)b;
-
- BLI_assert(link_and_position_a->link->tosock == link_and_position_b->link->tosock);
- const float link_a_y = link_and_position_a->multi_socket_position[1];
- const float link_b_y = link_and_position_b->multi_socket_position[1];
- return link_a_y > link_b_y ? 1 : -1;
-}
-
-void sort_multi_input_socket_links(SpaceNode *snode,
- bNode *node,
+void sort_multi_input_socket_links(SpaceNode &snode,
+ bNode &node,
bNodeLink *drag_link,
- float cursor[2])
+ const float2 *cursor)
{
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
if (!(socket->flag & SOCK_MULTI_INPUT)) {
continue;
}
- /* The total is calculated in #node_update_nodetree, which runs before this draw step. */
- int total_inputs = socket->total_inputs + 1;
- struct LinkAndPosition **input_links = (LinkAndPosition **)MEM_malloc_arrayN(
- total_inputs, sizeof(LinkAndPosition *), __func__);
+ Vector<LinkAndPosition, 8> links;
- int index = 0;
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
+ LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
if (link->tosock == socket) {
- struct LinkAndPosition *link_and_position = (LinkAndPosition *)MEM_callocN(
- sizeof(struct LinkAndPosition), __func__);
- link_and_position->link = link;
- node_link_calculate_multi_input_position(link->tosock->locx,
- link->tosock->locy,
- link->multi_input_socket_index,
- link->tosock->total_inputs,
- link_and_position->multi_socket_position);
- input_links[index] = link_and_position;
- index++;
+ links.append(
+ {link,
+ node_link_calculate_multi_input_position({link->tosock->locx, link->tosock->locy},
+ link->multi_input_socket_index,
+ link->tosock->total_inputs)});
}
}
if (drag_link) {
- LinkAndPosition *link_and_position = (LinkAndPosition *)MEM_callocN(sizeof(LinkAndPosition),
- __func__);
- link_and_position->link = drag_link;
- copy_v2_v2(link_and_position->multi_socket_position, cursor);
- input_links[index] = link_and_position;
- index++;
+ LinkAndPosition link_and_position{};
+ link_and_position.link = drag_link;
+ if (cursor) {
+ link_and_position.multi_socket_position = *cursor;
+ }
+ links.append(link_and_position);
}
- qsort(input_links, index, sizeof(bNodeLink *), compare_link_by_y_position);
+ std::sort(links.begin(), links.end(), [](const LinkAndPosition a, const LinkAndPosition b) {
+ return a.multi_socket_position.y < b.multi_socket_position.y;
+ });
- for (int i = 0; i < index; i++) {
- input_links[i]->link->multi_input_socket_index = i;
- }
-
- for (int i = 0; i < index; i++) {
- if (input_links[i]) {
- MEM_freeN(input_links[i]);
- }
+ for (const int i : links.index_range()) {
+ links[i].link->multi_input_socket_index = i;
}
- MEM_freeN(input_links);
}
}
-static void snode_autoconnect(Main *bmain,
- SpaceNode *snode,
+static void snode_autoconnect(Main &bmain,
+ SpaceNode &snode,
const bool allow_multiple,
const bool replace)
{
- bNodeTree *ntree = snode->edittree;
- ListBase *nodelist = (ListBase *)MEM_callocN(sizeof(ListBase), "items_list");
+ bNodeTree *ntree = snode.edittree;
+ Vector<bNode *> sorted_nodes;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & NODE_SELECT) {
- bNodeListItem *nli = (bNodeListItem *)MEM_mallocN(sizeof(bNodeListItem),
- "temporary node list item");
- nli->node = node;
- BLI_addtail(nodelist, nli);
+ sorted_nodes.append(node);
}
}
- /* sort nodes left to right */
- BLI_listbase_sort(nodelist, sort_nodes_locx);
+ /* Sort nodes left to right. */
+ std::sort(sorted_nodes.begin(), sorted_nodes.end(), [](const bNode *a, const bNode *b) {
+ return a->locx < b->locx;
+ });
int numlinks = 0;
- LISTBASE_FOREACH (bNodeListItem *, nli, nodelist) {
+ for (const int i : sorted_nodes.as_mutable_span().drop_back(1).index_range()) {
bool has_selected_inputs = false;
- if (nli->next == nullptr) {
- break;
- }
-
- bNode *node_fr = nli->node;
- bNode *node_to = nli->next->node;
+ bNode *node_fr = sorted_nodes[i];
+ bNode *node_to = sorted_nodes[i + 1];
/* corner case: input/output node aligned the wrong way around (T47729) */
if (BLI_listbase_is_empty(&node_to->inputs) || BLI_listbase_is_empty(&node_fr->outputs)) {
SWAP(bNode *, node_fr, node_to);
@@ -599,11 +443,8 @@ static void snode_autoconnect(Main *bmain,
}
if (numlinks > 0) {
- ntreeUpdateTree(bmain, ntree);
+ BKE_ntree_update_main_tree(&bmain, ntree, nullptr);
}
-
- BLI_freelistN(nodelist);
- MEM_freeN(nodelist);
}
/** \} */
@@ -612,164 +453,279 @@ static void snode_autoconnect(Main *bmain,
/** \name Link Viewer Operator
* \{ */
-static int node_link_viewer(const bContext *C, bNode *tonode)
-{
- SpaceNode *snode = CTX_wm_space_node(C);
+namespace viewer_linking {
- /* context check */
- if (tonode == nullptr || BLI_listbase_is_empty(&tonode->outputs)) {
- return OPERATOR_CANCELLED;
+/* Depending on the node tree type, different socket types are supported by viewer nodes. */
+static bool socket_can_be_viewed(const OutputSocketRef &socket)
+{
+ if (nodeSocketIsHidden(socket.bsocket())) {
+ return false;
}
- if (ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) {
- return OPERATOR_CANCELLED;
+ if (socket.idname() == "NodeSocketVirtual") {
+ return false;
}
+ if (socket.tree().btree()->type != NTREE_GEOMETRY) {
+ return true;
+ }
+ return ELEM(socket.typeinfo()->type,
+ SOCK_GEOMETRY,
+ SOCK_FLOAT,
+ SOCK_VECTOR,
+ SOCK_INT,
+ SOCK_BOOLEAN,
+ SOCK_RGBA);
+}
- /* get viewer */
- bNode *viewer_node = nullptr;
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
- if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) {
- if (node->flag & NODE_DO_OUTPUT) {
- viewer_node = node;
- break;
- }
- }
+static CustomDataType socket_type_to_custom_data_type(const eNodeSocketDatatype socket_type)
+{
+ switch (socket_type) {
+ case SOCK_FLOAT:
+ return CD_PROP_FLOAT;
+ case SOCK_INT:
+ return CD_PROP_INT32;
+ case SOCK_VECTOR:
+ return CD_PROP_FLOAT3;
+ case SOCK_BOOLEAN:
+ return CD_PROP_BOOL;
+ case SOCK_RGBA:
+ return CD_PROP_COLOR;
+ default:
+ /* Fallback. */
+ return CD_AUTO_FROM_NAME;
}
- /* no viewer, we make one active */
- if (viewer_node == nullptr) {
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
- if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) {
- node->flag |= NODE_DO_OUTPUT;
- viewer_node = node;
- break;
+}
+
+/**
+ * Find the socket to link to in a viewer node.
+ */
+static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree,
+ bNode &viewer_node,
+ bNodeSocket &src_socket)
+{
+ if (viewer_node.type != GEO_NODE_VIEWER) {
+ /* In viewer nodes in the compositor, only the first input should be linked to. */
+ return (bNodeSocket *)viewer_node.inputs.first;
+ }
+ /* For the geometry nodes viewer, find the socket with the correct type. */
+ LISTBASE_FOREACH (bNodeSocket *, viewer_socket, &viewer_node.inputs) {
+ if (viewer_socket->type == src_socket.type) {
+ if (viewer_socket->type == SOCK_GEOMETRY) {
+ return viewer_socket;
}
+ NodeGeometryViewer *storage = (NodeGeometryViewer *)viewer_node.storage;
+ const CustomDataType data_type = socket_type_to_custom_data_type(
+ (eNodeSocketDatatype)src_socket.type);
+ BLI_assert(data_type != CD_AUTO_FROM_NAME);
+ storage->data_type = data_type;
+ viewer_node.typeinfo->updatefunc(&ntree, &viewer_node);
+ return viewer_socket;
}
}
+ return nullptr;
+}
- bNodeSocket *sock = nullptr;
- bNodeLink *link = nullptr;
+static bool is_viewer_node(const NodeRef &node)
+{
+ return ELEM(node.bnode()->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER);
+}
- /* try to find an already connected socket to cycle to the next */
- if (viewer_node) {
- link = nullptr;
+static Vector<const NodeRef *> find_viewer_nodes(const NodeTreeRef &tree)
+{
+ Vector<const NodeRef *> viewer_nodes;
+ for (const NodeRef *node : tree.nodes()) {
+ if (is_viewer_node(*node)) {
+ viewer_nodes.append(node);
+ }
+ }
+ return viewer_nodes;
+}
- for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) {
- if (link->tonode == viewer_node && link->fromnode == tonode) {
- if (link->tosock == viewer_node->inputs.first) {
- break;
- }
- }
+static bool is_viewer_socket_in_viewer(const InputSocketRef &socket)
+{
+ const NodeRef &node = socket.node();
+ BLI_assert(is_viewer_node(node));
+ if (node.typeinfo()->type == GEO_NODE_VIEWER) {
+ return true;
+ }
+ return socket.index() == 0;
+}
+
+static bool is_linked_to_viewer(const OutputSocketRef &socket, const NodeRef &viewer_node)
+{
+ for (const InputSocketRef *target_socket : socket.directly_linked_sockets()) {
+ if (&target_socket->node() != &viewer_node) {
+ continue;
}
- if (link) {
- /* unlink existing connection */
- sock = link->fromsock;
- nodeRemLink(snode->edittree, link);
+ if (!target_socket->is_available()) {
+ continue;
+ }
+ if (is_viewer_socket_in_viewer(*target_socket)) {
+ return true;
+ }
+ }
+ return false;
+}
- /* find a socket after the previously connected socket */
- if (ED_node_is_geometry(snode)) {
- /* Geometry nodes viewer only supports geometry sockets for now. */
- for (sock = sock->next; sock; sock = sock->next) {
- if (sock->type == SOCK_GEOMETRY && !nodeSocketIsHidden(sock)) {
- break;
- }
- }
- }
- else {
- for (sock = sock->next; sock; sock = sock->next) {
- if (!nodeSocketIsHidden(sock)) {
- break;
- }
- }
+static int get_default_viewer_type(const bContext *C)
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ return ED_node_is_compositor(snode) ? CMP_NODE_VIEWER : GEO_NODE_VIEWER;
+}
+
+static void remove_links_to_unavailable_viewer_sockets(bNodeTree &btree, bNode &viewer_node)
+{
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &btree.links) {
+ if (link->tonode == &viewer_node) {
+ if (link->tosock->flag & SOCK_UNAVAIL) {
+ nodeRemLink(&btree, link);
}
}
}
+}
- if (tonode) {
- /* Find a selected socket that overrides the socket to connect to */
- if (ED_node_is_geometry(snode)) {
- /* Geometry nodes viewer only supports geometry sockets for now. */
- LISTBASE_FOREACH (bNodeSocket *, sock2, &tonode->outputs) {
- if (sock2->type == SOCK_GEOMETRY && !nodeSocketIsHidden(sock2) && sock2->flag & SELECT) {
- sock = sock2;
- break;
- }
- }
+static const NodeRef *get_existing_viewer(const NodeTreeRef &tree)
+{
+ Vector<const NodeRef *> viewer_nodes = find_viewer_nodes(tree);
+
+ /* Check if there is already an active viewer node that should be used. */
+ for (const NodeRef *viewer_node : viewer_nodes) {
+ if (viewer_node->bnode()->flag & NODE_DO_OUTPUT) {
+ return viewer_node;
}
- else {
- LISTBASE_FOREACH (bNodeSocket *, sock2, &tonode->outputs) {
- if (!nodeSocketIsHidden(sock2) && sock2->flag & SELECT) {
- sock = sock2;
- break;
- }
- }
+ }
+
+ /* If no active but non-active viewers exist, make one active. */
+ if (!viewer_nodes.is_empty()) {
+ viewer_nodes[0]->bnode()->flag |= NODE_DO_OUTPUT;
+ return viewer_nodes[0];
+ }
+ return nullptr;
+}
+
+static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *active_viewer_node,
+ const NodeRef &node_to_view)
+{
+ /* Check if any of the output sockets is selected, which is the case when the user just clicked
+ * on the socket. */
+ for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
+ if (output_socket->bsocket()->flag & SELECT) {
+ return output_socket;
}
}
- /* find a socket starting from the first socket */
- if (!sock) {
- if (ED_node_is_geometry(snode)) {
- /* Geometry nodes viewer only supports geometry sockets for now. */
- for (sock = (bNodeSocket *)tonode->outputs.first; sock; sock = sock->next) {
- if (sock->type == SOCK_GEOMETRY && !nodeSocketIsHidden(sock)) {
- break;
- }
+ const OutputSocketRef *last_socket_linked_to_viewer = nullptr;
+ if (active_viewer_node != nullptr) {
+ for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
+ if (!socket_can_be_viewed(*output_socket)) {
+ continue;
}
- }
- else {
- for (sock = (bNodeSocket *)tonode->outputs.first; sock; sock = sock->next) {
- if (!nodeSocketIsHidden(sock)) {
- break;
- }
+ if (is_linked_to_viewer(*output_socket, *active_viewer_node)) {
+ last_socket_linked_to_viewer = output_socket;
}
}
}
-
- if (sock) {
- /* add a new viewer if none exists yet */
- if (!viewer_node) {
- /* XXX location is a quick hack, just place it next to the linked socket */
- const int viewer_type = ED_node_is_compositor(snode) ? CMP_NODE_VIEWER : GEO_NODE_VIEWER;
- viewer_node = node_add_node(C, nullptr, viewer_type, sock->locx + 100, sock->locy);
- if (!viewer_node) {
- return OPERATOR_CANCELLED;
+ if (last_socket_linked_to_viewer == nullptr) {
+ /* If no output is connected to a viewer, use the first output that can be viewed. */
+ for (const OutputSocketRef *output_socket : node_to_view.outputs()) {
+ if (socket_can_be_viewed(*output_socket)) {
+ return output_socket;
}
-
- link = nullptr;
}
- else {
- /* get link to viewer */
- for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) {
- if (link->tonode == viewer_node && link->tosock == viewer_node->inputs.first) {
- break;
- }
+ }
+ else {
+ /* Pick the next socket to be linked to the viewer. */
+ const int tot_outputs = node_to_view.outputs().size();
+ for (const int offset : IndexRange(1, tot_outputs - 1)) {
+ const int index = (last_socket_linked_to_viewer->index() + offset) % tot_outputs;
+ const OutputSocketRef &output_socket = node_to_view.output(index);
+ if (!socket_can_be_viewed(output_socket)) {
+ continue;
}
+ if (is_linked_to_viewer(output_socket, *active_viewer_node)) {
+ continue;
+ }
+ return &output_socket;
}
+ }
+ return nullptr;
+}
- if (link == nullptr) {
- nodeAddLink(
- snode->edittree, tonode, sock, viewer_node, (bNodeSocket *)viewer_node->inputs.first);
- }
- else {
- link->fromnode = tonode;
- link->fromsock = sock;
- /* make sure the dependency sorting is updated */
- snode->edittree->update |= NTREE_UPDATE_LINKS;
+static int link_socket_to_viewer(const bContext &C,
+ bNode *viewer_bnode,
+ bNode &bnode_to_view,
+ bNodeSocket &bsocket_to_view)
+{
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeTree &btree = *snode.edittree;
+
+ if (viewer_bnode == nullptr) {
+ /* Create a new viewer node if none exists. */
+ const int viewer_type = get_default_viewer_type(&C);
+ viewer_bnode = node_add_node(
+ C, nullptr, viewer_type, bsocket_to_view.locx + 100, bsocket_to_view.locy);
+ if (viewer_bnode == nullptr) {
+ return OPERATOR_CANCELLED;
}
- if (ED_node_is_geometry(snode)) {
- ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(C), snode, viewer_node);
+ }
+
+ bNodeSocket *viewer_bsocket = node_link_viewer_get_socket(btree, *viewer_bnode, bsocket_to_view);
+ if (viewer_bsocket == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bNodeLink *link_to_change = nullptr;
+ LISTBASE_FOREACH (bNodeLink *, link, &btree.links) {
+ if (link->tosock == viewer_bsocket) {
+ link_to_change = link;
+ break;
}
+ }
+
+ if (link_to_change == nullptr) {
+ nodeAddLink(&btree, &bnode_to_view, &bsocket_to_view, viewer_bnode, viewer_bsocket);
+ }
+ else {
+ link_to_change->fromnode = &bnode_to_view;
+ link_to_change->fromsock = &bsocket_to_view;
+ BKE_ntree_update_tag_link_changed(&btree);
+ }
+
+ remove_links_to_unavailable_viewer_sockets(btree, *viewer_bnode);
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_update(snode, viewer_node);
- DEG_id_tag_update(&snode->edittree->id, 0);
+ if (btree.type == NTREE_GEOMETRY) {
+ ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(&C), &snode, viewer_bnode);
}
+ ED_node_tree_propagate_change(&C, CTX_data_main(&C), &btree);
return OPERATOR_FINISHED;
}
+static int node_link_viewer(const bContext &C, bNode &bnode_to_view)
+{
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeTree *btree = snode.edittree;
+
+ const NodeTreeRef tree{btree};
+ const NodeRef &node_to_view = *tree.find_node(bnode_to_view);
+ const NodeRef *active_viewer_node = get_existing_viewer(tree);
+
+ const OutputSocketRef *socket_to_view = find_output_socket_to_be_viewed(active_viewer_node,
+ node_to_view);
+ if (socket_to_view == nullptr) {
+ return OPERATOR_FINISHED;
+ }
+
+ bNodeSocket &bsocket_to_view = *socket_to_view->bsocket();
+ bNode *viewer_bnode = active_viewer_node ? active_viewer_node->bnode() : nullptr;
+ return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view);
+}
+
+} // namespace viewer_linking
+
static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNode *node = nodeGetActive(snode->edittree);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNode *node = nodeGetActive(snode.edittree);
if (!node) {
return OPERATOR_CANCELLED;
@@ -777,11 +733,11 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- if (node_link_viewer(C, node) == OPERATOR_CANCELLED) {
+ if (viewer_linking::node_link_viewer(*C, *node) == OPERATOR_CANCELLED) {
return OPERATOR_CANCELLED;
}
- snode_notify(C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
return OPERATOR_FINISHED;
}
@@ -816,6 +772,83 @@ void NODE_OT_link_viewer(wmOperatorType *ot)
/** \name Add Link Operator
* \{ */
+/**
+ * Check if any of the dragged links are connected to a socket on the side that they are dragged
+ * from.
+ */
+static bool dragged_links_are_detached(const bNodeLinkDrag &nldrag)
+{
+ if (nldrag.in_out == SOCK_OUT) {
+ for (const bNodeLink *link : nldrag.links) {
+ if (link->tonode && link->tosock) {
+ return false;
+ }
+ }
+ }
+ else {
+ for (const bNodeLink *link : nldrag.links) {
+ if (link->fromnode && link->fromsock) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool should_create_drag_link_search_menu(const bNodeTree &node_tree,
+ const bNodeLinkDrag &nldrag)
+{
+ /* Custom node trees aren't supported yet. */
+ if (node_tree.type == NTREE_CUSTOM) {
+ return false;
+ }
+ /* Only create the search menu when the drag has not already connected the links to a socket. */
+ if (!dragged_links_are_detached(nldrag)) {
+ return false;
+ }
+ /* Don't create the search menu if the drag is disconnecting a link from an input node. */
+ if (nldrag.start_socket->in_out == SOCK_IN && nldrag.start_link_count > 0) {
+ return false;
+ }
+ /* Don't allow a drag from the "new socket" of a group input node. Handling these
+ * properly in node callbacks increases the complexity too much for now. */
+ if (ELEM(nldrag.start_node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
+ if (nldrag.start_socket->type == SOCK_CUSTOM) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void draw_draglink_tooltip(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
+{
+ bNodeLinkDrag *nldrag = static_cast<bNodeLinkDrag *>(arg);
+
+ const uchar text_col[4] = {255, 255, 255, 255};
+ const int padding = 4 * UI_DPI_FAC;
+ const float x = nldrag->in_out == SOCK_IN ? nldrag->cursor[0] - 3.3f * padding :
+ nldrag->cursor[0];
+ const float y = nldrag->cursor[1] - 2.0f * UI_DPI_FAC;
+
+ UI_icon_draw_ex(x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false);
+}
+
+static void draw_draglink_tooltip_activate(const ARegion &region, bNodeLinkDrag &nldrag)
+{
+ if (nldrag.draw_handle == nullptr) {
+ nldrag.draw_handle = ED_region_draw_cb_activate(
+ region.type, draw_draglink_tooltip, &nldrag, REGION_DRAW_POST_PIXEL);
+ }
+}
+
+static void draw_draglink_tooltip_deactivate(const ARegion &region, bNodeLinkDrag &nldrag)
+{
+ if (nldrag.draw_handle) {
+ ED_region_draw_cb_exit(region.type, nldrag.draw_handle);
+ nldrag.draw_handle = nullptr;
+ }
+}
+
static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag))
{
char header[UI_MAX_DRAW_STR];
@@ -824,48 +857,49 @@ static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag))
ED_workspace_status_text(C, header);
}
-static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
+static int node_count_links(const bNodeTree &ntree, const bNodeSocket &socket)
{
int count = 0;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- if (ELEM(socket, link->fromsock, link->tosock)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (ELEM(&socket, link->fromsock, link->tosock)) {
count++;
}
}
return count;
}
-static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
+static void node_remove_extra_links(SpaceNode &snode, bNodeLink &link)
{
- bNodeTree *ntree = snode->edittree;
- bNodeSocket *from = link->fromsock, *to = link->tosock;
+ bNodeTree &ntree = *snode.edittree;
+ bNodeSocket &from = *link.fromsock;
+ bNodeSocket &to = *link.tosock;
int to_count = node_count_links(ntree, to);
int from_count = node_count_links(ntree, from);
- int to_link_limit = nodeSocketLinkLimit(to);
- int from_link_limit = nodeSocketLinkLimit(from);
+ int to_link_limit = nodeSocketLinkLimit(&to);
+ int from_link_limit = nodeSocketLinkLimit(&from);
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, tlink, &ntree->links) {
- if (tlink == link) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, tlink, &ntree.links) {
+ if (tlink == &link) {
continue;
}
- if (tlink && tlink->fromsock == from) {
+ if (tlink && tlink->fromsock == &from) {
if (from_count > from_link_limit) {
- nodeRemLink(ntree, tlink);
+ nodeRemLink(&ntree, tlink);
tlink = nullptr;
from_count--;
}
}
- if (tlink && tlink->tosock == to) {
+ if (tlink && tlink->tosock == &to) {
if (to_count > to_link_limit) {
- nodeRemLink(ntree, tlink);
+ nodeRemLink(&ntree, tlink);
tlink = nullptr;
to_count--;
}
- else if (tlink->fromsock == from) {
+ else if (tlink->fromsock == &from) {
/* Also remove link if it comes from the same output. */
- nodeRemLink(ntree, tlink);
+ nodeRemLink(&ntree, tlink);
tlink = nullptr;
to_count--;
from_count--;
@@ -874,27 +908,17 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
}
}
-static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
+static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
- bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata;
- bool do_tag_update = false;
- /* View will be reset if no links connect. */
- bool reset_view = true;
+ Main *bmain = CTX_data_main(&C);
+ ARegion &region = *CTX_wm_region(&C);
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeTree &ntree = *snode.edittree;
+ bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op.customdata;
/* avoid updates while applying links */
- ntree->is_updating = true;
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
-
- /* See note below, but basically TEST flag means that the link
- * was connected to output (or to a node which affects the
- * output).
- */
- do_tag_update |= (link->flag & NODE_LINK_TEST) != 0;
-
+ ntree.is_updating = true;
+ for (bNodeLink *link : nldrag->links) {
link->flag &= ~NODE_LINK_DRAGGED;
if (apply_links && link->tosock && link->fromsock) {
@@ -902,63 +926,47 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
* let nodes perform special link insertion handling
*/
if (link->fromnode->typeinfo->insert_link) {
- link->fromnode->typeinfo->insert_link(ntree, link->fromnode, link);
+ link->fromnode->typeinfo->insert_link(&ntree, link->fromnode, link);
}
if (link->tonode->typeinfo->insert_link) {
- link->tonode->typeinfo->insert_link(ntree, link->tonode, link);
+ link->tonode->typeinfo->insert_link(&ntree, link->tonode, link);
}
/* add link to the node tree */
- BLI_addtail(&ntree->links, link);
-
- ntree->update |= NTREE_UPDATE_LINKS;
-
- /* tag tonode for update */
- link->tonode->update |= NODE_UPDATE;
+ BLI_addtail(&ntree.links, link);
+ BKE_ntree_update_tag_link_added(&ntree, link);
/* we might need to remove a link */
- node_remove_extra_links(snode, link);
-
- if (link->tonode) {
- do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, link->tonode));
- }
-
- reset_view = false;
+ node_remove_extra_links(snode, *link);
}
else {
- nodeRemLink(ntree, link);
+ nodeRemLink(&ntree, link);
}
}
- ntree->is_updating = false;
+ ntree.is_updating = false;
- ntreeUpdateTree(bmain, ntree);
- snode_notify(C, snode);
- if (do_tag_update) {
- snode_dag_update(C, snode);
- }
+ ED_node_tree_propagate_change(&C, bmain, &ntree);
- if (reset_view) {
- UI_view2d_edge_pan_cancel(C, &nldrag->pan_data);
- }
+ /* Ensure draglink tooltip is disabled. */
+ draw_draglink_tooltip_deactivate(*CTX_wm_region(&C), *nldrag);
+
+ ED_workspace_status_text(&C, nullptr);
+ ED_region_tag_redraw(&region);
+ clear_picking_highlight(&snode.edittree->links);
- BLI_remlink(&snode->runtime->linkdrag, nldrag);
- /* links->data pointers are either held by the tree or freed already */
- BLI_freelistN(&nldrag->links);
- MEM_freeN(nldrag);
+ snode.runtime->linkdrag.reset();
}
-static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
+static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cursor)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata;
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op.customdata;
if (nldrag->in_out == SOCK_OUT) {
bNode *tnode;
bNodeSocket *tsock = nullptr;
if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
-
+ for (bNodeLink *link : nldrag->links) {
/* skip if socket is on the same node as the fromsock */
if (tnode && link->fromnode == tnode) {
continue;
@@ -966,7 +974,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
/* Skip if tsock is already linked with this output. */
bNodeLink *existing_link_connected_to_fromsock = nullptr;
- LISTBASE_FOREACH (bNodeLink *, existing_link, &snode->edittree->links) {
+ LISTBASE_FOREACH (bNodeLink *, existing_link, &snode.edittree->links) {
if (existing_link->fromsock == link->fromsock && existing_link->tosock == tsock) {
existing_link_connected_to_fromsock = existing_link;
break;
@@ -983,16 +991,15 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
continue;
}
if (link->tosock && link->tosock->flag & SOCK_MULTI_INPUT) {
- sort_multi_input_socket_links(snode, tnode, link, cursor);
+ sort_multi_input_socket_links(snode, *tnode, link, &cursor);
}
}
}
else {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
+ for (bNodeLink *link : nldrag->links) {
if (nldrag->last_node_hovered_while_dragging_a_link) {
sort_multi_input_socket_links(
- snode, nldrag->last_node_hovered_while_dragging_a_link, nullptr, cursor);
+ snode, *nldrag->last_node_hovered_while_dragging_a_link, nullptr, &cursor);
}
link->tonode = nullptr;
link->tosock = nullptr;
@@ -1003,9 +1010,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
bNode *tnode;
bNodeSocket *tsock = nullptr;
if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_OUT)) {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
-
+ for (bNodeLink *link : nldrag->links) {
/* skip if this is already the target socket */
if (link->fromsock == tsock) {
continue;
@@ -1021,9 +1026,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
}
}
else {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
-
+ for (bNodeLink *link : nldrag->links) {
link->fromnode = nullptr;
link->fromsock = nullptr;
}
@@ -1036,85 +1039,97 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata;
+ SpaceNode &snode = *CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
- float cursor[2];
UI_view2d_edge_pan_apply_event(C, &nldrag->pan_data, event);
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
+ float2 cursor;
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor.x, &cursor.y);
+ nldrag->cursor[0] = event->mval[0];
+ nldrag->cursor[1] = event->mval[1];
switch (event->type) {
case MOUSEMOVE:
if (nldrag->from_multi_input_socket && !RNA_boolean_get(op->ptr, "has_link_picked")) {
- pick_input_link_by_link_intersect(C, op, nldrag, cursor);
+ pick_input_link_by_link_intersect(*C, *op, *nldrag, cursor);
}
else {
- node_link_find_socket(C, op, cursor);
+ node_link_find_socket(*C, *op, cursor);
node_link_update_header(C, nldrag);
ED_region_tag_redraw(region);
}
- break;
+ if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) {
+ draw_draglink_tooltip_activate(*region, *nldrag);
+ }
+ else {
+ draw_draglink_tooltip_deactivate(*region, *nldrag);
+ }
+ break;
case LEFTMOUSE:
+ if (event->val == KM_RELEASE) {
+ /* Add a search menu for compatible sockets if the drag released on empty space. */
+ if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) {
+ bNodeLink &link = *nldrag->links.first();
+ if (nldrag->in_out == SOCK_OUT) {
+ invoke_node_link_drag_add_menu(*C, *link.fromnode, *link.fromsock, cursor);
+ }
+ else {
+ invoke_node_link_drag_add_menu(*C, *link.tonode, *link.tosock, cursor);
+ }
+ }
+
+ /* Finish link. */
+ node_link_exit(*C, *op, true);
+ return OPERATOR_FINISHED;
+ }
+ break;
case RIGHTMOUSE:
case MIDDLEMOUSE: {
if (event->val == KM_RELEASE) {
- node_link_exit(C, op, true);
-
- ED_workspace_status_text(C, nullptr);
- ED_region_tag_redraw(region);
- SpaceNode *snode = CTX_wm_space_node(C);
- clear_picking_highlight(&snode->edittree->links);
+ node_link_exit(*C, *op, true);
return OPERATOR_FINISHED;
}
break;
}
+ case EVT_ESCKEY: {
+ node_link_exit(*C, *op, true);
+ return OPERATOR_FINISHED;
+ }
}
return OPERATOR_RUNNING_MODAL;
}
-/* return 1 when socket clicked */
-static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor[2], bool detach)
+static std::unique_ptr<bNodeLinkDrag> node_link_init(SpaceNode &snode,
+ float2 cursor,
+ const bool detach)
{
- bNodeLinkDrag *nldrag = nullptr;
-
/* output indicated? */
bNode *node;
bNodeSocket *sock;
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) {
- nldrag = (bNodeLinkDrag *)MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata");
-
- const int num_links = nodeCountSocketLinks(snode->edittree, sock);
+ std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>();
+ nldrag->start_node = node;
+ nldrag->start_socket = sock;
+ nldrag->start_link_count = nodeCountSocketLinks(snode.edittree, sock);
int link_limit = nodeSocketLinkLimit(sock);
- if (num_links > 0 && (num_links >= link_limit || detach)) {
+ if (nldrag->start_link_count > 0 && (nldrag->start_link_count >= link_limit || detach)) {
/* dragged links are fixed on input side */
nldrag->in_out = SOCK_IN;
/* detach current links and store them in the operator data */
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) {
if (link->fromsock == sock) {
- LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data");
- bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
- linkdata->data = oplink;
+ bNodeLink *oplink = MEM_cnew<bNodeLink>("drag link op link");
*oplink = *link;
oplink->next = oplink->prev = nullptr;
oplink->flag |= NODE_LINK_VALID;
oplink->flag |= NODE_LINK_DRAGGED;
- /* The link could be disconnected and in that case we
- * wouldn't be able to check whether tag update is
- * needed or not when releasing mouse button. So we
- * cache whether the link affects output or not here
- * using TEST flag.
- */
- oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, snode->edittree, link->tonode)) {
- oplink->flag |= NODE_LINK_TEST;
- }
-
- BLI_addtail(&nldrag->links, linkdata);
- nodeRemLink(snode->edittree, link);
+ nldrag->links.append(oplink);
+ nodeRemLink(snode.edittree, link);
}
}
}
@@ -1122,23 +1137,25 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor
/* dragged links are fixed on output side */
nldrag->in_out = SOCK_OUT;
/* create a new link */
- LinkData *linkdata = create_drag_link(bmain, snode, node, sock);
-
- BLI_addtail(&nldrag->links, linkdata);
+ nldrag->links.append(create_drag_link(*node, *sock));
}
+ return nldrag;
}
+
/* or an input? */
- else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
- nldrag = (bNodeLinkDrag *)MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata");
+ if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
+ std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>();
nldrag->last_node_hovered_while_dragging_a_link = node;
+ nldrag->start_node = node;
+ nldrag->start_socket = sock;
- const int num_links = nodeCountSocketLinks(snode->edittree, sock);
- if (num_links > 0) {
+ nldrag->start_link_count = nodeCountSocketLinks(snode.edittree, sock);
+ if (nldrag->start_link_count > 0) {
/* dragged links are fixed on output side */
nldrag->in_out = SOCK_OUT;
/* detach current links and store them in the operator data */
bNodeLink *link_to_pick;
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) {
if (link->tosock == sock) {
if (sock->flag & SOCK_MULTI_INPUT) {
nldrag->from_multi_input_socket = true;
@@ -1148,24 +1165,18 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor
}
if (link_to_pick != nullptr && !nldrag->from_multi_input_socket) {
- LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data");
- bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
- linkdata->data = oplink;
+ bNodeLink *oplink = MEM_cnew<bNodeLink>("drag link op link");
*oplink = *link_to_pick;
oplink->next = oplink->prev = nullptr;
oplink->flag |= NODE_LINK_VALID;
oplink->flag |= NODE_LINK_DRAGGED;
- oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, snode->edittree, link_to_pick->tonode)) {
- oplink->flag |= NODE_LINK_TEST;
- }
- BLI_addtail(&nldrag->links, linkdata);
- nodeRemLink(snode->edittree, link_to_pick);
+ nldrag->links.append(oplink);
+ nodeRemLink(snode.edittree, link_to_pick);
/* send changed event to original link->tonode */
if (node) {
- snode_update(snode, node);
+ BKE_ntree_update_tag_node_property(snode.edittree, node);
}
}
}
@@ -1173,37 +1184,40 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor
/* dragged links are fixed on input side */
nldrag->in_out = SOCK_IN;
/* create a new link */
- LinkData *linkdata = create_drag_link(bmain, snode, node, sock);
-
- BLI_addtail(&nldrag->links, linkdata);
+ nldrag->links.append(create_drag_link(*node, *sock));
}
+ return nldrag;
}
- return nldrag;
+ return {};
}
static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
bool detach = RNA_boolean_get(op->ptr, "detach");
- float cursor[2];
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
+ float2 cursor;
+ UI_view2d_region_to_view(&region.v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
RNA_float_set_array(op->ptr, "drag_start", cursor);
RNA_boolean_set(op->ptr, "has_link_picked", false);
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
- bNodeLinkDrag *nldrag = node_link_init(bmain, snode, cursor, detach);
+ std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(snode, cursor, detach);
if (nldrag) {
UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op);
- op->customdata = nldrag;
- BLI_addtail(&snode->runtime->linkdrag, nldrag);
+ /* Add "+" icon when the link is dragged in empty space. */
+ if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) {
+ draw_draglink_tooltip_activate(*CTX_wm_region(C), *nldrag);
+ }
+ snode.runtime->linkdrag = std::move(nldrag);
+ op->customdata = snode.runtime->linkdrag.get();
/* add modal handler */
WM_event_add_modal_handler(C, op);
@@ -1218,12 +1232,10 @@ static void node_link_cancel(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata;
- BLI_remlink(&snode->runtime->linkdrag, nldrag);
-
UI_view2d_edge_pan_cancel(C, &nldrag->pan_data);
- BLI_freelistN(&nldrag->links);
- MEM_freeN(nldrag);
+ snode->runtime->linkdrag.reset();
+
clear_picking_highlight(&snode->edittree->links);
}
@@ -1286,11 +1298,11 @@ void NODE_OT_link(wmOperatorType *ot)
/* makes a link between selected output and input sockets */
static int node_make_link_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
const bool replace = RNA_boolean_get(op->ptr, "replace");
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
snode_autoconnect(bmain, snode, true, replace);
@@ -1298,9 +1310,7 @@ static int node_make_link_exec(bContext *C, wmOperator *op)
node_deselect_all_input_sockets(snode, false);
node_deselect_all_output_sockets(snode, false);
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
return OPERATOR_FINISHED;
}
@@ -1330,7 +1340,7 @@ void NODE_OT_link_make(wmOperatorType *ot)
/** \name Node Link Intersect
* \{ */
-static bool node_links_intersect(bNodeLink *link, const float mcoords[][2], int tot)
+static bool node_links_intersect(bNodeLink &link, const float mcoords[][2], int tot)
{
float coord_array[NODE_LINK_RESOL + 1][2];
@@ -1354,10 +1364,9 @@ static bool node_links_intersect(bNodeLink *link, const float mcoords[][2], int
static int cut_links_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
- bool do_tag_update = false;
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
int i = 0;
float mcoords[256][2];
@@ -1366,7 +1375,7 @@ static int cut_links_exec(bContext *C, wmOperator *op)
RNA_float_get_array(&itemptr, "loc", loc);
UI_view2d_region_to_view(
- &region->v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
+ &region.v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
i++;
if (i >= 256) {
break;
@@ -1377,38 +1386,29 @@ static int cut_links_exec(bContext *C, wmOperator *op)
if (i > 1) {
bool found = false;
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
continue;
}
- if (node_links_intersect(link, mcoords, i)) {
+ if (node_links_intersect(*link, mcoords, i)) {
if (found == false) {
/* TODO(sergey): Why did we kill jobs twice? */
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
found = true;
}
- do_tag_update |= (do_tag_update ||
- node_connected_to_output(bmain, snode->edittree, link->tonode));
-
- snode_update(snode, link->tonode);
bNode *to_node = link->tonode;
- nodeRemLink(snode->edittree, link);
- sort_multi_input_socket_links(snode, to_node, nullptr, nullptr);
+ nodeRemLink(snode.edittree, link);
+ sort_multi_input_socket_links(snode, *to_node, nullptr, nullptr);
}
}
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
if (found) {
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
- if (do_tag_update) {
- snode_dag_update(C, snode);
- }
-
return OPERATOR_FINISHED;
}
@@ -1451,10 +1451,9 @@ void NODE_OT_links_cut(wmOperatorType *ot)
static int mute_links_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
- bool do_tag_update = false;
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
int i = 0;
float mcoords[256][2];
@@ -1463,7 +1462,7 @@ static int mute_links_exec(bContext *C, wmOperator *op)
RNA_float_get_array(&itemptr, "loc", loc);
UI_view2d_region_to_view(
- &region->v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
+ &region.v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
i++;
if (i >= 256) {
break;
@@ -1472,16 +1471,16 @@ static int mute_links_exec(bContext *C, wmOperator *op)
RNA_END;
if (i > 1) {
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
/* Count intersected links and clear test flag. */
int tot = 0;
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
continue;
}
link->flag &= ~NODE_LINK_TEST;
- if (node_links_intersect(link, mcoords, i)) {
+ if (node_links_intersect(*link, mcoords, i)) {
tot++;
}
}
@@ -1490,34 +1489,25 @@ static int mute_links_exec(bContext *C, wmOperator *op)
}
/* Mute links. */
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link) || (link->flag & NODE_LINK_TEST)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link) || (link->flag & NODE_LINK_TEST)) {
continue;
}
- if (node_links_intersect(link, mcoords, i)) {
- do_tag_update |= (do_tag_update ||
- node_connected_to_output(bmain, snode->edittree, link->tonode));
-
- snode_update(snode, link->tonode);
- nodeMuteLinkToggle(snode->edittree, link);
+ if (node_links_intersect(*link, mcoords, i)) {
+ nodeMuteLinkToggle(snode.edittree, link);
}
}
/* Clear remaining test flags. */
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
continue;
}
link->flag &= ~NODE_LINK_TEST;
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
- if (do_tag_update) {
- snode_dag_update(C, snode);
- }
-
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
return OPERATOR_FINISHED;
}
@@ -1557,22 +1547,18 @@ void NODE_OT_links_mute(wmOperatorType *ot)
static int detach_links_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (node->flag & SELECT) {
- nodeInternalRelink(ntree, node);
+ nodeInternalRelink(&ntree, node);
}
}
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- snode_notify(C, snode);
- snode_dag_update(C, snode);
-
+ ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree);
return OPERATOR_FINISHED;
}
@@ -1598,14 +1584,14 @@ void NODE_OT_links_detach(wmOperatorType *ot)
static int node_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
- bNode *frame = nodeGetActive(ntree);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
+ bNode *frame = nodeGetActive(&ntree);
if (!frame || frame->type != NODE_FRAME) {
return OPERATOR_CANCELLED;
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (node == frame) {
continue;
}
@@ -1615,7 +1601,7 @@ static int node_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ED_node_sort(ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -1678,12 +1664,12 @@ static void node_join_attach_recursive(bNode *node, bNode *frame)
static int node_join_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
/* XXX save selection: node_add_node call below sets the new frame as single
* active+selected node */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (node->flag & NODE_SELECT) {
node->flag |= NODE_TEST;
}
@@ -1692,27 +1678,27 @@ static int node_join_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- bNode *frame = node_add_node(C, nullptr, NODE_FRAME, 0.0f, 0.0f);
+ bNode *frame = node_add_node(*C, nullptr, NODE_FRAME, 0.0f, 0.0f);
/* reset tags */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
node->done = 0;
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (!(node->done & NODE_JOIN_DONE)) {
node_join_attach_recursive(node, frame);
}
}
/* restore selection */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (node->flag & NODE_TEST) {
node->flag |= NODE_SELECT;
}
}
- ED_node_sort(ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -1739,15 +1725,15 @@ void NODE_OT_join(wmOperatorType *ot)
/** \name Attach Operator
* \{ */
-static bNode *node_find_frame_to_attach(ARegion *region,
- const bNodeTree *ntree,
+static bNode *node_find_frame_to_attach(ARegion &region,
+ const bNodeTree &ntree,
const int mouse_xy[2])
{
/* convert mouse coordinates to v2d space */
float cursor[2];
- UI_view2d_region_to_view(&region->v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]);
+ UI_view2d_region_to_view(&region.v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]);
- LISTBASE_FOREACH_BACKWARD (bNode *, frame, &ntree->nodes) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, frame, &ntree.nodes) {
/* skip selected, those are the nodes we want to attach */
if ((frame->type != NODE_FRAME) || (frame->flag & NODE_SELECT)) {
continue;
@@ -1762,13 +1748,13 @@ static bNode *node_find_frame_to_attach(ARegion *region,
static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- ARegion *region = CTX_wm_region(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ ARegion &region = *CTX_wm_region(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
bNode *frame = node_find_frame_to_attach(region, ntree, event->mval);
if (frame) {
- LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
if (node->flag & NODE_SELECT) {
if (node->parent == nullptr) {
/* disallow moving a parent into its child */
@@ -1798,7 +1784,7 @@ static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
}
}
- ED_node_sort(ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -1858,23 +1844,23 @@ static void node_detach_recursive(bNode *node)
/* detach the root nodes in the current selection */
static int node_detach_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
/* reset tags */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
node->done = 0;
}
/* detach nodes recursively
* relative order is preserved here!
*/
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (!(node->done & NODE_DETACH_DONE)) {
node_detach_recursive(node);
}
}
- ED_node_sort(ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -1946,7 +1932,7 @@ static bool ed_node_link_conditions(ScrArea *area,
/* test node for links */
LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ if (node_link_is_hidden_or_dimmed(region->v2d, *link)) {
continue;
}
@@ -1959,9 +1945,12 @@ static bool ed_node_link_conditions(ScrArea *area,
return true;
}
-/* test == 0, clear all intersect flags */
+} // namespace blender::ed::space_node
+
void ED_node_link_intersect_test(ScrArea *area, int test)
{
+ using namespace blender::ed::space_node;
+
bNode *select;
SpaceNode *snode;
if (!ed_node_link_conditions(area, test, &snode, &select)) {
@@ -1985,11 +1974,11 @@ void ED_node_link_intersect_test(ScrArea *area, int test)
LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
float coord_array[NODE_LINK_RESOL + 1][2];
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ if (node_link_is_hidden_or_dimmed(region->v2d, *link)) {
continue;
}
- if (node_link_bezier_points(nullptr, nullptr, link, coord_array, NODE_LINK_RESOL)) {
+ if (node_link_bezier_points(nullptr, nullptr, *link, coord_array, NODE_LINK_RESOL)) {
float dist = FLT_MAX;
/* loop over link coords to find shortest dist to
@@ -2021,6 +2010,8 @@ void ED_node_link_intersect_test(ScrArea *area, int test)
}
}
+namespace blender::ed::space_node {
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2031,18 +2022,19 @@ static int get_main_socket_priority(const bNodeSocket *socket)
{
switch ((eNodeSocketDatatype)socket->type) {
case __SOCK_MESH:
- case SOCK_CUSTOM:
return -1;
- case SOCK_BOOLEAN:
+ case SOCK_CUSTOM:
return 0;
- case SOCK_INT:
+ case SOCK_BOOLEAN:
return 1;
- case SOCK_FLOAT:
+ case SOCK_INT:
return 2;
- case SOCK_VECTOR:
+ case SOCK_FLOAT:
return 3;
- case SOCK_RGBA:
+ case SOCK_VECTOR:
return 4;
+ case SOCK_RGBA:
+ return 5;
case SOCK_STRING:
case SOCK_SHADER:
case SOCK_OBJECT:
@@ -2051,14 +2043,34 @@ static int get_main_socket_priority(const bNodeSocket *socket)
case SOCK_COLLECTION:
case SOCK_TEXTURE:
case SOCK_MATERIAL:
- return 5;
+ return 6;
}
return -1;
}
-/** Get the "main" socket of a socket list using a heuristic based on socket types. */
-static bNodeSocket *get_main_socket(ListBase *sockets)
+/** Get the "main" socket based on the node declaration or an heuristic. */
+static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out)
{
+ ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs;
+
+ /* Try to get the main socket based on the socket declaration. */
+ nodeDeclarationEnsure(&ntree, &node);
+ const nodes::NodeDeclaration *node_decl = node.declaration;
+ if (node_decl != nullptr) {
+ Span<nodes::SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() :
+ node_decl->outputs();
+ int index;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) {
+ const nodes::SocketDeclaration &socket_decl = *socket_decls[index];
+ if (nodeSocketIsHidden(socket)) {
+ continue;
+ }
+ if (socket_decl.is_default_link_socket()) {
+ return socket;
+ }
+ }
+ }
+
/* find priority range */
int maxpriority = -1;
LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
@@ -2101,19 +2113,19 @@ static bool node_parents_offset_flag_enable_cb(bNode *parent, void *UNUSED(userd
return true;
}
-static void node_offset_apply(bNode *node, const float offset_x)
+static void node_offset_apply(bNode &node, const float offset_x)
{
/* NODE_TEST is used to flag nodes that shouldn't be offset (again) */
- if ((node->flag & NODE_TEST) == 0) {
- node->anim_init_locx = node->locx;
- node->anim_ofsx = (offset_x / UI_DPI_FAC);
- node->flag |= NODE_TEST;
+ if ((node.flag & NODE_TEST) == 0) {
+ node.anim_init_locx = node.locx;
+ node.anim_ofsx = (offset_x / UI_DPI_FAC);
+ node.flag |= NODE_TEST;
}
}
static void node_parent_offset_apply(NodeInsertOfsData *data, bNode *parent, const float offset_x)
{
- node_offset_apply(parent, offset_x);
+ node_offset_apply(*parent, offset_x);
/* Flag all children as offset to prevent them from being offset
* separately (they've already moved with the parent). */
@@ -2140,10 +2152,10 @@ static bool node_link_insert_offset_frame_chain_cb(bNode *fromnode,
bNode *ofs_node = reversed ? fromnode : tonode;
if (ofs_node->parent && ofs_node->parent != data->insert_parent) {
- node_offset_apply(ofs_node->parent, data->offset_x);
+ node_offset_apply(*ofs_node->parent, data->offset_x);
}
else {
- node_offset_apply(ofs_node, data->offset_x);
+ node_offset_apply(*ofs_node, data->offset_x);
}
return true;
@@ -2182,7 +2194,7 @@ static bool node_link_insert_offset_chain_cb(bNode *fromnode,
node_link_insert_offset_frame_chains(data->ntree, ofs_node->parent, data, reversed);
}
else {
- node_offset_apply(ofs_node, data->offset_x);
+ node_offset_apply(*ofs_node, data->offset_x);
}
if (nodeIsChildOf(data->insert_parent, ofs_node) == false) {
@@ -2191,10 +2203,10 @@ static bool node_link_insert_offset_chain_cb(bNode *fromnode,
}
else if (ofs_node->parent) {
bNode *node = nodeFindRootParent(ofs_node);
- node_offset_apply(node, data->offset_x);
+ node_offset_apply(*node, data->offset_x);
}
else {
- node_offset_apply(ofs_node, data->offset_x);
+ node_offset_apply(*ofs_node, data->offset_x);
}
return true;
@@ -2206,9 +2218,9 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
const bool right_alignment)
{
bNodeTree *ntree = iofsd->ntree;
- bNode *insert = iofsd->insert;
+ bNode &insert = *iofsd->insert;
bNode *prev = iofsd->prev, *next = iofsd->next;
- bNode *init_parent = insert->parent; /* store old insert->parent for restoring later */
+ bNode *init_parent = insert.parent; /* store old insert.parent for restoring later */
const float min_margin = U.node_margin * UI_DPI_FAC;
const float width = NODE_WIDTH(insert);
@@ -2219,20 +2231,20 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
/* NODE_TEST will be used later, so disable for all nodes */
ntreeNodeFlagSet(ntree, NODE_TEST, false);
- /* insert->totr isn't updated yet,
- * so totr_insert is used to get the correct worldspace coords */
+ /* `insert.totr` isn't updated yet,
+ * so `totr_insert` is used to get the correct world-space coords. */
rctf totr_insert;
- node_to_updated_rect(insert, &totr_insert);
+ node_to_updated_rect(insert, totr_insert);
/* frame attachment wasn't handled yet
* so we search the frame that the node will be attached to later */
- insert->parent = node_find_frame_to_attach(region, ntree, mouse_xy);
+ insert.parent = node_find_frame_to_attach(*region, *ntree, mouse_xy);
/* this makes sure nodes are also correctly offset when inserting a node on top of a frame
* without actually making it a part of the frame (because mouse isn't intersecting it)
* - logic here is similar to node_find_frame_to_attach */
- if (!insert->parent ||
- (prev->parent && (prev->parent == next->parent) && (prev->parent != insert->parent))) {
+ if (!insert.parent ||
+ (prev->parent && (prev->parent == next->parent) && (prev->parent != insert.parent))) {
bNode *frame;
rctf totr_frame;
@@ -2244,15 +2256,15 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
}
/* for some reason frame y coords aren't correct yet */
- node_to_updated_rect(frame, &totr_frame);
+ node_to_updated_rect(*frame, totr_frame);
if (BLI_rctf_isect_x(&totr_frame, totr_insert.xmin) &&
BLI_rctf_isect_x(&totr_frame, totr_insert.xmax)) {
if (BLI_rctf_isect_y(&totr_frame, totr_insert.ymin) ||
BLI_rctf_isect_y(&totr_frame, totr_insert.ymax)) {
- /* frame isn't insert->parent actually, but this is needed to make offsetting
+ /* frame isn't insert.parent actually, but this is needed to make offsetting
* nodes work correctly for above checked cases (it is restored later) */
- insert->parent = frame;
+ insert.parent = frame;
break;
}
}
@@ -2282,12 +2294,12 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
const float addval = (min_margin - dist) * (right_alignment ? 1.0f : -1.0f);
if (needs_alignment) {
bNode *offs_node = right_alignment ? next : prev;
- if (!offs_node->parent || offs_node->parent == insert->parent ||
- nodeIsChildOf(offs_node->parent, insert)) {
- node_offset_apply(offs_node, addval);
+ if (!offs_node->parent || offs_node->parent == insert.parent ||
+ nodeIsChildOf(offs_node->parent, &insert)) {
+ node_offset_apply(*offs_node, addval);
}
- else if (!insert->parent && offs_node->parent) {
- node_offset_apply(nodeFindRootParent(offs_node), addval);
+ else if (!insert.parent && offs_node->parent) {
+ node_offset_apply(*nodeFindRootParent(offs_node), addval);
}
margin = addval;
}
@@ -2299,11 +2311,11 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
}
if (needs_alignment) {
- iofsd->insert_parent = insert->parent;
+ iofsd->insert_parent = insert.parent;
iofsd->offset_x = margin;
/* flag all parents of insert as offset to prevent them from being offset */
- nodeParentsIter(insert, node_parents_offset_flag_enable_cb, nullptr);
+ nodeParentsIter(&insert, node_parents_offset_flag_enable_cb, nullptr);
/* iterate over entire chain and apply offsets */
nodeChainIter(ntree,
right_alignment ? next : prev,
@@ -2312,7 +2324,7 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
!right_alignment);
}
- insert->parent = init_parent;
+ insert.parent = init_parent;
}
/**
@@ -2413,13 +2425,16 @@ void NODE_OT_insert_offset(wmOperatorType *ot)
/** \} */
+} // namespace blender::ed::space_node
+
/* -------------------------------------------------------------------- */
/** \name Note Link Insert
* \{ */
-/* assumes link with NODE_LINKFLAG_HILITE set */
void ED_node_link_insert(Main *bmain, ScrArea *area)
{
+ using namespace blender::ed::space_node;
+
bNode *select;
SpaceNode *snode;
if (!ed_node_link_conditions(area, true, &snode, &select)) {
@@ -2435,8 +2450,8 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
}
if (link) {
- bNodeSocket *best_input = get_main_socket(&select->inputs);
- bNodeSocket *best_output = get_main_socket(&select->outputs);
+ bNodeSocket *best_input = get_main_socket(*snode->edittree, *select, SOCK_IN);
+ bNodeSocket *best_output = get_main_socket(*snode->edittree, *select, SOCK_OUT);
if (best_input && best_output) {
bNode *node = link->tonode;
@@ -2444,7 +2459,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
link->tonode = select;
link->tosock = best_input;
- node_remove_extra_links(snode, link);
+ node_remove_extra_links(*snode, *link);
link->flag &= ~NODE_LINKFLAG_HILITE;
bNodeLink *new_link = nodeAddLink(snode->edittree, select, best_output, node, sockto);
@@ -2456,8 +2471,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
/* set up insert offset data, it needs stuff from here */
if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
- NodeInsertOfsData *iofsd = (NodeInsertOfsData *)MEM_callocN(sizeof(NodeInsertOfsData),
- __func__);
+ NodeInsertOfsData *iofsd = MEM_cnew<NodeInsertOfsData>(__func__);
iofsd->insert = select;
iofsd->prev = link->fromnode;
@@ -2466,10 +2480,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
snode->runtime->iofsd = iofsd;
}
- ntreeUpdateTree(bmain, snode->edittree); /* needed for pointers */
- snode_update(snode, select);
- ED_node_tag_update_id((ID *)snode->edittree);
- ED_node_tag_update_id(snode->id);
+ ED_node_tree_propagate_change(nullptr, bmain, snode->edittree);
}
}
}
diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc
index 29b8372d043..2751a53e8af 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -29,7 +29,6 @@
#include "BLI_lasso_2d.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_string_search.h"
@@ -61,7 +60,9 @@
#include "MEM_guardedalloc.h"
-#include "node_intern.h" /* own include */
+#include "node_intern.hh" /* own include */
+
+namespace blender::ed::space_node {
/**
* Function to detect if there is a visible view3d that uses workbench in texture mode.
@@ -98,43 +99,45 @@ static bool has_workbench_in_texture_color(const wmWindowManager *wm,
/** \name Public Node Selection API
* \{ */
-static bNode *node_under_mouse_select(bNodeTree *ntree, int mx, int my)
+static bNode *node_under_mouse_select(bNodeTree &ntree, int mx, int my)
{
- bNode *node;
-
- for (node = (bNode *)ntree->nodes.last; node; node = node->prev) {
- if (node->typeinfo->select_area_func) {
- if (node->typeinfo->select_area_func(node, mx, my)) {
- return node;
- }
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
+ if (BLI_rctf_isect_pt(&node->totr, mx, my)) {
+ return node;
}
}
return nullptr;
}
-static bNode *node_under_mouse_tweak(bNodeTree *ntree, int mx, int my)
+static bNode *node_under_mouse_tweak(bNodeTree &ntree, const float2 &mouse)
{
- bNode *node;
+ using namespace blender::math;
- for (node = (bNode *)ntree->nodes.last; node; node = node->prev) {
- if (node->typeinfo->tweak_area_func) {
- if (node->typeinfo->tweak_area_func(node, mx, my)) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
+ if (node->type == NODE_REROUTE) {
+ bNodeSocket *socket = (bNodeSocket *)node->inputs.first;
+ const float2 location{socket->locx, socket->locy};
+ if (distance(mouse, location) < 24.0f) {
return node;
}
}
+ if (BLI_rctf_isect_pt(&node->totr, mouse.x, mouse.y)) {
+ return node;
+ }
}
return nullptr;
}
-static bool is_position_over_node_or_socket(SpaceNode *snode, float mouse[2])
+static bool is_position_over_node_or_socket(SpaceNode &snode, const float2 &mouse)
{
- if (node_under_mouse_tweak(snode->edittree, mouse[0], mouse[1])) {
+ if (node_under_mouse_tweak(*snode.edittree, mouse)) {
return true;
}
bNode *node;
bNodeSocket *sock;
- if (node_find_indicated_socket(snode, &node, &sock, mouse, SOCK_IN | SOCK_OUT)) {
+ if (node_find_indicated_socket(
+ snode, &node, &sock, mouse, (eNodeSocketInOut)(SOCK_IN | SOCK_OUT))) {
return true;
}
@@ -145,9 +148,9 @@ static bool is_event_over_node_or_socket(bContext *C, const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
- float mouse[2];
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &mouse[0], &mouse[1]);
- return is_position_over_node_or_socket(snode, mouse);
+ float2 mouse;
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &mouse.x, &mouse.y);
+ return is_position_over_node_or_socket(*snode, mouse);
}
static void node_toggle(bNode *node)
@@ -155,9 +158,9 @@ static void node_toggle(bNode *node)
nodeSetSelected(node, !(node->flag & SELECT));
}
-void node_socket_select(bNode *node, bNodeSocket *sock)
+void node_socket_select(bNode *node, bNodeSocket &sock)
{
- sock->flag |= SELECT;
+ sock.flag |= SELECT;
/* select node too */
if (node) {
@@ -165,22 +168,22 @@ void node_socket_select(bNode *node, bNodeSocket *sock)
}
}
-void node_socket_deselect(bNode *node, bNodeSocket *sock, const bool deselect_node)
+void node_socket_deselect(bNode *node, bNodeSocket &sock, const bool deselect_node)
{
- sock->flag &= ~SELECT;
+ sock.flag &= ~SELECT;
if (node && deselect_node) {
bool sel = false;
/* if no selected sockets remain, also deselect the node */
- for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
- if (sock->flag & SELECT) {
+ LISTBASE_FOREACH (bNodeSocket *, input, &node->inputs) {
+ if (input->flag & SELECT) {
sel = true;
break;
}
}
- for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
- if (sock->flag & SELECT) {
+ LISTBASE_FOREACH (bNodeSocket *, output, &node->outputs) {
+ if (output->flag & SELECT) {
sel = true;
break;
}
@@ -192,9 +195,9 @@ void node_socket_deselect(bNode *node, bNodeSocket *sock, const bool deselect_no
}
}
-static void node_socket_toggle(bNode *node, bNodeSocket *sock, int deselect_node)
+static void node_socket_toggle(bNode *node, bNodeSocket &sock, bool deselect_node)
{
- if (sock->flag & SELECT) {
+ if (sock.flag & SELECT) {
node_socket_deselect(node, sock, deselect_node);
}
else {
@@ -202,38 +205,32 @@ static void node_socket_toggle(bNode *node, bNodeSocket *sock, int deselect_node
}
}
-/* no undo here! */
-void node_deselect_all(SpaceNode *snode)
+void node_deselect_all(SpaceNode &snode)
{
- bNode *node;
-
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) {
nodeSetSelected(node, false);
}
}
-void node_deselect_all_input_sockets(SpaceNode *snode, const bool deselect_nodes)
+void node_deselect_all_input_sockets(SpaceNode &snode, const bool deselect_nodes)
{
- bNode *node;
- bNodeSocket *sock;
-
/* XXX not calling node_socket_deselect here each time, because this does iteration
* over all node sockets internally to check if the node stays selected.
* We can do that more efficiently here.
*/
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
- int sel = 0;
+ LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) {
+ bool sel = false;
- for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
- sock->flag &= ~SELECT;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ socket->flag &= ~SELECT;
}
/* if no selected sockets remain, also deselect the node */
if (deselect_nodes) {
- for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
- if (sock->flag & SELECT) {
- sel = 1;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ if (socket->flag & SELECT) {
+ sel = true;
break;
}
}
@@ -245,27 +242,24 @@ void node_deselect_all_input_sockets(SpaceNode *snode, const bool deselect_nodes
}
}
-void node_deselect_all_output_sockets(SpaceNode *snode, const bool deselect_nodes)
+void node_deselect_all_output_sockets(SpaceNode &snode, const bool deselect_nodes)
{
- bNode *node;
- bNodeSocket *sock;
-
/* XXX not calling node_socket_deselect here each time, because this does iteration
* over all node sockets internally to check if the node stays selected.
* We can do that more efficiently here.
*/
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) {
bool sel = false;
- for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
- sock->flag &= ~SELECT;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ socket->flag &= ~SELECT;
}
/* if no selected sockets remain, also deselect the node */
if (deselect_nodes) {
- for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
- if (sock->flag & SELECT) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ if (socket->flag & SELECT) {
sel = true;
break;
}
@@ -286,58 +280,51 @@ void node_deselect_all_output_sockets(SpaceNode *snode, const bool deselect_node
/* Return true if we need redraw, otherwise false. */
-static bool node_select_grouped_type(SpaceNode *snode, bNode *node_act)
+static bool node_select_grouped_type(bNodeTree &node_tree, bNode &node_act)
{
- bNode *node;
bool changed = false;
-
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if ((node->flag & SELECT) == 0) {
- if (node->type == node_act->type) {
+ if (node->type == node_act.type) {
nodeSetSelected(node, true);
changed = true;
}
}
}
-
return changed;
}
-static bool node_select_grouped_color(SpaceNode *snode, bNode *node_act)
+static bool node_select_grouped_color(bNodeTree &node_tree, bNode &node_act)
{
- bNode *node;
bool changed = false;
-
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if ((node->flag & SELECT) == 0) {
- if (compare_v3v3(node->color, node_act->color, 0.005f)) {
+ if (compare_v3v3(node->color, node_act.color, 0.005f)) {
nodeSetSelected(node, true);
changed = true;
}
}
}
-
return changed;
}
-static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bool from_right)
+static bool node_select_grouped_name(bNodeTree &node_tree, bNode &node_act, const bool from_right)
{
- bNode *node;
bool changed = false;
const uint delims[] = {'.', '-', '_', '\0'};
size_t pref_len_act, pref_len_curr;
const char *sep, *suf_act, *suf_curr;
pref_len_act = BLI_str_partition_ex_utf8(
- node_act->name, nullptr, delims, &sep, &suf_act, from_right);
+ node_act.name, nullptr, delims, &sep, &suf_act, from_right);
/* NOTE: in case we are searching for suffix, and found none, use whole name as suffix. */
if (from_right && !(sep && suf_act)) {
pref_len_act = 0;
- suf_act = node_act->name;
+ suf_act = node_act.name;
}
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if (node->flag & SELECT) {
continue;
}
@@ -352,7 +339,7 @@ static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bo
if ((from_right && STREQ(suf_act, suf_curr)) ||
(!from_right && (pref_len_act == pref_len_curr) &&
- STREQLEN(node_act->name, node->name, pref_len_act))) {
+ STREQLEN(node_act.name, node->name, pref_len_act))) {
nodeSetSelected(node, true);
changed = true;
}
@@ -370,20 +357,20 @@ enum {
static int node_select_grouped_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNode *node_act = nodeGetActive(snode->edittree);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &node_tree = *snode.edittree;
+ bNode *node_act = nodeGetActive(snode.edittree);
if (node_act == nullptr) {
return OPERATOR_CANCELLED;
}
- bNode *node;
bool changed = false;
const bool extend = RNA_boolean_get(op->ptr, "extend");
const int type = RNA_enum_get(op->ptr, "type");
if (!extend) {
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
nodeSetSelected(node, false);
}
}
@@ -391,23 +378,23 @@ static int node_select_grouped_exec(bContext *C, wmOperator *op)
switch (type) {
case NODE_SELECT_GROUPED_TYPE:
- changed = node_select_grouped_type(snode, node_act);
+ changed = node_select_grouped_type(node_tree, *node_act);
break;
case NODE_SELECT_GROUPED_COLOR:
- changed = node_select_grouped_color(snode, node_act);
+ changed = node_select_grouped_color(node_tree, *node_act);
break;
case NODE_SELECT_GROUPED_PREFIX:
- changed = node_select_grouped_name(snode, node_act, false);
+ changed = node_select_grouped_name(node_tree, *node_act, false);
break;
case NODE_SELECT_GROUPED_SUFIX:
- changed = node_select_grouped_name(snode, node_act, true);
+ changed = node_select_grouped_name(node_tree, *node_act, true);
break;
default:
break;
}
if (changed) {
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
return OPERATOR_FINISHED;
}
@@ -455,32 +442,32 @@ void NODE_OT_select_grouped(wmOperatorType *ot)
/** \name Select (Cursor Pick) Operator
* \{ */
-void node_select_single(bContext *C, bNode *node)
+void node_select_single(bContext &C, bNode &node)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- const Object *ob = CTX_data_active_object(C);
- const Scene *scene = CTX_data_scene(C);
- const wmWindowManager *wm = CTX_wm_manager(C);
+ Main *bmain = CTX_data_main(&C);
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeTree &node_tree = *snode.edittree;
+ const Object *ob = CTX_data_active_object(&C);
+ const Scene *scene = CTX_data_scene(&C);
+ const wmWindowManager *wm = CTX_wm_manager(&C);
bool active_texture_changed = false;
- bNode *tnode;
- for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) {
- if (tnode != node) {
- nodeSetSelected(tnode, false);
+ LISTBASE_FOREACH (bNode *, node_iter, &node_tree.nodes) {
+ if (node_iter != &node) {
+ nodeSetSelected(node_iter, false);
}
}
- nodeSetSelected(node, true);
+ nodeSetSelected(&node, true);
- ED_node_set_active(bmain, snode, snode->edittree, node, &active_texture_changed);
- ED_node_set_active_viewer_key(snode);
+ ED_node_set_active(bmain, &snode, &node_tree, &node, &active_texture_changed);
+ ED_node_set_active_viewer_key(&snode);
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) {
- DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&node_tree.id, ID_RECALC_COPY_ON_WRITE);
}
- WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
+ WM_event_add_notifier(&C, NC_NODE | NA_SELECTED, nullptr);
}
static int node_mouse_select(bContext *C,
@@ -488,9 +475,9 @@ static int node_mouse_select(bContext *C,
const int mval[2],
bool wait_to_deselect_others)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
const Object *ob = CTX_data_active_object(C);
const Scene *scene = CTX_data_scene(C);
const wmWindowManager *wm = CTX_wm_manager(C);
@@ -511,20 +498,20 @@ static int node_mouse_select(bContext *C,
}
/* get mouse coordinates in view2d space */
- UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
+ UI_view2d_region_to_view(&region.v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
/* first do socket selection, these generally overlap with nodes. */
if (socket_select) {
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
/* NOTE: SOCK_IN does not take into account the extend case...
* This feature is not really used anyway currently? */
- node_socket_toggle(node, sock, true);
+ node_socket_toggle(node, *sock, true);
ret_value = OPERATOR_FINISHED;
}
else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) {
if (sock->flag & SELECT) {
if (extend) {
- node_socket_deselect(node, sock, true);
+ node_socket_deselect(node, *sock, true);
}
else {
ret_value = OPERATOR_FINISHED;
@@ -538,20 +525,20 @@ static int node_mouse_select(bContext *C,
if (tsock == sock) {
continue;
}
- node_socket_deselect(node, tsock, true);
+ node_socket_deselect(node, *tsock, true);
}
}
if (!extend) {
- for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) {
+ for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
if (tnode == node) {
continue;
}
for (tsock = (bNodeSocket *)tnode->outputs.first; tsock; tsock = tsock->next) {
- node_socket_deselect(tnode, tsock, true);
+ node_socket_deselect(tnode, *tsock, true);
}
}
}
- node_socket_select(node, sock);
+ node_socket_select(node, *sock);
ret_value = OPERATOR_FINISHED;
}
}
@@ -559,7 +546,7 @@ static int node_mouse_select(bContext *C,
if (!sock) {
/* find the closest visible node */
- node = node_under_mouse_select(snode->edittree, (int)cursor[0], (int)cursor[1]);
+ node = node_under_mouse_select(*snode.edittree, (int)cursor[0], (int)cursor[1]);
if (extend) {
if (node != nullptr) {
@@ -580,7 +567,7 @@ static int node_mouse_select(bContext *C,
}
else {
/* Deselect in empty space. */
- for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) {
+ for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
nodeSetSelected(tnode, false);
}
ret_value = OPERATOR_FINISHED;
@@ -595,7 +582,7 @@ static int node_mouse_select(bContext *C,
else {
nodeSetSelected(node, true);
- for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) {
+ for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
if (tnode != node) {
nodeSetSelected(tnode, false);
}
@@ -612,16 +599,16 @@ static int node_mouse_select(bContext *C,
bool viewer_node_changed = false;
if (node != nullptr && ret_value != OPERATOR_RUNNING_MODAL) {
viewer_node_changed = (node->flag & NODE_DO_OUTPUT) == 0 && node->type == GEO_NODE_VIEWER;
- ED_node_set_active(bmain, snode, snode->edittree, node, &active_texture_changed);
+ ED_node_set_active(&bmain, &snode, snode.edittree, node, &active_texture_changed);
}
else if (node != nullptr && node->type == GEO_NODE_VIEWER) {
- ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, node);
+ ED_spreadsheet_context_paths_set_geometry_node(&bmain, &snode, node);
}
- ED_node_set_active_viewer_key(snode);
- ED_node_sort(snode->edittree);
+ ED_node_set_active_viewer_key(&snode);
+ node_sort(*snode.edittree);
if ((active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) ||
viewer_node_changed) {
- DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&snode.edittree->id, ID_RECALC_COPY_ON_WRITE);
}
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
@@ -685,20 +672,21 @@ void NODE_OT_select(wmOperatorType *ot)
static int node_box_select_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &node_tree = *snode.edittree;
+ const ARegion &region = *CTX_wm_region(C);
rctf rectf;
WM_operator_properties_border_to_rctf(op, &rectf);
- UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
+ UI_view2d_region_to_view_rctf(&region.v2d, &rectf, &rectf);
const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode");
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT);
+ node_select_all(&node_tree.nodes, SEL_DESELECT);
}
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
bool is_inside;
if (node->type == NODE_FRAME) {
is_inside = BLI_rctf_inside_rctf(&rectf, &node->totr);
@@ -712,7 +700,7 @@ static int node_box_select_exec(bContext *C, wmOperator *op)
}
}
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
@@ -782,7 +770,7 @@ static int node_circleselect_exec(bContext *C, wmOperator *op)
WM_gesture_is_modal_first((const wmGesture *)op->customdata));
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT);
+ node_select_all(&snode->edittree->nodes, SEL_DESELECT);
}
/* get operator properties */
@@ -857,7 +845,7 @@ static bool do_lasso_select_node(bContext *C,
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT);
+ node_select_all(&snode->edittree->nodes, SEL_DESELECT);
changed = true;
}
@@ -944,13 +932,13 @@ void NODE_OT_select_lasso(wmOperatorType *ot)
static int node_select_all_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- ListBase *node_lb = &snode->edittree->nodes;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ListBase *node_lb = &snode.edittree->nodes;
int action = RNA_enum_get(op->ptr, "action");
- ED_node_select_all(node_lb, action);
+ node_select_all(node_lb, action);
- ED_node_sort(snode->edittree);
+ node_sort(*snode.edittree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
return OPERATOR_FINISHED;
@@ -981,15 +969,14 @@ void NODE_OT_select_all(wmOperatorType *ot)
static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeLink *link;
- bNode *node;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &node_tree = *snode.edittree;
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
node->flag &= ~NODE_TEST;
}
- for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) {
+ LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
if (nodeLinkIsHidden(link)) {
continue;
}
@@ -998,13 +985,13 @@ static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if (node->flag & NODE_TEST) {
nodeSetSelected(node, true);
}
}
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
return OPERATOR_FINISHED;
@@ -1033,15 +1020,14 @@ void NODE_OT_select_linked_to(wmOperatorType *ot)
static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeLink *link;
- bNode *node;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &node_tree = *snode.edittree;
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
node->flag &= ~NODE_TEST;
}
- for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) {
+ LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
if (nodeLinkIsHidden(link)) {
continue;
}
@@ -1050,13 +1036,13 @@ static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if (node->flag & NODE_TEST) {
nodeSetSelected(node, true);
}
}
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
return OPERATOR_FINISHED;
@@ -1149,13 +1135,13 @@ static int node_select_same_type_step_exec(bContext *C, wmOperator *op)
}
}
- node_select_single(C, active);
+ node_select_single(*C, *active);
/* is note outside view? */
if (active->totr.xmax < region->v2d.cur.xmin || active->totr.xmin > region->v2d.cur.xmax ||
active->totr.ymax < region->v2d.cur.ymin || active->totr.ymin > region->v2d.cur.ymax) {
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- space_node_view_flag(C, snode, region, NODE_SELECT, smooth_viewtx);
+ space_node_view_flag(*C, *snode, *region, NODE_SELECT, smooth_viewtx);
}
}
@@ -1213,7 +1199,7 @@ static void node_find_update_fn(const struct bContext *C,
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
char name[256];
node_find_create_label(node, name, ARRAY_SIZE(name));
- BLI_string_search_add(search, name, node);
+ BLI_string_search_add(search, name, node, 0);
}
bNode **filtered_nodes;
@@ -1239,12 +1225,12 @@ static void node_find_exec_fn(struct bContext *C, void *UNUSED(arg1), void *arg2
if (active) {
ARegion *region = CTX_wm_region(C);
- node_select_single(C, active);
+ node_select_single(*C, *active);
/* is note outside view? */
if (active->totr.xmax < region->v2d.cur.xmin || active->totr.xmin > region->v2d.cur.xmax ||
active->totr.ymax < region->v2d.cur.ymin || active->totr.ymin > region->v2d.cur.ymax) {
- space_node_view_flag(C, snode, region, NODE_SELECT, U.smooth_viewtx);
+ space_node_view_flag(*C, *snode, *region, NODE_SELECT, U.smooth_viewtx);
}
}
}
@@ -1323,3 +1309,5 @@ void NODE_OT_find_node(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc
index 648ede7abd5..113e2bd3bb3 100644
--- a/source/blender/editors/space_node/node_templates.cc
+++ b/source/blender/editors/space_node/node_templates.cc
@@ -20,6 +20,7 @@
#include <cstdlib>
#include <cstring>
+#include <optional>
#include "MEM_guardedalloc.h"
@@ -36,30 +37,37 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_node_tree_update.h"
#include "RNA_access.h"
+#include "NOD_node_declaration.hh"
#include "NOD_socket.h"
+#include "NOD_socket_declarations.hh"
#include "../interface/interface_intern.h" /* XXX bad level */
#include "UI_interface.h"
#include "ED_node.h" /* own include */
-#include "node_intern.h"
+#include "node_intern.hh"
#include "ED_undo.h"
+using blender::nodes::NodeDeclaration;
+
+namespace blender::ed::space_node {
+
/************************* Node Socket Manipulation **************************/
/* describes an instance of a node type and a specific socket to link */
struct NodeLinkItem {
- int socket_index; /* index for linking */
- int socket_type; /* socket type for compatibility check */
- const char *socket_name; /* ui label of the socket */
- const char *node_name; /* ui label of the node */
+ int socket_index = -1; /* index for linking */
+ int socket_type = SOCK_CUSTOM; /* socket type for compatibility check */
+ const char *socket_name = nullptr; /* ui label of the socket */
+ const char *node_name = nullptr; /* ui label of the node */
/* extra settings */
- bNodeTree *ngroup; /* group node tree */
+ bNodeTree *ngroup = nullptr; /* group node tree */
};
/* Compare an existing node to a link item to see if it can be reused.
@@ -78,7 +86,7 @@ static void node_link_item_apply(Main *bmain, bNode *node, NodeLinkItem *item)
{
if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
node->id = (ID *)item->ngroup;
- ntreeUpdateTree(bmain, item->ngroup);
+ BKE_ntree_update_main_tree(bmain, item->ngroup, nullptr);
}
else {
/* nothing to do for now */
@@ -173,10 +181,8 @@ static void node_socket_disconnect(Main *bmain,
nodeRemLink(ntree, sock_to->link);
sock_to->flag |= SOCK_COLLAPSED;
- nodeUpdate(ntree, node_to);
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, node_to);
+ BKE_ntree_update_tag_node_property(ntree, node_to);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/* remove all nodes connected to this socket, if they aren't connected to other nodes */
@@ -189,10 +195,8 @@ static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bN
node_remove_linked(bmain, ntree, sock_to->link->fromnode);
sock_to->flag |= SOCK_COLLAPSED;
- nodeUpdate(ntree, node_to);
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, node_to);
+ BKE_ntree_update_tag_node_property(ntree, node_to);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/* add new node connected to this socket, or replace an existing one */
@@ -293,11 +297,9 @@ static void node_socket_add_replace(const bContext *C,
node_remove_linked(bmain, ntree, node_prev);
}
- nodeUpdate(ntree, node_from);
- nodeUpdate(ntree, node_to);
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- ED_node_tag_update_nodetree(CTX_data_main(C), ntree, node_to);
+ BKE_ntree_update_tag_node_property(ntree, node_from);
+ BKE_ntree_update_tag_node_property(ntree, node_to);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/****************************** Node Link Menu *******************************/
@@ -319,15 +321,13 @@ struct NodeLinkArg {
uiLayout *layout;
};
-static void ui_node_link_items(NodeLinkArg *arg,
- int in_out,
- NodeLinkItem **r_items,
- int *r_totitems)
+static Vector<NodeLinkItem> ui_node_link_items(NodeLinkArg *arg,
+ int in_out,
+ std::optional<NodeDeclaration> &r_node_decl)
{
- /* XXX this should become a callback for node types! */
- NodeLinkItem *items = nullptr;
- int totitems = 0;
+ Vector<NodeLinkItem> items;
+ /* XXX this should become a callback for node types! */
if (arg->node_type->type == NODE_GROUP) {
bNodeTree *ngroup;
int i;
@@ -339,69 +339,111 @@ static void ui_node_link_items(NodeLinkArg *arg,
!nodeGroupPoll(arg->ntree, ngroup, &disabled_hint)) {
continue;
}
-
- ListBase *lb = ((in_out == SOCK_IN) ? &ngroup->inputs : &ngroup->outputs);
- totitems += BLI_listbase_count(lb);
}
- if (totitems > 0) {
- items = (NodeLinkItem *)MEM_callocN(sizeof(NodeLinkItem) * totitems, "ui node link items");
-
- i = 0;
- for (ngroup = (bNodeTree *)arg->bmain->nodetrees.first; ngroup;
- ngroup = (bNodeTree *)ngroup->id.next) {
- const char *disabled_hint;
- if ((ngroup->type != arg->ntree->type) ||
- !nodeGroupPoll(arg->ntree, ngroup, &disabled_hint)) {
- continue;
- }
+ i = 0;
+ for (ngroup = (bNodeTree *)arg->bmain->nodetrees.first; ngroup;
+ ngroup = (bNodeTree *)ngroup->id.next) {
+ const char *disabled_hint;
+ if ((ngroup->type != arg->ntree->type) ||
+ !nodeGroupPoll(arg->ntree, ngroup, &disabled_hint)) {
+ continue;
+ }
- ListBase *lb = (in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs);
- bNodeSocket *stemp;
- int index;
- for (stemp = (bNodeSocket *)lb->first, index = 0; stemp;
- stemp = stemp->next, index++, i++) {
- NodeLinkItem *item = &items[i];
-
- item->socket_index = index;
- /* NOTE: int stemp->type is not fully reliable, not used for node group
- * interface sockets. use the typeinfo->type instead.
- */
- item->socket_type = stemp->typeinfo->type;
- item->socket_name = stemp->name;
- item->node_name = ngroup->id.name + 2;
- item->ngroup = ngroup;
- }
+ ListBase *lb = (in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs);
+ bNodeSocket *stemp;
+ int index;
+ for (stemp = (bNodeSocket *)lb->first, index = 0; stemp; stemp = stemp->next, index++, i++) {
+ NodeLinkItem item;
+ item.socket_index = index;
+ /* NOTE: int stemp->type is not fully reliable, not used for node group
+ * interface sockets. use the typeinfo->type instead.
+ */
+ item.socket_type = stemp->typeinfo->type;
+ item.socket_name = stemp->name;
+ item.node_name = ngroup->id.name + 2;
+ item.ngroup = ngroup;
+
+ items.append(item);
}
}
}
+ else if (arg->node_type->declare != nullptr) {
+ using namespace blender;
+ using namespace blender::nodes;
+
+ r_node_decl.emplace(NodeDeclaration());
+ NodeDeclarationBuilder node_decl_builder{*r_node_decl};
+ arg->node_type->declare(node_decl_builder);
+ Span<SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? r_node_decl->inputs() :
+ r_node_decl->outputs();
+ int index = 0;
+ for (const SocketDeclarationPtr &socket_decl_ptr : socket_decls) {
+ const SocketDeclaration &socket_decl = *socket_decl_ptr;
+ NodeLinkItem item;
+ item.socket_index = index++;
+ if (dynamic_cast<const decl::Float *>(&socket_decl)) {
+ item.socket_type = SOCK_FLOAT;
+ }
+ else if (dynamic_cast<const decl::Int *>(&socket_decl)) {
+ item.socket_type = SOCK_INT;
+ }
+ else if (dynamic_cast<const decl::Bool *>(&socket_decl)) {
+ item.socket_type = SOCK_BOOLEAN;
+ }
+ else if (dynamic_cast<const decl::Vector *>(&socket_decl)) {
+ item.socket_type = SOCK_VECTOR;
+ }
+ else if (dynamic_cast<const decl::Color *>(&socket_decl)) {
+ item.socket_type = SOCK_RGBA;
+ }
+ else if (dynamic_cast<const decl::String *>(&socket_decl)) {
+ item.socket_type = SOCK_STRING;
+ }
+ else if (dynamic_cast<const decl::Image *>(&socket_decl)) {
+ item.socket_type = SOCK_IMAGE;
+ }
+ else if (dynamic_cast<const decl::Texture *>(&socket_decl)) {
+ item.socket_type = SOCK_TEXTURE;
+ }
+ else if (dynamic_cast<const decl::Material *>(&socket_decl)) {
+ item.socket_type = SOCK_MATERIAL;
+ }
+ else if (dynamic_cast<const decl::Shader *>(&socket_decl)) {
+ item.socket_type = SOCK_SHADER;
+ }
+ else if (dynamic_cast<const decl::Collection *>(&socket_decl)) {
+ item.socket_type = SOCK_COLLECTION;
+ }
+ else if (dynamic_cast<const decl::Object *>(&socket_decl)) {
+ item.socket_type = SOCK_OBJECT;
+ }
+ else {
+ item.socket_type = SOCK_CUSTOM;
+ }
+ item.socket_name = socket_decl.name().c_str();
+ item.node_name = arg->node_type->ui_name;
+ items.append(item);
+ }
+ }
else {
bNodeSocketTemplate *socket_templates = (in_out == SOCK_IN ? arg->node_type->inputs :
arg->node_type->outputs);
bNodeSocketTemplate *stemp;
int i;
- for (stemp = socket_templates; stemp && stemp->type != -1; stemp++) {
- totitems++;
- }
-
- if (totitems > 0) {
- items = (NodeLinkItem *)MEM_callocN(sizeof(NodeLinkItem) * totitems, "ui node link items");
-
- i = 0;
- for (stemp = socket_templates; stemp && stemp->type != -1; stemp++, i++) {
- NodeLinkItem *item = &items[i];
-
- item->socket_index = i;
- item->socket_type = stemp->type;
- item->socket_name = stemp->name;
- item->node_name = arg->node_type->ui_name;
- }
+ i = 0;
+ for (stemp = socket_templates; stemp && stemp->type != -1; stemp++, i++) {
+ NodeLinkItem item;
+ item.socket_index = i;
+ item.socket_type = stemp->type;
+ item.socket_name = stemp->name;
+ item.node_name = arg->node_type->ui_name;
+ items.append(item);
}
}
- *r_items = items;
- *r_totitems = totitems;
+ return items;
}
static void ui_node_link(bContext *C, void *arg_p, void *event_p)
@@ -426,7 +468,9 @@ static void ui_node_link(bContext *C, void *arg_p, void *event_p)
ED_undo_push(C, "Node input modify");
}
-static void ui_node_sock_name(bNodeTree *ntree, bNodeSocket *sock, char name[UI_MAX_NAME_STR])
+static void ui_node_sock_name(const bNodeTree *ntree,
+ bNodeSocket *sock,
+ char name[UI_MAX_NAME_STR])
{
if (sock->link && sock->link->fromnode) {
bNode *node = sock->link->fromnode;
@@ -513,8 +557,6 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
/* generate UI */
for (int j = 0; j < sorted_ntypes.size(); j++) {
bNodeType *ntype = sorted_ntypes[j];
- NodeLinkItem *items;
- int totitems;
char name[UI_MAX_NAME_STR];
const char *cur_node_name = nullptr;
int num = 0;
@@ -522,16 +564,17 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
arg->node_type = ntype;
- ui_node_link_items(arg, SOCK_OUT, &items, &totitems);
+ std::optional<blender::nodes::NodeDeclaration> node_decl;
+ Vector<NodeLinkItem> items = ui_node_link_items(arg, SOCK_OUT, node_decl);
- for (int i = 0; i < totitems; i++) {
- if (ui_compatible_sockets(items[i].socket_type, sock->type)) {
+ for (const NodeLinkItem &item : items) {
+ if (ui_compatible_sockets(item.socket_type, sock->type)) {
num++;
}
}
- for (int i = 0; i < totitems; i++) {
- if (!ui_compatible_sockets(items[i].socket_type, sock->type)) {
+ for (const NodeLinkItem &item : items) {
+ if (!ui_compatible_sockets(item.socket_type, sock->type)) {
continue;
}
@@ -546,8 +589,8 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
}
if (num > 1) {
- if (!cur_node_name || !STREQ(cur_node_name, items[i].node_name)) {
- cur_node_name = items[i].node_name;
+ if (!cur_node_name || !STREQ(cur_node_name, item.node_name)) {
+ cur_node_name = item.node_name;
/* XXX Do not use uiItemL here,
* it would add an empty icon as we are in a menu! */
uiDefBut(block,
@@ -566,11 +609,11 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
"");
}
- BLI_snprintf(name, UI_MAX_NAME_STR, "%s", IFACE_(items[i].socket_name));
+ BLI_snprintf(name, UI_MAX_NAME_STR, "%s", IFACE_(item.socket_name));
icon = ICON_BLANK1;
}
else {
- BLI_strncpy(name, IFACE_(items[i].node_name), UI_MAX_NAME_STR);
+ BLI_strncpy(name, IFACE_(item.node_name), UI_MAX_NAME_STR);
icon = ICON_NONE;
}
@@ -591,13 +634,9 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
TIP_("Add node to input"));
argN = (NodeLinkArg *)MEM_dupallocN(arg);
- argN->item = items[i];
+ argN->item = item;
UI_but_funcN_set(but, ui_node_link, argN, nullptr);
}
-
- if (items) {
- MEM_freeN(items);
- }
}
}
@@ -678,22 +717,26 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_
ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group"));
}
+} // namespace blender::ed::space_node
+
void uiTemplateNodeLink(
uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
{
+ using namespace blender::ed::space_node;
+
uiBlock *block = uiLayoutGetBlock(layout);
NodeLinkArg *arg;
uiBut *but;
float socket_col[4];
- arg = (NodeLinkArg *)MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
+ arg = MEM_new<NodeLinkArg>("NodeLinkArg");
arg->ntree = ntree;
arg->node = node;
arg->sock = input;
PointerRNA node_ptr;
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
- node_socket_color_get(C, ntree, &node_ptr, input, socket_col);
+ node_socket_color_get(*C, *ntree, node_ptr, *input, socket_col);
UI_block_layout_set_current(block, layout);
@@ -722,6 +765,8 @@ void uiTemplateNodeLink(
}
}
+namespace blender::ed::space_node {
+
/**************************** Node Tree Layout *******************************/
static void ui_node_draw_input(
@@ -753,7 +798,6 @@ static void ui_node_draw_input(
PointerRNA inputptr, nodeptr;
uiBlock *block = uiLayoutGetBlock(layout);
uiLayout *row = nullptr;
- bNode *lnode;
bool dependency_loop;
if (input->flag & SOCK_UNAVAIL) {
@@ -762,7 +806,7 @@ static void ui_node_draw_input(
/* to avoid eternal loops on cyclic dependencies */
node->flag |= NODE_TEST;
- lnode = (input->link) ? input->link->fromnode : nullptr;
+ bNode *lnode = (input->link) ? input->link->fromnode : nullptr;
dependency_loop = (lnode && (lnode->flag & NODE_TEST));
if (dependency_loop) {
@@ -852,7 +896,7 @@ static void ui_node_draw_input(
if (node_tree->type == NTREE_GEOMETRY && snode != nullptr) {
/* Only add the attribute search in the node editor, in other places there is not
* enough context. */
- node_geometry_add_attribute_search_button(C, node_tree, node, &inputptr, row);
+ node_geometry_add_attribute_search_button(*C, *node_tree, *node, inputptr, *row);
}
else {
uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);
@@ -875,9 +919,13 @@ static void ui_node_draw_input(
node->flag &= ~NODE_TEST;
}
+} // namespace blender::ed::space_node
+
void uiTemplateNodeView(
uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
{
+ using namespace blender::ed::space_node;
+
bNode *tnode;
if (!ntree) {
diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc
index 762b4b36a39..9d99709a780 100644
--- a/source/blender/editors/space_node/node_view.cc
+++ b/source/blender/editors/space_node/node_view.cc
@@ -24,7 +24,6 @@
#include "DNA_node_types.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"
@@ -54,33 +53,29 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-#include "node_intern.h" /* own include */
+#include "node_intern.hh" /* own include */
-using blender::StringRef;
+namespace blender::ed::space_node {
/* -------------------------------------------------------------------- */
/** \name View All Operator
* \{ */
-int space_node_view_flag(
- bContext *C, SpaceNode *snode, ARegion *region, const int node_flag, const int smooth_viewtx)
+bool space_node_view_flag(
+ bContext &C, SpaceNode &snode, ARegion &region, const int node_flag, const int smooth_viewtx)
{
- bNode *node;
- rctf cur_new;
- float oldwidth, oldheight, width, height;
- float oldasp, asp;
- int tot = 0;
- bool has_frame = false;
+ const float oldwidth = BLI_rctf_size_x(&region.v2d.cur);
+ const float oldheight = BLI_rctf_size_y(&region.v2d.cur);
- oldwidth = BLI_rctf_size_x(&region->v2d.cur);
- oldheight = BLI_rctf_size_y(&region->v2d.cur);
-
- oldasp = oldwidth / oldheight;
+ const float old_aspect = oldwidth / oldheight;
+ rctf cur_new;
BLI_rctf_init_minmax(&cur_new);
- if (snode->edittree) {
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ int tot = 0;
+ bool has_frame = false;
+ if (snode.edittree) {
+ LISTBASE_FOREACH (const bNode *, node, &snode.edittree->nodes) {
if ((node->flag & node_flag) == node_flag) {
BLI_rctf_union(&cur_new, &node->totr);
tot++;
@@ -92,37 +87,39 @@ int space_node_view_flag(
}
}
- if (tot) {
- width = BLI_rctf_size_x(&cur_new);
- height = BLI_rctf_size_y(&cur_new);
- asp = width / height;
+ if (tot == 0) {
+ return false;
+ }
- /* for single non-frame nodes, don't zoom in, just pan view,
- * but do allow zooming out, this allows for big nodes to be zoomed out */
- if ((tot == 1) && (has_frame == false) && ((oldwidth * oldheight) > (width * height))) {
- /* center, don't zoom */
- BLI_rctf_resize(&cur_new, oldwidth, oldheight);
+ const float width = BLI_rctf_size_x(&cur_new);
+ const float height = BLI_rctf_size_y(&cur_new);
+ const float new_aspect = width / height;
+
+ /* for single non-frame nodes, don't zoom in, just pan view,
+ * but do allow zooming out, this allows for big nodes to be zoomed out */
+ if ((tot == 1) && (has_frame == false) && ((oldwidth * oldheight) > (width * height))) {
+ /* center, don't zoom */
+ BLI_rctf_resize(&cur_new, oldwidth, oldheight);
+ }
+ else {
+ if (old_aspect < new_aspect) {
+ const float height_new = width / old_aspect;
+ cur_new.ymin = cur_new.ymin - height_new / 2.0f;
+ cur_new.ymax = cur_new.ymax + height_new / 2.0f;
}
else {
- if (oldasp < asp) {
- const float height_new = width / oldasp;
- cur_new.ymin = cur_new.ymin - height_new / 2.0f;
- cur_new.ymax = cur_new.ymax + height_new / 2.0f;
- }
- else {
- const float width_new = height * oldasp;
- cur_new.xmin = cur_new.xmin - width_new / 2.0f;
- cur_new.xmax = cur_new.xmax + width_new / 2.0f;
- }
-
- /* add some padding */
- BLI_rctf_scale(&cur_new, 1.1f);
+ const float width_new = height * old_aspect;
+ cur_new.xmin = cur_new.xmin - width_new / 2.0f;
+ cur_new.xmax = cur_new.xmax + width_new / 2.0f;
}
- UI_view2d_smooth_view(C, region, &cur_new, smooth_viewtx);
+ /* add some padding */
+ BLI_rctf_scale(&cur_new, 1.1f);
}
- return (tot != 0);
+ UI_view2d_smooth_view(&C, &region, &cur_new, smooth_viewtx);
+
+ return true;
}
static int node_view_all_exec(bContext *C, wmOperator *op)
@@ -135,7 +132,7 @@ static int node_view_all_exec(bContext *C, wmOperator *op)
snode->xof = 0;
snode->yof = 0;
- if (space_node_view_flag(C, snode, region, 0, smooth_viewtx)) {
+ if (space_node_view_flag(*C, *snode, *region, 0, smooth_viewtx)) {
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
@@ -168,7 +165,7 @@ static int node_view_selected_exec(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- if (space_node_view_flag(C, snode, region, NODE_SELECT, smooth_viewtx)) {
+ if (space_node_view_flag(*C, *snode, *region, NODE_SELECT, smooth_viewtx)) {
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
@@ -258,7 +255,7 @@ static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *
return OPERATOR_CANCELLED;
}
- nvm = (NodeViewMove *)MEM_callocN(sizeof(NodeViewMove), "NodeViewMove struct");
+ nvm = MEM_cnew<NodeViewMove>("NodeViewMove struct");
op->customdata = nvm;
nvm->mvalo[0] = event->mval[0];
nvm->mvalo[1] = event->mval[1];
@@ -447,7 +444,8 @@ static void sample_draw(const bContext *C, ARegion *region, void *arg_info)
}
}
-/* Returns mouse position in image space. */
+} // namespace blender::ed::space_node
+
bool ED_space_node_get_position(
Main *bmain, SpaceNode *snode, struct ARegion *region, const int mval[2], float fpos[2])
{
@@ -475,9 +473,6 @@ bool ED_space_node_get_position(
return true;
}
-/* Returns color in linear space, matching ED_space_image_color_sample().
- * And here we've got recursion in the comments tips...
- */
bool ED_space_node_color_sample(
Main *bmain, SpaceNode *snode, ARegion *region, const int mval[2], float r_col[3])
{
@@ -533,6 +528,8 @@ bool ED_space_node_color_sample(
return ret;
}
+namespace blender::ed::space_node {
+
static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
@@ -650,7 +647,7 @@ static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- info = (ImageSampleInfo *)MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
+ info = MEM_cnew<ImageSampleInfo>("ImageSampleInfo");
info->art = region->type;
info->draw_handle = ED_region_draw_cb_activate(
region->type, sample_draw, info, REGION_DRAW_POST_PIXEL);
@@ -738,7 +735,7 @@ static int space_node_view_geometry_nodes_legacy(bContext *C, SpaceNode *snode,
}
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- if (space_node_view_flag(C, snode, region, NODE_SELECT, smooth_viewtx)) {
+ if (space_node_view_flag(*C, *snode, *region, NODE_SELECT, smooth_viewtx)) {
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
@@ -790,3 +787,5 @@ void NODE_OT_geometry_node_view_legacy(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.cc
index 956fb3aa867..00fd328b2ed 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.cc
@@ -29,11 +29,9 @@
#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_node.h"
#include "BKE_screen.h"
@@ -52,21 +50,21 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "node_intern.h" /* own include */
+#include "node_intern.hh" /* own include */
+
+using blender::float2;
/* ******************** tree path ********************* */
void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
{
- bNodeTreePath *path, *path_next;
- for (path = snode->treepath.first; path; path = path_next) {
- path_next = path->next;
+ LISTBASE_FOREACH_MUTABLE (bNodeTreePath *, path, &snode->treepath) {
MEM_freeN(path);
}
BLI_listbase_clear(&snode->treepath);
if (ntree) {
- path = MEM_callocN(sizeof(bNodeTreePath), "node tree path");
+ bNodeTreePath *path = MEM_cnew<bNodeTreePath>("node tree path");
path->nodetree = ntree;
path->parent_key = NODE_INSTANCE_KEY_BASE;
@@ -94,13 +92,13 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
ED_node_set_active_viewer_key(snode);
- WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_NODES, nullptr);
}
void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode)
{
- bNodeTreePath *path = MEM_callocN(sizeof(bNodeTreePath), "node tree path");
- bNodeTreePath *prev_path = snode->treepath.last;
+ bNodeTreePath *path = MEM_cnew<bNodeTreePath>("node tree path");
+ bNodeTreePath *prev_path = (bNodeTreePath *)snode->treepath.last;
path->nodetree = ntree;
if (gnode) {
if (prev_path) {
@@ -129,12 +127,12 @@ void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode)
ED_node_set_active_viewer_key(snode);
- WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_NODES, nullptr);
}
void ED_node_tree_pop(SpaceNode *snode)
{
- bNodeTreePath *path = snode->treepath.last;
+ bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
/* don't remove root */
if (path == snode->treepath.first) {
@@ -145,13 +143,13 @@ void ED_node_tree_pop(SpaceNode *snode)
MEM_freeN(path);
/* update current tree */
- path = snode->treepath.last;
+ path = (bNodeTreePath *)snode->treepath.last;
snode->edittree = path->nodetree;
ED_node_set_active_viewer_key(snode);
/* listener updates the View2D center from edittree */
- WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_NODES, nullptr);
}
int ED_node_tree_depth(SpaceNode *snode)
@@ -163,12 +161,12 @@ bNodeTree *ED_node_tree_get(SpaceNode *snode, int level)
{
bNodeTreePath *path;
int i;
- for (path = snode->treepath.last, i = 0; path; path = path->prev, i++) {
+ for (path = (bNodeTreePath *)snode->treepath.last, i = 0; path; path = path->prev, i++) {
if (i == level) {
return path->nodetree;
}
}
- return NULL;
+ return nullptr;
}
int ED_node_tree_path_length(SpaceNode *snode)
@@ -201,61 +199,46 @@ void ED_node_tree_path_get(SpaceNode *snode, char *value)
}
}
-void ED_node_tree_path_get_fixedbuf(SpaceNode *snode, char *value, int max_length)
-{
- int size;
-
- value[0] = '\0';
- int i = 0;
- LISTBASE_FOREACH_INDEX (bNodeTreePath *, path, &snode->treepath, i) {
- if (i == 0) {
- size = BLI_strncpy_rlen(value, path->display_name, max_length);
- }
- else {
- size = BLI_snprintf_rlen(value, max_length, "/%s", path->display_name);
- }
- max_length -= size;
- if (max_length <= 0) {
- break;
- }
- value += size;
- }
-}
-
void ED_node_set_active_viewer_key(SpaceNode *snode)
{
- bNodeTreePath *path = snode->treepath.last;
+ bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
if (snode->nodetree && path) {
snode->nodetree->active_viewer_key = path->parent_key;
}
}
-void space_node_group_offset(SpaceNode *snode, float *x, float *y)
+void ED_node_cursor_location_get(const SpaceNode *snode, float value[2])
+{
+ copy_v2_v2(value, snode->runtime->cursor);
+}
+
+void ED_node_cursor_location_set(SpaceNode *snode, const float value[2])
+{
+ copy_v2_v2(snode->runtime->cursor, value);
+}
+
+namespace blender::ed::space_node {
+
+float2 space_node_group_offset(const SpaceNode &snode)
{
- bNodeTreePath *path = snode->treepath.last;
+ const bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
if (path && path->prev) {
- float dcenter[2];
- sub_v2_v2v2(dcenter, path->view_center, path->prev->view_center);
- *x = dcenter[0];
- *y = dcenter[1];
- }
- else {
- *x = *y = 0.0f;
+ return float2(path->view_center) - float2(path->prev->view_center);
}
+ return float2(0);
}
/* ******************** default callbacks for node space ***************** */
static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
- ARegion *region;
- SpaceNode *snode;
-
- snode = MEM_callocN(sizeof(SpaceNode), "initnode");
+ SpaceNode *snode = MEM_cnew<SpaceNode>("initnode");
snode->spacetype = SPACE_NODE;
snode->flag = SNODE_SHOW_GPENCIL | SNODE_USE_ALPHA;
+ snode->overlay.flag = (SN_OVERLAY_SHOW_OVERLAYS | SN_OVERLAY_SHOW_WIRE_COLORS |
+ SN_OVERLAY_SHOW_PATH);
/* backdrop */
snode->zoom = 1.0f;
@@ -268,21 +251,21 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s
NODE_TREE_TYPES_END;
/* header */
- region = MEM_callocN(sizeof(ARegion), "header for node");
+ ARegion *region = MEM_cnew<ARegion>("header for node");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_HEADER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
/* buttons/list view */
- region = MEM_callocN(sizeof(ARegion), "buttons for node");
+ region = MEM_cnew<ARegion>("buttons for node");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_UI;
region->alignment = RGN_ALIGN_RIGHT;
/* toolbar */
- region = MEM_callocN(sizeof(ARegion), "node tools");
+ region = MEM_cnew<ARegion>("node tools");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_TOOLS;
@@ -291,7 +274,7 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s
region->flag = RGN_FLAG_HIDDEN;
/* main region */
- region = MEM_callocN(sizeof(ARegion), "main region for node");
+ region = MEM_cnew<ARegion>("main region for node");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
@@ -309,7 +292,7 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s
region->v2d.max[0] = 32000.0f;
region->v2d.max[1] = 32000.0f;
- region->v2d.minzoom = 0.09f;
+ region->v2d.minzoom = 0.05f;
region->v2d.maxzoom = 2.31f;
region->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
@@ -327,7 +310,10 @@ static void node_free(SpaceLink *sl)
MEM_freeN(path);
}
- MEM_SAFE_FREE(snode->runtime);
+ if (snode->runtime) {
+ snode->runtime->linkdrag.reset();
+ MEM_freeN(snode->runtime);
+ }
}
/* spacetype; init callback */
@@ -335,9 +321,22 @@ static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *area)
{
SpaceNode *snode = (SpaceNode *)area->spacedata.first;
- if (snode->runtime == NULL) {
- snode->runtime = MEM_callocN(sizeof(SpaceNode_Runtime), __func__);
+ if (snode->runtime == nullptr) {
+ snode->runtime = MEM_new<SpaceNode_Runtime>(__func__);
+ }
+}
+
+static bool any_node_uses_id(const bNodeTree *ntree, const ID *id)
+{
+ if (ELEM(nullptr, ntree, id)) {
+ return false;
+ }
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->id == id) {
+ return true;
+ }
}
+ return false;
}
static void node_area_listener(const wmSpaceTypeListenerParams *params)
@@ -346,7 +345,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
wmNotifier *wmn = params->notifier;
/* NOTE: #ED_area_tag_refresh will re-execute compositor. */
- SpaceNode *snode = area->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)area->spacedata.first;
/* shaderfrom is only used for new shading nodes, otherwise all shaders are from objects */
short shader_type = snode->shaderfrom;
@@ -356,7 +355,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
switch (wmn->data) {
case ND_NODES: {
ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
- bNodeTreePath *path = snode->treepath.last;
+ bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
/* shift view to node tree center */
if (region && path) {
UI_view2d_center_set(&region->v2d, path->view_center[0], path->view_center[1]);
@@ -397,9 +396,6 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
else if (wmn->data == ND_SHADING_LINKS) {
ED_area_tag_refresh(area);
}
- else if (wmn->action == NA_ADDED && snode->edittree) {
- nodeSetActiveID(snode->edittree, ID_MA, wmn->reference);
- }
}
break;
case NC_TEXTURE:
@@ -423,7 +419,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
else if (ED_node_is_geometry(snode)) {
/* Rather strict check: only redraw when the reference matches the current editor's ID. */
if (wmn->data == ND_MODIFIER) {
- if (wmn->reference == snode->id || snode->id == NULL) {
+ if (wmn->reference == snode->id || snode->id == nullptr) {
ED_area_tag_refresh(area);
}
}
@@ -463,10 +459,9 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
case NC_IMAGE:
if (wmn->action == NA_EDITED) {
if (ED_node_is_compositor(snode)) {
- /* note that nodeUpdateID is already called by BKE_image_signal() on all
- * scenes so really this is just to know if the images is used in the compo else
- * painting on images could become very slow when the compositor is open. */
- if (nodeUpdateID(snode->nodetree, wmn->reference)) {
+ /* Without this check drawing on an image could become very slow when the compositor is
+ * open. */
+ if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) {
ED_area_tag_refresh(area);
}
}
@@ -476,7 +471,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
case NC_MOVIECLIP:
if (wmn->action == NA_EDITED) {
if (ED_node_is_compositor(snode)) {
- if (nodeUpdateID(snode->nodetree, wmn->reference)) {
+ if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) {
ED_area_tag_refresh(area);
}
}
@@ -504,64 +499,35 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
static void node_area_refresh(const struct bContext *C, ScrArea *area)
{
/* default now: refresh node is starting preview */
- SpaceNode *snode = area->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)area->spacedata.first;
- snode_set_context(C);
+ snode_set_context(*C);
if (snode->nodetree) {
- if (snode->nodetree->type == NTREE_SHADER) {
- if (GS(snode->id->name) == ID_MA) {
- Material *ma = (Material *)snode->id;
- if (ma->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
- }
- }
- else if (GS(snode->id->name) == ID_LA) {
- Light *la = (Light *)snode->id;
- if (la->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
- }
- }
- else if (GS(snode->id->name) == ID_WO) {
- World *wo = (World *)snode->id;
- if (wo->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
- }
- }
- }
- else if (snode->nodetree->type == NTREE_COMPOSIT) {
+ if (snode->nodetree->type == NTREE_COMPOSIT) {
Scene *scene = (Scene *)snode->id;
if (scene->use_nodes) {
/* recalc is set on 3d view changes for auto compo */
if (snode->runtime->recalc) {
snode->runtime->recalc = false;
- node_render_changed_exec((struct bContext *)C, NULL);
+ node_render_changed_exec((struct bContext *)C, nullptr);
}
else {
ED_node_composite_job(C, snode->nodetree, scene);
}
}
}
- else if (snode->nodetree->type == NTREE_TEXTURE) {
- Tex *tex = (Tex *)snode->id;
- if (tex->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
- }
- }
}
}
static SpaceLink *node_duplicate(SpaceLink *sl)
{
SpaceNode *snode = (SpaceNode *)sl;
- SpaceNode *snoden = MEM_dupallocN(snode);
+ SpaceNode *snoden = (SpaceNode *)MEM_dupallocN(snode);
BLI_duplicatelist(&snoden->treepath, &snode->treepath);
- if (snode->runtime != NULL) {
- snoden->runtime = MEM_dupallocN(snode->runtime);
- BLI_listbase_clear(&snoden->runtime->linkdrag);
- }
+ snoden->runtime = nullptr;
/* NOTE: no need to set node tree user counts,
* the editor only keeps at least 1 (id_us_ensure_real),
@@ -603,29 +569,19 @@ static void node_toolbar_region_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
-void ED_node_cursor_location_get(const SpaceNode *snode, float value[2])
-{
- copy_v2_v2(value, snode->runtime->cursor);
-}
-
-void ED_node_cursor_location_set(SpaceNode *snode, const float value[2])
-{
- copy_v2_v2(snode->runtime->cursor, value);
-}
-
static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region)
{
- SpaceNode *snode = area->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)area->spacedata.first;
/* convert mouse coordinates to v2d space */
UI_view2d_region_to_view(&region->v2d,
- win->eventstate->x - region->winrct.xmin,
- win->eventstate->y - region->winrct.ymin,
+ win->eventstate->xy[0] - region->winrct.xmin,
+ win->eventstate->xy[1] - region->winrct.ymin,
&snode->runtime->cursor[0],
&snode->runtime->cursor[1]);
/* here snode->runtime->cursor is used to detect the node edge for sizing */
- node_set_cursor(win, snode, snode->runtime->cursor);
+ node_set_cursor(*win, *snode, snode->runtime->cursor);
/* XXX snode->runtime->cursor is in placing new nodes space */
snode->runtime->cursor[0] /= UI_DPI_FAC;
@@ -659,7 +615,7 @@ static void node_main_region_init(wmWindowManager *wm, ARegion *region)
static void node_main_region_draw(const bContext *C, ARegion *region)
{
- node_draw_space(C, region);
+ node_draw_space(*C, *region);
}
/* ************* dropboxes ************* */
@@ -711,7 +667,7 @@ static void node_id_drop_copy(wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
- RNA_string_set(drop->ptr, "name", id->name + 2);
+ RNA_int_set(drop->ptr, "session_uuid", (int)id->session_uuid);
}
static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
@@ -729,7 +685,7 @@ static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
}
/* this region dropbox definition */
-static void node_dropboxes(void)
+static void node_dropboxes()
{
ListBase *lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW);
@@ -738,37 +694,37 @@ static void node_dropboxes(void)
node_object_drop_poll,
node_id_drop_copy,
WM_drag_free_imported_drag_ID,
- NULL);
+ nullptr);
WM_dropbox_add(lb,
"NODE_OT_add_collection",
node_collection_drop_poll,
node_id_drop_copy,
WM_drag_free_imported_drag_ID,
- NULL);
+ nullptr);
WM_dropbox_add(lb,
"NODE_OT_add_texture",
node_texture_drop_poll,
node_id_drop_copy,
WM_drag_free_imported_drag_ID,
- NULL);
+ nullptr);
WM_dropbox_add(lb,
"NODE_OT_add_group",
node_group_drop_poll,
node_group_drop_copy,
WM_drag_free_imported_drag_ID,
- NULL);
+ nullptr);
WM_dropbox_add(lb,
"NODE_OT_add_file",
node_ima_drop_poll,
node_id_path_drop_copy,
WM_drag_free_imported_drag_ID,
- NULL);
+ nullptr);
WM_dropbox_add(lb,
"NODE_OT_add_mask",
node_mask_drop_poll,
node_id_drop_copy,
WM_drag_free_imported_drag_ID,
- NULL);
+ nullptr);
}
/* ************* end drop *********** */
@@ -782,7 +738,7 @@ static void node_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region
static void node_header_region_draw(const bContext *C, ARegion *region)
{
/* find and set the context */
- snode_set_context(C);
+ snode_set_context(*C);
ED_region_header(C, region);
}
@@ -861,8 +817,14 @@ static void node_region_listener(const wmRegionListenerParams *params)
}
}
+} // namespace blender::ed::space_node
+
+/* Outside of blender namespace to avoid Python documentation build error with `ctypes`. */
const char *node_context_dir[] = {
- "selected_nodes", "active_node", "light", "material", "world", NULL};
+ "selected_nodes", "active_node", "light", "material", "world", nullptr};
+
+namespace blender::ed::space_node {
+
static int /*eContextResult*/ node_context(const bContext *C,
const char *member,
bContextDataResult *result)
@@ -874,10 +836,8 @@ static int /*eContextResult*/ node_context(const bContext *C,
return CTX_RESULT_OK;
}
if (CTX_data_equals(member, "selected_nodes")) {
- bNode *node;
-
if (snode->edittree) {
- for (node = snode->edittree->nodes.last; node; node = node->prev) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode->edittree->nodes) {
if (node->flag & NODE_SELECT) {
CTX_data_list_add(result, &snode->edittree->id, &RNA_Node, node);
}
@@ -926,20 +886,20 @@ static int /*eContextResult*/ node_context(const bContext *C,
return CTX_RESULT_MEMBER_NOT_FOUND;
}
-static void node_widgets(void)
+static void node_widgets()
{
- /* create the widgetmap for the area here */
- wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(
- &(const struct wmGizmoMapType_Params){SPACE_NODE, RGN_TYPE_WINDOW});
+ /* Create the widget-map for the area here. */
+ wmGizmoMapType_Params params{SPACE_NODE, RGN_TYPE_WINDOW};
+ wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&params);
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_transform);
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_crop);
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_sun_beams);
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_corner_pin);
}
-static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void node_id_remap_cb(ID *old_id, ID *new_id, void *user_data)
{
- SpaceNode *snode = (SpaceNode *)slink;
+ SpaceNode *snode = static_cast<SpaceNode *>(user_data);
if (snode->id == old_id) {
/* nasty DNA logic for SpaceNode:
@@ -947,15 +907,15 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I
*/
BLI_freelistN(&snode->treepath);
- /* XXX Untested in case new_id != NULL... */
+ /* XXX Untested in case new_id != nullptr... */
snode->id = new_id;
- snode->from = NULL;
- snode->nodetree = NULL;
- snode->edittree = NULL;
+ snode->from = nullptr;
+ snode->nodetree = nullptr;
+ snode->edittree = nullptr;
}
else if (GS(old_id->name) == ID_OB) {
if (snode->from == old_id) {
- if (new_id == NULL) {
+ if (new_id == nullptr) {
snode->flag &= ~SNODE_PIN;
}
snode->from = new_id;
@@ -971,7 +931,7 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I
else if (GS(old_id->name) == ID_NT) {
bNodeTreePath *path, *path_next;
- for (path = snode->treepath.first; path; path = path->next) {
+ for (path = (bNodeTreePath *)snode->treepath.first; path; path = path->next) {
if ((ID *)path->nodetree == old_id) {
path->nodetree = (bNodeTree *)new_id;
id_us_ensure_real(new_id);
@@ -980,7 +940,7 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I
/* first nodetree in path is same as snode->nodetree */
snode->nodetree = path->nodetree;
}
- if (path->nodetree == NULL) {
+ if (path->nodetree == nullptr) {
break;
}
}
@@ -996,24 +956,42 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I
/* edittree is just the last in the path,
* set this directly since the path may have been shortened above */
if (snode->treepath.last) {
- path = snode->treepath.last;
+ path = (bNodeTreePath *)snode->treepath.last;
snode->edittree = path->nodetree;
}
else {
- snode->edittree = NULL;
+ snode->edittree = nullptr;
}
}
}
+static void node_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
+{
+ /* Although we should be able to perform all the mappings in a single go this lead to issues when
+ * running the python test cases. Somehow the nodetree/edittree weren't updated to the new
+ * pointers that generated a SEGFAULT.
+ *
+ * To move forward we should perhaps remove snode->edittree and snode->nodetree as they are just
+ * copies of pointers. All usages should be calling a function that will receive the appropriate
+ * instance.
+ *
+ * We could also move a remap address at a time to ise the IDRemapper as that should get closer
+ * to cleaner code. See {D13615} for more information about this topic.
+ */
+ BKE_id_remapper_iter(mappings, node_id_remap_cb, slink);
+}
+
static int node_space_subtype_get(ScrArea *area)
{
- SpaceNode *snode = area->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)area->spacedata.first;
return rna_node_tree_idname_to_enum(snode->tree_idname);
}
static void node_space_subtype_set(ScrArea *area, int value)
{
- SpaceNode *snode = area->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)area->spacedata.first;
ED_node_set_tree_type(snode, rna_node_tree_type_from_enum(value));
}
@@ -1027,10 +1005,13 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item,
}
}
-/* only called once, from space/spacetypes.c */
-void ED_spacetype_node(void)
+} // namespace blender::ed::space_node
+
+void ED_spacetype_node()
{
- SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype node");
+ using namespace blender::ed::space_node;
+
+ SpaceType *st = MEM_cnew<SpaceType>("spacetype node");
ARegionType *art;
st->spaceid = SPACE_NODE;
@@ -1053,7 +1034,7 @@ void ED_spacetype_node(void)
st->space_subtype_set = node_space_subtype_set;
/* regions: main window */
- art = MEM_callocN(sizeof(ARegionType), "spacetype node region");
+ art = MEM_cnew<ARegionType>("spacetype node region");
art->regionid = RGN_TYPE_WINDOW;
art->init = node_main_region_init;
art->draw = node_main_region_draw;
@@ -1067,7 +1048,7 @@ void ED_spacetype_node(void)
BLI_addhead(&st->regiontypes, art);
/* regions: header */
- art = MEM_callocN(sizeof(ARegionType), "spacetype node region");
+ art = MEM_cnew<ARegionType>("spacetype node region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
@@ -1078,7 +1059,7 @@ void ED_spacetype_node(void)
BLI_addhead(&st->regiontypes, art);
/* regions: listview/buttons */
- art = MEM_callocN(sizeof(ARegionType), "spacetype node region");
+ art = MEM_cnew<ARegionType>("spacetype node region");
art->regionid = RGN_TYPE_UI;
art->prefsizex = UI_SIDEBAR_PANEL_WIDTH;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
@@ -1089,7 +1070,7 @@ void ED_spacetype_node(void)
BLI_addhead(&st->regiontypes, art);
/* regions: toolbar */
- art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region");
+ art = MEM_cnew<ARegionType>("spacetype view3d tools region");
art->regionid = RGN_TYPE_TOOLS;
art->prefsizex = 58; /* XXX */
art->prefsizey = 50; /* XXX */
@@ -1101,7 +1082,5 @@ void ED_spacetype_node(void)
art->draw = node_toolbar_region_draw;
BLI_addhead(&st->regiontypes, art);
- node_toolbar_register(art);
-
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index c31239f0e9c..60b881fb32b 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -34,18 +34,18 @@ set(INC
set(SRC
- outliner_collections.c
- outliner_context.c
- outliner_dragdrop.c
- outliner_draw.c
- outliner_edit.c
- outliner_ops.c
- outliner_select.c
- outliner_sync.c
- outliner_tools.c
- outliner_tree.c
- outliner_utils.c
- space_outliner.c
+ outliner_collections.cc
+ outliner_context.cc
+ outliner_dragdrop.cc
+ outliner_draw.cc
+ outliner_edit.cc
+ outliner_ops.cc
+ outliner_select.cc
+ outliner_sync.cc
+ outliner_tools.cc
+ outliner_tree.cc
+ outliner_utils.cc
+ space_outliner.cc
tree/common.cc
tree/tree_display.cc
tree/tree_display_data.cc
@@ -65,13 +65,13 @@ set(SRC
tree/tree_element_id_scene.cc
tree/tree_element_nla.cc
tree/tree_element_overrides.cc
+ tree/tree_element_rna.cc
tree/tree_element_scene_objects.cc
tree/tree_element_view_layer.cc
- outliner_intern.h
- tree/tree_display.h
+ outliner_intern.hh
+ tree/common.hh
tree/tree_display.hh
- tree/tree_element.h
tree/tree_element.hh
tree/tree_element_anim_data.hh
tree/tree_element_collection.hh
@@ -82,6 +82,7 @@ set(SRC
tree/tree_element_id_scene.hh
tree/tree_element_nla.hh
tree/tree_element_overrides.hh
+ tree/tree_element_rna.hh
tree/tree_element_scene_objects.hh
tree/tree_element_view_layer.hh
)
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.cc
index ff0bd533671..8d60a6088d3 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.cc
@@ -18,7 +18,7 @@
* \ingroup spoutliner
*/
-#include <string.h>
+#include <cstring>
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -49,7 +49,7 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-#include "outliner_intern.h" /* own include */
+#include "outliner_intern.hh" /* own include */
/* -------------------------------------------------------------------- */
/** \name Utility API
@@ -81,11 +81,11 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te)
TreeStoreElem *tselem = TREESTORE(te);
if (!tselem) {
- return NULL;
+ return nullptr;
}
if (tselem->type == TSE_LAYER_COLLECTION) {
- LayerCollection *lc = te->directdata;
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata);
return lc->collection;
}
if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
@@ -96,12 +96,12 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te)
return (Collection *)tselem->id;
}
- return NULL;
+ return nullptr;
}
TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *customdata)
{
- struct IDsSelectedData *data = customdata;
+ struct IDsSelectedData *data = reinterpret_cast<IDsSelectedData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
if (outliner_is_collection_tree_element(te)) {
@@ -118,14 +118,15 @@ TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *cu
TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata)
{
- struct IDsSelectedData *data = customdata;
+ struct IDsSelectedData *data = reinterpret_cast<IDsSelectedData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
if (outliner_is_collection_tree_element(te)) {
return TRAVERSE_CONTINUE;
}
- if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
+ if ((tselem->type != TSE_SOME_ID) || (tselem->id == nullptr) ||
+ (GS(tselem->id->name) != ID_OB)) {
return TRAVERSE_SKIP_CHILDS;
}
@@ -134,15 +135,10 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom
return TRAVERSE_CONTINUE;
}
-/**
- * Populates the \param objects: ListBase with all the outliner selected objects
- * We store it as (Object *)LinkData->data
- * \param objects: expected to be empty
- */
void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct IDsSelectedData data = {{NULL}};
+ struct IDsSelectedData data = {{nullptr}};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
0,
@@ -166,14 +162,14 @@ void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
bool ED_outliner_collections_editor_poll(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- return (space_outliner != NULL) &&
+ return (space_outliner != nullptr) &&
ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_LIBRARIES);
}
static bool outliner_view_layer_collections_editor_poll(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- return (space_outliner != NULL) && (space_outliner->outlinevis == SO_VIEW_LAYER);
+ return (space_outliner != nullptr) && (space_outliner->outlinevis == SO_VIEW_LAYER);
}
static bool collection_edit_in_active_scene_poll(bContext *C)
@@ -201,14 +197,14 @@ struct CollectionNewData {
static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata)
{
- struct CollectionNewData *data = customdata;
+ struct CollectionNewData *data = reinterpret_cast<CollectionNewData *>(customdata);
Collection *collection = outliner_collection_from_tree_element(te);
if (!collection) {
return TRAVERSE_SKIP_CHILDS;
}
- if (data->collection != NULL) {
+ if (data->collection != nullptr) {
data->error = true;
return TRAVERSE_BREAK;
}
@@ -225,10 +221,7 @@ static int collection_new_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- struct CollectionNewData data = {
- .error = false,
- .collection = NULL,
- };
+ CollectionNewData data{};
if (RNA_boolean_get(op->ptr, "nested")) {
outliner_build_tree(bmain, scene, view_layer, space_outliner, region);
@@ -246,7 +239,7 @@ static int collection_new_exec(bContext *C, wmOperator *op)
}
}
- if (data.collection == NULL || ID_IS_LINKED(data.collection) ||
+ if (data.collection == nullptr || ID_IS_LINKED(data.collection) ||
ID_IS_OVERRIDE_LIBRARY(data.collection)) {
data.collection = scene->master_collection;
}
@@ -256,13 +249,13 @@ static int collection_new_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_collection_add(bmain, data.collection, NULL);
+ BKE_collection_add(bmain, data.collection, nullptr);
DEG_id_tag_update(&data.collection->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
outliner_cleanup_tree(space_outliner);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
return OPERATOR_FINISHED;
}
@@ -300,7 +293,7 @@ struct CollectionEditData {
static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *customdata)
{
- struct CollectionEditData *data = customdata;
+ CollectionEditData *data = reinterpret_cast<CollectionEditData *>(customdata);
Collection *collection = outliner_collection_from_tree_element(te);
if (!collection) {
@@ -326,10 +319,9 @@ void outliner_collection_delete(
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
@@ -341,7 +333,8 @@ void outliner_collection_delete(
/* Effectively delete the collections. */
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
/* Test in case collection got deleted as part of another one. */
if (BLI_findindex(&bmain->collections, collection) != -1) {
@@ -363,7 +356,7 @@ void outliner_collection_delete(
BLI_assert(parent->id.flag & LIB_EMBEDDED_DATA);
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(&parent->id);
- BLI_assert(id_type->owner_get != NULL);
+ BLI_assert(id_type->owner_get != nullptr);
ID *scene_owner = id_type->owner_get(bmain, &parent->id);
BLI_assert(GS(scene_owner->name) == ID_SCE);
@@ -389,9 +382,11 @@ void outliner_collection_delete(
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
}
+/* FIXME: See comment above #WM_msg_publish_rna_prop(). */
+extern "C" {
static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -405,7 +400,7 @@ static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
if (basact_prev != BASACT(view_layer)) {
WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
@@ -415,6 +410,7 @@ static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+}
void OUTLINER_OT_collection_hierarchy_delete(wmOperatorType *ot)
{
@@ -445,12 +441,12 @@ struct CollectionObjectsSelectData {
static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te,
void *customdata)
{
- struct CollectionObjectsSelectData *data = customdata;
+ CollectionObjectsSelectData *data = reinterpret_cast<CollectionObjectsSelectData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
switch (tselem->type) {
case TSE_LAYER_COLLECTION:
- data->layer_collection = te->directdata;
+ data->layer_collection = reinterpret_cast<LayerCollection *>(te->directdata);
return TRAVERSE_BREAK;
case TSE_R_LAYER:
case TSE_SCENE_COLLECTION_BASE:
@@ -465,9 +461,7 @@ static LayerCollection *outliner_active_layer_collection(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionObjectsSelectData data = {
- .layer_collection = NULL,
- };
+ CollectionObjectsSelectData data{};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
@@ -484,7 +478,7 @@ static int collection_objects_select_exec(bContext *C, wmOperator *op)
LayerCollection *layer_collection = outliner_active_layer_collection(C);
bool deselect = STREQ(op->idname, "OUTLINER_OT_collection_objects_deselect");
- if (layer_collection == NULL) {
+ if (layer_collection == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -541,7 +535,7 @@ struct CollectionDuplicateData {
static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te,
void *customdata)
{
- struct CollectionDuplicateData *data = customdata;
+ CollectionDuplicateData *data = reinterpret_cast<CollectionDuplicateData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
switch (tselem->type) {
@@ -560,9 +554,7 @@ static TreeElement *outliner_active_collection(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionDuplicateData data = {
- .te = NULL,
- };
+ CollectionDuplicateData data = {};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
@@ -577,38 +569,38 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
TreeElement *te = outliner_active_collection(C);
- const bool linked = strstr(op->idname, "linked") != NULL;
+ const bool linked = strstr(op->idname, "linked") != nullptr;
/* Can happen when calling from a key binding. */
- if (te == NULL) {
+ if (te == nullptr) {
BKE_report(op->reports, RPT_ERROR, "No active collection");
return OPERATOR_CANCELLED;
}
Collection *collection = outliner_collection_from_tree_element(te);
- Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : NULL;
+ Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : nullptr;
/* We are allowed to duplicated linked collections (they will become local IDs then),
* but we should not allow its parent to be a linked ID, ever.
* This can happen when a whole scene is linked e.g. */
- if (parent != NULL && (ID_IS_LINKED(parent) || ID_IS_OVERRIDE_LIBRARY(parent))) {
+ if (parent != nullptr && (ID_IS_LINKED(parent) || ID_IS_OVERRIDE_LIBRARY(parent))) {
Scene *scene = CTX_data_scene(C);
- parent = (ID_IS_LINKED(scene) || ID_IS_OVERRIDE_LIBRARY(scene)) ? NULL :
+ parent = (ID_IS_LINKED(scene) || ID_IS_OVERRIDE_LIBRARY(scene)) ? nullptr :
scene->master_collection;
}
- else if (parent != NULL && (parent->flag & COLLECTION_IS_MASTER) != 0) {
+ else if (parent != nullptr && (parent->flag & COLLECTION_IS_MASTER) != 0) {
BLI_assert(parent->id.flag & LIB_EMBEDDED_DATA);
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(&parent->id);
- BLI_assert(id_type->owner_get != NULL);
+ BLI_assert(id_type->owner_get != nullptr);
Scene *scene_owner = (Scene *)id_type->owner_get(bmain, &parent->id);
- BLI_assert(scene_owner != NULL);
+ BLI_assert(scene_owner != nullptr);
BLI_assert(GS(scene_owner->id.name) == ID_SCE);
if (ID_IS_LINKED(scene_owner) || ID_IS_OVERRIDE_LIBRARY(scene_owner)) {
scene_owner = CTX_data_scene(C);
- parent = ID_IS_LINKED(scene_owner) ? NULL : scene_owner->master_collection;
+ parent = ID_IS_LINKED(scene_owner) ? nullptr : scene_owner->master_collection;
}
}
@@ -617,14 +609,15 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (parent == NULL) {
+ if (parent == nullptr) {
BKE_report(op->reports,
RPT_WARNING,
"Could not find a valid parent collection for the new duplicate, "
"it won't be linked to any view layer");
}
- const eDupli_ID_Flags dupli_flags = USER_DUP_OBJECT | (linked ? 0 : U.dupflag);
+ const eDupli_ID_Flags dupli_flags = (eDupli_ID_Flags)(USER_DUP_OBJECT |
+ (linked ? 0 : U.dupflag));
BKE_collection_duplicate(bmain, parent, collection, dupli_flags, LIB_ID_DUPLICATE_IS_ROOT_ID);
DEG_relations_tag_update(bmain);
@@ -679,10 +672,10 @@ static int collection_link_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Collection *active_collection = CTX_data_layer_collection(C)->collection;
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
if ((ID_IS_LINKED(active_collection) || ID_IS_OVERRIDE_LIBRARY(active_collection)) ||
((active_collection->flag & COLLECTION_IS_MASTER) &&
@@ -701,17 +694,18 @@ static int collection_link_exec(bContext *C, wmOperator *op)
/* Effectively link the collections. */
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_collection_child_add(bmain, active_collection, collection);
id_fake_user_clear(&collection->id);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
DEG_id_tag_update(&active_collection->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
return OPERATOR_FINISHED;
}
@@ -743,10 +737,9 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
@@ -760,7 +753,8 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
while (BKE_collection_cycle_find(active_lc->collection, collection)) {
active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc);
@@ -769,20 +763,21 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
/* Effectively instance the collections. */
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
Object *ob = ED_object_add_type(
- C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, NULL, false, 0);
+ C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, nullptr, false, 0);
ob->instance_collection = collection;
ob->transflag |= OB_DUPLICOLLECTION;
id_lib_extern(&collection->id);
id_us_plus(&collection->id);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
return OPERATOR_FINISHED;
}
@@ -810,14 +805,14 @@ void OUTLINER_OT_collection_instance(wmOperatorType *ot)
static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, void *customdata)
{
- struct CollectionEditData *data = customdata;
+ CollectionEditData *data = reinterpret_cast<CollectionEditData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) {
return TRAVERSE_CONTINUE;
}
- LayerCollection *lc = te->directdata;
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata);
if (lc->collection->flag & COLLECTION_IS_MASTER) {
/* skip - showing warning/error message might be misleading
@@ -841,10 +836,9 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag)
}
Scene *scene = CTX_data_scene(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
bool result = false;
@@ -857,7 +851,8 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag)
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
if (clear && (lc->flag & flag)) {
result = true;
@@ -867,7 +862,7 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag)
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
return result;
}
@@ -907,11 +902,10 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
- bool clear = strstr(op->idname, "clear") != NULL;
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
+ bool clear = strstr(op->idname, "clear") != nullptr;
int flag = strstr(op->idname, "holdout") ? LAYER_COLLECTION_HOLDOUT :
strstr(op->idname, "indirect_only") ? LAYER_COLLECTION_INDIRECT_ONLY :
LAYER_COLLECTION_EXCLUDE;
@@ -927,16 +921,17 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op)
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_layer_collection_set_flag(lc, flag, !clear);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
BKE_layer_collection_sync(scene, view_layer);
DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
return OPERATOR_FINISHED;
}
@@ -1045,10 +1040,9 @@ static int collection_isolate_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
const bool extend = RNA_boolean_get(op->ptr, "extend");
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
@@ -1059,7 +1053,8 @@ static int collection_isolate_exec(bContext *C, wmOperator *op)
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
if (extend) {
BKE_layer_collection_isolate_global(scene, view_layer, layer_collection, true);
@@ -1074,16 +1069,16 @@ static int collection_isolate_exec(bContext *C, wmOperator *op)
* was called. */
const bool value = !RNA_property_boolean_get(&ptr, prop);
outliner_collection_isolate_flag(
- scene, view_layer, layer_collection, NULL, prop, "hide_viewport", value);
+ scene, view_layer, layer_collection, nullptr, prop, "hide_viewport", value);
break;
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
BKE_layer_collection_sync(scene, view_layer);
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1132,7 +1127,7 @@ static bool collection_inside_poll(bContext *C)
if (!ED_outliner_collections_editor_poll(C)) {
return false;
}
- return outliner_active_layer_collection(C) != NULL;
+ return outliner_active_layer_collection(C) != nullptr;
}
static int collection_visibility_exec(bContext *C, wmOperator *op)
@@ -1140,12 +1135,11 @@ static int collection_visibility_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- const bool is_inside = strstr(op->idname, "inside") != NULL;
- const bool show = strstr(op->idname, "show") != NULL;
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ const bool is_inside = strstr(op->idname, "inside") != nullptr;
+ const bool show = strstr(op->idname, "show") != nullptr;
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
outliner_tree_traverse(space_outliner,
@@ -1157,15 +1151,16 @@ static int collection_visibility_exec(bContext *C, wmOperator *op)
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_layer_collection_set_visible(view_layer, layer_collection, show, is_inside);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
BKE_layer_collection_sync(scene, view_layer);
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1242,12 +1237,12 @@ static bool collection_flag_poll(bContext *C, bool clear, int flag)
}
TreeElement *te = outliner_active_collection(C);
- if (te == NULL) {
+ if (te == nullptr) {
return false;
}
Collection *collection = outliner_collection_from_tree_element(te);
- if (collection == NULL) {
+ if (collection == nullptr) {
return false;
}
@@ -1289,10 +1284,9 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
const bool is_render = strstr(op->idname, "render");
const bool clear = strstr(op->idname, "show") || strstr(op->idname, "enable");
int flag = is_render ? COLLECTION_HIDE_RENDER : COLLECTION_HIDE_VIEWPORT;
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
const bool has_layer_collection = space_outliner->outlinevis == SO_VIEW_LAYER;
@@ -1305,7 +1299,8 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
&data);
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
Collection *collection = layer_collection->collection;
if (ID_IS_LINKED(collection)) {
continue;
@@ -1322,7 +1317,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
layer_collection->flag &= ~LAYER_COLLECTION_HIDE;
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
}
else {
outliner_tree_traverse(space_outliner,
@@ -1333,7 +1328,8 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
&data);
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
if (ID_IS_LINKED(collection)) {
continue;
}
@@ -1345,7 +1341,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
collection->flag |= flag;
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
}
BKE_layer_collection_sync(scene, view_layer);
@@ -1355,7 +1351,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
DEG_relations_tag_update(CTX_data_main(C));
}
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1435,15 +1431,15 @@ struct OutlinerHideEditData {
static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void *customdata)
{
- struct OutlinerHideEditData *data = customdata;
+ OutlinerHideEditData *data = reinterpret_cast<OutlinerHideEditData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem == NULL) {
+ if (tselem == nullptr) {
return TRAVERSE_CONTINUE;
}
if (tselem->type == TSE_LAYER_COLLECTION) {
- LayerCollection *lc = te->directdata;
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata);
if (lc->collection->flag & COLLECTION_IS_MASTER) {
/* Skip - showing warning/error message might be misleading
@@ -1469,11 +1465,10 @@ static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct OutlinerHideEditData data = {
- .scene = scene,
- .view_layer = view_layer,
- .space_outliner = space_outliner,
- };
+ OutlinerHideEditData data{};
+ data.scene = scene;
+ data.view_layer = view_layer;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new("outliner_hide_exec__collections_to_edit");
data.bases_to_edit = BLI_gset_ptr_new("outliner_hide_exec__bases_to_edit");
@@ -1486,22 +1481,23 @@ static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op))
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_layer_collection_set_visible(view_layer, layer_collection, false, false);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
GSetIterator bases_to_edit_iter;
GSET_ITER (bases_to_edit_iter, data.bases_to_edit) {
- Base *base = BLI_gsetIterator_getKey(&bases_to_edit_iter);
+ Base *base = reinterpret_cast<Base *>(BLI_gsetIterator_getKey(&bases_to_edit_iter));
base->flag |= BASE_HIDDEN;
}
- BLI_gset_free(data.bases_to_edit, NULL);
+ BLI_gset_free(data.bases_to_edit, nullptr);
BKE_layer_collection_sync(scene, view_layer);
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1526,7 +1522,8 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op))
ViewLayer *view_layer = CTX_data_view_layer(C);
/* Unhide all the collections. */
- LayerCollection *lc_master = view_layer->layer_collections.first;
+ LayerCollection *lc_master = reinterpret_cast<LayerCollection *>(
+ view_layer->layer_collections.first);
LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
BKE_layer_collection_set_flag(lc_iter, LAYER_COLLECTION_HIDE, false);
}
@@ -1539,7 +1536,7 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op))
BKE_layer_collection_sync(scene, view_layer);
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1570,9 +1567,7 @@ static int outliner_color_tag_set_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
const short color_tag = RNA_enum_get(op->ptr, "color");
- struct IDsSelectedData selected = {
- .selected_array = {NULL, NULL},
- };
+ IDsSelectedData selected{};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
@@ -1598,7 +1593,7 @@ static int outliner_color_tag_set_exec(bContext *C, wmOperator *op)
BLI_freelistN(&selected.selected_array);
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_outliner/outliner_context.c b/source/blender/editors/space_outliner/outliner_context.cc
index d61bb17f661..d3b99928ec1 100644
--- a/source/blender/editors/space_outliner/outliner_context.c
+++ b/source/blender/editors/space_outliner/outliner_context.cc
@@ -27,7 +27,7 @@
#include "DNA_space_types.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
static void outliner_context_selected_ids_recursive(const ListBase *subtree,
bContextDataResult *result)
@@ -48,7 +48,7 @@ static void outliner_context_selected_ids(const SpaceOutliner *space_outliner,
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
}
-static const char *outliner_context_dir[] = {"selected_ids", NULL};
+static const char *outliner_context_dir[] = {"selected_ids", nullptr};
int /*eContextResult*/ outliner_context(const bContext *C,
const char *member,
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.cc
index a82f516b125..3745894d630 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <string.h>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -58,7 +58,7 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
static Collection *collection_parent_from_ID(ID *id);
@@ -83,7 +83,7 @@ static TreeElement *outliner_dropzone_element(TreeElement *te,
}
}
}
- return NULL;
+ return nullptr;
}
/* Find tree element to drop into. */
@@ -97,7 +97,7 @@ static TreeElement *outliner_dropzone_find(const SpaceOutliner *space_outliner,
return te_valid;
}
}
- return NULL;
+ return nullptr;
}
static TreeElement *outliner_drop_find(bContext *C, const wmEvent *event)
@@ -113,17 +113,17 @@ static TreeElement *outliner_drop_find(bContext *C, const wmEvent *event)
static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode)
{
TreeElement *te = outliner_drop_find(C, event);
- TreeStoreElem *tselem = (te) ? TREESTORE(te) : NULL;
+ TreeStoreElem *tselem = (te) ? TREESTORE(te) : nullptr;
if (te && (te->idcode == idcode) && (tselem->type == TSE_SOME_ID)) {
return tselem->id;
}
- return NULL;
+ return nullptr;
}
/* Find tree element to drop into, with additional before and after reorder support. */
static TreeElement *outliner_drop_insert_find(bContext *C,
- const wmEvent *event,
+ const int xy[2],
TreeElementInsertType *r_insert_type)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
@@ -133,11 +133,14 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
/* Empty tree, e.g. while filtered. */
if (BLI_listbase_is_empty(&space_outliner->tree)) {
- return NULL;
+ return nullptr;
}
- UI_view2d_region_to_view(
- &region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
+ int mval[2];
+ mval[0] = xy[0] - region->winrct.xmin;
+ mval[1] = xy[1] - region->winrct.ymin;
+
+ UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
te_hovered = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
if (te_hovered) {
@@ -154,7 +157,7 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
return te_hovered;
}
*r_insert_type = TE_INSERT_BEFORE;
- return te_hovered->subtree.first;
+ return reinterpret_cast<TreeElement *>(te_hovered->subtree.first);
}
*r_insert_type = TE_INSERT_AFTER;
return te_hovered;
@@ -169,8 +172,8 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
/* Mouse doesn't hover any item (ignoring x-axis),
* so it's either above list bounds or below. */
- TreeElement *first = space_outliner->tree.first;
- TreeElement *last = space_outliner->tree.last;
+ TreeElement *first = reinterpret_cast<TreeElement *>(space_outliner->tree.first);
+ TreeElement *last = reinterpret_cast<TreeElement *>(space_outliner->tree.last);
if (view_mval[1] < last->ys) {
*r_insert_type = TE_INSERT_AFTER;
@@ -181,21 +184,21 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
return first;
}
BLI_assert(0);
- return NULL;
+ return nullptr;
}
-typedef bool (*CheckTypeFn)(TreeElement *te);
+using CheckTypeFn = bool (*)(TreeElement *te);
static TreeElement *outliner_data_from_tree_element_and_parents(CheckTypeFn check_type,
TreeElement *te)
{
- while (te != NULL) {
+ while (te != nullptr) {
if (check_type(te)) {
return te;
}
te = te->parent;
}
- return NULL;
+ return nullptr;
}
static bool is_collection_element(TreeElement *te)
@@ -216,18 +219,18 @@ static bool is_pchan_element(TreeElement *te)
}
static TreeElement *outliner_drop_insert_collection_find(bContext *C,
- const wmEvent *event,
+ const int xy[2],
TreeElementInsertType *r_insert_type)
{
- TreeElement *te = outliner_drop_insert_find(C, event, r_insert_type);
+ TreeElement *te = outliner_drop_insert_find(C, xy, r_insert_type);
if (!te) {
- return NULL;
+ return nullptr;
}
TreeElement *collection_te = outliner_data_from_tree_element_and_parents(is_collection_element,
te);
if (!collection_te) {
- return NULL;
+ return nullptr;
}
Collection *collection = outliner_collection_from_tree_element(collection_te);
@@ -260,7 +263,7 @@ static int outliner_get_insert_index(TreeElement *drag_te,
}
}
- if (drop_te == NULL) {
+ if (drop_te == nullptr) {
return 0;
}
@@ -364,7 +367,7 @@ static void parent_drop_set_parents(bContext *C,
TreeElement *te = outliner_find_id(space_outliner, &space_outliner->tree, &parent->id);
Scene *scene = (Scene *)outliner_search_back(te, ID_SCE);
- if (scene == NULL) {
+ if (scene == nullptr) {
/* currently outliner organized in a way, that if there's no parent scene
* element for object it means that all displayed objects belong to
* active scene and parenting them is allowed (sergey)
@@ -387,7 +390,7 @@ static void parent_drop_set_parents(bContext *C,
}
if (ED_object_parent_set(
- reports, C, scene, object, parent, parent_type, false, keep_transform, NULL)) {
+ reports, C, scene, object, parent, parent_type, false, keep_transform, nullptr)) {
parent_set = true;
}
}
@@ -399,15 +402,15 @@ static void parent_drop_set_parents(bContext *C,
if (parent_set) {
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, nullptr);
}
}
static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
TreeElement *te = outliner_drop_find(C, event);
- TreeStoreElem *tselem = te ? TREESTORE(te) : NULL;
+ TreeStoreElem *tselem = te ? TREESTORE(te) : nullptr;
if (!(te && (te->idcode == ID_OB) && (tselem->type == TSE_SOME_ID))) {
return OPERATOR_CANCELLED;
@@ -416,7 +419,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Object *par = (Object *)tselem->id;
Object *ob = (Object *)WM_drag_get_local_ID_from_event(event, ID_OB);
- if (ELEM(NULL, ob, par)) {
+ if (ELEM(nullptr, ob, par)) {
return OPERATOR_CANCELLED;
}
if (ob == par) {
@@ -427,10 +430,11 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- ListBase *lb = event->customdata;
- wmDrag *drag = lb->first;
+ ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
+ wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
- parent_drop_set_parents(C, op->reports, drag->ids.first, par, PAR_OBJECT, event->alt);
+ parent_drop_set_parents(
+ C, op->reports, reinterpret_cast<wmDragID *>(drag->ids.first), par, PAR_OBJECT, event->alt);
return OPERATOR_FINISHED;
}
@@ -501,8 +505,8 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven
return OPERATOR_CANCELLED;
}
- ListBase *lb = event->customdata;
- wmDrag *drag = lb->first;
+ ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
+ wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) {
if (GS(drag_id->id->name) == ID_OB) {
@@ -513,8 +517,8 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven
}
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -540,7 +544,7 @@ static bool scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
/* Ensure item under cursor is valid drop target */
Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB);
- return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != NULL));
+ return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != nullptr));
}
static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
@@ -549,7 +553,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
Scene *scene = (Scene *)outliner_ID_drop_find(C, event, ID_SCE);
Object *ob = (Object *)WM_drag_get_local_ID_from_event(event, ID_OB);
- if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) {
+ if (ELEM(nullptr, ob, scene) || ID_IS_LINKED(scene)) {
return OPERATOR_CANCELLED;
}
@@ -605,7 +609,7 @@ static bool material_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
/* Ensure item under cursor is valid drop target */
Material *ma = (Material *)WM_drag_get_local_ID(drag, ID_MA);
- return (ma && (outliner_ID_drop_find(C, event, ID_OB) != NULL));
+ return (ma && (outliner_ID_drop_find(C, event, ID_OB) != nullptr));
}
static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
@@ -614,19 +618,19 @@ static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve
Object *ob = (Object *)outliner_ID_drop_find(C, event, ID_OB);
Material *ma = (Material *)WM_drag_get_local_ID_from_event(event, ID_MA);
- if (ELEM(NULL, ob, ma)) {
+ if (ELEM(nullptr, ob, ma)) {
return OPERATOR_CANCELLED;
}
/* only drop grease pencil material on grease pencil objects */
- if ((ma->gp_style != NULL) && (ob->type != OB_GPENCIL)) {
+ if ((ma->gp_style != nullptr) && (ob->type != OB_GPENCIL)) {
return OPERATOR_CANCELLED;
}
BKE_object_material_assign(bmain, ob, ma, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma);
return OPERATOR_FINISHED;
@@ -658,13 +662,13 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot)
* - Copying a single modifier/constraint/effect to another object.
* - Copying (linking) an object's modifiers/constraints/effects to another. */
-typedef enum eDataStackDropAction {
+enum eDataStackDropAction {
DATA_STACK_DROP_REORDER,
DATA_STACK_DROP_COPY,
DATA_STACK_DROP_LINK,
-} eDataStackDropAction;
+};
-typedef struct StackDropData {
+struct StackDropData {
Object *ob_parent;
bPoseChannel *pchan_parent;
TreeStoreElem *drag_tselem;
@@ -674,7 +678,7 @@ typedef struct StackDropData {
eDataStackDropAction drop_action;
TreeElement *drop_te;
TreeElementInsertType insert_type;
-} StackDropData;
+};
static void datastack_drop_data_init(wmDrag *drag,
Object *ob,
@@ -683,7 +687,7 @@ static void datastack_drop_data_init(wmDrag *drag,
TreeStoreElem *tselem,
void *directdata)
{
- StackDropData *drop_data = MEM_callocN(sizeof(*drop_data), "datastack drop data");
+ StackDropData *drop_data = MEM_cnew<StackDropData>("datastack drop data");
drop_data->ob_parent = ob;
drop_data->pchan_parent = pchan;
@@ -707,7 +711,7 @@ static bool datastack_drop_init(bContext *C, const wmEvent *event, StackDropData
return false;
}
- TreeElement *te_target = outliner_drop_insert_find(C, event, &drop_data->insert_type);
+ TreeElement *te_target = outliner_drop_insert_find(C, event->xy, &drop_data->insert_type);
if (!te_target) {
return false;
}
@@ -717,20 +721,20 @@ static bool datastack_drop_init(bContext *C, const wmEvent *event, StackDropData
return false;
}
- Object *ob = NULL;
+ Object *ob = nullptr;
TreeElement *object_te = outliner_data_from_tree_element_and_parents(is_object_element,
te_target);
if (object_te) {
ob = (Object *)TREESTORE(object_te)->id;
}
- bPoseChannel *pchan = NULL;
+ bPoseChannel *pchan = nullptr;
TreeElement *pchan_te = outliner_data_from_tree_element_and_parents(is_pchan_element, te_target);
if (pchan_te) {
pchan = (bPoseChannel *)pchan_te->directdata;
}
if (pchan) {
- ob = NULL;
+ ob = nullptr;
}
if (ob && ID_IS_LINKED(&ob->id)) {
@@ -833,7 +837,7 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
bool changed = outliner_flag_set(
&space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
- StackDropData *drop_data = drag->poin;
+ StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin);
if (!drop_data) {
return false;
}
@@ -868,10 +872,10 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
static char *datastack_drop_tooltip(bContext *UNUSED(C),
wmDrag *drag,
- const wmEvent *UNUSED(event),
+ const int UNUSED(xy[2]),
struct wmDropBox *UNUSED(drop))
{
- StackDropData *drop_data = drag->poin;
+ StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin);
switch (drop_data->drop_action) {
case DATA_STACK_DROP_REORDER:
return BLI_strdup(TIP_("Reorder"));
@@ -893,7 +897,7 @@ static char *datastack_drop_tooltip(bContext *UNUSED(C),
}
break;
}
- return NULL;
+ return nullptr;
}
static void datastack_drop_link(bContext *C, StackDropData *drop_data)
@@ -948,20 +952,28 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data)
switch (drop_data->drag_tselem->type) {
case TSE_MODIFIER:
if (drop_data->ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) {
- ED_object_gpencil_modifier_copy_to_object(ob_dst, drop_data->drag_directdata);
+ ED_object_gpencil_modifier_copy_to_object(
+ ob_dst, reinterpret_cast<GpencilModifierData *>(drop_data->drag_directdata));
}
else if (drop_data->ob_parent->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) {
ED_object_modifier_copy_to_object(
- C, ob_dst, drop_data->ob_parent, drop_data->drag_directdata);
+ C,
+ ob_dst,
+ drop_data->ob_parent,
+ reinterpret_cast<ModifierData *>(drop_data->drag_directdata));
}
break;
case TSE_CONSTRAINT:
if (tselem->type == TSE_POSE_CHANNEL) {
ED_object_constraint_copy_for_pose(
- bmain, ob_dst, drop_data->drop_te->directdata, drop_data->drag_directdata);
+ bmain,
+ ob_dst,
+ reinterpret_cast<bPoseChannel *>(drop_data->drop_te->directdata),
+ reinterpret_cast<bConstraint *>(drop_data->drag_directdata));
}
else {
- ED_object_constraint_copy_for_object(bmain, ob_dst, drop_data->drag_directdata);
+ ED_object_constraint_copy_for_object(
+ bmain, ob_dst, reinterpret_cast<bConstraint *>(drop_data->drag_directdata));
}
break;
case TSE_GPENCIL_EFFECT: {
@@ -969,7 +981,8 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data)
return;
}
- ED_object_shaderfx_copy(ob_dst, drop_data->drag_directdata);
+ ED_object_shaderfx_copy(ob_dst,
+ reinterpret_cast<ShaderFxData *>(drop_data->drag_directdata));
break;
}
}
@@ -995,11 +1008,16 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa
if (ob->type == OB_GPENCIL) {
index = outliner_get_insert_index(
drag_te, drop_te, insert_type, &ob->greasepencil_modifiers);
- ED_object_gpencil_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index);
+ ED_object_gpencil_modifier_move_to_index(
+ reports,
+ ob,
+ reinterpret_cast<GpencilModifierData *>(drop_data->drag_directdata),
+ index);
}
else {
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->modifiers);
- ED_object_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index);
+ ED_object_modifier_move_to_index(
+ reports, ob, reinterpret_cast<ModifierData *>(drop_data->drag_directdata), index);
}
break;
case TSE_CONSTRAINT:
@@ -1010,12 +1028,14 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa
else {
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->constraints);
}
- ED_object_constraint_move_to_index(ob, drop_data->drag_directdata, index);
+ ED_object_constraint_move_to_index(
+ ob, reinterpret_cast<bConstraint *>(drop_data->drag_directdata), index);
break;
case TSE_GPENCIL_EFFECT:
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->shader_fx);
- ED_object_shaderfx_move_to_index(reports, ob, drop_data->drag_directdata, index);
+ ED_object_shaderfx_move_to_index(
+ reports, ob, reinterpret_cast<ShaderFxData *>(drop_data->drag_directdata), index);
}
}
@@ -1025,9 +1045,9 @@ static int datastack_drop_invoke(bContext *C, wmOperator *op, const wmEvent *eve
return OPERATOR_CANCELLED;
}
- ListBase *lb = event->customdata;
- wmDrag *drag = lb->first;
- StackDropData *drop_data = drag->poin;
+ ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
+ wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
+ StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin);
switch (drop_data->drop_action) {
case DATA_STACK_DROP_LINK:
@@ -1062,19 +1082,19 @@ void OUTLINER_OT_datastack_drop(wmOperatorType *ot)
/* ******************** Collection Drop Operator *********************** */
-typedef struct CollectionDrop {
+struct CollectionDrop {
Collection *from;
Collection *to;
TreeElement *te;
TreeElementInsertType insert_type;
-} CollectionDrop;
+};
static Collection *collection_parent_from_ID(ID *id)
{
/* Can't change linked parent collections. */
if (!id || ID_IS_LINKED(id)) {
- return NULL;
+ return nullptr;
}
/* Also support dropping into/from scene collection. */
@@ -1085,17 +1105,15 @@ static Collection *collection_parent_from_ID(ID *id)
return (Collection *)id;
}
- return NULL;
+ return nullptr;
}
-static bool collection_drop_init(bContext *C,
- wmDrag *drag,
- const wmEvent *event,
- CollectionDrop *data)
+static bool collection_drop_init(
+ bContext *C, wmDrag *drag, const int xy[2], const bool is_link, CollectionDrop *data)
{
/* Get collection to drop into. */
TreeElementInsertType insert_type;
- TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type);
+ TreeElement *te = outliner_drop_insert_collection_find(C, xy, &insert_type);
if (!te) {
return false;
}
@@ -1110,8 +1128,8 @@ static bool collection_drop_init(bContext *C,
return false;
}
- wmDragID *drag_id = drag->ids.first;
- if (drag_id == NULL) {
+ wmDragID *drag_id = reinterpret_cast<wmDragID *>(drag->ids.first);
+ if (drag_id == nullptr) {
return false;
}
@@ -1123,12 +1141,12 @@ static bool collection_drop_init(bContext *C,
/* Get collection to drag out of. */
ID *parent = drag_id->from_parent;
Collection *from_collection = collection_parent_from_ID(parent);
- if (event->ctrl) {
- from_collection = NULL;
+ if (is_link) {
+ from_collection = nullptr;
}
/* Currently this should not be allowed, cannot edit items in an override of a Collection. */
- if (from_collection != NULL && ID_IS_OVERRIDE_LIBRARY(from_collection)) {
+ if (from_collection != nullptr && ID_IS_OVERRIDE_LIBRARY(from_collection)) {
return false;
}
@@ -1164,7 +1182,7 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
&space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
CollectionDrop data;
- if (!event->shift && collection_drop_init(C, drag, event, &data)) {
+ if (!event->shift && collection_drop_init(C, drag, event->xy, event->ctrl, &data)) {
TreeElement *te = data.te;
TreeStoreElem *tselem = TREESTORE(te);
if (!data.from || event->ctrl) {
@@ -1201,11 +1219,14 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
static char *collection_drop_tooltip(bContext *C,
wmDrag *drag,
- const wmEvent *event,
+ const int xy[2],
wmDropBox *UNUSED(drop))
{
+ wmWindow *win = CTX_wm_window(C);
+ const wmEvent *event = win ? win->eventstate : nullptr;
+
CollectionDrop data;
- if (!event->shift && collection_drop_init(C, drag, event, &data)) {
+ if (event && !event->shift && collection_drop_init(C, drag, xy, event->ctrl, &data)) {
TreeElement *te = data.te;
if (!data.from || event->ctrl) {
return BLI_strdup(TIP_("Link inside Collection"));
@@ -1242,7 +1263,7 @@ static char *collection_drop_tooltip(bContext *C,
}
}
}
- return NULL;
+ return nullptr;
}
static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
@@ -1254,16 +1275,16 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
return OPERATOR_CANCELLED;
}
- ListBase *lb = event->customdata;
- wmDrag *drag = lb->first;
+ ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
+ wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
CollectionDrop data;
- if (!collection_drop_init(C, drag, event, &data)) {
+ if (!collection_drop_init(C, drag, event->xy, event->ctrl, &data)) {
return OPERATOR_CANCELLED;
}
/* Before/after insert handling. */
- Collection *relative = NULL;
+ Collection *relative = nullptr;
bool relative_after = false;
if (ELEM(data.insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) {
@@ -1272,8 +1293,8 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
relative = data.to;
relative_after = (data.insert_type == TE_INSERT_AFTER);
- TreeElement *parent_te = outliner_find_parent_element(&space_outliner->tree, NULL, data.te);
- data.to = (parent_te) ? outliner_collection_from_tree_element(parent_te) : NULL;
+ TreeElement *parent_te = outliner_find_parent_element(&space_outliner->tree, nullptr, data.te);
+ data.to = (parent_te) ? outliner_collection_from_tree_element(parent_te) : nullptr;
}
if (!data.to) {
@@ -1286,7 +1307,7 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) {
/* Ctrl enables linking, so we don't need a from collection then. */
- Collection *from = (event->ctrl) ? NULL : collection_parent_from_ID(drag_id->from_parent);
+ Collection *from = (event->ctrl) ? nullptr : collection_parent_from_ID(drag_id->from_parent);
if (GS(drag_id->id->name) == ID_OB) {
/* Move/link object into collection. */
@@ -1309,7 +1330,7 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
}
if (from) {
- DEG_id_tag_update(&from->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&from->id, ID_RECALC_COPY_ON_WRITE | ID_RECALC_GEOMETRY);
}
}
@@ -1398,10 +1419,10 @@ static int outliner_item_drag_drop_invoke(bContext *C,
TSE_GPENCIL_EFFECT_BASE);
const int wm_drag_type = use_datastack_drag ? WM_DRAG_DATASTACK : WM_DRAG_ID;
- wmDrag *drag = WM_event_start_drag(C, data.icon, wm_drag_type, NULL, 0.0, WM_DRAG_NOP);
+ wmDrag *drag = WM_event_start_drag(C, data.icon, wm_drag_type, nullptr, 0.0, WM_DRAG_NOP);
if (use_datastack_drag) {
- TreeElement *te_bone = NULL;
+ TreeElement *te_bone = nullptr;
bPoseChannel *pchan = outliner_find_parent_bone(te, &te_bone);
datastack_drop_data_init(drag, (Object *)tselem->id, pchan, te, tselem, te->directdata);
}
@@ -1415,9 +1436,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
}
/* Gather all selected elements. */
- struct IDsSelectedData selected = {
- .selected_array = {NULL, NULL},
- };
+ IDsSelectedData selected{};
if (GS(data.drag_id->name) == ID_OB) {
outliner_tree_traverse(space_outliner,
@@ -1464,7 +1483,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
}
/* Find parent collection. */
- Collection *parent = NULL;
+ Collection *parent = nullptr;
if (te_selected->parent) {
for (TreeElement *te_parent = te_selected->parent; te_parent;
@@ -1513,21 +1532,24 @@ void OUTLINER_OT_item_drag_drop(wmOperatorType *ot)
/* *************************** Drop Boxes ************************** */
-/* region dropbox definition */
void outliner_dropboxes(void)
{
ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW);
- WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", parent_drop_poll, NULL, NULL, NULL);
- WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, NULL, NULL, NULL);
- WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, NULL, NULL, NULL);
- WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, NULL, NULL, NULL);
- WM_dropbox_add(
- lb, "OUTLINER_OT_datastack_drop", datastack_drop_poll, NULL, NULL, datastack_drop_tooltip);
+ WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", parent_drop_poll, nullptr, nullptr, nullptr);
+ WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, nullptr, nullptr, nullptr);
+ WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, nullptr, nullptr, nullptr);
+ WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, nullptr, nullptr, nullptr);
+ WM_dropbox_add(lb,
+ "OUTLINER_OT_datastack_drop",
+ datastack_drop_poll,
+ nullptr,
+ nullptr,
+ datastack_drop_tooltip);
WM_dropbox_add(lb,
"OUTLINER_OT_collection_drop",
collection_drop_poll,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
collection_drop_tooltip);
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.cc
index 7cdfb553da5..6de8d9539a9 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -78,7 +78,11 @@
#include "RNA_access.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
+#include "tree/tree_display.hh"
+#include "tree/tree_element.hh"
+
+using namespace blender::ed::outliner;
/* Disable - this is far too slow - campbell. */
/* #define USE_GROUP_SELECT */
@@ -93,7 +97,7 @@ static void outliner_tree_dimensions_impl(SpaceOutliner *space_outliner,
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
*width = MAX2(*width, te->xend);
- if (height != NULL) {
+ if (height != nullptr) {
*height += UI_UNIT_Y;
}
@@ -102,7 +106,7 @@ static void outliner_tree_dimensions_impl(SpaceOutliner *space_outliner,
outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, height);
}
else {
- outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, NULL);
+ outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, nullptr);
}
}
}
@@ -119,7 +123,7 @@ void outliner_tree_dimensions(SpaceOutliner *space_outliner, int *r_width, int *
*/
static bool is_object_data_in_editmode(const ID *id, const Object *obact)
{
- if (id == NULL) {
+ if (id == nullptr) {
return false;
}
@@ -141,9 +145,7 @@ static void restrictbutton_recursive_ebone(bArmature *arm,
int flag,
bool set_flag)
{
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) {
if (set_flag) {
ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
@@ -158,8 +160,7 @@ static void restrictbutton_recursive_ebone(bArmature *arm,
static void restrictbutton_recursive_bone(Bone *bone_parent, int flag, bool set_flag)
{
- Bone *bone;
- for (bone = bone_parent->childbase.first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, &bone_parent->childbase) {
if (set_flag) {
bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
bone->flag |= flag;
@@ -196,7 +197,7 @@ static void restrictbutton_bone_select_fn(bContext *C, void *UNUSED(poin), void
restrictbutton_recursive_bone(bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0);
}
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
}
static void restrictbutton_ebone_select_fn(bContext *C, void *poin, void *poin2)
@@ -213,7 +214,7 @@ static void restrictbutton_ebone_select_fn(bContext *C, void *poin, void *poin2)
arm, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0);
}
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
}
static void restrictbutton_ebone_visibility_fn(bContext *C, void *poin, void *poin2)
@@ -228,7 +229,7 @@ static void restrictbutton_ebone_visibility_fn(bContext *C, void *poin, void *po
restrictbutton_recursive_ebone(arm, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0);
}
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
}
static void restrictbutton_gp_layer_flag_fn(bContext *C, void *poin, void *UNUSED(poin2))
@@ -236,14 +237,14 @@ static void restrictbutton_gp_layer_flag_fn(bContext *C, void *poin, void *UNUSE
ID *id = (ID *)poin;
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, nullptr);
}
static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void *UNUSED(poin2))
{
ID *id = (ID *)poin;
- BLI_assert(id != NULL);
+ BLI_assert(id != nullptr);
if (id->flag & LIB_FAKEUSER) {
id_us_plus(id);
@@ -281,7 +282,8 @@ static void outliner_object_set_flag_recursive_fn(bContext *C,
Object *ob_parent = ob ? ob : base->object;
- for (Object *ob_iter = bmain->objects.first; ob_iter; ob_iter = ob_iter->id.next) {
+ for (Object *ob_iter = reinterpret_cast<Object *>(bmain->objects.first); ob_iter;
+ ob_iter = reinterpret_cast<Object *>(ob_iter->id.next)) {
if (BKE_object_is_child_recursive(ob_parent, ob_iter)) {
if (ob) {
RNA_id_pointer_create(&ob_iter->id, &ptr);
@@ -290,7 +292,7 @@ static void outliner_object_set_flag_recursive_fn(bContext *C,
else {
Base *base_iter = BKE_view_layer_base_find(view_layer, ob_iter);
/* Child can be in a collection excluded from viewlayer. */
- if (base_iter == NULL) {
+ if (base_iter == nullptr) {
continue;
}
RNA_pointer_create(&scene->id, &RNA_ObjectBase, base_iter, &ptr);
@@ -315,9 +317,9 @@ static void outliner_object_set_flag_recursive_fn(bContext *C,
*/
static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- Object *ob = poin;
- char *propname = poin2;
- outliner_object_set_flag_recursive_fn(C, NULL, ob, propname);
+ Object *ob = reinterpret_cast<Object *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
+ outliner_object_set_flag_recursive_fn(C, nullptr, ob, propname);
}
/**
@@ -325,9 +327,9 @@ static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void
*/
static void outliner__base_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- Base *base = poin;
- char *propname = poin2;
- outliner_object_set_flag_recursive_fn(C, base, NULL, propname);
+ Base *base = reinterpret_cast<Base *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
+ outliner_object_set_flag_recursive_fn(C, base, nullptr, propname);
}
/** Create either a RNA_LayerCollection or a RNA_Collection pointer. */
@@ -392,9 +394,9 @@ static void outliner_collection_set_flag_recursive(Scene *scene,
/* Keep going recursively. */
ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
LISTBASE_FOREACH (Link *, link, lb) {
- LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL;
+ LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : nullptr;
Collection *collection_iter = layer_collection ?
- (collection ? layer_collection_iter->collection : NULL) :
+ (collection ? layer_collection_iter->collection : nullptr) :
((CollectionChild *)link)->collection;
outliner_collection_set_flag_recursive(scene,
view_layer,
@@ -458,9 +460,9 @@ static bool outliner_collection_is_isolated(Scene *scene,
/* Keep going recursively. */
ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
LISTBASE_FOREACH (Link *, link, lb) {
- LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL;
+ LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : nullptr;
Collection *collection_iter = layer_collection ?
- (collection ? layer_collection_iter->collection : NULL) :
+ (collection ? layer_collection_iter->collection : nullptr) :
((CollectionChild *)link)->collection;
if (layer_collection_iter && layer_collection_iter->flag & LAYER_COLLECTION_EXCLUDE) {
continue;
@@ -488,11 +490,13 @@ void outliner_collection_isolate_flag(Scene *scene,
const bool value)
{
PointerRNA ptr;
- const bool is_hide = strstr(propname, "hide_") != NULL;
+ const bool is_hide = strstr(propname, "hide_") != nullptr;
- LayerCollection *top_layer_collection = layer_collection ? view_layer->layer_collections.first :
- NULL;
- Collection *top_collection = collection ? scene->master_collection : NULL;
+ LayerCollection *top_layer_collection = layer_collection ?
+ reinterpret_cast<LayerCollection *>(
+ view_layer->layer_collections.first) :
+ nullptr;
+ Collection *top_collection = collection ? scene->master_collection : nullptr;
bool was_isolated = (value == is_hide);
was_isolated &= outliner_collection_is_isolated(scene,
@@ -504,14 +508,14 @@ void outliner_collection_isolate_flag(Scene *scene,
top_collection);
if (was_isolated) {
- const bool default_value = RNA_property_boolean_get_default(NULL, layer_or_collection_prop);
+ const bool default_value = RNA_property_boolean_get_default(nullptr, layer_or_collection_prop);
/* Make every collection go back to its default "visibility" state. */
outliner_collection_set_flag_recursive(scene,
view_layer,
top_layer_collection,
top_collection,
layer_or_collection_prop,
- NULL,
+ nullptr,
default_value);
return;
}
@@ -522,12 +526,17 @@ void outliner_collection_isolate_flag(Scene *scene,
top_layer_collection,
top_collection,
layer_or_collection_prop,
- NULL,
+ nullptr,
is_hide);
/* Make this collection and its children collections the only "visible". */
- outliner_collection_set_flag_recursive(
- scene, view_layer, layer_collection, collection, layer_or_collection_prop, NULL, !is_hide);
+ outliner_collection_set_flag_recursive(scene,
+ view_layer,
+ layer_collection,
+ collection,
+ layer_or_collection_prop,
+ nullptr,
+ !is_hide);
/* Make this collection direct parents also "visible". */
if (layer_collection) {
@@ -541,7 +550,7 @@ void outliner_collection_isolate_flag(Scene *scene,
while (lc_parent != layer_collection) {
outliner_layer_or_collection_pointer_create(
- scene, lc_parent, collection ? lc_parent->collection : NULL, &ptr);
+ scene, lc_parent, collection ? lc_parent->collection : nullptr, &ptr);
RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide);
LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) {
@@ -555,7 +564,7 @@ void outliner_collection_isolate_flag(Scene *scene,
else {
CollectionParent *parent;
Collection *child = collection;
- while ((parent = child->parents.first)) {
+ while ((parent = reinterpret_cast<CollectionParent *>(child->parents.first))) {
if (parent->collection->flag & COLLECTION_IS_MASTER) {
break;
}
@@ -594,8 +603,8 @@ static void outliner_collection_set_flag_recursive_fn(bContext *C,
PropertyRNA *layer_or_collection_prop = RNA_struct_type_find_property(struct_rna, propname);
const bool value = RNA_property_boolean_get(&ptr, layer_or_collection_prop);
- PropertyRNA *base_or_object_prop = NULL;
- if (layer_collection != NULL) {
+ PropertyRNA *base_or_object_prop = nullptr;
+ if (layer_collection != nullptr) {
/* If we are toggling Layer collections we still want to change the properties of the base
* or the objects. If we have a matching property, toggle it as well, it can be NULL. */
struct_rna = collection ? &RNA_Object : &RNA_ObjectBase;
@@ -634,9 +643,9 @@ static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C,
void *poin,
void *poin2)
{
- LayerCollection *layer_collection = poin;
- char *propname = poin2;
- outliner_collection_set_flag_recursive_fn(C, layer_collection, NULL, propname);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
+ outliner_collection_set_flag_recursive_fn(C, layer_collection, nullptr, propname);
}
/**
@@ -645,8 +654,8 @@ static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C,
*/
static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- LayerCollection *layer_collection = poin;
- char *propname = poin2;
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
outliner_collection_set_flag_recursive_fn(
C, layer_collection, layer_collection->collection, propname);
}
@@ -657,18 +666,20 @@ static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin
*/
static void scenes__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- Collection *collection = poin;
- char *propname = poin2;
- outliner_collection_set_flag_recursive_fn(C, NULL, collection, propname);
+ Collection *collection = reinterpret_cast<Collection *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
+ outliner_collection_set_flag_recursive_fn(C, nullptr, collection, propname);
}
+/* FIXME: See comment above #WM_msg_publish_rna_prop(). */
+extern "C" {
static void namebutton_fn(bContext *C, void *tsep, char *oldname)
{
Main *bmain = CTX_data_main(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
BLI_mempool *ts = space_outliner->treestore;
- TreeStoreElem *tselem = tsep;
+ TreeStoreElem *tselem = reinterpret_cast<TreeStoreElem *>(tsep);
if (ts && tselem) {
TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
@@ -680,16 +691,16 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
switch (GS(tselem->id->name)) {
case ID_MA:
- WM_event_add_notifier(C, NC_MATERIAL, NULL);
+ WM_event_add_notifier(C, NC_MATERIAL, nullptr);
break;
case ID_TE:
- WM_event_add_notifier(C, NC_TEXTURE, NULL);
+ WM_event_add_notifier(C, NC_TEXTURE, nullptr);
break;
case ID_IM:
- WM_event_add_notifier(C, NC_IMAGE, NULL);
+ WM_event_add_notifier(C, NC_IMAGE, nullptr);
break;
case ID_SCE:
- WM_event_add_notifier(C, NC_SCENE, NULL);
+ WM_event_add_notifier(C, NC_SCENE, nullptr);
break;
case ID_OB: {
Object *ob = (Object *)tselem->id;
@@ -702,7 +713,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
default:
break;
}
- WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr);
/* Check the library target exists */
if (te->idcode == ID_LI) {
@@ -732,7 +743,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
switch (tselem->type) {
case TSE_DEFGROUP: {
Object *ob = (Object *)tselem->id;
- bDeformGroup *vg = te->directdata;
+ bDeformGroup *vg = reinterpret_cast<bDeformGroup *>(te->directdata);
BKE_object_defgroup_unique_name(vg, ob);
WM_msg_publish_rna_prop(mbus, &ob->id, vg, VertexGroup, name);
break;
@@ -746,7 +757,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
case TSE_EBONE: {
bArmature *arm = (bArmature *)tselem->id;
if (arm->edbo) {
- EditBone *ebone = te->directdata;
+ EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
char newname[sizeof(ebone->name)];
/* restore bone name */
@@ -754,7 +765,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
BLI_strncpy(ebone->name, oldname, sizeof(ebone->name));
ED_armature_bone_rename(bmain, arm, oldname, newname);
WM_msg_publish_rna_prop(mbus, &arm->id, ebone, EditBone, name);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
}
break;
}
@@ -764,7 +775,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
outliner_viewcontext_init(C, &tvc);
bArmature *arm = (bArmature *)tselem->id;
- Bone *bone = te->directdata;
+ Bone *bone = reinterpret_cast<Bone *>(te->directdata);
char newname[sizeof(bone->name)];
/* always make current object active */
@@ -775,7 +786,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
BLI_strncpy(bone->name, oldname, sizeof(bone->name));
ED_armature_bone_rename(bmain, arm, oldname, newname);
WM_msg_publish_rna_prop(mbus, &arm->id, bone, Bone, name);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
break;
}
case TSE_POSE_CHANNEL: {
@@ -784,7 +795,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
Object *ob = (Object *)tselem->id;
bArmature *arm = (bArmature *)ob->data;
- bPoseChannel *pchan = te->directdata;
+ bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
char newname[sizeof(pchan->name)];
/* always make current pose-bone active */
@@ -795,14 +806,15 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
/* restore bone name */
BLI_strncpy(newname, pchan->name, sizeof(pchan->name));
BLI_strncpy(pchan->name, oldname, sizeof(pchan->name));
- ED_armature_bone_rename(bmain, ob->data, oldname, newname);
+ ED_armature_bone_rename(
+ bmain, reinterpret_cast<bArmature *>(ob->data), oldname, newname);
WM_msg_publish_rna_prop(mbus, &arm->id, pchan->bone, Bone, name);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
break;
}
case TSE_POSEGRP: {
Object *ob = (Object *)tselem->id; /* id = object. */
- bActionGroup *grp = te->directdata;
+ bActionGroup *grp = reinterpret_cast<bActionGroup *>(te->directdata);
BLI_uniquename(&ob->pose->agroups,
grp,
@@ -816,7 +828,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
}
case TSE_GP_LAYER: {
bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */
- bGPDlayer *gpl = te->directdata;
+ bGPDlayer *gpl = reinterpret_cast<bGPDlayer *>(te->directdata);
/* always make layer active */
BKE_gpencil_layer_active_set(gpd, gpl);
@@ -832,7 +844,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
}
case TSE_R_LAYER: {
Scene *scene = (Scene *)tselem->id;
- ViewLayer *view_layer = te->directdata;
+ ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
/* Restore old name. */
char newname[sizeof(view_layer->name)];
@@ -842,7 +854,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
/* Rename, preserving animation and compositing data. */
BKE_view_layer_rename(bmain, scene, view_layer, newname);
WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, ViewLayer, name);
- WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr);
break;
}
case TSE_LAYER_COLLECTION: {
@@ -850,7 +862,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
Collection *collection = (Collection *)tselem->id;
BLI_libblock_ensure_unique_name(bmain, collection->id.name);
WM_msg_publish_rna_prop(mbus, &collection->id, &collection->id, ID, name);
- WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr);
break;
}
}
@@ -858,8 +870,9 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
tselem->flag &= ~TSE_TEXTBUT;
}
}
+}
-typedef struct RestrictProperties {
+struct RestrictProperties {
bool initialized;
PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render;
@@ -870,11 +883,11 @@ typedef struct RestrictProperties {
PropertyRNA *modifier_show_viewport, *modifier_show_render;
PropertyRNA *constraint_enable;
PropertyRNA *bone_hide_viewport;
-} RestrictProperties;
+};
/* We don't care about the value of the property
* but whether the property should be active or grayed out. */
-typedef struct RestrictPropertiesActive {
+struct RestrictPropertiesActive {
bool object_hide_viewport;
bool object_hide_select;
bool object_hide_render;
@@ -890,7 +903,7 @@ typedef struct RestrictPropertiesActive {
bool modifier_show_render;
bool constraint_enable;
bool bone_hide_viewport;
-} RestrictPropertiesActive;
+};
static void outliner_restrict_properties_enable_collection_set(
PointerRNA *collection_ptr, RestrictProperties *props, RestrictPropertiesActive *props_active)
@@ -982,8 +995,9 @@ static bool outliner_restrict_properties_collection_set(Scene *scene,
RestrictPropertiesActive *props_active)
{
TreeStoreElem *tselem = TREESTORE(te);
- LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? te->directdata :
- NULL;
+ LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ?
+ reinterpret_cast<LayerCollection *>(te->directdata) :
+ nullptr;
Collection *collection = outliner_collection_from_tree_element(te);
if (collection->flag & COLLECTION_IS_MASTER) {
@@ -992,7 +1006,7 @@ static bool outliner_restrict_properties_collection_set(Scene *scene,
/* Create the PointerRNA. */
RNA_id_pointer_create(&collection->id, collection_ptr);
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection, layer_collection_ptr);
}
@@ -1096,7 +1110,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) {
if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
/* View layer render toggle. */
- ViewLayer *layer = te->directdata;
+ ViewLayer *layer = reinterpret_cast<ViewLayer *>(te->directdata);
bt = uiDefIconButBitS(block,
UI_BTYPE_ICON_TOGGLE_N,
@@ -1113,7 +1127,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
0,
TIP_("Use view layer for rendering"));
- UI_but_func_set(bt, restrictbutton_r_lay_fn, tselem->id, NULL);
+ UI_but_func_set(bt, restrictbutton_r_lay_fn, tselem->id, nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
@@ -1256,7 +1270,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
-1,
-1,
- NULL);
+ nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
if (!props_active.constraint_enable) {
UI_but_flag_enable(bt, UI_BUT_INACTIVE);
@@ -1285,7 +1299,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
-1,
-1,
- NULL);
+ nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
if (!props_active.modifier_show_viewport) {
UI_but_flag_enable(bt, UI_BUT_INACTIVE);
@@ -1308,7 +1322,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
-1,
-1,
- NULL);
+ nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
if (!props_active.modifier_show_render) {
UI_but_flag_enable(bt, UI_BUT_INACTIVE);
@@ -1320,7 +1334,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
Bone *bone = pchan->bone;
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr);
@@ -1342,7 +1356,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
-1,
TIP_("Restrict visibility in the 3D View\n"
"* Shift to set children"));
- UI_but_func_set(bt, restrictbutton_bone_visibility_fn, bone, NULL);
+ UI_but_func_set(bt, restrictbutton_bone_visibility_fn, bone, nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
@@ -1470,11 +1484,12 @@ static void outliner_draw_restrictbuts(uiBlock *block,
scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active)) {
LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ?
- te->directdata :
- NULL;
+ reinterpret_cast<LayerCollection *>(
+ te->directdata) :
+ nullptr;
Collection *collection = outliner_collection_from_tree_element(te);
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
if (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) {
bt = uiDefIconButR_prop(block,
UI_BTYPE_ICON_TOGGLE,
@@ -1491,7 +1506,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
0,
0,
- NULL);
+ nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
}
@@ -1605,7 +1620,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
TIP_("Globally disable in viewports\n"
"* Ctrl to isolate collection\n"
"* Shift to set inside collections and objects"));
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
UI_but_func_set(bt,
view_layer__collection_set_flag_recursive_fn,
layer_collection,
@@ -1642,7 +1657,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
TIP_("Globally disable in renders\n"
"* Ctrl to isolate collection\n"
"* Shift to set inside collections and objects"));
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
UI_but_func_set(bt,
view_layer__collection_set_flag_recursive_fn,
layer_collection,
@@ -1677,7 +1692,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
TIP_("Disable selection in viewport\n"
"* Ctrl to isolate collection\n"
"* Shift to set inside collections and objects"));
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
UI_but_func_set(bt,
view_layer__collection_set_flag_recursive_fn,
layer_collection,
@@ -1721,7 +1736,7 @@ static void outliner_draw_userbuts(uiBlock *block,
if (tselem->type == TSE_SOME_ID) {
uiBut *bt;
ID *id = tselem->id;
- const char *tip = NULL;
+ const char *tip = nullptr;
char buf[16] = "";
int but_flag = UI_BUT_DRAG_LOCK;
@@ -1738,7 +1753,7 @@ static void outliner_draw_userbuts(uiBlock *block,
te->ys,
UI_UNIT_X,
UI_UNIT_Y,
- NULL,
+ nullptr,
0.0,
0.0,
0,
@@ -1767,7 +1782,7 @@ static void outliner_draw_userbuts(uiBlock *block,
0,
0,
tip);
- UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL);
+ UI_but_func_set(bt, restrictbutton_id_user_toggle, id, nullptr);
UI_but_flag_enable(bt, but_flag);
}
}
@@ -1791,7 +1806,7 @@ static bool outliner_draw_overrides_buts(uiBlock *block,
const bool do_draw = (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin &&
te->ys <= region->v2d.cur.ymax);
int but_flag = UI_BUT_DRAG_LOCK;
- const char *tip = NULL;
+ const char *tip = nullptr;
TreeStoreElem *tselem = TREESTORE(te);
switch (tselem->type) {
@@ -1838,19 +1853,23 @@ static bool outliner_draw_overrides_buts(uiBlock *block,
if (do_draw &&
(item_has_warnings || (any_child_has_warnings && !TSELEM_OPEN(tselem, space_outliner)))) {
- if (tip == NULL) {
+ if (tip == nullptr) {
tip = TIP_("Some sub-items require attention");
}
- uiBut *bt = uiDefIconBlockBut(block,
- NULL,
- NULL,
- 1,
- ICON_ERROR,
- (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_STATUS),
- te->ys,
- UI_UNIT_X,
- UI_UNIT_Y,
- tip);
+ uiBut *bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 1,
+ ICON_ERROR,
+ (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_STATUS),
+ te->ys,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ nullptr,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ tip);
UI_but_flag_enable(bt, but_flag);
}
any_item_has_warnings = any_item_has_warnings || item_has_warnings || any_child_has_warnings;
@@ -1898,7 +1917,7 @@ static void outliner_draw_rnabuts(
if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) {
if (tselem->type == TSE_RNA_PROPERTY) {
ptr = &te->rnaptr;
- prop = te->directdata;
+ prop = reinterpret_cast<PropertyRNA *>(te->directdata);
if (!TSELEM_OPEN(tselem, space_outliner)) {
if (RNA_property_type(prop) == PROP_POINTER) {
@@ -1919,7 +1938,7 @@ static void outliner_draw_rnabuts(
ptr,
prop,
-1,
- NULL,
+ nullptr,
ICON_NONE,
sizex,
te->ys,
@@ -1942,7 +1961,7 @@ static void outliner_draw_rnabuts(
}
else if (tselem->type == TSE_RNA_ARRAY_ELEM) {
ptr = &te->rnaptr;
- prop = te->directdata;
+ prop = reinterpret_cast<PropertyRNA *>(te->directdata);
uiDefAutoButR(block,
ptr,
@@ -1979,13 +1998,13 @@ static void outliner_buttons(const bContext *C,
/* If we add support to rename Sequence, need change this. */
if (tselem->type == TSE_EBONE) {
- len = sizeof(((EditBone *)0)->name);
+ len = sizeof(((EditBone *)nullptr)->name);
}
else if (tselem->type == TSE_MODIFIER) {
- len = sizeof(((ModifierData *)0)->name);
+ len = sizeof(((ModifierData *)nullptr)->name);
}
else if (tselem->id && GS(tselem->id->name) == ID_LI) {
- len = sizeof(((Library *)0)->filepath);
+ len = sizeof(((Library *)nullptr)->filepath);
}
else {
len = MAX_ID_NAME - 2;
@@ -2015,7 +2034,7 @@ static void outliner_buttons(const bContext *C,
tselem->flag &= ~TSE_TEXTBUT;
/* Bad! (notifier within draw) without this, we don't get a refresh. */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr);
}
}
@@ -2032,7 +2051,7 @@ static void outliner_mode_toggle_fn(bContext *C, void *tselem_poin, void *UNUSED
}
/* Check that the item is actually an object. */
- BLI_assert(tselem->id != NULL && GS(tselem->id->name) == ID_OB);
+ BLI_assert(tselem->id != nullptr && GS(tselem->id->name) == ID_OB);
Object *ob = (Object *)tselem->id;
const bool object_data_shared = (ob->data == tvc.obact->data);
@@ -2101,13 +2120,13 @@ static void outliner_draw_mode_column_toggle(uiBlock *block,
te->ys,
UI_UNIT_X,
UI_UNIT_Y,
- NULL,
+ nullptr,
0.0,
0.0,
0.0,
0.0,
tip);
- UI_but_func_set(but, outliner_mode_toggle_fn, tselem, NULL);
+ UI_but_func_set(but, outliner_mode_toggle_fn, tselem, nullptr);
UI_but_flag_enable(but, UI_BUT_DRAG_LOCK);
/* Mode toggling handles its own undo state because undo steps need to be grouped. */
UI_but_flag_disable(but, UI_BUT_UNDO);
@@ -2139,12 +2158,86 @@ static void outliner_draw_mode_column(const bContext *C,
}
}
+/* Returns `true` if some warning was drawn for that element or one of its sub-elements (if it is
+ * not open). */
+static bool outliner_draw_warning_tree_element(uiBlock *block,
+ SpaceOutliner *space_outliner,
+ TreeElement *te,
+ TreeStoreElem *tselem,
+ const bool use_mode_column,
+ const int te_ys)
+{
+ if ((te->flag & TE_HAS_WARNING) == 0) {
+ /* If given element has no warning, recursively try to display the first sub-elements' warning.
+ */
+ if (!TSELEM_OPEN(tselem, space_outliner)) {
+ LISTBASE_FOREACH (TreeElement *, sub_te, &te->subtree) {
+ TreeStoreElem *sub_tselem = TREESTORE(sub_te);
+
+ if (outliner_draw_warning_tree_element(
+ block, space_outliner, sub_te, sub_tselem, use_mode_column, te_ys)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ int icon = ICON_NONE;
+ const char *tip = "";
+ const bool has_warning = tree_element_warnings_get(te, &icon, &tip);
+ BLI_assert(has_warning);
+ UNUSED_VARS_NDEBUG(has_warning);
+
+ /* Move the warnings a unit left in view layer mode. */
+ const short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
+ UI_UNIT_X :
+ 0;
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS);
+ uiBut *but = uiDefIconBut(block,
+ UI_BTYPE_ICON_TOGGLE,
+ 0,
+ icon,
+ mode_column_offset,
+ te_ys,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ nullptr,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ tip);
+ /* No need for undo here, this is a pure info widget. */
+ UI_but_flag_disable(but, UI_BUT_UNDO);
+
+ return true;
+}
+
+static void outliner_draw_warning_column(const bContext *C,
+ uiBlock *block,
+ SpaceOutliner *space_outliner,
+ const bool use_mode_column,
+ ListBase *tree)
+{
+ LISTBASE_FOREACH (TreeElement *, te, tree) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ outliner_draw_warning_tree_element(block, space_outliner, te, tselem, use_mode_column, te->ys);
+
+ if (TSELEM_OPEN(tselem, space_outliner)) {
+ outliner_draw_warning_column(C, block, space_outliner, use_mode_column, &te->subtree);
+ }
+ }
+}
+
/* ****************************************************** */
/* Normal Drawing... */
TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
{
- TreeElementIcon data = {0};
+ TreeElementIcon data = {nullptr};
if (tselem->type != TSE_SOME_ID) {
switch (tselem->type) {
@@ -2178,7 +2271,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
data.drag_id = tselem->id;
break;
case TSE_CONSTRAINT: {
- bConstraint *con = te->directdata;
+ bConstraint *con = reinterpret_cast<bConstraint *>(te->directdata);
data.drag_id = tselem->id;
switch ((eBConstraint_Types)con->type) {
case CONSTRAINT_TYPE_CAMERASOLVER:
@@ -2291,9 +2384,11 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
data.drag_id = tselem->id;
if (ob->type != OB_GPENCIL) {
- ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr);
- const ModifierTypeInfo *modifier_type = BKE_modifier_get_info(md->type);
- if (modifier_type != NULL) {
+ ModifierData *md = reinterpret_cast<ModifierData *>(
+ BLI_findlink(&ob->modifiers, tselem->nr));
+ const ModifierTypeInfo *modifier_type = reinterpret_cast<const ModifierTypeInfo *>(
+ BKE_modifier_get_info((ModifierType)md->type));
+ if (modifier_type != nullptr) {
data.icon = modifier_type->icon;
}
else {
@@ -2302,7 +2397,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
}
else {
/* grease pencil modifiers */
- GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, tselem->nr);
+ GpencilModifierData *md = reinterpret_cast<GpencilModifierData *>(
+ BLI_findlink(&ob->greasepencil_modifiers, tselem->nr));
switch ((GpencilModifierType)md->type) {
case eGpencilModifierType_Noise:
data.icon = ICON_MOD_NOISE;
@@ -2364,6 +2460,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case eGpencilModifierType_WeightAngle:
data.icon = ICON_MOD_VERTEX_WEIGHT;
break;
+ case eGpencilModifierType_Shrinkwrap:
+ data.icon = ICON_MOD_SHRINKWRAP;
+ break;
/* Default */
default:
@@ -2470,7 +2569,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
Collection *collection = outliner_collection_from_tree_element(te);
if (collection && !(collection->flag & COLLECTION_IS_MASTER)) {
data.drag_id = tselem->id;
- data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL;
+ data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : nullptr;
}
data.icon = ICON_OUTLINER_COLLECTION;
@@ -2492,7 +2591,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
}
else if (tselem->id) {
data.drag_id = tselem->id;
- data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL;
+ data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : nullptr;
if (GS(tselem->id->name) == ID_OB) {
Object *ob = (Object *)tselem->id;
@@ -2632,7 +2731,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
break;
case ID_TXT: {
Text *text = (Text *)tselem->id;
- if (text->filepath == NULL || (text->flags & TXT_ISMEM)) {
+ if (text->filepath == nullptr || (text->flags & TXT_ISMEM)) {
data.icon = ICON_FILE_TEXT;
}
else {
@@ -2765,7 +2864,7 @@ static void tselem_draw_icon(uiBlock *block,
UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true);
}
else {
- UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, NULL, false);
+ UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false);
}
}
else {
@@ -2777,7 +2876,7 @@ static void tselem_draw_icon(uiBlock *block,
y,
UI_UNIT_X,
UI_UNIT_Y,
- NULL,
+ nullptr,
0.0,
0.0,
1.0,
@@ -2798,18 +2897,15 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle,
const float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
float ufac = 0.25f * UI_UNIT_X;
float offset_x = (float)offsx + UI_UNIT_X * 0.35f;
+ rctf rect{};
+ BLI_rctf_init(&rect,
+ offset_x + ufac,
+ offset_x + UI_UNIT_X - ufac,
+ (float)ys - UI_UNIT_Y * 0.2f + ufac,
+ (float)ys - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(
- &(const rctf){
- .xmin = offset_x + ufac,
- .xmax = offset_x + UI_UNIT_X - ufac,
- .ymin = (float)ys - UI_UNIT_Y * 0.2f + ufac,
- .ymax = (float)ys - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac,
- },
- true,
- (float)UI_UNIT_Y / 2.0f - ufac,
- color);
+ UI_draw_roundbox_aa(&rect, true, (float)UI_UNIT_Y / 2.0f - ufac, color);
/* Now the numbers. */
uchar text_col[4];
@@ -2822,7 +2918,7 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle,
/* We treat +99 as 4 digits to make sure the (eyeballed) alignment looks nice. */
int num_digits = 4;
- char number_text[4] = "+99\0";
+ char number_text[4] = "+99";
if (num_elements < 100) {
BLI_snprintf(number_text, sizeof(number_text), "%d", num_elements);
num_digits = num_elements < 10 ? 1 : 2;
@@ -2857,28 +2953,12 @@ static void outliner_draw_active_indicator(const float minx,
{
const float ufac = UI_UNIT_X / 20.0f;
const float radius = UI_UNIT_Y / 4.0f;
+ rctf rect{};
+ BLI_rctf_init(&rect, minx, maxx, miny + ufac, maxy - ufac);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(
- &(const rctf){
- .xmin = minx,
- .xmax = maxx,
- .ymin = miny + ufac,
- .ymax = maxy - ufac,
- },
- true,
- radius,
- icon_color);
- UI_draw_roundbox_aa(
- &(const rctf){
- .xmin = minx,
- .xmax = maxx,
- .ymin = miny + ufac,
- .ymax = maxy - ufac,
- },
- false,
- radius,
- icon_border);
+ UI_draw_roundbox_aa(&rect, true, radius, icon_color);
+ UI_draw_roundbox_aa(&rect, false, radius, icon_border);
GPU_blend(GPU_BLEND_ALPHA); /* Roundbox disables. */
}
@@ -2929,12 +3009,6 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
(*offsx) += UI_UNIT_X;
}
-/**
- * Return the index to use based on the TreeElement ID and object type
- *
- * We use a continuum of indices until we get to the object data-blocks
- * and we then make room for the object types.
- */
int tree_element_id_type_to_index(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
@@ -2951,11 +3025,11 @@ int tree_element_id_type_to_index(TreeElement *te)
return id_index + OB_TYPE_MAX;
}
-typedef struct MergedIconRow {
+struct MergedIconRow {
eOLDrawState active[INDEX_ID_MAX + OB_TYPE_MAX];
int num_elements[INDEX_ID_MAX + OB_TYPE_MAX];
TreeElement *tree_element[INDEX_ID_MAX + OB_TYPE_MAX];
-} MergedIconRow;
+};
static void outliner_draw_iconrow(bContext *C,
uiBlock *block,
@@ -3013,7 +3087,7 @@ static void outliner_draw_iconrow(bContext *C,
else {
const int index = tree_element_id_type_to_index(te);
merged->num_elements[index]++;
- if ((merged->tree_element[index] == NULL) || (active > merged->active[index])) {
+ if ((merged->tree_element[index] == nullptr) || (active > merged->active[index])) {
merged->tree_element[index] = te;
}
merged->active[index] = MAX2(active, merged->active[index]);
@@ -3090,7 +3164,7 @@ static bool element_should_draw_faded(const TreeViewContext *tvc,
const Base *base = (te->directdata) ? (const Base *)te->directdata :
BKE_view_layer_base_find(
(ViewLayer *)tvc->view_layer, (Object *)ob);
- const bool is_visible = (base != NULL) && (base->flag & BASE_VISIBLE_VIEWLAYER);
+ const bool is_visible = (base != nullptr) && (base->flag & BASE_VISIBLE_VIEWLAYER);
if (!is_visible) {
return true;
}
@@ -3139,7 +3213,7 @@ static void outliner_draw_tree_element(bContext *C,
const float alpha_fac = element_should_draw_faded(tvc, te, tselem) ? 0.5f : 1.0f;
int xmax = region->v2d.cur.xmax;
- if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) {
+ if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == nullptr)) {
*te_edit = te;
}
@@ -3156,7 +3230,7 @@ static void outliner_draw_tree_element(bContext *C,
Object *ob = (Object *)tselem->id;
Base *base = (te->directdata) ? (Base *)te->directdata :
BKE_view_layer_base_find(tvc->view_layer, ob);
- const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0);
+ const bool is_selected = (base != nullptr) && ((base->flag & BASE_SELECTED) != 0);
if (ob == tvc->obact) {
active = OL_DRAWSEL_ACTIVE;
@@ -3247,7 +3321,7 @@ static void outliner_draw_tree_element(bContext *C,
if (ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION) ||
((tselem->type == TSE_RNA_STRUCT) && RNA_struct_is_ID(te->rnaptr.type))) {
- const BIFIconID lib_icon = UI_icon_from_library(tselem->id);
+ const BIFIconID lib_icon = (BIFIconID)UI_icon_from_library(tselem->id);
if (lib_icon != ICON_NONE) {
UI_icon_draw_alpha(
(float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, lib_icon, alpha_fac);
@@ -3280,7 +3354,7 @@ static void outliner_draw_tree_element(bContext *C,
GPU_blend(GPU_BLEND_ALPHA);
- MergedIconRow merged = {{0}};
+ MergedIconRow merged{};
outliner_draw_iconrow(C,
block,
fstyle,
@@ -3351,7 +3425,7 @@ static void outliner_draw_hierarchy_line(
/* Small vertical padding. */
const short line_padding = UI_UNIT_Y / 4.0f;
- /* >= is 1.0 for undashed lines. */
+ /* >= is 1.0 for un-dashed lines. */
immUniform1f("dash_factor", draw_dashed ? 0.5f : 1.0f);
immBegin(GPU_PRIM_LINES, 2);
@@ -3611,17 +3685,22 @@ static void outliner_draw_tree(bContext *C,
SpaceOutliner *space_outliner,
const float restrict_column_width,
const bool use_mode_column,
+ const bool use_warning_column,
TreeElement **te_edit)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
int starty, startx;
/* Move the tree a unit left in view layer mode */
- short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
- UI_UNIT_X :
- 0;
+ short columns_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
+ UI_UNIT_X :
+ 0;
if (!use_mode_column && (space_outliner->outlinevis == SO_VIEW_LAYER)) {
- mode_column_offset -= UI_UNIT_X;
+ columns_offset -= UI_UNIT_X;
+ }
+
+ if (use_warning_column) {
+ columns_offset += UI_UNIT_X;
}
GPU_blend(GPU_BLEND_ALPHA); /* Only once. */
@@ -3649,12 +3728,12 @@ static void outliner_draw_tree(bContext *C,
/* Draw hierarchy lines for collections and object children. */
starty = (int)region->v2d.tot.ymax - OL_Y_OFFSET;
- startx = mode_column_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
+ startx = columns_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
outliner_draw_hierarchy_lines(space_outliner, &space_outliner->tree, startx, &starty);
/* Items themselves. */
starty = (int)region->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
- startx = mode_column_offset;
+ startx = columns_offset;
LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
outliner_draw_tree_element(C,
block,
@@ -3754,7 +3833,7 @@ void draw_outliner(const bContext *C)
View2D *v2d = &region->v2d;
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
uiBlock *block;
- TreeElement *te_edit = NULL;
+ TreeElement *te_edit = nullptr;
TreeViewContext tvc;
outliner_viewcontext_init(C, &tvc);
@@ -3785,6 +3864,11 @@ void draw_outliner(const bContext *C)
const bool use_mode_column = (space_outliner->flag & SO_MODE_COLUMN) &&
(ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES));
+ const bool use_warning_column = ELEM(space_outliner->outlinevis,
+ SO_LIBRARIES,
+ SO_OVERRIDES_LIBRARY) &&
+ space_outliner->runtime->tree_display->hasWarnings();
+
/* Draw outliner stuff (background, hierarchy lines and names). */
const float restrict_column_width = outliner_restrict_columns_width(space_outliner);
outliner_back(region);
@@ -3796,6 +3880,7 @@ void draw_outliner(const bContext *C)
space_outliner,
restrict_column_width,
use_mode_column,
+ use_warning_column,
&te_edit);
/* Compute outliner dimensions after it has been drawn. */
@@ -3840,6 +3925,11 @@ void draw_outliner(const bContext *C)
outliner_draw_mode_column(C, block, &tvc, space_outliner, &space_outliner->tree);
}
+ /* Draw warning icons */
+ if (use_warning_column) {
+ outliner_draw_warning_column(C, block, space_outliner, use_mode_column, &space_outliner->tree);
+ }
+
UI_block_emboss_set(block, UI_EMBOSS);
/* Draw edit buttons if necessary. */
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.cc
index 738db28a2b6..a10dbc94b34 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <string.h>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -38,6 +38,7 @@
#include "BLT_translation.h"
+#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_appdir.h"
#include "BKE_armature.h"
@@ -48,6 +49,7 @@
#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
#include "BKE_main.h"
+#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_workspace.h"
@@ -71,15 +73,13 @@
#include "GPU_material.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
static void outliner_show_active(SpaceOutliner *space_outliner,
ARegion *region,
TreeElement *te,
ID *id);
-/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Highlight on Cursor Motion Operator
* \{ */
@@ -107,11 +107,11 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const
TreeElement *hovered_te = outliner_find_item_at_y(
space_outliner, &space_outliner->tree, view_mval[1]);
- TreeElement *icon_te = NULL;
+ TreeElement *icon_te = nullptr;
bool is_over_icon = false;
if (hovered_te) {
icon_te = outliner_find_item_at_x_in_row(
- space_outliner, hovered_te, view_mval[0], NULL, &is_over_icon);
+ space_outliner, hovered_te, view_mval[0], nullptr, &is_over_icon);
}
bool changed = false;
@@ -154,9 +154,6 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot)
/** \name Toggle Open/Closed Operator
* \{ */
-/**
- * Open or close a tree element, optionally toggling all children recursively.
- */
void outliner_item_openclose(SpaceOutliner *space_outliner,
TreeElement *te,
bool open,
@@ -186,11 +183,11 @@ void outliner_item_openclose(SpaceOutliner *space_outliner,
}
}
-typedef struct OpenCloseData {
+struct OpenCloseData {
TreeStoreElem *prev_tselem;
bool open;
int x_location;
-} OpenCloseData;
+};
static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -221,7 +218,7 @@ static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEv
data->prev_tselem = TREESTORE(te);
}
else {
- data->prev_tselem = NULL;
+ data->prev_tselem = nullptr;
}
}
else if (event->val == KM_RELEASE) {
@@ -261,7 +258,7 @@ static int outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmE
}
/* Store last expanded tselem and x coordinate of disclosure triangle */
- OpenCloseData *toggle_data = MEM_callocN(sizeof(OpenCloseData), "open_close_data");
+ OpenCloseData *toggle_data = MEM_cnew<OpenCloseData>("open_close_data");
toggle_data->prev_tselem = tselem;
toggle_data->open = open;
toggle_data->x_location = te->xs;
@@ -378,7 +375,7 @@ static TreeElement *outliner_item_rename_find_active(const SpaceOutliner *space_
if (!active_element) {
BKE_report(reports, RPT_WARNING, "No active item to rename");
- return NULL;
+ return nullptr;
}
return active_element;
@@ -396,7 +393,7 @@ static TreeElement *outliner_item_rename_find_hovered(const SpaceOutliner *space
return hovered;
}
- return NULL;
+ return nullptr;
}
static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *event)
@@ -455,12 +452,12 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
Main *bmain = CTX_data_main(C);
ID *id = tselem->id;
- BLI_assert(id != NULL);
+ BLI_assert(id != nullptr);
BLI_assert(((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
(tselem->type == TSE_LAYER_COLLECTION));
UNUSED_VARS_NDEBUG(te);
- if (te->idcode == ID_LI && ((Library *)id)->parent != NULL) {
+ if (te->idcode == ID_LI && ((Library *)id)->parent != nullptr) {
BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked library '%s'", id->name);
return;
}
@@ -486,7 +483,7 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
BKE_id_delete(bmain, id);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
void id_delete_fn(bContext *C,
@@ -578,13 +575,13 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
const short id_type = (short)RNA_enum_get(op->ptr, "id_type");
- ID *old_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type),
- RNA_enum_get(op->ptr, "old_id"));
- ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type),
- RNA_enum_get(op->ptr, "new_id"));
+ ID *old_id = reinterpret_cast<ID *>(
+ BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id")));
+ ID *new_id = reinterpret_cast<ID *>(
+ BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id")));
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -617,7 +614,7 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op)
* such as lights so freeing correctly refreshes. */
GPU_materials_free(bmain);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
return OPERATOR_FINISHED;
}
@@ -632,8 +629,6 @@ static bool outliner_id_remap_find_tree_element(bContext *C,
TreeStoreElem *tselem = TREESTORE(te);
if ((tselem->type == TSE_SOME_ID) && tselem->id) {
- printf("found id %s (%p)!\n", tselem->id->name, tselem->id);
-
RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name));
RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2);
RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2);
@@ -659,7 +654,7 @@ static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent *
outliner_id_remap_find_tree_element(C, op, &space_outliner->tree, fmval[1]);
}
- return WM_operator_props_dialog_popup(C, op, 200);
+ return WM_operator_props_dialog_popup(C, op, 400);
}
static const EnumPropertyItem *outliner_id_itemf(bContext *C,
@@ -667,18 +662,18 @@ static const EnumPropertyItem *outliner_id_itemf(bContext *C,
PropertyRNA *UNUSED(prop),
bool *r_free)
{
- if (C == NULL) {
+ if (C == nullptr) {
return DummyRNA_NULL_items;
}
- EnumPropertyItem item_tmp = {0}, *item = NULL;
+ EnumPropertyItem item_tmp = {0}, *item = nullptr;
int totitem = 0;
int i = 0;
short id_type = (short)RNA_enum_get(ptr, "id_type");
- ID *id = which_libbase(CTX_data_main(C), id_type)->first;
+ ID *id = reinterpret_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first);
- for (; id; id = id->next) {
+ for (; id; id = reinterpret_cast<ID *>(id->next)) {
item_tmp.identifier = item_tmp.name = id->name + 2;
item_tmp.value = i++;
RNA_enum_item_add(&item, &totitem, &item_tmp);
@@ -708,10 +703,13 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
+ /* Changing ID type wont make sense, would return early with "Invalid old/new ID pair" anyways.
+ */
+ RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace");
- RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN);
+ RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, outliner_id_itemf);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN));
ot->prop = RNA_def_enum(ot->srna,
"new_id",
@@ -719,7 +717,7 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
0,
"New ID",
"New ID to remap all selected IDs' users to");
- RNA_def_property_enum_funcs_runtime(ot->prop, NULL, NULL, outliner_id_itemf);
+ RNA_def_property_enum_funcs_runtime(ot->prop, nullptr, nullptr, outliner_id_itemf);
RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE);
}
@@ -734,7 +732,7 @@ void id_remap_fn(bContext *C,
wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false);
PointerRNA op_props;
- BLI_assert(tselem->id != NULL);
+ BLI_assert(tselem->id != nullptr);
WM_operator_properties_create_ptr(&op_props, ot);
@@ -763,7 +761,7 @@ static int outliner_id_copy_tag(SpaceOutliner *space_outliner, ListBase *tree)
if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) {
ID *id = tselem->id;
if (!(id->tag & LIB_TAG_DOIT)) {
- BKE_copybuffer_tag_ID(tselem->id);
+ BKE_copybuffer_copy_tag_ID(tselem->id);
num_ids++;
}
}
@@ -781,7 +779,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
char str[FILE_MAX];
- BKE_copybuffer_begin(bmain);
+ BKE_copybuffer_copy_begin(bmain);
const int num_ids = outliner_id_copy_tag(space_outliner, &space_outliner->tree);
if (num_ids == 0) {
@@ -790,7 +788,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op)
}
BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
- BKE_copybuffer_save(bmain, str, op->reports);
+ BKE_copybuffer_copy_end(bmain, str, op->reports);
BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids);
@@ -831,7 +829,7 @@ static int outliner_id_paste_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
BKE_reportf(op->reports, RPT_INFO, "%d data-block(s) pasted", num_pasted);
@@ -865,7 +863,7 @@ static int lib_relocate(
PointerRNA op_props;
int ret = 0;
- BLI_assert(te->idcode == ID_LI && tselem->id != NULL);
+ BLI_assert(te->idcode == ID_LI && tselem->id != nullptr);
UNUSED_VARS_NDEBUG(te);
WM_operator_properties_create_ptr(&op_props, ot);
@@ -964,9 +962,6 @@ void OUTLINER_OT_lib_relocate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* XXX This does not work with several items
- * (it is only called once in the end, due to the 'deferred'
- * file-browser invocation through event system...). */
void lib_relocate_fn(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
@@ -975,6 +970,10 @@ void lib_relocate_fn(bContext *C,
TreeStoreElem *tselem,
void *UNUSED(user_data))
{
+ /* XXX: This does not work with several items
+ * (it is only called once in the end, due to the 'deferred'
+ * file-browser invocation through event system...). */
+
wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_relocate", false);
lib_relocate(C, te, tselem, ot, false);
@@ -1068,10 +1067,6 @@ int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel)
return 0;
}
-/**
- * Set or unset \a flag for all outliner elements in \a lb and sub-trees.
- * \return if any flag was modified.
- */
bool outliner_flag_set(ListBase *lb, short flag, short set)
{
bool changed = false;
@@ -1225,7 +1220,6 @@ static void outliner_set_coordinates_element_recursive(SpaceOutliner *space_outl
}
}
-/* to retrieve coordinates with redrawing the entire tree */
void outliner_set_coordinates(ARegion *region, SpaceOutliner *space_outliner)
{
int starty = (int)(region->v2d.tot.ymax) - UI_UNIT_Y;
@@ -1261,17 +1255,18 @@ static TreeElement *outliner_show_active_get_element(bContext *C,
Object *obact = OBACT(view_layer);
if (!obact) {
- return NULL;
+ return nullptr;
}
te = outliner_find_id(space_outliner, &space_outliner->tree, &obact->id);
- if (te != NULL && obact->type == OB_ARMATURE) {
+ if (te != nullptr && obact->type == OB_ARMATURE) {
/* traverse down the bone hierarchy in case of armature */
TreeElement *te_obact = te;
if (obact->mode & OB_MODE_POSE) {
- bPoseChannel *pchan = CTX_data_active_pose_bone(C);
+ Object *obpose = BKE_object_pose_armature_get(obact);
+ bPoseChannel *pchan = BKE_pose_channel_active(obpose, false);
if (pchan) {
te = outliner_find_posechannel(&te_obact->subtree, pchan);
}
@@ -1394,7 +1389,7 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
/* properties */
- prop = RNA_def_boolean(ot->srna, "up", 0, "Up", "Scroll up one page");
+ prop = RNA_def_boolean(ot->srna, "up", false, "Up", "Scroll up one page");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -1438,14 +1433,14 @@ static TreeElement *outliner_find_name(
}
/* nothing valid found */
- return NULL;
+ return nullptr;
}
static void outliner_find_panel(
Scene *UNUSED(scene), ARegion *region, SpaceOutliner *space_outliner, int again, int flags)
{
- ReportList *reports = NULL; /* CTX_wm_reports(C); */
- TreeElement *te = NULL;
+ ReportList *reports = nullptr; /* CTX_wm_reports(C); */
+ TreeElement *te = nullptr;
TreeElement *last_find;
TreeStoreElem *tselem;
int ytop, xdelta, prevFound = 0;
@@ -1462,7 +1457,7 @@ static void outliner_find_panel(
/* try to find matching element */
te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, last_find, &prevFound);
- if (te == NULL) {
+ if (te == nullptr) {
/* no more matches after previous, start from beginning again */
prevFound = 1;
te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, last_find, &prevFound);
@@ -1471,10 +1466,10 @@ static void outliner_find_panel(
else {
/* pop up panel - no previous, or user didn't want search after previous */
name[0] = '\0';
- /* XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) { */
- /* te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, NULL, &prevFound); */
- /* } */
- /* else return; XXX RETURN! XXX */
+ // XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) {
+ // te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, nullptr, &prevFound);
+ // }
+ // else return; XXX RETURN! XXX
}
/* do selection and reveal */
@@ -1490,7 +1485,7 @@ static void outliner_find_panel(
outliner_flag_set(space_outliner, &space_outliner->tree, TSE_SELECTED, 0);
tselem->flag |= TSE_SELECTED;
- /* make te->ys center of view */
+ /* Make `te->ys` center of view. */
ytop = (int)(te->ys + BLI_rctf_size_y(&region->v2d.mask) / 2);
if (ytop > 0) {
ytop = 0;
@@ -1498,7 +1493,7 @@ static void outliner_find_panel(
region->v2d.cur.ymax = (float)ytop;
region->v2d.cur.ymin = (float)(ytop - BLI_rctf_size_y(&region->v2d.mask));
- /* make te->xs ==> te->xend center of view */
+ /* Make `te->xs` ==> `te->xend` center of view. */
xdelta = (int)(te->xs - region->v2d.cur.xmin);
region->v2d.cur.xmin += xdelta;
region->v2d.cur.xmax += xdelta;
@@ -1591,7 +1586,7 @@ void OUTLINER_OT_show_one_level(wmOperatorType *ot)
/* no undo or registry, UI option */
/* properties */
- prop = RNA_def_boolean(ot->srna, "open", 1, "Open", "Expand all entries one level deep");
+ prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Expand all entries one level deep");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -1703,7 +1698,7 @@ static bool ed_operator_outliner_datablocks_active(bContext *C)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
return (space_outliner->outlinevis == SO_DATA_API);
}
- return 0;
+ return false;
}
/* Helper func to extract an RNA path from selected tree element
@@ -1718,13 +1713,13 @@ static void tree_element_to_path(TreeElement *te,
short *flag,
short *UNUSED(groupmode))
{
- ListBase hierarchy = {NULL, NULL};
+ ListBase hierarchy = {nullptr, nullptr};
LinkData *ld;
TreeElement *tem, *temnext;
TreeStoreElem *tse /* , *tsenext */ /* UNUSED */;
PointerRNA *ptr, *nextptr;
PropertyRNA *prop;
- char *newpath = NULL;
+ char *newpath = nullptr;
/* optimize tricks:
* - Don't do anything if the selected item is a 'struct', but arrays are allowed
@@ -1744,19 +1739,19 @@ static void tree_element_to_path(TreeElement *te,
/* step 1: flatten out hierarchy of parents into a flat chain */
for (tem = te->parent; tem; tem = tem->parent) {
- ld = MEM_callocN(sizeof(LinkData), "LinkData for tree_element_to_path()");
+ ld = MEM_cnew<LinkData>("LinkData for tree_element_to_path()");
ld->data = tem;
BLI_addhead(&hierarchy, ld);
}
/* step 2: step down hierarchy building the path
* (NOTE: addhead in previous loop was needed so that we can loop like this) */
- for (ld = hierarchy.first; ld; ld = ld->next) {
+ for (ld = reinterpret_cast<LinkData *>(hierarchy.first); ld; ld = ld->next) {
/* get data */
tem = (TreeElement *)ld->data;
tse = TREESTORE(tem);
ptr = &tem->rnaptr;
- prop = tem->directdata;
+ prop = reinterpret_cast<PropertyRNA *>(tem->directdata);
/* check if we're looking for first ID, or appending to path */
if (*id) {
@@ -1767,7 +1762,7 @@ static void tree_element_to_path(TreeElement *te,
if (tse->type == TSE_RNA_PROPERTY) {
if (RNA_property_type(prop) == PROP_POINTER) {
/* for pointer we just append property name */
- newpath = RNA_path_append(*path, ptr, prop, 0, NULL);
+ newpath = RNA_path_append(*path, ptr, prop, 0, nullptr);
}
else if (RNA_property_type(prop) == PROP_COLLECTION) {
char buf[128], *name;
@@ -1776,11 +1771,11 @@ static void tree_element_to_path(TreeElement *te,
// tsenext = TREESTORE(temnext); /* UNUSED */
nextptr = &temnext->rnaptr;
- name = RNA_struct_name_get_alloc(nextptr, buf, sizeof(buf), NULL);
+ name = RNA_struct_name_get_alloc(nextptr, buf, sizeof(buf), nullptr);
if (name) {
/* if possible, use name as a key in the path */
- newpath = RNA_path_append(*path, NULL, prop, 0, name);
+ newpath = RNA_path_append(*path, nullptr, prop, 0, name);
if (name != buf) {
MEM_freeN(name);
@@ -1795,7 +1790,7 @@ static void tree_element_to_path(TreeElement *te,
break;
}
}
- newpath = RNA_path_append(*path, NULL, prop, index, NULL);
+ newpath = RNA_path_append(*path, nullptr, prop, index, nullptr);
}
ld = ld->next;
@@ -1807,7 +1802,7 @@ static void tree_element_to_path(TreeElement *te,
MEM_freeN(*path);
}
*path = newpath;
- newpath = NULL;
+ newpath = nullptr;
}
}
else {
@@ -1817,12 +1812,12 @@ static void tree_element_to_path(TreeElement *te,
/* ptr->data not ptr->owner_id seems to be the one we want,
* since ptr->data is sometimes the owner of this ID? */
if (RNA_struct_is_ID(ptr->type)) {
- *id = ptr->data;
+ *id = reinterpret_cast<ID *>(ptr->data);
/* clear path */
if (*path) {
MEM_freeN(*path);
- path = NULL;
+ path = nullptr;
}
}
}
@@ -1833,7 +1828,7 @@ static void tree_element_to_path(TreeElement *te,
if (*id) {
/* add the active property to the path */
ptr = &te->rnaptr;
- prop = te->directdata;
+ prop = reinterpret_cast<PropertyRNA *>(te->directdata);
/* array checks */
if (tselem->type == TSE_RNA_ARRAY_ELEM) {
@@ -1846,7 +1841,7 @@ static void tree_element_to_path(TreeElement *te,
}
/* path */
- newpath = RNA_path_append(*path, NULL, prop, 0, NULL);
+ newpath = RNA_path_append(*path, nullptr, prop, 0, nullptr);
if (*path) {
MEM_freeN(*path);
}
@@ -1885,15 +1880,15 @@ static void do_outliner_drivers_editop(SpaceOutliner *space_outliner,
/* if item is selected, perform operation */
if (tselem->flag & TSE_SELECTED) {
- ID *id = NULL;
- char *path = NULL;
+ ID *id = nullptr;
+ char *path = nullptr;
int array_index = 0;
short flag = 0;
short groupmode = KSP_GROUP_KSNAME;
/* check if RNA-property described by this selected element is an animatable prop */
if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) &&
- RNA_property_animateable(&te->rnaptr, te->directdata)) {
+ RNA_property_animateable(&te->rnaptr, reinterpret_cast<PropertyRNA *>(te->directdata))) {
/* get id + path + index info from the selected element */
tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
}
@@ -1906,7 +1901,8 @@ static void do_outliner_drivers_editop(SpaceOutliner *space_outliner,
/* array checks */
if (flag & KSP_FLAG_WHOLE_ARRAY) {
/* entire array was selected, so add drivers for all */
- arraylen = RNA_property_array_length(&te->rnaptr, te->directdata);
+ arraylen = RNA_property_array_length(&te->rnaptr,
+ reinterpret_cast<PropertyRNA *>(te->directdata));
}
else {
arraylen = array_index;
@@ -1957,7 +1953,7 @@ static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -1966,7 +1962,7 @@ static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op)
space_outliner, &space_outliner->tree, op->reports, DRIVERS_EDITMODE_ADD);
/* send notifiers */
- WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); /* XXX */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, nullptr); /* XXX */
return OPERATOR_FINISHED;
}
@@ -1997,7 +1993,7 @@ static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2006,7 +2002,7 @@ static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op)
space_outliner, &space_outliner->tree, op->reports, DRIVERS_EDITMODE_REMOVE);
/* send notifiers */
- WM_event_add_notifier(C, ND_KEYS, NULL); /* XXX */
+ WM_event_add_notifier(C, ND_KEYS, nullptr); /* XXX */
return OPERATOR_FINISHED;
}
@@ -2047,22 +2043,23 @@ enum {
/* TODO: should this be an API func? */
static KeyingSet *verify_active_keyingset(Scene *scene, short add)
{
- KeyingSet *ks = NULL;
+ KeyingSet *ks = nullptr;
/* sanity check */
- if (scene == NULL) {
- return NULL;
+ if (scene == nullptr) {
+ return nullptr;
}
/* try to find one from scene */
if (scene->active_keyingset > 0) {
- ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1);
+ ks = reinterpret_cast<KeyingSet *>(
+ BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1));
}
/* Add if none found */
/* XXX the default settings have yet to evolve. */
- if ((add) && (ks == NULL)) {
- ks = BKE_keyingset_add(&scene->keyingsets, NULL, NULL, KEYINGSET_ABSOLUTE, 0);
+ if ((add) && (ks == nullptr)) {
+ ks = BKE_keyingset_add(&scene->keyingsets, nullptr, nullptr, KEYINGSET_ABSOLUTE, 0);
scene->active_keyingset = BLI_listbase_count(&scene->keyingsets);
}
@@ -2080,15 +2077,15 @@ static void do_outliner_keyingset_editop(SpaceOutliner *space_outliner,
/* if item is selected, perform operation */
if (tselem->flag & TSE_SELECTED) {
- ID *id = NULL;
- char *path = NULL;
+ ID *id = nullptr;
+ char *path = nullptr;
int array_index = 0;
short flag = 0;
short groupmode = KSP_GROUP_KSNAME;
/* check if RNA-property described by this selected element is an animatable prop */
if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) &&
- RNA_property_animateable(&te->rnaptr, te->directdata)) {
+ RNA_property_animateable(&te->rnaptr, reinterpret_cast<PropertyRNA *>(te->directdata))) {
/* get id + path + index info from the selected element */
tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
}
@@ -2101,13 +2098,13 @@ static void do_outliner_keyingset_editop(SpaceOutliner *space_outliner,
/* add a new path with the information obtained (only if valid) */
/* TODO: what do we do with group name?
* for now, we don't supply one, and just let this use the KeyingSet name */
- BKE_keyingset_add_path(ks, id, NULL, path, array_index, flag, groupmode);
+ BKE_keyingset_add_path(ks, id, nullptr, path, array_index, flag, groupmode);
ks->active_path = BLI_listbase_count(&ks->paths);
break;
}
case KEYINGSET_EDITMODE_REMOVE: {
/* find the relevant path, then remove it from the KeyingSet */
- KS_Path *ksp = BKE_keyingset_find_path(ks, id, NULL, path, array_index, groupmode);
+ KS_Path *ksp = BKE_keyingset_find_path(ks, id, nullptr, path, array_index, groupmode);
if (ksp) {
/* free path's data */
@@ -2144,11 +2141,11 @@ static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op)
KeyingSet *ks = verify_active_keyingset(scene, 1);
/* check for invalid states */
- if (ks == NULL) {
+ if (ks == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Operation requires an active keying set");
return OPERATOR_CANCELLED;
}
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2156,7 +2153,7 @@ static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op)
do_outliner_keyingset_editop(space_outliner, ks, &space_outliner->tree, KEYINGSET_EDITMODE_ADD);
/* send notifiers */
- WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, nullptr);
return OPERATOR_FINISHED;
}
@@ -2189,7 +2186,7 @@ static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(o
KeyingSet *ks = verify_active_keyingset(scene, 1);
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2198,7 +2195,7 @@ static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(o
space_outliner, ks, &space_outliner->tree, KEYINGSET_EDITMODE_REMOVE);
/* send notifiers */
- WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, nullptr);
return OPERATOR_FINISHED;
}
@@ -2227,15 +2224,13 @@ void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot)
static bool ed_operator_outliner_id_orphans_active(bContext *C)
{
ScrArea *area = CTX_wm_area(C);
- if (area != NULL && area->spacetype == SPACE_OUTLINER) {
+ if (area != nullptr && area->spacetype == SPACE_OUTLINER) {
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
return (space_outliner->outlinevis == SO_ID_ORPHANS);
}
return true;
}
-/** \} */
-
static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Main *bmain = CTX_data_main(C);
@@ -2314,14 +2309,14 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
* outliner several mouse events can be handled in one cycle without
* handling notifiers/redraw which leads to deleting the same object twice.
* cleanup tree here to prevent such cases. */
- if ((area != NULL) && (area->spacetype == SPACE_OUTLINER)) {
+ if ((area != nullptr) && (area->spacetype == SPACE_OUTLINER)) {
outliner_cleanup_tree(space_outliner);
}
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_ID | NA_REMOVED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_REMOVED, nullptr);
/* Force full redraw of the UI. */
- WM_main_add_notifier(NC_WINDOW, NULL);
+ WM_main_add_notifier(NC_WINDOW, nullptr);
return OPERATOR_FINISHED;
}
@@ -2343,7 +2338,7 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
/* properties */
PropertyRNA *prop = RNA_def_int(ot->srna, "num_deleted", 0, 0, INT_MAX, "", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
RNA_def_boolean(ot->srna,
"do_local_ids",
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.hh
index 5336376b576..a62d35131ca 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.hh
@@ -23,6 +23,8 @@
#pragma once
+#include <memory>
+
#include "RNA_types.h"
#ifdef __cplusplus
@@ -47,15 +49,25 @@ struct bPoseChannel;
struct wmKeyConfig;
struct wmOperatorType;
-typedef struct SpaceOutliner_Runtime {
- /** Internal C++ object to create and manage the tree for a specific display type (View Layers,
- * Scenes, Blender File, etc.). */
- struct TreeDisplay *tree_display;
+namespace blender::ed::outliner {
+class AbstractTreeDisplay;
+class AbstractTreeElement;
+} // namespace blender::ed::outliner
+
+struct SpaceOutliner_Runtime {
+ /** Object to create and manage the tree for a specific display type (View Layers, Scenes,
+ * Blender File, etc.). */
+ std::unique_ptr<blender::ed::outliner::AbstractTreeDisplay> tree_display;
/** Pointers to tree-store elements, grouped by `(id, type, nr)`
* in hash-table for faster searching. */
struct GHash *treehash;
-} SpaceOutliner_Runtime;
+
+ SpaceOutliner_Runtime() = default;
+ /** Used for copying runtime data to a duplicated space. */
+ SpaceOutliner_Runtime(const SpaceOutliner_Runtime &);
+ ~SpaceOutliner_Runtime();
+};
typedef enum TreeElementInsertType {
TE_INSERT_BEFORE,
@@ -82,7 +94,7 @@ typedef struct TreeElement {
* #TreeElement. Step by step, data should be moved to it and operations based on the type should
* become virtual methods of the class hierarchy.
*/
- struct TreeElementType *type;
+ std::unique_ptr<blender::ed::outliner::AbstractTreeElement> type;
ListBase subtree;
int xs, ys; /* Do selection. */
@@ -158,6 +170,8 @@ enum {
/* Child elements of the same type in the icon-row are drawn merged as one icon.
* This flag is set for an element that is part of these merged child icons. */
TE_ICONROW_MERGED = (1 << 7),
+ /* This element has some warning to be displayed. */
+ TE_HAS_WARNING = (1 << 8),
};
/* button events */
@@ -211,7 +225,7 @@ typedef enum {
* - not searching into RNA items helps but isn't the complete solution
*/
-#define SEARCHING_OUTLINER(sov) (sov->search_flags & SO_SEARCH_RECURSIVE)
+#define SEARCHING_OUTLINER(sov) ((sov)->search_flags & SO_SEARCH_RECURSIVE)
/* is the current element open? if so we also show children */
#define TSELEM_OPEN(telm, sv) \
@@ -250,16 +264,33 @@ typedef enum TreeItemSelectAction {
void outliner_free_tree(ListBase *tree);
void outliner_cleanup_tree(struct SpaceOutliner *space_outliner);
+/**
+ * Free \a element and its sub-tree and remove its link in \a parent_subtree.
+ *
+ * \note Does not remove the #TreeStoreElem of \a element!
+ * \param parent_subtree: Sub-tree of the parent element, so the list containing \a element.
+ */
void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree);
+/**
+ * Main entry point for building the tree data-structure that the outliner represents.
+ */
void outliner_build_tree(struct Main *mainvar,
struct Scene *scene,
struct ViewLayer *view_layer,
struct SpaceOutliner *space_outliner,
struct ARegion *region);
+struct TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
+ struct Collection *collection,
+ TreeElement *ten);
+
bool outliner_requires_rebuild_on_select_or_active_change(
const struct SpaceOutliner *space_outliner);
+/**
+ * Check if a display mode needs a full rebuild if the open/collapsed state changes.
+ * Element types in these modes don't actually add children if collapsed, so the rebuild is needed.
+ */
bool outliner_requires_rebuild_on_open_change(const struct SpaceOutliner *space_outliner);
typedef struct IDsSelectedData {
@@ -283,47 +314,77 @@ void outliner_collection_isolate_flag(struct Scene *scene,
struct Collection *collection,
struct PropertyRNA *layer_or_collection_prop,
const char *propname,
- const bool value);
+ bool value);
+/**
+ * Return the index to use based on the TreeElement ID and object type
+ *
+ * We use a continuum of indices until we get to the object data-blocks
+ * and we then make room for the object types.
+ */
int tree_element_id_type_to_index(TreeElement *te);
/* outliner_select.c -------------------------------------------- */
+/**
+ * Generic call for non-id data to make active in UI
+ */
void tree_element_type_active_set(struct bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
TreeStoreElem *tselem,
- const eOLSetState set,
+ eOLSetState set,
bool recursive);
+/**
+ * Generic call for non-id data to check the active state in UI.
+ */
eOLDrawState tree_element_type_active_state_get(const struct bContext *C,
const struct TreeViewContext *tvc,
const TreeElement *te,
const TreeStoreElem *tselem);
+/**
+ * Generic call for ID data check or make/check active in UI.
+ */
void tree_element_activate(struct bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
- const eOLSetState set,
- const bool handle_all_types);
+ eOLSetState set,
+ bool handle_all_types);
eOLDrawState tree_element_active_state_get(const TreeViewContext *tvc,
const TreeElement *te,
const TreeStoreElem *tselem);
struct bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te);
+/**
+ * Select the item using the set flags.
+ */
void outliner_item_select(struct bContext *C,
struct SpaceOutliner *space_outliner,
struct TreeElement *te,
- const short select_flag);
+ short select_flag);
+/**
+ * Find if x coordinate is over an icon or name.
+ */
bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x);
bool outliner_item_is_co_over_icon(const TreeElement *te, float view_co_x);
+/**
+ * Find if x coordinate is over element name.
+ */
bool outliner_item_is_co_over_name(const TreeElement *te, float view_co_x);
+/**
+ * Find if x coordinate is over element disclosure toggle.
+ */
bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x);
bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2]);
+/**
+ * Toggle the item's interaction mode if supported.
+ */
void outliner_item_mode_toggle(struct bContext *C,
TreeViewContext *tvc,
TreeElement *te,
- const bool do_extend);
+ bool do_extend);
/* outliner_edit.c ---------------------------------------------- */
typedef void (*outliner_operation_fn)(struct bContext *C,
@@ -334,6 +395,10 @@ typedef void (*outliner_operation_fn)(struct bContext *C,
TreeStoreElem *,
void *);
+/**
+ * \param recurse_selected: Set to false for operations which are already
+ * recursively operating on their children.
+ */
void outliner_do_object_operation_ex(struct bContext *C,
struct ReportList *reports,
struct Scene *scene,
@@ -349,7 +414,11 @@ void outliner_do_object_operation(struct bContext *C,
struct ListBase *lb,
outliner_operation_fn operation_fn);
-int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel);
+int outliner_flag_is_any_test(ListBase *lb, short flag, int curlevel);
+/**
+ * Set or unset \a flag for all outliner elements in \a lb and sub-trees.
+ * \return if any flag was modified.
+ */
bool outliner_flag_set(ListBase *lb, short flag, short set);
bool outliner_flag_flip(ListBase *lb, short flag);
@@ -390,14 +459,24 @@ void id_remap_fn(struct bContext *C,
struct TreeStoreElem *tselem,
void *user_data);
+/**
+ * To retrieve coordinates with redrawing the entire tree.
+ */
void outliner_set_coordinates(struct ARegion *region, struct SpaceOutliner *space_outliner);
+/**
+ * Open or close a tree element, optionally toggling all children recursively.
+ */
void outliner_item_openclose(struct SpaceOutliner *space_outliner,
TreeElement *te,
bool open,
bool toggle_all);
/* outliner_dragdrop.c */
+
+/**
+ * Region drop-box definition.
+ */
void outliner_dropboxes(void);
void OUTLINER_OT_item_drag_drop(struct wmOperatorType *ot);
@@ -446,6 +525,8 @@ void merged_element_search_menu_invoke(struct bContext *C,
TreeElement *parent_te,
TreeElement *activate_te);
+/* Menu only! Calls other operators */
+
void OUTLINER_OT_operation(struct wmOperatorType *ot);
void OUTLINER_OT_scene_operation(struct wmOperatorType *ot);
void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
@@ -510,19 +591,41 @@ void OUTLINER_OT_collection_color_tag_set(struct wmOperatorType *ot);
void outliner_viewcontext_init(const struct bContext *C, TreeViewContext *tvc);
+/**
+ * Try to find an item under y-coordinate \a view_co_y (view-space).
+ * \note Recursive
+ */
TreeElement *outliner_find_item_at_y(const SpaceOutliner *space_outliner,
const ListBase *tree,
float view_co_y);
+/**
+ * Collapsed items can show their children as click-able icons. This function tries to find
+ * such an icon that represents the child item at x-coordinate \a view_co_x (view-space).
+ *
+ * \return a hovered child item or \a parent_te (if no hovered child found).
+ */
TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner,
TreeElement *parent_te,
float view_co_x,
bool *r_is_merged_icon,
bool *r_is_over_icon);
+/**
+ * `tse` is not in the tree-store, we use its contents to find a match.
+ */
TreeElement *outliner_find_tse(struct SpaceOutliner *space_outliner, const TreeStoreElem *tse);
+/**
+ * Find specific item from the trees-tore.
+ */
TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem);
+/**
+ * Find parent element of te.
+ */
TreeElement *outliner_find_parent_element(ListBase *lb,
TreeElement *parent_te,
const TreeElement *child_te);
+/**
+ * Find tree-store that refers to given ID.
+ */
TreeElement *outliner_find_id(struct SpaceOutliner *space_outliner,
ListBase *lb,
const struct ID *id);
@@ -530,6 +633,14 @@ TreeElement *outliner_find_posechannel(ListBase *lb, const struct bPoseChannel *
TreeElement *outliner_find_editbone(ListBase *lb, const struct EditBone *ebone);
TreeElement *outliner_search_back_te(TreeElement *te, short idcode);
struct ID *outliner_search_back(TreeElement *te, short idcode);
+/**
+ * Iterate over all tree elements (pre-order traversal), executing \a func callback for
+ * each tree element matching the optional filters.
+ *
+ * \param filter_te_flag: If not 0, only TreeElements with this flag will be visited.
+ * \param filter_tselem_flag: Same as \a filter_te_flag, but for the TreeStoreElem.
+ * \param func: Custom callback to execute for each visited item.
+ */
bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
ListBase *tree,
int filter_te_flag,
@@ -537,16 +648,33 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
TreeTraversalFunc func,
void *customdata);
float outliner_restrict_columns_width(const struct SpaceOutliner *space_outliner);
+/**
+ * Find first tree element in tree with matching tree-store flag.
+ */
TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag);
+/**
+ * Find if element is visible in the outliner tree.
+ */
bool outliner_is_element_visible(const TreeElement *te);
+/**
+ * Scroll view vertically while keeping within total bounds.
+ */
void outliner_scroll_view(struct SpaceOutliner *space_outliner,
struct ARegion *region,
int delta_y);
+/**
+ * The outliner should generally use #ED_region_tag_redraw_no_rebuild() to avoid unnecessary tree
+ * rebuilds. If elements are open or closed, we may still have to rebuild.
+ * Upon changing the open/closed state, call this to avoid rebuilds if possible.
+ */
void outliner_tag_redraw_avoid_rebuild_on_open_change(const struct SpaceOutliner *space_outliner,
struct ARegion *region);
/* outliner_sync.c ---------------------------------------------- */
+/**
+ * If outliner is dirty sync selection from view layer and sequencer.
+ */
void outliner_sync_selection(const struct bContext *C, struct SpaceOutliner *space_outliner);
/* outliner_context.c ------------------------------------------- */
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.cc
index 7e5b0c90714..4664a3150a1 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.cc
@@ -25,7 +25,7 @@
#include "ED_screen.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
/* ************************** registration **********************************/
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.cc
index 5e409db0059..c2a7bfb9b37 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <stdlib.h>
+#include <cstdlib>
#include "MEM_guardedalloc.h"
@@ -79,7 +79,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
/**
* \note changes to selection are by convention and not essential.
@@ -96,14 +96,14 @@ static void do_outliner_item_editmode_toggle(bContext *C, Scene *scene, Base *ba
changed = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA);
if (changed) {
ED_object_base_select(base, BA_DESELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, nullptr);
}
}
else {
changed = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_NO_CONTEXT);
if (changed) {
ED_object_base_select(base, BA_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, nullptr);
}
}
@@ -134,14 +134,14 @@ static void do_outliner_item_posemode_toggle(bContext *C, Scene *scene, Base *ba
changed = ED_object_posemode_exit_ex(bmain, ob);
if (changed) {
ED_object_base_select(base, BA_DESELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, nullptr);
}
}
else {
changed = ED_object_posemode_enter_ex(bmain, ob);
if (changed) {
ED_object_base_select(base, BA_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, nullptr);
}
}
@@ -165,7 +165,7 @@ static void do_outliner_item_posemode_toggle(bContext *C, Scene *scene, Base *ba
*/
static void do_outliner_item_mode_toggle_generic(bContext *C, TreeViewContext *tvc, Base *base)
{
- const int active_mode = tvc->obact->mode;
+ const eObjectMode active_mode = (eObjectMode)tvc->obact->mode;
ED_undo_group_begin(C);
if (ED_object_mode_set(C, OB_MODE_OBJECT)) {
@@ -184,7 +184,6 @@ static void do_outliner_item_mode_toggle_generic(bContext *C, TreeViewContext *t
ED_undo_group_end(C);
}
-/* Toggle the item's interaction mode if supported */
void outliner_item_mode_toggle(bContext *C,
TreeViewContext *tvc,
TreeElement *te,
@@ -223,13 +222,13 @@ static void tree_element_viewlayer_activate(bContext *C, TreeElement *te)
return;
}
- ViewLayer *view_layer = te->directdata;
+ ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
wmWindow *win = CTX_wm_window(C);
Scene *scene = WM_window_get_active_scene(win);
if (BLI_findindex(&scene->view_layers, view_layer) != -1) {
WM_window_set_active_view_layer(win, view_layer);
- WM_event_add_notifier(C, NC_SCREEN | ND_LAYER, NULL);
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYER, nullptr);
}
}
@@ -242,7 +241,7 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer,
{
Base *base;
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
+ for (base = reinterpret_cast<Base *>(FIRSTBASE(view_layer)); base; base = base->next) {
Object *ob = base->object;
if ((((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) &&
BKE_object_is_child_recursive(ob_parent, ob))) {
@@ -253,8 +252,7 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer,
static void do_outliner_bone_select_recursive(bArmature *arm, Bone *bone_parent, bool select)
{
- Bone *bone;
- for (bone = bone_parent->childbase.first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, &bone_parent->childbase) {
if (select && PBONE_SELECTABLE(arm, bone)) {
bone->flag |= BONE_SELECTED;
}
@@ -288,11 +286,11 @@ static void tree_element_object_activate(bContext *C,
bool recursive)
{
TreeStoreElem *tselem = TREESTORE(te);
- TreeStoreElem *parent_tselem = NULL;
- TreeElement *parent_te = NULL;
+ TreeStoreElem *parent_tselem = nullptr;
+ TreeElement *parent_te = nullptr;
Scene *sce;
Base *base;
- Object *ob = NULL;
+ Object *ob = nullptr;
/* if id is not object, we search back */
if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
@@ -310,7 +308,7 @@ static void tree_element_object_activate(bContext *C,
}
}
}
- if (ob == NULL) {
+ if (ob == nullptr) {
return;
}
@@ -324,9 +322,9 @@ static void tree_element_object_activate(bContext *C,
base = BKE_view_layer_base_find(view_layer, ob);
if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
- if (base != NULL) {
+ if (base != nullptr) {
Object *obact = OBACT(view_layer);
- const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT;
+ const eObjectMode object_mode = obact ? (eObjectMode)obact->mode : OB_MODE_OBJECT;
if (base && !BKE_object_is_mode_compat(base->object, object_mode)) {
if (object_mode == OB_MODE_OBJECT) {
struct Main *bmain = CTX_data_main(C);
@@ -334,7 +332,7 @@ static void tree_element_object_activate(bContext *C,
ED_object_mode_generic_exit(bmain, depsgraph, scene, base->object);
}
if (!BKE_object_is_mode_compat(base->object, object_mode)) {
- base = NULL;
+ base = nullptr;
}
}
}
@@ -357,7 +355,7 @@ static void tree_element_object_activate(bContext *C,
}
}
else {
- /* deleselect all */
+ /* De-select all. */
/* Only in object mode so we can switch the active object,
* keeping all objects in the current 'mode' selected, useful for multi-pose/edit mode.
@@ -391,8 +389,8 @@ static void tree_element_material_activate(bContext *C, ViewLayer *view_layer, T
{
/* we search for the object parent */
Object *ob = (Object *)outliner_search_back(te, ID_OB);
- /* Note : ob->matbits can be NULL when a local object points to a library mesh. */
- if (ob == NULL || ob != OBACT(view_layer) || ob->matbits == NULL) {
+ /* Note : ob->matbits can be nullptr when a local object points to a library mesh. */
+ if (ob == nullptr || ob != OBACT(view_layer) || ob->matbits == nullptr) {
return; /* just paranoia */
}
@@ -412,7 +410,7 @@ static void tree_element_material_activate(bContext *C, ViewLayer *view_layer, T
* for render views to update. See T42973.
* Note that RNA material update does it too, see e.g. rna_MaterialSlot_update(). */
DEG_id_tag_update((ID *)ob, ID_RECALC_TRANSFORM);
- WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL);
+ WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, nullptr);
}
static void tree_element_camera_activate(bContext *C, Scene *scene, TreeElement *te)
@@ -422,17 +420,17 @@ static void tree_element_camera_activate(bContext *C, Scene *scene, TreeElement
scene->camera = ob;
Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = reinterpret_cast<wmWindowManager *>(bmain->wm.first);
WM_windows_scene_data_sync(&wm->windows, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_SCENE | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_SCENE | NA_EDITED, nullptr);
}
static void tree_element_world_activate(bContext *C, Scene *scene, TreeElement *te)
{
- Scene *sce = NULL;
+ Scene *sce = nullptr;
TreeElement *tep = te->parent;
if (tep) {
@@ -462,7 +460,7 @@ static void tree_element_defgroup_activate(bContext *C, TreeElement *te, TreeSto
static void tree_element_gplayer_activate(bContext *C, TreeElement *te, TreeStoreElem *tselem)
{
bGPdata *gpd = (bGPdata *)tselem->id;
- bGPDlayer *gpl = te->directdata;
+ bGPDlayer *gpl = reinterpret_cast<bGPDlayer *>(te->directdata);
/* We can only have a single "active" layer at a time
* and there must always be an active layer... */
@@ -490,30 +488,29 @@ static void tree_element_posechannel_activate(bContext *C,
bool recursive)
{
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
- bPoseChannel *pchan = te->directdata;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
+ bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
if (!(pchan->bone->flag & BONE_HIDDEN_P)) {
if (set != OL_SETSEL_EXTEND) {
/* Single select forces all other bones to get unselected. */
uint objects_len = 0;
- Object **objects = BKE_object_pose_array_get_unique(view_layer, NULL, &objects_len);
+ Object **objects = BKE_object_pose_array_get_unique(view_layer, nullptr, &objects_len);
for (uint object_index = 0; object_index < objects_len; object_index++) {
Object *ob_iter = BKE_object_pose_armature_get(objects[object_index]);
/* Sanity checks. */
- if (ELEM(NULL, ob_iter, ob_iter->pose, ob_iter->data)) {
+ if (ELEM(nullptr, ob_iter, ob_iter->pose, ob_iter->data)) {
continue;
}
- bPoseChannel *pchannel;
- for (pchannel = ob_iter->pose->chanbase.first; pchannel; pchannel = pchannel->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchannel, &ob_iter->pose->chanbase) {
pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
}
if (ob != ob_iter) {
- DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(reinterpret_cast<ID *>(ob_iter->data), ID_RECALC_SELECT);
}
}
MEM_freeN(objects);
@@ -546,14 +543,14 @@ static void tree_element_bone_activate(bContext *C,
bool recursive)
{
bArmature *arm = (bArmature *)tselem->id;
- Bone *bone = te->directdata;
+ Bone *bone = reinterpret_cast<Bone *>(te->directdata);
if (!(bone->flag & BONE_HIDDEN_P)) {
Object *ob = OBACT(view_layer);
if (ob) {
if (set != OL_SETSEL_EXTEND) {
/* single select forces all other bones to get unselected */
- for (Bone *bone_iter = arm->bonebase.first; bone_iter != NULL;
+ for (Bone *bone_iter = reinterpret_cast<Bone *>(arm->bonebase.first); bone_iter != nullptr;
bone_iter = bone_iter->next) {
bone_iter->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
do_outliner_bone_select_recursive(arm, bone_iter, false);
@@ -595,13 +592,18 @@ static void tree_element_ebone_activate(bContext *C,
bool recursive)
{
bArmature *arm = (bArmature *)tselem->id;
- EditBone *ebone = te->directdata;
+ EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
if (set == OL_SETSEL_NORMAL) {
if (!(ebone->flag & BONE_HIDDEN_A)) {
uint bases_len = 0;
- Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
- view_layer, NULL, &bases_len);
+
+ ObjectsInModeParams ob_params{};
+ ob_params.object_mode = OB_MODE_EDIT;
+ ob_params.no_dup_data = true;
+
+ Base **bases = BKE_view_layer_array_from_bases_in_mode_params(
+ view_layer, nullptr, &bases_len, &ob_params);
ED_armature_edit_deselect_all_multi_ex(bases, bases_len);
MEM_freeN(bases);
@@ -679,7 +681,7 @@ static void tree_element_sequence_activate(bContext *C,
if (BLI_findindex(ed->seqbasep, seq) != -1) {
if (set == OL_SETSEL_EXTEND) {
- SEQ_select_active_set(scene, NULL);
+ SEQ_select_active_set(scene, nullptr);
}
ED_sequencer_deselect_all(scene);
@@ -702,7 +704,7 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED
#if 0
select_single_seq(seq, 1);
#endif
- Sequence *p = ed->seqbasep->first;
+ Sequence *p = reinterpret_cast<Sequence *>(ed->seqbasep->first);
while (p) {
if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) {
p = p->next;
@@ -721,22 +723,23 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED
static void tree_element_master_collection_activate(const bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- LayerCollection *layer_collection = view_layer->layer_collections.first;
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ view_layer->layer_collections.first);
BKE_layer_collection_activate(view_layer, layer_collection);
/* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work
* when only the active collection changes. */
- WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, nullptr);
}
static void tree_element_layer_collection_activate(bContext *C, TreeElement *te)
{
Scene *scene = CTX_data_scene(C);
- LayerCollection *layer_collection = te->directdata;
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(te->directdata);
ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection);
BKE_layer_collection_activate(view_layer, layer_collection);
/* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work
* when only the active collection changes. */
- WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, nullptr);
}
static void tree_element_text_activate(bContext *C, TreeElement *te)
@@ -747,7 +750,6 @@ static void tree_element_text_activate(bContext *C, TreeElement *te)
/* ---------------------------------------------- */
-/* generic call for ID data check or make/check active in UI */
void tree_element_activate(bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
@@ -778,9 +780,6 @@ void tree_element_activate(bContext *C,
}
}
-/**
- * Generic call for non-id data to make active in UI
- */
void tree_element_type_active_set(bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
@@ -859,7 +858,7 @@ static eOLDrawState tree_element_bone_state_get(const ViewLayer *view_layer,
const TreeStoreElem *tselem)
{
const bArmature *arm = (const bArmature *)tselem->id;
- const Bone *bone = te->directdata;
+ const Bone *bone = reinterpret_cast<Bone *>(te->directdata);
const Object *ob = OBACT(view_layer);
if (ob && ob->data == arm) {
if (bone->flag & BONE_SELECTED) {
@@ -871,7 +870,7 @@ static eOLDrawState tree_element_bone_state_get(const ViewLayer *view_layer,
static eOLDrawState tree_element_ebone_state_get(const TreeElement *te)
{
- const EditBone *ebone = te->directdata;
+ const EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
if (ebone->flag & BONE_SELECTED) {
return OL_DRAWSEL_NORMAL;
}
@@ -899,7 +898,7 @@ static eOLDrawState tree_element_pose_state_get(const ViewLayer *view_layer,
const Object *ob = (const Object *)tselem->id;
/* This will just lookup in a cache, it will not change the arguments. */
const Base *base = BKE_view_layer_base_find((ViewLayer *)view_layer, (Object *)ob);
- if (base == NULL) {
+ if (base == nullptr) {
/* Armature not instantiated in current scene (e.g. inside an appended group). */
return OL_DRAWSEL_NONE;
}
@@ -915,7 +914,7 @@ static eOLDrawState tree_element_posechannel_state_get(const Object *ob_pose,
const TreeStoreElem *tselem)
{
const Object *ob = (const Object *)tselem->id;
- const bPoseChannel *pchan = te->directdata;
+ const bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
if (ob == ob_pose && ob->pose) {
if (pchan->bone->flag & BONE_SELECTED) {
return OL_DRAWSEL_NORMAL;
@@ -931,7 +930,7 @@ static eOLDrawState tree_element_viewlayer_state_get(const bContext *C, const Tr
return OL_DRAWSEL_NONE;
}
- const ViewLayer *view_layer = te->directdata;
+ const ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
if (CTX_data_view_layer(C) == view_layer) {
return OL_DRAWSEL_NORMAL;
@@ -1007,8 +1006,8 @@ static eOLDrawState tree_element_active_material_get(const ViewLayer *view_layer
{
/* we search for the object parent */
const Object *ob = (const Object *)outliner_search_back((TreeElement *)te, ID_OB);
- /* Note : ob->matbits can be NULL when a local object points to a library mesh. */
- if (ob == NULL || ob != OBACT(view_layer) || ob->matbits == NULL) {
+ /* Note : ob->matbits can be nullptr when a local object points to a library mesh. */
+ if (ob == nullptr || ob != OBACT(view_layer) || ob->matbits == nullptr) {
return OL_DRAWSEL_NONE; /* just paranoia */
}
@@ -1047,7 +1046,7 @@ static eOLDrawState tree_element_active_scene_get(const TreeViewContext *tvc,
static eOLDrawState tree_element_active_world_get(const Scene *scene, const TreeElement *te)
{
const TreeElement *tep = te->parent;
- if (tep == NULL) {
+ if (tep == nullptr) {
return OL_DRAWSEL_NORMAL;
}
@@ -1086,9 +1085,6 @@ eOLDrawState tree_element_active_state_get(const TreeViewContext *tvc,
return OL_DRAWSEL_NONE;
}
-/**
- * Generic call for non-id data to check the active state in UI.
- */
eOLDrawState tree_element_type_active_state_get(const bContext *C,
const TreeViewContext *tvc,
const TreeElement *te,
@@ -1146,7 +1142,7 @@ bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te
te = te->parent;
}
- return NULL;
+ return nullptr;
}
static void outliner_sync_to_properties_editors(const bContext *C,
@@ -1169,7 +1165,7 @@ static void outliner_sync_to_properties_editors(const bContext *C,
static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreElem *tselem)
{
- PointerRNA ptr = {0};
+ PointerRNA ptr = {nullptr};
int context = 0;
/* ID Types */
@@ -1217,7 +1213,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
break;
case TSE_CONSTRAINT_BASE:
case TSE_CONSTRAINT: {
- TreeElement *bone_te = NULL;
+ TreeElement *bone_te = nullptr;
bPoseChannel *pchan = outliner_find_parent_bone(te, &bone_te);
if (pchan) {
@@ -1231,7 +1227,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
/* Expand the selected constraint in the properties editor. */
if (tselem->type != TSE_CONSTRAINT_BASE) {
- BKE_constraint_panel_expand(te->directdata);
+ BKE_constraint_panel_expand(reinterpret_cast<bConstraint *>(te->directdata));
}
break;
}
@@ -1244,7 +1240,8 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
Object *ob = (Object *)tselem->id;
if (ob->type == OB_GPENCIL) {
- BKE_gpencil_modifier_panel_expand(te->directdata);
+ BKE_gpencil_modifier_panel_expand(
+ reinterpret_cast<GpencilModifierData *>(te->directdata));
}
else {
ModifierData *md = (ModifierData *)te->directdata;
@@ -1277,12 +1274,12 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
context = BCONTEXT_SHADERFX;
if (tselem->type != TSE_GPENCIL_EFFECT_BASE) {
- BKE_shaderfx_panel_expand(te->directdata);
+ BKE_shaderfx_panel_expand(reinterpret_cast<ShaderFxData *>(te->directdata));
}
break;
case TSE_BONE: {
bArmature *arm = (bArmature *)tselem->id;
- Bone *bone = te->directdata;
+ Bone *bone = reinterpret_cast<Bone *>(te->directdata);
RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr);
context = BCONTEXT_BONE;
@@ -1290,7 +1287,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_EBONE: {
bArmature *arm = (bArmature *)tselem->id;
- EditBone *ebone = te->directdata;
+ EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
RNA_pointer_create(&arm->id, &RNA_EditBone, ebone, &ptr);
context = BCONTEXT_BONE;
@@ -1298,8 +1295,8 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_POSE_CHANNEL: {
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
- bPoseChannel *pchan = te->directdata;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
+ bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
RNA_pointer_create(&arm->id, &RNA_PoseBone, pchan, &ptr);
context = BCONTEXT_BONE;
@@ -1307,7 +1304,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_POSE_BASE: {
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr);
context = BCONTEXT_DATA;
@@ -1315,7 +1312,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_R_LAYER_BASE:
case TSE_R_LAYER: {
- ViewLayer *view_layer = te->directdata;
+ ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
RNA_pointer_create(tselem->id, &RNA_ViewLayer, view_layer, &ptr);
context = BCONTEXT_VIEW_LAYER;
@@ -1324,7 +1321,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
case TSE_POSEGRP_BASE:
case TSE_POSEGRP: {
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr);
context = BCONTEXT_DATA;
@@ -1400,7 +1397,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
Collection *gr = (Collection *)tselem->id;
if (extend) {
- int sel = BA_SELECT;
+ eObjectSelect_Mode sel = BA_SELECT;
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) {
Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
if (base && (base->flag & BASE_SELECTED)) {
@@ -1424,7 +1421,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) {
Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
/* Object may not be in this scene */
- if (base != NULL) {
+ if (base != nullptr) {
if ((base->flag & BASE_SELECTED) == 0) {
ED_object_base_select(base, BA_SELECT);
}
@@ -1446,7 +1443,6 @@ static void do_outliner_item_activate_tree_element(bContext *C,
}
}
-/* Select the item using the set flags */
void outliner_item_select(bContext *C,
SpaceOutliner *space_outliner,
TreeElement *te,
@@ -1739,7 +1735,7 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op)
ARegion *region = CTX_wm_region(C);
rctf rectf;
- const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode");
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0);
@@ -1825,7 +1821,7 @@ static TreeElement *outliner_find_rightmost_visible_child(SpaceOutliner *space_o
{
while (te->subtree.last) {
if (TSELEM_OPEN(TREESTORE(te), space_outliner)) {
- te = te->subtree.last;
+ te = reinterpret_cast<TreeElement *>(te->subtree.last);
}
else {
break;
@@ -1869,7 +1865,7 @@ static TreeElement *outliner_find_next_element(SpaceOutliner *space_outliner, Tr
TreeStoreElem *tselem = TREESTORE(te);
if (TSELEM_OPEN(tselem, space_outliner) && te->subtree.first) {
- te = te->subtree.first;
+ te = reinterpret_cast<TreeElement *>(te->subtree.first);
}
else if (te->next) {
te = te->next;
@@ -1906,7 +1902,7 @@ static TreeElement *outliner_walk_right(SpaceOutliner *space_outliner,
/* Only walk down a level if the element is open and not toggling expand */
if (!toggle_all && TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) {
- te = te->subtree.first;
+ te = reinterpret_cast<TreeElement *>(te->subtree.first);
}
else {
outliner_item_openclose(space_outliner, te, true, toggle_all);
@@ -1957,7 +1953,7 @@ static TreeElement *find_walk_select_start_element(SpaceOutliner *space_outliner
/* If no active element exists, use the first element in the tree */
if (!active_te) {
- active_te = space_outliner->tree.first;
+ active_te = reinterpret_cast<TreeElement *>(space_outliner->tree.first);
*changed = true;
}
diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.cc
index d78767019b5..74416024b03 100644
--- a/source/blender/editors/space_outliner/outliner_sync.c
+++ b/source/blender/editors/space_outliner/outliner_sync.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <stdio.h>
+#include <cstdio>
#include "DNA_armature_types.h"
#include "DNA_layer_types.h"
@@ -50,9 +50,8 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
-/* Functions for tagging outliner selection syncing is dirty from operators */
void ED_outliner_select_sync_from_object_tag(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -89,13 +88,13 @@ bool ED_outliner_select_sync_is_dirty(const bContext *C)
return wm->outliner_sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_ALL;
}
-/* Copy sync select dirty flag from window manager to all outliners to be synced lazily on draw */
void ED_outliner_select_sync_flag_outliners(const bContext *C)
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
- for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = reinterpret_cast<bScreen *>(bmain->screens.first); screen;
+ screen = reinterpret_cast<bScreen *>(screen->id.next)) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_OUTLINER) {
@@ -116,12 +115,12 @@ void ED_outliner_select_sync_flag_outliners(const bContext *C)
* outliner display mode also needs to be considered. This stores the types of data
* to sync to increase code clarity.
*/
-typedef struct SyncSelectTypes {
+struct SyncSelectTypes {
bool object;
bool edit_bone;
bool pose_bone;
bool sequence;
-} SyncSelectTypes;
+};
/**
* Set which types of data to sync when syncing selection from the outliner based on object
@@ -175,11 +174,11 @@ static bool outliner_sync_select_to_outliner_set_types(const bContext *C,
* Stores items selected from a sync from the outliner. Prevents syncing the selection
* state of the last instance of an object linked in multiple collections.
*/
-typedef struct SelectedItems {
+struct SelectedItems {
GSet *objects;
GSet *edit_bones;
GSet *pose_bones;
-} SelectedItems;
+};
static void selected_items_init(SelectedItems *selected_items)
{
@@ -190,9 +189,9 @@ static void selected_items_init(SelectedItems *selected_items)
static void selected_items_free(SelectedItems *selected_items)
{
- BLI_gset_free(selected_items->objects, NULL);
- BLI_gset_free(selected_items->edit_bones, NULL);
- BLI_gset_free(selected_items->pose_bones, NULL);
+ BLI_gset_free(selected_items->objects, nullptr);
+ BLI_gset_free(selected_items->edit_bones, nullptr);
+ BLI_gset_free(selected_items->pose_bones, nullptr);
}
/* Check if an instance of this object been selected by the sync */
@@ -276,7 +275,7 @@ static void outliner_select_sync_to_pose_bone(TreeElement *te,
GSet *selected_pbones)
{
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
short bone_flag = pchan->bone->flag;
@@ -352,7 +351,6 @@ static void outliner_sync_selection_from_outliner(Scene *scene,
}
}
-/* Set clean outliner and mark other outliners for syncing */
void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *space_outliner)
{
/* Don't sync if not checked or in certain outliner display modes */
@@ -406,7 +404,7 @@ static void outliner_select_sync_from_object(ViewLayer *view_layer,
Object *ob = (Object *)tselem->id;
Base *base = (te->directdata) ? (Base *)te->directdata :
BKE_view_layer_base_find(view_layer, ob);
- const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0);
+ const bool is_selected = (base != nullptr) && ((base->flag & BASE_SELECTED) != 0);
if (base && (ob == obact)) {
tselem->flag |= TSE_ACTIVE;
@@ -489,12 +487,12 @@ static void outliner_select_sync_from_sequence(Sequence *sequence_active, TreeSt
* Contains active object, bones, and sequence for syncing to prevent getting active data
* repeatedly throughout syncing to the outliner.
*/
-typedef struct SyncSelectActiveData {
+struct SyncSelectActiveData {
Object *object;
EditBone *edit_bone;
bPoseChannel *pose_channel;
Sequence *sequence;
-} SyncSelectActiveData;
+};
/** Sync select and active flags from active view layer, bones, and sequences to the outliner. */
static void outliner_sync_selection_to_outliner(ViewLayer *view_layer,
@@ -547,7 +545,6 @@ static void get_sync_select_active_data(const bContext *C, SyncSelectActiveData
active_data->sequence = SEQ_select_active_get(scene);
}
-/* If outliner is dirty sync selection from view layer and sequencer. */
void outliner_sync_selection(const bContext *C, SpaceOutliner *space_outliner)
{
/* Set which types of data to sync from sync dirty flag and outliner display mode */
@@ -565,7 +562,7 @@ void outliner_sync_selection(const bContext *C, SpaceOutliner *space_outliner)
outliner_sync_selection_to_outliner(
view_layer, space_outliner, &space_outliner->tree, &active_data, &sync_types);
- /* Keep any unsynced data in the dirty flag */
+ /* Keep any un-synced data in the dirty flag. */
if (sync_types.object) {
space_outliner->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_OBJECT;
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.cc
index 9e314701719..1c1a4f6f4c2 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -95,7 +95,7 @@
#include "SEQ_relations.h"
#include "SEQ_sequencer.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
static CLG_LogRef LOG = {"ed.outliner.tools"};
@@ -197,11 +197,24 @@ static void get_element_operation_type(
static TreeElement *get_target_element(SpaceOutliner *space_outliner)
{
TreeElement *te = outliner_find_element_with_flag(&space_outliner->tree, TSE_ACTIVE);
- BLI_assert(te);
return te;
}
+static bool outliner_operation_tree_element_poll(bContext *C)
+{
+ if (!ED_operator_outliner_active(C)) {
+ return false;
+ }
+ SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
+ TreeElement *te = get_target_element(space_outliner);
+ if (te == nullptr) {
+ return false;
+ }
+
+ return true;
+}
+
static void unlink_action_fn(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
@@ -210,8 +223,8 @@ static void unlink_action_fn(bContext *C,
TreeStoreElem *UNUSED(tselem),
void *UNUSED(user_data))
{
- /* just set action to NULL */
- BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL);
+ /* just set action to nullptr */
+ BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, nullptr);
}
static void unlink_material_fn(bContext *UNUSED(C),
@@ -222,7 +235,7 @@ static void unlink_material_fn(bContext *UNUSED(C),
TreeStoreElem *UNUSED(tselem),
void *UNUSED(user_data))
{
- Material **matar = NULL;
+ Material **matar = nullptr;
int a, totcol = 0;
if (GS(tsep->id->name) == ID_OB) {
@@ -264,11 +277,11 @@ static void unlink_material_fn(bContext *UNUSED(C),
BLI_assert(0);
}
- if (LIKELY(matar != NULL)) {
+ if (LIKELY(matar != nullptr)) {
for (a = 0; a < totcol; a++) {
if (a == te->index && matar[a]) {
id_us_min(&matar[a]->id);
- matar[a] = NULL;
+ matar[a] = nullptr;
}
}
}
@@ -282,7 +295,7 @@ static void unlink_texture_fn(bContext *UNUSED(C),
TreeStoreElem *UNUSED(tselem),
void *UNUSED(user_data))
{
- MTex **mtex = NULL;
+ MTex **mtex = nullptr;
int a;
if (GS(tsep->id->name) == ID_LS) {
@@ -297,7 +310,7 @@ static void unlink_texture_fn(bContext *UNUSED(C),
if (a == te->index && mtex[a]) {
if (mtex[a]->tex) {
id_us_min(&mtex[a]->tex->id);
- mtex[a]->tex = NULL;
+ mtex[a]->tex = nullptr;
}
}
}
@@ -317,7 +330,7 @@ static void unlink_collection_fn(bContext *C,
if (tsep) {
if (GS(tsep->id->name) == ID_OB) {
Object *ob = (Object *)tsep->id;
- ob->instance_collection = NULL;
+ ob->instance_collection = nullptr;
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
DEG_relations_tag_update(bmain);
}
@@ -356,7 +369,7 @@ static void unlink_object_fn(bContext *C,
TreeElement *te_parent = te->parent;
while (tsep && GS(tsep->id->name) == ID_OB) {
te_parent = te_parent->parent;
- tsep = te_parent ? TREESTORE(te_parent) : NULL;
+ tsep = te_parent ? TREESTORE(te_parent) : nullptr;
}
}
@@ -391,7 +404,7 @@ static void unlink_world_fn(bContext *UNUSED(C),
/* need to use parent scene not just scene, otherwise may end up getting wrong one */
id_us_min(&wo->id);
- parscene->world = NULL;
+ parscene->world = nullptr;
}
static void outliner_do_libdata_operation(bContext *C,
@@ -407,7 +420,7 @@ static void outliner_do_libdata_operation(bContext *C,
if (tselem->flag & TSE_SELECTED) {
if (((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
tselem->type == TSE_LAYER_COLLECTION) {
- TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
+ TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : nullptr;
operation_fn(C, reports, scene, te, tsep, tselem, user_data);
}
}
@@ -424,13 +437,13 @@ static void outliner_do_libdata_operation(bContext *C,
/** \name Scene Menu Operator
* \{ */
-typedef enum eOutliner_PropSceneOps {
+enum eOutliner_PropSceneOps {
OL_SCENE_OP_DELETE = 1,
-} eOutliner_PropSceneOps;
+};
static const EnumPropertyItem prop_scene_op_types[] = {
{OL_SCENE_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static bool outliner_do_scene_operation(
@@ -475,7 +488,7 @@ static bool scene_fn(bContext *C,
static int outliner_scene_operation_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- const eOutliner_PropSceneOps event = RNA_enum_get(op->ptr, "type");
+ const eOutliner_PropSceneOps event = (eOutliner_PropSceneOps)RNA_enum_get(op->ptr, "type");
if (outliner_do_scene_operation(C, event, &space_outliner->tree, scene_fn) == false) {
return OPERATOR_CANCELLED;
@@ -521,10 +534,10 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
* the merged select popup menu. The sub-tree of the parent is searched and
* the child is needed to only show elements of the same type in the popup.
*/
-typedef struct MergedSearchData {
+struct MergedSearchData {
TreeElement *parent_element;
TreeElement *select_element;
-} MergedSearchData;
+};
static void merged_element_search_fn_recursive(
const ListBase *tree, short tselem_type, short type, const char *str, uiSearchItems *items)
@@ -602,13 +615,13 @@ static uiBlock *merged_element_search_menu(bContext *C, ARegion *region, void *d
but = uiDefSearchBut(
block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, menu_width, UI_UNIT_Y, 0, 0, "");
UI_but_func_search_set(but,
- NULL,
+ nullptr,
merged_element_search_update_fn,
data,
false,
- NULL,
+ nullptr,
merged_element_search_exec_fn,
- NULL);
+ nullptr);
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
/* Fake button to hold space for search items */
@@ -620,15 +633,16 @@ static uiBlock *merged_element_search_menu(bContext *C, ARegion *region, void *d
10 - UI_searchbox_size_y(),
menu_width,
UI_searchbox_size_y(),
- NULL,
+ nullptr,
0,
0,
0,
0,
- NULL);
+ nullptr);
/* Center the menu on the cursor */
- UI_block_bounds_set_popup(block, 6, (const int[2]){-(menu_width / 2), 0});
+ const int offset[2] = {-(menu_width / 2), 0};
+ UI_block_bounds_set_popup(block, 6, offset);
return block;
}
@@ -637,7 +651,7 @@ void merged_element_search_menu_invoke(bContext *C,
TreeElement *parent_te,
TreeElement *activate_te)
{
- MergedSearchData *select_data = MEM_callocN(sizeof(MergedSearchData), "merge_search_data");
+ MergedSearchData *select_data = MEM_cnew<MergedSearchData>("merge_search_data");
select_data->parent_element = parent_te;
select_data->select_element = activate_te;
@@ -742,7 +756,7 @@ static void id_local_fn(bContext *C,
}
}
else if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id)) {
- BKE_lib_override_library_free(&tselem->id->override_library, true);
+ BKE_lib_override_library_make_local(tselem->id);
}
}
@@ -760,7 +774,7 @@ static void object_proxy_to_override_convert_fn(bContext *C,
Object *ob_proxy = (Object *)id_proxy;
Scene *scene = CTX_data_scene(C);
- if (ob_proxy->proxy == NULL) {
+ if (ob_proxy->proxy == nullptr) {
return;
}
@@ -775,17 +789,17 @@ static void object_proxy_to_override_convert_fn(bContext *C,
}
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
-typedef struct OutlinerLibOverrideData {
+struct OutlinerLibOverrideData {
bool do_hierarchy;
/**
* For resync operation, force keeping newly created override IDs (or original linked IDs)
* instead of re-applying relevant existing ID pointer property override operations. Helps
* solving broken overrides while not losing *all* of your overrides. */
bool do_resync_hierarchy_enforce;
-} OutlinerLibOverrideData;
+};
static void id_override_library_create_fn(bContext *C,
ReportList *reports,
@@ -797,14 +811,14 @@ static void id_override_library_create_fn(bContext *C,
{
BLI_assert(TSE_IS_REAL_ID(tselem));
ID *id_root = tselem->id;
- OutlinerLibOverrideData *data = user_data;
+ OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
const bool do_hierarchy = data->do_hierarchy;
bool success = false;
- ID *id_reference = NULL;
+ ID *id_reference = nullptr;
bool is_override_instancing_object = false;
- if (tsep != NULL && tsep->type == TSE_SOME_ID && tsep->id != NULL &&
- GS(tsep->id->name) == ID_OB) {
+ if (tsep != nullptr && tsep->type == TSE_SOME_ID && tsep->id != nullptr &&
+ GS(tsep->id->name) == ID_OB && !ID_IS_OVERRIDE_LIBRARY(tsep->id)) {
Object *ob = (Object *)tsep->id;
if (ob->type == OB_EMPTY && &ob->instance_collection->id == id_root) {
BLI_assert(GS(id_root->name) == ID_GR);
@@ -834,7 +848,7 @@ static void id_override_library_create_fn(bContext *C,
if (do_hierarchy) {
/* Tag all linked parents in tree hierarchy to be also overridden. */
- while ((te = te->parent) != NULL) {
+ while ((te = te->parent) != nullptr) {
if (!TSE_IS_REAL_ID(te->store_elem)) {
continue;
}
@@ -856,10 +870,10 @@ static void id_override_library_create_fn(bContext *C,
}
success = BKE_lib_override_library_create(
- bmain, CTX_data_scene(C), CTX_data_view_layer(C), id_root, id_reference, NULL);
+ bmain, CTX_data_scene(C), CTX_data_view_layer(C), id_root, id_reference, nullptr);
}
else if (ID_IS_OVERRIDABLE_LIBRARY(id_root)) {
- success = BKE_lib_override_library_create_from_id(bmain, id_root, true) != NULL;
+ success = BKE_lib_override_library_create_from_id(bmain, id_root, true) != nullptr;
/* Cleanup. */
BKE_main_id_newptr_and_tag_clear(bmain);
@@ -890,7 +904,7 @@ static void id_override_library_reset_fn(bContext *C,
{
BLI_assert(TSE_IS_REAL_ID(tselem));
ID *id_root = tselem->id;
- OutlinerLibOverrideData *data = user_data;
+ OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
const bool do_hierarchy = data->do_hierarchy;
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
@@ -903,8 +917,8 @@ static void id_override_library_reset_fn(bContext *C,
BKE_lib_override_library_id_reset(bmain, id_root);
}
- WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, NULL);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, nullptr);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
}
else {
CLOG_WARN(&LOG, "Could not reset library override of data block '%s'", id_root->name);
@@ -921,7 +935,7 @@ static void id_override_library_resync_fn(bContext *C,
{
BLI_assert(TSE_IS_REAL_ID(tselem));
ID *id_root = tselem->id;
- OutlinerLibOverrideData *data = user_data;
+ OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
const bool do_hierarchy_enforce = data->do_resync_hierarchy_enforce;
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
@@ -930,7 +944,7 @@ static void id_override_library_resync_fn(bContext *C,
id_root->tag |= LIB_TAG_DOIT;
/* Tag all linked parents in tree hierarchy to be also overridden. */
- while ((te = te->parent) != NULL) {
+ while ((te = te->parent) != nullptr) {
if (!TSE_IS_REAL_ID(te->store_elem)) {
continue;
}
@@ -940,16 +954,12 @@ static void id_override_library_resync_fn(bContext *C,
te->store_elem->id->tag |= LIB_TAG_DOIT;
}
- BKE_lib_override_library_resync(bmain,
- scene,
- CTX_data_view_layer(C),
- id_root,
- NULL,
- do_hierarchy_enforce,
- true,
- &(struct BlendFileReadReport){.reports = reports});
+ BlendFileReadReport report{};
+ report.reports = reports;
+ BKE_lib_override_library_resync(
+ bmain, scene, CTX_data_view_layer(C), id_root, nullptr, do_hierarchy_enforce, &report);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
else {
CLOG_WARN(&LOG, "Could not resync library override of data block '%s'", id_root->name);
@@ -973,7 +983,7 @@ static void id_override_library_delete_fn(bContext *C,
id_root->tag |= LIB_TAG_DOIT;
/* Tag all linked parents in tree hierarchy to be also overridden. */
- while ((te = te->parent) != NULL) {
+ while ((te = te->parent) != nullptr) {
if (!TSE_IS_REAL_ID(te->store_elem)) {
continue;
}
@@ -985,7 +995,7 @@ static void id_override_library_delete_fn(bContext *C,
BKE_lib_override_library_delete(bmain, id_root);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
else {
CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name);
@@ -1049,7 +1059,7 @@ static void singleuser_action_fn(bContext *C,
if (id) {
IdAdtTemplate *iat = (IdAdtTemplate *)tsep->id;
- PointerRNA ptr = {NULL};
+ PointerRNA ptr = {nullptr};
PropertyRNA *prop;
RNA_pointer_create(&iat->id, &RNA_AnimData, iat->adt, &ptr);
@@ -1072,7 +1082,7 @@ static void singleuser_world_fn(bContext *C,
/* need to use parent scene not just scene, otherwise may end up getting wrong one */
if (id) {
Scene *parscene = (Scene *)tsep->id;
- PointerRNA ptr = {NULL};
+ PointerRNA ptr = {nullptr};
PropertyRNA *prop;
RNA_id_pointer_create(&parscene->id, &ptr);
@@ -1082,10 +1092,6 @@ static void singleuser_world_fn(bContext *C,
}
}
-/**
- * \param recurse_selected: Set to false for operations which are already
- * recursively operating on their children.
- */
void outliner_do_object_operation_ex(bContext *C,
ReportList *reports,
Scene *scene_act,
@@ -1106,10 +1112,10 @@ void outliner_do_object_operation_ex(bContext *C,
WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), scene_owner);
}
/* Important to use 'scene_owner' not scene_act else deleting objects can crash.
- * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the
+ * only use 'scene_act' when 'scene_owner' is nullptr, which can happen when the
* outliner isn't showing scenes: Visible Layer draw mode for eg. */
operation_fn(
- C, reports, scene_owner ? scene_owner : scene_act, te, NULL, tselem, user_data);
+ C, reports, scene_owner ? scene_owner : scene_act, te, nullptr, tselem, user_data);
select_handled = true;
}
}
@@ -1121,7 +1127,7 @@ void outliner_do_object_operation_ex(bContext *C,
space_outliner,
&te->subtree,
operation_fn,
- NULL,
+ nullptr,
recurse_selected);
}
}
@@ -1136,7 +1142,7 @@ void outliner_do_object_operation(bContext *C,
outliner_operation_fn operation_fn)
{
outliner_do_object_operation_ex(
- C, reports, scene_act, space_outliner, lb, operation_fn, NULL, true);
+ C, reports, scene_act, space_outliner, lb, operation_fn, nullptr, true);
}
/** \} */
@@ -1159,8 +1165,8 @@ static void unlinkact_animdata_fn(int UNUSED(event),
TreeStoreElem *tselem,
void *UNUSED(arg))
{
- /* just set action to NULL */
- BKE_animdata_set_action(NULL, tselem->id, NULL);
+ /* just set action to nullptr */
+ BKE_animdata_set_action(nullptr, tselem->id, nullptr);
DEG_id_tag_update(tselem->id, ID_RECALC_ANIMATION);
}
@@ -1200,25 +1206,25 @@ static void refreshdrivers_animdata_fn(int UNUSED(event),
/** \name Object Operation Utilities
* \{ */
-typedef enum eOutliner_PropDataOps {
+enum eOutliner_PropDataOps {
OL_DOP_SELECT = 1,
OL_DOP_DESELECT,
OL_DOP_HIDE,
OL_DOP_UNHIDE,
OL_DOP_SELECT_LINKED,
-} eOutliner_PropDataOps;
+};
-typedef enum eOutliner_PropConstraintOps {
+enum eOutliner_PropConstraintOps {
OL_CONSTRAINTOP_ENABLE = 1,
OL_CONSTRAINTOP_DISABLE,
OL_CONSTRAINTOP_DELETE,
-} eOutliner_PropConstraintOps;
+};
-typedef enum eOutliner_PropModifierOps {
+enum eOutliner_PropModifierOps {
OL_MODIFIER_OP_TOGVIS = 1,
OL_MODIFIER_OP_TOGREN,
OL_MODIFIER_OP_DELETE,
-} eOutliner_PropModifierOps;
+};
static void pchan_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
{
@@ -1333,7 +1339,7 @@ static void data_select_linked_fn(int event,
if (event == OL_DOP_SELECT_LINKED) {
if (RNA_struct_is_ID(te->rnaptr.type)) {
bContext *C = (bContext *)C_v;
- ID *id = te->rnaptr.data;
+ ID *id = reinterpret_cast<ID *>(te->rnaptr.data);
ED_object_select_linked_by_id(C, id);
}
@@ -1342,7 +1348,7 @@ static void data_select_linked_fn(int event,
static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
{
- bContext *C = C_v;
+ bContext *C = reinterpret_cast<bContext *>(C_v);
Main *bmain = CTX_data_main(C);
bConstraint *constraint = (bConstraint *)te->directdata;
Object *ob = (Object *)outliner_search_back(te, ID_OB);
@@ -1358,7 +1364,7 @@ static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
}
else if (event == OL_CONSTRAINTOP_DELETE) {
- ListBase *lb = NULL;
+ ListBase *lb = nullptr;
if (TREESTORE(te->parent->parent)->type == TSE_POSE_CHANNEL) {
lb = &((bPoseChannel *)te->parent->parent->directdata)->constraints;
@@ -1369,7 +1375,7 @@ static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel
if (BKE_constraint_remove_ex(lb, ob, constraint, true)) {
/* there's no active constraint now, so make sure this is the case */
- BKE_constraints_active_set(&ob->constraints, NULL);
+ BKE_constraints_active_set(&ob->constraints, nullptr);
/* needed to set the flags on posebones correctly */
ED_object_constraint_update(bmain, ob);
@@ -1399,7 +1405,7 @@ static void modifier_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
else if (event == OL_MODIFIER_OP_DELETE) {
- ED_object_modifier_remove(NULL, bmain, scene, ob, md);
+ ED_object_modifier_remove(nullptr, bmain, scene, ob, md);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_REMOVED, ob);
te->store_elem->flag &= ~TSE_SELECTED;
}
@@ -1426,25 +1432,26 @@ static void outliner_do_data_operation(
}
}
-static Base *outline_batch_delete_hierarchy(
+static Base *outliner_batch_delete_hierarchy(
ReportList *reports, Main *bmain, ViewLayer *view_layer, Scene *scene, Base *base)
{
Base *child_base, *base_next;
Object *object, *parent;
if (!base) {
- return NULL;
+ return nullptr;
}
object = base->object;
- for (child_base = view_layer->object_bases.first; child_base; child_base = base_next) {
+ for (child_base = reinterpret_cast<Base *>(view_layer->object_bases.first); child_base;
+ child_base = base_next) {
base_next = child_base->next;
for (parent = child_base->object->parent; parent && (parent != object);
parent = parent->parent) {
/* pass */
}
if (parent) {
- base_next = outline_batch_delete_hierarchy(reports, bmain, view_layer, scene, child_base);
+ base_next = outliner_batch_delete_hierarchy(reports, bmain, view_layer, scene, child_base);
}
}
@@ -1497,7 +1504,7 @@ static void object_batch_delete_hierarchy_fn(bContext *C,
ED_object_editmode_exit(C, EM_FREEDATA);
}
- outline_batch_delete_hierarchy(reports, CTX_data_main(C), view_layer, scene, base);
+ outliner_batch_delete_hierarchy(reports, CTX_data_main(C), view_layer, scene, base);
}
}
@@ -1531,7 +1538,7 @@ static const EnumPropertyItem prop_object_op_types[] = {
0,
"Convert Proxy to Override",
"Convert a Proxy object to a full library override, including all its dependencies"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_object_operation_exec(bContext *C, wmOperator *op)
@@ -1541,11 +1548,11 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
wmWindow *win = CTX_wm_window(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int event;
- const char *str = NULL;
+ const char *str = nullptr;
bool selection_changed = false;
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -1570,7 +1577,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
object_select_hierarchy_fn,
- NULL,
+ nullptr,
false);
if (scene != sce) {
WM_window_set_active_scene(bmain, C, win, sce);
@@ -1586,7 +1593,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
}
else if (event == OL_OP_REMAP) {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
}
@@ -1615,7 +1622,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
ED_outliner_select_sync_from_object_tag(C);
}
- if (str != NULL) {
+ if (str != nullptr) {
ED_undo_push(C, str);
}
@@ -1644,13 +1651,13 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot)
/** \name Delete Object/Collection Operator
* \{ */
-typedef void (*OutlinerDeleteFunc)(bContext *C, ReportList *reports, Scene *scene, Object *ob);
+using OutlinerDeleteFn = void (*)(bContext *C, ReportList *reports, Scene *scene, Object *ob);
static void outliner_do_object_delete(bContext *C,
ReportList *reports,
Scene *scene,
GSet *objects_to_delete,
- OutlinerDeleteFunc delete_fn)
+ OutlinerDeleteFn delete_fn)
{
GSetIterator objects_to_delete_iter;
GSET_ITER (objects_to_delete_iter, objects_to_delete) {
@@ -1669,7 +1676,8 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void
return TRAVERSE_CONTINUE;
}
- if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
+ if ((tselem->type != TSE_SOME_ID) || (tselem->id == nullptr) ||
+ (GS(tselem->id->name) != ID_OB)) {
return TRAVERSE_SKIP_CHILDS;
}
@@ -1678,6 +1686,8 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void
return TRAVERSE_CONTINUE;
}
+/* FIXME: See comment above #WM_msg_publish_rna_prop(). */
+extern "C" {
static int outliner_delete_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -1711,7 +1721,7 @@ static int outliner_delete_exec(bContext *C, wmOperator *op)
outliner_do_object_delete(C, op->reports, scene, objects_to_delete, outliner_object_delete_fn);
}
- BLI_gset_free(objects_to_delete, NULL);
+ BLI_gset_free(objects_to_delete, nullptr);
outliner_collection_delete(C, bmain, scene, op->reports, delete_hierarchy);
@@ -1737,6 +1747,7 @@ static int outliner_delete_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+}
void OUTLINER_OT_delete(wmOperatorType *ot)
{
@@ -1764,7 +1775,7 @@ void OUTLINER_OT_delete(wmOperatorType *ot)
/** \name ID-Data Menu Operator
* \{ */
-typedef enum eOutlinerIdOpTypes {
+enum eOutlinerIdOpTypes {
OUTLINER_IDOP_INVALID = 0,
OUTLINER_IDOP_UNLINK,
@@ -1789,7 +1800,7 @@ typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_RENAME,
OUTLINER_IDOP_SELECT_LINKED,
-} eOutlinerIdOpTypes;
+};
/* TODO: implement support for changing the ID-block used. */
static const EnumPropertyItem prop_id_op_types[] = {
@@ -1802,7 +1813,7 @@ static const EnumPropertyItem prop_id_op_types[] = {
0,
"Remap Users",
"Make all users of selected data-blocks to use instead current (clicked) one"},
- {0, "", 0, NULL, NULL},
+ {0, "", 0, nullptr, nullptr},
{OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
"OVERRIDE_LIBRARY_CREATE",
0,
@@ -1847,10 +1858,10 @@ static const EnumPropertyItem prop_id_op_types[] = {
"Delete Library Override Hierarchy",
"Delete this local override (including its hierarchy of override dependencies) and relink "
"its usages to the linked data-blocks"},
- {0, "", 0, NULL, NULL},
+ {0, "", 0, nullptr, nullptr},
{OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""},
{OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""},
- {0, "", 0, NULL, NULL},
+ {0, "", 0, nullptr, nullptr},
{OUTLINER_IDOP_FAKE_ADD,
"ADD_FAKE",
0,
@@ -1860,7 +1871,7 @@ static const EnumPropertyItem prop_id_op_types[] = {
{OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""},
{OUTLINER_IDOP_RENAME, "RENAME", 0, "Rename", ""},
{OUTLINER_IDOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static bool outliner_id_operation_item_poll(bContext *C,
@@ -1868,6 +1879,10 @@ static bool outliner_id_operation_item_poll(bContext *C,
PropertyRNA *UNUSED(prop),
const int enum_value)
{
+ if (!outliner_operation_tree_element_poll(C)) {
+ return false;
+ }
+
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
TreeElement *te = get_target_element(space_outliner);
TreeStoreElem *tselem = TREESTORE(te);
@@ -1890,7 +1905,7 @@ static bool outliner_id_operation_item_poll(bContext *C,
if (GS(tselem->id->name) == ID_OB) {
Object *ob = (Object *)tselem->id;
- if ((ob != NULL) && (ob->proxy != NULL)) {
+ if ((ob != nullptr) && (ob->proxy != nullptr)) {
return true;
}
}
@@ -1922,13 +1937,13 @@ static const EnumPropertyItem *outliner_id_operation_itemf(bContext *C,
PropertyRNA *prop,
bool *r_free)
{
- EnumPropertyItem *items = NULL;
+ EnumPropertyItem *items = nullptr;
int totitem = 0;
- if ((C == NULL) || (ED_operator_outliner_active(C) == false)) {
+ if ((C == nullptr) || (ED_operator_outliner_active(C) == false)) {
return prop_id_op_types;
}
- for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != NULL; it++) {
+ for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != nullptr; it++) {
if (!outliner_id_operation_item_poll(C, ptr, prop, it->value)) {
continue;
}
@@ -1948,22 +1963,27 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
- eOutlinerIdOpTypes event = RNA_enum_get(op->ptr, "type");
+ eOutlinerIdOpTypes event = (eOutlinerIdOpTypes)RNA_enum_get(op->ptr, "type");
switch (event) {
case OUTLINER_IDOP_UNLINK: {
/* unlink datablock from its parent */
if (objectlevel) {
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, unlink_object_fn, NULL);
-
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL);
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ unlink_object_fn,
+ nullptr);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, nullptr);
ED_undo_push(C, "Unlink Object");
break;
}
@@ -1976,9 +1996,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
unlink_action_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Unlink action");
break;
case ID_MA:
@@ -1988,9 +2008,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
unlink_material_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, nullptr);
ED_undo_push(C, "Unlink material");
break;
case ID_TE:
@@ -2000,16 +2020,21 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
unlink_texture_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, nullptr);
ED_undo_push(C, "Unlink texture");
break;
case ID_WO:
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, unlink_world_fn, NULL);
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ unlink_world_fn,
+ nullptr);
- WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_WORLD, nullptr);
ED_undo_push(C, "Unlink world");
break;
case ID_GR:
@@ -2019,9 +2044,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
unlink_collection_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, nullptr);
ED_undo_push(C, "Unlink Collection");
break;
default:
@@ -2033,29 +2058,32 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_LOCAL: {
/* make local */
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_local_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_local_fn, nullptr);
ED_undo_push(C, "Localized Data");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE: {
+ OutlinerLibOverrideData override_data{};
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_create_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = false});
+ &override_data);
ED_undo_push(C, "Overridden Data");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_create_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true});
+ &override_data);
ED_undo_push(C, "Overridden Data Hierarchy");
break;
}
@@ -2070,58 +2098,67 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: {
+ OutlinerLibOverrideData override_data{};
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_reset_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = false});
+ &override_data);
ED_undo_push(C, "Reset Overridden Data");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_reset_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true});
+ &override_data);
ED_undo_push(C, "Reset Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_resync_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true});
+ &override_data);
ED_undo_push(C, "Resync Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE: {
- outliner_do_libdata_operation(
- C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_override_library_resync_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true, .do_resync_hierarchy_enforce = true});
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
+ override_data.do_resync_hierarchy_enforce = true;
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ id_override_library_resync_fn,
+ &override_data);
ED_undo_push(C, "Resync Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_delete_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true});
+ &override_data);
ED_undo_push(C, "Delete Overridden Data Hierarchy");
break;
}
@@ -2135,9 +2172,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
singleuser_action_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Single-User Action");
break;
@@ -2148,9 +2185,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
singleuser_world_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_WORLD, nullptr);
ED_undo_push(C, "Single-User World");
break;
@@ -2163,7 +2200,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_DELETE: {
if (idlevel > 0) {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, nullptr);
ED_undo_push(C, "Delete");
}
break;
@@ -2171,7 +2208,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_REMAP: {
if (idlevel > 0) {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
}
@@ -2179,14 +2216,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
case OUTLINER_IDOP_COPY: {
wm->op_undo_depth++;
- WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, NULL);
+ WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, nullptr);
wm->op_undo_depth--;
/* No need for undo, this operation does not change anything... */
break;
}
case OUTLINER_IDOP_PASTE: {
wm->op_undo_depth++;
- WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, NULL);
+ WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, nullptr);
wm->op_undo_depth--;
ED_outliner_select_sync_from_all_tag(C);
ED_undo_push(C, "Paste");
@@ -2194,10 +2231,15 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
case OUTLINER_IDOP_FAKE_ADD: {
/* set fake user */
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_fake_user_set_fn, NULL);
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ id_fake_user_set_fn,
+ nullptr);
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Add Fake User");
break;
}
@@ -2209,24 +2251,29 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
id_fake_user_clear_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Clear Fake User");
break;
}
case OUTLINER_IDOP_RENAME: {
/* rename */
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, nullptr);
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Rename");
break;
}
case OUTLINER_IDOP_SELECT_LINKED:
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_select_linked_fn, NULL);
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ id_select_linked_fn,
+ nullptr);
ED_outliner_select_sync_from_all_tag(C);
ED_undo_push(C, "Select");
break;
@@ -2237,10 +2284,10 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
/* wrong notifier still... */
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
/* XXX: this is just so that outliner is always up to date. */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr);
return OPERATOR_FINISHED;
}
@@ -2254,7 +2301,7 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot)
/* callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = outliner_id_operation_exec;
- ot->poll = ED_operator_outliner_active;
+ ot->poll = outliner_operation_tree_element_poll;
ot->flag = 0;
@@ -2268,14 +2315,14 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot)
/** \name Library Menu Operator
* \{ */
-typedef enum eOutlinerLibOpTypes {
+enum eOutlinerLibOpTypes {
OL_LIB_INVALID = 0,
OL_LIB_RENAME,
OL_LIB_DELETE,
OL_LIB_RELOCATE,
OL_LIB_RELOAD,
-} eOutlinerLibOpTypes;
+};
static const EnumPropertyItem outliner_lib_op_type_items[] = {
{OL_LIB_RENAME, "RENAME", 0, "Rename", ""},
@@ -2291,7 +2338,7 @@ static const EnumPropertyItem outliner_lib_op_type_items[] = {
"Relocate",
"Select a new path for this library, and reload all its data"},
{OL_LIB_RELOAD, "RELOAD", ICON_FILE_REFRESH, "Reload", "Reload all data from this library"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
@@ -2301,39 +2348,39 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
- eOutlinerLibOpTypes event = RNA_enum_get(op->ptr, "type");
+ eOutlinerLibOpTypes event = (eOutlinerLibOpTypes)RNA_enum_get(op->ptr, "type");
switch (event) {
case OL_LIB_RENAME: {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, nullptr);
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Rename Library");
break;
}
case OL_LIB_DELETE: {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, nullptr);
ED_undo_push(C, "Delete Library");
break;
}
case OL_LIB_RELOCATE: {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, lib_relocate_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, lib_relocate_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
break;
}
case OL_LIB_RELOAD: {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, lib_reload_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, lib_reload_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
break;
@@ -2344,10 +2391,10 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
}
/* wrong notifier still... */
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
/* XXX: this is just so that outliner is always up to date */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr);
return OPERATOR_FINISHED;
}
@@ -2361,7 +2408,7 @@ void OUTLINER_OT_lib_operation(wmOperatorType *ot)
/* callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = outliner_lib_operation_exec;
- ot->poll = ED_operator_outliner_active;
+ ot->poll = outliner_operation_tree_element_poll;
ot->prop = RNA_def_enum(
ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", "");
@@ -2384,7 +2431,7 @@ static void outliner_do_id_set_operation(
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
if (tselem->type == type) {
- TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
+ TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : nullptr;
operation_fn(te, tselem, tsep, newid);
}
}
@@ -2403,14 +2450,14 @@ static void actionset_id_fn(TreeElement *UNUSED(te),
if (tselem->type == TSE_ANIM_DATA) {
/* "animation" entries - action is child of this */
- BKE_animdata_set_action(NULL, tselem->id, act);
+ BKE_animdata_set_action(nullptr, tselem->id, act);
}
/* TODO: if any other "expander" channels which own actions need to support this menu,
* add: tselem->type = ...
*/
else if (tsep && (tsep->type == TSE_ANIM_DATA)) {
/* "animation" entries case again */
- BKE_animdata_set_action(NULL, tsep->id, act);
+ BKE_animdata_set_action(nullptr, tsep->id, act);
}
/* TODO: other cases not supported yet. */
}
@@ -2420,21 +2467,16 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
-
bAction *act;
- /* check for invalid states */
- if (space_outliner == NULL) {
- return OPERATOR_CANCELLED;
- }
-
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
/* get action to use */
- act = BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action"));
+ act = reinterpret_cast<bAction *>(
+ BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action")));
- if (act == NULL) {
+ if (act == nullptr) {
BKE_report(op->reports, RPT_ERROR, "No valid action to add");
return OPERATOR_CANCELLED;
}
@@ -2463,7 +2505,7 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op)
}
/* set notifier that things have changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Set action");
/* done */
@@ -2482,7 +2524,7 @@ void OUTLINER_OT_action_set(wmOperatorType *ot)
/* api callbacks */
ot->invoke = WM_enum_search_invoke;
ot->exec = outliner_action_set_exec;
- ot->poll = ED_operator_outliner_active;
+ ot->poll = outliner_operation_tree_element_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2501,7 +2543,7 @@ void OUTLINER_OT_action_set(wmOperatorType *ot)
/** \name Animation Menu Operator
* \{ */
-typedef enum eOutliner_AnimDataOps {
+enum eOutliner_AnimDataOps {
OUTLINER_ANIMOP_INVALID = 0,
OUTLINER_ANIMOP_CLEAR_ADT,
@@ -2511,7 +2553,7 @@ typedef enum eOutliner_AnimDataOps {
OUTLINER_ANIMOP_REFRESH_DRV,
OUTLINER_ANIMOP_CLEAR_DRV
-} eOutliner_AnimDataOps;
+};
static const EnumPropertyItem prop_animdata_op_types[] = {
{OUTLINER_ANIMOP_CLEAR_ADT,
@@ -2523,7 +2565,7 @@ static const EnumPropertyItem prop_animdata_op_types[] = {
{OUTLINER_ANIMOP_CLEAR_ACT, "CLEAR_ACT", 0, "Unlink Action", ""},
{OUTLINER_ANIMOP_REFRESH_DRV, "REFRESH_DRIVERS", 0, "Refresh Drivers", ""},
{OUTLINER_ANIMOP_CLEAR_DRV, "CLEAR_DRIVERS", 0, "Clear Drivers", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
@@ -2531,12 +2573,6 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
wmWindowManager *wm = CTX_wm_manager(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
-
- /* check for invalid states */
- if (space_outliner == NULL) {
- return OPERATOR_CANCELLED;
- }
-
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
@@ -2545,21 +2581,21 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
}
/* perform the core operation */
- eOutliner_AnimDataOps event = RNA_enum_get(op->ptr, "type");
+ eOutliner_AnimDataOps event = (eOutliner_AnimDataOps)RNA_enum_get(op->ptr, "type");
switch (event) {
case OUTLINER_ANIMOP_CLEAR_ADT:
/* Remove Animation Data - this may remove the active action, in some cases... */
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, clear_animdata_fn, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, clear_animdata_fn, nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Clear Animation Data");
break;
case OUTLINER_ANIMOP_SET_ACT:
/* delegate once again... */
wm->op_undo_depth++;
- WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL);
+ WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, nullptr);
wm->op_undo_depth--;
ED_undo_push(C, "Set active action");
break;
@@ -2567,9 +2603,9 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_ANIMOP_CLEAR_ACT:
/* clear active action - using standard rules */
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, unlinkact_animdata_fn, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, unlinkact_animdata_fn, nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Unlink action");
break;
@@ -2579,17 +2615,21 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
event,
&space_outliner->tree,
refreshdrivers_animdata_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr);
/* ED_undo_push(C, "Refresh Drivers"); No undo needed - shouldn't have any impact? */
break;
case OUTLINER_ANIMOP_CLEAR_DRV:
- outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, cleardrivers_animdata_fn, NULL);
+ outliner_do_data_operation(space_outliner,
+ datalevel,
+ event,
+ &space_outliner->tree,
+ cleardrivers_animdata_fn,
+ nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr);
ED_undo_push(C, "Clear Drivers");
break;
@@ -2629,13 +2669,13 @@ static const EnumPropertyItem prop_constraint_op_types[] = {
{OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""},
{OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_HIDE_ON, "Disable", ""},
{OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_constraint_operation_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- eOutliner_PropConstraintOps event = RNA_enum_get(op->ptr, "type");
+ eOutliner_PropConstraintOps event = (eOutliner_PropConstraintOps)RNA_enum_get(op->ptr, "type");
outliner_do_data_operation(
space_outliner, TSE_CONSTRAINT, event, &space_outliner->tree, constraint_fn, C);
@@ -2676,13 +2716,13 @@ static const EnumPropertyItem prop_modifier_op_types[] = {
{OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle Viewport Use", ""},
{OL_MODIFIER_OP_TOGREN, "TOGREN", ICON_RESTRICT_RENDER_OFF, "Toggle Render Use", ""},
{OL_MODIFIER_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_modifier_operation_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- eOutliner_PropModifierOps event = RNA_enum_get(op->ptr, "type");
+ eOutliner_PropModifierOps event = (eOutliner_PropModifierOps)RNA_enum_get(op->ptr, "type");
outliner_do_data_operation(
space_outliner, TSE_MODIFIER, event, &space_outliner->tree, modifier_fn, C);
@@ -2722,37 +2762,31 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
-
- /* check for invalid states */
- if (space_outliner == NULL) {
- return OPERATOR_CANCELLED;
- }
-
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
- eOutliner_PropDataOps event = RNA_enum_get(op->ptr, "type");
+ eOutliner_PropDataOps event = (eOutliner_PropDataOps)RNA_enum_get(op->ptr, "type");
switch (datalevel) {
case TSE_POSE_CHANNEL: {
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, pchan_fn, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, pchan_fn, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
ED_undo_push(C, "PoseChannel operation");
break;
}
case TSE_BONE: {
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, bone_fn, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, bone_fn, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
ED_undo_push(C, "Bone operation");
break;
}
case TSE_EBONE: {
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, ebone_fn, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, ebone_fn, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
ED_undo_push(C, "EditBone operation");
break;
@@ -2768,8 +2802,8 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
}
case TSE_GP_LAYER: {
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, gpencil_layer_fn, NULL);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, gpencil_layer_fn, nullptr);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, nullptr);
ED_undo_push(C, "Grease Pencil Layer operation");
break;
@@ -2797,27 +2831,32 @@ static const EnumPropertyItem *outliner_data_op_sets_enum_item_fn(bContext *C,
bool *UNUSED(r_free))
{
/* Check for invalid states. */
- if (C == NULL) {
+ if (C == nullptr) {
return DummyRNA_DEFAULT_items;
}
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return DummyRNA_DEFAULT_items;
}
+ TreeElement *te = get_target_element(space_outliner);
+ if (te == nullptr) {
+ return DummyRNA_NULL_items;
+ }
+
+ TreeStoreElem *tselem = TREESTORE(te);
+
static const EnumPropertyItem optype_sel_and_hide[] = {
{OL_DOP_SELECT, "SELECT", 0, "Select", ""},
{OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""},
{OL_DOP_HIDE, "HIDE", 0, "Hide", ""},
{OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""},
- {0, NULL, 0, NULL, NULL}};
+ {0, nullptr, 0, nullptr, nullptr}};
static const EnumPropertyItem optype_sel_linked[] = {
- {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, {0, NULL, 0, NULL, NULL}};
-
- TreeElement *te = get_target_element(space_outliner);
- TreeStoreElem *tselem = TREESTORE(te);
+ {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
+ {0, nullptr, 0, nullptr, nullptr}};
if (tselem->type == TSE_RNA_STRUCT) {
return optype_sel_linked;
@@ -2835,7 +2874,7 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot)
/* callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = outliner_data_operation_exec;
- ot->poll = ED_operator_outliner_active;
+ ot->poll = outliner_operation_tree_element_poll;
ot->flag = 0;
@@ -2852,7 +2891,7 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot)
static int outliner_operator_menu(bContext *C, const char *opname)
{
wmOperatorType *ot = WM_operatortype_find(opname, false);
- uiPopupMenu *pup = UI_popup_menu_begin(C, WM_operatortype_name(ot, NULL), ICON_NONE);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, WM_operatortype_name(ot, nullptr), ICON_NONE);
uiLayout *layout = UI_popup_menu_layout(pup);
/* set this so the default execution context is the same as submenus */
@@ -2981,7 +3020,6 @@ static int outliner_operation(bContext *C, wmOperator *op, const wmEvent *event)
return do_outliner_operation_event(C, op->reports, region, space_outliner, hovered_te);
}
-/* Menu only! Calls other operators */
void OUTLINER_OT_operation(wmOperatorType *ot)
{
ot->name = "Context Menu";
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.cc
index 5427ae31ac3..be792be95a9 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.cc
@@ -21,8 +21,8 @@
* \ingroup spoutliner
*/
-#include <math.h>
-#include <string.h>
+#include <cmath>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -74,15 +74,19 @@
#include "RNA_access.h"
#include "UI_interface.h"
+#include "UI_resources.h"
-#include "outliner_intern.h"
-#include "tree/tree_display.h"
-#include "tree/tree_element.h"
+#include "outliner_intern.hh"
+#include "tree/common.hh"
+#include "tree/tree_display.hh"
+#include "tree/tree_element.hh"
#ifdef WIN32
# include "BLI_math_base.h" /* M_PI */
#endif
+using namespace blender::ed::outliner;
+
/* prototypes */
static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner);
@@ -101,7 +105,7 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
BLI_mempool_iter iter;
BLI_mempool_iternew(ts, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
+ while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
tselem->used = 0;
}
@@ -111,8 +115,8 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
space_outliner->storeflag &= ~SO_TREESTORE_CLEANUP;
BLI_mempool_iternew(ts, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- if (tselem->id == NULL) {
+ while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
+ if (tselem->id == nullptr) {
unused++;
}
}
@@ -120,10 +124,10 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
if (unused) {
if (BLI_mempool_len(ts) == unused) {
BLI_mempool_destroy(ts);
- space_outliner->treestore = NULL;
+ space_outliner->treestore = nullptr;
if (space_outliner->runtime->treehash) {
BKE_outliner_treehash_free(space_outliner->runtime->treehash);
- space_outliner->runtime->treehash = NULL;
+ space_outliner->runtime->treehash = nullptr;
}
}
else {
@@ -131,9 +135,9 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
BLI_mempool *new_ts = BLI_mempool_create(
sizeof(TreeStoreElem), BLI_mempool_len(ts) - unused, 512, BLI_MEMPOOL_ALLOW_ITER);
BLI_mempool_iternew(ts, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
+ while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
if (tselem->id) {
- tsenew = BLI_mempool_alloc(new_ts);
+ tsenew = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(new_ts));
*tsenew = *tselem;
}
}
@@ -156,14 +160,14 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
static void check_persistent(
SpaceOutliner *space_outliner, TreeElement *te, ID *id, short type, short nr)
{
- if (space_outliner->treestore == NULL) {
+ if (space_outliner->treestore == nullptr) {
/* if treestore was not created in readfile.c, create it here */
space_outliner->treestore = BLI_mempool_create(
sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
}
- if (space_outliner->runtime->treehash == NULL) {
- space_outliner->runtime->treehash = BKE_outliner_treehash_create_from_treestore(
- space_outliner->treestore);
+ if (space_outliner->runtime->treehash == nullptr) {
+ space_outliner->runtime->treehash = reinterpret_cast<GHash *>(
+ BKE_outliner_treehash_create_from_treestore(space_outliner->treestore));
}
/* find any unused tree element in treestore and mark it as used
@@ -177,7 +181,7 @@ static void check_persistent(
}
/* add 1 element to treestore */
- tselem = BLI_mempool_alloc(space_outliner->treestore);
+ tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(space_outliner->treestore));
tselem->type = type;
tselem->nr = type ? nr : 0;
tselem->id = id;
@@ -203,12 +207,6 @@ void outliner_cleanup_tree(SpaceOutliner *space_outliner)
outliner_storage_cleanup(space_outliner);
}
-/**
- * Free \a element and its sub-tree and remove its link in \a parent_subtree.
- *
- * \note Does not remove the #TreeStoreElem of \a element!
- * \param parent_subtree: Sub-tree of the parent element, so the list containing \a element.
- */
void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree)
{
BLI_assert(BLI_findindex(parent_subtree, element) > -1);
@@ -219,8 +217,8 @@ void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree)
if (element->flag & TE_FREE_NAME) {
MEM_freeN((void *)element->name);
}
- outliner_tree_element_type_free(&element->type);
- MEM_freeN(element);
+ element->type = nullptr;
+ MEM_delete(element);
}
/* ********************************************************* */
@@ -235,10 +233,6 @@ bool outliner_requires_rebuild_on_select_or_active_change(const SpaceOutliner *s
return exclude_flags & (SO_FILTER_OB_STATE_SELECTED | SO_FILTER_OB_STATE_ACTIVE);
}
-/**
- * Check if a display mode needs a full rebuild if the open/collapsed state changes.
- * Element types in these modes don't actually add children if collapsed, so the rebuild is needed.
- */
bool outliner_requires_rebuild_on_open_change(const SpaceOutliner *space_outliner)
{
return ELEM(space_outliner->outlinevis, SO_DATA_API);
@@ -263,14 +257,6 @@ static void outliner_add_bone(SpaceOutliner *space_outliner,
}
}
-bool outliner_animdata_test(const AnimData *adt)
-{
- if (adt) {
- return (adt->action || adt->drivers.first || adt->nla_tracks.first);
- }
- return false;
-}
-
#ifdef WITH_FREESTYLE
static void outliner_add_line_styles(SpaceOutliner *space_outliner,
ListBase *lb,
@@ -323,13 +309,13 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0);
if (ob->pose) {
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
TreeElement *tenla = outliner_add_element(
space_outliner, &te->subtree, ob, te, TSE_POSE_BASE, 0);
tenla->name = IFACE_("Pose");
/* channels undefined in editmode, but we want the 'tenla' pose icon itself */
- if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) {
+ if ((arm->edbo == nullptr) && (ob->mode & OB_MODE_POSE)) {
int const_index = 1000; /* ensure unique id for bone constraints */
int a;
LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob->pose->chanbase, a) {
@@ -369,7 +355,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
}
}
/* make hierarchy */
- TreeElement *ten = tenla->subtree.first;
+ TreeElement *ten = reinterpret_cast<TreeElement *>(tenla->subtree.first);
while (ten) {
TreeElement *nten = ten->next, *par;
tselem = TREESTORE(ten);
@@ -724,13 +710,15 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
ebone->temp.p = ten;
}
/* make hierarchy */
- TreeElement *ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL;
+ TreeElement *ten = arm->edbo->first ? reinterpret_cast<TreeElement *>(
+ ((EditBone *)arm->edbo->first)->temp.p) :
+ nullptr;
while (ten) {
TreeElement *nten = ten->next, *par;
EditBone *ebone = (EditBone *)ten->directdata;
if (ebone->parent) {
BLI_remlink(&te->subtree, ten);
- par = ebone->parent->temp.p;
+ par = reinterpret_cast<TreeElement *>(ebone->parent->temp.p);
BLI_addtail(&par->subtree, ten);
ten->parent = par;
}
@@ -822,13 +810,8 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
}
-/**
- * TODO: this function needs to be split up! It's getting a bit too large...
- *
- * \note "ID" is not always a real ID.
- * \note If child items are only added to the tree if the item is open,
- * the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change().
- */
+namespace blender::ed::outliner {
+
TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
ListBase *lb,
void *idv,
@@ -836,16 +819,16 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
short type,
short index)
{
- ID *id = idv;
+ ID *id = reinterpret_cast<ID *>(idv);
if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
id = ((PointerRNA *)idv)->owner_id;
if (!id) {
- id = ((PointerRNA *)idv)->data;
+ id = reinterpret_cast<ID *>(((PointerRNA *)idv)->data);
}
}
else if (type == TSE_GP_LAYER) {
- /* idv is the layer its self */
+ /* idv is the layer itself */
id = TREESTORE(parent)->id;
}
@@ -853,8 +836,8 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
if (type == TSE_ID_BASE) {
/* pass */
}
- else if (id == NULL) {
- return NULL;
+ else if (id == nullptr) {
+ return nullptr;
}
if (type == 0) {
@@ -862,7 +845,7 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
BLI_assert(TREESTORE_ID_TYPE(id));
}
- TreeElement *te = MEM_callocN(sizeof(TreeElement), __func__);
+ TreeElement *te = MEM_new<TreeElement>(__func__);
/* add to the visual tree */
BLI_addtail(lb, te);
/* add to the storage */
@@ -877,12 +860,12 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
te->parent = parent;
te->index = index; /* For data arrays. */
- /* New C++ based type handle (`TreeElementType` in C, `AbstractTreeElement` in C++). Only some
- * support this, eventually this should replace `TreeElement` entirely. */
- te->type = outliner_tree_element_type_create(type, te, idv);
+ /* New C++ based type handle. Only some support this, eventually this should replace
+ * `TreeElement` entirely. */
+ te->type = AbstractTreeElement::createFromType(type, *te, idv);
if (te->type) {
/* Element types ported to the new design are expected to have their name set at this point! */
- BLI_assert(te->name != NULL);
+ BLI_assert(te->name != nullptr);
}
if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
@@ -926,14 +909,14 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
te->idcode = GS(id->name);
}
- if (te->type && outliner_tree_element_type_is_expand_valid(te->type)) {
- outliner_tree_element_type_expand(te->type, space_outliner);
+ if (te->type && te->type->isExpandValid()) {
+ tree_element_expand(*te->type, *space_outliner);
}
else if (type == TSE_SOME_ID) {
/* ID types not (fully) ported to new design yet. */
- if (outliner_tree_element_type_expand_poll(te->type, space_outliner)) {
+ if (te->type->expandPoll(*space_outliner)) {
outliner_add_id_contents(space_outliner, te, tselem, id);
- outliner_tree_element_type_post_expand(te->type, space_outliner);
+ te->type->postExpand(*space_outliner);
}
}
else if (ELEM(type,
@@ -994,147 +977,16 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
te->directdata = seq;
te->name = seq->strip->stripdata->name;
}
- else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
- PointerRNA *ptr = (PointerRNA *)idv;
-
- /* Don't display arrays larger, weak but index is stored as a short,
- * also the outliner isn't intended for editing such large data-sets. */
- BLI_STATIC_ASSERT(sizeof(te->index) == 2, "Index is no longer short!")
- const int tot_limit = SHRT_MAX;
-
- /* we do lazy build, for speed and to avoid infinite recursion */
-
- if (ptr->data == NULL) {
- te->name = IFACE_("(empty)");
- }
- else if (type == TSE_RNA_STRUCT) {
- /* struct */
- te->name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL);
-
- if (te->name) {
- te->flag |= TE_FREE_NAME;
- }
- else {
- te->name = RNA_struct_ui_name(ptr->type);
- }
-
- /* If searching don't expand RNA entries */
- if (SEARCHING_OUTLINER(space_outliner) && BLI_strcasecmp("RNA", te->name) == 0) {
- tselem->flag &= ~TSE_CHILDSEARCH;
- }
-
- PropertyRNA *iterprop = RNA_struct_iterator_property(ptr->type);
- int tot = RNA_property_collection_length(ptr, iterprop);
- CLAMP_MAX(tot, tot_limit);
-
- /* auto open these cases */
- if (!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER) {
- if (!tselem->used) {
- tselem->flag &= ~TSE_CLOSED;
- }
- }
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- for (int a = 0; a < tot; a++) {
- PointerRNA propptr;
- RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr);
- if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a);
- }
- }
- }
- else if (tot) {
- te->flag |= TE_LAZY_CLOSED;
- }
-
- te->rnaptr = *ptr;
- }
- else if (type == TSE_RNA_PROPERTY) {
- /* property */
- PointerRNA propptr;
- PropertyRNA *iterprop = RNA_struct_iterator_property(ptr->type);
- RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr);
-
- PropertyRNA *prop = propptr.data;
- PropertyType proptype = RNA_property_type(prop);
-
- te->name = RNA_property_ui_name(prop);
- te->directdata = prop;
- te->rnaptr = *ptr;
-
- /* If searching don't expand RNA entries */
- if (SEARCHING_OUTLINER(space_outliner) && BLI_strcasecmp("RNA", te->name) == 0) {
- tselem->flag &= ~TSE_CHILDSEARCH;
- }
- if (proptype == PROP_POINTER) {
- PointerRNA pptr = RNA_property_pointer_get(ptr, prop);
-
- if (pptr.data) {
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, -1);
- }
- else {
- te->flag |= TE_LAZY_CLOSED;
- }
- }
- }
- else if (proptype == PROP_COLLECTION) {
- int tot = RNA_property_collection_length(ptr, prop);
- CLAMP_MAX(tot, tot_limit);
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- for (int a = 0; a < tot; a++) {
- PointerRNA pptr;
- RNA_property_collection_lookup_int(ptr, prop, a, &pptr);
- outliner_add_element(
- space_outliner, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, a);
- }
- }
- else if (tot) {
- te->flag |= TE_LAZY_CLOSED;
- }
- }
- else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
- int tot = RNA_property_array_length(ptr, prop);
- CLAMP_MAX(tot, tot_limit);
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- for (int a = 0; a < tot; a++) {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)ptr, te, TSE_RNA_ARRAY_ELEM, a);
- }
- }
- else if (tot) {
- te->flag |= TE_LAZY_CLOSED;
- }
- }
- }
- else if (type == TSE_RNA_ARRAY_ELEM) {
- PropertyRNA *prop = parent->directdata;
-
- te->directdata = prop;
- te->rnaptr = *ptr;
- te->index = index;
-
- char c = RNA_property_array_item_char(prop, index);
-
- te->name = MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName");
- if (c) {
- sprintf((char *)te->name, " %c", c);
- }
- else {
- sprintf((char *)te->name, " %d", index + 1);
- }
- te->flag |= TE_FREE_NAME;
- }
+ if (tree_element_warnings_get(te, nullptr, nullptr)) {
+ te->flag |= TE_HAS_WARNING;
}
return te;
}
+} // namespace blender::ed::outliner
+
/* ======================================================= */
BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collection)
@@ -1174,44 +1026,20 @@ TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
/* ======================================================= */
/* Generic Tree Building helpers - order these are called is top to bottom */
-/* Hierarchy --------------------------------------------- */
-
-/* make sure elements are correctly nested */
-void outliner_make_object_parent_hierarchy(ListBase *lb)
-{
- /* build hierarchy */
- /* XXX also, set extents here... */
- TreeElement *te = lb->first;
- while (te) {
- TreeElement *ten = te->next;
- TreeStoreElem *tselem = TREESTORE(te);
-
- if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) {
- Object *ob = (Object *)tselem->id;
- if (ob->parent && ob->parent->id.newid) {
- BLI_remlink(lb, te);
- TreeElement *tep = (TreeElement *)ob->parent->id.newid;
- BLI_addtail(&tep->subtree, te);
- te->parent = tep;
- }
- }
- te = ten;
- }
-}
-
/* Sorting ------------------------------------------------------ */
-typedef struct tTreeSort {
+struct tTreeSort {
TreeElement *te;
ID *id;
const char *name;
short idcode;
-} tTreeSort;
+};
/* alphabetical comparator, trying to put objects first */
static int treesort_alpha_ob(const void *v1, const void *v2)
{
- const tTreeSort *x1 = v1, *x2 = v2;
+ const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
+ const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
/* first put objects last (hierarchy) */
int comp = (x1->idcode == ID_OB);
@@ -1249,7 +1077,8 @@ static int treesort_alpha_ob(const void *v1, const void *v2)
/* Move children that are not in the collection to the end of the list. */
static int treesort_child_not_in_collection(const void *v1, const void *v2)
{
- const tTreeSort *x1 = v1, *x2 = v2;
+ const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
+ const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
/* Among objects first come the ones in the collection, followed by the ones not on it.
* This way we can have the dashed lines in a separate style connecting the former. */
@@ -1262,7 +1091,8 @@ static int treesort_child_not_in_collection(const void *v1, const void *v2)
/* alphabetical comparator */
static int treesort_alpha(const void *v1, const void *v2)
{
- const tTreeSort *x1 = v1, *x2 = v2;
+ const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
+ const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
int comp = BLI_strcasecmp_natural(x1->name, x2->name);
@@ -1319,24 +1149,25 @@ static int treesort_obtype_alpha(const void *v1, const void *v2)
/* sort happens on each subtree individual */
static void outliner_sort(ListBase *lb)
{
- TreeElement *te = lb->last;
- if (te == NULL) {
+ TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last);
+ if (last_te == nullptr) {
return;
}
- TreeStoreElem *tselem = TREESTORE(te);
+ TreeStoreElem *last_tselem = TREESTORE(last_te);
/* Sorting rules; only object lists, ID lists, or deform-groups. */
- if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) ||
- ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) {
+ if (ELEM(last_tselem->type, TSE_DEFGROUP, TSE_ID_BASE) ||
+ ((last_tselem->type == TSE_SOME_ID) && (last_te->idcode == ID_OB))) {
int totelem = BLI_listbase_count(lb);
if (totelem > 1) {
- tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
+ tTreeSort *tear = reinterpret_cast<tTreeSort *>(
+ MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"));
tTreeSort *tp = tear;
int skip = 0;
- for (te = lb->first; te; te = te->next, tp++) {
- tselem = TREESTORE(te);
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
+ TreeStoreElem *tselem = TREESTORE(te);
tp->te = te;
tp->name = te->name;
tp->idcode = te->idcode;
@@ -1349,6 +1180,7 @@ static void outliner_sort(ListBase *lb)
}
tp->id = tselem->id;
+ tp++;
}
/* just sort alphabetically */
@@ -1385,26 +1217,28 @@ static void outliner_sort(ListBase *lb)
static void outliner_collections_children_sort(ListBase *lb)
{
- TreeElement *te = lb->last;
- if (te == NULL) {
+ TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last);
+ if (last_te == nullptr) {
return;
}
- TreeStoreElem *tselem = TREESTORE(te);
+ TreeStoreElem *last_tselem = TREESTORE(last_te);
/* Sorting rules: only object lists. */
- if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
+ if ((last_tselem->type == TSE_SOME_ID) && (last_te->idcode == ID_OB)) {
int totelem = BLI_listbase_count(lb);
if (totelem > 1) {
- tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
+ tTreeSort *tear = reinterpret_cast<tTreeSort *>(
+ MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"));
tTreeSort *tp = tear;
- for (te = lb->first; te; te = te->next, tp++) {
- tselem = TREESTORE(te);
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
+ TreeStoreElem *tselem = TREESTORE(te);
tp->te = te;
tp->name = te->name;
tp->idcode = te->idcode;
tp->id = tselem->id;
+ tp++;
}
qsort(tear, totelem, sizeof(tTreeSort), treesort_child_not_in_collection);
@@ -1426,10 +1260,10 @@ static void outliner_collections_children_sort(ListBase *lb)
/* Filtering ----------------------------------------------- */
-typedef struct OutlinerTreeElementFocus {
+struct OutlinerTreeElementFocus {
TreeStoreElem *tselem;
int ys;
-} OutlinerTreeElementFocus;
+};
/**
* Bring the outliner scrolling back to where it was in relation to the original focus element
@@ -1441,12 +1275,12 @@ static void outliner_restore_scrolling_position(SpaceOutliner *space_outliner,
{
View2D *v2d = &region->v2d;
- if (focus->tselem != NULL) {
+ if (focus->tselem != nullptr) {
outliner_set_coordinates(region, space_outliner);
TreeElement *te_new = outliner_find_tree_element(&space_outliner->tree, focus->tselem);
- if (te_new != NULL) {
+ if (te_new != nullptr) {
int ys_new = te_new->ys;
int ys_old = focus->ys;
@@ -1484,17 +1318,16 @@ static TreeElement *outliner_find_first_desired_element_at_y_recursive(
}
if (TSELEM_OPEN(te->store_elem, space_outliner)) {
- TreeElement *te_iter, *te_sub;
- for (te_iter = te->subtree.first; te_iter; te_iter = te_iter->next) {
- te_sub = outliner_find_first_desired_element_at_y_recursive(
+ LISTBASE_FOREACH (TreeElement *, te_iter, &te->subtree) {
+ TreeElement *te_sub = outliner_find_first_desired_element_at_y_recursive(
space_outliner, te_iter, limit, callback_test);
- if (te_sub != NULL) {
+ if (te_sub != nullptr) {
return te_sub;
}
}
}
- return NULL;
+ return nullptr;
}
/**
@@ -1505,7 +1338,7 @@ static TreeElement *outliner_find_first_desired_element_at_y_recursive(
*
* Basically we keep going up and down the outliner tree from that point forward, until we find
* what we are looking for. If we are past the visible range and we can't find a valid element
- * we return NULL.
+ * we return nullptr.
*/
static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner *space_outliner,
const float view_co,
@@ -1522,15 +1355,15 @@ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner
callback_test = test_collection_callback;
}
- while (te != NULL) {
+ while (te != nullptr) {
TreeElement *te_sub = outliner_find_first_desired_element_at_y_recursive(
space_outliner, te, view_co_limit, callback_test);
- if (te_sub != NULL) {
+ if (te_sub != nullptr) {
/* Skip the element if it was not visible to start with. */
if (te->ys + UI_UNIT_Y > view_co_limit) {
return te_sub;
}
- return NULL;
+ return nullptr;
}
if (te->next) {
@@ -1538,7 +1371,7 @@ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner
continue;
}
- if (te->parent == NULL) {
+ if (te->parent == nullptr) {
break;
}
@@ -1551,7 +1384,7 @@ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner
}
}
- return NULL;
+ return nullptr;
}
/**
@@ -1572,12 +1405,12 @@ static void outliner_store_scrolling_position(SpaceOutliner *space_outliner,
TreeElement *te = outliner_find_first_desired_element_at_y(
space_outliner, region->v2d.cur.ymax, limit);
- if (te != NULL) {
+ if (te != nullptr) {
focus->tselem = TREESTORE(te);
focus->ys = te->ys;
}
else {
- focus->tselem = NULL;
+ focus->tselem = nullptr;
}
}
@@ -1635,7 +1468,7 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
Object *ob = (Object *)tselem->id;
Base *base = (Base *)te->directdata;
- BLI_assert((base == NULL) || (base->object == ob));
+ BLI_assert((base == nullptr) || (base->object == ob));
if (exclude_filter & SO_FILTER_OB_TYPE) {
switch (ob->type) {
@@ -1673,10 +1506,10 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
}
if (exclude_filter & SO_FILTER_OB_STATE) {
- if (base == NULL) {
+ if (base == nullptr) {
base = BKE_view_layer_base_find(view_layer, ob);
- if (base == NULL) {
+ if (base == nullptr) {
return false;
}
}
@@ -1711,14 +1544,14 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
return is_visible;
}
- if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
+ if ((te->parent != nullptr) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
(te->parent->idcode == ID_OB)) {
if (exclude_filter & SO_FILTER_NO_CHILDREN) {
return false;
}
}
}
- else if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
+ else if ((te->parent != nullptr) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
(te->parent->idcode == ID_OB)) {
if (exclude_filter & SO_FILTER_NO_OB_CONTENT) {
return false;
@@ -1761,8 +1594,9 @@ static TreeElement *outliner_extract_children_from_subtree(TreeElement *element,
TreeElement *te_next = element->next;
if (outliner_element_is_collection_or_object(element)) {
- TreeElement *te_prev = NULL;
- for (TreeElement *te = element->subtree.last; te; te = te_prev) {
+ TreeElement *te_prev = nullptr;
+ for (TreeElement *te = reinterpret_cast<TreeElement *>(element->subtree.last); te;
+ te = te_prev) {
te_prev = te->prev;
if (!outliner_element_is_collection_or_object(te)) {
@@ -1789,7 +1623,7 @@ static int outliner_filter_subtree(SpaceOutliner *space_outliner,
TreeElement *te, *te_next;
TreeStoreElem *tselem;
- for (te = lb->first; te; te = te_next) {
+ for (te = reinterpret_cast<TreeElement *>(lb->first); te; te = te_next) {
te_next = te->next;
if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) {
/* Don't free the tree, but extract the children from the parent and add to this tree. */
@@ -1842,7 +1676,7 @@ static int outliner_filter_subtree(SpaceOutliner *space_outliner,
static void outliner_filter_tree(SpaceOutliner *space_outliner, ViewLayer *view_layer)
{
- char search_buff[sizeof(((struct SpaceOutliner *)NULL)->search_string) + 2];
+ char search_buff[sizeof(((struct SpaceOutliner *)nullptr)->search_string) + 2];
char *search_string;
const int exclude_filter = outliner_exclude_filter_get(space_outliner);
@@ -1868,7 +1702,7 @@ static void outliner_clear_newid_from_main(Main *bmain)
{
ID *id_iter;
FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
- id_iter->newid = NULL;
+ id_iter->newid = nullptr;
}
FOREACH_MAIN_ID_END;
}
@@ -1876,7 +1710,6 @@ static void outliner_clear_newid_from_main(Main *bmain)
/* ======================================================= */
/* Main Tree Building API */
-/* Main entry point for building the tree data-structure that the outliner represents. */
void outliner_build_tree(Main *mainvar,
Scene *scene,
ViewLayer *view_layer,
@@ -1909,17 +1742,15 @@ void outliner_build_tree(Main *mainvar,
outliner_free_tree(&space_outliner->tree);
outliner_storage_cleanup(space_outliner);
- outliner_tree_display_destroy(&space_outliner->runtime->tree_display);
- space_outliner->runtime->tree_display = outliner_tree_display_create(space_outliner->outlinevis,
- space_outliner);
+ space_outliner->runtime->tree_display = AbstractTreeDisplay::createFromDisplayMode(
+ space_outliner->outlinevis, *space_outliner);
/* All tree displays should be created as sub-classes of AbstractTreeDisplay. */
- BLI_assert(space_outliner->runtime->tree_display != NULL);
+ BLI_assert(space_outliner->runtime->tree_display != nullptr);
- TreeSourceData source_data = {.bmain = mainvar, .scene = scene, .view_layer = view_layer};
- space_outliner->tree = outliner_tree_display_build_tree(space_outliner->runtime->tree_display,
- &source_data);
+ TreeSourceData source_data{*mainvar, *scene, *view_layer};
+ space_outliner->tree = space_outliner->runtime->tree_display->buildTree(source_data);
if ((space_outliner->flag & SO_SKIP_SORT_ALPHA) == 0) {
outliner_sort(&space_outliner->tree);
diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.cc
index 5feb157bfc8..86b56a7ec12 100644
--- a/source/blender/editors/space_outliner/outliner_utils.c
+++ b/source/blender/editors/space_outliner/outliner_utils.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <string.h>
+#include <cstring>
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -42,7 +42,7 @@
#include "UI_interface.h"
#include "UI_view2d.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
/* -------------------------------------------------------------------- */
/** \name Tree View Context
@@ -58,7 +58,7 @@ void outliner_viewcontext_init(const bContext *C, TreeViewContext *tvc)
/* Objects. */
tvc->obact = OBACT(tvc->view_layer);
- if (tvc->obact != NULL) {
+ if (tvc->obact != nullptr) {
tvc->ob_edit = OBEDIT_FROM_OBACT(tvc->obact);
if ((tvc->obact->type == OB_ARMATURE) ||
@@ -71,10 +71,6 @@ void outliner_viewcontext_init(const bContext *C, TreeViewContext *tvc)
/** \} */
-/**
- * Try to find an item under y-coordinate \a view_co_y (view-space).
- * \note Recursive
- */
TreeElement *outliner_find_item_at_y(const SpaceOutliner *space_outliner,
const ListBase *tree,
float view_co_y)
@@ -108,19 +104,17 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *space_outliner,
}
}
- return NULL;
+ return nullptr;
}
static TreeElement *outliner_find_item_at_x_in_row_recursive(const TreeElement *parent_te,
float view_co_x,
bool *r_is_merged_icon)
{
- TreeElement *child_te = parent_te->subtree.first;
-
- bool over_element = false;
+ TreeElement *child_te = reinterpret_cast<TreeElement *>(parent_te->subtree.first);
while (child_te) {
- over_element = (view_co_x > child_te->xs) && (view_co_x < child_te->xend);
+ const bool over_element = (view_co_x > child_te->xs) && (view_co_x < child_te->xend);
if ((child_te->flag & TE_ICONROW) && over_element) {
return child_te;
}
@@ -144,12 +138,6 @@ static TreeElement *outliner_find_item_at_x_in_row_recursive(const TreeElement *
return (TreeElement *)parent_te;
}
-/**
- * Collapsed items can show their children as click-able icons. This function tries to find
- * such an icon that represents the child item at x-coordinate \a view_co_x (view-space).
- *
- * \return a hovered child item or \a parent_te (if no hovered child found).
- */
TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner,
TreeElement *parent_te,
float view_co_x,
@@ -169,7 +157,6 @@ TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner,
return te;
}
-/* Find specific item from the trees-tore. */
TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
@@ -181,10 +168,9 @@ TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store
return tes;
}
}
- return NULL;
+ return nullptr;
}
-/* Find parent element of te */
TreeElement *outliner_find_parent_element(ListBase *lb,
TreeElement *parent_te,
const TreeElement *child_te)
@@ -199,29 +185,27 @@ TreeElement *outliner_find_parent_element(ListBase *lb,
return find_te;
}
}
- return NULL;
+ return nullptr;
}
-/* tse is not in the treestore, we use its contents to find a match */
TreeElement *outliner_find_tse(SpaceOutliner *space_outliner, const TreeStoreElem *tse)
{
TreeStoreElem *tselem;
- if (tse->id == NULL) {
- return NULL;
+ if (tse->id == nullptr) {
+ return nullptr;
}
- /* check if 'tse' is in treestore */
+ /* Check if 'tse' is in tree-store. */
tselem = BKE_outliner_treehash_lookup_any(
space_outliner->runtime->treehash, tse->type, tse->nr, tse->id);
if (tselem) {
return outliner_find_tree_element(&space_outliner->tree, tselem);
}
- return NULL;
+ return nullptr;
}
-/* Find treestore that refers to given ID */
TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const ID *id)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
@@ -237,7 +221,7 @@ TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const
return tes;
}
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
@@ -255,7 +239,7 @@ TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
}
}
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
@@ -273,7 +257,7 @@ TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
}
}
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_search_back_te(TreeElement *te, short idcode)
@@ -288,7 +272,7 @@ TreeElement *outliner_search_back_te(TreeElement *te, short idcode)
}
te = te->parent;
}
- return NULL;
+ return nullptr;
}
ID *outliner_search_back(TreeElement *te, short idcode)
@@ -301,17 +285,9 @@ ID *outliner_search_back(TreeElement *te, short idcode)
tselem = TREESTORE(search_te);
return tselem->id;
}
- return NULL;
+ return nullptr;
}
-/**
- * Iterate over all tree elements (pre-order traversal), executing \a func callback for
- * each tree element matching the optional filters.
- *
- * \param filter_te_flag: If not 0, only TreeElements with this flag will be visited.
- * \param filter_tselem_flag: Same as \a filter_te_flag, but for the TreeStoreElem.
- * \param func: Custom callback to execute for each visited item.
- */
bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
ListBase *tree,
int filter_te_flag,
@@ -319,7 +295,8 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
TreeTraversalFunc func,
void *customdata)
{
- for (TreeElement *te = tree->first, *te_next; te; te = te_next) {
+ for (TreeElement *te = reinterpret_cast<TreeElement *>(tree->first), *te_next; te;
+ te = te_next) {
TreeTraversalAction func_retval = TRAVERSE_CONTINUE;
/* in case te is freed in callback */
TreeStoreElem *tselem = TREESTORE(te);
@@ -395,7 +372,6 @@ float outliner_restrict_columns_width(const SpaceOutliner *space_outliner)
return (num_columns * UI_UNIT_X + V2D_SCROLL_WIDTH);
}
-/* Find first tree element in tree with matching treestore flag */
TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
@@ -407,10 +383,9 @@ TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag)
return active_element;
}
}
- return NULL;
+ return nullptr;
}
-/* Find if element is visible in the outliner tree */
bool outliner_is_element_visible(const TreeElement *te)
{
TreeStoreElem *tselem;
@@ -427,7 +402,6 @@ bool outliner_is_element_visible(const TreeElement *te)
return true;
}
-/* Find if x coordinate is over an icon or name */
bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x)
{
/* Special case: count area left of Scene Collection as empty space */
@@ -443,19 +417,16 @@ bool outliner_item_is_co_over_icon(const TreeElement *te, float view_co_x)
return (view_co_x > (te->xs + UI_UNIT_X)) && (view_co_x < (te->xs + UI_UNIT_X * 2));
}
-/* Find if x coordinate is over element name. */
bool outliner_item_is_co_over_name(const TreeElement *te, float view_co_x)
{
return (view_co_x > (te->xs + UI_UNIT_X * 2)) && (view_co_x < te->xend);
}
-/* Find if x coordinate is over element disclosure toggle */
bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x)
{
return (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X);
}
-/* Scroll view vertically while keeping within total bounds */
void outliner_scroll_view(SpaceOutliner *space_outliner, ARegion *region, int delta_y)
{
int tree_width, tree_height;
@@ -479,11 +450,6 @@ void outliner_scroll_view(SpaceOutliner *space_outliner, ARegion *region, int de
}
}
-/**
- * The outliner should generally use #ED_region_tag_redraw_no_rebuild() to avoid unnecessary tree
- * rebuilds. If elements are open or closed, we may still have to rebuild.
- * Upon changing the open/closed state, call this to avoid rebuilds if possible.
- */
void outliner_tag_redraw_avoid_rebuild_on_open_change(const SpaceOutliner *space_outliner,
ARegion *region)
{
@@ -496,14 +462,13 @@ void outliner_tag_redraw_avoid_rebuild_on_open_change(const SpaceOutliner *space
}
}
-/* Get base of object under cursor. Used for eyedropper tool */
Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2])
{
ARegion *region = CTX_wm_region(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
TreeElement *te;
- Base *base = NULL;
+ Base *base = nullptr;
float view_mval[2];
UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.cc
index 205f0117e6a..0fb17fa3f47 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.cc
@@ -21,8 +21,8 @@
* \ingroup spoutliner
*/
-#include <stdio.h>
-#include <string.h>
+#include <cstdio>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -31,6 +31,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_lib_remap.h"
#include "BKE_outliner_treehash.h"
#include "BKE_screen.h"
@@ -49,8 +50,20 @@
#include "UI_resources.h"
#include "UI_view2d.h"
-#include "outliner_intern.h"
-#include "tree/tree_display.h"
+#include "outliner_intern.hh"
+#include "tree/tree_display.hh"
+
+SpaceOutliner_Runtime::SpaceOutliner_Runtime(const SpaceOutliner_Runtime & /*other*/)
+ : tree_display(nullptr), treehash(nullptr)
+{
+}
+
+SpaceOutliner_Runtime::~SpaceOutliner_Runtime()
+{
+ if (treehash) {
+ BKE_outliner_treehash_free(treehash);
+ }
+}
static void outliner_main_region_init(wmWindowManager *wm, ARegion *region)
{
@@ -92,7 +105,7 @@ static void outliner_main_region_draw(const bContext *C, ARegion *region)
UI_view2d_view_restore(C);
/* scrollers */
- UI_view2d_scrollers_draw(v2d, NULL);
+ UI_view2d_scrollers_draw(v2d, nullptr);
}
static void outliner_main_region_free(ARegion *UNUSED(region))
@@ -104,7 +117,7 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params)
ScrArea *area = params->area;
ARegion *region = params->region;
wmNotifier *wmn = params->notifier;
- SpaceOutliner *space_outliner = area->spacedata.first;
+ SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
/* context changes */
switch (wmn->category) {
@@ -262,23 +275,25 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params)
}
}
+/* FIXME: See comment above #WM_msg_publish_rna_prop(). */
+extern "C" {
static void outliner_main_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
struct wmMsgBus *mbus = params->message_bus;
ScrArea *area = params->area;
ARegion *region = params->region;
- SpaceOutliner *space_outliner = area->spacedata.first;
+ SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
- wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
- .owner = region,
- .user_data = region,
- .notify = ED_region_do_msg_notify_tag_redraw,
- };
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw{};
+ msg_sub_value_region_tag_redraw.owner = region;
+ msg_sub_value_region_tag_redraw.user_data = region;
+ msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;
if (ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_OVERRIDES_LIBRARY)) {
WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw);
}
}
+}
/* ************************ header outliner area region *********************** */
@@ -324,7 +339,7 @@ static SpaceLink *outliner_create(const ScrArea *UNUSED(area), const Scene *UNUS
ARegion *region;
SpaceOutliner *space_outliner;
- space_outliner = MEM_callocN(sizeof(SpaceOutliner), "initoutliner");
+ space_outliner = MEM_cnew<SpaceOutliner>("initoutliner");
space_outliner->spacetype = SPACE_OUTLINER;
space_outliner->filter_id_type = ID_GR;
space_outliner->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE | SO_RESTRICT_RENDER;
@@ -334,14 +349,14 @@ static SpaceLink *outliner_create(const ScrArea *UNUSED(area), const Scene *UNUS
space_outliner->filter = SO_FILTER_NO_VIEW_LAYERS;
/* header */
- region = MEM_callocN(sizeof(ARegion), "header for outliner");
+ region = MEM_cnew<ARegion>("header for outliner");
BLI_addtail(&space_outliner->regionbase, region);
region->regiontype = RGN_TYPE_HEADER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
/* main region */
- region = MEM_callocN(sizeof(ARegion), "main region for outliner");
+ region = MEM_cnew<ARegion>("main region for outliner");
BLI_addtail(&space_outliner->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
@@ -359,84 +374,81 @@ static void outliner_free(SpaceLink *sl)
BLI_mempool_destroy(space_outliner->treestore);
}
- if (space_outliner->runtime) {
- outliner_tree_display_destroy(&space_outliner->runtime->tree_display);
- if (space_outliner->runtime->treehash) {
- BKE_outliner_treehash_free(space_outliner->runtime->treehash);
- }
- MEM_freeN(space_outliner->runtime);
- }
+ MEM_delete(space_outliner->runtime);
}
/* spacetype; init callback */
static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *area)
{
- SpaceOutliner *space_outliner = area->spacedata.first;
+ SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
- if (space_outliner->runtime == NULL) {
- space_outliner->runtime = MEM_callocN(sizeof(*space_outliner->runtime),
- "SpaceOutliner_Runtime");
+ if (space_outliner->runtime == nullptr) {
+ space_outliner->runtime = MEM_new<SpaceOutliner_Runtime>("SpaceOutliner_Runtime");
}
}
static SpaceLink *outliner_duplicate(SpaceLink *sl)
{
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
- SpaceOutliner *space_outliner_new = MEM_dupallocN(space_outliner);
+ SpaceOutliner *space_outliner_new = MEM_new<SpaceOutliner>(__func__, *space_outliner);
BLI_listbase_clear(&space_outliner_new->tree);
- space_outliner_new->treestore = NULL;
+ space_outliner_new->treestore = nullptr;
space_outliner_new->sync_select_dirty = WM_OUTLINER_SYNC_SELECT_FROM_ALL;
if (space_outliner->runtime) {
- space_outliner_new->runtime = MEM_dupallocN(space_outliner->runtime);
- space_outliner_new->runtime->tree_display = NULL;
- space_outliner_new->runtime->treehash = NULL;
+ /* Copy constructor handles details. */
+ space_outliner_new->runtime = MEM_new<SpaceOutliner_Runtime>("SpaceOutliner_runtime dup",
+ *space_outliner->runtime);
}
return (SpaceLink *)space_outliner_new;
}
-static void outliner_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id)
+static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRemapper *mappings)
{
SpaceOutliner *space_outliner = (SpaceOutliner *)slink;
- /* Some early out checks. */
- if (!TREESTORE_ID_TYPE(old_id)) {
- return; /* ID type is not used by outliner. */
- }
+ BKE_id_remapper_apply(mappings, (ID **)&space_outliner->search_tse.id, ID_REMAP_APPLY_DEFAULT);
- if (space_outliner->search_tse.id == old_id) {
- space_outliner->search_tse.id = new_id;
+ if (!space_outliner->treestore) {
+ return;
}
- if (space_outliner->treestore) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
- bool changed = false;
-
- BLI_mempool_iternew(space_outliner->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- if (tselem->id == old_id) {
- tselem->id = new_id;
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+ bool changed = false;
+ bool unassigned = false;
+
+ BLI_mempool_iternew(space_outliner->treestore, &iter);
+ while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
+ switch (BKE_id_remapper_apply(mappings, &tselem->id, ID_REMAP_APPLY_DEFAULT)) {
+ case ID_REMAP_RESULT_SOURCE_REMAPPED:
changed = true;
- }
+ break;
+ case ID_REMAP_RESULT_SOURCE_UNASSIGNED:
+ changed = true;
+ unassigned = true;
+ break;
+ case ID_REMAP_RESULT_SOURCE_UNAVAILABLE:
+ case ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE:
+ break;
}
+ }
- /* Note that the Outliner may not be the active editor of the area, and hence not initialized.
- * So runtime data might not have been created yet. */
- if (space_outliner->runtime && space_outliner->runtime->treehash && changed) {
- /* rebuild hash table, because it depends on ids too */
- /* postpone a full rebuild because this can be called many times on-free */
- space_outliner->storeflag |= SO_TREESTORE_REBUILD;
-
- if (new_id == NULL) {
- /* Redraw is needed when removing data for multiple outlines show the same data.
- * without this, the stale data won't get fully flushed when this outliner
- * is not the active outliner the user is interacting with. See T85976. */
- ED_area_tag_redraw(area);
- }
+ /* Note that the Outliner may not be the active editor of the area, and hence not initialized.
+ * So runtime data might not have been created yet. */
+ if (space_outliner->runtime && space_outliner->runtime->treehash && changed) {
+ /* rebuild hash table, because it depends on ids too */
+ /* postpone a full rebuild because this can be called many times on-free */
+ space_outliner->storeflag |= SO_TREESTORE_REBUILD;
+
+ if (unassigned) {
+ /* Redraw is needed when removing data for multiple outlines show the same data.
+ * without this, the stale data won't get fully flushed when this outliner
+ * is not the active outliner the user is interacting with. See T85976. */
+ ED_area_tag_redraw(area);
}
}
}
@@ -444,15 +456,14 @@ static void outliner_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *n
static void outliner_deactivate(struct ScrArea *area)
{
/* Remove hover highlights */
- SpaceOutliner *space_outliner = area->spacedata.first;
+ SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED_ANY, false);
ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW));
}
-/* only called once, from space_api/spacetypes.c */
void ED_spacetype_outliner(void)
{
- SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype time");
+ SpaceType *st = MEM_cnew<SpaceType>("spacetype time");
ARegionType *art;
st->spaceid = SPACE_OUTLINER;
@@ -470,7 +481,7 @@ void ED_spacetype_outliner(void)
st->context = outliner_context;
/* regions: main window */
- art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region");
+ art = MEM_cnew<ARegionType>("spacetype outliner region");
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
@@ -482,7 +493,7 @@ void ED_spacetype_outliner(void)
BLI_addhead(&st->regiontypes, art);
/* regions: header */
- art = MEM_callocN(sizeof(ARegionType), "spacetype outliner header region");
+ art = MEM_cnew<ARegionType>("spacetype outliner header region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
diff --git a/source/blender/editors/space_outliner/tree/common.cc b/source/blender/editors/space_outliner/tree/common.cc
index 306d59288f4..c6b5ee3b7ef 100644
--- a/source/blender/editors/space_outliner/tree/common.cc
+++ b/source/blender/editors/space_outliner/tree/common.cc
@@ -20,10 +20,18 @@
* Functions and helpers shared between tree-display types or other tree related code.
*/
+#include "BLI_listbase.h"
+
#include "BKE_idtype.h"
+#include "DNA_anim_types.h"
+#include "DNA_object_types.h"
+#include "DNA_outliner_types.h"
+
#include "RNA_access.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
/* -------------------------------------------------------------------- */
@@ -38,3 +46,33 @@ const char *outliner_idcode_to_plural(short idcode)
}
/** \} */
+
+void outliner_make_object_parent_hierarchy(ListBase *lb)
+{
+ /* build hierarchy */
+ /* XXX also, set extents here... */
+ TreeElement *te = reinterpret_cast<TreeElement *>(lb->first);
+ while (te) {
+ TreeElement *ten = te->next;
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) {
+ Object *ob = (Object *)tselem->id;
+ if (ob->parent && ob->parent->id.newid) {
+ BLI_remlink(lb, te);
+ TreeElement *tep = (TreeElement *)ob->parent->id.newid;
+ BLI_addtail(&tep->subtree, te);
+ te->parent = tep;
+ }
+ }
+ te = ten;
+ }
+}
+
+bool outliner_animdata_test(const AnimData *adt)
+{
+ if (adt) {
+ return (adt->action || adt->drivers.first || adt->nla_tracks.first);
+ }
+ return false;
+}
diff --git a/source/blender/editors/space_outliner/tree/common.hh b/source/blender/editors/space_outliner/tree/common.hh
new file mode 100644
index 00000000000..1745bfa436e
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/common.hh
@@ -0,0 +1,28 @@
+/*
+ * 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 spoutliner
+ */
+
+#pragma once
+
+struct ListBase;
+
+const char *outliner_idcode_to_plural(short idcode);
+
+void outliner_make_object_parent_hierarchy(ListBase *lb);
+bool outliner_animdata_test(const struct AnimData *adt);
diff --git a/source/blender/editors/space_outliner/tree/tree_display.cc b/source/blender/editors/space_outliner/tree/tree_display.cc
index 003afd5bdec..d2b6fff6996 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display.cc
@@ -19,50 +19,41 @@
*/
#include "DNA_listBase.h"
+#include "DNA_space_types.h"
#include "tree_display.hh"
using namespace blender::ed::outliner;
-TreeDisplay *outliner_tree_display_create(eSpaceOutliner_Mode mode, SpaceOutliner *space_outliner)
-{
- AbstractTreeDisplay *tree_display = nullptr;
+namespace blender::ed::outliner {
- switch (mode) {
+std::unique_ptr<AbstractTreeDisplay> AbstractTreeDisplay::createFromDisplayMode(
+ int /*eSpaceOutliner_Mode*/ mode, SpaceOutliner &space_outliner)
+{
+ switch ((eSpaceOutliner_Mode)mode) {
case SO_SCENES:
- tree_display = new TreeDisplayScenes(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayScenes>(space_outliner);
case SO_LIBRARIES:
- tree_display = new TreeDisplayLibraries(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayLibraries>(space_outliner);
case SO_SEQUENCE:
- tree_display = new TreeDisplaySequencer(*space_outliner);
- break;
+ return std::make_unique<TreeDisplaySequencer>(space_outliner);
case SO_DATA_API:
- tree_display = new TreeDisplayDataAPI(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayDataAPI>(space_outliner);
case SO_ID_ORPHANS:
- tree_display = new TreeDisplayIDOrphans(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayIDOrphans>(space_outliner);
case SO_OVERRIDES_LIBRARY:
- tree_display = new TreeDisplayOverrideLibrary(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayOverrideLibrary>(space_outliner);
case SO_VIEW_LAYER:
+ /* FIXME(Julian): this should not be the default! Return nullptr and handle that as valid
+ * case. */
default:
- tree_display = new TreeDisplayViewLayer(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayViewLayer>(space_outliner);
}
-
- return reinterpret_cast<TreeDisplay *>(tree_display);
}
-void outliner_tree_display_destroy(TreeDisplay **tree_display)
+bool AbstractTreeDisplay::hasWarnings() const
{
- delete reinterpret_cast<AbstractTreeDisplay *>(*tree_display);
- *tree_display = nullptr;
+ return has_warnings;
}
-ListBase outliner_tree_display_build_tree(TreeDisplay *tree_display, TreeSourceData *source_data)
-{
- return reinterpret_cast<AbstractTreeDisplay *>(tree_display)->buildTree(*source_data);
-}
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_display.h b/source/blender/editors/space_outliner/tree/tree_display.h
deleted file mode 100644
index c0a751f2cd5..00000000000
--- a/source/blender/editors/space_outliner/tree/tree_display.h
+++ /dev/null
@@ -1,68 +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.
- */
-
-/** \file
- * \ingroup spoutliner
- *
- * C-API for the Tree-Display types.
- */
-
-#pragma once
-
-#include "DNA_space_types.h"
-
-struct ListBase;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** C alias for an #AbstractTreeDisplay handle. */
-typedef struct TreeDisplay TreeDisplay;
-
-/**
- * \brief The data to build the tree from.
- */
-typedef struct TreeSourceData {
- struct Main *bmain;
- struct Scene *scene;
- struct ViewLayer *view_layer;
-} TreeSourceData;
-
-TreeDisplay *outliner_tree_display_create(eSpaceOutliner_Mode mode, SpaceOutliner *space_outliner);
-void outliner_tree_display_destroy(TreeDisplay **tree_display);
-
-ListBase outliner_tree_display_build_tree(TreeDisplay *tree_display, TreeSourceData *source_data);
-
-/* The following functions are needed to build the tree. They are calls back into C; the way
- * elements are created should be refactored and ported to C++ with a new design/API too. */
-struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
- ListBase *lb,
- void *idv,
- struct TreeElement *parent,
- short type,
- short index);
-void outliner_make_object_parent_hierarchy(ListBase *lb);
-bool outliner_animdata_test(const struct AnimData *adt);
-TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
- struct Collection *collection,
- TreeElement *ten);
-
-const char *outliner_idcode_to_plural(short idcode);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh
index 96af8258010..68f0f9c562d 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.hh
+++ b/source/blender/editors/space_outliner/tree/tree_display.hh
@@ -34,16 +34,35 @@
#pragma once
-#include "tree_display.h"
+#include <memory>
+struct ID;
+struct LayerCollection;
+struct Library;
struct ListBase;
struct Main;
+struct Scene;
+struct Sequence;
struct SpaceOutliner;
struct TreeElement;
-struct TreeSourceData;
+struct ViewLayer;
namespace blender::ed::outliner {
+/**
+ * \brief The data to build the tree from.
+ */
+struct TreeSourceData {
+ Main *bmain;
+ Scene *scene;
+ ViewLayer *view_layer;
+
+ TreeSourceData(Main &bmain, Scene &scene, ViewLayer &view_layer)
+ : bmain(&bmain), scene(&scene), view_layer(&view_layer)
+ {
+ }
+};
+
/* -------------------------------------------------------------------- */
/* Tree-Display Interface */
@@ -59,13 +78,21 @@ class AbstractTreeDisplay {
}
virtual ~AbstractTreeDisplay() = default;
+ static std::unique_ptr<AbstractTreeDisplay> createFromDisplayMode(
+ int /*eSpaceOutliner_Mode*/ mode, SpaceOutliner &space_outliner);
+
/**
* Build a tree for this display mode with the Blender context data given in \a source_data and
* the view settings in \a space_outliner.
*/
virtual ListBase buildTree(const TreeSourceData &source_data) = 0;
+ /** Accessor to whether given tree has some warnings to display. */
+ bool hasWarnings() const;
+
protected:
+ bool has_warnings = false;
+
/** All derived classes will need a handle to this, so storing it in the base for convenience. */
SpaceOutliner &space_outliner_;
};
@@ -105,8 +132,8 @@ class TreeDisplayLibraries final : public AbstractTreeDisplay {
ListBase buildTree(const TreeSourceData &source_data) override;
private:
- TreeElement *add_library_contents(Main &, ListBase &, Library *) const;
- bool library_id_filter_poll(Library *lib, ID *id) const;
+ TreeElement *add_library_contents(Main &, ListBase &, Library *);
+ bool library_id_filter_poll(const Library *lib, ID *id) const;
short id_filter_get() const;
};
@@ -123,8 +150,8 @@ class TreeDisplayOverrideLibrary final : public AbstractTreeDisplay {
ListBase buildTree(const TreeSourceData &source_data) override;
private:
- TreeElement *add_library_contents(Main &, ListBase &, Library *) const;
- bool override_library_id_filter_poll(Library *lib, ID *id) const;
+ TreeElement *add_library_contents(Main &, ListBase &, Library *);
+ bool override_library_id_filter_poll(const Library *lib, ID *id) const;
short id_filter_get() const;
};
@@ -148,6 +175,9 @@ class TreeDisplaySequencer final : public AbstractTreeDisplay {
private:
TreeElement *add_sequencer_contents() const;
+ /**
+ * Helped function to put duplicate sequence in the same tree.
+ */
SequenceAddOp need_add_seq_dup(Sequence *seq) const;
void add_seq_dup(Sequence *seq, TreeElement *te, short index) const;
};
diff --git a/source/blender/editors/space_outliner/tree/tree_display_data.cc b/source/blender/editors/space_outliner/tree/tree_display_data.cc
index 8a5c2e7d9f3..5c88e88bd37 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_data.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_data.cc
@@ -21,10 +21,13 @@
#include "BLI_listbase.h"
#include "BLI_mempool.h"
+#include "DNA_space_types.h"
+
#include "RNA_access.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
diff --git a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
index c6b700318dd..1d77e82612d 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
@@ -25,15 +25,17 @@
#include "BKE_main.h"
#include "DNA_collection_types.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplayLibraries::TreeDisplayLibraries(SpaceOutliner &space_outliner)
@@ -105,9 +107,7 @@ ListBase TreeDisplayLibraries::buildTree(const TreeSourceData &source_data)
return tree;
}
-TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar,
- ListBase &lb,
- Library *lib) const
+TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase &lb, Library *lib)
{
const short filter_id_type = id_filter_get();
@@ -150,6 +150,9 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar,
tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0);
tenlib->name = IFACE_("Current File");
}
+ if (tenlib->flag & TE_HAS_WARNING) {
+ has_warnings = true;
+ }
}
/* Create data-block list parent element on demand. */
@@ -186,7 +189,7 @@ short TreeDisplayLibraries::id_filter_get() const
return 0;
}
-bool TreeDisplayLibraries::library_id_filter_poll(Library *lib, ID *id) const
+bool TreeDisplayLibraries::library_id_filter_poll(const Library *lib, ID *id) const
{
if (id->lib != lib) {
return false;
diff --git a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
index 69ccf014642..587f807c40c 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
@@ -19,6 +19,7 @@
*/
#include "DNA_ID.h"
+#include "DNA_space_types.h"
#include "BLI_listbase.h"
#include "BLI_listbase_wrapper.hh"
@@ -26,12 +27,13 @@
#include "BKE_main.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplayIDOrphans::TreeDisplayIDOrphans(SpaceOutliner &space_outliner)
diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
index a17bf174a74..d9a0661d3b4 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
@@ -25,15 +25,23 @@
#include "BKE_main.h"
#include "DNA_collection_types.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
/* Convenience/readability. */
+/* Convenience/readability. */
+/* Convenience/readability. */
+/* Convenience/readability. */
+/* Convenience/readability. */
+/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplayOverrideLibrary::TreeDisplayOverrideLibrary(SpaceOutliner &space_outliner)
@@ -107,7 +115,7 @@ ListBase TreeDisplayOverrideLibrary::buildTree(const TreeSourceData &source_data
TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar,
ListBase &lb,
- Library *lib) const
+ Library *lib)
{
const short filter_id_type = id_filter_get();
@@ -147,6 +155,9 @@ TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar,
tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0);
tenlib->name = IFACE_("Current File");
}
+ if (tenlib->flag & TE_HAS_WARNING) {
+ has_warnings = true;
+ }
}
/* Create data-block list parent element on demand. */
@@ -186,7 +197,7 @@ short TreeDisplayOverrideLibrary::id_filter_get() const
return 0;
}
-bool TreeDisplayOverrideLibrary::override_library_id_filter_poll(Library *lib, ID *id) const
+bool TreeDisplayOverrideLibrary::override_library_id_filter_poll(const Library *lib, ID *id) const
{
if (id->lib != lib) {
return false;
diff --git a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
index 390f81cfcd1..ad66e8a7ee5 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
@@ -18,18 +18,21 @@
* \ingroup spoutliner
*/
+#include "DNA_space_types.h"
+
#include "BLI_listbase.h"
#include "BLI_listbase_wrapper.hh"
#include "BLI_mempool.h"
#include "BKE_main.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplayScenes::TreeDisplayScenes(SpaceOutliner &space_outliner)
diff --git a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
index 02af6a13cb3..7c5137a72dd 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
@@ -24,14 +24,17 @@
#include "BLI_listbase_wrapper.hh"
#include "BLI_utildefines.h"
+#include "DNA_sequence_types.h"
+#include "DNA_space_types.h"
+
#include "SEQ_sequencer.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplaySequencer::TreeDisplaySequencer(SpaceOutliner &space_outliner)
@@ -63,7 +66,6 @@ ListBase TreeDisplaySequencer::buildTree(const TreeSourceData &source_data)
return tree;
}
-/* Helped function to put duplicate sequence in the same tree. */
SequenceAddOp TreeDisplaySequencer::need_add_seq_dup(Sequence *seq) const
{
if ((!seq->strip) || (!seq->strip->stripdata)) {
diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
index c3d0aecd3cb..73990b45562 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
@@ -22,6 +22,7 @@
#include "DNA_collection_types.h"
#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
#include "BKE_layer.h"
@@ -32,12 +33,13 @@
#include "BLT_translation.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
class ObjectsChildrenBuilder {
diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc
index 113d421ed91..bed28e59f0b 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element.cc
@@ -20,6 +20,11 @@
#include "DNA_anim_types.h"
#include "DNA_listBase.h"
+#include "DNA_space_types.h"
+
+#include "UI_resources.h"
+
+#include "BLT_translation.h"
#include "tree_element_anim_data.hh"
#include "tree_element_collection.hh"
@@ -28,15 +33,18 @@
#include "tree_element_id.hh"
#include "tree_element_nla.hh"
#include "tree_element_overrides.hh"
+#include "tree_element_rna.hh"
#include "tree_element_scene_objects.hh"
#include "tree_element_view_layer.hh"
-#include "tree_element.h"
+#include "../outliner_intern.hh"
#include "tree_element.hh"
namespace blender::ed::outliner {
-static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te, void *idv)
+std::unique_ptr<AbstractTreeElement> AbstractTreeElement::createFromType(const int type,
+ TreeElement &legacy_te,
+ void *idv)
{
ID &id = *static_cast<ID *>(idv);
@@ -56,28 +64,38 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te
case TSE_SOME_ID:
return TreeElementID::createFromID(legacy_te, id);
case TSE_ANIM_DATA:
- return new TreeElementAnimData(legacy_te, *reinterpret_cast<IdAdtTemplate &>(id).adt);
+ return std::make_unique<TreeElementAnimData>(legacy_te,
+ *reinterpret_cast<IdAdtTemplate &>(id).adt);
case TSE_DRIVER_BASE:
- return new TreeElementDriverBase(legacy_te, *static_cast<AnimData *>(idv));
+ return std::make_unique<TreeElementDriverBase>(legacy_te, *static_cast<AnimData *>(idv));
case TSE_NLA:
- return new TreeElementNLA(legacy_te, *static_cast<AnimData *>(idv));
+ return std::make_unique<TreeElementNLA>(legacy_te, *static_cast<AnimData *>(idv));
case TSE_NLA_TRACK:
- return new TreeElementNLATrack(legacy_te, *static_cast<NlaTrack *>(idv));
+ return std::make_unique<TreeElementNLATrack>(legacy_te, *static_cast<NlaTrack *>(idv));
case TSE_NLA_ACTION:
- return new TreeElementNLAAction(legacy_te, *static_cast<bAction *>(idv));
+ return std::make_unique<TreeElementNLAAction>(legacy_te, *static_cast<bAction *>(idv));
case TSE_GP_LAYER:
- return new TreeElementGPencilLayer(legacy_te, *static_cast<bGPDlayer *>(idv));
+ return std::make_unique<TreeElementGPencilLayer>(legacy_te, *static_cast<bGPDlayer *>(idv));
case TSE_R_LAYER_BASE:
- return new TreeElementViewLayerBase(legacy_te, *static_cast<Scene *>(idv));
+ return std::make_unique<TreeElementViewLayerBase>(legacy_te, *static_cast<Scene *>(idv));
case TSE_SCENE_COLLECTION_BASE:
- return new TreeElementCollectionBase(legacy_te, *static_cast<Scene *>(idv));
+ return std::make_unique<TreeElementCollectionBase>(legacy_te, *static_cast<Scene *>(idv));
case TSE_SCENE_OBJECTS_BASE:
- return new TreeElementSceneObjectsBase(legacy_te, *static_cast<Scene *>(idv));
+ return std::make_unique<TreeElementSceneObjectsBase>(legacy_te, *static_cast<Scene *>(idv));
case TSE_LIBRARY_OVERRIDE_BASE:
- return new TreeElementOverridesBase(legacy_te, id);
+ return std::make_unique<TreeElementOverridesBase>(legacy_te, id);
case TSE_LIBRARY_OVERRIDE:
- return new TreeElementOverridesProperty(legacy_te,
- *static_cast<TreeElementOverridesData *>(idv));
+ return std::make_unique<TreeElementOverridesProperty>(
+ legacy_te, *static_cast<TreeElementOverridesData *>(idv));
+ case TSE_RNA_STRUCT:
+ return std::make_unique<TreeElementRNAStruct>(legacy_te,
+ *reinterpret_cast<PointerRNA *>(idv));
+ case TSE_RNA_PROPERTY:
+ return std::make_unique<TreeElementRNAProperty>(
+ legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index);
+ case TSE_RNA_ARRAY_ELEM:
+ return std::make_unique<TreeElementRNAArrayElement>(
+ legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index);
default:
break;
}
@@ -85,13 +103,7 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te
return nullptr;
}
-static void tree_element_free(AbstractTreeElement **tree_element)
-{
- delete *tree_element;
- *tree_element = nullptr;
-}
-
-static void tree_element_expand(AbstractTreeElement &tree_element, SpaceOutliner &space_outliner)
+void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner &space_outliner)
{
/* Most types can just expand. IDs optionally expand (hence the poll) and do additional, common
* expanding. Could be done nicer, we could request a small "expander" helper object from the
@@ -103,58 +115,39 @@ static void tree_element_expand(AbstractTreeElement &tree_element, SpaceOutliner
tree_element.postExpand(space_outliner);
}
-/**
- * Needed for types that still expand in C, but need to execute the same post-expand logic. Can be
- * removed once all ID types expand entirely using the new design.
- */
-static void tree_element_post_expand_only(AbstractTreeElement &tree_element,
- SpaceOutliner &space_outliner)
+bool tree_element_warnings_get(TreeElement *te, int *r_icon, const char **r_message)
{
- tree_element.postExpand(space_outliner);
-}
-/**
- * Needed for types that still expand in C, to poll if they should expand in current context. Can
- * be removed once all ID types expand entirely using the new design.
- */
-static bool tree_element_expand_poll(AbstractTreeElement &tree_element,
- SpaceOutliner &space_outliner)
-{
- return tree_element.expandPoll(space_outliner);
-}
+ TreeStoreElem *tselem = te->store_elem;
-} // namespace blender::ed::outliner
-
-namespace outliner = blender::ed::outliner;
-
-TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy_te, void *idv)
-{
- outliner::AbstractTreeElement *element = outliner::tree_element_create(type, *legacy_te, idv);
- return reinterpret_cast<TreeElementType *>(element);
-}
+ if (tselem->type != TSE_SOME_ID) {
+ return false;
+ }
+ if (te->idcode != ID_LI) {
+ return false;
+ }
-void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner)
-{
- outliner::tree_element_expand(reinterpret_cast<outliner::AbstractTreeElement &>(*type),
- *space_outliner);
-}
-bool outliner_tree_element_type_is_expand_valid(TreeElementType *type)
-{
- outliner::AbstractTreeElement &element = reinterpret_cast<outliner::AbstractTreeElement &>(
- *type);
- return element.isExpandValid();
-}
-bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner)
-{
- return outliner::tree_element_expand_poll(
- reinterpret_cast<outliner::AbstractTreeElement &>(*type), *space_outliner);
-}
-void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner)
-{
- outliner::tree_element_post_expand_only(reinterpret_cast<outliner::AbstractTreeElement &>(*type),
- *space_outliner);
+ Library *library = (Library *)tselem->id;
+ if (library->tag & LIBRARY_TAG_RESYNC_REQUIRED) {
+ if (r_icon) {
+ *r_icon = ICON_ERROR;
+ }
+ if (r_message) {
+ *r_message = TIP_(
+ "Contains linked library overrides that need to be resynced, updating the library is "
+ "recommended");
+ }
+ return true;
+ }
+ if (library->id.tag & LIB_TAG_MISSING) {
+ if (r_icon) {
+ *r_icon = ICON_ERROR;
+ }
+ if (r_message) {
+ *r_message = TIP_("Missing library");
+ }
+ return true;
+ }
+ return false;
}
-void outliner_tree_element_type_free(TreeElementType **type)
-{
- outliner::tree_element_free(reinterpret_cast<outliner::AbstractTreeElement **>(type));
-}
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element.h b/source/blender/editors/space_outliner/tree/tree_element.h
deleted file mode 100644
index 8e5b02278cc..00000000000
--- a/source/blender/editors/space_outliner/tree/tree_element.h
+++ /dev/null
@@ -1,48 +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.
- */
-
-/** \file
- * \ingroup spoutliner
- *
- * C-API for the Tree-Element types.
- * This API shouldn't stay for long. All tree building should eventually be done through C++ types,
- * with more type safety and an easier to reason about design.
- */
-
-#pragma once
-
-#include "DNA_space_types.h"
-
-struct TreeElement;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** C alias for an #AbstractTreeElement handle. */
-typedef struct TreeElementType TreeElementType;
-
-TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy_te, void *idv);
-void outliner_tree_element_type_free(TreeElementType **type);
-
-void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner);
-bool outliner_tree_element_type_is_expand_valid(TreeElementType *type);
-bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner);
-void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh
index 09bd0eec05d..aca5738b91a 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element.hh
@@ -20,7 +20,11 @@
#pragma once
-#include "tree_element.h"
+#include <memory>
+
+struct ListBase;
+struct SpaceOutliner;
+struct TreeElement;
namespace blender::ed::outliner {
@@ -39,6 +43,10 @@ class AbstractTreeElement {
public:
virtual ~AbstractTreeElement() = default;
+ static std::unique_ptr<AbstractTreeElement> createFromType(int type,
+ TreeElement &legacy_te,
+ void *idv);
+
/**
* Check if the type is expandable in current context.
*/
@@ -46,12 +54,6 @@ class AbstractTreeElement {
{
return true;
}
- /**
- * Let the type add its own children.
- */
- virtual void expand(SpaceOutliner &) const
- {
- }
virtual void postExpand(SpaceOutliner &) const
{
}
@@ -65,11 +67,46 @@ class AbstractTreeElement {
return true;
}
+ friend void tree_element_expand(const AbstractTreeElement &tree_element,
+ SpaceOutliner &space_outliner);
+
protected:
/* Pseudo-abstract: Only allow creation through derived types. */
AbstractTreeElement(TreeElement &legacy_te) : legacy_te_(legacy_te)
{
}
+
+ /**
+ * Let the type add its own children.
+ */
+ virtual void expand(SpaceOutliner &) const
+ {
+ }
};
+/**
+ * TODO: this function needs to be split up! It's getting a bit too large...
+ *
+ * \note "ID" is not always a real ID.
+ * \note If child items are only added to the tree if the item is open,
+ * the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change().
+ */
+struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
+ ListBase *lb,
+ void *idv,
+ struct TreeElement *parent,
+ short type,
+ short index);
+
+void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner &space_outliner);
+
+/**
+ * Get actual warning data of a tree element, if any.
+ *
+ * \param r_icon The icon to display as warning.
+ * \param r_message The message to display as warning.
+ * \return true if there is a warning, false otherwise.
+ */
+bool tree_element_warnings_get(struct TreeElement *te, int *r_icon, const char **r_message);
+
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
index c0fef7c98e2..41212f61d5d 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
@@ -22,11 +22,11 @@
#include "DNA_anim_types.h"
#include "DNA_listBase.h"
+#include "DNA_outliner_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_anim_data.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection.cc b/source/blender/editors/space_outliner/tree/tree_element_collection.cc
index 1add61db7f1..0a7ee21df15 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_collection.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_collection.cc
@@ -19,11 +19,12 @@
*/
#include "DNA_listBase.h"
+#include "DNA_outliner_types.h"
+#include "DNA_scene_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_collection.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver.cc b/source/blender/editors/space_outliner/tree/tree_element_driver.cc
index 42f51908eaa..49d7f91b557 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_driver.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_driver.cc
@@ -24,11 +24,11 @@
#include "DNA_anim_types.h"
#include "DNA_listBase.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_driver.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc
index 91e6fdcde4b..ead83ad6931 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc
@@ -21,8 +21,9 @@
#include "BLI_utildefines.h"
#include "DNA_gpencil_types.h"
+#include "DNA_space_types.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
#include "tree_element_gpencil_layer.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc
index 7ff5a3285f1..afbbd171cf4 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc
@@ -19,6 +19,7 @@
*/
#include "DNA_ID.h"
+#include "DNA_space_types.h"
#include "BLI_listbase_wrapper.hh"
#include "BLI_utildefines.h"
@@ -29,8 +30,8 @@
#include "RNA_access.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_element_id_library.hh"
#include "tree_element_id_scene.hh"
@@ -38,13 +39,13 @@
namespace blender::ed::outliner {
-TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, ID &id)
+std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_te, ID &id)
{
switch (ID_Type type = GS(id.name); type) {
case ID_LI:
- return new TreeElementIDLibrary(legacy_te, (Library &)id);
+ return std::make_unique<TreeElementIDLibrary>(legacy_te, (Library &)id);
case ID_SCE:
- return new TreeElementIDScene(legacy_te, (Scene &)id);
+ return std::make_unique<TreeElementIDScene>(legacy_te, (Scene &)id);
case ID_OB:
case ID_ME:
case ID_CU:
@@ -82,7 +83,7 @@ TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, ID &id)
case ID_PAL:
case ID_PC:
case ID_CF:
- return new TreeElementID(legacy_te, id);
+ return std::make_unique<TreeElementID>(legacy_te, id);
/* Deprecated */
case ID_IP:
BLI_assert_msg(0, "Outliner trying to build tree-element for deprecated ID type");
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.hh b/source/blender/editors/space_outliner/tree/tree_element_id.hh
index b3b5ca2770c..9b5b955be0b 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.hh
@@ -24,6 +24,9 @@
#include "tree_element.hh"
+struct AnimData;
+struct ID;
+
namespace blender::ed::outliner {
class TreeElementID : public AbstractTreeElement {
@@ -33,7 +36,7 @@ class TreeElementID : public AbstractTreeElement {
public:
TreeElementID(TreeElement &legacy_te, ID &id);
- static TreeElementID *createFromID(TreeElement &legacy_te, ID &id);
+ static std::unique_ptr<TreeElementID> createFromID(TreeElement &legacy_te, ID &id);
void postExpand(SpaceOutliner &) const override;
bool expandPoll(const SpaceOutliner &) const override;
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.cc b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
index 36f536c9845..b5fd67d4807 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
@@ -18,9 +18,10 @@
* \ingroup spoutliner
*/
+#include "DNA_ID.h"
#include "DNA_listBase.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
#include "tree_element_id_library.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.hh b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
index 88660cd8aa9..ce128b1a5ff 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
@@ -22,6 +22,8 @@
#include "tree_element_id.hh"
+struct Library;
+
namespace blender::ed::outliner {
class TreeElementIDLibrary final : public TreeElementID {
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc
index ae81b44a1e4..c71d6786c6e 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc
@@ -19,9 +19,10 @@
*/
#include "DNA_listBase.h"
+#include "DNA_outliner_types.h"
+#include "DNA_scene_types.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_id_scene.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.cc b/source/blender/editors/space_outliner/tree/tree_element_nla.cc
index 65832e8f981..89ebee49192 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_nla.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_nla.cc
@@ -22,11 +22,11 @@
#include "DNA_anim_types.h"
#include "DNA_listBase.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_nla.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
index 731beb3956e..ba1471625b9 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
@@ -27,10 +27,11 @@
#include "BLT_translation.h"
+#include "DNA_space_types.h"
+
#include "RNA_access.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_overrides.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.cc b/source/blender/editors/space_outliner/tree/tree_element_rna.cc
new file mode 100644
index 00000000000..0152f59268d
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_rna.cc
@@ -0,0 +1,249 @@
+/*
+ * 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 spoutliner
+ */
+
+#include <climits>
+#include <iostream>
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_outliner_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "../outliner_intern.hh"
+
+#include "tree_element_rna.hh"
+
+namespace blender::ed::outliner {
+
+/* Don't display arrays larger, weak but index is stored as a short,
+ * also the outliner isn't intended for editing such large data-sets. */
+BLI_STATIC_ASSERT(sizeof(TreeElement::index) == 2, "Index is no longer short!")
+
+/* -------------------------------------------------------------------- */
+/* Common functionality (#TreeElementRNACommon Base Class) */
+
+TreeElementRNACommon::TreeElementRNACommon(TreeElement &legacy_te, PointerRNA &rna_ptr)
+ : AbstractTreeElement(legacy_te), rna_ptr_(rna_ptr)
+{
+ /* Create an empty tree-element. */
+ if (!isRNAValid()) {
+ legacy_te_.name = IFACE_("(empty)");
+ return;
+ }
+
+ legacy_te_.rnaptr = rna_ptr;
+}
+
+bool TreeElementRNACommon::isExpandValid() const
+{
+ return true;
+}
+
+bool TreeElementRNACommon::isRNAValid() const
+{
+ return rna_ptr_.data != nullptr;
+}
+
+bool TreeElementRNACommon::expandPoll(const SpaceOutliner &) const
+{
+ return isRNAValid();
+}
+
+/* -------------------------------------------------------------------- */
+/* RNA Struct */
+
+TreeElementRNAStruct::TreeElementRNAStruct(TreeElement &legacy_te, PointerRNA &rna_ptr)
+ : TreeElementRNACommon(legacy_te, rna_ptr)
+{
+ if (!isRNAValid()) {
+ return;
+ }
+
+ legacy_te_.name = RNA_struct_name_get_alloc(&rna_ptr, nullptr, 0, nullptr);
+ if (legacy_te_.name) {
+ legacy_te_.flag |= TE_FREE_NAME;
+ }
+ else {
+ legacy_te_.name = RNA_struct_ui_name(rna_ptr.type);
+ }
+}
+
+void TreeElementRNAStruct::expand(SpaceOutliner &space_outliner) const
+{
+ TreeStoreElem &tselem = *TREESTORE(&legacy_te_);
+ PointerRNA *ptr = &legacy_te_.rnaptr;
+
+ /* If searching don't expand RNA entries */
+ if (SEARCHING_OUTLINER(&space_outliner) && BLI_strcasecmp("RNA", legacy_te_.name) == 0) {
+ tselem.flag &= ~TSE_CHILDSEARCH;
+ }
+
+ PropertyRNA *iterprop = RNA_struct_iterator_property(ptr->type);
+ int tot = RNA_property_collection_length(ptr, iterprop);
+ CLAMP_MAX(tot, max_index);
+
+ /* auto open these cases */
+ if (!legacy_te_.parent ||
+ (RNA_property_type(reinterpret_cast<PropertyRNA *>(legacy_te_.parent->directdata))) ==
+ PROP_POINTER) {
+ if (!tselem.used) {
+ tselem.flag &= ~TSE_CLOSED;
+ }
+ }
+
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ for (int index = 0; index < tot; index++) {
+ PointerRNA propptr;
+ RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr);
+ if (!(RNA_property_flag(reinterpret_cast<PropertyRNA *>(propptr.data)) & PROP_HIDDEN)) {
+ outliner_add_element(&space_outliner,
+ &legacy_te_.subtree,
+ (void *)ptr,
+ &legacy_te_,
+ TSE_RNA_PROPERTY,
+ index);
+ }
+ }
+ }
+ else if (tot) {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* RNA Property */
+
+TreeElementRNAProperty::TreeElementRNAProperty(TreeElement &legacy_te,
+ PointerRNA &rna_ptr,
+ const int index)
+ : TreeElementRNACommon(legacy_te, rna_ptr)
+{
+ if (!isRNAValid()) {
+ return;
+ }
+
+ PointerRNA propptr;
+ PropertyRNA *iterprop = RNA_struct_iterator_property(rna_ptr.type);
+ RNA_property_collection_lookup_int(&rna_ptr, iterprop, index, &propptr);
+
+ PropertyRNA *prop = reinterpret_cast<PropertyRNA *>(propptr.data);
+
+ legacy_te_.name = RNA_property_ui_name(prop);
+ legacy_te_.directdata = prop;
+ rna_prop_ = prop;
+}
+
+void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const
+{
+ TreeStoreElem &tselem = *TREESTORE(&legacy_te_);
+ PointerRNA rna_ptr = rna_ptr_;
+ PropertyType proptype = RNA_property_type(rna_prop_);
+
+ /* If searching don't expand RNA entries */
+ if (SEARCHING_OUTLINER(&space_outliner) && BLI_strcasecmp("RNA", legacy_te_.name) == 0) {
+ tselem.flag &= ~TSE_CHILDSEARCH;
+ }
+
+ if (proptype == PROP_POINTER) {
+ PointerRNA pptr = RNA_property_pointer_get(&rna_ptr, rna_prop_);
+
+ if (pptr.data) {
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, (void *)&pptr, &legacy_te_, TSE_RNA_STRUCT, -1);
+ }
+ else {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+ }
+ }
+ else if (proptype == PROP_COLLECTION) {
+ int tot = RNA_property_collection_length(&rna_ptr, rna_prop_);
+ CLAMP_MAX(tot, max_index);
+
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ for (int index = 0; index < tot; index++) {
+ PointerRNA pptr;
+ RNA_property_collection_lookup_int(&rna_ptr, rna_prop_, index, &pptr);
+ outliner_add_element(&space_outliner,
+ &legacy_te_.subtree,
+ (void *)&pptr,
+ &legacy_te_,
+ TSE_RNA_STRUCT,
+ index);
+ }
+ }
+ else if (tot) {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+ }
+ else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
+ int tot = RNA_property_array_length(&rna_ptr, rna_prop_);
+ CLAMP_MAX(tot, max_index);
+
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ for (int index = 0; index < tot; index++) {
+ outliner_add_element(&space_outliner,
+ &legacy_te_.subtree,
+ &rna_ptr,
+ &legacy_te_,
+ TSE_RNA_ARRAY_ELEM,
+ index);
+ }
+ }
+ else if (tot) {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* RNA Array Element */
+
+TreeElementRNAArrayElement::TreeElementRNAArrayElement(TreeElement &legacy_te,
+ PointerRNA &rna_ptr,
+ const int index)
+ : TreeElementRNACommon(legacy_te, rna_ptr)
+{
+ PropertyRNA *prop = reinterpret_cast<PropertyRNA *>(legacy_te_.parent->directdata);
+ legacy_te_.directdata = prop;
+ legacy_te_.index = index;
+
+ char c = RNA_property_array_item_char(prop, index);
+
+ legacy_te_.name = reinterpret_cast<char *>(
+ MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName"));
+ if (c) {
+ sprintf((char *)legacy_te_.name, " %c", c);
+ }
+ else {
+ sprintf((char *)legacy_te_.name, " %d", index + 1);
+ }
+ legacy_te_.flag |= TE_FREE_NAME;
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.hh b/source/blender/editors/space_outliner/tree/tree_element_rna.hh
new file mode 100644
index 00000000000..352b8763acb
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_rna.hh
@@ -0,0 +1,75 @@
+/*
+ * 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 spoutliner
+ */
+
+#pragma once
+
+#include <limits>
+
+#include "RNA_types.h"
+
+#include "tree_element.hh"
+
+struct PointerRNA;
+
+namespace blender::ed::outliner {
+
+/**
+ * Base class for common behavior of RNA tree elements.
+ */
+class TreeElementRNACommon : public AbstractTreeElement {
+ protected:
+ constexpr static int max_index = std::numeric_limits<short>::max();
+ PointerRNA rna_ptr_;
+
+ public:
+ TreeElementRNACommon(TreeElement &legacy_te, PointerRNA &rna_ptr);
+ bool isExpandValid() const override;
+ bool expandPoll(const SpaceOutliner &) const override;
+
+ bool isRNAValid() const;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementRNAStruct : public TreeElementRNACommon {
+ public:
+ TreeElementRNAStruct(TreeElement &legacy_te, PointerRNA &rna_ptr);
+ void expand(SpaceOutliner &space_outliner) const override;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementRNAProperty : public TreeElementRNACommon {
+ private:
+ PropertyRNA *rna_prop_ = nullptr;
+
+ public:
+ TreeElementRNAProperty(TreeElement &legacy_te, PointerRNA &rna_ptr, int index);
+ void expand(SpaceOutliner &space_outliner) const override;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementRNAArrayElement : public TreeElementRNACommon {
+ public:
+ TreeElementRNAArrayElement(TreeElement &legacy_te, PointerRNA &rna_ptr, int index);
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc
index a46e8de1bdd..dad03d392fb 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc
@@ -24,8 +24,10 @@
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "DNA_outliner_types.h"
+
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_element_scene_objects.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh
index a2aa29c4a33..7ce5a404f5c 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh
@@ -22,6 +22,8 @@
#include "tree_element.hh"
+struct Scene;
+
namespace blender::ed::outliner {
class TreeElementSceneObjectsBase final : public AbstractTreeElement {
diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc
index 7bb9405147e..65786ac89ed 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc
@@ -19,13 +19,14 @@
*/
#include "DNA_layer_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
#include "BLI_listbase_wrapper.hh"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_view_layer.hh"
diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c
index 11bee36e914..4c4cba2ac58 100644
--- a/source/blender/editors/space_script/space_script.c
+++ b/source/blender/editors/space_script/space_script.c
@@ -162,7 +162,6 @@ static void script_main_region_listener(const wmRegionListenerParams *UNUSED(par
#endif
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_script(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype script");
diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt
index e1c193b0c15..bf8cf89699d 100644
--- a/source/blender/editors/space_sequencer/CMakeLists.txt
+++ b/source/blender/editors/space_sequencer/CMakeLists.txt
@@ -22,6 +22,7 @@ set(INC
../../blenlib
../../blentranslation
../../depsgraph
+ ../../draw
../../gpu
../../imbuf
../../makesdna
@@ -45,6 +46,7 @@ set(SRC
sequencer_proxy.c
sequencer_scopes.c
sequencer_select.c
+ sequencer_thumbnails.c
sequencer_view.c
space_sequencer.c
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index bdfa639b327..72c39839739 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -59,6 +59,7 @@
#include "SEQ_add.h"
#include "SEQ_effects.h"
+#include "SEQ_iterator.h"
#include "SEQ_proxy.h"
#include "SEQ_relations.h"
#include "SEQ_render.h"
@@ -195,7 +196,7 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type)
}
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if ((type == -1 || seq->type == type) && (seq->enddisp < timeline_frame) &&
+ if ((ELEM(type, -1, seq->type)) && (seq->enddisp < timeline_frame) &&
(timeline_frame - seq->enddisp < proximity)) {
tgt = seq;
proximity = timeline_frame - seq->enddisp;
@@ -601,35 +602,48 @@ static IMB_Proxy_Size seq_get_proxy_size_flags(bContext *C)
return proxy_sizes;
}
-static void seq_build_proxy(bContext *C, Sequence *seq)
+static void seq_build_proxy(bContext *C, SeqCollection *movie_strips)
{
if (U.sequencer_proxy_setup != USER_SEQ_PROXY_SETUP_AUTOMATIC) {
return;
}
- /* Enable and set proxy size. */
- SEQ_proxy_set(seq, true);
- seq->strip->proxy->build_size_flags = seq_get_proxy_size_flags(C);
- seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING;
-
- /* Build proxy. */
- GSet *file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
wmJob *wm_job = ED_seq_proxy_wm_job_get(C);
ProxyJob *pj = ED_seq_proxy_job_get(C, wm_job);
- SEQ_proxy_rebuild_context(pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
- BLI_gset_free(file_list, MEM_freeN);
+
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, movie_strips) {
+ /* Enable and set proxy size. */
+ SEQ_proxy_set(seq, true);
+ seq->strip->proxy->build_size_flags = seq_get_proxy_size_flags(C);
+ seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING;
+ SEQ_proxy_rebuild_context(pj->main, pj->depsgraph, pj->scene, seq, NULL, &pj->queue, true);
+ }
if (!WM_jobs_is_running(wm_job)) {
G.is_break = false;
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
-
ED_area_tag_redraw(CTX_wm_area(C));
}
+static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene,
+ ListBase *seqbase,
+ Sequence *seq_movie,
+ Sequence *seq_sound)
+{
+ if (ELEM(NULL, seq_movie, seq_sound) || seq_sound->len <= seq_movie->len) {
+ return;
+ }
+
+ SEQ_transform_set_right_handle_frame(seq_sound, SEQ_transform_get_right_handle_frame(seq_movie));
+ SEQ_time_update_sequence(scene, seqbase, seq_sound);
+}
+
static void sequencer_add_movie_multiple_strips(bContext *C,
wmOperator *op,
- SeqLoadData *load_data)
+ SeqLoadData *load_data,
+ SeqCollection *r_movie_strips)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -678,23 +692,30 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
load_data->start_frame += audio_frame_offset;
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, audio_skip);
- int min_startdisp = MIN2(seq_movie->startdisp, seq_sound->startdisp);
- int max_enddisp = MAX2(seq_movie->enddisp, seq_sound->enddisp);
+ int min_startdisp = 0, max_enddisp = 0;
+ if (seq_sound != NULL) {
+ min_startdisp = MIN2(seq_movie->startdisp, seq_sound->startdisp);
+ max_enddisp = MAX2(seq_movie->enddisp, seq_sound->enddisp);
+ }
load_data->start_frame += max_enddisp - min_startdisp - audio_frame_offset;
}
else {
load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp;
}
+ sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound);
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
- seq_build_proxy(C, seq_movie);
+ SEQ_collection_append_strip(seq_movie, r_movie_strips);
}
}
RNA_END;
}
-static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoadData *load_data)
+static bool sequencer_add_movie_single_strip(bContext *C,
+ wmOperator *op,
+ SeqLoadData *load_data,
+ SeqCollection *r_movie_strips)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -737,9 +758,10 @@ static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoa
load_data->start_frame += audio_frame_offset;
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, audio_skip);
}
+ sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound);
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
- seq_build_proxy(C, seq_movie);
+ SEQ_collection_append_strip(seq_movie, r_movie_strips);
return true;
}
@@ -756,21 +778,25 @@ static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
ED_sequencer_deselect_all(scene);
}
+ SeqCollection *movie_strips = SEQ_collection_create(__func__);
const int tot_files = RNA_property_collection_length(op->ptr,
RNA_struct_find_property(op->ptr, "files"));
if (tot_files > 1) {
- sequencer_add_movie_multiple_strips(C, op, &load_data);
+ sequencer_add_movie_multiple_strips(C, op, &load_data, movie_strips);
}
else {
- if (!sequencer_add_movie_single_strip(C, op, &load_data)) {
- sequencer_add_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
+ sequencer_add_movie_single_strip(C, op, &load_data, movie_strips);
+ }
+
+ if (SEQ_collection_len(movie_strips) == 0) {
+ SEQ_collection_free(movie_strips);
+ return OPERATOR_CANCELLED;
}
/* Free custom data. */
sequencer_add_cancel(C, op);
+ seq_build_proxy(C, movie_strips);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -1111,7 +1137,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
/* Adjust length. */
if (load_data.image.len == 1) {
SEQ_transform_set_right_handle_frame(seq, load_data.image.end_frame);
- SEQ_time_update_sequence(scene, seq);
+ SEQ_time_update_sequence(scene, SEQ_active_seqbase_get(ed), seq);
}
seq_load_apply_generic_options(C, op, seq);
diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c
index 1e0ecfd890e..4ece7f6a481 100644
--- a/source/blender/editors/space_sequencer/sequencer_buttons.c
+++ b/source/blender/editors/space_sequencer/sequencer_buttons.c
@@ -78,9 +78,10 @@ static void metadata_panel_context_draw(const bContext *C, Panel *panel)
SpaceSeq *space_sequencer = CTX_wm_space_seq(C);
/* NOTE: We can only reliably show metadata for the original (current)
* frame when split view is used. */
- const bool show_split = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) &&
+ const bool show_split = (scene->ed &&
+ (scene->ed->overlay_frame_flag & SEQ_EDIT_OVERLAY_FRAME_SHOW) &&
(space_sequencer->mainb == SEQ_DRAW_IMG_IMBUF));
- if (show_split && space_sequencer->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE) {
+ if (show_split && (space_sequencer->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_REFERENCE)) {
return;
}
/* NOTE: We disable multiview for drawing, since we don't know what is the
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index ae392980069..6dffc0bc2a4 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -25,7 +25,6 @@
#include <string.h>
#include "BLI_blenlib.h"
-#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_string_utils.h"
#include "BLI_threads.h"
@@ -45,7 +44,6 @@
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
-#include "BKE_main.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
@@ -103,14 +101,13 @@
#define SEQ_HANDLE_SIZE 8.0f
#define SEQ_SCROLLER_TEXT_OFFSET 8
#define MUTE_ALPHA 120
-#define OVERLAP_ALPHA 180
static Sequence *special_seq_update = NULL;
void color3ubv_from_seq(const Scene *curscene,
- const Sequence *seq,
- const bool show_strip_color_tag,
- uchar r_col[3])
+ const Sequence *seq,
+ const bool show_strip_color_tag,
+ uchar r_col[3])
{
if (show_strip_color_tag && (uint)seq->color_tag < SEQUENCE_COLOR_TOT &&
seq->color_tag != SEQUENCE_COLOR_NONE) {
@@ -349,8 +346,8 @@ static void draw_seq_waveform_overlay(View2D *v2d,
float y2,
float frames_per_pixel)
{
- if (seq->sound &&
- ((sseq->flag & SEQ_TIMELINE_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) {
+ if (seq->sound && ((sseq->timeline_overlay.flag & SEQ_TIMELINE_ALL_WAVEFORMS) ||
+ (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) {
/* Make sure that the start drawing position is aligned to the pixels on the screen to avoid
* flickering when moving around the strip.
* To do this we figure out the fractional offset in pixel space by checking where the
@@ -671,7 +668,6 @@ static void drawmeta_contents(Scene *scene,
GPU_blend(GPU_BLEND_NONE);
}
-/* Get handle width in 2d-View space. */
float sequence_handle_size_get_clamped(Sequence *seq, const float pixelx)
{
const float maxhandle = (pixelx * SEQ_HANDLE_SIZE) * U.pixelsize;
@@ -1312,526 +1308,6 @@ static void draw_seq_fcurve_overlay(
}
}
-typedef struct ThumbnailDrawJob {
- SeqRenderData context;
- GHash *sequences_ghash;
- Scene *scene;
- rctf *view_area;
- float pixelx;
- float pixely;
-} ThumbnailDrawJob;
-
-typedef struct ThumbDataItem {
- Sequence *seq_dupli;
- Scene *scene;
-} ThumbDataItem;
-
-static void thumbnail_hash_data_free(void *val)
-{
- ThumbDataItem *item = val;
- SEQ_sequence_free(item->scene, item->seq_dupli, 0);
- MEM_freeN(val);
-}
-
-static void thumbnail_freejob(void *data)
-{
- ThumbnailDrawJob *tj = data;
- BLI_ghash_free(tj->sequences_ghash, NULL, thumbnail_hash_data_free);
- MEM_freeN(tj->view_area);
- MEM_freeN(tj);
-}
-
-static void thumbnail_endjob(void *data)
-{
- ThumbnailDrawJob *tj = data;
- WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, tj->scene);
-}
-
-static bool check_seq_need_thumbnails(Sequence *seq, rctf *view_area)
-{
- if (seq->type != SEQ_TYPE_MOVIE && seq->type != SEQ_TYPE_IMAGE) {
- return false;
- }
- if (min_ii(seq->startdisp, seq->start) > view_area->xmax) {
- return false;
- }
- if (max_ii(seq->enddisp, seq->start + seq->len) < view_area->xmin) {
- return false;
- }
- if (seq->machine + 1.0f < view_area->ymin) {
- return false;
- }
- if (seq->machine > view_area->ymax) {
- return false;
- }
-
- return true;
-}
-
-static void seq_get_thumb_image_dimensions(Sequence *seq,
- float pixelx,
- float pixely,
- float *r_thumb_width,
- float *r_thumb_height,
- float *r_image_width,
- float *r_image_height)
-{
- float image_width = seq->strip->stripdata->orig_width;
- float image_height = seq->strip->stripdata->orig_height;
-
- /* Fix the dimensions to be max SEQ_RENDER_THUMB_SIZE (256) for x or y. */
- float aspect_ratio = (float)image_width / image_height;
- if (image_width > image_height) {
- image_width = SEQ_RENDER_THUMB_SIZE;
- image_height = round_fl_to_int(image_width / aspect_ratio);
- }
- else {
- image_height = SEQ_RENDER_THUMB_SIZE;
- image_width = round_fl_to_int(image_height * aspect_ratio);
- }
-
- /* Calculate thumb dimensions. */
- float thumb_height = (SEQ_STRIP_OFSTOP - SEQ_STRIP_OFSBOTTOM) - (20 * U.dpi_fac * pixely);
- aspect_ratio = ((float)image_width) / image_height;
- float thumb_h_px = thumb_height / pixely;
- float thumb_width = aspect_ratio * thumb_h_px * pixelx;
-
- if (r_thumb_height == NULL) {
- *r_thumb_width = thumb_width;
- return;
- }
-
- *r_thumb_height = thumb_height;
- *r_image_width = image_width;
- *r_image_height = image_height;
- *r_thumb_width = thumb_width;
-}
-
-static float seq_thumbnail_get_start_frame(Sequence *seq, float frame_step, rctf *view_area)
-{
- if (seq->start > view_area->xmin && seq->start < view_area->xmax) {
- return seq->start;
- }
-
- /* Drawing and caching both check to see if strip is in view area or not before calling this
- * function so assuming strip/part of strip in view. */
-
- int no_invisible_thumbs = (view_area->xmin - seq->start) / frame_step;
- return ((no_invisible_thumbs - 1) * frame_step) + seq->start;
-}
-
-static void thumbnail_start_job(void *data,
- short *stop,
- short *UNUSED(do_update),
- float *UNUSED(progress))
-{
- ThumbnailDrawJob *tj = data;
- float start_frame, frame_step;
-
- GHashIterator gh_iter;
- BLI_ghashIterator_init(&gh_iter, tj->sequences_ghash);
- while (!BLI_ghashIterator_done(&gh_iter) & !*stop) {
- Sequence *seq_orig = BLI_ghashIterator_getKey(&gh_iter);
- ThumbDataItem *val = BLI_ghash_lookup(tj->sequences_ghash, seq_orig);
-
- if (check_seq_need_thumbnails(seq_orig, tj->view_area)) {
- seq_get_thumb_image_dimensions(
- val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, NULL, NULL, NULL);
- start_frame = seq_thumbnail_get_start_frame(seq_orig, frame_step, tj->view_area);
- SEQ_render_thumbnails(
- &tj->context, val->seq_dupli, seq_orig, start_frame, frame_step, tj->view_area, stop);
- SEQ_render_thumbnails_base_set(&tj->context, val->seq_dupli, seq_orig, tj->view_area, stop);
- }
- BLI_ghashIterator_step(&gh_iter);
- }
-}
-
-static SeqRenderData sequencer_thumbnail_context_init(const bContext *C)
-{
- struct Main *bmain = CTX_data_main(C);
- struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Scene *scene = CTX_data_scene(C);
- SpaceSeq *sseq = CTX_wm_space_seq(C);
- SeqRenderData context = {0};
-
- /* Taking rectx and recty as 0 as dimensions not known here, and context is used to calculate
- * hash key but not necessary as other variables of SeqRenderData are unique enough. */
- SEQ_render_new_render_data(bmain, depsgraph, scene, 0, 0, sseq->render_size, false, &context);
- context.view_id = BKE_scene_multiview_view_id_get(&scene->r, STEREO_LEFT_NAME);
- context.use_proxies = false;
-
- return context;
-}
-
-static GHash *sequencer_thumbnail_ghash_init(const bContext *C, View2D *v2d, Editing *ed)
-{
- Scene *scene = CTX_data_scene(C);
-
- /* Set the data for thumbnail caching job. */
- GHash *thumb_data_hash = BLI_ghash_ptr_new("seq_duplicates_and_origs");
-
- LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
- ThumbDataItem *val_need_update = BLI_ghash_lookup(thumb_data_hash, seq);
- if (val_need_update == NULL && check_seq_need_thumbnails(seq, &v2d->cur)) {
- ThumbDataItem *val = MEM_callocN(sizeof(ThumbDataItem), "Thumbnail Hash Values");
- val->seq_dupli = SEQ_sequence_dupli_recursive(scene, scene, NULL, seq, 0);
- val->scene = scene;
- BLI_ghash_insert(thumb_data_hash, seq, val);
- }
- else {
- if (val_need_update != NULL) {
- val_need_update->seq_dupli->start = seq->start;
- val_need_update->seq_dupli->startdisp = seq->startdisp;
- }
- }
- }
-
- return thumb_data_hash;
-}
-
-static void sequencer_thumbnail_init_job(const bContext *C, View2D *v2d, Editing *ed)
-{
- wmJob *wm_job;
- ThumbnailDrawJob *tj = NULL;
- ScrArea *area = CTX_wm_area(C);
- wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- CTX_data_scene(C),
- "Draw Thumbnails",
- 0,
- WM_JOB_TYPE_SEQ_DRAW_THUMBNAIL);
-
- /* Get the thumbnail job if it exists. */
- tj = WM_jobs_customdata_get(wm_job);
- if (!tj) {
- tj = MEM_callocN(sizeof(ThumbnailDrawJob), "Thumbnail cache job");
-
- /* Duplicate value of v2d->cur and v2d->tot to have module separation. */
- rctf *view_area = MEM_callocN(sizeof(struct rctf), "viewport area");
- view_area->xmax = v2d->cur.xmax;
- view_area->xmin = v2d->cur.xmin;
- view_area->ymax = v2d->cur.ymax;
- view_area->ymin = v2d->cur.ymin;
-
- tj->scene = CTX_data_scene(C);
- tj->view_area = view_area;
- tj->context = sequencer_thumbnail_context_init(C);
- tj->sequences_ghash = sequencer_thumbnail_ghash_init(C, v2d, ed);
- tj->pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
- tj->pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask);
- WM_jobs_customdata_set(wm_job, tj, thumbnail_freejob);
- WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_SEQUENCER, NC_SCENE | ND_SEQUENCER);
- WM_jobs_callbacks(wm_job, thumbnail_start_job, NULL, NULL, thumbnail_endjob);
- }
-
- if (!WM_jobs_is_running(wm_job)) {
- G.is_break = false;
- WM_jobs_start(CTX_wm_manager(C), wm_job);
- }
- else {
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL);
- }
-
- ED_area_tag_redraw(area);
-}
-
-static bool sequencer_thumbnail_v2d_is_navigating(const bContext *C)
-{
- ARegion *region = CTX_wm_region(C);
- View2D *v2d = &region->v2d;
- return (v2d->flag & V2D_IS_NAVIGATING) != 0;
-}
-
-static void sequencer_thumbnail_start_job_if_necessary(const bContext *C,
- Editing *ed,
- View2D *v2d,
- bool thumbnail_is_missing)
-{
- SpaceSeq *sseq = CTX_wm_space_seq(C);
-
- if (sequencer_thumbnail_v2d_is_navigating(C)) {
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL);
- return;
- }
-
- /* `thumbnail_is_missing` should be set to true if missing image in strip. False when normal call
- * to all strips done. */
- if (v2d->cur.xmax != sseq->runtime.last_thumbnail_area.xmax ||
- v2d->cur.ymax != sseq->runtime.last_thumbnail_area.ymax || thumbnail_is_missing) {
-
- /* Stop the job first as view has changed. Pointless to continue old job. */
- if (v2d->cur.xmax != sseq->runtime.last_thumbnail_area.xmax ||
- v2d->cur.ymax != sseq->runtime.last_thumbnail_area.ymax) {
- WM_jobs_stop(CTX_wm_manager(C), NULL, thumbnail_start_job);
- }
-
- sequencer_thumbnail_init_job(C, v2d, ed);
- sseq->runtime.last_thumbnail_area = v2d->cur;
- }
-}
-
-void last_displayed_thumbnails_list_free(void *val)
-{
- BLI_gset_free(val, NULL);
-}
-
-static GSet *last_displayed_thumbnails_list_ensure(const bContext *C, Sequence *seq)
-{
- SpaceSeq *sseq = CTX_wm_space_seq(C);
- if (sseq->runtime.last_displayed_thumbnails == NULL) {
- sseq->runtime.last_displayed_thumbnails = BLI_ghash_ptr_new(__func__);
- }
-
- GSet *displayed_thumbnails = BLI_ghash_lookup(sseq->runtime.last_displayed_thumbnails, seq);
- if (displayed_thumbnails == NULL) {
- displayed_thumbnails = BLI_gset_int_new(__func__);
- BLI_ghash_insert(sseq->runtime.last_displayed_thumbnails, seq, displayed_thumbnails);
- }
-
- return displayed_thumbnails;
-}
-
-static void last_displayed_thumbnails_list_cleanup(GSet *previously_displayed,
- float range_start,
- float range_end)
-{
- GSetIterator gset_iter;
- BLI_gsetIterator_init(&gset_iter, previously_displayed);
- while (!BLI_gsetIterator_done(&gset_iter)) {
- int frame = (float)POINTER_AS_INT(BLI_gsetIterator_getKey(&gset_iter));
- BLI_gsetIterator_step(&gset_iter);
-
- if (frame > range_start && frame < range_end) {
- BLI_gset_remove(previously_displayed, POINTER_FROM_INT(frame), NULL);
- }
- }
-}
-
-static int sequencer_thumbnail_closest_previous_frame_get(int timeline_frame,
- GSet *previously_displayed)
-{
- int best_diff = INT_MAX;
- int best_frame = timeline_frame;
-
- /* Previously displayed thumbnails. */
- GSetIterator gset_iter;
- BLI_gsetIterator_init(&gset_iter, previously_displayed);
- while (!BLI_gsetIterator_done(&gset_iter)) {
- int frame = POINTER_AS_INT(BLI_gsetIterator_getKey(&gset_iter));
- int diff = abs(frame - timeline_frame);
- if (diff < best_diff) {
- best_diff = diff;
- best_frame = frame;
- }
- BLI_gsetIterator_step(&gset_iter);
- }
- return best_frame;
-}
-
-static int sequencer_thumbnail_closest_guaranteed_frame_get(Sequence *seq, int timeline_frame)
-{
- if (timeline_frame <= seq->startdisp) {
- return seq->startdisp;
- }
-
- /* Set of "guaranteed" thumbnails. */
- const int frame_index = timeline_frame - seq->startdisp;
- const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(seq);
- const int relative_base_frame = round_fl_to_int((frame_index / (float)frame_step)) * frame_step;
- const int nearest_guaranted_absolute_frame = relative_base_frame + seq->startdisp;
- return nearest_guaranted_absolute_frame;
-}
-
-static ImBuf *sequencer_thumbnail_closest_from_memory(const SeqRenderData *context,
- Sequence *seq,
- int timeline_frame,
- GSet *previously_displayed,
- rcti *crop,
- bool clipped)
-{
- int frame_previous = sequencer_thumbnail_closest_previous_frame_get(timeline_frame,
- previously_displayed);
- ImBuf *ibuf_previous = SEQ_get_thumbnail(context, seq, frame_previous, crop, clipped);
-
- int frame_guaranteed = sequencer_thumbnail_closest_guaranteed_frame_get(seq, timeline_frame);
- ImBuf *ibuf_guaranteed = SEQ_get_thumbnail(context, seq, frame_guaranteed, crop, clipped);
-
- ImBuf *closest_in_memory = NULL;
-
- if (ibuf_previous && ibuf_guaranteed) {
- if (abs(frame_previous - timeline_frame) < abs(frame_guaranteed - timeline_frame)) {
- IMB_freeImBuf(ibuf_guaranteed);
- closest_in_memory = ibuf_previous;
- }
- else {
- IMB_freeImBuf(ibuf_previous);
- closest_in_memory = ibuf_guaranteed;
- }
- }
-
- if (ibuf_previous == NULL) {
- closest_in_memory = ibuf_guaranteed;
- }
-
- if (ibuf_guaranteed == NULL) {
- closest_in_memory = ibuf_previous;
- }
-
- return closest_in_memory;
-}
-
-static void draw_seq_strip_thumbnail(View2D *v2d,
- const bContext *C,
- Scene *scene,
- Sequence *seq,
- float y1,
- float y2,
- float pixelx,
- float pixely)
-{
- bool clipped = false;
- float image_height, image_width, thumb_width, thumb_height;
- rcti crop;
-
- /* If width of the strip too small ignore drawing thumbnails. */
- if ((y2 - y1) / pixely <= 40 * U.dpi_fac) {
- return;
- }
-
- SeqRenderData context = sequencer_thumbnail_context_init(C);
-
- if ((seq->flag & SEQ_FLAG_SKIP_THUMBNAILS) != 0) {
- return;
- }
-
- seq_get_thumb_image_dimensions(
- seq, pixelx, pixely, &thumb_width, &thumb_height, &image_width, &image_height);
-
- float thumb_y_end = y1 + thumb_height - pixely;
-
- float cut_off = 0;
- float upper_thumb_bound = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp;
- if (seq->type == SEQ_TYPE_IMAGE) {
- upper_thumb_bound = seq->enddisp;
- }
-
- float thumb_x_start = seq_thumbnail_get_start_frame(seq, thumb_width, &v2d->cur);
- float thumb_x_end;
-
- while (thumb_x_start + thumb_width < v2d->cur.xmin) {
- thumb_x_start += thumb_width;
- }
-
- /* Ignore thumbs to the left of strip. */
- while (thumb_x_start + thumb_width < seq->startdisp) {
- thumb_x_start += thumb_width;
- }
-
- GSet *last_displayed_thumbnails = last_displayed_thumbnails_list_ensure(C, seq);
- /* Cleanup thumbnail list outside of rendered range, which is cleaned up one by one to prevent
- * flickering after zooming. */
- if (!sequencer_thumbnail_v2d_is_navigating(C)) {
- last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, -FLT_MAX, thumb_x_start);
- }
-
- /* Start drawing. */
- while (thumb_x_start < upper_thumb_bound) {
- thumb_x_end = thumb_x_start + thumb_width;
- clipped = false;
-
- /* Checks to make sure that thumbs are loaded only when in view and within the confines of the
- * strip. Some may not be required but better to have conditions for safety as x1 here is
- * point to start caching from and not drawing. */
- if (thumb_x_start > v2d->cur.xmax) {
- break;
- }
-
- /* Set the clipping bound to show the left handle moving over thumbs and not shift thumbs. */
- if (IN_RANGE_INCL(seq->startdisp, thumb_x_start, thumb_x_end)) {
- cut_off = seq->startdisp - thumb_x_start;
- clipped = true;
- }
-
- /* Clip if full thumbnail cannot be displayed. */
- if (thumb_x_end > (upper_thumb_bound)) {
- thumb_x_end = upper_thumb_bound;
- clipped = true;
- if (thumb_x_end - thumb_x_start < 1) {
- break;
- }
- }
-
- float zoom_x = thumb_width / image_width;
- float zoom_y = thumb_height / image_height;
-
- float cropx_min = (cut_off / pixelx) / (zoom_y / pixely);
- float cropx_max = ((thumb_x_end - thumb_x_start) / pixelx) / (zoom_y / pixely);
- if (cropx_max == (thumb_x_end - thumb_x_start)) {
- cropx_max = cropx_max + 1;
- }
- BLI_rcti_init(&crop, (int)(cropx_min), (int)cropx_max, 0, (int)(image_height)-1);
-
- int timeline_frame = round_fl_to_int(thumb_x_start);
-
- /* Get the image. */
- ImBuf *ibuf = SEQ_get_thumbnail(&context, seq, timeline_frame, &crop, clipped);
-
- if (!ibuf) {
- sequencer_thumbnail_start_job_if_necessary(C, scene->ed, v2d, true);
-
- ibuf = sequencer_thumbnail_closest_from_memory(
- &context, seq, timeline_frame, last_displayed_thumbnails, &crop, clipped);
- }
- /* Store recently rendered frames, so they can be reused when zooming. */
- else if (!sequencer_thumbnail_v2d_is_navigating(C)) {
- /* Clear images in frame range occupied by new thumbnail. */
- last_displayed_thumbnails_list_cleanup(
- last_displayed_thumbnails, thumb_x_start, thumb_x_end);
- /* Insert new thumbnail frame to list. */
- BLI_gset_add(last_displayed_thumbnails, POINTER_FROM_INT(timeline_frame));
- }
-
- /* If there is no image still, abort. */
- if (!ibuf) {
- break;
- }
-
- /* Transparency on overlap. */
- if (seq->flag & SEQ_OVERLAP) {
- GPU_blend(GPU_BLEND_ALPHA);
- if (ibuf->rect) {
- unsigned char *buf = (unsigned char *)ibuf->rect;
- for (int pixel = ibuf->x * ibuf->y; pixel--; buf += 4) {
- buf[3] = OVERLAP_ALPHA;
- }
- }
- else if (ibuf->rect_float) {
- float *buf = (float *)ibuf->rect_float;
- for (int pixel = ibuf->x * ibuf->y; pixel--; buf += ibuf->channels) {
- buf[3] = (OVERLAP_ALPHA / 255.0f);
- }
- }
- }
-
- ED_draw_imbuf_ctx_clipping(C,
- ibuf,
- thumb_x_start + cut_off,
- y1,
- true,
- thumb_x_start + cut_off,
- y1,
- thumb_x_end,
- thumb_y_end,
- zoom_x,
- zoom_y);
- IMB_freeImBuf(ibuf);
- GPU_blend(GPU_BLEND_NONE);
- cut_off = 0;
- thumb_x_start += thumb_width;
- }
- last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, thumb_x_start, FLT_MAX);
-}
-
/* Draw visible strips. Bounds check are already made. */
static void draw_seq_strip(const bContext *C,
SpaceSeq *sseq,
@@ -1865,9 +1341,9 @@ static void draw_seq_strip(const bContext *C,
float text_margin_y;
bool y_threshold;
- if ((sseq->flag & SEQ_TIMELINE_SHOW_STRIP_NAME) ||
- (sseq->flag & SEQ_TIMELINE_SHOW_STRIP_SOURCE) ||
- (sseq->flag & SEQ_TIMELINE_SHOW_STRIP_DURATION)) {
+ if ((sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_NAME) ||
+ (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_SOURCE) ||
+ (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION)) {
/* Calculate height needed for drawing text on strip. */
text_margin_y = y2 - min_ff(0.40f, 20 * U.dpi_fac * pixely);
@@ -1911,8 +1387,9 @@ static void draw_seq_strip(const bContext *C,
if ((sseq->flag & SEQ_SHOW_OVERLAY) &&
(sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_THUMBNAILS) &&
- (seq->type == SEQ_TYPE_MOVIE || seq->type == SEQ_TYPE_IMAGE)) {
- draw_seq_strip_thumbnail(v2d, C, scene, seq, y1, y2, pixelx, pixely);
+ (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE))) {
+ draw_seq_strip_thumbnail(
+ v2d, C, scene, seq, y1, y_threshold ? text_margin_y : y2, pixelx, pixely);
}
if ((sseq->flag & SEQ_SHOW_OVERLAY) &&
@@ -2039,13 +1516,6 @@ void ED_sequencer_special_preview_clear(void)
sequencer_special_update_set(NULL);
}
-/**
- * Rendering using opengl will change the current viewport/context.
- * This is why we need the \a region, to set back the render area.
- *
- * TODO: do not rely on such hack and just update the \a ibuf outside of
- * the UI drawing code.
- */
ImBuf *sequencer_ibuf_get(struct Main *bmain,
ARegion *region,
struct Depsgraph *depsgraph,
@@ -2385,15 +1855,15 @@ static void sequencer_preview_get_rect(rctf *preview,
sequencer_display_size(scene, viewrect);
BLI_rctf_init(preview, -1.0f, 1.0f, -1.0f, 1.0f);
- if (draw_overlay && sseq->overlay_type == SEQ_DRAW_OVERLAY_RECT) {
+ if (draw_overlay && (sseq->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_RECT)) {
preview->xmax = v2d->tot.xmin +
- (fabsf(BLI_rctf_size_x(&v2d->tot)) * scene->ed->over_border.xmax);
+ (fabsf(BLI_rctf_size_x(&v2d->tot)) * scene->ed->overlay_frame_rect.xmax);
preview->xmin = v2d->tot.xmin +
- (fabsf(BLI_rctf_size_x(&v2d->tot)) * scene->ed->over_border.xmin);
+ (fabsf(BLI_rctf_size_x(&v2d->tot)) * scene->ed->overlay_frame_rect.xmin);
preview->ymax = v2d->tot.ymin +
- (fabsf(BLI_rctf_size_y(&v2d->tot)) * scene->ed->over_border.ymax);
+ (fabsf(BLI_rctf_size_y(&v2d->tot)) * scene->ed->overlay_frame_rect.ymax);
preview->ymin = v2d->tot.ymin +
- (fabsf(BLI_rctf_size_y(&v2d->tot)) * scene->ed->over_border.ymin);
+ (fabsf(BLI_rctf_size_y(&v2d->tot)) * scene->ed->overlay_frame_rect.ymin);
}
else if (draw_backdrop) {
float aspect = BLI_rcti_size_x(&region->winrct) / (float)BLI_rcti_size_y(&region->winrct);
@@ -2481,8 +1951,8 @@ static void sequencer_draw_display_buffer(const bContext *C,
rctf canvas;
sequencer_preview_get_rect(&preview, scene, region, sseq, draw_overlay, draw_backdrop);
- if (draw_overlay && sseq->overlay_type == SEQ_DRAW_OVERLAY_RECT) {
- canvas = scene->ed->over_border;
+ if (draw_overlay && (sseq->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_RECT)) {
+ canvas = scene->ed->overlay_frame_rect;
}
else {
BLI_rctf_init(&canvas, 0.0f, 1.0f, 0.0f, 1.0f);
@@ -2616,9 +2086,13 @@ static int sequencer_draw_get_transform_preview_frame(Scene *scene)
return preview_frame;
}
-static void seq_draw_image_origin_and_outline(const bContext *C, Sequence *seq)
+static void seq_draw_image_origin_and_outline(const bContext *C, Sequence *seq, bool is_active_seq)
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
+ const ARegion *region = CTX_wm_region(C);
+ if (region->regiontype == RGN_TYPE_PREVIEW && !sequencer_view_preview_only_poll(C)) {
+ return;
+ }
if ((seq->flag & SELECT) == 0) {
return;
}
@@ -2659,7 +2133,12 @@ static void seq_draw_image_origin_and_outline(const bContext *C, Sequence *seq)
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
float col[3];
- UI_GetThemeColor3fv(TH_SEQ_SELECTED, col);
+ if (is_active_seq) {
+ UI_GetThemeColor3fv(TH_SEQ_ACTIVE, col);
+ }
+ else {
+ UI_GetThemeColor3fv(TH_SEQ_SELECTED, col);
+ }
immUniformColor3fv(col);
immUniform1f("lineWidth", U.pixelsize);
immBegin(GPU_PRIM_LINE_LOOP, 4);
@@ -2725,7 +2204,8 @@ void sequencer_draw_preview(const bContext *C,
UI_view2d_view_ortho(v2d);
/* Draw background. */
- if (!draw_backdrop && (!draw_overlay || sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE)) {
+ if (!draw_backdrop &&
+ (!draw_overlay || (sseq->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_REFERENCE))) {
sequencer_preview_clear();
if (sseq->flag & SEQ_USE_ALPHA) {
@@ -2751,10 +2231,11 @@ void sequencer_draw_preview(const bContext *C,
}
if (!draw_backdrop && scene->ed != NULL) {
- SeqCollection *collection = SEQ_query_rendered_strips(&scene->ed->seqbase, timeline_frame, 0);
+ SeqCollection *collection = SEQ_query_rendered_strips(scene->ed->seqbasep, timeline_frame, 0);
Sequence *seq;
+ Sequence *active_seq = SEQ_select_active_get(scene);
SEQ_ITERATOR_FOREACH (seq, collection) {
- seq_draw_image_origin_and_outline(C, seq);
+ seq_draw_image_origin_and_outline(C, seq, seq == active_seq);
}
SEQ_collection_free(collection);
}
@@ -2767,6 +2248,11 @@ void sequencer_draw_preview(const bContext *C,
sequencer_draw_maskedit(C, scene, region, sseq);
#endif
+ /* Draw registered callbacks. */
+ GPU_framebuffer_bind(framebuffer_overlay);
+ ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW);
+ GPU_framebuffer_bind_no_srgb(framebuffer_overlay);
+
/* Scope is freed in sequencer_check_scopes when `ibuf` changes and redraw is needed. */
if (ibuf) {
IMB_freeImBuf(ibuf);
@@ -2776,28 +2262,15 @@ void sequencer_draw_preview(const bContext *C,
seq_prefetch_wm_notify(C, scene);
}
-/* Draw backdrop in sequencer timeline. */
-static void draw_seq_backdrop(View2D *v2d)
+static void draw_seq_timeline_channels(View2D *v2d)
{
- int i;
-
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- /* View backdrop. */
- immUniformThemeColorShade(TH_BACK, -25);
- immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
-
- /* Darker overlay over the view backdrop. */
- immUniformThemeColorShade(TH_BACK, -20);
- immRectf(pos, v2d->cur.xmin, -1.0, v2d->cur.xmax, 1.0);
-
- /* Alternating horizontal stripes. */
- i = max_ii(1, ((int)v2d->cur.ymin) - 1);
-
GPU_blend(GPU_BLEND_ALPHA);
immUniformThemeColor(TH_ROW_ALTERNATE);
+ /* Alternating horizontal stripes. */
+ int i = max_ii(1, ((int)v2d->cur.ymin) - 1);
while (i < v2d->cur.ymax) {
if (i & 1) {
immRectf(pos, v2d->cur.xmin, i, v2d->cur.xmax, i + 1);
@@ -2806,22 +2279,17 @@ static void draw_seq_backdrop(View2D *v2d)
}
GPU_blend(GPU_BLEND_NONE);
-
- /* Lines separating the horizontal bands. */
- i = max_ii(1, ((int)v2d->cur.ymin) - 1);
- int line_len = (int)v2d->cur.ymax - i + 1;
- immUniformThemeColorShade(TH_GRID, 10);
- immBegin(GPU_PRIM_LINES, line_len * 2);
- while (line_len--) {
- immVertex2f(pos, v2d->cur.xmax, i);
- immVertex2f(pos, v2d->cur.xmin, i);
- i++;
- }
- immEnd();
-
immUnbindProgram();
}
+static void draw_seq_timeline_channel_numbers(ARegion *region)
+{
+ View2D *v2d = &region->v2d;
+ rcti rect;
+ BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y);
+ UI_view2d_draw_scale_y__block(region, v2d, &rect, TH_SCROLL_TEXT);
+}
+
static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
{
Scene *scene = CTX_data_scene(C);
@@ -2924,7 +2392,7 @@ static void seq_draw_sfra_efra(const Scene *scene, View2D *v2d)
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* Draw overlay outside of frame range. */
- immUniformThemeColorShadeAlpha(TH_BACK, -25, -100);
+ immUniformThemeColorShadeAlpha(TH_BACK, -10, -100);
if (frame_sta < frame_end) {
immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)frame_sta, v2d->cur.ymax);
@@ -3197,9 +2665,9 @@ static void draw_cache_view(const bContext *C)
/* Draw sequencer timeline. */
static void draw_overlap_frame_indicator(const struct Scene *scene, const View2D *v2d)
{
- int overlap_frame = (scene->ed->over_flag & SEQ_EDIT_OVERLAY_ABS) ?
- scene->ed->over_cfra :
- scene->r.cfra + scene->ed->over_ofs;
+ int overlap_frame = (scene->ed->overlay_frame_flag & SEQ_EDIT_OVERLAY_FRAME_ABS) ?
+ scene->ed->overlay_frame_abs :
+ scene->r.cfra + scene->ed->overlay_frame_ofs;
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
@@ -3245,9 +2713,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
}
UI_view2d_view_ortho(v2d);
- /* Get timeline bound-box, needed for the scroll-bars. */
- SEQ_timeline_boundbox(scene, SEQ_active_seqbase_get(ed), &v2d->tot);
- draw_seq_backdrop(v2d);
+ draw_seq_timeline_channels(v2d);
if ((sseq->flag & SEQ_SHOW_OVERLAY) && (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_GRID)) {
U.v2d_min_gridsize *= 3;
UI_view2d_draw_lines_x__discrete_frames_or_seconds(
@@ -3293,6 +2759,10 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
UI_view2d_view_ortho(v2d);
ANIM_draw_previewrange(C, v2d, 1);
+ if ((sseq->gizmo_flag & SEQ_GIZMO_HIDE) == 0) {
+ WM_gizmomap_draw(region->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D);
+ }
+
/* Draw registered callbacks. */
GPU_framebuffer_bind(framebuffer_overlay);
ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW);
@@ -3301,13 +2771,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
UI_view2d_view_restore(C);
ED_time_scrub_draw(region, scene, !(sseq->flag & SEQ_DRAWFRAMES), true);
- /* Draw channel numbers. */
- {
- rcti rect;
- BLI_rcti_init(
- &rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y);
- UI_view2d_draw_scale_y__block(region, v2d, &rect, TH_SCROLL_TEXT);
- }
+ draw_seq_timeline_channel_numbers(region);
}
void draw_timeline_seq_display(const bContext *C, ARegion *region)
@@ -3319,12 +2783,15 @@ void draw_timeline_seq_display(const bContext *C, ARegion *region)
if (scene->ed != NULL) {
UI_view2d_view_ortho(v2d);
draw_cache_view(C);
- if (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) {
+ if (scene->ed->overlay_frame_flag & SEQ_EDIT_OVERLAY_FRAME_SHOW) {
draw_overlap_frame_indicator(scene, v2d);
}
UI_view2d_view_restore(C);
}
ED_time_scrub_draw_current_frame(region, scene, !(sseq->flag & SEQ_DRAWFRAMES));
+
+ const ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SEQ_timeline_boundbox(scene, seqbase, &v2d->tot);
UI_view2d_scrollers_draw(v2d, NULL);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 6daa8d690e5..3b5e16d84a9 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -39,6 +39,7 @@
#include "DNA_sound_types.h"
#include "BKE_context.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -46,6 +47,7 @@
#include "BKE_sound.h"
#include "SEQ_add.h"
+#include "SEQ_animation.h"
#include "SEQ_clipboard.h"
#include "SEQ_edit.h"
#include "SEQ_effects.h"
@@ -66,6 +68,7 @@
#include "RNA_enum_types.h"
/* For menu, popup, icons, etc. */
+#include "ED_keyframing.h"
#include "ED_numinput.h"
#include "ED_outliner.h"
#include "ED_screen.h"
@@ -127,17 +130,15 @@ bool ED_space_sequencer_maskedit_poll(bContext *C)
return false;
}
-/* Are we displaying the seq output (not channels or histogram). */
bool ED_space_sequencer_check_show_imbuf(SpaceSeq *sseq)
{
- return (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW) &&
- ELEM(sseq->mainb, SEQ_DRAW_SEQUENCE, SEQ_DRAW_IMG_IMBUF));
+ return (sseq->mainb == SEQ_DRAW_IMG_IMBUF) &&
+ (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW));
}
bool ED_space_sequencer_check_show_strip(SpaceSeq *sseq)
{
- return (ELEM(sseq->view, SEQ_VIEW_SEQUENCE, SEQ_VIEW_SEQUENCE_PREVIEW) &&
- ELEM(sseq->mainb, SEQ_DRAW_SEQUENCE, SEQ_DRAW_IMG_IMBUF));
+ return ELEM(sseq->view, SEQ_VIEW_SEQUENCE, SEQ_VIEW_SEQUENCE_PREVIEW);
}
static bool sequencer_fcurves_targets_color_strip(const FCurve *fcurve)
@@ -153,12 +154,6 @@ static bool sequencer_fcurves_targets_color_strip(const FCurve *fcurve)
return true;
}
-/*
- * Check if there is animation shown during playback.
- *
- * - Colors of color strips are displayed on the strip itself.
- * - Backdrop is drawn.
- */
bool ED_space_sequencer_has_playback_animation(const struct SpaceSeq *sseq,
const struct Scene *scene)
{
@@ -188,7 +183,6 @@ bool ED_space_sequencer_has_playback_animation(const struct SpaceSeq *sseq,
/** \name Shared Poll Functions
* \{ */
-/* Operator functions. */
bool sequencer_edit_poll(bContext *C)
{
return (SEQ_editing_get(CTX_data_scene(C)) != NULL);
@@ -211,25 +205,61 @@ bool sequencer_strip_has_path_poll(bContext *C)
(SEQ_HAS_PATH(seq)));
}
-bool sequencer_view_preview_poll(bContext *C)
+bool sequencer_view_has_preview_poll(bContext *C)
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
- Editing *ed = SEQ_editing_get(CTX_data_scene(C));
- if (ed && sseq && (sseq->mainb == SEQ_DRAW_IMG_IMBUF)) {
- return 1;
+ if (sseq == NULL) {
+ return false;
+ }
+ if (SEQ_editing_get(CTX_data_scene(C)) == NULL) {
+ return false;
+ }
+ if (!(ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW) &&
+ (sseq->mainb == SEQ_DRAW_IMG_IMBUF))) {
+ return false;
+ }
+ ARegion *region = CTX_wm_region(C);
+ if (!(region && region->regiontype == RGN_TYPE_PREVIEW)) {
+ return false;
}
- return 0;
+ return true;
}
-bool sequencer_view_strips_poll(bContext *C)
+bool sequencer_view_preview_only_poll(const bContext *C)
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
- if (sseq && ED_space_sequencer_check_show_strip(sseq)) {
- return 1;
+ if (sseq == NULL) {
+ return false;
+ }
+ if (SEQ_editing_get(CTX_data_scene(C)) == NULL) {
+ return false;
+ }
+ if (!(ELEM(sseq->view, SEQ_VIEW_PREVIEW) && (sseq->mainb == SEQ_DRAW_IMG_IMBUF))) {
+ return false;
+ }
+ ARegion *region = CTX_wm_region(C);
+ if (!(region && region->regiontype == RGN_TYPE_PREVIEW)) {
+ return false;
}
- return 0;
+ return true;
+}
+
+bool sequencer_view_strips_poll(bContext *C)
+{
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ if (sseq == NULL) {
+ return false;
+ }
+ if (!ED_space_sequencer_check_show_strip(sseq)) {
+ return false;
+ }
+ ARegion *region = CTX_wm_region(C);
+ if (!(region && region->regiontype == RGN_TYPE_WINDOW)) {
+ return false;
+ }
+ return true;
}
/** \} */
@@ -329,6 +359,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_active_seqbase_get(ed);
Sequence *seq;
int snap_frame;
@@ -352,7 +383,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
SEQ_transform_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL);
SEQ_transform_fix_single_image_seq_offsets(seq);
}
- SEQ_time_update_sequence(scene, seq);
+ SEQ_time_update_sequence(scene, seqbase, seq);
}
}
@@ -375,19 +406,19 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
if (!either_handle_selected) {
SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp));
}
- SEQ_time_update_sequence(scene, seq);
+ SEQ_time_update_sequence(scene, seqbase, seq);
}
else if (seq->seq2 && (seq->seq2->flag & SELECT)) {
if (!either_handle_selected) {
SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp));
}
- SEQ_time_update_sequence(scene, seq);
+ SEQ_time_update_sequence(scene, seqbase, seq);
}
else if (seq->seq3 && (seq->seq3->flag & SELECT)) {
if (!either_handle_selected) {
SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp));
}
- SEQ_time_update_sequence(scene, seq);
+ SEQ_time_update_sequence(scene, seqbase, seq);
}
}
}
@@ -629,7 +660,8 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
* we can skip calculating for effects.
* This way we can avoid an extra loop just for effects. */
if (!(seq->type & SEQ_TYPE_EFFECT)) {
- SEQ_time_update_sequence(scene, seq);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SEQ_time_update_sequence(scene, seqbase, seq);
}
}
if (changed) {
@@ -801,8 +833,6 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
case EVT_ESCKEY:
case RIGHTMOUSE: {
- Editing *ed = SEQ_editing_get(scene);
-
for (int i = 0; i < data->num_seq; i++) {
transseq_restore(data->ts + i, data->seq_array[i]);
}
@@ -810,7 +840,8 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
for (int i = 0; i < data->num_seq; i++) {
Sequence *seq = data->seq_array[i];
SEQ_add_reload_new_file(bmain, scene, seq, false);
- SEQ_time_update_sequence(scene, seq);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SEQ_time_update_sequence(scene, seqbase, seq);
}
MEM_freeN(data->seq_array);
@@ -821,8 +852,6 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
- SEQ_relations_free_imbuf(scene, &ed->seqbase, false);
-
if (area) {
ED_area_status_text(area, NULL);
}
@@ -870,9 +899,9 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
void SEQUENCER_OT_slip(struct wmOperatorType *ot)
{
/* Identifiers. */
- ot->name = "Trim Strips";
+ ot->name = "Slip Strips";
ot->idname = "SEQUENCER_OT_slip";
- ot->description = "Trim the contents of the active strip";
+ ot->description = "Slip the contents of selected strips";
/* Api callbacks. */
ot->invoke = sequencer_slip_invoke;
@@ -1098,7 +1127,6 @@ static int sequencer_reload_exec(bContext *C, wmOperator *op)
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT) {
- SEQ_relations_update_changed_seq_and_deps(scene, seq, 0, 1);
SEQ_add_reload_new_file(bmain, scene, seq, !adjust_length);
if (adjust_length) {
@@ -1308,7 +1336,9 @@ static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op)
last_seq->seq3 = seq3;
int old_start = last_seq->start;
- SEQ_relations_update_changed_seq_and_deps(scene, last_seq, 1, 1);
+ SEQ_time_update_recursive(scene, last_seq);
+
+ SEQ_relations_invalidate_cache_preprocessed(scene, last_seq);
SEQ_offset_animdata(scene, last_seq, (last_seq->start - old_start));
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -1366,7 +1396,7 @@ static int sequencer_swap_inputs_exec(bContext *C, wmOperator *op)
last_seq->seq1 = last_seq->seq2;
last_seq->seq2 = seq;
- SEQ_relations_update_changed_seq_and_deps(scene, last_seq, 1, 1);
+ SEQ_relations_invalidate_cache_preprocessed(scene, last_seq);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -1531,7 +1561,7 @@ static int sequencer_split_invoke(bContext *C, wmOperator *op, const wmEvent *ev
}
RNA_int_set(op->ptr, "channel", mouseloc[1]);
RNA_enum_set(op->ptr, "side", split_side);
- /*RNA_enum_set(op->ptr, "type", split_hard); */
+ // RNA_enum_set(op->ptr, "type", split_hard);
return sequencer_split_exec(C, op);
}
@@ -1628,6 +1658,35 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot)
/** \name Duplicate Strips Operator
* \{ */
+static void sequencer_backup_original_animation(Scene *scene, ListBase *list)
+{
+ if (scene->adt == NULL || scene->adt->action == NULL ||
+ BLI_listbase_is_empty(&scene->adt->action->curves)) {
+ return;
+ }
+
+ BLI_movelisttolist(list, &scene->adt->action->curves);
+}
+
+static void sequencer_restore_original_animation(Scene *scene, ListBase *list)
+{
+ if (scene->adt == NULL || scene->adt->action == NULL || BLI_listbase_is_empty(list)) {
+ return;
+ }
+
+ BLI_movelisttolist(&scene->adt->action->curves, list);
+}
+
+static void sequencer_duplicate_animation(Scene *scene, Sequence *seq, ListBase *curves_backup)
+{
+ GSet *fcurves = SEQ_fcurves_by_strip_get(seq, curves_backup);
+ GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) {
+ FCurve *fcu_cpy = BKE_fcurve_copy(fcu);
+ BLI_addtail(&scene->adt->action->curves, fcu_cpy);
+ }
+ GSET_FOREACH_END();
+}
+
static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -1638,32 +1697,44 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
}
Sequence *active_seq = SEQ_select_active_get(scene);
- ListBase duplicated = {NULL, NULL};
+ ListBase duplicated_strips = {NULL, NULL};
- SEQ_sequence_base_dupli_recursive(scene, scene, &duplicated, ed->seqbasep, 0, 0);
+ SEQ_sequence_base_dupli_recursive(scene, scene, &duplicated_strips, ed->seqbasep, 0, 0);
ED_sequencer_deselect_all(scene);
- if (duplicated.first) {
- Sequence *seq = duplicated.first;
- /* Rely on the nseqbase list being added at the end.
- * Their UUIDs has been re-generated by the SEQ_sequence_base_dupli_recursive(), */
- BLI_movelisttolist(ed->seqbasep, &duplicated);
-
- /* Handle duplicated strips: set active, select, ensure unique name and duplicate animation
- * data. */
- for (; seq; seq = seq->next) {
- if (active_seq != NULL && STREQ(seq->name, active_seq->name)) {
- SEQ_select_active_set(scene, seq);
- }
- seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK);
- SEQ_ensure_unique_name(seq, scene);
- }
+ if (duplicated_strips.first == NULL) {
+ return OPERATOR_CANCELLED;
+ }
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
- return OPERATOR_FINISHED;
+ /* Duplicate animation.
+ * First backup original curves from scene and duplicate strip curves from backup into scene.
+ * This way, when pasted strips are renamed, curves are renamed with them. Finally, restore
+ * original curves from backup.
+ */
+ ListBase fcurves_original_backup = {NULL, NULL};
+ sequencer_backup_original_animation(scene, &fcurves_original_backup);
+
+ Sequence *seq = duplicated_strips.first;
+
+ /* Rely on the nseqbase list being added at the end.
+ * Their UUIDs has been re-generated by the SEQ_sequence_base_dupli_recursive(), */
+ BLI_movelisttolist(ed->seqbasep, &duplicated_strips);
+
+ /* Handle duplicated strips: set active, select, ensure unique name and duplicate animation
+ * data. */
+ for (; seq; seq = seq->next) {
+ if (active_seq != NULL && STREQ(seq->name, active_seq->name)) {
+ SEQ_select_active_set(scene, seq);
+ }
+ seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK);
+ sequencer_duplicate_animation(scene, seq, &fcurves_original_backup);
+ SEQ_ensure_unique_name(seq, scene);
}
- return OPERATOR_CANCELLED;
+ sequencer_restore_original_animation(scene, &fcurves_original_backup);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ return OPERATOR_FINISHED;
}
void SEQUENCER_OT_duplicate(wmOperatorType *ot)
@@ -1691,16 +1762,23 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbasep = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+
+ if (sequencer_view_has_preview_poll(C) && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
SEQ_prefetch_stop(scene);
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
- if (seq->flag & SELECT) {
- SEQ_edit_flag_for_removal(scene, ed->seqbasep, seq);
- }
+ SeqCollection *selected_strips = selected_strips_from_context(C);
+ Sequence *seq;
+
+ SEQ_ITERATOR_FOREACH (seq, selected_strips) {
+ SEQ_edit_flag_for_removal(scene, seqbasep, seq);
}
- SEQ_edit_remove_flagged_sequences(scene, ed->seqbasep);
+ SEQ_edit_remove_flagged_sequences(scene, seqbasep);
+
+ SEQ_collection_free(selected_strips);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
DEG_relations_tag_update(bmain);
@@ -1763,7 +1841,9 @@ static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op))
/* Update lengths, etc. */
seq = ed->seqbasep->first;
while (seq) {
- SEQ_time_update_sequence(scene, seq);
+ ListBase *seqbase = SEQ_active_seqbase_get(ed);
+ SEQ_time_update_sequence(scene, seqbase, seq);
+ SEQ_relations_invalidate_cache_preprocessed(scene, seq);
seq = seq->next;
}
@@ -1806,6 +1886,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_active_seqbase_get(ed);
Sequence *seq, *seq_new;
Strip *strip_new;
@@ -1813,7 +1894,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
int start_ofs, timeline_frame, frame_end;
int step = RNA_int_get(op->ptr, "length");
- seq = ed->seqbasep->first; /* Poll checks this is valid. */
+ seq = seqbase->first; /* Poll checks this is valid. */
SEQ_prefetch_stop(scene);
@@ -1823,7 +1904,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
/* Remove seq so overlap tests don't conflict,
* see seq_free_sequence below for the real freeing. */
- BLI_remlink(ed->seqbasep, seq);
+ BLI_remlink(seqbase, seq);
/* TODO: remove f-curve and assign to split image strips.
* The old animation system would remove the user of `seq->ipo`. */
@@ -1834,8 +1915,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
/* New seq. */
se = SEQ_render_give_stripelem(seq, timeline_frame);
- seq_new = SEQ_sequence_dupli_recursive(
- scene, scene, ed->seqbasep, seq, SEQ_DUPE_UNIQUE_NAME);
+ seq_new = SEQ_sequence_dupli_recursive(scene, scene, seqbase, seq, SEQ_DUPE_UNIQUE_NAME);
seq_new->start = start_ofs;
seq_new->type = SEQ_TYPE_IMAGE;
@@ -1853,12 +1933,12 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
BLI_strncpy(se_new->name, se->name, sizeof(se_new->name));
strip_new->stripdata = se_new;
- SEQ_time_update_sequence(scene, seq_new);
+ SEQ_time_update_sequence(scene, seqbase, seq_new);
if (step > 1) {
seq_new->flag &= ~SEQ_OVERLAP;
- if (SEQ_transform_test_overlap(ed->seqbasep, seq_new)) {
- SEQ_transform_seqbase_shuffle(ed->seqbasep, seq_new, scene);
+ if (SEQ_transform_test_overlap(seqbase, seq_new)) {
+ SEQ_transform_seqbase_shuffle(seqbase, seq_new, scene);
}
}
@@ -1869,7 +1949,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
}
seq_next = seq->next;
- SEQ_sequence_free(scene, seq, true);
+ SEQ_edit_flag_for_removal(scene, seqbase, seq);
seq = seq_next;
}
else {
@@ -1877,7 +1957,9 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
}
}
- SEQ_sort(SEQ_active_seqbase_get(ed));
+ SEQ_edit_remove_flagged_sequences(scene, seqbase);
+
+ SEQ_sort(seqbase);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -1914,6 +1996,8 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
Editing *ed = SEQ_editing_get(scene);
Sequence *active_seq = SEQ_select_active_get(scene);
+ SEQ_prefetch_stop(scene);
+
if (active_seq && active_seq->type == SEQ_TYPE_META && active_seq->flag & SELECT) {
/* Enter meta-strip. */
SEQ_meta_stack_alloc(ed, active_seq);
@@ -1994,7 +2078,7 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
SEQ_sequence_base_unique_name_recursive(scene, &ed->seqbase, seqm);
seqm->start = meta_start_frame;
seqm->len = meta_end_frame - meta_start_frame;
- SEQ_time_update_sequence(scene, seqm);
+ SEQ_time_update_sequence(scene, active_seqbase, seqm);
SEQ_select_active_set(scene, seqm);
if (SEQ_transform_test_overlap(active_seqbase, seqm)) {
SEQ_transform_seqbase_shuffle(active_seqbase, seqm, scene);
@@ -2129,6 +2213,7 @@ static int sequencer_strip_jump_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
return OPERATOR_FINISHED;
@@ -2167,17 +2252,20 @@ static const EnumPropertyItem prop_side_lr_types[] = {
static void swap_sequence(Scene *scene, Sequence *seqa, Sequence *seqb)
{
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
int gap = seqb->startdisp - seqa->enddisp;
int seq_a_start;
int seq_b_start;
seq_b_start = (seqb->start - seqb->startdisp) + seqa->startdisp;
SEQ_transform_translate_sequence(scene, seqb, seq_b_start - seqb->start);
- SEQ_time_update_sequence(scene, seqb);
+ SEQ_time_update_sequence(scene, seqbase, seqb);
+ SEQ_relations_invalidate_cache_preprocessed(scene, seqb);
seq_a_start = (seqa->start - seqa->startdisp) + seqb->enddisp + gap;
SEQ_transform_translate_sequence(scene, seqa, seq_a_start - seqa->start);
- SEQ_time_update_sequence(scene, seqa);
+ SEQ_time_update_sequence(scene, seqbase, seqa);
+ SEQ_relations_invalidate_cache_preprocessed(scene, seqa);
}
static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, int sel)
@@ -2236,6 +2324,7 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
Sequence *active_seq = SEQ_select_active_get(scene);
+ ListBase *seqbase = SEQ_active_seqbase_get(ed);
Sequence *seq, *iseq;
int side = RNA_enum_get(op->ptr, "side");
@@ -2267,20 +2356,20 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
}
/* XXX: Should be a generic function. */
- for (iseq = scene->ed->seqbasep->first; iseq; iseq = iseq->next) {
+ for (iseq = seqbase->first; iseq; iseq = iseq->next) {
if ((iseq->type & SEQ_TYPE_EFFECT) &&
(seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) {
- SEQ_time_update_sequence(scene, iseq);
+ SEQ_time_update_sequence(scene, seqbase, iseq);
}
}
/* Do this in a new loop since both effects need to be calculated first. */
- for (iseq = scene->ed->seqbasep->first; iseq; iseq = iseq->next) {
+ for (iseq = seqbase->first; iseq; iseq = iseq->next) {
if ((iseq->type & SEQ_TYPE_EFFECT) &&
(seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) {
/* This may now overlap. */
- if (SEQ_transform_test_overlap(ed->seqbasep, iseq)) {
- SEQ_transform_seqbase_shuffle(ed->seqbasep, iseq, scene);
+ if (SEQ_transform_test_overlap(seqbase, iseq)) {
+ SEQ_transform_seqbase_shuffle(seqbase, iseq, scene);
}
}
}
@@ -2398,6 +2487,22 @@ static void seq_copy_del_sound(Scene *scene, Sequence *seq)
}
}
+static void sequencer_copy_animation(Scene *scene, Sequence *seq)
+{
+ if (scene->adt == NULL || scene->adt->action == NULL ||
+ BLI_listbase_is_empty(&scene->adt->action->curves)) {
+ return;
+ }
+
+ GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves);
+
+ GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) {
+ BLI_addtail(&fcurves_clipboard, BKE_fcurve_copy(fcu));
+ }
+ GSET_FOREACH_END();
+ BLI_gset_free(fcurves, NULL);
+}
+
static int sequencer_copy_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -2424,8 +2529,10 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
seqbase_clipboard_frame = scene->r.cfra;
SEQ_clipboard_active_seq_name_store(scene);
- /* Remove anything that references the current scene. */
LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) {
+ /* Copy curves. */
+ sequencer_copy_animation(scene, seq);
+ /* Remove anything that references the current scene. */
seq_copy_del_sound(scene, seq);
}
@@ -2470,6 +2577,29 @@ void ED_sequencer_deselect_all(Scene *scene)
}
}
+static void sequencer_paste_animation(bContext *C)
+{
+ if (BLI_listbase_is_empty(&fcurves_clipboard)) {
+ return;
+ }
+
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ bAction *act;
+
+ if (scene->adt != NULL && scene->adt->action != NULL) {
+ act = scene->adt->action;
+ }
+ else {
+ /* get action to add F-Curve+keyframe to */
+ act = ED_id_action_ensure(bmain, &scene->id);
+ }
+
+ LISTBASE_FOREACH (FCurve *, fcu, &fcurves_clipboard) {
+ BLI_addtail(&act->curves, BKE_fcurve_copy(fcu));
+ }
+}
+
static int sequencer_paste_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -2499,6 +2629,17 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
ofs = scene->r.cfra - min_seq_startdisp;
}
+ /* Paste animation.
+ * Note: Only fcurves are copied. Drivers and NLA action strips are not copied.
+ * First backup original curves from scene and move curves from clipboard into scene. This way,
+ * when pasted strips are renamed, pasted fcurves are renamed with them. Finally restore original
+ * curves from backup.
+ */
+
+ ListBase fcurves_original_backup = {NULL, NULL};
+ sequencer_backup_original_animation(scene, &fcurves_original_backup);
+ sequencer_paste_animation(C);
+
/* Copy strips, temporarily restoring pointers to actual data-blocks. This
* must happen on the clipboard itself, so that copying does user counting
* on the actual data-blocks. */
@@ -2528,6 +2669,8 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
}
}
+ sequencer_restore_original_animation(scene, &fcurves_original_backup);
+
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);
@@ -2594,8 +2737,9 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
seq_act->scene_sound = NULL;
seq_other->scene_sound = NULL;
- SEQ_time_update_sequence(scene, seq_act);
- SEQ_time_update_sequence(scene, seq_other);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SEQ_time_update_sequence(scene, seqbase, seq_act);
+ SEQ_time_update_sequence(scene, seqbase, seq_other);
if (seq_act->sound) {
BKE_sound_add_scene_sound_defaults(scene, seq_act);
@@ -2643,7 +2787,6 @@ static const EnumPropertyItem prop_change_effect_input_types[] = {
static int sequencer_change_effect_input_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
Sequence *seq = SEQ_select_active_get(scene);
Sequence **seq_1, **seq_2;
@@ -2670,10 +2813,7 @@ static int sequencer_change_effect_input_exec(bContext *C, wmOperator *op)
SWAP(Sequence *, *seq_1, *seq_2);
- SEQ_relations_update_changed_seq_and_deps(scene, seq, 0, 1);
-
- /* Invalidate cache. */
- SEQ_relations_free_imbuf(scene, &ed->seqbase, false);
+ SEQ_relations_invalidate_cache_preprocessed(scene, seq);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -2727,7 +2867,6 @@ EnumPropertyItem sequencer_prop_effect_types[] = {
static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
Sequence *seq = SEQ_select_active_get(scene);
const int new_type = RNA_enum_get(op->ptr, "type");
@@ -2753,10 +2892,7 @@ static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op)
sh = SEQ_effect_handle_get(seq);
sh.init(seq);
- SEQ_relations_update_changed_seq_and_deps(scene, seq, 0, 1);
- /* Invalidate cache. */
- SEQ_relations_free_imbuf(scene, &ed->seqbase, false);
-
+ SEQ_relations_invalidate_cache_preprocessed(scene, seq);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -2793,7 +2929,6 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
Sequence *seq = SEQ_select_active_get(scene);
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
@@ -2849,10 +2984,8 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
* Important not to set seq->len = len; allow the function to handle it. */
SEQ_add_reload_new_file(bmain, scene, seq, true);
- SEQ_time_update_sequence(scene, seq);
-
- /* Invalidate cache. */
- SEQ_relations_free_imbuf(scene, &ed->seqbase, false);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SEQ_time_update_sequence(scene, seqbase, seq);
}
else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
bSound *sound = seq->sound;
@@ -2876,8 +3009,10 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
prop = RNA_struct_find_property(&seq_ptr, "filepath");
RNA_property_string_set(&seq_ptr, prop, filepath);
RNA_property_update(C, &seq_ptr, prop);
+ SEQ_relations_sequence_free_anim(seq);
}
+ SEQ_relations_invalidate_cache_raw(scene, seq);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -3339,6 +3474,22 @@ static int sequencer_strip_color_tag_set_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static bool sequencer_strip_color_tag_set_poll(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ if (scene == NULL) {
+ return false;
+ }
+
+ Editing *ed = SEQ_editing_get(scene);
+ if (ed == NULL) {
+ return false;
+ }
+
+ Sequence *act_seq = ed->act_seq;
+ return act_seq != NULL;
+}
+
void SEQUENCER_OT_strip_color_tag_set(struct wmOperatorType *ot)
{
/* Identifiers. */
@@ -3348,7 +3499,7 @@ void SEQUENCER_OT_strip_color_tag_set(struct wmOperatorType *ot)
/* Api callbacks. */
ot->exec = sequencer_strip_color_tag_set_exec;
- ot->poll = sequencer_edit_poll;
+ ot->poll = sequencer_strip_color_tag_set_poll;
/* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -3358,3 +3509,64 @@ void SEQUENCER_OT_strip_color_tag_set(struct wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set 2D Cursor Operator
+ * \{ */
+
+static int sequencer_set_2d_cursor_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+
+ float cursor_pixel[2];
+ RNA_float_get_array(op->ptr, "location", cursor_pixel);
+
+ SEQ_image_preview_unit_from_px(scene, cursor_pixel, sseq->cursor);
+
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static int sequencer_set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *region = CTX_wm_region(C);
+ float cursor_pixel[2];
+ UI_view2d_region_to_view(
+ &region->v2d, event->mval[0], event->mval[1], &cursor_pixel[0], &cursor_pixel[1]);
+
+ RNA_float_set_array(op->ptr, "location", cursor_pixel);
+
+ return sequencer_set_2d_cursor_exec(C, op);
+}
+
+void SEQUENCER_OT_cursor_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set 2D Cursor";
+ ot->description = "Set 2D cursor location";
+ ot->idname = "SEQUENCER_OT_cursor_set";
+
+ /* api callbacks */
+ ot->exec = sequencer_set_2d_cursor_exec;
+ ot->invoke = sequencer_set_2d_cursor_invoke;
+ ot->poll = sequencer_view_has_preview_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_float_vector(ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Cursor location in normalized preview coordinates",
+ -10.0f,
+ 10.0f);
+}
+
+/** \} */
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 202eda85dca..7143a1fa1ca 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -33,13 +33,17 @@ struct ARegionType;
struct Depsgraph;
struct Main;
struct Scene;
+struct SeqCollection;
struct Sequence;
struct SpaceSeq;
struct StripElem;
+struct View2D;
struct bContext;
struct rctf;
struct wmOperator;
+#define OVERLAP_ALPHA 180
+
/* sequencer_draw.c */
void draw_timeline_seq(const struct bContext *C, struct ARegion *region);
void draw_timeline_seq_display(const struct bContext *C, struct ARegion *region);
@@ -53,15 +57,23 @@ void sequencer_draw_preview(const struct bContext *C,
bool draw_backdrop);
void color3ubv_from_seq(const struct Scene *curscene,
const struct Sequence *seq,
- const bool show_strip_color_tag,
+ bool show_strip_color_tag,
uchar r_col[3]);
void sequencer_special_update_set(Sequence *seq);
-float sequence_handle_size_get_clamped(struct Sequence *seq, const float pixelx);
+/* Get handle width in 2d-View space. */
+float sequence_handle_size_get_clamped(struct Sequence *seq, float pixelx);
/* UNUSED */
/* void seq_reset_imageofs(struct SpaceSeq *sseq); */
+/**
+ * Rendering using opengl will change the current viewport/context.
+ * This is why we need the \a region, to set back the render area.
+ *
+ * TODO: do not rely on such hack and just update the \a ibuf outside of
+ * the UI drawing code.
+ */
struct ImBuf *sequencer_ibuf_get(struct Main *bmain,
struct ARegion *region,
struct Depsgraph *depsgraph,
@@ -70,7 +82,17 @@ struct ImBuf *sequencer_ibuf_get(struct Main *bmain,
int timeline_frame,
int frame_ofs,
const char *viewname);
+
+/* sequencer_thumbnails.c */
void last_displayed_thumbnails_list_free(void *val);
+void draw_seq_strip_thumbnail(struct View2D *v2d,
+ const struct bContext *C,
+ struct Scene *scene,
+ struct Sequence *seq,
+ float y1,
+ float y2,
+ float pixelx,
+ float pixely);
/* sequencer_edit.c */
struct View2D;
@@ -97,9 +119,29 @@ bool sequencer_edit_poll(struct bContext *C);
/* UNUSED */
/* bool sequencer_strip_poll(struct bContext *C); */
bool sequencer_strip_has_path_poll(struct bContext *C);
-bool sequencer_view_preview_poll(struct bContext *C);
+bool sequencer_view_has_preview_poll(struct bContext *C);
+bool sequencer_view_preview_only_poll(const struct bContext *C);
bool sequencer_view_strips_poll(struct bContext *C);
+/**
+ * Returns collection with all strips presented to user. If operation is done in preview,
+ * collection is limited to all presented strips that can produce image output.
+ *
+ * \param C: context
+ * \return collection of strips (`Sequence`)
+ */
+struct SeqCollection *all_strips_from_context(struct bContext *C);
+
+/**
+ * Returns collection with selected strips presented to user. If operation is done in preview,
+ * collection is limited to selected presented strips, that can produce image output at current
+ * frame.
+ *
+ * \param C: context
+ * \return collection of strips (`Sequence`)
+ */
+struct SeqCollection *selected_strips_from_context(struct bContext *C);
+
/* Externs. */
extern EnumPropertyItem sequencer_prop_effect_types[];
extern EnumPropertyItem prop_side_types[];
@@ -152,6 +194,7 @@ void SEQUENCER_OT_strip_transform_clear(struct wmOperatorType *ot);
void SEQUENCER_OT_strip_transform_fit(struct wmOperatorType *ot);
void SEQUENCER_OT_strip_color_tag_set(struct wmOperatorType *ot);
+void SEQUENCER_OT_cursor_set(struct wmOperatorType *ot);
/* sequencer_select.c */
void SEQUENCER_OT_select_all(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index 95f7b44264c..2c5f211b0e4 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -80,6 +80,7 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_strip_transform_fit);
WM_operatortype_append(SEQUENCER_OT_strip_color_tag_set);
+ WM_operatortype_append(SEQUENCER_OT_cursor_set);
/* sequencer_select.c */
WM_operatortype_append(SEQUENCER_OT_select_all);
diff --git a/source/blender/editors/space_sequencer/sequencer_proxy.c b/source/blender/editors/space_sequencer/sequencer_proxy.c
index 0a8eb7cb88f..fb561025da2 100644
--- a/source/blender/editors/space_sequencer/sequencer_proxy.c
+++ b/source/blender/editors/space_sequencer/sequencer_proxy.c
@@ -85,7 +85,7 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports)
}
bool success = SEQ_proxy_rebuild_context(
- pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
+ pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue, false);
if (!success && (seq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) != 0) {
BKE_reportf(reports, RPT_WARNING, "Overwrite is not checked for %s, skipping", seq->name);
@@ -137,7 +137,7 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
short stop = 0, do_update;
float progress;
- SEQ_proxy_rebuild_context(bmain, depsgraph, scene, seq, file_list, &queue);
+ SEQ_proxy_rebuild_context(bmain, depsgraph, scene, seq, file_list, &queue, false);
for (link = queue.first; link; link = link->next) {
struct SeqIndexBuildContext *context = link->data;
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index aa6599a7c53..47696ab9256 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -25,6 +25,8 @@
#include <stdlib.h>
#include <string.h>
+#include "MEM_guardedalloc.h"
+
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -62,6 +64,34 @@
/** \name Selection Utilities
* \{ */
+SeqCollection *all_strips_from_context(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+
+ const bool is_preview = sequencer_view_has_preview_poll(C);
+ if (is_preview) {
+ return SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ }
+
+ return SEQ_query_all_strips(seqbase);
+}
+
+SeqCollection *selected_strips_from_context(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+
+ const bool is_preview = sequencer_view_has_preview_poll(C);
+ if (is_preview) {
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ SEQ_filter_selected_strips(strips);
+ return strips;
+ }
+
+ return SEQ_query_selected_strips(seqbase);
+}
+
static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRING BACK */
{
Sequence *neighbor;
@@ -409,14 +439,18 @@ static void sequencer_select_do_updates(bContext *C, Scene *scene)
static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
{
int action = RNA_enum_get(op->ptr, "action");
-
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
+
+ if (sequencer_view_has_preview_poll(C) && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SeqCollection *strips = all_strips_from_context(C);
Sequence *seq;
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (seq->flag & SEQ_ALLSEL) {
action = SEL_DESELECT;
break;
@@ -424,7 +458,7 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
}
}
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
switch (action) {
case SEL_SELECT:
seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
@@ -445,8 +479,9 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
}
}
- ED_outliner_select_sync_from_sequence_tag(C);
+ SEQ_collection_free(strips);
+ ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -478,10 +513,15 @@ void SEQUENCER_OT_select_all(struct wmOperatorType *ot)
static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
+
+ if (sequencer_view_has_preview_poll(C) && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SeqCollection *strips = all_strips_from_context(C);
Sequence *seq;
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (seq->flag & SELECT) {
seq->flag &= ~SEQ_ALLSEL;
}
@@ -491,8 +531,9 @@ static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ED_outliner_select_sync_from_sequence_tag(C);
+ SEQ_collection_free(strips);
+ ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -635,9 +676,51 @@ static void sequencer_select_linked_handle(const bContext *C,
}
}
-/* Check if click happened on image which belongs to strip. If multiple strips are found, loop
- * through them in order. */
-static Sequence *seq_select_seq_from_preview(const bContext *C, const int mval[2])
+/** Collect sequencer that are candidates for being selected. */
+struct SeqSelect_Link {
+ struct SeqSelect_Link *next, *prev;
+ Sequence *seq;
+ /** Only use for center selection. */
+ float center_dist_sq;
+};
+
+static int seq_sort_for_depth_select(const void *a, const void *b)
+{
+ const struct SeqSelect_Link *slink_a = a;
+ const struct SeqSelect_Link *slink_b = b;
+
+ /* Exactly overlapping strips, sort by machine (so the top-most is first). */
+ if (slink_a->seq->machine < slink_b->seq->machine) {
+ return 1;
+ }
+ if (slink_a->seq->machine > slink_b->seq->machine) {
+ return -1;
+ }
+ return 0;
+}
+
+static int seq_sort_for_center_select(const void *a, const void *b)
+{
+ const struct SeqSelect_Link *slink_a = a;
+ const struct SeqSelect_Link *slink_b = b;
+ if (slink_a->center_dist_sq > slink_b->center_dist_sq) {
+ return 1;
+ }
+ if (slink_a->center_dist_sq < slink_b->center_dist_sq) {
+ return -1;
+ }
+
+ /* Exactly overlapping strips, use depth. */
+ return seq_sort_for_depth_select(a, b);
+}
+
+/**
+ * Check if click happened on image which belongs to strip.
+ * If multiple strips are found, loop through them in order
+ * (depth (top-most first) or closest to mouse when `center` is true).
+ */
+static Sequence *seq_select_seq_from_preview(
+ const bContext *C, const int mval[2], const bool toggle, const bool extend, const bool center)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
@@ -648,28 +731,82 @@ static Sequence *seq_select_seq_from_preview(const bContext *C, const int mval[2
float mouseco_view[2];
UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouseco_view[0], &mouseco_view[1]);
+ /* Always update the coordinates (check extended after). */
+ const bool use_cycle = (!WM_cursor_test_motion_and_update(mval) || extend || toggle);
+
SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, sseq->chanshown);
+
+ /* Allow strips this far from the closest center to be included.
+ * This allows cycling over center points which are near enough
+ * to overlapping from the users perspective. */
+ const float center_dist_sq_max = square_f(75.0f * U.pixelsize);
+ const float center_scale_px[2] = {
+ UI_view2d_scale_get_x(v2d),
+ UI_view2d_scale_get_y(v2d),
+ };
+
+ struct SeqSelect_Link *slink_active = NULL;
+ Sequence *seq_active = SEQ_select_active_get(scene);
ListBase strips_ordered = {NULL};
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
- if (seq_point_image_isect(scene, seq, mouseco_view)) {
- BLI_remlink(seqbase, seq);
- BLI_addtail(&strips_ordered, seq);
+ bool isect = false;
+ float center_dist_sq_test = 0.0f;
+ if (center) {
+ /* Detect overlapping center points (scaled by the zoom level). */
+ float co[2];
+ SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, co);
+ sub_v2_v2(co, mouseco_view);
+ mul_v2_v2(co, center_scale_px);
+ center_dist_sq_test = len_squared_v2(co);
+ isect = center_dist_sq_test <= center_dist_sq_max;
+ if (isect) {
+ /* Use an active strip penalty for "center" selection when cycle is enabled. */
+ if (use_cycle && (seq == seq_active) && (seq_active->flag & SELECT)) {
+ center_dist_sq_test = square_f(sqrtf(center_dist_sq_test) + (3.0f * U.pixelsize));
+ }
+ }
+ }
+ else {
+ isect = seq_point_image_isect(scene, seq, mouseco_view);
+ }
+
+ if (isect) {
+ struct SeqSelect_Link *slink = MEM_callocN(sizeof(*slink), __func__);
+ slink->seq = seq;
+ slink->center_dist_sq = center_dist_sq_test;
+ BLI_addtail(&strips_ordered, slink);
+
+ if (seq == seq_active) {
+ slink_active = slink;
+ }
}
}
SEQ_collection_free(strips);
- SEQ_sort(&strips_ordered);
- Sequence *seq_active = SEQ_select_active_get(scene);
- Sequence *seq_select = strips_ordered.first;
- LISTBASE_FOREACH (Sequence *, seq_iter, &strips_ordered) {
- if (seq_iter == seq_active && seq_iter->next != NULL) {
- seq_select = seq_iter->next;
- break;
+ BLI_listbase_sort(&strips_ordered,
+ center ? seq_sort_for_center_select : seq_sort_for_depth_select);
+
+ struct SeqSelect_Link *slink_select = strips_ordered.first;
+ Sequence *seq_select = NULL;
+ if (slink_select != NULL) {
+ /* Only use special behavior for the active strip when it's selected. */
+ if ((center == false) && slink_active && (seq_active->flag & SELECT)) {
+ if (use_cycle) {
+ if (slink_active->next) {
+ slink_select = slink_active->next;
+ }
+ }
+ else {
+ /* Match object selection behavior: keep the current active item unless cycle is enabled.
+ * Clicking again in the same location will cycle away from the active object. */
+ slink_select = slink_active;
+ }
}
+ seq_select = slink_select->seq;
}
- BLI_movelisttolist(seqbase, &strips_ordered);
+ BLI_freelistN(&strips_ordered);
return seq_select;
}
@@ -686,14 +823,15 @@ static bool element_already_selected(const Sequence *seq, const int handle_click
static void sequencer_select_strip_impl(const Editing *ed,
Sequence *seq,
const int handle_clicked,
- const bool extend)
+ const bool extend,
+ const bool deselect,
+ const bool toggle)
{
- /* Deselect strip. */
- if (extend && (seq->flag & SELECT) && ed->act_seq == seq) {
+ const bool is_active = (ed->act_seq == seq);
+
+ /* Exception for active strip handles. */
+ if ((handle_clicked != SEQ_SIDE_NONE) && (seq->flag & SELECT) && is_active && toggle) {
switch (handle_clicked) {
- case SEQ_SIDE_NONE:
- seq->flag &= ~SEQ_ALLSEL;
- break;
case SEQ_SIDE_LEFT:
seq->flag ^= SEQ_LEFTSEL;
break;
@@ -701,8 +839,28 @@ static void sequencer_select_strip_impl(const Editing *ed,
seq->flag ^= SEQ_RIGHTSEL;
break;
}
+ return;
+ }
+
+ /* Select strip. */
+ /* Match object selection behavior. */
+ int action = -1;
+ if (extend) {
+ action = 1;
+ }
+ else if (deselect) {
+ action = 0;
+ }
+ else {
+ if (!((seq->flag & SELECT) && is_active)) {
+ action = 1;
+ }
+ else if (toggle) {
+ action = 0;
+ }
}
- else { /* Select strip. */
+
+ if (action == 1) {
seq->flag |= SELECT;
if (handle_clicked == SEQ_SIDE_LEFT) {
seq->flag |= SEQ_LEFTSEL;
@@ -711,6 +869,9 @@ static void sequencer_select_strip_impl(const Editing *ed,
seq->flag |= SEQ_RIGHTSEL;
}
}
+ else if (action == 0) {
+ seq->flag &= ~SEQ_ALLSEL;
+ }
}
static int sequencer_select_exec(bContext *C, wmOperator *op)
@@ -718,21 +879,36 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
View2D *v2d = UI_view2d_fromcontext(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
- const bool extend = RNA_boolean_get(op->ptr, "extend");
+ ARegion *region = CTX_wm_region(C);
if (ed == NULL) {
return OPERATOR_CANCELLED;
}
+ if (region->regiontype == RGN_TYPE_PREVIEW) {
+ if (!sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
+ const SpaceSeq *sseq = CTX_wm_space_seq(C);
+ if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+ bool deselect = RNA_boolean_get(op->ptr, "deselect");
+ bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+ bool toggle = RNA_boolean_get(op->ptr, "toggle");
+ bool center = RNA_boolean_get(op->ptr, "center");
+
int mval[2];
mval[0] = RNA_int_get(op->ptr, "mouse_x");
mval[1] = RNA_int_get(op->ptr, "mouse_y");
- ARegion *region = CTX_wm_region(C);
int handle_clicked = SEQ_SIDE_NONE;
Sequence *seq = NULL;
if (region->regiontype == RGN_TYPE_PREVIEW) {
- seq = seq_select_seq_from_preview(C, mval);
+ seq = seq_select_seq_from_preview(C, mval, toggle, extend, center);
}
else {
seq = find_nearest_seq(scene, v2d, &handle_clicked, mval);
@@ -741,10 +917,10 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
/* NOTE: `side_of_frame` and `linked_time` functionality is designed to be shared on one keymap,
* therefore both properties can be true at the same time. */
if (seq && RNA_boolean_get(op->ptr, "linked_time")) {
- if (!extend) {
+ if (!extend && !toggle) {
ED_sequencer_deselect_all(scene);
}
- sequencer_select_strip_impl(ed, seq, handle_clicked, extend);
+ sequencer_select_strip_impl(ed, seq, handle_clicked, extend, deselect, toggle);
select_linked_time(ed->seqbasep, seq);
sequencer_select_do_updates(C, scene);
sequencer_select_set_active(scene, seq);
@@ -753,7 +929,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
/* Select left, right or overlapping the current frame. */
if (RNA_boolean_get(op->ptr, "side_of_frame")) {
- if (!extend) {
+ if (!extend && !toggle) {
ED_sequencer_deselect_all(scene);
}
sequencer_select_side_of_frame(C, v2d, mval, scene);
@@ -763,7 +939,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
/* On Alt selection, select the strip and bordering handles. */
if (seq && RNA_boolean_get(op->ptr, "linked_handle")) {
- if (!extend) {
+ if (!extend && !toggle) {
ED_sequencer_deselect_all(scene);
}
sequencer_select_linked_handle(C, seq, handle_clicked);
@@ -776,29 +952,42 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
/* Clicking on already selected element falls on modal operation.
* All strips are deselected on mouse button release unless extend mode is used. */
- if (seq && element_already_selected(seq, handle_clicked) && wait_to_deselect_others && !extend) {
+ if (seq && element_already_selected(seq, handle_clicked) && wait_to_deselect_others && !toggle) {
return OPERATOR_RUNNING_MODAL;
}
- int ret_value = OPERATOR_CANCELLED;
+ bool changed = false;
- if (!extend) {
+ /* Deselect everything */
+ if (deselect_all || (seq && ((extend == false && deselect == false && toggle == false)))) {
ED_sequencer_deselect_all(scene);
- ret_value = OPERATOR_FINISHED;
+ changed = true;
}
/* Nothing to select, but strips could be deselected. */
if (!seq) {
- sequencer_select_do_updates(C, scene);
- return ret_value;
+ if (changed) {
+ sequencer_select_do_updates(C, scene);
+ }
+ return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
/* Do actual selection. */
- sequencer_select_strip_impl(ed, seq, handle_clicked, extend);
- ret_value = OPERATOR_FINISHED;
+ sequencer_select_strip_impl(ed, seq, handle_clicked, extend, deselect, toggle);
+
sequencer_select_do_updates(C, scene);
sequencer_select_set_active(scene, seq);
- return ret_value;
+ return OPERATOR_FINISHED;
+}
+
+static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const int retval = WM_generic_select_invoke(C, op, event);
+ ARegion *region = CTX_wm_region(C);
+ if (region && (region->regiontype == RGN_TYPE_PREVIEW)) {
+ return WM_operator_flag_only_pass_through_on_press(retval, event);
+ }
+ return retval;
}
void SEQUENCER_OT_select(wmOperatorType *ot)
@@ -812,7 +1001,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
/* Api callbacks. */
ot->exec = sequencer_select_exec;
- ot->invoke = WM_generic_select_invoke;
+ ot->invoke = sequencer_select_invoke;
ot->modal = WM_generic_select_modal;
ot->poll = ED_operator_sequencer_active;
@@ -822,7 +1011,14 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
/* Properties. */
WM_operator_properties_generic_select(ot);
- prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+ WM_operator_properties_mouse_select(ot);
+
+ prop = RNA_def_boolean(
+ ot->srna,
+ "center",
+ 0,
+ "Center",
+ "Use the object center when selecting, in edit mode used to extend object selection");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
@@ -1389,7 +1585,7 @@ static bool seq_box_select_rect_image_isect(const Scene *scene, const Sequence *
seq_image_quad[3], rect_quad[0], rect_quad[1], rect_quad[2], rect_quad[3]);
}
-static void seq_box_select_seq_from_preview(const bContext *C, rctf *rect)
+static void seq_box_select_seq_from_preview(const bContext *C, rctf *rect, const eSelectOp mode)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
@@ -1399,9 +1595,17 @@ static void seq_box_select_seq_from_preview(const bContext *C, rctf *rect)
SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, sseq->chanshown);
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
- if (seq_box_select_rect_image_isect(scene, seq, rect)) {
+ if (!seq_box_select_rect_image_isect(scene, seq, rect)) {
+ continue;
+ }
+
+ if (ELEM(mode, SEL_OP_ADD, SEL_OP_SET)) {
seq->flag |= SELECT;
}
+ else {
+ BLI_assert(mode == SEL_OP_SUB);
+ seq->flag &= ~SELECT;
+ }
}
SEQ_collection_free(strips);
@@ -1431,7 +1635,10 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
ARegion *region = CTX_wm_region(C);
if (region->regiontype == RGN_TYPE_PREVIEW) {
- seq_box_select_seq_from_preview(C, &rectf);
+ if (!sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
+ seq_box_select_seq_from_preview(C, &rectf, sel_op);
sequencer_select_do_updates(C, scene);
return OPERATOR_FINISHED;
}
@@ -1490,6 +1697,11 @@ static int sequencer_box_select_invoke(bContext *C, wmOperator *op, const wmEven
{
Scene *scene = CTX_data_scene(C);
View2D *v2d = &CTX_wm_region(C)->v2d;
+ ARegion *region = CTX_wm_region(C);
+
+ if (region->regiontype == RGN_TYPE_PREVIEW && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
const bool tweak = RNA_boolean_get(op->ptr, "tweak");
@@ -1571,7 +1783,8 @@ static const EnumPropertyItem sequencer_prop_select_grouped_types[] = {
"EFFECT_LINK",
0,
"Effect/Linked",
- "Other strips affected by the active one (sharing some time, and below or effect-assigned)"},
+ "Other strips affected by the active one (sharing some time, and below or "
+ "effect-assigned)"},
{SEQ_SELECT_GROUP_OVERLAP, "OVERLAP", 0, "Overlap", "Overlapping time"},
{0, NULL, 0, NULL, NULL},
};
@@ -1585,11 +1798,15 @@ static const EnumPropertyItem sequencer_prop_select_grouped_types[] = {
#define SEQ_CHANNEL_CHECK(_seq, _chan) (ELEM((_chan), 0, (_seq)->machine))
-static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_type(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == actseq->type) {
seq->flag |= SELECT;
changed = true;
@@ -1599,12 +1816,16 @@ static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel
return changed;
}
-static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_type_basic(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
const bool is_sound = SEQ_IS_SOUND(actseq);
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq))) {
seq->flag |= SELECT;
changed = true;
@@ -1614,12 +1835,16 @@ static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int c
return changed;
}
-static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_type_effect(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
const bool is_effect = SEQ_IS_EFFECT(actseq);
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) &&
(is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq))) {
seq->flag |= SELECT;
@@ -1630,7 +1855,10 @@ static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int
return changed;
}
-static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_data(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
const char *dir = actseq->strip ? actseq->strip->dir : NULL;
@@ -1639,8 +1867,10 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
return changed;
}
+ Sequence *seq;
+
if (SEQ_HAS_PATH(actseq) && dir) {
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip &&
STREQ(seq->strip->dir, dir)) {
seq->flag |= SELECT;
@@ -1650,7 +1880,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
}
else if (actseq->type == SEQ_TYPE_SCENE) {
Scene *sce = actseq->scene;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
seq->flag |= SELECT;
changed = true;
@@ -1659,7 +1889,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
}
else if (actseq->type == SEQ_TYPE_MOVIECLIP) {
MovieClip *clip = actseq->clip;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MOVIECLIP &&
seq->clip == clip) {
seq->flag |= SELECT;
@@ -1669,7 +1899,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
}
else if (actseq->type == SEQ_TYPE_MASK) {
struct Mask *mask = actseq->mask;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
seq->flag |= SELECT;
changed = true;
@@ -1680,7 +1910,10 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
return changed;
}
-static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_effect(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
bool effects[SEQ_TYPE_MAX + 1];
@@ -1689,14 +1922,15 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int chann
effects[i] = false;
}
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) &&
ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
effects[seq->type] = true;
}
}
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && effects[seq->type]) {
if (seq->seq1) {
seq->seq1->flag |= SELECT;
@@ -1714,11 +1948,14 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int chann
return changed;
}
-static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq)
+static bool select_grouped_time_overlap(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
+ Sequence *actseq)
{
bool changed = false;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (seq->startdisp < actseq->enddisp && seq->enddisp > actseq->startdisp) {
seq->flag |= SELECT;
changed = true;
@@ -1747,29 +1984,26 @@ static void query_lower_channel_strips(Sequence *seq_reference,
/* Select all strips within time range and with lower channel of initial selection. Then select
* effect chains of these strips. */
-static bool select_grouped_effect_link(Editing *ed,
+static bool select_grouped_effect_link(SeqCollection *strips,
+ ListBase *seqbase,
Sequence *UNUSED(actseq),
const int UNUSED(channel))
{
- ListBase *seqbase = SEQ_active_seqbase_get(ed);
-
/* Get collection of strips. */
- SeqCollection *collection = SEQ_query_selected_strips(seqbase);
- const int selected_strip_count = BLI_gset_len(collection->set);
- SEQ_collection_expand(seqbase, collection, query_lower_channel_strips);
- SEQ_collection_expand(seqbase, collection, SEQ_query_strip_effect_chain);
+ SEQ_filter_selected_strips(strips);
+ const int selected_strip_count = SEQ_collection_len(strips);
+ SEQ_collection_expand(seqbase, strips, query_lower_channel_strips);
+ SEQ_collection_expand(seqbase, strips, SEQ_query_strip_effect_chain);
/* Check if other strips will be affected. */
- const bool changed = BLI_gset_len(collection->set) > selected_strip_count;
+ const bool changed = SEQ_collection_len(strips) > selected_strip_count;
/* Actual logic. */
Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, collection) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
seq->flag |= SELECT;
}
- SEQ_collection_free(collection);
-
return changed;
}
@@ -1780,10 +2014,17 @@ static bool select_grouped_effect_link(Editing *ed,
static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
Sequence *actseq = SEQ_select_active_get(scene);
- if (actseq == NULL) {
+ const bool is_preview = sequencer_view_has_preview_poll(C);
+ if (is_preview && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SeqCollection *strips = all_strips_from_context(C);
+
+ if (actseq == NULL || (is_preview && !SEQ_collection_has_strip(actseq, strips))) {
BKE_report(op->reports, RPT_ERROR, "No active sequence!");
return OPERATOR_CANCELLED;
}
@@ -1795,7 +2036,7 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
bool changed = false;
if (!extend) {
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
seq->flag &= ~SELECT;
changed = true;
}
@@ -1803,31 +2044,33 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
switch (type) {
case SEQ_SELECT_GROUP_TYPE:
- changed |= select_grouped_type(ed, actseq, channel);
+ changed |= select_grouped_type(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_TYPE_BASIC:
- changed |= select_grouped_type_basic(ed, actseq, channel);
+ changed |= select_grouped_type_basic(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_TYPE_EFFECT:
- changed |= select_grouped_type_effect(ed, actseq, channel);
+ changed |= select_grouped_type_effect(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_DATA:
- changed |= select_grouped_data(ed, actseq, channel);
+ changed |= select_grouped_data(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_EFFECT:
- changed |= select_grouped_effect(ed, actseq, channel);
+ changed |= select_grouped_effect(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_EFFECT_LINK:
- changed |= select_grouped_effect_link(ed, actseq, channel);
+ changed |= select_grouped_effect_link(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_OVERLAP:
- changed |= select_grouped_time_overlap(ed, actseq);
+ changed |= select_grouped_time_overlap(strips, seqbase, actseq);
break;
default:
BLI_assert(0);
break;
}
+ SEQ_collection_free(strips);
+
if (changed) {
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
new file mode 100644
index 00000000000..82ba17d4db1
--- /dev/null
+++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
@@ -0,0 +1,592 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup spseq
+ */
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_scene.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "ED_screen.h"
+
+#include "BIF_glutil.h"
+
+#include "SEQ_relations.h"
+#include "SEQ_render.h"
+#include "SEQ_sequencer.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "MEM_guardedalloc.h"
+
+/* Own include. */
+#include "sequencer_intern.h"
+
+typedef struct ThumbnailDrawJob {
+ SeqRenderData context;
+ GHash *sequences_ghash;
+ Scene *scene;
+ rctf *view_area;
+ float pixelx;
+ float pixely;
+ float thumb_height;
+} ThumbnailDrawJob;
+
+typedef struct ThumbDataItem {
+ Sequence *seq_dupli;
+ Scene *scene;
+} ThumbDataItem;
+
+static void thumbnail_hash_data_free(void *val)
+{
+ ThumbDataItem *item = val;
+ SEQ_sequence_free(item->scene, item->seq_dupli);
+ MEM_freeN(val);
+}
+
+static void thumbnail_freejob(void *data)
+{
+ ThumbnailDrawJob *tj = data;
+ BLI_ghash_free(tj->sequences_ghash, NULL, thumbnail_hash_data_free);
+ MEM_freeN(tj->view_area);
+ MEM_freeN(tj);
+}
+
+static void thumbnail_endjob(void *data)
+{
+ ThumbnailDrawJob *tj = data;
+ WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, tj->scene);
+}
+
+static bool check_seq_need_thumbnails(Sequence *seq, rctf *view_area)
+{
+ if (!ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) {
+ return false;
+ }
+ if (min_ii(seq->startdisp, seq->start) > view_area->xmax) {
+ return false;
+ }
+ if (max_ii(seq->enddisp, seq->start + seq->len) < view_area->xmin) {
+ return false;
+ }
+ if (seq->machine + 1.0f < view_area->ymin) {
+ return false;
+ }
+ if (seq->machine > view_area->ymax) {
+ return false;
+ }
+
+ return true;
+}
+
+static void seq_get_thumb_image_dimensions(Sequence *seq,
+ float pixelx,
+ float pixely,
+ float *r_thumb_width,
+ float thumb_height,
+ float *r_image_width,
+ float *r_image_height)
+{
+ float image_width = seq->strip->stripdata->orig_width;
+ float image_height = seq->strip->stripdata->orig_height;
+
+ /* Fix the dimensions to be max SEQ_RENDER_THUMB_SIZE (256) for x or y. */
+ float aspect_ratio = (float)image_width / image_height;
+ if (image_width > image_height) {
+ image_width = SEQ_RENDER_THUMB_SIZE;
+ image_height = round_fl_to_int(image_width / aspect_ratio);
+ }
+ else {
+ image_height = SEQ_RENDER_THUMB_SIZE;
+ image_width = round_fl_to_int(image_height * aspect_ratio);
+ }
+
+ /* Calculate thumb dimensions. */
+ aspect_ratio = ((float)image_width) / image_height;
+ float thumb_h_px = thumb_height / pixely;
+ float thumb_width = aspect_ratio * thumb_h_px * pixelx;
+
+ *r_thumb_width = thumb_width;
+ if (r_image_width && r_image_height) {
+ *r_image_width = image_width;
+ *r_image_height = image_height;
+ }
+}
+
+static float seq_thumbnail_get_start_frame(Sequence *seq, float frame_step, rctf *view_area)
+{
+ if (seq->start > view_area->xmin && seq->start < view_area->xmax) {
+ return seq->start;
+ }
+
+ /* Drawing and caching both check to see if strip is in view area or not before calling this
+ * function so assuming strip/part of strip in view. */
+
+ int no_invisible_thumbs = (view_area->xmin - seq->start) / frame_step;
+ return ((no_invisible_thumbs - 1) * frame_step) + seq->start;
+}
+
+static void thumbnail_start_job(void *data,
+ short *stop,
+ short *UNUSED(do_update),
+ float *UNUSED(progress))
+{
+ ThumbnailDrawJob *tj = data;
+ float start_frame, frame_step;
+
+ GHashIterator gh_iter;
+
+ /* First pass: render visible images. */
+ BLI_ghashIterator_init(&gh_iter, tj->sequences_ghash);
+ while (!BLI_ghashIterator_done(&gh_iter) & !*stop) {
+ Sequence *seq_orig = BLI_ghashIterator_getKey(&gh_iter);
+ ThumbDataItem *val = BLI_ghash_lookup(tj->sequences_ghash, seq_orig);
+
+ if (check_seq_need_thumbnails(seq_orig, tj->view_area)) {
+ seq_get_thumb_image_dimensions(
+ val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, tj->thumb_height, NULL, NULL);
+ start_frame = seq_thumbnail_get_start_frame(seq_orig, frame_step, tj->view_area);
+ SEQ_render_thumbnails(
+ &tj->context, val->seq_dupli, seq_orig, start_frame, frame_step, tj->view_area, stop);
+ SEQ_relations_sequence_free_anim(val->seq_dupli);
+ }
+ BLI_ghashIterator_step(&gh_iter);
+ }
+
+ /* Second pass: render "guaranteed" set of images. */
+ BLI_ghashIterator_init(&gh_iter, tj->sequences_ghash);
+ while (!BLI_ghashIterator_done(&gh_iter) & !*stop) {
+ Sequence *seq_orig = BLI_ghashIterator_getKey(&gh_iter);
+ ThumbDataItem *val = BLI_ghash_lookup(tj->sequences_ghash, seq_orig);
+
+ if (check_seq_need_thumbnails(seq_orig, tj->view_area)) {
+ seq_get_thumb_image_dimensions(
+ val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, tj->thumb_height, NULL, NULL);
+ start_frame = seq_thumbnail_get_start_frame(seq_orig, frame_step, tj->view_area);
+ SEQ_render_thumbnails_base_set(&tj->context, val->seq_dupli, seq_orig, tj->view_area, stop);
+ SEQ_relations_sequence_free_anim(val->seq_dupli);
+ }
+ BLI_ghashIterator_step(&gh_iter);
+ }
+}
+
+static SeqRenderData sequencer_thumbnail_context_init(const bContext *C)
+{
+ struct Main *bmain = CTX_data_main(C);
+ struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Scene *scene = CTX_data_scene(C);
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ SeqRenderData context = {0};
+
+ /* Taking rectx and recty as 0 as dimensions not known here, and context is used to calculate
+ * hash key but not necessary as other variables of SeqRenderData are unique enough. */
+ SEQ_render_new_render_data(bmain, depsgraph, scene, 0, 0, sseq->render_size, false, &context);
+ context.view_id = BKE_scene_multiview_view_id_get(&scene->r, STEREO_LEFT_NAME);
+ context.use_proxies = false;
+
+ return context;
+}
+
+static GHash *sequencer_thumbnail_ghash_init(const bContext *C, View2D *v2d, Editing *ed)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ /* Set the data for thumbnail caching job. */
+ GHash *thumb_data_hash = BLI_ghash_ptr_new("seq_duplicates_and_origs");
+
+ LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
+ ThumbDataItem *val_need_update = BLI_ghash_lookup(thumb_data_hash, seq);
+ if (val_need_update == NULL && check_seq_need_thumbnails(seq, &v2d->cur)) {
+ ThumbDataItem *val = MEM_callocN(sizeof(ThumbDataItem), "Thumbnail Hash Values");
+ val->seq_dupli = SEQ_sequence_dupli_recursive(scene, scene, NULL, seq, 0);
+ val->scene = scene;
+ BLI_ghash_insert(thumb_data_hash, seq, val);
+ }
+ else {
+ if (val_need_update != NULL) {
+ val_need_update->seq_dupli->start = seq->start;
+ val_need_update->seq_dupli->startdisp = seq->startdisp;
+ }
+ }
+ }
+
+ return thumb_data_hash;
+}
+
+static void sequencer_thumbnail_init_job(const bContext *C,
+ View2D *v2d,
+ Editing *ed,
+ float thumb_height)
+{
+ wmJob *wm_job;
+ ThumbnailDrawJob *tj = NULL;
+ ScrArea *area = CTX_wm_area(C);
+ wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ CTX_data_scene(C),
+ "Draw Thumbnails",
+ 0,
+ WM_JOB_TYPE_SEQ_DRAW_THUMBNAIL);
+
+ /* Get the thumbnail job if it exists. */
+ tj = WM_jobs_customdata_get(wm_job);
+ if (!tj) {
+ tj = MEM_callocN(sizeof(ThumbnailDrawJob), "Thumbnail cache job");
+
+ /* Duplicate value of v2d->cur and v2d->tot to have module separation. */
+ rctf *view_area = MEM_callocN(sizeof(struct rctf), "viewport area");
+ view_area->xmax = v2d->cur.xmax;
+ view_area->xmin = v2d->cur.xmin;
+ view_area->ymax = v2d->cur.ymax;
+ view_area->ymin = v2d->cur.ymin;
+
+ tj->scene = CTX_data_scene(C);
+ tj->view_area = view_area;
+ tj->context = sequencer_thumbnail_context_init(C);
+ tj->sequences_ghash = sequencer_thumbnail_ghash_init(C, v2d, ed);
+ tj->pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
+ tj->pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask);
+ tj->thumb_height = thumb_height;
+ WM_jobs_customdata_set(wm_job, tj, thumbnail_freejob);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_SEQUENCER, NC_SCENE | ND_SEQUENCER);
+ WM_jobs_callbacks(wm_job, thumbnail_start_job, NULL, NULL, thumbnail_endjob);
+ }
+
+ if (!WM_jobs_is_running(wm_job)) {
+ G.is_break = false;
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ }
+ else {
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL);
+ }
+
+ ED_area_tag_redraw(area);
+}
+
+static bool sequencer_thumbnail_v2d_is_navigating(const bContext *C)
+{
+ ARegion *region = CTX_wm_region(C);
+ View2D *v2d = &region->v2d;
+ return (v2d->flag & V2D_IS_NAVIGATING) != 0;
+}
+
+static void sequencer_thumbnail_start_job_if_necessary(
+ const bContext *C, Editing *ed, View2D *v2d, bool thumbnail_is_missing, float thumb_height)
+{
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+
+ if (sequencer_thumbnail_v2d_is_navigating(C)) {
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL);
+ return;
+ }
+
+ /* During rendering, cache is wiped, it doesn't make sense to render thumbnails. */
+ if (G.is_rendering) {
+ return;
+ }
+
+ /* Job start requested, but over area which has been processed. Unless `thumbnail_is_missing` is
+ * true, ignore this request as all images are in view. */
+ if (v2d->cur.xmax == sseq->runtime.last_thumbnail_area.xmax &&
+ v2d->cur.ymax == sseq->runtime.last_thumbnail_area.ymax && !thumbnail_is_missing) {
+ return;
+ }
+
+ /* Stop the job first as view has changed. Pointless to continue old job. */
+ if (v2d->cur.xmax != sseq->runtime.last_thumbnail_area.xmax ||
+ v2d->cur.ymax != sseq->runtime.last_thumbnail_area.ymax) {
+ WM_jobs_stop(CTX_wm_manager(C), NULL, thumbnail_start_job);
+ }
+
+ sequencer_thumbnail_init_job(C, v2d, ed, thumb_height);
+ sseq->runtime.last_thumbnail_area = v2d->cur;
+}
+
+void last_displayed_thumbnails_list_free(void *val)
+{
+ BLI_gset_free(val, NULL);
+}
+
+static GSet *last_displayed_thumbnails_list_ensure(const bContext *C, Sequence *seq)
+{
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ if (sseq->runtime.last_displayed_thumbnails == NULL) {
+ sseq->runtime.last_displayed_thumbnails = BLI_ghash_ptr_new(__func__);
+ }
+
+ GSet *displayed_thumbnails = BLI_ghash_lookup(sseq->runtime.last_displayed_thumbnails, seq);
+ if (displayed_thumbnails == NULL) {
+ displayed_thumbnails = BLI_gset_int_new(__func__);
+ BLI_ghash_insert(sseq->runtime.last_displayed_thumbnails, seq, displayed_thumbnails);
+ }
+
+ return displayed_thumbnails;
+}
+
+static void last_displayed_thumbnails_list_cleanup(GSet *previously_displayed,
+ float range_start,
+ float range_end)
+{
+ GSetIterator gset_iter;
+ BLI_gsetIterator_init(&gset_iter, previously_displayed);
+ while (!BLI_gsetIterator_done(&gset_iter)) {
+ int frame = (float)POINTER_AS_INT(BLI_gsetIterator_getKey(&gset_iter));
+ BLI_gsetIterator_step(&gset_iter);
+
+ if (frame > range_start && frame < range_end) {
+ BLI_gset_remove(previously_displayed, POINTER_FROM_INT(frame), NULL);
+ }
+ }
+}
+
+static int sequencer_thumbnail_closest_previous_frame_get(int timeline_frame,
+ GSet *previously_displayed)
+{
+ int best_diff = INT_MAX;
+ int best_frame = timeline_frame;
+
+ /* Previously displayed thumbnails. */
+ GSetIterator gset_iter;
+ BLI_gsetIterator_init(&gset_iter, previously_displayed);
+ while (!BLI_gsetIterator_done(&gset_iter)) {
+ int frame = POINTER_AS_INT(BLI_gsetIterator_getKey(&gset_iter));
+ int diff = abs(frame - timeline_frame);
+ if (diff < best_diff) {
+ best_diff = diff;
+ best_frame = frame;
+ }
+ BLI_gsetIterator_step(&gset_iter);
+ }
+ return best_frame;
+}
+
+static int sequencer_thumbnail_closest_guaranteed_frame_get(Sequence *seq, int timeline_frame)
+{
+ if (timeline_frame <= seq->startdisp) {
+ return seq->startdisp;
+ }
+
+ /* Set of "guaranteed" thumbnails. */
+ const int frame_index = timeline_frame - seq->startdisp;
+ const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(seq);
+ const int relative_base_frame = round_fl_to_int((frame_index / (float)frame_step)) * frame_step;
+ const int nearest_guaranted_absolute_frame = relative_base_frame + seq->startdisp;
+ return nearest_guaranted_absolute_frame;
+}
+
+static ImBuf *sequencer_thumbnail_closest_from_memory(const SeqRenderData *context,
+ Sequence *seq,
+ int timeline_frame,
+ GSet *previously_displayed,
+ rcti *crop,
+ bool clipped)
+{
+ int frame_previous = sequencer_thumbnail_closest_previous_frame_get(timeline_frame,
+ previously_displayed);
+ ImBuf *ibuf_previous = SEQ_get_thumbnail(context, seq, frame_previous, crop, clipped);
+
+ int frame_guaranteed = sequencer_thumbnail_closest_guaranteed_frame_get(seq, timeline_frame);
+ ImBuf *ibuf_guaranteed = SEQ_get_thumbnail(context, seq, frame_guaranteed, crop, clipped);
+
+ ImBuf *closest_in_memory = NULL;
+
+ if (ibuf_previous && ibuf_guaranteed) {
+ if (abs(frame_previous - timeline_frame) < abs(frame_guaranteed - timeline_frame)) {
+ IMB_freeImBuf(ibuf_guaranteed);
+ closest_in_memory = ibuf_previous;
+ }
+ else {
+ IMB_freeImBuf(ibuf_previous);
+ closest_in_memory = ibuf_guaranteed;
+ }
+ }
+
+ if (ibuf_previous == NULL) {
+ closest_in_memory = ibuf_guaranteed;
+ }
+
+ if (ibuf_guaranteed == NULL) {
+ closest_in_memory = ibuf_previous;
+ }
+
+ return closest_in_memory;
+}
+
+void draw_seq_strip_thumbnail(View2D *v2d,
+ const bContext *C,
+ Scene *scene,
+ Sequence *seq,
+ float y1,
+ float y2,
+ float pixelx,
+ float pixely)
+{
+ bool clipped = false;
+ float image_height, image_width, thumb_width;
+ rcti crop;
+
+ /* If width of the strip too small ignore drawing thumbnails. */
+ if ((y2 - y1) / pixely <= 20 * U.dpi_fac) {
+ return;
+ }
+
+ SeqRenderData context = sequencer_thumbnail_context_init(C);
+
+ if ((seq->flag & SEQ_FLAG_SKIP_THUMBNAILS) != 0) {
+ return;
+ }
+
+ const float thumb_height = y2 - y1;
+ seq_get_thumb_image_dimensions(
+ seq, pixelx, pixely, &thumb_width, thumb_height, &image_width, &image_height);
+
+ float thumb_y_end = y1 + thumb_height;
+
+ float cut_off = 0;
+ float upper_thumb_bound = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp;
+ if (seq->type == SEQ_TYPE_IMAGE) {
+ upper_thumb_bound = seq->enddisp;
+ }
+
+ float thumb_x_start = seq_thumbnail_get_start_frame(seq, thumb_width, &v2d->cur);
+ float thumb_x_end;
+
+ while (thumb_x_start + thumb_width < v2d->cur.xmin) {
+ thumb_x_start += thumb_width;
+ }
+
+ /* Ignore thumbs to the left of strip. */
+ while (thumb_x_start + thumb_width < seq->startdisp) {
+ thumb_x_start += thumb_width;
+ }
+
+ GSet *last_displayed_thumbnails = last_displayed_thumbnails_list_ensure(C, seq);
+ /* Cleanup thumbnail list outside of rendered range, which is cleaned up one by one to prevent
+ * flickering after zooming. */
+ if (!sequencer_thumbnail_v2d_is_navigating(C)) {
+ last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, -FLT_MAX, thumb_x_start);
+ }
+
+ /* Start drawing. */
+ while (thumb_x_start < upper_thumb_bound) {
+ thumb_x_end = thumb_x_start + thumb_width;
+ clipped = false;
+
+ /* Checks to make sure that thumbs are loaded only when in view and within the confines of the
+ * strip. Some may not be required but better to have conditions for safety as x1 here is
+ * point to start caching from and not drawing. */
+ if (thumb_x_start > v2d->cur.xmax) {
+ break;
+ }
+
+ /* Set the clipping bound to show the left handle moving over thumbs and not shift thumbs. */
+ if (IN_RANGE_INCL(seq->startdisp, thumb_x_start, thumb_x_end)) {
+ cut_off = seq->startdisp - thumb_x_start;
+ clipped = true;
+ }
+
+ /* Clip if full thumbnail cannot be displayed. */
+ if (thumb_x_end > (upper_thumb_bound)) {
+ thumb_x_end = upper_thumb_bound;
+ clipped = true;
+ if (thumb_x_end - thumb_x_start < 1) {
+ break;
+ }
+ }
+
+ float zoom_x = thumb_width / image_width;
+ float zoom_y = thumb_height / image_height;
+
+ float cropx_min = (cut_off / pixelx) / (zoom_y / pixely);
+ float cropx_max = ((thumb_x_end - thumb_x_start) / pixelx) / (zoom_y / pixely);
+ if (cropx_max == (thumb_x_end - thumb_x_start)) {
+ cropx_max = cropx_max + 1;
+ }
+ BLI_rcti_init(&crop, (int)(cropx_min), (int)cropx_max, 0, (int)(image_height)-1);
+
+ int timeline_frame = round_fl_to_int(thumb_x_start);
+
+ /* Get the image. */
+ ImBuf *ibuf = SEQ_get_thumbnail(&context, seq, timeline_frame, &crop, clipped);
+
+ if (!ibuf) {
+ sequencer_thumbnail_start_job_if_necessary(C, scene->ed, v2d, true, thumb_height);
+
+ ibuf = sequencer_thumbnail_closest_from_memory(
+ &context, seq, timeline_frame, last_displayed_thumbnails, &crop, clipped);
+ }
+ /* Store recently rendered frames, so they can be reused when zooming. */
+ else if (!sequencer_thumbnail_v2d_is_navigating(C)) {
+ /* Clear images in frame range occupied by new thumbnail. */
+ last_displayed_thumbnails_list_cleanup(
+ last_displayed_thumbnails, thumb_x_start, thumb_x_end);
+ /* Insert new thumbnail frame to list. */
+ BLI_gset_add(last_displayed_thumbnails, POINTER_FROM_INT(timeline_frame));
+ }
+
+ /* If there is no image still, abort. */
+ if (!ibuf) {
+ break;
+ }
+
+ /* Transparency on overlap. */
+ if (seq->flag & SEQ_OVERLAP) {
+ GPU_blend(GPU_BLEND_ALPHA);
+ if (ibuf->rect) {
+ unsigned char *buf = (unsigned char *)ibuf->rect;
+ for (int pixel = ibuf->x * ibuf->y; pixel--; buf += 4) {
+ buf[3] = OVERLAP_ALPHA;
+ }
+ }
+ else if (ibuf->rect_float) {
+ float *buf = (float *)ibuf->rect_float;
+ for (int pixel = ibuf->x * ibuf->y; pixel--; buf += ibuf->channels) {
+ buf[3] = (OVERLAP_ALPHA / 255.0f);
+ }
+ }
+ }
+
+ ED_draw_imbuf_ctx_clipping(C,
+ ibuf,
+ thumb_x_start + cut_off,
+ y1,
+ true,
+ thumb_x_start + cut_off,
+ y1,
+ thumb_x_end,
+ thumb_y_end,
+ zoom_x,
+ zoom_y);
+ IMB_freeImBuf(ibuf);
+ GPU_blend(GPU_BLEND_NONE);
+ cut_off = 0;
+ thumb_x_start += thumb_width;
+ }
+ last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, thumb_x_start, FLT_MAX);
+}
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index 981f793c896..360aa2253de 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -92,7 +92,14 @@ static int sequencer_view_all_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
const Editing *ed = SEQ_editing_get(scene);
- SEQ_timeline_boundbox(scene, SEQ_active_seqbase_get(ed), &box);
+ SEQ_timeline_init_boundbox(scene, &box);
+ MetaStack *ms = SEQ_meta_stack_active_get(ed);
+ /* Use meta strip range instead of scene. */
+ if (ms != NULL) {
+ box.xmin = ms->disp_range[0] - 1;
+ box.xmax = ms->disp_range[1] + 1;
+ }
+ SEQ_timeline_expand_boundbox(SEQ_active_seqbase_get(ed), &box);
UI_view2d_smooth_view(C, region, &box, smooth_viewtx);
return OPERATOR_FINISHED;
}
@@ -380,7 +387,7 @@ static int view_ghost_border_exec(bContext *C, wmOperator *op)
CLAMP(rect.xmax, 0.0f, 1.0f);
CLAMP(rect.ymax, 0.0f, 1.0f);
- scene->ed->over_border = rect;
+ scene->ed->overlay_frame_rect = rect;
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -398,7 +405,7 @@ void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
ot->invoke = WM_gesture_box_invoke;
ot->exec = view_ghost_border_exec;
ot->modal = WM_gesture_box_modal;
- ot->poll = sequencer_view_preview_poll;
+ ot->poll = sequencer_view_has_preview_poll;
ot->cancel = WM_gesture_box_cancel;
/* Flags. */
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index ad0ceb82709..b294fdf4820 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -28,6 +28,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
+#include "DNA_sound_types.h"
#include "MEM_guardedalloc.h"
@@ -38,9 +39,12 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "BKE_sequencer_offscreen.h"
+#include "GPU_state.h"
+
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_transform.h"
@@ -53,6 +57,7 @@
#include "RNA_access.h"
+#include "SEQ_transform.h"
#include "SEQ_utils.h"
#include "UI_interface.h"
@@ -61,6 +66,9 @@
#include "IMB_imbuf.h"
+/* Only for cursor drawing. */
+#include "DRW_engine.h"
+
/* Own include. */
#include "sequencer_intern.h"
@@ -178,7 +186,7 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce
region->v2d.cur = region->v2d.tot;
region->v2d.min[0] = 10.0f;
- region->v2d.min[1] = 4.0f;
+ region->v2d.min[1] = 1.0f;
region->v2d.max[0] = MAXFRAMEF;
region->v2d.max[1] = MAXSEQ;
@@ -394,7 +402,7 @@ static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
}
}
- return 0;
+ return WM_drag_is_ID_type(drag, ID_IM);
}
static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
@@ -410,7 +418,8 @@ static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
}
}
}
- return 0;
+
+ return WM_drag_is_ID_type(drag, ID_MC);
}
static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
@@ -426,35 +435,61 @@ static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
}
}
}
- return 0;
+
+ return WM_drag_is_ID_type(drag, ID_SO);
}
static void sequencer_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- /* Copy drag path to properties. */
- if (RNA_struct_find_property(drop->ptr, "filepath")) {
- RNA_string_set(drop->ptr, "filepath", drag->path);
+ ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
+ /* ID dropped. */
+ if (id != NULL) {
+ const ID_Type id_type = GS(id->name);
+ if (id_type == ID_IM) {
+ Image *ima = (Image *)id;
+ PointerRNA itemptr;
+ char dir[FILE_MAX], file[FILE_MAX];
+ BLI_split_dirfile(ima->filepath, dir, file, sizeof(dir), sizeof(file));
+ RNA_string_set(drop->ptr, "directory", dir);
+ RNA_collection_clear(drop->ptr, "files");
+ RNA_collection_add(drop->ptr, "files", &itemptr);
+ RNA_string_set(&itemptr, "name", file);
+ }
+ else if (id_type == ID_MC) {
+ MovieClip *clip = (MovieClip *)id;
+ RNA_string_set(drop->ptr, "filepath", clip->filepath);
+ RNA_struct_property_unset(drop->ptr, "name");
+ }
+ else if (id_type == ID_SO) {
+ bSound *sound = (bSound *)id;
+ RNA_string_set(drop->ptr, "filepath", sound->filepath);
+ RNA_struct_property_unset(drop->ptr, "name");
+ }
}
+ /* Path dropped. */
+ else if (drag->path[0]) {
+ if (RNA_struct_find_property(drop->ptr, "filepath")) {
+ RNA_string_set(drop->ptr, "filepath", drag->path);
+ }
+ if (RNA_struct_find_property(drop->ptr, "directory")) {
+ PointerRNA itemptr;
+ char dir[FILE_MAX], file[FILE_MAX];
- if (RNA_struct_find_property(drop->ptr, "directory")) {
- PointerRNA itemptr;
- char dir[FILE_MAX], file[FILE_MAX];
-
- BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file));
+ BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file));
- RNA_string_set(drop->ptr, "directory", dir);
+ RNA_string_set(drop->ptr, "directory", dir);
- RNA_collection_clear(drop->ptr, "files");
- RNA_collection_add(drop->ptr, "files", &itemptr);
- RNA_string_set(&itemptr, "name", file);
+ RNA_collection_clear(drop->ptr, "files");
+ RNA_collection_add(drop->ptr, "files", &itemptr);
+ RNA_string_set(&itemptr, "name", file);
+ }
}
}
/* This region dropbox definition. */
-static void sequencer_dropboxes(void)
-{
- ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
+static void sequencer_dropboxes_add_to_lb(ListBase *lb)
+{
WM_dropbox_add(
lb, "SEQUENCER_OT_image_strip_add", image_drop_poll, sequencer_drop_copy, NULL, NULL);
WM_dropbox_add(
@@ -463,6 +498,14 @@ static void sequencer_dropboxes(void)
lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy, NULL, NULL);
}
+static void sequencer_dropboxes(void)
+{
+ ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
+ sequencer_dropboxes_add_to_lb(lb);
+ lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_PREVIEW);
+ sequencer_dropboxes_add_to_lb(lb);
+}
+
/* ************* end drop *********** */
/* DO NOT make this static, this hides the symbol and breaks API generation script. */
@@ -751,6 +794,9 @@ static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *region)
/* Own keymap. */
keymap = WM_keymap_ensure(wm->defaultconf, "SequencerPreview", SPACE_SEQ, 0);
WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
+
+ ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_PREVIEW);
+ WM_event_add_dropbox_handler(&region->handlers, lb);
}
static void sequencer_preview_region_layout(const bContext *C, ARegion *region)
@@ -769,41 +815,67 @@ static void sequencer_preview_region_view2d_changed(const bContext *C, ARegion *
sseq->flag &= ~SEQ_ZOOM_TO_FIT;
}
+static bool is_cursor_visible(const SpaceSeq *sseq)
+{
+ if (G.moving & G_TRANSFORM_CURSOR) {
+ return true;
+ }
+
+ if ((sseq->flag & SEQ_SHOW_OVERLAY) &&
+ (sseq->preview_overlay.flag & SEQ_PREVIEW_SHOW_2D_CURSOR) != 0) {
+ return true;
+ }
+ return false;
+}
+
static void sequencer_preview_region_draw(const bContext *C, ARegion *region)
{
ScrArea *area = CTX_wm_area(C);
SpaceSeq *sseq = area->spacedata.first;
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
- const bool draw_overlay = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) &&
- (sseq->flag & SEQ_SHOW_OVERLAY));
+ const bool draw_overlay = sseq->flag & SEQ_SHOW_OVERLAY;
+ const bool draw_frame_overlay = (scene->ed &&
+ (scene->ed->overlay_frame_flag & SEQ_EDIT_OVERLAY_FRAME_SHOW) &&
+ draw_overlay);
+ const bool is_playing = ED_screen_animation_playing(wm);
- /* XXX temp fix for wrong setting in sseq->mainb */
- if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
- sseq->mainb = SEQ_DRAW_IMG_IMBUF;
- }
-
- if (!draw_overlay || sseq->overlay_type != SEQ_DRAW_OVERLAY_REFERENCE) {
+ if (!(draw_frame_overlay && (sseq->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_REFERENCE))) {
sequencer_draw_preview(C, scene, region, sseq, scene->r.cfra, 0, false, false);
}
- if (draw_overlay && sseq->overlay_type != SEQ_DRAW_OVERLAY_CURRENT) {
+ if (draw_frame_overlay && sseq->overlay_frame_type != SEQ_OVERLAY_FRAME_TYPE_CURRENT) {
int over_cfra;
- if (scene->ed->over_flag & SEQ_EDIT_OVERLAY_ABS) {
- over_cfra = scene->ed->over_cfra;
+ if (scene->ed->overlay_frame_flag & SEQ_EDIT_OVERLAY_FRAME_ABS) {
+ over_cfra = scene->ed->overlay_frame_abs;
}
else {
- over_cfra = scene->r.cfra + scene->ed->over_ofs;
+ over_cfra = scene->r.cfra + scene->ed->overlay_frame_ofs;
}
- if (over_cfra != scene->r.cfra || sseq->overlay_type != SEQ_DRAW_OVERLAY_RECT) {
+ if ((over_cfra != scene->r.cfra) ||
+ (sseq->overlay_frame_type != SEQ_OVERLAY_FRAME_TYPE_RECT)) {
sequencer_draw_preview(
C, scene, region, sseq, scene->r.cfra, over_cfra - scene->r.cfra, true, false);
}
}
- WM_gizmomap_draw(region->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D);
+ /* No need to show the cursor for scopes. */
+ if ((is_playing == false) && (sseq->mainb == SEQ_DRAW_IMG_IMBUF) && is_cursor_visible(sseq)) {
+ GPU_color_mask(true, true, true, true);
+ GPU_depth_mask(false);
+ GPU_depth_test(GPU_DEPTH_NONE);
+
+ float cursor_pixel[2];
+ SEQ_image_preview_unit_to_px(scene, sseq->cursor, cursor_pixel);
+
+ DRW_draw_cursor_2d_ex(region, cursor_pixel);
+ }
+
+ if ((is_playing == false) && (sseq->gizmo_flag & SEQ_GIZMO_HIDE) == 0) {
+ WM_gizmomap_draw(region->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D);
+ }
if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
const rcti *rect = ED_region_visible_rect(region);
@@ -917,24 +989,16 @@ static void sequencer_buttons_region_listener(const wmRegionListenerParams *para
}
}
-static void sequencer_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void sequencer_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceSeq *sseq = (SpaceSeq *)slink;
-
- if (!ELEM(GS(old_id->name), ID_GD)) {
- return;
- }
-
- if ((ID *)sseq->gpd == old_id) {
- sseq->gpd = (bGPdata *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&sseq->gpd, ID_REMAP_APPLY_DEFAULT);
}
/* ************************************* */
-/* Only called once, from space/spacetypes.c. */
void ED_spacetype_sequencer(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype sequencer");
@@ -965,7 +1029,9 @@ void ED_spacetype_sequencer(void)
art->draw_overlay = sequencer_main_region_draw_overlay;
art->listener = sequencer_main_region_listener;
art->message_subscribe = sequencer_main_region_message_subscribe;
- art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION;
+ /* NOTE: inclusion of #ED_KEYMAP_GIZMO is currently for scripts and isn't used by default. */
+ art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES |
+ ED_KEYMAP_ANIMATION;
BLI_addhead(&st->regiontypes, art);
/* Preview. */
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
index e903feeec1b..f1db8dedf1a 100644
--- a/source/blender/editors/space_spreadsheet/CMakeLists.txt
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -35,26 +35,26 @@ set(INC
set(SRC
space_spreadsheet.cc
+ spreadsheet_cache.cc
spreadsheet_column.cc
spreadsheet_context.cc
spreadsheet_data_source.cc
spreadsheet_data_source_geometry.cc
spreadsheet_dataset_draw.cc
- spreadsheet_dataset_layout.cc
spreadsheet_draw.cc
spreadsheet_layout.cc
spreadsheet_ops.cc
+ spreadsheet_panels.cc
spreadsheet_row_filter.cc
spreadsheet_row_filter_ui.cc
- spreadsheet_cell_value.hh
+ spreadsheet_cache.hh
spreadsheet_column.hh
spreadsheet_column_values.hh
spreadsheet_context.hh
spreadsheet_data_source.hh
spreadsheet_data_source_geometry.hh
spreadsheet_dataset_draw.hh
- spreadsheet_dataset_layout.hh
spreadsheet_draw.hh
spreadsheet_intern.hh
spreadsheet_layout.hh
@@ -65,4 +65,14 @@ set(SRC
set(LIB
)
+if(WITH_OPENVDB)
+ list(APPEND INC_SYS
+ ${OPENVDB_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ ${OPENVDB_LIBRARIES}
+ )
+ add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
+endif()
+
blender_add_lib(bf_editor_space_spreadsheet "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index a82648aeee0..18f383d45fb 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -18,6 +18,7 @@
#include "BLI_listbase.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_screen.h"
@@ -41,6 +42,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "BLT_translation.h"
+
#include "BLF_api.h"
#include "spreadsheet_intern.hh"
@@ -58,15 +61,14 @@ using namespace blender::ed::spreadsheet;
static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
- SpaceSpreadsheet *spreadsheet_space = (SpaceSpreadsheet *)MEM_callocN(sizeof(SpaceSpreadsheet),
- "spreadsheet space");
+ SpaceSpreadsheet *spreadsheet_space = MEM_cnew<SpaceSpreadsheet>("spreadsheet space");
spreadsheet_space->spacetype = SPACE_SPREADSHEET;
spreadsheet_space->filter_flag = SPREADSHEET_FILTER_ENABLE;
{
/* Header. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet header");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet header");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_HEADER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
@@ -74,7 +76,7 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
{
/* Footer. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet footer region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet footer region");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_FOOTER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
@@ -82,16 +84,15 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
{
/* Dataset Region */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet dataset region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet dataset region");
BLI_addtail(&spreadsheet_space->regionbase, region);
- region->regiontype = RGN_TYPE_CHANNELS;
+ region->regiontype = RGN_TYPE_TOOLS;
region->alignment = RGN_ALIGN_LEFT;
- region->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
}
{
/* Properties region. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet right region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet right region");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_UI;
region->alignment = RGN_ALIGN_RIGHT;
@@ -100,7 +101,7 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
{
/* Main window. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet main region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet main region");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
}
@@ -112,7 +113,7 @@ static void spreadsheet_free(SpaceLink *sl)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
- MEM_SAFE_FREE(sspreadsheet->runtime);
+ MEM_delete(sspreadsheet->runtime);
LISTBASE_FOREACH_MUTABLE (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) {
spreadsheet_row_filter_free(row_filter);
@@ -129,8 +130,7 @@ static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)area->spacedata.first;
if (sspreadsheet->runtime == nullptr) {
- sspreadsheet->runtime = (SpaceSpreadsheet_Runtime *)MEM_callocN(
- sizeof(SpaceSpreadsheet_Runtime), __func__);
+ sspreadsheet->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__);
}
}
@@ -138,7 +138,13 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
{
const SpaceSpreadsheet *sspreadsheet_old = (SpaceSpreadsheet *)sl;
SpaceSpreadsheet *sspreadsheet_new = (SpaceSpreadsheet *)MEM_dupallocN(sspreadsheet_old);
- sspreadsheet_new->runtime = (SpaceSpreadsheet_Runtime *)MEM_dupallocN(sspreadsheet_old->runtime);
+ if (sspreadsheet_old->runtime) {
+ sspreadsheet_new->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__,
+ *sspreadsheet_old->runtime);
+ }
+ else {
+ sspreadsheet_new->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__);
+ }
BLI_listbase_clear(&sspreadsheet_new->row_filters);
LISTBASE_FOREACH (const SpreadsheetRowFilter *, src_filter, &sspreadsheet_old->row_filters) {
@@ -166,21 +172,23 @@ static void spreadsheet_keymap(wmKeyConfig *keyconf)
WM_keymap_ensure(keyconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0);
}
-static void spreadsheet_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void spreadsheet_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const IDRemapper *mappings)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)slink;
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
- if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
- SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
- if ((ID *)object_context->object == old_id) {
- if (new_id && GS(new_id->name) == ID_OB) {
- object_context->object = (Object *)new_id;
- }
- else {
- object_context->object = nullptr;
- }
- }
+ if (context->type != SPREADSHEET_CONTEXT_OBJECT) {
+ continue;
+ }
+ SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
+
+ if (object_context->object != nullptr && GS(object_context->object->id.name) != ID_OB) {
+ object_context->object = nullptr;
+ continue;
}
+
+ BKE_id_remapper_apply(mappings, ((ID **)&object_context->object), ID_REMAP_APPLY_DEFAULT);
}
}
@@ -294,16 +302,43 @@ static std::unique_ptr<DataSource> get_data_source(const bContext *C)
return {};
}
-static float get_column_width(const ColumnValues &values)
+static float get_default_column_width(const ColumnValues &values)
{
- if (values.default_width > 0) {
+ if (values.default_width > 0.0f) {
return values.default_width;
}
+ static const float float_width = 3;
+ switch (values.type()) {
+ case SPREADSHEET_VALUE_TYPE_BOOL:
+ return 2.0f;
+ case SPREADSHEET_VALUE_TYPE_INT32:
+ return float_width;
+ case SPREADSHEET_VALUE_TYPE_FLOAT:
+ return float_width;
+ case SPREADSHEET_VALUE_TYPE_FLOAT2:
+ return 2.0f * float_width;
+ case SPREADSHEET_VALUE_TYPE_FLOAT3:
+ return 3.0f * float_width;
+ case SPREADSHEET_VALUE_TYPE_COLOR:
+ return 4.0f * float_width;
+ case SPREADSHEET_VALUE_TYPE_INSTANCES:
+ return 8.0f;
+ case SPREADSHEET_VALUE_TYPE_STRING:
+ return 5.0f;
+ case SPREADSHEET_VALUE_TYPE_UNKNOWN:
+ return 2.0f;
+ }
+ return float_width;
+}
+
+static float get_column_width(const ColumnValues &values)
+{
+ float data_width = get_default_column_width(values);
const int fontid = UI_style_get()->widget.uifont_id;
BLF_size(fontid, UI_DEFAULT_TEXT_POINTS, U.dpi);
const StringRefNull name = values.name();
const float name_width = BLF_width(fontid, name.data(), name.size());
- return std::max<float>(name_width / UI_UNIT_X + 1.0f, 3.0f);
+ return std::max<float>(name_width / UI_UNIT_X + 1.0f, data_width);
}
static float get_column_width_in_pixels(const ColumnValues &values)
@@ -339,21 +374,28 @@ static void update_visible_columns(ListBase &columns, DataSource &data_source)
}
}
- data_source.foreach_default_column_ids([&](const SpreadsheetColumnID &column_id) {
- std::unique_ptr<ColumnValues> values = data_source.get_column_values(column_id);
- if (values) {
- if (used_ids.add(column_id)) {
- SpreadsheetColumnID *new_id = spreadsheet_column_id_copy(&column_id);
- SpreadsheetColumn *new_column = spreadsheet_column_new(new_id);
- BLI_addtail(&columns, new_column);
- }
- }
- });
+ data_source.foreach_default_column_ids(
+ [&](const SpreadsheetColumnID &column_id, const bool is_extra) {
+ std::unique_ptr<ColumnValues> values = data_source.get_column_values(column_id);
+ if (values) {
+ if (used_ids.add(column_id)) {
+ SpreadsheetColumnID *new_id = spreadsheet_column_id_copy(&column_id);
+ SpreadsheetColumn *new_column = spreadsheet_column_new(new_id);
+ if (is_extra) {
+ BLI_addhead(&columns, new_column);
+ }
+ else {
+ BLI_addtail(&columns, new_column);
+ }
+ }
+ }
+ });
}
static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ sspreadsheet->runtime->cache.set_all_unused();
spreadsheet_update_context_path(C);
std::unique_ptr<DataSource> data_source = get_data_source(C);
@@ -394,6 +436,9 @@ static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
ED_region_tag_redraw(footer);
ARegion *sidebar = BKE_area_find_region_type(CTX_wm_area(C), RGN_TYPE_UI);
ED_region_tag_redraw(sidebar);
+
+ /* Free all cache items that have not been used. */
+ sspreadsheet->runtime->cache.remove_all_unused();
}
static void spreadsheet_main_region_listener(const wmRegionListenerParams *params)
@@ -552,35 +597,10 @@ static void spreadsheet_dataset_region_listener(const wmRegionListenerParams *pa
spreadsheet_header_region_listener(params);
}
-static void spreadsheet_dataset_region_init(wmWindowManager *wm, ARegion *region)
-{
- region->v2d.scroll |= V2D_SCROLL_RIGHT;
- region->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP | V2D_SCROLL_BOTTOM);
- region->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
- region->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE;
-
- UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
-
- wmKeyMap *keymap = WM_keymap_ensure(
- wm->defaultconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0);
- WM_event_add_keymap_handler(&region->handlers, keymap);
-}
-
static void spreadsheet_dataset_region_draw(const bContext *C, ARegion *region)
{
spreadsheet_update_context_path(C);
-
- View2D *v2d = &region->v2d;
- UI_view2d_view_ortho(v2d);
- UI_ThemeClearColor(TH_BACK);
-
- draw_dataset_in_region(C, region);
-
- /* reset view matrix */
- UI_view2d_view_restore(C);
-
- /* scrollers */
- UI_view2d_scrollers_draw(v2d, nullptr);
+ ED_region_panels(C, region);
}
static void spreadsheet_sidebar_init(wmWindowManager *wm, ARegion *region)
@@ -601,9 +621,9 @@ static void spreadsheet_right_region_listener(const wmRegionListenerParams *UNUS
{
}
-void ED_spacetype_spreadsheet(void)
+void ED_spacetype_spreadsheet()
{
- SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet");
+ SpaceType *st = MEM_cnew<SpaceType>("spacetype spreadsheet");
ARegionType *art;
st->spaceid = SPACE_SPREADSHEET;
@@ -618,7 +638,7 @@ void ED_spacetype_spreadsheet(void)
st->id_remap = spreadsheet_id_remap;
/* regions: main window */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet region");
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
@@ -628,7 +648,7 @@ void ED_spacetype_spreadsheet(void)
BLI_addhead(&st->regiontypes, art);
/* regions: header */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet header region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet header region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = 0;
@@ -641,7 +661,7 @@ void ED_spacetype_spreadsheet(void)
BLI_addhead(&st->regiontypes, art);
/* regions: footer */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet footer region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet footer region");
art->regionid = RGN_TYPE_FOOTER;
art->prefsizey = HEADERY;
art->keymapflag = 0;
@@ -654,7 +674,7 @@ void ED_spacetype_spreadsheet(void)
BLI_addhead(&st->regiontypes, art);
/* regions: right panel buttons */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet right region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet right region");
art->regionid = RGN_TYPE_UI;
art->prefsizex = UI_SIDEBAR_PANEL_WIDTH;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
@@ -669,13 +689,14 @@ void ED_spacetype_spreadsheet(void)
register_row_filter_panels(*art);
/* regions: channels */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spreadsheet dataset region");
- art->regionid = RGN_TYPE_CHANNELS;
- art->prefsizex = 200 + V2D_SCROLL_WIDTH;
- art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
- art->init = spreadsheet_dataset_region_init;
+ art = MEM_cnew<ARegionType>("spreadsheet dataset region");
+ art->regionid = RGN_TYPE_TOOLS;
+ art->prefsizex = 150 + V2D_SCROLL_WIDTH;
+ art->keymapflag = ED_KEYMAP_UI;
+ art->init = ED_region_panels_init;
art->draw = spreadsheet_dataset_region_draw;
art->listener = spreadsheet_dataset_region_listener;
+ blender::ed::spreadsheet::spreadsheet_data_set_region_panels_register(*art);
BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cache.cc b/source/blender/editors/space_spreadsheet/spreadsheet_cache.cc
new file mode 100644
index 00000000000..2a399e018b6
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_cache.cc
@@ -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.
+ */
+
+#include "spreadsheet_cache.hh"
+
+namespace blender::ed::spreadsheet {
+
+void SpreadsheetCache::add(std::unique_ptr<Key> key, std::unique_ptr<Value> value)
+{
+ key->is_used = true;
+ cache_map_.add_overwrite(*key, std::move(value));
+ keys_.append(std::move(key));
+}
+
+SpreadsheetCache::Value *SpreadsheetCache::lookup(const Key &key)
+{
+ std::unique_ptr<Value> *value = cache_map_.lookup_ptr(key);
+ if (value == nullptr) {
+ return nullptr;
+ }
+ const Key &stored_cache_key = cache_map_.lookup_key(key);
+ stored_cache_key.is_used = true;
+ return value->get();
+}
+
+SpreadsheetCache::Value &SpreadsheetCache::lookup_or_add(
+ std::unique_ptr<Key> key, FunctionRef<std::unique_ptr<Value>()> create_value)
+{
+ Value *value = this->lookup(*key);
+ if (value != nullptr) {
+ return *value;
+ }
+ std::unique_ptr<Value> new_value = create_value();
+ value = new_value.get();
+ this->add(std::move(key), std::move(new_value));
+ return *value;
+}
+
+void SpreadsheetCache::set_all_unused()
+{
+ for (std::unique_ptr<Key> &key : keys_) {
+ key->is_used = false;
+ }
+}
+
+void SpreadsheetCache::remove_all_unused()
+{
+ /* First remove the keys from the map and free the values. */
+ for (auto it = cache_map_.keys().begin(); it != cache_map_.keys().end(); ++it) {
+ const Key &key = *it;
+ if (!key.is_used) {
+ cache_map_.remove(it);
+ }
+ }
+ /* Then free the keys. */
+ for (int i = 0; i < keys_.size();) {
+ if (keys_[i]->is_used) {
+ i++;
+ }
+ else {
+ keys_.remove_and_reorder(i);
+ }
+ }
+}
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cache.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cache.hh
new file mode 100644
index 00000000000..d370bdab5c1
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_cache.hh
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <atomic>
+
+#include "BLI_function_ref.hh"
+#include "BLI_map.hh"
+#include "BLI_vector.hh"
+
+namespace blender::ed::spreadsheet {
+
+/**
+ * A generic cache for the spreadsheet. Different data sources can cache custom data using custom
+ * keys.
+ *
+ * Elements are removed from the cache when they are not used during a redraw.
+ */
+class SpreadsheetCache {
+ public:
+ class Key {
+ public:
+ virtual ~Key() = default;
+
+ mutable bool is_used = false;
+
+ virtual uint64_t hash() const = 0;
+
+ friend bool operator==(const Key &a, const Key &b)
+ {
+ return a.is_equal_to(b);
+ }
+
+ private:
+ virtual bool is_equal_to(const Key &other) const = 0;
+ };
+
+ class Value {
+ public:
+ virtual ~Value() = default;
+ };
+
+ private:
+ Vector<std::unique_ptr<Key>> keys_;
+ Map<std::reference_wrapper<const Key>, std::unique_ptr<Value>> cache_map_;
+
+ public:
+ /* Adding or looking up a key tags it as being used, so that it won't be removed. */
+ void add(std::unique_ptr<Key> key, std::unique_ptr<Value> value);
+ Value *lookup(const Key &key);
+ Value &lookup_or_add(std::unique_ptr<Key> key,
+ FunctionRef<std::unique_ptr<Value>()> create_value);
+
+ void set_all_unused();
+ void remove_all_unused();
+
+ template<typename T> T &lookup_or_add(std::unique_ptr<Key> key)
+ {
+ return dynamic_cast<T &>(
+ this->lookup_or_add(std::move(key), []() { return std::make_unique<T>(); }));
+ }
+};
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
deleted file mode 100644
index 97170693cb3..00000000000
--- a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
+++ /dev/null
@@ -1,63 +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.
- */
-
-#pragma once
-
-#include <optional>
-
-#include "BLI_color.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
-
-struct Collection;
-struct Object;
-
-namespace blender::ed::spreadsheet {
-
-struct ObjectCellValue {
- const Object *object;
-};
-
-struct CollectionCellValue {
- const Collection *collection;
-};
-
-struct GeometrySetCellValue {
- const GeometrySet *geometry_set;
-};
-
-/**
- * This is a type that can hold the value of a cell in a spreadsheet. This type allows us to
- * decouple the drawing of individual cells from the code that generates the data to be displayed.
- */
-class CellValue {
- public:
- /* The implementation just uses a bunch of `std::option` for now. Unfortunately, we cannot use
- * `std::variant` yet, due to missing compiler support. This type can really be optimized more,
- * but it does not really matter too much currently. */
-
- std::optional<int> value_int;
- std::optional<float> value_float;
- std::optional<bool> value_bool;
- std::optional<float2> value_float2;
- std::optional<float3> value_float3;
- std::optional<ColorGeometry4f> value_color;
- std::optional<ObjectCellValue> value_object;
- std::optional<CollectionCellValue> value_collection;
- std::optional<GeometrySetCellValue> value_geometry_set;
-};
-
-} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
index ee08c86b29f..ede8756a9da 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -18,18 +18,54 @@
#include "MEM_guardedalloc.h"
+#include "BLI_color.hh"
#include "BLI_hash.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
+#include "BKE_geometry_set.hh"
+
+#include "FN_cpp_type.hh"
+
#include "spreadsheet_column.hh"
+#include "spreadsheet_column_values.hh"
namespace blender::ed::spreadsheet {
+eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type)
+{
+ if (type.is<bool>()) {
+ return SPREADSHEET_VALUE_TYPE_BOOL;
+ }
+ if (type.is<int>()) {
+ return SPREADSHEET_VALUE_TYPE_INT32;
+ }
+ if (type.is<float>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT;
+ }
+ if (type.is<float2>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT2;
+ }
+ if (type.is<float3>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT3;
+ }
+ if (type.is<ColorGeometry4f>()) {
+ return SPREADSHEET_VALUE_TYPE_COLOR;
+ }
+ if (type.is<std::string>()) {
+ return SPREADSHEET_VALUE_TYPE_STRING;
+ }
+ if (type.is<InstanceReference>()) {
+ return SPREADSHEET_VALUE_TYPE_INSTANCES;
+ }
+
+ return SPREADSHEET_VALUE_TYPE_UNKNOWN;
+}
+
SpreadsheetColumnID *spreadsheet_column_id_new()
{
- SpreadsheetColumnID *column_id = (SpreadsheetColumnID *)MEM_callocN(sizeof(SpreadsheetColumnID),
- __func__);
+ SpreadsheetColumnID *column_id = MEM_cnew<SpreadsheetColumnID>(__func__);
return column_id;
}
@@ -50,8 +86,7 @@ void spreadsheet_column_id_free(SpreadsheetColumnID *column_id)
SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id)
{
- SpreadsheetColumn *column = (SpreadsheetColumn *)MEM_callocN(sizeof(SpreadsheetColumn),
- __func__);
+ SpreadsheetColumn *column = MEM_cnew<SpreadsheetColumn>(__func__);
column->id = column_id;
return column;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column.hh
index 1a03278acad..7dad505c21b 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.hh
@@ -44,7 +44,7 @@ void spreadsheet_column_id_free(SpreadsheetColumnID *column_id);
SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id);
SpreadsheetColumn *spreadsheet_column_copy(const SpreadsheetColumn *src_column);
void spreadsheet_column_assign_runtime_data(SpreadsheetColumn *column,
- const eSpreadsheetColumnValueType data_type,
+ eSpreadsheetColumnValueType data_type,
const StringRefNull display_name);
void spreadsheet_column_free(SpreadsheetColumn *column);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
index 68370cf6a44..83e3217e5c8 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
@@ -20,33 +20,36 @@
#include "BLI_string_ref.hh"
-#include "spreadsheet_cell_value.hh"
+#include "FN_generic_virtual_array.hh"
namespace blender::ed::spreadsheet {
+struct CellDrawParams;
+
+eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type);
+
/**
* This represents a column in a spreadsheet. It has a name and provides a value for all the cells
* in the column.
*/
-class ColumnValues {
+class ColumnValues final {
protected:
- eSpreadsheetColumnValueType type_;
std::string name_;
- int size_;
+
+ fn::GVArray data_;
public:
- ColumnValues(const eSpreadsheetColumnValueType type, std::string name, const int size)
- : type_(type), name_(std::move(name)), size_(size)
+ ColumnValues(std::string name, fn::GVArray data) : name_(std::move(name)), data_(std::move(data))
{
+ /* The array should not be empty. */
+ BLI_assert(data_);
}
virtual ~ColumnValues() = default;
- virtual void get_value(int index, CellValue &r_cell_value) const = 0;
-
eSpreadsheetColumnValueType type() const
{
- return type_;
+ return cpp_type_to_column_type(data_.type());
}
StringRefNull name() const
@@ -56,50 +59,16 @@ class ColumnValues {
int size() const
{
- return size_;
+ return data_.size();
}
- /* The default width of newly created columns, in UI units. */
- float default_width = 0.0f;
-};
-
-/* Utility class for the function below. */
-template<typename GetValueF> class LambdaColumnValues : public ColumnValues {
- private:
- GetValueF get_value_;
-
- public:
- LambdaColumnValues(const eSpreadsheetColumnValueType type,
- std::string name,
- int size,
- GetValueF get_value)
- : ColumnValues(type, std::move(name), size), get_value_(std::move(get_value))
+ const fn::GVArray &data() const
{
+ return data_;
}
- void get_value(int index, CellValue &r_cell_value) const final
- {
- get_value_(index, r_cell_value);
- }
+ /* The default width of newly created columns, in UI units. */
+ float default_width = 0.0f;
};
-/* Utility function that simplifies creating a spreadsheet column from a lambda function. */
-template<typename GetValueF>
-std::unique_ptr<ColumnValues> column_values_from_function(const eSpreadsheetColumnValueType type,
- std::string name,
- const int size,
- GetValueF get_value,
- const float default_width = 0.0f)
-{
- std::unique_ptr<ColumnValues> column_values = std::make_unique<LambdaColumnValues<GetValueF>>(
- type, std::move(name), size, std::move(get_value));
- column_values->default_width = default_width;
- return column_values;
-}
-
-static constexpr float default_float_column_width = 3;
-static constexpr float default_float2_column_width = 2 * default_float_column_width;
-static constexpr float default_float3_column_width = 3 * default_float_column_width;
-static constexpr float default_color_column_width = 4 * default_float_column_width;
-
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
index c38e765caee..5cec016b727 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
@@ -50,8 +50,7 @@ namespace blender::ed::spreadsheet {
static SpreadsheetContextObject *spreadsheet_context_object_new()
{
- SpreadsheetContextObject *context = (SpreadsheetContextObject *)MEM_callocN(
- sizeof(SpreadsheetContextObject), __func__);
+ SpreadsheetContextObject *context = MEM_cnew<SpreadsheetContextObject>(__func__);
context->base.type = SPREADSHEET_CONTEXT_OBJECT;
return context;
}
@@ -77,8 +76,7 @@ static void spreadsheet_context_object_free(SpreadsheetContextObject *context)
static SpreadsheetContextModifier *spreadsheet_context_modifier_new()
{
- SpreadsheetContextModifier *context = (SpreadsheetContextModifier *)MEM_callocN(
- sizeof(SpreadsheetContextModifier), __func__);
+ SpreadsheetContextModifier *context = MEM_cnew<SpreadsheetContextModifier>(__func__);
context->base.type = SPREADSHEET_CONTEXT_MODIFIER;
return context;
}
@@ -111,8 +109,7 @@ static void spreadsheet_context_modifier_free(SpreadsheetContextModifier *contex
static SpreadsheetContextNode *spreadsheet_context_node_new()
{
- SpreadsheetContextNode *context = (SpreadsheetContextNode *)MEM_callocN(
- sizeof(SpreadsheetContextNode), __func__);
+ SpreadsheetContextNode *context = MEM_cnew<SpreadsheetContextNode>(__func__);
context->base.type = SPREADSHEET_CONTEXT_NODE;
return context;
}
@@ -373,6 +370,21 @@ void ED_spreadsheet_context_path_set_evaluated_object(SpaceSpreadsheet *sspreads
BLI_addtail(&sspreadsheet->context_path, context);
}
+static bScreen *find_screen_to_search_for_context(wmWindow *window,
+ SpaceSpreadsheet *current_space)
+{
+ bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ if (ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL)) {
+ /* If the spreadsheet is maximized, try to find the context in the unmaximized screen. */
+ ScrArea *main_area = (ScrArea *)screen->areabase.first;
+ SpaceLink *sl = (SpaceLink *)main_area->spacedata.first;
+ if (sl == (SpaceLink *)current_space) {
+ return main_area->full;
+ }
+ }
+ return screen;
+}
+
void ED_spreadsheet_context_path_guess(const bContext *C, SpaceSpreadsheet *sspreadsheet)
{
ED_spreadsheet_context_path_clear(sspreadsheet);
@@ -385,9 +397,12 @@ void ED_spreadsheet_context_path_guess(const bContext *C, SpaceSpreadsheet *sspr
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) {
LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
- bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ bScreen *screen = find_screen_to_search_for_context(window, sspreadsheet);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
SpaceLink *sl = (SpaceLink *)area->spacedata.first;
+ if (sl == nullptr) {
+ continue;
+ }
if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode = (SpaceNode *)sl;
if (snode->edittree != nullptr) {
@@ -466,9 +481,12 @@ bool ED_spreadsheet_context_path_is_active(const bContext *C, SpaceSpreadsheet *
}
LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
- bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ bScreen *screen = find_screen_to_search_for_context(window, sspreadsheet);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
SpaceLink *sl = (SpaceLink *)area->spacedata.first;
+ if (sl == nullptr) {
+ continue;
+ }
if (sl->spacetype != SPACE_NODE) {
continue;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
index 2ea7fb5809f..873735c81e5 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
@@ -36,8 +36,12 @@ class DataSource {
* Calls the callback with all the column ids that should be displayed as long as the user does
* not manually add or remove columns. The column id can be stack allocated. Therefore, the
* callback should not keep a reference to it (and copy it instead).
+ *
+ * The `is_extra` argument indicates that this column is special and should be drawn as the first
+ * column. (This can be made a bit more generic in the future when necessary.)
*/
- virtual void foreach_default_column_ids(FunctionRef<void(const SpreadsheetColumnID &)> fn) const
+ virtual void foreach_default_column_ids(
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
UNUSED_VARS(fn);
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index 78d9f61d8d5..b9b03732a40 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -14,12 +14,16 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BLI_virtual_array.hh"
+
#include "BKE_context.h"
#include "BKE_editmesh.h"
+#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
+#include "BKE_volume.h"
#include "DNA_ID.h"
#include "DNA_mesh_types.h"
@@ -33,18 +37,55 @@
#include "NOD_geometry_nodes_eval_log.hh"
+#include "BLT_translation.h"
+
+#include "RNA_access.h"
+#include "RNA_enum_types.h"
+
+#include "FN_field_cpp_type.hh"
+
#include "bmesh.h"
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_intern.hh"
namespace geo_log = blender::nodes::geometry_nodes_eval_log;
+using blender::fn::GField;
namespace blender::ed::spreadsheet {
+void ExtraColumns::foreach_default_column_ids(
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
+{
+ for (const auto item : columns_.items()) {
+ SpreadsheetColumnID column_id;
+ column_id.name = (char *)item.key.c_str();
+ fn(column_id, true);
+ }
+}
+
+std::unique_ptr<ColumnValues> ExtraColumns::get_column_values(
+ const SpreadsheetColumnID &column_id) const
+{
+ const fn::GSpan *values = columns_.lookup_ptr(column_id.name);
+ if (values == nullptr) {
+ return {};
+ }
+ return std::make_unique<ColumnValues>(column_id.name, fn::GVArray::ForSpan(*values));
+}
+
void GeometryDataSource::foreach_default_column_ids(
- FunctionRef<void(const SpreadsheetColumnID &)> fn) const
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
+ if (component_->attribute_domain_size(domain_) == 0) {
+ return;
+ }
+
+ if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) {
+ fn({(char *)"Name"}, false);
+ }
+
+ extra_columns_.foreach_default_column_ids(fn);
component_->attribute_foreach(
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
if (meta_data.domain != domain_) {
@@ -55,183 +96,134 @@ void GeometryDataSource::foreach_default_column_ids(
}
SpreadsheetColumnID column_id;
column_id.name = (char *)attribute_id.name().data();
- fn(column_id);
+ fn(column_id, false);
return true;
});
-}
-
-std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
- const SpreadsheetColumnID &column_id) const
-{
- std::lock_guard lock{mutex_};
- bke::ReadAttributeLookup attribute = component_->attribute_try_get_for_read(column_id.name);
- if (!attribute) {
- return {};
+ if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) {
+ fn({(char *)"Rotation"}, false);
+ fn({(char *)"Scale"}, false);
}
- const fn::GVArray *varray = scope_.add(std::move(attribute.varray));
- if (attribute.domain != domain_) {
- return {};
- }
- int domain_size = varray->size();
- const CustomDataType type = bke::cpp_type_to_custom_data_type(varray->type());
- switch (type) {
- case CD_PROP_FLOAT:
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- float value;
- varray->get(index, &value);
- r_cell_value.value_float = value;
- });
- case CD_PROP_INT32:
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_INT32,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- int value;
- varray->get(index, &value);
- r_cell_value.value_int = value;
- });
- case CD_PROP_BOOL:
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_BOOL,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- bool value;
- varray->get(index, &value);
- r_cell_value.value_bool = value;
- });
- case CD_PROP_FLOAT2: {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_FLOAT2,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- float2 value;
- varray->get(index, &value);
- r_cell_value.value_float2 = value;
- },
- default_float2_column_width);
+ else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) {
+ if (domain_ == ATTR_DOMAIN_EDGE) {
+ fn({(char *)"Vertex 1"}, false);
+ fn({(char *)"Vertex 2"}, false);
}
- case CD_PROP_FLOAT3: {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- float3 value;
- varray->get(index, &value);
- r_cell_value.value_float3 = value;
- },
- default_float3_column_width);
+ else if (domain_ == ATTR_DOMAIN_FACE) {
+ fn({(char *)"Corner Start"}, false);
+ fn({(char *)"Corner Size"}, false);
}
- case CD_PROP_COLOR: {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_COLOR,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- ColorGeometry4f value;
- varray->get(index, &value);
- r_cell_value.value_color = value;
- },
- default_color_column_width);
+ else if (domain_ == ATTR_DOMAIN_CORNER) {
+ fn({(char *)"Vertex"}, false);
+ fn({(char *)"Edge"}, false);
}
- default:
- break;
}
- return {};
}
-int GeometryDataSource::tot_rows() const
+std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
+ const SpreadsheetColumnID &column_id) const
{
- return component_->attribute_domain_size(domain_);
-}
+ const int domain_size = component_->attribute_domain_size(domain_);
+ if (domain_size == 0) {
+ return {};
+ }
-using IsVertexSelectedFn = FunctionRef<bool(int vertex_index)>;
+ std::lock_guard lock{mutex_};
-static void get_selected_vertex_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int i : IndexRange(mesh.totvert)) {
- if (!selection[i]) {
- continue;
- }
- if (!is_vertex_selected_fn(i)) {
- selection[i] = false;
- }
+ std::unique_ptr<ColumnValues> extra_column_values = extra_columns_.get_column_values(column_id);
+ if (extra_column_values) {
+ return extra_column_values;
}
-}
-static void get_selected_corner_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int i : IndexRange(mesh.totloop)) {
- const MLoop &loop = mesh.mloop[i];
- if (!selection[i]) {
- continue;
+ if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) {
+ const InstancesComponent &instances = static_cast<const InstancesComponent &>(*component_);
+ if (STREQ(column_id.name, "Name")) {
+ Span<int> reference_handles = instances.instance_reference_handles();
+ Span<InstanceReference> references = instances.references();
+ return std::make_unique<ColumnValues>(
+ column_id.name,
+ VArray<InstanceReference>::ForFunc(domain_size,
+ [reference_handles, references](int64_t index) {
+ return references[reference_handles[index]];
+ }));
}
- if (!is_vertex_selected_fn(loop.v)) {
- selection[i] = false;
+ Span<float4x4> transforms = instances.instance_transforms();
+ if (STREQ(column_id.name, "Rotation")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<float3>::ForFunc(domain_size, [transforms](int64_t index) {
+ return transforms[index].to_euler();
+ }));
}
- }
-}
-
-static void get_selected_face_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- if (!selection[poly_index]) {
- continue;
+ if (STREQ(column_id.name, "Scale")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<float3>::ForFunc(domain_size, [transforms](int64_t index) {
+ return transforms[index].scale();
+ }));
}
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = mesh.mloop[loop_index];
- if (!is_vertex_selected_fn(loop.v)) {
- selection[poly_index] = false;
- break;
+ }
+ else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &component = static_cast<const MeshComponent &>(*component_);
+ if (const Mesh *mesh = component.get_for_read()) {
+ if (domain_ == ATTR_DOMAIN_EDGE) {
+ if (STREQ(column_id.name, "Vertex 1")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totedge, [mesh](int64_t index) {
+ return mesh->medge[index].v1;
+ }));
+ }
+ if (STREQ(column_id.name, "Vertex 2")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totedge, [mesh](int64_t index) {
+ return mesh->medge[index].v2;
+ }));
+ }
+ }
+ else if (domain_ == ATTR_DOMAIN_FACE) {
+ if (STREQ(column_id.name, "Corner Start")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totpoly, [mesh](int64_t index) {
+ return mesh->mpoly[index].loopstart;
+ }));
+ }
+ if (STREQ(column_id.name, "Corner Size")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totpoly, [mesh](int64_t index) {
+ return mesh->mpoly[index].totloop;
+ }));
+ }
+ }
+ else if (domain_ == ATTR_DOMAIN_CORNER) {
+ if (STREQ(column_id.name, "Vertex")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totloop, [mesh](int64_t index) {
+ return mesh->mloop[index].v;
+ }));
+ }
+ if (STREQ(column_id.name, "Edge")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totloop, [mesh](int64_t index) {
+ return mesh->mloop[index].e;
+ }));
+ }
}
}
}
-}
-static void get_selected_edge_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int i : IndexRange(mesh.totedge)) {
- if (!selection[i]) {
- continue;
- }
- const MEdge &edge = mesh.medge[i];
- if (!is_vertex_selected_fn(edge.v1) || !is_vertex_selected_fn(edge.v2)) {
- selection[i] = false;
- }
+ bke::ReadAttributeLookup attribute = component_->attribute_try_get_for_read(column_id.name);
+ if (!attribute) {
+ return {};
+ }
+ fn::GVArray varray = std::move(attribute.varray);
+ if (attribute.domain != domain_) {
+ return {};
}
+
+ return std::make_unique<ColumnValues>(column_id.name, std::move(varray));
}
-static void get_selected_indices_on_domain(const Mesh &mesh,
- const AttributeDomain domain,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
+int GeometryDataSource::tot_rows() const
{
- switch (domain) {
- case ATTR_DOMAIN_POINT:
- return get_selected_vertex_indices(mesh, is_vertex_selected_fn, selection);
- case ATTR_DOMAIN_FACE:
- return get_selected_face_indices(mesh, is_vertex_selected_fn, selection);
- case ATTR_DOMAIN_CORNER:
- return get_selected_corner_indices(mesh, is_vertex_selected_fn, selection);
- case ATTR_DOMAIN_EDGE:
- return get_selected_edge_indices(mesh, is_vertex_selected_fn, selection);
- default:
- return;
- }
+ return component_->attribute_domain_size(domain_);
}
/**
@@ -253,7 +245,18 @@ bool GeometryDataSource::has_selection_filter() const
return true;
}
-void GeometryDataSource::apply_selection_filter(MutableSpan<bool> rows_included) const
+static IndexMask index_mask_from_bool_array(const VArray<bool> &selection,
+ Vector<int64_t> &indices)
+{
+ for (const int i : selection.index_range()) {
+ if (selection[i]) {
+ indices.append(i);
+ }
+ }
+ return IndexMask(indices);
+}
+
+IndexMask GeometryDataSource::apply_selection_filter(Vector<int64_t> &indices) const
{
std::lock_guard lock{mutex_};
@@ -269,138 +272,113 @@ void GeometryDataSource::apply_selection_filter(MutableSpan<bool> rows_included)
int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
if (orig_indices != nullptr) {
/* Use CD_ORIGINDEX layer if it exists. */
- auto is_vertex_selected = [&](int vertex_index) -> bool {
- const int i_orig = orig_indices[vertex_index];
- if (i_orig < 0) {
- return false;
- }
- if (i_orig >= bm->totvert) {
- return false;
- }
- BMVert *vert = bm->vtable[i_orig];
- return BM_elem_flag_test(vert, BM_ELEM_SELECT);
- };
- get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included);
+ VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
+ VArray<bool>::ForFunc(mesh_eval->totvert,
+ [bm, orig_indices](int vertex_index) -> bool {
+ const int i_orig = orig_indices[vertex_index];
+ if (i_orig < 0) {
+ return false;
+ }
+ if (i_orig >= bm->totvert) {
+ return false;
+ }
+ BMVert *vert = bm->vtable[i_orig];
+ return BM_elem_flag_test(vert, BM_ELEM_SELECT);
+ }),
+ ATTR_DOMAIN_POINT,
+ domain_);
+ return index_mask_from_bool_array(selection, indices);
}
- else if (mesh_eval->totvert == bm->totvert) {
+
+ if (mesh_eval->totvert == bm->totvert) {
/* Use a simple heuristic to match original vertices to evaluated ones. */
- auto is_vertex_selected = [&](int vertex_index) -> bool {
- BMVert *vert = bm->vtable[vertex_index];
- return BM_elem_flag_test(vert, BM_ELEM_SELECT);
- };
- get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included);
+ VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
+ VArray<bool>::ForFunc(mesh_eval->totvert,
+ [bm](int vertex_index) -> bool {
+ BMVert *vert = bm->vtable[vertex_index];
+ return BM_elem_flag_test(vert, BM_ELEM_SELECT);
+ }),
+ ATTR_DOMAIN_POINT,
+ domain_);
+ return index_mask_from_bool_array(selection, indices);
}
+
+ return IndexMask(mesh_eval->totvert);
}
-void InstancesDataSource::foreach_default_column_ids(
- FunctionRef<void(const SpreadsheetColumnID &)> fn) const
+void VolumeDataSource::foreach_default_column_ids(
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
- if (component_->instances_amount() == 0) {
+ if (component_->is_empty()) {
return;
}
- SpreadsheetColumnID column_id;
- column_id.name = (char *)"Name";
- fn(column_id);
- for (const char *name : {"Position", "Rotation", "Scale", "ID"}) {
- column_id.name = (char *)name;
- fn(column_id);
+ for (const char *name : {"Grid Name", "Data Type", "Class"}) {
+ SpreadsheetColumnID column_id{(char *)name};
+ fn(column_id, false);
}
}
-std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
+std::unique_ptr<ColumnValues> VolumeDataSource::get_column_values(
const SpreadsheetColumnID &column_id) const
{
- if (component_->instances_amount() == 0) {
+ const Volume *volume = component_->get_for_read();
+ if (volume == nullptr) {
return {};
}
+#ifdef WITH_OPENVDB
const int size = this->tot_rows();
- if (STREQ(column_id.name, "Name")) {
- Span<int> reference_handles = component_->instance_reference_handles();
- Span<InstanceReference> references = component_->references();
- std::unique_ptr<ColumnValues> values = column_values_from_function(
- SPREADSHEET_VALUE_TYPE_INSTANCES,
- "Name",
- size,
- [reference_handles, references](int index, CellValue &r_cell_value) {
- const InstanceReference &reference = references[reference_handles[index]];
- switch (reference.type()) {
- case InstanceReference::Type::Object: {
- Object &object = reference.object();
- r_cell_value.value_object = ObjectCellValue{&object};
- break;
- }
- case InstanceReference::Type::Collection: {
- Collection &collection = reference.collection();
- r_cell_value.value_collection = CollectionCellValue{&collection};
- break;
- }
- case InstanceReference::Type::GeometrySet: {
- const GeometrySet &geometry_set = reference.geometry_set();
- r_cell_value.value_geometry_set = GeometrySetCellValue{&geometry_set};
- break;
- }
- case InstanceReference::Type::None: {
- break;
- }
+ if (STREQ(column_id.name, "Grid Name")) {
+ return std::make_unique<ColumnValues>(
+ IFACE_("Grid Name"), VArray<std::string>::ForFunc(size, [volume](int64_t index) {
+ const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index);
+ return BKE_volume_grid_name(volume_grid);
+ }));
+ }
+ if (STREQ(column_id.name, "Data Type")) {
+ return std::make_unique<ColumnValues>(
+ IFACE_("Data Type"), VArray<std::string>::ForFunc(size, [volume](int64_t index) {
+ const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index);
+ const VolumeGridType type = BKE_volume_grid_type(volume_grid);
+ const char *name = nullptr;
+ RNA_enum_name_from_value(rna_enum_volume_grid_data_type_items, type, &name);
+ return IFACE_(name);
+ }));
+ }
+ if (STREQ(column_id.name, "Class")) {
+ return std::make_unique<ColumnValues>(
+ IFACE_("Class"), VArray<std::string>::ForFunc(size, [volume](int64_t index) {
+ const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index);
+ openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
+ openvdb::GridClass grid_class = grid->getGridClass();
+ if (grid_class == openvdb::GridClass::GRID_FOG_VOLUME) {
+ return IFACE_("Fog Volume");
+ }
+ if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) {
+ return IFACE_("Level Set");
}
- });
- values->default_width = 8.0f;
- return values;
- }
- Span<float4x4> transforms = component_->instance_transforms();
- if (STREQ(column_id.name, "Position")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].translation();
- },
- default_float3_column_width);
- }
- if (STREQ(column_id.name, "Rotation")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].to_euler();
- },
- default_float3_column_width);
- }
- if (STREQ(column_id.name, "Scale")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].scale();
- },
- default_float3_column_width);
- }
- Span<int> ids = component_->instance_ids();
- if (STREQ(column_id.name, "ID")) {
- /* Make the column a bit wider by default, since the IDs tend to be large numbers. */
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_INT32,
- column_id.name,
- size,
- [ids](int index, CellValue &r_cell_value) { r_cell_value.value_int = ids[index]; },
- 5.5f);
+ return IFACE_("Unknown");
+ }));
}
+#else
+ UNUSED_VARS(column_id);
+#endif
+
return {};
}
-int InstancesDataSource::tot_rows() const
+int VolumeDataSource::tot_rows() const
{
- return component_->instances_amount();
+ const Volume *volume = component_->get_for_read();
+ if (volume == nullptr) {
+ return 0;
+ }
+ return BKE_volume_num_grids(volume);
}
GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet,
- Object *object_eval,
- const GeometryComponentType used_component_type)
+ Object *object_eval)
{
GeometrySet geometry_set;
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
@@ -432,7 +410,7 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
}
}
else {
- if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) {
+ if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) {
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false);
if (mesh == nullptr) {
return geometry_set;
@@ -469,6 +447,36 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
return geometry_set;
}
+static void find_fields_to_evaluate(const SpaceSpreadsheet *sspreadsheet,
+ Map<std::string, GField> &r_fields)
+{
+ if (sspreadsheet->object_eval_state != SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) {
+ return;
+ }
+ if (BLI_listbase_count(&sspreadsheet->context_path) <= 1) {
+ /* No viewer is currently referenced by the context path. */
+ return;
+ }
+ const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_spreadsheet_editor_context(
+ *sspreadsheet);
+ if (node_log == nullptr) {
+ return;
+ }
+ for (const geo_log::SocketLog &socket_log : node_log->input_logs()) {
+ const geo_log::ValueLog *value_log = socket_log.value();
+ if (value_log == nullptr) {
+ continue;
+ }
+ if (const geo_log::GFieldValueLog *field_value_log =
+ dynamic_cast<const geo_log::GFieldValueLog *>(value_log)) {
+ const GField &field = field_value_log->field();
+ if (field) {
+ r_fields.add("Viewer", std::move(field));
+ }
+ }
+ }
+}
+
static GeometryComponentType get_display_component_type(const bContext *C, Object *object_eval)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
@@ -481,22 +489,89 @@ static GeometryComponentType get_display_component_type(const bContext *C, Objec
return GEO_COMPONENT_TYPE_MESH;
}
+class GeometryComponentCacheKey : public SpreadsheetCache::Key {
+ public:
+ /* Use the pointer to the geometry component as a key to detect when the geometry changed. */
+ const GeometryComponent *component;
+
+ GeometryComponentCacheKey(const GeometryComponent &component) : component(&component)
+ {
+ }
+
+ uint64_t hash() const override
+ {
+ return get_default_hash(this->component);
+ }
+
+ bool is_equal_to(const Key &other) const override
+ {
+ if (const GeometryComponentCacheKey *other_geo =
+ dynamic_cast<const GeometryComponentCacheKey *>(&other)) {
+ return this->component == other_geo->component;
+ }
+ return false;
+ }
+};
+
+class GeometryComponentCacheValue : public SpreadsheetCache::Value {
+ public:
+ /* Stores the result of fields evaluated on a geometry component. Without this, fields would have
+ * to be reevaluated on every redraw. */
+ Map<std::pair<AttributeDomain, GField>, fn::GArray<>> arrays;
+};
+
+static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
+ const GeometryComponent &component,
+ ExtraColumns &r_extra_columns)
+{
+ Map<std::string, GField> fields_to_show;
+ find_fields_to_evaluate(sspreadsheet, fields_to_show);
+
+ GeometryComponentCacheValue &cache =
+ sspreadsheet->runtime->cache.lookup_or_add<GeometryComponentCacheValue>(
+ std::make_unique<GeometryComponentCacheKey>(component));
+
+ const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain;
+ const int domain_size = component.attribute_domain_size(domain);
+ for (const auto item : fields_to_show.items()) {
+ StringRef name = item.key;
+ const GField &field = item.value;
+
+ /* Use the cached evaluated array if it exists, otherwise evaluate the field now. */
+ fn::GArray<> &evaluated_array = cache.arrays.lookup_or_add_cb({domain, field}, [&]() {
+ fn::GArray<> evaluated_array(field.cpp_type(), domain_size);
+
+ bke::GeometryComponentFieldContext field_context{component, domain};
+ fn::FieldEvaluator field_evaluator{field_context, domain_size};
+ field_evaluator.add_with_destination(field, evaluated_array);
+ field_evaluator.evaluate();
+ return evaluated_array;
+ });
+
+ r_extra_columns.add(std::move(name), evaluated_array.as_span());
+ }
+}
+
std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain;
const GeometryComponentType component_type = get_display_component_type(C, object_eval);
- GeometrySet geometry_set = spreadsheet_get_display_geometry_set(
- sspreadsheet, object_eval, component_type);
+ GeometrySet geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, object_eval);
if (!geometry_set.has(component_type)) {
return {};
}
- if (component_type == GEO_COMPONENT_TYPE_INSTANCES) {
- return std::make_unique<InstancesDataSource>(geometry_set);
+ const GeometryComponent &component = *geometry_set.get_component_for_read(component_type);
+ ExtraColumns extra_columns;
+ add_fields_as_extra_columns(sspreadsheet, component, extra_columns);
+
+ if (component_type == GEO_COMPONENT_TYPE_VOLUME) {
+ return std::make_unique<VolumeDataSource>(geometry_set);
}
- return std::make_unique<GeometryDataSource>(object_eval, geometry_set, component_type, domain);
+ return std::make_unique<GeometryDataSource>(
+ object_eval, geometry_set, component_type, domain, std::move(extra_columns));
}
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
index d1b5dc6845e..b5105050d2b 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
@@ -28,12 +28,34 @@ struct bContext;
namespace blender::ed::spreadsheet {
+/**
+ * Contains additional named columns that should be displayed that are not stored on the geometry
+ * directly. This is used for displaying the evaluated fields connected to a viewer node.
+ */
+class ExtraColumns {
+ private:
+ /** Maps column names to their data. The data is actually stored in the spreadsheet cache. */
+ Map<std::string, fn::GSpan> columns_;
+
+ public:
+ void add(std::string name, fn::GSpan data)
+ {
+ columns_.add(std::move(name), data);
+ }
+
+ void foreach_default_column_ids(
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const;
+
+ std::unique_ptr<ColumnValues> get_column_values(const SpreadsheetColumnID &column_id) const;
+};
+
class GeometryDataSource : public DataSource {
private:
Object *object_eval_;
const GeometrySet geometry_set_;
const GeometryComponent *component_;
AttributeDomain domain_;
+ ExtraColumns extra_columns_;
/* Some data is computed on the fly only when it is requested. Computing it does not change the
* logical state of this data source. Therefore, the corresponding methods are const and need to
@@ -45,11 +67,13 @@ class GeometryDataSource : public DataSource {
GeometryDataSource(Object *object_eval,
GeometrySet geometry_set,
const GeometryComponentType component_type,
- const AttributeDomain domain)
+ const AttributeDomain domain,
+ ExtraColumns extra_columns)
: object_eval_(object_eval),
geometry_set_(std::move(geometry_set)),
component_(geometry_set_.get_component_for_read(component_type)),
- domain_(domain)
+ domain_(domain),
+ extra_columns_(std::move(extra_columns))
{
}
@@ -58,11 +82,15 @@ class GeometryDataSource : public DataSource {
return object_eval_;
}
+ /**
+ * Only data sets corresponding to mesh objects in edit mode currently support selection
+ * filtering.
+ */
bool has_selection_filter() const override;
- void apply_selection_filter(MutableSpan<bool> rows_included) const;
+ IndexMask apply_selection_filter(Vector<int64_t> &indices) const;
void foreach_default_column_ids(
- FunctionRef<void(const SpreadsheetColumnID &)> fn) const override;
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const override;
std::unique_ptr<ColumnValues> get_column_values(
const SpreadsheetColumnID &column_id) const override;
@@ -70,19 +98,19 @@ class GeometryDataSource : public DataSource {
int tot_rows() const override;
};
-class InstancesDataSource : public DataSource {
+class VolumeDataSource : public DataSource {
const GeometrySet geometry_set_;
- const InstancesComponent *component_;
+ const VolumeComponent *component_;
public:
- InstancesDataSource(GeometrySet geometry_set)
+ VolumeDataSource(GeometrySet geometry_set)
: geometry_set_(std::move(geometry_set)),
- component_(geometry_set_.get_component_for_read<InstancesComponent>())
+ component_(geometry_set_.get_component_for_read<VolumeComponent>())
{
}
void foreach_default_column_ids(
- FunctionRef<void(const SpreadsheetColumnID &)> fn) const override;
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const override;
std::unique_ptr<ColumnValues> get_column_values(
const SpreadsheetColumnID &column_id) const override;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
index 2b31ce7d03c..2a81b56d129 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
@@ -14,274 +14,226 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include <array>
-
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
#include "BKE_context.h"
-
-#include "BLF_api.h"
-
-#include "BLI_rect.h"
+#include "BKE_volume.h"
#include "RNA_access.h"
#include "UI_interface.h"
-#include "UI_view2d.h"
+#include "UI_interface.hh"
+#include "UI_tree_view.hh"
#include "WM_types.h"
+#include "BLT_translation.h"
+
#include "spreadsheet_dataset_draw.hh"
#include "spreadsheet_draw.hh"
#include "spreadsheet_intern.hh"
-static int is_component_row_selected(struct uiBut *but, const void *arg)
-{
- SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)arg;
+namespace blender::ed::spreadsheet {
- GeometryComponentType component = (GeometryComponentType)UI_but_datasetrow_component_get(but);
- AttributeDomain domain = (AttributeDomain)UI_but_datasetrow_domain_get(but);
+class GeometryDataSetTreeView;
- const bool is_component_selected = (GeometryComponentType)
- sspreadsheet->geometry_component_type == component;
- const bool is_domain_selected = (AttributeDomain)sspreadsheet->attribute_domain == domain;
- bool is_selected = is_component_selected && is_domain_selected;
+class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem {
+ GeometryComponentType component_type_;
+ std::optional<AttributeDomain> domain_;
+ BIFIconID icon_;
- if (component == GEO_COMPONENT_TYPE_INSTANCES) {
- is_selected = is_component_selected;
- }
+ public:
+ GeometryDataSetTreeViewItem(GeometryComponentType component_type,
+ StringRef label,
+ BIFIconID icon);
+ GeometryDataSetTreeViewItem(GeometryComponentType component_type,
+ AttributeDomain domain,
+ StringRef label,
+ BIFIconID icon);
- return is_selected;
-}
+ void on_activate() override;
-namespace blender::ed::spreadsheet {
+ void build_row(uiLayout &row) override;
-/* -------------------------------------------------------------------- */
-/* Draw Context */
+ protected:
+ std::optional<bool> should_be_active() const override;
+ bool supports_collapsing() const override;
-class DatasetDrawContext {
- std::array<int, 2> mval_;
+ private:
+ GeometryDataSetTreeView &get_tree() const;
+ std::optional<int> count() const;
+};
- public:
- const SpaceSpreadsheet *sspreadsheet;
- Object *object_eval;
- /* Current geometry set, changes per component. */
- GeometrySet current_geometry_set;
+class GeometryDataSetTreeView : public ui::AbstractTreeView {
+ GeometrySet geometry_set_;
+ const bContext &C_;
+ SpaceSpreadsheet &sspreadsheet_;
+ bScreen &screen_;
- DatasetDrawContext(const bContext *C);
+ friend class GeometryDataSetTreeViewItem;
- GeometrySet geometry_set_from_component(GeometryComponentType component);
- const std::array<int, 2> &cursor_mval() const;
-};
-
-DatasetDrawContext::DatasetDrawContext(const bContext *C)
- : sspreadsheet(CTX_wm_space_spreadsheet(C)),
- object_eval(spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C)))
-{
- const wmWindow *win = CTX_wm_window(C);
- const ARegion *region = CTX_wm_region(C);
- mval_ = {win->eventstate->x - region->winrct.xmin, win->eventstate->y - region->winrct.ymin};
-}
+ public:
+ GeometryDataSetTreeView(GeometrySet geometry_set, const bContext &C)
+ : geometry_set_(std::move(geometry_set)),
+ C_(C),
+ sspreadsheet_(*CTX_wm_space_spreadsheet(&C)),
+ screen_(*CTX_wm_screen(&C))
+ {
+ }
-GeometrySet DatasetDrawContext::geometry_set_from_component(GeometryComponentType component)
-{
- return spreadsheet_get_display_geometry_set(sspreadsheet, object_eval, component);
-}
+ void build_tree() override
+ {
+ GeometryDataSetTreeViewItem &mesh = this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, IFACE_("Mesh"), ICON_MESH_DATA);
+ mesh.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_POINT, IFACE_("Vertex"), ICON_VERTEXSEL);
+ mesh.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_EDGE, IFACE_("Edge"), ICON_EDGESEL);
+ mesh.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_FACE, IFACE_("Face"), ICON_FACESEL);
+ mesh.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_CORNER, IFACE_("Face Corner"), ICON_NODE_CORNER);
+
+ GeometryDataSetTreeViewItem &curve = this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_CURVE, IFACE_("Curve"), ICON_CURVE_DATA);
+ curve.add_tree_item<GeometryDataSetTreeViewItem>(GEO_COMPONENT_TYPE_CURVE,
+ ATTR_DOMAIN_POINT,
+ IFACE_("Control Point"),
+ ICON_CURVE_BEZCIRCLE);
+ curve.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_CURVE, ATTR_DOMAIN_CURVE, IFACE_("Spline"), ICON_CURVE_PATH);
+
+ GeometryDataSetTreeViewItem &pointcloud = this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_POINT_CLOUD, IFACE_("Point Cloud"), ICON_POINTCLOUD_DATA);
+ pointcloud.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_POINT_CLOUD, ATTR_DOMAIN_POINT, IFACE_("Point"), ICON_PARTICLE_POINT);
+
+ this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_VOLUME, IFACE_("Volume Grids"), ICON_VOLUME_DATA);
+
+ this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_INSTANCES, ATTR_DOMAIN_INSTANCE, IFACE_("Instances"), ICON_EMPTY_AXIS);
+ }
+};
-const std::array<int, 2> &DatasetDrawContext::cursor_mval() const
+GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type,
+ StringRef label,
+ BIFIconID icon)
+ : component_type_(component_type), domain_(std::nullopt), icon_(icon)
{
- return mval_;
+ label_ = label;
+ this->set_collapsed(false);
}
-
-/* -------------------------------------------------------------------- */
-/* Drawer */
-
-DatasetRegionDrawer::DatasetRegionDrawer(const ARegion *region,
- uiBlock &block,
- DatasetDrawContext &draw_context)
- : row_height(UI_UNIT_Y),
- xmin(region->v2d.cur.xmin),
- xmax(region->v2d.cur.xmax),
- block(block),
- v2d(region->v2d),
- draw_context(draw_context)
+GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type,
+ AttributeDomain domain,
+ StringRef label,
+ BIFIconID icon)
+ : component_type_(component_type), domain_(domain), icon_(icon)
{
+ label_ = label;
}
-void DatasetRegionDrawer::draw_hierarchy(const DatasetLayoutHierarchy &layout)
+void GeometryDataSetTreeViewItem::on_activate()
{
- for (const DatasetComponentLayoutInfo &component : layout.components) {
- draw_context.current_geometry_set = draw_context.geometry_set_from_component(component.type);
-
- draw_component_row(component);
-
- /* Iterate attribute domains, skip unset ones (storage has to be in a enum-based, fixed size
- * array so uses optionals to support skipping enum values that shouldn't be displayed for a
- * component). */
- for (const auto &optional_domain : component.attr_domains) {
- if (!optional_domain) {
- continue;
- }
-
- const DatasetAttrDomainLayoutInfo &domain_info = *optional_domain;
- draw_attribute_domain_row(component, domain_info);
- }
+ GeometryDataSetTreeView &tree_view = this->get_tree();
+ bContext &C = const_cast<bContext &>(tree_view.C_);
+ SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_;
+ tree_view.sspreadsheet_.geometry_component_type = component_type_;
+ if (domain_) {
+ tree_view.sspreadsheet_.attribute_domain = *domain_;
}
+ PointerRNA ptr;
+ RNA_pointer_create(&tree_view.screen_.id, &RNA_SpaceSpreadsheet, &sspreadsheet, &ptr);
+ RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "attribute_domain"));
+ RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "geometry_component_type"));
}
-static int element_count_from_instances(const GeometrySet &geometry_set)
+void GeometryDataSetTreeViewItem::build_row(uiLayout &row)
{
- if (geometry_set.has_instances()) {
- const InstancesComponent *instances_component =
- geometry_set.get_component_for_read<InstancesComponent>();
- return instances_component->instances_amount();
+ uiItemL(&row, label_.c_str(), icon_);
+
+ if (const std::optional<int> count = this->count()) {
+ /* Using the tree row button instead of a separate right aligned button gives padding
+ * to the right side of the number, which it didn't have with the button. */
+ char element_count[7];
+ BLI_str_format_attribute_domain_size(element_count, *count);
+ UI_but_hint_drawstr_set((uiBut *)this->tree_row_button(), element_count);
}
- return 0;
}
-static int element_count_from_component_domain(const GeometrySet &geometry_set,
- GeometryComponentType component,
- AttributeDomain domain)
+std::optional<bool> GeometryDataSetTreeViewItem::should_be_active() const
{
- if (geometry_set.has_mesh() && component == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>();
- return mesh_component->attribute_domain_size(domain);
- }
+ GeometryDataSetTreeView &tree_view = this->get_tree();
+ SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_;
- if (geometry_set.has_pointcloud() && component == GEO_COMPONENT_TYPE_POINT_CLOUD) {
- const PointCloudComponent *point_cloud_component =
- geometry_set.get_component_for_read<PointCloudComponent>();
- return point_cloud_component->attribute_domain_size(domain);
+ if (component_type_ == GEO_COMPONENT_TYPE_VOLUME) {
+ return sspreadsheet.geometry_component_type == component_type_;
}
- if (geometry_set.has_volume() && component == GEO_COMPONENT_TYPE_VOLUME) {
- const VolumeComponent *volume_component =
- geometry_set.get_component_for_read<VolumeComponent>();
- return volume_component->attribute_domain_size(domain);
+ if (!domain_) {
+ return false;
}
- if (geometry_set.has_curve() && component == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
- return curve_component->attribute_domain_size(domain);
- }
-
- return 0;
+ return sspreadsheet.geometry_component_type == component_type_ &&
+ sspreadsheet.attribute_domain == *domain_;
}
-void DatasetRegionDrawer::draw_dataset_row(const int indentation,
- const GeometryComponentType component,
- const std::optional<AttributeDomain> domain,
- BIFIconID icon,
- const char *label,
- const bool is_active)
+bool GeometryDataSetTreeViewItem::supports_collapsing() const
{
+ return false;
+}
- const float row_height = UI_UNIT_Y;
- const float padding_x = UI_UNIT_X * 0.25f;
-
- const rctf rect = {float(xmin) + padding_x,
- float(xmax) - V2D_SCROLL_HANDLE_WIDTH,
- ymin_offset - row_height,
- ymin_offset};
-
- char element_count[7];
- if (component == GEO_COMPONENT_TYPE_INSTANCES) {
- BLI_str_format_attribute_domain_size(
- element_count, element_count_from_instances(draw_context.current_geometry_set));
- }
- else {
- BLI_str_format_attribute_domain_size(
- element_count,
- domain ? element_count_from_component_domain(
- draw_context.current_geometry_set, component, *domain) :
- 0);
- }
+GeometryDataSetTreeView &GeometryDataSetTreeViewItem::get_tree() const
+{
+ return static_cast<GeometryDataSetTreeView &>(this->get_tree_view());
+}
- std::string label_and_element_count = label;
- label_and_element_count += UI_SEP_CHAR;
- label_and_element_count += element_count;
-
- uiBut *bt = uiDefIconTextButO(&block,
- UI_BTYPE_DATASETROW,
- "SPREADSHEET_OT_change_spreadsheet_data_source",
- 0,
- icon,
- label,
- rect.xmin,
- rect.ymin,
- BLI_rctf_size_x(&rect),
- BLI_rctf_size_y(&rect),
- nullptr);
-
- UI_but_datasetrow_indentation_set(bt, indentation);
-
- if (is_active) {
- UI_but_hint_drawstr_set(bt, element_count);
- UI_but_datasetrow_component_set(bt, component);
- if (domain) {
- UI_but_datasetrow_domain_set(bt, *domain);
- }
- UI_but_func_pushed_state_set(bt, &is_component_row_selected, draw_context.sspreadsheet);
+std::optional<int> GeometryDataSetTreeViewItem::count() const
+{
+ GeometryDataSetTreeView &tree_view = this->get_tree();
+ GeometrySet &geometry = tree_view.geometry_set_;
- PointerRNA *but_ptr = UI_but_operator_ptr_get((uiBut *)bt);
- RNA_int_set(but_ptr, "component_type", component);
- if (domain) {
- RNA_int_set(but_ptr, "attribute_domain_type", *domain);
+ /* Special case for volumes since there is no grid domain. */
+ if (component_type_ == GEO_COMPONENT_TYPE_VOLUME) {
+ if (const Volume *volume = geometry.get_volume_for_read()) {
+ return BKE_volume_num_grids(volume);
}
+ return 0;
}
- ymin_offset -= row_height;
-}
-
-void DatasetRegionDrawer::draw_component_row(const DatasetComponentLayoutInfo &component_info)
-{
- if (component_info.type == GEO_COMPONENT_TYPE_INSTANCES) {
- draw_dataset_row(
- 0, component_info.type, std::nullopt, component_info.icon, component_info.label, true);
+ if (!domain_) {
+ return std::nullopt;
}
- else {
- draw_dataset_row(
- 0, component_info.type, std::nullopt, component_info.icon, component_info.label, false);
+
+ if (const GeometryComponent *component = geometry.get_component_for_read(component_type_)) {
+ return component->attribute_domain_size(*domain_);
}
-}
-void DatasetRegionDrawer::draw_attribute_domain_row(
- const DatasetComponentLayoutInfo &component_info,
- const DatasetAttrDomainLayoutInfo &domain_info)
-{
- draw_dataset_row(
- 1, component_info.type, domain_info.type, domain_info.icon, domain_info.label, true);
+ return 0;
}
-/* -------------------------------------------------------------------- */
-/* Drawer */
-
-void draw_dataset_in_region(const bContext *C, ARegion *region)
+void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel)
{
- DatasetDrawContext draw_context{C};
- if (!draw_context.object_eval) {
- /* No object means nothing to display. Keep the region empty. */
+ const SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ Object *object = spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C));
+ if (!object) {
return;
}
+ uiLayout *layout = panel->layout;
- uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
-
- DatasetRegionDrawer drawer{region, *block, draw_context};
+ uiBlock *block = uiLayoutGetBlock(layout);
- /* Start with an offset to align buttons to spreadsheet rows. Use spreadsheet drawing info for
- * that. */
- drawer.ymin_offset = -SpreadsheetDrawer().top_row_height + drawer.row_height;
+ UI_block_layout_set_current(block, layout);
- const DatasetLayoutHierarchy hierarchy = dataset_layout_hierarchy();
- drawer.draw_hierarchy(hierarchy);
-#ifndef NDEBUG
- dataset_layout_hierarchy_sanity_check(hierarchy);
-#endif
+ ui::AbstractTreeView *tree_view = UI_block_add_view(
+ *block,
+ "Data Set Tree View",
+ std::make_unique<GeometryDataSetTreeView>(
+ spreadsheet_get_display_geometry_set(sspreadsheet, object), *C));
- UI_block_end(C, block);
- UI_view2d_totRect_set(&region->v2d, region->winx, abs(drawer.ymin_offset));
- UI_block_draw(C, block);
+ ui::TreeViewBuilder builder(*block);
+ builder.build_tree_view(*tree_view);
}
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh
index 19906d73e7f..4a604533f11 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh
@@ -16,49 +16,11 @@
#pragma once
-#include <array>
-
-#include "BKE_geometry_set.hh"
-#include "UI_interface.h"
-#include "spreadsheet_dataset_layout.hh"
-
-struct ARegion;
-struct View2D;
+struct Panel;
struct bContext;
-struct uiBlock;
namespace blender::ed::spreadsheet {
-class DatasetDrawContext;
-
-class DatasetRegionDrawer {
- public:
- const int row_height;
- float ymin_offset = 0;
-
- int xmin;
- int xmax;
- uiBlock &block;
- const View2D &v2d;
- DatasetDrawContext &draw_context;
-
- DatasetRegionDrawer(const ARegion *region, uiBlock &block, DatasetDrawContext &draw_context);
-
- void draw_hierarchy(const DatasetLayoutHierarchy &layout);
-
- void draw_attribute_domain_row(const DatasetComponentLayoutInfo &component,
- const DatasetAttrDomainLayoutInfo &domain_info);
- void draw_component_row(const DatasetComponentLayoutInfo &component_info);
-
- private:
- void draw_dataset_row(const int indentation,
- const GeometryComponentType component,
- const std::optional<AttributeDomain> domain,
- const BIFIconID icon,
- const char *label,
- const bool is_active);
-};
-
-void draw_dataset_in_region(const bContext *C, ARegion *region);
+void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel);
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc
deleted file mode 100644
index abbad8c7088..00000000000
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc
+++ /dev/null
@@ -1,112 +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.
- */
-
-#include <optional>
-
-#include "BLI_span.hh"
-
-#include "BLT_translation.h"
-
-#include "spreadsheet_dataset_layout.hh"
-
-namespace blender::ed::spreadsheet {
-
-#define ATTR_INFO(type, label, icon) \
- std::optional<DatasetAttrDomainLayoutInfo> \
- { \
- std::in_place, type, label, icon \
- }
-#define ATTR_INFO_NONE(type) \
- { \
- std::nullopt \
- }
-
-/**
- * Definition for the component->attribute-domain hierarchy.
- * Constructed at compile time.
- *
- * \warning Order of attribute-domains matters! It __must__ match the #AttributeDomain
- * definition and fill gaps with unset optionals (i.e. `std::nullopt`). Would be nice to use
- * array designators for this (which C++ doesn't support).
- */
-constexpr DatasetComponentLayoutInfo DATASET_layout_hierarchy[] = {
- {
- GEO_COMPONENT_TYPE_MESH,
- N_("Mesh"),
- ICON_MESH_DATA,
- {
- ATTR_INFO(ATTR_DOMAIN_POINT, N_("Vertex"), ICON_VERTEXSEL),
- ATTR_INFO(ATTR_DOMAIN_EDGE, N_("Edge"), ICON_EDGESEL),
- ATTR_INFO(ATTR_DOMAIN_FACE, N_("Face"), ICON_FACESEL),
- ATTR_INFO(ATTR_DOMAIN_CORNER, N_("Face Corner"), ICON_NODE_CORNER),
- },
- },
- {
- GEO_COMPONENT_TYPE_CURVE,
- N_("Curves"),
- ICON_CURVE_DATA,
- {
- ATTR_INFO(ATTR_DOMAIN_POINT, N_("Control Point"), ICON_CURVE_BEZCIRCLE),
- ATTR_INFO_NONE(ATTR_DOMAIN_EDGE),
- ATTR_INFO_NONE(ATTR_DOMAIN_CORNER),
- ATTR_INFO_NONE(ATTR_DOMAIN_FACE),
- ATTR_INFO(ATTR_DOMAIN_CURVE, N_("Spline"), ICON_CURVE_PATH),
- },
- },
- {
- GEO_COMPONENT_TYPE_POINT_CLOUD,
- N_("Point Cloud"),
- ICON_POINTCLOUD_DATA,
- {
- ATTR_INFO(ATTR_DOMAIN_POINT, N_("Point"), ICON_PARTICLE_POINT),
- },
- },
- {
- GEO_COMPONENT_TYPE_INSTANCES,
- N_("Instances"),
- ICON_EMPTY_AXIS,
- {},
- },
-};
-
-#undef ATTR_INFO
-#undef ATTR_INFO_LABEL
-
-DatasetLayoutHierarchy dataset_layout_hierarchy()
-{
- return DatasetLayoutHierarchy{
- Span{DATASET_layout_hierarchy, ARRAY_SIZE(DATASET_layout_hierarchy)}};
-}
-
-#ifndef NDEBUG
-/**
- * Debug-only sanity check for correct attribute domain initialization (order/indices must
- * match AttributeDomain). This doesn't check for all possible missuses, but should catch the most
- * likely mistakes.
- */
-void dataset_layout_hierarchy_sanity_check(const DatasetLayoutHierarchy &hierarchy)
-{
- for (const DatasetComponentLayoutInfo &component : hierarchy.components) {
- for (uint i = 0; i < component.attr_domains.size(); i++) {
- if (component.attr_domains[i]) {
- BLI_assert(component.attr_domains[i]->type == static_cast<AttributeDomain>(i));
- }
- }
- }
-}
-#endif
-
-} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh
deleted file mode 100644
index d463739a0fa..00000000000
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh
+++ /dev/null
@@ -1,68 +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.
- */
-
-#pragma once
-
-#include <array>
-#include <optional>
-
-/* Enum definitions... */
-#include "BKE_attribute.h"
-#include "BKE_geometry_set.h"
-
-#include "BLI_span.hh"
-
-/* More enum definitions... */
-#include "UI_resources.h"
-
-#pragma once
-
-namespace blender::ed::spreadsheet {
-
-struct DatasetAttrDomainLayoutInfo {
- AttributeDomain type;
- const char *label;
- BIFIconID icon;
-
- constexpr DatasetAttrDomainLayoutInfo(AttributeDomain type, const char *label, BIFIconID icon)
- : type(type), label(label), icon(icon)
- {
- }
-};
-
-struct DatasetComponentLayoutInfo {
- GeometryComponentType type;
- const char *label;
- BIFIconID icon;
- /** Array of attribute-domains. Has to be fixed size based on #AttributeDomain enum, but not all
- * values need displaying for all parent components. Hence the optional use. */
- using AttrDomainArray = std::array<std::optional<DatasetAttrDomainLayoutInfo>, ATTR_DOMAIN_NUM>;
- const AttrDomainArray attr_domains;
-};
-
-struct DatasetLayoutHierarchy {
- /** The components for display (with layout info like icon and label). Each component stores
- * the attribute domains it wants to display (also with layout info like icon and label). */
- const Span<DatasetComponentLayoutInfo> components;
-};
-
-DatasetLayoutHierarchy dataset_layout_hierarchy();
-
-#ifndef NDEBUG
-void dataset_layout_hierarchy_sanity_check(const DatasetLayoutHierarchy &hierarchy);
-#endif
-
-} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
index b911c80fa63..857aa20da92 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
@@ -27,6 +27,8 @@
#include "spreadsheet_draw.hh"
+#define CELL_RIGHT_PADDING (2.0f * UI_DPI_FAC)
+
namespace blender::ed::spreadsheet {
SpreadsheetDrawer::SpreadsheetDrawer()
@@ -159,7 +161,7 @@ static void draw_left_column_content(const int scroll_offset_y,
params.xmin = 0;
params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height -
scroll_offset_y;
- params.width = drawer.left_column_width;
+ params.width = drawer.left_column_width - CELL_RIGHT_PADDING;
params.height = drawer.row_height;
drawer.draw_left_column_cell(row_index, params);
}
@@ -194,7 +196,7 @@ static void draw_top_row_content(const bContext *C,
params.block = first_row_block;
params.xmin = left_x;
params.ymin = region->winy - drawer.top_row_height;
- params.width = column_width;
+ params.width = column_width - CELL_RIGHT_PADDING;
params.height = drawer.top_row_height;
drawer.draw_top_row_cell(column_index, params);
@@ -242,7 +244,7 @@ static void draw_cell_contents(const bContext *C,
params.xmin = left_x;
params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height -
scroll_offset_y;
- params.width = column_width;
+ params.width = column_width - CELL_RIGHT_PADDING;
params.height = drawer.row_height;
drawer.draw_content_cell(row_index, column_index, params);
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
index 8be5283fd63..df23a27aa22 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
@@ -17,22 +17,37 @@
#pragma once
#include "BKE_geometry_set.hh"
+#include "spreadsheet_cache.hh"
-typedef struct SpaceSpreadsheet_Runtime {
- int visible_rows;
- int tot_rows;
- int tot_columns;
-} SpaceSpreadsheet_Runtime;
+struct SpaceSpreadsheet_Runtime {
+ public:
+ int visible_rows = 0;
+ int tot_rows = 0;
+ int tot_columns = 0;
+ blender::ed::spreadsheet::SpreadsheetCache cache;
+
+ SpaceSpreadsheet_Runtime() = default;
+
+ /* The cache is not copied currently. */
+ SpaceSpreadsheet_Runtime(const SpaceSpreadsheet_Runtime &other)
+ : visible_rows(other.visible_rows), tot_rows(other.tot_rows), tot_columns(other.tot_columns)
+ {
+ }
+};
+
+struct ARegionType;
struct bContext;
-void spreadsheet_operatortypes(void);
+void spreadsheet_operatortypes();
void spreadsheet_update_context_path(const bContext *C);
Object *spreadsheet_get_object_eval(const SpaceSpreadsheet *sspreadsheet,
const Depsgraph *depsgraph);
namespace blender::ed::spreadsheet {
GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet,
- Object *object_eval,
- const GeometryComponentType used_component_type);
-}
+ Object *object_eval);
+
+void spreadsheet_data_set_region_panels_register(ARegionType &region_type);
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index 1a5eac53306..f4b5ff819ed 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -17,8 +17,15 @@
#include <iomanip>
#include <sstream>
+#include "BLI_math_vec_types.hh"
+
+#include "BKE_geometry_set.hh"
+
+#include "spreadsheet_column_values.hh"
#include "spreadsheet_layout.hh"
+#include "DNA_collection_types.h"
+#include "DNA_object_types.h"
#include "DNA_userdef_types.h"
#include "UI_interface.h"
@@ -92,11 +99,14 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
{
const int real_index = spreadsheet_layout_.row_indices[row_index];
const ColumnValues &column = *spreadsheet_layout_.columns[column_index].values;
- CellValue cell_value;
- column.get_value(real_index, cell_value);
+ if (real_index > column.size()) {
+ return;
+ }
- if (cell_value.value_int.has_value()) {
- const int value = *cell_value.value_int;
+ const fn::GVArray &data = column.data();
+
+ if (data.type().is<int>()) {
+ const int value = data.get<int>(real_index);
const std::string value_str = std::to_string(value);
uiBut *but = uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
@@ -117,8 +127,8 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
}
- else if (cell_value.value_float.has_value()) {
- const float value = *cell_value.value_float;
+ else if (data.type().is<float>()) {
+ const float value = data.get<float>(real_index);
std::stringstream ss;
ss << std::fixed << std::setprecision(3) << value;
const std::string value_str = ss.str();
@@ -141,8 +151,8 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
}
- else if (cell_value.value_bool.has_value()) {
- const bool value = *cell_value.value_bool;
+ else if (data.type().is<bool>()) {
+ const bool value = data.get<bool>(real_index);
const int icon = value ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
uiBut *but = uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
@@ -161,70 +171,81 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
nullptr);
UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT);
}
- else if (cell_value.value_float2.has_value()) {
- const float2 value = *cell_value.value_float2;
+ else if (data.type().is<float2>()) {
+ const float2 value = data.get<float2>(real_index);
this->draw_float_vector(params, Span(&value.x, 2));
}
- else if (cell_value.value_float3.has_value()) {
- const float3 value = *cell_value.value_float3;
+ else if (data.type().is<float3>()) {
+ const float3 value = data.get<float3>(real_index);
this->draw_float_vector(params, Span(&value.x, 3));
}
- else if (cell_value.value_color.has_value()) {
- const ColorGeometry4f value = *cell_value.value_color;
+ else if (data.type().is<ColorGeometry4f>()) {
+ const ColorGeometry4f value = data.get<ColorGeometry4f>(real_index);
this->draw_float_vector(params, Span(&value.r, 4));
}
- else if (cell_value.value_object.has_value()) {
- const ObjectCellValue value = *cell_value.value_object;
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_OBJECT_DATA,
- reinterpret_cast<const ID *const>(value.object)->name + 2,
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
- }
- else if (cell_value.value_collection.has_value()) {
- const CollectionCellValue value = *cell_value.value_collection;
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_OUTLINER_COLLECTION,
- reinterpret_cast<const ID *const>(value.collection)->name + 2,
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
- }
- else if (cell_value.value_geometry_set.has_value()) {
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_MESH_DATA,
- "Geometry",
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
+ else if (data.type().is<InstanceReference>()) {
+ const InstanceReference value = data.get<InstanceReference>(real_index);
+ switch (value.type()) {
+ case InstanceReference::Type::Object: {
+ const Object &object = value.object();
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_OBJECT_DATA,
+ object.id.name + 2,
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ break;
+ }
+ case InstanceReference::Type::Collection: {
+ Collection &collection = value.collection();
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_OUTLINER_COLLECTION,
+ collection.id.name + 2,
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ break;
+ }
+ case InstanceReference::Type::GeometrySet: {
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_MESH_DATA,
+ "Geometry",
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ break;
+ }
+ case InstanceReference::Type::None: {
+ break;
+ }
+ }
}
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh
index 1768af6ae09..f996cd99dad 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh
@@ -32,7 +32,7 @@ struct ColumnLayout {
/* Layout information for the entire spreadsheet. */
struct SpreadsheetLayout {
Vector<ColumnLayout> columns;
- Span<int64_t> row_indices;
+ IndexMask row_indices;
int index_column_width = 100;
};
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
new file mode 100644
index 00000000000..db8265a33ce
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
@@ -0,0 +1,37 @@
+/*
+ * 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 "BKE_screen.h"
+
+#include "BLT_translation.h"
+
+#include "spreadsheet_dataset_draw.hh"
+#include "spreadsheet_intern.hh"
+
+namespace blender::ed::spreadsheet {
+
+void spreadsheet_data_set_region_panels_register(ARegionType &region_type)
+{
+ PanelType *panel_type = MEM_cnew<PanelType>(__func__);
+ strcpy(panel_type->idname, "SPREADSHEET_PT_data_set");
+ strcpy(panel_type->label, N_("Data Set"));
+ strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ panel_type->flag = PANEL_TYPE_NO_HEADER;
+ panel_type->draw = spreadsheet_data_set_panel_draw;
+ BLI_addtail(&region_type.paneltypes, panel_type);
+}
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index 1e46fef8d71..556c0b0d5ca 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -18,7 +18,6 @@
#include "BLI_listbase.h"
-#include "DNA_collection_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -38,238 +37,193 @@
namespace blender::ed::spreadsheet {
-template<typename OperationFn>
-static void apply_filter_operation(const ColumnValues &values,
+template<typename T, typename OperationFn>
+static void apply_filter_operation(const VArray<T> &data,
OperationFn check_fn,
- MutableSpan<bool> rows_included)
+ const IndexMask mask,
+ Vector<int64_t> &new_indices)
{
- for (const int i : rows_included.index_range()) {
- if (!rows_included[i]) {
- continue;
- }
- CellValue cell_value;
- values.get_value(i, cell_value);
- if (!check_fn(cell_value)) {
- rows_included[i] = false;
+ for (const int64_t i : mask) {
+ if (check_fn(data[i])) {
+ new_indices.append(i);
}
}
}
-static void apply_row_filter(const SpreadsheetLayout &spreadsheet_layout,
- const SpreadsheetRowFilter &row_filter,
- MutableSpan<bool> rows_included)
+static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
+ const Map<StringRef, const ColumnValues *> &columns,
+ const IndexMask prev_mask,
+ Vector<int64_t> &new_indices)
{
- for (const ColumnLayout &column : spreadsheet_layout.columns) {
- const ColumnValues &values = *column.values;
- if (values.name() != row_filter.column_name) {
- continue;
+ const ColumnValues &column = *columns.lookup(row_filter.column_name);
+ const fn::GVArray &column_data = column.data();
+ if (column_data.type().is<float>()) {
+ const float value = row_filter.value_float;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<float>(),
+ [&](const float cell) { return std::abs(cell - value) < threshold; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<float>(),
+ [&](const float cell) { return cell > value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<float>(),
+ [&](const float cell) { return cell < value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
}
-
- switch (values.type()) {
- case SPREADSHEET_VALUE_TYPE_INT32: {
- const int value = row_filter.value_int;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_int == value;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_int > value;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_int < value;
- },
- rows_included);
- break;
- }
- }
+ }
+ else if (column_data.type().is<int>()) {
+ const int value = row_filter.value_int;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ apply_filter_operation(
+ column_data.typed<int>(),
+ [&](const int cell) { return cell == value; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_FLOAT: {
- const float value = row_filter.value_float;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold = row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold](const CellValue &cell_value) -> bool {
- return std::abs(*cell_value.value_float - value) < threshold;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_float > value;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_float < value;
- },
- rows_included);
- break;
- }
- }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<int>(),
+ [value](const int cell) { return cell > value; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_FLOAT2: {
- const float2 value = row_filter.value_float2;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_squared = row_filter.threshold * row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold_squared](const CellValue &cell_value) -> bool {
- return float2::distance_squared(*cell_value.value_float2, value) <
- threshold_squared;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float2->x > value.x &&
- cell_value.value_float2->y > value.y;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float2->x < value.x &&
- cell_value.value_float2->y < value.y;
- },
- rows_included);
- break;
- }
- }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<int>(),
+ [&](const int cell) { return cell < value; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_FLOAT3: {
- const float3 value = row_filter.value_float3;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_squared = row_filter.threshold * row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold_squared](const CellValue &cell_value) -> bool {
- return float3::distance_squared(*cell_value.value_float3, value) <
- threshold_squared;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float3->x > value.x &&
- cell_value.value_float3->y > value.y &&
- cell_value.value_float3->z > value.z;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float3->x < value.x &&
- cell_value.value_float3->y < value.y &&
- cell_value.value_float3->z < value.z;
- },
- rows_included);
- break;
- }
- }
+ }
+ }
+ else if (column_data.type().is<float2>()) {
+ const float2 value = row_filter.value_float2;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_sq = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<float2>(),
+ [&](const float2 cell) { return math::distance_squared(cell, value) > threshold_sq; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_COLOR: {
- const ColorGeometry4f value = row_filter.value_color;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_squared = row_filter.threshold * row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold_squared](const CellValue &cell_value) -> bool {
- return len_squared_v4v4(value, *cell_value.value_color) < threshold_squared;
- },
- rows_included);
- break;
- }
- }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<float2>(),
+ [&](const float2 cell) { return cell.x > value.x && cell.y > value.y; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<float2>(),
+ [&](const float2 cell) { return cell.x < value.x && cell.y < value.y; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ }
+ }
+ else if (column_data.type().is<float3>()) {
+ const float3 value = row_filter.value_float3;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_sq = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<float3>(),
+ [&](const float3 cell) { return math::distance_squared(cell, value) > threshold_sq; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_BOOL: {
- const bool value = (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) != 0;
+ case SPREADSHEET_ROW_FILTER_GREATER: {
apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_bool == value;
+ column_data.typed<float3>(),
+ [&](const float3 cell) {
+ return cell.x > value.x && cell.y > value.y && cell.z > value.z;
},
- rows_included);
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_INSTANCES: {
- const StringRef value = row_filter.value_string;
+ case SPREADSHEET_ROW_FILTER_LESS: {
apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- const ID *id = nullptr;
- if (cell_value.value_object) {
- id = &cell_value.value_object->object->id;
- }
- else if (cell_value.value_collection) {
- id = &cell_value.value_collection->collection->id;
- }
- if (id == nullptr) {
- return false;
- }
-
- return value == id->name + 2;
+ column_data.typed<float3>(),
+ [&](const float3 cell) {
+ return cell.x < value.x && cell.y < value.y && cell.z < value.z;
},
- rows_included);
+ prev_mask,
+ new_indices);
break;
}
- default:
+ }
+ }
+ else if (column_data.type().is<ColorGeometry4f>()) {
+ const ColorGeometry4f value = row_filter.value_color;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_sq = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4f>(),
+ [&](const ColorGeometry4f cell) {
+ return len_squared_v4v4(cell, value) > threshold_sq;
+ },
+ prev_mask,
+ new_indices);
break;
+ }
}
-
- /* Only one column should have this name. */
- break;
}
-}
-
-static void index_vector_from_bools(Span<bool> selection, Vector<int64_t> &indices)
-{
- for (const int i : selection.index_range()) {
- if (selection[i]) {
- indices.append(i);
+ else if (column_data.type().is<InstanceReference>()) {
+ const StringRef value = row_filter.value_string;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ apply_filter_operation(
+ column_data.typed<InstanceReference>(),
+ [&](const InstanceReference cell) {
+ switch (cell.type()) {
+ case InstanceReference::Type::Object: {
+ return value == (reinterpret_cast<ID &>(cell.object()).name + 2);
+ }
+ case InstanceReference::Type::Collection: {
+ return value == (reinterpret_cast<ID &>(cell.collection()).name + 2);
+ }
+ case InstanceReference::Type::GeometrySet: {
+ return false;
+ }
+ case InstanceReference::Type::None: {
+ return false;
+ }
+ }
+ BLI_assert_unreachable();
+ return false;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
}
}
}
@@ -297,10 +251,10 @@ static bool use_selection_filter(const SpaceSpreadsheet &sspreadsheet,
return true;
}
-Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
- const SpreadsheetLayout &spreadsheet_layout,
- const DataSource &data_source,
- ResourceScope &scope)
+IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
+ const SpreadsheetLayout &spreadsheet_layout,
+ const DataSource &data_source,
+ ResourceScope &scope)
{
const int tot_rows = data_source.tot_rows();
@@ -309,35 +263,51 @@ Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
/* Avoid allocating an array if no row filtering is necessary. */
if (!(use_filters || use_selection)) {
- return IndexRange(tot_rows).as_span();
+ return IndexMask(tot_rows);
}
- Array<bool> rows_included(tot_rows, true);
+ IndexMask mask(tot_rows);
+
+ Vector<int64_t> mask_indices;
+ mask_indices.reserve(tot_rows);
+
+ if (use_selection) {
+ const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
+ &data_source);
+ mask = geometry_data_source->apply_selection_filter(mask_indices);
+ }
if (use_filters) {
+ Map<StringRef, const ColumnValues *> columns;
+ for (const ColumnLayout &column : spreadsheet_layout.columns) {
+ columns.add(column.values->name(), column.values);
+ }
+
LISTBASE_FOREACH (const SpreadsheetRowFilter *, row_filter, &sspreadsheet.row_filters) {
if (row_filter->flag & SPREADSHEET_ROW_FILTER_ENABLED) {
- apply_row_filter(spreadsheet_layout, *row_filter, rows_included);
+ if (!columns.contains(row_filter->column_name)) {
+ continue;
+ }
+ Vector<int64_t> new_indices;
+ new_indices.reserve(mask_indices.size());
+ apply_row_filter(*row_filter, columns, mask, new_indices);
+ std::swap(new_indices, mask_indices);
+ mask = IndexMask(mask_indices);
}
}
}
- if (use_selection) {
- const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
- &data_source);
- geometry_data_source->apply_selection_filter(rows_included);
+ if (mask_indices.is_empty()) {
+ BLI_assert(mask.is_empty() || mask.is_range());
+ return mask;
}
- Vector<int64_t> &indices = scope.construct<Vector<int64_t>>();
- index_vector_from_bools(rows_included, indices);
-
- return indices;
+ return IndexMask(scope.add_value(std::move(mask_indices)));
}
SpreadsheetRowFilter *spreadsheet_row_filter_new()
{
- SpreadsheetRowFilter *row_filter = (SpreadsheetRowFilter *)MEM_callocN(
- sizeof(SpreadsheetRowFilter), __func__);
+ SpreadsheetRowFilter *row_filter = MEM_cnew<SpreadsheetRowFilter>(__func__);
row_filter->flag = (SPREADSHEET_ROW_FILTER_UI_EXPAND | SPREADSHEET_ROW_FILTER_ENABLED);
row_filter->operation = SPREADSHEET_ROW_FILTER_LESS;
row_filter->threshold = 0.01f;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh
index 0a5783e318d..3788baaa993 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh
@@ -23,10 +23,10 @@
namespace blender::ed::spreadsheet {
-Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
- const SpreadsheetLayout &spreadsheet_layout,
- const DataSource &data_source,
- ResourceScope &scope);
+IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
+ const SpreadsheetLayout &spreadsheet_layout,
+ const DataSource &data_source,
+ ResourceScope &scope);
SpreadsheetRowFilter *spreadsheet_row_filter_new();
SpreadsheetRowFilter *spreadsheet_row_filter_copy(const SpreadsheetRowFilter *src_row_filter);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
index 219d03c1dcd..56722104b4f 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
@@ -105,12 +105,17 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter,
return row_filter.value_string;
}
return "";
- case SPREADSHEET_VALUE_TYPE_COLOR:
+ case SPREADSHEET_VALUE_TYPE_COLOR: {
std::ostringstream result;
result.precision(3);
result << std::fixed << "(" << row_filter.value_color[0] << ", " << row_filter.value_color[1]
<< ", " << row_filter.value_color[2] << ", " << row_filter.value_color[3] << ")";
return result.str();
+ }
+ case SPREADSHEET_VALUE_TYPE_STRING:
+ return row_filter.value_string;
+ case SPREADSHEET_VALUE_TYPE_UNKNOWN:
+ return "";
}
BLI_assert_unreachable();
return "";
@@ -234,6 +239,12 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
uiItemR(layout, filter_ptr, "value_color", 0, IFACE_("Value"), ICON_NONE);
uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
break;
+ case SPREADSHEET_VALUE_TYPE_STRING:
+ uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE);
+ break;
+ case SPREADSHEET_VALUE_TYPE_UNKNOWN:
+ uiItemL(layout, IFACE_("Unkown column type"), ICON_ERROR);
+ break;
}
}
@@ -320,7 +331,7 @@ static void set_filter_expand_flag(const bContext *UNUSED(C), Panel *panel, shor
void register_row_filter_panels(ARegionType &region_type)
{
{
- PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ PanelType *panel_type = MEM_cnew<PanelType>(__func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_row_filters");
strcpy(panel_type->label, N_("Filters"));
strcpy(panel_type->category, "Filters");
@@ -331,12 +342,12 @@ void register_row_filter_panels(ARegionType &region_type)
}
{
- PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ PanelType *panel_type = MEM_cnew<PanelType>(__func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_filter");
strcpy(panel_type->label, "");
strcpy(panel_type->category, "Filters");
strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- panel_type->flag = PANEL_TYPE_INSTANCED | PANEL_TYPE_DRAW_BOX | PANEL_TYPE_HEADER_EXPAND;
+ panel_type->flag = PANEL_TYPE_INSTANCED | PANEL_TYPE_HEADER_EXPAND;
panel_type->draw_header = spreadsheet_filter_panel_draw_header;
panel_type->draw = spreadsheet_filter_panel_draw;
panel_type->get_list_data_expand_flag = get_filter_expand_flag;
diff --git a/source/blender/editors/space_statusbar/space_statusbar.c b/source/blender/editors/space_statusbar/space_statusbar.c
index bf2a5534e0b..91a85e4c4b0 100644
--- a/source/blender/editors/space_statusbar/space_statusbar.c
+++ b/source/blender/editors/space_statusbar/space_statusbar.c
@@ -144,7 +144,6 @@ static void statusbar_header_region_message_subscribe(const wmRegionMessageSubsc
WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_statusbar(void)
{
SpaceType *st = MEM_callocN(sizeof(*st), "spacetype statusbar");
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 89e92231657..7339d8248c8 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -32,6 +32,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_screen.h"
@@ -302,7 +303,7 @@ static void text_cursor(wmWindow *win, ScrArea *area, ARegion *region)
int wmcursor = WM_CURSOR_TEXT_EDIT;
if (st->text && BLI_rcti_isect_pt(&st->runtime.scroll_region_handle,
- win->eventstate->x - region->winrct.xmin,
+ win->eventstate->xy[0] - region->winrct.xmin,
st->runtime.scroll_region_handle.ymin)) {
wmcursor = WM_CURSOR_DEFAULT;
}
@@ -401,23 +402,16 @@ static void text_properties_region_draw(const bContext *C, ARegion *region)
}
}
-static void text_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void text_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceText *stext = (SpaceText *)slink;
-
- if (!ELEM(GS(old_id->name), ID_TXT)) {
- return;
- }
-
- if ((ID *)stext->text == old_id) {
- stext->text = (Text *)new_id;
- id_us_ensure_real(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&stext->text, ID_REMAP_APPLY_ENSURE_REAL);
}
/********************* registration ********************/
-/* only called once, from space/spacetypes.c */
void ED_spacetype_text(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype text");
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index b541b65d676..8fb55ed9b46 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -70,7 +70,7 @@ static void text_draw_context_init(const SpaceText *st, TextDrawContext *tdc)
static void text_font_begin(const TextDrawContext *tdc)
{
- BLF_size(tdc->font_id, tdc->lheight_px, 72);
+ BLF_size(tdc->font_id, (float)tdc->lheight_px, 72);
}
static void text_font_end(const TextDrawContext *UNUSED(tdc))
@@ -200,7 +200,6 @@ int wrap_width(const SpaceText *st, ARegion *region)
return max > 8 ? max : 8;
}
-/* Sets (offl, offc) for transforming (line, curs) to its wrapped position */
void wrap_offset(
const SpaceText *st, ARegion *region, TextLine *linein, int cursin, int *offl, int *offc)
{
@@ -305,7 +304,6 @@ void wrap_offset(
}
}
-/* cursin - mem, offc - view */
void wrap_offset_in_line(
const SpaceText *st, ARegion *region, TextLine *linein, int cursin, int *offl, int *offc)
{
@@ -1671,7 +1669,7 @@ void draw_text_main(SpaceText *st, ARegion *region)
if (st->showlinenrs && !wrap_skip) {
/* Draw line number. */
- UI_FontThemeColor(tdc.font_id, (tmp == text->curl) ? TH_HILITE : TH_LINENUMBERS);
+ UI_FontThemeColor(tdc.font_id, (tmp == text->sell) ? TH_HILITE : TH_LINENUMBERS);
BLI_snprintf(linenr,
sizeof(linenr),
"%*d",
@@ -1754,8 +1752,6 @@ bool ED_text_activate_in_screen(bContext *C, Text *text)
return false;
}
-/* Moves the view to the cursor location,
- * also used to make sure the view isn't outside the file */
void ED_text_scroll_to_cursor(SpaceText *st, ARegion *region, const bool center)
{
Text *text;
@@ -1823,7 +1819,6 @@ void ED_text_scroll_to_cursor(SpaceText *st, ARegion *region, const bool center)
st->runtime.scroll_ofs_px[1] = 0;
}
-/* takes an area instead of a region, use for listeners */
void text_scroll_to_cursor__area(SpaceText *st, ScrArea *area, const bool center)
{
ARegion *region;
@@ -1847,9 +1842,6 @@ void text_update_cursor_moved(bContext *C)
text_scroll_to_cursor__area(st, area, true);
}
-/**
- * Takes a cursor (row, character) and returns x,y pixel coords.
- */
bool ED_text_region_location_from_cursor(SpaceText *st,
ARegion *region,
const int cursor_co[2],
diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c
index 66765206fa6..cf0a7c089b5 100644
--- a/source/blender/editors/space_text/text_format.c
+++ b/source/blender/editors/space_text/text_format.c
@@ -111,7 +111,6 @@ void flatten_string_free(FlattenString *fs)
}
}
-/* takes a string within fs->buf and returns its length */
int flatten_string_strlen(FlattenString *fs, const char *str)
{
const int len = (fs->pos - (int)(str - fs->buf)) - 1;
@@ -119,8 +118,6 @@ int flatten_string_strlen(FlattenString *fs, const char *str)
return len;
}
-/* Ensures the format string for the given line is long enough, reallocating
- * as needed. Allocation is done here, alone, to ensure consistency. */
int text_check_format_len(TextLine *line, uint len)
{
if (line->format) {
@@ -142,12 +139,6 @@ int text_check_format_len(TextLine *line, uint len)
return 1;
}
-/**
- * Fill the string with formatting constant,
- * advancing \a str_p and \a fmt_p
- *
- * \param len: length in bytes of \a fmt_p to fill.
- */
void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len)
{
const char *str = *str_p;
@@ -170,10 +161,6 @@ void text_format_fill(const char **str_p, char **fmt_p, const char type, const i
*str_p = str;
*fmt_p = fmt;
}
-/**
- * ascii version of #text_format_fill,
- * use when we no the text being stepped over is ascii (as is the case for most keywords)
- */
void text_format_fill_ascii(const char **str_p, char **fmt_p, const char type, const int len)
{
const char *str = *str_p;
diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h
index 833f40730ad..ebccaa54342 100644
--- a/source/blender/editors/space_text/text_format.h
+++ b/source/blender/editors/space_text/text_format.h
@@ -33,7 +33,9 @@ typedef struct FlattenString {
int pos, len;
} FlattenString;
-/* format continuation flags (stored just after the NULL terminator) */
+/**
+ * Format continuation flags (stored just after the NULL terminator).
+ */
enum {
FMT_CONT_NOP = 0, /* no continuation */
FMT_CONT_QUOTESINGLE = (1 << 0), /* single quotes */
@@ -48,11 +50,28 @@ enum {
int flatten_string(const struct SpaceText *st, FlattenString *fs, const char *in);
void flatten_string_free(FlattenString *fs);
+/**
+ * Takes a string within `fs->buf` and returns its length.
+ */
int flatten_string_strlen(FlattenString *fs, const char *str);
+/**
+ * Ensures the format string for the given line is long enough, reallocating
+ * as needed. Allocation is done here, alone, to ensure consistency.
+ */
int text_check_format_len(TextLine *line, unsigned int len);
-void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len);
-void text_format_fill_ascii(const char **str_p, char **fmt_p, const char type, const int len);
+/**
+ * Fill the string with formatting constant,
+ * advancing \a str_p and \a fmt_p
+ *
+ * \param len: length in bytes of \a fmt_p to fill.
+ */
+void text_format_fill(const char **str_p, char **fmt_p, char type, int len);
+/**
+ * ASCII version of #text_format_fill,
+ * use when we no the text being stepped over is ascii (as is the case for most keywords)
+ */
+void text_format_fill_ascii(const char **str_p, char **fmt_p, char type, int len);
/* *** Generalize Formatting *** */
typedef struct TextFormatType {
@@ -69,13 +88,13 @@ typedef struct TextFormatType {
*
* See: FMT_TYPE_ enums below
*/
- void (*format_line)(SpaceText *st, TextLine *line, const bool do_next);
+ void (*format_line)(SpaceText *st, TextLine *line, bool do_next);
const char **ext; /* NULL terminated extensions */
} TextFormatType;
enum {
- /** Whitespace */
+ /** White-space */
FMT_TYPE_WHITESPACE = '_',
/** Comment text */
FMT_TYPE_COMMENT = '#',
@@ -85,7 +104,7 @@ enum {
FMT_TYPE_NUMERAL = 'n',
/** String letters */
FMT_TYPE_STRING = 'l',
- /** Decorator / Preprocessor directive */
+ /** Decorator / Pre-processor directive */
FMT_TYPE_DIRECTIVE = 'd',
/** Special variables (class, def) */
FMT_TYPE_SPECIAL = 'v',
diff --git a/source/blender/editors/space_text/text_format_lua.c b/source/blender/editors/space_text/text_format_lua.c
index 0cd2d9baa0b..cdc43246a2f 100644
--- a/source/blender/editors/space_text/text_format_lua.c
+++ b/source/blender/editors/space_text/text_format_lua.c
@@ -277,7 +277,7 @@ static void txtfmt_lua_format_line(SpaceText *st, TextLine *line, const bool do_
cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
*fmt = FMT_TYPE_STRING;
}
- /* Whitespace (all ws. has been converted to spaces) */
+ /* White-space (all ws. has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
diff --git a/source/blender/editors/space_text/text_format_osl.c b/source/blender/editors/space_text/text_format_osl.c
index 97d9ec546ca..6fc65a19d98 100644
--- a/source/blender/editors/space_text/text_format_osl.c
+++ b/source/blender/editors/space_text/text_format_osl.c
@@ -170,7 +170,7 @@ static int txtfmt_osl_find_preprocessor(const char *string)
{
if (string[0] == '#') {
int i = 1;
- /* Whitespace is ok '# foo' */
+ /* White-space is ok '# foo'. */
while (text_check_whitespace(string[i])) {
i++;
}
@@ -298,7 +298,7 @@ static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const bool do_
cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
*fmt = FMT_TYPE_STRING;
}
- /* Whitespace (all ws. has been converted to spaces) */
+ /* White-space (all ws. has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
diff --git a/source/blender/editors/space_text/text_format_pov.c b/source/blender/editors/space_text/text_format_pov.c
index ea3d0ec1478..0f103351eee 100644
--- a/source/blender/editors/space_text/text_format_pov.c
+++ b/source/blender/editors/space_text/text_format_pov.c
@@ -709,7 +709,7 @@ static int txtfmt_pov_find_bool(const char *string)
/* Keep aligned args for readability. */
/* clang-format off */
- /* Built-in Constants */
+ /* Built-in Constants. */
if (STR_LITERAL_STARTSWITH(string, "unofficial", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "no", len)) { i = len;
@@ -719,7 +719,7 @@ static int txtfmt_pov_find_bool(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "on", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "pi", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "tau", len)) { i = len;
- /* Encodings */
+ /* Encodings. */
} else if (STR_LITERAL_STARTSWITH(string, "sint16be", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "sint16le", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "sint32be", len)) { i = len;
@@ -732,7 +732,7 @@ static int txtfmt_pov_find_bool(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "uint8", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "ascii", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "utf8", len)) { i = len;
- /* Filetypes */
+ /* File-types. */
} else if (STR_LITERAL_STARTSWITH(string, "tiff", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "df3", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "exr", len)) { i = len;
@@ -870,7 +870,7 @@ static void txtfmt_pov_format_line(SpaceText *st, TextLine *line, const bool do_
cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
*fmt = FMT_TYPE_STRING;
}
- /* Whitespace (all ws. has been converted to spaces) */
+ /* White-space (all ws. has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
diff --git a/source/blender/editors/space_text/text_format_pov_ini.c b/source/blender/editors/space_text/text_format_pov_ini.c
index 259ad02a6b7..2ce8bc37868 100644
--- a/source/blender/editors/space_text/text_format_pov_ini.c
+++ b/source/blender/editors/space_text/text_format_pov_ini.c
@@ -279,7 +279,7 @@ static int txtfmt_ini_find_reserved(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "Dither", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "Flags", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "Font", len)) { i = len;
- /* Filetypes */
+ /* File-types. */
} else if (STR_LITERAL_STARTSWITH(string, "df3", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "exr", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "gif", len)) { i = len;
@@ -292,7 +292,7 @@ static int txtfmt_ini_find_reserved(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "sys", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "tga", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "tiff", len)) { i = len;
- /* Encodings */
+ /* Encodings. */
} else if (STR_LITERAL_STARTSWITH(string, "ascii", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "utf8", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "uint8", len)) { i = len;
@@ -448,7 +448,7 @@ static void txtfmt_pov_ini_format_line(SpaceText *st, TextLine *line, const bool
cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
*fmt = FMT_TYPE_STRING;
}
- /* Whitespace (all ws. has been converted to spaces) */
+ /* White-space (all ws. has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c
index e2a01a8d85d..a8a3bfa3a68 100644
--- a/source/blender/editors/space_text/text_format_py.c
+++ b/source/blender/editors/space_text/text_format_py.c
@@ -423,7 +423,7 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, const bool do_n
}
*fmt = FMT_TYPE_STRING;
}
- /* Whitespace (all ws. has been converted to spaces) */
+ /* White-space (all ws. has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index 241e0133a8a..0b81cd74a42 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -39,7 +39,10 @@ void draw_text_main(struct SpaceText *st, struct ARegion *region);
void text_update_line_edited(struct TextLine *line);
void text_update_edited(struct Text *text);
void text_update_character_width(struct SpaceText *st);
-void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *area, const bool center);
+/**
+ * Takes an area instead of a region, use for listeners.
+ */
+void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *area, bool center);
void text_update_cursor_moved(struct bContext *C);
/* Padding around line numbers in character widths. */
@@ -73,12 +76,18 @@ void text_update_cursor_moved(struct bContext *C);
#define TOOL_DOCUMENT 0x02
int wrap_width(const struct SpaceText *st, struct ARegion *region);
+/**
+ * Sets (offl, offc) for transforming (line, curs) to its wrapped position.
+ */
void wrap_offset(const struct SpaceText *st,
struct ARegion *region,
struct TextLine *linein,
int cursin,
int *offl,
int *offc);
+/**
+ * cursin - mem, offc - view.
+ */
void wrap_offset_in_line(const struct SpaceText *st,
struct ARegion *region,
struct TextLine *linein,
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index c3bc474b98a..430ffe6d56f 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -29,6 +29,7 @@
#include "DNA_text_types.h"
#include "BLI_blenlib.h"
+#include "BLI_math.h"
#include "BLI_math_base.h"
#include "BLT_translation.h"
@@ -85,6 +86,30 @@ static void test_line_start(char c, bool *r_last_state)
}
/**
+ * This function receives a character and returns its closing pair if it exists.
+ * \param character: Character to find the closing pair.
+ * \return The closing pair of the character if it exists.
+ */
+static char text_closing_character_pair_get(const char character)
+{
+
+ switch (character) {
+ case '(':
+ return ')';
+ case '[':
+ return ']';
+ case '{':
+ return '}';
+ case '"':
+ return '"';
+ case '\'':
+ return '\'';
+ default:
+ return 0;
+ }
+}
+
+/**
* This function converts the indentation tabs from a buffer to spaces.
* \param in_buf: A pointer to a cstring.
* \param tab_size: The size, in spaces, of the tab character.
@@ -771,7 +796,7 @@ static int text_run_script(bContext *C, ReportList *reports)
/* Don't report error messages while live editing */
if (!is_live) {
- /* text may have freed its self */
+ /* text may have freed itself */
if (CTX_data_edit_text(C) == text) {
if (text->curl != curl_prev || curc_prev != text->curc) {
text_update_cursor_moved(C);
@@ -2402,7 +2427,17 @@ static int text_delete_exec(bContext *C, wmOperator *op)
}
}
}
-
+ if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) {
+ const char *curr = text->curl->line + text->curc;
+ if (*curr != '\0') {
+ const char *prev = BLI_str_find_prev_char_utf8(curr, text->curl->line);
+ if ((curr != prev) && /* When back-spacing from the start of the line. */
+ (*curr == text_closing_character_pair_get(*prev))) {
+ txt_move_right(text, false);
+ txt_backspace_char(text);
+ }
+ }
+ }
txt_backspace_char(text);
}
else if (type == DEL_NEXT_WORD) {
@@ -2592,20 +2627,18 @@ static void text_scroll_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceText *st = CTX_wm_space_text(C);
TextScroll *tsc = op->customdata;
- const int mval[2] = {event->x, event->y};
+ const int mval[2] = {event->xy[0], event->xy[1]};
text_update_character_width(st);
/* compute mouse move distance */
if (tsc->is_first) {
- tsc->mval_prev[0] = mval[0];
- tsc->mval_prev[1] = mval[1];
+ copy_v2_v2_int(tsc->mval_prev, mval);
tsc->is_first = false;
}
if (event->type != MOUSEPAN) {
- tsc->mval_delta[0] = mval[0] - tsc->mval_prev[0];
- tsc->mval_delta[1] = mval[1] - tsc->mval_prev[1];
+ sub_v2_v2v2_int(tsc->mval_delta, mval, tsc->mval_prev);
}
/* accumulate scroll, in float values for events that give less than one
@@ -2757,11 +2790,10 @@ static int text_scroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (event->type == MOUSEPAN) {
text_update_character_width(st);
- tsc->mval_prev[0] = event->x;
- tsc->mval_prev[1] = event->y;
+ copy_v2_v2_int(tsc->mval_prev, event->xy);
/* Sensitivity of scroll set to 4pix per line/char */
- tsc->mval_delta[0] = (event->x - event->prevx) * st->runtime.cwidth_px / 4;
- tsc->mval_delta[1] = (event->y - event->prevy) * st->runtime.lheight_px / 4;
+ tsc->mval_delta[0] = (event->xy[0] - event->prev_xy[0]) * st->runtime.cwidth_px / 4;
+ tsc->mval_delta[1] = (event->xy[1] - event->prev_xy[1]) * st->runtime.lheight_px / 4;
tsc->is_first = false;
tsc->is_scrollbar = false;
text_scroll_apply(C, op, event);
@@ -3445,6 +3477,12 @@ static int text_insert_exec(bContext *C, wmOperator *op)
while (str[i]) {
code = BLI_str_utf8_as_unicode_step(str, str_len, &i);
done |= txt_add_char(text, code);
+ if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) {
+ if (text_closing_character_pair_get(code)) {
+ done |= txt_add_char(text, text_closing_character_pair_get(code));
+ txt_move_left(text, false);
+ }
+ }
}
}
diff --git a/source/blender/editors/space_text/text_undo.c b/source/blender/editors/space_text/text_undo.c
index 80af7d8c9f6..3e40593d40e 100644
--- a/source/blender/editors/space_text/text_undo.c
+++ b/source/blender/editors/space_text/text_undo.c
@@ -252,8 +252,6 @@ static void text_undosys_foreach_ID_ref(UndoStep *us_p,
foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->text_ref));
}
-/* Export for ED_undo_sys. */
-
void ED_text_undosys_type(UndoType *ut)
{
ut->name = "Text";
@@ -276,7 +274,6 @@ void ED_text_undosys_type(UndoType *ut)
/** \name Utilities
* \{ */
-/* Use operator system to finish the undo step. */
UndoStep *ED_text_undo_push_init(bContext *C)
{
UndoStack *ustack = ED_undo_stack_get();
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index 419721cf89e..82a0de9b845 100644
--- a/source/blender/editors/space_topbar/space_topbar.c
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -35,6 +35,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_screen.h"
+#include "BKE_undo_system.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -236,7 +237,64 @@ static void recent_files_menu_register(void)
WM_menutype_add(mt);
}
-/* only called once, from space/spacetypes.c */
+static void undo_history_draw_menu(const bContext *C, Menu *menu)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (wm->undo_stack == NULL) {
+ return;
+ }
+
+ int undo_step_count = 0;
+ int undo_step_count_all = 0;
+ for (UndoStep *us = wm->undo_stack->steps.last; us; us = us->prev) {
+ undo_step_count_all += 1;
+ if (us->skip) {
+ continue;
+ }
+ undo_step_count += 1;
+ }
+
+ uiLayout *split = uiLayoutSplit(menu->layout, 0.0f, false);
+ uiLayout *column = NULL;
+
+ const int col_size = 20 + (undo_step_count / 12);
+
+ undo_step_count = 0;
+
+ /* Reverse the order so the most recent state is first in the menu. */
+ int i = undo_step_count_all - 1;
+ for (UndoStep *us = wm->undo_stack->steps.last; us; us = us->prev, i--) {
+ if (us->skip) {
+ continue;
+ }
+ if (!(undo_step_count % col_size)) {
+ column = uiLayoutColumn(split, false);
+ }
+ const bool is_active = (us == wm->undo_stack->step_active);
+ uiLayout *row = uiLayoutRow(column, false);
+ uiLayoutSetEnabled(row, !is_active);
+ uiItemIntO(row,
+ IFACE_(us->name),
+ is_active ? ICON_LAYER_ACTIVE : ICON_NONE,
+ "ED_OT_undo_history",
+ "item",
+ i);
+ undo_step_count += 1;
+ }
+}
+
+static void undo_history_menu_register(void)
+{
+ MenuType *mt;
+
+ mt = MEM_callocN(sizeof(MenuType), __func__);
+ strcpy(mt->idname, "TOPBAR_MT_undo_history");
+ strcpy(mt->label, N_("Undo History"));
+ strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ mt->draw = undo_history_draw_menu;
+ WM_menutype_add(mt);
+}
+
void ED_spacetype_topbar(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype topbar");
@@ -279,6 +337,7 @@ void ED_spacetype_topbar(void)
BLI_addhead(&st->regiontypes, art);
recent_files_menu_register();
+ undo_history_menu_register();
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index ceba8ca268d..b1ee6da1a33 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -113,9 +113,9 @@ static SpaceLink *userpref_duplicate(SpaceLink *sl)
/* add handlers, stuff you only do once or on area/region changes */
static void userpref_main_region_init(wmWindowManager *wm, ARegion *region)
{
- /* do not use here, the properties changed in userprefs do a system-wide refresh,
+ /* do not use here, the properties changed in user-preferences do a system-wide refresh,
* then scroller jumps back */
- /* region->v2d.flag &= ~V2D_IS_INIT; */
+ // region->v2d.flag &= ~V2D_IS_INIT;
region->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE;
@@ -199,7 +199,6 @@ static void userpref_execute_region_listener(const wmRegionListenerParams *UNUSE
{
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_userpref(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype userpref");
diff --git a/source/blender/editors/space_userpref/userpref_ops.c b/source/blender/editors/space_userpref/userpref_ops.c
index 63506678b70..d40229332fd 100644
--- a/source/blender/editors/space_userpref/userpref_ops.c
+++ b/source/blender/editors/space_userpref/userpref_ops.c
@@ -24,6 +24,7 @@
#include <string.h>
#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "BLI_listbase.h"
#ifdef WIN32
@@ -139,23 +140,51 @@ static void PREFERENCES_OT_autoexec_path_remove(wmOperatorType *ot)
/** \name Add Asset Library Operator
* \{ */
-static int preferences_asset_library_add_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+static int preferences_asset_library_add_exec(bContext *UNUSED(C), wmOperator *op)
{
- BKE_preferences_asset_library_add(&U, NULL, NULL);
+ char *directory = RNA_string_get_alloc(op->ptr, "directory", NULL, 0, NULL);
+
+ /* NULL is a valid directory path here. A library without path will be created then. */
+ BKE_preferences_asset_library_add(&U, NULL, directory);
U.runtime.is_dirty = true;
+
+ /* There's no dedicated notifier for the Preferences. */
+ WM_main_add_notifier(NC_WINDOW, NULL);
+
+ MEM_freeN(directory);
return OPERATOR_FINISHED;
}
+static int preferences_asset_library_add_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ if (!RNA_struct_property_is_set(op->ptr, "directory")) {
+ WM_event_add_fileselect(C, op);
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ return preferences_asset_library_add_exec(C, op);
+}
+
static void PREFERENCES_OT_asset_library_add(wmOperatorType *ot)
{
ot->name = "Add Asset Library";
ot->idname = "PREFERENCES_OT_asset_library_add";
- ot->description =
- "Add a path to a .blend file to be used by the Asset Browser as source of assets";
+ ot->description = "Add a directory to be used by the Asset Browser as source of assets";
ot->exec = preferences_asset_library_add_exec;
+ ot->invoke = preferences_asset_library_add_invoke;
ot->flag = OPTYPE_INTERNAL;
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER,
+ FILE_SPECIAL,
+ FILE_OPENFILE,
+ WM_FILESEL_DIRECTORY,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_DEFAULT);
}
/** \} */
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index fe84a3b8ae9..19f869ed50b 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -44,6 +44,7 @@ set(SRC
space_view3d.c
view3d_buttons.c
view3d_camera_control.c
+ view3d_cursor_snap.c
view3d_draw.c
view3d_edit.c
view3d_gizmo_armature.c
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 6b9da431510..48f39f835c5 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -48,58 +48,6 @@
#include "view3d_intern.h" /* bad level include */
-/* OpenGL Circle Drawing - Tables for Optimized Drawing Speed */
-/* 32 values of sin function (still same result!) */
-#define CIRCLE_RESOL 32
-
-static const float sinval[CIRCLE_RESOL] = {
- 0.00000000, 0.20129852, 0.39435585, 0.57126821, 0.72479278, 0.84864425, 0.93775213,
- 0.98846832, 0.99871650, 0.96807711, 0.89780453, 0.79077573, 0.65137248, 0.48530196,
- 0.29936312, 0.10116832, -0.10116832, -0.29936312, -0.48530196, -0.65137248, -0.79077573,
- -0.89780453, -0.96807711, -0.99871650, -0.98846832, -0.93775213, -0.84864425, -0.72479278,
- -0.57126821, -0.39435585, -0.20129852, 0.00000000,
-};
-
-/* 32 values of cos function (still same result!) */
-static const float cosval[CIRCLE_RESOL] = {
- 1.00000000, 0.97952994, 0.91895781, 0.82076344, 0.68896691, 0.52896401, 0.34730525,
- 0.15142777, -0.05064916, -0.25065253, -0.44039415, -0.61210598, -0.75875812, -0.87434661,
- -0.95413925, -0.99486932, -0.99486932, -0.95413925, -0.87434661, -0.75875812, -0.61210598,
- -0.44039415, -0.25065253, -0.05064916, 0.15142777, 0.34730525, 0.52896401, 0.68896691,
- 0.82076344, 0.91895781, 0.97952994, 1.00000000,
-};
-
-static void circball_array_fill(const float verts[CIRCLE_RESOL][3],
- const float cent[3],
- float rad,
- const float tmat[4][4])
-{
- float vx[3], vy[3];
- float *viter = (float *)verts;
-
- mul_v3_v3fl(vx, tmat[0], rad);
- mul_v3_v3fl(vy, tmat[1], rad);
-
- for (uint a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
- viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
- viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1];
- viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2];
- }
-}
-
-void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], uint pos)
-{
- float verts[CIRCLE_RESOL][3];
-
- circball_array_fill(verts, cent, rad, tmat);
-
- immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL);
- for (int i = 0; i < CIRCLE_RESOL; i++) {
- immVertex3fv(pos, verts[i]);
- }
- immEnd();
-}
-
#ifdef VIEW3D_CAMERA_BORDER_HACK
uchar view3d_camera_border_hack_col[3];
bool view3d_camera_border_hack_test = false;
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index f68a4d78a00..0a5bebac8a8 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -30,6 +30,7 @@
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
#include "MEM_guardedalloc.h"
@@ -39,12 +40,15 @@
#include "BLT_translation.h"
+#include "BKE_asset.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_lattice.h"
+#include "BKE_layer.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
@@ -54,6 +58,7 @@
#include "BKE_workspace.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_render.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -81,12 +86,12 @@
#endif
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "view3d_intern.h" /* own include */
/* ******************** manage regions ********************* */
-/* function to always find a regionview3d context inside 3D window */
RegionView3D *ED_view3d_context_rv3d(bContext *C)
{
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -103,8 +108,6 @@ RegionView3D *ED_view3d_context_rv3d(bContext *C)
return rv3d;
}
-/* ideally would return an rv3d but in some cases the region is needed too
- * so return that, the caller can then access the region->regiondata */
bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_region)
{
ScrArea *area = CTX_wm_area(C);
@@ -135,10 +138,6 @@ bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_regi
return false;
}
-/**
- * Similar to #ED_view3d_context_user_region() but does not use context. Always performs a lookup.
- * Also works if \a v3d is not the active space.
- */
bool ED_view3d_area_user_region(const ScrArea *area, const View3D *v3d, ARegion **r_region)
{
RegionView3D *rv3d = NULL;
@@ -177,17 +176,6 @@ bool ED_view3d_area_user_region(const ScrArea *area, const View3D *v3d, ARegion
return false;
}
-/* Most of the time this isn't needed since you could assume the view matrix was
- * set while drawing, however when functions like mesh_foreachScreenVert are
- * called by selection tools, we can't be sure this object was the last.
- *
- * for example, transparent objects are drawn after editmode and will cause
- * the rv3d mat's to change and break selection.
- *
- * 'ED_view3d_init_mats_rv3d' should be called before
- * view3d_project_short_clip and view3d_project_short_noclip in cases where
- * these functions are not used during draw_object
- */
void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d)
{
/* local viewmat and persmat, to calculate projections */
@@ -209,7 +197,6 @@ void ED_view3d_init_mats_rv3d_gl(const struct Object *ob, struct RegionView3D *r
}
#ifdef DEBUG
-/* ensure we correctly initialize */
void ED_view3d_clear_mats_rv3d(struct RegionView3D *rv3d)
{
zero_m4(rv3d->viewmatob);
@@ -473,7 +460,7 @@ static void view3d_main_region_exit(wmWindowManager *wm, ARegion *region)
static bool view3d_drop_in_main_region_poll(bContext *C, const wmEvent *event)
{
ScrArea *area = CTX_wm_area(C);
- return ED_region_overlap_isect_any_xy(area, &event->x) == false;
+ return ED_region_overlap_isect_any_xy(area, event->xy) == false;
}
static ID_Type view3d_drop_id_in_main_region_poll_get_id_type(bContext *C,
@@ -482,7 +469,7 @@ static ID_Type view3d_drop_id_in_main_region_poll_get_id_type(bContext *C,
{
const ScrArea *area = CTX_wm_area(C);
- if (ED_region_overlap_isect_any_xy(area, &event->x)) {
+ if (ED_region_overlap_isect_any_xy(area, event->xy)) {
return 0;
}
if (!view3d_drop_in_main_region_poll(C, event)) {
@@ -514,10 +501,74 @@ static bool view3d_drop_id_in_main_region_poll(bContext *C,
return WM_drag_is_ID_type(drag, id_type);
}
+static void view3d_ob_drop_draw_activate(struct wmDropBox *drop, wmDrag *drag)
+{
+ V3DSnapCursorState *state = drop->draw_data;
+ if (state) {
+ return;
+ }
+
+ /* Don't use the snap cursor when linking the object. Object transform isn't editable then and
+ * would be reset on reload. */
+ if (WM_drag_asset_will_import_linked(drag)) {
+ return;
+ }
+
+ state = drop->draw_data = ED_view3d_cursor_snap_active();
+ state->draw_plane = true;
+
+ float dimensions[3] = {0.0f};
+ if (drag->type == WM_DRAG_ID) {
+ Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB);
+ BKE_object_dimensions_get(ob, dimensions);
+ }
+ else {
+ struct AssetMetaData *meta_data = WM_drag_get_asset_meta_data(drag, ID_OB);
+ IDProperty *dimensions_prop = BKE_asset_metadata_idprop_find(meta_data, "dimensions");
+ if (dimensions_prop) {
+ copy_v3_v3(dimensions, IDP_Array(dimensions_prop));
+ }
+ }
+
+ if (!is_zero_v3(dimensions)) {
+ mul_v3_v3fl(state->box_dimensions, dimensions, 0.5f);
+ UI_GetThemeColor4ubv(TH_GIZMO_PRIMARY, state->color_box);
+ state->draw_box = true;
+ }
+}
+
+static void view3d_ob_drop_draw_deactivate(struct wmDropBox *drop, wmDrag *UNUSED(drag))
+{
+ V3DSnapCursorState *state = drop->draw_data;
+ if (state) {
+ ED_view3d_cursor_snap_deactive(state);
+ drop->draw_data = NULL;
+ }
+}
+
static bool view3d_ob_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
return view3d_drop_id_in_main_region_poll(C, drag, event, ID_OB);
}
+static bool view3d_ob_drop_poll_external_asset(bContext *C, wmDrag *drag, const wmEvent *event)
+{
+ if (!view3d_ob_drop_poll(C, drag, event) || (drag->type != WM_DRAG_ASSET)) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * \note the term local here refers to not being an external asset,
+ * poll will succeed for linked library objects.
+ */
+static bool view3d_ob_drop_poll_local_id(bContext *C, wmDrag *drag, const wmEvent *event)
+{
+ if (!view3d_ob_drop_poll(C, drag, event) || (drag->type != WM_DRAG_ID)) {
+ return false;
+ }
+ return true;
+}
static bool view3d_collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
@@ -531,12 +582,17 @@ static bool view3d_mat_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
static char *view3d_mat_drop_tooltip(bContext *C,
wmDrag *drag,
- const wmEvent *event,
+ const int xy[2],
struct wmDropBox *drop)
{
const char *name = WM_drag_get_item_name(drag);
+ ARegion *region = CTX_wm_region(C);
RNA_string_set(drop->ptr, "name", name);
- return ED_object_ot_drop_named_material_tooltip(C, drop->ptr, event);
+ int mval[2] = {
+ xy[0] - region->winrct.xmin,
+ xy[1] - region->winrct.ymin,
+ };
+ return ED_object_ot_drop_named_material_tooltip(C, drop->ptr, mval);
}
static bool view3d_world_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
@@ -555,7 +611,7 @@ static bool view3d_object_data_drop_poll(bContext *C, wmDrag *drag, const wmEven
static char *view3d_object_data_drop_tooltip(bContext *UNUSED(C),
wmDrag *UNUSED(drag),
- const wmEvent *UNUSED(event),
+ const int UNUSED(xy[2]),
wmDropBox *UNUSED(drop))
{
return BLI_strdup(TIP_("Create object instance from object-data"));
@@ -563,7 +619,7 @@ static char *view3d_object_data_drop_tooltip(bContext *UNUSED(C),
static bool view3d_ima_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
- if (ED_region_overlap_isect_any_xy(CTX_wm_area(C), &event->x)) {
+ if (ED_region_overlap_isect_any_xy(CTX_wm_area(C), event->xy)) {
return false;
}
if (drag->type == WM_DRAG_PATH) {
@@ -625,19 +681,92 @@ static bool view3d_volume_drop_poll(bContext *UNUSED(C),
return (drag->type == WM_DRAG_PATH) && (drag->icon == ICON_FILE_VOLUME);
}
-static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop)
+static void view3d_ob_drop_matrix_from_snap(V3DSnapCursorState *snap_state,
+ Object *ob,
+ float obmat_final[4][4])
+{
+ V3DSnapCursorData *snap_data;
+ snap_data = ED_view3d_cursor_snap_data_get(snap_state, NULL, 0, 0);
+ BLI_assert(snap_state->draw_box || snap_state->draw_plane);
+ copy_m4_m3(obmat_final, snap_data->plane_omat);
+ copy_v3_v3(obmat_final[3], snap_data->loc);
+
+ float scale[3];
+ mat4_to_size(scale, ob->obmat);
+ rescale_m4(obmat_final, scale);
+
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ if (bb) {
+ float offset[3];
+ BKE_boundbox_calc_center_aabb(bb, offset);
+ offset[2] = bb->vec[0][2];
+ mul_mat3_m4_v3(obmat_final, offset);
+ sub_v3_v3(obmat_final[3], offset);
+ }
+}
+
+static void view3d_ob_drop_copy_local_id(wmDrag *drag, wmDropBox *drop)
{
- ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, ID_OB);
+ ID *id = WM_drag_get_local_ID(drag, ID_OB);
RNA_string_set(drop->ptr, "name", id->name + 2);
- RNA_boolean_set(drop->ptr, "duplicate", false);
+ /* Don't duplicate ID's which were just imported. Only do that for existing, local IDs. */
+ BLI_assert(drag->type != WM_DRAG_ASSET);
+
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ float obmat_final[4][4];
+
+ view3d_ob_drop_matrix_from_snap(snap_state, (Object *)id, obmat_final);
+
+ RNA_float_set_array(drop->ptr, "matrix", &obmat_final[0][0]);
+}
+
+static void view3d_ob_drop_copy_external_asset(wmDrag *drag, wmDropBox *drop)
+{
+ /* NOTE(@campbellbarton): Selection is handled here, de-selecting objects before append,
+ * using auto-select to ensure the new objects are selected.
+ * This is done so #OBJECT_OT_transform_to_mouse (which runs after this drop handler)
+ * can use the context setup here to place the objects. */
+ BLI_assert(drag->type == WM_DRAG_ASSET);
+
+ wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, 0);
+ bContext *C = asset_drag->evil_C;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ BKE_view_layer_base_deselect_all(view_layer);
+
+ ID *id = WM_drag_asset_id_import(asset_drag, FILE_AUTOSELECT);
+
+ /* TODO(sergey): Only update relations for the current scene. */
+ DEG_relations_tag_update(CTX_data_main(C));
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
+
+ RNA_string_set(drop->ptr, "name", id->name + 2);
+
+ Base *base = BKE_view_layer_base_find(view_layer, (Object *)id);
+ if (base != NULL) {
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
+ WM_main_add_notifier(NC_SCENE | ND_OB_ACTIVE, scene);
+ }
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_object_tag(C);
+
+ V3DSnapCursorState *snap_state = drop->draw_data;
+ if (snap_state) {
+ float obmat_final[4][4];
+
+ view3d_ob_drop_matrix_from_snap(snap_state, (Object *)id, obmat_final);
+
+ RNA_float_set_array(drop->ptr, "matrix", &obmat_final[0][0]);
+ }
}
static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, ID_GR);
- RNA_string_set(drop->ptr, "name", id->name + 2);
+ RNA_int_set(drop->ptr, "session_uuid", (int)id->session_uuid);
}
static void view3d_id_drop_copy(wmDrag *drag, wmDropBox *drop)
@@ -695,12 +824,29 @@ static void view3d_dropboxes(void)
{
ListBase *lb = WM_dropboxmap_find("View3D", SPACE_VIEW3D, RGN_TYPE_WINDOW);
- WM_dropbox_add(lb,
- "OBJECT_OT_add_named",
- view3d_ob_drop_poll,
- view3d_ob_drop_copy,
- WM_drag_free_imported_drag_ID,
- NULL);
+ struct wmDropBox *drop;
+ drop = WM_dropbox_add(lb,
+ "OBJECT_OT_add_named",
+ view3d_ob_drop_poll_local_id,
+ view3d_ob_drop_copy_local_id,
+ WM_drag_free_imported_drag_ID,
+ NULL);
+
+ drop->draw = WM_drag_draw_item_name_fn;
+ drop->draw_activate = view3d_ob_drop_draw_activate;
+ drop->draw_deactivate = view3d_ob_drop_draw_deactivate;
+
+ drop = WM_dropbox_add(lb,
+ "OBJECT_OT_transform_to_mouse",
+ view3d_ob_drop_poll_external_asset,
+ view3d_ob_drop_copy_external_asset,
+ WM_drag_free_imported_drag_ID,
+ NULL);
+
+ drop->draw = WM_drag_draw_item_name_fn;
+ drop->draw_activate = view3d_ob_drop_draw_activate;
+ drop->draw_deactivate = view3d_ob_drop_draw_deactivate;
+
WM_dropbox_add(lb,
"OBJECT_OT_drop_named_material",
view3d_mat_drop_poll,
@@ -1130,6 +1276,7 @@ static void view3d_main_region_message_subscribe(const wmRegionMessageSubscribeP
&RNA_Object,
&RNA_UnitSettings, /* grid-floor */
+ &RNA_View3DCursor,
&RNA_View3DOverlay,
&RNA_View3DShading,
&RNA_World,
@@ -1567,10 +1714,7 @@ static void space_view3d_listener(const wmSpaceTypeListenerParams *params)
case NC_SCENE:
switch (wmn->data) {
case ND_WORLD: {
- const bool use_scene_world = ((v3d->shading.type == OB_MATERIAL) &&
- (v3d->shading.flag & V3D_SHADING_SCENE_WORLD)) ||
- ((v3d->shading.type == OB_RENDER) &&
- (v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER));
+ const bool use_scene_world = V3D_USES_SCENE_WORLD(v3d);
if (v3d->flag2 & V3D_HIDE_OVERLAYS || use_scene_world) {
ED_area_tag_redraw_regiontype(area, RGN_TYPE_WINDOW);
}
@@ -1616,6 +1760,7 @@ static void space_view3d_refresh(const bContext *C, ScrArea *area)
const char *view3d_context_dir[] = {
"active_object",
+ "selected_ids",
NULL,
};
@@ -1626,8 +1771,9 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, view3d_context_dir);
+ return CTX_RESULT_OK;
}
- else if (CTX_data_equals(member, "active_object")) {
+ if (CTX_data_equals(member, "active_object")) {
/* In most cases the active object is the `view_layer->basact->object`.
* For the 3D view however it can be NULL when hidden.
*
@@ -1651,63 +1797,74 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
}
}
- return 1;
+ return CTX_RESULT_OK;
}
- else {
- return 0; /* not found */
+ if (CTX_data_equals(member, "selected_ids")) {
+ ListBase selected_objects;
+ CTX_data_selected_objects(C, &selected_objects);
+ LISTBASE_FOREACH (CollectionPointerLink *, object_ptr_link, &selected_objects) {
+ ID *selected_id = object_ptr_link->ptr.owner_id;
+ CTX_data_id_list_add(result, selected_id);
+ }
+ BLI_freelistN(&selected_objects);
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return CTX_RESULT_OK;
}
- return -1; /* found but not available */
+ return CTX_RESULT_MEMBER_NOT_FOUND;
}
-static void view3d_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id)
+static void view3d_id_remap_v3d_ob_centers(View3D *v3d, const struct IDRemapper *mappings)
{
- View3D *v3d;
- ARegion *region;
- bool is_local = false;
-
- if (!ELEM(GS(old_id->name), ID_OB, ID_MA, ID_IM, ID_MC)) {
- return;
+ if (BKE_id_remapper_apply(mappings, (ID **)&v3d->ob_center, ID_REMAP_APPLY_DEFAULT) ==
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
+ /* Otherwise, bonename may remain valid...
+ * We could be smart and check this, too? */
+ v3d->ob_center_bone[0] = '\0';
}
+}
- for (v3d = (View3D *)slink; v3d; v3d = v3d->localvd, is_local = true) {
- if ((ID *)v3d->camera == old_id) {
- v3d->camera = (Object *)new_id;
- if (!new_id) {
- /* 3D view might be inactive, in that case needs to use slink->regionbase */
- ListBase *regionbase = (slink == area->spacedata.first) ? &area->regionbase :
- &slink->regionbase;
- for (region = regionbase->first; region; region = region->next) {
- if (region->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d = is_local ? ((RegionView3D *)region->regiondata)->localvd :
- region->regiondata;
- if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
- rv3d->persp = RV3D_PERSP;
- }
- }
+static void view3d_id_remap_v3d(ScrArea *area,
+ SpaceLink *slink,
+ View3D *v3d,
+ const struct IDRemapper *mappings,
+ const bool is_local)
+{
+ ARegion *region;
+ if (BKE_id_remapper_apply(mappings, (ID **)&v3d->camera, ID_REMAP_APPLY_DEFAULT) ==
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
+ /* 3D view might be inactive, in that case needs to use slink->regionbase */
+ ListBase *regionbase = (slink == area->spacedata.first) ? &area->regionbase :
+ &slink->regionbase;
+ for (region = regionbase->first; region; region = region->next) {
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = is_local ? ((RegionView3D *)region->regiondata)->localvd :
+ region->regiondata;
+ if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
+ rv3d->persp = RV3D_PERSP;
}
}
}
+ }
+}
- /* Values in local-view aren't used, see: T52663 */
- if (is_local == false) {
- if ((ID *)v3d->ob_center == old_id) {
- v3d->ob_center = (Object *)new_id;
- /* Otherwise, bonename may remain valid...
- * We could be smart and check this, too? */
- if (new_id == NULL) {
- v3d->ob_center_bone[0] = '\0';
- }
- }
- }
+static void view3d_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRemapper *mappings)
+{
- if (is_local) {
- break;
- }
+ if (!BKE_id_remapper_has_mapping_for(
+ mappings, FILTER_ID_OB | FILTER_ID_MA | FILTER_ID_IM | FILTER_ID_MC)) {
+ return;
+ }
+
+ View3D *view3d = (View3D *)slink;
+ view3d_id_remap_v3d(area, slink, view3d, mappings, false);
+ view3d_id_remap_v3d_ob_centers(view3d, mappings);
+ if (view3d->localvd != NULL) {
+ /* Object centers in local-view aren't used, see: T52663 */
+ view3d_id_remap_v3d(area, slink, view3d->localvd, mappings, true);
}
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_view3d(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype view3d");
@@ -1798,5 +1955,10 @@ void ED_spacetype_view3d(void)
art = ED_area_type_hud(st->spaceid);
BLI_addhead(&st->regiontypes, art);
+ /* regions: xr */
+ art = MEM_callocN(sizeof(ARegionType), "spacetype view3d xr region");
+ art->regionid = RGN_TYPE_XR;
+ BLI_addhead(&st->regiontypes, art);
+
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index b79303551a1..243d4033cbc 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -87,7 +87,7 @@ typedef struct {
} TransformMedian_Generic;
typedef struct {
- float location[3], bv_weight, be_weight, skin[2], crease;
+ float location[3], bv_weight, v_crease, be_weight, skin[2], e_crease;
} TransformMedian_Mesh;
typedef struct {
@@ -319,6 +319,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
BMIter iter;
const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
+ const int cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
@@ -335,6 +336,10 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
median->bv_weight += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_bweight_offset);
}
+ if (cd_vert_crease_offset != -1) {
+ median->v_crease += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_crease_offset);
+ }
+
if (has_skinradius) {
MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
add_v2_v2(median->skin, vs->radius); /* Third val not used currently. */
@@ -352,7 +357,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
if (cd_edge_crease_offset != -1) {
- median->crease += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset);
+ median->e_crease += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset);
}
totedgedata++;
@@ -489,11 +494,12 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
if (has_meshdata) {
TransformMedian_Mesh *median = &median_basis.mesh;
if (totedgedata) {
- median->crease /= (float)totedgedata;
+ median->e_crease /= (float)totedgedata;
median->be_weight /= (float)totedgedata;
}
if (tot) {
median->bv_weight /= (float)tot;
+ median->v_crease /= (float)tot;
if (has_skinradius) {
median->skin[0] /= (float)tot;
median->skin[1] /= (float)tot;
@@ -683,6 +689,23 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
TIP_("Vertex weight used by Bevel modifier"));
UI_but_number_step_size_set(but, 1);
UI_but_number_precision_set(but, 2);
+ /* customdata layer added on demand */
+ but = uiDefButF(block,
+ UI_BTYPE_NUM,
+ B_TRANSFORM_PANEL_MEDIAN,
+ tot == 1 ? IFACE_("Vertex Crease:") : IFACE_("Mean Vertex Crease:"),
+ 0,
+ yi -= buth + but_margin,
+ butw,
+ buth,
+ &ve_median->v_crease,
+ 0.0,
+ 1.0,
+ 0,
+ 0,
+ TIP_("Weight used by the Subdivision Surface modifier"));
+ UI_but_number_step_size_set(but, 1);
+ UI_but_number_precision_set(but, 2);
}
if (has_skinradius) {
UI_block_align_begin(block);
@@ -761,7 +784,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
yi -= buth + but_margin,
butw,
buth,
- &ve_median->crease,
+ &ve_median->e_crease,
0.0,
1.0,
0,
@@ -958,8 +981,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
const bool apply_vcos = (tot == 1) || (len_squared_v3(median_basis.generic.location) != 0.0f);
if ((ob->type == OB_MESH) &&
- (apply_vcos || median_basis.mesh.bv_weight || median_basis.mesh.skin[0] ||
- median_basis.mesh.skin[1] || median_basis.mesh.be_weight || median_basis.mesh.crease)) {
+ (apply_vcos || median_basis.mesh.bv_weight || median_basis.mesh.v_crease ||
+ median_basis.mesh.skin[0] || median_basis.mesh.skin[1] || median_basis.mesh.be_weight ||
+ median_basis.mesh.e_crease)) {
const TransformMedian_Mesh *median = &median_basis.mesh, *ve_median = &ve_median_basis.mesh;
Mesh *me = ob->data;
BMEditMesh *em = me->edit_mesh;
@@ -969,18 +993,21 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
BMEdge *eed;
int cd_vert_bweight_offset = -1;
+ int cd_vert_crease_offset = -1;
int cd_vert_skin_offset = -1;
int cd_edge_bweight_offset = -1;
int cd_edge_crease_offset = -1;
float scale_bv_weight = 1.0f;
+ float scale_v_crease = 1.0f;
float scale_skin[2] = {1.0f, 1.0f};
float scale_be_weight = 1.0f;
- float scale_crease = 1.0f;
+ float scale_e_crease = 1.0f;
/* Vertices */
- if (apply_vcos || median->bv_weight || median->skin[0] || median->skin[1]) {
+ if (apply_vcos || median->bv_weight || median->v_crease || median->skin[0] ||
+ median->skin[1]) {
if (median->bv_weight) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT);
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
@@ -989,6 +1016,14 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
scale_bv_weight = compute_scale_factor(ve_median->bv_weight, median->bv_weight);
}
+ if (median->v_crease) {
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_CREASE);
+ cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
+ BLI_assert(cd_vert_crease_offset != -1);
+
+ scale_v_crease = compute_scale_factor(ve_median->v_crease, median->v_crease);
+ }
+
for (int i = 0; i < 2; i++) {
if (median->skin[i]) {
cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
@@ -1011,6 +1046,11 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
apply_scale_factor_clamp(b_weight, tot, ve_median->bv_weight, scale_bv_weight);
}
+ if (cd_vert_crease_offset != -1) {
+ float *crease = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset);
+ apply_scale_factor_clamp(crease, tot, ve_median->v_crease, scale_v_crease);
+ }
+
if (cd_vert_skin_offset != -1) {
MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
@@ -1033,7 +1073,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
/* Edges */
- if (median->be_weight || median->crease) {
+ if (median->be_weight || median->e_crease) {
if (median->be_weight) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
@@ -1042,12 +1082,12 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
scale_be_weight = compute_scale_factor(ve_median->be_weight, median->be_weight);
}
- if (median->crease) {
+ if (median->e_crease) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
BLI_assert(cd_edge_crease_offset != -1);
- scale_crease = compute_scale_factor(ve_median->crease, median->crease);
+ scale_e_crease = compute_scale_factor(ve_median->e_crease, median->e_crease);
}
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
@@ -1057,9 +1097,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
apply_scale_factor_clamp(b_weight, tot, ve_median->be_weight, scale_be_weight);
}
- if (median->crease != 0.0f) {
+ if (median->e_crease != 0.0f) {
float *crease = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset);
- apply_scale_factor_clamp(crease, tot, ve_median->crease, scale_crease);
+ apply_scale_factor_clamp(crease, tot, ve_median->e_crease, scale_e_crease);
}
}
}
@@ -1552,7 +1592,7 @@ static void v3d_posearmature_buts(uiLayout *layout, Object *ob)
PointerRNA pchanptr;
uiLayout *col;
- pchan = BKE_pose_channel_active(ob);
+ pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (!pchan) {
uiItemL(layout, IFACE_("No Bone Active"), ICON_NONE);
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index 8380c87b999..535a65c8f0c 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -102,9 +102,6 @@ BLI_INLINE Object *view3d_cameracontrol_object(const View3DCameraControl *vctrl)
return vctrl->root_parent ? vctrl->root_parent : vctrl->ctx_v3d->camera;
}
-/**
- * Returns the object which is being manipulated or NULL.
- */
Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
{
RegionView3D *rv3d = vctrl->ctx_rv3d;
@@ -116,10 +113,6 @@ Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
return NULL;
}
-/**
- * Creates a #View3DCameraControl handle and sets up
- * the view for first-person style navigation.
- */
struct View3DCameraControl *ED_view3d_cameracontrol_acquire(Depsgraph *depsgraph,
Scene *scene,
View3D *v3d,
@@ -243,9 +236,6 @@ static bool object_apply_mat4_with_protect(Object *ob,
return view_changed;
}
-/**
- * Updates cameras from the `rv3d` values, optionally auto-keyframing.
- */
void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl,
/* args for keyframing */
const bool use_autokey,
@@ -317,12 +307,6 @@ void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl,
}
}
-/**
- * Release view control.
- *
- * \param restore: Sets the view state to the values that were set
- * before #ED_view3d_control_acquire was called.
- */
void ED_view3d_cameracontrol_release(View3DCameraControl *vctrl, const bool restore)
{
View3D *v3d = vctrl->ctx_v3d;
diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c
new file mode 100644
index 00000000000..f5abba2c674
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c
@@ -0,0 +1,1017 @@
+/*
+ * 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) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup wm
+ *
+ * \brief Snap cursor.
+ */
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_rect.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+
+#include "ED_screen.h"
+#include "ED_transform.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "WM_api.h"
+
+#define STATE_INTERN_GET(state) \
+ (SnapStateIntern *)((char *)state - offsetof(SnapStateIntern, snap_state))
+
+typedef struct SnapStateIntern {
+ struct SnapStateIntern *next, *prev;
+ V3DSnapCursorState snap_state;
+} SnapStateIntern;
+
+typedef struct SnapCursorDataIntern {
+ V3DSnapCursorState state_default;
+ ListBase state_intern;
+ V3DSnapCursorData snap_data;
+
+ struct SnapObjectContext *snap_context_v3d;
+ const Scene *scene;
+ short snap_elem_hidden;
+
+ float prevpoint_stack[3];
+
+ /* Copy of the parameters of the last event state in order to detect updates. */
+ struct {
+ int x;
+ int y;
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ short shift, ctrl, alt, oskey;
+#endif
+ } last_eventstate;
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ struct wmKeyMap *keymap;
+ int snap_on;
+#endif
+
+ struct wmPaintCursor *handle;
+
+ bool is_initiated;
+} SnapCursorDataIntern;
+
+static SnapCursorDataIntern g_data_intern = {
+ .state_default = {.flag = V3D_SNAPCURSOR_SNAP_EDIT_GEOM_FINAL,
+ .snap_elem_force = SCE_SNAP_MODE_GEOM,
+ .plane_axis = 2,
+ .color_point = {255, 255, 255, 255},
+ .color_line = {255, 255, 255, 128},
+ .color_box = {255, 255, 255, 128},
+ .box_dimensions = {1.0f, 1.0f, 1.0f},
+ .draw_point = true}};
+
+/**
+ * Dot products below this will be considered view aligned.
+ * In this case we can't usefully project the mouse cursor onto the plane.
+ */
+static const float eps_view_align = 1e-2f;
+
+/**
+ * Calculate a 3x3 orientation matrix from the surface under the cursor.
+ */
+static void v3d_cursor_poject_surface_normal(const float normal[3],
+ const float obmat[4][4],
+ float r_mat[3][3])
+{
+ float mat[3][3];
+ copy_m3_m4(mat, obmat);
+ normalize_m3(mat);
+
+ float dot_best = fabsf(dot_v3v3(mat[0], normal));
+ int i_best = 0;
+ for (int i = 1; i < 3; i++) {
+ float dot_test = fabsf(dot_v3v3(mat[i], normal));
+ if (dot_test > dot_best) {
+ i_best = i;
+ dot_best = dot_test;
+ }
+ }
+ if (dot_v3v3(mat[i_best], normal) < 0.0f) {
+ negate_v3(mat[(i_best + 1) % 3]);
+ negate_v3(mat[(i_best + 2) % 3]);
+ }
+ copy_v3_v3(mat[i_best], normal);
+ orthogonalize_m3(mat, i_best);
+ normalize_m3(mat);
+
+ copy_v3_v3(r_mat[0], mat[(i_best + 1) % 3]);
+ copy_v3_v3(r_mat[1], mat[(i_best + 2) % 3]);
+ copy_v3_v3(r_mat[2], mat[i_best]);
+}
+
+/**
+ * Calculate 3D view incremental (grid) snapping.
+ *
+ * \note This could be moved to a public function.
+ */
+static bool v3d_cursor_snap_calc_incremental(
+ Scene *scene, View3D *v3d, ARegion *region, const float co_relative[3], float co[3])
+{
+ const float grid_size = ED_view3d_grid_view_scale(scene, v3d, region, NULL);
+ if (UNLIKELY(grid_size == 0.0f)) {
+ return false;
+ }
+
+ if (scene->toolsettings->snap_flag & SCE_SNAP_ABS_GRID) {
+ co_relative = NULL;
+ }
+
+ if (co_relative != NULL) {
+ sub_v3_v3(co, co_relative);
+ }
+ mul_v3_fl(co, 1.0f / grid_size);
+ co[0] = roundf(co[0]);
+ co[1] = roundf(co[1]);
+ co[2] = roundf(co[2]);
+ mul_v3_fl(co, grid_size);
+ if (co_relative != NULL) {
+ add_v3_v3(co, co_relative);
+ }
+
+ return true;
+}
+
+/**
+ * Re-order \a mat so \a axis_align uses its own axis which is closest to \a v.
+ */
+static bool mat3_align_axis_to_v3(float mat[3][3], const int axis_align, const float v[3])
+{
+ float dot_best = -1.0f;
+ int axis_found = axis_align;
+ for (int i = 0; i < 3; i++) {
+ const float dot_test = fabsf(dot_v3v3(mat[i], v));
+ if (dot_test > dot_best) {
+ dot_best = dot_test;
+ axis_found = i;
+ }
+ }
+
+ if (axis_align != axis_found) {
+ float tmat[3][3];
+ copy_m3_m3(tmat, mat);
+ const int offset = mod_i(axis_found - axis_align, 3);
+ for (int i = 0; i < 3; i++) {
+ copy_v3_v3(mat[i], tmat[(i + offset) % 3]);
+ }
+ return true;
+ }
+ return false;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Drawings
+ * \{ */
+
+static void v3d_cursor_plane_draw_grid(const int resolution,
+ const float scale,
+ const float scale_fade,
+ const float matrix[4][4],
+ const int plane_axis,
+ const float color[4])
+{
+ BLI_assert(scale_fade <= scale);
+ const int resolution_min = resolution - 1;
+ float color_fade[4] = {UNPACK4(color)};
+ const float *center = matrix[3];
+
+ GPU_blend(GPU_BLEND_ADDITIVE);
+ GPU_line_smooth(true);
+ GPU_line_width(1.0f);
+
+ GPUVertFormat *format = immVertexFormat();
+ const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ const uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
+
+ const size_t coords_len = resolution * resolution;
+ float(*coords)[3] = MEM_mallocN(sizeof(*coords) * coords_len, __func__);
+
+ const int axis_x = (plane_axis + 0) % 3;
+ const int axis_y = (plane_axis + 1) % 3;
+ const int axis_z = (plane_axis + 2) % 3;
+
+ int i;
+ const float resolution_div = (float)1.0f / (float)resolution;
+ i = 0;
+ for (int x = 0; x < resolution; x++) {
+ const float x_fl = (x * resolution_div) - 0.5f;
+ for (int y = 0; y < resolution; y++) {
+ const float y_fl = (y * resolution_div) - 0.5f;
+ coords[i][axis_x] = 0.0f;
+ coords[i][axis_y] = x_fl * scale;
+ coords[i][axis_z] = y_fl * scale;
+ mul_m4_v3(matrix, coords[i]);
+ i += 1;
+ }
+ }
+ BLI_assert(i == (int)coords_len);
+ immBeginAtMost(GPU_PRIM_LINES, coords_len * 4);
+ i = 0;
+ for (int x = 0; x < resolution_min; x++) {
+ for (int y = 0; y < resolution_min; y++) {
+
+ /* Add #resolution_div to ensure we fade-out entirely. */
+#define FADE(v) \
+ max_ff(0.0f, (1.0f - square_f(((len_v3v3(v, center) / scale_fade) + resolution_div) * 2.0f)))
+
+ const float *v0 = coords[(resolution * x) + y];
+ const float *v1 = coords[(resolution * (x + 1)) + y];
+ const float *v2 = coords[(resolution * x) + (y + 1)];
+
+ const float f0 = FADE(v0);
+ const float f1 = FADE(v1);
+ const float f2 = FADE(v2);
+
+ if (f0 > 0.0f || f1 > 0.0f) {
+ color_fade[3] = color[3] * f0;
+ immAttr4fv(col_id, color_fade);
+ immVertex3fv(pos_id, v0);
+ color_fade[3] = color[3] * f1;
+ immAttr4fv(col_id, color_fade);
+ immVertex3fv(pos_id, v1);
+ }
+ if (f0 > 0.0f || f2 > 0.0f) {
+ color_fade[3] = color[3] * f0;
+ immAttr4fv(col_id, color_fade);
+ immVertex3fv(pos_id, v0);
+
+ color_fade[3] = color[3] * f2;
+ immAttr4fv(col_id, color_fade);
+ immVertex3fv(pos_id, v2);
+ }
+
+#undef FADE
+
+ i++;
+ }
+ }
+
+ MEM_freeN(coords);
+
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_line_smooth(false);
+ GPU_blend(GPU_BLEND_NONE);
+}
+
+static void v3d_cursor_plane_draw(const RegionView3D *rv3d,
+ const int plane_axis,
+ const float matrix[4][4])
+{
+ /* Draw */
+ float pixel_size;
+
+ if (rv3d->is_persp) {
+ float center[3];
+ negate_v3_v3(center, rv3d->ofs);
+ pixel_size = ED_view3d_pixel_size(rv3d, center);
+ }
+ else {
+ pixel_size = ED_view3d_pixel_size(rv3d, matrix[3]);
+ }
+
+ if (pixel_size > FLT_EPSILON) {
+
+ /* Arbitrary, 1.0 is a little too strong though. */
+ float color_alpha = 0.75f;
+ if (rv3d->is_persp) {
+ /* Scale down the alpha when this is drawn very small,
+ * since the add shader causes the small size to show too dense & bright. */
+ const float relative_pixel_scale = pixel_size / ED_view3d_pixel_size(rv3d, matrix[3]);
+ if (relative_pixel_scale < 1.0f) {
+ color_alpha *= max_ff(square_f(relative_pixel_scale), 0.3f);
+ }
+ }
+
+ {
+ /* Extra adjustment when it's near view-aligned as it seems overly bright. */
+ float view_vector[3];
+ ED_view3d_global_to_vector(rv3d, matrix[3], view_vector);
+ float view_dot = fabsf(dot_v3v3(matrix[plane_axis], view_vector));
+ color_alpha *= max_ff(0.3f, 1.0f - square_f(square_f(1.0f - view_dot)));
+ }
+
+ const float scale_mod = U.gizmo_size * 2 * U.dpi_fac / U.pixelsize;
+
+ float final_scale = (scale_mod * pixel_size);
+
+ const int lines_subdiv = 10;
+ int lines = lines_subdiv;
+
+ float final_scale_fade = final_scale;
+ final_scale = ceil_power_of_10(final_scale);
+
+ float fac = final_scale_fade / final_scale;
+
+ float color[4] = {1, 1, 1, color_alpha};
+ color[3] *= square_f(1.0f - fac);
+ if (color[3] > 0.0f) {
+ v3d_cursor_plane_draw_grid(
+ lines * lines_subdiv, final_scale, final_scale_fade, matrix, plane_axis, color);
+ }
+
+ color[3] = color_alpha;
+ /* When the grid is large, we only need the 2x lines in the middle. */
+ if (fac < 0.2f) {
+ lines = 1;
+ final_scale = final_scale_fade;
+ }
+ v3d_cursor_plane_draw_grid(lines, final_scale, final_scale_fade, matrix, plane_axis, color);
+ }
+}
+
+static void cursor_box_draw(const float dimensions[3], uchar color[4])
+{
+ GPUVertFormat *format = immVertexFormat();
+ const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ GPU_blend(GPU_BLEND_ALPHA);
+ GPU_line_smooth(true);
+ GPU_line_width(1.0f);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4ubv(color);
+ imm_draw_cube_corners_3d(pos_id, (const float[3]){0.0f, 0.0f, dimensions[2]}, dimensions, 0.15f);
+ immUnbindProgram();
+
+ GPU_line_smooth(false);
+ GPU_blend(GPU_BLEND_NONE);
+}
+
+void ED_view3d_cursor_snap_draw_util(RegionView3D *rv3d,
+ const float loc_prev[3],
+ const float loc_curr[3],
+ const float normal[3],
+ const uchar color_line[4],
+ const uchar color_point[4],
+ const short snap_elem_type)
+{
+ if (!loc_prev && !loc_curr) {
+ return;
+ }
+
+ float view_inv[4][4];
+ copy_m4_m4(view_inv, rv3d->viewinv);
+
+ /* The size of the circle is larger than the vertex size.
+ * This prevents a drawing overlaps the other. */
+ float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ if (loc_curr) {
+ immUniformColor4ubv(color_point);
+ imm_drawcircball(loc_curr, ED_view3d_pixel_size(rv3d, loc_curr) * radius, view_inv, pos);
+
+ /* draw normal if needed */
+ if (normal) {
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, loc_curr);
+ immVertex3f(pos, loc_curr[0] + normal[0], loc_curr[1] + normal[1], loc_curr[2] + normal[2]);
+ immEnd();
+ }
+ }
+
+ if (loc_prev) {
+ /* Draw an "X" indicating where the previous snap point is.
+ * This is useful for indicating perpendicular snap. */
+
+ /* v1, v2, v3 and v4 indicate the coordinates of the ends of the "X". */
+ float vx[3], vy[3], v1[3], v2[3], v3[3], v4[4];
+
+ /* Multiply by 0.75f so that the final size of the "X" is close to that of
+ * the circle.
+ * (A closer value is 0.7071f, but we don't need to be exact here). */
+ float x_size = 0.75f * radius * ED_view3d_pixel_size(rv3d, loc_prev);
+
+ mul_v3_v3fl(vx, view_inv[0], x_size);
+ mul_v3_v3fl(vy, view_inv[1], x_size);
+
+ add_v3_v3v3(v1, vx, vy);
+ sub_v3_v3v3(v2, vx, vy);
+ negate_v3_v3(v3, v1);
+ negate_v3_v3(v4, v2);
+
+ add_v3_v3(v1, loc_prev);
+ add_v3_v3(v2, loc_prev);
+ add_v3_v3(v3, loc_prev);
+ add_v3_v3(v4, loc_prev);
+
+ immUniformColor4ubv(color_line);
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex3fv(pos, v3);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v4);
+ immVertex3fv(pos, v2);
+ immEnd();
+
+ if (loc_curr && (snap_elem_type & SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ /* Dashed line. */
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+ immUniform1f("dash_width", 6.0f * U.pixelsize);
+ immUniform1f("dash_factor", 1.0f / 4.0f);
+ immUniformColor4ubv(color_line);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, loc_prev);
+ immVertex3fv(pos, loc_curr);
+ immEnd();
+ }
+ }
+
+ immUnbindProgram();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event State
+ * \{ */
+
+/* Checks if the current event is different from the one captured in the last update. */
+static bool v3d_cursor_eventstate_has_changed(SnapCursorDataIntern *data_intern,
+ V3DSnapCursorState *state,
+ const wmWindowManager *wm,
+ const int x,
+ const int y)
+{
+ if (wm && wm->winactive) {
+ const wmEvent *event = wm->winactive->eventstate;
+ if ((x != data_intern->last_eventstate.x) || (y != data_intern->last_eventstate.y)) {
+ return true;
+ }
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ if (!(state && (state->flag & V3D_SNAPCURSOR_TOGGLE_ALWAYS_TRUE))) {
+ if ((event->ctrl != data_intern->last_eventstate.ctrl) ||
+ (event->shift != data_intern->last_eventstate.shift) ||
+ (event->alt != data_intern->last_eventstate.alt) ||
+ (event->oskey != data_intern->last_eventstate.oskey)) {
+ return true;
+ }
+ }
+#endif
+ }
+ return false;
+}
+
+/* Copies the current eventstate. */
+static void v3d_cursor_eventstate_save_xy(SnapCursorDataIntern *cursor_snap,
+ const int x,
+ const int y)
+{
+ cursor_snap->last_eventstate.x = x;
+ cursor_snap->last_eventstate.y = y;
+}
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+static bool v3d_cursor_is_snap_invert(SnapCursorDataIntern *data_intern, const wmWindowManager *wm)
+{
+ if (!wm || !wm->winactive) {
+ return false;
+ }
+
+ const wmEvent *event = wm->winactive->eventstate;
+ if ((event->ctrl == data_intern->last_eventstate.ctrl) &&
+ (event->shift == data_intern->last_eventstate.shift) &&
+ (event->alt == data_intern->last_eventstate.alt) &&
+ (event->oskey == data_intern->last_eventstate.oskey)) {
+ /* Nothing has changed. */
+ return data_intern->snap_data.is_snap_invert;
+ }
+
+ /* Save new eventstate. */
+ data_intern->last_eventstate.ctrl = event->ctrl;
+ data_intern->last_eventstate.shift = event->shift;
+ data_intern->last_eventstate.alt = event->alt;
+ data_intern->last_eventstate.oskey = event->oskey;
+
+ const int snap_on = data_intern->snap_on;
+
+ wmKeyMap *keymap = WM_keymap_active(wm, data_intern->keymap);
+ for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ if (kmi->flag & KMI_INACTIVE) {
+ continue;
+ }
+
+ if (kmi->propvalue == snap_on) {
+ if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) && event->ctrl) ||
+ (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) && event->shift) ||
+ (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && event->alt) ||
+ ((kmi->type == EVT_OSKEY) && event->oskey)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+#endif
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Update
+ * \{ */
+
+static short v3d_cursor_snap_elements(V3DSnapCursorState *snap_state, Scene *scene)
+{
+ short snap_elements = snap_state->snap_elem_force;
+ if (!snap_elements) {
+ return scene->toolsettings->snap_mode;
+ }
+ return snap_elements;
+}
+
+static void v3d_cursor_snap_context_ensure(Scene *scene)
+{
+ SnapCursorDataIntern *data_intern = &g_data_intern;
+ if (data_intern->snap_context_v3d && (data_intern->scene != scene)) {
+ ED_transform_snap_object_context_destroy(data_intern->snap_context_v3d);
+ data_intern->snap_context_v3d = NULL;
+ }
+ if (data_intern->snap_context_v3d == NULL) {
+ data_intern->snap_context_v3d = ED_transform_snap_object_context_create(scene, 0);
+ data_intern->scene = scene;
+ }
+}
+
+static void v3d_cursor_snap_update(V3DSnapCursorState *state,
+ const bContext *C,
+ wmWindowManager *wm,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ ARegion *region,
+ View3D *v3d,
+ int x,
+ int y)
+{
+ SnapCursorDataIntern *data_intern = &g_data_intern;
+ V3DSnapCursorData *snap_data = &data_intern->snap_data;
+ v3d_cursor_snap_context_ensure(scene);
+
+ float co[3], no[3], face_nor[3], obmat[4][4], omat[3][3];
+ short snap_elem = 0;
+ int snap_elem_index[3] = {-1, -1, -1};
+ int index = -1;
+
+ const float mval_fl[2] = {x, y};
+ zero_v3(no);
+ zero_v3(face_nor);
+ unit_m3(omat);
+
+ ushort snap_elements = v3d_cursor_snap_elements(state, scene);
+ data_intern->snap_elem_hidden = 0;
+ const bool draw_plane = state->draw_plane || state->draw_box;
+ if (draw_plane && !(snap_elements & SCE_SNAP_MODE_FACE)) {
+ data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE;
+ snap_elements |= SCE_SNAP_MODE_FACE;
+ }
+
+ snap_data->is_enabled = true;
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ if (!(state->flag & V3D_SNAPCURSOR_TOGGLE_ALWAYS_TRUE)) {
+ snap_data->is_snap_invert = v3d_cursor_is_snap_invert(data_intern, wm);
+
+ const ToolSettings *ts = scene->toolsettings;
+ if (snap_data->is_snap_invert != !(ts->snap_flag & SCE_SNAP)) {
+ snap_data->is_enabled = false;
+ if (!draw_plane) {
+ snap_data->snap_elem = 0;
+ return;
+ }
+ snap_elements = data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE;
+ }
+ }
+#endif
+
+ if (snap_elements & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
+ SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ float prev_co[3] = {0.0f};
+ if (state->prevpoint) {
+ copy_v3_v3(prev_co, state->prevpoint);
+ }
+ else {
+ snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR;
+ }
+
+ eSnapSelect snap_select = (state->flag & V3D_SNAPCURSOR_SNAP_ONLY_ACTIVE) ? SNAP_ONLY_ACTIVE :
+ SNAP_ALL;
+
+ eSnapEditType edit_mode_type = (state->flag & V3D_SNAPCURSOR_SNAP_EDIT_GEOM_FINAL) ?
+ SNAP_GEOM_FINAL :
+ (state->flag & V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE) ?
+ SNAP_GEOM_CAGE :
+ SNAP_GEOM_EDIT;
+
+ bool use_occlusion_test = (state->flag & V3D_SNAPCURSOR_OCCLUSION_ALWAYS_TRUE) ? false : true;
+
+ float dist_px = 12.0f * U.pixelsize;
+
+ snap_elem = ED_transform_snap_object_project_view3d_ex(
+ data_intern->snap_context_v3d,
+ depsgraph,
+ region,
+ v3d,
+ snap_elements,
+ &(const struct SnapObjectParams){
+ .snap_select = snap_select,
+ .edit_mode_type = edit_mode_type,
+ .use_occlusion_test = use_occlusion_test,
+ },
+ mval_fl,
+ prev_co,
+ &dist_px,
+ co,
+ no,
+ &index,
+ NULL,
+ obmat,
+ face_nor);
+ }
+
+ if (is_zero_v3(face_nor)) {
+ face_nor[state->plane_axis] = 1.0f;
+ }
+
+ if (draw_plane) {
+ RegionView3D *rv3d = region->regiondata;
+ bool orient_surface = snap_elem && (state->plane_orient == V3D_PLACE_ORIENT_SURFACE);
+ if (orient_surface) {
+ copy_m3_m4(omat, obmat);
+ }
+ else {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ const int orient_index = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
+ const int pivot_point = scene->toolsettings->transform_pivot_point;
+ ED_transform_calc_orientation_from_type_ex(
+ scene, view_layer, v3d, rv3d, ob, NULL, orient_index, pivot_point, omat);
+
+ if (state->use_plane_axis_auto) {
+ mat3_align_axis_to_v3(omat, state->plane_axis, rv3d->viewinv[2]);
+ }
+ }
+
+ /* Non-orthogonal matrices cause the preview and final result not to match.
+ *
+ * While making orthogonal doesn't always work well (especially with gimbal orientation for
+ * e.g.) it's a corner case, without better alternatives as objects don't support shear. */
+ orthogonalize_m3(omat, state->plane_axis);
+
+ if (orient_surface) {
+ if (dot_v3v3(rv3d->viewinv[2], face_nor) < 0.0f) {
+ negate_v3(face_nor);
+ }
+ v3d_cursor_poject_surface_normal(face_nor, obmat, omat);
+ }
+ }
+
+ float *co_depth = snap_elem ? co : scene->cursor.location;
+ snap_elem &= ~data_intern->snap_elem_hidden;
+ if (snap_elem == 0) {
+ RegionView3D *rv3d = region->regiondata;
+ const float *plane_normal = omat[state->plane_axis];
+ bool do_plane_isect = (state->plane_depth != V3D_PLACE_DEPTH_CURSOR_VIEW) &&
+ (rv3d->is_persp ||
+ (fabsf(dot_v3v3(plane_normal, rv3d->viewinv[2])) > eps_view_align));
+
+ if (do_plane_isect) {
+ float plane[4];
+ plane_from_point_normal_v3(plane, co_depth, plane_normal);
+ do_plane_isect = ED_view3d_win_to_3d_on_plane(region, plane, mval_fl, rv3d->is_persp, co);
+ }
+
+ if (!do_plane_isect) {
+ ED_view3d_win_to_3d(v3d, region, co_depth, mval_fl, co);
+ }
+
+ if (snap_data->is_enabled && (snap_elements & SCE_SNAP_MODE_INCREMENT)) {
+ v3d_cursor_snap_calc_incremental(scene, v3d, region, state->prevpoint, co);
+ }
+ }
+ else if (snap_elem == SCE_SNAP_MODE_VERTEX) {
+ snap_elem_index[0] = index;
+ }
+ else if (snap_elem &
+ (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ snap_elem_index[1] = index;
+ }
+ else if (snap_elem == SCE_SNAP_MODE_FACE) {
+ snap_elem_index[2] = index;
+ }
+
+ snap_data->snap_elem = snap_elem;
+ copy_v3_v3(snap_data->loc, co);
+ copy_v3_v3(snap_data->nor, no);
+ copy_m4_m4(snap_data->obmat, obmat);
+ copy_v3_v3_int(snap_data->elem_index, snap_elem_index);
+
+ copy_m3_m3(snap_data->plane_omat, omat);
+
+ v3d_cursor_eventstate_save_xy(data_intern, x, y);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks
+ * \{ */
+
+static bool v3d_cursor_snap_poll_fn(bContext *C)
+{
+ if (G.moving) {
+ return false;
+ }
+
+ ScrArea *area = CTX_wm_area(C);
+ if (area->spacetype != SPACE_VIEW3D) {
+ return false;
+ }
+
+ ARegion *region = CTX_wm_region(C);
+ if (region->regiontype != RGN_TYPE_WINDOW) {
+ if (!region->overlap) {
+ return false;
+ }
+ /* Sometimes the cursor may be on an invisible part of an overlapping region. */
+ const wmWindowManager *wm = CTX_wm_manager(C);
+ const wmEvent *event = wm->winactive->eventstate;
+ if (ED_region_overlap_isect_xy(region, event->xy)) {
+ return false;
+ }
+ /* Find the visible region under the cursor.
+ * TODO(Germano): Shouldn't this be the region in context? */
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ }
+
+ RegionView3D *rv3d = region->regiondata;
+ if (rv3d->rflag & RV3D_NAVIGATING) {
+ /* Don't draw the cursor while navigating. It can be distracting. */
+ return false;
+ };
+
+ V3DSnapCursorState *state = ED_view3d_cursor_snap_state_get();
+ if (state->gzgrp_type) {
+ /* Check the respective gizmo group is in the region. */
+ wmGizmoMap *gzmap = region->gizmo_map;
+ if (WM_gizmomap_group_find_ptr(gzmap, state->gzgrp_type) == NULL) {
+ /* Wrong viewport. */
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(customdata))
+{
+ SnapCursorDataIntern *data_intern = &g_data_intern;
+ V3DSnapCursorState *state = ED_view3d_cursor_snap_state_get();
+ V3DSnapCursorData *snap_data = &data_intern->snap_data;
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ x -= region->winrct.xmin;
+ y -= region->winrct.ymin;
+ if (v3d_cursor_eventstate_has_changed(data_intern, state, wm, x, y)) {
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ View3D *v3d = CTX_wm_view3d(C);
+ v3d_cursor_snap_update(state, C, wm, depsgraph, scene, region, v3d, x, y);
+ }
+
+ const bool draw_plane = state->draw_plane || state->draw_box;
+ if (!snap_data->snap_elem && !draw_plane) {
+ return;
+ }
+
+ /* Setup viewport & matrix. */
+ RegionView3D *rv3d = region->regiondata;
+ wmViewport(&region->winrct);
+ GPU_matrix_projection_set(rv3d->winmat);
+ GPU_matrix_set(rv3d->viewmat);
+
+ float matrix[4][4];
+ if (draw_plane) {
+ copy_m4_m3(matrix, snap_data->plane_omat);
+ copy_v3_v3(matrix[3], snap_data->loc);
+
+ v3d_cursor_plane_draw(rv3d, state->plane_axis, matrix);
+ }
+
+ if (snap_data->snap_elem && (state->draw_point || state->draw_box)) {
+ const float *prev_point = (snap_data->snap_elem & SCE_SNAP_MODE_EDGE_PERPENDICULAR) ?
+ state->prevpoint :
+ NULL;
+
+ GPU_line_smooth(false);
+ GPU_line_width(1.0f);
+
+ ED_view3d_cursor_snap_draw_util(rv3d,
+ prev_point,
+ snap_data->loc,
+ NULL,
+ state->color_line,
+ state->color_point,
+ snap_data->snap_elem);
+ }
+
+ if (state->draw_box) {
+ GPU_matrix_mul(matrix);
+ cursor_box_draw(state->box_dimensions, state->color_box);
+ }
+
+ /* Restore matrix. */
+ wmWindowViewport(CTX_wm_window(C));
+}
+
+/** \} */
+
+V3DSnapCursorState *ED_view3d_cursor_snap_state_get(void)
+{
+ SnapCursorDataIntern *data_intern = &g_data_intern;
+ if (BLI_listbase_is_empty(&data_intern->state_intern)) {
+ return &g_data_intern.state_default;
+ }
+ return &((SnapStateIntern *)data_intern->state_intern.last)->snap_state;
+}
+
+static void v3d_cursor_snap_activate(void)
+{
+ SnapCursorDataIntern *data_intern = &g_data_intern;
+
+ if (!data_intern->handle) {
+ if (!data_intern->is_initiated) {
+ /* Only initiate intern data once.
+ * TODO: ED_view3d_cursor_snap_init */
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ struct wmKeyConfig *keyconf = ((wmWindowManager *)G.main->wm.first)->defaultconf;
+
+ data_intern->keymap = WM_modalkeymap_find(keyconf, "Generic Gizmo Tweak Modal Map");
+ RNA_enum_value_from_id(data_intern->keymap->modal_items, "SNAP_ON", &data_intern->snap_on);
+#endif
+ data_intern->is_initiated = true;
+ }
+
+ struct wmPaintCursor *pc = WM_paint_cursor_activate(
+ SPACE_VIEW3D, RGN_TYPE_WINDOW, v3d_cursor_snap_poll_fn, v3d_cursor_snap_draw_fn, NULL);
+ data_intern->handle = pc;
+ }
+}
+
+static void v3d_cursor_snap_free(void)
+{
+ SnapCursorDataIntern *data_intern = &g_data_intern;
+ if (data_intern->handle) {
+ if (G_MAIN->wm.first) {
+ WM_paint_cursor_end(data_intern->handle);
+ }
+ data_intern->handle = NULL;
+ }
+ if (data_intern->snap_context_v3d) {
+ ED_transform_snap_object_context_destroy(data_intern->snap_context_v3d);
+ data_intern->snap_context_v3d = NULL;
+ }
+}
+
+void ED_view3d_cursor_snap_state_default_set(V3DSnapCursorState *state)
+{
+ g_data_intern.state_default = *state;
+
+ /* These values are temporarily set by the tool.
+ * They are not convenient as default values.
+ * So reset to null. */
+ g_data_intern.state_default.gzgrp_type = NULL;
+ g_data_intern.state_default.prevpoint = NULL;
+ g_data_intern.state_default.draw_plane = false;
+ g_data_intern.state_default.draw_box = false;
+}
+
+V3DSnapCursorState *ED_view3d_cursor_snap_active(void)
+{
+ SnapCursorDataIntern *data_intern = &g_data_intern;
+ if (!data_intern->handle) {
+ v3d_cursor_snap_activate();
+ }
+
+ SnapStateIntern *state_intern = MEM_mallocN(sizeof(*state_intern), __func__);
+ state_intern->snap_state = g_data_intern.state_default;
+ BLI_addtail(&g_data_intern.state_intern, state_intern);
+
+ return (V3DSnapCursorState *)&state_intern->snap_state;
+}
+
+void ED_view3d_cursor_snap_deactive(V3DSnapCursorState *state)
+{
+ SnapCursorDataIntern *data_intern = &g_data_intern;
+ if (BLI_listbase_is_empty(&data_intern->state_intern)) {
+ return;
+ }
+
+ SnapStateIntern *state_intern = STATE_INTERN_GET(state);
+ BLI_remlink(&data_intern->state_intern, state_intern);
+ MEM_freeN(state_intern);
+ if (BLI_listbase_is_empty(&data_intern->state_intern)) {
+ v3d_cursor_snap_free();
+ }
+}
+
+void ED_view3d_cursor_snap_prevpoint_set(V3DSnapCursorState *state, const float prev_point[3])
+{
+ SnapCursorDataIntern *data_intern = &g_data_intern;
+ if (!state) {
+ state = ED_view3d_cursor_snap_state_get();
+ }
+ if (prev_point) {
+ copy_v3_v3(data_intern->prevpoint_stack, prev_point);
+ state->prevpoint = data_intern->prevpoint_stack;
+ }
+ else {
+ state->prevpoint = NULL;
+ }
+}
+
+V3DSnapCursorData *ED_view3d_cursor_snap_data_get(V3DSnapCursorState *state,
+ const bContext *C,
+ const int x,
+ const int y)
+{
+ SnapCursorDataIntern *data_intern = &g_data_intern;
+ if (C) {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (v3d_cursor_eventstate_has_changed(data_intern, state, wm, x, y)) {
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ if (!state) {
+ state = ED_view3d_cursor_snap_state_get();
+ }
+ v3d_cursor_snap_update(state, C, wm, depsgraph, scene, region, v3d, x, y);
+ }
+ }
+
+ return &data_intern->snap_data;
+}
+
+struct SnapObjectContext *ED_view3d_cursor_snap_context_ensure(Scene *scene)
+{
+ SnapCursorDataIntern *data_intern = &g_data_intern;
+ v3d_cursor_snap_context_ensure(scene);
+ return data_intern->snap_context_v3d;
+}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 5cb35080cc0..b1f19581543 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -108,9 +108,6 @@
/** \name General Functions
* \{ */
-/**
- * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
- */
void ED_view3d_update_viewmat(Depsgraph *depsgraph,
const Scene *scene,
View3D *v3d,
@@ -339,14 +336,22 @@ static void view3d_xr_mirror_setup(const wmWindowManager *wm,
}
view3d_main_region_setup_view(depsgraph, scene, v3d, region, viewmat, NULL, rect);
- /* Reset overridden View3D data */
+ /* Set draw flags. */
+ SET_FLAG_FROM_TEST(v3d->flag2,
+ (wm->xr.session_settings.draw_flags & V3D_OFSDRAW_XR_SHOW_CONTROLLERS) != 0,
+ V3D_XR_SHOW_CONTROLLERS);
+ SET_FLAG_FROM_TEST(v3d->flag2,
+ (wm->xr.session_settings.draw_flags & V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS) !=
+ 0,
+ V3D_XR_SHOW_CUSTOM_OVERLAYS);
+ /* Hide navigation gizmo since it gets distorted if the view matrix has a scale factor. */
+ v3d->gizmo_flag |= V3D_GIZMO_HIDE_NAVIGATE;
+
+ /* Reset overridden View3D data. */
v3d->lens = lens_old;
}
#endif /* WITH_XR_OPENXR */
-/**
- * Set the correct matrices
- */
void ED_view3d_draw_setup_view(const wmWindowManager *wm,
wmWindow *win,
Depsgraph *depsgraph,
@@ -608,11 +613,10 @@ static void drawviewborder(Scene *scene, Depsgraph *depsgraph, ARegion *region,
}
GPU_blend(GPU_BLEND_NONE);
+ immUniformThemeColor3(TH_BACK);
+ imm_draw_box_wire_2d(shdr_pos, x1i, y1i, x2i, y2i);
}
- immUniformThemeColor3(TH_BACK);
- imm_draw_box_wire_2d(shdr_pos, x1i, y1i, x2i, y2i);
-
#ifdef VIEW3D_CAMERA_BORDER_HACK
if (view3d_camera_border_hack_test == true) {
immUniformColor3ubv(view3d_camera_border_hack_col);
@@ -781,9 +785,9 @@ static void drawviewborder(Scene *scene, Depsgraph *depsgraph, ARegion *region,
immUniformThemeColorShadeAlpha(TH_VIEW_OVERLAY, 100, 255);
/* TODO: Was using:
- * UI_draw_roundbox_4fv(false, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f, color);
- * We'll probably need a new imm_draw_line_roundbox_dashed dor that - though in practice the
- * 2.0f round corner effect was nearly not visible anyway... */
+ * `UI_draw_roundbox_4fv(false, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f, color);`
+ * We'll probably need a new imm_draw_line_roundbox_dashed or that - though in practice the
+ * 2.0f round corner effect was nearly not visible anyway. */
imm_draw_box_wire_2d(shdr_pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
}
@@ -838,7 +842,6 @@ static void drawrenderborder(ARegion *region, View3D *v3d)
/** \name Other Elements
* \{ */
-/** could move this elsewhere, but tied into #ED_view3d_grid_scale */
float ED_scene_grid_scale(const Scene *scene, const char **r_grid_unit)
{
/* apply units */
@@ -911,9 +914,6 @@ void ED_view3d_grid_steps(const Scene *scene,
}
}
-/* Simulates the grid scale that is actually viewed.
- * The actual code is seen in `object_grid_frag.glsl` (see `grid_res`).
- * Currently the simulation is only done when RV3D_VIEW_IS_AXIS. */
float ED_view3d_grid_view_scale(Scene *scene,
View3D *v3d,
ARegion *region,
@@ -1308,10 +1308,9 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y
}
/**
- * Draw info beside axes in bottom left-corner:
+ * Draw info beside axes in top-left corner:
* frame-number, collection, object name, bone name (if available), marker name (if available).
*/
-
static void draw_selected_name(
Scene *scene, ViewLayer *view_layer, Object *ob, int xoffset, int *yoffset)
{
@@ -1334,14 +1333,13 @@ static void draw_selected_name(
(ob == NULL) ? "" : " |");
}
- /*
- * info can contain:
- * - a frame (7 + 2)
- * - a collection name (MAX_NAME + 3)
- * - 3 object names (MAX_NAME)
- * - 2 BREAD_CRUMB_SEPARATORs (6)
- * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room!
- * - a marker name (MAX_NAME + 3)
+ /* Info can contain:
+ * - A frame `(7 + 2)`.
+ * - A collection name `(MAX_NAME + 3)`.
+ * - 3 object names `(MAX_NAME)`.
+ * - 2 BREAD_CRUMB_SEPARATOR(s) `(6)`.
+ * - A SHAPE_KEY_PINNED marker and a trailing '\0' `(9+1)` - translated, so give some room!
+ * - A marker name `(MAX_NAME + 3)`.
*/
/* get name of marker on current frame (if available) */
@@ -1464,9 +1462,6 @@ static void draw_grid_unit_name(
}
}
-/**
- * Information drawn on top of the solid plates and composed data
- */
void view3d_draw_region_info(const bContext *C, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -1586,6 +1581,7 @@ void view3d_main_region_draw(const bContext *C, ARegion *region)
view3d_draw_view(C, region);
+ DRW_cache_free_old_subdiv();
DRW_cache_free_old_batches(bmain);
BKE_image_free_old_gputextures(bmain);
GPU_pass_cache_garbage_collect();
@@ -1743,14 +1739,10 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
G.f &= ~G_FLAG_RENDER_VIEWPORT;
}
-/**
- * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen). Similar too
- * #ED_view_draw_offscreen_imbuf_simple, but takes view/projection matrices as arguments.
- */
void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
Scene *scene,
View3DShading *shading_override,
- int drawtype,
+ eDrawType drawtype,
int winx,
int winy,
uint draw_flags,
@@ -1758,6 +1750,7 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
const float winmat[4][4],
float clip_start,
float clip_end,
+ bool is_xr_surface,
bool is_image_render,
bool draw_background,
const char *viewname,
@@ -1787,23 +1780,37 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
v3d.shading.flag = V3D_SHADING_SCENE_WORLD | V3D_SHADING_SCENE_LIGHTS;
}
- if (draw_flags & V3D_OFSDRAW_SHOW_ANNOTATION) {
- v3d.flag2 |= V3D_SHOW_ANNOTATION;
+ if ((draw_flags & ~V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS) == V3D_OFSDRAW_NONE) {
+ v3d.flag2 = V3D_HIDE_OVERLAYS;
}
- if (draw_flags & V3D_OFSDRAW_SHOW_GRIDFLOOR) {
- v3d.gridflag |= V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y;
- v3d.grid = 1.0f;
- v3d.gridlines = 16;
- v3d.gridsubdiv = 10;
-
- /* Show grid, disable other overlays (set all available _HIDE_ flags). */
+ else {
+ if (draw_flags & V3D_OFSDRAW_SHOW_ANNOTATION) {
+ v3d.flag2 |= V3D_SHOW_ANNOTATION;
+ }
+ if (draw_flags & V3D_OFSDRAW_SHOW_GRIDFLOOR) {
+ v3d.gridflag |= V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y;
+ v3d.grid = 1.0f;
+ v3d.gridlines = 16;
+ v3d.gridsubdiv = 10;
+ }
+ if (draw_flags & V3D_OFSDRAW_SHOW_SELECTION) {
+ v3d.flag |= V3D_SELECT_OUTLINE;
+ }
+ if (draw_flags & V3D_OFSDRAW_XR_SHOW_CONTROLLERS) {
+ v3d.flag2 |= V3D_XR_SHOW_CONTROLLERS;
+ }
+ if (draw_flags & V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS) {
+ v3d.flag2 |= V3D_XR_SHOW_CUSTOM_OVERLAYS;
+ }
+ /* Disable other overlays (set all available _HIDE_ flags). */
v3d.overlay.flag |= V3D_OVERLAY_HIDE_CURSOR | V3D_OVERLAY_HIDE_TEXT |
V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_BONES |
V3D_OVERLAY_HIDE_OBJECT_XTRAS | V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
v3d.flag |= V3D_HIDE_HELPLINES;
}
- else {
- v3d.flag2 = V3D_HIDE_OVERLAYS;
+
+ if (is_xr_surface) {
+ v3d.flag |= V3D_XR_SESSION_SURFACE;
}
rv3d.persp = RV3D_PERSP;
@@ -1830,12 +1837,6 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
viewport);
}
-/**
- * Utility func for ED_view3d_draw_offscreen
- *
- * \param ofs: Optional off-screen buffer, can be NULL.
- * (avoids re-creating when doing multiple GL renders).
- */
ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
Scene *scene,
eDrawType drawtype,
@@ -1985,14 +1986,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
return ibuf;
}
-/**
- * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf)
- *
- * \param ofs: Optional off-screen buffer can be NULL.
- * (avoids re-creating when doing multiple GL renders).
- *
- * \note used by the sequencer
- */
ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
Scene *scene,
View3DShading *shading_override,
@@ -2023,6 +2016,15 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
}
memcpy(&v3d.shading, source_shading_settings, sizeof(View3DShading));
+ if (drawtype == OB_RENDER) {
+ /* Don't use external engines for preview. Fall back to solid instead of Eevee as rendering
+ * with Eevee is potentially slow due to compiling shaders and loading textures, and the
+ * depsgraph may not have been updated to have all the right geometry attributes. */
+ if (!(BKE_scene_uses_blender_eevee(scene) || BKE_scene_uses_blender_workbench(scene))) {
+ drawtype = OB_SOLID;
+ }
+ }
+
if (drawtype == OB_MATERIAL) {
v3d.shading.flag = V3D_SHADING_SCENE_WORLD | V3D_SHADING_SCENE_LIGHTS;
v3d.shading.render_pass = SCE_PASS_COMBINED;
@@ -2114,15 +2116,6 @@ static bool view3d_clipping_test(const float co[3], const float clip[6][4])
return true;
}
-/**
- * Return true when `co` is hidden by the 3D views clipping planes.
- *
- * \param local: When true use local (object-space) #ED_view3d_clipping_local must run first,
- * then all comparisons can be done in local-space.
- * \return True when `co` is outside all clipping planes.
- *
- * \note Callers should check #RV3D_CLIPPING_ENABLED first.
- */
bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local)
{
return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
@@ -2208,10 +2201,6 @@ void ED_view3d_select_id_validate(ViewContext *vc)
validate_object_select_id(vc->depsgraph, vc->view_layer, vc->region, vc->v3d, vc->obact);
}
-/**
- * allow for small values [0.5 - 2.5],
- * and large values, FLT_MAX by clamping by the area size
- */
int ED_view3d_backbuf_sample_size_clamp(ARegion *region, const float dist)
{
return (int)min_ff(ceilf(dist), (float)max_ii(region->winx, region->winx));
@@ -2274,8 +2263,13 @@ static ViewDepths *view3d_depths_create(ARegion *region)
{
GPUViewport *viewport = WM_draw_region_get_viewport(region);
GPUTexture *depth_tx = GPU_viewport_depth_texture(viewport);
- d->depths = GPU_texture_read(depth_tx, GPU_DATA_FLOAT, 0);
-
+ uint32_t *int_depths = GPU_texture_read(depth_tx, GPU_DATA_UINT_24_8, 0);
+ d->depths = (float *)int_depths;
+ /* Convert in-place. */
+ int pixel_count = GPU_texture_width(depth_tx) * GPU_texture_height(depth_tx);
+ for (int i = 0; i < pixel_count; i++) {
+ d->depths[i] = (int_depths[i] >> 8u) / (float)0xFFFFFF;
+ }
/* Assumed to be this as they are never changed. */
d->depth_range[0] = 0.0;
d->depth_range[1] = 1.0;
@@ -2283,7 +2277,6 @@ static ViewDepths *view3d_depths_create(ARegion *region)
return d;
}
-/* Utility function to find the closest Z value, use for auto-depth. */
float view3d_depth_near(ViewDepths *d)
{
/* Convert to float for comparisons. */
@@ -2307,14 +2300,6 @@ float view3d_depth_near(ViewDepths *d)
return far == far_real ? FLT_MAX : far;
}
-/**
- * Redraw the viewport depth buffer.
- *
- * \param mode: V3D_DEPTH_NO_GPENCIL - Redraw viewport without Grease Pencil and Annotations.
- * V3D_DEPTH_GPENCIL_ONLY - Redraw viewport with Grease Pencil and Annotations only.
- * V3D_DEPTH_OBJECT_ONLY - Redraw viewport with active object only.
- * \param update_cache: If true, store the entire depth buffer in #rv3d->depths.
- */
void ED_view3d_depth_override(Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
@@ -2429,7 +2414,6 @@ void ED_view3d_datamask(const bContext *C,
}
}
-/* Goes over all modes and view3d settings. */
void ED_view3d_screen_datamask(const bContext *C,
const Scene *scene,
const bScreen *screen,
@@ -2499,10 +2483,6 @@ void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixSto
/** \name FPS Drawing
* \{ */
-/**
- * \note The info that this uses is updated in #ED_refresh_viewport_fps,
- * which currently gets called during #SCREEN_OT_animation_step.
- */
void ED_scene_draw_fps(const Scene *scene, int xoffset, int *yoffset)
{
ScreenFrameRateInfo *fpsi = scene->fps_info;
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 15ccf5891d4..80089815284 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -47,7 +47,6 @@
#include "BKE_armature.h"
#include "BKE_camera.h"
#include "BKE_context.h"
-#include "BKE_font.h"
#include "BKE_gpencil_geom.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
@@ -57,6 +56,7 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_vfont.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -191,7 +191,7 @@ typedef struct ViewOpsData {
float dist;
float camzoom;
float quat[4];
- /** #wmEvent.x, y. */
+ /** #wmEvent.xy. */
int event_xy[2];
/** Offset to use when #VIEWOPS_FLAG_USE_MOUSE_INIT is not set.
* so we can simulate pressing in the middle of the screen. */
@@ -473,17 +473,16 @@ static void viewops_data_create(bContext *C,
vod->init.dist = rv3d->dist;
vod->init.camzoom = rv3d->camzoom;
copy_qt_qt(vod->init.quat, rv3d->viewquat);
- vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x;
- vod->init.event_xy[1] = vod->prev.event_xy[1] = event->y;
+ copy_v2_v2_int(vod->init.event_xy, event->xy);
+ copy_v2_v2_int(vod->prev.event_xy, event->xy);
if (viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) {
- vod->init.event_xy_offset[0] = 0;
- vod->init.event_xy_offset[1] = 0;
+ zero_v2_int(vod->init.event_xy_offset);
}
else {
/* Simulate the event starting in the middle of the region. */
- vod->init.event_xy_offset[0] = BLI_rcti_cent_x(&vod->region->winrct) - event->x;
- vod->init.event_xy_offset[1] = BLI_rcti_cent_y(&vod->region->winrct) - event->y;
+ vod->init.event_xy_offset[0] = BLI_rcti_cent_x(&vod->region->winrct) - event->xy[0];
+ vod->init.event_xy_offset[1] = BLI_rcti_cent_y(&vod->region->winrct) - event->xy[1];
}
vod->init.event_type = event->type;
@@ -548,10 +547,9 @@ static void viewops_data_create(bContext *C,
ED_view3d_win_to_vector(vod->region, (const float[2]){UNPACK2(event->mval)}, vod->init.mousevec);
{
- const int event_xy_offset[2] = {
- event->x + vod->init.event_xy_offset[0],
- event->y + vod->init.event_xy_offset[1],
- };
+ int event_xy_offset[2];
+ add_v2_v2v2_int(event_xy_offset, event->xy, vod->init.event_xy_offset);
+
/* For rotation with trackball rotation. */
calctrackballvec(&vod->region->winrct, event_xy_offset, vod->init.trackvec);
}
@@ -620,7 +618,6 @@ enum {
VIEWROT_MODAL_SWITCH_ROTATE = 6,
};
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void viewrotate_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -675,7 +672,6 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
float zaxis_best[3];
int x, y, z;
bool found = false;
- bool is_axis_aligned = false;
invert_qt_qt_normalized(viewquat_inv, vod->curr.viewquat);
@@ -693,10 +689,6 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
if (angle_normalized_v3v3(zaxis_test, zaxis) < axis_limit) {
copy_v3_v3(zaxis_best, zaxis_test);
found = true;
-
- if (abs(x) + abs(y) + abs(z) == 1) {
- is_axis_aligned = true;
- }
}
}
}
@@ -769,7 +761,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
viewrotate_apply_dyn_ofs(vod, rv3d->viewquat);
if (U.uiflag & USER_AUTOPERSP) {
- if (is_axis_aligned) {
+ if (RV3D_VIEW_IS_AXIS(rv3d->view)) {
if (rv3d->persp == RV3D_PERSP) {
rv3d->persp = RV3D_ORTHO;
}
@@ -955,7 +947,7 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (event_code == VIEW_APPLY) {
- viewrotate_apply(vod, &event->x);
+ viewrotate_apply(vod, event->xy);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
@@ -1006,18 +998,16 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (event->type == MOUSEPAN) {
if (event->is_direction_inverted) {
- event_xy[0] = 2 * event->x - event->prevx;
- event_xy[1] = 2 * event->y - event->prevy;
+ event_xy[0] = 2 * event->xy[0] - event->prev_xy[0];
+ event_xy[1] = 2 * event->xy[1] - event->prev_xy[1];
}
else {
- event_xy[0] = event->prevx;
- event_xy[1] = event->prevy;
+ copy_v2_v2_int(event_xy, event->prev_xy);
}
}
else {
/* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
- event_xy[0] = event->prevx;
- event_xy[1] = event->y;
+ copy_v2_v2_int(event_xy, event->prev_xy);
}
viewrotate_apply(vod, event_xy);
@@ -1259,9 +1249,6 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof,
}
}
-/**
- * Called from both fly mode and walk mode,
- */
void view3d_ndof_fly(const wmNDOFMotionData *ndof,
View3D *v3d,
RegionView3D *rv3d,
@@ -1694,7 +1681,6 @@ void VIEW3D_OT_ndof_all(struct wmOperatorType *ot)
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void viewmove_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -1799,7 +1785,7 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (event_code == VIEW_APPLY) {
- viewmove_apply(vod, event->x, event->y);
+ viewmove_apply(vod, event->xy[0], event->xy[1]);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
@@ -1844,7 +1830,8 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (event->type == MOUSEPAN) {
/* invert it, trackpad scroll follows same principle as 2d windows this way */
- viewmove_apply(vod, 2 * event->x - event->prevx, 2 * event->y - event->prevy);
+ viewmove_apply(
+ vod, 2 * event->xy[0] - event->prev_xy[0], 2 * event->xy[1] - event->prev_xy[1]);
viewops_data_free(C, op);
@@ -1890,7 +1877,6 @@ void VIEW3D_OT_move(wmOperatorType *ot)
* \{ */
/* #viewdolly_modal_keymap has an exact copy of this, apply fixes to both. */
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void viewzoom_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -1924,7 +1910,7 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf)
/**
* \param zoom_xy: Optionally zoom to window location
- * (coords compatible w/ #wmEvent.x, y). Use when not NULL.
+ * (coords compatible w/ #wmEvent.xy). Use when not NULL.
*/
static void view_zoom_to_window_xy_camera(Scene *scene,
Depsgraph *depsgraph,
@@ -1977,7 +1963,7 @@ static void view_zoom_to_window_xy_camera(Scene *scene,
/**
* \param zoom_xy: Optionally zoom to window location
- * (coords compatible w/ #wmEvent.x, y). Use when not NULL.
+ * (coords compatible w/ #wmEvent.xy). Use when not NULL.
*/
static void view_zoom_to_window_xy_3d(ARegion *region, float dfac, const int zoom_xy[2])
{
@@ -2249,7 +2235,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event_code == VIEW_APPLY) {
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
viewzoom_apply(vod,
- &event->x,
+ event->xy,
(eViewZoom_Style)U.viewzoom,
(U.uiflag & USER_ZOOM_INVERT) != 0,
(use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
@@ -2374,8 +2360,8 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* if one or the other zoom position aren't set, set from event */
if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) {
- RNA_int_set(op->ptr, "mx", event->x);
- RNA_int_set(op->ptr, "my", event->y);
+ RNA_int_set(op->ptr, "mx", event->xy[0]);
+ RNA_int_set(op->ptr, "my", event->xy[1]);
}
if (RNA_struct_property_is_set(op->ptr, "delta")) {
@@ -2385,15 +2371,15 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
if (U.uiflag & USER_ZOOM_HORIZ) {
- vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x;
+ vod->init.event_xy[0] = vod->prev.event_xy[0] = event->xy[0];
}
else {
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
- vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->x -
- event->prevx;
+ vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->xy[0] -
+ event->prev_xy[0];
}
viewzoom_apply(vod,
- &event->prevx,
+ event->prev_xy,
USER_ZOOM_DOLLY,
(U.uiflag & USER_ZOOM_INVERT) != 0,
(use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
@@ -2454,7 +2440,6 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
* \{ */
/* This is an exact copy of #viewzoom_modal_keymap. */
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void viewdolly_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -2572,7 +2557,7 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (event_code == VIEW_APPLY) {
- viewdolly_apply(vod, &event->x, (U.uiflag & USER_ZOOM_INVERT) != 0);
+ viewdolly_apply(vod, event->xy, (U.uiflag & USER_ZOOM_INVERT) != 0);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
@@ -2688,8 +2673,8 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* if one or the other zoom position aren't set, set from event */
if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) {
- RNA_int_set(op->ptr, "mx", event->x);
- RNA_int_set(op->ptr, "my", event->y);
+ RNA_int_set(op->ptr, "mx", event->xy[0]);
+ RNA_int_set(op->ptr, "my", event->xy[1]);
}
if (RNA_struct_property_is_set(op->ptr, "delta")) {
@@ -2706,14 +2691,14 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* Bypass Zoom invert flag for track pads (pass false always) */
if (U.uiflag & USER_ZOOM_HORIZ) {
- vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x;
+ vod->init.event_xy[0] = vod->prev.event_xy[0] = event->xy[0];
}
else {
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
- vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->x -
- event->prevx;
+ vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->xy[0] -
+ event->prev_xy[0];
}
- viewdolly_apply(vod, &event->prevx, (U.uiflag & USER_ZOOM_INVERT) == 0);
+ viewdolly_apply(vod, event->prev_xy, (U.uiflag & USER_ZOOM_INVERT) == 0);
viewops_data_free(C, op);
return OPERATOR_FINISHED;
@@ -3067,6 +3052,23 @@ static int viewselected_exec(bContext *C, wmOperator *op)
if ((gps->flag & GP_STROKE_SELECT) && (gps->flag & GP_STROKE_3DSPACE)) {
ok |= BKE_gpencil_stroke_minmax(gps, true, min, max);
}
+ if (gps->editcurve != NULL) {
+ for (int i = 0; i < gps->editcurve->tot_curve_points; i++) {
+ BezTriple *bezt = &gps->editcurve->curve_points[i].bezt;
+ if ((bezt->f1 & SELECT)) {
+ minmax_v3v3_v3(min, max, bezt->vec[0]);
+ ok = true;
+ }
+ if ((bezt->f2 & SELECT)) {
+ minmax_v3v3_v3(min, max, bezt->vec[1]);
+ ok = true;
+ }
+ if ((bezt->f3 & SELECT)) {
+ minmax_v3v3_v3(min, max, bezt->vec[2]);
+ ok = true;
+ }
+ }
+ }
}
CTX_DATA_END;
@@ -3214,7 +3216,7 @@ static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op))
if (obact->mode & OB_MODE_POSE) {
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact);
- bPoseChannel *pcham_act = BKE_pose_channel_active(obact_eval);
+ bPoseChannel *pcham_act = BKE_pose_channel_active_if_layer_visible(obact_eval);
if (pcham_act) {
BLI_strncpy(v3d->ob_center_bone, pcham_act->name, sizeof(v3d->ob_center_bone));
}
@@ -4421,7 +4423,7 @@ static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (event_code == VIEW_APPLY) {
- viewroll_apply(vod, event->x, event->y);
+ viewroll_apply(vod, event->xy[0], event->xy[1]);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
@@ -4535,8 +4537,8 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
negate_v3(vod->init.mousevec);
if (event->type == MOUSEROTATE) {
- vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x;
- viewroll_apply(vod, event->prevx, event->prevy);
+ vod->init.event_xy[0] = vod->prev.event_xy[0] = event->xy[0];
+ viewroll_apply(vod, event->prev_xy[0], event->prev_xy[1]);
viewops_data_free(C, op);
return OPERATOR_FINISHED;
@@ -4891,6 +4893,7 @@ static int drop_world_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ id_us_min((ID *)scene->world);
id_us_plus(&world->id);
scene->world = world;
@@ -5017,7 +5020,6 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot)
* \{ */
/* cursor position in vec, result in vec, mval in region coords */
-/* NOTE: cannot use `event->mval` here, called by #object_add(). */
void ED_view3d_cursor3d_position(bContext *C,
const int mval[2],
const bool use_depth,
@@ -5099,14 +5101,15 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
float ray_no[3];
float ray_co[3];
- struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- scene, 0, region, v3d);
+ struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create(scene, 0);
float obmat[4][4];
Object *ob_dummy = NULL;
float dist_px = 0;
if (ED_transform_snap_object_project_view3d_ex(snap_context,
CTX_data_ensure_evaluated_depsgraph(C),
+ region,
+ v3d,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
@@ -5120,7 +5123,8 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
ray_no,
NULL,
&ob_dummy,
- obmat) != 0) {
+ obmat,
+ NULL) != 0) {
if (use_depth) {
copy_v3_v3(cursor_co, ray_co);
}
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
index 83d3286c8b3..31ae8a92f81 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_armature.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
@@ -134,7 +134,7 @@ static bool WIDGETGROUP_armature_spline_poll(const bContext *C, wmGizmoGroupType
if (ob) {
const bArmature *arm = ob->data;
if (arm->drawtype == ARM_B_BONE) {
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && pchan->bone->segments > 1) {
return true;
}
@@ -148,7 +148,7 @@ static void WIDGETGROUP_armature_spline_setup(const bContext *C, wmGizmoGroup *g
{
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = BKE_object_pose_armature_get(OBACT(view_layer));
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true);
@@ -187,7 +187,7 @@ static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmGizmoGroup
}
struct BoneSplineWidgetGroup *bspline_group = gzgroup->customdata;
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
/* Handles */
for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) {
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
index 07c3b6bd1d8..513fdbecc74 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
@@ -29,9 +29,11 @@
#include "BLI_math.h"
#include "DNA_mesh_types.h"
+#include "DNA_view3d_types.h"
#include "BKE_context.h"
#include "BKE_editmesh.h"
+#include "BKE_global.h"
#include "BKE_layer.h"
#include "DEG_depsgraph.h"
@@ -51,6 +53,39 @@
#include "ED_view3d.h"
/* -------------------------------------------------------------------- */
+/** \name Shared Internal API
+ * \{ */
+
+/**
+ * Check if drawing should be performed, clear the pre-selection in the case it's disabled.
+ * Without this, the gizmo would be visible while transforming. See T92954.
+ *
+ * NOTE(@campbellbarton): This is a workaround for the gizmo system, since typically poll
+ * would be used for this purpose. The problem with using poll is once the gizmo is visible again
+ * is there is a visible flicker showing the previous location before cursor motion causes the
+ * pre selection to be updated. While this is only a glitch, it's distracting.
+ * The gizmo system it's self could support this use case by tracking which gizmos draw and ensure
+ * gizmos always run #wmGizmoType.test_select before drawing, however pre-selection is already
+ * outside the scope of what gizmos are meant to be used for, so keep this workaround localized
+ * to this gizmo type unless this seems worth supporting for more typical use-cases.
+ *
+ * Longer term it may be better to use #wmPaintCursor instead of gizmos (as snapping preview does).
+ */
+static bool gizmo_preselect_poll_for_draw(const bContext *C, wmGizmo *gz)
+{
+ if (G.moving == false) {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (!(rv3d && (rv3d->rflag & RV3D_NAVIGATING))) {
+ return true;
+ }
+ }
+ ED_view3d_gizmo_mesh_preselect_clear(gz);
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Mesh Element (Vert/Edge/Face) Pre-Select Gizmo API
* \{ */
@@ -65,8 +100,12 @@ typedef struct MeshElemGizmo3D {
struct EditMesh_PreSelElem *psel;
} MeshElemGizmo3D;
-static void gizmo_preselect_elem_draw(const bContext *UNUSED(C), wmGizmo *gz)
+static void gizmo_preselect_elem_draw(const bContext *C, wmGizmo *gz)
{
+ if (!gizmo_preselect_poll_for_draw(C, gz)) {
+ return;
+ }
+
MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
if (gz_ele->base_index != -1) {
Object *ob = gz_ele->bases[gz_ele->base_index]->object;
@@ -292,8 +331,12 @@ typedef struct MeshEdgeRingGizmo3D {
struct EditMesh_PreSelEdgeRing *psel;
} MeshEdgeRingGizmo3D;
-static void gizmo_preselect_edgering_draw(const bContext *UNUSED(C), wmGizmo *gz)
+static void gizmo_preselect_edgering_draw(const bContext *C, wmGizmo *gz)
{
+ if (!gizmo_preselect_poll_for_draw(C, gz)) {
+ return;
+ }
+
MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz;
if (gz_ring->base_index != -1) {
Object *ob = gz_ring->bases[gz_ring->base_index]->object;
@@ -504,4 +547,33 @@ void ED_view3d_gizmo_mesh_preselect_get_active(bContext *C,
}
}
}
+
+void ED_view3d_gizmo_mesh_preselect_clear(wmGizmo *gz)
+{
+ if (STREQ(gz->type->idname, "GIZMO_GT_mesh_preselect_elem_3d")) {
+ MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
+ gz_ele->base_index = -1;
+ gz_ele->vert_index = -1;
+ gz_ele->edge_index = -1;
+ gz_ele->face_index = -1;
+ }
+ else if (STREQ(gz->type->idname, "GIZMO_GT_mesh_preselect_edgering_3d")) {
+ MeshEdgeRingGizmo3D *gz_ele = (MeshEdgeRingGizmo3D *)gz;
+ gz_ele->base_index = -1;
+ gz_ele->edge_index = -1;
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+
+ const char *prop_ids[] = {"object_index", "vert_index", "edge_index", "face_index"};
+ for (int i = 0; i < ARRAY_SIZE(prop_ids); i++) {
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, prop_ids[i]);
+ if (prop == NULL) {
+ continue;
+ }
+ RNA_property_int_set(gz->ptr, prop, -1);
+ }
+}
+
/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index f8278edbcae..1082483dcd7 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -115,8 +115,10 @@ enum {
CONSTRAIN_AXIS_Z = 2,
};
-/* Constraining modes.
- Off / Scene orientation / Global (or Local if Scene orientation is Global) */
+/**
+ * Constraining modes.
+ * Off / Scene orientation / Global (or Local if Scene orientation is Global).
+ */
enum {
CONSTRAIN_MODE_OFF = 0,
CONSTRAIN_MODE_1 = 1,
@@ -163,7 +165,7 @@ typedef struct RulerInfo {
typedef struct RulerItem {
wmGizmo gz;
- /* worldspace coords, middle being optional */
+ /** World-space coords, middle being optional. */
float co[3][3];
int flag;
@@ -332,7 +334,8 @@ static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3], cons
/**
* Use for mouse-move events.
*/
-static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
+static bool view3d_ruler_item_mousemove(const bContext *C,
+ struct Depsgraph *depsgraph,
RulerInfo *ruler_info,
RulerItem *ruler_item,
const int mval[2],
@@ -356,8 +359,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
if (do_thickness && inter->co_index != 1) {
Scene *scene = DEG_get_input_scene(depsgraph);
View3D *v3d = ruler_info->area->spacedata.first;
- SnapObjectContext *snap_context = ED_gizmotypes_snap_3d_context_ensure(
- scene, ruler_info->region, v3d, snap_gizmo);
+ SnapObjectContext *snap_context = ED_gizmotypes_snap_3d_context_ensure(scene, snap_gizmo);
const float mval_fl[2] = {UNPACK2(mval)};
float ray_normal[3];
float ray_start[3];
@@ -367,6 +369,8 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
if (ED_transform_snap_object_project_view3d(snap_context,
depsgraph,
+ ruler_info->region,
+ v3d,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
@@ -382,6 +386,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias);
ED_transform_snap_object_project_ray(snap_context,
depsgraph,
+ v3d,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
.edit_mode_type = SNAP_GEOM_CAGE,
@@ -399,7 +404,6 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
#endif
{
View3D *v3d = ruler_info->area->spacedata.first;
- const float mval_fl[2] = {UNPACK2(mval)};
float *prev_point = NULL;
if (inter->co_index != 1) {
@@ -418,11 +422,8 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point);
}
- ED_gizmotypes_snap_3d_update(
- snap_gizmo, depsgraph, ruler_info->region, v3d, ruler_info->wm, mval_fl);
-
if (ED_gizmotypes_snap_3d_is_enabled(snap_gizmo)) {
- ED_gizmotypes_snap_3d_data_get(snap_gizmo, co, NULL, NULL, NULL);
+ ED_gizmotypes_snap_3d_data_get(C, snap_gizmo, co, NULL, NULL, NULL);
}
#ifdef USE_AXIS_CONSTRAINTS
@@ -644,7 +645,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
GPU_line_width(1.0f);
BLF_enable(blf_mono_font, BLF_ROTATION);
- BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi);
+ BLF_size(blf_mono_font, 14.0f * U.pixelsize, U.dpi);
BLF_rotation(blf_mono_font, 0.0f);
UI_GetThemeColor3ubv(TH_TEXT, color_text);
@@ -1048,7 +1049,8 @@ static int gizmo_ruler_modal(bContext *C,
if (do_cursor_update) {
if (ruler_info->state == RULER_STATE_DRAG) {
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- if (view3d_ruler_item_mousemove(depsgraph,
+ if (view3d_ruler_item_mousemove(C,
+ depsgraph,
ruler_info,
ruler_item,
event->mval,
@@ -1115,7 +1117,8 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
/* update the new location */
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- view3d_ruler_item_mousemove(depsgraph,
+ view3d_ruler_item_mousemove(C,
+ depsgraph,
ruler_info,
ruler_item_pick,
event->mval,
@@ -1234,7 +1237,7 @@ static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup)
(SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
/* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */
SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT));
- ED_gizmotypes_snap_3d_flag_set(gizmo, ED_SNAPGIZMO_SNAP_EDIT_GEOM_CAGE);
+ ED_gizmotypes_snap_3d_flag_set(gizmo, V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE);
WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f});
wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_ruler_add", true);
@@ -1319,7 +1322,8 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
/* snap the first point added, not essential but handy */
inter->co_index = 0;
- view3d_ruler_item_mousemove(depsgraph,
+ view3d_ruler_item_mousemove(C,
+ depsgraph,
ruler_info,
ruler_item,
event->mval,
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
index 0e0d59764e5..1de08e75f80 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
@@ -140,13 +140,10 @@ static void WIDGETGROUP_tool_generic_refresh(const bContext *C, wmGizmoGroup *gz
ToolSettings *ts = CTX_data_tool_settings(C);
if (ts->workspace_tool_type != SCE_WORKSPACE_TOOL_FALLBACK) {
- gzgroup->use_fallback_keymap = false;
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
return;
}
- gzgroup->use_fallback_keymap = true;
-
/* skip, we don't draw anything anyway */
{
int orientation;
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index a21fc006b02..6a1a09df316 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -91,7 +91,13 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
void VIEW3D_OT_toggle_shading(struct wmOperatorType *ot);
void VIEW3D_OT_toggle_xray(struct wmOperatorType *ot);
+/**
+ * For home, center etc.
+ */
void view3d_boxview_copy(struct ScrArea *area, struct ARegion *region);
+/**
+ * Sync center/zoom view of region to others, for view transforms.
+ */
void view3d_boxview_sync(struct ScrArea *area, struct ARegion *region);
void view3d_orbit_apply_dyn_ofs(float r_ofs[3],
@@ -103,27 +109,37 @@ void view3d_orbit_apply_dyn_ofs(float r_ofs[3],
#ifdef WITH_INPUT_NDOF
struct wmNDOFMotionData;
+/**
+ * Called from both fly mode and walk mode,
+ */
void view3d_ndof_fly(const struct wmNDOFMotionData *ndof,
struct View3D *v3d,
struct RegionView3D *rv3d,
- const bool use_precision,
- const short protectflag,
+ bool use_precision,
+ short protectflag,
bool *r_has_translate,
bool *r_has_rotate);
#endif /* WITH_INPUT_NDOF */
/* view3d_navigate_fly.c */
+
void view3d_keymap(struct wmKeyConfig *keyconf);
void VIEW3D_OT_fly(struct wmOperatorType *ot);
/* view3d_navigate_walk.c */
+
void VIEW3D_OT_walk(struct wmOperatorType *ot);
/* view3d_draw.c */
+
void view3d_main_region_draw(const struct bContext *C, struct ARegion *region);
+/**
+ * Information drawn on top of the solid plates and composed data.
+ */
void view3d_draw_region_info(const struct bContext *C, struct ARegion *region);
/* view3d_draw_legacy.c */
+
void ED_view3d_draw_select_loop(struct Depsgraph *depsgraph,
ViewContext *vc,
Scene *scene,
@@ -139,6 +155,9 @@ void ED_view3d_draw_depth_loop(struct Depsgraph *depsgraph,
View3D *v3d);
void view3d_depths_rect_create(struct ARegion *region, struct rcti *rect, struct ViewDepths *r_d);
+/**
+ * Utility function to find the closest Z value, use for auto-depth.
+ */
float view3d_depth_near(struct ViewDepths *d);
/* view3d_select.c */
@@ -175,35 +194,59 @@ typedef struct V3D_SmoothParams {
const float *dyn_ofs;
} V3D_SmoothParams;
+/**
+ * The arguments are the desired situation.
+ */
void ED_view3d_smooth_view_ex(const struct Depsgraph *depsgraph,
struct wmWindowManager *wm,
struct wmWindow *win,
struct ScrArea *area,
struct View3D *v3d,
struct ARegion *region,
- const int smooth_viewtx,
+ int smooth_viewtx,
const V3D_SmoothParams *sview);
void ED_view3d_smooth_view(struct bContext *C,
struct View3D *v3d,
struct ARegion *region,
- const int smooth_viewtx,
+ int smooth_viewtx,
const V3D_SmoothParams *sview);
+/**
+ * Apply the smooth-view immediately, use when we need to start a new view operation.
+ * (so we don't end up half-applying a view operation when pressing keys quickly).
+ */
void ED_view3d_smooth_view_force_finish(struct bContext *C,
struct View3D *v3d,
struct ARegion *region);
+/**
+ * \param rect: optional for picking (can be NULL).
+ */
void view3d_winmatrix_set(struct Depsgraph *depsgraph,
struct ARegion *region,
const View3D *v3d,
const rcti *rect);
+/**
+ * Sets #RegionView3D.viewmat
+ *
+ * \param depsgraph: Depsgraph.
+ * \param scene: Scene for camera and cursor location.
+ * \param v3d: View 3D space data.
+ * \param rv3d: 3D region which stores the final matrices.
+ * \param rect_scale: Optional 2D scale argument,
+ * Use when displaying a sub-region, eg: when #view3d_winmatrix_set takes a 'rect' argument.
+ *
+ * \note don't set windows active in here, is used by renderwin too.
+ */
void view3d_viewmatrix_set(struct Depsgraph *depsgraph,
const struct Scene *scene,
const View3D *v3d,
RegionView3D *rv3d,
const float rect_scale[2]);
+/* Called in transform_ops.c, on each regeneration of key-maps. */
+
void fly_modal_keymap(struct wmKeyConfig *keyconf);
void walk_modal_keymap(struct wmKeyConfig *keyconf);
void viewrotate_modal_keymap(struct wmKeyConfig *keyconf);
@@ -213,23 +256,46 @@ void viewdolly_modal_keymap(struct wmKeyConfig *keyconf);
void viewplace_modal_keymap(struct wmKeyConfig *keyconf);
/* view3d_buttons.c */
+
void VIEW3D_OT_object_mode_pie_or_toggle(struct wmOperatorType *ot);
void view3d_buttons_register(struct ARegionType *art);
/* view3d_camera_control.c */
+
+/**
+ * Creates a #View3DCameraControl handle and sets up
+ * the view for first-person style navigation.
+ */
struct View3DCameraControl *ED_view3d_cameracontrol_acquire(struct Depsgraph *depsgraph,
Scene *scene,
View3D *v3d,
RegionView3D *rv3d);
+/**
+ * Updates cameras from the `rv3d` values, optionally auto-keyframing.
+ */
void ED_view3d_cameracontrol_update(struct View3DCameraControl *vctrl,
- const bool use_autokey,
+ bool use_autokey,
struct bContext *C,
- const bool do_rotate,
- const bool do_translate);
-void ED_view3d_cameracontrol_release(struct View3DCameraControl *vctrl, const bool restore);
+ bool do_rotate,
+ bool do_translate);
+/**
+ * Release view control.
+ *
+ * \param restore: Sets the view state to the values that were set
+ * before #ED_view3d_control_acquire was called.
+ */
+void ED_view3d_cameracontrol_release(struct View3DCameraControl *vctrl, bool restore);
+/**
+ * Returns the object which is being manipulated or NULL.
+ */
struct Object *ED_view3d_cameracontrol_object_get(struct View3DCameraControl *vctrl);
/* view3d_snap.c */
+
+/**
+ * Calculates the bounding box corners (min and max) for \a obedit.
+ * The returned values are in global space.
+ */
bool ED_view3d_minmax_verts(struct Object *obedit, float min[3], float max[3]);
void VIEW3D_OT_snap_selected_to_grid(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index 20e00356152..990b4fc85b1 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -272,8 +272,7 @@ typedef struct foreachScreenFace_userData {
static void meshobject_foreachScreenVert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
foreachScreenObjectVert_userData *data = userData;
struct MVert *mv = &((Mesh *)(data->vc.obact->data))->mvert[index];
@@ -322,8 +321,7 @@ void meshobject_foreachScreenVert(
static void mesh_foreachScreenVert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
foreachScreenVert_userData *data = userData;
BMVert *eve = BM_vert_at_index(data->vc.em->bm, index);
@@ -486,10 +484,6 @@ static void mesh_foreachScreenEdge_clip_bb_segment__mapFunc(void *userData,
data->func(data->userData, eed, screen_co_a, screen_co_b, index);
}
-/**
- * A version of #mesh_foreachScreenEdge that clips the segment when
- * there is a clipping bounding box.
- */
void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc,
void (*func)(void *userData,
BMEdge *eed,
@@ -691,7 +685,6 @@ void nurbs_foreachScreenVert(ViewContext *vc,
/** \name Edit-Meta: For Each Screen Meta-Element
* \{ */
-/* ED_view3d_init_mats_rv3d must be called first */
void mball_foreachScreenElem(struct ViewContext *vc,
void (*func)(void *userData,
struct MetaElem *ml,
@@ -756,7 +749,6 @@ void lattice_foreachScreenVert(ViewContext *vc,
/** \name Edit-Armature: For Each Screen Bone
* \{ */
-/* ED_view3d_init_mats_rv3d must be called first */
void armature_foreachScreenBone(struct ViewContext *vc,
void (*func)(void *userData,
struct EditBone *ebone,
@@ -824,8 +816,6 @@ void armature_foreachScreenBone(struct ViewContext *vc,
/** \name Pose: For Each Screen Bone
* \{ */
-/* ED_view3d_init_mats_rv3d must be called first */
-/* almost _exact_ copy of #armature_foreachScreenBone */
void pose_foreachScreenBone(struct ViewContext *vc,
void (*func)(void *userData,
struct bPoseChannel *pchan,
@@ -834,6 +824,8 @@ void pose_foreachScreenBone(struct ViewContext *vc,
void *userData,
const eV3DProjTest clip_flag)
{
+ /* Almost _exact_ copy of #armature_foreachScreenBone */
+
const Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
const bArmature *arm_eval = ob_eval->data;
bPose *pose = vc->obact->pose;
diff --git a/source/blender/editors/space_view3d/view3d_navigate_fly.c b/source/blender/editors/space_view3d/view3d_navigate_fly.c
index 5752837c40f..2e9cb419e2e 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_fly.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_fly.c
@@ -101,7 +101,6 @@ typedef enum eFlyPanState {
FLY_AXISLOCK_STATE_ACTIVE = 2,
} eFlyPanState;
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void fly_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -539,7 +538,7 @@ static void flyEvent(FlyInfo *fly, const wmEvent *event)
/* Speed adjusting with mouse-pan (track-pad). */
case FLY_MODAL_SPEED: {
- float fac = 0.02f * (event->prevy - event->y);
+ float fac = 0.02f * (event->prev_xy[1] - event->xy[1]);
/* allowing to brake immediate */
if (fac > 0.0f && fly->speed < 0.0f) {
diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c
index 1ac241013ed..ed76b10c95a 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_walk.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c
@@ -142,7 +142,6 @@ typedef enum eWalkLockState {
WALK_AXISLOCK_STATE_DONE = 3,
} eWalkLockState;
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void walk_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -423,6 +422,7 @@ static bool walk_floor_distance_get(RegionView3D *rv3d,
ret = ED_transform_snap_object_project_ray(
walk->snap_context,
walk->depsgraph,
+ walk->v3d,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
/* Avoid having to convert the edit-mesh to a regular mesh. */
@@ -464,6 +464,7 @@ static bool walk_ray_cast(RegionView3D *rv3d,
ret = ED_transform_snap_object_project_ray(walk->snap_context,
walk->depsgraph,
+ walk->v3d,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
},
@@ -602,8 +603,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->rv3d->rflag |= RV3D_NAVIGATING;
- walk->snap_context = ED_transform_snap_object_context_create_view3d(
- walk->scene, 0, walk->region, walk->v3d);
+ walk->snap_context = ED_transform_snap_object_context_create(walk->scene, 0);
walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
walk->depsgraph, walk->scene, walk->v3d, walk->rv3d);
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index eb8c043319c..823aa3b6643 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -63,19 +63,19 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op)
char str[FILE_MAX];
int num_copied = 0;
- BKE_copybuffer_begin(bmain);
+ BKE_copybuffer_copy_begin(bmain);
/* context, selection, could be generalized */
CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
- BKE_copybuffer_tag_ID(&ob->id);
+ BKE_copybuffer_copy_tag_ID(&ob->id);
num_copied++;
}
}
CTX_DATA_END;
BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend");
- BKE_copybuffer_save(bmain, str, op->reports);
+ BKE_copybuffer_copy_end(bmain, str, op->reports);
BKE_reportf(op->reports, RPT_INFO, "Copied %d selected object(s)", num_copied);
diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c
index aa3bf46d2e5..8c1cab6bf14 100644
--- a/source/blender/editors/space_view3d/view3d_placement.c
+++ b/source/blender/editors/space_view3d/view3d_placement.c
@@ -25,17 +25,7 @@
#include "MEM_guardedalloc.h"
-#include "DNA_collection_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_vfont_types.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
#include "BKE_context.h"
-#include "BKE_global.h"
-#include "BKE_main.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -43,30 +33,20 @@
#include "WM_api.h"
#include "WM_toolsystem.h"
-#include "WM_types.h"
-#include "ED_gizmo_library.h"
#include "ED_gizmo_utils.h"
#include "ED_screen.h"
#include "ED_space_api.h"
-#include "ED_transform.h"
-#include "ED_transform_snap_object_context.h"
#include "ED_view3d.h"
#include "UI_resources.h"
-#include "GPU_batch.h"
#include "GPU_immediate.h"
-#include "GPU_matrix.h"
-#include "GPU_state.h"
#include "view3d_intern.h"
static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement";
-static void preview_plane_cursor_setup(wmGizmoGroup *gzgroup);
-static void preview_plane_cursor_visible_set(wmGizmoGroup *gzgroup, bool do_draw);
-
/**
* Dot products below this will be considered view aligned.
* In this case we can't usefully project the mouse cursor onto the plane,
@@ -96,17 +76,6 @@ enum ePlace_Aspect {
PLACE_ASPECT_FIXED = 2,
};
-enum ePlace_Depth {
- PLACE_DEPTH_SURFACE = 1,
- PLACE_DEPTH_CURSOR_PLANE = 2,
- PLACE_DEPTH_CURSOR_VIEW = 3,
-};
-
-enum ePlace_Orient {
- PLACE_ORIENT_SURFACE = 1,
- PLACE_ORIENT_DEFAULT = 2,
-};
-
enum ePlace_SnapTo {
PLACE_SNAP_TO_GEOMETRY = 1,
PLACE_SNAP_TO_DEFAULT = 2,
@@ -178,6 +147,7 @@ struct InteractivePlaceData {
float matrix_orient[3][3];
int orient_axis;
+ V3DSnapCursorState *snap_state;
bool use_snap, is_snap_found, is_snap_invert;
float snap_co[3];
@@ -198,9 +168,6 @@ struct InteractivePlaceData {
/** When activated without a tool. */
bool wait_for_input;
- /** Optional snap gizmo, needed for snapping. */
- wmGizmo *snap_gizmo;
-
enum ePlace_SnapTo snap_to;
};
@@ -251,127 +218,8 @@ static int dot_v3_array_find_max_index(const float dirs[][3],
return index_found;
}
-/**
- * Re-order \a mat so \a axis_align uses its own axis which is closest to \a v.
- */
-static bool mat3_align_axis_to_v3(float mat[3][3], const int axis_align, const float v[3])
-{
- float dot_best = -1.0f;
- int axis_found = axis_align;
- for (int i = 0; i < 3; i++) {
- const float dot_test = fabsf(dot_v3v3(mat[i], v));
- if (dot_test > dot_best) {
- dot_best = dot_test;
- axis_found = i;
- }
- }
-
- if (axis_align != axis_found) {
- float tmat[3][3];
- copy_m3_m3(tmat, mat);
- const int offset = mod_i(axis_found - axis_align, 3);
- for (int i = 0; i < 3; i++) {
- copy_v3_v3(mat[i], tmat[(i + offset) % 3]);
- }
- return true;
- }
- return false;
-}
-
-/* On-screen snap distance. */
-#define MVAL_MAX_PX_DIST 12.0f
-
-static bool idp_snap_point_from_gizmo_ex(wmGizmo *gz, const char *prop_id, float r_location[3])
-{
- if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) {
- PropertyRNA *prop_location = RNA_struct_find_property(gz->ptr, prop_id);
- RNA_property_float_get_array(gz->ptr, prop_location, r_location);
- return true;
- }
- return false;
-}
-
-static bool idp_snap_point_from_gizmo(wmGizmo *gz, float r_location[3])
-{
- return idp_snap_point_from_gizmo_ex(gz, "location", r_location);
-}
-
-static bool idp_snap_normal_from_gizmo(wmGizmo *gz, float r_normal[3])
-{
- return idp_snap_point_from_gizmo_ex(gz, "normal", r_normal);
-}
-
-/**
- * Calculate a 3x3 orientation matrix from the surface under the cursor.
- */
-static bool idp_poject_surface_normal(SnapObjectContext *snap_context,
- struct Depsgraph *depsgraph,
- const float mval_fl[2],
- const float mat_fallback[3][3],
- const float normal_fallback[3],
- float r_mat[3][3])
-{
- bool success = false;
- float normal[3] = {0.0f};
- float co_dummy[3];
- /* We could use the index to get the orientation from the face. */
- Object *ob_snap;
- float obmat[4][4];
-
- if (ED_transform_snap_object_project_view3d_ex(snap_context,
- depsgraph,
- SCE_SNAP_MODE_FACE,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
- .edit_mode_type = SNAP_GEOM_EDIT,
- },
- mval_fl,
- NULL,
- NULL,
- co_dummy,
- normal,
- NULL,
- &ob_snap,
- obmat)) {
- /* pass */
- }
- else if (normal_fallback != NULL) {
- copy_m4_m3(obmat, mat_fallback);
- copy_v3_v3(normal, normal_fallback);
- }
-
- if (!is_zero_v3(normal)) {
- float mat[3][3];
- copy_m3_m4(mat, obmat);
- normalize_m3(mat);
-
- float dot_best = fabsf(dot_v3v3(mat[0], normal));
- int i_best = 0;
- for (int i = 1; i < 3; i++) {
- float dot_test = fabsf(dot_v3v3(mat[i], normal));
- if (dot_test > dot_best) {
- i_best = i;
- dot_best = dot_test;
- }
- }
- if (dot_v3v3(mat[i_best], normal) < 0.0f) {
- negate_v3(mat[(i_best + 1) % 3]);
- negate_v3(mat[(i_best + 2) % 3]);
- }
- copy_v3_v3(mat[i_best], normal);
- orthogonalize_m3(mat, i_best);
- normalize_m3(mat);
-
- copy_v3_v3(r_mat[0], mat[(i_best + 1) % 3]);
- copy_v3_v3(r_mat[1], mat[(i_best + 2) % 3]);
- copy_v3_v3(r_mat[2], mat[i_best]);
- success = true;
- }
-
- return success;
-}
-
-static wmGizmoGroup *idp_gizmogroup_from_region(ARegion *region)
+static UNUSED_FUNCTION_WITH_RETURN_TYPE(wmGizmoGroup *,
+ idp_gizmogroup_from_region)(ARegion *region)
{
wmGizmoMap *gzmap = region->gizmo_map;
return gzmap ? WM_gizmomap_group_find(gzmap, view3d_gzgt_placement_id) : NULL;
@@ -413,20 +261,6 @@ static bool idp_snap_calc_incremental(
return true;
}
-static void idp_snap_gizmo_update_snap_elements(Scene *scene,
- enum ePlace_SnapTo snap_to,
- wmGizmo *gizmo)
-{
- const int snap_mode =
- (snap_to == PLACE_SNAP_TO_GEOMETRY) ?
- (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
- /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */
- SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT) :
- scene->toolsettings->snap_mode;
-
- RNA_enum_set(gizmo->ptr, "snap_elements_force", snap_mode);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -857,151 +691,25 @@ static void draw_primitive_view(const struct bContext *C, ARegion *UNUSED(region
* Use by both the operator and placement cursor.
* \{ */
-static void view3d_interactive_add_calc_plane(bContext *C,
- Scene *scene,
- View3D *v3d,
- ARegion *region,
- const float mval_fl[2],
- wmGizmo *snap_gizmo,
- const enum ePlace_SnapTo snap_to,
- const enum ePlace_Depth plane_depth,
- const enum ePlace_Orient plane_orient,
- const int plane_axis,
- const bool plane_axis_auto,
- float r_co_src[3],
- float r_matrix_orient[3][3])
+static bool view3d_interactive_add_calc_snap(bContext *UNUSED(C),
+ const wmEvent *UNUSED(event),
+ float r_co_src[3],
+ float r_matrix_orient[3][3],
+ bool *r_is_enabled,
+ bool *r_is_snap_invert)
{
- const RegionView3D *rv3d = region->regiondata;
- ED_transform_calc_orientation_from_type(C, r_matrix_orient);
-
- /* Non-orthogonal matrices cause the preview and final result not to match.
- *
- * While making orthogonal doesn't always work well (especially with gimbal orientation for e.g.)
- * it's a corner case, without better alternatives as objects don't support shear. */
- orthogonalize_m3(r_matrix_orient, plane_axis);
-
- SnapObjectContext *snap_context = NULL;
- bool snap_context_free = false;
-
- /* Set the orientation. */
- if ((plane_orient == PLACE_ORIENT_SURFACE) || (plane_depth == PLACE_DEPTH_SURFACE)) {
- snap_context = (snap_gizmo ?
- ED_gizmotypes_snap_3d_context_ensure(scene, region, v3d, snap_gizmo) :
- NULL);
- if (snap_context == NULL) {
- snap_context = ED_transform_snap_object_context_create_view3d(scene, 0, region, v3d);
- snap_context_free = true;
- }
- }
-
- if (plane_orient == PLACE_ORIENT_SURFACE) {
- bool found_surface_or_normal = false;
- float matrix_orient_surface[3][3];
-
- /* Use the snap normal as a fallback in case the cursor isn't over a surface
- * but snapping is enabled. */
- float normal_fallback[3];
- bool use_normal_fallback = snap_gizmo ?
- idp_snap_normal_from_gizmo(snap_gizmo, normal_fallback) :
- false;
-
- if ((snap_context != NULL) &&
- idp_poject_surface_normal(snap_context,
- CTX_data_ensure_evaluated_depsgraph(C),
- mval_fl,
- use_normal_fallback ? r_matrix_orient : NULL,
- use_normal_fallback ? normal_fallback : NULL,
- matrix_orient_surface)) {
- copy_m3_m3(r_matrix_orient, matrix_orient_surface);
- found_surface_or_normal = true;
- }
-
- if (!found_surface_or_normal && plane_axis_auto) {
- /* Drawing into empty space, draw onto the plane most aligned to the view direction. */
- mat3_align_axis_to_v3(r_matrix_orient, plane_axis, rv3d->viewinv[2]);
- }
- }
-
- const bool is_snap_found = snap_gizmo ? idp_snap_point_from_gizmo(snap_gizmo, r_co_src) : false;
-
- if (is_snap_found) {
- /* pass */
- }
- else {
- bool use_depth_fallback = true;
- if (plane_depth == PLACE_DEPTH_CURSOR_VIEW) {
- /* View plane. */
- ED_view3d_win_to_3d(v3d, region, scene->cursor.location, mval_fl, r_co_src);
- use_depth_fallback = false;
- }
- else if (plane_depth == PLACE_DEPTH_SURFACE) {
- if ((snap_context != NULL) &&
- ED_transform_snap_object_project_view3d(snap_context,
- CTX_data_ensure_evaluated_depsgraph(C),
- SCE_SNAP_MODE_FACE,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
- .edit_mode_type = SNAP_GEOM_EDIT,
- },
- mval_fl,
- NULL,
- NULL,
- r_co_src,
- NULL)) {
- use_depth_fallback = false;
- }
- }
-
- /* Use as fallback to surface. */
- if (use_depth_fallback || (plane_depth == PLACE_DEPTH_CURSOR_PLANE)) {
- /* Cursor plane. */
- float plane[4];
- const float *plane_normal = r_matrix_orient[plane_axis];
-
- const float view_axis_dot = fabsf(dot_v3v3(rv3d->viewinv[2], r_matrix_orient[plane_axis]));
- if (view_axis_dot < eps_view_align) {
- /* In this case, just project onto the view plane as it's important the location
- * is _always_ under the mouse cursor, even if it turns out that won't lie on
- * the original 'plane' that's been calculated for us. */
- plane_normal = rv3d->viewinv[2];
- }
-
- plane_from_point_normal_v3(plane, scene->cursor.location, plane_normal);
-
- if (view3d_win_to_3d_on_plane_maybe_fallback(region, plane, mval_fl, NULL, r_co_src)) {
- use_depth_fallback = false;
- }
-
- /* Even if the calculation works, it's possible the point found is behind the view,
- * or very far away (past the far clipping).
- * In either case creating objects won't be useful. */
- if (rv3d->is_persp) {
- float dir[3];
- sub_v3_v3v3(dir, rv3d->viewinv[3], r_co_src);
- const float dot = dot_v3v3(dir, rv3d->viewinv[2]);
- if (dot < v3d->clip_start || dot > v3d->clip_end) {
- use_depth_fallback = true;
- }
- }
- }
-
- if (use_depth_fallback) {
- float co_depth[3];
- /* Fallback to view center. */
- negate_v3_v3(co_depth, rv3d->ofs);
- ED_view3d_win_to_3d(v3d, region, co_depth, mval_fl, r_co_src);
- }
+ V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get(NULL, NULL, 0, 0);
+ copy_v3_v3(r_co_src, snap_data->loc);
+ if (r_matrix_orient) {
+ copy_m3_m3(r_matrix_orient, snap_data->plane_omat);
}
-
- if (!is_snap_found && ((snap_gizmo != NULL) && ED_gizmotypes_snap_3d_is_enabled(snap_gizmo))) {
- if (snap_to == PLACE_SNAP_TO_DEFAULT) {
- idp_snap_calc_incremental(scene, v3d, region, NULL, r_co_src);
- }
+ if (r_is_enabled) {
+ *r_is_enabled = snap_data->is_enabled;
}
-
- if (snap_context_free) {
- ED_transform_snap_object_context_destroy(snap_context);
+ if (r_is_snap_invert) {
+ *r_is_snap_invert = snap_data->is_snap_invert;
}
+ return snap_data->snap_elem != 0;
}
/** \} */
@@ -1012,11 +720,11 @@ static void view3d_interactive_add_calc_plane(bContext *C,
static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEvent *event)
{
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
- const int plane_axis = RNA_enum_get(op->ptr, "plane_axis");
- const bool plane_axis_auto = RNA_boolean_get(op->ptr, "plane_axis_auto");
+ const int plane_axis = snap_state->plane_axis;
const enum ePlace_SnapTo snap_to = RNA_enum_get(op->ptr, "snap_target");
- const enum ePlace_Depth plane_depth = RNA_enum_get(op->ptr, "plane_depth");
+
const enum ePlace_Origin plane_origin[2] = {
RNA_enum_get(op->ptr, "plane_origin_base"),
RNA_enum_get(op->ptr, "plane_origin_depth"),
@@ -1025,58 +733,24 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv
RNA_enum_get(op->ptr, "plane_aspect_base"),
RNA_enum_get(op->ptr, "plane_aspect_depth"),
};
- const enum ePlace_Orient plane_orient = RNA_enum_get(op->ptr, "plane_orientation");
-
- const float mval_fl[2] = {UNPACK2(event->mval)};
struct InteractivePlaceData *ipd = op->customdata;
- /* Assign snap gizmo which is may be used as part of the tool. */
- {
- wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(ipd->region);
- if (gzgroup != NULL) {
- if (gzgroup->gizmos.first) {
- ipd->snap_gizmo = gzgroup->gizmos.first;
- }
+ ipd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
- /* Can be NULL when gizmos are disabled. */
- if (gzgroup->customdata != NULL) {
- preview_plane_cursor_visible_set(gzgroup, false);
- }
- }
+ V3DSnapCursorState *snap_state_new = ED_view3d_cursor_snap_active();
+ if (snap_state_new) {
+ ipd->snap_state = snap_state = snap_state_new;
}
- /* For tweak events the snap target may have changed since dragging,
- * update the snap target at the cursor location where tweak began.
- *
- * NOTE: we could investigating solving this in a more generic way,
- * so each operator doesn't have to account for it. */
- if (ISTWEAK(event->type)) {
- if (ipd->snap_gizmo != NULL) {
- ED_gizmotypes_snap_3d_update(ipd->snap_gizmo,
- CTX_data_ensure_evaluated_depsgraph(C),
- ipd->region,
- ipd->v3d,
- G_MAIN->wm.first,
- mval_fl);
- }
- }
+ snap_state->draw_point = true;
+ snap_state->draw_plane = true;
+ ipd->is_snap_found =
+ view3d_interactive_add_calc_snap(
+ C, event, ipd->co_src, ipd->matrix_orient, &ipd->use_snap, &ipd->is_snap_invert) != 0;
- ipd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
-
- view3d_interactive_add_calc_plane(C,
- ipd->scene,
- ipd->v3d,
- ipd->region,
- mval_fl,
- ipd->snap_gizmo,
- snap_to,
- plane_depth,
- plane_orient,
- plane_axis,
- plane_axis_auto,
- ipd->co_src,
- ipd->matrix_orient);
+ snap_state->draw_plane = false;
+ ED_view3d_cursor_snap_prevpoint_set(snap_state, ipd->co_src);
ipd->orient_axis = plane_axis;
for (int i = 0; i < 2; i++) {
@@ -1155,13 +829,6 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv
}
}
- ipd->is_snap_invert = ipd->snap_gizmo ? ED_gizmotypes_snap_3d_invert_snap_get(ipd->snap_gizmo) :
- false;
- {
- const ToolSettings *ts = ipd->scene->toolsettings;
- ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP));
- }
-
ipd->draw_handle_view = ED_region_draw_cb_activate(
ipd->region->type, draw_primitive_view, ipd, REGION_DRAW_POST_VIEW);
@@ -1237,20 +904,12 @@ static void view3d_interactive_add_exit(bContext *C, wmOperator *op)
UNUSED_VARS(C);
struct InteractivePlaceData *ipd = op->customdata;
+ ED_view3d_cursor_snap_deactive(ipd->snap_state);
ED_region_draw_cb_exit(ipd->region->type, ipd->draw_handle_view);
ED_region_tag_redraw(ipd->region);
- {
- wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(ipd->region);
- if (gzgroup != NULL) {
- if (gzgroup->customdata != NULL) {
- preview_plane_cursor_visible_set(gzgroup, true);
- }
- }
- }
-
MEM_freeN(ipd);
}
@@ -1368,6 +1027,8 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve
if (ipd->step_index == STEP_BASE) {
if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) {
if (event->val == KM_RELEASE) {
+ ED_view3d_cursor_snap_prevpoint_set(ipd->snap_state, ipd->co_src);
+
/* Set secondary plane. */
/* Create normal. */
@@ -1515,19 +1176,8 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve
/* Calculate the snap location on mouse-move or when toggling snap. */
ipd->is_snap_found = false;
if (ipd->use_snap) {
- if (ipd->snap_gizmo != NULL) {
- ED_gizmotypes_snap_3d_flag_set(ipd->snap_gizmo, ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE);
- if (ED_gizmotypes_snap_3d_update(ipd->snap_gizmo,
- CTX_data_ensure_evaluated_depsgraph(C),
- ipd->region,
- ipd->v3d,
- G_MAIN->wm.first,
- mval_fl)) {
- ED_gizmotypes_snap_3d_data_get(ipd->snap_gizmo, ipd->snap_co, NULL, NULL, NULL);
- ipd->is_snap_found = true;
- }
- ED_gizmotypes_snap_3d_flag_clear(ipd->snap_gizmo, ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE);
- }
+ ipd->is_snap_found = view3d_interactive_add_calc_snap(
+ C, event, ipd->snap_co, NULL, NULL, NULL);
}
if (ipd->step_index == STEP_BASE) {
@@ -1597,6 +1247,98 @@ static bool view3d_interactive_add_poll(bContext *C)
return ELEM(mode, CTX_MODE_OBJECT, CTX_MODE_EDIT_MESH);
}
+static int idp_rna_plane_axis_get_fn(struct PointerRNA *UNUSED(ptr),
+ struct PropertyRNA *UNUSED(prop))
+{
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ return snap_state->plane_axis;
+}
+
+static void idp_rna_plane_axis_set_fn(struct PointerRNA *UNUSED(ptr),
+ struct PropertyRNA *UNUSED(prop),
+ int value)
+{
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ snap_state->plane_axis = (short)value;
+ ED_view3d_cursor_snap_state_default_set(snap_state);
+}
+
+static int idp_rna_plane_depth_get_fn(struct PointerRNA *UNUSED(ptr),
+ struct PropertyRNA *UNUSED(prop))
+{
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ return snap_state->plane_depth;
+}
+
+static void idp_rna_plane_depth_set_fn(struct PointerRNA *UNUSED(ptr),
+ struct PropertyRNA *UNUSED(prop),
+ int value)
+{
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ snap_state->plane_depth = value;
+ ED_view3d_cursor_snap_state_default_set(snap_state);
+}
+
+static int idp_rna_plane_orient_get_fn(struct PointerRNA *UNUSED(ptr),
+ struct PropertyRNA *UNUSED(prop))
+{
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ return snap_state->plane_orient;
+}
+
+static void idp_rna_plane_orient_set_fn(struct PointerRNA *UNUSED(ptr),
+ struct PropertyRNA *UNUSED(prop),
+ int value)
+{
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ snap_state->plane_orient = value;
+ ED_view3d_cursor_snap_state_default_set(snap_state);
+}
+
+static int idp_rna_snap_target_get_fn(struct PointerRNA *UNUSED(ptr),
+ struct PropertyRNA *UNUSED(prop))
+{
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ if (!snap_state->snap_elem_force) {
+ return PLACE_SNAP_TO_DEFAULT;
+ }
+
+ /* Make sure you keep a consistent #snap_mode. */
+ snap_state->snap_elem_force = SCE_SNAP_MODE_GEOM;
+ return PLACE_SNAP_TO_GEOMETRY;
+}
+
+static void idp_rna_snap_target_set_fn(struct PointerRNA *UNUSED(ptr),
+ struct PropertyRNA *UNUSED(prop),
+ int value)
+{
+ short snap_mode = 0; /* #toolsettings->snap_mode. */
+ const enum ePlace_SnapTo snap_to = value;
+ if (snap_to == PLACE_SNAP_TO_GEOMETRY) {
+ snap_mode = SCE_SNAP_MODE_GEOM;
+ }
+
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ snap_state->snap_elem_force = snap_mode;
+ ED_view3d_cursor_snap_state_default_set(snap_state);
+}
+
+static bool idp_rna_use_plane_axis_auto_get_fn(struct PointerRNA *UNUSED(ptr),
+ struct PropertyRNA *UNUSED(prop))
+{
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ return snap_state->use_plane_axis_auto;
+}
+
+static void idp_rna_use_plane_axis_auto_set_fn(struct PointerRNA *UNUSED(ptr),
+ struct PropertyRNA *UNUSED(prop),
+ bool value)
+{
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get();
+ snap_state->use_plane_axis_auto = value;
+ ED_view3d_cursor_snap_state_default_set(snap_state);
+}
+
void VIEW3D_OT_interactive_add(struct wmOperatorType *ot)
{
/* identifiers */
@@ -1617,6 +1359,12 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot)
/* properties */
PropertyRNA *prop;
+ /* WORKAROUND: properties with `_funcs_runtime` should not be saved in keymaps.
+ * So reassign the #PROP_IDPROPERTY flag to trick the property as not being set.
+ * (See #RNA_property_is_set). */
+ PropertyFlag unsalvageable = PROP_SKIP_SAVE | PROP_HIDDEN | PROP_PTR_NO_OWNERSHIP |
+ PROP_IDPROPERTY;
+
/* Normally not accessed directly, leave unset and check the active tool. */
static const EnumPropertyItem primitive_type[] = {
{PLACE_PRIMITIVE_TYPE_CUBE, "CUBE", 0, "Cube", ""},
@@ -1626,6 +1374,7 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot)
{PLACE_PRIMITIVE_TYPE_SPHERE_ICO, "SPHERE_ICO", 0, "ICO Sphere", ""},
{0, NULL, 0, NULL, NULL},
};
+
prop = RNA_def_property(ot->srna, "primitive_type", PROP_ENUM, PROP_NONE);
RNA_def_property_ui_text(prop, "Primitive", "");
RNA_def_property_enum_items(prop, primitive_type);
@@ -1635,7 +1384,9 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot)
RNA_def_property_ui_text(prop, "Plane Axis", "The axis used for placing the base region");
RNA_def_property_enum_default(prop, 2);
RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_enum_funcs_runtime(
+ prop, idp_rna_plane_axis_get_fn, idp_rna_plane_axis_set_fn, NULL);
+ RNA_def_property_flag(prop, unsalvageable);
prop = RNA_def_boolean(ot->srna,
"plane_axis_auto",
@@ -1643,21 +1394,23 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot)
"Auto Axis",
"Select the closest axis when placing objects "
"(surface overrides)");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_boolean_funcs_runtime(
+ prop, idp_rna_use_plane_axis_auto_get_fn, idp_rna_use_plane_axis_auto_set_fn);
+ RNA_def_property_flag(prop, unsalvageable);
static const EnumPropertyItem plane_depth_items[] = {
- {PLACE_DEPTH_SURFACE,
+ {V3D_PLACE_DEPTH_SURFACE,
"SURFACE",
0,
"Surface",
"Start placing on the surface, using the 3D cursor position as a fallback"},
- {PLACE_DEPTH_CURSOR_PLANE,
+ {V3D_PLACE_DEPTH_CURSOR_PLANE,
"CURSOR_PLANE",
0,
"Cursor Plane",
"Start placement using a point projected onto the orientation axis "
"at the 3D cursor position"},
- {PLACE_DEPTH_CURSOR_VIEW,
+ {V3D_PLACE_DEPTH_CURSOR_VIEW,
"CURSOR_VIEW",
0,
"Cursor View",
@@ -1666,17 +1419,19 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot)
};
prop = RNA_def_property(ot->srna, "plane_depth", PROP_ENUM, PROP_NONE);
RNA_def_property_ui_text(prop, "Position", "The initial depth used when placing the cursor");
- RNA_def_property_enum_default(prop, PLACE_DEPTH_SURFACE);
+ RNA_def_property_enum_default(prop, V3D_PLACE_DEPTH_SURFACE);
RNA_def_property_enum_items(prop, plane_depth_items);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_enum_funcs_runtime(
+ prop, idp_rna_plane_depth_get_fn, idp_rna_plane_depth_set_fn, NULL);
+ RNA_def_property_flag(prop, unsalvageable);
static const EnumPropertyItem plane_orientation_items[] = {
- {PLACE_ORIENT_SURFACE,
+ {V3D_PLACE_ORIENT_SURFACE,
"SURFACE",
ICON_SNAP_NORMAL,
"Surface",
"Use the surface normal (using the transform orientation as a fallback)"},
- {PLACE_ORIENT_DEFAULT,
+ {V3D_PLACE_ORIENT_DEFAULT,
"DEFAULT",
ICON_ORIENTATION_GLOBAL,
"Default",
@@ -1685,9 +1440,11 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot)
};
prop = RNA_def_property(ot->srna, "plane_orientation", PROP_ENUM, PROP_NONE);
RNA_def_property_ui_text(prop, "Orientation", "The initial depth used when placing the cursor");
- RNA_def_property_enum_default(prop, PLACE_ORIENT_SURFACE);
+ RNA_def_property_enum_default(prop, V3D_PLACE_ORIENT_SURFACE);
RNA_def_property_enum_items(prop, plane_orientation_items);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_enum_funcs_runtime(
+ prop, idp_rna_plane_orient_get_fn, idp_rna_plane_orient_set_fn, NULL);
+ RNA_def_property_flag(prop, unsalvageable);
static const EnumPropertyItem snap_to_items[] = {
{PLACE_SNAP_TO_GEOMETRY, "GEOMETRY", 0, "Geometry", "Snap to all geometry"},
@@ -1698,7 +1455,9 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot)
RNA_def_property_ui_text(prop, "Snap to", "The target to use while snapping");
RNA_def_property_enum_default(prop, PLACE_SNAP_TO_GEOMETRY);
RNA_def_property_enum_items(prop, snap_to_items);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_enum_funcs_runtime(
+ prop, idp_rna_snap_target_get_fn, idp_rna_snap_target_set_fn, NULL);
+ RNA_def_property_flag(prop, unsalvageable);
{ /* Plane Origin. */
static const EnumPropertyItem items[] = {
@@ -1746,24 +1505,22 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot)
* we could show a placement plane here.
* \{ */
-static void WIDGETGROUP_placement_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+static void preview_plane_free_fn(void *customdata)
{
- wmGizmo *gizmo;
-
- {
- /* The gizmo snap has to be the first gizmo. */
- const wmGizmoType *gzt_snap;
- gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
- gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL);
+ V3DSnapCursorState *snap_state = customdata;
+ ED_view3d_cursor_snap_deactive(snap_state);
+}
- WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f});
+static void WIDGETGROUP_placement_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_active();
+ if (snap_state) {
+ snap_state->gzgrp_type = gzgroup->type;
+ snap_state->draw_plane = true;
- /* Don't handle any events, this is for display only. */
- gizmo->flag |= WM_GIZMO_HIDDEN_KEYMAP;
+ gzgroup->customdata = snap_state;
+ gzgroup->customdata_free = preview_plane_free_fn;
}
-
- /* Sets the gizmos custom-data which has its own free callback. */
- preview_plane_cursor_setup(gzgroup);
}
void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt)
@@ -1781,353 +1538,3 @@ void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt)
}
/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Placement Preview Plane
- *
- * Preview the plane that will be used for placement.
- *
- * Note that we might want to split this into its own file,
- * for now this is coupled with the 3D view placement gizmo.
- * \{ */
-
-static void gizmo_plane_update_cursor(const bContext *C,
- ARegion *region,
- const int mval[2],
- float r_co[3],
- float r_matrix_orient[3][3],
- int *r_plane_axis)
-{
- wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_interactive_add", true);
- BLI_assert(ot != NULL);
- PointerRNA ptr;
-
- ScrArea *area = CTX_wm_area(C);
- BLI_assert(region == CTX_wm_region(C));
- bToolRef *tref = area->runtime.tool;
- WM_toolsystem_ref_properties_ensure_from_operator(tref, ot, &ptr);
-
- const enum ePlace_SnapTo snap_to = RNA_enum_get(&ptr, "snap_target");
- const int plane_axis = RNA_enum_get(&ptr, "plane_axis");
- const bool plane_axis_auto = RNA_boolean_get(&ptr, "plane_axis_auto");
- const enum ePlace_Depth plane_depth = RNA_enum_get(&ptr, "plane_depth");
- const enum ePlace_Orient plane_orient = RNA_enum_get(&ptr, "plane_orientation");
-
- const float mval_fl[2] = {UNPACK2(mval)};
-
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
-
- /* Assign snap gizmo which is may be used as part of the tool. */
- wmGizmo *snap_gizmo = NULL;
- {
- wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(region);
- if ((gzgroup != NULL) && gzgroup->gizmos.first) {
- snap_gizmo = gzgroup->gizmos.first;
- }
- }
-
- /* This ensures the snap gizmo has settings from this tool.
- * This function call could be moved a more appropriate place,
- * responding to the setting being changed for example,
- * however setting the value isn't expensive, so do it here. */
- idp_snap_gizmo_update_snap_elements(scene, snap_to, snap_gizmo);
-
- view3d_interactive_add_calc_plane((bContext *)C,
- scene,
- v3d,
- region,
- mval_fl,
- snap_gizmo,
- snap_to,
- plane_depth,
- plane_orient,
- plane_axis,
- plane_axis_auto,
- r_co,
- r_matrix_orient);
- *r_plane_axis = plane_axis;
-}
-
-static void gizmo_plane_draw_grid(const int resolution,
- const float scale,
- const float scale_fade,
- const float matrix[4][4],
- const int plane_axis,
- const float color[4])
-{
- BLI_assert(scale_fade <= scale);
- const int resolution_min = resolution - 1;
- float color_fade[4] = {UNPACK4(color)};
- const float *center = matrix[3];
-
- GPU_blend(GPU_BLEND_ADDITIVE);
- GPU_line_smooth(true);
- GPU_line_width(1.0f);
-
- GPUVertFormat *format = immVertexFormat();
- const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- const uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-
- immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
-
- const size_t coords_len = resolution * resolution;
- float(*coords)[3] = MEM_mallocN(sizeof(*coords) * coords_len, __func__);
-
- const int axis_x = (plane_axis + 0) % 3;
- const int axis_y = (plane_axis + 1) % 3;
- const int axis_z = (plane_axis + 2) % 3;
-
- int i;
- const float resolution_div = (float)1.0f / (float)resolution;
- i = 0;
- for (int x = 0; x < resolution; x++) {
- const float x_fl = (x * resolution_div) - 0.5f;
- for (int y = 0; y < resolution; y++) {
- const float y_fl = (y * resolution_div) - 0.5f;
- coords[i][axis_x] = 0.0f;
- coords[i][axis_y] = x_fl * scale;
- coords[i][axis_z] = y_fl * scale;
- mul_m4_v3(matrix, coords[i]);
- i += 1;
- }
- }
- BLI_assert(i == coords_len);
- immBeginAtMost(GPU_PRIM_LINES, coords_len * 4);
- i = 0;
- for (int x = 0; x < resolution_min; x++) {
- for (int y = 0; y < resolution_min; y++) {
-
- /* Add #resolution_div to ensure we fade-out entirely. */
-#define FADE(v) \
- max_ff(0.0f, (1.0f - square_f(((len_v3v3(v, center) / scale_fade) + resolution_div) * 2.0f)))
-
- const float *v0 = coords[(resolution * x) + y];
- const float *v1 = coords[(resolution * (x + 1)) + y];
- const float *v2 = coords[(resolution * x) + (y + 1)];
-
- const float f0 = FADE(v0);
- const float f1 = FADE(v1);
- const float f2 = FADE(v2);
-
- if (f0 > 0.0f || f1 > 0.0f) {
- color_fade[3] = color[3] * f0;
- immAttr4fv(col_id, color_fade);
- immVertex3fv(pos_id, v0);
- color_fade[3] = color[3] * f1;
- immAttr4fv(col_id, color_fade);
- immVertex3fv(pos_id, v1);
- }
- if (f0 > 0.0f || f2 > 0.0f) {
- color_fade[3] = color[3] * f0;
- immAttr4fv(col_id, color_fade);
- immVertex3fv(pos_id, v0);
-
- color_fade[3] = color[3] * f2;
- immAttr4fv(col_id, color_fade);
- immVertex3fv(pos_id, v2);
- }
-
-#undef FADE
-
- i++;
- }
- }
-
- MEM_freeN(coords);
-
- immEnd();
-
- immUnbindProgram();
-
- GPU_line_smooth(false);
- GPU_blend(GPU_BLEND_NONE);
-}
-
-/* -------------------------------------------------------------------- */
-/** \name Preview Plane Cursor
- * \{ */
-
-struct PlacementCursor {
- /**
- * Back-pointer to the gizmo-group that uses this cursor.
- * Needed so we know that the cursor belongs to the region.
- */
- wmGizmoGroup *gzgroup;
-
- /**
- * Enable this while the modal operator is running,
- * so the preview-plane doesn't show at the same time as add-object preview shape
- * since it's distracting & not helpful.
- */
- bool do_draw;
-
- void *paintcursor;
-
- int plane_axis;
- float matrix[4][4];
-
- /* Check if we need to re-calculate the plane matrix. */
- int mval_prev[2];
- float persmat_prev[4][4];
-};
-
-static void cursor_plane_draw(bContext *C, int x, int y, void *customdata)
-{
- struct PlacementCursor *plc = (struct PlacementCursor *)customdata;
- ARegion *region = CTX_wm_region(C);
- const RegionView3D *rv3d = region->regiondata;
-
- /* Early exit.
- * Note that we can't do most of these checks in the poll function (besides global checks)
- * so test them here instead.
- *
- * This cursor is only active while the gizmo is being used
- * so it's not so important to have a poll function. */
- if (plc->do_draw == false) {
- return;
- }
- if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) {
- return;
- }
- if (rv3d->rflag & RV3D_NAVIGATING) {
- return;
- }
-
- /* Check this gizmo group is in the region. */
- {
- wmGizmoMap *gzmap = region->gizmo_map;
- wmGizmoGroup *gzgroup_test = WM_gizmomap_group_find_ptr(gzmap, plc->gzgroup->type);
- if (gzgroup_test != plc->gzgroup) {
- /* Wrong viewport. */
- return;
- }
- }
-
- const int mval[2] = {x - region->winrct.xmin, y - region->winrct.ymin};
-
- /* Update matrix? */
- if ((plc->mval_prev[0] != mval[0]) || (plc->mval_prev[1] != mval[1]) ||
- !equals_m4m4(plc->persmat_prev, rv3d->persmat)) {
- plc->mval_prev[0] = mval[0];
- plc->mval_prev[1] = mval[1];
-
- float orient_matrix[3][3];
- float co[3];
- gizmo_plane_update_cursor(C, region, mval, co, orient_matrix, &plc->plane_axis);
- copy_m4_m3(plc->matrix, orient_matrix);
- copy_v3_v3(plc->matrix[3], co);
-
- copy_m4_m4(plc->persmat_prev, rv3d->persmat);
- }
-
- /* Draw */
- float pixel_size;
-
- if (rv3d->is_persp) {
- float center[3];
- negate_v3_v3(center, rv3d->ofs);
- pixel_size = ED_view3d_pixel_size(rv3d, center);
- }
- else {
- pixel_size = ED_view3d_pixel_size(rv3d, plc->matrix[3]);
- }
-
- if (pixel_size > FLT_EPSILON) {
-
- /* Arbitrary, 1.0 is a little too strong though. */
- float color_alpha = 0.75f;
- if (rv3d->is_persp) {
- /* Scale down the alpha when this is drawn very small,
- * since the add shader causes the small size to show too dense & bright. */
- const float relative_pixel_scale = pixel_size / ED_view3d_pixel_size(rv3d, plc->matrix[3]);
- if (relative_pixel_scale < 1.0f) {
- color_alpha *= max_ff(square_f(relative_pixel_scale), 0.3f);
- }
- }
-
- {
- /* Extra adjustment when it's near view-aligned as it seems overly bright. */
- float view_vector[3];
- ED_view3d_global_to_vector(rv3d, plc->matrix[3], view_vector);
- float view_dot = fabsf(dot_v3v3(plc->matrix[plc->plane_axis], view_vector));
- color_alpha *= max_ff(0.3f, 1.0f - square_f(square_f(1.0f - view_dot)));
- }
-
- /* Setup viewport & matrix. */
- wmViewport(&region->winrct);
- GPU_matrix_push_projection();
- GPU_matrix_push();
- GPU_matrix_projection_set(rv3d->winmat);
- GPU_matrix_set(rv3d->viewmat);
-
- const float scale_mod = U.gizmo_size * 2 * U.dpi_fac / U.pixelsize;
-
- float final_scale = (scale_mod * pixel_size);
-
- const int lines_subdiv = 10;
- int lines = lines_subdiv;
-
- float final_scale_fade = final_scale;
- final_scale = ceil_power_of_10(final_scale);
-
- float fac = final_scale_fade / final_scale;
-
- float color[4] = {1, 1, 1, color_alpha};
- color[3] *= square_f(1.0f - fac);
- if (color[3] > 0.0f) {
- gizmo_plane_draw_grid(lines * lines_subdiv,
- final_scale,
- final_scale_fade,
- plc->matrix,
- plc->plane_axis,
- color);
- }
-
- color[3] = color_alpha;
- /* When the grid is large, we only need the 2x lines in the middle. */
- if (fac < 0.2f) {
- lines = 1;
- final_scale = final_scale_fade;
- }
- gizmo_plane_draw_grid(
- lines, final_scale, final_scale_fade, plc->matrix, plc->plane_axis, color);
-
- /* Restore matrix. */
- GPU_matrix_pop();
- GPU_matrix_pop_projection();
- }
-}
-
-static void preview_plane_cursor_free(void *customdata)
-{
- struct PlacementCursor *plc = customdata;
-
- /* The window manager is freed first on exit. */
- wmWindowManager *wm = G_MAIN->wm.first;
- if (UNLIKELY(wm != NULL)) {
- WM_paint_cursor_end(plc->paintcursor);
- }
- MEM_freeN(plc);
-}
-
-static void preview_plane_cursor_setup(wmGizmoGroup *gzgroup)
-{
- BLI_assert(gzgroup->customdata == NULL);
- struct PlacementCursor *plc = MEM_callocN(sizeof(*plc), __func__);
- plc->gzgroup = gzgroup;
- plc->paintcursor = WM_paint_cursor_activate(
- SPACE_VIEW3D, RGN_TYPE_WINDOW, NULL, cursor_plane_draw, plc);
- gzgroup->customdata = plc;
- gzgroup->customdata_free = preview_plane_cursor_free;
-
- preview_plane_cursor_visible_set(gzgroup, true);
-}
-
-static void preview_plane_cursor_visible_set(wmGizmoGroup *gzgroup, bool do_draw)
-{
- struct PlacementCursor *plc = gzgroup->customdata;
- plc->do_draw = do_draw;
-}
-
-/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 88efc530484..8c2e0df0275 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -43,9 +43,6 @@
/* Non Clipping Projection Functions
* ********************************* */
-/**
- * \note use #ED_view3d_ob_project_mat_get to get the projection matrix
- */
void ED_view3d_project_float_v2_m4(const ARegion *region,
const float co[3],
float r_co[2],
@@ -68,9 +65,6 @@ void ED_view3d_project_float_v2_m4(const ARegion *region,
}
}
-/**
- * \note use #ED_view3d_ob_project_mat_get to get projecting mat
- */
void ED_view3d_project_float_v3_m4(const ARegion *region,
const float co[3],
float r_co[3],
@@ -231,7 +225,6 @@ eV3DProjStatus ED_view3d_project_float_ex(const ARegion *region,
return ret;
}
-/* --- short --- */
eV3DProjStatus ED_view3d_project_short_global(const ARegion *region,
const float co[3],
short r_co[2],
@@ -240,7 +233,6 @@ eV3DProjStatus ED_view3d_project_short_global(const ARegion *region,
RegionView3D *rv3d = region->regiondata;
return ED_view3d_project_short_ex(region, rv3d->persmat, false, co, r_co, flag);
}
-/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_short_object(const ARegion *region,
const float co[3],
short r_co[2],
@@ -251,7 +243,6 @@ eV3DProjStatus ED_view3d_project_short_object(const ARegion *region,
return ED_view3d_project_short_ex(region, rv3d->persmatob, true, co, r_co, flag);
}
-/* --- int --- */
eV3DProjStatus ED_view3d_project_int_global(const ARegion *region,
const float co[3],
int r_co[2],
@@ -260,7 +251,6 @@ eV3DProjStatus ED_view3d_project_int_global(const ARegion *region,
RegionView3D *rv3d = region->regiondata;
return ED_view3d_project_int_ex(region, rv3d->persmat, false, co, r_co, flag);
}
-/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_int_object(const ARegion *region,
const float co[3],
int r_co[2],
@@ -271,7 +261,6 @@ eV3DProjStatus ED_view3d_project_int_object(const ARegion *region,
return ED_view3d_project_int_ex(region, rv3d->persmatob, true, co, r_co, flag);
}
-/* --- float --- */
eV3DProjStatus ED_view3d_project_float_global(const ARegion *region,
const float co[3],
float r_co[2],
@@ -280,7 +269,6 @@ eV3DProjStatus ED_view3d_project_float_global(const ARegion *region,
RegionView3D *rv3d = region->regiondata;
return ED_view3d_project_float_ex(region, rv3d->persmat, false, co, r_co, flag);
}
-/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_float_object(const ARegion *region,
const float co[3],
float r_co[2],
@@ -304,9 +292,6 @@ float ED_view3d_pixel_size_no_ui_scale(const RegionView3D *rv3d, const float co[
return mul_project_m4_v3_zfac(rv3d->persmat, co) * rv3d->pixsize;
}
-/**
- * Calculate a depth value from \a co, use with #ED_view3d_win_to_delta
- */
float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_flip)
{
float zfac = mul_project_m4_v3_zfac(rv3d->persmat, co);
@@ -330,9 +315,6 @@ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_f
return zfac;
}
-/**
- * Calculate a depth value from `co` (result should only be used for comparison).
- */
float ED_view3d_calc_depth_for_comparison(const RegionView3D *rv3d, const float co[3])
{
if (rv3d->is_persp) {
@@ -388,22 +370,6 @@ bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float
return true;
}
-/**
- * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
- * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
- * ray_start is clipped by the view near limit so points in front of it are always in view.
- * In orthographic view the resulting ray_normal will match the view vector.
- * This version also returns the ray_co point of the ray on window plane, useful to fix precision
- * issues esp. with ortho view, where default ray_start is set rather far away.
- * \param region: The region (used for the window width and height).
- * \param v3d: The 3d viewport (used for near clipping value).
- * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
- * \param r_ray_co: The world-space point where the ray intersects the window plane.
- * \param r_ray_normal: The normalized world-space direction of towards mval.
- * \param r_ray_start: The world-space starting point of the ray.
- * \param do_clip_planes: Optionally clip the start of the ray by the view clipping planes.
- * \return success, false if the ray is totally clipped.
- */
bool ED_view3d_win_to_ray_clipped_ex(struct Depsgraph *depsgraph,
const ARegion *region,
const View3D *v3d,
@@ -426,19 +392,6 @@ bool ED_view3d_win_to_ray_clipped_ex(struct Depsgraph *depsgraph,
return true;
}
-/**
- * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
- * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
- * ray_start is clipped by the view near limit so points in front of it are always in view.
- * In orthographic view the resulting ray_normal will match the view vector.
- * \param region: The region (used for the window width and height).
- * \param v3d: The 3d viewport (used for near clipping value).
- * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
- * \param r_ray_start: The world-space point where the ray intersects the window plane.
- * \param r_ray_normal: The normalized world-space direction of towards mval.
- * \param do_clip_planes: Optionally clip the start of the ray by the view clipping planes.
- * \return success, false if the ray is totally clipped.
- */
bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph,
const ARegion *region,
const View3D *v3d,
@@ -451,17 +404,6 @@ bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph,
depsgraph, region, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip_planes);
}
-/**
- * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
- * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
- * \param region: The region (used for the window width and height).
- * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
- * \param r_ray_start: The world-space point where the ray intersects the window plane.
- * \param r_ray_normal: The normalized world-space direction of towards mval.
- *
- * \note Ignores view near/far clipping,
- * to take this into account use #ED_view3d_win_to_ray_clipped.
- */
void ED_view3d_win_to_ray(const ARegion *region,
const float mval[2],
float r_ray_start[3],
@@ -471,13 +413,6 @@ void ED_view3d_win_to_ray(const ARegion *region,
ED_view3d_win_to_vector(region, mval, r_ray_normal);
}
-/**
- * Calculate a normalized 3d direction vector from the viewpoint towards a global location.
- * In orthographic view the resulting vector will match the view vector.
- * \param rv3d: The region (used for the window width and height).
- * \param coord: The world-space location.
- * \param vec: The resulting normalized vector.
- */
void ED_view3d_global_to_vector(const RegionView3D *rv3d, const float coord[3], float vec[3])
{
if (rv3d->is_persp) {
@@ -536,13 +471,6 @@ bool view3d_get_view_aligned_coordinate(ARegion *region,
}
#endif
-/**
- * Calculate a 3d location from 2d window coordinates.
- * \param region: The region (used for the window width and height).
- * \param depth_pt: The reference location used to calculate the Z depth.
- * \param mval: The area relative location (such as event->mval converted to floats).
- * \param r_out: The resulting world-space location.
- */
void ED_view3d_win_to_3d(const View3D *v3d,
const ARegion *region,
const float depth_pt[3],
@@ -636,13 +564,6 @@ bool ED_view3d_win_to_3d_on_plane_int(const ARegion *region,
return ED_view3d_win_to_3d_on_plane(region, plane, mval_fl, do_clip, r_out);
}
-/**
- * A wrapper for #ED_view3d_win_to_3d_on_plane that projects onto \a plane_fallback
- * then maps this back to \a plane.
- *
- * This is intended to be used when \a plane is orthogonal to the views Z axis where
- * projecting the \a mval doesn't work well (or fail completely when exactly aligned).
- */
bool ED_view3d_win_to_3d_on_plane_with_fallback(const ARegion *region,
const float plane[4],
const float mval[2],
@@ -678,14 +599,6 @@ bool ED_view3d_win_to_3d_on_plane_with_fallback(const ARegion *region,
return true;
}
-/**
- * Calculate a 3d difference vector from 2d window offset.
- * note that #ED_view3d_calc_zfac() must be called first to determine
- * the depth used to calculate the delta.
- * \param region: The region (used for the window width and height).
- * \param mval: The area relative 2d difference (such as event->mval[0] - other_x).
- * \param out: The resulting world-space delta.
- */
void ED_view3d_win_to_delta(const ARegion *region,
const float mval[2],
float out[3],
@@ -702,16 +615,6 @@ void ED_view3d_win_to_delta(const ARegion *region,
out[2] = (rv3d->persinv[0][2] * dx + rv3d->persinv[1][2] * dy);
}
-/**
- * Calculate a 3d origin from 2d window coordinates.
- * \note Orthographic views have a less obvious origin,
- * Since far clip can be a very large value resulting in numeric precision issues,
- * the origin in this case is close to zero coordinate.
- *
- * \param region: The region (used for the window width and height).
- * \param mval: The area relative 2d location (such as event->mval converted to floats).
- * \param out: The resulting normalized world-space direction vector.
- */
void ED_view3d_win_to_origin(const ARegion *region, const float mval[2], float out[3])
{
RegionView3D *rv3d = region->regiondata;
@@ -733,19 +636,6 @@ void ED_view3d_win_to_origin(const ARegion *region, const float mval[2], float o
}
}
-/**
- * Calculate a 3d direction vector from 2d window coordinates.
- * This direction vector starts and the view in the direction of the 2d window coordinates.
- * In orthographic view all window coordinates yield the same vector.
- *
- * \note doesn't rely on ED_view3d_calc_zfac
- * for perspective view, get the vector direction to
- * the mouse cursor as a normalized vector.
- *
- * \param region: The region (used for the window width and height).
- * \param mval: The area relative 2d location (such as event->mval converted to floats).
- * \param out: The resulting normalized world-space direction vector.
- */
void ED_view3d_win_to_vector(const ARegion *region, const float mval[2], float out[3])
{
RegionView3D *rv3d = region->regiondata;
@@ -763,20 +653,6 @@ void ED_view3d_win_to_vector(const ARegion *region, const float mval[2], float o
normalize_v3(out);
}
-/**
- * Calculate a 3d segment from 2d window coordinates.
- * This ray_start is located at the viewpoint, ray_end is a far point.
- * ray_start and ray_end are clipped by the view near and far limits
- * so points along this line are always in view.
- * In orthographic view all resulting segments will be parallel.
- * \param region: The region (used for the window width and height).
- * \param v3d: The 3d viewport (used for near and far clipping range).
- * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
- * \param r_ray_start: The world-space starting point of the segment.
- * \param r_ray_end: The world-space end point of the segment.
- * \param do_clip_planes: Optionally clip the ray by the view clipping planes.
- * \return success, false if the segment is totally clipped.
- */
bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph,
const ARegion *region,
View3D *v3d,
@@ -817,9 +693,6 @@ void ED_view3d_ob_project_mat_get_from_obmat(const RegionView3D *rv3d,
mul_m4_m4m4(r_pmat, rv3d->winmat, vmat);
}
-/**
- * Convert between region relative coordinates (x,y) and depth component z and
- * a point in world space. */
void ED_view3d_project_v3(const struct ARegion *region, const float world[3], float r_region_co[3])
{
/* Viewport is set up to make coordinates relative to the region, not window. */
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 07f1f8a753c..45899880b41 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -119,9 +119,10 @@ float ED_view3d_select_dist_px(void)
return 75.0f * U.pixelsize;
}
-/* TODO: should return whether there is valid context to continue */
void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc, Depsgraph *depsgraph)
{
+ /* TODO: should return whether there is valid context to continue. */
+
memset(vc, 0, sizeof(ViewContext));
vc->C = C;
vc->region = CTX_wm_region(C);
@@ -1279,40 +1280,6 @@ static bool do_lasso_select_paintface(ViewContext *vc,
return changed;
}
-#if 0
-static void do_lasso_select_node(int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
-{
- SpaceNode *snode = area->spacedata.first;
-
- bNode *node;
- rcti rect;
- int node_cent[2];
- float node_centf[2];
- bool changed = false;
-
- BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
-
- /* store selection in temp test flag */
- for (node = snode->edittree->nodes.first; node; node = node->next) {
- node_centf[0] = BLI_RCT_CENTER_X(&node->totr);
- node_centf[1] = BLI_RCT_CENTER_Y(&node->totr);
-
- ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
- const bool is_select = node->flag & SELECT;
- const bool is_inside = (BLI_rcti_isect_pt_v(&rect, node_cent) &&
- BLI_lasso_is_point_inside(mcoords, mcoords_len, node_cent[0], node_cent[1]));
- const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
- if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(node->flag, sel_op_result, SELECT);
- changed = true;
- }
- }
- if (changed) {
- BIF_undo_push("Lasso select nodes");
- }
-}
-#endif
-
static bool view3d_lasso_select(bContext *C,
ViewContext *vc,
const int mcoords[][2],
@@ -2047,19 +2014,16 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc,
bool enumerate,
bool *r_do_nearest)
{
- static int last_mval[2] = {-100, -100};
bool do_nearest = false;
View3D *v3d = vc->v3d;
/* define if we use solid nearest select or not */
if (use_cycle) {
+ /* Update the coordinates (even if the return value isn't used). */
+ const bool has_motion = WM_cursor_test_motion_and_update(mval);
if (!XRAY_ACTIVE(v3d)) {
- do_nearest = true;
- if (len_manhattan_v2v2_int(mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) {
- do_nearest = false;
- }
+ do_nearest = has_motion;
}
- copy_v2_v2_int(last_mval, mval);
}
else {
if (!XRAY_ACTIVE(v3d)) {
@@ -2232,7 +2196,6 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
return basact;
}
-/* mval comes from event->mval, only use within region handlers */
Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
{
return ed_view3d_give_base_under_cursor_ex(C, mval, NULL);
@@ -4077,7 +4040,9 @@ static bool lattice_circle_select(ViewContext *vc,
return data.is_changed;
}
-/* NOTE: pose-bone case is copied from editbone case... */
+/**
+ * \note logic is shared with the edit-bone case, see #armature_circle_doSelectJoint.
+ */
static bool pchan_circle_doSelectJoint(void *userData,
bPoseChannel *pchan,
const float screen_co[2])
@@ -4174,6 +4139,9 @@ static bool pose_circle_select(ViewContext *vc,
return data.is_changed;
}
+/**
+ * \note logic is shared with the pose-bone case, see #pchan_circle_doSelectJoint.
+ */
static bool armature_circle_doSelectJoint(void *userData,
EditBone *ebone,
const float screen_co[2],
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index 4482e5897ca..53bd181f544 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -58,7 +58,7 @@
#include "view3d_intern.h"
-static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]);
+static bool snap_curs_to_sel_ex(bContext *C, const int pivot_point, float r_cursor[3]);
static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3]);
/* -------------------------------------------------------------------- */
@@ -310,9 +310,11 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
* and be snapped by the selection pivot point (median, active),
* or if every object origin should be snapped to the given location.
*/
-static int snap_selected_to_location(bContext *C,
- const float snap_target_global[3],
- const bool use_offset)
+static bool snap_selected_to_location(bContext *C,
+ const float snap_target_global[3],
+ const bool use_offset,
+ const int pivot_point,
+ const bool use_toolsettings)
{
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
@@ -326,12 +328,11 @@ static int snap_selected_to_location(bContext *C,
int a;
if (use_offset) {
- if ((v3d && scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) &&
- snap_calc_active_center(C, true, center_global)) {
+ if ((pivot_point == V3D_AROUND_ACTIVE) && snap_calc_active_center(C, true, center_global)) {
/* pass */
}
else {
- snap_curs_to_sel_ex(C, center_global);
+ snap_curs_to_sel_ex(C, pivot_point, center_global);
}
sub_v3_v3v3(offset_global, snap_target_global, center_global);
}
@@ -341,7 +342,7 @@ static int snap_selected_to_location(bContext *C,
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
- view_layer, CTX_wm_view3d(C), &objects_len);
+ view_layer, v3d, &objects_len);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
obedit = objects[ob_index];
@@ -435,18 +436,23 @@ static int snap_selected_to_location(bContext *C,
}
/* copy new position */
- if ((pchan->protectflag & OB_LOCK_LOCX) == 0) {
- pchan->loc[0] = cursor_pose[0];
- }
- if ((pchan->protectflag & OB_LOCK_LOCY) == 0) {
- pchan->loc[1] = cursor_pose[1];
+ if (use_toolsettings) {
+ if ((pchan->protectflag & OB_LOCK_LOCX) == 0) {
+ pchan->loc[0] = cursor_pose[0];
+ }
+ if ((pchan->protectflag & OB_LOCK_LOCY) == 0) {
+ pchan->loc[1] = cursor_pose[1];
+ }
+ if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) {
+ pchan->loc[2] = cursor_pose[2];
+ }
+
+ /* auto-keyframing */
+ ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
}
- if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) {
- pchan->loc[2] = cursor_pose[2];
+ else {
+ copy_v3_v3(pchan->loc, cursor_pose);
}
-
- /* auto-keyframing */
- ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
}
}
@@ -484,9 +490,11 @@ static int snap_selected_to_location(bContext *C,
objects_len = BLI_array_len(objects);
}
- const bool use_transform_skip_children = (scene->toolsettings->transform_flag &
+ const bool use_transform_skip_children = use_toolsettings &&
+ (scene->toolsettings->transform_flag &
SCE_XFORM_SKIP_CHILDREN);
- const bool use_transform_data_origin = (scene->toolsettings->transform_flag &
+ const bool use_transform_data_origin = use_toolsettings &&
+ (scene->toolsettings->transform_flag &
SCE_XFORM_DATA_ORIGIN);
struct XFormObjectSkipChild_Container *xcs = NULL;
struct XFormObjectData_Container *xds = NULL;
@@ -538,19 +546,24 @@ static int snap_selected_to_location(bContext *C,
invert_m3_m3(imat, originmat);
mul_m3_v3(imat, cursor_parent);
}
- if ((ob->protectflag & OB_LOCK_LOCX) == 0) {
- ob->loc[0] += cursor_parent[0];
- }
- if ((ob->protectflag & OB_LOCK_LOCY) == 0) {
- ob->loc[1] += cursor_parent[1];
+ if (use_toolsettings) {
+ if ((ob->protectflag & OB_LOCK_LOCX) == 0) {
+ ob->loc[0] += cursor_parent[0];
+ }
+ if ((ob->protectflag & OB_LOCK_LOCY) == 0) {
+ ob->loc[1] += cursor_parent[1];
+ }
+ if ((ob->protectflag & OB_LOCK_LOCZ) == 0) {
+ ob->loc[2] += cursor_parent[2];
+ }
+
+ /* auto-keyframing */
+ ED_autokeyframe_object(C, scene, ob, ks);
}
- if ((ob->protectflag & OB_LOCK_LOCZ) == 0) {
- ob->loc[2] += cursor_parent[2];
+ else {
+ add_v3_v3(ob->loc, cursor_parent);
}
- /* auto-keyframing */
- ED_autokeyframe_object(C, scene, ob, ks);
-
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
}
@@ -570,7 +583,21 @@ static int snap_selected_to_location(bContext *C,
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- return OPERATOR_FINISHED;
+ return true;
+}
+
+bool ED_view3d_snap_selected_to_location(bContext *C,
+ const float snap_target_global[3],
+ const int pivot_point)
+{
+ /* These could be passed as arguments if needed. */
+ /* Always use pivot point. */
+ const bool use_offset = true;
+ /* Disable object protected flags & auto-keyframing,
+ * so this can be used as a low level function. */
+ const bool use_toolsettings = false;
+ return snap_selected_to_location(
+ C, snap_target_global, use_offset, pivot_point, use_toolsettings);
}
/** \} */
@@ -586,8 +613,12 @@ static int snap_selected_to_cursor_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
const float *snap_target_global = scene->cursor.location;
+ const int pivot_point = scene->toolsettings->transform_pivot_point;
- return snap_selected_to_location(C, snap_target_global, use_offset);
+ if (snap_selected_to_location(C, snap_target_global, use_offset, pivot_point, true)) {
+ return OPERATOR_CANCELLED;
+ }
+ return OPERATOR_FINISHED;
}
void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
@@ -628,7 +659,10 @@ static int snap_selected_to_active_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- return snap_selected_to_location(C, snap_target_global, false);
+ if (!snap_selected_to_location(C, snap_target_global, false, -1, true)) {
+ return OPERATOR_CANCELLED;
+ }
+ return OPERATOR_FINISHED;
}
void VIEW3D_OT_snap_selected_to_active(wmOperatorType *ot)
@@ -752,7 +786,7 @@ static void bundle_midpoint(Scene *scene, Object *ob, float r_vec[3])
}
/** Snaps the 3D cursor location to the median point of the selection. */
-static bool snap_curs_to_sel_ex(bContext *C, float cursor[3])
+static bool snap_curs_to_sel_ex(bContext *C, const int pivot_point, float r_cursor[3])
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
@@ -849,12 +883,12 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3])
return false;
}
- if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_BOUNDS) {
- mid_v3_v3v3(cursor, min, max);
+ if (pivot_point == V3D_AROUND_CENTER_BOUNDS) {
+ mid_v3_v3v3(r_cursor, min, max);
}
else {
mul_v3_fl(centroid, 1.0f / (float)count);
- copy_v3_v3(cursor, centroid);
+ copy_v3_v3(r_cursor, centroid);
}
return true;
}
@@ -862,7 +896,8 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3])
static int snap_curs_to_sel_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- if (snap_curs_to_sel_ex(C, scene->cursor.location)) {
+ const int pivot_point = scene->toolsettings->transform_pivot_point;
+ if (snap_curs_to_sel_ex(C, pivot_point, scene->cursor.location)) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
@@ -978,10 +1013,6 @@ void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
/** \name Min/Max Object Vertices Utility
* \{ */
-/**
- * Calculates the bounding box corners (min and max) for \a obedit.
- * The returned values are in global space.
- */
bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3])
{
TransVertStore tvs = {NULL};
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index e09453b9957..8b75ce63cde 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -122,9 +122,6 @@ void ED_view3d_dist_range_get(const View3D *v3d, float r_dist_range[2])
r_dist_range[1] = v3d->clip_end * 10.0f;
}
-/**
- * \note copies logic of #ED_view3d_viewplane_get(), keep in sync.
- */
bool ED_view3d_clip_range_get(Depsgraph *depsgraph,
const View3D *v3d,
const RegionView3D *rv3d,
@@ -191,10 +188,6 @@ bool ED_view3d_viewplane_get(Depsgraph *depsgraph,
/** \name View State/Context Utilities
* \{ */
-/**
- * Use this call when executing an operator,
- * event system doesn't set for each event the OpenGL drawing context.
- */
void view3d_operator_needs_opengl(const bContext *C)
{
wmWindow *win = CTX_wm_window(C);
@@ -218,9 +211,6 @@ void view3d_region_operator_needs_opengl(wmWindow *UNUSED(win), ARegion *region)
}
}
-/**
- * Use instead of: `GPU_polygon_offset(rv3d->dist, ...)` see bug T37727.
- */
void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
{
if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) {
@@ -339,18 +329,6 @@ static void points_in_planes_minmax_fn(
minmax_v3v3_v3(user_data->min, user_data->max, co);
}
-/**
- * Clamp min/max by the viewport clipping.
- *
- * \note This is an approximation, with the limitation that the bounding box from the (mix, max)
- * calculation might not have any geometry inside the clipped region.
- * Performing a clipping test on each vertex would work well enough for most cases,
- * although it's not perfect either as edges/faces may intersect the clipping without having any
- * of their vertices inside it.
- * A more accurate result would be quite involved.
- *
- * \return True when the arguments were clamped.
- */
bool ED_view3d_clipping_clamp_minmax(const RegionView3D *rv3d, float min[3], float max[3])
{
/* 6 planes for the cube, 4..6 for the current view clipping planes. */
@@ -481,9 +459,6 @@ bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d)
return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_center_cursor || v3d->ob_center);
}
-/**
- * Use to store the last view, before entering camera view.
- */
void ED_view3d_lastview_store(RegionView3D *rv3d)
{
copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
@@ -503,13 +478,6 @@ void ED_view3d_lock_clear(View3D *v3d)
v3d->flag2 &= ~V3D_LOCK_CAMERA;
}
-/**
- * For viewport operators that exit camera perspective.
- *
- * \note This differs from simply setting `rv3d->persp = persp` because it
- * sets the `ofs` and `dist` values of the viewport so it matches the camera,
- * otherwise switching out of camera view may jump to a different part of the scene.
- */
void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph,
View3D *v3d,
RegionView3D *rv3d,
@@ -528,12 +496,6 @@ void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph,
rv3d->persp = persp;
}
}
-/**
- * Action to take when rotating the view,
- * handle auto-perspective and logic for switching out of views.
- *
- * shared with NDOF.
- */
bool ED_view3d_persp_ensure(const Depsgraph *depsgraph, View3D *v3d, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -569,19 +531,12 @@ bool ED_view3d_persp_ensure(const Depsgraph *depsgraph, View3D *v3d, ARegion *re
* Lock the camera to the 3D Viewport, allowing view manipulation to transform the camera.
* \{ */
-/**
- * \return true when the 3D Viewport is locked to its camera.
- */
bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
{
return ((v3d->camera) && (!ID_IS_LINKED(v3d->camera)) && (v3d->flag2 & V3D_LOCK_CAMERA) &&
(rv3d->persp == RV3D_CAMOB));
}
-/**
- * Apply the camera object transformation to the 3D Viewport.
- * (needed so we can use regular 3D Viewport manipulation operators, that sync back to the camera).
- */
void ED_view3d_camera_lock_init_ex(const Depsgraph *depsgraph,
View3D *v3d,
RegionView3D *rv3d,
@@ -603,11 +558,6 @@ void ED_view3d_camera_lock_init(const Depsgraph *depsgraph, View3D *v3d, RegionV
ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, true);
}
-/**
- * Apply the 3D Viewport transformation back to the camera object.
- *
- * \return true if the camera is moved.
- */
bool ED_view3d_camera_lock_sync(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
{
if (ED_view3d_camera_lock_check(v3d, rv3d)) {
@@ -701,12 +651,6 @@ bool ED_view3d_camera_autokey(const Scene *scene,
return false;
}
-/**
- * Call after modifying a locked view.
- *
- * \note Not every view edit currently auto-keys (num-pad for eg),
- * this is complicated because of smooth-view.
- */
bool ED_view3d_camera_lock_autokey(View3D *v3d,
RegionView3D *rv3d,
struct bContext *C,
@@ -885,7 +829,6 @@ static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_
}
}
-/* sync center/zoom view of region to others, for view transforms */
void view3d_boxview_sync(ScrArea *area, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -910,7 +853,6 @@ void view3d_boxview_sync(ScrArea *area, ARegion *region)
}
}
-/* for home, center etc */
void view3d_boxview_copy(ScrArea *area, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -935,7 +877,6 @@ void view3d_boxview_copy(ScrArea *area, ARegion *region)
}
}
-/* 'clip' is used to know if our clip setting has changed */
void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip)
{
ARegion *region_sync = NULL;
@@ -1023,14 +964,6 @@ static float view_autodist_depth_margin(ARegion *region, const int mval[2], int
return depth_close;
}
-/**
- * Get the world-space 3d location from a screen-space 2d point.
- * TODO: Implement #alphaoverride. We don't want to zoom into billboards.
- *
- * \param mval: Input screen-space pixel location.
- * \param mouse_worldloc: Output world-space location.
- * \param fallback_depth_pt: Use this points depth when no depth can be found.
- */
bool ED_view3d_autodist(Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
@@ -1069,7 +1002,6 @@ bool ED_view3d_autodist(Depsgraph *depsgraph,
return false;
}
-/* no 4x4 sampling, run #ED_view3d_depth_override first */
bool ED_view3d_autodist_simple(ARegion *region,
const int mval[2],
float mouse_worldloc[3],
@@ -1094,17 +1026,10 @@ bool ED_view3d_autodist_simple(ARegion *region,
return ED_view3d_unproject_v3(region, centx, centy, depth, mouse_worldloc);
}
-bool ED_view3d_autodist_depth(ARegion *region, const int mval[2], int margin, float *depth)
-{
- *depth = view_autodist_depth_margin(region, mval, margin);
-
- return (*depth != FLT_MAX);
-}
-
static bool depth_segment_cb(int x, int y, void *userData)
{
struct {
- ARegion *region;
+ const ViewDepths *vd;
int margin;
float depth;
} *data = userData;
@@ -1114,29 +1039,27 @@ static bool depth_segment_cb(int x, int y, void *userData)
mval[0] = x;
mval[1] = y;
- depth = view_autodist_depth_margin(data->region, mval, data->margin);
-
- if (depth != FLT_MAX) {
+ if (ED_view3d_depth_read_cached(data->vd, mval, data->margin, &depth)) {
data->depth = depth;
return false;
}
return true;
}
-bool ED_view3d_autodist_depth_seg(
- ARegion *region, const int mval_sta[2], const int mval_end[2], int margin, float *depth)
+bool ED_view3d_depth_read_cached_seg(
+ const ViewDepths *vd, const int mval_sta[2], const int mval_end[2], int margin, float *depth)
{
struct {
- ARegion *region;
+ const ViewDepths *vd;
int margin;
float depth;
} data = {NULL};
int p1[2];
int p2[2];
- data.region = region;
+ data.vd = vd;
data.margin = margin;
- data.depth = FLT_MAX;
+ data.depth = 1.0f;
copy_v2_v2_int(p1, mval_sta);
copy_v2_v2_int(p2, mval_end);
@@ -1145,7 +1068,7 @@ bool ED_view3d_autodist_depth_seg(
*depth = data.depth;
- return (*depth != FLT_MAX);
+ return (*depth != 1.0f);
}
/** \} */
@@ -1166,31 +1089,6 @@ float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
return radius / (DEFAULT_SENSOR_WIDTH / lens);
}
-/**
- * Return a new RegionView3D.dist value to fit the \a radius.
- *
- * \note Depth isn't taken into account, this will fit a flat plane exactly,
- * but points towards the view (with a perspective projection),
- * may be within the radius but outside the view. eg:
- *
- * <pre>
- * +
- * pt --> + /^ radius
- * / |
- * / |
- * view + +
- * \ |
- * \ |
- * \|
- * +
- * </pre>
- *
- * \param region: Can be NULL if \a use_aspect is false.
- * \param persp: Allow the caller to tell what kind of perspective to use (ortho/view/camera)
- * \param use_aspect: Increase the distance to account for non 1:1 view aspect.
- * \param radius: The radius will be fitted exactly,
- * typically pre-scaled by a margin (#VIEW3D_MARGIN).
- */
float ED_view3d_radius_to_dist(const View3D *v3d,
const ARegion *region,
const struct Depsgraph *depsgraph,
@@ -1271,18 +1169,6 @@ float ED_view3d_radius_to_dist(const View3D *v3d,
/** \name View Distance Utilities
* \{ */
-/**
- * This function solves the problem of having to switch between camera and non-camera views.
- *
- * When viewing from the perspective of \a mat, and having the view center \a ofs,
- * this calculates a distance from \a ofs to the matrix \a mat.
- * Using \a fallback_dist when the distance would be too small.
- *
- * \param mat: A matrix use for the view-point (typically the camera objects matrix).
- * \param ofs: Orbit center (negated), matching #RegionView3D.ofs, which is typically passed in.
- * \param fallback_dist: The distance to use if the object is too near or in front of \a ofs.
- * \returns A newly calculated distance or the fallback.
- */
float ED_view3d_offset_distance(const float mat[4][4],
const float ofs[3],
const float fallback_dist)
@@ -1304,11 +1190,6 @@ float ED_view3d_offset_distance(const float mat[4][4],
return dist;
}
-/**
- * Set the dist without moving the view (compensate with #RegionView3D.ofs)
- *
- * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first.
- */
void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
{
float viewinv[4];
@@ -1329,13 +1210,6 @@ void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
rv3d->dist = dist;
}
-/**
- * Change the distance & offset to match the depth of \a dist_co along the view axis.
- *
- * \param dist_co: A world-space location to use for the new depth.
- * \param dist_min: Resulting distances below this will be ignored.
- * \return Success if the distance was set.
- */
bool ED_view3d_distance_set_from_location(RegionView3D *rv3d,
const float dist_co[3],
const float dist_min)
@@ -1494,14 +1368,6 @@ bool ED_view3d_lock(RegionView3D *rv3d)
/** \name View Transform Utilities
* \{ */
-/**
- * Set the view transformation from a 4x4 matrix.
- *
- * \param mat: The view 4x4 transformation matrix to assign.
- * \param ofs: The view offset, normally from RegionView3D.ofs.
- * \param quat: The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist: The view distance from ofs, normally from RegionView3D.dist.
- */
void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const float *dist)
{
float nmat[3][3];
@@ -1528,14 +1394,6 @@ void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const
}
}
-/**
- * Calculate the view transformation matrix from RegionView3D input.
- * The resulting matrix is equivalent to RegionView3D.viewinv
- * \param mat: The view 4x4 transformation matrix to calculate.
- * \param ofs: The view offset, normally from RegionView3D.ofs.
- * \param quat: The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist: The view distance from ofs, normally from RegionView3D.dist.
- */
void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist)
{
const float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]};
@@ -1546,14 +1404,6 @@ void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], c
sub_v3_v3v3(mat[3], dvec, ofs);
}
-/**
- * Set the RegionView3D members from an objects transformation and optionally lens.
- * \param ob: The object to set the view to.
- * \param ofs: The view offset to be set, normally from RegionView3D.ofs.
- * \param quat: The view rotation to be set, quaternion normally from RegionView3D.viewquat.
- * \param dist: The view distance from ofs to be set, normally from RegionView3D.dist.
- * \param lens: The view lens angle set for cameras and lights, normally from View3D.lens.
- */
void ED_view3d_from_object(const Object *ob, float ofs[3], float quat[4], float *dist, float *lens)
{
ED_view3d_from_m4(ob->obmat, ofs, quat, dist);
@@ -1567,15 +1417,6 @@ void ED_view3d_from_object(const Object *ob, float ofs[3], float quat[4], float
}
}
-/**
- * Set the object transformation from RegionView3D members.
- * \param depsgraph: The depsgraph to get the evaluated object parent
- * for the transformation calculation.
- * \param ob: The object which has the transformation assigned.
- * \param ofs: The view offset, normally from RegionView3D.ofs.
- * \param quat: The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist: The view distance from ofs, normally from RegionView3D.dist.
- */
void ED_view3d_to_object(const Depsgraph *depsgraph,
Object *ob,
const float ofs[3],
@@ -1656,6 +1497,9 @@ bool ED_view3d_depth_read_cached(const ViewDepths *vd,
int margin,
float *r_depth)
{
+ BLI_assert(1.0 <= vd->depth_range[1]);
+ *r_depth = 1.0f;
+
if (!vd || !vd->depths) {
return false;
}
@@ -1685,7 +1529,6 @@ bool ED_view3d_depth_read_cached(const ViewDepths *vd,
depth = vd->depths[y * vd->w + x];
}
- BLI_assert(1.0 <= vd->depth_range[1]);
if (depth != 1.0f) {
*r_depth = depth;
return true;
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index f5da7c14a88..165f931394d 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -123,7 +123,6 @@ static void view3d_smooth_view_state_restore(const struct SmoothView3DState *sms
}
/* will start timer if appropriate */
-/* the arguments are the desired situation */
void ED_view3d_smooth_view_ex(
/* avoid passing in the context */
const Depsgraph *depsgraph,
@@ -407,10 +406,6 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w
return OPERATOR_FINISHED;
}
-/**
- * Apply the smooth-view immediately, use when we need to start a new view operation.
- * (so we don't end up half-applying a view operation when pressing keys quickly).
- */
void ED_view3d_smooth_view_force_finish(bContext *C, View3D *v3d, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -696,21 +691,18 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
/** \name Window and View Matrix Calculation
* \{ */
-/**
- * \param rect: optional for picking (can be NULL).
- */
void view3d_winmatrix_set(Depsgraph *depsgraph,
ARegion *region,
const View3D *v3d,
const rcti *rect)
{
RegionView3D *rv3d = region->regiondata;
- rctf viewplane;
+ rctf full_viewplane;
float clipsta, clipend;
bool is_ortho;
is_ortho = ED_view3d_viewplane_get(
- depsgraph, v3d, rv3d, region->winx, region->winy, &viewplane, &clipsta, &clipend, NULL);
+ depsgraph, v3d, rv3d, region->winx, region->winy, &full_viewplane, &clipsta, &clipend, NULL);
rv3d->is_persp = !is_ortho;
#if 0
@@ -718,21 +710,29 @@ void view3d_winmatrix_set(Depsgraph *depsgraph,
__func__,
winx,
winy,
- viewplane.xmin,
- viewplane.ymin,
- viewplane.xmax,
- viewplane.ymax,
+ full_viewplane.xmin,
+ full_viewplane.ymin,
+ full_viewplane.xmax,
+ full_viewplane.ymax,
clipsta,
clipend);
#endif
- if (rect) { /* picking */
- rctf r;
- r.xmin = viewplane.xmin + (BLI_rctf_size_x(&viewplane) * (rect->xmin / (float)region->winx));
- r.ymin = viewplane.ymin + (BLI_rctf_size_y(&viewplane) * (rect->ymin / (float)region->winy));
- r.xmax = viewplane.xmin + (BLI_rctf_size_x(&viewplane) * (rect->xmax / (float)region->winx));
- r.ymax = viewplane.ymin + (BLI_rctf_size_y(&viewplane) * (rect->ymax / (float)region->winy));
- viewplane = r;
+ /* Note the code here was tweaked to avoid an apparent compiler bug in clang 13 (see T91680). */
+ rctf viewplane;
+ if (rect) {
+ /* Smaller viewplane subset for selection picking. */
+ viewplane.xmin = full_viewplane.xmin +
+ (BLI_rctf_size_x(&full_viewplane) * (rect->xmin / (float)region->winx));
+ viewplane.ymin = full_viewplane.ymin +
+ (BLI_rctf_size_y(&full_viewplane) * (rect->ymin / (float)region->winy));
+ viewplane.xmax = full_viewplane.xmin +
+ (BLI_rctf_size_x(&full_viewplane) * (rect->xmax / (float)region->winx));
+ viewplane.ymax = full_viewplane.ymin +
+ (BLI_rctf_size_y(&full_viewplane) * (rect->ymax / (float)region->winy));
+ }
+ else {
+ viewplane = full_viewplane;
}
if (is_ortho) {
@@ -761,18 +761,6 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob)
mat4_normalized_to_quat(rv3d->viewquat, rv3d->viewmat);
}
-/**
- * Sets #RegionView3D.viewmat
- *
- * \param depsgraph: Depsgraph.
- * \param scene: Scene for camera and cursor location.
- * \param v3d: View 3D space data.
- * \param rv3d: 3D region which stores the final matrices.
- * \param rect_scale: Optional 2D scale argument,
- * Use when displaying a sub-region, eg: when #view3d_winmatrix_set takes a 'rect' argument.
- *
- * \note don't set windows active in here, is used by renderwin too.
- */
void view3d_viewmatrix_set(Depsgraph *depsgraph,
const Scene *scene,
const View3D *v3d,
@@ -862,11 +850,6 @@ void view3d_viewmatrix_set(Depsgraph *depsgraph,
/** \name OpenGL Select Utilities
* \{ */
-/**
- * Optionally cache data for multiple calls to #view3d_opengl_select
- *
- * just avoid GPU_select headers outside this file
- */
void view3d_opengl_select_cache_begin(void)
{
GPU_select_cache_begin();
@@ -943,13 +926,6 @@ static bool drw_select_filter_object_mode_lock_for_weight_paint(Object *ob, void
return ob_pose_list && (BLI_linklist_index(ob_pose_list, DEG_get_original_object(ob)) != -1);
}
-/**
- * \warning be sure to account for a negative return value
- * This is an error, "Too many objects in select buffer"
- * and no action should be taken (can crash blender) if this happens
- *
- * \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
- */
int view3d_opengl_select_ex(ViewContext *vc,
uint *buffer,
uint bufsize,
@@ -1621,11 +1597,6 @@ static void view3d_local_collections_reset(Main *bmain, const uint local_view_bi
}
}
-/**
- * See if current uuid is valid, otherwise set a valid uuid to v3d,
- * Try to keep the same uuid previously used to allow users to
- * quickly toggle back and forth.
- */
bool ED_view3d_local_collections_set(Main *bmain, struct View3D *v3d)
{
if ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0) {
@@ -1730,7 +1701,12 @@ void ED_view3d_xr_shading_update(wmWindowManager *wm, const View3D *v3d, const S
if (v3d->runtime.flag & V3D_RUNTIME_XR_SESSION_ROOT) {
View3DShading *xr_shading = &wm->xr.session_settings.shading;
/* Flags that shouldn't be overridden by the 3D View shading. */
- const int flag_copy = V3D_SHADING_WORLD_ORIENTATION;
+ int flag_copy = 0;
+ if (v3d->shading.type != OB_SOLID) {
+ /* Don't set V3D_SHADING_WORLD_ORIENTATION for solid shading since it results in distorted
+ * lighting when the view matrix has a scale factor. */
+ flag_copy |= V3D_SHADING_WORLD_ORIENTATION;
+ }
BLI_assert(WM_xr_session_exists(&wm->xr));
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 6ed2c28a7eb..386fd85213e 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -48,6 +48,8 @@
#include "ED_screen.h"
#include "ED_space_api.h"
+#include "SEQ_transform.h"
+
#include "WM_api.h"
#include "WM_message.h"
#include "WM_types.h"
@@ -128,6 +130,11 @@ void setTransformViewAspect(TransInfo *t, float r_aspect[3])
ED_space_image_get_uv_aspect(sima, &r_aspect[0], &r_aspect[1]);
}
}
+ else if (t->spacetype == SPACE_SEQ) {
+ if (t->options & CTX_CURSOR) {
+ SEQ_image_preview_unit_to_px(t->scene, r_aspect, r_aspect);
+ }
+ }
else if (t->spacetype == SPACE_CLIP) {
SpaceClip *sclip = t->area->spacedata.first;
@@ -594,8 +601,15 @@ static bool transform_modal_item_poll(const wmOperator *op, int value)
if ((t->tsnap.mode & ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) == 0) {
return false;
}
- if (!validSnap(t)) {
- return false;
+ if (value == TFM_MODAL_ADD_SNAP) {
+ if (!validSnap(t)) {
+ return false;
+ }
+ }
+ else {
+ if (!t->tsnap.selectedPoint) {
+ return false;
+ }
}
break;
}
@@ -654,7 +668,6 @@ static bool transform_modal_item_poll(const wmOperator *op, int value)
return true;
}
-/* Called in transform_ops.c, on each regeneration of key-maps. */
wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -790,6 +803,25 @@ static bool transform_event_modal_constraint(TransInfo *t, short modal_type)
if (constraint_new == CON_AXIS2) {
return false;
}
+
+ if (t->data_type == TC_SEQ_IMAGE_DATA) {
+ /* Setup the 2d msg string so it writes out the transform space. */
+ msg_2d = msg_3d;
+
+ short orient_index = 1;
+ if (t->orient_curr == O_DEFAULT || ELEM(constraint_curr, -1, constraint_new)) {
+ /* Successive presses on existing axis, cycle orientation modes. */
+ orient_index = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient));
+ }
+
+ transform_orientations_current_set(t, orient_index);
+ if (orient_index != 0) {
+ /* Make sure that we don't stop the constraint unless we are looped back around to
+ * "no constraint". */
+ constraint_curr = -1;
+ }
+ }
+
if (constraint_curr == constraint_new) {
stopConstraint(t);
}
@@ -999,7 +1031,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_PROPSIZE:
/* MOUSEPAN usage... */
if (t->flag & T_PROP_EDIT) {
- float fac = 1.0f + 0.005f * (event->y - event->prevy);
+ float fac = 1.0f + 0.005f * (event->xy[1] - event->prev_xy[1]);
t->prop_size *= fac;
if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->clip_end),
@@ -1071,8 +1103,8 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_AUTOCONSTRAINT:
case TFM_MODAL_AUTOCONSTRAINTPLANE:
- if ((t->flag & T_RELEASE_CONFIRM) && (event->prevval == KM_RELEASE) &&
- event->prevtype == t->launch_event) {
+ if ((t->flag & T_RELEASE_CONFIRM) && (event->prev_val == KM_RELEASE) &&
+ event->prev_type == t->launch_event) {
/* Confirm transform if launch key is released after mouse move. */
t->state = TRANS_CONFIRM;
}
@@ -1111,13 +1143,13 @@ int transformEvent(TransInfo *t, const wmEvent *event)
}
break;
case TFM_MODAL_PRECISION:
- if (event->prevval == KM_PRESS) {
+ if (event->prev_val == KM_PRESS) {
t->modifiers |= MOD_PRECISION;
/* Shift is modifier for higher precision transform. */
t->mouse.precision = 1;
t->redraw |= TREDRAW_HARD;
}
- else if (event->prevval == KM_RELEASE) {
+ else if (event->prev_val == KM_RELEASE) {
t->modifiers &= ~MOD_PRECISION;
t->mouse.precision = 0;
t->redraw |= TREDRAW_HARD;
@@ -1416,9 +1448,6 @@ static void drawTransformPixel(const struct bContext *C, ARegion *region, void *
}
}
-/**
- * \see #initTransform which reads values from the operator.
- */
void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
{
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1637,11 +1666,6 @@ static void initSnapSpatial(TransInfo *t, float r_snap[2])
}
}
-/**
- * \note caller needs to free 't' on a 0 return
- * \warning \a event might be NULL (when tweaking from redo panel)
- * \see #saveTransform which writes these values back.
- */
bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode)
{
int options = 0;
@@ -1954,7 +1978,6 @@ int transformEnd(bContext *C, TransInfo *t)
return exit_code;
}
-/* TODO: move to: `transform_query.c`. */
bool checkUseAxisMatrix(TransInfo *t)
{
/* currently only checks for editmode */
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 7f4e533ccd7..642de550812 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -222,6 +222,7 @@ typedef enum {
TC_POSE,
TC_ARMATURE_VERTS,
TC_CURSOR_IMAGE,
+ TC_CURSOR_SEQUENCER,
TC_CURSOR_VIEW3D,
TC_CURVE_VERTS,
TC_GRAPH_EDIT_DATA,
@@ -297,6 +298,10 @@ enum {
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Transform Types
+ * \{ */
+
typedef struct TransSnapPoint {
struct TransSnapPoint *next, *prev;
float co[3];
@@ -316,9 +321,9 @@ typedef struct TransSnap {
/* Snapped Element Type (currently for objects only). */
char snapElem;
/** snapping from this point (in global-space). */
- float snapPoint[3];
- /** to this point (in global-space). */
float snapTarget[3];
+ /** to this point (in global-space). */
+ float snapPoint[3];
float snapTargetGrid[3];
float snapNormal[3];
char snapNodeBorder;
@@ -365,18 +370,18 @@ typedef struct TransCon {
* The last three parameters are pointers to the in/out/printable vectors. */
void (*applyVec)(const struct TransInfo *t,
const struct TransDataContainer *tc,
- struct TransData *td,
+ const struct TransData *td,
const float in[3],
float r_out[3]);
/** Apply function pointer for size transformation. */
void (*applySize)(const struct TransInfo *t,
const struct TransDataContainer *tc,
- struct TransData *td,
+ const struct TransData *td,
float r_smat[3][3]);
/** Apply function pointer for rotation transformation */
void (*applyRot)(const struct TransInfo *t,
const struct TransDataContainer *tc,
- struct TransData *td,
+ const struct TransData *td,
float r_axis[3],
float *r_angle);
} TransCon;
@@ -607,7 +612,7 @@ typedef struct TransInfo {
* mouse button then.) */
bool is_launch_event_tweak;
- bool is_orient_set;
+ bool is_orient_default_overwrite;
struct {
short type;
@@ -620,6 +625,12 @@ typedef struct TransInfo {
O_SET,
} orient_curr;
+ /**
+ * All values from `TransInfo.orient[].type` converted into a flag
+ * to allow quickly checking which orientation types are used.
+ */
+ int orient_type_mask;
+
short prop_mode;
/** Value taken as input, either through mouse coordinates or entered as a parameter. */
@@ -680,11 +691,19 @@ typedef struct TransInfo {
/** \name Public Transform API
* \{ */
+/**
+ * \note caller needs to free `t` on a 0 return
+ * \warning \a event might be NULL (when tweaking from redo panel)
+ * \see #saveTransform which writes these values back.
+ */
bool initTransform(struct bContext *C,
struct TransInfo *t,
struct wmOperator *op,
const struct wmEvent *event,
int mode);
+/**
+ * \see #initTransform which reads values from the operator.
+ */
void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op);
int transformEvent(TransInfo *t, const struct wmEvent *event);
void transformApply(struct bContext *C, TransInfo *t);
@@ -693,14 +712,17 @@ int transformEnd(struct bContext *C, TransInfo *t);
void setTransformViewMatrices(TransInfo *t);
void setTransformViewAspect(TransInfo *t, float r_aspect[3]);
void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy);
-void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag);
+void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], eV3DProjTest flag);
void projectIntView(TransInfo *t, const float vec[3], int adr[2]);
-void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag);
+void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], eV3DProjTest flag);
void projectFloatView(TransInfo *t, const float vec[3], float adr[2]);
void applyAspectRatio(TransInfo *t, float vec[2]);
void removeAspectRatio(TransInfo *t, float vec[2]);
+/**
+ * Called in transform_ops.c, on each regeneration of key-maps.
+ */
struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
/** \} */
@@ -712,7 +734,8 @@ struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
/* transform_gizmo.c */
#define GIZMO_AXIS_LINE_WIDTH 2.0f
-bool gimbal_axis(struct Object *ob, float gmat[3][3]);
+bool gimbal_axis_pose(struct Object *ob, const struct bPoseChannel *pchan, float gmat[3][3]);
+bool gimbal_axis_object(struct Object *ob, float gmat[3][3]);
void drawDial3d(const TransInfo *t);
/** \} */
@@ -747,7 +770,7 @@ typedef enum {
} MouseInputMode;
void initMouseInput(
- TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], const bool precision);
+ TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], bool precision);
void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode);
void applyMouseInput(struct TransInfo *t,
struct MouseInput *mi,
@@ -764,12 +787,28 @@ void setInputPostFct(MouseInput *mi, void (*post)(struct TransInfo *t, float val
/** \name Generics
* \{ */
+/**
+ * Setup internal data, mouse, vectors
+ *
+ * \note \a op and \a event can be NULL
+ *
+ * \see #saveTransform does the reverse.
+ */
void initTransInfo(struct bContext *C,
TransInfo *t,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * Needed for mode switching.
+ */
void freeTransCustomDataForMode(TransInfo *t);
+/**
+ * Here I would suggest only #TransInfo related issues, like free data & reset vars. Not redraws.
+ */
void postTrans(struct bContext *C, TransInfo *t);
+/**
+ * Free data before switching to another mode.
+ */
void resetTransModal(TransInfo *t);
void resetTransRestrictions(TransInfo *t);
@@ -792,17 +831,25 @@ void calculateCenterMedian(TransInfo *t, float r_center[3]);
void calculateCenterCursor(TransInfo *t, float r_center[3]);
void calculateCenterCursor2D(TransInfo *t, float r_center[2]);
void calculateCenterCursorGraph2D(TransInfo *t, float r_center[2]);
+/**
+ * \param select_only: only get active center from data being transformed.
+ */
bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]);
void calculatePropRatio(TransInfo *t);
+/**
+ * Rotate an element, low level code, ignore protected channels.
+ * (use for objects or pose-bones)
+ * Similar to #ElementRotation.
+ */
void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot);
struct Object *transform_object_deform_pose_armature_get(const TransInfo *t, struct Object *ob);
void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
-/* TODO: `transform_query.c`. */
+/* TODO: move to: `transform_query.c`. */
bool checkUseAxisMatrix(TransInfo *t);
#define TRANSFORM_SNAP_MAX_PX 100.0f
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index 7135395ee2d..ede4c3e458c 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -295,10 +295,6 @@ static void constraint_snap_plane_to_edge(const TransInfo *t, const float plane[
}
}
-/**
- * Snap to the nearest point between the snap point and the line that
- * intersects the face plane with the constraint plane.
- */
static void UNUSED_FUNCTION(constraint_snap_plane_to_face(const TransInfo *t,
const float plane[4],
float r_out[3]))
@@ -314,9 +310,6 @@ static void UNUSED_FUNCTION(constraint_snap_plane_to_face(const TransInfo *t,
}
}
-/**
- * Snap to the nearest point on the axis to the edge/line element.
- */
void transform_constraint_snap_axis_to_edge(const TransInfo *t,
const float axis[3],
float r_out[3])
@@ -331,9 +324,6 @@ void transform_constraint_snap_axis_to_edge(const TransInfo *t,
}
}
-/**
- * Snap to the intersection of the axis and the plane defined by the face.
- */
void transform_constraint_snap_axis_to_face(const TransInfo *t,
const float axis[3],
float r_out[3])
@@ -384,6 +374,29 @@ static void planeProjection(const TransInfo *t, const float in[3], float out[3])
add_v3_v3v3(out, in, vec);
}
+static short transform_orientation_or_default(const TransInfo *t)
+{
+ short orientation = t->orient[t->orient_curr].type;
+ if (orientation == V3D_ORIENT_CUSTOM_MATRIX) {
+ /* Use the real value of the "orient_type". */
+ orientation = t->orient[O_DEFAULT].type;
+ }
+ return orientation;
+}
+
+static const float (*transform_object_axismtx_get(const TransInfo *t,
+ const TransDataContainer *UNUSED(tc),
+ const TransData *td))[3]
+{
+ if (transform_orientation_or_default(t) == V3D_ORIENT_GIMBAL) {
+ BLI_assert(t->orient_type_mask & (1 << V3D_ORIENT_GIMBAL));
+ if (t->options & (CTX_POSE_BONE | CTX_OBJECT)) {
+ return td->ext->axismtx_gimbal;
+ }
+ }
+ return td->axismtx;
+}
+
/**
* Generic callback for constant spatial constraints applied to linear motion
*
@@ -393,7 +406,7 @@ static void planeProjection(const TransInfo *t, const float in[3], float out[3])
*/
static void applyAxisConstraintVec(const TransInfo *t,
const TransDataContainer *UNUSED(tc),
- TransData *td,
+ const TransData *td,
const float in[3],
float out[3])
{
@@ -477,7 +490,7 @@ static void applyAxisConstraintVec(const TransInfo *t,
*/
static void applyObjectConstraintVec(const TransInfo *t,
const TransDataContainer *tc,
- TransData *td,
+ const TransData *td,
const float in[3],
float out[3])
{
@@ -489,7 +502,8 @@ static void applyObjectConstraintVec(const TransInfo *t,
copy_v3_v3(out, in);
if (t->con.mode & CON_APPLY) {
mul_m3_v3(t->spacemtx_inv, out);
- mul_m3_v3(td->axismtx, out);
+ const float(*axismtx)[3] = transform_object_axismtx_get(t, tc, td);
+ mul_m3_v3(axismtx, out);
if (t->flag & T_EDIT) {
mul_m3_v3(tc->mat3_unit, out);
}
@@ -502,7 +516,7 @@ static void applyObjectConstraintVec(const TransInfo *t,
*/
static void applyAxisConstraintSize(const TransInfo *t,
const TransDataContainer *UNUSED(tc),
- TransData *td,
+ const TransData *td,
float r_smat[3][3])
{
if (!td && t->con.mode & CON_APPLY) {
@@ -528,14 +542,15 @@ static void applyAxisConstraintSize(const TransInfo *t,
*/
static void applyObjectConstraintSize(const TransInfo *t,
const TransDataContainer *tc,
- TransData *td,
+ const TransData *td,
float r_smat[3][3])
{
if (td && t->con.mode & CON_APPLY) {
float tmat[3][3];
float imat[3][3];
- invert_m3_m3(imat, td->axismtx);
+ const float(*axismtx)[3] = transform_object_axismtx_get(t, tc, td);
+ invert_m3_m3(imat, axismtx);
if (!(t->con.mode & CON_AXIS0)) {
r_smat[0][0] = 1.0f;
@@ -551,7 +566,7 @@ static void applyObjectConstraintSize(const TransInfo *t,
if (t->flag & T_EDIT) {
mul_m3_m3m3(r_smat, tc->mat3_unit, r_smat);
}
- mul_m3_m3m3(r_smat, td->axismtx, tmat);
+ mul_m3_m3m3(r_smat, axismtx, tmat);
}
}
@@ -603,7 +618,7 @@ static void constraints_rotation_impl(const TransInfo *t,
*/
static void applyAxisConstraintRot(const TransInfo *t,
const TransDataContainer *UNUSED(tc),
- TransData *td,
+ const TransData *td,
float r_axis[3],
float *r_angle)
{
@@ -627,7 +642,7 @@ static void applyAxisConstraintRot(const TransInfo *t,
*/
static void applyObjectConstraintRot(const TransInfo *t,
const TransDataContainer *tc,
- TransData *td,
+ const TransData *td,
float r_axis[3],
float *r_angle)
{
@@ -647,7 +662,7 @@ static void applyObjectConstraintRot(const TransInfo *t,
axismtx = tmp_axismtx;
}
else {
- axismtx = td->axismtx;
+ axismtx = transform_object_axismtx_get(t, tc, td);
}
constraints_rotation_impl(t, axismtx, r_axis, r_angle);
@@ -675,7 +690,6 @@ void setConstraint(TransInfo *t, int mode, const char text[])
t->redraw = TREDRAW_HARD;
}
-/* applies individual td->axismtx constraints */
void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[])
{
BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
@@ -703,26 +717,16 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[])
}
}
-/**
- * Set the constraint according to the user defined orientation
- *
- * `ftext` is a format string passed to #BLI_snprintf. It will add the name of
- * the orientation where %s is (logically).
- */
void setUserConstraint(TransInfo *t, int mode, const char ftext[])
{
char text[256];
- short orientation = t->orient[t->orient_curr].type;
- if (orientation == V3D_ORIENT_CUSTOM_MATRIX) {
- /* Use the real value of the "orient_type". */
- orientation = t->orient[0].type;
- }
-
+ const short orientation = transform_orientation_or_default(t);
const char *spacename = transform_orientations_spacename_get(t, orientation);
BLI_snprintf(text, sizeof(text), ftext, spacename);
switch (orientation) {
case V3D_ORIENT_LOCAL:
+ case V3D_ORIENT_GIMBAL:
setLocalConstraint(t, mode, text);
break;
case V3D_ORIENT_NORMAL:
@@ -734,7 +738,6 @@ void setUserConstraint(TransInfo *t, int mode, const char ftext[])
case V3D_ORIENT_GLOBAL:
case V3D_ORIENT_VIEW:
case V3D_ORIENT_CURSOR:
- case V3D_ORIENT_GIMBAL:
case V3D_ORIENT_CUSTOM_MATRIX:
case V3D_ORIENT_CUSTOM:
default: {
@@ -755,7 +758,7 @@ void drawConstraint(TransInfo *t)
{
TransCon *tc = &(t->con);
- if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) {
+ if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE, SPACE_SEQ)) {
return;
}
if (!(tc->mode & CON_APPLY)) {
@@ -822,7 +825,6 @@ void drawConstraint(TransInfo *t)
}
}
-/* called from drawview.c, as an extra per-window draw option */
void drawPropCircle(const struct bContext *C, TransInfo *t)
{
if (t->flag & T_PROP_EDIT) {
@@ -905,7 +907,7 @@ static void drawObjectConstraint(TransInfo *t)
TransData *td = tc->data;
for (int i = 0; i < tc->data_len; i++, td++) {
float co[3];
- float(*axismtx)[3];
+ const float(*axismtx)[3];
if (t->flag & T_PROP_EDIT) {
/* we're sorted, so skip the rest */
@@ -921,19 +923,30 @@ static void drawObjectConstraint(TransInfo *t)
}
}
+ if (t->options & CTX_SEQUENCER_IMAGE) {
+ /* Because we construct an "L" shape to deform the sequence, we should skip
+ * all points except the first vertex. Otherwise we will draw the same axis constraint line
+ * 3 times for each strip.
+ */
+ if (i % 3 != 0) {
+ continue;
+ }
+ }
+
if (t->flag & T_EDIT) {
mul_v3_m4v3(co, tc->mat, td->center);
mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->axismtx);
axismtx = tmp_axismtx;
}
- else if (t->options & CTX_POSE_BONE) {
- mul_v3_m4v3(co, tc->mat, td->center);
- axismtx = td->axismtx;
- }
else {
- copy_v3_v3(co, td->center);
- axismtx = td->axismtx;
+ if (t->options & CTX_POSE_BONE) {
+ mul_v3_m4v3(co, tc->mat, td->center);
+ }
+ else {
+ copy_v3_v3(co, td->center);
+ }
+ axismtx = transform_object_axismtx_get(t, tc, td);
}
if (t->con.mode & CON_AXIS0) {
@@ -1169,13 +1182,6 @@ bool isLockConstraint(const TransInfo *t)
return false;
}
-/**
- * Returns the dimension of the constraint space.
- *
- * For that reason, the flags always needs to be set to properly evaluate here,
- * even if they aren't actually used in the callback function.
- * (Which could happen for weird constraints not yet designed. Along a path for example.)
- */
int getConstraintSpaceDimension(const TransInfo *t)
{
int n = 0;
diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h
index 3632b352476..12151f9df07 100644
--- a/source/blender/editors/transform/transform_constraints.h
+++ b/source/blender/editors/transform/transform_constraints.h
@@ -26,17 +26,35 @@
struct TransInfo;
void constraintNumInput(TransInfo *t, float vec[3]);
+/**
+ * Snap to the nearest point on the axis to the edge/line element.
+ */
void transform_constraint_snap_axis_to_edge(const TransInfo *t,
const float axis[3],
float r_out[3]);
+/**
+ * Snap to the intersection of the axis and the plane defined by the face.
+ */
void transform_constraint_snap_axis_to_face(const TransInfo *t,
const float axis[3],
float r_out[3]);
void setConstraint(TransInfo *t, int mode, const char text[]);
+/**
+ * Applies individual `td->axismtx` constraints.
+ */
void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]);
void setLocalConstraint(TransInfo *t, int mode, const char text[]);
+/**
+ * Set the constraint according to the user defined orientation
+ *
+ * `ftext` is a format string passed to #BLI_snprintf. It will add the name of
+ * the orientation where %s is (logically).
+ */
void setUserConstraint(TransInfo *t, int mode, const char text[]);
void drawConstraint(TransInfo *t);
+/**
+ * Called from drawview.c, as an extra per-window draw option.
+ */
void drawPropCircle(const struct bContext *C, TransInfo *t);
void startConstraint(TransInfo *t);
void stopConstraint(TransInfo *t);
@@ -47,4 +65,11 @@ void setNearestAxis(TransInfo *t);
int constraintModeToIndex(const TransInfo *t);
char constraintModeToChar(const TransInfo *t);
bool isLockConstraint(const TransInfo *t);
+/**
+ * Returns the dimension of the constraint space.
+ *
+ * For that reason, the flags always needs to be set to properly evaluate here,
+ * even if they aren't actually used in the callback function.
+ * (Which could happen for weird constraints not yet designed. Along a path for example.)
+ */
int getConstraintSpaceDimension(const TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 557fa79e7ac..4107cc3a71c 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -68,10 +68,6 @@ bool transform_mode_use_local_origins(const TransInfo *t)
return ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL);
}
-/**
- * Transforming around ourselves is no use, fallback to individual origins,
- * useful for curve/armatures.
- */
void transform_around_single_fallback_ex(TransInfo *t, int data_len_all)
{
if (data_len_all != 1) {
@@ -228,7 +224,7 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
* Used to find #TransData from the index returned by #BLI_kdtree_find_nearest. */
TransData **td_table = MEM_mallocN(sizeof(*td_table) * td_table_len, __func__);
- /* Create and fill kd-tree of selected's positions - in global or proj_vec space. */
+ /* Create and fill KD-tree of selected's positions - in global or proj_vec space. */
KDTree_3d *td_tree = BLI_kdtree_3d_new(td_table_len);
int td_table_index = 0;
@@ -369,7 +365,6 @@ static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
return changed;
}
-/* change the chain-length of auto-ik */
void transform_autoik_update(TransInfo *t, short mode)
{
Main *bmain = CTX_data_main(t->context);
@@ -482,7 +477,6 @@ void calc_distanceCurveVerts(TransData *head, TransData *tail, bool cyclic)
BLI_LINKSTACK_FREE(queue);
}
-/* Utility function for getting the handle data from bezier's */
TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt)
{
TransDataCurveHandleFlags *hdata;
@@ -611,9 +605,6 @@ void clipUVData(TransInfo *t)
/** \name Animation Editors (General)
* \{ */
-/**
- * Used for `TFM_TIME_EXTEND`.
- */
char transform_convert_frame_side_dir_get(TransInfo *t, float cframe)
{
char r_dir;
@@ -636,7 +627,6 @@ char transform_convert_frame_side_dir_get(TransInfo *t, float cframe)
return r_dir;
}
-/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
bool FrameOnMouseSide(char side, float frame, float cframe)
{
/* both sides, so it doesn't matter */
@@ -667,14 +657,6 @@ typedef struct tRetainedKeyframe {
size_t del_count; /* number of keyframes of this sort that have been deleted so far */
} tRetainedKeyframe;
-/**
- * Called during special_aftertrans_update to make sure selected keyframes replace
- * any other keyframes which may reside on that frame (that is not selected).
- *
- * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
- * but may want to use a different one at times (if caller does not operate on
- * selection).
- */
void posttrans_fcurve_clean(FCurve *fcu, const int sel_flag, const bool use_handle)
{
/* NOTE: We assume that all keys are sorted */
@@ -798,12 +780,6 @@ void posttrans_fcurve_clean(FCurve *fcu, const int sel_flag, const bool use_hand
/** \name Transform Utilities
* \{ */
-/* Little helper function for ObjectToTransData used to give certain
- * constraints (ChildOf, FollowPath, and others that may be added)
- * inverse corrections for transform, so that they aren't in CrazySpace.
- * These particular constraints benefit from this, but others don't, hence
- * this semi-hack ;-) - Aligorith
- */
bool constraints_list_needinv(TransInfo *t, ListBase *list)
{
bConstraint *con;
@@ -894,14 +870,12 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list)
/** \name Transform (After-Transform Update)
* \{ */
-/* inserting keys, pointcache, redraw events... */
-/**
- * \note Sequencer freeing has its own function now because of a conflict
- * with transform's order of freeing (campbell).
- * Order changed, the sequencer stuff should go back in here
- */
void special_aftertrans_update(bContext *C, TransInfo *t)
{
+ /* NOTE: Sequencer freeing has its own function now because of a conflict
+ * with transform's order of freeing (campbell).
+ * Order changed, the sequencer stuff should go back in here. */
+
/* early out when nothing happened */
if (t->data_len_all == 0 || t->mode == TFM_DUMMY) {
return;
@@ -940,11 +914,15 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
case TC_SEQ_DATA:
special_aftertrans_update__sequencer(C, t);
break;
+ case TC_SEQ_IMAGE_DATA:
+ special_aftertrans_update__sequencer_image(C, t);
+ break;
case TC_TRACKING_DATA:
special_aftertrans_update__movieclip(C, t);
break;
case TC_ARMATURE_VERTS:
case TC_CURSOR_IMAGE:
+ case TC_CURSOR_SEQUENCER:
case TC_CURSOR_VIEW3D:
case TC_CURVE_VERTS:
case TC_GPENCIL:
@@ -955,7 +933,6 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
case TC_OBJECT_TEXSPACE:
case TC_PAINT_CURVE_VERTS:
case TC_PARTICLE_VERTS:
- case TC_SEQ_IMAGE_DATA:
case TC_NONE:
default:
break;
@@ -964,6 +941,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
int special_transform_moving(TransInfo *t)
{
+ if (t->options & CTX_CURSOR) {
+ return G_TRANSFORM_CURSOR;
+ }
if (t->spacetype == SPACE_SEQ) {
return G_TRANSFORM_SEQ;
}
@@ -1037,6 +1017,7 @@ static void init_proportional_edit(TransInfo *t)
case TC_POSE: /* Disable PET, its not usable in pose mode yet T32444. */
case TC_ARMATURE_VERTS:
case TC_CURSOR_IMAGE:
+ case TC_CURSOR_SEQUENCER:
case TC_CURSOR_VIEW3D:
case TC_NLA_DATA:
case TC_OBJECT_TEXSPACE:
@@ -1112,6 +1093,7 @@ static void init_TransDataContainers(TransInfo *t,
case TC_ACTION_DATA:
case TC_GRAPH_EDIT_DATA:
case TC_CURSOR_IMAGE:
+ case TC_CURSOR_SEQUENCER:
case TC_CURSOR_VIEW3D:
case TC_MASKING_DATA:
case TC_NLA_DATA:
@@ -1223,6 +1205,7 @@ static eTFlag flags_from_data_type(eTConvertType data_type)
case TC_MESH_UV:
return T_EDIT | T_POINTS | T_2D_EDIT;
case TC_CURSOR_IMAGE:
+ case TC_CURSOR_SEQUENCER:
return T_2D_EDIT;
case TC_PARTICLE_VERTS:
return T_POINTS;
@@ -1249,6 +1232,9 @@ static eTConvertType convert_type_get(const TransInfo *t, Object **r_obj_armatur
if (t->spacetype == SPACE_IMAGE) {
convert_type = TC_CURSOR_IMAGE;
}
+ else if (t->spacetype == SPACE_SEQ) {
+ convert_type = TC_CURSOR_SEQUENCER;
+ }
else {
convert_type = TC_CURSOR_VIEW3D;
}
@@ -1396,6 +1382,9 @@ void createTransData(bContext *C, TransInfo *t)
case TC_CURSOR_IMAGE:
createTransCursor_image(t);
break;
+ case TC_CURSOR_SEQUENCER:
+ createTransCursor_sequencer(t);
+ break;
case TC_CURSOR_VIEW3D:
createTransCursor_view3d(t);
break;
@@ -1596,7 +1585,6 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc)
}
}
-/* for the realtime animation recording feature, handle overlapping data */
void animrecord_check_state(TransInfo *t, struct Object *ob)
{
Scene *scene = t->scene;
@@ -1695,7 +1683,6 @@ void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const fl
}
}
-/* called for updating while transform acts, once per redraw */
void recalcData(TransInfo *t)
{
switch (t->data_type) {
@@ -1714,8 +1701,11 @@ void recalcData(TransInfo *t)
case TC_CURSOR_IMAGE:
recalcData_cursor_image(t);
break;
+ case TC_CURSOR_SEQUENCER:
+ recalcData_cursor_sequencer(t);
+ break;
case TC_CURSOR_VIEW3D:
- recalcData_cursor(t);
+ recalcData_cursor_view3d(t);
break;
case TC_GRAPH_EDIT_DATA:
recalcData_graphedit(t);
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index 66d84bca2d2..c40f3c28a79 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -36,47 +36,101 @@ struct TransInfo;
struct bContext;
/* transform_convert.c */
+
+/**
+ * Change the chain-length of auto-IK.
+ */
void transform_autoik_update(TransInfo *t, short mode);
int special_transform_moving(TransInfo *t);
+/**
+ * Inserting keys, point-cache, redraw events.
+ */
void special_aftertrans_update(struct bContext *C, TransInfo *t);
void sort_trans_data_dist(TransInfo *t);
void createTransData(struct bContext *C, TransInfo *t);
-bool clipUVTransform(TransInfo *t, float vec[2], const bool resize);
+bool clipUVTransform(TransInfo *t, float vec[2], bool resize);
void clipUVData(TransInfo *t);
-void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const float y_fac);
+void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, float y_fac);
+/**
+ * Called for updating while transform acts, once per redraw.
+ */
void recalcData(TransInfo *t);
/* transform_convert_mesh.c */
+
void transform_convert_mesh_customdatacorrect_init(TransInfo *t);
/* transform_convert_sequencer.c */
+
void transform_convert_sequencer_channel_clamp(TransInfo *t, float r_val[2]);
/********************* intern **********************/
/* transform_convert.c */
+
bool transform_mode_use_local_origins(const TransInfo *t);
+/**
+ * Transforming around ourselves is no use, fallback to individual origins,
+ * useful for curve/armatures.
+ */
void transform_around_single_fallback_ex(TransInfo *t, int data_len_all);
void transform_around_single_fallback(TransInfo *t);
-void posttrans_fcurve_clean(struct FCurve *fcu, const int sel_flag, const bool use_handle);
+/**
+ * Called during special_aftertrans_update to make sure selected keyframes replace
+ * any other keyframes which may reside on that frame (that is not selected).
+ *
+ * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
+ * but may want to use a different one at times (if caller does not operate on
+ * selection).
+ */
+void posttrans_fcurve_clean(struct FCurve *fcu, int sel_flag, bool use_handle);
+/**
+ * Little helper function for ObjectToTransData used to give certain
+ * constraints (ChildOf, FollowPath, and others that may be added)
+ * inverse corrections for transform, so that they aren't in CrazySpace.
+ * These particular constraints benefit from this, but others don't, hence
+ * this semi-hack ;-) - Aligorith
+ */
bool constraints_list_needinv(TransInfo *t, ListBase *list);
void calc_distanceCurveVerts(TransData *head, TransData *tail, bool cyclic);
+/**
+ * Utility function for getting the handle data from bezier's.
+ */
struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt);
+/**
+ * Used for `TFM_TIME_EXTEND`.
+ */
char transform_convert_frame_side_dir_get(TransInfo *t, float cframe);
+/**
+ * This function tests if a point is on the "mouse" side of the cursor/frame-marking.
+ */
bool FrameOnMouseSide(char side, float frame, float cframe);
void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc);
+/**
+ * For the realtime animation recording feature, handle overlapping data.
+ */
void animrecord_check_state(TransInfo *t, struct Object *ob);
/* transform_convert_action.c */
+
void createTransActionData(bContext *C, TransInfo *t);
+/* helper for recalcData() - for Action Editor transforms */
void recalcData_actedit(TransInfo *t);
void special_aftertrans_update__actedit(bContext *C, TransInfo *t);
/* transform_convert_armature.c */
+
+/**
+ * Sets transform flags in the bones.
+ * Returns total number of bones with #BONE_TRANSFORM.
+ */
int transform_convert_pose_transflags_update(Object *ob,
- const int mode,
- const short around,
+ int mode,
+ short around,
bool has_translate_rotate[2]);
+/**
+ * When objects array is NULL, use 't->data_container' as is.
+ */
void createTransPose(TransInfo *t);
void createTransArmatureVerts(TransInfo *t);
void recalcData_edit_armature(TransInfo *t);
@@ -84,22 +138,37 @@ void recalcData_pose(TransInfo *t);
void special_aftertrans_update__pose(bContext *C, TransInfo *t);
/* transform_convert_cursor.c */
+
void createTransCursor_image(TransInfo *t);
+void createTransCursor_sequencer(TransInfo *t);
void createTransCursor_view3d(TransInfo *t);
void recalcData_cursor_image(TransInfo *t);
-void recalcData_cursor(TransInfo *t);
+void recalcData_cursor_sequencer(TransInfo *t);
+void recalcData_cursor_view3d(TransInfo *t);
/* transform_convert_curve.c */
+
void createTransCurveVerts(TransInfo *t);
void recalcData_curve(TransInfo *t);
/* transform_convert_graph.c */
+/**
+ * It is important to note that this doesn't always act on the selection (like it's usually done),
+ * it acts on a subset of it. E.g. the selection code may leave a hint that we just dragged on a
+ * left or right handle (SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT/RIGHT) and then we only transform the
+ * selected left or right handles accordingly.
+ * The points to be transformed are tagged with BEZT_FLAG_TEMP_TAG; some lower level curve
+ * functions may need to be made aware of this. It's ugly that these act based on selection state
+ * anyway.
+ */
void createTransGraphEditData(bContext *C, TransInfo *t);
+/* helper for recalcData() - for Graph Editor transforms */
void recalcData_graphedit(TransInfo *t);
void special_aftertrans_update__graph(bContext *C, TransInfo *t);
/* transform_convert_gpencil.c */
void createTransGPencil(bContext *C, TransInfo *t);
+/* force recalculation of triangles during transformation */
void recalcData_gpencil_strokes(TransInfo *t);
/* transform_convert_lattice.c */
@@ -139,21 +208,30 @@ struct TransMeshDataCrazySpace {
};
void transform_convert_mesh_islands_calc(struct BMEditMesh *em,
- const bool calc_single_islands,
- const bool calc_island_center,
- const bool calc_island_axismtx,
+ bool calc_single_islands,
+ bool calc_island_center,
+ bool calc_island_axismtx,
struct TransIslandData *r_island_data);
void transform_convert_mesh_islanddata_free(struct TransIslandData *island_data);
+/**
+ * \param mtx: Measure distance in this space.
+ * \param dists: Store the closest connected distance to selected vertices.
+ * \param index: Optionally store the original index we're measuring the distance to (can be NULL).
+ */
void transform_convert_mesh_connectivity_distance(struct BMesh *bm,
const float mtx[3][3],
float *dists,
int *index);
void transform_convert_mesh_mirrordata_calc(struct BMEditMesh *em,
- const bool use_select,
- const bool use_topology,
+ bool use_select,
+ bool use_topology,
const bool mirror_axis[3],
struct TransMirrorData *r_mirror_data);
void transform_convert_mesh_mirrordata_free(struct TransMirrorData *mirror_data);
+/**
+ * Detect CrazySpace [tm].
+ * Vertices with space affected by quats are marked with #BM_ELEM_TAG.
+ */
void transform_convert_mesh_crazyspace_detect(TransInfo *t,
struct TransDataContainer *tc,
struct BMEditMesh *em,
@@ -179,10 +257,12 @@ void recalcData_mesh_skin(TransInfo *t);
/* transform_convert_mesh_uv.c */
void createTransUVs(bContext *C, TransInfo *t);
+/* helper for recalcData() - for Image Editor transforms */
void recalcData_uv(TransInfo *t);
/* transform_convert_nla.c */
void createTransNlaData(bContext *C, TransInfo *t);
+/* helper for recalcData() - for NLA Editor transforms */
void recalcData_nla(TransInfo *t);
void special_aftertrans_update__nla(bContext *C, TransInfo *t);
@@ -193,11 +273,13 @@ void special_aftertrans_update__node(bContext *C, TransInfo *t);
/* transform_convert_object.c */
void createTransObject(bContext *C, TransInfo *t);
+/* helper for recalcData() - for object transforms, typically in the 3D view */
void recalcData_objects(TransInfo *t);
void special_aftertrans_update__object(bContext *C, TransInfo *t);
/* transform_convert_object_texspace.c */
void createTransTexspace(TransInfo *t);
+/* helper for recalcData() - for object transforms, typically in the 3D view */
void recalcData_texspace(TransInfo *t);
/* transform_convert_paintcurve.c */
@@ -215,14 +297,17 @@ void special_aftertrans_update__sculpt(bContext *C, TransInfo *t);
/* transform_convert_sequencer.c */
void createTransSeqData(TransInfo *t);
+/* helper for recalcData() - for sequencer transforms */
void recalcData_sequencer(TransInfo *t);
void special_aftertrans_update__sequencer(bContext *C, TransInfo *t);
/* transform_convert_sequencer_image.c */
void createTransSeqImageData(TransInfo *t);
void recalcData_sequencer_image(TransInfo *t);
+void special_aftertrans_update__sequencer_image(bContext *C, TransInfo *t);
/* transform_convert_tracking.c */
void createTransTrackingData(bContext *C, TransInfo *t);
+/* helper for recalcData() - for Movie Clip transforms */
void recalcData_tracking(TransInfo *t);
void special_aftertrans_update__movieclip(bContext *C, TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c
index a6658ae00a3..69b4de48c56 100644
--- a/source/blender/editors/transform/transform_convert_action.c
+++ b/source/blender/editors/transform/transform_convert_action.c
@@ -159,8 +159,11 @@ static void TimeToTransData(
copy_v2_v2(td2d->ih2, td2d->h2);
/* Setup #TransData. */
- td->loc = time; /* Usually #td2d->loc is used here. But this is for when the original location is
- not float[3]. */
+
+ /* Usually #td2d->loc is used here.
+ * But this is for when the original location is not float[3]. */
+ td->loc = time;
+
copy_v3_v3(td->iloc, td->loc);
td->val = time;
td->ival = *(time);
@@ -577,7 +580,6 @@ static void flushTransIntFrameActionData(TransInfo *t)
}
}
-/* helper for recalcData() - for Action Editor transforms */
void recalcData_actedit(TransInfo *t)
{
ViewLayer *view_layer = t->view_layer;
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 8f896512410..5d0a3bd9dd1 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -427,7 +427,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob)
/* Rule: allow multiple Bones
* (but they must be selected, and only one ik-solver per chain should get added) */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->layer & arm->layer) {
+ if (BKE_pose_is_layer_visible(arm, pchan)) {
if (pchan->bone->flag & (BONE_SELECTED | BONE_TRANSFORM_MIRROR)) {
/* Rule: no IK for solitary (unconnected) bones. */
for (bonec = pchan->bone->childbase.first; bonec; bonec = bonec->next) {
@@ -662,6 +662,12 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
mul_m3_m3m3(td->axismtx, omat, pmat);
normalize_m3(td->axismtx);
+ if (t->orient_type_mask & (1 << V3D_ORIENT_GIMBAL)) {
+ if (!gimbal_axis_pose(ob, pchan, td->ext->axismtx_gimbal)) {
+ copy_m3_m3(td->ext->axismtx_gimbal, td->axismtx);
+ }
+ }
+
if (t->mode == TFM_BONE_ENVELOPE_DIST) {
td->loc = NULL;
td->val = &bone->dist;
@@ -710,9 +716,6 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
td->con = pchan->constraints.first;
}
-/**
- * When objects array is NULL, use 't->data_container' as is.
- */
void createTransPose(TransInfo *t)
{
Main *bmain = CTX_data_main(t->context);
@@ -1496,8 +1499,6 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
}
}
-/* Sets transform flags in the bones.
- * Returns total number of bones with `BONE_TRANSFORM`. */
int transform_convert_pose_transflags_update(Object *ob,
const int mode,
const short around,
@@ -1730,7 +1731,7 @@ void special_aftertrans_update__pose(bContext *C, TransInfo *t)
BKE_pose_where_is(t->depsgraph, t->scene, pose_ob);
}
- /* set BONE_TRANSFORM flags for autokey, gizmo draw might have changed them */
+ /* Set BONE_TRANSFORM flags for auto-key, gizmo draw might have changed them. */
if (!canceled && (t->mode != TFM_DUMMY)) {
transform_convert_pose_transflags_update(ob, t->mode, t->around, NULL);
}
diff --git a/source/blender/editors/transform/transform_convert_cursor.c b/source/blender/editors/transform/transform_convert_cursor.c
index 1f3eff31205..4846e8d2d1a 100644
--- a/source/blender/editors/transform/transform_convert_cursor.c
+++ b/source/blender/editors/transform/transform_convert_cursor.c
@@ -19,6 +19,8 @@
/** \file
* \ingroup edtransform
+ *
+ * Instead of transforming the selection, move the 2D/3D cursor.
*/
#include "DNA_space_types.h"
@@ -35,45 +37,104 @@
#include "transform_convert.h"
/* -------------------------------------------------------------------- */
-/** \name Cursor Transform Creation
- *
- * Instead of transforming the selection, move the 2D/3D cursor.
- *
+/** \name Shared 2D Cursor Utilities
* \{ */
-void createTransCursor_image(TransInfo *t)
+static void createTransCursor_2D_impl(TransInfo *t, float cursor_location[2])
{
TransData *td;
- SpaceImage *sima = t->area->spacedata.first;
- float *cursor_location = sima->cursor;
-
+ TransData2D *td2d;
{
BLI_assert(t->data_container_len == 1);
TransDataContainer *tc = t->data_container;
tc->data_len = 1;
td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
- td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransObData2D(Cursor)");
+ td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransCursorExt");
}
td->flag = TD_SELECTED;
- /* UV coords are scaled by aspects (see UVsToTransData). This also applies for the Cursor in the
+ td2d->loc2d = cursor_location;
+
+ /* UV coords are scaled by aspects (see #UVsToTransData). This also applies for the Cursor in the
* UV Editor which also means that for display and when the cursor coords are flushed
* (recalcData_cursor_image), these are converted each time. */
- cursor_location[0] = cursor_location[0] * t->aspect[0];
- cursor_location[1] = cursor_location[1] * t->aspect[1];
+ td2d->loc[0] = cursor_location[0] * t->aspect[0];
+ td2d->loc[1] = cursor_location[1] * t->aspect[1];
+ td2d->loc[2] = 0.0f;
+
+ copy_v3_v3(td->center, td2d->loc);
- copy_v3_v3(td->center, cursor_location);
td->ob = NULL;
unit_m3(td->mtx);
unit_m3(td->axismtx);
pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
- td->loc = cursor_location;
- copy_v3_v3(td->iloc, cursor_location);
+ td->loc = td2d->loc;
+ copy_v3_v3(td->iloc, td2d->loc);
+}
+
+static void recalcData_cursor_2D_impl(TransInfo *t)
+{
+ TransDataContainer *tc = t->data_container;
+ TransData *td = tc->data;
+ TransData2D *td2d = tc->data_2d;
+ float aspect_inv[2];
+
+ aspect_inv[0] = 1.0f / t->aspect[0];
+ aspect_inv[1] = 1.0f / t->aspect[1];
+
+ td2d->loc2d[0] = td->loc[0] * aspect_inv[0];
+ td2d->loc2d[1] = td->loc[1] * aspect_inv[1];
+
+ DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Cursor
+ * \{ */
+
+void createTransCursor_image(TransInfo *t)
+{
+ SpaceImage *sima = t->area->spacedata.first;
+ createTransCursor_2D_impl(t, sima->cursor);
+}
+
+void recalcData_cursor_image(TransInfo *t)
+{
+ recalcData_cursor_2D_impl(t);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sequencer Cursor
+ * \{ */
+
+void createTransCursor_sequencer(TransInfo *t)
+{
+ SpaceSeq *sseq = t->area->spacedata.first;
+ if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
+ return;
+ }
+ createTransCursor_2D_impl(t, sseq->cursor);
+}
+
+void recalcData_cursor_sequencer(TransInfo *t)
+{
+ recalcData_cursor_2D_impl(t);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View 3D Cursor
+ * \{ */
+
void createTransCursor_view3d(TransInfo *t)
{
TransData *td;
@@ -133,28 +194,7 @@ void createTransCursor_view3d(TransInfo *t)
td->ext->rotOrder = cursor->rotation_mode;
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Recalc Cursor
- * \{ */
-
-void recalcData_cursor_image(TransInfo *t)
-{
- TransDataContainer *tc = t->data_container;
- TransData *td = tc->data;
- float aspect_inv[2];
-
- aspect_inv[0] = 1.0f / t->aspect[0];
- aspect_inv[1] = 1.0f / t->aspect[1];
-
- td->loc[0] = td->loc[0] * aspect_inv[0];
- td->loc[1] = td->loc[1] * aspect_inv[1];
-
- DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE);
-}
-
-void recalcData_cursor(TransInfo *t)
+void recalcData_cursor_view3d(TransInfo *t)
{
DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE);
}
diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c
index 255af3feca2..924e51a2b41 100644
--- a/source/blender/editors/transform/transform_convert_curve.c
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -357,26 +357,6 @@ void createTransCurveVerts(TransInfo *t)
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
if (bp->hide == 0) {
if (is_prop_edit || (bp->f1 & SELECT)) {
- float axismtx[3][3];
-
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- if (nu->pntsv == 1) {
- float normal[3], plane[3];
-
- BKE_nurb_bpoint_calc_normal(nu, bp, normal);
- BKE_nurb_bpoint_calc_plane(nu, bp, plane);
-
- if (createSpaceNormalTangent(axismtx, normal, plane)) {
- /* pass */
- }
- else {
- normalize_v3(normal);
- axis_dominant_v3_to_m3(axismtx, normal);
- invert_m3(axismtx);
- }
- }
- }
-
copy_v3_v3(td->iloc, bp->vec);
td->loc = bp->vec;
copy_v3_v3(td->center, td->loc);
@@ -400,9 +380,22 @@ void createTransCurveVerts(TransInfo *t)
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
+
if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
if (nu->pntsv == 1) {
- copy_m3_m3(td->axismtx, axismtx);
+ float normal[3], plane[3];
+
+ BKE_nurb_bpoint_calc_normal(nu, bp, normal);
+ BKE_nurb_bpoint_calc_plane(nu, bp, plane);
+
+ if (createSpaceNormalTangent(td->axismtx, normal, plane)) {
+ /* pass */
+ }
+ else {
+ normalize_v3(normal);
+ axis_dominant_v3_to_m3(td->axismtx, normal);
+ invert_m3(td->axismtx);
+ }
}
}
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
index f7b78b10868..e52dcb17806 100644
--- a/source/blender/editors/transform/transform_convert_gpencil.c
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -496,8 +496,8 @@ static void createTransGPencil_strokes(bContext *C,
if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene;
bGPDframe *gpf = gpl->actframe;
- float diff_mat[4][4];
- float inverse_diff_mat[4][4];
+ float diff_mat[3][3];
+ float inverse_diff_mat[3][3];
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
/* Init multiframe falloff options. */
@@ -509,9 +509,14 @@ static void createTransGPencil_strokes(bContext *C,
}
/* Calculate difference matrix. */
- BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
- /* Undo matrix. */
- invert_m4_m4(inverse_diff_mat, diff_mat);
+ {
+ float diff_mat_tmp[4][4];
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat_tmp);
+ copy_m3_m4(diff_mat, diff_mat_tmp);
+ }
+
+ /* Use safe invert for cases where the input matrix has zero axes. */
+ invert_m3_m3_safe_ortho(inverse_diff_mat, diff_mat);
/* Make a new frame to work on if the layer's frame
* and the current scene frame don't match up.
@@ -651,9 +656,9 @@ static void createTransGPencil_strokes(bContext *C,
}
}
/* apply parent transformations */
- copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
- copy_m3_m4(td->mtx, diff_mat); /* display position */
- copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
+ copy_m3_m3(td->smtx, inverse_diff_mat); /* final position */
+ copy_m3_m3(td->mtx, diff_mat); /* display position */
+ copy_m3_m3(td->axismtx, diff_mat); /* axis orientation */
/* Triangulation must be calculated again,
* so save the stroke for recalc function */
@@ -748,7 +753,6 @@ void createTransGPencil(bContext *C, TransInfo *t)
}
}
-/* force recalculation of triangles during transformation */
void recalcData_gpencil_strokes(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
index d22277f9d91..40c226b8f7c 100644
--- a/source/blender/editors/transform/transform_convert_graph.c
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -218,15 +218,6 @@ static void graph_key_shortest_dist(
}
}
-/**
- * It is important to note that this doesn't always act on the selection (like it's usually done),
- * it acts on a subset of it. E.g. the selection code may leave a hint that we just dragged on a
- * left or right handle (SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT/RIGHT) and then we only transform the
- * selected left or right handles accordingly.
- * The points to be transformed are tagged with BEZT_FLAG_TEMP_TAG; some lower level curve
- * functions may need to be made aware of this. It's ugly that these act based on selection state
- * anyway.
- */
void createTransGraphEditData(bContext *C, TransInfo *t)
{
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
@@ -913,7 +904,6 @@ static void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
}
}
-/* helper for recalcData() - for Graph Editor transforms */
void recalcData_graphedit(TransInfo *t)
{
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c
index 1a25cfd1efb..e26172cd764 100644
--- a/source/blender/editors/transform/transform_convert_mask.c
+++ b/source/blender/editors/transform/transform_convert_mask.c
@@ -472,12 +472,7 @@ void special_aftertrans_update__mask(bContext *C, TransInfo *t)
}
if (t->scene->nodetree) {
- /* tracks can be used for stabilization nodes,
- * flush update for such nodes */
- // if (nodeUpdateID(t->scene->nodetree, &mask->id))
- {
- WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
- }
+ WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
}
/* TODO: don't key all masks. */
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 7377e47da3d..e00522f0f88 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1000,11 +1000,6 @@ static bool bmesh_test_loose_edge(BMEdge *edge)
return true;
}
-/**
- * \param mtx: Measure distance in this space.
- * \param dists: Store the closest connected distance to selected vertices.
- * \param index: Optionally store the original index we're measuring the distance to (can be NULL).
- */
void transform_convert_mesh_connectivity_distance(struct BMesh *bm,
const float mtx[3][3],
float *dists,
@@ -1307,8 +1302,6 @@ void transform_convert_mesh_mirrordata_free(struct TransMirrorData *mirror_data)
/** \name Crazy Space
* \{ */
-/* Detect CrazySpace [tm].
- * Vertices with space affected by quats are marked with #BM_ELEM_TAG */
void transform_convert_mesh_crazyspace_detect(TransInfo *t,
struct TransDataContainer *tc,
struct BMEditMesh *em,
@@ -1472,7 +1465,7 @@ static void VertsToTransData(TransInfo *t,
td->ext = NULL;
td->val = NULL;
td->extra = eve;
- if (t->mode == TFM_BWEIGHT) {
+ if (t->mode == TFM_BWEIGHT || t->mode == TFM_VERT_CREASE) {
td->val = bweight;
td->ival = *bweight;
}
@@ -1613,10 +1606,15 @@ void createTransEditVerts(TransInfo *t)
}
int cd_vert_bweight_offset = -1;
+ int cd_vert_crease_offset = -1;
if (t->mode == TFM_BWEIGHT) {
BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT);
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
+ else if (t->mode == TFM_VERT_CREASE) {
+ BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_CREASE);
+ cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
+ }
TransData *tob = tc->data;
TransDataMirror *td_mirror = tc->data_mirror;
@@ -1652,6 +1650,8 @@ void createTransEditVerts(TransInfo *t)
else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
float *bweight = (cd_vert_bweight_offset != -1) ?
BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
+ (cd_vert_crease_offset != -1) ?
+ BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset) :
NULL;
/* Do not use the island center in case we are using islands
@@ -2099,6 +2099,7 @@ void recalcData_mesh(TransInfo *t)
tc_mesh_partial_update(t, tc, &partial_state);
}
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2164,4 +2165,5 @@ void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
break;
}
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c
index 2db3e259153..2243f66cc7f 100644
--- a/source/blender/editors/transform/transform_convert_mesh_edge.c
+++ b/source/blender/editors/transform/transform_convert_mesh_edge.c
@@ -86,8 +86,8 @@ void createTransEdge(TransInfo *t)
BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_BWEIGHT);
cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
}
- else { /* if (t->mode == TFM_CREASE) { */
- BLI_assert(t->mode == TFM_CREASE);
+ else { /* if (t->mode == TFM_EDGE_CREASE) { */
+ BLI_assert(t->mode == TFM_EDGE_CREASE);
BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_CREASE);
cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
}
diff --git a/source/blender/editors/transform/transform_convert_mesh_skin.c b/source/blender/editors/transform/transform_convert_mesh_skin.c
index 69b44998980..7c742f29c86 100644
--- a/source/blender/editors/transform/transform_convert_mesh_skin.c
+++ b/source/blender/editors/transform/transform_convert_mesh_skin.c
@@ -303,4 +303,5 @@ void recalcData_mesh_skin(TransInfo *t)
BKE_editmesh_looptri_and_normals_calc(em);
}
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c
index 61397b6ef4b..69f29389b31 100644
--- a/source/blender/editors/transform/transform_convert_mesh_uv.c
+++ b/source/blender/editors/transform/transform_convert_mesh_uv.c
@@ -464,7 +464,6 @@ static void flushTransUVs(TransInfo *t)
}
}
-/* helper for recalcData() - for Image Editor transforms */
void recalcData_uv(TransInfo *t)
{
SpaceImage *sima = t->area->spacedata.first;
diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c
index acef8a666e3..d19698a4f61 100644
--- a/source/blender/editors/transform/transform_convert_nla.c
+++ b/source/blender/editors/transform/transform_convert_nla.c
@@ -266,7 +266,6 @@ void createTransNlaData(bContext *C, TransInfo *t)
ANIM_animdata_freelist(&anim_data);
}
-/* helper for recalcData() - for NLA Editor transforms */
void recalcData_nla(TransInfo *t)
{
SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c
index ecc7f01be33..e8cdfaf1f40 100644
--- a/source/blender/editors/transform/transform_convert_node.c
+++ b/source/blender/editors/transform/transform_convert_node.c
@@ -31,6 +31,7 @@
#include "BKE_context.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "ED_node.h"
@@ -173,9 +174,11 @@ void flushTransNodes(TransInfo *t)
}
else {
/* Edge panning functions expect window coordinates, mval is relative to region */
- const float x = t->region->winrct.xmin + t->mval[0];
- const float y = t->region->winrct.ymin + t->mval[1];
- UI_view2d_edge_pan_apply(t->context, customdata, x, y);
+ const int xy[2] = {
+ t->region->winrct.xmin + t->mval[0],
+ t->region->winrct.ymin + t->mval[1],
+ };
+ UI_view2d_edge_pan_apply(t->context, customdata, xy);
}
}
@@ -244,7 +247,7 @@ void special_aftertrans_update__node(bContext *C, TransInfo *t)
nodeRemoveNode(bmain, ntree, node, true);
}
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(C, bmain, ntree);
}
}
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index bcbac009948..52365e4e519 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -181,6 +181,11 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
/* axismtx has the real orientation */
transform_orientations_create_from_axis(td->axismtx, UNPACK3(ob->obmat));
+ if (t->orient_type_mask & (1 << V3D_ORIENT_GIMBAL)) {
+ if (!gimbal_axis_object(ob, td->ext->axismtx_gimbal)) {
+ copy_m3_m3(td->ext->axismtx_gimbal, td->axismtx);
+ }
+ }
td->con = ob->constraints.first;
@@ -388,7 +393,7 @@ static void set_trans_object_base_flags(TransInfo *t)
if (parsel != NULL) {
/* Rotation around local centers are allowed to propagate. */
if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
- (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)) {
+ (ELEM(t->mode, TFM_ROTATION, TFM_TRACKBALL))) {
base->flag_legacy |= BA_TRANSFORM_CHILD;
}
else {
@@ -432,8 +437,7 @@ static int count_proportional_objects(TransInfo *t)
/* Clear all flags we need. It will be used to detect dependencies. */
trans_object_base_deps_flag_prepare(view_layer);
/* Rotations around local centers are allowed to propagate, so we take all objects. */
- if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
- (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))) {
+ if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) && (ELEM(t->mode, TFM_ROTATION, TFM_TRACKBALL)))) {
/* Mark all parents. */
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTED_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)) {
@@ -870,7 +874,6 @@ static bool motionpath_need_update_object(Scene *scene, Object *ob)
/** \name Recalc Data object
* \{ */
-/* helper for recalcData() - for object transforms, typically in the 3D view */
void recalcData_objects(TransInfo *t)
{
bool motionpath_update = false;
@@ -910,7 +913,8 @@ void recalcData_objects(TransInfo *t)
if (motionpath_update) {
/* Update motion paths once for all transformed objects. */
- ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CURRENT_FRAME);
+ ED_objects_recalculate_paths_selected(
+ t->context, t->scene, OBJECT_PATH_CALC_RANGE_CURRENT_FRAME);
}
if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
@@ -958,25 +962,25 @@ void special_aftertrans_update__object(bContext *C, TransInfo *t)
}
BLI_freelistN(&pidlist);
- /* pointcache refresh */
+ /* Point-cache refresh. */
if (BKE_ptcache_object_reset(t->scene, ob, PTCACHE_RESET_OUTDATED)) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
- /* Needed for proper updating of "quick cached" dynamics. */
- /* Creates troubles for moving animated objects without */
- /* autokey though, probably needed is an anim sys override? */
- /* Please remove if some other solution is found. -jahka */
+ /* Needed for proper updating of "quick cached" dynamics.
+ * Creates troubles for moving animated objects without
+ * auto-key though, probably needed is an animation-system override?
+ * NOTE(@jahka): Please remove if some other solution is found. */
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
- /* Set autokey if necessary */
+ /* Set auto-key if necessary. */
if (!canceled) {
autokeyframe_object(C, t->scene, t->view_layer, ob, t->mode);
}
motionpath_update |= motionpath_need_update_object(t->scene, ob);
- /* restore rigid body transform */
+ /* Restore rigid body transform. */
if (ob->rigidbody_object && canceled) {
float ctime = BKE_scene_ctime_get(t->scene);
if (BKE_rigidbody_check_sim_running(t->scene->rigidbody_world, ctime)) {
@@ -994,7 +998,7 @@ void special_aftertrans_update__object(bContext *C, TransInfo *t)
/* Update motion paths once for all transformed objects. */
const eObjectPathCalcRange range = canceled ? OBJECT_PATH_CALC_RANGE_CURRENT_FRAME :
OBJECT_PATH_CALC_RANGE_CHANGED;
- ED_objects_recalculate_paths(C, t->scene, range);
+ ED_objects_recalculate_paths_selected(C, t->scene, range);
}
clear_trans_object_base_flags(t);
diff --git a/source/blender/editors/transform/transform_convert_object_texspace.c b/source/blender/editors/transform/transform_convert_object_texspace.c
index 371a5b48818..3e434da66ec 100644
--- a/source/blender/editors/transform/transform_convert_object_texspace.c
+++ b/source/blender/editors/transform/transform_convert_object_texspace.c
@@ -51,7 +51,7 @@ void createTransTexspace(TransInfo *t)
TransData *td;
Object *ob;
ID *id;
- short *texflag;
+ char *texflag;
ob = OBACT(view_layer);
@@ -102,7 +102,6 @@ void createTransTexspace(TransInfo *t)
/** \name Recalc Data object
* \{ */
-/* helper for recalcData() - for object transforms, typically in the 3D view */
void recalcData_texspace(TransInfo *t)
{
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index a2698b342d0..01eae36e846 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -34,6 +34,7 @@
#include "ED_markers.h"
+#include "SEQ_animation.h"
#include "SEQ_edit.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
@@ -275,7 +276,7 @@ static void seq_transform_cancel(TransInfo *t, SeqCollection *transformed_strips
SEQ_transform_seqbase_shuffle(seqbase, seq, t->scene);
}
- SEQ_time_update_sequence_bounds(t->scene, seq);
+ SEQ_time_update_sequence(t->scene, seqbase, seq);
}
}
@@ -302,7 +303,7 @@ static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strip
return collection;
}
-/* Query strips positioned after left edge of transformed strips boundbox. */
+/* Query strips positioned after left edge of transformed strips bound-box. */
static SeqCollection *query_right_side_strips(ListBase *seqbase, SeqCollection *transformed_strips)
{
int minframe = MAXFRAME;
@@ -327,7 +328,8 @@ static void seq_transform_update_effects(TransInfo *t, SeqCollection *collection
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, collection) {
if ((seq->type & SEQ_TYPE_EFFECT) && (seq->seq1 || seq->seq2 || seq->seq3)) {
- SEQ_time_update_sequence(t->scene, seq);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene));
+ SEQ_time_update_sequence(t->scene, seqbase, seq);
}
}
}
@@ -350,7 +352,7 @@ static ListBase *seqbase_active_get(const TransInfo *t)
return SEQ_active_seqbase_get(ed);
}
-/* Offset all strips positioned after left edge of transformed strips boundbox by amount equal
+/* Offset all strips positioned after left edge of transformed strips bound-box by amount equal
* to overlap of transformed strips. */
static void seq_transform_handle_expand_to_fit(TransInfo *t, SeqCollection *transformed_strips)
{
@@ -457,6 +459,7 @@ static void seq_transform_handle_overwrite_split(const TransInfo *t,
SEQ_edit_strip_split(
bmain, scene, seqbase, split_strip, transformed->enddisp, SEQ_SPLIT_SOFT, NULL);
SEQ_edit_flag_for_removal(scene, seqbase_active_get(t), split_strip);
+ SEQ_edit_remove_flagged_sequences(t->scene, seqbase_active_get(t));
}
/* Trim strips by adjusting handle position.
@@ -487,7 +490,9 @@ static void seq_transform_handle_overwrite_trim(const TransInfo *t,
BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE);
SEQ_transform_set_right_handle_frame(seq, transformed->startdisp);
}
- SEQ_time_update_sequence(t->scene, seq);
+
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene));
+ SEQ_time_update_sequence(t->scene, seqbase, seq);
}
SEQ_collection_free(targets);
}
@@ -495,8 +500,8 @@ static void seq_transform_handle_overwrite_trim(const TransInfo *t,
static void seq_transform_handle_overwrite(const TransInfo *t, SeqCollection *transformed_strips)
{
SeqCollection *targets = query_overwrite_targets(t, transformed_strips);
+ SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
- bool strips_delete = false;
Sequence *target;
Sequence *transformed;
SEQ_ITERATOR_FOREACH (target, targets) {
@@ -508,13 +513,10 @@ static void seq_transform_handle_overwrite(const TransInfo *t, SeqCollection *tr
const eOvelapDescrition overlap = overlap_description_get(transformed, target);
if (overlap == STRIP_OVERLAP_IS_FULL) {
- /* Remove covered strip. */
- SEQ_edit_flag_for_removal(t->scene, seqbase_active_get(t), target);
- strips_delete = true;
+ SEQ_collection_append_strip(target, strips_to_delete);
}
else if (overlap == STRIP_OVERLAP_IS_INSIDE) {
seq_transform_handle_overwrite_split(t, transformed, target);
- strips_delete = true;
}
else if (ELEM(overlap, STRIP_OVERLAP_LEFT_SIDE, STRIP_OVERLAP_RIGHT_SIDE)) {
seq_transform_handle_overwrite_trim(t, transformed, target, overlap);
@@ -524,9 +526,16 @@ static void seq_transform_handle_overwrite(const TransInfo *t, SeqCollection *tr
SEQ_collection_free(targets);
- if (strips_delete) {
+ /* Remove covered strips. This must be done in separate loop, because `SEQ_edit_strip_split()`
+ * also uses `SEQ_edit_remove_flagged_sequences()`. See T91096. */
+ if (SEQ_collection_len(strips_to_delete) > 0) {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips_to_delete) {
+ SEQ_edit_flag_for_removal(t->scene, seqbase_active_get(t), seq);
+ }
SEQ_edit_remove_flagged_sequences(t->scene, seqbase_active_get(t));
}
+ SEQ_collection_free(strips_to_delete);
}
static void seq_transform_handle_overlap_shuffle(const TransInfo *t,
@@ -704,7 +713,9 @@ BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int s
/* Calculate this strip and all nested strips.
* Children are ALWAYS transformed first so we don't need to do this in another loop.
*/
- SEQ_time_update_sequence(sce, seq);
+
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(sce));
+ SEQ_time_update_sequence(sce, seqbase, seq);
if (sel_flag == SELECT) {
SEQ_offset_animdata(sce, seq, seq->start - old_start);
@@ -744,13 +755,13 @@ static void flushTransSeq(TransInfo *t)
SEQ_transform_set_left_handle_frame(seq, new_frame);
SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
SEQ_transform_fix_single_image_seq_offsets(seq);
- SEQ_time_update_sequence(t->scene, seq);
+ SEQ_time_update_sequence(t->scene, seqbasep, seq);
break;
case SEQ_RIGHTSEL: /* No vertical transform. */
SEQ_transform_set_right_handle_frame(seq, new_frame);
SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
SEQ_transform_fix_single_image_seq_offsets(seq);
- SEQ_time_update_sequence(t->scene, seq);
+ SEQ_time_update_sequence(t->scene, seqbasep, seq);
break;
}
}
@@ -759,7 +770,7 @@ static void flushTransSeq(TransInfo *t)
if (ELEM(t->mode, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) {
for (seq = seqbasep->first; seq; seq = seq->next) {
if (seq->seq1 || seq->seq2 || seq->seq3) {
- SEQ_time_update_sequence(t->scene, seq);
+ SEQ_time_update_sequence(t->scene, seqbasep, seq);
}
}
}
@@ -779,7 +790,6 @@ static void flushTransSeq(TransInfo *t)
SEQ_collection_free(transformed_strips);
}
-/* helper for recalcData() - for sequencer transforms */
void recalcData_sequencer(TransInfo *t)
{
TransData *td;
diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c
index 6e3f12de472..3a5770c2863 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -38,8 +38,12 @@
#include "SEQ_transform.h"
#include "SEQ_utils.h"
+#include "ED_keyframing.h"
+
#include "UI_view2d.h"
+#include "RNA_access.h"
+
#include "transform.h"
#include "transform_convert.h"
@@ -64,12 +68,16 @@ static TransData *SeqToTransData(const Scene *scene,
SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, origin);
float vertex[2] = {origin[0], origin[1]};
- /* Add control vertex, so rotation and scale can be calculated. */
+ /* Add control vertex, so rotation and scale can be calculated.
+ * All three vertices will form a "L" shape that is aligned to the local strip axis.
+ */
if (vert_index == 1) {
- vertex[0] += 1.0f;
+ vertex[0] += cosf(transform->rotation);
+ vertex[1] += sinf(transform->rotation);
}
else if (vert_index == 2) {
- vertex[1] += 1.0f;
+ vertex[0] -= sinf(transform->rotation);
+ vertex[1] += cosf(transform->rotation);
}
td2d->loc[0] = vertex[0];
@@ -81,11 +89,12 @@ static TransData *SeqToTransData(const Scene *scene,
td->center[0] = origin[0];
td->center[1] = origin[1];
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
unit_m3(td->mtx);
unit_m3(td->smtx);
+ axis_angle_to_mat3_single(td->axismtx, 'Z', transform->rotation);
+ normalize_m3(td->axismtx);
+
tdseq->seq = seq;
copy_v2_v2(tdseq->orig_origin_position, origin);
tdseq->orig_translation[0] = transform->xofs;
@@ -113,10 +122,18 @@ static void freeSeqData(TransInfo *UNUSED(t),
void createTransSeqImageData(TransInfo *t)
{
Editing *ed = SEQ_editing_get(t->scene);
+ const SpaceSeq *sseq = t->area->spacedata.first;
+ const ARegion *region = t->region;
if (ed == NULL) {
return;
}
+ if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
+ return;
+ }
+ if (region->regiontype == RGN_TYPE_PREVIEW && sseq->view == SEQ_VIEW_SEQUENCE_PREVIEW) {
+ return;
+ }
ListBase *seqbase = SEQ_active_seqbase_get(ed);
SeqCollection *strips = SEQ_query_rendered_strips(seqbase, t->scene->r.cfra, 0);
@@ -159,18 +176,18 @@ void recalcData_sequencer_image(TransInfo *t)
for (i = 0, td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
/* Origin. */
- float loc[2];
- copy_v2_v2(loc, td2d->loc);
+ float origin[2];
+ copy_v2_v2(origin, td2d->loc);
i++, td++, td2d++;
/* X and Y control points used to read scale and rotation. */
float handle_x[2];
copy_v2_v2(handle_x, td2d->loc);
- sub_v2_v2(handle_x, loc);
+ sub_v2_v2(handle_x, origin);
i++, td++, td2d++;
float handle_y[2];
copy_v2_v2(handle_y, td2d->loc);
- sub_v2_v2(handle_y, loc);
+ sub_v2_v2(handle_y, origin);
TransDataSeq *tdseq = td->extra;
Sequence *seq = tdseq->seq;
@@ -181,8 +198,9 @@ void recalcData_sequencer_image(TransInfo *t)
/* Calculate translation. */
float translation[2];
copy_v2_v2(translation, tdseq->orig_origin_position);
- sub_v2_v2(translation, loc);
+ sub_v2_v2(translation, origin);
mul_v2_v2(translation, mirror);
+
transform->xofs = tdseq->orig_translation[0] - translation[0];
transform->yofs = tdseq->orig_translation[1] - translation[1];
@@ -192,7 +210,8 @@ void recalcData_sequencer_image(TransInfo *t)
/* Rotation. Scaling can cause negative rotation. */
if (t->mode == TFM_ROTATION) {
- float rotation = angle_signed_v2v2(handle_x, (float[]){1, 0}) * mirror[0] * mirror[1];
+ const float orig_dir[2] = {cosf(tdseq->orig_rotation), sinf(tdseq->orig_rotation)};
+ float rotation = angle_signed_v2v2(handle_x, orig_dir) * mirror[0] * mirror[1];
transform->rotation = tdseq->orig_rotation + rotation;
transform->rotation += DEG2RAD(360.0);
transform->rotation = fmod(transform->rotation, DEG2RAD(360.0));
@@ -200,3 +219,44 @@ void recalcData_sequencer_image(TransInfo *t)
SEQ_relations_invalidate_cache_preprocessed(t->scene, seq);
}
}
+
+void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *t)
+{
+ if (t->state == TRANS_CANCEL) {
+ return;
+ }
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ int i;
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ for (i = 0, td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
+ TransDataSeq *tdseq = td->extra;
+ Sequence *seq = tdseq->seq;
+ StripTransform *transform = seq->strip->transform;
+ Scene *scene = t->scene;
+
+ RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform, &ptr);
+
+ if (t->mode == TFM_ROTATION) {
+ prop = RNA_struct_find_property(&ptr, "rotation");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ }
+ if (t->mode == TFM_TRANSLATION) {
+ prop = RNA_struct_find_property(&ptr, "offset_x");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ prop = RNA_struct_find_property(&ptr, "offset_y");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ }
+ if (t->mode == TFM_RESIZE) {
+ prop = RNA_struct_find_property(&ptr, "scale_x");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ prop = RNA_struct_find_property(&ptr, "scale_y");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ }
+ }
+}
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index 211dec3c4e8..f2d0fb7ac2f 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -29,8 +29,10 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
#include "ED_clip.h"
@@ -707,7 +709,6 @@ static void flushTransTracking(TransInfo *t)
}
}
-/* helper for recalcData() - for Movie Clip transforms */
void recalcData_tracking(TransInfo *t)
{
SpaceClip *sc = t->area->spacedata.first;
@@ -794,8 +795,12 @@ void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
/* Tracks can be used for stabilization nodes,
* flush update for such nodes.
*/
- nodeUpdateID(t->scene->nodetree, &clip->id);
- WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
+ if (t->context != NULL) {
+ Main *bmain = CTX_data_main(C);
+ BKE_ntree_update_tag_id_changed(bmain, &clip->id);
+ BKE_ntree_update_main(bmain, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
+ }
}
}
diff --git a/source/blender/editors/transform/transform_data.h b/source/blender/editors/transform/transform_data.h
index 15e40ec466b..a78c2491a1a 100644
--- a/source/blender/editors/transform/transform_data.h
+++ b/source/blender/editors/transform/transform_data.h
@@ -27,8 +27,8 @@ struct Object;
struct bConstraint;
#define TRANSDATABASIC \
- /** Extra data (mirrored element pointer, in editmode mesh to BMVert) \
- * (editbone for roll fixing) (...). */ \
+ /** Extra data (mirrored element pointer, in edit-mode mesh to #BMVert) \
+ * (edit-bone for roll fixing) (...). */ \
void *extra; \
/** Location of the data to transform. */ \
float *loc; \
@@ -85,6 +85,8 @@ typedef struct TransDataExtension {
float isize[3];
/** Object matrix. */
float obmat[4][4];
+ /** Use for #V3D_ORIENT_GIMBAL orientation. */
+ float axismtx_gimbal[3][3];
/** Use instead of #TransData.smtx,
* It is the same but without the #Bone.bone_mat, see #TD_PBONE_LOCAL_MTX_C. */
float l_smtx[3][3];
diff --git a/source/blender/editors/transform/transform_draw_cursors.c b/source/blender/editors/transform/transform_draw_cursors.c
index af1f3cb72a4..13127ae06bb 100644
--- a/source/blender/editors/transform/transform_draw_cursors.c
+++ b/source/blender/editors/transform/transform_draw_cursors.c
@@ -88,20 +88,12 @@ static void drawArrow(const uint pos_id, const enum eArrowDirection dir)
immEnd();
}
-/**
- * Poll callback for cursor drawing:
- * #WM_paint_cursor_activate
- */
bool transform_draw_cursor_poll(bContext *C)
{
ARegion *region = CTX_wm_region(C);
return (region && ELEM(region->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_PREVIEW)) ? 1 : 0;
}
-/**
- * Cursor and help-line drawing, callback for:
- * #WM_paint_cursor_activate
- */
void transform_draw_cursor_draw(bContext *UNUSED(C), int x, int y, void *customdata)
{
TransInfo *t = (TransInfo *)customdata;
diff --git a/source/blender/editors/transform/transform_draw_cursors.h b/source/blender/editors/transform/transform_draw_cursors.h
index 0f626c9039b..b520cd1d4f8 100644
--- a/source/blender/editors/transform/transform_draw_cursors.h
+++ b/source/blender/editors/transform/transform_draw_cursors.h
@@ -24,5 +24,14 @@
#pragma once
/* Callbacks for #WM_paint_cursor_activate */
+
+/**
+ * Poll callback for cursor drawing:
+ * #WM_paint_cursor_activate
+ */
bool transform_draw_cursor_poll(struct bContext *C);
+/**
+ * Cursor and help-line drawing, callback for:
+ * #WM_paint_cursor_activate
+ */
void transform_draw_cursor_draw(struct bContext *C, int x, int y, void *customdata);
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index fa323f0c1f7..d1cbab9ff8a 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -46,6 +46,8 @@
#include "BKE_modifier.h"
#include "BKE_paint.h"
+#include "SEQ_transform.h"
+
#include "ED_clip.h"
#include "ED_image.h"
#include "ED_object.h"
@@ -71,47 +73,58 @@
void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis, short options)
{
+ if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_SEQ)) {
+ return;
+ }
+
float v1[3], v2[3], v3[3];
uchar col[3], col2[3];
if (t->spacetype == SPACE_VIEW3D) {
View3D *v3d = t->view;
- GPU_matrix_push();
-
copy_v3_v3(v3, dir);
mul_v3_fl(v3, v3d->clip_end);
sub_v3_v3v3(v2, center, v3);
add_v3_v3v3(v1, center, v3);
+ }
+ else if (t->spacetype == SPACE_SEQ) {
+ View2D *v2d = t->view;
- if (options & DRAWLIGHT) {
- col[0] = col[1] = col[2] = 220;
- }
- else {
- UI_GetThemeColor3ubv(TH_GRID, col);
- }
- UI_make_axis_color(col, col2, axis);
+ copy_v3_v3(v3, dir);
+ float max_dist = max_ff(BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur));
+ mul_v3_fl(v3, max_dist);
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ sub_v3_v3v3(v2, center, v3);
+ add_v3_v3v3(v1, center, v3);
+ }
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- immUniformColor3ubv(col2);
+ GPU_matrix_push();
- immBegin(GPU_PRIM_LINES, 2);
- immVertex3fv(pos, v1);
- immVertex3fv(pos, v2);
- immEnd();
+ if (options & DRAWLIGHT) {
+ col[0] = col[1] = col[2] = 220;
+ }
+ else {
+ UI_GetThemeColor3ubv(TH_GRID, col);
+ }
+ UI_make_axis_color(col, col2, axis);
- immUnbindProgram();
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- GPU_matrix_pop();
- }
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3ubv(col2);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_matrix_pop();
}
-/**
- * Free data before switching to another mode.
- */
void resetTransModal(TransInfo *t)
{
freeTransCustomDataForMode(t);
@@ -122,13 +135,59 @@ void resetTransRestrictions(TransInfo *t)
t->flag &= ~T_ALL_RESTRICTIONS;
}
-/**
- * Setup internal data, mouse, vectors
- *
- * \note \a op and \a event can be NULL
- *
- * \see #saveTransform does the reverse.
- */
+static void *t_view_get(TransInfo *t)
+{
+ if (t->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = t->area->spacedata.first;
+ return (void *)v3d;
+ }
+ if (t->region) {
+ return (void *)&t->region->v2d;
+ }
+ return NULL;
+}
+
+static int t_around_get(TransInfo *t)
+{
+ if (t->flag & T_OVERRIDE_CENTER) {
+ /* Avoid initialization of individual origins (#V3D_AROUND_LOCAL_ORIGINS). */
+ return V3D_AROUND_CENTER_BOUNDS;
+ }
+
+ ScrArea *area = t->area;
+ switch (t->spacetype) {
+ case SPACE_VIEW3D: {
+ if (t->mode == TFM_BEND) {
+ /* Bend always uses the cursor. */
+ return V3D_AROUND_CURSOR;
+ }
+ return t->settings->transform_pivot_point;
+ }
+ case SPACE_IMAGE: {
+ SpaceImage *sima = area->spacedata.first;
+ return sima->around;
+ }
+ case SPACE_GRAPH: {
+ SpaceGraph *sipo = area->spacedata.first;
+ return sipo->around;
+ }
+ case SPACE_CLIP: {
+ SpaceClip *sclip = area->spacedata.first;
+ return sclip->around;
+ }
+ case SPACE_SEQ: {
+ if (t->region->regiontype == RGN_TYPE_PREVIEW) {
+ return SEQ_tool_settings_pivot_point_get(t->scene);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return V3D_AROUND_CENTER_BOUNDS;
+}
+
void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
{
Scene *sce = CTX_data_scene(C);
@@ -155,7 +214,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->flag = 0;
- if (obact && ELEM(object_mode, OB_MODE_EDIT, OB_MODE_EDIT_GPENCIL)) {
+ if (obact && !(t->options & (CTX_CURSOR | CTX_TEXTURE_SPACE)) &&
+ ELEM(object_mode, OB_MODE_EDIT, OB_MODE_EDIT_GPENCIL)) {
t->obedit_type = obact->type;
}
else {
@@ -200,7 +260,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
/* Crease needs edge flag */
- if (ELEM(t->mode, TFM_CREASE, TFM_BWEIGHT)) {
+ if (ELEM(t->mode, TFM_EDGE_CREASE, TFM_BWEIGHT)) {
t->options |= CTX_EDGE_DATA;
}
@@ -245,32 +305,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
if (t->spacetype == SPACE_VIEW3D) {
- View3D *v3d = area->spacedata.first;
bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C));
- t->view = v3d;
t->animtimer = (animscreen) ? animscreen->animtimer : NULL;
if (t->scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) {
t->flag |= T_V3D_ALIGN;
}
- t->around = t->scene->toolsettings->transform_pivot_point;
-
- /* bend always uses the cursor */
- if (t->mode == TFM_BEND) {
- t->around = V3D_AROUND_CURSOR;
- }
-
- /* exceptional case */
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
- const bool use_island = transdata_check_local_islands(t, t->around);
-
- if ((t->obedit_type != -1) && !use_island) {
- t->options |= CTX_NO_PET;
- }
- }
- }
if (object_mode & OB_MODE_ALL_PAINT) {
Paint *p = BKE_paint_get_active_from_context(C);
@@ -297,10 +338,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
else if (t->spacetype == SPACE_IMAGE) {
SpaceImage *sima = area->spacedata.first;
- /* XXX for now, get View2D from the active region. */
- t->view = &region->v2d;
- t->around = sima->around;
-
if (ED_space_image_show_uvedit(sima, OBACT(t->view_layer))) {
/* UV transform */
}
@@ -315,21 +352,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
/* image not in uv edit, nor in mask mode, can happen for some tools */
}
- else if (t->spacetype == SPACE_NODE) {
- /* XXX for now, get View2D from the active region. */
- t->view = &region->v2d;
- t->around = V3D_AROUND_CENTER_BOUNDS;
- }
- else if (t->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = area->spacedata.first;
- t->view = &region->v2d;
- t->around = sipo->around;
- }
else if (t->spacetype == SPACE_CLIP) {
SpaceClip *sclip = area->spacedata.first;
- t->view = &region->v2d;
- t->around = sclip->around;
-
if (ED_space_clip_check_show_trackedit(sclip)) {
t->options |= CTX_MOVIECLIP;
}
@@ -338,20 +362,30 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
else if (t->spacetype == SPACE_SEQ && region->regiontype == RGN_TYPE_PREVIEW) {
- t->view = &region->v2d;
- t->around = SEQ_tool_settings_pivot_point_get(t->scene);
t->options |= CTX_SEQUENCER_IMAGE;
}
- else {
- if (region) {
- /* XXX: For now, get View2D from the active region. */
- t->view = &region->v2d;
- /* XXX: For now, the center point is the midpoint of the data. */
- }
- else {
- t->view = NULL;
+
+ setTransformViewAspect(t, t->aspect);
+
+ if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, t->center_global);
+ mul_v3_v3(t->center_global, t->aspect);
+ t->flag |= T_OVERRIDE_CENTER;
+ }
+
+ t->view = t_view_get(t);
+ t->around = t_around_get(t);
+
+ /* Exceptional case. */
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
+ const bool use_island = transdata_check_local_islands(t, t->around);
+
+ if ((t->obedit_type != -1) && !use_island) {
+ t->options |= CTX_NO_PET;
+ }
}
- t->around = V3D_AROUND_CENTER_BOUNDS;
}
bool t_values_set_is_array = false;
@@ -360,11 +394,11 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
RNA_property_is_set(op->ptr, prop)) {
float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory. */
if (RNA_property_array_check(prop)) {
- RNA_float_get_array(op->ptr, "value", values);
+ RNA_property_float_get_array(op->ptr, prop, values);
t_values_set_is_array = true;
}
else {
- values[0] = RNA_float_get(op->ptr, "value");
+ values[0] = RNA_property_float_get(op->ptr, prop);
}
if (t->flag & T_MODAL) {
@@ -450,25 +484,31 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
+ orient_type_default = orient_type_scene;
+
if (orient_type_set != -1) {
- orient_type_default = orient_type_set;
- t->is_orient_set = true;
+ if (!(t->con.mode & CON_APPLY)) {
+ /* Only overwrite default if not constrained. */
+ orient_type_default = orient_type_set;
+ t->is_orient_default_overwrite = true;
+ }
}
else if (orient_type_matrix_set != -1) {
- orient_type_default = orient_type_set = orient_type_matrix_set;
- t->is_orient_set = true;
+ orient_type_set = orient_type_matrix_set;
+ if (!(t->con.mode & CON_APPLY)) {
+ /* Only overwrite default if not constrained. */
+ orient_type_default = orient_type_set;
+ t->is_orient_default_overwrite = true;
+ }
}
else if (t->con.mode & CON_APPLY) {
- orient_type_default = orient_type_set = orient_type_scene;
+ orient_type_set = orient_type_scene;
+ }
+ else if (orient_type_scene == V3D_ORIENT_GLOBAL) {
+ orient_type_set = V3D_ORIENT_LOCAL;
}
else {
- orient_type_default = orient_type_scene;
- if (orient_type_scene == V3D_ORIENT_GLOBAL) {
- orient_type_set = V3D_ORIENT_LOCAL;
- }
- else {
- orient_type_set = V3D_ORIENT_GLOBAL;
- }
+ orient_type_set = V3D_ORIENT_GLOBAL;
}
BLI_assert(!ELEM(-1, orient_type_default, orient_type_set));
@@ -496,6 +536,15 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
+ t->orient_type_mask = 0;
+ for (int i = 0; i < 3; i++) {
+ const int type = t->orient[i].type;
+ if (type < V3D_ORIENT_CUSTOM_MATRIX) {
+ BLI_assert(type < 32);
+ t->orient_type_mask |= (1 << type);
+ }
+ }
+
transform_orientations_current_set(t, (t->con.mode & CON_APPLY) ? 2 : 0);
}
@@ -631,15 +680,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->flag |= T_NO_CURSOR_WRAP;
}
- setTransformViewAspect(t, t->aspect);
-
- if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) &&
- RNA_property_is_set(op->ptr, prop)) {
- RNA_property_float_get_array(op->ptr, prop, t->center_global);
- mul_v3_v3(t->center_global, t->aspect);
- t->flag |= T_OVERRIDE_CENTER;
- }
-
setTransformViewMatrices(t);
initNumInput(&t->num);
}
@@ -670,9 +710,6 @@ static void freeTransCustomDataContainer(TransInfo *t,
}
}
-/**
- * Needed for mode switching.
- */
void freeTransCustomDataForMode(TransInfo *t)
{
freeTransCustomData(t, NULL, &t->custom.mode);
@@ -681,7 +718,6 @@ void freeTransCustomDataForMode(TransInfo *t)
}
}
-/* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
void postTrans(bContext *C, TransInfo *t)
{
if (t->draw_handle_view) {
@@ -885,12 +921,18 @@ void calculateCenterCursor(TransInfo *t, float r_center[3])
void calculateCenterCursor2D(TransInfo *t, float r_center[2])
{
+ float cursor_local_buf[2];
const float *cursor = NULL;
if (t->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)t->area->spacedata.first;
cursor = sima->cursor;
}
+ if (t->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = (SpaceSeq *)t->area->spacedata.first;
+ SEQ_image_preview_unit_to_px(t->scene, sseq->cursor, cursor_local_buf);
+ cursor = cursor_local_buf;
+ }
else if (t->spacetype == SPACE_CLIP) {
SpaceClip *space_clip = (SpaceClip *)t->area->spacedata.first;
cursor = space_clip->cursor;
@@ -1013,9 +1055,6 @@ void calculateCenterBound(TransInfo *t, float r_center[3])
}
}
-/**
- * \param select_only: only get active center from data being transformed.
- */
bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
@@ -1069,7 +1108,7 @@ static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[
calculateCenterMedian(t, r_center);
break;
case V3D_AROUND_CURSOR:
- if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) {
+ if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_SEQ, SPACE_CLIP)) {
calculateCenterCursor2D(t, r_center);
}
else if (t->spacetype == SPACE_GRAPH) {
@@ -1269,11 +1308,6 @@ void calculatePropRatio(TransInfo *t)
}
}
-/**
- * Rotate an element, low level code, ignore protected channels.
- * (use for objects or pose-bones)
- * Similar to #ElementRotation.
- */
void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot)
{
float totmat[3][3];
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
index 0d66db0d7e1..c3a0e4b1163 100644
--- a/source/blender/editors/transform/transform_gizmo_2d.c
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -32,6 +32,7 @@
#include "DNA_view3d_types.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_layer.h"
#include "RNA_access.h"
@@ -70,14 +71,40 @@ static bool gizmo2d_generic_poll(const bContext *C, wmGizmoGroupType *gzgt)
return false;
}
+ if (G.moving) {
+ return false;
+ }
+
ScrArea *area = CTX_wm_area(C);
+ if (area == NULL) {
+ return false;
+ }
+
+ /* NOTE: below this is assumed to be a tool gizmo.
+ * If there are cases that need to check other flags - this function could be split. */
switch (area->spacetype) {
case SPACE_IMAGE: {
- SpaceImage *sima = area->spacedata.first;
+ const SpaceImage *sima = area->spacedata.first;
Object *obedit = CTX_data_edit_object(C);
if (!ED_space_image_show_uvedit(sima, obedit)) {
return false;
}
+ break;
+ }
+ case SPACE_SEQ: {
+ const SpaceSeq *sseq = area->spacedata.first;
+ if (sseq->gizmo_flag & (SEQ_GIZMO_HIDE | SEQ_GIZMO_HIDE_TOOL)) {
+ return false;
+ }
+ if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
+ return false;
+ }
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = SEQ_editing_get(scene);
+ if (ed == NULL) {
+ return false;
+ }
+ break;
}
}
@@ -149,6 +176,7 @@ typedef struct GizmoGroup2D {
float origin[2];
float min[2];
float max[2];
+ float rotation;
bool no_cage;
@@ -217,7 +245,7 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
}
ScrArea *area = CTX_wm_area(C);
- bool changed = false;
+ bool has_select = false;
if (area->spacetype == SPACE_IMAGE) {
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -225,18 +253,82 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, NULL, &objects_len);
if (ED_uvedit_minmax_multi(scene, objects, objects_len, r_min, r_max)) {
- changed = true;
+ has_select = true;
}
MEM_freeN(objects);
}
+ else if (area->spacetype == SPACE_SEQ) {
+ Scene *scene = CTX_data_scene(C);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ SEQ_filter_selected_strips(strips);
+ int selected_strips = SEQ_collection_len(strips);
+ if (selected_strips > 0) {
+ INIT_MINMAX2(r_min, r_max);
+ has_select = true;
+
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
+ float quad[4][2];
+ SEQ_image_transform_quad_get(scene, seq, selected_strips != 1, quad);
+ for (int i = 0; i < 4; i++) {
+ minmax_v2v2_v2(r_min, r_max, quad[i]);
+ }
+ }
+ }
+ SEQ_collection_free(strips);
+ if (selected_strips > 1) {
+ /* Don't draw the cage as transforming multiple strips isn't currently very useful as it
+ * doesn't behave as one would expect.
+ *
+ * This is because our current transform system doesn't support shearing which would make the
+ * scaling transforms of the bounding box behave weirdly.
+ * In addition to this, the rotation of the bounding box can not currently be hooked up
+ * properly to read the result from the transform system (when transforming multiple strips).
+ */
+ const int pivot_point = scene->toolsettings->sequencer_tool_settings->pivot_point;
+ if (pivot_point == V3D_AROUND_CURSOR) {
+ SpaceSeq *sseq = area->spacedata.first;
+ SEQ_image_preview_unit_to_px(scene, sseq->cursor, r_center);
+ }
+ else {
+ mid_v2_v2v2(r_center, r_min, r_max);
+ }
+ zero_v2(r_min);
+ zero_v2(r_max);
+ return has_select;
+ }
+ }
- if (changed == false) {
+ if (has_select == false) {
zero_v2(r_min);
zero_v2(r_max);
}
mid_v2_v2v2(r_center, r_min, r_max);
- return changed;
+ return has_select;
+}
+
+static int gizmo2d_calc_transform_orientation(const bContext *C)
+{
+ ScrArea *area = CTX_wm_area(C);
+ if (area->spacetype != SPACE_SEQ) {
+ return V3D_ORIENT_GLOBAL;
+ }
+
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_active_seqbase_get(ed);
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ SEQ_filter_selected_strips(strips);
+
+ bool use_local_orient = SEQ_collection_len(strips) == 1;
+ SEQ_collection_free(strips);
+
+ if (use_local_orient) {
+ return V3D_ORIENT_LOCAL;
+ }
+ return V3D_ORIENT_GLOBAL;
}
static float gizmo2d_calc_rotation(const bContext *C)
@@ -252,9 +344,10 @@ static float gizmo2d_calc_rotation(const bContext *C)
SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, strips) {
- if (seq == ed->act_seq) {
+ if (SEQ_collection_len(strips) == 1) {
+ /* Only return the strip rotation if only one is selected. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
StripTransform *transform = seq->strip->transform;
float mirror[2];
SEQ_image_transform_mirror_factor_get(seq, mirror);
@@ -267,37 +360,59 @@ static float gizmo2d_calc_rotation(const bContext *C)
return 0.0f;
}
-static bool gizmo2d_calc_center(const bContext *C, float r_center[2])
+static bool seq_get_strip_pivot_median(const Scene *scene, float r_pivot[2])
+{
+ zero_v2(r_pivot);
+
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ SEQ_filter_selected_strips(strips);
+ bool has_select = SEQ_collection_len(strips) != 0;
+
+ if (has_select) {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
+ float origin[2];
+ SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, origin);
+ add_v2_v2(r_pivot, origin);
+ }
+ mul_v2_fl(r_pivot, 1.0f / SEQ_collection_len(strips));
+ }
+
+ SEQ_collection_free(strips);
+ return has_select;
+}
+
+static bool gizmo2d_calc_transform_pivot(const bContext *C, float r_pivot[2])
{
ScrArea *area = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
bool has_select = false;
- zero_v2(r_center);
+
if (area->spacetype == SPACE_IMAGE) {
SpaceImage *sima = area->spacedata.first;
ViewLayer *view_layer = CTX_data_view_layer(C);
- ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_center, sima->around, &has_select);
+ ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_pivot, sima->around, &has_select);
}
else if (area->spacetype == SPACE_SEQ) {
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
- SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
- SEQ_filter_selected_strips(strips);
+ SpaceSeq *sseq = area->spacedata.first;
+ const int pivot_point = scene->toolsettings->sequencer_tool_settings->pivot_point;
+
+ if (pivot_point == V3D_AROUND_CURSOR) {
+ SEQ_image_preview_unit_to_px(scene, sseq->cursor, r_pivot);
- if (SEQ_collection_len(strips) <= 0) {
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ SEQ_filter_selected_strips(strips);
+ has_select = SEQ_collection_len(strips) != 0;
SEQ_collection_free(strips);
- return false;
}
-
- has_select = true;
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, strips) {
- float origin[2];
- SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, origin);
- add_v2_v2(r_center, origin);
+ else {
+ has_select = seq_get_strip_pivot_median(scene, r_pivot);
}
- mul_v2_fl(r_center, 1.0f / SEQ_collection_len(strips));
-
- SEQ_collection_free(strips);
+ }
+ else {
+ BLI_assert_msg(0, "Unhandled space type!");
}
return has_select;
}
@@ -321,7 +436,7 @@ static int gizmo2d_modal(bContext *C,
ARegion *region = CTX_wm_region(C);
float origin[3];
- gizmo2d_calc_center(C, origin);
+ gizmo2d_calc_transform_pivot(C, origin);
gizmo2d_origin_to_region(region, origin);
WM_gizmo_set_matrix_location(widget, origin);
@@ -410,17 +525,17 @@ static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup
ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X, ot_resize, NULL);
PropertyRNA *prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
- RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
RNA_property_boolean_set(ptr, prop_release_confirm, true);
- ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X, ot_resize, NULL);
RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
+ ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X, ot_resize, NULL);
RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y, ot_resize, NULL);
- RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
RNA_property_boolean_set(ptr, prop_release_confirm, true);
- ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y, ot_resize, NULL);
RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
+ ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y, ot_resize, NULL);
RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
ptr = WM_gizmo_operator_set(
ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y, ot_resize, NULL);
@@ -439,97 +554,51 @@ static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup
}
}
-static void gizmo2d_xform_setup_no_cage(const bContext *C, wmGizmoGroup *gzgroup)
+static void rotate_around_center_v2(float point[2], const float center[2], const float angle)
{
- gizmo2d_xform_setup(C, gzgroup);
- GizmoGroup2D *ggd = gzgroup->customdata;
- ggd->no_cage = true;
+ float tmp[2];
+
+ sub_v2_v2v2(tmp, point, center);
+ rotate_v2_v2fl(point, tmp, angle);
+ add_v2_v2(point, center);
}
static void gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup2D *ggd = gzgroup->customdata;
- float origin[3];
bool has_select;
if (ggd->no_cage) {
- has_select = gizmo2d_calc_center(C, origin);
+ has_select = gizmo2d_calc_transform_pivot(C, ggd->origin);
}
else {
- has_select = gizmo2d_calc_bounds(C, origin, ggd->min, ggd->max);
+ has_select = gizmo2d_calc_bounds(C, ggd->origin, ggd->min, ggd->max);
+ ggd->rotation = gizmo2d_calc_rotation(C);
}
- copy_v2_v2(ggd->origin, origin);
- bool show_cage = !ggd->no_cage && !equals_v2v2(ggd->min, ggd->max);
- if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
- Scene *scene = CTX_data_scene(C);
- if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
- gzgroup->use_fallback_keymap = true;
- }
- else {
- gzgroup->use_fallback_keymap = false;
- }
- }
+ bool show_cage = !ggd->no_cage && !equals_v2v2(ggd->min, ggd->max);
if (has_select == false) {
+ /* Nothing selected. Disable gizmo drawing and return. */
+ ggd->cage->flag |= WM_GIZMO_HIDDEN;
for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
ggd->translate_xy[i]->flag |= WM_GIZMO_HIDDEN;
}
- ggd->cage->flag |= WM_GIZMO_HIDDEN;
+ return;
}
- else {
- if (show_cage) {
- ggd->cage->flag &= ~WM_GIZMO_HIDDEN;
- for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
- wmGizmo *gz = ggd->translate_xy[i];
- gz->flag |= WM_GIZMO_HIDDEN;
- }
- }
- else {
- ggd->cage->flag |= WM_GIZMO_HIDDEN;
- for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
- wmGizmo *gz = ggd->translate_xy[i];
- gz->flag &= ~WM_GIZMO_HIDDEN;
- }
- }
- if (show_cage) {
- wmGizmoOpElem *gzop;
- float mid[2];
- const float *min = ggd->min;
- const float *max = ggd->max;
- mid_v2_v2v2(mid, min, max);
-
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X);
- PropertyRNA *prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){max[0], mid[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){min[0], mid[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){mid[0], max[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){mid[0], min[1], 0.0f});
-
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){max[0], max[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){max[0], min[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){min[0], max[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){min[0], min[1], 0.0f});
-
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_ROTATE);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){mid[0], mid[1], 0.0f});
+ if (!show_cage) {
+ /* Disable cage gizmo drawing and return. */
+ ggd->cage->flag |= WM_GIZMO_HIDDEN;
+ for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
+ ggd->translate_xy[i]->flag &= ~WM_GIZMO_HIDDEN;
}
+ return;
+ }
+
+ /* We will show the cage gizmo! Setup all necessary data. */
+ ggd->cage->flag &= ~WM_GIZMO_HIDDEN;
+ for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
+ ggd->translate_xy[i]->flag |= WM_GIZMO_HIDDEN;
}
}
@@ -538,7 +607,6 @@ static void gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
ARegion *region = CTX_wm_region(C);
GizmoGroup2D *ggd = gzgroup->customdata;
float origin[3] = {UNPACK2(ggd->origin), 0.0f};
- const float origin_aa[3] = {UNPACK2(ggd->origin), 0.0f};
gizmo2d_origin_to_region(region, origin);
@@ -548,19 +616,129 @@ static void gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
}
UI_view2d_view_to_region_m4(&region->v2d, ggd->cage->matrix_space);
- WM_gizmo_set_matrix_offset_location(ggd->cage, origin_aa);
+ /* Define the bounding box of the gizmo in the offset transform matrix. */
+ unit_m4(ggd->cage->matrix_offset);
ggd->cage->matrix_offset[0][0] = (ggd->max[0] - ggd->min[0]);
ggd->cage->matrix_offset[1][1] = (ggd->max[1] - ggd->min[1]);
+
+ ScrArea *area = CTX_wm_area(C);
+
+ if (area->spacetype == SPACE_SEQ) {
+ Scene *scene = CTX_data_scene(C);
+ seq_get_strip_pivot_median(scene, origin);
+
+ float matrix_rotate[4][4];
+ unit_m4(matrix_rotate);
+ copy_v3_v3(matrix_rotate[3], origin);
+ rotate_m4(matrix_rotate, 'Z', ggd->rotation);
+ unit_m4(ggd->cage->matrix_basis);
+ mul_m4_m4m4(ggd->cage->matrix_basis, matrix_rotate, ggd->cage->matrix_basis);
+
+ float mid[2];
+ sub_v2_v2v2(mid, origin, ggd->origin);
+ mul_v2_fl(mid, -1.0f);
+ copy_v2_v2(ggd->cage->matrix_offset[3], mid);
+ }
+ else {
+ const float origin_aa[3] = {UNPACK2(ggd->origin), 0.0f};
+ WM_gizmo_set_matrix_offset_location(ggd->cage, origin_aa);
+ }
}
-static void gizmo2d_xform_no_cage_message_subscribe(const struct bContext *C,
- struct wmGizmoGroup *gzgroup,
- struct wmMsgBus *mbus)
+static void gizmo2d_xform_invoke_prepare(const bContext *C,
+ wmGizmoGroup *gzgroup,
+ wmGizmo *UNUSED(gz),
+ const wmEvent *UNUSED(event))
{
- bScreen *screen = CTX_wm_screen(C);
+ GizmoGroup2D *ggd = gzgroup->customdata;
+ wmGizmoOpElem *gzop;
+ const float *mid = ggd->origin;
+ const float *min = ggd->min;
+ const float *max = ggd->max;
+
+ /* Define the different transform center points that will be used when grabbing the corners or
+ * rotating with the gizmo.
+ *
+ * The coordinates are referred to as their cardinal directions:
+ * N
+ * o
+ *NW | NE
+ * x-----------x
+ * | |
+ *W| C |E
+ * | |
+ * x-----------x
+ *SW S SE
+ */
+ float n[3] = {mid[0], max[1], 0.0f};
+ float w[3] = {min[0], mid[1], 0.0f};
+ float e[3] = {max[0], mid[1], 0.0f};
+ float s[3] = {mid[0], min[1], 0.0f};
+
+ float nw[3] = {min[0], max[1], 0.0f};
+ float ne[3] = {max[0], max[1], 0.0f};
+ float sw[3] = {min[0], min[1], 0.0f};
+ float se[3] = {max[0], min[1], 0.0f};
+
+ float c[3] = {mid[0], mid[1], 0.0f};
+
+ float orient_matrix[3][3];
+
ScrArea *area = CTX_wm_area(C);
- ARegion *region = CTX_wm_region(C);
- gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
+
+ if (ggd->rotation != 0.0f && area->spacetype == SPACE_SEQ) {
+ float origin[3];
+ Scene *scene = CTX_data_scene(C);
+ seq_get_strip_pivot_median(scene, origin);
+ /* We need to rotate the cardinal points so they align with the rotated bounding box. */
+
+ rotate_around_center_v2(n, origin, ggd->rotation);
+ rotate_around_center_v2(w, origin, ggd->rotation);
+ rotate_around_center_v2(e, origin, ggd->rotation);
+ rotate_around_center_v2(s, origin, ggd->rotation);
+
+ rotate_around_center_v2(nw, origin, ggd->rotation);
+ rotate_around_center_v2(ne, origin, ggd->rotation);
+ rotate_around_center_v2(sw, origin, ggd->rotation);
+ rotate_around_center_v2(se, origin, ggd->rotation);
+
+ rotate_around_center_v2(c, origin, ggd->rotation);
+
+ axis_angle_to_mat3_single(orient_matrix, 'Z', ggd->rotation);
+ }
+
+ int orient_type = gizmo2d_calc_transform_orientation(C);
+
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X);
+ PropertyRNA *prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
+ PropertyRNA *prop_mouse_dir = RNA_struct_find_property(&gzop->ptr, "mouse_dir_constraint");
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, e);
+ RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[0]);
+ RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, w);
+ RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[0]);
+ RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, n);
+ RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[1]);
+ RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, s);
+ RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[1]);
+ RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
+
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, ne);
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, se);
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, nw);
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, sw);
+
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_ROTATE);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, c);
}
void ED_widgetgroup_gizmo2d_xform_callbacks_set(wmGizmoGroupType *gzgt)
@@ -570,6 +748,24 @@ void ED_widgetgroup_gizmo2d_xform_callbacks_set(wmGizmoGroupType *gzgt)
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->refresh = gizmo2d_xform_refresh;
gzgt->draw_prepare = gizmo2d_xform_draw_prepare;
+ gzgt->invoke_prepare = gizmo2d_xform_invoke_prepare;
+}
+
+static void gizmo2d_xform_setup_no_cage(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ gizmo2d_xform_setup(C, gzgroup);
+ GizmoGroup2D *ggd = gzgroup->customdata;
+ ggd->no_cage = true;
+}
+
+static void gizmo2d_xform_no_cage_message_subscribe(const struct bContext *C,
+ struct wmGizmoGroup *gzgroup,
+ struct wmMsgBus *mbus)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
}
void ED_widgetgroup_gizmo2d_xform_no_cage_callbacks_set(wmGizmoGroupType *gzgt)
@@ -614,7 +810,7 @@ static void gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup_Resize2D *ggd = gzgroup->customdata;
float origin[3];
- const bool has_select = gizmo2d_calc_center(C, origin);
+ const bool has_select = gizmo2d_calc_transform_pivot(C, origin);
if (has_select == false) {
for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
@@ -636,16 +832,6 @@ static void gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup
GizmoGroup_Resize2D *ggd = gzgroup->customdata;
float origin[3] = {UNPACK2(ggd->origin), 0.0f};
- if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
- Scene *scene = CTX_data_scene(C);
- if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
- gzgroup->use_fallback_keymap = true;
- }
- else {
- gzgroup->use_fallback_keymap = false;
- }
- }
-
gizmo2d_origin_to_region(region, origin);
for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
@@ -720,6 +906,18 @@ static void gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgrou
}
}
+static void gizmo2d_resize_invoke_prepare(const bContext *C,
+ wmGizmoGroup *UNUSED(gzgroup),
+ wmGizmo *gz,
+ const wmEvent *UNUSED(event))
+{
+ wmGizmoOpElem *gzop;
+ int orient_type = gizmo2d_calc_transform_orientation(C);
+
+ gzop = WM_gizmo_operator_get(gz, 0);
+ RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
+}
+
static void gizmo2d_resize_message_subscribe(const struct bContext *C,
struct wmGizmoGroup *gzgroup,
struct wmMsgBus *mbus)
@@ -737,6 +935,7 @@ void ED_widgetgroup_gizmo2d_resize_callbacks_set(wmGizmoGroupType *gzgt)
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->refresh = gizmo2d_resize_refresh;
gzgt->draw_prepare = gizmo2d_resize_draw_prepare;
+ gzgt->invoke_prepare = gizmo2d_resize_invoke_prepare;
gzgt->message_subscribe = gizmo2d_resize_message_subscribe;
}
@@ -771,7 +970,7 @@ static void gizmo2d_rotate_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup_Rotate2D *ggd = gzgroup->customdata;
float origin[3];
- const bool has_select = gizmo2d_calc_center(C, origin);
+ const bool has_select = gizmo2d_calc_transform_pivot(C, origin);
if (has_select == false) {
ggd->gizmo->flag |= WM_GIZMO_HIDDEN;
@@ -788,16 +987,6 @@ static void gizmo2d_rotate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup
GizmoGroup_Rotate2D *ggd = gzgroup->customdata;
float origin[3] = {UNPACK2(ggd->origin), 0.0f};
- if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
- Scene *scene = CTX_data_scene(C);
- if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
- gzgroup->use_fallback_keymap = true;
- }
- else {
- gzgroup->use_fallback_keymap = false;
- }
- }
-
gizmo2d_origin_to_region(region, origin);
wmGizmo *gz = ggd->gizmo;
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index 0fa179c4f74..9bd55d78039 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -515,7 +515,7 @@ static void protectflag_to_drawflags_pchan(RegionView3D *rv3d,
{
/* Protect-flags apply to local space in pose mode, so only let them influence axis
* visibility if we show the global orientation, otherwise it's confusing. */
- if (orientation_index == V3D_ORIENT_LOCAL) {
+ if (ELEM(orientation_index, V3D_ORIENT_LOCAL, V3D_ORIENT_GIMBAL)) {
protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
}
}
@@ -564,76 +564,65 @@ static bool test_rotmode_euler(short rotmode)
return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1;
}
-/**
- * Return false when no gimbal for selection.
- */
-bool gimbal_axis(Object *ob, float gmat[3][3])
+bool gimbal_axis_pose(Object *ob, const bPoseChannel *pchan, float gmat[3][3])
{
- if (ob->mode & OB_MODE_POSE) {
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
-
- if (pchan) {
- float mat[3][3], tmat[3][3], obmat[3][3];
- if (test_rotmode_euler(pchan->rotmode)) {
- eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
- }
- else { /* quat */
- return 0;
- }
-
- /* apply bone transformation */
- mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
+ float mat[3][3], tmat[3][3], obmat[3][3];
+ if (test_rotmode_euler(pchan->rotmode)) {
+ eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
+ }
+ else { /* quat */
+ return 0;
+ }
- if (pchan->parent) {
- float parent_mat[3][3];
+ /* apply bone transformation */
+ mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
- copy_m3_m4(parent_mat,
- (pchan->bone->flag & BONE_HINGE) ? pchan->parent->bone->arm_mat :
- pchan->parent->pose_mat);
- mul_m3_m3m3(mat, parent_mat, tmat);
+ if (pchan->parent) {
+ float parent_mat[3][3];
- /* needed if object transformation isn't identity */
- copy_m3_m4(obmat, ob->obmat);
- mul_m3_m3m3(gmat, obmat, mat);
- }
- else {
- /* needed if object transformation isn't identity */
- copy_m3_m4(obmat, ob->obmat);
- mul_m3_m3m3(gmat, obmat, tmat);
- }
+ copy_m3_m4(parent_mat,
+ (pchan->bone->flag & BONE_HINGE) ? pchan->parent->bone->arm_mat :
+ pchan->parent->pose_mat);
+ mul_m3_m3m3(mat, parent_mat, tmat);
- normalize_m3(gmat);
- return 1;
- }
+ /* needed if object transformation isn't identity */
+ copy_m3_m4(obmat, ob->obmat);
+ mul_m3_m3m3(gmat, obmat, mat);
}
else {
- if (test_rotmode_euler(ob->rotmode)) {
- eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
- }
- else if (ob->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
- }
- else { /* quat */
- return 0;
- }
+ /* needed if object transformation isn't identity */
+ copy_m3_m4(obmat, ob->obmat);
+ mul_m3_m3m3(gmat, obmat, tmat);
+ }
- if (ob->parent) {
- float parent_mat[3][3];
- copy_m3_m4(parent_mat, ob->parent->obmat);
- normalize_m3(parent_mat);
- mul_m3_m3m3(gmat, parent_mat, gmat);
- }
- return 1;
+ normalize_m3(gmat);
+ return true;
+}
+
+bool gimbal_axis_object(Object *ob, float gmat[3][3])
+{
+ if (test_rotmode_euler(ob->rotmode)) {
+ eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
+ }
+ else if (ob->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
+ }
+ else { /* quat */
+ return 0;
}
- return 0;
+ if (ob->parent) {
+ float parent_mat[3][3];
+ copy_m3_m4(parent_mat, ob->parent->obmat);
+ normalize_m3(parent_mat);
+ mul_m3_m3m3(gmat, parent_mat, gmat);
+ }
+ return 1;
}
-/* centroid, boundbox, of selection */
-/* returns total items selected */
int ED_transform_calc_gizmo_stats(const bContext *C,
const struct TransformCalcParams *params,
struct TransformBounds *tbounds)
@@ -646,10 +635,8 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
Depsgraph *depsgraph = CTX_data_expect_evaluated_depsgraph(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = area->spacedata.first;
- Object *obedit = CTX_data_edit_object(C);
RegionView3D *rv3d = region->regiondata;
Base *base;
- Object *ob = OBACT(view_layer);
bGPdata *gpd = CTX_data_gpencil_data(C);
const bool is_gp_edit = GPENCIL_ANY_MODE(gpd);
const bool is_curve_edit = GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
@@ -660,6 +647,17 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
(params->orientation_index - 1) :
BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
+ Object *ob = OBACT(view_layer);
+ Object *obedit = OBEDIT_FROM_OBACT(ob);
+ if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
+ Object *obpose = BKE_object_pose_armature_get(ob);
+ if (obpose != NULL) {
+ ob = obpose;
+ }
+ }
+
+ tbounds->use_matrix_space = false;
+
/* transform widget matrix */
unit_m4(rv3d->twmat);
@@ -682,13 +680,16 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
reset_tw_center(tbounds);
copy_m3_m4(tbounds->axis, rv3d->twmat);
- if (params->use_local_axis && (ob && ob->mode & OB_MODE_EDIT)) {
+ if (params->use_local_axis && (ob && ob->mode & (OB_MODE_EDIT | OB_MODE_POSE))) {
float diff_mat[3][3];
copy_m3_m4(diff_mat, ob->obmat);
normalize_m3(diff_mat);
invert_m3(diff_mat);
mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat);
normalize_m3(tbounds->axis);
+
+ tbounds->use_matrix_space = true;
+ copy_m4_m4(tbounds->matrix_space, ob->obmat);
}
if (is_gp_edit) {
@@ -963,8 +964,10 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
if (totsel_iter) {
float mat_local[4][4];
- if (use_mat_local) {
- mul_m4_m4m4(mat_local, ob->imat, ob_iter->obmat);
+ if (params->use_local_axis) {
+ if (use_mat_local) {
+ mul_m4_m4m4(mat_local, ob->imat, ob_iter->obmat);
+ }
}
/* use channels to get stats */
@@ -1057,9 +1060,13 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
}
}
- /* Protect-flags apply to world space in object mode, so only let them influence axis
- * visibility if we show the global orientation, otherwise it's confusing. */
if (orient_index == V3D_ORIENT_GLOBAL) {
+ /* Protect-flags apply to world space in object mode,
+ * so only let them influence axis visibility if we show the global orientation,
+ * otherwise it's confusing. */
+ protectflag_to_drawflags(base->object->protectflag & OB_LOCK_LOC, &rv3d->twdrawflag);
+ }
+ else if (ELEM(orient_index, V3D_ORIENT_LOCAL, V3D_ORIENT_GIMBAL)) {
protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
}
totsel++;
@@ -1670,13 +1677,6 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
RegionView3D *rv3d = region->regiondata;
struct TransformBounds tbounds;
- if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
- gzgroup->use_fallback_keymap = true;
- }
- else {
- gzgroup->use_fallback_keymap = false;
- }
-
if (ggd->use_twtype_refresh) {
ggd->twtype = v3d->gizmo_show_object & ggd->twtype_init;
if (ggd->twtype != ggd->twtype_prev) {
@@ -2003,7 +2003,6 @@ void VIEW3D_GGT_xform_gizmo(wmGizmoGroupType *gzgt)
"");
}
-/** Only poll, flag & gzmap_params differ. */
void VIEW3D_GGT_xform_gizmo_context(wmGizmoGroupType *gzgt)
{
gzgt->name = "3D View: Transform Gizmo Context";
@@ -2105,13 +2104,6 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgr
struct TransformBounds tbounds;
- if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
- gzgroup->use_fallback_keymap = true;
- }
- else {
- gzgroup->use_fallback_keymap = false;
- }
-
const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, SCE_ORIENT_SCALE);
if ((ED_transform_calc_gizmo_stats(C,
@@ -2124,10 +2116,8 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgr
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
else {
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- if (ob && ob->mode & OB_MODE_EDIT) {
- copy_m4_m4(gz->matrix_space, ob->obmat);
+ if (tbounds.use_matrix_space) {
+ copy_m4_m4(gz->matrix_space, tbounds.matrix_space);
}
else {
unit_m4(gz->matrix_space);
@@ -2316,13 +2306,6 @@ static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzg
struct XFormShearWidgetGroup *xgzgroup = gzgroup->customdata;
struct TransformBounds tbounds;
- if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
- gzgroup->use_fallback_keymap = true;
- }
- else {
- gzgroup->use_fallback_keymap = false;
- }
-
/* Needed to test view orientation changes. */
copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
diff --git a/source/blender/editors/transform/transform_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
index ca4ed01c0f6..dee6e7281ef 100644
--- a/source/blender/editors/transform/transform_gizmo_extrude_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
@@ -82,6 +82,7 @@ typedef struct GizmoExtrudeGroup {
float orient_matrix[3][3];
bool constraint_axis[3];
float value[4];
+ int orient_type;
} redo_xform;
/* Depends on object type. */
@@ -310,6 +311,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup)
RNA_float_get_array(op_xform->ptr, "orient_matrix", &ggd->redo_xform.orient_matrix[0][0]);
RNA_boolean_get_array(op_xform->ptr, "constraint_axis", ggd->redo_xform.constraint_axis);
RNA_float_get_array(op_xform->ptr, "value", ggd->redo_xform.value);
+ ggd->redo_xform.orient_type = RNA_enum_get(op_xform->ptr, "orient_type");
/* Set properties for redo. */
for (int i = 0; i < 3; i++) {
@@ -381,11 +383,9 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup)
if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
WM_gizmo_set_flag(ggd->invoke_view, WM_GIZMO_HIDDEN, false);
- gzgroup->use_fallback_keymap = true;
}
else {
WM_gizmo_set_flag(ggd->invoke_view, WM_GIZMO_HIDDEN, true);
- gzgroup->use_fallback_keymap = false;
}
}
@@ -437,7 +437,8 @@ static void gizmo_mesh_extrude_invoke_prepare(const bContext *UNUSED(C),
if (gz == ggd->adjust[0]) {
RNA_boolean_set_array(&macroptr, "constraint_axis", ggd->redo_xform.constraint_axis);
RNA_float_set_array(&macroptr, "orient_matrix", &ggd->redo_xform.orient_matrix[0][0]);
- RNA_enum_set(&macroptr, "orient_type", V3D_ORIENT_NORMAL);
+ RNA_enum_set(&macroptr, "orient_matrix_type", ggd->redo_xform.orient_type);
+ RNA_enum_set(&macroptr, "orient_type", ggd->redo_xform.orient_type);
}
RNA_float_set_array(&macroptr, "value", ggd->redo_xform.value);
}
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index b14d499cb66..e1fea62ae54 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -78,7 +78,6 @@ bool transdata_check_local_center(const TransInfo *t, short around)
(t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE | CTX_SEQUENCER_IMAGE))));
}
-/* Informs if the mode can be switched during modal. */
bool transform_mode_is_changeable(const int mode)
{
return ELEM(mode,
@@ -520,10 +519,12 @@ void constraintSizeLim(const TransInfo *t, TransData *td)
}
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Transform (Rotation Utils)
* \{ */
-/* Used by Transform Rotation and Transform Normal Rotation */
+
void headerRotation(TransInfo *t, char *str, const int str_size, float final)
{
size_t ofs = 0;
@@ -551,12 +552,6 @@ void headerRotation(TransInfo *t, char *str, const int str_size, float final)
}
}
-/**
- * Applies values of rotation to `td->loc` and `td->ext->quat`
- * based on a rotation matrix (mat) and a pivot (center).
- *
- * Protected axis and other transform settings are taken into account.
- */
void ElementRotation_ex(const TransInfo *t,
const TransDataContainer *tc,
TransData *td,
@@ -828,11 +823,13 @@ void ElementRotation(const TransInfo *t,
ElementRotation_ex(t, tc, td, mat, center);
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Transform (Resize Utils)
* \{ */
+
void headerResize(TransInfo *t, const float vec[3], char *str, const int str_size)
{
char tvec[NUM_STR_REP_LEN * 3];
@@ -1045,7 +1042,7 @@ void ElementResize(const TransInfo *t,
applyNumInput(&num_evil, values_final_evil);
float ratio = values_final_evil[0];
- *td->val = td->ival * ratio * gps->runtime.multi_frame_falloff;
+ *td->val = td->ival * fabs(ratio) * gps->runtime.multi_frame_falloff;
CLAMP_MIN(*td->val, 0.001f);
}
}
@@ -1054,6 +1051,11 @@ void ElementResize(const TransInfo *t,
}
if (t->options & (CTX_OBJECT | CTX_POSE_BONE)) {
+ if (t->options & CTX_POSE_BONE) {
+ /* Without this, the resulting location of scaled bones aren't correct,
+ * especially noticeable scaling root or disconnected bones around the cursor, see T92515. */
+ mul_mat3_m4_v3(tc->poseobj->obmat, vec);
+ }
mul_m3_v3(td->smtx, vec);
}
@@ -1082,9 +1084,24 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
case TFM_ROTATION:
initRotation(t);
break;
- case TFM_RESIZE:
- initResize(t);
+ case TFM_RESIZE: {
+ float mouse_dir_constraint[3];
+ if (op) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "mouse_dir_constraint");
+ if (prop) {
+ RNA_property_float_get_array(op->ptr, prop, mouse_dir_constraint);
+ }
+ else {
+ /* Resize is expected to have this property. */
+ BLI_assert(!STREQ(op->idname, "TRANSFORM_OT_resize"));
+ }
+ }
+ else {
+ zero_v3(mouse_dir_constraint);
+ }
+ initResize(t, mouse_dir_constraint);
break;
+ }
case TFM_SKIN_RESIZE:
initSkinResize(t);
break;
@@ -1118,8 +1135,11 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
case TFM_PUSHPULL:
initPushPull(t);
break;
- case TFM_CREASE:
- initCrease(t);
+ case TFM_EDGE_CREASE:
+ initEgdeCrease(t);
+ break;
+ case TFM_VERT_CREASE:
+ initVertCrease(t);
break;
case TFM_BONESIZE:
initBoneSize(t);
@@ -1212,15 +1232,12 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
* BLI_assert(t->mode == mode); */
}
-/**
- * When in modal and not set, initializes a default orientation for the mode.
- */
void transform_mode_default_modal_orientation_set(TransInfo *t, int type)
{
/* Currently only these types are supported. */
BLI_assert(ELEM(type, V3D_ORIENT_GLOBAL, V3D_ORIENT_VIEW));
- if (t->is_orient_set) {
+ if (t->is_orient_default_overwrite) {
return;
}
@@ -1256,4 +1273,5 @@ void transform_mode_default_modal_orientation_set(TransInfo *t, int type)
transform_orientations_current_set(t, O_DEFAULT);
}
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index d8601000ddb..16b26724c67 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -42,12 +42,24 @@ typedef struct TransDataGenericSlideVert {
/* transform_mode.c */
int transform_mode_really_used(struct bContext *C, int mode);
bool transdata_check_local_center(const TransInfo *t, short around);
-bool transform_mode_is_changeable(const int mode);
+/**
+ * Informs if the mode can be switched during modal.
+ */
+bool transform_mode_is_changeable(int mode);
void protectedTransBits(short protectflag, float vec[3]);
void protectedSizeBits(short protectflag, float size[3]);
void constraintTransLim(const TransInfo *t, TransData *td);
void constraintSizeLim(const TransInfo *t, TransData *td);
+/**
+ * Used by Transform Rotation and Transform Normal Rotation.
+ */
void headerRotation(TransInfo *t, char *str, int str_size, float final);
+/**
+ * Applies values of rotation to `td->loc` and `td->ext->quat`
+ * based on a rotation matrix (mat) and a pivot (center).
+ *
+ * Protected axis and other transform settings are taken into account.
+ */
void ElementRotation_ex(const TransInfo *t,
const TransDataContainer *tc,
TransData *td,
@@ -57,13 +69,16 @@ void ElementRotation(const TransInfo *t,
const TransDataContainer *tc,
TransData *td,
const float mat[3][3],
- const short around);
+ short around);
void headerResize(TransInfo *t, const float vec[3], char *str, int str_size);
void ElementResize(const TransInfo *t,
const TransDataContainer *tc,
TransData *td,
const float mat[3][3]);
-void transform_mode_init(TransInfo *t, struct wmOperator *op, const int mode);
+void transform_mode_init(TransInfo *t, struct wmOperator *op, int mode);
+/**
+ * When in modal and not set, initializes a default orientation for the mode.
+ */
void transform_mode_default_modal_orientation_set(TransInfo *t, int type);
/* transform_mode_align.c */
@@ -91,7 +106,8 @@ void initCurveShrinkFatten(TransInfo *t);
void initBevelWeight(TransInfo *t);
/* transform_mode_edge_crease.c */
-void initCrease(TransInfo *t);
+void initEgdeCrease(TransInfo *t);
+void initVertCrease(TransInfo *t);
/* transform_mode_edge_rotate_normal.c */
void initNormalRotation(TransInfo *t);
@@ -121,7 +137,7 @@ void initMirror(TransInfo *t);
void initPushPull(TransInfo *t);
/* transform_mode_resize.c */
-void initResize(TransInfo *t);
+void initResize(TransInfo *t, float mouse_dir_constraint[3]);
/* transform_mode_rotate.c */
void initRotation(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_mode_align.c b/source/blender/editors/transform/transform_mode_align.c
index 1a1d84699f4..f27a194dda0 100644
--- a/source/blender/editors/transform/transform_mode_align.c
+++ b/source/blender/editors/transform/transform_mode_align.c
@@ -89,4 +89,5 @@ void initAlign(TransInfo *t)
initMouseInputMode(t, &t->mouse, INPUT_NONE);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_baketime.c b/source/blender/editors/transform/transform_mode_baketime.c
index 653944b56a7..46d6e5c5983 100644
--- a/source/blender/editors/transform/transform_mode_baketime.c
+++ b/source/blender/editors/transform/transform_mode_baketime.c
@@ -132,4 +132,5 @@ void initBakeTime(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_NONE; /* Don't think this uses units? */
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_bbone_resize.c b/source/blender/editors/transform/transform_mode_bbone_resize.c
index 95e2d944b9b..ce2f3c15651 100644
--- a/source/blender/editors/transform/transform_mode_bbone_resize.c
+++ b/source/blender/editors/transform/transform_mode_bbone_resize.c
@@ -123,6 +123,7 @@ static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
float ratio = t->values[0];
copy_v3_fl(t->values_final, ratio);
+ add_v3_v3(t->values_final, t->values_modal_offset);
transform_snap_increment(t, t->values_final);
@@ -184,4 +185,5 @@ void initBoneSize(TransInfo *t)
t->num.unit_type[1] = B_UNIT_NONE;
t->num.unit_type[2] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_bend.c b/source/blender/editors/transform/transform_mode_bend.c
index 6d84c397fa6..a1bcd3aeb50 100644
--- a/source/blender/editors/transform/transform_mode_bend.c
+++ b/source/blender/editors/transform/transform_mode_bend.c
@@ -393,4 +393,5 @@ void initBend(TransInfo *t)
t->custom.mode.data = data;
t->custom.mode.use_free = true;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_boneenvelope.c b/source/blender/editors/transform/transform_mode_boneenvelope.c
index da7393ab42e..bb7bd81f7bd 100644
--- a/source/blender/editors/transform/transform_mode_boneenvelope.c
+++ b/source/blender/editors/transform/transform_mode_boneenvelope.c
@@ -51,7 +51,7 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
diff --git a/source/blender/editors/transform/transform_mode_boneroll.c b/source/blender/editors/transform/transform_mode_boneroll.c
index cd04ca2b844..00629b13ede 100644
--- a/source/blender/editors/transform/transform_mode_boneroll.c
+++ b/source/blender/editors/transform/transform_mode_boneroll.c
@@ -52,7 +52,7 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
float final;
- final = t->values[0];
+ final = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &final);
@@ -107,4 +107,5 @@ void initBoneRoll(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
index 9433502ef55..c4c33c881ed 100644
--- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
@@ -51,7 +51,7 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -115,4 +115,5 @@ void initCurveShrinkFatten(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_bevelweight.c b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
index 5466ba3e91f..8aa7955bc2a 100644
--- a/source/blender/editors/transform/transform_mode_edge_bevelweight.c
+++ b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
@@ -96,7 +96,7 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- weight = t->values[0];
+ weight = t->values[0] + t->values_modal_offset[0];
CLAMP_MAX(weight, 1.0f);
@@ -174,4 +174,5 @@ void initBevelWeight(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c
index 1d3b4dbb4f0..60b95a1d2da 100644
--- a/source/blender/editors/transform/transform_mode_edge_crease.c
+++ b/source/blender/editors/transform/transform_mode_edge_crease.c
@@ -97,7 +97,7 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- crease = t->values[0];
+ crease = t->values[0] + t->values_modal_offset[0];
CLAMP_MAX(crease, 1.0f);
@@ -157,9 +157,9 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
-void initCrease(TransInfo *t)
+static void initCrease_ex(TransInfo *t, int mode)
{
- t->mode = TFM_CREASE;
+ t->mode = mode;
t->transform = applyCrease;
initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA);
@@ -176,4 +176,13 @@ void initCrease(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+void initEgdeCrease(TransInfo *t)
+{
+ initCrease_ex(t, TFM_EDGE_CREASE);
+}
+
+void initVertCrease(TransInfo *t)
+{
+ initCrease_ex(t, TFM_VERT_CREASE);
+}
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
index 1f57bacf78f..edba9809207 100644
--- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
+++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
@@ -95,7 +95,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
float axis[3];
float mat[3][3];
- float angle = t->values[0];
+ float angle = t->values[0] + t->values_modal_offset[0];
copy_v3_v3(axis, axis_final);
transform_snap_increment(t, &angle);
@@ -152,4 +152,5 @@ void initNormalRotation(TransInfo *t)
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c
index cfcb17b8da0..223f2511c72 100644
--- a/source/blender/editors/transform/transform_mode_edge_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_slide.c
@@ -195,7 +195,7 @@ static bool bm_loop_calc_opposite_co(BMLoop *l_tmp, const float plane_no[3], flo
/* allow some overlap to avoid missing the intersection because of float precision */
if ((fac > -FLT_EPSILON) && (fac < 1.0f + FLT_EPSILON)) {
/* likelihood of multiple intersections per ngon is quite low,
- * it would have to loop back on its self, but better support it
+ * it would have to loop back on itself, but better support it
* so check for the closest opposite edge */
const float tdist = len_v3v3(l_tmp->v->co, tvec);
if (tdist < dist) {
@@ -1458,7 +1458,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
- final = t->values[0];
+ final = t->values[0] + t->values_modal_offset[0];
applySnapping(t, &final);
if (!validSnap(t)) {
@@ -1567,4 +1567,5 @@ void initEdgeSlide(TransInfo *t)
{
initEdgeSlide_ex(t, true, false, false, true);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c
index 748769491f1..5772c6b4717 100644
--- a/source/blender/editors/transform/transform_mode_gpopacity.c
+++ b/source/blender/editors/transform/transform_mode_gpopacity.c
@@ -53,7 +53,7 @@ static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -125,4 +125,5 @@ void initGPOpacity(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
index bc081edd597..f4a0c3c659c 100644
--- a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
@@ -53,7 +53,7 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -127,4 +127,5 @@ void initGPShrinkFatten(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
index 327a639773c..a1a8bed59b3 100644
--- a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
@@ -52,7 +52,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
bool initial_feather = false;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -141,4 +141,5 @@ void initMaskShrinkFatten(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c
index 2ae32f3545a..ee584cb9833 100644
--- a/source/blender/editors/transform/transform_mode_mirror.c
+++ b/source/blender/editors/transform/transform_mode_mirror.c
@@ -238,4 +238,5 @@ void initMirror(TransInfo *t)
t->flag |= T_NULL_ONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_push_pull.c b/source/blender/editors/transform/transform_mode_push_pull.c
index 0527d1bc08e..8577a0a5e11 100644
--- a/source/blender/editors/transform/transform_mode_push_pull.c
+++ b/source/blender/editors/transform/transform_mode_push_pull.c
@@ -124,7 +124,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- distance = t->values[0];
+ distance = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &distance);
@@ -199,4 +199,5 @@ void initPushPull(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_LENGTH;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c
index 65f4623b3be..3d7f0aa6d67 100644
--- a/source/blender/editors/transform/transform_mode_resize.c
+++ b/source/blender/editors/transform/transform_mode_resize.c
@@ -201,14 +201,45 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
-void initResize(TransInfo *t)
+void initResize(TransInfo *t, float mouse_dir_constraint[3])
{
t->mode = TFM_RESIZE;
t->transform = applyResize;
t->tsnap.applySnap = ApplySnapResize;
t->tsnap.distance = ResizeBetween;
- initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
+ if (is_zero_v3(mouse_dir_constraint)) {
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
+ }
+ else {
+ int mval_start[2], mval_end[2];
+ float mval_dir[3], t_mval[2];
+ float viewmat[3][3];
+
+ copy_m3_m4(viewmat, t->viewmat);
+ mul_v3_m3v3(mval_dir, viewmat, mouse_dir_constraint);
+ normalize_v2(mval_dir);
+ if (is_zero_v2(mval_dir)) {
+ /* The screen space direction is orthogonal to the view.
+ * Fall back to constraining on the Y axis. */
+ mval_dir[0] = 0;
+ mval_dir[1] = 1;
+ }
+
+ mval_start[0] = t->center2d[0];
+ mval_start[1] = t->center2d[1];
+
+ t_mval[0] = t->mval[0] - mval_start[0];
+ t_mval[1] = t->mval[1] - mval_start[1];
+ project_v2_v2v2(mval_dir, t_mval, mval_dir);
+
+ mval_end[0] = t->center2d[0] + mval_dir[0];
+ mval_end[1] = t->center2d[1] + mval_dir[1];
+
+ setCustomPoints(t, &t->mouse, mval_end, mval_start);
+
+ initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO);
+ }
t->flag |= T_NULL_ONE;
t->num.val_flag[0] |= NUM_NULL_ONE;
@@ -236,4 +267,5 @@ void initResize(TransInfo *t)
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_GLOBAL);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c
index bfbdaa389f4..e8ef71a6639 100644
--- a/source/blender/editors/transform/transform_mode_rotate.c
+++ b/source/blender/editors/transform/transform_mode_rotate.c
@@ -363,4 +363,5 @@ void initRotation(TransInfo *t)
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c
index 018725ec6dd..9369cb2e62b 100644
--- a/source/blender/editors/transform/transform_mode_shear.c
+++ b/source/blender/editors/transform/transform_mode_shear.c
@@ -199,7 +199,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
char str[UI_MAX_DRAW_STR];
const bool is_local_center = transdata_check_local_center(t, t->around);
- value = t->values[0];
+ value = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &value);
@@ -289,4 +289,5 @@ void initShear(TransInfo *t)
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c
index b96b8103392..01dd1b701a5 100644
--- a/source/blender/editors/transform/transform_mode_shrink_fatten.c
+++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c
@@ -110,7 +110,7 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
size_t ofs = 0;
UnitSettings *unit = &t->scene->unit;
- distance = t->values[0];
+ distance = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &distance);
@@ -188,7 +188,9 @@ void initShrinkFatten(TransInfo *t)
{
/* If not in mesh edit mode, fallback to Resize. */
if ((t->flag & T_EDIT) == 0 || (t->obedit_type != OB_MESH)) {
- initResize(t);
+ float no_mouse_dir_constraint[3];
+ zero_v3(no_mouse_dir_constraint);
+ initResize(t, no_mouse_dir_constraint);
}
else {
t->mode = TFM_SHRINKFATTEN;
@@ -214,4 +216,5 @@ void initShrinkFatten(TransInfo *t)
}
}
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c
index 236c9024201..f5e502fed4f 100644
--- a/source/blender/editors/transform/transform_mode_skin_resize.c
+++ b/source/blender/editors/transform/transform_mode_skin_resize.c
@@ -107,6 +107,7 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
}
else {
copy_v3_fl(t->values_final, t->values[0]);
+ add_v3_v3(t->values_final, t->values_modal_offset);
transform_snap_increment(t, t->values_final);
@@ -179,4 +180,5 @@ void initSkinResize(TransInfo *t)
t->num.unit_type[1] = B_UNIT_NONE;
t->num.unit_type[2] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_tilt.c b/source/blender/editors/transform/transform_mode_tilt.c
index b48f474e16e..6451a7d77d5 100644
--- a/source/blender/editors/transform/transform_mode_tilt.c
+++ b/source/blender/editors/transform/transform_mode_tilt.c
@@ -52,7 +52,7 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
float final;
- final = t->values[0];
+ final = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &final);
@@ -111,4 +111,5 @@ void initTilt(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_timescale.c b/source/blender/editors/transform/transform_mode_timescale.c
index 0a7ae54982e..c198f235cf8 100644
--- a/source/blender/editors/transform/transform_mode_timescale.c
+++ b/source/blender/editors/transform/transform_mode_timescale.c
@@ -151,4 +151,5 @@ void initTimeScale(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_timeslide.c b/source/blender/editors/transform/transform_mode_timeslide.c
index 5cc53eb08ce..98abab0fd6b 100644
--- a/source/blender/editors/transform/transform_mode_timeslide.c
+++ b/source/blender/editors/transform/transform_mode_timeslide.c
@@ -232,4 +232,5 @@ void initTimeSlide(TransInfo *t)
/* No time unit supporting frames currently... */
t->num.unit_type[0] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c
index 294040946bd..84ca5d3ae54 100644
--- a/source/blender/editors/transform/transform_mode_timetranslate.c
+++ b/source/blender/editors/transform/transform_mode_timetranslate.c
@@ -62,27 +62,28 @@ static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR])
float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival;
float val = ival + t->values_final[0];
- float snap_val = val;
- snapFrameTransform(t, autosnap, ival, val, &snap_val);
+ snapFrameTransform(t, autosnap, ival, val, &val);
+ float delta_x = val - ival;
if (ELEM(autosnap, SACTSNAP_SECOND, SACTSNAP_TSTEP)) {
/* Convert to seconds. */
const Scene *scene = t->scene;
const double secf = FPS;
- snap_val /= secf;
+ delta_x /= secf;
+ val /= secf;
}
if (autosnap == SACTSNAP_FRAME) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", snap_val, val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", delta_x, val);
}
else if (autosnap == SACTSNAP_SECOND) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", snap_val, val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", delta_x, val);
}
else if (autosnap == SACTSNAP_TSTEP) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", snap_val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", delta_x);
}
else {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", snap_val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", delta_x);
}
}
@@ -157,4 +158,5 @@ void initTimeTranslate(TransInfo *t)
/* No time unit supporting frames currently... */
t->num.unit_type[0] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_tosphere.c b/source/blender/editors/transform/transform_mode_tosphere.c
index bfc85b2fe44..2062f78c326 100644
--- a/source/blender/editors/transform/transform_mode_tosphere.c
+++ b/source/blender/editors/transform/transform_mode_tosphere.c
@@ -194,7 +194,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -277,4 +277,5 @@ void initToSphere(TransInfo *t)
to_sphere_radius_update(t);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c
index aa8b0783d0a..ddffc4f8438 100644
--- a/source/blender/editors/transform/transform_mode_trackball.c
+++ b/source/blender/editors/transform/transform_mode_trackball.c
@@ -218,4 +218,5 @@ void initTrackball(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 82574cffb82..b8b043c650f 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -225,11 +225,12 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
if (t->spacetype == SPACE_GRAPH) {
/* WORKAROUND:
* Special case where snapping is done in #recalData.
- * Update the header based on the first element. */
+ * Update the header based on the #center_local. */
const short autosnap = getAnimEdit_SnapMode(t);
- float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival;
+ float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->center_local[0];
float val = ival + dvec[0];
- snapFrameTransform(t, autosnap, ival, val, &dvec[0]);
+ snapFrameTransform(t, autosnap, ival, val, &val);
+ dvec[0] = val - ival;
}
if (t->con.mode & CON_APPLY) {
@@ -403,7 +404,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
* since re-applying translation without rotation removes rotation. */
}
else {
- /* When transforming data that it's self stores rotation (objects, bones etc),
+ /* When transforming data that itself stores rotation (objects, bones etc),
* apply rotation if it was applied (with the snap normal) previously.
* This is needed because failing to rotate will leave the rotation at the last
* value used before snapping was disabled. */
@@ -579,4 +580,5 @@ void initTranslation(TransInfo *t)
t->custom.mode.data = custom_data;
t->custom.mode.use_free = true;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c
index def5f911c6f..48a8fcf60eb 100644
--- a/source/blender/editors/transform/transform_mode_vert_slide.c
+++ b/source/blender/editors/transform/transform_mode_vert_slide.c
@@ -582,7 +582,7 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
- final = t->values[0];
+ final = t->values[0] + t->values_modal_offset[0];
applySnapping(t, &final);
if (!validSnap(t)) {
@@ -687,4 +687,5 @@ void initVertSlide(TransInfo *t)
{
initVertSlide_ex(t, false, false, true);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 3a4a9342e18..80feb934f1a 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -59,6 +59,7 @@ typedef struct TransformModeItem {
void (*opfunc)(wmOperatorType *);
} TransformModeItem;
+static const float VecZero[3] = {0, 0, 0};
static const float VecOne[3] = {1, 1, 1};
static const char OP_TRANSLATION[] = "TRANSFORM_OT_translate";
@@ -77,6 +78,7 @@ static const char OP_BONE_SIZE[] = "TRANSFORM_OT_bbone_resize";
static const char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide";
static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide";
static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
+static const char OP_VERT_CREASE[] = "TRANSFORM_OT_vert_crease";
static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight";
static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide";
static const char OP_NORMAL_ROTATION[] = "TRANSFORM_OT_rotate_normal";
@@ -97,6 +99,7 @@ static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot);
+static void TRANSFORM_OT_vert_crease(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot);
static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot);
@@ -117,7 +120,8 @@ static TransformModeItem transform_modes[] = {
{OP_BONE_SIZE, TFM_BONESIZE, TRANSFORM_OT_bbone_resize},
{OP_EDGE_SLIDE, TFM_EDGE_SLIDE, TRANSFORM_OT_edge_slide},
{OP_VERT_SLIDE, TFM_VERT_SLIDE, TRANSFORM_OT_vert_slide},
- {OP_EDGE_CREASE, TFM_CREASE, TRANSFORM_OT_edge_crease},
+ {OP_EDGE_CREASE, TFM_EDGE_CREASE, TRANSFORM_OT_edge_crease},
+ {OP_VERT_CREASE, TFM_VERT_CREASE, TRANSFORM_OT_vert_crease},
{OP_EDGE_BWEIGHT, TFM_BWEIGHT, TRANSFORM_OT_edge_bevelweight},
{OP_SEQ_SLIDE, TFM_SEQ_SLIDE, TRANSFORM_OT_seq_slide},
{OP_NORMAL_ROTATION, TFM_NORMAL_ROTATION, TRANSFORM_OT_rotate_normal},
@@ -138,7 +142,8 @@ const EnumPropertyItem rna_enum_transform_mode_types[] = {
{TFM_TILT, "TILT", 0, "Tilt", ""},
{TFM_TRACKBALL, "TRACKBALL", 0, "Trackball", ""},
{TFM_PUSHPULL, "PUSHPULL", 0, "Push/Pull", ""},
- {TFM_CREASE, "CREASE", 0, "Crease", ""},
+ {TFM_EDGE_CREASE, "CREASE", 0, "Crease", ""},
+ {TFM_VERT_CREASE, "VERTEX_CREASE", 0, "Vertex Crease", ""},
{TFM_MIRROR, "MIRROR", 0, "Mirror", ""},
{TFM_BONESIZE, "BONE_SIZE", 0, "Bone Size", ""},
{TFM_BONE_ENVELOPE, "BONE_ENVELOPE", 0, "Bone Envelope", ""},
@@ -783,6 +788,19 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
RNA_def_float_vector(
ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Scale", "", -FLT_MAX, FLT_MAX);
+ PropertyRNA *prop;
+ prop = RNA_def_float_vector(ot->srna,
+ "mouse_dir_constraint",
+ 3,
+ VecZero,
+ -FLT_MAX,
+ FLT_MAX,
+ "Mouse Directional Constraint",
+ "",
+ -FLT_MAX,
+ FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
WM_operatortype_props_advanced_begin(ot);
Transform_Properties(ot,
@@ -1182,6 +1200,29 @@ static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
Transform_Properties(ot, P_SNAP);
}
+static void TRANSFORM_OT_vert_crease(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Crease";
+ ot->description = "Change the crease of vertices";
+ ot->idname = OP_VERT_CREASE;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* api callbacks */
+ ot->invoke = transform_invoke;
+ ot->exec = transform_exec;
+ ot->modal = transform_modal;
+ ot->cancel = transform_cancel;
+ ot->poll = ED_operator_editmesh;
+ ot->poll_property = transform_poll_property;
+
+ RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
+
+ WM_operatortype_props_advanced_begin(ot);
+
+ Transform_Properties(ot, P_SNAP);
+}
+
static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 1e3acdf1071..5ac5bccd69c 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -30,6 +30,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_sequence_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
@@ -52,6 +53,8 @@
#include "ED_armature.h"
+#include "SEQ_select.h"
+
#include "transform.h"
#include "transform_orientations.h"
@@ -312,11 +315,6 @@ bool createSpaceNormal(float mat[3][3], const float normal[3])
return true;
}
-/**
- * \note To recreate an orientation from the matrix:
- * - (plane == mat[1])
- * - (normal == mat[2])
- */
bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const float tangent[3])
{
if (normalize_v3_v3(mat[2], normal) == 0.0f) {
@@ -500,15 +498,6 @@ void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3
scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, r_mat);
}
-/**
- * \note The resulting matrix may not be orthogonal,
- * callers that depend on `r_mat` to be orthogonal should use #orthogonalize_m3.
- *
- * A non orthogonal matrix may be returned when:
- * - #V3D_ORIENT_GIMBAL the result won't be orthogonal unless the object has no rotation.
- * - #V3D_ORIENT_LOCAL may contain shear from non-uniform scale in parent/child relationships.
- * - #V3D_ORIENT_CUSTOM may have been created from #V3D_ORIENT_LOCAL.
- */
short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
ViewLayer *view_layer,
const View3D *v3d,
@@ -521,8 +510,19 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
{
switch (orientation_index) {
case V3D_ORIENT_GIMBAL: {
- if (ob && gimbal_axis(ob, r_mat)) {
- break;
+
+ if (ob) {
+ if (ob->mode & OB_MODE_POSE) {
+ const bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
+ if (pchan && gimbal_axis_pose(ob, pchan, r_mat)) {
+ break;
+ }
+ }
+ else {
+ if (gimbal_axis_object(ob, r_mat)) {
+ break;
+ }
+ }
}
/* If not gimbal, fall through to normal. */
ATTR_FALLTHROUGH;
@@ -588,9 +588,6 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
return orientation_index;
}
-/* Sets the matrix of the specified space orientation.
- * If the matrix cannot be obtained, an orientation different from the one
- * informed is returned */
short transform_orientation_matrix_get(bContext *C,
TransInfo *t,
short orient_index,
@@ -602,6 +599,15 @@ short transform_orientation_matrix_get(bContext *C,
return V3D_ORIENT_CUSTOM_MATRIX;
}
+ if (t->spacetype == SPACE_SEQ && t->options & CTX_SEQUENCER_IMAGE) {
+ Scene *scene = t->scene;
+ Sequence *seq = SEQ_select_active_get(scene);
+ if (seq && seq->strip->transform && orient_index == V3D_ORIENT_LOCAL) {
+ axis_angle_to_mat3_single(r_spacemtx, 'Z', seq->strip->transform->rotation);
+ return orient_index;
+ }
+ }
+
Object *ob = CTX_data_active_object(C);
Object *obedit = CTX_data_edit_object(C);
Scene *scene = t->scene;
@@ -1218,7 +1224,7 @@ int getTransformOrientation_ex(ViewLayer *view_layer,
float imat[3][3], mat[3][3];
bool ok = false;
- if (activeOnly && (pchan = BKE_pose_channel_active(ob))) {
+ if (activeOnly && (pchan = BKE_pose_channel_active_if_layer_visible(ob))) {
add_v3_v3(normal, pchan->pose_mat[2]);
add_v3_v3(plane, pchan->pose_mat[1]);
ok = true;
diff --git a/source/blender/editors/transform/transform_orientations.h b/source/blender/editors/transform/transform_orientations.h
index 1da369c8307..dd2d5bc86c5 100644
--- a/source/blender/editors/transform/transform_orientations.h
+++ b/source/blender/editors/transform/transform_orientations.h
@@ -25,26 +25,37 @@
struct TransInfo;
+/**
+ * Sets the matrix of the specified space orientation.
+ * If the matrix cannot be obtained, an orientation different from the one informed is returned.
+ */
short transform_orientation_matrix_get(struct bContext *C,
struct TransInfo *t,
short orient_index,
const float custom[3][3],
float r_spacemtx[3][3]);
-const char *transform_orientations_spacename_get(struct TransInfo *t, const short orient_type);
-void transform_orientations_current_set(struct TransInfo *t, const short orient_index);
+const char *transform_orientations_spacename_get(struct TransInfo *t, short orient_type);
+void transform_orientations_current_set(struct TransInfo *t, short orient_index);
-/* Those two fill in mat and return non-zero on success */
+/**
+ * Those two fill in mat and return non-zero on success.
+ */
bool transform_orientations_create_from_axis(float mat[3][3],
const float x[3],
const float y[3],
const float z[3]);
bool createSpaceNormal(float mat[3][3], const float normal[3]);
+/**
+ * \note To recreate an orientation from the matrix:
+ * - (plane == mat[1])
+ * - (normal == mat[2])
+ */
bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const float tangent[3]);
struct TransformOrientation *addMatrixSpace(struct bContext *C,
float mat[3][3],
const char *name,
- const bool overwrite);
+ bool overwrite);
void applyTransformOrientation(const struct TransformOrientation *ts,
float r_mat[3][3],
char r_name[64]);
@@ -64,5 +75,5 @@ int getTransformOrientation_ex(ViewLayer *view_layer,
struct Object *obedit,
float normal[3],
float plane[3],
- const short around);
+ short around);
int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3]);
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 39a70f5477e..40be8e6e641 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -48,6 +48,7 @@
#include "ED_node.h"
#include "ED_transform_snap_object_context.h"
#include "ED_uvedit.h"
+#include "ED_view3d.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -199,7 +200,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
bool draw_target = (t->tsnap.status & TARGET_INIT) &&
- (t->scene->toolsettings->snap_mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR);
+ (t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR);
if (draw_target || validSnap(t)) {
const float *loc_cur = NULL;
@@ -247,7 +248,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
loc_cur = t->tsnap.snapPoint;
}
- ED_gizmotypes_snap_3d_draw_util(
+ ED_view3d_cursor_snap_draw_util(
rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem);
GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
@@ -374,6 +375,8 @@ void applyProject(TransInfo *t)
if (ED_transform_snap_object_project_view3d(
t->tsnap.object_context,
t->depsgraph,
+ t->region,
+ t->view,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = t->tsnap.modeSelect,
@@ -480,7 +483,7 @@ void applySnapping(TransInfo *t, float *vec)
}
if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) {
- /* The snap has already been resolved for each transdata. */
+ /* A similar snap will be applied to each transdata in `applyProject`. */
return;
}
@@ -496,13 +499,15 @@ void applySnapping(TransInfo *t, float *vec)
/* Time base quirky code to go around find-nearest slowness. */
/* TODO: add exception for object mode, no need to slow it down then. */
if (current - t->tsnap.last >= 0.01) {
- t->tsnap.calcSnap(t, vec);
+ if (t->tsnap.calcSnap) {
+ t->tsnap.calcSnap(t, vec);
+ }
if (t->tsnap.targetSnap) {
t->tsnap.targetSnap(t);
}
- }
- t->tsnap.last = current;
+ t->tsnap.last = current;
+ }
if (validSnap(t)) {
t->tsnap.applySnap(t, vec);
@@ -571,70 +576,61 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data))
return true;
}
-static void initSnappingMode(TransInfo *t)
+static short snap_mode_from_scene(TransInfo *t)
{
ToolSettings *ts = t->settings;
- /* All obedit types will match. */
- const int obedit_type = t->obedit_type;
- ViewLayer *view_layer = t->view_layer;
- Base *base_act = view_layer->basact;
+ short r_snap_mode = SCE_SNAP_MODE_INCREMENT;
if (t->spacetype == SPACE_NODE) {
- /* force project off when not supported */
- t->tsnap.project = 0;
-
- t->tsnap.mode = ts->snap_node_mode;
+ r_snap_mode = ts->snap_node_mode;
}
else if (t->spacetype == SPACE_IMAGE) {
- /* force project off when not supported */
- t->tsnap.project = 0;
-
- t->tsnap.mode = ts->snap_uv_mode;
- if ((t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) &&
+ r_snap_mode = ts->snap_uv_mode;
+ if ((r_snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) &&
(t->mode == TFM_TRANSLATION)) {
- t->tsnap.mode &= ~SCE_SNAP_MODE_INCREMENT;
- t->tsnap.mode |= SCE_SNAP_MODE_GRID;
+ r_snap_mode &= ~SCE_SNAP_MODE_INCREMENT;
+ r_snap_mode |= SCE_SNAP_MODE_GRID;
}
}
else if (t->spacetype == SPACE_SEQ) {
- t->tsnap.mode = SEQ_tool_settings_snap_mode_get(t->scene);
+ r_snap_mode = SEQ_tool_settings_snap_mode_get(t->scene);
}
else if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) {
- /* force project off when not supported */
- if ((ts->snap_mode & SCE_SNAP_MODE_FACE) == 0) {
- t->tsnap.project = 0;
- }
-
- t->tsnap.mode = ts->snap_mode;
- if ((t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) &&
- (t->mode == TFM_TRANSLATION)) {
- /* Special case in which snap to increments is transformed to snap to grid. */
- t->tsnap.mode &= ~SCE_SNAP_MODE_INCREMENT;
- t->tsnap.mode |= SCE_SNAP_MODE_GRID;
+ /* All obedit types will match. */
+ const int obedit_type = t->obedit_type;
+ if ((t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) ||
+ ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL, -1)) {
+ r_snap_mode = ts->snap_mode;
+ if ((r_snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) &&
+ (t->mode == TFM_TRANSLATION)) {
+ /* Special case in which snap to increments is transformed to snap to grid. */
+ r_snap_mode &= ~SCE_SNAP_MODE_INCREMENT;
+ r_snap_mode |= SCE_SNAP_MODE_GRID;
+ }
}
}
- else if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) {
+ else if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) {
/* No incremental snapping. */
- t->tsnap.mode = 0;
- }
- else {
- /* Fallback. */
- t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
+ r_snap_mode = 0;
}
- if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) {
- /* Only 3D view or UV. */
- /* Not with camera selected in camera view. */
+ return r_snap_mode;
+}
- setSnappingCallback(t);
+static short snap_select_type_get(TransInfo *t)
+{
+ short r_snap_select = SNAP_ALL;
+ ViewLayer *view_layer = t->view_layer;
+ Base *base_act = view_layer->basact;
+ if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) {
+ const int obedit_type = t->obedit_type;
if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) {
/* In "Edit Strokes" mode,
* snap tool can perform snap to selected or active objects (see T49632)
* TODO: perform self snap in gpencil_strokes.
*
* When we're moving the origins, allow snapping onto our own geometry (see T69132). */
- t->tsnap.modeSelect = SNAP_ALL;
}
else if ((obedit_type != -1) &&
ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) {
@@ -643,36 +639,50 @@ static void initSnappingMode(TransInfo *t)
if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
/* Exclude editmesh if using proportional edit */
- t->tsnap.modeSelect = SNAP_NOT_ACTIVE;
+ r_snap_select = SNAP_NOT_ACTIVE;
}
- else {
- t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_ACTIVE;
+ else if (!t->tsnap.snap_self) {
+ r_snap_select = SNAP_NOT_ACTIVE;
}
}
else if ((obedit_type == -1) && base_act && base_act->object &&
(base_act->object->mode & OB_MODE_PARTICLE_EDIT)) {
/* Particles edit mode. */
- t->tsnap.modeSelect = SNAP_ALL;
}
else if (obedit_type == -1) {
/* Object mode */
- t->tsnap.modeSelect = SNAP_NOT_SELECTED;
- }
- else {
- /* Increment if snap is not possible */
- t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
+ r_snap_select = SNAP_NOT_SELECTED;
}
}
else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
- setSnappingCallback(t);
- t->tsnap.modeSelect = SNAP_NOT_SELECTED;
+ r_snap_select = SNAP_NOT_SELECTED;
+ }
+
+ return r_snap_select;
+}
+
+static void initSnappingMode(TransInfo *t)
+{
+ ToolSettings *ts = t->settings;
+ t->tsnap.mode = snap_mode_from_scene(t);
+ t->tsnap.modeSelect = snap_select_type_get(t);
+
+ if ((t->spacetype != SPACE_VIEW3D) || !(ts->snap_mode & SCE_SNAP_MODE_FACE)) {
+ /* Force project off when not supported. */
+ t->tsnap.project = 0;
+ }
+
+ if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE, SPACE_SEQ)) {
+ /* Not with camera selected in camera view. */
+ if (!(t->options & CTX_CAMERA)) {
+ setSnappingCallback(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);
+ t->tsnap.object_context = ED_transform_snap_object_context_create(t->scene, 0);
if (t->data_type == TC_MESH_VERTS) {
/* Ignore elements being transformed. */
@@ -683,6 +693,15 @@ static void initSnappingMode(TransInfo *t)
bm_face_is_snap_target,
POINTER_FROM_UINT((BM_ELEM_SELECT | BM_ELEM_HIDDEN)));
}
+ else {
+ /* Ignore hidden geometry in the general case. */
+ ED_transform_snap_object_context_set_editmesh_callbacks(
+ t->tsnap.object_context,
+ (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
+ (bool (*)(BMEdge *, void *))BM_elem_cb_check_hflag_disabled,
+ (bool (*)(BMFace *, void *))BM_elem_cb_check_hflag_disabled,
+ POINTER_FROM_UINT(BM_ELEM_HIDDEN));
+ }
}
}
else if (t->spacetype == SPACE_SEQ) {
@@ -700,33 +719,39 @@ void initSnapping(TransInfo *t, wmOperator *op)
resetSnapping(t);
/* if snap property exists */
- if (op && RNA_struct_find_property(op->ptr, "snap") &&
- RNA_struct_property_is_set(op->ptr, "snap")) {
- if (RNA_boolean_get(op->ptr, "snap")) {
+ PropertyRNA *prop;
+ if (op && (prop = RNA_struct_find_property(op->ptr, "snap")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop)) {
t->modifiers |= MOD_SNAP;
- if (RNA_struct_property_is_set(op->ptr, "snap_target")) {
- snap_target = RNA_enum_get(op->ptr, "snap_target");
+ if ((prop = RNA_struct_find_property(op->ptr, "snap_target")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ snap_target = RNA_property_enum_get(op->ptr, prop);
}
- if (RNA_struct_property_is_set(op->ptr, "snap_point")) {
- RNA_float_get_array(op->ptr, "snap_point", t->tsnap.snapPoint);
+ if ((prop = RNA_struct_find_property(op->ptr, "snap_point")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, t->tsnap.snapPoint);
t->tsnap.status |= SNAP_FORCED | POINT_INIT;
}
/* snap align only defined in specific cases */
- if (RNA_struct_find_property(op->ptr, "snap_align")) {
- t->tsnap.align = RNA_boolean_get(op->ptr, "snap_align");
+ if ((prop = RNA_struct_find_property(op->ptr, "snap_align")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ t->tsnap.align = RNA_property_boolean_get(op->ptr, prop);
RNA_float_get_array(op->ptr, "snap_normal", t->tsnap.snapNormal);
normalize_v3(t->tsnap.snapNormal);
}
- if (RNA_struct_find_property(op->ptr, "use_snap_project")) {
- t->tsnap.project = RNA_boolean_get(op->ptr, "use_snap_project");
+ if ((prop = RNA_struct_find_property(op->ptr, "use_snap_project")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ t->tsnap.project = RNA_property_boolean_get(op->ptr, prop);
}
- if (RNA_struct_find_property(op->ptr, "use_snap_self")) {
- t->tsnap.snap_self = RNA_boolean_get(op->ptr, "use_snap_self");
+ if ((prop = RNA_struct_find_property(op->ptr, "use_snap_self")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ t->tsnap.snap_self = RNA_property_boolean_get(op->ptr, prop);
}
}
}
@@ -769,8 +794,15 @@ static void setSnappingCallback(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
t->tsnap.calcSnap = snap_calc_view3d_fn;
}
- else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) {
- t->tsnap.calcSnap = snap_calc_uv_fn;
+ else if (t->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = t->area->spacedata.first;
+ Object *obact = t->view_layer->basact ? t->view_layer->basact->object : NULL;
+
+ const bool is_uv_editor = sima->mode == SI_MODE_UV;
+ const bool has_edit_object = obact && BKE_object_is_in_editmode(obact);
+ if (is_uv_editor && has_edit_object) {
+ t->tsnap.calcSnap = snap_calc_uv_fn;
+ }
}
else if (t->spacetype == SPACE_NODE) {
t->tsnap.calcSnap = snap_calc_node_fn;
@@ -916,8 +948,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
mval[0] = t->mval[0];
mval[1] = t->mval[1];
- if (t->tsnap.mode & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
- SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ if (t->tsnap.mode & SCE_SNAP_MODE_GEOM) {
zero_v3(no); /* objects won't set this */
snap_elem = snapObjectsTransform(t, mval, &dist_px, loc, no);
found = snap_elem != 0;
@@ -946,7 +977,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
{
- BLI_assert(t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH);
+ BLI_assert(t->spacetype == SPACE_IMAGE);
if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
float co[2];
@@ -1242,10 +1273,12 @@ short snapObjectsTransform(
TransInfo *t, const float mval[2], float *dist_px, float r_loc[3], float r_no[3])
{
float *target = (t->tsnap.status & TARGET_INIT) ? t->tsnap.snapTarget : t->center_global;
- return ED_transform_snap_object_project_view3d_ex(
+ return ED_transform_snap_object_project_view3d(
t->tsnap.object_context,
t->depsgraph,
- t->settings->snap_mode,
+ t->region,
+ t->view,
+ t->tsnap.mode,
&(const struct SnapObjectParams){
.snap_select = t->tsnap.modeSelect,
.edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
@@ -1256,10 +1289,7 @@ short snapObjectsTransform(
target,
dist_px,
r_loc,
- r_no,
- NULL,
- NULL,
- NULL);
+ r_no);
}
/** \} */
@@ -1280,6 +1310,8 @@ bool peelObjectsTransform(TransInfo *t,
ED_transform_snap_object_project_all_view3d_ex(
t->tsnap.object_context,
t->depsgraph,
+ t->region,
+ t->view,
&(const struct SnapObjectParams){
.snap_select = t->tsnap.modeSelect,
.edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
@@ -1320,7 +1352,7 @@ bool peelObjectsTransform(TransInfo *t,
}
}
}
- /* in this case has only one hit. treat as raycast */
+ /* In this case has only one hit. treat as ray-cast. */
if (hit_max == NULL) {
hit_max = hit_min;
}
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index ed7f93304bc..389c1441db1 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -27,7 +27,7 @@
bool peelObjectsTransform(struct TransInfo *t,
const float mval[2],
- const bool use_peel_object,
+ bool use_peel_object,
/* return args */
float r_loc[3],
float r_no[3],
@@ -76,19 +76,31 @@ void removeSnapPoint(TransInfo *t);
float transform_snap_distance_len_squared_fn(TransInfo *t, const float p1[3], const float p2[3]);
/* transform_snap_sequencer.c */
+
struct TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t);
void transform_snap_sequencer_data_free(struct TransSeqSnapData *data);
bool transform_snap_sequencer_calc(struct TransInfo *t);
void transform_snap_sequencer_apply_translate(TransInfo *t, float *vec);
/* transform_snap_animation.c */
+
+/**
+ * This function returns the snapping 'mode' for Animation Editors only.
+ * We cannot use the standard snapping due to NLA-strip scaling complexities.
+ *
+ * TODO: these modifier checks should be accessible from the key-map.
+ */
short getAnimEdit_SnapMode(TransInfo *t);
void snapFrameTransform(TransInfo *t,
- const eAnimEdit_AutoSnap autosnap,
- const float val_initial,
- const float val_final,
+ eAnimEdit_AutoSnap autosnap,
+ float val_initial,
+ float val_final,
float *r_val_final);
+/**
+ * This function is used by Animation Editor specific transform functions to do
+ * the Snap Keyframe to Nearest Frame/Marker
+ */
void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
- const eAnimEdit_AutoSnap autosnap,
+ eAnimEdit_AutoSnap autosnap,
float *r_val_final);
diff --git a/source/blender/editors/transform/transform_snap_animation.c b/source/blender/editors/transform/transform_snap_animation.c
index 08335924ddf..6ca16c171e2 100644
--- a/source/blender/editors/transform/transform_snap_animation.c
+++ b/source/blender/editors/transform/transform_snap_animation.c
@@ -38,12 +38,6 @@
/** \name Snapping in Anim Editors
* \{ */
-/**
- * This function returns the snapping 'mode' for Animation Editors only.
- * We cannot use the standard snapping due to NLA-strip scaling complexities.
- *
- * TODO: these modifier checks should be accessible from the key-map.
- */
short getAnimEdit_SnapMode(TransInfo *t)
{
short autosnap = SACTSNAP_OFF;
@@ -56,8 +50,10 @@ short getAnimEdit_SnapMode(TransInfo *t)
}
}
else if (t->spacetype == SPACE_GRAPH) {
+ if ((t->mode == TFM_TRANSLATION) && activeSnap(t)) {
+ return autosnap;
+ }
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
-
if (sipo) {
autosnap = sipo->autosnap;
}
@@ -126,9 +122,6 @@ void snapFrameTransform(TransInfo *t,
}
}
-/* This function is used by Animation Editor specific transform functions to do
- * the Snap Keyframe to Nearest Frame/Marker
- */
void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
const eAnimEdit_AutoSnap autosnap,
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 811f30c96e5..9dc8b6cf69d 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -69,17 +69,6 @@ enum eViewProj {
VIEW_PROJ_PERSP = -1,
};
-typedef struct SnapData {
- float mval[2];
- float pmat[4][4]; /* perspective matrix */
- float win_size[2]; /* win x and y */
- enum eViewProj view_proj;
- float clip_plane[MAX_CLIPPLANE_LEN][4];
- short clip_plane_len;
- short snap_to_flag;
- bool has_occlusion_plane; /* Ignore plane of occlusion in curves. */
-} SnapData;
-
typedef struct SnapObjectData {
enum {
SNAP_MESH = 1,
@@ -113,14 +102,6 @@ struct SnapObjectContext {
int flag;
- /* Optional: when performing screen-space projection.
- * otherwise this doesn't take viewport into account. */
- bool use_v3d;
- struct {
- const struct View3D *v3d;
- const struct ARegion *region;
- } v3d_data;
-
/* Object -> SnapObjectData map */
struct {
GHash *object_map;
@@ -138,6 +119,21 @@ struct SnapObjectContext {
void *user_data;
} edit_mesh;
} callbacks;
+
+ struct {
+ Depsgraph *depsgraph;
+ const ARegion *region;
+ const View3D *v3d;
+
+ float mval[2];
+ float pmat[4][4]; /* perspective matrix */
+ float win_size[2]; /* win x and y */
+ enum eViewProj view_proj;
+ float clip_plane[MAX_CLIPPLANE_LEN][4];
+ short clip_plane_len;
+ short snap_to_flag;
+ bool has_occlusion_plane; /* Ignore plane of occlusion in curves. */
+ } runtime;
};
/** \} */
@@ -150,26 +146,28 @@ struct SnapObjectContext {
* If NULL the BMesh should be used. */
static Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide)
{
- Mesh *me_eval = ob_eval->data;
+ Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
bool use_hide = false;
if (BKE_object_is_in_editmode(ob_eval)) {
if (edit_mode_type == SNAP_GEOM_EDIT) {
return NULL;
}
- BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval);
- if ((edit_mode_type == SNAP_GEOM_FINAL) && em_eval->mesh_eval_final) {
- if (em_eval->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval);
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
+
+ if ((edit_mode_type == SNAP_GEOM_FINAL) && editmesh_eval_final) {
+ if (editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
return NULL;
}
- me_eval = em_eval->mesh_eval_final;
+ me_eval = editmesh_eval_final;
use_hide = true;
}
- else if ((edit_mode_type == SNAP_GEOM_CAGE) && em_eval->mesh_eval_cage) {
- if (em_eval->mesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ else if ((edit_mode_type == SNAP_GEOM_CAGE) && editmesh_eval_cage) {
+ if (editmesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
return NULL;
}
- me_eval = em_eval->mesh_eval_cage;
+ me_eval = editmesh_eval_cage;
use_hide = true;
}
}
@@ -322,12 +320,14 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx,
if (sod->treedata_mesh.tree == NULL) {
sod->treedata_mesh.vert = me_eval->mvert;
+ sod->treedata_mesh.vert_normals = BKE_mesh_vertex_normals_ensure(me_eval);
sod->treedata_mesh.loop = me_eval->mloop;
sod->treedata_mesh.looptri = BKE_mesh_runtime_looptri_ensure(me_eval);
BLI_assert(sod->has_looptris == false);
}
else {
BLI_assert(sod->treedata_mesh.vert != NULL);
+ BLI_assert(sod->treedata_mesh.vert_normals != NULL);
BLI_assert(sod->treedata_mesh.loop != NULL);
BLI_assert(sod->treedata_mesh.looptri != NULL);
sod->has_looptris = true;
@@ -347,12 +347,14 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx,
static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob_eval)
{
- BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval);
- if (em_eval->mesh_eval_final) {
- return &em_eval->mesh_eval_final->runtime;
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval);
+ if (editmesh_eval_final) {
+ return &editmesh_eval_final->runtime;
}
- if (em_eval->mesh_eval_cage) {
- return &em_eval->mesh_eval_cage->runtime;
+
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
+ if (editmesh_eval_cage) {
+ return &editmesh_eval_cage->runtime;
}
return &((Mesh *)ob_eval->data)->runtime;
@@ -446,10 +448,9 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
* \{ */
typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
float obmat[4][4],
- eSnapEditType edit_mode_type,
- bool use_backface_culling,
bool is_object_active,
void *data);
@@ -457,31 +458,26 @@ typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
* Walks through all objects in the scene to create the list of objects to snap.
*/
static void iter_snap_objects(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
const struct SnapObjectParams *params,
IterSnapObjsCallback sob_callback,
void *data)
{
- ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
- const View3D *v3d = sctx->v3d_data.v3d;
+ ViewLayer *view_layer = DEG_get_input_view_layer(sctx->runtime.depsgraph);
const eSnapSelect snap_select = params->snap_select;
- const eSnapEditType edit_mode_type = params->edit_mode_type;
- const bool use_backface_culling = params->use_backface_culling;
Base *base_act = view_layer->basact;
if (snap_select == SNAP_ONLY_ACTIVE) {
- Object *obj_eval = DEG_get_evaluated_object(depsgraph, base_act->object);
- sob_callback(
- sctx, obj_eval, obj_eval->obmat, edit_mode_type, use_backface_culling, true, data);
+ Object *obj_eval = DEG_get_evaluated_object(sctx->runtime.depsgraph, base_act->object);
+ sob_callback(sctx, params, obj_eval, obj_eval->obmat, true, data);
return;
}
for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) {
- if (!BASE_VISIBLE(v3d, base)) {
+ if (!BASE_VISIBLE(sctx->runtime.v3d, base)) {
continue;
}
- if (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE) {
+ if ((snap_select == SNAP_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
/* pass */
}
else if (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) {
@@ -489,40 +485,33 @@ static void iter_snap_objects(SnapObjectContext *sctx,
}
const bool is_object_active = (base == base_act);
- if (snap_select == SNAP_NOT_SELECTED) {
+ if (snap_select == SNAP_NOT_ACTIVE) {
+ if (is_object_active) {
+ continue;
+ }
+ }
+ else if (snap_select == SNAP_NOT_SELECTED) {
if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) {
continue;
}
}
- else if (snap_select == SNAP_NOT_ACTIVE) {
- if (is_object_active) {
+ else if (snap_select == SNAP_SELECTABLE) {
+ if (!(base->flag & BASE_SELECTABLE)) {
continue;
}
}
- Object *obj_eval = DEG_get_evaluated_object(depsgraph, base->object);
+ Object *obj_eval = DEG_get_evaluated_object(sctx->runtime.depsgraph, base->object);
if (obj_eval->transflag & OB_DUPLI || BKE_object_has_geometry_set_instances(obj_eval)) {
- ListBase *lb = object_duplilist(depsgraph, sctx->scene, obj_eval);
+ ListBase *lb = object_duplilist(sctx->runtime.depsgraph, sctx->scene, obj_eval);
for (DupliObject *dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
BLI_assert(DEG_is_evaluated_object(dupli_ob->ob));
- sob_callback(sctx,
- dupli_ob->ob,
- dupli_ob->mat,
- edit_mode_type,
- use_backface_culling,
- is_object_active,
- data);
+ sob_callback(sctx, params, dupli_ob->ob, dupli_ob->mat, is_object_active, data);
}
free_object_duplilist(lb);
}
- sob_callback(sctx,
- obj_eval,
- obj_eval->obmat,
- edit_mode_type,
- use_backface_culling,
- is_object_active,
- data);
+ sob_callback(sctx, params, obj_eval, obj_eval->obmat, is_object_active, data);
}
}
@@ -598,15 +587,15 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
struct RayCastAll_Data *data = userdata;
data->raycast_callback(data->bvhdata, index, ray, hit);
if (hit->index != -1) {
- /* get all values in worldspace */
+ /* Get all values in world-space. */
float location[3], normal[3];
float depth;
- /* worldspace location */
+ /* World-space location. */
mul_v3_m4v3(location, (float(*)[4])data->obmat, hit->co);
depth = (hit->dist + data->len_diff) / data->local_scale;
- /* worldspace normal */
+ /* World-space normal. */
copy_v3_v3(normal, hit->no);
mul_m3_v3((float(*)[3])data->timat, normal);
normalize_v3(normal);
@@ -682,6 +671,7 @@ static void editmesh_looptri_raycast_backface_culling_cb(void *userdata,
}
static bool raycastMesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_dir[3],
Object *ob_eval,
@@ -689,7 +679,6 @@ static bool raycastMesh(SnapObjectContext *sctx,
const float obmat[4][4],
const uint ob_index,
bool use_hide,
- bool use_backface_culling,
/* read/write args */
float *ray_depth,
/* return args */
@@ -724,7 +713,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
}
/* Test BoundBox */
- BoundBox *bb = BKE_mesh_boundbox_get(ob_eval);
+ BoundBox *bb = BKE_object_boundbox_get(ob_eval);
if (bb) {
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
if (!isect_ray_aabb_v3_simple(
@@ -791,8 +780,9 @@ static bool raycastMesh(SnapObjectContext *sctx,
ray_normal_local,
0.0f,
&hit,
- use_backface_culling ? mesh_looptri_raycast_backface_culling_cb :
- treedata->raycast_callback,
+ params->use_backface_culling ?
+ mesh_looptri_raycast_backface_culling_cb :
+ treedata->raycast_callback,
treedata) != -1) {
hit.dist += len_diff;
hit.dist /= local_scale;
@@ -800,7 +790,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
*ray_depth = hit.dist;
copy_v3_v3(r_loc, hit.co);
- /* back to worldspace */
+ /* Back to world-space. */
mul_m4_v3(obmat, r_loc);
if (r_no) {
@@ -822,13 +812,13 @@ static bool raycastMesh(SnapObjectContext *sctx,
}
static bool raycastEditMesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_dir[3],
Object *ob_eval,
BMEditMesh *em,
const float obmat[4][4],
const uint ob_index,
- bool use_backface_culling,
/* read/write args */
float *ray_depth,
/* return args */
@@ -961,8 +951,9 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
ray_normal_local,
0.0f,
&hit,
- use_backface_culling ? editmesh_looptri_raycast_backface_culling_cb :
- treedata->raycast_callback,
+ params->use_backface_culling ?
+ editmesh_looptri_raycast_backface_culling_cb :
+ treedata->raycast_callback,
treedata) != -1) {
hit.dist += len_diff;
hit.dist /= local_scale;
@@ -970,7 +961,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
*ray_depth = hit.dist;
copy_v3_v3(r_loc, hit.co);
- /* back to worldspace */
+ /* Back to world-space. */
mul_m4_v3(obmat, r_loc);
if (r_no) {
@@ -1011,15 +1002,12 @@ struct RaycastObjUserData {
};
/**
- * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
- *
* \note Duplicate args here are documented at #snapObjectsRay
*/
static void raycast_obj_fn(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
float obmat[4][4],
- eSnapEditType edit_mode_type,
- bool use_backface_culling,
bool is_object_active,
void *data)
{
@@ -1031,12 +1019,6 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
bool retval = false;
if (use_occlusion_test) {
- if ((edit_mode_type == SNAP_GEOM_EDIT) && sctx->use_v3d &&
- XRAY_FLAG_ENABLED(sctx->v3d_data.v3d)) {
- /* Use of occlude geometry in editing mode disabled. */
- return;
- }
-
if (ELEM(ob_eval->dt, OB_BOUNDBOX, OB_WIRE)) {
/* Do not hit objects that are in wire or bounding box
* display mode. */
@@ -1046,19 +1028,20 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
switch (ob_eval->type) {
case OB_MESH: {
+ const eSnapEditType edit_mode_type = params->edit_mode_type;
bool use_hide = false;
Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
if (me_eval == NULL) {
/* Operators only update the editmesh looptris of the original mesh. */
BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval));
retval = raycastEditMesh(sctx,
+ params,
dt->ray_start,
dt->ray_dir,
ob_eval,
em_orig,
obmat,
ob_index,
- use_backface_culling,
ray_depth,
dt->r_loc,
dt->r_no,
@@ -1067,6 +1050,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
break;
}
retval = raycastMesh(sctx,
+ params,
dt->ray_start,
dt->ray_dir,
ob_eval,
@@ -1074,7 +1058,6 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
obmat,
ob_index,
use_hide,
- use_backface_culling,
ray_depth,
dt->r_loc,
dt->r_no,
@@ -1089,6 +1072,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
if (mesh_eval) {
retval = raycastMesh(sctx,
+ params,
dt->ray_start,
dt->ray_dir,
ob_eval,
@@ -1096,7 +1080,6 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
obmat,
ob_index,
false,
- use_backface_culling,
ray_depth,
dt->r_loc,
dt->r_no,
@@ -1126,7 +1109,6 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
* Walks through all objects in the scene to find the `hit` on object surface.
*
* \param sctx: Snap context to store data.
- * \param params: Snapping behavior.
*
* Read/Write Args
* ---------------
@@ -1146,7 +1128,6 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
* \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
*/
static bool raycastObjects(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_dir[3],
@@ -1162,6 +1143,15 @@ static bool raycastObjects(SnapObjectContext *sctx,
float r_obmat[4][4],
ListBase *r_hit_list)
{
+ const View3D *v3d = sctx->runtime.v3d;
+ if (params->use_occlusion_test && v3d && XRAY_FLAG_ENABLED(v3d)) {
+ /* General testing of occlusion geometry is disabled if the snap is not intended for the edit
+ * cage. */
+ if (params->edit_mode_type == SNAP_GEOM_EDIT) {
+ return false;
+ }
+ }
+
struct RaycastObjUserData data = {
.ray_start = ray_start,
.ray_dir = ray_dir,
@@ -1177,7 +1167,7 @@ static bool raycastObjects(SnapObjectContext *sctx,
.ret = false,
};
- iter_snap_objects(sctx, depsgraph, params, raycast_obj_fn, &data);
+ iter_snap_objects(sctx, params, raycast_obj_fn, &data);
return data.ret;
}
@@ -1211,56 +1201,96 @@ static bool snap_bound_box_check_dist(const float min[3],
return true;
}
-static void cb_mvert_co_get(const int index, const void *user_data, const float **r_co)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks
+ * \{ */
+
+struct Nearest2dUserData;
+
+typedef void (*Nearest2DGetVertCoCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ const float **r_co);
+typedef void (*Nearest2DGetEdgeVertsCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ int r_v_index[2]);
+typedef void (*Nearest2DGetTriVertsCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ int r_v_index[3]);
+/* Equal the previous one */
+typedef void (*Nearest2DGetTriEdgesCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ int r_e_index[3]);
+typedef void (*Nearest2DCopyVertNoCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ float r_no[3]);
+
+typedef struct Nearest2dUserData {
+ Nearest2DGetVertCoCallback get_vert_co;
+ Nearest2DGetEdgeVertsCallback get_edge_verts_index;
+ Nearest2DGetTriVertsCallback get_tri_verts_index;
+ Nearest2DGetTriEdgesCallback get_tri_edges_index;
+ Nearest2DCopyVertNoCallback copy_vert_no;
+
+ union {
+ struct {
+ struct BMesh *bm;
+ };
+ struct {
+ const struct MVert *vert;
+ const float (*vert_normals)[3];
+ const struct MEdge *edge; /* only used for #BVHTreeFromMeshEdges */
+ const struct MLoop *loop;
+ const struct MLoopTri *looptri;
+ };
+ };
+
+ bool is_persp;
+ bool use_backface_culling;
+} Nearest2dUserData;
+
+static void cb_mvert_co_get(const int index, const Nearest2dUserData *data, const float **r_co)
{
- const BVHTreeFromMesh *data = user_data;
*r_co = data->vert[index].co;
}
-static void cb_bvert_co_get(const int index, const void *user_data, const float **r_co)
+static void cb_bvert_co_get(const int index, const Nearest2dUserData *data, const float **r_co)
{
- const BMEditMesh *data = user_data;
BMVert *eve = BM_vert_at_index(data->bm, index);
*r_co = eve->co;
}
-static void cb_mvert_no_copy(const int index, const void *user_data, float r_no[3])
+static void cb_mvert_no_copy(const int index, const Nearest2dUserData *data, float r_no[3])
{
- const BVHTreeFromMesh *data = user_data;
- const MVert *vert = data->vert + index;
-
- normal_short_to_float_v3(r_no, vert->no);
+ copy_v3_v3(r_no, data->vert_normals[index]);
}
-static void cb_bvert_no_copy(const int index, const void *user_data, float r_no[3])
+static void cb_bvert_no_copy(const int index, const Nearest2dUserData *data, float r_no[3])
{
- const BMEditMesh *data = user_data;
BMVert *eve = BM_vert_at_index(data->bm, index);
copy_v3_v3(r_no, eve->no);
}
-static void cb_medge_verts_get(const int index, const void *user_data, int r_v_index[2])
+static void cb_medge_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[2])
{
- const BVHTreeFromMesh *data = user_data;
const MEdge *edge = &data->edge[index];
r_v_index[0] = edge->v1;
r_v_index[1] = edge->v2;
}
-static void cb_bedge_verts_get(const int index, const void *user_data, int r_v_index[2])
+static void cb_bedge_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[2])
{
- const BMEditMesh *data = user_data;
BMEdge *eed = BM_edge_at_index(data->bm, index);
r_v_index[0] = BM_elem_index_get(eed->v1);
r_v_index[1] = BM_elem_index_get(eed->v2);
}
-static void cb_mlooptri_edges_get(const int index, const void *user_data, int r_v_index[3])
+static void cb_mlooptri_edges_get(const int index, const Nearest2dUserData *data, int r_v_index[3])
{
- const BVHTreeFromMesh *data = user_data;
const MEdge *medge = data->edge;
const MLoop *mloop = data->loop;
const MLoopTri *lt = &data->looptri[index];
@@ -1277,9 +1307,8 @@ static void cb_mlooptri_edges_get(const int index, const void *user_data, int r_
}
}
-static void cb_mlooptri_verts_get(const int index, const void *user_data, int r_v_index[3])
+static void cb_mlooptri_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[3])
{
- const BVHTreeFromMesh *data = user_data;
const MLoop *loop = data->loop;
const MLoopTri *looptri = &data->looptri[index];
@@ -1348,66 +1377,6 @@ static bool test_projected_edge_dist(const struct DistProjectedAABBPrecalc *prec
precalc, clip_plane, clip_plane_len, is_persp, near_co, dist_px_sq, r_co);
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Walk DFS
- * \{ */
-
-typedef void (*Nearest2DGetVertCoCallback)(const int index,
- const void *user_data,
- const float **r_co);
-typedef void (*Nearest2DGetEdgeVertsCallback)(const int index,
- const void *user_data,
- int r_v_index[2]);
-typedef void (*Nearest2DGetTriVertsCallback)(const int index,
- const void *user_data,
- int r_v_index[3]);
-/* Equal the previous one */
-typedef void (*Nearest2DGetTriEdgesCallback)(const int index,
- const void *user_data,
- int r_e_index[3]);
-typedef void (*Nearest2DCopyVertNoCallback)(const int index, const void *user_data, float r_no[3]);
-
-typedef struct Nearest2dUserData {
- void *userdata;
- Nearest2DGetVertCoCallback get_vert_co;
- Nearest2DGetEdgeVertsCallback get_edge_verts_index;
- Nearest2DGetTriVertsCallback get_tri_verts_index;
- Nearest2DGetTriEdgesCallback get_tri_edges_index;
- Nearest2DCopyVertNoCallback copy_vert_no;
-
- bool is_persp;
- bool use_backface_culling;
-} Nearest2dUserData;
-
-static void nearest2d_data_init(SnapObjectData *sod,
- bool is_persp,
- bool use_backface_culling,
- Nearest2dUserData *r_nearest2d)
-{
- if (sod->type == SNAP_MESH) {
- r_nearest2d->userdata = &sod->treedata_mesh;
- r_nearest2d->get_vert_co = cb_mvert_co_get;
- r_nearest2d->get_edge_verts_index = cb_medge_verts_get;
- r_nearest2d->copy_vert_no = cb_mvert_no_copy;
- r_nearest2d->get_tri_verts_index = cb_mlooptri_verts_get;
- r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get;
- }
- else {
- BLI_assert(sod->type == SNAP_EDIT_MESH);
- r_nearest2d->userdata = sod->treedata_editmesh.em;
- r_nearest2d->get_vert_co = cb_bvert_co_get;
- r_nearest2d->get_edge_verts_index = cb_bedge_verts_get;
- r_nearest2d->copy_vert_no = cb_bvert_no_copy;
- r_nearest2d->get_tri_verts_index = NULL;
- r_nearest2d->get_tri_edges_index = NULL;
- }
-
- r_nearest2d->is_persp = is_persp;
- r_nearest2d->use_backface_culling = use_backface_culling;
-}
-
static void cb_snap_vert(void *userdata,
int index,
const struct DistProjectedAABBPrecalc *precalc,
@@ -1415,10 +1384,10 @@ static void cb_snap_vert(void *userdata,
const int clip_plane_len,
BVHTreeNearest *nearest)
{
- struct Nearest2dUserData *data = userdata;
+ Nearest2dUserData *data = userdata;
const float *co;
- data->get_vert_co(index, data->userdata, &co);
+ data->get_vert_co(index, data, &co);
if (test_projected_vert_dist(precalc,
clip_plane,
@@ -1427,7 +1396,7 @@ static void cb_snap_vert(void *userdata,
co,
&nearest->dist_sq,
nearest->co)) {
- data->copy_vert_no(index, data->userdata, nearest->no);
+ data->copy_vert_no(index, data, nearest->no);
nearest->index = index;
}
}
@@ -1442,11 +1411,11 @@ static void cb_snap_edge(void *userdata,
struct Nearest2dUserData *data = userdata;
int vindex[2];
- data->get_edge_verts_index(index, data->userdata, vindex);
+ data->get_edge_verts_index(index, data, vindex);
const float *v_pair[2];
- data->get_vert_co(vindex[0], data->userdata, &v_pair[0]);
- data->get_vert_co(vindex[1], data->userdata, &v_pair[1]);
+ data->get_vert_co(vindex[0], data, &v_pair[0]);
+ data->get_vert_co(vindex[1], data, &v_pair[1]);
if (test_projected_edge_dist(precalc,
clip_plane,
@@ -1471,7 +1440,7 @@ static void cb_snap_edge_verts(void *userdata,
struct Nearest2dUserData *data = userdata;
int vindex[2];
- data->get_edge_verts_index(index, data->userdata, vindex);
+ data->get_edge_verts_index(index, data, vindex);
for (int i = 2; i--;) {
if (vindex[i] == nearest->index) {
@@ -1488,16 +1457,16 @@ static void cb_snap_tri_edges(void *userdata,
const int clip_plane_len,
BVHTreeNearest *nearest)
{
- struct Nearest2dUserData *data = userdata;
+ Nearest2dUserData *data = userdata;
if (data->use_backface_culling) {
int vindex[3];
- data->get_tri_verts_index(index, data->userdata, vindex);
+ data->get_tri_verts_index(index, data, vindex);
const float *t0, *t1, *t2;
- data->get_vert_co(vindex[0], data->userdata, &t0);
- data->get_vert_co(vindex[1], data->userdata, &t1);
- data->get_vert_co(vindex[2], data->userdata, &t2);
+ data->get_vert_co(vindex[0], data, &t0);
+ data->get_vert_co(vindex[1], data, &t1);
+ data->get_vert_co(vindex[2], data, &t2);
float dummy[3];
if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
return;
@@ -1505,7 +1474,7 @@ static void cb_snap_tri_edges(void *userdata,
}
int eindex[3];
- data->get_tri_edges_index(index, data->userdata, eindex);
+ data->get_tri_edges_index(index, data, eindex);
for (int i = 3; i--;) {
if (eindex[i] != -1) {
if (eindex[i] == nearest->index) {
@@ -1526,13 +1495,13 @@ static void cb_snap_tri_verts(void *userdata,
struct Nearest2dUserData *data = userdata;
int vindex[3];
- data->get_tri_verts_index(index, data->userdata, vindex);
+ data->get_tri_verts_index(index, data, vindex);
if (data->use_backface_culling) {
const float *t0, *t1, *t2;
- data->get_vert_co(vindex[0], data->userdata, &t0);
- data->get_vert_co(vindex[1], data->userdata, &t1);
- data->get_vert_co(vindex[2], data->userdata, &t2);
+ data->get_vert_co(vindex[0], data, &t0);
+ data->get_vert_co(vindex[1], data, &t1);
+ data->get_vert_co(vindex[2], data, &t2);
float dummy[3];
if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
return;
@@ -1547,6 +1516,39 @@ static void cb_snap_tri_verts(void *userdata,
}
}
+static void nearest2d_data_init(SnapObjectData *sod,
+ bool is_persp,
+ bool use_backface_culling,
+ Nearest2dUserData *r_nearest2d)
+{
+ if (sod->type == SNAP_MESH) {
+ r_nearest2d->get_vert_co = cb_mvert_co_get;
+ r_nearest2d->get_edge_verts_index = cb_medge_verts_get;
+ r_nearest2d->copy_vert_no = cb_mvert_no_copy;
+ r_nearest2d->get_tri_verts_index = cb_mlooptri_verts_get;
+ r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get;
+
+ r_nearest2d->vert = sod->treedata_mesh.vert;
+ r_nearest2d->vert_normals = sod->treedata_mesh.vert_normals;
+ r_nearest2d->edge = sod->treedata_mesh.edge;
+ r_nearest2d->loop = sod->treedata_mesh.loop;
+ r_nearest2d->looptri = sod->treedata_mesh.looptri;
+ }
+ else {
+ BLI_assert(sod->type == SNAP_EDIT_MESH);
+ r_nearest2d->get_vert_co = cb_bvert_co_get;
+ r_nearest2d->get_edge_verts_index = cb_bedge_verts_get;
+ r_nearest2d->copy_vert_no = cb_bvert_no_copy;
+ r_nearest2d->get_tri_verts_index = NULL;
+ r_nearest2d->get_tri_edges_index = NULL;
+
+ r_nearest2d->bm = sod->treedata_editmesh.em->bm;
+ }
+
+ r_nearest2d->is_persp = is_persp;
+ r_nearest2d->use_backface_culling = use_backface_culling;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1554,10 +1556,9 @@ static void cb_snap_tri_verts(void *userdata,
* \{ */
static short snap_mesh_polygon(SnapObjectContext *sctx,
- SnapData *snapdata,
+ const struct SnapObjectParams *params,
Object *ob_eval,
const float obmat[4][4],
- bool use_backface_culling,
/* read/write args */
float *dist_px,
/* return args */
@@ -1568,16 +1569,16 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
short elem = 0;
float lpmat[4][4];
- mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
struct DistProjectedAABBPrecalc neasrest_precalc;
dist_squared_to_projected_aabb_precalc(
- &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
+ &neasrest_precalc, lpmat, sctx->runtime.win_size, sctx->runtime.mval);
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
- for (int i = snapdata->clip_plane_len; i--;) {
- mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
+ for (int i = sctx->runtime.clip_plane_len; i--;) {
+ mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
}
BVHTreeNearest nearest = {
@@ -1590,14 +1591,14 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
Nearest2dUserData nearest2d;
nearest2d_data_init(
- sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d);
+ sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
if (sod->type == SNAP_MESH) {
BVHTreeFromMesh *treedata = &sod->treedata_mesh;
const MPoly *mp = &sod->poly[*r_index];
const MLoop *ml = &treedata->loop[mp->loopstart];
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
+ if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
elem = SCE_SNAP_MODE_EDGE;
BLI_assert(treedata->edge != NULL);
for (int i = mp->totloop; i--; ml++) {
@@ -1605,7 +1606,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
ml->e,
&neasrest_precalc,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
&nearest);
}
}
@@ -1616,7 +1617,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
ml->v,
&neasrest_precalc,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
&nearest);
}
}
@@ -1629,7 +1630,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
BMFace *f = BM_face_at_index(em->bm, *r_index);
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
+ if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
elem = SCE_SNAP_MODE_EDGE;
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_EDGE);
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE);
@@ -1638,7 +1639,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
BM_elem_index_get(l_iter->e),
&neasrest_precalc,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
&nearest);
} while ((l_iter = l_iter->next) != l_first);
}
@@ -1651,7 +1652,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
BM_elem_index_get(l_iter->v),
&neasrest_precalc,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
&nearest);
} while ((l_iter = l_iter->next) != l_first);
}
@@ -1680,12 +1681,11 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
}
static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
- SnapData *snapdata,
+ const struct SnapObjectParams *params,
Object *ob_eval,
const float obmat[4][4],
float original_dist_px,
const float prev_co[3],
- bool use_backface_culling,
/* read/write args */
float *dist_px,
/* return args */
@@ -1704,22 +1704,22 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
Nearest2dUserData nearest2d;
nearest2d_data_init(
- sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d);
+ sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
int vindex[2];
- nearest2d.get_edge_verts_index(*r_index, nearest2d.userdata, vindex);
+ nearest2d.get_edge_verts_index(*r_index, &nearest2d, vindex);
const float *v_pair[2];
- nearest2d.get_vert_co(vindex[0], nearest2d.userdata, &v_pair[0]);
- nearest2d.get_vert_co(vindex[1], nearest2d.userdata, &v_pair[1]);
+ nearest2d.get_vert_co(vindex[0], &nearest2d, &v_pair[0]);
+ nearest2d.get_vert_co(vindex[1], &nearest2d, &v_pair[1]);
struct DistProjectedAABBPrecalc neasrest_precalc;
{
float lpmat[4][4];
- mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
dist_squared_to_projected_aabb_precalc(
- &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
+ &neasrest_precalc, lpmat, sctx->runtime.win_size, sctx->runtime.mval);
}
BVHTreeNearest nearest = {
@@ -1736,7 +1736,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
/* do nothing */
}
else {
- short snap_to_flag = snapdata->snap_to_flag;
+ short snap_to_flag = sctx->runtime.snap_to_flag;
int e_mode_len = ((snap_to_flag & SCE_SNAP_MODE_EDGE) != 0) +
((snap_to_flag & SCE_SNAP_MODE_VERTEX) != 0) +
((snap_to_flag & SCE_SNAP_MODE_EDGE_MIDPOINT) != 0);
@@ -1758,7 +1758,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
if (r_no) {
float imat[4][4];
invert_m4_m4(imat, obmat);
- nearest2d.copy_vert_no(vindex[v_id], nearest2d.userdata, r_no);
+ nearest2d.copy_vert_no(vindex[v_id], &nearest2d, r_no);
mul_transposed_mat3_m4_v3(imat, r_no);
normalize_v3(r_no);
}
@@ -1785,7 +1785,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
}
}
- if (prev_co && (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ if (prev_co && (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
float v_near[3], va_g[3], vb_g[3];
mul_v3_m4v3(va_g, obmat, v_pair[0]);
@@ -1797,7 +1797,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
if (len_squared_v3v3(prev_co, v_near) > FLT_EPSILON) {
dist_squared_to_projected_aabb_precalc(
- &neasrest_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval);
+ &neasrest_precalc, sctx->runtime.pmat, sctx->runtime.win_size, sctx->runtime.mval);
if (test_projected_vert_dist(&neasrest_precalc,
NULL,
@@ -1828,7 +1828,8 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
return elem;
}
-static short snapArmature(SnapData *snapdata,
+static short snapArmature(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
const float obmat[4][4],
/* read/write args */
@@ -1840,102 +1841,70 @@ static short snapArmature(SnapData *snapdata,
{
short retval = 0;
- if (snapdata->snap_to_flag == SCE_SNAP_MODE_FACE) { /* Currently only edge and vert */
+ if (sctx->runtime.snap_to_flag == SCE_SNAP_MODE_FACE) { /* Currently only edge and vert */
return retval;
}
float lpmat[4][4], dist_px_sq = square_f(*dist_px);
- mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
struct DistProjectedAABBPrecalc neasrest_precalc;
dist_squared_to_projected_aabb_precalc(
- &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
+ &neasrest_precalc, lpmat, sctx->runtime.win_size, sctx->runtime.mval);
bool use_obedit = ((bArmature *)ob_eval->data)->edbo != NULL;
if (use_obedit == false) {
/* Test BoundBox */
BoundBox *bb = BKE_armature_boundbox_get(ob_eval);
- if (bb && !snap_bound_box_check_dist(
- bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
+ if (bb && !snap_bound_box_check_dist(bb->vec[0],
+ bb->vec[6],
+ lpmat,
+ sctx->runtime.win_size,
+ sctx->runtime.mval,
+ dist_px_sq)) {
return retval;
}
}
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
- for (int i = snapdata->clip_plane_len; i--;) {
- mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
+ for (int i = sctx->runtime.clip_plane_len; i--;) {
+ mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
}
- bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ const eSnapSelect snap_select = params->snap_select;
+ bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
bArmature *arm = ob_eval->data;
if (arm->edbo) {
LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) {
if (eBone->layer & arm->layer) {
- /* skip hidden or moving (selected) bones */
- if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
- bool has_vert_snap = false;
-
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
- has_vert_snap = test_projected_vert_dist(&neasrest_precalc,
- clip_planes_local,
- snapdata->clip_plane_len,
- is_persp,
- eBone->head,
- &dist_px_sq,
- r_loc);
- has_vert_snap |= test_projected_vert_dist(&neasrest_precalc,
- clip_planes_local,
- snapdata->clip_plane_len,
- is_persp,
- eBone->tail,
- &dist_px_sq,
- r_loc);
-
- if (has_vert_snap) {
- retval = SCE_SNAP_MODE_VERTEX;
- }
- }
- if (!has_vert_snap && snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
- if (test_projected_edge_dist(&neasrest_precalc,
- clip_planes_local,
- snapdata->clip_plane_len,
- is_persp,
- eBone->head,
- eBone->tail,
- &dist_px_sq,
- r_loc)) {
- retval = SCE_SNAP_MODE_EDGE;
- }
- }
+ if (eBone->flag & BONE_HIDDEN_A) {
+ /* Skip hidden bones. */
+ continue;
+ }
+
+ const bool is_selected = (eBone->flag & (BONE_ROOTSEL | BONE_TIPSEL)) != 0;
+ if (is_selected && snap_select == SNAP_NOT_SELECTED) {
+ continue;
}
- }
- }
- }
- else if (ob_eval->pose && ob_eval->pose->chanbase.first) {
- LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_eval->pose->chanbase) {
- Bone *bone = pchan->bone;
- /* skip hidden bones */
- if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
bool has_vert_snap = false;
- const float *head_vec = pchan->pose_head;
- const float *tail_vec = pchan->pose_tail;
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
has_vert_snap = test_projected_vert_dist(&neasrest_precalc,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
is_persp,
- head_vec,
+ eBone->head,
&dist_px_sq,
r_loc);
has_vert_snap |= test_projected_vert_dist(&neasrest_precalc,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
is_persp,
- tail_vec,
+ eBone->tail,
+
&dist_px_sq,
r_loc);
@@ -1943,13 +1912,13 @@ static short snapArmature(SnapData *snapdata,
retval = SCE_SNAP_MODE_VERTEX;
}
}
- if (!has_vert_snap && snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
+ if (!has_vert_snap && sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
if (test_projected_edge_dist(&neasrest_precalc,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
is_persp,
- head_vec,
- tail_vec,
+ eBone->head,
+ eBone->tail,
&dist_px_sq,
r_loc)) {
retval = SCE_SNAP_MODE_EDGE;
@@ -1958,6 +1927,51 @@ static short snapArmature(SnapData *snapdata,
}
}
}
+ else if (ob_eval->pose && ob_eval->pose->chanbase.first) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_eval->pose->chanbase) {
+ Bone *bone = pchan->bone;
+ /* skip hidden bones */
+ if (!bone || (bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
+ continue;
+ }
+ bool has_vert_snap = false;
+ const float *head_vec = pchan->pose_head;
+ const float *tail_vec = pchan->pose_tail;
+
+ if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ has_vert_snap = test_projected_vert_dist(&neasrest_precalc,
+ clip_planes_local,
+ sctx->runtime.clip_plane_len,
+ is_persp,
+ head_vec,
+ &dist_px_sq,
+ r_loc);
+ has_vert_snap |= test_projected_vert_dist(&neasrest_precalc,
+ clip_planes_local,
+ sctx->runtime.clip_plane_len,
+ is_persp,
+ tail_vec,
+ &dist_px_sq,
+ r_loc);
+
+ if (has_vert_snap) {
+ retval = SCE_SNAP_MODE_VERTEX;
+ }
+ }
+ if (!has_vert_snap && sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
+ if (test_projected_edge_dist(&neasrest_precalc,
+ clip_planes_local,
+ sctx->runtime.clip_plane_len,
+ is_persp,
+ head_vec,
+ tail_vec,
+ &dist_px_sq,
+ r_loc)) {
+ retval = SCE_SNAP_MODE_EDGE;
+ }
+ }
+ }
+ }
if (retval) {
*dist_px = sqrtf(dist_px_sq);
@@ -1972,10 +1986,10 @@ static short snapArmature(SnapData *snapdata,
return 0;
}
-static short snapCurve(SnapData *snapdata,
+static short snapCurve(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
const float obmat[4][4],
- bool use_obedit,
/* read/write args */
float *dist_px,
/* return args */
@@ -1986,7 +2000,7 @@ static short snapCurve(SnapData *snapdata,
bool has_snap = false;
/* only vertex snapping mode (eg control points and handles) supported for now) */
- if ((snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) == 0) {
+ if ((sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) == 0) {
return 0;
}
@@ -1994,19 +2008,23 @@ static short snapCurve(SnapData *snapdata,
float dist_px_sq = square_f(*dist_px);
float lpmat[4][4];
- mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
struct DistProjectedAABBPrecalc neasrest_precalc;
dist_squared_to_projected_aabb_precalc(
- &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
+ &neasrest_precalc, lpmat, sctx->runtime.win_size, sctx->runtime.mval);
- use_obedit = use_obedit && BKE_object_is_in_editmode(ob_eval);
+ const bool use_obedit = BKE_object_is_in_editmode(ob_eval);
if (use_obedit == false) {
/* Test BoundBox */
BoundBox *bb = BKE_curve_boundbox_get(ob_eval);
- if (bb && !snap_bound_box_check_dist(
- bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
+ if (bb && !snap_bound_box_check_dist(bb->vec[0],
+ bb->vec[6],
+ lpmat,
+ sctx->runtime.win_size,
+ sctx->runtime.mval,
+ dist_px_sq)) {
return 0;
}
}
@@ -2014,10 +2032,10 @@ static short snapCurve(SnapData *snapdata,
float tobmat[4][4];
transpose_m4_m4(tobmat, obmat);
- float(*clip_planes)[4] = snapdata->clip_plane;
- int clip_plane_len = snapdata->clip_plane_len;
+ float(*clip_planes)[4] = sctx->runtime.clip_plane;
+ int clip_plane_len = sctx->runtime.clip_plane_len;
- if (snapdata->has_occlusion_plane) {
+ if (sctx->runtime.has_occlusion_plane) {
/* We snap to vertices even if occluded. */
clip_planes++;
clip_plane_len--;
@@ -2028,15 +2046,21 @@ static short snapCurve(SnapData *snapdata,
mul_v4_m4v4(clip_planes_local[i], tobmat, clip_planes[i]);
}
- bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
+ bool skip_selected = params->snap_select == SNAP_NOT_SELECTED;
for (Nurb *nu = (use_obedit ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
for (int u = 0; u < nu->pntsu; u++) {
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
if (use_obedit) {
if (nu->bezt) {
- /* don't snap to selected (moving) or hidden */
- if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) {
+ if (nu->bezt[u].hide) {
+ /* Skip hidden. */
+ continue;
+ }
+
+ bool is_selected = (nu->bezt[u].f2 & SELECT) != 0;
+ if (is_selected && skip_selected) {
continue;
}
has_snap |= test_projected_vert_dist(&neasrest_precalc,
@@ -2048,8 +2072,9 @@ static short snapCurve(SnapData *snapdata,
r_loc);
/* Don't snap if handle is selected (moving),
* or if it is aligning to a moving handle. */
- if (!(nu->bezt[u].f1 & SELECT) &&
- !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) {
+ is_selected = (!(nu->bezt[u].f1 & SELECT) &&
+ !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) != 0;
+ if (!(is_selected && skip_selected)) {
has_snap |= test_projected_vert_dist(&neasrest_precalc,
clip_planes_local,
clip_plane_len,
@@ -2058,8 +2083,10 @@ static short snapCurve(SnapData *snapdata,
&dist_px_sq,
r_loc);
}
- if (!(nu->bezt[u].f3 & SELECT) &&
- !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) {
+
+ is_selected = (!(nu->bezt[u].f3 & SELECT) &&
+ !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) != 0;
+ if (!(is_selected && skip_selected)) {
has_snap |= test_projected_vert_dist(&neasrest_precalc,
clip_planes_local,
clip_plane_len,
@@ -2070,10 +2097,16 @@ static short snapCurve(SnapData *snapdata,
}
}
else {
- /* don't snap to selected (moving) or hidden */
- if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) {
+ if (nu->bp[u].hide) {
+ /* Skip hidden. */
+ continue;
+ }
+
+ bool is_selected = (nu->bp[u].f1 & SELECT) != 0;
+ if (is_selected && skip_selected) {
continue;
}
+
has_snap |= test_projected_vert_dist(&neasrest_precalc,
clip_planes_local,
clip_plane_len,
@@ -2123,7 +2156,7 @@ static short snapCurve(SnapData *snapdata,
}
/* may extend later (for now just snaps to empty center) */
-static short snap_object_center(SnapData *snapdata,
+static short snap_object_center(const SnapObjectContext *sctx,
Object *ob_eval,
const float obmat[4][4],
/* read/write args */
@@ -2140,24 +2173,24 @@ static short snap_object_center(SnapData *snapdata,
}
/* for now only vertex supported */
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
struct DistProjectedAABBPrecalc neasrest_precalc;
dist_squared_to_projected_aabb_precalc(
- &neasrest_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval);
+ &neasrest_precalc, sctx->runtime.pmat, sctx->runtime.win_size, sctx->runtime.mval);
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
- for (int i = snapdata->clip_plane_len; i--;) {
- mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
+ for (int i = sctx->runtime.clip_plane_len; i--;) {
+ mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
}
- bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
float dist_px_sq = square_f(*dist_px);
float co[3];
copy_v3_v3(co, obmat[3]);
if (test_projected_vert_dist(&neasrest_precalc,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
is_persp,
co,
&dist_px_sq,
@@ -2179,7 +2212,6 @@ static short snap_object_center(SnapData *snapdata,
}
static short snapCamera(const SnapObjectContext *sctx,
- SnapData *snapdata,
Object *object,
float obmat[4][4],
/* read/write args */
@@ -2193,7 +2225,7 @@ static short snapCamera(const SnapObjectContext *sctx,
Scene *scene = sctx->scene;
- bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
float dist_px_sq = square_f(*dist_px);
float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
@@ -2201,7 +2233,7 @@ static short snapCamera(const SnapObjectContext *sctx,
MovieTracking *tracking;
if (clip == NULL) {
- return snap_object_center(snapdata, object, obmat, dist_px, r_loc, r_no, r_index);
+ return snap_object_center(sctx, object, obmat, dist_px, r_loc, r_no, r_index);
}
if (object->transflag & OB_DUPLI) {
return retval;
@@ -2214,10 +2246,10 @@ static short snapCamera(const SnapObjectContext *sctx,
invert_m4_m4(orig_camera_imat, orig_camera_mat);
invert_m4_m4(imat, obmat);
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
struct DistProjectedAABBPrecalc neasrest_precalc;
dist_squared_to_projected_aabb_precalc(
- &neasrest_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval);
+ &neasrest_precalc, sctx->runtime.pmat, sctx->runtime.win_size, sctx->runtime.mval);
MovieTrackingObject *tracking_object;
for (tracking_object = tracking->objects.first; tracking_object;
@@ -2252,8 +2284,8 @@ static short snapCamera(const SnapObjectContext *sctx,
mul_m4_v3(vertex_obmat, bundle_pos);
if (test_projected_vert_dist(&neasrest_precalc,
- snapdata->clip_plane,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane,
+ sctx->runtime.clip_plane_len,
is_persp,
bundle_pos,
&dist_px_sq,
@@ -2277,12 +2309,11 @@ static short snapCamera(const SnapObjectContext *sctx,
}
static short snapMesh(SnapObjectContext *sctx,
- SnapData *snapdata,
+ const struct SnapObjectParams *params,
Object *ob_eval,
Mesh *me_eval,
const float obmat[4][4],
bool use_hide,
- bool use_backface_culling,
/* read/write args */
float *dist_px,
/* return args */
@@ -2290,23 +2321,24 @@ static short snapMesh(SnapObjectContext *sctx,
float r_no[3],
int *r_index)
{
- BLI_assert(snapdata->snap_to_flag != SCE_SNAP_MODE_FACE);
+ BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
if (me_eval->totvert == 0) {
return 0;
}
- if (me_eval->totedge == 0 && !(snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
+ if (me_eval->totedge == 0 && !(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
return 0;
}
float lpmat[4][4];
- mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
float dist_px_sq = square_f(*dist_px);
/* Test BoundBox */
- BoundBox *bb = BKE_mesh_boundbox_get(ob_eval);
- if (bb && !snap_bound_box_check_dist(
- bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
+ BoundBox *bb = BKE_object_boundbox_get(ob_eval);
+ if (bb &&
+ !snap_bound_box_check_dist(
+ bb->vec[0], bb->vec[6], lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq)) {
return 0;
}
@@ -2330,7 +2362,7 @@ static short snapMesh(SnapObjectContext *sctx,
treedata_tmp.looptri_allocated));
}
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
if (sod->has_loose_vert && sod->bvhtree[1] == NULL) {
sod->bvhtree[1] = BKE_bvhtree_from_mesh_get(
&treedata_tmp, me_eval, BVHTREE_FROM_LOOSEVERTS, 2);
@@ -2353,7 +2385,7 @@ static short snapMesh(SnapObjectContext *sctx,
Nearest2dUserData nearest2d;
nearest2d_data_init(
- sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d);
+ sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
BVHTreeNearest nearest = {
.index = -1,
@@ -2364,18 +2396,18 @@ static short snapMesh(SnapObjectContext *sctx,
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
- for (int i = snapdata->clip_plane_len; i--;) {
- mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
+ for (int i = sctx->runtime.clip_plane_len; i--;) {
+ mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
}
- if (sod->bvhtree[1] && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
+ if (sod->bvhtree[1] && (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
/* snap to loose verts */
BLI_bvhtree_find_nearest_projected(sod->bvhtree[1],
lpmat,
- snapdata->win_size,
- snapdata->mval,
+ sctx->runtime.win_size,
+ sctx->runtime.mval,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
&nearest,
cb_snap_vert,
&nearest2d);
@@ -2383,15 +2415,15 @@ static short snapMesh(SnapObjectContext *sctx,
last_index = nearest.index;
}
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
+ if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
if (sod->bvhtree[0]) {
/* snap to loose edges */
BLI_bvhtree_find_nearest_projected(sod->bvhtree[0],
lpmat,
- snapdata->win_size,
- snapdata->mval,
+ sctx->runtime.win_size,
+ sctx->runtime.mval,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
&nearest,
cb_snap_edge,
&nearest2d);
@@ -2401,10 +2433,10 @@ static short snapMesh(SnapObjectContext *sctx,
/* snap to looptris */
BLI_bvhtree_find_nearest_projected(treedata->tree,
lpmat,
- snapdata->win_size,
- snapdata->mval,
+ sctx->runtime.win_size,
+ sctx->runtime.mval,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
&nearest,
cb_snap_tri_edges,
&nearest2d);
@@ -2415,15 +2447,15 @@ static short snapMesh(SnapObjectContext *sctx,
}
}
else {
- BLI_assert(snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX);
+ BLI_assert(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX);
if (sod->bvhtree[0]) {
/* snap to loose edge verts */
BLI_bvhtree_find_nearest_projected(sod->bvhtree[0],
lpmat,
- snapdata->win_size,
- snapdata->mval,
+ sctx->runtime.win_size,
+ sctx->runtime.mval,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
&nearest,
cb_snap_edge_verts,
&nearest2d);
@@ -2433,10 +2465,10 @@ static short snapMesh(SnapObjectContext *sctx,
/* snap to looptri verts */
BLI_bvhtree_find_nearest_projected(treedata->tree,
lpmat,
- snapdata->win_size,
- snapdata->mval,
+ sctx->runtime.win_size,
+ sctx->runtime.mval,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
&nearest,
cb_snap_tri_verts,
&nearest2d);
@@ -2468,11 +2500,10 @@ static short snapMesh(SnapObjectContext *sctx,
}
static short snapEditMesh(SnapObjectContext *sctx,
- SnapData *snapdata,
+ const struct SnapObjectParams *params,
Object *ob_eval,
BMEditMesh *em,
const float obmat[4][4],
- bool use_backface_culling,
/* read/write args */
float *dist_px,
/* return args */
@@ -2480,9 +2511,9 @@ static short snapEditMesh(SnapObjectContext *sctx,
float r_no[3],
int *r_index)
{
- BLI_assert(snapdata->snap_to_flag != SCE_SNAP_MODE_FACE);
+ BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
- if ((snapdata->snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) {
+ if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) {
if (em->bm->totvert == 0) {
return 0;
}
@@ -2494,7 +2525,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
}
float lpmat[4][4];
- mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
float dist_px_sq = square_f(*dist_px);
@@ -2504,11 +2535,11 @@ static short snapEditMesh(SnapObjectContext *sctx,
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
if (!snap_bound_box_check_dist(
- sod->min, sod->max, lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
+ sod->min, sod->max, lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq)) {
return 0;
}
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
BVHTreeFromEditMesh treedata = {.tree = sod->bvhtree[0]};
if (treedata.tree == NULL) {
@@ -2540,7 +2571,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
}
}
- if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
+ if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
BVHTreeFromEditMesh treedata = {.tree = sod->bvhtree[1]};
if (treedata.tree == NULL) {
@@ -2574,7 +2605,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
Nearest2dUserData nearest2d;
nearest2d_data_init(
- sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d);
+ sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
BVHTreeNearest nearest = {
.index = -1,
@@ -2585,35 +2616,35 @@ static short snapEditMesh(SnapObjectContext *sctx,
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
- for (int i = snapdata->clip_plane_len; i--;) {
- mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
+ for (int i = sctx->runtime.clip_plane_len; i--;) {
+ mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
}
- if (sod->bvhtree[0] && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
+ if (sod->bvhtree[0] && (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
BLI_bvhtree_find_nearest_projected(sod->bvhtree[0],
lpmat,
- snapdata->win_size,
- snapdata->mval,
+ sctx->runtime.win_size,
+ sctx->runtime.mval,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
&nearest,
cb_snap_vert,
&nearest2d);
}
- if (sod->bvhtree[1] && (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE)) {
+ if (sod->bvhtree[1] && (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE)) {
int last_index = nearest.index;
nearest.index = -1;
BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT);
BM_mesh_elem_index_ensure(em->bm, BM_EDGE | BM_VERT);
BLI_bvhtree_find_nearest_projected(sod->bvhtree[1],
lpmat,
- snapdata->win_size,
- snapdata->mval,
+ sctx->runtime.win_size,
+ sctx->runtime.mval,
clip_planes_local,
- snapdata->clip_plane_len,
+ sctx->runtime.clip_plane_len,
&nearest,
cb_snap_edge,
&nearest2d);
@@ -2650,7 +2681,6 @@ static short snapEditMesh(SnapObjectContext *sctx,
}
struct SnapObjUserData {
- SnapData *snapdata;
/* read/write args */
float *dist_px;
/* return args */
@@ -2663,15 +2693,12 @@ struct SnapObjUserData {
};
/**
- * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
- *
* \note Duplicate args here are documented at #snapObjectsRay
*/
static void snap_obj_fn(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
float obmat[4][4],
- eSnapEditType edit_mode_type,
- bool use_backface_culling,
bool UNUSED(is_object_active),
void *data)
{
@@ -2680,21 +2707,14 @@ static void snap_obj_fn(SnapObjectContext *sctx,
switch (ob_eval->type) {
case OB_MESH: {
+ const eSnapEditType edit_mode_type = params->edit_mode_type;
bool use_hide;
Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
if (me_eval == NULL) {
/* Operators only update the editmesh looptris of the original mesh. */
BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval));
- retval = snapEditMesh(sctx,
- dt->snapdata,
- ob_eval,
- em_orig,
- obmat,
- use_backface_culling,
- dt->dist_px,
- dt->r_loc,
- dt->r_no,
- dt->r_index);
+ retval = snapEditMesh(
+ sctx, params, ob_eval, em_orig, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
}
if (ob_eval->dt == OB_BOUNDBOX) {
@@ -2703,12 +2723,11 @@ static void snap_obj_fn(SnapObjectContext *sctx,
}
retval = snapMesh(sctx,
- dt->snapdata,
+ params,
ob_eval,
me_eval,
obmat,
use_hide,
- use_backface_culling,
dt->dist_px,
dt->r_loc,
dt->r_no,
@@ -2717,29 +2736,22 @@ static void snap_obj_fn(SnapObjectContext *sctx,
}
case OB_ARMATURE:
retval = snapArmature(
- dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
case OB_CURVE:
- retval = snapCurve(dt->snapdata,
- ob_eval,
- obmat,
- edit_mode_type == SNAP_GEOM_EDIT,
- dt->dist_px,
- dt->r_loc,
- dt->r_no,
- dt->r_index);
+ retval = snapCurve(
+ sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */
case OB_SURF:
case OB_FONT: {
Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
if (mesh_eval) {
retval |= snapMesh(sctx,
- dt->snapdata,
+ params,
ob_eval,
mesh_eval,
obmat,
false,
- use_backface_culling,
dt->dist_px,
dt->r_loc,
dt->r_no,
@@ -2751,11 +2763,10 @@ static void snap_obj_fn(SnapObjectContext *sctx,
case OB_GPENCIL:
case OB_LAMP:
retval = snap_object_center(
- dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ sctx, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
case OB_CAMERA:
- retval = snapCamera(
- sctx, dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ retval = snapCamera(sctx, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
}
@@ -2777,8 +2788,6 @@ static void snap_obj_fn(SnapObjectContext *sctx,
* Walks through all objects in the scene to find the closest snap element ray.
*
* \param sctx: Snap context to store data.
- * \param snapdata: struct generated in `get_snapdata`.
- * \param params: Parameters for control snap behavior.
*
* Read/Write Args
* ---------------
@@ -2796,8 +2805,6 @@ static void snap_obj_fn(SnapObjectContext *sctx,
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
*/
static short snapObjectsRay(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
- SnapData *snapdata,
const struct SnapObjectParams *params,
/* read/write args */
/* Parameters below cannot be const, because they are assigned to a
@@ -2811,7 +2818,6 @@ static short snapObjectsRay(SnapObjectContext *sctx,
float r_obmat[4][4])
{
struct SnapObjUserData data = {
- .snapdata = snapdata,
.dist_px = dist_px,
.r_loc = r_loc,
.r_no = r_no,
@@ -2821,7 +2827,7 @@ static short snapObjectsRay(SnapObjectContext *sctx,
.ret = 0,
};
- iter_snap_objects(sctx, depsgraph, params, snap_obj_fn, &data);
+ iter_snap_objects(sctx, params, snap_obj_fn, &data);
return data.ret;
}
@@ -2848,21 +2854,6 @@ SnapObjectContext *ED_transform_snap_object_context_create(Scene *scene, int fla
return sctx;
}
-SnapObjectContext *ED_transform_snap_object_context_create_view3d(Scene *scene,
- int flag,
- /* extra args for view3d */
- const ARegion *region,
- const View3D *v3d)
-{
- SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, flag);
-
- sctx->use_v3d = true;
- sctx->v3d_data.region = region;
- sctx->v3d_data.v3d = v3d;
-
- return sctx;
-}
-
static void snap_object_data_free(void *sod_v)
{
SnapObjectData *sod = sod_v;
@@ -2896,6 +2887,7 @@ void ED_transform_snap_object_context_set_editmesh_callbacks(
bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx,
Depsgraph *depsgraph,
+ const View3D *v3d,
const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_normal[3],
@@ -2906,29 +2898,16 @@ bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx,
Object **r_ob,
float r_obmat[4][4])
{
- return raycastObjects(sctx,
- depsgraph,
- params,
- ray_start,
- ray_normal,
- ray_depth,
- r_loc,
- r_no,
- r_index,
- r_ob,
- r_obmat,
- NULL);
+ sctx->runtime.depsgraph = depsgraph;
+ sctx->runtime.v3d = v3d;
+
+ return raycastObjects(
+ sctx, params, ray_start, ray_normal, ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
-/**
- * Fill in a list of all hits.
- *
- * \param ray_depth: Only depths in this range are considered, -1.0 for maximum.
- * \param sort: Optionally sort the hits by depth.
- * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
- */
bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
Depsgraph *depsgraph,
+ const View3D *v3d,
const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_normal[3],
@@ -2936,6 +2915,9 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
bool sort,
ListBase *r_hit_list)
{
+ sctx->runtime.depsgraph = depsgraph;
+ sctx->runtime.v3d = v3d;
+
if (ray_depth == -1.0f) {
ray_depth = BVH_RAYCAST_DIST_MAX;
}
@@ -2944,18 +2926,8 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
float ray_depth_prev = ray_depth;
#endif
- bool retval = raycastObjects(sctx,
- depsgraph,
- params,
- ray_start,
- ray_normal,
- &ray_depth,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- r_hit_list);
+ bool retval = raycastObjects(
+ sctx, params, ray_start, ray_normal, &ray_depth, NULL, NULL, NULL, NULL, NULL, r_hit_list);
/* meant to be readonly for 'all' hits, ensure it is */
#ifdef DEBUG
@@ -2978,6 +2950,7 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
*/
static bool transform_snap_context_project_ray_impl(SnapObjectContext *sctx,
Depsgraph *depsgraph,
+ const View3D *v3d,
const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_normal[3],
@@ -2988,14 +2961,25 @@ static bool transform_snap_context_project_ray_impl(SnapObjectContext *sctx,
bool ret;
/* try snap edge, then face if it fails */
- ret = ED_transform_snap_object_project_ray_ex(
- sctx, depsgraph, params, ray_start, ray_normal, ray_depth, r_co, r_no, NULL, NULL, NULL);
+ ret = ED_transform_snap_object_project_ray_ex(sctx,
+ depsgraph,
+ v3d,
+ params,
+ ray_start,
+ ray_normal,
+ ray_depth,
+ r_co,
+ r_no,
+ NULL,
+ NULL,
+ NULL);
return ret;
}
bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
Depsgraph *depsgraph,
+ const View3D *v3d,
const struct SnapObjectParams *params,
const float ray_origin[3],
const float ray_direction[3],
@@ -3010,12 +2994,14 @@ bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
}
return transform_snap_context_project_ray_impl(
- sctx, depsgraph, params, ray_origin, ray_direction, ray_depth, r_co, r_no);
+ sctx, depsgraph, v3d, params, ray_origin, ray_direction, ray_depth, r_co, r_no);
}
static short transform_snap_context_project_view3d_mixed_impl(
SnapObjectContext *sctx,
Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
const ushort snap_to_flag,
const struct SnapObjectParams *params,
const float mval[2],
@@ -3025,8 +3011,13 @@ static short transform_snap_context_project_view3d_mixed_impl(
float r_no[3],
int *r_index,
Object **r_ob,
- float r_obmat[4][4])
+ float r_obmat[4][4],
+ float r_face_nor[3])
{
+ sctx->runtime.depsgraph = depsgraph;
+ sctx->runtime.region = region;
+ sctx->runtime.v3d = v3d;
+
BLI_assert((snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) !=
0);
@@ -3042,28 +3033,20 @@ static short transform_snap_context_project_view3d_mixed_impl(
float obmat[4][4];
int index = -1;
- const ARegion *region = sctx->v3d_data.region;
const RegionView3D *rv3d = region->regiondata;
- bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(sctx->v3d_data.v3d);
+ bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(v3d);
if (snap_to_flag & SCE_SNAP_MODE_FACE || use_occlusion_test) {
float ray_start[3], ray_normal[3];
- if (!ED_view3d_win_to_ray_clipped_ex(depsgraph,
- sctx->v3d_data.region,
- sctx->v3d_data.v3d,
- mval,
- NULL,
- ray_normal,
- ray_start,
- true)) {
+ if (!ED_view3d_win_to_ray_clipped_ex(
+ depsgraph, region, v3d, mval, NULL, ray_normal, ray_start, true)) {
return 0;
}
float dummy_ray_depth = BVH_RAYCAST_DIST_MAX;
has_hit = raycastObjects(sctx,
- depsgraph,
params,
ray_start,
ray_normal,
@@ -3075,21 +3058,27 @@ static short transform_snap_context_project_view3d_mixed_impl(
obmat,
NULL);
- if (has_hit && (snap_to_flag & SCE_SNAP_MODE_FACE)) {
- retval = SCE_SNAP_MODE_FACE;
-
- copy_v3_v3(r_loc, loc);
- if (r_no) {
- copy_v3_v3(r_no, no);
+ if (has_hit) {
+ if (r_face_nor) {
+ copy_v3_v3(r_face_nor, no);
}
- if (r_ob) {
- *r_ob = ob_eval;
- }
- if (r_obmat) {
- copy_m4_m4(r_obmat, obmat);
- }
- if (r_index) {
- *r_index = index;
+
+ if ((snap_to_flag & SCE_SNAP_MODE_FACE)) {
+ retval = SCE_SNAP_MODE_FACE;
+
+ copy_v3_v3(r_loc, loc);
+ if (r_no) {
+ copy_v3_v3(r_no, no);
+ }
+ if (r_ob) {
+ *r_ob = ob_eval;
+ }
+ if (r_obmat) {
+ copy_m4_m4(r_obmat, obmat);
+ }
+ if (r_index) {
+ *r_index = index;
+ }
}
}
}
@@ -3099,24 +3088,28 @@ static short transform_snap_context_project_view3d_mixed_impl(
short elem_test, elem = 0;
float dist_px_tmp = *dist_px;
- SnapData snapdata;
- copy_m4_m4(snapdata.pmat, rv3d->persmat);
- snapdata.win_size[0] = region->winx;
- snapdata.win_size[1] = region->winy;
- copy_v2_v2(snapdata.mval, mval);
- snapdata.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
+ copy_m4_m4(sctx->runtime.pmat, rv3d->persmat);
+ sctx->runtime.win_size[0] = region->winx;
+ sctx->runtime.win_size[1] = region->winy;
+ copy_v2_v2(sctx->runtime.mval, mval);
+ sctx->runtime.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
/* First snap to edge instead of middle or perpendicular. */
- snapdata.snap_to_flag = snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE);
+ sctx->runtime.snap_to_flag = snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE);
if (snap_to_flag & (SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
- snapdata.snap_to_flag |= SCE_SNAP_MODE_EDGE;
+ sctx->runtime.snap_to_flag |= SCE_SNAP_MODE_EDGE;
}
- planes_from_projmat(
- snapdata.pmat, NULL, NULL, NULL, NULL, snapdata.clip_plane[0], snapdata.clip_plane[1]);
+ planes_from_projmat(sctx->runtime.pmat,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ sctx->runtime.clip_plane[0],
+ sctx->runtime.clip_plane[1]);
- snapdata.clip_plane_len = 2;
- snapdata.has_occlusion_plane = false;
+ sctx->runtime.clip_plane_len = 2;
+ sctx->runtime.has_occlusion_plane = false;
/* By convention we only snap to the original elements of a curve. */
if (has_hit && ob_eval->type != OB_CURVE) {
@@ -3124,7 +3117,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
float new_clipplane[4];
BLI_ASSERT_UNIT_V3(no);
plane_from_point_normal_v3(new_clipplane, loc, no);
- if (dot_v3v3(snapdata.clip_plane[0], new_clipplane) > 0.0f) {
+ if (dot_v3v3(sctx->runtime.clip_plane[0], new_clipplane) > 0.0f) {
/* The plane is facing the wrong direction. */
negate_v4(new_clipplane);
}
@@ -3133,30 +3126,21 @@ static short transform_snap_context_project_view3d_mixed_impl(
new_clipplane[3] += 0.01f;
/* Try to snap only to the polygon. */
- elem_test = snap_mesh_polygon(sctx,
- &snapdata,
- ob_eval,
- obmat,
- params->use_backface_culling,
- &dist_px_tmp,
- loc,
- no,
- &index);
+ elem_test = snap_mesh_polygon(sctx, params, ob_eval, obmat, &dist_px_tmp, loc, no, &index);
if (elem_test) {
elem = elem_test;
}
/* Add the new clip plane to the beginning of the list. */
- for (int i = snapdata.clip_plane_len; i != 0; i--) {
- copy_v4_v4(snapdata.clip_plane[i], snapdata.clip_plane[i - 1]);
+ for (int i = sctx->runtime.clip_plane_len; i != 0; i--) {
+ copy_v4_v4(sctx->runtime.clip_plane[i], sctx->runtime.clip_plane[i - 1]);
}
- copy_v4_v4(snapdata.clip_plane[0], new_clipplane);
- snapdata.clip_plane_len++;
- snapdata.has_occlusion_plane = true;
+ copy_v4_v4(sctx->runtime.clip_plane[0], new_clipplane);
+ sctx->runtime.clip_plane_len++;
+ sctx->runtime.has_occlusion_plane = true;
}
- elem_test = snapObjectsRay(
- sctx, depsgraph, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob_eval, obmat);
+ elem_test = snapObjectsRay(sctx, params, &dist_px_tmp, loc, no, &index, &ob_eval, obmat);
if (elem_test) {
elem = elem_test;
}
@@ -3164,18 +3148,9 @@ static short transform_snap_context_project_view3d_mixed_impl(
if ((elem == SCE_SNAP_MODE_EDGE) &&
(snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE_MIDPOINT |
SCE_SNAP_MODE_EDGE_PERPENDICULAR))) {
- snapdata.snap_to_flag = snap_to_flag;
- elem = snap_mesh_edge_verts_mixed(sctx,
- &snapdata,
- ob_eval,
- obmat,
- *dist_px,
- prev_co,
- params->use_backface_culling,
- &dist_px_tmp,
- loc,
- no,
- &index);
+ sctx->runtime.snap_to_flag = snap_to_flag;
+ elem = snap_mesh_edge_verts_mixed(
+ sctx, params, ob_eval, obmat, *dist_px, prev_co, &dist_px_tmp, loc, no, &index);
}
if (elem & snap_to_flag) {
@@ -3194,6 +3169,10 @@ static short transform_snap_context_project_view3d_mixed_impl(
if (r_index) {
*r_index = index;
}
+ if (r_face_nor && !has_hit) {
+ /* Fallback. */
+ copy_v3_v3(r_face_nor, no);
+ }
*dist_px = dist_px_tmp;
}
@@ -3204,6 +3183,8 @@ static short transform_snap_context_project_view3d_mixed_impl(
short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
const ushort snap_to,
const struct SnapObjectParams *params,
const float mval[2],
@@ -3213,10 +3194,13 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
float r_no[3],
int *r_index,
Object **r_ob,
- float r_obmat[4][4])
+ float r_obmat[4][4],
+ float r_face_nor[3])
{
return transform_snap_context_project_view3d_mixed_impl(sctx,
depsgraph,
+ region,
+ v3d,
snap_to,
params,
mval,
@@ -3226,34 +3210,26 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
r_no,
r_index,
r_ob,
- r_obmat);
+ r_obmat,
+ r_face_nor);
}
-/**
- * Convenience function for performing snapping.
- *
- * Given a 2D region value, snap to vert/edge/face.
- *
- * \param sctx: Snap context.
- * \param mval: Screenspace coordinate.
- * \param prev_co: Coordinate for perpendicular point calculation (optional).
- * \param dist_px: Maximum distance to snap (in pixels).
- * \param r_loc: hit location.
- * \param r_no: hit normal (optional).
- * \return Snap success
- */
-bool ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
- const ushort snap_to,
- const struct SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3])
+short ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const ushort snap_to,
+ const struct SnapObjectParams *params,
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3])
{
return ED_transform_snap_object_project_view3d_ex(sctx,
depsgraph,
+ region,
+ v3d,
snap_to,
params,
mval,
@@ -3263,14 +3239,14 @@ bool ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
r_no,
NULL,
NULL,
- NULL) != 0;
+ NULL,
+ NULL);
}
-/**
- * see: #ED_transform_snap_object_project_ray_all
- */
bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx,
Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
const struct SnapObjectParams *params,
const float mval[2],
float ray_depth,
@@ -3279,19 +3255,13 @@ bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx,
{
float ray_start[3], ray_normal[3];
- if (!ED_view3d_win_to_ray_clipped_ex(depsgraph,
- sctx->v3d_data.region,
- sctx->v3d_data.v3d,
- mval,
- NULL,
- ray_normal,
- ray_start,
- true)) {
+ if (!ED_view3d_win_to_ray_clipped_ex(
+ depsgraph, region, v3d, mval, NULL, ray_normal, ray_start, true)) {
return false;
}
return ED_transform_snap_object_project_ray_all(
- sctx, depsgraph, params, ray_start, ray_normal, ray_depth, sort, r_hit_list);
+ sctx, depsgraph, v3d, params, ray_start, ray_normal, ray_depth, sort, r_hit_list);
}
/** \} */
diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c
index 2acdf5cfd9c..7bcf6812ce9 100644
--- a/source/blender/editors/transform/transform_snap_sequencer.c
+++ b/source/blender/editors/transform/transform_snap_sequencer.c
@@ -220,13 +220,13 @@ static void seq_snap_target_points_build(const TransInfo *t,
int content_end = max_ii(seq->startdisp, seq->start + seq->len);
/* Effects and single image strips produce incorrect content length. Skip these strips. */
if ((seq->type & SEQ_TYPE_EFFECT) != 0 || seq->len == 1) {
- if (seq->anim_startofs == 0 && seq->startstill == 0) {
- content_start = seq->startdisp;
- }
- if (seq->anim_endofs == 0 && seq->endstill == 0) {
- content_end = seq->enddisp;
- }
+ content_start = seq->startdisp;
+ content_end = seq->enddisp;
}
+
+ CLAMP(content_start, seq->startdisp, seq->enddisp);
+ CLAMP(content_end, seq->startdisp, seq->enddisp);
+
snap_data->target_snap_points[i] = content_start;
snap_data->target_snap_points[i + 1] = content_end;
i += 2;
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index 22064e04e86..c6fa5acfff5 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -64,6 +64,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -77,9 +78,6 @@ static CLG_LogRef LOG = {"ed.undo"};
* Non-operator undo editor functions.
* \{ */
-/**
- * Run from the main event loop, basic checks that undo is left in a correct state.
- */
bool ED_undo_is_state_valid(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -146,7 +144,7 @@ void ED_undo_push(bContext *C, const char *str)
}
}
- UndoPushReturn push_retval;
+ eUndoPushReturn push_retval;
/* Only apply limit if this is the last undo step. */
if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) {
@@ -377,6 +375,9 @@ static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList *
wmWindowManager *wm = CTX_wm_manager(C);
const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active);
+ if (undo_index == active_step_index) {
+ return OPERATOR_CANCELLED;
+ }
const enum eUndoStepDir undo_dir = (undo_index < active_step_index) ? STEP_UNDO : STEP_REDO;
CLOG_INFO(&LOG,
@@ -438,7 +439,6 @@ void ED_undo_pop_op(bContext *C, wmOperator *op)
ed_undo_step_by_name(C, op->type->name, op->reports);
}
-/* name optionally, function used to check for operator redo panel */
bool ED_undo_is_valid(const bContext *C, const char *undoname)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -461,14 +461,6 @@ bool ED_undo_is_memfile_compatible(const bContext *C)
return true;
}
-/**
- * When a property of ID changes, return false.
- *
- * This is to avoid changes to a property making undo pushes
- * which are ignored by the undo-system.
- * For example, changing a brush property isn't stored by sculpt-mode undo steps.
- * This workaround is needed until the limitation is removed, see: T61948.
- */
bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, ID *id)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -494,13 +486,6 @@ bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, ID *id)
return true;
}
-/**
- * Ideally we won't access the stack directly,
- * this is needed for modes which handle undo themselves (bypassing #ED_undo_push).
- *
- * Using global isn't great, this just avoids doing inline,
- * causing 'BKE_global.h' & 'BKE_main.h' includes.
- */
UndoStack *ED_undo_stack_get(void)
{
wmWindowManager *wm = G_MAIN->wm.first;
@@ -513,17 +498,28 @@ UndoStack *ED_undo_stack_get(void)
/** \name Undo, Undo Push & Redo Operators
* \{ */
+/**
+ * Refresh to run after user activated undo/redo actions.
+ */
+static void ed_undo_refresh_for_op(bContext *C)
+{
+ /* The "last operator" should disappear, later we can tie this with undo stack nicer. */
+ WM_operator_stack_clear(CTX_wm_manager(C));
+
+ /* Keep button under the cursor active. */
+ WM_event_add_mousemove(CTX_wm_window(C));
+
+ ED_outliner_select_sync_from_all_tag(C);
+}
+
static int ed_undo_exec(bContext *C, wmOperator *op)
{
/* "last operator" should disappear, later we can tie this with undo stack nicer */
WM_operator_stack_clear(CTX_wm_manager(C));
int ret = ed_undo_step_direction(C, STEP_UNDO, op->reports);
if (ret & OPERATOR_FINISHED) {
- /* Keep button under the cursor active. */
- WM_event_add_mousemove(CTX_wm_window(C));
+ ed_undo_refresh_for_op(C);
}
-
- ED_outliner_select_sync_from_all_tag(C);
return ret;
}
@@ -548,11 +544,8 @@ static int ed_redo_exec(bContext *C, wmOperator *op)
{
int ret = ed_undo_step_direction(C, STEP_REDO, op->reports);
if (ret & OPERATOR_FINISHED) {
- /* Keep button under the cursor active. */
- WM_event_add_mousemove(CTX_wm_window(C));
+ ed_undo_refresh_for_op(C);
}
-
- ED_outliner_select_sync_from_all_tag(C);
return ret;
}
@@ -682,7 +675,6 @@ void ED_OT_undo_redo(wmOperatorType *ot)
/** \name Operator Repeat
* \{ */
-/* ui callbacks should call this rather than calling WM_operator_repeat() themselves */
int ED_undo_operator_repeat(bContext *C, wmOperator *op)
{
int ret = 0;
@@ -768,97 +760,36 @@ void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_un
/* -------------------------------------------------------------------- */
/** \name Undo History Operator
+ *
+ * See `TOPBAR_MT_undo_history` which is used to access this operator.
* \{ */
-/* create enum based on undo items */
-static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem)
-{
- EnumPropertyItem item_tmp = {0}, *item = NULL;
- int i = 0;
-
- wmWindowManager *wm = CTX_wm_manager(C);
- if (wm->undo_stack == NULL) {
- return NULL;
- }
-
- for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) {
- if (us->skip == false) {
- item_tmp.identifier = us->name;
- item_tmp.name = IFACE_(us->name);
- if (us == wm->undo_stack->step_active) {
- item_tmp.icon = ICON_LAYER_ACTIVE;
- }
- else {
- item_tmp.icon = ICON_NONE;
- }
- item_tmp.value = i;
- RNA_enum_item_add(&item, totitem, &item_tmp);
- }
- }
- RNA_enum_item_end(&item, totitem);
-
- return item;
-}
-
-static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+/* NOTE: also check #ed_undo_step() in top if you change notifiers. */
+static int undo_history_exec(bContext *C, wmOperator *op)
{
- int totitem = 0;
-
- {
- const EnumPropertyItem *item = rna_undo_itemf(C, &totitem);
-
- if (totitem > 0) {
- uiPopupMenu *pup = UI_popup_menu_begin(
- C, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
- uiLayout *layout = UI_popup_menu_layout(pup);
- uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
- uiLayout *column = NULL;
- const int col_size = 20 + totitem / 12;
- int i, c;
- bool add_col = true;
-
- for (c = 0, i = totitem; i--;) {
- if (add_col && !(c % col_size)) {
- column = uiLayoutColumn(split, false);
- add_col = false;
- }
- if (item[i].identifier) {
- uiItemIntO(column, item[i].name, item[i].icon, op->type->idname, "item", item[i].value);
- c++;
- add_col = true;
- }
- }
-
- MEM_freeN((void *)item);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ const int item = RNA_property_int_get(op->ptr, prop);
+ const int ret = ed_undo_step_by_index(C, item, op->reports);
+ if (ret & OPERATOR_FINISHED) {
+ ed_undo_refresh_for_op(C);
- UI_popup_menu_end(C, pup);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ return OPERATOR_FINISHED;
}
}
return OPERATOR_CANCELLED;
}
-/* NOTE: also check #ed_undo_step() in top if you change notifiers. */
-static int undo_history_exec(bContext *C, wmOperator *op)
+static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
if (RNA_property_is_set(op->ptr, prop)) {
- int item = RNA_property_int_get(op->ptr, prop);
- WM_operator_stack_clear(CTX_wm_manager(C));
- ed_undo_step_by_index(C, item, op->reports);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- return OPERATOR_FINISHED;
+ return undo_history_exec(C, op);
}
- return OPERATOR_CANCELLED;
-}
-static bool undo_history_poll(bContext *C)
-{
- if (!ed_undo_is_init_and_screenactive_poll(C)) {
- return false;
- }
- UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack;
- /* More than just original state entry. */
- return BLI_listbase_count_at_most(&undo_stack->steps, 2) > 1;
+ WM_menu_name_call(C, "TOPBAR_MT_undo_history", WM_OP_INVOKE_DEFAULT);
+ return OPERATOR_FINISHED;
}
void ED_OT_undo_history(wmOperatorType *ot)
@@ -871,7 +802,7 @@ void ED_OT_undo_history(wmOperatorType *ot)
/* api callbacks */
ot->invoke = undo_history_invoke;
ot->exec = undo_history_exec;
- ot->poll = undo_history_poll;
+ ot->poll = ed_undo_is_init_and_screenactive_poll;
RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX);
}
@@ -899,9 +830,6 @@ void ED_undo_object_set_active_or_warn(
}
}
-/**
- * Load all our objects from `object_array` into edit-mode, clear everything else.
- */
void ED_undo_object_editmode_restore_helper(struct bContext *C,
Object **object_array,
uint object_array_len,
diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c
index 1bdc2b2251e..b6ad5603808 100644
--- a/source/blender/editors/undo/memfile_undo.c
+++ b/source/blender/editors/undo/memfile_undo.c
@@ -35,6 +35,7 @@
#include "BKE_blender_undo.h"
#include "BKE_context.h"
+#include "BKE_icons.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
@@ -48,6 +49,7 @@
#include "WM_types.h"
#include "ED_object.h"
+#include "ED_render.h"
#include "ED_undo.h"
#include "ED_util.h"
@@ -142,6 +144,32 @@ static int memfile_undosys_step_id_reused_cb(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
+/**
+ * ID previews may be generated in a parallel job. So whatever operation generates the preview
+ * likely does the undo push before the preview is actually done and stored in the ID. Hence they
+ * get some extra treatment here:
+ * When undoing back to the moment the preview generation was triggered, this function schedules
+ * the preview for regeneration.
+ */
+static void memfile_undosys_unfinished_id_previews_restart(ID *id)
+{
+ PreviewImage *preview = BKE_previewimg_id_get(id);
+ if (!preview) {
+ return;
+ }
+
+ for (int i = 0; i < NUM_ICON_SIZES; i++) {
+ if (preview->flag[i] & PRV_USER_EDITED) {
+ /* Don't modify custom previews. */
+ continue;
+ }
+
+ if (!BKE_previewimg_is_finished(preview, i)) {
+ ED_preview_restart_queue_add(id, i);
+ }
+ }
+}
+
static void memfile_undosys_step_decode(struct bContext *C,
struct Main *bmain,
UndoStep *us_p,
@@ -188,6 +216,9 @@ static void memfile_undosys_step_decode(struct bContext *C,
}
ED_editors_exit(bmain, false);
+ /* Ensure there's no preview job running. Unfinished previews will be scheduled for regeneration
+ * via #memfile_undosys_unfinished_id_previews_restart(). */
+ ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
MemFileUndoStep *us = (MemFileUndoStep *)us_p;
BKE_memfile_undo_decode(us->data, undo_direction, use_old_bmain_data, C);
@@ -239,6 +270,9 @@ static void memfile_undosys_step_decode(struct bContext *C,
bmain, &scene->master_collection->id, scene->master_collection->id.recalc);
}
}
+
+ /* Restart preview generation if the undo state was generating previews. */
+ memfile_undosys_unfinished_id_previews_restart(id);
}
FOREACH_MAIN_ID_END;
@@ -263,6 +297,14 @@ static void memfile_undosys_step_decode(struct bContext *C,
}
FOREACH_MAIN_ID_END;
}
+ else {
+ ID *id = NULL;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ /* Restart preview generation if the undo state was generating previews. */
+ memfile_undosys_unfinished_id_previews_restart(id);
+ }
+ FOREACH_MAIN_ID_END;
+ }
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C));
}
@@ -283,7 +325,6 @@ static void memfile_undosys_step_free(UndoStep *us_p)
BKE_memfile_undo_free(us->data);
}
-/* Export for ED_undo_sys. */
void ED_memfile_undosys_type(UndoType *ut)
{
ut->name = "Global Undo";
@@ -322,21 +363,6 @@ struct MemFile *ED_undosys_stack_memfile_get_active(UndoStack *ustack)
return NULL;
}
-/**
- * If the last undo step is a memfile one, find the first #MemFileChunk matching given ID
- * (using its session UUID), and tag it as "changed in the future".
- *
- * Since non-memfile undo-steps cannot automatically set this flag in the previous step as done
- * with memfile ones, this has to be called manually by relevant undo code.
- *
- * \note Only current known case for this is undoing a switch from Object to Sculpt mode (see
- * T82388).
- *
- * \note Calling this ID by ID is not optimal, as it will loop over all #MemFile.chunks until it
- * finds the expected one. If this becomes an issue we'll have to add a mapping from session UUID
- * to first #MemFileChunk in #MemFile itself
- * (currently we only do that in #MemFileWriteData when writing a new step).
- */
void ED_undosys_stack_memfile_id_changed_tag(UndoStack *ustack, ID *id)
{
UndoStep *us = ustack->step_active;
diff --git a/source/blender/editors/undo/undo_intern.h b/source/blender/editors/undo/undo_intern.h
index 660f1a5b57d..d27bc1c8c0a 100644
--- a/source/blender/editors/undo/undo_intern.h
+++ b/source/blender/editors/undo/undo_intern.h
@@ -25,4 +25,6 @@
struct UndoType;
/* memfile_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_memfile_undosys_type(struct UndoType *ut);
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index b339bfbdc47..90a09c87cc6 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -55,6 +55,7 @@ set(SRC
../include/ED_clip.h
../include/ED_curve.h
../include/ED_datafiles.h
+ ../include/ED_file_indexer.h
../include/ED_fileselect.h
../include/ED_geometry.h
../include/ED_gizmo_library.h
diff --git a/source/blender/editors/util/ed_draw.c b/source/blender/editors/util/ed_draw.c
index fc351ab728c..3e85862a847 100644
--- a/source/blender/editors/util/ed_draw.c
+++ b/source/blender/editors/util/ed_draw.c
@@ -223,7 +223,7 @@ static void draw_main_line(const rctf *main_line_rect,
static void draw_backdrop(const int fontid,
const rctf *main_line_rect,
- const float color_bg[4],
+ const uint8_t color_bg[4],
const short region_y_size,
const float base_tick_height)
{
@@ -241,7 +241,7 @@ static void draw_backdrop(const int fontid,
.ymin = pad[1],
.ymax = region_y_size - pad[1],
};
- UI_draw_roundbox_aa(&backdrop_rect, true, 4.0f, color_bg);
+ UI_draw_roundbox_3ub_alpha(&backdrop_rect, true, 4.0f, color_bg, color_bg[3]);
}
/**
@@ -260,19 +260,19 @@ static void slider_draw(const struct bContext *UNUSED(C), ARegion *region, void
uint8_t color_line[4];
uint8_t color_handle[4];
uint8_t color_overshoot[4];
- float color_bg[4];
+ uint8_t color_bg[4];
/* Get theme colors. */
- UI_GetThemeColor4ubv(TH_TEXT, color_text);
- UI_GetThemeColor4ubv(TH_TEXT, color_line);
- UI_GetThemeColor4ubv(TH_TEXT, color_overshoot);
- UI_GetThemeColor4ubv(TH_ACTIVE, color_handle);
- UI_GetThemeColor3fv(TH_BACK, color_bg);
+ UI_GetThemeColor4ubv(TH_HEADER_TEXT_HI, color_handle);
+ UI_GetThemeColor4ubv(TH_HEADER_TEXT, color_text);
+ UI_GetThemeColor4ubv(TH_HEADER_TEXT, color_line);
+ UI_GetThemeColor4ubv(TH_HEADER_TEXT, color_overshoot);
+ UI_GetThemeColor4ubv(TH_HEADER, color_bg);
- color_bg[3] = 0.5f;
- color_overshoot[0] = color_overshoot[0] * 0.7;
- color_overshoot[1] = color_overshoot[1] * 0.7;
- color_overshoot[2] = color_overshoot[2] * 0.7;
+ color_overshoot[0] = color_overshoot[0] * 0.8;
+ color_overshoot[1] = color_overshoot[1] * 0.8;
+ color_overshoot[2] = color_overshoot[2] * 0.8;
+ color_bg[3] = 160;
/* Get the default font. */
const uiStyle *style = UI_style_get();
@@ -356,12 +356,11 @@ static void slider_draw(const struct bContext *UNUSED(C), ARegion *region, void
static void slider_update_factor(tSlider *slider, const wmEvent *event)
{
- const float factor_delta = (event->x - slider->last_cursor[0]) / SLIDE_PIXEL_DISTANCE;
+ const float factor_delta = (event->xy[0] - slider->last_cursor[0]) / SLIDE_PIXEL_DISTANCE;
/* Reduced factor delta in precision mode (shift held). */
slider->raw_factor += slider->precision ? (factor_delta / 8) : factor_delta;
slider->factor = slider->raw_factor;
- slider->last_cursor[0] = event->x;
- slider->last_cursor[1] = event->y;
+ copy_v2fl_v2i(slider->last_cursor, event->xy);
if (!slider->overshoot) {
slider->factor = clamp_f(slider->factor, 0, 1);
@@ -398,18 +397,11 @@ tSlider *ED_slider_create(struct bContext *C)
return slider;
}
-/**
- * For modal operations so the percentage doesn't pop on the first mouse movement.
- */
void ED_slider_init(struct tSlider *slider, const wmEvent *event)
{
- slider->last_cursor[0] = event->x;
- slider->last_cursor[1] = event->y;
+ copy_v2fl_v2i(slider->last_cursor, event->xy);
}
-/**
- * Calculate slider factor based on mouse position.
- */
bool ED_slider_modal(tSlider *slider, const wmEvent *event)
{
bool event_handled = true;
@@ -443,9 +435,6 @@ bool ED_slider_modal(tSlider *slider, const wmEvent *event)
return event_handled;
}
-/**
- * Return string based on the current state of the slider.
- */
void ED_slider_status_string_get(const struct tSlider *slider,
char *status_string,
const size_t size_of_status_string)
@@ -525,16 +514,13 @@ void ED_slider_allow_overshoot_set(struct tSlider *slider, const bool value)
/** \} */
-/**
- * Callback that draws a line between the mouse and a position given as the initial argument.
- */
void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *region, void *arg_info)
{
wmWindow *win = CTX_wm_window(C);
const float *mval_src = (float *)arg_info;
const float mval_dst[2] = {
- win->eventstate->x - region->winrct.xmin,
- win->eventstate->y - region->winrct.ymin,
+ win->eventstate->xy[0] - region->winrct.xmin,
+ win->eventstate->xy[1] - region->winrct.ymin,
};
const uint shdr_pos = GPU_vertformat_attr_add(
@@ -613,9 +599,9 @@ static void metadata_custom_draw_fields(const char *field, const char *value, vo
}
MetadataCustomDrawContext *ctx = (MetadataCustomDrawContext *)ctx_v;
char temp_str[MAX_METADATA_STR];
- BLI_snprintf(temp_str, MAX_METADATA_STR, "%s: %s", field, value);
+ SNPRINTF(temp_str, "%s: %s", field, value);
BLF_position(ctx->fontid, ctx->xmin, ctx->ymin + ctx->current_y, 0.0f);
- BLF_draw(ctx->fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(ctx->fontid, temp_str, sizeof(temp_str));
ctx->current_y += ctx->vertical_offset;
}
@@ -639,18 +625,18 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const
/* first line */
if (i == 0) {
bool do_newline = false;
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[0]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[0]);
if (metadata_is_valid(ibuf, temp_str, 0, len)) {
BLF_position(fontid, xmin, ymax - vertical_offset, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
do_newline = true;
}
- len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[1]);
+ len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[1]);
if (metadata_is_valid(ibuf, temp_str, 1, len)) {
- int line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ int line_width = BLF_width(fontid, temp_str, sizeof(temp_str));
BLF_position(fontid, xmax - line_width, ymax - vertical_offset, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
do_newline = true;
}
@@ -659,32 +645,32 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const
}
} /* Strip */
else if (ELEM(i, 1, 2)) {
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i + 1]);
if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
ofs_y += vertical_offset;
}
} /* Note (wrapped) */
else if (i == 3) {
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i + 1]);
if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
struct ResultBLF info;
BLF_enable(fontid, BLF_WORD_WRAP);
BLF_wordwrap(fontid, ibuf->x - (margin * 2));
BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f);
- BLF_draw_ex(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX, &info);
+ BLF_draw_ex(fontid, temp_str, sizeof(temp_str), &info);
BLF_wordwrap(fontid, 0);
BLF_disable(fontid, BLF_WORD_WRAP);
ofs_y += vertical_offset * info.lines;
}
}
else {
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i + 1]);
if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
- int line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ int line_width = BLF_width(fontid, temp_str, sizeof(temp_str));
BLF_position(fontid, xmax - line_width, ymax - vertical_offset - ofs_y, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
ofs_y += vertical_offset;
}
}
@@ -701,12 +687,12 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const
int ofs_x = 0;
ofs_y = ctx.current_y;
for (int i = 5; i < 10; i++) {
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i]);
if (metadata_is_valid(ibuf, temp_str, i, len)) {
BLF_position(fontid, xmin + ofs_x, ymin + ofs_y, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
- ofs_x += BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX) + UI_UNIT_X;
+ ofs_x += BLF_width(fontid, temp_str, sizeof(temp_str)) + UI_UNIT_X;
}
}
}
@@ -778,9 +764,6 @@ static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top)
return 0;
}
-/**
- * \note Keep in sync with #BKE_image_stamp_buf.
- */
void ED_region_image_metadata_draw(
int x, int y, ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy)
{
diff --git a/source/blender/editors/util/ed_transverts.c b/source/blender/editors/util/ed_transverts.c
index b4a93eb996c..b8efbad1ad9 100644
--- a/source/blender/editors/util/ed_transverts.c
+++ b/source/blender/editors/util/ed_transverts.c
@@ -41,6 +41,7 @@
#include "BKE_editmesh.h"
#include "BKE_lattice.h"
#include "BKE_mesh_iterators.h"
+#include "BKE_object.h"
#include "DEG_depsgraph.h"
@@ -168,11 +169,7 @@ void ED_transverts_update_obedit(TransVertStore *tvs, Object *obedit)
}
}
-static void set_mapped_co(void *vuserdata,
- int index,
- const float co[3],
- const float UNUSED(no[3]),
- const short UNUSED(no_s[3]))
+static void set_mapped_co(void *vuserdata, int index, const float co[3], const float UNUSED(no[3]))
{
void **userdata = vuserdata;
BMEditMesh *em = userdata[0];
@@ -315,9 +312,10 @@ void ED_transverts_create_from_obedit(TransVertStore *tvs, Object *obedit, const
userdata[1] = tvs->transverts;
}
- if (tvs->transverts && em->mesh_eval_cage) {
+ struct Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(obedit);
+ if (tvs->transverts && editmesh_eval_cage) {
BM_mesh_elem_table_ensure(bm, BM_VERT);
- BKE_mesh_foreach_mapped_vert(em->mesh_eval_cage, set_mapped_co, userdata, MESH_FOREACH_NOP);
+ BKE_mesh_foreach_mapped_vert(editmesh_eval_cage, set_mapped_co, userdata, MESH_FOREACH_NOP);
}
}
else if (obedit->type == OB_ARMATURE) {
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 73f328f85d7..0320a2a9a1a 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -33,7 +33,9 @@
#include "BLT_translation.h"
+#include "BKE_collection.h"
#include "BKE_global.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_multires.h"
@@ -121,48 +123,66 @@ void ED_editors_init(bContext *C)
continue;
}
+ /* Reset object to Object mode, so that code below can properly re-switch it to its
+ * previous mode if possible, re-creating its mode data, etc. */
ID *ob_data = ob->data;
ob->mode = OB_MODE_OBJECT;
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
- if (obact && (ob->type == obact->type) && !ID_IS_LINKED(ob) &&
- !(ob_data && ID_IS_LINKED(ob_data))) {
- if (mode == OB_MODE_EDIT) {
- ED_object_editmode_enter_ex(bmain, scene, ob, 0);
- }
- else if (mode == OB_MODE_POSE) {
- ED_object_posemode_enter_ex(bmain, ob);
- }
- else if (mode & OB_MODE_ALL_SCULPT) {
- if (obact == ob) {
- if (mode == OB_MODE_SCULPT) {
- ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, true, reports);
- }
- else if (mode == OB_MODE_VERTEX_PAINT) {
- ED_object_vpaintmode_enter_ex(bmain, depsgraph, scene, ob);
- }
- else if (mode == OB_MODE_WEIGHT_PAINT) {
- ED_object_wpaintmode_enter_ex(bmain, depsgraph, scene, ob);
- }
- else {
- BLI_assert_unreachable();
- }
+
+ /* Object mode is enforced if there is no active object, or if the active object's type is
+ * different. */
+ if (obact == NULL || ob->type != obact->type) {
+ continue;
+ }
+ /* Object mode is enforced for linked data (or their obdata). */
+ if (ID_IS_LINKED(ob) || (ob_data != NULL && ID_IS_LINKED(ob_data))) {
+ continue;
+ }
+
+ /* Pose mode is very similar to Object one, we can apply it even on objects not in current
+ * scene. */
+ if (mode == OB_MODE_POSE) {
+ ED_object_posemode_enter_ex(bmain, ob);
+ }
+
+ /* Other edit/paint/etc. modes are only settable for objects in active scene currently. */
+ if (!BKE_collection_has_object_recursive(scene->master_collection, ob)) {
+ continue;
+ }
+
+ if (mode == OB_MODE_EDIT) {
+ ED_object_editmode_enter_ex(bmain, scene, ob, 0);
+ }
+ else if (mode & OB_MODE_ALL_SCULPT) {
+ if (obact == ob) {
+ if (mode == OB_MODE_SCULPT) {
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, true, reports);
+ }
+ else if (mode == OB_MODE_VERTEX_PAINT) {
+ ED_object_vpaintmode_enter_ex(bmain, depsgraph, scene, ob);
+ }
+ else if (mode == OB_MODE_WEIGHT_PAINT) {
+ ED_object_wpaintmode_enter_ex(bmain, depsgraph, scene, ob);
}
else {
- /* Create data for non-active objects which need it for
- * mode-switching but don't yet support multi-editing. */
- if (mode & OB_MODE_ALL_SCULPT) {
- ob->mode = mode;
- BKE_object_sculpt_data_create(ob);
- }
+ BLI_assert_unreachable();
}
}
else {
- /* TODO(campbell): avoid operator calls. */
- if (obact == ob) {
- ED_object_mode_set(C, mode);
+ /* Create data for non-active objects which need it for
+ * mode-switching but don't yet support multi-editing. */
+ if (mode & OB_MODE_ALL_SCULPT) {
+ ob->mode = mode;
+ BKE_object_sculpt_data_create(ob);
}
}
}
+ else {
+ /* TODO(campbell): avoid operator calls. */
+ if (obact == ob) {
+ ED_object_mode_set(C, mode);
+ }
+ }
}
/* image editor paint mode */
@@ -176,7 +196,6 @@ void ED_editors_init(bContext *C)
wm->op_undo_depth--;
}
-/* frees all editmode stuff */
void ED_editors_exit(Main *bmain, bool do_undo_system)
{
if (!bmain) {
@@ -272,8 +291,6 @@ bool ED_editors_flush_edits_for_object(Main *bmain, Object *ob)
return ED_editors_flush_edits_for_object_ex(bmain, ob, false, false);
}
-/* flush any temp data from object editing to DNA before writing files,
- * rendering, copying, etc. */
bool ED_editors_flush_edits_ex(Main *bmain, bool for_render, bool check_needs_flush)
{
bool has_edited = false;
@@ -298,11 +315,6 @@ bool ED_editors_flush_edits(Main *bmain)
/* ***** XXX: functions are using old blender names, cleanup later ***** */
-/**
- * Now only used in 2D spaces, like time, f-curve, NLA, image, etc.
- *
- * \note Shift/Control are not configurable key-bindings.
- */
void apply_keyb_grid(
int shift, int ctrl, float *val, float fac1, float fac2, float fac3, int invert)
{
@@ -341,6 +353,7 @@ void unpack_menu(bContext *C,
uiLayout *layout;
char line[FILE_MAX + 100];
wmOperatorType *ot = WM_operatortype_find(opname, 1);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
pup = UI_popup_menu_begin(C, IFACE_("Unpack File"), ICON_NONE);
layout = UI_popup_menu_layout(pup);
@@ -350,13 +363,13 @@ void unpack_menu(bContext *C,
RNA_enum_set(&props_ptr, "method", PF_REMOVE);
RNA_string_set(&props_ptr, "id", id_name);
- if (G.relbase_valid) {
+ if (blendfile_path[0] != '\0') {
char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
BLI_split_file_part(abs_name, fi, sizeof(fi));
BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi);
if (!STREQ(abs_name, local_name)) {
- switch (BKE_packedfile_compare_to_file(BKE_main_blendfile_path(bmain), local_name, pf)) {
+ switch (BKE_packedfile_compare_to_file(blendfile_path, local_name, pf)) {
case PF_CMP_NOFILE:
BLI_snprintf(line, sizeof(line), TIP_("Create %s"), local_name);
uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr);
@@ -389,7 +402,7 @@ void unpack_menu(bContext *C,
}
}
- switch (BKE_packedfile_compare_to_file(BKE_main_blendfile_path(bmain), abs_name, pf)) {
+ switch (BKE_packedfile_compare_to_file(blendfile_path, abs_name, pf)) {
case PF_CMP_NOFILE:
BLI_snprintf(line, sizeof(line), TIP_("Create %s"), abs_name);
// uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL);
@@ -422,16 +435,27 @@ void unpack_menu(bContext *C,
UI_popup_menu_end(C, pup);
}
-/**
- * Use to free ID references within runtime data (stored outside of DNA)
- *
- * \param new_id: may be NULL to unlink \a old_id.
- */
-void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, ID *old_id, ID *new_id)
+void ED_spacedata_id_remap(struct ScrArea *area,
+ struct SpaceLink *sl,
+ const struct IDRemapper *mappings)
+{
+ SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
+ if (st && st->id_remap) {
+ st->id_remap(area, sl, mappings);
+ }
+}
+
+void ED_spacedata_id_remap_single(struct ScrArea *area,
+ struct SpaceLink *sl,
+ ID *old_id,
+ ID *new_id)
{
SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
if (st && st->id_remap) {
- st->id_remap(area, sl, old_id, new_id);
+ struct IDRemapper *mappings = BKE_id_remapper_create();
+ BKE_id_remapper_add(mappings, old_id, new_id);
+ st->id_remap(area, sl, mappings);
+ BKE_id_remapper_free(mappings);
}
}
diff --git a/source/blender/editors/util/ed_util_imbuf.c b/source/blender/editors/util/ed_util_imbuf.c
index fcbc0807893..2e983eeff39 100644
--- a/source/blender/editors/util/ed_util_imbuf.c
+++ b/source/blender/editors/util/ed_util_imbuf.c
@@ -278,13 +278,13 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
/* XXX node curve integration. */
#if 0
{
- ScrArea *sa, *cur = curarea;
+ ScrArea *area, *cur = curarea;
node_curvemap_sample(fp); /* sends global to node editor */
- for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_NODE) {
- areawinset(sa->win);
- scrarea_do_windraw(sa);
+ for (area = G.curscreen->areabase.first; area; area = area->next) {
+ if (area->spacetype == SPACE_NODE) {
+ areawinset(area->win);
+ scrarea_do_windraw(area);
}
}
node_curvemap_sample(NULL); /* clears global in node editor */
@@ -312,7 +312,6 @@ static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *e
float fx, fy;
if (ibuf == NULL) {
- IMB_freeImBuf(ibuf);
info->draw = 0;
return;
}
@@ -386,14 +385,20 @@ static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *e
static void ed_imbuf_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
-
- if (sa && sa->spacetype == SPACE_IMAGE) {
- image_sample_apply(C, op, event);
+ ScrArea *area = CTX_wm_area(C);
+ if (area == NULL) {
+ return;
}
- if (sa && sa->spacetype == SPACE_SEQ) {
- sequencer_sample_apply(C, op, event);
+ switch (area->spacetype) {
+ case SPACE_IMAGE: {
+ image_sample_apply(C, op, event);
+ break;
+ }
+ case SPACE_SEQ: {
+ sequencer_sample_apply(C, op, event);
+ break;
+ }
}
}
@@ -427,9 +432,9 @@ void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info)
info->zfp);
if (info->sample_size > 1) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_IMAGE) {
+ if (area && area->spacetype == SPACE_IMAGE) {
const wmWindow *win = CTX_wm_window(C);
const wmEvent *event = win->eventstate;
@@ -446,7 +451,7 @@ void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info)
rctf sample_rect_fl;
BLI_rctf_init_pt_radius(
&sample_rect_fl,
- (float[2]){event->x - region->winrct.xmin, event->y - region->winrct.ymin},
+ (float[2]){event->xy[0] - region->winrct.xmin, event->xy[1] - region->winrct.ymin},
(float)(info->sample_size / 2.0f) * sima->zoom);
GPU_logic_op_xor_set(true);
@@ -477,9 +482,29 @@ void ED_imbuf_sample_exit(bContext *C, wmOperator *op)
int ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
- ImageSampleInfo *info;
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
+ case SPACE_IMAGE: {
+ SpaceImage *sima = area->spacedata.first;
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ if (ED_space_image_show_cache_and_mval_over(sima, region, event->mval)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+ }
+ if (!ED_space_image_has_buffer(sima)) {
+ return OPERATOR_CANCELLED;
+ }
+ break;
+ }
+ case SPACE_SEQ: {
+ /* Sequencer checks could be added. */
+ break;
+ }
+ }
+ }
- info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
+ ImageSampleInfo *info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
info->art = region->type;
info->draw_handle = ED_region_draw_cb_activate(
@@ -487,22 +512,6 @@ int ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
info->sample_size = RNA_int_get(op->ptr, "size");
op->customdata = info;
- ScrArea *sa = CTX_wm_area(C);
-
- if (sa && sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = CTX_wm_space_image(C);
-
- if (region->regiontype == RGN_TYPE_WINDOW) {
- if (event->mval[1] <= 16 && ED_space_image_show_cache(sima)) {
- return OPERATOR_PASS_THROUGH;
- }
- }
-
- if (!ED_space_image_has_buffer(sima)) {
- return OPERATOR_CANCELLED;
- }
- }
-
ed_imbuf_sample_apply(C, op, event);
WM_event_add_modal_handler(C, op);
@@ -535,37 +544,42 @@ void ED_imbuf_sample_cancel(bContext *C, wmOperator *op)
bool ED_imbuf_sample_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
-
- if (sa && sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = CTX_wm_space_image(C);
- if (sima == NULL) {
- return false;
- }
+ ScrArea *area = CTX_wm_area(C);
+ if (area == NULL) {
+ return false;
+ }
- Object *obedit = CTX_data_edit_object(C);
- if (obedit) {
- /* Disable when UV editing so it doesn't swallow all click events
- * (use for setting cursor). */
- if (ED_space_image_show_uvedit(sima, obedit)) {
+ switch (area->spacetype) {
+ case SPACE_IMAGE: {
+ SpaceImage *sima = area->spacedata.first;
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit) {
+ /* Disable when UV editing so it doesn't swallow all click events
+ * (use for setting cursor). */
+ if (ED_space_image_show_uvedit(sima, obedit)) {
+ return false;
+ }
+ }
+ else if (sima->mode != SI_MODE_VIEW) {
return false;
}
+ return true;
}
- else if (sima->mode != SI_MODE_VIEW) {
- return false;
- }
-
- return true;
- }
-
- if (sa && sa->spacetype == SPACE_SEQ) {
- SpaceSeq *sseq = CTX_wm_space_seq(C);
+ case SPACE_SEQ: {
+ SpaceSeq *sseq = area->spacedata.first;
- if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
- return false;
+ if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
+ return false;
+ }
+ if (SEQ_editing_get(CTX_data_scene(C)) == NULL) {
+ return false;
+ }
+ ARegion *region = CTX_wm_region(C);
+ if (!(region && (region->regiontype == RGN_TYPE_PREVIEW))) {
+ return false;
+ }
+ return true;
}
-
- return sseq && SEQ_editing_get(CTX_data_scene(C)) != NULL;
}
return false;
diff --git a/source/blender/editors/util/ed_util_ops.cc b/source/blender/editors/util/ed_util_ops.cc
index 7d32d252718..ae37dab7bb4 100644
--- a/source/blender/editors/util/ed_util_ops.cc
+++ b/source/blender/editors/util/ed_util_ops.cc
@@ -110,7 +110,7 @@ static void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot)
ot->invoke = WM_operator_filesel;
/* flags */
- ot->flag = OPTYPE_INTERNAL;
+ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE,
@@ -121,6 +121,22 @@ static void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot)
FILE_SORT_DEFAULT);
}
+static bool lib_id_generate_preview_poll(bContext *C)
+{
+ if (!lib_id_preview_editing_poll(C)) {
+ return false;
+ }
+
+ const PointerRNA idptr = CTX_data_pointer_get(C, "id");
+ const ID *id = (ID *)idptr.data;
+ if (GS(id->name) == ID_NT) {
+ CTX_wm_operator_poll_msg_set(C, TIP_("Can't generate automatic preview for node group"));
+ return false;
+ }
+
+ return true;
+}
+
static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op))
{
PointerRNA idptr = CTX_data_pointer_get(C, "id");
@@ -148,13 +164,57 @@ static void ED_OT_lib_id_generate_preview(wmOperatorType *ot)
ot->idname = "ED_OT_lib_id_generate_preview";
/* api callbacks */
- ot->poll = lib_id_preview_editing_poll;
+ ot->poll = lib_id_generate_preview_poll;
ot->exec = lib_id_generate_preview_exec;
/* flags */
ot->flag = OPTYPE_INTERNAL | OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static bool lib_id_generate_preview_from_object_poll(bContext *C)
+{
+ if (!lib_id_preview_editing_poll(C)) {
+ return false;
+ }
+ if (CTX_data_active_object(C) == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+static int lib_id_generate_preview_from_object_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PointerRNA idptr = CTX_data_pointer_get(C, "id");
+ ID *id = (ID *)idptr.data;
+
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+
+ Object *object_to_render = CTX_data_active_object(C);
+
+ BKE_previewimg_id_free(id);
+ PreviewImage *preview_image = BKE_previewimg_id_ensure(id);
+ UI_icon_render_id_ex(C, nullptr, &object_to_render->id, ICON_SIZE_PREVIEW, true, preview_image);
+
+ WM_event_add_notifier(C, NC_ASSET | NA_EDITED, nullptr);
+ ED_assetlist_storage_tag_main_data_dirty();
+
+ return OPERATOR_FINISHED;
+}
+
+static void ED_OT_lib_id_generate_preview_from_object(wmOperatorType *ot)
+{
+ ot->name = "Generate Preview from Object";
+ ot->description = "Create a preview for this asset by rendering the active object";
+ ot->idname = "ED_OT_lib_id_generate_preview_from_object";
+
+ /* api callbacks */
+ ot->poll = lib_id_generate_preview_from_object_poll;
+ ot->exec = lib_id_generate_preview_from_object_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_INTERNAL | OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -276,10 +336,11 @@ static void ED_OT_flush_edits(wmOperatorType *ot)
/** \} */
-void ED_operatortypes_edutils(void)
+void ED_operatortypes_edutils()
{
WM_operatortype_append(ED_OT_lib_id_load_custom_preview);
WM_operatortype_append(ED_OT_lib_id_generate_preview);
+ WM_operatortype_append(ED_OT_lib_id_generate_preview_from_object);
WM_operatortype_append(ED_OT_lib_id_fake_user_toggle);
WM_operatortype_append(ED_OT_lib_id_unlink);
diff --git a/source/blender/editors/util/gizmo_utils.c b/source/blender/editors/util/gizmo_utils.c
index 08e7b3a9a0a..99df194f0eb 100644
--- a/source/blender/editors/util/gizmo_utils.c
+++ b/source/blender/editors/util/gizmo_utils.c
@@ -70,7 +70,6 @@ bool ED_gizmo_poll_or_unlink_delayed_from_tool_ex(const bContext *C,
return true;
}
-/** Can use this as poll function directly. */
bool ED_gizmo_poll_or_unlink_delayed_from_tool(const bContext *C, wmGizmoGroupType *gzgt)
{
return ED_gizmo_poll_or_unlink_delayed_from_tool_ex(C, gzgt, gzgt->idname);
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index d0eed6a6eb1..583e4060a9a 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -98,7 +98,6 @@ void initNumInput(NumInput *n)
n->str_cur = 0;
}
-/* str must be NUM_STR_REP_LEN * (idx_max + 1) length. */
void outputNumInput(NumInput *n, char *str, UnitSettings *unit_settings)
{
short j;
@@ -201,9 +200,6 @@ bool hasNumInput(const NumInput *n)
return false;
}
-/**
- * \warning \a vec must be set beforehand otherwise we risk uninitialized vars.
- */
bool applyNumInput(NumInput *n, float *vec)
{
short i, j;
@@ -472,8 +468,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
return true;
case EVT_PADPERIOD:
case EVT_PERIODKEY:
- /* Force numdot, some OSs/countries generate a comma char in this case,
- * sic... (T37992) */
+ /* Force number-pad "." since some OS's/countries generate a comma char, see: T37992 */
ascii[0] = '.';
utf8_buf = ascii;
break;
diff --git a/source/blender/editors/util/select_utils.c b/source/blender/editors/util/select_utils.c
index 5681edd2f5c..c7bb26db1bd 100644
--- a/source/blender/editors/util/select_utils.c
+++ b/source/blender/editors/util/select_utils.c
@@ -18,15 +18,14 @@
* \ingroup edutil
*/
+#include <float.h>
+
#include "BLI_kdtree.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "ED_select_utils.h"
-#include "float.h"
-
-/** 1: select, 0: deselect, -1: pass. */
int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside)
{
switch (sel_op) {
@@ -44,12 +43,6 @@ int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool
BLI_assert_msg(0, "invalid sel_op");
return -1;
}
-/**
- * Use when we've de-selected all items first (for modes that need it).
- *
- * \note In some cases changing selection needs to perform other checks,
- * so it's more straightforward to deselect all, then select.
- */
int ED_select_op_action_deselected(const eSelectOp sel_op,
const bool is_select,
const bool is_inside)
@@ -71,9 +64,6 @@ int ED_select_op_action_deselected(const eSelectOp sel_op,
return -1;
}
-/**
- * Utility to use for selection operations that run multiple times (circle select).
- */
eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first)
{
if (sel_op == SEL_OP_SET) {
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index cd8fbd00316..9646444c103 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -74,13 +74,13 @@ typedef struct UvNearestHit {
bool uv_find_nearest_vert(struct Scene *scene,
struct Object *obedit,
const float co[2],
- const float penalty_dist,
+ float penalty_dist,
struct UvNearestHit *hit);
bool uv_find_nearest_vert_multi(struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
- const float penalty_dist,
+ float penalty_dist,
struct UvNearestHit *hit);
bool uv_find_nearest_edge(struct Scene *scene,
@@ -89,28 +89,37 @@ bool uv_find_nearest_edge(struct Scene *scene,
struct UvNearestHit *hit);
bool uv_find_nearest_edge_multi(struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
struct UvNearestHit *hit);
+/**
+ * \param only_in_face: when true, only hit faces which `co` is inside.
+ * This gives users a result they might expect, especially when zoomed in.
+ *
+ * \note Concave faces can cause odd behavior, although in practice this isn't often an issue.
+ * The center can be outside the face, in this case the distance to the center
+ * could cause the face to be considered too far away.
+ * If this becomes an issue we could track the distance to the faces closest edge.
+ */
bool uv_find_nearest_face_ex(struct Scene *scene,
struct Object *obedit,
const float co[2],
struct UvNearestHit *hit,
- const bool only_in_face);
+ bool only_in_face);
bool uv_find_nearest_face(struct Scene *scene,
struct Object *obedit,
const float co[2],
struct UvNearestHit *hit);
bool uv_find_nearest_face_multi_ex(struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
struct UvNearestHit *hit,
- const bool only_in_face);
+ bool only_in_face);
bool uv_find_nearest_face_multi(struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
struct UvNearestHit *hit);
@@ -153,10 +162,14 @@ void UV_OT_shortest_path_select(struct wmOperatorType *ot);
bool uvedit_select_is_any_selected(struct Scene *scene, struct Object *obedit);
bool uvedit_select_is_any_selected_multi(struct Scene *scene,
struct Object **objects,
- const uint objects_len);
+ uint objects_len);
+/**
+ * \warning This returns first selected UV,
+ * not ideal in many cases since there could be multiple.
+ */
const float *uvedit_first_selected_uv_from_vertex(struct Scene *scene,
struct BMVert *eve,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
void UV_OT_select_all(struct wmOperatorType *ot);
void UV_OT_select(struct wmOperatorType *ot);
diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.c
index 62173f4eaff..63a7ab6ab2d 100644
--- a/source/blender/editors/uvedit/uvedit_islands.c
+++ b/source/blender/editors/uvedit/uvedit_islands.c
@@ -237,8 +237,7 @@ static void bm_face_array_uv_scale_y(BMFace **faces,
/** \name UDIM packing helper functions
* \{ */
-/* Returns true if UV coordinates lie on a valid tile in UDIM grid or tiled image. */
-bool uv_coords_isect_udim(const Image *image, const int udim_grid[2], float coords[2])
+bool uv_coords_isect_udim(const Image *image, const int udim_grid[2], const float coords[2])
{
const float coords_floor[2] = {floorf(coords[0]), floorf(coords[1])};
const bool is_tiled_image = image && (image->source == IMA_SRC_TILED);
@@ -452,11 +451,9 @@ static int bm_mesh_calc_uv_islands(const Scene *scene,
* \{ */
void ED_uvedit_pack_islands_multi(const Scene *scene,
- const SpaceImage *sima,
Object **objects,
const uint objects_len,
- const bool use_target_udim,
- int target_udim,
+ const struct UVMapUDIM_Params *udim_params,
const struct UVPackIsland_Params *params)
{
/* Align to the Y axis, could make this configurable. */
@@ -512,7 +509,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list, index) {
/* Skip calculation if using specified UDIM option. */
- if (!use_target_udim) {
+ if (udim_params && (udim_params->use_target_udim == false)) {
float bounds_min[2], bounds_max[2];
INIT_MINMAX2(bounds_min, bounds_max);
for (int i = 0; i < island->faces_len; i++) {
@@ -525,6 +522,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
selection_max_co[0] = MAX2(bounds_max[0], selection_max_co[0]);
selection_max_co[1] = MAX2(bounds_max[1], selection_max_co[1]);
}
+
if (params->rotate) {
if (island->aspect_y != 1.0f) {
bm_face_array_uv_scale_y(
@@ -559,7 +557,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
/* Center of bounding box containing all selected UVs. */
float selection_center[2];
- if (!use_target_udim) {
+ if (udim_params && (udim_params->use_target_udim == false)) {
selection_center[0] = (selection_min_co[0] + selection_max_co[0]) / 2.0f;
selection_center[1] = (selection_min_co[1] + selection_max_co[1]) / 2.0f;
}
@@ -590,24 +588,22 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
/* Tile offset. */
float base_offset[2] = {0.0f, 0.0f};
+ /* CASE: ignore UDIM. */
+ if (udim_params == NULL) {
+ /* pass */
+ }
/* CASE: Active/specified(smart uv project) UDIM. */
- if (use_target_udim) {
+ else if (udim_params->use_target_udim) {
+
/* Calculate offset based on specified_tile_index. */
- base_offset[0] = (target_udim - 1001) % 10;
- base_offset[1] = (target_udim - 1001) / 10;
+ base_offset[0] = (udim_params->target_udim - 1001) % 10;
+ base_offset[1] = (udim_params->target_udim - 1001) / 10;
}
/* CASE: Closest UDIM. */
else {
- const Image *image;
- int udim_grid[2] = {1, 1};
- /* To handle cases where `sima == NULL` - Smart UV project in 3D viewport. */
- if (sima != NULL) {
- image = sima->image;
- udim_grid[0] = sima->tile_grid_shape[0];
- udim_grid[1] = sima->tile_grid_shape[1];
- }
-
+ const Image *image = udim_params->image;
+ const int *udim_grid = udim_params->grid_shape;
/* Check if selection lies on a valid UDIM grid tile. */
bool is_valid_udim = uv_coords_isect_udim(image, udim_grid, selection_center);
if (is_valid_udim) {
@@ -643,8 +639,8 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
island->bounds_rect.ymin,
};
const float offset[2] = {
- (boxarray[i].x * scale[0]) - island->bounds_rect.xmin + base_offset[0],
- (boxarray[i].y * scale[1]) - island->bounds_rect.ymin + base_offset[1],
+ ((boxarray[i].x * scale[0]) - island->bounds_rect.xmin) + base_offset[0],
+ ((boxarray[i].y * scale[1]) - island->bounds_rect.ymin) + base_offset[1],
};
for (int j = 0; j < island->faces_len; j++) {
BMFace *efa = island->faces[j];
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 0757e177235..64e1fa2f768 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -180,7 +180,7 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i
if (node && is_image_texture_node(node)) {
node->id = &ima->id;
- ED_node_tag_update_nodetree(bmain, ma->nodetree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ma->nodetree);
}
}
@@ -253,7 +253,6 @@ bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float r_min[2], float
return ED_uvedit_minmax_multi(scene, &obedit, 1, r_min, r_max);
}
-/* Be careful when using this, it bypasses all synchronization options */
void ED_uvedit_select_all(BMesh *bm)
{
BMFace *efa;
@@ -1765,11 +1764,9 @@ static int uv_set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *e
float location[2];
if (region->regiontype == RGN_TYPE_WINDOW) {
- if (event->mval[1] <= 16) {
- SpaceImage *sima = CTX_wm_space_image(C);
- if (sima && ED_space_image_show_cache(sima)) {
- return OPERATOR_PASS_THROUGH;
- }
+ SpaceImage *sima = CTX_wm_space_image(C);
+ if (sima && ED_space_image_show_cache_and_mval_over(sima, region, event->mval)) {
+ return OPERATOR_PASS_THROUGH;
}
}
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 86390882bed..72fd31503de 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -148,10 +148,6 @@ BMLoop *ED_uvedit_active_edge_loop_get(BMesh *bm)
/** \name Visibility and Selection Utilities
* \{ */
-/**
- * Intentionally don't return #UV_SELECT_ISLAND as it's not an element type.
- * In this case return #UV_SELECT_VERTEX as a fallback.
- */
char ED_uvedit_select_mode_get(const Scene *scene)
{
const ToolSettings *ts = scene->toolsettings;
@@ -719,15 +715,6 @@ bool uv_find_nearest_edge_multi(
return found;
}
-/**
- * \param only_in_face: when true, only hit faces which `co` is inside.
- * This gives users a result they might expect, especially when zoomed in.
- *
- * \note Concave faces can cause odd behavior, although in practice this isn't often an issue.
- * The center can be outside the face, in this case the distance to the center
- * could cause the face to be considered too far away.
- * If this becomes an issue we could track the distance to the faces closest edge.
- */
bool uv_find_nearest_face_ex(
Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit, const bool only_in_face)
{
@@ -1542,10 +1529,6 @@ static void uv_select_linked_multi(Scene *scene,
}
}
-/**
- * \warning This returns first selected UV,
- * not ideal in many cases since there could be multiple.
- */
const float *uvedit_first_selected_uv_from_vertex(Scene *scene,
BMVert *eve,
const int cd_loop_uv_offset)
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 4e183732db9..362e020f306 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -118,7 +118,7 @@ static bool ED_uvedit_ensure_uvs(Object *obedit)
int cd_loop_uv_offset;
if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
- ED_mesh_uv_texture_add(obedit->data, NULL, true, true);
+ ED_mesh_uv_texture_add(obedit->data, NULL, true, true, NULL);
}
/* Happens when there are no faces. */
@@ -145,6 +145,60 @@ static bool ED_uvedit_ensure_uvs(Object *obedit)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name UDIM Access
+ * \{ */
+
+bool ED_uvedit_udim_params_from_image_space(const SpaceImage *sima,
+ bool use_active,
+ struct UVMapUDIM_Params *udim_params)
+{
+ memset(udim_params, 0, sizeof(*udim_params));
+
+ udim_params->grid_shape[0] = 1;
+ udim_params->grid_shape[1] = 1;
+ udim_params->target_udim = 0;
+ udim_params->use_target_udim = false;
+
+ if (sima == NULL) {
+ return false;
+ }
+
+ udim_params->image = sima->image;
+ udim_params->grid_shape[0] = sima->tile_grid_shape[0];
+ udim_params->grid_shape[1] = sima->tile_grid_shape[1];
+
+ if (use_active) {
+ int active_udim = 1001;
+ /* NOTE: Presently, when UDIM grid and tiled image are present together, only active tile for
+ * the tiled image is considered. */
+ const Image *image = sima->image;
+ if (image && image->source == IMA_SRC_TILED) {
+ ImageTile *active_tile = BLI_findlink(&image->tiles, image->active_tile_index);
+ if (active_tile) {
+ active_udim = active_tile->tile_number;
+ }
+ }
+ else {
+ /* TODO: Support storing an active UDIM when there are no tiles present.
+ * Until then, use 2D cursor to find the active tile index for the UDIM grid. */
+ if (uv_coords_isect_udim(sima->image, sima->tile_grid_shape, sima->cursor)) {
+ int tile_number = 1001;
+ tile_number += floorf(sima->cursor[1]) * 10;
+ tile_number += floorf(sima->cursor[0]);
+ active_udim = tile_number;
+ }
+ }
+
+ udim_params->target_udim = active_udim;
+ udim_params->use_target_udim = true;
+ }
+
+ return true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Parametrizer Conversion
* \{ */
@@ -1040,7 +1094,6 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
/* RNA props */
const bool rotate = RNA_boolean_get(op->ptr, "rotate");
const int udim_source = RNA_enum_get(op->ptr, "udim_source");
- bool use_target_udim = false;
if (RNA_struct_property_is_set(op->ptr, "margin")) {
scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
}
@@ -1048,46 +1101,15 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
}
- int target_udim = 1001;
- if (udim_source == PACK_UDIM_SRC_CLOSEST) {
- /* pass */
- }
- else if (udim_source == PACK_UDIM_SRC_ACTIVE) {
- int active_udim = 1001;
- /* NOTE: Presently, when UDIM grid and tiled image are present together, only active tile for
- * the tiled imgae is considered. */
- if (sima && sima->image) {
- Image *image = sima->image;
- ImageTile *active_tile = BLI_findlink(&image->tiles, image->active_tile_index);
- if (active_tile) {
- active_udim = active_tile->tile_number;
- }
- }
- else if (sima && !sima->image) {
- /* Use 2D cursor to find the active tile index for the UDIM grid. */
- float cursor_loc[2] = {sima->cursor[0], sima->cursor[1]};
- if (uv_coords_isect_udim(sima->image, sima->tile_grid_shape, cursor_loc)) {
- int tile_number = 1001;
- tile_number += floorf(cursor_loc[1]) * 10;
- tile_number += floorf(cursor_loc[0]);
- active_udim = tile_number;
- }
- /* TODO: Support storing an active UDIM when there are no tiles present. */
- }
-
- target_udim = active_udim;
- use_target_udim = true;
- }
- else {
- BLI_assert_unreachable();
- }
+ struct UVMapUDIM_Params udim_params;
+ const bool use_active = (udim_source == PACK_UDIM_SRC_ACTIVE);
+ const bool use_udim_params = ED_uvedit_udim_params_from_image_space(
+ sima, use_active, &udim_params);
ED_uvedit_pack_islands_multi(scene,
- sima,
objects,
objects_len,
- use_target_udim,
- target_udim,
+ use_udim_params ? &udim_params : NULL,
&(struct UVPackIsland_Params){
.rotate = rotate,
.rotate_align_axis = -1,
@@ -2114,7 +2136,6 @@ static int smart_project_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- const SpaceImage *sima = CTX_wm_space_image(C);
/* May be NULL. */
View3D *v3d = CTX_wm_view3d(C);
@@ -2125,7 +2146,6 @@ static int smart_project_exec(bContext *C, wmOperator *op)
const float project_angle_limit_cos = cosf(project_angle_limit);
const float project_angle_limit_half_cos = cosf(project_angle_limit / 2);
- const int target_udim = 1001; /* 0-1 UV space. */
/* Memory arena for list links (cleared for each object). */
MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
@@ -2265,11 +2285,9 @@ static int smart_project_exec(bContext *C, wmOperator *op)
/* Depsgraph refresh functions are called here. */
const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
ED_uvedit_pack_islands_multi(scene,
- sima,
objects_changed,
object_changed_len,
- true,
- target_udim,
+ NULL,
&(struct UVPackIsland_Params){
.rotate = true,
/* We could make this optional. */
@@ -2808,6 +2826,8 @@ void UV_OT_cylinder_project(wmOperatorType *ot)
uv_map_clip_correct_properties(ot);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Cube UV Project Operator
* \{ */
diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt
index b7eaf018dba..d16787714c9 100644
--- a/source/blender/freestyle/CMakeLists.txt
+++ b/source/blender/freestyle/CMakeLists.txt
@@ -594,4 +594,7 @@ if(WIN32)
endif()
blender_add_lib(bf_freestyle "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
-blender_precompile_headers(bf_freestyle FRS_precomp.cpp FRS_precomp.h)
+
+if(COMMAND target_precompile_headers)
+ target_precompile_headers(bf_freestyle PRIVATE FRS_precomp.h)
+endif()
diff --git a/source/blender/freestyle/FRS_freestyle.h b/source/blender/freestyle/FRS_freestyle.h
index bc5e9d49bee..77e906c6ea5 100644
--- a/source/blender/freestyle/FRS_freestyle.h
+++ b/source/blender/freestyle/FRS_freestyle.h
@@ -59,6 +59,10 @@ void FRS_exit(void);
void FRS_copy_active_lineset(struct FreestyleConfig *config);
void FRS_paste_active_lineset(struct FreestyleConfig *config);
void FRS_delete_active_lineset(struct FreestyleConfig *config);
+/**
+ * Reinsert the active lineset at an offset \a direction from current position.
+ * \return if position of active lineset has changed.
+ */
bool FRS_move_active_lineset(struct FreestyleConfig *config, int direction);
/* Testing */
diff --git a/source/blender/freestyle/FRS_precomp.cpp b/source/blender/freestyle/FRS_precomp.cpp
deleted file mode 100644
index 7e50a47f45b..00000000000
--- a/source/blender/freestyle/FRS_precomp.cpp
+++ /dev/null
@@ -1,2 +0,0 @@
-/* Pre-compiled headers, see: D2606. */
-#include "FRS_precomp.h"
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 0a82c237256..455d3b5b236 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -48,6 +48,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -415,7 +416,7 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain,
}
nodeSetActive(ntree, output_material);
- ntreeUpdateTree(bmain, ntree);
+ BKE_ntree_update_main_tree(bmain, ntree, nullptr);
return ma;
}
@@ -684,9 +685,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
vertices->co[0] = svRep[0]->point2d()[0];
vertices->co[1] = svRep[0]->point2d()[1];
vertices->co[2] = get_stroke_vertex_z();
- vertices->no[0] = 0;
- vertices->no[1] = 0;
- vertices->no[2] = SHRT_MAX;
+
++vertices;
++vertex_index;
@@ -694,9 +693,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
vertices->co[0] = svRep[1]->point2d()[0];
vertices->co[1] = svRep[1]->point2d()[1];
vertices->co[2] = get_stroke_vertex_z();
- vertices->no[0] = 0;
- vertices->no[1] = 0;
- vertices->no[2] = SHRT_MAX;
+
++vertices;
++vertex_index;
@@ -712,9 +709,6 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
vertices->co[0] = svRep[2]->point2d()[0];
vertices->co[1] = svRep[2]->point2d()[1];
vertices->co[2] = get_stroke_vertex_z();
- vertices->no[0] = 0;
- vertices->no[1] = 0;
- vertices->no[2] = SHRT_MAX;
++vertices;
++vertex_index;
@@ -820,6 +814,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
} // loop over strokes
BKE_object_materials_test(freestyle_bmain, object_mesh, (ID *)mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
#if 0 // XXX
BLI_assert(mesh->totvert == vertex_index);
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index c74fd60fe35..ce80ed78594 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -86,8 +86,8 @@ static void load_post_callback(struct Main * /*main*/,
}
static bCallbackFuncStore load_post_callback_funcstore = {
- nullptr,
- nullptr, /* next, prev */
+ nullptr, /* next */
+ nullptr, /* prev */
load_post_callback, /* func */
nullptr, /* arg */
0 /* alloc */
@@ -494,7 +494,7 @@ void FRS_composite_result(Render *re, ViewLayer *view_layer, Render *freestyle_r
if (view_layer->freestyle_config.flags & FREESTYLE_AS_RENDER_PASS) {
// Create a blank render pass output.
RE_create_render_pass(
- re->result, RE_PASSNAME_FREESTYLE, 4, "RGBA", view_layer->name, re->viewname);
+ re->result, RE_PASSNAME_FREESTYLE, 4, "RGBA", view_layer->name, re->viewname, true);
}
return;
}
@@ -530,7 +530,7 @@ void FRS_composite_result(Render *re, ViewLayer *view_layer, Render *freestyle_r
if (view_layer->freestyle_config.flags & FREESTYLE_AS_RENDER_PASS) {
RE_create_render_pass(
- re->result, RE_PASSNAME_FREESTYLE, 4, "RGBA", view_layer->name, re->viewname);
+ re->result, RE_PASSNAME_FREESTYLE, 4, "RGBA", view_layer->name, re->viewname, true);
dest = RE_RenderLayerGetPass(rl, RE_PASSNAME_FREESTYLE, re->viewname);
}
else {
@@ -769,10 +769,6 @@ void FRS_delete_active_lineset(FreestyleConfig *config)
}
}
-/**
- * Reinsert the active lineset at an offset \a direction from current position.
- * \return if position of active lineset has changed.
- */
bool FRS_move_active_lineset(FreestyleConfig *config, int direction)
{
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
diff --git a/source/blender/freestyle/intern/image/GaussianFilter.h b/source/blender/freestyle/intern/image/GaussianFilter.h
index 2cb3e7d7ac5..f6bfdbd31b0 100644
--- a/source/blender/freestyle/intern/image/GaussianFilter.h
+++ b/source/blender/freestyle/intern/image/GaussianFilter.h
@@ -37,14 +37,16 @@ namespace Freestyle {
class GaussianFilter {
protected:
/* The mask is a symmetrical 2d array (with respect to the middle point).
- * Thus, M(i,j) = M(-i,j) = M(i,-j) = M(-i,-j).
- * For this reason, to represent a NxN array (N odd), we only store a ((N+1)/2)x((N+1)/2) array.
- */
+ * Thus: `M(i,j) = M(-i,j) = M(i,-j) = M(-i,-j)`.
+ * For this reason, to represent a NxN array (N odd),
+ * we only store a `((N+1)/2)x((N+1)/2)` array. */
+
+ /** The sigma value of the gaussian function. */
float _sigma;
float *_mask;
int _bound;
- // the real mask size (must be odd)(the size of the mask we store is
- // ((_maskSize+1)/2)*((_maskSize+1)/2))
+ /* the real mask size (must be odd)(the size of the mask we store is:
+ * `((_maskSize+1)/2)*((_maskSize+1)/2))`. */
int _maskSize;
int _storedMaskSize; // (_maskSize+1)/2)
@@ -65,8 +67,6 @@ class GaussianFilter {
* The abscissa of the pixel where we want to evaluate the gaussian blur.
* \param y:
* The ordinate of the pixel where we want to evaluate the gaussian blur.
- * \param sigma:
- * The sigma value of the gaussian function.
*/
template<class Map> float getSmoothedPixel(Map *map, int x, int y);
@@ -123,7 +123,7 @@ class GaussianFilter {
template<class Map> float GaussianFilter::getSmoothedPixel(Map *map, int x, int y)
{
- float sum = 0.0f;
+ // float sum = 0.0f;
float L = 0.0f;
int w = (int)map->width(); // soc
int h = (int)map->height(); // soc
@@ -142,7 +142,7 @@ template<class Map> float GaussianFilter::getSmoothedPixel(Map *map, int x, int
float tmpL = map->pixel(x + j, y + i);
float m = _mask[abs(i) * _storedMaskSize + abs(j)];
L += m * tmpL;
- sum += m;
+ // sum += m;
}
}
// L /= sum;
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp
index ab39b9ad883..bcb7af0e5a7 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp
@@ -63,7 +63,7 @@ static char SmoothingShader___doc__[] =
"\n"
".. method:: shade(stroke)\n"
"\n"
- " Smoothes the stroke by moving the vertices to make the stroke\n"
+ " Smooths the stroke by moving the vertices to make the stroke\n"
" smoother. Uses curvature flow to converge towards a curve of\n"
" constant curvature. The diffusion method we use is anisotropic to\n"
" prevent the diffusion across corners.\n"
diff --git a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
index ecdba75b864..a66380f01be 100644
--- a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
+++ b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
@@ -57,8 +57,8 @@ class FrsMaterial {
const float *iAmbiant,
const float *iSpecular,
const float *iEmission,
- const float iShininess,
- const int iPriority);
+ float iShininess,
+ int iPriority);
/** Copy constructor */
inline FrsMaterial(const FrsMaterial &m);
@@ -240,7 +240,7 @@ class FrsMaterial {
* \param a:
* Alpha component
*/
- inline void setLine(const float r, const float g, const float b, const float a);
+ inline void setLine(float r, float g, float b, float a);
/** Sets the diffuse color.
* \param r:
@@ -252,7 +252,7 @@ class FrsMaterial {
* \param a:
* Alpha component
*/
- inline void setDiffuse(const float r, const float g, const float b, const float a);
+ inline void setDiffuse(float r, float g, float b, float a);
/** Sets the specular color.
* \param r:
@@ -264,7 +264,7 @@ class FrsMaterial {
* \param a:
* Alpha component
*/
- inline void setSpecular(const float r, const float g, const float b, const float a);
+ inline void setSpecular(float r, float g, float b, float a);
/** Sets the ambient color.
* \param r:
@@ -276,7 +276,7 @@ class FrsMaterial {
* \param a:
* Alpha component
*/
- inline void setAmbient(const float r, const float g, const float b, const float a);
+ inline void setAmbient(float r, float g, float b, float a);
/** Sets the emissive color.
* \param r:
@@ -288,19 +288,19 @@ class FrsMaterial {
* \param a:
* Alpha component
*/
- inline void setEmission(const float r, const float g, const float b, const float a);
+ inline void setEmission(float r, float g, float b, float a);
/** Sets the shininess.
* \param s:
* Shininess
*/
- inline void setShininess(const float s);
+ inline void setShininess(float s);
/** Sets the line color priority.
* \param priority:
* Priority
*/
- inline void setPriority(const int priority);
+ inline void setPriority(int priority);
/* operators */
inline FrsMaterial &operator=(const FrsMaterial &m);
diff --git a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h
index 52cd037a73a..b41beb356c4 100644
--- a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h
+++ b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h
@@ -119,7 +119,7 @@ class SmoothingShader : public StrokeShader {
* 0.2
* \param iAnisoPoint:
* 0
- * \param iAnisNormal:
+ * \param iAnisoNormal:
* 0
* \param iAnisoCurvature:
* 0
diff --git a/source/blender/freestyle/intern/stroke/ChainingIterators.h b/source/blender/freestyle/intern/stroke/ChainingIterators.h
index 93aba258358..66e0c30bea9 100644
--- a/source/blender/freestyle/intern/stroke/ChainingIterators.h
+++ b/source/blender/freestyle/intern/stroke/ChainingIterators.h
@@ -198,7 +198,7 @@ class ChainingIterator : public ViewEdgeInternal::ViewEdgeIterator {
return "ChainingIterator";
}
- /** Inits the iterator context.
+ /** Initializes the iterator context.
* This method is called each time a new chain is started.
* It can be used to reset some history information that you might want to keep.
*/
@@ -299,7 +299,7 @@ class ChainSilhouetteIterator : public ChainingIterator {
*/
virtual int traverse(const AdjacencyIterator &it);
- /** Inits the iterator context */
+ /** Initializes the iterator context */
virtual int init()
{
return 0;
@@ -406,7 +406,7 @@ class ChainPredicateIterator : public ChainingIterator {
*/
virtual int traverse(const AdjacencyIterator &it);
- /** Inits the iterator context */
+ /** Initializes the iterator context. */
virtual int init()
{
return 0;
diff --git a/source/blender/freestyle/intern/stroke/Curve.h b/source/blender/freestyle/intern/stroke/Curve.h
index 9a05fcd380b..b26408d8183 100644
--- a/source/blender/freestyle/intern/stroke/Curve.h
+++ b/source/blender/freestyle/intern/stroke/Curve.h
@@ -540,7 +540,7 @@ class Curve : public Interface1D {
}
const SShape *occluded_shape() const;
- const bool occludee_empty() const;
+ bool occludee_empty() const;
real z_discontinuity(int iCombination = 0) const;
int shape_id() const;
const SShape *shape() const;
diff --git a/source/blender/freestyle/intern/stroke/Operators.cpp b/source/blender/freestyle/intern/stroke/Operators.cpp
index c73bb739e47..cdb85817a85 100644
--- a/source/blender/freestyle/intern/stroke/Operators.cpp
+++ b/source/blender/freestyle/intern/stroke/Operators.cpp
@@ -885,7 +885,7 @@ static int __recursiveSplit(Chain *_curve,
#endif
real _min = FLT_MAX;
++it;
- real mean = 0.0f;
+ // real mean = 0.0f;
// soc unused - real variance = 0.0f;
unsigned count = 0;
CurveInternal::CurvePointIterator next = it;
@@ -904,14 +904,14 @@ static int __recursiveSplit(Chain *_curve,
if (func(it0d) < 0) {
return -1;
}
- mean += func.result;
+ // mean += func.result;
if (func.result < _min) {
_min = func.result;
split = it;
bsplit = true;
}
}
- mean /= (float)count;
+ // mean /= (float)count;
// if ((!bsplit) || (mean - _min > mean)) { // we didn't find any minimum
if (!bsplit) { // we didn't find any minimum
diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h
index 50ebacbd6e8..90dbc259038 100644
--- a/source/blender/freestyle/intern/system/PythonInterpreter.h
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.h
@@ -71,7 +71,7 @@ class PythonInterpreter : public Interpreter {
bool ok = BPY_run_filepath(_context, fn, reports);
#else
bool ok;
- Text *text = BKE_text_load(&_freestyle_bmain, fn, G_MAIN->name);
+ Text *text = BKE_text_load(&_freestyle_bmain, fn, G_MAIN->filepath);
if (text) {
ok = BPY_run_text(_context, text, reports, false);
BKE_id_delete(&_freestyle_bmain, text);
diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp
index 9bf00ed7092..de7fcb7a728 100644
--- a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp
+++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp
@@ -190,7 +190,7 @@ void FEdgeXDetector::computeCurvatures(WXVertex *vertex)
}
// CURVATURE LAYER
- // store all the curvature datas for each vertex
+ // store all the curvature data for each vertex
// soc unused - real K1, K2
real cos2theta, sin2theta;
diff --git a/source/blender/freestyle/intern/view_map/ViewMapIO.h b/source/blender/freestyle/intern/view_map/ViewMapIO.h
index e4c42c094d0..4b737f1eb8c 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapIO.h
+++ b/source/blender/freestyle/intern/view_map/ViewMapIO.h
@@ -44,11 +44,11 @@ namespace Options {
static const unsigned char FLOAT_VECTORS = 1;
static const unsigned char NO_OCCLUDERS = 2;
-void setFlags(const unsigned char flags);
+void setFlags(unsigned char flags);
-void addFlags(const unsigned char flags);
+void addFlags(unsigned char flags);
-void rmFlags(const unsigned char flags);
+void rmFlags(unsigned char flags);
unsigned char getFlags();
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
index 411685bd921..ec07a124808 100644
--- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
@@ -104,27 +104,6 @@ static real angle_from_cotan(WVertex *vo, WVertex *v1, WVertex *v2)
return (fabs(atan2(denom, udotv)));
}
-/** gts_vertex_mean_curvature_normal:
- * \param v: a #WVertex.
- * \param s: a #GtsSurface.
- * \param Kh: the Mean Curvature Normal at \a v.
- *
- * Computes the Discrete Mean Curvature Normal approximation at \a v.
- * The mean curvature at \a v is half the magnitude of the vector \a Kh.
- *
- * NOTE: the normal computed is not unit length, and may point either into or out of the surface,
- * depending on the curvature at \a v. It is the responsibility of the caller of the function to
- * use the mean curvature normal appropriately.
- *
- * This approximation is from the paper:
- * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
- * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
- * VisMath '02, Berlin (Germany)
- * http://www-grail.usc.edu/pubs.html
- *
- * Returns: %true if the operator could be evaluated, %false if the evaluation failed for some
- * reason (@v is boundary or is the endpoint of a non-manifold edge.)
- */
bool gts_vertex_mean_curvature_normal(WVertex *v, Vec3r &Kh)
{
real area = 0.0;
@@ -175,22 +154,6 @@ bool gts_vertex_mean_curvature_normal(WVertex *v, Vec3r &Kh)
return true;
}
-/** gts_vertex_gaussian_curvature:
- * \param v: a #WVertex.
- * \param s: a #GtsSurface.
- * \param Kg: the Discrete Gaussian Curvature approximation at \a v.
- *
- * Computes the Discrete Gaussian Curvature approximation at \a v.
- *
- * This approximation is from the paper:
- * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
- * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
- * VisMath '02, Berlin (Germany)
- * http://www-grail.usc.edu/pubs.html
- *
- * Returns: %true if the operator could be evaluated, %false if the evaluation failed for some
- * reason (@v is boundary or is the endpoint of a non-manifold edge.)
- */
bool gts_vertex_gaussian_curvature(WVertex *v, real *Kg)
{
real area = 0.0;
@@ -226,20 +189,6 @@ bool gts_vertex_gaussian_curvature(WVertex *v, real *Kg)
return true;
}
-/** gts_vertex_principal_curvatures:
- * @Kh: mean curvature.
- * @Kg: Gaussian curvature.
- * @K1: first principal curvature.
- * @K2: second principal curvature.
- *
- * Computes the principal curvatures at a point given the mean and Gaussian curvatures at that
- * point.
- *
- * The mean curvature can be computed as one-half the magnitude of the vector computed by
- * gts_vertex_mean_curvature_normal().
- *
- * The Gaussian curvature can be computed with gts_vertex_gaussian_curvature().
- */
void gts_vertex_principal_curvatures(real Kh, real Kg, real *K1, real *K2)
{
real temp = Kh * Kh - Kg;
@@ -279,21 +228,6 @@ static void eigenvector(real a, real b, real c, Vec3r e)
e[2] = 0.0;
}
-/** gts_vertex_principal_directions:
- * \param v: a #WVertex.
- * \param s: a #GtsSurface.
- * \param Kh: mean curvature normal (a #Vec3r).
- * \param Kg: Gaussian curvature (a real).
- * \param e1: first principal curvature direction (direction of largest curvature).
- * \param e2: second principal curvature direction.
- *
- * Computes the principal curvature directions at a point given \a Kh and \a Kg,
- * the mean curvature normal and Gaussian curvatures at that point, computed with
- * gts_vertex_mean_curvature_normal() and gts_vertex_gaussian_curvature(), respectively.
- *
- * Note that this computation is very approximate and tends to be unstable. Smoothing of the
- * surface or the principal directions may be necessary to achieve reasonable results.
- */
void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, Vec3r &e2)
{
Vec3r N;
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.h b/source/blender/freestyle/intern/winged_edge/Curvature.h
index 0eefc57c3a2..acbe4e8daf6 100644
--- a/source/blender/freestyle/intern/winged_edge/Curvature.h
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.h
@@ -122,12 +122,75 @@ class Face_Curvature_Info {
#endif
};
+/**
+ * \param v: a #WVertex.
+ * \param Kh: the Mean Curvature Normal at \a v.
+ *
+ * Computes the Discrete Mean Curvature Normal approximation at \a v.
+ * The mean curvature at \a v is half the magnitude of the vector \a Kh.
+ *
+ * \note the normal computed is not unit length, and may point either into or out of the surface,
+ * depending on the curvature at \a v. It is the responsibility of the caller of the function to
+ * use the mean curvature normal appropriately.
+ *
+ * This approximation is from the paper:
+ * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
+ * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
+ * VisMath '02, Berlin (Germany)
+ * http://www-grail.usc.edu/pubs.html
+ *
+ * Returns: %true if the operator could be evaluated, %false if the evaluation failed for some
+ * reason (`v` is boundary or is the endpoint of a non-manifold edge.)
+ */
bool gts_vertex_mean_curvature_normal(WVertex *v, Vec3r &Kh);
+/**
+ * \param v: a #WVertex.
+ * \param Kg: the Discrete Gaussian Curvature approximation at \a v.
+ *
+ * Computes the Discrete Gaussian Curvature approximation at \a v.
+ *
+ * This approximation is from the paper:
+ * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
+ * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
+ * VisMath '02, Berlin (Germany)
+ * http://www-grail.usc.edu/pubs.html
+ *
+ * Returns: %true if the operator could be evaluated, %false if the evaluation failed for some
+ * reason (`v` is boundary or is the endpoint of a non-manifold edge.)
+ */
bool gts_vertex_gaussian_curvature(WVertex *v, real *Kg);
+/**
+ * \param Kh: mean curvature.
+ * \param Kg: Gaussian curvature.
+ * \param K1: first principal curvature.
+ * \param K2: second principal curvature.
+ *
+ * Computes the principal curvatures at a point given the mean and Gaussian curvatures at that
+ * point.
+ *
+ * The mean curvature can be computed as one-half the magnitude of the vector computed by
+ * #gts_vertex_mean_curvature_normal().
+ *
+ * The Gaussian curvature can be computed with gts_vertex_gaussian_curvature().
+ */
void gts_vertex_principal_curvatures(real Kh, real Kg, real *K1, real *K2);
+/**
+ * \param v: a #WVertex.
+ * \param Kh: mean curvature normal (a #Vec3r).
+ * \param Kg: Gaussian curvature (a real).
+ * \param e1: first principal curvature direction (direction of largest curvature).
+ * \param e2: second principal curvature direction.
+ *
+ * Computes the principal curvature directions at a point given \a Kh and \a Kg,
+ * the mean curvature normal and Gaussian curvatures at that point, computed with
+ * #gts_vertex_mean_curvature_normal() and #gts_vertex_gaussian_curvature(), respectively.
+ *
+ * Note that this computation is very approximate and tends to be unstable. Smoothing of the
+ * surface or the principal directions may be necessary to achieve reasonable results.
+ */
void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, Vec3r &e2);
namespace OGF {
diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.h b/source/blender/freestyle/intern/winged_edge/WEdge.h
index adc08f60ddf..92b8bc70aa8 100644
--- a/source/blender/freestyle/intern/winged_edge/WEdge.h
+++ b/source/blender/freestyle/intern/winged_edge/WEdge.h
@@ -874,7 +874,7 @@ class WFace {
return _VerticesNormals[index];
}
- /** Returns the tex coords of the vertex of `index`. */
+ /** Returns the texture coords of the vertex of `index`. */
inline Vec2f &GetVertexTexCoords(int index)
{
return _VerticesTexCoords[index];
@@ -1225,7 +1225,7 @@ class WShape {
* orientation and (so) the face orientation. iMaterialIndex The materialIndex for this face
* iNormalsList
* The list of normals, iNormalsList[i] corresponding to the normal of the vertex
- * iVertexList[i] for that face. iTexCoordsList The list of tex coords, iTexCoordsList[i]
+ * iVertexList[i] for that face. iTexCoordsList The list of texture coords, iTexCoordsList[i]
* corresponding to the normal of the vertex iVertexList[i] for that face.
*/
virtual WFace *MakeFace(vector<WVertex *> &iVertexList,
diff --git a/source/blender/freestyle/intern/winged_edge/WXEdge.h b/source/blender/freestyle/intern/winged_edge/WXEdge.h
index b335a364365..7ef2e7bcda2 100644
--- a/source/blender/freestyle/intern/winged_edge/WXEdge.h
+++ b/source/blender/freestyle/intern/winged_edge/WXEdge.h
@@ -783,7 +783,7 @@ class WXShape : public WShape {
* The list of normals, iNormalsList[i]
* corresponding to the normal of the vertex iVertexList[i] for that face.
* - iTexCoordsList:
- * The list of tex coords, iTexCoordsList[i]
+ * The list of texture coords, iTexCoordsList[i]
* corresponding to the normal of the vertex iVertexList[i] for that face.
*/
virtual WFace *MakeFace(vector<WVertex *> &iVertexList,
diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index 309b92f1cb4..9cfaf3eabea 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -34,15 +34,17 @@ set(SRC
intern/generic_virtual_vector_array.cc
intern/multi_function.cc
intern/multi_function_builder.cc
- intern/multi_function_parallel.cc
+ intern/multi_function_params.cc
intern/multi_function_procedure.cc
intern/multi_function_procedure_builder.cc
intern/multi_function_procedure_executor.cc
+ intern/multi_function_procedure_optimization.cc
FN_cpp_type.hh
FN_cpp_type_make.hh
FN_field.hh
FN_field_cpp_type.hh
+ FN_generic_array.hh
FN_generic_pointer.hh
FN_generic_span.hh
FN_generic_value_map.hh
@@ -53,12 +55,12 @@ set(SRC
FN_multi_function_builder.hh
FN_multi_function_context.hh
FN_multi_function_data_type.hh
- FN_multi_function_parallel.hh
FN_multi_function_param_type.hh
FN_multi_function_params.hh
FN_multi_function_procedure.hh
FN_multi_function_procedure_builder.hh
FN_multi_function_procedure_executor.hh
+ FN_multi_function_procedure_optimization.hh
FN_multi_function_signature.hh
)
@@ -88,10 +90,13 @@ if(WITH_GTESTS)
set(TEST_SRC
tests/FN_cpp_type_test.cc
tests/FN_field_test.cc
+ tests/FN_generic_array_test.cc
tests/FN_generic_span_test.cc
tests/FN_generic_vector_array_test.cc
tests/FN_multi_function_procedure_test.cc
tests/FN_multi_function_test.cc
+
+ tests/FN_multi_function_test_common.hh
)
set(TEST_LIB
bf_functions
diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh
index 643b2fc1f28..7ddb5bf1f46 100644
--- a/source/blender/functions/FN_cpp_type.hh
+++ b/source/blender/functions/FN_cpp_type.hh
@@ -207,6 +207,18 @@ class CPPType : NonCopyable, NonMovable {
return is_trivially_destructible_;
}
+ /**
+ * When true, the value is like a normal C type, it can be copied around with #memcpy and does
+ * not have to be destructed.
+ *
+ * C++ equivalent:
+ * std::is_trivial_v<T>;
+ */
+ bool is_trivial() const
+ {
+ return is_trivial_;
+ }
+
bool is_default_constructible() const
{
return default_construct_ != nullptr;
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index 3ce0993da59..e869927c33b 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -49,83 +49,56 @@
#include "BLI_function_ref.hh"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
#include "FN_generic_virtual_array.hh"
#include "FN_multi_function_builder.hh"
-#include "FN_multi_function_procedure.hh"
-#include "FN_multi_function_procedure_builder.hh"
-#include "FN_multi_function_procedure_executor.hh"
namespace blender::fn {
class FieldInput;
+struct FieldInputs;
+
+/**
+ * Have a fixed set of base node types, because all code that works with field nodes has to
+ * understand those.
+ */
+enum class FieldNodeType {
+ Input,
+ Operation,
+ Constant,
+};
/**
* A node in a field-tree. It has at least one output that can be referenced by fields.
*/
class FieldNode {
private:
- bool is_input_;
+ FieldNodeType node_type_;
+
+ protected:
/**
- * True when this node is a #FieldInput or (potentially indirectly) depends on one. This could
- * always be derived again later by traversing the field-tree, but keeping track of it while the
- * field is built is cheaper.
- *
- * If this is false, the field is constant. Note that even when this is true, the field may be
- * constant when all inputs are constant.
+ * Keeps track of the inputs that this node depends on. This avoids recomputing it every time the
+ * data is required. It is a shared pointer, because very often multiple nodes depend on the same
+ * inputs.
+ * Might contain null.
*/
- bool depends_on_input_;
+ std::shared_ptr<const FieldInputs> field_inputs_;
public:
- FieldNode(bool is_input, bool depends_on_input)
- : is_input_(is_input), depends_on_input_(depends_on_input)
- {
- }
+ FieldNode(FieldNodeType node_type);
virtual ~FieldNode() = default;
virtual const CPPType &output_cpp_type(int output_index) const = 0;
- bool is_input() const
- {
- return is_input_;
- }
+ FieldNodeType node_type() const;
+ bool depends_on_input() const;
- bool is_operation() const
- {
- return !is_input_;
- }
-
- bool depends_on_input() const
- {
- return depends_on_input_;
- }
-
- /**
- * Invoke callback for every field input. It might be called multiple times for the same input.
- * The caller is responsible for deduplication if required.
- */
- virtual void foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const = 0;
-
- virtual uint64_t hash() const
- {
- return get_default_hash(this);
- }
+ const std::shared_ptr<const FieldInputs> &field_inputs() const;
- friend bool operator==(const FieldNode &a, const FieldNode &b)
- {
- return a.is_equal_to(b);
- }
-
- friend bool operator!=(const FieldNode &a, const FieldNode &b)
- {
- return !(a == b);
- }
-
- virtual bool is_equal_to(const FieldNode &other) const
- {
- return this == &other;
- }
+ virtual uint64_t hash() const;
+ virtual bool is_equal_to(const FieldNode &other) const;
};
/**
@@ -209,11 +182,19 @@ class GFieldRef : public GFieldBase<const FieldNode *> {
}
};
+namespace detail {
+/* Utility class to make #is_field_v work. */
+struct TypedFieldBase {
+};
+} // namespace detail
+
/**
* A typed version of #GField. It has the same memory layout as #GField.
*/
-template<typename T> class Field : public GField {
+template<typename T> class Field : public GField, detail::TypedFieldBase {
public:
+ using base_type = T;
+
Field() = default;
Field(GField field) : GField(std::move(field))
@@ -227,6 +208,11 @@ template<typename T> class Field : public GField {
}
};
+/** True when T is any Field<...> type. */
+template<typename T>
+static constexpr bool is_field_v = std::is_base_of_v<detail::TypedFieldBase, T> &&
+ !std::is_same_v<detail::TypedFieldBase, T>;
+
/**
* A #FieldNode that allows composing existing fields into new fields.
*/
@@ -235,43 +221,20 @@ class FieldOperation : public FieldNode {
* The multi-function used by this node. It is optionally owned.
* Multi-functions with mutable or vector parameters are not supported currently.
*/
- std::unique_ptr<const MultiFunction> owned_function_;
+ std::shared_ptr<const MultiFunction> owned_function_;
const MultiFunction *function_;
/** Inputs to the operation. */
blender::Vector<GField> inputs_;
public:
- FieldOperation(std::unique_ptr<const MultiFunction> function, Vector<GField> inputs = {});
+ FieldOperation(std::shared_ptr<const MultiFunction> function, Vector<GField> inputs = {});
FieldOperation(const MultiFunction &function, Vector<GField> inputs = {});
- Span<GField> inputs() const
- {
- return inputs_;
- }
-
- const MultiFunction &multi_function() const
- {
- return *function_;
- }
+ Span<GField> inputs() const;
+ const MultiFunction &multi_function() const;
- const CPPType &output_cpp_type(int output_index) const override
- {
- int output_counter = 0;
- for (const int param_index : function_->param_indices()) {
- MFParamType param_type = function_->param_type(param_index);
- if (param_type.is_output()) {
- if (output_counter == output_index) {
- return param_type.data_type().single_type();
- }
- output_counter++;
- }
- }
- BLI_assert_unreachable();
- return CPPType::get<float>();
- }
-
- void foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const override;
+ const CPPType &output_cpp_type(int output_index) const override;
};
class FieldContext;
@@ -280,9 +243,19 @@ class FieldContext;
* A #FieldNode that represents an input to the entire field-tree.
*/
class FieldInput : public FieldNode {
+ public:
+ /* The order is also used for sorting in socket inspection. */
+ enum class Category {
+ NamedAttribute = 0,
+ Generated = 1,
+ AnonymousAttribute = 2,
+ Unknown,
+ };
+
protected:
const CPPType *type_;
std::string debug_name_;
+ Category category_ = Category::Unknown;
public:
FieldInput(const CPPType &type, std::string debug_name = "");
@@ -291,33 +264,43 @@ class FieldInput : public FieldNode {
* Get the value of this specific input based on the given context. The returned virtual array,
* should live at least as long as the passed in #scope. May return null.
*/
- virtual const GVArray *get_varray_for_context(const FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const = 0;
+ virtual GVArray get_varray_for_context(const FieldContext &context,
+ IndexMask mask,
+ ResourceScope &scope) const = 0;
- virtual std::string socket_inspection_name() const
- {
- return debug_name_;
- }
+ virtual std::string socket_inspection_name() const;
+ blender::StringRef debug_name() const;
+ const CPPType &cpp_type() const;
+ Category category() const;
- blender::StringRef debug_name() const
- {
- return debug_name_;
- }
+ const CPPType &output_cpp_type(int output_index) const override;
+};
- const CPPType &cpp_type() const
- {
- return *type_;
- }
+class FieldConstant : public FieldNode {
+ private:
+ const CPPType &type_;
+ void *value_;
- const CPPType &output_cpp_type(int output_index) const override
- {
- BLI_assert(output_index == 0);
- UNUSED_VARS_NDEBUG(output_index);
- return *type_;
- }
+ public:
+ FieldConstant(const CPPType &type, const void *value);
+ ~FieldConstant();
+
+ const CPPType &output_cpp_type(int output_index) const override;
+ const CPPType &type() const;
+ GPointer value() const;
+};
- void foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const override;
+/**
+ * Keeps track of the inputs of a field.
+ */
+struct FieldInputs {
+ /** All #FieldInput nodes that a field (possibly indirectly) depends on. */
+ VectorSet<const FieldInput *> nodes;
+ /**
+ * Same as above but the inputs are deduplicated. For example, when there are two separate index
+ * input nodes, only one will show up in this list.
+ */
+ VectorSet<std::reference_wrapper<const FieldInput>> deduplicated_nodes;
};
/**
@@ -325,11 +308,11 @@ class FieldInput : public FieldNode {
*/
class FieldContext {
public:
- ~FieldContext() = default;
+ virtual ~FieldContext() = default;
- virtual const GVArray *get_varray_for_input(const FieldInput &field_input,
- IndexMask mask,
- ResourceScope &scope) const;
+ virtual GVArray get_varray_for_input(const FieldInput &field_input,
+ IndexMask mask,
+ ResourceScope &scope) const;
};
/**
@@ -348,11 +331,14 @@ class FieldEvaluator : NonMovable, NonCopyable {
const FieldContext &context_;
const IndexMask mask_;
Vector<GField> fields_to_evaluate_;
- Vector<GVMutableArray *> dst_varrays_;
- Vector<const GVArray *> evaluated_varrays_;
+ Vector<GVMutableArray> dst_varrays_;
+ Vector<GVArray> evaluated_varrays_;
Vector<OutputPointerInfo> output_pointer_infos_;
bool is_evaluated_ = false;
+ Field<bool> selection_field_;
+ IndexMask selection_mask_;
+
public:
/** Takes #mask by pointer because the mask has to live longer than the evaluator. */
FieldEvaluator(const FieldContext &context, const IndexMask *mask)
@@ -373,16 +359,27 @@ class FieldEvaluator : NonMovable, NonCopyable {
}
/**
+ * The selection field is evaluated first to determine which indices of the other fields should
+ * be evaluated. Calling this method multiple times will just replace the previously set
+ * selection field. Only the elements selected by both this selection and the selection provided
+ * in the constructor are calculated. If no selection field is set, it is assumed that all
+ * indices passed to the constructor are selected.
+ */
+ void set_selection(Field<bool> selection)
+ {
+ selection_field_ = std::move(selection);
+ }
+
+ /**
* \param field: Field to add to the evaluator.
* \param dst: Mutable virtual array that the evaluated result for this field is be written into.
*/
- int add_with_destination(GField field, GVMutableArray &dst);
+ int add_with_destination(GField field, GVMutableArray dst);
/** Same as #add_with_destination but typed. */
- template<typename T> int add_with_destination(Field<T> field, VMutableArray<T> &dst)
+ template<typename T> int add_with_destination(Field<T> field, VMutableArray<T> dst)
{
- GVMutableArray &varray = scope_.construct<GVMutableArray_For_VMutableArray<T>>(dst);
- return this->add_with_destination(GField(std::move(field)), varray);
+ return this->add_with_destination(GField(std::move(field)), GVMutableArray(std::move(dst)));
}
/**
@@ -401,11 +398,10 @@ class FieldEvaluator : NonMovable, NonCopyable {
*/
template<typename T> int add_with_destination(Field<T> field, MutableSpan<T> dst)
{
- GVMutableArray &varray = scope_.construct<GVMutableArray_For_MutableSpan<T>>(dst);
- return this->add_with_destination(std::move(field), varray);
+ return this->add_with_destination(std::move(field), VMutableArray<T>::ForSpan(dst));
}
- int add(GField field, const GVArray **varray_ptr);
+ int add(GField field, GVArray *varray_ptr);
/**
* \param field: Field to add to the evaluator.
@@ -413,14 +409,14 @@ class FieldEvaluator : NonMovable, NonCopyable {
* assigned to the given position.
* \return Index of the field in the evaluator which can be used in the #get_evaluated methods.
*/
- template<typename T> int add(Field<T> field, const VArray<T> **varray_ptr)
+ template<typename T> int add(Field<T> field, VArray<T> *varray_ptr)
{
const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
- dst_varrays_.append(nullptr);
- output_pointer_infos_.append(
- OutputPointerInfo{varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &scope) {
- *(const VArray<T> **)dst = &*scope.construct<GVArray_Typed<T>>(varray);
- }});
+ dst_varrays_.append({});
+ output_pointer_infos_.append(OutputPointerInfo{
+ varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &UNUSED(scope)) {
+ *(VArray<T> *)dst = varray.typed<T>();
+ }});
return field_index;
}
@@ -437,33 +433,51 @@ class FieldEvaluator : NonMovable, NonCopyable {
const GVArray &get_evaluated(const int field_index) const
{
BLI_assert(is_evaluated_);
- return *evaluated_varrays_[field_index];
+ return evaluated_varrays_[field_index];
}
- template<typename T> const VArray<T> &get_evaluated(const int field_index)
+ template<typename T> VArray<T> get_evaluated(const int field_index)
{
- const GVArray &varray = this->get_evaluated(field_index);
- GVArray_Typed<T> &typed_varray = scope_.construct<GVArray_Typed<T>>(varray);
- return *typed_varray;
+ return this->get_evaluated(field_index).typed<T>();
}
+ IndexMask get_evaluated_selection_as_mask();
+
/**
* Retrieve the output of an evaluated boolean field and convert it to a mask, which can be used
* to avoid calculations for unnecessary elements later on. The evaluator will own the indices in
* some cases, so it must live at least as long as the returned mask.
*/
- IndexMask get_evaluated_as_mask(const int field_index);
+ IndexMask get_evaluated_as_mask(int field_index);
};
-Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
- Span<GFieldRef> fields_to_evaluate,
- IndexMask mask,
- const FieldContext &context,
- Span<GVMutableArray *> dst_varrays = {});
-
-/* --------------------------------------------------------------------
- * Utility functions for simple field creation and evaluation.
+/**
+ * Evaluate fields in the given context. If possible, multiple fields should be evaluated together,
+ * because that can be more efficient when they share common sub-fields.
+ *
+ * \param scope: The resource scope that owns data that makes up the output virtual arrays. Make
+ * sure the scope is not destructed when the output virtual arrays are still used.
+ * \param fields_to_evaluate: The fields that should be evaluated together.
+ * \param mask: Determines which indices are computed. The mask may be referenced by the returned
+ * virtual arrays. So the underlying indices (if applicable) should live longer then #scope.
+ * \param context: The context that the field is evaluated in. Used to retrieve data from each
+ * #FieldInput in the field network.
+ * \param dst_varrays: If provided, the computed data will be written into those virtual arrays
+ * instead of into newly created ones. That allows making the computed data live longer than
+ * #scope and is more efficient when the data will be written into those virtual arrays
+ * later anyway.
+ * \return The computed virtual arrays for each provided field. If #dst_varrays is passed, the
+ * provided virtual arrays are returned.
*/
+Vector<GVArray> evaluate_fields(ResourceScope &scope,
+ Span<GFieldRef> fields_to_evaluate,
+ IndexMask mask,
+ const FieldContext &context,
+ Span<GVMutableArray> dst_varrays = {});
+
+/* -------------------------------------------------------------------- */
+/** \name Utility functions for simple field creation and evaluation
+ * \{ */
void evaluate_constant_field(const GField &field, void *r_value);
@@ -477,20 +491,192 @@ template<typename T> T evaluate_constant_field(const Field<T> &field)
template<typename T> Field<T> make_constant_field(T value)
{
- auto constant_fn = std::make_unique<fn::CustomMF_Constant<T>>(std::forward<T>(value));
- auto operation = std::make_shared<FieldOperation>(std::move(constant_fn));
- return Field<T>{GField{std::move(operation), 0}};
+ return make_constant_field(CPPType::get<T>(), &value);
}
+GField make_constant_field(const CPPType &type, const void *value);
+
+/**
+ * If the field depends on some input, the same field is returned.
+ * Otherwise the field is evaluated and a new field is created that just computes this constant.
+ *
+ * Making the field constant has two benefits:
+ * - The field-tree becomes a single node, which is more efficient when the field is evaluated many
+ * times.
+ * - Memory of the input fields may be freed.
+ */
GField make_field_constant_if_possible(GField field);
class IndexFieldInput final : public FieldInput {
public:
IndexFieldInput();
- const GVArray *get_varray_for_context(const FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const final;
+ static GVArray get_index_varray(IndexMask mask);
+
+ GVArray get_varray_for_context(const FieldContext &context,
+ IndexMask mask,
+ ResourceScope &scope) const final;
+
+ uint64_t hash() const override;
+ bool is_equal_to(const fn::FieldNode &other) const override;
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Value or Field Class
+ *
+ * Utility class that wraps a single value and a field, to simplify accessing both of the types.
+ * \{ */
+
+template<typename T> struct ValueOrField {
+ /** Value that is used when the field is empty. */
+ T value{};
+ Field<T> field;
+
+ ValueOrField() = default;
+
+ ValueOrField(T value) : value(std::move(value))
+ {
+ }
+
+ ValueOrField(Field<T> field) : field(std::move(field))
+ {
+ }
+
+ bool is_field() const
+ {
+ return (bool)this->field;
+ }
+
+ Field<T> as_field() const
+ {
+ if (this->field) {
+ return this->field;
+ }
+ return make_constant_field(this->value);
+ }
+
+ T as_value() const
+ {
+ if (this->field) {
+ /* This returns a default value when the field is not constant. */
+ return evaluate_constant_field(this->field);
+ }
+ return this->value;
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #FieldNode Inline Methods
+ * \{ */
+
+inline FieldNode::FieldNode(const FieldNodeType node_type) : node_type_(node_type)
+{
+}
+
+inline FieldNodeType FieldNode::node_type() const
+{
+ return node_type_;
+}
+
+inline bool FieldNode::depends_on_input() const
+{
+ return field_inputs_ && !field_inputs_->nodes.is_empty();
+}
+
+inline const std::shared_ptr<const FieldInputs> &FieldNode::field_inputs() const
+{
+ return field_inputs_;
+}
+
+inline uint64_t FieldNode::hash() const
+{
+ return get_default_hash(this);
+}
+
+inline bool FieldNode::is_equal_to(const FieldNode &other) const
+{
+ return this == &other;
+}
+
+inline bool operator==(const FieldNode &a, const FieldNode &b)
+{
+ return a.is_equal_to(b);
+}
+
+inline bool operator!=(const FieldNode &a, const FieldNode &b)
+{
+ return !(a == b);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #FieldOperation Inline Methods
+ * \{ */
+
+inline Span<GField> FieldOperation::inputs() const
+{
+ return inputs_;
+}
+
+inline const MultiFunction &FieldOperation::multi_function() const
+{
+ return *function_;
+}
+
+inline const CPPType &FieldOperation::output_cpp_type(int output_index) const
+{
+ int output_counter = 0;
+ for (const int param_index : function_->param_indices()) {
+ MFParamType param_type = function_->param_type(param_index);
+ if (param_type.is_output()) {
+ if (output_counter == output_index) {
+ return param_type.data_type().single_type();
+ }
+ output_counter++;
+ }
+ }
+ BLI_assert_unreachable();
+ return CPPType::get<float>();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #FieldInput Inline Methods
+ * \{ */
+
+inline std::string FieldInput::socket_inspection_name() const
+{
+ return debug_name_;
+}
+
+inline StringRef FieldInput::debug_name() const
+{
+ return debug_name_;
+}
+
+inline const CPPType &FieldInput::cpp_type() const
+{
+ return *type_;
+}
+
+inline FieldInput::Category FieldInput::category() const
+{
+ return category_;
+}
+
+inline const CPPType &FieldInput::output_cpp_type(int output_index) const
+{
+ BLI_assert(output_index == 0);
+ UNUSED_VARS_NDEBUG(output_index);
+ return *type_;
+}
+
+/** \} */
+
} // namespace blender::fn
diff --git a/source/blender/functions/FN_field_cpp_type.hh b/source/blender/functions/FN_field_cpp_type.hh
index 5e6f1b5a585..940faba6d70 100644
--- a/source/blender/functions/FN_field_cpp_type.hh
+++ b/source/blender/functions/FN_field_cpp_type.hh
@@ -30,19 +30,19 @@ template<typename T> struct FieldCPPTypeParam {
class FieldCPPType : public CPPType {
private:
- const CPPType &field_type_;
+ const CPPType &base_type_;
public:
template<typename T>
FieldCPPType(FieldCPPTypeParam<Field<T>> /* unused */, StringRef debug_name)
: CPPType(CPPTypeParam<Field<T>, CPPTypeFlags::None>(), debug_name),
- field_type_(CPPType::get<T>())
+ base_type_(CPPType::get<T>())
{
}
- const CPPType &field_type() const
+ const CPPType &base_type() const
{
- return field_type_;
+ return base_type_;
}
/* Ensure that #GField and #Field<T> have the same layout, to enable casting between the two. */
@@ -60,6 +60,84 @@ class FieldCPPType : public CPPType {
}
};
+class ValueOrFieldCPPType : public CPPType {
+ private:
+ const CPPType &base_type_;
+ void (*construct_from_value_)(void *dst, const void *value);
+ void (*construct_from_field_)(void *dst, GField field);
+ const void *(*get_value_ptr_)(const void *value_or_field);
+ const GField *(*get_field_ptr_)(const void *value_or_field);
+ bool (*is_field_)(const void *value_or_field);
+ GField (*as_field_)(const void *value_or_field);
+
+ public:
+ template<typename T>
+ ValueOrFieldCPPType(FieldCPPTypeParam<ValueOrField<T>> /* unused */, StringRef debug_name)
+ : CPPType(CPPTypeParam<ValueOrField<T>, CPPTypeFlags::None>(), debug_name),
+ base_type_(CPPType::get<T>())
+ {
+ construct_from_value_ = [](void *dst, const void *value_or_field) {
+ new (dst) ValueOrField<T>(*(const T *)value_or_field);
+ };
+ construct_from_field_ = [](void *dst, GField field) {
+ new (dst) ValueOrField<T>(Field<T>(std::move(field)));
+ };
+ get_value_ptr_ = [](const void *value_or_field) {
+ return (const void *)&((ValueOrField<T> *)value_or_field)->value;
+ };
+ get_field_ptr_ = [](const void *value_or_field) -> const GField * {
+ return &((ValueOrField<T> *)value_or_field)->field;
+ };
+ is_field_ = [](const void *value_or_field) {
+ return ((ValueOrField<T> *)value_or_field)->is_field();
+ };
+ as_field_ = [](const void *value_or_field) -> GField {
+ return ((ValueOrField<T> *)value_or_field)->as_field();
+ };
+ }
+
+ const CPPType &base_type() const
+ {
+ return base_type_;
+ }
+
+ void construct_from_value(void *dst, const void *value) const
+ {
+ construct_from_value_(dst, value);
+ }
+
+ void construct_from_field(void *dst, GField field) const
+ {
+ construct_from_field_(dst, field);
+ }
+
+ const void *get_value_ptr(const void *value_or_field) const
+ {
+ return get_value_ptr_(value_or_field);
+ }
+
+ void *get_value_ptr(void *value_or_field) const
+ {
+ /* Use `const_cast` to avoid duplicating the callback for the non-const case. */
+ return const_cast<void *>(get_value_ptr_(value_or_field));
+ }
+
+ const GField *get_field_ptr(const void *value_or_field) const
+ {
+ return get_field_ptr_(value_or_field);
+ }
+
+ bool is_field(const void *value_or_field) const
+ {
+ return is_field_(value_or_field);
+ }
+
+ GField as_field(const void *value_or_field) const
+ {
+ return as_field_(value_or_field);
+ }
+};
+
} // namespace blender::fn
#define MAKE_FIELD_CPP_TYPE(DEBUG_NAME, FIELD_TYPE) \
@@ -69,4 +147,13 @@ class FieldCPPType : public CPPType {
static blender::fn::FieldCPPType cpp_type{ \
blender::fn::FieldCPPTypeParam<blender::fn::Field<FIELD_TYPE>>(), STRINGIFY(DEBUG_NAME)}; \
return cpp_type; \
+ } \
+ template<> \
+ const blender::fn::CPPType & \
+ blender::fn::CPPType::get_impl<blender::fn::ValueOrField<FIELD_TYPE>>() \
+ { \
+ static blender::fn::ValueOrFieldCPPType cpp_type{ \
+ blender::fn::FieldCPPTypeParam<blender::fn::ValueOrField<FIELD_TYPE>>(), \
+ STRINGIFY(DEBUG_NAME##OrValue)}; \
+ return cpp_type; \
}
diff --git a/source/blender/functions/FN_generic_array.hh b/source/blender/functions/FN_generic_array.hh
new file mode 100644
index 00000000000..401e496a66c
--- /dev/null
+++ b/source/blender/functions/FN_generic_array.hh
@@ -0,0 +1,270 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup fn
+ *
+ * This is a generic counterpart to #blender::Array, used when the type is not known at runtime.
+ *
+ * `GArray` should generally only be used for passing data around in dynamic contexts.
+ * It does not support a few things that #blender::Array supports:
+ * - Small object optimization / inline buffer.
+ * - Exception safety and various more specific constructors.
+ */
+
+#include "BLI_allocator.hh"
+
+#include "FN_cpp_type.hh"
+#include "FN_generic_span.hh"
+
+namespace blender::fn {
+
+template<
+ /**
+ * The allocator used by this array. Should rarely be changed, except when you don't want that
+ * MEM_* functions are used internally.
+ */
+ typename Allocator = GuardedAllocator>
+class GArray {
+ protected:
+ /** The type of the data in the array, will be null after the array is default constructed,
+ * but a value should be assigned before any other interaction with the array. */
+ const CPPType *type_ = nullptr;
+ void *data_ = nullptr;
+ int64_t size_ = 0;
+
+ Allocator allocator_;
+
+ public:
+ /**
+ * The default constructor creates an empty array, the only situation in which the type is
+ * allowed to be null. This default constructor exists so `GArray` can be used in containers,
+ * but the type should be supplied before doing anything else to the array.
+ */
+ GArray(Allocator allocator = {}) noexcept : allocator_(allocator)
+ {
+ }
+
+ GArray(NoExceptConstructor, Allocator allocator = {}) noexcept : GArray(allocator)
+ {
+ }
+
+ /**
+ * Create and allocate a new array, with elements default constructed
+ * (which does not do anything for trivial types).
+ */
+ GArray(const CPPType &type, int64_t size, Allocator allocator = {}) : GArray(type, allocator)
+ {
+ BLI_assert(size >= 0);
+ size_ = size;
+ data_ = this->allocate(size_);
+ type_->default_construct_n(data_, size_);
+ }
+
+ /**
+ * Create an empty array with just a type.
+ */
+ GArray(const CPPType &type, Allocator allocator = {}) : GArray(allocator)
+ {
+ type_ = &type;
+ }
+
+ /**
+ * Take ownership of a buffer with a provided size. The buffer should be
+ * allocated with the same allocator provided to the constructor.
+ */
+ GArray(const CPPType &type, void *buffer, int64_t size, Allocator allocator = {})
+ : GArray(type, allocator)
+ {
+ BLI_assert(size >= 0);
+ BLI_assert(buffer != nullptr || size == 0);
+ BLI_assert(type_->pointer_has_valid_alignment(buffer));
+
+ data_ = buffer;
+ size_ = size;
+ }
+
+ /**
+ * Create an array by copying values from a generic span.
+ */
+ GArray(const GSpan span, Allocator allocator = {}) : GArray(span.type(), span.size(), allocator)
+ {
+ if (span.data() != nullptr) {
+ BLI_assert(span.size() != 0);
+ /* Use copy assign rather than construct since the memory is already initialized. */
+ type_->copy_assign_n(span.data(), data_, size_);
+ }
+ }
+
+ /**
+ * Create an array by copying values from another generic array.
+ */
+ GArray(const GArray &other) : GArray(other.as_span(), other.allocator())
+ {
+ }
+
+ /**
+ * Create an array by taking ownership of another array's data, clearing the data in the other.
+ */
+ GArray(GArray &&other) : GArray(other.type(), other.data(), other.size(), other.allocator())
+ {
+ other.data_ = nullptr;
+ other.size_ = 0;
+ }
+
+ ~GArray()
+ {
+ if (data_ != nullptr) {
+ type_->destruct_n(data_, size_);
+ this->deallocate(data_);
+ }
+ }
+
+ GArray &operator=(const GArray &other)
+ {
+ return copy_assign_container(*this, other);
+ }
+
+ GArray &operator=(GArray &&other)
+ {
+ return move_assign_container(*this, std::move(other));
+ }
+
+ const CPPType &type() const
+ {
+ BLI_assert(type_ != nullptr);
+ return *type_;
+ }
+
+ bool is_empty() const
+ {
+ return size_ == 0;
+ }
+
+ /**
+ * Return the number of elements in the array (not the size in bytes).
+ */
+ int64_t size() const
+ {
+ return size_;
+ }
+
+ /**
+ * Get a pointer to the beginning of the array.
+ */
+ const void *data() const
+ {
+ return data_;
+ }
+ void *data()
+ {
+ return data_;
+ }
+
+ const void *operator[](int64_t index) const
+ {
+ BLI_assert(index < size_);
+ return POINTER_OFFSET(data_, type_->size() * index);
+ }
+
+ void *operator[](int64_t index)
+ {
+ BLI_assert(index < size_);
+ return POINTER_OFFSET(data_, type_->size() * index);
+ }
+
+ operator GSpan() const
+ {
+ BLI_assert(type_ != nullptr);
+ return GSpan(*type_, data_, size_);
+ }
+
+ operator GMutableSpan()
+ {
+ BLI_assert(type_ != nullptr);
+ return GMutableSpan(*type_, data_, size_);
+ }
+
+ GSpan as_span() const
+ {
+ return *this;
+ }
+
+ GMutableSpan as_mutable_span()
+ {
+ return *this;
+ }
+
+ /**
+ * Access the allocator used by this array.
+ */
+ Allocator &allocator()
+ {
+ return allocator_;
+ }
+ const Allocator &allocator() const
+ {
+ return allocator_;
+ }
+
+ /**
+ * Destruct values and create a new array of the given size. The values in the new array are
+ * default constructed.
+ */
+ void reinitialize(const int64_t new_size)
+ {
+ BLI_assert(new_size >= 0);
+ int64_t old_size = size_;
+
+ type_->destruct_n(data_, size_);
+ size_ = 0;
+
+ if (new_size <= old_size) {
+ type_->default_construct_n(data_, new_size);
+ }
+ else {
+ void *new_data = this->allocate(new_size);
+ try {
+ type_->default_construct_n(new_data, new_size);
+ }
+ catch (...) {
+ this->deallocate(new_data);
+ throw;
+ }
+ this->deallocate(data_);
+ data_ = new_data;
+ }
+
+ size_ = new_size;
+ }
+
+ private:
+ void *allocate(int64_t size)
+ {
+ const int64_t item_size = type_->size();
+ const int64_t alignment = type_->alignment();
+ return allocator_.allocate(static_cast<size_t>(size) * item_size, alignment, AT);
+ }
+
+ void deallocate(void *ptr)
+ {
+ allocator_.deallocate(ptr);
+ }
+};
+
+} // namespace blender::fn
diff --git a/source/blender/functions/FN_generic_span.hh b/source/blender/functions/FN_generic_span.hh
index e2c49697ba9..6f0147b7fb3 100644
--- a/source/blender/functions/FN_generic_span.hh
+++ b/source/blender/functions/FN_generic_span.hh
@@ -93,6 +93,11 @@ class GSpan {
const int64_t new_size = std::max<int64_t>(0, std::min(size, size_ - start));
return GSpan(*type_, POINTER_OFFSET(data_, type_->size() * start), new_size);
}
+
+ GSpan slice(const IndexRange range) const
+ {
+ return this->slice(range.start(), range.size());
+ }
};
/**
@@ -169,6 +174,11 @@ class GMutableSpan {
const int64_t new_size = std::max<int64_t>(0, std::min(size, size_ - start));
return GMutableSpan(*type_, POINTER_OFFSET(data_, type_->size() * start), new_size);
}
+
+ GMutableSpan slice(IndexRange range) const
+ {
+ return this->slice(range.start(), range.size());
+ }
};
} // namespace blender::fn
diff --git a/source/blender/functions/FN_generic_vector_array.hh b/source/blender/functions/FN_generic_vector_array.hh
index 179e85671f8..57efa1b5ba9 100644
--- a/source/blender/functions/FN_generic_vector_array.hh
+++ b/source/blender/functions/FN_generic_vector_array.hh
@@ -125,8 +125,7 @@ template<typename T> class GVectorArray_TypedMutableRef {
void extend(const int64_t index, const VArray<T> &values)
{
- GVArray_For_VArray<T> array{values};
- this->extend(index, array);
+ vector_array_->extend(index, values);
}
MutableSpan<T> operator[](const int64_t index)
diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh
index 703118ba23e..bcb710e3472 100644
--- a/source/blender/functions/FN_generic_virtual_array.hh
+++ b/source/blender/functions/FN_generic_virtual_array.hh
@@ -23,938 +23,870 @@
* the data type is only known at runtime.
*/
-#include <optional>
-
+#include "BLI_timeit.hh"
#include "BLI_virtual_array.hh"
+#include "FN_generic_array.hh"
#include "FN_generic_span.hh"
namespace blender::fn {
-template<typename T> class GVArray_Typed;
-template<typename T> class GVMutableArray_Typed;
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl and #GVMutableArrayImpl.
+ * \{ */
class GVArray;
+class GVArrayImpl;
class GVMutableArray;
+class GVMutableArrayImpl;
-using GVArrayPtr = std::unique_ptr<GVArray>;
-using GVMutableArrayPtr = std::unique_ptr<GVMutableArray>;
-
-/* A generically typed version of `VArray<T>`. */
-class GVArray {
+/* A generically typed version of #VArrayImpl. */
+class GVArrayImpl {
protected:
const CPPType *type_;
int64_t size_;
public:
- GVArray(const CPPType &type, const int64_t size) : type_(&type), size_(size)
- {
- BLI_assert(size_ >= 0);
- }
+ GVArrayImpl(const CPPType &type, int64_t size);
+ virtual ~GVArrayImpl() = default;
- virtual ~GVArray() = default;
+ const CPPType &type() const;
- const CPPType &type() const
- {
- return *type_;
- }
+ int64_t size() const;
- int64_t size() const
- {
- return size_;
- }
+ virtual void get(int64_t index, void *r_value) const;
+ virtual void get_to_uninitialized(int64_t index, void *r_value) const = 0;
- bool is_empty() const
- {
- return size_ == 0;
- }
+ virtual bool is_span() const;
+ virtual GSpan get_internal_span() const;
- /* Copies the value at the given index into the provided storage. The `r_value` pointer is
- * expected to point to initialized memory. */
- void get(const int64_t index, void *r_value) const
- {
- BLI_assert(index >= 0);
- BLI_assert(index < size_);
- this->get_impl(index, r_value);
- }
+ virtual bool is_single() const;
+ virtual void get_internal_single(void *UNUSED(r_value)) const;
- /* Same as `get`, but `r_value` is expected to point to uninitialized memory. */
- void get_to_uninitialized(const int64_t index, void *r_value) const
- {
- BLI_assert(index >= 0);
- BLI_assert(index < size_);
- this->get_to_uninitialized_impl(index, r_value);
- }
+ virtual void materialize(const IndexMask mask, void *dst) const;
+ virtual void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
- /* Returns true when the virtual array is stored as a span internally. */
- bool is_span() const
- {
- if (size_ == 0) {
- return true;
- }
- return this->is_span_impl();
- }
+ virtual bool try_assign_VArray(void *varray) const;
+ virtual bool may_have_ownership() const;
+};
- /* Returns the internally used span of the virtual array. This invokes undefined behavior is the
- * virtual array is not stored as a span internally. */
- GSpan get_internal_span() const
- {
- BLI_assert(this->is_span());
- if (size_ == 0) {
- return GSpan(*type_);
- }
- return this->get_internal_span_impl();
- }
+/* A generic version of #VMutableArrayImpl. */
+class GVMutableArrayImpl : public GVArrayImpl {
+ public:
+ GVMutableArrayImpl(const CPPType &type, int64_t size);
- /* Returns true when the virtual array returns the same value for every index. */
- bool is_single() const
- {
- if (size_ == 1) {
- return true;
- }
- return this->is_single_impl();
- }
+ virtual void set_by_copy(int64_t index, const void *value);
+ virtual void set_by_relocate(int64_t index, void *value);
+ virtual void set_by_move(int64_t index, void *value) = 0;
- /* Copies the value that is used for every element into `r_value`, which is expected to point to
- * initialized memory. This invokes undefined behavior if the virtual array would not return the
- * same value for every index. */
- void get_internal_single(void *r_value) const
- {
- BLI_assert(this->is_single());
- if (size_ == 1) {
- this->get(0, r_value);
- return;
- }
- this->get_internal_single_impl(r_value);
- }
+ virtual void set_all(const void *src);
- /* Same as `get_internal_single`, but `r_value` points to initialized memory. */
- void get_internal_single_to_uninitialized(void *r_value) const
- {
- type_->default_construct(r_value);
- this->get_internal_single(r_value);
- }
+ virtual bool try_assign_VMutableArray(void *varray) const;
+};
- void materialize(void *dst) const;
- void materialize(const IndexMask mask, void *dst) const;
+/** \} */
- void materialize_to_uninitialized(void *dst) const;
- void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
+/* -------------------------------------------------------------------- */
+/** \name #GVArray and #GVMutableArray
+ * \{ */
- template<typename T> const VArray<T> *try_get_internal_varray() const
- {
- BLI_assert(type_->is<T>());
- return (const VArray<T> *)this->try_get_internal_varray_impl();
- }
+namespace detail {
+struct GVArrayAnyExtraInfo {
+ const GVArrayImpl *(*get_varray)(const void *buffer) =
+ [](const void *UNUSED(buffer)) -> const GVArrayImpl * { return nullptr; };
- /* Create a typed virtual array for this generic virtual array. */
- template<typename T> GVArray_Typed<T> typed() const
- {
- return GVArray_Typed<T>(*this);
- }
+ template<typename StorageT> static GVArrayAnyExtraInfo get();
+};
+} // namespace detail
- GVArrayPtr shallow_copy() const;
+class GVMutableArray;
+/**
+ * Utility class to reduce code duplication between #GVArray and #GVMutableArray.
+ * It pretty much follows #VArrayCommon. Don't use this class outside of this header.
+ */
+class GVArrayCommon {
protected:
- virtual void get_impl(const int64_t index, void *r_value) const;
- virtual void get_to_uninitialized_impl(const int64_t index, void *r_value) const = 0;
+ /**
+ * See #VArrayCommon for more information. The inline buffer is a bit larger here, because
+ * generic virtual array implementations often require a bit more space than typed ones.
+ */
+ using Storage = Any<detail::GVArrayAnyExtraInfo, 40, 8>;
- virtual bool is_span_impl() const;
- virtual GSpan get_internal_span_impl() const;
+ const GVArrayImpl *impl_ = nullptr;
+ Storage storage_;
- virtual bool is_single_impl() const;
- virtual void get_internal_single_impl(void *UNUSED(r_value)) const;
+ protected:
+ GVArrayCommon();
+ GVArrayCommon(const GVArrayCommon &other);
+ GVArrayCommon(GVArrayCommon &&other) noexcept;
+ GVArrayCommon(const GVArrayImpl *impl);
+ GVArrayCommon(std::shared_ptr<const GVArrayImpl> impl);
+ ~GVArrayCommon();
- virtual void materialize_impl(const IndexMask mask, void *dst) const;
- virtual void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const;
+ template<typename ImplT, typename... Args> void emplace(Args &&...args);
- virtual const void *try_get_internal_varray_impl() const;
-};
+ void copy_from(const GVArrayCommon &other);
+ void move_from(GVArrayCommon &&other) noexcept;
+
+ const GVArrayImpl *impl_from_storage() const;
-/* Similar to GVArray, but supports changing the elements in the virtual array. */
-class GVMutableArray : public GVArray {
public:
- GVMutableArray(const CPPType &type, const int64_t size) : GVArray(type, size)
- {
- }
+ const CPPType &type() const;
+ operator bool() const;
- void set_by_copy(const int64_t index, const void *value)
- {
- BLI_assert(index >= 0);
- BLI_assert(index < size_);
- this->set_by_copy_impl(index, value);
- }
+ int64_t size() const;
+ bool is_empty() const;
+ IndexRange index_range() const;
- void set_by_move(const int64_t index, void *value)
- {
- BLI_assert(index >= 0);
- BLI_assert(index < size_);
- this->set_by_move_impl(index, value);
- }
+ template<typename T> bool try_assign_VArray(VArray<T> &varray) const;
+ bool may_have_ownership() const;
- void set_by_relocate(const int64_t index, void *value)
- {
- BLI_assert(index >= 0);
- BLI_assert(index < size_);
- this->set_by_relocate_impl(index, value);
- }
+ void materialize(void *dst) const;
+ void materialize(const IndexMask mask, void *dst) const;
- GMutableSpan get_internal_span()
- {
- BLI_assert(this->is_span());
- GSpan span = static_cast<const GVArray *>(this)->get_internal_span();
- return GMutableSpan(span.type(), const_cast<void *>(span.data()), span.size());
- }
+ void materialize_to_uninitialized(void *dst) const;
+ void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
- template<typename T> VMutableArray<T> *try_get_internal_mutable_varray()
- {
- BLI_assert(type_->is<T>());
- return (VMutableArray<T> *)this->try_get_internal_mutable_varray_impl();
- }
+ /**
+ * Returns true when the virtual array is stored as a span internally.
+ */
+ bool is_span() const;
+ /**
+ * Returns the internally used span of the virtual array. This invokes undefined behavior is the
+ * virtual array is not stored as a span internally.
+ */
+ GSpan get_internal_span() const;
+
+ /**
+ * Returns true when the virtual array returns the same value for every index.
+ */
+ bool is_single() const;
+ /**
+ * Copies the value that is used for every element into `r_value`, which is expected to point to
+ * initialized memory. This invokes undefined behavior if the virtual array would not return the
+ * same value for every index.
+ */
+ void get_internal_single(void *r_value) const;
+ /**
+ * Same as `get_internal_single`, but `r_value` points to initialized memory.
+ */
+ void get_internal_single_to_uninitialized(void *r_value) const;
+
+ void get(int64_t index, void *r_value) const;
+ /**
+ * Returns a copy of the value at the given index. Usually a typed virtual array should
+ * be used instead, but sometimes this is simpler when only a few indices are needed.
+ */
+ template<typename T> T get(int64_t index) const;
+ void get_to_uninitialized(int64_t index, void *r_value) const;
+};
- /* Create a typed virtual array for this generic virtual array. */
- template<typename T> GVMutableArray_Typed<T> typed()
- {
- return GVMutableArray_Typed<T>(*this);
- }
+/** Generic version of #VArray. */
+class GVArray : public GVArrayCommon {
+ private:
+ friend GVMutableArray;
- void fill(const void *value);
+ public:
+ GVArray() = default;
- /* Copy the values from the source buffer to all elements in the virtual array. */
- void set_all(const void *src)
- {
- this->set_all_impl(src);
- }
+ GVArray(const GVArray &other);
+ GVArray(GVArray &&other) noexcept;
+ GVArray(const GVArrayImpl *impl);
+ GVArray(std::shared_ptr<const GVArrayImpl> impl);
- protected:
- virtual void set_by_copy_impl(const int64_t index, const void *value);
- virtual void set_by_relocate_impl(const int64_t index, void *value);
- virtual void set_by_move_impl(const int64_t index, void *value) = 0;
+ template<typename T> GVArray(const VArray<T> &varray);
+ template<typename T> VArray<T> typed() const;
- virtual void set_all_impl(const void *src);
+ template<typename ImplT, typename... Args> static GVArray For(Args &&...args);
- virtual void *try_get_internal_mutable_varray_impl();
-};
+ static GVArray ForSingle(const CPPType &type, int64_t size, const void *value);
+ static GVArray ForSingleRef(const CPPType &type, int64_t size, const void *value);
+ static GVArray ForSingleDefault(const CPPType &type, int64_t size);
+ static GVArray ForSpan(GSpan span);
+ static GVArray ForGArray(GArray<> array);
+ static GVArray ForEmpty(const CPPType &type);
-class GVArray_For_GSpan : public GVArray {
- protected:
- const void *data_ = nullptr;
- const int64_t element_size_;
+ GVArray slice(IndexRange slice) const;
- public:
- GVArray_For_GSpan(const GSpan span)
- : GVArray(span.type(), span.size()), data_(span.data()), element_size_(span.type().size())
- {
- }
+ GVArray &operator=(const GVArray &other);
+ GVArray &operator=(GVArray &&other) noexcept;
- protected:
- GVArray_For_GSpan(const CPPType &type, const int64_t size)
- : GVArray(type, size), element_size_(type.size())
+ const GVArrayImpl *get_implementation() const
{
+ return impl_;
}
-
- void get_impl(const int64_t index, void *r_value) const override;
- void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
-
- bool is_span_impl() const override;
- GSpan get_internal_span_impl() const override;
};
-class GVArray_For_Empty : public GVArray {
+/** Generic version of #VMutableArray. */
+class GVMutableArray : public GVArrayCommon {
public:
- GVArray_For_Empty(const CPPType &type) : GVArray(type, 0)
- {
- }
+ GVMutableArray() = default;
+ GVMutableArray(const GVMutableArray &other);
+ GVMutableArray(GVMutableArray &&other) noexcept;
+ GVMutableArray(GVMutableArrayImpl *impl);
+ GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl);
- protected:
- void get_to_uninitialized_impl(const int64_t UNUSED(index), void *UNUSED(r_value)) const override
- {
- BLI_assert(false);
- }
-};
+ template<typename T> GVMutableArray(const VMutableArray<T> &varray);
+ template<typename T> VMutableArray<T> typed() const;
-class GVMutableArray_For_GMutableSpan : public GVMutableArray {
- protected:
- void *data_ = nullptr;
- const int64_t element_size_;
+ template<typename ImplT, typename... Args> static GVMutableArray For(Args &&...args);
- public:
- GVMutableArray_For_GMutableSpan(const GMutableSpan span)
- : GVMutableArray(span.type(), span.size()),
- data_(span.data()),
- element_size_(span.type().size())
- {
- }
+ static GVMutableArray ForSpan(GMutableSpan span);
- protected:
- GVMutableArray_For_GMutableSpan(const CPPType &type, const int64_t size)
- : GVMutableArray(type, size), element_size_(type.size())
- {
- }
+ operator GVArray() const &;
+ operator GVArray() &&noexcept;
- void get_impl(const int64_t index, void *r_value) const override;
- void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
+ GVMutableArray &operator=(const GVMutableArray &other);
+ GVMutableArray &operator=(GVMutableArray &&other) noexcept;
- void set_by_copy_impl(const int64_t index, const void *value) override;
- void set_by_move_impl(const int64_t index, void *value) override;
- void set_by_relocate_impl(const int64_t index, void *value) override;
+ GMutableSpan get_internal_span() const;
- bool is_span_impl() const override;
- GSpan get_internal_span_impl() const override;
-};
+ template<typename T> bool try_assign_VMutableArray(VMutableArray<T> &varray) const;
-/* Generic virtual array where each element has the same value. The value is not owned. */
-class GVArray_For_SingleValueRef : public GVArray {
- protected:
- const void *value_ = nullptr;
+ void set_by_copy(int64_t index, const void *value);
+ void set_by_move(int64_t index, void *value);
+ void set_by_relocate(int64_t index, void *value);
- public:
- GVArray_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
- : GVArray(type, size), value_(value)
- {
- }
+ void fill(const void *value);
+ /**
+ * Copy the values from the source buffer to all elements in the virtual array.
+ */
+ void set_all(const void *src);
- protected:
- GVArray_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArray(type, size)
- {
- }
+ GVMutableArrayImpl *get_implementation() const;
+
+ private:
+ GVMutableArrayImpl *get_impl() const;
+};
+
+/** \} */
- void get_impl(const int64_t index, void *r_value) const override;
- void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
+/* -------------------------------------------------------------------- */
+/** \name #GVArray_GSpan and #GVMutableArray_GSpan.
+ * \{ */
- bool is_span_impl() const override;
- GSpan get_internal_span_impl() const override;
+/* A generic version of VArray_Span. */
+class GVArray_GSpan : public GSpan {
+ private:
+ GVArray varray_;
+ void *owned_data_ = nullptr;
- bool is_single_impl() const override;
- void get_internal_single_impl(void *r_value) const override;
+ public:
+ GVArray_GSpan(GVArray varray);
+ ~GVArray_GSpan();
};
-/* Same as GVArray_For_SingleValueRef, but the value is owned. */
-class GVArray_For_SingleValue : public GVArray_For_SingleValueRef {
+/* A generic version of VMutableArray_Span. */
+class GVMutableArray_GSpan : public GMutableSpan {
+ private:
+ GVMutableArray varray_;
+ void *owned_data_ = nullptr;
+ bool save_has_been_called_ = false;
+ bool show_not_saved_warning_ = true;
+
public:
- GVArray_For_SingleValue(const CPPType &type, const int64_t size, const void *value);
- ~GVArray_For_SingleValue();
+ GVMutableArray_GSpan(GVMutableArray varray, bool copy_values_to_span = true);
+ ~GVMutableArray_GSpan();
+
+ void save();
+ void disable_not_applied_warning();
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Conversions between generic and typed virtual arrays.
+ * \{ */
+
/* Used to convert a typed virtual array into a generic one. */
-template<typename T> class GVArray_For_VArray : public GVArray {
+template<typename T> class GVArrayImpl_For_VArray : public GVArrayImpl {
protected:
- const VArray<T> *varray_ = nullptr;
+ VArray<T> varray_;
public:
- GVArray_For_VArray(const VArray<T> &varray)
- : GVArray(CPPType::get<T>(), varray.size()), varray_(&varray)
+ GVArrayImpl_For_VArray(VArray<T> varray)
+ : GVArrayImpl(CPPType::get<T>(), varray.size()), varray_(std::move(varray))
{
}
protected:
- GVArray_For_VArray(const int64_t size) : GVArray(CPPType::get<T>(), size)
+ void get(const int64_t index, void *r_value) const override
{
+ *(T *)r_value = varray_[index];
}
- void get_impl(const int64_t index, void *r_value) const override
+ void get_to_uninitialized(const int64_t index, void *r_value) const override
{
- *(T *)r_value = varray_->get(index);
+ new (r_value) T(varray_[index]);
}
- void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
+ bool is_span() const override
{
- new (r_value) T(varray_->get(index));
+ return varray_.is_span();
}
- bool is_span_impl() const override
+ GSpan get_internal_span() const override
{
- return varray_->is_span();
+ return GSpan(varray_.get_internal_span());
}
- GSpan get_internal_span_impl() const override
+ bool is_single() const override
{
- return GSpan(varray_->get_internal_span());
+ return varray_.is_single();
}
- bool is_single_impl() const override
+ void get_internal_single(void *r_value) const override
{
- return varray_->is_single();
+ *(T *)r_value = varray_.get_internal_single();
}
- void get_internal_single_impl(void *r_value) const override
+ void materialize(const IndexMask mask, void *dst) const override
{
- *(T *)r_value = varray_->get_internal_single();
+ varray_.materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
- void materialize_impl(const IndexMask mask, void *dst) const override
+ void materialize_to_uninitialized(const IndexMask mask, void *dst) const override
{
- varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
+ varray_.materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
- void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override
+ bool try_assign_VArray(void *varray) const override
{
- varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
+ *(VArray<T> *)varray = varray_;
+ return true;
}
- const void *try_get_internal_varray_impl() const override
+ bool may_have_ownership() const override
{
- return varray_;
+ return varray_.may_have_ownership();
}
};
/* Used to convert any generic virtual array into a typed one. */
-template<typename T> class VArray_For_GVArray : public VArray<T> {
+template<typename T> class VArrayImpl_For_GVArray : public VArrayImpl<T> {
protected:
- const GVArray *varray_ = nullptr;
+ GVArray varray_;
public:
- VArray_For_GVArray(const GVArray &varray) : VArray<T>(varray.size()), varray_(&varray)
+ VArrayImpl_For_GVArray(GVArray varray) : VArrayImpl<T>(varray.size()), varray_(std::move(varray))
{
- BLI_assert(varray_->type().template is<T>());
+ BLI_assert(varray_);
+ BLI_assert(varray_.type().template is<T>());
}
protected:
- VArray_For_GVArray(const int64_t size) : VArray<T>(size)
- {
- }
-
- T get_impl(const int64_t index) const override
+ T get(const int64_t index) const override
{
T value;
- varray_->get(index, &value);
+ varray_.get(index, &value);
return value;
}
- bool is_span_impl() const override
+ bool is_span() const override
{
- return varray_->is_span();
+ return varray_.is_span();
}
- Span<T> get_internal_span_impl() const override
+ Span<T> get_internal_span() const override
{
- return varray_->get_internal_span().template typed<T>();
+ return varray_.get_internal_span().template typed<T>();
}
- bool is_single_impl() const override
+ bool is_single() const override
{
- return varray_->is_single();
+ return varray_.is_single();
}
- T get_internal_single_impl() const override
+ T get_internal_single() const override
{
T value;
- varray_->get_internal_single(&value);
+ varray_.get_internal_single(&value);
return value;
}
-};
-
-/* Used to convert an generic mutable virtual array into a typed one. */
-template<typename T> class VMutableArray_For_GVMutableArray : public VMutableArray<T> {
- protected:
- GVMutableArray *varray_ = nullptr;
-
- public:
- VMutableArray_For_GVMutableArray(GVMutableArray &varray)
- : VMutableArray<T>(varray.size()), varray_(&varray)
- {
- BLI_assert(varray.type().template is<T>());
- }
-
- VMutableArray_For_GVMutableArray(const int64_t size) : VMutableArray<T>(size)
- {
- }
-
- private:
- T get_impl(const int64_t index) const override
- {
- T value;
- varray_->get(index, &value);
- return value;
- }
-
- void set_impl(const int64_t index, T value) override
- {
- varray_->set_by_relocate(index, &value);
- }
-
- bool is_span_impl() const override
- {
- return varray_->is_span();
- }
- Span<T> get_internal_span_impl() const override
+ bool try_assign_GVArray(GVArray &varray) const override
{
- return varray_->get_internal_span().template typed<T>();
+ varray = varray_;
+ return true;
}
- bool is_single_impl() const override
+ bool may_have_ownership() const override
{
- return varray_->is_single();
- }
-
- T get_internal_single_impl() const override
- {
- T value;
- varray_->get_internal_single(&value);
- return value;
+ return varray_.may_have_ownership();
}
};
/* Used to convert any typed virtual mutable array into a generic one. */
-template<typename T> class GVMutableArray_For_VMutableArray : public GVMutableArray {
+template<typename T> class GVMutableArrayImpl_For_VMutableArray : public GVMutableArrayImpl {
protected:
- VMutableArray<T> *varray_ = nullptr;
+ VMutableArray<T> varray_;
public:
- GVMutableArray_For_VMutableArray(VMutableArray<T> &varray)
- : GVMutableArray(CPPType::get<T>(), varray.size()), varray_(&varray)
+ GVMutableArrayImpl_For_VMutableArray(VMutableArray<T> varray)
+ : GVMutableArrayImpl(CPPType::get<T>(), varray.size()), varray_(std::move(varray))
{
}
protected:
- GVMutableArray_For_VMutableArray(const int64_t size) : GVMutableArray(CPPType::get<T>(), size)
+ void get(const int64_t index, void *r_value) const override
{
+ *(T *)r_value = varray_[index];
}
- void get_impl(const int64_t index, void *r_value) const override
+ void get_to_uninitialized(const int64_t index, void *r_value) const override
{
- *(T *)r_value = varray_->get(index);
+ new (r_value) T(varray_[index]);
}
- void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
+ bool is_span() const override
{
- new (r_value) T(varray_->get(index));
+ return varray_.is_span();
}
- bool is_span_impl() const override
+ GSpan get_internal_span() const override
{
- return varray_->is_span();
- }
-
- GSpan get_internal_span_impl() const override
- {
- Span<T> span = varray_->get_internal_span();
+ Span<T> span = varray_.get_internal_span();
return span;
}
- bool is_single_impl() const override
+ bool is_single() const override
{
- return varray_->is_single();
+ return varray_.is_single();
}
- void get_internal_single_impl(void *r_value) const override
+ void get_internal_single(void *r_value) const override
{
- *(T *)r_value = varray_->get_internal_single();
+ *(T *)r_value = varray_.get_internal_single();
}
- void set_by_copy_impl(const int64_t index, const void *value) override
+ void set_by_copy(const int64_t index, const void *value) override
{
const T &value_ = *(const T *)value;
- varray_->set(index, value_);
+ varray_.set(index, value_);
}
- void set_by_relocate_impl(const int64_t index, void *value) override
+ void set_by_relocate(const int64_t index, void *value) override
{
T &value_ = *(T *)value;
- varray_->set(index, std::move(value_));
+ varray_.set(index, std::move(value_));
value_.~T();
}
- void set_by_move_impl(const int64_t index, void *value) override
+ void set_by_move(const int64_t index, void *value) override
{
T &value_ = *(T *)value;
- varray_->set(index, std::move(value_));
+ varray_.set(index, std::move(value_));
}
- void set_all_impl(const void *src) override
+ void set_all(const void *src) override
{
- varray_->set_all(Span((T *)src, size_));
+ varray_.set_all(Span((T *)src, size_));
}
- void materialize_impl(const IndexMask mask, void *dst) const override
+ void materialize(const IndexMask mask, void *dst) const override
{
- varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
+ varray_.materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
- void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override
+ void materialize_to_uninitialized(const IndexMask mask, void *dst) const override
{
- varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
+ varray_.materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
- const void *try_get_internal_varray_impl() const override
+ bool try_assign_VArray(void *varray) const override
{
- return (const VArray<T> *)varray_;
+ *(VArray<T> *)varray = varray_;
+ return true;
}
- void *try_get_internal_mutable_varray_impl() override
+ bool try_assign_VMutableArray(void *varray) const override
{
- return varray_;
+ *(VMutableArray<T> *)varray = varray_;
+ return true;
}
-};
-
-/* A generic version of VArray_Span. */
-class GVArray_GSpan : public GSpan {
- private:
- const GVArray &varray_;
- void *owned_data_ = nullptr;
-
- public:
- GVArray_GSpan(const GVArray &varray);
- ~GVArray_GSpan();
-};
-
-/* A generic version of VMutableArray_Span. */
-class GVMutableArray_GSpan : public GMutableSpan {
- private:
- GVMutableArray &varray_;
- void *owned_data_ = nullptr;
- bool save_has_been_called_ = false;
- bool show_not_saved_warning_ = true;
-
- public:
- GVMutableArray_GSpan(GVMutableArray &varray, bool copy_values_to_span = true);
- ~GVMutableArray_GSpan();
-
- void save();
- void disable_not_applied_warning();
-};
-/* Similar to GVArray_GSpan, but the resulting span is typed. */
-template<typename T> class GVArray_Span : public Span<T> {
- private:
- GVArray_GSpan varray_gspan_;
-
- public:
- GVArray_Span(const GVArray &varray) : varray_gspan_(varray)
+ bool may_have_ownership() const override
{
- BLI_assert(varray.type().is<T>());
- this->data_ = (const T *)varray_gspan_.data();
- this->size_ = varray_gspan_.size();
+ return varray_.may_have_ownership();
}
};
-template<typename T> class GVArray_For_OwnedVArray : public GVArray_For_VArray<T> {
- private:
- VArrayPtr<T> owned_varray_;
+/* Used to convert an generic mutable virtual array into a typed one. */
+template<typename T> class VMutableArrayImpl_For_GVMutableArray : public VMutableArrayImpl<T> {
+ protected:
+ GVMutableArray varray_;
public:
- /* Takes ownership of varray and passes a reference to the base class. */
- GVArray_For_OwnedVArray(VArrayPtr<T> varray)
- : GVArray_For_VArray<T>(*varray), owned_varray_(std::move(varray))
+ VMutableArrayImpl_For_GVMutableArray(GVMutableArray varray)
+ : VMutableArrayImpl<T>(varray.size()), varray_(varray)
{
+ BLI_assert(varray_);
+ BLI_assert(varray_.type().template is<T>());
}
-};
-template<typename T> class VArray_For_OwnedGVArray : public VArray_For_GVArray<T> {
private:
- GVArrayPtr owned_varray_;
-
- public:
- /* Takes ownership of varray and passes a reference to the base class. */
- VArray_For_OwnedGVArray(GVArrayPtr varray)
- : VArray_For_GVArray<T>(*varray), owned_varray_(std::move(varray))
+ T get(const int64_t index) const override
{
+ T value;
+ varray_.get(index, &value);
+ return value;
}
-};
-template<typename T>
-class GVMutableArray_For_OwnedVMutableArray : public GVMutableArray_For_VMutableArray<T> {
- private:
- VMutableArrayPtr<T> owned_varray_;
-
- public:
- /* Takes ownership of varray and passes a reference to the base class. */
- GVMutableArray_For_OwnedVMutableArray(VMutableArrayPtr<T> varray)
- : GVMutableArray_For_VMutableArray<T>(*varray), owned_varray_(std::move(varray))
+ void set(const int64_t index, T value) override
{
+ varray_.set_by_relocate(index, &value);
}
-};
-
-template<typename T>
-class VMutableArray_For_OwnedGVMutableArray : public VMutableArray_For_GVMutableArray<T> {
- private:
- GVMutableArrayPtr owned_varray_;
- public:
- /* Takes ownership of varray and passes a reference to the base class. */
- VMutableArray_For_OwnedGVMutableArray(GVMutableArrayPtr varray)
- : VMutableArray_For_GVMutableArray<T>(*varray), owned_varray_(std::move(varray))
+ bool is_span() const override
{
+ return varray_.is_span();
}
-};
-/* Utility to embed a typed virtual array into a generic one. This avoids one allocation and give
- * the compiler more opportunity to optimize the generic virtual array. */
-template<typename T, typename VArrayT>
-class GVArray_For_EmbeddedVArray : public GVArray_For_VArray<T> {
- private:
- VArrayT embedded_varray_;
-
- public:
- template<typename... Args>
- GVArray_For_EmbeddedVArray(const int64_t size, Args &&...args)
- : GVArray_For_VArray<T>(size), embedded_varray_(std::forward<Args>(args)...)
+ Span<T> get_internal_span() const override
{
- this->varray_ = &embedded_varray_;
+ return varray_.get_internal_span().template typed<T>();
}
-};
-
-/* Same as GVArray_For_EmbeddedVArray, but for mutable virtual arrays. */
-template<typename T, typename VMutableArrayT>
-class GVMutableArray_For_EmbeddedVMutableArray : public GVMutableArray_For_VMutableArray<T> {
- private:
- VMutableArrayT embedded_varray_;
- public:
- template<typename... Args>
- GVMutableArray_For_EmbeddedVMutableArray(const int64_t size, Args &&...args)
- : GVMutableArray_For_VMutableArray<T>(size), embedded_varray_(std::forward<Args>(args)...)
+ bool is_single() const override
{
- this->varray_ = &embedded_varray_;
+ return varray_.is_single();
}
-};
-/* Same as VArray_For_ArrayContainer, but for a generic virtual array. */
-template<typename Container, typename T = typename Container::value_type>
-class GVArray_For_ArrayContainer
- : public GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>> {
- public:
- GVArray_For_ArrayContainer(Container container)
- : GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>>(
- container.size(), std::move(container))
+ T get_internal_single() const override
{
+ T value;
+ varray_.get_internal_single(&value);
+ return value;
}
-};
-/* Same as VArray_For_DerivedSpan, but for a generic virtual array. */
-template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
-class GVArray_For_DerivedSpan
- : public GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>> {
- public:
- GVArray_For_DerivedSpan(const Span<StructT> data)
- : GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>>(
- data.size(), data)
+ bool try_assign_GVArray(GVArray &varray) const override
{
+ varray = varray_;
+ return true;
}
-};
-/* Same as VMutableArray_For_DerivedSpan, but for a generic virtual array. */
-template<typename StructT,
- typename ElemT,
- ElemT (*GetFunc)(const StructT &),
- void (*SetFunc)(StructT &, ElemT)>
-class GVMutableArray_For_DerivedSpan
- : public GVMutableArray_For_EmbeddedVMutableArray<
- ElemT,
- VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>> {
- public:
- GVMutableArray_For_DerivedSpan(const MutableSpan<StructT> data)
- : GVMutableArray_For_EmbeddedVMutableArray<
- ElemT,
- VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>(data.size(), data)
+ bool try_assign_GVMutableArray(GVMutableArray &varray) const override
{
+ varray = varray_;
+ return true;
}
-};
-/* Same as VArray_For_Span, but for a generic virtual array. */
-template<typename T>
-class GVArray_For_Span : public GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>> {
- public:
- GVArray_For_Span(const Span<T> data)
- : GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>>(data.size(), data)
+ bool may_have_ownership() const override
{
+ return varray_.may_have_ownership();
}
};
-/* Same as VMutableArray_For_MutableSpan, but for a generic virtual array. */
-template<typename T>
-class GVMutableArray_For_MutableSpan
- : public GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>> {
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl_For_GSpan.
+ * \{ */
+
+class GVArrayImpl_For_GSpan : public GVMutableArrayImpl {
+ protected:
+ void *data_ = nullptr;
+ const int64_t element_size_;
+
public:
- GVMutableArray_For_MutableSpan(const MutableSpan<T> data)
- : GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>>(data.size(),
- data)
- {
- }
-};
+ GVArrayImpl_For_GSpan(const GMutableSpan span);
-/**
- * Utility class to create the "best" typed virtual array for a given generic virtual array.
- * In most cases we don't just want to use VArray_For_GVArray, because it adds an additional
- * indirection on element-access that can be avoided in many cases (e.g. when the virtual array is
- * just a span or single value).
- *
- * This is not a virtual array itself, but is used to get a virtual array.
- */
-template<typename T> class GVArray_Typed {
- private:
- const VArray<T> *varray_;
- /* Of these optional virtual arrays, at most one is constructed at any time. */
- std::optional<VArray_For_Span<T>> varray_span_;
- std::optional<VArray_For_Single<T>> varray_single_;
- std::optional<VArray_For_GVArray<T>> varray_any_;
- GVArrayPtr owned_gvarray_;
+ protected:
+ GVArrayImpl_For_GSpan(const CPPType &type, int64_t size);
public:
- explicit GVArray_Typed(const GVArray &gvarray)
- {
- BLI_assert(gvarray.type().is<T>());
- if (gvarray.is_span()) {
- const GSpan span = gvarray.get_internal_span();
- varray_span_.emplace(span.typed<T>());
- varray_ = &*varray_span_;
- }
- else if (gvarray.is_single()) {
- T single_value;
- gvarray.get_internal_single(&single_value);
- varray_single_.emplace(single_value, gvarray.size());
- varray_ = &*varray_single_;
- }
- else if (const VArray<T> *internal_varray = gvarray.try_get_internal_varray<T>()) {
- varray_ = internal_varray;
- }
- else {
- varray_any_.emplace(gvarray);
- varray_ = &*varray_any_;
- }
- }
+ void get(int64_t index, void *r_value) const override;
+ void get_to_uninitialized(int64_t index, void *r_value) const override;
- /* Same as the constructor above, but also takes ownership of the passed in virtual array. */
- explicit GVArray_Typed(GVArrayPtr gvarray) : GVArray_Typed(*gvarray)
- {
- owned_gvarray_ = std::move(gvarray);
- }
+ void set_by_copy(int64_t index, const void *value) override;
+ void set_by_move(int64_t index, void *value) override;
+ void set_by_relocate(int64_t index, void *value) override;
- const VArray<T> &operator*() const
- {
- return *varray_;
- }
+ bool is_span() const override;
+ GSpan get_internal_span() const override;
+};
- const VArray<T> *operator->() const
- {
- return varray_;
- }
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline methods for #GVArrayImpl.
+ * \{ */
+
+inline GVArrayImpl::GVArrayImpl(const CPPType &type, const int64_t size)
+ : type_(&type), size_(size)
+{
+ BLI_assert(size_ >= 0);
+}
+
+inline const CPPType &GVArrayImpl::type() const
+{
+ return *type_;
+}
+
+inline int64_t GVArrayImpl::size() const
+{
+ return size_;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline methods for #GVMutableArrayImpl.
+ * \{ */
+
+inline void GVMutableArray::set_by_copy(const int64_t index, const void *value)
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ this->get_impl()->set_by_copy(index, value);
+}
+
+inline void GVMutableArray::set_by_move(const int64_t index, void *value)
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ this->get_impl()->set_by_move(index, value);
+}
+
+inline void GVMutableArray::set_by_relocate(const int64_t index, void *value)
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ this->get_impl()->set_by_relocate(index, value);
+}
- /* Support implicit cast to the typed virtual array for convenience when `varray->typed<T>()` is
- * used within an expression. */
- operator const VArray<T> &() const
- {
- return *varray_;
+template<typename T>
+inline bool GVMutableArray::try_assign_VMutableArray(VMutableArray<T> &varray) const
+{
+ BLI_assert(impl_->type().is<T>());
+ return this->get_impl()->try_assign_VMutableArray(&varray);
+}
+
+inline GVMutableArrayImpl *GVMutableArray::get_impl() const
+{
+ return (GVMutableArrayImpl *)impl_;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline methods for #GVArrayCommon.
+ * \{ */
+
+template<typename ImplT, typename... Args> inline void GVArrayCommon::emplace(Args &&...args)
+{
+ static_assert(std::is_base_of_v<GVArrayImpl, ImplT>);
+ if constexpr (std::is_copy_constructible_v<ImplT> && Storage::template is_inline_v<ImplT>) {
+ impl_ = &storage_.template emplace<ImplT>(std::forward<Args>(args)...);
+ }
+ else {
+ std::shared_ptr<const GVArrayImpl> ptr = std::make_shared<ImplT>(std::forward<Args>(args)...);
+ impl_ = &*ptr;
+ storage_ = std::move(ptr);
+ }
+}
+
+/* Copies the value at the given index into the provided storage. The `r_value` pointer is
+ * expected to point to initialized memory. */
+inline void GVArrayCommon::get(const int64_t index, void *r_value) const
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ impl_->get(index, r_value);
+}
+
+template<typename T> inline T GVArrayCommon::get(const int64_t index) const
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ BLI_assert(this->type().is<T>());
+ T value{};
+ impl_->get(index, &value);
+ return value;
+}
+
+/* Same as `get`, but `r_value` is expected to point to uninitialized memory. */
+inline void GVArrayCommon::get_to_uninitialized(const int64_t index, void *r_value) const
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ impl_->get_to_uninitialized(index, r_value);
+}
+
+template<typename T> inline bool GVArrayCommon::try_assign_VArray(VArray<T> &varray) const
+{
+ BLI_assert(impl_->type().is<T>());
+ return impl_->try_assign_VArray(&varray);
+}
+
+inline const CPPType &GVArrayCommon::type() const
+{
+ return impl_->type();
+}
+
+inline GVArrayCommon::operator bool() const
+{
+ return impl_ != nullptr;
+}
+
+inline int64_t GVArrayCommon::size() const
+{
+ if (impl_ == nullptr) {
+ return 0;
+ }
+ return impl_->size();
+}
+
+inline bool GVArrayCommon::is_empty() const
+{
+ return this->size() == 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline methods for #GVArray.
+ * \{ */
+
+namespace detail {
+template<typename StorageT> inline GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get()
+{
+ static_assert(std::is_base_of_v<GVArrayImpl, StorageT> ||
+ is_same_any_v<StorageT, const GVArrayImpl *, std::shared_ptr<const GVArrayImpl>>);
+
+ if constexpr (std::is_base_of_v<GVArrayImpl, StorageT>) {
+ return {[](const void *buffer) {
+ return static_cast<const GVArrayImpl *>((const StorageT *)buffer);
+ }};
+ }
+ else if constexpr (std::is_same_v<StorageT, const GVArrayImpl *>) {
+ return {[](const void *buffer) { return *(const StorageT *)buffer; }};
+ }
+ else if constexpr (std::is_same_v<StorageT, std::shared_ptr<const GVArrayImpl>>) {
+ return {[](const void *buffer) { return ((const StorageT *)buffer)->get(); }};
+ }
+ else {
+ BLI_assert_unreachable();
+ return {};
+ }
+}
+} // namespace detail
+
+template<typename ImplT, typename... Args> inline GVArray GVArray::For(Args &&...args)
+{
+ static_assert(std::is_base_of_v<GVArrayImpl, ImplT>);
+ GVArray varray;
+ varray.template emplace<ImplT>(std::forward<Args>(args)...);
+ return varray;
+}
+
+template<typename T> inline GVArray::GVArray(const VArray<T> &varray)
+{
+ if (!varray) {
+ return;
+ }
+ if (varray.try_assign_GVArray(*this)) {
+ return;
+ }
+ /* Need to check this before the span/single special cases, because otherwise we might loose
+ * ownership to the referenced data when #varray goes out of scope. */
+ if (varray.may_have_ownership()) {
+ *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
+ }
+ else if (varray.is_span()) {
+ Span<T> data = varray.get_internal_span();
+ *this = GVArray::ForSpan(data);
+ }
+ else if (varray.is_single()) {
+ T value = varray.get_internal_single();
+ *this = GVArray::ForSingle(CPPType::get<T>(), varray.size(), &value);
+ }
+ else {
+ *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
+ }
+}
+
+template<typename T> inline VArray<T> GVArray::typed() const
+{
+ if (!*this) {
+ return {};
+ }
+ BLI_assert(impl_->type().is<T>());
+ VArray<T> varray;
+ if (this->try_assign_VArray(varray)) {
+ return varray;
+ }
+ if (this->may_have_ownership()) {
+ return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this);
}
-
- T operator[](const int64_t index) const
- {
- return varray_->get(index);
+ if (this->is_span()) {
+ const Span<T> span = this->get_internal_span().typed<T>();
+ return VArray<T>::ForSpan(span);
}
-
- int64_t size() const
- {
- return varray_->size();
+ if (this->is_single()) {
+ T value;
+ this->get_internal_single(&value);
+ return VArray<T>::ForSingle(value, this->size());
}
+ return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this);
+}
- IndexRange index_range() const
- {
- return IndexRange(this->size());
- }
-};
+/** \} */
-/* Same as GVArray_Typed, but for mutable virtual arrays. */
-template<typename T> class GVMutableArray_Typed {
- private:
- VMutableArray<T> *varray_;
- std::optional<VMutableArray_For_MutableSpan<T>> varray_span_;
- std::optional<VMutableArray_For_GVMutableArray<T>> varray_any_;
- GVMutableArrayPtr owned_gvarray_;
+/* -------------------------------------------------------------------- */
+/** \name Inline methods for #GVMutableArray.
+ * \{ */
- public:
- explicit GVMutableArray_Typed(GVMutableArray &gvarray)
- {
- BLI_assert(gvarray.type().is<T>());
- if (gvarray.is_span()) {
- const GMutableSpan span = gvarray.get_internal_span();
- varray_span_.emplace(span.typed<T>());
- varray_ = &*varray_span_;
- }
- else if (VMutableArray<T> *internal_varray = gvarray.try_get_internal_mutable_varray<T>()) {
- varray_ = internal_varray;
- }
- else {
- varray_any_.emplace(gvarray);
- varray_ = &*varray_any_;
- }
- }
+template<typename ImplT, typename... Args>
+inline GVMutableArray GVMutableArray::For(Args &&...args)
+{
+ static_assert(std::is_base_of_v<GVMutableArrayImpl, ImplT>);
+ GVMutableArray varray;
+ varray.emplace<ImplT>(std::forward<Args>(args)...);
+ return varray;
+}
- explicit GVMutableArray_Typed(GVMutableArrayPtr gvarray) : GVMutableArray_Typed(*gvarray)
- {
- owned_gvarray_ = std::move(gvarray);
+template<typename T> inline GVMutableArray::GVMutableArray(const VMutableArray<T> &varray)
+{
+ if (!varray) {
+ return;
}
-
- VMutableArray<T> &operator*()
- {
- return *varray_;
+ if (varray.try_assign_GVMutableArray(*this)) {
+ return;
}
-
- VMutableArray<T> *operator->()
- {
- return varray_;
+ if (varray.may_have_ownership()) {
+ *this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray);
}
-
- operator VMutableArray<T> &()
- {
- return *varray_;
+ else if (varray.is_span()) {
+ MutableSpan<T> data = varray.get_internal_span();
+ *this = GVMutableArray::ForSpan(data);
}
-
- T operator[](const int64_t index) const
- {
- return varray_->get(index);
+ else {
+ *this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray);
}
+}
- int64_t size() const
- {
- return varray_->size();
+template<typename T> inline VMutableArray<T> GVMutableArray::typed() const
+{
+ if (!*this) {
+ return {};
}
-};
-
-class GVArray_For_SlicedGVArray : public GVArray {
- protected:
- const GVArray &varray_;
- int64_t offset_;
-
- public:
- GVArray_For_SlicedGVArray(const GVArray &varray, const IndexRange slice)
- : GVArray(varray.type(), slice.size()), varray_(varray), offset_(slice.start())
- {
- BLI_assert(slice.one_after_last() <= varray.size());
+ BLI_assert(this->type().is<T>());
+ VMutableArray<T> varray;
+ if (this->try_assign_VMutableArray(varray)) {
+ return varray;
}
-
- /* TODO: Add #materialize method. */
- void get_impl(const int64_t index, void *r_value) const override;
- void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
-};
-
-/**
- * Utility class to create the "best" sliced virtual array.
- */
-class GVArray_Slice {
- private:
- const GVArray *varray_;
- /* Of these optional virtual arrays, at most one is constructed at any time. */
- std::optional<GVArray_For_GSpan> varray_span_;
- std::optional<GVArray_For_SlicedGVArray> varray_any_;
-
- public:
- GVArray_Slice(const GVArray &varray, const IndexRange slice);
-
- const GVArray &operator*()
- {
- return *varray_;
+ if (this->may_have_ownership()) {
+ return VMutableArray<T>::template For<VMutableArrayImpl_For_GVMutableArray<T>>(*this);
}
-
- const GVArray *operator->()
- {
- return varray_;
+ if (this->is_span()) {
+ const MutableSpan<T> span = this->get_internal_span().typed<T>();
+ return VMutableArray<T>::ForSpan(span);
}
+ return VMutableArray<T>::template For<VMutableArrayImpl_For_GVMutableArray<T>>(*this);
+}
- operator const GVArray &()
- {
- return *varray_;
- }
-};
+/** \} */
} // namespace blender::fn
diff --git a/source/blender/functions/FN_generic_virtual_vector_array.hh b/source/blender/functions/FN_generic_virtual_vector_array.hh
index 4155a55a801..b89ca22fe7e 100644
--- a/source/blender/functions/FN_generic_virtual_vector_array.hh
+++ b/source/blender/functions/FN_generic_virtual_vector_array.hh
@@ -88,10 +88,10 @@ class GVVectorArray {
}
protected:
- virtual int64_t get_vector_size_impl(const int64_t index) const = 0;
+ virtual int64_t get_vector_size_impl(int64_t index) const = 0;
- virtual void get_vector_element_impl(const int64_t index,
- const int64_t index_in_vector,
+ virtual void get_vector_element_impl(int64_t index,
+ int64_t index_in_vector,
void *r_value) const = 0;
virtual bool is_single_vector_impl() const
@@ -100,38 +100,38 @@ class GVVectorArray {
}
};
-class GVArray_For_GVVectorArrayIndex : public GVArray {
+class GVArray_For_GVVectorArrayIndex : public GVArrayImpl {
private:
const GVVectorArray &vector_array_;
const int64_t index_;
public:
GVArray_For_GVVectorArrayIndex(const GVVectorArray &vector_array, const int64_t index)
- : GVArray(vector_array.type(), vector_array.get_vector_size(index)),
+ : GVArrayImpl(vector_array.type(), vector_array.get_vector_size(index)),
vector_array_(vector_array),
index_(index)
{
}
protected:
- void get_impl(const int64_t index_in_vector, void *r_value) const override;
- void get_to_uninitialized_impl(const int64_t index_in_vector, void *r_value) const override;
+ void get(int64_t index_in_vector, void *r_value) const override;
+ void get_to_uninitialized(int64_t index_in_vector, void *r_value) const override;
};
class GVVectorArray_For_SingleGVArray : public GVVectorArray {
private:
- const GVArray &array_;
+ GVArray varray_;
public:
- GVVectorArray_For_SingleGVArray(const GVArray &array, const int64_t size)
- : GVVectorArray(array.type(), size), array_(array)
+ GVVectorArray_For_SingleGVArray(GVArray varray, const int64_t size)
+ : GVVectorArray(varray.type(), size), varray_(std::move(varray))
{
}
protected:
- int64_t get_vector_size_impl(const int64_t index) const override;
- void get_vector_element_impl(const int64_t index,
- const int64_t index_in_vector,
+ int64_t get_vector_size_impl(int64_t index) const override;
+ void get_vector_element_impl(int64_t index,
+ int64_t index_in_vector,
void *r_value) const override;
bool is_single_vector_impl() const override;
@@ -148,9 +148,9 @@ class GVVectorArray_For_SingleGSpan : public GVVectorArray {
}
protected:
- int64_t get_vector_size_impl(const int64_t UNUSED(index)) const override;
- void get_vector_element_impl(const int64_t UNUSED(index),
- const int64_t index_in_vector,
+ int64_t get_vector_size_impl(int64_t UNUSED(index)) const override;
+ void get_vector_element_impl(int64_t UNUSED(index),
+ int64_t index_in_vector,
void *r_value) const override;
bool is_single_vector_impl() const override;
diff --git a/source/blender/functions/FN_multi_function.hh b/source/blender/functions/FN_multi_function.hh
index 98788025558..1e36d87668a 100644
--- a/source/blender/functions/FN_multi_function.hh
+++ b/source/blender/functions/FN_multi_function.hh
@@ -60,6 +60,13 @@ class MultiFunction {
{
}
+ /**
+ * The result is the same as using #call directly but this method has some additional features.
+ * - Automatic multi-threading when possible and appropriate.
+ * - Automatic index mask offsetting to avoid large temporary intermediate arrays that are mostly
+ * unused.
+ */
+ void call_auto(IndexMask mask, MFParams params, MFContext context) const;
virtual void call(IndexMask mask, MFParams params, MFContext context) const = 0;
virtual uint64_t hash() const
@@ -97,6 +104,8 @@ class MultiFunction {
return signature_ref_->function_name;
}
+ virtual std::string debug_name() const;
+
bool depends_on_context() const
{
return signature_ref_->depends_on_context;
@@ -108,6 +117,31 @@ class MultiFunction {
return *signature_ref_;
}
+ /**
+ * Information about how the multi-function behaves that help a caller to execute it efficiently.
+ */
+ struct ExecutionHints {
+ /**
+ * Suggested minimum workload under which multi-threading does not really help.
+ * This should be lowered when the multi-function is doing something computationally expensive.
+ */
+ int64_t min_grain_size = 10000;
+ /**
+ * Indicates that the multi-function will allocate an array large enough to hold all indices
+ * passed in as mask. This tells the caller that it would be preferable to pass in smaller
+ * indices. Also maybe the full mask should be split up into smaller segments to decrease peak
+ * memory usage.
+ */
+ bool allocates_array = false;
+ /**
+ * Tells the caller that every execution takes about the same time. This helps making a more
+ * educated guess about a good grain size.
+ */
+ bool uniform_execution_time = true;
+ };
+
+ ExecutionHints execution_hints() const;
+
protected:
/* Make the function use the given signature. This should be called once in the constructor of
* child classes. No copy of the signature is made, so the caller has to make sure that the
@@ -119,6 +153,8 @@ class MultiFunction {
BLI_assert(signature != nullptr);
signature_ref_ = signature;
}
+
+ virtual ExecutionHints get_execution_hints() const;
};
inline MFParamsBuilder::MFParamsBuilder(const MultiFunction &fn, int64_t mask_size)
@@ -131,8 +167,6 @@ inline MFParamsBuilder::MFParamsBuilder(const MultiFunction &fn, const IndexMask
{
}
-extern const MultiFunction &dummy_multi_function;
-
namespace multi_function_types {
using fn::CPPType;
using fn::GMutableSpan;
diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh
index 0ce05cbca30..eaf9e5ce70f 100644
--- a/source/blender/functions/FN_multi_function_builder.hh
+++ b/source/blender/functions/FN_multi_function_builder.hh
@@ -43,7 +43,7 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio
MFSignature signature_;
public:
- CustomMF_SI_SO(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SI_SO(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_input<In1>("In1");
@@ -53,7 +53,7 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio
}
template<typename ElementFuncT>
- CustomMF_SI_SO(StringRef name, ElementFuncT element_fn)
+ CustomMF_SI_SO(const char *name, ElementFuncT element_fn)
: CustomMF_SI_SO(name, CustomMF_SI_SO::create_function(element_fn))
{
}
@@ -92,7 +92,7 @@ class CustomMF_SI_SI_SO : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_input<In1>("In1");
@@ -103,7 +103,7 @@ class CustomMF_SI_SI_SO : public MultiFunction {
}
template<typename ElementFuncT>
- CustomMF_SI_SI_SO(StringRef name, ElementFuncT element_fn)
+ CustomMF_SI_SI_SO(const char *name, ElementFuncT element_fn)
: CustomMF_SI_SI_SO(name, CustomMF_SI_SI_SO::create_function(element_fn))
{
}
@@ -150,7 +150,7 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SI_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_input<In1>("In1");
@@ -162,7 +162,7 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction {
}
template<typename ElementFuncT>
- CustomMF_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn)
+ CustomMF_SI_SI_SI_SO(const char *name, ElementFuncT element_fn)
: CustomMF_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SO::create_function(element_fn))
{
}
@@ -211,7 +211,7 @@ class CustomMF_SI_SI_SI_SI_SO : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_SI_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SI_SI_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_input<In1>("In1");
@@ -224,7 +224,7 @@ class CustomMF_SI_SI_SI_SI_SO : public MultiFunction {
}
template<typename ElementFuncT>
- CustomMF_SI_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn)
+ CustomMF_SI_SI_SI_SI_SO(const char *name, ElementFuncT element_fn)
: CustomMF_SI_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SI_SO::create_function(element_fn))
{
}
@@ -265,7 +265,7 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_SM(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SM(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_mutable<Mut1>("Mut1");
@@ -274,7 +274,7 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction {
}
template<typename ElementFuncT>
- CustomMF_SM(StringRef name, ElementFuncT element_fn)
+ CustomMF_SM(const char *name, ElementFuncT element_fn)
: CustomMF_SM(name, CustomMF_SM::create_function(element_fn))
{
}
@@ -306,8 +306,8 @@ template<typename From, typename To> class CustomMF_Convert : public MultiFuncti
static MFSignature create_signature()
{
- std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name();
- MFSignatureBuilder signature{std::move(name)};
+ static std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name();
+ MFSignatureBuilder signature{name.c_str()};
signature.single_input<From>("Input");
signature.single_output<To>("Output");
return signature.build();
@@ -372,9 +372,7 @@ template<typename T> class CustomMF_Constant : public MultiFunction {
template<typename U> CustomMF_Constant(U &&value) : value_(std::forward<U>(value))
{
MFSignatureBuilder signature{"Constant"};
- std::stringstream ss;
- ss << value_;
- signature.single_output<T>(ss.str());
+ signature.single_output<T>("Value");
signature_ = signature.build();
this->set_signature(&signature_);
}
@@ -414,9 +412,7 @@ class CustomMF_DefaultOutput : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_DefaultOutput(StringRef name,
- Span<MFDataType> input_types,
- Span<MFDataType> output_types);
+ CustomMF_DefaultOutput(Span<MFDataType> input_types, Span<MFDataType> output_types);
void call(IndexMask mask, MFParams params, MFContext context) const override;
};
@@ -425,7 +421,7 @@ class CustomMF_GenericCopy : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_GenericCopy(StringRef name, MFDataType data_type);
+ CustomMF_GenericCopy(MFDataType data_type);
void call(IndexMask mask, MFParams params, MFContext context) const override;
};
diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh
index d187985de9d..f4ddc4f2881 100644
--- a/source/blender/functions/FN_multi_function_params.hh
+++ b/source/blender/functions/FN_multi_function_params.hh
@@ -25,6 +25,8 @@
* the function. `MFParams` is then used inside the called function to access the parameters.
*/
+#include <mutex>
+
#include "BLI_resource_scope.hh"
#include "FN_generic_pointer.hh"
@@ -40,11 +42,14 @@ class MFParamsBuilder {
const MFSignature *signature_;
IndexMask mask_;
int64_t min_array_size_;
- Vector<const GVArray *> virtual_arrays_;
+ Vector<GVArray> virtual_arrays_;
Vector<GMutableSpan> mutable_spans_;
Vector<const GVVectorArray *> virtual_vector_arrays_;
Vector<GVectorArray *> vector_arrays_;
+ std::mutex mutex_;
+ Vector<std::pair<int, GMutableSpan>> dummy_output_spans_;
+
friend class MFParams;
MFParamsBuilder(const MFSignature &signature, const IndexMask mask)
@@ -62,30 +67,28 @@ class MFParamsBuilder {
template<typename T> void add_readonly_single_input_value(T value, StringRef expected_name = "")
{
- T *value_ptr = &scope_.add_value<T>(std::move(value));
- this->add_readonly_single_input(value_ptr, expected_name);
+ this->add_readonly_single_input(VArray<T>::ForSingle(std::move(value), min_array_size_),
+ expected_name);
}
template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "")
{
this->add_readonly_single_input(
- scope_.construct<GVArray_For_SingleValueRef>(CPPType::get<T>(), min_array_size_, value),
- expected_name);
+ GVArray::ForSingleRef(CPPType::get<T>(), min_array_size_, value), expected_name);
}
void add_readonly_single_input(const GSpan span, StringRef expected_name = "")
{
- this->add_readonly_single_input(scope_.construct<GVArray_For_GSpan>(span), expected_name);
+ this->add_readonly_single_input(GVArray::ForSpan(span), expected_name);
}
void add_readonly_single_input(GPointer value, StringRef expected_name = "")
{
this->add_readonly_single_input(
- scope_.construct<GVArray_For_SingleValueRef>(*value.type(), min_array_size_, value.get()),
- expected_name);
+ GVArray::ForSingleRef(*value.type(), min_array_size_, value.get()), expected_name);
}
- void add_readonly_single_input(const GVArray &ref, StringRef expected_name = "")
+ void add_readonly_single_input(GVArray varray, StringRef expected_name = "")
{
- this->assert_current_param_type(MFParamType::ForSingleInput(ref.type()), expected_name);
- BLI_assert(ref.size() >= min_array_size_);
- virtual_arrays_.append(&ref);
+ this->assert_current_param_type(MFParamType::ForSingleInput(varray.type()), expected_name);
+ BLI_assert(varray.size() >= min_array_size_);
+ virtual_arrays_.append(varray);
}
void add_readonly_vector_input(const GVectorArray &vector_array, StringRef expected_name = "")
@@ -221,16 +224,16 @@ class MFParams {
{
}
- template<typename T> const VArray<T> &readonly_single_input(int param_index, StringRef name = "")
+ template<typename T> VArray<T> readonly_single_input(int param_index, StringRef name = "")
{
- const GVArray &array = this->readonly_single_input(param_index, name);
- return builder_->scope_.construct<GVArray_Typed<T>>(array);
+ const GVArray &varray = this->readonly_single_input(param_index, name);
+ return varray.typed<T>();
}
const GVArray &readonly_single_input(int param_index, StringRef name = "")
{
this->assert_correct_param(param_index, name, MFParamType::SingleInput);
int data_index = builder_->signature_->data_index(param_index);
- return *builder_->virtual_arrays_[data_index];
+ return builder_->virtual_arrays_[data_index];
}
/**
@@ -256,20 +259,12 @@ class MFParams {
this->assert_correct_param(param_index, name, MFParamType::SingleOutput);
int data_index = builder_->signature_->data_index(param_index);
GMutableSpan span = builder_->mutable_spans_[data_index];
- if (span.is_empty()) {
- /* The output is ignored by the caller, but the multi-function does not handle this case. So
- * create a temporary buffer that the multi-function can write to. */
- const CPPType &type = span.type();
- void *buffer = builder_->scope_.linear_allocator().allocate(
- builder_->min_array_size_ * type.size(), type.alignment());
- if (!type.is_trivially_destructible()) {
- /* Make sure the temporary elements will be destructed in the end. */
- builder_->scope_.add_destruct_call(
- [&type, buffer, mask = builder_->mask_]() { type.destruct_indices(buffer, mask); });
- }
- span = GMutableSpan{type, buffer, builder_->min_array_size_};
+ if (!span.is_empty()) {
+ return span;
}
- return span;
+ /* The output is ignored by the caller, but the multi-function does not handle this case. So
+ * create a temporary buffer that the multi-function can write to. */
+ return this->ensure_dummy_single_output(data_index);
}
/**
@@ -358,6 +353,8 @@ class MFParams {
}
#endif
}
+
+ GMutableSpan ensure_dummy_single_output(int data_index);
};
} // namespace blender::fn
diff --git a/source/blender/functions/FN_multi_function_procedure.hh b/source/blender/functions/FN_multi_function_procedure.hh
index 4c06ce98ee3..d73bc089278 100644
--- a/source/blender/functions/FN_multi_function_procedure.hh
+++ b/source/blender/functions/FN_multi_function_procedure.hh
@@ -268,6 +268,7 @@ class MFProcedure : NonCopyable, NonMovable {
Vector<MFReturnInstruction *> return_instructions_;
Vector<MFVariable *> variables_;
Vector<MFParameter> params_;
+ Vector<destruct_ptr<MultiFunction>> owned_functions_;
MFInstruction *entry_ = nullptr;
friend class MFProcedureDotExport;
@@ -284,9 +285,10 @@ class MFProcedure : NonCopyable, NonMovable {
MFReturnInstruction &new_return_instruction();
void add_parameter(MFParamType::InterfaceType interface_type, MFVariable &variable);
-
Span<ConstMFParameter> params() const;
+ template<typename T, typename... Args> const MultiFunction &construct_function(Args &&...args);
+
MFInstruction *entry();
const MFInstruction *entry() const;
void set_entry(MFInstruction &entry);
@@ -323,9 +325,9 @@ using MFDestructInstruction = fn::MFDestructInstruction;
using MFProcedure = fn::MFProcedure;
} // namespace multi_function_procedure_types
-/* --------------------------------------------------------------------
- * MFInstructionCursor inline methods.
- */
+/* -------------------------------------------------------------------- */
+/** \name #MFInstructionCursor Inline Methods
+ * \{ */
inline MFInstructionCursor::MFInstructionCursor(MFCallInstruction &instruction)
: type_(Call), instruction_(&instruction)
@@ -367,9 +369,11 @@ inline MFInstructionCursor::Type MFInstructionCursor::type() const
return type_;
}
-/* --------------------------------------------------------------------
- * MFVariable inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #MFVariable Inline Methods
+ * \{ */
inline MFDataType MFVariable::data_type() const
{
@@ -391,9 +395,11 @@ inline int MFVariable::id() const
return id_;
}
-/* --------------------------------------------------------------------
- * MFInstruction inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #MFInstruction Inline Methods
+ * \{ */
inline MFInstructionType MFInstruction::type() const
{
@@ -405,9 +411,11 @@ inline Span<MFInstructionCursor> MFInstruction::prev() const
return prev_;
}
-/* --------------------------------------------------------------------
- * MFCallInstruction inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #MFCallInstruction Inline Methods
+ * \{ */
inline const MultiFunction &MFCallInstruction::fn() const
{
@@ -434,9 +442,11 @@ inline Span<const MFVariable *> MFCallInstruction::params() const
return params_;
}
-/* --------------------------------------------------------------------
- * MFBranchInstruction inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #MFBranchInstruction Inline Methods
+ * \{ */
inline MFVariable *MFBranchInstruction::condition()
{
@@ -468,9 +478,11 @@ inline const MFInstruction *MFBranchInstruction::branch_false() const
return branch_false_;
}
-/* --------------------------------------------------------------------
- * MFDestructInstruction inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #MFDestructInstruction Inline Methods
+ * \{ */
inline MFVariable *MFDestructInstruction::variable()
{
@@ -492,9 +504,11 @@ inline const MFInstruction *MFDestructInstruction::next() const
return next_;
}
-/* --------------------------------------------------------------------
- * MFDummyInstruction inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #MFDummyInstruction Inline Methods
+ * \{ */
inline MFInstruction *MFDummyInstruction::next()
{
@@ -506,9 +520,11 @@ inline const MFInstruction *MFDummyInstruction::next() const
return next_;
}
-/* --------------------------------------------------------------------
- * MFProcedure inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #MFProcedure Inline Methods
+ * \{ */
inline Span<ConstMFParameter> MFProcedure::params() const
{
@@ -536,4 +552,15 @@ inline Span<const MFVariable *> MFProcedure::variables() const
return variables_;
}
+template<typename T, typename... Args>
+inline const MultiFunction &MFProcedure::construct_function(Args &&...args)
+{
+ destruct_ptr<T> fn = allocator_.construct<T>(std::forward<Args>(args)...);
+ const MultiFunction &fn_ref = *fn;
+ owned_functions_.append(std::move(fn));
+ return fn_ref;
+}
+
+/** \} */
+
} // namespace blender::fn
diff --git a/source/blender/functions/FN_multi_function_procedure_executor.hh b/source/blender/functions/FN_multi_function_procedure_executor.hh
index 9c8b59739b8..409a031e7ed 100644
--- a/source/blender/functions/FN_multi_function_procedure_executor.hh
+++ b/source/blender/functions/FN_multi_function_procedure_executor.hh
@@ -31,9 +31,12 @@ class MFProcedureExecutor : public MultiFunction {
const MFProcedure &procedure_;
public:
- MFProcedureExecutor(std::string name, const MFProcedure &procedure);
+ MFProcedureExecutor(const MFProcedure &procedure);
void call(IndexMask mask, MFParams params, MFContext context) const override;
+
+ private:
+ ExecutionHints get_execution_hints() const override;
};
} // namespace blender::fn
diff --git a/source/blender/functions/FN_multi_function_procedure_optimization.hh b/source/blender/functions/FN_multi_function_procedure_optimization.hh
new file mode 100644
index 00000000000..e5ffc12b241
--- /dev/null
+++ b/source/blender/functions/FN_multi_function_procedure_optimization.hh
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup fn
+ *
+ * A #MFProcedure optimization pass takes an existing procedure and changes it in a way that
+ * improves its performance when executed.
+ *
+ * Oftentimes it would also be possible to implement a specific optimization directly during
+ * construction of the initial #MFProcedure. There is a trade-off between doing that or just
+ * building a "simple" procedure and then optimizing it uses separate optimization passes.
+ * - Doing optimizations directly during construction is typically faster than doing it as a
+ * separate pass. However, it would be much harder to turn the optimization off when it is not
+ * necessary, making the construction potentially slower in those cases.
+ * - Doing optimizations directly would also make code more complex, because it mixes the logic
+ * that generates the procedure from some other data with optimization decisions.
+ * - Having a separate pass allows us to use it in different places when necessary.
+ * - Having a separate pass allows us to enable and disable it easily to better understand its
+ * impact on performance.
+ */
+
+#include "FN_multi_function_procedure.hh"
+
+namespace blender::fn::procedure_optimization {
+
+/**
+ * When generating a procedure, destruct instructions (#MFDestructInstruction) have to be inserted
+ * for all variables that are not outputs. Often the simplest approach is to add these instructions
+ * at the very end. However, when the procedure is executed this is not optimal, because many more
+ * variables are initialized at the same time than necessary. This inhibits the reuse of memory
+ * buffers which decreases performance and increases memory use.
+ *
+ * This optimization pass moves destruct instructions up in the procedure. The goal is to destruct
+ * each variable right after its last use.
+ *
+ * For simplicity, and because this is the most common use case, this optimization currently only
+ * works on a single chain of instructions. Destruct instructions are not moved across branches.
+ *
+ * \param procedure The procedure that should be optimized.
+ * \param block_end_instr The instruction that points to the last instruction within a linear chain
+ * of instructions. The algorithm moves instructions backward starting at this instruction.
+ */
+void move_destructs_up(MFProcedure &procedure, MFInstruction &block_end_instr);
+
+} // namespace blender::fn::procedure_optimization
diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh
index d05948cc645..3c991bc9c56 100644
--- a/source/blender/functions/FN_multi_function_signature.hh
+++ b/source/blender/functions/FN_multi_function_signature.hh
@@ -30,8 +30,15 @@
namespace blender::fn {
struct MFSignature {
- std::string function_name;
- Vector<std::string> param_names;
+ /**
+ * The name should be statically allocated so that it lives longer than this signature. This is
+ * used instead of an #std::string because of the overhead when many functions are created.
+ * If the name of the function has to be more dynamic for debugging purposes, override
+ * #MultiFunction::debug_name() instead. Then the dynamic name will only be computed when it is
+ * actually needed.
+ */
+ const char *function_name;
+ Vector<const char *> param_names;
Vector<MFParamType> param_types;
Vector<int> param_data_indices;
bool depends_on_context = false;
@@ -51,9 +58,9 @@ class MFSignatureBuilder {
int vector_array_count_ = 0;
public:
- MFSignatureBuilder(std::string function_name)
+ MFSignatureBuilder(const char *function_name)
{
- signature_.function_name = std::move(function_name);
+ signature_.function_name = function_name;
}
MFSignature build() const
@@ -63,23 +70,23 @@ class MFSignatureBuilder {
/* Input Parameter Types */
- template<typename T> void single_input(StringRef name)
+ template<typename T> void single_input(const char *name)
{
this->single_input(name, CPPType::get<T>());
}
- void single_input(StringRef name, const CPPType &type)
+ void single_input(const char *name, const CPPType &type)
{
this->input(name, MFDataType::ForSingle(type));
}
- template<typename T> void vector_input(StringRef name)
+ template<typename T> void vector_input(const char *name)
{
this->vector_input(name, CPPType::get<T>());
}
- void vector_input(StringRef name, const CPPType &base_type)
+ void vector_input(const char *name, const CPPType &base_type)
{
this->input(name, MFDataType::ForVector(base_type));
}
- void input(StringRef name, MFDataType data_type)
+ void input(const char *name, MFDataType data_type)
{
signature_.param_names.append(name);
signature_.param_types.append(MFParamType(MFParamType::Input, data_type));
@@ -96,23 +103,23 @@ class MFSignatureBuilder {
/* Output Parameter Types */
- template<typename T> void single_output(StringRef name)
+ template<typename T> void single_output(const char *name)
{
this->single_output(name, CPPType::get<T>());
}
- void single_output(StringRef name, const CPPType &type)
+ void single_output(const char *name, const CPPType &type)
{
this->output(name, MFDataType::ForSingle(type));
}
- template<typename T> void vector_output(StringRef name)
+ template<typename T> void vector_output(const char *name)
{
this->vector_output(name, CPPType::get<T>());
}
- void vector_output(StringRef name, const CPPType &base_type)
+ void vector_output(const char *name, const CPPType &base_type)
{
this->output(name, MFDataType::ForVector(base_type));
}
- void output(StringRef name, MFDataType data_type)
+ void output(const char *name, MFDataType data_type)
{
signature_.param_names.append(name);
signature_.param_types.append(MFParamType(MFParamType::Output, data_type));
@@ -129,23 +136,23 @@ class MFSignatureBuilder {
/* Mutable Parameter Types */
- template<typename T> void single_mutable(StringRef name)
+ template<typename T> void single_mutable(const char *name)
{
this->single_mutable(name, CPPType::get<T>());
}
- void single_mutable(StringRef name, const CPPType &type)
+ void single_mutable(const char *name, const CPPType &type)
{
this->mutable_(name, MFDataType::ForSingle(type));
}
- template<typename T> void vector_mutable(StringRef name)
+ template<typename T> void vector_mutable(const char *name)
{
this->vector_mutable(name, CPPType::get<T>());
}
- void vector_mutable(StringRef name, const CPPType &base_type)
+ void vector_mutable(const char *name, const CPPType &base_type)
{
this->mutable_(name, MFDataType::ForVector(base_type));
}
- void mutable_(StringRef name, MFDataType data_type)
+ void mutable_(const char *name, MFDataType data_type)
{
signature_.param_names.append(name);
signature_.param_types.append(MFParamType(MFParamType::Mutable, data_type));
@@ -160,7 +167,7 @@ class MFSignatureBuilder {
}
}
- void add(StringRef name, const MFParamType &param_type)
+ void add(const char *name, const MFParamType &param_type)
{
switch (param_type.interface_type()) {
case MFParamType::Input:
diff --git a/source/blender/functions/intern/cpp_types.cc b/source/blender/functions/intern/cpp_types.cc
index 058fb76af2b..0bbfbc8cb10 100644
--- a/source/blender/functions/intern/cpp_types.cc
+++ b/source/blender/functions/intern/cpp_types.cc
@@ -18,9 +18,8 @@
#include "FN_field_cpp_type.hh"
#include "BLI_color.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
+#include "BLI_math_vec_types.hh"
namespace blender::fn {
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index 39688ef3daf..d6b83c42294 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -21,7 +21,10 @@
#include "BLI_vector_set.hh"
#include "FN_field.hh"
-#include "FN_multi_function_parallel.hh"
+#include "FN_multi_function_procedure.hh"
+#include "FN_multi_function_procedure_builder.hh"
+#include "FN_multi_function_procedure_executor.hh"
+#include "FN_multi_function_procedure_optimization.hh"
namespace blender::fn {
@@ -61,17 +64,26 @@ static FieldTreeInfo preprocess_field_tree(Span<GFieldRef> entry_fields)
while (!fields_to_check.is_empty()) {
GFieldRef field = fields_to_check.pop();
- if (field.node().is_input()) {
- const FieldInput &field_input = static_cast<const FieldInput &>(field.node());
- field_tree_info.deduplicated_field_inputs.add(field_input);
- continue;
- }
- BLI_assert(field.node().is_operation());
- const FieldOperation &operation = static_cast<const FieldOperation &>(field.node());
- for (const GFieldRef operation_input : operation.inputs()) {
- field_tree_info.field_users.add(operation_input, field);
- if (handled_fields.add(operation_input)) {
- fields_to_check.push(operation_input);
+ const FieldNode &field_node = field.node();
+ switch (field_node.node_type()) {
+ case FieldNodeType::Input: {
+ const FieldInput &field_input = static_cast<const FieldInput &>(field_node);
+ field_tree_info.deduplicated_field_inputs.add(field_input);
+ break;
+ }
+ case FieldNodeType::Operation: {
+ const FieldOperation &operation = static_cast<const FieldOperation &>(field_node);
+ for (const GFieldRef operation_input : operation.inputs()) {
+ field_tree_info.field_users.add(operation_input, field);
+ if (handled_fields.add(operation_input)) {
+ fields_to_check.push(operation_input);
+ }
+ }
+ break;
+ }
+ case FieldNodeType::Constant: {
+ /* Nothing to do. */
+ break;
}
}
}
@@ -81,19 +93,18 @@ static FieldTreeInfo preprocess_field_tree(Span<GFieldRef> entry_fields)
/**
* Retrieves the data from the context that is passed as input into the field.
*/
-static Vector<const GVArray *> get_field_context_inputs(
+static Vector<GVArray> get_field_context_inputs(
ResourceScope &scope,
const IndexMask mask,
const FieldContext &context,
const Span<std::reference_wrapper<const FieldInput>> field_inputs)
{
- Vector<const GVArray *> field_context_inputs;
+ Vector<GVArray> field_context_inputs;
for (const FieldInput &field_input : field_inputs) {
- const GVArray *varray = context.get_varray_for_input(field_input, mask, scope);
- if (varray == nullptr) {
+ GVArray varray = context.get_varray_for_input(field_input, mask, scope);
+ if (!varray) {
const CPPType &type = field_input.cpp_type();
- varray = &scope.construct<GVArray_For_SingleValueRef>(
- type, mask.min_array_size(), type.default_value());
+ varray = GVArray::ForSingleDefault(type, mask.min_array_size());
}
field_context_inputs.append(varray);
}
@@ -105,7 +116,7 @@ static Vector<const GVArray *> get_field_context_inputs(
* for different indices.
*/
static Set<GFieldRef> find_varying_fields(const FieldTreeInfo &field_tree_info,
- Span<const GVArray *> field_context_inputs)
+ Span<GVArray> field_context_inputs)
{
Set<GFieldRef> found_fields;
Stack<GFieldRef> fields_to_check;
@@ -114,8 +125,8 @@ static Set<GFieldRef> find_varying_fields(const FieldTreeInfo &field_tree_info,
* start the tree search at the non-constant input fields and traverse through all fields that
* depend on them. */
for (const int i : field_context_inputs.index_range()) {
- const GVArray *varray = field_context_inputs[i];
- if (varray->is_single()) {
+ const GVArray &varray = field_context_inputs[i];
+ if (varray.is_single()) {
continue;
}
const FieldInput &field_input = field_tree_info.deduplicated_field_inputs[i];
@@ -177,56 +188,71 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure,
fields_to_check.pop();
continue;
}
- /* Field inputs should already be handled above. */
- BLI_assert(field.node().is_operation());
-
- const FieldOperation &operation = static_cast<const FieldOperation &>(field.node());
- const Span<GField> operation_inputs = operation.inputs();
-
- if (field_with_index.current_input_index < operation_inputs.size()) {
- /* Not all inputs are handled yet. Push the next input field to the stack and increment the
- * input index. */
- fields_to_check.push({operation_inputs[field_with_index.current_input_index]});
- field_with_index.current_input_index++;
- }
- else {
- /* All inputs variables are ready, now gather all variables that are used by the function
- * and call it. */
- const MultiFunction &multi_function = operation.multi_function();
- Vector<MFVariable *> variables(multi_function.param_amount());
-
- int param_input_index = 0;
- int param_output_index = 0;
- for (const int param_index : multi_function.param_indices()) {
- const MFParamType param_type = multi_function.param_type(param_index);
- const MFParamType::InterfaceType interface_type = param_type.interface_type();
- if (interface_type == MFParamType::Input) {
- const GField &input_field = operation_inputs[param_input_index];
- variables[param_index] = variable_by_field.lookup(input_field);
- param_input_index++;
- }
- else if (interface_type == MFParamType::Output) {
- const GFieldRef output_field{operation, param_output_index};
- const bool output_is_ignored =
- field_tree_info.field_users.lookup(output_field).is_empty() &&
- !output_fields.contains(output_field);
- if (output_is_ignored) {
- /* Ignored outputs don't need a variable. */
- variables[param_index] = nullptr;
- }
- else {
- /* Create a new variable for used outputs. */
- MFVariable &new_variable = procedure.new_variable(param_type.data_type());
- variables[param_index] = &new_variable;
- variable_by_field.add_new(output_field, &new_variable);
- }
- param_output_index++;
+ const FieldNode &field_node = field.node();
+ switch (field_node.node_type()) {
+ case FieldNodeType::Input: {
+ /* Field inputs should already be handled above. */
+ break;
+ }
+ case FieldNodeType::Operation: {
+ const FieldOperation &operation_node = static_cast<const FieldOperation &>(field.node());
+ const Span<GField> operation_inputs = operation_node.inputs();
+
+ if (field_with_index.current_input_index < operation_inputs.size()) {
+ /* Not all inputs are handled yet. Push the next input field to the stack and increment
+ * the input index. */
+ fields_to_check.push({operation_inputs[field_with_index.current_input_index]});
+ field_with_index.current_input_index++;
}
else {
- BLI_assert_unreachable();
+ /* All inputs variables are ready, now gather all variables that are used by the
+ * function and call it. */
+ const MultiFunction &multi_function = operation_node.multi_function();
+ Vector<MFVariable *> variables(multi_function.param_amount());
+
+ int param_input_index = 0;
+ int param_output_index = 0;
+ for (const int param_index : multi_function.param_indices()) {
+ const MFParamType param_type = multi_function.param_type(param_index);
+ const MFParamType::InterfaceType interface_type = param_type.interface_type();
+ if (interface_type == MFParamType::Input) {
+ const GField &input_field = operation_inputs[param_input_index];
+ variables[param_index] = variable_by_field.lookup(input_field);
+ param_input_index++;
+ }
+ else if (interface_type == MFParamType::Output) {
+ const GFieldRef output_field{operation_node, param_output_index};
+ const bool output_is_ignored =
+ field_tree_info.field_users.lookup(output_field).is_empty() &&
+ !output_fields.contains(output_field);
+ if (output_is_ignored) {
+ /* Ignored outputs don't need a variable. */
+ variables[param_index] = nullptr;
+ }
+ else {
+ /* Create a new variable for used outputs. */
+ MFVariable &new_variable = procedure.new_variable(param_type.data_type());
+ variables[param_index] = &new_variable;
+ variable_by_field.add_new(output_field, &new_variable);
+ }
+ param_output_index++;
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ }
+ builder.add_call_with_all_variables(multi_function, variables);
}
+ break;
+ }
+ case FieldNodeType::Constant: {
+ const FieldConstant &constant_node = static_cast<const FieldConstant &>(field_node);
+ const MultiFunction &fn = procedure.construct_function<CustomMF_GenericConstant>(
+ constant_node.type(), constant_node.value().get(), false);
+ MFVariable &new_variable = *builder.add_call<1>(fn)[0];
+ variable_by_field.add_new(field, &new_variable);
+ break;
}
- builder.add_call_with_all_variables(multi_function, variables);
}
}
}
@@ -238,8 +264,7 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure,
if (!already_output_variables.add(variable)) {
/* One variable can be output at most once. To output the same value twice, we have to make
* a copy first. */
- const MultiFunction &copy_fn = scope.construct<CustomMF_GenericCopy>("copy",
- variable->data_type());
+ const MultiFunction &copy_fn = scope.construct<CustomMF_GenericCopy>(variable->data_type());
variable = builder.add_call<1>(copy_fn, {variable})[0];
}
builder.add_output_parameter(*variable);
@@ -254,66 +279,75 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure,
builder.add_destruct(*variable);
}
- builder.add_return();
+ MFReturnInstruction &return_instr = builder.add_return();
+
+ procedure_optimization::move_destructs_up(procedure, return_instr);
// std::cout << procedure.to_dot() << "\n";
BLI_assert(procedure.validate());
}
-/**
- * Evaluate fields in the given context. If possible, multiple fields should be evaluated together,
- * because that can be more efficient when they share common sub-fields.
- *
- * \param scope: The resource scope that owns data that makes up the output virtual arrays. Make
- * sure the scope is not destructed when the output virtual arrays are still used.
- * \param fields_to_evaluate: The fields that should be evaluated together.
- * \param mask: Determines which indices are computed. The mask may be referenced by the returned
- * virtual arrays. So the underlying indices (if applicable) should live longer then #scope.
- * \param context: The context that the field is evaluated in. Used to retrieve data from each
- * #FieldInput in the field network.
- * \param dst_varrays: If provided, the computed data will be written into those virtual arrays
- * instead of into newly created ones. That allows making the computed data live longer than
- * #scope and is more efficient when the data will be written into those virtual arrays
- * later anyway.
- * \return The computed virtual arrays for each provided field. If #dst_varrays is passed, the
- * provided virtual arrays are returned.
- */
-Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
- Span<GFieldRef> fields_to_evaluate,
- IndexMask mask,
- const FieldContext &context,
- Span<GVMutableArray *> dst_varrays)
+Vector<GVArray> evaluate_fields(ResourceScope &scope,
+ Span<GFieldRef> fields_to_evaluate,
+ IndexMask mask,
+ const FieldContext &context,
+ Span<GVMutableArray> dst_varrays)
{
- Vector<const GVArray *> r_varrays(fields_to_evaluate.size(), nullptr);
+ Vector<GVArray> r_varrays(fields_to_evaluate.size());
+ Array<bool> is_output_written_to_dst(fields_to_evaluate.size(), false);
const int array_size = mask.min_array_size();
+ if (mask.is_empty()) {
+ for (const int i : fields_to_evaluate.index_range()) {
+ const CPPType &type = fields_to_evaluate[i].cpp_type();
+ r_varrays[i] = GVArray::ForEmpty(type);
+ }
+ return r_varrays;
+ }
+
/* Destination arrays are optional. Create a small utility method to access them. */
- auto get_dst_varray_if_available = [&](int index) -> GVMutableArray * {
+ auto get_dst_varray = [&](int index) -> GVMutableArray {
if (dst_varrays.is_empty()) {
- return nullptr;
+ return {};
}
- BLI_assert(dst_varrays[index] == nullptr || dst_varrays[index]->size() >= array_size);
- return dst_varrays[index];
+ const GVMutableArray &varray = dst_varrays[index];
+ if (!varray) {
+ return {};
+ }
+ BLI_assert(varray.size() >= array_size);
+ return varray;
};
/* Traverse the field tree and prepare some data that is used in later steps. */
FieldTreeInfo field_tree_info = preprocess_field_tree(fields_to_evaluate);
/* Get inputs that will be passed into the field when evaluated. */
- Vector<const GVArray *> field_context_inputs = get_field_context_inputs(
+ Vector<GVArray> field_context_inputs = get_field_context_inputs(
scope, mask, context, field_tree_info.deduplicated_field_inputs);
- /* Finish fields that output an input varray directly. For those we don't have to do any further
- * processing. */
+ /* Finish fields that don't need any processing directly. */
for (const int out_index : fields_to_evaluate.index_range()) {
const GFieldRef &field = fields_to_evaluate[out_index];
- if (!field.node().is_input()) {
- continue;
+ const FieldNode &field_node = field.node();
+ switch (field_node.node_type()) {
+ case FieldNodeType::Input: {
+ const FieldInput &field_input = static_cast<const FieldInput &>(field.node());
+ const int field_input_index = field_tree_info.deduplicated_field_inputs.index_of(
+ field_input);
+ const GVArray &varray = field_context_inputs[field_input_index];
+ r_varrays[out_index] = varray;
+ break;
+ }
+ case FieldNodeType::Constant: {
+ const FieldConstant &field_constant = static_cast<const FieldConstant &>(field.node());
+ r_varrays[out_index] = GVArray::ForSingleRef(
+ field_constant.type(), mask.min_array_size(), field_constant.value().get());
+ break;
+ }
+ case FieldNodeType::Operation: {
+ break;
+ }
}
- const FieldInput &field_input = static_cast<const FieldInput &>(field.node());
- const int field_input_index = field_tree_info.deduplicated_field_inputs.index_of(field_input);
- const GVArray *varray = field_context_inputs[field_input_index];
- r_varrays[out_index] = varray;
}
Set<GFieldRef> varying_fields = find_varying_fields(field_tree_info, field_context_inputs);
@@ -325,7 +359,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
Vector<GFieldRef> constant_fields_to_evaluate;
Vector<int> constant_field_indices;
for (const int i : fields_to_evaluate.index_range()) {
- if (r_varrays[i] != nullptr) {
+ if (r_varrays[i]) {
/* Already done. */
continue;
}
@@ -346,19 +380,14 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
MFProcedure procedure;
build_multi_function_procedure_for_fields(
procedure, scope, field_tree_info, varying_fields_to_evaluate);
- MFProcedureExecutor procedure_executor{"Procedure", procedure};
- /* Add multi threading capabilities to the field evaluation. */
- const int grain_size = 10000;
- fn::ParallelMultiFunction parallel_procedure_executor{procedure_executor, grain_size};
- /* Utility variable to make easy to switch the executor. */
- const MultiFunction &executor_fn = parallel_procedure_executor;
-
- MFParamsBuilder mf_params{executor_fn, &mask};
+ MFProcedureExecutor procedure_executor{procedure};
+
+ MFParamsBuilder mf_params{procedure_executor, &mask};
MFContextBuilder mf_context;
/* Provide inputs to the procedure executor. */
- for (const GVArray *varray : field_context_inputs) {
- mf_params.add_readonly_single_input(*varray);
+ for (const GVArray &varray : field_context_inputs) {
+ mf_params.add_readonly_single_input(varray);
}
for (const int i : varying_fields_to_evaluate.index_range()) {
@@ -367,9 +396,9 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
const int out_index = varying_field_indices[i];
/* Try to get an existing virtual array that the result should be written into. */
- GVMutableArray *output_varray = get_dst_varray_if_available(out_index);
+ GVMutableArray dst_varray = get_dst_varray(out_index);
void *buffer;
- if (output_varray == nullptr || !output_varray->is_span()) {
+ if (!dst_varray || !dst_varray.is_span()) {
/* Allocate a new buffer for the computed result. */
buffer = scope.linear_allocator().allocate(type.size() * array_size, type.alignment());
@@ -379,14 +408,14 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
[buffer, mask, &type]() { type.destruct_indices(buffer, mask); });
}
- r_varrays[out_index] = &scope.construct<GVArray_For_GSpan>(
- GSpan{type, buffer, array_size});
+ r_varrays[out_index] = GVArray::ForSpan({type, buffer, array_size});
}
else {
/* Write the result into the existing span. */
- buffer = output_varray->get_internal_span().data();
+ buffer = dst_varray.get_internal_span().data();
- r_varrays[out_index] = output_varray;
+ r_varrays[out_index] = dst_varray;
+ is_output_written_to_dst[out_index] = true;
}
/* Pass output buffer to the procedure executor. */
@@ -394,7 +423,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
mf_params.add_uninitialized_single_output(span);
}
- executor_fn.call(mask, mf_params, mf_context);
+ procedure_executor.call_auto(mask, mf_params, mf_context);
}
/* Evaluate constant fields if necessary. */
@@ -403,16 +432,13 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
MFProcedure procedure;
build_multi_function_procedure_for_fields(
procedure, scope, field_tree_info, constant_fields_to_evaluate);
- MFProcedureExecutor procedure_executor{"Procedure", procedure};
- /* Run the code below even when the mask is empty, so that outputs are properly prepared.
- * Higher level code can detect this as well and just skip evaluating the field. */
- const int mask_size = mask.is_empty() ? 0 : 1;
- MFParamsBuilder mf_params{procedure_executor, mask_size};
+ MFProcedureExecutor procedure_executor{procedure};
+ MFParamsBuilder mf_params{procedure_executor, 1};
MFContextBuilder mf_context;
/* Provide inputs to the procedure executor. */
- for (const GVArray *varray : field_context_inputs) {
- mf_params.add_readonly_single_input(*varray);
+ for (const GVArray &varray : field_context_inputs) {
+ mf_params.add_readonly_single_input(varray);
}
for (const int i : constant_fields_to_evaluate.index_range()) {
@@ -421,55 +447,52 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
/* Allocate memory where the computed value will be stored in. */
void *buffer = scope.linear_allocator().allocate(type.size(), type.alignment());
- if (!type.is_trivially_destructible() && mask_size > 0) {
- BLI_assert(mask_size == 1);
+ if (!type.is_trivially_destructible()) {
/* Destruct value in the end. */
scope.add_destruct_call([buffer, &type]() { type.destruct(buffer); });
}
/* Pass output buffer to the procedure executor. */
- mf_params.add_uninitialized_single_output({type, buffer, mask_size});
+ mf_params.add_uninitialized_single_output({type, buffer, 1});
/* Create virtual array that can be used after the procedure has been executed below. */
const int out_index = constant_field_indices[i];
- r_varrays[out_index] = &scope.construct<GVArray_For_SingleValueRef>(
- type, array_size, buffer);
+ r_varrays[out_index] = GVArray::ForSingleRef(type, array_size, buffer);
}
- procedure_executor.call(IndexRange(mask_size), mf_params, mf_context);
+ procedure_executor.call(IndexRange(1), mf_params, mf_context);
}
- /* Copy data to supplied destination arrays if necessary. In some cases the evaluation above has
- * written the computed data in the right place already. */
+ /* Copy data to supplied destination arrays if necessary. In some cases the evaluation above
+ * has written the computed data in the right place already. */
if (!dst_varrays.is_empty()) {
for (const int out_index : fields_to_evaluate.index_range()) {
- GVMutableArray *output_varray = get_dst_varray_if_available(out_index);
- if (output_varray == nullptr) {
+ GVMutableArray dst_varray = get_dst_varray(out_index);
+ if (!dst_varray) {
/* Caller did not provide a destination for this output. */
continue;
}
- const GVArray *computed_varray = r_varrays[out_index];
- BLI_assert(computed_varray->type() == output_varray->type());
- if (output_varray == computed_varray) {
+ const GVArray &computed_varray = r_varrays[out_index];
+ BLI_assert(computed_varray.type() == dst_varray.type());
+ if (is_output_written_to_dst[out_index]) {
/* The result has been written into the destination provided by the caller already. */
continue;
}
/* Still have to copy over the data in the destination provided by the caller. */
- if (output_varray->is_span()) {
+ if (dst_varray.is_span()) {
/* Materialize into a span. */
- computed_varray->materialize_to_uninitialized(mask,
- output_varray->get_internal_span().data());
+ computed_varray.materialize_to_uninitialized(mask, dst_varray.get_internal_span().data());
}
else {
/* Slower materialize into a different structure. */
- const CPPType &type = computed_varray->type();
+ const CPPType &type = computed_varray.type();
BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
for (const int i : mask) {
- computed_varray->get_to_uninitialized(i, buffer);
- output_varray->set_by_relocate(i, buffer);
+ computed_varray.get_to_uninitialized(i, buffer);
+ dst_varray.set_by_relocate(i, buffer);
}
}
- r_varrays[out_index] = output_varray;
+ r_varrays[out_index] = dst_varray;
}
}
return r_varrays;
@@ -477,21 +500,18 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
void evaluate_constant_field(const GField &field, void *r_value)
{
+ if (field.node().depends_on_input()) {
+ const CPPType &type = field.cpp_type();
+ type.copy_construct(type.default_value(), r_value);
+ return;
+ }
+
ResourceScope scope;
FieldContext context;
- Vector<const GVArray *> varrays = evaluate_fields(scope, {field}, IndexRange(1), context);
- varrays[0]->get_to_uninitialized(0, r_value);
+ Vector<GVArray> varrays = evaluate_fields(scope, {field}, IndexRange(1), context);
+ varrays[0].get_to_uninitialized(0, r_value);
}
-/**
- * If the field depends on some input, the same field is returned.
- * Otherwise the field is evaluated and a new field is created that just computes this constant.
- *
- * Making the field constant has two benefits:
- * - The field-tree becomes a single node, which is more efficient when the field is evaluated many
- * times.
- * - Memory of the input fields may be freed.
- */
GField make_field_constant_if_possible(GField field)
{
if (field.node().depends_on_input()) {
@@ -500,15 +520,20 @@ GField make_field_constant_if_possible(GField field)
const CPPType &type = field.cpp_type();
BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
evaluate_constant_field(field, buffer);
- auto constant_fn = std::make_unique<CustomMF_GenericConstant>(type, buffer, true);
+ GField new_field = make_constant_field(type, buffer);
type.destruct(buffer);
- auto operation = std::make_shared<FieldOperation>(std::move(constant_fn));
- return GField{operation, 0};
+ return new_field;
}
-const GVArray *FieldContext::get_varray_for_input(const FieldInput &field_input,
- IndexMask mask,
- ResourceScope &scope) const
+GField make_constant_field(const CPPType &type, const void *value)
+{
+ auto constant_node = std::make_shared<FieldConstant>(type, value);
+ return GField{std::move(constant_node)};
+}
+
+GVArray FieldContext::get_varray_for_input(const FieldInput &field_input,
+ IndexMask mask,
+ ResourceScope &scope) const
{
/* By default ask the field input to create the varray. Another field context might overwrite
* the context here. */
@@ -517,73 +542,158 @@ const GVArray *FieldContext::get_varray_for_input(const FieldInput &field_input,
IndexFieldInput::IndexFieldInput() : FieldInput(CPPType::get<int>(), "Index")
{
+ category_ = Category::Generated;
}
-const GVArray *IndexFieldInput::get_varray_for_context(const fn::FieldContext &UNUSED(context),
- IndexMask mask,
- ResourceScope &scope) const
+GVArray IndexFieldInput::get_index_varray(IndexMask mask)
{
- /* TODO: Investigate a similar method to IndexRange::as_span() */
auto index_func = [](int i) { return i; };
- return &scope.construct<
- fn::GVArray_For_EmbeddedVArray<int, VArray_For_Func<int, decltype(index_func)>>>(
- mask.min_array_size(), mask.min_array_size(), index_func);
+ return VArray<int>::ForFunc(mask.min_array_size(), index_func);
+}
+
+GVArray IndexFieldInput::get_varray_for_context(const fn::FieldContext &UNUSED(context),
+ IndexMask mask,
+ ResourceScope &UNUSED(scope)) const
+{
+ /* TODO: Investigate a similar method to IndexRange::as_span() */
+ return get_index_varray(mask);
+}
+
+uint64_t IndexFieldInput::hash() const
+{
+ /* Some random constant hash. */
+ return 128736487678;
+}
+
+bool IndexFieldInput::is_equal_to(const fn::FieldNode &other) const
+{
+ return dynamic_cast<const IndexFieldInput *>(&other) != nullptr;
}
/* --------------------------------------------------------------------
* FieldOperation.
*/
-FieldOperation::FieldOperation(std::unique_ptr<const MultiFunction> function,
+FieldOperation::FieldOperation(std::shared_ptr<const MultiFunction> function,
Vector<GField> inputs)
: FieldOperation(*function, std::move(inputs))
{
owned_function_ = std::move(function);
}
-static bool any_field_depends_on_input(Span<GField> fields)
+/**
+ * Returns the field inputs used by all the provided fields.
+ * This tries to reuse an existing #FieldInputs whenever possible to avoid copying it.
+ */
+static std::shared_ptr<const FieldInputs> combine_field_inputs(Span<GField> fields)
{
+ /* The #FieldInputs that we try to reuse if possible. */
+ const std::shared_ptr<const FieldInputs> *field_inputs_candidate = nullptr;
for (const GField &field : fields) {
- if (field.node().depends_on_input()) {
- return true;
+ const std::shared_ptr<const FieldInputs> &field_inputs = field.node().field_inputs();
+ /* Only try to reuse non-empty #FieldInputs. */
+ if (field_inputs && !field_inputs->nodes.is_empty()) {
+ if (field_inputs_candidate == nullptr) {
+ field_inputs_candidate = &field_inputs;
+ }
+ else if ((*field_inputs_candidate)->nodes.size() < field_inputs->nodes.size()) {
+ /* Always try to reuse the #FieldInputs that has the most nodes already. */
+ field_inputs_candidate = &field_inputs;
+ }
}
}
- return false;
+ if (field_inputs_candidate == nullptr) {
+ /* None of the field depends on an input. */
+ return {};
+ }
+ /* Check if all inputs are in the candidate. */
+ Vector<const FieldInput *> inputs_not_in_candidate;
+ for (const GField &field : fields) {
+ const std::shared_ptr<const FieldInputs> &field_inputs = field.node().field_inputs();
+ if (!field_inputs) {
+ continue;
+ }
+ if (&field_inputs == field_inputs_candidate) {
+ continue;
+ }
+ for (const FieldInput *field_input : field_inputs->nodes) {
+ if (!(*field_inputs_candidate)->nodes.contains(field_input)) {
+ inputs_not_in_candidate.append(field_input);
+ }
+ }
+ }
+ if (inputs_not_in_candidate.is_empty()) {
+ /* The existing #FieldInputs can be reused, because no other field has additional inputs. */
+ return *field_inputs_candidate;
+ }
+ /* Create new #FieldInputs that contains all of the inputs that the fields depend on. */
+ std::shared_ptr<FieldInputs> new_field_inputs = std::make_shared<FieldInputs>(
+ **field_inputs_candidate);
+ for (const FieldInput *field_input : inputs_not_in_candidate) {
+ new_field_inputs->nodes.add(field_input);
+ new_field_inputs->deduplicated_nodes.add(*field_input);
+ }
+ return new_field_inputs;
}
FieldOperation::FieldOperation(const MultiFunction &function, Vector<GField> inputs)
- : FieldNode(false, any_field_depends_on_input(inputs)),
- function_(&function),
- inputs_(std::move(inputs))
+ : FieldNode(FieldNodeType::Operation), function_(&function), inputs_(std::move(inputs))
{
+ field_inputs_ = combine_field_inputs(inputs_);
}
-void FieldOperation::foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const
+/* --------------------------------------------------------------------
+ * FieldInput.
+ */
+
+FieldInput::FieldInput(const CPPType &type, std::string debug_name)
+ : FieldNode(FieldNodeType::Input), type_(&type), debug_name_(std::move(debug_name))
{
- for (const GField &field : inputs_) {
- field.node().foreach_field_input(foreach_fn);
- }
+ std::shared_ptr<FieldInputs> field_inputs = std::make_shared<FieldInputs>();
+ field_inputs->nodes.add_new(this);
+ field_inputs->deduplicated_nodes.add_new(*this);
+ field_inputs_ = std::move(field_inputs);
}
/* --------------------------------------------------------------------
- * FieldInput.
+ * FieldConstant.
*/
-FieldInput::FieldInput(const CPPType &type, std::string debug_name)
- : FieldNode(true, true), type_(&type), debug_name_(std::move(debug_name))
+FieldConstant::FieldConstant(const CPPType &type, const void *value)
+ : FieldNode(FieldNodeType::Constant), type_(type)
+{
+ value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
+ type.copy_construct(value, value_);
+}
+
+FieldConstant::~FieldConstant()
+{
+ type_.destruct(value_);
+ MEM_freeN(value_);
+}
+
+const CPPType &FieldConstant::output_cpp_type(int output_index) const
+{
+ BLI_assert(output_index == 0);
+ UNUSED_VARS_NDEBUG(output_index);
+ return type_;
+}
+
+const CPPType &FieldConstant::type() const
{
+ return type_;
}
-void FieldInput::foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const
+GPointer FieldConstant::value() const
{
- foreach_fn(*this);
+ return {type_, value_};
}
/* --------------------------------------------------------------------
* FieldEvaluator.
*/
-static Vector<int64_t> indices_from_selection(const VArray<bool> &selection)
+static Vector<int64_t> indices_from_selection(IndexMask mask, const VArray<bool> &selection)
{
/* If the selection is just a single value, it's best to avoid calling this
* function when constructing an IndexMask and use an IndexRange instead. */
@@ -592,14 +702,14 @@ static Vector<int64_t> indices_from_selection(const VArray<bool> &selection)
Vector<int64_t> indices;
if (selection.is_span()) {
Span<bool> span = selection.get_internal_span();
- for (const int64_t i : span.index_range()) {
+ for (const int64_t i : mask) {
if (span[i]) {
indices.append(i);
}
}
}
else {
- for (const int i : selection.index_range()) {
+ for (const int i : mask) {
if (selection[i]) {
indices.append(i);
}
@@ -608,27 +718,26 @@ static Vector<int64_t> indices_from_selection(const VArray<bool> &selection)
return indices;
}
-int FieldEvaluator::add_with_destination(GField field, GVMutableArray &dst)
+int FieldEvaluator::add_with_destination(GField field, GVMutableArray dst)
{
const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
- dst_varrays_.append(&dst);
+ dst_varrays_.append(dst);
output_pointer_infos_.append({});
return field_index;
}
int FieldEvaluator::add_with_destination(GField field, GMutableSpan dst)
{
- GVMutableArray &varray = scope_.construct<GVMutableArray_For_GMutableSpan>(dst);
- return this->add_with_destination(std::move(field), varray);
+ return this->add_with_destination(std::move(field), GVMutableArray::ForSpan(dst));
}
-int FieldEvaluator::add(GField field, const GVArray **varray_ptr)
+int FieldEvaluator::add(GField field, GVArray *varray_ptr)
{
const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
dst_varrays_.append(nullptr);
output_pointer_infos_.append(OutputPointerInfo{
varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &UNUSED(scope)) {
- *(const GVArray **)dst = &varray;
+ *(GVArray *)dst = varray;
}});
return field_index;
}
@@ -641,19 +750,41 @@ int FieldEvaluator::add(GField field)
return field_index;
}
+static IndexMask evaluate_selection(const Field<bool> &selection_field,
+ const FieldContext &context,
+ IndexMask full_mask,
+ ResourceScope &scope)
+{
+ if (selection_field) {
+ VArray<bool> selection =
+ evaluate_fields(scope, {selection_field}, full_mask, context)[0].typed<bool>();
+ if (selection.is_single()) {
+ if (selection.get_internal_single()) {
+ return full_mask;
+ }
+ return IndexRange(0);
+ }
+ return scope.add_value(indices_from_selection(full_mask, selection)).as_span();
+ }
+ return full_mask;
+}
+
void FieldEvaluator::evaluate()
{
BLI_assert_msg(!is_evaluated_, "Cannot evaluate fields twice.");
+
+ selection_mask_ = evaluate_selection(selection_field_, context_, mask_, scope_);
+
Array<GFieldRef> fields(fields_to_evaluate_.size());
for (const int i : fields_to_evaluate_.index_range()) {
fields[i] = fields_to_evaluate_[i];
}
- evaluated_varrays_ = evaluate_fields(scope_, fields, mask_, context_, dst_varrays_);
+ evaluated_varrays_ = evaluate_fields(scope_, fields, selection_mask_, context_, dst_varrays_);
BLI_assert(fields_to_evaluate_.size() == evaluated_varrays_.size());
for (const int i : fields_to_evaluate_.index_range()) {
OutputPointerInfo &info = output_pointer_infos_[i];
if (info.dst != nullptr) {
- info.set(info.dst, *evaluated_varrays_[i], scope_);
+ info.set(info.dst, evaluated_varrays_[i], scope_);
}
}
is_evaluated_ = true;
@@ -661,17 +792,22 @@ void FieldEvaluator::evaluate()
IndexMask FieldEvaluator::get_evaluated_as_mask(const int field_index)
{
- const GVArray &varray = this->get_evaluated(field_index);
- GVArray_Typed<bool> typed_varray{varray};
+ VArray<bool> varray = this->get_evaluated(field_index).typed<bool>();
- if (typed_varray->is_single()) {
- if (typed_varray->get_internal_single()) {
- return IndexRange(typed_varray.size());
+ if (varray.is_single()) {
+ if (varray.get_internal_single()) {
+ return IndexRange(varray.size());
}
return IndexRange(0);
}
- return scope_.add_value(indices_from_selection(*typed_varray)).as_span();
+ return scope_.add_value(indices_from_selection(mask_, varray)).as_span();
+}
+
+IndexMask FieldEvaluator::get_evaluated_selection_as_mask()
+{
+ BLI_assert(is_evaluated_);
+ return selection_mask_;
}
} // namespace blender::fn
diff --git a/source/blender/functions/intern/generic_vector_array.cc b/source/blender/functions/intern/generic_vector_array.cc
index ec95a283919..0d478007a5a 100644
--- a/source/blender/functions/intern/generic_vector_array.cc
+++ b/source/blender/functions/intern/generic_vector_array.cc
@@ -60,15 +60,14 @@ void GVectorArray::extend(const int64_t index, const GVArray &values)
void GVectorArray::extend(const int64_t index, const GSpan values)
{
- GVArray_For_GSpan varray{values};
- this->extend(index, varray);
+ this->extend(index, GVArray::ForSpan(values));
}
void GVectorArray::extend(IndexMask mask, const GVVectorArray &values)
{
for (const int i : mask) {
GVArray_For_GVVectorArrayIndex array{values, i};
- this->extend(i, array);
+ this->extend(i, GVArray(&array));
}
}
diff --git a/source/blender/functions/intern/generic_virtual_array.cc b/source/blender/functions/intern/generic_virtual_array.cc
index 9a83d8cd497..b4180a885e7 100644
--- a/source/blender/functions/intern/generic_virtual_array.cc
+++ b/source/blender/functions/intern/generic_virtual_array.cc
@@ -18,52 +18,11 @@
namespace blender::fn {
-/* --------------------------------------------------------------------
- * GVArray_For_ShallowCopy.
- */
-
-class GVArray_For_ShallowCopy : public GVArray {
- private:
- const GVArray &varray_;
-
- public:
- GVArray_For_ShallowCopy(const GVArray &varray)
- : GVArray(varray.type(), varray.size()), varray_(varray)
- {
- }
-
- private:
- void get_impl(const int64_t index, void *r_value) const override
- {
- varray_.get(index, r_value);
- }
-
- void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
- {
- varray_.get_to_uninitialized(index, r_value);
- }
-
- void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override
- {
- varray_.materialize_to_uninitialized(mask, dst);
- }
-};
-
-/* --------------------------------------------------------------------
- * GVArray.
- */
-
-void GVArray::materialize(void *dst) const
-{
- this->materialize(IndexMask(size_), dst);
-}
-
-void GVArray::materialize(const IndexMask mask, void *dst) const
-{
- this->materialize_impl(mask, dst);
-}
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl
+ * \{ */
-void GVArray::materialize_impl(const IndexMask mask, void *dst) const
+void GVArrayImpl::materialize(const IndexMask mask, void *dst) const
{
for (const int64_t i : mask) {
void *elem_dst = POINTER_OFFSET(dst, type_->size() * i);
@@ -71,18 +30,7 @@ void GVArray::materialize_impl(const IndexMask mask, void *dst) const
}
}
-void GVArray::materialize_to_uninitialized(void *dst) const
-{
- this->materialize_to_uninitialized(IndexMask(size_), dst);
-}
-
-void GVArray::materialize_to_uninitialized(const IndexMask mask, void *dst) const
-{
- BLI_assert(mask.min_array_size() <= size_);
- this->materialize_to_uninitialized_impl(mask, dst);
-}
-
-void GVArray::materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const
+void GVArrayImpl::materialize_to_uninitialized(const IndexMask mask, void *dst) const
{
for (const int64_t i : mask) {
void *elem_dst = POINTER_OFFSET(dst, type_->size() * i);
@@ -90,81 +38,75 @@ void GVArray::materialize_to_uninitialized_impl(const IndexMask mask, void *dst)
}
}
-void GVArray::get_impl(const int64_t index, void *r_value) const
+void GVArrayImpl::get(const int64_t index, void *r_value) const
{
type_->destruct(r_value);
- this->get_to_uninitialized_impl(index, r_value);
+ this->get_to_uninitialized(index, r_value);
}
-bool GVArray::is_span_impl() const
+bool GVArrayImpl::is_span() const
{
return false;
}
-GSpan GVArray::get_internal_span_impl() const
+GSpan GVArrayImpl::get_internal_span() const
{
BLI_assert(false);
return GSpan(*type_);
}
-bool GVArray::is_single_impl() const
+bool GVArrayImpl::is_single() const
{
return false;
}
-void GVArray::get_internal_single_impl(void *UNUSED(r_value)) const
+void GVArrayImpl::get_internal_single(void *UNUSED(r_value)) const
{
BLI_assert(false);
}
-const void *GVArray::try_get_internal_varray_impl() const
+bool GVArrayImpl::try_assign_VArray(void *UNUSED(varray)) const
{
- return nullptr;
+ return false;
}
-/**
- * Creates a new `std::unique_ptr<GVArray>` based on this `GVArray`.
- * The lifetime of the returned virtual array must not be longer than the lifetime of this virtual
- * array.
- */
-GVArrayPtr GVArray::shallow_copy() const
+bool GVArrayImpl::may_have_ownership() const
{
- if (this->is_span()) {
- return std::make_unique<GVArray_For_GSpan>(this->get_internal_span());
- }
- if (this->is_single()) {
- BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer);
- this->get_internal_single(buffer);
- std::unique_ptr new_varray = std::make_unique<GVArray_For_SingleValue>(*type_, size_, buffer);
- type_->destruct(buffer);
- return new_varray;
- }
- return std::make_unique<GVArray_For_ShallowCopy>(*this);
+ /* Use true as default to avoid accidentally creating subclasses that have this set to false but
+ * actually own data. Subclasses should set the to false instead. */
+ return true;
}
-/* --------------------------------------------------------------------
- * GVMutableArray.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVMutableArrayImpl
+ * \{ */
+
+GVMutableArrayImpl::GVMutableArrayImpl(const CPPType &type, const int64_t size)
+ : GVArrayImpl(type, size)
+{
+}
-void GVMutableArray::set_by_copy_impl(const int64_t index, const void *value)
+void GVMutableArrayImpl::set_by_copy(const int64_t index, const void *value)
{
BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer);
type_->copy_construct(value, buffer);
- this->set_by_move_impl(index, buffer);
+ this->set_by_move(index, buffer);
type_->destruct(buffer);
}
-void GVMutableArray::set_by_relocate_impl(const int64_t index, void *value)
+void GVMutableArrayImpl::set_by_relocate(const int64_t index, void *value)
{
- this->set_by_move_impl(index, value);
+ this->set_by_move(index, value);
type_->destruct(value);
}
-void GVMutableArray::set_all_impl(const void *src)
+void GVMutableArrayImpl::set_all(const void *src)
{
if (this->is_span()) {
- const GMutableSpan span = this->get_internal_span();
- type_->copy_assign_n(src, span.data(), size_);
+ const GSpan span = this->get_internal_span();
+ type_->copy_assign_n(src, const_cast<void *>(span.data()), size_);
}
else {
for (int64_t i : IndexRange(size_)) {
@@ -173,147 +115,232 @@ void GVMutableArray::set_all_impl(const void *src)
}
}
-void *GVMutableArray::try_get_internal_mutable_varray_impl()
-{
- return nullptr;
-}
-
void GVMutableArray::fill(const void *value)
{
if (this->is_span()) {
- const GMutableSpan span = this->get_internal_span();
- type_->fill_assign_n(value, span.data(), size_);
+ const GSpan span = this->get_internal_span();
+ this->type().fill_assign_n(value, const_cast<void *>(span.data()), this->size());
}
else {
- for (int64_t i : IndexRange(size_)) {
+ for (int64_t i : IndexRange(this->size())) {
this->set_by_copy(i, value);
}
}
}
-/* --------------------------------------------------------------------
- * GVArray_For_GSpan.
- */
-
-void GVArray_For_GSpan::get_impl(const int64_t index, void *r_value) const
+bool GVMutableArrayImpl::try_assign_VMutableArray(void *UNUSED(varray)) const
{
- type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value);
+ return false;
}
-void GVArray_For_GSpan::get_to_uninitialized_impl(const int64_t index, void *r_value) const
-{
- type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value);
-}
+/** \} */
-bool GVArray_For_GSpan::is_span_impl() const
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl_For_GSpan
+ * \{ */
+
+GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const GMutableSpan span)
+ : GVMutableArrayImpl(span.type(), span.size()),
+ data_(span.data()),
+ element_size_(span.type().size())
{
- return true;
}
-GSpan GVArray_For_GSpan::get_internal_span_impl() const
+GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size)
+ : GVMutableArrayImpl(type, size), element_size_(type.size())
{
- return GSpan(*type_, data_, size_);
}
-/* --------------------------------------------------------------------
- * GVMutableArray_For_GMutableSpan.
- */
-
-void GVMutableArray_For_GMutableSpan::get_impl(const int64_t index, void *r_value) const
+void GVArrayImpl_For_GSpan::get(const int64_t index, void *r_value) const
{
type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
-void GVMutableArray_For_GMutableSpan::get_to_uninitialized_impl(const int64_t index,
- void *r_value) const
+void GVArrayImpl_For_GSpan::get_to_uninitialized(const int64_t index, void *r_value) const
{
type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
-void GVMutableArray_For_GMutableSpan::set_by_copy_impl(const int64_t index, const void *value)
+void GVArrayImpl_For_GSpan::set_by_copy(const int64_t index, const void *value)
{
type_->copy_assign(value, POINTER_OFFSET(data_, element_size_ * index));
}
-void GVMutableArray_For_GMutableSpan::set_by_move_impl(const int64_t index, void *value)
+void GVArrayImpl_For_GSpan::set_by_move(const int64_t index, void *value)
{
type_->move_construct(value, POINTER_OFFSET(data_, element_size_ * index));
}
-void GVMutableArray_For_GMutableSpan::set_by_relocate_impl(const int64_t index, void *value)
+void GVArrayImpl_For_GSpan::set_by_relocate(const int64_t index, void *value)
{
type_->relocate_assign(value, POINTER_OFFSET(data_, element_size_ * index));
}
-bool GVMutableArray_For_GMutableSpan::is_span_impl() const
+bool GVArrayImpl_For_GSpan::is_span() const
{
return true;
}
-GSpan GVMutableArray_For_GMutableSpan::get_internal_span_impl() const
+GSpan GVArrayImpl_For_GSpan::get_internal_span() const
{
return GSpan(*type_, data_, size_);
}
-/* --------------------------------------------------------------------
- * GVArray_For_SingleValueRef.
- */
+class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan {
+ public:
+ using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan;
-void GVArray_For_SingleValueRef::get_impl(const int64_t UNUSED(index), void *r_value) const
-{
- type_->copy_assign(value_, r_value);
-}
+ private:
+ bool may_have_ownership() const override
+ {
+ return false;
+ }
+};
-void GVArray_For_SingleValueRef::get_to_uninitialized_impl(const int64_t UNUSED(index),
- void *r_value) const
-{
- type_->copy_construct(value_, r_value);
-}
+/** \} */
-bool GVArray_For_SingleValueRef::is_span_impl() const
-{
- return size_ == 1;
-}
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl_For_SingleValueRef
+ * \{ */
-GSpan GVArray_For_SingleValueRef::get_internal_span_impl() const
-{
- return GSpan{*type_, value_, 1};
-}
+/* Generic virtual array where each element has the same value. The value is not owned. */
+class GVArrayImpl_For_SingleValueRef : public GVArrayImpl {
+ protected:
+ const void *value_ = nullptr;
-bool GVArray_For_SingleValueRef::is_single_impl() const
-{
- return true;
-}
+ public:
+ GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
+ : GVArrayImpl(type, size), value_(value)
+ {
+ }
-void GVArray_For_SingleValueRef::get_internal_single_impl(void *r_value) const
-{
- type_->copy_assign(value_, r_value);
-}
+ protected:
+ GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArrayImpl(type, size)
+ {
+ }
-/* --------------------------------------------------------------------
- * GVArray_For_SingleValue.
- */
+ void get(const int64_t UNUSED(index), void *r_value) const override
+ {
+ type_->copy_assign(value_, r_value);
+ }
+ void get_to_uninitialized(const int64_t UNUSED(index), void *r_value) const override
+ {
+ type_->copy_construct(value_, r_value);
+ }
-GVArray_For_SingleValue::GVArray_For_SingleValue(const CPPType &type,
- const int64_t size,
- const void *value)
- : GVArray_For_SingleValueRef(type, size)
-{
- value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
- type.copy_construct(value, (void *)value_);
-}
+ bool is_span() const override
+ {
+ return size_ == 1;
+ }
+ GSpan get_internal_span() const override
+ {
+ return GSpan{*type_, value_, 1};
+ }
-GVArray_For_SingleValue::~GVArray_For_SingleValue()
-{
- type_->destruct((void *)value_);
- MEM_freeN((void *)value_);
-}
+ bool is_single() const override
+ {
+ return true;
+ }
+ void get_internal_single(void *r_value) const override
+ {
+ type_->copy_assign(value_, r_value);
+ }
+};
+
+class GVArrayImpl_For_SingleValueRef_final final : public GVArrayImpl_For_SingleValueRef {
+ public:
+ using GVArrayImpl_For_SingleValueRef::GVArrayImpl_For_SingleValueRef;
-/* --------------------------------------------------------------------
- * GVArray_GSpan.
+ private:
+ bool may_have_ownership() const override
+ {
+ return false;
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl_For_SingleValue
+ * \{ */
+
+/* Same as GVArrayImpl_For_SingleValueRef, but the value is owned. */
+class GVArrayImpl_For_SingleValue : public GVArrayImpl_For_SingleValueRef,
+ NonCopyable,
+ NonMovable {
+ public:
+ GVArrayImpl_For_SingleValue(const CPPType &type, const int64_t size, const void *value)
+ : GVArrayImpl_For_SingleValueRef(type, size)
+ {
+ value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
+ type.copy_construct(value, (void *)value_);
+ }
+
+ ~GVArrayImpl_For_SingleValue() override
+ {
+ type_->destruct((void *)value_);
+ MEM_freeN((void *)value_);
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl_For_SmallTrivialSingleValue
+ * \{ */
+
+/**
+ * Contains an inline buffer that can store a single value of a trivial type.
+ * This avoids the allocation that would be done by #GVArrayImpl_For_SingleValue.
*/
+template<int BufferSize> class GVArrayImpl_For_SmallTrivialSingleValue : public GVArrayImpl {
+ private:
+ AlignedBuffer<BufferSize, 8> buffer_;
-GVArray_GSpan::GVArray_GSpan(const GVArray &varray) : GSpan(varray.type()), varray_(varray)
+ public:
+ GVArrayImpl_For_SmallTrivialSingleValue(const CPPType &type,
+ const int64_t size,
+ const void *value)
+ : GVArrayImpl(type, size)
+ {
+ BLI_assert(type.is_trivial());
+ BLI_assert(type.alignment() <= 8);
+ BLI_assert(type.size() <= BufferSize);
+ type.copy_construct(value, &buffer_);
+ }
+
+ private:
+ void get(const int64_t UNUSED(index), void *r_value) const override
+ {
+ this->copy_value_to(r_value);
+ }
+ void get_to_uninitialized(const int64_t UNUSED(index), void *r_value) const override
+ {
+ this->copy_value_to(r_value);
+ }
+
+ bool is_single() const override
+ {
+ return true;
+ }
+ void get_internal_single(void *r_value) const override
+ {
+ this->copy_value_to(r_value);
+ }
+
+ void copy_value_to(void *dst) const
+ {
+ memcpy(dst, &buffer_, type_->size());
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVArray_GSpan
+ * \{ */
+
+GVArray_GSpan::GVArray_GSpan(GVArray varray) : GSpan(varray.type()), varray_(std::move(varray))
{
size_ = varray_.size();
if (varray_.is_span()) {
@@ -334,12 +361,14 @@ GVArray_GSpan::~GVArray_GSpan()
}
}
-/* --------------------------------------------------------------------
- * GVMutableArray_GSpan.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVMutableArray_GSpan
+ * \{ */
-GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray &varray, const bool copy_values_to_span)
- : GMutableSpan(varray.type()), varray_(varray)
+GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray varray, const bool copy_values_to_span)
+ : GMutableSpan(varray.type()), varray_(std::move(varray))
{
size_ = varray_.size();
if (varray_.is_span()) {
@@ -387,47 +416,323 @@ void GVMutableArray_GSpan::disable_not_applied_warning()
show_not_saved_warning_ = false;
}
-/* --------------------------------------------------------------------
- * GVArray_For_SlicedGVArray.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl_For_SlicedGVArray
+ * \{ */
+
+class GVArrayImpl_For_SlicedGVArray : public GVArrayImpl {
+ protected:
+ GVArray varray_;
+ int64_t offset_;
+ IndexRange slice_;
+
+ public:
+ GVArrayImpl_For_SlicedGVArray(GVArray varray, const IndexRange slice)
+ : GVArrayImpl(varray.type(), slice.size()),
+ varray_(std::move(varray)),
+ offset_(slice.start()),
+ slice_(slice)
+ {
+ BLI_assert(slice.one_after_last() <= varray_.size());
+ }
+
+ void get(const int64_t index, void *r_value) const override
+ {
+ varray_.get(index + offset_, r_value);
+ }
+
+ void get_to_uninitialized(const int64_t index, void *r_value) const override
+ {
+ varray_.get_to_uninitialized(index + offset_, r_value);
+ }
+
+ bool is_span() const override
+ {
+ return varray_.is_span();
+ }
+ GSpan get_internal_span() const override
+ {
+ return varray_.get_internal_span().slice(slice_);
+ }
+
+ bool is_single() const override
+ {
+ return varray_.is_single();
+ }
+ void get_internal_single(void *r_value) const override
+ {
+ varray_.get_internal_single(r_value);
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayCommon
+ * \{ */
-void GVArray_For_SlicedGVArray::get_impl(const int64_t index, void *r_value) const
+GVArrayCommon::GVArrayCommon() = default;
+
+GVArrayCommon::GVArrayCommon(const GVArrayCommon &other) : storage_(other.storage_)
{
- varray_.get(index + offset_, r_value);
+ impl_ = this->impl_from_storage();
}
-void GVArray_For_SlicedGVArray::get_to_uninitialized_impl(const int64_t index, void *r_value) const
+GVArrayCommon::GVArrayCommon(GVArrayCommon &&other) noexcept : storage_(std::move(other.storage_))
{
- varray_.get_to_uninitialized(index + offset_, r_value);
+ impl_ = this->impl_from_storage();
+ other.storage_.reset();
+ other.impl_ = nullptr;
}
-/* --------------------------------------------------------------------
- * GVArray_Slice.
- */
+GVArrayCommon::GVArrayCommon(const GVArrayImpl *impl) : impl_(impl)
+{
+ storage_ = impl_;
+}
-GVArray_Slice::GVArray_Slice(const GVArray &varray, const IndexRange slice)
+GVArrayCommon::GVArrayCommon(std::shared_ptr<const GVArrayImpl> impl) : impl_(impl.get())
{
- if (varray.is_span()) {
- /* Create a new virtual for the sliced span. */
- const GSpan span = varray.get_internal_span();
- const GSpan sliced_span = span.slice(slice.start(), slice.size());
- varray_span_.emplace(sliced_span);
- varray_ = &*varray_span_;
+ if (impl) {
+ storage_ = std::move(impl);
}
- else if (varray.is_single()) {
- /* Can just use the existing virtual array, because it's the same value for the indices in the
- * slice anyway. */
- varray_ = &varray;
+}
+
+GVArrayCommon::~GVArrayCommon() = default;
+
+void GVArrayCommon::materialize(void *dst) const
+{
+ this->materialize(IndexMask(impl_->size()), dst);
+}
+
+void GVArrayCommon::materialize(const IndexMask mask, void *dst) const
+{
+ impl_->materialize(mask, dst);
+}
+
+void GVArrayCommon::materialize_to_uninitialized(void *dst) const
+{
+ this->materialize_to_uninitialized(IndexMask(impl_->size()), dst);
+}
+
+void GVArrayCommon::materialize_to_uninitialized(const IndexMask mask, void *dst) const
+{
+ BLI_assert(mask.min_array_size() <= impl_->size());
+ impl_->materialize_to_uninitialized(mask, dst);
+}
+
+bool GVArrayCommon::may_have_ownership() const
+{
+ return impl_->may_have_ownership();
+}
+
+void GVArrayCommon::copy_from(const GVArrayCommon &other)
+{
+ if (this == &other) {
+ return;
}
- else {
- /* Generic version when none of the above method works.
- * We don't necessarily want to materialize the input varray because there might be
- * large distances between the required indices. Then we would materialize many elements that
- * are not accessed later on.
- */
- varray_any_.emplace(varray, slice);
- varray_ = &*varray_any_;
+ storage_ = other.storage_;
+ impl_ = this->impl_from_storage();
+}
+
+void GVArrayCommon::move_from(GVArrayCommon &&other) noexcept
+{
+ if (this == &other) {
+ return;
+ }
+ storage_ = std::move(other.storage_);
+ impl_ = this->impl_from_storage();
+ other.storage_.reset();
+ other.impl_ = nullptr;
+}
+
+bool GVArrayCommon::is_span() const
+{
+ return impl_->is_span();
+}
+
+GSpan GVArrayCommon::get_internal_span() const
+{
+ BLI_assert(this->is_span());
+ return impl_->get_internal_span();
+}
+
+bool GVArrayCommon::is_single() const
+{
+ return impl_->is_single();
+}
+
+void GVArrayCommon::get_internal_single(void *r_value) const
+{
+ BLI_assert(this->is_single());
+ impl_->get_internal_single(r_value);
+}
+
+void GVArrayCommon::get_internal_single_to_uninitialized(void *r_value) const
+{
+ impl_->type().default_construct(r_value);
+ this->get_internal_single(r_value);
+}
+
+const GVArrayImpl *GVArrayCommon::impl_from_storage() const
+{
+ return storage_.extra_info().get_varray(storage_.get());
+}
+
+IndexRange GVArrayCommon::index_range() const
+{
+ return IndexRange(this->size());
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVArray
+ * \{ */
+
+GVArray::GVArray(const GVArray &other) = default;
+
+GVArray::GVArray(GVArray &&other) noexcept = default;
+
+GVArray::GVArray(const GVArrayImpl *impl) : GVArrayCommon(impl)
+{
+}
+
+GVArray::GVArray(std::shared_ptr<const GVArrayImpl> impl) : GVArrayCommon(std::move(impl))
+{
+}
+
+GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value)
+{
+ if (type.is_trivial() && type.size() <= 16 && type.alignment() <= 8) {
+ return GVArray::For<GVArrayImpl_For_SmallTrivialSingleValue<16>>(type, size, value);
+ }
+ return GVArray::For<GVArrayImpl_For_SingleValue>(type, size, value);
+}
+
+GVArray GVArray::ForSingleRef(const CPPType &type, const int64_t size, const void *value)
+{
+ return GVArray::For<GVArrayImpl_For_SingleValueRef_final>(type, size, value);
+}
+
+GVArray GVArray::ForSingleDefault(const CPPType &type, const int64_t size)
+{
+ return GVArray::ForSingleRef(type, size, type.default_value());
+}
+
+GVArray GVArray::ForSpan(GSpan span)
+{
+ /* Use const-cast because the underlying virtual array implementation is shared between const
+ * and non const data. */
+ GMutableSpan mutable_span{span.type(), const_cast<void *>(span.data()), span.size()};
+ return GVArray::For<GVArrayImpl_For_GSpan_final>(mutable_span);
+}
+
+class GVArrayImpl_For_GArray : public GVArrayImpl_For_GSpan {
+ protected:
+ GArray<> array_;
+
+ public:
+ GVArrayImpl_For_GArray(GArray<> array)
+ : GVArrayImpl_For_GSpan(array.as_mutable_span()), array_(std::move(array))
+ {
}
+};
+
+GVArray GVArray::ForGArray(GArray<> array)
+{
+ return GVArray::For<GVArrayImpl_For_GArray>(array);
+}
+
+GVArray GVArray::ForEmpty(const CPPType &type)
+{
+ return GVArray::ForSpan(GSpan(type));
+}
+
+GVArray GVArray::slice(IndexRange slice) const
+{
+ return GVArray::For<GVArrayImpl_For_SlicedGVArray>(*this, slice);
+}
+
+GVArray &GVArray::operator=(const GVArray &other)
+{
+ this->copy_from(other);
+ return *this;
}
+GVArray &GVArray::operator=(GVArray &&other) noexcept
+{
+ this->move_from(std::move(other));
+ return *this;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVMutableArray
+ * \{ */
+
+GVMutableArray::GVMutableArray(const GVMutableArray &other) = default;
+GVMutableArray::GVMutableArray(GVMutableArray &&other) noexcept = default;
+
+GVMutableArray::GVMutableArray(GVMutableArrayImpl *impl) : GVArrayCommon(impl)
+{
+}
+
+GVMutableArray::GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl)
+ : GVArrayCommon(std::move(impl))
+{
+}
+
+GVMutableArray GVMutableArray::ForSpan(GMutableSpan span)
+{
+ return GVMutableArray::For<GVArrayImpl_For_GSpan_final>(span);
+}
+
+GVMutableArray::operator GVArray() const &
+{
+ GVArray varray;
+ varray.copy_from(*this);
+ return varray;
+}
+
+GVMutableArray::operator GVArray() &&noexcept
+{
+ GVArray varray;
+ varray.move_from(std::move(*this));
+ return varray;
+}
+
+GVMutableArray &GVMutableArray::operator=(const GVMutableArray &other)
+{
+ this->copy_from(other);
+ return *this;
+}
+
+GVMutableArray &GVMutableArray::operator=(GVMutableArray &&other) noexcept
+{
+ this->move_from(std::move(other));
+ return *this;
+}
+
+GVMutableArrayImpl *GVMutableArray::get_implementation() const
+{
+ return this->get_impl();
+}
+
+void GVMutableArray::set_all(const void *src)
+{
+ this->get_impl()->set_all(src);
+}
+
+GMutableSpan GVMutableArray::get_internal_span() const
+{
+ BLI_assert(this->is_span());
+ const GSpan span = impl_->get_internal_span();
+ return GMutableSpan(span.type(), const_cast<void *>(span.data()), span.size());
+}
+
+/** \} */
+
} // namespace blender::fn
diff --git a/source/blender/functions/intern/generic_virtual_vector_array.cc b/source/blender/functions/intern/generic_virtual_vector_array.cc
index 6b90ce993ae..e3c0d3109fa 100644
--- a/source/blender/functions/intern/generic_virtual_vector_array.cc
+++ b/source/blender/functions/intern/generic_virtual_vector_array.cc
@@ -18,13 +18,13 @@
namespace blender::fn {
-void GVArray_For_GVVectorArrayIndex::get_impl(const int64_t index_in_vector, void *r_value) const
+void GVArray_For_GVVectorArrayIndex::get(const int64_t index_in_vector, void *r_value) const
{
vector_array_.get_vector_element(index_, index_in_vector, r_value);
}
-void GVArray_For_GVVectorArrayIndex::get_to_uninitialized_impl(const int64_t index_in_vector,
- void *r_value) const
+void GVArray_For_GVVectorArrayIndex::get_to_uninitialized(const int64_t index_in_vector,
+ void *r_value) const
{
type_->default_construct(r_value);
vector_array_.get_vector_element(index_, index_in_vector, r_value);
@@ -32,14 +32,14 @@ void GVArray_For_GVVectorArrayIndex::get_to_uninitialized_impl(const int64_t ind
int64_t GVVectorArray_For_SingleGVArray::get_vector_size_impl(const int64_t UNUSED(index)) const
{
- return array_.size();
+ return varray_.size();
}
void GVVectorArray_For_SingleGVArray::get_vector_element_impl(const int64_t UNUSED(index),
const int64_t index_in_vector,
void *r_value) const
{
- array_.get(index_in_vector, r_value);
+ varray_.get(index_in_vector, r_value);
}
bool GVVectorArray_For_SingleGVArray::is_single_vector_impl() const
diff --git a/source/blender/functions/intern/multi_function.cc b/source/blender/functions/intern/multi_function.cc
index bb657f321ec..837ccc4f4fb 100644
--- a/source/blender/functions/intern/multi_function.cc
+++ b/source/blender/functions/intern/multi_function.cc
@@ -16,30 +16,138 @@
#include "FN_multi_function.hh"
+#include "BLI_task.hh"
+#include "BLI_threads.h"
+
namespace blender::fn {
-class DummyMultiFunction : public MultiFunction {
- public:
- DummyMultiFunction()
- {
- static MFSignature signature = create_signature();
- this->set_signature(&signature);
+using ExecutionHints = MultiFunction::ExecutionHints;
+
+ExecutionHints MultiFunction::execution_hints() const
+{
+ return this->get_execution_hints();
+}
+
+ExecutionHints MultiFunction::get_execution_hints() const
+{
+ return ExecutionHints{};
+}
+
+static bool supports_threading_by_slicing_params(const MultiFunction &fn)
+{
+ for (const int i : fn.param_indices()) {
+ const MFParamType param_type = fn.param_type(i);
+ if (ELEM(param_type.interface_type(),
+ MFParamType::InterfaceType::Mutable,
+ MFParamType::InterfaceType::Output)) {
+ if (param_type.data_type().is_vector()) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static int64_t compute_grain_size(const ExecutionHints &hints, const IndexMask mask)
+{
+ int64_t grain_size = hints.min_grain_size;
+ if (hints.uniform_execution_time) {
+ const int thread_count = BLI_system_thread_count();
+ /* Avoid using a small grain size even if it is not necessary. */
+ const int64_t thread_based_grain_size = mask.size() / thread_count / 4;
+ grain_size = std::max(grain_size, thread_based_grain_size);
+ }
+ if (hints.allocates_array) {
+ const int64_t max_grain_size = 10000;
+ /* Avoid allocating many large intermediate arrays. Better process data in smaller chunks to
+ * keep peak memory usage lower. */
+ grain_size = std::min(grain_size, max_grain_size);
+ }
+ return grain_size;
+}
+
+void MultiFunction::call_auto(IndexMask mask, MFParams params, MFContext context) const
+{
+ if (mask.is_empty()) {
+ return;
}
+ const ExecutionHints hints = this->execution_hints();
+ const int64_t grain_size = compute_grain_size(hints, mask);
- static MFSignature create_signature()
- {
- MFSignatureBuilder signature{"Dummy"};
- return signature.build();
+ if (mask.size() <= grain_size) {
+ this->call(mask, params, context);
+ return;
}
- void call(IndexMask UNUSED(mask),
- MFParams UNUSED(params),
- MFContext UNUSED(context)) const override
- {
+ const bool supports_threading = supports_threading_by_slicing_params(*this);
+ if (!supports_threading) {
+ this->call(mask, params, context);
+ return;
}
-};
-static DummyMultiFunction dummy_multi_function_;
-const MultiFunction &dummy_multi_function = dummy_multi_function_;
+ threading::parallel_for(mask.index_range(), grain_size, [&](const IndexRange sub_range) {
+ const IndexMask sliced_mask = mask.slice(sub_range);
+ if (!hints.allocates_array) {
+ /* There is no benefit to changing indices in this case. */
+ this->call(sliced_mask, params, context);
+ return;
+ }
+ if (sliced_mask[0] < grain_size) {
+ /* The indices are low, no need to offset them. */
+ this->call(sliced_mask, params, context);
+ return;
+ }
+ const int64_t input_slice_start = sliced_mask[0];
+ const int64_t input_slice_size = sliced_mask.last() - input_slice_start + 1;
+ const IndexRange input_slice_range{input_slice_start, input_slice_size};
+
+ Vector<int64_t> offset_mask_indices;
+ const IndexMask offset_mask = mask.slice_and_offset(sub_range, offset_mask_indices);
+
+ MFParamsBuilder offset_params{*this, offset_mask.min_array_size()};
+
+ /* Slice all parameters so that for the actual function call. */
+ for (const int param_index : this->param_indices()) {
+ const MFParamType param_type = this->param_type(param_index);
+ switch (param_type.category()) {
+ case MFParamType::SingleInput: {
+ const GVArray &varray = params.readonly_single_input(param_index);
+ offset_params.add_readonly_single_input(varray.slice(input_slice_range));
+ break;
+ }
+ case MFParamType::SingleMutable: {
+ const GMutableSpan span = params.single_mutable(param_index);
+ const GMutableSpan sliced_span = span.slice(input_slice_range);
+ offset_params.add_single_mutable(sliced_span);
+ break;
+ }
+ case MFParamType::SingleOutput: {
+ const GMutableSpan span = params.uninitialized_single_output_if_required(param_index);
+ if (span.is_empty()) {
+ offset_params.add_ignored_single_output();
+ }
+ else {
+ const GMutableSpan sliced_span = span.slice(input_slice_range);
+ offset_params.add_uninitialized_single_output(sliced_span);
+ }
+ break;
+ }
+ case MFParamType::VectorInput:
+ case MFParamType::VectorMutable:
+ case MFParamType::VectorOutput: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+ }
+
+ this->call(offset_mask, offset_params, context);
+ });
+}
+
+std::string MultiFunction::debug_name() const
+{
+ return signature_ref_->function_name;
+}
} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_builder.cc b/source/blender/functions/intern/multi_function_builder.cc
index f891f162820..24f9bbe0179 100644
--- a/source/blender/functions/intern/multi_function_builder.cc
+++ b/source/blender/functions/intern/multi_function_builder.cc
@@ -32,10 +32,8 @@ CustomMF_GenericConstant::CustomMF_GenericConstant(const CPPType &type,
}
value_ = value;
- MFSignatureBuilder signature{"Constant " + type.name()};
- std::stringstream ss;
- type.print_or_default(value, ss, type.name());
- signature.single_output(ss.str(), type);
+ MFSignatureBuilder signature{"Constant"};
+ signature.single_output("Value", type);
signature_ = signature.build();
this->set_signature(&signature_);
}
@@ -73,28 +71,11 @@ bool CustomMF_GenericConstant::equals(const MultiFunction &other) const
return type_.is_equal(value_, _other->value_);
}
-static std::string gspan_to_string(GSpan array)
-{
- const CPPType &type = array.type();
- std::stringstream ss;
- ss << "[";
- const int64_t max_amount = 5;
- for (int64_t i : IndexRange(std::min(max_amount, array.size()))) {
- type.print_or_default(array[i], ss, type.name());
- ss << ", ";
- }
- if (max_amount < array.size()) {
- ss << "...";
- }
- ss << "]";
- return ss.str();
-}
-
CustomMF_GenericConstantArray::CustomMF_GenericConstantArray(GSpan array) : array_(array)
{
const CPPType &type = array.type();
- MFSignatureBuilder signature{"Constant " + type.name() + " Vector"};
- signature.vector_output(gspan_to_string(array), type);
+ MFSignatureBuilder signature{"Constant Vector"};
+ signature.vector_output("Value", type);
signature_ = signature.build();
this->set_signature(&signature_);
}
@@ -109,12 +90,11 @@ void CustomMF_GenericConstantArray::call(IndexMask mask,
}
}
-CustomMF_DefaultOutput::CustomMF_DefaultOutput(StringRef name,
- Span<MFDataType> input_types,
+CustomMF_DefaultOutput::CustomMF_DefaultOutput(Span<MFDataType> input_types,
Span<MFDataType> output_types)
: output_amount_(output_types.size())
{
- MFSignatureBuilder signature{name};
+ MFSignatureBuilder signature{"Default Output"};
for (MFDataType data_type : input_types) {
signature.input("Input", data_type);
}
@@ -140,9 +120,9 @@ void CustomMF_DefaultOutput::call(IndexMask mask, MFParams params, MFContext UNU
}
}
-CustomMF_GenericCopy::CustomMF_GenericCopy(StringRef name, MFDataType data_type)
+CustomMF_GenericCopy::CustomMF_GenericCopy(MFDataType data_type)
{
- MFSignatureBuilder signature{name};
+ MFSignatureBuilder signature{"Copy"};
signature.input("Input", data_type);
signature.output("Output", data_type);
signature_ = signature.build();
diff --git a/source/blender/functions/intern/multi_function_parallel.cc b/source/blender/functions/intern/multi_function_parallel.cc
deleted file mode 100644
index 5a8c621f0b3..00000000000
--- a/source/blender/functions/intern/multi_function_parallel.cc
+++ /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.
- */
-
-#include "FN_multi_function_parallel.hh"
-
-#include "BLI_task.hh"
-
-namespace blender::fn {
-
-ParallelMultiFunction::ParallelMultiFunction(const MultiFunction &fn, const int64_t grain_size)
- : fn_(fn), grain_size_(grain_size)
-{
- this->set_signature(&fn.signature());
-
- threading_supported_ = true;
- for (const int param_index : fn.param_indices()) {
- const MFParamType param_type = fn.param_type(param_index);
- if (param_type.data_type().category() == MFDataType::Vector) {
- /* Vector parameters do not support threading yet. */
- threading_supported_ = false;
- break;
- }
- }
-}
-
-void ParallelMultiFunction::call(IndexMask full_mask, MFParams params, MFContext context) const
-{
- if (full_mask.size() <= grain_size_ || !threading_supported_) {
- fn_.call(full_mask, params, context);
- return;
- }
-
- threading::parallel_for(full_mask.index_range(), grain_size_, [&](const IndexRange mask_slice) {
- Vector<int64_t> sub_mask_indices;
- const IndexMask sub_mask = full_mask.slice_and_offset(mask_slice, sub_mask_indices);
- if (sub_mask.is_empty()) {
- return;
- }
- const int64_t input_slice_start = full_mask[mask_slice.first()];
- const int64_t input_slice_size = full_mask[mask_slice.last()] - input_slice_start + 1;
- const IndexRange input_slice_range{input_slice_start, input_slice_size};
-
- MFParamsBuilder sub_params{fn_, sub_mask.min_array_size()};
- ResourceScope &scope = sub_params.resource_scope();
-
- /* All parameters are sliced so that the wrapped multi-function does not have to take care of
- * the index offset. */
- for (const int param_index : fn_.param_indices()) {
- const MFParamType param_type = fn_.param_type(param_index);
- switch (param_type.category()) {
- case MFParamType::SingleInput: {
- const GVArray &varray = params.readonly_single_input(param_index);
- const GVArray &sliced_varray = scope.construct<GVArray_Slice>(varray, input_slice_range);
- sub_params.add_readonly_single_input(sliced_varray);
- break;
- }
- case MFParamType::SingleMutable: {
- const GMutableSpan span = params.single_mutable(param_index);
- const GMutableSpan sliced_span = span.slice(input_slice_start, input_slice_size);
- sub_params.add_single_mutable(sliced_span);
- break;
- }
- case MFParamType::SingleOutput: {
- const GMutableSpan span = params.uninitialized_single_output(param_index);
- const GMutableSpan sliced_span = span.slice(input_slice_start, input_slice_size);
- sub_params.add_uninitialized_single_output(sliced_span);
- break;
- }
- case MFParamType::VectorInput:
- case MFParamType::VectorMutable:
- case MFParamType::VectorOutput: {
- BLI_assert_unreachable();
- break;
- }
- }
- }
-
- fn_.call(sub_mask, sub_params, context);
- });
-}
-
-} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_params.cc b/source/blender/functions/intern/multi_function_params.cc
new file mode 100644
index 00000000000..376c5b2deb7
--- /dev/null
+++ b/source/blender/functions/intern/multi_function_params.cc
@@ -0,0 +1,44 @@
+/*
+ * 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 "FN_multi_function_params.hh"
+
+namespace blender::fn {
+
+GMutableSpan MFParams::ensure_dummy_single_output(int data_index)
+{
+ /* Lock because we are actually modifying #builder_ and it may be used by multiple threads. */
+ std::lock_guard lock{builder_->mutex_};
+
+ for (const std::pair<int, GMutableSpan> &items : builder_->dummy_output_spans_) {
+ if (items.first == data_index) {
+ return items.second;
+ }
+ }
+
+ const CPPType &type = builder_->mutable_spans_[data_index].type();
+ void *buffer = builder_->scope_.linear_allocator().allocate(
+ builder_->min_array_size_ * type.size(), type.alignment());
+ if (!type.is_trivially_destructible()) {
+ builder_->scope_.add_destruct_call(
+ [&type, buffer, mask = builder_->mask_]() { type.destruct_indices(buffer, mask); });
+ }
+ const GMutableSpan span{type, buffer, builder_->min_array_size_};
+ builder_->dummy_output_spans_.append({data_index, span});
+ return span;
+}
+
+} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_procedure.cc b/source/blender/functions/intern/multi_function_procedure.cc
index 986c5dff0c4..804beb7d66f 100644
--- a/source/blender/functions/intern/multi_function_procedure.cc
+++ b/source/blender/functions/intern/multi_function_procedure.cc
@@ -782,7 +782,7 @@ class MFProcedureDotExport {
void instruction_to_string(const MFCallInstruction &instruction, std::stringstream &ss)
{
const MultiFunction &fn = instruction.fn();
- this->instruction_name_format(fn.name() + ": ", ss);
+ this->instruction_name_format(fn.debug_name() + ": ", ss);
for (const int param_index : fn.param_indices()) {
const MFParamType param_type = fn.param_type(param_index);
const MFVariable *variable = instruction.params()[param_index];
diff --git a/source/blender/functions/intern/multi_function_procedure_executor.cc b/source/blender/functions/intern/multi_function_procedure_executor.cc
index 6d2d121bafd..47643ed22ee 100644
--- a/source/blender/functions/intern/multi_function_procedure_executor.cc
+++ b/source/blender/functions/intern/multi_function_procedure_executor.cc
@@ -20,13 +20,12 @@
namespace blender::fn {
-MFProcedureExecutor::MFProcedureExecutor(std::string name, const MFProcedure &procedure)
- : procedure_(procedure)
+MFProcedureExecutor::MFProcedureExecutor(const MFProcedure &procedure) : procedure_(procedure)
{
- MFSignatureBuilder signature(std::move(name));
+ MFSignatureBuilder signature("Procedure Executor");
for (const ConstMFParameter &param : procedure.params()) {
- signature.add(param.variable->name(), MFParamType(param.type, param.variable->data_type()));
+ signature.add("Parameter", MFParamType(param.type, param.variable->data_type()));
}
signature_ = signature.build();
@@ -66,6 +65,7 @@ struct VariableValue_GVArray : public VariableValue {
VariableValue_GVArray(const GVArray &data) : VariableValue(static_type), data(data)
{
+ BLI_assert(data);
}
};
@@ -139,32 +139,36 @@ class VariableState;
*/
class ValueAllocator : NonCopyable, NonMovable {
private:
- /* Allocate with 64 byte alignment for better reusability of buffers and improved cache
- * performance. */
+ /**
+ * Allocate with 64 byte alignment for better reusability of buffers and improved cache
+ * performance.
+ */
static constexpr inline int min_alignment = 64;
- /* Use stacks so that the most recently used buffers are reused first. This improves cache
- * efficiency. */
- std::array<Stack<VariableValue *>, tot_variable_value_types> values_free_lists_;
- /* The integer key is the size of one element (e.g. 4 for an integer buffer). All buffers are
- * aligned to #min_alignment bytes. */
+ /** All buffers in the free-lists below have been allocated with this allocator. */
+ LinearAllocator<> &linear_allocator_;
+
+ /**
+ * Use stacks so that the most recently used buffers are reused first. This improves cache
+ * efficiency.
+ */
+ std::array<Stack<VariableValue *>, tot_variable_value_types> variable_value_free_lists_;
+
+ /**
+ * The integer key is the size of one element (e.g. 4 for an integer buffer). All buffers are
+ * aligned to #min_alignment bytes.
+ */
Map<int, Stack<void *>> span_buffers_free_list_;
- public:
- ValueAllocator() = default;
+ /** Cache buffers for single values of different types. */
+ Map<const CPPType *, Stack<void *>> single_value_free_lists_;
- ~ValueAllocator()
+ /** The cached memory buffers can hold #VariableState values. */
+ Stack<void *> variable_state_free_list_;
+
+ public:
+ ValueAllocator(LinearAllocator<> &linear_allocator) : linear_allocator_(linear_allocator)
{
- for (Stack<VariableValue *> &stack : values_free_lists_) {
- while (!stack.is_empty()) {
- MEM_freeN(stack.pop());
- }
- }
- for (Stack<void *> &stack : span_buffers_free_list_.values()) {
- while (!stack.is_empty()) {
- MEM_freeN(stack.pop());
- }
- }
}
template<typename... Args> VariableState *obtain_variable_state(Args &&...args);
@@ -190,17 +194,17 @@ class ValueAllocator : NonCopyable, NonMovable {
{
void *buffer = nullptr;
- const int element_size = type.size();
- const int alignment = type.alignment();
+ const int64_t element_size = type.size();
+ const int64_t alignment = type.alignment();
if (alignment > min_alignment) {
/* In this rare case we fallback to not reusing existing buffers. */
- buffer = MEM_mallocN_aligned(element_size * size, alignment, __func__);
+ buffer = linear_allocator_.allocate(element_size * size, alignment);
}
else {
Stack<void *> *stack = span_buffers_free_list_.lookup_ptr(element_size);
if (stack == nullptr || stack->is_empty()) {
- buffer = MEM_mallocN_aligned(element_size * size, min_alignment, __func__);
+ buffer = linear_allocator_.allocate(element_size * size, min_alignment);
}
else {
/* Reuse existing buffer. */
@@ -224,7 +228,14 @@ class ValueAllocator : NonCopyable, NonMovable {
VariableValue_OneSingle *obtain_OneSingle(const CPPType &type)
{
- void *buffer = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
+ Stack<void *> &stack = single_value_free_lists_.lookup_or_add_default(&type);
+ void *buffer;
+ if (stack.is_empty()) {
+ buffer = linear_allocator_.allocate(type.size(), type.alignment());
+ }
+ else {
+ buffer = stack.pop();
+ }
return this->obtain<VariableValue_OneSingle>(buffer);
}
@@ -262,11 +273,11 @@ class ValueAllocator : NonCopyable, NonMovable {
}
case ValueType::OneSingle: {
auto *value_typed = static_cast<VariableValue_OneSingle *>(value);
+ const CPPType &type = data_type.single_type();
if (value_typed->is_initialized) {
- const CPPType &type = data_type.single_type();
type.destruct(value_typed->data);
}
- MEM_freeN(value_typed->data);
+ single_value_free_lists_.lookup_or_add_default(&type).push(value_typed->data);
break;
}
case ValueType::OneVector: {
@@ -276,7 +287,7 @@ class ValueAllocator : NonCopyable, NonMovable {
}
}
- Stack<VariableValue *> &stack = values_free_lists_[(int)value->type];
+ Stack<VariableValue *> &stack = variable_value_free_lists_[(int)value->type];
stack.push(value);
}
@@ -284,9 +295,9 @@ class ValueAllocator : NonCopyable, NonMovable {
template<typename T, typename... Args> T *obtain(Args &&...args)
{
static_assert(std::is_base_of_v<VariableValue, T>);
- Stack<VariableValue *> &stack = values_free_lists_[(int)T::static_type];
+ Stack<VariableValue *> &stack = variable_value_free_lists_[(int)T::static_type];
if (stack.is_empty()) {
- void *buffer = MEM_mallocN(sizeof(T), __func__);
+ void *buffer = linear_allocator_.allocate(sizeof(T), alignof(T));
return new (buffer) T(std::forward<Args>(args)...);
}
return new (stack.pop()) T(std::forward<Args>(args)...);
@@ -669,7 +680,12 @@ class VariableState : NonCopyable, NonMovable {
tot_initialized_ += mask.size();
}
- void destruct(IndexMask mask,
+ /**
+ * Destruct the masked elements in this variable.
+ * \return True when all elements of this variable are initialized and the variable state can be
+ * released.
+ */
+ bool destruct(IndexMask mask,
IndexMask full_mask,
const MFDataType &data_type,
ValueAllocator &value_allocator)
@@ -679,13 +695,12 @@ class VariableState : NonCopyable, NonMovable {
/* Sanity check to make sure that enough indices can be destructed. */
BLI_assert(new_tot_initialized >= 0);
+ bool do_destruct_self = false;
+
switch (value_->type) {
case ValueType::GVArray: {
if (mask.size() == full_mask.size()) {
- /* All elements are destructed. The elements are owned by the caller, so we don't
- * actually destruct them. */
- value_allocator.release_value(value_, data_type);
- value_ = value_allocator.obtain_OneSingle(data_type.single_type());
+ do_destruct_self = true;
}
else {
/* Not all elements are destructed. Since we can't work on the original array, we have to
@@ -701,18 +716,13 @@ class VariableState : NonCopyable, NonMovable {
const CPPType &type = data_type.single_type();
type.destruct_indices(this->value_as<VariableValue_Span>()->data, mask);
if (new_tot_initialized == 0) {
- /* Release span when all values are initialized. */
- value_allocator.release_value(value_, data_type);
- value_ = value_allocator.obtain_OneSingle(data_type.single_type());
+ do_destruct_self = true;
}
break;
}
case ValueType::GVVectorArray: {
if (mask.size() == full_mask.size()) {
- /* All elements are cleared. The elements are owned by the caller, so don't actually
- * destruct them. */
- value_allocator.release_value(value_, data_type);
- value_ = value_allocator.obtain_OneVector(data_type.vector_base_type());
+ do_destruct_self = true;
}
else {
/* Not all elements are cleared. Since we can't work on the original vector array, we
@@ -731,23 +741,24 @@ class VariableState : NonCopyable, NonMovable {
case ValueType::OneSingle: {
auto *value_typed = this->value_as<VariableValue_OneSingle>();
BLI_assert(value_typed->is_initialized);
+ UNUSED_VARS_NDEBUG(value_typed);
if (mask.size() == tot_initialized_) {
- const CPPType &type = data_type.single_type();
- type.destruct(value_typed->data);
- value_typed->is_initialized = false;
+ do_destruct_self = true;
}
break;
}
case ValueType::OneVector: {
auto *value_typed = this->value_as<VariableValue_OneVector>();
+ UNUSED_VARS(value_typed);
if (mask.size() == tot_initialized_) {
- value_typed->data.clear({0});
+ do_destruct_self = true;
}
break;
}
}
tot_initialized_ = new_tot_initialized;
+ return do_destruct_self;
}
void indices_split(IndexMask mask, IndicesSplitVectors &r_indices)
@@ -756,7 +767,7 @@ class VariableState : NonCopyable, NonMovable {
switch (value_->type) {
case ValueType::GVArray: {
- const GVArray_Typed<bool> varray{this->value_as<VariableValue_GVArray>()->data};
+ const VArray<bool> varray = this->value_as<VariableValue_GVArray>()->data.typed<bool>();
for (const int i : mask) {
r_indices[varray[i]].append(i);
}
@@ -801,12 +812,17 @@ class VariableState : NonCopyable, NonMovable {
template<typename... Args> VariableState *ValueAllocator::obtain_variable_state(Args &&...args)
{
- return new VariableState(std::forward<Args>(args)...);
+ if (variable_state_free_list_.is_empty()) {
+ void *buffer = linear_allocator_.allocate(sizeof(VariableState), alignof(VariableState));
+ return new (buffer) VariableState(std::forward<Args>(args)...);
+ }
+ return new (variable_state_free_list_.pop()) VariableState(std::forward<Args>(args)...);
}
void ValueAllocator::release_variable_state(VariableState *state)
{
- delete state;
+ state->~VariableState();
+ variable_state_free_list_.push(state);
}
/** Keeps track of the states of all variables during evaluation. */
@@ -817,7 +833,8 @@ class VariableStates {
IndexMask full_mask_;
public:
- VariableStates(IndexMask full_mask) : full_mask_(full_mask)
+ VariableStates(LinearAllocator<> &linear_allocator, IndexMask full_mask)
+ : value_allocator_(linear_allocator), full_mask_(full_mask)
{
}
@@ -939,7 +956,10 @@ class VariableStates {
void destruct(const MFVariable &variable, const IndexMask &mask)
{
VariableState &variable_state = this->get_variable_state(variable);
- variable_state.destruct(mask, full_mask_, variable.data_type(), value_allocator_);
+ if (variable_state.destruct(mask, full_mask_, variable.data_type(), value_allocator_)) {
+ variable_state.destruct_self(value_allocator_, variable.data_type());
+ variable_states_.remove_contained(&variable);
+ }
}
VariableState &get_variable_state(const MFVariable &variable)
@@ -1045,7 +1065,7 @@ static void execute_call_instruction(const MFCallInstruction &instruction,
}
try {
- fn.call(mask, params, context);
+ fn.call_auto(mask, params, context);
}
catch (...) {
/* Multi-functions must not throw exceptions. */
@@ -1161,9 +1181,9 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c
{
BLI_assert(procedure_.validate());
- LinearAllocator<> allocator;
+ LinearAllocator<> linear_allocator;
- VariableStates variable_states{full_mask};
+ VariableStates variable_states{linear_allocator, full_mask};
variable_states.add_initial_variable_states(*this, procedure_, params);
InstructionScheduler scheduler;
@@ -1236,4 +1256,12 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c
}
}
+MultiFunction::ExecutionHints MFProcedureExecutor::get_execution_hints() const
+{
+ ExecutionHints hints;
+ hints.allocates_array = true;
+ hints.min_grain_size = 10000;
+ return hints;
+}
+
} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_procedure_optimization.cc b/source/blender/functions/intern/multi_function_procedure_optimization.cc
new file mode 100644
index 00000000000..9ad428dcbd8
--- /dev/null
+++ b/source/blender/functions/intern/multi_function_procedure_optimization.cc
@@ -0,0 +1,90 @@
+/*
+ * 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 "FN_multi_function_procedure_optimization.hh"
+
+namespace blender::fn::procedure_optimization {
+
+void move_destructs_up(MFProcedure &procedure, MFInstruction &block_end_instr)
+{
+ /* A mapping from a variable to its destruct instruction. */
+ Map<MFVariable *, MFDestructInstruction *> destruct_instructions;
+ MFInstruction *current_instr = &block_end_instr;
+ while (true) {
+ MFInstructionType instr_type = current_instr->type();
+ switch (instr_type) {
+ case MFInstructionType::Destruct: {
+ MFDestructInstruction &destruct_instr = static_cast<MFDestructInstruction &>(
+ *current_instr);
+ MFVariable *variable = destruct_instr.variable();
+ if (variable == nullptr) {
+ continue;
+ }
+ /* Remember this destruct instruction so that it can be moved up later on when the last use
+ * of the variable is found. */
+ destruct_instructions.add(variable, &destruct_instr);
+ break;
+ }
+ case MFInstructionType::Call: {
+ MFCallInstruction &call_instr = static_cast<MFCallInstruction &>(*current_instr);
+ /* For each variable, place the corresponding remembered destruct instruction right after
+ * this call instruction. */
+ for (MFVariable *variable : call_instr.params()) {
+ if (variable == nullptr) {
+ continue;
+ }
+ MFDestructInstruction *destruct_instr = destruct_instructions.pop_default(variable,
+ nullptr);
+ if (destruct_instr == nullptr) {
+ continue;
+ }
+
+ /* Unlink destruct instruction from previous position. */
+ MFInstruction *after_destruct_instr = destruct_instr->next();
+ while (!destruct_instr->prev().is_empty()) {
+ /* Do a copy of the cursor here, because `destruct_instr->prev()` changes when
+ * #set_next is called below. */
+ const MFInstructionCursor cursor = destruct_instr->prev()[0];
+ cursor.set_next(procedure, after_destruct_instr);
+ }
+
+ /* Insert destruct instruction in new position. */
+ MFInstruction *next_instr = call_instr.next();
+ call_instr.set_next(destruct_instr);
+ destruct_instr->set_next(next_instr);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ const Span<MFInstructionCursor> prev_cursors = current_instr->prev();
+ if (prev_cursors.size() != 1) {
+ /* Stop when there is some branching before this instruction. */
+ break;
+ }
+ const MFInstructionCursor &prev_cursor = prev_cursors[0];
+ current_instr = prev_cursor.instruction();
+ if (current_instr == nullptr) {
+ /* Stop when there is no previous instruction. E.g. when this is the first instruction. */
+ break;
+ }
+ }
+}
+
+} // namespace blender::fn::procedure_optimization
diff --git a/source/blender/functions/tests/FN_field_test.cc b/source/blender/functions/tests/FN_field_test.cc
index 041cdbd0f00..4614f9eee58 100644
--- a/source/blender/functions/tests/FN_field_test.cc
+++ b/source/blender/functions/tests/FN_field_test.cc
@@ -34,14 +34,12 @@ class IndexFieldInput final : public FieldInput {
{
}
- const GVArray *get_varray_for_context(const FieldContext &UNUSED(context),
- IndexMask mask,
- ResourceScope &scope) const final
+ GVArray get_varray_for_context(const FieldContext &UNUSED(context),
+ IndexMask mask,
+ ResourceScope &UNUSED(scope)) const final
{
auto index_func = [](int i) { return i; };
- return &scope.construct<
- GVArray_For_EmbeddedVArray<int, VArray_For_Func<int, decltype(index_func)>>>(
- mask.min_array_size(), mask.min_array_size(), index_func);
+ return VArray<int>::ForFunc(mask.min_array_size(), index_func);
}
};
@@ -162,9 +160,9 @@ class TwoOutputFunction : public MultiFunction {
MFSignature signature_;
public:
- TwoOutputFunction(StringRef name)
+ TwoOutputFunction()
{
- MFSignatureBuilder signature{name};
+ MFSignatureBuilder signature{"Two Outputs"};
signature.single_input<int>("In1");
signature.single_input<int>("In2");
signature.single_output<int>("Add");
@@ -192,8 +190,8 @@ TEST(field, FunctionTwoOutputs)
GField index_field_1{std::make_shared<IndexFieldInput>()};
GField index_field_2{std::make_shared<IndexFieldInput>()};
- std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(FieldOperation(
- std::make_unique<TwoOutputFunction>("SI_SI_SO_SO"), {index_field_1, index_field_2}));
+ std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(
+ FieldOperation(std::make_unique<TwoOutputFunction>(), {index_field_1, index_field_2}));
GField result_field_1{fn, 0};
GField result_field_2{fn, 1};
@@ -223,8 +221,8 @@ TEST(field, TwoFunctionsTwoOutputs)
{
GField index_field{std::make_shared<IndexFieldInput>()};
- std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(FieldOperation(
- std::make_unique<TwoOutputFunction>("SI_SI_SO_SO"), {index_field, index_field}));
+ std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(
+ FieldOperation(std::make_unique<TwoOutputFunction>(), {index_field, index_field}));
Array<int64_t> mask_indices = {2, 4, 6, 8};
IndexMask mask = mask_indices.as_span();
@@ -240,20 +238,20 @@ TEST(field, TwoFunctionsTwoOutputs)
FieldContext field_context;
FieldEvaluator field_evaluator{field_context, &mask};
- const VArray<int> *result_1 = nullptr;
- const VArray<int> *result_2 = nullptr;
+ VArray<int> result_1;
+ VArray<int> result_2;
field_evaluator.add(result_field_1, &result_1);
field_evaluator.add(result_field_2, &result_2);
field_evaluator.evaluate();
- EXPECT_EQ(result_1->get(2), 4);
- EXPECT_EQ(result_1->get(4), 8);
- EXPECT_EQ(result_1->get(6), 12);
- EXPECT_EQ(result_1->get(8), 16);
- EXPECT_EQ(result_2->get(2), 24);
- EXPECT_EQ(result_2->get(4), 28);
- EXPECT_EQ(result_2->get(6), 32);
- EXPECT_EQ(result_2->get(8), 36);
+ EXPECT_EQ(result_1.get(2), 4);
+ EXPECT_EQ(result_1.get(4), 8);
+ EXPECT_EQ(result_1.get(6), 12);
+ EXPECT_EQ(result_1.get(8), 16);
+ EXPECT_EQ(result_2.get(2), 24);
+ EXPECT_EQ(result_2.get(4), 28);
+ EXPECT_EQ(result_2.get(6), 32);
+ EXPECT_EQ(result_2.get(8), 36);
}
TEST(field, SameFieldTwice)
@@ -264,16 +262,16 @@ TEST(field, SameFieldTwice)
FieldContext field_context;
IndexMask mask{IndexRange(2)};
ResourceScope scope;
- Vector<const GVArray *> results = evaluate_fields(
+ Vector<GVArray> results = evaluate_fields(
scope, {constant_field, constant_field}, mask, field_context);
- GVArray_Typed<int> varray1{*results[0]};
- GVArray_Typed<int> varray2{*results[1]};
+ VArray<int> varray1 = results[0].typed<int>();
+ VArray<int> varray2 = results[1].typed<int>();
- EXPECT_EQ(varray1->get(0), 10);
- EXPECT_EQ(varray1->get(1), 10);
- EXPECT_EQ(varray2->get(0), 10);
- EXPECT_EQ(varray2->get(1), 10);
+ EXPECT_EQ(varray1.get(0), 10);
+ EXPECT_EQ(varray1.get(1), 10);
+ EXPECT_EQ(varray2.get(0), 10);
+ EXPECT_EQ(varray2.get(1), 10);
}
TEST(field, IgnoredOutput)
@@ -283,12 +281,12 @@ TEST(field, IgnoredOutput)
FieldContext field_context;
FieldEvaluator field_evaluator{field_context, 10};
- const VArray<int> *results = nullptr;
+ VArray<int> results;
field_evaluator.add(field, &results);
field_evaluator.evaluate();
- EXPECT_EQ(results->get(0), 5);
- EXPECT_EQ(results->get(3), 5);
+ EXPECT_EQ(results.get(0), 5);
+ EXPECT_EQ(results.get(3), 5);
}
} // namespace blender::fn::tests
diff --git a/source/blender/functions/tests/FN_generic_array_test.cc b/source/blender/functions/tests/FN_generic_array_test.cc
new file mode 100644
index 00000000000..417ab479cca
--- /dev/null
+++ b/source/blender/functions/tests/FN_generic_array_test.cc
@@ -0,0 +1,118 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_array.hh"
+
+#include "FN_generic_array.hh"
+
+namespace blender::fn::tests {
+
+TEST(generic_array, TypeConstructor)
+{
+ GArray array(CPPType::get<float>());
+ EXPECT_TRUE(array.data() == nullptr);
+ EXPECT_EQ(array.size(), 0);
+ EXPECT_EQ(array.as_span().typed<float>().size(), 0);
+ EXPECT_TRUE(array.is_empty());
+}
+
+TEST(generic_array, MoveConstructor)
+{
+ GArray array_a(CPPType::get<int32_t>(), (int64_t)10);
+ GMutableSpan span_a = array_a.as_mutable_span();
+ MutableSpan<int32_t> typed_span_a = span_a.typed<int32_t>();
+ typed_span_a.fill(42);
+
+ const GArray array_b = std::move(array_a);
+ Span<int32_t> typed_span_b = array_b.as_span().typed<int32_t>();
+ EXPECT_FALSE(array_b.data() == nullptr);
+ EXPECT_EQ(array_b.size(), 10);
+ EXPECT_EQ(typed_span_b[4], 42);
+
+ /* Make sure the copy constructor cleaned up the original, but it shouldn't clear the type. */
+ EXPECT_TRUE(array_a.data() == nullptr); /* NOLINT: bugprone-use-after-move */
+ EXPECT_EQ(array_a.size(), 0); /* NOLINT: bugprone-use-after-move */
+ EXPECT_TRUE(array_a.is_empty()); /* NOLINT: bugprone-use-after-move */
+ EXPECT_EQ(array_b.type(), array_a.type()); /* NOLINT: bugprone-use-after-move */
+}
+
+TEST(generic_array, CopyConstructor)
+{
+ GArray array_a(CPPType::get<int32_t>(), (int64_t)10);
+ GMutableSpan span_a = array_a.as_mutable_span();
+ MutableSpan<int32_t> typed_span_a = span_a.typed<int32_t>();
+ typed_span_a.fill(42);
+
+ /* From span directly. */
+ const GArray array_b = array_a.as_span();
+ Span<int32_t> typed_span_b = array_b.as_span().typed<int32_t>();
+ EXPECT_FALSE(array_b.data() == nullptr);
+ EXPECT_EQ(array_b.size(), 10);
+ EXPECT_EQ(typed_span_b[4], 42);
+ EXPECT_FALSE(array_a.is_empty());
+
+ /* From array. */
+ const GArray array_c = array_a;
+ Span<int32_t> typed_span_c = array_c.as_span().typed<int32_t>();
+ EXPECT_FALSE(array_c.data() == nullptr);
+ EXPECT_EQ(array_c.size(), 10);
+ EXPECT_EQ(typed_span_c[4], 42);
+ EXPECT_FALSE(array_a.is_empty());
+}
+
+TEST(generic_array, BufferAndSizeConstructor)
+{
+ int32_t *values = (int32_t *)MEM_malloc_arrayN(12, sizeof(int32_t), __func__);
+ void *buffer = (void *)values;
+ GArray array(CPPType::get<int32_t>(), buffer, 4);
+ EXPECT_FALSE(array.data() == nullptr);
+ EXPECT_EQ(array.size(), 4);
+ EXPECT_FALSE(array.is_empty());
+ EXPECT_EQ(array.as_span().typed<int>().size(), 4);
+ EXPECT_EQ(array[0], &values[0]);
+ EXPECT_EQ(array[1], &values[1]);
+ EXPECT_EQ(array[2], &values[2]);
+ EXPECT_EQ(array[3], &values[3]);
+}
+
+TEST(generic_array, Reinitialize)
+{
+ GArray array(CPPType::get<int32_t>(), (int64_t)5);
+ EXPECT_FALSE(array.data() == nullptr);
+ GMutableSpan span = array.as_mutable_span();
+ MutableSpan<int32_t> typed_span = span.typed<int32_t>();
+ typed_span.fill(77);
+ EXPECT_FALSE(typed_span.data() == nullptr);
+ typed_span[2] = 8;
+ EXPECT_EQ(array[2], &typed_span[2]);
+ EXPECT_EQ(typed_span[0], 77);
+ EXPECT_EQ(typed_span[1], 77);
+
+ array.reinitialize(10);
+ EXPECT_EQ(array.size(), 10);
+ span = array.as_mutable_span();
+ EXPECT_EQ(span.size(), 10);
+
+ typed_span = span.typed<int32_t>();
+ EXPECT_FALSE(typed_span.data() == nullptr);
+
+ array.reinitialize(0);
+ EXPECT_EQ(array.size(), 0);
+}
+
+TEST(generic_array, InContainer)
+{
+ blender::Array<GArray<>> arrays;
+ for (GArray<> &array : arrays) {
+ array = GArray(CPPType::get<int32_t>(), (int64_t)5);
+ array.as_mutable_span().typed<int32_t>().fill(55);
+ }
+ for (GArray<> &array : arrays) {
+ EXPECT_EQ(array.as_span().typed<int32_t>()[3], 55);
+ }
+}
+
+} // namespace blender::fn::tests
diff --git a/source/blender/functions/tests/FN_multi_function_procedure_test.cc b/source/blender/functions/tests/FN_multi_function_procedure_test.cc
index 0b4b88fba3d..e3de23550c5 100644
--- a/source/blender/functions/tests/FN_multi_function_procedure_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_procedure_test.cc
@@ -9,6 +9,43 @@
namespace blender::fn::tests {
+TEST(multi_function_procedure, ConstantOutput)
+{
+ /**
+ * procedure(int *var2) {
+ * var1 = 5;
+ * var2 = var1 + var1;
+ * }
+ */
+
+ CustomMF_Constant<int> constant_fn{5};
+ CustomMF_SI_SI_SO<int, int, int> add_fn{"Add", [](int a, int b) { return a + b; }};
+
+ MFProcedure procedure;
+ MFProcedureBuilder builder{procedure};
+
+ auto [var1] = builder.add_call<1>(constant_fn);
+ auto [var2] = builder.add_call<1>(add_fn, {var1, var1});
+ builder.add_destruct(*var1);
+ builder.add_return();
+ builder.add_output_parameter(*var2);
+
+ EXPECT_TRUE(procedure.validate());
+
+ MFProcedureExecutor executor{procedure};
+
+ MFParamsBuilder params{executor, 2};
+ MFContextBuilder context;
+
+ Array<int> output_array(2);
+ params.add_uninitialized_single_output(output_array.as_mutable_span());
+
+ executor.call(IndexRange(2), params, context);
+
+ EXPECT_EQ(output_array[0], 10);
+ EXPECT_EQ(output_array[1], 10);
+}
+
TEST(multi_function_procedure, SimpleTest)
{
/**
@@ -36,7 +73,7 @@ TEST(multi_function_procedure, SimpleTest)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor executor{"My Procedure", procedure};
+ MFProcedureExecutor executor{procedure};
MFParamsBuilder params{executor, 3};
MFContextBuilder context;
@@ -88,7 +125,7 @@ TEST(multi_function_procedure, BranchTest)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor procedure_fn{"Condition Test", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
MFParamsBuilder params(procedure_fn, 5);
Array<int> values_a = {1, 5, 3, 6, 2};
@@ -130,7 +167,7 @@ TEST(multi_function_procedure, EvaluateOne)
builder.add_return();
builder.add_output_parameter(*var2);
- MFProcedureExecutor procedure_fn{"Evaluate One", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
MFParamsBuilder params{procedure_fn, 5};
Array<int> values_out = {1, 2, 3, 4, 5};
@@ -202,7 +239,7 @@ TEST(multi_function_procedure, SimpleLoop)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor procedure_fn{"Simple Loop", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
MFParamsBuilder params{procedure_fn, 5};
Array<int> counts = {4, 3, 7, 6, 4};
@@ -258,7 +295,7 @@ TEST(multi_function_procedure, Vectors)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor procedure_fn{"Vectors", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
MFParamsBuilder params{procedure_fn, 5};
Array<int> v1 = {5, 2, 3};
@@ -322,7 +359,7 @@ TEST(multi_function_procedure, BufferReuse)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor procedure_fn{"Buffer Reuse", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
Array<int> inputs = {4, 1, 6, 2, 3};
Array<int> results(5, -1);
diff --git a/source/blender/functions/tests/FN_multi_function_test.cc b/source/blender/functions/tests/FN_multi_function_test.cc
index d99993b35ac..20ca00cf598 100644
--- a/source/blender/functions/tests/FN_multi_function_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_test.cc
@@ -264,7 +264,6 @@ TEST(multi_function, CustomMF_GenericConstant)
{
int value = 42;
CustomMF_GenericConstant fn{CPPType::get<int32_t>(), (const void *)&value, false};
- EXPECT_EQ(fn.param_name(0), "42");
Array<int> outputs(4, 0);
@@ -285,7 +284,6 @@ TEST(multi_function, CustomMF_GenericConstantArray)
{
std::array<int, 4> values = {3, 4, 5, 6};
CustomMF_GenericConstantArray fn{GSpan(Span(values))};
- EXPECT_EQ(fn.param_name(0), "[3, 4, 5, 6, ]");
GVectorArray vector_array{CPPType::get<int32_t>(), 4};
GVectorArray_TypedMutableRef<int> vector_array_ref{vector_array};
diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt
new file mode 100644
index 00000000000..f7ddd393b4d
--- /dev/null
+++ b/source/blender/geometry/CMakeLists.txt
@@ -0,0 +1,61 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+
+set(INC
+ .
+ ../blenkernel
+ ../blenlib
+ ../blentranslation
+ ../functions
+ ../makesdna
+ ../makesrna
+ ../../../intern/guardedalloc
+ ${CMAKE_BINARY_DIR}/source/blender/makesdna/intern
+)
+
+set(SRC
+ intern/mesh_merge_by_distance.cc
+ intern/mesh_to_curve_convert.cc
+ intern/point_merge_by_distance.cc
+ intern/realize_instances.cc
+
+ GEO_mesh_merge_by_distance.hh
+ GEO_mesh_to_curve.hh
+ GEO_point_merge_by_distance.hh
+ GEO_realize_instances.hh
+)
+
+set(LIB
+ bf_blenkernel
+ bf_blenlib
+)
+
+if(WITH_TBB)
+ add_definitions(-DWITH_TBB)
+
+ list(APPEND INC_SYS
+ ${TBB_INCLUDE_DIRS}
+ )
+
+ list(APPEND LIB
+ ${TBB_LIBRARIES}
+ )
+endif()
+
+blender_add_lib(bf_geometry "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/geometry/GEO_mesh_merge_by_distance.hh b/source/blender/geometry/GEO_mesh_merge_by_distance.hh
new file mode 100644
index 00000000000..1d64680a02b
--- /dev/null
+++ b/source/blender/geometry/GEO_mesh_merge_by_distance.hh
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include <optional>
+
+#include "BLI_index_mask.hh"
+#include "BLI_span.hh"
+
+struct Mesh;
+
+/** \file
+ * \ingroup geo
+ */
+
+namespace blender::geometry {
+
+/**
+ * Merge selected vertices into other selected vertices within the \a merge_distance. The merged
+ * indices favor speed over accuracy, since the results will depend on the order of the vertices.
+ *
+ * \returns #std::nullopt if the mesh should not be changed (no vertices are merged), in order to
+ * avoid copying the input. Otherwise returns the new mesh with merged geometry.
+ */
+std::optional<Mesh *> mesh_merge_by_distance_all(const Mesh &mesh,
+ IndexMask selection,
+ float merge_distance);
+
+/**
+ * Merge selected vertices along edges to other selected vertices. Only vertices connected by edges
+ * are considered for merging.
+ *
+ * \returns #std::nullopt if the mesh should not be changed (no vertices are merged), in order to
+ * avoid copying the input. Otherwise returns the new mesh with merged geometry.
+ */
+std::optional<Mesh *> mesh_merge_by_distance_connected(const Mesh &mesh,
+ Span<bool> selection,
+ float merge_distance,
+ bool only_loose_edges);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_mesh_to_curve.hh b/source/blender/geometry/GEO_mesh_to_curve.hh
new file mode 100644
index 00000000000..fac40cc40d5
--- /dev/null
+++ b/source/blender/geometry/GEO_mesh_to_curve.hh
@@ -0,0 +1,40 @@
+/*
+ * 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 "BLI_index_mask.hh"
+
+#include "BKE_spline.hh"
+
+#pragma once
+
+struct Mesh;
+class MeshComponent;
+
+/** \file
+ * \ingroup geo
+ */
+
+namespace blender::geometry {
+
+/**
+ * Convert the mesh into one or many poly splines. Since splines cannot have branches,
+ * intersections of more than three edges will become breaks in splines. Attributes that
+ * are not built-in on meshes and not curves are transferred to the result curve.
+ */
+std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_component,
+ const IndexMask selection);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_point_merge_by_distance.hh b/source/blender/geometry/GEO_point_merge_by_distance.hh
new file mode 100644
index 00000000000..6766f3c559d
--- /dev/null
+++ b/source/blender/geometry/GEO_point_merge_by_distance.hh
@@ -0,0 +1,38 @@
+/*
+ * 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 "BLI_index_mask.hh"
+
+#pragma once
+
+struct PointCloud;
+class PointCloudComponent;
+
+/** \file
+ * \ingroup geo
+ */
+
+namespace blender::geometry {
+
+/**
+ * Merge selected points into other selected points within the \a merge_distance. The merged
+ * indices favor speed over accuracy, since the results will depend on the order of the points.
+ */
+PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
+ const float merge_distance,
+ const IndexMask selection);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_realize_instances.hh b/source/blender/geometry/GEO_realize_instances.hh
new file mode 100644
index 00000000000..ac16196667d
--- /dev/null
+++ b/source/blender/geometry/GEO_realize_instances.hh
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BKE_geometry_set.hh"
+
+namespace blender::geometry {
+
+struct RealizeInstancesOptions {
+ /**
+ * The default is to generate new ids for every element (when there was any id attribute in the
+ * input). This avoids having a geometry that contains the same id many times.
+ * When this is `true` the ids on the original geometries are kept unchanged and ids on instances
+ * are ignored. Ids are zero initialized when the original geometry did not have an id.
+ */
+ bool keep_original_ids = false;
+ /**
+ * When `true` the output geometry will contain all the generic attributes that existed on
+ * instances. Otherwise, instance attributes are ignored.
+ */
+ bool realize_instance_attributes = true;
+};
+
+/**
+ * Join all instances into a single geometry component for each geometry type. For example, all
+ * mesh instances (including the already realized mesh) are joined into a single mesh. The output
+ * geometry set does not contain any instances. If the input did not contain any instances, it is
+ * returned directly.
+ *
+ * The `id` attribute has special handling. If there is an id attribute on any component, the
+ * output will contain an `id` attribute as well. The output id is generated by mixing/hashing ids
+ * of instances and of the instanced geometry data.
+ */
+GeometrySet realize_instances(GeometrySet geometry_set, const RealizeInstancesOptions &options);
+
+GeometrySet realize_instances_legacy(GeometrySet geometry_set);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/mesh_merge_by_distance.cc b/source/blender/geometry/intern/mesh_merge_by_distance.cc
new file mode 100644
index 00000000000..1a07ebf31f6
--- /dev/null
+++ b/source/blender/geometry/intern/mesh_merge_by_distance.cc
@@ -0,0 +1,1729 @@
+/*
+ * 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 "BLI_array.hh"
+#include "BLI_index_mask.hh"
+#include "BLI_kdtree.h"
+#include "BLI_math_vector.hh"
+#include "BLI_vector.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+
+#include "GEO_mesh_merge_by_distance.hh"
+
+//#define USE_WELD_DEBUG
+//#define USE_WELD_NORMALS
+
+namespace blender::geometry {
+
+/* Indicates when the element was not computed. */
+#define OUT_OF_CONTEXT (int)(-1)
+/* Indicates if the edge or face will be collapsed. */
+#define ELEM_COLLAPSED (int)(-2)
+/* indicates whether an edge or vertex in groups_map will be merged. */
+#define ELEM_MERGED (int)(-2)
+
+/* Used to indicate a range in an array specifying a group. */
+struct WeldGroup {
+ int len;
+ int ofs;
+};
+
+/* Edge groups that will be merged. Final vertices are also indicated. */
+struct WeldGroupEdge {
+ struct WeldGroup group;
+ int v1;
+ int v2;
+};
+
+struct WeldVert {
+ /* Indexes relative to the original Mesh. */
+ int vert_dest;
+ int vert_orig;
+};
+
+struct WeldEdge {
+ union {
+ int flag;
+ struct {
+ /* Indexes relative to the original Mesh. */
+ int edge_dest;
+ int edge_orig;
+ int vert_a;
+ int vert_b;
+ };
+ };
+};
+
+struct WeldLoop {
+ union {
+ int flag;
+ struct {
+ /* Indexes relative to the original Mesh. */
+ int vert;
+ int edge;
+ int loop_orig;
+ int loop_skip_to;
+ };
+ };
+};
+
+struct WeldPoly {
+ union {
+ int flag;
+ struct {
+ /* Indexes relative to the original Mesh. */
+ int poly_dst;
+ int poly_orig;
+ int loop_start;
+ int loop_end;
+ /* Final Polygon Size. */
+ int len;
+ /* Group of loops that will be affected. */
+ struct WeldGroup loops;
+ };
+ };
+};
+
+struct WeldMesh {
+ /* Group of vertices to be merged. */
+ Array<WeldGroup> vert_groups;
+ Array<int> vert_groups_buffer;
+
+ /* Group of edges to be merged. */
+ Array<WeldGroupEdge> edge_groups;
+ Array<int> edge_groups_buffer;
+ /* From the original index of the vertex, this indicates which group it is or is going to be
+ * merged. */
+ Array<int> edge_groups_map;
+
+ /* References all polygons and loops that will be affected. */
+ Vector<WeldLoop> wloop;
+ Vector<WeldPoly> wpoly;
+ WeldPoly *wpoly_new;
+ int wloop_len;
+ int wpoly_len;
+ int wpoly_new_len;
+
+ /* From the actual index of the element in the mesh, it indicates what is the index of the Weld
+ * element above. */
+ Array<int> loop_map;
+ Array<int> poly_map;
+
+ int vert_kill_len;
+ int edge_kill_len;
+ int loop_kill_len;
+ int poly_kill_len; /* Including the new polygons. */
+
+ /* Size of the affected polygon with more sides. */
+ int max_poly_len;
+};
+
+struct WeldLoopOfPolyIter {
+ int loop_start;
+ int loop_end;
+ Span<WeldLoop> wloop;
+ Span<MLoop> mloop;
+ Span<int> loop_map;
+ /* Weld group. */
+ int *group;
+
+ int l_curr;
+ int l_next;
+
+ /* Return */
+ int group_len;
+ int v;
+ int e;
+ char type;
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Debug Utils
+ * \{ */
+
+#ifdef USE_WELD_DEBUG
+static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
+ const WeldPoly &wp,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map,
+ int *group_buffer);
+
+static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter);
+
+static void weld_assert_edge_kill_len(Span<WeldEdge> wedge, const int supposed_kill_len)
+{
+ int kills = 0;
+ const WeldEdge *we = &wedge[0];
+ for (int i = wedge.size(); i--; we++) {
+ int edge_dest = we->edge_dest;
+ /* Magically includes collapsed edges. */
+ if (edge_dest != OUT_OF_CONTEXT) {
+ kills++;
+ }
+ }
+ BLI_assert(kills == supposed_kill_len);
+}
+
+static void weld_assert_poly_and_loop_kill_len(Span<WeldPoly> wpoly,
+ Span<WeldPoly> wpoly_new,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map,
+ Span<int> poly_map,
+ Span<MPoly> mpoly,
+ const int supposed_poly_kill_len,
+ const int supposed_loop_kill_len)
+{
+ int poly_kills = 0;
+ int loop_kills = mloop.size();
+ const MPoly *mp = &mpoly[0];
+ for (int i = 0; i < mpoly.size(); i++, mp++) {
+ int poly_ctx = poly_map[i];
+ if (poly_ctx != OUT_OF_CONTEXT) {
+ const WeldPoly *wp = &wpoly[poly_ctx];
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(&iter, *wp, wloop, mloop, loop_map, nullptr)) {
+ poly_kills++;
+ continue;
+ }
+ else {
+ if (wp->poly_dst != OUT_OF_CONTEXT) {
+ poly_kills++;
+ continue;
+ }
+ int remain = wp->len;
+ int l = wp->loop_start;
+ while (remain) {
+ int l_next = l + 1;
+ int loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->loop_skip_to != OUT_OF_CONTEXT) {
+ l_next = wl->loop_skip_to;
+ }
+ if (wl->flag != ELEM_COLLAPSED) {
+ loop_kills--;
+ remain--;
+ }
+ }
+ else {
+ loop_kills--;
+ remain--;
+ }
+ l = l_next;
+ }
+ }
+ }
+ else {
+ loop_kills -= mp->totloop;
+ }
+ }
+
+ const WeldPoly *wp = wpoly_new.data();
+ for (int i = wpoly_new.size(); i--; wp++) {
+ if (wp->poly_dst != OUT_OF_CONTEXT) {
+ poly_kills++;
+ continue;
+ }
+ int remain = wp->len;
+ int l = wp->loop_start;
+ while (remain) {
+ int l_next = l + 1;
+ int loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->loop_skip_to != OUT_OF_CONTEXT) {
+ l_next = wl->loop_skip_to;
+ }
+ if (wl->flag != ELEM_COLLAPSED) {
+ loop_kills--;
+ remain--;
+ }
+ }
+ else {
+ loop_kills--;
+ remain--;
+ }
+ l = l_next;
+ }
+ }
+
+ BLI_assert(poly_kills == supposed_poly_kill_len);
+ BLI_assert(loop_kills == supposed_loop_kill_len);
+}
+
+static void weld_assert_poly_no_vert_repetition(const WeldPoly &wp,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map)
+{
+ const int len = wp.len;
+ Array<int, 64> verts(len);
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) {
+ return;
+ }
+ else {
+ int i = 0;
+ while (weld_iter_loop_of_poly_next(iter)) {
+ verts[i++] = iter.v;
+ }
+ }
+ for (int i = 0; i < len; i++) {
+ int va = verts[i];
+ for (int j = i + 1; j < len; j++) {
+ int vb = verts[j];
+ BLI_assert(va != vb);
+ }
+ }
+}
+
+static void weld_assert_poly_len(const WeldPoly *wp, const Span<WeldLoop> wloop)
+{
+ if (wp->flag == ELEM_COLLAPSED) {
+ return;
+ }
+
+ int len = wp->len;
+ const WeldLoop *wl = &wloop[wp->loops.ofs];
+ BLI_assert(wp->loop_start <= wl->loop_orig);
+
+ int end_wloop = wp->loops.ofs + wp->loops.len;
+ const WeldLoop *wl_end = &wloop[end_wloop - 1];
+
+ int min_len = 0;
+ for (; wl <= wl_end; wl++) {
+ BLI_assert(wl->loop_skip_to == OUT_OF_CONTEXT); /* Not for this case. */
+ if (wl->flag != ELEM_COLLAPSED) {
+ min_len++;
+ }
+ }
+ BLI_assert(len >= min_len);
+
+ int max_len = wp->loop_end - wp->loop_start + 1;
+ BLI_assert(len <= max_len);
+}
+
+#endif /* USE_WELD_DEBUG */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vert API
+ * \{ */
+
+static Vector<WeldVert> weld_vert_ctx_alloc_and_setup(Span<int> vert_dest_map,
+ const int vert_kill_len)
+{
+ Vector<WeldVert> wvert;
+ wvert.reserve(std::min<int>(2 * vert_kill_len, vert_dest_map.size()));
+
+ for (const int i : vert_dest_map.index_range()) {
+ if (vert_dest_map[i] != OUT_OF_CONTEXT) {
+ WeldVert wv{};
+ wv.vert_dest = vert_dest_map[i];
+ wv.vert_orig = i;
+ wvert.append(wv);
+ }
+ }
+ return wvert;
+}
+
+static void weld_vert_groups_setup(Span<WeldVert> wvert,
+ Span<int> vert_dest_map,
+ MutableSpan<int> r_vert_groups_map,
+ Array<int> &r_vert_groups_buffer,
+ Array<WeldGroup> &r_vert_groups)
+{
+ /* Get weld vert groups. */
+
+ int wgroups_len = 0;
+ for (const int i : vert_dest_map.index_range()) {
+ const int vert_dest = vert_dest_map[i];
+ if (vert_dest != OUT_OF_CONTEXT) {
+ if (vert_dest != i) {
+ r_vert_groups_map[i] = ELEM_MERGED;
+ }
+ else {
+ r_vert_groups_map[i] = wgroups_len;
+ wgroups_len++;
+ }
+ }
+ else {
+ r_vert_groups_map[i] = OUT_OF_CONTEXT;
+ }
+ }
+
+ r_vert_groups.reinitialize(wgroups_len);
+ r_vert_groups.fill({0, 0});
+ MutableSpan<WeldGroup> wgroups = r_vert_groups;
+
+ for (const WeldVert &wv : wvert) {
+ int group_index = r_vert_groups_map[wv.vert_dest];
+ wgroups[group_index].len++;
+ }
+
+ int ofs = 0;
+ for (WeldGroup &wg : wgroups) {
+ wg.ofs = ofs;
+ ofs += wg.len;
+ }
+
+ BLI_assert(ofs == wvert.size());
+
+ r_vert_groups_buffer.reinitialize(ofs);
+ for (const WeldVert &wv : wvert) {
+ int group_index = r_vert_groups_map[wv.vert_dest];
+ r_vert_groups_buffer[wgroups[group_index].ofs++] = wv.vert_orig;
+ }
+
+ for (WeldGroup &wg : wgroups) {
+ wg.ofs -= wg.len;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edge API
+ * \{ */
+
+static Vector<WeldEdge> weld_edge_ctx_alloc(Span<MEdge> medge,
+ Span<int> vert_dest_map,
+ MutableSpan<int> r_edge_dest_map,
+ MutableSpan<int> r_edge_ctx_map)
+{
+ /* Edge Context. */
+ int wedge_len = 0;
+
+ Vector<WeldEdge> wedge;
+ wedge.reserve(medge.size());
+
+ for (const int i : medge.index_range()) {
+ int v1 = medge[i].v1;
+ int v2 = medge[i].v2;
+ int v_dest_1 = vert_dest_map[v1];
+ int v_dest_2 = vert_dest_map[v2];
+ if ((v_dest_1 != OUT_OF_CONTEXT) || (v_dest_2 != OUT_OF_CONTEXT)) {
+ WeldEdge we{};
+ we.vert_a = (v_dest_1 != OUT_OF_CONTEXT) ? v_dest_1 : v1;
+ we.vert_b = (v_dest_2 != OUT_OF_CONTEXT) ? v_dest_2 : v2;
+ we.edge_dest = OUT_OF_CONTEXT;
+ we.edge_orig = i;
+ wedge.append(we);
+ r_edge_dest_map[i] = i;
+ r_edge_ctx_map[i] = wedge_len++;
+ }
+ else {
+ r_edge_dest_map[i] = OUT_OF_CONTEXT;
+ r_edge_ctx_map[i] = OUT_OF_CONTEXT;
+ }
+ }
+
+ return wedge;
+}
+
+static void weld_edge_ctx_setup(MutableSpan<WeldGroup> r_vlinks,
+ MutableSpan<int> r_edge_dest_map,
+ MutableSpan<WeldEdge> r_wedge,
+ int *r_edge_kiil_len)
+{
+ /* Setup Edge Overlap. */
+ int edge_kill_len = 0;
+
+ MutableSpan<WeldGroup> v_links = r_vlinks;
+
+ for (WeldEdge &we : r_wedge) {
+ int dst_vert_a = we.vert_a;
+ int dst_vert_b = we.vert_b;
+
+ if (dst_vert_a == dst_vert_b) {
+ BLI_assert(we.edge_dest == OUT_OF_CONTEXT);
+ r_edge_dest_map[we.edge_orig] = ELEM_COLLAPSED;
+ we.flag = ELEM_COLLAPSED;
+ edge_kill_len++;
+ continue;
+ }
+
+ v_links[dst_vert_a].len++;
+ v_links[dst_vert_b].len++;
+ }
+
+ int link_len = 0;
+ for (WeldGroup &vl : r_vlinks) {
+ vl.ofs = link_len;
+ link_len += vl.len;
+ }
+
+ if (link_len > 0) {
+ Array<int> link_edge_buffer(link_len);
+
+ for (const int i : r_wedge.index_range()) {
+ const WeldEdge &we = r_wedge[i];
+ if (we.flag == ELEM_COLLAPSED) {
+ continue;
+ }
+
+ int dst_vert_a = we.vert_a;
+ int dst_vert_b = we.vert_b;
+
+ link_edge_buffer[v_links[dst_vert_a].ofs++] = i;
+ link_edge_buffer[v_links[dst_vert_b].ofs++] = i;
+ }
+
+ for (WeldGroup &vl : r_vlinks) {
+ /* Fix offset */
+ vl.ofs -= vl.len;
+ }
+
+ for (const int i : r_wedge.index_range()) {
+ const WeldEdge &we = r_wedge[i];
+ if (we.edge_dest != OUT_OF_CONTEXT) {
+ /* No need to retest edges.
+ * (Already includes collapsed edges). */
+ continue;
+ }
+
+ int dst_vert_a = we.vert_a;
+ int dst_vert_b = we.vert_b;
+
+ struct WeldGroup *link_a = &v_links[dst_vert_a];
+ struct WeldGroup *link_b = &v_links[dst_vert_b];
+
+ int edges_len_a = link_a->len;
+ int edges_len_b = link_b->len;
+
+ if (edges_len_a <= 1 || edges_len_b <= 1) {
+ continue;
+ }
+
+ int *edges_ctx_a = &link_edge_buffer[link_a->ofs];
+ int *edges_ctx_b = &link_edge_buffer[link_b->ofs];
+ int edge_orig = we.edge_orig;
+
+ for (; edges_len_a--; edges_ctx_a++) {
+ int e_ctx_a = *edges_ctx_a;
+ if (e_ctx_a == i) {
+ continue;
+ }
+ while (edges_len_b && *edges_ctx_b < e_ctx_a) {
+ edges_ctx_b++;
+ edges_len_b--;
+ }
+ if (edges_len_b == 0) {
+ break;
+ }
+ int e_ctx_b = *edges_ctx_b;
+ if (e_ctx_a == e_ctx_b) {
+ WeldEdge *we_b = &r_wedge[e_ctx_b];
+ BLI_assert(ELEM(we_b->vert_a, dst_vert_a, dst_vert_b));
+ BLI_assert(ELEM(we_b->vert_b, dst_vert_a, dst_vert_b));
+ BLI_assert(we_b->edge_dest == OUT_OF_CONTEXT);
+ BLI_assert(we_b->edge_orig != edge_orig);
+ r_edge_dest_map[we_b->edge_orig] = edge_orig;
+ we_b->edge_dest = edge_orig;
+ edge_kill_len++;
+ }
+ }
+ }
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_edge_kill_len(r_wedge, edge_kill_len);
+#endif
+ }
+
+ *r_edge_kiil_len = edge_kill_len;
+}
+
+static void weld_edge_groups_setup(const int medge_len,
+ const int edge_kill_len,
+ MutableSpan<WeldEdge> wedge,
+ Span<int> wedge_map,
+ MutableSpan<int> r_edge_groups_map,
+ Array<int> &r_edge_groups_buffer,
+ Array<WeldGroupEdge> &r_edge_groups)
+{
+ /* Get weld edge groups. */
+ int wgroups_len = wedge.size() - edge_kill_len;
+ r_edge_groups.reinitialize(wgroups_len);
+ r_edge_groups.fill({{0}});
+ MutableSpan<WeldGroupEdge> wegroups = r_edge_groups;
+
+ wgroups_len = 0;
+ for (const int i : IndexRange(medge_len)) {
+ int edge_ctx = wedge_map[i];
+ if (edge_ctx != OUT_OF_CONTEXT) {
+ WeldEdge *we = &wedge[edge_ctx];
+ int edge_dest = we->edge_dest;
+ if (edge_dest != OUT_OF_CONTEXT) {
+ BLI_assert(edge_dest != we->edge_orig);
+ r_edge_groups_map[i] = ELEM_MERGED;
+ }
+ else {
+ we->edge_dest = we->edge_orig;
+ wegroups[wgroups_len].v1 = we->vert_a;
+ wegroups[wgroups_len].v2 = we->vert_b;
+ r_edge_groups_map[i] = wgroups_len;
+ wgroups_len++;
+ }
+ }
+ else {
+ r_edge_groups_map[i] = OUT_OF_CONTEXT;
+ }
+ }
+
+ BLI_assert(wgroups_len == wedge.size() - edge_kill_len);
+
+ if (wgroups_len == 0) {
+ /* All edges in the context are collapsed. */
+ return;
+ }
+
+ for (const WeldEdge &we : wedge) {
+ if (we.flag == ELEM_COLLAPSED) {
+ continue;
+ }
+ int group_index = r_edge_groups_map[we.edge_dest];
+ wegroups[group_index].group.len++;
+ }
+
+ int ofs = 0;
+ for (WeldGroupEdge &wegrp : wegroups) {
+ wegrp.group.ofs = ofs;
+ ofs += wegrp.group.len;
+ }
+
+ r_edge_groups_buffer.reinitialize(ofs);
+ for (const WeldEdge &we : wedge) {
+ if (we.flag == ELEM_COLLAPSED) {
+ continue;
+ }
+ int group_index = r_edge_groups_map[we.edge_dest];
+ r_edge_groups_buffer[wegroups[group_index].group.ofs++] = we.edge_orig;
+ }
+
+ for (WeldGroupEdge &wegrp : wegroups) {
+ wegrp.group.ofs -= wegrp.group.len;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Poly and Loop API
+ * \{ */
+
+static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter &iter,
+ const WeldPoly &wp,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map,
+ int *group_buffer)
+{
+ if (wp.flag == ELEM_COLLAPSED) {
+ return false;
+ }
+
+ iter.loop_start = wp.loop_start;
+ iter.loop_end = wp.loop_end;
+ iter.wloop = wloop;
+ iter.mloop = mloop;
+ iter.loop_map = loop_map;
+ iter.group = group_buffer;
+
+ int group_len = 0;
+ if (group_buffer) {
+ /* First loop group needs more attention. */
+ int loop_start, loop_end, l;
+ loop_start = iter.loop_start;
+ loop_end = l = iter.loop_end;
+ while (l >= loop_start) {
+ const int loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->flag == ELEM_COLLAPSED) {
+ l--;
+ continue;
+ }
+ }
+ break;
+ }
+ if (l != loop_end) {
+ group_len = loop_end - l;
+ int i = 0;
+ while (l < loop_end) {
+ iter.group[i++] = ++l;
+ }
+ }
+ }
+ iter.group_len = group_len;
+
+ iter.l_next = iter.loop_start;
+#ifdef USE_WELD_DEBUG
+ iter.v = OUT_OF_CONTEXT;
+#endif
+ return true;
+}
+
+static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter &iter)
+{
+ const int loop_end = iter.loop_end;
+ Span<WeldLoop> wloop = iter.wloop;
+ Span<int> loop_map = iter.loop_map;
+ int l = iter.l_curr = iter.l_next;
+ if (l == iter.loop_start) {
+ /* `grupo_len` is already calculated in the first loop */
+ }
+ else {
+ iter.group_len = 0;
+ }
+ while (l <= loop_end) {
+ int l_next = l + 1;
+ const int loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->loop_skip_to != OUT_OF_CONTEXT) {
+ l_next = wl->loop_skip_to;
+ }
+ if (wl->flag == ELEM_COLLAPSED) {
+ if (iter.group) {
+ iter.group[iter.group_len++] = l;
+ }
+ l = l_next;
+ continue;
+ }
+#ifdef USE_WELD_DEBUG
+ BLI_assert(iter.v != wl->vert);
+#endif
+ iter.v = wl->vert;
+ iter.e = wl->edge;
+ iter.type = 1;
+ }
+ else {
+ const MLoop &ml = iter.mloop[l];
+#ifdef USE_WELD_DEBUG
+ BLI_assert((uint)iter.v != ml.v);
+#endif
+ iter.v = ml.v;
+ iter.e = ml.e;
+ iter.type = 0;
+ }
+ if (iter.group) {
+ iter.group[iter.group_len++] = l;
+ }
+ iter.l_next = l_next;
+ return true;
+ }
+
+ return false;
+}
+
+static void weld_poly_loop_ctx_alloc(Span<MPoly> mpoly,
+ Span<MLoop> mloop,
+ Span<int> vert_dest_map,
+ Span<int> edge_dest_map,
+ WeldMesh *r_weld_mesh)
+{
+ /* Loop/Poly Context. */
+ Array<int> loop_map(mloop.size());
+ Array<int> poly_map(mpoly.size());
+ int wloop_len = 0;
+ int wpoly_len = 0;
+ int max_ctx_poly_len = 4;
+
+ Vector<WeldLoop> wloop;
+ wloop.reserve(mloop.size());
+
+ Vector<WeldPoly> wpoly;
+ wpoly.reserve(mpoly.size());
+
+ int maybe_new_poly = 0;
+
+ for (const int i : mpoly.index_range()) {
+ const MPoly &mp = mpoly[i];
+ const int loopstart = mp.loopstart;
+ const int totloop = mp.totloop;
+
+ int vert_ctx_len = 0;
+
+ int prev_wloop_len = wloop_len;
+ for (const int i_loop : mloop.index_range().slice(loopstart, totloop)) {
+ int v = mloop[i_loop].v;
+ int e = mloop[i_loop].e;
+ int v_dest = vert_dest_map[v];
+ int e_dest = edge_dest_map[e];
+ bool is_vert_ctx = v_dest != OUT_OF_CONTEXT;
+ bool is_edge_ctx = e_dest != OUT_OF_CONTEXT;
+ if (is_vert_ctx) {
+ vert_ctx_len++;
+ }
+ if (is_vert_ctx || is_edge_ctx) {
+ WeldLoop wl{};
+ wl.vert = is_vert_ctx ? v_dest : v;
+ wl.edge = is_edge_ctx ? e_dest : e;
+ wl.loop_orig = i_loop;
+ wl.loop_skip_to = OUT_OF_CONTEXT;
+ wloop.append(wl);
+
+ loop_map[i_loop] = wloop_len++;
+ }
+ else {
+ loop_map[i_loop] = OUT_OF_CONTEXT;
+ }
+ }
+ if (wloop_len != prev_wloop_len) {
+ int loops_len = wloop_len - prev_wloop_len;
+ WeldPoly wp{};
+ wp.poly_dst = OUT_OF_CONTEXT;
+ wp.poly_orig = i;
+ wp.loops.len = loops_len;
+ wp.loops.ofs = prev_wloop_len;
+ wp.loop_start = loopstart;
+ wp.loop_end = loopstart + totloop - 1;
+ wp.len = totloop;
+ wpoly.append(wp);
+
+ poly_map[i] = wpoly_len++;
+ if (totloop > 5 && vert_ctx_len > 1) {
+ int max_new = (totloop / 3) - 1;
+ vert_ctx_len /= 2;
+ maybe_new_poly += MIN2(max_new, vert_ctx_len);
+ CLAMP_MIN(max_ctx_poly_len, totloop);
+ }
+ }
+ else {
+ poly_map[i] = OUT_OF_CONTEXT;
+ }
+ }
+
+ if (mpoly.size() < (wpoly_len + maybe_new_poly)) {
+ wpoly.resize(wpoly_len + maybe_new_poly);
+ }
+
+ WeldPoly *poly_new = wpoly.data() + wpoly_len;
+
+ r_weld_mesh->wloop = std::move(wloop);
+ r_weld_mesh->wpoly = std::move(wpoly);
+ r_weld_mesh->wpoly_new = poly_new;
+ r_weld_mesh->wloop_len = wloop_len;
+ r_weld_mesh->wpoly_len = wpoly_len;
+ r_weld_mesh->wpoly_new_len = 0;
+ r_weld_mesh->loop_map = std::move(loop_map);
+ r_weld_mesh->poly_map = std::move(poly_map);
+ r_weld_mesh->max_poly_len = max_ctx_poly_len;
+}
+
+static void weld_poly_split_recursive(Span<int> vert_dest_map,
+#ifdef USE_WELD_DEBUG
+ const Span<MLoop> mloop,
+#endif
+ int ctx_verts_len,
+ WeldPoly *r_wp,
+ WeldMesh *r_weld_mesh,
+ int *r_poly_kill,
+ int *r_loop_kill)
+{
+ int poly_len = r_wp->len;
+ if (poly_len > 3 && ctx_verts_len > 1) {
+ const int ctx_loops_len = r_wp->loops.len;
+ const int ctx_loops_ofs = r_wp->loops.ofs;
+ MutableSpan<WeldLoop> wloop = r_weld_mesh->wloop;
+ WeldPoly *wpoly_new = r_weld_mesh->wpoly_new;
+
+ int loop_kill = 0;
+
+ WeldLoop *poly_loops = &wloop[ctx_loops_ofs];
+ WeldLoop *wla = &poly_loops[0];
+ WeldLoop *wla_prev = &poly_loops[ctx_loops_len - 1];
+ while (wla_prev->flag == ELEM_COLLAPSED) {
+ wla_prev--;
+ }
+ const int la_len = ctx_loops_len - 1;
+ for (int la = 0; la < la_len; la++, wla++) {
+ wa_continue:
+ if (wla->flag == ELEM_COLLAPSED) {
+ continue;
+ }
+ int vert_a = wla->vert;
+ /* Only test vertices that will be merged. */
+ if (vert_dest_map[vert_a] != OUT_OF_CONTEXT) {
+ int lb = la + 1;
+ WeldLoop *wlb = wla + 1;
+ WeldLoop *wlb_prev = wla;
+ int killed_ab = 0;
+ ctx_verts_len = 1;
+ for (; lb < ctx_loops_len; lb++, wlb++) {
+ BLI_assert(wlb->loop_skip_to == OUT_OF_CONTEXT);
+ if (wlb->flag == ELEM_COLLAPSED) {
+ killed_ab++;
+ continue;
+ }
+ int vert_b = wlb->vert;
+ if (vert_dest_map[vert_b] != OUT_OF_CONTEXT) {
+ ctx_verts_len++;
+ }
+ if (vert_a == vert_b) {
+ const int dist_a = wlb->loop_orig - wla->loop_orig - killed_ab;
+ const int dist_b = poly_len - dist_a;
+
+ BLI_assert(dist_a != 0 && dist_b != 0);
+ if (dist_a == 1 || dist_b == 1) {
+ BLI_assert(dist_a != dist_b);
+ BLI_assert((wla->flag == ELEM_COLLAPSED) || (wlb->flag == ELEM_COLLAPSED));
+ }
+ else {
+ WeldLoop *wl_tmp = nullptr;
+ if (dist_a == 2) {
+ wl_tmp = wlb_prev;
+ BLI_assert(wla->flag != ELEM_COLLAPSED);
+ BLI_assert(wl_tmp->flag != ELEM_COLLAPSED);
+ wla->flag = ELEM_COLLAPSED;
+ wl_tmp->flag = ELEM_COLLAPSED;
+ loop_kill += 2;
+ poly_len -= 2;
+ }
+ if (dist_b == 2) {
+ if (wl_tmp != nullptr) {
+ r_wp->flag = ELEM_COLLAPSED;
+ *r_poly_kill += 1;
+ }
+ else {
+ wl_tmp = wla_prev;
+ BLI_assert(wlb->flag != ELEM_COLLAPSED);
+ BLI_assert(wl_tmp->flag != ELEM_COLLAPSED);
+ wlb->flag = ELEM_COLLAPSED;
+ wl_tmp->flag = ELEM_COLLAPSED;
+ }
+ loop_kill += 2;
+ poly_len -= 2;
+ }
+ if (wl_tmp == nullptr) {
+ const int new_loops_len = lb - la;
+ const int new_loops_ofs = ctx_loops_ofs + la;
+
+ WeldPoly *new_wp = &wpoly_new[r_weld_mesh->wpoly_new_len++];
+ new_wp->poly_dst = OUT_OF_CONTEXT;
+ new_wp->poly_orig = r_wp->poly_orig;
+ new_wp->loops.len = new_loops_len;
+ new_wp->loops.ofs = new_loops_ofs;
+ new_wp->loop_start = wla->loop_orig;
+ new_wp->loop_end = wlb_prev->loop_orig;
+ new_wp->len = dist_a;
+ weld_poly_split_recursive(vert_dest_map,
+#ifdef USE_WELD_DEBUG
+ mloop,
+#endif
+ ctx_verts_len,
+ new_wp,
+ r_weld_mesh,
+ r_poly_kill,
+ r_loop_kill);
+ BLI_assert(dist_b == poly_len - dist_a);
+ poly_len = dist_b;
+ if (wla_prev->loop_orig > wla->loop_orig) {
+ /* New start. */
+ r_wp->loop_start = wlb->loop_orig;
+ }
+ else {
+ /* The `loop_start` doesn't change but some loops must be skipped. */
+ wla_prev->loop_skip_to = wlb->loop_orig;
+ }
+ wla = wlb;
+ la = lb;
+ goto wa_continue;
+ }
+ break;
+ }
+ }
+ if (wlb->flag != ELEM_COLLAPSED) {
+ wlb_prev = wlb;
+ }
+ }
+ }
+ if (wla->flag != ELEM_COLLAPSED) {
+ wla_prev = wla;
+ }
+ }
+ r_wp->len = poly_len;
+ *r_loop_kill += loop_kill;
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_no_vert_repetition(*r_wp, wloop, mloop, r_weld_mesh->loop_map);
+#endif
+ }
+}
+
+static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
+#ifdef USE_WELD_DEBUG
+ Span<MPoly> mpoly,
+#endif
+ const int mvert_len,
+ Span<int> vert_dest_map,
+ const int remain_edge_ctx_len,
+ MutableSpan<WeldGroup> r_vlinks,
+ WeldMesh *r_weld_mesh)
+{
+ MutableSpan<WeldPoly> wpoly = r_weld_mesh->wpoly;
+ MutableSpan<WeldLoop> wloop = r_weld_mesh->wloop;
+ WeldPoly *wpoly_new = r_weld_mesh->wpoly_new;
+ int wpoly_len = r_weld_mesh->wpoly_len;
+ int wpoly_new_len = 0;
+ int poly_kill_len = 0;
+ int loop_kill_len = 0;
+
+ Span<int> loop_map = r_weld_mesh->loop_map;
+
+ if (remain_edge_ctx_len) {
+
+ /* Setup Poly/Loop. Note that `wpoly_len` may be different than `wpoly.size()` here. */
+ for (const int i : IndexRange(wpoly_len)) {
+ WeldPoly &wp = wpoly[i];
+ const int ctx_loops_len = wp.loops.len;
+ const int ctx_loops_ofs = wp.loops.ofs;
+
+ int poly_len = wp.len;
+ int ctx_verts_len = 0;
+ WeldLoop *wl = &wloop[ctx_loops_ofs];
+ for (int l = ctx_loops_len; l--; wl++) {
+ const int edge_dest = wl->edge;
+ if (edge_dest == ELEM_COLLAPSED) {
+ wl->flag = ELEM_COLLAPSED;
+ if (poly_len == 3) {
+ wp.flag = ELEM_COLLAPSED;
+ poly_kill_len++;
+ loop_kill_len += 3;
+ poly_len = 0;
+ break;
+ }
+ loop_kill_len++;
+ poly_len--;
+ }
+ else {
+ const int vert_dst = wl->vert;
+ if (vert_dest_map[vert_dst] != OUT_OF_CONTEXT) {
+ ctx_verts_len++;
+ }
+ }
+ }
+
+ if (poly_len) {
+ wp.len = poly_len;
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_len(wp, wloop);
+#endif
+
+ weld_poly_split_recursive(vert_dest_map,
+#ifdef USE_WELD_DEBUG
+ mloop,
+#endif
+ ctx_verts_len,
+ &wp,
+ r_weld_mesh,
+ &poly_kill_len,
+ &loop_kill_len);
+
+ wpoly_new_len = r_weld_mesh->wpoly_new_len;
+ }
+ }
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_and_loop_kill_len(wpoly,
+ {wpoly_new, wpoly_new_len},
+ wloop,
+ mloop,
+ loop_map,
+ r_weld_mesh->poly_map,
+ mpoly,
+ poly_kill_len,
+ loop_kill_len);
+#endif
+
+ /* Setup Polygon Overlap. */
+
+ const int wpoly_and_new_len = wpoly_len + wpoly_new_len;
+
+ r_vlinks.fill({0, 0});
+ MutableSpan<WeldGroup> v_links = r_vlinks;
+
+ for (const int i : IndexRange(wpoly_and_new_len)) {
+ const WeldPoly &wp = wpoly[i];
+ WeldLoopOfPolyIter iter;
+ if (weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr)) {
+ while (weld_iter_loop_of_poly_next(iter)) {
+ v_links[iter.v].len++;
+ }
+ }
+ }
+
+ int link_len = 0;
+ for (const int i : IndexRange(mvert_len)) {
+ v_links[i].ofs = link_len;
+ link_len += v_links[i].len;
+ }
+
+ if (link_len) {
+ Array<int> link_poly_buffer(link_len);
+
+ for (const int i : IndexRange(wpoly_and_new_len)) {
+ const WeldPoly &wp = wpoly[i];
+ WeldLoopOfPolyIter iter;
+ if (weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr)) {
+ while (weld_iter_loop_of_poly_next(iter)) {
+ link_poly_buffer[v_links[iter.v].ofs++] = i;
+ }
+ }
+ }
+
+ for (WeldGroup &vl : r_vlinks) {
+ /* Fix offset */
+ vl.ofs -= vl.len;
+ }
+
+ int polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b;
+ polys_len_b = p_ctx_b = 0; /* silence warnings */
+
+ for (const int i : IndexRange(wpoly_and_new_len)) {
+ const WeldPoly &wp = wpoly[i];
+ if (wp.poly_dst != OUT_OF_CONTEXT) {
+ /* No need to retest poly.
+ * (Already includes collapsed polygons). */
+ continue;
+ }
+
+ WeldLoopOfPolyIter iter;
+ weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr);
+ weld_iter_loop_of_poly_next(iter);
+ struct WeldGroup *link_a = &v_links[iter.v];
+ polys_len_a = link_a->len;
+ if (polys_len_a == 1) {
+ BLI_assert(link_poly_buffer[link_a->ofs] == i);
+ continue;
+ }
+ int wp_len = wp.len;
+ polys_ctx_a = &link_poly_buffer[link_a->ofs];
+ for (; polys_len_a--; polys_ctx_a++) {
+ p_ctx_a = *polys_ctx_a;
+ if (p_ctx_a == i) {
+ continue;
+ }
+
+ WeldPoly *wp_tmp = &wpoly[p_ctx_a];
+ if (wp_tmp->len != wp_len) {
+ continue;
+ }
+
+ WeldLoopOfPolyIter iter_b = iter;
+ while (weld_iter_loop_of_poly_next(iter_b)) {
+ struct WeldGroup *link_b = &v_links[iter_b.v];
+ polys_len_b = link_b->len;
+ if (polys_len_b == 1) {
+ BLI_assert(link_poly_buffer[link_b->ofs] == i);
+ polys_len_b = 0;
+ break;
+ }
+
+ polys_ctx_b = &link_poly_buffer[link_b->ofs];
+ for (; polys_len_b; polys_len_b--, polys_ctx_b++) {
+ p_ctx_b = *polys_ctx_b;
+ if (p_ctx_b < p_ctx_a) {
+ continue;
+ }
+ if (p_ctx_b >= p_ctx_a) {
+ if (p_ctx_b > p_ctx_a) {
+ polys_len_b = 0;
+ }
+ break;
+ }
+ }
+ if (polys_len_b == 0) {
+ break;
+ }
+ }
+ if (polys_len_b == 0) {
+ continue;
+ }
+ BLI_assert(p_ctx_a > i);
+ BLI_assert(p_ctx_a == p_ctx_b);
+ BLI_assert(wp_tmp->poly_dst == OUT_OF_CONTEXT);
+ BLI_assert(wp_tmp != &wp);
+ wp_tmp->poly_dst = wp.poly_orig;
+ loop_kill_len += wp_tmp->len;
+ poly_kill_len++;
+ }
+ }
+ }
+ }
+ else {
+ poly_kill_len = r_weld_mesh->wpoly_len;
+ loop_kill_len = r_weld_mesh->wloop_len;
+
+ for (WeldPoly &wp : wpoly) {
+ wp.flag = ELEM_COLLAPSED;
+ }
+ }
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_and_loop_kill_len(wpoly,
+ {wpoly_new, wpoly_new_len},
+ wloop,
+ mloop,
+ loop_map,
+ r_weld_mesh->poly_map,
+ mpoly,
+ poly_kill_len,
+ loop_kill_len);
+#endif
+
+ r_weld_mesh->wpoly_new = wpoly_new;
+ r_weld_mesh->poly_kill_len = poly_kill_len;
+ r_weld_mesh->loop_kill_len = loop_kill_len;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh API
+ * \{ */
+
+static void weld_mesh_context_create(const Mesh &mesh,
+ MutableSpan<int> vert_dest_map,
+ const int vert_kill_len,
+ WeldMesh *r_weld_mesh)
+{
+ Span<MEdge> medge{mesh.medge, mesh.totedge};
+ Span<MPoly> mpoly{mesh.mpoly, mesh.totpoly};
+ Span<MLoop> mloop{mesh.mloop, mesh.totloop};
+ const int mvert_len = mesh.totvert;
+
+ Vector<WeldVert> wvert = weld_vert_ctx_alloc_and_setup(vert_dest_map, vert_kill_len);
+ r_weld_mesh->vert_kill_len = vert_kill_len;
+
+ Array<int> edge_dest_map(medge.size());
+ Array<int> edge_ctx_map(medge.size());
+ Vector<WeldEdge> wedge = weld_edge_ctx_alloc(medge, vert_dest_map, edge_dest_map, edge_ctx_map);
+
+ Array<WeldGroup> v_links(mvert_len, {0, 0});
+ weld_edge_ctx_setup(v_links, edge_dest_map, wedge, &r_weld_mesh->edge_kill_len);
+
+ weld_poly_loop_ctx_alloc(mpoly, mloop, vert_dest_map, edge_dest_map, r_weld_mesh);
+
+ weld_poly_loop_ctx_setup(mloop,
+#ifdef USE_WELD_DEBUG
+ mpoly,
+
+#endif
+ mvert_len,
+ vert_dest_map,
+ wedge.size() - r_weld_mesh->edge_kill_len,
+ v_links,
+ r_weld_mesh);
+
+ weld_vert_groups_setup(wvert,
+ vert_dest_map,
+ vert_dest_map,
+ r_weld_mesh->vert_groups_buffer,
+ r_weld_mesh->vert_groups);
+
+ weld_edge_groups_setup(medge.size(),
+ r_weld_mesh->edge_kill_len,
+ wedge,
+ edge_ctx_map,
+ edge_dest_map,
+ r_weld_mesh->edge_groups_buffer,
+ r_weld_mesh->edge_groups);
+
+ r_weld_mesh->edge_groups_map = std::move(edge_dest_map);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name CustomData
+ * \{ */
+
+static void customdata_weld(
+ const CustomData *source, CustomData *dest, const int *src_indices, int count, int dest_index)
+{
+ if (count == 1) {
+ CustomData_copy_data(source, dest, src_indices[0], dest_index, 1);
+ return;
+ }
+
+ CustomData_interp(source, dest, (const int *)src_indices, nullptr, nullptr, count, dest_index);
+
+ int src_i, dest_i;
+ int j;
+
+ float co[3] = {0.0f, 0.0f, 0.0f};
+#ifdef USE_WELD_NORMALS
+ float no[3] = {0.0f, 0.0f, 0.0f};
+#endif
+ int crease = 0;
+ int bweight = 0;
+ short flag = 0;
+
+ /* interpolates a layer at a time */
+ dest_i = 0;
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
+ const int type = source->layers[src_i].type;
+
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while (dest_i < dest->totlayer && dest->layers[dest_i].type < type) {
+ dest_i++;
+ }
+
+ /* if there are no more dest layers, we're done */
+ if (dest_i == dest->totlayer) {
+ break;
+ }
+
+ /* if we found a matching layer, add the data */
+ if (dest->layers[dest_i].type == type) {
+ void *src_data = source->layers[src_i].data;
+
+ if (type == CD_MVERT) {
+ for (j = 0; j < count; j++) {
+ MVert *mv_src = &((MVert *)src_data)[src_indices[j]];
+ add_v3_v3(co, mv_src->co);
+#ifdef USE_WELD_NORMALS
+ short *mv_src_no = mv_src->no;
+ no[0] += mv_src_no[0];
+ no[1] += mv_src_no[1];
+ no[2] += mv_src_no[2];
+#endif
+ bweight += mv_src->bweight;
+ flag |= mv_src->flag;
+ }
+ }
+ else if (type == CD_MEDGE) {
+ for (j = 0; j < count; j++) {
+ MEdge *me_src = &((MEdge *)src_data)[src_indices[j]];
+ crease += me_src->crease;
+ bweight += me_src->bweight;
+ flag |= me_src->flag;
+ }
+ }
+ else if (CustomData_layer_has_interp(dest, dest_i)) {
+ /* Already calculated.
+ * TODO: Optimize by exposing `typeInfo->interp`. */
+ }
+ else if (CustomData_layer_has_math(dest, dest_i)) {
+ const int size = CustomData_sizeof(type);
+ void *dst_data = dest->layers[dest_i].data;
+ void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
+ for (j = 0; j < count; j++) {
+ CustomData_data_add(
+ type, v_dst, POINTER_OFFSET(src_data, (size_t)src_indices[j] * size));
+ }
+ }
+ else {
+ CustomData_copy_layer_type_data(source, dest, type, src_indices[0], dest_index, 1);
+ }
+
+ /* if there are multiple source & dest layers of the same type,
+ * we don't want to copy all source layers to the same dest, so
+ * increment dest_i
+ */
+ dest_i++;
+ }
+ }
+
+ float fac = 1.0f / count;
+
+ for (dest_i = 0; dest_i < dest->totlayer; dest_i++) {
+ CustomDataLayer *layer_dst = &dest->layers[dest_i];
+ const int type = layer_dst->type;
+ if (type == CD_MVERT) {
+ MVert *mv = &((MVert *)layer_dst->data)[dest_index];
+ mul_v3_fl(co, fac);
+ bweight *= fac;
+ CLAMP_MAX(bweight, 255);
+
+ copy_v3_v3(mv->co, co);
+#ifdef USE_WELD_NORMALS
+ mul_v3_fl(no, fac);
+ short *mv_no = mv->no;
+ mv_no[0] = (short)no[0];
+ mv_no[1] = (short)no[1];
+ mv_no[2] = (short)no[2];
+#endif
+
+ mv->flag = (char)flag;
+ mv->bweight = (char)bweight;
+ }
+ else if (type == CD_MEDGE) {
+ MEdge *me = &((MEdge *)layer_dst->data)[dest_index];
+ crease *= fac;
+ bweight *= fac;
+ CLAMP_MAX(crease, 255);
+ CLAMP_MAX(bweight, 255);
+
+ me->crease = (char)crease;
+ me->bweight = (char)bweight;
+ me->flag = flag;
+ }
+ else if (CustomData_layer_has_interp(dest, dest_i)) {
+ /* Already calculated. */
+ }
+ else if (CustomData_layer_has_math(dest, dest_i)) {
+ const int size = CustomData_sizeof(type);
+ void *dst_data = layer_dst->data;
+ void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
+ CustomData_data_multiply(type, v_dst, fac);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Vertex Merging
+ * \{ */
+
+static Mesh *create_merged_mesh(const Mesh &mesh,
+ MutableSpan<int> vert_dest_map,
+ const int removed_vertex_count)
+{
+ Span<MPoly> mpoly{mesh.mpoly, mesh.totpoly};
+ Span<MLoop> mloop{mesh.mloop, mesh.totloop};
+ const int totvert = mesh.totvert;
+ const int totedge = mesh.totedge;
+ const int totloop = mesh.totloop;
+ const int totpoly = mesh.totpoly;
+
+ WeldMesh weld_mesh;
+ weld_mesh_context_create(mesh, vert_dest_map, removed_vertex_count, &weld_mesh);
+
+ const int result_nverts = totvert - weld_mesh.vert_kill_len;
+ const int result_nedges = totedge - weld_mesh.edge_kill_len;
+ const int result_nloops = totloop - weld_mesh.loop_kill_len;
+ const int result_npolys = totpoly - weld_mesh.poly_kill_len + weld_mesh.wpoly_new_len;
+
+ Mesh *result = BKE_mesh_new_nomain_from_template(
+ &mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys);
+
+ /* Vertices. */
+
+ /* Be careful when editing this array, to avoid new allocations it uses the same buffer as
+ * #vert_dest_map. This map will be used to adjust the edges, polys and loops. */
+ MutableSpan<int> vert_final = vert_dest_map;
+
+ int dest_index = 0;
+ for (int i = 0; i < totvert; i++) {
+ int source_index = i;
+ int count = 0;
+ while (i < totvert && vert_dest_map[i] == OUT_OF_CONTEXT) {
+ vert_final[i] = dest_index + count;
+ count++;
+ i++;
+ }
+ if (count) {
+ CustomData_copy_data(&mesh.vdata, &result->vdata, source_index, dest_index, count);
+ dest_index += count;
+ }
+ if (i == totvert) {
+ break;
+ }
+ if (vert_dest_map[i] != ELEM_MERGED) {
+ struct WeldGroup *wgroup = &weld_mesh.vert_groups[vert_dest_map[i]];
+ customdata_weld(&mesh.vdata,
+ &result->vdata,
+ &weld_mesh.vert_groups_buffer[wgroup->ofs],
+ wgroup->len,
+ dest_index);
+ vert_final[i] = dest_index;
+ dest_index++;
+ }
+ }
+
+ BLI_assert(dest_index == result_nverts);
+
+ /* Edges. */
+
+ /* Be careful when editing this array, to avoid new allocations it uses the same buffer as
+ * #edge_groups_map. This map will be used to adjust the polys and loops. */
+ MutableSpan<int> edge_final = weld_mesh.edge_groups_map;
+
+ dest_index = 0;
+ for (int i = 0; i < totedge; i++) {
+ const int source_index = i;
+ int count = 0;
+ while (i < totedge && weld_mesh.edge_groups_map[i] == OUT_OF_CONTEXT) {
+ edge_final[i] = dest_index + count;
+ count++;
+ i++;
+ }
+ if (count) {
+ CustomData_copy_data(&mesh.edata, &result->edata, source_index, dest_index, count);
+ MEdge *me = &result->medge[dest_index];
+ dest_index += count;
+ for (; count--; me++) {
+ me->v1 = vert_final[me->v1];
+ me->v2 = vert_final[me->v2];
+ }
+ }
+ if (i == totedge) {
+ break;
+ }
+ if (weld_mesh.edge_groups_map[i] != ELEM_MERGED) {
+ struct WeldGroupEdge *wegrp = &weld_mesh.edge_groups[weld_mesh.edge_groups_map[i]];
+ customdata_weld(&mesh.edata,
+ &result->edata,
+ &weld_mesh.edge_groups_buffer[wegrp->group.ofs],
+ wegrp->group.len,
+ dest_index);
+ MEdge *me = &result->medge[dest_index];
+ me->v1 = vert_final[wegrp->v1];
+ me->v2 = vert_final[wegrp->v2];
+ /* "For now, assume that all merged edges are loose. This flag will be cleared in the
+ * Polys/Loops step". */
+ me->flag |= ME_LOOSEEDGE;
+
+ edge_final[i] = dest_index;
+ dest_index++;
+ }
+ }
+
+ BLI_assert(dest_index == result_nedges);
+
+ /* Polys/Loops. */
+
+ MPoly *r_mp = &result->mpoly[0];
+ MLoop *r_ml = &result->mloop[0];
+ int r_i = 0;
+ int loop_cur = 0;
+ Array<int, 64> group_buffer(weld_mesh.max_poly_len);
+ for (const int i : mpoly.index_range()) {
+ const MPoly &mp = mpoly[i];
+ const int loop_start = loop_cur;
+ const int poly_ctx = weld_mesh.poly_map[i];
+ if (poly_ctx == OUT_OF_CONTEXT) {
+ int mp_loop_len = mp.totloop;
+ CustomData_copy_data(&mesh.ldata, &result->ldata, mp.loopstart, loop_cur, mp_loop_len);
+ loop_cur += mp_loop_len;
+ for (; mp_loop_len--; r_ml++) {
+ r_ml->v = vert_final[r_ml->v];
+ r_ml->e = edge_final[r_ml->e];
+ }
+ }
+ else {
+ const WeldPoly &wp = weld_mesh.wpoly[poly_ctx];
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(
+ iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) {
+ continue;
+ }
+
+ if (wp.poly_dst != OUT_OF_CONTEXT) {
+ continue;
+ }
+ while (weld_iter_loop_of_poly_next(iter)) {
+ customdata_weld(
+ &mesh.ldata, &result->ldata, group_buffer.data(), iter.group_len, loop_cur);
+ int v = vert_final[iter.v];
+ int e = edge_final[iter.e];
+ r_ml->v = v;
+ r_ml->e = e;
+ r_ml++;
+ loop_cur++;
+ if (iter.type) {
+ result->medge[e].flag &= ~ME_LOOSEEDGE;
+ }
+ BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
+ }
+ }
+
+ CustomData_copy_data(&mesh.pdata, &result->pdata, i, r_i, 1);
+ r_mp->loopstart = loop_start;
+ r_mp->totloop = loop_cur - loop_start;
+ r_mp++;
+ r_i++;
+ }
+
+ for (const int i : IndexRange(weld_mesh.wpoly_new_len)) {
+ const WeldPoly &wp = weld_mesh.wpoly_new[i];
+ const int loop_start = loop_cur;
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(
+ iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) {
+ continue;
+ }
+
+ if (wp.poly_dst != OUT_OF_CONTEXT) {
+ continue;
+ }
+ while (weld_iter_loop_of_poly_next(iter)) {
+ customdata_weld(&mesh.ldata, &result->ldata, group_buffer.data(), iter.group_len, loop_cur);
+ int v = vert_final[iter.v];
+ int e = edge_final[iter.e];
+ r_ml->v = v;
+ r_ml->e = e;
+ r_ml++;
+ loop_cur++;
+ if (iter.type) {
+ result->medge[e].flag &= ~ME_LOOSEEDGE;
+ }
+ BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
+ }
+
+ r_mp->loopstart = loop_start;
+ r_mp->totloop = loop_cur - loop_start;
+ r_mp++;
+ r_i++;
+ }
+
+ BLI_assert((int)r_i == result_npolys);
+ BLI_assert(loop_cur == result_nloops);
+
+ /* We could only update the normals of the elements in context, but the next modifier can make it
+ * dirty anyway which would make the work useless. */
+ BKE_mesh_normals_tag_dirty(result);
+
+ return result;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Merge Map Creation
+ * \{ */
+
+std::optional<Mesh *> mesh_merge_by_distance_all(const Mesh &mesh,
+ const IndexMask selection,
+ const float merge_distance)
+{
+ Array<int> vert_dest_map(mesh.totvert, OUT_OF_CONTEXT);
+
+ KDTree_3d *tree = BLI_kdtree_3d_new(selection.size());
+
+ for (const int i : selection) {
+ BLI_kdtree_3d_insert(tree, i, mesh.mvert[i].co);
+ }
+
+ BLI_kdtree_3d_balance(tree);
+ const int vert_kill_len = BLI_kdtree_3d_calc_duplicates_fast(
+ tree, merge_distance, false, vert_dest_map.data());
+ BLI_kdtree_3d_free(tree);
+
+ if (vert_kill_len == 0) {
+ return std::nullopt;
+ }
+
+ return create_merged_mesh(mesh, vert_dest_map, vert_kill_len);
+}
+
+struct WeldVertexCluster {
+ float co[3];
+ int merged_verts;
+};
+
+std::optional<Mesh *> mesh_merge_by_distance_connected(const Mesh &mesh,
+ Span<bool> selection,
+ const float merge_distance,
+ const bool only_loose_edges)
+{
+ Span<MVert> verts{mesh.mvert, mesh.totvert};
+ Span<MEdge> edges{mesh.medge, mesh.totedge};
+
+ int vert_kill_len = 0;
+
+ /* From the original index of the vertex.
+ * This indicates which vert it is or is going to be merged. */
+ Array<int> vert_dest_map(mesh.totvert, OUT_OF_CONTEXT);
+
+ Array<WeldVertexCluster> vert_clusters(mesh.totvert);
+
+ for (const int i : verts.index_range()) {
+ WeldVertexCluster &vc = vert_clusters[i];
+ copy_v3_v3(vc.co, verts[i].co);
+ vc.merged_verts = 0;
+ }
+ const float merge_dist_sq = square_f(merge_distance);
+
+ range_vn_i(vert_dest_map.data(), mesh.totvert, 0);
+
+ /* Collapse Edges that are shorter than the threshold. */
+ for (const int i : edges.index_range()) {
+ int v1 = edges[i].v1;
+ int v2 = edges[i].v2;
+
+ if (only_loose_edges && (edges[i].flag & ME_LOOSEEDGE) == 0) {
+ continue;
+ }
+ while (v1 != vert_dest_map[v1]) {
+ v1 = vert_dest_map[v1];
+ }
+ while (v2 != vert_dest_map[v2]) {
+ v2 = vert_dest_map[v2];
+ }
+ if (v1 == v2) {
+ continue;
+ }
+ if (!selection.is_empty() && (!selection[v1] || !selection[v2])) {
+ continue;
+ }
+ if (v1 > v2) {
+ SWAP(int, v1, v2);
+ }
+ WeldVertexCluster *v1_cluster = &vert_clusters[v1];
+ WeldVertexCluster *v2_cluster = &vert_clusters[v2];
+
+ float edgedir[3];
+ sub_v3_v3v3(edgedir, v2_cluster->co, v1_cluster->co);
+ const float dist_sq = len_squared_v3(edgedir);
+ if (dist_sq <= merge_dist_sq) {
+ float influence = (v2_cluster->merged_verts + 1) /
+ (float)(v1_cluster->merged_verts + v2_cluster->merged_verts + 2);
+ madd_v3_v3fl(v1_cluster->co, edgedir, influence);
+
+ v1_cluster->merged_verts += v2_cluster->merged_verts + 1;
+ vert_dest_map[v2] = v1;
+ vert_kill_len++;
+ }
+ }
+
+ if (vert_kill_len == 0) {
+ return std::nullopt;
+ }
+
+ for (const int i : IndexRange(mesh.totvert)) {
+ if (i == vert_dest_map[i]) {
+ vert_dest_map[i] = OUT_OF_CONTEXT;
+ }
+ else {
+ int v = i;
+ while ((v != vert_dest_map[v]) && (vert_dest_map[v] != OUT_OF_CONTEXT)) {
+ v = vert_dest_map[v];
+ }
+ vert_dest_map[v] = v;
+ vert_dest_map[i] = v;
+ }
+ }
+
+ return create_merged_mesh(mesh, vert_dest_map, vert_kill_len);
+}
+
+/** \} */
+
+} // namespace blender::geometry
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc
index 11349dc7d42..965c09984fa 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc
+++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc
@@ -15,26 +15,21 @@
*/
#include "BLI_array.hh"
+#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
#include "BLI_task.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
+#include "BKE_geometry_set.hh"
#include "BKE_spline.hh"
-#include "node_geometry_util.hh"
+#include "GEO_mesh_to_curve.hh"
-using blender::Array;
-
-namespace blender::nodes {
-
-static void geo_node_mesh_to_curve_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>("Mesh");
- b.add_input<decl::String>("Selection");
- b.add_output<decl::Geometry>("Curve");
-}
+namespace blender::geometry {
template<typename T>
static void copy_attribute_to_points(const VArray<T> &source_data,
@@ -47,82 +42,118 @@ static void copy_attribute_to_points(const VArray<T> &source_data,
}
}
-static void copy_attributes_to_points(CurveEval &curve,
- const MeshComponent &mesh_component,
- Span<Vector<int>> point_to_vert_maps)
+static std::unique_ptr<CurveEval> create_curve_from_vert_indices(
+ const MeshComponent &mesh_component, Span<Vector<int>> vert_indices, IndexRange cyclic_splines)
{
- MutableSpan<SplinePtr> splines = curve.splines();
- Set<AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids();
+ std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+ curve->resize(vert_indices.size());
+
+ MutableSpan<SplinePtr> splines = curve->splines();
+
+ for (const int i : vert_indices.index_range()) {
+ splines[i] = std::make_unique<PolySpline>();
+ splines[i]->resize(vert_indices[i].size());
+ }
+ for (const int i : cyclic_splines) {
+ splines[i]->set_cyclic(true);
+ }
+
+ Set<bke::AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids();
/* Copy builtin control point attributes. */
if (source_attribute_ids.contains("tilt")) {
- const GVArray_Typed<float> tilt_attribute = mesh_component.attribute_get_for_read<float>(
+ const VArray<float> tilt_attribute = mesh_component.attribute_get_for_read<float>(
"tilt", ATTR_DOMAIN_POINT, 0.0f);
threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
for (const int i : range) {
- copy_attribute_to_points<float>(
- *tilt_attribute, point_to_vert_maps[i], splines[i]->tilts());
+ copy_attribute_to_points<float>(tilt_attribute, vert_indices[i], splines[i]->tilts());
}
});
source_attribute_ids.remove_contained("tilt");
}
+ else {
+ for (SplinePtr &spline : splines) {
+ spline->tilts().fill(0.0f);
+ }
+ }
+
if (source_attribute_ids.contains("radius")) {
- const GVArray_Typed<float> radius_attribute = mesh_component.attribute_get_for_read<float>(
+ const VArray<float> radius_attribute = mesh_component.attribute_get_for_read<float>(
"radius", ATTR_DOMAIN_POINT, 1.0f);
threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
for (const int i : range) {
- copy_attribute_to_points<float>(
- *radius_attribute, point_to_vert_maps[i], splines[i]->radii());
+ copy_attribute_to_points<float>(radius_attribute, vert_indices[i], splines[i]->radii());
}
});
source_attribute_ids.remove_contained("radius");
}
+ else {
+ for (SplinePtr &spline : splines) {
+ spline->radii().fill(1.0f);
+ }
+ }
+
+ VArray<float3> mesh_positions = mesh_component.attribute_get_for_read(
+ "position", ATTR_DOMAIN_POINT, float3(0));
+ threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ copy_attribute_to_points(mesh_positions, vert_indices[i], splines[i]->positions());
+ }
+ });
- /* Don't copy other builtin control point attributes. */
- source_attribute_ids.remove("position");
+ for (const bke::AttributeIDRef &attribute_id : source_attribute_ids) {
+ if (mesh_component.attribute_is_builtin(attribute_id)) {
+ /* Don't copy attributes that are built-in on meshes but not on curves. */
+ continue;
+ }
- /* Copy dynamic control point attributes. */
- for (const AttributeIDRef &attribute_id : source_attribute_ids) {
- const GVArrayPtr mesh_attribute = mesh_component.attribute_try_get_for_read(attribute_id,
- ATTR_DOMAIN_POINT);
+ if (!attribute_id.should_be_kept()) {
+ continue;
+ }
+
+ const fn::GVArray mesh_attribute = mesh_component.attribute_try_get_for_read(
+ attribute_id, ATTR_DOMAIN_POINT);
/* Some attributes might not exist if they were builtin attribute on domains that don't
* have any elements, i.e. a face attribute on the output of the line primitive node. */
if (!mesh_attribute) {
continue;
}
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(mesh_attribute->type());
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(mesh_attribute.type());
threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
/* Create attribute on the spline points. */
splines[i]->attributes.create(attribute_id, data_type);
- std::optional<GMutableSpan> spline_attribute = splines[i]->attributes.get_for_write(
+ std::optional<fn::GMutableSpan> spline_attribute = splines[i]->attributes.get_for_write(
attribute_id);
BLI_assert(spline_attribute);
/* Copy attribute based on the map for this spline. */
- attribute_math::convert_to_static_type(mesh_attribute->type(), [&](auto dummy) {
+ attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) {
using T = decltype(dummy);
copy_attribute_to_points<T>(
- mesh_attribute->typed<T>(), point_to_vert_maps[i], spline_attribute->typed<T>());
+ mesh_attribute.typed<T>(), vert_indices[i], spline_attribute->typed<T>());
});
}
});
}
- curve.assert_valid_point_attributes();
+ curve->assert_valid_point_attributes();
+ return curve;
}
struct CurveFromEdgesOutput {
- std::unique_ptr<CurveEval> curve;
- Vector<Vector<int>> point_to_vert_maps;
+ /** The indices in the mesh for each control point of each result splines. */
+ Vector<Vector<int>> vert_indices;
+ /** A subset of splines that should be set cyclic. */
+ IndexRange cyclic_splines;
};
-static CurveFromEdgesOutput mesh_to_curve(Span<MVert> verts, Span<std::pair<int, int>> edges)
+static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
+ Span<std::pair<int, int>> edges)
{
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- Vector<Vector<int>> point_to_vert_maps;
+ Vector<Vector<int>> vert_indices;
/* Compute the number of edges connecting to each vertex. */
Array<int> neighbor_count(verts.size(), 0);
@@ -174,19 +205,15 @@ static CurveFromEdgesOutput mesh_to_curve(Span<MVert> verts, Span<std::pair<int,
continue;
}
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- Vector<int> point_to_vert_map;
-
- spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
- point_to_vert_map.append(current_vert);
+ Vector<int> spline_indices;
+ spline_indices.append(current_vert);
/* Follow connected edges until we read a vertex with more than two connected edges. */
while (true) {
int last_vert = current_vert;
current_vert = next_vert;
- spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
- point_to_vert_map.append(current_vert);
+ spline_indices.append(current_vert);
unused_edges[current_vert]--;
unused_edges[last_vert]--;
@@ -200,12 +227,13 @@ static CurveFromEdgesOutput mesh_to_curve(Span<MVert> verts, Span<std::pair<int,
next_vert = (last_vert == next_a) ? next_b : next_a;
}
- spline->attributes.reallocate(spline->size());
- curve->add_spline(std::move(spline));
- point_to_vert_maps.append(std::move(point_to_vert_map));
+ vert_indices.append(std::move(spline_indices));
}
}
+ /* All splines added after this are cyclic. */
+ const int cyclic_start = vert_indices.size();
+
/* All remaining edges are part of cyclic splines (we skipped vertices with two edges before). */
for (const int start_vert : verts.index_range()) {
if (unused_edges[start_vert] != 2) {
@@ -215,20 +243,16 @@ static CurveFromEdgesOutput mesh_to_curve(Span<MVert> verts, Span<std::pair<int,
int current_vert = start_vert;
int next_vert = neighbors[neighbor_offsets[current_vert]];
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- Vector<int> point_to_vert_map;
- spline->set_cyclic(true);
+ Vector<int> spline_indices;
- spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
- point_to_vert_map.append(current_vert);
+ spline_indices.append(current_vert);
/* Follow connected edges until we loop back to the start vertex. */
while (next_vert != start_vert) {
const int last_vert = current_vert;
current_vert = next_vert;
- spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
- point_to_vert_map.append(current_vert);
+ spline_indices.append(current_vert);
unused_edges[current_vert]--;
unused_edges[last_vert]--;
@@ -238,13 +262,12 @@ static CurveFromEdgesOutput mesh_to_curve(Span<MVert> verts, Span<std::pair<int,
next_vert = (last_vert == next_a) ? next_b : next_a;
}
- spline->attributes.reallocate(spline->size());
- curve->add_spline(std::move(spline));
- point_to_vert_maps.append(std::move(point_to_vert_map));
+ vert_indices.append(std::move(spline_indices));
}
- curve->attributes.reallocate(curve->splines().size());
- return {std::move(curve), std::move(point_to_vert_maps)};
+ const int final_size = vert_indices.size();
+
+ return {std::move(vert_indices), IndexRange(cyclic_start, final_size - cyclic_start)};
}
/**
@@ -252,63 +275,26 @@ static CurveFromEdgesOutput mesh_to_curve(Span<MVert> verts, Span<std::pair<int,
* This helps to make the above algorithm simpler by removing the need to check for selection
* in many places.
*/
-static Vector<std::pair<int, int>> get_selected_edges(GeoNodeExecParams params,
- const MeshComponent &component)
+static Vector<std::pair<int, int>> get_selected_edges(const Mesh &mesh, const IndexMask selection)
{
- const Mesh &mesh = *component.get_for_read();
- const std::string selection_name = params.extract_input<std::string>("Selection");
- if (!selection_name.empty() && !component.attribute_exists(selection_name)) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("No attribute with name \"") + selection_name + "\"");
- }
- GVArray_Typed<bool> selection = component.attribute_get_for_read<bool>(
- selection_name, ATTR_DOMAIN_EDGE, true);
-
Vector<std::pair<int, int>> selected_edges;
- for (const int i : IndexRange(mesh.totedge)) {
- if (selection[i]) {
- selected_edges.append({mesh.medge[i].v1, mesh.medge[i].v2});
- }
+ for (const int i : selection) {
+ selected_edges.append({mesh.medge[i].v1, mesh.medge[i].v2});
}
-
return selected_edges;
}
-static void geo_node_mesh_to_curve_exec(GeoNodeExecParams params)
+std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_component,
+ const IndexMask selection)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
-
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
-
- if (!geometry_set.has_mesh()) {
- params.set_output("Curve", GeometrySet());
- return;
- }
-
- const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
- const Mesh &mesh = *component.get_for_read();
- Span<MVert> verts = Span{mesh.mvert, mesh.totvert};
- Vector<std::pair<int, int>> selected_edges = get_selected_edges(params, component);
- if (selected_edges.size() == 0) {
- params.set_output("Curve", GeometrySet());
- return;
- }
-
- CurveFromEdgesOutput output = mesh_to_curve(verts, selected_edges);
- copy_attributes_to_points(*output.curve, component, output.point_to_vert_maps);
-
- params.set_output("Curve", GeometrySet::create_with_curve(output.curve.release()));
+ const Mesh &mesh = *mesh_component.get_for_read();
+ Vector<std::pair<int, int>> selected_edges = get_selected_edges(*mesh_component.get_for_read(),
+ selection);
+ CurveFromEdgesOutput output = edges_to_curve_point_indices({mesh.mvert, mesh.totvert},
+ selected_edges);
+
+ return create_curve_from_vert_indices(
+ mesh_component, output.vert_indices, output.cyclic_splines);
}
-} // namespace blender::nodes
-
-void register_node_type_geo_mesh_to_curve()
-{
- static bNodeType ntype;
-
- geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_to_curve_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_to_curve_exec;
- nodeRegisterType(&ntype);
-}
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/point_merge_by_distance.cc b/source/blender/geometry/intern/point_merge_by_distance.cc
new file mode 100644
index 00000000000..daa08a3bce6
--- /dev/null
+++ b/source/blender/geometry/intern/point_merge_by_distance.cc
@@ -0,0 +1,183 @@
+/*
+ * 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 "BLI_kdtree.h"
+#include "BLI_task.hh"
+
+#include "DNA_pointcloud_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_geometry_set.hh"
+#include "BKE_pointcloud.h"
+
+#include "GEO_point_merge_by_distance.hh"
+
+namespace blender::geometry {
+
+PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
+ const float merge_distance,
+ const IndexMask selection)
+{
+ const PointCloud &src_pointcloud = *src_points.get_for_read();
+ const int src_size = src_pointcloud.totpoint;
+ Span<float3> positions{reinterpret_cast<float3 *>(src_pointcloud.co), src_size};
+
+ /* Create the KD tree based on only the selected points, to speed up merge detection and
+ * balancing. */
+ KDTree_3d *tree = BLI_kdtree_3d_new(selection.size());
+ for (const int i : selection.index_range()) {
+ BLI_kdtree_3d_insert(tree, i, positions[selection[i]]);
+ }
+ BLI_kdtree_3d_balance(tree);
+
+ /* Find the duplicates in the KD tree. Because the tree only contains the selected points, the
+ * resulting indices are indices into the selection, rather than indices of the source point
+ * cloud. */
+ Array<int> selection_merge_indices(selection.size(), -1);
+ const int duplicate_count = BLI_kdtree_3d_calc_duplicates_fast(
+ tree, merge_distance, false, selection_merge_indices.data());
+ BLI_kdtree_3d_free(tree);
+
+ /* Create the new point cloud and add it to a temporary component for the attribute API. */
+ const int dst_size = src_size - duplicate_count;
+ PointCloud *dst_pointcloud = BKE_pointcloud_new_nomain(dst_size);
+ PointCloudComponent dst_points;
+ dst_points.replace(dst_pointcloud, GeometryOwnershipType::Editable);
+
+ /* By default, every point is just "merged" with itself. Then fill in the results of the merge
+ * finding, converting from indices into the selection to indices into the full input point
+ * cloud. */
+ Array<int> merge_indices(src_size);
+ for (const int i : merge_indices.index_range()) {
+ merge_indices[i] = i;
+ }
+ for (const int i : selection_merge_indices.index_range()) {
+ const int merge_index = selection_merge_indices[i];
+ if (merge_index != -1) {
+ const int src_merge_index = selection[merge_index];
+ const int src_index = selection[i];
+ merge_indices[src_index] = src_merge_index;
+ }
+ }
+
+ /* For every source index, find the corresponding index in the result by iterating through the
+ * source indices and counting how many merges happened before that point. */
+ int merged_points = 0;
+ Array<int> src_to_dst_indices(src_size);
+ for (const int i : IndexRange(src_size)) {
+ src_to_dst_indices[i] = i - merged_points;
+ if (merge_indices[i] != i) {
+ merged_points++;
+ }
+ }
+
+ /* In order to use a contiguous array as the storage for every destination point's source
+ * indices, first the number of source points must be counted for every result point. */
+ Array<int> point_merge_counts(dst_size, 0);
+ for (const int i : IndexRange(src_size)) {
+ const int merge_index = merge_indices[i];
+ const int dst_index = src_to_dst_indices[merge_index];
+ point_merge_counts[dst_index]++;
+ }
+
+ /* This array stores an offset into `merge_map` for every result point. */
+ Array<int> map_offsets(dst_size + 1);
+ int offset = 0;
+ for (const int i : IndexRange(dst_size)) {
+ map_offsets[i] = offset;
+ offset += point_merge_counts[i];
+ }
+ map_offsets.last() = offset;
+
+ point_merge_counts.fill(0);
+
+ /* This array stores all of the source indices for every result point. The size is the source
+ * size because every input point is either merged with another or copied directly. */
+ Array<int> merge_map(src_size);
+ for (const int i : IndexRange(src_size)) {
+ const int merge_index = merge_indices[i];
+ const int dst_index = src_to_dst_indices[merge_index];
+
+ const IndexRange point_range(map_offsets[dst_index],
+ map_offsets[dst_index + 1] - map_offsets[dst_index]);
+ MutableSpan<int> point_merge_indices = merge_map.as_mutable_span().slice(point_range);
+ point_merge_indices[point_merge_counts[dst_index]] = i;
+ point_merge_counts[dst_index]++;
+ }
+
+ Set<bke::AttributeIDRef> attributes = src_points.attribute_ids();
+
+ /* Transfer the ID attribute if it exists, using the ID of the first merged point. */
+ if (attributes.contains("id")) {
+ VArray<int> src = src_points.attribute_get_for_read<int>("id", ATTR_DOMAIN_POINT, 0);
+ bke::OutputAttribute_Typed<int> dst = dst_points.attribute_try_get_for_output_only<int>(
+ "id", ATTR_DOMAIN_POINT);
+ Span<int> src_ids = src.get_internal_span();
+ MutableSpan<int> dst_ids = dst.as_span();
+
+ threading::parallel_for(IndexRange(dst_size), 1024, [&](IndexRange range) {
+ for (const int i_dst : range) {
+ const IndexRange point_range(map_offsets[i_dst],
+ map_offsets[i_dst + 1] - map_offsets[i_dst]);
+ dst_ids[i_dst] = src_ids[point_range.first()];
+ }
+ });
+
+ dst.save();
+ attributes.remove_contained("id");
+ }
+
+ /* Transfer all other attributes. */
+ for (const bke::AttributeIDRef &id : attributes) {
+ if (!id.should_be_kept()) {
+ continue;
+ }
+
+ bke::ReadAttributeLookup src_attribute = src_points.attribute_try_get_for_read(id);
+ attribute_math::convert_to_static_type(src_attribute.varray.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ bke::OutputAttribute_Typed<T> dst_attribute =
+ dst_points.attribute_try_get_for_output_only<T>(id, ATTR_DOMAIN_POINT);
+ Span<T> src = src_attribute.varray.get_internal_span().typed<T>();
+ MutableSpan<T> dst = dst_attribute.as_span();
+
+ threading::parallel_for(IndexRange(dst_size), 1024, [&](IndexRange range) {
+ for (const int i_dst : range) {
+ /* Create a separate mixer for every point to avoid allocating temporary buffers
+ * in the mixer the size of the result point cloud and to improve memory locality. */
+ attribute_math::DefaultMixer<T> mixer{dst.slice(i_dst, 1)};
+
+ const IndexRange point_range(map_offsets[i_dst],
+ map_offsets[i_dst + 1] - map_offsets[i_dst]);
+ Span<int> src_merge_indices = merge_map.as_span().slice(point_range);
+ for (const int i_src : src_merge_indices) {
+ mixer.mix_in(0, src[i_src]);
+ }
+
+ mixer.finalize();
+ }
+ });
+
+ dst_attribute.save();
+ }
+ });
+ }
+
+ return dst_pointcloud;
+}
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
new file mode 100644
index 00000000000..4022794d53f
--- /dev/null
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -0,0 +1,1347 @@
+/*
+ * 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 "GEO_realize_instances.hh"
+
+#include "DNA_collection_types.h"
+#include "DNA_layer_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_pointcloud_types.h"
+
+#include "BLI_noise.hh"
+#include "BLI_task.hh"
+
+#include "BKE_collection.h"
+#include "BKE_geometry_set_instances.hh"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_pointcloud.h"
+#include "BKE_spline.hh"
+#include "BKE_type_conversions.hh"
+
+namespace blender::geometry {
+
+using blender::bke::AttributeIDRef;
+using blender::bke::custom_data_type_to_cpp_type;
+using blender::bke::CustomDataAttributes;
+using blender::bke::object_get_evaluated_geometry_set;
+using blender::bke::OutputAttribute;
+using blender::bke::OutputAttribute_Typed;
+using blender::bke::ReadAttributeLookup;
+using blender::fn::CPPType;
+using blender::fn::GArray;
+using blender::fn::GMutableSpan;
+using blender::fn::GSpan;
+using blender::fn::GVArray;
+using blender::fn::GVArray_GSpan;
+
+/**
+ * An ordered set of attribute ids. Attributes are ordered to avoid name lookups in many places.
+ * Once the attributes are ordered, they can just be referred to by index.
+ */
+struct OrderedAttributes {
+ VectorSet<AttributeIDRef> ids;
+ Vector<AttributeKind> kinds;
+
+ int size() const
+ {
+ return this->kinds.size();
+ }
+
+ IndexRange index_range() const
+ {
+ return this->kinds.index_range();
+ }
+};
+
+struct AttributeFallbacksArray {
+ /**
+ * Instance attribute values used as fallback when the geometry does not have the
+ * corresponding attributes itself. The pointers point to attributes stored in the instances
+ * component or in #r_temporary_arrays. The order depends on the corresponding #OrderedAttributes
+ * instance.
+ */
+ Array<const void *> array;
+
+ AttributeFallbacksArray(int size) : array(size, nullptr)
+ {
+ }
+};
+
+struct PointCloudRealizeInfo {
+ const PointCloud *pointcloud = nullptr;
+ /** Matches the order stored in #AllPointCloudsInfo.attributes. */
+ Array<std::optional<GVArray_GSpan>> attributes;
+ /** Id attribute on the point cloud. If there are no ids, this #Span is empty. */
+ Span<int> stored_ids;
+};
+
+struct RealizePointCloudTask {
+ /** Starting index in the final realized point cloud. */
+ int start_index;
+ /** Preprocessed information about the point cloud. */
+ const PointCloudRealizeInfo *pointcloud_info;
+ /** Transformation that is applied to all positions. */
+ float4x4 transform;
+ AttributeFallbacksArray attribute_fallbacks;
+ /** Only used when the output contains an output attribute. */
+ uint32_t id = 0;
+};
+
+/** Start indices in the final output mesh. */
+struct MeshElementStartIndices {
+ int vertex = 0;
+ int edge = 0;
+ int poly = 0;
+ int loop = 0;
+};
+
+struct MeshRealizeInfo {
+ const Mesh *mesh = nullptr;
+ /** Maps old material indices to new material indices. */
+ Array<int> material_index_map;
+ /** Matches the order in #AllMeshesInfo.attributes. */
+ Array<std::optional<GVArray_GSpan>> attributes;
+ /** Vertex ids stored on the mesh. If there are no ids, this #Span is empty. */
+ Span<int> stored_vertex_ids;
+};
+
+struct RealizeMeshTask {
+ MeshElementStartIndices start_indices;
+ const MeshRealizeInfo *mesh_info;
+ /** Transformation that is applied to all positions. */
+ float4x4 transform;
+ AttributeFallbacksArray attribute_fallbacks;
+ /** Only used when the output contains an output attribute. */
+ uint32_t id = 0;
+};
+
+struct RealizeCurveInfo {
+ const CurveEval *curve = nullptr;
+ /**
+ * Matches the order in #AllCurvesInfo.attributes. For point attributes, the `std::optional`
+ * will be empty.
+ */
+ Array<std::optional<GVArray_GSpan>> spline_attributes;
+};
+
+struct RealizeCurveTask {
+ /* Start index in the final curve. */
+ int start_spline_index = 0;
+ const RealizeCurveInfo *curve_info;
+ /* Transformation applied to the position of control points and handles. */
+ float4x4 transform;
+ AttributeFallbacksArray attribute_fallbacks;
+ /** Only used when the output contains an output attribute. */
+ uint32_t id = 0;
+};
+
+struct AllPointCloudsInfo {
+ /** Ordering of all attributes that are propagated to the output point cloud generically. */
+ OrderedAttributes attributes;
+ /** Ordering of the original point clouds that are joined. */
+ VectorSet<const PointCloud *> order;
+ /** Preprocessed data about every original point cloud. This is ordered by #order. */
+ Array<PointCloudRealizeInfo> realize_info;
+ bool create_id_attribute = false;
+};
+
+struct AllMeshesInfo {
+ /** Ordering of all attributes that are propagated to the output mesh generically. */
+ OrderedAttributes attributes;
+ /** Ordering of the original meshes that are joined. */
+ VectorSet<const Mesh *> order;
+ /** Preprocessed data about every original mesh. This is ordered by #order. */
+ Array<MeshRealizeInfo> realize_info;
+ /** Ordered materials on the output mesh. */
+ VectorSet<Material *> materials;
+ bool create_id_attribute = false;
+};
+
+struct AllCurvesInfo {
+ /** Ordering of all attributes that are propagated to the output curve generically. */
+ OrderedAttributes attributes;
+ /** Ordering of the original curves that are joined. */
+ VectorSet<const CurveEval *> order;
+ /** Preprocessed data about every original curve. This is ordered by #order. */
+ Array<RealizeCurveInfo> realize_info;
+ bool create_id_attribute = false;
+};
+
+/** Collects all tasks that need to be executed to realize all instances. */
+struct GatherTasks {
+ Vector<RealizePointCloudTask> pointcloud_tasks;
+ Vector<RealizeMeshTask> mesh_tasks;
+ Vector<RealizeCurveTask> curve_tasks;
+
+ /* Volumes only have very simple support currently. Only the first found volume is put into the
+ * output. */
+ UserCounter<VolumeComponent> first_volume;
+};
+
+/** Current offsets while during the gather operation. */
+struct GatherOffsets {
+ int pointcloud_offset = 0;
+ MeshElementStartIndices mesh_offsets;
+ int spline_offset = 0;
+};
+
+struct GatherTasksInfo {
+ /** Static information about all geometries that are joined. */
+ const AllPointCloudsInfo &pointclouds;
+ const AllMeshesInfo &meshes;
+ const AllCurvesInfo &curves;
+ bool create_id_attribute_on_any_component = false;
+
+ /**
+ * Under some circumstances, temporary arrays need to be allocated during the gather operation.
+ * For example, when an instance attribute has to be realized as a different data type. This
+ * array owns all the temporary arrays so that they can live until all processing is done.
+ * Use #std::unique_ptr to avoid depending on whether #GArray has an inline buffer or not.
+ */
+ Vector<std::unique_ptr<GArray<>>> &r_temporary_arrays;
+
+ /** All gathered tasks. */
+ GatherTasks r_tasks;
+ /** Current offsets while gathering tasks. */
+ GatherOffsets r_offsets;
+};
+
+/**
+ * Information about the parent instances in the current context.
+ */
+struct InstanceContext {
+ /** Ordered by #AllPointCloudsInfo.attributes. */
+ AttributeFallbacksArray pointclouds;
+ /** Ordered by #AllMeshesInfo.attributes. */
+ AttributeFallbacksArray meshes;
+ /** Ordered by #AllCurvesInfo.attributes. */
+ AttributeFallbacksArray curves;
+ /** Id mixed from all parent instances. */
+ uint32_t id = 0;
+
+ InstanceContext(const GatherTasksInfo &gather_info)
+ : pointclouds(gather_info.pointclouds.attributes.size()),
+ meshes(gather_info.meshes.attributes.size()),
+ curves(gather_info.curves.attributes.size())
+ {
+ }
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Gather Realize Tasks
+ * \{ */
+
+/* Forward declaration. */
+static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
+ const GeometrySet &geometry_set,
+ const float4x4 &base_transform,
+ const InstanceContext &base_instance_context);
+
+/**
+ * Checks which of the #ordered_attributes exist on the #instances_component. For each attribute
+ * that exists on the instances, a pair is returned that contains the attribute index and the
+ * corresponding attribute data.
+ */
+static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks(
+ GatherTasksInfo &gather_info,
+ const InstancesComponent &instances_component,
+ const OrderedAttributes &ordered_attributes)
+{
+ Vector<std::pair<int, GSpan>> attributes_to_override;
+ const CustomDataAttributes &attributes = instances_component.attributes();
+ attributes.foreach_attribute(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ const int attribute_index = ordered_attributes.ids.index_of_try(attribute_id);
+ if (attribute_index == -1) {
+ /* The attribute is not propagated to the final geometry. */
+ return true;
+ }
+ GSpan span = *attributes.get_for_read(attribute_id);
+ const CustomDataType expected_type = ordered_attributes.kinds[attribute_index].data_type;
+ if (meta_data.data_type != expected_type) {
+ const CPPType &from_type = span.type();
+ const CPPType &to_type = *custom_data_type_to_cpp_type(expected_type);
+ const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
+ if (!conversions.is_convertible(from_type, to_type)) {
+ /* Ignore the attribute because it can not be converted to the desired type. */
+ return true;
+ }
+ /* Convert the attribute on the instances component to the expected attribute type. */
+ std::unique_ptr<GArray<>> temporary_array = std::make_unique<GArray<>>(
+ to_type, instances_component.instances_amount());
+ conversions.convert_to_initialized_n(span, temporary_array->as_mutable_span());
+ span = temporary_array->as_span();
+ gather_info.r_temporary_arrays.append(std::move(temporary_array));
+ }
+ attributes_to_override.append({attribute_index, span});
+ return true;
+ },
+ ATTR_DOMAIN_INSTANCE);
+ return attributes_to_override;
+}
+
+/**
+ * Calls #fn for every geometry in the given #InstanceReference. Also passes on the transformation
+ * that is applied to every instance.
+ */
+static void foreach_geometry_in_reference(
+ const InstanceReference &reference,
+ const float4x4 &base_transform,
+ const uint32_t id,
+ FunctionRef<void(const GeometrySet &geometry_set, const float4x4 &transform, uint32_t id)> fn)
+{
+ switch (reference.type()) {
+ case InstanceReference::Type::Object: {
+ const Object &object = reference.object();
+ const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(object);
+ fn(object_geometry_set, base_transform, id);
+ break;
+ }
+ case InstanceReference::Type::Collection: {
+ Collection &collection = reference.collection();
+ float4x4 offset_matrix = float4x4::identity();
+ sub_v3_v3(offset_matrix.values[3], collection.instance_offset);
+ int index = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
+ const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(*object);
+ const float4x4 matrix = base_transform * offset_matrix * object->obmat;
+ const int sub_id = noise::hash(id, index);
+ fn(object_geometry_set, matrix, sub_id);
+ index++;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ break;
+ }
+ case InstanceReference::Type::GeometrySet: {
+ const GeometrySet &instance_geometry_set = reference.geometry_set();
+ fn(instance_geometry_set, base_transform, id);
+ break;
+ }
+ case InstanceReference::Type::None: {
+ break;
+ }
+ }
+}
+
+static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
+ const InstancesComponent &instances_component,
+ const float4x4 &base_transform,
+ const InstanceContext &base_instance_context)
+{
+ const Span<InstanceReference> references = instances_component.references();
+ const Span<int> handles = instances_component.instance_reference_handles();
+ const Span<float4x4> transforms = instances_component.instance_transforms();
+
+ Span<int> stored_instance_ids;
+ if (gather_info.create_id_attribute_on_any_component) {
+ std::optional<GSpan> ids = instances_component.attributes().get_for_read("id");
+ if (ids.has_value()) {
+ stored_instance_ids = ids->typed<int>();
+ }
+ }
+
+ /* Prepare attribute fallbacks. */
+ InstanceContext instance_context = base_instance_context;
+ Vector<std::pair<int, GSpan>> pointcloud_attributes_to_override = prepare_attribute_fallbacks(
+ gather_info, instances_component, gather_info.pointclouds.attributes);
+ Vector<std::pair<int, GSpan>> mesh_attributes_to_override = prepare_attribute_fallbacks(
+ gather_info, instances_component, gather_info.meshes.attributes);
+ Vector<std::pair<int, GSpan>> curve_attributes_to_override = prepare_attribute_fallbacks(
+ gather_info, instances_component, gather_info.curves.attributes);
+
+ for (const int i : transforms.index_range()) {
+ const int handle = handles[i];
+ const float4x4 &transform = transforms[i];
+ const InstanceReference &reference = references[handle];
+ const float4x4 new_base_transform = base_transform * transform;
+
+ /* Update attribute fallbacks for the current instance. */
+ for (const std::pair<int, GSpan> &pair : pointcloud_attributes_to_override) {
+ instance_context.pointclouds.array[pair.first] = pair.second[i];
+ }
+ for (const std::pair<int, GSpan> &pair : mesh_attributes_to_override) {
+ instance_context.meshes.array[pair.first] = pair.second[i];
+ }
+ for (const std::pair<int, GSpan> &pair : curve_attributes_to_override) {
+ instance_context.curves.array[pair.first] = pair.second[i];
+ }
+
+ uint32_t local_instance_id = 0;
+ if (gather_info.create_id_attribute_on_any_component) {
+ if (stored_instance_ids.is_empty()) {
+ local_instance_id = (uint32_t)i;
+ }
+ else {
+ local_instance_id = (uint32_t)stored_instance_ids[i];
+ }
+ }
+ const uint32_t instance_id = noise::hash(base_instance_context.id, local_instance_id);
+
+ /* Add realize tasks for all referenced geometry sets recursively. */
+ foreach_geometry_in_reference(reference,
+ new_base_transform,
+ instance_id,
+ [&](const GeometrySet &instance_geometry_set,
+ const float4x4 &transform,
+ const uint32_t id) {
+ instance_context.id = id;
+ gather_realize_tasks_recursive(gather_info,
+ instance_geometry_set,
+ transform,
+ instance_context);
+ });
+ }
+}
+
+/**
+ * Gather tasks for all geometries in the #geometry_set.
+ */
+static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
+ const GeometrySet &geometry_set,
+ const float4x4 &base_transform,
+ const InstanceContext &base_instance_context)
+{
+ for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
+ const GeometryComponentType type = component->type();
+ switch (type) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ const MeshComponent &mesh_component = *static_cast<const MeshComponent *>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh != nullptr && mesh->totvert > 0) {
+ const int mesh_index = gather_info.meshes.order.index_of(mesh);
+ const MeshRealizeInfo &mesh_info = gather_info.meshes.realize_info[mesh_index];
+ gather_info.r_tasks.mesh_tasks.append({gather_info.r_offsets.mesh_offsets,
+ &mesh_info,
+ base_transform,
+ base_instance_context.meshes,
+ base_instance_context.id});
+ gather_info.r_offsets.mesh_offsets.vertex += mesh->totvert;
+ gather_info.r_offsets.mesh_offsets.edge += mesh->totedge;
+ gather_info.r_offsets.mesh_offsets.loop += mesh->totloop;
+ gather_info.r_offsets.mesh_offsets.poly += mesh->totpoly;
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ const PointCloudComponent &pointcloud_component =
+ *static_cast<const PointCloudComponent *>(component);
+ const PointCloud *pointcloud = pointcloud_component.get_for_read();
+ if (pointcloud != nullptr && pointcloud->totpoint > 0) {
+ const int pointcloud_index = gather_info.pointclouds.order.index_of(pointcloud);
+ const PointCloudRealizeInfo &pointcloud_info =
+ gather_info.pointclouds.realize_info[pointcloud_index];
+ gather_info.r_tasks.pointcloud_tasks.append({gather_info.r_offsets.pointcloud_offset,
+ &pointcloud_info,
+ base_transform,
+ base_instance_context.pointclouds,
+ base_instance_context.id});
+ gather_info.r_offsets.pointcloud_offset += pointcloud->totpoint;
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ const CurveComponent &curve_component = *static_cast<const CurveComponent *>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve != nullptr && !curve->splines().is_empty()) {
+ const int curve_index = gather_info.curves.order.index_of(curve);
+ const RealizeCurveInfo &curve_info = gather_info.curves.realize_info[curve_index];
+ gather_info.r_tasks.curve_tasks.append({gather_info.r_offsets.spline_offset,
+ &curve_info,
+ base_transform,
+ base_instance_context.curves,
+ base_instance_context.id});
+ gather_info.r_offsets.spline_offset += curve->splines().size();
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ const InstancesComponent &instances_component = *static_cast<const InstancesComponent *>(
+ component);
+ gather_realize_tasks_for_instances(
+ gather_info, instances_component, base_transform, base_instance_context);
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME: {
+ const VolumeComponent *volume_component = static_cast<const VolumeComponent *>(component);
+ if (!gather_info.r_tasks.first_volume) {
+ volume_component->user_add();
+ gather_info.r_tasks.first_volume = const_cast<VolumeComponent *>(volume_component);
+ }
+ break;
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Point Cloud
+ * \{ */
+
+static OrderedAttributes gather_generic_pointcloud_attributes_to_propagate(
+ const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
+{
+ Vector<GeometryComponentType> src_component_types;
+ src_component_types.append(GEO_COMPONENT_TYPE_POINT_CLOUD);
+ if (options.realize_instance_attributes) {
+ src_component_types.append(GEO_COMPONENT_TYPE_INSTANCES);
+ }
+
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ in_geometry_set.gather_attributes_for_propagation(
+ src_component_types, GEO_COMPONENT_TYPE_POINT_CLOUD, true, attributes_to_propagate);
+ attributes_to_propagate.remove("position");
+ r_create_id = attributes_to_propagate.pop_try("id").has_value();
+ OrderedAttributes ordered_attributes;
+ for (const auto item : attributes_to_propagate.items()) {
+ ordered_attributes.ids.add_new(item.key);
+ ordered_attributes.kinds.append(item.value);
+ }
+ return ordered_attributes;
+}
+
+static void gather_pointclouds_to_realize(const GeometrySet &geometry_set,
+ VectorSet<const PointCloud *> &r_pointclouds)
+{
+ if (const PointCloud *pointcloud = geometry_set.get_pointcloud_for_read()) {
+ if (pointcloud->totpoint > 0) {
+ r_pointclouds.add(pointcloud);
+ }
+ }
+ if (const InstancesComponent *instances =
+ geometry_set.get_component_for_read<InstancesComponent>()) {
+ instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
+ gather_pointclouds_to_realize(instance_geometry_set, r_pointclouds);
+ });
+ }
+}
+
+static AllPointCloudsInfo preprocess_pointclouds(const GeometrySet &geometry_set,
+ const RealizeInstancesOptions &options)
+{
+ AllPointCloudsInfo info;
+ info.attributes = gather_generic_pointcloud_attributes_to_propagate(
+ geometry_set, options, info.create_id_attribute);
+
+ gather_pointclouds_to_realize(geometry_set, info.order);
+ info.realize_info.reinitialize(info.order.size());
+ for (const int pointcloud_index : info.realize_info.index_range()) {
+ PointCloudRealizeInfo &pointcloud_info = info.realize_info[pointcloud_index];
+ const PointCloud *pointcloud = info.order[pointcloud_index];
+ pointcloud_info.pointcloud = pointcloud;
+
+ /* Access attributes. */
+ PointCloudComponent component;
+ component.replace(const_cast<PointCloud *>(pointcloud), GeometryOwnershipType::ReadOnly);
+ pointcloud_info.attributes.reinitialize(info.attributes.size());
+ for (const int attribute_index : info.attributes.index_range()) {
+ const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
+ const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
+ if (component.attribute_exists(attribute_id)) {
+ GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
+ pointcloud_info.attributes[attribute_index].emplace(std::move(attribute));
+ }
+ }
+ if (info.create_id_attribute) {
+ ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id");
+ if (ids_lookup) {
+ pointcloud_info.stored_ids = ids_lookup.varray.get_internal_span().typed<int>();
+ }
+ }
+ }
+ return info;
+}
+
+static void execute_realize_pointcloud_task(const RealizeInstancesOptions &options,
+ const RealizePointCloudTask &task,
+ PointCloud &dst_pointcloud,
+ MutableSpan<GMutableSpan> dst_attribute_spans,
+ MutableSpan<int> all_dst_ids)
+{
+ const PointCloudRealizeInfo &pointcloud_info = *task.pointcloud_info;
+ const PointCloud &pointcloud = *pointcloud_info.pointcloud;
+ const Span<float3> src_positions{(float3 *)pointcloud.co, pointcloud.totpoint};
+ const IndexRange point_slice{task.start_index, pointcloud.totpoint};
+ MutableSpan<float3> dst_positions{(float3 *)dst_pointcloud.co + task.start_index,
+ pointcloud.totpoint};
+ MutableSpan<int> dst_ids = all_dst_ids.slice(task.start_index, pointcloud.totpoint);
+
+ /* Copy transformed positions. */
+ threading::parallel_for(IndexRange(pointcloud.totpoint), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ dst_positions[i] = task.transform * src_positions[i];
+ }
+ });
+ /* Create point ids. */
+ if (!all_dst_ids.is_empty()) {
+ if (options.keep_original_ids) {
+ if (pointcloud_info.stored_ids.is_empty()) {
+ dst_ids.fill(0);
+ }
+ else {
+ dst_ids.copy_from(pointcloud_info.stored_ids);
+ }
+ }
+ else {
+ threading::parallel_for(IndexRange(pointcloud.totpoint), 1024, [&](const IndexRange range) {
+ if (pointcloud_info.stored_ids.is_empty()) {
+ for (const int i : range) {
+ dst_ids[i] = noise::hash(task.id, i);
+ }
+ }
+ else {
+ for (const int i : range) {
+ dst_ids[i] = noise::hash(task.id, pointcloud_info.stored_ids[i]);
+ }
+ }
+ });
+ }
+ }
+ /* Copy generic attributes. */
+ threading::parallel_for(
+ dst_attribute_spans.index_range(), 10, [&](const IndexRange attribute_range) {
+ for (const int attribute_index : attribute_range) {
+ GMutableSpan dst_span = dst_attribute_spans[attribute_index].slice(point_slice);
+ const CPPType &cpp_type = dst_span.type();
+ const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
+ if (pointcloud_info.attributes[attribute_index].has_value()) {
+ /* Copy attribute from the original point cloud. */
+ const GSpan src_span = *pointcloud_info.attributes[attribute_index];
+ threading::parallel_for(
+ IndexRange(pointcloud.totpoint), 1024, [&](const IndexRange range) {
+ cpp_type.copy_assign_n(
+ src_span.slice(range).data(), dst_span.slice(range).data(), range.size());
+ });
+ }
+ else {
+ if (attribute_fallback == nullptr) {
+ attribute_fallback = cpp_type.default_value();
+ }
+ /* As the fallback value for the attribute. */
+ threading::parallel_for(
+ IndexRange(pointcloud.totpoint), 1024, [&](const IndexRange range) {
+ cpp_type.fill_assign_n(
+ attribute_fallback, dst_span.slice(range).data(), range.size());
+ });
+ }
+ }
+ });
+}
+
+static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &options,
+ const AllPointCloudsInfo &all_pointclouds_info,
+ const Span<RealizePointCloudTask> tasks,
+ const OrderedAttributes &ordered_attributes,
+ GeometrySet &r_realized_geometry)
+{
+ if (tasks.is_empty()) {
+ return;
+ }
+
+ const RealizePointCloudTask &last_task = tasks.last();
+ const PointCloud &last_pointcloud = *last_task.pointcloud_info->pointcloud;
+ const int tot_points = last_task.start_index + last_pointcloud.totpoint;
+
+ /* Allocate new point cloud. */
+ PointCloud *dst_pointcloud = BKE_pointcloud_new_nomain(tot_points);
+ PointCloudComponent &dst_component =
+ r_realized_geometry.get_component_for_write<PointCloudComponent>();
+ dst_component.replace(dst_pointcloud);
+
+ /* Prepare id attribute. */
+ OutputAttribute_Typed<int> point_ids;
+ MutableSpan<int> point_ids_span;
+ if (all_pointclouds_info.create_id_attribute) {
+ point_ids = dst_component.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_POINT);
+ point_ids_span = point_ids.as_span();
+ }
+
+ /* Prepare generic output attributes. */
+ Vector<OutputAttribute> dst_attributes;
+ Vector<GMutableSpan> dst_attribute_spans;
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, ATTR_DOMAIN_POINT, data_type);
+ dst_attribute_spans.append(dst_attribute.as_span());
+ dst_attributes.append(std::move(dst_attribute));
+ }
+
+ /* Actually execute all tasks. */
+ threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
+ for (const int task_index : task_range) {
+ const RealizePointCloudTask &task = tasks[task_index];
+ execute_realize_pointcloud_task(
+ options, task, *dst_pointcloud, dst_attribute_spans, point_ids_span);
+ }
+ });
+
+ /* Save modified attributes. */
+ for (OutputAttribute &dst_attribute : dst_attributes) {
+ dst_attribute.save();
+ }
+ if (point_ids) {
+ point_ids.save();
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh
+ * \{ */
+
+static OrderedAttributes gather_generic_mesh_attributes_to_propagate(
+ const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
+{
+ Vector<GeometryComponentType> src_component_types;
+ src_component_types.append(GEO_COMPONENT_TYPE_MESH);
+ if (options.realize_instance_attributes) {
+ src_component_types.append(GEO_COMPONENT_TYPE_INSTANCES);
+ }
+
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ in_geometry_set.gather_attributes_for_propagation(
+ src_component_types, GEO_COMPONENT_TYPE_MESH, true, attributes_to_propagate);
+ attributes_to_propagate.remove("position");
+ attributes_to_propagate.remove("normal");
+ attributes_to_propagate.remove("material_index");
+ attributes_to_propagate.remove("shade_smooth");
+ attributes_to_propagate.remove("crease");
+ r_create_id = attributes_to_propagate.pop_try("id").has_value();
+ OrderedAttributes ordered_attributes;
+ for (const auto item : attributes_to_propagate.items()) {
+ ordered_attributes.ids.add_new(item.key);
+ ordered_attributes.kinds.append(item.value);
+ }
+ return ordered_attributes;
+}
+
+static void gather_meshes_to_realize(const GeometrySet &geometry_set,
+ VectorSet<const Mesh *> &r_meshes)
+{
+ if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
+ if (mesh->totvert > 0) {
+ r_meshes.add(mesh);
+ }
+ }
+ if (const InstancesComponent *instances =
+ geometry_set.get_component_for_read<InstancesComponent>()) {
+ instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
+ gather_meshes_to_realize(instance_geometry_set, r_meshes);
+ });
+ }
+}
+
+static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
+ const RealizeInstancesOptions &options)
+{
+ AllMeshesInfo info;
+ info.attributes = gather_generic_mesh_attributes_to_propagate(
+ geometry_set, options, info.create_id_attribute);
+
+ gather_meshes_to_realize(geometry_set, info.order);
+ for (const Mesh *mesh : info.order) {
+ for (const int slot_index : IndexRange(mesh->totcol)) {
+ Material *material = mesh->mat[slot_index];
+ info.materials.add(material);
+ }
+ }
+ info.realize_info.reinitialize(info.order.size());
+ for (const int mesh_index : info.realize_info.index_range()) {
+ MeshRealizeInfo &mesh_info = info.realize_info[mesh_index];
+ const Mesh *mesh = info.order[mesh_index];
+ mesh_info.mesh = mesh;
+
+ /* Create material index mapping. */
+ mesh_info.material_index_map.reinitialize(mesh->totcol);
+ for (const int old_slot_index : IndexRange(mesh->totcol)) {
+ Material *material = mesh->mat[old_slot_index];
+ const int new_slot_index = info.materials.index_of(material);
+ mesh_info.material_index_map[old_slot_index] = new_slot_index;
+ }
+
+ /* Access attributes. */
+ MeshComponent component;
+ component.replace(const_cast<Mesh *>(mesh), GeometryOwnershipType::ReadOnly);
+ mesh_info.attributes.reinitialize(info.attributes.size());
+ for (const int attribute_index : info.attributes.index_range()) {
+ const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
+ const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
+ if (component.attribute_exists(attribute_id)) {
+ GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
+ mesh_info.attributes[attribute_index].emplace(std::move(attribute));
+ }
+ }
+ if (info.create_id_attribute) {
+ ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id");
+ if (ids_lookup) {
+ mesh_info.stored_vertex_ids = ids_lookup.varray.get_internal_span().typed<int>();
+ }
+ }
+ }
+ return info;
+}
+
+static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
+ const RealizeMeshTask &task,
+ const OrderedAttributes &ordered_attributes,
+ Mesh &dst_mesh,
+ MutableSpan<GMutableSpan> dst_attribute_spans,
+ MutableSpan<int> all_dst_vertex_ids)
+{
+ const MeshRealizeInfo &mesh_info = *task.mesh_info;
+ const Mesh &mesh = *mesh_info.mesh;
+
+ const Span<MVert> src_verts{mesh.mvert, mesh.totvert};
+ const Span<MEdge> src_edges{mesh.medge, mesh.totedge};
+ const Span<MLoop> src_loops{mesh.mloop, mesh.totloop};
+ const Span<MPoly> src_polys{mesh.mpoly, mesh.totpoly};
+
+ MutableSpan<MVert> dst_verts{dst_mesh.mvert + task.start_indices.vertex, mesh.totvert};
+ MutableSpan<MEdge> dst_edges{dst_mesh.medge + task.start_indices.edge, mesh.totedge};
+ MutableSpan<MLoop> dst_loops{dst_mesh.mloop + task.start_indices.loop, mesh.totloop};
+ MutableSpan<MPoly> dst_polys{dst_mesh.mpoly + task.start_indices.poly, mesh.totpoly};
+
+ MutableSpan<int> dst_vertex_ids = all_dst_vertex_ids.slice(task.start_indices.vertex,
+ mesh.totvert);
+
+ const Span<int> material_index_map = mesh_info.material_index_map;
+
+ threading::parallel_for(IndexRange(mesh.totvert), 1024, [&](const IndexRange vert_range) {
+ for (const int i : vert_range) {
+ const MVert &src_vert = src_verts[i];
+ MVert &dst_vert = dst_verts[i];
+ dst_vert = src_vert;
+ copy_v3_v3(dst_vert.co, task.transform * float3(src_vert.co));
+ }
+ });
+ threading::parallel_for(IndexRange(mesh.totedge), 1024, [&](const IndexRange edge_range) {
+ for (const int i : edge_range) {
+ const MEdge &src_edge = src_edges[i];
+ MEdge &dst_edge = dst_edges[i];
+ dst_edge = src_edge;
+ dst_edge.v1 += task.start_indices.vertex;
+ dst_edge.v2 += task.start_indices.vertex;
+ }
+ });
+ threading::parallel_for(IndexRange(mesh.totloop), 1024, [&](const IndexRange loop_range) {
+ for (const int i : loop_range) {
+ const MLoop &src_loop = src_loops[i];
+ MLoop &dst_loop = dst_loops[i];
+ dst_loop = src_loop;
+ dst_loop.v += task.start_indices.vertex;
+ dst_loop.e += task.start_indices.edge;
+ }
+ });
+ threading::parallel_for(IndexRange(mesh.totpoly), 1024, [&](const IndexRange poly_range) {
+ for (const int i : poly_range) {
+ const MPoly &src_poly = src_polys[i];
+ MPoly &dst_poly = dst_polys[i];
+ dst_poly = src_poly;
+ dst_poly.loopstart += task.start_indices.loop;
+ if (src_poly.mat_nr >= 0 && src_poly.mat_nr < mesh.totcol) {
+ dst_poly.mat_nr = material_index_map[src_poly.mat_nr];
+ }
+ else {
+ /* The material index was invalid before. */
+ dst_poly.mat_nr = 0;
+ }
+ }
+ });
+ /* Create id attribute. */
+ if (!all_dst_vertex_ids.is_empty()) {
+ if (options.keep_original_ids) {
+ if (mesh_info.stored_vertex_ids.is_empty()) {
+ dst_vertex_ids.fill(0);
+ }
+ else {
+ dst_vertex_ids.copy_from(mesh_info.stored_vertex_ids);
+ }
+ }
+ else {
+ threading::parallel_for(IndexRange(mesh.totvert), 1024, [&](const IndexRange vert_range) {
+ if (mesh_info.stored_vertex_ids.is_empty()) {
+ for (const int i : vert_range) {
+ dst_vertex_ids[i] = noise::hash(task.id, i);
+ }
+ }
+ else {
+ for (const int i : vert_range) {
+ const int original_id = mesh_info.stored_vertex_ids[i];
+ dst_vertex_ids[i] = noise::hash(task.id, original_id);
+ }
+ }
+ });
+ }
+ }
+ /* Copy generic attributes. */
+ threading::parallel_for(
+ dst_attribute_spans.index_range(), 10, [&](const IndexRange attribute_range) {
+ for (const int attribute_index : attribute_range) {
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ IndexRange element_slice;
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ element_slice = IndexRange(task.start_indices.vertex, mesh.totvert);
+ break;
+ case ATTR_DOMAIN_EDGE:
+ element_slice = IndexRange(task.start_indices.edge, mesh.totedge);
+ break;
+ case ATTR_DOMAIN_CORNER:
+ element_slice = IndexRange(task.start_indices.loop, mesh.totloop);
+ break;
+ case ATTR_DOMAIN_FACE:
+ element_slice = IndexRange(task.start_indices.poly, mesh.totpoly);
+ break;
+ default:
+ BLI_assert_unreachable();
+ }
+ GMutableSpan dst_span = dst_attribute_spans[attribute_index].slice(element_slice);
+ const CPPType &cpp_type = dst_span.type();
+ const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
+ if (mesh_info.attributes[attribute_index].has_value()) {
+ const GSpan src_span = *mesh_info.attributes[attribute_index];
+ threading::parallel_for(
+ IndexRange(element_slice.size()), 1024, [&](const IndexRange sub_range) {
+ cpp_type.copy_assign_n(src_span.slice(sub_range).data(),
+ dst_span.slice(sub_range).data(),
+ sub_range.size());
+ });
+ }
+ else {
+ if (attribute_fallback == nullptr) {
+ attribute_fallback = cpp_type.default_value();
+ }
+ threading::parallel_for(
+ IndexRange(element_slice.size()), 1024, [&](const IndexRange sub_range) {
+ cpp_type.fill_assign_n(
+ attribute_fallback, dst_span.slice(sub_range).data(), sub_range.size());
+ });
+ }
+ }
+ });
+}
+
+static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
+ const AllMeshesInfo &all_meshes_info,
+ const Span<RealizeMeshTask> tasks,
+ const OrderedAttributes &ordered_attributes,
+ const VectorSet<Material *> &ordered_materials,
+ GeometrySet &r_realized_geometry)
+{
+ if (tasks.is_empty()) {
+ return;
+ }
+
+ const RealizeMeshTask &last_task = tasks.last();
+ const Mesh &last_mesh = *last_task.mesh_info->mesh;
+ const int tot_vertices = last_task.start_indices.vertex + last_mesh.totvert;
+ const int tot_edges = last_task.start_indices.edge + last_mesh.totedge;
+ const int tot_loops = last_task.start_indices.loop + last_mesh.totloop;
+ const int tot_poly = last_task.start_indices.poly + last_mesh.totpoly;
+
+ Mesh *dst_mesh = BKE_mesh_new_nomain(tot_vertices, tot_edges, 0, tot_loops, tot_poly);
+ MeshComponent &dst_component = r_realized_geometry.get_component_for_write<MeshComponent>();
+ dst_component.replace(dst_mesh);
+
+ /* Copy settings from the first input geometry set with a mesh. */
+ const RealizeMeshTask &first_task = tasks.first();
+ const Mesh &first_mesh = *first_task.mesh_info->mesh;
+ BKE_mesh_copy_parameters_for_eval(dst_mesh, &first_mesh);
+
+ /* Add materials. */
+ for (const int i : IndexRange(ordered_materials.size())) {
+ Material *material = ordered_materials[i];
+ BKE_id_material_eval_assign(&dst_mesh->id, i + 1, material);
+ }
+
+ /* Prepare id attribute. */
+ OutputAttribute_Typed<int> vertex_ids;
+ MutableSpan<int> vertex_ids_span;
+ if (all_meshes_info.create_id_attribute) {
+ vertex_ids = dst_component.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_POINT);
+ vertex_ids_span = vertex_ids.as_span();
+ }
+
+ /* Prepare generic output attributes. */
+ Vector<OutputAttribute> dst_attributes;
+ Vector<GMutableSpan> dst_attribute_spans;
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, domain, data_type);
+ dst_attribute_spans.append(dst_attribute.as_span());
+ dst_attributes.append(std::move(dst_attribute));
+ }
+
+ /* Actually execute all tasks. */
+ threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
+ for (const int task_index : task_range) {
+ const RealizeMeshTask &task = tasks[task_index];
+ execute_realize_mesh_task(
+ options, task, ordered_attributes, *dst_mesh, dst_attribute_spans, vertex_ids_span);
+ }
+ });
+
+ /* Save modified attributes. */
+ for (OutputAttribute &dst_attribute : dst_attributes) {
+ dst_attribute.save();
+ }
+ if (vertex_ids) {
+ vertex_ids.save();
+ }
+
+ BKE_mesh_normals_tag_dirty(dst_mesh);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Curve
+ * \{ */
+
+static OrderedAttributes gather_generic_curve_attributes_to_propagate(
+ const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
+{
+ Vector<GeometryComponentType> src_component_types;
+ src_component_types.append(GEO_COMPONENT_TYPE_CURVE);
+ if (options.realize_instance_attributes) {
+ src_component_types.append(GEO_COMPONENT_TYPE_INSTANCES);
+ }
+
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ in_geometry_set.gather_attributes_for_propagation(
+ src_component_types, GEO_COMPONENT_TYPE_CURVE, true, attributes_to_propagate);
+ attributes_to_propagate.remove("position");
+ attributes_to_propagate.remove("cyclic");
+ attributes_to_propagate.remove("resolution");
+ attributes_to_propagate.remove("tilt");
+ attributes_to_propagate.remove("radius");
+ attributes_to_propagate.remove("handle_right");
+ attributes_to_propagate.remove("handle_left");
+ r_create_id = attributes_to_propagate.pop_try("id").has_value();
+ OrderedAttributes ordered_attributes;
+ for (const auto item : attributes_to_propagate.items()) {
+ ordered_attributes.ids.add_new(item.key);
+ ordered_attributes.kinds.append(item.value);
+ }
+ return ordered_attributes;
+}
+
+static void gather_curves_to_realize(const GeometrySet &geometry_set,
+ VectorSet<const CurveEval *> &r_curves)
+{
+ if (const CurveEval *curve = geometry_set.get_curve_for_read()) {
+ if (!curve->splines().is_empty()) {
+ r_curves.add(curve);
+ }
+ }
+ if (const InstancesComponent *instances =
+ geometry_set.get_component_for_read<InstancesComponent>()) {
+ instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
+ gather_curves_to_realize(instance_geometry_set, r_curves);
+ });
+ }
+}
+
+static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set,
+ const RealizeInstancesOptions &options)
+{
+ AllCurvesInfo info;
+ info.attributes = gather_generic_curve_attributes_to_propagate(
+ geometry_set, options, info.create_id_attribute);
+
+ gather_curves_to_realize(geometry_set, info.order);
+ info.realize_info.reinitialize(info.order.size());
+ for (const int curve_index : info.realize_info.index_range()) {
+ RealizeCurveInfo &curve_info = info.realize_info[curve_index];
+ const CurveEval *curve = info.order[curve_index];
+ curve_info.curve = curve;
+
+ /* Access attributes. */
+ CurveComponent component;
+ component.replace(const_cast<CurveEval *>(curve), GeometryOwnershipType::ReadOnly);
+ curve_info.spline_attributes.reinitialize(info.attributes.size());
+ for (const int attribute_index : info.attributes.index_range()) {
+ const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
+ if (domain != ATTR_DOMAIN_CURVE) {
+ continue;
+ }
+ const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
+ const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ if (component.attribute_exists(attribute_id)) {
+ GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
+ curve_info.spline_attributes[attribute_index].emplace(std::move(attribute));
+ }
+ }
+ }
+ return info;
+}
+
+static void execute_realize_curve_task(const RealizeInstancesOptions &options,
+ const AllCurvesInfo &all_curves_info,
+ const RealizeCurveTask &task,
+ const OrderedAttributes &ordered_attributes,
+ MutableSpan<SplinePtr> dst_splines,
+ MutableSpan<GMutableSpan> dst_spline_attributes)
+{
+ const RealizeCurveInfo &curve_info = *task.curve_info;
+ const CurveEval &curve = *curve_info.curve;
+
+ const Span<SplinePtr> src_splines = curve.splines();
+
+ /* Initialize point attributes. */
+ threading::parallel_for(src_splines.index_range(), 100, [&](const IndexRange src_spline_range) {
+ for (const int src_spline_index : src_spline_range) {
+ const int dst_spline_index = src_spline_index + task.start_spline_index;
+ const Spline &src_spline = *src_splines[src_spline_index];
+ SplinePtr dst_spline = src_spline.copy_without_attributes();
+ dst_spline->transform(task.transform);
+ const int spline_size = dst_spline->size();
+
+ const CustomDataAttributes &src_point_attributes = src_spline.attributes;
+ CustomDataAttributes &dst_point_attributes = dst_spline->attributes;
+
+ /* Create point ids. */
+ if (all_curves_info.create_id_attribute) {
+ dst_point_attributes.create("id", CD_PROP_INT32);
+ MutableSpan<int> dst_point_ids = dst_point_attributes.get_for_write("id")->typed<int>();
+ std::optional<GSpan> src_point_ids_opt = src_point_attributes.get_for_read("id");
+ if (options.keep_original_ids) {
+ if (src_point_ids_opt.has_value()) {
+ const Span<int> src_point_ids = src_point_ids_opt->typed<int>();
+ dst_point_ids.copy_from(src_point_ids);
+ }
+ else {
+ dst_point_ids.fill(0);
+ }
+ }
+ else {
+ if (src_point_ids_opt.has_value()) {
+ const Span<int> src_point_ids = src_point_ids_opt->typed<int>();
+ for (const int i : IndexRange(dst_spline->size())) {
+ dst_point_ids[i] = noise::hash(task.id, src_point_ids[i]);
+ }
+ }
+ else {
+ for (const int i : IndexRange(dst_spline->size())) {
+ /* Mix spline index into the id, because otherwise points on different splines will
+ * get the same id. */
+ dst_point_ids[i] = noise::hash(task.id, src_spline_index, i);
+ }
+ }
+ }
+ }
+
+ /* Copy generic point attributes. */
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ if (domain != ATTR_DOMAIN_POINT) {
+ continue;
+ }
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ const CPPType &cpp_type = *custom_data_type_to_cpp_type(data_type);
+ const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
+ const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
+ const std::optional<GSpan> src_span_opt = src_point_attributes.get_for_read(attribute_id);
+ void *dst_buffer = MEM_malloc_arrayN(spline_size, cpp_type.size(), "Curve Attribute");
+ if (src_span_opt.has_value()) {
+ const GSpan src_span = *src_span_opt;
+ cpp_type.copy_construct_n(src_span.data(), dst_buffer, spline_size);
+ }
+ else {
+ if (attribute_fallback == nullptr) {
+ attribute_fallback = cpp_type.default_value();
+ }
+ cpp_type.fill_construct_n(attribute_fallback, dst_buffer, spline_size);
+ }
+ dst_point_attributes.create_by_move(attribute_id, data_type, dst_buffer);
+ }
+
+ dst_splines[dst_spline_index] = std::move(dst_spline);
+ }
+ });
+ /* Initialize spline attributes. */
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ if (domain != ATTR_DOMAIN_CURVE) {
+ continue;
+ }
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ const CPPType &cpp_type = *custom_data_type_to_cpp_type(data_type);
+
+ GMutableSpan dst_span = dst_spline_attributes[attribute_index].slice(task.start_spline_index,
+ src_splines.size());
+ if (curve_info.spline_attributes[attribute_index].has_value()) {
+ const GSpan src_span = *curve_info.spline_attributes[attribute_index];
+ cpp_type.copy_construct_n(src_span.data(), dst_span.data(), src_splines.size());
+ }
+ else {
+ const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
+ if (attribute_fallback == nullptr) {
+ attribute_fallback = cpp_type.default_value();
+ }
+ cpp_type.fill_construct_n(attribute_fallback, dst_span.data(), src_splines.size());
+ }
+ }
+}
+
+static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
+ const AllCurvesInfo &all_curves_info,
+ const Span<RealizeCurveTask> tasks,
+ const OrderedAttributes &ordered_attributes,
+ GeometrySet &r_realized_geometry)
+{
+ if (tasks.is_empty()) {
+ return;
+ }
+
+ const RealizeCurveTask &last_task = tasks.last();
+ const CurveEval &last_curve = *last_task.curve_info->curve;
+ const int tot_splines = last_task.start_spline_index + last_curve.splines().size();
+
+ Array<SplinePtr> dst_splines(tot_splines);
+
+ CurveEval *dst_curve = new CurveEval();
+ dst_curve->attributes.reallocate(tot_splines);
+ CustomDataAttributes &spline_attributes = dst_curve->attributes;
+
+ /* Prepare spline attributes. */
+ Vector<GMutableSpan> dst_spline_attributes;
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ if (domain == ATTR_DOMAIN_CURVE) {
+ spline_attributes.create(attribute_id, data_type);
+ dst_spline_attributes.append(*spline_attributes.get_for_write(attribute_id));
+ }
+ else {
+ dst_spline_attributes.append({CPPType::get<float>()});
+ }
+ }
+
+ /* Actually execute all tasks. */
+ threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
+ for (const int task_index : task_range) {
+ const RealizeCurveTask &task = tasks[task_index];
+ execute_realize_curve_task(
+ options, all_curves_info, task, ordered_attributes, dst_splines, dst_spline_attributes);
+ }
+ });
+
+ dst_curve->add_splines(dst_splines);
+
+ CurveComponent &dst_component = r_realized_geometry.get_component_for_write<CurveComponent>();
+ dst_component.replace(dst_curve);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Realize Instances
+ * \{ */
+
+static void remove_id_attribute_from_instances(GeometrySet &geometry_set)
+{
+ geometry_set.modify_geometry_sets([&](GeometrySet &sub_geometry) {
+ if (sub_geometry.has<InstancesComponent>()) {
+ InstancesComponent &component = geometry_set.get_component_for_write<InstancesComponent>();
+ component.attributes().remove("id");
+ }
+ });
+}
+
+GeometrySet realize_instances(GeometrySet geometry_set, const RealizeInstancesOptions &options)
+{
+ /* The algorithm works in three steps:
+ * 1. Preprocess each unique geometry that is instanced (e.g. each `Mesh`).
+ * 2. Gather "tasks" that need to be executed to realize the instances. Each task corresponds to
+ * instances of the previously preprocessed geometry.
+ * 3. Execute all tasks in parallel.
+ */
+
+ if (!geometry_set.has_instances()) {
+ return geometry_set;
+ }
+
+ if (options.keep_original_ids) {
+ remove_id_attribute_from_instances(geometry_set);
+ }
+
+ AllPointCloudsInfo all_pointclouds_info = preprocess_pointclouds(geometry_set, options);
+ AllMeshesInfo all_meshes_info = preprocess_meshes(geometry_set, options);
+ AllCurvesInfo all_curves_info = preprocess_curves(geometry_set, options);
+
+ Vector<std::unique_ptr<GArray<>>> temporary_arrays;
+ const bool create_id_attribute = all_pointclouds_info.create_id_attribute ||
+ all_meshes_info.create_id_attribute ||
+ all_curves_info.create_id_attribute;
+ GatherTasksInfo gather_info = {all_pointclouds_info,
+ all_meshes_info,
+ all_curves_info,
+ create_id_attribute,
+ temporary_arrays};
+ const float4x4 transform = float4x4::identity();
+ InstanceContext attribute_fallbacks(gather_info);
+ gather_realize_tasks_recursive(gather_info, geometry_set, transform, attribute_fallbacks);
+
+ GeometrySet new_geometry_set;
+ execute_realize_pointcloud_tasks(options,
+ all_pointclouds_info,
+ gather_info.r_tasks.pointcloud_tasks,
+ all_pointclouds_info.attributes,
+ new_geometry_set);
+ execute_realize_mesh_tasks(options,
+ all_meshes_info,
+ gather_info.r_tasks.mesh_tasks,
+ all_meshes_info.attributes,
+ all_meshes_info.materials,
+ new_geometry_set);
+ execute_realize_curve_tasks(options,
+ all_curves_info,
+ gather_info.r_tasks.curve_tasks,
+ all_curves_info.attributes,
+ new_geometry_set);
+
+ if (gather_info.r_tasks.first_volume) {
+ new_geometry_set.add(*gather_info.r_tasks.first_volume);
+ }
+
+ return new_geometry_set;
+}
+
+GeometrySet realize_instances_legacy(GeometrySet geometry_set)
+{
+ RealizeInstancesOptions options;
+ options.keep_original_ids = true;
+ options.realize_instance_attributes = false;
+ return realize_instances(std::move(geometry_set), options);
+}
+
+/** \} */
+
+} // namespace blender::geometry
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index afcd551d0af..5ee75619259 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -62,6 +62,7 @@ set(SRC
intern/MOD_gpencilnoise.c
intern/MOD_gpenciloffset.c
intern/MOD_gpencilopacity.c
+ intern/MOD_gpencilshrinkwrap.c
intern/MOD_gpencilsimplify.c
intern/MOD_gpencilsmooth.c
intern/MOD_gpencilsubdiv.c
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h b/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h
index 7d75ed5804e..95028ee959d 100644
--- a/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h
@@ -23,6 +23,7 @@
#include "DNA_windowmanager_types.h"
/* Operator types should be in exposed header. */
+
void OBJECT_OT_lineart_bake_strokes(struct wmOperatorType *ot);
void OBJECT_OT_lineart_bake_strokes_all(struct wmOperatorType *ot);
void OBJECT_OT_lineart_clear(struct wmOperatorType *ot);
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
index d9285f44a37..56cee115760 100644
--- a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
@@ -48,6 +48,7 @@ extern GpencilModifierTypeInfo modifierType_Gpencil_WeightProximity;
extern GpencilModifierTypeInfo modifierType_Gpencil_WeightAngle;
extern GpencilModifierTypeInfo modifierType_Gpencil_Lineart;
extern GpencilModifierTypeInfo modifierType_Gpencil_Dash;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Shrinkwrap;
/* MOD_gpencil_util.c */
void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
index e750c22f0e8..fe78a7e7bcc 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
@@ -203,9 +203,6 @@ void gpencil_modifier_curve_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiTemplateCurveMapping(layout, ptr, "curve", 0, false, false, false, false);
}
-/**
- * Draw modifier error message.
- */
void gpencil_modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
{
GpencilModifierData *md = ptr->data;
@@ -232,7 +229,7 @@ PointerRNA *gpencil_modifier_panel_get_property_pointers(Panel *panel, PointerRN
UI_block_lock_clear(block);
UI_block_lock_set(block, ID_IS_LINKED((Object *)ptr->owner_id), ERROR_LIBDATA_MESSAGE);
- uiLayoutSetContextPointer(panel->layout, "modifier", ptr);
+ UI_panel_context_pointer_set(panel, "modifier", ptr);
return ptr;
}
@@ -312,7 +309,7 @@ static void gpencil_modifier_panel_header(const bContext *UNUSED(C), Panel *pane
PointerRNA *ptr = UI_panel_custom_data_get(panel);
GpencilModifierData *md = (GpencilModifierData *)ptr->data;
- uiLayoutSetContextPointer(panel->layout, "modifier", ptr);
+ UI_panel_context_pointer_set(panel, "modifier", ptr);
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
bool narrow_panel = (panel->sizex < UI_UNIT_X * 9 && panel->sizex != 0);
@@ -360,9 +357,6 @@ static void gpencil_modifier_panel_header(const bContext *UNUSED(C), Panel *pane
/** \name Modifier Registration Helpers
* \{ */
-/**
- * Create a panel in the context's region
- */
PanelType *gpencil_modifier_panel_register(ARegionType *region_type,
GpencilModifierType type,
PanelDrawFn draw)
@@ -380,7 +374,7 @@ PanelType *gpencil_modifier_panel_register(ARegionType *region_type,
/* Give the panel the special flag that says it was built here and corresponds to a
* modifier rather than a #PanelType. */
- panel_type->flag = PANEL_TYPE_HEADER_EXPAND | PANEL_TYPE_DRAW_BOX | PANEL_TYPE_INSTANCED;
+ panel_type->flag = PANEL_TYPE_HEADER_EXPAND | PANEL_TYPE_INSTANCED;
panel_type->reorder = gpencil_modifier_reorder;
panel_type->get_list_data_expand_flag = get_gpencil_modifier_expand_flag;
panel_type->set_list_data_expand_flag = set_gpencil_modifier_expand_flag;
@@ -390,12 +384,6 @@ PanelType *gpencil_modifier_panel_register(ARegionType *region_type,
return panel_type;
}
-/**
- * Add a child panel to the parent.
- *
- * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
- * idname.
- */
PanelType *gpencil_modifier_subpanel_register(ARegionType *region_type,
const char *name,
const char *label,
@@ -413,7 +401,7 @@ PanelType *gpencil_modifier_subpanel_register(ARegionType *region_type,
panel_type->draw_header = draw_header;
panel_type->draw = draw;
panel_type->poll = gpencil_modifier_ui_poll;
- panel_type->flag = (PANEL_TYPE_DEFAULT_CLOSED | PANEL_TYPE_DRAW_BOX);
+ panel_type->flag = PANEL_TYPE_DEFAULT_CLOSED;
BLI_assert(parent != NULL);
BLI_strncpy(panel_type->parent_id, parent->idname, BKE_ST_MAXNAME);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h
index 782b36d47ed..2cccd6e15dd 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h
@@ -37,15 +37,27 @@ void gpencil_modifier_masking_panel_draw(Panel *panel, bool use_material, bool u
void gpencil_modifier_curve_header_draw(const bContext *C, Panel *panel);
void gpencil_modifier_curve_panel_draw(const bContext *C, Panel *panel);
+/**
+ * Draw modifier error message.
+ */
void gpencil_modifier_panel_end(struct uiLayout *layout, PointerRNA *ptr);
struct PointerRNA *gpencil_modifier_panel_get_property_pointers(struct Panel *panel,
struct PointerRNA *r_ob_ptr);
+/**
+ * Create a panel in the context's region
+ */
PanelType *gpencil_modifier_panel_register(struct ARegionType *region_type,
GpencilModifierType type,
PanelDrawFn draw);
+/**
+ * Add a child panel to the parent.
+ *
+ * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
+ * idname.
+ */
struct PanelType *gpencil_modifier_subpanel_register(struct ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index df78ac8110e..c583a45a27d 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -40,6 +40,8 @@
#include "MOD_gpencil_modifiertypes.h"
#include "MOD_gpencil_util.h"
+#include "DEG_depsgraph_query.h"
+
void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
{
#define INIT_GP_TYPE(typeName) \
@@ -67,10 +69,10 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
INIT_GP_TYPE(WeightProximity);
INIT_GP_TYPE(Lineart);
INIT_GP_TYPE(Dash);
+ INIT_GP_TYPE(Shrinkwrap);
#undef INIT_GP_TYPE
}
-/* verify if valid layer, material and pass index */
bool is_stroke_affected_by_modifier(Object *ob,
char *mlayername,
Material *material,
@@ -84,8 +86,8 @@ bool is_stroke_affected_by_modifier(Object *ob,
const bool inv3,
const bool inv4)
{
- Material *ma = BKE_gpencil_material(ob, gps->mat_nr + 1);
- MaterialGPencilStyle *gp_style = ma->gp_style;
+ Material *ma_gps = BKE_gpencil_material(ob, gps->mat_nr + 1);
+ MaterialGPencilStyle *gp_style = ma_gps->gp_style;
/* omit if filter by layer */
if (mlayername[0] != '\0') {
@@ -102,13 +104,16 @@ bool is_stroke_affected_by_modifier(Object *ob,
}
/* Omit if filter by material. */
if (material != NULL) {
+ /* Requires to use the original material to compare the same pointer address. */
+ Material *ma_md_orig = (Material *)DEG_get_original_id(&material->id);
+ Material *ma_gps_orig = (Material *)DEG_get_original_id(&ma_gps->id);
if (inv4 == false) {
- if (material != ma) {
+ if (ma_md_orig != ma_gps_orig) {
return false;
}
}
else {
- if (material == ma) {
+ if (ma_md_orig == ma_gps_orig) {
return false;
}
}
@@ -147,7 +152,6 @@ bool is_stroke_affected_by_modifier(Object *ob,
return true;
}
-/* verify if valid vertex group *and return weight */
float get_modifier_point_weight(MDeformVert *dvert, bool inverse, int def_nr)
{
float weight = 1.0f;
@@ -156,7 +160,7 @@ float get_modifier_point_weight(MDeformVert *dvert, bool inverse, int def_nr)
MDeformWeight *dw = BKE_defvert_find_index(dvert, def_nr);
weight = dw ? dw->weight : -1.0f;
if ((weight >= 0.0f) && (inverse)) {
- return -1.0f;
+ return 1.0f - weight;
}
if ((weight < 0.0f) && (!inverse)) {
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
index 30e54f44499..22893bdb184 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -29,17 +29,23 @@ struct Object;
struct bGPDlayer;
struct bGPDstroke;
+/**
+ * Verify if valid layer, material and pass index.
+ */
bool is_stroke_affected_by_modifier(struct Object *ob,
char *mlayername,
struct Material *material,
- const int mpassindex,
- const int gpl_passindex,
- const int minpoints,
+ int mpassindex,
+ int gpl_passindex,
+ int minpoints,
bGPDlayer *gpl,
bGPDstroke *gps,
- const bool inv1,
- const bool inv2,
- const bool inv3,
- const bool inv4);
+ bool inv1,
+ bool inv2,
+ bool inv3,
+ bool inv4);
+/**
+ * Verify if valid vertex group *and return weight.
+ */
float get_modifier_point_weight(struct MDeformVert *dvert, bool inverse, int def_nr);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
index ba33edd6a94..6a4d0de5c80 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
@@ -170,6 +170,7 @@ static bool stroke_dash(const bGPDstroke *gps,
stroke->points[is].z = p->z;
stroke->points[is].pressure = p->pressure * ds->radius;
stroke->points[is].strength = p->strength * ds->opacity;
+ copy_v4_v4(stroke->points[is].vert_color, p->vert_color);
}
BLI_addtail(r_strokes, stroke);
@@ -255,7 +256,7 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec
BKE_gpencil_frame_active_set(depsgraph, gpd);
bGPDframe *gpf = gpl->actframe;
if (gpf == NULL) {
- return;
+ continue;
}
apply_dash_for_frame(ob, gpl, gpd, gpf, (DashGpencilModifierData *)md);
}
@@ -312,8 +313,6 @@ static void panel_draw(const bContext *C, Panel *panel)
UI_TEMPLATE_LIST_FLAG_NONE);
uiLayout *col = uiLayoutColumn(row, false);
- uiLayoutSetContextPointer(col, "modifier", ptr);
-
uiLayout *sub = uiLayoutColumn(col, true);
uiItemO(sub, "", ICON_ADD, "GPENCIL_OT_segment_add");
uiItemO(sub, "", ICON_REMOVE, "GPENCIL_OT_segment_remove");
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
index 80b60547e92..af0067e06aa 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
@@ -23,8 +23,10 @@
#include <stdio.h>
+#include "BLI_hash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -56,6 +58,7 @@
#include "MOD_gpencil_util.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
static void initData(GpencilModifierData *md)
{
@@ -71,6 +74,20 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
BKE_gpencil_modifier_copydata_generic(md, target);
}
+static float *noise_table(int len, int offset, int seed)
+{
+ float *table = MEM_callocN(sizeof(float) * len, __func__);
+ for (int i = 0; i < len; i++) {
+ table[i] = BLI_hash_int_01(BLI_hash_int_2d(seed, i + offset + 1));
+ }
+ return table;
+}
+
+BLI_INLINE float table_sample(float *table, float x)
+{
+ return interpf(table[(int)ceilf(x)], table[(int)floor(x)], fractf(x));
+}
+
static bool gpencil_modify_stroke(bGPDstroke *gps,
const float length,
const float overshoot_fac,
@@ -104,9 +121,15 @@ static bool gpencil_modify_stroke(bGPDstroke *gps,
return changed;
}
-static void applyLength(LengthGpencilModifierData *lmd, bGPdata *gpd, bGPDstroke *gps)
+static void applyLength(GpencilModifierData *md,
+ Depsgraph *depsgraph,
+ bGPdata *gpd,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ Object *ob)
{
bool changed = false;
+ LengthGpencilModifierData *lmd = (LengthGpencilModifierData *)md;
const float len = (lmd->mode == GP_LENGTH_ABSOLUTE) ? 1.0f :
BKE_gpencil_stroke_length(gps, true);
const int totpoints = gps->totpoints;
@@ -120,11 +143,48 @@ static void applyLength(LengthGpencilModifierData *lmd, bGPdata *gpd, bGPDstroke
int first_mode = 1;
float second_fac = lmd->end_fac;
int second_mode = 2;
+
+ float rand[2] = {0.0f, 0.0f};
+ if (lmd->rand_start_fac != 0.0 || lmd->rand_end_fac != 0.0) {
+ int seed = lmd->seed;
+
+ /* Make sure different modifiers get different seeds. */
+ seed += BLI_hash_string(ob->id.name + 2);
+ seed += BLI_hash_string(md->name);
+
+ if (lmd->flag & GP_LENGTH_USE_RANDOM) {
+ seed += ((int)DEG_get_ctime(depsgraph)) / lmd->step;
+ }
+
+ float rand_offset = BLI_hash_int_01(seed);
+
+ /* Get stroke index for random offset. */
+ int rnd_index = BLI_findindex(&gpf->strokes, gps);
+ const uint primes[2] = {2, 3};
+ double offset[2] = {0.0f, 0.0f};
+ double r[2];
+
+ float *noise_table_length = noise_table(4, (int)floor(lmd->rand_offset), seed + 2);
+
+ /* To ensure a nice distribution, we use halton sequence and offset using the seed. */
+ BLI_halton_2d(primes, offset, rnd_index, r);
+ for (int j = 0; j < 2; j++) {
+ float noise = table_sample(noise_table_length, j * 2 + fractf(lmd->rand_offset));
+
+ rand[j] = fmodf(r[j] + rand_offset, 1.0f);
+ rand[j] = fabs(fmodf(sin(rand[j] * 12.9898f + j * 78.233f) * 43758.5453f, 1.0f) + noise);
+ }
+
+ MEM_SAFE_FREE(noise_table_length);
+
+ first_fac = first_fac + rand[0] * lmd->rand_start_fac;
+ second_fac = second_fac + rand[1] * lmd->rand_end_fac;
+ }
+
if (first_fac < 0) {
SWAP(float, first_fac, second_fac);
SWAP(int, first_mode, second_mode);
}
-
const int first_extra_point_count = ceil(first_fac * lmd->point_density);
const int second_extra_point_count = ceil(second_fac * lmd->point_density);
@@ -161,10 +221,10 @@ static void applyLength(LengthGpencilModifierData *lmd, bGPdata *gpd, bGPDstroke
}
static void deformStroke(GpencilModifierData *md,
- Depsgraph *UNUSED(depsgraph),
+ Depsgraph *depsgraph,
Object *ob,
bGPDlayer *gpl,
- bGPDframe *UNUSED(gpf),
+ bGPDframe *gpf,
bGPDstroke *gps)
{
bGPdata *gpd = ob->data;
@@ -187,7 +247,7 @@ static void deformStroke(GpencilModifierData *md,
/* Don't affect cyclic strokes as they have no start/end. */
return;
}
- applyLength(lmd, gpd, gps);
+ applyLength(md, depsgraph, gpd, gpf, gps, ob);
}
static void bakeModifier(Main *UNUSED(bmain),
@@ -214,6 +274,39 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk,
walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
}
+static void random_header_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ uiItemR(layout, ptr, "use_random", 0, IFACE_("Randomize"), ICON_NONE);
+}
+
+static void random_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ uiLayoutSetPropSep(layout, true);
+
+ uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_random"));
+
+ uiItemR(layout, ptr, "step", 0, NULL, ICON_NONE);
+}
+
+static void offset_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+ uiLayoutSetPropSep(layout, true);
+ uiItemR(layout, ptr, "random_start_factor", 0, IFACE_("Random Offset Start"), ICON_NONE);
+ uiItemR(layout, ptr, "random_end_factor", 0, IFACE_("Random Offset End"), ICON_NONE);
+ uiItemR(layout, ptr, "random_offset", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "seed", 0, NULL, ICON_NONE);
+}
+
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
@@ -277,6 +370,10 @@ static void panelRegister(ARegionType *region_type)
region_type, eGpencilModifierType_Length, panel_draw);
gpencil_modifier_subpanel_register(
region_type, "curvature", "", curvature_header_draw, curvature_panel_draw, panel_type);
+ PanelType *offset_panel = gpencil_modifier_subpanel_register(
+ region_type, "offset", "Random Offsets", NULL, offset_panel_draw, panel_type);
+ gpencil_modifier_subpanel_register(
+ region_type, "randomize", "", random_header_draw, random_panel_draw, offset_panel);
gpencil_modifier_subpanel_register(
region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type);
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
index c5ccf1d8229..6a3a27a6630 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -160,12 +160,14 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec
LineartCache *local_lc = gpd->runtime.lineart_cache;
if (!gpd->runtime.lineart_cache) {
- MOD_lineart_compute_feature_lines(depsgraph, lmd, &gpd->runtime.lineart_cache);
+ MOD_lineart_compute_feature_lines(
+ depsgraph, lmd, &gpd->runtime.lineart_cache, (!(ob->dtx & OB_DRAW_IN_FRONT)));
MOD_lineart_destroy_render_data(lmd);
}
else {
if (!(lmd->flags & LRT_GPENCIL_USE_CACHE)) {
- MOD_lineart_compute_feature_lines(depsgraph, lmd, &local_lc);
+ MOD_lineart_compute_feature_lines(
+ depsgraph, lmd, &local_lc, (!(ob->dtx & OB_DRAW_IN_FRONT)));
MOD_lineart_destroy_render_data(lmd);
}
MOD_lineart_chain_clear_picked_flag(local_lc);
@@ -210,7 +212,8 @@ static void bakeModifier(Main *UNUSED(bmain),
lmd->edge_types_override = lmd->edge_types;
lmd->level_end_override = lmd->level_end;
- MOD_lineart_compute_feature_lines(depsgraph, lmd, &gpd->runtime.lineart_cache);
+ MOD_lineart_compute_feature_lines(
+ depsgraph, lmd, &gpd->runtime.lineart_cache, (!(ob->dtx & OB_DRAW_IN_FRONT)));
MOD_lineart_destroy_render_data(lmd);
}
@@ -261,7 +264,13 @@ static void updateDepsgraph(GpencilModifierData *md,
else {
add_this_collection(ctx->scene->master_collection, ctx, mode);
}
- if (ctx->scene->camera) {
+ if (lmd->calculation_flags & LRT_USE_CUSTOM_CAMERA && lmd->source_camera) {
+ DEG_add_object_relation(
+ ctx->node, lmd->source_camera, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
+ DEG_add_object_relation(
+ ctx->node, lmd->source_camera, DEG_OB_COMP_PARAMETERS, "Line Art Modifier");
+ }
+ else if (ctx->scene->camera) {
DEG_add_object_relation(
ctx->node, ctx->scene->camera, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
DEG_add_object_relation(
@@ -277,6 +286,7 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk,
walk(userData, ob, (ID **)&lmd->source_collection, IDWALK_CB_NOP);
walk(userData, ob, (ID **)&lmd->source_object, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&lmd->source_camera, IDWALK_CB_NOP);
}
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -304,7 +314,9 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "source_object", 0, NULL, ICON_OBJECT_DATA);
}
else if (source_type == LRT_SOURCE_COLLECTION) {
- uiItemR(layout, ptr, "source_collection", 0, NULL, ICON_OUTLINER_COLLECTION);
+ uiLayout *sub = uiLayoutRow(layout, true);
+ uiItemR(sub, ptr, "source_collection", 0, NULL, ICON_OUTLINER_COLLECTION);
+ uiItemR(sub, ptr, "use_invert_collection", 0, "", ICON_ARROW_LEFTRIGHT);
}
else {
/* Source is Scene. */
@@ -378,11 +390,16 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetEnabled(layout, !is_baked);
if (use_cache && !is_first) {
- uiItemL(layout, "Cached from the first line art modifier.", ICON_INFO);
+ uiItemL(layout, TIP_("Cached from the first line art modifier"), ICON_INFO);
return;
}
- uiItemR(layout, ptr, "overscan", 0, NULL, ICON_NONE);
+ uiLayout *row = uiLayoutRowWithHeading(layout, false, IFACE_("Custom Camera"));
+ uiItemR(row, ptr, "use_custom_camera", 0, "", 0);
+ uiLayout *subrow = uiLayoutRow(row, true);
+ uiLayoutSetActive(subrow, RNA_boolean_get(ptr, "use_custom_camera"));
+ uiLayoutSetPropSep(subrow, true);
+ uiItemR(subrow, ptr, "source_camera", 0, "", ICON_OBJECT_DATA);
uiLayout *col = uiLayoutColumn(layout, true);
@@ -391,7 +408,8 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "use_object_instances", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_clip_plane_boundaries", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_crease_on_smooth", 0, IFACE_("Crease On Smooth"), ICON_NONE);
- uiItemR(layout, ptr, "use_crease_on_sharp", 0, IFACE_("Crease On Sharp"), ICON_NONE);
+ uiItemR(col, ptr, "use_crease_on_sharp", 0, IFACE_("Crease On Sharp"), ICON_NONE);
+ uiItemR(col, ptr, "use_back_face_culling", 0, NULL, ICON_NONE);
}
static void style_panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -412,14 +430,23 @@ static void style_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void occlusion_panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
- PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+ const bool use_multiple_levels = RNA_boolean_get(ptr, "use_multiple_levels");
+ const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front");
+
uiLayoutSetPropSep(layout, true);
uiLayoutSetEnabled(layout, !is_baked);
- const bool use_multiple_levels = RNA_boolean_get(ptr, "use_multiple_levels");
+ if (!show_in_front) {
+ uiItemL(layout, TIP_("Object is not in front"), ICON_INFO);
+ }
+
+ layout = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(layout, show_in_front);
uiItemR(layout, ptr, "use_multiple_levels", 0, IFACE_("Range"), ICON_NONE);
@@ -447,11 +474,14 @@ static bool anything_showing_through(PointerRNA *ptr)
static void material_mask_panel_draw_header(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
- PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
+ const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front");
+
uiLayoutSetEnabled(layout, !is_baked);
- uiLayoutSetActive(layout, anything_showing_through(ptr));
+ uiLayoutSetActive(layout, show_in_front && anything_showing_through(ptr));
uiItemR(layout, ptr, "use_material_mask", 0, IFACE_("Material Mask"), ICON_NONE);
}
@@ -541,7 +571,7 @@ static void face_mark_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetEnabled(layout, !is_baked);
if (use_cache && !is_first) {
- uiItemL(layout, "Cached from the first line art modifier.", ICON_INFO);
+ uiItemL(layout, TIP_("Cached from the first line art modifier"), ICON_INFO);
return;
}
@@ -551,6 +581,7 @@ static void face_mark_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "use_face_mark_invert", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "use_face_mark_boundaries", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_face_mark_keep_contour", 0, NULL, ICON_NONE);
}
static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -569,7 +600,7 @@ static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetEnabled(layout, !is_baked);
if (use_cache && !is_first) {
- uiItemL(layout, "Cached from the first line art modifier.", ICON_INFO);
+ uiItemL(layout, TIP_("Cached from the first line art modifier"), ICON_INFO);
return;
}
@@ -578,6 +609,7 @@ static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "use_fuzzy_all", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_loose_edge_chain", 0, IFACE_("Loose Edges"), ICON_NONE);
uiItemR(col, ptr, "use_loose_as_contour", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_detail_preserve", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_geometry_space_chain", 0, IFACE_("Geometry Space"), ICON_NONE);
uiItemR(layout,
@@ -606,7 +638,7 @@ static void vgroup_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetEnabled(layout, !is_baked);
if (use_cache && !is_first) {
- uiItemL(layout, "Cached from the first line art modifier.", ICON_INFO);
+ uiItemL(layout, TIP_("Cached from the first line art modifier"), ICON_INFO);
return;
}
@@ -639,7 +671,7 @@ static void bake_panel_draw(const bContext *UNUSED(C), Panel *panel)
if (is_baked) {
uiLayout *col = uiLayoutColumn(layout, false);
uiLayoutSetPropSep(col, false);
- uiItemL(col, IFACE_("Modifier has baked data"), ICON_NONE);
+ uiItemL(col, TIP_("Modifier has baked data"), ICON_NONE);
uiItemR(
col, ptr, "is_baked", UI_ITEM_R_TOGGLE, IFACE_("Continue Without Clearing"), ICON_NONE);
}
@@ -654,6 +686,32 @@ static void bake_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemO(col, NULL, ICON_NONE, "OBJECT_OT_lineart_clear_all");
}
+static void composition_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ uiLayout *layout = panel->layout;
+
+ const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front");
+
+ uiLayoutSetPropSep(layout, true);
+
+ uiItemR(layout, ptr, "overscan", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_image_boundary_trimming", 0, NULL, ICON_NONE);
+
+ if (show_in_front) {
+ uiItemL(layout, TIP_("Object is shown in front"), ICON_ERROR);
+ }
+
+ uiLayout *col = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(col, !show_in_front);
+
+ uiItemR(col, ptr, "stroke_depth_offset", UI_ITEM_R_SLIDER, IFACE_("Depth Offset"), ICON_NONE);
+ uiItemR(
+ col, ptr, "use_offset_towards_custom_camera", 0, IFACE_("Towards Custom Camera"), ICON_NONE);
+}
+
static void panelRegister(ARegionType *region_type)
{
PanelType *panel_type = gpencil_modifier_panel_register(
@@ -682,6 +740,8 @@ static void panelRegister(ARegionType *region_type)
gpencil_modifier_subpanel_register(
region_type, "vgroup", "Vertex Weight Transfer", NULL, vgroup_panel_draw, panel_type);
gpencil_modifier_subpanel_register(
+ region_type, "composition", "Composition", NULL, composition_panel_draw, panel_type);
+ gpencil_modifier_subpanel_register(
region_type, "bake", "Bake", NULL, bake_panel_draw, panel_type);
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
index fb75b1e99ac..2e55369ea97 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
@@ -240,10 +240,10 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "hardness", 0, NULL, ICON_NONE);
}
else {
- const bool is_normalized = RNA_boolean_get(ptr, "normalize_opacity");
+ const bool is_normalized = RNA_boolean_get(ptr, "use_normalized_opacity");
const bool is_weighted = RNA_boolean_get(ptr, "use_weight_factor");
- uiItemR(layout, ptr, "normalize_opacity", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_normalized_opacity", 0, NULL, ICON_NONE);
const char *text = (is_normalized) ? IFACE_("Strength") : IFACE_("Opacity Factor");
uiLayout *row = uiLayoutRow(layout, true);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
new file mode 100644
index 00000000000..6990b41e6ce
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
@@ -0,0 +1,350 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+#include <string.h> /* For #MEMCPY_STRUCT_AFTER. */
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_defaults.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_shrinkwrap.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+#include "MOD_gpencil_ui_common.h"
+#include "MOD_gpencil_util.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+static void initData(GpencilModifierData *md)
+{
+ ShrinkwrapGpencilModifierData *gpmd = (ShrinkwrapGpencilModifierData *)md;
+
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
+
+ MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(ShrinkwrapGpencilModifierData), modifier);
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copydata_generic(md, target);
+}
+
+static void deformStroke(GpencilModifierData *md,
+ Depsgraph *UNUSED(depsgraph),
+ Object *ob,
+ bGPDlayer *gpl,
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps)
+{
+ bGPdata *gpd = ob->data;
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername,
+ mmd->material,
+ mmd->pass_index,
+ mmd->layer_pass,
+ 1,
+ gpl,
+ gps,
+ mmd->flag & GP_SHRINKWRAP_INVERT_LAYER,
+ mmd->flag & GP_SHRINKWRAP_INVERT_PASS,
+ mmd->flag & GP_SHRINKWRAP_INVERT_LAYERPASS,
+ mmd->flag & GP_SHRINKWRAP_INVERT_MATERIAL)) {
+ return;
+ }
+
+ if ((mmd->cache_data == NULL) || (mmd->target == ob) || (mmd->aux_target == ob)) {
+ return;
+ }
+
+ bGPDspoint *pt = gps->points;
+ float(*vert_coords)[3] = MEM_mallocN(sizeof(float[3]) * gps->totpoints, __func__);
+ int i;
+ /* Prepare array of points. */
+ for (i = 0; i < gps->totpoints; i++, pt++) {
+ copy_v3_v3(vert_coords[i], &pt->x);
+ }
+
+ shrinkwrapGpencilModifier_deform(mmd, ob, gps->dvert, def_nr, vert_coords, gps->totpoints);
+
+ /* Apply deformed coordinates. */
+ pt = gps->points;
+ for (i = 0; i < gps->totpoints; i++, pt++) {
+ copy_v3_v3(&pt->x, vert_coords[i]);
+ /* Smooth stroke. */
+ if (mmd->smooth_factor > 0.0f) {
+ for (int r = 0; r < mmd->smooth_step; r++) {
+ BKE_gpencil_stroke_smooth_point(gps, i, mmd->smooth_factor, true);
+ }
+ }
+ }
+
+ MEM_freeN(vert_coords);
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+}
+
+static void bakeModifier(Main *UNUSED(bmain),
+ Depsgraph *depsgraph,
+ GpencilModifierData *md,
+ Object *ob)
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = ob->data;
+ int oldframe = (int)DEG_get_ctime(depsgraph);
+
+ if ((mmd->target == ob) || (mmd->aux_target == ob)) {
+ return;
+ }
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ /* Apply shrinkwrap effects on this frame. */
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph);
+
+ /* Recalculate shrinkwrap data. */
+ if (mmd->cache_data) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ Object *ob_target = DEG_get_evaluated_object(depsgraph, mmd->target);
+ Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
+ mmd->cache_data = MEM_callocN(sizeof(ShrinkwrapTreeData), __func__);
+ if (BKE_shrinkwrap_init_tree(
+ mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false)) {
+
+ /* Compute shrinkwrap effects on this frame. */
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ deformStroke(md, depsgraph, ob, gpl, gpf, gps);
+ }
+ }
+ /* Free data. */
+ if (mmd->cache_data) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ }
+ }
+
+ /* Return frame state and DB to original state. */
+ CFRA = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph);
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ if (mmd->cache_data) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+}
+
+static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+
+ /* The object type check is only needed here in case we have a placeholder
+ * object assigned (because the library containing the mesh is missing).
+ *
+ * In other cases it should be impossible to have a type mismatch.
+ */
+ if (!mmd->target || mmd->target->type != OB_MESH) {
+ return true;
+ }
+ if (mmd->aux_target && mmd->aux_target->type != OB_MESH) {
+ return true;
+ }
+ return false;
+}
+
+static void updateDepsgraph(GpencilModifierData *md,
+ const ModifierUpdateDepsgraphContext *ctx,
+ const int UNUSED(mode))
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ CustomData_MeshMasks mask = {0};
+
+ if (BKE_shrinkwrap_needs_normals(mmd->shrink_type, mmd->shrink_mode)) {
+ mask.vmask |= CD_MASK_NORMAL;
+ mask.lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
+ }
+
+ if (mmd->target != NULL) {
+ DEG_add_object_relation(ctx->node, mmd->target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
+ DEG_add_object_relation(ctx->node, mmd->target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ DEG_add_customdata_mask(ctx->node, mmd->target, &mask);
+ if (mmd->shrink_type == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ DEG_add_special_eval_flag(ctx->node, &mmd->target->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY);
+ }
+ }
+ if (mmd->aux_target != NULL) {
+ DEG_add_object_relation(
+ ctx->node, mmd->aux_target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
+ DEG_add_object_relation(
+ ctx->node, mmd->aux_target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ DEG_add_customdata_mask(ctx->node, mmd->aux_target, &mask);
+ if (mmd->shrink_type == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ DEG_add_special_eval_flag(
+ ctx->node, &mmd->aux_target->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY);
+ }
+ }
+ DEG_add_modifier_to_transform_relation(ctx->node, "Shrinkwrap Modifier");
+}
+
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->target, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&mmd->aux_target, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+}
+
+static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *row, *col;
+ uiLayout *layout = panel->layout;
+ int toggles_flag = UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE;
+
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ uiLayoutSetPropSep(layout, true);
+
+ int wrap_method = RNA_enum_get(ptr, "wrap_method");
+
+ uiItemR(layout, ptr, "wrap_method", 0, NULL, ICON_NONE);
+
+ if (ELEM(wrap_method,
+ MOD_SHRINKWRAP_PROJECT,
+ MOD_SHRINKWRAP_NEAREST_SURFACE,
+ MOD_SHRINKWRAP_TARGET_PROJECT)) {
+ uiItemR(layout, ptr, "wrap_mode", 0, NULL, ICON_NONE);
+ }
+
+ if (wrap_method == MOD_SHRINKWRAP_PROJECT) {
+ uiItemR(layout, ptr, "project_limit", 0, IFACE_("Limit"), ICON_NONE);
+ uiItemR(layout, ptr, "subsurf_levels", 0, NULL, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ row = uiLayoutRowWithHeading(col, true, IFACE_("Axis"));
+ uiItemR(row, ptr, "use_project_x", toggles_flag, NULL, ICON_NONE);
+ uiItemR(row, ptr, "use_project_y", toggles_flag, NULL, ICON_NONE);
+ uiItemR(row, ptr, "use_project_z", toggles_flag, NULL, ICON_NONE);
+
+ uiItemR(col, ptr, "use_negative_direction", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_positive_direction", 0, NULL, ICON_NONE);
+
+ uiItemR(layout, ptr, "cull_face", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ col = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(col,
+ RNA_boolean_get(ptr, "use_negative_direction") &&
+ RNA_enum_get(ptr, "cull_face") != 0);
+ uiItemR(col, ptr, "use_invert_cull", 0, NULL, ICON_NONE);
+ }
+
+ uiItemR(layout, ptr, "target", 0, NULL, ICON_NONE);
+ if (wrap_method == MOD_SHRINKWRAP_PROJECT) {
+ uiItemR(layout, ptr, "auxiliary_target", 0, NULL, ICON_NONE);
+ }
+ uiItemR(layout, ptr, "offset", 0, NULL, ICON_NONE);
+
+ uiLayoutSetPropSep(layout, true);
+
+ uiItemR(layout, ptr, "smooth_factor", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "smooth_step", 0, IFACE_("Repeat"), ICON_NONE);
+
+ gpencil_modifier_panel_end(layout, ptr);
+}
+
+static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ gpencil_modifier_masking_panel_draw(panel, true, true);
+}
+
+static void panelRegister(ARegionType *region_type)
+{
+ PanelType *panel_type = gpencil_modifier_panel_register(
+ region_type, eGpencilModifierType_Shrinkwrap, panel_draw);
+ gpencil_modifier_subpanel_register(
+ region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Shrinkwrap = {
+ /* name */ "Shrinkwrap",
+ /* structName */ "ShrinkwrapGpencilModifierData",
+ /* structSize */ sizeof(ShrinkwrapGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachIDLink */ foreachIDLink,
+ /* foreachTexLink */ NULL,
+ /* panelRegister */ panelRegister,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
index b00db1ba2d2..a63cbb53645 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
@@ -132,7 +132,7 @@ static void deformStroke(GpencilModifierData *md,
const float val = mmd->factor * weight;
/* perform smoothing */
if (mmd->flag & GP_SMOOTH_MOD_LOCATION) {
- BKE_gpencil_stroke_smooth_point(gps, i, val);
+ BKE_gpencil_stroke_smooth_point(gps, i, val, false);
}
if (mmd->flag & GP_SMOOTH_MOD_STRENGTH) {
BKE_gpencil_stroke_smooth_strength(gps, i, val);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
index cac700e15f4..233992bbd31 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
@@ -191,8 +191,8 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetPropSep(layout, true);
- uiItemR(layout, ptr, "normalize_thickness", 0, NULL, ICON_NONE);
- if (RNA_boolean_get(ptr, "normalize_thickness")) {
+ uiItemR(layout, ptr, "use_normalized_thickness", 0, NULL, ICON_NONE);
+ if (RNA_boolean_get(ptr, "use_normalized_thickness")) {
uiItemR(layout, ptr, "thickness", 0, NULL, ICON_NONE);
}
else {
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index c00f34185dd..cb17d1d5f1a 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -182,9 +182,9 @@ typedef struct LineartEdgeChain {
typedef struct LineartEdgeChainItem {
struct LineartEdgeChainItem *next, *prev;
- /** Need z value for fading */
- float pos[3];
- /** For restoring position to 3d space */
+ /** Need z value for fading, w value for image frame clipping. */
+ float pos[4];
+ /** For restoring position to 3d space. */
float gpos[3];
float normal[3];
unsigned char line_type;
@@ -299,18 +299,24 @@ typedef struct LineartRenderBuffer {
bool use_loose_as_contour;
bool use_loose_edge_chain;
bool use_geometry_space_chain;
+ bool use_image_boundary_trimming;
+ bool use_back_face_culling;
bool filter_face_mark;
bool filter_face_mark_invert;
bool filter_face_mark_boundaries;
+ bool filter_face_mark_keep_contour;
bool force_crease;
bool sharp_as_crease;
+ bool chain_preserve_details;
+
/* Keep an copy of these data so when line art is running it's self-contained. */
bool cam_is_persp;
float cam_obmat[4][4];
double camera_pos[3];
+ double active_camera_pos[3]; /* Stroke offset calculation may use active or selected camera. */
double near_clip, far_clip;
float shift_x, shift_y;
float crease_threshold;
@@ -448,10 +454,10 @@ typedef struct LineartBoundingArea {
ListBase up;
ListBase bp;
- int16_t triangle_count;
- int16_t max_triangle_count;
- int16_t line_count;
- int16_t max_line_count;
+ uint16_t triangle_count;
+ uint16_t max_triangle_count;
+ uint16_t line_count;
+ uint16_t max_line_count;
/* Use array for speeding up multiple accesses. */
struct LineartTriangle **linked_triangles;
@@ -474,11 +480,32 @@ typedef struct LineartBoundingArea {
#define LRT_MIN3_INDEX_ABC(x, y, z) (x < y ? (x < z ? a : (y < z ? b : c)) : (y < z ? b : c))
#define LRT_ABC(index) (index == 0 ? a : (index == 1 ? b : c))
+#define LRT_PABC(index) (index == 0 ? pa : (index == 1 ? pb : pc))
+#define DBL_LOOSER 1e-5
+#define LRT_DOUBLE_CLOSE_LOOSER(a, b) (((a) + DBL_LOOSER) >= (b) && ((a)-DBL_LOOSER) <= (b))
#define LRT_DOUBLE_CLOSE_ENOUGH(a, b) (((a) + DBL_EDGE_LIM) >= (b) && ((a)-DBL_EDGE_LIM) <= (b))
+#define LRT_DOUBLE_CLOSE_ENOUGH_TRI(a, b) \
+ (((a) + DBL_TRIANGLE_LIM) >= (b) && ((a)-DBL_TRIANGLE_LIM) <= (b))
-BLI_INLINE int lineart_LineIntersectTest2d(
- const double *a1, const double *a2, const double *b1, const double *b2, double *aRatio)
+/* Notes on this function:
+ *
+ * r_ratio: The ratio on segment a1-a2. When r_ratio is very close to zero or one, it
+ * fixes the value to zero or one, this makes it easier to identify "on the tip" situations.
+ *
+ * r_aligned: True when 1) a and b is exactly on the same straight line and 2) a and b share a
+ * common end-point.
+ *
+ * Important: if r_aligned is true, r_ratio will be either 0 or 1 depending on which point from
+ * segment a is shared with segment b. If it's a1 then r_ratio is 0, else then r_ratio is 1. This
+ * extra information is needed for line art occlusion stage to work correctly in such cases.
+ */
+BLI_INLINE int lineart_intersect_seg_seg(const double *a1,
+ const double *a2,
+ const double *b1,
+ const double *b2,
+ double *r_ratio,
+ bool *r_aligned)
{
/* Legacy intersection math aligns better with occlusion function quirks. */
/* #define USE_VECTOR_LINE_INTERSECTION */
@@ -502,27 +529,27 @@ BLI_INLINE int lineart_LineIntersectTest2d(
double rr;
if (fabs(a2[0] - a1[0]) > fabs(a2[1] - a1[1])) {
- *aRatio = ratiod(a1[0], a2[0], rx);
+ *r_ratio = ratiod(a1[0], a2[0], rx);
if (fabs(b2[0] - b1[0]) > fabs(b2[1] - b1[1])) {
rr = ratiod(b1[0], b2[0], rx);
}
else {
rr = ratiod(b1[1], b2[1], ry);
}
- if ((*aRatio) > 0 && (*aRatio) < 1 && rr > 0 && rr < 1) {
+ if ((*r_ratio) > 0 && (*r_ratio) < 1 && rr > 0 && rr < 1) {
return 1;
}
return 0;
}
- *aRatio = ratiod(a1[1], a2[1], ry);
+ *r_ratio = ratiod(a1[1], a2[1], ry);
if (fabs(b2[0] - b1[0]) > fabs(b2[1] - b1[1])) {
rr = ratiod(b1[0], b2[0], rx);
}
else {
rr = ratiod(b1[1], b2[1], ry);
}
- if ((*aRatio) > 0 && (*aRatio) < 1 && rr > 0 && rr < 1) {
+ if ((*r_ratio) > 0 && (*r_ratio) < 1 && rr > 0 && rr < 1) {
return 1;
}
return 0;
@@ -537,34 +564,62 @@ BLI_INLINE int lineart_LineIntersectTest2d(
double x_diff = (a2[0] - a1[0]);
double x_diff2 = (b2[0] - b1[0]);
+ *r_aligned = false;
+
if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff, 0)) {
if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff2, 0)) {
- *aRatio = 0;
+ /* This means two segments are both vertical. */
+ if ((LRT_DOUBLE_CLOSE_ENOUGH(a2[0], b1[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a2[1], b1[1])) ||
+ (LRT_DOUBLE_CLOSE_ENOUGH(a2[0], b2[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a2[1], b2[1]))) {
+ *r_aligned = true;
+ *r_ratio = 1;
+ }
+ else if ((LRT_DOUBLE_CLOSE_ENOUGH(a1[0], b1[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a1[1], b1[1])) ||
+ (LRT_DOUBLE_CLOSE_ENOUGH(a1[0], b2[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a1[1], b2[1]))) {
+ *r_aligned = true;
+ *r_ratio = 0;
+ }
return 0;
}
double r2 = ratiod(b1[0], b2[0], a1[0]);
x = interpd(b2[0], b1[0], r2);
y = interpd(b2[1], b1[1], r2);
- *aRatio = ratio = ratiod(a1[1], a2[1], y);
+ *r_ratio = ratio = ratiod(a1[1], a2[1], y);
}
else {
if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff2, 0)) {
ratio = ratiod(a1[0], a2[0], b1[0]);
x = interpd(a2[0], a1[0], ratio);
- *aRatio = ratio;
+ *r_ratio = ratio;
}
else {
- k1 = (a2[1] - a1[1]) / x_diff;
- k2 = (b2[1] - b1[1]) / x_diff2;
-
- if (k1 == k2)
+ double y_diff = a2[1] - a1[1], y_diff2 = b2[1] - b1[1];
+ k1 = y_diff / x_diff;
+ k2 = y_diff2 / x_diff2;
+
+ if (LRT_DOUBLE_CLOSE_ENOUGH_TRI(k2, k1)) {
+ /* This means two segments are parallel. This also handles k==0 (both completely
+ * horizontal) cases. */
+ if ((LRT_DOUBLE_CLOSE_ENOUGH(a2[0], b1[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a2[1], b1[1])) ||
+ (LRT_DOUBLE_CLOSE_ENOUGH(a2[0], b2[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a2[1], b2[1]))) {
+ *r_aligned = true;
+ *r_ratio = 1;
+ }
+ else if ((LRT_DOUBLE_CLOSE_ENOUGH(a1[0], b1[0]) &&
+ LRT_DOUBLE_CLOSE_ENOUGH(a1[1], b1[1])) ||
+ (LRT_DOUBLE_CLOSE_ENOUGH(a1[0], b2[0]) &&
+ LRT_DOUBLE_CLOSE_ENOUGH(a1[1], b2[1]))) {
+ *r_aligned = true;
+ *r_ratio = 0;
+ }
return 0;
+ }
x = (a1[1] - b1[1] - k1 * a1[0] + k2 * b1[0]) / (k2 - k1);
ratio = (x - a1[0]) / x_diff;
- *aRatio = ratio;
+ *r_ratio = ratio;
}
}
@@ -578,6 +633,13 @@ BLI_INLINE int lineart_LineIntersectTest2d(
(b2[0] < b1[0] && x < b2[0]))
return 0;
+ if (LRT_DOUBLE_CLOSE_ENOUGH_TRI(*r_ratio, 1)) {
+ *r_ratio = 1;
+ }
+ else if (LRT_DOUBLE_CLOSE_ENOUGH_TRI(*r_ratio, 0)) {
+ *r_ratio = 0;
+ }
+
return 1;
#endif
}
@@ -591,29 +653,57 @@ void MOD_lineart_destroy_render_data(struct LineartGpencilModifierData *lmd);
void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb);
void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb);
+/**
+ * This function only connects two different chains. It will not do any clean up or smart chaining.
+ * So no: removing overlapping chains, removal of short isolated segments, and no loop reduction is
+ * implemented yet.
+ */
void MOD_lineart_chain_connect(LineartRenderBuffer *rb);
-void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold);
+void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, float threshold);
+void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb);
+/**
+ * This should always be the last stage!, see the end of
+ * #MOD_lineart_chain_split_for_fixed_occlusion().
+ */
void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad);
void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance);
+void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
+ float dist,
+ bool use_custom_camera);
int MOD_lineart_chain_count(const LineartEdgeChain *ec);
void MOD_lineart_chain_clear_picked_flag(LineartCache *lc);
+/**
+ * This is the entry point of all line art calculations.
+ *
+ * \return True when a change is made.
+ */
bool MOD_lineart_compute_feature_lines(struct Depsgraph *depsgraph,
struct LineartGpencilModifierData *lmd,
- LineartCache **cached_result);
+ struct LineartCache **cached_result,
+ bool enable_stroke_offset);
struct Scene;
+/**
+ * This only gets initial "biggest" tile.
+ */
LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb,
double x,
double y);
+/**
+ * Wrapper for more convenience.
+ */
LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y);
struct bGPDframe;
struct bGPDlayer;
+/**
+ * Wrapper for external calls.
+ */
void MOD_lineart_gpencil_generate(LineartCache *cache,
struct Depsgraph *depsgraph,
struct Object *ob,
@@ -634,6 +724,9 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
const char *vgname,
int modifier_flags);
+/**
+ * Length is in image space.
+ */
float MOD_lineart_chain_compute_length(LineartEdgeChain *ec);
void ED_operatortypes_lineart(void);
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
index 8935bdd1870..78ad895c93e 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -126,7 +126,7 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb,
eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem));
- copy_v2_v2(eci->pos, fbcoord);
+ copy_v4_v4(eci->pos, fbcoord);
copy_v3_v3(eci->gpos, gpos);
eci->index = index;
copy_v3_v3(eci->normal, normal);
@@ -156,7 +156,7 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb
eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem));
- copy_v2_v2(eci->pos, fbcoord);
+ copy_v4_v4(eci->pos, fbcoord);
copy_v3_v3(eci->gpos, gpos);
eci->index = index;
copy_v3_v3(eci->normal, normal);
@@ -177,15 +177,15 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
int last_occlusion;
unsigned char last_transparency;
/* Used when converting from double. */
- float use_fbcoord[2];
+ float use_fbcoord[4];
float use_gpos[3];
#define VERT_COORD_TO_FLOAT(a) \
- copy_v2fl_v2db(use_fbcoord, (a)->fbcoord); \
+ copy_v4fl_v4db(use_fbcoord, (a)->fbcoord); \
copy_v3fl_v3db(use_gpos, (a)->gloc);
#define POS_TO_FLOAT(lpos, gpos) \
- copy_v2fl_v2db(use_fbcoord, lpos); \
+ copy_v3fl_v3db(use_fbcoord, lpos); \
copy_v3fl_v3db(use_gpos, gpos);
LRT_ITER_ALL_LINES_BEGIN
@@ -262,6 +262,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at);
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
+ use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
lineart_chain_prepend_point(rb,
ec,
@@ -287,6 +288,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at);
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
+ use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
lineart_chain_prepend_point(rb,
ec,
@@ -340,6 +342,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
interp_v3_v3v3_db(lpos, e->v1->fbcoord, e->v2->fbcoord, es->at);
interp_v3_v3v3_db(gpos, e->v1->gloc, e->v2->gloc, global_at);
+ use_fbcoord[3] = interpf(e->v2->fbcoord[3], e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
lineart_chain_append_point(rb,
ec,
@@ -403,6 +406,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at);
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
+ use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
last_occlusion = es->prev ? es->prev->occlusion : last_occlusion;
last_transparency = es->prev ? es->prev->material_mask_bits : last_transparency;
POS_TO_FLOAT(lpos, gpos)
@@ -430,6 +434,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at);
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
+ use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
POS_TO_FLOAT(lpos, gpos)
lineart_chain_append_point(rb,
ec,
@@ -566,6 +571,57 @@ static void lineart_bounding_area_link_chain(LineartRenderBuffer *rb, LineartEdg
}
}
+static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec,
+ LineartEdgeChainItem *last_matching_eci,
+ float distance_threshold,
+ bool preserve_details,
+ LineartEdgeChainItem **r_next_eci)
+{
+ float dist_accum = 0;
+
+ int fixed_occ = last_matching_eci->occlusion;
+ unsigned char fixed_mask = last_matching_eci->material_mask_bits;
+
+ LineartEdgeChainItem *can_skip_to = NULL;
+ LineartEdgeChainItem *last_eci = last_matching_eci;
+ for (LineartEdgeChainItem *eci = last_matching_eci->next; eci; eci = eci->next) {
+ dist_accum += len_v2v2(last_eci->pos, eci->pos);
+ if (dist_accum > distance_threshold) {
+ break;
+ }
+ last_eci = eci;
+ /* The reason for this is because we don't want visible segments to be "skipped" into
+ * connecting with invisible segments. */
+ if (eci->occlusion < fixed_occ) {
+ break;
+ }
+ if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) {
+ can_skip_to = eci;
+ }
+ }
+ if (can_skip_to) {
+ /* Either mark all in-between segments with the same occlusion and mask or delete those
+ * different ones. */
+ LineartEdgeChainItem *next_eci;
+ for (LineartEdgeChainItem *eci = last_matching_eci->next; eci != can_skip_to; eci = next_eci) {
+ next_eci = eci->next;
+ if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) {
+ continue;
+ }
+ if (preserve_details) {
+ eci->material_mask_bits = fixed_mask;
+ eci->occlusion = fixed_occ;
+ }
+ else {
+ BLI_remlink(&ec->chain, eci);
+ }
+ }
+ *r_next_eci = can_skip_to;
+ return true;
+ }
+ return false;
+}
+
void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
{
LineartEdgeChain *ec, *new_ec;
@@ -592,6 +648,13 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
if (lineart_point_overlapping(next_eci, eci->pos[0], eci->pos[1], 1e-5)) {
continue;
}
+ if (lineart_chain_fix_ambiguous_segments(ec,
+ eci->prev,
+ rb->chaining_image_threshold,
+ rb->chain_preserve_details,
+ &next_eci)) {
+ continue;
+ }
}
else {
/* Set the same occlusion level for the end vertex, so when further connection is needed
@@ -629,6 +692,8 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
}
}
}
+ /* Get rid of those very short "zig-zag" lines that jumps around visibility. */
+ MOD_lineart_chain_discard_short(rb, DBL_EDGE_LIM);
LISTBASE_FOREACH (LineartEdgeChain *, iec, &rb->chains) {
lineart_bounding_area_link_chain(rb, iec);
}
@@ -787,11 +852,6 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
return closest_cre;
}
-/**
- * This function only connects two different chains. It will not do any clean up or smart chaining.
- * So no: removing overlapping chains, removal of short isolated segments, and no loop reduction is
- * implemented yet.
- */
void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
{
LineartEdgeChain *ec;
@@ -874,9 +934,6 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
}
}
-/**
- * Length is in image space.
- */
float MOD_lineart_chain_compute_length(LineartEdgeChain *ec)
{
LineartEdgeChainItem *eci;
@@ -885,6 +942,9 @@ float MOD_lineart_chain_compute_length(LineartEdgeChain *ec)
float last_point[2];
eci = ec->chain.first;
+ if (!eci) {
+ return 0;
+ }
copy_v2_v2(last_point, eci->pos);
for (eci = ec->chain.first; eci; eci = eci->next) {
dist = len_v2v2(eci->pos, last_point);
@@ -926,9 +986,9 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc)
void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
{
- LISTBASE_FOREACH (LineartEdgeChain *, rlc, &rb->chains) {
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
LineartEdgeChainItem *next_eci;
- for (LineartEdgeChainItem *eci = rlc->chain.first; eci; eci = next_eci) {
+ for (LineartEdgeChainItem *eci = ec->chain.first; eci; eci = next_eci) {
next_eci = eci->next;
LineartEdgeChainItem *eci2, *eci3, *eci4;
@@ -944,7 +1004,7 @@ void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
if (dist_to_line_segment_v2(eci3->pos, eci->pos, eci2->pos) < tolerance) {
/* And if p4 is on the extension of p1-p2 , we remove p3. */
if ((eci4 = eci3->next) && (dist_to_line_v2(eci4->pos, eci->pos, eci2->pos) < tolerance)) {
- BLI_remlink(&rlc->chain, eci3);
+ BLI_remlink(&ec->chain, eci3);
next_eci = eci;
}
}
@@ -952,10 +1012,116 @@ void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
}
}
-/**
- * This should always be the last stage!, see the end of
- * #MOD_lineart_chain_split_for_fixed_occlusion().
- */
+static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBuffer *rb,
+ LineartEdgeChainItem *eci_inside,
+ LineartEdgeChainItem *eci_outside)
+{
+ float isec[2];
+ float LU[2] = {-1.0f, 1.0f}, LB[2] = {-1.0f, -1.0f}, RU[2] = {1.0f, 1.0f}, RB[2] = {1.0f, -1.0f};
+ bool found = false;
+ LineartEdgeChainItem *eci2 = eci_outside, *eci1 = eci_inside;
+ if (eci2->pos[0] < -1.0f) {
+ found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LU, LB, isec) > 0);
+ }
+ if (!found && eci2->pos[0] > 1.0f) {
+ found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, RU, RB, isec) > 0);
+ }
+ if (!found && eci2->pos[1] < -1.0f) {
+ found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LB, RB, isec) > 0);
+ }
+ if (!found && eci2->pos[1] > 1.0f) {
+ found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LU, RU, isec) > 0);
+ }
+
+ if (UNLIKELY(!found)) {
+ return NULL;
+ }
+
+ float ratio = (fabs(eci2->pos[0] - eci1->pos[0]) > fabs(eci2->pos[1] - eci1->pos[1])) ?
+ ratiof(eci1->pos[0], eci2->pos[0], isec[0]) :
+ ratiof(eci1->pos[1], eci2->pos[1], isec[1]);
+ float gratio = eci1->pos[3] * ratio / (ratio * eci1->pos[3] + (1 - ratio) * eci2->pos[3]);
+
+ LineartEdgeChainItem *eci = lineart_mem_acquire(rb->chain_data_pool,
+ sizeof(LineartEdgeChainItem));
+ memcpy(eci, eci1, sizeof(LineartEdgeChainItem));
+ interp_v3_v3v3(eci->gpos, eci1->gpos, eci2->gpos, gratio);
+ interp_v3_v3v3(eci->pos, eci1->pos, eci2->pos, ratio);
+ eci->pos[3] = interpf(eci2->pos[3], eci1->pos[3], gratio);
+ eci->next = eci->prev = NULL;
+ return eci;
+}
+
+#define LRT_ECI_INSIDE(eci) \
+ ((eci)->pos[0] >= -1.0f && (eci)->pos[0] <= 1.0f && (eci)->pos[1] >= -1.0f && \
+ (eci)->pos[1] <= 1.0f)
+
+void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
+{
+ LineartEdgeChain *ec;
+ LineartEdgeChainItem *eci, *next_eci, *prev_eci, *new_eci;
+ bool is_inside, new_inside;
+ ListBase swap = {0};
+ swap.first = rb->chains.first;
+ swap.last = rb->chains.last;
+
+ rb->chains.last = rb->chains.first = NULL;
+ while ((ec = BLI_pophead(&swap)) != NULL) {
+ bool ec_added = false;
+ LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
+ is_inside = LRT_ECI_INSIDE(first_eci) ? true : false;
+ if (!is_inside) {
+ ec->picked = true;
+ }
+ for (eci = first_eci->next; eci; eci = next_eci) {
+ next_eci = eci->next;
+ prev_eci = eci->prev;
+
+ /* We only need to do something if the edge crossed from outside to the inside or from inside
+ * to the outside. */
+ if ((new_inside = LRT_ECI_INSIDE(eci)) != is_inside) {
+ if (new_inside == false) {
+ /* Stroke goes out. */
+ new_eci = lineart_chain_create_crossing_point(rb, prev_eci, eci);
+
+ LineartEdgeChain *new_ec = lineart_mem_acquire(rb->chain_data_pool,
+ sizeof(LineartEdgeChain));
+ memcpy(new_ec, ec, sizeof(LineartEdgeChain));
+ new_ec->chain.first = next_eci;
+ eci->prev = NULL;
+ prev_eci->next = NULL;
+ ec->chain.last = prev_eci;
+ BLI_addtail(&ec->chain, new_eci);
+ BLI_addtail(&rb->chains, ec);
+ ec_added = true;
+ ec = new_ec;
+
+ next_eci = eci->next;
+ is_inside = new_inside;
+ continue;
+ }
+ /* Stroke comes in. */
+ new_eci = lineart_chain_create_crossing_point(rb, eci, prev_eci);
+
+ ec->chain.first = eci;
+ eci->prev = NULL;
+
+ BLI_addhead(&ec->chain, new_eci);
+
+ ec_added = false;
+
+ next_eci = eci->next;
+ is_inside = new_inside;
+ continue;
+ }
+ }
+
+ if ((!ec_added) && is_inside) {
+ BLI_addtail(&rb->chains, ec);
+ }
+ }
+}
+
void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad)
{
LineartEdgeChain *ec, *new_ec;
@@ -1008,3 +1174,45 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
}
}
}
+
+void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
+ float dist,
+ bool use_custom_camera)
+{
+ float dir[3];
+ float cam[3];
+ float view[3];
+ float view_clamp[3];
+ copy_v3fl_v3db(cam, rb->camera_pos);
+ copy_v3fl_v3db(view, rb->view_vector);
+
+ if (use_custom_camera) {
+ copy_v3fl_v3db(cam, rb->camera_pos);
+ }
+ else {
+ copy_v3fl_v3db(cam, rb->active_camera_pos);
+ }
+
+ if (rb->cam_is_persp) {
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
+ LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
+ sub_v3_v3v3(dir, cam, eci->gpos);
+ float orig_len = len_v3(dir);
+ normalize_v3(dir);
+ mul_v3_fl(dir, MIN2(dist, orig_len - rb->near_clip));
+ add_v3_v3(eci->gpos, dir);
+ }
+ }
+ }
+ else {
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
+ LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
+ sub_v3_v3v3(dir, cam, eci->gpos);
+ float len_lim = dot_v3v3(view, dir) - rb->near_clip;
+ normalize_v3_v3(view_clamp, view);
+ mul_v3_fl(view_clamp, MIN2(dist, len_lim));
+ add_v3_v3(eci->gpos, view_clamp);
+ }
+ }
+ }
+}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index 5b878a4326f..5434f7768b2 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -327,7 +327,12 @@ BLI_INLINE bool lineart_occlusion_is_adjacent_intersection(LineartEdge *e, Linea
static void lineart_bounding_area_triangle_add(LineartRenderBuffer *rb,
LineartBoundingArea *ba,
LineartTriangle *tri)
-{
+{ /* In case of too many triangles concentrating in one point, do not add anymore, these triangles
+ * will be either narrower than a single pixel, or will still be added into the list of other
+ * less dense areas. */
+ if (ba->triangle_count >= 65535) {
+ return;
+ }
if (ba->triangle_count >= ba->max_triangle_count) {
LineartTriangle **new_array = lineart_mem_acquire(
&rb->render_data_pool, sizeof(LineartTriangle *) * ba->max_triangle_count * 2);
@@ -343,6 +348,12 @@ static void lineart_bounding_area_line_add(LineartRenderBuffer *rb,
LineartBoundingArea *ba,
LineartEdge *e)
{
+ /* In case of too many lines concentrating in one point, do not add anymore, these lines will
+ * be either shorter than a single pixel, or will still be added into the list of other less
+ * dense areas. */
+ if (ba->line_count >= 65535) {
+ return;
+ }
if (ba->line_count >= ba->max_line_count) {
LineartEdge **new_array = lineart_mem_acquire(&rb->render_data_pool,
sizeof(LineartEdge *) * ba->max_line_count * 2);
@@ -567,20 +578,26 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2]
return 0;
}
- if (v1[0] - v0[0]) {
+ if (!LRT_DOUBLE_CLOSE_ENOUGH(v1[0], v0[0])) {
c1 = ratiod(v0[0], v1[0], v[0]);
}
- else if (v[0] == v1[0]) {
- c2 = ratiod(v0[1], v1[1], v[1]);
- return (c2 >= 0 && c2 <= 1);
+ else {
+ if (LRT_DOUBLE_CLOSE_ENOUGH(v[0], v1[0])) {
+ c2 = ratiod(v0[1], v1[1], v[1]);
+ return (c2 >= -DBL_TRIANGLE_LIM && c2 <= 1 + DBL_TRIANGLE_LIM);
+ }
+ return false;
}
- if (v1[1] - v0[1]) {
+ if (!LRT_DOUBLE_CLOSE_ENOUGH(v1[1], v0[1])) {
c2 = ratiod(v0[1], v1[1], v[1]);
}
- else if (v[1] == v1[1]) {
- c1 = ratiod(v0[0], v1[0], v[0]);
- return (c1 >= 0 && c1 <= 1);
+ else {
+ if (LRT_DOUBLE_CLOSE_ENOUGH(v[1], v1[1])) {
+ c1 = ratiod(v0[0], v1[0], v[0]);
+ return (c1 >= -DBL_TRIANGLE_LIM && c1 <= 1 + DBL_TRIANGLE_LIM);
+ }
+ return false;
}
if (LRT_DOUBLE_CLOSE_ENOUGH(c1, c2) && c1 >= 0 && c1 <= 1) {
@@ -1329,6 +1346,10 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
/* Select the triangle in the array. */
tri = (void *)(((uchar *)eln->pointer) + rb->triangle_size * i);
+ if (tri->flags & LRT_CULL_DISCARD) {
+ continue;
+ }
+
LRT_CULL_DECIDE_INSIDE
LRT_CULL_ENSURE_MEMORY
lineart_triangle_cull_single(rb,
@@ -1472,6 +1493,7 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
FreestyleEdge *fel, *fer;
bool face_mark_filtered = false;
uint16_t edge_flag_result = 0;
+ bool only_contour = false;
if (use_freestyle_face && rb->filter_face_mark) {
fel = CustomData_bmesh_get(&bm_if_freestyle->pdata, ll->f->head.data, CD_FREESTYLE_FACE);
@@ -1496,7 +1518,12 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
face_mark_filtered = !face_mark_filtered;
}
if (!face_mark_filtered) {
- return 0;
+ if (rb->filter_face_mark_keep_contour) {
+ only_contour = true;
+ }
+ else {
+ return 0;
+ }
}
}
@@ -1519,8 +1546,31 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
double dot_1 = 0, dot_2 = 0;
double result;
- if (rb->cam_is_persp) {
- sub_v3_v3v3_db(view_vector, l->gloc, rb->camera_pos);
+ if (rb->use_contour || rb->use_back_face_culling) {
+
+ if (rb->cam_is_persp) {
+ sub_v3_v3v3_db(view_vector, rb->camera_pos, l->gloc);
+ }
+ else {
+ view_vector = rb->view_vector;
+ }
+
+ dot_1 = dot_v3v3_db(view_vector, tri1->gn);
+ dot_2 = dot_v3v3_db(view_vector, tri2->gn);
+
+ if (rb->use_contour && (result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
+ edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
+ }
+
+ /* Because the ray points towards the camera, so back-face is when dot value being negative. */
+ if (rb->use_back_face_culling) {
+ if (dot_1 < 0) {
+ tri1->flags |= LRT_CULL_DISCARD;
+ }
+ if (dot_2 < 0) {
+ tri2->flags |= LRT_CULL_DISCARD;
+ }
+ }
}
else {
view_vector = rb->view_vector;
@@ -1529,10 +1579,16 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
dot_1 = dot_v3v3_db(view_vector, tri1->gn);
dot_2 = dot_v3v3_db(view_vector, tri2->gn);
- if ((result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
+ if ((result = dot_1 * dot_2) <= 0 && (fabs(dot_1) + fabs(dot_2))) {
edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
}
+ /* For when face mark filtering decided that we discard the face but keep_contour option is on.
+ * so we still have correct full contour around the object. */
+ if (only_contour) {
+ return edge_flag_result;
+ }
+
if (rb->use_crease) {
if (rb->sharp_as_crease && !BM_elem_flag_test(e, BM_ELEM_SMOOTH)) {
edge_flag_result |= LRT_EDGE_FLAG_CREASE;
@@ -1760,7 +1816,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
if (orig_ob->lineart.flags & OBJECT_LRT_OWN_CREASE) {
use_crease = cosf(M_PI - orig_ob->lineart.crease_threshold);
}
- if (obi->original_me->flag & ME_AUTOSMOOTH) {
+ else if (obi->original_me->flag & ME_AUTOSMOOTH) {
use_crease = cosf(obi->original_me->smoothresh);
use_auto_smooth = true;
}
@@ -1830,7 +1886,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
if (usage == OBJECT_LRT_INTERSECTION_ONLY) {
tri->flags |= LRT_TRIANGLE_INTERSECTION_ONLY;
}
- else if (usage == OBJECT_LRT_NO_INTERSECTION || usage == OBJECT_LRT_OCCLUSION_ONLY) {
+ else if (ELEM(usage, OBJECT_LRT_NO_INTERSECTION, OBJECT_LRT_OCCLUSION_ONLY)) {
tri->flags |= LRT_TRIANGLE_NO_INTERSECTION;
}
@@ -1858,7 +1914,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
bm);
if (eflag) {
/* Only allocate for feature lines (instead of all lines) to save memory.
- * If allow duplicated edges, one edge gets added multiple times if it has multiple types. */
+ * If allow duplicated edges, one edge gets added multiple times if it has multiple types.
+ */
allocate_la_e += rb->allow_duplicated_types ? lineart_edge_type_duplication_count(eflag) : 1;
}
/* Here we just use bm's flag for when loading actual lines, then we don't need to call
@@ -1917,8 +1974,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
la_e->flags = use_type;
la_e->object_ref = orig_ob;
BLI_addtail(&la_e->segments, la_s);
- if (usage == OBJECT_LRT_INHERIT || usage == OBJECT_LRT_INCLUDE ||
- usage == OBJECT_LRT_NO_INTERSECTION) {
+ if (ELEM(usage, OBJECT_LRT_INHERIT, OBJECT_LRT_INCLUDE, OBJECT_LRT_NO_INTERSECTION)) {
lineart_add_edge_to_list_thread(obi, la_e);
}
@@ -1954,13 +2010,12 @@ static uchar lineart_intersection_mask_check(Collection *c, Object *ob)
}
}
- if (c->children.first == NULL) {
- if (BKE_collection_has_object(c, (Object *)(ob->id.orig_id))) {
- if (c->lineart_flags & COLLECTION_LRT_USE_INTERSECTION_MASK) {
- return c->lineart_intersection_mask;
- }
+ if (BKE_collection_has_object(c, (Object *)(ob->id.orig_id))) {
+ if (c->lineart_flags & COLLECTION_LRT_USE_INTERSECTION_MASK) {
+ return c->lineart_intersection_mask;
}
}
+
return 0;
}
@@ -2054,8 +2109,8 @@ static bool lineart_geometry_check_visible(double (*model_view_proj)[4],
}
bool cond[6] = {true, true, true, true, true, true};
- /* Because for a point to be inside clip space, it must satisfy `-Wc <= XYCc <= Wc`, here if all
- * verts falls to the same side of the clip space border, we know it's outside view. */
+ /* Because for a point to be inside clip space, it must satisfy `-Wc <= XYCc <= Wc`, here if
+ * all verts falls to the same side of the clip space border, we know it's outside view. */
for (int i = 0; i < 8; i++) {
cond[0] &= (co[i][0] < -co[i][3]);
cond[1] &= (co[i][0] > co[i][3]);
@@ -2130,7 +2185,8 @@ static void lineart_main_load_geometries(
int thread_count = rb->thread_count;
- /* This memory is in render buffer memory pool. so we don't need to free those after loading. */
+ /* This memory is in render buffer memory pool. so we don't need to free those after loading.
+ */
LineartObjectLoadTaskInfo *olti = lineart_mem_acquire(
&rb->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count);
@@ -2168,6 +2224,12 @@ static void lineart_main_load_geometries(
use_mesh = use_ob->data;
}
else {
+ /* If DEG_ITER_OBJECT_FLAG_DUPLI is set, the curve objects are going to have a mesh
+ * equivalent already in the object list, so ignore converting the original curve in this
+ * case. */
+ if (allow_duplicates) {
+ continue;
+ }
use_mesh = BKE_mesh_new_from_object(depsgraph, use_ob, true, true);
}
@@ -2300,7 +2362,7 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
{ \
index = (num < is[order[0]] ? \
order[0] : \
- (num < is[order[1]] ? order[1] : (num < is[order[2]] ? order[2] : order[2]))); \
+ (num < is[order[1]] ? order[1] : (num < is[order[2]] ? order[2] : -1))); \
}
/* `ia ib ic` are ordered. */
@@ -2308,7 +2370,7 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
{ \
index = (num > is[order[2]] ? \
order[2] : \
- (num > is[order[1]] ? order[1] : (num > is[order[0]] ? order[0] : order[0]))); \
+ (num > is[order[1]] ? order[1] : (num > is[order[0]] ? order[0] : -1))); \
}
/**
@@ -2316,6 +2378,22 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
* the occlusion status between 1(one) triangle and 1(one) line.
* if returns true, then from/to will carry the occluded segments
* in ratio from `e->v1` to `e->v2`. The line is later cut with these two values.
+ *
+ * TODO(@Yiming): This function uses a convoluted method that needs to be redesigned.
+ *
+ * 1) The #lineart_intersect_seg_seg() and #lineart_point_triangle_relation() are separate calls,
+ * which would potentially return results that doesn't agree, especially when it's an edge
+ * extruding from one of the triangle's point. To get the information using one math process can
+ * solve this problem.
+ *
+ * 2) Currently using discrete a/b/c/pa/pb/pc/is[3] values for storing
+ * intersection/edge_aligned/intersection_order info, which isn't optimal, needs a better
+ * representation (likely a struct) for readability and clarity of code path.
+ *
+ * I keep this function as-is because it's still fast, and more importantly the output value
+ * threshold is already in tune with the cutting function in the next stage.
+ * While current "edge aligned" fix isn't ideal, it does solve most of the precision issue
+ * especially in orthographic camera mode.
*/
static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
const LineartTriangle *tri,
@@ -2333,7 +2411,8 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
double is[3] = {0};
int order[3];
int LCross = -1, RCross = -1;
- int a, b, c;
+ int a, b, c; /* Crossing info. */
+ bool pa, pb, pc; /* Parallel info. */
int st_l = 0, st_r = 0;
double Lv[3];
@@ -2363,9 +2442,9 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
}
/* Check if the line visually crosses one of the edge in the triangle. */
- a = lineart_LineIntersectTest2d(LFBC, RFBC, FBC0, FBC1, &is[0]);
- b = lineart_LineIntersectTest2d(LFBC, RFBC, FBC1, FBC2, &is[1]);
- c = lineart_LineIntersectTest2d(LFBC, RFBC, FBC2, FBC0, &is[2]);
+ a = lineart_intersect_seg_seg(LFBC, RFBC, FBC0, FBC1, &is[0], &pa);
+ b = lineart_intersect_seg_seg(LFBC, RFBC, FBC1, FBC2, &is[1], &pb);
+ c = lineart_intersect_seg_seg(LFBC, RFBC, FBC2, FBC0, &is[2], &pc);
/* Sort the intersection distance. */
INTERSECT_SORT_MIN_TO_MAX_3(is[0], is[1], is[2], order);
@@ -2390,20 +2469,24 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
dot_f = dot_v3v3_db(Cv, tri->gn);
/* NOTE(Yiming): When we don't use `dot_f==0` here, it's theoretically possible that _some_
- * faces in perspective mode would get erroneously caught in this condition where they really are
- * legit faces that would produce occlusion, but haven't encountered those yet in my test files.
+ * faces in perspective mode would get erroneously caught in this condition where they really
+ * are legit faces that would produce occlusion, but haven't encountered those yet in my test
+ * files.
*/
if (fabs(dot_f) < FLT_EPSILON) {
return false;
}
+ /* If the edge doesn't visually cross any edge of the triangle... */
if (!a && !b && !c) {
+ /* And if both end point from the edge is outside of the triangle... */
if (!(st_l = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2)) &&
!(st_r = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2))) {
- return 0; /* Intersection point is not inside triangle. */
+ return 0; /* We don't have any occlusion. */
}
}
+ /* Whether two end points are inside/on_the_edge/outside of the triangle. */
st_l = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2);
st_r = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2);
@@ -2450,69 +2533,112 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
cut = ratiod(e->v1->fbcoord[1], e->v2->fbcoord[1], trans[1]);
}
- /* Determine the pair of edges that the line has crossed. */
+#define LRT_GUARD_NOT_FOUND \
+ if (LCross < 0 || RCross < 0) { \
+ return false; \
+ }
+
+ /* Determine the pair of edges that the line has crossed. The "|" symbol in the comment
+ * indicates triangle boundary. DBL_TRIANGLE_LIM is needed to for floating point precision
+ * tolerance. */
if (st_l == 2) {
+ /* Left side is in the triangle. */
if (st_r == 2) {
+ /* | l---r | */
INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
}
else if (st_r == 1) {
+ /* | l------r| */
INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
}
else if (st_r == 0) {
+ /* | l-------|------r */
INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
INTERSECT_JUST_GREATER(is, order, 0, RCross);
}
}
else if (st_l == 1) {
+ /* Left side is on some edge of the triangle. */
if (st_r == 2) {
+ /* |l------r | */
INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
}
else if (st_r == 1) {
+ /* |l---------r| */
INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
}
else if (st_r == 0) {
+ /* |l----------|-------r (crossing the triangle) [OR]
+ * r---------|l | (not crossing the triangle) */
INTERSECT_JUST_GREATER(is, order, DBL_TRIANGLE_LIM, RCross);
- if (LRT_ABC(RCross) && is[RCross] > (DBL_TRIANGLE_LIM)) {
+ if (RCross >= 0 && LRT_ABC(RCross) && is[RCross] > (DBL_TRIANGLE_LIM)) {
INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
}
else {
- INTERSECT_JUST_SMALLER(is, order, -DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, -DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, RCross);
+ if (RCross > 0) {
+ INTERSECT_JUST_SMALLER(is, order, is[RCross], LCross);
+ }
+ }
+ LRT_GUARD_NOT_FOUND
+ /* We could have the edge being completely parallel to the triangle where there isn't a
+ * viable occlusion result. */
+ if ((LRT_PABC(LCross) && !LRT_ABC(LCross)) || (LRT_PABC(RCross) && !LRT_ABC(RCross))) {
+ return false;
}
}
}
else if (st_l == 0) {
+ /* Left side is outside of the triangle. */
if (st_r == 2) {
+ /* l---|---r | */
INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
}
else if (st_r == 1) {
+ /* |r----------|-------l (crossing the triangle) [OR]
+ * l---------|r | (not crossing the triangle) */
INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
- if (LRT_ABC(LCross) && is[LCross] < (1 - DBL_TRIANGLE_LIM)) {
+ if (LCross >= 0 && LRT_ABC(LCross) && is[LCross] < (1 - DBL_TRIANGLE_LIM)) {
INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
}
else {
- INTERSECT_JUST_SMALLER(is, order, 1 + DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 + DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
+ if (LCross > 0) {
+ INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ }
+ }
+ LRT_GUARD_NOT_FOUND
+ /* The same logic applies as above case. */
+ if ((LRT_PABC(LCross) && !LRT_ABC(LCross)) || (LRT_PABC(RCross) && !LRT_ABC(RCross))) {
+ return false;
}
}
else if (st_r == 0) {
- INTERSECT_JUST_GREATER(is, order, DBL_TRIANGLE_LIM, LCross);
- if (LRT_ABC(LCross) && is[LCross] > DBL_TRIANGLE_LIM) {
+ /* l---|----|----r (crossing the triangle) [OR]
+ * l----r | | (not crossing the triangle) */
+ INTERSECT_JUST_GREATER(is, order, -DBL_TRIANGLE_LIM, LCross);
+ if (LCross >= 0 && LRT_ABC(LCross)) {
INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
}
else {
- INTERSECT_JUST_GREATER(is, order, is[LCross], LCross);
- INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ if (LCross >= 0) {
+ INTERSECT_JUST_GREATER(is, order, is[LCross], LCross);
+ if (LCross >= 0) {
+ INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ }
+ }
}
}
}
+ LRT_GUARD_NOT_FOUND
+
double LF = dot_l * dot_f, RF = dot_r * dot_f;
/* Determine the start and end point of image space cut on a line. */
@@ -2861,15 +2987,7 @@ static LineartEdge *lineart_triangle_intersect(LineartRenderBuffer *rb,
result->intersection_mask = (tri->intersection_mask | testing->intersection_mask);
lineart_prepend_edge_direct(&rb->intersection.first, result);
- int r1, r2, c1, c2, row, col;
- if (lineart_get_edge_bounding_areas(rb, result, &r1, &r2, &c1, &c2)) {
- for (row = r1; row != r2 + 1; row++) {
- for (col = c1; col != c2 + 1; col++) {
- lineart_bounding_area_link_edge(
- rb, &rb->initial_bounding_areas[row * LRT_BA_ROWS + col], result);
- }
- }
- }
+
return result;
}
@@ -2993,7 +3111,7 @@ void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd)
}
}
-static LineartCache *lineart_init_cache()
+static LineartCache *lineart_init_cache(void)
{
LineartCache *lc = MEM_callocN(sizeof(LineartCache), "Lineart Cache");
return lc;
@@ -3011,6 +3129,8 @@ void MOD_lineart_clear_cache(struct LineartCache **lc)
static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
LineartGpencilModifierData *lmd,
+ Object *camera,
+ Object *active_camera,
LineartCache *lc)
{
LineartRenderBuffer *rb = MEM_callocN(sizeof(LineartRenderBuffer), "Line Art render buffer");
@@ -3019,10 +3139,10 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
lmd->render_buffer_ptr = rb;
lc->rb_edge_types = lmd->edge_types_override;
- if (!scene || !scene->camera || !lc) {
+ if (!scene || !camera || !lc) {
return NULL;
}
- Camera *c = scene->camera->data;
+ Camera *c = camera->data;
double clipping_offset = 0;
if (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) {
@@ -3030,8 +3150,11 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
clipping_offset = 0.0001;
}
- copy_v3db_v3fl(rb->camera_pos, scene->camera->obmat[3]);
- copy_m4_m4(rb->cam_obmat, scene->camera->obmat);
+ copy_v3db_v3fl(rb->camera_pos, camera->obmat[3]);
+ if (active_camera) {
+ copy_v3db_v3fl(rb->active_camera_pos, active_camera->obmat[3]);
+ }
+ copy_m4_m4(rb->cam_obmat, camera->obmat);
rb->cam_is_persp = (c->type == CAM_PERSP);
rb->near_clip = c->clip_start + clipping_offset;
rb->far_clip = c->clip_end - clipping_offset;
@@ -3067,6 +3190,8 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
rb->use_loose_as_contour = (lmd->calculation_flags & LRT_LOOSE_AS_CONTOUR) != 0;
rb->use_loose_edge_chain = (lmd->calculation_flags & LRT_CHAIN_LOOSE_EDGES) != 0;
rb->use_geometry_space_chain = (lmd->calculation_flags & LRT_CHAIN_GEOMETRY_SPACE) != 0;
+ rb->use_image_boundary_trimming = (lmd->calculation_flags & LRT_USE_IMAGE_BOUNDARY_TRIMMING) !=
+ 0;
/* See lineart_edge_from_triangle() for how this option may impact performance. */
rb->allow_overlapping_edges = (lmd->calculation_flags & LRT_ALLOW_OVERLAPPING_EDGES) != 0;
@@ -3076,6 +3201,14 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
rb->force_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SMOOTH_SURFACES) != 0;
rb->sharp_as_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SHARP_EDGES) != 0;
+ rb->chain_preserve_details = (lmd->calculation_flags & LRT_CHAIN_PRESERVE_DETAILS) != 0;
+
+ /* This is used to limit calculation to a certain level to save time, lines who have higher
+ * occlusion levels will get ignored. */
+ rb->max_occlusion_level = lmd->level_end_override;
+
+ rb->use_back_face_culling = (lmd->calculation_flags & LRT_USE_BACK_FACE_CULLING) != 0;
+
int16_t edge_types = lmd->edge_types_override;
rb->use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0;
@@ -3089,6 +3222,8 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
rb->filter_face_mark = (lmd->calculation_flags & LRT_FILTER_FACE_MARK) != 0;
rb->filter_face_mark_boundaries = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_BOUNDARIES) !=
0;
+ rb->filter_face_mark_keep_contour = (lmd->calculation_flags &
+ LRT_FILTER_FACE_MARK_KEEP_CONTOUR) != 0;
rb->chain_data_pool = &lc->chain_data_pool;
@@ -3333,7 +3468,6 @@ static void lineart_bounding_area_split(LineartRenderBuffer *rb,
LineartBoundingArea *ba = lineart_mem_acquire(&rb->render_data_pool,
sizeof(LineartBoundingArea) * 4);
LineartTriangle *tri;
- LineartEdge *e;
ba[0].l = root->cx;
ba[0].r = root->r;
@@ -3399,11 +3533,6 @@ static void lineart_bounding_area_split(LineartRenderBuffer *rb,
}
}
- for (int i = 0; i < root->line_count; i++) {
- e = root->linked_lines[i];
- lineart_bounding_area_link_edge(rb, root, e);
- }
-
rb->bounding_area_count += 3;
}
@@ -3683,9 +3812,6 @@ static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb,
return true;
}
-/**
- * This only gets initial "biggest" tile.
- */
LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb,
double x,
double y)
@@ -3757,9 +3883,6 @@ static LineartBoundingArea *lineart_get_bounding_area(LineartRenderBuffer *rb, d
return iba;
}
-/**
- * Wrapper for more convenience.
- */
LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y)
{
LineartBoundingArea *ba;
@@ -3815,25 +3938,26 @@ static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer
double data[2] = {e->v1->fbcoord[0], e->v1->fbcoord[1]};
double LU[2] = {-1, 1}, RU[2] = {1, 1}, LB[2] = {-1, -1}, RB[2] = {1, -1};
double r = 1, sr = 1;
+ bool p_unused;
if (data[0] > -1 && data[0] < 1 && data[1] > -1 && data[1] < 1) {
return lineart_get_bounding_area(rb, data[0], data[1]);
}
- if (lineart_LineIntersectTest2d(e->v1->fbcoord, e->v2->fbcoord, LU, RU, &sr) && sr < r &&
- sr > 0) {
+ if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, LU, RU, &sr, &p_unused) &&
+ sr < r && sr > 0) {
r = sr;
}
- if (lineart_LineIntersectTest2d(e->v1->fbcoord, e->v2->fbcoord, LB, RB, &sr) && sr < r &&
- sr > 0) {
+ if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, LB, RB, &sr, &p_unused) &&
+ sr < r && sr > 0) {
r = sr;
}
- if (lineart_LineIntersectTest2d(e->v1->fbcoord, e->v2->fbcoord, LB, LU, &sr) && sr < r &&
- sr > 0) {
+ if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, LB, LU, &sr, &p_unused) &&
+ sr < r && sr > 0) {
r = sr;
}
- if (lineart_LineIntersectTest2d(e->v1->fbcoord, e->v2->fbcoord, RB, RU, &sr) && sr < r &&
- sr > 0) {
+ if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, RB, RU, &sr, &p_unused) &&
+ sr < r && sr > 0) {
r = sr;
}
interp_v2_v2v2_db(data, e->v1->fbcoord, e->v2->fbcoord, r);
@@ -4064,18 +4188,15 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
return 0;
}
-/**
- * This is the entry point of all line art calculations.
- *
- * \return True when a change is made.
- */
bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
LineartGpencilModifierData *lmd,
- LineartCache **cached_result)
+ LineartCache **cached_result,
+ bool enable_stroke_depth_offset)
{
LineartRenderBuffer *rb;
Scene *scene = DEG_get_evaluated_scene(depsgraph);
int intersections_only = 0; /* Not used right now, but preserve for future. */
+ Object *use_camera;
double t_start;
@@ -4085,25 +4206,29 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
BKE_scene_camera_switch_update(scene);
- if (!scene->camera) {
- return false;
+ if (lmd->calculation_flags & LRT_USE_CUSTOM_CAMERA) {
+ if (!lmd->source_camera ||
+ (use_camera = DEG_get_evaluated_object(depsgraph, lmd->source_camera))->type !=
+ OB_CAMERA) {
+ return false;
+ }
+ }
+ else {
+ if (!scene->camera) {
+ return false;
+ }
+ use_camera = scene->camera;
}
LineartCache *lc = lineart_init_cache();
*cached_result = lc;
- rb = lineart_create_render_buffer(scene, lmd, lc);
+ rb = lineart_create_render_buffer(scene, lmd, use_camera, scene->camera, lc);
/* Triangle thread testing data size varies depending on the thread count.
* See definition of LineartTriangleThread for details. */
rb->triangle_size = lineart_triangle_size_get(scene, rb);
- /* This is used to limit calculation to a certain level to save time, lines who have higher
- * occlusion levels will get ignored. */
- rb->max_occlusion_level = (lmd->flags & LRT_GPENCIL_USE_CACHE) ?
- lmd->level_end_override :
- (lmd->use_multiple_levels ? lmd->level_end : lmd->level_start);
-
/* FIXME(Yiming): See definition of int #LineartRenderBuffer::_source_type for detailed. */
rb->_source_type = lmd->source_type;
rb->_source_collection = lmd->source_collection;
@@ -4112,7 +4237,7 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
/* Get view vector before loading geometries, because we detect feature lines there. */
lineart_main_get_view_vector(rb);
lineart_main_load_geometries(
- depsgraph, scene, scene->camera, rb, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS);
+ depsgraph, scene, use_camera, rb, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS);
if (!rb->vertex_buffer_pointers.first) {
/* No geometry loaded, return early. */
@@ -4175,15 +4300,24 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
if (rb->chain_smooth_tolerance > FLT_EPSILON) {
/* Keeping UI range of 0-1 for ease of read while scaling down the actual value for best
- * effective range in image-space (Coordinate only goes from -1 to 1). This value is somewhat
- * arbitrary, but works best for the moment. */
+ * effective range in image-space (Coordinate only goes from -1 to 1). This value is
+ * somewhat arbitrary, but works best for the moment. */
MOD_lineart_smooth_chains(rb, rb->chain_smooth_tolerance / 50);
}
+ if (rb->use_image_boundary_trimming) {
+ MOD_lineart_chain_clip_at_border(rb);
+ }
+
if (rb->angle_splitting_threshold > FLT_EPSILON) {
MOD_lineart_chain_split_angle(rb, rb->angle_splitting_threshold);
}
+ if (enable_stroke_depth_offset && lmd->stroke_depth_offset > FLT_EPSILON) {
+ MOD_lineart_chain_offset_towards_camera(
+ rb, lmd->stroke_depth_offset, lmd->flags & LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA);
+ }
+
/* Finally transfer the result list into cache. */
memcpy(&lc->chains, &rb->chains, sizeof(ListBase));
@@ -4276,8 +4410,15 @@ static void lineart_gpencil_generate(LineartCache *cache,
continue;
}
if (orig_col && ec->object_ref) {
- if (!BKE_collection_has_object_recursive_instanced(orig_col, (Object *)ec->object_ref)) {
- continue;
+ if (BKE_collection_has_object_recursive_instanced(orig_col, (Object *)ec->object_ref)) {
+ if (modifier_flags & LRT_GPENCIL_INVERT_COLLECTION) {
+ continue;
+ }
+ }
+ else {
+ if (!(modifier_flags & LRT_GPENCIL_INVERT_COLLECTION)) {
+ continue;
+ }
}
}
if (mask_switches & LRT_GPENCIL_MATERIAL_MASK_ENABLE) {
@@ -4292,7 +4433,7 @@ static void lineart_gpencil_generate(LineartCache *cache,
}
}
}
- if (types & LRT_EDGE_FLAG_INTERSECTION) {
+ if (ec->type & LRT_EDGE_FLAG_INTERSECTION) {
if (mask_switches & LRT_GPENCIL_INTERSECTION_MATCH) {
if (ec->intersection_mask != intersection_mask) {
continue;
@@ -4375,9 +4516,6 @@ static void lineart_gpencil_generate(LineartCache *cache,
}
}
-/**
- * Wrapper for external calls.
- */
void MOD_lineart_gpencil_generate(LineartCache *cache,
Depsgraph *depsgraph,
Object *ob,
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
index 988c90483a6..c53404a87e2 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
@@ -118,12 +118,12 @@ static bool bake_strokes(Object *ob,
}
LineartCache *local_lc = *lc;
if (!(*lc)) {
- MOD_lineart_compute_feature_lines(dg, lmd, lc);
+ MOD_lineart_compute_feature_lines(dg, lmd, lc, (!(ob->dtx & OB_DRAW_IN_FRONT)));
MOD_lineart_destroy_render_data(lmd);
}
else {
if (is_first || (!(lmd->flags & LRT_GPENCIL_USE_CACHE))) {
- MOD_lineart_compute_feature_lines(dg, lmd, &local_lc);
+ MOD_lineart_compute_feature_lines(dg, lmd, &local_lc, (!(ob->dtx & OB_DRAW_IN_FRONT)));
MOD_lineart_destroy_render_data(lmd);
}
MOD_lineart_chain_clear_picked_flag(local_lc);
@@ -444,7 +444,6 @@ static int lineart_gpencil_clear_strokes_all_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* Bake all line art modifiers on the current object. */
void OBJECT_OT_lineart_bake_strokes(wmOperatorType *ot)
{
ot->name = "Bake Line Art";
@@ -456,7 +455,6 @@ void OBJECT_OT_lineart_bake_strokes(wmOperatorType *ot)
ot->modal = lineart_gpencil_bake_strokes_commom_modal;
}
-/* Bake all lineart objects in the scene. */
void OBJECT_OT_lineart_bake_strokes_all(wmOperatorType *ot)
{
ot->name = "Bake Line Art (All)";
@@ -468,7 +466,6 @@ void OBJECT_OT_lineart_bake_strokes_all(wmOperatorType *ot)
ot->modal = lineart_gpencil_bake_strokes_commom_modal;
}
-/* clear all line art modifiers on the current object. */
void OBJECT_OT_lineart_clear(wmOperatorType *ot)
{
ot->name = "Clear Baked Line Art";
@@ -478,7 +475,6 @@ void OBJECT_OT_lineart_clear(wmOperatorType *ot)
ot->exec = lineart_gpencil_clear_strokes_exec;
}
-/* clear all lineart objects in the scene. */
void OBJECT_OT_lineart_clear_all(wmOperatorType *ot)
{
ot->name = "Clear Baked Line Art (All)";
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index b82fd9416b1..5bca82b52e4 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -37,6 +37,7 @@ set(INC
../imbuf
../makesdna
../makesrna
+ ../windowmanager
../editors/include
@@ -82,6 +83,8 @@ set(SRC
intern/gpu_select_sample_query.cc
intern/gpu_shader.cc
intern/gpu_shader_builtin.c
+ intern/gpu_shader_create_info.cc
+ intern/gpu_shader_dependency.cc
intern/gpu_shader_interface.cc
intern/gpu_shader_log.cc
intern/gpu_state.cc
@@ -134,6 +137,7 @@ set(SRC
GPU_primitive.h
GPU_select.h
GPU_shader.h
+ GPU_shader_shared.h
GPU_state.h
GPU_texture.h
GPU_uniform_buffer.h
@@ -158,6 +162,8 @@ set(SRC
intern/gpu_private.h
intern/gpu_query.hh
intern/gpu_select_private.h
+ intern/gpu_shader_create_info.hh
+ intern/gpu_shader_create_info_private.hh
intern/gpu_shader_interface.hh
intern/gpu_shader_private.hh
intern/gpu_state_private.hh
@@ -196,182 +202,259 @@ if(NOT WITH_SYSTEM_GLEW)
)
endif()
-data_to_c_simple(shaders/gpu_shader_depth_only_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_uniform_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_checker_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_diag_stripes_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_simple_lighting_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_flat_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_flat_id_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_area_borders_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_area_borders_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_widget_base_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_widget_base_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_widget_shadow_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_widget_shadow_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_nodelink_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_nodelink_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_flat_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_line_dashed_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_smooth_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_smooth_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_image_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_image_rect_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_image_multi_rect_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_desaturate_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_overlays_merge_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_shuffle_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_varying_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_image_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_normal_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_flat_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_polyline_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_polyline_geom.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_polyline_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_smooth_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_smooth_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_passthrough_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_point_uniform_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_point_uniform_color_aa_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_point_varying_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_point_varying_size_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_2D_edituvs_points_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_edituvs_facedots_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_edituvs_edges_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_edituvs_edges_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_edituvs_faces_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_edituvs_stretch_vert.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_text_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_text_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_keyframe_shape_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_keyframe_shape_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)
-data_to_c_simple(shaders/material/gpu_shader_material_ambient_occlusion.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_anisotropic.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_attribute.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_background.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_bevel.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_wavelength.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_blackbody.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_bright_contrast.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_bump.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_camera.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_clamp.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_color_ramp.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_color_util.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_combine_hsv.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_combine_rgb.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_combine_xyz.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_diffuse.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_displacement.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_eevee_specular.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_emission.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_fractal_noise.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_fresnel.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_gamma.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_geometry.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_glass.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_glossy.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_hair_info.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_hash.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_holdout.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_hue_sat_val.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_invert.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_layer_weight.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_light_falloff.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_light_path.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_mapping.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_map_range.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_math.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_math_util.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_mix_rgb.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_mix_shader.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_noise.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_normal.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_normal_map.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_object_info.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_output_aov.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_output_material.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_output_world.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_particle_info.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_principled.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_refraction.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_rgb_curves.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_rgb_to_bw.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_separate_hsv.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_separate_rgb.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_separate_xyz.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_set.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_shader_to_rgba.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_squeeze.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_subsurface_scattering.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tangent.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_brick.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_checker.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_environment.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_gradient.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_image.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_magic.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_musgrave.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_noise.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_sky.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_texture_coordinates.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_voronoi.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_wave.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_white_noise.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_toon.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_translucent.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_transparent.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_uv_map.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_vector_curves.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_vector_displacement.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_vector_math.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_vector_rotate.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_velvet.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_vertex_color.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_volume_absorption.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_volume_info.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_volume_principled.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_volume_scatter.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_wireframe.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_world_normals.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_gpencil_stroke_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_gpencil_stroke_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_gpencil_stroke_geom.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_cfg_world_clip_lib.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_colorspace_lib.glsl SRC)
+set(GLSL_SRC
+ GPU_shader_shared.h
+
+ shaders/gpu_shader_depth_only_frag.glsl
+ shaders/gpu_shader_uniform_color_frag.glsl
+ shaders/gpu_shader_checker_frag.glsl
+ shaders/gpu_shader_diag_stripes_frag.glsl
+ shaders/gpu_shader_simple_lighting_frag.glsl
+ shaders/gpu_shader_flat_color_frag.glsl
+ shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl
+ shaders/gpu_shader_flat_id_frag.glsl
+ shaders/gpu_shader_2D_vert.glsl
+ shaders/gpu_shader_2D_area_borders_vert.glsl
+ shaders/gpu_shader_2D_area_borders_frag.glsl
+ shaders/gpu_shader_2D_widget_base_vert.glsl
+ shaders/gpu_shader_2D_widget_base_frag.glsl
+ shaders/gpu_shader_2D_widget_shadow_vert.glsl
+ shaders/gpu_shader_2D_widget_shadow_frag.glsl
+ shaders/gpu_shader_2D_nodelink_frag.glsl
+ shaders/gpu_shader_2D_nodelink_vert.glsl
+ shaders/gpu_shader_2D_flat_color_vert.glsl
+ shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl
+ shaders/gpu_shader_2D_line_dashed_frag.glsl
+ shaders/gpu_shader_2D_smooth_color_vert.glsl
+ shaders/gpu_shader_2D_smooth_color_frag.glsl
+ shaders/gpu_shader_2D_image_vert.glsl
+ shaders/gpu_shader_2D_image_rect_vert.glsl
+ shaders/gpu_shader_2D_image_multi_rect_vert.glsl
+ shaders/gpu_shader_image_frag.glsl
+ shaders/gpu_shader_image_desaturate_frag.glsl
+ shaders/gpu_shader_image_overlays_merge_frag.glsl
+ shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
+ shaders/gpu_shader_image_modulate_alpha_frag.glsl
+ shaders/gpu_shader_image_shuffle_color_frag.glsl
+ shaders/gpu_shader_image_color_frag.glsl
+ shaders/gpu_shader_image_varying_color_frag.glsl
+ shaders/gpu_shader_3D_image_vert.glsl
+ shaders/gpu_shader_3D_vert.glsl
+ shaders/gpu_shader_3D_normal_vert.glsl
+ shaders/gpu_shader_3D_flat_color_vert.glsl
+ shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl
+ shaders/gpu_shader_3D_polyline_frag.glsl
+ shaders/gpu_shader_3D_polyline_geom.glsl
+ shaders/gpu_shader_3D_polyline_vert.glsl
+ shaders/gpu_shader_3D_smooth_color_vert.glsl
+ shaders/gpu_shader_3D_smooth_color_frag.glsl
+ shaders/gpu_shader_3D_passthrough_vert.glsl
+ shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl
+
+ shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
+
+ shaders/gpu_shader_point_uniform_color_aa_frag.glsl
+ shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl
+ shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl
+ shaders/gpu_shader_point_varying_color_frag.glsl
+ shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl
+ shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl
+ shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl
+ shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl
+ shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl
+ shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl
+
+ shaders/gpu_shader_text_vert.glsl
+ shaders/gpu_shader_text_frag.glsl
+ shaders/gpu_shader_keyframe_shape_vert.glsl
+ shaders/gpu_shader_keyframe_shape_frag.glsl
+
+ shaders/gpu_shader_codegen_lib.glsl
+
+ shaders/gpu_shader_geometry.glsl
+
+ shaders/material/gpu_shader_material_add_shader.glsl
+ shaders/material/gpu_shader_material_ambient_occlusion.glsl
+ shaders/material/gpu_shader_material_anisotropic.glsl
+ shaders/material/gpu_shader_material_attribute.glsl
+ shaders/material/gpu_shader_material_background.glsl
+ shaders/material/gpu_shader_material_bevel.glsl
+ shaders/material/gpu_shader_material_wavelength.glsl
+ shaders/material/gpu_shader_material_blackbody.glsl
+ shaders/material/gpu_shader_material_bright_contrast.glsl
+ shaders/material/gpu_shader_material_bump.glsl
+ shaders/material/gpu_shader_material_camera.glsl
+ shaders/material/gpu_shader_material_clamp.glsl
+ shaders/material/gpu_shader_material_color_ramp.glsl
+ shaders/material/gpu_shader_material_color_util.glsl
+ shaders/material/gpu_shader_material_combine_hsv.glsl
+ shaders/material/gpu_shader_material_combine_rgb.glsl
+ shaders/material/gpu_shader_material_combine_xyz.glsl
+ shaders/material/gpu_shader_material_diffuse.glsl
+ shaders/material/gpu_shader_material_displacement.glsl
+ shaders/material/gpu_shader_material_eevee_specular.glsl
+ shaders/material/gpu_shader_material_emission.glsl
+ shaders/material/gpu_shader_material_float_curve.glsl
+ shaders/material/gpu_shader_material_fractal_noise.glsl
+ shaders/material/gpu_shader_material_fresnel.glsl
+ shaders/material/gpu_shader_material_gamma.glsl
+ shaders/material/gpu_shader_material_geometry.glsl
+ shaders/material/gpu_shader_material_glass.glsl
+ shaders/material/gpu_shader_material_glossy.glsl
+ shaders/material/gpu_shader_material_hair_info.glsl
+ shaders/material/gpu_shader_material_hash.glsl
+ shaders/material/gpu_shader_material_holdout.glsl
+ shaders/material/gpu_shader_material_hue_sat_val.glsl
+ shaders/material/gpu_shader_material_invert.glsl
+ shaders/material/gpu_shader_material_layer_weight.glsl
+ shaders/material/gpu_shader_material_light_falloff.glsl
+ shaders/material/gpu_shader_material_light_path.glsl
+ shaders/material/gpu_shader_material_mapping.glsl
+ shaders/material/gpu_shader_material_map_range.glsl
+ shaders/material/gpu_shader_material_math.glsl
+ shaders/material/gpu_shader_material_math_util.glsl
+ shaders/material/gpu_shader_material_mix_rgb.glsl
+ shaders/material/gpu_shader_material_mix_shader.glsl
+ shaders/material/gpu_shader_material_noise.glsl
+ shaders/material/gpu_shader_material_normal.glsl
+ shaders/material/gpu_shader_material_normal_map.glsl
+ shaders/material/gpu_shader_material_object_info.glsl
+ shaders/material/gpu_shader_material_output_aov.glsl
+ shaders/material/gpu_shader_material_output_material.glsl
+ shaders/material/gpu_shader_material_output_world.glsl
+ shaders/material/gpu_shader_material_particle_info.glsl
+ shaders/material/gpu_shader_material_point_info.glsl
+ shaders/material/gpu_shader_material_principled.glsl
+ shaders/material/gpu_shader_material_refraction.glsl
+ shaders/material/gpu_shader_material_rgb_curves.glsl
+ shaders/material/gpu_shader_material_rgb_to_bw.glsl
+ shaders/material/gpu_shader_material_separate_hsv.glsl
+ shaders/material/gpu_shader_material_separate_rgb.glsl
+ shaders/material/gpu_shader_material_separate_xyz.glsl
+ shaders/material/gpu_shader_material_set.glsl
+ shaders/material/gpu_shader_material_shader_to_rgba.glsl
+ shaders/material/gpu_shader_material_squeeze.glsl
+ shaders/material/gpu_shader_material_subsurface_scattering.glsl
+ shaders/material/gpu_shader_material_tangent.glsl
+ shaders/material/gpu_shader_material_tex_brick.glsl
+ shaders/material/gpu_shader_material_tex_checker.glsl
+ shaders/material/gpu_shader_material_tex_environment.glsl
+ shaders/material/gpu_shader_material_tex_gradient.glsl
+ shaders/material/gpu_shader_material_tex_image.glsl
+ shaders/material/gpu_shader_material_tex_magic.glsl
+ shaders/material/gpu_shader_material_tex_musgrave.glsl
+ shaders/material/gpu_shader_material_tex_noise.glsl
+ shaders/material/gpu_shader_material_tex_sky.glsl
+ shaders/material/gpu_shader_material_texture_coordinates.glsl
+ shaders/material/gpu_shader_material_tex_voronoi.glsl
+ shaders/material/gpu_shader_material_tex_wave.glsl
+ shaders/material/gpu_shader_material_tex_white_noise.glsl
+ shaders/material/gpu_shader_material_toon.glsl
+ shaders/material/gpu_shader_material_translucent.glsl
+ shaders/material/gpu_shader_material_transparent.glsl
+ shaders/material/gpu_shader_material_uv_map.glsl
+ shaders/material/gpu_shader_material_vector_curves.glsl
+ shaders/material/gpu_shader_material_vector_displacement.glsl
+ shaders/material/gpu_shader_material_vector_math.glsl
+ shaders/material/gpu_shader_material_vector_rotate.glsl
+ shaders/material/gpu_shader_material_velvet.glsl
+ shaders/material/gpu_shader_material_vertex_color.glsl
+ shaders/material/gpu_shader_material_volume_absorption.glsl
+ shaders/material/gpu_shader_material_volume_info.glsl
+ shaders/material/gpu_shader_material_volume_principled.glsl
+ shaders/material/gpu_shader_material_volume_scatter.glsl
+ shaders/material/gpu_shader_material_wireframe.glsl
+ shaders/material/gpu_shader_material_world_normals.glsl
+
+ shaders/gpu_shader_gpencil_stroke_vert.glsl
+ shaders/gpu_shader_gpencil_stroke_frag.glsl
+ shaders/gpu_shader_gpencil_stroke_geom.glsl
+
+ shaders/gpu_shader_cfg_world_clip_lib.glsl
+ shaders/gpu_shader_colorspace_lib.glsl
+
+ intern/gpu_shader_shared_utils.h
+)
+
+set(GLSL_C)
+foreach(GLSL_FILE ${GLSL_SRC})
+ data_to_c_simple(${GLSL_FILE} GLSL_C)
+endforeach()
+
+blender_add_lib(bf_gpu_shaders "${GLSL_C}" "" "" "")
+
+list(APPEND LIB
+ bf_gpu_shaders
+)
+
+set(GLSL_SOURCE_CONTENT "")
+foreach(GLSL_FILE ${GLSL_SRC})
+ get_filename_component(GLSL_FILE_NAME ${GLSL_FILE} NAME)
+ string(REPLACE "." "_" GLSL_FILE_NAME_UNDERSCORES ${GLSL_FILE_NAME})
+ string(APPEND GLSL_SOURCE_CONTENT "SHADER_SOURCE\(datatoc_${GLSL_FILE_NAME_UNDERSCORES}, \"${GLSL_FILE_NAME}\", \"${GLSL_FILE}\"\)\n")
+endforeach()
+
+set(glsl_source_list_file "${CMAKE_CURRENT_BINARY_DIR}/glsl_gpu_source_list.h")
+file(GENERATE OUTPUT ${glsl_source_list_file} CONTENT "${GLSL_SOURCE_CONTENT}")
+list(APPEND SRC ${glsl_source_list_file})
+list(APPEND INC ${CMAKE_CURRENT_BINARY_DIR})
+
+set(SHADER_CREATE_INFOS
+../draw/engines/workbench/shaders/infos/workbench_composite_info.hh
+../draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh
+../draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh
+../draw/engines/workbench/shaders/infos/workbench_effect_dof_info.hh
+../draw/engines/workbench/shaders/infos/workbench_effect_outline_info.hh
+../draw/engines/workbench/shaders/infos/workbench_merge_infront_info.hh
+../draw/engines/workbench/shaders/infos/workbench_prepass_info.hh
+../draw/engines/workbench/shaders/infos/workbench_shadow_info.hh
+../draw/engines/workbench/shaders/infos/workbench_transparent_resolve_info.hh
+../draw/engines/workbench/shaders/infos/workbench_volume_info.hh
+../draw/intern/shaders/draw_fullscreen_info.hh
+../draw/intern/shaders/draw_object_infos_info.hh
+../draw/intern/shaders/draw_view_info.hh
+../draw/intern/shaders/draw_hair_refine_info.hh
+
+shaders/infos/gpu_clip_planes_info.hh
+shaders/infos/gpu_shader_2D_area_borders_info.hh
+shaders/infos/gpu_shader_2D_checker_info.hh
+shaders/infos/gpu_shader_2D_diag_stripes_info.hh
+shaders/infos/gpu_shader_2D_flat_color_info.hh
+shaders/infos/gpu_shader_2D_image_color_info.hh
+shaders/infos/gpu_shader_2D_image_desaturate_color_info.hh
+shaders/infos/gpu_shader_2D_image_info.hh
+shaders/infos/gpu_shader_2D_image_multi_rect_color_info.hh
+shaders/infos/gpu_shader_2D_image_overlays_merge_info.hh
+shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
+shaders/infos/gpu_shader_2D_image_rect_color_info.hh
+shaders/infos/gpu_shader_2D_image_shuffle_color_info.hh
+shaders/infos/gpu_shader_2D_nodelink_info.hh
+shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_aa_info.hh
+shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_outline_aa_info.hh
+shaders/infos/gpu_shader_2D_point_varying_size_varying_color_info.hh
+shaders/infos/gpu_shader_2D_smooth_color_info.hh
+shaders/infos/gpu_shader_2D_uniform_color_info.hh
+shaders/infos/gpu_shader_3D_depth_only_info.hh
+shaders/infos/gpu_shader_3D_flat_color_info.hh
+shaders/infos/gpu_shader_3D_image_modulate_alpha_info.hh
+shaders/infos/gpu_shader_3D_point_info.hh
+shaders/infos/gpu_shader_3D_smooth_color_info.hh
+shaders/infos/gpu_shader_3D_uniform_color_info.hh
+shaders/infos/gpu_shader_gpencil_stroke_info.hh
+shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh
+shaders/infos/gpu_shader_keyframe_shape_info.hh
+shaders/infos/gpu_shader_simple_lighting_info.hh
+shaders/infos/gpu_shader_text_info.hh
+shaders/infos/gpu_srgb_to_framebuffer_space_info.hh
+)
+
+set(SHADER_CREATE_INFOS_CONTENT "")
+foreach(DESCRIPTOR_FILE ${SHADER_CREATE_INFOS})
+string(APPEND SHADER_CREATE_INFOS_CONTENT "#include \"${DESCRIPTOR_FILE}\"\n")
+endforeach()
+
+set(shader_create_info_list_file "${CMAKE_CURRENT_BINARY_DIR}/gpu_shader_create_info_list.hh")
+file(GENERATE OUTPUT ${shader_create_info_list_file} CONTENT "${SHADER_CREATE_INFOS_CONTENT}")
if(WITH_MOD_FLUID)
add_definitions(-DWITH_FLUID)
@@ -384,11 +467,48 @@ if(WITH_IMAGE_DDS)
endif()
blender_add_lib(bf_gpu "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+target_link_libraries(bf_gpu PUBLIC
+ bf_draw_shaders
+ bf_gpu_shaders
+)
if(CXX_WARN_NO_SUGGEST_OVERRIDE)
target_compile_options(bf_gpu PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-Wsuggest-override>)
endif()
+
+
+if(WITH_GPU_SHADER_BUILDER)
+ add_executable(shader_builder
+ intern/gpu_shader_builder.cc
+ intern/gpu_shader_builder_stubs.cc
+ ${shader_create_info_list_file}
+ )
+
+ target_link_libraries(shader_builder PUBLIC
+ bf_blenkernel
+ ${PLATFORM_LINKLIBS}
+ )
+ target_include_directories(shader_builder PRIVATE ${INC} ${CMAKE_CURRENT_BINARY_DIR})
+
+ set(BAKED_CREATE_INFOS_FILE ${CMAKE_CURRENT_BINARY_DIR}/shader_baked.hh)
+
+ add_custom_command(
+ OUTPUT
+ ${BAKED_CREATE_INFOS_FILE}
+ COMMAND
+ "$<TARGET_FILE:shader_builder>" ${BAKED_CREATE_INFOS_FILE}
+ DEPENDS shader_builder
+ )
+ set(GPU_SHADER_INFO_SRC
+ intern/gpu_shader_info_baked.cc
+ ${BAKED_CREATE_INFOS_FILE}
+ )
+
+ blender_add_lib(bf_gpu_shader_infos "${GPU_SHADER_INFO_SRC}" "" "" "")
+endif()
+
+
if(WITH_GTESTS)
if(WITH_OPENGL_DRAW_TESTS)
set(TEST_SRC
@@ -401,10 +521,8 @@ if(WITH_GTESTS)
tests/gpu_testing.hh
)
set(TEST_INC
- "../../../intern/ghost/"
)
set(TEST_LIB
-
)
include(GTestTesting)
blender_add_test_lib(bf_gpu_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index 018e192bf37..b193b45d65c 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -30,9 +30,10 @@
#include "GPU_index_buffer.h"
#include "GPU_shader.h"
+#include "GPU_uniform_buffer.h"
#include "GPU_vertex_buffer.h"
-#define GPU_BATCH_VBO_MAX_LEN 6
+#define GPU_BATCH_VBO_MAX_LEN 16
#define GPU_BATCH_INST_VBO_MAX_LEN 2
#define GPU_BATCH_VAO_STATIC_LEN 3
#define GPU_BATCH_VAO_DYN_ALLOC_COUNT 16
@@ -54,11 +55,11 @@ typedef enum eGPUBatchFlag {
GPU_BATCH_OWNS_INDEX = (GPU_BATCH_OWNS_INST_VBO_MAX << 1),
/** Has been initialized. At least one VBO is set. */
- GPU_BATCH_INIT = (1 << 16),
+ GPU_BATCH_INIT = (1 << 26),
/** Batch is initialized but its VBOs are still being populated. (optional) */
- GPU_BATCH_BUILDING = (1 << 16),
+ GPU_BATCH_BUILDING = (1 << 26),
/** Cached data need to be rebuild. (VAO, PSO, ...) */
- GPU_BATCH_DIRTY = (1 << 17),
+ GPU_BATCH_DIRTY = (1 << 27),
} eGPUBatchFlag;
#define GPU_BATCH_OWNS_NONE GPU_BATCH_INVALID
@@ -102,25 +103,48 @@ void GPU_batch_init_ex(GPUBatch *batch,
GPUVertBuf *vert,
GPUIndexBuf *elem,
eGPUBatchFlag owns_flag);
+/**
+ * This will share the VBOs with the new batch.
+ */
void GPU_batch_copy(GPUBatch *batch_dst, GPUBatch *batch_src);
#define GPU_batch_create(prim, verts, elem) GPU_batch_create_ex(prim, verts, elem, 0)
#define GPU_batch_init(batch, prim, verts, elem) GPU_batch_init_ex(batch, prim, verts, elem, 0)
-/* Same as discard but does not free. (does not call free callback). */
+/**
+ * Same as discard but does not free. (does not call free callback).
+ */
void GPU_batch_clear(GPUBatch *);
-void GPU_batch_discard(GPUBatch *); /* verts & elem are not discarded */
+/**
+ * \note Verts & elem are not discarded.
+ */
+void GPU_batch_discard(GPUBatch *);
+/**
+ * \note Override ONLY the first instance VBO (and free them if owned).
+ */
void GPU_batch_instbuf_set(GPUBatch *, GPUVertBuf *, bool own_vbo); /* Instancing */
+/**
+ * \note Override any previously assigned elem (and free it if owned).
+ */
void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo);
int GPU_batch_instbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo);
+/**
+ * Returns the index of verts in the batch.
+ */
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_set_shader(GPUBatch *batch, GPUShader *shader);
+/**
+ * Bind program bound to IMM to the batch.
+ *
+ * XXX Use this with much care. Drawing with the #GPUBatch API is not compatible with IMM.
+ * DO NOT DRAW WITH THE BATCH BEFORE CALLING #immUnbindProgram.
+ */
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,
@@ -129,6 +153,7 @@ void GPU_batch_program_set_builtin_with_config(GPUBatch *batch,
/* Will only work after setting the batch program. */
/* TODO(fclem): These need to be replaced by GPU_shader_uniform_* with explicit shader. */
+
#define GPU_batch_uniform_1i(batch, name, x) GPU_shader_uniform_1i((batch)->shader, name, x);
#define GPU_batch_uniform_1b(batch, name, x) GPU_shader_uniform_1b((batch)->shader, name, x);
#define GPU_batch_uniform_1f(batch, name, x) GPU_shader_uniform_1f((batch)->shader, name, x);
@@ -146,19 +171,26 @@ void GPU_batch_program_set_builtin_with_config(GPUBatch *batch,
GPU_shader_uniform_4fv_array((batch)->shader, name, len, val);
#define GPU_batch_uniform_mat4(batch, name, val) \
GPU_shader_uniform_mat4((batch)->shader, name, val);
+#define GPU_batch_uniformbuf_bind(batch, name, ubo) \
+ GPU_uniformbuf_bind(ubo, GPU_shader_get_uniform_block_binding((batch)->shader, name));
#define GPU_batch_texture_bind(batch, name, tex) \
GPU_texture_bind(tex, GPU_shader_get_texture_binding((batch)->shader, name));
void GPU_batch_draw(GPUBatch *batch);
void GPU_batch_draw_range(GPUBatch *batch, int v_first, int v_count);
+/**
+ * Draw multiple instance of a batch without having any instance attributes.
+ */
void GPU_batch_draw_instanced(GPUBatch *batch, int i_count);
-/* This does not bind/unbind shader and does not call GPU_matrix_bind() */
+/**
+ * This does not bind/unbind shader and does not call GPU_matrix_bind().
+ */
void GPU_batch_draw_advanced(GPUBatch *, int v_first, int v_count, int i_first, int i_count);
#if 0 /* future plans */
-/* Can multiple batches share a GPUVertBuf? Use ref count? */
+/* Can multiple batches share a #GPUVertBuf? Use ref count? */
/* We often need a batch with its own data, to be created and discarded together. */
/* WithOwn variants reduce number of system allocations. */
diff --git a/source/blender/gpu/GPU_batch_presets.h b/source/blender/gpu/GPU_batch_presets.h
index 19f200fecbf..1681db8126a 100644
--- a/source/blender/gpu/GPU_batch_presets.h
+++ b/source/blender/gpu/GPU_batch_presets.h
@@ -35,14 +35,18 @@ extern "C" {
/* gpu_batch_presets.c */
-/* Replacement for gluSphere */
+/* Replacement for #gluSphere */
+
struct GPUBatch *GPU_batch_preset_sphere(int lod) ATTR_WARN_UNUSED_RESULT;
struct GPUBatch *GPU_batch_preset_sphere_wire(int lod) ATTR_WARN_UNUSED_RESULT;
-struct GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize,
+struct GPUBatch *GPU_batch_preset_panel_drag_widget(float pixelsize,
const float col_high[4],
const float col_dark[4],
- const float width) ATTR_WARN_UNUSED_RESULT;
+ float width) ATTR_WARN_UNUSED_RESULT;
+/**
+ * To be used with procedural placement inside shader.
+ */
struct GPUBatch *GPU_batch_preset_quad(void);
void gpu_batch_presets_init(void);
diff --git a/source/blender/gpu/GPU_batch_utils.h b/source/blender/gpu/GPU_batch_utils.h
index 37dccc4621c..660ae0c8844 100644
--- a/source/blender/gpu/GPU_batch_utils.h
+++ b/source/blender/gpu/GPU_batch_utils.h
@@ -30,6 +30,16 @@ extern "C" {
struct rctf;
/* gpu_batch_utils.c */
+
+/**
+ * Creates triangles from a byte-array of polygons.
+ *
+ * See 'make_shape_2d_from_blend.py' utility to create data to pass to this function.
+ *
+ * \param polys_flat: Pairs of X, Y coordinates (repeating to signify closing the polygon).
+ * \param polys_flat_len: Length of the array (must be an even number).
+ * \param rect: Optional region to map the byte 0..255 coords to. When not set use -1..1.
+ */
struct GPUBatch *GPU_batch_tris_from_poly_2d_encoded(
const uchar *polys_flat, uint polys_flat_len, const struct rctf *rect) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
@@ -37,7 +47,11 @@ struct GPUBatch *GPU_batch_wire_from_poly_2d_encoded(
const uchar *polys_flat, uint polys_flat_len, const struct rctf *rect) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
-/* Only use by draw manager. Use the presets function instead for interface. */
+/**
+ * Replacement for #gluSphere.
+ *
+ * \note Only use by draw manager. Use the presets function instead for interface.
+ */
struct GPUBatch *gpu_batch_sphere(int lat_res, int lon_res) ATTR_WARN_UNUSED_RESULT;
#ifdef __cplusplus
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index b770bde65fc..0a1d9c3b6d5 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -44,54 +44,82 @@ struct Mesh;
struct PBVH;
struct SubdivCCG;
-/* Buffers for drawing from PBVH grids. */
+/**
+ * Buffers for drawing from PBVH grids.
+ */
typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers;
-/* Build must be called once before using the other functions, used every time
- * mesh topology changes. Threaded. */
+/**
+ * Build must be called once before using the other functions,
+ * used every time mesh topology changes.
+ *
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct MPoly *mpoly,
const struct MLoop *mloop,
const struct MLoopTri *looptri,
const struct MVert *mvert,
const int *face_indices,
const int *sculpt_face_sets,
- const int face_indices_len,
+ int face_indices_len,
const struct Mesh *mesh);
+/**
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, unsigned int **grid_hidden);
+/**
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading);
-/* Free part of data for update. Not thread safe, must run in OpenGL main thread. */
+/**
+ * Free part of data for update. Not thread safe, must run in OpenGL main thread.
+ */
void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers);
void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
const struct DMFlagMat *grid_flag_mats,
const int *grid_indices);
-/* Update mesh buffers without topology changes. Threaded. */
+/**
+ * Update mesh buffers without topology changes. Threaded.
+ */
enum {
GPU_PBVH_BUFFERS_SHOW_MASK = (1 << 1),
GPU_PBVH_BUFFERS_SHOW_VCOL = (1 << 2),
GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS = (1 << 3),
};
+/**
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const struct MVert *mvert,
+ const float (*vert_normals)[3],
const float *vmask,
const struct MLoopCol *vcol,
const int *sculpt_face_sets,
- const int face_sets_color_seed,
- const int face_sets_color_default,
+ int face_sets_color_seed,
+ int face_sets_color_default,
const struct MPropCol *vtcol,
- const int update_flags);
+ int update_flags);
+/**
+ * Creates a vertex buffer (coordinate, normal, color) and,
+ * if smooth shading, an element index buffer.
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
struct BMesh *bm,
struct GSet *bm_faces,
struct GSet *bm_unique_verts,
struct GSet *bm_other_verts,
- const int update_flags);
+ int update_flags);
+/**
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
struct SubdivCCG *subdiv_ccg,
struct CCGElem **grids,
@@ -99,18 +127,22 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
int *grid_indices,
int totgrid,
const int *sculpt_face_sets,
- const int face_sets_color_seed,
- const int face_sets_color_default,
+ int face_sets_color_seed,
+ int face_sets_color_default,
const struct CCGKey *key,
- const int update_flags);
+ int update_flags);
-/* Finish update. Not thread safe, must run in OpenGL main thread. */
+/**
+ * Finish update. Not thread safe, must run in OpenGL main thread.
+ */
void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers);
-/* Free buffers. Not thread safe, must run in OpenGL main thread. */
+/**
+ * Free buffers. Not thread safe, must run in OpenGL main thread.
+ */
void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
-/* draw */
+/** Draw. */
struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires);
short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers);
diff --git a/source/blender/gpu/GPU_capabilities.h b/source/blender/gpu/GPU_capabilities.h
index 5b5d0f16c9f..9cd1dbd37f1 100644
--- a/source/blender/gpu/GPU_capabilities.h
+++ b/source/blender/gpu/GPU_capabilities.h
@@ -64,6 +64,9 @@ bool GPU_shader_image_load_store_support(void);
bool GPU_mem_stats_supported(void);
void GPU_mem_stats_get(int *totalmem, int *freemem);
+/**
+ * Return support for the active context + window.
+ */
bool GPU_stereo_quadbuffer_support(void);
#ifdef __cplusplus
diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h
index 82f13424502..5e67441be27 100644
--- a/source/blender/gpu/GPU_context.h
+++ b/source/blender/gpu/GPU_context.h
@@ -40,12 +40,20 @@ typedef enum eGPUBackendType {
void GPU_backend_init(eGPUBackendType backend);
void GPU_backend_exit(void);
+eGPUBackendType GPU_backend_get_type(void);
+
/** Opaque type hiding blender::gpu::Context. */
typedef struct GPUContext GPUContext;
GPUContext *GPU_context_create(void *ghost_window);
+/**
+ * To be called after #GPU_context_active_set(ctx_to_destroy).
+ */
void GPU_context_discard(GPUContext *);
+/**
+ * Ctx can be NULL.
+ */
void GPU_context_active_set(GPUContext *);
GPUContext *GPU_context_active_get(void);
diff --git a/source/blender/gpu/GPU_debug.h b/source/blender/gpu/GPU_debug.h
index f67e850ad80..9796ac63272 100644
--- a/source/blender/gpu/GPU_debug.h
+++ b/source/blender/gpu/GPU_debug.h
@@ -33,7 +33,14 @@ extern "C" {
void GPU_debug_group_begin(const char *name);
void GPU_debug_group_end(void);
+/**
+ * Return a formatted string showing the current group hierarchy in this format:
+ * "Group1 > Group 2 > Group3 > ... > GroupN : "
+ */
void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf);
+/**
+ * Return true if inside a debug group with the same name.
+ */
bool GPU_debug_group_match(const char *ref);
#ifdef __cplusplus
diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h
index bf0ab3dc533..b203c49a7f1 100644
--- a/source/blender/gpu/GPU_framebuffer.h
+++ b/source/blender/gpu/GPU_framebuffer.h
@@ -62,6 +62,9 @@ typedef struct GPUOffScreen GPUOffScreen;
GPUFrameBuffer *GPU_framebuffer_create(const char *name);
void GPU_framebuffer_free(GPUFrameBuffer *fb);
void GPU_framebuffer_bind(GPUFrameBuffer *fb);
+/**
+ * Workaround for binding a SRGB frame-buffer without doing the SRGB transform.
+ */
void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *fb);
void GPU_framebuffer_restore(void);
@@ -69,6 +72,9 @@ bool GPU_framebuffer_bound(GPUFrameBuffer *fb);
bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]);
GPUFrameBuffer *GPU_framebuffer_active_get(void);
+/**
+ * Returns the default frame-buffer. Will always exists even if it's just a dummy.
+ */
GPUFrameBuffer *GPU_framebuffer_back_get(void);
#define GPU_FRAMEBUFFER_FREE_SAFE(fb) \
@@ -113,6 +119,12 @@ void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, struct GPUTexture *tex);
GPU_framebuffer_config_array(*(_fb), config, (sizeof(config) / sizeof(GPUAttachment))); \
} while (0)
+/**
+ * First #GPUAttachment in *config is always the depth/depth_stencil buffer.
+ * Following #GPUAttachments are color buffers.
+ * Setting #GPUAttachment.mip to -1 will leave the texture in this slot.
+ * Setting #GPUAttachment.tex to NULL will detach the texture in this slot.
+ */
void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *config, int config_len);
#define GPU_ATTACHMENT_NONE \
@@ -156,8 +168,16 @@ void GPU_framebuffer_texture_cubeface_attach(
/* Frame-buffer operations. */
+/**
+ * Viewport and scissor size is stored per frame-buffer.
+ * It is only reset to its original dimensions explicitly OR when binding the frame-buffer after
+ * modifying its attachments.
+ */
void GPU_framebuffer_viewport_set(GPUFrameBuffer *fb, int x, int y, int w, int h);
void GPU_framebuffer_viewport_get(GPUFrameBuffer *fb, int r_viewport[4]);
+/**
+ * Reset to its attachment(s) size.
+ */
void GPU_framebuffer_viewport_reset(GPUFrameBuffer *fb);
void GPU_framebuffer_clear(GPUFrameBuffer *fb,
@@ -184,6 +204,9 @@ void GPU_framebuffer_clear(GPUFrameBuffer *fb,
#define GPU_framebuffer_clear_color_depth_stencil(fb, col, depth, stencil) \
GPU_framebuffer_clear(fb, GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT, col, depth, stencil)
+/**
+ * Clear all textures attached to this frame-buffer with a different color.
+ */
void GPU_framebuffer_multi_clear(GPUFrameBuffer *fb, const float (*clear_cols)[4]);
void GPU_framebuffer_read_depth(
@@ -198,6 +221,9 @@ void GPU_framebuffer_read_color(GPUFrameBuffer *fb,
eGPUDataFormat format,
void *data);
+/**
+ * Read_slot and write_slot are only used for color buffers.
+ */
void GPU_framebuffer_blit(GPUFrameBuffer *fb_read,
int read_slot,
GPUFrameBuffer *fb_write,
@@ -233,6 +259,9 @@ int GPU_offscreen_width(const GPUOffScreen *ofs);
int GPU_offscreen_height(const GPUOffScreen *ofs);
struct GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs);
+/**
+ * \note only to be used by viewport code!
+ */
void GPU_offscreen_viewport_data_get(GPUOffScreen *ofs,
GPUFrameBuffer **r_fb,
struct GPUTexture **r_color,
diff --git a/source/blender/gpu/GPU_immediate.h b/source/blender/gpu/GPU_immediate.h
index edb7c9fe5b5..1b288d19c4a 100644
--- a/source/blender/gpu/GPU_immediate.h
+++ b/source/blender/gpu/GPU_immediate.h
@@ -39,7 +39,7 @@ extern "C" {
/** Returns a cleared vertex format, ready for #add_attr. */
GPUVertFormat *immVertexFormat(void);
-/** Every immBegin must have a program bound first. */
+/** Every #immBegin must have a program bound first. */
void immBindShader(GPUShader *shader);
/** Call after your last immEnd, or before binding another program. */
void immUnbindProgram(void);
@@ -50,10 +50,12 @@ void immBegin(GPUPrimType, uint vertex_len);
void immBeginAtMost(GPUPrimType, uint max_vertex_len);
void immEnd(void); /* finishes and draws. */
-/* immBegin a batch, then use standard immFunctions as usual. */
-/* immEnd will finalize the batch instead of drawing. */
-/* Then you can draw it as many times as you like!
+/* - #immBegin a batch, then use standard `imm*` functions as usual.
+ * - #immEnd will finalize the batch instead of drawing.
+ *
+ * Then you can draw it as many times as you like!
* Partially replaces the need for display lists. */
+
GPUBatch *immBeginBatch(GPUPrimType, uint vertex_len);
GPUBatch *immBeginBatchAtMost(GPUPrimType, uint vertex_len);
@@ -81,12 +83,14 @@ void immAttr4ub(uint attr_id, unsigned char r, unsigned char g, unsigned char b,
void immAttr3ubv(uint attr_id, const unsigned char data[3]);
void immAttr4ubv(uint attr_id, const unsigned char data[4]);
-/* Explicitly skip an attribute. */
-/* This advanced option kills automatic value copying for this attr_id. */
+/* Explicitly skip an attribute.
+ * This advanced option kills automatic value copying for this attr_id. */
+
void immAttrSkip(uint attr_id);
-/* Provide one last attribute value & end the current vertex. */
-/* This is most often used for 2D or 3D position (similar to glVertex). */
+/* Provide one last attribute value & end the current vertex.
+ * This is most often used for 2D or 3D position (similar to #glVertex). */
+
void immVertex2f(uint attr_id, float x, float y);
void immVertex3f(uint attr_id, float x, float y, float z);
void immVertex4f(uint attr_id, float x, float y, float z, float w);
@@ -101,6 +105,7 @@ void immVertex3fv(uint attr_id, const float data[3]);
void immVertex2iv(uint attr_id, const int data[2]);
/* Provide uniform values that don't change for the entire draw call. */
+
void immUniform1i(const char *name, int x);
void immUniform1f(const char *name, float x);
void immUniform2f(const char *name, float x, float y);
@@ -109,14 +114,19 @@ void immUniform3f(const char *name, float x, float y, float z);
void immUniform3fv(const char *name, const float data[3]);
void immUniform4f(const char *name, float x, float y, float z, float w);
void immUniform4fv(const char *name, const float data[4]);
+/**
+ * Note array index is not supported for name (i.e: "array[0]").
+ */
void immUniformArray4fv(const char *bare_name, const float *data, int count);
void immUniformMatrix4fv(const char *name, const float data[4][4]);
void immBindTexture(const char *name, GPUTexture *tex);
void immBindTextureSampler(const char *name, GPUTexture *tex, eGPUSamplerState state);
+void immBindUniformBuf(const char *name, GPUUniformBuf *ubo);
/* Convenience functions for setting "uniform vec4 color". */
-/* The rgb functions have implicit alpha = 1.0. */
+/* The RGB functions have implicit alpha = 1.0. */
+
void immUniformColor4f(float r, float g, float b, float a);
void immUniformColor4fv(const float rgba[4]);
void immUniformColor3f(float r, float g, float b);
@@ -135,7 +145,7 @@ void immUniformColor4ubv(const unsigned char rgba[4]);
*/
void immBindBuiltinProgram(eGPUBuiltinShader shader_id);
-/* Extend immUniformColor to take Blender's themes */
+/** Extend #immUniformColor to take Blender's themes. */
void immUniformThemeColor(int color_id);
void immUniformThemeColorAlpha(int color_id, float a);
void immUniformThemeColor3(int color_id);
diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h
index 3ea809d59a7..cd45913158d 100644
--- a/source/blender/gpu/GPU_immediate_util.h
+++ b/source/blender/gpu/GPU_immediate_util.h
@@ -31,32 +31,85 @@ extern "C" {
void immRectf(uint pos, float x1, float y1, float x2, float y2);
void immRecti(uint pos, int x1, int y1, int x2, int y2);
-/* Same as immRectf/immRecti but does not call immBegin/immEnd. To use with GPU_PRIM_TRIS. */
+/**
+ * Same as #immRectf / #immRecti but does not call #immBegin / #immEnd.
+ * To use with #GPU_PRIM_TRIS.
+ */
void immRectf_fast(uint pos, float x1, float y1, float x2, float y2);
void immRectf_fast_with_color(
uint pos, uint col, float x1, float y1, float x2, float y2, const float color[4]);
void immRecti_fast_with_color(
uint pos, uint col, int x1, int y1, int x2, int y2, const float color[4]);
+/**
+ * Pack color into 3 bytes
+ *
+ * This define converts a numerical value to the equivalent 24-bit
+ * color, while not being endian-sensitive. On little-endian, this
+ * is the same as doing a 'naive' indexing, on big-endian, it is not!
+ *
+ * \note BGR format (i.e. 0xBBGGRR)...
+ *
+ * \param x: color.
+ */
void imm_cpack(uint x);
+/**
+ * Draw a circle outline with the given \a radius.
+ * The circle is centered at \a x, \a y and drawn in the XY plane.
+ *
+ * \param shdr_pos: The vertex attribute number for position.
+ * \param x: Horizontal center.
+ * \param y: Vertical center.
+ * \param radius: The circle's radius.
+ * \param nsegments: The number of segments to use in drawing (more = smoother).
+ */
void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments);
+/**
+ * Draw a filled circle with the given \a radius.
+ * The circle is centered at \a x, \a y and drawn in the XY plane.
+ *
+ * \param shdr_pos: The vertex attribute number for position.
+ * \param x: Horizontal center.
+ * \param y: Vertical center.
+ * \param radius: The circle's radius.
+ * \param nsegments: The number of segments to use in drawing (more = smoother).
+ */
void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float radius, int nsegments);
void imm_draw_circle_wire_aspect_2d(
- uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments);
+ uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments);
void imm_draw_circle_fill_aspect_2d(
- uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments);
+ uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments);
-/* use this version when GPUVertFormat has a vec3 position */
+/**
+ * Use this version when #GPUVertFormat has a vec3 position.
+ */
void imm_draw_circle_wire_3d(uint pos, float x, float y, float radius, int nsegments);
void imm_draw_circle_dashed_3d(uint pos, float x, float y, float radius, int nsegments);
void imm_draw_circle_fill_3d(uint pos, float x, float y, float radius, int nsegments);
-/* same as 'imm_draw_disk_partial_fill_2d', except it draws a wire arc. */
+/**
+ * Same as 'imm_draw_disk_partial_fill_2d', except it draws a wire arc.
+ */
void imm_draw_circle_partial_wire_2d(
uint pos, float x, float y, float radius, int nsegments, float start, float sweep);
+/**
+ * Draw a filled arc with the given inner and outer radius.
+ * The circle is centered at \a x, \a y and drawn in the XY plane.
+ *
+ * \note Arguments are `gluPartialDisk` compatible.
+ *
+ * \param pos: The vertex attribute number for position.
+ * \param x: Horizontal center.
+ * \param y: Vertical center.
+ * \param rad_inner: The inner circle's radius.
+ * \param rad_outer: The outer circle's radius (can be zero).
+ * \param nsegments: The number of segments to use in drawing (more = smoother).
+ * \param start: Specifies the starting angle, in degrees, of the disk portion.
+ * \param sweep: Specifies the sweep angle, in degrees, of the disk portion.
+ */
void imm_draw_disk_partial_fill_2d(uint pos,
float x,
float y,
@@ -66,9 +119,21 @@ void imm_draw_disk_partial_fill_2d(uint pos,
float start,
float sweep);
+/**
+ * Draw a lined box.
+ *
+ * \param pos: The vertex attribute number for position.
+ * \param x1: left.
+ * \param y1: bottom.
+ * \param x2: right.
+ * \param y2: top.
+ */
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2);
void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2);
+/**
+ * Draw a standard checkerboard to indicate transparent backgrounds.
+ */
void imm_draw_box_checker_2d_ex(float x1,
float y1,
float x2,
@@ -78,9 +143,25 @@ void imm_draw_box_checker_2d_ex(float x1,
int checker_size);
void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2);
-void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3]);
-void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3]);
+void imm_draw_cube_fill_3d(uint pos, const float center[3], const float aspect[3]);
+void imm_draw_cube_wire_3d(uint pos, const float center[3], const float aspect[3]);
+void imm_draw_cube_corners_3d(uint pos,
+ const float center[3],
+ const float aspect[3],
+ float factor);
+/**
+ * Draw a cylinder. Replacement for #gluCylinder.
+ * \warning Slow, better use it only if you no other choices.
+ *
+ * \param pos: The vertex attribute number for position.
+ * \param nor: The vertex attribute number for normal.
+ * \param base: Specifies the radius of the cylinder at z = 0.
+ * \param top: Specifies the radius of the cylinder at z = height.
+ * \param height: Specifies the height of the cylinder.
+ * \param slices: Specifies the number of subdivisions around the z axis.
+ * \param stacks: Specifies the number of subdivisions along the z axis.
+ */
void imm_draw_cylinder_fill_normal_3d(
uint pos, uint nor, float base, float top, float height, int slices, int stacks);
void imm_draw_cylinder_wire_3d(
@@ -88,6 +169,7 @@ void imm_draw_cylinder_wire_3d(
void imm_draw_cylinder_fill_3d(
uint pos, float base, float top, float height, int slices, int stacks);
+void imm_drawcircball(const float cent[3], float radius, const float tmat[4][4], uint pos);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_index_buffer.h b/source/blender/gpu/GPU_index_buffer.h
index 197077cf76c..0f83e590597 100644
--- a/source/blender/gpu/GPU_index_buffer.h
+++ b/source/blender/gpu/GPU_index_buffer.h
@@ -53,10 +53,12 @@ void GPU_indexbuf_init_ex(GPUIndexBufBuilder *, GPUPrimType, uint index_len, uin
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len);
GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len);
+void GPU_indexbuf_init_build_on_device(GPUIndexBuf *elem, uint index_len);
+
/*
* Thread safe.
*
- * Function inspired by the reduction directives of multithread work APIs..
+ * Function inspired by the reduction directives of multi-thread work API's.
*/
void GPU_indexbuf_join(GPUIndexBufBuilder *builder, const GPUIndexBufBuilder *builder_from);
@@ -82,6 +84,16 @@ void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, GPUIndexBuf *);
void GPU_indexbuf_bind_as_ssbo(GPUIndexBuf *elem, int binding);
+/* Upload data to the GPU (if not built on the device) and bind the buffer to its default target.
+ */
+void GPU_indexbuf_use(GPUIndexBuf *elem);
+
+/* Partially update the GPUIndexBuf which was already sent to the device, or built directly on the
+ * device. The data needs to be compatible with potential compression applied to the original
+ * indices when the index buffer was built, i.e., if the data was compressed to use shorts instead
+ * of ints, shorts should passed here. */
+void GPU_indexbuf_update_sub(GPUIndexBuf *elem, uint start, uint len, const void *data);
+
/* Create a sub-range of an existing index-buffer. */
GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length);
void GPU_indexbuf_create_subrange_in_place(GPUIndexBuf *elem,
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 2dd9af84e93..6e3598703a2 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -24,6 +24,7 @@
#pragma once
#include "DNA_customdata_types.h" /* for CustomDataType */
+#include "DNA_image_types.h"
#include "DNA_listBase.h"
#include "BLI_sys_types.h" /* for bool */
@@ -55,7 +56,7 @@ typedef struct GPUMaterial GPUMaterial;
typedef struct GPUNode GPUNode;
typedef struct GPUNodeLink GPUNodeLink;
-/* Functions to create GPU Materials nodes */
+/* Functions to create GPU Materials nodes. */
typedef enum eGPUType {
/* Keep in sync with GPU_DATATYPE_STR */
@@ -181,7 +182,7 @@ bool GPU_stack_eval_link(GPUMaterial *material,
GPUNodeLink *GPU_uniformbuf_link_out(struct GPUMaterial *mat,
struct bNode *node,
struct GPUNodeStack *stack,
- const int index);
+ int index);
void GPU_material_output_surface(GPUMaterial *material, GPUNodeLink *link);
void GPU_material_output_volume(GPUMaterial *material, GPUNodeLink *link);
@@ -194,15 +195,25 @@ void GPU_material_add_closure_eval(GPUMaterial *material,
const GPUNodeLink *weight_link,
const GPUNodeLink *eval_link);
-/* High level functions to create and use GPU materials */
+/**
+ * High level functions to create and use GPU materials.
+ */
+GPUMaterial *GPU_material_from_nodetree_find(struct ListBase *gpumaterials,
+ const void *engine_type,
+ int options);
+/**
+ * \note Caller must use #GPU_material_from_nodetree_find to re-use existing materials,
+ * This is enforced since constructing other arguments to this function may be expensive
+ * so only do this when they are needed.
+ */
GPUMaterial *GPU_material_from_nodetree(struct Scene *scene,
struct Material *ma,
struct bNodeTree *ntree,
struct ListBase *gpumaterials,
const char *name,
- const uint64_t shader_uuid,
- const bool is_volume_shader,
- const bool is_lookdev,
+ uint64_t shader_uuid,
+ bool is_volume_shader,
+ bool is_lookdev,
GPUCodegenCallbackFn callback,
void *thunk);
@@ -214,11 +225,22 @@ void GPU_materials_free(struct Main *bmain);
struct Scene *GPU_material_scene(GPUMaterial *material);
struct GPUPass *GPU_material_get_pass(GPUMaterial *material);
struct GPUShader *GPU_material_get_shader(GPUMaterial *material);
+/**
+ * Return can be NULL if it's a world material.
+ */
struct Material *GPU_material_get_material(GPUMaterial *material);
+/**
+ * Return true if the material compilation has not yet begin or begin.
+ */
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat);
void GPU_material_status_set(GPUMaterial *mat, eGPUMaterialStatus status);
struct GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material);
+/**
+ * Create dynamic UBO from parameters
+ *
+ * \param inputs: Items are #LinkData, data is #GPUInput (`BLI_genericNodeN(GPUInput)`).
+ */
void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs);
struct GPUUniformBuf *GPU_material_create_sss_profile_ubo(void);
@@ -247,7 +269,8 @@ typedef struct GPUMaterialAttribute {
typedef struct GPUMaterialTexture {
struct GPUMaterialTexture *next, *prev;
struct Image *ima;
- struct ImageUser *iuser;
+ struct ImageUser iuser;
+ bool iuser_available;
struct GPUTexture **colorband;
char sampler_name[32]; /* Name of sampler in GLSL. */
char tiled_mapping_name[32]; /* Name of tile mapping sampler in GLSL. */
diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h
index edf16f04349..bfd4a14d112 100644
--- a/source/blender/gpu/GPU_matrix.h
+++ b/source/blender/gpu/GPU_matrix.h
@@ -31,7 +31,10 @@ extern "C" {
struct GPUShader;
-void GPU_matrix_reset(void); /* to Identity transform & empty stack */
+/**
+ * To Identity transform & empty stack.
+ */
+void GPU_matrix_reset(void);
/* ModelView Matrix (2D or 3D) */
@@ -52,9 +55,13 @@ void GPU_matrix_translate_3fv(const float vec[3]);
void GPU_matrix_scale_3f(float x, float y, float z);
void GPU_matrix_scale_3fv(const float vec[3]);
-/* Axis of rotation should be a unit vector. */
+/**
+ * Axis of rotation should be a unit vector.
+ */
void GPU_matrix_rotate_3f(float deg, float x, float y, float z);
-/* Axis of rotation should be a unit vector. */
+/**
+ * Axis of rotation should be a unit vector.
+ */
void GPU_matrix_rotate_3fv(float deg, const float axis[3]);
void GPU_matrix_rotate_axis(float deg, char axis); /* TODO: enum for axis? */
@@ -78,12 +85,12 @@ void GPU_matrix_scale_2f(float x, float y);
void GPU_matrix_scale_2fv(const float vec[2]);
void GPU_matrix_rotate_2d(float deg);
-/* Projection Matrix (2D or 3D) */
+/* Projection Matrix (2D or 3D). */
void GPU_matrix_push_projection(void);
void GPU_matrix_pop_projection(void);
-/* 3D Projection Matrix */
+/* 3D Projection Matrix. */
void GPU_matrix_identity_projection_set(void);
void GPU_matrix_projection_set(const float m[4][4]);
@@ -136,11 +143,12 @@ bool GPU_matrix_unproject_3fv(const float win[3],
const int view[4],
float r_world[3]);
-/* 2D Projection Matrix */
+/* 2D Projection Matrix. */
void GPU_matrix_ortho_2d_set(float left, float right, float bottom, float top);
-/* functions to get matrix values */
+/* Functions to get matrix values. */
+
const float (*GPU_matrix_model_view_get(float m[4][4]))[4];
const float (*GPU_matrix_projection_get(float m[4][4]))[4];
const float (*GPU_matrix_model_view_projection_get(float m[4][4]))[4];
@@ -148,12 +156,19 @@ const float (*GPU_matrix_model_view_projection_get(float m[4][4]))[4];
const float (*GPU_matrix_normal_get(float m[3][3]))[3];
const float (*GPU_matrix_normal_inverse_get(float m[3][3]))[3];
-/* set uniform values for currently bound shader */
+/**
+ * Set uniform values for currently bound shader.
+ */
void GPU_matrix_bind(struct GPUShader *shader);
bool GPU_matrix_dirty_get(void); /* since last bind */
-/* own working polygon offset */
+/**
+ * Own working polygon offset.
+ */
float GPU_polygon_offset_calc(const float (*winmat)[4], float viewdist, float dist);
+/**
+ * \note \a viewdist is only for orthographic projections at the moment.
+ */
void GPU_polygon_offset(float viewdist, float dist);
/* Python API needs to be able to inspect the stack so errors raise exceptions
diff --git a/source/blender/gpu/GPU_platform.h b/source/blender/gpu/GPU_platform.h
index fa7d5d7fba8..0d80c0ed8af 100644
--- a/source/blender/gpu/GPU_platform.h
+++ b/source/blender/gpu/GPU_platform.h
@@ -66,7 +66,10 @@ typedef enum eGPUSupportLevel {
extern "C" {
#endif
+/* GPU Types */
+
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver);
+
eGPUSupportLevel GPU_platform_support_level(void);
const char *GPU_platform_vendor(void);
const char *GPU_platform_renderer(void);
diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h
index d28363253b1..c02af763311 100644
--- a/source/blender/gpu/GPU_select.h
+++ b/source/blender/gpu/GPU_select.h
@@ -31,7 +31,7 @@ extern "C" {
struct rcti;
-/* flags for mode of operation */
+/** Flags for mode of operation. */
enum {
GPU_SELECT_ALL = 1,
/* gpu_select_query */
@@ -42,21 +42,48 @@ enum {
GPU_SELECT_PICK_NEAREST = 5,
};
+/**
+ * Initialize and provide buffer for results.
+ */
void GPU_select_begin(
unsigned int *buffer, unsigned int bufsize, const struct rcti *input, char mode, int oldhits);
+/**
+ * Loads a new selection id and ends previous query, if any.
+ * In second pass of selection it also returns
+ * if id has been hit on the first pass already.
+ * Thus we can skip drawing un-hit objects.
+ *
+ * \warning We rely on the order of object rendering on passes to be the same for this to work.
+ */
bool GPU_select_load_id(unsigned int id);
void GPU_select_finalize(void);
+/**
+ * Cleanup and flush selection results to buffer.
+ * Return number of hits and hits in buffer.
+ * if \a dopass is true, we will do a second pass with occlusion queries to get the closest hit.
+ */
unsigned int GPU_select_end(void);
-/* cache selection region */
+/* Cache selection region. */
+
bool GPU_select_is_cached(void);
void GPU_select_cache_begin(void);
void GPU_select_cache_load_id(void);
void GPU_select_cache_end(void);
-/* utilities */
+/* Utilities. */
+
+/**
+ * Helper function, nothing special but avoids doing inline since hits aren't sorted by depth
+ * and purpose of 4x buffer indices isn't so clear.
+ *
+ * Note that comparing depth as uint is fine.
+ */
const uint *GPU_select_buffer_near(const uint *buffer, int hits);
uint GPU_select_buffer_remove_by_id(uint *buffer, int hits, uint select_id);
+/**
+ * Part of the solution copied from `rect_subregion_stride_calc`.
+ */
void GPU_select_buffer_stride_realign(const struct rcti *src, const struct rcti *dst, uint *r_buf);
#ifdef __cplusplus
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index b9077dfc783..564a02bd068 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -30,6 +30,8 @@ extern "C" {
struct GPUIndexBuf;
struct GPUVertBuf;
+/** Opaque type hiding #blender::gpu::shader::ShaderCreateInfo */
+typedef struct GPUShaderCreateInfo GPUShaderCreateInfo;
/** Opaque type hiding #blender::gpu::Shader */
typedef struct GPUShader GPUShader;
@@ -70,14 +72,36 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
const char *computecode,
const char *libcode,
const char *defines,
- const eGPUShaderTFBType tf_type,
+ eGPUShaderTFBType tf_type,
const char **tf_names,
- const int tf_count,
+ int tf_count,
const char *shname);
+GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info);
+GPUShader *GPU_shader_create_from_info_name(const char *info_name);
struct GPU_ShaderCreateFromArray_Params {
const char **vert, **geom, **frag, **defs;
};
+/**
+ * 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, const char *func, int line);
@@ -96,10 +120,13 @@ void GPU_shader_unbind(void);
const char *GPU_shader_get_name(GPUShader *shader);
-/* Returns true if transform feedback was successfully enabled. */
+/**
+ * Returns true if transform feedback was successfully enabled.
+ */
bool GPU_shader_transform_feedback_enable(GPUShader *shader, struct GPUVertBuf *vertbuf);
void GPU_shader_transform_feedback_disable(GPUShader *shader);
+/** DEPRECATED: Kept only because of BGL API. */
int GPU_shader_get_program(GPUShader *shader);
typedef enum {
@@ -130,9 +157,14 @@ typedef enum {
} GPUUniformBuiltin;
typedef enum {
+ /** Deprecated */
GPU_UNIFORM_BLOCK_VIEW = 0, /* viewBlock */
GPU_UNIFORM_BLOCK_MODEL, /* modelBlock */
GPU_UNIFORM_BLOCK_INFO, /* infoBlock */
+ /** New ones */
+ GPU_UNIFORM_BLOCK_DRW_VIEW,
+ GPU_UNIFORM_BLOCK_DRW_MODEL,
+ GPU_UNIFORM_BLOCK_DRW_INFOS,
GPU_NUM_UNIFORM_BLOCKS, /* Special value, denotes number of builtin uniforms block. */
} GPUUniformBlockBuiltin;
@@ -149,6 +181,7 @@ int GPU_shader_get_uniform(GPUShader *shader, const char *name);
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin);
int GPU_shader_get_builtin_block(GPUShader *shader, int builtin);
int GPU_shader_get_builtin_ssbo(GPUShader *shader, int builtin);
+/** DEPRECATED: Kept only because of Python GPU API. */
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name);
int GPU_shader_get_ssbo(GPUShader *shader, const char *name);
@@ -274,15 +307,16 @@ typedef enum eGPUBuiltinShader {
GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE,
GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE,
GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR,
- /* points */
/**
- * Draw round points with a hardcoded size.
- * Take a single color for all the vertices and a 2D position for each vertex.
+ * Draw texture with alpha. Take a 3D position and a 2D texture coordinate for each vertex.
*
- * \param color: uniform vec4
- * \param pos: in vec2
+ * \param alpha: uniform float
+ * \param image: uniform sampler2D
+ * \param texCoord: in vec2
+ * \param pos: in vec3
*/
- GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR,
+ GPU_SHADER_3D_IMAGE_MODULATE_ALPHA,
+ /* points */
/**
* Draw round points with a constant size.
* Take a single color for all the vertices and a 2D position for each vertex.
@@ -304,34 +338,6 @@ typedef enum eGPUBuiltinShader {
*/
GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA,
/**
- * Draw round points with a constant size and an outline.
- * Take a 2D position and a color for each vertex.
- *
- * \param size: uniform float
- * \param outlineWidth: uniform float
- * \param outlineColor: uniform vec4
- * \param color: in vec4
- * \param pos: in vec2
- */
- GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA,
- /**
- * Draw round points with a constant size and an outline.
- * Take a 2D position and a color for each vertex.
- *
- * \param size: in float
- * \param color: in vec4
- * \param pos: in vec2
- */
- GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR,
- /**
- * Draw round points with a hardcoded size.
- * Take a single color for all the vertices and a 3D position for each vertex.
- *
- * \param color: uniform vec4
- * \param pos: in vec3
- */
- GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR,
- /**
* Draw round points with a hardcoded size.
* Take a single color for all the vertices and a 3D position for each vertex.
*
@@ -350,26 +356,6 @@ typedef enum eGPUBuiltinShader {
GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA,
/**
* Draw round points with a constant size and an outline.
- * Take a single color for all the vertices and a 3D position for each vertex.
- *
- * \param size: uniform float
- * \param outlineWidth: uniform float
- * \param color: uniform vec4
- * \param outlineColor: uniform vec4
- * \param pos: in vec3
- */
- GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA,
- /**
- * Draw round points with a constant size and an outline.
- * Take a single color for all the vertices and a 3D position for each vertex.
- *
- * \param color: uniform vec4
- * \param size: in float
- * \param pos: in vec3
- */
- GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR,
- /**
- * Draw round points with a constant size and an outline.
* Take a 3D position and a color for each vertex.
*
* \param size: in float
@@ -385,23 +371,14 @@ typedef enum eGPUBuiltinShader {
/* grease pencil drawing */
GPU_SHADER_GPENCIL_STROKE,
/* specialized for widget drawing */
- GPU_SHADER_2D_AREA_EDGES,
+ GPU_SHADER_2D_AREA_BORDERS,
GPU_SHADER_2D_WIDGET_BASE,
GPU_SHADER_2D_WIDGET_BASE_INST,
GPU_SHADER_2D_WIDGET_SHADOW,
GPU_SHADER_2D_NODELINK,
GPU_SHADER_2D_NODELINK_INST,
- /* specialized for edituv drawing */
- GPU_SHADER_2D_UV_UNIFORM_COLOR,
- GPU_SHADER_2D_UV_VERTS,
- GPU_SHADER_2D_UV_FACEDOTS,
- GPU_SHADER_2D_UV_EDGES,
- GPU_SHADER_2D_UV_EDGES_SMOOTH,
- GPU_SHADER_2D_UV_FACES,
- GPU_SHADER_2D_UV_FACES_STRETCH_AREA,
- GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE,
} eGPUBuiltinShader;
-#define GPU_SHADER_BUILTIN_LEN (GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE + 1)
+#define GPU_SHADER_BUILTIN_LEN (GPU_SHADER_2D_NODELINK_INST + 1)
/** Support multiple configurations. */
typedef enum eGPUShaderConfig {
diff --git a/source/blender/gpu/GPU_shader_shared.h b/source/blender/gpu/GPU_shader_shared.h
new file mode 100644
index 00000000000..eeca7ee6caa
--- /dev/null
+++ b/source/blender/gpu/GPU_shader_shared.h
@@ -0,0 +1,84 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#ifndef USE_GPU_SHADER_CREATE_INFO
+# include "intern/gpu_shader_shared_utils.h"
+#endif
+
+struct NodeLinkData {
+ float4 colors[3];
+ /* bezierPts Is actually a float2, but due to std140 each element needs to be aligned to 16
+ * bytes. */
+ float4 bezierPts[4];
+ bool1 doArrow;
+ bool1 doMuted;
+ float dim_factor;
+ float thickness;
+ float dash_factor;
+ float dash_alpha;
+ float expandSize;
+ float arrowSize;
+};
+BLI_STATIC_ASSERT_ALIGN(struct NodeLinkData, 16)
+
+struct NodeLinkInstanceData {
+ float4 colors[6];
+ float expandSize;
+ float arrowSize;
+ float2 _pad;
+};
+BLI_STATIC_ASSERT_ALIGN(struct NodeLinkInstanceData, 16)
+
+struct GPencilStrokeData {
+ float2 viewport;
+ float pixsize;
+ float objscale;
+ float pixfactor;
+ int xraymode;
+ int caps_start;
+ int caps_end;
+ bool1 keep_size;
+ bool1 fill_stroke;
+ float2 _pad;
+};
+BLI_STATIC_ASSERT_ALIGN(struct GPencilStrokeData, 16)
+
+struct GPUClipPlanes {
+ float4x4 ModelMatrix;
+ float4 world[6];
+};
+BLI_STATIC_ASSERT_ALIGN(struct GPUClipPlanes, 16)
+
+struct SimpleLightingData {
+ float4 color;
+ float3 light;
+ float _pad;
+};
+BLI_STATIC_ASSERT_ALIGN(struct SimpleLightingData, 16)
+
+#define MAX_CALLS 16
+
+struct MultiRectCallData {
+ float4 calls_data[MAX_CALLS * 3];
+};
+BLI_STATIC_ASSERT_ALIGN(struct MultiRectCallData, 16)
diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h
index f92860deab0..bd52b8321bb 100644
--- a/source/blender/gpu/GPU_state.h
+++ b/source/blender/gpu/GPU_state.h
@@ -43,21 +43,23 @@ typedef enum eGPUBarrier {
GPU_BARRIER_SHADER_STORAGE = (1 << 3),
GPU_BARRIER_TEXTURE_FETCH = (1 << 4),
GPU_BARRIER_TEXTURE_UPDATE = (1 << 5),
+ GPU_BARRIER_VERTEX_ATTRIB_ARRAY = (1 << 6),
+ GPU_BARRIER_ELEMENT_ARRAY = (1 << 7),
} eGPUBarrier;
-ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_TEXTURE_UPDATE)
+ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_ELEMENT_ARRAY)
/**
* Defines the fixed pipeline blending equation.
* SRC is the output color from the shader.
* DST is the color from the frame-buffer.
- * The blending equation is :
- * (SRC * A) + (DST * B).
+ * The blending equation is:
+ * `(SRC * A) + (DST * B)`.
* The blend mode will modify the A and B parameters.
*/
typedef enum eGPUBlend {
GPU_BLEND_NONE = 0,
- /** Premult variants will _NOT_ multiply rgb output by alpha. */
+ /** Pre-multiply variants will _NOT_ multiply rgb output by alpha. */
GPU_BLEND_ALPHA,
GPU_BLEND_ALPHA_PREMULT,
GPU_BLEND_ADDITIVE,
@@ -127,10 +129,23 @@ void GPU_front_facing(bool invert);
void GPU_depth_range(float near, float far);
void GPU_scissor_test(bool enable);
void GPU_line_smooth(bool enable);
+/**
+ * \note By convention, this is set as needed and not reset back to 1.0.
+ * This means code that draws lines must always set the line width beforehand,
+ * but is not expected to restore it's previous value.
+ */
void GPU_line_width(float width);
void GPU_logic_op_xor_set(bool enable);
void GPU_point_size(float size);
void GPU_polygon_smooth(bool enable);
+
+/**
+ * Programmable point size:
+ * - Shaders set their own point size when enabled
+ * - Use GPU_point_size when disabled.
+ *
+ * TODO: remove and use program point size everywhere.
+ */
void GPU_program_point_size(bool enable);
void GPU_scissor(int x, int y, int width, int height);
void GPU_scissor_get(int coords[4]);
@@ -161,6 +176,9 @@ eGPUDepthTest GPU_depth_test_get(void);
eGPUWriteMask GPU_write_mask_get(void);
uint GPU_stencil_mask_get(void);
eGPUStencilTest GPU_stencil_test_get(void);
+/**
+ * \note Already pre-multiplied by `U.pixelsize`.
+ */
float GPU_line_width_get(void);
void GPU_flush(void);
@@ -168,6 +186,10 @@ void GPU_finish(void);
void GPU_apply_state(void);
void GPU_bgl_start(void);
+
+/**
+ * Just turn off the `bgl` safeguard system. Can be called even without #GPU_bgl_start.
+ */
void GPU_bgl_end(void);
bool GPU_bgl_get(void);
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index deff9e47871..d65115541fa 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -32,7 +32,8 @@ struct GPUVertBuf;
/** Opaque type hiding blender::gpu::Texture. */
typedef struct GPUTexture GPUTexture;
-/* GPU Samplers state
+/**
+ * GPU Samplers state
* - Specify the sampler state to bind a texture with.
* - Internally used by textures.
* - All states are created at startup to avoid runtime costs.
@@ -60,8 +61,9 @@ typedef enum eGPUSamplerState {
} \
} while (0)
-/* `GPU_SAMPLER_MAX` is not a valid enum value, but only a limit.
- * It also creates a bad mask for the `NOT` operator in `ENUM_OPERATORS`.
+/**
+ * #GPU_SAMPLER_MAX is not a valid enum value, but only a limit.
+ * It also creates a bad mask for the `NOT` operator in #ENUM_OPERATORS.
*/
static const int GPU_SAMPLER_MAX = (GPU_SAMPLER_ICON + 1);
ENUM_OPERATORS(eGPUSamplerState, GPU_SAMPLER_ICON)
@@ -70,6 +72,9 @@ ENUM_OPERATORS(eGPUSamplerState, GPU_SAMPLER_ICON)
extern "C" {
#endif
+/**
+ * Update user defined sampler states.
+ */
void GPU_samplers_update(void);
/* GPU Texture
@@ -84,11 +89,13 @@ void GPU_samplers_update(void);
* - if created with from_blender, will not free the texture
*/
-/* Wrapper to supported OpenGL/Vulkan texture internal storage
+/**
+ * Wrapper to supported OpenGL/Vulkan texture internal storage
* If you need a type just un-comment it. Be aware that some formats
* are not supported by render-buffers. All of the following formats
* are part of the OpenGL 3.3 core
- * specification. */
+ * specification.
+ */
typedef enum eGPUTextureFormat {
/* Formats texture & render-buffer. */
GPU_RGBA8UI,
@@ -221,12 +228,19 @@ GPUTexture *GPU_texture_create_cube_array(
const char *name, int w, int d, int mip_len, eGPUTextureFormat format, const float *data);
/* Special textures. */
+
GPUTexture *GPU_texture_create_from_vertbuf(const char *name, struct GPUVertBuf *vert);
/**
* \a data should hold all the data for all mipmaps.
*/
+/**
+ * DDS texture loading. Return NULL if support is not available.
+ */
GPUTexture *GPU_texture_create_compressed_2d(
const char *name, int w, int h, int miplen, eGPUTextureFormat format, const void *data);
+/**
+ * Create an error texture that will bind an invalid texture (pink) at draw time.
+ */
GPUTexture *GPU_texture_create_error(int dimension, bool array);
void GPU_texture_update_mipmap(GPUTexture *tex,
@@ -234,6 +248,9 @@ void GPU_texture_update_mipmap(GPUTexture *tex,
eGPUDataFormat gpu_data_format,
const void *pixels);
+/**
+ * \note Updates only mip 0.
+ */
void GPU_texture_update(GPUTexture *tex, eGPUDataFormat data_format, const void *data);
void GPU_texture_update_sub(GPUTexture *tex,
eGPUDataFormat data_format,
@@ -244,16 +261,27 @@ void GPU_texture_update_sub(GPUTexture *tex,
int width,
int height,
int depth);
+/**
+ * Makes data interpretation aware of the source layout.
+ * Skipping pixels correctly when changing rows when doing partial update.
+ */
void GPU_unpack_row_length_set(uint len);
void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat data_format, int miplvl);
+/**
+ * Fills the whole texture with the same data for all pixels.
+ * \warning Only work for 2D texture for now.
+ * \warning Only clears the mip 0 of the texture.
+ * \param data_format: data format of the pixel data.
+ * \param data: 1 pixel worth of data to fill the texture with.
+ */
void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data);
void GPU_texture_free(GPUTexture *tex);
void GPU_texture_ref(GPUTexture *tex);
void GPU_texture_bind(GPUTexture *tex, int unit);
-void GPU_texture_bind_ex(GPUTexture *tex, eGPUSamplerState state, int unit, const bool set_number);
+void GPU_texture_bind_ex(GPUTexture *tex, eGPUSamplerState state, int unit, bool set_number);
void GPU_texture_unbind(GPUTexture *tex);
void GPU_texture_unbind_all(void);
@@ -261,6 +289,9 @@ void GPU_texture_image_bind(GPUTexture *tex, int unit);
void GPU_texture_image_unbind(GPUTexture *tex);
void GPU_texture_image_unbind_all(void);
+/**
+ * Copy a texture content to a similar texture. Only MIP 0 is copied.
+ */
void GPU_texture_copy(GPUTexture *dst, GPUTexture *src);
void GPU_texture_generate_mipmap(GPUTexture *tex);
@@ -292,7 +323,8 @@ int GPU_texture_opengl_bindcode(const GPUTexture *tex);
void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size);
-/* utilities */
+/* Utilities. */
+
size_t GPU_texture_component_len(eGPUTextureFormat format);
size_t GPU_texture_dataformat_size(eGPUDataFormat data_format);
diff --git a/source/blender/gpu/GPU_uniform_buffer.h b/source/blender/gpu/GPU_uniform_buffer.h
index 4efac0a8c00..c9ea1582ad4 100644
--- a/source/blender/gpu/GPU_uniform_buffer.h
+++ b/source/blender/gpu/GPU_uniform_buffer.h
@@ -40,6 +40,12 @@ struct ListBase;
typedef struct GPUUniformBuf GPUUniformBuf;
GPUUniformBuf *GPU_uniformbuf_create_ex(size_t size, const void *data, const char *name);
+/**
+ * Create UBO from inputs list.
+ * Return NULL if failed to create or if \param inputs: is empty.
+ *
+ * \param inputs: ListBase of #BLI_genericNodeN(#GPUInput).
+ */
GPUUniformBuf *GPU_uniformbuf_create_from_list(struct ListBase *inputs, const char *name);
#define GPU_uniformbuf_create(size) GPU_uniformbuf_create_ex(size, NULL, __func__);
diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h
index abe49bb02fa..43a8e7fc4cb 100644
--- a/source/blender/gpu/GPU_vertex_buffer.h
+++ b/source/blender/gpu/GPU_vertex_buffer.h
@@ -79,39 +79,61 @@ GPUVertBuf *GPU_vertbuf_create_with_format_ex(const GPUVertFormat *, GPUUsageTyp
*/
const void *GPU_vertbuf_read(GPUVertBuf *verts);
void *GPU_vertbuf_unmap(const GPUVertBuf *verts, const void *mapped_data);
+/** Same as discard but does not free. */
void GPU_vertbuf_clear(GPUVertBuf *verts);
void GPU_vertbuf_discard(GPUVertBuf *);
-/* Avoid GPUVertBuf datablock being free but not its data. */
+/**
+ * Avoid GPUVertBuf data-block being free but not its data.
+ */
void GPU_vertbuf_handle_ref_add(GPUVertBuf *verts);
void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts);
void GPU_vertbuf_init_with_format_ex(GPUVertBuf *, const GPUVertFormat *, GPUUsageType);
+void GPU_vertbuf_init_build_on_device(GPUVertBuf *verts, GPUVertFormat *format, uint v_len);
+
#define GPU_vertbuf_init_with_format(verts, format) \
GPU_vertbuf_init_with_format_ex(verts, format, GPU_USAGE_STATIC)
GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts);
+/**
+ * Create a new allocation, discarding any existing data.
+ */
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len);
+/**
+ * Resize buffer keeping existing data.
+ */
void GPU_vertbuf_data_resize(GPUVertBuf *, uint v_len);
+/**
+ * Set vertex count but does not change allocation.
+ * Only this many verts will be uploaded to the GPU and rendered.
+ * This is useful for streaming data.
+ */
void GPU_vertbuf_data_len_set(GPUVertBuf *, uint v_len);
-/* The most important #set_attr variant is the untyped one. Get it right first.
+/**
+ * The most important #set_attr variant is the untyped one. Get it right first.
* It takes a void* so the app developer is responsible for matching their app data types
* to the vertex attribute's type and component count. They're in control of both, so this
- * should not be a problem. */
-
+ * should not be a problem.
+ */
void GPU_vertbuf_attr_set(GPUVertBuf *, uint a_idx, uint v_idx, const void *data);
+/** Fills a whole vertex (all attributes). Data must match packed layout. */
void GPU_vertbuf_vert_set(GPUVertBuf *verts, uint v_idx, const void *data);
-/* Tightly packed, non interleaved input data. */
+/**
+ * Tightly packed, non interleaved input data.
+ */
void GPU_vertbuf_attr_fill(GPUVertBuf *, uint a_idx, const void *data);
void GPU_vertbuf_attr_fill_stride(GPUVertBuf *, uint a_idx, uint stride, const void *data);
-/* For low level access only */
+/**
+ * For low level access only.
+ */
typedef struct GPUVertBufRaw {
uint size;
uint stride;
@@ -138,19 +160,36 @@ GPU_INLINE uint GPU_vertbuf_raw_used(GPUVertBufRaw *a)
void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *, uint a_idx, GPUVertBufRaw *access);
+/**
+ * Returns the data buffer and set it to null internally to avoid freeing.
+ * \note Be careful when using this. The data needs to match the expected format.
+ */
void *GPU_vertbuf_steal_data(GPUVertBuf *verts);
-void *GPU_vertbuf_get_data(GPUVertBuf *verts);
+/**
+ * \note Be careful when using this. The data needs to match the expected format.
+ */
+void *GPU_vertbuf_get_data(const GPUVertBuf *verts);
const GPUVertFormat *GPU_vertbuf_get_format(const GPUVertBuf *verts);
uint GPU_vertbuf_get_vertex_alloc(const GPUVertBuf *verts);
uint GPU_vertbuf_get_vertex_len(const GPUVertBuf *verts);
GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts);
+void GPU_vertbuf_tag_dirty(GPUVertBuf *verts);
+/**
+ * Should be rename to #GPU_vertbuf_data_upload.
+ */
void GPU_vertbuf_use(GPUVertBuf *);
void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding);
-/* XXX do not use. */
-void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data);
+void GPU_vertbuf_wrap_handle(GPUVertBuf *verts, uint64_t handle);
+
+/**
+ * XXX: do not use!
+ * This is just a wrapper for the use of the Hair refine workaround.
+ * To be used with #GPU_vertbuf_use().
+ */
+void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, const void *data);
/* Metrics */
uint GPU_vertbuf_get_memory_usage(void);
diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h
index 0d5388c6b82..4af9901a88c 100644
--- a/source/blender/gpu/GPU_vertex_format.h
+++ b/source/blender/gpu/GPU_vertex_format.h
@@ -113,8 +113,33 @@ uint GPU_vertformat_attr_add(
GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode);
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias);
+/**
+ * Makes vertex attribute from the next vertices to be accessible in the vertex shader.
+ * For an attribute named "attr" you can access the next nth vertex using "attr{number}".
+ * Use this function after specifying all the attributes in the format.
+ *
+ * NOTE: This does NOT work when using indexed rendering.
+ * NOTE: Only works for first attribute name. (this limitation can be changed if needed)
+ *
+ * WARNING: this function creates a lot of aliases/attributes, make sure to keep the attribute
+ * name short to avoid overflowing the name-buffer.
+ */
void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count);
+/**
+ * Make attribute layout non-interleaved.
+ * Warning! This does not change data layout!
+ * Use direct buffer access to fill the data.
+ * This is for advanced usage.
+ *
+ * De-interleaved data means all attribute data for each attribute
+ * is stored continuously like this:
+ * 000011112222
+ * instead of:
+ * 012012012012
+ *
+ * \note This is per attribute de-interleaving, NOT per component.
+ */
void GPU_vertformat_deinterleave(GPUVertFormat *format);
int GPU_vertformat_attr_id_get(const GPUVertFormat *, const char *name);
@@ -126,10 +151,16 @@ BLI_INLINE const char *GPU_vertformat_attr_name_get(const GPUVertFormat *format,
return format->names + attr->names[n_idx];
}
-/* WARNING: Can only rename using a string with same character count.
- * WARNING: This removes all other aliases of this attribute. */
+/**
+ * \warning Can only rename using a string with same character count.
+ * \warning This removes all other aliases of this attribute.
+ */
void GPU_vertformat_attr_rename(GPUVertFormat *format, int attr, const char *new_name);
+/**
+ * \warning Always add a prefix to the result of this function as
+ * the generated string can start with a number and not be a valid attribute name.
+ */
void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint max_len);
/* format conversion */
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
index 4d9970dac90..917b87efeaa 100644
--- a/source/blender/gpu/GPU_viewport.h
+++ b/source/blender/gpu/GPU_viewport.h
@@ -40,21 +40,35 @@ extern "C" {
typedef struct GHash GHash;
typedef struct GPUViewport GPUViewport;
-struct GPUFrameBuffer;
+struct DRWData;
struct DefaultFramebufferList;
struct DefaultTextureList;
-struct DRWData;
+struct GPUFrameBuffer;
GPUViewport *GPU_viewport_create(void);
GPUViewport *GPU_viewport_stereo_create(void);
void GPU_viewport_bind(GPUViewport *viewport, int view, const rcti *rect);
void GPU_viewport_unbind(GPUViewport *viewport);
+/**
+ * Merge and draw the buffers of \a viewport into the currently active framebuffer, performing
+ * color transform to display space.
+ *
+ * \param rect: Coordinates to draw into. By swapping min and max values, drawing can be done
+ * with inversed axis coordinates (upside down or sideways).
+ */
void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect);
+/**
+ * Version of #GPU_viewport_draw_to_screen() that lets caller decide if display colorspace
+ * transform should be performed.
+ */
void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
int view,
const rcti *rect,
bool display_colorspace,
bool do_overlay_merge);
+/**
+ * Must be executed inside Draw-manager OpenGL Context.
+ */
void GPU_viewport_free(GPUViewport *viewport);
void GPU_viewport_colorspace_set(GPUViewport *viewport,
@@ -62,7 +76,13 @@ void GPU_viewport_colorspace_set(GPUViewport *viewport,
const ColorManagedDisplaySettings *display_settings,
float dither);
+/**
+ * Should be called from DRW after DRW_opengl_context_enable.
+ */
void GPU_viewport_bind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs);
+/**
+ * Clear vars assigned from offscreen, so we don't free data owned by `GPUOffScreen`.
+ */
void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
struct GPUOffScreen *ofs,
bool display_colorspace,
@@ -70,6 +90,9 @@ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
struct DRWData **GPU_viewport_data_get(GPUViewport *viewport);
+/**
+ * Merge the stereo textures. `color` and `overlay` texture will be modified.
+ */
void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo_format);
void GPU_viewport_tag_update(GPUViewport *viewport);
@@ -82,6 +105,9 @@ GPUTexture *GPU_viewport_color_texture(GPUViewport *viewport, int view);
GPUTexture *GPU_viewport_overlay_texture(GPUViewport *viewport, int view);
GPUTexture *GPU_viewport_depth_texture(GPUViewport *viewport);
+/**
+ * Overlay frame-buffer for drawing outside of DRW module.
+ */
GPUFrameBuffer *GPU_viewport_framebuffer_overlay_get(GPUViewport *viewport);
#ifdef __cplusplus
diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh
index 73792215569..00645f34173 100644
--- a/source/blender/gpu/intern/gpu_backend.hh
+++ b/source/blender/gpu/intern/gpu_backend.hh
@@ -42,24 +42,24 @@ class VertBuf;
class GPUBackend {
public:
- virtual ~GPUBackend(){};
+ virtual ~GPUBackend() = default;
- static GPUBackend *get(void);
+ static GPUBackend *get();
- virtual void samplers_update(void) = 0;
+ virtual void samplers_update() = 0;
virtual void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) = 0;
virtual Context *context_alloc(void *ghost_window) = 0;
- virtual Batch *batch_alloc(void) = 0;
+ virtual Batch *batch_alloc() = 0;
virtual DrawList *drawlist_alloc(int list_length) = 0;
virtual FrameBuffer *framebuffer_alloc(const char *name) = 0;
- virtual IndexBuf *indexbuf_alloc(void) = 0;
- virtual QueryPool *querypool_alloc(void) = 0;
+ virtual IndexBuf *indexbuf_alloc() = 0;
+ virtual QueryPool *querypool_alloc() = 0;
virtual Shader *shader_alloc(const char *name) = 0;
virtual Texture *texture_alloc(const char *name) = 0;
virtual UniformBuf *uniformbuf_alloc(int size, const char *name) = 0;
- virtual VertBuf *vertbuf_alloc(void) = 0;
+ virtual VertBuf *vertbuf_alloc() = 0;
};
} // namespace gpu
diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc
index 0e5c7900da9..2874dea775f 100644
--- a/source/blender/gpu/intern/gpu_batch.cc
+++ b/source/blender/gpu/intern/gpu_batch.cc
@@ -50,7 +50,7 @@ using namespace blender::gpu;
/** \name Creation & Deletion
* \{ */
-GPUBatch *GPU_batch_calloc(void)
+GPUBatch *GPU_batch_calloc()
{
GPUBatch *batch = GPUBackend::get()->batch_alloc();
memset(batch, 0, sizeof(*batch));
@@ -90,7 +90,6 @@ void GPU_batch_init_ex(GPUBatch *batch,
batch->shader = nullptr;
}
-/* This will share the VBOs with the new batch. */
void GPU_batch_copy(GPUBatch *batch_dst, GPUBatch *batch_src)
{
GPU_batch_init_ex(
@@ -137,7 +136,6 @@ void GPU_batch_discard(GPUBatch *batch)
/** \name Buffers Management
* \{ */
-/* NOTE: Override ONLY the first instance vbo (and free them if owned). */
void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo)
{
BLI_assert(inst);
@@ -151,7 +149,6 @@ void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo)
SET_FLAG_FROM_TEST(batch->flag, own_vbo, GPU_BATCH_OWNS_INST_VBO);
}
-/* NOTE: Override any previously assigned elem (and free it if owned). */
void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo)
{
BLI_assert(elem);
@@ -188,7 +185,6 @@ int GPU_batch_instbuf_add_ex(GPUBatch *batch, GPUVertBuf *insts, bool own_vbo)
return -1;
}
-/* Returns the index of verts in the batch. */
int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo)
{
BLI_assert(verts);
@@ -243,7 +239,6 @@ void GPU_batch_draw_range(GPUBatch *batch, int v_first, int v_count)
GPU_batch_draw_advanced(batch, v_first, v_count, 0, 0);
}
-/* Draw multiple instance of a batch without having any instance attributes. */
void GPU_batch_draw_instanced(GPUBatch *batch, int i_count)
{
BLI_assert(batch->inst[0] == nullptr);
@@ -301,9 +296,6 @@ void GPU_batch_program_set_builtin(GPUBatch *batch, eGPUBuiltinShader shader_id)
GPU_batch_program_set_builtin_with_config(batch, shader_id, GPU_SHADER_CFG_DEFAULT);
}
-/* Bind program bound to IMM to the batch.
- * XXX Use this with much care. Drawing with the GPUBatch API is not compatible with IMM.
- * DO NOT DRAW WITH THE BATCH BEFORE CALLING immUnbindProgram. */
void GPU_batch_program_set_imm_shader(GPUBatch *batch)
{
GPU_batch_set_shader(batch, immGetShader());
@@ -315,12 +307,12 @@ void GPU_batch_program_set_imm_shader(GPUBatch *batch)
/** \name Init/Exit
* \{ */
-void gpu_batch_init(void)
+void gpu_batch_init()
{
gpu_batch_presets_init();
}
-void gpu_batch_exit(void)
+void gpu_batch_exit()
{
gpu_batch_presets_exit();
}
diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c
index 6a1645a71d8..b97378ad638 100644
--- a/source/blender/gpu/intern/gpu_batch_presets.c
+++ b/source/blender/gpu/intern/gpu_batch_presets.c
@@ -154,7 +154,6 @@ GPUBatch *GPU_batch_preset_sphere_wire(int lod)
/** \name Create Sphere (3D)
* \{ */
-/* Replacement for gluSphere */
GPUBatch *gpu_batch_sphere(int lat_res, int lon_res)
{
const float lon_inc = 2 * M_PI / lon_res;
@@ -331,7 +330,6 @@ GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize,
return g_presets_2d.batch.panel_drag_widget;
}
-/* To be used with procedural placement inside shader. */
GPUBatch *GPU_batch_preset_quad(void)
{
if (!g_presets_2d.batch.quad) {
diff --git a/source/blender/gpu/intern/gpu_batch_private.hh b/source/blender/gpu/intern/gpu_batch_private.hh
index eed96864f20..4c2f221e9b6 100644
--- a/source/blender/gpu/intern/gpu_batch_private.hh
+++ b/source/blender/gpu/intern/gpu_batch_private.hh
@@ -47,7 +47,7 @@ class Batch : public GPUBatch {
virtual void draw(int v_first, int v_count, int i_first, int i_count) = 0;
/* Convenience casts. */
- IndexBuf *elem_(void) const
+ IndexBuf *elem_() const
{
return unwrap(elem);
}
diff --git a/source/blender/gpu/intern/gpu_batch_utils.c b/source/blender/gpu/intern/gpu_batch_utils.c
index e2d03d27035..a381df5974a 100644
--- a/source/blender/gpu/intern/gpu_batch_utils.c
+++ b/source/blender/gpu/intern/gpu_batch_utils.c
@@ -33,15 +33,6 @@
/** \name Polygon Creation (2D)
* \{ */
-/**
- * Creates triangles from a byte-array of polygons.
- *
- * See 'make_shape_2d_from_blend.py' utility to create data to pass to this function.
- *
- * \param polys_flat: Pairs of X, Y coordinates (repeating to signify closing the polygon).
- * \param polys_flat_len: Length of the array (must be an even number).
- * \param rect: Optional region to map the byte 0..255 coords to. When not set use -1..1.
- */
GPUBatch *GPU_batch_tris_from_poly_2d_encoded(const uchar *polys_flat,
uint polys_flat_len,
const rctf *rect)
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 43483916236..dd53bea4eca 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -57,6 +57,10 @@
/* XXX: the rest of the code in this file is used for optimized PBVH
* drawing and doesn't interact at all with the buffer code above */
+/* -------------------------------------------------------------------- */
+/** \name Private Types
+ * \{ */
+
struct GPU_PBVH_Buffers {
GPUIndexBuf *index_buf, *index_buf_fast;
GPUIndexBuf *index_lines_buf, *index_lines_buf_fast;
@@ -204,9 +208,9 @@ static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt,
sculpt_face_sets[lt->poly] > SCULPT_FACE_SET_NONE);
}
-/* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const MVert *mvert,
+ const float (*vert_normals)[3],
const float *vmask,
const MLoopCol *vcol,
const int *sculpt_face_sets,
@@ -289,7 +293,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co);
if (buffers->smooth) {
- copy_v3_v3_short(no, v->no);
+ normal_float_to_short_v3(no, vert_normals[vtri[j]]);
}
copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no);
@@ -337,7 +341,6 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->mvert = mvert;
}
-/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly,
const MLoop *mloop,
const MLoopTri *looptri,
@@ -584,7 +587,6 @@ void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
}
}
-/* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
SubdivCCG *subdiv_ccg,
CCGElem **grids,
@@ -764,7 +766,6 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->show_overlay = !empty_mask || !default_face_set;
}
-/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden)
{
GPU_PBVH_Buffers *buffers;
@@ -878,9 +879,6 @@ void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers)
}
}
-/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
- * shading, an element index buffer.
- * Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
BMesh *bm,
GSet *bm_faces,
@@ -1048,7 +1046,6 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
/** \name Generic
* \{ */
-/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
{
GPU_PBVH_Buffers *buffers;
diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc
index c6e9dc210cb..f12fd96d1ba 100644
--- a/source/blender/gpu/intern/gpu_capabilities.cc
+++ b/source/blender/gpu/intern/gpu_capabilities.cc
@@ -44,7 +44,7 @@ using namespace blender::gpu;
/** \name Capabilities
* \{ */
-int GPU_max_texture_size(void)
+int GPU_max_texture_size()
{
return GCaps.max_texture_size;
}
@@ -57,27 +57,27 @@ int GPU_texture_size_with_limit(int res, bool limit_gl_texture_size)
return min_ii(reslimit, res);
}
-int GPU_max_texture_layers(void)
+int GPU_max_texture_layers()
{
return GCaps.max_texture_layers;
}
-int GPU_max_textures_vert(void)
+int GPU_max_textures_vert()
{
return GCaps.max_textures_vert;
}
-int GPU_max_textures_geom(void)
+int GPU_max_textures_geom()
{
return GCaps.max_textures_geom;
}
-int GPU_max_textures_frag(void)
+int GPU_max_textures_frag()
{
return GCaps.max_textures_frag;
}
-int GPU_max_textures(void)
+int GPU_max_textures()
{
return GCaps.max_textures;
}
@@ -92,37 +92,37 @@ int GPU_max_work_group_size(int index)
return GCaps.max_work_group_size[index];
}
-int GPU_max_uniforms_vert(void)
+int GPU_max_uniforms_vert()
{
return GCaps.max_uniforms_vert;
}
-int GPU_max_uniforms_frag(void)
+int GPU_max_uniforms_frag()
{
return GCaps.max_uniforms_frag;
}
-int GPU_max_batch_indices(void)
+int GPU_max_batch_indices()
{
return GCaps.max_batch_indices;
}
-int GPU_max_batch_vertices(void)
+int GPU_max_batch_vertices()
{
return GCaps.max_batch_vertices;
}
-int GPU_max_vertex_attribs(void)
+int GPU_max_vertex_attribs()
{
return GCaps.max_vertex_attribs;
}
-int GPU_max_varying_floats(void)
+int GPU_max_varying_floats()
{
return GCaps.max_varying_floats;
}
-int GPU_extensions_len(void)
+int GPU_extensions_len()
{
return GCaps.extensions_len;
}
@@ -132,43 +132,43 @@ const char *GPU_extension_get(int i)
return GCaps.extension_get ? GCaps.extension_get(i) : "\0";
}
-bool GPU_mip_render_workaround(void)
+bool GPU_mip_render_workaround()
{
return GCaps.mip_render_workaround;
}
-bool GPU_depth_blitting_workaround(void)
+bool GPU_depth_blitting_workaround()
{
return GCaps.depth_blitting_workaround;
}
-bool GPU_use_main_context_workaround(void)
+bool GPU_use_main_context_workaround()
{
return GCaps.use_main_context_workaround;
}
-bool GPU_crappy_amd_driver(void)
+bool GPU_crappy_amd_driver()
{
/* Currently are the same drivers with the `unused_fb_slot` problem. */
return GCaps.broken_amd_driver;
}
-bool GPU_use_hq_normals_workaround(void)
+bool GPU_use_hq_normals_workaround()
{
return GCaps.use_hq_normals_workaround;
}
-bool GPU_compute_shader_support(void)
+bool GPU_compute_shader_support()
{
return GCaps.compute_shader_support;
}
-bool GPU_shader_storage_buffer_objects_support(void)
+bool GPU_shader_storage_buffer_objects_support()
{
return GCaps.shader_storage_buffer_objects_support;
}
-bool GPU_shader_image_load_store_support(void)
+bool GPU_shader_image_load_store_support()
{
return GCaps.shader_image_load_store_support;
}
@@ -179,7 +179,7 @@ bool GPU_shader_image_load_store_support(void)
/** \name Memory statistics
* \{ */
-bool GPU_mem_stats_supported(void)
+bool GPU_mem_stats_supported()
{
return GCaps.mem_stats_support;
}
@@ -189,8 +189,7 @@ void GPU_mem_stats_get(int *totalmem, int *freemem)
Context::get()->memory_statistics_get(totalmem, freemem);
}
-/* Return support for the active context + window. */
-bool GPU_stereo_quadbuffer_support(void)
+bool GPU_stereo_quadbuffer_support()
{
return Context::get()->front_right != nullptr;
}
diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh
index 95cf7fd335d..1f94b6715f1 100644
--- a/source/blender/gpu/intern/gpu_capabilities_private.hh
+++ b/source/blender/gpu/intern/gpu_capabilities_private.hh
@@ -29,10 +29,10 @@ namespace blender::gpu {
/**
* This includes both hardware capabilities & workarounds.
- * Try to limit these to the implementation codebase (i.e.: gpu/opengl/).
+ * Try to limit these to the implementation code-base (i.e.: `gpu/opengl/`).
* Only add workarounds here if they are common to all implementation or
* if you need access to it outside of the GPU module.
- * Same goes for capabilities (i.e.: texture size)
+ * Same goes for capabilities (i.e.: texture size).
*/
struct GPUCapabilities {
int max_texture_size = 0;
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index 943a6151ced..98714269402 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -109,7 +109,6 @@ GPUContext *GPU_context_create(void *ghost_window)
return wrap(ctx);
}
-/* to be called after GPU_context_active_set(ctx_to_destroy) */
void GPU_context_discard(GPUContext *ctx_)
{
Context *ctx = unwrap(ctx_);
@@ -117,7 +116,6 @@ void GPU_context_discard(GPUContext *ctx_)
active_ctx = nullptr;
}
-/* ctx can be NULL */
void GPU_context_active_set(GPUContext *ctx_)
{
Context *ctx = unwrap(ctx_);
@@ -133,7 +131,7 @@ void GPU_context_active_set(GPUContext *ctx_)
}
}
-GPUContext *GPU_context_active_get(void)
+GPUContext *GPU_context_active_get()
{
return wrap(Context::get());
}
@@ -146,12 +144,12 @@ GPUContext *GPU_context_active_get(void)
static std::mutex main_context_mutex;
-void GPU_context_main_lock(void)
+void GPU_context_main_lock()
{
main_context_mutex.lock();
}
-void GPU_context_main_unlock(void)
+void GPU_context_main_unlock()
{
main_context_mutex.unlock();
}
@@ -180,7 +178,7 @@ void GPU_backend_init(eGPUBackendType backend_type)
}
}
-void GPU_backend_exit(void)
+void GPU_backend_exit()
{
/* TODO: assert no resource left. Currently UI textures are still not freed in their context
* correctly. */
@@ -188,6 +186,15 @@ void GPU_backend_exit(void)
g_backend = nullptr;
}
+eGPUBackendType GPU_backend_get_type()
+{
+ if (g_backend && dynamic_cast<GLBackend *>(g_backend) != nullptr) {
+ return GPU_BACKEND_OPENGL;
+ }
+
+ return GPU_BACKEND_NONE;
+}
+
GPUBackend *GPUBackend::get()
{
return g_backend;
diff --git a/source/blender/gpu/intern/gpu_context_private.hh b/source/blender/gpu/intern/gpu_context_private.hh
index 82753b44c51..d99555b3bf5 100644
--- a/source/blender/gpu/intern/gpu_context_private.hh
+++ b/source/blender/gpu/intern/gpu_context_private.hh
@@ -75,22 +75,22 @@ class Context {
Context();
virtual ~Context();
- static Context *get(void);
+ static Context *get();
- virtual void activate(void) = 0;
- virtual void deactivate(void) = 0;
+ virtual void activate() = 0;
+ virtual void deactivate() = 0;
/* Will push all pending commands to the GPU. */
- virtual void flush(void) = 0;
+ virtual void flush() = 0;
/* Will wait until the GPU has finished executing all command. */
- virtual void finish(void) = 0;
+ virtual void finish() = 0;
virtual void memory_statistics_get(int *total_mem, int *free_mem) = 0;
virtual void debug_group_begin(const char *, int){};
- virtual void debug_group_end(void){};
+ virtual void debug_group_end(){};
- bool is_active_on_thread(void);
+ bool is_active_on_thread();
};
/* Syntactic sugar. */
diff --git a/source/blender/gpu/intern/gpu_debug.cc b/source/blender/gpu/intern/gpu_debug.cc
index 2d9fb7822ae..85cec67d2a7 100644
--- a/source/blender/gpu/intern/gpu_debug.cc
+++ b/source/blender/gpu/intern/gpu_debug.cc
@@ -45,7 +45,7 @@ void GPU_debug_group_begin(const char *name)
ctx->debug_group_begin(name, stack.size());
}
-void GPU_debug_group_end(void)
+void GPU_debug_group_end()
{
if (!(G.debug & G_DEBUG_GPU)) {
return;
@@ -55,10 +55,6 @@ void GPU_debug_group_end(void)
ctx->debug_group_end();
}
-/**
- * Return a formatted string showing the current group hierarchy in this format:
- * "Group1 > Group 2 > Group3 > ... > GroupN : "
- */
void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf)
{
Context *ctx = Context::get();
@@ -77,7 +73,6 @@ void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf)
r_name_buf[sz - 3] = '\0';
}
-/* Return true if inside a debug group with the same name. */
bool GPU_debug_group_match(const char *ref)
{
/* Otherwise there will be no names. */
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc
index 9099a6e4245..5b1eac2e82f 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.cc
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -216,18 +216,12 @@ void GPU_framebuffer_bind(GPUFrameBuffer *gpu_fb)
unwrap(gpu_fb)->bind(enable_srgb);
}
-/**
- * Workaround for binding a SRGB frame-buffer without doing the SRGB transform.
- */
void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *gpu_fb)
{
const bool enable_srgb = false;
unwrap(gpu_fb)->bind(enable_srgb);
}
-/**
- * For stereo rendering.
- */
void GPU_backbuffer_bind(eGPUBackBuffer buffer)
{
Context *ctx = Context::get();
@@ -240,19 +234,18 @@ void GPU_backbuffer_bind(eGPUBackBuffer buffer)
}
}
-void GPU_framebuffer_restore(void)
+void GPU_framebuffer_restore()
{
Context::get()->back_left->bind(false);
}
-GPUFrameBuffer *GPU_framebuffer_active_get(void)
+GPUFrameBuffer *GPU_framebuffer_active_get()
{
Context *ctx = Context::get();
return wrap(ctx ? ctx->active_fb : nullptr);
}
-/* Returns the default frame-buffer. Will always exists even if it's just a dummy. */
-GPUFrameBuffer *GPU_framebuffer_back_get(void)
+GPUFrameBuffer *GPU_framebuffer_back_get()
{
Context *ctx = Context::get();
return wrap(ctx ? ctx->back_left : nullptr);
@@ -302,12 +295,6 @@ void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
unwrap(tex)->detach_from(unwrap(fb));
}
-/**
- * First GPUAttachment in *config is always the depth/depth_stencil buffer.
- * Following GPUAttachments are color buffers.
- * Setting GPUAttachment.mip to -1 will leave the texture in this slot.
- * Setting GPUAttachment.tex to NULL will detach the texture in this slot.
- */
void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb,
const GPUAttachment *config,
int config_len)
@@ -341,11 +328,6 @@ void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb,
/* ---------- Viewport & Scissor Region ----------- */
-/**
- * Viewport and scissor size is stored per frame-buffer.
- * It is only reset to its original dimensions explicitly OR when binding the frame-buffer after
- * modifying its attachments.
- */
void GPU_framebuffer_viewport_set(GPUFrameBuffer *gpu_fb, int x, int y, int width, int height)
{
int viewport_rect[4] = {x, y, width, height};
@@ -357,9 +339,6 @@ void GPU_framebuffer_viewport_get(GPUFrameBuffer *gpu_fb, int r_viewport[4])
unwrap(gpu_fb)->viewport_get(r_viewport);
}
-/**
- * Reset to its attachment(s) size.
- */
void GPU_framebuffer_viewport_reset(GPUFrameBuffer *gpu_fb)
{
unwrap(gpu_fb)->viewport_reset();
@@ -376,9 +355,6 @@ void GPU_framebuffer_clear(GPUFrameBuffer *gpu_fb,
unwrap(gpu_fb)->clear(buffers, clear_col, clear_depth, clear_stencil);
}
-/**
- * Clear all textures attached to this frame-buffer with a different color.
- */
void GPU_framebuffer_multi_clear(GPUFrameBuffer *gpu_fb, const float (*clear_cols)[4])
{
unwrap(gpu_fb)->clear_multi(clear_cols);
@@ -425,7 +401,6 @@ void GPU_frontbuffer_read_pixels(
Context::get()->front_left->read(GPU_COLOR_BIT, format, rect, channels, 0, data);
}
-/* read_slot and write_slot are only used for color buffers. */
/* TODO(fclem): port as texture operation. */
void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read,
int read_slot,
@@ -466,11 +441,6 @@ void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read,
prev_fb->bind(true);
}
-/**
- * Use this if you need to custom down-sample your texture and use the previous mip-level as
- * input. This function only takes care of the correct texture handling. It execute the callback
- * for each texture level.
- */
void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *gpu_fb,
int max_lvl,
void (*callback)(void *userData, int level),
@@ -514,14 +484,14 @@ void GPU_framebuffer_push(GPUFrameBuffer *fb)
FrameBufferStack.top++;
}
-GPUFrameBuffer *GPU_framebuffer_pop(void)
+GPUFrameBuffer *GPU_framebuffer_pop()
{
BLI_assert(FrameBufferStack.top > 0);
FrameBufferStack.top--;
return FrameBufferStack.framebuffers[FrameBufferStack.top];
}
-uint GPU_framebuffer_stack_level_get(void)
+uint GPU_framebuffer_stack_level_get()
{
return FrameBufferStack.top;
}
@@ -593,7 +563,7 @@ static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs)
GPUOffScreen *GPU_offscreen_create(
int width, int height, bool depth, eGPUTextureFormat format, char err_out[256])
{
- GPUOffScreen *ofs = (GPUOffScreen *)MEM_callocN(sizeof(GPUOffScreen), __func__);
+ GPUOffScreen *ofs = MEM_cnew<GPUOffScreen>(__func__);
/* Sometimes areas can have 0 height or width and this will
* create a 1D texture which we don't want. */
@@ -704,9 +674,6 @@ GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs)
return ofs->color;
}
-/**
- * \note only to be used by viewport code!
- */
void GPU_offscreen_viewport_data_get(GPUOffScreen *ofs,
GPUFrameBuffer **r_fb,
GPUTexture **r_color,
diff --git a/source/blender/gpu/intern/gpu_framebuffer_private.hh b/source/blender/gpu/intern/gpu_framebuffer_private.hh
index 019f3a8d940..e7505258d2a 100644
--- a/source/blender/gpu/intern/gpu_framebuffer_private.hh
+++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh
@@ -189,24 +189,24 @@ class FrameBuffer {
copy_v4_v4_int(r_scissor, scissor_);
}
- inline bool scissor_test_get(void) const
+ inline bool scissor_test_get() const
{
return scissor_test_;
}
- inline void viewport_reset(void)
+ inline void viewport_reset()
{
int viewport_rect[4] = {0, 0, width_, height_};
viewport_set(viewport_rect);
}
- inline void scissor_reset(void)
+ inline void scissor_reset()
{
int scissor_rect[4] = {0, 0, width_, height_};
scissor_set(scissor_rect);
}
- inline GPUTexture *depth_tex(void) const
+ inline GPUTexture *depth_tex() const
{
if (attachments_[GPU_FB_DEPTH_ATTACHMENT].tex) {
return attachments_[GPU_FB_DEPTH_ATTACHMENT].tex;
diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc
index cdd56a117db..e28776c87b3 100644
--- a/source/blender/gpu/intern/gpu_immediate.cc
+++ b/source/blender/gpu/intern/gpu_immediate.cc
@@ -89,7 +89,6 @@ void immUnbindProgram()
imm->shader = nullptr;
}
-/* XXX do not use it. Special hack to use OCIO with batch API. */
GPUShader *immGetShader()
{
return imm->shader;
@@ -603,7 +602,6 @@ void immUniform4fv(const char *name, const float data[4])
GPU_shader_uniform_4fv(imm->shader, name, data);
}
-/* Note array index is not supported for name (i.e: "array[0]"). */
void immUniformArray4fv(const char *name, const float *data, int count)
{
GPU_shader_uniform_4fv_array(imm->shader, name, count, (const float(*)[4])data);
@@ -631,6 +629,12 @@ void immBindTextureSampler(const char *name, GPUTexture *tex, eGPUSamplerState s
GPU_texture_bind_ex(tex, state, binding, true);
}
+void immBindUniformBuf(const char *name, GPUUniformBuf *ubo)
+{
+ int binding = GPU_shader_get_uniform_block_binding(imm->shader, name);
+ GPU_uniformbuf_bind(ubo, binding);
+}
+
/* --- convenience functions for setting "uniform vec4 color" --- */
void immUniformColor4f(float r, float g, float b, float a)
diff --git a/source/blender/gpu/intern/gpu_immediate_private.hh b/source/blender/gpu/intern/gpu_immediate_private.hh
index 382f70eeec4..bc1ae403c52 100644
--- a/source/blender/gpu/intern/gpu_immediate_private.hh
+++ b/source/blender/gpu/intern/gpu_immediate_private.hh
@@ -68,11 +68,11 @@ class Immediate {
Immediate(){};
virtual ~Immediate(){};
- virtual uchar *begin(void) = 0;
- virtual void end(void) = 0;
+ virtual uchar *begin() = 0;
+ virtual void end() = 0;
};
} // namespace blender::gpu
-void immActivate(void);
-void immDeactivate(void);
+void immActivate();
+void immDeactivate();
diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c
index d18dc862ce7..37a423d41a0 100644
--- a/source/blender/gpu/intern/gpu_immediate_util.c
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -143,17 +143,6 @@ void immRecti_complete(int x1, int y1, int x2, int y2, const float color[4])
}
#endif
-/**
- * Pack color into 3 bytes
- *
- * This define converts a numerical value to the equivalent 24-bit
- * color, while not being endian-sensitive. On little-endian, this
- * is the same as doing a 'naive' indexing, on big-endian, it is not!
- *
- * \note BGR format (i.e. 0xBBGGRR)...
- *
- * \param x: color.
- */
void imm_cpack(uint x)
{
immUniformColor3ub(((x)&0xFF), (((x) >> 8) & 0xFF), (((x) >> 16) & 0xFF));
@@ -163,64 +152,44 @@ static void imm_draw_circle(GPUPrimType prim_type,
const uint shdr_pos,
float x,
float y,
- float rad_x,
- float rad_y,
+ float radius_x,
+ float radius_y,
int nsegments)
{
immBegin(prim_type, nsegments);
for (int i = 0; i < nsegments; i++) {
const float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
- immVertex2f(shdr_pos, x + (rad_x * cosf(angle)), y + (rad_y * sinf(angle)));
+ immVertex2f(shdr_pos, x + (radius_x * cosf(angle)), y + (radius_y * sinf(angle)));
}
immEnd();
}
-/**
- * Draw a circle outline with the given \a radius.
- * The circle is centered at \a x, \a y and drawn in the XY plane.
- *
- * \param shdr_pos: The vertex attribute number for position.
- * \param x: Horizontal center.
- * \param y: Vertical center.
- * \param rad: The circle's radius.
- * \param nsegments: The number of segments to use in drawing (more = smoother).
- */
-void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, rad, rad, nsegments);
+ imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, radius, radius, nsegments);
}
-/**
- * Draw a filled circle with the given \a radius.
- * The circle is centered at \a x, \a y and drawn in the XY plane.
- *
- * \param shdr_pos: The vertex attribute number for position.
- * \param x: Horizontal center.
- * \param y: Vertical center.
- * \param rad: The circle's radius.
- * \param nsegments: The number of segments to use in drawing (more = smoother).
- */
-void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, rad, rad, nsegments);
+ imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, radius, radius, nsegments);
}
void imm_draw_circle_wire_aspect_2d(
- uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments)
+ uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments)
{
- imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, rad_x, rad_y, nsegments);
+ imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, radius_x, radius_y, nsegments);
}
void imm_draw_circle_fill_aspect_2d(
- uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments)
+ uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments)
{
- imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, rad_x, rad_y, nsegments);
+ imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, radius_x, radius_y, nsegments);
}
static void imm_draw_circle_partial(GPUPrimType prim_type,
uint pos,
float x,
float y,
- float rad,
+ float radius,
int nsegments,
float start,
float sweep)
@@ -234,15 +203,15 @@ static void imm_draw_circle_partial(GPUPrimType prim_type,
const float angle = interpf(angle_start, angle_end, ((float)i / (float)(nsegments - 1)));
const float angle_sin = sinf(angle);
const float angle_cos = cosf(angle);
- immVertex2f(pos, x + rad * angle_cos, y + rad * angle_sin);
+ immVertex2f(pos, x + radius * angle_cos, y + radius * angle_sin);
}
immEnd();
}
void imm_draw_circle_partial_wire_2d(
- uint pos, float x, float y, float rad, int nsegments, float start, float sweep)
+ uint pos, float x, float y, float radius, int nsegments, float start, float sweep)
{
- imm_draw_circle_partial(GPU_PRIM_LINE_STRIP, pos, x, y, rad, nsegments, start, sweep);
+ imm_draw_circle_partial(GPU_PRIM_LINE_STRIP, pos, x, y, radius, nsegments, start, sweep);
}
static void imm_draw_disk_partial(GPUPrimType prim_type,
@@ -274,21 +243,6 @@ static void imm_draw_disk_partial(GPUPrimType prim_type,
immEnd();
}
-/**
- * Draw a filled arc with the given inner and outer radius.
- * The circle is centered at \a x, \a y and drawn in the XY plane.
- *
- * \note Arguments are `gluPartialDisk` compatible.
- *
- * \param pos: The vertex attribute number for position.
- * \param x: Horizontal center.
- * \param y: Vertical center.
- * \param rad_inner: The inner circle's radius.
- * \param rad_outer: The outer circle's radius (can be zero).
- * \param nsegments: The number of segments to use in drawing (more = smoother).
- * \param start: Specifies the starting angle, in degrees, of the disk portion.
- * \param sweep: Specifies the sweep angle, in degrees, of the disk portion.
- */
void imm_draw_disk_partial_fill_2d(uint pos,
float x,
float y,
@@ -303,40 +257,31 @@ void imm_draw_disk_partial_fill_2d(uint pos,
}
static void imm_draw_circle_3D(
- GPUPrimType prim_type, uint pos, float x, float y, float rad, int nsegments)
+ GPUPrimType prim_type, uint pos, float x, float y, float radius, int nsegments)
{
immBegin(prim_type, nsegments);
for (int i = 0; i < nsegments; i++) {
float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
- immVertex3f(pos, x + rad * cosf(angle), y + rad * sinf(angle), 0.0f);
+ immVertex3f(pos, x + radius * cosf(angle), y + radius * sinf(angle), 0.0f);
}
immEnd();
}
-void imm_draw_circle_wire_3d(uint pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_wire_3d(uint pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle_3D(GPU_PRIM_LINE_LOOP, pos, x, y, rad, nsegments);
+ imm_draw_circle_3D(GPU_PRIM_LINE_LOOP, pos, x, y, radius, nsegments);
}
-void imm_draw_circle_dashed_3d(uint pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_dashed_3d(uint pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle_3D(GPU_PRIM_LINES, pos, x, y, rad, nsegments / 2);
+ imm_draw_circle_3D(GPU_PRIM_LINES, pos, x, y, radius, nsegments / 2);
}
-void imm_draw_circle_fill_3d(uint pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_fill_3d(uint pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle_3D(GPU_PRIM_TRI_FAN, pos, x, y, rad, nsegments);
+ imm_draw_circle_3D(GPU_PRIM_TRI_FAN, pos, x, y, radius, nsegments);
}
-/**
- * Draw a lined box.
- *
- * \param pos: The vertex attribute number for position.
- * \param x1: left.
- * \param y1: bottom.
- * \param x2: right.
- * \param y2: top.
- */
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
{
immBegin(GPU_PRIM_LINE_LOOP, 4);
@@ -358,9 +303,6 @@ void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2)
immEnd();
}
-/**
- * Draw a standard checkerboard to indicate transparent backgrounds.
- */
void imm_draw_box_checker_2d_ex(float x1,
float y1,
float x2,
@@ -391,12 +333,12 @@ void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2)
imm_draw_box_checker_2d_ex(x1, y1, x2, y2, checker_primary, checker_secondary, checker_size);
}
-void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3])
+void imm_draw_cube_fill_3d(uint pos, const float center[3], const float aspect[3])
{
float coords[ARRAY_SIZE(cube_coords)][3];
for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) {
- madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect);
+ madd_v3_v3v3v3(coords[i], center, cube_coords[i], aspect);
}
immBegin(GPU_PRIM_TRIS, ARRAY_SIZE(cube_quad_index) * 3 * 2);
@@ -412,12 +354,12 @@ void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3])
immEnd();
}
-void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3])
+void imm_draw_cube_wire_3d(uint pos, const float center[3], const float aspect[3])
{
float coords[ARRAY_SIZE(cube_coords)][3];
for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) {
- madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect);
+ madd_v3_v3v3v3(coords[i], center, cube_coords[i], aspect);
}
immBegin(GPU_PRIM_LINES, ARRAY_SIZE(cube_line_index) * 2);
@@ -428,18 +370,36 @@ void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3])
immEnd();
}
-/**
- * Draw a cylinder. Replacement for gluCylinder.
- * _warning_ : Slow, better use it only if you no other choices.
- *
- * \param pos: The vertex attribute number for position.
- * \param nor: The vertex attribute number for normal.
- * \param base: Specifies the radius of the cylinder at z = 0.
- * \param top: Specifies the radius of the cylinder at z = height.
- * \param height: Specifies the height of the cylinder.
- * \param slices: Specifies the number of subdivisions around the z axis.
- * \param stacks: Specifies the number of subdivisions along the z axis.
- */
+void imm_draw_cube_corners_3d(uint pos,
+ const float center[3],
+ const float aspect[3],
+ const float factor)
+{
+ float coords[ARRAY_SIZE(cube_coords)][3];
+
+ for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) {
+ madd_v3_v3v3v3(coords[i], center, cube_coords[i], aspect);
+ }
+
+ immBegin(GPU_PRIM_LINES, ARRAY_SIZE(cube_line_index) * 4);
+ for (int i = 0; i < ARRAY_SIZE(cube_line_index); i++) {
+ float vec[3], co[3];
+ sub_v3_v3v3(vec, coords[cube_line_index[i][1]], coords[cube_line_index[i][0]]);
+ mul_v3_fl(vec, factor);
+
+ copy_v3_v3(co, coords[cube_line_index[i][0]]);
+ immVertex3fv(pos, co);
+ add_v3_v3(co, vec);
+ immVertex3fv(pos, co);
+
+ copy_v3_v3(co, coords[cube_line_index[i][1]]);
+ immVertex3fv(pos, co);
+ sub_v3_v3(co, vec);
+ immVertex3fv(pos, co);
+ }
+ immEnd();
+}
+
void imm_draw_cylinder_fill_normal_3d(
uint pos, uint nor, float base, float top, float height, int slices, int stacks)
{
@@ -572,3 +532,55 @@ void imm_draw_cylinder_fill_3d(
}
immEnd();
}
+
+/* Circle Drawing - Tables for Optimized Drawing Speed */
+#define CIRCLE_RESOL 32
+
+static void circball_array_fill(const float verts[CIRCLE_RESOL][3],
+ const float cent[3],
+ const float radius,
+ const float tmat[4][4])
+{
+ /* 32 values of sin function (still same result!) */
+ const float sinval[CIRCLE_RESOL] = {
+ 0.00000000, 0.20129852, 0.39435585, 0.57126821, 0.72479278, 0.84864425, 0.93775213,
+ 0.98846832, 0.99871650, 0.96807711, 0.89780453, 0.79077573, 0.65137248, 0.48530196,
+ 0.29936312, 0.10116832, -0.10116832, -0.29936312, -0.48530196, -0.65137248, -0.79077573,
+ -0.89780453, -0.96807711, -0.99871650, -0.98846832, -0.93775213, -0.84864425, -0.72479278,
+ -0.57126821, -0.39435585, -0.20129852, 0.00000000,
+ };
+
+ /* 32 values of cos function (still same result!) */
+ const float cosval[CIRCLE_RESOL] = {
+ 1.00000000, 0.97952994, 0.91895781, 0.82076344, 0.68896691, 0.52896401, 0.34730525,
+ 0.15142777, -0.05064916, -0.25065253, -0.44039415, -0.61210598, -0.75875812, -0.87434661,
+ -0.95413925, -0.99486932, -0.99486932, -0.95413925, -0.87434661, -0.75875812, -0.61210598,
+ -0.44039415, -0.25065253, -0.05064916, 0.15142777, 0.34730525, 0.52896401, 0.68896691,
+ 0.82076344, 0.91895781, 0.97952994, 1.00000000,
+ };
+
+ float vx[3], vy[3];
+ float *viter = (float *)verts;
+
+ mul_v3_v3fl(vx, tmat[0], radius);
+ mul_v3_v3fl(vy, tmat[1], radius);
+
+ for (uint a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
+ viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
+ viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1];
+ viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2];
+ }
+}
+
+void imm_drawcircball(const float cent[3], float radius, const float tmat[4][4], uint pos)
+{
+ float verts[CIRCLE_RESOL][3];
+
+ circball_array_fill(verts, cent, radius, tmat);
+
+ immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL);
+ for (int i = 0; i < CIRCLE_RESOL; i++) {
+ immVertex3fv(pos, verts[i]);
+ }
+ immEnd();
+}
diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc
index be7470e79c1..895b2a8461b 100644
--- a/source/blender/gpu/intern/gpu_index_buffer.cc
+++ b/source/blender/gpu/intern/gpu_index_buffer.cc
@@ -74,11 +74,16 @@ void GPU_indexbuf_init(GPUIndexBufBuilder *builder,
GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len)
{
GPUIndexBuf *elem_ = GPU_indexbuf_calloc();
- IndexBuf *elem = unwrap(elem_);
- elem->init_build_on_device(index_len);
+ GPU_indexbuf_init_build_on_device(elem_, index_len);
return elem_;
}
+void GPU_indexbuf_init_build_on_device(GPUIndexBuf *elem, uint index_len)
+{
+ IndexBuf *elem_ = unwrap(elem);
+ elem_->init_build_on_device(index_len);
+}
+
void GPU_indexbuf_join(GPUIndexBufBuilder *builder_to, const GPUIndexBufBuilder *builder_from)
{
BLI_assert(builder_to->data == builder_from->data);
@@ -349,7 +354,7 @@ uint32_t *IndexBuf::unmap(const uint32_t *mapped_memory) const
/** \name C-API
* \{ */
-GPUIndexBuf *GPU_indexbuf_calloc(void)
+GPUIndexBuf *GPU_indexbuf_calloc()
{
return wrap(GPUBackend::get()->indexbuf_alloc());
}
@@ -410,9 +415,19 @@ int GPU_indexbuf_primitive_len(GPUPrimType prim_type)
return indices_per_primitive(prim_type);
}
+void GPU_indexbuf_use(GPUIndexBuf *elem)
+{
+ unwrap(elem)->upload_data();
+}
+
void GPU_indexbuf_bind_as_ssbo(GPUIndexBuf *elem, int binding)
{
unwrap(elem)->bind_as_ssbo(binding);
}
+void GPU_indexbuf_update_sub(GPUIndexBuf *elem, uint start, uint len, const void *data)
+{
+ unwrap(elem)->update_sub(start, len, data);
+}
+
/** \} */
diff --git a/source/blender/gpu/intern/gpu_index_buffer_private.hh b/source/blender/gpu/intern/gpu_index_buffer_private.hh
index ed7dd830c8c..4bb46689727 100644
--- a/source/blender/gpu/intern/gpu_index_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_index_buffer_private.hh
@@ -77,26 +77,30 @@ class IndexBuf {
void init_subrange(IndexBuf *elem_src, uint start, uint length);
void init_build_on_device(uint index_len);
- uint32_t index_len_get(void) const
+ uint32_t index_len_get() const
{
return index_len_;
}
/* Return size in byte of the drawable data buffer range. Actual buffer size might be bigger. */
- size_t size_get(void) const
+ size_t size_get() const
{
return index_len_ * to_bytesize(index_type_);
};
- bool is_init(void) const
+ bool is_init() const
{
return is_init_;
};
+ virtual void upload_data() = 0;
+
virtual void bind_as_ssbo(uint binding) = 0;
virtual const uint32_t *read() const = 0;
uint32_t *unmap(const uint32_t *mapped_memory) const;
+ virtual void update_sub(uint start, uint len, const void *data) = 0;
+
private:
inline void squeeze_indices_short(uint min_idx, uint max_idx);
inline uint index_range(uint *r_min, uint *r_max);
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index 0eb2fe57c28..5815fb10b0c 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -32,6 +32,8 @@
#include "intern/gpu_codegen.h"
#include "intern/gpu_material_library.h"
#include "intern/gpu_private.h"
+#include "intern/gpu_shader_create_info_private.hh"
+#include "intern/gpu_shader_dependency_private.h"
/**
* although the order of initialization and shutdown should not matter
@@ -49,6 +51,9 @@ void GPU_init(void)
initialized = true;
+ gpu_shader_dependency_init();
+ gpu_shader_create_info_init();
+
gpu_codegen_init();
gpu_material_library_init();
@@ -70,6 +75,9 @@ void GPU_exit(void)
gpu_material_library_exit();
gpu_codegen_exit();
+ gpu_shader_dependency_exit();
+ gpu_shader_create_info_exit();
+
initialized = false;
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index e40d6195eab..ca1f45f7238 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -44,6 +44,8 @@
#include "BKE_scene.h"
#include "BKE_world.h"
+#include "NOD_shader.h"
+
#include "GPU_material.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
@@ -84,6 +86,7 @@ struct GPUMaterial {
Material *ma;
/** 1D Texture array containing all color bands. */
GPUTexture *coba_tex;
+
GPUColorBandBuilder *coba_builder;
/* Low level node graph(s). Also contains resources needed by the material. */
GPUNodeGraph graph;
@@ -100,7 +103,6 @@ enum {
/* Functions */
-/* Returns the address of the future pointer to coba_tex */
GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat,
int size,
float *pixels,
@@ -189,7 +191,6 @@ GPUShader *GPU_material_get_shader(GPUMaterial *material)
return material->pass ? GPU_pass_shader_get(material->pass) : NULL;
}
-/* Return can be NULL if it's a world material. */
Material *GPU_material_get_material(GPUMaterial *material)
{
return material->ma;
@@ -200,11 +201,6 @@ GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material)
return material->ubo;
}
-/**
- * Create dynamic UBO from parameters
- *
- * \param inputs: Items are #LinkData, data is #GPUInput (`BLI_genericNodeN(GPUInput)`).
- */
void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs)
{
#ifndef NDEBUG
@@ -332,9 +328,9 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
bNodeTree *ntree,
ListBase *gpumaterials,
const char *name,
- const uint64_t shader_uuid,
- const bool is_volume_shader,
- const bool is_lookdev,
+ uint64_t shader_uuid,
+ bool is_volume_shader,
+ bool is_lookdev,
GPUCodegenCallbackFn callback,
void *thunk)
{
diff --git a/source/blender/gpu/intern/gpu_material_library.c b/source/blender/gpu/intern/gpu_material_library.c
index 6d14993e2ac..6f68729eaae 100644
--- a/source/blender/gpu/intern/gpu_material_library.c
+++ b/source/blender/gpu/intern/gpu_material_library.c
@@ -62,6 +62,7 @@ extern char datatoc_gpu_shader_material_diffuse_glsl[];
extern char datatoc_gpu_shader_material_displacement_glsl[];
extern char datatoc_gpu_shader_material_eevee_specular_glsl[];
extern char datatoc_gpu_shader_material_emission_glsl[];
+extern char datatoc_gpu_shader_material_float_curve_glsl[];
extern char datatoc_gpu_shader_material_fractal_noise_glsl[];
extern char datatoc_gpu_shader_material_fresnel_glsl[];
extern char datatoc_gpu_shader_material_gamma_glsl[];
@@ -90,6 +91,7 @@ extern char datatoc_gpu_shader_material_output_aov_glsl[];
extern char datatoc_gpu_shader_material_output_material_glsl[];
extern char datatoc_gpu_shader_material_output_world_glsl[];
extern char datatoc_gpu_shader_material_particle_info_glsl[];
+extern char datatoc_gpu_shader_material_point_info_glsl[];
extern char datatoc_gpu_shader_material_principled_glsl[];
extern char datatoc_gpu_shader_material_refraction_glsl[];
extern char datatoc_gpu_shader_material_rgb_curves_glsl[];
@@ -262,6 +264,11 @@ static GPUMaterialLibrary gpu_shader_material_emission_library = {
.dependencies = {NULL},
};
+static GPUMaterialLibrary gpu_shader_material_float_curve_library = {
+ .code = datatoc_gpu_shader_material_float_curve_glsl,
+ .dependencies = {NULL},
+};
+
static GPUMaterialLibrary gpu_shader_material_fresnel_library = {
.code = datatoc_gpu_shader_material_fresnel_glsl,
.dependencies = {NULL},
@@ -289,7 +296,7 @@ static GPUMaterialLibrary gpu_shader_material_glass_library = {
static GPUMaterialLibrary gpu_shader_material_hair_info_library = {
.code = datatoc_gpu_shader_material_hair_info_glsl,
- .dependencies = {NULL},
+ .dependencies = {&gpu_shader_material_hash_library, NULL},
};
static GPUMaterialLibrary gpu_shader_material_holdout_library = {
@@ -382,6 +389,11 @@ static GPUMaterialLibrary gpu_shader_material_particle_info_library = {
.dependencies = {NULL},
};
+static GPUMaterialLibrary gpu_shader_material_point_info_library = {
+ .code = datatoc_gpu_shader_material_point_info_glsl,
+ .dependencies = {&gpu_shader_material_hash_library, NULL},
+};
+
static GPUMaterialLibrary gpu_shader_material_principled_library = {
.code = datatoc_gpu_shader_material_principled_glsl,
.dependencies = {NULL},
@@ -591,6 +603,7 @@ static GPUMaterialLibrary *gpu_material_libraries[] = {
&gpu_shader_material_color_util_library,
&gpu_shader_material_hash_library,
&gpu_shader_material_noise_library,
+ &gpu_shader_material_float_curve_library,
&gpu_shader_material_fractal_noise_library,
&gpu_shader_material_add_shader_library,
&gpu_shader_material_ambient_occlusion_library,
@@ -637,6 +650,7 @@ static GPUMaterialLibrary *gpu_material_libraries[] = {
&gpu_shader_material_output_material_library,
&gpu_shader_material_output_world_library,
&gpu_shader_material_particle_info_library,
+ &gpu_shader_material_point_info_library,
&gpu_shader_material_principled_library,
&gpu_shader_material_refraction_library,
&gpu_shader_material_rgb_curves_library,
diff --git a/source/blender/gpu/intern/gpu_material_library.h b/source/blender/gpu/intern/gpu_material_library.h
index 139f5200f59..d9c56ddd425 100644
--- a/source/blender/gpu/intern/gpu_material_library.h
+++ b/source/blender/gpu/intern/gpu_material_library.h
@@ -67,7 +67,7 @@ char *gpu_material_library_generate_code(struct GSet *used_libraries);
/* Code Parsing */
const char *gpu_str_skip_token(const char *str, char *token, int max);
-const char *gpu_data_type_to_string(const eGPUType type);
+const char *gpu_data_type_to_string(eGPUType type);
#ifdef __cplusplus
}
diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc
index bbcc241f5e3..cf3f7f5e778 100644
--- a/source/blender/gpu/intern/gpu_matrix.cc
+++ b/source/blender/gpu/intern/gpu_matrix.cc
@@ -67,7 +67,7 @@ struct GPUMatrixState {
#define ProjectionStack Context::get()->matrix_state->projection_stack
#define Projection ProjectionStack.stack[ProjectionStack.top]
-GPUMatrixState *GPU_matrix_state_create(void)
+GPUMatrixState *GPU_matrix_state_create()
{
#define MATRIX_4X4_IDENTITY \
{ \
@@ -99,7 +99,7 @@ static void gpu_matrix_state_active_set_dirty(bool value)
state->dirty = value;
}
-void GPU_matrix_reset(void)
+void GPU_matrix_reset()
{
GPUMatrixState *state = Context::get()->matrix_state;
state->model_view_stack.top = 0;
@@ -132,28 +132,28 @@ static void checkmat(cosnt float *m)
#endif
-void GPU_matrix_push(void)
+void GPU_matrix_push()
{
BLI_assert(ModelViewStack.top + 1 < MATRIX_STACK_DEPTH);
ModelViewStack.top++;
copy_m4_m4(ModelView, ModelViewStack.stack[ModelViewStack.top - 1]);
}
-void GPU_matrix_pop(void)
+void GPU_matrix_pop()
{
BLI_assert(ModelViewStack.top > 0);
ModelViewStack.top--;
gpu_matrix_state_active_set_dirty(true);
}
-void GPU_matrix_push_projection(void)
+void GPU_matrix_push_projection()
{
BLI_assert(ProjectionStack.top + 1 < MATRIX_STACK_DEPTH);
ProjectionStack.top++;
copy_m4_m4(Projection, ProjectionStack.stack[ProjectionStack.top - 1]);
}
-void GPU_matrix_pop_projection(void)
+void GPU_matrix_pop_projection()
{
BLI_assert(ProjectionStack.top > 0);
ProjectionStack.top--;
@@ -167,7 +167,7 @@ void GPU_matrix_set(const float m[4][4])
gpu_matrix_state_active_set_dirty(true);
}
-void GPU_matrix_identity_projection_set(void)
+void GPU_matrix_identity_projection_set()
{
unit_m4(Projection);
CHECKMAT(Projection3D);
@@ -181,7 +181,7 @@ void GPU_matrix_projection_set(const float m[4][4])
gpu_matrix_state_active_set_dirty(true);
}
-void GPU_matrix_identity_set(void)
+void GPU_matrix_identity_set()
{
unit_m4(ModelView);
gpu_matrix_state_active_set_dirty(true);
@@ -668,7 +668,7 @@ void GPU_matrix_bind(GPUShader *shader)
gpu_matrix_state_active_set_dirty(false);
}
-bool GPU_matrix_dirty_get(void)
+bool GPU_matrix_dirty_get()
{
GPUMatrixState *state = Context::get()->matrix_state;
return state->dirty;
@@ -677,17 +677,18 @@ bool GPU_matrix_dirty_get(void)
/* -------------------------------------------------------------------- */
/** \name Python API Helpers
* \{ */
+
BLI_STATIC_ASSERT(GPU_PY_MATRIX_STACK_LEN + 1 == MATRIX_STACK_DEPTH, "define mismatch");
/* Return int since caller is may subtract. */
-int GPU_matrix_stack_level_get_model_view(void)
+int GPU_matrix_stack_level_get_model_view()
{
GPUMatrixState *state = Context::get()->matrix_state;
return (int)state->model_view_stack.top;
}
-int GPU_matrix_stack_level_get_projection(void)
+int GPU_matrix_stack_level_get_projection()
{
GPUMatrixState *state = Context::get()->matrix_state;
return (int)state->projection_stack.top;
@@ -733,9 +734,6 @@ float GPU_polygon_offset_calc(const float (*winmat)[4], float viewdist, float di
return winmat[3][2] * -0.0025f * dist;
}
-/**
- * \note \a viewdist is only for ortho at the moment.
- */
void GPU_polygon_offset(float viewdist, float dist)
{
static float winmat[4][4], offset = 0.0f;
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index 7d1bd763a5b..593a89bbf21 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -435,7 +435,10 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph,
if (tex == NULL) {
tex = MEM_callocN(sizeof(*tex), __func__);
tex->ima = ima;
- tex->iuser = iuser;
+ if (iuser != NULL) {
+ tex->iuser = *iuser;
+ tex->iuser_available = true;
+ }
tex->colorband = colorband;
tex->sampler_state = sampler_state;
BLI_snprintf(tex->sampler_name, sizeof(tex->sampler_name), "samp%d", num_textures);
@@ -644,25 +647,27 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
}
va_end(params);
+ GPUNodeGraph *graph = gpu_material_node_graph(mat);
BLI_addtail(&graph->nodes, node);
return true;
}
-static bool gpu_stack_link_v(GPUMaterial *material,
- bNode *bnode,
- const char *name,
- GPUNodeStack *in,
- GPUNodeStack *out,
- va_list params)
+bool GPU_stack_link(GPUMaterial *material,
+ bNode *bnode,
+ const char *name,
+ GPUNodeStack *in,
+ GPUNodeStack *out,
+ ...)
{
- GPUNodeGraph *graph = gpu_material_node_graph(material);
+ GSet *used_libraries = gpu_material_used_libraries(material);
GPUNode *node;
GPUFunction *function;
GPUNodeLink *link, **linkptr;
+ va_list params;
int i, totin, totout;
- function = gpu_material_library_use_function(graph->used_libraries, name);
+ function = gpu_material_library_use_function(used_libraries, name);
if (!function) {
fprintf(stderr, "GPU failed to find function %s\n", name);
return false;
@@ -690,6 +695,7 @@ static bool gpu_stack_link_v(GPUMaterial *material,
}
}
+ va_start(params, out);
for (i = 0; i < function->totparam; i++) {
if (function->paramqual[i] != FUNCTION_QUAL_IN) {
if (totout == 0) {
@@ -715,53 +721,14 @@ static bool gpu_stack_link_v(GPUMaterial *material,
}
}
}
+ va_end(params);
+ GPUNodeGraph *graph = gpu_material_node_graph(material);
BLI_addtail(&graph->nodes, node);
return true;
}
-bool GPU_stack_link(GPUMaterial *material,
- bNode *bnode,
- const char *name,
- GPUNodeStack *in,
- GPUNodeStack *out,
- ...)
-{
- va_list params;
- va_start(params, out);
- bool valid = gpu_stack_link_v(material, bnode, name, in, out, params);
- va_end(params);
-
- return valid;
-}
-
-/* This is a special function to call the "*_eval" function of a BSDF node.
- * This must be call right after GPU_stack_link() so that out[0] contains a valid link. */
-bool GPU_stack_eval_link(GPUMaterial *material,
- bNode *bnode,
- const char *name,
- GPUNodeStack *in,
- GPUNodeStack *out,
- ...)
-{
- /* Save the closure link to replace the one created by the eval function call. Avoiding
- * dependency to the eval call before the end of the graph. */
- GPUNodeLink *closure_out = out[0].link;
-
- va_list params;
- va_start(params, out);
- bool valid = gpu_stack_link_v(material, bnode, name, in, out, params);
- va_end(params);
-
- /* Save both nodes for graph amendment. */
- GPU_material_add_closure_eval(material, closure_out, out[0].link);
- /* Restore original link. */
- out[0].link = closure_out;
-
- return valid;
-}
-
GPUNodeLink *GPU_uniformbuf_link_out(GPUMaterial *mat,
bNode *node,
GPUNodeStack *stack,
@@ -815,7 +782,6 @@ static void gpu_node_free(GPUNode *node)
MEM_freeN(node);
}
-/* Free intermediate node graph. */
void gpu_node_graph_free_nodes(GPUNodeGraph *graph)
{
GPUNode *node;
@@ -824,14 +790,9 @@ void gpu_node_graph_free_nodes(GPUNodeGraph *graph)
gpu_node_free(node);
}
- BLI_freelistN(&graph->eval_nodes);
- graph->outlink_surface = NULL;
- graph->outlink_volume = NULL;
- graph->outlink_displacement = NULL;
- graph->outlink_thickness = NULL;
+ graph->outlink = NULL;
}
-/* Free both node graph, requested attributes and textures. */
void gpu_node_graph_free(GPUNodeGraph *graph)
{
BLI_freelistN(&graph->outlink_aovs);
@@ -844,32 +805,28 @@ void gpu_node_graph_free(GPUNodeGraph *graph)
BLI_freelistN(&graph->textures);
BLI_freelistN(&graph->attributes);
GPU_uniform_attr_list_free(&graph->uniform_attrs);
-
- if (graph->used_libraries) {
- BLI_gset_free(graph->used_libraries, NULL);
- graph->used_libraries = NULL;
- }
}
/* Prune Unused Nodes */
-static void gpu_nodes_tag(GPUNodeLink *link, eGPUNodeTag tag)
+static void gpu_nodes_tag(GPUNodeLink *link)
{
GPUNode *node;
+ GPUInput *input;
- if (!link || !link->output) {
+ if (!link->output) {
return;
}
node = link->output->node;
- if (node->tag & tag) {
+ if (node->tag) {
return;
}
- node->tag |= tag;
- LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
+ node->tag = true;
+ for (input = node->inputs.first; input; input = input->next) {
if (input->link) {
- gpu_nodes_tag(input->link, tag);
+ gpu_nodes_tag(input->link);
}
}
}
@@ -877,30 +834,18 @@ static void gpu_nodes_tag(GPUNodeLink *link, eGPUNodeTag tag)
void gpu_node_graph_prune_unused(GPUNodeGraph *graph)
{
LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
- node->tag = GPU_NODE_TAG_NONE;
+ node->tag = false;
}
- gpu_nodes_tag(graph->outlink_surface, GPU_NODE_TAG_SURFACE);
- gpu_nodes_tag(graph->outlink_volume, GPU_NODE_TAG_VOLUME);
- gpu_nodes_tag(graph->outlink_displacement, GPU_NODE_TAG_DISPLACEMENT);
- gpu_nodes_tag(graph->outlink_thickness, GPU_NODE_TAG_THICKNESS);
-
+ gpu_nodes_tag(graph->outlink);
LISTBASE_FOREACH (GPUNodeGraphOutputLink *, aovlink, &graph->outlink_aovs) {
- gpu_nodes_tag(aovlink->outlink, GPU_NODE_TAG_AOV);
- }
-
- LISTBASE_FOREACH (GPUNodeGraphEvalNode *, node, &graph->eval_nodes) {
- /* Copy weight node tag to avoid pruning of eval node since they are node connected to
- * output. */
- if (node->weight_node->tag != GPU_NODE_TAG_NONE) {
- node->eval_node->tag = GPU_NODE_TAG_EVAL | node->weight_node->tag;
- }
+ gpu_nodes_tag(aovlink->outlink);
}
for (GPUNode *node = graph->nodes.first, *next = NULL; node; node = next) {
next = node->next;
- if (node->tag == GPU_NODE_TAG_NONE) {
+ if (!node->tag) {
BLI_remlink(&graph->nodes, node);
gpu_node_free(node);
}
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index b3e9690dd32..9f1a729738b 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -191,12 +191,21 @@ typedef struct GPUNodeGraph {
void gpu_node_graph_prune_unused(GPUNodeGraph *graph);
void gpu_node_graph_finalize_uniform_attrs(GPUNodeGraph *graph);
+/**
+ * Free intermediate node graph.
+ */
void gpu_node_graph_free_nodes(GPUNodeGraph *graph);
+/**
+ * Free both node graph and requested attributes and textures.
+ */
void gpu_node_graph_free(GPUNodeGraph *graph);
/* Material calls */
struct GPUNodeGraph *gpu_material_node_graph(struct GPUMaterial *material);
+/**
+ * Returns the address of the future pointer to coba_tex.
+ */
struct GPUTexture **gpu_material_ramp_texture_row_set(struct GPUMaterial *mat,
int size,
float *pixels,
diff --git a/source/blender/gpu/intern/gpu_platform.cc b/source/blender/gpu/intern/gpu_platform.cc
index 49dde473300..34834a62268 100644
--- a/source/blender/gpu/intern/gpu_platform.cc
+++ b/source/blender/gpu/intern/gpu_platform.cc
@@ -127,37 +127,36 @@ eGPUSupportLevel GPU_platform_support_level()
return GPG.support_level;
}
-const char *GPU_platform_vendor(void)
+const char *GPU_platform_vendor()
{
BLI_assert(GPG.initialized);
return GPG.vendor;
}
-const char *GPU_platform_renderer(void)
+const char *GPU_platform_renderer()
{
BLI_assert(GPG.initialized);
return GPG.renderer;
}
-const char *GPU_platform_version(void)
+const char *GPU_platform_version()
{
BLI_assert(GPG.initialized);
return GPG.version;
}
-const char *GPU_platform_support_level_key(void)
+const char *GPU_platform_support_level_key()
{
BLI_assert(GPG.initialized);
return GPG.support_key;
}
-const char *GPU_platform_gpu_name(void)
+const char *GPU_platform_gpu_name()
{
BLI_assert(GPG.initialized);
return GPG.gpu_name;
}
-/* GPU Types */
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
{
BLI_assert(GPG.initialized);
diff --git a/source/blender/gpu/intern/gpu_platform_private.hh b/source/blender/gpu/intern/gpu_platform_private.hh
index f823269ab54..faae7c48588 100644
--- a/source/blender/gpu/intern/gpu_platform_private.hh
+++ b/source/blender/gpu/intern/gpu_platform_private.hh
@@ -49,7 +49,7 @@ class GPUPlatformGlobal {
const char *renderer_str,
const char *version_str);
- void clear(void);
+ void clear();
};
extern GPUPlatformGlobal GPG;
diff --git a/source/blender/gpu/intern/gpu_query.hh b/source/blender/gpu/intern/gpu_query.hh
index 0356e145b00..a004c355c8f 100644
--- a/source/blender/gpu/intern/gpu_query.hh
+++ b/source/blender/gpu/intern/gpu_query.hh
@@ -45,8 +45,8 @@ class QueryPool {
* Will start and end the query at this index inside the pool.
* The pool will resize automatically.
*/
- virtual void begin_query(void) = 0;
- virtual void end_query(void) = 0;
+ virtual void begin_query() = 0;
+ virtual void end_query() = 0;
/**
* Must be fed with a buffer large enough to contain all the queries issued.
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index 88b704a84a1..958aab65b57 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -20,8 +20,8 @@
/** \file
* \ingroup gpu
*
- * Interface for accessing gpu-related methods for selection. The semantics are
- * similar to glRenderMode(GL_SELECT) from older OpenGL versions.
+ * Interface for accessing GPU-related methods for selection. The semantics are
+ * similar to `glRenderMode(GL_SELECT)` from older OpenGL versions.
*/
#include <stdlib.h>
#include <string.h>
@@ -38,6 +38,10 @@
#include "gpu_select_private.h"
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
/* Internal algorithm used */
enum {
/** glBegin/EndQuery(GL_SAMPLES_PASSED... ), `gpu_select_query.c`
@@ -57,13 +61,25 @@ typedef struct GPUSelectState {
char algorithm;
/* allow GPU_select_begin/end without drawing */
bool use_cache;
+ /**
+ * Signifies that #GPU_select_cache_begin has been called,
+ * future calls to #GPU_select_begin should initialize the cache.
+ *
+ * \note #GPU_select_cache_begin could perform initialization but doesn't as it's inconvenient
+ * for callers making the cache begin/end calls outside lower level selection logic
+ * where the `mode` to pass to #GPU_select_begin yet isn't known.
+ */
+ bool use_cache_needs_init;
} GPUSelectState;
static GPUSelectState g_select_state = {0};
-/**
- * initialize and provide buffer for results
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public API
+ * \{ */
+
void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode, int oldhits)
{
if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
@@ -83,9 +99,26 @@ void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode,
g_select_state.algorithm = ALGO_GL_QUERY;
}
+ /* This function is called when cache has already been initialized,
+ * so only manipulate cache values when cache is pending. */
+ if (g_select_state.use_cache_needs_init) {
+ g_select_state.use_cache_needs_init = false;
+
+ switch (g_select_state.algorithm) {
+ case ALGO_GL_QUERY: {
+ g_select_state.use_cache = false;
+ break;
+ }
+ default: {
+ g_select_state.use_cache = true;
+ gpu_select_pick_cache_begin();
+ break;
+ }
+ }
+ }
+
switch (g_select_state.algorithm) {
case ALGO_GL_QUERY: {
- g_select_state.use_cache = false;
gpu_select_query_begin((uint(*)[4])buffer, bufsize / 4, input, mode, oldhits);
break;
}
@@ -97,14 +130,6 @@ void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode,
}
}
-/**
- * loads a new selection id and ends previous query, if any.
- * In second pass of selection it also returns
- * if id has been hit on the first pass already.
- * Thus we can skip drawing un-hit objects.
- *
- * \warning We rely on the order of object rendering on passes to be the same for this to work.
- */
bool GPU_select_load_id(uint id)
{
/* if no selection mode active, ignore */
@@ -123,11 +148,6 @@ bool GPU_select_load_id(uint id)
}
}
-/**
- * Cleanup and flush selection results to buffer.
- * Return number of hits and hits in buffer.
- * if \a dopass is true, we will do a second pass with occlusion queries to get the closest hit.
- */
uint GPU_select_end(void)
{
uint hits = 0;
@@ -149,21 +169,24 @@ uint GPU_select_end(void)
return hits;
}
-/* ----------------------------------------------------------------------------
- * Caching
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Caching
*
* Support multiple begin/end's as long as they are within the initial region.
- * Currently only used by ALGO_GL_PICK.
- */
+ * Currently only used by #ALGO_GL_PICK.
+ * \{ */
void GPU_select_cache_begin(void)
{
- /* validate on GPU_select_begin, clear if not supported */
- BLI_assert(g_select_state.use_cache == false);
- g_select_state.use_cache = true;
- if (g_select_state.algorithm == ALGO_GL_PICK) {
- gpu_select_pick_cache_begin();
- }
+ BLI_assert(g_select_state.select_is_active == false);
+ /* Ensure #GPU_select_cache_end is always called. */
+ BLI_assert(g_select_state.use_cache_needs_init == false);
+
+ /* Signal that cache should be used, instead of calling the algorithms cache-begin function.
+ * This is more convenient as the exact method of selection may not be known by the caller. */
+ g_select_state.use_cache_needs_init = true;
}
void GPU_select_cache_load_id(void)
@@ -177,9 +200,12 @@ void GPU_select_cache_load_id(void)
void GPU_select_cache_end(void)
{
if (g_select_state.algorithm == ALGO_GL_PICK) {
+ BLI_assert(g_select_state.use_cache == true);
gpu_select_pick_cache_end();
}
g_select_state.use_cache = false;
+ /* Paranoid assignment, should already be false. */
+ g_select_state.use_cache_needs_init = false;
}
bool GPU_select_is_cached(void)
@@ -187,16 +213,12 @@ bool GPU_select_is_cached(void)
return g_select_state.use_cache && gpu_select_pick_is_cached();
}
-/* ----------------------------------------------------------------------------
- * Utilities
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
-/**
- * Helper function, nothing special but avoids doing inline since hits aren't sorted by depth
- * and purpose of 4x buffer indices isn't so clear.
- *
- * Note that comparing depth as uint is fine.
- */
const uint *GPU_select_buffer_near(const uint *buffer, int hits)
{
const uint *buffer_near = NULL;
@@ -230,7 +252,6 @@ uint GPU_select_buffer_remove_by_id(uint *buffer, int hits, uint select_id)
return hits_final;
}
-/* Part of the solution copied from `rect_subregion_stride_calc`. */
void GPU_select_buffer_stride_realign(const rcti *src, const rcti *dst, uint *r_buf)
{
const int x = dst->xmin - src->xmin;
@@ -269,3 +290,5 @@ void GPU_select_buffer_stride_realign(const rcti *src, const rcti *dst, uint *r_
}
memset(r_buf, 0, (last_px_id + 1) * sizeof(*r_buf));
}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index 7fb704c29dd..ddd3dfc6879 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -51,9 +51,9 @@
/* Z-depth of cleared depth buffer */
#define DEPTH_MAX 0xffffffff
-/* ----------------------------------------------------------------------------
- * SubRectStride
- */
+/* -------------------------------------------------------------------- */
+/** \name #SubRectStride
+ * \{ */
/* For looping over a sub-region of a rect, could be moved into 'rct.c'. */
typedef struct SubRectStride {
@@ -99,14 +99,16 @@ BLI_INLINE bool depth_is_filled(const depth_t *prev, const depth_t *curr)
return (*prev != *curr) && (*curr != DEPTH_MAX);
}
-/* ----------------------------------------------------------------------------
- * DepthBufCache
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #DepthBufCache
*
- * Result of reading glReadPixels,
+ * Result of reading #glReadPixels,
* use for both cache and non-cached storage.
- */
+ * \{ */
-/* store result of glReadPixels */
+/** Store result of #glReadPixels. */
typedef struct DepthBufCache {
struct DepthBufCache *next, *prev;
uint id;
@@ -188,11 +190,13 @@ static bool depth_buf_subrect_depth_any_filled(const DepthBufCache *rect_src,
return false;
}
-/* ----------------------------------------------------------------------------
- * DepthID
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #DepthID
*
* Internal structure for storing hits.
- */
+ * \{ */
typedef struct DepthID {
uint id;
@@ -225,6 +229,12 @@ static int depth_cmp(const void *v1, const void *v2)
return 0;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Main Selection Begin/End/Load API
+ * \{ */
+
/* depth sorting */
typedef struct GPUPickState {
/* cache on initialization */
@@ -663,7 +673,7 @@ uint gpu_select_pick_end(void)
#endif
/* first 3 are dummy values */
g_pick_state.buffer[hits][0] = 1;
- g_pick_state.buffer[hits][1] = 0x0; /* depth_data[i].depth; */ /* unused */
+ g_pick_state.buffer[hits][1] = depth_data[i].depth;
g_pick_state.buffer[hits][2] = 0x0; /* z-far is currently never used. */
g_pick_state.buffer[hits][3] = depth_data[i].id;
hits++;
@@ -691,11 +701,13 @@ uint gpu_select_pick_end(void)
return hits;
}
-/* ----------------------------------------------------------------------------
- * Caching
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Caching
*
* Support multiple begin/end's reusing depth buffers.
- */
+ * \{ */
void gpu_select_pick_cache_begin(void)
{
@@ -718,7 +730,6 @@ void gpu_select_pick_cache_end(void)
BLI_freelistN(&g_pick_state.cache.bufs);
}
-/* is drawing needed? */
bool gpu_select_pick_is_cached(void)
{
return g_pick_state.is_cached;
@@ -749,3 +760,5 @@ void gpu_select_pick_cache_load_id(void)
}
}
}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_select_private.h b/source/blender/gpu/intern/gpu_select_private.h
index e49feb3fc50..e5a84a037a6 100644
--- a/source/blender/gpu/intern/gpu_select_private.h
+++ b/source/blender/gpu/intern/gpu_select_private.h
@@ -30,16 +30,21 @@ extern "C" {
#endif
/* gpu_select_pick */
+
void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, char mode);
bool gpu_select_pick_load_id(uint id, bool end);
uint gpu_select_pick_end(void);
void gpu_select_pick_cache_begin(void);
void gpu_select_pick_cache_end(void);
+/**
+ * \return true if drawing is not needed.
+ */
bool gpu_select_pick_is_cached(void);
void gpu_select_pick_cache_load_id(void);
/* gpu_select_sample_query */
+
void gpu_select_query_begin(
uint (*buffer)[4], uint bufsize, const rcti *input, char mode, int oldhits);
bool gpu_select_query_load_id(uint id);
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.cc b/source/blender/gpu/intern/gpu_select_sample_query.cc
index 7b9b3020639..a430d4a9d62 100644
--- a/source/blender/gpu/intern/gpu_select_sample_query.cc
+++ b/source/blender/gpu/intern/gpu_select_sample_query.cc
@@ -20,8 +20,8 @@
/** \file
* \ingroup gpu
*
- * Interface for accessing gpu-related methods for selection. The semantics will be
- * similar to glRenderMode(GL_SELECT) since the goal is to maintain compatibility.
+ * Interface for accessing GPU-related methods for selection. The semantics will be
+ * similar to `glRenderMode(GL_SELECT)` since the goal is to maintain compatibility.
*/
#include <cstdlib>
@@ -151,7 +151,7 @@ bool gpu_select_query_load_id(uint id)
return true;
}
-uint gpu_select_query_end(void)
+uint gpu_select_query_end()
{
uint hits = 0;
const uint maxhits = g_query_state.bufsize;
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index cab73963620..830e65f69d9 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -31,10 +31,32 @@
#include "gpu_backend.hh"
#include "gpu_context_private.hh"
+#include "gpu_shader_create_info.hh"
+#include "gpu_shader_create_info_private.hh"
+#include "gpu_shader_dependency_private.h"
#include "gpu_shader_private.hh"
+#include <string>
+
extern "C" char datatoc_gpu_shader_colorspace_lib_glsl[];
+namespace blender::gpu {
+
+std::string Shader::defines_declare(const shader::ShaderCreateInfo &info) const
+{
+ std::string defines;
+ for (const auto &def : info.defines_) {
+ defines += "#define ";
+ defines += def[0];
+ defines += " ";
+ defines += def[1];
+ defines += "\n";
+ }
+ return defines;
+}
+
+} // namespace blender::gpu
+
using namespace blender;
using namespace blender::gpu;
@@ -59,6 +81,8 @@ static void standard_defines(Vector<const char *> &sources)
BLI_assert(sources.size() == 0);
/* Version needs to be first. Exact values will be added by implementation. */
sources.append("version");
+ /* Define to identify code usage in shading language. */
+ sources.append("#define GPU_SHADER\n");
/* some useful defines to detect GPU type */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
sources.append("#define GPU_ATI\n");
@@ -225,6 +249,188 @@ GPUShader *GPU_shader_create_compute(const char *computecode,
shname);
}
+GPUShader *GPU_shader_create_from_info_name(const char *info_name)
+{
+ using namespace blender::gpu::shader;
+ const GPUShaderCreateInfo *_info = gpu_shader_create_info_get(info_name);
+ const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>(_info);
+ if (!info.do_static_compilation_) {
+ printf("Warning: Trying to compile \"%s\" which was not marked for static compilation.\n",
+ info.name_.c_str());
+ }
+ return GPU_shader_create_from_info(_info);
+}
+
+GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
+{
+ using namespace blender::gpu::shader;
+ const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>(_info);
+
+ const_cast<ShaderCreateInfo &>(info).finalize();
+
+ /* At least a vertex shader and a fragment shader are required, or only a compute shader. */
+ if (info.compute_source_.is_empty()) {
+ if (info.vertex_source_.is_empty()) {
+ printf("Missing vertex shader in %s.\n", info.name_.c_str());
+ }
+ if (info.fragment_source_.is_empty()) {
+ printf("Missing fragment shader in %s.\n", info.name_.c_str());
+ }
+ BLI_assert(!info.vertex_source_.is_empty() && !info.fragment_source_.is_empty());
+ }
+ else {
+ if (!info.vertex_source_.is_empty()) {
+ printf("Compute shader has vertex_source_ shader attached in %s.\n", info.name_.c_str());
+ }
+ if (!info.geometry_source_.is_empty()) {
+ printf("Compute shader has geometry_source_ shader attached in %s.\n", info.name_.c_str());
+ }
+ if (!info.fragment_source_.is_empty()) {
+ printf("Compute shader has fragment_source_ shader attached in %s.\n", info.name_.c_str());
+ }
+ BLI_assert(info.vertex_source_.is_empty() && info.geometry_source_.is_empty() &&
+ info.fragment_source_.is_empty());
+ }
+
+ Shader *shader = GPUBackend::get()->shader_alloc(info.name_.c_str());
+
+ std::string defines = shader->defines_declare(info);
+ std::string resources = shader->resources_declare(info);
+ char *shader_shared_utils = nullptr;
+
+ defines += "#define USE_GPU_SHADER_CREATE_INFO\n";
+
+ Vector<char *> typedefs;
+ for (auto filename : info.typedef_sources_) {
+ typedefs.append(gpu_shader_dependency_get_source(filename.c_str()));
+ }
+ if (!typedefs.is_empty()) {
+ shader_shared_utils = gpu_shader_dependency_get_source("gpu_shader_shared_utils.h");
+ }
+
+ if (!info.vertex_source_.is_empty()) {
+ uint32_t builtins = 0;
+ std::string interface = shader->vertex_interface_declare(info);
+ char *code = gpu_shader_dependency_get_resolved_source(info.vertex_source_.c_str(), &builtins);
+
+ Vector<const char *> sources;
+ standard_defines(sources);
+ sources.append("#define GPU_VERTEX_SHADER\n");
+ if (!info.geometry_source_.is_empty()) {
+ sources.append("#define USE_GEOMETRY_SHADER\n");
+ }
+ sources.append(defines.c_str());
+ if (!typedefs.is_empty()) {
+ sources.append(shader_shared_utils);
+ }
+ for (auto *types : typedefs) {
+ sources.append(types);
+ }
+ sources.append(resources.c_str());
+ sources.append(interface.c_str());
+ sources.append(code);
+
+ shader->vertex_shader_from_glsl(sources);
+
+ free(code);
+ }
+
+ if (!info.fragment_source_.is_empty()) {
+ uint32_t builtins = 0;
+ std::string interface = shader->fragment_interface_declare(info);
+ char *code = gpu_shader_dependency_get_resolved_source(info.fragment_source_.c_str(),
+ &builtins);
+
+ Vector<const char *> sources;
+ standard_defines(sources);
+ sources.append("#define GPU_FRAGMENT_SHADER\n");
+ if (!info.geometry_source_.is_empty()) {
+ sources.append("#define USE_GEOMETRY_SHADER\n");
+ }
+ sources.append(defines.c_str());
+ if (!typedefs.is_empty()) {
+ sources.append(shader_shared_utils);
+ }
+ for (auto *types : typedefs) {
+ sources.append(types);
+ }
+ sources.append(resources.c_str());
+ sources.append(interface.c_str());
+ sources.append(code);
+
+ shader->fragment_shader_from_glsl(sources);
+
+ free(code);
+ }
+
+ if (!info.geometry_source_.is_empty()) {
+ uint32_t builtins = 0;
+ std::string interface = shader->geometry_interface_declare(info);
+ std::string layout = shader->geometry_layout_declare(info);
+ char *code = gpu_shader_dependency_get_resolved_source(info.geometry_source_.c_str(),
+ &builtins);
+
+ Vector<const char *> sources;
+ standard_defines(sources);
+ sources.append("#define GPU_GEOMETRY_SHADER\n");
+ sources.append(defines.c_str());
+ if (!typedefs.is_empty()) {
+ sources.append(shader_shared_utils);
+ }
+ for (auto *types : typedefs) {
+ sources.append(types);
+ }
+ sources.append(resources.c_str());
+ sources.append(layout.c_str());
+ sources.append(interface.c_str());
+ sources.append(code);
+
+ shader->geometry_shader_from_glsl(sources);
+
+ free(code);
+ }
+
+ if (!info.compute_source_.is_empty()) {
+ uint32_t builtins = 0;
+ char *code = gpu_shader_dependency_get_resolved_source(info.compute_source_.c_str(),
+ &builtins);
+ std::string layout = shader->compute_layout_declare(info);
+
+ Vector<const char *> sources;
+ standard_defines(sources);
+ sources.append("#define GPU_COMPUTE_SHADER\n");
+ sources.append(defines.c_str());
+ if (!typedefs.is_empty()) {
+ sources.append(shader_shared_utils);
+ }
+ for (auto *types : typedefs) {
+ sources.append(types);
+ }
+ sources.append(resources.c_str());
+ sources.append(layout.c_str());
+ sources.append(code);
+
+ shader->compute_shader_from_glsl(sources);
+
+ free(code);
+ }
+
+ for (auto *types : typedefs) {
+ free(types);
+ }
+
+ if (shader_shared_utils) {
+ free(shader_shared_utils);
+ }
+
+ if (!shader->finalize(&info)) {
+ delete shader;
+ return nullptr;
+ }
+
+ return wrap(shader);
+}
+
GPUShader *GPU_shader_create_from_python(const char *vertcode,
const char *fragcode,
const char *geomcode,
@@ -284,26 +490,6 @@ static const char *string_join_array_maybe_alloc(const char **str_arr, bool *r_i
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, const char *func, int line)
{
@@ -359,7 +545,7 @@ void GPU_shader_bind(GPUShader *gpu_shader)
}
}
-void GPU_shader_unbind(void)
+void GPU_shader_unbind()
{
#ifndef NDEBUG
Context *ctx = Context::get();
@@ -437,7 +623,6 @@ int GPU_shader_get_ssbo(GPUShader *shader, const char *name)
return ssbo ? ssbo->location : -1;
}
-/* DEPRECATED. */
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
{
ShaderInterface *interface = unwrap(shader)->interface;
@@ -472,7 +657,6 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name)
/** \name Getters
* \{ */
-/* DEPRECATED: Kept only because of BGL API */
int GPU_shader_get_program(GPUShader *shader)
{
return unwrap(shader)->program_handle_get();
diff --git a/source/blender/gpu/intern/gpu_shader_builder.cc b/source/blender/gpu/intern/gpu_shader_builder.cc
new file mode 100644
index 00000000000..334bdb2ec58
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_builder.cc
@@ -0,0 +1,102 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Compile time automation of shader compilation and validation.
+ */
+
+#include <iostream>
+
+#include "GHOST_C-api.h"
+
+#include "GPU_context.h"
+#include "GPU_init_exit.h"
+#include "gpu_shader_create_info_private.hh"
+
+#include "CLG_log.h"
+
+namespace blender::gpu::shader_builder {
+
+class ShaderBuilder {
+ private:
+ GHOST_SystemHandle ghost_system_;
+ GHOST_ContextHandle ghost_context_;
+ GPUContext *gpu_context_ = nullptr;
+
+ public:
+ void init();
+ bool bake_create_infos();
+ void exit();
+};
+
+bool ShaderBuilder::bake_create_infos()
+{
+ return gpu_shader_create_info_compile_all();
+}
+
+void ShaderBuilder::init()
+{
+ CLG_init();
+
+ GHOST_GLSettings glSettings = {0};
+ ghost_system_ = GHOST_CreateSystem();
+ ghost_context_ = GHOST_CreateOpenGLContext(ghost_system_, glSettings);
+ GHOST_ActivateOpenGLContext(ghost_context_);
+
+ gpu_context_ = GPU_context_create(nullptr);
+ GPU_init();
+}
+
+void ShaderBuilder::exit()
+{
+ GPU_backend_exit();
+ GPU_exit();
+
+ GPU_context_discard(gpu_context_);
+
+ GHOST_DisposeOpenGLContext(ghost_system_, ghost_context_);
+ GHOST_DisposeSystem(ghost_system_);
+
+ CLG_exit();
+}
+
+} // namespace blender::gpu::shader_builder
+
+/** \brief Entry point for the shader_builder. */
+int main(int argc, const char *argv[])
+{
+ if (argc < 2) {
+ printf("Usage: %s <data_file_to>\n", argv[0]);
+ exit(1);
+ }
+
+ int exit_code = 0;
+
+ blender::gpu::shader_builder::ShaderBuilder builder;
+ builder.init();
+ if (!builder.bake_create_infos()) {
+ exit_code = 1;
+ }
+ builder.exit();
+ exit(exit_code);
+
+ return exit_code;
+}
diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
new file mode 100644
index 00000000000..40e54ab4394
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
@@ -0,0 +1,258 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Stubs to reduce linking time for shader_builder.
+ */
+
+#include "BLI_utildefines.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_subdiv_ccg.h"
+
+#include "DNA_userdef_types.h"
+
+#include "DRW_engine.h"
+
+#include "bmesh.h"
+
+#include "UI_resources.h"
+
+extern "C" {
+
+Global G;
+UserDef U;
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BLI_imbuf_types.h
+ * \{ */
+
+void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
+{
+ BLI_assert_unreachable();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of UI_resources.h
+ * \{ */
+
+void UI_GetThemeColor4fv(int UNUSED(colorid), float UNUSED(col[4]))
+{
+ BLI_assert_unreachable();
+}
+
+void UI_GetThemeColor3fv(int UNUSED(colorid), float UNUSED(col[3]))
+{
+ BLI_assert_unreachable();
+}
+
+void UI_GetThemeColorShade4fv(int UNUSED(colorid), int UNUSED(offset), float UNUSED(col[4]))
+{
+ BLI_assert_unreachable();
+}
+
+void UI_GetThemeColorShadeAlpha4fv(int UNUSED(colorid),
+ int UNUSED(coloffset),
+ int UNUSED(alphaoffset),
+ float UNUSED(col[4]))
+{
+ BLI_assert_unreachable();
+}
+void UI_GetThemeColorBlendShade4fv(int UNUSED(colorid1),
+ int UNUSED(colorid2),
+ float UNUSED(fac),
+ int UNUSED(offset),
+ float UNUSED(col[4]))
+{
+ BLI_assert_unreachable();
+}
+
+void UI_GetThemeColorBlend3ubv(int UNUSED(colorid1),
+ int UNUSED(colorid2),
+ float UNUSED(fac),
+ unsigned char UNUSED(col[3]))
+{
+ BLI_assert_unreachable();
+}
+
+void UI_GetThemeColorShadeAlpha4ubv(int UNUSED(colorid),
+ int UNUSED(coloffset),
+ int UNUSED(alphaoffset),
+ unsigned char UNUSED(col[4]))
+{
+ BLI_assert_unreachable();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_paint.h
+ * \{ */
+bool paint_is_face_hidden(const struct MLoopTri *UNUSED(lt),
+ const struct MVert *UNUSED(mvert),
+ const struct MLoop *UNUSED(mloop))
+{
+ BLI_assert_unreachable();
+ return false;
+}
+
+void BKE_paint_face_set_overlay_color_get(const int UNUSED(face_set),
+ const int UNUSED(seed),
+ uchar UNUSED(r_color[4]))
+{
+ BLI_assert_unreachable();
+}
+
+bool paint_is_grid_face_hidden(const unsigned int *UNUSED(grid_hidden),
+ int UNUSED(gridsize),
+ int UNUSED(x),
+ int UNUSED(y))
+{
+ BLI_assert_unreachable();
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_mesh.h
+ * \{ */
+void BKE_mesh_calc_poly_normal(const struct MPoly *UNUSED(mpoly),
+ const struct MLoop *UNUSED(loopstart),
+ const struct MVert *UNUSED(mvarray),
+ float UNUSED(r_no[3]))
+{
+ BLI_assert_unreachable();
+}
+
+void BKE_mesh_looptri_get_real_edges(const struct Mesh *UNUSED(mesh),
+ const struct MLoopTri *UNUSED(looptri),
+ int UNUSED(r_edges[3]))
+{
+ BLI_assert_unreachable();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_material.h
+ * \{ */
+
+void BKE_material_defaults_free_gpu(void)
+{
+ /* This function is reachable via GPU_exit. */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_customdata.h
+ * \{ */
+
+int CustomData_get_offset(const struct CustomData *UNUSED(data), int UNUSED(type))
+{
+ BLI_assert_unreachable();
+ return 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_pbvh.h
+ * \{ */
+
+int BKE_pbvh_count_grid_quads(BLI_bitmap **UNUSED(grid_hidden),
+ const int *UNUSED(grid_indices),
+ int UNUSED(totgrid),
+ int UNUSED(gridsize))
+{
+ BLI_assert_unreachable();
+ return 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_subdiv_ccg.h
+ * \{ */
+int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *UNUSED(subdiv_ccg),
+ const int UNUSED(grid_index))
+{
+ BLI_assert_unreachable();
+ return 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_node.h
+ * \{ */
+void ntreeGPUMaterialNodes(struct bNodeTree *UNUSED(localtree),
+ struct GPUMaterial *UNUSED(mat),
+ bool *UNUSED(has_surface_output),
+ bool *UNUSED(has_volume_output))
+{
+ BLI_assert_unreachable();
+}
+
+struct bNodeTree *ntreeLocalize(struct bNodeTree *UNUSED(ntree))
+{
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+void ntreeFreeLocalTree(struct bNodeTree *UNUSED(ntree))
+{
+ BLI_assert_unreachable();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of bmesh.h
+ * \{ */
+void BM_face_as_array_vert_tri(BMFace *UNUSED(f), BMVert *UNUSED(r_verts[3]))
+{
+ BLI_assert_unreachable();
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of DRW_engine.h
+ * \{ */
+void DRW_deferred_shader_remove(struct GPUMaterial *UNUSED(mat))
+{
+ BLI_assert_unreachable();
+}
+
+/** \} */
+}
diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c
index 9ea46788f44..6b1163fdc78 100644
--- a/source/blender/gpu/intern/gpu_shader_builtin.c
+++ b/source/blender/gpu/intern/gpu_shader_builtin.c
@@ -77,6 +77,7 @@ extern char datatoc_gpu_shader_image_overlays_merge_frag_glsl[];
extern char datatoc_gpu_shader_image_overlays_stereo_merge_frag_glsl[];
extern char datatoc_gpu_shader_image_color_frag_glsl[];
extern char datatoc_gpu_shader_image_desaturate_frag_glsl[];
+extern char datatoc_gpu_shader_image_modulate_alpha_frag_glsl[];
extern char datatoc_gpu_shader_image_varying_color_frag_glsl[];
extern char datatoc_gpu_shader_image_shuffle_color_frag_glsl[];
extern char datatoc_gpu_shader_3D_vert_glsl[];
@@ -92,28 +93,15 @@ extern char datatoc_gpu_shader_3D_clipped_uniform_color_vert_glsl[];
extern char datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl[];
-extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[];
extern char datatoc_gpu_shader_point_uniform_color_aa_frag_glsl[];
extern char datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl[];
-extern char datatoc_gpu_shader_point_varying_color_outline_aa_frag_glsl[];
extern char datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl[];
extern char datatoc_gpu_shader_point_varying_color_frag_glsl[];
extern char datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl[];
-extern char datatoc_gpu_shader_3D_point_varying_size_vert_glsl[];
extern char datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl[];
extern char datatoc_gpu_shader_3D_point_uniform_size_aa_vert_glsl[];
-extern char datatoc_gpu_shader_3D_point_uniform_size_outline_aa_vert_glsl[];
-extern char datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl[];
extern char datatoc_gpu_shader_2D_point_uniform_size_aa_vert_glsl[];
extern char datatoc_gpu_shader_2D_point_uniform_size_outline_aa_vert_glsl[];
-extern char datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert_glsl[];
-
-extern char datatoc_gpu_shader_2D_edituvs_points_vert_glsl[];
-extern char datatoc_gpu_shader_2D_edituvs_facedots_vert_glsl[];
-extern char datatoc_gpu_shader_2D_edituvs_edges_vert_glsl[];
-extern char datatoc_gpu_shader_2D_edituvs_edges_frag_glsl[];
-extern char datatoc_gpu_shader_2D_edituvs_faces_vert_glsl[];
-extern char datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl[];
extern char datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl[];
extern char datatoc_gpu_shader_2D_line_dashed_frag_glsl[];
@@ -157,133 +145,97 @@ typedef struct {
const char *frag;
/** Optional. */
const char *defs;
+
+ const char *create_info;
+ const char *clipped_create_info;
} GPUShaderStages;
static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
[GPU_SHADER_TEXT] =
{
.name = "GPU_SHADER_TEXT",
- .vert = datatoc_gpu_shader_text_vert_glsl,
- .frag = datatoc_gpu_shader_text_frag_glsl,
+ .create_info = "gpu_shader_text",
},
[GPU_SHADER_KEYFRAME_SHAPE] =
{
.name = "GPU_SHADER_KEYFRAME_SHAPE",
- .vert = datatoc_gpu_shader_keyframe_shape_vert_glsl,
- .frag = datatoc_gpu_shader_keyframe_shape_frag_glsl,
+ .create_info = "gpu_shader_keyframe_shape",
},
[GPU_SHADER_SIMPLE_LIGHTING] =
{
.name = "GPU_SHADER_SIMPLE_LIGHTING",
- .vert = datatoc_gpu_shader_3D_normal_vert_glsl,
- .frag = datatoc_gpu_shader_simple_lighting_frag_glsl,
+ .create_info = "gpu_shader_simple_lighting",
+ },
+ [GPU_SHADER_3D_IMAGE_MODULATE_ALPHA] =
+ {
+ .name = "GPU_SHADER_3D_IMAGE_MODULATE_ALPHA",
+ .create_info = "gpu_shader_3D_image_modulate_alpha",
},
-
[GPU_SHADER_2D_CHECKER] =
{
.name = "GPU_SHADER_2D_CHECKER",
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_checker_frag_glsl,
+ .create_info = "gpu_shader_2D_checker",
},
[GPU_SHADER_2D_DIAG_STRIPES] =
{
.name = "GPU_SHADER_2D_DIAG_STRIPES",
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_diag_stripes_frag_glsl,
+ .create_info = "gpu_shader_2D_diag_stripes",
},
- [GPU_SHADER_2D_UNIFORM_COLOR] =
- {
- .name = "GPU_SHADER_2D_UNIFORM_COLOR",
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_uniform_color_frag_glsl,
- },
- [GPU_SHADER_2D_FLAT_COLOR] =
- {
- .name = "GPU_SHADER_2D_FLAT_COLOR",
- .vert = datatoc_gpu_shader_2D_flat_color_vert_glsl,
- .frag = datatoc_gpu_shader_flat_color_frag_glsl,
- },
- [GPU_SHADER_2D_SMOOTH_COLOR] =
- {
- .name = "GPU_SHADER_2D_SMOOTH_COLOR",
- .vert = datatoc_gpu_shader_2D_smooth_color_vert_glsl,
- .frag = datatoc_gpu_shader_2D_smooth_color_frag_glsl,
- },
+ [GPU_SHADER_2D_UNIFORM_COLOR] = {.name = "GPU_SHADER_2D_UNIFORM_COLOR",
+ .create_info = "gpu_shader_2D_uniform_color"},
+ [GPU_SHADER_2D_FLAT_COLOR] = {.name = "GPU_SHADER_2D_FLAT_COLOR",
+ .create_info = "gpu_shader_2D_flat_color"},
+ [GPU_SHADER_2D_SMOOTH_COLOR] = {.name = "GPU_SHADER_2D_SMOOTH_COLOR",
+ .create_info = "gpu_shader_2D_smooth_color"},
[GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE] =
{
.name = "GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE",
+#ifdef __APPLE__
+ /* GPUShaderCreateInfo is disabled on MacOS due to mismatch with OCIO shader. See
+ * T95052 for more details. */
.vert = datatoc_gpu_shader_2D_image_vert_glsl,
.frag = datatoc_gpu_shader_image_overlays_merge_frag_glsl,
+#else
+ .create_info = "gpu_shader_2D_image_overlays_merge",
+#endif
},
[GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE] =
- {
- .name = "GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE",
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_image_overlays_stereo_merge_frag_glsl,
- },
- [GPU_SHADER_2D_IMAGE] =
- {
- .name = "GPU_SHADER_2D_IMAGE",
- .vert = datatoc_gpu_shader_2D_image_vert_glsl,
- .frag = datatoc_gpu_shader_image_frag_glsl,
- },
- [GPU_SHADER_2D_IMAGE_COLOR] =
- {
- .name = "GPU_SHADER_2D_IMAGE_COLOR",
- .vert = datatoc_gpu_shader_2D_image_vert_glsl,
- .frag = datatoc_gpu_shader_image_color_frag_glsl,
- },
- [GPU_SHADER_2D_IMAGE_DESATURATE_COLOR] =
- {
- .name = "GPU_SHADER_2D_IMAGE_DESATURATE_COLOR",
- .vert = datatoc_gpu_shader_2D_image_vert_glsl,
- .frag = datatoc_gpu_shader_image_desaturate_frag_glsl,
- },
+ {.name = "GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE",
+ .create_info = "gpu_shader_2D_image_overlays_stereo_merge"},
+ [GPU_SHADER_2D_IMAGE] = {.name = "GPU_SHADER_2D_IMAGE", .create_info = "gpu_shader_2D_image"},
+ [GPU_SHADER_2D_IMAGE_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_COLOR",
+ .create_info = "gpu_shader_2D_image_color"},
+ [GPU_SHADER_2D_IMAGE_DESATURATE_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_DESATURATE_COLOR",
+ .create_info =
+ "gpu_shader_2D_image_desaturate_color"},
[GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR] =
{
.name = "GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR",
- .vert = datatoc_gpu_shader_2D_image_vert_glsl,
- .frag = datatoc_gpu_shader_image_shuffle_color_frag_glsl,
- },
- [GPU_SHADER_2D_IMAGE_RECT_COLOR] =
- {
- .name = "GPU_SHADER_2D_IMAGE_RECT_COLOR",
- .vert = datatoc_gpu_shader_2D_image_rect_vert_glsl,
- .frag = datatoc_gpu_shader_image_color_frag_glsl,
- },
- [GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR] =
- {
- .name = "GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR",
- .vert = datatoc_gpu_shader_2D_image_multi_rect_vert_glsl,
- .frag = datatoc_gpu_shader_image_varying_color_frag_glsl,
+ .create_info = "gpu_shader_2D_image_shuffle_color",
},
+ [GPU_SHADER_2D_IMAGE_RECT_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_RECT_COLOR",
+ .create_info = "gpu_shader_2D_image_rect_color"},
+ [GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR",
+ .create_info =
+ "gpu_shader_2D_image_multi_rect_color"},
[GPU_SHADER_3D_UNIFORM_COLOR] =
{
.name = "GPU_SHADER_3D_UNIFORM_COLOR",
- .vert = datatoc_gpu_shader_3D_vert_glsl,
- .frag = datatoc_gpu_shader_uniform_color_frag_glsl,
- },
- [GPU_SHADER_3D_FLAT_COLOR] =
- {
- .name = "GPU_SHADER_3D_FLAT_COLOR",
- .vert = datatoc_gpu_shader_3D_flat_color_vert_glsl,
- .frag = datatoc_gpu_shader_flat_color_frag_glsl,
- },
- [GPU_SHADER_3D_SMOOTH_COLOR] =
- {
- .name = "GPU_SHADER_3D_SMOOTH_COLOR",
- .vert = datatoc_gpu_shader_3D_smooth_color_vert_glsl,
- .frag = datatoc_gpu_shader_3D_smooth_color_frag_glsl,
- },
- [GPU_SHADER_3D_DEPTH_ONLY] =
- {
- .name = "GPU_SHADER_3D_DEPTH_ONLY",
- .vert = datatoc_gpu_shader_3D_vert_glsl,
- .frag = datatoc_gpu_shader_depth_only_frag_glsl,
- },
+ .create_info = "gpu_shader_3D_uniform_color",
+ .clipped_create_info = "gpu_shader_3D_uniform_color_clipped",
+ },
+ [GPU_SHADER_3D_FLAT_COLOR] = {.name = "GPU_SHADER_3D_FLAT_COLOR",
+ .create_info = "gpu_shader_3D_flat_color",
+ .clipped_create_info = "gpu_shader_3D_flat_color_clipped"},
+ [GPU_SHADER_3D_SMOOTH_COLOR] = {.name = "GPU_SHADER_3D_SMOOTH_COLOR",
+ .create_info = "gpu_shader_3D_smooth_color",
+ .clipped_create_info = "gpu_shader_3D_smooth_color_clipped"},
+ [GPU_SHADER_3D_DEPTH_ONLY] = {.name = "GPU_SHADER_3D_DEPTH_ONLY",
+ .create_info = "gpu_shader_3D_depth_only",
+ .clipped_create_info = "gpu_shader_3D_depth_only_clipped"},
[GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR] =
{
.name = "GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR",
@@ -338,72 +290,26 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.frag = datatoc_gpu_shader_2D_line_dashed_frag_glsl,
},
- [GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR] =
- {
- .name = "GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR",
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_frag_glsl,
- },
- [GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR] =
- {
- .name = "GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR",
- .vert = datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl,
- .frag = datatoc_gpu_shader_point_varying_color_frag_glsl,
- },
[GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA] =
{
.name = "GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA",
- .vert = datatoc_gpu_shader_2D_point_uniform_size_aa_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_aa_frag_glsl,
+ .create_info = "gpu_shader_2D_point_uniform_size_uniform_color_aa",
},
[GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA] =
{
.name = "GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA",
- .vert = datatoc_gpu_shader_2D_point_uniform_size_outline_aa_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl,
- },
- [GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA] =
- {
- .name = "GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA",
- .vert = datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert_glsl,
- .frag = datatoc_gpu_shader_point_varying_color_outline_aa_frag_glsl,
- },
- [GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR] =
- {
- .name = "GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR",
- .vert = datatoc_gpu_shader_3D_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_frag_glsl,
+ .create_info = "gpu_shader_2D_point_uniform_size_uniform_color_outline_aa",
},
[GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR] =
- {
- .name = "GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR",
- .vert = datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl,
- .frag = datatoc_gpu_shader_point_varying_color_frag_glsl,
- },
- [GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR] =
- {
- .name = "GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR",
- .vert = datatoc_gpu_shader_3D_point_varying_size_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_frag_glsl,
- },
+ {.name = "GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR",
+ .create_info = "gpu_shader_3D_point_fixed_size_varying_color"},
[GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR] =
- {
- .name = "GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR",
- .vert = datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl,
- .frag = datatoc_gpu_shader_point_varying_color_frag_glsl,
- },
+ {.name = "GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR",
+ .create_info = "gpu_shader_3D_point_varying_size_varying_color"},
[GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA] =
- {
- .name = "GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA",
- .vert = datatoc_gpu_shader_3D_point_uniform_size_aa_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_aa_frag_glsl,
- },
- [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA] =
- {
- .name = "GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA",
- .vert = datatoc_gpu_shader_3D_point_uniform_size_outline_aa_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl,
- },
+ {.name = "GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA",
+ .create_info = "gpu_shader_3D_point_uniform_size_uniform_color_aa",
+ .clipped_create_info = "gpu_shader_3D_point_uniform_size_uniform_color_aa_clipped"},
[GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE] =
{
@@ -413,12 +319,8 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.defs = "#define UNIFORM_SCALE\n",
},
- [GPU_SHADER_2D_AREA_EDGES] =
- {
- .name = "GPU_SHADER_2D_AREA_EDGES",
- .vert = datatoc_gpu_shader_2D_area_borders_vert_glsl,
- .frag = datatoc_gpu_shader_2D_area_borders_frag_glsl,
- },
+ [GPU_SHADER_2D_AREA_BORDERS] = {.name = "GPU_SHADER_2D_AREA_BORDERS",
+ .create_info = "gpu_shader_2D_area_borders"},
[GPU_SHADER_2D_WIDGET_BASE] =
{
.name = "GPU_SHADER_2D_WIDGET_BASE",
@@ -438,79 +340,14 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.vert = datatoc_gpu_shader_2D_widget_shadow_vert_glsl,
.frag = datatoc_gpu_shader_2D_widget_shadow_frag_glsl,
},
- [GPU_SHADER_2D_NODELINK] =
- {
- .name = "GPU_SHADER_2D_NODELINK",
- .vert = datatoc_gpu_shader_2D_nodelink_vert_glsl,
- .frag = datatoc_gpu_shader_2D_nodelink_frag_glsl,
- },
- [GPU_SHADER_2D_NODELINK_INST] =
- {
- .name = "GPU_SHADER_2D_NODELINK_INST",
- .vert = datatoc_gpu_shader_2D_nodelink_vert_glsl,
- .frag = datatoc_gpu_shader_2D_nodelink_frag_glsl,
- .defs = "#define USE_INSTANCE\n",
- },
+ [GPU_SHADER_2D_NODELINK] = {.name = "GPU_SHADER_2D_NODELINK",
+ .create_info = "gpu_shader_2D_nodelink"},
- [GPU_SHADER_2D_UV_UNIFORM_COLOR] =
- {
- .name = "GPU_SHADER_2D_UV_UNIFORM_COLOR",
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_uniform_color_frag_glsl,
- .defs = "#define UV_POS\n",
- },
- [GPU_SHADER_2D_UV_VERTS] =
- {
- .name = "GPU_SHADER_2D_UV_VERTS",
- .vert = datatoc_gpu_shader_2D_edituvs_points_vert_glsl,
- .frag = datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl,
- },
- [GPU_SHADER_2D_UV_FACEDOTS] =
- {
- .name = "GPU_SHADER_2D_UV_FACEDOTS",
- .vert = datatoc_gpu_shader_2D_edituvs_facedots_vert_glsl,
- .frag = datatoc_gpu_shader_point_varying_color_frag_glsl,
- },
- [GPU_SHADER_2D_UV_EDGES] =
- {
- .name = "GPU_SHADER_2D_UV_EDGES",
- .vert = datatoc_gpu_shader_2D_edituvs_edges_vert_glsl,
- .frag = datatoc_gpu_shader_2D_edituvs_edges_frag_glsl,
- },
- [GPU_SHADER_2D_UV_EDGES_SMOOTH] =
- {
- .name = "GPU_SHADER_2D_UV_EDGES_SMOOTH",
- .vert = datatoc_gpu_shader_2D_edituvs_edges_vert_glsl,
- .frag = datatoc_gpu_shader_2D_edituvs_edges_frag_glsl,
- .defs = "#define SMOOTH_COLOR\n",
- },
- [GPU_SHADER_2D_UV_FACES] =
- {
- .name = "GPU_SHADER_2D_UV_FACES",
- .vert = datatoc_gpu_shader_2D_edituvs_faces_vert_glsl,
- .frag = datatoc_gpu_shader_flat_color_frag_glsl,
- },
- [GPU_SHADER_2D_UV_FACES_STRETCH_AREA] =
- {
- .name = "GPU_SHADER_2D_UV_FACES_STRETCH_AREA",
- .vert = datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl,
- .frag = datatoc_gpu_shader_2D_smooth_color_frag_glsl,
- },
- [GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE] =
- {
- .name = "GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE",
- .vert = datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl,
- .frag = datatoc_gpu_shader_2D_smooth_color_frag_glsl,
- .defs = "#define STRETCH_ANGLE\n",
- },
+ [GPU_SHADER_2D_NODELINK_INST] = {.name = "GPU_SHADER_2D_NODELINK_INST",
+ .create_info = "gpu_shader_2D_nodelink_inst"},
- [GPU_SHADER_GPENCIL_STROKE] =
- {
- .name = "GPU_SHADER_GPENCIL_STROKE",
- .vert = datatoc_gpu_shader_gpencil_stroke_vert_glsl,
- .geom = datatoc_gpu_shader_gpencil_stroke_geom_glsl,
- .frag = datatoc_gpu_shader_gpencil_stroke_frag_glsl,
- },
+ [GPU_SHADER_GPENCIL_STROKE] = {.name = "GPU_SHADER_GPENCIL_STROKE",
+ .create_info = "gpu_shader_gpencil_stroke"},
};
GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
@@ -525,14 +362,20 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
/* common case */
if (sh_cfg == GPU_SHADER_CFG_DEFAULT) {
- *sh_p = GPU_shader_create_from_arrays_named(
- stages->name,
- {
- .vert = (const char *[]){stages->vert, NULL},
- .geom = (const char *[]){stages->geom, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL},
- .defs = (const char *[]){stages->defs, NULL},
- });
+ if (stages->create_info != NULL) {
+ *sh_p = GPU_shader_create_from_info_name(stages->create_info);
+ }
+ else {
+ *sh_p = GPU_shader_create_from_arrays_named(
+ stages->name,
+ {
+ .vert = (const char *[]){stages->vert, NULL},
+ .geom = (const char *[]){stages->geom, NULL},
+ .frag =
+ (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL},
+ .defs = (const char *[]){stages->defs, NULL},
+ });
+ }
}
else if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
/* Remove eventually, for now ensure support for each shader has been added. */
@@ -541,21 +384,26 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
GPU_SHADER_3D_SMOOTH_COLOR,
GPU_SHADER_3D_DEPTH_ONLY,
GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE,
- GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA,
GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA,
GPU_SHADER_3D_FLAT_COLOR,
GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR));
- const char *world_clip_lib = datatoc_gpu_shader_cfg_world_clip_lib_glsl;
- const char *world_clip_def = "#define USE_WORLD_CLIP_PLANES\n";
/* In rare cases geometry shaders calculate clipping themselves. */
- *sh_p = GPU_shader_create_from_arrays_named(
- stages->name,
- {
- .vert = (const char *[]){world_clip_lib, stages->vert, NULL},
- .geom = (const char *[]){stages->geom ? world_clip_lib : NULL, stages->geom, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL},
- .defs = (const char *[]){world_clip_def, stages->defs, NULL},
- });
+ if (stages->clipped_create_info != NULL) {
+ *sh_p = GPU_shader_create_from_info_name(stages->clipped_create_info);
+ }
+ else {
+ const char *world_clip_lib = datatoc_gpu_shader_cfg_world_clip_lib_glsl;
+ const char *world_clip_def = "#define USE_WORLD_CLIP_PLANES\n";
+ *sh_p = GPU_shader_create_from_arrays_named(
+ stages->name,
+ {
+ .vert = (const char *[]){world_clip_lib, stages->vert, NULL},
+ .geom = (const char *[]){stages->geom ? world_clip_lib : NULL, stages->geom, NULL},
+ .frag =
+ (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL},
+ .defs = (const char *[]){world_clip_def, stages->defs, NULL},
+ });
+ }
}
else {
BLI_assert(0);
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc
new file mode 100644
index 00000000000..f7622751726
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_create_info.cc
@@ -0,0 +1,263 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Descriptor type used to define shader structure, resources and interfaces.
+ */
+
+#include "BLI_map.hh"
+#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
+
+#include "GPU_capabilities.h"
+#include "GPU_platform.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+#include "gpu_shader_create_info.hh"
+#include "gpu_shader_create_info_private.hh"
+
+#undef GPU_SHADER_INTERFACE_INFO
+#undef GPU_SHADER_CREATE_INFO
+
+namespace blender::gpu::shader {
+
+using CreateInfoDictionnary = Map<StringRef, ShaderCreateInfo *>;
+using InterfaceDictionnary = Map<StringRef, StageInterfaceInfo *>;
+
+static CreateInfoDictionnary *g_create_infos = nullptr;
+static InterfaceDictionnary *g_interfaces = nullptr;
+
+void ShaderCreateInfo::finalize()
+{
+ if (finalized_) {
+ return;
+ }
+ finalized_ = true;
+
+ for (auto &info_name : additional_infos_) {
+ const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>(
+ gpu_shader_create_info_get(info_name.c_str()));
+
+ /* Recursive. */
+ const_cast<ShaderCreateInfo &>(info).finalize();
+
+#if 0 /* Enabled for debugging merging. TODO(fclem) exception handling and error reporting in \
+ console. */
+ std::cout << "Merging : " << info_name << " > " << name_ << std::endl;
+#endif
+
+ interface_names_size_ += info.interface_names_size_;
+
+ vertex_inputs_.extend(info.vertex_inputs_);
+ fragment_outputs_.extend(info.fragment_outputs_);
+ vertex_out_interfaces_.extend(info.vertex_out_interfaces_);
+ geometry_out_interfaces_.extend(info.geometry_out_interfaces_);
+
+ push_constants_.extend(info.push_constants_);
+ defines_.extend(info.defines_);
+
+ batch_resources_.extend(info.batch_resources_);
+ pass_resources_.extend(info.pass_resources_);
+ typedef_sources_.extend_non_duplicates(info.typedef_sources_);
+
+ validate(info);
+
+ if (info.compute_layout_.local_size_x != -1) {
+ compute_layout_.local_size_x = info.compute_layout_.local_size_x;
+ compute_layout_.local_size_y = info.compute_layout_.local_size_y;
+ compute_layout_.local_size_z = info.compute_layout_.local_size_z;
+ }
+
+ if (!info.vertex_source_.is_empty()) {
+ BLI_assert(vertex_source_.is_empty());
+ vertex_source_ = info.vertex_source_;
+ }
+ if (!info.geometry_source_.is_empty()) {
+ BLI_assert(geometry_source_.is_empty());
+ geometry_source_ = info.geometry_source_;
+ geometry_layout_ = info.geometry_layout_;
+ }
+ if (!info.fragment_source_.is_empty()) {
+ BLI_assert(fragment_source_.is_empty());
+ fragment_source_ = info.fragment_source_;
+ }
+ if (!info.compute_source_.is_empty()) {
+ BLI_assert(compute_source_.is_empty());
+ compute_source_ = info.compute_source_;
+ }
+
+ do_static_compilation_ = do_static_compilation_ || info.do_static_compilation_;
+ }
+}
+
+void ShaderCreateInfo::validate(const ShaderCreateInfo &other_info)
+{
+ {
+ /* Check same bind-points usage in OGL. */
+ Set<int> images, samplers, ubos, ssbos;
+
+ auto register_resource = [&](const Resource &res) -> bool {
+ switch (res.bind_type) {
+ case Resource::BindType::UNIFORM_BUFFER:
+ return images.add(res.slot);
+ case Resource::BindType::STORAGE_BUFFER:
+ return samplers.add(res.slot);
+ case Resource::BindType::SAMPLER:
+ return ubos.add(res.slot);
+ case Resource::BindType::IMAGE:
+ return ssbos.add(res.slot);
+ default:
+ return false;
+ }
+ };
+
+ auto print_error_msg = [&](const Resource &res) {
+ std::cerr << name_ << ": Validation failed : Overlapping ";
+
+ switch (res.bind_type) {
+ case Resource::BindType::UNIFORM_BUFFER:
+ std::cerr << "Uniform Buffer " << res.uniformbuf.name;
+ break;
+ case Resource::BindType::STORAGE_BUFFER:
+ std::cerr << "Storage Buffer " << res.storagebuf.name;
+ break;
+ case Resource::BindType::SAMPLER:
+ std::cerr << "Sampler " << res.sampler.name;
+ break;
+ case Resource::BindType::IMAGE:
+ std::cerr << "Image " << res.image.name;
+ break;
+ default:
+ std::cerr << "Unknown Type";
+ break;
+ }
+ std::cerr << " (" << res.slot << ") while merging " << other_info.name_ << std::endl;
+ };
+
+ for (auto &res : batch_resources_) {
+ if (register_resource(res) == false) {
+ print_error_msg(res);
+ }
+ }
+
+ for (auto &res : pass_resources_) {
+ if (register_resource(res) == false) {
+ print_error_msg(res);
+ }
+ }
+ }
+ {
+ /* TODO(fclem) Push constant validation. */
+ }
+}
+
+} // namespace blender::gpu::shader
+
+using namespace blender::gpu::shader;
+
+void gpu_shader_create_info_init()
+{
+ g_create_infos = new CreateInfoDictionnary();
+ g_interfaces = new InterfaceDictionnary();
+
+#define GPU_SHADER_INTERFACE_INFO(_interface, _inst_name) \
+ auto *ptr_##_interface = new StageInterfaceInfo(#_interface, _inst_name); \
+ auto &_interface = *ptr_##_interface; \
+ g_interfaces->add_new(#_interface, ptr_##_interface); \
+ _interface
+
+#define GPU_SHADER_CREATE_INFO(_info) \
+ auto *ptr_##_info = new ShaderCreateInfo(#_info); \
+ auto &_info = *ptr_##_info; \
+ g_create_infos->add_new(#_info, ptr_##_info); \
+ _info
+
+/* Declare, register and construct the infos. */
+#include "gpu_shader_create_info_list.hh"
+
+/* Baked shader data appended to create infos. */
+/* TODO(jbakker): should call a function with a callback. so we could switch implementations.
+ * We cannot compile bf_gpu twice. */
+#ifdef GPU_RUNTIME
+# include "gpu_shader_baked.hh"
+#endif
+
+ /* WORKAROUND: Replace draw_mesh info with the legacy one for systems that have problems with UBO
+ * indexing. */
+ if (GPU_type_matches(GPU_DEVICE_INTEL | GPU_DEVICE_INTEL_UHD, GPU_OS_ANY, GPU_DRIVER_ANY) ||
+ GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY) || GPU_crappy_amd_driver()) {
+ draw_modelmat = draw_modelmat_legacy;
+ }
+
+ /* TEST */
+ // gpu_shader_create_info_compile_all();
+}
+
+void gpu_shader_create_info_exit()
+{
+ for (auto *value : g_create_infos->values()) {
+ delete value;
+ }
+ delete g_create_infos;
+
+ for (auto *value : g_interfaces->values()) {
+ delete value;
+ }
+ delete g_interfaces;
+}
+
+bool gpu_shader_create_info_compile_all()
+{
+ int success = 0;
+ int total = 0;
+ for (ShaderCreateInfo *info : g_create_infos->values()) {
+ if (info->do_static_compilation_) {
+ total++;
+ GPUShader *shader = GPU_shader_create_from_info(
+ reinterpret_cast<const GPUShaderCreateInfo *>(info));
+ if (shader == nullptr) {
+ printf("Compilation %s Failed\n", info->name_.c_str());
+ }
+ else {
+ success++;
+ }
+ GPU_shader_free(shader);
+ }
+ }
+ printf("===============================\n");
+ printf("Shader Test compilation result: \n");
+ printf("%d Total\n", total);
+ printf("%d Passed\n", success);
+ printf("%d Failed\n", total - success);
+ printf("===============================\n");
+ return success == total;
+}
+
+/* Runtime create infos are not registered in the dictionary and cannot be searched. */
+const GPUShaderCreateInfo *gpu_shader_create_info_get(const char *info_name)
+{
+ if (g_create_infos->contains(info_name) == false) {
+ printf("Error: Cannot find shader create info named \"%s\"\n", info_name);
+ }
+ ShaderCreateInfo *info = g_create_infos->lookup(info_name);
+ return reinterpret_cast<const GPUShaderCreateInfo *>(info);
+}
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh
new file mode 100644
index 00000000000..6236e92a226
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_create_info.hh
@@ -0,0 +1,622 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Descriptor type used to define shader structure, resources and interfaces.
+ *
+ * Some rule of thumb:
+ * - Do not include anything else than this file in each info file.
+ */
+
+#pragma once
+
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+#include "GPU_texture.h"
+
+namespace blender::gpu::shader {
+
+#ifndef GPU_SHADER_CREATE_INFO
+/* Helps intelisense / auto-completion. */
+# define GPU_SHADER_INTERFACE_INFO(_interface, _inst_name) \
+ StageInterfaceInfo _interface(#_interface, _inst_name); \
+ _interface
+# define GPU_SHADER_CREATE_INFO(_info) \
+ ShaderCreateInfo _info(#_info); \
+ _info
+#endif
+
+enum class Type {
+ FLOAT = 0,
+ VEC2,
+ VEC3,
+ VEC4,
+ MAT3,
+ MAT4,
+ UINT,
+ UVEC2,
+ UVEC3,
+ UVEC4,
+ INT,
+ IVEC2,
+ IVEC3,
+ IVEC4,
+ BOOL,
+};
+
+enum class BuiltinBits {
+ /**
+ * Allow getting barycentric coordinates inside the fragment shader.
+ * \note Emulated on OpenGL.
+ */
+ BARYCENTRIC_COORD = (1 << 0),
+ FRAG_COORD = (1 << 2),
+ FRONT_FACING = (1 << 4),
+ GLOBAL_INVOCATION_ID = (1 << 5),
+ INSTANCE_ID = (1 << 6),
+ LAYER = (1 << 7),
+ LOCAL_INVOCATION_ID = (1 << 8),
+ LOCAL_INVOCATION_INDEX = (1 << 9),
+ NUM_WORK_GROUP = (1 << 10),
+ POINT_COORD = (1 << 11),
+ POINT_SIZE = (1 << 12),
+ PRIMITIVE_ID = (1 << 13),
+ VERTEX_ID = (1 << 14),
+ WORK_GROUP_ID = (1 << 15),
+ WORK_GROUP_SIZE = (1 << 16),
+};
+ENUM_OPERATORS(BuiltinBits, BuiltinBits::WORK_GROUP_SIZE);
+
+/* Samplers & images. */
+enum class ImageType {
+ /** Color samplers/image. */
+ FLOAT_BUFFER = 0,
+ FLOAT_1D,
+ FLOAT_1D_ARRAY,
+ FLOAT_2D,
+ FLOAT_2D_ARRAY,
+ FLOAT_3D,
+ FLOAT_CUBE,
+ FLOAT_CUBE_ARRAY,
+ INT_BUFFER,
+ INT_1D,
+ INT_1D_ARRAY,
+ INT_2D,
+ INT_2D_ARRAY,
+ INT_3D,
+ INT_CUBE,
+ INT_CUBE_ARRAY,
+ UINT_BUFFER,
+ UINT_1D,
+ UINT_1D_ARRAY,
+ UINT_2D,
+ UINT_2D_ARRAY,
+ UINT_3D,
+ UINT_CUBE,
+ UINT_CUBE_ARRAY,
+ /** Depth samplers (not supported as image). */
+ SHADOW_2D,
+ SHADOW_2D_ARRAY,
+ SHADOW_CUBE,
+ SHADOW_CUBE_ARRAY,
+ DEPTH_2D,
+ DEPTH_2D_ARRAY,
+ DEPTH_CUBE,
+ DEPTH_CUBE_ARRAY,
+};
+
+/* Storage qualifiers. */
+enum class Qualifier {
+ RESTRICT = (1 << 0),
+ READ_ONLY = (1 << 1),
+ WRITE_ONLY = (1 << 2),
+ QUALIFIER_MAX = (WRITE_ONLY << 1) - 1,
+};
+ENUM_OPERATORS(Qualifier, Qualifier::QUALIFIER_MAX);
+
+enum class Frequency {
+ BATCH = 0,
+ PASS,
+};
+
+/* Dual Source Blending Index. */
+enum class DualBlend {
+ NONE = 0,
+ SRC_0,
+ SRC_1,
+};
+
+/* Interpolation qualifiers. */
+enum class Interpolation {
+ SMOOTH = 0,
+ FLAT,
+ NO_PERSPECTIVE,
+};
+
+/** Input layout for geometry shader. */
+enum class PrimitiveIn {
+ POINTS = 0,
+ LINES,
+ LINES_ADJACENCY,
+ TRIANGLES,
+ TRIANGLES_ADJACENCY,
+};
+
+/** Output layout for geometry shader. */
+enum class PrimitiveOut {
+ POINTS = 0,
+ LINE_STRIP,
+ TRIANGLE_STRIP,
+};
+
+struct StageInterfaceInfo {
+ struct InOut {
+ Interpolation interp;
+ Type type;
+ StringRefNull name;
+ };
+
+ StringRefNull name;
+ /** Name of the instance of the block (used to access).
+ * Can be empty string (i.e: "") only if not using geometry shader. */
+ StringRefNull instance_name;
+ /** List of all members of the interface. */
+ Vector<InOut> inouts;
+
+ StageInterfaceInfo(const char *name_, const char *instance_name_)
+ : name(name_), instance_name(instance_name_){};
+ ~StageInterfaceInfo(){};
+
+ using Self = StageInterfaceInfo;
+
+ Self &smooth(Type type, StringRefNull _name)
+ {
+ inouts.append({Interpolation::SMOOTH, type, _name});
+ return *(Self *)this;
+ }
+
+ Self &flat(Type type, StringRefNull _name)
+ {
+ inouts.append({Interpolation::FLAT, type, _name});
+ return *(Self *)this;
+ }
+
+ Self &no_perspective(Type type, StringRefNull _name)
+ {
+ inouts.append({Interpolation::NO_PERSPECTIVE, type, _name});
+ return *(Self *)this;
+ }
+};
+
+/**
+ * @brief Describe inputs & outputs, stage interfaces, resources and sources of a shader.
+ * If all data is correctly provided, this is all that is needed to create and compile
+ * a GPUShader.
+ *
+ * IMPORTANT: All strings are references only. Make sure all the strings used by a
+ * ShaderCreateInfo are not freed until it is consumed or deleted.
+ */
+struct ShaderCreateInfo {
+ /** Shader name for debugging. */
+ StringRefNull name_;
+ /** True if the shader is static and can be pre-compiled at compile time. */
+ bool do_static_compilation_ = false;
+ /** If true, all additionally linked create info will be merged into this one. */
+ bool finalized_ = false;
+ /**
+ * Maximum length of all the resource names including each null terminator.
+ * Only for names used by gpu::ShaderInterface.
+ */
+ size_t interface_names_size_ = 0;
+
+ struct VertIn {
+ int index;
+ Type type;
+ StringRefNull name;
+ };
+ Vector<VertIn> vertex_inputs_;
+
+ struct GeometryStageLayout {
+ PrimitiveIn primitive_in;
+ int invocations;
+ PrimitiveOut primitive_out;
+ /** Set to -1 by default to check if used. */
+ int max_vertices = -1;
+ };
+ GeometryStageLayout geometry_layout_;
+
+ struct ComputeStageLayout {
+ int local_size_x = -1;
+ int local_size_y = -1;
+ int local_size_z = -1;
+ };
+
+ ComputeStageLayout compute_layout_;
+
+ struct FragOut {
+ int index;
+ Type type;
+ DualBlend blend;
+ StringRefNull name;
+ };
+ Vector<FragOut> fragment_outputs_;
+
+ struct Sampler {
+ ImageType type;
+ eGPUSamplerState sampler;
+ StringRefNull name;
+ };
+
+ struct Image {
+ eGPUTextureFormat format;
+ ImageType type;
+ Qualifier qualifiers;
+ StringRefNull name;
+ };
+
+ struct UniformBuf {
+ StringRefNull type_name;
+ StringRefNull name;
+ };
+
+ struct StorageBuf {
+ Qualifier qualifiers;
+ StringRefNull type_name;
+ StringRefNull name;
+ };
+
+ struct Resource {
+ enum BindType {
+ UNIFORM_BUFFER = 0,
+ STORAGE_BUFFER,
+ SAMPLER,
+ IMAGE,
+ };
+
+ BindType bind_type;
+ int slot;
+ union {
+ Sampler sampler;
+ Image image;
+ UniformBuf uniformbuf;
+ StorageBuf storagebuf;
+ };
+
+ Resource(BindType type, int _slot) : bind_type(type), slot(_slot){};
+ };
+ /**
+ * Resources are grouped by frequency of change.
+ * Pass resources are meant to be valid for the whole pass.
+ * Batch resources can be changed in a more granular manner (per object/material).
+ * Mis-usage will only produce suboptimal performance.
+ */
+ Vector<Resource> pass_resources_, batch_resources_;
+
+ Vector<StageInterfaceInfo *> vertex_out_interfaces_;
+ Vector<StageInterfaceInfo *> geometry_out_interfaces_;
+
+ struct PushConst {
+ int index;
+ Type type;
+ StringRefNull name;
+ int array_size;
+ };
+
+ Vector<PushConst> push_constants_;
+
+ /* Sources for resources type definitions. */
+ Vector<StringRefNull> typedef_sources_;
+
+ StringRefNull vertex_source_, geometry_source_, fragment_source_, compute_source_;
+
+ Vector<std::array<StringRefNull, 2>> defines_;
+ /**
+ * Name of other infos to recursively merge with this one.
+ * No data slot must overlap otherwise we throw an error.
+ */
+ Vector<StringRefNull> additional_infos_;
+
+ public:
+ ShaderCreateInfo(const char *name) : name_(name){};
+ ~ShaderCreateInfo(){};
+
+ using Self = ShaderCreateInfo;
+
+ /* -------------------------------------------------------------------- */
+ /** \name Shaders in/outs (fixed function pipeline config)
+ * \{ */
+
+ Self &vertex_in(int slot, Type type, StringRefNull name)
+ {
+ vertex_inputs_.append({slot, type, name});
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ Self &vertex_out(StageInterfaceInfo &interface)
+ {
+ vertex_out_interfaces_.append(&interface);
+ return *(Self *)this;
+ }
+
+ /**
+ * IMPORTANT: invocations count is only used if GL_ARB_gpu_shader5 is supported. On
+ * implementations that do not supports it, the max_vertices will be be multiplied by
+ * invocations. Your shader needs to account for this fact. Use `#ifdef GPU_ARB_gpu_shader5`
+ * and make a code path that does not rely on gl_InvocationID.
+ */
+ Self &geometry_layout(PrimitiveIn prim_in,
+ PrimitiveOut prim_out,
+ int max_vertices,
+ int invocations = -1)
+ {
+ geometry_layout_.primitive_in = prim_in;
+ geometry_layout_.primitive_out = prim_out;
+ geometry_layout_.max_vertices = max_vertices;
+ geometry_layout_.invocations = invocations;
+ return *(Self *)this;
+ }
+
+ Self &local_group_size(int local_size_x = -1, int local_size_y = -1, int local_size_z = -1)
+ {
+ compute_layout_.local_size_x = local_size_x;
+ compute_layout_.local_size_y = local_size_y;
+ compute_layout_.local_size_z = local_size_z;
+ return *(Self *)this;
+ }
+
+ /**
+ * Only needed if geometry shader is enabled.
+ * IMPORTANT: Input and output instance name will have respectively "_in" and "_out" suffix
+ * appended in the geometry shader IF AND ONLY IF the vertex_out interface instance name matches
+ * the geometry_out interface instance name.
+ */
+ Self &geometry_out(StageInterfaceInfo &interface)
+ {
+ geometry_out_interfaces_.append(&interface);
+ return *(Self *)this;
+ }
+
+ Self &fragment_out(int slot, Type type, StringRefNull name, DualBlend blend = DualBlend::NONE)
+ {
+ fragment_outputs_.append({slot, type, blend, name});
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Resources bindings points
+ * \{ */
+
+ Self &uniform_buf(int slot,
+ StringRefNull type_name,
+ StringRefNull name,
+ Frequency freq = Frequency::PASS)
+ {
+ Resource res(Resource::BindType::UNIFORM_BUFFER, slot);
+ res.uniformbuf.name = name;
+ res.uniformbuf.type_name = type_name;
+ ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res);
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ Self &storage_buf(int slot,
+ Qualifier qualifiers,
+ StringRefNull type_name,
+ StringRefNull name,
+ Frequency freq = Frequency::PASS)
+ {
+ Resource res(Resource::BindType::STORAGE_BUFFER, slot);
+ res.storagebuf.qualifiers = qualifiers;
+ res.storagebuf.type_name = type_name;
+ res.storagebuf.name = name;
+ ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res);
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ Self &image(int slot,
+ eGPUTextureFormat format,
+ Qualifier qualifiers,
+ ImageType type,
+ StringRefNull name,
+ Frequency freq = Frequency::PASS)
+ {
+ Resource res(Resource::BindType::IMAGE, slot);
+ res.image.format = format;
+ res.image.qualifiers = qualifiers;
+ res.image.type = type;
+ res.image.name = name;
+ ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res);
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ Self &sampler(int slot,
+ ImageType type,
+ StringRefNull name,
+ Frequency freq = Frequency::PASS,
+ eGPUSamplerState sampler = (eGPUSamplerState)-1)
+ {
+ Resource res(Resource::BindType::SAMPLER, slot);
+ res.sampler.type = type;
+ res.sampler.name = name;
+ res.sampler.sampler = sampler;
+ ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res);
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Shader Source
+ * \{ */
+
+ Self &vertex_source(StringRefNull filename)
+ {
+ vertex_source_ = filename;
+ return *(Self *)this;
+ }
+
+ Self &geometry_source(StringRefNull filename)
+ {
+ geometry_source_ = filename;
+ return *(Self *)this;
+ }
+
+ Self &fragment_source(StringRefNull filename)
+ {
+ fragment_source_ = filename;
+ return *(Self *)this;
+ }
+
+ Self &compute_source(StringRefNull filename)
+ {
+ compute_source_ = filename;
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Push constants
+ *
+ * Data managed by GPUShader. Can be set through uniform functions. Must be less than 128bytes.
+ * One slot represents 4bytes. Each element needs to have enough empty space left after it.
+ * example:
+ * [0] = PUSH_CONSTANT(MAT4, "ModelMatrix"),
+ * ---- 16 slots occupied by ModelMatrix ----
+ * [16] = PUSH_CONSTANT(VEC4, "color"),
+ * ---- 4 slots occupied by color ----
+ * [20] = PUSH_CONSTANT(BOOL, "srgbToggle"),
+ * The maximum slot is 31.
+ * \{ */
+
+ Self &push_constant(int slot, Type type, StringRefNull name, int array_size = 0)
+ {
+ BLI_assert_msg(name.find("[") == -1,
+ "Array syntax is forbidden for push constants."
+ "Use the array_size parameter instead.");
+ push_constants_.append({slot, type, name, array_size});
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Defines
+ * \{ */
+
+ Self &define(StringRefNull name, StringRefNull value = "")
+ {
+ defines_.append({name, value});
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Defines
+ * \{ */
+
+ Self &do_static_compilation(bool value)
+ {
+ do_static_compilation_ = value;
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Additional Create Info
+ *
+ * Used to share parts of the infos that are common to many shaders.
+ * \{ */
+
+ Self &additional_info(StringRefNull info_name0,
+ StringRefNull info_name1 = "",
+ StringRefNull info_name2 = "",
+ StringRefNull info_name3 = "",
+ StringRefNull info_name4 = "",
+ StringRefNull info_name5 = "",
+ StringRefNull info_name6 = "")
+ {
+ additional_infos_.append(info_name0);
+ if (!info_name1.is_empty()) {
+ additional_infos_.append(info_name1);
+ }
+ if (!info_name2.is_empty()) {
+ additional_infos_.append(info_name2);
+ }
+ if (!info_name3.is_empty()) {
+ additional_infos_.append(info_name3);
+ }
+ if (!info_name4.is_empty()) {
+ additional_infos_.append(info_name4);
+ }
+ if (!info_name5.is_empty()) {
+ additional_infos_.append(info_name5);
+ }
+ if (!info_name6.is_empty()) {
+ additional_infos_.append(info_name6);
+ }
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Typedef Sources
+ *
+ * Some resource declarations might need some special structure defined.
+ * Adding a file using typedef_source will include it before the resource
+ * and interface definitions.
+ * \{ */
+
+ Self &typedef_source(StringRefNull filename)
+ {
+ typedef_sources_.append(filename);
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Recursive evaluation.
+ *
+ * Flatten all dependency so that this descriptor contains all the data from the additional
+ * descriptors. This avoids tedious traversal in shader source creation.
+ * \{ */
+
+ /* WARNING: Recursive. */
+ void finalize();
+
+ /** Error detection that some backend compilers do not complain about. */
+ void validate(const ShaderCreateInfo &other_info);
+
+ /** \} */
+};
+
+} // namespace blender::gpu::shader
diff --git a/source/blender/gpu/intern/gpu_shader_create_info_private.hh b/source/blender/gpu/intern/gpu_shader_create_info_private.hh
new file mode 100644
index 00000000000..6d2878377ad
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_create_info_private.hh
@@ -0,0 +1,46 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Descriptor type used to define shader structure, resources and interfaces.
+ *
+ * Some rule of thumb:
+ * - Do not include anything else than this file in each descriptor file.
+ */
+
+#pragma once
+
+#include "GPU_shader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gpu_shader_create_info_init(void);
+void gpu_shader_create_info_exit(void);
+
+bool gpu_shader_create_info_compile_all(void);
+
+const GPUShaderCreateInfo *gpu_shader_create_info_get(const char *info_name);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
new file mode 100644
index 00000000000..2333590810f
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -0,0 +1,388 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Shader source dependency builder that make possible to support #include directive inside the
+ * shader files.
+ */
+
+#include <iostream>
+
+#include "BLI_map.hh"
+#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
+
+#include "gpu_shader_create_info.hh"
+#include "gpu_shader_dependency_private.h"
+
+extern "C" {
+#define SHADER_SOURCE(datatoc, filename, filepath) extern char datatoc[];
+#include "glsl_draw_source_list.h"
+#include "glsl_gpu_source_list.h"
+#undef SHADER_SOURCE
+}
+
+namespace blender::gpu {
+
+using GPUSourceDictionnary = Map<StringRef, struct GPUSource *>;
+
+struct GPUSource {
+ StringRefNull fullpath;
+ StringRefNull filename;
+ StringRefNull source;
+ Vector<GPUSource *> dependencies;
+ bool dependencies_init = false;
+ shader::BuiltinBits builtins = (shader::BuiltinBits)0;
+ std::string processed_source;
+
+ GPUSource(const char *path, const char *file, const char *datatoc)
+ : fullpath(path), filename(file), source(datatoc)
+ {
+ /* Scan for builtins. */
+ /* FIXME: This can trigger false positive caused by disabled #if blocks. */
+ /* TODO(fclem): Could be made faster by scanning once. */
+ /* TODO(fclem): BARYCENTRIC_COORD. */
+ if (source.find("gl_FragCoord", 0)) {
+ builtins |= shader::BuiltinBits::FRAG_COORD;
+ }
+ if (source.find("gl_FrontFacing", 0)) {
+ builtins |= shader::BuiltinBits::FRONT_FACING;
+ }
+ if (source.find("gl_GlobalInvocationID", 0)) {
+ builtins |= shader::BuiltinBits::GLOBAL_INVOCATION_ID;
+ }
+ if (source.find("gl_InstanceID", 0)) {
+ builtins |= shader::BuiltinBits::INSTANCE_ID;
+ }
+ if (source.find("gl_Layer", 0)) {
+ builtins |= shader::BuiltinBits::LAYER;
+ }
+ if (source.find("gl_LocalInvocationID", 0)) {
+ builtins |= shader::BuiltinBits::LOCAL_INVOCATION_ID;
+ }
+ if (source.find("gl_LocalInvocationIndex", 0)) {
+ builtins |= shader::BuiltinBits::LOCAL_INVOCATION_INDEX;
+ }
+ if (source.find("gl_NumWorkGroup", 0)) {
+ builtins |= shader::BuiltinBits::NUM_WORK_GROUP;
+ }
+ if (source.find("gl_PointCoord", 0)) {
+ builtins |= shader::BuiltinBits::POINT_COORD;
+ }
+ if (source.find("gl_PointSize", 0)) {
+ builtins |= shader::BuiltinBits::POINT_SIZE;
+ }
+ if (source.find("gl_PrimitiveID", 0)) {
+ builtins |= shader::BuiltinBits::PRIMITIVE_ID;
+ }
+ if (source.find("gl_VertexID", 0)) {
+ builtins |= shader::BuiltinBits::VERTEX_ID;
+ }
+ if (source.find("gl_WorkGroupID", 0)) {
+ builtins |= shader::BuiltinBits::WORK_GROUP_ID;
+ }
+ if (source.find("gl_WorkGroupSize", 0)) {
+ builtins |= shader::BuiltinBits::WORK_GROUP_SIZE;
+ }
+
+ /* TODO(fclem): We could do that at compile time. */
+ /* Limit to shared header files to avoid the temptation to use C++ syntax in .glsl files. */
+ if (filename.endswith(".h") || filename.endswith(".hh")) {
+ enum_preprocess();
+ }
+ };
+
+ bool is_in_comment(const StringRef &input, int64_t offset)
+ {
+ return (input.rfind("/*", offset) > input.rfind("*/", offset)) ||
+ (input.rfind("//", offset) > input.rfind("\n", offset));
+ }
+
+ template<bool check_whole_word = true, bool reversed = false, typename T>
+ int64_t find_str(const StringRef &input, const T keyword, int64_t offset = 0)
+ {
+ while (1) {
+ if constexpr (reversed) {
+ offset = input.rfind(keyword, offset);
+ }
+ else {
+ offset = input.find(keyword, offset);
+ }
+ if (offset > 0) {
+ if constexpr (check_whole_word) {
+ /* Fix false positive if something has "enum" as suffix. */
+ char previous_char = input[offset - 1];
+ if (!(ELEM(previous_char, '\n', '\t', ' ', ':'))) {
+ offset += (reversed) ? -1 : 1;
+ continue;
+ }
+ }
+ /* Fix case where the keyword is in a comment. */
+ if (is_in_comment(input, offset)) {
+ offset += (reversed) ? -1 : 1;
+ continue;
+ }
+ }
+ return offset;
+ }
+ }
+
+ void print_error(const StringRef &input, int64_t offset, const StringRef message)
+ {
+ std::cout << " error: " << message << "\n";
+ StringRef sub = input.substr(0, offset);
+ int64_t line_number = std::count(sub.begin(), sub.end(), '\n') + 1;
+ int64_t line_end = input.find("\n", offset);
+ int64_t line_start = input.rfind("\n", offset) + 1;
+ int64_t char_number = offset - line_start + 1;
+ char line_prefix[16] = "";
+ SNPRINTF(line_prefix, "%5ld | ", line_number);
+
+ /* TODO Use clog. */
+
+ std::cout << fullpath << ":" << line_number << ":" << char_number;
+
+ std::cout << " error: " << message << "\n";
+ std::cout << line_prefix << input.substr(line_start, line_end - line_start) << "\n";
+ std::cout << " | ";
+ for (int64_t i = 0; i < char_number - 1; i++) {
+ std::cout << " ";
+ }
+ std::cout << "^\n";
+ }
+
+ /**
+ * Transform C,C++ enum declaration into GLSL compatible defines and constants:
+ *
+ * \code{.cpp}
+ * enum eMyEnum : uint32_t {
+ * ENUM_1 = 0u,
+ * ENUM_2 = 1u,
+ * ENUM_3 = 2u,
+ * };
+ * \endcode
+ *
+ * or
+ *
+ * \code{.c}
+ * enum eMyEnum {
+ * ENUM_1 = 0u,
+ * ENUM_2 = 1u,
+ * ENUM_3 = 2u,
+ * };
+ * \endcode
+ *
+ * becomes
+ *
+ * \code{.glsl}
+ * #define eMyEnum uint
+ * const uint ENUM_1 = 0u, ENUM_2 = 1u, ENUM_3 = 2u;
+ * \endcode
+ *
+ * IMPORTANT: This has some requirements:
+ * - Enums needs to have underlying types specified to uint32_t to make them usable in UBO/SSBO.
+ * - All values needs to be specified using constant literals to avoid compiler differencies.
+ * - All values needs to have the 'u' suffix to avoid GLSL compiler errors.
+ */
+ void enum_preprocess(void)
+ {
+ const StringRefNull input = source;
+ std::string output = "";
+ int64_t cursor = 0;
+ int64_t last_pos = 0;
+ const bool is_cpp = filename.endswith(".hh");
+
+#define find_keyword find_str<true, false>
+#define find_token find_str<false, false>
+#define rfind_token find_str<false, true>
+#define CHECK(test_value, str, ofs, msg) \
+ if ((test_value) == -1) { \
+ print_error(str, ofs, msg); \
+ cursor++; \
+ continue; \
+ }
+
+ while (1) {
+ cursor = find_keyword(input, "enum ", cursor);
+ if (cursor == -1) {
+ break;
+ }
+ /* Output anything between 2 enums blocks. */
+ output += input.substr(last_pos, cursor - last_pos);
+
+ /* Extract enum type name. */
+ int64_t name_start = input.find(" ", cursor);
+
+ int64_t values_start = find_token(input, '{', cursor);
+ CHECK(values_start, input, cursor, "Malformed enum class. Expected \'{\' after typename.");
+
+ StringRef enum_name = input.substr(name_start, values_start - name_start);
+ if (is_cpp) {
+ int64_t name_end = find_token(enum_name, ":");
+ CHECK(name_end, input, name_start, "Expected \':\' after C++ enum name.");
+
+ int64_t underlying_type = find_keyword(enum_name, "uint32_t", name_end);
+ CHECK(underlying_type, input, name_start, "C++ enums needs uint32_t underlying type.");
+
+ enum_name = input.substr(name_start, name_end);
+ }
+
+ output += "#define " + enum_name + " uint\n";
+
+ /* Extract enum values. */
+ int64_t values_end = find_token(input, '}', values_start);
+ CHECK(values_end, input, cursor, "Malformed enum class. Expected \'}\' after values.");
+
+ /* Skip opening brackets. */
+ values_start += 1;
+
+ StringRef enum_values = input.substr(values_start, values_end - values_start);
+
+ /* Really poor check. Could be done better. */
+ int64_t token = find_token(enum_values, '{');
+ int64_t not_found = (token == -1) ? 0 : -1;
+ CHECK(not_found, input, values_start + token, "Unexpected \'{\' token inside enum values.");
+
+ /* Do not capture the comma after the last value (if present). */
+ int64_t last_equal = rfind_token(enum_values, '=', values_end);
+ int64_t last_comma = rfind_token(enum_values, ',', values_end);
+ if (last_comma > last_equal) {
+ enum_values = input.substr(values_start, last_comma);
+ }
+
+ output += "const uint " + enum_values;
+
+ int64_t semicolon_found = (input[values_end + 1] == ';') ? 0 : -1;
+ CHECK(semicolon_found, input, values_end + 1, "Expected \';\' after enum type declaration.");
+
+ /* Skip the curly bracket but not the semicolon. */
+ cursor = last_pos = values_end + 1;
+ }
+ /* If nothing has been changed, do not allocate processed_source. */
+ if (last_pos == 0) {
+ return;
+ }
+
+#undef find_keyword
+#undef find_token
+#undef rfind_token
+
+ if (last_pos != 0) {
+ output += input.substr(last_pos);
+ }
+ processed_source = output;
+ source = processed_source.c_str();
+ };
+
+ void init_dependencies(const GPUSourceDictionnary &dict)
+ {
+ if (dependencies_init) {
+ return;
+ }
+ dependencies_init = true;
+ int64_t pos = 0;
+ while (true) {
+ pos = source.find("pragma BLENDER_REQUIRE(", pos);
+ if (pos == -1) {
+ return;
+ }
+ int64_t start = source.find('(', pos) + 1;
+ int64_t end = source.find(')', pos);
+ if (end == -1) {
+ /* TODO Use clog. */
+ std::cout << "Error: " << filename << " : Malformed BLENDER_REQUIRE: Missing \")\"."
+ << std::endl;
+ return;
+ }
+ StringRef dependency_name = source.substr(start, end - start);
+ GPUSource *dependency_source = dict.lookup_default(dependency_name, nullptr);
+ if (dependency_source == nullptr) {
+ /* TODO Use clog. */
+ std::cout << "Error: " << filename << " : Dependency not found \"" << dependency_name
+ << "\"." << std::endl;
+ return;
+ }
+ /* Recursive. */
+ dependency_source->init_dependencies(dict);
+
+ for (auto *dep : dependency_source->dependencies) {
+ dependencies.append_non_duplicates(dep);
+ }
+ dependencies.append_non_duplicates(dependency_source);
+ pos++;
+ };
+ }
+
+ /* Returns the final string with all includes done. */
+ void build(std::string &str, shader::BuiltinBits &out_builtins)
+ {
+ for (auto *dep : dependencies) {
+ out_builtins |= builtins;
+ str += dep->source;
+ }
+ str += source;
+ }
+};
+
+} // namespace blender::gpu
+
+using namespace blender::gpu;
+
+static GPUSourceDictionnary *g_sources = nullptr;
+
+void gpu_shader_dependency_init()
+{
+ g_sources = new GPUSourceDictionnary();
+
+#define SHADER_SOURCE(datatoc, filename, filepath) \
+ g_sources->add_new(filename, new GPUSource(filepath, filename, datatoc));
+#include "glsl_draw_source_list.h"
+#include "glsl_gpu_source_list.h"
+#undef SHADER_SOURCE
+
+ for (auto *value : g_sources->values()) {
+ value->init_dependencies(*g_sources);
+ }
+}
+
+void gpu_shader_dependency_exit()
+{
+ for (auto *value : g_sources->values()) {
+ delete value;
+ }
+ delete g_sources;
+}
+
+char *gpu_shader_dependency_get_resolved_source(const char *shader_source_name, uint32_t *builtins)
+{
+ GPUSource *source = g_sources->lookup(shader_source_name);
+ std::string str;
+ shader::BuiltinBits out_builtins;
+ source->build(str, out_builtins);
+ *builtins |= (uint32_t)out_builtins;
+ return strdup(str.c_str());
+}
+
+char *gpu_shader_dependency_get_source(const char *shader_source_name)
+{
+ GPUSource *src = g_sources->lookup(shader_source_name);
+ return strdup(src->source.c_str());
+}
diff --git a/source/blender/gpu/intern/gpu_shader_dependency_private.h b/source/blender/gpu/intern/gpu_shader_dependency_private.h
new file mode 100644
index 00000000000..b129ca74a48
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_dependency_private.h
@@ -0,0 +1,44 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Shader source dependency builder that make possible to support #include directive inside the
+ * shader files.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gpu_shader_dependency_init(void);
+
+void gpu_shader_dependency_exit(void);
+
+/* User must free the resulting string using free. */
+char *gpu_shader_dependency_get_resolved_source(const char *shader_source_name,
+ uint32_t *builtins);
+char *gpu_shader_dependency_get_source(const char *shader_source_name);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/intern/gpu_shader_info_baked.cc b/source/blender/gpu/intern/gpu_shader_info_baked.cc
new file mode 100644
index 00000000000..55115a6d459
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_info_baked.cc
@@ -0,0 +1,24 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Intentionally empty for compiling shader builder.
+ */
diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc
index ae94112b17b..937f49ccaec 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.cc
+++ b/source/blender/gpu/intern/gpu_shader_interface.cc
@@ -65,14 +65,17 @@ static void sort_input_list(MutableSpan<ShaderInput> dst)
}
}
-/* Sorts all inputs inside their respective array.
- * This is to allow fast hash collision detection.
- * See ShaderInterface::input_lookup for more details. */
void ShaderInterface::sort_inputs()
{
+ /* Sorts all inputs inside their respective array.
+ * This is to allow fast hash collision detection.
+ * See `ShaderInterface::input_lookup` for more details. */
+
sort_input_list(MutableSpan<ShaderInput>(inputs_, attr_len_));
sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_, ubo_len_));
sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_));
+ sort_input_list(
+ MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_ + uniform_len_, ssbo_len_));
}
void ShaderInterface::debug_print()
diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh
index d4060cb80b4..f94006d1407 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.hh
+++ b/source/blender/gpu/intern/gpu_shader_interface.hh
@@ -34,6 +34,7 @@
#include "BLI_utildefines.h"
#include "GPU_shader.h"
+#include "gpu_shader_create_info.hh"
namespace blender::gpu {
@@ -50,6 +51,7 @@ typedef struct ShaderInput {
* Base class which is then specialized for each implementation (GL, VK, ...).
*/
class ShaderInterface {
+ friend shader::ShaderCreateInfo;
/* TODO(fclem): should be protected. */
public:
/** Flat array. In this order: Attributes, Ubos, Uniforms. */
@@ -73,9 +75,10 @@ class ShaderInterface {
public:
ShaderInterface();
+ ShaderInterface(const shader::ShaderCreateInfo &info);
virtual ~ShaderInterface();
- void debug_print(void);
+ void debug_print();
inline const ShaderInput *attr_get(const char *name) const
{
@@ -137,18 +140,24 @@ class ShaderInterface {
static inline const char *builtin_buffer_block_name(GPUBufferBlockBuiltin u);
inline uint32_t set_input_name(ShaderInput *input, char *name, uint32_t name_len) const;
+ inline void copy_input_name(ShaderInput *input,
+ const StringRefNull &name,
+ char *name_buffer,
+ uint32_t &name_buffer_offset) const;
- /* Finalize interface construction by sorting the ShaderInputs for faster lookups. */
- void sort_inputs(void);
+ /**
+ * Finalize interface construction by sorting the #ShaderInputs for faster lookups.
+ */
+ void sort_inputs();
private:
inline const ShaderInput *input_lookup(const ShaderInput *const inputs,
- const uint inputs_len,
+ uint inputs_len,
const char *name) const;
inline const ShaderInput *input_lookup(const ShaderInput *const inputs,
- const uint inputs_len,
- const int binding) const;
+ uint inputs_len,
+ int binding) const;
};
inline const char *ShaderInterface::builtin_uniform_name(GPUUniformBuiltin u)
@@ -188,11 +197,11 @@ inline const char *ShaderInterface::builtin_uniform_name(GPUUniformBuiltin u)
case GPU_UNIFORM_COLOR:
return "color";
case GPU_UNIFORM_BASE_INSTANCE:
- return "baseInstance";
+ return "gpu_BaseInstance";
case GPU_UNIFORM_RESOURCE_CHUNK:
- return "resourceChunk";
+ return "drw_resourceChunk";
case GPU_UNIFORM_RESOURCE_ID:
- return "resourceId";
+ return "drw_ResourceID";
case GPU_UNIFORM_SRGB_TRANSFORM:
return "srgbTarget";
@@ -210,6 +219,13 @@ inline const char *ShaderInterface::builtin_uniform_block_name(GPUUniformBlockBu
return "modelBlock";
case GPU_UNIFORM_BLOCK_INFO:
return "infoBlock";
+
+ case GPU_UNIFORM_BLOCK_DRW_VIEW:
+ return "drw_view";
+ case GPU_UNIFORM_BLOCK_DRW_MODEL:
+ return "drw_matrices";
+ case GPU_UNIFORM_BLOCK_DRW_INFOS:
+ return "drw_infos";
default:
return NULL;
}
@@ -232,8 +248,12 @@ inline uint32_t ShaderInterface::set_input_name(ShaderInput *input,
{
/* remove "[0]" from array name */
if (name[name_len - 1] == ']') {
- name[name_len - 3] = '\0';
- name_len -= 3;
+ for (; name_len > 1; name_len--) {
+ if (name[name_len] == '[') {
+ name[name_len] = '\0';
+ break;
+ }
+ }
}
input->name_offset = (uint32_t)(name - name_buffer_);
@@ -241,6 +261,17 @@ inline uint32_t ShaderInterface::set_input_name(ShaderInput *input,
return name_len + 1; /* include NULL terminator */
}
+inline void ShaderInterface::copy_input_name(ShaderInput *input,
+ const StringRefNull &name,
+ char *name_buffer,
+ uint32_t &name_buffer_offset) const
+{
+ uint32_t name_len = name.size();
+ /* Copy include NULL terminator. */
+ memcpy(name_buffer + name_buffer_offset, name.c_str(), name_len + 1);
+ name_buffer_offset += set_input_name(input, name_buffer + name_buffer_offset, name_len);
+}
+
inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const inputs,
const uint inputs_len,
const char *name) const
diff --git a/source/blender/gpu/intern/gpu_shader_private.hh b/source/blender/gpu/intern/gpu_shader_private.hh
index 65720e457d8..3bfecdefba7 100644
--- a/source/blender/gpu/intern/gpu_shader_private.hh
+++ b/source/blender/gpu/intern/gpu_shader_private.hh
@@ -24,9 +24,12 @@
#include "BLI_string_ref.hh"
#include "GPU_shader.h"
+#include "gpu_shader_create_info.hh"
#include "gpu_shader_interface.hh"
#include "gpu_vertex_buffer_private.hh"
+#include <string>
+
namespace blender {
namespace gpu {
@@ -53,35 +56,40 @@ class Shader {
virtual void geometry_shader_from_glsl(MutableSpan<const char *> sources) = 0;
virtual void fragment_shader_from_glsl(MutableSpan<const char *> sources) = 0;
virtual void compute_shader_from_glsl(MutableSpan<const char *> sources) = 0;
- virtual bool finalize(void) = 0;
+ virtual bool finalize(const shader::ShaderCreateInfo *info = nullptr) = 0;
virtual void transform_feedback_names_set(Span<const char *> name_list,
- const eGPUShaderTFBType geom_type) = 0;
+ eGPUShaderTFBType geom_type) = 0;
virtual bool transform_feedback_enable(GPUVertBuf *) = 0;
- virtual void transform_feedback_disable(void) = 0;
+ virtual void transform_feedback_disable() = 0;
- virtual void bind(void) = 0;
- virtual void unbind(void) = 0;
+ virtual void bind() = 0;
+ virtual void unbind() = 0;
virtual void uniform_float(int location, int comp_len, int array_size, const float *data) = 0;
virtual void uniform_int(int location, int comp_len, int array_size, const int *data) = 0;
virtual void vertformat_from_shader(GPUVertFormat *) const = 0;
+ std::string defines_declare(const shader::ShaderCreateInfo &info) const;
+ virtual std::string resources_declare(const shader::ShaderCreateInfo &info) const = 0;
+ virtual std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const = 0;
+ virtual std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const = 0;
+ virtual std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const = 0;
+ virtual std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const = 0;
+ virtual std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const = 0;
+
/* DEPRECATED: Kept only because of BGL API. */
- virtual int program_handle_get(void) const = 0;
+ virtual int program_handle_get() const = 0;
- inline const char *const name_get(void) const
+ inline const char *const name_get() const
{
return name;
};
protected:
- void print_log(Span<const char *> sources,
- char *log,
- const char *stage,
- const bool error,
- GPULogParser *parser);
+ void print_log(
+ Span<const char *> sources, char *log, const char *stage, bool error, GPULogParser *parser);
};
/* Syntactic sugar. */
@@ -137,4 +145,4 @@ class GPULogParser {
} // namespace blender
/* XXX do not use it. Special hack to use OCIO with batch API. */
-GPUShader *immGetShader(void);
+GPUShader *immGetShader();
diff --git a/source/blender/gpu/intern/gpu_shader_shared_utils.h b/source/blender/gpu/intern/gpu_shader_shared_utils.h
new file mode 100644
index 00000000000..0d283fb1e66
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_shared_utils.h
@@ -0,0 +1,116 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Glue definition to make shared declaration of struct & functions work in both C / C++ and GLSL.
+ * We use the same vector and matrix types as Blender C++. Some math functions are defined to use
+ * the float version to match the GLSL syntax.
+ * This file can be used for C & C++ code and the syntax used should follow the same rules.
+ * Some preprocessing is done by the GPU back-end to make it GLSL compatible.
+ *
+ * IMPORTANT:
+ * - Always use `u` suffix for enum values. GLSL do not support implicit cast.
+ * - Define all values. This is in order to simplify custom pre-processor code.
+ * - (C++ only) Always use `uint32_t` as underlying type (`enum eMyEnum : uint32_t`).
+ * - (C only) do NOT use the enum type inside UBO/SSBO structs and use `uint` instead.
+ * - Use float suffix by default for float literals to avoid double promotion in C++.
+ * - Pack one float or int after a vec3/ivec3 to fulfill alignment rules.
+ *
+ * NOTE: Due to alignment restriction and buggy drivers, do not try to use mat3 inside structs.
+ * NOTE: (UBO only) Do not use arrays of float. They are padded to arrays of vec4 and are not worth
+ * it. This does not apply to SSBO.
+ *
+ * IMPORTANT: Do not forget to align mat4, vec3 and vec4 to 16 bytes, and vec2 to 8 bytes.
+ *
+ * NOTE: You can use bool type using bool1 a int boolean type matching the GLSL type.
+ */
+
+#ifdef GPU_SHADER
+# define BLI_STATIC_ASSERT_ALIGN(type_, align_)
+# define BLI_STATIC_ASSERT_SIZE(type_, size_)
+# define static
+# define inline
+# define cosf cos
+# define sinf sin
+# define tanf tan
+# define acosf acos
+# define asinf asin
+# define atanf atan
+# define floorf floor
+# define ceilf ceil
+# define sqrtf sqrt
+
+# define float2 vec2
+# define float3 vec3
+# define float4 vec4
+# define float4x4 mat4
+# define int2 ivec2
+# define int3 ivec3
+# define int4 ivec4
+# define uint2 uvec2
+# define uint3 uvec3
+# define uint4 uvec4
+# define bool1 bool
+# define bool2 bvec2
+# define bool3 bvec3
+# define bool4 bvec4
+
+#else /* C / C++ */
+# pragma once
+
+# include "BLI_assert.h"
+
+# ifdef __cplusplus
+# include "BLI_float4x4.hh"
+# include "BLI_math_vec_types.hh"
+using blender::float2;
+using blender::float3;
+using blender::float4;
+using blender::float4x4;
+using blender::int2;
+using blender::int3;
+using blender::int4;
+using blender::uint2;
+using blender::uint3;
+using blender::uint4;
+using bool1 = int;
+using bool2 = blender::int2;
+using bool3 = blender::int3;
+using bool4 = blender::int4;
+
+# else /* C */
+typedef float float2[2];
+typedef float float3[3];
+typedef float float4[4];
+typedef float float4x4[4][4];
+typedef int int2[2];
+typedef int int3[2];
+typedef int int4[4];
+typedef uint uint2[2];
+typedef uint uint3[3];
+typedef uint uint4[4];
+typedef int bool1;
+typedef int bool2[2];
+typedef int bool3[2];
+typedef int bool4[4];
+# endif
+
+#endif
diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc
index 9ee8a8b8d32..a43ddb09ff8 100644
--- a/source/blender/gpu/intern/gpu_state.cc
+++ b/source/blender/gpu/intern/gpu_state.cc
@@ -165,11 +165,6 @@ void GPU_depth_range(float near, float far)
copy_v2_fl2(state.depth_range, near, far);
}
-/**
- * \note By convention, this is set as needed and not reset back to 1.0.
- * This means code that draws lines must always set the line width beforehand,
- * but is not expected to restore it's previous value.
- */
void GPU_line_width(float width)
{
width = max_ff(1.0f, width * PIXELSIZE);
@@ -184,10 +179,6 @@ void GPU_point_size(float size)
state.point_size = size * ((state.point_size > 0.0) ? 1.0f : -1.0f);
}
-/* Programmable point size
- * - shaders set their own point size when enabled
- * - use GPU_point_size when disabled */
-/* TODO: remove and use program point size everywhere. */
void GPU_program_point_size(bool enable)
{
StateManager *stack = Context::get()->state_manager;
@@ -264,7 +255,6 @@ eGPUStencilTest GPU_stencil_test_get()
return (eGPUStencilTest)state.stencil_test;
}
-/* NOTE: Already premultiplied by U.pixelsize. */
float GPU_line_width_get()
{
const GPUStateMutable &state = Context::get()->state_manager->mutable_state;
@@ -363,7 +353,6 @@ void GPU_bgl_start()
}
}
-/* Just turn off the bgl safeguard system. Can be called even without GPU_bgl_start. */
void GPU_bgl_end()
{
Context *ctx = Context::get();
diff --git a/source/blender/gpu/intern/gpu_state_private.hh b/source/blender/gpu/intern/gpu_state_private.hh
index b96b71a7ac4..864b7d0446a 100644
--- a/source/blender/gpu/intern/gpu_state_private.hh
+++ b/source/blender/gpu/intern/gpu_state_private.hh
@@ -62,7 +62,7 @@ union GPUState {
uint32_t polygon_smooth : 1;
uint32_t line_smooth : 1;
};
- /* Here to allow fast bitwise ops. */
+ /* Here to allow fast bit-wise ops. */
uint64_t data;
};
@@ -159,18 +159,18 @@ class StateManager {
StateManager();
virtual ~StateManager(){};
- virtual void apply_state(void) = 0;
- virtual void force_state(void) = 0;
+ virtual void apply_state() = 0;
+ virtual void force_state() = 0;
virtual void issue_barrier(eGPUBarrier barrier_bits) = 0;
virtual void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) = 0;
virtual void texture_unbind(Texture *tex) = 0;
- virtual void texture_unbind_all(void) = 0;
+ virtual void texture_unbind_all() = 0;
virtual void image_bind(Texture *tex, int unit) = 0;
virtual void image_unbind(Texture *tex) = 0;
- virtual void image_unbind_all(void) = 0;
+ virtual void image_unbind_all() = 0;
virtual void texture_unpack_row_length_set(uint len) = 0;
};
diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc
index 2744c0c5e17..1b8b28bf04c 100644
--- a/source/blender/gpu/intern/gpu_texture.cc
+++ b/source/blender/gpu/intern/gpu_texture.cc
@@ -190,7 +190,7 @@ using namespace blender::gpu;
/* ------ Memory Management ------ */
-uint GPU_texture_memory_usage_get(void)
+uint GPU_texture_memory_usage_get()
{
/* TODO(fclem): Do that inside the new Texture class. */
return 0;
@@ -298,7 +298,6 @@ GPUTexture *GPU_texture_create_cube_array(
name, w, w, d, GPU_TEXTURE_CUBE_ARRAY, mip_len, format, GPU_DATA_FLOAT, data);
}
-/* DDS texture loading. Return NULL if support is not available. */
GPUTexture *GPU_texture_create_compressed_2d(
const char *name, int w, int h, int miplen, eGPUTextureFormat tex_format, const void *data)
{
@@ -337,7 +336,6 @@ GPUTexture *GPU_texture_create_from_vertbuf(const char *name, GPUVertBuf *vert)
return reinterpret_cast<GPUTexture *>(tex);
}
-/* Create an error texture that will bind an invalid texture (pink) at draw time. */
GPUTexture *GPU_texture_create_error(int dimension, bool is_array)
{
float pixel[4] = {1.0f, 0.0f, 1.0f, 1.0f};
@@ -386,27 +384,17 @@ void *GPU_texture_read(GPUTexture *tex_, eGPUDataFormat data_format, int miplvl)
return tex->read(miplvl, data_format);
}
-/**
- * Fills the whole texture with the same data for all pixels.
- * \warning Only work for 2D texture for now.
- * \warning Only clears the mip 0 of the texture.
- * \param data_format: data format of the pixel data.
- * \param data: 1 pixel worth of data to fill the texture with.
- */
void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data)
{
BLI_assert(data != nullptr); /* Do not accept NULL as parameter. */
reinterpret_cast<Texture *>(tex)->clear(data_format, data);
}
-/* NOTE: Updates only mip 0. */
void GPU_texture_update(GPUTexture *tex, eGPUDataFormat data_format, const void *data)
{
reinterpret_cast<Texture *>(tex)->update(data_format, data);
}
-/* Makes data interpretation aware of the source layout.
- * Skipping pixels correctly when changing rows when doing partial update. */
void GPU_unpack_row_length_set(uint len)
{
Context::get()->state_manager->texture_unpack_row_length_set(len);
@@ -436,7 +424,7 @@ void GPU_texture_unbind(GPUTexture *tex_)
Context::get()->state_manager->texture_unbind(tex);
}
-void GPU_texture_unbind_all(void)
+void GPU_texture_unbind_all()
{
Context::get()->state_manager->texture_unbind_all();
}
@@ -451,7 +439,7 @@ void GPU_texture_image_unbind(GPUTexture *tex)
Context::get()->state_manager->image_unbind(unwrap(tex));
}
-void GPU_texture_image_unbind_all(void)
+void GPU_texture_image_unbind_all()
{
Context::get()->state_manager->image_unbind_all();
}
@@ -461,7 +449,6 @@ void GPU_texture_generate_mipmap(GPUTexture *tex)
reinterpret_cast<Texture *>(tex)->generate_mipmap();
}
-/* Copy a texture content to a similar texture. Only MIP 0 is copied. */
void GPU_texture_copy(GPUTexture *dst_, GPUTexture *src_)
{
Texture *src = reinterpret_cast<Texture *>(src_);
@@ -626,8 +613,7 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *r_size)
* Override texture sampler state for one sampler unit only.
* \{ */
-/* Update user defined sampler states. */
-void GPU_samplers_update(void)
+void GPU_samplers_update()
{
GPUBackend::get()->samplers_update();
}
diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh
index 17c888e4fcd..73b59b9f06f 100644
--- a/source/blender/gpu/intern/gpu_texture_private.hh
+++ b/source/blender/gpu/intern/gpu_texture_private.hh
@@ -66,7 +66,7 @@ ENUM_OPERATORS(eGPUTextureType, GPU_TEXTURE_CUBE_ARRAY)
#endif
/* Maximum number of FBOs a texture can be attached to. */
-#define GPU_TEX_MAX_FBO_ATTACHED 20
+#define GPU_TEX_MAX_FBO_ATTACHED 32
/**
* Implementation of Textures.
@@ -123,7 +123,7 @@ class Texture {
bool init_cubemap(int w, int layers, eGPUTextureFormat format);
bool init_buffer(GPUVertBuf *vbo, eGPUTextureFormat format);
- virtual void generate_mipmap(void) = 0;
+ virtual void generate_mipmap() = 0;
virtual void copy_to(Texture *tex) = 0;
virtual void clear(eGPUDataFormat format, const void *data) = 0;
virtual void swizzle_set(const char swizzle_mask[4]) = 0;
@@ -138,17 +138,17 @@ class Texture {
int mip, int offset[3], int extent[3], eGPUDataFormat format, const void *data) = 0;
/* TODO(fclem): Legacy. Should be removed at some point. */
- virtual uint gl_bindcode_get(void) const = 0;
+ virtual uint gl_bindcode_get() const = 0;
- int width_get(void) const
+ int width_get() const
{
return w_;
}
- int height_get(void) const
+ int height_get() const
{
return h_;
}
- int depth_get(void) const
+ int depth_get() const
{
return d_;
}
@@ -188,7 +188,7 @@ class Texture {
}
/* Return number of dimension taking the array type into account. */
- int dimensions_count(void) const
+ int dimensions_count() const
{
const int array = (type_ & GPU_TEXTURE_ARRAY) ? 1 : 0;
switch (type_ & ~GPU_TEXTURE_ARRAY) {
@@ -205,7 +205,7 @@ class Texture {
}
}
/* Return number of array layer (or face layer) for texture array or 1 for the others. */
- int layer_count(void) const
+ int layer_count() const
{
switch (type_) {
case GPU_TEXTURE_1D_ARRAY:
@@ -218,15 +218,15 @@ class Texture {
}
}
- eGPUTextureFormat format_get(void) const
+ eGPUTextureFormat format_get() const
{
return format_;
}
- eGPUTextureFormatFlag format_flag_get(void) const
+ eGPUTextureFormatFlag format_flag_get() const
{
return format_flag_;
}
- eGPUTextureType type_get(void) const
+ eGPUTextureType type_get() const
{
return type_;
}
@@ -248,7 +248,7 @@ class Texture {
}
protected:
- virtual bool init_internal(void) = 0;
+ virtual bool init_internal() = 0;
virtual bool init_internal(GPUVertBuf *vbo) = 0;
};
@@ -348,23 +348,12 @@ inline eGPUTextureFormatFlag to_format_flag(eGPUTextureFormat format)
case GPU_DEPTH24_STENCIL8:
case GPU_DEPTH32F_STENCIL8:
return GPU_FORMAT_DEPTH_STENCIL;
- case GPU_R8I:
case GPU_R8UI:
+ case GPU_RG16I:
case GPU_R16I:
+ case GPU_RG16UI:
case GPU_R16UI:
case GPU_R32UI:
- case GPU_RG8I:
- case GPU_RG8UI:
- case GPU_RG16I:
- case GPU_RG16UI:
- case GPU_RG32I:
- case GPU_RG32UI:
- case GPU_RGBA8I:
- case GPU_RGBA8UI:
- case GPU_RGBA16I:
- case GPU_RGBA16UI:
- case GPU_RGBA32I:
- case GPU_RGBA32UI:
return GPU_FORMAT_INTEGER;
case GPU_SRGB8_A8_DXT1:
case GPU_SRGB8_A8_DXT3:
@@ -381,16 +370,11 @@ inline eGPUTextureFormatFlag to_format_flag(eGPUTextureFormat format)
inline int to_component_len(eGPUTextureFormat format)
{
switch (format) {
- case GPU_RGBA8UI:
- case GPU_RGBA8I:
case GPU_RGBA8:
- case GPU_RGBA32UI:
- case GPU_RGBA32I:
- case GPU_RGBA32F:
- case GPU_RGBA16UI:
- case GPU_RGBA16I:
+ case GPU_RGBA8UI:
case GPU_RGBA16F:
case GPU_RGBA16:
+ case GPU_RGBA32F:
case GPU_SRGB8_A8:
case GPU_RGB10_A2:
return 4;
@@ -444,27 +428,16 @@ inline bool validate_data_format(eGPUTextureFormat tex_format, eGPUDataFormat da
case GPU_DEPTH24_STENCIL8:
case GPU_DEPTH32F_STENCIL8:
return data_format == GPU_DATA_UINT_24_8;
+ case GPU_R8UI:
case GPU_R16UI:
- case GPU_R32UI:
case GPU_RG16UI:
- case GPU_RG32UI:
- case GPU_RGBA16UI:
- case GPU_RGBA32UI:
+ case GPU_R32UI:
return data_format == GPU_DATA_UINT;
- case GPU_R16I:
- case GPU_R32I:
- case GPU_R8I:
case GPU_RG16I:
- case GPU_RG32I:
- case GPU_RG8I:
- case GPU_RGBA16I:
- case GPU_RGBA32I:
- case GPU_RGBA8I:
+ case GPU_R16I:
return data_format == GPU_DATA_INT;
case GPU_R8:
- case GPU_R8UI:
case GPU_RG8:
- case GPU_RG8UI:
case GPU_RGBA8:
case GPU_RGBA8UI:
case GPU_SRGB8_A8:
@@ -489,27 +462,16 @@ inline eGPUDataFormat to_data_format(eGPUTextureFormat tex_format)
case GPU_DEPTH24_STENCIL8:
case GPU_DEPTH32F_STENCIL8:
return GPU_DATA_UINT_24_8;
+ case GPU_R8UI:
case GPU_R16UI:
- case GPU_R32UI:
case GPU_RG16UI:
- case GPU_RG32UI:
- case GPU_RGBA16UI:
- case GPU_RGBA32UI:
+ case GPU_R32UI:
return GPU_DATA_UINT;
- case GPU_R16I:
- case GPU_R32I:
- case GPU_R8I:
case GPU_RG16I:
- case GPU_RG32I:
- case GPU_RG8I:
- case GPU_RGBA16I:
- case GPU_RGBA32I:
- case GPU_RGBA8I:
+ case GPU_R16I:
return GPU_DATA_INT;
case GPU_R8:
- case GPU_R8UI:
case GPU_RG8:
- case GPU_RG8UI:
case GPU_RGBA8:
case GPU_RGBA8UI:
case GPU_SRGB8_A8:
diff --git a/source/blender/gpu/intern/gpu_uniform_buffer.cc b/source/blender/gpu/intern/gpu_uniform_buffer.cc
index 3a9269d1753..332875ba81f 100644
--- a/source/blender/gpu/intern/gpu_uniform_buffer.cc
+++ b/source/blender/gpu/intern/gpu_uniform_buffer.cc
@@ -201,12 +201,6 @@ GPUUniformBuf *GPU_uniformbuf_create_ex(size_t size, const void *data, const cha
return wrap(ubo);
}
-/**
- * Create UBO from inputs list.
- * Return NULL if failed to create or if \param inputs: is empty.
- *
- * \param inputs: ListBase of #BLI_genericNodeN(#GPUInput).
- */
GPUUniformBuf *GPU_uniformbuf_create_from_list(ListBase *inputs, const char *name)
{
/* There is no point on creating an UBO if there is no arguments. */
@@ -245,7 +239,7 @@ void GPU_uniformbuf_unbind(GPUUniformBuf *ubo)
unwrap(ubo)->unbind();
}
-void GPU_uniformbuf_unbind_all(void)
+void GPU_uniformbuf_unbind_all()
{
/* FIXME */
}
diff --git a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
index e8fc1343eaf..018b85c865e 100644
--- a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
@@ -54,7 +54,7 @@ class UniformBuf {
virtual void update(const void *data) = 0;
virtual void bind(int slot) = 0;
- virtual void unbind(void) = 0;
+ virtual void unbind() = 0;
/** Used to defer data upload at drawing time.
* This is useful if the thread has no context bound.
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc
index 956d89ff832..dba31f501f2 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.cc
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc
@@ -144,6 +144,12 @@ void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts_,
unwrap(verts_)->init(format, usage);
}
+void GPU_vertbuf_init_build_on_device(GPUVertBuf *verts, GPUVertFormat *format, uint v_len)
+{
+ GPU_vertbuf_init_with_format_ex(verts, format, GPU_USAGE_DEVICE_ONLY);
+ GPU_vertbuf_data_alloc(verts, v_len);
+}
+
GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts_)
{
return wrap(unwrap(verts_)->duplicate());
@@ -159,7 +165,6 @@ void *GPU_vertbuf_unmap(const GPUVertBuf *verts, const void *mapped_data)
return unwrap(verts)->unmap(mapped_data);
}
-/** Same as discard but does not free. */
void GPU_vertbuf_clear(GPUVertBuf *verts)
{
unwrap(verts)->clear();
@@ -183,21 +188,16 @@ void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts)
/* -------- Data update -------- */
-/* create a new allocation, discarding any existing data */
void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len)
{
unwrap(verts)->allocate(v_len);
}
-/* resize buffer keeping existing data */
void GPU_vertbuf_data_resize(GPUVertBuf *verts, uint v_len)
{
unwrap(verts)->resize(v_len);
}
-/* Set vertex count but does not change allocation.
- * Only this many verts will be uploaded to the GPU and rendered.
- * This is useful for streaming data. */
void GPU_vertbuf_data_len_set(GPUVertBuf *verts_, uint v_len)
{
VertBuf *verts = unwrap(verts_);
@@ -229,7 +229,6 @@ void GPU_vertbuf_attr_fill(GPUVertBuf *verts_, uint a_idx, const void *data)
GPU_vertbuf_attr_fill_stride(verts_, a_idx, stride, data);
}
-/** Fills a whole vertex (all attributes). Data must match packed layout. */
void GPU_vertbuf_vert_set(GPUVertBuf *verts_, uint v_idx, const void *data)
{
VertBuf *verts = unwrap(verts_);
@@ -284,17 +283,12 @@ void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *verts_, uint a_idx, GPUVertBufRaw
/* -------- Getters -------- */
-/* NOTE: Be careful when using this. The data needs to match the expected format. */
-void *GPU_vertbuf_get_data(GPUVertBuf *verts_)
+void *GPU_vertbuf_get_data(const GPUVertBuf *verts)
{
/* TODO: Assert that the format has no padding. */
- VertBuf *verts = unwrap(verts_);
- verts->flag |= GPU_VERTBUF_DATA_DIRTY;
- return verts->data;
+ return unwrap(verts)->data;
}
-/* Returns the data buffer and set it to null internally to avoid freeing.
- * NOTE: Be careful when using this. The data needs to match the expected format. */
void *GPU_vertbuf_steal_data(GPUVertBuf *verts_)
{
VertBuf *verts = unwrap(verts_);
@@ -325,25 +319,32 @@ GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts)
return unwrap(verts)->flag;
}
+void GPU_vertbuf_tag_dirty(GPUVertBuf *verts)
+{
+ unwrap(verts)->flag |= GPU_VERTBUF_DATA_DIRTY;
+}
+
uint GPU_vertbuf_get_memory_usage()
{
return VertBuf::memory_usage;
}
-/* Should be rename to GPU_vertbuf_data_upload */
void GPU_vertbuf_use(GPUVertBuf *verts)
{
unwrap(verts)->upload();
}
+void GPU_vertbuf_wrap_handle(GPUVertBuf *verts, uint64_t handle)
+{
+ unwrap(verts)->wrap_handle(handle);
+}
+
void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding)
{
unwrap(verts)->bind_as_ssbo(binding);
}
-/* XXX this is just a wrapper for the use of the Hair refine workaround.
- * To be used with GPU_vertbuf_use(). */
-void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data)
+void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, const void *data)
{
unwrap(verts)->update_sub(start, len, data);
}
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
index 9531c2c1a5f..97514b382b1 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
@@ -60,34 +60,36 @@ class VertBuf {
virtual ~VertBuf();
void init(const GPUVertFormat *format, GPUUsageType usage);
- void clear(void);
+ void clear();
/* Data management. */
void allocate(uint vert_len);
void resize(uint vert_len);
- void upload(void);
+ void upload();
virtual void bind_as_ssbo(uint binding) = 0;
- VertBuf *duplicate(void);
+ virtual void wrap_handle(uint64_t handle) = 0;
+
+ VertBuf *duplicate();
/* Size of the data allocated. */
- size_t size_alloc_get(void) const
+ size_t size_alloc_get() const
{
BLI_assert(format.packed);
return vertex_alloc * format.stride;
}
/* Size of the data uploaded to the GPU. */
- size_t size_used_get(void) const
+ size_t size_used_get() const
{
BLI_assert(format.packed);
return vertex_len * format.stride;
}
- void reference_add(void)
+ void reference_add()
{
handle_refcount_++;
}
- void reference_remove(void)
+ void reference_remove()
{
BLI_assert(handle_refcount_ > 0);
handle_refcount_--;
@@ -96,15 +98,15 @@ class VertBuf {
}
}
- virtual void update_sub(uint start, uint len, void *data) = 0;
+ virtual void update_sub(uint start, uint len, const void *data) = 0;
virtual const void *read() const = 0;
virtual void *unmap(const void *mapped_data) const = 0;
protected:
- virtual void acquire_data(void) = 0;
- virtual void resize_data(void) = 0;
- virtual void release_data(void) = 0;
- virtual void upload_data(void) = 0;
+ virtual void acquire_data() = 0;
+ virtual void resize_data() = 0;
+ virtual void release_data() = 0;
+ virtual void upload_data() = 0;
virtual void duplicate_data(VertBuf *dst) = 0;
};
diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc
index 78a119bcec8..ad45f2a4d7b 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.cc
+++ b/source/blender/gpu/intern/gpu_vertex_format.cc
@@ -190,17 +190,6 @@ void GPU_vertformat_alias_add(GPUVertFormat *format, const char *alias)
attr->names[attr->name_len++] = copy_attr_name(format, alias);
}
-/**
- * Makes vertex attribute from the next vertices to be accessible in the vertex shader.
- * For an attribute named "attr" you can access the next nth vertex using "attr{number}".
- * Use this function after specifying all the attributes in the format.
- *
- * NOTE: This does NOT work when using indexed rendering.
- * NOTE: Only works for first attribute name. (this limitation can be changed if needed)
- *
- * WARNING: this function creates a lot of aliases/attributes, make sure to keep the attribute
- * name short to avoid overflowing the name-buffer.
- */
void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count)
{
/* Sanity check. Maximum can be upgraded if needed. */
@@ -271,8 +260,6 @@ static void safe_bytes(char out[11], const char data[8])
}
}
-/* Warning: Always add a prefix to the result of this function as
- * the generated string can start with a number and not be a valid attribute name. */
void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint UNUSED(max_len))
{
char data[8] = {0};
@@ -306,20 +293,6 @@ void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uin
#endif
}
-/**
- * Make attribute layout non-interleaved.
- * Warning! This does not change data layout!
- * Use direct buffer access to fill the data.
- * This is for advanced usage.
- *
- * De-interleaved data means all attribute data for each attribute
- * is stored continuously like this:
- * 000011112222
- * instead of:
- * 012012012012
- *
- * \note This is per attribute de-interleaving, NOT per component.
- */
void GPU_vertformat_deinterleave(GPUVertFormat *format)
{
/* Ideally we should change the stride and offset here. This would allow
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index ccd9a4c061b..6d8ff8e7088 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -137,19 +137,25 @@ struct DRWData **GPU_viewport_data_get(GPUViewport *viewport)
static void gpu_viewport_textures_create(GPUViewport *viewport)
{
int *size = viewport->size;
+ float empty_pixel_fl[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ uchar empty_pixel_u[4] = {0, 0, 0, 0};
if (viewport->color_render_tx[0] == NULL) {
viewport->color_render_tx[0] = GPU_texture_create_2d(
"dtxl_color", UNPACK2(size), 1, GPU_RGBA16F, NULL);
+ GPU_texture_clear(viewport->color_render_tx[0], GPU_DATA_FLOAT, empty_pixel_fl);
viewport->color_overlay_tx[0] = GPU_texture_create_2d(
"dtxl_color_overlay", UNPACK2(size), 1, GPU_SRGB8_A8, NULL);
+ GPU_texture_clear(viewport->color_overlay_tx[0], GPU_DATA_UBYTE, empty_pixel_u);
}
if ((viewport->flag & GPU_VIEWPORT_STEREO) != 0 && viewport->color_render_tx[1] == NULL) {
viewport->color_render_tx[1] = GPU_texture_create_2d(
"dtxl_color_stereo", UNPACK2(size), 1, GPU_RGBA16F, NULL);
+ GPU_texture_clear(viewport->color_render_tx[1], GPU_DATA_FLOAT, empty_pixel_fl);
viewport->color_overlay_tx[1] = GPU_texture_create_2d(
"dtxl_color_overlay_stereo", UNPACK2(size), 1, GPU_SRGB8_A8, NULL);
+ GPU_texture_clear(viewport->color_overlay_tx[1], GPU_DATA_UBYTE, empty_pixel_u);
}
/* Can be shared with GPUOffscreen. */
@@ -194,7 +200,6 @@ void GPU_viewport_bind(GPUViewport *viewport, int view, const rcti *rect)
viewport->active_view = view;
}
-/* Should be called from DRW after DRW_opengl_context_enable. */
void GPU_viewport_bind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs)
{
GPUTexture *color, *depth;
@@ -258,7 +263,6 @@ void GPU_viewport_colorspace_set(GPUViewport *viewport,
viewport->do_color_management = true;
}
-/* Merge the stereo textures. `color` and `overlay` texture will be modified. */
void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo_format)
{
if (!ELEM(stereo_format->display_mode, S3D_DISPLAY_ANAGLYPH, S3D_DISPLAY_INTERLACE)) {
@@ -452,10 +456,6 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
}
}
-/**
- * Version of #GPU_viewport_draw_to_screen() that lets caller decide if display colorspace
- * transform should be performed.
- */
void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
int view,
const rcti *rect,
@@ -508,21 +508,11 @@ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
viewport, view, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge);
}
-/**
- * Merge and draw the buffers of \a viewport into the currently active framebuffer, performing
- * color transform to display space.
- *
- * \param rect: Coordinates to draw into. By swapping min and max values, drawing can be done
- * with inversed axis coordinates (upside down or sideways).
- */
void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect)
{
GPU_viewport_draw_to_screen_ex(viewport, view, rect, true, true);
}
-/**
- * Clear vars assigned from offscreen, so we don't free data owned by `GPUOffScreen`.
- */
void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
struct GPUOffScreen *ofs,
bool display_colorspace,
@@ -587,18 +577,17 @@ GPUTexture *GPU_viewport_depth_texture(GPUViewport *viewport)
return viewport->depth_tx;
}
-/* Overlay framebuffer for drawing outside of DRW module. */
GPUFrameBuffer *GPU_viewport_framebuffer_overlay_get(GPUViewport *viewport)
{
- GPU_framebuffer_ensure_config(&viewport->overlay_fb,
- {
- GPU_ATTACHMENT_TEXTURE(viewport->depth_tx),
- GPU_ATTACHMENT_TEXTURE(viewport->color_overlay_tx[0]),
- });
+ GPU_framebuffer_ensure_config(
+ &viewport->overlay_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(viewport->depth_tx),
+ GPU_ATTACHMENT_TEXTURE(viewport->color_overlay_tx[viewport->active_view]),
+ });
return viewport->overlay_fb;
}
-/* Must be executed inside Draw-manager OpenGL Context. */
void GPU_viewport_free(GPUViewport *viewport)
{
if (viewport->draw_data) {
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index 2855d5078ff..92d180f1140 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -240,12 +240,14 @@ static void detect_workarounds()
GLContext::unused_fb_slot_workaround = true;
/* Turn off extensions. */
GCaps.shader_image_load_store_support = false;
+ GCaps.shader_storage_buffer_objects_support = false;
GLContext::base_instance_support = false;
GLContext::clear_texture_support = false;
GLContext::copy_image_support = false;
GLContext::debug_layer_support = false;
GLContext::direct_state_access_support = false;
GLContext::fixed_restart_index_support = false;
+ GLContext::geometry_shader_invocations = false;
GLContext::multi_bind_support = false;
GLContext::multi_draw_indirect_support = false;
GLContext::shader_draw_parameters_support = false;
@@ -412,19 +414,36 @@ static void detect_workarounds()
if (GLContext::debug_layer_support == false) {
GLContext::debug_layer_workaround = true;
}
+
+ /* Broken glGenerateMipmap on macOS 10.15.7 security update. */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_ANY) &&
+ strstr(renderer, "HD Graphics 4000")) {
+ GLContext::generate_mipmap_workaround = true;
+ }
+
+ /* Buggy interface query functions cause crashes when handling SSBOs (T93680) */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY) &&
+ (strstr(renderer, "HD Graphics 4400") || strstr(renderer, "HD Graphics 4600"))) {
+ GCaps.shader_storage_buffer_objects_support = false;
+ }
} // namespace blender::gpu
/** Internal capabilities. */
+
GLint GLContext::max_cubemap_size = 0;
GLint GLContext::max_texture_3d_size = 0;
GLint GLContext::max_ubo_binds = 0;
GLint GLContext::max_ubo_size = 0;
+
/** Extensions. */
+
bool GLContext::base_instance_support = false;
bool GLContext::clear_texture_support = false;
bool GLContext::copy_image_support = false;
bool GLContext::debug_layer_support = false;
bool GLContext::direct_state_access_support = false;
+bool GLContext::explicit_location_support = false;
+bool GLContext::geometry_shader_invocations = false;
bool GLContext::fixed_restart_index_support = false;
bool GLContext::multi_bind_support = false;
bool GLContext::multi_draw_indirect_support = false;
@@ -433,9 +452,12 @@ bool GLContext::texture_cube_map_array_support = false;
bool GLContext::texture_filter_anisotropic_support = false;
bool GLContext::texture_gather_support = false;
bool GLContext::vertex_attrib_binding_support = false;
+
/** Workarounds. */
+
bool GLContext::debug_layer_workaround = false;
bool GLContext::unused_fb_slot_workaround = false;
+bool GLContext::generate_mipmap_workaround = false;
float GLContext::derivative_signs[2] = {1.0f, 1.0f};
void GLBackend::capabilities_init()
@@ -480,6 +502,8 @@ void GLBackend::capabilities_init()
GLContext::copy_image_support = GLEW_ARB_copy_image;
GLContext::debug_layer_support = GLEW_VERSION_4_3 || GLEW_KHR_debug || GLEW_ARB_debug_output;
GLContext::direct_state_access_support = GLEW_ARB_direct_state_access;
+ GLContext::explicit_location_support = GLEW_VERSION_4_3;
+ GLContext::geometry_shader_invocations = GLEW_ARB_gpu_shader5;
GLContext::fixed_restart_index_support = GLEW_ARB_ES3_compatibility;
GLContext::multi_bind_support = GLEW_ARB_multi_bind;
GLContext::multi_draw_indirect_support = GLEW_ARB_multi_draw_indirect;
diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh
index e9dcdffced0..abac9174d4a 100644
--- a/source/blender/gpu/opengl/gl_backend.hh
+++ b/source/blender/gpu/opengl/gl_backend.hh
@@ -62,12 +62,12 @@ class GLBackend : public GPUBackend {
GLBackend::platform_exit();
}
- static GLBackend *get(void)
+ static GLBackend *get()
{
return static_cast<GLBackend *>(GPUBackend::get());
}
- void samplers_update(void) override
+ void samplers_update() override
{
GLTexture::samplers_update();
};
@@ -77,7 +77,7 @@ class GLBackend : public GPUBackend {
return new GLContext(ghost_window, shared_orphan_list_);
};
- Batch *batch_alloc(void) override
+ Batch *batch_alloc() override
{
return new GLBatch();
};
@@ -92,12 +92,12 @@ class GLBackend : public GPUBackend {
return new GLFrameBuffer(name);
};
- IndexBuf *indexbuf_alloc(void) override
+ IndexBuf *indexbuf_alloc() override
{
return new GLIndexBuf();
};
- QueryPool *querypool_alloc(void) override
+ QueryPool *querypool_alloc() override
{
return new GLQueryPool();
};
@@ -117,12 +117,12 @@ class GLBackend : public GPUBackend {
return new GLUniformBuf(size, name);
};
- VertBuf *vertbuf_alloc(void) override
+ VertBuf *vertbuf_alloc() override
{
return new GLVertBuf();
};
- GLSharedOrphanLists &shared_orphan_list_get(void)
+ GLSharedOrphanLists &shared_orphan_list_get()
{
return shared_orphan_list_;
};
@@ -134,10 +134,10 @@ class GLBackend : public GPUBackend {
}
private:
- static void platform_init(void);
- static void platform_exit(void);
+ static void platform_init();
+ static void platform_exit();
- static void capabilities_init(void);
+ static void capabilities_init();
};
} // namespace gpu
diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc
index fc1d1006d0d..83cb0ddd053 100644
--- a/source/blender/gpu/opengl/gl_batch.cc
+++ b/source/blender/gpu/opengl/gl_batch.cc
@@ -74,7 +74,6 @@ void GLVaoCache::init()
vao_id_ = 0;
}
-/* Create a new VAO object and store it in the cache. */
void GLVaoCache::insert(const GLShaderInterface *interface, GLuint vao)
{
/* Now insert the cache. */
@@ -191,7 +190,6 @@ void GLVaoCache::clear()
this->init();
}
-/* Return 0 on cache miss (invalid VAO) */
GLuint GLVaoCache::lookup(const GLShaderInterface *interface)
{
const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
@@ -205,8 +203,6 @@ GLuint GLVaoCache::lookup(const GLShaderInterface *interface)
return 0;
}
-/* The GLVaoCache object is only valid for one GLContext.
- * Reset the cache if trying to draw in another context; */
void GLVaoCache::context_check()
{
GLContext *ctx = GLContext::get();
@@ -276,6 +272,7 @@ GLuint GLVaoCache::vao_get(GPUBatch *batch)
return vao_id_;
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/gpu/opengl/gl_batch.hh b/source/blender/gpu/opengl/gl_batch.hh
index 704b6471dd5..4e6e25cdb0f 100644
--- a/source/blender/gpu/opengl/gl_batch.hh
+++ b/source/blender/gpu/opengl/gl_batch.hh
@@ -43,9 +43,11 @@ class GLShaderInterface;
#define GPU_VAO_STATIC_LEN 3
-/* VAO management: remembers all geometry state (vertex attribute bindings & element buffer)
- * for each shader interface. Start with a static number of vaos and fallback to dynamic count
- * if necessary. Once a batch goes dynamic it does not go back. */
+/**
+ * VAO management: remembers all geometry state (vertex attribute bindings & element buffer)
+ * for each shader interface. Start with a static number of VAO's and fallback to dynamic count
+ * if necessary. Once a batch goes dynamic it does not go back.
+ */
class GLVaoCache {
private:
/** Context for which the vao_cache_ was generated. */
@@ -80,14 +82,24 @@ class GLVaoCache {
GLuint vao_get(GPUBatch *batch);
GLuint base_instance_vao_get(GPUBatch *batch, int i_first);
+ /**
+ * Return 0 on cache miss (invalid VAO).
+ */
GLuint lookup(const GLShaderInterface *interface);
+ /**
+ * Create a new VAO object and store it in the cache.
+ */
void insert(const GLShaderInterface *interface, GLuint vao_id);
void remove(const GLShaderInterface *interface);
- void clear(void);
+ void clear();
private:
- void init(void);
- void context_check(void);
+ void init();
+ /**
+ * The #GLVaoCache object is only valid for one #GLContext.
+ * Reset the cache if trying to draw in another context;.
+ */
+ void context_check();
};
class GLBatch : public Batch {
@@ -100,7 +112,8 @@ class GLBatch : public Batch {
void bind(int i_first);
/* Convenience getters. */
- GLIndexBuf *elem_(void) const
+
+ GLIndexBuf *elem_() const
{
return static_cast<GLIndexBuf *>(unwrap(elem));
}
diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh
index 0222adaba25..dd22418972b 100644
--- a/source/blender/gpu/opengl/gl_context.hh
+++ b/source/blender/gpu/opengl/gl_context.hh
@@ -50,22 +50,27 @@ class GLSharedOrphanLists {
Vector<GLuint> buffers;
public:
- void orphans_clear(void);
+ void orphans_clear();
};
class GLContext : public Context {
public:
/** Capabilities. */
+
static GLint max_cubemap_size;
static GLint max_texture_3d_size;
static GLint max_ubo_size;
static GLint max_ubo_binds;
+
/** Extensions. */
+
static bool base_instance_support;
static bool clear_texture_support;
static bool copy_image_support;
static bool debug_layer_support;
static bool direct_state_access_support;
+ static bool explicit_location_support;
+ static bool geometry_shader_invocations;
static bool fixed_restart_index_support;
static bool multi_bind_support;
static bool multi_draw_indirect_support;
@@ -74,9 +79,12 @@ class GLContext : public Context {
static bool texture_filter_anisotropic_support;
static bool texture_gather_support;
static bool vertex_attrib_binding_support;
+
/** Workarounds. */
+
static bool debug_layer_workaround;
static bool unused_fb_slot_workaround;
+ static bool generate_mipmap_workaround;
static float derivative_signs[2];
/** VBO for missing vertex attrib binding. Avoid undefined behavior on some implementation. */
@@ -106,11 +114,11 @@ class GLContext : public Context {
static void check_error(const char *info);
- void activate(void) override;
- void deactivate(void) override;
+ void activate() override;
+ void deactivate() override;
- void flush(void) override;
- void finish(void) override;
+ void flush() override;
+ void finish() override;
void memory_statistics_get(int *total_mem, int *free_mem) override;
@@ -136,11 +144,11 @@ class GLContext : public Context {
void vao_cache_unregister(GLVaoCache *cache);
void debug_group_begin(const char *name, int index) override;
- void debug_group_end(void) override;
+ void debug_group_end() override;
private:
static void orphans_add(Vector<GLuint> &orphan_list, std::mutex &list_mutex, GLuint id);
- void orphans_clear(void);
+ void orphans_clear();
MEM_CXX_CLASS_ALLOC_FUNCS("GLContext")
};
diff --git a/source/blender/gpu/opengl/gl_debug.cc b/source/blender/gpu/opengl/gl_debug.cc
index 3e259235515..0a06d9cdb7c 100644
--- a/source/blender/gpu/opengl/gl_debug.cc
+++ b/source/blender/gpu/opengl/gl_debug.cc
@@ -142,7 +142,6 @@ static void APIENTRY debug_callback(GLenum UNUSED(source),
#undef APIENTRY
-/* This function needs to be called once per context. */
void init_gl_callbacks()
{
CLOG_ENSURE(&LOG);
diff --git a/source/blender/gpu/opengl/gl_debug.hh b/source/blender/gpu/opengl/gl_debug.hh
index 892fb1d2ddb..7917c05f94b 100644
--- a/source/blender/gpu/opengl/gl_debug.hh
+++ b/source/blender/gpu/opengl/gl_debug.hh
@@ -88,9 +88,17 @@ namespace debug {
void raise_gl_error(const char *info);
void check_gl_error(const char *info);
void check_gl_resources(const char *info);
-void init_gl_callbacks(void);
+/**
+ * This function needs to be called once per context.
+ */
+void init_gl_callbacks();
-void init_debug_layer(void);
+/**
+ * Initialize a fallback layer (to KHR_debug) that covers only some functions.
+ * We override the functions pointers by our own implementation that just checks #glGetError.
+ * Some additional functions (not overridable) are covered inside the header using wrappers.
+ */
+void init_debug_layer();
void object_label(GLenum type, GLuint object, const char *name);
diff --git a/source/blender/gpu/opengl/gl_debug_layer.cc b/source/blender/gpu/opengl/gl_debug_layer.cc
index a5225f98fd9..e624cb9ee46 100644
--- a/source/blender/gpu/opengl/gl_debug_layer.cc
+++ b/source/blender/gpu/opengl/gl_debug_layer.cc
@@ -105,11 +105,6 @@ DEBUG_FUNC_DECLARE(PFNGLUSEPROGRAMPROC, void, glUseProgram, GLuint, program);
#undef DEBUG_FUNC_DECLARE
-/**
- * Initialize a fallback layer (to KHR_debug) that covers only some functions.
- * We override the functions pointers by our own implementation that just checks #glGetError.
- * Some additional functions (not overridable) are covered inside the header using wrappers.
- */
void init_debug_layer()
{
#define DEBUG_WRAP(function) \
diff --git a/source/blender/gpu/opengl/gl_drawlist.cc b/source/blender/gpu/opengl/gl_drawlist.cc
index 50ab5574cd2..8b000784fc8 100644
--- a/source/blender/gpu/opengl/gl_drawlist.cc
+++ b/source/blender/gpu/opengl/gl_drawlist.cc
@@ -236,5 +236,3 @@ void GLDrawList::submit()
/* Avoid keeping reference to the batch. */
batch_ = nullptr;
}
-
-/** \} */
diff --git a/source/blender/gpu/opengl/gl_drawlist.hh b/source/blender/gpu/opengl/gl_drawlist.hh
index 6f80fdd5a8a..bb7b89ca707 100644
--- a/source/blender/gpu/opengl/gl_drawlist.hh
+++ b/source/blender/gpu/opengl/gl_drawlist.hh
@@ -48,10 +48,10 @@ class GLDrawList : public DrawList {
~GLDrawList();
void append(GPUBatch *batch, int i_first, int i_count) override;
- void submit(void) override;
+ void submit() override;
private:
- void init(void);
+ void init();
/** Batch for which we are recording commands for. */
GLBatch *batch_;
diff --git a/source/blender/gpu/opengl/gl_framebuffer.cc b/source/blender/gpu/opengl/gl_framebuffer.cc
index 8da114d9270..13f03195437 100644
--- a/source/blender/gpu/opengl/gl_framebuffer.cc
+++ b/source/blender/gpu/opengl/gl_framebuffer.cc
@@ -110,7 +110,6 @@ void GLFrameBuffer::init()
/** \name Config
* \{ */
-/* This is a rather slow operation. Don't check in normal cases. */
bool GLFrameBuffer::check(char err_out[256])
{
this->bind(true);
@@ -451,9 +450,6 @@ void GLFrameBuffer::read(eGPUFrameBufferBits plane,
glReadPixels(UNPACK4(area), format, type, r_data);
}
-/**
- * Copy \a src at the give offset inside \a dst.
- */
void GLFrameBuffer::blit_to(
eGPUFrameBufferBits planes, int src_slot, FrameBuffer *dst_, int dst_slot, int x, int y)
{
diff --git a/source/blender/gpu/opengl/gl_framebuffer.hh b/source/blender/gpu/opengl/gl_framebuffer.hh
index 9a0e6a95675..00a7676dd3f 100644
--- a/source/blender/gpu/opengl/gl_framebuffer.hh
+++ b/source/blender/gpu/opengl/gl_framebuffer.hh
@@ -79,6 +79,9 @@ class GLFrameBuffer : public FrameBuffer {
void bind(bool enabled_srgb) override;
+ /**
+ * This is a rather slow operation. Don't check in normal cases.
+ */
bool check(char err_out[256]) override;
void clear(eGPUFrameBufferBits buffers,
@@ -97,6 +100,9 @@ class GLFrameBuffer : public FrameBuffer {
int slot,
void *r_data) override;
+ /**
+ * Copy \a src at the give offset inside \a dst.
+ */
void blit_to(eGPUFrameBufferBits planes,
int src_slot,
FrameBuffer *dst,
@@ -104,12 +110,12 @@ class GLFrameBuffer : public FrameBuffer {
int dst_offset_x,
int dst_offset_y) override;
- void apply_state(void);
+ void apply_state();
private:
- void init(void);
- void update_attachments(void);
- void update_drawbuffers(void);
+ void init();
+ void update_attachments();
+ void update_drawbuffers();
MEM_CXX_CLASS_ALLOC_FUNCS("GLFrameBuffer");
};
diff --git a/source/blender/gpu/opengl/gl_immediate.hh b/source/blender/gpu/opengl/gl_immediate.hh
index b42f439f9ec..235bc1254f2 100644
--- a/source/blender/gpu/opengl/gl_immediate.hh
+++ b/source/blender/gpu/opengl/gl_immediate.hh
@@ -58,21 +58,21 @@ class GLImmediate : public Immediate {
GLImmediate();
~GLImmediate();
- uchar *begin(void) override;
- void end(void) override;
+ uchar *begin() override;
+ void end() override;
private:
- GLuint &vbo_id(void)
+ GLuint &vbo_id()
{
return strict_vertex_len ? buffer_strict.vbo_id : buffer.vbo_id;
};
- size_t &buffer_offset(void)
+ size_t &buffer_offset()
{
return strict_vertex_len ? buffer_strict.buffer_offset : buffer.buffer_offset;
};
- size_t &buffer_size(void)
+ size_t &buffer_size()
{
return strict_vertex_len ? buffer_strict.buffer_size : buffer.buffer_size;
};
diff --git a/source/blender/gpu/opengl/gl_index_buffer.cc b/source/blender/gpu/opengl/gl_index_buffer.cc
index e305f765ad9..82bab460ae3 100644
--- a/source/blender/gpu/opengl/gl_index_buffer.cc
+++ b/source/blender/gpu/opengl/gl_index_buffer.cc
@@ -81,4 +81,14 @@ bool GLIndexBuf::is_active() const
return ibo_id_ == active_ibo_id;
}
+void GLIndexBuf::upload_data()
+{
+ bind();
+}
+
+void GLIndexBuf::update_sub(uint start, uint len, const void *data)
+{
+ glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, start, len, data);
+}
+
} // namespace blender::gpu
diff --git a/source/blender/gpu/opengl/gl_index_buffer.hh b/source/blender/gpu/opengl/gl_index_buffer.hh
index 0dbdaa6d398..aaec10d43b3 100644
--- a/source/blender/gpu/opengl/gl_index_buffer.hh
+++ b/source/blender/gpu/opengl/gl_index_buffer.hh
@@ -42,7 +42,7 @@ class GLIndexBuf : public IndexBuf {
public:
~GLIndexBuf();
- void bind(void);
+ void bind();
void bind_as_ssbo(uint binding) override;
const uint32_t *read() const override;
@@ -56,11 +56,15 @@ class GLIndexBuf : public IndexBuf {
return (GLushort *)0 + additional_vertex_offset;
}
- GLuint restart_index(void) const
+ GLuint restart_index() const
{
return (index_type_ == GPU_INDEX_U16) ? 0xFFFFu : 0xFFFFFFFFu;
}
+ void upload_data() override;
+
+ void update_sub(uint start, uint len, const void *data) override;
+
private:
bool is_active() const;
diff --git a/source/blender/gpu/opengl/gl_query.hh b/source/blender/gpu/opengl/gl_query.hh
index b4f971f45ee..2848a7abb8b 100644
--- a/source/blender/gpu/opengl/gl_query.hh
+++ b/source/blender/gpu/opengl/gl_query.hh
@@ -50,8 +50,8 @@ class GLQueryPool : public QueryPool {
void init(GPUQueryType type) override;
- void begin_query(void) override;
- void end_query(void) override;
+ void begin_query() override;
+ void end_query() override;
void get_occlusion_result(MutableSpan<uint32_t> r_values) override;
};
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index f8a7a2e400c..1e6e2475665 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -38,6 +38,7 @@
using namespace blender;
using namespace blender::gpu;
+using namespace blender::gpu::shader;
/* -------------------------------------------------------------------- */
/** \name Creation / Destruction
@@ -47,7 +48,7 @@ GLShader::GLShader(const char *name) : Shader(name)
{
#if 0 /* Would be nice to have, but for now the Deferred compilation \
* does not have a GPUContext. */
- BLI_assert(GLContext::get() != NULL);
+ BLI_assert(GLContext::get() != nullptr);
#endif
shader_program_ = glCreateProgram();
@@ -58,7 +59,7 @@ GLShader::~GLShader()
{
#if 0 /* Would be nice to have, but for now the Deferred compilation \
* does not have a GPUContext. */
- BLI_assert(GLContext::get() != NULL);
+ BLI_assert(GLContext::get() != nullptr);
#endif
/* Invalid handles are silently ignored. */
glDeleteShader(vert_shader_);
@@ -71,20 +72,503 @@ GLShader::~GLShader()
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Create Info
+ * \{ */
+
+static const char *to_string(const Interpolation &interp)
+{
+ switch (interp) {
+ case Interpolation::SMOOTH:
+ return "smooth";
+ case Interpolation::FLAT:
+ return "flat";
+ case Interpolation::NO_PERSPECTIVE:
+ return "noperspective";
+ default:
+ return "unkown";
+ }
+}
+
+static const char *to_string(const Type &type)
+{
+ switch (type) {
+ case Type::FLOAT:
+ return "float";
+ case Type::VEC2:
+ return "vec2";
+ case Type::VEC3:
+ return "vec3";
+ case Type::VEC4:
+ return "vec4";
+ case Type::MAT3:
+ return "mat3";
+ case Type::MAT4:
+ return "mat4";
+ case Type::UINT:
+ return "uint";
+ case Type::UVEC2:
+ return "uvec2";
+ case Type::UVEC3:
+ return "uvec3";
+ case Type::UVEC4:
+ return "uvec4";
+ case Type::INT:
+ return "int";
+ case Type::IVEC2:
+ return "ivec2";
+ case Type::IVEC3:
+ return "ivec3";
+ case Type::IVEC4:
+ return "ivec4";
+ case Type::BOOL:
+ return "bool";
+ default:
+ return "unkown";
+ }
+}
+
+static const char *to_string(const PrimitiveIn &layout)
+{
+ switch (layout) {
+ case PrimitiveIn::POINTS:
+ return "points";
+ case PrimitiveIn::LINES:
+ return "lines";
+ case PrimitiveIn::LINES_ADJACENCY:
+ return "lines_adjacency";
+ case PrimitiveIn::TRIANGLES:
+ return "triangles";
+ case PrimitiveIn::TRIANGLES_ADJACENCY:
+ return "triangles_adjacency";
+ default:
+ return "unknown";
+ }
+}
+
+static const char *to_string(const PrimitiveOut &layout)
+{
+ switch (layout) {
+ case PrimitiveOut::POINTS:
+ return "points";
+ case PrimitiveOut::LINE_STRIP:
+ return "line_strip";
+ case PrimitiveOut::TRIANGLE_STRIP:
+ return "triangle_strip";
+ default:
+ return "unknown";
+ }
+}
+
+static void print_image_type(std::ostream &os,
+ const ImageType &type,
+ const ShaderCreateInfo::Resource::BindType bind_type)
+{
+ switch (type) {
+ case ImageType::INT_BUFFER:
+ case ImageType::INT_1D:
+ case ImageType::INT_1D_ARRAY:
+ case ImageType::INT_2D:
+ case ImageType::INT_2D_ARRAY:
+ case ImageType::INT_3D:
+ case ImageType::INT_CUBE:
+ case ImageType::INT_CUBE_ARRAY:
+ os << "i";
+ break;
+ case ImageType::UINT_BUFFER:
+ case ImageType::UINT_1D:
+ case ImageType::UINT_1D_ARRAY:
+ case ImageType::UINT_2D:
+ case ImageType::UINT_2D_ARRAY:
+ case ImageType::UINT_3D:
+ case ImageType::UINT_CUBE:
+ case ImageType::UINT_CUBE_ARRAY:
+ os << "u";
+ break;
+ default:
+ break;
+ }
+
+ if (bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) {
+ os << "image";
+ }
+ else {
+ os << "sampler";
+ }
+
+ switch (type) {
+ case ImageType::FLOAT_BUFFER:
+ case ImageType::INT_BUFFER:
+ case ImageType::UINT_BUFFER:
+ os << "Buffer";
+ break;
+ case ImageType::FLOAT_1D:
+ case ImageType::FLOAT_1D_ARRAY:
+ case ImageType::INT_1D:
+ case ImageType::INT_1D_ARRAY:
+ case ImageType::UINT_1D:
+ case ImageType::UINT_1D_ARRAY:
+ os << "1D";
+ break;
+ case ImageType::FLOAT_2D:
+ case ImageType::FLOAT_2D_ARRAY:
+ case ImageType::INT_2D:
+ case ImageType::INT_2D_ARRAY:
+ case ImageType::UINT_2D:
+ case ImageType::UINT_2D_ARRAY:
+ case ImageType::SHADOW_2D:
+ case ImageType::SHADOW_2D_ARRAY:
+ case ImageType::DEPTH_2D:
+ case ImageType::DEPTH_2D_ARRAY:
+ os << "2D";
+ break;
+ case ImageType::FLOAT_3D:
+ case ImageType::INT_3D:
+ case ImageType::UINT_3D:
+ os << "3D";
+ break;
+ case ImageType::FLOAT_CUBE:
+ case ImageType::FLOAT_CUBE_ARRAY:
+ case ImageType::INT_CUBE:
+ case ImageType::INT_CUBE_ARRAY:
+ case ImageType::UINT_CUBE:
+ case ImageType::UINT_CUBE_ARRAY:
+ case ImageType::SHADOW_CUBE:
+ case ImageType::SHADOW_CUBE_ARRAY:
+ case ImageType::DEPTH_CUBE:
+ case ImageType::DEPTH_CUBE_ARRAY:
+ os << "Cube";
+ break;
+ default:
+ break;
+ }
+
+ switch (type) {
+ case ImageType::FLOAT_1D_ARRAY:
+ case ImageType::FLOAT_2D_ARRAY:
+ case ImageType::FLOAT_CUBE_ARRAY:
+ case ImageType::INT_1D_ARRAY:
+ case ImageType::INT_2D_ARRAY:
+ case ImageType::INT_CUBE_ARRAY:
+ case ImageType::UINT_1D_ARRAY:
+ case ImageType::UINT_2D_ARRAY:
+ case ImageType::UINT_CUBE_ARRAY:
+ case ImageType::SHADOW_2D_ARRAY:
+ case ImageType::SHADOW_CUBE_ARRAY:
+ case ImageType::DEPTH_2D_ARRAY:
+ case ImageType::DEPTH_CUBE_ARRAY:
+ os << "Array";
+ break;
+ default:
+ break;
+ }
+
+ switch (type) {
+ case ImageType::SHADOW_2D:
+ case ImageType::SHADOW_2D_ARRAY:
+ case ImageType::SHADOW_CUBE:
+ case ImageType::SHADOW_CUBE_ARRAY:
+ os << "Shadow";
+ break;
+ default:
+ break;
+ }
+ os << " ";
+}
+
+static std::ostream &print_qualifier(std::ostream &os, const Qualifier &qualifiers)
+{
+ if ((qualifiers & Qualifier::RESTRICT) == Qualifier::RESTRICT) {
+ os << "restrict ";
+ }
+ if ((qualifiers & Qualifier::READ_ONLY) == Qualifier::READ_ONLY) {
+ os << "readonly ";
+ }
+ if ((qualifiers & Qualifier::WRITE_ONLY) == Qualifier::WRITE_ONLY) {
+ os << "writeonly ";
+ }
+ return os;
+}
+
+static void print_resource(std::ostream &os, const ShaderCreateInfo::Resource &res)
+{
+ if (GLContext::explicit_location_support) {
+ os << "layout(binding = " << res.slot;
+ if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) {
+ os << ", " << res.image.format;
+ }
+ else if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) {
+ os << ", std140";
+ }
+ else if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) {
+ os << ", std430";
+ }
+ os << ") ";
+ }
+ else if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) {
+ os << "layout(std140) ";
+ }
+
+ int64_t array_offset;
+ StringRef name_no_array;
+
+ switch (res.bind_type) {
+ case ShaderCreateInfo::Resource::BindType::SAMPLER:
+ os << "uniform ";
+ print_image_type(os, res.sampler.type, res.bind_type);
+ os << res.sampler.name << ";\n";
+ break;
+ case ShaderCreateInfo::Resource::BindType::IMAGE:
+ os << "uniform ";
+ print_qualifier(os, res.image.qualifiers);
+ print_image_type(os, res.image.type, res.bind_type);
+ os << res.image.name << ";\n";
+ break;
+ case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER:
+ array_offset = res.uniformbuf.name.find_first_of("[");
+ name_no_array = (array_offset == -1) ? res.uniformbuf.name :
+ StringRef(res.uniformbuf.name.c_str(), array_offset);
+ os << "uniform " << name_no_array << " { " << res.uniformbuf.type_name << " _"
+ << res.uniformbuf.name << "; };\n";
+ break;
+ case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER:
+ array_offset = res.storagebuf.name.find_first_of("[");
+ name_no_array = (array_offset == -1) ? res.storagebuf.name :
+ StringRef(res.storagebuf.name.c_str(), array_offset);
+ print_qualifier(os, res.storagebuf.qualifiers);
+ os << "buffer ";
+ os << name_no_array << " { " << res.storagebuf.type_name << " _" << res.storagebuf.name
+ << "; };\n";
+ break;
+ }
+}
+
+static void print_resource_alias(std::ostream &os, const ShaderCreateInfo::Resource &res)
+{
+ int64_t array_offset;
+ StringRef name_no_array;
+
+ switch (res.bind_type) {
+ case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER:
+ array_offset = res.uniformbuf.name.find_first_of("[");
+ name_no_array = (array_offset == -1) ? res.uniformbuf.name :
+ StringRef(res.uniformbuf.name.c_str(), array_offset);
+ os << "#define " << name_no_array << " (_" << name_no_array << ")\n";
+ break;
+ case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER:
+ array_offset = res.storagebuf.name.find_first_of("[");
+ name_no_array = (array_offset == -1) ? res.storagebuf.name :
+ StringRef(res.storagebuf.name.c_str(), array_offset);
+ os << "#define " << name_no_array << " (_" << name_no_array << ")\n";
+ break;
+ default:
+ break;
+ }
+}
+
+static void print_interface(std::ostream &os,
+ const StringRefNull &prefix,
+ const StageInterfaceInfo &iface,
+ const StringRefNull &suffix = "")
+{
+ /* TODO(fclem) Move that to interface check. */
+ // if (iface.instance_name.is_empty()) {
+ // BLI_assert_msg(0, "Interfaces require an instance name for geometry shader.");
+ // std::cout << iface.name << ": Interfaces require an instance name for geometry shader.\n";
+ // continue;
+ // }
+ os << prefix << " " << iface.name << "{" << std::endl;
+ for (const StageInterfaceInfo::InOut &inout : iface.inouts) {
+ os << " " << to_string(inout.interp) << " " << to_string(inout.type) << " " << inout.name
+ << ";\n";
+ }
+ os << "}";
+ os << (iface.instance_name.is_empty() ? "" : "\n") << iface.instance_name << suffix << ";\n";
+}
+
+std::string GLShader::resources_declare(const ShaderCreateInfo &info) const
+{
+ std::stringstream ss;
+
+ /* NOTE: We define macros in GLSL to trigger compilation error if the resource names
+ * are reused for local variables. This is to match other backend behavior which needs accessors
+ * macros. */
+
+ ss << "\n/* Pass Resources. */\n";
+ for (const ShaderCreateInfo::Resource &res : info.pass_resources_) {
+ print_resource(ss, res);
+ }
+ for (const ShaderCreateInfo::Resource &res : info.pass_resources_) {
+ print_resource_alias(ss, res);
+ }
+ ss << "\n/* Batch Resources. */\n";
+ for (const ShaderCreateInfo::Resource &res : info.batch_resources_) {
+ print_resource(ss, res);
+ }
+ for (const ShaderCreateInfo::Resource &res : info.batch_resources_) {
+ print_resource_alias(ss, res);
+ }
+ ss << "\n/* Push Constants. */\n";
+ for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) {
+ if (GLContext::explicit_location_support) {
+ ss << "layout(location = " << uniform.index << ") ";
+ }
+ ss << "uniform " << to_string(uniform.type) << " " << uniform.name;
+ if (uniform.array_size > 0) {
+ ss << "[" << uniform.array_size << "]";
+ }
+ ss << ";\n";
+ }
+ for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) {
+ ss << "#define " << uniform.name << " (" << uniform.name << ")\n";
+ }
+ ss << "\n";
+ return ss.str();
+}
+
+std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) const
+{
+ std::stringstream ss;
+
+ ss << "\n/* Inputs. */\n";
+ for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) {
+ if (GLContext::explicit_location_support) {
+ ss << "layout(location = " << attr.index << ") ";
+ }
+ ss << "in " << to_string(attr.type) << " " << attr.name << ";\n";
+ }
+ ss << "\n/* Interfaces. */\n";
+ for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) {
+ print_interface(ss, "out", *iface);
+ }
+ ss << "\n";
+ return ss.str();
+}
+
+std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) const
+{
+ std::stringstream ss;
+ ss << "\n/* Interfaces. */\n";
+ const Vector<StageInterfaceInfo *> &in_interfaces = (info.geometry_source_.is_empty()) ?
+ info.vertex_out_interfaces_ :
+ info.geometry_out_interfaces_;
+ for (const StageInterfaceInfo *iface : in_interfaces) {
+ print_interface(ss, "in", *iface);
+ }
+ ss << "\n/* Outputs. */\n";
+ for (const ShaderCreateInfo::FragOut &output : info.fragment_outputs_) {
+ ss << "layout(location = " << output.index;
+ switch (output.blend) {
+ case DualBlend::SRC_0:
+ ss << ", index = 0";
+ break;
+ case DualBlend::SRC_1:
+ ss << ", index = 1";
+ break;
+ default:
+ break;
+ }
+ ss << ") ";
+ ss << "out " << to_string(output.type) << " " << output.name << ";\n";
+ }
+ ss << "\n";
+ return ss.str();
+}
+
+std::string GLShader::geometry_layout_declare(const ShaderCreateInfo &info) const
+{
+ int max_verts = info.geometry_layout_.max_vertices;
+ int invocations = info.geometry_layout_.invocations;
+
+ if (GLContext::geometry_shader_invocations == false && invocations != -1) {
+ max_verts *= invocations;
+ invocations = -1;
+ }
+
+ std::stringstream ss;
+ ss << "\n/* Geometry Layout. */\n";
+ ss << "layout(" << to_string(info.geometry_layout_.primitive_in);
+ if (invocations != -1) {
+ ss << ", invocations = " << invocations;
+ }
+ ss << ") in;\n";
+
+ ss << "layout(" << to_string(info.geometry_layout_.primitive_out)
+ << ", max_vertices = " << max_verts << ") out;\n";
+ ss << "\n";
+ return ss.str();
+}
+
+static StageInterfaceInfo *find_interface_by_name(const Vector<StageInterfaceInfo *> &ifaces,
+ const StringRefNull &name)
+{
+ for (auto iface : ifaces) {
+ if (iface->name == name) {
+ return iface;
+ }
+ }
+ return nullptr;
+}
+
+std::string GLShader::geometry_interface_declare(const ShaderCreateInfo &info) const
+{
+
+ std::stringstream ss;
+ ss << "\n/* Interfaces. */\n";
+ for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) {
+ bool has_matching_output_iface = find_interface_by_name(info.geometry_out_interfaces_,
+ iface->instance_name) != nullptr;
+ const char *suffix = (has_matching_output_iface) ? "_in[]" : "[]";
+ print_interface(ss, "in", *iface, suffix);
+ }
+ ss << "\n";
+ for (const StageInterfaceInfo *iface : info.geometry_out_interfaces_) {
+ bool has_matching_input_iface = find_interface_by_name(info.vertex_out_interfaces_,
+ iface->instance_name) != nullptr;
+ const char *suffix = (has_matching_input_iface) ? "_out" : "";
+ print_interface(ss, "out", *iface, suffix);
+ }
+ ss << "\n";
+ return ss.str();
+}
+
+std::string GLShader::compute_layout_declare(const ShaderCreateInfo &info) const
+{
+ std::stringstream ss;
+ ss << "\n/* Compute Layout. */\n";
+ ss << "layout(local_size_x = " << info.compute_layout_.local_size_x;
+ if (info.compute_layout_.local_size_y != -1) {
+ ss << ", local_size_y = " << info.compute_layout_.local_size_y;
+ }
+ if (info.compute_layout_.local_size_z != -1) {
+ ss << ", local_size_y = " << info.compute_layout_.local_size_z;
+ }
+ ss << ") in;\n";
+ ss << "\n";
+ return ss.str();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Shader stage creation
* \{ */
static char *glsl_patch_default_get()
{
/** Used for shader patching. Init once. */
- static char patch[512] = "\0";
+ static char patch[700] = "\0";
if (patch[0] != '\0') {
return patch;
}
size_t slen = 0;
/* Version need to go first. */
- STR_CONCAT(patch, slen, "#version 430\n");
+ if (GLEW_VERSION_4_3) {
+ STR_CONCAT(patch, slen, "#version 430\n");
+ }
+ else {
+ STR_CONCAT(patch, slen, "#version 330\n");
+ }
/* Enable extensions for features that are not part of our base GLSL version
* don't use an extension for something already available! */
@@ -99,16 +583,32 @@ static char *glsl_patch_default_get()
if (GLContext::shader_draw_parameters_support) {
STR_CONCAT(patch, slen, "#extension GL_ARB_shader_draw_parameters : enable\n");
STR_CONCAT(patch, slen, "#define GPU_ARB_shader_draw_parameters\n");
+ STR_CONCAT(patch, slen, "#define gpu_BaseInstance gl_BaseInstanceARB\n");
+ }
+ if (GLContext::geometry_shader_invocations) {
+ STR_CONCAT(patch, slen, "#extension GL_ARB_gpu_shader5 : enable\n");
+ STR_CONCAT(patch, slen, "#define GPU_ARB_gpu_shader5\n");
}
if (GLContext::texture_cube_map_array_support) {
STR_CONCAT(patch, slen, "#extension GL_ARB_texture_cube_map_array : enable\n");
STR_CONCAT(patch, slen, "#define GPU_ARB_texture_cube_map_array\n");
}
+ if (GLEW_ARB_conservative_depth) {
+ STR_CONCAT(patch, slen, "#extension GL_ARB_conservative_depth : enable\n");
+ }
if (GPU_shader_image_load_store_support()) {
- STR_CONCAT(patch, slen, "#extension GL_ARB_shader_image_load_store : enable\n");
- STR_CONCAT(patch, slen, "#define GPU_ARB_shader_image_load_store\n");
+ STR_CONCAT(patch, slen, "#extension GL_ARB_shader_image_load_store: enable\n");
+ STR_CONCAT(patch, slen, "#extension GL_ARB_shading_language_420pack: enable\n");
}
+ /* Fallbacks. */
+ if (!GLContext::shader_draw_parameters_support) {
+ STR_CONCAT(patch, slen, "uniform int gpu_BaseInstance;\n");
+ }
+
+ /* Vulkan GLSL compat. */
+ STR_CONCAT(patch, slen, "#define gpu_InstanceIndex (gl_InstanceID + gpu_BaseInstance)\n");
+
/* Derivative sign can change depending on implementation. */
STR_CONCATF(patch, slen, "#define DFDX_SIGN %1.1f\n", GLContext::derivative_signs[0]);
STR_CONCATF(patch, slen, "#define DFDY_SIGN %1.1f\n", GLContext::derivative_signs[1]);
@@ -141,7 +641,6 @@ char *GLShader::glsl_patch_get(GLenum gl_stage)
return glsl_patch_default_get();
}
-/* Create, compile and attach the shader stage to the shader program. */
GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources)
{
GLuint shader = glCreateShader(gl_stage);
@@ -211,7 +710,7 @@ void GLShader::compute_shader_from_glsl(MutableSpan<const char *> sources)
compute_shader_ = this->create_shader_stage(GL_COMPUTE_SHADER, sources);
}
-bool GLShader::finalize()
+bool GLShader::finalize(const shader::ShaderCreateInfo *info)
{
if (compilation_failed_) {
return false;
@@ -230,7 +729,12 @@ bool GLShader::finalize()
return false;
}
- interface = new GLShaderInterface(shader_program_);
+ if (info != nullptr) {
+ interface = new GLShaderInterface(shader_program_, *info);
+ }
+ else {
+ interface = new GLShaderInterface(shader_program_);
+ }
return true;
}
@@ -262,7 +766,6 @@ void GLShader::unbind()
* TODO(fclem): Should be replaced by compute shaders.
* \{ */
-/* Should be called before linking. */
void GLShader::transform_feedback_names_set(Span<const char *> name_list,
const eGPUShaderTFBType geom_type)
{
diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh
index 770bc29747e..a82ab026c16 100644
--- a/source/blender/gpu/opengl/gl_shader.hh
+++ b/source/blender/gpu/opengl/gl_shader.hh
@@ -27,6 +27,7 @@
#include "glew-mx.h"
+#include "gpu_shader_create_info.hh"
#include "gpu_shader_private.hh"
namespace blender {
@@ -36,6 +37,9 @@ namespace gpu {
* Implementation of shader compilation and uniforms handling using OpenGL.
*/
class GLShader : public Shader {
+ friend shader::ShaderCreateInfo;
+ friend shader::StageInterfaceInfo;
+
private:
/** Handle for full program (links shader stages below). */
GLuint shader_program_ = 0;
@@ -53,32 +57,41 @@ class GLShader : public Shader {
GLShader(const char *name);
~GLShader();
- /* Return true on success. */
+ /** Return true on success. */
void vertex_shader_from_glsl(MutableSpan<const char *> sources) override;
void geometry_shader_from_glsl(MutableSpan<const char *> sources) override;
void fragment_shader_from_glsl(MutableSpan<const char *> sources) override;
void compute_shader_from_glsl(MutableSpan<const char *> sources) override;
- bool finalize(void) override;
+ bool finalize(const shader::ShaderCreateInfo *info = nullptr) override;
+
+ std::string resources_declare(const shader::ShaderCreateInfo &info) const override;
+ std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const override;
+ std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const override;
+ std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const override;
+ std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const override;
+ std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const override;
+ /** Should be called before linking. */
void transform_feedback_names_set(Span<const char *> name_list,
- const eGPUShaderTFBType geom_type) override;
+ eGPUShaderTFBType geom_type) override;
bool transform_feedback_enable(GPUVertBuf *buf) override;
- void transform_feedback_disable(void) override;
+ void transform_feedback_disable() override;
- void bind(void) override;
- void unbind(void) override;
+ void bind() override;
+ void unbind() override;
void uniform_float(int location, int comp_len, int array_size, const float *data) override;
void uniform_int(int location, int comp_len, int array_size, const int *data) override;
void vertformat_from_shader(GPUVertFormat *format) const override;
- /* DEPRECATED: Kept only because of BGL API. */
- int program_handle_get(void) const override;
+ /** DEPRECATED: Kept only because of BGL API. */
+ int program_handle_get() const override;
private:
char *glsl_patch_get(GLenum gl_stage);
+ /** Create, compile and attach the shader stage to the shader program. */
GLuint create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources);
MEM_CXX_CLASS_ALLOC_FUNCS("GLShader");
diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc
index c65315007ad..467731f2889 100644
--- a/source/blender/gpu/opengl/gl_shader_interface.cc
+++ b/source/blender/gpu/opengl/gl_shader_interface.cc
@@ -25,7 +25,9 @@
#include "BLI_bitmap.h"
+#include "gl_backend.hh"
#include "gl_batch.hh"
+#include "gl_context.hh"
#include "gl_shader_interface.hh"
@@ -350,6 +352,163 @@ GLShaderInterface::GLShaderInterface(GLuint program)
this->sort_inputs();
}
+GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateInfo &info)
+{
+ using namespace blender::gpu::shader;
+
+ attr_len_ = info.vertex_inputs_.size();
+ uniform_len_ = info.push_constants_.size();
+ ubo_len_ = 0;
+ ssbo_len_ = 0;
+
+ Vector<ShaderCreateInfo::Resource> all_resources;
+ all_resources.extend(info.pass_resources_);
+ all_resources.extend(info.batch_resources_);
+
+ for (ShaderCreateInfo::Resource &res : all_resources) {
+ switch (res.bind_type) {
+ case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER:
+ ubo_len_++;
+ break;
+ case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER:
+ ssbo_len_++;
+ break;
+ case ShaderCreateInfo::Resource::BindType::SAMPLER:
+ uniform_len_++;
+ break;
+ case ShaderCreateInfo::Resource::BindType::IMAGE:
+ uniform_len_++;
+ break;
+ }
+ }
+
+ size_t workaround_names_size = 0;
+ Vector<StringRefNull> workaround_uniform_names;
+ auto check_enabled_uniform = [&](const char *uniform_name) {
+ if (glGetUniformLocation(program, uniform_name) != -1) {
+ workaround_uniform_names.append(uniform_name);
+ workaround_names_size += StringRefNull(uniform_name).size() + 1;
+ uniform_len_++;
+ }
+ };
+
+ if (!GLContext::shader_draw_parameters_support) {
+ check_enabled_uniform("gpu_BaseInstance");
+ }
+
+ BLI_assert_msg(ubo_len_ <= 16, "enabled_ubo_mask_ is uint16_t");
+
+ int input_tot_len = attr_len_ + ubo_len_ + uniform_len_ + ssbo_len_;
+ inputs_ = (ShaderInput *)MEM_callocN(sizeof(ShaderInput) * input_tot_len, __func__);
+ ShaderInput *input = inputs_;
+
+ name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_ + workaround_names_size,
+ "name_buffer");
+ uint32_t name_buffer_offset = 0;
+
+ /* Necessary to make #glUniform works. TODO(fclem) Remove. */
+ glUseProgram(program);
+
+ /* Attributes */
+ for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) {
+ copy_input_name(input, attr.name, name_buffer_, name_buffer_offset);
+ if (true || !GLContext::explicit_location_support) {
+ input->location = input->binding = glGetAttribLocation(program, attr.name.c_str());
+ }
+ else {
+ input->location = input->binding = attr.index;
+ }
+ enabled_attr_mask_ |= (1 << input->location);
+ input++;
+ }
+
+ /* Uniform Blocks */
+ for (const ShaderCreateInfo::Resource &res : all_resources) {
+ if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) {
+ copy_input_name(input, res.uniformbuf.name, name_buffer_, name_buffer_offset);
+ if (true || !GLContext::explicit_location_support) {
+ input->location = glGetUniformBlockIndex(program, name_buffer_ + input->name_offset);
+ glUniformBlockBinding(program, input->location, res.slot);
+ }
+ input->binding = res.slot;
+ enabled_ubo_mask_ |= (1 << input->binding);
+ input++;
+ }
+ }
+
+ /* Uniforms & samplers & images */
+ for (const ShaderCreateInfo::Resource &res : all_resources) {
+ if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) {
+ copy_input_name(input, res.sampler.name, name_buffer_, name_buffer_offset);
+ /* Until we make use of explicit uniform location or eliminate all
+ * sampler manually changing. */
+ if (true || !GLContext::explicit_location_support) {
+ input->location = glGetUniformLocation(program, res.sampler.name.c_str());
+ glUniform1i(input->location, res.slot);
+ }
+ input->binding = res.slot;
+ enabled_tex_mask_ |= (1ull << input->binding);
+ input++;
+ }
+ else if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) {
+ copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset);
+ /* Until we make use of explicit uniform location. */
+ if (true || !GLContext::explicit_location_support) {
+ input->location = glGetUniformLocation(program, res.image.name.c_str());
+ glUniform1i(input->location, res.slot);
+ }
+ input->binding = res.slot;
+ enabled_ima_mask_ |= (1 << input->binding);
+ input++;
+ }
+ }
+ for (const ShaderCreateInfo::PushConst &uni : info.push_constants_) {
+ copy_input_name(input, uni.name, name_buffer_, name_buffer_offset);
+ /* Until we make use of explicit uniform location. */
+ if (true || !GLContext::explicit_location_support) {
+ input->location = glGetUniformLocation(program, name_buffer_ + input->name_offset);
+ }
+ input->binding = -1;
+ input++;
+ }
+
+ /* Compatibility uniforms. */
+ for (auto &name : workaround_uniform_names) {
+ copy_input_name(input, name, name_buffer_, name_buffer_offset);
+ input->location = glGetUniformLocation(program, name_buffer_ + input->name_offset);
+ input->binding = -1;
+ input++;
+ }
+
+ /* SSBOs */
+ for (const ShaderCreateInfo::Resource &res : all_resources) {
+ if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) {
+ copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset);
+ input->location = input->binding = res.slot;
+ enabled_ubo_mask_ |= (1 << input->binding);
+ input++;
+ }
+ }
+
+ /* Builtin Uniforms */
+ for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) {
+ GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int);
+ const ShaderInput *uni = this->uniform_get(builtin_uniform_name(u));
+ builtins_[u] = (uni != nullptr) ? uni->location : -1;
+ }
+
+ /* Builtin Uniforms Blocks */
+ for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) {
+ GPUUniformBlockBuiltin u = static_cast<GPUUniformBlockBuiltin>(u_int);
+ const ShaderInput *block = this->ubo_get(builtin_uniform_block_name(u));
+ builtin_blocks_[u] = (block != nullptr) ? block->binding : -1;
+ }
+
+ this->sort_inputs();
+
+ // this->debug_print();
+}
+
GLShaderInterface::~GLShaderInterface()
{
for (auto *ref : refs_) {
diff --git a/source/blender/gpu/opengl/gl_shader_interface.hh b/source/blender/gpu/opengl/gl_shader_interface.hh
index 89a5b631047..94b6dd58316 100644
--- a/source/blender/gpu/opengl/gl_shader_interface.hh
+++ b/source/blender/gpu/opengl/gl_shader_interface.hh
@@ -34,6 +34,7 @@
#include "glew-mx.h"
+#include "gpu_shader_create_info.hh"
#include "gpu_shader_interface.hh"
namespace blender::gpu {
@@ -49,6 +50,7 @@ class GLShaderInterface : public ShaderInterface {
Vector<GLVaoCache *> refs_;
public:
+ GLShaderInterface(GLuint program, const shader::ShaderCreateInfo &info);
GLShaderInterface(GLuint program);
~GLShaderInterface();
diff --git a/source/blender/gpu/opengl/gl_state.cc b/source/blender/gpu/opengl/gl_state.cc
index 1106e3dab50..c6c013fcf3a 100644
--- a/source/blender/gpu/opengl/gl_state.cc
+++ b/source/blender/gpu/opengl/gl_state.cc
@@ -52,6 +52,7 @@ GLStateManager::GLStateManager()
glDisable(GL_DITHER);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPrimitiveRestartIndex((GLuint)0xFFFFFFFF);
@@ -83,7 +84,6 @@ void GLStateManager::apply_state()
active_fb->apply_state();
};
-/* Will set all the states regardless of the current ones. */
void GLStateManager::force_state()
{
/* Little exception for clip distances since they need to keep the old count correct. */
@@ -377,7 +377,7 @@ void GLStateManager::set_blend(const eGPUBlend value)
break;
}
case GPU_BLEND_ADDITIVE: {
- /* Do not let alpha accumulate but premult the source RGB by it. */
+ /* Do not let alpha accumulate but pre-multiply the source RGB by it. */
src_rgb = GL_SRC_ALPHA;
dst_rgb = GL_ONE;
src_alpha = GL_ZERO;
@@ -481,7 +481,6 @@ void GLStateManager::texture_bind(Texture *tex_, eGPUSamplerState sampler_type,
dirty_texture_binds_ |= 1ULL << unit;
}
-/* Bind the texture to slot 0 for editing purpose. Used by legacy pipeline. */
void GLStateManager::texture_bind_temp(GLTexture *tex)
{
glActiveTexture(GL_TEXTURE0);
diff --git a/source/blender/gpu/opengl/gl_state.hh b/source/blender/gpu/opengl/gl_state.hh
index 84def7d981c..5985f1583f2 100644
--- a/source/blender/gpu/opengl/gl_state.hh
+++ b/source/blender/gpu/opengl/gl_state.hh
@@ -71,43 +71,49 @@ class GLStateManager : public StateManager {
public:
GLStateManager();
- void apply_state(void) override;
- void force_state(void) override;
+ void apply_state() override;
+ /**
+ * Will set all the states regardless of the current ones.
+ */
+ void force_state() override;
void issue_barrier(eGPUBarrier barrier_bits) override;
void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) override;
+ /**
+ * Bind the texture to slot 0 for editing purpose. Used by legacy pipeline.
+ */
void texture_bind_temp(GLTexture *tex);
void texture_unbind(Texture *tex) override;
- void texture_unbind_all(void) override;
+ void texture_unbind_all() override;
void image_bind(Texture *tex, int unit) override;
void image_unbind(Texture *tex) override;
- void image_unbind_all(void) override;
+ void image_unbind_all() override;
void texture_unpack_row_length_set(uint len) override;
- uint64_t bound_texture_slots(void);
- uint8_t bound_image_slots(void);
+ uint64_t bound_texture_slots();
+ uint8_t bound_image_slots();
private:
- static void set_write_mask(const eGPUWriteMask value);
- static void set_depth_test(const eGPUDepthTest value);
- static void set_stencil_test(const eGPUStencilTest test, const eGPUStencilOp operation);
- static void set_stencil_mask(const eGPUStencilTest test, const GPUStateMutable state);
- static void set_clip_distances(const int new_dist_len, const int old_dist_len);
- static void set_logic_op(const bool enable);
- static void set_facing(const bool invert);
- static void set_backface_culling(const eGPUFaceCullTest test);
- static void set_provoking_vert(const eGPUProvokingVertex vert);
- static void set_shadow_bias(const bool enable);
- static void set_blend(const eGPUBlend value);
+ static void set_write_mask(eGPUWriteMask value);
+ static void set_depth_test(eGPUDepthTest value);
+ static void set_stencil_test(eGPUStencilTest test, eGPUStencilOp operation);
+ static void set_stencil_mask(eGPUStencilTest test, const GPUStateMutable state);
+ static void set_clip_distances(int new_dist_len, int old_dist_len);
+ static void set_logic_op(bool enable);
+ static void set_facing(bool invert);
+ static void set_backface_culling(eGPUFaceCullTest test);
+ static void set_provoking_vert(eGPUProvokingVertex vert);
+ static void set_shadow_bias(bool enable);
+ static void set_blend(eGPUBlend value);
void set_state(const GPUState &state);
void set_mutable_state(const GPUStateMutable &state);
- void texture_bind_apply(void);
- void image_bind_apply(void);
+ void texture_bind_apply();
+ void image_bind_apply();
MEM_CXX_CLASS_ALLOC_FUNCS("GLStateManager")
};
@@ -133,6 +139,12 @@ static inline GLbitfield to_gl(eGPUBarrier barrier_bits)
if (barrier_bits & GPU_BARRIER_FRAMEBUFFER) {
barrier |= GL_FRAMEBUFFER_BARRIER_BIT;
}
+ if (barrier_bits & GPU_BARRIER_VERTEX_ATTRIB_ARRAY) {
+ barrier |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
+ }
+ if (barrier_bits & GPU_BARRIER_ELEMENT_ARRAY) {
+ barrier |= GL_ELEMENT_ARRAY_BARRIER_BIT;
+ }
return barrier;
}
diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc
index db1fda63c28..d84d21d3021 100644
--- a/source/blender/gpu/opengl/gl_texture.cc
+++ b/source/blender/gpu/opengl/gl_texture.cc
@@ -62,7 +62,6 @@ GLTexture::~GLTexture()
GLContext::tex_free(tex_id_);
}
-/* Return true on success. */
bool GLTexture::init_internal()
{
if ((format_ == GPU_DEPTH24_STENCIL8) && GPU_depth_blitting_workaround()) {
@@ -100,7 +99,6 @@ bool GLTexture::init_internal()
return true;
}
-/* Return true on success. */
bool GLTexture::init_internal(GPUVertBuf *vbo)
{
GLVertBuf *gl_vbo = static_cast<GLVertBuf *>(unwrap(vbo));
@@ -123,7 +121,6 @@ bool GLTexture::init_internal(GPUVertBuf *vbo)
return true;
}
-/* Will create enough mipmaps up to get to the given level. */
void GLTexture::ensure_mipmaps(int miplvl)
{
int effective_h = (type_ == GPU_TEXTURE_1D_ARRAY) ? 0 : h_;
@@ -225,6 +222,8 @@ void GLTexture::update_sub_direct_state_access(
break;
}
}
+
+ has_pixels_ = true;
}
void GLTexture::update_sub(
@@ -288,6 +287,8 @@ void GLTexture::update_sub(
break;
}
}
+
+ has_pixels_ = true;
}
/**
@@ -307,6 +308,16 @@ void GLTexture::generate_mipmap()
return;
}
+ if (GLContext::generate_mipmap_workaround) {
+ /* Broken glGenerateMipmap, don't call it and render without mipmaps.
+ * If no top level pixels have been filled in, the levels will get filled by
+ * other means and there is no need to disable mipmapping. */
+ if (has_pixels_) {
+ this->mip_range_set(0, 0);
+ }
+ return;
+ }
+
/* Down-sample from mip 0 using implementation. */
if (GLContext::direct_state_access_support) {
glGenerateTextureMipmap(tex_id_);
@@ -337,6 +348,8 @@ void GLTexture::clear(eGPUDataFormat data_format, const void *data)
GPU_framebuffer_bind(prev_fb);
}
+
+ has_pixels_ = true;
}
void GLTexture::copy_to(Texture *dst_)
@@ -363,6 +376,8 @@ void GLTexture::copy_to(Texture *dst_)
GPU_framebuffer_blit(
src->framebuffer_get(), 0, dst->framebuffer_get(), 0, to_framebuffer_bits(format_));
}
+
+ has_pixels_ = true;
}
void *GLTexture::read(int mip, eGPUDataFormat type)
@@ -452,6 +467,7 @@ struct GPUFrameBuffer *GLTexture::framebuffer_get()
GPUTexture *gputex = reinterpret_cast<GPUTexture *>(static_cast<Texture *>(this));
framebuffer_ = GPU_framebuffer_create(name_);
GPU_framebuffer_texture_attach(framebuffer_, gputex, 0, 0);
+ has_pixels_ = true;
return framebuffer_;
}
diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh
index 2a480e71017..e786eaed38a 100644
--- a/source/blender/gpu/opengl/gl_texture.hh
+++ b/source/blender/gpu/opengl/gl_texture.hh
@@ -53,6 +53,8 @@ class GLTexture : public Texture {
/** True if this texture is bound to at least one texture unit. */
/* TODO(fclem): How do we ensure thread safety here? */
bool is_bound_ = false;
+ /** True if pixels in the texture have been initialized. */
+ bool has_pixels_ = false;
public:
GLTexture(const char *name);
@@ -61,32 +63,41 @@ class GLTexture : public Texture {
void update_sub(
int mip, int offset[3], int extent[3], eGPUDataFormat type, const void *data) override;
- void generate_mipmap(void) override;
+ /**
+ * This will create the mipmap images and populate them with filtered data from base level.
+ *
+ * \warning Depth textures are not populated but they have their mips correctly defined.
+ * \warning This resets the mipmap range.
+ */
+ void generate_mipmap() override;
void copy_to(Texture *dst) override;
void clear(eGPUDataFormat format, const void *data) override;
void swizzle_set(const char swizzle_mask[4]) override;
void mip_range_set(int min, int max) override;
void *read(int mip, eGPUDataFormat type) override;
- void check_feedback_loop(void);
+ void check_feedback_loop();
/* TODO(fclem): Legacy. Should be removed at some point. */
- uint gl_bindcode_get(void) const override;
+ uint gl_bindcode_get() const override;
- static void samplers_init(void);
- static void samplers_free(void);
- static void samplers_update(void);
+ static void samplers_init();
+ static void samplers_free();
+ static void samplers_update();
protected:
- bool init_internal(void) override;
+ /** Return true on success. */
+ bool init_internal() override;
+ /** Return true on success. */
bool init_internal(GPUVertBuf *vbo) override;
private:
bool proxy_check(int mip);
+ /** Will create enough mipmaps up to get to the given level. */
void ensure_mipmaps(int mip);
void update_sub_direct_state_access(
int mip, int offset[3], int extent[3], GLenum gl_format, GLenum gl_type, const void *data);
- GPUFrameBuffer *framebuffer_get(void);
+ GPUFrameBuffer *framebuffer_get();
MEM_CXX_CLASS_ALLOC_FUNCS("GLTexture")
};
@@ -292,7 +303,9 @@ inline GLenum to_gl(eGPUDataFormat format)
}
}
-/* Definitely not complete, edit according to the gl specification. */
+/**
+ * Definitely not complete, edit according to the OpenGL specification.
+ */
inline GLenum to_gl_data_format(eGPUTextureFormat format)
{
/* You can add any of the available type to this list
@@ -364,7 +377,9 @@ inline GLenum to_gl_data_format(eGPUTextureFormat format)
}
}
-/* Assume Unorm / Float target. Used with glReadPixels. */
+/**
+ * Assume Unorm / Float target. Used with #glReadPixels.
+ */
inline GLenum channel_len_to_gl(int channel_len)
{
switch (channel_len) {
diff --git a/source/blender/gpu/opengl/gl_uniform_buffer.hh b/source/blender/gpu/opengl/gl_uniform_buffer.hh
index 6cc525a2b7a..d7b9982dfb8 100644
--- a/source/blender/gpu/opengl/gl_uniform_buffer.hh
+++ b/source/blender/gpu/opengl/gl_uniform_buffer.hh
@@ -48,10 +48,10 @@ class GLUniformBuf : public UniformBuf {
void update(const void *data) override;
void bind(int slot) override;
- void unbind(void) override;
+ void unbind() override;
private:
- void init(void);
+ void init();
MEM_CXX_CLASS_ALLOC_FUNCS("GLUniformBuf");
};
diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc
index e324916b934..282ede5ba9b 100644
--- a/source/blender/gpu/opengl/gl_vertex_array.cc
+++ b/source/blender/gpu/opengl/gl_vertex_array.cc
@@ -108,7 +108,6 @@ static uint16_t vbo_bind(const ShaderInterface *interface,
return enabled_attrib;
}
-/* Update the Attribute Binding of the currently bound VAO. */
void GLVertArray::update_bindings(const GLuint vao,
const GPUBatch *batch_, /* Should be GLBatch. */
const ShaderInterface *interface,
@@ -156,7 +155,6 @@ void GLVertArray::update_bindings(const GLuint vao,
}
}
-/* Another version of update_bindings for Immediate mode. */
void GLVertArray::update_bindings(const GLuint vao,
const uint v_first,
const GPUVertFormat *format,
diff --git a/source/blender/gpu/opengl/gl_vertex_array.hh b/source/blender/gpu/opengl/gl_vertex_array.hh
index 7037986e31e..b8edbf3a691 100644
--- a/source/blender/gpu/opengl/gl_vertex_array.hh
+++ b/source/blender/gpu/opengl/gl_vertex_array.hh
@@ -33,13 +33,19 @@ namespace gpu {
namespace GLVertArray {
+/**
+ * Update the Attribute Binding of the currently bound VAO.
+ */
void update_bindings(const GLuint vao,
const GPUBatch *batch,
const ShaderInterface *interface,
- const int base_instance);
+ int base_instance);
+/**
+ * Another version of update_bindings for Immediate mode.
+ */
void update_bindings(const GLuint vao,
- const uint v_first,
+ uint v_first,
const GPUVertFormat *format,
const ShaderInterface *interface);
diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.cc b/source/blender/gpu/opengl/gl_vertex_buffer.cc
index ce16a491528..469ac2cf8d6 100644
--- a/source/blender/gpu/opengl/gl_vertex_buffer.cc
+++ b/source/blender/gpu/opengl/gl_vertex_buffer.cc
@@ -49,6 +49,10 @@ void GLVertBuf::resize_data()
void GLVertBuf::release_data()
{
+ if (is_wrapper_) {
+ return;
+ }
+
if (vbo_id_ != 0) {
GLContext::buf_free(vbo_id_);
vbo_id_ = 0;
@@ -137,6 +141,16 @@ void *GLVertBuf::unmap(const void *mapped_data) const
return result;
}
+void GLVertBuf::wrap_handle(uint64_t handle)
+{
+ BLI_assert(vbo_id_ == 0);
+ BLI_assert(glIsBuffer(static_cast<uint>(handle)));
+ is_wrapper_ = true;
+ vbo_id_ = static_cast<uint>(handle);
+ /* We assume the data is already on the device, so no need to allocate or send it. */
+ flag = GPU_VERTBUF_DATA_UPLOADED;
+}
+
bool GLVertBuf::is_active() const
{
if (!vbo_id_) {
@@ -147,7 +161,7 @@ bool GLVertBuf::is_active() const
return vbo_id_ == active_vbo_id;
}
-void GLVertBuf::update_sub(uint start, uint len, void *data)
+void GLVertBuf::update_sub(uint start, uint len, const void *data)
{
glBufferSubData(GL_ARRAY_BUFFER, start, len, data);
}
diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.hh b/source/blender/gpu/opengl/gl_vertex_buffer.hh
index 6c38a2225b3..d347b6d56ca 100644
--- a/source/blender/gpu/opengl/gl_vertex_buffer.hh
+++ b/source/blender/gpu/opengl/gl_vertex_buffer.hh
@@ -39,22 +39,27 @@ class GLVertBuf : public VertBuf {
private:
/** OpenGL buffer handle. Init on first upload. Immutable after that. */
GLuint vbo_id_ = 0;
+ /** Defines whether the buffer handle is wrapped by this GLVertBuf, i.e. we do not own it and
+ * should not free it. */
+ bool is_wrapper_ = false;
/** Size on the GPU. */
size_t vbo_size_ = 0;
public:
- void bind(void);
+ void bind();
- void update_sub(uint start, uint len, void *data) override;
+ void update_sub(uint start, uint len, const void *data) override;
const void *read() const override;
void *unmap(const void *mapped_data) const override;
+ void wrap_handle(uint64_t handle) override;
+
protected:
- void acquire_data(void) override;
- void resize_data(void) override;
- void release_data(void) override;
- void upload_data(void) override;
+ void acquire_data() override;
+ void resize_data() override;
+ void release_data() override;
+ void upload_data() override;
void duplicate_data(VertBuf *dst) override;
void bind_as_ssbo(uint binding) override;
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_frag.glsl
index 5a36b414229..4ebcb9c397f 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_frag.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec4 color;
uniform float scale;
in vec2 uv;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl
index d20ddcd27c0..c6f01d68eee 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl
@@ -1,4 +1,4 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform vec4 rect;
@@ -8,6 +8,7 @@ uniform float scale;
in vec2 pos;
out vec2 uv;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_frag.glsl
deleted file mode 100644
index 108fc85c4a5..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_frag.glsl
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-uniform float dashWidth;
-
-#ifdef SMOOTH_COLOR
-noperspective in vec4 finalColor;
-#else
-flat in vec4 finalColor;
-#endif
-
-noperspective in vec2 stipple_pos;
-flat in vec2 stipple_start;
-
-out vec4 fragColor;
-
-void main()
-{
- fragColor = finalColor;
-
- /* Avoid passing viewport size */
- vec2 dd = fwidth(stipple_pos);
-
- float dist = distance(stipple_start, stipple_pos) / max(dd.x, dd.y);
-
- if (fract(dist / dashWidth) > 0.5) {
- fragColor.rgb = vec3(0.0);
- }
-
- fragColor = blender_srgb_to_framebuffer_space(fragColor);
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl
deleted file mode 100644
index 69fe5c93a61..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl
+++ /dev/null
@@ -1,38 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec4 edgeColor;
-uniform vec4 selectColor;
-
-in vec2 pos;
-in int flag;
-
-#ifdef SMOOTH_COLOR
-noperspective out vec4 finalColor;
-#else
-flat out vec4 finalColor;
-#endif
-
-noperspective out vec2 stipple_pos;
-flat out vec2 stipple_start;
-
-/* TODO: Port drawing to draw manager and
- * remove constants duplications. */
-#define VERT_UV_SELECT (1 << 3)
-#define EDGE_UV_SELECT (1 << 5)
-
-void main()
-{
-#ifdef SMOOTH_COLOR
- bool is_select = (flag & VERT_UV_SELECT) != 0;
-#else
- bool is_select = (flag & EDGE_UV_SELECT) != 0;
-#endif
-
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
- gl_Position.z = float(!is_select);
-
- /* Avoid precision loss. */
- stipple_start = stipple_pos = 500.0 + 500.0 * (gl_Position.xy / gl_Position.w);
-
- finalColor = (is_select) ? selectColor : edgeColor;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl
deleted file mode 100644
index 7a94fc088c4..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl
+++ /dev/null
@@ -1,19 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec4 vertColor;
-uniform vec4 selectColor;
-
-in vec2 pos;
-in int flag;
-
-out vec4 finalColor;
-
-/* TODO: Port drawing to draw manager and
- * remove constants duplications. */
-#define FACE_UV_SELECT (1 << 7)
-
-void main()
-{
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
- finalColor = ((flag & FACE_UV_SELECT) != 0) ? selectColor : vertColor;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl
deleted file mode 100644
index 6fc41271cf5..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl
+++ /dev/null
@@ -1,26 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec4 faceColor;
-uniform vec4 selectColor;
-uniform vec4 activeColor;
-
-in vec2 pos;
-in int flag;
-
-flat out vec4 finalColor;
-
-/* TODO: Port drawing to draw manager and
- * remove constants duplications. */
-#define FACE_UV_ACTIVE (1 << 6)
-#define FACE_UV_SELECT (1 << 7)
-
-void main()
-{
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
-
- bool is_selected = (flag & FACE_UV_SELECT) != 0;
- bool is_active = (flag & FACE_UV_ACTIVE) != 0;
-
- finalColor = (is_selected) ? selectColor : faceColor;
- finalColor = (is_active) ? activeColor : finalColor;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl
deleted file mode 100644
index bec565be1df..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl
+++ /dev/null
@@ -1,44 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec4 vertColor;
-uniform vec4 selectColor;
-uniform vec4 pinnedColor;
-uniform float pointSize;
-uniform float outlineWidth;
-
-in vec2 pos;
-in int flag;
-
-out vec4 fillColor;
-out vec4 outlineColor;
-out vec4 radii;
-
-/* TODO: Port drawing to draw manager and
- * remove constants duplications. */
-#define VERT_UV_SELECT (1 << 3)
-#define VERT_UV_PINNED (1 << 4)
-
-void main()
-{
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
- gl_PointSize = pointSize;
-
- bool is_selected = (flag & VERT_UV_SELECT) != 0;
- bool is_pinned = (flag & VERT_UV_PINNED) != 0;
-
- vec4 deselect_col = (is_pinned) ? pinnedColor : vertColor;
- fillColor = (is_selected) ? selectColor : deselect_col;
- outlineColor = (is_pinned) ? pinnedColor : vec4(fillColor.rgb, 0.0);
-
- /* Calculate concentric radii in pixels. */
- float radius = 0.5 * pointSize;
-
- /* Start at the outside and progress toward the center. */
- radii[0] = radius;
- radii[1] = radius - 1.0;
- radii[2] = radius - outlineWidth;
- radii[3] = radius - outlineWidth - 1.0;
-
- /* Convert to PointCoord units. */
- radii /= pointSize;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
deleted file mode 100644
index 3254a7e1508..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
+++ /dev/null
@@ -1,98 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec2 aspect;
-
-in vec2 pos;
-
-#ifdef STRETCH_ANGLE
-in vec2 uv_angles;
-in float angle;
-
-#else
-in float ratio;
-uniform float totalAreaRatio;
-uniform float totalAreaRatioInv;
-
-#endif
-
-noperspective out vec4 finalColor;
-
-vec3 weight_to_rgb(float weight)
-{
- vec3 r_rgb;
- float blend = ((weight / 2.0) + 0.5);
-
- if (weight <= 0.25) { /* blue->cyan */
- r_rgb[0] = 0.0;
- r_rgb[1] = blend * weight * 4.0;
- r_rgb[2] = blend;
- }
- else if (weight <= 0.50) { /* cyan->green */
- r_rgb[0] = 0.0;
- r_rgb[1] = blend;
- r_rgb[2] = blend * (1.0 - ((weight - 0.25) * 4.0));
- }
- else if (weight <= 0.75) { /* green->yellow */
- r_rgb[0] = blend * ((weight - 0.50) * 4.0);
- r_rgb[1] = blend;
- r_rgb[2] = 0.0;
- }
- else if (weight <= 1.0) { /* yellow->red */
- r_rgb[0] = blend;
- r_rgb[1] = blend * (1.0 - ((weight - 0.75) * 4.0));
- r_rgb[2] = 0.0;
- }
- else {
- /* exceptional value, unclamped or nan,
- * avoid uninitialized memory use */
- r_rgb[0] = 1.0;
- r_rgb[1] = 0.0;
- r_rgb[2] = 1.0;
- }
-
- return r_rgb;
-}
-
-#define M_PI 3.1415926535897932
-
-vec2 angle_to_v2(float angle)
-{
- return vec2(cos(angle), sin(angle));
-}
-
-/* Adapted from BLI_math_vector.h */
-float angle_normalized_v2v2(vec2 v1, vec2 v2)
-{
- v1 = normalize(v1 * aspect);
- v2 = normalize(v2 * aspect);
- /* this is the same as acos(dot_v3v3(v1, v2)), but more accurate */
- bool q = (dot(v1, v2) >= 0.0);
- vec2 v = (q) ? (v1 - v2) : (v1 + v2);
- float a = 2.0 * asin(length(v) / 2.0);
- return (q) ? a : M_PI - a;
-}
-
-float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio)
-{
- ratio *= (ratio > 0.0f) ? tot_ratio : -inv_tot_ratio;
- return (ratio > 1.0f) ? (1.0f / ratio) : ratio;
-}
-
-void main()
-{
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
-
-#ifdef STRETCH_ANGLE
- vec2 v1 = angle_to_v2(uv_angles.x * M_PI);
- vec2 v2 = angle_to_v2(uv_angles.y * M_PI);
- float uv_angle = angle_normalized_v2v2(v1, v2) / M_PI;
- float stretch = 1.0 - abs(uv_angle - angle);
- stretch = stretch;
- stretch = 1.0 - stretch * stretch;
-#else
- float stretch = 1.0 - area_ratio_to_stretch(ratio, totalAreaRatio, totalAreaRatioInv);
-
-#endif
-
- finalColor = vec4(weight_to_rgb(stretch), 1.0);
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl
index df2507c0dc9..494ef8d888e 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
in vec2 pos;
in vec4 color;
flat out vec4 finalColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
index bdc0d37a7ae..9851e08fe2e 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
@@ -4,7 +4,8 @@
*/
/* Same as ICON_DRAW_CACHE_SIZE */
-#define MAX_CALLS 16
+#ifndef USE_GPU_SHADER_CREATE_INFO
+# define MAX_CALLS 16
uniform vec4 calls_data[MAX_CALLS * 3];
@@ -12,12 +13,13 @@ out vec2 texCoord_interp;
flat out vec4 finalColor;
in vec2 pos;
+#endif
void main()
{
- vec4 rect = calls_data[gl_InstanceID * 3];
- vec4 tex = calls_data[gl_InstanceID * 3 + 1];
- finalColor = calls_data[gl_InstanceID * 3 + 2];
+ vec4 rect = multi_rect_data.calls_data[gl_InstanceID * 3];
+ vec4 tex = multi_rect_data.calls_data[gl_InstanceID * 3 + 1];
+ finalColor = multi_rect_data.calls_data[gl_InstanceID * 3 + 2];
/* Use pos to select the right swizzle (instead of gl_VertexID)
* in order to workaround an OSX driver bug. */
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl
index ab9c30505c2..d9a5aeeef46 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl
@@ -3,11 +3,13 @@
* does not need any vertex input (producing less call to immBegin/End)
*/
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform vec4 rect_icon;
uniform vec4 rect_geom;
out vec2 texCoord_interp;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl
index cdb066c9c52..0b5e3759dfb 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
/* Keep in sync with intern/opencolorio/gpu_shader_display_transform_vertex.glsl */
in vec2 texCoord;
in vec2 pos;
out vec2 texCoord_interp;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
index 44a9db76834..af9a24d1280 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
@@ -6,6 +6,8 @@
* Dashed is performed in screen space.
*/
+#ifndef USE_GPU_SHADER_CREATE_INFO
+
uniform float dash_width;
/* Simple mode, discarding non-dash parts (so no need for blending at all). */
@@ -13,7 +15,7 @@ uniform float dash_factor; /* if > 1.0, solid line. */
/* More advanced mode, allowing for complex, multi-colored patterns.
* Enabled when colors_len > 0. */
-/* Note: max number of steps/colors in pattern is 32! */
+/* NOTE: max number of steps/colors in pattern is 32! */
uniform int colors_len; /* Enabled if > 0, 1 for solid line. */
uniform vec4 colors[32];
@@ -23,6 +25,7 @@ noperspective in vec2 stipple_pos;
flat in vec2 stipple_start;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl
index 15362d020e4..9d52820188b 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl
@@ -5,7 +5,7 @@
*
* Dashed is performed in screen space.
*/
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform vec4 color;
@@ -18,6 +18,7 @@ flat out vec4 color_vert;
/* We leverage hardware interpolation to compute distance along the line. */
noperspective out vec2 stipple_pos; /* In screen space */
flat out vec2 stipple_start; /* In screen space */
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl
index 55d5d941290..c4d56579b18 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl
@@ -1,15 +1,18 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in float colorGradient;
in vec4 finalColor;
in float lineU;
flat in float lineLength;
flat in float dashFactor;
+flat in float dashAlpha;
flat in int isMainLine;
out vec4 fragColor;
+#endif
-#define DASH_WIDTH 20.0
+#define DASH_WIDTH 10.0
#define ANTIALIAS 1.0
+#define MINIMUM_ALPHA 0.5
void main()
{
@@ -28,13 +31,10 @@ void main()
float t = ANTIALIAS / DASH_WIDTH;
float slope = 1.0 / (2.0 * t);
- float alpha = min(1.0, max(0.0, slope * (normalized_distance_triangle - dashFactor + t)));
-
- if (alpha < 0.0) {
- discard;
- }
+ float unclamped_alpha = 1.0 - slope * (normalized_distance_triangle - dashFactor + t);
+ float alpha = max(dashAlpha, min(unclamped_alpha, 1.0));
- fragColor.a *= 1.0 - alpha;
+ fragColor.a *= alpha;
}
fragColor.a *= smoothstep(1.0, 0.1, abs(colorGradient));
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl
index 8f46c8eda4b..b83ea59a692 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl
@@ -4,53 +4,44 @@
#define MID_VERTEX 65
+#ifndef USE_GPU_SHADER_CREATE_INFO
+
/* u is position along the curve, defining the tangent space.
* v is "signed" distance (compressed to [0..1] range) from the pos in expand direction */
in vec2 uv;
in vec2 pos; /* verts position in the curve tangent space */
in vec2 expand;
-#ifdef USE_INSTANCE
+# ifdef USE_INSTANCE
/* Instance attrs. */
in vec2 P0;
in vec2 P1;
in vec2 P2;
in vec2 P3;
in ivec4 colid_doarrow;
+in vec4 start_color;
+in vec4 end_color;
in ivec2 domuted;
in float dim_factor;
in float thickness;
in float dash_factor;
+in float dash_alpha;
uniform vec4 colors[6];
-# define colStart colors[colid_doarrow[0]]
-# define colEnd colors[colid_doarrow[1]]
-# define colShadow colors[colid_doarrow[2]]
-# define doArrow (colid_doarrow[3] != 0)
-# define doMuted (domuted[0] != 0)
-
-#else
+# else
/* Single curve drawcall, use uniform. */
uniform vec2 bezierPts[4];
-# define P0 bezierPts[0]
-# define P1 bezierPts[1]
-# define P2 bezierPts[2]
-# define P3 bezierPts[3]
-
uniform vec4 colors[3];
uniform bool doArrow;
uniform bool doMuted;
uniform float dim_factor;
uniform float thickness;
uniform float dash_factor;
+uniform float dash_alpha;
-# define colShadow colors[0]
-# define colStart colors[1]
-# define colEnd colors[2]
-
-#endif
+# endif
uniform float expandSize;
uniform float arrowSize;
@@ -61,13 +52,47 @@ out vec4 finalColor;
out float lineU;
flat out float lineLength;
flat out float dashFactor;
+flat out float dashAlpha;
flat out int isMainLine;
+#endif
+
+#ifdef USE_INSTANCE
+# define colStart (colid_doarrow[0] < 3 ? start_color : node_link_data.colors[colid_doarrow[0]])
+# define colEnd (colid_doarrow[1] < 3 ? end_color : node_link_data.colors[colid_doarrow[1]])
+# define colShadow node_link_data.colors[colid_doarrow[2]]
+# define doArrow (colid_doarrow[3] != 0)
+# define doMuted (domuted[0] != 0)
+
+#else
+# define P0 node_link_data.bezierPts[0].xy
+# define P1 node_link_data.bezierPts[1].xy
+# define P2 node_link_data.bezierPts[2].xy
+# define P3 node_link_data.bezierPts[3].xy
+# define cols node_link_data.colors
+# define doArrow node_link_data.doArrow
+# define doMuted node_link_data.doMuted
+# define dim_factor node_link_data.dim_factor
+# define thickness node_link_data.thickness
+# define dash_factor node_link_data.dash_factor
+# define dash_alpha node_link_data.dash_alpha
+
+# define colShadow node_link_data.colors[0]
+# define colStart node_link_data.colors[1]
+# define colEnd node_link_data.colors[2]
+
+#endif
+
+/* Define where along the noodle the gradient will starts and ends.
+ * Use 0.25 instead of 0.35-0.65, because of a visual shift issue. */
+const float start_gradient_threshold = 0.25;
+const float end_gradient_threshold = 0.55;
void main(void)
{
/* Parameters for the dashed line. */
isMainLine = expand.y != 1.0 ? 0 : 1;
dashFactor = dash_factor;
+ dashAlpha = dash_alpha;
/* Approximate line length, no need for real bezier length calculation. */
lineLength = distance(P0, P3);
/* TODO: Incorrect U, this leads to non-uniform dash distribution. */
@@ -90,7 +115,7 @@ void main(void)
vec2 normal = tangent.yx * vec2(-1.0, 1.0);
/* Position vertex on the curve tangent space */
- point += (pos.x * tangent + pos.y * normal) * arrowSize;
+ point += (pos.x * tangent + pos.y * normal) * node_link_data.arrowSize;
gl_Position = ModelViewProjectionMatrix * vec4(point, 0.0, 1.0);
@@ -109,7 +134,16 @@ void main(void)
}
else {
/* Second pass */
- finalColor = mix(colStart, colEnd, uv.x);
+ if (uv.x < start_gradient_threshold) {
+ finalColor = colStart;
+ }
+ else if (uv.x > end_gradient_threshold) {
+ finalColor = colEnd;
+ }
+ else {
+ /* Add 0.1 to avoid a visual shift issue. */
+ finalColor = mix(colStart, colEnd, uv.x + 0.1);
+ }
expand_dist *= 0.5;
if (doMuted) {
finalColor[3] = 0.65;
@@ -119,7 +153,7 @@ void main(void)
finalColor[3] *= dim_factor;
/* Expand into a line */
- gl_Position.xy += exp_axis * expandSize * expand_dist * thickness;
+ gl_Position.xy += exp_axis * node_link_data.expandSize * expand_dist * thickness;
/* If the link is not muted or is not a reroute arrow the points are squashed to the center of
* the line. Magic numbers are defined in drawnode.c */
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl
index 1453393aa9f..f2b6aa1f12c 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl
@@ -1,9 +1,11 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform float size;
in vec2 pos;
out vec2 radii;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl
index 5c555b2d3e7..5d97fca1116 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform float size;
uniform float outlineWidth;
in vec2 pos;
out vec4 radii;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl
deleted file mode 100644
index 3eec271913a..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl
+++ /dev/null
@@ -1,28 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-uniform float size;
-uniform float outlineWidth;
-
-in vec2 pos;
-in vec4 color;
-out vec4 radii;
-out vec4 fillColor;
-
-void main()
-{
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
- gl_PointSize = size;
- fillColor = color;
-
- /* Calculate concentric radii in pixels. */
- float radius = 0.5 * size;
-
- /* Start at the outside and progress toward the center. */
- radii[0] = radius;
- radii[1] = radius - 1.0;
- radii[2] = radius - outlineWidth;
- radii[3] = radius - outlineWidth - 1.0;
-
- /* Convert to PointCoord units. */
- radii /= size;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl
index 469370b9173..6ba6f980406 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
in vec2 pos;
in float size;
in vec4 color;
out vec4 finalColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl
index 1333c00682c..4d887a37807 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl
@@ -1,6 +1,7 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
noperspective in vec4 finalColor;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl
index fcf436d50af..5d19aea9168 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
in vec2 pos;
in vec4 color;
noperspective out vec4 finalColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl
index de6547715f3..698f20ae1f9 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl
@@ -1,11 +1,13 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
-#ifdef UV_POS
+# ifdef UV_POS
in vec2 u;
-# define pos u
-#else
+# define pos u
+# else
in vec2 pos;
+# endif
#endif
void main()
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
index 6dd0201535d..a03b88db342 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
@@ -1,3 +1,4 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec3 checkerColorAndSize;
noperspective in vec2 uvInterp;
@@ -12,6 +13,7 @@ flat in vec4 embossColor;
flat in float lineWidth;
out vec4 fragColor;
+#endif
vec3 compute_masks(vec2 uv)
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
index b5036b51d9d..80b93baf20a 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
@@ -1,12 +1,13 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
-#define MAX_PARAM 12
-#ifdef USE_INSTANCE
-# define MAX_INSTANCE 6
+# define MAX_PARAM 12
+# ifdef USE_INSTANCE
+# define MAX_INSTANCE 6
uniform vec4 parameters[MAX_PARAM * MAX_INSTANCE];
-#else
+# else
uniform vec4 parameters[MAX_PARAM];
+# endif
#endif
/* gl_InstanceID is supposed to be 0 if not drawing instances, but this seems
@@ -41,6 +42,7 @@ uniform vec4 parameters[MAX_PARAM];
#define doAlphaCheck (alphaDiscard < 0.0)
#define discardFactor abs(alphaDiscard)
+#ifndef USE_GPU_SHADER_CREATE_INFO
noperspective out vec2 uvInterp;
flat out vec2 outRectSize;
flat out vec4 outRoundCorners;
@@ -51,8 +53,9 @@ flat out float lineWidth;
noperspective out float butCo;
flat out float discardFac;
-#ifdef OS_MAC
+# ifdef OS_MAC
in float dummy;
+# endif
#endif
vec2 do_widget(void)
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl
index e8a6a43191e..a624d3f2f8b 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl
@@ -1,9 +1,11 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
in float shadowFalloff;
out vec4 fragColor;
uniform float alpha;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl
index dc2849c8aa9..d3eed997292 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl
@@ -51,9 +51,12 @@ const vec2 cornervec[36] = vec2[36](vec2(0.0, 1.0),
#define INNER_FLAG uint(1 << 10) /* is inner vert */
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform vec4 parameters[4];
+#endif
+
/* radi and rad per corner */
#define recti parameters[0]
#define rect parameters[1]
@@ -61,9 +64,11 @@ uniform vec4 parameters[4];
#define rads parameters[2].y
#define roundCorners parameters[3]
+#ifndef USE_GPU_SHADER_CREATE_INFO
in uint vflag;
out float shadowFalloff;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl
index 16424ece2b6..1a87796f7c4 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl
@@ -1,9 +1,10 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform mat4 ModelMatrix;
uniform vec4 ClipPlane;
in vec3 pos;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl
index 5b6a890ccc8..b6132113bc9 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl
@@ -1,33 +1,24 @@
+#pragma BLENDER_REQUIRE(gpu_shader_cfg_world_clip_lib.glsl)
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
+# ifdef USE_WORLD_CLIP_PLANES
uniform mat4 ModelMatrix;
-#endif
+# endif
in vec3 pos;
-#if defined(USE_COLOR_U32)
-in uint color;
-#else
in vec4 color;
-#endif
flat out vec4 finalColor;
+#endif
void main()
{
vec4 pos_4d = vec4(pos, 1.0);
gl_Position = ModelViewProjectionMatrix * pos_4d;
-
-#if defined(USE_COLOR_U32)
- finalColor = vec4(((color)&uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 8) & uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 16) & uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 24)) * (1.0f / 255.0f));
-#else
finalColor = color;
-#endif
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance((clipPlanes.ModelMatrix * pos_4d).xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl
index 0fb8d06e317..908d442739a 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl
@@ -1,9 +1,11 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
in vec2 texCoord;
in vec3 pos;
out vec2 texCoord_interp;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl
index aefa47275f5..9328e0a13e9 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl
@@ -6,11 +6,13 @@
* Dashed is performed in screen space.
*/
+#ifndef USE_GPU_SHADER_CREATE_INFO
+
uniform mat4 ModelViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
+# ifdef USE_WORLD_CLIP_PLANES
uniform mat4 ModelMatrix;
-#endif
+# endif
uniform vec4 color;
uniform vec2 viewport_size;
@@ -22,6 +24,7 @@ flat out vec4 color_vert;
/* We leverage hardware interpolation to compute distance along the line. */
noperspective out vec2 stipple_pos; /* In screen space */
flat out vec2 stipple_start; /* In screen space */
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl
index 252fee87015..18fed69eff6 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform mat3 NormalMatrix;
in vec3 pos;
in vec3 nor;
out vec3 normal;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl
index 12594b04da9..52e9e71fdd8 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl
@@ -1,9 +1,11 @@
-#ifdef USE_WORLD_CLIP_PLANES
+#ifndef USE_GPU_SHADER_CREATE_INFO
+# ifdef USE_WORLD_CLIP_PLANES
uniform mat4 ModelMatrix;
-#endif
+# endif
/* Does Nothing */
in vec3 pos;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl
index 776656fc2df..504b3f75373 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl
@@ -1,9 +1,10 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
in vec3 pos;
in vec4 color;
out vec4 finalColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl
index 5d67658c639..7f143ccc28d 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl
@@ -1,12 +1,15 @@
+#pragma BLENDER_REQUIRE(gpu_shader_cfg_world_clip_lib.glsl)
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
+# ifdef USE_WORLD_CLIP_PLANES
uniform mat4 ModelMatrix;
-#endif
+# endif
uniform float size;
in vec3 pos;
out vec2 radii;
+#endif
void main()
{
@@ -25,6 +28,6 @@ void main()
radii /= size;
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance((clipPlanes.ModelMatrix * pos_4d).xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl
deleted file mode 100644
index fb5506a778d..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl
+++ /dev/null
@@ -1,33 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
-uniform mat4 ModelMatrix;
-#endif
-uniform float size;
-uniform float outlineWidth;
-
-in vec3 pos;
-out vec4 radii;
-
-void main()
-{
- vec4 pos_4d = vec4(pos, 1.0);
- gl_Position = ModelViewProjectionMatrix * pos_4d;
- gl_PointSize = size;
-
- /* calculate concentric radii in pixels */
- float radius = 0.5 * size;
-
- /* start at the outside and progress toward the center */
- radii[0] = radius;
- radii[1] = radius - 1.0;
- radii[2] = radius - outlineWidth;
- radii[3] = radius - outlineWidth - 1.0;
-
- /* convert to PointCoord units */
- radii /= size;
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz);
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl
index 3bc72535266..f048e143da7 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
in vec3 pos;
in float size;
in vec4 color;
out vec4 finalColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl
deleted file mode 100644
index fc61be936fe..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl
+++ /dev/null
@@ -1,11 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-
-in vec3 pos;
-in float size;
-
-void main()
-{
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
- gl_PointSize = size;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl
index 3ea8f7dbfbe..8687763f4c1 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl
@@ -1,14 +1,15 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform float lineWidth;
uniform bool lineSmooth = true;
in vec4 finalColor;
noperspective in float smoothline;
-#ifdef CLIP
+# ifdef CLIP
in float clip;
-#endif
+# endif
out vec4 fragColor;
+#endif
#define SMOOTH_WIDTH 1.0
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl
index 70026398937..627e91af4d6 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl
@@ -1,4 +1,4 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
layout(lines) in;
layout(triangle_strip, max_vertices = 4) out;
@@ -7,17 +7,18 @@ uniform vec2 viewportSize;
uniform float lineWidth;
uniform bool lineSmooth = true;
-#if !defined(UNIFORM)
+# if !defined(UNIFORM)
in vec4 finalColor_g[];
-#endif
+# endif
-#ifdef CLIP
+# ifdef CLIP
in float clip_g[];
out float clip;
-#endif
+# endif
out vec4 finalColor;
noperspective out float smoothline;
+#endif
#define SMOOTH_WIDTH 1.0
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl
index 28aa2a4ccc6..5c673494870 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl
@@ -1,18 +1,19 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform mat4 ModelMatrix;
uniform vec4 ClipPlane;
in vec3 pos;
-#if !defined(UNIFORM)
+# if !defined(UNIFORM)
in vec4 color;
out vec4 finalColor_g;
-#endif
+# endif
-#ifdef CLIP
+# ifdef CLIP
out float clip_g;
+# endif
#endif
void main()
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl
index 3a2d96c9929..de555cc5706 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl
@@ -1,6 +1,7 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec4 finalColor;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl
index 4eafb7b7be3..56a1210c957 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl
@@ -1,14 +1,17 @@
+#pragma BLENDER_REQUIRE(gpu_shader_cfg_world_clip_lib.glsl)
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
+# ifdef USE_WORLD_CLIP_PLANES
uniform mat4 ModelMatrix;
-#endif
+# endif
in vec3 pos;
in vec4 color;
out vec4 finalColor;
+#endif
void main()
{
@@ -16,6 +19,6 @@ void main()
finalColor = color;
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz);
+ world_clip_planes_calc_clip_distance((clipPlanes.ModelMatrix * vec4(pos, 1.0)).xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl
index 70bb881ffea..1d7b7df49a8 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl
@@ -1,17 +1,20 @@
+#pragma BLENDER_REQUIRE(gpu_shader_cfg_world_clip_lib.glsl)
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
+# ifdef USE_WORLD_CLIP_PLANES
uniform mat4 ModelMatrix;
-#endif
+# endif
in vec3 pos;
+#endif
void main()
{
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz);
+ world_clip_planes_calc_clip_distance((clipPlanes.ModelMatrix * vec4(pos, 1.0)).xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl b/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl
index 46cf2fe09a2..cdc716db7a4 100644
--- a/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl
@@ -1,7 +1,9 @@
#ifdef USE_WORLD_CLIP_PLANES
# if defined(GPU_VERTEX_SHADER) || defined(GPU_GEOMETRY_SHADER)
+# ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec4 WorldClipPlanes[6];
+# endif
# define _world_clip_planes_calc_clip_distance(wpos, _clipplanes) \
{ \
@@ -14,6 +16,10 @@ uniform vec4 WorldClipPlanes[6];
gl_ClipDistance[5] = dot(_clipplanes[5], pos); \
}
+/* When all shaders are builtin shaders are migrated this could be applied directly. */
+# ifdef USE_GPU_SHADER_CREATE_INFO
+# define WorldClipPlanes clipPlanes.world
+# endif
/* HACK Dirty hack to be able to override the definition in common_view_lib.glsl.
* Not doing this would require changing the include order in every shaders. */
# define world_clip_planes_calc_clip_distance(wpos) \
diff --git a/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl b/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl
index 156b6cb75ab..9065da0275a 100644
--- a/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl
@@ -1,9 +1,10 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec4 color1;
uniform vec4 color2;
uniform int size;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl b/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl
index aae659516bb..74341701fb0 100644
--- a/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl
@@ -2,7 +2,9 @@
/* Undefine the macro that avoids compilation errors. */
#undef blender_srgb_to_framebuffer_space
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform bool srgbTarget = false;
+#endif
vec4 blender_srgb_to_framebuffer_space(vec4 color)
{
diff --git a/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl b/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl
index 48979af4ad0..a4a24ed8e46 100644
--- a/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec4 color1;
uniform vec4 color2;
uniform int size1;
uniform int size2;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl
index 6f7d68856d5..d3d4b66589b 100644
--- a/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl
@@ -1,6 +1,7 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
flat in vec4 finalColor;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl
index 99d8b6ab685..1675de3d567 100644
--- a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl
@@ -1,6 +1,7 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
flat in vec4 finalColor;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl
index 8e1287c483a..2aabdb84f16 100644
--- a/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl
@@ -1,6 +1,7 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
flat in uint finalId;
out uint fragId;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
index 3b4e2e17ccc..4fdc14289e1 100644
--- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
@@ -1,4 +1,4 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ProjectionMatrix;
uniform int PrimitiveIdBase;
@@ -19,6 +19,7 @@ out vec3 varposition;
uniform bool osd_flat_shading;
uniform int osd_fvar_count;
+#endif
#define INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord) \
{ \
@@ -38,8 +39,10 @@ uniform int osd_fvar_count;
result = vec3(tmp, 0); \
}
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform samplerBuffer FVarDataBuffer;
uniform isamplerBuffer FVarDataOffsetBuffer;
+#endif
out block
{
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl
index fc3f47c0aaa..37541bb91f3 100644
--- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl
@@ -1,16 +1,18 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec4 mColor;
in vec2 mTexCoord;
out vec4 fragColor;
+#endif
void main()
{
const vec2 center = vec2(0, 0.5);
- vec4 tColor = vec4(mColor);
+ vec4 tColor = vec4(geometry_out.mColor);
/* if alpha < 0, then encap */
- if (mColor.a < 0) {
+ if (geometry_out.mColor.a < 0) {
tColor.a = tColor.a * -1.0;
- float dist = length(mTexCoord - center);
+ float dist = length(geometry_out.mTexCoord - center);
if (dist > 0.25) {
discard;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl
index b937323f62a..f076655b459 100644
--- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl
@@ -1,3 +1,4 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform vec2 Viewport;
uniform int xraymode;
@@ -13,6 +14,7 @@ in float finalThickness[4];
out vec4 mColor;
out vec2 mTexCoord;
+#endif
#define GP_XRAY_FRONT 0
#define GP_XRAY_3DSPACE 1
@@ -23,19 +25,19 @@ out vec2 mTexCoord;
/* project 3d point to 2d on screen space */
vec2 toScreenSpace(vec4 vertex)
{
- return vec2(vertex.xy / vertex.w) * Viewport;
+ return vec2(vertex.xy / vertex.w) * gpencil_stroke_data.viewport;
}
/* get zdepth value */
float getZdepth(vec4 point)
{
- if (xraymode == GP_XRAY_FRONT) {
+ if (gpencil_stroke_data.xraymode == GP_XRAY_FRONT) {
return 0.0;
}
- if (xraymode == GP_XRAY_3DSPACE) {
+ if (gpencil_stroke_data.xraymode == GP_XRAY_3DSPACE) {
return (point.z / point.w);
}
- if (xraymode == GP_XRAY_BACK) {
+ if (gpencil_stroke_data.xraymode == GP_XRAY_BACK) {
return 1.0;
}
@@ -75,7 +77,7 @@ void main(void)
vec2 sp3 = toScreenSpace(P3); /* end of next segment */
/* culling outside viewport */
- vec2 area = Viewport * 4.0;
+ vec2 area = gpencil_stroke_data.viewport * 4.0;
if (sp1.x < -area.x || sp1.x > area.x) {
return;
}
@@ -112,8 +114,8 @@ void main(void)
if (bn1 == 0) {
bn1 = 1;
}
- float length_a = finalThickness[1] / an1;
- float length_b = finalThickness[2] / bn1;
+ float length_a = geometry_in[1].finalThickness / an1;
+ float length_b = geometry_in[2].finalThickness / bn1;
if (length_a <= 0.0) {
length_a = 0.01;
}
@@ -124,41 +126,49 @@ void main(void)
/* prevent excessively long miters at sharp corners */
if (dot(v0, v1) < -MiterLimit) {
miter_a = n1;
- length_a = finalThickness[1];
+ length_a = geometry_in[1].finalThickness;
/* close the gap */
if (dot(v0, n1) > 0) {
- mTexCoord = vec2(0, 0);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 + finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4((sp1 + geometry_in[1].finalThickness * n0) / gpencil_stroke_data.viewport,
+ getZdepth(P1),
+ 1.0);
EmitVertex();
- mTexCoord = vec2(0, 0);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 + finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4((sp1 + geometry_in[1].finalThickness * n1) / gpencil_stroke_data.viewport,
+ getZdepth(P1),
+ 1.0);
EmitVertex();
- mTexCoord = vec2(0, 0.5);
- mColor = finalColor[1];
- gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0.5);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
EmitVertex();
EndPrimitive();
}
else {
- mTexCoord = vec2(0, 1);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 - finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 1);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4((sp1 - geometry_in[1].finalThickness * n1) / gpencil_stroke_data.viewport,
+ getZdepth(P1),
+ 1.0);
EmitVertex();
- mTexCoord = vec2(0, 1);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 - finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 1);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4((sp1 - geometry_in[1].finalThickness * n0) / gpencil_stroke_data.viewport,
+ getZdepth(P1),
+ 1.0);
EmitVertex();
- mTexCoord = vec2(0, 0.5);
- mColor = finalColor[1];
- gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0.5);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
EmitVertex();
EndPrimitive();
@@ -167,66 +177,74 @@ void main(void)
if (dot(v1, v2) < -MiterLimit) {
miter_b = n1;
- length_b = finalThickness[2];
+ length_b = geometry_in[2].finalThickness;
}
/* Generate the start end-cap (alpha < 0 used as end-cap flag). */
- float extend = (fill_stroke > 0) ? 2 : 1;
- if ((caps_start != GPENCIL_FLATCAP) && is_equal(P0, P2)) {
- mTexCoord = vec2(1, 0.5);
- mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0);
+ float extend = gpencil_stroke_data.fill_stroke ? 2 : 1;
+ if ((gpencil_stroke_data.caps_start != GPENCIL_FLATCAP) && is_equal(P0, P2)) {
+ geometry_out.mTexCoord = vec2(1, 0.5);
+ geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0);
vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0 * extend;
- gl_Position = vec4((sp1 + svn1) / Viewport, getZdepth(P1), 1.0);
+ gl_Position = vec4((sp1 + svn1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
EmitVertex();
- mTexCoord = vec2(0, 0);
- mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0);
- gl_Position = vec4((sp1 - (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0);
+ geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0);
+ gl_Position = vec4(
+ (sp1 - (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
EmitVertex();
- mTexCoord = vec2(0, 1);
- mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0);
- gl_Position = vec4((sp1 + (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 1);
+ geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0);
+ gl_Position = vec4(
+ (sp1 + (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
EmitVertex();
}
/* generate the triangle strip */
- mTexCoord = vec2(0, 0);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 + length_a * miter_a) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4(
+ (sp1 + length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
EmitVertex();
- mTexCoord = vec2(0, 1);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 - length_a * miter_a) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 1);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4(
+ (sp1 - length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
EmitVertex();
- mTexCoord = vec2(0, 0);
- mColor = finalColor[2];
- gl_Position = vec4((sp2 + length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0);
+ geometry_out.mColor = geometry_in[2].finalColor;
+ gl_Position = vec4(
+ (sp2 + length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
EmitVertex();
- mTexCoord = vec2(0, 1);
- mColor = finalColor[2];
- gl_Position = vec4((sp2 - length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
+ geometry_out.mTexCoord = vec2(0, 1);
+ geometry_out.mColor = geometry_in[2].finalColor;
+ gl_Position = vec4(
+ (sp2 - length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
EmitVertex();
/* Generate the end end-cap (alpha < 0 used as end-cap flag). */
- if ((caps_end != GPENCIL_FLATCAP) && is_equal(P1, P3)) {
- mTexCoord = vec2(0, 1);
- mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0);
- gl_Position = vec4((sp2 + (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
+ if ((gpencil_stroke_data.caps_end != GPENCIL_FLATCAP) && is_equal(P1, P3)) {
+ geometry_out.mTexCoord = vec2(0, 1);
+ geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0);
+ gl_Position = vec4(
+ (sp2 + (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
EmitVertex();
- mTexCoord = vec2(0, 0);
- mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0);
- gl_Position = vec4((sp2 - (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0);
+ geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0);
+ gl_Position = vec4(
+ (sp2 - (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
EmitVertex();
- mTexCoord = vec2(1, 0.5);
- mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0);
+ geometry_out.mTexCoord = vec2(1, 0.5);
+ geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0);
vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0 * extend;
- gl_Position = vec4((sp2 + svn2) / Viewport, getZdepth(P2), 1.0);
+ gl_Position = vec4((sp2 + svn2) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
EmitVertex();
}
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl
index 07b4ae52110..16e12b2989e 100644
--- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl
@@ -1,3 +1,4 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform mat4 ProjectionMatrix;
@@ -12,22 +13,21 @@ in float thickness;
out vec4 finalColor;
out float finalThickness;
+#endif
-#define TRUE 1
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
+float defaultpixsize = gpencil_stroke_data.pixsize * (1000.0 / gpencil_stroke_data.pixfactor);
void main(void)
{
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
- finalColor = color;
+ geometry_in.finalColor = color;
- if (keep_size == TRUE) {
- finalThickness = thickness;
+ if (gpencil_stroke_data.keep_size) {
+ geometry_in.finalThickness = thickness;
}
else {
float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) :
(thickness / defaultpixsize);
- finalThickness = max(size * objscale, 1.0);
+ geometry_in.finalThickness = max(size * gpencil_stroke_data.objscale, 1.0);
}
}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl
index 6dc7a1618e1..1846dae346a 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl
@@ -1,9 +1,10 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec2 texCoord_interp;
out vec4 fragColor;
uniform vec4 color;
uniform sampler2D image;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl
index dfbaaeda7b5..ad52b9819ab 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform float factor;
in vec2 texCoord_interp;
out vec4 fragColor;
uniform vec4 color;
uniform sampler2D image;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_image_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_frag.glsl
index aff6ddf01bf..befd6b57bf8 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_frag.glsl
@@ -1,8 +1,9 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec2 texCoord_interp;
out vec4 fragColor;
uniform sampler2D image;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl
new file mode 100644
index 00000000000..ceebaae896d
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl
@@ -0,0 +1,14 @@
+
+#ifndef USE_GPU_SHADER_CREATE_INFO
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform float alpha;
+uniform sampler2D image;
+#endif
+
+void main()
+{
+ fragColor = texture(image, texCoord_interp);
+ fragColor.a *= alpha;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl
index 7f3fe2f5252..2314dbbc5d5 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl
@@ -1,6 +1,7 @@
/* Merge overlays texture on top of image texture and transform to display space (assume sRGB) */
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform sampler2D image_texture;
uniform sampler2D overlays_texture;
uniform bool display_transform;
@@ -9,6 +10,7 @@ uniform bool overlay;
in vec2 texCoord_interp;
out vec4 fragColor;
+#endif
float linearrgb_to_srgb(float c)
{
diff --git a/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
index c6e9860d940..9b1e6fe9d23 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
@@ -7,18 +7,20 @@
/* Composite stereo textures */
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform sampler2D imageTexture;
uniform sampler2D overlayTexture;
uniform int stereoDisplaySettings;
+layout(location = 0) out vec4 imageColor;
+layout(location = 1) out vec4 overlayColor;
+#endif
+
#define stereo_display_mode (stereoDisplaySettings & ((1 << 3) - 1))
#define stereo_interlace_mode ((stereoDisplaySettings >> 3) & ((1 << 3) - 1))
#define stereo_interlace_swap bool(stereoDisplaySettings >> 6)
-layout(location = 0) out vec4 imageColor;
-layout(location = 1) out vec4 overlayColor;
-
bool interlace(ivec2 texel)
{
int interlace_mode = stereo_interlace_mode;
diff --git a/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl
index ed69184ef14..e8bfb70b897 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl
@@ -1,15 +1,16 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec2 texCoord_interp;
out vec4 fragColor;
uniform sampler2D image;
uniform vec4 color;
uniform vec4 shuffle;
+#endif
void main()
{
- vec4 sample = texture(image, texCoord_interp);
- fragColor = vec4(sample.r * shuffle.r + sample.g * shuffle.g + sample.b * shuffle.b +
- sample.a * shuffle.a) *
+ vec4 sampled_color = texture(image, texCoord_interp);
+ fragColor = vec4(sampled_color.r * shuffle.r + sampled_color.g * shuffle.g +
+ sampled_color.b * shuffle.b + sampled_color.a * shuffle.a) *
color;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl
index becf0fbd133..3058f73ab37 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl
@@ -1,9 +1,10 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec2 texCoord_interp;
flat in vec4 finalColor;
out vec4 fragColor;
uniform sampler2D image;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
index 10228a1e985..14450037ca8 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
@@ -1,4 +1,4 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ViewProjectionMatrix;
/* ---- Instantiated Attrs ---- */
@@ -7,13 +7,14 @@ in vec3 pos;
/* ---- Per instance Attrs ---- */
in mat4 InstanceModelMatrix;
in vec4 color;
-#ifdef UNIFORM_SCALE
+# ifdef UNIFORM_SCALE
in float size;
-#else
+# else
in vec3 size;
-#endif
+# endif
flat out vec4 finalColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_frag.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_frag.glsl
index a3b61dca8b4..2a2eaab7340 100644
--- a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_frag.glsl
@@ -11,6 +11,7 @@
#define GPU_KEYFRAME_SHAPE_SQUARE \
(GPU_KEYFRAME_SHAPE_CLIPPED_VERTICAL | GPU_KEYFRAME_SHAPE_CLIPPED_HORIZONTAL)
+#ifndef USE_GPU_SHADER_CREATE_INFO
flat in vec4 radii;
flat in vec4 thresholds;
@@ -20,6 +21,7 @@ flat in vec4 finalOutlineColor;
flat in int finalFlags;
out vec4 fragColor;
+#endif
const float diagonal_scale = sqrt(0.5);
diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl
index 18e8b76ba23..4ef3ff1a8d0 100644
--- a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl
@@ -11,15 +11,16 @@
#define GPU_KEYFRAME_SHAPE_SQUARE \
(GPU_KEYFRAME_SHAPE_CLIPPED_VERTICAL | GPU_KEYFRAME_SHAPE_CLIPPED_HORIZONTAL)
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec2 ViewportSize = vec2(-1, -1);
-uniform float outline_scale = 1.0;
-
const float line_falloff = 1.0;
const float circle_scale = sqrt(2.0 / 3.1416);
const float square_scale = sqrt(0.5);
const float diagonal_scale = sqrt(0.5);
+#ifndef USE_GPU_SHADER_CREATE_INFO
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 ViewportSize = vec2(-1, -1);
+uniform float outline_scale = 1.0;
+
in vec2 pos;
in float size;
in vec4 color;
@@ -33,6 +34,7 @@ flat out int finalFlags;
flat out vec4 radii;
flat out vec4 thresholds;
+#endif
bool test(int bit)
{
diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl
index 52d59d2030f..960b5e6efac 100644
--- a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl
@@ -1,8 +1,9 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec4 color;
in vec2 radii;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl
deleted file mode 100644
index 692320bea93..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl
+++ /dev/null
@@ -1,18 +0,0 @@
-
-uniform vec4 color;
-
-out vec4 fragColor;
-
-void main()
-{
- vec2 centered = gl_PointCoord - vec2(0.5);
- float dist_squared = dot(centered, centered);
- const float rad_squared = 0.25;
-
- // round point with jaggy edges
- if (dist_squared > rad_squared) {
- discard;
- }
-
- fragColor = color;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl
index 2ece73b3845..cdf3aa8024d 100644
--- a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl
@@ -1,9 +1,10 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec4 color;
uniform vec4 outlineColor;
in vec4 radii;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl
index 86c0e5c950a..23e9f9bc20f 100644
--- a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl
@@ -1,6 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec4 finalColor;
out vec4 fragColor;
+#endif
+
+#if defined(VERT)
+in float vertexCrease;
+#endif
void main()
{
@@ -13,5 +18,14 @@ void main()
discard;
}
+#if defined(VERT)
+ fragColor = finalColor;
+
+ float midStroke = 0.5 * rad_squared;
+ if (vertexCrease > 0.0 && dist_squared > midStroke) {
+ fragColor.rgb = mix(finalColor.rgb, colorEdgeCrease.rgb, vertexCrease);
+ }
+#else
fragColor = finalColor;
+#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl
deleted file mode 100644
index 1d936e4e072..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl
+++ /dev/null
@@ -1,33 +0,0 @@
-
-uniform vec4 outlineColor;
-
-in vec4 radii;
-in vec4 fillColor;
-out vec4 fragColor;
-
-void main()
-{
- float dist = length(gl_PointCoord - vec2(0.5));
-
- /* transparent outside of point
- * --- 0 ---
- * smooth transition
- * --- 1 ---
- * pure outline color
- * --- 2 ---
- * smooth transition
- * --- 3 ---
- * pure fill color
- * ...
- * dist = 0 at center of point */
-
- float midStroke = 0.5 * (radii[1] + radii[2]);
-
- if (dist > midStroke) {
- fragColor.rgb = outlineColor.rgb;
- fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist));
- }
- else {
- fragColor = mix(fillColor, outlineColor, smoothstep(radii[3], radii[2], dist));
- }
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl
index c9bd9e881bf..04a7e3d80d0 100644
--- a/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl
@@ -1,8 +1,9 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec4 radii;
in vec4 fillColor;
in vec4 outlineColor;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl
index 6bce517fee3..6725bc82841 100644
--- a/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl
@@ -1,18 +1,19 @@
-
-#ifndef USE_INSTANCE_COLOR
+#ifndef USE_GPU_SHADER_CREATE_INFO
+# ifndef USE_INSTANCE_COLOR
uniform vec4 color;
-#endif
+# endif
uniform vec3 light;
in vec3 normal;
-#ifdef USE_INSTANCE_COLOR
+# ifdef USE_INSTANCE_COLOR
flat in vec4 finalColor;
-# define color finalColor
-#endif
+# define color finalColor
+# endif
out vec4 fragColor;
+#endif
void main()
{
- fragColor = color;
- fragColor.xyz *= clamp(dot(normalize(normal), light), 0.0, 1.0);
+ fragColor = simple_lighting_data.color;
+ fragColor.xyz *= clamp(dot(normalize(normal), simple_lighting_data.light), 0.0, 1.0);
}
diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
index 2568cd74445..1456bd0c732 100644
--- a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
@@ -1,4 +1,4 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
flat in vec4 color_flat;
noperspective in vec2 texCoord_interp;
flat in int glyph_offset;
@@ -8,6 +8,7 @@ flat in int interp_size;
out vec4 fragColor;
uniform sampler2D glyph;
+#endif
const vec2 offsets4[4] = vec2[4](
vec2(-0.5, 0.5), vec2(0.5, 0.5), vec2(-0.5, -0.5), vec2(-0.5, -0.5));
diff --git a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
index 768638e5229..5b01fea5266 100644
--- a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
@@ -1,4 +1,4 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
in vec4 pos; /* rect */
@@ -11,6 +11,7 @@ noperspective out vec2 texCoord_interp;
flat out int glyph_offset;
flat out ivec2 glyph_dim;
flat out int interp_size;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
index 2033401db67..b4a75cc489b 100644
--- a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
@@ -1,21 +1,10 @@
-#if defined(USE_COLOR_U32)
-uniform uint color;
-#else
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec4 color;
-#endif
-
out vec4 fragColor;
+#endif
void main()
{
-#if defined(USE_COLOR_U32)
- fragColor = vec4(((color)&uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 8) & uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 16) & uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 24)) * (1.0f / 255.0f));
-#else
- fragColor = color;
-#endif
- fragColor = blender_srgb_to_framebuffer_space(fragColor);
+ fragColor = blender_srgb_to_framebuffer_space(color);
}
diff --git a/source/blender/editors/space_node/node_toolbar.cc b/source/blender/gpu/shaders/infos/gpu_clip_planes_info.hh
index 2e7d6ab6cd5..81b3c523628 100644
--- a/source/blender/editors/space_node/node_toolbar.cc
+++ b/source/blender/gpu/shaders/infos/gpu_clip_planes_info.hh
@@ -13,27 +13,17 @@
* 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) 2012 Blender Foundation.
+ * The Original Code is Copyright (C) 2022 Blender Foundation.
* All rights reserved.
*/
/** \file
- * \ingroup nodes
+ * \ingroup gpu
*/
-#include "BLI_utildefines.h"
+#include "gpu_shader_create_info.hh"
-#include "DNA_node_types.h"
-
-#include "BKE_context.h"
-#include "BKE_screen.h"
-
-#include "WM_api.h"
-
-#include "node_intern.h" /* own include */
-
-/* ******************* node toolbar registration ************** */
-
-void node_toolbar_register(ARegionType *UNUSED(art))
-{
-}
+GPU_SHADER_CREATE_INFO(gpu_clip_planes)
+ .uniform_buf(1, "GPUClipPlanes", "clipPlanes", Frequency::PASS)
+ .typedef_source("GPU_shader_shared.h")
+ .define("USE_WORLD_CLIP_PLANES");
diff --git a/source/blender/gpu/shaders/infos/gpu_interface_info.hh b/source/blender/gpu/shaders/infos/gpu_interface_info.hh
new file mode 100644
index 00000000000..d5ad333638f
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_interface_info.hh
@@ -0,0 +1,36 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(flat_color_iface, "").flat(Type::VEC4, "finalColor");
+GPU_SHADER_INTERFACE_INFO(no_perspective_color_iface, "").no_perspective(Type::VEC4, "finalColor");
+GPU_SHADER_INTERFACE_INFO(smooth_color_iface, "").smooth(Type::VEC4, "finalColor");
+GPU_SHADER_INTERFACE_INFO(smooth_tex_coord_interp_iface, "").smooth(Type::VEC2, "texCoord_interp");
+GPU_SHADER_INTERFACE_INFO(smooth_radii_iface, "").smooth(Type::VEC2, "radii");
+GPU_SHADER_INTERFACE_INFO(smooth_radii_outline_iface, "").smooth(Type::VEC4, "radii");
+GPU_SHADER_INTERFACE_INFO(flat_color_smooth_tex_coord_interp_iface, "")
+ .flat(Type::VEC4, "finalColor")
+ .smooth(Type::VEC2, "texCoord_interp");
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_area_borders_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_area_borders_info.hh
new file mode 100644
index 00000000000..bf746eae9b4
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_area_borders_info.hh
@@ -0,0 +1,39 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(smooth_uv_iface, "").smooth(Type::VEC2, "uv");
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_area_borders)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_out(smooth_uv_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(16, Type::VEC4, "rect")
+ .push_constant(20, Type::VEC4, "color")
+ .push_constant(24, Type::FLOAT, "scale")
+ .push_constant(25, Type::INT, "cornerLen")
+ .vertex_source("gpu_shader_2D_area_borders_vert.glsl")
+ .fragment_source("gpu_shader_2D_area_borders_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_checker_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_checker_info.hh
new file mode 100644
index 00000000000..48c261da8dd
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_checker_info.hh
@@ -0,0 +1,35 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_checker)
+ .vertex_in(0, Type::VEC2, "pos")
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(16, Type::VEC4, "color1")
+ .push_constant(20, Type::VEC4, "color2")
+ .push_constant(24, Type::INT, "size")
+ .vertex_source("gpu_shader_2D_vert.glsl")
+ .fragment_source("gpu_shader_checker_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_diag_stripes_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_diag_stripes_info.hh
new file mode 100644
index 00000000000..51ce7f503df
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_diag_stripes_info.hh
@@ -0,0 +1,36 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_diag_stripes)
+ .vertex_in(0, Type::VEC2, "pos")
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(16, Type::VEC4, "color1")
+ .push_constant(20, Type::VEC4, "color2")
+ .push_constant(24, Type::INT, "size1")
+ .push_constant(28, Type::INT, "size2")
+ .vertex_source("gpu_shader_2D_vert.glsl")
+ .fragment_source("gpu_shader_diag_stripes_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_flat_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_flat_color_info.hh
new file mode 100644
index 00000000000..bbc5446f16f
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_flat_color_info.hh
@@ -0,0 +1,37 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+#include "gpu_interface_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_flat_color)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_in(1, Type::VEC4, "color")
+ .vertex_out(flat_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_2D_flat_color_vert.glsl")
+ .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_color_info.hh
new file mode 100644
index 00000000000..a6cc9076d4a
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_color_info.hh
@@ -0,0 +1,30 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_color)
+ .additional_info("gpu_shader_2D_image_common")
+ .push_constant(16, Type::VEC4, "color")
+ .fragment_source("gpu_shader_image_color_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_desaturate_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_desaturate_color_info.hh
new file mode 100644
index 00000000000..e11d6746446
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_desaturate_color_info.hh
@@ -0,0 +1,31 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_desaturate_color)
+ .additional_info("gpu_shader_2D_image_common")
+ .push_constant(16, Type::VEC4, "color")
+ .push_constant(20, Type::FLOAT, "factor")
+ .fragment_source("gpu_shader_image_desaturate_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_info.hh
new file mode 100644
index 00000000000..3d20b63c265
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_info.hh
@@ -0,0 +1,39 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_common)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_in(1, Type::VEC2, "texCoord")
+ .vertex_out(smooth_tex_coord_interp_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .sampler(0, ImageType::FLOAT_2D, "image")
+ .vertex_source("gpu_shader_2D_image_vert.glsl");
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image)
+ .additional_info("gpu_shader_2D_image_common")
+ .fragment_source("gpu_shader_image_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_multi_rect_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_multi_rect_color_info.hh
new file mode 100644
index 00000000000..4b154a045ee
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_multi_rect_color_info.hh
@@ -0,0 +1,13 @@
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_multi_rect_color)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_out(flat_color_smooth_tex_coord_interp_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .uniform_buf(0, "MultiRectCallData", "multi_rect_data")
+ .sampler(0, ImageType::FLOAT_2D, "image")
+ .typedef_source("GPU_shader_shared.h")
+ .vertex_source("gpu_shader_2D_image_multi_rect_vert.glsl")
+ .fragment_source("gpu_shader_image_varying_color_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_merge_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_merge_info.hh
new file mode 100644
index 00000000000..c2c0e9fec78
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_merge_info.hh
@@ -0,0 +1,39 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_overlays_merge)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_in(1, Type::VEC2, "texCoord")
+ .vertex_out(smooth_tex_coord_interp_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(16, Type::BOOL, "display_transform")
+ .push_constant(17, Type::BOOL, "overlay")
+ .sampler(0, ImageType::FLOAT_2D, "image_texture")
+ .sampler(1, ImageType::FLOAT_2D, "overlays_texture")
+ .vertex_source("gpu_shader_2D_image_vert.glsl")
+ .fragment_source("gpu_shader_image_overlays_merge_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
new file mode 100644
index 00000000000..c1e6c3957d3
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
@@ -0,0 +1,36 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_overlays_stereo_merge)
+ .vertex_in(0, Type::VEC2, "pos")
+ .fragment_out(0, Type::VEC4, "imageColor")
+ .fragment_out(1, Type::VEC4, "overlayColor")
+ .sampler(0, ImageType::FLOAT_2D, "imageTexture")
+ .sampler(1, ImageType::FLOAT_2D, "overlayTexture")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(16, Type::INT, "stereoDisplaySettings")
+ .vertex_source("gpu_shader_2D_vert.glsl")
+ .fragment_source("gpu_shader_image_overlays_stereo_merge_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_rect_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_rect_color_info.hh
new file mode 100644
index 00000000000..4e10b91ef39
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_rect_color_info.hh
@@ -0,0 +1,37 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_rect_color)
+ .vertex_out(smooth_tex_coord_interp_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(16, Type::VEC4, "color")
+ .push_constant(20, Type::VEC4, "rect_icon")
+ .push_constant(24, Type::VEC4, "rect_geom")
+ .sampler(0, ImageType::FLOAT_2D, "image")
+ .vertex_source("gpu_shader_2D_image_rect_vert.glsl")
+ .fragment_source("gpu_shader_image_color_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_shuffle_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_shuffle_color_info.hh
new file mode 100644
index 00000000000..3663de0a98f
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_shuffle_color_info.hh
@@ -0,0 +1,31 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_shuffle_color)
+ .additional_info("gpu_shader_2D_image_common")
+ .push_constant(16, Type::VEC4, "color")
+ .push_constant(20, Type::VEC4, "shuffle")
+ .fragment_source("gpu_shader_image_shuffle_color_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_line_dashed_uniform_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_line_dashed_uniform_color_info.hh
new file mode 100644
index 00000000000..371a35386a7
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_line_dashed_uniform_color_info.hh
@@ -0,0 +1,34 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+/* TODO(jbakker): Skipped as data doesn't fit as push constant. */
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_line_dashed_uniform_color)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_out(flat_color_iface)
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_2D_line_dashed_uniform_color_vert.glsl")
+ .fragment_source("gpu_shader_2D_line_dashed_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_nodelink_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_nodelink_info.hh
new file mode 100644
index 00000000000..b15d7ba3ada
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_nodelink_info.hh
@@ -0,0 +1,72 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(nodelink_iface, "")
+ .smooth(Type::VEC4, "finalColor")
+ .smooth(Type::FLOAT, "colorGradient")
+ .smooth(Type::FLOAT, "lineU")
+ .flat(Type::FLOAT, "lineLength")
+ .flat(Type::FLOAT, "dashFactor")
+ .flat(Type::FLOAT, "dashAlpha")
+ .flat(Type::INT, "isMainLine");
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_nodelink)
+ .vertex_in(0, Type::VEC2, "uv")
+ .vertex_in(1, Type::VEC2, "pos")
+ .vertex_in(2, Type::VEC2, "expand")
+ .vertex_out(nodelink_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .uniform_buf(0, "NodeLinkData", "node_link_data", Frequency::PASS)
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_2D_nodelink_vert.glsl")
+ .fragment_source("gpu_shader_2D_nodelink_frag.glsl")
+ .typedef_source("GPU_shader_shared.h")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_nodelink_inst)
+ .vertex_in(0, Type::VEC2, "uv")
+ .vertex_in(1, Type::VEC2, "pos")
+ .vertex_in(2, Type::VEC2, "expand")
+ .vertex_in(3, Type::VEC2, "P0")
+ .vertex_in(4, Type::VEC2, "P1")
+ .vertex_in(5, Type::VEC2, "P2")
+ .vertex_in(6, Type::VEC2, "P3")
+ .vertex_in(7, Type::IVEC4, "colid_doarrow")
+ .vertex_in(8, Type::VEC4, "start_color")
+ .vertex_in(9, Type::VEC4, "end_color")
+ .vertex_in(10, Type::IVEC2, "domuted")
+ .vertex_in(11, Type::FLOAT, "dim_factor")
+ .vertex_in(12, Type::FLOAT, "thickness")
+ .vertex_in(13, Type::FLOAT, "dash_factor")
+ .vertex_in(14, Type::FLOAT, "dash_alpha")
+ .vertex_out(nodelink_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .uniform_buf(0, "NodeLinkInstanceData", "node_link_data", Frequency::PASS)
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_2D_nodelink_vert.glsl")
+ .fragment_source("gpu_shader_2D_nodelink_frag.glsl")
+ .typedef_source("GPU_shader_shared.h")
+ .define("USE_INSTANCE")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_aa_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_aa_info.hh
new file mode 100644
index 00000000000..d2753af8e9b
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_aa_info.hh
@@ -0,0 +1,36 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_point_uniform_size_uniform_color_aa)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_out(smooth_radii_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(16, Type::VEC4, "color")
+ .push_constant(20, Type::FLOAT, "size")
+ .vertex_source("gpu_shader_2D_point_uniform_size_aa_vert.glsl")
+ .fragment_source("gpu_shader_point_uniform_color_aa_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_outline_aa_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_outline_aa_info.hh
new file mode 100644
index 00000000000..edc83534573
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_outline_aa_info.hh
@@ -0,0 +1,38 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_point_uniform_size_uniform_color_outline_aa)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_out(smooth_radii_outline_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(20, Type::VEC4, "color")
+ .push_constant(24, Type::VEC4, "outlineColor")
+ .push_constant(28, Type::FLOAT, "size")
+ .push_constant(29, Type::FLOAT, "outlineWidth")
+ .vertex_source("gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl")
+ .fragment_source("gpu_shader_point_uniform_color_outline_aa_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_point_varying_size_varying_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_point_varying_size_varying_color_info.hh
new file mode 100644
index 00000000000..4358e94f91f
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_point_varying_size_varying_color_info.hh
@@ -0,0 +1,36 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_point_varying_size_varying_color)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_in(1, Type::FLOAT, "size")
+ .vertex_in(2, Type::VEC4, "color")
+ .vertex_out(smooth_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_2D_point_varying_size_varying_color_vert.glsl")
+ .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_smooth_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_smooth_color_info.hh
new file mode 100644
index 00000000000..0029e8d2044
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_smooth_color_info.hh
@@ -0,0 +1,36 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_smooth_color)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_in(1, Type::VEC4, "color")
+ .vertex_out(smooth_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_2D_smooth_color_vert.glsl")
+ .fragment_source("gpu_shader_2D_smooth_color_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_uniform_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_uniform_color_info.hh
new file mode 100644
index 00000000000..7e75b265711
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_uniform_color_info.hh
@@ -0,0 +1,34 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_uniform_color)
+ .vertex_in(0, Type::VEC2, "pos")
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(16, Type::VEC4, "color")
+ .vertex_source("gpu_shader_2D_vert.glsl")
+ .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_depth_only_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_depth_only_info.hh
new file mode 100644
index 00000000000..3e7e4aeecda
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_depth_only_info.hh
@@ -0,0 +1,37 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_depth_only)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_out(flat_color_iface)
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_3D_vert.glsl")
+ .fragment_source("gpu_shader_depth_only_frag.glsl")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_depth_only_clipped)
+ .additional_info("gpu_shader_3D_depth_only")
+ .additional_info("gpu_clip_planes");
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_flat_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_flat_color_info.hh
new file mode 100644
index 00000000000..14a6986f478
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_flat_color_info.hh
@@ -0,0 +1,40 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_flat_color)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC4, "color")
+ .vertex_out(flat_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_3D_flat_color_vert.glsl")
+ .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_flat_color_clipped)
+ .additional_info("gpu_shader_3D_flat_color")
+ .additional_info("gpu_clip_planes");
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_image_modulate_alpha_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_image_modulate_alpha_info.hh
new file mode 100644
index 00000000000..b829975448c
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_image_modulate_alpha_info.hh
@@ -0,0 +1,37 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_image_modulate_alpha)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC2, "texCoord")
+ .vertex_out(smooth_tex_coord_interp_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(16, Type::FLOAT, "alpha")
+ .sampler(0, ImageType::FLOAT_2D, "image", Frequency::PASS)
+ .vertex_source("gpu_shader_3D_image_vert.glsl")
+ .fragment_source("gpu_shader_image_modulate_alpha_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_line_dashed_uniform_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_line_dashed_uniform_color_info.hh
new file mode 100644
index 00000000000..d43ea799420
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_line_dashed_uniform_color_info.hh
@@ -0,0 +1,34 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+/* TODO(jbakker): Skipped as data doesn't fit as push constant. */
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_line_dashed_uniform_color)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_out(flat_color_iface)
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_3D_line_dashed_uniform_color_vert.glsl")
+ .fragment_source("gpu_shader_2D_line_dashed_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh
new file mode 100644
index 00000000000..27357eef8c9
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh
@@ -0,0 +1,60 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_point_fixed_size_varying_color)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC4, "color")
+ .vertex_out(smooth_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_3D_point_fixed_size_varying_color_vert.glsl")
+ .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_point_varying_size_varying_color)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC4, "color")
+ .vertex_in(2, Type::FLOAT, "size")
+ .vertex_out(smooth_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_3D_point_varying_size_varying_color_vert.glsl")
+ .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_point_uniform_size_uniform_color_aa)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_out(smooth_radii_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(16, Type::VEC4, "color")
+ .push_constant(20, Type::FLOAT, "size")
+ .vertex_source("gpu_shader_3D_point_uniform_size_aa_vert.glsl")
+ .fragment_source("gpu_shader_point_uniform_color_aa_frag.glsl")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_point_uniform_size_uniform_color_aa_clipped)
+ .additional_info("gpu_shader_3D_point_uniform_size_uniform_color_aa")
+ .additional_info("gpu_clip_planes");
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh
new file mode 100644
index 00000000000..d2961c10a1f
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh
@@ -0,0 +1,32 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+/* TODO(jbakker): Skipped as it needs a uniform/storage buffer. */
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_polyline_uniform_color)
+ .vertex_source("gpu_shader_3D_polyline_vert.glsl")
+ .geometry_source("gpu_shader_3D_polyline_geom.glsl")
+ .fragment_source("gpu_shader_3D_polyline_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_smooth_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_smooth_color_info.hh
new file mode 100644
index 00000000000..c99d9ed199d
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_smooth_color_info.hh
@@ -0,0 +1,40 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_smooth_color)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC4, "color")
+ .vertex_out(smooth_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_3D_smooth_color_vert.glsl")
+ .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_smooth_color_clipped)
+ .additional_info("gpu_shader_3D_smooth_color")
+ .additional_info("gpu_clip_planes");
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh
new file mode 100644
index 00000000000..5b8517310ea
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh
@@ -0,0 +1,38 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_uniform_color)
+ .vertex_in(0, Type::VEC3, "pos")
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(16, Type::VEC4, "color")
+ .vertex_source("gpu_shader_3D_vert.glsl")
+ .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_uniform_color_clipped)
+ .additional_info("gpu_shader_3D_uniform_color")
+ .additional_info("gpu_clip_planes");
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_gpencil_stroke_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_gpencil_stroke_info.hh
new file mode 100644
index 00000000000..c337c399f59
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_gpencil_stroke_info.hh
@@ -0,0 +1,50 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(gpencil_stroke_vert_iface, "geometry_in")
+ .smooth(Type::VEC4, "finalColor")
+ .smooth(Type::FLOAT, "finalThickness");
+GPU_SHADER_INTERFACE_INFO(gpencil_stroke_geom_iface, "geometry_out")
+ .smooth(Type::VEC4, "mColor")
+ .smooth(Type::VEC2, "mTexCoord");
+
+GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke)
+ .vertex_in(0, Type::VEC4, "color")
+ .vertex_in(1, Type::VEC3, "pos")
+ .vertex_in(2, Type::FLOAT, "thickness")
+ .vertex_out(gpencil_stroke_vert_iface)
+ .geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::TRIANGLE_STRIP, 13)
+ .geometry_out(gpencil_stroke_geom_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+
+ .uniform_buf(0, "GPencilStrokeData", "gpencil_stroke_data")
+
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(16, Type::MAT4, "ProjectionMatrix")
+ .vertex_source("gpu_shader_gpencil_stroke_vert.glsl")
+ .geometry_source("gpu_shader_gpencil_stroke_geom.glsl")
+ .fragment_source("gpu_shader_gpencil_stroke_frag.glsl")
+ .typedef_source("GPU_shader_shared.h")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh
new file mode 100644
index 00000000000..98a1fcf5b37
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh
@@ -0,0 +1,38 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_instance_varying_color_varying_size)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::MAT4, "InstanceModelMatrix")
+ .vertex_in(2, Type::VEC4, "color")
+ .vertex_in(3, Type::FLOAT, "size")
+ .vertex_out(flat_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ViewProjectionMatrix")
+ .vertex_source("gpu_shader_instance_variying_size_variying_color_vert.glsl")
+ .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_keyframe_shape_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_keyframe_shape_info.hh
new file mode 100644
index 00000000000..f8cb94e52d0
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_keyframe_shape_info.hh
@@ -0,0 +1,46 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(keyframe_shape_iface, "")
+ .flat(Type::VEC4, "finalColor")
+ .flat(Type::VEC4, "finalOutlineColor")
+ .flat(Type::VEC4, "radii")
+ .flat(Type::VEC4, "thresholds")
+ .flat(Type::INT, "finalFlags");
+
+GPU_SHADER_CREATE_INFO(gpu_shader_keyframe_shape)
+ .vertex_in(0, Type::VEC4, "color")
+ .vertex_in(1, Type::VEC4, "outlineColor")
+ .vertex_in(2, Type::VEC2, "pos")
+ .vertex_in(3, Type::FLOAT, "size")
+ .vertex_in(4, Type ::INT, "flags")
+ .vertex_out(keyframe_shape_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(16, Type::VEC2, "ViewportSize")
+ .push_constant(24, Type::FLOAT, "outline_scale")
+ .vertex_source("gpu_shader_keyframe_shape_vert.glsl")
+ .fragment_source("gpu_shader_keyframe_shape_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_simple_lighting_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_simple_lighting_info.hh
new file mode 100644
index 00000000000..c3f86ed2b6f
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_simple_lighting_info.hh
@@ -0,0 +1,40 @@
+
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(smooth_normal_iface, "").smooth(Type::VEC3, "normal");
+
+GPU_SHADER_CREATE_INFO(gpu_shader_simple_lighting)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC3, "nor")
+ .vertex_out(smooth_normal_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .uniform_buf(0, "SimpleLightingData", "simple_lighting_data", Frequency::PASS)
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(16, Type::MAT3, "NormalMatrix")
+ .typedef_source("GPU_shader_shared.h")
+ .vertex_source("gpu_shader_3D_normal_vert.glsl")
+ .fragment_source("gpu_shader_simple_lighting_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_text_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_text_info.hh
new file mode 100644
index 00000000000..2c17a494d76
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_text_info.hh
@@ -0,0 +1,45 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(text_iface, "")
+ .flat(Type::VEC4, "color_flat")
+ .no_perspective(Type::VEC2, "texCoord_interp")
+ .flat(Type::INT, "glyph_offset")
+ .flat(Type::IVEC2, "glyph_dim")
+ .flat(Type::INT, "interp_size");
+
+GPU_SHADER_CREATE_INFO(gpu_shader_text)
+ .vertex_in(0, Type::VEC4, "pos")
+ .vertex_in(1, Type::VEC4, "col")
+ .vertex_in(2, Type ::IVEC2, "glyph_size")
+ .vertex_in(3, Type ::INT, "offset")
+ .vertex_out(text_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(0, Type::MAT4, "ModelViewProjectionMatrix")
+ .sampler(0, ImageType::FLOAT_2D, "glyph", Frequency::PASS)
+ .vertex_source("gpu_shader_text_vert.glsl")
+ .fragment_source("gpu_shader_text_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_srgb_to_framebuffer_space_info.hh b/source/blender/gpu/shaders/infos/gpu_srgb_to_framebuffer_space_info.hh
new file mode 100644
index 00000000000..3af49b56ab1
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_srgb_to_framebuffer_space_info.hh
@@ -0,0 +1,27 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_srgb_to_framebuffer_space)
+ .define("blender_srgb_to_framebuffer_space(a) a");
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl
new file mode 100644
index 00000000000..514409f7fdf
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl
@@ -0,0 +1,33 @@
+/* ext is vec4(in_x, in_dy, out_x, out_dy). */
+float curve_float_extrapolate(float x, float y, vec4 ext)
+{
+ if (x < 0.0) {
+ return y + x * ext.y;
+ }
+ else if (x > 1.0) {
+ return y + (x - 1.0) * ext.w;
+ }
+ else {
+ return y;
+ }
+}
+
+#define RANGE_RESCALE(x, min, range) ((x - min) * range)
+
+void curve_float(float fac,
+ float vec,
+ sampler1DArray curvemap,
+ float layer,
+ float range,
+ vec4 ext,
+ out float outvec)
+{
+ float xyz_min = ext.x;
+ vec = RANGE_RESCALE(vec, xyz_min, range);
+
+ outvec = texture(curvemap, vec2(vec, layer)).x;
+
+ outvec = curve_float_extrapolate(vec, outvec, ext);
+
+ outvec = mix(vec, outvec, fac);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
index f25691c1a83..95f2be4bd44 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
@@ -5,7 +5,7 @@ float fractal_noise(float p, float octaves, float roughness)
float amp = 1.0;
float maxamp = 0.0;
float sum = 0.0;
- octaves = clamp(octaves, 0.0, 16.0);
+ octaves = clamp(octaves, 0.0, 15.0);
int n = int(octaves);
for (int i = 0; i <= n; i++) {
float t = noise(fscale * p);
@@ -34,7 +34,7 @@ float fractal_noise(vec2 p, float octaves, float roughness)
float amp = 1.0;
float maxamp = 0.0;
float sum = 0.0;
- octaves = clamp(octaves, 0.0, 16.0);
+ octaves = clamp(octaves, 0.0, 15.0);
int n = int(octaves);
for (int i = 0; i <= n; i++) {
float t = noise(fscale * p);
@@ -63,7 +63,7 @@ float fractal_noise(vec3 p, float octaves, float roughness)
float amp = 1.0;
float maxamp = 0.0;
float sum = 0.0;
- octaves = clamp(octaves, 0.0, 16.0);
+ octaves = clamp(octaves, 0.0, 15.0);
int n = int(octaves);
for (int i = 0; i <= n; i++) {
float t = noise(fscale * p);
@@ -92,7 +92,7 @@ float fractal_noise(vec4 p, float octaves, float roughness)
float amp = 1.0;
float maxamp = 0.0;
float sum = 0.0;
- octaves = clamp(octaves, 0.0, 16.0);
+ octaves = clamp(octaves, 0.0, 15.0);
int n = int(octaves);
for (int i = 0; i <= n; i++) {
float t = noise(fscale * p);
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 e45a25c3b49..e74389f93e4 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,15 +1,4 @@
-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(float hair_length,
out float is_strand,
out float intercept,
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl
index 86191451e5f..cb798047791 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl
@@ -215,3 +215,14 @@ float integer_noise(int n)
nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
return 0.5 * (float(nn) / 1073741824.0);
}
+
+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);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
index 7853aae31a1..1def3abec26 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
@@ -4,13 +4,128 @@ float smootherstep(float edge0, float edge1, float x)
return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
}
+vec3 smootherstep(vec3 edge0, vec3 edge1, vec3 x)
+{
+ x = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0, 1.0);
+ return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
+}
+
+void vector_map_range_linear(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
+{
+ vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
+ v_result = v_to_min + factor * (v_to_max - v_to_min);
+ if (use_clamp > 0.0) {
+ v_result.x = (v_to_min.x > v_to_max.x) ? clamp(v_result.x, v_to_max.x, v_to_min.x) :
+ clamp(v_result.x, v_to_min.x, v_to_max.x);
+ v_result.y = (v_to_min.y > v_to_max.y) ? clamp(v_result.y, v_to_max.y, v_to_min.y) :
+ clamp(v_result.y, v_to_min.y, v_to_max.y);
+ v_result.z = (v_to_min.z > v_to_max.z) ? clamp(v_result.z, v_to_max.z, v_to_min.z) :
+ clamp(v_result.z, v_to_min.z, v_to_max.z);
+ }
+}
+
+void vector_map_range_stepped(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
+{
+ vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
+ factor = safe_divide(floor(factor * (v_steps + 1.0)), v_steps);
+ v_result = v_to_min + factor * (v_to_max - v_to_min);
+ if (use_clamp > 0.0) {
+ v_result.x = (v_to_min.x > v_to_max.x) ? clamp(v_result.x, v_to_max.x, v_to_min.x) :
+ clamp(v_result.x, v_to_min.x, v_to_max.x);
+ v_result.y = (v_to_min.y > v_to_max.y) ? clamp(v_result.y, v_to_max.y, v_to_min.y) :
+ clamp(v_result.y, v_to_min.y, v_to_max.y);
+ v_result.z = (v_to_min.z > v_to_max.z) ? clamp(v_result.z, v_to_max.z, v_to_min.z) :
+ clamp(v_result.z, v_to_min.z, v_to_max.z);
+ }
+}
+
+void vector_map_range_smoothstep(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
+{
+ vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
+ factor = clamp(factor, 0.0, 1.0);
+ factor = (3.0 - 2.0 * factor) * (factor * factor);
+ v_result = v_to_min + factor * (v_to_max - v_to_min);
+}
+
+void vector_map_range_smootherstep(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
+{
+ vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
+ factor = clamp(factor, 0.0, 1.0);
+ factor = factor * factor * factor * (factor * (factor * 6.0 - 15.0) + 10.0);
+ v_result = v_to_min + factor * (v_to_max - v_to_min);
+}
+
void map_range_linear(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
- out float result)
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
{
if (fromMax != fromMin) {
result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
@@ -26,7 +141,15 @@ void map_range_stepped(float value,
float toMin,
float toMax,
float steps,
- out float result)
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
{
if (fromMax != fromMin) {
float factor = (value - fromMin) / (fromMax - fromMin);
@@ -44,7 +167,15 @@ void map_range_smoothstep(float value,
float toMin,
float toMax,
float steps,
- out float result)
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
{
if (fromMax != fromMin) {
float factor = (fromMin > fromMax) ? 1.0 - smoothstep(fromMax, fromMin, value) :
@@ -62,7 +193,15 @@ void map_range_smootherstep(float value,
float toMin,
float toMax,
float steps,
- out float result)
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
{
if (fromMax != fromMin) {
float factor = (fromMin > fromMax) ? 1.0 - smootherstep(fromMax, fromMin, value) :
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
new file mode 100644
index 00000000000..d717ac97b28
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
@@ -0,0 +1,13 @@
+
+void node_point_info(out vec3 position, out float radius, out float random)
+{
+#ifdef POINTCLOUD_SHADER
+ position = pointPosition;
+ radius = pointRadius;
+ random = wang_hash_noise(uint(pointID));
+#else
+ position = vec3(0.0, 0.0, 0.0);
+ radius = 0.0;
+ random = 0.0;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
index 942c507cc38..1dc5ff433a8 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
@@ -1,7 +1,8 @@
void node_tex_magic(
vec3 co, float scale, float distortion, float depth, out vec4 color, out float fac)
{
- vec3 p = co * scale;
+ vec3 p = mod(co * scale, 2.0 * M_PI);
+
float x = sin((p.x + p.y + p.z) * 5.0);
float y = cos((-p.x + p.y - p.z) * 5.0);
float z = -cos((-p.x - p.y + p.z) * 5.0);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
index 7ecca286acd..586385b7e86 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
@@ -19,7 +19,7 @@ void node_tex_musgrave_fBm_1d(vec3 co,
{
float p = w * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float value = 0.0;
@@ -59,7 +59,7 @@ void node_tex_musgrave_multi_fractal_1d(vec3 co,
{
float p = w * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float value = 1.0;
@@ -100,7 +100,7 @@ void node_tex_musgrave_hetero_terrain_1d(vec3 co,
{
float p = w * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float pwHL = pow(lacunarity, -H);
@@ -146,7 +146,7 @@ void node_tex_musgrave_hybrid_multi_fractal_1d(vec3 co,
{
float p = w * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float pwHL = pow(lacunarity, -H);
@@ -196,7 +196,7 @@ void node_tex_musgrave_ridged_multi_fractal_1d(vec3 co,
{
float p = w * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float pwHL = pow(lacunarity, -H);
@@ -241,7 +241,7 @@ void node_tex_musgrave_fBm_2d(vec3 co,
{
vec2 p = co.xy * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float value = 0.0;
@@ -281,7 +281,7 @@ void node_tex_musgrave_multi_fractal_2d(vec3 co,
{
vec2 p = co.xy * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float value = 1.0;
@@ -322,7 +322,7 @@ void node_tex_musgrave_hetero_terrain_2d(vec3 co,
{
vec2 p = co.xy * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float pwHL = pow(lacunarity, -H);
@@ -368,7 +368,7 @@ void node_tex_musgrave_hybrid_multi_fractal_2d(vec3 co,
{
vec2 p = co.xy * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float pwHL = pow(lacunarity, -H);
@@ -418,7 +418,7 @@ void node_tex_musgrave_ridged_multi_fractal_2d(vec3 co,
{
vec2 p = co.xy * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float pwHL = pow(lacunarity, -H);
@@ -463,7 +463,7 @@ void node_tex_musgrave_fBm_3d(vec3 co,
{
vec3 p = co * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float value = 0.0;
@@ -503,7 +503,7 @@ void node_tex_musgrave_multi_fractal_3d(vec3 co,
{
vec3 p = co * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float value = 1.0;
@@ -544,7 +544,7 @@ void node_tex_musgrave_hetero_terrain_3d(vec3 co,
{
vec3 p = co * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float pwHL = pow(lacunarity, -H);
@@ -590,7 +590,7 @@ void node_tex_musgrave_hybrid_multi_fractal_3d(vec3 co,
{
vec3 p = co * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float pwHL = pow(lacunarity, -H);
@@ -640,7 +640,7 @@ void node_tex_musgrave_ridged_multi_fractal_3d(vec3 co,
{
vec3 p = co * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float pwHL = pow(lacunarity, -H);
@@ -685,7 +685,7 @@ void node_tex_musgrave_fBm_4d(vec3 co,
{
vec4 p = vec4(co, w) * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float value = 0.0;
@@ -725,7 +725,7 @@ void node_tex_musgrave_multi_fractal_4d(vec3 co,
{
vec4 p = vec4(co, w) * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float value = 1.0;
@@ -766,7 +766,7 @@ void node_tex_musgrave_hetero_terrain_4d(vec3 co,
{
vec4 p = vec4(co, w) * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float pwHL = pow(lacunarity, -H);
@@ -812,7 +812,7 @@ void node_tex_musgrave_hybrid_multi_fractal_4d(vec3 co,
{
vec4 p = vec4(co, w) * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float pwHL = pow(lacunarity, -H);
@@ -862,7 +862,7 @@ void node_tex_musgrave_ridged_multi_fractal_4d(vec3 co,
{
vec4 p = vec4(co, w) * scale;
float H = max(dimension, 1e-5);
- float octaves = clamp(detail, 0.0, 16.0);
+ float octaves = clamp(detail, 0.0, 15.0);
float lacunarity = max(lac, 1e-5);
float pwHL = pow(lacunarity, -H);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
index 0f69a4b9aa0..c8219848e29 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
@@ -72,7 +72,7 @@ void node_tex_voronoi_smooth_f1_1d(vec3 coord,
out float outRadius)
{
randomness = clamp(randomness, 0.0, 1.0);
- smoothness = clamp(smoothness / 2.0, 0, 0.5);
+ smoothness = clamp(smoothness / 2.0, 0.0, 0.5);
float scaledCoord = w * scale;
float cellPosition = floor(scaledCoord);
@@ -301,7 +301,7 @@ void node_tex_voronoi_smooth_f1_2d(vec3 coord,
out float outRadius)
{
randomness = clamp(randomness, 0.0, 1.0);
- smoothness = clamp(smoothness / 2.0, 0, 0.5);
+ smoothness = clamp(smoothness / 2.0, 0.0, 0.5);
vec2 scaledCoord = coord.xy * scale;
vec2 cellPosition = floor(scaledCoord);
@@ -565,7 +565,7 @@ void node_tex_voronoi_smooth_f1_3d(vec3 coord,
out float outRadius)
{
randomness = clamp(randomness, 0.0, 1.0);
- smoothness = clamp(smoothness / 2.0, 0, 0.5);
+ smoothness = clamp(smoothness / 2.0, 0.0, 0.5);
vec3 scaledCoord = coord * scale;
vec3 cellPosition = floor(scaledCoord);
@@ -852,7 +852,7 @@ void node_tex_voronoi_smooth_f1_4d(vec3 coord,
out float outRadius)
{
randomness = clamp(randomness, 0.0, 1.0);
- smoothness = clamp(smoothness / 2.0, 0, 0.5);
+ smoothness = clamp(smoothness / 2.0, 0.0, 0.5);
vec4 scaledCoord = vec4(coord, w) * scale;
vec4 cellPosition = floor(scaledCoord);
diff --git a/source/blender/gpu/tests/gpu_shader_builtin_test.cc b/source/blender/gpu/tests/gpu_shader_builtin_test.cc
index 523a7e5b881..6d6a772f5fb 100644
--- a/source/blender/gpu/tests/gpu_shader_builtin_test.cc
+++ b/source/blender/gpu/tests/gpu_shader_builtin_test.cc
@@ -29,7 +29,6 @@ static void test_shader_builtin()
test_compile_builtin_shader(GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE);
test_compile_builtin_shader(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
test_compile_builtin_shader(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
- test_compile_builtin_shader(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
test_compile_builtin_shader(GPU_SHADER_TEXT, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_KEYFRAME_SHAPE, GPU_SHADER_CFG_DEFAULT);
@@ -53,40 +52,22 @@ static void test_shader_builtin()
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR,
- GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA,
- GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR,
- GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR,
- GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA,
GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA,
GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR,
GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR,
- GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR,
GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_GPENCIL_STROKE, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_AREA_EDGES, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_AREA_BORDERS, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_WIDGET_BASE, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_WIDGET_BASE_INST, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_WIDGET_SHADOW, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_NODELINK, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_NODELINK_INST, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_VERTS, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_FACEDOTS, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_EDGES, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_EDGES_SMOOTH, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_FACES, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_FACES_STRETCH_AREA, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE, GPU_SHADER_CFG_DEFAULT);
}
GPU_TEST(shader_builtin)
diff --git a/source/blender/gpu/tests/gpu_testing.cc b/source/blender/gpu/tests/gpu_testing.cc
index ac42c5875c8..7fd473069c2 100644
--- a/source/blender/gpu/tests/gpu_testing.cc
+++ b/source/blender/gpu/tests/gpu_testing.cc
@@ -18,6 +18,7 @@ void GPUTest::SetUp()
CLG_init();
ghost_system = GHOST_CreateSystem();
ghost_context = GHOST_CreateOpenGLContext(ghost_system, glSettings);
+ GHOST_ActivateOpenGLContext(ghost_context);
context = GPU_context_create(nullptr);
GPU_init();
}
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index b9411f6dd2d..4a4e22ed884 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -284,7 +284,7 @@ static int initialize_chain(Object *ob, bPoseChannel *pchan_tip, bConstraint *co
/* setup the chain data */
/* create a target */
- target = (PoseTarget *)MEM_callocN(sizeof(PoseTarget), "posetarget");
+ target = MEM_cnew<PoseTarget>("posetarget");
target->con = con;
/* by construction there can be only one tree per channel
* and each channel can be part of at most one tree. */
@@ -292,7 +292,7 @@ static int initialize_chain(Object *ob, bPoseChannel *pchan_tip, bConstraint *co
if (tree == nullptr) {
/* make new tree */
- tree = (PoseTree *)MEM_callocN(sizeof(PoseTree), "posetree");
+ tree = MEM_cnew<PoseTree>("posetree");
tree->iterations = data->iterations;
tree->totchannel = segcount;
@@ -644,7 +644,7 @@ static bool base_callback(const iTaSC::Timestamp &timestamp,
ikscene->baseFrame = iTaSC::F_identity;
}
next.setValue(&rootmat[0][0]);
- /* if there is a polar target (only during solving otherwise we don't have end efffector) */
+ /* If there is a polar target (only during solving otherwise we don't have end effector). */
if (ikscene->polarConstraint && timestamp.update) {
/* compute additional rotation of base frame so that armature follows the polar target */
float imat[4][4]; /* IK tree base inverse matrix */
@@ -1876,9 +1876,10 @@ static void execute_scene(struct Depsgraph *depsgraph,
}
}
-/*---------------------------------------------------
- * plugin interface
- */
+/* -------------------------------------------------------------------- */
+/** \name Plugin Interface
+ * \{ */
+
void itasc_initialize_tree(struct Depsgraph *depsgraph,
struct Scene *scene,
Object *ob,
@@ -2012,3 +2013,5 @@ void itasc_test_constraint(struct Object *ob, struct bConstraint *cons)
break;
}
}
+
+/** \} */
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index be0e364c85f..479f4f7e82f 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -64,6 +64,7 @@ set(SRC
intern/thumbs.c
intern/thumbs_blend.c
intern/thumbs_font.c
+ intern/transform.cc
intern/util.c
intern/util_gpu.c
intern/writeimage.c
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 53b0e295385..30f2f24447f 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -45,7 +45,9 @@ struct bContext;
struct ColorManagedDisplay;
struct ColorSpace;
-/* ** Generic functions ** */
+/* -------------------------------------------------------------------- */
+/** \name Generic Functions
+ * \{ */
void IMB_colormanagement_check_file_config(struct Main *bmain);
@@ -67,13 +69,35 @@ bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_is_srgb(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_name_is_data(const char *name);
+/**
+ * Convert a float RGB triplet to the correct luminance weighted average.
+ *
+ * Gray-scale, or Luma is a distillation of RGB data values down to a weighted average
+ * based on the luminance positions of the red, green, and blue primaries.
+ * Given that the internal reference space may be arbitrarily set, any
+ * effort to glean the luminance coefficients must be aware of the reference
+ * space primaries.
+ *
+ * See http://wiki.blender.org/index.php/User:Nazg-gul/ColorManagement#Luminance
+ */
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3]);
+/**
+ * Byte equivalent of #IMB_colormanagement_get_luminance().
+ */
BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]);
BLI_INLINE void IMB_colormanagement_xyz_to_rgb(float rgb[3], const float xyz[3]);
BLI_INLINE void IMB_colormanagement_rgb_to_xyz(float xyz[3], const float rgb[3]);
const float *IMB_colormanagement_get_xyz_to_rgb(void);
-/* ** Color space transformation functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Space Transformation Functions
+ * \{ */
+
+/**
+ * Convert the whole buffer from specified by name color space to another.
+ */
void IMB_colormanagement_transform(float *buffer,
int width,
int height,
@@ -81,6 +105,10 @@ void IMB_colormanagement_transform(float *buffer,
const char *from_colorspace,
const char *to_colorspace,
bool predivide);
+/**
+ * Convert the whole buffer from specified by name color space to another
+ * will do threaded conversion.
+ */
void IMB_colormanagement_transform_threaded(float *buffer,
int width,
int height,
@@ -88,6 +116,9 @@ void IMB_colormanagement_transform_threaded(float *buffer,
const char *from_colorspace,
const char *to_colorspace,
bool predivide);
+/**
+ * Similar to #IMB_colormanagement_transform_threaded, but operates on byte buffer.
+ */
void IMB_colormanagement_transform_byte(unsigned char *buffer,
int width,
int height,
@@ -100,6 +131,9 @@ void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer,
int channels,
const char *from_colorspace,
const char *to_colorspace);
+/**
+ * Similar to #IMB_colormanagement_transform_byte_threaded, but gets float buffer from display one.
+ */
void IMB_colormanagement_transform_from_byte(float *float_buffer,
unsigned char *byte_buffer,
int width,
@@ -118,12 +152,20 @@ void IMB_colormanagement_transform_v4(float pixel[4],
const char *from_colorspace,
const char *to_colorspace);
+/**
+ * Convert pixel from specified by descriptor color space to scene linear
+ * used by performance-critical areas such as renderer and baker.
+ */
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3],
struct ColorSpace *colorspace);
void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4],
bool predivide,
struct ColorSpace *colorspace);
+/**
+ * Same as #IMB_colormanagement_colorspace_to_scene_linear_v4,
+ * but converts colors in opposite direction.
+ */
void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3],
struct ColorSpace *colorspace);
@@ -135,29 +177,51 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer,
bool predivide);
void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
- const int x,
- const int y,
- const int width,
- const int height,
+ int x,
+ int y,
+ int width,
+ int height,
const struct ImBuf *ibuf,
- const bool compress_as_srgb,
- const bool store_premultiplied);
+ bool compress_as_srgb,
+ bool store_premultiplied);
void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
- const int offset_x,
- const int offset_y,
- const int width,
- const int height,
+ int offset_x,
+ int offset_y,
+ int width,
+ int height,
const struct ImBuf *ibuf,
- const bool store_premultiplied);
-
+ bool store_premultiplied);
+
+/**
+ * Conversion between color picking role. Typically we would expect such a
+ * requirements:
+ * - It is approximately perceptually linear, so that the HSV numbers and
+ * the HSV cube/circle have an intuitive distribution.
+ * - It has the same gamut as the scene linear color space.
+ * - Color picking values 0..1 map to scene linear values in the 0..1 range,
+ * so that picked albedo values are energy conserving.
+ */
void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3]);
void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3]);
+/**
+ * Conversion between sRGB, for rare cases like hex color or copy/pasting
+ * between UI theme and scene linear colors.
+ */
void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3]);
void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3]);
+/**
+ * Convert pixel from scene linear to display space using default view
+ * used by performance-critical areas such as color-related widgets where we want to reduce
+ * amount of per-widget allocations.
+ */
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3],
struct ColorManagedDisplay *display);
+/**
+ * Same as #IMB_colormanagement_scene_linear_to_display_v3,
+ * but converts color in opposite direction.
+ */
void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3],
struct ColorManagedDisplay *display);
@@ -178,6 +242,18 @@ void IMB_colormanagement_imbuf_make_display_space(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
+/**
+ * Prepare image buffer to be saved on disk, applying color management if needed
+ * color management would be applied if image is saving as render result and if
+ * file format is not expecting float buffer to be in linear space (currently
+ * JPEG2000 and TIFF are such formats -- they're storing image as float but
+ * file itself stores applied color space).
+ *
+ * Both byte and float buffers would contain applied color space, and result's
+ * float_colorspace would be set to display color space. This should be checked
+ * in image format write callback and if float_colorspace is not NULL, no color
+ * space transformation should be applied on this buffer.
+ */
struct ImBuf *IMB_colormanagement_imbuf_for_write(
struct ImBuf *ibuf,
bool save_as_render,
@@ -196,7 +272,11 @@ void IMB_colormanagement_buffer_make_display_space(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
-/* ** Public display buffers interfaces ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public Display Buffers Interfaces
+ * \{ */
void IMB_colormanagement_display_settings_from_ctx(
const struct bContext *C,
@@ -207,11 +287,17 @@ const char *IMB_colormanagement_get_display_colorspace_name(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
+/**
+ * Acquire display buffer for given image buffer using specified view and display settings.
+ */
unsigned char *IMB_display_buffer_acquire(
struct ImBuf *ibuf,
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
void **cache_handle);
+/**
+ * Same as #IMB_display_buffer_acquire but gets view and display settings from context.
+ */
unsigned char *IMB_display_buffer_acquire_ctx(const struct bContext *C,
struct ImBuf *ibuf,
void **cache_handle);
@@ -227,24 +313,47 @@ void IMB_display_buffer_transform_apply(unsigned char *display_buffer,
void IMB_display_buffer_release(void *cache_handle);
-/* ** Display functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Display Functions
+ * \{ */
+
int IMB_colormanagement_display_get_named_index(const char *name);
const char *IMB_colormanagement_display_get_indexed_name(int index);
const char *IMB_colormanagement_display_get_default_name(void);
+/**
+ * Used by performance-critical pixel processing areas, such as color widgets.
+ */
struct ColorManagedDisplay *IMB_colormanagement_display_get_named(const char *name);
const char *IMB_colormanagement_display_get_none_name(void);
const char *IMB_colormanagement_display_get_default_view_transform_name(
struct ColorManagedDisplay *display);
-/* ** View functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Functions
+ * \{ */
+
int IMB_colormanagement_view_get_named_index(const char *name);
const char *IMB_colormanagement_view_get_indexed_name(int index);
-/* ** Look functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Look Functions
+ * \{ */
+
int IMB_colormanagement_look_get_named_index(const char *name);
const char *IMB_colormanagement_look_get_indexed_name(int index);
-/* ** Color space functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Space Functions
+ * \{ */
+
int IMB_colormanagement_colorspace_get_named_index(const char *name);
const char *IMB_colormanagement_colorspace_get_indexed_name(int index);
const char *IMB_colormanagement_view_get_default_name(const char *display_name);
@@ -252,7 +361,12 @@ const char *IMB_colormanagement_view_get_default_name(const char *display_name);
void IMB_colormanagement_colorspace_from_ibuf_ftype(
struct ColorManagedColorspaceSettings *colorspace_settings, struct ImBuf *ibuf);
-/* ** RNA helper functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name RNA Helper Functions
+ * \{ */
+
void IMB_colormanagement_display_items_add(struct EnumPropertyItem **items, int *totitem);
void IMB_colormanagement_view_items_add(struct EnumPropertyItem **items,
int *totitem,
@@ -262,7 +376,12 @@ void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items,
const char *view_name);
void IMB_colormanagement_colorspace_items_add(struct EnumPropertyItem **items, int *totitem);
-/* ** Tile-based buffer management ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Tile-based Buffer Management
+ * \{ */
+
void IMB_partial_display_buffer_update(struct ImBuf *ibuf,
const float *linear_buffer,
const unsigned char *byte_buffer,
@@ -293,7 +412,12 @@ void IMB_partial_display_buffer_update_threaded(
void IMB_partial_display_buffer_update_delayed(
struct ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax);
-/* ** Pixel processor functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pixel Processor Functions
+ * \{ */
+
struct ColormanageProcessor *IMB_colormanagement_display_processor_new(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
@@ -321,17 +445,40 @@ void IMB_colormanagement_processor_apply_byte(struct ColormanageProcessor *cm_pr
int channels);
void IMB_colormanagement_processor_free(struct ColormanageProcessor *cm_processor);
-/* ** OpenGL drawing routines using GLSL for color space transform ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name OpenGL Drawing Routines Using GLSL for Color Space Transform
+ * \{ */
-/* Test if GLSL drawing is supported for combination of graphics card and this configuration */
+/**
+ * Test if GLSL drawing is supported for combination of graphics card and this configuration.
+ */
bool IMB_colormanagement_support_glsl_draw(const struct ColorManagedViewSettings *view_settings);
-/* Configures GLSL shader for conversion from scene linear to display space */
+/**
+ * Configures GLSL shader for conversion from scene linear to display space.
+ */
bool IMB_colormanagement_setup_glsl_draw(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
float dither,
bool predivide);
-/* Same as above, but display space conversion happens from a specified space */
+/**
+ * \note Same as IMB_colormanagement_setup_glsl_draw,
+ * but display space conversion happens from a specified space.
+ *
+ * Configures GLSL shader for conversion from specified to
+ * display color space
+ *
+ * Will create appropriate OCIO processor and setup GLSL shader,
+ * so further 2D texture usage will use this conversion.
+ *
+ * When there's no need to apply transform on 2D textures, use
+ * IMB_colormanagement_finish_glsl_draw().
+ *
+ * This is low-level function, use ED_draw_imbuf_ctx if you
+ * only need to display given image buffer
+ */
bool IMB_colormanagement_setup_glsl_draw_from_space(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
@@ -339,20 +486,31 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(
float dither,
bool predivide,
bool do_overlay_merge);
-/* Same as setup_glsl_draw, but color management settings are guessing from a given context */
+/**
+ * Same as setup_glsl_draw, but color management settings are guessing from a given context.
+ */
bool IMB_colormanagement_setup_glsl_draw_ctx(const struct bContext *C,
float dither,
bool predivide);
-/* Same as setup_glsl_draw_from_space,
- * but color management settings are guessing from a given context. */
+/**
+ * Same as `setup_glsl_draw_from_space`,
+ * but color management settings are guessing from a given context.
+ */
bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const struct bContext *C,
struct ColorSpace *colorspace,
float dither,
bool predivide);
-/* Finish GLSL-based display space conversion */
+/**
+ * Finish GLSL-based display space conversion.
+ */
void IMB_colormanagement_finish_glsl_draw(void);
-/* ** View transform ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Transform
+ * \{ */
+
void IMB_colormanagement_init_default_view_settings(
struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
@@ -368,6 +526,8 @@ enum {
COLOR_ROLE_DATA,
};
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index dd8e6549e24..a557d7dc6d1 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -199,6 +199,17 @@ bool addzbuffloatImBuf(struct ImBuf *ibuf);
size_t IMB_get_size_in_memory(struct ImBuf *ibuf);
/**
+ * \brief Get the length of the rect of the given image buffer in terms of pixels.
+ *
+ * This is the width * the height of the image buffer.
+ * This function is preferred over `ibuf->x * ibuf->y` due to overflow issues when
+ * working with large resolution images (30kx30k).
+ *
+ * \attention Defined in allocimbuf.c
+ */
+size_t IMB_get_rect_len(const struct ImBuf *ibuf);
+
+/**
*
* \attention Defined in rectop.c
*/
@@ -244,8 +255,14 @@ void IMB_blend_color_float(float dst[4],
const float src2[4],
IMB_BlendMode mode);
+/**
+ * In-place image crop.
+ */
void IMB_rect_crop(struct ImBuf *ibuf, const struct rcti *crop);
+/**
+ * In-place size setting (caller must fill in buffer contents).
+ */
void IMB_rect_size_set(struct ImBuf *ibuf, const uint size[2]);
void IMB_rectclip(struct ImBuf *dbuf,
@@ -342,7 +359,9 @@ typedef enum eIMBInterpolationFilterMode {
IMB_FILTER_BILINEAR,
} eIMBInterpolationFilterMode;
-/* Defaults to BL_proxy within the directory of the animation. */
+/**
+ * Defaults to BL_proxy within the directory of the animation.
+ */
void IMB_anim_set_index_dir(struct anim *anim, const char *dir);
void IMB_anim_get_fname(struct anim *anim, char *file, int size);
@@ -352,21 +371,28 @@ IMB_Proxy_Size IMB_anim_proxy_get_existing(struct anim *anim);
struct IndexBuildContext;
-/* Prepare context for proxies/time-codes builder. */
+/**
+ * Prepare context for proxies/time-codes builder
+ */
struct IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Timecode_Type tcs_in_use,
IMB_Proxy_Size proxy_sizes_in_use,
int quality,
const bool overwrite,
- struct GSet *file_list);
+ struct GSet *file_list,
+ bool build_only_on_bad_performance);
-/* Will rebuild all used indices and proxies at once. */
+/**
+ * Will rebuild all used indices and proxies at once.
+ */
void IMB_anim_index_rebuild(struct IndexBuildContext *context,
short *stop,
short *do_update,
float *progress);
-/* Finish rebuilding proxies/time-codes and free temporary contexts used. */
+/**
+ * Finish rebuilding proxies/time-codes and free temporary contexts used.
+ */
void IMB_anim_index_rebuild_finish(struct IndexBuildContext *context, short stop);
/**
@@ -406,6 +432,7 @@ bool IMB_anim_can_produce_frames(const struct anim *anim);
int ismovie(const char *filepath);
int IMB_anim_get_image_width(struct anim *anim);
int IMB_anim_get_image_height(struct anim *anim);
+bool IMB_get_gop_decode_time(struct anim *anim);
/**
*
@@ -442,8 +469,20 @@ void IMB_free_anim(struct anim *anim);
void IMB_filter(struct ImBuf *ibuf);
void IMB_mask_filter_extend(char *mask, int width, int height);
void IMB_mask_clear(struct ImBuf *ibuf, const char *mask, int val);
+/**
+ * If alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
+ * When a mask is given, the mask will be used instead of the alpha channel, where only
+ * pixels with a mask value of 0 will be written to, and only pixels with a mask value of 1
+ * will be used for the average. The mask will be set to one for the pixels which were written.
+ */
void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter);
+/**
+ * Frees too (if there) and recreates new data.
+ */
void IMB_makemipmap(struct ImBuf *ibuf, int use_filter);
+/**
+ * Thread-safe version, only recreates existing maps.
+ */
void IMB_remakemipmap(struct ImBuf *ibuf, int use_filter);
struct ImBuf *IMB_getmipmap(struct ImBuf *ibuf, int level);
@@ -452,6 +491,9 @@ struct ImBuf *IMB_getmipmap(struct ImBuf *ibuf, int level);
* \attention Defined in cache.c
*/
+/**
+ * Presumed to be called when no threads are running.
+ */
void IMB_tile_cache_params(int totthread, int maxmem);
unsigned int *IMB_gettile(struct ImBuf *ibuf, int tx, int ty, int thread);
void IMB_tiles_to_rect(struct ImBuf *ibuf);
@@ -471,6 +513,8 @@ struct ImBuf *IMB_onehalf(struct ImBuf *ibuf1);
/**
*
* \attention Defined in scaling.c
+ *
+ * Return true if \a ibuf is modified.
*/
bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
@@ -478,6 +522,9 @@ bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
*
* \attention Defined in scaling.c
*/
+/**
+ * Return true if \a ibuf is modified.
+ */
bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
/**
@@ -491,7 +538,7 @@ void IMB_scaleImBuf_threaded(struct ImBuf *ibuf, unsigned int newx, unsigned int
* \attention Defined in writeimage.c
*/
bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags);
-bool IMB_prepare_write_ImBuf(const bool isfloat, struct ImBuf *ibuf);
+bool IMB_prepare_write_ImBuf(bool isfloat, struct ImBuf *ibuf);
/**
*
@@ -499,7 +546,7 @@ bool IMB_prepare_write_ImBuf(const bool isfloat, struct ImBuf *ibuf);
*/
bool IMB_ispic(const char *filepath);
bool IMB_ispic_type_matches(const char *filepath, int filetype);
-int IMB_ispic_type_from_memory(const unsigned char *buf, const size_t buf_size);
+int IMB_ispic_type_from_memory(const unsigned char *buf, size_t buf_size);
int IMB_ispic_type(const char *filepath);
/**
@@ -520,16 +567,27 @@ int imb_get_anim_type(const char *filepath);
*/
bool IMB_isfloat(const struct ImBuf *ibuf);
-/* Do byte/float and colorspace conversions need to take alpha into account? */
+/**
+ * Test if color-space conversions of pixels in buffer need to take into account alpha.
+ */
bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf);
-/* create char buffer, color corrected if necessary, for ImBufs that lack one */
+/**
+ * Create char buffer, color corrected if necessary, for ImBufs that lack one.
+ */
void IMB_rect_from_float(struct ImBuf *ibuf);
void IMB_float_from_rect(struct ImBuf *ibuf);
+/**
+ * No profile conversion.
+ */
void IMB_color_to_bw(struct ImBuf *ibuf);
void IMB_saturation(struct ImBuf *ibuf, float sat);
-/* converting pixel buffers */
+/* Converting pixel buffers. */
+
+/**
+ * Float to byte pixels, output 4-channel RGBA.
+ */
void IMB_buffer_byte_from_float(unsigned char *rect_to,
const float *rect_from,
int channels_from,
@@ -541,6 +599,9 @@ void IMB_buffer_byte_from_float(unsigned char *rect_to,
int height,
int stride_to,
int stride_from);
+/**
+ * Float to byte pixels, output 4-channel RGBA.
+ */
void IMB_buffer_byte_from_float_mask(unsigned char *rect_to,
const float *rect_from,
int channels_from,
@@ -551,6 +612,9 @@ void IMB_buffer_byte_from_float_mask(unsigned char *rect_to,
int stride_to,
int stride_from,
char *mask);
+/**
+ * Byte to float pixels, input and output 4-channel RGBA.
+ */
void IMB_buffer_float_from_byte(float *rect_to,
const unsigned char *rect_from,
int profile_to,
@@ -560,6 +624,9 @@ void IMB_buffer_float_from_byte(float *rect_to,
int height,
int stride_to,
int stride_from);
+/**
+ * Float to float pixels, output 4-channel RGBA.
+ */
void IMB_buffer_float_from_float(float *rect_to,
const float *rect_from,
int channels_from,
@@ -580,6 +647,9 @@ void IMB_buffer_float_from_float_threaded(float *rect_to,
int height,
int stride_to,
int stride_from);
+/**
+ * Float to float pixels, output 4-channel RGBA.
+ */
void IMB_buffer_float_from_float_mask(float *rect_to,
const float *rect_from,
int channels_from,
@@ -588,6 +658,9 @@ void IMB_buffer_float_from_float_mask(float *rect_to,
int stride_to,
int stride_from,
char *mask);
+/**
+ * Byte to byte pixels, input and output 4-channel RGBA.
+ */
void IMB_buffer_byte_from_byte(unsigned char *rect_to,
const unsigned char *rect_from,
int profile_to,
@@ -605,6 +678,8 @@ void IMB_buffer_float_premultiply(float *buf, int width, int height);
* rgba to abgr. size * 4 color bytes are reordered.
*
* \attention Defined in imageprocess.c
+ *
+ * Only this one is used liberally here, and in imbuf.
*/
void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf);
@@ -612,27 +687,50 @@ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf);
*
* \attention defined in imageprocess.c
*/
+
void bicubic_interpolation(
- struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+ const struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
void nearest_interpolation(
- struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+ const struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
void bilinear_interpolation(
- struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+ const struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+typedef void (*InterpolationColorFunction)(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void bicubic_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+
+/* Functions assumes out to be zeroed, only does RGBA. */
+
+void nearest_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+void nearest_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void nearest_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void nearest_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void bilinear_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+void bilinear_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+void bilinear_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+/**
+ * Note about wrapping, the u/v still needs to be within the image bounds,
+ * just the interpolation is wrapped.
+ * This the same as bilinear_interpolation_color except it wraps
+ * rather than using empty and emptyI.
+ */
void bilinear_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3]);
void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float backcol[3]);
+/**
+ * Sample pixel of image using NEAREST method.
+ */
void IMB_sampleImageAtLocation(
struct ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4]);
@@ -686,7 +784,7 @@ struct ImBuf *IMB_double_y(struct ImBuf *ibuf1);
void IMB_flipx(struct ImBuf *ibuf);
void IMB_flipy(struct ImBuf *ibuf);
-/* Premultiply alpha */
+/* Pre-multiply alpha. */
void IMB_premultiply_alpha(struct ImBuf *ibuf);
void IMB_unpremultiply_alpha(struct ImBuf *ibuf);
@@ -702,7 +800,27 @@ void IMB_freezbuffloatImBuf(struct ImBuf *ibuf);
*
* \attention Defined in rectop.c
*/
+/**
+ * Replace pixels of entire image with solid color.
+ * \param drect: An image to be filled with color. It must be 4 channel image.
+ * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
+ */
void IMB_rectfill(struct ImBuf *drect, const float col[4]);
+/**
+ * Blend pixels of image area with solid color.
+ *
+ * For images with `uchar` buffer use color matching image color-space.
+ * For images with float buffer use color display color-space.
+ * If display color-space can not be referenced, use color in SRGB color-space.
+ *
+ * \param ibuf: an image to be filled with color. It must be 4 channel image.
+ * \param col: RGBA color.
+ * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
+ * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
+ * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
+ * order the area between x1 and x2, and y1 and y2 is filled.
+ * \param display: color-space reference for display space.
+ */
void IMB_rectfill_area(struct ImBuf *ibuf,
const float col[4],
int x1,
@@ -710,12 +828,23 @@ void IMB_rectfill_area(struct ImBuf *ibuf,
int x2,
int y2,
struct ColorManagedDisplay *display);
+/**
+ * Replace pixels of image area with solid color.
+ * \param ibuf: an image to be filled with color. It must be 4 channel image.
+ * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
+ * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
+ * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
+ * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
+ * order the area between x1 and x2, and y1 and y2 is filled.
+ */
void IMB_rectfill_area_replace(
const struct ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2);
-void IMB_rectfill_alpha(struct ImBuf *ibuf, const float value);
+void IMB_rectfill_alpha(struct ImBuf *ibuf, float value);
-/* This should not be here, really,
- * we needed it for operating on render data, IMB_rectfill_area calls it. */
+/**
+ * This should not be here, really,
+ * we needed it for operating on render data, #IMB_rectfill_area calls it.
+ */
void buf_rectfill_area(unsigned char *rect,
float *rectf,
int width,
@@ -727,23 +856,34 @@ void buf_rectfill_area(unsigned char *rect,
int x2,
int y2);
-/* exported for image tools in blender, to quickly allocate 32 bits rect */
+/**
+ * Exported for image tools in blender, to quickly allocate 32 bits rect.
+ */
void *imb_alloc_pixels(
unsigned int x, unsigned int y, unsigned int channels, size_t typesize, const char *name);
bool imb_addrectImBuf(struct ImBuf *ibuf);
+/**
+ * Any free `ibuf->rect` frees mipmaps to be sure, creation is in render on first request.
+ */
void imb_freerectImBuf(struct ImBuf *ibuf);
bool imb_addrectfloatImBuf(struct ImBuf *ibuf);
+/**
+ * Any free `ibuf->rect` frees mipmaps to be sure, creation is in render on first request.
+ */
void imb_freerectfloatImBuf(struct ImBuf *ibuf);
void imb_freemipmapImBuf(struct ImBuf *ibuf);
bool imb_addtilesImBuf(struct ImBuf *ibuf);
void imb_freetilesImBuf(struct ImBuf *ibuf);
+/** Free all pixel data (associated with image size). */
void imb_freerectImbuf_all(struct ImBuf *ibuf);
-/* threaded processors */
+/**
+ * Threaded processors.
+ */
void IMB_processor_apply_threaded(
int buffer_lines,
int handle_size,
@@ -756,13 +896,48 @@ void IMB_processor_apply_threaded_scanlines(int total_scanlines,
ScanlineThreadFunc do_thread,
void *custom_data);
-void IMB_transform(struct ImBuf *src,
+/**
+ * \brief Transform modes to use for IMB_transform function.
+ *
+ * These are not flags as the combination of cropping and repeat can lead to different expectation.
+ */
+typedef enum eIMBTransformMode {
+ /** \brief Do not crop or repeat. */
+ IMB_TRANSFORM_MODE_REGULAR = 0,
+ /** \brief Crop the source buffer. */
+ IMB_TRANSFORM_MODE_CROP_SRC = 1,
+ /** \brief Wrap repeat the source buffer. Only supported in with nearest filtering. */
+ IMB_TRANSFORM_MODE_WRAP_REPEAT = 2,
+} eIMBTransformMode;
+
+/**
+ * \brief Transform source image buffer onto destination image buffer using a transform matrix.
+ *
+ * \param src Image buffer to read from.
+ * \param dst Image buffer to write to. rect or rect_float must already be initialized.
+ * - dst buffer must be a 4 channel buffers.
+ * - Only one data type buffer will be used (rect_float has priority over rect)
+ * \param mode Cropping/Wrap repeat effect to apply during transformation.
+ * \param filter Interpolation to use during sampling.
+ * \param transform_matrix Transformation matrix to use.
+ * The given matrix should transform between dst pixel space to src pixel space.
+ * One unit is one pixel.
+ * \param src_crop cropping region how to crop the source buffer. Should only be passed when mode
+ * is set to #IMB_TRANSFORM_MODE_CROP_SRC. For any other mode this should be empty.
+ *
+ * During transformation no data/color conversion will happens.
+ * When transforming between float images the number of channels of the source buffer may be
+ * between 1 and 4. When source buffer has one channel the data will be read as a gray scale value.
+ */
+void IMB_transform(const struct ImBuf *src,
struct ImBuf *dst,
- float transform_matrix[3][3],
- struct rctf *src_crop,
- const eIMBInterpolationFilterMode filter);
+ eIMBTransformMode mode,
+ eIMBInterpolationFilterMode filter,
+ const float transform_matrix[4][4],
+ const struct rctf *src_crop);
+
+/* FFMPEG */
-/* ffmpeg */
void IMB_ffmpeg_init(void);
const char *IMB_ffmpeg_last_error(void);
@@ -775,8 +950,17 @@ struct GPUTexture *IMB_create_gpu_texture(const char *name,
bool use_high_bitdepth,
bool use_premult,
bool limit_gl_texture_size);
+/**
+ * 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().
+ */
struct GPUTexture *IMB_touch_gpu_texture(
const char *name, struct ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth);
+/**
+ * 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(struct GPUTexture *tex,
struct ImBuf *ibuf,
int x,
@@ -788,36 +972,33 @@ void IMB_update_gpu_texture_sub(struct GPUTexture *tex,
bool use_premult);
/**
- *
* \attention defined in stereoimbuf.c
*/
-void IMB_stereo3d_write_dimensions(const char mode,
- const bool is_squeezed,
- const size_t width,
- const size_t height,
- size_t *r_width,
- size_t *r_height);
-void IMB_stereo3d_read_dimensions(const char mode,
- const bool is_squeezed,
- const size_t width,
- const size_t height,
- size_t *r_width,
- size_t *r_height);
+void IMB_stereo3d_write_dimensions(
+ char mode, bool is_squeezed, size_t width, size_t height, size_t *r_width, size_t *r_height);
+void IMB_stereo3d_read_dimensions(
+ char mode, bool is_squeezed, size_t width, size_t height, size_t *r_width, size_t *r_height);
int *IMB_stereo3d_from_rect(struct ImageFormatData *im_format,
- const size_t x,
- const size_t y,
- const size_t channels,
+ size_t x,
+ size_t y,
+ size_t channels,
int *rect_left,
int *rect_right);
float *IMB_stereo3d_from_rectf(struct ImageFormatData *im_format,
- const size_t x,
- const size_t y,
- const size_t channels,
+ size_t x,
+ size_t y,
+ size_t channels,
float *rectf_left,
float *rectf_right);
+/**
+ * Left/right are always float.
+ */
struct ImBuf *IMB_stereo3d_ImBuf(struct ImageFormatData *im_format,
struct ImBuf *ibuf_left,
struct ImBuf *ibuf_right);
+/**
+ * Reading a stereo encoded ibuf (*left) and generating two ibufs from it (*left and *right).
+ */
void IMB_ImBufFromStereo3d(struct Stereo3dFormat *s3d,
struct ImBuf *ibuf_stereo,
struct ImBuf **r_ibuf_left,
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 9697064b445..58148743b7e 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -143,10 +143,9 @@ typedef struct ImbFormatOptions {
char quality;
} ImbFormatOptions;
-/**
- * \name Imbuf Component flags
+/* -------------------------------------------------------------------- */
+/** \name Imbuf Component flags
* \brief These flags determine the components of an ImBuf struct.
- *
* \{ */
typedef enum eImBufFlags {
@@ -175,6 +174,11 @@ typedef enum eImBufFlags {
} eImBufFlags;
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Buffer
+ * \{ */
+
typedef struct ImBuf {
struct ImBuf *next, *prev; /** < allow lists of #ImBufs, for caches or flip-books. */
@@ -301,11 +305,14 @@ enum {
IB_PERSISTENT = (1 << 5),
};
-/**
- * \name Imbuf preset profile tags
- * \brief Some predefined color space profiles that 8 bit imbufs can represent
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Imbuf Preset Profile Tags
*
+ * \brief Some predefined color space profiles that 8 bit imbufs can represent.
* \{ */
+
#define IB_PROFILE_NONE 0
#define IB_PROFILE_LINEAR_RGB 1
#define IB_PROFILE_SRGB 2
@@ -322,7 +329,7 @@ enum {
# endif /* DDS_MAKEFOURCC */
/*
- * FOURCC codes for DX compressed-texture pixel formats
+ * FOURCC codes for DX compressed-texture pixel formats.
*/
# define FOURCC_DDS (DDS_MAKEFOURCC('D', 'D', 'S', ' '))
@@ -337,13 +344,13 @@ extern const char *imb_ext_image[];
extern const char *imb_ext_movie[];
extern const char *imb_ext_audio[];
-/* image formats that can only be loaded via filepath */
+/** Image formats that can only be loaded via filepath. */
extern const char *imb_ext_image_filepath_only[];
-/**
- * \name Imbuf Color Management Flag
- * \brief Used with #ImBuf.colormanage_flag
+/* -------------------------------------------------------------------- */
+/** \name Imbuf Color Management Flag
*
+ * \brief Used with #ImBuf.colormanage_flag
* \{ */
enum {
diff --git a/source/blender/imbuf/IMB_metadata.h b/source/blender/imbuf/IMB_metadata.h
index 652ce913ee5..50982d08c3e 100644
--- a/source/blender/imbuf/IMB_metadata.h
+++ b/source/blender/imbuf/IMB_metadata.h
@@ -58,10 +58,7 @@ void IMB_metadata_free(struct IDProperty *metadata);
* \param len: length of value buffer allocated by user.
* \return 1 (true) if metadata is present and value for the key found, 0 (false) otherwise.
*/
-bool IMB_metadata_get_field(struct IDProperty *metadata,
- const char *key,
- char *value,
- const size_t len);
+bool IMB_metadata_get_field(struct IDProperty *metadata, const char *key, char *value, size_t len);
/**
* Set user data in the metadata.
diff --git a/source/blender/imbuf/IMB_moviecache.h b/source/blender/imbuf/IMB_moviecache.h
index 8e5f15a64a0..156a060c621 100644
--- a/source/blender/imbuf/IMB_moviecache.h
+++ b/source/blender/imbuf/IMB_moviecache.h
@@ -59,7 +59,7 @@ void IMB_moviecache_set_priority_callback(struct MovieCache *cache,
void IMB_moviecache_put(struct MovieCache *cache, void *userkey, struct ImBuf *ibuf);
bool IMB_moviecache_put_if_possible(struct MovieCache *cache, void *userkey, struct ImBuf *ibuf);
-struct ImBuf *IMB_moviecache_get(struct MovieCache *cache, void *userkey);
+struct ImBuf *IMB_moviecache_get(struct MovieCache *cache, void *userkey, bool *r_is_cached_empty);
void IMB_moviecache_remove(struct MovieCache *cache, void *userkey);
bool IMB_moviecache_has_frame(struct MovieCache *cache, void *userkey);
void IMB_moviecache_free(struct MovieCache *cache);
@@ -70,6 +70,9 @@ void IMB_moviecache_cleanup(struct MovieCache *cache,
void *userdata),
void *userdata);
+/**
+ * Get segments of cached frames. Useful for debugging cache policies.
+ */
void IMB_moviecache_get_cache_segments(
struct MovieCache *cache, int proxy, int render_flags, int *r_totseg, int **r_points);
diff --git a/source/blender/imbuf/IMB_thumbs.h b/source/blender/imbuf/IMB_thumbs.h
index e1a315a0bd2..6a739002fb3 100644
--- a/source/blender/imbuf/IMB_thumbs.h
+++ b/source/blender/imbuf/IMB_thumbs.h
@@ -48,47 +48,66 @@ typedef enum ThumbSource {
THB_SOURCE_FONT,
} ThumbSource;
-/* don't generate thumbs for images bigger than this (100mb) */
+/**
+ * Don't generate thumbs for images bigger than this (100mb).
+ */
#define THUMB_SIZE_MAX (100 * 1024 * 1024)
#define PREVIEW_RENDER_DEFAULT_HEIGHT 128
#define PREVIEW_RENDER_LARGE_HEIGHT 256
-/* Note this can also be used as versioning system,
+/**
+ * Note this can also be used as versioning system,
* to force refreshing all thumbnails if e.g. we change some thumb generating code or so.
- * Only used by fonts so far. */
+ * Only used by fonts so far.
+ */
#define THUMB_DEFAULT_HASH "00000000000000000000000000000000"
-/* create thumbnail for file and returns new imbuf for thumbnail */
+/**
+ * Create thumbnail for file and returns new imbuf for thumbnail.
+ */
struct ImBuf *IMB_thumb_create(const char *path,
ThumbSize size,
ThumbSource source,
struct ImBuf *img);
-/* read thumbnail for file and returns new imbuf for thumbnail */
+/**
+ * Read thumbnail for file and returns new imbuf for thumbnail.
+ */
struct ImBuf *IMB_thumb_read(const char *path, ThumbSize size);
-/* delete all thumbs for the file */
+/**
+ * Delete all thumbs for the file.
+ */
void IMB_thumb_delete(const char *path, ThumbSize size);
-/* return the state of the thumb, needed to determine how to manage the thumb */
+/**
+ * Create the thumb if necessary and manage failed and old thumbs.
+ */
struct ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source);
-/* create the necessary dirs to store the thumbnails */
+/**
+ * Create the necessary dirs to store the thumbnails.
+ */
void IMB_thumb_makedirs(void);
-/* special function for loading a thumbnail embedded into a blend file */
+/**
+ * Special function for loading a thumbnail embedded into a blend file.
+ */
struct ImBuf *IMB_thumb_load_blend(const char *blen_path,
const char *blen_group,
const char *blen_id);
-/* special function for previewing fonts */
+/**
+ * Special function for previewing fonts.
+ */
struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y);
bool IMB_thumb_load_font_get_hash(char *r_hash);
void IMB_thumb_clear_translations(void);
void IMB_thumb_ensure_translations(void);
/* Threading */
+
void IMB_thumb_locks_acquire(void);
void IMB_thumb_locks_release(void);
void IMB_thumb_path_lock(const char *path);
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index c8f6135f330..bf6aef3ecd3 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -22,7 +22,9 @@
#include "IMB_imbuf.h"
-/* Generic File Type */
+/* -------------------------------------------------------------------- */
+/** \name Generic File Type
+ * \{ */
struct ImBuf;
@@ -39,7 +41,7 @@ typedef struct ImFileType {
* \note that this may only read in a small part of the files header,
* see: #IMB_ispic_type for details.
*/
- bool (*is_a)(const unsigned char *buf, const size_t size);
+ bool (*is_a)(const unsigned char *buf, size_t size);
/** Load an image from memory. */
struct ImBuf *(*load)(const unsigned char *mem,
@@ -78,36 +80,62 @@ void imb_tile_cache_init(void);
void imb_tile_cache_exit(void);
void imb_loadtile(struct ImBuf *ibuf, int tx, int ty, unsigned int *rect);
+/**
+ * External free.
+ */
void imb_tile_cache_tile_free(struct ImBuf *ibuf, int tx, int ty);
+/** \} */
+
/* Type Specific Functions */
-/* png */
-bool imb_is_a_png(const unsigned char *mem, const size_t size);
+/* -------------------------------------------------------------------- */
+/** \name Format: PNG (#IMB_FTYPE_PNG)
+ * \{ */
+
+bool imb_is_a_png(const unsigned char *mem, size_t size);
struct ImBuf *imb_loadpng(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_savepng(struct ImBuf *ibuf, const char *filepath, int flags);
-/* targa */
-bool imb_is_a_targa(const unsigned char *buf, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: TARGA (#IMB_FTYPE_TGA)
+ * \{ */
+
+bool imb_is_a_targa(const unsigned char *buf, size_t size);
struct ImBuf *imb_loadtarga(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_savetarga(struct ImBuf *ibuf, const char *filepath, int flags);
-/* iris */
-bool imb_is_a_iris(const unsigned char *mem, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: IRIS (#IMB_FTYPE_IMAGIC)
+ * \{ */
+
+bool imb_is_a_iris(const unsigned char *mem, size_t size);
+/**
+ * Read in a B/W RGB or RGBA iris image file and return an image buffer.
+ */
struct ImBuf *imb_loadiris(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_saveiris(struct ImBuf *ibuf, const char *filepath, int flags);
-/* jp2 */
-bool imb_is_a_jp2(const unsigned char *buf, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: JP2 (#IMB_FTYPE_JP2)
+ * \{ */
+
+bool imb_is_a_jp2(const unsigned char *buf, size_t size);
struct ImBuf *imb_load_jp2(const unsigned char *mem,
size_t size,
int flags,
@@ -117,53 +145,110 @@ struct ImBuf *imb_load_jp2_filepath(const char *filepath,
char colorspace[IM_MAX_SPACE]);
bool imb_save_jp2(struct ImBuf *ibuf, const char *filepath, int flags);
-/* jpeg */
-bool imb_is_a_jpeg(const unsigned char *mem, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: JPEG (#IMB_FTYPE_JPG)
+ * \{ */
+
+bool imb_is_a_jpeg(const unsigned char *mem, size_t size);
bool imb_savejpeg(struct ImBuf *ibuf, const char *filepath, int flags);
struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
-/* bmp */
-bool imb_is_a_bmp(const unsigned char *buf, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: BMP (#IMB_FTYPE_BMP)
+ * \{ */
+
+bool imb_is_a_bmp(const unsigned char *buf, size_t size);
struct ImBuf *imb_bmp_decode(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
+/* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
bool imb_savebmp(struct ImBuf *ibuf, const char *filepath, int flags);
-/* cineon */
-bool imb_is_a_cineon(const unsigned char *buf, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: CINEON (#IMB_FTYPE_CINEON)
+ * \{ */
+
+bool imb_is_a_cineon(const unsigned char *buf, size_t size);
bool imb_save_cineon(struct ImBuf *buf, const char *filepath, int flags);
struct ImBuf *imb_load_cineon(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
-/* dpx */
-bool imb_is_a_dpx(const unsigned char *buf, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: DPX (#IMB_FTYPE_DPX)
+ * \{ */
+
+bool imb_is_a_dpx(const unsigned char *buf, size_t size);
bool imb_save_dpx(struct ImBuf *buf, const char *filepath, int flags);
struct ImBuf *imb_load_dpx(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
-/* hdr */
-bool imb_is_a_hdr(const unsigned char *buf, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: HDR (#IMB_FTYPE_RADHDR)
+ * \{ */
+
+bool imb_is_a_hdr(const unsigned char *buf, size_t size);
struct ImBuf *imb_loadhdr(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_savehdr(struct ImBuf *ibuf, const char *filepath, int flags);
-/* tiff */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: TIFF (#IMB_FTYPE_TIF)
+ * \{ */
+
void imb_inittiff(void);
-bool imb_is_a_tiff(const unsigned char *buf, const size_t size);
+bool imb_is_a_tiff(const unsigned char *buf, size_t size);
+/**
+ * Loads a TIFF file.
+ * \param mem: Memory containing the TIFF file.
+ * \param size: Size of the mem buffer.
+ * \param flags: If flags has IB_test set then the file is not actually loaded,
+ * but all other operations take place.
+ *
+ * \return A newly allocated #ImBuf structure if successful, otherwise NULL.
+ */
struct ImBuf *imb_loadtiff(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
void imb_loadtiletiff(
struct ImBuf *ibuf, const unsigned char *mem, size_t size, int tx, int ty, unsigned int *rect);
+/**
+ * Saves a TIFF file.
+ *
+ * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA
+ * respectively) are accepted, and interpreted correctly. Note that the TIFF
+ * convention is to use pre-multiplied alpha, which can be achieved within
+ * Blender by setting "Premul" alpha handling. Other alpha conventions are
+ * not strictly correct, but are permitted anyhow.
+ *
+ * \param ibuf: Image buffer.
+ * \param filepath: Name of the TIFF file to create.
+ * \param flags: Currently largely ignored.
+ *
+ * \return 1 if the function is successful, 0 on failure.
+ */
bool imb_savetiff(struct ImBuf *ibuf, const char *filepath, int flags);
+
+/** \} */
diff --git a/source/blender/imbuf/intern/IMB_filter.h b/source/blender/imbuf/intern/IMB_filter.h
index 556362d78c1..434750e6736 100644
--- a/source/blender/imbuf/intern/IMB_filter.h
+++ b/source/blender/imbuf/intern/IMB_filter.h
@@ -34,4 +34,7 @@ void IMB_premultiply_rect_float(float *rect_float, int channels, int w, int h);
void IMB_unpremultiply_rect(unsigned int *rect, char planes, int w, int h);
void IMB_unpremultiply_rect_float(float *rect_float, int channels, int w, int h);
+/**
+ * Result in ibuf2, scaling should be done correctly.
+ */
void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1);
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 1369f8cc0f8..197d7e6b1d5 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -93,7 +93,6 @@ void imb_freemipmapImBuf(ImBuf *ibuf)
ibuf->miptot = 0;
}
-/* any free rect frees mipmaps to be sure, creation is in render on first request */
void imb_freerectfloatImBuf(ImBuf *ibuf)
{
if (ibuf == NULL) {
@@ -111,7 +110,6 @@ void imb_freerectfloatImBuf(ImBuf *ibuf)
ibuf->mall &= ~IB_rectfloat;
}
-/* any free rect frees mipmaps to be sure, creation is in render on first request */
void imb_freerectImBuf(ImBuf *ibuf)
{
if (ibuf == NULL) {
@@ -197,7 +195,6 @@ void IMB_freezbuffloatImBuf(ImBuf *ibuf)
ibuf->mall &= ~IB_zbuffloat;
}
-/** Free all pixel data (associated with image size). */
void imb_freerectImbuf_all(ImBuf *ibuf)
{
imb_freerectImBuf(ibuf);
@@ -403,9 +400,10 @@ bool imb_addrectfloatImBuf(ImBuf *ibuf)
return false;
}
-/* question; why also add zbuf? */
bool imb_addrectImBuf(ImBuf *ibuf)
{
+ /* Question; why also add ZBUF (when `planes > 32`)? */
+
if (ibuf == NULL) {
return false;
}
@@ -430,9 +428,6 @@ bool imb_addrectImBuf(ImBuf *ibuf)
return false;
}
-/**
- * \param take_ownership: When true, the buffers become owned by the resulting image.
- */
struct ImBuf *IMB_allocFromBufferOwn(
unsigned int *rect, float *rectf, unsigned int w, unsigned int h, unsigned int channels)
{
@@ -580,7 +575,6 @@ bool IMB_initImBuf(
return true;
}
-/* does no zbuffers? */
ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
{
ImBuf *ibuf2, tbuf;
@@ -669,6 +663,11 @@ ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
return ibuf2;
}
+size_t IMB_get_rect_len(const ImBuf *ibuf)
+{
+ return (size_t)ibuf->x * (size_t)ibuf->y;
+}
+
size_t IMB_get_size_in_memory(ImBuf *ibuf)
{
int a;
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 13f9356751e..17e82fc79c9 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -58,6 +58,8 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "DNA_scene_types.h"
+
#include "MEM_guardedalloc.h"
#ifdef WITH_AVI
@@ -502,11 +504,6 @@ static ImBuf *avi_fetchibuf(struct anim *anim, int position)
#ifdef WITH_FFMPEG
-BLI_INLINE bool need_aligned_ffmpeg_buffer(struct anim *anim)
-{
- return (anim->x & 31) != 0;
-}
-
static int startffmpeg(struct anim *anim)
{
int i, video_stream_index;
@@ -705,23 +702,20 @@ static int startffmpeg(struct anim *anim)
anim->pFrameComplete = false;
anim->pFrameDeinterlaced = av_frame_alloc();
anim->pFrameRGB = av_frame_alloc();
+ anim->pFrameRGB->format = AV_PIX_FMT_RGBA;
+ anim->pFrameRGB->width = anim->x;
+ anim->pFrameRGB->height = anim->y;
- if (need_aligned_ffmpeg_buffer(anim)) {
- anim->pFrameRGB->format = AV_PIX_FMT_RGBA;
- anim->pFrameRGB->width = anim->x;
- anim->pFrameRGB->height = anim->y;
-
- if (av_frame_get_buffer(anim->pFrameRGB, 32) < 0) {
- fprintf(stderr, "Could not allocate frame data.\n");
- avcodec_free_context(&anim->pCodecCtx);
- avformat_close_input(&anim->pFormatCtx);
- av_packet_free(&anim->cur_packet);
- av_frame_free(&anim->pFrameRGB);
- av_frame_free(&anim->pFrameDeinterlaced);
- av_frame_free(&anim->pFrame);
- anim->pCodecCtx = NULL;
- return -1;
- }
+ if (av_frame_get_buffer(anim->pFrameRGB, 0) < 0) {
+ fprintf(stderr, "Could not allocate frame data.\n");
+ avcodec_free_context(&anim->pCodecCtx);
+ avformat_close_input(&anim->pFormatCtx);
+ av_packet_free(&anim->cur_packet);
+ av_frame_free(&anim->pFrameRGB);
+ av_frame_free(&anim->pFrameDeinterlaced);
+ av_frame_free(&anim->pFrame);
+ anim->pCodecCtx = NULL;
+ return -1;
}
if (av_image_get_buffer_size(AV_PIX_FMT_RGBA, anim->x, anim->y, 1) != anim->x * anim->y * 4) {
@@ -849,104 +843,61 @@ static void ffmpeg_postprocess(struct anim *anim)
}
}
- if (!need_aligned_ffmpeg_buffer(anim)) {
- av_image_fill_arrays(anim->pFrameRGB->data,
- anim->pFrameRGB->linesize,
- (unsigned char *)ibuf->rect,
- AV_PIX_FMT_RGBA,
- anim->x,
- anim->y,
- 1);
- }
-
-# if defined(__x86_64__) || defined(_M_X64)
- /* Scale and flip image over Y axis in one go, using negative strides.
- * This doesn't work with ARM/PowerPC though and may be misusing the API.
- * Limit it x86_64 where it appears to work.
- * http://trac.ffmpeg.org/ticket/9060 */
- int *dstStride = anim->pFrameRGB->linesize;
- uint8_t **dst = anim->pFrameRGB->data;
- const int dstStride2[4] = {-dstStride[0], 0, 0, 0};
- uint8_t *dst2[4] = {dst[0] + (anim->y - 1) * dstStride[0], 0, 0, 0};
-
- sws_scale(anim->img_convert_ctx,
- (const uint8_t *const *)input->data,
- input->linesize,
- 0,
- anim->y,
- dst2,
- dstStride2);
-# else
- /* Scale with swscale then flip image over Y axis. */
- int *dstStride = anim->pFrameRGB->linesize;
- uint8_t **dst = anim->pFrameRGB->data;
- const int dstStride2[4] = {dstStride[0], 0, 0, 0};
- uint8_t *dst2[4] = {dst[0], 0, 0, 0};
- int x, y, h, w;
- unsigned char *bottom;
- unsigned char *top;
-
sws_scale(anim->img_convert_ctx,
(const uint8_t *const *)input->data,
input->linesize,
0,
anim->y,
- dst2,
- dstStride2);
-
- bottom = (unsigned char *)ibuf->rect;
- top = bottom + ibuf->x * (ibuf->y - 1) * 4;
-
- h = (ibuf->y + 1) / 2;
- w = ibuf->x;
-
- for (y = 0; y < h; y++) {
- unsigned char tmp[4];
- unsigned int *tmp_l = (unsigned int *)tmp;
-
- for (x = 0; x < w; x++) {
- tmp[0] = bottom[0];
- tmp[1] = bottom[1];
- tmp[2] = bottom[2];
- tmp[3] = bottom[3];
-
- bottom[0] = top[0];
- bottom[1] = top[1];
- bottom[2] = top[2];
- bottom[3] = top[3];
-
- *(unsigned int *)top = *tmp_l;
-
- bottom += 4;
- top += 4;
- }
- top -= 8 * w;
+ anim->pFrameRGB->data,
+ anim->pFrameRGB->linesize);
+
+ /* Copy the valid bytes from the aligned buffer vertically flipped into ImBuf */
+ int aligned_stride = anim->pFrameRGB->linesize[0];
+ const uint8_t *const src[4] = {
+ anim->pFrameRGB->data[0] + (anim->y - 1) * aligned_stride, 0, 0, 0};
+ /* NOTE: Negative linesize is used to copy and flip image at once with function
+ * `av_image_copy_to_buffer`. This could cause issues in future and image may need to be flipped
+ * explicitly. */
+ const int src_linesize[4] = {-anim->pFrameRGB->linesize[0], 0, 0, 0};
+ int dst_size = av_image_get_buffer_size(
+ anim->pFrameRGB->format, anim->pFrameRGB->width, anim->pFrameRGB->height, 1);
+ av_image_copy_to_buffer(
+ (uint8_t *)ibuf->rect, dst_size, src, src_linesize, AV_PIX_FMT_RGBA, anim->x, anim->y, 1);
+ if (filter_y) {
+ IMB_filtery(ibuf);
}
-# endif
+}
- if (need_aligned_ffmpeg_buffer(anim)) {
- uint8_t *buf_src = anim->pFrameRGB->data[0];
- uint8_t *buf_dst = (uint8_t *)ibuf->rect;
- for (int y = 0; y < anim->y; y++) {
- memcpy(buf_dst, buf_src, anim->x * 4);
- buf_dst += anim->x * 4;
- buf_src += anim->pFrameRGB->linesize[0];
- }
- }
+static void ffmpeg_decode_store_frame_pts(struct anim *anim)
+{
+ anim->cur_pts = av_get_pts_from_frame(anim->pFrame);
- if (filter_y) {
- IMB_filtery(ibuf);
+ if (anim->pFrame->key_frame) {
+ anim->cur_key_frame_pts = anim->cur_pts;
}
+
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ " FRAME DONE: cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
+ (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts,
+ (int64_t)anim->cur_pts);
}
/* decode one video frame also considering the packet read into cur_packet */
-
static int ffmpeg_decode_video_frame(struct anim *anim)
{
- int rval = 0;
-
av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE VIDEO FRAME\n");
+ /* Sometimes, decoder returns more than one frame per sent packet. Check if frames are available.
+ * This frames must be read, otherwise decoding will fail. See T91405. */
+ anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
+ if (anim->pFrameComplete) {
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE FROM CODEC BUFFER\n");
+ ffmpeg_decode_store_frame_pts(anim);
+ return 1;
+ }
+
+ int rval = 0;
if (anim->cur_packet->stream_index == anim->videoStream) {
av_packet_unref(anim->cur_packet);
anim->cur_packet->stream_index = -1;
@@ -963,22 +914,11 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
(anim->cur_packet->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->cur_packet->pts,
(anim->cur_packet->flags & AV_PKT_FLAG_KEY) ? " KEY" : "");
if (anim->cur_packet->stream_index == anim->videoStream) {
- anim->pFrameComplete = 0;
-
avcodec_send_packet(anim->pCodecCtx, anim->cur_packet);
anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
if (anim->pFrameComplete) {
- anim->cur_pts = av_get_pts_from_frame(anim->pFrame);
-
- if (anim->pFrame->key_frame) {
- anim->cur_key_frame_pts = anim->cur_pts;
- }
- av_log(anim->pFormatCtx,
- AV_LOG_DEBUG,
- " FRAME DONE: cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
- (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts,
- (int64_t)anim->cur_pts);
+ ffmpeg_decode_store_frame_pts(anim);
break;
}
}
@@ -988,22 +928,11 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
if (rval == AVERROR_EOF) {
/* Flush any remaining frames out of the decoder. */
- anim->pFrameComplete = 0;
-
avcodec_send_packet(anim->pCodecCtx, NULL);
anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
if (anim->pFrameComplete) {
- anim->cur_pts = av_get_pts_from_frame(anim->pFrame);
-
- if (anim->pFrame->key_frame) {
- anim->cur_key_frame_pts = anim->cur_pts;
- }
- av_log(anim->pFormatCtx,
- AV_LOG_DEBUG,
- " FRAME DONE (after EOF): cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
- (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts,
- (int64_t)anim->cur_pts);
+ ffmpeg_decode_store_frame_pts(anim);
rval = 0;
}
}
@@ -1443,7 +1372,15 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ
*
* The issue was reported to FFmpeg under ticket #8747 in the FFmpeg tracker
* and is fixed in the newer versions than 4.3.1. */
- anim->cur_frame_final = IMB_allocImBuf(anim->x, anim->y, 32, 0);
+
+ const AVPixFmtDescriptor *pix_fmt_descriptor = av_pix_fmt_desc_get(anim->pCodecCtx->pix_fmt);
+
+ int planes = R_IMF_PLANES_RGBA;
+ if ((pix_fmt_descriptor->flags & AV_PIX_FMT_FLAG_ALPHA) == 0) {
+ planes = R_IMF_PLANES_RGB;
+ }
+
+ anim->cur_frame_final = IMB_allocImBuf(anim->x, anim->y, planes, 0);
anim->cur_frame_final->rect = MEM_mallocN_aligned(
(size_t)4 * anim->x * anim->y, 32, "ffmpeg ibuf");
anim->cur_frame_final->mall |= IB_rect;
@@ -1471,20 +1408,6 @@ static void free_anim_ffmpeg(struct anim *anim)
av_packet_free(&anim->cur_packet);
av_frame_free(&anim->pFrame);
-
- if (!need_aligned_ffmpeg_buffer(anim)) {
- /* If there's no need for own aligned buffer it means that FFmpeg's
- * frame shares the same buffer as temporary ImBuf. In this case we
- * should not free the buffer when freeing the FFmpeg buffer.
- */
- av_image_fill_arrays(anim->pFrameRGB->data,
- anim->pFrameRGB->linesize,
- NULL,
- AV_PIX_FMT_RGBA,
- anim->x,
- anim->y,
- 1);
- }
av_frame_free(&anim->pFrameRGB);
av_frame_free(&anim->pFrameDeinterlaced);
@@ -1496,16 +1419,16 @@ static void free_anim_ffmpeg(struct anim *anim)
#endif
-/* Try next picture to read */
-/* No picture, try to open next animation */
-/* Succeed, remove first image from animation */
-
-static ImBuf *anim_getnew(struct anim *anim)
+/**
+ * Try to initialize the #anim struct.
+ * Returns true on success.
+ */
+static bool anim_getnew(struct anim *anim)
{
- struct ImBuf *ibuf = NULL;
-
+ BLI_assert(anim->curtype == ANIM_NONE);
if (anim == NULL) {
- return NULL;
+ /* Nothing to initialize. */
+ return false;
}
free_anim_movie(anim);
@@ -1518,44 +1441,43 @@ static ImBuf *anim_getnew(struct anim *anim)
free_anim_ffmpeg(anim);
#endif
- if (anim->curtype != 0) {
- return NULL;
- }
anim->curtype = imb_get_anim_type(anim->name);
switch (anim->curtype) {
- case ANIM_SEQUENCE:
- ibuf = IMB_loadiffname(anim->name, anim->ib_flags, anim->colorspace);
+ case ANIM_SEQUENCE: {
+ ImBuf *ibuf = IMB_loadiffname(anim->name, anim->ib_flags, anim->colorspace);
if (ibuf) {
BLI_strncpy(anim->first, anim->name, sizeof(anim->first));
anim->duration_in_frames = 1;
+ IMB_freeImBuf(ibuf);
+ }
+ else {
+ return false;
}
break;
+ }
case ANIM_MOVIE:
if (startmovie(anim)) {
- return NULL;
+ return false;
}
- ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0); /* fake */
break;
#ifdef WITH_AVI
case ANIM_AVI:
if (startavi(anim)) {
printf("couldn't start avi\n");
- return NULL;
+ return false;
}
- ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0);
break;
#endif
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
if (startffmpeg(anim)) {
- return 0;
+ return false;
}
- ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0);
break;
#endif
}
- return ibuf;
+ return true;
}
struct ImBuf *IMB_anim_previewframe(struct anim *anim)
@@ -1589,14 +1511,10 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim,
filter_y = (anim->ib_flags & IB_animdeinterlace);
if (preview_size == IMB_PROXY_NONE) {
- if (anim->curtype == 0) {
- ibuf = anim_getnew(anim);
- if (ibuf == NULL) {
+ if (anim->curtype == ANIM_NONE) {
+ if (!anim_getnew(anim)) {
return NULL;
}
-
- IMB_freeImBuf(ibuf); /* ???? */
- ibuf = NULL;
}
if (position < 0) {
diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c
index 70bb70ec4fa..b44b12999bf 100644
--- a/source/blender/imbuf/intern/bmp.c
+++ b/source/blender/imbuf/intern/bmp.c
@@ -151,8 +151,7 @@ ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[
}
/* Validate and cross-check offsets and sizes. */
- if (x < 1 ||
- !(depth == 1 || depth == 4 || depth == 8 || depth == 16 || depth == 24 || depth == 32)) {
+ if (x < 1 || !(ELEM(depth, 1, 4, 8, 16, 24, 32))) {
return NULL;
}
@@ -307,7 +306,6 @@ static int putShortLSB(ushort us, FILE *ofile)
return putc((us >> 8) & 0xFF, ofile);
}
-/* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
bool imb_savebmp(ImBuf *ibuf, const char *filepath, int UNUSED(flags))
{
BMPINFOHEADER infoheader;
diff --git a/source/blender/imbuf/intern/cache.c b/source/blender/imbuf/intern/cache.c
index 02d1fe3710a..ce11e1c3f80 100644
--- a/source/blender/imbuf/intern/cache.c
+++ b/source/blender/imbuf/intern/cache.c
@@ -153,7 +153,6 @@ static void imb_global_cache_tile_unload(ImGlobalTile *gtile)
GLOBAL_CACHE.totmem -= sizeof(unsigned int) * ibuf->tilex * ibuf->tiley;
}
-/* external free */
void imb_tile_cache_tile_free(ImBuf *ibuf, int tx, int ty)
{
ImGlobalTile *gtile, lookuptile;
@@ -248,7 +247,6 @@ void imb_tile_cache_exit(void)
}
}
-/* presumed to be called when no threads are running */
void IMB_tile_cache_params(int totthread, int maxmem)
{
int a;
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c
index 1223033f535..758b21f8cda 100644
--- a/source/blender/imbuf/intern/cineon/cineonlib.c
+++ b/source/blender/imbuf/intern/cineon/cineonlib.c
@@ -239,13 +239,13 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t
}
if (cineon->depth == 1) {
- /* Grayscale image */
+ /* Gray-scale image. */
cineon->element[0].descriptor = descriptor_Luminance;
cineon->element[0].transfer = transfer_Linear;
cineon->element[0].depth = 1;
}
else if (cineon->depth == 3) {
- /* RGB image */
+ /* RGB image. */
if (cineon->numElements == 1) {
cineon->element[0].descriptor = descriptor_RGB;
cineon->element[0].transfer = transfer_PrintingDensity;
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 119ef3ff971..6e9e5dd3ddb 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -342,7 +342,7 @@ static ImBuf *colormanage_cache_get_ibuf(ImBuf *ibuf,
*cache_handle = NULL;
- cache_ibuf = IMB_moviecache_get(moviecache, key);
+ cache_ibuf = IMB_moviecache_get(moviecache, key, NULL);
*cache_handle = cache_ibuf;
@@ -1968,7 +1968,6 @@ static void colormanagement_transform_ex(unsigned char *byte_buffer,
IMB_colormanagement_processor_free(cm_processor);
}
-/* convert the whole buffer from specified by name color space to another */
void IMB_colormanagement_transform(float *buffer,
int width,
int height,
@@ -1981,9 +1980,6 @@ void IMB_colormanagement_transform(float *buffer,
NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false);
}
-/* convert the whole buffer from specified by name color space to another
- * will do threaded conversion
- */
void IMB_colormanagement_transform_threaded(float *buffer,
int width,
int height,
@@ -1996,7 +1992,6 @@ void IMB_colormanagement_transform_threaded(float *buffer,
NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true);
}
-/* Similar to functions above, but operates on byte buffer. */
void IMB_colormanagement_transform_byte(unsigned char *buffer,
int width,
int height,
@@ -2018,7 +2013,6 @@ void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer,
buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, true);
}
-/* Similar to above, but gets float buffer from display one. */
void IMB_colormanagement_transform_from_byte(float *float_buffer,
unsigned char *byte_buffer,
int width,
@@ -2098,9 +2092,6 @@ void IMB_colormanagement_transform_v4(float pixel[4],
IMB_colormanagement_processor_free(cm_processor);
}
-/* convert pixel from specified by descriptor color space to scene linear
- * used by performance-critical areas such as renderer and baker
- */
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpace *colorspace)
{
OCIO_ConstCPUProcessorRcPtr *processor;
@@ -2118,7 +2109,6 @@ void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpac
}
}
-/* same as above, but converts colors in opposite direction */
void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], ColorSpace *colorspace)
{
OCIO_ConstCPUProcessorRcPtr *processor;
@@ -2315,14 +2305,6 @@ void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
}
}
-/* Conversion between color picking role. Typically we would expect such a
- * requirements:
- * - It is approximately perceptually linear, so that the HSV numbers and
- * the HSV cube/circle have an intuitive distribution.
- * - It has the same gamut as the scene linear color space.
- * - Color picking values 0..1 map to scene linear values in the 0..1 range,
- * so that picked albedo values are energy conserving.
- */
void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3])
{
if (!global_color_picking_state.cpu_processor_to && !global_color_picking_state.failed) {
@@ -2377,8 +2359,6 @@ void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3])
}
}
-/* Conversion between sRGB, for rare cases like hex color or copy/pasting
- * between UI theme and scene linear colors. */
void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3])
{
mul_m3_v3(imbuf_rgb_to_xyz, pixel);
@@ -2393,10 +2373,6 @@ void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3])
mul_m3_v3(imbuf_xyz_to_rgb, pixel);
}
-/* convert pixel from scene linear to display space using default view
- * used by performance-critical areas such as color-related widgets where we want to reduce
- * amount of per-widget allocations
- */
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManagedDisplay *display)
{
OCIO_ConstCPUProcessorRcPtr *processor = display_from_scene_linear_processor(display);
@@ -2406,7 +2382,6 @@ void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManaged
}
}
-/* same as above, but converts color in opposite direction */
void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], ColorManagedDisplay *display)
{
OCIO_ConstCPUProcessorRcPtr *processor = display_to_scene_linear_processor(display);
@@ -2468,17 +2443,6 @@ void IMB_colormanagement_imbuf_make_display_space(
colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, false);
}
-/* prepare image buffer to be saved on disk, applying color management if needed
- * color management would be applied if image is saving as render result and if
- * file format is not expecting float buffer to be in linear space (currently
- * JPEG2000 and TIFF are such formats -- they're storing image as float but
- * file itself stores applied color space).
- *
- * Both byte and float buffers would contain applied color space, and result's
- * float_colorspace would be set to display color space. This should be checked
- * in image format write callback and if float_colorspace is not NULL, no color
- * space transformation should be applied on this buffer.
- */
ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
bool save_as_render,
bool allocate_result,
@@ -2640,7 +2604,6 @@ void IMB_colormanagement_buffer_make_display_space(
/** \name Public Display Buffers Interfaces
* \{ */
-/* acquire display buffer for given image buffer using specified view and display settings */
unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf,
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
@@ -2738,7 +2701,6 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf,
return display_buffer;
}
-/* same as IMB_display_buffer_acquire but gets view and display settings from context */
unsigned char *IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, void **cache_handle)
{
ColorManagedViewSettings *view_settings;
@@ -2899,7 +2861,6 @@ const char *IMB_colormanagement_display_get_default_name(void)
return display->name;
}
-/* used by performance-critical pixel processing areas, such as color widgets */
ColorManagedDisplay *IMB_colormanagement_display_get_named(const char *name)
{
return colormanage_display_get_named(name);
@@ -4027,19 +3988,6 @@ bool IMB_colormanagement_support_glsl_draw(const ColorManagedViewSettings *UNUSE
return OCIO_supportGPUShader();
}
-/**
- * Configures GLSL shader for conversion from specified to
- * display color space
- *
- * Will create appropriate OCIO processor and setup GLSL shader,
- * so further 2D texture usage will use this conversion.
- *
- * When there's no need to apply transform on 2D textures, use
- * IMB_colormanagement_finish_glsl_draw().
- *
- * This is low-level function, use ED_draw_imbuf_ctx if you
- * only need to display given image buffer
- */
bool IMB_colormanagement_setup_glsl_draw_from_space(
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
@@ -4097,7 +4045,6 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(
return global_gpu_state.gpu_shader_bound;
}
-/* Configures GLSL shader for conversion from scene linear to display space */
bool IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
float dither,
@@ -4107,10 +4054,6 @@ bool IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_se
view_settings, display_settings, NULL, dither, predivide, false);
}
-/**
- * Same as setup_glsl_draw_from_space,
- * but color management settings are guessing from a given context.
- */
bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const bContext *C,
struct ColorSpace *from_colorspace,
float dither,
@@ -4125,13 +4068,11 @@ bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const bContext *C,
view_settings, display_settings, from_colorspace, dither, predivide, false);
}
-/* Same as setup_glsl_draw, but color management settings are guessing from a given context */
bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, float dither, bool predivide)
{
return IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, NULL, dither, predivide);
}
-/* Finish GLSL-based display space conversion */
void IMB_colormanagement_finish_glsl_draw(void)
{
if (global_gpu_state.gpu_shader_bound) {
diff --git a/source/blender/imbuf/intern/colormanagement_inline.c b/source/blender/imbuf/intern/colormanagement_inline.c
index c304ad8d8e5..6e57a8cc1b2 100644
--- a/source/blender/imbuf/intern/colormanagement_inline.c
+++ b/source/blender/imbuf/intern/colormanagement_inline.c
@@ -27,23 +27,11 @@
#include "BLI_math_vector.h"
#include "IMB_colormanagement_intern.h"
-/* Convert a float RGB triplet to the correct luminance weighted average.
- *
- * Grayscale, or Luma is a distillation of RGB data values down to a weighted average
- * based on the luminance positions of the red, green, and blue primaries.
- * Given that the internal reference space may be arbitrarily set, any
- * effort to glean the luminance coefficients must be aware of the reference
- * space primaries.
- *
- * See http://wiki.blender.org/index.php/User:Nazg-gul/ColorManagement#Luminance
- */
-
float IMB_colormanagement_get_luminance(const float rgb[3])
{
return dot_v3v3(imbuf_luma_coefficients, rgb);
}
-/* Byte equivalent of IMB_colormanagement_get_luminance(). */
unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char rgb[3])
{
float rgbf[3];
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.cpp b/source/blender/imbuf/intern/dds/BlockDXT.cpp
index 4e4fca864a0..e471b6834ae 100644
--- a/source/blender/imbuf/intern/dds/BlockDXT.cpp
+++ b/source/blender/imbuf/intern/dds/BlockDXT.cpp
@@ -158,7 +158,6 @@ uint BlockDXT1::evaluatePaletteNV5x(Color32 color_array[4]) const
return 3;
}
-/* Evaluate palette assuming 3 color block. */
void BlockDXT1::evaluatePalette3(Color32 color_array[4]) const
{
color_array[0].b = (col0.b << 3) | (col0.b >> 2);
@@ -184,7 +183,6 @@ void BlockDXT1::evaluatePalette3(Color32 color_array[4]) const
color_array[3].a = 0x00;
}
-/* Evaluate palette assuming 4 color block. */
void BlockDXT1::evaluatePalette4(Color32 color_array[4]) const
{
color_array[0].b = (col0.b << 3) | (col0.b >> 2);
@@ -247,14 +245,12 @@ void BlockDXT1::setIndices(const int *idx)
}
}
-/** Flip DXT1 block vertically. */
inline void BlockDXT1::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
-/** Flip half DXT1 block vertically. */
inline void BlockDXT1::flip2()
{
swap(row[0], row[1]);
@@ -299,27 +295,23 @@ void AlphaBlockDXT3::decodeBlock(ColorBlock *block) const
block->color(0xF).a = (alphaF << 4) | alphaF;
}
-/** Flip DXT3 alpha block vertically. */
void AlphaBlockDXT3::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
-/** Flip half DXT3 alpha block vertically. */
void AlphaBlockDXT3::flip2()
{
swap(row[0], row[1]);
}
-/** Flip DXT3 block vertically. */
void BlockDXT3::flip4()
{
alpha.flip4();
color.flip4();
}
-/** Flip half DXT3 block vertically. */
void BlockDXT3::flip2()
{
alpha.flip2();
@@ -458,21 +450,18 @@ void BlockDXT5::decodeBlockNV5x(ColorBlock *block) const
alpha.decodeBlock(block);
}
-/** Flip DXT5 block vertically. */
void BlockDXT5::flip4()
{
alpha.flip4();
color.flip4();
}
-/** Flip half DXT5 block vertically. */
void BlockDXT5::flip2()
{
alpha.flip2();
color.flip2();
}
-/** Decode ATI1 block. */
void BlockATI1::decodeBlock(ColorBlock *block) const
{
uint8 alpha_array[8];
@@ -488,19 +477,16 @@ void BlockATI1::decodeBlock(ColorBlock *block) const
}
}
-/** Flip ATI1 block vertically. */
void BlockATI1::flip4()
{
alpha.flip4();
}
-/** Flip half ATI1 block vertically. */
void BlockATI1::flip2()
{
alpha.flip2();
}
-/** Decode ATI2 block. */
void BlockATI2::decodeBlock(ColorBlock *block) const
{
uint8 alpha_array[8];
@@ -525,14 +511,12 @@ void BlockATI2::decodeBlock(ColorBlock *block) const
}
}
-/** Flip ATI2 block vertically. */
void BlockATI2::flip4()
{
x.flip4();
y.flip4();
}
-/** Flip half ATI2 block vertically. */
void BlockATI2::flip2()
{
x.flip2();
@@ -586,14 +570,12 @@ void BlockCTX1::setIndices(const int *idx)
}
}
-/** Flip CTX1 block vertically. */
inline void BlockCTX1::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
-/** Flip half CTX1 block vertically. */
inline void BlockCTX1::flip2()
{
swap(row[0], row[1]);
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.h b/source/blender/imbuf/intern/dds/BlockDXT.h
index 1fefa7c739d..eb2d5f8726c 100644
--- a/source/blender/imbuf/intern/dds/BlockDXT.h
+++ b/source/blender/imbuf/intern/dds/BlockDXT.h
@@ -69,7 +69,9 @@ struct BlockDXT1 {
uint evaluatePalette(Color32 color_array[4]) const;
uint evaluatePaletteNV5x(Color32 color_array[4]) const;
+ /** Evaluate palette assuming 3 color block. */
void evaluatePalette3(Color32 color_array[4]) const;
+ /** Evaluate palette assuming 4 color block. */
void evaluatePalette4(Color32 color_array[4]) const;
void decodeBlock(ColorBlock *block) const;
@@ -77,7 +79,9 @@ struct BlockDXT1 {
void setIndices(const int *idx);
+ /** Flip DXT1 block vertically. */
void flip4();
+ /** Flip half DXT1 block vertically. */
void flip2();
};
@@ -113,7 +117,9 @@ struct AlphaBlockDXT3 {
void decodeBlock(ColorBlock *block) const;
+ /** Flip DXT3 alpha block vertically. */
void flip4();
+ /** Flip half DXT3 alpha block vertically. */
void flip2();
};
@@ -125,7 +131,9 @@ struct BlockDXT3 {
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
+ /** Flip DXT3 block vertically. */
void flip4();
+ /** Flip half DXT3 block vertically. */
void flip2();
};
@@ -253,7 +261,9 @@ struct BlockDXT5 {
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
+ /** Flip DXT5 block vertically. */
void flip4();
+ /** Flip half DXT5 block vertically. */
void flip2();
};
@@ -261,9 +271,12 @@ struct BlockDXT5 {
struct BlockATI1 {
AlphaBlockDXT5 alpha;
+ /** Decode ATI1 block. */
void decodeBlock(ColorBlock *block) const;
+ /** Flip ATI1 block vertically. */
void flip4();
+ /** Flip half ATI1 block vertically. */
void flip2();
};
@@ -272,9 +285,12 @@ struct BlockATI2 {
AlphaBlockDXT5 x;
AlphaBlockDXT5 y;
+ /** Decode ATI2 block. */
void decodeBlock(ColorBlock *block) const;
+ /** Flip ATI2 block vertically. */
void flip4();
+ /** Flip half ATI2 block vertically. */
void flip2();
};
@@ -292,7 +308,9 @@ struct BlockCTX1 {
void decodeBlock(ColorBlock *block) const;
+ /** Flip CTX1 block vertically. */
void flip4();
+ /** Flip half CTX1 block vertically. */
void flip2();
};
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.cpp b/source/blender/imbuf/intern/dds/ColorBlock.cpp
index 6974e0bf99d..0ab98c01f6f 100644
--- a/source/blender/imbuf/intern/dds/ColorBlock.cpp
+++ b/source/blender/imbuf/intern/dds/ColorBlock.cpp
@@ -46,7 +46,6 @@ inline static uint colorDistance(Color32 c0, Color32 c1)
}
#endif
-/** Init the color block from an array of colors. */
ColorBlock::ColorBlock(const uint *linearImage)
{
for (uint i = 0; i < 16; i++) {
@@ -54,7 +53,6 @@ ColorBlock::ColorBlock(const uint *linearImage)
}
}
-/** Init the color block with the contents of the given block. */
ColorBlock::ColorBlock(const ColorBlock &block)
{
for (uint i = 0; i < 16; i++) {
@@ -62,7 +60,6 @@ ColorBlock::ColorBlock(const ColorBlock &block)
}
}
-/** Initialize this color block. */
ColorBlock::ColorBlock(const Image *img, uint x, uint y)
{
init(img, x, y);
@@ -153,7 +150,6 @@ void ColorBlock::swizzle(uint x, uint y, uint z, uint w)
}
}
-/** Returns true if the block has a single color. */
bool ColorBlock::isSingleColor(Color32 mask /*= Color32(0xFF, 0xFF, 0xFF, 0x00) */) const
{
uint u = m_color[0].u & mask.u;
@@ -234,7 +230,6 @@ Color32 ColorBlock::averageColor() const
}
#endif
-/** Return true if the block is not fully opaque. */
bool ColorBlock::hasAlpha() const
{
for (const auto &i : m_color) {
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.h b/source/blender/imbuf/intern/dds/ColorBlock.h
index 934837bb129..1dee5c76c9e 100644
--- a/source/blender/imbuf/intern/dds/ColorBlock.h
+++ b/source/blender/imbuf/intern/dds/ColorBlock.h
@@ -35,8 +35,11 @@
/** Uncompressed 4x4 color block. */
struct ColorBlock {
ColorBlock() = default;
+ /** Init the color block from an array of colors. */
ColorBlock(const uint *linearImage);
+ /** Init the color block with the contents of the given block. */
ColorBlock(const ColorBlock &block);
+ /** Initialize this color block. */
ColorBlock(const Image *img, uint x, uint y);
void init(const Image *img, uint x, uint y);
@@ -45,7 +48,9 @@ struct ColorBlock {
void swizzle(uint x, uint y, uint z, uint w); /* 0=r, 1=g, 2=b, 3=a, 4=0xFF, 5=0 */
+ /** Returns true if the block has a single color. */
bool isSingleColor(Color32 mask = Color32(0xFF, 0xFF, 0xFF, 0x00)) const;
+ /** Return true if the block is not fully opaque. */
bool hasAlpha() const;
/* Accessors */
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
index b665996b18f..efa438c2af5 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
@@ -1107,8 +1107,6 @@ void DirectDrawSurface::mipmap(Image *img, uint face, uint mipmap)
}
}
-/* It was easier to copy this function from upstream than to resync.
- * This should be removed if a resync ever occurs. */
void *DirectDrawSurface::readData(uint &rsize)
{
uint header_size = 128; // sizeof(DDSHeader);
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.h b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
index 381fa51f75c..343a7367f91 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.h
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
@@ -157,6 +157,10 @@ class DirectDrawSurface {
void setUserVersion(int version);
void mipmap(Image *img, uint f, uint m);
+ /**
+ * It was easier to copy this function from upstream than to resync.
+ * This should be removed if a resync ever occurs.
+ */
void *readData(uint &size);
// void mipmap(FloatImage *img, uint f, uint m);
@@ -174,7 +178,8 @@ class DirectDrawSurface {
void readBlock(ColorBlock *rgba);
private:
- Stream stream; /* Memory where DDS file resides. */
+ /** Memory where DDS file resides. */
+ Stream stream;
DDSHeader header;
};
diff --git a/source/blender/imbuf/intern/dds/FlipDXT.cpp b/source/blender/imbuf/intern/dds/FlipDXT.cpp
index 2acf072556a..6686d56e9d1 100644
--- a/source/blender/imbuf/intern/dds/FlipDXT.cpp
+++ b/source/blender/imbuf/intern/dds/FlipDXT.cpp
@@ -168,10 +168,16 @@ static void FlipDXT5BlockHalf(uint8_t *block)
FlipDXT1BlockHalf(block + 8);
}
-/* Flips a DXTC image, by flipping and swapping DXTC blocks as appropriate. */
-int FlipDXTCImage(
- unsigned int width, unsigned int height, unsigned int levels, int fourcc, uint8_t *data)
+int FlipDXTCImage(unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ int fourcc,
+ uint8_t *data,
+ int data_size,
+ unsigned int *r_num_valid_levels)
{
+ *r_num_valid_levels = 0;
+
/* Must have valid dimensions. */
if (width == 0 || height == 0) {
return 0;
@@ -205,14 +211,25 @@ int FlipDXTCImage(
return 0;
}
+ *r_num_valid_levels = levels;
+
unsigned int mip_width = width;
unsigned int mip_height = height;
+ const uint8_t *data_end = data + data_size;
+
for (unsigned int i = 0; i < levels; i++) {
unsigned int blocks_per_row = (mip_width + 3) / 4;
unsigned int blocks_per_col = (mip_height + 3) / 4;
unsigned int blocks = blocks_per_row * blocks_per_col;
+ if (data + block_bytes * blocks > data_end) {
+ /* Stop flipping when running out of data to be modified, avoiding possible buffer overrun
+ * on a malformed files. */
+ *r_num_valid_levels = i;
+ break;
+ }
+
if (mip_height == 1) {
/* no flip to do, and we're done. */
break;
diff --git a/source/blender/imbuf/intern/dds/FlipDXT.h b/source/blender/imbuf/intern/dds/FlipDXT.h
index d35157251bd..f9d3ce6112e 100644
--- a/source/blender/imbuf/intern/dds/FlipDXT.h
+++ b/source/blender/imbuf/intern/dds/FlipDXT.h
@@ -18,6 +18,15 @@
#include "BLI_sys_types.h"
-/* flip compressed DXT image vertically to fit OpenGL convention */
-int FlipDXTCImage(
- unsigned int width, unsigned int height, unsigned int levels, int fourcc, uint8_t *data);
+/**
+ * Flips a DXTC image, by flipping and swapping DXTC blocks as appropriate.
+ *
+ * Use to flip vertically to fit OpenGL convention.
+ */
+int FlipDXTCImage(unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ int fourcc,
+ uint8_t *data,
+ int data_size,
+ unsigned int *r_num_valid_levels);
diff --git a/source/blender/imbuf/intern/dds/Stream.cpp b/source/blender/imbuf/intern/dds/Stream.cpp
index 3dab3c35675..31bf2076ed1 100644
--- a/source/blender/imbuf/intern/dds/Stream.cpp
+++ b/source/blender/imbuf/intern/dds/Stream.cpp
@@ -26,6 +26,21 @@
static const char *msg_error_seek = "DDS: trying to seek beyond end of stream (corrupt file?)";
static const char *msg_error_read = "DDS: trying to read beyond end of stream (corrupt file?)";
+inline bool is_read_within_bounds(const Stream &mem, unsigned int cnt)
+{
+ if (mem.pos >= mem.size) {
+ /* No more data remained in the memory buffer. */
+ return false;
+ }
+
+ if (cnt > mem.size - mem.pos) {
+ /* Reading past the memory bounds. */
+ return false;
+ }
+
+ return true;
+}
+
unsigned int Stream::seek(unsigned int p)
{
if (p > size) {
@@ -40,7 +55,7 @@ unsigned int Stream::seek(unsigned int p)
unsigned int mem_read(Stream &mem, unsigned long long &i)
{
- if (mem.pos + 8 > mem.size) {
+ if (!is_read_within_bounds(mem, 8)) {
mem.set_failed(msg_error_seek);
return 0;
}
@@ -51,7 +66,7 @@ unsigned int mem_read(Stream &mem, unsigned long long &i)
unsigned int mem_read(Stream &mem, unsigned int &i)
{
- if (mem.pos + 4 > mem.size) {
+ if (!is_read_within_bounds(mem, 4)) {
mem.set_failed(msg_error_read);
return 0;
}
@@ -62,7 +77,7 @@ unsigned int mem_read(Stream &mem, unsigned int &i)
unsigned int mem_read(Stream &mem, unsigned short &i)
{
- if (mem.pos + 2 > mem.size) {
+ if (!is_read_within_bounds(mem, 2)) {
mem.set_failed(msg_error_read);
return 0;
}
@@ -73,7 +88,7 @@ unsigned int mem_read(Stream &mem, unsigned short &i)
unsigned int mem_read(Stream &mem, unsigned char &i)
{
- if (mem.pos + 1 > mem.size) {
+ if (!is_read_within_bounds(mem, 1)) {
mem.set_failed(msg_error_read);
return 0;
}
@@ -84,7 +99,7 @@ unsigned int mem_read(Stream &mem, unsigned char &i)
unsigned int mem_read(Stream &mem, unsigned char *i, unsigned int cnt)
{
- if (mem.pos + cnt > mem.size) {
+ if (!is_read_within_bounds(mem, cnt)) {
mem.set_failed(msg_error_read);
return 0;
}
diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp
index 1729a9a64f8..f576209ff62 100644
--- a/source/blender/imbuf/intern/dds/dds_api.cpp
+++ b/source/blender/imbuf/intern/dds/dds_api.cpp
@@ -186,8 +186,13 @@ struct ImBuf *imb_load_dds(const unsigned char *mem,
/* flip compressed texture */
if (ibuf->dds_data.data) {
- FlipDXTCImage(
- dds.width(), dds.height(), dds.mipmapCount(), dds.fourCC(), ibuf->dds_data.data);
+ FlipDXTCImage(dds.width(),
+ dds.height(),
+ ibuf->dds_data.nummipmaps,
+ dds.fourCC(),
+ ibuf->dds_data.data,
+ ibuf->dds_data.size,
+ &ibuf->dds_data.nummipmaps);
}
}
else {
diff --git a/source/blender/imbuf/intern/dds/dds_api.h b/source/blender/imbuf/intern/dds/dds_api.h
index 931c4f267f9..2d540f13a52 100644
--- a/source/blender/imbuf/intern/dds/dds_api.h
+++ b/source/blender/imbuf/intern/dds/dds_api.h
@@ -26,7 +26,7 @@
extern "C" {
#endif
-bool imb_is_a_dds(const unsigned char *mem, const size_t size);
+bool imb_is_a_dds(const unsigned char *mem, size_t size);
bool imb_save_dds(struct ImBuf *ibuf, const char *name, int flags);
struct ImBuf *imb_load_dds(const unsigned char *mem,
size_t size,
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index e6f42da1597..ff86fbfdd38 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -102,13 +102,11 @@ MINLINE void float_to_byte_dither_v4(
b[3] = unit_float_to_uchar_clamp(f[3]);
}
-/* Test if colorspace conversions of pixels in buffer need to take into account alpha. */
bool IMB_alpha_affects_rgb(const ImBuf *ibuf)
{
return (ibuf->flags & IB_alphamode_channel_packed) == 0;
}
-/* float to byte pixels, output 4-channel RGBA */
void IMB_buffer_byte_from_float(uchar *rect_to,
const float *rect_from,
int channels_from,
@@ -275,7 +273,6 @@ void IMB_buffer_byte_from_float(uchar *rect_to,
}
}
-/* float to byte pixels, output 4-channel RGBA */
void IMB_buffer_byte_from_float_mask(uchar *rect_to,
const float *rect_from,
int channels_from,
@@ -366,7 +363,6 @@ void IMB_buffer_byte_from_float_mask(uchar *rect_to,
}
}
-/* Byte to float pixels, input and output 4-channel RGBA. */
void IMB_buffer_float_from_byte(float *rect_to,
const uchar *rect_from,
int profile_to,
@@ -386,7 +382,7 @@ void IMB_buffer_float_from_byte(float *rect_to,
/* RGBA input */
for (y = 0; y < height; y++) {
- const uchar *from = rect_from + stride_from * y * 4;
+ const uchar *from = rect_from + ((size_t)stride_from) * y * 4;
float *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
@@ -426,7 +422,6 @@ void IMB_buffer_float_from_byte(float *rect_to,
}
}
-/* float to float pixels, output 4-channel RGBA */
void IMB_buffer_float_from_float(float *rect_to,
const float *rect_from,
int channels_from,
@@ -592,7 +587,6 @@ void IMB_buffer_float_from_float_threaded(float *rect_to,
}
}
-/* float to float pixels, output 4-channel RGBA */
void IMB_buffer_float_from_float_mask(float *rect_to,
const float *rect_from,
int channels_from,
@@ -646,7 +640,6 @@ void IMB_buffer_float_from_float_mask(float *rect_to,
}
}
-/* byte to byte pixels, input and output 4-channel RGBA */
void IMB_buffer_byte_from_byte(uchar *rect_to,
const uchar *rect_from,
int profile_to,
@@ -791,17 +784,14 @@ void IMB_float_from_rect(ImBuf *ibuf)
*/
rect_float = ibuf->rect_float;
if (rect_float == NULL) {
- size_t size;
-
- size = ((size_t)ibuf->x) * ibuf->y;
- size = sizeof(float[4]) * size;
- ibuf->channels = 4;
-
+ const size_t size = IMB_get_rect_len(ibuf) * sizeof(float[4]);
rect_float = MEM_callocN(size, "IMB_float_from_rect");
if (rect_float == NULL) {
return;
}
+
+ ibuf->channels = 4;
}
/* first, create float buffer in non-linear space */
@@ -834,10 +824,9 @@ void IMB_float_from_rect(ImBuf *ibuf)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Color to Grayscale
+/** \name Color to Gray-Scale
* \{ */
-/* no profile conversion */
void IMB_color_to_bw(ImBuf *ibuf)
{
float *rct_fl = ibuf->rect_float;
@@ -845,13 +834,13 @@ void IMB_color_to_bw(ImBuf *ibuf)
size_t i;
if (rct_fl) {
- for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct_fl += 4) {
rct_fl[0] = rct_fl[1] = rct_fl[2] = IMB_colormanagement_get_luminance(rct_fl);
}
}
if (rct) {
- for (i = ((size_t)ibuf->x * ibuf->y); i > 0; i--, rct += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct += 4) {
rct[0] = rct[1] = rct[2] = IMB_colormanagement_get_luminance_byte(rct);
}
}
@@ -892,7 +881,7 @@ void IMB_saturation(ImBuf *ibuf, float sat)
if (rct) {
float rgb[3];
- for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct += 4) {
rgb_uchar_to_float(rgb, rct);
rgb_to_hsv_v(rgb, hsv);
hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb, rgb + 1, rgb + 2);
@@ -901,7 +890,7 @@ void IMB_saturation(ImBuf *ibuf, float sat)
}
if (rct_fl) {
- for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct_fl += 4) {
rgb_to_hsv_v(rct_fl, hsv);
hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rct_fl, rct_fl + 1, rct_fl + 2);
}
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 343c8cd8f64..324bc9806c1 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -420,12 +420,6 @@ static int check_pixel_assigned(
return res;
}
-/**
- * if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
- *
- * When a mask is given, only effect pixels with a mask value of 1,
- * defined as #BAKE_MASK_MARGIN in rendercore.c
- */
void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
{
const int width = ibuf->x;
@@ -557,7 +551,6 @@ void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
}
}
-/* threadsafe version, only recreates existing maps */
void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
{
ImBuf *hbuf = ibuf;
@@ -594,7 +587,6 @@ void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
}
}
-/* frees too (if there) and recreates new data */
void IMB_makemipmap(ImBuf *ibuf, int use_filter)
{
ImBuf *hbuf = ibuf;
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 804c9c3eb89..23c4c53d602 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -20,11 +20,10 @@
/** \file
* \ingroup imbuf
*
- * This file was moved here from the src/ directory. It is meant to
- * deal with endianness. It resided in a general blending lib. The
- * other functions were only used during rendering. This single
- * function remained. It should probably move to imbuf/intern/util.c,
- * but we'll keep it here for the time being. (nzc)
+ * This file was moved here from the `src/` directory.
+ * It is meant to deal with endianness. It resided in a general blending lib.
+ * The other functions were only used during rendering. This single function remained.
+ * It should probably move to `imbuf/intern/util.c`, but we'll keep it here for the time being.
*/
#include <math.h>
@@ -41,7 +40,6 @@
#include "IMB_imbuf_types.h"
#include <math.h>
-/* Only this one is used liberally here, and in imbuf */
void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
{
size_t size;
@@ -77,7 +75,8 @@ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
}
}
-static void pixel_from_buffer(struct ImBuf *ibuf, unsigned char **outI, float **outF, int x, int y)
+static void pixel_from_buffer(
+ const struct ImBuf *ibuf, unsigned char **outI, float **outF, int x, int y)
{
size_t offset = ((size_t)ibuf->x) * y * 4 + 4 * x;
@@ -96,7 +95,7 @@ static void pixel_from_buffer(struct ImBuf *ibuf, unsigned char **outI, float **
* \{ */
void bicubic_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
if (outF) {
BLI_bicubic_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
@@ -106,7 +105,7 @@ void bicubic_interpolation_color(
}
}
-void bicubic_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
+void bicubic_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
{
unsigned char *outI = NULL;
float *outF = NULL;
@@ -127,16 +126,16 @@ void bicubic_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, in
/** \name Bi-Linear Interpolation
* \{ */
-BLI_INLINE void bilinear_interpolation_color_fl(
- struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
+void bilinear_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
{
BLI_assert(outF);
BLI_assert(in->rect_float);
BLI_bilinear_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
}
-BLI_INLINE void bilinear_interpolation_color_char(
- struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
+void bilinear_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
{
BLI_assert(outI);
BLI_assert(in->rect);
@@ -144,7 +143,7 @@ BLI_INLINE void bilinear_interpolation_color_char(
}
void bilinear_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
if (outF) {
BLI_bilinear_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
@@ -157,12 +156,8 @@ void bilinear_interpolation_color(
/* function assumes out to be zero'ed, only does RGBA */
/* BILINEAR INTERPOLATION */
-/* Note about wrapping, the u/v still needs to be within the image bounds,
- * just the interpolation is wrapped.
- * This the same as bilinear_interpolation_color except it wraps
- * rather than using empty and emptyI. */
void bilinear_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
float *row1, *row2, *row3, *row4, a, b;
unsigned char *row1I, *row2I, *row3I, *row4I;
@@ -233,7 +228,7 @@ void bilinear_interpolation_color_wrap(
}
}
-void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
+void bilinear_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
{
unsigned char *outI = NULL;
float *outF = NULL;
@@ -254,9 +249,8 @@ void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, i
/** \name Nearest Interpolation
* \{ */
-/* functions assumes out to be zero'ed, only does RGBA */
-BLI_INLINE void nearest_interpolation_color_char(
- struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
+void nearest_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
{
BLI_assert(outI);
BLI_assert(in->rect);
@@ -270,7 +264,7 @@ BLI_INLINE void nearest_interpolation_color_char(
return;
}
- const size_t offset = (in->x * y1 + x1) * 4;
+ const size_t offset = ((size_t)in->x * y1 + x1) * 4;
const unsigned char *dataI = (unsigned char *)in->rect + offset;
outI[0] = dataI[0];
outI[1] = dataI[1];
@@ -278,8 +272,8 @@ BLI_INLINE void nearest_interpolation_color_char(
outI[3] = dataI[3];
}
-BLI_INLINE void nearest_interpolation_color_fl(
- struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
+void nearest_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
{
BLI_assert(outF);
BLI_assert(in->rect_float);
@@ -293,13 +287,13 @@ BLI_INLINE void nearest_interpolation_color_fl(
return;
}
- const size_t offset = (in->x * y1 + x1) * 4;
+ const size_t offset = ((size_t)in->x * y1 + x1) * 4;
const float *dataF = in->rect_float + offset;
copy_v4_v4(outF, dataF);
}
void nearest_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
if (outF) {
nearest_interpolation_color_fl(in, outI, outF, u, v);
@@ -310,7 +304,7 @@ void nearest_interpolation_color(
}
void nearest_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
const float *dataF;
unsigned char *dataI;
@@ -348,7 +342,7 @@ void nearest_interpolation_color_wrap(
}
}
-void nearest_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
+void nearest_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
{
unsigned char *outI = NULL;
float *outF = NULL;
@@ -363,139 +357,6 @@ void nearest_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, in
nearest_interpolation_color(in, outI, outF, u, v);
}
-/* -------------------------------------------------------------------- */
-/** \name Image transform
- * \{ */
-typedef struct TransformUserData {
- ImBuf *src;
- ImBuf *dst;
- float start_uv[2];
- float add_x[2];
- float add_y[2];
- rctf src_crop;
-} TransformUserData;
-
-static void imb_transform_calc_start_uv(const float transform_matrix[3][3], float r_start_uv[2])
-{
- float orig[2];
- orig[0] = 0.0f;
- orig[1] = 0.0f;
- mul_v2_m3v2(r_start_uv, transform_matrix, orig);
-}
-
-static void imb_transform_calc_add_x(const float transform_matrix[3][3],
- const float start_uv[2],
- const int width,
- float r_add_x[2])
-{
- float uv_max_x[2];
- uv_max_x[0] = width;
- uv_max_x[1] = 0.0f;
- mul_v2_m3v2(r_add_x, transform_matrix, uv_max_x);
- sub_v2_v2(r_add_x, start_uv);
- mul_v2_fl(r_add_x, 1.0f / width);
-}
-
-static void imb_transform_calc_add_y(const float transform_matrix[3][3],
- const float start_uv[2],
- const int height,
- float r_add_y[2])
-{
- float uv_max_y[2];
- uv_max_y[0] = 0.0f;
- uv_max_y[1] = height;
- mul_v2_m3v2(r_add_y, transform_matrix, uv_max_y);
- sub_v2_v2(r_add_y, start_uv);
- mul_v2_fl(r_add_y, 1.0f / height);
-}
-
-typedef void (*InterpolationColorFunction)(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
-BLI_INLINE void imb_transform_scanlines(const TransformUserData *user_data,
- int scanline,
- InterpolationColorFunction interpolation)
-{
- const int width = user_data->dst->x;
-
- float uv[2];
- madd_v2_v2v2fl(uv, user_data->start_uv, user_data->add_y, scanline);
-
- unsigned char *outI = NULL;
- float *outF = NULL;
- pixel_from_buffer(user_data->dst, &outI, &outF, 0, scanline);
-
- for (int xi = 0; xi < width; xi++) {
- if (uv[0] >= user_data->src_crop.xmin && uv[0] < user_data->src_crop.xmax &&
- uv[1] >= user_data->src_crop.ymin && uv[1] < user_data->src_crop.ymax) {
- interpolation(user_data->src, outI, outF, uv[0], uv[1]);
- }
- add_v2_v2(uv, user_data->add_x);
- if (outI) {
- outI += 4;
- }
- if (outF) {
- outF += 4;
- }
- }
-}
-
-static void imb_transform_nearest_scanlines(void *custom_data, int scanline)
-{
- const TransformUserData *user_data = custom_data;
- InterpolationColorFunction interpolation = NULL;
- if (user_data->dst->rect_float) {
- interpolation = nearest_interpolation_color_fl;
- }
- else {
- interpolation = nearest_interpolation_color_char;
- }
- imb_transform_scanlines(user_data, scanline, interpolation);
-}
-
-static void imb_transform_bilinear_scanlines(void *custom_data, int scanline)
-{
- const TransformUserData *user_data = custom_data;
- InterpolationColorFunction interpolation = NULL;
- if (user_data->dst->rect_float) {
- interpolation = bilinear_interpolation_color_fl;
- }
- else if (user_data->dst->rect) {
- interpolation = bilinear_interpolation_color_char;
- }
- imb_transform_scanlines(user_data, scanline, interpolation);
-}
-
-static ScanlineThreadFunc imb_transform_scanline_func(const eIMBInterpolationFilterMode filter)
-{
- ScanlineThreadFunc scanline_func = NULL;
- switch (filter) {
- case IMB_FILTER_NEAREST:
- scanline_func = imb_transform_nearest_scanlines;
- break;
- case IMB_FILTER_BILINEAR:
- scanline_func = imb_transform_bilinear_scanlines;
- break;
- }
- return scanline_func;
-}
-
-void IMB_transform(struct ImBuf *src,
- struct ImBuf *dst,
- float transform_matrix[3][3],
- struct rctf *src_crop,
- const eIMBInterpolationFilterMode filter)
-{
- TransformUserData user_data;
- user_data.src = src;
- user_data.dst = dst;
- user_data.src_crop = *src_crop;
- imb_transform_calc_start_uv(transform_matrix, user_data.start_uv);
- imb_transform_calc_add_x(transform_matrix, user_data.start_uv, src->x, user_data.add_x);
- imb_transform_calc_add_y(transform_matrix, user_data.start_uv, src->y, user_data.add_y);
- ScanlineThreadFunc scanline_func = imb_transform_scanline_func(filter);
- IMB_processor_apply_threaded_scanlines(dst->y, scanline_func, &user_data);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -637,7 +498,6 @@ void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float b
/** \name Sample Pixel
* \{ */
-/* Sample pixel of image using NEAREST method. */
void IMB_sampleImageAtLocation(ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4])
{
if (ibuf->rect_float) {
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index bbb0f3b5b22..a85ba65d014 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -37,6 +37,8 @@
# include "BLI_winstuff.h"
#endif
+#include "PIL_time.h"
+
#include "IMB_anim.h"
#include "IMB_indexer.h"
#include "imbuf.h"
@@ -170,7 +172,6 @@ struct anim_index *IMB_indexer_open(const char *name)
int i;
if (!fp) {
- fprintf(stderr, "Couldn't open indexer file: %s\n", name);
return NULL;
}
@@ -183,13 +184,13 @@ struct anim_index *IMB_indexer_open(const char *name)
header[12] = 0;
if (memcmp(header, binary_header_str, 8) != 0) {
- fprintf(stderr, "Error reading %s: Binary file type string missmatch\n", name);
+ fprintf(stderr, "Error reading %s: Binary file type string mismatch\n", name);
fclose(fp);
return NULL;
}
if (atoi(header + 9) != INDEX_FILE_VERSION) {
- fprintf(stderr, "Error reading %s: File version missmatch\n", name);
+ fprintf(stderr, "Error reading %s: File version mismatch\n", name);
fclose(fp);
return NULL;
}
@@ -222,7 +223,7 @@ struct anim_index *IMB_indexer_open(const char *name)
}
if (UNLIKELY(items_read != idx->num_entries * 5)) {
- fprintf(stderr, "Error: Element data size missmatch in: %s\n", name);
+ fprintf(stderr, "Error: Element data size mismatch in: %s\n", name);
MEM_freeN(idx->entries);
MEM_freeN(idx);
fclose(fp);
@@ -815,12 +816,16 @@ typedef struct FFmpegIndexBuilderContext {
double pts_time_base;
int frameno, frameno_gapless;
int start_pts_set;
+
+ bool build_only_on_bad_performance;
+ bool building_cancelled;
} FFmpegIndexBuilderContext;
static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim,
IMB_Timecode_Type tcs_in_use,
IMB_Proxy_Size proxy_sizes_in_use,
- int quality)
+ int quality,
+ bool build_only_on_bad_performance)
{
FFmpegIndexBuilderContext *context = MEM_callocN(sizeof(FFmpegIndexBuilderContext),
"FFmpeg index builder context");
@@ -832,6 +837,7 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim,
context->proxy_sizes_in_use = proxy_sizes_in_use;
context->num_proxy_sizes = IMB_PROXY_MAX_SLOT;
context->num_indexers = IMB_TC_MAX_SLOT;
+ context->build_only_on_bad_performance = build_only_on_bad_performance;
memset(context->proxy_ctx, 0, sizeof(context->proxy_ctx));
memset(context->indexer, 0, sizeof(context->indexer));
@@ -937,15 +943,17 @@ static void index_rebuild_ffmpeg_finish(FFmpegIndexBuilderContext *context, int
{
int i;
+ const bool do_rollback = stop || context->building_cancelled;
+
for (i = 0; i < context->num_indexers; i++) {
if (context->tcs_in_use & tc_types[i]) {
- IMB_index_builder_finish(context->indexer[i], stop);
+ IMB_index_builder_finish(context->indexer[i], do_rollback);
}
}
for (i = 0; i < context->num_proxy_sizes; i++) {
if (context->proxy_sizes_in_use & proxy_sizes[i]) {
- free_proxy_output_ffmpeg(context->proxy_ctx[i], stop);
+ free_proxy_output_ffmpeg(context->proxy_ctx[i], do_rollback);
}
}
@@ -1096,6 +1104,111 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
return 1;
}
+/* Get number of frames, that can be decoded in specified time period. */
+static int indexer_performance_get_decode_rate(FFmpegIndexBuilderContext *context,
+ const double time_period)
+{
+ AVFrame *in_frame = av_frame_alloc();
+ AVPacket *packet = av_packet_alloc();
+
+ const double start = PIL_check_seconds_timer();
+ int frames_decoded = 0;
+
+ while (av_read_frame(context->iFormatCtx, packet) >= 0) {
+ if (packet->stream_index != context->videoStream) {
+ continue;
+ }
+
+ int ret = avcodec_send_packet(context->iCodecCtx, packet);
+ while (ret >= 0) {
+ ret = avcodec_receive_frame(context->iCodecCtx, in_frame);
+
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+ break;
+ }
+
+ if (ret < 0) {
+ fprintf(stderr, "Error decoding proxy frame: %s\n", av_err2str(ret));
+ break;
+ }
+ frames_decoded++;
+ }
+
+ const double end = PIL_check_seconds_timer();
+
+ if (end > start + time_period) {
+ break;
+ }
+ }
+
+ avcodec_flush_buffers(context->iCodecCtx);
+ av_seek_frame(context->iFormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
+ return frames_decoded;
+}
+
+/* Read up to 10k movie packets and return max GOP size detected.
+ * Number of packets is arbitrary. It should be as large as possible, but processed within
+ * reasonable time period, so detected GOP size is as close to real as possible. */
+static int indexer_performance_get_max_gop_size(FFmpegIndexBuilderContext *context)
+{
+ AVPacket *packet = av_packet_alloc();
+
+ const int packets_max = 10000;
+ int packet_index = 0;
+ int max_gop = 0;
+ int cur_gop = 0;
+
+ while (av_read_frame(context->iFormatCtx, packet) >= 0) {
+ if (packet->stream_index != context->videoStream) {
+ continue;
+ }
+ packet_index++;
+ cur_gop++;
+
+ if (packet->flags & AV_PKT_FLAG_KEY) {
+ max_gop = max_ii(max_gop, cur_gop);
+ cur_gop = 0;
+ }
+
+ if (packet_index > packets_max) {
+ break;
+ }
+ }
+
+ av_seek_frame(context->iFormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
+ return max_gop;
+}
+
+/* Assess scrubbing performance of provided file. This function is not meant to be very exact.
+ * It compares number number of frames decoded in reasonable time with largest detected GOP size.
+ * Because seeking happens in single GOP, it means, that maximum seek time can be detected this
+ * way.
+ * Since proxies use GOP size of 10 frames, skip building if detected GOP size is less or
+ * equal.
+ */
+static bool indexer_need_to_build_proxy(FFmpegIndexBuilderContext *context)
+{
+ if (!context->build_only_on_bad_performance) {
+ return true;
+ }
+
+ /* Make sure, that file is not cold read. */
+ indexer_performance_get_decode_rate(context, 0.1);
+ /* Get decode rate per 100ms. This is arbitrary, but seems to be good baseline cadence of
+ * seeking. */
+ const int decode_rate = indexer_performance_get_decode_rate(context, 0.1);
+ const int max_gop_size = indexer_performance_get_max_gop_size(context);
+
+ if (max_gop_size <= 10 || max_gop_size < decode_rate) {
+ printf("Skipping proxy building for %s: Decoding performance is already good.\n",
+ context->iFormatCtx->url);
+ context->building_cancelled = true;
+ return false;
+ }
+
+ return true;
+}
+
#endif
/* ----------------------------------------------------------------------
@@ -1275,7 +1388,8 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Proxy_Size proxy_sizes_in_use,
int quality,
const bool overwrite,
- GSet *file_list)
+ GSet *file_list,
+ bool build_only_on_bad_performance)
{
IndexBuildContext *context = NULL;
IMB_Proxy_Size proxy_sizes_to_build = proxy_sizes_in_use;
@@ -1329,9 +1443,13 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
switch (anim->curtype) {
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
- context = index_ffmpeg_create_context(anim, tcs_in_use, proxy_sizes_to_build, quality);
+ context = index_ffmpeg_create_context(
+ anim, tcs_in_use, proxy_sizes_to_build, quality, build_only_on_bad_performance);
break;
+#else
+ UNUSED_VARS(build_only_on_bad_performance);
#endif
+
#ifdef WITH_AVI
default:
context = index_fallback_create_context(anim, tcs_in_use, proxy_sizes_to_build, quality);
@@ -1359,7 +1477,9 @@ void IMB_anim_index_rebuild(struct IndexBuildContext *context,
switch (context->anim_type) {
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
- index_rebuild_ffmpeg((FFmpegIndexBuilderContext *)context, stop, do_update, progress);
+ if (indexer_need_to_build_proxy((FFmpegIndexBuilderContext *)context)) {
+ index_rebuild_ffmpeg((FFmpegIndexBuilderContext *)context, stop, do_update, progress);
+ }
break;
#endif
#ifdef WITH_AVI
diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c
index df516d2a5c4..1c8548009e8 100644
--- a/source/blender/imbuf/intern/iris.c
+++ b/source/blender/imbuf/intern/iris.c
@@ -251,12 +251,6 @@ bool imb_is_a_iris(const uchar *mem, size_t size)
return ((GS(mem) == IMAGIC) || (GSS(mem) == IMAGIC));
}
-/*
- * longimagedata -
- * read in a B/W RGB or RGBA iris image file and return a
- * pointer to an array of ints.
- */
-
struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
uint *base, *lptr = NULL;
@@ -274,7 +268,7 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
return NULL;
}
- /* Could pe part of the magic check above,
+ /* Could be part of the magic check above,
* by convention this check only requests the size needed to read it's magic though. */
if (size < HEADER_SIZE) {
return NULL;
@@ -542,7 +536,7 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
}
}
else if (image.zsize == 2) {
- /* grayscale with alpha */
+ /* Gray-scale with alpha. */
rect = (uchar *)ibuf->rect;
for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) {
rect[0] = rect[2];
@@ -570,7 +564,7 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
}
}
else if (image.zsize == 2) {
- /* grayscale with alpha */
+ /* Gray-scale with alpha. */
fbase = ibuf->rect_float;
for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) {
fbase[0] = fbase[2];
diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c
index 117e0d97b2e..3af7367ef6e 100644
--- a/source/blender/imbuf/intern/jp2.c
+++ b/source/blender/imbuf/intern/jp2.c
@@ -424,13 +424,13 @@ static ImBuf *imb_load_jp2_stream(opj_stream_t *stream,
h = image->comps[0].h;
switch (image->numcomps) {
- case 1: /* Grayscale */
- case 3: /* Color */
+ case 1: /* Gray-scale. */
+ case 3: /* Color. */
planes = 24;
use_alpha = false;
break;
- default: /* 2 or 4 - Grayscale or Color + alpha */
- planes = 32; /* grayscale + alpha */
+ default: /* 2 or 4 - Gray-scale or Color + alpha. */
+ planes = 32; /* Gray-scale + alpha. */
use_alpha = true;
break;
}
@@ -529,7 +529,7 @@ static ImBuf *imb_load_jp2_stream(opj_stream_t *stream,
r = image->comps[0].data;
a = (use_alpha) ? image->comps[1].data : NULL;
- /* grayscale */
+ /* Gray-scale. */
if (use_alpha) {
a = image->comps[3].data;
PIXEL_LOOPER_BEGIN (rect_uchar) {
@@ -848,7 +848,7 @@ static opj_image_t *ibuftoimage(ImBuf *ibuf, opj_cparameters_t *parameters)
chanel_colormanage_cb = channel_colormanage_noop;
}
else {
- /* standard linear-to-srgb conversion if float buffer wasn't managed */
+ /* standard linear-to-SRGB conversion if float buffer wasn't managed */
chanel_colormanage_cb = linearrgb_to_srgb;
}
@@ -891,8 +891,8 @@ static opj_image_t *ibuftoimage(ImBuf *ibuf, opj_cparameters_t *parameters)
prec = 8;
}
- /* 32bit images == alpha channel */
- /* grayscale not supported yet */
+ /* 32bit images == alpha channel. */
+ /* Gray-scale not supported yet. */
numcomps = (ibuf->planes == 32) ? 4 : 3;
}
diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c
index 48b5b0c34db..c3a07d7face 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -40,8 +40,9 @@
#include "IMB_imbuf_types.h"
#include "IMB_metadata.h"
#include "imbuf.h"
-#include "jerror.h"
-#include "jpeglib.h"
+
+#include <jerror.h>
+#include <jpeglib.h>
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c
index 6cc1932eff6..f290ab1a060 100644
--- a/source/blender/imbuf/intern/moviecache.c
+++ b/source/blender/imbuf/intern/moviecache.c
@@ -87,6 +87,8 @@ typedef struct MovieCacheItem {
ImBuf *ibuf;
MEM_CacheLimiterHandleC *c_handle;
void *priority_data;
+ /* Indicates that #ibuf is null, because there was an error during load. */
+ bool added_empty;
} MovieCacheItem;
static unsigned int moviecache_hashhash(const void *keyv)
@@ -120,8 +122,13 @@ static void moviecache_valfree(void *val)
PRINT("%s: cache '%s' free item %p buffer %p\n", __func__, cache->name, item, item->ibuf);
- if (item->ibuf) {
+ if (item->c_handle) {
+ BLI_mutex_lock(&limitor_lock);
MEM_CacheLimiter_unmanage(item->c_handle);
+ BLI_mutex_unlock(&limitor_lock);
+ }
+
+ if (item->ibuf) {
IMB_freeImBuf(item->ibuf);
}
@@ -141,11 +148,16 @@ static void check_unused_keys(MovieCache *cache)
while (!BLI_ghashIterator_done(&gh_iter)) {
const MovieCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
const MovieCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
- bool remove;
BLI_ghashIterator_step(&gh_iter);
- remove = !item->ibuf;
+ if (item->added_empty) {
+ /* Don't remove entries that have been added empty. Those indicate that the image couldn't be
+ * loaded correctly. */
+ continue;
+ }
+
+ bool remove = !item->ibuf;
if (remove) {
PRINT("%s: cache '%s' remove item %p without buffer\n", __func__, cache->name, item);
@@ -230,6 +242,9 @@ static int get_item_priority(void *item_v, int default_priority)
static bool get_item_destroyable(void *item_v)
{
MovieCacheItem *item = (MovieCacheItem *)item_v;
+ if (item->ibuf == NULL) {
+ return true;
+ }
/* IB_BITMAPDIRTY means image was modified from inside blender and
* changes are not saved to disk.
*
@@ -253,6 +268,7 @@ void IMB_moviecache_destruct(void)
{
if (limitor) {
delete_MEM_CacheLimiter(limitor);
+ limitor = NULL;
}
}
@@ -309,7 +325,9 @@ static void do_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf, boo
IMB_moviecache_init();
}
- IMB_refImBuf(ibuf);
+ if (ibuf != NULL) {
+ IMB_refImBuf(ibuf);
+ }
key = BLI_mempool_alloc(cache->keys_pool);
key->cache_owner = cache;
@@ -324,6 +342,7 @@ static void do_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf, boo
item->cache_owner = cache;
item->c_handle = NULL;
item->priority_data = NULL;
+ item->added_empty = ibuf == NULL;
if (cache->getprioritydatafp) {
item->priority_data = cache->getprioritydatafp(userkey);
@@ -365,7 +384,7 @@ bool IMB_moviecache_put_if_possible(MovieCache *cache, void *userkey, ImBuf *ibu
size_t mem_in_use, mem_limit, elem_size;
bool result = false;
- elem_size = get_size_in_memory(ibuf);
+ elem_size = (ibuf == NULL) ? 0 : get_size_in_memory(ibuf);
mem_limit = MEM_CacheLimiter_get_maximum();
BLI_mutex_lock(&limitor_lock);
@@ -389,7 +408,7 @@ void IMB_moviecache_remove(MovieCache *cache, void *userkey)
BLI_ghash_remove(cache->hash, &key, moviecache_keyfree, moviecache_valfree);
}
-ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey)
+ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey, bool *r_is_cached_empty)
{
MovieCacheKey key;
MovieCacheItem *item;
@@ -398,6 +417,10 @@ ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey)
key.userkey = userkey;
item = (MovieCacheItem *)BLI_ghash_lookup(cache->hash, &key);
+ if (r_is_cached_empty) {
+ *r_is_cached_empty = false;
+ }
+
if (item) {
if (item->ibuf) {
BLI_mutex_lock(&limitor_lock);
@@ -408,6 +431,9 @@ ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey)
return item->ibuf;
}
+ if (r_is_cached_empty) {
+ *r_is_cached_empty = true;
+ }
}
return NULL;
@@ -470,7 +496,6 @@ void IMB_moviecache_cleanup(MovieCache *cache,
}
}
-/* get segments of cached frames. useful for debugging cache policies */
void IMB_moviecache_get_cache_segments(
MovieCache *cache, int proxy, int render_flags, int *r_totseg, int **r_points)
{
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
index 3ad902a241d..22533b04b58 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
@@ -221,7 +221,7 @@ struct ImBuf *imb_load_photoshop(const char *filename, int flags, char colorspac
string ics = spec.get_string_attribute("oiio:ColorSpace");
BLI_strncpy(file_colorspace, ics.c_str(), IM_MAX_SPACE);
- /* only use colorspaces exis */
+ /* Only use color-spaces exist. */
if (colormanage_colorspace_get_named(file_colorspace)) {
strcpy(colorspace, file_colorspace);
}
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.h b/source/blender/imbuf/intern/oiio/openimageio_api.h
index 659050cdb00..1201bd1b5e0 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.h
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.h
@@ -31,7 +31,7 @@ extern "C" {
struct ImBuf;
-bool imb_is_a_photoshop(const unsigned char *mem, const size_t size);
+bool imb_is_a_photoshop(const unsigned char *mem, size_t size);
int imb_save_photoshop(struct ImBuf *ibuf, const char *name, int flags);
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index adf09f8dda8..ec8cf36dd49 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -327,10 +327,6 @@ static half float_to_half_safe(const float value)
extern "C" {
-/**
- * Test presence of OpenEXR file.
- * \param mem: pointer to loaded OpenEXR bitstream
- */
bool imb_is_a_openexr(const unsigned char *mem, const size_t size)
{
/* No define is exposed for this size. */
@@ -687,7 +683,7 @@ static bool imb_exr_multilayer_parse_channels_from_file(ExrHandle *data);
void *IMB_exr_get_handle(void)
{
- ExrHandle *data = (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
+ ExrHandle *data = MEM_cnew<ExrHandle>("exr handle");
data->multiView = new StringVector();
BLI_addtail(&exrhandles, data);
@@ -781,9 +777,6 @@ static void imb_exr_insert_view_name(char *name_full, const char *passname, cons
}
}
-/* adds flattened ExrChannels */
-/* xstride, ystride and rect can be done in set_channel too, for tile writing */
-/* passname does not include view */
void IMB_exr_add_channel(void *handle,
const char *layname,
const char *passname,
@@ -796,7 +789,7 @@ void IMB_exr_add_channel(void *handle,
ExrHandle *data = (ExrHandle *)handle;
ExrChannel *echan;
- echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr channel");
+ echan = MEM_cnew<ExrChannel>("exr channel");
echan->m = new MultiViewChannelName();
if (layname && layname[0] != '\0') {
@@ -840,7 +833,6 @@ void IMB_exr_add_channel(void *handle,
BLI_addtail(&data->channels, echan);
}
-/* used for output files (from RenderResult) (single and multilayer, single and multiview) */
bool IMB_exr_begin_write(void *handle,
const char *filename,
int width,
@@ -896,8 +888,6 @@ bool IMB_exr_begin_write(void *handle,
return (data->ofile != nullptr);
}
-/* only used for writing temp. render results (not image files)
- * (FSA and Save Buffers) */
void IMB_exrtile_begin_write(
void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley)
{
@@ -963,7 +953,6 @@ void IMB_exrtile_begin_write(
}
}
-/* read from file */
bool IMB_exr_begin_read(
void *handle, const char *filename, int *width, int *height, const bool parse_channels)
{
@@ -1024,8 +1013,6 @@ bool IMB_exr_begin_read(
return true;
}
-/* still clumsy name handling, layers/channels can be ordered as list in list later */
-/* passname here is the raw channel name without the layer */
void IMB_exr_set_channel(
void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
{
@@ -1167,8 +1154,6 @@ void IMB_exr_write_channels(void *handle)
}
}
-/* temporary function, used for FSA and Save Buffers */
-/* called once per tile * view */
void IMB_exrtile_write_channels(
void *handle, int partx, int party, int level, const char *viewname, bool empty)
{
@@ -1511,7 +1496,7 @@ static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname)
ExrLayer *lay = (ExrLayer *)BLI_findstring(lb, layname, offsetof(ExrLayer, name));
if (lay == nullptr) {
- lay = (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer");
+ lay = MEM_cnew<ExrLayer>("exr layer");
BLI_addtail(lb, lay);
BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME);
}
@@ -1524,7 +1509,7 @@ static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
ExrPass *pass = (ExrPass *)BLI_findstring(lb, passname, offsetof(ExrPass, name));
if (pass == nullptr) {
- pass = (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass");
+ pass = MEM_cnew<ExrPass>("exr pass");
if (STREQ(passname, "Combined")) {
BLI_addhead(lb, pass);
@@ -1937,8 +1922,8 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
file = new MultiPartInputFile(*membuf);
Box2i dw = file->header(0).dataWindow();
- const int width = dw.max.x - dw.min.x + 1;
- const int height = dw.max.y - dw.min.y + 1;
+ const size_t width = dw.max.x - dw.min.x + 1;
+ const size_t height = dw.max.y - dw.min.y + 1;
// printf("OpenEXR-load: image data window %d %d %d %d\n",
// dw.min.x, dw.min.y, dw.max.x, dw.max.y);
@@ -2001,8 +1986,8 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
const bool has_luma = exr_has_luma(*file);
FrameBuffer frameBuffer;
float *first;
- int xstride = sizeof(float[4]);
- int ystride = -xstride * width;
+ size_t xstride = sizeof(float[4]);
+ size_t ystride = -xstride * width;
imb_addrectfloatImBuf(ibuf);
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.h b/source/blender/imbuf/intern/openexr/openexr_api.h
index 940715690a7..4321c95db30 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.h
+++ b/source/blender/imbuf/intern/openexr/openexr_api.h
@@ -32,7 +32,11 @@ extern "C" {
void imb_initopenexr(void);
void imb_exitopenexr(void);
-bool imb_is_a_openexr(const unsigned char *mem, const size_t size);
+/**
+ * Test presence of OpenEXR file.
+ * \param mem: pointer to loaded OpenEXR bit-stream.
+ */
+bool imb_is_a_openexr(const unsigned char *mem, size_t size);
bool imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags);
diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h
index 82a5d161ded..0c3c4a4400f 100644
--- a/source/blender/imbuf/intern/openexr/openexr_multi.h
+++ b/source/blender/imbuf/intern/openexr/openexr_multi.h
@@ -23,7 +23,7 @@
#pragma once
-/* experiment with more advanced exr api */
+/* Experiment with more advanced EXR API. */
/* XXX layer+pass name max 64? */
/* This api also supports max 8 channels per pass now. easy to fix! */
@@ -41,6 +41,12 @@ struct StampData;
void *IMB_exr_get_handle(void);
void *IMB_exr_get_handle_name(const char *name);
+
+/**
+ * Adds flattened #ExrChannel's
+ * `xstride`, `ystride` and `rect` can be done in set_channel too, for tile writing.
+ * \param passname: Does not include view.
+ */
void IMB_exr_add_channel(void *handle,
const char *layname,
const char *passname,
@@ -50,17 +56,32 @@ void IMB_exr_add_channel(void *handle,
float *rect,
bool use_half_float);
+/**
+ * Read from file.
+ */
bool IMB_exr_begin_read(
- void *handle, const char *filename, int *width, int *height, const bool parse_channels);
+ void *handle, const char *filename, int *width, int *height, bool parse_channels);
+/**
+ * Used for output files (from #RenderResult) (single and multi-layer, single and multi-view).
+ */
bool IMB_exr_begin_write(void *handle,
const char *filename,
int width,
int height,
int compress,
const struct StampData *stamp);
+/**
+ * Only used for writing temp. render results (not image files)
+ * (FSA and Save Buffers).
+ */
void IMB_exrtile_begin_write(
void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley);
+/**
+ * Still clumsy name handling, layers/channels can be ordered as list in list later.
+ *
+ * \param passname: Here is the raw channel name without the layer.
+ */
void IMB_exr_set_channel(void *handle,
const char *layname,
const char *passname,
@@ -74,6 +95,10 @@ float *IMB_exr_channel_rect(void *handle,
void IMB_exr_read_channels(void *handle);
void IMB_exr_write_channels(void *handle);
+/**
+ * Temporary function, used for FSA and Save Buffers.
+ * called once per `tile * view`.
+ */
void IMB_exrtile_write_channels(
void *handle, int partx, int party, int level, const char *viewname, bool empty);
void IMB_exr_clear_channels(void *handle);
diff --git a/source/blender/imbuf/intern/openexr/openexr_stub.cpp b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
index 639100ac6fe..9b4d6178613 100644
--- a/source/blender/imbuf/intern/openexr/openexr_stub.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
@@ -49,7 +49,7 @@ bool IMB_exr_begin_read(void * /*handle*/,
int * /*height*/,
const bool /*add_channels*/)
{
- return 0;
+ return false;
}
bool IMB_exr_begin_write(void * /*handle*/,
const char * /*filename*/,
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
index 399fd487065..aaf56b1daa0 100644
--- a/source/blender/imbuf/intern/png.c
+++ b/source/blender/imbuf/intern/png.c
@@ -23,7 +23,7 @@
* \todo Save floats as 16 bits per channel, currently readonly.
*/
-#include "png.h"
+#include <png.h>
#include "BLI_fileops.h"
#include "BLI_math.h"
@@ -153,7 +153,7 @@ bool imb_savepng(struct ImBuf *ibuf, const char *filepath, int flags)
chanel_colormanage_cb = channel_colormanage_noop;
}
else {
- /* standard linear-to-srgb conversion if float buffer wasn't managed */
+ /* Standard linear-to-SRGB conversion if float buffer wasn't managed. */
chanel_colormanage_cb = linearrgb_to_srgb;
}
diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c
index 7f4e4dd31df..925ef0a8502 100644
--- a/source/blender/imbuf/intern/radiance_hdr.c
+++ b/source/blender/imbuf/intern/radiance_hdr.c
@@ -77,7 +77,7 @@ static const unsigned char *oldreadcolrs(RGBE *scan,
scan[0][BLU] = *mem++;
scan[0][EXP] = *mem++;
if (scan[0][RED] == 1 && scan[0][GRN] == 1 && scan[0][BLU] == 1) {
- for (i = scan[0][EXP] << rshift; i > 0; i--) {
+ for (i = scan[0][EXP] << rshift; i > 0 && len > 0; i--) {
COPY_RGBE(scan[-1], scan[0]);
scan++;
len--;
@@ -227,7 +227,7 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem,
int found = 0;
int width = 0, height = 0;
const unsigned char *ptr, *mem_eof = mem + size;
- char oriY[80], oriX[80];
+ char oriY[3], oriX[3];
if (!imb_is_a_hdr(mem, size)) {
return NULL;
@@ -244,22 +244,33 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem,
}
}
- if ((found && (x < (size + 2))) == 0) {
+ if ((found && (x < (size - 1))) == 0) {
/* Data not found! */
return NULL;
}
- if (sscanf((const char *)&mem[x + 1],
- "%79s %d %79s %d",
- (char *)&oriY,
- &height,
- (char *)&oriX,
- &width) != 4) {
+ x++;
+
+ /* sscanf requires a null-terminated buffer argument */
+ char buf[32] = {0};
+ memcpy(buf, &mem[x], MIN2(sizeof(buf) - 1, size - x));
+
+ if (sscanf(buf, "%2s %d %2s %d", (char *)&oriY, &height, (char *)&oriX, &width) != 4) {
+ return NULL;
+ }
+
+ if (width < 1 || height < 1) {
return NULL;
}
+ /* Checking that width x height does not extend past mem_eof is not easily possible
+ * since the format uses RLE compression. Can cause excessive memory allocation to occur. */
+
/* find end of this line, data right behind it */
- ptr = (const unsigned char *)strchr((const char *)&mem[x + 1], '\n');
+ ptr = (const unsigned char *)strchr((const char *)&mem[x], '\n');
+ if (ptr == NULL || ptr >= mem_eof) {
+ return NULL;
+ }
ptr++;
if (flags & IB_test) {
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
index 50210650f05..c75bdfa375c 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -126,7 +126,7 @@ ImBuf *IMB_ibImageFromMemory(const unsigned char *mem,
}
if ((flags & IB_test) == 0) {
- fprintf(stderr, "%s: unknown fileformat (%s)\n", __func__, descr);
+ fprintf(stderr, "%s: unknown file-format (%s)\n", __func__, descr);
}
return NULL;
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 4b5d68b9c13..1d81ee768e9 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -251,9 +251,6 @@ static void rect_crop_16bytes(void **buf_p, const int size_src[2], const rcti *c
*buf_p = (void *)MEM_reallocN(*buf_p, sizeof(uint[4]) * size_dst[0] * size_dst[1]);
}
-/**
- * In-place image crop.
- */
void IMB_rect_crop(ImBuf *ibuf, const rcti *crop)
{
const int size_src[2] = {
@@ -302,9 +299,6 @@ static void rect_realloc_16bytes(void **buf_p, const uint size[2])
*buf_p = MEM_mallocN(sizeof(uint[4]) * size[0] * size[1], __func__);
}
-/**
- * In-place size setting (caller must fill in buffer contents).
- */
void IMB_rect_size_set(ImBuf *ibuf, const uint size[2])
{
BLI_assert(size[0] > 0 && size[1] > 0);
@@ -1070,11 +1064,6 @@ void IMB_rectblend_threaded(ImBuf *dbuf,
}
}
-/**
- * Replace pixels of entire image with solid color.
- * \param ibuf: An image to be filled with color. It must be 4 channel image.
- * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
- */
void IMB_rectfill(ImBuf *drect, const float col[4])
{
int num;
@@ -1107,15 +1096,6 @@ void IMB_rectfill(ImBuf *drect, const float col[4])
}
}
-/**
- * Replace pixels of image area with solid color.
- * \param ibuf: an image to be filled with color. It must be 4 channel image.
- * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
- * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
- * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
- * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
- * order the area between x1 and x2, and y1 and y2 is filled.
- */
void IMB_rectfill_area_replace(
const ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2)
{
@@ -1273,21 +1253,6 @@ void buf_rectfill_area(unsigned char *rect,
}
}
-/**
- * Blend pixels of image area with solid color.
- *
- * For images with `uchar` buffer use color matching image color-space.
- * For images with float buffer use color display color-space.
- * If display color-space can not be referenced, use color in SRGB color-space.
- *
- * \param ibuf: an image to be filled with color. It must be 4 channel image.
- * \param col: RGBA color.
- * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
- * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
- * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
- * order the area between x1 and x2, and y1 and y2 is filled.
- * \param display: color-space reference for display space.
- */
void IMB_rectfill_area(ImBuf *ibuf,
const float col[4],
int x1,
diff --git a/source/blender/imbuf/intern/rotate.c b/source/blender/imbuf/intern/rotate.c
index c2fc2190ce5..f02f3e37d6a 100644
--- a/source/blender/imbuf/intern/rotate.c
+++ b/source/blender/imbuf/intern/rotate.c
@@ -32,7 +32,7 @@
void IMB_flipy(struct ImBuf *ibuf)
{
- int x, y;
+ size_t x_size, y_size;
if (ibuf == NULL) {
return;
@@ -41,21 +41,23 @@ void IMB_flipy(struct ImBuf *ibuf)
if (ibuf->rect) {
unsigned int *top, *bottom, *line;
- x = ibuf->x;
- y = ibuf->y;
+ x_size = ibuf->x;
+ y_size = ibuf->y;
+
+ const size_t stride = x_size * sizeof(int);
top = ibuf->rect;
- bottom = top + ((y - 1) * x);
- line = MEM_mallocN(x * sizeof(int), "linebuf");
+ bottom = top + ((y_size - 1) * x_size);
+ line = MEM_mallocN(stride, "linebuf");
- y >>= 1;
+ y_size >>= 1;
- for (; y > 0; y--) {
- memcpy(line, top, x * sizeof(int));
- memcpy(top, bottom, x * sizeof(int));
- memcpy(bottom, line, x * sizeof(int));
- bottom -= x;
- top += x;
+ for (; y_size > 0; y_size--) {
+ memcpy(line, top, stride);
+ memcpy(top, bottom, stride);
+ memcpy(bottom, line, stride);
+ bottom -= x_size;
+ top += x_size;
}
MEM_freeN(line);
@@ -64,21 +66,23 @@ void IMB_flipy(struct ImBuf *ibuf)
if (ibuf->rect_float) {
float *topf = NULL, *bottomf = NULL, *linef = NULL;
- x = ibuf->x;
- y = ibuf->y;
+ x_size = ibuf->x;
+ y_size = ibuf->y;
+
+ const size_t stride = x_size * 4 * sizeof(float);
topf = ibuf->rect_float;
- bottomf = topf + 4 * ((y - 1) * x);
- linef = MEM_mallocN(4 * x * sizeof(float), "linebuff");
+ bottomf = topf + 4 * ((y_size - 1) * x_size);
+ linef = MEM_mallocN(stride, "linebuf");
- y >>= 1;
+ y_size >>= 1;
- for (; y > 0; y--) {
- memcpy(linef, topf, 4 * x * sizeof(float));
- memcpy(topf, bottomf, 4 * x * sizeof(float));
- memcpy(bottomf, linef, 4 * x * sizeof(float));
- bottomf -= 4 * x;
- topf += 4 * x;
+ for (; y_size > 0; y_size--) {
+ memcpy(linef, topf, stride);
+ memcpy(topf, bottomf, stride);
+ memcpy(bottomf, linef, stride);
+ bottomf -= 4 * x_size;
+ topf += 4 * x_size;
}
MEM_freeN(linef);
@@ -99,20 +103,22 @@ void IMB_flipx(struct ImBuf *ibuf)
if (ibuf->rect) {
for (yi = y - 1; yi >= 0; yi--) {
+ const size_t x_offset = (size_t)x * yi;
for (xr = x - 1, xl = 0; xr >= xl; xr--, xl++) {
- SWAP(unsigned int, ibuf->rect[(x * yi) + xr], ibuf->rect[(x * yi) + xl]);
+ SWAP(unsigned int, ibuf->rect[x_offset + xr], ibuf->rect[x_offset + xl]);
}
}
}
if (ibuf->rect_float) {
for (yi = y - 1; yi >= 0; yi--) {
+ const size_t x_offset = (size_t)x * yi;
for (xr = x - 1, xl = 0; xr >= xl; xr--, xl++) {
- memcpy(&px_f, &ibuf->rect_float[((x * yi) + xr) * 4], sizeof(float[4]));
- memcpy(&ibuf->rect_float[((x * yi) + xr) * 4],
- &ibuf->rect_float[((x * yi) + xl) * 4],
+ memcpy(&px_f, &ibuf->rect_float[(x_offset + xr) * 4], sizeof(float[4]));
+ memcpy(&ibuf->rect_float[(x_offset + xr) * 4],
+ &ibuf->rect_float[(x_offset + xl) * 4],
sizeof(float[4]));
- memcpy(&ibuf->rect_float[((x * yi) + xl) * 4], &px_f, sizeof(float[4]));
+ memcpy(&ibuf->rect_float[(x_offset + xl) * 4], &px_f, sizeof(float[4]));
}
}
}
diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c
index 1c4b7af6ef1..a18ba6748de 100644
--- a/source/blender/imbuf/intern/scaling.c
+++ b/source/blender/imbuf/intern/scaling.c
@@ -372,7 +372,6 @@ MINLINE void premul_ushort_to_straight_uchar(unsigned char *result, const unsign
}
}
-/* result in ibuf2, scaling should be done correctly */
void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1)
{
int x, y;
@@ -912,7 +911,7 @@ static ImBuf *scaledownx(struct ImBuf *ibuf, int newx)
{
const int do_rect = (ibuf->rect != NULL);
const int do_float = (ibuf->rect_float != NULL);
- const size_t rect_size = ibuf->x * ibuf->y * 4;
+ const size_t rect_size = IMB_get_rect_len(ibuf) * 4;
uchar *rect, *_newrect, *newrect;
float *rectf, *_newrectf, *newrectf;
@@ -1053,7 +1052,7 @@ static ImBuf *scaledowny(struct ImBuf *ibuf, int newy)
{
const int do_rect = (ibuf->rect != NULL);
const int do_float = (ibuf->rect_float != NULL);
- const size_t rect_size = ibuf->x * ibuf->y * 4;
+ const size_t rect_size = IMB_get_rect_len(ibuf) * 4;
uchar *rect, *_newrect, *newrect;
float *rectf, *_newrectf, *newrectf;
@@ -1661,9 +1660,6 @@ static void scalefast_Z_ImBuf(ImBuf *ibuf, int newx, int newy)
}
}
-/**
- * Return true if \a ibuf is modified.
- */
bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
{
BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!");
@@ -1709,9 +1705,6 @@ struct imbufRGBA {
float r, g, b, a;
};
-/**
- * Return true if \a ibuf is modified.
- */
bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
{
BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!");
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index d3c91b55f22..dae2604802f 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -757,7 +757,6 @@ float *IMB_stereo3d_from_rectf(ImageFormatData *im_format,
return r_rectf;
}
-/* left/right are always float */
ImBuf *IMB_stereo3d_ImBuf(ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
{
ImBuf *ibuf_stereo = NULL;
@@ -1275,7 +1274,6 @@ static void imb_stereo3d_read_topbottom(Stereo3DData *s3d)
/** \name Preparing To Call The Read Functions
* \{ */
-/* reading a stereo encoded ibuf (*left) and generating two ibufs from it (*left and *right) */
void IMB_ImBufFromStereo3d(Stereo3dFormat *s3d,
ImBuf *ibuf_stereo3d,
ImBuf **r_ibuf_left,
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index aa1da65253d..c39ce2e9a2a 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -523,7 +523,6 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
path, uri, thumb_name, false, THUMB_DEFAULT_HASH, NULL, NULL, size, source, img);
}
-/* read thumbnail for file and returns new imbuf for thumbnail */
ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
{
char thumb[FILE_MAX];
@@ -540,7 +539,6 @@ ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
return img;
}
-/* delete all thumbs for the file */
void IMB_thumb_delete(const char *path, ThumbSize size)
{
char thumb[FILE_MAX];
@@ -559,7 +557,6 @@ void IMB_thumb_delete(const char *path, ThumbSize size)
}
}
-/* create the thumb if necessary and manage failed and old thumbs */
ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source)
{
char thumb_path[FILE_MAX];
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index d9e1db27ef0..1d3589f00a6 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -29,7 +29,7 @@
* high-level routine that loads all images as 32-bit RGBA, handling all the
* required conversions between many different TIFF types internally.
*
- * Saving supports RGB, RGBA and BW (grayscale) images correctly, with
+ * Saving supports RGB, RGBA and BW (gray-scale) images correctly, with
* 8 bits per channel in all cases. The "deflate" compression algorithm is
* used to compress images.
*/
@@ -52,7 +52,7 @@
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
-#include "tiffio.h"
+#include <tiffio.h>
#ifdef WIN32
# include "utfconv.h"
@@ -457,7 +457,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
}
/* simple RGBA image */
- if (!(bitspersample == 32 || bitspersample == 16)) {
+ if (!(ELEM(bitspersample, 32, 16))) {
success |= TIFFReadRGBAImage(image, ibuf->x, ibuf->y, tmpibuf->rect, 0);
}
/* contiguous channels: RGBRGBRGB */
@@ -488,7 +488,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
if (chan == 3 && spp == 3) { /* fill alpha if only RGB TIFF */
copy_vn_fl(fbuf, ibuf->x, 1.0f);
}
- else if (chan >= spp) { /* for grayscale, duplicate first channel into G and B */
+ else if (chan >= spp) { /* For gray-scale, duplicate first channel into G and B. */
success |= TIFFReadScanline(image, fbuf, row, 0);
}
else {
@@ -500,7 +500,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
if (chan == 3 && spp == 3) { /* fill alpha if only RGB TIFF */
copy_vn_ushort(sbuf, ibuf->x, 65535);
}
- else if (chan >= spp) { /* for grayscale, duplicate first channel into G and B */
+ else if (chan >= spp) { /* For gray-scale, duplicate first channel into G and B. */
success |= TIFFReadScanline(image, fbuf, row, 0);
}
else {
@@ -553,15 +553,6 @@ void imb_inittiff(void)
}
}
-/**
- * Loads a TIFF file.
- * \param mem: Memory containing the TIFF file.
- * \param size: Size of the mem buffer.
- * \param flags: If flags has IB_test set then the file is not actually loaded,
- * but all other operations take place.
- *
- * \return A newly allocated #ImBuf structure if successful, otherwise NULL.
- */
ImBuf *imb_loadtiff(const unsigned char *mem,
size_t size,
int flags,
@@ -744,21 +735,6 @@ void imb_loadtiletiff(
/** \name Save TIFF
* \{ */
-/**
- * Saves a TIFF file.
- *
- * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA
- * respectively) are accepted, and interpreted correctly. Note that the TIFF
- * convention is to use pre-multiplied alpha, which can be achieved within
- * Blender by setting "Premul" alpha handling. Other alpha conventions are
- * not strictly correct, but are permitted anyhow.
- *
- * \param ibuf: Image buffer.
- * \param name: Name of the TIFF file to create.
- * \param flags: Currently largely ignored.
- *
- * \return 1 if the function is successful, 0 on failure.
- */
bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
{
TIFF *image = NULL;
@@ -872,7 +848,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
}
else if (samplesperpixel == 1) {
- /* grayscale images, 1 channel */
+ /* Gray-scale images, 1 channel */
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
}
@@ -895,9 +871,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
copy_v3_v3(rgb, &fromf[from_i]);
}
else {
- /* Standard linear-to-srgb conversion if float buffer
- * wasn't managed.
- */
+ /* Standard linear-to-SRGB conversion if float buffer wasn't managed. */
linearrgb_to_srgb_v3_v3(rgb, &fromf[from_i]);
}
if (channels_in_float == 4) {
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
new file mode 100644
index 00000000000..e1c451a8412
--- /dev/null
+++ b/source/blender/imbuf/intern/transform.cc
@@ -0,0 +1,604 @@
+/*
+ * 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 imbuf
+ */
+
+#include <array>
+#include <type_traits>
+
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+namespace blender::imbuf::transform {
+
+struct TransformUserData {
+ /** \brief Source image buffer to read from. */
+ const ImBuf *src;
+ /** \brief Destination image buffer to write to. */
+ ImBuf *dst;
+ /** \brief UV coordinates at the origin (0,0) in source image space. */
+ float start_uv[2];
+
+ /**
+ * \brief delta UV coordinates along the source image buffer, when moving a single pixel in the X
+ * axis of the dst image buffer.
+ */
+ float add_x[2];
+
+ /**
+ * \brief delta UV coordinate along the source image buffer, when moving a single pixel in the Y
+ * axes of the dst image buffer.
+ */
+ float add_y[2];
+
+ /**
+ * \brief Cropping region in source image pixel space.
+ */
+ rctf src_crop;
+
+ /**
+ * \brief Initialize the start_uv, add_x and add_y fields based on the given transform matrix.
+ */
+ void init(const float transform_matrix[4][4])
+ {
+ init_start_uv(transform_matrix);
+ init_add_x(transform_matrix);
+ init_add_y(transform_matrix);
+ }
+
+ private:
+ void init_start_uv(const float transform_matrix[4][4])
+ {
+ float start_uv_v3[3];
+ float orig[3];
+ zero_v3(orig);
+ mul_v3_m4v3(start_uv_v3, transform_matrix, orig);
+ copy_v2_v2(start_uv, start_uv_v3);
+ }
+
+ void init_add_x(const float transform_matrix[4][4])
+ {
+ const int width = src->x;
+ float add_x_v3[3];
+ float uv_max_x[3];
+ zero_v3(uv_max_x);
+ uv_max_x[0] = width;
+ uv_max_x[1] = 0.0f;
+ mul_v3_m4v3(add_x_v3, transform_matrix, uv_max_x);
+ sub_v2_v2(add_x_v3, start_uv);
+ mul_v2_fl(add_x_v3, 1.0f / width);
+ copy_v2_v2(add_x, add_x_v3);
+ }
+
+ void init_add_y(const float transform_matrix[4][4])
+ {
+ const int height = src->y;
+ float add_y_v3[3];
+ float uv_max_y[3];
+ zero_v3(uv_max_y);
+ uv_max_y[0] = 0.0f;
+ uv_max_y[1] = height;
+ mul_v3_m4v3(add_y_v3, transform_matrix, uv_max_y);
+ sub_v2_v2(add_y_v3, start_uv);
+ mul_v2_fl(add_y_v3, 1.0f / height);
+ copy_v2_v2(add_y, add_y_v3);
+ }
+};
+
+/**
+ * \brief Base class for source discarding.
+ *
+ * The class decides if a specific uv coordinate from the source buffer should be ignored.
+ * This is used to mix multiple images over a single output buffer. Discarded pixels will
+ * not change the output buffer.
+ */
+class BaseDiscard {
+ public:
+ virtual ~BaseDiscard() = default;
+
+ /**
+ * \brief Should the source pixel at the given uv coordinate be discarded.
+ */
+ virtual bool should_discard(const TransformUserData &user_data, const float uv[2]) = 0;
+};
+
+/**
+ * \brief Crop uv-coordinates that are outside the user data src_crop rect.
+ */
+class CropSource : public BaseDiscard {
+ public:
+ /**
+ * \brief Should the source pixel at the given uv coordinate be discarded.
+ *
+ * Uses user_data.src_crop to determine if the uv coordinate should be skipped.
+ */
+ bool should_discard(const TransformUserData &user_data, const float uv[2]) override
+ {
+ return uv[0] < user_data.src_crop.xmin || uv[0] >= user_data.src_crop.xmax ||
+ uv[1] < user_data.src_crop.ymin || uv[1] >= user_data.src_crop.ymax;
+ }
+};
+
+/**
+ * \brief Discard that does not discard anything.
+ */
+class NoDiscard : public BaseDiscard {
+ public:
+ /**
+ * \brief Should the source pixel at the given uv coordinate be discarded.
+ *
+ * Will never discard any pixels.
+ */
+ bool should_discard(const TransformUserData &UNUSED(user_data),
+ const float UNUSED(uv[2])) override
+ {
+ return false;
+ }
+};
+
+/**
+ * \brief Pointer to a pixel to write to in serial.
+ */
+template<
+ /**
+ * \brief Kind of buffer.
+ * Possible options: float, unsigned char.
+ */
+ typename StorageType = float,
+
+ /**
+ * \brief Number of channels of a single pixel.
+ */
+ int NumChannels = 4>
+class PixelPointer {
+ public:
+ static const int ChannelLen = NumChannels;
+
+ private:
+ StorageType *pointer;
+
+ public:
+ void init_pixel_pointer(const ImBuf *image_buffer, int x, int y)
+ {
+ const size_t offset = (y * (size_t)image_buffer->x + x) * NumChannels;
+
+ if constexpr (std::is_same_v<StorageType, float>) {
+ pointer = image_buffer->rect_float + offset;
+ }
+ else if constexpr (std::is_same_v<StorageType, unsigned char>) {
+ pointer = const_cast<unsigned char *>(
+ static_cast<const unsigned char *>(static_cast<const void *>(image_buffer->rect)) +
+ offset);
+ }
+ else {
+ pointer = nullptr;
+ }
+ }
+
+ /**
+ * \brief Get pointer to the current pixel to write to.
+ */
+ StorageType *get_pointer()
+ {
+ return pointer;
+ }
+
+ void increase_pixel_pointer()
+ {
+ pointer += NumChannels;
+ }
+};
+
+/**
+ * \brief Wrapping mode for the uv coordinates.
+ *
+ * Subclasses have the ability to change the UV coordinates when sampling the source buffer.
+ */
+class BaseUVWrapping {
+ public:
+ /**
+ * \brief modify the given u coordinate.
+ */
+ virtual float modify_u(const ImBuf *source_buffer, float u) = 0;
+
+ /**
+ * \brief modify the given v coordinate.
+ */
+ virtual float modify_v(const ImBuf *source_buffer, float v) = 0;
+};
+
+/**
+ * \brief UVWrapping method that does not modify the UV coordinates.
+ */
+class PassThroughUV : public BaseUVWrapping {
+ public:
+ float modify_u(const ImBuf *UNUSED(source_buffer), float u) override
+ {
+ return u;
+ }
+
+ float modify_v(const ImBuf *UNUSED(source_buffer), float v) override
+ {
+ return v;
+ }
+};
+
+/**
+ * \brief UVWrapping method that wrap repeats the UV coordinates.
+ */
+class WrapRepeatUV : public BaseUVWrapping {
+ public:
+ float modify_u(const ImBuf *source_buffer, float u) override
+
+ {
+ int x = (int)floor(u);
+ x = x % source_buffer->x;
+ if (x < 0) {
+ x += source_buffer->x;
+ }
+ return x;
+ }
+
+ float modify_v(const ImBuf *source_buffer, float v) override
+ {
+ int y = (int)floor(v);
+ y = y % source_buffer->y;
+ if (y < 0) {
+ y += source_buffer->y;
+ }
+ return y;
+ }
+};
+
+/**
+ * \brief Read a sample from an image buffer.
+ *
+ * A sampler can read from an image buffer.
+ *
+ */
+template<
+ /** \brief Interpolation mode to use when sampling. */
+ eIMBInterpolationFilterMode Filter,
+
+ /** \brief storage type of a single pixel channel (unsigned char or float). */
+ typename StorageType,
+ /**
+ * \brief number of channels if the image to read.
+ *
+ * Must match the actual channels of the image buffer that is sampled.
+ */
+ int NumChannels,
+ /**
+ * \brief Wrapping method to perform
+ *
+ * Should be a subclass of BaseUVWrapper
+ */
+ typename UVWrapping>
+class Sampler {
+ UVWrapping uv_wrapper;
+
+ public:
+ using ChannelType = StorageType;
+ static const int ChannelLen = NumChannels;
+ using SampleType = std::array<StorageType, NumChannels>;
+
+ void sample(const ImBuf *source, const float u, const float v, SampleType &r_sample)
+ {
+ if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float> &&
+ NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ bilinear_interpolation_color_fl(source, nullptr, &r_sample[0], wrapped_u, wrapped_v);
+ }
+ else if constexpr (Filter == IMB_FILTER_NEAREST &&
+ std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ nearest_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
+ }
+ else if constexpr (Filter == IMB_FILTER_BILINEAR &&
+ std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ bilinear_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
+ }
+ else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float>) {
+ if constexpr (std::is_same_v<UVWrapping, WrapRepeatUV>) {
+ BLI_bilinear_interpolation_wrap_fl(
+ source->rect_float, &r_sample[0], source->x, source->y, NumChannels, u, v, true, true);
+ }
+ else {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ BLI_bilinear_interpolation_fl(source->rect_float,
+ &r_sample[0],
+ source->x,
+ source->y,
+ NumChannels,
+ wrapped_u,
+ wrapped_v);
+ }
+ }
+ else if constexpr (Filter == IMB_FILTER_NEAREST && std::is_same_v<StorageType, float>) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ sample_nearest_float(source, wrapped_u, wrapped_v, r_sample);
+ }
+ else {
+ /* Unsupported sampler. */
+ BLI_assert_unreachable();
+ }
+ }
+
+ private:
+ void sample_nearest_float(const ImBuf *source,
+ const float u,
+ const float v,
+ SampleType &r_sample)
+ {
+ BLI_STATIC_ASSERT(std::is_same_v<StorageType, float>);
+
+ /* ImBuf in must have a valid rect or rect_float, assume this is already checked */
+ int x1 = (int)(u);
+ int y1 = (int)(v);
+
+ /* Break when sample outside image is requested. */
+ if (x1 < 0 || x1 >= source->x || y1 < 0 || y1 >= source->y) {
+ for (int i = 0; i < NumChannels; i++) {
+ r_sample[i] = 0.0f;
+ }
+ return;
+ }
+
+ const size_t offset = ((size_t)source->x * y1 + x1) * NumChannels;
+ const float *dataF = source->rect_float + offset;
+ for (int i = 0; i < NumChannels; i++) {
+ r_sample[i] = dataF[i];
+ }
+ }
+};
+
+/**
+ * \brief Change the number of channels and store it.
+ *
+ * Template class to convert and store a sample in a PixelPointer.
+ * It supports:
+ * - 4 channel unsigned char -> 4 channel unsigned char.
+ * - 4 channel float -> 4 channel float.
+ * - 3 channel float -> 4 channel float.
+ * - 2 channel float -> 4 channel float.
+ * - 1 channel float -> 4 channel float.
+ */
+template<typename StorageType, int SourceNumChannels, int DestinationNumChannels>
+class ChannelConverter {
+ public:
+ using SampleType = std::array<StorageType, SourceNumChannels>;
+ using PixelType = PixelPointer<StorageType, DestinationNumChannels>;
+
+ /**
+ * \brief Convert the number of channels of the given sample to match the pixel pointer and store
+ * it at the location the pixel_pointer points at.
+ */
+ void convert_and_store(const SampleType &sample, PixelType &pixel_pointer)
+ {
+ if constexpr (std::is_same_v<StorageType, unsigned char>) {
+ BLI_STATIC_ASSERT(SourceNumChannels == 4, "Unsigned chars always have 4 channels.");
+ BLI_STATIC_ASSERT(DestinationNumChannels == 4, "Unsigned chars always have 4 channels.");
+
+ copy_v4_v4_uchar(pixel_pointer.get_pointer(), &sample[0]);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 4 &&
+ DestinationNumChannels == 4) {
+ copy_v4_v4(pixel_pointer.get_pointer(), &sample[0]);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 3 &&
+ DestinationNumChannels == 4) {
+ copy_v4_fl4(pixel_pointer.get_pointer(), sample[0], sample[1], sample[2], 1.0f);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 2 &&
+ DestinationNumChannels == 4) {
+ copy_v4_fl4(pixel_pointer.get_pointer(), sample[0], sample[1], 0.0f, 1.0f);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 1 &&
+ DestinationNumChannels == 4) {
+ copy_v4_fl4(pixel_pointer.get_pointer(), sample[0], sample[0], sample[0], 1.0f);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ }
+};
+
+/**
+ * \brief Processor for a scanline.
+ */
+template<
+ /**
+ * \brief Discard function to use.
+ *
+ * \attention Should be a subclass of BaseDiscard.
+ */
+ typename Discard,
+
+ /**
+ * \brief Color interpolation function to read from the source buffer.
+ */
+ typename Sampler,
+
+ /**
+ * \brief Kernel to store to the destination buffer.
+ * Should be an PixelPointer
+ */
+ typename OutputPixelPointer>
+class ScanlineProcessor {
+ Discard discarder;
+ OutputPixelPointer output;
+ Sampler sampler;
+
+ /**
+ * \brief Channels sizzling logic to convert between the input image buffer and the output image
+ * buffer.
+ */
+ ChannelConverter<typename Sampler::ChannelType,
+ Sampler::ChannelLen,
+ OutputPixelPointer::ChannelLen>
+ channel_converter;
+
+ public:
+ /**
+ * \brief Inner loop of the transformations, processing a full scanline.
+ */
+ void process(const TransformUserData *user_data, int scanline)
+ {
+ const int width = user_data->dst->x;
+
+ float uv[2];
+ madd_v2_v2v2fl(uv, user_data->start_uv, user_data->add_y, scanline);
+
+ output.init_pixel_pointer(user_data->dst, 0, scanline);
+ for (int xi = 0; xi < width; xi++) {
+ if (!discarder.should_discard(*user_data, uv)) {
+ typename Sampler::SampleType sample;
+ sampler.sample(user_data->src, uv[0], uv[1], sample);
+ channel_converter.convert_and_store(sample, output);
+ }
+
+ add_v2_v2(uv, user_data->add_x);
+ output.increase_pixel_pointer();
+ }
+ }
+};
+
+/**
+ * \brief callback function for threaded transformation.
+ */
+template<typename Processor> void transform_scanline_function(void *custom_data, int scanline)
+{
+ const TransformUserData *user_data = static_cast<const TransformUserData *>(custom_data);
+ Processor processor;
+ processor.process(user_data, scanline);
+}
+
+template<eIMBInterpolationFilterMode Filter,
+ typename StorageType,
+ int SourceNumChannels,
+ int DestinationNumChannels>
+ScanlineThreadFunc get_scanline_function(const eIMBTransformMode mode)
+
+{
+ switch (mode) {
+ case IMB_TRANSFORM_MODE_REGULAR:
+ return transform_scanline_function<
+ ScanlineProcessor<NoDiscard,
+ Sampler<Filter, StorageType, SourceNumChannels, PassThroughUV>,
+ PixelPointer<StorageType, DestinationNumChannels>>>;
+ case IMB_TRANSFORM_MODE_CROP_SRC:
+ return transform_scanline_function<
+ ScanlineProcessor<CropSource,
+ Sampler<Filter, StorageType, SourceNumChannels, PassThroughUV>,
+ PixelPointer<StorageType, DestinationNumChannels>>>;
+ case IMB_TRANSFORM_MODE_WRAP_REPEAT:
+ return transform_scanline_function<
+ ScanlineProcessor<NoDiscard,
+ Sampler<Filter, StorageType, SourceNumChannels, WrapRepeatUV>,
+ PixelPointer<StorageType, DestinationNumChannels>>>;
+ }
+
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+template<eIMBInterpolationFilterMode Filter>
+ScanlineThreadFunc get_scanline_function(const TransformUserData *user_data,
+ const eIMBTransformMode mode)
+{
+ const ImBuf *src = user_data->src;
+ const ImBuf *dst = user_data->dst;
+
+ if (src->channels == 4 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 4, 4>(mode);
+ }
+ if (src->channels == 3 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 3, 4>(mode);
+ }
+ if (src->channels == 2 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 2, 4>(mode);
+ }
+ if (src->channels == 1 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 1, 4>(mode);
+ }
+ return nullptr;
+}
+
+template<eIMBInterpolationFilterMode Filter>
+static void transform_threaded(TransformUserData *user_data, const eIMBTransformMode mode)
+{
+ ScanlineThreadFunc scanline_func = nullptr;
+
+ if (user_data->dst->rect_float && user_data->src->rect_float) {
+ scanline_func = get_scanline_function<Filter>(user_data, mode);
+ }
+ else if (user_data->dst->rect && user_data->src->rect) {
+ /* Number of channels is always 4 when using unsigned char buffers (sRGB + straight alpha). */
+ scanline_func = get_scanline_function<Filter, unsigned char, 4, 4>(mode);
+ }
+
+ if (scanline_func != nullptr) {
+ IMB_processor_apply_threaded_scanlines(user_data->dst->y, scanline_func, user_data);
+ }
+}
+
+} // namespace blender::imbuf::transform
+
+extern "C" {
+
+using namespace blender::imbuf::transform;
+
+void IMB_transform(const struct ImBuf *src,
+ struct ImBuf *dst,
+ const eIMBTransformMode mode,
+ const eIMBInterpolationFilterMode filter,
+ const float transform_matrix[4][4],
+ const struct rctf *src_crop)
+{
+ BLI_assert_msg(mode != IMB_TRANSFORM_MODE_CROP_SRC || src_crop != nullptr,
+ "No source crop rect given, but crop source is requested. Or source crop rect "
+ "was given, but crop source was not requested.");
+
+ TransformUserData user_data;
+ user_data.src = src;
+ user_data.dst = dst;
+ if (mode == IMB_TRANSFORM_MODE_CROP_SRC) {
+ user_data.src_crop = *src_crop;
+ }
+ user_data.init(transform_matrix);
+
+ if (filter == IMB_FILTER_NEAREST) {
+ transform_threaded<IMB_FILTER_NEAREST>(&user_data, mode);
+ }
+ else {
+ transform_threaded<IMB_FILTER_BILINEAR>(&user_data, mode);
+ }
+}
+}
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index 1bb047f1317..18ed4710e78 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -98,7 +98,7 @@ const char *imb_ext_movie[] = {
".mpg2", ".vob", ".mkv", ".flv", ".divx", ".xvid", ".mxf", ".webm", NULL,
};
-/* sort of wrong being here... */
+/** Sort of wrong having audio extensions in imbuf. */
const char *imb_ext_audio[] = {
".wav",
".ogg",
diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c
index 2b99a0aa81d..cc6fef634d5 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -162,8 +162,6 @@ static void *imb_gpu_get_data(const ImBuf *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(
const char *name, ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth)
{
@@ -183,9 +181,6 @@ GPUTexture *IMB_touch_gpu_texture(
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,
diff --git a/source/blender/io/CMakeLists.txt b/source/blender/io/CMakeLists.txt
index f11ad7627b9..b97b3ef97de 100644
--- a/source/blender/io/CMakeLists.txt
+++ b/source/blender/io/CMakeLists.txt
@@ -19,6 +19,7 @@
# ***** END GPL LICENSE BLOCK *****
add_subdirectory(common)
+add_subdirectory(wavefront_obj)
if(WITH_ALEMBIC)
add_subdirectory(alembic)
diff --git a/source/blender/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h
index 0b5e927f02f..18b0c91b67c 100644
--- a/source/blender/io/alembic/ABC_alembic.h
+++ b/source/blender/io/alembic/ABC_alembic.h
@@ -26,6 +26,7 @@ extern "C" {
#endif
struct CacheArchiveHandle;
+struct CacheFileLayer;
struct CacheReader;
struct ListBase;
struct Main;
@@ -102,6 +103,7 @@ bool ABC_import(struct bContext *C,
struct CacheArchiveHandle *ABC_create_handle(struct Main *bmain,
const char *filename,
+ const struct CacheFileLayer *layers,
struct ListBase *object_paths);
void ABC_free_handle(struct CacheArchiveHandle *handle);
@@ -115,16 +117,16 @@ void ABC_get_transform(struct CacheReader *reader,
struct Mesh *ABC_read_mesh(struct CacheReader *reader,
struct Object *ob,
struct Mesh *existing_mesh,
- const float time,
+ float time,
const char **err_str,
- const int read_flags,
+ int read_flags,
const char *velocity_name,
- const float velocity_scale);
+ float velocity_scale);
bool ABC_mesh_topology_changed(struct CacheReader *reader,
struct Object *ob,
struct Mesh *existing_mesh,
- const float time,
+ float time,
const char **err_str);
void ABC_CacheReader_incref(struct CacheReader *reader);
diff --git a/source/blender/io/alembic/exporter/abc_archive.cc b/source/blender/io/alembic/exporter/abc_archive.cc
index e066704cd24..c070539fc94 100644
--- a/source/blender/io/alembic/exporter/abc_archive.cc
+++ b/source/blender/io/alembic/exporter/abc_archive.cc
@@ -51,7 +51,7 @@ static MetaData create_abc_metadata(const Main *bmain, double scene_fps)
{
MetaData abc_metadata;
- std::string abc_user_description(bmain->name);
+ std::string abc_user_description(bmain->filepath);
if (abc_user_description.empty()) {
abc_user_description = "unknown";
}
diff --git a/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc b/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc
index 8073e157c13..bd12f3c10d3 100644
--- a/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc
+++ b/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc
@@ -72,8 +72,6 @@ void SubdivModifierDisabler::disable_modifiers()
}
}
-/* Check if the mesh is a subsurf, ignoring disabled modifiers and
- * displace if it's after subsurf. */
ModifierData *SubdivModifierDisabler::get_subdiv_modifier(Scene *scene, Object *ob)
{
ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last);
diff --git a/source/blender/io/alembic/exporter/abc_subdiv_disabler.h b/source/blender/io/alembic/exporter/abc_subdiv_disabler.h
index 3556df7ff31..c6541fd8afe 100644
--- a/source/blender/io/alembic/exporter/abc_subdiv_disabler.h
+++ b/source/blender/io/alembic/exporter/abc_subdiv_disabler.h
@@ -45,6 +45,10 @@ class SubdivModifierDisabler final {
void disable_modifiers();
+ /**
+ * Check if the mesh is a subsurf, ignoring disabled modifiers and
+ * displace if it's after subsurf.
+ */
static ModifierData *get_subdiv_modifier(Scene *scene, Object *ob);
};
diff --git a/source/blender/io/alembic/exporter/abc_writer_hair.cc b/source/blender/io/alembic/exporter/abc_writer_hair.cc
index 80f2cadd08c..e8c156a2b8d 100644
--- a/source/blender/io/alembic/exporter/abc_writer_hair.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_hair.cc
@@ -136,6 +136,7 @@ void ABCHairWriter::write_hair_sample(const HierarchyContext &context,
MTFace *mtface = mesh->mtface;
MFace *mface = mesh->mface;
MVert *mverts = mesh->mvert;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
if ((!mtface || !mface) && !uv_warning_shown_) {
std::fprintf(stderr,
@@ -173,8 +174,17 @@ void ABCHairWriter::write_hair_sample(const HierarchyContext &context,
psys_interpolate_uvs(tface, face->v4, pa->fuv, r_uv);
uv_values.emplace_back(r_uv[0], r_uv[1]);
- psys_interpolate_face(
- mverts, face, tface, nullptr, mapfw, vec, normal, nullptr, nullptr, nullptr);
+ psys_interpolate_face(mverts,
+ vert_normals,
+ face,
+ tface,
+ nullptr,
+ mapfw,
+ vec,
+ normal,
+ nullptr,
+ nullptr,
+ nullptr);
copy_yup_from_zup(tmp_nor.getValue(), normal);
norm_values.push_back(tmp_nor);
@@ -206,10 +216,7 @@ void ABCHairWriter::write_hair_sample(const HierarchyContext &context,
if (vtx[o] == num) {
uv_values.emplace_back(tface->uv[o][0], tface->uv[o][1]);
-
- MVert *mv = mverts + vtx[o];
-
- normal_short_to_float_v3(normal, mv->no);
+ copy_v3_v3(normal, vert_normals[vtx[o]]);
copy_yup_from_zup(tmp_nor.getValue(), normal);
norm_values.push_back(tmp_nor);
found = true;
@@ -250,6 +257,7 @@ void ABCHairWriter::write_hair_child_sample(const HierarchyContext &context,
MTFace *mtface = mesh->mtface;
MVert *mverts = mesh->mvert;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
ParticleSystem *psys = context.particle_system;
ParticleSettings *part = psys->part;
@@ -281,8 +289,17 @@ void ABCHairWriter::write_hair_child_sample(const HierarchyContext &context,
psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv);
uv_values.emplace_back(r_uv[0], r_uv[1]);
- psys_interpolate_face(
- mverts, face, tface, nullptr, mapfw, vec, tmpnor, nullptr, nullptr, nullptr);
+ psys_interpolate_face(mverts,
+ vert_normals,
+ face,
+ tface,
+ nullptr,
+ mapfw,
+ vec,
+ tmpnor,
+ nullptr,
+ nullptr,
+ nullptr);
/* Convert Z-up to Y-up. */
norm_values.emplace_back(tmpnor[0], tmpnor[2], -tmpnor[1]);
diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
index 8f410978211..6ab4b06fba6 100644
--- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
@@ -76,10 +76,13 @@ static void get_topology(struct Mesh *mesh,
std::vector<int32_t> &poly_verts,
std::vector<int32_t> &loop_counts,
bool &r_has_flat_shaded_poly);
-static void get_creases(struct Mesh *mesh,
- std::vector<int32_t> &indices,
- std::vector<int32_t> &lengths,
- std::vector<float> &sharpnesses);
+static void get_edge_creases(struct Mesh *mesh,
+ std::vector<int32_t> &indices,
+ std::vector<int32_t> &lengths,
+ std::vector<float> &sharpnesses);
+static void get_vert_creases(struct Mesh *mesh,
+ std::vector<int32_t> &indices,
+ std::vector<float> &sharpnesses);
static void get_loop_normals(struct Mesh *mesh,
std::vector<Imath::V3f> &normals,
bool has_flat_shaded_poly);
@@ -166,9 +169,10 @@ void ABCGenericMeshWriter::do_write(HierarchyContext &context)
const int quad_method = args_.export_params->quad_method;
const int ngon_method = args_.export_params->ngon_method;
- struct BMeshCreateParams bmcp = {false};
- struct BMeshFromMeshParams bmfmp = {true, false, false, 0};
- BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmcp, &bmfmp);
+ BMeshCreateParams bmesh_create_params{};
+ BMeshFromMeshParams bmesh_from_mesh_params{};
+ bmesh_from_mesh_params.calc_face_normal = true;
+ BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params);
BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, nullptr, nullptr, nullptr);
@@ -189,6 +193,7 @@ void ABCGenericMeshWriter::do_write(HierarchyContext &context)
m_custom_data_config.totpoly = mesh->totpoly;
m_custom_data_config.totloop = mesh->totloop;
m_custom_data_config.totvert = mesh->totvert;
+ m_custom_data_config.timesample_index = timesample_index_;
try {
if (is_subd_) {
@@ -281,15 +286,16 @@ void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
void ABCGenericMeshWriter::write_subd(HierarchyContext &context, struct Mesh *mesh)
{
- std::vector<float> crease_sharpness;
+ std::vector<float> edge_crease_sharpness, vert_crease_sharpness;
std::vector<Imath::V3f> points;
std::vector<int32_t> poly_verts, loop_counts;
- std::vector<int32_t> crease_indices, crease_lengths;
+ std::vector<int32_t> edge_crease_indices, edge_crease_lengths, vert_crease_indices;
bool has_flat_poly = false;
get_vertices(mesh, points);
get_topology(mesh, poly_verts, loop_counts, has_flat_poly);
- get_creases(mesh, crease_indices, crease_lengths, crease_sharpness);
+ get_edge_creases(mesh, edge_crease_indices, edge_crease_lengths, edge_crease_sharpness);
+ get_vert_creases(mesh, vert_crease_indices, vert_crease_sharpness);
if (!frame_has_been_written_ && args_.export_params->face_sets) {
write_face_sets(context.object, mesh, abc_subdiv_schema_);
@@ -320,10 +326,15 @@ void ABCGenericMeshWriter::write_subd(HierarchyContext &context, struct Mesh *me
write_generated_coordinates(abc_poly_mesh_schema_.getArbGeomParams(), m_custom_data_config);
}
- if (!crease_indices.empty()) {
- subdiv_sample.setCreaseIndices(Int32ArraySample(crease_indices));
- subdiv_sample.setCreaseLengths(Int32ArraySample(crease_lengths));
- subdiv_sample.setCreaseSharpnesses(FloatArraySample(crease_sharpness));
+ if (!edge_crease_indices.empty()) {
+ subdiv_sample.setCreaseIndices(Int32ArraySample(edge_crease_indices));
+ subdiv_sample.setCreaseLengths(Int32ArraySample(edge_crease_lengths));
+ subdiv_sample.setCreaseSharpnesses(FloatArraySample(edge_crease_sharpness));
+ }
+
+ if (!vert_crease_indices.empty()) {
+ subdiv_sample.setCornerIndices(Int32ArraySample(vert_crease_indices));
+ subdiv_sample.setCornerSharpnesses(FloatArraySample(vert_crease_sharpness));
}
update_bounding_box(context.object);
@@ -350,7 +361,7 @@ void ABCGenericMeshWriter::write_face_sets(Object *object, struct Mesh *mesh, Sc
void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me)
{
- if (frame_has_been_written_ || !args_.export_params->vcolors) {
+ if (!args_.export_params->vcolors) {
return;
}
@@ -475,10 +486,10 @@ static void get_topology(struct Mesh *mesh,
}
}
-static void get_creases(struct Mesh *mesh,
- std::vector<int32_t> &indices,
- std::vector<int32_t> &lengths,
- std::vector<float> &sharpnesses)
+static void get_edge_creases(struct Mesh *mesh,
+ std::vector<int32_t> &indices,
+ std::vector<int32_t> &lengths,
+ std::vector<float> &sharpnesses)
{
const float factor = 1.0f / 255.0f;
@@ -501,6 +512,29 @@ static void get_creases(struct Mesh *mesh,
lengths.resize(sharpnesses.size(), 2);
}
+static void get_vert_creases(struct Mesh *mesh,
+ std::vector<int32_t> &indices,
+ std::vector<float> &sharpnesses)
+{
+ indices.clear();
+ sharpnesses.clear();
+
+ const float *creases = static_cast<const float *>(CustomData_get_layer(&mesh->vdata, CD_CREASE));
+
+ if (!creases) {
+ return;
+ }
+
+ for (int i = 0, v = mesh->totvert; i < v; i++) {
+ const float sharpness = creases[i];
+
+ if (sharpness != 0.0f) {
+ indices.push_back(i);
+ sharpnesses.push_back(sharpness);
+ }
+ }
+}
+
static void get_loop_normals(struct Mesh *mesh,
std::vector<Imath::V3f> &normals,
bool has_flat_shaded_poly)
diff --git a/source/blender/io/alembic/exporter/abc_writer_points.cc b/source/blender/io/alembic/exporter/abc_writer_points.cc
index 70608fdbe92..2db9ad4ffab 100644
--- a/source/blender/io/alembic/exporter/abc_writer_points.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_points.cc
@@ -112,7 +112,7 @@ void ABCPointsWriter::do_write(HierarchyContext &context)
}
state.time = DEG_get_ctime(args_.depsgraph);
- if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
+ if (psys_get_particle_state(&sim, p, &state, false) == 0) {
continue;
}
diff --git a/source/blender/io/alembic/intern/abc_axis_conversion.cc b/source/blender/io/alembic/intern/abc_axis_conversion.cc
index 23b24d2fd9a..78ea7166faf 100644
--- a/source/blender/io/alembic/intern/abc_axis_conversion.cc
+++ b/source/blender/io/alembic/intern/abc_axis_conversion.cc
@@ -75,8 +75,6 @@ void create_swapped_rotation_matrix(float rot_x_mat[3][3],
} // namespace
// alembicvoidcreate_swapped_rotation_matrix(floatrot_x_mat[3][3],floatrot_y_mat[3][3],floatrot_z_mat[3][3],constfloateuler[3],AbcAxisSwapModemode)
-/* Convert matrix from Z=up to Y=up or vice versa.
- * Use yup_mat = zup_mat for in-place conversion. */
void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode)
{
float dst_rot[3][3], src_rot[3][3], dst_scale_mat[4][4];
@@ -139,8 +137,6 @@ void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMod
mul_m4_m4m4(dst_mat, dst_mat, dst_scale_mat);
}
-/* Recompute transform matrix of object in new coordinate system
- * (from Z-Up to Y-Up). */
void create_transform_matrix(Object *obj,
float r_yup_mat[4][4],
AbcMatrixMode mode,
diff --git a/source/blender/io/alembic/intern/abc_axis_conversion.h b/source/blender/io/alembic/intern/abc_axis_conversion.h
index 30988222fb7..21b95ec717e 100644
--- a/source/blender/io/alembic/intern/abc_axis_conversion.h
+++ b/source/blender/io/alembic/intern/abc_axis_conversion.h
@@ -70,20 +70,27 @@ BLI_INLINE void copy_yup_from_zup(short yup[3], const short zup[3])
}
/* Names are given in (dst, src) order, just like
- * the parameters of copy_m44_axis_swap() */
+ * the parameters of copy_m44_axis_swap(). */
+
typedef enum {
ABC_ZUP_FROM_YUP = 1,
ABC_YUP_FROM_ZUP = 2,
} AbcAxisSwapMode;
-/* Create a rotation matrix for each axis from euler angles.
- * Euler angles are swapped to change coordinate system. */
+/**
+ * Create a rotation matrix for each axis from euler angles.
+ * Euler angles are swapped to change coordinate system.
+ */
void create_swapped_rotation_matrix(float rot_x_mat[3][3],
float rot_y_mat[3][3],
float rot_z_mat[3][3],
const float euler[3],
AbcAxisSwapMode mode);
+/**
+ * Convert matrix from Z=up to Y=up or vice versa.
+ * Use yup_mat = zup_mat for in-place conversion.
+ */
void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode);
typedef enum {
@@ -91,6 +98,10 @@ typedef enum {
ABC_MATRIX_LOCAL = 2,
} AbcMatrixMode;
+/**
+ * Recompute transform matrix of object in new coordinate system
+ * (from Z-Up to Y-Up).
+ */
void create_transform_matrix(Object *obj,
float r_yup_mat[4][4],
AbcMatrixMode mode,
diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc
index 087d60f8896..c3ff64fd0ad 100644
--- a/source/blender/io/alembic/intern/abc_customdata.cc
+++ b/source/blender/io/alembic/intern/abc_customdata.cc
@@ -36,6 +36,7 @@
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
+#include "BKE_mesh.h"
/* NOTE: for now only UVs and Vertex Colors are supported for streaming.
* Although Alembic only allows for a single UV layer per {I|O}Schema, and does
@@ -176,29 +177,23 @@ static void write_uv(const OCompoundProperty &prop,
UInt32ArraySample(&indices.front(), indices.size()),
kFacevaryingScope);
param.set(sample);
+ param.setTimeSampling(config.timesample_index);
config.abc_uv_maps[uv_map_name] = param;
}
-/* Convention to write Vertex Colors:
- * - C3fGeomParam/C4fGeomParam on the arbGeomParam
- * - set scope as vertex varying
- */
-static void write_mcol(const OCompoundProperty &prop,
- const CDStreamConfig &config,
- void *data,
- const char *name)
+static void get_cols(const CDStreamConfig &config,
+ std::vector<Imath::C4f> &buffer,
+ std::vector<uint32_t> &uvidx,
+ void *cd_data)
{
const float cscale = 1.0f / 255.0f;
MPoly *polys = config.mpoly;
MLoop *mloops = config.mloop;
- MCol *cfaces = static_cast<MCol *>(data);
-
- std::vector<Imath::C4f> buffer;
- std::vector<uint32_t> indices;
+ MCol *cfaces = static_cast<MCol *>(cd_data);
buffer.reserve(config.totvert);
- indices.reserve(config.totvert);
+ uvidx.reserve(config.totvert);
Imath::C4f col;
@@ -217,22 +212,50 @@ static void write_mcol(const OCompoundProperty &prop,
col[3] = cface->b * cscale;
buffer.push_back(col);
- indices.push_back(buffer.size() - 1);
+ uvidx.push_back(buffer.size() - 1);
}
}
+}
- OC4fGeomParam param(prop, name, true, kFacevaryingScope, 1);
+/* Convention to write Vertex Colors:
+ * - C3fGeomParam/C4fGeomParam on the arbGeomParam
+ * - set scope as vertex varying
+ */
+static void write_mcol(const OCompoundProperty &prop,
+ CDStreamConfig &config,
+ void *data,
+ const char *name)
+{
+ std::vector<uint32_t> indices;
+ std::vector<Imath::C4f> buffer;
+
+ get_cols(config, buffer, indices, data);
+
+ if (indices.empty() || buffer.empty()) {
+ return;
+ }
+
+ std::string vcol_name(name);
+ OC4fGeomParam param = config.abc_vertex_colors[vcol_name];
+
+ if (!param.valid()) {
+ param = OC4fGeomParam(prop, name, true, kFacevaryingScope, 1);
+ }
OC4fGeomParam::Sample sample(C4fArraySample(&buffer.front(), buffer.size()),
UInt32ArraySample(&indices.front(), indices.size()),
kVertexScope);
param.set(sample);
+ param.setTimeSampling(config.timesample_index);
+
+ config.abc_vertex_colors[vcol_name] = param;
}
void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &config)
{
- const void *customdata = CustomData_get_layer(&config.mesh->vdata, CD_ORCO);
+ Mesh *mesh = config.mesh;
+ const void *customdata = CustomData_get_layer(&mesh->vdata, CD_ORCO);
if (customdata == nullptr) {
/* Data not available, so don't even bother creating an Alembic property for it. */
return;
@@ -247,6 +270,11 @@ void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &
coords[vertex_idx].setValue(orco_yup[0], orco_yup[1], orco_yup[2]);
}
+ /* ORCOs are always stored in the normalized 0..1 range in Blender, but Alembic stores them
+ * unnormalized, so we need to unnormalize (invert transform) them. */
+ BKE_mesh_orco_verts_transform(
+ mesh, reinterpret_cast<float(*)[3]>(&coords[0]), mesh->totvert, true);
+
if (!config.abc_orco.valid()) {
/* Create the Alembic property and keep a reference so future frames can reuse it. */
config.abc_orco = OV3fGeomParam(prop, propNameOriginalCoordinates, false, kVertexScope, 1);
@@ -513,22 +541,33 @@ void read_generated_coordinates(const ICompoundProperty &prop,
}
IV3fGeomParam::Sample sample = param.getExpandedValue(iss);
- Alembic::AbcGeom::V3fArraySamplePtr abc_ocro = sample.getVals();
- const size_t totvert = abc_ocro.get()->size();
+ Alembic::AbcGeom::V3fArraySamplePtr abc_orco = sample.getVals();
+ const size_t totvert = abc_orco.get()->size();
+ Mesh *mesh = config.mesh;
+
+ if (totvert != mesh->totvert) {
+ /* Either the data is somehow corrupted, or we have a dynamic simulation where only the ORCOs
+ * for the first frame were exported. */
+ return;
+ }
void *cd_data;
- if (CustomData_has_layer(&config.mesh->vdata, CD_ORCO)) {
- cd_data = CustomData_get_layer(&config.mesh->vdata, CD_ORCO);
+ if (CustomData_has_layer(&mesh->vdata, CD_ORCO)) {
+ cd_data = CustomData_get_layer(&mesh->vdata, CD_ORCO);
}
else {
- cd_data = CustomData_add_layer(&config.mesh->vdata, CD_ORCO, CD_CALLOC, nullptr, totvert);
+ cd_data = CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_CALLOC, nullptr, totvert);
}
float(*orcodata)[3] = static_cast<float(*)[3]>(cd_data);
for (int vertex_idx = 0; vertex_idx < totvert; ++vertex_idx) {
- const Imath::V3f &abc_coords = (*abc_ocro)[vertex_idx];
+ const Imath::V3f &abc_coords = (*abc_orco)[vertex_idx];
copy_zup_from_yup(orcodata[vertex_idx], abc_coords.getValue());
}
+
+ /* ORCOs are always stored in the normalized 0..1 range in Blender, but Alembic stores them
+ * unnormalized, so we need to normalize them. */
+ BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false);
}
void read_custom_data(const std::string &iobject_full_name,
@@ -570,12 +609,6 @@ void read_custom_data(const std::string &iobject_full_name,
}
}
-/* UVs can be defined per-loop (one value per vertex per face), or per-vertex (one value per
- * vertex). The first case is the most common, as this is the standard way of storing this data
- * given that some vertices might be on UV seams and have multiple possible UV coordinates; the
- * second case can happen when the mesh is split according to the UV islands, in which case storing
- * a single UV value per vertex allows to deduplicate data and thus to reduce the file size since
- * vertices are guaranteed to only have a single UV coordinate. */
AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
const CDStreamConfig &config,
const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
@@ -587,7 +620,7 @@ AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
/* kVaryingScope is sometimes used for vertex scopes as the values vary across the vertices. To
* be sure, one has to check the size of the data against the number of vertices, as it could
* also be a varying attribute across the faces (i.e. one value per face). */
- if ((scope == kVaryingScope || scope == kVertexScope) && indices->size() == config.totvert) {
+ if ((ELEM(scope, kVaryingScope, kVertexScope)) && indices->size() == config.totvert) {
return ABC_UV_SCOPE_VERTEX;
}
diff --git a/source/blender/io/alembic/intern/abc_customdata.h b/source/blender/io/alembic/intern/abc_customdata.h
index 2662ad733e0..97a9235753f 100644
--- a/source/blender/io/alembic/intern/abc_customdata.h
+++ b/source/blender/io/alembic/intern/abc_customdata.h
@@ -66,6 +66,7 @@ struct CDStreamConfig {
float weight;
float time;
+ int timesample_index;
bool use_vertex_interpolation;
Alembic::AbcGeom::index_t index;
Alembic::AbcGeom::index_t ceil_index;
@@ -82,6 +83,9 @@ struct CDStreamConfig {
/* ORCO coordinates, aka Generated Coordinates. */
Alembic::AbcGeom::OV3fGeomParam abc_orco;
+ /* Mapping from vertex color layer name to its Alembic color data. */
+ std::map<std::string, Alembic::AbcGeom::OC4fGeomParam> abc_vertex_colors;
+
CDStreamConfig()
: mloop(NULL),
totloop(0),
@@ -122,18 +126,20 @@ void read_custom_data(const std::string &iobject_full_name,
const CDStreamConfig &config,
const Alembic::Abc::ISampleSelector &iss);
-void read_velocity(const Alembic::Abc::ICompoundProperty &prop,
- const Alembic::Abc::PropertyHeader *prop_header,
- const Alembic::Abc::ISampleSelector &selector,
- const CDStreamConfig &config,
- const char *velocity_name,
- const float velocity_scale);
typedef enum {
ABC_UV_SCOPE_NONE,
ABC_UV_SCOPE_LOOP,
ABC_UV_SCOPE_VERTEX,
} AbcUvScope;
+/**
+ * UVs can be defined per-loop (one value per vertex per face), or per-vertex (one value per
+ * vertex). The first case is the most common, as this is the standard way of storing this data
+ * given that some vertices might be on UV seams and have multiple possible UV coordinates; the
+ * second case can happen when the mesh is split according to the UV islands, in which case storing
+ * a single UV value per vertex allows to de-duplicate data and thus to reduce the file size since
+ * vertices are guaranteed to only have a single UV coordinate.
+ */
AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
const CDStreamConfig &config,
const Alembic::AbcGeom::UInt32ArraySamplePtr &indices);
diff --git a/source/blender/io/alembic/intern/abc_reader_archive.cc b/source/blender/io/alembic/intern/abc_reader_archive.cc
index 4951dc0e035..94def041285 100644
--- a/source/blender/io/alembic/intern/abc_reader_archive.cc
+++ b/source/blender/io/alembic/intern/abc_reader_archive.cc
@@ -23,6 +23,8 @@
#include "abc_reader_archive.h"
+#include "Alembic/AbcCoreLayer/Read.h"
+
#include "BKE_main.h"
#include "BLI_path_util.h"
@@ -76,6 +78,46 @@ static IArchive open_archive(const std::string &filename,
return IArchive();
}
+ArchiveReader *ArchiveReader::get(struct Main *bmain, const std::vector<const char *> &filenames)
+{
+ std::vector<ArchiveReader *> readers;
+
+ for (const char *filename : filenames) {
+ auto reader = new ArchiveReader(bmain, filename);
+
+ if (!reader->valid()) {
+ delete reader;
+ continue;
+ }
+
+ readers.push_back(reader);
+ }
+
+ if (readers.size() == 0) {
+ return nullptr;
+ }
+
+ if (readers.size() == 1) {
+ return readers[0];
+ }
+
+ return new ArchiveReader(readers);
+}
+
+ArchiveReader::ArchiveReader(const std::vector<ArchiveReader *> &readers) : m_readers(readers)
+{
+ Alembic::AbcCoreLayer::ArchiveReaderPtrs archives;
+
+ for (auto &reader : readers) {
+ archives.push_back(reader->m_archive.getPtr());
+ }
+
+ Alembic::AbcCoreLayer::ReadArchive layer;
+ Alembic::AbcCoreAbstract::ArchiveReaderPtr arPtr = layer(archives);
+
+ m_archive = IArchive(arPtr, kWrapExisting, ErrorHandler::kThrowPolicy);
+}
+
ArchiveReader::ArchiveReader(struct Main *bmain, const char *filename)
{
char abs_filename[FILE_MAX];
@@ -96,6 +138,13 @@ ArchiveReader::ArchiveReader(struct Main *bmain, const char *filename)
m_archive = open_archive(abs_filename, m_streams);
}
+ArchiveReader::~ArchiveReader()
+{
+ for (ArchiveReader *reader : m_readers) {
+ delete reader;
+ }
+}
+
bool ArchiveReader::valid() const
{
return m_archive.valid();
diff --git a/source/blender/io/alembic/intern/abc_reader_archive.h b/source/blender/io/alembic/intern/abc_reader_archive.h
index 67000194aa1..937e3a190cf 100644
--- a/source/blender/io/alembic/intern/abc_reader_archive.h
+++ b/source/blender/io/alembic/intern/abc_reader_archive.h
@@ -41,9 +41,17 @@ class ArchiveReader {
std::ifstream m_infile;
std::vector<std::istream *> m_streams;
- public:
+ std::vector<ArchiveReader *> m_readers;
+
+ ArchiveReader(const std::vector<ArchiveReader *> &readers);
+
ArchiveReader(struct Main *bmain, const char *filename);
+ public:
+ static ArchiveReader *get(struct Main *bmain, const std::vector<const char *> &filenames);
+
+ ~ArchiveReader();
+
bool valid() const;
Alembic::Abc::IObject getTop();
diff --git a/source/blender/io/alembic/intern/abc_reader_curves.cc b/source/blender/io/alembic/intern/abc_reader_curves.cc
index d2ec7fb84db..bd1e57da648 100644
--- a/source/blender/io/alembic/intern/abc_reader_curves.cc
+++ b/source/blender/io/alembic/intern/abc_reader_curves.cc
@@ -274,12 +274,6 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
}
}
-/* NOTE: Alembic only stores data about control points, but the Mesh
- * passed from the cache modifier contains the displist, which has more data
- * than the control points, so to avoid corrupting the displist we modify the
- * object directly and create a new Mesh from that. Also we might need to
- * create new or delete existing NURBS in the curve.
- */
Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
const ISampleSelector &sample_sel,
int /*read_flag*/,
diff --git a/source/blender/io/alembic/intern/abc_reader_curves.h b/source/blender/io/alembic/intern/abc_reader_curves.h
index df5d68d7850..e7e6fa9f0b2 100644
--- a/source/blender/io/alembic/intern/abc_reader_curves.h
+++ b/source/blender/io/alembic/intern/abc_reader_curves.h
@@ -43,11 +43,18 @@ class AbcCurveReader final : public AbcObjectReader {
const char **err_str) const override;
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
+ /**
+ * \note Alembic only stores data about control points, but the Mesh
+ * passed from the cache modifier contains the #DispList, which has more data
+ * than the control points, so to avoid corrupting the #DispList we modify the
+ * object directly and create a new Mesh from that. Also we might need to
+ * create new or delete existing NURBS in the curve.
+ */
struct Mesh *read_mesh(struct Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel,
- const int read_flag,
+ int read_flag,
const char *velocity_name,
- const float velocity_scale,
+ float velocity_scale,
const char **err_str) override;
void read_curve_sample(Curve *cu,
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index eab94139f55..43581ad48d9 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -34,6 +34,7 @@
#include "DNA_object_types.h"
#include "BLI_compiler_compat.h"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math_geom.h"
@@ -44,6 +45,7 @@
#include "BKE_modifier.h"
#include "BKE_object.h"
+using Alembic::Abc::FloatArraySamplePtr;
using Alembic::Abc::Int32ArraySamplePtr;
using Alembic::Abc::IV3fArrayProperty;
using Alembic::Abc::P3fArraySamplePtr;
@@ -160,27 +162,26 @@ static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data)
return;
}
- read_mverts(mverts, positions, nullptr);
+ read_mverts(*config.mesh, positions, nullptr);
}
-void read_mverts(MVert *mverts, const P3fArraySamplePtr positions, const N3fArraySamplePtr normals)
+void read_mverts(Mesh &mesh, const P3fArraySamplePtr positions, const N3fArraySamplePtr normals)
{
for (int i = 0; i < positions->size(); i++) {
- MVert &mvert = mverts[i];
+ MVert &mvert = mesh.mvert[i];
Imath::V3f pos_in = (*positions)[i];
copy_zup_from_yup(mvert.co, pos_in.getValue());
mvert.bweight = 0;
-
- if (normals) {
+ }
+ if (normals) {
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(&mesh);
+ for (const int i : IndexRange(normals->size())) {
Imath::V3f nor_in = (*normals)[i];
-
- short no[3];
- normal_float_to_short_v3(no, nor_in.getValue());
-
- copy_zup_from_yup(mvert.no, no);
+ copy_zup_from_yup(vert_normals[i], nor_in.getValue());
}
+ BKE_mesh_vertex_normals_clear_dirty(&mesh);
}
}
@@ -435,6 +436,13 @@ static V3fArraySamplePtr get_velocity_prop(const ICompoundProperty &schema,
const ICompoundProperty &prop = ICompoundProperty(schema, header.getName());
if (has_property(prop, name)) {
+ /* Header cannot be null here, as its presence is checked via has_property, so it is safe
+ * to dereference. */
+ const PropertyHeader *header = prop.getPropertyHeader(name);
+ if (!IV3fArrayProperty::matches(*header)) {
+ continue;
+ }
+
const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(prop, name, 0);
if (velocity_prop) {
return velocity_prop.getValue(selector);
@@ -442,7 +450,7 @@ static V3fArraySamplePtr get_velocity_prop(const ICompoundProperty &schema,
}
}
else if (header.isArray()) {
- if (header.getName() == name) {
+ if (header.getName() == name && IV3fArrayProperty::matches(header)) {
const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(schema, name, 0);
return velocity_prop.getValue(selector);
}
@@ -456,13 +464,17 @@ static void read_velocity(const V3fArraySamplePtr &velocities,
const CDStreamConfig &config,
const float velocity_scale)
{
+ const int num_velocity_vectors = static_cast<int>(velocities->size());
+ if (num_velocity_vectors != config.mesh->totvert) {
+ /* Files containing videogrammetry data may be malformed and export velocity data on missing
+ * frames (most likely by copying the last valid data). */
+ return;
+ }
+
CustomDataLayer *velocity_layer = BKE_id_attribute_new(
&config.mesh->id, "velocity", CD_PROP_FLOAT3, ATTR_DOMAIN_POINT, nullptr);
float(*velocity)[3] = (float(*)[3])velocity_layer->data;
- const int num_velocity_vectors = static_cast<int>(velocities->size());
- BLI_assert(num_velocity_vectors == config.mesh->totvert);
-
for (int i = 0; i < num_velocity_vectors; i++) {
const Imath::V3f &vel_in = (*velocities)[i];
copy_zup_from_yup(velocity[i], vel_in.getValue());
@@ -899,6 +911,66 @@ static void read_subd_sample(const std::string &iobject_full_name,
}
}
+static void read_vertex_creases(Mesh *mesh,
+ const Int32ArraySamplePtr &indices,
+ const FloatArraySamplePtr &sharpnesses)
+{
+ if (!(indices && sharpnesses && indices->size() == sharpnesses->size() &&
+ indices->size() != 0)) {
+ return;
+ }
+
+ float *vertex_crease_data = (float *)CustomData_add_layer(
+ &mesh->vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh->totvert);
+ const int totvert = mesh->totvert;
+
+ for (int i = 0, v = indices->size(); i < v; ++i) {
+ const int idx = (*indices)[i];
+
+ if (idx >= totvert) {
+ continue;
+ }
+
+ vertex_crease_data[idx] = (*sharpnesses)[i];
+ }
+
+ mesh->cd_flag |= ME_CDFLAG_VERT_CREASE;
+}
+
+static void read_edge_creases(Mesh *mesh,
+ const Int32ArraySamplePtr &indices,
+ const FloatArraySamplePtr &sharpnesses)
+{
+ if (!(indices && sharpnesses)) {
+ return;
+ }
+
+ MEdge *edges = mesh->medge;
+ int totedge = mesh->totedge;
+
+ for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, s++) {
+ int v1 = (*indices)[i];
+ int v2 = (*indices)[i + 1];
+
+ if (v2 < v1) {
+ /* It appears to be common to store edges with the smallest index first, in which case this
+ * prevents us from doing the second search below. */
+ std::swap(v1, v2);
+ }
+
+ MEdge *edge = find_edge(edges, totedge, v1, v2);
+ if (edge == nullptr) {
+ edge = find_edge(edges, totedge, v2, v1);
+ }
+
+ if (edge) {
+ edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]);
+ }
+ }
+
+ mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
+}
+
/* ************************************************************************** */
AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings)
@@ -962,35 +1034,9 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
return;
}
- Int32ArraySamplePtr indices = sample.getCreaseIndices();
- Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses();
-
- if (indices && sharpnesses) {
- MEdge *edges = mesh->medge;
- int totedge = mesh->totedge;
-
- for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, s++) {
- int v1 = (*indices)[i];
- int v2 = (*indices)[i + 1];
-
- if (v2 < v1) {
- /* It appears to be common to store edges with the smallest index first, in which case this
- * prevents us from doing the second search below. */
- std::swap(v1, v2);
- }
+ read_edge_creases(mesh, sample.getCreaseIndices(), sample.getCreaseSharpnesses());
- MEdge *edge = find_edge(edges, totedge, v1, v2);
- if (edge == nullptr) {
- edge = find_edge(edges, totedge, v2, v1);
- }
-
- if (edge) {
- edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]);
- }
- }
-
- mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
- }
+ read_vertex_creases(mesh, sample.getCornerIndices(), sample.getCornerSharpnesses());
if (m_settings->validate_meshes) {
BKE_mesh_validate(mesh, false, false);
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.h b/source/blender/io/alembic/intern/abc_reader_mesh.h
index 2e34ca8ded0..1123616943e 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.h
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.h
@@ -42,9 +42,9 @@ class AbcMeshReader final : public AbcObjectReader {
struct Mesh *read_mesh(struct Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel,
- const int read_flag,
+ int read_flag,
const char *velocity_name,
- const float velocity_scale,
+ float velocity_scale,
const char **err_str) override;
bool topology_changed(Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel) override;
@@ -75,13 +75,13 @@ class AbcSubDReader final : public AbcObjectReader {
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
struct Mesh *read_mesh(struct Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel,
- const int read_flag,
+ int read_flag,
const char *velocity_name,
- const float velocity_scale,
+ float velocity_scale,
const char **err_str) override;
};
-void read_mverts(MVert *mverts,
+void read_mverts(Mesh &mesh,
const Alembic::AbcGeom::P3fArraySamplePtr positions,
const Alembic::AbcGeom::N3fArraySamplePtr normals);
diff --git a/source/blender/io/alembic/intern/abc_reader_object.cc b/source/blender/io/alembic/intern/abc_reader_object.cc
index a6d46c4b42a..86fa580bf1f 100644
--- a/source/blender/io/alembic/intern/abc_reader_object.cc
+++ b/source/blender/io/alembic/intern/abc_reader_object.cc
@@ -67,7 +67,6 @@ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings
determine_inherits_xform();
}
-/* Determine whether we can inherit our parent's XForm */
void AbcObjectReader::determine_inherits_xform()
{
m_inherits_xform = false;
@@ -121,29 +120,10 @@ static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1,
* the matrices manually.
*/
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- mat0[i][j] = static_cast<float>(m0[i][j]);
- }
- }
-
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- mat1[i][j] = static_cast<float>(m1[i][j]);
- }
- }
-
+ convert_matrix_datatype(m0, mat0);
+ convert_matrix_datatype(m1, mat1);
interp_m4_m4m4(ret, mat0, mat1, weight);
-
- Imath::M44d m;
-
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- m[i][j] = ret[i][j];
- }
- }
-
- return m;
+ return convert_matrix_datatype(ret);
}
Imath::M44d get_matrix(const IXformSchema &schema, const float time)
diff --git a/source/blender/io/alembic/intern/abc_reader_object.h b/source/blender/io/alembic/intern/abc_reader_object.h
index 6e97f841a88..5b327a9ddd9 100644
--- a/source/blender/io/alembic/intern/abc_reader_object.h
+++ b/source/blender/io/alembic/intern/abc_reader_object.h
@@ -149,15 +149,15 @@ class AbcObjectReader {
virtual struct Mesh *read_mesh(struct Mesh *mesh,
const Alembic::Abc::ISampleSelector &sample_sel,
- const int read_flag,
+ int read_flag,
const char *velocity_name,
- const float velocity_scale,
+ float velocity_scale,
const char **err_str);
virtual bool topology_changed(Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel);
/** Reads the object matrix and sets up an object transform if animated. */
- void setupObjectTransform(const float time);
+ void setupObjectTransform(float time);
void addCacheModifier();
@@ -168,12 +168,13 @@ class AbcObjectReader {
void incref();
void decref();
- void read_matrix(float r_mat[4][4], const float time, const float scale, bool &is_constant);
+ void read_matrix(float r_mat[4][4], float time, float scale, bool &is_constant);
protected:
+ /** Determine whether we can inherit our parent's XForm. */
void determine_inherits_xform();
};
-Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time);
+Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, float time);
} // namespace blender::io::alembic
diff --git a/source/blender/io/alembic/intern/abc_reader_points.cc b/source/blender/io/alembic/intern/abc_reader_points.cc
index 75ed18f57f2..0135e150097 100644
--- a/source/blender/io/alembic/intern/abc_reader_points.cc
+++ b/source/blender/io/alembic/intern/abc_reader_points.cc
@@ -121,7 +121,7 @@ void read_points_sample(const IPointsSchema &schema,
}
}
- read_mverts(config.mvert, positions, vnormals);
+ read_mverts(*config.mesh, positions, vnormals);
}
struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh,
diff --git a/source/blender/io/alembic/intern/abc_reader_points.h b/source/blender/io/alembic/intern/abc_reader_points.h
index 105d1276f7a..2f91e07d26a 100644
--- a/source/blender/io/alembic/intern/abc_reader_points.h
+++ b/source/blender/io/alembic/intern/abc_reader_points.h
@@ -45,7 +45,7 @@ class AbcPointsReader final : public AbcObjectReader {
const Alembic::Abc::ISampleSelector &sample_sel,
int read_flag,
const char *velocity_name,
- const float velocity_scale,
+ float velocity_scale,
const char **err_str) override;
};
diff --git a/source/blender/io/alembic/intern/abc_util.cc b/source/blender/io/alembic/intern/abc_util.cc
index 3d3ba0347c5..952fe1fa783 100644
--- a/source/blender/io/alembic/intern/abc_util.cc
+++ b/source/blender/io/alembic/intern/abc_util.cc
@@ -63,15 +63,6 @@ std::string get_valid_abc_name(const char *name)
return name_string;
}
-/**
- * \brief get_object_dag_path_name returns the name under which the object
- * will be exported in the Alembic file. It is of the form
- * "[../grandparent/]parent/object" if dupli_parent is NULL, or
- * "dupli_parent/[../grandparent/]parent/object" otherwise.
- * \param ob:
- * \param dupli_parent:
- * \return
- */
std::string get_object_dag_path_name(const Object *const ob, Object *dupli_parent)
{
std::string name = get_id_name(ob);
diff --git a/source/blender/io/alembic/intern/abc_util.h b/source/blender/io/alembic/intern/abc_util.h
index ced9fde0f85..672494e80db 100644
--- a/source/blender/io/alembic/intern/abc_util.h
+++ b/source/blender/io/alembic/intern/abc_util.h
@@ -35,6 +35,15 @@ struct ImportSettings;
std::string get_id_name(const ID *const id);
std::string get_id_name(const Object *const ob);
std::string get_valid_abc_name(const char *name);
+/**
+ * \brief get_object_dag_path_name returns the name under which the object
+ * will be exported in the Alembic file. It is of the form
+ * "[../grandparent/]parent/object" if dupli_parent is NULL, or
+ * "dupli_parent/[../grandparent/]parent/object" otherwise.
+ * \param ob:
+ * \param dupli_parent:
+ * \return
+ */
std::string get_object_dag_path_name(const Object *const ob, Object *dupli_parent);
/* Convert from float to Alembic matrix representations. Does NOT convert from Z-up to Y-up. */
@@ -42,7 +51,7 @@ Imath::M44d convert_matrix_datatype(float mat[4][4]);
/* Convert from Alembic to float matrix representations. Does NOT convert from Y-up to Z-up. */
void convert_matrix_datatype(const Imath::M44d &xform, float r_mat[4][4]);
-void split(const std::string &s, const char delim, std::vector<std::string> &tokens);
+void split(const std::string &s, char delim, std::vector<std::string> &tokens);
template<class TContainer> bool begins_with(const TContainer &input, const TContainer &match)
{
diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc
index 63565b902f3..58fc4dd599d 100644
--- a/source/blender/io/alembic/intern/alembic_capi.cc
+++ b/source/blender/io/alembic/intern/alembic_capi.cc
@@ -159,11 +159,25 @@ static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
CacheArchiveHandle *ABC_create_handle(struct Main *bmain,
const char *filename,
+ const CacheFileLayer *layers,
ListBase *object_paths)
{
- ArchiveReader *archive = new ArchiveReader(bmain, filename);
+ std::vector<const char *> filenames;
+ filenames.push_back(filename);
- if (!archive->valid()) {
+ while (layers) {
+ if ((layers->flag & CACHEFILE_LAYER_HIDDEN) == 0) {
+ filenames.push_back(layers->filepath);
+ }
+ layers = layers->next;
+ }
+
+ /* We need to reverse the order as overriding archives should come first. */
+ std::reverse(filenames.begin(), filenames.end());
+
+ ArchiveReader *archive = ArchiveReader::get(bmain, filenames);
+
+ if (!archive || !archive->valid()) {
delete archive;
return nullptr;
}
@@ -447,9 +461,9 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
WM_set_locked_interface(data->wm, true);
- ArchiveReader *archive = new ArchiveReader(data->bmain, data->filename);
+ ArchiveReader *archive = ArchiveReader::get(data->bmain, {data->filename});
- if (!archive->valid()) {
+ if (!archive || !archive->valid()) {
data->error_code = ABC_ARCHIVE_FAIL;
delete archive;
return;
@@ -460,7 +474,7 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
/* Decrement the ID ref-count because it is going to be incremented for each
* modifier and constraint that it will be attached to, so since currently
- * it is not used by anyone, its use count will off by one. */
+ * it is not used by anyone, its use count will be off by one. */
id_us_min(&cache_file->id);
cache_file->is_sequence = data->settings.is_sequence;
diff --git a/source/blender/io/avi/intern/avi.c b/source/blender/io/avi/intern/avi.c
index 88f2e1a259f..221e56ac793 100644
--- a/source/blender/io/avi/intern/avi.c
+++ b/source/blender/io/avi/intern/avi.c
@@ -145,7 +145,7 @@ static bool fcc_is_data(int fcc)
fccs[2] = fcc >> 16;
fccs[3] = fcc >> 24;
- if (!isdigit(fccs[0]) || !isdigit(fccs[1]) || (fccs[2] != 'd' && fccs[2] != 'w')) {
+ if (!isdigit(fccs[0]) || !isdigit(fccs[1]) || (!ELEM(fccs[2], 'd', 'w'))) {
return 0;
}
if (!ELEM(fccs[3], 'b', 'c')) {
@@ -591,7 +591,7 @@ AviError AVI_open_movie(const char *name, AviMovie *movie)
BLI_fseek(movie->fp, size - 4, SEEK_CUR);
if (GET_FCC(movie->fp) != FCC("idx1")) {
- DEBUG_PRINT("bad index informatio\n");
+ DEBUG_PRINT("bad index information\n");
return AVI_ERROR_FORMAT;
}
diff --git a/source/blender/io/avi/intern/avi_mjpeg.c b/source/blender/io/avi/intern/avi_mjpeg.c
index 75059c202e5..8b132df7b8f 100644
--- a/source/blender/io/avi/intern/avi_mjpeg.c
+++ b/source/blender/io/avi/intern/avi_mjpeg.c
@@ -33,8 +33,8 @@
#include "BLI_math_base.h"
#include "IMB_imbuf.h"
-#include "jerror.h"
-#include "jpeglib.h"
+#include <jerror.h>
+#include <jpeglib.h>
#include "avi_mjpeg.h"
diff --git a/source/blender/io/avi/intern/avi_rgb.c b/source/blender/io/avi/intern/avi_rgb.c
index 8af728f0737..f1d83b9857b 100644
--- a/source/blender/io/avi/intern/avi_rgb.c
+++ b/source/blender/io/avi/intern/avi_rgb.c
@@ -20,7 +20,7 @@
/** \file
* \ingroup avi
*
- * This is external code. Converts rgb-type avi-s.
+ * This is external code. Converts RGB-type AVI files.
*/
#include <stdlib.h>
diff --git a/source/blender/io/collada/AnimationExporter.cpp b/source/blender/io/collada/AnimationExporter.cpp
index 9ba59c0414d..56fd0938eea 100644
--- a/source/blender/io/collada/AnimationExporter.cpp
+++ b/source/blender/io/collada/AnimationExporter.cpp
@@ -126,7 +126,6 @@ bool AnimationExporter::exportAnimations()
return animation_count;
}
-/* called for each exported object */
void AnimationExporter::exportAnimation(Object *ob, BCAnimationSampler &sampler)
{
bool container_is_open = false;
@@ -165,16 +164,6 @@ void AnimationExporter::exportAnimation(Object *ob, BCAnimationSampler &sampler)
close_animation_container(container_is_open);
}
-/*
- * Export all animation FCurves of an Object.
- *
- * NOTE: This uses the keyframes as sample points,
- * and exports "baked keyframes" while keeping the tangent information
- * of the FCurves intact. This works for simple cases, but breaks
- * especially when negative scales are involved in the animation.
- * And when parent inverse matrices are involved (when exporting
- * object hierarchies)
- */
void AnimationExporter::export_curve_animation_set(Object *ob,
BCAnimationSampler &sampler,
bool export_as_matrix)
@@ -254,7 +243,6 @@ BC_global_rotation_type AnimationExporter::get_global_rotation_type(Object *ob)
return (apply_global_rotation) ? BC_DATA_ROTATION : BC_OBJECT_ROTATION;
}
-/* Write bone animations in transform matrix sources. */
void AnimationExporter::export_bone_animations_recursive(Object *ob,
Bone *bone,
BCAnimationSampler &sampler)
@@ -277,14 +265,6 @@ void AnimationExporter::export_bone_animations_recursive(Object *ob,
}
}
-/**
- * In some special cases the exported Curve needs to be replaced
- * by a modified curve (for collada purposes)
- * This method checks if a conversion is necessary and if applicable
- * returns a pointer to the modified BCAnimationCurve.
- * IMPORTANT: the modified curve must be deleted by the caller when no longer needed
- * if no conversion is needed this method returns a NULL;
- */
BCAnimationCurve *AnimationExporter::get_modified_export_curve(Object *ob,
BCAnimationCurve &curve,
BCAnimationCurveMap &curves)
@@ -549,7 +529,7 @@ void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNa
param.push_back("TRANSFORM");
}
else {
- /* assumes if axis isn't specified all axises are added */
+ /* assumes if axis isn't specified all axes are added */
param.push_back("X");
param.push_back("Y");
param.push_back("Z");
@@ -657,9 +637,6 @@ std::string AnimationExporter::collada_source_from_values(
return source_id;
}
-/*
- * Create a collada matrix source for a set of samples
- */
std::string AnimationExporter::collada_source_from_values(
BCMatrixSampleMap &samples,
const std::string &anim_id,
@@ -823,10 +800,6 @@ std::string AnimationExporter::get_collada_name(std::string channel_type) const
return tm_name;
}
-/*
- * Assign sid of the animated parameter or transform for rotation,
- * axis name is always appended and the value of append_axis is ignored
- */
std::string AnimationExporter::get_collada_sid(const BCAnimationCurve &curve,
const std::string axis_name)
{
diff --git a/source/blender/io/collada/AnimationExporter.h b/source/blender/io/collada/AnimationExporter.h
index fd691184e8b..11732af33ba 100644
--- a/source/blender/io/collada/AnimationExporter.h
+++ b/source/blender/io/collada/AnimationExporter.h
@@ -100,7 +100,7 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
bool exportAnimations();
- /* called for each exported object */
+ /** Called for each exported object. */
void operator()(Object *ob);
protected:
@@ -148,25 +148,34 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
std::vector<std::vector<std::string>> anim_meta;
- /* Main entry point into Animation export (called for each exported object) */
+ /** Main entry point into Animation export (called for each exported object). */
void exportAnimation(Object *ob, BCAnimationSampler &sampler);
- /* export animation as separate trans/rot/scale curves */
+ /**
+ * Export all animation FCurves of an Object.
+ *
+ * \note This uses the keyframes as sample points,
+ * and exports "baked keyframes" while keeping the tangent information
+ * of the FCurves intact. This works for simple cases, but breaks
+ * especially when negative scales are involved in the animation.
+ * And when parent inverse matrices are involved (when exporting
+ * object hierarchies)
+ */
void export_curve_animation_set(Object *ob, BCAnimationSampler &sampler, bool export_as_matrix);
- /* export one single curve */
+ /** Export one single curve. */
void export_curve_animation(Object *ob, BCAnimationCurve &curve);
- /* export animation as matrix data */
+ /** Export animation as matrix data. */
void export_matrix_animation(Object *ob, BCAnimationSampler &sampler);
- /* step through the bone hierarchy */
+ /** Write bone animations in transform matrix sources (step through the bone hierarchy). */
void export_bone_animations_recursive(Object *ob_arm, Bone *bone, BCAnimationSampler &sampler);
- /* Export for one bone */
+ /** Export for one bone. */
void export_bone_animation(Object *ob, Bone *bone, BCFrames &frames, BCMatrixSampleMap &samples);
- /* call to the low level collada exporter */
+ /** Call to the low level collada exporter. */
void export_collada_curve_animation(std::string id,
std::string name,
std::string target,
@@ -174,7 +183,7 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
BCAnimationCurve &curve,
BC_global_rotation_type global_rotation_type);
- /* call to the low level collada exporter */
+ /** Call to the low level collada exporter. */
void export_collada_matrix_animation(std::string id,
std::string name,
std::string target,
@@ -183,29 +192,38 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
BC_global_rotation_type global_rotation_type,
Matrix &parentinv);
+ /**
+ * In some special cases the exported Curve needs to be replaced
+ * by a modified curve (for collada purposes)
+ * This method checks if a conversion is necessary and if applicable
+ * returns a pointer to the modified BCAnimationCurve.
+ * IMPORTANT: the modified curve must be deleted by the caller when no longer needed
+ * if no conversion is needed this method returns a NULL;
+ */
BCAnimationCurve *get_modified_export_curve(Object *ob,
BCAnimationCurve &curve,
BCAnimationCurveMap &curves);
- /* Helper functions */
+ /* Helper functions. */
+
void openAnimationWithClip(std::string id, std::string name);
bool open_animation_container(bool has_container, Object *ob);
void close_animation_container(bool has_container);
- /* Input and Output sources (single valued) */
+ /** Input and Output sources (single valued). */
std::string collada_source_from_values(BC_animation_source_type source_type,
COLLADASW::InputSemantic::Semantics semantic,
std::vector<float> &values,
const std::string &anim_id,
const std::string axis_name);
- /* Output sources (matrix data) */
+ /** Output sources (matrix data). * Create a collada matrix source for a set of samples. */
std::string collada_source_from_values(BCMatrixSampleMap &samples,
const std::string &anim_id,
BC_global_rotation_type global_rotation_type,
Matrix &parentinv);
- /* Interpolation sources */
+ /** Interpolation sources. */
std::string collada_linear_interpolation_source(int tot, const std::string &anim_id);
/* source ID = animation_name + semantic_suffix */
@@ -240,6 +258,10 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
std::string get_axis_name(std::string channel, int id);
std::string get_collada_name(std::string channel_type) const;
+ /**
+ * Assign sid of the animated parameter or transform for rotation,
+ * axis name is always appended and the value of append_axis is ignored.
+ */
std::string get_collada_sid(const BCAnimationCurve &curve, const std::string axis_name);
/* ===================================== */
diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp
index 5b6391c1b9c..49a4b22dbc3 100644
--- a/source/blender/io/collada/AnimationImporter.cpp
+++ b/source/blender/io/collada/AnimationImporter.cpp
@@ -81,7 +81,6 @@ void AnimationImporter::add_bezt(FCurve *fcu,
calchandles_fcurve(fcu);
}
-/* create one or several fcurves depending on the number of parameters being animated */
void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
{
COLLADAFW::FloatOrDoubleArray &input = curve->getInputValues();
@@ -238,7 +237,7 @@ void AnimationImporter::add_fcurves_to_object(Main *bmain,
/* no matching groups, so add one */
if (grp == nullptr) {
/* Add a new group, and make it active */
- grp = (bActionGroup *)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
+ grp = MEM_cnew<bActionGroup>("bActionGroup");
grp->flag = AGRP_SELECTED;
BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
@@ -323,7 +322,6 @@ bool AnimationImporter::write_animation(const COLLADAFW::Animation *anim)
return true;
}
-/* called on post-process stage after writeVisualScenes */
bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList *animlist)
{
const COLLADAFW::UniqueId &animlist_id = animlist->getUniqueId();
@@ -343,11 +341,6 @@ bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList *ani
return true;
}
-/**
- * \todo refactor read_node_transform to not automatically apply anything,
- * but rather return the transform matrix, so caller can do with it what is
- * necessary. Same for \ref get_node_mat
- */
void AnimationImporter::read_node_transform(COLLADAFW::Node *node, Object *ob)
{
float mat[4][4];
@@ -463,7 +456,6 @@ virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act)
}
#endif
-/* sets the rna_path and array index to curve */
void AnimationImporter::modify_fcurve(std::vector<FCurve *> *curves,
const char *rna_path,
int array_index,
@@ -535,8 +527,6 @@ static int get_animation_axis_index(const COLLADABU::Math::Vector3 &axis)
return index;
}
-/* creates the rna_paths and array indices of fcurves from animations using transformation and
- * bound animation class of each animation. */
void AnimationImporter::Assign_transform_animations(
COLLADAFW::Transformation *transform,
const COLLADAFW::AnimationList::AnimationBinding *binding,
@@ -654,8 +644,6 @@ void AnimationImporter::Assign_transform_animations(
}
}
-/* creates the rna_paths and array indices of fcurves from animations using color and bound
- * animation class of each animation. */
void AnimationImporter::Assign_color_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
const char *anim_type)
@@ -765,11 +753,6 @@ float AnimationImporter::convert_to_focal_length(float in_xfov,
return fov_to_focallength(xfov, sensorx);
}
-/*
- * Lens animations must be stored in COLLADA by using FOV,
- * while blender internally uses focal length.
- * The imported animation curves must be converted appropriately.
- */
void AnimationImporter::Assign_lens_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
const double aspect,
@@ -1403,8 +1386,6 @@ void AnimationImporter::add_bone_animation_sampled(Object *ob,
chan->rotmode = ROT_MODE_QUAT;
}
-/* Check if object is animated by checking if animlist_map
- * holds the animlist_id of node transforms */
AnimationImporter::AnimMix *AnimationImporter::get_animation_type(
const COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map)
@@ -1514,7 +1495,6 @@ int AnimationImporter::setAnimType(const COLLADAFW::Animatable *prop, int types,
return anim_type;
}
-/* Is not used anymore. */
void AnimationImporter::find_frames_old(std::vector<float> *frames,
COLLADAFW::Node *node,
COLLADAFW::Transformation::TransformationType tm_type)
@@ -1579,9 +1559,6 @@ void AnimationImporter::find_frames_old(std::vector<float> *frames,
}
}
-/* prerequisites:
- * animlist_map - map animlist id -> animlist
- * curve_map - map anim id -> curve(s) */
Object *AnimationImporter::translate_animation_OLD(
COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, Object *> &object_map,
@@ -1854,9 +1831,6 @@ Object *AnimationImporter::translate_animation_OLD(
return job;
}
-/* internal, better make it private
- * warning: evaluates only rotation and only assigns matrix transforms now
- * prerequisites: animlist_map, curve_map */
void AnimationImporter::evaluate_transform_at_frame(float mat[4][4],
COLLADAFW::Node *node,
float fra)
@@ -1915,7 +1889,6 @@ static void report_class_type_unsupported(const char *path,
}
}
-/* return true to indicate that mat contains a sane value */
bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm,
float mat[4][4],
float fra,
@@ -2063,7 +2036,6 @@ bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm,
return false;
}
-/* gives a world-space mat of joint at rest position */
void AnimationImporter::get_joint_rest_mat(float mat[4][4],
COLLADAFW::Node *root,
COLLADAFW::Node *node)
@@ -2079,7 +2051,6 @@ void AnimationImporter::get_joint_rest_mat(float mat[4][4],
}
}
-/* gives a world-space mat, end's mat not included */
bool AnimationImporter::calc_joint_parent_mat_rest(float mat[4][4],
float par[4][4],
COLLADAFW::Node *node,
@@ -2206,7 +2177,7 @@ void AnimationImporter::add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurv
/* no matching groups, so add one */
if (grp == nullptr) {
/* Add a new group, and make it active */
- grp = (bActionGroup *)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
+ grp = MEM_cnew<bActionGroup>("bActionGroup");
grp->flag = AGRP_SELECTED;
BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
diff --git a/source/blender/io/collada/AnimationImporter.h b/source/blender/io/collada/AnimationImporter.h
index 44001366adc..909a3017e66 100644
--- a/source/blender/io/collada/AnimationImporter.h
+++ b/source/blender/io/collada/AnimationImporter.h
@@ -75,7 +75,9 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
float value,
eBezTriple_Interpolation ipo = BEZT_IPO_LIN);
- /* create one or several fcurves depending on the number of parameters being animated */
+ /**
+ * Create one or several fcurves depending on the number of parameters being animated.
+ */
void animation_to_fcurves(COLLADAFW::AnimationCurve *curve);
void fcurve_deg_to_rad(FCurve *cu);
@@ -143,9 +145,14 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
void set_import_from_version(std::string import_from_version);
bool write_animation(const COLLADAFW::Animation *anim);
- /* called on post-process stage after writeVisualScenes */
+ /** Called on post-process stage after writeVisualScenes. */
bool write_animation_list(const COLLADAFW::AnimationList *animlist);
+ /**
+ * \todo refactor read_node_transform to not automatically apply anything,
+ * but rather return the transform matrix, so caller can do with it what is
+ * necessary. Same for \ref get_node_mat
+ */
void read_node_transform(COLLADAFW::Node *node, Object *ob);
#if 0
virtual void change_eul_to_quat(Object *ob, bAction *act);
@@ -157,6 +164,10 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map,
std::map<COLLADAFW::UniqueId, Material *> uid_material_map);
+ /**
+ * Check if object is animated by checking if animlist_map
+ * holds the animlist_id of node transforms.
+ */
AnimMix *get_animation_type(
const COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map);
@@ -173,35 +184,51 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
COLLADAFW::Node *node,
COLLADAFW::Transformation *tm);
+ /**
+ * Creates the rna_paths and array indices of fcurves from animations using transformation and
+ * bound animation class of each animation.
+ */
void Assign_transform_animations(COLLADAFW::Transformation *transform,
const COLLADAFW::AnimationList::AnimationBinding *binding,
std::vector<FCurve *> *curves,
bool is_joint,
char *joint_path);
+ /**
+ * Creates the rna_paths and array indices of fcurves from animations using color and bound
+ * animation class of each animation.
+ */
void Assign_color_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
const char *anim_type);
void Assign_float_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
const char *anim_type);
+ /**
+ * Lens animations must be stored in COLLADA by using FOV,
+ * while blender internally uses focal length.
+ * The imported animation curves must be converted appropriately.
+ */
void Assign_lens_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
- const double aspect,
+ double aspect,
Camera *cam,
const char *anim_type,
int fov_type);
int setAnimType(const COLLADAFW::Animatable *prop, int type, int addition);
+ /** Sets the rna_path and array index to curve. */
void modify_fcurve(std::vector<FCurve *> *curves,
const char *rna_path,
int array_index,
int scale = 1);
void unused_fcurve(std::vector<FCurve *> *curves);
- /* prerequisites:
+ /**
+ * Prerequisites:
* animlist_map - map animlist id -> animlist
- * curve_map - map anim id -> curve(s) */
+ * curve_map - map anim id -> curve(s).
+ */
Object *translate_animation_OLD(COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, Object *> &object_map,
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *> &root_map,
@@ -209,24 +236,27 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
Object *par_job = NULL);
void find_frames(std::vector<float> *frames, std::vector<FCurve *> *curves);
+ /** Is not used anymore. */
void find_frames_old(std::vector<float> *frames,
COLLADAFW::Node *node,
COLLADAFW::Transformation::TransformationType tm_type);
- /* internal, better make it private
- * warning: evaluates only rotation
- * prerequisites: animlist_map, curve_map */
+ /**
+ * Internal, better make it private
+ * warning: evaluates only rotation and only assigns matrix transforms now
+ * prerequisites: animlist_map, curve_map.
+ */
void evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra);
- /* return true to indicate that mat contains a sane value */
+ /** Return true to indicate that mat contains a sane value. */
bool evaluate_animation(COLLADAFW::Transformation *tm,
float mat[4][4],
float fra,
const char *node_id);
- /* gives a world-space mat of joint at rest position */
+ /** Gives a world-space mat of joint at rest position. */
void get_joint_rest_mat(float mat[4][4], COLLADAFW::Node *root, COLLADAFW::Node *node);
- /* gives a world-space mat, end's mat not included */
+ /** * Gives a world-space mat, end's mat not included. */
bool calc_joint_parent_mat_rest(float mat[4][4],
float par[4][4],
COLLADAFW::Node *node,
@@ -239,8 +269,10 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
#endif
#if 0
- /* recursively evaluates joint tree until end is found, mat then is world-space matrix of end
- * mat must be identity on enter, node must be root */
+ /**
+ * Recursively evaluates joint tree until end is found, mat then is world-space matrix of end
+ * mat must be identity on enter, node must be root.
+ */
bool evaluate_joint_world_transform_at_frame(
float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end, float fra);
#endif
diff --git a/source/blender/io/collada/ArmatureExporter.cpp b/source/blender/io/collada/ArmatureExporter.cpp
index 28f5f9d40bc..5da70211bfd 100644
--- a/source/blender/io/collada/ArmatureExporter.cpp
+++ b/source/blender/io/collada/ArmatureExporter.cpp
@@ -40,7 +40,6 @@
#include "GeometryExporter.h"
#include "SceneExporter.h"
-/* write bone nodes */
void ArmatureExporter::add_armature_bones(Object *ob_arm,
ViewLayer *view_layer,
SceneExporter *se,
@@ -144,7 +143,6 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm,
}
#endif
-/* parent_mat is armature-space */
void ArmatureExporter::add_bone_node(Bone *bone,
Object *ob_arm,
SceneExporter *se,
diff --git a/source/blender/io/collada/ArmatureExporter.h b/source/blender/io/collada/ArmatureExporter.h
index b994741f342..c1b58f0071c 100644
--- a/source/blender/io/collada/ArmatureExporter.h
+++ b/source/blender/io/collada/ArmatureExporter.h
@@ -62,6 +62,7 @@ class ArmatureExporter : public COLLADASW::LibraryControllers,
{
}
+ /* write bone nodes */
void add_armature_bones(Object *ob_arm,
ViewLayer *view_layer,
SceneExporter *se,
@@ -83,8 +84,11 @@ class ArmatureExporter : public COLLADASW::LibraryControllers,
void find_objects_using_armature(Object *ob_arm, std::vector<Object *> &objects, Scene *sce);
#endif
- /* Scene, SceneExporter and the list of child_objects
- * are required for writing bone parented objects */
+ /**
+ * Scene, SceneExporter and the list of child_objects
+ * are required for writing bone parented objects.
+ * \param parent_mat: is armature-space.
+ */
void add_bone_node(Bone *bone,
Object *ob_arm,
SceneExporter *se,
diff --git a/source/blender/io/collada/ArmatureImporter.cpp b/source/blender/io/collada/ArmatureImporter.cpp
index f36b9aacd8b..cfe9ed6b2e0 100644
--- a/source/blender/io/collada/ArmatureImporter.cpp
+++ b/source/blender/io/collada/ArmatureImporter.cpp
@@ -220,12 +220,6 @@ int ArmatureImporter::create_bone(SkinInfo *skin,
return chain_length + 1;
}
-/**
- * Collada only knows Joints, hence bones at the end of a bone chain
- * don't have a defined length. This function guesses reasonable
- * tail locations for the affected bones (nodes which don't have any connected child)
- * Hint: The extended_bones set gets populated in ArmatureImporter::create_bone
- */
void ArmatureImporter::fix_leaf_bone_hierarchy(bArmature *armature,
Bone *bone,
bool fix_orientation)
@@ -757,11 +751,6 @@ bool ArmatureImporter::node_is_decomposed(const COLLADAFW::Node *node)
return true;
}
-/**
- * root - if this joint is the top joint in hierarchy, if a joint
- * is a child of a node (not joint), root should be true since
- * this is where we build armature bones from
- */
void ArmatureImporter::add_root_joint(COLLADAFW::Node *node, Object *parent)
{
root_joints.push_back(node);
@@ -786,7 +775,6 @@ void ArmatureImporter::add_root_joint(COLLADAFW::Node *node)
}
#endif
-/* here we add bones to armatures, having armatures previously created in write_controller */
void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &objects_to_scale)
{
Main *bmain = CTX_data_main(C);
@@ -955,7 +943,7 @@ void ArmatureImporter::make_shape_keys(bContext *C)
COLLADAFW::UniqueIdArray &morphTargetIds = (*mc)->getMorphTargets();
COLLADAFW::FloatOrDoubleArray &morphWeights = (*mc)->getMorphWeights();
- /* Prereq: all the geometries must be imported and mesh objects must be made */
+ /* Prerequisite: all the geometries must be imported and mesh objects must be made. */
Object *source_ob = this->mesh_importer->get_object_by_geom_uid((*mc)->getSource());
if (source_ob) {
@@ -1042,7 +1030,6 @@ void ArmatureImporter::get_rna_path_for_joint(COLLADAFW::Node *node,
BLI_snprintf(joint_path, count, "pose.bones[\"%s\"]", bone_name_esc);
}
-/* gives a world-space mat */
bool ArmatureImporter::get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint)
{
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
diff --git a/source/blender/io/collada/ArmatureImporter.h b/source/blender/io/collada/ArmatureImporter.h
index 16265e66a8e..fc0333b0ab1 100644
--- a/source/blender/io/collada/ArmatureImporter.h
+++ b/source/blender/io/collada/ArmatureImporter.h
@@ -111,10 +111,16 @@ class ArmatureImporter : private TransformReader {
std::vector<std::string> &layer_labels,
BoneExtensionMap &extended_bones);
+ /**
+ * Collada only knows Joints, hence bones at the end of a bone chain
+ * don't have a defined length. This function guesses reasonable
+ * tail locations for the affected bones (nodes which don't have any connected child)
+ * Hint: The extended_bones set gets populated in ArmatureImporter::create_bone
+ */
void fix_leaf_bone_hierarchy(bArmature *armature, Bone *bone, bool fix_orientation);
void fix_leaf_bone(bArmature *armature, EditBone *ebone, BoneExtended *be, bool fix_orientation);
void fix_parent_connect(bArmature *armature, Bone *bone);
- void connect_bone_chains(bArmature *armature, Bone *bone, const int max_chain_length);
+ void connect_bone_chains(bArmature *armature, Bone *bone, int max_chain_length);
void set_pose(Object *ob_arm,
COLLADAFW::Node *root_node,
@@ -152,15 +158,20 @@ class ArmatureImporter : private TransformReader {
const ImportSettings *import_settings);
~ArmatureImporter();
+ /**
+ * root - if this joint is the top joint in hierarchy, if a joint
+ * is a child of a node (not joint), root should be true since
+ * this is where we build armature bones from
+ */
void add_root_joint(COLLADAFW::Node *node, Object *parent);
- /* here we add bones to armatures, having armatures previously created in write_controller */
+ /** Here we add bones to armatures, having armatures previously created in write_controller. */
void make_armatures(bContext *C, std::vector<Object *> &objects_to_scale);
void make_shape_keys(bContext *C);
#if 0
- /* link with meshes, create vertex groups, assign weights */
+ /** Link with meshes, create vertex groups, assign weights. */
void link_armature(Object *ob_arm,
const COLLADAFW::UniqueId &geom_id,
const COLLADAFW::UniqueId &controller_data_id);
@@ -176,7 +187,7 @@ class ArmatureImporter : private TransformReader {
void get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t count);
- /* gives a world-space mat */
+ /** Gives a world-space mat. */
bool get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint);
void set_tags_map(TagsMap &tags_map);
diff --git a/source/blender/io/collada/BCAnimationCurve.h b/source/blender/io/collada/BCAnimationCurve.h
index 36b2a5e8509..cf4cb4e0642 100644
--- a/source/blender/io/collada/BCAnimationCurve.h
+++ b/source/blender/io/collada/BCAnimationCurve.h
@@ -59,8 +59,8 @@ class BCCurveKey {
BCCurveKey();
BCCurveKey(const BC_animation_type type,
const std::string path,
- const int array_index,
- const int subindex = -1);
+ int array_index,
+ int subindex = -1);
void operator=(const BCCurveKey &other);
std::string get_full_path() const;
std::string get_path() const;
@@ -127,7 +127,7 @@ class BCAnimationCurve {
FCurve *get_fcurve() const;
int sample_count() const;
- float get_value(const float frame);
+ float get_value(float frame);
void get_values(BCValues &values) const;
void get_value_map(BCValueMap &value_map);
@@ -135,14 +135,14 @@ class BCAnimationCurve {
/* Curve edit functions create a copy of the underlying #FCurve. */
FCurve *get_edit_fcurve();
- bool add_value_from_rna(const int frame);
- bool add_value_from_matrix(const BCSample &sample, const int frame);
- void add_value(const float val, const int frame);
+ bool add_value_from_rna(int frame);
+ bool add_value_from_matrix(const BCSample &sample, int frame);
+ void add_value(float val, int frame);
void clean_handles();
/* experimental stuff */
- int closest_index_above(const float sample_frame, const int start_at) const;
- int closest_index_below(const float sample_frame) const;
+ int closest_index_above(float sample_frame, int start_at) const;
+ int closest_index_below(float sample_frame) const;
};
typedef std::map<BCCurveKey, BCAnimationCurve *> BCAnimationCurveMap;
diff --git a/source/blender/io/collada/BCAnimationSampler.cpp b/source/blender/io/collada/BCAnimationSampler.cpp
index 953af5adffc..a2d711050cb 100644
--- a/source/blender/io/collada/BCAnimationSampler.cpp
+++ b/source/blender/io/collada/BCAnimationSampler.cpp
@@ -418,11 +418,6 @@ void BCAnimationSampler::generate_transforms(Object *ob, Bone *bone, BCAnimation
}
}
-/**
- * Collect all keyframes from all animation curves related to the object.
- * The bc_get... functions check for NULL and correct object type.
- * The #add_keyframes_from() function checks for NULL.
- */
void BCAnimationSampler::initialize_keyframes(BCFrameSet &frameset, Object *ob)
{
frameset.clear();
@@ -517,7 +512,6 @@ BCSample &BCSampleFrame::add(Object *ob)
return *sample;
}
-/* Get the matrix for the given key, returns Unity when the key does not exist */
const BCSample *BCSampleFrame::get_sample(Object *ob) const
{
BCSampleMap::const_iterator it = sampleMap.find(ob);
@@ -537,7 +531,6 @@ const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob) const
return &sample->get_matrix();
}
-/* Get the matrix for the given Bone, returns Unity when the Object is not sampled. */
const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob, Bone *bone) const
{
BCSampleMap::const_iterator it = sampleMap.find(ob);
@@ -550,13 +543,11 @@ const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob, Bone *bone) const
return bc_bone;
}
-/* Check if the key is in this BCSampleFrame */
bool BCSampleFrame::has_sample_for(Object *ob) const
{
return sampleMap.find(ob) != sampleMap.end();
}
-/* Check if the Bone is in this BCSampleFrame */
bool BCSampleFrame::has_sample_for(Object *ob, Bone *bone) const
{
const BCMatrix *bc_bone = get_sample_matrix(ob, bone);
@@ -575,7 +566,6 @@ BCSample &BCSampleFrameContainer::add(Object *ob, int frame_index)
/* Below are the getters which we need to export the data */
/* ====================================================== */
-/* Return either the BCSampleFrame or NULL if frame does not exist. */
BCSampleFrame *BCSampleFrameContainer::get_frame(int frame_index)
{
BCSampleFrameMap::iterator it = sample_frames.find(frame_index);
@@ -583,7 +573,6 @@ BCSampleFrame *BCSampleFrameContainer::get_frame(int frame_index)
return frame;
}
-/* Return a list of all frames that need to be sampled */
int BCSampleFrameContainer::get_frames(std::vector<int> &frames) const
{
frames.clear(); /* safety; */
diff --git a/source/blender/io/collada/BCAnimationSampler.h b/source/blender/io/collada/BCAnimationSampler.h
index 19b1bc35264..c78590b8e37 100644
--- a/source/blender/io/collada/BCAnimationSampler.h
+++ b/source/blender/io/collada/BCAnimationSampler.h
@@ -89,11 +89,16 @@ class BCSampleFrame {
BCSample &add(Object *ob);
/* Following methods return NULL if object is not in the sampleMap. */
+
+ /** Get the matrix for the given key, returns Unity when the key does not exist. */
const BCSample *get_sample(Object *ob) const;
const BCMatrix *get_sample_matrix(Object *ob) const;
+ /** Get the matrix for the given Bone, returns Unity when the Object is not sampled. */
const BCMatrix *get_sample_matrix(Object *ob, Bone *bone) const;
+ /** Check if the key is in this BCSampleFrame. */
bool has_sample_for(Object *ob) const;
+ /** Check if the Bone is in this BCSampleFrame. */
bool has_sample_for(Object *ob, Bone *bone) const;
};
@@ -134,8 +139,10 @@ class BCSampleFrameContainer {
}
BCSample &add(Object *ob, int frame_index);
- BCSampleFrame *get_frame(int frame_index); /* returns NULL if frame does not exist */
+ /** Return either the #BCSampleFrame or NULL if frame does not exist. */
+ BCSampleFrame *get_frame(int frame_index);
+ /** Return a list of all frames that need to be sampled. */
int get_frames(std::vector<int> &frames) const;
int get_frames(Object *ob, BCFrames &frames) const;
int get_frames(Object *ob, Bone *bone, BCFrames &frames) const;
@@ -159,6 +166,11 @@ class BCAnimationSampler {
void generate_transforms(Object *ob, Bone *bone, BCAnimationCurveMap &curves);
void initialize_curves(BCAnimationCurveMap &curves, Object *ob);
+ /**
+ * Collect all keyframes from all animation curves related to the object.
+ * The bc_get... functions check for NULL and correct object type.
+ * The #add_keyframes_from() function checks for NULL.
+ */
void initialize_keyframes(BCFrameSet &frameset, Object *ob);
BCSample &sample_object(Object *ob, int frame_index, bool for_opensim);
void update_animation_curves(BCAnimation &animation,
diff --git a/source/blender/io/collada/BCMath.cpp b/source/blender/io/collada/BCMath.cpp
index 51c86ee53f2..c3ee3355a41 100644
--- a/source/blender/io/collada/BCMath.cpp
+++ b/source/blender/io/collada/BCMath.cpp
@@ -183,8 +183,6 @@ void BCMatrix::unit()
quat_to_eul(this->rot, this->q);
}
-/* We need double here because the OpenCollada API needs it.
- * precision = -1 indicates to not limit the precision. */
void BCMatrix::get_matrix(DMatrix &mat, const bool transposed, const int precision) const
{
for (int i = 0; i < 4; i++) {
diff --git a/source/blender/io/collada/BCMath.h b/source/blender/io/collada/BCMath.h
index c57d5c6301f..dbcfe96bc61 100644
--- a/source/blender/io/collada/BCMath.h
+++ b/source/blender/io/collada/BCMath.h
@@ -78,25 +78,29 @@ class BCMatrix {
BCMatrix(Object *ob);
BCMatrix();
- void get_matrix(DMatrix &matrix, const bool transposed = false, const int precision = -1) const;
+ /**
+ * We need double here because the OpenCollada API needs it.
+ * precision = -1 indicates to not limit the precision.
+ */
+ void get_matrix(DMatrix &matrix, bool transposed = false, int precision = -1) const;
void get_matrix(Matrix &matrix,
- const bool transposed = false,
- const int precision = -1,
- const bool inverted = false) const;
+ bool transposed = false,
+ int precision = -1,
+ bool inverted = false) const;
void set_transform(Object *ob);
void set_transform(Matrix &mat);
void add_transform(Matrix &to,
const Matrix &transform,
const Matrix &from,
- const bool inverted = false);
+ bool inverted = false);
void apply_transform(Matrix &to,
const Matrix &transform,
const Matrix &from,
- const bool inverse = false);
+ bool inverse = false);
void add_inverted_transform(Matrix &to, const Matrix &transform, const Matrix &from);
- void add_transform(const Matrix &matrix, const bool inverted = false);
- void add_transform(const BCMatrix &matrix, const bool inverted = false);
- void apply_transform(const BCMatrix &matrix, const bool inverted = false);
+ void add_transform(const Matrix &matrix, bool inverted = false);
+ void add_transform(const BCMatrix &matrix, bool inverted = false);
+ void apply_transform(const BCMatrix &matrix, bool inverted = false);
bool in_range(const BCMatrix &other, float distance) const;
diff --git a/source/blender/io/collada/BCSampleData.cpp b/source/blender/io/collada/BCSampleData.cpp
index 339dc829742..9915514dc01 100644
--- a/source/blender/io/collada/BCSampleData.cpp
+++ b/source/blender/io/collada/BCSampleData.cpp
@@ -39,7 +39,6 @@ void BCSample::add_bone_matrix(Bone *bone, Matrix &mat)
bonemats[bone] = matrix;
}
-/* Get channel value */
bool BCSample::get_value(std::string channel_target, const int array_index, float *val) const
{
std::string bname = bc_string_before(channel_target, ".");
diff --git a/source/blender/io/collada/BCSampleData.h b/source/blender/io/collada/BCSampleData.h
index 06d234e2c3e..a76466a42f5 100644
--- a/source/blender/io/collada/BCSampleData.h
+++ b/source/blender/io/collada/BCSampleData.h
@@ -53,7 +53,8 @@ class BCSample {
void add_bone_matrix(Bone *bone, Matrix &mat);
- bool get_value(std::string channel_target, const int array_index, float *val) const;
+ /** Get channel value. */
+ bool get_value(std::string channel_target, int array_index, float *val) const;
const BCMatrix &get_matrix() const;
const BCMatrix *get_matrix(Bone *bone) const; /* returns NULL if bone is not animated */
};
diff --git a/source/blender/io/collada/BlenderContext.cpp b/source/blender/io/collada/BlenderContext.cpp
index ab420e79ba7..2a1968d00d2 100644
--- a/source/blender/io/collada/BlenderContext.cpp
+++ b/source/blender/io/collada/BlenderContext.cpp
@@ -31,12 +31,6 @@ bool bc_is_base_node(LinkNode *export_set, Object *ob, ViewLayer *view_layer)
return (root == ob);
}
-/**
- * Returns the highest selected ancestor
- * returns NULL if no ancestor is selected
- * IMPORTANT: This function expects that all exported objects have set:
- * ob->id.tag & LIB_TAG_DOIT
- */
Object *bc_get_highest_exported_ancestor_or_self(LinkNode *export_set,
Object *ob,
ViewLayer *view_layer)
diff --git a/source/blender/io/collada/BlenderContext.h b/source/blender/io/collada/BlenderContext.h
index 9163b30c86f..86738bbd242 100644
--- a/source/blender/io/collada/BlenderContext.h
+++ b/source/blender/io/collada/BlenderContext.h
@@ -38,6 +38,12 @@ static const BC_global_up_axis BC_DEFAULT_UP = BC_GLOBAL_UP_Z;
bool bc_is_in_Export_set(LinkNode *export_set, Object *ob, ViewLayer *view_layer);
bool bc_is_base_node(LinkNode *export_set, Object *ob, ViewLayer *view_layer);
+/**
+ * Returns the highest selected ancestor
+ * returns NULL if no ancestor is selected
+ * IMPORTANT: This function expects that all exported objects have set:
+ * `ob->id.tag & LIB_TAG_DOIT`
+ */
Object *bc_get_highest_exported_ancestor_or_self(LinkNode *export_set,
Object *ob,
ViewLayer *view_layer);
diff --git a/source/blender/io/collada/ControllerExporter.cpp b/source/blender/io/collada/ControllerExporter.cpp
index d768d2e44e8..6c13c83fbc7 100644
--- a/source/blender/io/collada/ControllerExporter.cpp
+++ b/source/blender/io/collada/ControllerExporter.cpp
@@ -161,8 +161,6 @@ std::string ControllerExporter::get_controller_id(Key *key, Object *ob)
return translate_id(id_name(ob)) + MORPH_CONTROLLER_ID_SUFFIX;
}
-/* ob should be of type OB_MESH
- * both args are required */
void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
{
/* joint names
@@ -377,7 +375,6 @@ std::string ControllerExporter::add_morph_weights(Key *key, Object *ob)
return source_id;
}
-/* Added to implement support for animations. */
void ControllerExporter::add_weight_extras(Key *key)
{
/* can also try the base element and param alternative */
diff --git a/source/blender/io/collada/ControllerExporter.h b/source/blender/io/collada/ControllerExporter.h
index 0aec9e8d179..d262d21012b 100644
--- a/source/blender/io/collada/ControllerExporter.h
+++ b/source/blender/io/collada/ControllerExporter.h
@@ -91,8 +91,7 @@ class ControllerExporter : public COLLADASW::LibraryControllers,
std::string get_controller_id(Key *key, Object *ob);
- /* ob should be of type OB_MESH
- * both args are required */
+ /** `ob` should be of type OB_MESH, both arguments are required. */
void export_skin_controller(Object *ob, Object *ob_arm);
void export_morph_controller(Object *ob, Key *key);
@@ -107,6 +106,9 @@ class ControllerExporter : public COLLADASW::LibraryControllers,
std::string add_morph_weights(Key *key, Object *ob);
+ /**
+ * Added to implement support for animations.
+ */
void add_weight_extras(Key *key);
std::string add_joints_source(Object *ob_arm,
diff --git a/source/blender/io/collada/DocumentImporter.cpp b/source/blender/io/collada/DocumentImporter.cpp
index 35bdc0a4e06..013df2fa2b7 100644
--- a/source/blender/io/collada/DocumentImporter.cpp
+++ b/source/blender/io/collada/DocumentImporter.cpp
@@ -320,10 +320,6 @@ void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node,
}
}
-/**
- * If the imported file was made with Blender, return the Blender version used,
- * otherwise return an empty std::string
- */
std::string DocumentImporter::get_import_version(const COLLADAFW::FileInfo *asset)
{
const char AUTORING_TOOL[] = "authoring_tool";
@@ -347,10 +343,6 @@ std::string DocumentImporter::get_import_version(const COLLADAFW::FileInfo *asse
return "";
}
-/**
- * When this method is called, the writer must write the global document asset.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeGlobalAsset(const COLLADAFW::FileInfo *asset)
{
unit_converter.read_asset(asset);
@@ -359,10 +351,6 @@ bool DocumentImporter::writeGlobalAsset(const COLLADAFW::FileInfo *asset)
return true;
}
-/**
- * When this method is called, the writer must write the scene.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeScene(const COLLADAFW::Scene *scene)
{
/* XXX could store the scene id, but do nothing for now */
@@ -476,8 +464,6 @@ Object *DocumentImporter::create_instance_node(Object *source_ob,
return obn;
}
-/* to create constraints off node <extra> tags. Assumes only constraint data in
- * current <extra> with blender profile. */
void DocumentImporter::create_constraints(ExtraTags *et, Object *ob)
{
if (et && et->isProfile("blender")) {
@@ -712,10 +698,6 @@ finally:
return root_objects;
}
-/**
- * When this method is called, the writer must write the entire visual scene.
- * Return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScene)
{
if (mImportStage == Fetching_Controller_data) {
@@ -738,11 +720,6 @@ bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScen
return true;
}
-/**
- * When this method is called, the writer must handle all nodes contained in the
- * library nodes.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryNodes)
{
if (mImportStage == Fetching_Controller_data) {
@@ -762,10 +739,6 @@ bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryN
return true;
}
-/**
- * When this method is called, the writer must write the geometry.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom)
{
if (mImportStage == Fetching_Controller_data) {
@@ -775,10 +748,6 @@ bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom)
return mesh_importer.write_geometry(geom);
}
-/**
- * When this method is called, the writer must write the material.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat)
{
if (mImportStage == Fetching_Controller_data) {
@@ -821,10 +790,6 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
matNode.update_material_nodetree();
}
-/**
- * When this method is called, the writer must write the effect.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
{
if (mImportStage == Fetching_Controller_data) {
@@ -860,10 +825,6 @@ bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
return true;
}
-/**
- * When this method is called, the writer must write the camera.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
{
if (mImportStage == Fetching_Controller_data) {
@@ -973,10 +934,6 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
return true;
}
-/**
- * When this method is called, the writer must write the image.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
{
if (mImportStage == Fetching_Controller_data) {
@@ -1013,10 +970,6 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
return true;
}
-/**
- * When this method is called, the writer must write the light.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
{
if (mImportStage == Fetching_Controller_data) {
@@ -1164,7 +1117,6 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
return true;
}
-/* this function is called only for animations that pass COLLADAFW::validate */
bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim)
{
if (mImportStage == Fetching_Controller_data) {
@@ -1174,7 +1126,6 @@ bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim)
return anim_importer.write_animation(anim);
}
-/* called on post-process stage after writeVisualScenes */
bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animationList)
{
if (mImportStage == Fetching_Controller_data) {
@@ -1186,10 +1137,10 @@ bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animat
}
#if WITH_OPENCOLLADA_ANIMATION_CLIP
-/* Since opencollada 1.6.68
- * called on post-process stage after writeVisualScenes */
bool DocumentImporter::writeAnimationClip(const COLLADAFW::AnimationClip *animationClip)
{
+ /* Since opencollada 1.6.68: called on post-process stage after writeVisualScenes. */
+
if (mImportStage == Fetching_Controller_data) {
return true;
}
@@ -1200,16 +1151,11 @@ bool DocumentImporter::writeAnimationClip(const COLLADAFW::AnimationClip *animat
}
#endif
-/**
- * When this method is called, the writer must write the skin controller data.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeSkinControllerData(const COLLADAFW::SkinControllerData *skin)
{
return armature_importer.write_skin_controller_data(skin);
}
-/* this is called on postprocess, before writeVisualScenes */
bool DocumentImporter::writeController(const COLLADAFW::Controller *controller)
{
if (mImportStage == Fetching_Controller_data) {
diff --git a/source/blender/io/collada/DocumentImporter.h b/source/blender/io/collada/DocumentImporter.h
index 8e553f1ce7a..63faaca4711 100644
--- a/source/blender/io/collada/DocumentImporter.h
+++ b/source/blender/io/collada/DocumentImporter.h
@@ -64,6 +64,10 @@ class DocumentImporter : COLLADAFW::IWriter {
Object *create_camera_object(COLLADAFW::InstanceCamera *, Scene *);
Object *create_light_object(COLLADAFW::InstanceLight *, Scene *);
Object *create_instance_node(Object *, COLLADAFW::Node *, COLLADAFW::Node *, Scene *, bool);
+ /**
+ * To create constraints off node <extra> tags. Assumes only constraint data in
+ * current <extra> with blender profile.
+ */
void create_constraints(ExtraTags *et, Object *ob);
std::vector<Object *> *write_node(COLLADAFW::Node *, COLLADAFW::Node *, Scene *, Object *, bool);
void write_profile_COMMON(COLLADAFW::EffectCommon *, Material *);
@@ -86,17 +90,44 @@ class DocumentImporter : COLLADAFW::IWriter {
*/
void finish();
+ /**
+ * When this method is called, the writer must write the global document asset.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeGlobalAsset(const COLLADAFW::FileInfo *);
+ /**
+ * If the imported file was made with Blender, return the Blender version used,
+ * otherwise return an empty std::string
+ */
std::string get_import_version(const COLLADAFW::FileInfo *asset);
+ /**
+ * When this method is called, the writer must write the scene.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeScene(const COLLADAFW::Scene *);
+ /**
+ * When this method is called, the writer must write the entire visual scene.
+ * Return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeVisualScene(const COLLADAFW::VisualScene *);
+ /**
+ * When this method is called, the writer must handle all nodes contained in the
+ * library nodes.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeLibraryNodes(const COLLADAFW::LibraryNodes *);
+ /**
+ * This function is called only for animations that pass COLLADAFW::validate.
+ */
bool writeAnimation(const COLLADAFW::Animation *);
+ /**
+ * Called on post-process stage after writeVisualScenes.
+ */
bool writeAnimationList(const COLLADAFW::AnimationList *);
#if WITH_OPENCOLLADA_ANIMATION_CLIP
@@ -105,20 +136,49 @@ class DocumentImporter : COLLADAFW::IWriter {
bool writeAnimationClip(const COLLADAFW::AnimationClip *animationClip);
#endif
+ /**
+ * When this method is called, the writer must write the geometry.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeGeometry(const COLLADAFW::Geometry *);
+ /**
+ * When this method is called, the writer must write the material.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeMaterial(const COLLADAFW::Material *);
+ /**
+ * When this method is called, the writer must write the effect.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeEffect(const COLLADAFW::Effect *);
+ /**
+ * When this method is called, the writer must write the camera.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeCamera(const COLLADAFW::Camera *);
+ /**
+ * When this method is called, the writer must write the image.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeImage(const COLLADAFW::Image *);
+ /**
+ * When this method is called, the writer must write the light.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeLight(const COLLADAFW::Light *);
+ /**
+ * When this method is called, the writer must write the skin controller data.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeSkinControllerData(const COLLADAFW::SkinControllerData *);
+ /** This is called on post-process, before writeVisualScenes. */
bool writeController(const COLLADAFW::Controller *);
bool writeFormulas(const COLLADAFW::Formulas *);
diff --git a/source/blender/io/collada/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp
index 382bb8a6e36..73e3eeda462 100644
--- a/source/blender/io/collada/GeometryExporter.cpp
+++ b/source/blender/io/collada/GeometryExporter.cpp
@@ -324,7 +324,6 @@ std::string GeometryExporter::makeVertexColorSourceId(std::string &geom_id, char
return result;
}
-/* powerful because it handles both cases when there is material and when there's not */
void GeometryExporter::create_mesh_primitive_list(short material_index,
bool has_uvs,
bool has_color,
@@ -441,7 +440,6 @@ void GeometryExporter::create_mesh_primitive_list(short material_index,
finish_and_delete_primitive_List(is_triangulated, primitive_list);
}
-/* creates <source> for positions */
void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
{
#if 0
@@ -542,7 +540,6 @@ std::string GeometryExporter::makeTexcoordSourceId(std::string &geom_id,
return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
}
-/* creates <source> for texcoords */
void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
{
@@ -593,7 +590,6 @@ bool operator<(const Normal &a, const Normal &b)
return a.x < b.x || (a.x == b.x && (a.y < b.y || (a.y == b.y && a.z < b.z)));
}
-/* creates <source> for normals */
void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal> &nor)
{
#if 0
@@ -635,6 +631,7 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
int last_normal_index = -1;
MVert *verts = me->mvert;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me);
MLoop *mloops = me->mloop;
float(*lnors)[3] = nullptr;
bool use_custom_normals = false;
@@ -670,7 +667,7 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
normalize_v3_v3(normalized, lnors[loop_idx]);
}
else {
- normal_short_to_float_v3(normalized, verts[mloops[loop_index].v].no);
+ copy_v3_v3(normalized, vert_normals[mloops[loop_index].v]);
normalize_v3(normalized);
}
Normal n = {normalized[0], normalized[1], normalized[2]};
diff --git a/source/blender/io/collada/GeometryExporter.h b/source/blender/io/collada/GeometryExporter.h
index 948aafa760d..e6e08f2b977 100644
--- a/source/blender/io/collada/GeometryExporter.h
+++ b/source/blender/io/collada/GeometryExporter.h
@@ -72,7 +72,7 @@ class GeometryExporter : COLLADASW::LibraryGeometries {
void createLooseEdgeList(Object *ob, Mesh *me, std::string &geom_id);
- /* powerful because it handles both cases when there is material and when there's not */
+ /** Powerful because it handles both cases when there is material and when there's not. */
void create_mesh_primitive_list(short material_index,
bool has_uvs,
bool has_color,
@@ -81,17 +81,17 @@ class GeometryExporter : COLLADASW::LibraryGeometries {
std::string &geom_id,
std::vector<BCPolygonNormalsIndices> &norind);
- /* creates <source> for positions */
+ /** Creates <source> for positions. */
void createVertsSource(std::string geom_id, Mesh *me);
void createVertexColorSource(std::string geom_id, Mesh *me);
std::string makeTexcoordSourceId(std::string &geom_id, int layer_index, bool is_single_layer);
- /* creates <source> for texcoords */
+ /** Creates <source> for texcoords. */
void createTexcoordsSource(std::string geom_id, Mesh *me);
- /* creates <source> for normals */
+ /** Creates <source> for normals. */
void createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal> &nor);
void create_normals(std::vector<Normal> &nor,
diff --git a/source/blender/io/collada/Materials.cpp b/source/blender/io/collada/Materials.cpp
index 81f0cc608d2..6e17172f642 100644
--- a/source/blender/io/collada/Materials.cpp
+++ b/source/blender/io/collada/Materials.cpp
@@ -16,6 +16,8 @@
#include "Materials.h"
+#include "BKE_node_tree_update.h"
+
MaterialNode::MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map)
: mContext(C), material(ma), effect(nullptr), key_image_map(&key_image_map)
{
@@ -91,7 +93,6 @@ void MaterialNode::setShaderType()
#endif
}
-/* returns null if material already has a node tree */
bNodeTree *MaterialNode::prepare_material_nodetree()
{
if (material->nodetree) {
@@ -107,7 +108,7 @@ bNodeTree *MaterialNode::prepare_material_nodetree()
void MaterialNode::update_material_nodetree()
{
- ntreeUpdateTree(CTX_data_main(mContext), ntree);
+ BKE_ntree_update_main_tree(CTX_data_main(mContext), ntree, nullptr);
}
bNode *MaterialNode::add_node(int node_type, int locx, int locy, std::string label)
diff --git a/source/blender/io/collada/Materials.h b/source/blender/io/collada/Materials.h
index 1886acb7a6a..e68f67bf049 100644
--- a/source/blender/io/collada/Materials.h
+++ b/source/blender/io/collada/Materials.h
@@ -45,6 +45,7 @@ class MaterialNode {
bNode *shader_node;
bNode *output_node;
+ /** Returns null if material already has a node tree. */
bNodeTree *prepare_material_nodetree();
bNode *add_node(int node_type, int locx, int locy, std::string label);
void add_link(bNode *from_node, int from_index, bNode *to_node, int to_index);
diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp
index ef486375ce3..036819af6a3 100644
--- a/source/blender/io/collada/MeshImporter.cpp
+++ b/source/blender/io/collada/MeshImporter.cpp
@@ -267,7 +267,6 @@ void MeshImporter::print_index_list(COLLADAFW::IndexList &index_list)
}
#endif
-/* checks if mesh has supported primitive types: lines, polylist, triangles, triangle_fans */
bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh)
{
COLLADAFW::MeshPrimitiveArray &prim_arr = mesh->getMeshPrimitives();
@@ -356,12 +355,6 @@ void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me)
}
}
-/* =====================================================================
- * condition 1: The Primitive has normals
- * condition 2: The number of normals equals the number of faces.
- * return true if both conditions apply.
- * return false otherwise.
- * ===================================================================== */
bool MeshImporter::primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp)
{
@@ -385,10 +378,6 @@ bool MeshImporter::primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp)
return has_useable_normals;
}
-/* =====================================================================
- * Assume that only TRIANGLES, TRIANGLE_FANS, POLYLIST and POLYGONS
- * have faces. (to be verified)
- * ===================================================================== */
bool MeshImporter::primitive_has_faces(COLLADAFW::MeshPrimitive *mp)
{
@@ -420,12 +409,6 @@ static std::string extract_vcolname(const COLLADAFW::String &collada_id)
return colname;
}
-/* =================================================================
- * Return the number of faces by summing up
- * the face-counts of the parts.
- * hint: This is done because `mesh->getFacesCount()` does
- * count loose edges as extra faces, which is not what we want here.
- * ================================================================= */
void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
{
COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives();
@@ -554,13 +537,6 @@ unsigned int MeshImporter::get_loose_edge_count(COLLADAFW::Mesh *mesh)
return loose_edge_count;
}
-/* =================================================================
- * This function is copied from source/blender/editors/mesh/mesh_data.c
- *
- * TODO: (As discussed with sergey-) :
- * Maybe move this function to blenderkernel/intern/mesh.c
- * and add definition to BKE_mesh.c
- * ================================================================= */
void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
{
CustomData edata;
@@ -594,12 +570,6 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
mesh->totedge = totedge;
}
-/* =================================================================
- * Read all loose edges.
- * Important: This function assumes that all edges from existing
- * faces have already been generated and added to me->medge
- * So this function MUST be called after read_faces() (see below)
- * ================================================================= */
void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
{
unsigned int loose_edge_count = get_loose_edge_count(mesh);
@@ -633,13 +603,6 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
}
}
-/* =======================================================================
- * Read all faces from TRIANGLES, TRIANGLE_FANS, POLYLIST, POLYGON
- * Important: This function MUST be called before read_lines()
- * Otherwise we will lose all edges from faces (see read_lines() above)
- *
- * TODO: import uv set names
- * ======================================================================== */
void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
{
unsigned int i;
@@ -965,11 +928,6 @@ static void bc_remove_materials_from_object(Object *ob, Mesh *me)
}
}
-/**
- * Returns the list of Users of the given Mesh object.
- * NOTE: This function uses the object user flag to control
- * which objects have already been processed.
- */
std::vector<Object *> MeshImporter::get_all_users_of(Mesh *reference_mesh)
{
std::vector<Object *> mesh_users;
@@ -985,24 +943,6 @@ std::vector<Object *> MeshImporter::get_all_users_of(Mesh *reference_mesh)
return mesh_users;
}
-/**
- *
- * During import all materials have been assigned to Object.
- * Now we iterate over the imported objects and optimize
- * the assignments as follows:
- *
- * for each imported geometry:
- * if number of users is 1:
- * get the user (object)
- * move the materials from Object to Data
- * else:
- * determine which materials are assigned to the first user
- * check if all other users have the same materials in the same order
- * if the check is positive:
- * Add the materials of the first user to the geometry
- * adjust all other users accordingly.
- *
- */
void MeshImporter::optimize_material_assignements()
{
for (Object *ob : imported_objects) {
@@ -1035,14 +975,6 @@ void MeshImporter::optimize_material_assignements()
}
}
-/**
- * We do not know in advance which objects will share geometries.
- * And we do not know either if the objects which share geometries
- * come along with different materials. So we first create the objects
- * and assign the materials to Object, then in a later cleanup we decide
- * which materials shall be moved to the created geometries. Also see
- * optimize_material_assignements() above.
- */
void MeshImporter::assign_material_to_geom(
COLLADAFW::MaterialBinding cmaterial,
std::map<COLLADAFW::UniqueId, Material *> &uid_material_map,
@@ -1165,7 +1097,6 @@ Object *MeshImporter::create_mesh_object(
return ob;
}
-/* create a mesh storing a pointer in a map so it can be retrieved later by geometry UID */
bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
{
diff --git a/source/blender/io/collada/MeshImporter.h b/source/blender/io/collada/MeshImporter.h
index 6f4f62b7f0f..95ac32a1b4c 100644
--- a/source/blender/io/collada/MeshImporter.h
+++ b/source/blender/io/collada/MeshImporter.h
@@ -122,23 +122,60 @@ class MeshImporter : public MeshImporterBase {
void print_index_list(COLLADAFW::IndexList &index_list);
#endif
+ /** Checks if mesh has supported primitive types: lines, polylist, triangles, triangle_fans. */
bool is_nice_mesh(COLLADAFW::Mesh *mesh);
void read_vertices(COLLADAFW::Mesh *mesh, Mesh *me);
+ /**
+ * Condition 1: The Primitive has normals
+ * condition 2: The number of normals equals the number of faces.
+ * return true if both conditions apply.
+ * return false otherwise.
+ */
bool primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp);
+ /**
+ * Assume that only TRIANGLES, TRIANGLE_FANS, POLYLIST and POLYGONS
+ * have faces. (to be verified).
+ */
bool primitive_has_faces(COLLADAFW::MeshPrimitive *mp);
+ /**
+ * This function is copied from source/blender/editors/mesh/mesh_data.c
+ *
+ * TODO: (As discussed with sergey-) :
+ * Maybe move this function to `blenderkernel/intern/mesh.c`.
+ * and add definition to BKE_mesh.c.
+ */
static void mesh_add_edges(Mesh *mesh, int len);
unsigned int get_loose_edge_count(COLLADAFW::Mesh *mesh);
CustomData create_edge_custom_data(EdgeHash *eh);
+ /**
+ * Return the number of faces by summing up
+ * the face-counts of the parts.
+ * hint: This is done because `mesh->getFacesCount()` does
+ * count loose edges as extra faces, which is not what we want here.
+ */
void allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me);
/* TODO: import uv set names */
+ /**
+ * Read all faces from TRIANGLES, TRIANGLE_FANS, POLYLIST, POLYGON
+ * Important: This function MUST be called before read_lines()
+ * Otherwise we will lose all edges from faces (see read_lines() above)
+ *
+ * TODO: import uv set names.
+ */
void read_polys(COLLADAFW::Mesh *mesh, Mesh *me);
+ /**
+ * Read all loose edges.
+ * Important: This function assumes that all edges from existing
+ * faces have already been generated and added to me->medge
+ * So this function MUST be called after read_faces() (see below)
+ */
void read_lines(COLLADAFW::Mesh *mesh, Mesh *me);
unsigned int get_vertex_count(COLLADAFW::Polygons *mp, int index);
@@ -146,6 +183,11 @@ class MeshImporter : public MeshImporterBase {
bool is_flat_face(unsigned int *nind, COLLADAFW::MeshVertexData &nor, int count);
+ /**
+ * Returns the list of Users of the given Mesh object.
+ * NOTE: This function uses the object user flag to control
+ * which objects have already been processed.
+ */
std::vector<Object *> get_all_users_of(Mesh *reference_mesh);
public:
@@ -159,8 +201,34 @@ class MeshImporter : public MeshImporterBase {
virtual Mesh *get_mesh_by_geom_uid(const COLLADAFW::UniqueId &geom_uid);
+ /**
+ *
+ * During import all materials have been assigned to Object.
+ * Now we iterate over the imported objects and optimize
+ * the assignments as follows:
+ *
+ * for each imported geometry:
+ * if number of users is 1:
+ * get the user (object)
+ * move the materials from Object to Data
+ * else:
+ * determine which materials are assigned to the first user
+ * check if all other users have the same materials in the same order
+ * if the check is positive:
+ * Add the materials of the first user to the geometry
+ * adjust all other users accordingly.
+ *
+ */
void optimize_material_assignements();
+ /**
+ * We do not know in advance which objects will share geometries.
+ * And we do not know either if the objects which share geometries
+ * come along with different materials. So we first create the objects
+ * and assign the materials to Object, then in a later cleanup we decide
+ * which materials shall be moved to the created geometries. Also see
+ * optimize_material_assignements() above.
+ */
void assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
std::map<COLLADAFW::UniqueId, Material *> &uid_material_map,
Object *ob,
@@ -172,7 +240,7 @@ class MeshImporter : public MeshImporterBase {
bool isController,
std::map<COLLADAFW::UniqueId, Material *> &uid_material_map);
- /* create a mesh storing a pointer in a map so it can be retrieved later by geometry UID */
+ /** Create a mesh storing a pointer in a map so it can be retrieved later by geometry UID. */
bool write_geometry(const COLLADAFW::Geometry *geom);
std::string *get_geometry_name(const std::string &mesh_name);
};
diff --git a/source/blender/io/collada/SkinInfo.cpp b/source/blender/io/collada/SkinInfo.cpp
index f0e1c5e4c26..3b740b9cd8c 100644
--- a/source/blender/io/collada/SkinInfo.cpp
+++ b/source/blender/io/collada/SkinInfo.cpp
@@ -53,9 +53,6 @@ template<class T> static const char *bc_get_joint_name(T *node)
return id.empty() ? node->getOriginalId().c_str() : id.c_str();
}
-/* This is used to store data passed in write_controller_data.
- * Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members
- * so that arrays don't get freed until we free them explicitly. */
SkinInfo::SkinInfo() = default;
SkinInfo::SkinInfo(const SkinInfo &skin)
@@ -77,7 +74,6 @@ SkinInfo::SkinInfo(UnitConverter *conv) : unit_converter(conv), ob_arm(nullptr),
{
}
-/* nobody owns the data after this, so it should be freed manually with releaseMemory */
template<class T> void SkinInfo::transfer_array_data(T &src, T &dest)
{
dest.setData(src.getData(), src.getCount());
@@ -85,7 +81,6 @@ template<class T> void SkinInfo::transfer_array_data(T &src, T &dest)
dest.yieldOwnerShip();
}
-/* when src is const we cannot src.yieldOwnerShip, this is used by copy constructor */
void SkinInfo::transfer_int_array_data_const(const COLLADAFW::IntValuesArray &src,
COLLADAFW::IntValuesArray &dest)
{
@@ -124,9 +119,6 @@ void SkinInfo::free()
// weights.releaseMemory();
}
-/* using inverse bind matrices to construct armature
- * it is safe to invert them to get the original matrices
- * because if they are inverse matrices, they can be inverted */
void SkinInfo::add_joint(const COLLADABU::Math::Matrix4 &matrix)
{
JointData jd;
@@ -152,7 +144,6 @@ void SkinInfo::set_controller(const COLLADAFW::SkinController *co)
}
}
-/* called from write_controller */
Object *SkinInfo::create_armature(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
ob_arm = bc_add_object(bmain, scene, view_layer, OB_ARMATURE, nullptr);
@@ -193,11 +184,6 @@ const COLLADAFW::UniqueId &SkinInfo::get_controller_uid()
return controller_uid;
}
-/* check if this skin controller references a joint or any descendant of it
- *
- * some nodes may not be referenced by SkinController,
- * in this case to determine if the node belongs to this armature,
- * we need to search down the tree */
bool SkinInfo::uses_joint_or_descendant(COLLADAFW::Node *node)
{
const COLLADAFW::UniqueId &uid = node->getUniqueId();
diff --git a/source/blender/io/collada/SkinInfo.h b/source/blender/io/collada/SkinInfo.h
index 7ce66b22a5f..49a820f2fcd 100644
--- a/source/blender/io/collada/SkinInfo.h
+++ b/source/blender/io/collada/SkinInfo.h
@@ -35,9 +35,11 @@
#include "TransformReader.h"
#include "collada_internal.h"
-/* This is used to store data passed in write_controller_data.
- * Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members
- * so that arrays don't get freed until we free them explicitly. */
+/**
+ * This is used to store data passed in write_controller_data.
+ * Arrays from #COLLADAFW::SkinControllerData lose ownership, so do this class members
+ * so that arrays don't get freed until we free them explicitly.
+ */
class SkinInfo {
private:
/* to build armature bones from inverse bind matrices */
@@ -69,10 +71,10 @@ class SkinInfo {
SkinInfo(const SkinInfo &skin);
SkinInfo(UnitConverter *conv);
- /* nobody owns the data after this, so it should be freed manually with releaseMemory */
+ /** Nobody owns the data after this, so it should be freed manually with releaseMemory. */
template<typename T> void transfer_array_data(T &src, T &dest);
- /* when src is const we cannot src.yieldOwnerShip, this is used by copy constructor */
+ /** When src is const we cannot `src.yieldOwnerShip`, this is used by copy constructor. */
void transfer_int_array_data_const(const COLLADAFW::IntValuesArray &src,
COLLADAFW::IntValuesArray &dest);
@@ -83,14 +85,16 @@ class SkinInfo {
void free();
- /* using inverse bind matrices to construct armature
+ /**
+ * Using inverse bind matrices to construct armature
* it is safe to invert them to get the original matrices
- * because if they are inverse matrices, they can be inverted */
+ * because if they are inverse matrices, they can be inverted.
+ */
void add_joint(const COLLADABU::Math::Matrix4 &matrix);
void set_controller(const COLLADAFW::SkinController *co);
- /* called from write_controller */
+ /** Called from write_controller. */
Object *create_armature(Main *bmain, Scene *scene, ViewLayer *view_layer);
Object *set_armature(Object *ob_arm);
@@ -101,11 +105,13 @@ class SkinInfo {
const COLLADAFW::UniqueId &get_controller_uid();
- /* check if this skin controller references a joint or any descendant of it
+ /**
+ * Check if this skin controller references a joint or any descendant of it
*
* some nodes may not be referenced by SkinController,
* in this case to determine if the node belongs to this armature,
- * we need to search down the tree */
+ * we need to search down the tree.
+ */
bool uses_joint_or_descendant(COLLADAFW::Node *node);
void link_armature(bContext *C,
diff --git a/source/blender/io/collada/collada_internal.cpp b/source/blender/io/collada/collada_internal.cpp
index bd6f496c8ec..5592f5393a2 100644
--- a/source/blender/io/collada/collada_internal.cpp
+++ b/source/blender/io/collada/collada_internal.cpp
@@ -213,7 +213,6 @@ void clear_global_id_map()
global_id_map.clear();
}
-/** Look at documentation of translate_map */
std::string translate_id(const char *idString)
{
std::string id = std::string(idString);
diff --git a/source/blender/io/collada/collada_internal.h b/source/blender/io/collada/collada_internal.h
index e3894093507..cdd19ebe9a7 100644
--- a/source/blender/io/collada/collada_internal.h
+++ b/source/blender/io/collada/collada_internal.h
@@ -76,6 +76,7 @@ class UnitConverter {
extern void clear_global_id_map();
/** Look at documentation of translate_map */
extern std::string translate_id(const std::string &id);
+/** Look at documentation of translate_map */
extern std::string translate_id(const char *idString);
extern std::string id_name(void *id);
diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp
index 60c4a9bad13..d3655c10655 100644
--- a/source/blender/io/collada/collada_utils.cpp
+++ b/source/blender/io/collada/collada_utils.cpp
@@ -92,9 +92,10 @@ float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray &array, unsigned in
return array.getDoubleValues()->getData()[index];
}
-/* copied from /editors/object/object_relations.c */
int bc_test_parent_loop(Object *par, Object *ob)
{
+ /* Copied from /editors/object/object_relations.c */
+
/* test if 'ob' is a parent somewhere in par's parents */
if (par == nullptr) {
@@ -289,9 +290,10 @@ bool bc_has_object_type(LinkNode *export_set, short obtype)
return false;
}
-/* Use bubble sort algorithm for sorting the export set */
void bc_bubble_sort_by_Object_name(LinkNode *export_set)
{
+ /* Use bubble sort algorithm for sorting the export set. */
+
bool sorted = false;
LinkNode *node;
for (node = export_set; node->next && !sorted; node = node->next) {
@@ -312,11 +314,6 @@ void bc_bubble_sort_by_Object_name(LinkNode *export_set)
}
}
-/* Check if a bone is the top most exportable bone in the bone hierarchy.
- * When deform_bones_only == false, then only bones with NO parent
- * can be root bones. Otherwise the top most deform bones in the hierarchy
- * are root bones.
- */
bool bc_is_root_bone(Bone *aBone, bool deform_bones_only)
{
if (deform_bones_only) {
@@ -360,12 +357,6 @@ std::string bc_replace_string(std::string data,
return data;
}
-/**
- * Calculate a rescale factor such that the imported scene's scale
- * is preserved. I.e. 1 meter in the import will also be
- * 1 meter in the current scene.
- */
-
void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene)
{
if (scale_to_scene) {
@@ -386,9 +377,6 @@ void bc_match_scale(std::vector<Object *> *objects_done,
}
}
-/*
- * Convenience function to get only the needed components of a matrix
- */
void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size)
{
if (size) {
@@ -408,17 +396,6 @@ void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], floa
}
}
-/*
- * Create rotation_quaternion from a delta rotation and a reference quat
- *
- * Input:
- * mat_from: The rotation matrix before rotation
- * mat_to : The rotation matrix after rotation
- * qref : the quat corresponding to mat_from
- *
- * Output:
- * rot : the calculated result (quaternion)
- */
void bc_rotate_from_reference_quat(float quat_to[4], float quat_from[4], float mat_to[4][4])
{
float qd[4];
@@ -444,22 +421,19 @@ void bc_triangulate_mesh(Mesh *me)
/* XXX: The triangulation method selection could be offered in the UI. */
int quad_method = MOD_TRIANGULATE_QUAD_SHORTEDGE;
- const struct BMeshCreateParams bm_create_params = {0};
+ const BMeshCreateParams bm_create_params{};
BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_create_params);
- BMeshFromMeshParams bm_from_me_params = {0};
+ BMeshFromMeshParams bm_from_me_params{};
bm_from_me_params.calc_face_normal = true;
BM_mesh_bm_from_me(bm, me, &bm_from_me_params);
BM_mesh_triangulate(bm, quad_method, use_beauty, 4, tag_only, nullptr, nullptr, nullptr);
- BMeshToMeshParams bm_to_me_params = {0};
+ BMeshToMeshParams bm_to_me_params{};
bm_to_me_params.calc_object_remap = false;
BM_mesh_bm_to_me(nullptr, bm, me, &bm_to_me_params);
BM_mesh_free(bm);
}
-/*
- * A bone is a leaf when it has no children or all children are not connected.
- */
bool bc_is_leaf_bone(Bone *bone)
{
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
@@ -501,11 +475,6 @@ int bc_set_layer(int bitfield, int layer, bool enable)
return bitfield;
}
-/**
- * This method creates a new extension map when needed.
- * \note The ~BoneExtensionManager destructor takes care
- * to delete the created maps when the manager is removed.
- */
BoneExtensionMap &BoneExtensionManager::getExtensionMap(bArmature *armature)
{
std::string key = armature->id.name;
@@ -535,7 +504,6 @@ BoneExtensionManager::~BoneExtensionManager()
* See ArmatureImporter::fix_leaf_bones()
* and ArmatureImporter::connect_bone_chains()
*/
-
BoneExtended::BoneExtended(EditBone *aBone)
{
this->set_name(aBone->name);
@@ -697,9 +665,6 @@ int BoneExtended::get_use_connect()
return this->use_connect;
}
-/**
- * Stores a 4*4 matrix as a custom bone property array of size 16
- */
void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4])
{
IDProperty *idgroup = (IDProperty *)ebone->prop;
@@ -745,19 +710,11 @@ static void bc_set_IDProperty(EditBone *ebone, const char *key, float value)
}
#endif
-/**
- * Get a custom property when it exists.
- * This function is also used to check if a property exists.
- */
IDProperty *bc_get_IDProperty(Bone *bone, std::string key)
{
return (bone->prop == nullptr) ? nullptr : IDP_GetPropertyFromGroup(bone->prop, key.c_str());
}
-/**
- * Read a custom bone property and convert to float
- * Return def if the property does not exist.
- */
float bc_get_property(Bone *bone, std::string key, float def)
{
float result = def;
@@ -780,14 +737,6 @@ float bc_get_property(Bone *bone, std::string key, float def)
return result;
}
-/**
- * Read a custom bone property and convert to matrix
- * Return true if conversion was successful
- *
- * Return false if:
- * - the property does not exist
- * - is not an array of size 16
- */
bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4])
{
IDProperty *property = bc_get_IDProperty(bone, key);
@@ -803,9 +752,6 @@ bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4])
return false;
}
-/**
- * get a vector that is stored in 3 custom properties (used in Blender <= 2.78)
- */
void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3])
{
val[0] = bc_get_property(bone, key + "_x", def[0]);
@@ -1014,12 +960,6 @@ void bc_apply_global_transform(Vector &to_vec, const BCMatrix &global_transform,
mul_v3_m4v3(to_vec, transform, to_vec);
}
-/**
- * Check if custom information about bind matrix exists and modify the from_mat
- * accordingly.
- *
- * NOTE: This is old style for Blender <= 2.78 only kept for compatibility
- */
void bc_create_restpose_mat(BCExportSettings &export_settings,
Bone *bone,
float to_mat[4][4],
diff --git a/source/blender/io/collada/collada_utils.h b/source/blender/io/collada/collada_utils.h
index d0a5d37d6d2..e06f7b2cb8b 100644
--- a/source/blender/io/collada/collada_utils.h
+++ b/source/blender/io/collada/collada_utils.h
@@ -143,6 +143,12 @@ extern char *bc_CustomData_get_layer_name(const CustomData *data, int type, int
extern char *bc_CustomData_get_active_layer_name(const CustomData *data, int type);
extern void bc_bubble_sort_by_Object_name(LinkNode *export_set);
+/**
+ * Check if a bone is the top most exportable bone in the bone hierarchy.
+ * When deform_bones_only == false, then only bones with NO parent
+ * can be root bones. Otherwise the top most deform bones in the hierarchy
+ * are root bones.
+ */
extern bool bc_is_root_bone(Bone *aBone, bool deform_bones_only);
extern int bc_get_active_UVLayer(Object *ob);
@@ -195,17 +201,39 @@ extern std::string bc_replace_string(std::string data,
const std::string &pattern,
const std::string &replacement);
extern std::string bc_url_encode(std::string data);
+/**
+ * Calculate a rescale factor such that the imported scene's scale
+ * is preserved. I.e. 1 meter in the import will also be
+ * 1 meter in the current scene.
+ */
extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene);
extern void bc_match_scale(std::vector<Object *> *objects_done,
UnitConverter &bc_unit,
bool scale_to_scene);
+/**
+ * Convenience function to get only the needed components of a matrix.
+ */
extern void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size);
+/**
+ * Create rotation_quaternion from a delta rotation and a reference quat
+ *
+ * Input:
+ * mat_from: The rotation matrix before rotation
+ * mat_to : The rotation matrix after rotation
+ * qref : the quat corresponding to mat_from
+ *
+ * Output:
+ * rot : the calculated result (quaternion).
+ */
extern void bc_rotate_from_reference_quat(float quat_to[4],
float quat_from[4],
float mat_to[4][4]);
extern void bc_triangulate_mesh(Mesh *me);
+/**
+ * A bone is a leaf when it has no children or all children are not connected.
+ */
extern bool bc_is_leaf_bone(Bone *bone);
extern EditBone *bc_get_edit_bone(bArmature *armature, char *name);
extern int bc_set_layer(int bitfield, int layer, bool enable);
@@ -224,12 +252,34 @@ void bc_copy_v44_m4d(std::vector<std::vector<double>> &r, double (&a)[4][4]);
void bc_sanitize_v3(double v[3], int precision);
void bc_sanitize_v3(float v[3], int precision);
+/**
+ * Get a custom property when it exists.
+ * This function is also used to check if a property exists.
+ */
extern IDProperty *bc_get_IDProperty(Bone *bone, std::string key);
extern void bc_set_IDProperty(EditBone *ebone, const char *key, float value);
+/**
+ * Stores a 4*4 matrix as a custom bone property array of size 16.
+ */
extern void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4]);
+/**
+ * Read a custom bone property and convert to float
+ * Return def if the property does not exist.
+ */
extern float bc_get_property(Bone *bone, std::string key, float def);
+/**
+ * Get a vector that is stored in 3 custom properties (used in Blender <= 2.78).
+ */
extern void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3]);
+/**
+ * Read a custom bone property and convert to matrix
+ * Return true if conversion was successful
+ *
+ * Return false if:
+ * - the property does not exist
+ * - is not an array of size 16
+ */
extern bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4]);
extern void bc_enable_fcurves(bAction *act, char *bone_name);
@@ -241,23 +291,29 @@ extern bool bc_has_animations(Object *ob);
extern void bc_add_global_transform(Matrix &to_mat,
const Matrix &from_mat,
const BCMatrix &global_transform,
- const bool invert = false);
+ bool invert = false);
extern void bc_add_global_transform(Vector &to_vec,
const Vector &from_vec,
const BCMatrix &global_transform,
- const bool invert = false);
+ bool invert = false);
extern void bc_add_global_transform(Vector &to_vec,
const BCMatrix &global_transform,
- const bool invert = false);
+ bool invert = false);
extern void bc_add_global_transform(Matrix &to_mat,
const BCMatrix &global_transform,
- const bool invert = false);
+ bool invert = false);
extern void bc_apply_global_transform(Matrix &to_mat,
const BCMatrix &global_transform,
- const bool invert = false);
+ bool invert = false);
extern void bc_apply_global_transform(Vector &to_vec,
const BCMatrix &global_transform,
- const bool invert = false);
+ bool invert = false);
+/**
+ * Check if custom information about bind matrix exists and modify the from_mat
+ * accordingly.
+ *
+ * \note This is old style for Blender <= 2.78 only kept for compatibility.
+ */
extern void bc_create_restpose_mat(BCExportSettings &export_settings,
Bone *bone,
float to_mat[4][4],
@@ -326,7 +382,7 @@ class BoneExtended {
void set_name(char *aName);
char *get_name();
- void set_chain_length(const int aLength);
+ void set_chain_length(int aLength);
int get_chain_length();
void set_leaf_bone(bool state);
@@ -364,6 +420,11 @@ class BoneExtensionManager {
std::map<std::string, BoneExtensionMap *> extended_bone_maps;
public:
+ /**
+ * This method creates a new extension map when needed.
+ * \note The ~BoneExtensionManager destructor takes care
+ * to delete the created maps when the manager is removed.
+ */
BoneExtensionMap &getExtensionMap(bArmature *armature);
~BoneExtensionManager();
};
diff --git a/source/blender/io/common/IO_abstract_hierarchy_iterator.h b/source/blender/io/common/IO_abstract_hierarchy_iterator.h
index 0bebc4384a9..e024b766c99 100644
--- a/source/blender/io/common/IO_abstract_hierarchy_iterator.h
+++ b/source/blender/io/common/IO_abstract_hierarchy_iterator.h
@@ -111,7 +111,7 @@ struct HierarchyContext {
void mark_as_instance_of(const std::string &reference_export_path);
void mark_as_not_instanced();
- bool is_object_visible(const enum eEvaluationMode evaluation_mode) const;
+ bool is_object_visible(enum eEvaluationMode evaluation_mode) const;
};
/* Abstract writer for objects. Create concrete subclasses to write to USD, Alembic, etc.
diff --git a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
index 3cda4d125d0..bfd91620654 100644
--- a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
+++ b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
@@ -462,7 +462,6 @@ void AbstractHierarchyIterator::visit_dupli_object(DupliObject *dupli_object,
context->weak_export = false;
context->export_path = "";
context->original_export_path = "";
- context->export_path = "";
context->animation_check_include_parent = false;
copy_m4_m4(context->matrix_world, dupli_object->mat);
@@ -682,6 +681,15 @@ void AbstractHierarchyIterator::make_writers_particle_systems(
writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_hair_writer);
break;
case PART_EMITTER:
+ case PART_FLUID_FLIP:
+ case PART_FLUID_SPRAY:
+ case PART_FLUID_BUBBLE:
+ case PART_FLUID_FOAM:
+ case PART_FLUID_TRACER:
+ case PART_FLUID_SPRAYFOAM:
+ case PART_FLUID_SPRAYBUBBLE:
+ case PART_FLUID_FOAMBUBBLE:
+ case PART_FLUID_SPRAYFOAMBUBBLE:
writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_particle_writer);
break;
}
diff --git a/source/blender/io/gpencil/gpencil_io.h b/source/blender/io/gpencil/gpencil_io.h
index fab867b38b3..ea328a531c6 100644
--- a/source/blender/io/gpencil/gpencil_io.h
+++ b/source/blender/io/gpencil/gpencil_io.h
@@ -82,9 +82,16 @@ typedef enum eGpencilExportSelect {
typedef enum eGpencilExportFrame {
GP_EXPORT_FRAME_ACTIVE = 0,
GP_EXPORT_FRAME_SELECTED = 1,
+ GP_EXPORT_FRAME_SCENE = 2,
} eGpencilExportFrame;
+/**
+ * Main export entry point function.
+ */
bool gpencil_io_export(const char *filename, struct GpencilIOParams *iparams);
+/**
+ * Main import entry point function.
+ */
bool gpencil_io_import(const char *filename, struct GpencilIOParams *iparams);
#ifdef __cplusplus
diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.cc b/source/blender/io/gpencil/intern/gpencil_io_base.cc
index 294f6bfccb7..7868bade8c1 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_base.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_base.cc
@@ -23,9 +23,8 @@
* \ingroup bgpencil
*/
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_path_util.h"
#include "BLI_span.hh"
@@ -145,7 +144,6 @@ void GpencilIO::prepare_camera_params(Scene *scene, const GpencilIOParams *ipara
}
}
-/** Create a list of selected objects sorted from back to front */
void GpencilIO::create_object_list()
{
ViewLayer *view_layer = CTX_data_view_layer(params_.C);
@@ -194,17 +192,12 @@ void GpencilIO::create_object_list()
});
}
-/**
- * Set file input_text full path.
- * \param filename: Path of the file provided by save dialog.
- */
void GpencilIO::filename_set(const char *filename)
{
BLI_strncpy(filename_, filename, FILE_MAX);
BLI_path_abs(filename_, BKE_main_blendfile_path(bmain_));
}
-/** Convert to screenspace. */
bool GpencilIO::gpencil_3D_point_to_screen_space(const float3 co, float2 &r_co)
{
float3 parent_co = diff_mat_ * co;
@@ -244,7 +237,6 @@ bool GpencilIO::gpencil_3D_point_to_screen_space(const float3 co, float2 &r_co)
return false;
}
-/** Convert to render space. */
float2 GpencilIO::gpencil_3D_point_to_render_space(const float3 co)
{
float3 parent_co = diff_mat_ * co;
@@ -266,7 +258,6 @@ float2 GpencilIO::gpencil_3D_point_to_render_space(const float3 co)
return r_co;
}
-/** Convert to 2D. */
float2 GpencilIO::gpencil_3D_point_to_2D(const float3 co)
{
const bool is_camera = (bool)(rv3d_->persp == RV3D_CAMOB);
@@ -278,7 +269,6 @@ float2 GpencilIO::gpencil_3D_point_to_2D(const float3 co)
return result;
}
-/** Get radius of point. */
float GpencilIO::stroke_point_radius_get(bGPDlayer *gpl, bGPDstroke *gps)
{
bGPDspoint *pt = &gps->points[0];
@@ -292,7 +282,7 @@ float GpencilIO::stroke_point_radius_get(bGPDlayer *gpl, bGPDstroke *gps)
const float2 screen_ex = gpencil_3D_point_to_2D(&pt->x);
const float2 v1 = screen_co - screen_ex;
- float radius = v1.length();
+ float radius = math::length(v1);
BKE_gpencil_free_stroke(gps_perimeter);
return MAX2(radius, 1.0f);
@@ -338,7 +328,6 @@ bool GpencilIO::is_camera_mode()
return is_camera_;
}
-/* Calculate selected strokes boundbox. */
void GpencilIO::selected_objects_boundbox_calc()
{
const float gap = 10.0f;
diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.hh b/source/blender/io/gpencil/intern/gpencil_io_base.hh
index 02758883f19..ae54d5056dc 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_base.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_base.hh
@@ -22,9 +22,8 @@
* \ingroup bgpencil
*/
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_vector.hh"
#include "DNA_space_types.h" /* for FILE_MAX */
@@ -49,7 +48,7 @@ class GpencilIO {
public:
GpencilIO(const GpencilIOParams *iparams);
- void frame_number_set(const int value);
+ void frame_number_set(int value);
void prepare_camera_params(Scene *scene, const GpencilIOParams *iparams);
protected:
@@ -87,11 +86,16 @@ class GpencilIO {
float stroke_color_[4], fill_color_[4];
/* Geometry functions. */
+ /** Convert to screenspace. */
bool gpencil_3D_point_to_screen_space(const float3 co, float2 &r_co);
+ /** Convert to render space. */
float2 gpencil_3D_point_to_render_space(const float3 co);
+ /** Convert to 2D. */
float2 gpencil_3D_point_to_2D(const float3 co);
+ /** Get radius of point. */
float stroke_point_radius_get(struct bGPDlayer *gpl, struct bGPDstroke *gps);
+ /** Create a list of selected objects sorted from back to front */
void create_object_list();
bool is_camera_mode();
@@ -101,8 +105,13 @@ class GpencilIO {
void prepare_layer_export_matrix(struct Object *ob, struct bGPDlayer *gpl);
void prepare_stroke_export_colors(struct Object *ob, struct bGPDstroke *gps);
+ /* Calculate selected strokes boundbox. */
void selected_objects_boundbox_calc();
void selected_objects_boundbox_get(rctf *boundbox);
+ /**
+ * Set file input_text full path.
+ * \param filename: Path of the file provided by save dialog.
+ */
void filename_set(const char *filename);
private:
diff --git a/source/blender/io/gpencil/intern/gpencil_io_capi.cc b/source/blender/io/gpencil/intern/gpencil_io_capi.cc
index 544c51e0b4f..92ce165e059 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_capi.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_capi.cc
@@ -112,32 +112,39 @@ static bool gpencil_io_export_pdf(Depsgraph *depsgraph,
exporter->frame_number_set(iparams->frame_cur);
result |= exporter->new_document();
- const bool use_frame_selected = (iparams->frame_mode == GP_EXPORT_FRAME_SELECTED);
- if (use_frame_selected) {
- for (int32_t i = iparams->frame_start; i < iparams->frame_end + 1; i++) {
- if (!is_keyframe_included(gpd_eval, i, use_frame_selected)) {
- continue;
- }
-
- CFRA = i;
- BKE_scene_graph_update_for_newframe(depsgraph);
+ switch (iparams->frame_mode) {
+ case GP_EXPORT_FRAME_ACTIVE: {
exporter->prepare_camera_params(scene, iparams);
- exporter->frame_number_set(i);
exporter->add_newpage();
exporter->add_body();
+ result = exporter->write();
+ break;
}
- result = exporter->write();
- /* Back to original frame. */
- exporter->frame_number_set(iparams->frame_cur);
- CFRA = iparams->frame_cur;
- BKE_scene_camera_switch_update(scene);
- BKE_scene_graph_update_for_newframe(depsgraph);
- }
- else {
- exporter->prepare_camera_params(scene, iparams);
- exporter->add_newpage();
- exporter->add_body();
- result = exporter->write();
+ case GP_EXPORT_FRAME_SELECTED:
+ case GP_EXPORT_FRAME_SCENE: {
+ for (int32_t i = iparams->frame_start; i < iparams->frame_end + 1; i++) {
+ if ((iparams->frame_mode == GP_EXPORT_FRAME_SELECTED) &&
+ (!is_keyframe_included(gpd_eval, i, true))) {
+ continue;
+ }
+
+ CFRA = i;
+ BKE_scene_graph_update_for_newframe(depsgraph);
+ exporter->prepare_camera_params(scene, iparams);
+ exporter->frame_number_set(i);
+ exporter->add_newpage();
+ exporter->add_body();
+ }
+ result = exporter->write();
+ /* Back to original frame. */
+ exporter->frame_number_set(iparams->frame_cur);
+ CFRA = iparams->frame_cur;
+ BKE_scene_camera_switch_update(scene);
+ BKE_scene_graph_update_for_newframe(depsgraph);
+ break;
+ }
+ default:
+ break;
}
return result;
@@ -170,7 +177,6 @@ static bool gpencil_io_export_frame_svg(GpencilExporterSVG *exporter,
}
#endif
-/* Main import entry point function. */
bool gpencil_io_import(const char *filename, GpencilIOParams *iparams)
{
GpencilImporterSVG importer = GpencilImporterSVG(filename, iparams);
@@ -178,7 +184,6 @@ bool gpencil_io_import(const char *filename, GpencilIOParams *iparams)
return gpencil_io_import_frame(&importer, *iparams);
}
-/* Main export entry point function. */
bool gpencil_io_export(const char *filename, GpencilIOParams *iparams)
{
Depsgraph *depsgraph_ = CTX_data_depsgraph_pointer(iparams->C);
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
index 82f8444d43e..c856e60c4b8 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
@@ -109,7 +109,6 @@ bool GpencilExporterPDF::write()
return (res == 0) ? true : false;
}
-/* Create pdf document. */
bool GpencilExporterPDF::create_document()
{
pdf_ = HPDF_New(error_handler, nullptr);
@@ -120,7 +119,6 @@ bool GpencilExporterPDF::create_document()
return true;
}
-/* Add page. */
bool GpencilExporterPDF::add_page()
{
/* Add a new page object. */
@@ -136,7 +134,6 @@ bool GpencilExporterPDF::add_page()
return true;
}
-/* Main layer loop. */
void GpencilExporterPDF::export_gpencil_layers()
{
/* If is doing a set of frames, the list of objects can change for each frame. */
@@ -229,10 +226,6 @@ void GpencilExporterPDF::export_gpencil_layers()
}
}
-/**
- * Export a stroke using polyline or polygon
- * \param do_fill: True if the stroke is only fill
- */
void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl,
bGPDstroke *gps,
const bool is_stroke,
@@ -245,7 +238,7 @@ void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl,
/* Get the thickness in pixels using a simple 1 point stroke. */
bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, false, false);
gps_temp->totpoints = 1;
- gps_temp->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points");
+ gps_temp->points = MEM_cnew<bGPDspoint>("gp_stroke_points");
const bGPDspoint *pt_src = &gps->points[0];
bGPDspoint *pt_dst = &gps_temp->points[0];
copy_v3_v3(&pt_dst->x, &pt_src->x);
@@ -288,10 +281,6 @@ void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl,
HPDF_Page_GRestore(page_);
}
-/**
- * Set color.
- * \param do_fill: True if the stroke is only fill.
- */
void GpencilExporterPDF::color_set(bGPDlayer *gpl, const bool do_fill)
{
const float fill_opacity = fill_color_[3] * gpl->opacity;
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh
index 89d97f79783..5de22530fec 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh
@@ -45,21 +45,29 @@ class GpencilExporterPDF : public GpencilExporter {
protected:
private:
- /* PDF document. */
+ /** PDF document. */
HPDF_Doc pdf_;
- /* PDF page. */
+ /** PDF page. */
HPDF_Page page_;
+ /** Create PDF document. */
bool create_document();
+ /** Add page. */
bool add_page();
+ /** Main layer loop. */
void export_gpencil_layers();
- void export_stroke_to_polyline(bGPDlayer *gpl,
- bGPDstroke *gps,
- const bool is_stroke,
- const bool do_fill,
- const bool normalize);
- void color_set(bGPDlayer *gpl, const bool do_fill);
+ /**
+ * Export a stroke using poly-line or polygon
+ * \param do_fill: True if the stroke is only fill
+ */
+ void export_stroke_to_polyline(
+ bGPDlayer *gpl, bGPDstroke *gps, bool is_stroke, bool do_fill, bool normalize);
+ /**
+ * Set color.
+ * \param do_fill: True if the stroke is only fill.
+ */
+ void color_set(bGPDlayer *gpl, bool do_fill);
};
} // namespace blender::io::gpencil
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
index a9745415d40..3ca6ed6cd45 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
@@ -97,7 +97,6 @@ bool GpencilExporterSVG::write()
return result;
}
-/* Create document header and main svg node. */
void GpencilExporterSVG::create_document_header()
{
/* Add a custom document declaration node. */
@@ -133,7 +132,6 @@ void GpencilExporterSVG::create_document_header()
main_node_.append_attribute("viewBox").set_value(viewbox.c_str());
}
-/* Main layer loop. */
void GpencilExporterSVG::export_gpencil_layers()
{
const bool is_clipping = is_camera_mode() && (params_.flag & GP_EXPORT_CLIP_CAMERA) != 0;
@@ -254,11 +252,6 @@ void GpencilExporterSVG::export_gpencil_layers()
}
}
-/**
- * Export a stroke using SVG path
- * \param node_gpl: Node of the layer.
- * \param do_fill: True if the stroke is only fill
- */
void GpencilExporterSVG::export_stroke_to_path(bGPDlayer *gpl,
bGPDstroke *gps,
pugi::xml_node node_gpl,
@@ -303,11 +296,6 @@ void GpencilExporterSVG::export_stroke_to_path(bGPDlayer *gpl,
node_gps.append_attribute("d").set_value(txt.c_str());
}
-/**
- * Export a stroke using polyline or polygon
- * \param node_gpl: Node of the layer.
- * \param do_fill: True if the stroke is only fill
- */
void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl,
bGPDstroke *gps,
pugi::xml_node node_gpl,
@@ -320,7 +308,7 @@ void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl,
/* Get the thickness in pixels using a simple 1 point stroke. */
bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, false, false);
gps_temp->totpoints = 1;
- gps_temp->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points");
+ gps_temp->points = MEM_cnew<bGPDspoint>("gp_stroke_points");
bGPDspoint *pt_src = &gps->points[0];
bGPDspoint *pt_dst = &gps_temp->points[0];
copy_v3_v3(&pt_dst->x, &pt_src->x);
@@ -351,11 +339,6 @@ void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl,
node_gps.append_attribute("points").set_value(txt.c_str());
}
-/**
- * Set color SVG string for stroke
- * \param node_gps: Stroke node.
- * \param do_fill: True if the stroke is only fill.
- */
void GpencilExporterSVG::color_string_set(bGPDlayer *gpl,
bGPDstroke *gps,
pugi::xml_node node_gps,
@@ -392,16 +375,6 @@ void GpencilExporterSVG::color_string_set(bGPDlayer *gpl,
}
}
-/**
- * Create a SVG rectangle
- * \param node: Parent node
- * \param x: X location
- * \param y: Y location
- * \param width: width of the rectangle
- * \param height: Height of the rectangle
- * \param thickness: Thickness of the line
- * \param hexcolor: Color of the line
- */
void GpencilExporterSVG::add_rect(pugi::xml_node node,
float x,
float y,
@@ -422,15 +395,6 @@ void GpencilExporterSVG::add_rect(pugi::xml_node node,
}
}
-/**
- * Create SVG text
- * \param node: Parent node
- * \param x: X location
- * \param y: Y location
- * \param text: Text to include
- * \param size: Size of the text
- * \param hexcolor: Color of the text
- */
void GpencilExporterSVG::add_text(pugi::xml_node node,
float x,
float y,
@@ -448,7 +412,6 @@ void GpencilExporterSVG::add_text(pugi::xml_node node,
nodetxt.text().set(text.c_str());
}
-/** Convert a color to Hex value (#FFFFFF). */
std::string GpencilExporterSVG::rgb_to_hexstr(const float color[3])
{
uint8_t r = color[0] * 255.0f;
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh b/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh
index 6d8a0c2f6ac..8b88e9dc142 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh
@@ -42,6 +42,16 @@ class GpencilExporterSVG : public GpencilExporter {
bool write();
protected:
+ /**
+ * Create a SVG rectangle
+ * \param node: Parent node
+ * \param x: X location
+ * \param y: Y location
+ * \param width: width of the rectangle
+ * \param height: Height of the rectangle
+ * \param thickness: Thickness of the line
+ * \param hexcolor: Color of the line
+ */
static void add_rect(pugi::xml_node node,
float x,
float y,
@@ -50,39 +60,62 @@ class GpencilExporterSVG : public GpencilExporter {
float thickness,
std::string hexcolor);
- static void add_text(pugi::xml_node node,
- float x,
- float y,
- std::string text,
- const float size,
- std::string hexcolor);
+ /**
+ * Create SVG text
+ * \param node: Parent node
+ * \param x: X location
+ * \param y: Y location
+ * \param text: Text to include
+ * \param size: Size of the text
+ * \param hexcolor: Color of the text
+ */
+ static void add_text(
+ pugi::xml_node node, float x, float y, std::string text, float size, std::string hexcolor);
private:
- /* XML doc. */
+ /** XML doc. */
pugi::xml_document main_doc_;
- /* Main document node. */
+ /** Main document node. */
pugi::xml_node main_node_;
/** Frame node. */
pugi::xml_node frame_node_;
+ /** Create document header and main SVG node. */
void create_document_header();
+ /** Main layer loop. */
void export_gpencil_layers();
+ /**
+ * Export a stroke using SVG path
+ * \param node_gpl: Node of the layer.
+ * \param do_fill: True if the stroke is only fill
+ */
void export_stroke_to_path(struct bGPDlayer *gpl,
struct bGPDstroke *gps,
pugi::xml_node node_gpl,
- const bool do_fill);
+ bool do_fill);
+ /**
+ * Export a stroke using poly-line or polygon
+ * \param node_gpl: Node of the layer.
+ * \param do_fill: True if the stroke is only fill
+ */
void export_stroke_to_polyline(struct bGPDlayer *gpl,
struct bGPDstroke *gps,
pugi::xml_node node_gpl,
- const bool is_stroke,
- const bool do_fill);
+ bool is_stroke,
+ bool do_fill);
+ /**
+ * Set color SVG string for stroke
+ * \param node_gps: Stroke node.
+ * \param do_fill: True if the stroke is only fill.
+ */
void color_string_set(struct bGPDlayer *gpl,
struct bGPDstroke *gps,
pugi::xml_node node_gps,
- const bool do_fill);
+ bool do_fill);
+ /** Convert a color to Hex value (#FFFFFF). */
std::string rgb_to_hexstr(const float color[3]);
};
diff --git a/source/blender/io/gpencil/intern/gpencil_io_import_base.hh b/source/blender/io/gpencil/intern/gpencil_io_import_base.hh
index 7d6fad2340b..31ded8234c8 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_import_base.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_import_base.hh
@@ -33,7 +33,7 @@ class GpencilImporter : public GpencilIO {
protected:
struct Object *create_object();
- int32_t create_material(const char *name, const bool stroke, const bool fill);
+ int32_t create_material(const char *name, bool stroke, bool fill);
private:
};
diff --git a/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc
index 941d1137f4d..455ebb7c3cb 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc
@@ -21,8 +21,8 @@
* \ingroup bgpencil
*/
-#include "BLI_float3.hh"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "DNA_gpencil_types.h"
diff --git a/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh b/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh
index 99e8b1ed4fd..24e80563a14 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh
@@ -47,10 +47,10 @@ class GpencilImporterSVG : public GpencilImporter {
struct bGPDframe *gpf,
struct NSVGshape *shape,
struct NSVGpath *path,
- const int32_t mat_index,
+ int32_t mat_index,
const float matrix[4][4]);
- void convert_color(const int32_t color, float r_linear_rgba[4]);
+ void convert_color(int32_t color, float r_linear_rgba[4]);
};
} // namespace blender::io::gpencil
diff --git a/source/blender/io/usd/intern/usd_capi_export.cc b/source/blender/io/usd/intern/usd_capi_export.cc
index efa31df25c1..0cc3fde8c6c 100644
--- a/source/blender/io/usd/intern/usd_capi_export.cc
+++ b/source/blender/io/usd/intern/usd_capi_export.cc
@@ -223,7 +223,7 @@ bool USD_export(bContext *C,
return export_ok;
}
-int USD_get_version(void)
+int USD_get_version()
{
/* USD 19.11 defines:
*
diff --git a/source/blender/io/usd/intern/usd_reader_curve.cc b/source/blender/io/usd/intern/usd_reader_curve.cc
index 12de1d82c72..5007d204020 100644
--- a/source/blender/io/usd/intern/usd_reader_curve.cc
+++ b/source/blender/io/usd/intern/usd_reader_curve.cc
@@ -108,11 +108,11 @@ void USDCurvesReader::read_curve_sample(Curve *cu, const double motionSampleTime
* Perhaps to be replaced by Blender/USD Schema. */
if (!usdNormals.empty()) {
/* Set extrusion to 1.0f. */
- curve_->ext1 = 1.0f;
+ curve_->extrude = 1.0f;
}
else {
/* Set bevel depth to 1.0f. */
- curve_->ext2 = 1.0f;
+ curve_->bevel_radius = 1.0f;
}
size_t idx = 0;
@@ -164,7 +164,7 @@ void USDCurvesReader::read_curve_sample(Curve *cu, const double motionSampleTime
bp->f1 = SELECT;
bp->weight = weight;
- float radius = curve_->width;
+ float radius = curve_->offset;
if (idx < usdWidths.size()) {
radius = usdWidths[idx];
}
diff --git a/source/blender/io/usd/intern/usd_reader_material.cc b/source/blender/io/usd/intern/usd_reader_material.cc
index 93e433e231c..645dea42971 100644
--- a/source/blender/io/usd/intern/usd_reader_material.cc
+++ b/source/blender/io/usd/intern/usd_reader_material.cc
@@ -23,6 +23,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BLI_math_vector.h"
#include "BLI_string.h"
@@ -298,7 +299,6 @@ Material *USDMaterialReader::add_material(const pxr::UsdShadeMaterial &usd_mater
return mtl;
}
-/* Create the Principled BSDF shader node network. */
void USDMaterialReader::import_usd_preview(Material *mtl,
const pxr::UsdShadeShader &usd_shader) const
{
@@ -340,7 +340,7 @@ void USDMaterialReader::import_usd_preview(Material *mtl,
nodeSetActive(ntree, output);
- ntreeUpdateTree(bmain_, ntree);
+ BKE_ntree_update_main_tree(bmain_, ntree, nullptr);
/* Optionally, set the material blend mode. */
@@ -416,7 +416,6 @@ void USDMaterialReader::set_principled_node_inputs(bNode *principled,
}
}
-/* Convert the given USD shader input to an input on the given Blender node. */
void USDMaterialReader::set_node_input(const pxr::UsdShadeInput &usd_input,
bNode *dest_node,
const char *dest_socket_name,
@@ -484,8 +483,6 @@ void USDMaterialReader::set_node_input(const pxr::UsdShadeInput &usd_input,
}
}
-/* Follow the connected source of the USD input to create corresponding inputs
- * for the given Blender node. */
void USDMaterialReader::follow_connection(const pxr::UsdShadeInput &usd_input,
bNode *dest_node,
const char *dest_socket_name,
@@ -594,8 +591,6 @@ void USDMaterialReader::convert_usd_uv_texture(const pxr::UsdShadeShader &usd_sh
}
}
-/* Load the texture image node's texture from the path given by the USD shader's
- * file input value. */
void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader,
bNode *tex_image) const
{
@@ -648,15 +643,11 @@ void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader,
color_space = file_input.GetAttr().GetColorSpace();
}
- if (color_space == usdtokens::RAW || color_space == usdtokens::raw) {
+ if (ELEM(color_space, usdtokens::RAW, usdtokens::raw)) {
STRNCPY(image->colorspace_settings.name, "Raw");
}
}
-/* This function creates a Blender UV Map node, under the simplifying assumption that
- * UsdPrimvarReader_float2 shaders output UV coordinates.
- * TODO(makowalski): investigate supporting conversion to other Blender node types
- * (e.g., Attribute Nodes) if needed. */
void USDMaterialReader::convert_usd_primvar_reader_float2(
const pxr::UsdShadeShader &usd_shader,
const pxr::TfToken & /* usd_source_name */,
diff --git a/source/blender/io/usd/intern/usd_reader_material.h b/source/blender/io/usd/intern/usd_reader_material.h
index a17504bd590..fb40b4f2f6d 100644
--- a/source/blender/io/usd/intern/usd_reader_material.h
+++ b/source/blender/io/usd/intern/usd_reader_material.h
@@ -90,12 +90,14 @@ class USDMaterialReader {
Material *add_material(const pxr::UsdShadeMaterial &usd_material) const;
protected:
+ /** Create the Principled BSDF shader node network. */
void import_usd_preview(Material *mtl, const pxr::UsdShadeShader &usd_shader) const;
void set_principled_node_inputs(bNode *principled_node,
bNodeTree *ntree,
const pxr::UsdShadeShader &usd_shader) const;
+ /** Convert the given USD shader input to an input on the given Blender node. */
void set_node_input(const pxr::UsdShadeInput &usd_input,
bNode *dest_node,
const char *dest_socket_name,
@@ -103,6 +105,10 @@ class USDMaterialReader {
int column,
NodePlacementContext *r_ctx) const;
+ /**
+ * Follow the connected source of the USD input to create corresponding inputs
+ * for the given Blender node.
+ */
void follow_connection(const pxr::UsdShadeInput &usd_input,
bNode *dest_node,
const char *dest_socket_name,
@@ -118,8 +124,18 @@ class USDMaterialReader {
int column,
NodePlacementContext *r_ctx) const;
+ /**
+ * Load the texture image node's texture from the path given by the USD shader's
+ * file input value.
+ */
void load_tex_image(const pxr::UsdShadeShader &usd_shader, bNode *tex_image) const;
+ /**
+ * This function creates a Blender UV Map node, under the simplifying assumption that
+ * UsdPrimvarReader_float2 shaders output UV coordinates.
+ * TODO(makowalski): investigate supporting conversion to other Blender node types
+ * (e.g., Attribute Nodes) if needed.
+ */
void convert_usd_primvar_reader_float2(const pxr::UsdShadeShader &usd_shader,
const pxr::TfToken &usd_source_name,
bNode *dest_node,
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 9c75bc8afae..95b73c85da6 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -30,6 +30,8 @@
#include "BLI_math.h"
#include "BLI_math_geom.h"
+#include "BLI_math_vec_types.hh"
+#include "BLI_span.hh"
#include "BLI_string.h"
#include "DNA_customdata_types.h"
@@ -390,8 +392,9 @@ void USDMeshReader::read_uvs(Mesh *mesh, const double motionSampleTime, const bo
const UVSample &sample = uv_primvars[layer_idx];
- if (!(sample.interpolation == pxr::UsdGeomTokens->faceVarying ||
- sample.interpolation == pxr::UsdGeomTokens->vertex)) {
+ if (!(ELEM(sample.interpolation,
+ pxr::UsdGeomTokens->faceVarying,
+ pxr::UsdGeomTokens->vertex))) {
std::cerr << "WARNING: unexpected interpolation type " << sample.interpolation
<< " for uv " << layer->name << std::endl;
continue;
@@ -519,6 +522,38 @@ void USDMeshReader::read_colors(Mesh *mesh, const double motionSampleTime)
}
}
+void USDMeshReader::read_vertex_creases(Mesh *mesh, const double motionSampleTime)
+{
+ pxr::VtIntArray corner_indices;
+ if (!mesh_prim_.GetCornerIndicesAttr().Get(&corner_indices, motionSampleTime)) {
+ return;
+ }
+
+ pxr::VtIntArray corner_sharpnesses;
+ if (!mesh_prim_.GetCornerSharpnessesAttr().Get(&corner_sharpnesses, motionSampleTime)) {
+ return;
+ }
+
+ /* It is fine to have fewer indices than vertices, but never the other way other. */
+ if (corner_indices.size() > mesh->totvert) {
+ std::cerr << "WARNING: too many vertex crease for mesh " << prim_path_ << std::endl;
+ return;
+ }
+
+ if (corner_indices.size() != corner_sharpnesses.size()) {
+ std::cerr << "WARNING: vertex crease indices and sharpnesses count mismatch for mesh "
+ << prim_path_ << std::endl;
+ return;
+ }
+
+ float *creases = static_cast<float *>(
+ CustomData_add_layer(&mesh->vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh->totvert));
+
+ for (size_t i = 0; i < corner_indices.size(); i++) {
+ creases[corner_indices[i]] = corner_sharpnesses[i];
+ }
+}
+
void USDMeshReader::process_normals_vertex_varying(Mesh *mesh)
{
if (!mesh) {
@@ -526,34 +561,32 @@ void USDMeshReader::process_normals_vertex_varying(Mesh *mesh)
}
if (normals_.empty()) {
- BKE_mesh_calc_normals(mesh);
return;
}
if (normals_.size() != mesh->totvert) {
std::cerr << "WARNING: vertex varying normals count mismatch for mesh " << prim_path_
<< std::endl;
- BKE_mesh_calc_normals(mesh);
return;
}
- for (int i = 0; i < normals_.size(); i++) {
- MVert &mvert = mesh->mvert[i];
- normal_float_to_short_v3(mvert.no, normals_[i].data());
- }
+ MutableSpan vert_normals{(float3 *)BKE_mesh_vertex_normals_for_write(mesh), mesh->totvert};
+ BLI_STATIC_ASSERT(sizeof(normals_[0]) == sizeof(float3), "Expected float3 normals size");
+ vert_normals.copy_from({(float3 *)normals_.data(), static_cast<int64_t>(normals_.size())});
+ BKE_mesh_vertex_normals_clear_dirty(mesh);
}
void USDMeshReader::process_normals_face_varying(Mesh *mesh)
{
if (normals_.empty()) {
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
return;
}
/* Check for normals count mismatches to prevent crashes. */
if (normals_.size() != mesh->totloop) {
std::cerr << "WARNING: loop normal count mismatch for mesh " << mesh->id.name << std::endl;
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
return;
}
@@ -588,18 +621,17 @@ void USDMeshReader::process_normals_face_varying(Mesh *mesh)
MEM_freeN(lnors);
}
-/* Set USD uniform (per-face) normals as Blender loop normals. */
void USDMeshReader::process_normals_uniform(Mesh *mesh)
{
if (normals_.empty()) {
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
return;
}
/* Check for normals count mismatches to prevent crashes. */
if (normals_.size() != mesh->totpoly) {
std::cerr << "WARNING: uniform normal count mismatch for mesh " << mesh->id.name << std::endl;
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
return;
}
@@ -640,6 +672,8 @@ void USDMeshReader::read_mesh_sample(ImportSettings *settings,
mvert.co[1] = positions_[i][1];
mvert.co[2] = positions_[i][2];
}
+
+ read_vertex_creases(mesh, motionSampleTime);
}
if (new_mesh || (settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
@@ -652,14 +686,11 @@ void USDMeshReader::read_mesh_sample(ImportSettings *settings,
}
else {
/* Default */
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
}
}
- /* Process point normals after reading polys. This
- * is important in the case where the normals are empty
- * and we invoke BKE_mesh_calc_normals(mesh), which requires
- * edges to be defined. */
+ /* Process point normals after reading polys. */
if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0 &&
normal_interpolation_ == pxr::UsdGeomTokens->vertex) {
process_normals_vertex_varying(mesh);
@@ -781,9 +812,10 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
bool is_uv = false;
/* Assume all UVs are stored in one of these primvar types */
- if (type == pxr::SdfValueTypeNames->TexCoord2hArray ||
- type == pxr::SdfValueTypeNames->TexCoord2fArray ||
- type == pxr::SdfValueTypeNames->TexCoord2dArray) {
+ if (ELEM(type,
+ pxr::SdfValueTypeNames->TexCoord2hArray,
+ pxr::SdfValueTypeNames->TexCoord2fArray,
+ pxr::SdfValueTypeNames->TexCoord2dArray)) {
is_uv = true;
}
/* In some cases, the st primvar is stored as float2 values. */
@@ -795,7 +827,7 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
pxr::TfToken interp = p.GetInterpolation();
- if (!(interp == pxr::UsdGeomTokens->faceVarying || interp == pxr::UsdGeomTokens->vertex)) {
+ if (!(ELEM(interp, pxr::UsdGeomTokens->faceVarying, pxr::UsdGeomTokens->vertex))) {
continue;
}
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h
index 54ad144d191..c5869fcbd32 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.h
+++ b/source/blender/io/usd/intern/usd_reader_mesh.h
@@ -75,6 +75,7 @@ class USDMeshReader : public USDGeomReader {
private:
void process_normals_vertex_varying(Mesh *mesh);
void process_normals_face_varying(Mesh *mesh);
+ /** Set USD uniform (per-face) normals as Blender loop normals. */
void process_normals_uniform(Mesh *mesh);
void readFaceSetsSample(Main *bmain, Mesh *mesh, double motionSampleTime);
void assign_facesets_to_mpoly(double motionSampleTime,
@@ -85,6 +86,7 @@ class USDMeshReader : public USDGeomReader {
void read_mpolys(Mesh *mesh);
void read_uvs(Mesh *mesh, double motionSampleTime, bool load_uvs = false);
void read_colors(Mesh *mesh, double motionSampleTime);
+ void read_vertex_creases(Mesh *mesh, double motionSampleTime);
void read_mesh_sample(ImportSettings *settings,
Mesh *mesh,
diff --git a/source/blender/io/usd/intern/usd_reader_nurbs.cc b/source/blender/io/usd/intern/usd_reader_nurbs.cc
index d6977d9c91a..8370804b776 100644
--- a/source/blender/io/usd/intern/usd_reader_nurbs.cc
+++ b/source/blender/io/usd/intern/usd_reader_nurbs.cc
@@ -112,11 +112,11 @@ void USDNurbsReader::read_curve_sample(Curve *cu, const double motionSampleTime)
* Perhaps to be replaced by Blender USD Schema. */
if (!usdNormals.empty()) {
/* Set extrusion to 1. */
- curve_->ext1 = 1.0f;
+ curve_->extrude = 1.0f;
}
else {
/* Set bevel depth to 1. */
- curve_->ext2 = 1.0f;
+ curve_->bevel_radius = 1.0f;
}
size_t idx = 0;
diff --git a/source/blender/io/usd/intern/usd_reader_stage.cc b/source/blender/io/usd/intern/usd_reader_stage.cc
index 8c4cc18a9af..9df5611bec9 100644
--- a/source/blender/io/usd/intern/usd_reader_stage.cc
+++ b/source/blender/io/usd/intern/usd_reader_stage.cc
@@ -110,11 +110,6 @@ USDPrimReader *USDStageReader::create_reader(const pxr::UsdPrim &prim)
return nullptr;
}
-/* Returns true if the given prim should be included in the
- * traversal based on the import options and the prim's visibility
- * attribute. Note that the prim will be trivially included
- * if it has no visibility attribute or if the visibility
- * is inherited. */
bool USDStageReader::include_by_visibility(const pxr::UsdGeomImageable &imageable) const
{
if (!params_.import_visible_only) {
@@ -140,11 +135,6 @@ bool USDStageReader::include_by_visibility(const pxr::UsdGeomImageable &imageabl
return visibility != pxr::UsdGeomTokens->invisible;
}
-/* Returns true if the given prim should be included in the
- * traversal based on the import options and the prim's purpose
- * attribute. E.g., return false (to exclude the prim) if the prim
- * represents guide geometry and the 'Import Guide' option is
- * toggled off. */
bool USDStageReader::include_by_purpose(const pxr::UsdGeomImageable &imageable) const
{
if (params_.import_guide && params_.import_proxy && params_.import_render) {
diff --git a/source/blender/io/usd/intern/usd_reader_stage.h b/source/blender/io/usd/intern/usd_reader_stage.h
index ba223962c0c..df5f83067c1 100644
--- a/source/blender/io/usd/intern/usd_reader_stage.h
+++ b/source/blender/io/usd/intern/usd_reader_stage.h
@@ -82,8 +82,22 @@ class USDStageReader {
private:
USDPrimReader *collect_readers(Main *bmain, const pxr::UsdPrim &prim);
+ /**
+ * Returns true if the given prim should be included in the
+ * traversal based on the import options and the prim's visibility
+ * attribute. Note that the prim will be trivially included
+ * if it has no visibility attribute or if the visibility
+ * is inherited.
+ */
bool include_by_visibility(const pxr::UsdGeomImageable &imageable) const;
+ /**
+ * Returns true if the given prim should be included in the
+ * traversal based on the import options and the prim's purpose
+ * attribute. E.g., return false (to exclude the prim) if the prim
+ * represents guide geometry and the 'Import Guide' option is
+ * toggled off.
+ */
bool include_by_purpose(const pxr::UsdGeomImageable &imageable) const;
};
diff --git a/source/blender/io/usd/intern/usd_reader_xform.h b/source/blender/io/usd/intern/usd_reader_xform.h
index 587ac373a4f..7720a054772 100644
--- a/source/blender/io/usd/intern/usd_reader_xform.h
+++ b/source/blender/io/usd/intern/usd_reader_xform.h
@@ -46,7 +46,7 @@ class USDXformReader : public USDPrimReader {
void create_object(Main *bmain, double motionSampleTime) override;
void read_object_data(Main *bmain, double motionSampleTime) override;
- void read_matrix(float r_mat[4][4], const float time, const float scale, bool *r_is_constant);
+ void read_matrix(float r_mat[4][4], float time, float scale, bool *r_is_constant);
bool use_parent_xform() const
{
diff --git a/source/blender/io/usd/intern/usd_writer_abstract.cc b/source/blender/io/usd/intern/usd_writer_abstract.cc
index 6965ecf6249..2b5326eb4c1 100644
--- a/source/blender/io/usd/intern/usd_writer_abstract.cc
+++ b/source/blender/io/usd/intern/usd_writer_abstract.cc
@@ -121,7 +121,6 @@ void USDAbstractWriter::write_visibility(const HierarchyContext &context,
usd_value_writer_.SetAttribute(attr_visibility, pxr::VtValue(visibility), timecode);
}
-/* Reference the original data instead of writing a copy. */
bool USDAbstractWriter::mark_as_instance(const HierarchyContext &context, const pxr::UsdPrim &prim)
{
BLI_assert(context.is_instance());
@@ -134,7 +133,7 @@ bool USDAbstractWriter::mark_as_instance(const HierarchyContext &context, const
pxr::SdfPath ref_path(context.original_export_path);
if (!prim.GetReferences().AddInternalReference(ref_path)) {
- /* See this URL for a description fo why referencing may fail"
+ /* See this URL for a description for why referencing may fail"
* https://graphics.pixar.com/usd/docs/api/class_usd_references.html#Usd_Failing_References
*/
printf("USD Export warning: unable to add reference from %s to %s, not instancing object\n",
diff --git a/source/blender/io/usd/intern/usd_writer_abstract.h b/source/blender/io/usd/intern/usd_writer_abstract.h
index 6f143a7e241..dd81dd47c83 100644
--- a/source/blender/io/usd/intern/usd_writer_abstract.h
+++ b/source/blender/io/usd/intern/usd_writer_abstract.h
@@ -52,13 +52,15 @@ class USDAbstractWriter : public AbstractHierarchyWriter {
virtual void write(HierarchyContext &context) override;
- /* Returns true if the data to be written is actually supported. This would, for example, allow a
+ /**
+ * Returns true if the data to be written is actually supported. This would, for example, allow a
* hypothetical camera writer accept a perspective camera but reject an orthogonal one.
*
* Returning false from a transform writer will prevent the object and all its descendants from
* being exported. Returning false from a data writer (object data, hair, or particles) will
* only prevent that data from being written (and thus cause the object to be exported as an
- * Empty). */
+ * Empty).
+ */
virtual bool is_supported(const HierarchyContext *context) const;
const pxr::SdfPath &usd_path() const;
@@ -73,8 +75,12 @@ class USDAbstractWriter : public AbstractHierarchyWriter {
const pxr::UsdTimeCode timecode,
pxr::UsdGeomImageable &usd_geometry);
- /* Turn `prim` into an instance referencing `context.original_export_path`.
- * Return true when the instancing was successful, false otherwise. */
+ /**
+ * Turn `prim` into an instance referencing `context.original_export_path`.
+ * Return true when the instancing was successful, false otherwise.
+ *
+ * Reference the original data instead of writing a copy.
+ */
virtual bool mark_as_instance(const HierarchyContext &context, const pxr::UsdPrim &prim);
};
diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc
index 61b14155dd0..b061a2ff795 100644
--- a/source/blender/io/usd/intern/usd_writer_mesh.cc
+++ b/source/blender/io/usd/intern/usd_writer_mesh.cc
@@ -110,6 +110,12 @@ struct USDMeshData {
* single sharpness or a value per-edge, USD will encode either a single sharpness per crease on
* a mesh, or sharpness's for all edges making up the creases on a mesh. */
pxr::VtFloatArray crease_sharpnesses;
+
+ /* The lengths of this array specifies the number of sharp corners (or vertex crease) on the
+ * surface. Each value is the index of a vertex in the mesh's vertex list. */
+ pxr::VtIntArray corner_indices;
+ /* The per-vertex sharpnesses. The lengths of this array must match that of `corner_indices`. */
+ pxr::VtFloatArray corner_sharpnesses;
};
void USDGenericMeshWriter::write_uv_maps(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh)
@@ -214,6 +220,23 @@ void USDGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
attr_crease_sharpness, pxr::VtValue(usd_mesh_data.crease_sharpnesses), timecode);
}
+ if (!usd_mesh_data.corner_indices.empty() &&
+ usd_mesh_data.corner_indices.size() == usd_mesh_data.corner_sharpnesses.size()) {
+ pxr::UsdAttribute attr_corner_indices = usd_mesh.CreateCornerIndicesAttr(pxr::VtValue(), true);
+ pxr::UsdAttribute attr_corner_sharpnesses = usd_mesh.CreateCornerSharpnessesAttr(
+ pxr::VtValue(), true);
+
+ if (!attr_corner_indices.HasValue()) {
+ attr_corner_indices.Set(usd_mesh_data.corner_indices, defaultTime);
+ attr_corner_sharpnesses.Set(usd_mesh_data.corner_sharpnesses, defaultTime);
+ }
+
+ usd_value_writer_.SetAttribute(
+ attr_corner_indices, pxr::VtValue(usd_mesh_data.corner_indices), timecode);
+ usd_value_writer_.SetAttribute(
+ attr_corner_sharpnesses, pxr::VtValue(usd_mesh_data.crease_sharpnesses), timecode);
+ }
+
if (usd_export_context_.export_params.export_uvmaps) {
write_uv_maps(mesh, usd_mesh);
}
@@ -268,7 +291,7 @@ static void get_loops_polys(const Mesh *mesh, USDMeshData &usd_mesh_data)
}
}
-static void get_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
+static void get_edge_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
{
const float factor = 1.0f / 255.0f;
@@ -293,11 +316,30 @@ static void get_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
}
}
+static void get_vert_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
+{
+ const float *creases = static_cast<const float *>(CustomData_get_layer(&mesh->vdata, CD_CREASE));
+
+ if (!creases) {
+ return;
+ }
+
+ for (int i = 0, v = mesh->totvert; i < v; i++) {
+ const float sharpness = creases[i];
+
+ if (sharpness != 0.0f) {
+ usd_mesh_data.corner_indices.push_back(i);
+ usd_mesh_data.corner_sharpnesses.push_back(sharpness);
+ }
+ }
+}
+
void USDGenericMeshWriter::get_geometry_data(const Mesh *mesh, USDMeshData &usd_mesh_data)
{
get_vertices(mesh, usd_mesh_data);
get_loops_polys(mesh, usd_mesh_data);
- get_creases(mesh, usd_mesh_data);
+ get_edge_creases(mesh, usd_mesh_data);
+ get_vert_creases(mesh, usd_mesh_data);
}
void USDGenericMeshWriter::assign_materials(const HierarchyContext &context,
@@ -378,16 +420,15 @@ void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_
}
else {
/* Compute the loop normals based on the 'smooth' flag. */
- float normal[3];
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ const float(*face_normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
MPoly *mpoly = mesh->mpoly;
- const MVert *mvert = mesh->mvert;
for (int poly_idx = 0, totpoly = mesh->totpoly; poly_idx < totpoly; ++poly_idx, ++mpoly) {
MLoop *mloop = mesh->mloop + mpoly->loopstart;
if ((mpoly->flag & ME_SMOOTH) == 0) {
/* Flat shaded, use common normal for all verts. */
- BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, normal);
- pxr::GfVec3f pxr_normal(normal);
+ pxr::GfVec3f pxr_normal(face_normals[poly_idx]);
for (int loop_idx = 0; loop_idx < mpoly->totloop; ++loop_idx) {
loop_normals.push_back(pxr_normal);
}
@@ -395,8 +436,7 @@ void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_
else {
/* Smooth shaded, use individual vert normals. */
for (int loop_idx = 0; loop_idx < mpoly->totloop; ++loop_idx, ++mloop) {
- normal_short_to_float_v3(normal, mvert[mloop->v].no);
- loop_normals.push_back(pxr::GfVec3f(normal));
+ loop_normals.push_back(pxr::GfVec3f(vert_normals[mloop->v]));
}
}
}
diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h
index 2a036c3d398..16bd826ecdd 100644
--- a/source/blender/io/usd/usd.h
+++ b/source/blender/io/usd/usd.h
@@ -106,14 +106,14 @@ void USD_get_transform(struct CacheReader *reader, float r_mat[4][4], float time
struct Mesh *USD_read_mesh(struct CacheReader *reader,
struct Object *ob,
struct Mesh *existing_mesh,
- const float time,
+ float time,
const char **err_str,
int read_flag);
bool USD_mesh_topology_changed(struct CacheReader *reader,
struct Object *ob,
struct Mesh *existing_mesh,
- const float time,
+ float time,
const char **err_str);
struct CacheReader *CacheReader_open_usd_object(struct CacheArchiveHandle *handle,
diff --git a/source/blender/io/wavefront_obj/CMakeLists.txt b/source/blender/io/wavefront_obj/CMakeLists.txt
new file mode 100644
index 00000000000..296dd70b5a2
--- /dev/null
+++ b/source/blender/io/wavefront_obj/CMakeLists.txt
@@ -0,0 +1,84 @@
+# ***** 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
+ .
+ ./exporter
+ ../../blenkernel
+ ../../blenlib
+ ../../bmesh
+ ../../bmesh/intern
+ ../../depsgraph
+ ../../editors/include
+ ../../makesdna
+ ../../makesrna
+ ../../nodes
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ IO_wavefront_obj.cc
+ exporter/obj_export_file_writer.cc
+ exporter/obj_export_mesh.cc
+ exporter/obj_export_mtl.cc
+ exporter/obj_export_nurbs.cc
+ exporter/obj_exporter.cc
+
+ IO_wavefront_obj.h
+ exporter/obj_export_file_writer.hh
+ exporter/obj_export_io.hh
+ exporter/obj_export_mesh.hh
+ exporter/obj_export_mtl.hh
+ exporter/obj_export_nurbs.hh
+ exporter/obj_exporter.hh
+)
+
+set(LIB
+ bf_blenkernel
+)
+
+blender_add_lib(bf_wavefront_obj "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_GTESTS)
+ set(TEST_SRC
+ tests/obj_exporter_tests.cc
+ tests/obj_exporter_tests.hh
+ )
+
+ set(TEST_INC
+ ${INC}
+
+ ../../blenloader
+ ../../../../tests/gtests
+ )
+
+ set(TEST_LIB
+ ${LIB}
+
+ bf_blenloader_tests
+ bf_wavefront_obj
+ )
+
+ include(GTestTesting)
+ blender_add_test_lib(bf_wavefront_obj_tests "${TEST_SRC}" "${TEST_INC}" "${INC_SYS}" "${TEST_LIB}")
+ add_dependencies(bf_wavefront_obj_tests bf_wavefront_obj)
+endif()
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.cc b/source/blender/io/wavefront_obj/IO_wavefront_obj.cc
new file mode 100644
index 00000000000..1c93eafe91a
--- /dev/null
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.cc
@@ -0,0 +1,34 @@
+/*
+ * 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 obj
+ */
+
+#include "BLI_timeit.hh"
+
+#include "IO_wavefront_obj.h"
+
+#include "obj_exporter.hh"
+
+/**
+ * C-interface for the exporter.
+ */
+void OBJ_export(bContext *C, const OBJExportParams *export_params)
+{
+ SCOPED_TIMER("OBJ export");
+ blender::io::obj::exporter_main(C, *export_params);
+}
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
new file mode 100644
index 00000000000..684eb3eda41
--- /dev/null
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -0,0 +1,97 @@
+/*
+ * 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 obj
+ */
+
+#pragma once
+
+#include "BKE_context.h"
+#include "BLI_path_util.h"
+#include "DEG_depsgraph.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ OBJ_AXIS_X_UP = 0,
+ OBJ_AXIS_Y_UP = 1,
+ OBJ_AXIS_Z_UP = 2,
+ OBJ_AXIS_NEGATIVE_X_UP = 3,
+ OBJ_AXIS_NEGATIVE_Y_UP = 4,
+ OBJ_AXIS_NEGATIVE_Z_UP = 5,
+} eTransformAxisUp;
+
+typedef enum {
+ OBJ_AXIS_X_FORWARD = 0,
+ OBJ_AXIS_Y_FORWARD = 1,
+ OBJ_AXIS_Z_FORWARD = 2,
+ OBJ_AXIS_NEGATIVE_X_FORWARD = 3,
+ OBJ_AXIS_NEGATIVE_Y_FORWARD = 4,
+ OBJ_AXIS_NEGATIVE_Z_FORWARD = 5,
+} eTransformAxisForward;
+
+static const int TOTAL_AXES = 3;
+
+struct OBJExportParams {
+ /** Full path to the destination .OBJ file. */
+ char filepath[FILE_MAX];
+
+ /** Full path to current blender file (used for comments in output). */
+ const char *blen_filepath;
+
+ /** Whether multiple frames should be exported. */
+ bool export_animation;
+ /** The first frame to be exported. */
+ int start_frame;
+ /** The last frame to be exported. */
+ int end_frame;
+
+ /* Geometry Transform options. */
+ eTransformAxisForward forward_axis;
+ eTransformAxisUp up_axis;
+ float scaling_factor;
+
+ /* File Write Options. */
+ bool export_selected_objects;
+ eEvaluationMode export_eval_mode;
+ bool export_uv;
+ bool export_normals;
+ bool export_materials;
+ bool export_triangulated_mesh;
+ bool export_curves_as_nurbs;
+
+ /* Grouping options. */
+ bool export_object_groups;
+ bool export_material_groups;
+ bool export_vertex_groups;
+ /**
+ * Calculate smooth groups from sharp edges.
+ */
+ bool export_smooth_groups;
+ /**
+ * Create bitflags instead of the default "0"/"1" group IDs.
+ */
+ bool smooth_groups_bitflags;
+};
+
+void OBJ_export(bContext *C, const struct OBJExportParams *export_params);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
new file mode 100644
index 00000000000..d31353c4a76
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
@@ -0,0 +1,521 @@
+/*
+ * 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 obj
+ */
+
+#include <algorithm>
+#include <cstdio>
+
+#include "BKE_blender_version.h"
+
+#include "BLI_path_util.h"
+
+#include "obj_export_mesh.hh"
+#include "obj_export_mtl.hh"
+#include "obj_export_nurbs.hh"
+
+#include "obj_export_file_writer.hh"
+
+namespace blender::io::obj {
+/**
+ * Per reference http://www.martinreddy.net/gfx/3d/OBJ.spec:
+ * To turn off smoothing groups, use a value of 0 or off.
+ * Polygonal elements use group numbers to put elements in different smoothing groups.
+ * For free-form surfaces, smoothing groups are either turned on or off;
+ * there is no difference between values greater than 0.
+ */
+const int SMOOTH_GROUP_DISABLED = 0;
+const int SMOOTH_GROUP_DEFAULT = 1;
+
+const char *DEFORM_GROUP_DISABLED = "off";
+/* There is no deform group default name. Use what the user set in the UI. */
+
+/**
+ * Per reference http://www.martinreddy.net/gfx/3d/OBJ.spec:
+ * Once a material is assigned, it cannot be turned off; it can only be changed.
+ * If a material name is not specified, a white material is used.
+ * So an empty material name is written. */
+const char *MATERIAL_GROUP_DISABLED = "";
+
+void OBJWriter::write_vert_uv_normal_indices(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> normal_indices) const
+{
+ BLI_assert(vert_indices.size() == uv_indices.size() &&
+ vert_indices.size() == normal_indices.size());
+ file_handler_->write<eOBJSyntaxElement::poly_element_begin>();
+ for (int j = 0; j < vert_indices.size(); j++) {
+ file_handler_->write<eOBJSyntaxElement::vertex_uv_normal_indices>(
+ vert_indices[j] + index_offsets_.vertex_offset + 1,
+ uv_indices[j] + index_offsets_.uv_vertex_offset + 1,
+ normal_indices[j] + index_offsets_.normal_offset + 1);
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_element_end>();
+}
+
+void OBJWriter::write_vert_normal_indices(Span<int> vert_indices,
+ Span<int> /*uv_indices*/,
+ Span<int> normal_indices) const
+{
+ BLI_assert(vert_indices.size() == normal_indices.size());
+ file_handler_->write<eOBJSyntaxElement::poly_element_begin>();
+ for (int j = 0; j < vert_indices.size(); j++) {
+ file_handler_->write<eOBJSyntaxElement::vertex_normal_indices>(
+ vert_indices[j] + index_offsets_.vertex_offset + 1,
+ normal_indices[j] + index_offsets_.normal_offset + 1);
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_element_end>();
+}
+
+void OBJWriter::write_vert_uv_indices(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> /*normal_indices*/) const
+{
+ BLI_assert(vert_indices.size() == uv_indices.size());
+ file_handler_->write<eOBJSyntaxElement::poly_element_begin>();
+ for (int j = 0; j < vert_indices.size(); j++) {
+ file_handler_->write<eOBJSyntaxElement::vertex_uv_indices>(
+ vert_indices[j] + index_offsets_.vertex_offset + 1,
+ uv_indices[j] + index_offsets_.uv_vertex_offset + 1);
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_element_end>();
+}
+
+void OBJWriter::write_vert_indices(Span<int> vert_indices,
+ Span<int> /*uv_indices*/,
+ Span<int> /*normal_indices*/) const
+{
+ file_handler_->write<eOBJSyntaxElement::poly_element_begin>();
+ for (const int vert_index : vert_indices) {
+ file_handler_->write<eOBJSyntaxElement::vertex_indices>(vert_index +
+ index_offsets_.vertex_offset + 1);
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_element_end>();
+}
+
+void OBJWriter::write_header() const
+{
+ using namespace std::string_literals;
+ file_handler_->write<eOBJSyntaxElement::string>("# Blender "s + BKE_blender_version_string() +
+ "\n");
+ file_handler_->write<eOBJSyntaxElement::string>("# www.blender.org\n");
+}
+
+void OBJWriter::write_mtllib_name(const StringRefNull mtl_filepath) const
+{
+ /* Split .MTL file path into parent directory and filename. */
+ char mtl_file_name[FILE_MAXFILE];
+ char mtl_dir_name[FILE_MAXDIR];
+ BLI_split_dirfile(mtl_filepath.data(), mtl_dir_name, mtl_file_name, FILE_MAXDIR, FILE_MAXFILE);
+ file_handler_->write<eOBJSyntaxElement::mtllib>(mtl_file_name);
+}
+
+void OBJWriter::write_object_group(const OBJMesh &obj_mesh_data) const
+{
+ /* "o object_name" is not mandatory. A valid .OBJ file may contain neither
+ * "o name" nor "g group_name". */
+ BLI_assert(export_params_.export_object_groups);
+ if (!export_params_.export_object_groups) {
+ return;
+ }
+ const std::string object_name = obj_mesh_data.get_object_name();
+ const char *object_mesh_name = obj_mesh_data.get_object_mesh_name();
+ const char *object_material_name = obj_mesh_data.get_object_material_name(0);
+ if (export_params_.export_materials && export_params_.export_material_groups &&
+ object_material_name) {
+ file_handler_->write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name +
+ "_" + object_material_name);
+ return;
+ }
+ file_handler_->write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name);
+}
+
+void OBJWriter::write_object_name(const OBJMesh &obj_mesh_data) const
+{
+ const char *object_name = obj_mesh_data.get_object_name();
+ if (export_params_.export_object_groups) {
+ write_object_group(obj_mesh_data);
+ return;
+ }
+ file_handler_->write<eOBJSyntaxElement::object_name>(object_name);
+}
+
+void OBJWriter::write_vertex_coords(const OBJMesh &obj_mesh_data) const
+{
+ const int tot_vertices = obj_mesh_data.tot_vertices();
+ for (int i = 0; i < tot_vertices; i++) {
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ file_handler_->write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
+ }
+}
+
+void OBJWriter::write_uv_coords(OBJMesh &r_obj_mesh_data) const
+{
+ Vector<std::array<float, 2>> uv_coords;
+ /* UV indices are calculated and stored in an OBJMesh member here. */
+ r_obj_mesh_data.store_uv_coords_and_indices(uv_coords);
+
+ for (const std::array<float, 2> &uv_vertex : uv_coords) {
+ file_handler_->write<eOBJSyntaxElement::uv_vertex_coords>(uv_vertex[0], uv_vertex[1]);
+ }
+}
+
+void OBJWriter::write_poly_normals(OBJMesh &obj_mesh_data)
+{
+ obj_mesh_data.ensure_mesh_normals();
+ Vector<float3> normals;
+ obj_mesh_data.store_normal_coords_and_indices(normals);
+ for (const float3 &normal : normals) {
+ file_handler_->write<eOBJSyntaxElement::normal>(normal[0], normal[1], normal[2]);
+ }
+}
+
+int OBJWriter::write_smooth_group(const OBJMesh &obj_mesh_data,
+ const int poly_index,
+ const int last_poly_smooth_group) const
+{
+ int current_group = SMOOTH_GROUP_DISABLED;
+ if (!export_params_.export_smooth_groups && obj_mesh_data.is_ith_poly_smooth(poly_index)) {
+ /* Smooth group calculation is disabled, but polygon is smooth-shaded. */
+ current_group = SMOOTH_GROUP_DEFAULT;
+ }
+ else if (obj_mesh_data.is_ith_poly_smooth(poly_index)) {
+ /* Smooth group calc is enabled and polygon is smooth–shaded, so find the group. */
+ current_group = obj_mesh_data.ith_smooth_group(poly_index);
+ }
+
+ if (current_group == last_poly_smooth_group) {
+ /* Group has already been written, even if it is "s 0". */
+ return current_group;
+ }
+ file_handler_->write<eOBJSyntaxElement::smooth_group>(current_group);
+ return current_group;
+}
+
+int16_t OBJWriter::write_poly_material(const OBJMesh &obj_mesh_data,
+ const int poly_index,
+ const int16_t last_poly_mat_nr,
+ std::function<const char *(int)> matname_fn) const
+{
+ if (!export_params_.export_materials || obj_mesh_data.tot_materials() <= 0) {
+ return last_poly_mat_nr;
+ }
+ const int16_t current_mat_nr = obj_mesh_data.ith_poly_matnr(poly_index);
+ /* Whenever a polygon with a new material is encountered, write its material
+ * and/or group, otherwise pass. */
+ if (last_poly_mat_nr == current_mat_nr) {
+ return current_mat_nr;
+ }
+ if (current_mat_nr == NOT_FOUND) {
+ file_handler_->write<eOBJSyntaxElement::poly_usemtl>(MATERIAL_GROUP_DISABLED);
+ return current_mat_nr;
+ }
+ if (export_params_.export_object_groups) {
+ write_object_group(obj_mesh_data);
+ }
+ const char *mat_name = matname_fn(current_mat_nr);
+ if (!mat_name) {
+ mat_name = MATERIAL_GROUP_DISABLED;
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_usemtl>(mat_name);
+
+ return current_mat_nr;
+}
+
+int16_t OBJWriter::write_vertex_group(const OBJMesh &obj_mesh_data,
+ const int poly_index,
+ const int16_t last_poly_vertex_group) const
+{
+ if (!export_params_.export_vertex_groups) {
+ return last_poly_vertex_group;
+ }
+ const int16_t current_group = obj_mesh_data.get_poly_deform_group_index(poly_index);
+
+ if (current_group == last_poly_vertex_group) {
+ /* No vertex group found in this polygon, just like in the last iteration. */
+ return current_group;
+ }
+ if (current_group == NOT_FOUND) {
+ file_handler_->write<eOBJSyntaxElement::object_group>(DEFORM_GROUP_DISABLED);
+ return current_group;
+ }
+ file_handler_->write<eOBJSyntaxElement::object_group>(
+ obj_mesh_data.get_poly_deform_group_name(current_group));
+ return current_group;
+}
+
+OBJWriter::func_vert_uv_normal_indices OBJWriter::get_poly_element_writer(
+ const int total_uv_vertices) const
+{
+ if (export_params_.export_normals) {
+ if (export_params_.export_uv && (total_uv_vertices > 0)) {
+ /* Write both normals and UV indices. */
+ return &OBJWriter::write_vert_uv_normal_indices;
+ }
+ /* Write normals indices. */
+ return &OBJWriter::write_vert_normal_indices;
+ }
+ /* Write UV indices. */
+ if (export_params_.export_uv && (total_uv_vertices > 0)) {
+ return &OBJWriter::write_vert_uv_indices;
+ }
+ /* Write neither normals nor UV indices. */
+ return &OBJWriter::write_vert_indices;
+}
+
+void OBJWriter::write_poly_elements(const OBJMesh &obj_mesh_data,
+ std::function<const char *(int)> matname_fn)
+{
+ int last_poly_smooth_group = NEGATIVE_INIT;
+ int16_t last_poly_vertex_group = NEGATIVE_INIT;
+ int16_t last_poly_mat_nr = NEGATIVE_INIT;
+
+ const func_vert_uv_normal_indices poly_element_writer = get_poly_element_writer(
+ obj_mesh_data.tot_uv_vertices());
+
+ const int tot_polygons = obj_mesh_data.tot_polygons();
+ for (int i = 0; i < tot_polygons; i++) {
+ Vector<int> poly_vertex_indices = obj_mesh_data.calc_poly_vertex_indices(i);
+ Span<int> poly_uv_indices = obj_mesh_data.calc_poly_uv_indices(i);
+ Vector<int> poly_normal_indices = obj_mesh_data.calc_poly_normal_indices(i);
+
+ last_poly_smooth_group = write_smooth_group(obj_mesh_data, i, last_poly_smooth_group);
+ last_poly_vertex_group = write_vertex_group(obj_mesh_data, i, last_poly_vertex_group);
+ last_poly_mat_nr = write_poly_material(obj_mesh_data, i, last_poly_mat_nr, matname_fn);
+ (this->*poly_element_writer)(poly_vertex_indices, poly_uv_indices, poly_normal_indices);
+ }
+}
+
+void OBJWriter::write_edges_indices(const OBJMesh &obj_mesh_data) const
+{
+ obj_mesh_data.ensure_mesh_edges();
+ const int tot_edges = obj_mesh_data.tot_edges();
+ for (int edge_index = 0; edge_index < tot_edges; edge_index++) {
+ const std::optional<std::array<int, 2>> vertex_indices =
+ obj_mesh_data.calc_loose_edge_vert_indices(edge_index);
+ if (!vertex_indices) {
+ continue;
+ }
+ file_handler_->write<eOBJSyntaxElement::edge>(
+ (*vertex_indices)[0] + index_offsets_.vertex_offset + 1,
+ (*vertex_indices)[1] + index_offsets_.vertex_offset + 1);
+ }
+}
+
+void OBJWriter::write_nurbs_curve(const OBJCurve &obj_nurbs_data) const
+{
+ const int total_splines = obj_nurbs_data.total_splines();
+ for (int spline_idx = 0; spline_idx < total_splines; spline_idx++) {
+ const int total_vertices = obj_nurbs_data.total_spline_vertices(spline_idx);
+ for (int vertex_idx = 0; vertex_idx < total_vertices; vertex_idx++) {
+ const float3 vertex_coords = obj_nurbs_data.vertex_coordinates(
+ spline_idx, vertex_idx, export_params_.scaling_factor);
+ file_handler_->write<eOBJSyntaxElement::vertex_coords>(
+ vertex_coords[0], vertex_coords[1], vertex_coords[2]);
+ }
+
+ const char *nurbs_name = obj_nurbs_data.get_curve_name();
+ const int nurbs_degree = obj_nurbs_data.get_nurbs_degree(spline_idx);
+ file_handler_->write<eOBJSyntaxElement::object_group>(nurbs_name);
+ file_handler_->write<eOBJSyntaxElement::cstype>();
+ file_handler_->write<eOBJSyntaxElement::nurbs_degree>(nurbs_degree);
+ /**
+ * The numbers written here are indices into the vertex coordinates written
+ * earlier, relative to the line that is going to be written.
+ * [0.0 - 1.0] is the curve parameter range.
+ * 0.0 1.0 -1 -2 -3 -4 for a non-cyclic curve with 4 vertices.
+ * 0.0 1.0 -1 -2 -3 -4 -1 -2 -3 for a cyclic curve with 4 vertices.
+ */
+ const int total_control_points = obj_nurbs_data.total_spline_control_points(spline_idx);
+ file_handler_->write<eOBJSyntaxElement::curve_element_begin>();
+ for (int i = 0; i < total_control_points; i++) {
+ /* "+1" to keep indices one-based, even if they're negative: i.e., -1 refers to the
+ * last vertex coordinate, -2 second last. */
+ file_handler_->write<eOBJSyntaxElement::vertex_indices>(-((i % total_vertices) + 1));
+ }
+ file_handler_->write<eOBJSyntaxElement::curve_element_end>();
+
+ /**
+ * In `parm u 0 0.1 ..` line:, (total control points + 2) equidistant numbers in the
+ * parameter range are inserted.
+ */
+ file_handler_->write<eOBJSyntaxElement::nurbs_parameter_begin>();
+ for (int i = 1; i <= total_control_points + 2; i++) {
+ file_handler_->write<eOBJSyntaxElement::nurbs_parameters>(1.0f * i /
+ (total_control_points + 2 + 1));
+ }
+ file_handler_->write<eOBJSyntaxElement::nurbs_parameter_end>();
+
+ file_handler_->write<eOBJSyntaxElement::nurbs_group_end>();
+ }
+}
+
+void OBJWriter::update_index_offsets(const OBJMesh &obj_mesh_data)
+{
+ index_offsets_.vertex_offset += obj_mesh_data.tot_vertices();
+ index_offsets_.uv_vertex_offset += obj_mesh_data.tot_uv_vertices();
+ index_offsets_.normal_offset += obj_mesh_data.tot_normal_indices();
+}
+
+/* -------------------------------------------------------------------- */
+/** \name .MTL writers.
+ * \{ */
+
+/**
+ * Convert #float3 to string of space-separated numbers, with no leading or trailing space.
+ * Only to be used in NON-performance-critical code.
+ */
+static std::string float3_to_string(const float3 &numbers)
+{
+ std::ostringstream r_string;
+ r_string << numbers[0] << " " << numbers[1] << " " << numbers[2];
+ return r_string.str();
+};
+
+MTLWriter::MTLWriter(const char *obj_filepath) noexcept(false)
+{
+ mtl_filepath_ = obj_filepath;
+ const bool ok = BLI_path_extension_replace(mtl_filepath_.data(), FILE_MAX, ".mtl");
+ if (!ok) {
+ throw std::system_error(ENAMETOOLONG, std::system_category(), "");
+ }
+ file_handler_ = std::make_unique<FormattedFileHandler<eFileType::MTL>>(mtl_filepath_);
+}
+
+void MTLWriter::write_header(const char *blen_filepath) const
+{
+ using namespace std::string_literals;
+ const char *blen_basename = (blen_filepath && blen_filepath[0] != '\0') ?
+ BLI_path_basename(blen_filepath) :
+ "None";
+ file_handler_->write<eMTLSyntaxElement::string>("# Blender "s + BKE_blender_version_string() +
+ " MTL File: '" + blen_basename + "'\n");
+ file_handler_->write<eMTLSyntaxElement::string>("# www.blender.org\n");
+}
+
+StringRefNull MTLWriter::mtl_file_path() const
+{
+ return mtl_filepath_;
+}
+
+void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl_material)
+{
+ file_handler_->write<eMTLSyntaxElement::Ns>(mtl_material.Ns);
+ file_handler_->write<eMTLSyntaxElement::Ka>(
+ mtl_material.Ka.x, mtl_material.Ka.y, mtl_material.Ka.z);
+ file_handler_->write<eMTLSyntaxElement::Kd>(
+ mtl_material.Kd.x, mtl_material.Kd.y, mtl_material.Kd.z);
+ file_handler_->write<eMTLSyntaxElement::Ks>(
+ mtl_material.Ks.x, mtl_material.Ks.y, mtl_material.Ks.z);
+ file_handler_->write<eMTLSyntaxElement::Ke>(
+ mtl_material.Ke.x, mtl_material.Ke.y, mtl_material.Ke.z);
+ file_handler_->write<eMTLSyntaxElement::Ni>(mtl_material.Ni);
+ file_handler_->write<eMTLSyntaxElement::d>(mtl_material.d);
+ file_handler_->write<eMTLSyntaxElement::illum>(mtl_material.illum);
+}
+
+void MTLWriter::write_texture_map(
+ const MTLMaterial &mtl_material,
+ const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map)
+{
+ std::string translation;
+ std::string scale;
+ std::string map_bump_strength;
+ /* Optional strings should have their own leading spaces. */
+ if (texture_map.value.translation != float3{0.0f, 0.0f, 0.0f}) {
+ translation.append(" -s ").append(float3_to_string(texture_map.value.translation));
+ }
+ if (texture_map.value.scale != float3{1.0f, 1.0f, 1.0f}) {
+ scale.append(" -o ").append(float3_to_string(texture_map.value.scale));
+ }
+ if (texture_map.key == eMTLSyntaxElement::map_Bump && mtl_material.map_Bump_strength > 0.0001f) {
+ map_bump_strength.append(" -bm ").append(std::to_string(mtl_material.map_Bump_strength));
+ }
+
+#define SYNTAX_DISPATCH(eMTLSyntaxElement) \
+ if (texture_map.key == eMTLSyntaxElement) { \
+ file_handler_->write<eMTLSyntaxElement>(translation + scale + map_bump_strength, \
+ texture_map.value.image_path); \
+ return; \
+ }
+
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Kd);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ks);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ns);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_d);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_refl);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ke);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Bump);
+
+ BLI_assert(!"This map type was not written to the file.");
+}
+
+void MTLWriter::write_materials()
+{
+ if (mtlmaterials_.size() == 0) {
+ return;
+ }
+ std::sort(mtlmaterials_.begin(),
+ mtlmaterials_.end(),
+ [](const MTLMaterial &a, const MTLMaterial &b) { return a.name < b.name; });
+ for (const MTLMaterial &mtlmat : mtlmaterials_) {
+ file_handler_->write<eMTLSyntaxElement::string>("\n");
+ file_handler_->write<eMTLSyntaxElement::newmtl>(mtlmat.name);
+ write_bsdf_properties(mtlmat);
+ for (const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map :
+ mtlmat.texture_maps.items()) {
+ if (!texture_map.value.image_path.empty()) {
+ write_texture_map(mtlmat, texture_map);
+ }
+ }
+ }
+}
+
+Vector<int> MTLWriter::add_materials(const OBJMesh &mesh_to_export)
+{
+ Vector<int> r_mtl_indices;
+ r_mtl_indices.resize(mesh_to_export.tot_materials());
+ for (int16_t i = 0; i < mesh_to_export.tot_materials(); i++) {
+ const Material *material = mesh_to_export.get_object_material(i);
+ if (!material) {
+ r_mtl_indices[i] = -1;
+ continue;
+ }
+ int mtlmat_index = material_map_.lookup_default(material, -1);
+ if (mtlmat_index != -1) {
+ r_mtl_indices[i] = mtlmat_index;
+ }
+ else {
+ mtlmaterials_.append(mtlmaterial_for_material(material));
+ r_mtl_indices[i] = mtlmaterials_.size() - 1;
+ material_map_.add_new(material, r_mtl_indices[i]);
+ }
+ }
+ return r_mtl_indices;
+}
+
+const char *MTLWriter::mtlmaterial_name(int index)
+{
+ if (index < 0 || index >= mtlmaterials_.size()) {
+ return nullptr;
+ }
+ return mtlmaterials_[index].name.c_str();
+}
+/** \} */
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
new file mode 100644
index 00000000000..7385d9fabe2
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
@@ -0,0 +1,217 @@
+/*
+ * 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 obj
+ */
+
+#pragma once
+
+#include "DNA_meshdata_types.h"
+
+#include "BLI_map.hh"
+#include "BLI_vector.hh"
+
+#include "IO_wavefront_obj.h"
+#include "obj_export_io.hh"
+#include "obj_export_mtl.hh"
+
+namespace blender::io::obj {
+
+class OBJCurve;
+class OBJMesh;
+/**
+ * Total vertices/ UV vertices/ normals of previous Objects
+ * should be added to the current Object's indices.
+ */
+struct IndexOffsets {
+ int vertex_offset;
+ int uv_vertex_offset;
+ int normal_offset;
+};
+
+/**
+ * Responsible for writing a .OBJ file.
+ */
+class OBJWriter : NonMovable, NonCopyable {
+ private:
+ const OBJExportParams &export_params_;
+ std::unique_ptr<FormattedFileHandler<eFileType::OBJ>> file_handler_ = nullptr;
+ IndexOffsets index_offsets_{0, 0, 0};
+
+ public:
+ OBJWriter(const char *filepath, const OBJExportParams &export_params) noexcept(false)
+ : export_params_(export_params)
+ {
+ file_handler_ = std::make_unique<FormattedFileHandler<eFileType::OBJ>>(filepath);
+ }
+
+ void write_header() const;
+
+ /**
+ * Write object's name or group.
+ */
+ void write_object_name(const OBJMesh &obj_mesh_data) const;
+ /**
+ * Write an object's group with mesh and/or material name appended conditionally.
+ */
+ void write_object_group(const OBJMesh &obj_mesh_data) const;
+ /**
+ * Write file name of Material Library in .OBJ file.
+ */
+ void write_mtllib_name(const StringRefNull mtl_filepath) const;
+ /**
+ * Write vertex coordinates for all vertices as "v x y z".
+ */
+ void write_vertex_coords(const OBJMesh &obj_mesh_data) const;
+ /**
+ * Write UV vertex coordinates for all vertices as `vt u v`.
+ * \note UV indices are stored here, but written with polygons later.
+ */
+ void write_uv_coords(OBJMesh &obj_mesh_data) const;
+ /**
+ * Write loop normals for smooth-shaded polygons, and polygon normals otherwise, as "vn x y z".
+ * \note Normal indices ares stored here, but written with polygons later.
+ */
+ void write_poly_normals(OBJMesh &obj_mesh_data);
+ /**
+ * Write smooth group if polygon at the given index is shaded smooth else "s 0"
+ */
+ int write_smooth_group(const OBJMesh &obj_mesh_data,
+ int poly_index,
+ int last_poly_smooth_group) const;
+ /**
+ * Write material name and material group of a polygon in the .OBJ file.
+ * \return #mat_nr of the polygon at the given index.
+ * \note It doesn't write to the material library.
+ */
+ int16_t write_poly_material(const OBJMesh &obj_mesh_data,
+ int poly_index,
+ int16_t last_poly_mat_nr,
+ std::function<const char *(int)> matname_fn) const;
+ /**
+ * Write the name of the deform group of a polygon.
+ */
+ int16_t write_vertex_group(const OBJMesh &obj_mesh_data,
+ int poly_index,
+ int16_t last_poly_vertex_group) const;
+ /**
+ * Write polygon elements with at least vertex indices, and conditionally with UV vertex
+ * indices and polygon normal indices. Also write groups: smooth, vertex, material.
+ * The matname_fn turns a 0-indexed material slot number in an Object into the
+ * name used in the .obj file.
+ * \note UV indices were stored while writing UV vertices.
+ */
+ void write_poly_elements(const OBJMesh &obj_mesh_data,
+ std::function<const char *(int)> matname_fn);
+ /**
+ * Write loose edges of a mesh as "l v1 v2".
+ */
+ void write_edges_indices(const OBJMesh &obj_mesh_data) const;
+ /**
+ * Write a NURBS curve to the .OBJ file in parameter form.
+ */
+ void write_nurbs_curve(const OBJCurve &obj_nurbs_data) const;
+
+ /**
+ * When there are multiple objects in a frame, the indices of previous objects' coordinates or
+ * normals add up.
+ */
+ void update_index_offsets(const OBJMesh &obj_mesh_data);
+
+ private:
+ using func_vert_uv_normal_indices = void (OBJWriter::*)(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> normal_indices) const;
+ /**
+ * \return Writer function with appropriate polygon-element syntax.
+ */
+ func_vert_uv_normal_indices get_poly_element_writer(int total_uv_vertices) const;
+
+ /**
+ * Write one line of polygon indices as "f v1/vt1/vn1 v2/vt2/vn2 ...".
+ */
+ void write_vert_uv_normal_indices(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> normal_indices) const;
+ /**
+ * Write one line of polygon indices as "f v1//vn1 v2//vn2 ...".
+ */
+ void write_vert_normal_indices(Span<int> vert_indices,
+ Span<int> /*uv_indices*/,
+ Span<int> normal_indices) const;
+ /**
+ * Write one line of polygon indices as "f v1/vt1 v2/vt2 ...".
+ */
+ void write_vert_uv_indices(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> /*normal_indices*/) const;
+ /**
+ * Write one line of polygon indices as "f v1 v2 ...".
+ */
+ void write_vert_indices(Span<int> vert_indices,
+ Span<int> /*uv_indices*/,
+ Span<int> /*normal_indices*/) const;
+};
+
+/**
+ * Responsible for writing a .MTL file.
+ */
+class MTLWriter : NonMovable, NonCopyable {
+ private:
+ std::unique_ptr<FormattedFileHandler<eFileType::MTL>> file_handler_ = nullptr;
+ std::string mtl_filepath_;
+ Vector<MTLMaterial> mtlmaterials_;
+ /* Map from a Material* to an index into mtlmaterials_. */
+ Map<const Material *, int> material_map_;
+
+ public:
+ /*
+ * Create the .MTL file.
+ */
+ MTLWriter(const char *obj_filepath) noexcept(false);
+
+ void write_header(const char *blen_filepath) const;
+ /**
+ * Write all of the material specifications to the MTL file.
+ * For consistency of output from run to run (useful for testing),
+ * the materials are sorted by name before writing.
+ */
+ void write_materials();
+ StringRefNull mtl_file_path() const;
+ /**
+ * Add the materials of the given object to #MTLWriter, de-duplicating
+ * against ones that are already there.
+ * Return a Vector of indices into mtlmaterials_ that hold the #MTLMaterial
+ * that corresponds to each material slot, in order, of the given Object.
+ * Indexes are returned rather than pointers to the MTLMaterials themselves
+ * because the mtlmaterials_ Vector may move around when resized.
+ */
+ Vector<int> add_materials(const OBJMesh &mesh_to_export);
+ const char *mtlmaterial_name(int index);
+
+ private:
+ /**
+ * Write properties sourced from p-BSDF node or #Object.Material.
+ */
+ void write_bsdf_properties(const MTLMaterial &mtl_material);
+ /**
+ * Write a texture map in the form "map_XX -s 1. 1. 1. -o 0. 0. 0. [-bm 1.] path/to/image".
+ */
+ void write_texture_map(const MTLMaterial &mtl_material,
+ const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map);
+};
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
new file mode 100644
index 00000000000..1bbefaee75f
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
@@ -0,0 +1,353 @@
+/*
+ * 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 obj
+ */
+
+#pragma once
+
+#include <cstdio>
+#include <string>
+#include <system_error>
+#include <type_traits>
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_fileops.h"
+#include "BLI_string_ref.hh"
+#include "BLI_utility_mixins.hh"
+
+namespace blender::io::obj {
+
+enum class eFileType {
+ OBJ,
+ MTL,
+};
+
+enum class eOBJSyntaxElement {
+ vertex_coords,
+ uv_vertex_coords,
+ normal,
+ poly_element_begin,
+ vertex_uv_normal_indices,
+ vertex_normal_indices,
+ vertex_uv_indices,
+ vertex_indices,
+ poly_element_end,
+ poly_usemtl,
+ edge,
+ cstype,
+ nurbs_degree,
+ curve_element_begin,
+ curve_element_end,
+ nurbs_parameter_begin,
+ nurbs_parameters,
+ nurbs_parameter_end,
+ nurbs_group_end,
+ new_line,
+ mtllib,
+ smooth_group,
+ object_group,
+ object_name,
+ /* Use rarely. New line is NOT included for string. */
+ string,
+};
+
+enum class eMTLSyntaxElement {
+ newmtl,
+ Ni,
+ d,
+ Ns,
+ illum,
+ Ka,
+ Kd,
+ Ks,
+ Ke,
+ map_Kd,
+ map_Ks,
+ map_Ns,
+ map_d,
+ map_refl,
+ map_Ke,
+ map_Bump,
+ /* Use rarely. New line is NOT included for string. */
+ string,
+};
+
+template<eFileType filetype> struct FileTypeTraits;
+
+/* Used to prevent mixing of say OBJ file format with MTL syntax elements. */
+template<> struct FileTypeTraits<eFileType::OBJ> {
+ using SyntaxType = eOBJSyntaxElement;
+};
+
+template<> struct FileTypeTraits<eFileType::MTL> {
+ using SyntaxType = eMTLSyntaxElement;
+};
+
+struct FormattingSyntax {
+ /* Formatting syntax with the file format key like `newmtl %s\n`. */
+ const char *fmt = nullptr;
+ /* Number of arguments needed by the syntax. */
+ const int total_args = 0;
+ /* Whether types of the given arguments are accepted by the syntax above. Fail to compile by
+ * default.
+ */
+ const bool are_types_valid = false;
+};
+
+/**
+ * Type dependent but always false. Use to add a `constexpr` conditional compile-time error.
+ */
+template<typename T> struct always_false : std::false_type {
+};
+
+template<typename... T>
+constexpr bool is_type_float = (... && std::is_floating_point_v<std::decay_t<T>>);
+
+template<typename... T>
+constexpr bool is_type_integral = (... && std::is_integral_v<std::decay_t<T>>);
+
+template<typename... T>
+constexpr bool is_type_string_related = (... && std::is_constructible_v<std::string, T>);
+
+template<typename... T>
+constexpr FormattingSyntax syntax_elem_to_formatting(const eOBJSyntaxElement key)
+{
+ switch (key) {
+ case eOBJSyntaxElement::vertex_coords: {
+ return {"v %f %f %f\n", 3, is_type_float<T...>};
+ }
+ case eOBJSyntaxElement::uv_vertex_coords: {
+ return {"vt %f %f\n", 2, is_type_float<T...>};
+ }
+ case eOBJSyntaxElement::normal: {
+ return {"vn %.4f %.4f %.4f\n", 3, is_type_float<T...>};
+ }
+ case eOBJSyntaxElement::poly_element_begin: {
+ return {"f", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::vertex_uv_normal_indices: {
+ return {" %d/%d/%d", 3, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::vertex_normal_indices: {
+ return {" %d//%d", 2, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::vertex_uv_indices: {
+ return {" %d/%d", 2, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::vertex_indices: {
+ return {" %d", 1, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::poly_usemtl: {
+ return {"usemtl %s\n", 1, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::edge: {
+ return {"l %d %d\n", 2, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::cstype: {
+ return {"cstype bspline\n", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_degree: {
+ return {"deg %d\n", 1, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::curve_element_begin: {
+ return {"curv 0.0 1.0", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_parameter_begin: {
+ return {"parm 0.0", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_parameters: {
+ return {" %f", 1, is_type_float<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_parameter_end: {
+ return {" 1.0\n", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_group_end: {
+ return {"end\n", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::poly_element_end: {
+ ATTR_FALLTHROUGH;
+ }
+ case eOBJSyntaxElement::curve_element_end: {
+ ATTR_FALLTHROUGH;
+ }
+ case eOBJSyntaxElement::new_line: {
+ return {"\n", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::mtllib: {
+ return {"mtllib %s\n", 1, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::smooth_group: {
+ return {"s %d\n", 1, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::object_group: {
+ return {"g %s\n", 1, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::object_name: {
+ return {"o %s\n", 1, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::string: {
+ return {"%s", 1, is_type_string_related<T...>};
+ }
+ }
+}
+
+template<typename... T>
+constexpr FormattingSyntax syntax_elem_to_formatting(const eMTLSyntaxElement key)
+{
+ switch (key) {
+ case eMTLSyntaxElement::newmtl: {
+ return {"newmtl %s\n", 1, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::Ni: {
+ return {"Ni %.6f\n", 1, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::d: {
+ return {"d %.6f\n", 1, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::Ns: {
+ return {"Ns %.6f\n", 1, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::illum: {
+ return {"illum %d\n", 1, is_type_integral<T...>};
+ }
+ case eMTLSyntaxElement::Ka: {
+ return {"Ka %.6f %.6f %.6f\n", 3, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::Kd: {
+ return {"Kd %.6f %.6f %.6f\n", 3, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::Ks: {
+ return {"Ks %.6f %.6f %.6f\n", 3, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::Ke: {
+ return {"Ke %.6f %.6f %.6f\n", 3, is_type_float<T...>};
+ }
+ /* Keep only one space between options since filepaths may have leading spaces too. */
+ case eMTLSyntaxElement::map_Kd: {
+ return {"map_Kd %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_Ks: {
+ return {"map_Ks %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_Ns: {
+ return {"map_Ns %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_d: {
+ return {"map_d %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_refl: {
+ return {"map_refl %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_Ke: {
+ return {"map_Ke %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_Bump: {
+ return {"map_Bump %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::string: {
+ return {"%s", 1, is_type_string_related<T...>};
+ }
+ }
+}
+
+/**
+ * File format and syntax agnostic file writer.
+ */
+template<eFileType filetype> class FormattedFileHandler : NonCopyable, NonMovable {
+ private:
+ std::FILE *outfile_ = nullptr;
+ std::string outfile_path_;
+
+ public:
+ FormattedFileHandler(std::string outfile_path) noexcept(false)
+ : outfile_path_(std::move(outfile_path))
+ {
+ outfile_ = BLI_fopen(outfile_path_.c_str(), "w");
+ if (!outfile_) {
+ throw std::system_error(errno, std::system_category(), "Cannot open file " + outfile_path_);
+ }
+ }
+
+ ~FormattedFileHandler()
+ {
+ if (outfile_ && std::fclose(outfile_)) {
+ std::cerr << "Error: could not close the file '" << outfile_path_
+ << "' properly, it may be corrupted." << std::endl;
+ }
+ }
+
+ /**
+ * Example invocation: `writer->write<eMTLSyntaxElement::newmtl>("foo")`.
+ *
+ * \param key Must match what the instance's filetype expects; i.e., `eMTLSyntaxElement` for
+ * `eFileType::MTL`.
+ */
+ template<typename FileTypeTraits<filetype>::SyntaxType key, typename... T>
+ constexpr void write(T &&...args) const
+ {
+ /* Get format syntax, number of arguments expected and whether types of given arguments are
+ * valid.
+ */
+ constexpr FormattingSyntax fmt_nargs_valid = syntax_elem_to_formatting<T...>(key);
+ BLI_STATIC_ASSERT(fmt_nargs_valid.are_types_valid &&
+ (sizeof...(T) == fmt_nargs_valid.total_args),
+ "Types of all arguments and the number of arguments should match what the "
+ "formatting specifies.");
+ write_impl(fmt_nargs_valid.fmt, std::forward<T>(args)...);
+ }
+
+ private:
+ /* Remove this after upgrading to C++20. */
+ template<typename T> using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
+
+ /**
+ * Make #std::string etc., usable for `fprintf` family. int float etc. are not affected.
+ * \return: `const char *` or the original argument if the argument is
+ * not related to #std::string.
+ */
+ template<typename T> constexpr auto convert_to_primitive(T &&arg) const
+ {
+ if constexpr (std::is_same_v<remove_cvref_t<T>, std::string> ||
+ std::is_same_v<remove_cvref_t<T>, blender::StringRefNull>) {
+ return arg.c_str();
+ }
+ else if constexpr (std::is_same_v<remove_cvref_t<T>, blender::StringRef>) {
+ BLI_STATIC_ASSERT(
+ (always_false<T>::value),
+ "Null-terminated string not present. Please use blender::StringRefNull instead.");
+ /* Another trick to cause a compile-time error: returning nothing to #std::printf. */
+ return;
+ }
+ else {
+ /* For int, float etc. */
+ return std::forward<T>(arg);
+ }
+ }
+
+ template<typename... T> constexpr void write_impl(const char *fmt, T &&...args) const
+ {
+ if constexpr (sizeof...(T) == 0) {
+ std::fputs(fmt, outfile_);
+ }
+ else {
+ std::fprintf(outfile_, fmt, convert_to_primitive(std::forward<T>(args))...);
+ }
+ }
+};
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
new file mode 100644
index 00000000000..c1b12ddd217
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
@@ -0,0 +1,468 @@
+/*
+ * 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 obj
+ */
+/* Silence warnings from copying deprecated fields. Needed for an Object copy constructor use. */
+#define DNA_DEPRECATED_ALLOW
+
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_lib_id.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_map.hh"
+#include "BLI_math.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "obj_export_mesh.hh"
+
+namespace blender::io::obj {
+OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Object *mesh_object)
+{
+ /* We need to copy the object because it may be in temporary space. */
+ Object *obj_eval = DEG_get_evaluated_object(depsgraph, mesh_object);
+ export_object_eval_ = *obj_eval;
+ export_mesh_eval_ = BKE_object_get_evaluated_mesh(&export_object_eval_);
+ mesh_eval_needs_free_ = false;
+
+ if (!export_mesh_eval_) {
+ /* Curves and NURBS surfaces need a new mesh when they're
+ * exported in the form of vertices and edges.
+ */
+ export_mesh_eval_ = BKE_mesh_new_from_object(depsgraph, &export_object_eval_, true, true);
+ /* Since a new mesh been allocated, it needs to be freed in the destructor. */
+ mesh_eval_needs_free_ = true;
+ }
+ if (export_params.export_triangulated_mesh && ELEM(export_object_eval_.type, OB_MESH, OB_SURF)) {
+ std::tie(export_mesh_eval_, mesh_eval_needs_free_) = triangulate_mesh_eval();
+ }
+ set_world_axes_transform(export_params.forward_axis, export_params.up_axis);
+}
+
+/**
+ * Free new meshes allocated for triangulated meshes, or Curve converted to Mesh.
+ */
+OBJMesh::~OBJMesh()
+{
+ free_mesh_if_needed();
+ if (poly_smooth_groups_) {
+ MEM_freeN(poly_smooth_groups_);
+ }
+}
+
+void OBJMesh::free_mesh_if_needed()
+{
+ if (mesh_eval_needs_free_ && export_mesh_eval_) {
+ BKE_id_free(nullptr, export_mesh_eval_);
+ }
+}
+
+std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
+{
+ if (export_mesh_eval_->totpoly <= 0) {
+ return {export_mesh_eval_, false};
+ }
+ const struct BMeshCreateParams bm_create_params = {0u};
+ const struct BMeshFromMeshParams bm_convert_params = {1u, 0, 0, 0};
+ /* Lower threshold where triangulation of a polygon starts, i.e. a quadrilateral will be
+ * triangulated here. */
+ const int triangulate_min_verts = 4;
+
+ unique_bmesh_ptr bmesh(
+ BKE_mesh_to_bmesh_ex(export_mesh_eval_, &bm_create_params, &bm_convert_params));
+ BM_mesh_triangulate(bmesh.get(),
+ MOD_TRIANGULATE_NGON_BEAUTY,
+ MOD_TRIANGULATE_QUAD_SHORTEDGE,
+ triangulate_min_verts,
+ false,
+ nullptr,
+ nullptr,
+ nullptr);
+
+ Mesh *triangulated = BKE_mesh_from_bmesh_for_eval_nomain(
+ bmesh.get(), nullptr, export_mesh_eval_);
+ free_mesh_if_needed();
+ return {triangulated, true};
+}
+
+void OBJMesh::set_world_axes_transform(const eTransformAxisForward forward,
+ const eTransformAxisUp up)
+{
+ float axes_transform[3][3];
+ unit_m3(axes_transform);
+ /* +Y-forward and +Z-up are the default Blender axis settings. */
+ mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform);
+ /* mat3_from_axis_conversion returns a transposed matrix! */
+ transpose_m3(axes_transform);
+ mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_.obmat);
+ /* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */
+ mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, export_object_eval_.obmat[3]);
+ world_and_axes_transform_[3][3] = export_object_eval_.obmat[3][3];
+}
+
+int OBJMesh::tot_vertices() const
+{
+ return export_mesh_eval_->totvert;
+}
+
+int OBJMesh::tot_polygons() const
+{
+ return export_mesh_eval_->totpoly;
+}
+
+int OBJMesh::tot_uv_vertices() const
+{
+ return tot_uv_vertices_;
+}
+
+int OBJMesh::tot_edges() const
+{
+ return export_mesh_eval_->totedge;
+}
+
+int16_t OBJMesh::tot_materials() const
+{
+ return export_mesh_eval_->totcol;
+}
+
+int OBJMesh::tot_normal_indices() const
+{
+ return tot_normal_indices_;
+}
+
+int OBJMesh::ith_smooth_group(const int poly_index) const
+{
+ /* Calculate smooth groups first: #OBJMesh::calc_smooth_groups. */
+ BLI_assert(tot_smooth_groups_ != -NEGATIVE_INIT);
+ BLI_assert(poly_smooth_groups_);
+ return poly_smooth_groups_[poly_index];
+}
+
+void OBJMesh::ensure_mesh_normals() const
+{
+ BKE_mesh_calc_normals_split(export_mesh_eval_);
+}
+
+void OBJMesh::ensure_mesh_edges() const
+{
+ BKE_mesh_calc_edges(export_mesh_eval_, true, false);
+ BKE_mesh_calc_edges_loose(export_mesh_eval_);
+}
+
+void OBJMesh::calc_smooth_groups(const bool use_bitflags)
+{
+ poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(export_mesh_eval_->medge,
+ export_mesh_eval_->totedge,
+ export_mesh_eval_->mpoly,
+ export_mesh_eval_->totpoly,
+ export_mesh_eval_->mloop,
+ export_mesh_eval_->totloop,
+ &tot_smooth_groups_,
+ use_bitflags);
+}
+
+const Material *OBJMesh::get_object_material(const int16_t mat_nr) const
+{
+ /**
+ * The const_cast is safe here because BKE_object_material_get won't change the object
+ * but it is a big can of worms to fix the declaration of that function right now.
+ *
+ * The call uses "+ 1" as material getter needs one-based indices.
+ */
+ Object *obj = const_cast<Object *>(&export_object_eval_);
+ const Material *r_mat = BKE_object_material_get(obj, mat_nr + 1);
+#ifdef DEBUG
+ if (!r_mat) {
+ std::cerr << "Material not found for mat_nr = " << mat_nr << std::endl;
+ }
+#endif
+ return r_mat;
+}
+
+bool OBJMesh::is_ith_poly_smooth(const int poly_index) const
+{
+ return export_mesh_eval_->mpoly[poly_index].flag & ME_SMOOTH;
+}
+
+int16_t OBJMesh::ith_poly_matnr(const int poly_index) const
+{
+ BLI_assert(poly_index < export_mesh_eval_->totpoly);
+ const int16_t r_mat_nr = export_mesh_eval_->mpoly[poly_index].mat_nr;
+ return r_mat_nr >= 0 ? r_mat_nr : NOT_FOUND;
+}
+
+const char *OBJMesh::get_object_name() const
+{
+ return export_object_eval_.id.name + 2;
+}
+
+const char *OBJMesh::get_object_mesh_name() const
+{
+ return export_mesh_eval_->id.name + 2;
+}
+
+const char *OBJMesh::get_object_material_name(const int16_t mat_nr) const
+{
+ const Material *mat = get_object_material(mat_nr);
+ if (!mat) {
+ return nullptr;
+ }
+ return mat->id.name + 2;
+}
+
+float3 OBJMesh::calc_vertex_coords(const int vert_index, const float scaling_factor) const
+{
+ float3 r_coords;
+ copy_v3_v3(r_coords, export_mesh_eval_->mvert[vert_index].co);
+ mul_v3_fl(r_coords, scaling_factor);
+ mul_m4_v3(world_and_axes_transform_, r_coords);
+ return r_coords;
+}
+
+Vector<int> OBJMesh::calc_poly_vertex_indices(const int poly_index) const
+{
+ const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
+ const MLoop *mloop = &export_mesh_eval_->mloop[mpoly.loopstart];
+ const int totloop = mpoly.totloop;
+ Vector<int> r_poly_vertex_indices(totloop);
+ for (int loop_index = 0; loop_index < totloop; loop_index++) {
+ r_poly_vertex_indices[loop_index] = mloop[loop_index].v;
+ }
+ return r_poly_vertex_indices;
+}
+
+void OBJMesh::store_uv_coords_and_indices(Vector<std::array<float, 2>> &r_uv_coords)
+{
+ const MPoly *mpoly = export_mesh_eval_->mpoly;
+ const MLoop *mloop = export_mesh_eval_->mloop;
+ const int totpoly = export_mesh_eval_->totpoly;
+ const int totvert = export_mesh_eval_->totvert;
+ const MLoopUV *mloopuv = static_cast<MLoopUV *>(
+ CustomData_get_layer(&export_mesh_eval_->ldata, CD_MLOOPUV));
+ if (!mloopuv) {
+ tot_uv_vertices_ = 0;
+ return;
+ }
+ const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
+
+ UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(
+ mpoly, mloop, mloopuv, totpoly, totvert, limit, false, false);
+
+ uv_indices_.resize(totpoly);
+ /* At least total vertices of a mesh will be present in its texture map. So
+ * reserve minimum space early. */
+ r_uv_coords.reserve(totvert);
+
+ tot_uv_vertices_ = 0;
+ for (int vertex_index = 0; vertex_index < totvert; vertex_index++) {
+ const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map, vertex_index);
+ for (; uv_vert; uv_vert = uv_vert->next) {
+ if (uv_vert->separate) {
+ tot_uv_vertices_ += 1;
+ }
+ const int vertices_in_poly = mpoly[uv_vert->poly_index].totloop;
+
+ /* Store UV vertex coordinates. */
+ r_uv_coords.resize(tot_uv_vertices_);
+ const int loopstart = mpoly[uv_vert->poly_index].loopstart;
+ Span<float> vert_uv_coords(mloopuv[loopstart + uv_vert->loop_of_poly_index].uv, 2);
+ r_uv_coords[tot_uv_vertices_ - 1][0] = vert_uv_coords[0];
+ r_uv_coords[tot_uv_vertices_ - 1][1] = vert_uv_coords[1];
+
+ /* Store UV vertex indices. */
+ uv_indices_[uv_vert->poly_index].resize(vertices_in_poly);
+ /* Keep indices zero-based and let the writer handle the "+ 1" as per OBJ spec. */
+ uv_indices_[uv_vert->poly_index][uv_vert->loop_of_poly_index] = tot_uv_vertices_ - 1;
+ }
+ }
+ BKE_mesh_uv_vert_map_free(uv_vert_map);
+}
+
+Span<int> OBJMesh::calc_poly_uv_indices(const int poly_index) const
+{
+ if (uv_indices_.size() <= 0) {
+ return {};
+ }
+ BLI_assert(poly_index < export_mesh_eval_->totpoly);
+ BLI_assert(poly_index < uv_indices_.size());
+ return uv_indices_[poly_index];
+}
+
+float3 OBJMesh::calc_poly_normal(const int poly_index) const
+{
+ float3 r_poly_normal;
+ const MPoly &poly = export_mesh_eval_->mpoly[poly_index];
+ const MLoop &mloop = export_mesh_eval_->mloop[poly.loopstart];
+ const MVert &mvert = *(export_mesh_eval_->mvert);
+ BKE_mesh_calc_poly_normal(&poly, &mloop, &mvert, r_poly_normal);
+ mul_mat3_m4_v3(world_and_axes_transform_, r_poly_normal);
+ return r_poly_normal;
+}
+
+/** Round \a f to \a round_digits decimal digits. */
+static float round_float_to_n_digits(const float f, int round_digits)
+{
+ float scale = powf(10.0, round_digits);
+ return ceilf((scale * f - 0.49999999f)) / scale;
+}
+
+static float3 round_float3_to_n_digits(const float3 &v, int round_digits)
+{
+ float3 ans;
+ ans.x = round_float_to_n_digits(v.x, round_digits);
+ ans.y = round_float_to_n_digits(v.y, round_digits);
+ ans.z = round_float_to_n_digits(v.z, round_digits);
+ return ans;
+}
+
+void OBJMesh::store_normal_coords_and_indices(Vector<float3> &r_normal_coords)
+{
+ /* We'll round normal components to 4 digits.
+ * This will cover up some minor differences
+ * between floating point calculations on different platforms.
+ * Since normals are normalized, there will be no perceptible loss
+ * of precision when rounding to 4 digits. */
+ constexpr int round_digits = 4;
+ int cur_normal_index = 0;
+ Map<float3, int> normal_to_index;
+ /* We don't know how many unique normals there will be, but this is a guess. */
+ normal_to_index.reserve(export_mesh_eval_->totpoly);
+ loop_to_normal_index_.resize(export_mesh_eval_->totloop);
+ loop_to_normal_index_.fill(-1);
+ const float(
+ *lnors)[3] = (const float(*)[3])(CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL));
+ for (int poly_index = 0; poly_index < export_mesh_eval_->totpoly; ++poly_index) {
+ const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
+ bool need_per_loop_normals = is_ith_poly_smooth(poly_index);
+ if (need_per_loop_normals) {
+ for (int loop_of_poly = 0; loop_of_poly < mpoly.totloop; ++loop_of_poly) {
+ float3 loop_normal;
+ int loop_index = mpoly.loopstart + loop_of_poly;
+ BLI_assert(loop_index < export_mesh_eval_->totloop);
+ copy_v3_v3(loop_normal, lnors[loop_index]);
+ mul_mat3_m4_v3(world_and_axes_transform_, loop_normal);
+ float3 rounded_loop_normal = round_float3_to_n_digits(loop_normal, round_digits);
+ int loop_norm_index = normal_to_index.lookup_default(rounded_loop_normal, -1);
+ if (loop_norm_index == -1) {
+ loop_norm_index = cur_normal_index++;
+ normal_to_index.add(rounded_loop_normal, loop_norm_index);
+ r_normal_coords.append(rounded_loop_normal);
+ }
+ loop_to_normal_index_[loop_index] = loop_norm_index;
+ }
+ }
+ else {
+ float3 poly_normal = calc_poly_normal(poly_index);
+ float3 rounded_poly_normal = round_float3_to_n_digits(poly_normal, round_digits);
+ int poly_norm_index = normal_to_index.lookup_default(rounded_poly_normal, -1);
+ if (poly_norm_index == -1) {
+ poly_norm_index = cur_normal_index++;
+ normal_to_index.add(rounded_poly_normal, poly_norm_index);
+ r_normal_coords.append(rounded_poly_normal);
+ }
+ for (int i = 0; i < mpoly.totloop; ++i) {
+ int loop_index = mpoly.loopstart + i;
+ BLI_assert(loop_index < export_mesh_eval_->totloop);
+ loop_to_normal_index_[loop_index] = poly_norm_index;
+ }
+ }
+ }
+ tot_normal_indices_ = cur_normal_index;
+}
+
+Vector<int> OBJMesh::calc_poly_normal_indices(const int poly_index) const
+{
+ const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
+ const int totloop = mpoly.totloop;
+ Vector<int> r_poly_normal_indices(totloop);
+ for (int poly_loop_index = 0; poly_loop_index < totloop; poly_loop_index++) {
+ int loop_index = mpoly.loopstart + poly_loop_index;
+ r_poly_normal_indices[poly_loop_index] = loop_to_normal_index_[loop_index];
+ }
+ return r_poly_normal_indices;
+}
+
+int16_t OBJMesh::get_poly_deform_group_index(const int poly_index) const
+{
+ BLI_assert(poly_index < export_mesh_eval_->totpoly);
+ const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
+ const MLoop *mloop = &export_mesh_eval_->mloop[mpoly.loopstart];
+ const Object *obj = &export_object_eval_;
+ const int tot_deform_groups = BKE_object_defgroup_count(obj);
+ /* Indices of the vector index into deform groups of an object; values are the]
+ * number of vertex members in one deform group. */
+ Vector<int16_t> deform_group_members(tot_deform_groups, 0);
+ /* Whether at least one vertex in the polygon belongs to any group. */
+ bool found_group = false;
+
+ const MDeformVert *dvert_orig = static_cast<MDeformVert *>(
+ CustomData_get_layer(&export_mesh_eval_->vdata, CD_MDEFORMVERT));
+ if (!dvert_orig) {
+ return NOT_FOUND;
+ }
+
+ const MDeformWeight *curr_weight = nullptr;
+ const MDeformVert *dvert = nullptr;
+ for (int loop_index = 0; loop_index < mpoly.totloop; loop_index++) {
+ dvert = &dvert_orig[(mloop + loop_index)->v];
+ curr_weight = dvert->dw;
+ if (curr_weight) {
+ bDeformGroup *vertex_group = static_cast<bDeformGroup *>(
+ BLI_findlink(BKE_object_defgroup_list(obj), curr_weight->def_nr));
+ if (vertex_group) {
+ deform_group_members[curr_weight->def_nr] += 1;
+ found_group = true;
+ }
+ }
+ }
+
+ if (!found_group) {
+ return NOT_FOUND;
+ }
+ /* Index of the group with maximum vertices. */
+ int16_t max_idx = std::max_element(deform_group_members.begin(), deform_group_members.end()) -
+ deform_group_members.begin();
+ return max_idx;
+}
+
+const char *OBJMesh::get_poly_deform_group_name(const int16_t def_group_index) const
+{
+ const bDeformGroup &vertex_group = *(static_cast<bDeformGroup *>(
+ BLI_findlink(BKE_object_defgroup_list(&export_object_eval_), def_group_index)));
+ return vertex_group.name;
+}
+
+std::optional<std::array<int, 2>> OBJMesh::calc_loose_edge_vert_indices(const int edge_index) const
+{
+ const MEdge &edge = export_mesh_eval_->medge[edge_index];
+ if (edge.flag & ME_LOOSEEDGE) {
+ return std::array<int, 2>{static_cast<int>(edge.v1), static_cast<int>(edge.v2)};
+ }
+ return std::nullopt;
+}
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
new file mode 100644
index 00000000000..f3ace140006
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
@@ -0,0 +1,226 @@
+/*
+ * 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 obj
+ */
+
+#pragma once
+
+#include <optional>
+
+#include "BLI_math_vec_types.hh"
+#include "BLI_utility_mixins.hh"
+#include "BLI_vector.hh"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "IO_wavefront_obj.h"
+
+namespace blender::io::obj {
+/** Denote absence for usually non-negative numbers. */
+const int NOT_FOUND = -1;
+/** Any negative number other than `NOT_FOUND` to initialize usually non-negative numbers. */
+const int NEGATIVE_INIT = -10;
+
+/**
+ * #std::unique_ptr than handles freeing #BMesh.
+ */
+struct CustomBMeshDeleter {
+ void operator()(BMesh *bmesh)
+ {
+ if (bmesh) {
+ BM_mesh_free(bmesh);
+ }
+ }
+};
+
+using unique_bmesh_ptr = std::unique_ptr<BMesh, CustomBMeshDeleter>;
+
+class OBJMesh : NonCopyable {
+ private:
+ /**
+ * We need to copy the entire Object structure here because the dependency graph iterator
+ * sometimes builds an Object in a temporary space that doesn't persist.
+ */
+ Object export_object_eval_;
+ Mesh *export_mesh_eval_;
+ /**
+ * For curves which are converted to mesh, and triangulated meshes, a new mesh is allocated.
+ */
+ bool mesh_eval_needs_free_ = false;
+ /**
+ * Final transform of an object obtained from export settings (up_axis, forward_axis) and the
+ * object's world transform matrix.
+ */
+ float world_and_axes_transform_[4][4];
+
+ /**
+ * Total UV vertices in a mesh's texture map.
+ */
+ int tot_uv_vertices_ = 0;
+ /**
+ * Per-polygon-per-vertex UV vertex indices.
+ */
+ Vector<Vector<int>> uv_indices_;
+ /**
+ * Per-loop normal index.
+ */
+ Vector<int> loop_to_normal_index_;
+ /*
+ * Total number of normal indices (maximum entry, plus 1, in
+ * the loop_to_norm_index_ vector).
+ */
+ int tot_normal_indices_ = 0;
+ /**
+ * Total smooth groups in an object.
+ */
+ int tot_smooth_groups_ = NEGATIVE_INIT;
+ /**
+ * Polygon aligned array of their smooth groups.
+ */
+ int *poly_smooth_groups_ = nullptr;
+
+ public:
+ /**
+ * Store evaluated Object and Mesh pointers. Conditionally triangulate a mesh, or
+ * create a new Mesh from a Curve.
+ */
+ OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Object *mesh_object);
+ ~OBJMesh();
+
+ int tot_vertices() const;
+ int tot_polygons() const;
+ int tot_uv_vertices() const;
+ int tot_normal_indices() const;
+ int tot_edges() const;
+
+ /**
+ * \return Total materials in the object.
+ */
+ int16_t tot_materials() const;
+ /**
+ * Return mat_nr-th material of the object. The given index should be zero-based.
+ */
+ const Material *get_object_material(int16_t mat_nr) const;
+ /**
+ * Returns a zero-based index of a polygon's material indexing into
+ * the Object's material slots.
+ */
+ int16_t ith_poly_matnr(int poly_index) const;
+
+ void ensure_mesh_normals() const;
+ void ensure_mesh_edges() const;
+
+ /**
+ * Calculate smooth groups of a smooth-shaded object.
+ * \return A polygon aligned array of smooth group numbers.
+ */
+ void calc_smooth_groups(bool use_bitflags);
+ /**
+ * \return Smooth group of the polygon at the given index.
+ */
+ int ith_smooth_group(int poly_index) const;
+ bool is_ith_poly_smooth(int poly_index) const;
+
+ /**
+ * Get object name as it appears in the outliner.
+ */
+ const char *get_object_name() const;
+ /**
+ * Get Object's Mesh's name.
+ */
+ const char *get_object_mesh_name() const;
+ /**
+ * Get object's material (at the given index) name. The given index should be zero-based.
+ */
+ const char *get_object_material_name(int16_t mat_nr) const;
+
+ /**
+ * Calculate coordinates of the vertex at the given index.
+ */
+ float3 calc_vertex_coords(int vert_index, float scaling_factor) const;
+ /**
+ * Calculate vertex indices of all vertices of the polygon at the given index.
+ */
+ Vector<int> calc_poly_vertex_indices(int poly_index) const;
+ /**
+ * Calculate UV vertex coordinates of an Object.
+ *
+ * \note Also store the UV vertex indices in the member variable.
+ */
+ void store_uv_coords_and_indices(Vector<std::array<float, 2>> &r_uv_coords);
+ Span<int> calc_poly_uv_indices(int poly_index) const;
+ /**
+ * Calculate polygon normal of a polygon at given index.
+ *
+ * Should be used for flat-shaded polygons.
+ */
+ float3 calc_poly_normal(int poly_index) const;
+ /**
+ * Find the unique normals of the mesh and return them in \a r_normal_coords.
+ * Store the indices into that vector with for each loop in this #OBJMesh.
+ */
+ void store_normal_coords_and_indices(Vector<float3> &r_normal_coords);
+ /**
+ * Calculate a polygon's polygon/loop normal indices.
+ * \param poly_index Index of the polygon to calculate indices for.
+ * \return Vector of normal indices, aligned with vertices of polygon.
+ */
+ Vector<int> calc_poly_normal_indices(int poly_index) const;
+ /**
+ * Find the index of the vertex group with the maximum number of vertices in a polygon.
+ * The index indices into the #Object.defbase.
+ *
+ * If two or more groups have the same number of vertices (maximum), group name depends on the
+ * implementation of #std::max_element.
+ */
+ int16_t get_poly_deform_group_index(int poly_index) const;
+ /**
+ * Find the name of the vertex deform group at the given index.
+ * The index indices into the #Object.defbase.
+ */
+ const char *get_poly_deform_group_name(int16_t def_group_index) const;
+
+ /**
+ * Calculate vertex indices of an edge's corners if it is a loose edge.
+ */
+ std::optional<std::array<int, 2>> calc_loose_edge_vert_indices(int edge_index) const;
+
+ private:
+ /**
+ * Free the mesh if _the exporter_ created it.
+ */
+ void free_mesh_if_needed();
+ /**
+ * Allocate a new Mesh with triangulated polygons.
+ *
+ * The returned mesh can be the same as the old one.
+ * \return Owning pointer to the new Mesh, and whether a new Mesh was created.
+ */
+ std::pair<Mesh *, bool> triangulate_mesh_eval();
+ /**
+ * Set the final transform after applying axes settings and an Object's world transform.
+ */
+ void set_world_axes_transform(eTransformAxisForward forward, eTransformAxisUp up);
+};
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
new file mode 100644
index 00000000000..48136dad5f7
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
@@ -0,0 +1,360 @@
+/*
+ * 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 obj
+ */
+
+#include "BKE_image.h"
+#include "BKE_node.h"
+
+#include "BLI_map.hh"
+#include "BLI_math_vec_types.hh"
+#include "BLI_path_util.h"
+
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+
+#include "NOD_node_tree_ref.hh"
+
+#include "obj_export_mesh.hh"
+#include "obj_export_mtl.hh"
+
+namespace blender::io::obj {
+
+/**
+ * Copy a float property of the given type from the bNode to given buffer.
+ */
+static void copy_property_from_node(const eNodeSocketDatatype property_type,
+ const bNode *node,
+ const char *identifier,
+ MutableSpan<float> r_property)
+{
+ if (!node) {
+ return;
+ }
+ bNodeSocket *socket{nodeFindSocket(node, SOCK_IN, identifier)};
+ BLI_assert(socket && socket->type == property_type);
+ if (!socket) {
+ return;
+ }
+ switch (property_type) {
+ case SOCK_FLOAT: {
+ BLI_assert(r_property.size() == 1);
+ bNodeSocketValueFloat *socket_def_value = static_cast<bNodeSocketValueFloat *>(
+ socket->default_value);
+ r_property[0] = socket_def_value->value;
+ break;
+ }
+ case SOCK_RGBA: {
+ BLI_assert(r_property.size() == 3);
+ bNodeSocketValueRGBA *socket_def_value = static_cast<bNodeSocketValueRGBA *>(
+ socket->default_value);
+ copy_v3_v3(r_property.data(), socket_def_value->value);
+ break;
+ }
+ case SOCK_VECTOR: {
+ BLI_assert(r_property.size() == 3);
+ bNodeSocketValueVector *socket_def_value = static_cast<bNodeSocketValueVector *>(
+ socket->default_value);
+ copy_v3_v3(r_property.data(), socket_def_value->value);
+ break;
+ }
+ default: {
+ /* Other socket types are not handled here. */
+ BLI_assert(0);
+ break;
+ }
+ }
+}
+
+/**
+ * Collect all the source sockets linked to the destination socket in a destination node.
+ */
+static void linked_sockets_to_dest_id(const bNode *dest_node,
+ const nodes::NodeTreeRef &node_tree,
+ StringRefNull dest_socket_id,
+ Vector<const nodes::OutputSocketRef *> &r_linked_sockets)
+{
+ r_linked_sockets.clear();
+ if (!dest_node) {
+ return;
+ }
+ Span<const nodes::NodeRef *> object_dest_nodes = node_tree.nodes_by_type(dest_node->idname);
+ Span<const nodes::InputSocketRef *> dest_inputs = object_dest_nodes.first()->inputs();
+ const nodes::InputSocketRef *dest_socket = nullptr;
+ for (const nodes::InputSocketRef *curr_socket : dest_inputs) {
+ if (STREQ(curr_socket->bsocket()->identifier, dest_socket_id.c_str())) {
+ dest_socket = curr_socket;
+ break;
+ }
+ }
+ if (dest_socket) {
+ Span<const nodes::OutputSocketRef *> linked_sockets = dest_socket->directly_linked_sockets();
+ r_linked_sockets.resize(linked_sockets.size());
+ r_linked_sockets = linked_sockets;
+ }
+}
+
+/**
+ * From a list of sockets, get the parent node which is of the given node type.
+ */
+static const bNode *get_node_of_type(Span<const nodes::OutputSocketRef *> sockets_list,
+ const int node_type)
+{
+ for (const nodes::SocketRef *socket : sockets_list) {
+ const bNode *parent_node = socket->bnode();
+ if (parent_node->typeinfo->type == node_type) {
+ return parent_node;
+ }
+ }
+ return nullptr;
+}
+
+/**
+ * From a texture image shader node, get the image's filepath.
+ * Returned filepath is stripped of initial "//". If packed image is found,
+ * only the file "name" is returned.
+ */
+static const char *get_image_filepath(const bNode *tex_node)
+{
+ if (!tex_node) {
+ return nullptr;
+ }
+ Image *tex_image = reinterpret_cast<Image *>(tex_node->id);
+ if (!tex_image || !BKE_image_has_filepath(tex_image)) {
+ return nullptr;
+ }
+ const char *path = tex_image->filepath;
+ if (BKE_image_has_packedfile(tex_image)) {
+ /* Put image in the same directory as the .MTL file. */
+ path = BLI_path_slash_rfind(path) + 1;
+ fprintf(stderr,
+ "Packed image found:'%s'. Unpack and place the image in the same "
+ "directory as the .MTL file.\n",
+ path);
+ }
+ if (path[0] == '/' && path[1] == '/') {
+ path += 2;
+ }
+ return path;
+}
+
+/**
+ * Find the Principled-BSDF Node in nodetree.
+ * We only want one that feeds directly into a Material Output node
+ * (that is the behavior of the legacy Python exporter).
+ */
+static const nodes::NodeRef *find_bsdf_node(const nodes::NodeTreeRef *nodetree)
+{
+ if (!nodetree) {
+ return nullptr;
+ }
+ for (const nodes::NodeRef *node : nodetree->nodes_by_type("ShaderNodeOutputMaterial")) {
+ const nodes::InputSocketRef *node_input_socket0 = node->inputs()[0];
+ for (const nodes::OutputSocketRef *out_sock : node_input_socket0->directly_linked_sockets()) {
+ const nodes::NodeRef &in_node = out_sock->node();
+ if (in_node.typeinfo()->type == SH_NODE_BSDF_PRINCIPLED) {
+ return &in_node;
+ }
+ }
+ }
+ return nullptr;
+}
+
+/**
+ * Store properties found either in bNode or material into r_mtl_mat.
+ */
+static void store_bsdf_properties(const nodes::NodeRef *bsdf_node,
+ const Material *material,
+ MTLMaterial &r_mtl_mat)
+{
+ const bNode *bnode = nullptr;
+ if (bsdf_node) {
+ bnode = bsdf_node->bnode();
+ }
+
+ /* If p-BSDF is not present, fallback to #Object.Material. */
+ float roughness = material->roughness;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Roughness", {&roughness, 1});
+ }
+ /* Empirical approximation. Importer should use the inverse of this method. */
+ float spec_exponent = (1.0f - roughness) * 30;
+ spec_exponent *= spec_exponent;
+
+ float specular = material->spec;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Specular", {&specular, 1});
+ }
+
+ float metallic = material->metallic;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Metallic", {&metallic, 1});
+ }
+
+ float refraction_index = 1.0f;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "IOR", {&refraction_index, 1});
+ }
+
+ float dissolved = material->a;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Alpha", {&dissolved, 1});
+ }
+ const bool transparent = dissolved != 1.0f;
+
+ float3 diffuse_col = {material->r, material->g, material->b};
+ if (bnode) {
+ copy_property_from_node(SOCK_RGBA, bnode, "Base Color", {diffuse_col, 3});
+ }
+
+ float3 emission_col{0.0f};
+ float emission_strength = 0.0f;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1});
+ copy_property_from_node(SOCK_RGBA, bnode, "Emission", {emission_col, 3});
+ }
+ mul_v3_fl(emission_col, emission_strength);
+
+ /* See https://wikipedia.org/wiki/Wavefront_.obj_file for all possible values of `illum`. */
+ /* Highlight on. */
+ int illum = 2;
+ if (specular == 0.0f) {
+ /* Color on and Ambient on. */
+ illum = 1;
+ }
+ else if (metallic > 0.0f) {
+ /* Metallic ~= Reflection. */
+ if (transparent) {
+ /* Transparency: Refraction on, Reflection: ~~Fresnel off and Ray trace~~ on. */
+ illum = 6;
+ }
+ else {
+ /* Reflection on and Ray trace on. */
+ illum = 3;
+ }
+ }
+ else if (transparent) {
+ /* Transparency: Glass on, Reflection: Ray trace off */
+ illum = 9;
+ }
+ r_mtl_mat.Ns = spec_exponent;
+ if (metallic != 0.0f) {
+ r_mtl_mat.Ka = {metallic, metallic, metallic};
+ }
+ else {
+ r_mtl_mat.Ka = {1.0f, 1.0f, 1.0f};
+ }
+ r_mtl_mat.Kd = diffuse_col;
+ r_mtl_mat.Ks = {specular, specular, specular};
+ r_mtl_mat.Ke = emission_col;
+ r_mtl_mat.Ni = refraction_index;
+ r_mtl_mat.d = dissolved;
+ r_mtl_mat.illum = illum;
+}
+
+/**
+ * Store image texture options and file-paths in `r_mtl_mat`.
+ */
+static void store_image_textures(const nodes::NodeRef *bsdf_node,
+ const nodes::NodeTreeRef *node_tree,
+ const Material *material,
+ MTLMaterial &r_mtl_mat)
+{
+ if (!material || !node_tree || !bsdf_node) {
+ /* No nodetree, no images, or no Principled BSDF node. */
+ return;
+ }
+ const bNode *bnode = bsdf_node->bnode();
+
+ /* Normal Map Texture has two extra tasks of:
+ * - finding a Normal Map node before finding a texture node.
+ * - finding "Strength" property of the node for `-bm` option.
+ */
+
+ for (Map<const eMTLSyntaxElement, tex_map_XX>::MutableItem texture_map :
+ r_mtl_mat.texture_maps.items()) {
+ Vector<const nodes::OutputSocketRef *> linked_sockets;
+ const bNode *normal_map_node{nullptr};
+
+ if (texture_map.key == eMTLSyntaxElement::map_Bump) {
+ /* Find sockets linked to destination "Normal" socket in P-BSDF node. */
+ linked_sockets_to_dest_id(bnode, *node_tree, "Normal", linked_sockets);
+ /* Among the linked sockets, find Normal Map shader node. */
+ normal_map_node = get_node_of_type(linked_sockets, SH_NODE_NORMAL_MAP);
+
+ /* Find sockets linked to "Color" socket in normal map node. */
+ linked_sockets_to_dest_id(normal_map_node, *node_tree, "Color", linked_sockets);
+ }
+ else if (texture_map.key == eMTLSyntaxElement::map_Ke) {
+ float emission_strength = 0.0f;
+ copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1});
+ if (emission_strength == 0.0f) {
+ continue;
+ }
+ }
+ else {
+ /* Find sockets linked to the destination socket of interest, in P-BSDF node. */
+ linked_sockets_to_dest_id(
+ bnode, *node_tree, texture_map.value.dest_socket_id, linked_sockets);
+ }
+
+ /* Among the linked sockets, find Image Texture shader node. */
+ const bNode *tex_node{get_node_of_type(linked_sockets, SH_NODE_TEX_IMAGE)};
+ if (!tex_node) {
+ continue;
+ }
+ const char *tex_image_filepath = get_image_filepath(tex_node);
+ if (!tex_image_filepath) {
+ continue;
+ }
+
+ /* Find "Mapping" node if connected to texture node. */
+ linked_sockets_to_dest_id(tex_node, *node_tree, "Vector", linked_sockets);
+ const bNode *mapping = get_node_of_type(linked_sockets, SH_NODE_MAPPING);
+
+ if (normal_map_node) {
+ copy_property_from_node(
+ SOCK_FLOAT, normal_map_node, "Strength", {&r_mtl_mat.map_Bump_strength, 1});
+ }
+ /* Texture transform options. Only translation (origin offset, "-o") and scale
+ * ("-o") are supported. */
+ copy_property_from_node(SOCK_VECTOR, mapping, "Location", {texture_map.value.translation, 3});
+ copy_property_from_node(SOCK_VECTOR, mapping, "Scale", {texture_map.value.scale, 3});
+
+ texture_map.value.image_path = tex_image_filepath;
+ }
+}
+
+MTLMaterial mtlmaterial_for_material(const Material *material)
+{
+ BLI_assert(material != nullptr);
+ MTLMaterial mtlmat;
+ mtlmat.name = std::string(material->id.name + 2);
+ std::replace(mtlmat.name.begin(), mtlmat.name.end(), ' ', '_');
+ const nodes::NodeTreeRef *nodetree = nullptr;
+ if (material->nodetree) {
+ nodetree = new nodes::NodeTreeRef(material->nodetree);
+ }
+ const nodes::NodeRef *bsdf_node = find_bsdf_node(nodetree);
+ store_bsdf_properties(bsdf_node, material, mtlmat);
+ store_image_textures(bsdf_node, nodetree, material, mtlmat);
+ delete nodetree;
+ return mtlmat;
+}
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh
new file mode 100644
index 00000000000..a84dcb80a48
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh
@@ -0,0 +1,104 @@
+/*
+ * 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 obj
+ */
+
+#pragma once
+
+#include "BLI_map.hh"
+#include "BLI_math_vec_types.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+#include "DNA_node_types.h"
+#include "obj_export_io.hh"
+
+namespace blender {
+template<> struct DefaultHash<io::obj::eMTLSyntaxElement> {
+ uint64_t operator()(const io::obj::eMTLSyntaxElement value) const
+ {
+ return static_cast<uint64_t>(value);
+ }
+};
+
+} // namespace blender
+
+namespace blender::io::obj {
+class OBJMesh;
+
+/**
+ * Generic container for texture node properties.
+ */
+struct tex_map_XX {
+ tex_map_XX(StringRef to_socket_id) : dest_socket_id(to_socket_id){};
+
+ /** Target socket which this texture node connects to. */
+ const std::string dest_socket_id;
+ float3 translation{0.0f};
+ float3 scale{1.0f};
+ /* Only Flat and Smooth projections are supported. */
+ int projection_type = SHD_PROJ_FLAT;
+ std::string image_path;
+ std::string mtl_dir_path;
+};
+
+/**
+ * Container suited for storing Material data for/from a .MTL file.
+ */
+struct MTLMaterial {
+ MTLMaterial()
+ {
+ texture_maps.add(eMTLSyntaxElement::map_Kd, tex_map_XX("Base Color"));
+ texture_maps.add(eMTLSyntaxElement::map_Ks, tex_map_XX("Specular"));
+ texture_maps.add(eMTLSyntaxElement::map_Ns, tex_map_XX("Roughness"));
+ texture_maps.add(eMTLSyntaxElement::map_d, tex_map_XX("Alpha"));
+ texture_maps.add(eMTLSyntaxElement::map_refl, tex_map_XX("Metallic"));
+ texture_maps.add(eMTLSyntaxElement::map_Ke, tex_map_XX("Emission"));
+ texture_maps.add(eMTLSyntaxElement::map_Bump, tex_map_XX("Normal"));
+ }
+
+ /**
+ * Caller must ensure that the given lookup key exists in the Map.
+ * \return Texture map corresponding to the given ID.
+ */
+ tex_map_XX &tex_map_of_type(const eMTLSyntaxElement key)
+ {
+ {
+ BLI_assert(texture_maps.contains_as(key));
+ return texture_maps.lookup_as(key);
+ }
+ }
+
+ std::string name;
+ /* Always check for negative values while importing or exporting. Use defaults if
+ * any value is negative. */
+ float Ns{-1.0f};
+ float3 Ka{-1.0f};
+ float3 Kd{-1.0f};
+ float3 Ks{-1.0f};
+ float3 Ke{-1.0f};
+ float Ni{-1.0f};
+ float d{-1.0f};
+ int illum{-1};
+ Map<const eMTLSyntaxElement, tex_map_XX> texture_maps;
+ /** Only used for Normal Map node: "map_Bump". */
+ float map_Bump_strength{-1.0f};
+};
+
+MTLMaterial mtlmaterial_for_material(const Material *material);
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
new file mode 100644
index 00000000000..ec690115115
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
@@ -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.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "IO_wavefront_obj.h"
+#include "obj_export_nurbs.hh"
+
+namespace blender::io::obj {
+OBJCurve::OBJCurve(const Depsgraph *depsgraph,
+ const OBJExportParams &export_params,
+ Object *curve_object)
+ : export_object_eval_(curve_object)
+{
+ export_object_eval_ = DEG_get_evaluated_object(depsgraph, curve_object);
+ export_curve_ = static_cast<Curve *>(export_object_eval_->data);
+ set_world_axes_transform(export_params.forward_axis, export_params.up_axis);
+}
+
+void OBJCurve::set_world_axes_transform(const eTransformAxisForward forward,
+ const eTransformAxisUp up)
+{
+ float axes_transform[3][3];
+ unit_m3(axes_transform);
+ /* +Y-forward and +Z-up are the Blender's default axis settings. */
+ mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform);
+ /* mat3_from_axis_conversion returns a transposed matrix! */
+ transpose_m3(axes_transform);
+ mul_m4_m3m4(world_axes_transform_, axes_transform, export_object_eval_->obmat);
+ /* #mul_m4_m3m4 does not transform last row of #Object.obmat, i.e. location data. */
+ mul_v3_m3v3(world_axes_transform_[3], axes_transform, export_object_eval_->obmat[3]);
+ world_axes_transform_[3][3] = export_object_eval_->obmat[3][3];
+}
+
+const char *OBJCurve::get_curve_name() const
+{
+ return export_object_eval_->id.name + 2;
+}
+
+int OBJCurve::total_splines() const
+{
+ return BLI_listbase_count(&export_curve_->nurb);
+}
+
+int OBJCurve::total_spline_vertices(const int spline_index) const
+{
+ const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index));
+ return nurb->pntsu * nurb->pntsv;
+}
+
+float3 OBJCurve::vertex_coordinates(const int spline_index,
+ const int vertex_index,
+ const float scaling_factor) const
+{
+ const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index));
+ float3 r_coord;
+ const BPoint &bpoint = nurb->bp[vertex_index];
+ copy_v3_v3(r_coord, bpoint.vec);
+ mul_m4_v3(world_axes_transform_, r_coord);
+ mul_v3_fl(r_coord, scaling_factor);
+ return r_coord;
+}
+
+int OBJCurve::total_spline_control_points(const int spline_index) const
+{
+ const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index));
+ const int r_nurbs_degree = nurb->orderu - 1;
+ /* Total control points = Number of points in the curve (+ degree of the
+ * curve if it is cyclic). */
+ int r_tot_control_points = nurb->pntsv * nurb->pntsu;
+ if (nurb->flagu & CU_NURB_CYCLIC) {
+ r_tot_control_points += r_nurbs_degree;
+ }
+ return r_tot_control_points;
+}
+
+int OBJCurve::get_nurbs_degree(const int spline_index) const
+{
+ const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index));
+ return nurb->orderu - 1;
+}
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
new file mode 100644
index 00000000000..0c71c3cc09d
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
@@ -0,0 +1,72 @@
+/*
+ * 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 obj
+ */
+
+#pragma once
+
+#include "BLI_utility_mixins.hh"
+
+#include "DNA_curve_types.h"
+
+namespace blender::io::obj {
+
+/**
+ * Provides access to the a Curve Object's properties.
+ * Only #CU_NURBS type is supported.
+ *
+ * \note Used for Curves to be exported in parameter form, and not converted to meshes.
+ */
+class OBJCurve : NonCopyable {
+ private:
+ const Object *export_object_eval_;
+ const Curve *export_curve_;
+ float world_axes_transform_[4][4];
+
+ public:
+ OBJCurve(const Depsgraph *depsgraph, const OBJExportParams &export_params, Object *curve_object);
+
+ const char *get_curve_name() const;
+ int total_splines() const;
+ /**
+ * \param spline_index: Zero-based index of spline of interest.
+ * \return: Total vertices in a spline.
+ */
+ int total_spline_vertices(int spline_index) const;
+ /**
+ * Get coordinates of the vertex at the given index on the given spline.
+ */
+ float3 vertex_coordinates(int spline_index, int vertex_index, float scaling_factor) const;
+ /**
+ * Get total control points of the NURBS spline at the given index. This is different than total
+ * vertices of a spline.
+ */
+ int total_spline_control_points(int spline_index) const;
+ /**
+ * Get the degree of the NURBS spline at the given index.
+ */
+ int get_nurbs_degree(int spline_index) const;
+
+ private:
+ /**
+ * Set the final transform after applying axes settings and an Object's world transform.
+ */
+ void set_world_axes_transform(eTransformAxisForward forward, eTransformAxisUp up);
+};
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
new file mode 100644
index 00000000000..0c753ccdcac
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
@@ -0,0 +1,291 @@
+/*
+ * 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 obj
+ */
+
+#include <cstdio>
+#include <exception>
+#include <memory>
+
+#include "BKE_scene.h"
+
+#include "BLI_path_util.h"
+#include "BLI_vector.hh"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_scene_types.h"
+
+#include "ED_object.h"
+
+#include "obj_export_mesh.hh"
+#include "obj_export_nurbs.hh"
+#include "obj_exporter.hh"
+
+#include "obj_export_file_writer.hh"
+
+namespace blender::io::obj {
+
+OBJDepsgraph::OBJDepsgraph(const bContext *C, const eEvaluationMode eval_mode)
+{
+ Scene *scene = CTX_data_scene(C);
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ if (eval_mode == DAG_EVAL_RENDER) {
+ depsgraph_ = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
+ needs_free_ = true;
+ DEG_graph_build_for_all_objects(depsgraph_);
+ BKE_scene_graph_evaluated_ensure(depsgraph_, bmain);
+ }
+ else {
+ depsgraph_ = CTX_data_ensure_evaluated_depsgraph(C);
+ needs_free_ = false;
+ }
+}
+
+OBJDepsgraph::~OBJDepsgraph()
+{
+ if (needs_free_) {
+ DEG_graph_free(depsgraph_);
+ }
+}
+
+Depsgraph *OBJDepsgraph::get()
+{
+ return depsgraph_;
+}
+
+void OBJDepsgraph::update_for_newframe()
+{
+ BKE_scene_graph_update_for_newframe(depsgraph_);
+}
+
+static void print_exception_error(const std::system_error &ex)
+{
+ std::cerr << ex.code().category().name() << ": " << ex.what() << ": " << ex.code().message()
+ << std::endl;
+}
+
+/**
+ * Filter supported objects from the Scene.
+ *
+ * \note Curves are also stored with Meshes if export settings specify so.
+ */
+std::pair<Vector<std::unique_ptr<OBJMesh>>, Vector<std::unique_ptr<OBJCurve>>>
+filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_params)
+{
+ Vector<std::unique_ptr<OBJMesh>> r_exportable_meshes;
+ Vector<std::unique_ptr<OBJCurve>> r_exportable_nurbs;
+ const int deg_objects_visibility_flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI;
+ DEG_OBJECT_ITER_BEGIN (depsgraph, object, deg_objects_visibility_flags) {
+ if (export_params.export_selected_objects && !(object->base_flag & BASE_SELECTED)) {
+ continue;
+ }
+ switch (object->type) {
+ case OB_SURF:
+ /* Export in mesh form: vertices and polygons. */
+ ATTR_FALLTHROUGH;
+ case OB_MESH:
+ r_exportable_meshes.append(std::make_unique<OBJMesh>(depsgraph, export_params, object));
+ break;
+ case OB_CURVE: {
+ Curve *curve = static_cast<Curve *>(object->data);
+ Nurb *nurb{static_cast<Nurb *>(curve->nurb.first)};
+ if (!nurb) {
+ /* An empty curve. Not yet supported to export these as meshes. */
+ if (export_params.export_curves_as_nurbs) {
+ r_exportable_nurbs.append(
+ std::make_unique<OBJCurve>(depsgraph, export_params, object));
+ }
+ break;
+ }
+ switch (nurb->type) {
+ case CU_NURBS:
+ if (export_params.export_curves_as_nurbs) {
+ /* Export in parameter form: control points. */
+ r_exportable_nurbs.append(
+ std::make_unique<OBJCurve>(depsgraph, export_params, object));
+ }
+ else {
+ /* Export in mesh form: edges and vertices. */
+ r_exportable_meshes.append(
+ std::make_unique<OBJMesh>(depsgraph, export_params, object));
+ }
+ break;
+ case CU_BEZIER:
+ /* Always export in mesh form: edges and vertices. */
+ r_exportable_meshes.append(
+ std::make_unique<OBJMesh>(depsgraph, export_params, object));
+ break;
+ default:
+ /* Other curve types are not supported. */
+ break;
+ }
+ break;
+ }
+ default:
+ /* Other object types are not supported. */
+ break;
+ }
+ }
+ DEG_OBJECT_ITER_END;
+ return {std::move(r_exportable_meshes), std::move(r_exportable_nurbs)};
+}
+
+static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_mesh,
+ OBJWriter &obj_writer,
+ MTLWriter *mtl_writer,
+ const OBJExportParams &export_params)
+{
+ if (mtl_writer) {
+ obj_writer.write_mtllib_name(mtl_writer->mtl_file_path());
+ }
+
+ /* Smooth groups and UV vertex indices may make huge memory allocations, so they should be freed
+ * right after they're written, instead of waiting for #blender::Vector to clean them up after
+ * all the objects are exported. */
+ for (auto &obj_mesh : exportable_as_mesh) {
+ obj_writer.write_object_name(*obj_mesh);
+ obj_writer.write_vertex_coords(*obj_mesh);
+ Vector<int> obj_mtlindices;
+
+ if (obj_mesh->tot_polygons() > 0) {
+ if (export_params.export_smooth_groups) {
+ obj_mesh->calc_smooth_groups(export_params.smooth_groups_bitflags);
+ }
+ if (export_params.export_normals) {
+ obj_writer.write_poly_normals(*obj_mesh);
+ }
+ if (export_params.export_uv) {
+ obj_writer.write_uv_coords(*obj_mesh);
+ }
+ if (mtl_writer) {
+ obj_mtlindices = mtl_writer->add_materials(*obj_mesh);
+ }
+ /* This function takes a 0-indexed slot index for the obj_mesh object and
+ * returns the material name that we are using in the .obj file for it. */
+ std::function<const char *(int)> matname_fn = [&](int s) -> const char * {
+ if (!mtl_writer || s < 0 || s >= obj_mtlindices.size()) {
+ return nullptr;
+ }
+ return mtl_writer->mtlmaterial_name(obj_mtlindices[s]);
+ };
+ obj_writer.write_poly_elements(*obj_mesh, matname_fn);
+ }
+ obj_writer.write_edges_indices(*obj_mesh);
+
+ obj_writer.update_index_offsets(*obj_mesh);
+ }
+}
+
+/**
+ * Export NURBS Curves in parameter form, not as vertices and edges.
+ */
+static void write_nurbs_curve_objects(const Vector<std::unique_ptr<OBJCurve>> &exportable_as_nurbs,
+ const OBJWriter &obj_writer)
+{
+ /* #OBJCurve doesn't have any dynamically allocated memory, so it's fine
+ * to wait for #blender::Vector to clean the objects up. */
+ for (const std::unique_ptr<OBJCurve> &obj_curve : exportable_as_nurbs) {
+ obj_writer.write_nurbs_curve(*obj_curve);
+ }
+}
+
+void export_frame(Depsgraph *depsgraph, const OBJExportParams &export_params, const char *filepath)
+{
+ std::unique_ptr<OBJWriter> frame_writer = nullptr;
+ try {
+ frame_writer = std::make_unique<OBJWriter>(filepath, export_params);
+ }
+ catch (const std::system_error &ex) {
+ print_exception_error(ex);
+ return;
+ }
+ if (!frame_writer) {
+ BLI_assert(!"File should be writable by now.");
+ return;
+ }
+ std::unique_ptr<MTLWriter> mtl_writer = nullptr;
+ if (export_params.export_materials) {
+ try {
+ mtl_writer = std::make_unique<MTLWriter>(export_params.filepath);
+ }
+ catch (const std::system_error &ex) {
+ print_exception_error(ex);
+ }
+ }
+
+ frame_writer->write_header();
+
+ auto [exportable_as_mesh, exportable_as_nurbs] = filter_supported_objects(depsgraph,
+ export_params);
+
+ write_mesh_objects(
+ std::move(exportable_as_mesh), *frame_writer, mtl_writer.get(), export_params);
+ if (mtl_writer) {
+ mtl_writer->write_header(export_params.blen_filepath);
+ mtl_writer->write_materials();
+ }
+ write_nurbs_curve_objects(std::move(exportable_as_nurbs), *frame_writer);
+}
+
+bool append_frame_to_filename(const char *filepath, const int frame, char *r_filepath_with_frames)
+{
+ BLI_strncpy(r_filepath_with_frames, filepath, FILE_MAX);
+ BLI_path_extension_replace(r_filepath_with_frames, FILE_MAX, "");
+ const int digits = frame == 0 ? 1 : integer_digits_i(abs(frame));
+ BLI_path_frame(r_filepath_with_frames, frame, digits);
+ return BLI_path_extension_replace(r_filepath_with_frames, FILE_MAX, ".obj");
+}
+
+void exporter_main(bContext *C, const OBJExportParams &export_params)
+{
+ ED_object_mode_set(C, OB_MODE_OBJECT);
+ OBJDepsgraph obj_depsgraph(C, export_params.export_eval_mode);
+ Scene *scene = DEG_get_input_scene(obj_depsgraph.get());
+ const char *filepath = export_params.filepath;
+
+ /* Single frame export, i.e. no animation. */
+ if (!export_params.export_animation) {
+ fprintf(stderr, "Writing to %s\n", filepath);
+ export_frame(obj_depsgraph.get(), export_params, filepath);
+ return;
+ }
+
+ char filepath_with_frames[FILE_MAX];
+ /* Used to reset the Scene to its original state. */
+ const int original_frame = CFRA;
+
+ for (int frame = export_params.start_frame; frame <= export_params.end_frame; frame++) {
+ const bool filepath_ok = append_frame_to_filename(filepath, frame, filepath_with_frames);
+ if (!filepath_ok) {
+ fprintf(stderr, "Error: File Path too long.\n%s\n", filepath_with_frames);
+ return;
+ }
+
+ CFRA = frame;
+ obj_depsgraph.update_for_newframe();
+ fprintf(stderr, "Writing to %s\n", filepath_with_frames);
+ export_frame(obj_depsgraph.get(), export_params, filepath_with_frames);
+ }
+ CFRA = original_frame;
+}
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.hh b/source/blender/io/wavefront_obj/exporter/obj_exporter.hh
new file mode 100644
index 00000000000..a06898a21cf
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.hh
@@ -0,0 +1,101 @@
+/*
+ * 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 obj
+ */
+
+#pragma once
+
+#include "BLI_utility_mixins.hh"
+
+#include "BLI_vector.hh"
+
+#include "IO_wavefront_obj.h"
+
+namespace blender::io::obj {
+
+/**
+ * Behaves like `std::unique_ptr<Depsgraph, custom_deleter>`.
+ * Needed to free a new Depsgraph created for #DAG_EVAL_RENDER.
+ */
+class OBJDepsgraph : NonMovable, NonCopyable {
+ private:
+ Depsgraph *depsgraph_ = nullptr;
+ bool needs_free_ = false;
+
+ public:
+ OBJDepsgraph(const bContext *C, eEvaluationMode eval_mode);
+ ~OBJDepsgraph();
+
+ Depsgraph *get();
+ void update_for_newframe();
+};
+
+/**
+ * The main function for exporting a .obj file according to the given `export_parameters`.
+ * It uses the context `C` to get the dependency graph, and from that, the `Scene`.
+ * Depending on whether or not `export_params.export_animation` is set, it writes
+ * either one file per animation frame, or just one file.
+ */
+/**
+ * Central internal function to call Scene update & writer functions.
+ */
+void exporter_main(bContext *C, const OBJExportParams &export_params);
+
+class OBJMesh;
+class OBJCurve;
+
+/**
+ * Export a single frame of a .obj file, according to the given `export_parameters`.
+ * The frame state is given in `depsgraph`.
+ * The output file name is given by `filepath`.
+ * This function is normally called from `exporter_main`, but is exposed here for testing purposes.
+ */
+/**
+ * Export a single frame to a .OBJ file.
+ *
+ * Conditionally write a .MTL file also.
+ */
+void export_frame(Depsgraph *depsgraph,
+ const OBJExportParams &export_params,
+ const char *filepath);
+
+/**
+ * Find the objects to be exported in the `view_layer` of the dependency graph`depsgraph`,
+ * and return them in vectors `unique_ptr`s of `OBJMesh` and `OBJCurve`.
+ * If `export_params.export_selected_objects` is set, then only selected objects are to be
+ * exported, else all objects are to be exported. But only objects of type `OB_MESH`, `OB_CURVE`,
+ * and `OB_SURF` are supported; the rest will be ignored. If `export_params.export_curves_as_nurbs`
+ * is set, then curves of type `CU_NURBS` are exported in curve form in the .obj file, otherwise
+ * they are converted to mesh and returned in the `OBJMesh` vector. All other exportable types are
+ * always converted to mesh and returned in the `OBJMesh` vector.
+ */
+std::pair<Vector<std::unique_ptr<OBJMesh>>, Vector<std::unique_ptr<OBJCurve>>>
+filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_params);
+
+/**
+ * Makes `r_filepath_with_frames` (which should point at a character array of size `FILE_MAX`)
+ * be `filepath` with its "#" characters replaced by the number representing `frame`, and with
+ * a .obj extension.
+ */
+/**
+ * Append the current frame number in the .OBJ file name.
+ *
+ * \return Whether the filepath is in #FILE_MAX limits.
+ */
+bool append_frame_to_filename(const char *filepath, int frame, char *r_filepath_with_frames);
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
new file mode 100644
index 00000000000..89e1de49511
--- /dev/null
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
@@ -0,0 +1,430 @@
+/* Apache License, Version 2.0 */
+
+#include <gtest/gtest.h>
+#include <ios>
+#include <memory>
+#include <string>
+#include <system_error>
+
+#include "testing/testing.h"
+#include "tests/blendfile_loading_base_test.h"
+
+#include "BKE_appdir.h"
+#include "BKE_blender_version.h"
+
+#include "BLI_fileops.h"
+#include "BLI_index_range.hh"
+#include "BLI_string_utf8.h"
+#include "BLI_vector.hh"
+
+#include "DEG_depsgraph.h"
+
+#include "obj_export_file_writer.hh"
+#include "obj_export_mesh.hh"
+#include "obj_export_nurbs.hh"
+#include "obj_exporter.hh"
+
+#include "obj_exporter_tests.hh"
+
+namespace blender::io::obj {
+/* Set this true to keep comparison-failing test output in temp file directory. */
+constexpr bool save_failing_test_output = false;
+
+/* This is also the test name. */
+class obj_exporter_test : public BlendfileLoadingBaseTest {
+ public:
+ /**
+ * \param filepath: relative to "tests" directory.
+ */
+ bool load_file_and_depsgraph(const std::string &filepath,
+ const eEvaluationMode eval_mode = DAG_EVAL_VIEWPORT)
+ {
+ if (!blendfile_load(filepath.c_str())) {
+ return false;
+ }
+ depsgraph_create(eval_mode);
+ return true;
+ }
+};
+
+const std::string all_objects_file = "io_tests/blend_scene/all_objects.blend";
+const std::string all_curve_objects_file = "io_tests/blend_scene/all_curves.blend";
+
+TEST_F(obj_exporter_test, filter_objects_curves_as_mesh)
+{
+ OBJExportParamsDefault _export;
+ if (!load_file_and_depsgraph(all_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+ auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+ EXPECT_EQ(objmeshes.size(), 19);
+ EXPECT_EQ(objcurves.size(), 0);
+}
+
+TEST_F(obj_exporter_test, filter_objects_curves_as_nurbs)
+{
+ OBJExportParamsDefault _export;
+ if (!load_file_and_depsgraph(all_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+ _export.params.export_curves_as_nurbs = true;
+ auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+ EXPECT_EQ(objmeshes.size(), 18);
+ EXPECT_EQ(objcurves.size(), 2);
+}
+
+TEST_F(obj_exporter_test, filter_objects_selected)
+{
+ OBJExportParamsDefault _export;
+ if (!load_file_and_depsgraph(all_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+ _export.params.export_selected_objects = true;
+ _export.params.export_curves_as_nurbs = true;
+ auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+ EXPECT_EQ(objmeshes.size(), 1);
+ EXPECT_EQ(objcurves.size(), 0);
+}
+
+TEST(obj_exporter_utils, append_negative_frame_to_filename)
+{
+ const char path_original[FILE_MAX] = "/my_file.obj";
+ const char path_truth[FILE_MAX] = "/my_file-123.obj";
+ const int frame = -123;
+ char path_with_frame[FILE_MAX] = {0};
+ const bool ok = append_frame_to_filename(path_original, frame, path_with_frame);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ_ARRAY(path_with_frame, path_truth, BLI_strlen_utf8(path_truth));
+}
+
+TEST(obj_exporter_utils, append_positive_frame_to_filename)
+{
+ const char path_original[FILE_MAX] = "/my_file.obj";
+ const char path_truth[FILE_MAX] = "/my_file123.obj";
+ const int frame = 123;
+ char path_with_frame[FILE_MAX] = {0};
+ const bool ok = append_frame_to_filename(path_original, frame, path_with_frame);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ_ARRAY(path_with_frame, path_truth, BLI_strlen_utf8(path_truth));
+}
+
+TEST_F(obj_exporter_test, curve_nurbs_points)
+{
+ if (!load_file_and_depsgraph(all_curve_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+
+ OBJExportParamsDefault _export;
+ _export.params.export_curves_as_nurbs = true;
+ auto [objmeshes_unused, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+
+ for (auto &objcurve : objcurves) {
+ if (all_nurbs_truth.count(objcurve->get_curve_name()) != 1) {
+ ADD_FAILURE();
+ return;
+ }
+ const NurbsObject *const nurbs_truth = all_nurbs_truth.at(objcurve->get_curve_name()).get();
+ EXPECT_EQ(objcurve->total_splines(), nurbs_truth->total_splines());
+ for (int spline_index : IndexRange(objcurve->total_splines())) {
+ EXPECT_EQ(objcurve->total_spline_vertices(spline_index),
+ nurbs_truth->total_spline_vertices(spline_index));
+ EXPECT_EQ(objcurve->get_nurbs_degree(spline_index),
+ nurbs_truth->get_nurbs_degree(spline_index));
+ EXPECT_EQ(objcurve->total_spline_control_points(spline_index),
+ nurbs_truth->total_spline_control_points(spline_index));
+ }
+ }
+}
+
+TEST_F(obj_exporter_test, curve_coordinates)
+{
+ if (!load_file_and_depsgraph(all_curve_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+
+ OBJExportParamsDefault _export;
+ _export.params.export_curves_as_nurbs = true;
+ auto [objmeshes_unused, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+
+ for (auto &objcurve : objcurves) {
+ if (all_nurbs_truth.count(objcurve->get_curve_name()) != 1) {
+ ADD_FAILURE();
+ return;
+ }
+ const NurbsObject *const nurbs_truth = all_nurbs_truth.at(objcurve->get_curve_name()).get();
+ EXPECT_EQ(objcurve->total_splines(), nurbs_truth->total_splines());
+ for (int spline_index : IndexRange(objcurve->total_splines())) {
+ for (int vertex_index : IndexRange(objcurve->total_spline_vertices(spline_index))) {
+ EXPECT_V3_NEAR(objcurve->vertex_coordinates(
+ spline_index, vertex_index, _export.params.scaling_factor),
+ nurbs_truth->vertex_coordinates(spline_index, vertex_index),
+ 0.000001f);
+ }
+ }
+ }
+}
+
+static std::unique_ptr<OBJWriter> init_writer(const OBJExportParams &params,
+ const std::string out_filepath)
+{
+ try {
+ auto writer = std::make_unique<OBJWriter>(out_filepath.c_str(), params);
+ return writer;
+ }
+ catch (const std::system_error &ex) {
+ std::cerr << ex.code().category().name() << ": " << ex.what() << ": " << ex.code().message()
+ << std::endl;
+ return nullptr;
+ }
+}
+
+/* The following is relative to BKE_tempdir_base.
+ * Use Latin Capital Letter A with Ogonek, Cyrillic Capital Letter Zhe
+ * at the end, to test I/O on non-English file names. */
+const char *const temp_file_path = "output\xc4\x84\xd0\x96.OBJ";
+
+static std::string read_temp_file_in_string(const std::string &file_path)
+{
+ std::string res;
+ size_t buffer_len;
+ void *buffer = BLI_file_read_text_as_mem(file_path.c_str(), 0, &buffer_len);
+ if (buffer != NULL) {
+ res.assign((const char *)buffer, buffer_len);
+ MEM_freeN(buffer);
+ }
+ return res;
+}
+
+TEST(obj_exporter_writer, header)
+{
+ /* Because testing doesn't fully initialize Blender, we need the following. */
+ BKE_tempdir_init(nullptr);
+ std::string out_file_path = blender::tests::flags_test_release_dir() + "/" + temp_file_path;
+ {
+ OBJExportParamsDefault _export;
+ std::unique_ptr<OBJWriter> writer = init_writer(_export.params, out_file_path);
+ if (!writer) {
+ ADD_FAILURE();
+ return;
+ }
+ writer->write_header();
+ }
+ const std::string result = read_temp_file_in_string(out_file_path);
+ using namespace std::string_literals;
+ ASSERT_EQ(result, "# Blender "s + BKE_blender_version_string() + "\n" + "# www.blender.org\n");
+ BLI_delete(out_file_path.c_str(), false, false);
+}
+
+TEST(obj_exporter_writer, mtllib)
+{
+ std::string out_file_path = blender::tests::flags_test_release_dir() + "/" + temp_file_path;
+ {
+ OBJExportParamsDefault _export;
+ std::unique_ptr<OBJWriter> writer = init_writer(_export.params, out_file_path);
+ if (!writer) {
+ ADD_FAILURE();
+ return;
+ }
+ writer->write_mtllib_name("/Users/blah.mtl");
+ writer->write_mtllib_name("\\C:\\blah.mtl");
+ }
+ const std::string result = read_temp_file_in_string(out_file_path);
+ ASSERT_EQ(result, "mtllib blah.mtl\nmtllib blah.mtl\n");
+ BLI_delete(out_file_path.c_str(), false, false);
+}
+
+/* Return true if string #a and string #b are equal after their first newline. */
+static bool strings_equal_after_first_lines(const std::string &a, const std::string &b)
+{
+ /* If `dbg_level` is true then a failing test will print context around the first mismatch. */
+ const bool dbg_level = false;
+ const size_t a_len = a.size();
+ const size_t b_len = b.size();
+ const size_t a_next = a.find_first_of('\n');
+ const size_t b_next = b.find_first_of('\n');
+ if (a_next == std::string::npos || b_next == std::string::npos) {
+ if (dbg_level) {
+ std::cout << "Couldn't find newline in one of args\n";
+ }
+ return false;
+ }
+ if (dbg_level) {
+ if (a.compare(a_next, a_len - a_next, b, b_next, b_len - b_next) != 0) {
+ for (int i = 0; i < a_len - a_next && i < b_len - b_next; ++i) {
+ if (a[a_next + i] != b[b_next + i]) {
+ std::cout << "Difference found at pos " << a_next + i << " of a\n";
+ std::cout << "a: " << a.substr(a_next + i, 100) << " ...\n";
+ std::cout << "b: " << b.substr(b_next + i, 100) << " ... \n";
+ return false;
+ }
+ }
+ }
+ else {
+ return true;
+ }
+ }
+ return a.compare(a_next, a_len - a_next, b, b_next, b_len - b_next) == 0;
+}
+
+/* From here on, tests are whole file tests, testing for golden output. */
+class obj_exporter_regression_test : public obj_exporter_test {
+ public:
+ /**
+ * Export the given blend file with the given parameters and
+ * test to see if it matches a golden file (ignoring any difference in Blender version number).
+ * \param blendfile: input, relative to "tests" directory.
+ * \param golden_obj: expected output, relative to "tests" directory.
+ * \param params: the parameters to be used for export.
+ */
+ void compare_obj_export_to_golden(const std::string &blendfile,
+ const std::string &golden_obj,
+ const std::string &golden_mtl,
+ OBJExportParams &params)
+ {
+ if (!load_file_and_depsgraph(blendfile)) {
+ return;
+ }
+ /* Because testing doesn't fully initialize Blender, we need the following. */
+ BKE_tempdir_init(nullptr);
+ std::string tempdir = std::string(BKE_tempdir_base());
+ std::string out_file_path = tempdir + BLI_path_basename(golden_obj.c_str());
+ strncpy(params.filepath, out_file_path.c_str(), FILE_MAX - 1);
+ params.blen_filepath = blendfile.c_str();
+ export_frame(depsgraph, params, out_file_path.c_str());
+ std::string output_str = read_temp_file_in_string(out_file_path);
+
+ std::string golden_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_obj;
+ std::string golden_str = read_temp_file_in_string(golden_file_path);
+ bool are_equal = strings_equal_after_first_lines(output_str, golden_str);
+ if (save_failing_test_output && !are_equal) {
+ printf("failing test output in %s\n", out_file_path.c_str());
+ }
+ ASSERT_TRUE(are_equal);
+ if (!save_failing_test_output || are_equal) {
+ BLI_delete(out_file_path.c_str(), false, false);
+ }
+ if (!golden_mtl.empty()) {
+ std::string out_mtl_file_path = tempdir + BLI_path_basename(golden_mtl.c_str());
+ std::string output_mtl_str = read_temp_file_in_string(out_mtl_file_path);
+ std::string golden_mtl_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_mtl;
+ std::string golden_mtl_str = read_temp_file_in_string(golden_mtl_file_path);
+ ASSERT_TRUE(strings_equal_after_first_lines(output_mtl_str, golden_mtl_str));
+ BLI_delete(out_mtl_file_path.c_str(), false, false);
+ }
+ }
+};
+
+TEST_F(obj_exporter_regression_test, all_tris)
+{
+ OBJExportParamsDefault _export;
+ compare_obj_export_to_golden("io_tests/blend_geometry/all_tris.blend",
+ "io_tests/obj/all_tris.obj",
+ "io_tests/obj/all_tris.mtl",
+ _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, all_quads)
+{
+ OBJExportParamsDefault _export;
+ _export.params.scaling_factor = 2.0f;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/all_quads.blend", "io_tests/obj/all_quads.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, fgons)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/fgons.blend", "io_tests/obj/fgons.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, edges)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/edges.blend", "io_tests/obj/edges.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, vertices)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/vertices.blend", "io_tests/obj/vertices.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, nurbs_as_nurbs)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ _export.params.export_curves_as_nurbs = true;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/nurbs.blend", "io_tests/obj/nurbs.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, nurbs_as_mesh)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ _export.params.export_curves_as_nurbs = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/nurbs.blend", "io_tests/obj/nurbs_mesh.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, cube_all_data_triangulated)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ _export.params.export_triangulated_mesh = true;
+ compare_obj_export_to_golden("io_tests/blend_geometry/cube_all_data.blend",
+ "io_tests/obj/cube_all_data_triangulated.obj",
+ "",
+ _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, suzanne_all_data)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ _export.params.export_smooth_groups = true;
+ compare_obj_export_to_golden("io_tests/blend_geometry/suzanne_all_data.blend",
+ "io_tests/obj/suzanne_all_data.obj",
+ "",
+ _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, all_objects)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_smooth_groups = true;
+ compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend",
+ "io_tests/obj/all_objects.obj",
+ "io_tests/obj/all_objects.mtl",
+ _export.params);
+}
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
new file mode 100644
index 00000000000..c101081ca54
--- /dev/null
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
@@ -0,0 +1,149 @@
+/* Apache License, Version 2.0 */
+
+/**
+ * This file contains default values for several items like
+ * vertex coordinates, export parameters, MTL values etc.
+ */
+
+#pragma once
+
+#include <array>
+#include <gtest/gtest.h>
+#include <string>
+#include <vector>
+
+#include "IO_wavefront_obj.h"
+
+namespace blender::io::obj {
+
+using array_float_3 = std::array<float, 3>;
+
+/**
+ * This matches #OBJCurve's member functions, except that all the numbers and names are known
+ * constants. Used to store expected values of NURBS curves objects.
+ */
+class NurbsObject {
+ private:
+ std::string nurbs_name_;
+ /* The indices in these vectors are spline indices. */
+ std::vector<std::vector<array_float_3>> coordinates_;
+ std::vector<int> degrees_;
+ std::vector<int> control_points_;
+
+ public:
+ NurbsObject(const std::string nurbs_name,
+ const std::vector<std::vector<array_float_3>> coordinates,
+ const std::vector<int> degrees,
+ const std::vector<int> control_points)
+ : nurbs_name_(nurbs_name),
+ coordinates_(coordinates),
+ degrees_(degrees),
+ control_points_(control_points)
+ {
+ }
+
+ int total_splines() const
+ {
+ return coordinates_.size();
+ }
+
+ int total_spline_vertices(const int spline_index) const
+ {
+ if (spline_index >= coordinates_.size()) {
+ ADD_FAILURE();
+ return 0;
+ }
+ return coordinates_[spline_index].size();
+ }
+
+ const float *vertex_coordinates(const int spline_index, const int vertex_index) const
+ {
+ return coordinates_[spline_index][vertex_index].data();
+ }
+
+ int get_nurbs_degree(const int spline_index) const
+ {
+ return degrees_[spline_index];
+ }
+
+ int total_spline_control_points(const int spline_index) const
+ {
+ return control_points_[spline_index];
+ }
+};
+
+struct OBJExportParamsDefault {
+ OBJExportParams params;
+ OBJExportParamsDefault()
+ {
+ params.filepath[0] = '\0';
+ params.blen_filepath = "";
+ params.export_animation = false;
+ params.start_frame = 0;
+ params.end_frame = 1;
+
+ params.forward_axis = OBJ_AXIS_NEGATIVE_Z_FORWARD;
+ params.up_axis = OBJ_AXIS_Y_UP;
+ params.scaling_factor = 1.f;
+
+ params.export_eval_mode = DAG_EVAL_VIEWPORT;
+ params.export_selected_objects = false;
+ params.export_uv = true;
+ params.export_normals = true;
+ params.export_materials = true;
+ params.export_triangulated_mesh = false;
+ params.export_curves_as_nurbs = false;
+
+ params.export_object_groups = false;
+ params.export_material_groups = false;
+ params.export_vertex_groups = false;
+ params.export_smooth_groups = true;
+ params.smooth_groups_bitflags = false;
+ }
+};
+
+const std::vector<std::vector<array_float_3>> coordinates_NurbsCurve{
+ {{6.94742, 0.000000, 0.000000},
+ {7.44742, 0.000000, -1.000000},
+ {9.44742, 0.000000, -1.000000},
+ {9.94742, 0.000000, 0.000000}}};
+const std::vector<std::vector<array_float_3>> coordinates_NurbsCircle{
+ {{11.463165, 0.000000, 1.000000},
+ {10.463165, 0.000000, 1.000000},
+ {10.463165, 0.000000, 0.000000},
+ {10.463165, 0.000000, -1.000000},
+ {11.463165, 0.000000, -1.000000},
+ {12.463165, 0.000000, -1.000000},
+ {12.463165, 0.000000, 0.000000},
+ {12.463165, 0.000000, 1.000000}}};
+const std::vector<std::vector<array_float_3>> coordinates_NurbsPathCurve{
+ {{13.690557, 0.000000, 0.000000},
+ {14.690557, 0.000000, 0.000000},
+ {15.690557, 0.000000, 0.000000},
+ {16.690557, 0.000000, 0.000000},
+ {17.690557, 0.000000, 0.000000}},
+ {{14.192808, 0.000000, 0.000000},
+ {14.692808, 0.000000, -1.000000},
+ {16.692808, 0.000000, -1.000000},
+ {17.192808, 0.000000, 0.000000}}};
+
+const std::map<std::string, std::unique_ptr<NurbsObject>> all_nurbs_truth = []() {
+ std::map<std::string, std::unique_ptr<NurbsObject>> all_nurbs;
+ all_nurbs.emplace(
+ "NurbsCurve",
+ /* Name, coordinates, degrees of splines, control points of splines. */
+ std::make_unique<NurbsObject>(
+ "NurbsCurve", coordinates_NurbsCurve, std::vector<int>{3}, std::vector<int>{4}));
+ all_nurbs.emplace(
+ "NurbsCircle",
+ std::make_unique<NurbsObject>(
+ "NurbsCircle", coordinates_NurbsCircle, std::vector<int>{3}, std::vector<int>{11}));
+ /* This is actually an Object containing a NurbsPath and a NurbsCurve spline. */
+ all_nurbs.emplace("NurbsPathCurve",
+ std::make_unique<NurbsObject>("NurbsPathCurve",
+ coordinates_NurbsPathCurve,
+ std::vector<int>{3, 3},
+ std::vector<int>{5, 4}));
+ return all_nurbs;
+}();
+} // namespace blender::io::obj
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index d829d707a71..060b55ffe5c 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -147,17 +147,18 @@ typedef struct IDProperty {
#define DEFAULT_ALLOC_FOR_NULL_STRINGS 64
/*->type*/
-enum {
+typedef enum eIDPropertyType {
IDP_STRING = 0,
IDP_INT = 1,
IDP_FLOAT = 2,
+ /** Array containing int, floats, doubles or groups. */
IDP_ARRAY = 5,
IDP_GROUP = 6,
IDP_ID = 7,
IDP_DOUBLE = 8,
IDP_IDPARRAY = 9,
- IDP_NUMTYPES = 10,
-};
+} eIDPropertyType;
+#define IDP_NUMTYPES 10
/** Used by some IDP utils, keep values in sync with type enum above. */
enum {
@@ -211,11 +212,15 @@ typedef struct IDOverrideLibraryPropertyOperation {
char _pad0[2];
/* Sub-item references, if needed (for arrays or collections only).
- * We need both reference and local values to allow e.g. insertion into collections
+ * We need both reference and local values to allow e.g. insertion into RNA collections
* (constraints, modifiers...).
- * In collection case, if names are defined, they are used in priority.
- * Names are pointers (instead of char[64]) to save some space, NULL when unset.
- * Indices are -1 when unset. */
+ * In RNA collection case, if names are defined, they are used in priority.
+ * Names are pointers (instead of char[64]) to save some space, NULL or empty string when unset.
+ * Indices are -1 when unset.
+ *
+ * NOTE: For insertion operations in RNA collections, reference may not actually exist in the
+ * linked reference data. It is used to identify the anchor of the insertion operation (i.e. the
+ * item after or before which the new local item should be inserted), in the local override. */
char *subitem_reference_name;
char *subitem_local_name;
int subitem_reference_index;
@@ -311,8 +316,22 @@ typedef struct IDOverrideLibrary {
struct ID *storage;
IDOverrideLibraryRuntime *runtime;
+
+ void *_pad_0;
+
+ unsigned int flag;
+ char _pad_1[4];
} IDOverrideLibrary;
+/* IDOverrideLibrary->flag */
+enum {
+ /**
+ * The override data-block should not be considered as part of an override hierarchy (generally
+ * because it was created as an single override, outside of any hierarchy consideration).
+ */
+ IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY = 1 << 0,
+};
+
/* watch it: Sequence has identical beginning. */
/**
* ID is the first thing included in all serializable types. It
@@ -427,12 +446,21 @@ typedef struct Library {
struct PackedFile *packedfile;
+ ushort tag;
+ char _pad_0[6];
+
/* Temp data needed by read/write code, and liboverride recursive resync. */
int temp_index;
/** See BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION, needed for do_versions. */
short versionfile, subversionfile;
} Library;
+/* Library.tag */
+enum eLibrary_Tag {
+ /* Automatic recursive resync was needed when linking/loading data from that library. */
+ LIBRARY_TAG_RESYNC_REQUIRED = 1 << 0,
+};
+
/**
* A weak library/ID reference for local data that has been appended, to allow re-using that local
* data instead of creating a new copy of it in future appends.
@@ -457,7 +485,7 @@ typedef struct LibraryWeakReference {
enum ePreviewImage_Flag {
PRV_CHANGED = (1 << 0),
PRV_USER_EDITED = (1 << 1), /* if user-edited, do not auto-update this anymore! */
- PRV_UNFINISHED = (1 << 2), /* The preview is not done rendering yet. */
+ PRV_RENDERING = (1 << 2), /* Rendering was invoked. Cleared on file read. */
};
/* for PreviewImage->tag */
@@ -798,6 +826,9 @@ typedef enum IDRecalcFlag {
*/
ID_RECALC_TAG_FOR_UNDO = (1 << 24),
+ /* The node tree has changed in a way that affects its output nodes. */
+ ID_RECALC_NTREE_OUTPUT = (1 << 25),
+
/***************************************************************************
* Pseudonyms, to have more semantic meaning in the actual code without
* using too much low-level and implementation specific tags. */
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index e899e6bd3ec..82b20483902 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -468,7 +468,7 @@ typedef enum eRotationModes {
typedef struct bPose {
/** List of pose channels, PoseBones in RNA. */
ListBase chanbase;
- /** Ghash for quicker string lookups. */
+ /** Use a hash-table for quicker string lookups. */
struct GHash *chanhash;
/* Flat array of pose channels. It references pointers from
@@ -682,6 +682,10 @@ typedef struct bAction {
int idroot;
char _pad[4];
+ /** Start and end of the manually set intended playback frame range. Used by UI and
+ * some editing tools, but doesn't directly affect animation evaluation in any way. */
+ float frame_start, frame_end;
+
PreviewImage *preview;
} bAction;
@@ -695,6 +699,10 @@ typedef enum eAction_Flags {
ACT_MUTED = (1 << 9),
/* ACT_PROTECTED = (1 << 10), */ /* UNUSED */
/* ACT_DISABLED = (1 << 11), */ /* UNUSED */
+ /** The action has a manually set intended playback frame range. */
+ ACT_FRAME_RANGE = (1 << 12),
+ /** The action is intended to be a cycle (requires ACT_FRAME_RANGE). */
+ ACT_CYCLIC = (1 << 13),
} eAction_Flags;
/* ************************************************ */
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 5dbed6b4d24..bd9f9d8ec3d 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -348,7 +348,7 @@ typedef enum eDriverTarget_Flag {
/** idtype can only be 'Object' */
DTAR_FLAG_ID_OB_ONLY = (1 << 1),
- /* "localspace" flags */
+ /* "local-space" flags. */
/** base flag - basically "pre parent+constraints" */
DTAR_FLAG_LOCALSPACE = (1 << 2),
/** include constraints transformed to space including parents */
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index 3b65378f9eb..566ffd19669 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -124,11 +124,11 @@ typedef struct bArmature {
ListBase bonebase;
- /** Ghash for quicker lookups of bones by name. */
+ /** Use a hash-table for quicker lookups of bones by name. */
struct GHash *bonehash;
void *_pad1;
- /** Editbone listbase, we use pointer so we can check state. */
+ /** #EditBone list (use an allocated pointer so the state can be checked). */
ListBase *edbo;
/* active bones should work like active object where possible
diff --git a/source/blender/makesdna/DNA_asset_types.h b/source/blender/makesdna/DNA_asset_types.h
index f5bdad3e79e..bd604b90b5a 100644
--- a/source/blender/makesdna/DNA_asset_types.h
+++ b/source/blender/makesdna/DNA_asset_types.h
@@ -56,6 +56,9 @@ typedef struct AssetFilterSettings {
* more than that from the file. So pointers to other IDs or ID data are strictly forbidden.
*/
typedef struct AssetMetaData {
+ /** Runtime type, to reference event callbacks. Only valid for local assets. */
+ struct AssetTypeInfo *local_type_info;
+
/** Custom asset meta-data. Cannot store pointers to IDs (#STRUCT_NO_DATABLOCK_IDPROPERTIES)! */
struct IDProperty *properties;
@@ -72,8 +75,12 @@ typedef struct AssetMetaData {
* #catalog_id is updated. */
char catalog_simple_name[64]; /* MAX_NAME */
+ /** Optional name of the author for display in the UI. Dynamic length. */
+ char *author;
+
/** Optional description of this asset for display in the UI. Dynamic length. */
char *description;
+
/** User defined tags for this asset. The asset manager uses these for filtering, but how they
* function exactly (e.g. how they are registered to provide a list of searchable available tags)
* is up to the asset-engine. */
diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h
index 72b2db89cef..2f41389f2c6 100644
--- a/source/blender/makesdna/DNA_brush_enums.h
+++ b/source/blender/makesdna/DNA_brush_enums.h
@@ -522,7 +522,7 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_SLIDE_RELAX, \
SCULPT_TOOL_MASK) == 0)
-/* ImagePaintSettings.tool */
+/** #ImagePaintSettings.tool */
typedef enum eBrushImagePaintTool {
PAINT_TOOL_DRAW = 0,
PAINT_TOOL_SOFTEN = 1,
@@ -532,6 +532,9 @@ typedef enum eBrushImagePaintTool {
PAINT_TOOL_MASK = 5,
} eBrushImagePaintTool;
+/* The enums here should be kept in sync with the weight paint tool.
+ * This is because #smooth_brush_toggle_on and #smooth_brush_toggle_off
+ * assumes that the blur brush has the same enum value. */
typedef enum eBrushVertexPaintTool {
VPAINT_TOOL_DRAW = 0,
VPAINT_TOOL_BLUR = 1,
@@ -539,6 +542,7 @@ typedef enum eBrushVertexPaintTool {
VPAINT_TOOL_SMEAR = 3,
} eBrushVertexPaintTool;
+/* See #eBrushVertexPaintTool when changing this definition. */
typedef enum eBrushWeightPaintTool {
WPAINT_TOOL_DRAW = 0,
WPAINT_TOOL_BLUR = 1,
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 634ebdff253..4976168a890 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -123,7 +123,7 @@ typedef struct BrushGpencilSettings {
int sculpt_mode_flag;
/** Preset type (used to reset brushes - internal). */
short preset_type;
- /** Brush preselected mode (Active/Material/Vertexcolor). */
+ /** Brush preselected mode (Active/Material/Vertex-color). */
short brush_draw_mode;
/** Randomness for Hue. */
diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h
index 0f4c53a6e7e..65e1dd6c096 100644
--- a/source/blender/makesdna/DNA_cachefile_types.h
+++ b/source/blender/makesdna/DNA_cachefile_types.h
@@ -59,6 +59,18 @@ typedef struct CacheObjectPath {
char path[4096];
} CacheObjectPath;
+/* CacheFileLayer::flag */
+enum { CACHEFILE_LAYER_HIDDEN = (1 << 0) };
+
+typedef struct CacheFileLayer {
+ struct CacheFileLayer *next, *prev;
+
+ /** 1024 = FILE_MAX. */
+ char filepath[1024];
+ int flag;
+ int _pad;
+} CacheFileLayer;
+
/* CacheFile::velocity_unit
* Determines what temporal unit is used to interpret velocity vectors for motion blur effects. */
enum {
@@ -73,6 +85,8 @@ typedef struct CacheFile {
/** Paths of the objects inside of the archive referenced by this CacheFile. */
ListBase object_paths;
+ ListBase layers;
+
/** 1024 = FILE_MAX. */
char filepath[1024];
@@ -109,7 +123,10 @@ typedef struct CacheFile {
/** Size in megabytes for the prefetch cache used by the Cycles Procedural. */
int prefetch_cache_size;
- char _pad2[7];
+ /** Index of the currently selected layer in the UI, starts at 1. */
+ int active_layer;
+
+ char _pad2[3];
char velocity_unit;
/* Name of the velocity property in the archive. */
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 28756395f7d..d587bd8082b 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -728,7 +728,7 @@ typedef enum eBConstraint_Flags {
/* bConstraint->ownspace/tarspace */
typedef enum eBConstraint_SpaceTypes {
- /** Default for all - worldspace. */
+ /** Default for all - world-space. */
CONSTRAINT_SPACE_WORLD = 0,
/** For all - custom space. */
CONSTRAINT_SPACE_CUSTOM = 5,
@@ -939,7 +939,7 @@ typedef enum eTrackToAxis_Modes {
/* Shrinkwrap flags */
typedef enum eShrinkwrap_Flags {
- /* Also raycast in the opposite direction. */
+ /* Also ray-cast in the opposite direction. */
CON_SHRINKWRAP_PROJECT_OPPOSITE = (1 << 0),
/* Invert the cull mode when projecting opposite. */
CON_SHRINKWRAP_PROJECT_INVERT_CULL = (1 << 1),
diff --git a/source/blender/makesdna/DNA_curve_defaults.h b/source/blender/makesdna/DNA_curve_defaults.h
index 557615fd047..614653db2b8 100644
--- a/source/blender/makesdna/DNA_curve_defaults.h
+++ b/source/blender/makesdna/DNA_curve_defaults.h
@@ -34,7 +34,7 @@
.pathlen = 100, \
.resolu = 12, \
.resolv = 12, \
- .width = 1.0, \
+ .offset = 1.0, \
.wordspace = 1.0, \
.spacing = 1.0f, \
.linedist = 1.0, \
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index a2433dbbbbd..c1c8fe06121 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -228,16 +228,15 @@ typedef struct Curve {
/** Creation-time type of curve datablock. */
short type;
- /** Keep a short because of BKE_object_obdata_texspace_get(). */
- short texflag;
- char _pad0[6];
+ char texflag;
+ char _pad0[7];
short twist_mode;
float twist_smooth, smallcaps_scale;
int pathlen;
short bevresol, totcol;
int flag;
- float width, ext1, ext2;
+ float offset, extrude, bevel_radius;
/* default */
short resolu, resolv;
@@ -421,10 +420,8 @@ enum {
enum {
CU_POLY = 0,
CU_BEZIER = 1,
- CU_BSPLINE = 2,
- CU_CARDINAL = 3,
CU_NURBS = 4,
- CU_TYPE = (CU_POLY | CU_BEZIER | CU_BSPLINE | CU_CARDINAL | CU_NURBS),
+ CU_TYPE = (CU_POLY | CU_BEZIER | CU_NURBS),
/* only for adding */
CU_PRIMITIVE = 0xF00,
@@ -457,6 +454,8 @@ enum {
typedef enum eBezTriple_Flag {
/* SELECT */
BEZT_FLAG_TEMP_TAG = (1 << 1), /* always clear. */
+ /* Can be used to ignore keyframe points for certain operations. */
+ BEZT_FLAG_IGNORE_TAG = (1 << 2),
} eBezTriple_Flag;
/* h1 h2 (beztriple) */
diff --git a/source/blender/makesdna/DNA_curveprofile_types.h b/source/blender/makesdna/DNA_curveprofile_types.h
index 7c76251adc3..447e94d2659 100644
--- a/source/blender/makesdna/DNA_curveprofile_types.h
+++ b/source/blender/makesdna/DNA_curveprofile_types.h
@@ -29,13 +29,6 @@
extern "C" {
#endif
-/** Number of points in high resolution table is dynamic up to a maximum. */
-#define PROF_TABLE_MAX 512
-/** 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_TABLE_LEN(n_pts) min_ii(PROF_TABLE_MAX, (((n_pts - 1)) * PROF_RESOL) + 1)
-
/**
* Each control point that makes up the profile.
* \note The flags use the same enum as Bezier curves, but they aren't guaranteed
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 36bdd4915ff..629a5e88de7 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -134,17 +134,21 @@ typedef enum CustomDataType {
CD_CLOTH_ORCO = 23,
/* CD_RECAST = 24, */ /* UNUSED */
- /* BMESH ONLY START */
CD_MPOLY = 25,
CD_MLOOP = 26,
CD_SHAPE_KEYINDEX = 27,
CD_SHAPEKEY = 28,
CD_BWEIGHT = 29,
+ /**
+ * Usage of #CD_CREASE depends on where on the Mesh the layer is added:
+ * - For vertex creasing, this is persistent data across all modes and is stored in the file.
+ * - For edge creasing, it is runtime data which is only used in edit-mode before being copied
+ * to #MEdge when exiting edit-mode.
+ */
CD_CREASE = 30,
CD_ORIGSPACE_MLOOP = 31,
CD_PREVIEW_MLOOPCOL = 32,
CD_BM_ELEM_PYPTR = 33,
- /* BMESH ONLY END */
CD_PAINT_MASK = 34,
CD_GRID_PAINT_MASK = 35,
@@ -164,7 +168,6 @@ typedef enum CustomDataType {
CD_PROP_COLOR = 47,
CD_PROP_FLOAT3 = 48,
CD_PROP_FLOAT2 = 49,
-
CD_PROP_BOOL = 50,
CD_HAIRLENGTH = 51,
@@ -197,7 +200,6 @@ typedef enum CustomDataType {
#define CD_MASK_CLOTH_ORCO (1 << CD_CLOTH_ORCO)
// #define CD_MASK_RECAST (1 << CD_RECAST) /* DEPRECATED */
-/* BMESH ONLY START */
#define CD_MASK_MPOLY (1 << CD_MPOLY)
#define CD_MASK_MLOOP (1 << CD_MLOOP)
#define CD_MASK_SHAPE_KEYINDEX (1 << CD_SHAPE_KEYINDEX)
@@ -207,7 +209,6 @@ typedef enum CustomDataType {
#define CD_MASK_ORIGSPACE_MLOOP (1LL << CD_ORIGSPACE_MLOOP)
#define CD_MASK_PREVIEW_MLOOPCOL (1LL << CD_PREVIEW_MLOOPCOL)
#define CD_MASK_BM_ELEM_PYPTR (1LL << CD_BM_ELEM_PYPTR)
-/* BMESH ONLY END */
#define CD_MASK_PAINT_MASK (1LL << CD_PAINT_MASK)
#define CD_MASK_GRID_PAINT_MASK (1LL << CD_GRID_PAINT_MASK)
diff --git a/source/blender/makesdna/DNA_defaults.h b/source/blender/makesdna/DNA_defaults.h
index 1549e33b267..ef7f573e7a8 100644
--- a/source/blender/makesdna/DNA_defaults.h
+++ b/source/blender/makesdna/DNA_defaults.h
@@ -36,7 +36,9 @@ extern "C" {
extern const void *DNA_default_table[SDNA_TYPE_MAX];
-char *_DNA_struct_default_alloc_impl(const char *data_src, size_t size, const char *alloc_str);
+uint8_t *_DNA_struct_default_alloc_impl(const uint8_t *data_src,
+ size_t size,
+ const char *alloc_str);
/**
* Wrap with macro that casts correctly.
@@ -46,7 +48,9 @@ char *_DNA_struct_default_alloc_impl(const char *data_src, size_t size, const ch
#define DNA_struct_default_alloc(struct_name) \
(struct_name *)_DNA_struct_default_alloc_impl( \
- DNA_default_table[SDNA_TYPE_FROM_STRUCT(struct_name)], sizeof(struct_name), __func__)
+ (const uint8_t *)DNA_default_table[SDNA_TYPE_FROM_STRUCT(struct_name)], \
+ sizeof(struct_name), \
+ __func__)
#ifdef __cplusplus
}
diff --git a/source/blender/makesdna/DNA_effect_types.h b/source/blender/makesdna/DNA_effect_types.h
index 3de13169616..2e086a2834c 100644
--- a/source/blender/makesdna/DNA_effect_types.h
+++ b/source/blender/makesdna/DNA_effect_types.h
@@ -27,7 +27,7 @@
extern "C" {
#endif
-/* Don't forget, new effects also in writefile.c for DNA! */
+/* Don't forget, new effects also in `writefile.c` for DNA! */
#define PAF_MAXMULT 4
diff --git a/source/blender/makesdna/DNA_fileglobal_types.h b/source/blender/makesdna/DNA_fileglobal_types.h
index a0285215ff9..3b6fb60cc2e 100644
--- a/source/blender/makesdna/DNA_fileglobal_types.h
+++ b/source/blender/makesdna/DNA_fileglobal_types.h
@@ -50,7 +50,7 @@ typedef struct FileGlobal {
/** Hash from buildinfo. */
char build_hash[16];
/** File path where this was saved, for recover (1024 = FILE_MAX). */
- char filename[1024];
+ char filepath[1024];
} FileGlobal;
/* minversion: in file, the oldest past blender version you can use compliant */
diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h
index 0cbef540306..d8065410f2b 100644
--- a/source/blender/makesdna/DNA_fluid_types.h
+++ b/source/blender/makesdna/DNA_fluid_types.h
@@ -513,7 +513,7 @@ typedef struct FluidDomainSettings {
float p1[3]; /* End point of BB in local space. */
float dp0[3]; /* Difference from object center to grid start point. */
float cell_size[3]; /* Size of simulation cell in local space. */
- float global_size[3]; /* Global size of domain axises. */
+ float global_size[3]; /* Global size of domain axes. */
float prev_loc[3];
int shift[3]; /* Current domain shift in simulation cells. */
float shift_f[3]; /* Exact domain shift. */
@@ -694,7 +694,7 @@ typedef struct FluidDomainSettings {
char openvdb_data_depth;
char _pad11[7]; /* Unused. */
- /* -- Deprecated / unsed options (below). -- */
+ /* -- Deprecated / unused options (below). -- */
/* View options. */
int viewsettings;
diff --git a/source/blender/makesdna/DNA_genfile.h b/source/blender/makesdna/DNA_genfile.h
index fda1cbaeae6..dd118658003 100644
--- a/source/blender/makesdna/DNA_genfile.h
+++ b/source/blender/makesdna/DNA_genfile.h
@@ -83,8 +83,11 @@ enum eSDNA_StructCompare {
SDNA_CMP_UNKNOWN = 3,
};
+/**
+ * Constructs and returns a decoded SDNA structure from the given encoded SDNA data block.
+ */
struct SDNA *DNA_sdna_from_data(const void *data,
- const int data_len,
+ int data_len,
bool do_endian_swap,
bool data_alloc,
const char **r_error_message);
@@ -97,22 +100,58 @@ const struct SDNA *DNA_sdna_current_get(void);
void DNA_sdna_current_free(void);
struct DNA_ReconstructInfo;
+/**
+ * Pre-process information about how structs in \a newsdna can be reconstructed from structs in
+ * \a oldsdna. This information is then used to speedup #DNA_struct_reconstruct.
+ */
struct DNA_ReconstructInfo *DNA_reconstruct_info_create(const struct SDNA *oldsdna,
const struct SDNA *newsdna,
const char *compare_flags);
void DNA_reconstruct_info_free(struct DNA_ReconstructInfo *reconstruct_info);
+/**
+ * Returns the index of the struct info for the struct with the specified name.
+ */
int DNA_struct_find_nr_ex(const struct SDNA *sdna, const char *str, unsigned int *index_last);
int DNA_struct_find_nr(const struct SDNA *sdna, const char *str);
+/**
+ * Does endian swapping on the fields of a struct value.
+ *
+ * \param sdna: SDNA of the struct_nr belongs to
+ * \param struct_nr: Index of struct info within sdna
+ * \param data: Struct data that is to be converted
+ */
void DNA_struct_switch_endian(const struct SDNA *sdna, int struct_nr, char *data);
+/**
+ * Constructs and returns an array of byte flags with one element for each struct in oldsdna,
+ * indicating how it compares to newsdna.
+ */
const char *DNA_struct_get_compareflags(const struct SDNA *sdna, const struct SDNA *newsdna);
+/**
+ * \param reconstruct_info: Information preprocessed by #DNA_reconstruct_info_create.
+ * \param old_struct_nr: Index of struct info within oldsdna.
+ * \param blocks: The number of array elements.
+ * \param old_blocks: Array of struct data.
+ * \return An allocated reconstructed struct.
+ */
void *DNA_struct_reconstruct(const struct DNA_ReconstructInfo *reconstruct_info,
int old_struct_nr,
int blocks,
const void *old_blocks);
+/**
+ * Returns the offset of the field with the specified name and type within the specified
+ * struct type in #SDNA, -1 on failure.
+ */
int DNA_elem_offset(struct SDNA *sdna, const char *stype, const char *vartype, const char *name);
+/**
+ * Returns the size of struct fields of the specified type and name.
+ *
+ * \param type: Index into sdna->types/types_size
+ * \param name: Index into sdna->names,
+ * needed to extract possible pointer/array information.
+ */
int DNA_elem_size_nr(const struct SDNA *sdna, short type, short name);
bool DNA_struct_find(const struct SDNA *sdna, const char *stype);
@@ -121,11 +160,22 @@ bool DNA_struct_elem_find(const struct SDNA *sdna,
const char *vartype,
const char *name);
-int DNA_elem_type_size(const eSDNA_Type elem_nr);
+/**
+ * Returns the size in bytes of a primitive type.
+ */
+int DNA_elem_type_size(eSDNA_Type elem_nr);
+/**
+ * Rename a struct
+ */
bool DNA_sdna_patch_struct(struct SDNA *sdna,
const char *struct_name_old,
const char *struct_name_new);
+/**
+ * Replace \a elem_old with \a elem_new for struct \a struct_name
+ * handles search & replace, maintaining surrounding non-identifier characters
+ * such as pointer & array size.
+ */
bool DNA_sdna_patch_struct_member(struct SDNA *sdna,
const char *struct_name,
const char *elem_old,
@@ -134,14 +184,28 @@ bool DNA_sdna_patch_struct_member(struct SDNA *sdna,
void DNA_sdna_alias_data_ensure(struct SDNA *sdna);
/* Alias lookups (using runtime struct member names). */
+
+/**
+ * \note requires #DNA_sdna_alias_data_ensure_structs_map to be called.
+ */
int DNA_struct_alias_find_nr_ex(const struct SDNA *sdna,
const char *str,
unsigned int *index_last);
+/**
+ * \note requires #DNA_sdna_alias_data_ensure_structs_map to be called.
+ */
int DNA_struct_alias_find_nr(const struct SDNA *sdna, const char *str);
+/**
+ * \note requires #DNA_sdna_alias_data_ensure_structs_map to be called.
+ */
bool DNA_struct_alias_elem_find(const struct SDNA *sdna,
const char *stype,
const char *vartype,
const char *name);
+/**
+ * Separated from #DNA_sdna_alias_data_ensure because it's not needed
+ * unless we want to lookup aliased struct names (#DNA_struct_alias_find_nr and friends).
+ */
void DNA_sdna_alias_data_ensure_structs_map(struct SDNA *sdna);
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
index 11299ae9717..c51a615bfb6 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
@@ -315,10 +315,12 @@
.opacity = 1.0f, \
.flags = LRT_GPENCIL_MATCH_OUTPUT_VGROUP, \
.crease_threshold = DEG2RAD(140.0f), \
- .calculation_flags = LRT_ALLOW_DUPLI_OBJECTS | LRT_ALLOW_CLIPPING_BOUNDARIES | LRT_USE_CREASE_ON_SHARP_EDGES, \
+ .calculation_flags = LRT_ALLOW_DUPLI_OBJECTS | LRT_ALLOW_CLIPPING_BOUNDARIES | \
+ LRT_USE_CREASE_ON_SHARP_EDGES | LRT_FILTER_FACE_MARK_KEEP_CONTOUR, \
.angle_splitting_threshold = DEG2RAD(60.0f), \
.chaining_image_threshold = 0.001f, \
.chain_smooth_tolerance = 0.2f,\
+ .stroke_depth_offset = 0.05,\
}
#define _DNA_DEFAULT_LengthGpencilModifierData \
@@ -332,6 +334,11 @@
.point_density = 30.0f,\
.segment_influence = 0.0f,\
.max_angle = DEG2RAD(170.0f),\
+ .rand_start_fac = 0.0f,\
+ .rand_end_fac = 0.0f,\
+ .rand_offset = 0.0f,\
+ .seed = 0,\
+ .step = 4,\
}
#define _DNA_DEFAULT_DashGpencilModifierData \
@@ -352,5 +359,26 @@
.mat_nr = -1, \
}
+#define _DNA_DEFAULT_ShrinkwrapGpencilModifierData \
+ { \
+ .target = NULL, \
+ .aux_target = NULL, \
+ .keep_dist = 0.05f, \
+ .shrink_type = MOD_SHRINKWRAP_NEAREST_SURFACE, \
+ .shrink_opts = MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR, \
+ .shrink_mode = 0, \
+ .proj_limit = 0.0f, \
+ .proj_axis = 0, \
+ .subsurf_levels = 0, \
+ .material = NULL, \
+ .layername = "", \
+ .vgname = "", \
+ .pass_index = 0, \
+ .flag = 0, \
+ .layer_pass = 0, \
+ .smooth_factor = 0.05f, \
+ .smooth_step = 1, \
+ }
+
/* clang-format off */
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index ea5c81761c6..b361372ff8b 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -28,6 +28,7 @@ extern "C" {
#endif
struct LatticeDeformData;
+struct ShrinkwrapTreeData;
/* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE!
* (ONLY ADD NEW ITEMS AT THE END)
@@ -58,6 +59,7 @@ typedef enum GpencilModifierType {
eGpencilModifierType_WeightProximity = 21,
eGpencilModifierType_Dash = 22,
eGpencilModifierType_WeightAngle = 23,
+ eGpencilModifierType_Shrinkwrap = 24,
/* Keep last. */
NUM_GREASEPENCIL_MODIFIER_TYPES,
} GpencilModifierType;
@@ -260,7 +262,7 @@ typedef struct ColorGpencilModifierData {
int pass_index;
/** Flags. */
int flag;
- /** Hsv factors. */
+ /** HSV factors. */
float hsv[3];
/** Modify stroke, fill or both. */
char modify_color;
@@ -490,10 +492,17 @@ typedef struct LengthGpencilModifierData {
int layer_pass;
/** Length. */
float start_fac, end_fac;
+ /** Random length factors. */
+ float rand_start_fac, rand_end_fac, rand_offset;
/** Overshoot trajectory factor. */
float overshoot_fac;
+ /** (first element is the index) random values. */
+ int seed;
+ /** How many frames before recalculate randoms. */
+ int step;
/** Modifier mode. */
int mode;
+ char _pad[4];
/* Curvature parameters. */
float point_density;
float segment_influence;
@@ -507,6 +516,7 @@ typedef enum eLengthGpencil_Flag {
GP_LENGTH_INVERT_MATERIAL = (1 << 3),
GP_LENGTH_USE_CURVATURE = (1 << 4),
GP_LENGTH_INVERT_CURVATURE = (1 << 5),
+ GP_LENGTH_USE_RANDOM = (1 << 6),
} eLengthGpencil_Flag;
typedef enum eLengthGpencil_Type {
@@ -728,7 +738,7 @@ typedef struct SmoothGpencilModifierData {
int pass_index;
/** Several flags. */
int flag;
- /** Factor of noise. */
+ /** Factor of smooth. */
float factor;
/** How many times apply smooth. */
int step;
@@ -978,6 +988,8 @@ typedef enum eLineArtGPencilModifierFlags {
LRT_GPENCIL_BINARY_WEIGHTS = (1 << 2) /* Deprecated, this is removed for lack of use case. */,
LRT_GPENCIL_IS_BAKED = (1 << 3),
LRT_GPENCIL_USE_CACHE = (1 << 4),
+ LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA = (1 << 5),
+ LRT_GPENCIL_INVERT_COLLECTION = (1 << 6),
} eLineArtGPencilModifierFlags;
typedef enum eLineartGpencilMaskSwitches {
@@ -1004,6 +1016,8 @@ typedef struct LineartGpencilModifierData {
short level_start;
short level_end;
+ struct Object *source_camera;
+
struct Object *source_object;
struct Collection *source_collection;
@@ -1042,7 +1056,6 @@ typedef struct LineartGpencilModifierData {
/** Strength for smoothing jagged chains. */
float chain_smooth_tolerance;
- int _pad1;
/* CPU mode */
float chaining_image_threshold;
@@ -1053,6 +1066,9 @@ typedef struct LineartGpencilModifierData {
/* #eLineArtGPencilModifierFlags, modifier internal state. */
int flags;
+ /* Move strokes towards camera to avoid clipping while preserve depth for the viewport. */
+ float stroke_depth_offset;
+
/* Runtime data. */
/* Because we can potentially only compute features lines once per modifier stack (Use Cache), we
@@ -1068,6 +1084,60 @@ typedef struct LineartGpencilModifierData {
} LineartGpencilModifierData;
+typedef struct ShrinkwrapGpencilModifierData {
+ GpencilModifierData modifier;
+ /** Shrink target. */
+ struct Object *target;
+ /** Additional shrink target. */
+ struct Object *aux_target;
+ /** Material for filtering. */
+ struct Material *material;
+ /** Layer name. */
+ char layername[64];
+ /** Optional vertexgroup filter name, MAX_VGROUP_NAME. */
+ char vgname[64];
+ /** Custom index for passes. */
+ int pass_index;
+ /** Flags. */
+ int flag;
+ /** Custom index for passes. */
+ int layer_pass;
+ /** Distance offset to keep from mesh/projection point. */
+ float keep_dist;
+ /** Shrink type projection. */
+ short shrink_type;
+ /** Shrink options. */
+ char shrink_opts;
+ /** Shrink to surface mode. */
+ char shrink_mode;
+ /** Limit the projection ray cast. */
+ float proj_limit;
+ /** Axis to project over. */
+ char proj_axis;
+
+ /** If using projection over vertex normal this controls the level of subsurface that must be
+ * done before getting the vertex coordinates and normal
+ */
+ char subsurf_levels;
+ char _pad[6];
+ /** Factor of smooth. */
+ float smooth_factor;
+ /** How many times apply smooth. */
+ int smooth_step;
+
+ /** Runtime only. */
+ struct ShrinkwrapTreeData *cache_data;
+} ShrinkwrapGpencilModifierData;
+
+typedef enum eShrinkwrapGpencil_Flag {
+ GP_SHRINKWRAP_INVERT_LAYER = (1 << 0),
+ GP_SHRINKWRAP_INVERT_PASS = (1 << 1),
+ GP_SHRINKWRAP_INVERT_LAYERPASS = (1 << 3),
+ GP_SHRINKWRAP_INVERT_MATERIAL = (1 << 4),
+ /* Keep next bit as is to be equals to mesh modifier flag to reuse functions. */
+ GP_SHRINKWRAP_INVERT_VGROUP = (1 << 6),
+} eShrinkwrapGpencil_Flag;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_gpu_types.h b/source/blender/makesdna/DNA_gpu_types.h
index 8cea1451525..7d1e7d4e4f2 100644
--- a/source/blender/makesdna/DNA_gpu_types.h
+++ b/source/blender/makesdna/DNA_gpu_types.h
@@ -28,7 +28,7 @@ extern "C" {
#endif
/* Keep for 'Camera' versioning. */
-/** Properties for dof effect. */
+/** Properties for DOF effect. */
typedef struct GPUDOFSettings {
/** Focal distance for depth of field. */
float focus_distance;
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 30ca9540735..64c8fd3e3a9 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -51,16 +51,13 @@ typedef struct ImageUser {
/** Offset within movie, start frame in global time. */
int offset, sfra;
/** Cyclic flag. */
- char _pad0, cycl;
- char ok;
+ char cycl;
/** Multiview current eye - for internal use of drawing routines. */
char multiview_eye;
short pass;
- char _pad1[2];
int tile;
- int _pad2;
/** Listbase indices, for menu browsing or retrieve buffer. */
short multi_index, view, layer;
@@ -112,9 +109,7 @@ typedef struct ImageTile {
struct ImageTile_Runtime runtime;
- char ok;
- char _pad[3];
-
+ char _pad[4];
int tile_number;
char label[64];
} ImageTile;
@@ -147,6 +142,12 @@ typedef enum eImageTextureResolution {
IMA_TEXTURE_RESOLUTION_LEN
} eImageTextureResolution;
+typedef struct Image_Runtime {
+ /* Mutex used to guarantee thread-safe access to the cached ImBuf of the corresponding image ID.
+ */
+ void *cache_mutex;
+} Image_Runtime;
+
typedef struct Image {
ID id;
@@ -213,6 +214,8 @@ typedef struct Image {
/** ImageView. */
ListBase views;
struct Stereo3dFormat *stereo3d_format;
+
+ Image_Runtime runtime;
} Image;
/* **************** IMAGE ********************* */
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index 520f989452c..63e4597150c 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -68,7 +68,7 @@ typedef enum eViewLayerCryptomatteFlags {
VIEW_LAYER_CRYPTOMATTE_OBJECT = (1 << 0),
VIEW_LAYER_CRYPTOMATTE_MATERIAL = (1 << 1),
VIEW_LAYER_CRYPTOMATTE_ASSET = (1 << 2),
- /* VIEW_LAYER_CRYPTOMATTE_ACCURATE = (1 << 3), */ /* DEPRECATED */
+ VIEW_LAYER_CRYPTOMATTE_ACCURATE = (1 << 3),
} eViewLayerCryptomatteFlags;
#define VIEW_LAYER_CRYPTOMATTE_ALL \
(VIEW_LAYER_CRYPTOMATTE_OBJECT | VIEW_LAYER_CRYPTOMATTE_MATERIAL | VIEW_LAYER_CRYPTOMATTE_ASSET)
diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h
index 3386722a072..d8ab21727c1 100644
--- a/source/blender/makesdna/DNA_lightprobe_types.h
+++ b/source/blender/makesdna/DNA_lightprobe_types.h
@@ -153,7 +153,7 @@ BLI_STATIC_ASSERT_ALIGN(LightGridCache, 16)
typedef struct LightCacheTexture {
struct GPUTexture *tex;
- /** Copy of GPU datas to create GPUTextures on file read. */
+ /** Copy of GPU data to create GPUTextures on file read. */
char *data;
int tex_size[3];
char data_type;
diff --git a/source/blender/makesdna/DNA_lineart_types.h b/source/blender/makesdna/DNA_lineart_types.h
index bdc9bcb6980..3e77d566d27 100644
--- a/source/blender/makesdna/DNA_lineart_types.h
+++ b/source/blender/makesdna/DNA_lineart_types.h
@@ -49,6 +49,11 @@ typedef enum eLineartMainFlags {
LRT_ALLOW_OVERLAP_EDGE_TYPES = (1 << 14),
LRT_USE_CREASE_ON_SMOOTH_SURFACES = (1 << 15),
LRT_USE_CREASE_ON_SHARP_EDGES = (1 << 16),
+ LRT_USE_CUSTOM_CAMERA = (1 << 17),
+ LRT_FILTER_FACE_MARK_KEEP_CONTOUR = (1 << 18),
+ LRT_USE_BACK_FACE_CULLING = (1 << 19),
+ LRT_USE_IMAGE_BOUNDARY_TRIMMING = (1 << 20),
+ LRT_CHAIN_PRESERVE_DETAILS = (1 << 22),
} eLineartMainFlags;
typedef enum eLineartEdgeFlag {
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index 4d4a4bae72e..b91d681df0c 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -293,7 +293,7 @@ typedef struct Material {
/* #define TEXCO_STRESS (1 << 14) */ /* deprecated */
/* #define TEXCO_SPEED (1 << 15) */ /* deprecated */
-/* mapto */
+/** #MTex.mapto */
#define MAP_COL (1 << 0)
#define MAP_ALPHA (1 << 7)
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 97f14b2195d..bf50100b302 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -74,7 +74,7 @@ struct MLoopTri_Store {
int len_alloc;
};
-/* not saved in file! */
+/** Runtime data, not saved in files. */
typedef struct Mesh_Runtime {
/* Evaluated mesh for objects which do not have effective modifiers.
* This mesh is used as a result of modifier stack evaluation.
@@ -82,27 +82,37 @@ typedef struct Mesh_Runtime {
struct Mesh *mesh_eval;
void *eval_mutex;
- struct EditMeshData *edit_data;
- void *batch_cache;
+ /* A separate mutex is needed for normal calculation, because sometimes
+ * the normals are needed while #eval_mutex is already locked. */
+ void *normals_mutex;
- struct SubdivCCG *subdiv_ccg;
- void *_pad1;
- int subdiv_ccg_tot_level;
- char _pad2[4];
+ /** Needed to ensure some thread-safety during render data pre-processing. */
+ void *render_mutex;
- int64_t cd_dirty_vert;
- int64_t cd_dirty_edge;
- int64_t cd_dirty_loop;
- int64_t cd_dirty_poly;
+ /** Lazily initialized SoA data from the #edit_mesh field in #Mesh. */
+ struct EditMeshData *edit_data;
+
+ /**
+ * Data used to efficiently draw the mesh in the viewport, especially useful when
+ * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.c`.
+ */
+ void *batch_cache;
+ /** Cache for derived triangulation of the mesh. */
struct MLoopTri_Store looptris;
- /** `BVHCache` defined in 'BKE_bvhutil.c' */
+ /** Cache for BVH trees generated for the mesh. Defined in 'BKE_bvhutil.c' */
struct BVHCache *bvh_cache;
- /** Non-manifold boundary data for Shrinkwrap Target Project. */
+ /** Cache of non-manifold boundary data for Shrinkwrap Target Project. */
struct ShrinkwrapBoundaryData *shrinkwrap_data;
+ /** Needed in case we need to lazily initialize the mesh. */
+ CustomData_MeshMasks cd_mask_extra;
+
+ struct SubdivCCG *subdiv_ccg;
+ int subdiv_ccg_tot_level;
+
/** Set by modifier stack if only deformed from original. */
char deformed_only;
/**
@@ -122,10 +132,26 @@ typedef struct Mesh_Runtime {
*/
char wrapper_type_finalize;
- char _pad[4];
+ /**
+ * Settings for lazily evaluating the subdivision on the CPU if needed. These are
+ * set in the modifier when GPU subdivision can be performed.
+ */
+ char subsurf_apply_render;
+ char subsurf_use_optimal_display;
+ char _pad[2];
+ int subsurf_resolution;
- /** Needed in case we need to lazily initialize the mesh. */
- CustomData_MeshMasks cd_mask_extra;
+ void *_pad2;
+
+ /**
+ * Used to mark when derived data needs to be recalculated for a certain layer.
+ * Currently only normals.
+ */
+
+ int64_t cd_dirty_vert;
+ int64_t cd_dirty_edge;
+ int64_t cd_dirty_loop;
+ int64_t cd_dirty_poly;
} Mesh_Runtime;
@@ -137,101 +163,191 @@ typedef struct Mesh {
/** Old animation system, deprecated for 2.5. */
struct Ipo *ipo DNA_DEPRECATED;
struct Key *key;
- struct Material **mat;
- struct MSelect *mselect;
- /* BMESH ONLY */
- /* New face structures. */
- struct MPoly *mpoly;
- struct MLoop *mloop;
- struct MLoopUV *mloopuv;
- struct MLoopCol *mloopcol;
- /* END BMESH ONLY */
+ /**
+ * An array of materials, with length #totcol. These can be overridden by material slots
+ * on #Object. Indices in #MPoly.mat_nr control which material is used for every face.
+ */
+ struct Material **mat;
/**
- * Legacy face storage (quads & tries only),
- * faces are now stored in #Mesh.mpoly & #Mesh.mloop arrays.
- *
- * \note This would be marked deprecated however the particles still use this at run-time
- * for placing particles on the mesh (something which should be eventually upgraded).
+ * Array of vertices. Edges and faces are defined by indices into this array.
+ * \note This pointer is for convenient access to the #CD_MVERT layer in #vdata.
*/
- struct MFace *mface;
- /** Store tessellation face UV's and texture here. */
- struct MTFace *mtface;
- /** Deprecated, use mtface. */
- struct TFace *tface DNA_DEPRECATED;
- /** Array of verts. */
struct MVert *mvert;
- /** Array of edges. */
+ /**
+ * Array of edges, containing vertex indices. For simple triangle or quad meshes, edges could be
+ * calculated from the #MPoly and #MLoop arrays, however, edges need to be stored explicitly to
+ * edge domain attributes and to support loose edges that aren't connected to faces.
+ * \note This pointer is for convenient access to the #CD_MEDGE layer in #edata.
+ */
struct MEdge *medge;
- /** Deform-group vertices. */
- struct MDeformVert *dvert;
- /** List of bDeformGroup names and flag only. */
- ListBase vertex_group_names;
+ /**
+ * Face topology storage of the size and offset of each face's section of the #mloop face corner
+ * array. Also stores various flags and the `material_index` attribute.
+ * \note This pointer is for convenient access to the #CD_MPOLY layer in #pdata.
+ */
+ struct MPoly *mpoly;
+ /**
+ * The vertex and edge index at each face corner.
+ * \note This pointer is for convenient access to the #CD_MLOOP layer in #ldata.
+ */
+ struct MLoop *mloop;
- /* array of colors for the tessellated faces, must be number of tessellated
- * faces * 4 in length */
- struct MCol *mcol;
- struct Mesh *texcomesh;
+ /** The number of vertices (#MVert) in the mesh, and the size of #vdata. */
+ int totvert;
+ /** The number of edges (#MEdge) in the mesh, and the size of #edata. */
+ int totedge;
+ /** The number of polygons/faces (#MPoly) in the mesh, and the size of #pdata. */
+ int totpoly;
+ /** The number of face corners (#MLoop) in the mesh, and the size of #ldata. */
+ int totloop;
- /* When the object is available, the preferred access method is: BKE_editmesh_from_object(ob) */
- /** Not saved in file. */
- struct BMEditMesh *edit_mesh;
+ CustomData vdata, edata, pdata, ldata;
- struct CustomData vdata, edata, fdata;
+ /** "Vertex group" vertices. */
+ struct MDeformVert *dvert;
+ /**
+ * List of vertex group (#bDeformGroup) names and flags only. Actual weights are stored in dvert.
+ * \note This pointer is for convenient access to the #CD_MDEFORMVERT layer in #vdata.
+ */
+ ListBase vertex_group_names;
+ /** The active index in the #vertex_group_names list. */
+ int vertex_group_active_index;
- /* BMESH ONLY */
- struct CustomData pdata, ldata;
- /* END BMESH ONLY */
+ /**
+ * The index of the active attribute in the UI. The attribute list is a combination of the
+ * generic type attributes from vertex, edge, face, and corner custom data.
+ */
+ int attributes_active_index;
- int totvert, totedge, totface, totselect;
+ /**
+ * 2D vector data used for UVs. "UV" data can also be stored as generic attributes in #ldata.
+ * \note This pointer is for convenient access to the #CD_MLOOPUV layer in #ldata.
+ */
+ struct MLoopUV *mloopuv;
+ /**
+ * The active vertex corner color layer, if it exists. Also called "Vertex Color" in Blender's
+ * UI, even though it is stored per face corner.
+ * \note This pointer is for convenient access to the #CD_MLOOPCOL layer in #ldata.
+ */
+ struct MLoopCol *mloopcol;
- /* BMESH ONLY */
- int totpoly, totloop;
- /* END BMESH ONLY */
+ /**
+ * Runtime storage of the edit mode mesh. If it exists, it generally has the most up-to-date
+ * information about the mesh.
+ * \note When the object is available, the preferred access method is #BKE_editmesh_from_object.
+ */
+ struct BMEditMesh *edit_mesh;
- int attributes_active_index;
- int vertex_group_active_index;
+ /**
+ * This array represents the selection order when the user manually picks elements in edit-mode,
+ * some tools take advantage of this information. All elements in this array are expected to be
+ * selected, see #BKE_mesh_mselect_validate which ensures this. For procedurally created meshes,
+ * this is generally empty (selections are stored as boolean attributes in the corresponding
+ * custom data).
+ */
+ struct MSelect *mselect;
+
+ /** The length of the #mselect array. */
+ int totselect;
- /* the last selected vertex/edge/face are used for the active face however
- * this means the active face must always be selected, this is to keep track
- * of the last selected face and is similar to the old active face flag where
- * the face does not need to be selected, -1 is inactive */
+ /**
+ * In most cases the last selected element (see #mselect) represents the active element.
+ * For faces we make an exception and store the active face separately so it can be active
+ * even when no faces are selected. This is done to prevent flickering in the material properties
+ * and UV Editor which base the content they display on the current material which is controlled
+ * by the active face.
+ *
+ * \note This is mainly stored for use in edit-mode.
+ */
int act_face;
- /* texture space, copied as one block in editobject.c */
+ /**
+ * An optional mesh owned elsewhere (by #Main) that can be used to override
+ * the texture space #loc and #size.
+ * \note Vertex indices should be aligned for this to work usefully.
+ */
+ struct Mesh *texcomesh;
+
+ /** Texture space location and size, used for procedural coordinates when rendering. */
float loc[3];
float size[3];
+ char texflag;
- short texflag, flag;
+ /** Various flags used when editing the mesh. */
+ char editflag;
+ /** Mostly more flags used when editing or displaying the mesh. */
+ short flag;
+
+ /**
+ * The angle for auto smooth in radians. `M_PI` (180 degrees) causes all edges to be smooth.
+ */
float smoothresh;
- /* customdata flag, for bevel-weight and crease, which are now optional */
- char cd_flag, _pad;
+ /**
+ * Flag for choosing whether or not so store bevel weight and crease as custom data layers in the
+ * edit mesh (they are always stored in #MVert and #MEdge currently). In the future, this data
+ * may be stored as generic named attributes (see T89054 and T93602).
+ */
+ char cd_flag;
- char subdiv DNA_DEPRECATED, subdivr DNA_DEPRECATED;
- /** Only kept for backwards compat, not used anymore. */
- char subsurftype DNA_DEPRECATED;
- char editflag;
+ /**
+ * User-defined symmetry flag (#eMeshSymmetryType) that causes editing operations to maintain
+ * symmetrical geometry. Supported by operations such as transform and weight-painting.
+ */
+ char symmetry;
+ /** The length of the #mat array. */
short totcol;
- float remesh_voxel_size;
- float remesh_voxel_adaptivity;
+ /** Choice between different remesh methods in the UI. */
char remesh_mode;
- /* Indicates the symmetry that a mesh has, according to the artist, so that tools can
- * consistently ensure that this symmetry is maintained. */
- char symmetry;
+ char subdiv DNA_DEPRECATED;
+ char subdivr DNA_DEPRECATED;
+ char subsurftype DNA_DEPRECATED;
- char _pad1[2];
+ /**
+ * Deprecated. Store of runtime data for tessellation face UVs and texture.
+ *
+ * \note This would be marked deprecated, however the particles still use this at run-time
+ * for placing particles on the mesh (something which should be eventually upgraded).
+ */
+ struct MTFace *mtface;
+ /** Deprecated, use mtface. */
+ struct TFace *tface DNA_DEPRECATED;
+
+ /* Deprecated. Array of colors for the tessellated faces, must be number of tessellated
+ * faces * 4 in length. This is stored in #fdata, and deprecated. */
+ struct MCol *mcol;
+
+ /**
+ * Deprecated face storage (quads & triangles only);
+ * faces are now pointed to by #Mesh.mpoly and #Mesh.mloop.
+ *
+ * \note This would be marked deprecated, however the particles still use this at run-time
+ * for placing particles on the mesh (something which should be eventually upgraded).
+ */
+ struct MFace *mface;
+ /* Deprecated storage of old faces (only triangles or quads). */
+ CustomData fdata;
+ /* Deprecated size of #fdata. */
+ int totface;
+
+ /** Per-mesh settings for voxel remesh. */
+ float remesh_voxel_size;
+ float remesh_voxel_adaptivity;
int face_sets_color_seed;
/* Stores the initial Face Set to be rendered white. This way the overlay can be enabled by
* default and Face Sets can be used without affecting the color of the mesh. */
int face_sets_color_default;
+ char _pad1[4];
+
void *_pad2;
+
Mesh_Runtime runtime;
} Mesh;
@@ -255,16 +371,17 @@ typedef enum eMeshWrapperType {
ME_WRAPPER_TYPE_MDATA = 0,
/** Use edit-mesh data (#Mesh.edit_mesh, #Mesh_Runtime.edit_data). */
ME_WRAPPER_TYPE_BMESH = 1,
- /* ME_WRAPPER_TYPE_SUBD = 2, */ /* TODO */
+ /** Use subdivision mesh data (#Mesh_Runtime.mesh_eval). */
+ ME_WRAPPER_TYPE_SUBD = 2,
} eMeshWrapperType;
-/* texflag */
+/** #Mesh.texflag */
enum {
ME_AUTOSPACE = 1,
ME_AUTOSPACE_EVALUATED = 2,
};
-/* me->editflag */
+/** #Mesh.editflag */
enum {
ME_EDIT_MIRROR_VERTEX_GROUPS = 1 << 0,
ME_EDIT_MIRROR_Y = 1 << 1, /* unused so far */
@@ -286,7 +403,7 @@ enum {
((_me)->editflag & ME_EDIT_PAINT_VERT_SEL) ? SCE_SELECT_VERTEX : \
0)
-/* me->flag */
+/** #Mesh.flag */
enum {
ME_FLAG_UNUSED_0 = 1 << 0, /* cleared */
ME_FLAG_UNUSED_1 = 1 << 1, /* cleared */
@@ -306,26 +423,27 @@ enum {
ME_REMESH_REPROJECT_SCULPT_FACE_SETS = 1 << 15,
};
-/* me->cd_flag */
+/** #Mesh.cd_flag */
enum {
ME_CDFLAG_VERT_BWEIGHT = 1 << 0,
ME_CDFLAG_EDGE_BWEIGHT = 1 << 1,
ME_CDFLAG_EDGE_CREASE = 1 << 2,
+ ME_CDFLAG_VERT_CREASE = 1 << 3,
};
-/* me->remesh_mode */
+/** #Mesh.remesh_mode */
enum {
REMESH_VOXEL = 0,
REMESH_QUAD = 1,
};
-/* Subsurf Type */
+/** #SubsurfModifierData.subdivType */
enum {
ME_CC_SUBSURF = 0,
ME_SIMPLE_SUBSURF = 1,
};
-/* me->symmetry */
+/** #Mesh.symmetry */
typedef enum eMeshSymmetryType {
ME_SYMMETRY_X = 1 << 0,
ME_SYMMETRY_Y = 1 << 1,
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index bc6b35c8e43..22c523901c0 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -41,12 +41,8 @@ extern "C" {
*/
typedef struct MVert {
float co[3];
- /**
- * Cache the normal, can always be recalculated from surrounding faces.
- * See #CD_CUSTOMLOOPNORMAL for custom normals.
- */
- short no[3];
char flag, bweight;
+ char _pad[2];
} MVert;
/** #MVert.flag */
@@ -106,19 +102,15 @@ enum {
};
/**
- * Mesh Loops.
- * Each loop represents the corner of a polygon (#MPoly).
+ * Mesh Face Corners.
+ * "Loop" is an internal name for the corner of a polygon (#MPoly).
*
* Typically accessed from #Mesh.mloop.
*/
typedef struct MLoop {
- /** Vertex index. */
+ /** Vertex index into an #MVert array. */
unsigned int v;
- /**
- * Edge index.
- *
- * \note The e here is because we want to move away from relying on edge hashes.
- */
+ /** Edge index into an #MEdge array. */
unsigned int e;
} MLoop;
@@ -291,8 +283,22 @@ typedef struct MDeformWeight {
float weight;
} MDeformWeight;
+/**
+ * Stores all of an element's vertex groups, and their weight values.
+ */
typedef struct MDeformVert {
+ /**
+ * Array of weight indices and values.
+ * - There must not be any duplicate #def_nr indices.
+ * - Groups in the array are unordered.
+ * - Indices outside the usable range of groups are ignored.
+ */
struct MDeformWeight *dw;
+ /**
+ * The length of the #dw array.
+ * \note This is not necessarily the same length as the total number of vertex groups.
+ * However, generally it isn't larger.
+ */
int totweight;
/** Flag is only in use as a run-time tag at the moment. */
int flag;
diff --git a/source/blender/makesdna/DNA_meta_types.h b/source/blender/makesdna/DNA_meta_types.h
index d257363b6ef..e489ba7d7ac 100644
--- a/source/blender/makesdna/DNA_meta_types.h
+++ b/source/blender/makesdna/DNA_meta_types.h
@@ -83,8 +83,8 @@ typedef struct MetaBall {
char flag, flag2;
short totcol;
/** Used to store MB_AUTOSPACE. */
- short texflag;
- char _pad[1];
+ char texflag;
+ char _pad[2];
/**
* ID data is older than edit-mode data (TODO: move to edit-mode struct).
diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h
index 5b2694f420b..78ab41031a6 100644
--- a/source/blender/makesdna/DNA_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_modifier_defaults.h
@@ -429,6 +429,7 @@
.uv_offset = {0.0f, 0.0f}, \
.uv_offset_copy = {0.0f, 0.0f}, \
.mirror_ob = NULL, \
+ .use_correct_order_on_merge = true, \
}
#define _DNA_DEFAULT_MultiresModifierData \
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 631db64ddd3..1d0796bda8b 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -121,28 +121,28 @@ typedef struct ModifierData {
int type, mode;
char _pad0[4];
short flag;
- /* An "expand" bit for each of the modifier's (sub)panels (uiPanelDataExpansion). */
+ /** An "expand" bit for each of the modifier's (sub)panels (#uiPanelDataExpansion). */
short ui_expand_flag;
/** MAX_NAME. */
char name[64];
char *error;
- /* Pointer to a ModifierData in the original domain. */
+ /** Pointer to a #ModifierData in the original domain. */
struct ModifierData *orig_modifier_data;
- /* Runtime field which contains unique identifier of the modifier. */
+ /** Runtime field which contains unique identifier of the modifier. */
SessionUUID session_uuid;
- /* Runtime field which contains runtime data which is specific to a modifier type. */
+ /** Runtime field which contains runtime data which is specific to a modifier type. */
void *runtime;
void *_pad1;
} ModifierData;
typedef enum {
- /* This modifier has been inserted in local override, and hence can be fully edited. */
+ /** This modifier has been inserted in local override, and hence can be fully edited. */
eModifierFlag_OverrideLibrary_Local = (1 << 0),
- /* This modifier does not own its caches, but instead shares them with another modifier. */
+ /** This modifier does not own its caches, but instead shares them with another modifier. */
eModifierFlag_SharedCaches = (1 << 1),
/**
* This modifier is the object's active modifier. Used for context in the node editor.
@@ -151,7 +151,9 @@ typedef enum {
eModifierFlag_Active = (1 << 2),
} ModifierFlag;
-/* not a real modifier */
+/**
+ * \note Not a real modifier.
+ */
typedef struct MappingInfoModifierData {
ModifierData modifier;
@@ -194,6 +196,13 @@ typedef enum {
SUBSURF_BOUNDARY_SMOOTH_PRESERVE_CORNERS = 1,
} eSubsurfBoundarySmooth;
+typedef struct SubsurfRuntimeData {
+ /* Cached subdivision surface descriptor, with topology and settings. */
+ struct Subdiv *subdiv;
+ char set_by_draw_code;
+ char _pad[7];
+} SubsurfRuntimeData;
+
typedef struct SubsurfModifierData {
ModifierData modifier;
@@ -219,7 +228,7 @@ typedef struct LatticeModifierData {
void *_pad1;
} LatticeModifierData;
-/* Lattice modifier flags. */
+/** #LatticeModifierData.flag */
enum {
MOD_LATTICE_INVERT_VGROUP = (1 << 0),
};
@@ -237,12 +246,12 @@ typedef struct CurveModifierData {
void *_pad1;
} CurveModifierData;
-/* Curve modifier flags */
+/** #CurveModifierData.flag */
enum {
MOD_CURVE_INVERT_VGROUP = (1 << 0),
};
-/* CurveModifierData->defaxis */
+/** #CurveModifierData.defaxis */
enum {
MOD_CURVE_POSX = 1,
MOD_CURVE_POSY = 2,
@@ -264,7 +273,7 @@ typedef struct BuildModifierData {
int seed;
} BuildModifierData;
-/* Build Modifier -> flag */
+/** #BuildModifierData.flag */
enum {
/** order of vertices is randomized */
MOD_BUILD_FLAG_RANDOMIZE = (1 << 0),
@@ -272,7 +281,7 @@ enum {
MOD_BUILD_FLAG_REVERSE = (1 << 1),
};
-/* Mask Modifier */
+/** Mask Modifier. */
typedef struct MaskModifierData {
ModifierData modifier;
@@ -289,13 +298,13 @@ typedef struct MaskModifierData {
void *_pad1;
} MaskModifierData;
-/* Mask Modifier -> mode */
+/** #MaskModifierData.mode */
enum {
MOD_MASK_MODE_VGROUP = 0,
MOD_MASK_MODE_ARM = 1,
};
-/* Mask Modifier -> flag */
+/** #MaskModifierData.flag */
enum {
MOD_MASK_INV = (1 << 0),
MOD_MASK_SMOOTH = (1 << 1),
@@ -304,63 +313,68 @@ enum {
typedef struct ArrayModifierData {
ModifierData modifier;
- /* the object with which to cap the start of the array. */
+ /** The object with which to cap the start of the array. */
struct Object *start_cap;
- /* the object with which to cap the end of the array. */
+ /** The object with which to cap the end of the array. */
struct Object *end_cap;
- /* the curve object to use for MOD_ARR_FITCURVE. */
+ /** The curve object to use for #MOD_ARR_FITCURVE. */
struct Object *curve_ob;
- /* the object to use for object offset. */
+ /** The object to use for object offset. */
struct Object *offset_ob;
- /* a constant duplicate offset;
- * 1 means the duplicates are 1 unit apart
+ /**
+ * A constant duplicate offset;
+ * 1 means the duplicates are 1 unit apart.
*/
float offset[3];
- /* a scaled factor for duplicate offsets;
- * 1 means the duplicates are 1 object-width apart
+ /**
+ * A scaled factor for duplicate offsets;
+ * 1 means the duplicates are 1 object-width apart.
*/
float scale[3];
- /* the length over which to distribute the duplicates */
+ /** The length over which to distribute the duplicates. */
float length;
- /* the limit below which to merge vertices in adjacent duplicates */
+ /** The limit below which to merge vertices in adjacent duplicates. */
float merge_dist;
- /* determines how duplicate count is calculated; one of:
- * - MOD_ARR_FIXEDCOUNT -> fixed
- * - MOD_ARR_FITLENGTH -> calculated to fit a set length
- * - MOD_ARR_FITCURVE -> calculated to fit the length of a Curve object
+ /**
+ * Determines how duplicate count is calculated; one of:
+ * - #MOD_ARR_FIXEDCOUNT -> fixed.
+ * - #MOD_ARR_FITLENGTH -> calculated to fit a set length.
+ * - #MOD_ARR_FITCURVE -> calculated to fit the length of a Curve object.
*/
int fit_type;
- /* flags specifying how total offset is calculated; binary OR of:
- * - MOD_ARR_OFF_CONST -> total offset += offset
- * - MOD_ARR_OFF_RELATIVE -> total offset += relative * object width
- * - MOD_ARR_OFF_OBJ -> total offset += offset_ob's matrix
- * total offset is the sum of the individual enabled offsets
+ /**
+ * Flags specifying how total offset is calculated; binary OR of:
+ * - #MOD_ARR_OFF_CONST -> total offset += offset.
+ * - #MOD_ARR_OFF_RELATIVE -> total offset += relative * object width.
+ * - #MOD_ARR_OFF_OBJ -> total offset += offset_ob's matrix.
+ * Total offset is the sum of the individual enabled offsets.
*/
int offset_type;
- /* general flags:
- * MOD_ARR_MERGE -> merge vertices in adjacent duplicates
+ /**
+ * General flags:
+ * #MOD_ARR_MERGE -> merge vertices in adjacent duplicates.
*/
int flags;
- /* the number of duplicates to generate for MOD_ARR_FIXEDCOUNT */
+ /** The number of duplicates to generate for #MOD_ARR_FIXEDCOUNT. */
int count;
float uv_offset[2];
} ArrayModifierData;
-/* ArrayModifierData->fit_type */
+/** #ArrayModifierData.fit_type */
enum {
MOD_ARR_FIXEDCOUNT = 0,
MOD_ARR_FITLENGTH = 1,
MOD_ARR_FITCURVE = 2,
};
-/* ArrayModifierData->offset_type */
+/** #ArrayModifierData.offset_type */
enum {
MOD_ARR_OFF_CONST = (1 << 0),
MOD_ARR_OFF_RELATIVE = (1 << 1),
MOD_ARR_OFF_OBJ = (1 << 2),
};
-/* ArrayModifierData->flags */
+/** #ArrayModifierData.flags */
enum {
MOD_ARR_MERGE = (1 << 0),
MOD_ARR_MERGEFINAL = (1 << 1),
@@ -374,14 +388,22 @@ typedef struct MirrorModifierData {
short flag;
float tolerance;
float bisect_threshold;
- char _pad[4];
+
+ /** Mirror modifier used to merge the old vertex into its new copy, which would break code
+ * relying on access to the original geometry vertices. However, modifying this behavior to the
+ * correct one (i.e. merging the copy vertices into their original sources) has several potential
+ * effects on other modifiers and tools, so we need to keep that incorrect behavior for existing
+ * modifiers, and only use the new correct one for new modifiers. */
+ uint8_t use_correct_order_on_merge;
+
+ char _pad[3];
float uv_offset[2];
float uv_offset_copy[2];
struct Object *mirror_ob;
void *_pad1;
} MirrorModifierData;
-/* MirrorModifierData->flag */
+/** #MirrorModifierData.flag */
enum {
MOD_MIR_CLIPPING = (1 << 0),
MOD_MIR_MIRROR_U = (1 << 1),
@@ -408,7 +430,7 @@ typedef struct EdgeSplitModifierData {
int flags;
} EdgeSplitModifierData;
-/* EdgeSplitModifierData->flags */
+/** #EdgeSplitModifierData.flags */
enum {
MOD_EDGESPLIT_FROMANGLE = (1 << 1),
MOD_EDGESPLIT_FROMFLAG = (1 << 2),
@@ -460,7 +482,7 @@ typedef struct BevelModifierData {
void *_pad2;
} BevelModifierData;
-/* BevelModifierData->flags and BevelModifierData->lim_flags */
+/** #BevelModifierData.flags and BevelModifierData.lim_flags */
enum {
#ifdef DNA_DEPRECATED_ALLOW
MOD_BEVEL_VERT_DEPRECATED = (1 << 1),
@@ -483,7 +505,7 @@ enum {
MOD_BEVEL_HARDEN_NORMALS = (1 << 15),
};
-/* BevelModifierData->val_flags (not used as flags any more) */
+/** #BevelModifierData.val_flags (not used as flags any more) */
enum {
MOD_BEVEL_AMT_OFFSET = 0,
MOD_BEVEL_AMT_WIDTH = 1,
@@ -492,19 +514,19 @@ enum {
MOD_BEVEL_AMT_ABSOLUTE = 4,
};
-/* BevelModifierData->profile_type */
+/** #BevelModifierData.profile_type */
enum {
MOD_BEVEL_PROFILE_SUPERELLIPSE = 0,
MOD_BEVEL_PROFILE_CUSTOM = 1,
};
-/* BevelModifierData->edge_flags */
+/** #BevelModifierData.edge_flags */
enum {
MOD_BEVEL_MARK_SEAM = (1 << 0),
MOD_BEVEL_MARK_SHARP = (1 << 1),
};
-/* BevelModifierData->face_str_mode */
+/** #BevelModifierData.face_str_mode */
enum {
MOD_BEVEL_FACE_STRENGTH_NONE = 0,
MOD_BEVEL_FACE_STRENGTH_NEW = 1,
@@ -512,20 +534,20 @@ enum {
MOD_BEVEL_FACE_STRENGTH_ALL = 3,
};
-/* BevelModifier->miter_inner and ->miter_outer */
+/** #BevelModifier.miter_inner & #BevelModifier.miter_outer */
enum {
MOD_BEVEL_MITER_SHARP = 0,
MOD_BEVEL_MITER_PATCH = 1,
MOD_BEVEL_MITER_ARC = 2,
};
-/* BevelModifier->vmesh_method */
+/** #BevelModifier.vmesh_method */
enum {
MOD_BEVEL_VMESH_ADJ = 0,
MOD_BEVEL_VMESH_CUTOFF = 1,
};
-/* BevelModifier->affect_type */
+/** #BevelModifier.affect_type */
enum {
MOD_BEVEL_AFFECT_VERTICES = 0,
MOD_BEVEL_AFFECT_EDGES = 1,
@@ -545,7 +567,7 @@ typedef struct FluidModifierData {
void *_pad1;
} FluidModifierData;
-/* Fluid modifier flags */
+/** #FluidModifierData.type */
enum {
MOD_FLUID_TYPE_DOMAIN = (1 << 0),
MOD_FLUID_TYPE_FLOW = (1 << 1),
@@ -555,7 +577,8 @@ enum {
typedef struct DisplaceModifierData {
ModifierData modifier;
- /* keep in sync with MappingInfoModifierData */
+ /* Keep in sync with #MappingInfoModifierData. */
+
struct Tex *texture;
struct Object *map_object;
char map_bone[64];
@@ -575,12 +598,12 @@ typedef struct DisplaceModifierData {
char _pad[6];
} DisplaceModifierData;
-/* DisplaceModifierData->flag */
+/** #DisplaceModifierData.flag */
enum {
MOD_DISP_INVERT_VGROUP = (1 << 0),
};
-/* DisplaceModifierData->direction */
+/** #DisplaceModifierData.direction */
enum {
MOD_DISP_DIR_X = 0,
MOD_DISP_DIR_Y = 1,
@@ -590,7 +613,7 @@ enum {
MOD_DISP_DIR_CLNOR = 5,
};
-/* DisplaceModifierData->texmapping */
+/** #DisplaceModifierData.texmapping */
enum {
MOD_DISP_MAP_LOCAL = 0,
MOD_DISP_MAP_GLOBAL = 1,
@@ -598,7 +621,7 @@ enum {
MOD_DISP_MAP_UV = 3,
};
-/* DisplaceModifierData->space */
+/** #DisplaceModifierData.space */
enum {
MOD_DISP_SPACE_LOCAL = 0,
MOD_DISP_SPACE_GLOBAL = 1,
@@ -606,9 +629,10 @@ enum {
typedef struct UVProjectModifierData {
ModifierData modifier;
-
- /* the objects which do the projecting */
- /** MOD_UVPROJECT_MAXPROJECTORS. */
+ /**
+ * The objects which do the projecting.
+ * \note 10=MOD_UVPROJECT_MAXPROJECTORS.
+ */
struct Object *projectors[10];
char _pad2[4];
int num_projectors;
@@ -641,7 +665,7 @@ typedef struct DecimateModifierData {
float defgrp_factor;
short flag, mode;
- /* runtime only */
+ /** runtime only. */
int face_count;
} DecimateModifierData;
@@ -670,7 +694,7 @@ typedef struct SmoothModifierData {
} SmoothModifierData;
-/* Smooth modifier flags */
+/** #SmoothModifierData.flag */
enum {
MOD_SMOOTH_INVERT_VGROUP = (1 << 0),
MOD_SMOOTH_X = (1 << 1),
@@ -687,11 +711,13 @@ typedef struct CastModifierData {
float size;
/** MAX_VGROUP_NAME. */
char defgrp_name[64];
- short flag, type;
+ short flag;
+ /** Cast modifier projection type. */
+ short type;
void *_pad1;
} CastModifierData;
-/* Cast modifier flags */
+/** #CastModifierData.flag */
enum {
/* And what bout (1 << 0) flag? ;) */
MOD_CAST_INVERT_VGROUP = (1 << 0),
@@ -702,7 +728,7 @@ enum {
MOD_CAST_SIZE_FROM_RADIUS = (1 << 5),
};
-/* Cast modifier projection types */
+/** #CastModifierData.type */
enum {
MOD_CAST_TYPE_SPHERE = 0,
MOD_CAST_TYPE_CYLINDER = 1,
@@ -712,7 +738,8 @@ enum {
typedef struct WaveModifierData {
ModifierData modifier;
- /* keep in sync with MappingInfoModifierData */
+ /* Keep in sync with #MappingInfoModifierData. */
+
struct Tex *texture;
struct Object *map_object;
char map_bone[64];
@@ -720,7 +747,7 @@ typedef struct WaveModifierData {
char uvlayer_name[64];
int uvlayer_tmp;
int texmapping;
- /* end MappingInfoModifierData */
+ /* End MappingInfoModifierData. */
struct Object *objectcenter;
/** MAX_VGROUP_NAME. */
@@ -737,7 +764,7 @@ typedef struct WaveModifierData {
void *_pad2;
} WaveModifierData;
-/* WaveModifierData.flag */
+/** #WaveModifierData.flag */
enum {
MOD_WAVE_INVERT_VGROUP = (1 << 0),
MOD_WAVE_X = (1 << 1),
@@ -767,7 +794,7 @@ enum {
MOD_HOOK_INVERT_VGROUP = (1 << 1),
};
-/* same as WarpModifierFalloff */
+/** \note same as #WarpModifierFalloff */
typedef enum {
eHook_Falloff_None = 0,
eHook_Falloff_Curve = 1,
@@ -824,15 +851,17 @@ typedef struct ClothModifierData {
/** Definition is in DNA_cloth_types.h. */
struct ClothCollSettings *coll_parms;
- /* PointCache can be shared with other instances of ClothModifierData.
- * Inspect (modifier.flag & eModifierFlag_SharedCaches) to find out. */
+ /**
+ * PointCache can be shared with other instances of #ClothModifierData.
+ * Inspect `modifier.flag & eModifierFlag_SharedCaches` to find out.
+ */
/** Definition is in DNA_object_force_types.h. */
struct PointCache *point_cache;
struct ListBase ptcaches;
- /* XXX nasty hack, remove once hair can be separated from cloth modifier data */
+ /** XXX: nasty hack, remove once hair can be separated from cloth modifier data. */
struct ClothHairData *hairdata;
- /* grid geometry values of hair continuum */
+ /** Grid geometry values of hair continuum. */
float hair_grid_min[3];
float hair_grid_max[3];
int hair_grid_res[3];
@@ -899,20 +928,20 @@ typedef struct BooleanModifierData {
char bm_flag;
} BooleanModifierData;
-/* BooleanModifierData->operation */
+/** #BooleanModifierData.operation */
typedef enum {
eBooleanModifierOp_Intersect = 0,
eBooleanModifierOp_Union = 1,
eBooleanModifierOp_Difference = 2,
} BooleanModifierOp;
-/* BooleanModifierData->solver */
+/** #BooleanModifierData.solver */
typedef enum {
eBooleanModifierSolver_Fast = 0,
eBooleanModifierSolver_Exact = 1,
} BooleanModifierSolver;
-/* BooleanModifierData->flag */
+/** #BooleanModifierData.flag */
enum {
eBooleanModifierFlag_Self = (1 << 0),
eBooleanModifierFlag_Object = (1 << 1),
@@ -920,7 +949,7 @@ enum {
eBooleanModifierFlag_HoleTolerant = (1 << 3),
};
-/* bm_flag only used when G_DEBUG. */
+/** #BooleanModifierData.bm_flag (only used when #G_DEBUG is set). */
enum {
eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 0),
eBooleanModifierBMeshFlag_BMesh_NoDissolve = (1 << 1),
@@ -1094,7 +1123,7 @@ typedef enum {
eMultiresModifierFlag_UseSculptBaseMesh = (1 << 4),
} MultiresModifierFlag;
-/* DEPRECATED, only used for versioning. */
+/** DEPRECATED: only used for versioning. */
typedef struct FluidsimModifierData {
ModifierData modifier;
@@ -1103,7 +1132,7 @@ typedef struct FluidsimModifierData {
void *_pad1;
} FluidsimModifierData;
-/* DEPRECATED, only used for versioning. */
+/** DEPRECATED: only used for versioning. */
typedef struct SmokeModifierData {
ModifierData modifier;
@@ -1142,7 +1171,7 @@ typedef struct ShrinkwrapModifierData {
char _pad[2];
} ShrinkwrapModifierData;
-/* Shrinkwrap->shrinkType */
+/** #ShrinkwrapModifierData.shrinkType */
enum {
MOD_SHRINKWRAP_NEAREST_SURFACE = 0,
MOD_SHRINKWRAP_PROJECT = 1,
@@ -1150,7 +1179,7 @@ enum {
MOD_SHRINKWRAP_TARGET_PROJECT = 3,
};
-/* Shrinkwrap->shrinkMode */
+/** #ShrinkwrapModifierData.shrinkMode */
enum {
/** Move vertex to the surface of the target object (keepDist towards original position) */
MOD_SHRINKWRAP_ON_SURFACE = 0,
@@ -1164,7 +1193,7 @@ enum {
MOD_SHRINKWRAP_ABOVE_SURFACE = 4,
};
-/* Shrinkwrap->shrinkOpts */
+/** #ShrinkwrapModifierData.shrinkOpts */
enum {
/** allow shrinkwrap to move the vertex in the positive direction of axis */
MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR = (1 << 0),
@@ -1188,7 +1217,7 @@ enum {
#define MOD_SHRINKWRAP_CULL_TARGET_MASK \
(MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)
-/* Shrinkwrap->projAxis */
+/** #ShrinkwrapModifierData.projAxis */
enum {
/** projection over normal is used if no axis is selected */
MOD_SHRINKWRAP_PROJECT_OVER_NORMAL = 0,
@@ -1220,7 +1249,7 @@ typedef struct SimpleDeformModifierData {
void *_pad1;
} SimpleDeformModifierData;
-/* SimpleDeform->flag */
+/** #SimpleDeformModifierData.flag */
enum {
MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP = (1 << 0),
};
@@ -1426,7 +1455,9 @@ enum {
typedef struct WarpModifierData {
ModifierData modifier;
- /* keep in sync with MappingInfoModifierData */
+
+ /* Keep in sync with #MappingInfoModifierData. */
+
struct Tex *texture;
struct Object *map_object;
char map_bone[64];
@@ -1434,7 +1465,7 @@ typedef struct WarpModifierData {
char uvlayer_name[64];
int uvlayer_tmp;
int texmapping;
- /* end MappingInfoModifierData */
+ /* End #MappingInfoModifierData. */
struct Object *object_from;
struct Object *object_to;
@@ -1454,12 +1485,13 @@ typedef struct WarpModifierData {
void *_pad1;
} WarpModifierData;
-/* WarpModifierData->flag */
+/** #WarpModifierData.flag */
enum {
MOD_WARP_VOLUME_PRESERVE = (1 << 0),
MOD_WARP_INVERT_VGROUP = (1 << 1),
};
+/** \note same as #HookModifierFalloff. */
typedef enum {
eWarp_Falloff_None = 0,
eWarp_Falloff_Curve = 1,
@@ -1500,7 +1532,7 @@ typedef struct WeightVGEditModifierData {
char mask_defgrp_name[64];
/* Texture masking. */
- /** Which channel to use as weightf. */
+ /** Which channel to use as weight/mask. */
int mask_tex_use_channel;
/** The texture. */
struct Tex *mask_texture;
@@ -1518,7 +1550,7 @@ typedef struct WeightVGEditModifierData {
void *_pad1;
} WeightVGEditModifierData;
-/* WeightVGEdit flags. */
+/** #WeightVGEdit.edit_flags */
enum {
MOD_WVG_EDIT_WEIGHTS_NORMALIZE = (1 << 0),
MOD_WVG_INVERT_FALLOFF = (1 << 1),
@@ -1573,7 +1605,7 @@ typedef struct WeightVGMixModifierData {
char _pad1[3];
} WeightVGMixModifierData;
-/* How second vgroup's weights affect first ones. */
+/** #WeightVGMixModifierData.mix_mode (how second vgroup's weights affect first ones). */
enum {
/** Second weights replace weights. */
MOD_WVG_MIX_SET = 1,
@@ -1591,7 +1623,7 @@ enum {
MOD_WVG_MIX_AVG = 7,
};
-/* What vertices to affect. */
+/** #WeightVGMixModifierData.mix_set (what vertices to affect). */
enum {
/** Affect all vertices. */
MOD_WVG_SET_ALL = 1,
@@ -1605,7 +1637,7 @@ enum {
MOD_WVG_SET_AND = 5,
};
-/* WeightVGMix->flag */
+/** #WeightVGMixModifierData.flag */
enum {
MOD_WVG_MIX_INVERT_VGROUP_MASK = (1 << 0),
MOD_WVG_MIX_WEIGHTS_NORMALIZE = (1 << 1),
@@ -1623,8 +1655,9 @@ typedef struct WeightVGProximityModifierData {
/** The custom mapping curve. */
struct CurveMapping *cmap_curve;
- /* Proximity modes. */
+ /** Modes of proximity weighting. */
int proximity_mode;
+ /** Options for proximity weighting. */
int proximity_flags;
/* Target object from which to calculate vertices distances. */
@@ -1654,20 +1687,21 @@ typedef struct WeightVGProximityModifierData {
float min_dist, max_dist;
/* Put here to avoid breaking existing struct... */
- /** Using MOD_WVG_MAPPING_* enums. */
+ /**
+ * Mapping modes (using MOD_WVG_MAPPING_* enums). */
short falloff_type;
/* Padding... */
char _pad0[2];
} WeightVGProximityModifierData;
-/* Modes of proximity weighting. */
+/** #WeightVGProximityModifierData.proximity_mode */
enum {
MOD_WVG_PROXIMITY_OBJECT = 1, /* source vertex to other location */
MOD_WVG_PROXIMITY_GEOMETRY = 2, /* source vertex to other geometry */
};
-/* Flags options for proximity weighting. */
+/** #WeightVGProximityModifierData.proximity_flags */
enum {
/* Use nearest vertices of target obj, in MOD_WVG_PROXIMITY_GEOMETRY mode. */
MOD_WVG_PROXIMITY_GEOM_VERTS = (1 << 0),
@@ -1681,7 +1715,8 @@ enum {
};
/* Defines common to all WeightVG modifiers. */
-/* Mapping modes. */
+
+/** #WeightVGProximityModifierData.falloff_type */
enum {
MOD_WVG_MAPPING_NONE = 0,
MOD_WVG_MAPPING_CURVE = 1,
@@ -1695,7 +1730,7 @@ enum {
MOD_WVG_MAPPING_STEP = 9, /* Median Step. */
};
-/* Tex channel to be used as mask. */
+/** #WeightVGProximityModifierData.mask_tex_use_channel */
enum {
MOD_WVG_MASK_TEX_USE_INT = 1,
MOD_WVG_MASK_TEX_USE_RED = 2,
@@ -1717,13 +1752,13 @@ typedef struct DynamicPaintModifierData {
char _pad[4];
} DynamicPaintModifierData;
-/* Dynamic paint modifier flags */
+/** #DynamicPaintModifierData.type */
enum {
MOD_DYNAMICPAINT_TYPE_CANVAS = (1 << 0),
MOD_DYNAMICPAINT_TYPE_BRUSH = (1 << 1),
};
-/* Remesh modifier */
+/** Remesh modifier. */
typedef enum eRemeshModifierFlags {
MOD_REMESH_FLOOD_FILL = (1 << 0),
MOD_REMESH_SMOOTH_SHADING = (1 << 1),
@@ -1762,7 +1797,7 @@ typedef struct RemeshModifierData {
float adaptivity;
} RemeshModifierData;
-/* Skin modifier */
+/** Skin modifier. */
typedef struct SkinModifierData {
ModifierData modifier;
@@ -1775,19 +1810,19 @@ typedef struct SkinModifierData {
char _pad[2];
} SkinModifierData;
-/* SkinModifierData.symmetry_axes */
+/** #SkinModifierData.symmetry_axes */
enum {
MOD_SKIN_SYMM_X = (1 << 0),
MOD_SKIN_SYMM_Y = (1 << 1),
MOD_SKIN_SYMM_Z = (1 << 2),
};
-/* SkinModifierData.flag */
+/** #SkinModifierData.flag */
enum {
MOD_SKIN_SMOOTH_SHADING = 1,
};
-/* Triangulate modifier */
+/** Triangulate modifier. */
typedef struct TriangulateModifierData {
ModifierData modifier;
@@ -1797,7 +1832,7 @@ typedef struct TriangulateModifierData {
int min_vertices;
} TriangulateModifierData;
-/* TriangulateModifierData.flag */
+/** #TriangulateModifierData.flag */
enum {
#ifdef DNA_DEPRECATED_ALLOW
MOD_TRIANGULATE_BEAUTY = (1 << 0), /* deprecated */
@@ -1805,18 +1840,19 @@ enum {
MOD_TRIANGULATE_KEEP_CUSTOMLOOP_NORMALS = 1 << 1,
};
-/* Triangulate methods - NGons */
+/** #TriangulateModifierData.ngon_method triangulate method (N-gons). */
enum {
MOD_TRIANGULATE_NGON_BEAUTY = 0,
MOD_TRIANGULATE_NGON_EARCLIP = 1,
};
-/* Triangulate methods - Quads */
+/** #TriangulateModifierData.quad_method triangulate method (quads). */
enum {
MOD_TRIANGULATE_QUAD_BEAUTY = 0,
MOD_TRIANGULATE_QUAD_FIXED = 1,
MOD_TRIANGULATE_QUAD_ALTERNATE = 2,
MOD_TRIANGULATE_QUAD_SHORTEDGE = 3,
+ MOD_TRIANGULATE_QUAD_LONGEDGE = 4,
};
typedef struct LaplacianSmoothModifierData {
@@ -1829,7 +1865,7 @@ typedef struct LaplacianSmoothModifierData {
short flag, repeat;
} LaplacianSmoothModifierData;
-/* Smooth modifier flags */
+/** #LaplacianSmoothModifierData.flag */
enum {
MOD_LAPLACIANSMOOTH_X = (1 << 1),
MOD_LAPLACIANSMOOTH_Y = (1 << 2),
@@ -1884,7 +1920,7 @@ enum {
MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND = 1,
};
-/* Corrective Smooth modifier flags */
+/** #CorrectiveSmoothModifierData.flag */
enum {
MOD_CORRECTIVESMOOTH_INVERT_VGROUP = (1 << 0),
MOD_CORRECTIVESMOOTH_ONLY_SMOOTH = (1 << 1),
@@ -1918,12 +1954,12 @@ typedef struct UVWarpModifierData {
char uvlayer_name[64];
} UVWarpModifierData;
-/* UVWarp modifier flags */
+/** #UVWarpModifierData.flag */
enum {
MOD_UVWARP_INVERT_VGROUP = 1 << 0,
};
-/* cache modifier */
+/** Mesh cache modifier. */
typedef struct MeshCacheModifierData {
ModifierData modifier;
@@ -1959,7 +1995,7 @@ typedef struct MeshCacheModifierData {
char filepath[1024];
} MeshCacheModifierData;
-/* MeshCache modifier flags. */
+/** #MeshCacheModifierData.flag */
enum {
MOD_MESHCACHE_INVERT_VERTEX_GROUP = 1 << 0,
};
@@ -2004,13 +2040,15 @@ typedef struct LaplacianDeformModifierData {
} LaplacianDeformModifierData;
-/* Laplacian Deform modifier flags */
+/** #LaplacianDeformModifierData.flag */
enum {
MOD_LAPLACIANDEFORM_BIND = 1 << 0,
MOD_LAPLACIANDEFORM_INVERT_VGROUP = 1 << 1,
};
-/* many of these options match 'solidify' */
+/**
+ * \note many of these options match 'solidify'.
+ */
typedef struct WireframeModifierData {
ModifierData modifier;
/** MAX_VGROUP_NAME. */
@@ -2045,13 +2083,13 @@ typedef struct WeldModifierData {
char _pad[2];
} WeldModifierData;
-/* WeldModifierData->flag */
+/** #WeldModifierData.flag */
enum {
MOD_WELD_INVERT_VGROUP = (1 << 0),
MOD_WELD_LOOSE_EDGES = (1 << 1),
};
-/* #WeldModifierData.mode */
+/** #WeldModifierData.mode */
enum {
MOD_WELD_MODE_ALL = 0,
MOD_WELD_MODE_CONNECTED = 1,
@@ -2092,7 +2130,7 @@ typedef struct DataTransferModifierData {
void *_pad2;
} DataTransferModifierData;
-/* DataTransferModifierData.flags */
+/** #DataTransferModifierData.flags */
enum {
MOD_DATATRANSFER_OBSRC_TRANSFORM = 1 << 0,
MOD_DATATRANSFER_MAP_MAXDIST = 1 << 1,
@@ -2105,7 +2143,7 @@ enum {
MOD_DATATRANSFER_USE_POLY = 1u << 31,
};
-/* Set Split Normals modifier */
+/** Set Split Normals modifier. */
typedef struct NormalEditModifierData {
ModifierData modifier;
/** MAX_VGROUP_NAME. */
@@ -2123,20 +2161,20 @@ typedef struct NormalEditModifierData {
void *_pad1;
} NormalEditModifierData;
-/* NormalEditModifierData.mode */
+/** #NormalEditModifierData.mode */
enum {
MOD_NORMALEDIT_MODE_RADIAL = 0,
MOD_NORMALEDIT_MODE_DIRECTIONAL = 1,
};
-/* NormalEditModifierData.flags */
+/** #NormalEditModifierData.flags */
enum {
MOD_NORMALEDIT_INVERT_VGROUP = (1 << 0),
MOD_NORMALEDIT_USE_DIRECTION_PARALLEL = (1 << 1),
MOD_NORMALEDIT_NO_POLYNORS_FIX = (1 << 2),
};
-/* NormalEditModifierData.mix_mode */
+/** #NormalEditModifierData.mix_mode */
enum {
MOD_NORMALEDIT_MIX_COPY = 0,
MOD_NORMALEDIT_MIX_ADD = 1,
@@ -2161,7 +2199,7 @@ typedef struct MeshSeqCacheModifierData {
char reader_object_path[1024];
} MeshSeqCacheModifierData;
-/* MeshSeqCacheModifierData.read_flag */
+/** #MeshSeqCacheModifierData.read_flag */
enum {
MOD_MESHSEQ_READ_VERT = (1 << 0),
MOD_MESHSEQ_READ_POLY = (1 << 1),
@@ -2206,7 +2244,7 @@ typedef struct SurfaceDeformModifierData {
void *_pad1;
} SurfaceDeformModifierData;
-/* Surface Deform modifier flags */
+/** Surface Deform modifier flags. */
enum {
/* This indicates "do bind on next modifier evaluation" as well as "is bound". */
MOD_SDEF_BIND = (1 << 0),
@@ -2215,7 +2253,7 @@ enum {
MOD_SDEF_SPARSE_BIND = (1 << 2),
};
-/* Surface Deform vertex bind modes */
+/** Surface Deform vertex bind modes. */
enum {
MOD_SDEF_MODE_LOOPTRI = 0,
MOD_SDEF_MODE_NGON = 1,
@@ -2235,14 +2273,14 @@ typedef struct WeightedNormalModifierData {
/* Name/id of the generic PROP_INT cdlayer storing face weights. */
#define MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID "__mod_weightednormals_faceweight"
-/* WeightedNormalModifierData.mode */
+/** #WeightedNormalModifierData.mode */
enum {
MOD_WEIGHTEDNORMAL_MODE_FACE = 0,
MOD_WEIGHTEDNORMAL_MODE_ANGLE = 1,
MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE = 2,
};
-/* WeightedNormalModifierData.flag */
+/** #WeightedNormalModifierData.flag */
enum {
MOD_WEIGHTEDNORMAL_KEEP_SHARP = (1 << 0),
MOD_WEIGHTEDNORMAL_INVERT_VGROUP = (1 << 1),
@@ -2262,8 +2300,10 @@ typedef struct NodesModifierData {
struct bNodeTree *node_group;
struct NodesModifierSettings settings;
- /* Contains logged information from the last evaluation. This can be used to help the user to
- * debug a node tree. */
+ /**
+ * Contains logged information from the last evaluation.
+ * This can be used to help the user to debug a node tree.
+ */
void *runtime_eval_log;
void *_pad1;
} NodesModifierData;
@@ -2296,7 +2336,7 @@ typedef struct MeshToVolumeModifierData {
void *_pad3;
} MeshToVolumeModifierData;
-/* MeshToVolumeModifierData->resolution_mode */
+/** #MeshToVolumeModifierData.resolution_mode */
typedef enum MeshToVolumeModifierResolutionMode {
MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT = 0,
MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE = 1,
@@ -2314,7 +2354,7 @@ typedef struct VolumeDisplaceModifierData {
float texture_sample_radius;
} VolumeDisplaceModifierData;
-/* VolumeDisplaceModifierData->texture_map_mode */
+/** #VolumeDisplaceModifierData.texture_map_mode */
enum {
MOD_VOLUME_DISPLACE_MAP_LOCAL = 0,
MOD_VOLUME_DISPLACE_MAP_GLOBAL = 1,
diff --git a/source/blender/makesdna/DNA_movieclip_defaults.h b/source/blender/makesdna/DNA_movieclip_defaults.h
index 753147eb072..441c2231009 100644
--- a/source/blender/makesdna/DNA_movieclip_defaults.h
+++ b/source/blender/makesdna/DNA_movieclip_defaults.h
@@ -45,6 +45,34 @@
.frame_offset = 0, \
}
+#define _DNA_DEFAULT_MovieClipUser \
+ { \
+ .framenr = 1, \
+ .render_size = MCLIP_PROXY_RENDER_SIZE_FULL, \
+ .render_flag = 0, \
+ }
+
+#define _DNA_DEFAULT_MovieClipScopes \
+ { \
+ .ok = 0, \
+ .use_track_mask = 0, \
+ .track_preview_height = 120, \
+ .frame_width = 0, \
+ .frame_height = 0, \
+ .undist_marker = _DNA_DEFAULT_MovieTrackingMarker, \
+ .track_pos = {0, 0}, \
+ .track_disabled = 0, \
+ .track_locked = 0, \
+ .scene_framenr = 0, \
+ .slide_scale = {0.0f, 0.0f}, \
+ }
+
+/* initialize as all zeros. */
+#define _DNA_DEFAULT_MovieTrackingMarker \
+ { \
+ .pos = {0.0f, 0.0f}, \
+ }
+
/** \} */
/* clang-format on */
diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h
index 8e01a9e1f1f..08064e6242b 100644
--- a/source/blender/makesdna/DNA_movieclip_types.h
+++ b/source/blender/makesdna/DNA_movieclip_types.h
@@ -160,7 +160,7 @@ typedef struct MovieClipScopes {
float slide_scale[2];
} MovieClipScopes;
-/* MovieClipProxy->build_size_flag */
+/** #MovieClipProxy.build_size_flag */
enum {
MCLIP_PROXY_SIZE_25 = (1 << 0),
MCLIP_PROXY_SIZE_50 = (1 << 1),
@@ -172,13 +172,13 @@ enum {
MCLIP_PROXY_UNDISTORTED_SIZE_100 = (1 << 7),
};
-/* MovieClip->source */
+/** #MovieClip.source */
enum {
MCLIP_SRC_SEQUENCE = 1,
MCLIP_SRC_MOVIE = 2,
};
-/* MovieClip->flag */
+/** #MovieClip.flag */
enum {
MCLIP_USE_PROXY = (1 << 0),
MCLIP_USE_PROXY_CUSTOM_DIR = (1 << 1),
@@ -188,7 +188,7 @@ enum {
MCLIP_TIMECODE_FLAGS = (MCLIP_USE_PROXY | MCLIP_USE_PROXY_CUSTOM_DIR),
};
-/* MovieClip->render_size */
+/** #MovieClip.render_size */
enum {
MCLIP_PROXY_RENDER_SIZE_FULL = 0,
MCLIP_PROXY_RENDER_SIZE_25 = 1,
@@ -197,7 +197,7 @@ enum {
MCLIP_PROXY_RENDER_SIZE_100 = 4,
};
-/* MovieClip->render_flag */
+/** #MovieClip.render_flag */
enum {
MCLIP_PROXY_RENDER_UNDISTORT = 1,
/** Use original, if proxy is not found. */
diff --git a/source/blender/makesdna/DNA_nla_types.h b/source/blender/makesdna/DNA_nla_types.h
index 7808dd68384..82edc0e1816 100644
--- a/source/blender/makesdna/DNA_nla_types.h
+++ b/source/blender/makesdna/DNA_nla_types.h
@@ -33,7 +33,7 @@ struct Ipo;
struct Object;
struct bAction;
-/* simple uniform modifier structure, assumed it can hold all type info */
+/** Simple uniform modifier structure, assumed it can hold all type info. */
typedef struct bActionModifier {
struct bActionModifier *next, *prev;
short type, flag;
@@ -95,7 +95,7 @@ typedef struct bActionStrip {
#define ACTSTRIPMODE_BLEND 0
#define ACTSTRIPMODE_ADD 1
-/* strip->flag */
+/** #bActionStrip.flag */
typedef enum eActStrip_Flag {
ACTSTRIP_SELECT = (1 << 0),
ACTSTRIP_USESTRIDE = (1 << 1),
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 99c83b57521..0b24dfea0b0 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -38,6 +38,7 @@ struct ID;
struct Image;
struct ListBase;
struct Material;
+struct PreviewImage;
struct Tex;
struct bGPdata;
struct bNodeInstanceHash;
@@ -80,8 +81,21 @@ typedef struct bNodeStack {
#define NS_CR_FIT 4
#define NS_CR_STRETCH 5
+/** Workaround to forward-declare C++ type in C header. */
+#ifdef __cplusplus
+namespace blender::nodes {
+class NodeDeclaration;
+class SocketDeclaration;
+} // namespace blender::nodes
+using NodeDeclarationHandle = blender::nodes::NodeDeclaration;
+using SocketDeclarationHandle = blender::nodes::SocketDeclaration;
+#else
+typedef struct NodeDeclarationHandle NodeDeclarationHandle;
+typedef struct SocketDeclarationHandle SocketDeclarationHandle;
+#endif
+
typedef struct bNodeSocket {
- struct bNodeSocket *next, *prev, *new_sock;
+ struct bNodeSocket *next, *prev;
/** User-defined properties. */
IDProperty *prop;
@@ -92,15 +106,21 @@ typedef struct bNodeSocket {
/** MAX_NAME. */
char name[64];
- /* XXX deprecated, only used for the Image and OutputFile nodes,
- * should be removed at some point.
- */
- /** Custom storage. */
+ /** Only used for the Image and OutputFile nodes, should be removed at some point. */
void *storage;
- short type, flag;
- /** Max. number of links. Read via nodeSocketLinkLimit,
- * because the limit might be defined on the socket type. */
+ /**
+ * The socket's data type. #eNodeSocketDatatype.
+ */
+ short type;
+ /** #eNodeSocketFlag */
+ short flag;
+ /**
+ * Maximum number of links that can connect to the socket. Read via #nodeSocketLinkLimit, because
+ * the limit might be defined on the socket type, in which case this value does not have any
+ * effect. It is necessary to store this in the socket because it is exposed as an RNA property
+ * for custom nodes.
+ */
short limit;
/** Input/output type. */
short in_out;
@@ -109,6 +129,10 @@ typedef struct bNodeSocket {
/** Runtime type identifier. */
char idname[64];
+ /**
+ * The location of the sockets, in the view-space of the node editor.
+ * \note These are runtime data-- only calculated when drawing, and could be removed from DNA.
+ */
float locx, locy;
/** Default input value used for unlinked sockets. */
@@ -145,16 +169,26 @@ typedef struct bNodeSocket {
* restores pointer from matching own_index. */
struct bNodeSocket *groupsock DNA_DEPRECATED;
- /** A link pointer, set in ntreeUpdateTree. */
+ /** A link pointer, set in #BKE_ntree_update_main. */
struct bNodeLink *link;
/* XXX deprecated, socket input values are stored in default_value now.
* kept for forward compatibility */
/** Custom data for inputs, only UI writes in this. */
bNodeStack ns DNA_DEPRECATED;
+
+ /**
+ * References a socket declaration that is owned by `node->declaration`. This is only runtime
+ * data. It has to be updated when the node declaration changes.
+ */
+ const SocketDeclarationHandle *declaration;
+
+ /** #eNodeTreeChangedFlag. */
+ uint32_t changed_flag;
+ char _pad[4];
} bNodeSocket;
-/* sock->type */
+/** #bNodeSocket.type & #bNodeSocketType.type */
typedef enum eNodeSocketDatatype {
SOCK_CUSTOM = -1, /* socket has no integer type */
SOCK_FLOAT = 0,
@@ -173,7 +207,7 @@ typedef enum eNodeSocketDatatype {
SOCK_MATERIAL = 13,
} eNodeSocketDatatype;
-/* Socket shape. */
+/** Socket shape. */
typedef enum eNodeSocketDisplayShape {
SOCK_DISPLAY_SHAPE_CIRCLE = 0,
SOCK_DISPLAY_SHAPE_SQUARE = 1,
@@ -183,13 +217,13 @@ typedef enum eNodeSocketDisplayShape {
SOCK_DISPLAY_SHAPE_DIAMOND_DOT = 5,
} eNodeSocketDisplayShape;
-/* Socket side (input/output). */
+/** Socket side (input/output). */
typedef enum eNodeSocketInOut {
SOCK_IN = 1 << 0,
SOCK_OUT = 1 << 1,
} eNodeSocketInOut;
-/* #bNodeSocket.flag, first bit is selection. */
+/** #bNodeSocket.flag, first bit is selection. */
typedef enum eNodeSocketFlag {
/** Hidden is user defined, to hide unused sockets. */
SOCK_HIDDEN = (1 << 1),
@@ -219,19 +253,9 @@ typedef enum eNodeSocketFlag {
SOCK_HIDE_LABEL = (1 << 12),
} eNodeSocketFlag;
-/** Workaround to forward-declare C++ type in C header. */
-#ifdef __cplusplus
-namespace blender::nodes {
-class NodeDeclaration;
-}
-using NodeDeclarationHandle = blender::nodes::NodeDeclaration;
-#else
-typedef struct NodeDeclarationHandle NodeDeclarationHandle;
-#endif
-
-/* TODO: Limit data in bNode to what we want to see saved. */
+/** TODO: Limit data in #bNode to what we want to see saved. */
typedef struct bNode {
- struct bNode *next, *prev, *new_node;
+ struct bNode *next, *prev;
/** User-defined properties. */
IDProperty *prop;
@@ -250,8 +274,9 @@ typedef struct bNode {
/** Used as a boolean for execution. */
uint8_t need_exec;
-
- char _pad[1];
+ char _pad2[5];
+ /** #eNodeTreeChangedFlag. */
+ uint32_t changed_flag;
/** Custom user-defined color. */
float color[3];
@@ -292,10 +317,8 @@ typedef struct bNode {
char _pad1[4];
- /** Entire boundbox (worldspace). */
+ /** Entire bound-box (world-space). */
rctf totr;
- /** Optional buttons area. */
- rctf butr;
/** Optional preview area. */
rctf prvr;
/**
@@ -315,8 +338,6 @@ typedef struct bNode {
char branch_tag;
/** Used at runtime when iterating over node branches. */
char iter_flag;
- /** Runtime during drawing. */
- struct uiBlock *block;
/**
* Describes the desired interface of the node. This is run-time data only.
@@ -345,7 +366,7 @@ typedef struct bNode {
#define NODE_PREVIEW 4
#define NODE_HIDDEN 8
#define NODE_ACTIVE 16
-#define NODE_ACTIVE_ID 32
+// #define NODE_ACTIVE_ID 32 /* deprecated */
/* Used to indicate which group output node is used and which viewer node is active. */
#define NODE_DO_OUTPUT 64
#define __NODE_GROUP_EDIT 128 /* DEPRECATED */
@@ -354,8 +375,7 @@ typedef struct bNode {
/* node is disabled */
#define NODE_MUTED 512
// #define NODE_CUSTOM_NAME 1024 /* deprecated! */
-/* group node types: use const outputs by default */
-#define NODE_CONST_OUTPUT (1 << 11)
+// #define NODE_CONST_OUTPUT (1 << 11) /* deprecated */
/* node is always behind others */
#define NODE_BACKGROUND (1 << 12)
/* automatic flag for nodes included in transforms */
@@ -384,10 +404,6 @@ typedef struct bNode {
#define __NODE_ACTIVE_PREVIEW (1 << 18) /* deprecated */
/* node->update */
-/* XXX NODE_UPDATE is a generic update flag. More fine-grained updates
- * might be used in the future, but currently all work the same way.
- */
-#define NODE_UPDATE 0xFFFF /* generic update flag (includes all others) */
#define NODE_UPDATE_ID 1 /* associated id data block has changed */
#define NODE_UPDATE_OPERATOR 2 /* node update triggered from update operator */
@@ -495,8 +511,12 @@ typedef struct bNodeTree {
*/
int cur_index;
int flag;
- /** Update flags. */
- int update;
+ /**
+ * Keeps track of what changed in the node tree until the next update.
+ * Should not be changed directly, instead use the functions in `BKE_node_tree_update.h`.
+ * #eNodeTreeChangedFlag.
+ */
+ uint32_t changed_flag;
/** Flag to prevent re-entrant update calls. */
short is_updating;
/** Generic temporary flag for recursion check (DFS/BFS). */
@@ -530,7 +550,11 @@ typedef struct bNodeTree {
* in case multiple different editors are used and make context ambiguous.
*/
bNodeInstanceKey active_viewer_key;
- char _pad[4];
+ /**
+ * A hash of the topology of the node tree leading up to the outputs. This is used to determine
+ * of the node tree changed in a way that requires updating geometry nodes or shaders.
+ */
+ uint32_t output_topology_hash;
/** Execution data.
*
@@ -550,19 +574,24 @@ typedef struct bNodeTree {
int (*test_break)(void *);
void (*update_draw)(void *);
void *tbh, *prh, *sdh, *udh;
+
+ /** Image representing what the node group does. */
+ struct PreviewImage *preview;
} bNodeTree;
-/* ntree->type, index */
-#define NTREE_CUSTOM -1 /* for dynamically registered custom types */
+/** #NodeTree.type, index */
+
+#define NTREE_UNDEFINED -2 /* Represents #NodeTreeTypeUndefined type. */
+#define NTREE_CUSTOM -1 /* for dynamically registered custom types */
#define NTREE_SHADER 0
#define NTREE_COMPOSIT 1
#define NTREE_TEXTURE 2
#define NTREE_GEOMETRY 3
-/* ntree->init, flag */
+/** #NodeTree.init, flag */
#define NTREE_TYPE_INIT 1
-/* ntree->flag */
+/** #NodeTree.flag */
#define NTREE_DS_EXPAND (1 << 0) /* for animation editors */
#define NTREE_COM_OPENCL (1 << 1) /* use opencl */
#define NTREE_TWO_PASS (1 << 2) /* two pass */
@@ -573,20 +602,6 @@ typedef struct bNodeTree {
/* tree is localized copy, free when deleting node groups */
/* #define NTREE_IS_LOCALIZED (1 << 5) */
-/* ntree->update */
-typedef enum eNodeTreeUpdate {
- NTREE_UPDATE = 0xFFFF, /* generic update flag (includes all others) */
- NTREE_UPDATE_LINKS = (1 << 0), /* links have been added or removed */
- NTREE_UPDATE_NODES = (1 << 1), /* nodes or sockets have been added or removed */
- NTREE_UPDATE_GROUP_IN = (1 << 4), /* group inputs have changed */
- NTREE_UPDATE_GROUP_OUT = (1 << 5), /* group outputs have changed */
- /* The field interface has changed. So e.g. an output that was always a field before is not
- * anymore. This implies that the field type inferencing has to be done again. */
- NTREE_UPDATE_FIELD_INFERENCING = (1 << 6),
- /* group has changed (generic flag including all other group flags) */
- NTREE_UPDATE_GROUP = (NTREE_UPDATE_GROUP_IN | NTREE_UPDATE_GROUP_OUT),
-} eNodeTreeUpdate;
-
/* tree->execution_mode */
typedef enum eNodeTreeExecutionMode {
NTREE_EXECUTION_MODE_TILED = 0,
@@ -653,7 +668,8 @@ typedef struct bNodeSocketValueMaterial {
struct Material *value;
} bNodeSocketValueMaterial;
-/* Data structs, for node->storage. */
+/* Data structs, for `node->storage`. */
+
enum {
CMP_NODE_MASKTYPE_ADD = 0,
CMP_NODE_MASKTYPE_SUBTRACT = 1,
@@ -692,7 +708,7 @@ typedef struct NodeFrame {
short label_size;
} NodeFrame;
-/* This one has been replaced with ImageUser, keep it for do_versions(). */
+/** \note This one has been replaced with #ImageUser, keep it for do_versions(). */
typedef struct NodeImageAnim {
int frames DNA_DEPRECATED;
int sfra DNA_DEPRECATED;
@@ -746,7 +762,7 @@ typedef struct NodeEllipseMask {
char _pad[4];
} NodeEllipseMask;
-/* Layer info for image node outputs. */
+/** Layer info for image node outputs. */
typedef struct NodeImageLayer {
/* index in the Image->layers->passes lists */
int pass_index DNA_DEPRECATED;
@@ -784,7 +800,7 @@ typedef struct NodeAntiAliasingData {
float corner_rounding;
} NodeAntiAliasingData;
-/* NOTE: Only for do-version code. */
+/** \note Only for do-version code. */
typedef struct NodeHueSat {
float hue, sat, val;
} NodeHueSat;
@@ -796,7 +812,9 @@ typedef struct NodeImageFile {
int sfra, efra;
} NodeImageFile;
-/* XXX first struct fields should match NodeImageFile to ensure forward compatibility */
+/**
+ * XXX: first struct fields should match #NodeImageFile to ensure forward compatibility.
+ */
typedef struct NodeImageMultiFile {
/** 1024 = FILE_MAX. */
char base_path[1024];
@@ -904,6 +922,11 @@ typedef struct NodeColorspill {
float uspillr, uspillg, uspillb;
} NodeColorspill;
+typedef struct NodeConvertColorSpace {
+ char from_color_space[64];
+ char to_color_space[64];
+} NodeConvertColorSpace;
+
typedef struct NodeDilateErode {
char falloff;
} NodeDilateErode;
@@ -1045,7 +1068,7 @@ typedef struct NodeShaderPrincipled {
char _pad[3];
} NodeShaderPrincipled;
-/* TEX_output */
+/** TEX_output. */
typedef struct TexNodeOutput {
char name[64];
} TexNodeOutput;
@@ -1183,6 +1206,16 @@ typedef struct NodeDenoise {
char prefilter;
} NodeDenoise;
+typedef struct NodeMapRange {
+ /* CustomDataType */
+ uint8_t data_type;
+
+ /* NodeMapRangeType. */
+ uint8_t interpolation_type;
+ uint8_t clamp;
+ char _pad[5];
+} NodeMapRange;
+
typedef struct NodeAttributeClamp {
/* CustomDataType. */
uint8_t data_type;
@@ -1235,6 +1268,13 @@ typedef struct NodeRandomValue {
uint8_t data_type;
} NodeRandomValue;
+typedef struct NodeAccumulateField {
+ /* CustomDataType. */
+ uint8_t data_type;
+ /* AttributeDomain. */
+ uint8_t domain;
+} NodeAccumulateField;
+
typedef struct NodeAttributeRandomize {
/* CustomDataType. */
uint8_t data_type;
@@ -1280,10 +1320,22 @@ typedef struct NodeAttributeCurveMap {
CurveMapping *curve_rgb;
} NodeAttributeCurveMap;
+typedef struct NodeInputBool {
+ uint8_t boolean;
+} NodeInputBool;
+
+typedef struct NodeInputInt {
+ int integer;
+} NodeInputInt;
+
typedef struct NodeInputVector {
float vector[3];
} NodeInputVector;
+typedef struct NodeInputColor {
+ float color[4];
+} NodeInputColor;
+
typedef struct NodeInputString {
char *string;
} NodeInputString;
@@ -1322,6 +1374,11 @@ typedef struct NodeGeometryPointTranslate {
uint8_t input_type;
} NodeGeometryPointTranslate;
+typedef struct NodeGeometryExtrudeMesh {
+ /* GeometryNodeExtrudeMeshMode */
+ uint8_t mode;
+} NodeGeometryExtrudeMesh;
+
typedef struct NodeGeometryObjectInfo {
/* GeometryNodeTransformSpace. */
uint8_t transform_space;
@@ -1421,6 +1478,11 @@ typedef struct NodeGeometryCurveSplineType {
uint8_t spline_type;
} NodeGeometryCurveSplineType;
+typedef struct NodeGeometrySetCurveHandlePositions {
+ /* GeometryNodeCurveHandleMode. */
+ uint8_t mode;
+} NodeGeometrySetCurveHandlePositions;
+
typedef struct NodeGeometryCurveSetHandles {
/* GeometryNodeCurveHandleType. */
uint8_t handle_type;
@@ -1435,6 +1497,11 @@ typedef struct NodeGeometryCurveSelectHandles {
uint8_t mode;
} NodeGeometryCurveSelectHandles;
+typedef struct NodeGeometryCurvePrimitiveArc {
+ /* GeometryNodeCurvePrimitiveArcMode. */
+ uint8_t mode;
+} NodeGeometryCurvePrimitiveArc;
+
typedef struct NodeGeometryCurvePrimitiveLine {
/* GeometryNodeCurvePrimitiveLineMode. */
uint8_t mode;
@@ -1492,13 +1559,27 @@ typedef struct NodeGeometryAttributeTransfer {
uint8_t mapping;
} NodeGeometryAttributeTransfer;
+typedef struct NodeGeometryTransferAttribute {
+ /* CustomDataType. */
+ int8_t data_type;
+ /* AttributeDomain. */
+ int8_t domain;
+ /* GeometryNodeAttributeTransferMode. */
+ uint8_t mode;
+ char _pad[1];
+} NodeGeometryTransferAttribute;
+
typedef struct NodeGeometryRaycast {
/* GeometryNodeRaycastMapMode. */
uint8_t mapping;
+ /* CustomDataType. */
+ int8_t data_type;
+
+ /* Deprecated input types in new Ray-cast node. Can be removed when legacy nodes are no longer
+ * supported. */
uint8_t input_type_ray_direction;
uint8_t input_type_ray_length;
- char _pad[1];
} NodeGeometryRaycast;
typedef struct NodeGeometryCurveFill {
@@ -1527,6 +1608,38 @@ typedef struct NodeGeometryStringToCurves {
char _pad[1];
} NodeGeometryStringToCurves;
+typedef struct NodeGeometryDeleteGeometry {
+ /* AttributeDomain. */
+ int8_t domain;
+ /* GeometryNodeDeleteGeometryMode. */
+ int8_t mode;
+} NodeGeometryDeleteGeometry;
+
+typedef struct NodeGeometrySeparateGeometry {
+ /* AttributeDomain. */
+ int8_t domain;
+} NodeGeometrySeparateGeometry;
+
+typedef struct NodeGeometryImageTexture {
+ int interpolation;
+ int extension;
+} NodeGeometryImageTexture;
+
+typedef struct NodeGeometryViewer {
+ /* CustomDataType. */
+ int8_t data_type;
+} NodeGeometryViewer;
+
+typedef struct NodeFunctionCompare {
+ /* NodeCompareOperation */
+ int8_t operation;
+ /* eNodeSocketDatatype */
+ int8_t data_type;
+ /* NodeCompareMode */
+ int8_t mode;
+ char _pad[1];
+} NodeFunctionCompare;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -1538,14 +1651,17 @@ typedef struct NodeGeometryStringToCurves {
#define NODE_IES_INTERNAL 0
#define NODE_IES_EXTERNAL 1
-/* frame node flags */
+/* Frame node flags. */
+
#define NODE_FRAME_SHRINK 1 /* keep the bounding box minimal */
#define NODE_FRAME_RESIZEABLE 2 /* test flag, if frame can be resized by user */
-/* proxy node flags */
+/* Proxy node flags. */
+
#define NODE_PROXY_AUTOTYPE 1 /* automatically change output type based on link */
-/* comp channel matte */
+/* Comp channel matte. */
+
#define CMP_NODE_CHANNEL_MATTE_CS_RGB 1
#define CMP_NODE_CHANNEL_MATTE_CS_HSV 2
#define CMP_NODE_CHANNEL_MATTE_CS_YUV 3
@@ -1567,7 +1683,7 @@ typedef struct NodeGeometryStringToCurves {
#define SHD_VECT_TRANSFORM_SPACE_OBJECT 1
#define SHD_VECT_TRANSFORM_SPACE_CAMERA 2
-/* attribute */
+/** #NodeShaderAttribute.type */
enum {
SHD_ATTRIBUTE_GEOMETRY = 0,
SHD_ATTRIBUTE_OBJECT = 1,
@@ -1701,7 +1817,7 @@ enum {
#define SHD_AO_INSIDE 1
#define SHD_AO_LOCAL 2
-/* Mapping node vector types. */
+/** Mapping node vector types. */
enum {
NODE_MAPPING_TYPE_POINT = 0,
NODE_MAPPING_TYPE_TEXTURE = 1,
@@ -1709,7 +1825,7 @@ enum {
NODE_MAPPING_TYPE_NORMAL = 3,
};
-/* Rotation node vector types. */
+/** Rotation node vector types. */
enum {
NODE_VECTOR_ROTATE_TYPE_AXIS = 0,
NODE_VECTOR_ROTATE_TYPE_AXIS_X = 1,
@@ -1721,7 +1837,6 @@ enum {
/* math node clamp */
#define SHD_MATH_CLAMP 1
-/* Math node operations. */
typedef enum NodeMathOperation {
NODE_MATH_ADD = 0,
NODE_MATH_SUBTRACT = 1,
@@ -1765,7 +1880,6 @@ typedef enum NodeMathOperation {
NODE_MATH_SMOOTH_MAX = 39,
} NodeMathOperation;
-/* Vector Math node operations. */
typedef enum NodeVectorMathOperation {
NODE_VECTOR_MATH_ADD = 0,
NODE_VECTOR_MATH_SUBTRACT = 1,
@@ -1799,24 +1913,39 @@ typedef enum NodeVectorMathOperation {
NODE_VECTOR_MATH_MULTIPLY_ADD = 26,
} NodeVectorMathOperation;
-/* Boolean math node operations. */
-enum {
+typedef enum NodeBooleanMathOperation {
NODE_BOOLEAN_MATH_AND = 0,
NODE_BOOLEAN_MATH_OR = 1,
NODE_BOOLEAN_MATH_NOT = 2,
-};
-/* Float compare node operations. */
-typedef enum FloatCompareOperation {
- NODE_FLOAT_COMPARE_LESS_THAN = 0,
- NODE_FLOAT_COMPARE_LESS_EQUAL = 1,
- NODE_FLOAT_COMPARE_GREATER_THAN = 2,
- NODE_FLOAT_COMPARE_GREATER_EQUAL = 3,
- NODE_FLOAT_COMPARE_EQUAL = 4,
- NODE_FLOAT_COMPARE_NOT_EQUAL = 5,
-} FloatCompareOperation;
-
-/* Float to Int node operations. */
+ NODE_BOOLEAN_MATH_NAND = 3,
+ NODE_BOOLEAN_MATH_NOR = 4,
+ NODE_BOOLEAN_MATH_XNOR = 5,
+ NODE_BOOLEAN_MATH_XOR = 6,
+
+ NODE_BOOLEAN_MATH_IMPLY = 7,
+ NODE_BOOLEAN_MATH_NIMPLY = 8,
+} NodeBooleanMathOperation;
+
+typedef enum NodeCompareMode {
+ NODE_COMPARE_MODE_ELEMENT = 0,
+ NODE_COMPARE_MODE_LENGTH = 1,
+ NODE_COMPARE_MODE_AVERAGE = 2,
+ NODE_COMPARE_MODE_DOT_PRODUCT = 3,
+ NODE_COMPARE_MODE_DIRECTION = 4
+} NodeCompareMode;
+
+typedef enum NodeCompareOperation {
+ NODE_COMPARE_LESS_THAN = 0,
+ NODE_COMPARE_LESS_EQUAL = 1,
+ NODE_COMPARE_GREATER_THAN = 2,
+ NODE_COMPARE_GREATER_EQUAL = 3,
+ NODE_COMPARE_EQUAL = 4,
+ NODE_COMPARE_NOT_EQUAL = 5,
+ NODE_COMPARE_COLOR_BRIGHTER = 6,
+ NODE_COMPARE_COLOR_DARKER = 7,
+} NodeCompareOperation;
+
typedef enum FloatToIntRoundingMode {
FN_NODE_FLOAT_TO_INT_ROUND = 0,
FN_NODE_FLOAT_TO_INT_FLOOR = 1,
@@ -1824,13 +1953,13 @@ typedef enum FloatToIntRoundingMode {
FN_NODE_FLOAT_TO_INT_TRUNCATE = 3,
} FloatToIntRoundingMode;
-/* Clamp node types. */
+/** Clamp node types. */
enum {
NODE_CLAMP_MINMAX = 0,
NODE_CLAMP_RANGE = 1,
};
-/* Map range node types. */
+/** Map range node types. */
enum {
NODE_MAP_RANGE_LINEAR = 0,
NODE_MAP_RANGE_STEPPED = 1,
@@ -1842,14 +1971,15 @@ enum {
#define SHD_MIXRGB_USE_ALPHA 1
#define SHD_MIXRGB_CLAMP 2
-/* subsurface */
+/* Subsurface. */
+
enum {
#ifdef DNA_DEPRECATED_ALLOW
SHD_SUBSURFACE_COMPATIBLE = 0, /* Deprecated */
SHD_SUBSURFACE_CUBIC = 1,
SHD_SUBSURFACE_GAUSSIAN = 2,
#endif
- SHD_SUBSURFACE_DIFFUSION = 3,
+ SHD_SUBSURFACE_BURLEY = 3,
SHD_SUBSURFACE_RANDOM_WALK_FIXED_RADIUS = 4,
SHD_SUBSURFACE_RANDOM_WALK = 5,
};
@@ -1873,25 +2003,29 @@ enum {
/* viewer and composite output. */
#define CMP_NODE_OUTPUT_IGNORE_ALPHA 1
-/* Plane track deform node */
+/* Plane track deform node. */
+
enum {
CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR = 1,
};
-/* Stabilization node */
+/* Stabilization node. */
+
enum {
CMP_NODEFLAG_STABILIZE_INVERSE = 1,
};
/* Set Alpha Node. */
-/* `NodeSetAlpha.mode` */
+
+/** #NodeSetAlpha.mode */
typedef enum CMPNodeSetAlphaMode {
CMP_NODE_SETALPHA_MODE_APPLY = 0,
CMP_NODE_SETALPHA_MODE_REPLACE_ALPHA = 1,
} CMPNodeSetAlphaMode;
/* Denoise Node. */
-/* `NodeDenoise.prefilter` */
+
+/** #NodeDenoise.prefilter */
typedef enum CMPNodeDenoisePrefilter {
CMP_NODE_DENOISE_PREFILTER_FAST = 0,
CMP_NODE_DENOISE_PREFILTER_NONE = 1,
@@ -1985,6 +2119,7 @@ typedef enum GeometryNodeTriangulateQuads {
GEO_NODE_TRIANGULATE_QUAD_FIXED = 1,
GEO_NODE_TRIANGULATE_QUAD_ALTERNATE = 2,
GEO_NODE_TRIANGULATE_QUAD_SHORTEDGE = 3,
+ GEO_NODE_TRIANGULATE_QUAD_LONGEDGE = 4,
} GeometryNodeTriangulateQuads;
typedef enum GeometryNodePointInstanceType {
@@ -2016,11 +2151,22 @@ typedef enum GeometryNodeDistributePointsOnFacesMode {
GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON = 1,
} GeometryNodeDistributePointsOnFacesMode;
+typedef enum GeometryNodeExtrudeMeshMode {
+ GEO_NODE_EXTRUDE_MESH_VERTICES = 0,
+ GEO_NODE_EXTRUDE_MESH_EDGES = 1,
+ GEO_NODE_EXTRUDE_MESH_FACES = 2,
+} GeometryNodeExtrudeMeshMode;
+
typedef enum GeometryNodeRotatePointsType {
GEO_NODE_POINT_ROTATE_TYPE_EULER = 0,
GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE = 1,
} GeometryNodeRotatePointsType;
+typedef enum FunctionNodeRotatePointsType {
+ FN_NODE_ROTATE_EULER_TYPE_EULER = 0,
+ FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE = 1,
+} FunctionNodeRotatePointsType;
+
typedef enum GeometryNodeAttributeVectorRotateMode {
GEO_NODE_VECTOR_ROTATE_TYPE_AXIS = 0,
GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_X = 1,
@@ -2041,6 +2187,11 @@ typedef enum GeometryNodeRotatePointsSpace {
GEO_NODE_POINT_ROTATE_SPACE_POINT = 1,
} GeometryNodeRotatePointsSpace;
+typedef enum FunctionNodeRotateEulerSpace {
+ FN_NODE_ROTATE_EULER_SPACE_OBJECT = 0,
+ FN_NODE_ROTATE_EULER_SPACE_LOCAL = 1,
+} FunctionNodeRotateEulerSpace;
+
typedef enum GeometryNodeAlignRotationToVectorAxis {
GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_X = 0,
GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_Y = 1,
@@ -2054,6 +2205,19 @@ typedef enum GeometryNodeAlignRotationToVectorPivotAxis {
GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_Z = 3,
} GeometryNodeAlignRotationToVectorPivotAxis;
+typedef enum NodeAlignEulerToVectorAxis {
+ FN_NODE_ALIGN_EULER_TO_VECTOR_AXIS_X = 0,
+ FN_NODE_ALIGN_EULER_TO_VECTOR_AXIS_Y = 1,
+ FN_NODE_ALIGN_EULER_TO_VECTOR_AXIS_Z = 2,
+} NodeAlignEulerToVectorAxis;
+
+typedef enum NodeAlignEulerToVectorPivotAxis {
+ FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_AUTO = 0,
+ FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_X = 1,
+ FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_Y = 2,
+ FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_Z = 3,
+} NodeAlignEulerToVectorPivotAxis;
+
typedef enum GeometryNodeTransformSpace {
GEO_NODE_TRANSFORM_SPACE_ORIGINAL = 0,
GEO_NODE_TRANSFORM_SPACE_RELATIVE = 1,
@@ -2080,6 +2244,11 @@ typedef enum GeometryNodeMeshLineCountMode {
GEO_NODE_MESH_LINE_COUNT_RESOLUTION = 1,
} GeometryNodeMeshLineCountMode;
+typedef enum GeometryNodeCurvePrimitiveArcMode {
+ GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS = 0,
+ GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS = 1,
+} GeometryNodeCurvePrimitiveArcMode;
+
typedef enum GeometryNodeCurvePrimitiveLineMode {
GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS = 0,
GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION = 1
@@ -2115,9 +2284,15 @@ typedef enum GeometryNodeCurveFilletMode {
} GeometryNodeCurveFilletMode;
typedef enum GeometryNodeAttributeTransferMapMode {
+ GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED = 0,
+ GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER_NEAREST = 1,
+} GeometryNodeAttributeTransferMapMode;
+
+typedef enum GeometryNodeAttributeTransferMode {
GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED = 0,
GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST = 1,
-} GeometryNodeAttributeTransferMapMode;
+ GEO_NODE_ATTRIBUTE_TRANSFER_INDEX = 2,
+} GeometryNodeAttributeTransferMode;
typedef enum GeometryNodeRaycastMapMode {
GEO_NODE_RAYCAST_INTERPOLATED = 0,
@@ -2158,6 +2333,21 @@ typedef enum GeometryNodeStringToCurvesAlignYMode {
GEO_NODE_STRING_TO_CURVES_ALIGN_Y_BOTTOM = 4,
} GeometryNodeStringToCurvesAlignYMode;
+typedef enum GeometryNodeDeleteGeometryMode {
+ GEO_NODE_DELETE_GEOMETRY_MODE_ALL = 0,
+ GEO_NODE_DELETE_GEOMETRY_MODE_EDGE_FACE = 1,
+ GEO_NODE_DELETE_GEOMETRY_MODE_ONLY_FACE = 2,
+} GeometryNodeDeleteGeometryMode;
+
+typedef enum GeometryNodeRealizeInstancesFlag {
+ GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR = (1 << 0),
+} GeometryNodeRealizeInstancesFlag;
+
+typedef enum GeometryNodeScaleElementsMode {
+ GEO_NODE_SCALE_ELEMENTS_UNIFORM = 0,
+ GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS = 1,
+} GeometryNodeScaleElementsMode;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_object_force_types.h b/source/blender/makesdna/DNA_object_force_types.h
index fcaac4ded76..7d0d4c0d460 100644
--- a/source/blender/makesdna/DNA_object_force_types.h
+++ b/source/blender/makesdna/DNA_object_force_types.h
@@ -30,7 +30,9 @@
extern "C" {
#endif
-/* pd->forcefield: Effector Fields types */
+struct BodySpring;
+
+/** #PartDeflect.forcefield: Effector Fields types. */
typedef enum ePFieldType {
/** (this is used for general effector weight). */
PFIELD_NULL = 0,
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 5a88ce7c9f5..602f968634e 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -57,7 +57,7 @@ struct SculptSession;
struct SoftBody;
struct bGPdata;
-/* Vertex Groups - Name Info */
+/** Vertex Groups - Name Info */
typedef struct bDeformGroup {
struct bDeformGroup *next, *prev;
/** MAX_VGROUP_NAME. */
@@ -66,7 +66,7 @@ typedef struct bDeformGroup {
char flag, _pad0[7];
} bDeformGroup;
-/* Face Maps. */
+/** Face Maps. */
typedef struct bFaceMap {
struct bFaceMap *next, *prev;
/** MAX_VGROUP_NAME. */
@@ -107,7 +107,7 @@ typedef struct BoundBox {
char _pad0[4];
} BoundBox;
-/* boundbox flag */
+/** #BoundBox.flag */
enum {
BOUNDBOX_DISABLED = (1 << 0),
BOUNDBOX_DIRTY = (1 << 1),
@@ -115,7 +115,7 @@ enum {
struct CustomData_MeshMasks;
-/* Not saved in file! */
+/** Not saved in file! */
typedef struct Object_Runtime {
/**
* The custom data layer mask that was last used
@@ -126,7 +126,12 @@ typedef struct Object_Runtime {
/** Did last modifier stack generation need mapping support? */
char last_need_mapping;
- char _pad0[3];
+ /** Opaque data reserved for management of objects in collection context.
+ * E.g. used currently to check for potential duplicates of objects in a collection, after
+ * remapping process. */
+ char collection_management;
+
+ char _pad0[2];
/** Only used for drawing the parent/child help-line. */
float parent_display_origin[3];
@@ -147,7 +152,7 @@ typedef struct Object_Runtime {
/** Start time of the mode transfer overlay animation. */
double overlay_mode_transfer_start_time;
- /** Axis aligned boundbox (in localspace). */
+ /** Axis aligned bound-box (in local-space). */
struct BoundBox *bb;
/**
@@ -176,6 +181,12 @@ typedef struct Object_Runtime {
*/
struct Mesh *mesh_deform_eval;
+ /* Evaluated mesh cage in edit mode. */
+ struct Mesh *editmesh_eval_cage;
+
+ /** Cached cage bounding box of `editmesh_eval_cage` for selection. */
+ struct BoundBox *editmesh_bb_cage;
+
/**
* Original grease pencil bGPdata pointer, before object->data was changed to point
* to gpd_eval.
@@ -205,6 +216,12 @@ typedef struct Object_Runtime {
unsigned short local_collections_bits;
short _pad2[3];
+
+ float (*crazyspace_deform_imats)[3][3];
+ float (*crazyspace_deform_cos)[3];
+ int crazyspace_num_verts;
+
+ int _pad3[3];
} Object_Runtime;
typedef struct ObjectLineArt {
@@ -246,7 +263,7 @@ typedef struct Object {
/** String describing subobject info, MAX_ID_NAME-2. */
char parsubstr[64];
struct Object *parent, *track;
- /* if ob->proxy (or proxy_group), this object is proxy for object ob->proxy */
+ /* If `ob->proxy` (or proxy_group), this object is proxy for object `ob->proxy`. */
/* proxy_from is set in target back to the proxy. */
struct Object *proxy, *proxy_group, *proxy_from;
/** Old animation system, deprecated for 2.5. */
@@ -311,7 +328,7 @@ typedef struct Object {
float rotAxis[3], drotAxis[3];
/** Axis angle rotation - angle part. */
float rotAngle, drotAngle;
- /** Final worldspace matrix with constraints & animsys applied. */
+ /** Final world-space matrix with constraints & animsys applied. */
float obmat[4][4];
/** Inverse result of parent, so that object doesn't 'stick' to parent. */
float parentinv[4][4];
@@ -322,8 +339,7 @@ typedef struct Object {
* Inverse matrix of 'obmat' for any other use than rendering!
*
* \note this isn't assured to be valid as with 'obmat',
- * before using this value you should do...
- * invert_m4_m4(ob->imat, ob->obmat);
+ * before using this value you should do: `invert_m4_m4(ob->imat, ob->obmat)`
*/
float imat[4][4];
@@ -436,7 +452,7 @@ typedef struct Object {
Object_Runtime runtime;
} Object;
-/* Warning, this is not used anymore because hooks are now modifiers */
+/** DEPRECATED: this is not used anymore because hooks are now modifiers. */
typedef struct ObHook {
struct ObHook *next, *prev;
@@ -466,7 +482,7 @@ typedef struct ObHook {
/* used many places, should be specialized. */
#define SELECT 1
-/* type */
+/** #Object.type */
enum {
OB_EMPTY = 0,
OB_MESH = 1,
@@ -501,6 +517,9 @@ enum {
/* check if the object type supports materials */
#define OB_TYPE_SUPPORT_MATERIAL(_type) \
(((_type) >= OB_MESH && (_type) <= OB_MBALL) || ((_type) >= OB_GPENCIL && (_type) <= OB_VOLUME))
+/** Does the object have some render-able geometry (unlike empties, cameras, etc.). */
+#define OB_TYPE_IS_GEOMETRY(_type) \
+ (ELEM(_type, OB_MESH, OB_SURF, OB_FONT, OB_MBALL, OB_GPENCIL, OB_HAIR, OB_POINTCLOUD, OB_VOLUME))
#define OB_TYPE_SUPPORT_VGROUP(_type) (ELEM(_type, OB_MESH, OB_LATTICE, OB_GPENCIL))
#define OB_TYPE_SUPPORT_EDITMODE(_type) \
(ELEM(_type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE))
@@ -541,7 +560,7 @@ enum {
case ID_PT: \
case ID_VO
-/* partype: first 4 bits: type */
+/** #Object.partype: first 4 bits: type. */
enum {
PARTYPE = (1 << 4) - 1,
PAROBJECT = 0,
@@ -552,7 +571,7 @@ enum {
};
-/* (short) transflag */
+/** #Object.transflag (short) */
enum {
OB_TRANSFORM_ADJUST_ROOT_PARENT_FOR_VIEW_LOCK = 1 << 0,
OB_TRANSFLAG_UNUSED_1 = 1 << 1, /* cleared */
@@ -574,7 +593,7 @@ enum {
OB_DUPLI = OB_DUPLIVERTS | OB_DUPLICOLLECTION | OB_DUPLIFACES | OB_DUPLIPARTS,
};
-/* (short) trackflag / upflag */
+/** #Object.trackflag / #Object.upflag (short) */
enum {
OB_POSX = 0,
OB_POSY = 1,
@@ -584,7 +603,7 @@ enum {
OB_NEGZ = 5,
};
-/* dtx: flags (short) */
+/** #Object.dtx draw type extra flags (short) */
enum {
OB_DRAWBOUNDOX = 1 << 0,
OB_AXIS = 1 << 1,
@@ -603,7 +622,7 @@ enum {
OB_USE_GPENCIL_LIGHTS = 1 << 10,
};
-/* empty_drawtype: no flags */
+/** #Object.empty_drawtype: no flags */
enum {
OB_ARROWS = 1,
OB_PLAINAXES = 2,
@@ -615,7 +634,10 @@ enum {
OB_EMPTY_IMAGE = 8,
};
-/* gpencil add types */
+/**
+ * Grease-pencil add types.
+ * TODO: doesn't need to be DNA, local to `OBJECT_OT_gpencil_add`.
+ */
enum {
GP_EMPTY = 0,
GP_STROKE = 1,
@@ -625,7 +647,7 @@ enum {
GP_LRT_COLLECTION = 5,
};
-/* boundtype */
+/** #Object.boundtype */
enum {
OB_BOUND_BOX = 0,
OB_BOUND_SPHERE = 1,
@@ -639,7 +661,7 @@ enum {
/* **************** BASE ********************* */
-/* base->flag_legacy */
+/** #Base.flag_legacy */
enum {
BA_WAS_SEL = (1 << 1),
/* NOTE: BA_HAS_RECALC_DATA can be re-used later if freed in readfile.c. */
@@ -668,7 +690,7 @@ enum {
# define OB_FLAG_UNUSED_12 (1 << 12) /* cleared */
#endif
-/* ob->visibility_flag */
+/** #Object.visibility_flag */
enum {
OB_HIDE_VIEWPORT = 1 << 0,
OB_HIDE_SELECT = 1 << 1,
@@ -683,7 +705,7 @@ enum {
OB_SHADOW_CATCHER = 1 << 10
};
-/* ob->shapeflag */
+/** #Object.shapeflag */
enum {
OB_SHAPE_LOCK = 1 << 0,
#ifdef DNA_DEPRECATED_ALLOW
@@ -692,7 +714,7 @@ enum {
OB_SHAPE_EDIT_MODE = 1 << 2,
};
-/* ob->nlaflag */
+/** #Object.nlaflag */
enum {
OB_ADS_UNUSED_1 = 1 << 0, /* cleared */
OB_ADS_UNUSED_2 = 1 << 1, /* cleared */
@@ -708,7 +730,7 @@ enum {
/* OB_ADS_SHOWPARTS = 1 << 14, */ /* UNUSED */
};
-/* ob->protectflag */
+/** #Object.protectflag */
enum {
OB_LOCK_LOCX = 1 << 0,
OB_LOCK_LOCY = 1 << 1,
@@ -726,13 +748,13 @@ enum {
OB_LOCK_ROT4D = 1 << 10,
};
-/* ob->duplicator_visibility_flag */
+/** #Object.duplicator_visibility_flag */
enum {
OB_DUPLI_FLAG_VIEWPORT = 1 << 0,
OB_DUPLI_FLAG_RENDER = 1 << 1,
};
-/* ob->empty_image_depth */
+/** #Object.empty_image_depth */
#define OB_EMPTY_IMAGE_DEPTH_DEFAULT 0
#define OB_EMPTY_IMAGE_DEPTH_FRONT 1
#define OB_EMPTY_IMAGE_DEPTH_BACK 2
diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h
index ebf3d4a248c..a50d0524998 100644
--- a/source/blender/makesdna/DNA_outliner_types.h
+++ b/source/blender/makesdna/DNA_outliner_types.h
@@ -41,13 +41,13 @@ typedef struct TreeStoreElem {
/** Used only to store data in blend files. */
typedef struct TreeStore {
- /** Was previously used for memory preallocation. */
+ /** Was previously used for memory pre-allocation. */
int totelem DNA_DEPRECATED;
/** Number of elements in data array. */
int usedelem;
/**
- * Elements to be packed from mempool in writefile.c
- * or extracted to mempool in readfile.c
+ * Elements to be packed from mempool in `writefile.c`
+ * or extracted to mempool in `readfile.c`.
*/
TreeStoreElem *data;
} TreeStore;
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index a51c532dfb3..5add664f624 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -72,7 +72,7 @@ typedef struct ParticleSpring {
unsigned int particle_index[2], delete_flag;
} ParticleSpring;
-/* Child particles are created around or between parent particles */
+/** Child particles are created around or between parent particles. */
typedef struct ChildParticle {
/** Face index on the final derived mesh. */
int num;
@@ -364,8 +364,7 @@ typedef struct ParticleSystem {
int flag, totpart, totunexist, totchild, totcached, totchildcache;
/* NOTE: Recalc is one of ID_RECALC_PSYS_ALL flags.
*
- * TODO(sergey): Use part->id.recalc instead of this duplicated flag
- * somehow. */
+ * TODO(sergey): Use #ParticleSettings.id.recalc instead of this duplicated flag somehow. */
int recalc;
short target_psys, totkeyed, bakespace;
char _pad1[6];
@@ -438,9 +437,11 @@ typedef enum eParticleDrawFlag {
PART_DRAW_HAIR_GRID = (1 << 18),
} eParticleDrawFlag;
-/* part->type
+/**
+ * #ParticleSettings.type
* Hair is always baked static in object/geometry space.
- * Other types (normal particles) are in global space and not static baked. */
+ * Other types (normal particles) are in global space and not static baked.
+ */
enum {
PART_EMITTER = 0,
/* REACTOR type currently unused */
@@ -458,7 +459,7 @@ enum {
PART_FLUID_SPRAYFOAMBUBBLE = 12,
};
-/* Mirroring Mantaflow particle types from particle.h (Mantaflow header). */
+/** Mirroring Mantaflow particle types from particle.h (Mantaflow header). */
enum {
/* PARTICLE_TYPE_NONE = (0 << 0), */ /* UNUSED */
/* PARTICLE_TYPE_NEW = (1 << 0), */ /* UNUSED */
@@ -470,7 +471,7 @@ enum {
/* PARTICLE_TYPE_INVALID = (1 << 30), */ /* UNUSED */
};
-/* part->flag */
+/** #ParticleSettings.flag */
#define PART_REACT_STA_END 1
#define PART_REACT_MULTIPLE 2
@@ -514,26 +515,26 @@ enum {
#define PART_SELF_EFFECT (1 << 22)
-/* part->from */
+/** #ParticleSettings.from */
#define PART_FROM_VERT 0
#define PART_FROM_FACE 1
#define PART_FROM_VOLUME 2
/* #define PART_FROM_PARTICLE 3 deprecated! */
#define PART_FROM_CHILD 4
-/* part->distr */
+/** #ParticleSettings.distr */
#define PART_DISTR_JIT 0
#define PART_DISTR_RAND 1
#define PART_DISTR_GRID 2
-/* part->phystype */
+/** #ParticleSettings.phystype */
#define PART_PHYS_NO 0
#define PART_PHYS_NEWTON 1
#define PART_PHYS_KEYED 2
#define PART_PHYS_BOIDS 3
#define PART_PHYS_FLUID 4
-/* part->kink */
+/** #ParticleSettings.kink */
typedef enum eParticleKink {
PART_KINK_NO = 0,
PART_KINK_CURL = 1,
@@ -543,7 +544,7 @@ typedef enum eParticleKink {
PART_KINK_SPIRAL = 5,
} eParticleKink;
-/* part->child_flag */
+/** #ParticleSettings.child_flag */
typedef enum eParticleChildFlag {
PART_CHILD_USE_CLUMP_NOISE = (1 << 0),
PART_CHILD_USE_CLUMP_CURVE = (1 << 1),
@@ -551,22 +552,22 @@ typedef enum eParticleChildFlag {
PART_CHILD_USE_TWIST_CURVE = (1 << 3),
} eParticleChildFlag;
-/* part->shape_flag */
+/** #ParticleSettings.shape_flag */
typedef enum eParticleShapeFlag {
PART_SHAPE_CLOSE_TIP = (1 << 0),
} eParticleShapeFlag;
-/* part->draw_col */
+/* #ParticleSettings.draw_col */
#define PART_DRAW_COL_NONE 0
#define PART_DRAW_COL_MAT 1
#define PART_DRAW_COL_VEL 2
#define PART_DRAW_COL_ACC 3
-/* part->time_flag */
+/* #ParticleSettings.time_flag */
#define PART_TIME_AUTOSF 1 /* Automatic subframes */
-/* part->draw_as */
-/* part->ren_as */
+/* #ParticleSettings.draw_as */
+/* #ParticleSettings.ren_as */
#define PART_DRAW_NOT 0
#define PART_DRAW_DOT 1
#define PART_DRAW_HALO 1
@@ -580,13 +581,13 @@ typedef enum eParticleShapeFlag {
#define PART_DRAW_BB 9 /* deprecated */
#define PART_DRAW_REND 10
-/* part->integrator */
+/* #ParticleSettings.integrator */
#define PART_INT_EULER 0
#define PART_INT_MIDPOINT 1
#define PART_INT_RK4 2
#define PART_INT_VERLET 3
-/* part->rotmode */
+/* #ParticleSettings.rotmode */
#define PART_ROT_NOR 1
#define PART_ROT_VEL 2
#define PART_ROT_GLOB_X 3
@@ -597,7 +598,7 @@ typedef enum eParticleShapeFlag {
#define PART_ROT_OB_Z 8
#define PART_ROT_NOR_TAN 9
-/* part->avemode */
+/* #ParticleSettings.avemode */
#define PART_AVE_VELOCITY 1
#define PART_AVE_RAND 2
#define PART_AVE_HORIZONTAL 3
@@ -606,12 +607,12 @@ typedef enum eParticleShapeFlag {
#define PART_AVE_GLOBAL_Y 6
#define PART_AVE_GLOBAL_Z 7
-/* part->reactevent */
+/* #ParticleSettings.reactevent */
#define PART_EVENT_DEATH 0
#define PART_EVENT_COLLIDE 1
#define PART_EVENT_NEAR 2
-/* part->childtype */
+/* #ParticleSettings.childtype */
#define PART_CHILD_PARTICLES 1
#define PART_CHILD_FACES 2
@@ -675,7 +676,7 @@ typedef enum eParticleShapeFlag {
#define PTARGET_MODE_FRIEND 1
#define PTARGET_MODE_ENEMY 2
-/* mapto */
+/** #MTex.mapto */
typedef enum eParticleTextureInfluence {
/* init */
PAMAP_TIME = (1 << 0), /* emission time */
diff --git a/source/blender/makesdna/DNA_pointcache_types.h b/source/blender/makesdna/DNA_pointcache_types.h
index 7de0bb29c46..2b6e1c4f7de 100644
--- a/source/blender/makesdna/DNA_pointcache_types.h
+++ b/source/blender/makesdna/DNA_pointcache_types.h
@@ -131,8 +131,8 @@ typedef struct PointCache {
void (*free_edit)(struct PTCacheEdit *edit);
} PointCache;
+/** #PointCache.flag */
enum {
- /* pointcache->flag */
PTCACHE_BAKED = 1 << 0,
PTCACHE_OUTDATED = 1 << 1,
PTCACHE_SIMULATION_VALID = 1 << 2,
diff --git a/source/blender/makesdna/DNA_pointcloud_types.h b/source/blender/makesdna/DNA_pointcloud_types.h
index 26f1db3324b..53fda29a33a 100644
--- a/source/blender/makesdna/DNA_pointcloud_types.h
+++ b/source/blender/makesdna/DNA_pointcloud_types.h
@@ -54,7 +54,7 @@ typedef struct PointCloud {
void *batch_cache;
} PointCloud;
-/* PointCloud.flag */
+/** #PointCloud.flag */
enum {
PT_DS_EXPAND = (1 << 0),
};
diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h
index aa11e74e89d..f653905e169 100644
--- a/source/blender/makesdna/DNA_rigidbody_types.h
+++ b/source/blender/makesdna/DNA_rigidbody_types.h
@@ -38,7 +38,7 @@ struct EffectorWeights;
/* ******************************** */
/* RigidBody World */
-/* Container for data shared by original and evaluated copies of RigidBodyWorld */
+/** Container for data shared by original and evaluated copies of #RigidBodyWorld. */
typedef struct RigidBodyWorld_Shared {
/* cache */
struct PointCache *pointcache;
@@ -90,7 +90,7 @@ typedef struct RigidBodyWorld {
float time_scale;
} RigidBodyWorld;
-/* Flags for RigidBodyWorld */
+/** RigidBodyWorld.flag */
typedef enum eRigidBodyWorld_Flag {
/* should sim world be skipped when evaluating (user setting) */
RBW_FLAG_MUTED = (1 << 0),
@@ -170,7 +170,7 @@ typedef struct RigidBodyOb {
struct RigidBodyOb_Shared *shared;
} RigidBodyOb;
-/* Participation types for RigidBodyOb */
+/** #RigidBodyOb.type */
typedef enum eRigidBodyOb_Type {
/* active geometry participant in simulation. is directly controlled by sim */
RBO_TYPE_ACTIVE = 0,
@@ -178,7 +178,7 @@ typedef enum eRigidBodyOb_Type {
RBO_TYPE_PASSIVE = 1,
} eRigidBodyOb_Type;
-/* Flags for RigidBodyOb */
+/** #RigidBodyOb.flag */
typedef enum eRigidBodyOb_Flag {
/* rigidbody is kinematic (controlled by the animation system) */
RBO_FLAG_KINEMATIC = (1 << 0),
@@ -198,7 +198,7 @@ typedef enum eRigidBodyOb_Flag {
RBO_FLAG_USE_DEFORM = (1 << 7),
} eRigidBodyOb_Flag;
-/* RigidBody Collision Shape */
+/** Rigid Body Collision Shape. */
typedef enum eRigidBody_Shape {
/** Simple box (i.e. bounding box). */
RB_SHAPE_BOX = 0,
@@ -304,7 +304,7 @@ typedef struct RigidBodyCon {
void *physics_constraint;
} RigidBodyCon;
-/* Participation types for RigidBodyOb */
+/** Participation types for #RigidBodyOb.type */
typedef enum eRigidBodyCon_Type {
/** lets bodies rotate around a specified point */
RBC_TYPE_POINT = 0,
@@ -333,13 +333,13 @@ typedef enum eRigidBodyCon_Type {
RBC_TYPE_MOTOR = 11,
} eRigidBodyCon_Type;
-/* Spring implementation type for RigidBodyOb */
+/** Spring implementation type for RigidBodyOb. */
typedef enum eRigidBodyCon_SpringType {
RBC_SPRING_TYPE1 = 0, /* btGeneric6DofSpringConstraint */
RBC_SPRING_TYPE2 = 1, /* btGeneric6DofSpring2Constraint */
} eRigidBodyCon_SpringType;
-/* Flags for RigidBodyCon */
+/** #RigidBodyCon.flag */
typedef enum eRigidBodyCon_Flag {
/* constraint influences rigid body motion */
RBC_FLAG_ENABLED = (1 << 0),
diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h
index 9ffadfe40a9..502abfbdf1d 100644
--- a/source/blender/makesdna/DNA_scene_defaults.h
+++ b/source/blender/makesdna/DNA_scene_defaults.h
@@ -47,6 +47,7 @@
.width = 512, \
.height = 512, \
.margin = 16, \
+ .margin_type = R_BAKE_ADJACENT_FACES, \
.normal_space = R_BAKE_SPACE_TANGENT, \
.normal_swizzle = {R_BAKE_POSX, R_BAKE_POSY, R_BAKE_POSZ}, \
}
@@ -102,7 +103,8 @@
.dither_intensity = 1.0f, \
\
.bake_mode = 0, \
- .bake_filter = 16, \
+ .bake_margin = 16, \
+ .bake_margin_type = R_BAKE_ADJACENT_FACES, \
.bake_flag = R_BAKE_CLEAR, \
.bake_samples = 256, \
.bake_biasdist = 0.001f, \
@@ -376,3 +378,5 @@
}
/* clang-format off */
+
+/** \} */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index f3926e46ebc..36fef503efc 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -34,7 +34,7 @@
#include "DNA_ID.h"
#include "DNA_color_types.h" /* color management */
-#include "DNA_customdata_types.h" /* Scene's runtime cddata masks. */
+#include "DNA_customdata_types.h" /* Scene's runtime custom-data masks. */
#include "DNA_layer_types.h"
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
@@ -195,7 +195,7 @@ typedef struct AudioData {
/* *************************************************************** */
/* Render Layers */
-/* Render Layer */
+/** Render Layer. */
typedef struct SceneRenderLayer {
struct SceneRenderLayer *next, *prev;
@@ -323,7 +323,7 @@ typedef enum eScenePassType {
#define RE_PASSNAME_BLOOM "BloomCol"
#define RE_PASSNAME_VOLUME_LIGHT "VolumeDir"
-/* View - MultiView */
+/** View - MultiView. */
typedef struct SceneRenderView {
struct SceneRenderView *next, *prev;
@@ -563,11 +563,18 @@ typedef struct BakeData {
char target;
char save_mode;
- char _pad[6];
+ char margin_type;
+ char _pad[5];
struct Object *cage_object;
} BakeData;
+/** #BakeData.margin_type (char) */
+typedef enum eBakeMarginType {
+ R_BAKE_ADJACENT_FACES = 0,
+ R_BAKE_EXTEND = 1,
+} eBakeMarginType;
+
/** #BakeData.normal_swizzle (char) */
typedef enum eBakeNormalSwizzle {
R_BAKE_POSX = 0,
@@ -715,11 +722,14 @@ typedef struct RenderData {
/* Bake Render options */
short bake_mode, bake_flag;
- short bake_filter, bake_samples;
+ short bake_margin, bake_samples;
+ short bake_margin_type;
+ char _pad9[6];
float bake_biasdist, bake_user_scale;
/* path to render output */
/** 1024 = FILE_MAX. */
+ /* NOTE: Excluded from `BKE_bpath_foreach_path_` / `scene_foreach_path` code. */
char pic[1024];
/* stamps flags. */
@@ -784,12 +794,12 @@ typedef struct RenderData {
struct CurveMapping mblur_shutter_curve;
} RenderData;
-/* RenderData.quality_flag */
+/** #RenderData.quality_flag */
typedef enum eQualityOption {
SCE_PERF_HQ_NORMALS = (1 << 0),
} eQualityOption;
-/* RenderData.hair_type */
+/** #RenderData.hair_type */
typedef enum eHairType {
SCE_HAIR_SHAPE_STRAND = 0,
SCE_HAIR_SHAPE_STRIP = 1,
@@ -798,7 +808,7 @@ typedef enum eHairType {
/* *************************************************************** */
/* Render Conversion/Simplification Settings */
-/* control render convert and shading engine */
+/** Control render convert and shading engine. */
typedef struct RenderProfile {
struct RenderProfile *next, *prev;
char name[32];
@@ -828,7 +838,7 @@ typedef struct RenderProfile {
#define STEREO_RIGHT_SUFFIX "_R"
#define STEREO_LEFT_SUFFIX "_L"
-/* View3D.stereo3d_camera / View3D.multiview_eye / ImageUser.multiview_eye */
+/** #View3D.stereo3d_camera / #View3D.multiview_eye / #ImageUser.multiview_eye */
typedef enum eStereoViews {
STEREO_LEFT_ID = 0,
STEREO_RIGHT_ID = 1,
@@ -860,12 +870,12 @@ typedef struct Paint_Runtime {
char _pad[2];
} Paint_Runtime;
-/* We might want to store other things here. */
+/** We might want to store other things here. */
typedef struct PaintToolSlot {
struct Brush *brush;
} PaintToolSlot;
-/* Paint Tool Base */
+/** Paint Tool Base. */
typedef struct Paint {
struct Brush *brush;
@@ -902,7 +912,7 @@ typedef struct Paint {
/* ------------------------------------------- */
/* Image Paint */
-/* Texture/Image Editor */
+/** Texture/Image Editor. */
typedef struct ImagePaintSettings {
Paint paint;
@@ -933,7 +943,7 @@ typedef struct ImagePaintSettings {
/* ------------------------------------------- */
/* Particle Edit */
-/* Settings for a Particle Editing Brush */
+/** Settings for a Particle Editing Brush. */
typedef struct ParticleBrushData {
/** Common setting. */
short size;
@@ -943,7 +953,7 @@ typedef struct ParticleBrushData {
float strength;
} ParticleBrushData;
-/* Particle Edit Mode Settings */
+/** Particle Edit Mode Settings. */
typedef struct ParticleEditSettings {
short flag;
short totrekey;
@@ -970,7 +980,7 @@ typedef struct ParticleEditSettings {
/* ------------------------------------------- */
/* Sculpt */
-/* Sculpt */
+/** Sculpt. */
typedef struct Sculpt {
Paint paint;
@@ -1005,7 +1015,7 @@ typedef struct UvSculpt {
Paint paint;
} UvSculpt;
-/* grease pencil drawing brushes */
+/** Grease pencil drawing brushes. */
typedef struct GpPaint {
Paint paint;
int flag;
@@ -1019,21 +1029,21 @@ enum {
GPPAINT_FLAG_USE_VERTEXCOLOR = 1,
};
-/* Grease pencil vertex paint. */
+/** Grease pencil vertex paint. */
typedef struct GpVertexPaint {
Paint paint;
int flag;
char _pad[4];
} GpVertexPaint;
-/* Grease pencil sculpt paint. */
+/** Grease pencil sculpt paint. */
typedef struct GpSculptPaint {
Paint paint;
int flag;
char _pad[4];
} GpSculptPaint;
-/* Grease pencil weight paint. */
+/** Grease pencil weight paint. */
typedef struct GpWeightPaint {
Paint paint;
int flag;
@@ -1043,7 +1053,7 @@ typedef struct GpWeightPaint {
/* ------------------------------------------- */
/* Vertex Paint */
-/* Vertex Paint */
+/** Vertex Paint. */
typedef struct VPaint {
Paint paint;
char flag;
@@ -1061,7 +1071,7 @@ enum {
/* ------------------------------------------- */
/* GPencil Stroke Sculpting */
-/* GP_Sculpt_Settings.lock_axis */
+/** #GP_Sculpt_Settings.lock_axis */
typedef enum eGP_Lockaxis_Types {
GP_LOCKAXIS_VIEW = 0,
GP_LOCKAXIS_X = 1,
@@ -1070,7 +1080,7 @@ typedef enum eGP_Lockaxis_Types {
GP_LOCKAXIS_CURSOR = 4,
} eGP_Lockaxis_Types;
-/* Settings for a GPencil Speed Guide */
+/** Settings for a GPencil Speed Guide. */
typedef struct GP_Sculpt_Guide {
char use_guide;
char use_snapping;
@@ -1084,7 +1094,7 @@ typedef struct GP_Sculpt_Guide {
struct Object *reference_object;
} GP_Sculpt_Guide;
-/* GPencil Stroke Sculpting Settings */
+/** GPencil Stroke Sculpting Settings. */
typedef struct GP_Sculpt_Settings {
/** Runtime. */
void *paintcursor;
@@ -1133,7 +1143,7 @@ typedef enum eGP_vertex_SelectMaskFlag {
GP_VERTEX_MASK_SELECTMODE_SEGMENT = (1 << 2),
} eGP_Vertex_SelectMaskFlag;
-/* Settings for GP Interpolation Operators */
+/** Settings for GP Interpolation Operators. */
typedef struct GP_Interpolate_Settings {
/** Custom interpolation curve (for use with GP_IPO_CURVEMAP). */
struct CurveMapping *custom_ipo;
@@ -1254,7 +1264,7 @@ typedef struct UnifiedPaintSettings {
struct ColorSpace *colorspace;
} UnifiedPaintSettings;
-/* UnifiedPaintSettings.flag */
+/** #UnifiedPaintSettings.flag */
typedef enum {
UNIFIED_PAINT_SIZE = (1 << 0),
UNIFIED_PAINT_ALPHA = (1 << 1),
@@ -1312,7 +1322,7 @@ enum {
/* *************************************************************** */
/* Stats */
-/* Stats for Meshes */
+/** Stats for Meshes. */
typedef struct MeshStatVis {
char type;
char _pad1[2];
@@ -1340,8 +1350,10 @@ typedef struct SequencerToolSettings {
short snap_flag;
/* eSeqOverlapMode */
int overlap_mode;
- /** When there are many snap points, 0-1 range corresponds to resolution from boundbox to all
- * possible snap points. */
+ /**
+ * When there are many snap points,
+ * 0-1 range corresponds to resolution from bound-box to all possible snap points.
+ */
int snap_distance;
int pivot_point;
} SequencerToolSettings;
@@ -1569,8 +1581,8 @@ typedef struct PhysicsSettings {
char _pad0[4];
} PhysicsSettings;
-/* ------------------------------------------- */
-/* Safe Area options used in Camera View & Sequencer
+/**
+ * Safe Area options used in Camera View & Sequencer.
*/
typedef struct DisplaySafeAreas {
/* each value represents the (x,y) margins as a multiplier.
@@ -1586,8 +1598,9 @@ typedef struct DisplaySafeAreas {
float action_center[2];
} DisplaySafeAreas;
-/* ------------------------------------------- */
-/* Scene Display - used for store scene specific display settings for the 3d view */
+/**
+ * Scene Display - used for store scene specific display settings for the 3d view.
+ */
typedef struct SceneDisplay {
/** Light direction for shadows/highlight. */
float light_direction[3];
@@ -2066,6 +2079,9 @@ enum {
#define SCE_SNAP_MODE_VOLUME (1 << 3)
#define SCE_SNAP_MODE_EDGE_MIDPOINT (1 << 4)
#define SCE_SNAP_MODE_EDGE_PERPENDICULAR (1 << 5)
+#define SCE_SNAP_MODE_GEOM \
+ (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | \
+ SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT)
/** #SequencerToolSettings.snap_mode */
#define SEQ_SNAP_TO_STRIPS (1 << 0)
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index d5b7458ae7b..1a1d7cba7af 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -154,6 +154,9 @@ typedef struct Panel_Runtime {
/* Pointer to the panel's block. Useful when changes to panel #uiBlocks
* need some context from traversal of the panel "tree". */
struct uiBlock *block;
+
+ /* Non-owning pointer. The context is stored in the block. */
+ struct bContextStore *context;
} Panel_Runtime;
/** The part from uiBlock that needs saved in file. */
@@ -241,7 +244,7 @@ typedef struct PanelCategoryDyn {
rcti rect;
} PanelCategoryDyn;
-/* region stack of active tabs */
+/** Region stack of active tabs. */
typedef struct PanelCategoryStack {
struct PanelCategoryStack *next, *prev;
char idname[64];
@@ -458,6 +461,9 @@ typedef struct ARegion_Runtime {
/* The offset needed to not overlap with window scrollbars. Only used by HUD regions for now. */
int offset_x, offset_y;
+
+ /* Maps uiBlock->name to uiBlock for faster lookups. */
+ struct GHash *block_name_map;
} ARegion_Runtime;
typedef struct ARegion {
@@ -648,9 +654,11 @@ enum {
#define UILST_FLT_SORT_MASK (((unsigned int)(UILST_FLT_SORT_REVERSE | UILST_FLT_SORT_LOCK)) - 1)
-/* regiontype, first two are the default set */
-/* Do NOT change order, append on end. Types are hardcoded needed */
-typedef enum eRegionType {
+/**
+ * regiontype, first two are the default set.
+ * \warning Do NOT change order, append on end. Types are hard-coded needed.
+ */
+typedef enum eRegion_Type {
RGN_TYPE_WINDOW = 0,
RGN_TYPE_HEADER = 1,
RGN_TYPE_CHANNELS = 2,
@@ -666,9 +674,12 @@ typedef enum eRegionType {
RGN_TYPE_EXECUTE = 10,
RGN_TYPE_FOOTER = 11,
RGN_TYPE_TOOL_HEADER = 12,
+ /* Region type used exclusively by internal code and add-ons to register draw callbacks to the XR
+ * context (surface, mirror view). Does not represent any real region. */
+ RGN_TYPE_XR = 13,
-#define RGN_TYPE_LEN (RGN_TYPE_TOOL_HEADER + 1)
-} eRegionType;
+#define RGN_TYPE_LEN (RGN_TYPE_XR + 1)
+} eRegion_Type;
/* use for function args */
#define RGN_TYPE_ANY -1
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 828702f9aa8..5fe67a34dae 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -47,6 +47,10 @@ struct SequenceLookup;
struct VFont;
struct bSound;
+/* -------------------------------------------------------------------- */
+/** \name Sequence & Editing Structs
+ * \{ */
+
/* strlens; 256= FILE_MAXFILE, 768= FILE_MAXDIR */
typedef struct StripAnim {
@@ -79,9 +83,13 @@ typedef struct StripTransform {
} StripTransform;
typedef struct StripColorBalance {
+ int method;
float lift[3];
float gamma[3];
float gain[3];
+ float slope[3];
+ float offset[3];
+ float power[3];
int flag;
char _pad[4];
/* float exposure; */
@@ -175,7 +183,8 @@ typedef struct Sequence {
/** Starting and ending points of the strip in the sequence. */
int startdisp, enddisp;
float sat;
- float mul, handsize;
+ float mul;
+ float _pad;
short anim_preseek; /* UNUSED. */
/** Streamindex for movie or sound files with several streams. */
@@ -233,18 +242,20 @@ typedef struct Sequence {
float blend_opacity;
/* Tag color showed if `SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG` is set. */
- int16_t color_tag;
- char _pad4[6];
+ int8_t color_tag;
+
+ char alpha_mode;
+ char _pad4[2];
+
+ int cache_flag;
/* is sfra needed anymore? - it looks like its only used in one place */
/** Starting frame according to the timeline of the scene. */
int sfra;
- char alpha_mode;
- char _pad[2];
-
/* Multiview */
char views_format;
+ char _pad1[3];
struct Stereo3dFormat *stereo3d_format;
struct IDProperty *prop;
@@ -252,9 +263,6 @@ typedef struct Sequence {
/* modifiers */
ListBase modifiers;
- int cache_flag;
- int _pad2[3];
-
SequenceRuntime runtime;
} Sequence;
@@ -286,9 +294,11 @@ typedef struct Editing {
/** 1024 = FILE_MAX. */
char proxy_dir[1024];
- int over_ofs, over_cfra;
- int over_flag, proxy_storage;
- rctf over_border;
+ int proxy_storage;
+
+ int overlay_frame_ofs, overlay_frame_abs;
+ int overlay_frame_flag;
+ rctf overlay_frame_rect;
struct SeqCache *cache;
@@ -305,7 +315,12 @@ typedef struct Editing {
void *_pad1;
} Editing;
-/* ************* Effect Variable Structs ********* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Effect Variable Structs
+ * \{ */
+
typedef struct WipeVars {
float edgeWidth, angle;
short forward, wipetype;
@@ -354,7 +369,7 @@ typedef struct SpeedControlVars {
float speed_fader_frame_number;
} SpeedControlVars;
-/* SpeedControlVars.speed_control_type */
+/** #SpeedControlVars.speed_control_type */
enum {
SEQ_SPEED_STRETCH = 0,
SEQ_SPEED_MULTIPLY = 1,
@@ -371,7 +386,7 @@ typedef struct TextVars {
char text[512];
struct VFont *text_font;
int text_blf_id;
- int text_size;
+ float text_size;
float color[4], shadow_color[4], box_color[4];
float loc[2];
float wrap_width;
@@ -381,7 +396,7 @@ typedef struct TextVars {
char _pad[5];
} TextVars;
-/* TextVars.flag */
+/** #TextVars.flag */
enum {
SEQ_TEXT_SHADOW = (1 << 0),
SEQ_TEXT_BOX = (1 << 1),
@@ -389,14 +404,14 @@ enum {
SEQ_TEXT_ITALIC = (1 << 3),
};
-/* TextVars.align */
+/** #TextVars.align */
enum {
SEQ_TEXT_ALIGN_X_LEFT = 0,
SEQ_TEXT_ALIGN_X_CENTER = 1,
SEQ_TEXT_ALIGN_X_RIGHT = 2,
};
-/* TextVars.align_y */
+/** #TextVars.align_y */
enum {
SEQ_TEXT_ALIGN_Y_TOP = 0,
SEQ_TEXT_ALIGN_Y_CENTER = 1,
@@ -412,7 +427,11 @@ typedef struct ColorMixVars {
float factor;
} ColorMixVars;
-/* ***************** Sequence modifiers ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sequence Modifiers
+ * \{ */
typedef struct SequenceModifierData {
struct SequenceModifierData *next, *prev;
@@ -435,6 +454,11 @@ typedef struct ColorBalanceModifierData {
float color_multiply;
} ColorBalanceModifierData;
+enum {
+ SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN = 0,
+ SEQ_COLOR_BALANCE_METHOD_SLOPEOFFSETPOWER = 1,
+};
+
typedef struct CurvesModifierData {
SequenceModifierData modifier;
@@ -478,7 +502,11 @@ enum {
SEQ_TONEMAP_RD_PHOTORECEPTOR = 1,
};
-/* ***************** Scopes ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scopes
+ * \{ */
typedef struct SequencerScopes {
struct ImBuf *reference_ibuf;
@@ -494,9 +522,9 @@ typedef struct SequencerScopes {
#define SELECT 1
-/* Editor->over_flag */
-#define SEQ_EDIT_OVERLAY_SHOW 1
-#define SEQ_EDIT_OVERLAY_ABS 2
+/** #Editor.overlay_frame_flag */
+#define SEQ_EDIT_OVERLAY_FRAME_SHOW 1
+#define SEQ_EDIT_OVERLAY_FRAME_ABS 2
#define SEQ_STRIP_OFSBOTTOM 0.05f
#define SEQ_STRIP_OFSTOP 0.95f
@@ -511,10 +539,15 @@ typedef struct SequencerScopes {
#define SEQ_SPEED_UNUSED_3 (1 << 2) /* cleared */
#define SEQ_SPEED_USE_INTERPOLATION (1 << 3)
-/* ***************** SEQUENCE ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flags & Types
+ * \{ */
+
#define SEQ_NAME_MAXSTR 64
-/* seq->flag */
+/** #Sequence.flag */
enum {
/* SELECT */
SEQ_LEFTSEL = (1 << 1),
@@ -557,7 +590,7 @@ enum {
SEQ_INVALID_EFFECT = (1u << 31),
};
-/* StripProxy->storage */
+/** #StripProxy.storage */
enum {
SEQ_STORAGE_PROXY_CUSTOM_FILE = (1 << 1), /* store proxy in custom directory */
SEQ_STORAGE_PROXY_CUSTOM_DIR = (1 << 2), /* store proxy in custom file */
@@ -572,6 +605,9 @@ enum {
#define SEQ_COLOR_BALANCE_INVERSE_GAIN 1
#define SEQ_COLOR_BALANCE_INVERSE_GAMMA 2
#define SEQ_COLOR_BALANCE_INVERSE_LIFT 4
+#define SEQ_COLOR_BALANCE_INVERSE_SLOPE 8
+#define SEQ_COLOR_BALANCE_INVERSE_OFFSET 16
+#define SEQ_COLOR_BALANCE_INVERSE_POWER 32
/* !!! has to be same as IMB_imbuf.h IMB_PROXY_... and IMB_TC_... */
@@ -587,18 +623,22 @@ enum {
#define SEQ_PROXY_TC_RECORD_RUN_NO_GAPS 8
#define SEQ_PROXY_TC_ALL 15
-/* SeqProxy->build_flags */
+/** SeqProxy.build_flags */
enum {
SEQ_PROXY_SKIP_EXISTING = 1,
};
-/* seq->alpha_mode */
+/** #Sequence.alpha_mode */
enum {
SEQ_ALPHA_STRAIGHT = 0,
SEQ_ALPHA_PREMUL = 1,
};
-/* seq->type WATCH IT: SEQ_TYPE_EFFECT BIT is used to determine if this is an effect strip!!! */
+/**
+ * #Sequence.type
+ *
+ * \warning #SEQ_TYPE_EFFECT BIT is used to determine if this is an effect strip!
+ */
enum {
SEQ_TYPE_IMAGE = 0,
SEQ_TYPE_META = 1,
@@ -667,7 +707,7 @@ enum {
/* modifiers */
-/* SequenceModifierData->type */
+/** #SequenceModifierData.type */
enum {
seqModifierType_ColorBalance = 1,
seqModifierType_Curves = 2,
@@ -680,7 +720,7 @@ enum {
NUM_SEQUENCE_MODIFIER_TYPES,
};
-/* SequenceModifierData->flag */
+/** #SequenceModifierData.flag */
enum {
SEQUENCE_MODIFIER_MUTE = (1 << 0),
SEQUENCE_MODIFIER_EXPANDED = (1 << 1),
@@ -698,13 +738,14 @@ enum {
SEQUENCE_MASK_TIME_ABSOLUTE = 1,
};
-/* Sequence->cache_flag
- * SEQ_CACHE_STORE_RAW
- * SEQ_CACHE_STORE_PREPROCESSED
- * SEQ_CACHE_STORE_COMPOSITE
- * FINAL_OUT is ignored
+/**
+ * #Sequence.cache_flag
+ * - #SEQ_CACHE_STORE_RAW
+ * - #SEQ_CACHE_STORE_PREPROCESSED
+ * - #SEQ_CACHE_STORE_COMPOSITE
+ * - #FINAL_OUT is ignored
*
- * Editing->cache_flag
+ * #Editing.cache_flag
* all entries
*/
enum {
@@ -731,7 +772,7 @@ enum {
SEQ_CACHE_STORE_THUMBNAIL = (1 << 12),
};
-/* Sequence->color_tag. */
+/** #Sequence.color_tag. */
typedef enum SequenceColorTag {
SEQUENCE_COLOR_NONE = -1,
SEQUENCE_COLOR_01,
diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h
index 01e3b3a5230..be787c1760f 100644
--- a/source/blender/makesdna/DNA_shader_fx_types.h
+++ b/source/blender/makesdna/DNA_shader_fx_types.h
@@ -77,7 +77,7 @@ typedef struct ShaderFxData {
char *error;
} ShaderFxData;
-/* Runtime temp data */
+/** Runtime temp data. */
typedef struct ShaderFxData_Runtime {
float loc[3];
char _pad[4];
diff --git a/source/blender/makesdna/DNA_simulation_types.h b/source/blender/makesdna/DNA_simulation_types.h
index a700c9fe2f8..b14301ed32d 100644
--- a/source/blender/makesdna/DNA_simulation_types.h
+++ b/source/blender/makesdna/DNA_simulation_types.h
@@ -38,7 +38,7 @@ typedef struct Simulation {
char _pad[4];
} Simulation;
-/* Simulation.flag */
+/** #Simulation.flag */
enum {
SIM_DS_EXPAND = (1 << 0),
};
diff --git a/source/blender/makesdna/DNA_space_defaults.h b/source/blender/makesdna/DNA_space_defaults.h
new file mode 100644
index 00000000000..785abb39cc9
--- /dev/null
+++ b/source/blender/makesdna/DNA_space_defaults.h
@@ -0,0 +1,67 @@
+/*
+ * 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 DNA
+ */
+
+#pragma once
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name SpaceClip Struct
+ * \{ */
+
+#define _DNA_DEFAULT_MaskSpaceInfo \
+ { \
+ .draw_flag = 0, \
+ .draw_type = MASK_DT_OUTLINE, \
+ .overlay_mode = MASK_OVERLAY_ALPHACHANNEL, \
+ }
+
+#define _DNA_DEFAULT_SpaceClip \
+ { \
+ .spacetype = SPACE_CLIP, \
+ .link_flag = 0, \
+ .xof = 0, \
+ .yof = 0, \
+ .xlockof = 0, \
+ .ylockof = 0, \
+ .zoom = 1.0f, \
+ .user = _DNA_DEFAULT_MovieClipUser, \
+ .scopes = _DNA_DEFAULT_MovieClipScopes, \
+ .flag = SC_SHOW_MARKER_PATTERN | SC_SHOW_TRACK_PATH | SC_SHOW_GRAPH_TRACKS_MOTION | \
+ SC_SHOW_GRAPH_FRAMES | SC_SHOW_ANNOTATION, \
+ .mode = SC_MODE_TRACKING, \
+ .view = SC_VIEW_CLIP, \
+ .path_length = 20, \
+ .loc = {0, 0}, \
+ .scale = 0, \
+ .angle = 0, \
+ .stabmat = _DNA_DEFAULT_UNIT_M4, \
+ .unistabmat = _DNA_DEFAULT_UNIT_M4, \
+ .postproc_flag = 0, \
+ .gpencil_src = SC_GPENCIL_SRC_CLIP, \
+ .around = V3D_AROUND_CENTER_MEDIAN, \
+ .cursor = {0, 0}, \
+ .mask_info = _DNA_DEFAULT_MaskSpaceInfo, \
+ }
+
+/** \} */
+
+/* clang-format on */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 2f3f52a6b82..4e12f135242 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -61,16 +61,23 @@ struct bNodeTree;
struct wmOperator;
struct wmTimer;
-/* Defined in `buttons_intern.h`. */
+/** Defined in `buttons_intern.h`. */
typedef struct SpaceProperties_Runtime SpaceProperties_Runtime;
-/* Defined in `node_intern.h`. */
+/** Defined in `node_intern.hh`. */
+#ifdef __cplusplus
+namespace blender::ed::space_node {
+struct SpaceNode_Runtime;
+} // namespace blender::ed::space_node
+using SpaceNode_Runtime = blender::ed::space_node::SpaceNode_Runtime;
+#else
typedef struct SpaceNode_Runtime SpaceNode_Runtime;
+#endif
-/* Defined in `file_intern.h`. */
+/** Defined in `file_intern.h`. */
typedef struct SpaceFile_Runtime SpaceFile_Runtime;
-/* Defined in `spreadsheet_intern.hh`. */
+/** Defined in `spreadsheet_intern.hh`. */
typedef struct SpaceSpreadsheet_Runtime SpaceSpreadsheet_Runtime;
/* -------------------------------------------------------------------- */
@@ -91,7 +98,7 @@ typedef struct SpaceLink {
char _pad0[6];
} SpaceLink;
-/* SpaceLink.link_flag */
+/** #SpaceLink.link_flag */
enum {
/**
* The space is not a regular one opened through the editor menu (for example) but spawned by an
@@ -113,7 +120,7 @@ enum {
/** \name Space Info
* \{ */
-/* Info Header */
+/** Info Header. */
typedef struct SpaceInfo {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -127,7 +134,7 @@ typedef struct SpaceInfo {
char _pad[7];
} SpaceInfo;
-/* SpaceInfo.rpt_mask */
+/** #SpaceInfo.rpt_mask */
typedef enum eSpaceInfo_RptMask {
INFO_RPT_DEBUG = (1 << 0),
INFO_RPT_INFO = (1 << 1),
@@ -142,7 +149,7 @@ typedef enum eSpaceInfo_RptMask {
/** \name Properties Editor
* \{ */
-/* Properties Editor */
+/** Properties Editor. */
typedef struct SpaceProperties {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -210,7 +217,7 @@ typedef struct SpaceProperties {
// #define BUTS_EFFECTS 14
#endif /* DNA_DEPRECATED_ALLOW */
-/* SpaceProperties.mainb new */
+/** #SpaceProperties.mainb new */
typedef enum eSpaceButtons_Context {
BCONTEXT_RENDER = 0,
BCONTEXT_SCENE = 1,
@@ -235,7 +242,7 @@ typedef enum eSpaceButtons_Context {
BCONTEXT_TOT,
} eSpaceButtons_Context;
-/* SpaceProperties.flag */
+/** #SpaceProperties.flag */
typedef enum eSpaceButtons_Flag {
/* SB_PRV_OSA = (1 << 0), */ /* UNUSED */
SB_PIN_CONTEXT = (1 << 1),
@@ -246,7 +253,7 @@ typedef enum eSpaceButtons_Flag {
SB_SHADING_CONTEXT = (1 << 4),
} eSpaceButtons_Flag;
-/* SpaceProperties.outliner_sync */
+/** #SpaceProperties.outliner_sync */
typedef enum eSpaceButtons_OutlinerSync {
PROPERTIES_SYNC_AUTO = 0,
PROPERTIES_SYNC_NEVER = 1,
@@ -259,10 +266,10 @@ typedef enum eSpaceButtons_OutlinerSync {
/** \name Outliner
* \{ */
-/* Defined in `outliner_intern.h`. */
+/** Defined in `outliner_intern.hh`. */
typedef struct SpaceOutliner_Runtime SpaceOutliner_Runtime;
-/* Outliner */
+/** Outliner */
typedef struct SpaceOutliner {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -281,7 +288,7 @@ typedef struct SpaceOutliner {
* Note that treestore may contain duplicate elements if element
* is used multiple times in outliner tree (e. g. linked objects)
* Also note that BLI_mempool can not be read/written in DNA directly,
- * therefore readfile.c/writefile.c linearize treestore into TreeStore structure
+ * therefore `readfile.c/writefile.c` linearize treestore into TreeStore structure
*/
struct BLI_mempool *treestore;
@@ -303,7 +310,7 @@ typedef struct SpaceOutliner {
SpaceOutliner_Runtime *runtime;
} SpaceOutliner;
-/* SpaceOutliner.flag */
+/** #SpaceOutliner.flag */
typedef enum eSpaceOutliner_Flag {
/* SO_TESTBLOCKS = (1 << 0), */ /* UNUSED */
/* SO_NEWSELECTED = (1 << 1), */ /* UNUSED */
@@ -314,7 +321,7 @@ typedef enum eSpaceOutliner_Flag {
SO_MODE_COLUMN = (1 << 6),
} eSpaceOutliner_Flag;
-/* SpaceOutliner.filter */
+/** #SpaceOutliner.filter */
typedef enum eSpaceOutliner_Filter {
SO_FILTER_SEARCH = (1 << 0), /* Run-time flag. */
SO_FILTER_CLEARED_1 = (1 << 1),
@@ -356,7 +363,7 @@ typedef enum eSpaceOutliner_Filter {
(SO_FILTER_NO_OB_CONTENT | SO_FILTER_NO_CHILDREN | SO_FILTER_OB_TYPE | SO_FILTER_OB_STATE | \
SO_FILTER_NO_COLLECTION | SO_FILTER_NO_VIEW_LAYERS | SO_FILTER_NO_LIB_OVERRIDE)
-/* SpaceOutliner.filter_state */
+/** #SpaceOutliner.filter_state */
typedef enum eSpaceOutliner_StateFilter {
SO_FILTER_OB_ALL = 0,
SO_FILTER_OB_VISIBLE = 1,
@@ -366,7 +373,7 @@ typedef enum eSpaceOutliner_StateFilter {
SO_FILTER_OB_SELECTABLE = 5,
} eSpaceOutliner_StateFilter;
-/* SpaceOutliner.show_restrict_flags */
+/** #SpaceOutliner.show_restrict_flags */
typedef enum eSpaceOutliner_ShowRestrictFlag {
SO_RESTRICT_ENABLE = (1 << 0),
SO_RESTRICT_SELECT = (1 << 1),
@@ -377,7 +384,7 @@ typedef enum eSpaceOutliner_ShowRestrictFlag {
SO_RESTRICT_INDIRECT_ONLY = (1 << 6),
} eSpaceOutliner_Restrict;
-/* SpaceOutliner.outlinevis */
+/** #SpaceOutliner.outlinevis */
typedef enum eSpaceOutliner_Mode {
SO_SCENES = 0,
/* SO_CUR_SCENE = 1, */ /* deprecated! */
@@ -398,7 +405,7 @@ typedef enum eSpaceOutliner_Mode {
SO_OVERRIDES_LIBRARY = 16,
} eSpaceOutliner_Mode;
-/* SpaceOutliner.storeflag */
+/** #SpaceOutliner.storeflag */
typedef enum eSpaceOutliner_StoreFlag {
/* cleanup tree */
SO_TREESTORE_CLEANUP = (1 << 0),
@@ -408,7 +415,7 @@ typedef enum eSpaceOutliner_StoreFlag {
SO_TREESTORE_REBUILD = (1 << 2),
} eSpaceOutliner_StoreFlag;
-/* outliner search flags (SpaceOutliner.search_flags) */
+/** Outliner search flags (#SpaceOutliner.search_flags) */
typedef enum eSpaceOutliner_Search_Flags {
SO_FIND_CASE_SENSITIVE = (1 << 0),
SO_FIND_COMPLETE = (1 << 1),
@@ -429,7 +436,7 @@ typedef struct SpaceGraph_Runtime {
ListBase ghost_curves;
} SpaceGraph_Runtime;
-/* 'Graph' Editor (formerly known as the IPO Editor) */
+/** 'Graph' Editor (formerly known as the IPO Editor). */
typedef struct SpaceGraph {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -467,7 +474,7 @@ typedef struct SpaceGraph {
SpaceGraph_Runtime runtime;
} SpaceGraph;
-/* SpaceGraph.flag (Graph Editor Settings) */
+/** #SpaceGraph.flag (Graph Editor Settings) */
typedef enum eGraphEdit_Flag {
/* OLD DEPRECATED SETTING */
/* SIPO_LOCK_VIEW = (1 << 0), */
@@ -504,7 +511,7 @@ typedef enum eGraphEdit_Flag {
SIPO_NO_DRAW_EXTRAPOLATION = (1 << 17),
} eGraphEdit_Flag;
-/* SpaceGraph.mode (Graph Editor Mode) */
+/** #SpaceGraph.mode (Graph Editor Mode) */
typedef enum eGraphEdit_Mode {
/* all animation curves (from all over Blender) */
SIPO_MODE_ANIMATION = 0,
@@ -532,7 +539,7 @@ typedef enum eGraphEdit_Runtime_Flag {
/** \name NLA Editor
* \{ */
-/* NLA Editor */
+/** NLA Editor */
typedef struct SpaceNla {
struct SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -552,7 +559,7 @@ typedef struct SpaceNla {
View2D v2d DNA_DEPRECATED;
} SpaceNla;
-/* SpaceNla.flag */
+/** #SpaceNla.flag */
typedef enum eSpaceNla_Flag {
SNLA_FLAG_UNUSED_0 = (1 << 0),
SNLA_FLAG_UNUSED_1 = (1 << 1),
@@ -581,8 +588,9 @@ typedef struct SequencerPreviewOverlay {
char _pad0[4];
} SequencerPreviewOverlay;
-/* SequencerPreviewOverlay.flag */
+/** #SequencerPreviewOverlay.flag */
typedef enum eSpaceSeq_SequencerPreviewOverlay_Flag {
+ SEQ_PREVIEW_SHOW_2D_CURSOR = (1 << 1),
SEQ_PREVIEW_SHOW_OUTLINE_SELECTED = (1 << 2),
SEQ_PREVIEW_SHOW_SAFE_MARGINS = (1 << 3),
SEQ_PREVIEW_SHOW_GPENCIL = (1 << 4),
@@ -595,7 +603,7 @@ typedef struct SequencerTimelineOverlay {
char _pad0[4];
} SequencerTimelineOverlay;
-/* SequencerTimelineOverlay.flag */
+/** #SequencerTimelineOverlay.flag */
typedef enum eSpaceSeq_SequencerTimelineOverlay_Flag {
SEQ_TIMELINE_SHOW_STRIP_OFFSETS = (1 << 1),
SEQ_TIMELINE_SHOW_THUMBNAILS = (1 << 2),
@@ -616,7 +624,7 @@ typedef struct SpaceSeqRuntime {
struct GHash *last_displayed_thumbnails;
} SpaceSeqRuntime;
-/* Sequencer */
+/** Sequencer. */
typedef struct SpaceSeq {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -641,12 +649,16 @@ typedef struct SpaceSeq {
/** Deprecated, handled by View2D now. */
float zoom DNA_DEPRECATED;
/** See SEQ_VIEW_* below. */
- int view;
- int overlay_type;
+ char view;
+ char overlay_frame_type;
/** Overlay an image of the editing on below the strips. */
- int draw_flag;
+ char draw_flag;
+ char gizmo_flag;
char _pad[4];
+ /** 2D cursor for transform. */
+ float cursor[2];
+
/** Grease-pencil data. */
struct bGPdata *gpd;
@@ -662,23 +674,22 @@ typedef struct SpaceSeq {
SpaceSeqRuntime runtime;
} SpaceSeq;
-/* SpaceSeq.mainb */
+/** #SpaceSeq.mainb */
typedef enum eSpaceSeq_RegionType {
- SEQ_DRAW_SEQUENCE = 0,
SEQ_DRAW_IMG_IMBUF = 1,
SEQ_DRAW_IMG_WAVEFORM = 2,
SEQ_DRAW_IMG_VECTORSCOPE = 3,
SEQ_DRAW_IMG_HISTOGRAM = 4,
} eSpaceSeq_RegionType;
-/* SpaceSeq.draw_flag */
+/** #SpaceSeq.draw_flag */
typedef enum eSpaceSeq_DrawFlag {
SEQ_DRAW_BACKDROP = (1 << 0),
SEQ_DRAW_UNUSED_1 = (1 << 1),
SEQ_DRAW_TRANSFORM_PREVIEW = (1 << 2),
} eSpaceSeq_DrawFlag;
-/* SpaceSeq.flag */
+/** #SpaceSeq.flag */
typedef enum eSpaceSeq_Flag {
SEQ_DRAWFRAMES = (1 << 0),
SEQ_MARKER_TRANS = (1 << 1),
@@ -699,14 +710,14 @@ typedef enum eSpaceSeq_Flag {
SEQ_SHOW_GRID = (1 << 18),
} eSpaceSeq_Flag;
-/* SpaceSeq.view */
+/** #SpaceSeq.view */
typedef enum eSpaceSeq_Displays {
SEQ_VIEW_SEQUENCE = 1,
SEQ_VIEW_PREVIEW = 2,
SEQ_VIEW_SEQUENCE_PREVIEW = 3,
} eSpaceSeq_Dispays;
-/* SpaceSeq.render_size */
+/** #SpaceSeq.render_size */
typedef enum eSpaceSeq_Proxy_RenderSize {
SEQ_RENDER_SIZE_NONE = -1,
SEQ_RENDER_SIZE_SCENE = 0,
@@ -727,12 +738,21 @@ typedef struct MaskSpaceInfo {
char _pad3[5];
} MaskSpaceInfo;
-/* SpaceSeq.mainb */
-typedef enum eSpaceSeq_OverlayType {
- SEQ_DRAW_OVERLAY_RECT = 0,
- SEQ_DRAW_OVERLAY_REFERENCE = 1,
- SEQ_DRAW_OVERLAY_CURRENT = 2,
-} eSpaceSeq_OverlayType;
+/** #SpaceSeq.gizmo_flag */
+enum {
+ /** All gizmos. */
+ SEQ_GIZMO_HIDE = (1 << 0),
+ SEQ_GIZMO_HIDE_NAVIGATE = (1 << 1),
+ SEQ_GIZMO_HIDE_CONTEXT = (1 << 2),
+ SEQ_GIZMO_HIDE_TOOL = (1 << 3),
+};
+
+/** #SpaceSeq.mainb */
+typedef enum eSpaceSeq_OverlayFrameType {
+ SEQ_OVERLAY_FRAME_TYPE_RECT = 0,
+ SEQ_OVERLAY_FRAME_TYPE_REFERENCE = 1,
+ SEQ_OVERLAY_FRAME_TYPE_CURRENT = 2,
+} eSpaceSeq_OverlayFrameType;
/** \} */
@@ -740,7 +760,7 @@ typedef enum eSpaceSeq_OverlayType {
/** \name File Selector
* \{ */
-/* Config and Input for File Selector */
+/** Config and Input for File Selector. */
typedef struct FileSelectParams {
/** Title, also used for the text of the execute button. */
char title[96];
@@ -760,7 +780,7 @@ typedef struct FileSelectParams {
const ID *rename_id;
void *_pad3;
- /** List of filetypes to filter (FILE_MAXFILE). */
+ /** List of file-types to filter (#FILE_MAXFILE). */
char filter_glob[256];
/** Text items name must match to be shown. */
@@ -806,9 +826,14 @@ typedef struct FileAssetSelectParams {
FileSelectParams base_params;
AssetLibraryReference asset_library_ref;
+ short asset_catalog_visibility; /* eFileSel_Params_AssetCatalogVisibility */
+ char _pad[6];
+ /** If #asset_catalog_visibility is #FILE_SHOW_ASSETS_FROM_CATALOG, this sets the ID of the
+ * catalog to show. */
+ bUUID catalog_id;
short import_type; /* eFileAssetImportType */
- char _pad[6];
+ char _pad2[6];
} FileAssetSelectParams;
typedef enum eFileAssetImportType {
@@ -839,7 +864,7 @@ typedef struct FileFolderHistory {
ListBase folders_next;
} FileFolderHistory;
-/* File Browser */
+/** File Browser. */
typedef struct SpaceFile {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -903,7 +928,7 @@ typedef struct SpaceFile {
SpaceFile_Runtime *runtime;
} SpaceFile;
-/* SpaceFile.browse_mode (File Space Browsing Mode) */
+/** #SpaceFile.browse_mode (File Space Browsing Mode). */
typedef enum eFileBrowse_Mode {
/* Regular Blender File Browser */
FILE_BROWSE_MODE_FILES = 0,
@@ -911,7 +936,7 @@ typedef enum eFileBrowse_Mode {
FILE_BROWSE_MODE_ASSETS = 1,
} eFileBrowse_Mode;
-/* FileSelectParams.display */
+/** #FileSelectParams.display */
enum eFileDisplayType {
/** Internal (not exposed to users): Keep whatever display type was used during the last File
* Browser use, or the default if no such record is found. Use this unless there's a good reason
@@ -925,7 +950,7 @@ enum eFileDisplayType {
FILE_IMGDISPLAY = 3,
};
-/* FileSelectParams.sort */
+/** #FileSelectParams.sort */
enum eFileSortType {
/** Internal (not exposed to users): Sort by whatever was sorted by during the last File Browser
* use, or the default if no such record is found. Use this unless there's a good reason to set a
@@ -940,14 +965,14 @@ enum eFileSortType {
FILE_SORT_SIZE = 4,
};
-/* SpaceFile.tags */
+/** #SpaceFile.tags */
enum eFileTags {
/** Tag the space as having to update files representing or containing main data. Must be set
* after file read and undo/redo. */
FILE_TAG_REBUILD_MAIN_FILES = (1 << 0),
};
-/* FileSelectParams.details_flags */
+/** #FileSelectParams.details_flags */
enum eFileDetails {
FILE_DETAILS_SIZE = (1 << 0),
FILE_DETAILS_DATETIME = (1 << 1),
@@ -968,7 +993,7 @@ enum eFileDetails {
*/
#define FILE_SELECT_MAX_RECURSIONS (FILE_MAX_LIBEXTRA / 2)
-/* filesel types */
+/** File selector types. */
typedef enum eFileSelectType {
FILE_LOADLIB = 1,
FILE_MAIN = 2,
@@ -982,14 +1007,14 @@ typedef enum eFileSelectType {
FILE_SPECIAL = 9,
} eFileSelectType;
-/* filesel op property -> action */
+/** File-selector op property -> action. */
typedef enum eFileSel_Action {
FILE_OPENFILE = 0,
FILE_SAVE = 1,
} eFileSel_Action;
-/* sfile->params->flag */
/**
+ * #FileSelectParams.flag / `sfile->params->flag`.
* \note short flag, also used as 16 lower bits of flags in link/append code
* (WM and BLO code area, see #eBLOLibLinkFlags in BLO_readfile.h).
*/
@@ -1004,15 +1029,25 @@ typedef enum eFileSel_Params_Flag {
FILE_DIRSEL_ONLY = (1 << 7),
FILE_FILTER = (1 << 8),
FILE_PARAMS_FLAG_UNUSED_3 = (1 << 9),
- FILE_PARAMS_FLAG_UNUSED_4 = (1 << 10),
+ FILE_PATH_TOKENS_ALLOW = (1 << 10),
FILE_SORT_INVERT = (1 << 11),
FILE_HIDE_TOOL_PROPS = (1 << 12),
FILE_CHECK_EXISTING = (1 << 13),
FILE_ASSETS_ONLY = (1 << 14),
+ /** Enables filtering by asset catalog. */
+ FILE_FILTER_ASSET_CATALOG = (1 << 15),
} eFileSel_Params_Flag;
-/* sfile->params->rename_flag */
-/* NOTE: short flag. Defined as bitflags, but currently only used as exclusive status markers... */
+typedef enum eFileSel_Params_AssetCatalogVisibility {
+ FILE_SHOW_ASSETS_ALL_CATALOGS,
+ FILE_SHOW_ASSETS_FROM_CATALOG,
+ FILE_SHOW_ASSETS_WITHOUT_CATALOG,
+} eFileSel_Params_AssetCatalogVisibility;
+
+/**
+ * #FileSelectParams.rename_flag / `sfile->params->rename_flag`.
+ * \note short flag. Defined as bit-flags, but currently only used as exclusive status markers.
+ */
typedef enum eFileSel_Params_RenameFlag {
/** Used when we only have the name of the entry we want to rename,
* but not yet access to its matching file entry. */
@@ -1058,7 +1093,7 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_BLENDERLIB = (1u << 31),
} eFileSel_File_Types;
-/* Selection Flags in filesel: struct direntry, unsigned char selflag */
+/** Selection Flags in filesel: struct direntry, unsigned char selflag. */
typedef enum eDirEntry_SelectFlag {
/* FILE_SEL_ACTIVE = (1 << 1), */ /* UNUSED */
FILE_SEL_HIGHLIGHTED = (1 << 2),
@@ -1125,16 +1160,19 @@ typedef struct FileDirEntryArr {
ListBase entries;
int nbr_entries;
int nbr_entries_filtered;
- int entry_idx_start, entry_idx_end;
/** FILE_MAX. */
char root[1024];
} FileDirEntryArr;
-/* FileDirEntry.flags */
+/** #FileDirEntry.flags */
enum {
- FILE_ENTRY_INVALID_PREVIEW = 1 << 0, /* The preview for this entry could not be generated. */
+ /* The preview for this entry could not be generated. */
+ FILE_ENTRY_INVALID_PREVIEW = 1 << 0,
+ /* The entry name needs to be freed when clearing file list. */
FILE_ENTRY_NAME_FREE = 1 << 1,
+ /* The preview for this entry is being loaded on another thread. */
+ FILE_ENTRY_PREVIEW_LOADING = 1 << 2,
};
/** \} */
@@ -1185,13 +1223,10 @@ typedef struct SpaceImage {
char mode_prev;
char pin;
- char _pad1;
- /**
- * The currently active tile of the image when tile is enabled,
- * is kept in sync with the active faces tile.
- */
- short curtile;
- short lock;
+
+ char pixel_snap_mode;
+
+ char lock;
/** UV draw type. */
char dt_uv;
/** Sticky selection type. */
@@ -1199,10 +1234,9 @@ typedef struct SpaceImage {
char dt_uvstretch;
char around;
- int flag;
+ char _pad1[3];
- char pixel_snap_mode;
- char _pad2[7];
+ int flag;
float uv_opacity;
@@ -1218,7 +1252,7 @@ typedef struct SpaceImage {
SpaceImageOverlay overlay;
} SpaceImage;
-/* SpaceImage.dt_uv */
+/** #SpaceImage.dt_uv */
typedef enum eSpaceImage_UVDT {
SI_UVDT_OUTLINE = 0,
SI_UVDT_DASH = 1,
@@ -1226,20 +1260,20 @@ typedef enum eSpaceImage_UVDT {
SI_UVDT_WHITE = 3,
} eSpaceImage_UVDT;
-/* SpaceImage.dt_uvstretch */
+/** #SpaceImage.dt_uvstretch */
typedef enum eSpaceImage_UVDT_Stretch {
SI_UVDT_STRETCH_ANGLE = 0,
SI_UVDT_STRETCH_AREA = 1,
} eSpaceImage_UVDT_Stretch;
-/* SpaceImage.pixel_snap_mode */
+/** #SpaceImage.pixel_snap_mode */
typedef enum eSpaceImage_PixelSnapMode {
SI_PIXEL_SNAP_DISABLED = 0,
SI_PIXEL_SNAP_CENTER = 1,
SI_PIXEL_SNAP_CORNER = 2,
} eSpaceImage_Snap_Mode;
-/* SpaceImage.mode */
+/** #SpaceImage.mode */
typedef enum eSpaceImage_Mode {
SI_MODE_VIEW = 0,
SI_MODE_PAINT = 1,
@@ -1256,7 +1290,7 @@ typedef enum eSpaceImage_Sticky {
SI_STICKY_VERTEX = 2,
} eSpaceImage_Sticky;
-/* SpaceImage.flag */
+/** #SpaceImage.flag */
typedef enum eSpaceImage_Flag {
SI_FLAG_UNUSED_0 = (1 << 0), /* cleared */
SI_FLAG_UNUSED_1 = (1 << 1), /* cleared */
@@ -1350,7 +1384,7 @@ typedef struct SpaceText_Runtime {
} SpaceText_Runtime;
-/* Text Editor */
+/** Text Editor. */
typedef struct SpaceText {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1400,12 +1434,12 @@ typedef struct SpaceText {
SpaceText_Runtime runtime;
} SpaceText;
-/* SpaceText flags (moved from DNA_text_types.h) */
+/** SpaceText flags (moved from DNA_text_types.h). */
typedef enum eSpaceText_Flags {
/* scrollable */
ST_SCROLL_SELECT = (1 << 0),
- ST_FLAG_UNUSED_4 = (1 << 4), /* dirty */
+ ST_FLAG_UNUSED_4 = (1 << 4), /* Cleared. */
ST_FIND_WRAP = (1 << 5),
ST_FIND_ALL = (1 << 6),
@@ -1424,7 +1458,7 @@ typedef enum eSpaceText_Flags {
/** \name Script View (Obsolete)
* \{ */
-/* Script Runtime Data - Obsolete (pre 2.5) */
+/** Script Runtime Data - Obsolete (pre 2.5). */
typedef struct Script {
ID id;
@@ -1449,7 +1483,7 @@ typedef struct Script {
_script->py_globaldict = NULL; \
_script->flags = 0
-/* Script View - Obsolete (pre 2.5) */
+/** Script View - Obsolete (pre 2.5). */
typedef struct SpaceScript {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1488,6 +1522,18 @@ typedef struct bNodeTreePath {
char display_name[64];
} bNodeTreePath;
+typedef struct SpaceNodeOverlay {
+ /* eSpaceNodeOverlay_Flag */
+ int flag;
+} SpaceNodeOverlay;
+
+typedef enum eSpaceNodeOverlay_Flag {
+ SN_OVERLAY_SHOW_OVERLAYS = (1 << 1),
+ SN_OVERLAY_SHOW_WIRE_COLORS = (1 << 2),
+ SN_OVERLAY_SHOW_TIMINGS = (1 << 3),
+ SN_OVERLAY_SHOW_PATH = (1 << 4),
+} eSpaceNodeOverlay_Flag;
+
typedef struct SpaceNode {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1541,10 +1587,13 @@ typedef struct SpaceNode {
/** Grease-pencil data. */
struct bGPdata *gpd;
+ SpaceNodeOverlay overlay;
+ char _pad2[4];
+
SpaceNode_Runtime *runtime;
} SpaceNode;
-/* SpaceNode.flag */
+/** #SpaceNode.flag */
typedef enum eSpaceNode_Flag {
SNODE_BACKDRAW = (1 << 1),
SNODE_SHOW_GPENCIL = (1 << 2),
@@ -1562,7 +1611,7 @@ typedef enum eSpaceNode_Flag {
SNODE_SKIP_INSOFFSET = (1 << 13),
} eSpaceNode_Flag;
-/* SpaceNode.texfrom */
+/** #SpaceNode.texfrom */
typedef enum eSpaceNode_TexFrom {
/* SNODE_TEX_OBJECT = 0, */
SNODE_TEX_WORLD = 1,
@@ -1570,14 +1619,14 @@ typedef enum eSpaceNode_TexFrom {
SNODE_TEX_LINESTYLE = 3,
} eSpaceNode_TexFrom;
-/* SpaceNode.shaderfrom */
+/** #SpaceNode.shaderfrom */
typedef enum eSpaceNode_ShaderFrom {
SNODE_SHADER_OBJECT = 0,
SNODE_SHADER_WORLD = 1,
SNODE_SHADER_LINESTYLE = 2,
} eSpaceNode_ShaderFrom;
-/* SpaceNode.insert_ofs_dir */
+/** #SpaceNode.insert_ofs_dir */
enum {
SNODE_INSERTOFS_DIR_RIGHT = 0,
SNODE_INSERTOFS_DIR_LEFT = 1,
@@ -1589,7 +1638,7 @@ enum {
/** \name Console
* \{ */
-/* Console content */
+/** Console content. */
typedef struct ConsoleLine {
struct ConsoleLine *next, *prev;
@@ -1605,7 +1654,7 @@ typedef struct ConsoleLine {
int type;
} ConsoleLine;
-/* ConsoleLine.type */
+/** #ConsoleLine.type */
typedef enum eConsoleLine_Type {
CONSOLE_LINE_OUTPUT = 0,
CONSOLE_LINE_INPUT = 1,
@@ -1613,7 +1662,7 @@ typedef enum eConsoleLine_Type {
CONSOLE_LINE_ERROR = 3,
} eConsoleLine_Type;
-/* Console View */
+/** Console View. */
typedef struct SpaceConsole {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1667,7 +1716,7 @@ typedef struct SpaceUserPref {
/** \name Motion Tracking
* \{ */
-/* Clip Editor */
+/** Clip Editor. */
typedef struct SpaceClip {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1713,7 +1762,7 @@ typedef struct SpaceClip {
*/
float stabmat[4][4], unistabmat[4][4];
- /* movie postprocessing */
+ /** Movie postprocessing. */
int postproc_flag;
/* grease pencil */
@@ -1730,7 +1779,7 @@ typedef struct SpaceClip {
MaskSpaceInfo mask_info;
} SpaceClip;
-/* SpaceClip.flag */
+/** #SpaceClip.flag */
typedef enum eSpaceClip_Flag {
SC_SHOW_MARKER_PATTERN = (1 << 0),
SC_SHOW_MARKER_SEARCH = (1 << 1),
@@ -1757,7 +1806,7 @@ typedef enum eSpaceClip_Flag {
SC_SHOW_METADATA = (1 << 22),
} eSpaceClip_Flag;
-/* SpaceClip.mode */
+/** #SpaceClip.mode */
typedef enum eSpaceClip_Mode {
SC_MODE_TRACKING = 0,
// SC_MODE_RECONSTRUCTION = 1, /* DEPRECATED */
@@ -1765,14 +1814,14 @@ typedef enum eSpaceClip_Mode {
SC_MODE_MASKEDIT = 3,
} eSpaceClip_Mode;
-/* SpaceClip.view */
+/** #SpaceClip.view */
typedef enum eSpaceClip_View {
SC_VIEW_CLIP = 0,
SC_VIEW_GRAPH = 1,
SC_VIEW_DOPESHEET = 2,
} eSpaceClip_View;
-/* SpaceClip.gpencil_src */
+/** #SpaceClip.gpencil_src */
typedef enum eSpaceClip_GPencil_Source {
SC_GPENCIL_SRC_CLIP = 0,
SC_GPENCIL_SRC_TRACK = 1,
@@ -1966,6 +2015,7 @@ typedef enum eSpaceSpreadsheet_ContextType {
} eSpaceSpreadsheet_ContextType;
typedef enum eSpreadsheetColumnValueType {
+ SPREADSHEET_VALUE_TYPE_UNKNOWN = -1,
SPREADSHEET_VALUE_TYPE_BOOL = 0,
SPREADSHEET_VALUE_TYPE_INT32 = 1,
SPREADSHEET_VALUE_TYPE_FLOAT = 2,
@@ -1973,6 +2023,7 @@ typedef enum eSpreadsheetColumnValueType {
SPREADSHEET_VALUE_TYPE_FLOAT3 = 4,
SPREADSHEET_VALUE_TYPE_COLOR = 5,
SPREADSHEET_VALUE_TYPE_INSTANCES = 6,
+ SPREADSHEET_VALUE_TYPE_STRING = 7,
} eSpreadsheetColumnValueType;
/**
@@ -1988,8 +2039,10 @@ typedef enum eSpreadsheetColumnValueType {
/** \name Space Defines (eSpace_Type)
* \{ */
-/* space types, moved from DNA_screen_types.h */
-/* Do NOT change order, append on end. types are hardcoded needed */
+/**
+ * Space types: #SpaceLink.spacetype & #ScrArea.spacetype.
+ * \note Do NOT change order, append on end. types are hardcoded needed.
+ */
typedef enum eSpace_Type {
SPACE_EMPTY = 0,
SPACE_VIEW3D = 1,
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index ee33e8666ec..cd19825d29f 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -98,8 +98,10 @@ typedef struct CBData {
int cur;
} CBData;
-/* 32 = MAXCOLORBAND */
-/* note that this has to remain a single struct, for UserDef */
+/**
+ * 32 = #MAXCOLORBAND
+ * \note that this has to remain a single struct, for UserDef.
+ */
typedef struct ColorBand {
short tot, cur;
char ipotype, ipotype_hue;
@@ -128,9 +130,9 @@ typedef struct PointDensity {
struct Object *object;
/** `index + 1` in ob.particlesystem, non-ID pointer not allowed */
int psys;
- /** cache points in worldspace, object space, ... ? */
+ /** cache points in world-space, object space, ... ? */
short psys_cache_space;
- /** cache points in worldspace, object space, ... ? */
+ /** cache points in world-space, object space, ... ? */
short ob_cache_space;
/** vertex attribute layer for color source, MAX_CUSTOMDATA_LAYER_NAME */
char vertex_attribute_name[64];
@@ -454,14 +456,14 @@ typedef struct ColorMapping {
/* **************** ColorBand ********************* */
-/* colormode */
+/** color-mode. */
enum {
COLBAND_BLEND_RGB = 0,
COLBAND_BLEND_HSV = 1,
COLBAND_BLEND_HSL = 2,
};
-/* interpolation */
+/** Interpolation. */
enum {
COLBAND_INTERP_LINEAR = 0,
COLBAND_INTERP_EASE = 1,
@@ -470,7 +472,7 @@ enum {
COLBAND_INTERP_CONSTANT = 4,
};
-/* color interpolation */
+/** Color interpolation. */
enum {
COLBAND_HUE_NEAR = 0,
COLBAND_HUE_FAR = 1,
@@ -509,7 +511,7 @@ enum {
/* #define TEX_PD_NOISE_AGE 2 */ /* Deprecated */
/* #define TEX_PD_NOISE_TIME 3 */ /* Deprecated */
-/* color_source */
+/** color_source. */
enum {
TEX_PD_COLOR_CONSTANT = 0,
/* color_source: particles */
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index fb2d985d353..815fab59876 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -398,6 +398,8 @@ typedef struct MovieTrackingDopesheetChannel {
int *segments;
/** Longest segment length and total number of tracked frames. */
int max_segment, total_frames;
+ /** These numbers are valid only if tot_segment > 0. */
+ int first_not_disabled_marker_framenr, last_not_disabled_marker_framenr;
} MovieTrackingDopesheetChannel;
typedef struct MovieTrackingDopesheetCoverageSegment {
@@ -460,7 +462,7 @@ typedef struct MovieTracking {
MovieTrackingDopesheet dopesheet;
} MovieTracking;
-/* MovieTrackingCamera->distortion_model */
+/** #MovieTrackingCamera.distortion_model */
enum {
TRACKING_DISTORTION_MODEL_POLYNOMIAL = 0,
TRACKING_DISTORTION_MODEL_DIVISION = 1,
@@ -468,13 +470,13 @@ enum {
TRACKING_DISTORTION_MODEL_BROWN = 3,
};
-/* MovieTrackingCamera->units */
+/** #MovieTrackingCamera.units */
enum {
CAMERA_UNITS_PX = 0,
CAMERA_UNITS_MM = 1,
};
-/* MovieTrackingMarker->flag */
+/** #MovieTrackingMarker.flag */
enum {
MARKER_DISABLED = (1 << 0),
MARKER_TRACKED = (1 << 1),
@@ -483,7 +485,7 @@ enum {
MARKER_GRAPH_SEL = (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y),
};
-/* MovieTrackingTrack->flag */
+/** #MovieTrackingTrack.flag */
enum {
TRACK_HAS_BUNDLE = (1 << 1),
TRACK_DISABLE_RED = (1 << 2),
@@ -499,7 +501,7 @@ enum {
TRACK_USE_2D_STAB_ROT = (1 << 12),
};
-/* MovieTrackingTrack->motion_model */
+/** #MovieTrackingTrack.motion_model */
enum {
TRACK_MOTION_MODEL_TRANSLATION = 0,
TRACK_MOTION_MODEL_TRANSLATION_ROTATION = 1,
@@ -509,27 +511,27 @@ enum {
TRACK_MOTION_MODEL_HOMOGRAPHY = 5,
};
-/* MovieTrackingTrack->algorithm_flag */
+/** #MovieTrackingTrack.algorithm_flag */
enum {
TRACK_ALGORITHM_FLAG_USE_BRUTE = (1 << 0),
TRACK_ALGORITHM_FLAG_USE_NORMALIZATION = (1 << 2),
TRACK_ALGORITHM_FLAG_USE_MASK = (1 << 3),
};
-/* MovieTrackingTrack->pattern_match */
+/** #MovieTrackingTrack.pattern_match */
typedef enum eTrackFrameMatch {
TRACK_MATCH_KEYFRAME = 0,
TRACK_MATCH_PREVIOS_FRAME = 1,
} eTrackFrameMatch;
-/* MovieTrackingSettings->motion_flag */
+/** #MovieTrackingSettings.motion_flag */
enum {
TRACKING_MOTION_TRIPOD = (1 << 0),
TRACKING_MOTION_MODAL = (TRACKING_MOTION_TRIPOD),
};
-/* MovieTrackingSettings->speed */
+/** #MovieTrackingSettings.speed */
enum {
TRACKING_SPEED_FASTEST = 0,
TRACKING_SPEED_REALTIME = 1,
@@ -538,13 +540,13 @@ enum {
TRACKING_SPEED_DOUBLE = 5,
};
-/* MovieTrackingSettings->reconstruction_flag */
+/** #MovieTrackingSettings.reconstruction_flag */
enum {
/* TRACKING_USE_FALLBACK_RECONSTRUCTION = (1 << 0), */ /* DEPRECATED */
TRACKING_USE_KEYFRAME_SELECTION = (1 << 1),
};
-/* MovieTrackingSettings->refine_camera_intrinsics */
+/** #MovieTrackingSettings.refine_camera_intrinsics */
enum {
REFINE_NO_INTRINSICS = (0),
@@ -554,7 +556,7 @@ enum {
REFINE_TANGENTIAL_DISTORTION = (1 << 3),
};
-/* MovieTrackingStabilization->flag */
+/** #MovieTrackingStabilization.flag */
enum {
TRACKING_2D_STABILIZATION = (1 << 0),
TRACKING_AUTOSCALE = (1 << 1),
@@ -563,19 +565,19 @@ enum {
TRACKING_SHOW_STAB_TRACKS = (1 << 5),
};
-/* MovieTrackingStabilization->filter */
+/** #MovieTrackingStabilization.filter */
enum {
TRACKING_FILTER_NEAREST = 0,
TRACKING_FILTER_BILINEAR = 1,
TRACKING_FILTER_BICUBIC = 2,
};
-/* MovieTrackingReconstruction->flag */
+/** #MovieTrackingReconstruction.flag */
enum {
TRACKING_RECONSTRUCTED = (1 << 0),
};
-/* MovieTrackingObject->flag */
+/** #MovieTrackingObject.flag */
enum {
TRACKING_OBJECT_CAMERA = (1 << 0),
};
@@ -586,35 +588,37 @@ enum {
TRACKING_CLEAN_DELETE_SEGMENT = 2,
};
-/* MovieTrackingDopesheet->sort_method */
+/** #MovieTrackingDopesheet.sort_method */
enum {
TRACKING_DOPE_SORT_NAME = 0,
TRACKING_DOPE_SORT_LONGEST = 1,
TRACKING_DOPE_SORT_TOTAL = 2,
TRACKING_DOPE_SORT_AVERAGE_ERROR = 3,
+ TRACKING_DOPE_SORT_START = 4,
+ TRACKING_DOPE_SORT_END = 5,
};
-/* MovieTrackingDopesheet->flag */
+/** #MovieTrackingDopesheet.flag */
enum {
TRACKING_DOPE_SORT_INVERSE = (1 << 0),
TRACKING_DOPE_SELECTED_ONLY = (1 << 1),
TRACKING_DOPE_SHOW_HIDDEN = (1 << 2),
};
-/* MovieTrackingDopesheetCoverageSegment->trackness */
+/** #MovieTrackingDopesheetCoverageSegment.trackness */
enum {
TRACKING_COVERAGE_BAD = 0,
TRACKING_COVERAGE_ACCEPTABLE = 1,
TRACKING_COVERAGE_OK = 2,
};
-/* MovieTrackingPlaneMarker->flag */
+/** #MovieTrackingPlaneMarker.flag */
enum {
PLANE_MARKER_DISABLED = (1 << 0),
PLANE_MARKER_TRACKED = (1 << 1),
};
-/* MovieTrackingPlaneTrack->flag */
+/** #MovieTrackingPlaneTrack.flag */
enum {
PLANE_TRACK_HIDDEN = (1 << 1),
PLANE_TRACK_LOCKED = (1 << 2),
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 291f6de5ba2..15bb1ef920d 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -30,7 +30,8 @@
extern "C" {
#endif
-/* themes; defines in BIF_resource.h */
+/* Themes; defines in `BIF_resource.h`. */
+
struct ColorBand;
/* ************************ style definitions ******************** */
@@ -50,27 +51,29 @@ typedef enum eUIFont_ID {
/* UIFONT_CUSTOM2 = 3, */ /* UNUSED */
} eUIFont_ID;
-/* default fonts to load/initialize */
-/* first font is the default (index 0), others optional */
+/**
+ * Default fonts to load/initialize.
+ * First font is the default (index 0), others optional.
+ */
+#
+#
typedef struct uiFont {
struct uiFont *next, *prev;
/** 1024 = FILE_MAX. */
- char filename[1024];
+ char filepath[1024];
/** From blfont lib. */
short blf_id;
/** Own id (eUIFont_ID). */
short uifont_id;
- /** Fonts that read from left to right. */
- short r_to_l;
- char _pad0[2];
} uiFont;
/** This state defines appearance of text. */
typedef struct uiFontStyle {
/** Saved in file, 0 is default. */
short uifont_id;
+ char _pad1[2];
/** Actual size depends on 'global' dpi. */
- short points;
+ float points;
/** Style hint. */
short italic, bold;
/** Value is amount of pixels blur. */
@@ -82,6 +85,7 @@ typedef struct uiFontStyle {
float shadowalpha;
/** 1 value, typically white or black anyway. */
float shadowcolor;
+ char _pad2[4];
} uiFontStyle;
/* this is fed to the layout engine and widget code */
@@ -206,6 +210,9 @@ typedef struct ThemeUI {
/** Intensity of the border icons. >0 will render an border around themed
* icons. */
float icon_border_intensity;
+ float panel_roundness;
+ char _pad2[4];
+
} ThemeUI;
/* try to put them all in one, if needed a special struct can be created as well
@@ -319,6 +326,8 @@ typedef struct ThemeSpace {
unsigned char vertex_size, outline_width, obcenter_dia, facedot_size;
unsigned char noodle_curving;
unsigned char grid_levels;
+ char _pad5[3];
+ float dash_alpha;
/* syntax for textwindow and nodes */
unsigned char syntaxl[4], syntaxs[4]; /* in nodespace used for backdrop matte */
@@ -341,6 +350,7 @@ typedef struct ThemeSpace {
unsigned char active_strip[4], selected_strip[4];
/** For dopesheet - scale factor for size of keyframes (i.e. height of channels). */
+ char _pad7[1];
float keyframe_scale_fac;
unsigned char editmesh_active[4];
@@ -437,7 +447,7 @@ typedef enum eBackgroundGradientTypes {
TH_BACKGROUND_GRADIENT_RADIAL = 2,
} eBackgroundGradientTypes;
-/* set of colors for use as a custom color set for Objects/Bones wire drawing */
+/** Set of colors for use as a custom color set for Objects/Bones wire drawing. */
typedef struct ThemeWireColor {
unsigned char solid[4];
unsigned char select[4];
@@ -551,7 +561,7 @@ typedef struct bUserMenuItem_Op {
bUserMenuItem item;
char op_idname[64];
struct IDProperty *prop;
- char opcontext;
+ char opcontext; /* #wmOperatorCallContext */
char _pad0[7];
} bUserMenuItem_Op;
@@ -644,6 +654,8 @@ typedef struct UserDef_Experimental {
char no_proxy_to_override_conversion;
char use_cycles_debug;
char use_geometry_nodes_legacy;
+ char show_asset_debug_info;
+ char no_asset_indexing;
char SANITIZE_AFTER_HERE;
/* The following options are automatically sanitized (set to 0)
* when the release cycle is not alpha. */
@@ -654,7 +666,7 @@ typedef struct UserDef_Experimental {
char use_sculpt_tools_tilt;
char use_extended_asset_browser;
char use_override_templates;
- char _pad[3];
+ char _pad[1];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
@@ -932,7 +944,8 @@ typedef struct UserDef {
short sequencer_proxy_setup; /* eUserpref_SeqProxySetup */
float collection_instance_empty_size;
- char _pad10[2];
+ char text_flag;
+ char _pad10[1];
char file_preview_type; /* eUserpref_File_Preview_Type */
char statusbar_flag; /* eUserpref_StatusBar_Flag */
@@ -949,7 +962,7 @@ typedef struct UserDef {
UserDef_Runtime runtime;
} UserDef;
-/* from blenkernel blender.c */
+/** From blenkernel `blender.c`. */
extern UserDef U;
/* ***************** USERDEF ****************** */
@@ -1132,6 +1145,7 @@ typedef enum eUserpref_GPU_Flag {
USER_GPU_FLAG_NO_DEPT_PICK = (1 << 0),
USER_GPU_FLAG_NO_EDIT_MODE_SMOOTH_WIRE = (1 << 1),
USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE = (1 << 2),
+ USER_GPU_FLAG_SUBDIVISION_EVALUATION = (1 << 3),
} eUserpref_GPU_Flag;
/** #UserDef.tablet_api */
@@ -1242,6 +1256,9 @@ typedef enum eDupli_ID_Flags {
USER_DUP_HAIR = (1 << 14),
USER_DUP_POINTCLOUD = (1 << 15),
USER_DUP_VOLUME = (1 << 16),
+ USER_DUP_LATTICE = (1 << 17),
+ USER_DUP_CAMERA = (1 << 18),
+ USER_DUP_SPEAKER = (1 << 19),
USER_DUP_OBDATA = (~0) & ((1 << 24) - 1),
@@ -1254,6 +1271,14 @@ typedef enum eDupli_ID_Flags {
} eDupli_ID_Flags;
/**
+ * Text Editor options
+ * #UserDef.text_flag
+ */
+typedef enum eTextEdit_Flags {
+ USER_TEXT_EDIT_AUTO_CLOSE = (1 << 0),
+} eTextEdit_Flags;
+
+/**
* Text draw options
* #UserDef.text_render
*/
diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h
index f8166305fd9..6c03422963d 100644
--- a/source/blender/makesdna/DNA_view2d_types.h
+++ b/source/blender/makesdna/DNA_view2d_types.h
@@ -31,7 +31,7 @@ extern "C" {
/* ---------------------------------- */
-/* View 2D data - stored per region */
+/** View 2D data - stored per region. */
typedef struct View2D {
/** Tot - area that data can be drawn in; cur - region of tot that is visible in viewport. */
rctf tot, cur;
@@ -83,7 +83,7 @@ typedef struct View2D {
/* ---------------------------------- */
-/* view zooming restrictions, per axis (v2d->keepzoom) */
+/** View zooming restrictions, per axis (#View2D.keepzoom) */
enum {
/* zoom is clamped to lie within limits set by minzoom and maxzoom */
V2D_LIMITZOOM = (1 << 0),
@@ -97,7 +97,7 @@ enum {
V2D_LOCKZOOM_Y = (1 << 9),
};
-/* view panning restrictions, per axis (v2d->keepofs) */
+/** View panning restrictions, per axis (#View2D.keepofs). */
enum {
/* panning on x-axis is not allowed */
V2D_LOCKOFS_X = (1 << 1),
@@ -109,7 +109,7 @@ enum {
V2D_KEEPOFS_Y = (1 << 4),
};
-/* view extent restrictions (v2d->keeptot) */
+/** View extent restrictions (#View2D.keeptot). */
enum {
/** 'cur' view can be out of extents of 'tot' */
V2D_KEEPTOT_FREE = 0,
@@ -120,7 +120,7 @@ enum {
V2D_KEEPTOT_STRICT = 2,
};
-/* general refresh settings (v2d->flag) */
+/** General refresh settings (#View2D.flag). */
enum {
/* global view2d horizontal locking (for showing same time interval) */
/* TODO: this flag may be set in old files but is not accessible currently,
@@ -138,7 +138,7 @@ enum {
V2D_IS_INIT = (1 << 10),
};
-/* scroller flags for View2D (v2d->scroll) */
+/** Scroller flags for View2D (#View2D.scroll). */
enum {
/* left scrollbar */
V2D_SCROLL_LEFT = (1 << 0),
@@ -162,13 +162,15 @@ enum {
V2D_SCROLL_HORIZONTAL_FULLR = (1 << 10),
};
-/* scroll_ui, activate flag for drawing */
+/** scroll_ui, activate flag for drawing. */
enum {
V2D_SCROLL_H_ACTIVE = (1 << 0),
V2D_SCROLL_V_ACTIVE = (1 << 1),
};
-/* alignment flags for totrect, flags use 'shading-out' convention (v2d->align) */
+/**
+ * Alignment flags for `totrect`, flags use 'shading-out' convention (#View2D.align).
+ */
enum {
/* all quadrants free */
V2D_ALIGN_FREE = 0,
diff --git a/source/blender/makesdna/DNA_view3d_defaults.h b/source/blender/makesdna/DNA_view3d_defaults.h
index c4d0c83b346..870197a401c 100644
--- a/source/blender/makesdna/DNA_view3d_defaults.h
+++ b/source/blender/makesdna/DNA_view3d_defaults.h
@@ -53,6 +53,7 @@
.wireframe_threshold = 1.0f, \
.wireframe_opacity = 1.0f, \
.xray_alpha_bone = 0.5f, \
+ .bone_wire_alpha = 1.0f, \
.fade_alpha = 0.40f, \
.texture_paint_mode_opacity = 1.0f, \
.weight_paint_mode_opacity = 1.0f, \
diff --git a/source/blender/makesdna/DNA_view3d_enums.h b/source/blender/makesdna/DNA_view3d_enums.h
index aec52da1bf9..59012a0cd8d 100644
--- a/source/blender/makesdna/DNA_view3d_enums.h
+++ b/source/blender/makesdna/DNA_view3d_enums.h
@@ -30,6 +30,9 @@ typedef enum eV3DOffscreenDrawFlag {
V3D_OFSDRAW_SHOW_ANNOTATION = (1 << 0),
V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS = (1 << 1),
V3D_OFSDRAW_SHOW_GRIDFLOOR = (1 << 2),
+ V3D_OFSDRAW_SHOW_SELECTION = (1 << 3),
+ V3D_OFSDRAW_XR_SHOW_CONTROLLERS = (1 << 4),
+ V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS = (1 << 5),
} eV3DOffscreenDrawFlag;
/** #View3DShading.light */
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 4d88f6f0c15..dafae6f2eb7 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -64,12 +64,14 @@ typedef struct RegionView3D {
/** User defined clipping planes. */
float clip[6][4];
- /** Clip in object space,
- * means we can test for clipping in editmode without first going into worldspace. */
+ /**
+ * Clip in object space,
+ * means we can test for clipping in edit-mode without first going into world-space.
+ */
float clip_local[6][4];
struct BoundBox *clipbb;
- /** Allocated backup of its self while in local-view. */
+ /** Allocated backup of itself while in local-view. */
struct RegionView3D *localvd;
struct RenderEngine *render_engine;
@@ -94,8 +96,8 @@ typedef struct RegionView3D {
/** Runtime only. */
float pixsize;
/**
- * View center & orbit pivot, negative of worldspace location,
- * also matches -viewinv[3][0:3] in ortho mode.
+ * View center & orbit pivot, negative of world-space location,
+ * also matches `-viewinv[3][0:3]` in orthographic mode.
*/
float ofs[3];
/** Viewport zoom on the camera frame, see BKE_screen_view3d_zoom_to_fac. */
@@ -222,6 +224,8 @@ typedef struct View3DOverlay {
/** Armature edit/pose mode settings. */
float xray_alpha_bone;
+ float bone_wire_alpha;
+ char _pad1[4];
/** Darken Inactive. */
float fade_alpha;
@@ -243,7 +247,7 @@ typedef struct View3DOverlay {
char _pad[4];
} View3DOverlay;
-/* View3DOverlay->handle_display */
+/** #View3DOverlay.handle_display */
typedef enum eHandleDisplay {
/* Display only selected points. */
CURVE_HANDLE_SELECTED = 0,
@@ -298,7 +302,7 @@ typedef struct View3D {
struct Object *camera, *ob_center;
rctf render_border;
- /** Allocated backup of its self while in local-view. */
+ /** Allocated backup of itself while in local-view. */
struct View3D *localvd;
/** Optional string for armature bone to define center, MAXBONENAME. */
@@ -373,6 +377,7 @@ typedef struct View3D {
#define V3D_HIDE_HELPLINES (1 << 2)
#define V3D_FLAG_UNUSED_2 (1 << 3) /* cleared */
#define V3D_XR_SESSION_MIRROR (1 << 4)
+#define V3D_XR_SESSION_SURFACE (1 << 5)
#define V3D_FLAG_UNUSED_10 (1 << 10) /* cleared */
#define V3D_SELECT_OUTLINE (1 << 11)
@@ -416,7 +421,7 @@ enum {
RV3D_LOCK_ANY_TRANSFORM = (RV3D_LOCK_LOCATION | RV3D_LOCK_ROTATION | RV3D_LOCK_ZOOM_AND_DOLLY),
};
-/* Bitwise OR of the regular lock-flags with runtime only lock-flags. */
+/** Bit-wise OR of the regular lock-flags with runtime only lock-flags. */
#define RV3D_LOCK_FLAGS(rv3d) ((rv3d)->viewlock | ((rv3d)->runtime_viewlock))
/** #RegionView3D.viewlock_quad */
@@ -465,6 +470,8 @@ enum {
#define V3D_FLAG2_UNUSED_13 (1 << 13) /* cleared */
#define V3D_FLAG2_UNUSED_14 (1 << 14) /* cleared */
#define V3D_FLAG2_UNUSED_15 (1 << 15) /* cleared */
+#define V3D_XR_SHOW_CONTROLLERS (1 << 16)
+#define V3D_XR_SHOW_CUSTOM_OVERLAYS (1 << 17)
/** #View3D.gp_flag (short) */
#define V3D_GP_FADE_OBJECTS (1 << 0) /* Fade all non GP objects */
@@ -497,6 +504,16 @@ enum {
V3D_SHADING_STUDIOLIGHT_VIEW_ROTATION = (1 << 14),
};
+#define V3D_USES_SCENE_LIGHTS(v3d) \
+ ((((v3d)->shading.type == OB_MATERIAL) && ((v3d)->shading.flag & V3D_SHADING_SCENE_LIGHTS)) || \
+ (((v3d)->shading.type == OB_RENDER) && \
+ ((v3d)->shading.flag & V3D_SHADING_SCENE_LIGHTS_RENDER)))
+
+#define V3D_USES_SCENE_WORLD(v3d) \
+ ((((v3d)->shading.type == OB_MATERIAL) && ((v3d)->shading.flag & V3D_SHADING_SCENE_WORLD)) || \
+ (((v3d)->shading.type == OB_RENDER) && \
+ ((v3d)->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER)))
+
/** #View3DShading.cavity_type */
enum {
V3D_SHADING_CAVITY_SSAO = 0,
diff --git a/source/blender/makesdna/DNA_volume_types.h b/source/blender/makesdna/DNA_volume_types.h
index 1344f295ea9..df5a122faaf 100644
--- a/source/blender/makesdna/DNA_volume_types.h
+++ b/source/blender/makesdna/DNA_volume_types.h
@@ -30,13 +30,13 @@ struct PackedFile;
struct VolumeGridVector;
typedef struct Volume_Runtime {
- /* OpenVDB Grids */
+ /** OpenVDB Grids. */
struct VolumeGridVector *grids;
- /* Current frame in sequence for evaluated volume */
+ /** Current frame in sequence for evaluated volume. */
int frame;
- /* Default simplify level for volume grids loaded from files. */
+ /** Default simplify level for volume grids loaded from files. */
int default_simplify_level;
} Volume_Runtime;
@@ -96,12 +96,12 @@ typedef struct Volume {
Volume_Runtime runtime;
} Volume;
-/* Volume.flag */
+/** #Volume.flag */
enum {
VO_DS_EXPAND = (1 << 0),
};
-/* Volume.sequence_mode */
+/** #Volume.sequence_mode */
typedef enum VolumeSequenceMode {
VOLUME_SEQUENCE_CLIP = 0,
VOLUME_SEQUENCE_EXTEND = 1,
@@ -109,7 +109,7 @@ typedef enum VolumeSequenceMode {
VOLUME_SEQUENCE_PING_PONG = 3,
} VolumeSequenceMode;
-/* VolumeDisplay.wireframe_type */
+/** #VolumeDisplay.wireframe_type */
typedef enum VolumeWireframeType {
VOLUME_WIREFRAME_NONE = 0,
VOLUME_WIREFRAME_BOUNDS = 1,
@@ -117,32 +117,32 @@ typedef enum VolumeWireframeType {
VOLUME_WIREFRAME_POINTS = 3,
} VolumeWireframeType;
-/* VolumeDisplay.wireframe_detail */
+/** #VolumeDisplay.wireframe_detail */
typedef enum VolumeWireframeDetail {
VOLUME_WIREFRAME_COARSE = 0,
VOLUME_WIREFRAME_FINE = 1,
} VolumeWireframeDetail;
-/* VolumeRender.space */
+/** #VolumeRender.space */
typedef enum VolumeRenderSpace {
VOLUME_SPACE_OBJECT = 0,
VOLUME_SPACE_WORLD = 1,
} VolumeRenderSpace;
-/* VolumeDisplay.interpolation_method */
+/** #VolumeDisplay.interpolation_method */
typedef enum VolumeDisplayInterpMethod {
VOLUME_DISPLAY_INTERP_LINEAR = 0,
VOLUME_DISPLAY_INTERP_CUBIC = 1,
VOLUME_DISPLAY_INTERP_CLOSEST = 2,
} VolumeDisplayInterpMethod;
-/* VolumeDisplay.axis_slice_method */
+/** #VolumeDisplay.axis_slice_method */
typedef enum AxisAlignedSlicingMethod {
VOLUME_AXIS_SLICE_FULL = 0,
VOLUME_AXIS_SLICE_SINGLE = 1,
} AxisAlignedSlicingMethod;
-/* VolumeDisplay.slice_axis */
+/** #VolumeDisplay.slice_axis */
typedef enum SliceAxis {
VOLUME_SLICE_AXIS_AUTO = 0,
VOLUME_SLICE_AXIS_X = 1,
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index a9016dd4edd..d0e4184d2a5 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -33,7 +33,8 @@
extern "C" {
#endif
-/* defined here: */
+/* Defined here: */
+
struct wmWindow;
struct wmWindowManager;
@@ -45,7 +46,8 @@ struct wmMsgBus;
struct wmOperator;
struct wmOperatorType;
-/* forwards */
+/* Forward declarations: */
+
struct PointerRNA;
struct Report;
struct ReportList;
@@ -58,8 +60,8 @@ struct wmTimer;
#define OP_MAX_TYPENAME 64
#define KMAP_MAX_NAME 64
-/* keep in sync with 'rna_enum_wm_report_items' in wm_rna.c */
-typedef enum ReportType {
+/** Keep in sync with 'rna_enum_wm_report_items' in `wm_rna.c`. */
+typedef enum eReportType {
RPT_DEBUG = (1 << 0),
RPT_INFO = (1 << 1),
RPT_OPERATOR = (1 << 2),
@@ -69,7 +71,7 @@ typedef enum ReportType {
RPT_ERROR_INVALID_INPUT = (1 << 6),
RPT_ERROR_INVALID_CONTEXT = (1 << 7),
RPT_ERROR_OUT_OF_MEMORY = (1 << 8),
-} ReportType;
+} eReportType;
#define RPT_DEBUG_ALL (RPT_DEBUG)
#define RPT_INFO_ALL (RPT_INFO)
@@ -91,7 +93,7 @@ enum ReportListFlags {
#
typedef struct Report {
struct Report *next, *prev;
- /** ReportType. */
+ /** eReportType. */
short type;
short flag;
/** `strlen(message)`, saves some time calculating the word wrap. */
@@ -100,12 +102,14 @@ typedef struct Report {
const char *message;
} Report;
-/* saved in the wm, don't remove */
+/**
+ * \note Saved in the wm, don't remove.
+ */
typedef struct ReportList {
ListBase list;
- /** ReportType. */
+ /** eReportType. */
int printlevel;
- /** ReportType. */
+ /** eReportType. */
int storelevel;
int flag;
char _pad[4];
@@ -133,12 +137,19 @@ typedef struct wmXrData {
/* reports need to be before wmWindowManager */
-/* windowmanager is saved, tag WMAN */
+/** Window-manager is saved, tag WMAN. */
typedef struct wmWindowManager {
ID id;
/** Separate active from drawable. */
- struct wmWindow *windrawable, *winactive;
+ struct wmWindow *windrawable;
+ /**
+ * \note `CTX_wm_window(C)` is usually preferred.
+ * Avoid relying on this where possible as this may become NULL during when handling
+ * events that close or replace windows (opening a file for e.g.).
+ * While this happens rarely in practice, it can cause difficult to reproduce bugs.
+ */
+ struct wmWindow *winactive;
ListBase windows;
/** Set on file read. */
@@ -197,13 +208,13 @@ typedef struct wmWindowManager {
//#endif
} wmWindowManager;
-/* wmWindowManager.initialized */
+/** #wmWindowManager.initialized */
enum {
WM_WINDOW_IS_INIT = (1 << 0),
WM_KEYCONFIG_IS_INIT = (1 << 1),
};
-/* wmWindowManager.outliner_sync_select_dirty */
+/** #wmWindowManager.outliner_sync_select_dirty */
enum {
WM_OUTLINER_SYNC_SELECT_FROM_OBJECT = (1 << 0),
WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE = (1 << 1),
@@ -224,7 +235,9 @@ enum {
# endif
#endif
-/* the saveable part, rest of data is local in ghostwinlay */
+/**
+ * The saveable part, the rest of the data is local in GHOST.
+ */
typedef struct wmWindow {
struct wmWindow *next, *prev;
@@ -345,7 +358,9 @@ typedef struct wmOperatorTypeMacro {
struct PointerRNA *ptr;
} wmOperatorTypeMacro;
-/* Partial copy of the event, for matching by event handler. */
+/**
+ * Partial copy of the event, for matching by event handler.
+ */
typedef struct wmKeyMapItem {
struct wmKeyMapItem *next, *prev;
@@ -429,7 +444,9 @@ enum {
KMI_TYPE_NDOF = 5,
};
-/* stored in WM, the actively used keymaps */
+/**
+ * Stored in WM, the actively used key-maps.
+ */
typedef struct wmKeyMap {
struct wmKeyMap *next, *prev;
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
index a0856588a58..95530c7b0f7 100644
--- a/source/blender/makesdna/DNA_workspace_types.h
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -60,7 +60,9 @@ typedef struct bToolRef_Runtime {
int flag;
} bToolRef_Runtime;
-/* Stored per mode. */
+/**
+ * \note Stored per mode.
+ */
typedef struct bToolRef {
struct bToolRef *next, *prev;
char idname[64];
diff --git a/source/blender/makesdna/DNA_xr_types.h b/source/blender/makesdna/DNA_xr_types.h
index a9d427777f7..f7da912f299 100644
--- a/source/blender/makesdna/DNA_xr_types.h
+++ b/source/blender/makesdna/DNA_xr_types.h
@@ -32,8 +32,8 @@ typedef struct XrSessionSettings {
/** Shading settings, struct shared with 3D-View so settings are the same. */
struct View3DShading shading;
- char _pad[7];
-
+ float base_scale;
+ char _pad[3];
char base_pose_type; /* #eXRSessionBasePoseType */
/** Object to take the location and rotation as base position from. */
Object *base_pose_object;
@@ -42,7 +42,9 @@ typedef struct XrSessionSettings {
/** View3D draw flags (V3D_OFSDRAW_NONE, V3D_OFSDRAW_SHOW_ANNOTATION, ...). */
char draw_flags;
- char _pad2[3];
+ /** Draw style for controller visualization. */
+ char controller_draw_style;
+ char _pad2[2];
/** Clipping distance. */
float clip_start, clip_end;
@@ -61,6 +63,13 @@ typedef enum eXRSessionBasePoseType {
XR_BASE_POSE_CUSTOM = 2,
} eXRSessionBasePoseType;
+typedef enum eXrSessionControllerDrawStyle {
+ XR_CONTROLLER_DRAW_DARK = 0,
+ XR_CONTROLLER_DRAW_LIGHT = 1,
+ XR_CONTROLLER_DRAW_DARK_RAY = 2,
+ XR_CONTROLLER_DRAW_LIGHT_RAY = 3,
+} eXrSessionControllerDrawStyle;
+
/** XR action type. Enum values match those in GHOST_XrActionType enum for consistency. */
typedef enum eXrActionType {
XR_BOOLEAN_INPUT = 1,
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index db34cf83fa9..a3c54e91780 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -159,6 +159,7 @@ set(SRC
../DNA_pointcloud_defaults.h
../DNA_scene_defaults.h
../DNA_simulation_defaults.h
+ ../DNA_space_defaults.h
../DNA_speaker_defaults.h
../DNA_texture_defaults.h
../DNA_vec_defaults.h
diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c
index 2dbbb35c3ca..5bc5de7a20b 100644
--- a/source/blender/makesdna/intern/dna_defaults.c
+++ b/source/blender/makesdna/intern/dna_defaults.c
@@ -103,6 +103,7 @@
#include "DNA_light_types.h"
#include "DNA_lightprobe_types.h"
#include "DNA_linestyle_types.h"
+#include "DNA_mask_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
@@ -144,6 +145,7 @@
#include "DNA_pointcloud_defaults.h"
#include "DNA_scene_defaults.h"
#include "DNA_simulation_defaults.h"
+#include "DNA_space_defaults.h"
#include "DNA_speaker_defaults.h"
#include "DNA_texture_defaults.h"
#include "DNA_volume_defaults.h"
@@ -208,6 +210,8 @@ SDNA_DEFAULT_DECL_STRUCT(MetaBall);
/* DNA_movieclip_defaults.h */
SDNA_DEFAULT_DECL_STRUCT(MovieClip);
+SDNA_DEFAULT_DECL_STRUCT(MovieClipUser);
+SDNA_DEFAULT_DECL_STRUCT(MovieClipScopes);
/* DNA_object_defaults.h */
SDNA_DEFAULT_DECL_STRUCT(Object);
@@ -225,6 +229,9 @@ SDNA_DEFAULT_DECL_STRUCT(ToolSettings);
/* DNA_simulation_defaults.h */
SDNA_DEFAULT_DECL_STRUCT(Simulation);
+/* DNA_space_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(SpaceClip);
+
/* DNA_speaker_defaults.h */
SDNA_DEFAULT_DECL_STRUCT(Speaker);
@@ -324,6 +331,7 @@ SDNA_DEFAULT_DECL_STRUCT(LineartGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(LengthGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(DashGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(DashGpencilModifierSegment);
+SDNA_DEFAULT_DECL_STRUCT(ShrinkwrapGpencilModifierData);
#undef SDNA_DEFAULT_DECL_STRUCT
@@ -405,11 +413,18 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
/* DNA_mesh_defaults.h */
SDNA_DEFAULT_DECL(Mesh),
+ /* DNA_space_defaults.h */
+ SDNA_DEFAULT_DECL(SpaceClip),
+ SDNA_DEFAULT_DECL_EX(MaskSpaceInfo, SpaceClip.mask_info),
+
/* DNA_meta_defaults.h */
SDNA_DEFAULT_DECL(MetaBall),
/* DNA_movieclip_defaults.h */
SDNA_DEFAULT_DECL(MovieClip),
+ SDNA_DEFAULT_DECL(MovieClipUser),
+ SDNA_DEFAULT_DECL(MovieClipScopes),
+ SDNA_DEFAULT_DECL_EX(MovieTrackingMarker, MovieClipScopes.undist_marker),
/* DNA_object_defaults.h */
SDNA_DEFAULT_DECL(Object),
@@ -555,13 +570,16 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
SDNA_DEFAULT_DECL(LengthGpencilModifierData),
SDNA_DEFAULT_DECL(DashGpencilModifierData),
SDNA_DEFAULT_DECL(DashGpencilModifierSegment),
+ SDNA_DEFAULT_DECL(ShrinkwrapGpencilModifierData),
};
#undef SDNA_DEFAULT_DECL
#undef SDNA_DEFAULT_DECL_EX
-char *_DNA_struct_default_alloc_impl(const char *data_src, size_t size, const char *alloc_str)
+uint8_t *_DNA_struct_default_alloc_impl(const uint8_t *data_src,
+ size_t size,
+ const char *alloc_str)
{
- char *data_dst = MEM_mallocN(size, alloc_str);
+ uint8_t *data_dst = MEM_mallocN(size, alloc_str);
memcpy(data_dst, data_src, size);
return data_dst;
}
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 24d0d39292e..6322cb459dd 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -177,13 +177,6 @@ static bool ispointer(const char *name)
return (name[0] == '*' || (name[0] == '(' && name[1] == '*'));
}
-/**
- * Returns the size of struct fields of the specified type and name.
- *
- * \param type: Index into sdna->types/types_size
- * \param name: Index into sdna->names,
- * needed to extract possible pointer/array information.
- */
int DNA_elem_size_nr(const SDNA *sdna, short type, short name)
{
const char *cp = sdna->names[name];
@@ -265,9 +258,6 @@ static int dna_struct_find_nr_ex_impl(
return -1;
}
-/**
- * Returns the index of the struct info for the struct with the specified name.
- */
int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last)
{
return dna_struct_find_nr_ex_impl(
@@ -284,7 +274,6 @@ int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index
index_last);
}
-/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */
int DNA_struct_alias_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last)
{
#ifdef WITH_DNA_GHASH
@@ -310,7 +299,6 @@ int DNA_struct_find_nr(const SDNA *sdna, const char *str)
return DNA_struct_find_nr_ex(sdna, str, &index_last_dummy);
}
-/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */
int DNA_struct_alias_find_nr(const SDNA *sdna, const char *str)
{
unsigned int index_last_dummy = UINT_MAX;
@@ -525,7 +513,7 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error
sdna->pointer_size = sdna->types_size[struct_info->type] / 2;
- if (struct_info->members_len != 2 || (sdna->pointer_size != 4 && sdna->pointer_size != 8)) {
+ if (struct_info->members_len != 2 || (!ELEM(sdna->pointer_size, 4, 8))) {
*r_error_message = "ListBase struct error! Needs it to calculate pointerize.";
/* well, at least sizeof(ListBase) is error proof! (ton) */
return false;
@@ -544,9 +532,6 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error
return true;
}
-/**
- * Constructs and returns a decoded SDNA structure from the given encoded SDNA data block.
- */
SDNA *DNA_sdna_from_data(const void *data,
const int data_len,
bool do_endian_swap,
@@ -691,10 +676,6 @@ static void set_compare_flags_for_struct(const SDNA *oldsdna,
compare_flags[old_struct_index] = SDNA_CMP_EQUAL;
}
-/**
- * Constructs and returns an array of byte flags with one element for each struct in oldsdna,
- * indicating how it compares to newsdna.
- */
const char *DNA_struct_get_compareflags(const SDNA *oldsdna, const SDNA *newsdna)
{
if (oldsdna->structs_len == 0) {
@@ -1018,13 +999,6 @@ static int get_member_size_in_bytes(const SDNA *sdna, const SDNA_StructMember *m
return type_size * array_length;
}
-/**
- * Does endian swapping on the fields of a struct value.
- *
- * \param sdna: SDNA of the struct_nr belongs to
- * \param struct_nr: Index of struct info within sdna
- * \param data: Struct data that is to be converted
- */
void DNA_struct_switch_endian(const SDNA *sdna, int struct_nr, char *data)
{
if (struct_nr == -1) {
@@ -1153,7 +1127,7 @@ static void reconstruct_structs(const DNA_ReconstructInfo *reconstruct_info,
*
* \param reconstruct_info: Preprocessed reconstruct information generated by
* #DNA_reconstruct_info_create.
- * \param new_struct_nr: Index in newsdna->structs of the struct that is being reconstructed.
+ * \param new_struct_nr: Index in `newsdna->structs` of the struct that is being reconstructed.
* \param old_block: Memory buffer containing the old struct.
* \param new_block: Where to put converted struct contents.
*/
@@ -1230,13 +1204,6 @@ static void reconstruct_structs(const DNA_ReconstructInfo *reconstruct_info,
}
}
-/**
- * \param reconstruct_info: Information preprocessed by #DNA_reconstruct_info_create.
- * \param old_struct_nr: Index of struct info within oldsdna.
- * \param blocks: The number of array elements.
- * \param old_blocks: Array of struct data.
- * \return An allocated reconstructed struct.
- */
void *DNA_struct_reconstruct(const DNA_ReconstructInfo *reconstruct_info,
int old_struct_nr,
int blocks,
@@ -1534,10 +1501,6 @@ static int compress_reconstruct_steps(ReconstructStep *steps, const int old_step
return new_step_count;
}
-/**
- * Pre-process information about how structs in \a newsdna can be reconstructed from structs in
- * \a oldsdna. This information is then used to speedup #DNA_struct_reconstruct.
- */
DNA_ReconstructInfo *DNA_reconstruct_info_create(const SDNA *oldsdna,
const SDNA *newsdna,
const char *compare_flags)
@@ -1546,9 +1509,9 @@ DNA_ReconstructInfo *DNA_reconstruct_info_create(const SDNA *oldsdna,
reconstruct_info->oldsdna = oldsdna;
reconstruct_info->newsdna = newsdna;
reconstruct_info->compare_flags = compare_flags;
- reconstruct_info->step_counts = MEM_malloc_arrayN(sizeof(int), newsdna->structs_len, __func__);
+ reconstruct_info->step_counts = MEM_malloc_arrayN(newsdna->structs_len, sizeof(int), __func__);
reconstruct_info->steps = MEM_malloc_arrayN(
- sizeof(ReconstructStep *), newsdna->structs_len, __func__);
+ newsdna->structs_len, sizeof(ReconstructStep *), __func__);
/* Generate reconstruct steps for all structs. */
for (int new_struct_nr = 0; new_struct_nr < newsdna->structs_len; new_struct_nr++) {
@@ -1597,10 +1560,6 @@ void DNA_reconstruct_info_free(DNA_ReconstructInfo *reconstruct_info)
MEM_freeN(reconstruct_info);
}
-/**
- * Returns the offset of the field with the specified name and type within the specified
- * struct type in #SDNA, -1 on failure.
- */
int DNA_elem_offset(SDNA *sdna, const char *stype, const char *vartype, const char *name)
{
const int SDNAnr = DNA_struct_find_nr(sdna, stype);
@@ -1632,7 +1591,6 @@ bool DNA_struct_elem_find(const SDNA *sdna,
return false;
}
-/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */
bool DNA_struct_alias_elem_find(const SDNA *sdna,
const char *stype,
const char *vartype,
@@ -1651,9 +1609,6 @@ bool DNA_struct_alias_elem_find(const SDNA *sdna,
return false;
}
-/**
- * Returns the size in bytes of a primitive type.
- */
int DNA_elem_type_size(const eSDNA_Type elem_nr)
{
/* should contain all enum types */
@@ -1696,9 +1651,6 @@ static bool DNA_sdna_patch_struct_nr(SDNA *sdna,
sdna->types[struct_info->type] = struct_name_new;
return true;
}
-/**
- * Rename a struct
- */
bool DNA_sdna_patch_struct(SDNA *sdna, const char *struct_name_old, const char *struct_name_new)
{
const int struct_name_old_nr = DNA_struct_find_nr(sdna, struct_name_old);
@@ -1756,11 +1708,6 @@ static bool DNA_sdna_patch_struct_member_nr(SDNA *sdna,
}
return false;
}
-/**
- * Replace \a elem_old with \a elem_new for struct \a struct_name
- * handles search & replace, maintaining surrounding non-identifier characters
- * such as pointer & array size.
- */
bool DNA_sdna_patch_struct_member(SDNA *sdna,
const char *struct_name,
const char *elem_old,
@@ -1800,7 +1747,7 @@ static void sdna_expand_names(SDNA *sdna)
int names_expand_index = 0;
for (int struct_nr = 0; struct_nr < sdna->structs_len; struct_nr++) {
- /* We can't edit this memory 'sdna->structs' points to (readonly datatoc file). */
+ /* We can't edit this memory 'sdna->structs' points to (read-only `datatoc` file). */
const SDNA_Struct *struct_old = sdna->structs[struct_nr];
const int array_size = sizeof(short) * 2 + sizeof(SDNA_StructMember) * struct_old->members_len;
@@ -1909,10 +1856,6 @@ void DNA_sdna_alias_data_ensure(SDNA *sdna)
BLI_ghash_free(elem_map_alias_from_static, MEM_freeN, NULL);
}
-/**
- * Separated from #DNA_sdna_alias_data_ensure because it's not needed
- * unless we want to lookup aliased struct names (#DNA_struct_alias_find_nr and friends).
- */
void DNA_sdna_alias_data_ensure_structs_map(SDNA *sdna)
{
DNA_sdna_alias_data_ensure(sdna);
diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h
index 2feebbfd4f4..cb8052856a7 100644
--- a/source/blender/makesdna/intern/dna_rename_defs.h
+++ b/source/blender/makesdna/intern/dna_rename_defs.h
@@ -50,7 +50,9 @@
/* No include guard (intentional). */
-/* Match RNA names where possible, keep sorted. */
+/* Match RNA names where possible. */
+
+/* NOTE: Keep sorted! */
DNA_STRUCT_RENAME(Lamp, Light)
DNA_STRUCT_RENAME(SpaceButs, SpaceProperties)
@@ -63,16 +65,24 @@ DNA_STRUCT_RENAME_ELEM(Bone, curveInY, curve_in_z)
DNA_STRUCT_RENAME_ELEM(Bone, curveOutX, curve_out_x)
DNA_STRUCT_RENAME_ELEM(Bone, curveOutY, curve_out_z)
DNA_STRUCT_RENAME_ELEM(Bone, scaleIn, scale_in_x)
-DNA_STRUCT_RENAME_ELEM(Bone, scale_in_y, scale_in_z)
DNA_STRUCT_RENAME_ELEM(Bone, scaleOut, scale_out_x)
+DNA_STRUCT_RENAME_ELEM(Bone, scale_in_y, scale_in_z)
DNA_STRUCT_RENAME_ELEM(Bone, scale_out_y, scale_out_z)
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)
+DNA_STRUCT_RENAME_ELEM(Curve, ext1, extrude)
+DNA_STRUCT_RENAME_ELEM(Curve, ext2, bevel_radius)
+DNA_STRUCT_RENAME_ELEM(Curve, len_wchar, len_char32)
+DNA_STRUCT_RENAME_ELEM(Curve, width, offset)
+DNA_STRUCT_RENAME_ELEM(Editing, over_border, overlay_frame_rect)
+DNA_STRUCT_RENAME_ELEM(Editing, over_cfra, overlay_frame_abs)
+DNA_STRUCT_RENAME_ELEM(Editing, over_flag, overlay_frame_flag)
+DNA_STRUCT_RENAME_ELEM(Editing, over_ofs, overlay_frame_ofs)
+DNA_STRUCT_RENAME_ELEM(FileGlobal, filename, filepath)
DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, cache_frame_pause_guiding, cache_frame_pause_guide)
DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_alpha, guide_alpha)
DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_beta, guide_beta)
@@ -82,16 +92,24 @@ DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_vel_factor, guide_vel_factor
DNA_STRUCT_RENAME_ELEM(FluidEffectorSettings, guiding_mode, guide_mode)
DNA_STRUCT_RENAME_ELEM(Image, name, filepath)
DNA_STRUCT_RENAME_ELEM(Library, name, filepath)
+DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, line_types, edge_types)
+DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_flags, mask_switches)
+DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_mask, material_mask_bits)
DNA_STRUCT_RENAME_ELEM(MaskLayer, restrictflag, visibility_flag)
+DNA_STRUCT_RENAME_ELEM(MaterialLineArt, transparency_mask, material_mask_bits)
DNA_STRUCT_RENAME_ELEM(MovieClip, name, filepath)
DNA_STRUCT_RENAME_ELEM(Object, col, color)
DNA_STRUCT_RENAME_ELEM(Object, dup_group, instance_collection)
DNA_STRUCT_RENAME_ELEM(Object, dupfacesca, instance_faces_scale)
-DNA_STRUCT_RENAME_ELEM(Object, size, scale)
DNA_STRUCT_RENAME_ELEM(Object, restrictflag, visibility_flag)
+DNA_STRUCT_RENAME_ELEM(Object, size, scale)
DNA_STRUCT_RENAME_ELEM(ParticleSettings, dup_group, instance_collection)
DNA_STRUCT_RENAME_ELEM(ParticleSettings, dup_ob, instance_object)
DNA_STRUCT_RENAME_ELEM(ParticleSettings, dupliweights, instance_weights)
+DNA_STRUCT_RENAME_ELEM(RigidBodyWorld, steps_per_second, substeps_per_frame)
+DNA_STRUCT_RENAME_ELEM(RenderData, bake_filter, bake_margin)
+DNA_STRUCT_RENAME_ELEM(SpaceSeq, overlay_type, overlay_frame_type)
+DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numverts, num_bind_verts)
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)
@@ -109,8 +127,8 @@ DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveInY, curve_in_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveOutX, curve_out_x)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveOutY, curve_out_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, scaleIn, scale_in_x)
-DNA_STRUCT_RENAME_ELEM(bPoseChannel, scale_in_y, scale_in_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, scaleOut, scale_out_x)
+DNA_STRUCT_RENAME_ELEM(bPoseChannel, scale_in_y, scale_in_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, scale_out_y, scale_out_z)
DNA_STRUCT_RENAME_ELEM(bSameVolumeConstraint, flag, free_axis)
DNA_STRUCT_RENAME_ELEM(bSound, name, filepath)
@@ -131,12 +149,8 @@ DNA_STRUCT_RENAME_ELEM(bTheme, tstatusbar, space_statusbar)
DNA_STRUCT_RENAME_ELEM(bTheme, ttopbar, space_topbar)
DNA_STRUCT_RENAME_ELEM(bTheme, tuserpref, space_preferences)
DNA_STRUCT_RENAME_ELEM(bTheme, tv3d, space_view3d)
-DNA_STRUCT_RENAME_ELEM(RigidBodyWorld, steps_per_second, substeps_per_frame)
/* Write with a different name, old Blender versions crash loading files with non-NULL
* global_areas. See D9442. */
DNA_STRUCT_RENAME_ELEM(wmWindow, global_area_map, global_areas)
-DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, line_types, edge_types)
-DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_flags, mask_switches)
-DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_mask, material_mask_bits)
-DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numverts, num_bind_verts)
-DNA_STRUCT_RENAME_ELEM(MaterialLineArt, transparency_mask, material_mask_bits)
+
+/* NOTE: Keep sorted! */
diff --git a/source/blender/makesdna/intern/dna_utils.c b/source/blender/makesdna/intern/dna_utils.c
index f050934b5b3..b2e2e263ea3 100644
--- a/source/blender/makesdna/intern/dna_utils.c
+++ b/source/blender/makesdna/intern/dna_utils.c
@@ -39,10 +39,6 @@
/** \name Struct Member Evaluation
* \{ */
-/**
- * Parses the `[n1][n2]...` on the end of an array name
- * and returns the number of array elements `n1 * n2 ...`.
- */
int DNA_elem_array_size(const char *str)
{
int result = 1;
@@ -106,9 +102,6 @@ uint DNA_elem_id_offset_end(const char *elem_full)
return elem_full_offset;
}
-/**
- * \a elem_dst must be at least the size of \a elem_src.
- */
uint DNA_elem_id_strip_copy(char *elem_dst, const char *elem_src)
{
const uint elem_src_offset = DNA_elem_id_offset_start(elem_src);
@@ -129,10 +122,6 @@ uint DNA_elem_id_strip(char *elem)
return elem_trim_len;
}
-/**
- * Check if 'var' matches '*var[3]' for eg,
- * return true if it does, with start/end offsets.
- */
bool DNA_elem_id_match(const char *elem_search,
const int elem_search_len,
const char *elem_full,
@@ -151,9 +140,6 @@ bool DNA_elem_id_match(const char *elem_search,
return false;
}
-/**
- * Return a renamed dna name, allocated from \a mem_arena.
- */
char *DNA_elem_id_rename(struct MemArena *mem_arena,
const char *elem_src,
const int elem_src_len,
@@ -297,19 +283,15 @@ void DNA_alias_maps(enum eDNA_RenameDir version_dir, GHash **r_struct_map, GHash
/** \name Struct Name Legacy Hack
* \{ */
-/**
- * DNA Compatibility Hack
- * ======================
- *
- * Only keep this for compatibility: **NEVER ADD NEW STRINGS HERE**.
- *
- * The renaming here isn't complete, references to the old struct names
- * are still included in DNA, now fixing these struct names properly
- * breaks forward compatibility. Leave these as-is, but don't add to them!
- * See D4342#98780
- */
const char *DNA_struct_rename_legacy_hack_static_from_alias(const char *name)
{
+ /* Only keep this for compatibility: *NEVER ADD NEW STRINGS HERE*.
+ *
+ * The renaming here isn't complete, references to the old struct names
+ * are still included in DNA, now fixing these struct names properly
+ * breaks forward compatibility. Leave these as-is, but don't add to them!
+ * See D4342#98780. */
+
/* 'bScreen' replaces the old IrisGL 'Screen' struct */
if (STREQ("bScreen", name)) {
return "Screen";
diff --git a/source/blender/makesdna/intern/dna_utils.h b/source/blender/makesdna/intern/dna_utils.h
index f711056c575..e161e317c42 100644
--- a/source/blender/makesdna/intern/dna_utils.h
+++ b/source/blender/makesdna/intern/dna_utils.h
@@ -27,26 +27,42 @@ extern "C" {
struct GHash;
struct MemArena;
+/**
+ * Parses the `[n1][n2]...` on the end of an array name
+ * and returns the number of array elements `n1 * n2 ...`.
+ */
int DNA_elem_array_size(const char *str);
uint DNA_elem_id_offset_start(const char *elem_full);
uint DNA_elem_id_offset_end(const char *elem_full);
+/**
+ * \a elem_dst must be at least the size of \a elem_src.
+ */
uint DNA_elem_id_strip_copy(char *elem_dst, const char *elem_src);
uint DNA_elem_id_strip(char *elem);
+/**
+ * Check if 'var' matches '*var[3]' for eg,
+ * return true if it does, with start/end offsets.
+ */
bool DNA_elem_id_match(const char *elem_search,
- const int elem_search_len,
+ int elem_search_len,
const char *elem_full,
uint *r_elem_full_offset);
+/**
+ * Return a renamed dna name, allocated from \a mem_arena.
+ */
char *DNA_elem_id_rename(struct MemArena *mem_arena,
const char *elem_src,
- const int elem_src_len,
+ int elem_src_len,
const char *elem_dst,
- const int elem_dst_len,
+ int elem_dst_len,
const char *elem_src_full,
- const int elem_src_full_len,
- const uint elem_src_full_offset_len);
+ int elem_src_full_len,
+ uint elem_src_full_offset_len);
-/* When requesting version info, support both directions. */
+/**
+ * When requesting version info, support both directions.
+ */
enum eDNA_RenameDir {
DNA_RENAME_STATIC_FROM_ALIAS = -1,
DNA_RENAME_ALIAS_FROM_STATIC = 1,
@@ -56,6 +72,9 @@ void DNA_alias_maps(enum eDNA_RenameDir version_dir,
struct GHash **r_elem_map);
const char *DNA_struct_rename_legacy_hack_alias_from_static(const char *name);
+/**
+ * DNA Compatibility Hack.
+ */
const char *DNA_struct_rename_legacy_hack_static_from_alias(const char *name);
#ifdef __cplusplus
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 9957808b63d..114c0b40407 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -23,10 +23,8 @@
* \brief Struct muncher for making SDNA.
*
* \section aboutmakesdnac About makesdna tool
- * Originally by Ton, some mods by Frank, and some cleaning and
- * extension by Nzc.
*
- * Makesdna creates a .c file with a long string of numbers that
+ * `makesdna` creates a .c file with a long string of numbers that
* encode the Blender file format. It is fast, because it is basically
* a binary dump. There are some details to mind when reconstructing
* the file (endianness and byte-alignment).
@@ -36,9 +34,9 @@
* how much memory (on disk or in ram) is needed to store that struct,
* and the offsets for reaching a particular one.
*
- * There is a facility to get verbose output from sdna. Search for
- * \ref debugSDNA. This int can be set to 0 (no output) to some int. Higher
- * numbers give more output.
+ * There is a facility to get verbose output from `sdna`. Search for
+ * \ref debugSDNA. This int can be set to 0 (no output) to some int.
+ * Higher numbers give more output.
*/
#define DNA_DEPRECATED_ALLOW
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index ce53e3390e1..1ade964854d 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -105,6 +105,7 @@ extern StructRNA RNA_BuildModifier;
extern StructRNA RNA_ByteColorAttribute;
extern StructRNA RNA_ByteColorAttributeValue;
extern StructRNA RNA_CacheFile;
+extern StructRNA RNA_CacheFileLayer;
extern StructRNA RNA_Camera;
extern StructRNA RNA_CameraDOFSettings;
extern StructRNA RNA_CastModifier;
@@ -137,6 +138,7 @@ extern StructRNA RNA_CompositorNodeChannelMatte;
extern StructRNA RNA_CompositorNodeChromaMatte;
extern StructRNA RNA_CompositorNodeColorMatte;
extern StructRNA RNA_CompositorNodeColorSpill;
+extern StructRNA RNA_CompositorNodeConvertColorSpace;
extern StructRNA RNA_CompositorNodeCombHSVA;
extern StructRNA RNA_CompositorNodeCombRGBA;
extern StructRNA RNA_CompositorNodeCombYCCA;
@@ -184,6 +186,7 @@ extern StructRNA RNA_CompositorNodeRGBToBW;
extern StructRNA RNA_CompositorNodeRLayers;
extern StructRNA RNA_CompositorNodeRotate;
extern StructRNA RNA_CompositorNodeScale;
+extern StructRNA RNA_CompositorNodeSceneTime;
extern StructRNA RNA_CompositorNodeSepHSVA;
extern StructRNA RNA_CompositorNodeSepRGBA;
extern StructRNA RNA_CompositorNodeSepYCCA;
@@ -558,6 +561,7 @@ extern StructRNA RNA_ShaderFxWave;
extern StructRNA RNA_ShaderNode;
extern StructRNA RNA_ShaderNodeCameraData;
extern StructRNA RNA_ShaderNodeCombineRGB;
+extern StructRNA RNA_ShaderNodeFloatCurve;
extern StructRNA RNA_ShaderNodeGamma;
extern StructRNA RNA_ShaderNodeHueSaturation;
extern StructRNA RNA_ShaderNodeInvert;
@@ -776,7 +780,7 @@ bool RNA_pointer_is_null(const PointerRNA *ptr);
bool RNA_path_resolved_create(PointerRNA *ptr,
struct PropertyRNA *prop,
- const int prop_index,
+ int prop_index,
PathResolvedRNA *r_anim_rna);
void RNA_blender_rna_pointer_create(PointerRNA *r_ptr);
@@ -800,6 +804,11 @@ PropertyRNA *RNA_struct_name_property(const StructRNA *type);
const EnumPropertyItem *RNA_struct_property_tag_defines(const StructRNA *type);
PropertyRNA *RNA_struct_iterator_property(StructRNA *type);
StructRNA *RNA_struct_base(StructRNA *type);
+/**
+ * Use to find the sub-type directly below a base-type.
+ *
+ * So if type were `RNA_SpotLight`, `RNA_struct_base_of(type, &RNA_ID)` would return `&RNA_Light`.
+ */
const StructRNA *RNA_struct_base_child_of(const StructRNA *type, const StructRNA *parent_type);
bool RNA_struct_is_ID(const StructRNA *type);
@@ -822,16 +831,32 @@ struct IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create);
bool RNA_struct_idprops_check(StructRNA *srna);
bool RNA_struct_idprops_register_check(const StructRNA *type);
bool RNA_struct_idprops_datablock_allowed(const StructRNA *type);
+/**
+ * Whether given type implies datablock usage by IDProperties.
+ * This is used to prevent classes allowed to have IDProperties,
+ * but not datablock ones, to indirectly use some
+ * (e.g. by assigning an IDP_GROUP containing some IDP_ID pointers...).
+ */
bool RNA_struct_idprops_contains_datablock(const StructRNA *type);
+/**
+ * Remove an id-property.
+ */
bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier);
PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier);
bool RNA_struct_contains_property(PointerRNA *ptr, PropertyRNA *prop_test);
unsigned int RNA_struct_count_properties(StructRNA *srna);
-/* lower level functions for access to type properties */
+/**
+ * Low level direct access to type->properties,
+ * note this ignores parent classes so should be used with care.
+ */
const struct ListBase *RNA_struct_type_properties(StructRNA *srna);
PropertyRNA *RNA_struct_type_find_property_no_base(StructRNA *srna, const char *identifier);
+/**
+ * \note #RNA_struct_find_property is a higher level alternative to this function
+ * which takes a #PointerRNA instead of a #StructRNA.
+ */
PropertyRNA *RNA_struct_type_find_property(StructRNA *srna, const char *identifier);
FunctionRNA *RNA_struct_find_function(StructRNA *srna, const char *identifier);
@@ -839,6 +864,9 @@ const struct ListBase *RNA_struct_type_functions(StructRNA *srna);
char *RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, int *r_len);
+/**
+ * Use when registering structs with the #STRUCT_PUBLIC_NAMESPACE flag.
+ */
bool RNA_struct_available_or_report(struct ReportList *reports, const char *identifier);
bool RNA_struct_bl_idname_ok_or_report(struct ReportList *reports,
const char *identifier,
@@ -860,17 +888,32 @@ PropertyUnit RNA_property_unit(PropertyRNA *prop);
PropertyScaleType RNA_property_ui_scale(PropertyRNA *prop);
int RNA_property_flag(PropertyRNA *prop);
int RNA_property_override_flag(PropertyRNA *prop);
+/**
+ * Get the tags set for \a prop as int bitfield.
+ * \note Doesn't perform any validity check on the set bits. #RNA_def_property_tags does this
+ * in debug builds (to avoid performance issues in non-debug builds), which should be
+ * the only way to set tags. Hence, at this point we assume the tag bitfield to be valid.
+ */
int RNA_property_tags(PropertyRNA *prop);
bool RNA_property_builtin(PropertyRNA *prop);
void *RNA_property_py_data_get(PropertyRNA *prop);
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_array_check(PropertyRNA *prop);
+/**
+ * Return the size of Nth dimension.
+ */
int RNA_property_multi_array_length(PointerRNA *ptr, PropertyRNA *prop, int dimension);
+/**
+ * Used by BPY to make an array from the python object.
+ */
int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[]);
char RNA_property_array_item_char(PropertyRNA *prop, int index);
int RNA_property_array_item_index(PropertyRNA *prop, char name);
+/**
+ * \return the maximum length including the \0 terminator. '0' is used when there is no maximum.
+ */
int RNA_property_string_maxlength(PropertyRNA *prop);
const char *RNA_property_ui_name(const PropertyRNA *prop);
@@ -897,21 +940,23 @@ void RNA_property_float_ui_range(PointerRNA *ptr,
int RNA_property_float_clamp(PointerRNA *ptr, PropertyRNA *prop, float *value);
int RNA_property_int_clamp(PointerRNA *ptr, PropertyRNA *prop, int *value);
-bool RNA_enum_identifier(const EnumPropertyItem *item, const int value, const char **identifier);
-int RNA_enum_bitflag_identifiers(const EnumPropertyItem *item,
- const int value,
- const char **identifier);
-bool RNA_enum_name(const EnumPropertyItem *item, const int value, const char **r_name);
-bool RNA_enum_description(const EnumPropertyItem *item, const int value, const char **description);
-int RNA_enum_from_value(const EnumPropertyItem *item, const int value);
+bool RNA_enum_identifier(const EnumPropertyItem *item, int value, const char **identifier);
+int RNA_enum_bitflag_identifiers(const EnumPropertyItem *item, int value, const char **identifier);
+bool RNA_enum_name(const EnumPropertyItem *item, int value, const char **r_name);
+bool RNA_enum_description(const EnumPropertyItem *item, int value, const char **description);
+int RNA_enum_from_value(const EnumPropertyItem *item, int value);
int RNA_enum_from_identifier(const EnumPropertyItem *item, const char *identifier);
+/**
+ * Take care using this with translated enums,
+ * prefer #RNA_enum_from_identifier where possible.
+ */
int RNA_enum_from_name(const EnumPropertyItem *item, const char *name);
unsigned int RNA_enum_items_count(const EnumPropertyItem *item);
void RNA_property_enum_items_ex(struct bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
- const bool use_static,
+ bool use_static,
const EnumPropertyItem **r_item,
int *r_totitem,
bool *r_free);
@@ -935,58 +980,71 @@ void RNA_property_enum_items_gettexted_all(struct bContext *C,
bool *r_free);
bool RNA_property_enum_value(
struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const char *identifier, int *r_value);
-bool RNA_property_enum_identifier(struct bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- const int value,
- const char **identifier);
+bool RNA_property_enum_identifier(
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int value, const char **identifier);
bool RNA_property_enum_name(
- struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **name);
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int value, const char **name);
bool RNA_property_enum_name_gettexted(
- struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **name);
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int value, const char **name);
-bool RNA_property_enum_item_from_value(struct bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- const int value,
- EnumPropertyItem *r_item);
-bool RNA_property_enum_item_from_value_gettexted(struct bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- const int value,
- EnumPropertyItem *r_item);
-
-int RNA_property_enum_bitflag_identifiers(struct bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- const int value,
- const char **identifier);
+bool RNA_property_enum_item_from_value(
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int value, EnumPropertyItem *r_item);
+bool RNA_property_enum_item_from_value_gettexted(
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int value, EnumPropertyItem *r_item);
+
+int RNA_property_enum_bitflag_identifiers(
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int value, const char **identifier);
StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *value);
bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * Version of #RNA_property_editable that tries to return additional info in \a r_info
+ * that can be exposed in UI.
+ */
bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info);
+/**
+ * Same as RNA_property_editable(), except this checks individual items in an array.
+ */
bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index);
-/* without lib check, only checks the flag */
+/**
+ * Without lib check, only checks the flag.
+ */
bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * \note Does not take into account editable status, this has to be checked separately
+ * (using #RNA_property_editable_flag() usually).
+ */
bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop);
-bool RNA_property_overridable_library_set(PointerRNA *ptr,
- PropertyRNA *prop,
- const bool is_overridable);
+/**
+ * Should only be used for custom properties.
+ */
+bool RNA_property_overridable_library_set(PointerRNA *ptr, PropertyRNA *prop, bool is_overridable);
bool RNA_property_overridden(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_comparable(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * This function is to check if its possible to create a valid path from the ID
+ * its slow so don't call in a loop.
+ */
bool RNA_property_path_from_ID_check(PointerRNA *ptr, PropertyRNA *prop); /* slow, use with care */
void RNA_property_update(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * \param scene: may be NULL.
+ */
void RNA_property_update_main(struct Main *bmain,
struct Scene *scene,
PointerRNA *ptr,
PropertyRNA *prop);
+/**
+ * \note its possible this returns a false positive in the case of #PROP_CONTEXT_UPDATE
+ * but this isn't likely to be a performance problem.
+ */
bool RNA_property_update_check(struct PropertyRNA *prop);
/* Property Data */
@@ -1030,15 +1088,28 @@ char *RNA_property_string_get_alloc(
PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len);
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value);
void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const char *value, int len);
+/**
+ * \return the length without `\0` terminator.
+ */
int RNA_property_string_length(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_string_get_default(PropertyRNA *prop, char *value, int max_len);
char *RNA_property_string_get_default_alloc(
PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len);
+/**
+ * \return the length without `\0` terminator.
+ */
int RNA_property_string_default_length(PointerRNA *ptr, PropertyRNA *prop);
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value);
int RNA_property_enum_get_default(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * Get the value of the item that is \a step items away from \a from_value.
+ *
+ * \param from_value: Item value to start stepping from.
+ * \param step: Absolute value defines step size, sign defines direction.
+ * E.g to get the next item, pass 1, for the previous -1.
+ */
int RNA_property_enum_step(
const struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step);
@@ -1067,9 +1138,12 @@ int RNA_property_collection_lookup_string(PointerRNA *ptr,
PointerRNA *r_ptr);
int RNA_property_collection_lookup_string_index(
PointerRNA *ptr, PropertyRNA *prop, const char *key, PointerRNA *r_ptr, int *r_index);
+/**
+ * Zero return is an assignment error.
+ */
int RNA_property_collection_assign_int(PointerRNA *ptr,
PropertyRNA *prop,
- const int key,
+ int key,
const PointerRNA *assign_ptr);
bool RNA_property_collection_type_get(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *r_ptr);
@@ -1124,31 +1198,99 @@ char *RNA_path_append(
char *RNA_path_back(const char *path);
#endif
-/* path_resolve() variants only ensure that a valid pointer (and optionally property) exist */
+/* RNA_path_resolve() variants only ensure that a valid pointer (and optionally property) exist. */
+
+/**
+ * Resolve the given RNA Path to find the pointer and/or property
+ * indicated by fully resolving the path.
+ *
+ * \warning Unlike \a RNA_path_resolve_property(), that one *will* try to follow RNAPointers,
+ * e.g. the path 'parent' applied to a RNAObject \a ptr will return the object.parent in \a r_ptr,
+ * and a NULL \a r_prop...
+ *
+ * \note Assumes all pointers provided are valid
+ * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
+ */
bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop);
+/**
+ * Resolve the given RNA Path to find the pointer and/or property + array index
+ * indicated by fully resolving the path.
+ *
+ * \note Assumes all pointers provided are valid.
+ * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
+ */
bool RNA_path_resolve_full(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
+/**
+ * A version of #RNA_path_resolve_full doesn't check the value of #PointerRNA.data.
+ *
+ * \note While it's correct to ignore the value of #PointerRNA.data
+ * most callers need to know if the resulting pointer was found and not null.
+ */
bool RNA_path_resolve_full_maybe_null(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
-/* path_resolve_property() variants ensure that pointer + property both exist */
+/* RNA_path_resolve_property() variants ensure that pointer + property both exist. */
+
+/**
+ * Resolve the given RNA Path to find both the pointer AND property
+ * indicated by fully resolving the path.
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax.
+ * \note Assumes all pointers provided are valid
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
bool RNA_path_resolve_property(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop);
+/**
+ * Resolve the given RNA Path to find the pointer AND property (as well as the array index)
+ * indicated by fully resolving the path.
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax.
+ * \note Assumes all pointers provided are valid
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
bool RNA_path_resolve_property_full(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
-/* path_resolve_property_and_item_pointer() variants ensure that pointer + property both exist,
+/* RNA_path_resolve_property_and_item_pointer() variants ensure that pointer + property both exist,
* and resolve last Pointer value if possible (Pointer prop or item of a Collection prop). */
+
+/**
+ * Resolve the given RNA Path to find both the pointer AND property
+ * indicated by fully resolving the path, and get the value of the Pointer property
+ * (or item of the collection).
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax,
+ * it combines both \a RNA_path_resolve and #RNA_path_resolve_property in a single call.
+ * \note Assumes all pointers provided are valid.
+ * \param r_item_ptr: The final Pointer or Collection item value.
+ * You must check for its validity before use!
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop,
PointerRNA *r_item_ptr);
+/**
+ * Resolve the given RNA Path to find both the pointer AND property (as well as the array index)
+ * indicated by fully resolving the path,
+ * and get the value of the Pointer property (or item of the collection).
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax,
+ * it combines both \a RNA_path_resolve_full and
+ * \a RNA_path_resolve_property_full in a single call.
+ * \note Assumes all pointers provided are valid.
+ * \param r_item_ptr: The final Pointer or Collection item value.
+ * You must check for its validity before use!
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
bool RNA_path_resolve_property_and_item_pointer_full(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
@@ -1163,10 +1305,36 @@ struct PropertyElemRNA {
PropertyRNA *prop;
int index;
};
+/**
+ * Resolve the given RNA Path into a linked list of #PropertyElemRNA's.
+ *
+ * To be used when complex operations over path are needed, like e.g. get relative paths,
+ * to avoid too much string operations.
+ *
+ * \return True if there was no error while resolving the path
+ * \note Assumes all pointers provided are valid
+ */
bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements);
+/**
+ * Find the path from the structure referenced by the pointer to the runtime RNA-defined
+ * #IDProperty object.
+ *
+ * \note Does *not* handle pure user-defined IDProperties (a.k.a. custom properties).
+ *
+ * \param ptr: Reference to the object owning the custom property storage.
+ * \param needle: Custom property object to find.
+ * \return Relative path or NULL.
+ */
char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, struct IDProperty *needle);
+/**
+ * Find the actual ID pointer and path from it to the given ID.
+ *
+ * \param id: ID reference to search the global owner for.
+ * \param[out] r_path: Path from the real ID to the initial ID.
+ * \return The ID pointer, or NULL in case of failure.
+ */
struct ID *RNA_find_real_ID_and_path(struct Main *bmain, struct ID *id, const char **r_path);
char *RNA_path_from_ID_to_struct(const PointerRNA *ptr);
@@ -1174,6 +1342,11 @@ char *RNA_path_from_ID_to_struct(const PointerRNA *ptr);
char *RNA_path_from_real_ID_to_struct(struct Main *bmain, PointerRNA *ptr, struct ID **r_real);
char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
+ * \param index: The *flattened* index to use when \a `index_dim > 0`,
+ * this is expanded when used with multi-dimensional arrays.
+ */
char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
PropertyRNA *prop,
int index_dim,
@@ -1186,19 +1359,43 @@ char *RNA_path_from_real_ID_to_property_index(struct Main *bmain,
int index,
struct ID **r_real_id);
+/**
+ * \return the path to given ptr/prop from the closest ancestor of given type,
+ * if any (else return NULL).
+ */
char *RNA_path_resolve_from_type_to_property(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const struct StructRNA *type);
+/**
+ * Get the ID as a python representation, eg:
+ * bpy.data.foo["bar"]
+ */
char *RNA_path_full_ID_py(struct Main *bmain, struct ID *id);
+/**
+ * Get the ID.struct as a python representation, eg:
+ * bpy.data.foo["bar"].some_struct
+ */
char *RNA_path_full_struct_py(struct Main *bmain, struct PointerRNA *ptr);
+/**
+ * Get the ID.struct.property as a python representation, eg:
+ * bpy.data.foo["bar"].some_struct.some_prop[10]
+ */
char *RNA_path_full_property_py_ex(
struct Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback);
char *RNA_path_full_property_py(struct Main *bmain,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
int index);
+/**
+ * Get the struct.property as a python representation, eg:
+ * some_struct.some_prop[10]
+ */
char *RNA_path_struct_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
+/**
+ * Get the struct.property as a python representation, eg:
+ * some_prop[10]
+ */
char *RNA_path_property_py(const struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
/* Quick name based property access
@@ -1313,42 +1510,53 @@ void RNA_collection_clear(PointerRNA *ptr, const char *name);
} \
((void)0)
-/* check if the idproperty exists, for operators */
+/**
+ * Check if the #IDproperty exists, for operators.
+ */
bool RNA_property_is_set_ex(PointerRNA *ptr, PropertyRNA *prop, bool use_ghost);
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_struct_property_is_set_ex(PointerRNA *ptr, const char *identifier, bool use_ghost);
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier);
bool RNA_property_is_idprop(const PropertyRNA *prop);
+/**
+ * \note Mainly for the UI.
+ */
bool RNA_property_is_unlink(PropertyRNA *prop);
void RNA_struct_property_unset(PointerRNA *ptr, const char *identifier);
-/* python compatible string representation of this property, (must be freed!) */
+/**
+ * Python compatible string representation of this property, (must be freed!).
+ */
char *RNA_property_as_string(
struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int index, int max_prop_length);
+/**
+ * String representation of a property, Python compatible but can be used for display too.
+ * \param C: can be NULL.
+ */
char *RNA_pointer_as_string_id(struct bContext *C, PointerRNA *ptr);
char *RNA_pointer_as_string(struct bContext *C,
PointerRNA *ptr,
PropertyRNA *prop_ptr,
PointerRNA *ptr_prop);
+/**
+ * \param C: can be NULL.
+ */
char *RNA_pointer_as_string_keywords_ex(struct bContext *C,
PointerRNA *ptr,
- const bool as_function,
- const bool all_args,
- const bool nested_args,
- const int max_prop_length,
+ bool as_function,
+ bool all_args,
+ bool nested_args,
+ int max_prop_length,
PropertyRNA *iterprop);
char *RNA_pointer_as_string_keywords(struct bContext *C,
PointerRNA *ptr,
- const bool as_function,
- const bool all_args,
- const bool nested_args,
- const int max_prop_length);
-char *RNA_function_as_string_keywords(struct bContext *C,
- FunctionRNA *func,
- const bool as_function,
- const bool all_args,
- const int max_prop_length);
+ bool as_function,
+ bool all_args,
+ bool nested_args,
+ int max_prop_length);
+char *RNA_function_as_string_keywords(
+ struct bContext *C, FunctionRNA *func, bool as_function, bool all_args, int max_prop_length);
/* Function */
@@ -1382,7 +1590,9 @@ void RNA_parameter_get(ParameterList *parms, PropertyRNA *parm, void **value);
void RNA_parameter_get_lookup(ParameterList *parms, const char *identifier, void **value);
void RNA_parameter_set(ParameterList *parms, PropertyRNA *parm, const void *value);
void RNA_parameter_set_lookup(ParameterList *parms, const char *identifier, const void *value);
+
/* Only for PROP_DYNAMIC properties! */
+
int RNA_parameter_dynamic_length_get(ParameterList *parms, PropertyRNA *parm);
int RNA_parameter_dynamic_length_get_data(ParameterList *parms, PropertyRNA *parm, void *data);
void RNA_parameter_dynamic_length_set(ParameterList *parms, PropertyRNA *parm, int length);
@@ -1453,6 +1663,7 @@ StructRNA *ID_code_to_RNA_type(short idcode);
# define RNA_warning(format, ...) _RNA_warning("%s: " format "\n", __FUNCTION__, __VA_ARGS__)
#endif
+/** Use to implement the #RNA_warning macro which includes `__func__` suffix. */
void _RNA_warning(const char *format, ...) ATTR_PRINTF_FORMAT(1, 2);
/* Equals test. */
@@ -1519,15 +1730,29 @@ typedef enum eRNAOverrideStatus {
RNA_OVERRIDE_STATUS_LOCKED = 1 << 3,
} eRNAOverrideStatus;
+/**
+ * Check whether reference and local overridden data match (are the same),
+ * with respect to given restrictive sets of properties.
+ * If requested, will generate needed new property overrides, and/or restore values from reference.
+ *
+ * \param r_report_flags: If given,
+ * will be set with flags matching actions taken by the function on \a ptr_local.
+ *
+ * \return True if _resulting_ \a ptr_local does match \a ptr_reference.
+ */
bool RNA_struct_override_matches(struct Main *bmain,
struct PointerRNA *ptr_local,
struct PointerRNA *ptr_reference,
const char *root_path,
- const size_t root_path_len,
+ size_t root_path_len,
struct IDOverrideLibrary *override,
- const eRNAOverrideMatch flags,
+ eRNAOverrideMatch flags,
eRNAOverrideMatchResult *r_report_flags);
+/**
+ * Store needed second operands into \a storage data-block
+ * for differential override operations.
+ */
bool RNA_struct_override_store(struct Main *bmain,
struct PointerRNA *ptr_local,
struct PointerRNA *ptr_reference,
@@ -1543,12 +1768,16 @@ typedef enum eRNAOverrideApplyFlag {
RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS = 1 << 0,
} eRNAOverrideApplyFlag;
+/**
+ * Apply given \a override operations on \a ptr_dst, using \a ptr_src
+ * (and \a ptr_storage for differential ops) as source.
+ */
void RNA_struct_override_apply(struct Main *bmain,
struct PointerRNA *ptr_dst,
struct PointerRNA *ptr_src,
struct PointerRNA *ptr_storage,
struct IDOverrideLibrary *override,
- const eRNAOverrideApplyFlag flag);
+ eRNAOverrideApplyFlag flag);
struct IDOverrideLibraryProperty *RNA_property_override_property_find(struct Main *bmain,
PointerRNA *ptr,
@@ -1563,23 +1792,23 @@ struct IDOverrideLibraryPropertyOperation *RNA_property_override_property_operat
struct Main *bmain,
PointerRNA *ptr,
PropertyRNA *prop,
- const int index,
- const bool strict,
+ int index,
+ bool strict,
bool *r_strict);
struct IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_get(
struct Main *bmain,
PointerRNA *ptr,
PropertyRNA *prop,
- const short operation,
- const int index,
- const bool strict,
+ short operation,
+ int index,
+ bool strict,
bool *r_strict,
bool *r_created);
eRNAOverrideStatus RNA_property_override_library_status(struct Main *bmainm,
PointerRNA *ptr,
PropertyRNA *prop,
- const int index);
+ int index);
void RNA_struct_state_owner_set(const char *name);
const char *RNA_struct_state_owner_get(void);
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index 01e26cbb41c..ca534316c39 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -49,13 +49,20 @@ void RNA_free(BlenderRNA *brna);
void RNA_define_verify_sdna(bool verify);
void RNA_define_animate_sdna(bool animate);
void RNA_define_fallback_property_update(int noteflag, const char *updatefunc);
-void RNA_define_lib_overridable(const bool make_overridable);
+/**
+ * Properties defined when this is enabled are lib-overridable by default
+ * (except for Pointer ones).
+ */
+void RNA_define_lib_overridable(bool make_overridable);
void RNA_init(void);
void RNA_exit(void);
/* Struct */
+/**
+ * Struct Definition.
+ */
StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRNA *srnafrom);
StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char *from);
void RNA_def_struct_sdna(StructRNA *srna, const char *structname);
@@ -72,6 +79,9 @@ void RNA_def_struct_register_funcs(StructRNA *srna,
const char *unreg,
const char *instance);
void RNA_def_struct_path_func(StructRNA *srna, const char *path);
+/**
+ * Only used in one case when we name the struct for the purpose of useful error messages.
+ */
void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier);
void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *identifier);
void RNA_def_struct_ui_text(StructRNA *srna, const char *name, const char *description);
@@ -176,6 +186,9 @@ PropertyRNA *RNA_def_enum(StructOrFunctionRNA *cont,
int default_value,
const char *ui_name,
const char *ui_description);
+/**
+ * Same as above but sets #PROP_ENUM_FLAG before setting the default value.
+ */
PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont,
const char *identifier,
const EnumPropertyItem *items,
@@ -362,6 +375,13 @@ void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag);
void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag);
void RNA_def_property_override_flag(PropertyRNA *prop, PropertyOverrideFlag flag);
void RNA_def_property_override_clear_flag(PropertyRNA *prop, PropertyOverrideFlag flag);
+/**
+ * Add the property-tags passed as \a tags to \a prop (if valid).
+ *
+ * \note Multiple tags can be set by passing them within \a tags (using bit-flags).
+ * \note Doesn't do any type-checking with the tags defined in the parent #StructRNA
+ * of \a prop. This should be done before (e.g. see #WM_operatortype_prop_tag).
+ */
void RNA_def_property_tags(PropertyRNA *prop, int tags);
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype);
void RNA_def_property_array(PropertyRNA *prop, int length);
@@ -381,11 +401,25 @@ void RNA_def_property_boolean_array_default(PropertyRNA *prop, const bool *array
void RNA_def_property_int_default(PropertyRNA *prop, int value);
void RNA_def_property_int_array_default(PropertyRNA *prop, const int *array);
void RNA_def_property_float_default(PropertyRNA *prop, float value);
+/**
+ * Array must remain valid after this function finishes.
+ */
void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array);
void RNA_def_property_enum_default(PropertyRNA *prop, int value);
void RNA_def_property_string_default(PropertyRNA *prop, const char *value);
void RNA_def_property_ui_text(PropertyRNA *prop, const char *name, const char *description);
+/**
+ * The values hare are a little confusing:
+ *
+ * \param step: Used as the value to increase/decrease when clicking on number buttons,
+ * as well as scaling mouse input for click-dragging number buttons.
+ * For floats this is (step * UI_PRECISION_FLOAT_SCALE), why? - nobody knows.
+ * For ints, whole values are used.
+ *
+ * \param precision: The number of zeros to show
+ * (as a whole number - common range is 1 - 6), see UI_PRECISION_FLOAT_MAX
+ */
void RNA_def_property_ui_range(
PropertyRNA *prop, double min, double max, double step, int precision);
void RNA_def_property_ui_scale_type(PropertyRNA *prop, PropertyScaleType scale_type);
@@ -395,6 +429,11 @@ void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *update
void RNA_def_property_editable_func(PropertyRNA *prop, const char *editable);
void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editable);
+/**
+ * Set custom callbacks for override operations handling.
+ *
+ * \note \a diff callback will also be used by RNA comparison/equality functions.
+ */
void RNA_def_property_override_funcs(PropertyRNA *prop,
const char *diff,
const char *store,
@@ -472,6 +511,9 @@ void RNA_def_property_translation_context(PropertyRNA *prop, const char *context
FunctionRNA *RNA_def_function(StructRNA *srna, const char *identifier, const char *call);
FunctionRNA *RNA_def_function_runtime(StructRNA *srna, const char *identifier, CallFunc call);
+/**
+ * C return value only! multiple RNA returns can be done with #RNA_def_function_output.
+ */
void RNA_def_function_return(FunctionRNA *func, PropertyRNA *ret);
void RNA_def_function_output(FunctionRNA *func, PropertyRNA *ret);
void RNA_def_function_flag(FunctionRNA *func, int flag);
@@ -514,7 +556,8 @@ void RNA_def_property_free_identifier_deferred_finish(StructOrFunctionRNA *cont_
void RNA_def_property_free_pointers_set_py_data_callback(
void (*py_data_clear_fn)(PropertyRNA *prop));
-/* utilities */
+/* Utilities. */
+
const char *RNA_property_typename(PropertyType type);
#define IS_DNATYPE_FLOAT_COMPAT(_str) (strcmp(_str, "float") == 0 || strcmp(_str, "double") == 0)
#define IS_DNATYPE_INT_COMPAT(_str) \
@@ -525,16 +568,19 @@ const char *RNA_property_typename(PropertyType type);
void RNA_identifier_sanitize(char *identifier, int property);
+/* Common arguments for length. */
+
extern const int rna_matrix_dimsize_3x3[];
extern const int rna_matrix_dimsize_4x4[];
extern const int rna_matrix_dimsize_4x2[];
+/* Common arguments for defaults. */
+
extern const float rna_default_axis_angle[4];
extern const float rna_default_quaternion[4];
extern const float rna_default_scale_3d[3];
-/* max size for dynamic defined type descriptors,
- * this value is arbitrary */
+/** Maximum size for dynamic defined type descriptors, this value is arbitrary. */
#define RNA_DYN_DESCR_MAX 240
#ifdef __cplusplus
diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h
index 03d371be1f7..baa9ddba1be 100644
--- a/source/blender/makesrna/RNA_enum_items.h
+++ b/source/blender/makesrna/RNA_enum_items.h
@@ -61,6 +61,8 @@ DEF_ENUM(rna_enum_object_shaderfx_type_items)
DEF_ENUM(rna_enum_modifier_triangulate_quad_method_items)
DEF_ENUM(rna_enum_modifier_triangulate_ngon_method_items)
DEF_ENUM(rna_enum_modifier_shrinkwrap_mode_items)
+DEF_ENUM(rna_enum_shrinkwrap_type_items)
+DEF_ENUM(rna_enum_shrinkwrap_face_cull_items)
DEF_ENUM(rna_enum_image_type_items)
DEF_ENUM(rna_enum_image_color_mode_items)
@@ -70,6 +72,7 @@ DEF_ENUM(rna_enum_image_generated_type_items)
DEF_ENUM(rna_enum_normal_space_items)
DEF_ENUM(rna_enum_normal_swizzle_items)
DEF_ENUM(rna_enum_bake_save_mode_items)
+DEF_ENUM(rna_enum_bake_margin_type_items)
DEF_ENUM(rna_enum_bake_target_items)
DEF_ENUM(rna_enum_views_format_items)
@@ -172,6 +175,7 @@ DEF_ENUM(rna_enum_mapping_type_items)
DEF_ENUM(rna_enum_node_vec_math_items)
DEF_ENUM(rna_enum_node_boolean_math_items)
DEF_ENUM(rna_enum_node_float_compare_items)
+DEF_ENUM(rna_enum_node_compare_operation_items)
DEF_ENUM(rna_enum_node_filter_items)
DEF_ENUM(rna_enum_node_float_to_int_items)
DEF_ENUM(rna_enum_node_map_range_items)
@@ -208,7 +212,11 @@ DEF_ENUM(rna_enum_preference_section_items)
DEF_ENUM(rna_enum_attribute_type_items)
DEF_ENUM(rna_enum_attribute_type_with_auto_items)
DEF_ENUM(rna_enum_attribute_domain_items)
+DEF_ENUM(rna_enum_attribute_domain_without_corner_items)
DEF_ENUM(rna_enum_attribute_domain_with_auto_items)
+DEF_ENUM(rna_enum_geometry_component_type_items)
+
+DEF_ENUM(rna_enum_volume_grid_data_type_items)
DEF_ENUM(rna_enum_collection_color_items)
DEF_ENUM(rna_enum_strip_color_items)
@@ -218,7 +226,7 @@ DEF_ENUM(rna_enum_subdivision_boundary_smooth_items)
DEF_ENUM(rna_enum_transform_orientation_items)
-/* Not available to RNA pre-processing (`makrsrna`).
+/* Not available to RNA pre-processing (`makesrna`).
* Defined in editors for example. */
#ifndef RNA_MAKESRNA
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index d7520834287..fcae1009c8b 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -35,7 +35,9 @@ struct bNodeType;
#define DEF_ENUM(id) extern const EnumPropertyItem id[];
#include "RNA_enum_items.h"
-extern const EnumPropertyItem *rna_enum_attribute_domain_itemf(struct ID *id, bool *r_free);
+extern const EnumPropertyItem *rna_enum_attribute_domain_itemf(struct ID *id,
+ bool include_instances,
+ bool *r_free);
/**
* For ID filters (#FILTER_ID_AC, #FILTER_ID_AR, ...) an int isn't enough. This version allows 64
@@ -83,8 +85,10 @@ const EnumPropertyItem *rna_TransformOrientation_itemf(struct bContext *C,
struct PropertyRNA *prop,
bool *r_free);
-/* Generic functions, return an enum from library data, index is the position
- * in the linked list can add more for different types as needed */
+/**
+ * Generic functions, return an enum from library data, index is the position
+ * in the linked list can add more for different types as needed.
+ */
const EnumPropertyItem *RNA_action_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index d880c892aa9..c5581c01921 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -240,7 +240,7 @@ typedef enum PropertyFlag {
PROP_ID_REFCOUNT = (1 << 6),
/**
- * Disallow assigning a variable to its self, eg an object tracking its self
+ * Disallow assigning a variable to itself, eg an object tracking itself
* only apply this to types that are derived from an ID ().
*/
PROP_ID_SELF_CHECK = (1 << 20),
@@ -265,7 +265,8 @@ typedef enum PropertyFlag {
* This is crucial information for processes that walk the whole data of an ID e.g.
* (like library override).
* Note that all ID pointers are enforced to this by default,
- * this probably will need to be rechecked (see ugly infamous NodeTrees of mat/tex/scene/etc.).
+ * this probably will need to be rechecked
+ * (see ugly infamous node-trees of material/texture/scene/etc.).
*/
PROP_PTR_NO_OWNERSHIP = (1 << 7),
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 7e6d0aea2ee..e3c89af6186 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -70,6 +70,7 @@ set(DEFSRC
rna_packedfile.c
rna_palette.c
rna_particle.c
+ rna_pointcloud.c
rna_pose.c
rna_render.c
rna_rigidbody.c
@@ -100,11 +101,9 @@ set(DEFSRC
if(WITH_EXPERIMENTAL_FEATURES)
add_definitions(-DWITH_SIMULATION_DATABLOCK)
- add_definitions(-DWITH_POINT_CLOUD)
add_definitions(-DWITH_HAIR_NODES)
list(APPEND DEFSRC
rna_hair.c
- rna_pointcloud.c
rna_simulation.c
)
endif()
@@ -203,6 +202,9 @@ set(INC
../../blenloader
${CMAKE_BINARY_DIR}/source/blender/makesdna/intern
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern
)
set(INC_SYS
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 36f19907080..1e9cebbc3ea 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -4401,9 +4401,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_packedfile.c", NULL, RNA_def_packedfile},
{"rna_palette.c", NULL, RNA_def_palette},
{"rna_particle.c", NULL, RNA_def_particle},
-#ifdef WITH_POINT_CLOUD
{"rna_pointcloud.c", NULL, RNA_def_pointcloud},
-#endif
{"rna_pose.c", "rna_pose_api.c", RNA_def_pose},
{"rna_curveprofile.c", NULL, RNA_def_profile},
{"rna_lightprobe.c", NULL, RNA_def_lightprobe},
@@ -4698,6 +4696,19 @@ static const char *cpp_classes =
" inline static int sname##_##identifier##_length_wrap(PointerRNA *ptr) \\\n"
" { return sname##_##identifier##_length(ptr); } \n"
"\n"
+ "#define COLLECTION_PROPERTY_EMPTY_false(sname, identifier) \\\n"
+ " inline static bool sname##_##identifier##_empty_wrap(PointerRNA *ptr) \\\n"
+ " { \\\n"
+ " CollectionPropertyIterator iter; \\\n"
+ " sname##_##identifier##_begin(&iter, ptr); \\\n"
+ " bool empty = !iter.valid; \\\n"
+ " sname##_##identifier##_end(&iter); \\\n"
+ " return empty; \\\n"
+ " } \n"
+ "#define COLLECTION_PROPERTY_EMPTY_true(sname, identifier) \\\n"
+ " inline static bool sname##_##identifier##_empty_wrap(PointerRNA *ptr) \\\n"
+ " { return sname##_##identifier##_length(ptr) == 0; } \n"
+ "\n"
"#define COLLECTION_PROPERTY_LOOKUP_INT_false(sname, identifier) \\\n"
" inline static int sname##_##identifier##_lookup_int_wrap(PointerRNA *ptr, int key, "
"PointerRNA *r_ptr) \\\n"
@@ -4774,11 +4785,13 @@ static const char *cpp_classes =
" typedef CollectionIterator<type, sname##_##identifier##_begin, \\\n"
" sname##_##identifier##_next, sname##_##identifier##_end> identifier##_iterator; \\\n"
" COLLECTION_PROPERTY_LENGTH_##has_length(sname, identifier) \\\n"
+ " COLLECTION_PROPERTY_EMPTY_##has_length(sname, identifier) \\\n"
" COLLECTION_PROPERTY_LOOKUP_INT_##has_lookup_int(sname, identifier) \\\n"
" COLLECTION_PROPERTY_LOOKUP_STRING_##has_lookup_string(sname, identifier) \\\n"
" CollectionRef<sname, type, sname##_##identifier##_begin, \\\n"
" sname##_##identifier##_next, sname##_##identifier##_end, \\\n"
" sname##_##identifier##_length_wrap, \\\n"
+ " sname##_##identifier##_empty_wrap, \\\n"
" sname##_##identifier##_lookup_int_wrap, sname##_##identifier##_lookup_string_wrap, "
"collection_funcs> identifier;\n"
"\n"
@@ -4792,6 +4805,7 @@ static const char *cpp_classes =
"\n"
" bool operator==(const Pointer &other) const { return ptr.data == other.ptr.data; }\n"
" bool operator!=(const Pointer &other) const { return ptr.data != other.ptr.data; }\n"
+ " bool operator<(const Pointer &other) const { return ptr.data < other.ptr.data; }\n"
"\n"
" PointerRNA ptr;\n"
"};\n"
@@ -4843,6 +4857,7 @@ static const char *cpp_classes =
"typedef void (*TNextFunc)(CollectionPropertyIterator *iter);\n"
"typedef void (*TEndFunc)(CollectionPropertyIterator *iter);\n"
"typedef int (*TLengthFunc)(PointerRNA *ptr);\n"
+ "typedef bool (*TEmptyFunc)(PointerRNA *ptr);\n"
"typedef int (*TLookupIntFunc)(PointerRNA *ptr, int key, PointerRNA *r_ptr);\n"
"typedef int (*TLookupStringFunc)(PointerRNA *ptr, const char *key, PointerRNA *r_ptr);\n"
"\n"
@@ -4881,8 +4896,8 @@ static const char *cpp_classes =
"};\n"
"\n"
"template<typename Tp, typename T, TBeginFunc Tbegin, TNextFunc Tnext, TEndFunc Tend,\n"
- " TLengthFunc Tlength, TLookupIntFunc Tlookup_int, TLookupStringFunc Tlookup_string,\n"
- " typename Tcollection_funcs>\n"
+ " TLengthFunc Tlength, TEmptyFunc Tempty, TLookupIntFunc Tlookup_int,\n"
+ " TLookupStringFunc Tlookup_string, typename Tcollection_funcs>\n"
"class CollectionRef : public Tcollection_funcs {\n"
"public:\n"
" CollectionRef(const PointerRNA &p) : Tcollection_funcs(p), ptr(p) {}\n"
@@ -4896,6 +4911,8 @@ static const char *cpp_classes =
""
" int length()\n"
" { return Tlength(&ptr); }\n"
+ " bool empty()\n"
+ " { return Tempty(&ptr); }\n"
" T operator[](int key)\n"
" { PointerRNA r_ptr; Tlookup_int(&ptr, key, &r_ptr); return T(r_ptr); }\n"
" T operator[](const std::string &key)\n"
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 1113ac0eb45..264e89b2c2d 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -131,7 +131,7 @@ static const EnumPropertyItem rna_enum_override_library_property_operation_items
*/
const struct IDFilterEnumPropertyItem rna_enum_id_type_filter_items[] = {
/* Datablocks */
- {FILTER_ID_AC, "filter_action", ICON_ANIM_DATA, "Actions", "Show Action data-blocks"},
+ {FILTER_ID_AC, "filter_action", ICON_ACTION, "Actions", "Show Action data-blocks"},
{FILTER_ID_AR,
"filter_armature",
ICON_ARMATURE_DATA,
@@ -173,7 +173,7 @@ const struct IDFilterEnumPropertyItem rna_enum_id_type_filter_items[] = {
{FILTER_ID_MB, "filter_metaball", ICON_META_DATA, "Metaballs", "Show Metaball data-blocks"},
{FILTER_ID_MC,
"filter_movie_clip",
- ICON_TRACKER_DATA,
+ ICON_TRACKER,
"Movie Clips",
"Show Movie Clip data-blocks"},
{FILTER_ID_ME, "filter_mesh", ICON_MESH_DATA, "Meshes", "Show Mesh data-blocks"},
@@ -225,7 +225,6 @@ const struct IDFilterEnumPropertyItem rna_enum_id_type_filter_items[] = {
# include "BLI_math_base.h"
# include "BKE_anim_data.h"
-# include "BKE_font.h"
# include "BKE_global.h" /* XXX, remove me */
# include "BKE_idprop.h"
# include "BKE_idtype.h"
@@ -234,6 +233,7 @@ const struct IDFilterEnumPropertyItem rna_enum_id_type_filter_items[] = {
# include "BKE_lib_remap.h"
# include "BKE_library.h"
# include "BKE_material.h"
+# include "BKE_vfont.h"
# include "DEG_depsgraph.h"
# include "DEG_depsgraph_build.h"
@@ -423,11 +423,9 @@ short RNA_type_to_ID_code(const StructRNA *type)
if (base_type == &RNA_PaintCurve) {
return ID_PC;
}
-# ifdef WITH_POINT_CLOUD
if (base_type == &RNA_PointCloud) {
return ID_PT;
}
-# endif
if (base_type == &RNA_LightProbe) {
return ID_LP;
}
@@ -533,11 +531,7 @@ StructRNA *ID_code_to_RNA_type(short idcode)
case ID_PC:
return &RNA_PaintCurve;
case ID_PT:
-# ifdef WITH_POINT_CLOUD
return &RNA_PointCloud;
-# else
- return &RNA_ID;
-# endif
case ID_LP:
return &RNA_LightProbe;
case ID_SCE:
@@ -669,14 +663,22 @@ static ID *rna_ID_copy(ID *id, Main *bmain)
return newid;
}
-static void rna_ID_asset_mark(ID *id, bContext *C)
+static void rna_ID_asset_mark(ID *id)
{
- if (ED_asset_mark_id(C, id)) {
+ if (ED_asset_mark_id(id)) {
WM_main_add_notifier(NC_ID | NA_EDITED, NULL);
WM_main_add_notifier(NC_ASSET | NA_ADDED, NULL);
}
}
+static void rna_ID_asset_generate_preview(ID *id, bContext *C)
+{
+ ED_asset_generate_preview(C, id);
+
+ WM_main_add_notifier(NC_ID | NA_EDITED, NULL);
+ WM_main_add_notifier(NC_ASSET | NA_EDITED, NULL);
+}
+
static void rna_ID_asset_clear(ID *id)
{
if (ED_asset_clear_id(id)) {
@@ -1437,7 +1439,7 @@ static void rna_def_ID_properties(BlenderRNA *brna)
RNA_def_struct_refine_func(srna, "rna_PropertyGroup_refine");
/* important so python types can have their name used in list views
- * however this isn't prefect because it overrides how python would set the name
+ * however this isn't perfect because it overrides how python would set the name
* when we only really want this so RNA_def_struct_name_property() is set to something useful */
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_flag(prop, PROP_IDPROPERTY);
@@ -1800,6 +1802,14 @@ static void rna_def_ID_override_library(BlenderRNA *brna)
RNA_def_pointer(
srna, "reference", "ID", "Reference ID", "Linked ID used as reference by this override");
+ prop = RNA_def_boolean(srna,
+ "is_in_hierarchy",
+ true,
+ "Is In Hierarchy",
+ "Whether this library override is defined as part of a library "
+ "hierarchy, or as a single, isolated and autonomous override");
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY);
+
prop = RNA_def_collection(srna,
"properties",
"IDOverrideLibraryProperty",
@@ -1986,13 +1996,17 @@ static void rna_def_ID(BlenderRNA *brna)
func,
"Enable easier reuse of the data-block through the Asset Browser, with the help of "
"customizable metadata (like previews, descriptions and tags)");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT);
func = RNA_def_function(srna, "asset_clear", "rna_ID_asset_clear");
RNA_def_function_ui_description(
func,
"Delete all asset metadata and turn the asset data-block back into a normal data-block");
+ func = RNA_def_function(srna, "asset_generate_preview", "rna_ID_asset_generate_preview");
+ RNA_def_function_ui_description(
+ func, "Generate preview image (might be scheduled in a background thread)");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+
func = RNA_def_function(srna, "override_create", "rna_ID_override_create");
RNA_def_function_ui_description(func,
"Create an overridden local copy of this linked data-block (not "
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index f1980eed811..63eb016b5de 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -438,12 +438,6 @@ static PropertyRNA *arraytypemap[IDP_NUMTYPES] = {
(PropertyRNA *)&rna_PropertyGroupItem_double_array,
};
-/* This function initializes a PropertyRNAOrID with all required info, from a given PropertyRNA
- * and PointerRNA data. It deals properly with the three cases (static RNA, runtime RNA, and
- * IDProperty).
- * WARNING: given `ptr` PointerRNA is assumed to be a valid data one here, calling code is
- * responsible to ensure that.
- */
void rna_property_rna_or_id_get(PropertyRNA *prop,
PointerRNA *ptr,
PropertyRNAOrID *r_prop_rna_or_id)
@@ -515,8 +509,6 @@ void rna_property_rna_or_id_get(PropertyRNA *prop,
}
}
-/* This function only returns an IDProperty,
- * or NULL (in case IDProp could not be found, or prop is a real RNA property). */
IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
{
PropertyRNAOrID prop_rna_or_id;
@@ -527,8 +519,6 @@ IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
return prop_rna_or_id.idprop;
}
-/* This function always return the valid, real data pointer, be it a regular RNA property one,
- * or an IDProperty one. */
PropertyRNA *rna_ensure_property_realdata(PropertyRNA **prop, PointerRNA *ptr)
{
PropertyRNAOrID prop_rna_or_id;
@@ -661,11 +651,6 @@ StructRNA *RNA_struct_base(StructRNA *type)
return type->base;
}
-/**
- * Use to find the subtype directly below a base-type.
- *
- * So if type were `RNA_SpotLIght`, `RNA_struct_base_of(type, &RNA_ID)` would return `&RNA_Light`.
- */
const StructRNA *RNA_struct_base_child_of(const StructRNA *type, const StructRNA *parent_type)
{
while (type) {
@@ -697,18 +682,11 @@ bool RNA_struct_idprops_datablock_allowed(const StructRNA *type)
return (type->flag & (STRUCT_NO_DATABLOCK_IDPROPERTIES | STRUCT_NO_IDPROPERTIES)) == 0;
}
-/**
- * Whether given type implies datablock usage by IDProperties.
- * This is used to prevent classes allowed to have IDProperties,
- * but not datablock ones, to indirectly use some
- * (e.g. by assigning an IDP_GROUP containing some IDP_ID pointers...).
- */
bool RNA_struct_idprops_contains_datablock(const StructRNA *type)
{
return (type->flag & (STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES | STRUCT_ID)) != 0;
}
-/* remove an id-property */
bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier)
{
IDProperty *group = RNA_struct_idprops(ptr, 0);
@@ -825,8 +803,6 @@ unsigned int RNA_struct_count_properties(StructRNA *srna)
return counter;
}
-/* Low level direct access to type->properties,
- * note this ignores parent classes so should be used with care. */
const struct ListBase *RNA_struct_type_properties(StructRNA *srna)
{
return &srna->cont.properties;
@@ -837,10 +813,6 @@ PropertyRNA *RNA_struct_type_find_property_no_base(StructRNA *srna, const char *
return BLI_findstring_ptr(&srna->cont.properties, identifier, offsetof(PropertyRNA, identifier));
}
-/**
- * \note #RNA_struct_find_property is a higher level alternative to this function
- * which takes a #PointerRNA instead of a #StructRNA.
- */
PropertyRNA *RNA_struct_type_find_property(StructRNA *srna, const char *identifier)
{
for (; srna; srna = srna->base) {
@@ -953,9 +925,6 @@ char *RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, i
return NULL;
}
-/**
- * Use when registering structs with the #STRUCT_PUBLIC_NAMESPACE flag.
- */
bool RNA_struct_available_or_report(ReportList *reports, const char *identifier)
{
const StructRNA *srna_exists = RNA_struct_find(identifier);
@@ -1098,12 +1067,6 @@ int RNA_property_flag(PropertyRNA *prop)
return rna_ensure_property(prop)->flag;
}
-/**
- * Get the tags set for \a prop as int bitfield.
- * \note Doesn't perform any validity check on the set bits. #RNA_def_property_tags does this
- * in debug builds (to avoid performance issues in non-debug builds), which should be
- * the only way to set tags. Hence, at this point we assume the tag bitfield to be valid.
- */
int RNA_property_tags(PropertyRNA *prop)
{
return rna_ensure_property(prop)->tags;
@@ -1129,7 +1092,6 @@ bool RNA_property_array_check(PropertyRNA *prop)
return rna_ensure_property_array_check(prop);
}
-/* used by BPY to make an array from the python object */
int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[])
{
PropertyRNA *rprop = rna_ensure_property(prop);
@@ -1141,7 +1103,6 @@ int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[
return rprop->arraydimension;
}
-/* Return the size of Nth dimension. */
int RNA_property_multi_array_length(PointerRNA *ptr, PropertyRNA *prop, int dim)
{
int len[RNA_MAX_ARRAY_DIMENSION];
@@ -1445,8 +1406,6 @@ int RNA_property_int_clamp(PointerRNA *ptr, PropertyRNA *prop, int *value)
return 0;
}
-/* this is the max length including \0 terminator.
- * '0' used when their is no maximum */
int RNA_property_string_maxlength(PropertyRNA *prop)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
@@ -1773,10 +1732,6 @@ int RNA_enum_from_identifier(const EnumPropertyItem *item, const char *identifie
return -1;
}
-/**
- * Take care using this with translated enums,
- * prefer #RNA_enum_from_identifier where possible.
- */
int RNA_enum_from_name(const EnumPropertyItem *item, const char *name)
{
int i = 0;
@@ -1972,10 +1927,6 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop_orig)
(!ID_IS_OVERRIDE_LIBRARY(id) || RNA_property_overridable_get(ptr, prop_orig)))));
}
-/**
- * Version of #RNA_property_editable that tries to return additional info in \a r_info
- * that can be exposed in UI.
- */
bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info)
{
ID *id = ptr->owner_id;
@@ -2026,7 +1977,6 @@ bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop)
return (flag & PROP_EDITABLE) != 0;
}
-/* same as RNA_property_editable(), except this checks individual items in an array */
bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index)
{
ID *id;
@@ -2089,8 +2039,6 @@ bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop)
return false;
}
-/* this function is to check if its possible to create a valid path from the ID
- * its slow so don't call in a loop */
bool RNA_property_path_from_ID_check(PointerRNA *ptr, PropertyRNA *prop)
{
char *path = RNA_path_from_ID_to_property(ptr, prop);
@@ -2193,11 +2141,9 @@ static void rna_property_update(
}
}
-/* must keep in sync with 'rna_property_update'
- * NOTE: its possible this returns a false positive in the case of #PROP_CONTEXT_UPDATE
- * but this isn't likely to be a performance problem. */
bool RNA_property_update_check(PropertyRNA *prop)
{
+ /* NOTE: must keep in sync with #rna_property_update. */
return (prop->magic != RNA_MAGIC || prop->update || prop->noteflag);
}
@@ -2206,7 +2152,6 @@ void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
rna_property_update(C, CTX_data_main(C), CTX_data_scene(C), ptr, prop);
}
-/* NOTE: `scene` pointer may be NULL. */
void RNA_property_update_main(Main *bmain, Scene *scene, PointerRNA *ptr, PropertyRNA *prop)
{
rna_property_update(NULL, bmain, scene, ptr, prop);
@@ -3276,7 +3221,6 @@ char *RNA_property_string_get_alloc(
return buf;
}
-/* this is the length without \0 terminator */
int RNA_property_string_length(PointerRNA *ptr, PropertyRNA *prop)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
@@ -3316,10 +3260,10 @@ void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *val
rna_idproperty_touch(idprop);
}
else if (sprop->set) {
- sprop->set(ptr, value); /* set function needs to clamp its self */
+ sprop->set(ptr, value); /* set function needs to clamp itself */
}
else if (sprop->set_ex) {
- sprop->set_ex(ptr, prop, value); /* set function needs to clamp its self */
+ sprop->set_ex(ptr, prop, value); /* set function needs to clamp itself */
}
else if (prop->flag & PROP_EDITABLE) {
IDProperty *group;
@@ -3348,11 +3292,11 @@ void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const cha
}
else if (sprop->set) {
/* XXX, should take length argument (currently not used). */
- sprop->set(ptr, value); /* set function needs to clamp its self */
+ sprop->set(ptr, value); /* set function needs to clamp itself */
}
else if (sprop->set_ex) {
/* XXX, should take length argument (currently not used). */
- sprop->set_ex(ptr, prop, value); /* set function needs to clamp its self */
+ sprop->set_ex(ptr, prop, value); /* set function needs to clamp itself */
}
else if (prop->flag & PROP_EDITABLE) {
IDProperty *group;
@@ -3416,7 +3360,6 @@ char *RNA_property_string_get_default_alloc(
return buf;
}
-/* this is the length without \0 terminator */
int RNA_property_string_default_length(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
@@ -3497,13 +3440,6 @@ int RNA_property_enum_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
return eprop->defaultvalue;
}
-/**
- * Get the value of the item that is \a step items away from \a from_value.
- *
- * \param from_value: Item value to start stepping from.
- * \param step: Absolute value defines step size, sign defines direction.
- * E.g to get the next item, pass 1, for the previous -1.
- */
int RNA_property_enum_step(
const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step)
{
@@ -4211,7 +4147,6 @@ int RNA_property_collection_lookup_string(PointerRNA *ptr,
return RNA_property_collection_lookup_string_index(ptr, prop, key, r_ptr, &index);
}
-/* zero return is an assignment error */
int RNA_property_collection_assign_int(PointerRNA *ptr,
PropertyRNA *prop,
const int key,
@@ -4986,6 +4921,10 @@ static char *rna_path_token_in_brackets(const char **path,
return buf;
}
+/**
+ * \return true when when the key in the path is correctly parsed and found in the collection
+ * or when the path is empty.
+ */
static bool rna_path_parse_collection_key(const char **path,
PointerRNA *ptr,
PropertyRNA *prop,
@@ -5001,6 +4940,7 @@ static bool rna_path_parse_collection_key(const char **path,
return true;
}
+ bool found = false;
if (**path == '[') {
bool quoted;
char *token;
@@ -5015,7 +4955,7 @@ static bool rna_path_parse_collection_key(const char **path,
/* check for "" to see if it is a string */
if (quoted) {
if (RNA_property_collection_lookup_string(ptr, prop, token, r_nextptr)) {
- /* pass */
+ found = true;
}
else {
r_nextptr->data = NULL;
@@ -5028,7 +4968,7 @@ static bool rna_path_parse_collection_key(const char **path,
return false; /* we can be sure the fixedbuf was used in this case */
}
if (RNA_property_collection_lookup_int(ptr, prop, intkey, r_nextptr)) {
- /* pass */
+ found = true;
}
else {
r_nextptr->data = NULL;
@@ -5041,7 +4981,7 @@ static bool rna_path_parse_collection_key(const char **path,
}
else {
if (RNA_property_collection_type_get(ptr, prop, r_nextptr)) {
- /* pass */
+ found = true;
}
else {
/* ensure we quit on invalid values */
@@ -5049,7 +4989,7 @@ static bool rna_path_parse_collection_key(const char **path,
}
}
- return true;
+ return found;
}
static bool rna_path_parse_array_index(const char **path,
@@ -5325,17 +5265,6 @@ static bool rna_path_parse(PointerRNA *ptr,
return true;
}
-/**
- * Resolve the given RNA Path to find the pointer and/or property
- * indicated by fully resolving the path.
- *
- * \warning Unlike \a RNA_path_resolve_property(), that one *will* try to follow RNAPointers,
- * e.g. the path 'parent' applied to a RNAObject \a ptr will return the object.parent in \a r_ptr,
- * and a NULL \a r_prop...
- *
- * \note Assumes all pointers provided are valid
- * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
- */
bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
{
if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, true)) {
@@ -5345,13 +5274,6 @@ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, Prop
return r_ptr->data != NULL;
}
-/**
- * Resolve the given RNA Path to find the pointer and/or property + array index
- * indicated by fully resolving the path.
- *
- * \note Assumes all pointers provided are valid.
- * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
- */
bool RNA_path_resolve_full(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
@@ -5362,26 +5284,12 @@ bool RNA_path_resolve_full(
return r_ptr->data != NULL;
}
-/**
- * A version of #RNA_path_resolve_full doesn't check the value of #PointerRNA.data.
- *
- * \note While it's correct to ignore the value of #PointerRNA.data
- * most callers need to know if the resulting pointer was found and not null.
- */
bool RNA_path_resolve_full_maybe_null(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
return rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true);
}
-/**
- * Resolve the given RNA Path to find both the pointer AND property
- * indicated by fully resolving the path.
- *
- * This is a convenience method to avoid logic errors and ugly syntax.
- * \note Assumes all pointers provided are valid
- * \return True only if both a valid pointer and property are found after resolving the path
- */
bool RNA_path_resolve_property(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
@@ -5394,14 +5302,6 @@ bool RNA_path_resolve_property(PointerRNA *ptr,
return r_ptr->data != NULL && *r_prop != NULL;
}
-/**
- * Resolve the given RNA Path to find the pointer AND property (as well as the array index)
- * indicated by fully resolving the path.
- *
- * This is a convenience method to avoid logic errors and ugly syntax.
- * \note Assumes all pointers provided are valid
- * \return True only if both a valid pointer and property are found after resolving the path
- */
bool RNA_path_resolve_property_full(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
@@ -5412,18 +5312,6 @@ bool RNA_path_resolve_property_full(
return r_ptr->data != NULL && *r_prop != NULL;
}
-/**
- * Resolve the given RNA Path to find both the pointer AND property
- * indicated by fully resolving the path, and get the value of the Pointer property
- * (or item of the collection).
- *
- * This is a convenience method to avoid logic errors and ugly syntax,
- * it combines both \a RNA_path_resolve and #RNA_path_resolve_property in a single call.
- * \note Assumes all pointers provided are valid.
- * \param r_item_ptr: The final Pointer or Collection item value.
- * You must check for its validity before use!
- * \return True only if both a valid pointer and property are found after resolving the path
- */
bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
@@ -5437,19 +5325,6 @@ bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
return r_ptr->data != NULL && *r_prop != NULL;
}
-/**
- * Resolve the given RNA Path to find both the pointer AND property (as well as the array index)
- * indicated by fully resolving the path,
- * and get the value of the Pointer property (or item of the collection).
- *
- * This is a convenience method to avoid logic errors and ugly syntax,
- * it combines both \a RNA_path_resolve_full and
- * \a RNA_path_resolve_property_full in a single call.
- * \note Assumes all pointers provided are valid.
- * \param r_item_ptr: The final Pointer or Collection item value.
- * You must check for its validity before use!
- * \return True only if both a valid pointer and property are found after resolving the path
- */
bool RNA_path_resolve_property_and_item_pointer_full(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
@@ -5463,15 +5338,6 @@ bool RNA_path_resolve_property_and_item_pointer_full(PointerRNA *ptr,
return r_ptr->data != NULL && *r_prop != NULL;
}
-/**
- * Resolve the given RNA Path into a linked list of PropertyElemRNA's.
- *
- * To be used when complex operations over path are needed, like e.g. get relative paths,
- * to avoid too much string operations.
- *
- * \return True if there was no error while resolving the path
- * \note Assumes all pointers provided are valid
- */
bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements)
{
return rna_path_parse(ptr, path, NULL, NULL, NULL, NULL, r_elements, false);
@@ -5722,16 +5588,6 @@ static char *rna_idp_path(PointerRNA *ptr,
return path;
}
-/**
- * Find the path from the structure referenced by the pointer to the runtime RNA-defined
- * #IDProperty object.
- *
- * \note Does *not* handle pure user-defined IDProperties (a.k.a. custom properties).
- *
- * \param ptr: Reference to the object owning the custom property storage.
- * \param needle: Custom property object to find.
- * \return Relative path or NULL.
- */
char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, IDProperty *needle)
{
IDProperty *haystack = RNA_struct_idprops(ptr, false);
@@ -5758,13 +5614,6 @@ static char *rna_path_from_ID_to_idpgroup(const PointerRNA *ptr)
return RNA_path_from_struct_to_idproperty(&id_ptr, ptr->data);
}
-/**
- * Find the actual ID pointer and path from it to the given ID.
- *
- * \param id: ID reference to search the global owner for.
- * \param[out] r_path: Path from the real ID to the initial ID.
- * \return The ID pointer, or NULL in case of failure.
- */
ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path)
{
if (r_path) {
@@ -5917,11 +5766,6 @@ static void rna_path_array_multi_string_from_flat_index(PointerRNA *ptr,
}
}
-/**
- * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
- * \param index: The *flattened* index to use when \a `index_dim > 0`,
- * this is expanded when used with multi-dimensional arrays.
- */
char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
PropertyRNA *prop,
int index_dim,
@@ -5993,10 +5837,6 @@ char *RNA_path_from_real_ID_to_property_index(
return path != NULL ? rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real_id) : NULL;
}
-/**
- * \return the path to given ptr/prop from the closest ancestor of given type,
- * if any (else return NULL).
- */
char *RNA_path_resolve_from_type_to_property(PointerRNA *ptr,
PropertyRNA *prop,
const StructRNA *type)
@@ -6035,10 +5875,6 @@ char *RNA_path_resolve_from_type_to_property(PointerRNA *ptr,
return path;
}
-/**
- * Get the ID as a python representation, eg:
- * bpy.data.foo["bar"]
- */
char *RNA_path_full_ID_py(Main *bmain, ID *id)
{
const char *path;
@@ -6074,10 +5910,6 @@ char *RNA_path_full_ID_py(Main *bmain, ID *id)
path);
}
-/**
- * Get the ID.struct as a python representation, eg:
- * bpy.data.foo["bar"].some_struct
- */
char *RNA_path_full_struct_py(Main *bmain, struct PointerRNA *ptr)
{
char *id_path;
@@ -6106,10 +5938,6 @@ char *RNA_path_full_struct_py(Main *bmain, struct PointerRNA *ptr)
return ret;
}
-/**
- * Get the ID.struct.property as a python representation, eg:
- * bpy.data.foo["bar"].some_struct.some_prop[10]
- */
char *RNA_path_full_property_py_ex(
Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
{
@@ -6163,10 +5991,6 @@ char *RNA_path_full_property_py(Main *bmain, PointerRNA *ptr, PropertyRNA *prop,
return RNA_path_full_property_py_ex(bmain, ptr, prop, index, false);
}
-/**
- * Get the struct.property as a python representation, eg:
- * some_struct.some_prop[10]
- */
char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
{
char *data_path;
@@ -6204,10 +6028,6 @@ char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
return ret;
}
-/**
- * Get the struct.property as a python representation, eg:
- * some_prop[10]
- */
char *RNA_path_property_py(const PointerRNA *UNUSED(ptr), PropertyRNA *prop, int index)
{
char *ret;
@@ -6677,7 +6497,6 @@ bool RNA_property_is_idprop(const PropertyRNA *prop)
return (prop->magic != RNA_MAGIC);
}
-/* mainly for the UI */
bool RNA_property_is_unlink(PropertyRNA *prop)
{
const int flag = RNA_property_flag(prop);
@@ -6687,9 +6506,6 @@ bool RNA_property_is_unlink(PropertyRNA *prop)
return (flag & (PROP_NEVER_UNLINK | PROP_NEVER_NULL)) == 0;
}
-/* string representation of a property, python
- * compatible but can be used for display too,
- * context may be NULL */
char *RNA_pointer_as_string_id(bContext *C, PointerRNA *ptr)
{
DynStr *dynstr = BLI_dynstr_new();
@@ -6751,7 +6567,6 @@ char *RNA_pointer_as_string(bContext *C,
return rna_pointer_as_string__bldata(CTX_data_main(C), ptr_prop);
}
-/* context can be NULL */
char *RNA_pointer_as_string_keywords_ex(bContext *C,
PointerRNA *ptr,
const bool as_function,
@@ -8114,7 +7929,6 @@ bool RNA_property_assign_default(PointerRNA *ptr, PropertyRNA *prop)
}
}
-/* use RNA_warning macro which includes __func__ suffix */
void _RNA_warning(const char *format, ...)
{
va_list args;
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index be8972dbff3..950eccdb552 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -126,8 +126,6 @@ int RNA_property_override_flag(PropertyRNA *prop)
return rna_ensure_property(prop)->flag_override;
}
-/** \note Does not take into account editable status, this has to be checked separately
- * (using #RNA_property_editable_flag() usually). */
bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
{
if (prop->magic == RNA_MAGIC) {
@@ -170,7 +168,6 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
return (idprop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) != 0;
}
-/* Should only be used for custom properties */
bool RNA_property_overridable_library_set(PointerRNA *UNUSED(ptr),
PropertyRNA *prop,
const bool is_overridable)
@@ -614,37 +611,27 @@ static bool rna_property_override_operation_apply(Main *bmain,
}
/* get and set the default values as appropriate for the various types */
- const bool sucess = override_apply(bmain,
- ptr_dst,
- ptr_src,
- ptr_storage,
- prop_dst,
- prop_src,
- prop_storage,
- len_dst,
- len_src,
- len_storage,
- ptr_item_dst,
- ptr_item_src,
- ptr_item_storage,
- opop);
- if (sucess) {
+ const bool success = override_apply(bmain,
+ ptr_dst,
+ ptr_src,
+ ptr_storage,
+ prop_dst,
+ prop_src,
+ prop_storage,
+ len_dst,
+ len_src,
+ len_storage,
+ ptr_item_dst,
+ ptr_item_src,
+ ptr_item_storage,
+ opop);
+ if (success) {
RNA_property_update_main(bmain, NULL, ptr_dst, prop_dst);
}
- return sucess;
+ return success;
}
-/**
- * Check whether reference and local overridden data match (are the same),
- * with respect to given restrictive sets of properties.
- * If requested, will generate needed new property overrides, and/or restore values from reference.
- *
- * \param r_report_flags: If given,
- * will be set with flags matching actions taken by the function on \a ptr_local.
- *
- * \return True if _resulting_ \a ptr_local does match \a ptr_reference.
- */
bool RNA_struct_override_matches(Main *bmain,
PointerRNA *ptr_local,
PointerRNA *ptr_reference,
@@ -928,10 +915,6 @@ bool RNA_struct_override_matches(Main *bmain,
return matching;
}
-/**
- * Store needed second operands into \a storage data-block
- * for differential override operations.
- */
bool RNA_struct_override_store(Main *bmain,
PointerRNA *ptr_local,
PointerRNA *ptr_reference,
@@ -1076,7 +1059,12 @@ static void rna_porperty_override_collection_subitem_lookup(
*r_ptr_item_storage = private_ptr_item_storage;
}
- if ((*r_ptr_item_dst)->type == NULL) {
+ /* Note that there is no reason to report in case no item is expected, i.e. in case subitem name
+ * and index are invalid. This can often happen when inserting new items (constraint,
+ * modifier...) in a collection that supports it. */
+ if ((*r_ptr_item_dst)->type == NULL &&
+ ((opop->subitem_reference_name != NULL && opop->subitem_reference_name[0] != '\0') ||
+ opop->subitem_reference_index != -1)) {
CLOG_INFO(&LOG,
2,
"Failed to find destination sub-item '%s' (%d) of '%s' in new override data '%s'",
@@ -1085,7 +1073,9 @@ static void rna_porperty_override_collection_subitem_lookup(
op->rna_path,
ptr_dst->owner_id->name);
}
- if ((*r_ptr_item_src)->type == NULL) {
+ if ((*r_ptr_item_src)->type == NULL &&
+ ((opop->subitem_local_name != NULL && opop->subitem_local_name[0] != '\0') ||
+ opop->subitem_local_index != -1)) {
CLOG_INFO(&LOG,
2,
"Failed to find source sub-item '%s' (%d) of '%s' in old override data '%s'",
@@ -1098,15 +1088,24 @@ static void rna_porperty_override_collection_subitem_lookup(
static void rna_property_override_check_resync(Main *bmain,
PointerRNA *ptr_dst,
+ PointerRNA *ptr_src,
PointerRNA *ptr_item_dst,
PointerRNA *ptr_item_src)
{
- ID *id_owner = rna_property_override_property_real_id_owner(bmain, ptr_dst, NULL, NULL);
+ ID *id_owner_src = rna_property_override_property_real_id_owner(bmain, ptr_src, NULL, NULL);
+ ID *id_owner_dst = rna_property_override_property_real_id_owner(bmain, ptr_dst, NULL, NULL);
ID *id_src = rna_property_override_property_real_id_owner(bmain, ptr_item_src, NULL, NULL);
ID *id_dst = rna_property_override_property_real_id_owner(bmain, ptr_item_dst, NULL, NULL);
- BLI_assert(id_src == NULL || ID_IS_OVERRIDE_LIBRARY_REAL(id_src));
- /* Work around file corruption on writing, see T86853. */
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_owner_src));
+
+ /* If the owner ID is not part of an override hierarchy, there is no possible resync. */
+ if (id_owner_src->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY) {
+ return;
+ }
+
+ /* If `id_src` is not a liboverride, we cannot perform any further 'need resync' checks from
+ * here. */
if (id_src != NULL && !ID_IS_OVERRIDE_LIBRARY_REAL(id_src)) {
return;
}
@@ -1126,9 +1125,12 @@ static void rna_property_override_check_resync(Main *bmain,
* NOTE: Here we are testing if `id_owner` is referencing itself, in that case the new
* override copy generated by `BKE_lib_override_library_update` will already have its
* self-references updated to itself, instead of still pointing to its linked source. */
- (id_dst->lib == id_src->lib && id_dst != id_owner))) {
- ptr_dst->owner_id->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
- CLOG_INFO(&LOG, 3, "Local override %s detected as needing resync", ptr_dst->owner_id->name);
+ (id_dst->lib == id_src->lib && id_dst != id_owner_dst))) {
+ id_owner_dst->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
+ if (ID_IS_LINKED(id_owner_src)) {
+ id_owner_src->lib->tag |= LIBRARY_TAG_RESYNC_REQUIRED;
+ }
+ CLOG_INFO(&LOG, 3, "Local override %s detected as needing resync", id_owner_dst->name);
}
}
@@ -1195,10 +1197,6 @@ static void rna_property_override_apply_ex(Main *bmain,
}
}
-/**
- * Apply given \a override operations on \a ptr_dst, using \a ptr_src
- * (and \a ptr_storage for differential ops) as source.
- */
void RNA_struct_override_apply(Main *bmain,
PointerRNA *ptr_dst,
PointerRNA *ptr_src,
@@ -1249,7 +1247,8 @@ void RNA_struct_override_apply(Main *bmain,
PointerRNA prop_ptr_src = RNA_property_pointer_get(&data_src, prop_src);
PointerRNA prop_ptr_dst = RNA_property_pointer_get(&data_dst, prop_dst);
- rna_property_override_check_resync(bmain, ptr_dst, &prop_ptr_dst, &prop_ptr_src);
+ rna_property_override_check_resync(
+ bmain, ptr_dst, ptr_src, &prop_ptr_dst, &prop_ptr_src);
}
else if (op->rna_prop_type == PROP_COLLECTION) {
if (RNA_struct_is_ID(RNA_property_pointer_type(&data_src, prop_src))) {
@@ -1280,7 +1279,8 @@ void RNA_struct_override_apply(Main *bmain,
op,
opop);
- rna_property_override_check_resync(bmain, ptr_dst, ptr_item_dst, ptr_item_src);
+ rna_property_override_check_resync(
+ bmain, ptr_dst, ptr_src, ptr_item_dst, ptr_item_src);
}
}
}
diff --git a/source/blender/makesrna/intern/rna_access_internal.h b/source/blender/makesrna/intern/rna_access_internal.h
index 73407123863..9f1be5bbd67 100644
--- a/source/blender/makesrna/intern/rna_access_internal.h
+++ b/source/blender/makesrna/intern/rna_access_internal.h
@@ -27,6 +27,13 @@
struct IDProperty;
struct PropertyRNAOrID;
+/**
+ * This function initializes a #PropertyRNAOrID with all required info, from a given #PropertyRNA
+ * and #PointerRNA data. It deals properly with the three cases
+ * (static RNA, runtime RNA, and #IDProperty).
+ * \warning given `ptr` #PointerRNA is assumed to be a valid data one here, calling code is
+ * responsible to ensure that.
+ */
void rna_property_rna_or_id_get(PropertyRNA *prop,
PointerRNA *ptr,
PropertyRNAOrID *r_prop_rna_or_id);
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 2aa09a30c75..6b134977c5a 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -246,12 +246,60 @@ static void rna_Action_active_pose_marker_index_range(
*max = max_ii(0, BLI_listbase_count(&act->markers) - 1);
}
-static void rna_Action_frame_range_get(PointerRNA *ptr, float *values)
+static void rna_Action_frame_range_get(PointerRNA *ptr, float *r_values)
+{
+ BKE_action_get_frame_range((bAction *)ptr->owner_id, &r_values[0], &r_values[1]);
+}
+
+static void rna_Action_frame_range_set(PointerRNA *ptr, const float *values)
+{
+ bAction *data = (bAction *)ptr->owner_id;
+
+ data->flag |= ACT_FRAME_RANGE;
+ data->frame_start = values[0];
+ data->frame_end = values[1];
+ CLAMP_MIN(data->frame_end, data->frame_start);
+}
+
+static void rna_Action_curve_frame_range_get(PointerRNA *ptr, float *values)
{ /* don't include modifiers because they too easily can have very large
* ranges: MINAFRAMEF to MAXFRAMEF. */
calc_action_range((bAction *)ptr->owner_id, values, values + 1, false);
}
+static void rna_Action_use_frame_range_set(PointerRNA *ptr, bool value)
+{
+ bAction *data = (bAction *)ptr->owner_id;
+
+ if (value) {
+ /* If the frame range is blank, initialize it by scanning F-Curves. */
+ if ((data->frame_start == data->frame_end) && (data->frame_start == 0)) {
+ calc_action_range(data, &data->frame_start, &data->frame_end, false);
+ }
+
+ data->flag |= ACT_FRAME_RANGE;
+ }
+ else {
+ data->flag &= ~ACT_FRAME_RANGE;
+ }
+}
+
+static void rna_Action_start_frame_set(PointerRNA *ptr, float value)
+{
+ bAction *data = (bAction *)ptr->owner_id;
+
+ data->frame_start = value;
+ CLAMP_MIN(data->frame_end, data->frame_start);
+}
+
+static void rna_Action_end_frame_set(PointerRNA *ptr, float value)
+{
+ bAction *data = (bAction *)ptr->owner_id;
+
+ data->frame_end = value;
+ CLAMP_MAX(data->frame_start, data->frame_end);
+}
+
/* Used to check if an action (value pointer)
* is suitable to be assigned to the ID-block that is ptr. */
bool rna_Action_id_poll(PointerRNA *ptr, PointerRNA value)
@@ -834,17 +882,73 @@ static void rna_def_action(BlenderRNA *brna)
rna_def_action_pose_markers(brna, prop);
/* properties */
+ prop = RNA_def_property(srna, "use_frame_range", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_FRAME_RANGE);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_Action_use_frame_range_set");
+ RNA_def_property_ui_text(
+ prop,
+ "Manual Frame Range",
+ "Manually specify the intended playback frame range for the action "
+ "(this range is used by some tools, but does not affect animation evaluation)");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "use_cyclic", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_CYCLIC);
+ RNA_def_property_ui_text(
+ prop,
+ "Cyclic Animation",
+ "The action is intended to be used as a cycle looping over its manually set "
+ "playback frame range (enabling this doesn't automatically make it loop)");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_float_sdna(prop, NULL, "frame_start");
+ RNA_def_property_float_funcs(prop, NULL, "rna_Action_start_frame_set", NULL);
+ RNA_def_property_ui_range(prop, MINFRAME, MAXFRAME, 100, 2);
+ RNA_def_property_ui_text(
+ prop, "Start Frame", "The start frame of the manually set intended playback range");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_float_sdna(prop, NULL, "frame_end");
+ RNA_def_property_float_funcs(prop, NULL, "rna_Action_end_frame_set", NULL);
+ RNA_def_property_ui_range(prop, MINFRAME, MAXFRAME, 100, 2);
+ RNA_def_property_ui_text(
+ prop, "End Frame", "The end frame of the manually set intended playback range");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ prop = RNA_def_float_vector(
+ srna,
+ "frame_range",
+ 2,
+ NULL,
+ 0,
+ 0,
+ "Frame Range",
+ "The intended playback frame range of this action, using the manually set range "
+ "if available, or the combined frame range of all F-Curves within this action "
+ "if not (assigning sets the manual frame range)",
+ 0,
+ 0);
+ RNA_def_property_float_funcs(
+ prop, "rna_Action_frame_range_get", "rna_Action_frame_range_set", NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
prop = RNA_def_float_vector(srna,
- "frame_range",
+ "curve_frame_range",
2,
NULL,
0,
0,
- "Frame Range",
- "The final frame range of all F-Curves within this action",
+ "Curve Frame Range",
+ "The combined frame range of all F-Curves within this action",
0,
0);
- RNA_def_property_float_funcs(prop, "rna_Action_frame_range_get", NULL, NULL);
+ RNA_def_property_float_funcs(prop, "rna_Action_curve_frame_range_get", NULL, NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* special "type" limiter - should not really be edited in general,
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index 52c25bae45a..9068fdb6e72 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -761,8 +761,8 @@ bool rna_NLA_tracks_override_apply(Main *bmain,
/* This is not working so well with index-based insertion, especially in case some tracks get
* added to lib linked data. So we simply add locale tracks at the end of the list always, order
* of override operations should ensure order of local tracks is preserved properly. */
- if (opop->subitem_local_index >= 0) {
- nla_track_anchor = BLI_findlink(&anim_data_dst->nla_tracks, opop->subitem_local_index);
+ if (opop->subitem_reference_index >= 0) {
+ nla_track_anchor = BLI_findlink(&anim_data_dst->nla_tracks, opop->subitem_reference_index);
}
/* Otherwise we just insert in first position. */
# else
@@ -773,9 +773,11 @@ bool rna_NLA_tracks_override_apply(Main *bmain,
if (opop->subitem_local_index >= 0) {
nla_track_src = BLI_findlink(&anim_data_src->nla_tracks, opop->subitem_local_index);
}
- nla_track_src = nla_track_src ? nla_track_src->next : anim_data_src->nla_tracks.first;
- BLI_assert(nla_track_src != NULL);
+ if (nla_track_src == NULL) {
+ BLI_assert(nla_track_src != NULL);
+ return false;
+ }
NlaTrack *nla_track_dst = BKE_nlatrack_copy(bmain, nla_track_src, true, 0);
diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c
index b205b3d7139..0525d2f6fb1 100644
--- a/source/blender/makesrna/intern/rna_animviz.c
+++ b/source/blender/makesrna/intern/rna_animviz.c
@@ -117,7 +117,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna)
srna = RNA_def_struct(brna, "MotionPath", NULL);
RNA_def_struct_sdna(srna, "bMotionPath");
RNA_def_struct_ui_text(
- srna, "Motion Path", "Cache of the worldspace positions of an element over a frame range");
+ srna, "Motion Path", "Cache of the world-space positions of an element over a frame range");
/* Collections */
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
@@ -207,6 +207,8 @@ static void rna_def_animviz_paths(BlenderRNA *brna)
RNA_def_struct_ui_text(
srna, "Motion Path Settings", "Motion Path settings for animation visualization");
+ RNA_define_lib_overridable(true);
+
/* Enums */
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "path_type");
@@ -301,6 +303,8 @@ static void rna_def_animviz_paths(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Has Motion Paths", "Are there any bone paths that will need updating (read-only)");
+
+ RNA_define_lib_overridable(false);
}
/* --- */
@@ -312,6 +316,7 @@ void rna_def_animviz_common(StructRNA *srna)
prop = RNA_def_property(srna, "animation_visualization", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "avs");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Animation Visualization", "Animation data for this data-block");
}
@@ -328,6 +333,7 @@ static void rna_def_animviz(BlenderRNA *brna)
/* motion path settings (nested struct) */
prop = RNA_def_property(srna, "motion_path", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_struct_type(prop, "AnimVizMotionPaths");
RNA_def_property_pointer_funcs(prop, "rna_AnimViz_motion_paths_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Motion Paths", "Motion Path settings for visualization");
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 690506fa517..28e50e80f32 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -669,10 +669,10 @@ static void rna_Armature_transform(bArmature *arm, float mat[16])
#else
-/* Settings for curved bbone settings -
- * The posemode values get applied over the top of the editmode ones. */
void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editbone)
{
+ /* NOTE: The pose-mode values get applied over the top of the edit-mode ones. */
+
# define RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone) \
{ \
if (is_posebone) { \
@@ -993,7 +993,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
}
RNA_def_property_float_sdna(prop, NULL, "rad_head");
- /* XXX range is 0 to lim, where lim = 10000.0f * MAX2(1.0, view3d->grid); */
+ /* XXX range is 0 to limit, where limit = 10000.0f * MAX2(1.0, view3d->grid); */
// RNA_def_property_range(prop, 0, 1000);
RNA_def_property_ui_range(prop, 0.01, 100, 0.1, 3);
RNA_def_property_ui_text(
@@ -1007,7 +1007,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
}
RNA_def_property_float_sdna(prop, NULL, "rad_tail");
- /* XXX range is 0 to lim, where lim = 10000.0f * MAX2(1.0, view3d->grid); */
+ /* XXX range is 0 to limit, where limit = 10000.0f * MAX2(1.0, view3d->grid); */
// RNA_def_property_range(prop, 0, 1000);
RNA_def_property_ui_range(prop, 0.01, 100, 0.1, 3);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_armature_api.c b/source/blender/makesrna/intern/rna_armature_api.c
index a02f55667e3..7d165ce045d 100644
--- a/source/blender/makesrna/intern/rna_armature_api.c
+++ b/source/blender/makesrna/intern/rna_armature_api.c
@@ -119,7 +119,7 @@ void RNA_api_armature_edit_bone(StructRNA *srna)
func = RNA_def_function(srna, "align_roll", "rna_EditBone_align_roll");
RNA_def_function_ui_description(func,
- "Align the bone to a localspace roll so the Z axis "
+ "Align the bone to a local-space roll so the Z axis "
"points in the direction of the vector given");
parm = RNA_def_float_vector(
func, "vector", 3, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c
index 80824df1bc8..e79cbc838d4 100644
--- a/source/blender/makesrna/intern/rna_asset.c
+++ b/source/blender/makesrna/intern/rna_asset.c
@@ -139,6 +139,40 @@ static IDProperty **rna_AssetMetaData_idprops(PointerRNA *ptr)
return &asset_data->properties;
}
+static void rna_AssetMetaData_author_get(PointerRNA *ptr, char *value)
+{
+ AssetMetaData *asset_data = ptr->data;
+
+ if (asset_data->author) {
+ strcpy(value, asset_data->author);
+ }
+ else {
+ value[0] = '\0';
+ }
+}
+
+static int rna_AssetMetaData_author_length(PointerRNA *ptr)
+{
+ AssetMetaData *asset_data = ptr->data;
+ return asset_data->author ? strlen(asset_data->author) : 0;
+}
+
+static void rna_AssetMetaData_author_set(PointerRNA *ptr, const char *value)
+{
+ AssetMetaData *asset_data = ptr->data;
+
+ if (asset_data->author) {
+ MEM_freeN(asset_data->author);
+ }
+
+ if (value[0]) {
+ asset_data->author = BLI_strdup(value);
+ }
+ else {
+ asset_data->author = NULL;
+ }
+}
+
static void rna_AssetMetaData_description_get(PointerRNA *ptr, char *value)
{
AssetMetaData *asset_data = ptr->data;
@@ -215,6 +249,25 @@ static void rna_AssetMetaData_catalog_id_set(PointerRNA *ptr, const char *value)
BKE_asset_metadata_catalog_id_set(asset_data, new_uuid, "");
}
+void rna_AssetMetaData_catalog_id_update(struct bContext *C, struct PointerRNA *ptr)
+{
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ if (sfile == NULL) {
+ /* Until there is a proper Asset Service available, it's only possible to get the asset library
+ * from within the asset browser context. */
+ return;
+ }
+
+ AssetLibrary *asset_library = ED_fileselect_active_asset_library_get(sfile);
+ if (asset_library == NULL) {
+ /* The SpaceFile may not be an asset browser but a regular file browser. */
+ return;
+ }
+
+ AssetMetaData *asset_data = ptr->data;
+ BKE_asset_library_refresh_catalog_simplename(asset_library, asset_data);
+}
+
static PointerRNA rna_AssetHandle_file_data_get(PointerRNA *ptr)
{
AssetHandle *asset_handle = ptr->data;
@@ -254,7 +307,7 @@ const EnumPropertyItem *rna_asset_library_reference_itemf(bContext *UNUSED(C),
PropertyRNA *UNUSED(prop),
bool *r_free)
{
- const EnumPropertyItem *items = ED_asset_library_reference_to_rna_enum_itemf();
+ const EnumPropertyItem *items = ED_asset_library_reference_to_rna_enum_itemf(true);
if (!items) {
*r_free = false;
}
@@ -328,6 +381,14 @@ static void rna_def_asset_data(BlenderRNA *brna)
RNA_def_struct_idprops_func(srna, "rna_AssetMetaData_idprops");
RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES); /* Mandatory! */
+ prop = RNA_def_property(srna, "author", PROP_STRING, PROP_NONE);
+ RNA_def_property_editable_func(prop, "rna_AssetMetaData_editable");
+ RNA_def_property_string_funcs(prop,
+ "rna_AssetMetaData_author_get",
+ "rna_AssetMetaData_author_length",
+ "rna_AssetMetaData_author_set");
+ RNA_def_property_ui_text(prop, "Author", "Name of the creator of the asset");
+
prop = RNA_def_property(srna, "description", PROP_STRING, PROP_NONE);
RNA_def_property_editable_func(prop, "rna_AssetMetaData_editable");
RNA_def_property_string_funcs(prop,
@@ -356,6 +417,7 @@ static void rna_def_asset_data(BlenderRNA *brna)
"rna_AssetMetaData_catalog_id_length",
"rna_AssetMetaData_catalog_id_set");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, 0, "rna_AssetMetaData_catalog_id_update");
RNA_def_property_ui_text(prop,
"Catalog UUID",
"Identifier for the asset's catalog, used by Blender to look up the "
@@ -431,9 +493,6 @@ static void rna_def_asset_library_reference(BlenderRNA *brna)
srna, "Asset Library Reference", "Identifier to refer to the asset library");
}
-/**
- * \note the UI text and updating has to be set by the caller.
- */
PropertyRNA *rna_def_asset_library_reference_common(struct StructRNA *srna,
const char *get,
const char *set)
diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c
index 49e813e6a6c..35da353a043 100644
--- a/source/blender/makesrna/intern/rna_attribute.c
+++ b/source/blender/makesrna/intern/rna_attribute.c
@@ -72,6 +72,16 @@ const EnumPropertyItem rna_enum_attribute_domain_items[] = {
/* Not implement yet */
// {ATTR_DOMAIN_GRIDS, "GRIDS", 0, "Grids", "Attribute on mesh multires grids"},
{ATTR_DOMAIN_CURVE, "CURVE", 0, "Spline", "Attribute on spline"},
+ {ATTR_DOMAIN_INSTANCE, "INSTANCE", 0, "Instance", "Attribute on instance"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_attribute_domain_without_corner_items[] = {
+ {ATTR_DOMAIN_POINT, "POINT", 0, "Point", "Attribute on point"},
+ {ATTR_DOMAIN_EDGE, "EDGE", 0, "Edge", "Attribute on mesh edge"},
+ {ATTR_DOMAIN_FACE, "FACE", 0, "Face", "Attribute on mesh faces"},
+ {ATTR_DOMAIN_CURVE, "CURVE", 0, "Spline", "Attribute on spline"},
+ {ATTR_DOMAIN_INSTANCE, "INSTANCE", 0, "Instance", "Attribute on instance"},
{0, NULL, 0, NULL, NULL},
};
@@ -82,6 +92,7 @@ const EnumPropertyItem rna_enum_attribute_domain_with_auto_items[] = {
{ATTR_DOMAIN_FACE, "FACE", 0, "Face", "Attribute on mesh faces"},
{ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", "Attribute on mesh face corner"},
{ATTR_DOMAIN_CURVE, "CURVE", 0, "Spline", "Attribute on spline"},
+ {ATTR_DOMAIN_INSTANCE, "INSTANCE", 0, "Instance", "Attribute on instance"},
{0, NULL, 0, NULL, NULL},
};
@@ -155,7 +166,9 @@ static int rna_Attribute_type_get(PointerRNA *ptr)
return layer->type;
}
-const EnumPropertyItem *rna_enum_attribute_domain_itemf(ID *id, bool *r_free)
+const EnumPropertyItem *rna_enum_attribute_domain_itemf(ID *id,
+ bool include_instances,
+ bool *r_free)
{
EnumPropertyItem *item = NULL;
const EnumPropertyItem *domain_item = NULL;
@@ -177,6 +190,9 @@ const EnumPropertyItem *rna_enum_attribute_domain_itemf(ID *id, bool *r_free)
if (id_type == ID_ME && ELEM(domain_item->value, ATTR_DOMAIN_CURVE)) {
continue;
}
+ if (!include_instances && domain_item->value == ATTR_DOMAIN_INSTANCE) {
+ continue;
+ }
if (domain_item->value == ATTR_DOMAIN_POINT && id_type == ID_ME) {
RNA_enum_item_add(&item, &totitem, &mesh_vertex_domain_item);
@@ -196,7 +212,7 @@ static const EnumPropertyItem *rna_Attribute_domain_itemf(bContext *UNUSED(C),
PropertyRNA *UNUSED(prop),
bool *r_free)
{
- return rna_enum_attribute_domain_itemf(ptr->owner_id, r_free);
+ return rna_enum_attribute_domain_itemf(ptr->owner_id, true, r_free);
}
static int rna_Attribute_domain_get(PointerRNA *ptr)
@@ -315,8 +331,10 @@ static void rna_AttributeGroup_next_domain(ID *id,
int(skip)(CollectionPropertyIterator *iter, void *data))
{
do {
- CustomDataLayer *prev_layers = (CustomDataLayer *)iter->internal.array.endptr -
- iter->internal.array.length;
+ CustomDataLayer *prev_layers = (iter->internal.array.endptr == NULL) ?
+ NULL :
+ (CustomDataLayer *)iter->internal.array.endptr -
+ iter->internal.array.length;
CustomData *customdata = BKE_id_attributes_iterator_next_domain(id, prev_layers);
if (customdata == NULL) {
return;
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 1d3b8cd9f9c..b4cf15ebfc6 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -1283,7 +1283,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
static EnumPropertyItem gppaint_mode_types_items[] = {
{GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Vertex Color affects to Stroke only"},
{GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Vertex Color affects to Fill only"},
- {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Vertex Color affects to Stroke and Fill"},
+ {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", "Vertex Color affects to Stroke and Fill"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c
index 74d924b8937..2f8fc004d85 100644
--- a/source/blender/makesrna/intern/rna_cachefile.c
+++ b/source/blender/makesrna/intern/rna_cachefile.c
@@ -32,6 +32,7 @@
#ifdef RNA_RUNTIME
+# include "BLI_math.h"
# include "BLI_string.h"
# include "BKE_cachefile.h"
@@ -54,6 +55,14 @@ static void rna_CacheFile_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
}
+static void rna_CacheFileLayer_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ CacheFile *cache_file = (CacheFile *)ptr->owner_id;
+
+ DEG_id_tag_update(&cache_file->id, ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+}
+
static void rna_CacheFile_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
rna_CacheFile_update(bmain, scene, ptr);
@@ -66,6 +75,91 @@ static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, P
rna_iterator_listbase_begin(iter, &cache_file->object_paths, NULL);
}
+static PointerRNA rna_CacheFile_active_layer_get(PointerRNA *ptr)
+{
+ CacheFile *cache_file = (CacheFile *)ptr->owner_id;
+ return rna_pointer_inherit_refine(
+ ptr, &RNA_CacheFileLayer, BKE_cachefile_get_active_layer(cache_file));
+}
+
+static void rna_CacheFile_active_layer_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *reports)
+{
+ CacheFile *cache_file = (CacheFile *)ptr->owner_id;
+ int index = BLI_findindex(&cache_file->layers, value.data);
+ if (index == -1) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Layer '%s' not found in object '%s'",
+ ((CacheFileLayer *)value.data)->filepath,
+ cache_file->id.name + 2);
+ return;
+ }
+
+ cache_file->active_layer = index + 1;
+}
+
+static int rna_CacheFile_active_layer_index_get(PointerRNA *ptr)
+{
+ CacheFile *cache_file = (CacheFile *)ptr->owner_id;
+ return cache_file->active_layer - 1;
+}
+
+static void rna_CacheFile_active_layer_index_set(PointerRNA *ptr, int value)
+{
+ CacheFile *cache_file = (CacheFile *)ptr->owner_id;
+ cache_file->active_layer = value + 1;
+}
+
+static void rna_CacheFile_active_layer_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ CacheFile *cache_file = (CacheFile *)ptr->owner_id;
+
+ *min = 0;
+ *max = max_ii(0, BLI_listbase_count(&cache_file->layers) - 1);
+}
+
+static void rna_CacheFileLayer_hidden_flag_set(PointerRNA *ptr, const bool value)
+{
+ CacheFileLayer *layer = (CacheFileLayer *)ptr->data;
+
+ if (value) {
+ layer->flag |= CACHEFILE_LAYER_HIDDEN;
+ }
+ else {
+ layer->flag &= ~CACHEFILE_LAYER_HIDDEN;
+ }
+}
+
+static CacheFileLayer *rna_CacheFile_layer_new(CacheFile *cache_file,
+ bContext *C,
+ ReportList *reports,
+ const char *filepath)
+{
+ CacheFileLayer *layer = BKE_cachefile_add_layer(cache_file, filepath);
+ if (layer == NULL) {
+ BKE_reportf(
+ reports, RPT_ERROR, "Cannot add a layer to CacheFile '%s'", cache_file->id.name + 2);
+ return NULL;
+ }
+
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ BKE_cachefile_reload(depsgraph, cache_file);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ return layer;
+}
+
+static void rna_CacheFile_layer_remove(CacheFile *cache_file, bContext *C, PointerRNA *layer_ptr)
+{
+ CacheFileLayer *layer = layer_ptr->data;
+ BKE_cachefile_remove_layer(cache_file, layer);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ BKE_cachefile_reload(depsgraph, cache_file);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+}
+
#else
/* cachefile.object_paths */
@@ -94,6 +188,61 @@ static void rna_def_cachefile_object_paths(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_struct_ui_text(srna, "Object Paths", "Collection of object paths");
}
+static void rna_def_cachefile_layer(BlenderRNA *brna)
+{
+ StructRNA *srna = RNA_def_struct(brna, "CacheFileLayer", NULL);
+ RNA_def_struct_sdna(srna, "CacheFileLayer");
+ RNA_def_struct_ui_text(
+ srna,
+ "Cache Layer",
+ "Layer of the cache, used to load or override data from the first the first layer");
+
+ PropertyRNA *prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_ui_text(prop, "File Path", "Path to the archive");
+ RNA_def_property_update(prop, 0, "rna_CacheFileLayer_update");
+
+ prop = RNA_def_property(srna, "hide_layer", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CACHEFILE_LAYER_HIDDEN);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_CacheFileLayer_hidden_flag_set");
+ RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
+ RNA_def_property_ui_text(prop, "Hide Layer", "Do not load data from this layer");
+ RNA_def_property_update(prop, 0, "rna_CacheFileLayer_update");
+}
+
+static void rna_def_cachefile_layers(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ RNA_def_property_srna(cprop, "CacheFileLayers");
+ StructRNA *srna = RNA_def_struct(brna, "CacheFileLayers", NULL);
+ RNA_def_struct_sdna(srna, "CacheFile");
+ RNA_def_struct_ui_text(srna, "Cache Layers", "Collection of cache layers");
+
+ PropertyRNA *prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "CacheFileLayer");
+ RNA_def_property_pointer_funcs(
+ prop, "rna_CacheFile_active_layer_get", "rna_CacheFile_active_layer_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Active Layer", "Active layer of the CacheFile");
+
+ /* Add a layer. */
+ FunctionRNA *func = RNA_def_function(srna, "new", "rna_CacheFile_layer_new");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Add a new layer");
+ PropertyRNA *parm = RNA_def_string(
+ func, "filepath", "File Path", 0, "", "File path to the archive used as a layer");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* Return type. */
+ parm = RNA_def_pointer(func, "layer", "CacheFileLayer", "", "Newly created layer");
+ RNA_def_function_return(func, parm);
+
+ /* Remove a layer. */
+ func = RNA_def_function(srna, "remove", "rna_CacheFile_layer_remove");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Remove an existing layer from the cache file");
+ parm = RNA_def_pointer(func, "layer", "CacheFileLayer", "", "Layer to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+}
+
static void rna_def_cachefile(BlenderRNA *brna)
{
StructRNA *srna = RNA_def_struct(brna, "CacheFile", "ID");
@@ -234,6 +383,23 @@ static void rna_def_cachefile(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_CacheFile_update");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ /* ----------------- Alembic Layers ----------------- */
+
+ prop = RNA_def_property(srna, "layers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "layers", NULL);
+ RNA_def_property_struct_type(prop, "CacheFileLayer");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Cache Layers", "Layers of the cache");
+ rna_def_cachefile_layers(brna, prop);
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_int_sdna(prop, NULL, "active_layer");
+ RNA_def_property_int_funcs(prop,
+ "rna_CacheFile_active_layer_index_get",
+ "rna_CacheFile_active_layer_index_set",
+ "rna_CacheFile_active_layer_index_range");
+
RNA_define_lib_overridable(false);
rna_def_cachefile_object_paths(brna, prop);
@@ -245,6 +411,7 @@ void RNA_def_cachefile(BlenderRNA *brna)
{
rna_def_cachefile(brna);
rna_def_alembic_object_path(brna);
+ rna_def_cachefile_layer(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c
index 2bc00dd5af5..187e232b030 100644
--- a/source/blender/makesrna/intern/rna_cloth.c
+++ b/source/blender/makesrna/intern/rna_cloth.c
@@ -584,6 +584,8 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "ClothSimSettings");
RNA_def_struct_path_func(srna, "rna_ClothSettings_path");
+ RNA_define_lib_overridable(true);
+
/* goal */
prop = RNA_def_property(srna, "goal_min", PROP_FLOAT, PROP_FACTOR);
@@ -659,6 +661,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_mass_vgroup_get",
"rna_ClothSettings_mass_vgroup_length",
"rna_ClothSettings_mass_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Mass Vertex Group", "Vertex Group for pinning of vertices");
RNA_def_property_update(prop, 0, "rna_cloth_pinning_changed");
@@ -707,6 +710,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_shrink_vgroup_get",
"rna_ClothSettings_shrink_vgroup_length",
"rna_ClothSettings_shrink_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Shrink Vertex Group", "Vertex Group for shrinking cloth");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -810,6 +814,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_struct_vgroup_get",
"rna_ClothSettings_struct_vgroup_length",
"rna_ClothSettings_struct_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop,
"Structural Stiffness Vertex Group",
"Vertex group for fine control over structural stiffness");
@@ -820,6 +825,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_shear_vgroup_get",
"rna_ClothSettings_shear_vgroup_length",
"rna_ClothSettings_shear_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop, "Shear Stiffness Vertex Group", "Vertex group for fine control over shear stiffness");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -856,6 +862,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_bend_vgroup_get",
"rna_ClothSettings_bend_vgroup_length",
"rna_ClothSettings_bend_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop,
"Bending Stiffness Vertex Group",
"Vertex group for fine control over bending stiffness");
@@ -874,6 +881,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_rest_shape_key_set",
NULL,
NULL);
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop, "Rest Shape Key", "Shape key to use the rest spring lengths from");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -976,6 +984,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_internal_vgroup_get",
"rna_ClothSettings_internal_vgroup_length",
"rna_ClothSettings_internal_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop,
"Internal Springs Vertex Group",
"Vertex group for fine control over the internal spring stiffness");
@@ -1044,6 +1053,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_pressure_vgroup_get",
"rna_ClothSettings_pressure_vgroup_length",
"rna_ClothSettings_pressure_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop,
"Pressure Vertex Group",
@@ -1082,6 +1092,8 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Maximum Spring Extension", "Maximum extension before spring gets cut");
# endif
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_cloth_collision_settings(BlenderRNA *brna)
@@ -1097,6 +1109,8 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "ClothCollSettings");
RNA_def_struct_path_func(srna, "rna_ClothCollisionSettings_path");
+ RNA_define_lib_overridable(true);
+
/* general collision */
prop = RNA_def_property(srna, "use_collision", PROP_BOOLEAN, PROP_NONE);
@@ -1169,7 +1183,6 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "collection", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "group");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Collision Collection", "Limit colliders to this Collection");
RNA_def_property_update(prop, 0, "rna_cloth_dependency_update");
@@ -1178,6 +1191,7 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
"rna_CollSettings_selfcol_vgroup_get",
"rna_CollSettings_selfcol_vgroup_length",
"rna_CollSettings_selfcol_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop,
"Selfcollision Vertex Group",
@@ -1189,6 +1203,7 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
"rna_CollSettings_objcol_vgroup_get",
"rna_CollSettings_objcol_vgroup_length",
"rna_CollSettings_objcol_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop,
"Collision Vertex Group",
@@ -1203,6 +1218,8 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
"Impulse Clamping",
"Clamp collision impulses to avoid instability (0.0 to disable clamping)");
RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ RNA_define_lib_overridable(false);
}
void RNA_def_cloth(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 5c12fc3a227..b12ec4651b4 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -26,6 +26,8 @@
#include "BLI_utildefines.h"
+#include "BKE_node_tree_update.h"
+
#include "RNA_define.h"
#include "rna_internal.h"
@@ -321,7 +323,8 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
CMP_NODE_VALTORGB,
TEX_NODE_VALTORGB,
GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP)) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
}
break;
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 5968c8bac8f..0c993660f39 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -3446,7 +3446,8 @@ static void rna_def_constraint_transform_cache(BlenderRNA *brna)
RNA_define_lib_overridable(false);
}
-/* base struct for constraints */
+/* Define the base struct for constraints. */
+
void RNA_def_constraint(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3474,6 +3475,15 @@ void RNA_def_constraint(BlenderRNA *brna)
RNA_def_property_enum_items(prop, rna_enum_constraint_type_items);
RNA_def_property_ui_text(prop, "Type", "");
+ prop = RNA_def_boolean(srna,
+ "is_override_data",
+ false,
+ "Override Constraint",
+ "In a local override object, whether this constraint comes from the "
+ "linked reference object, or is local to the override");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONSTRAINT_OVERRIDE_LIBRARY_LOCAL);
+
RNA_define_lib_overridable(true);
prop = RNA_def_property(srna, "owner_space", PROP_ENUM, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 0bfb1200f49..86ed0f307c4 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -30,7 +30,7 @@
#include "BLT_translation.h"
-#include "BKE_font.h"
+#include "BKE_vfont.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -141,8 +141,6 @@ const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = {
static const EnumPropertyItem curve_type_items[] = {
{CU_POLY, "POLY", 0, "Poly", ""},
{CU_BEZIER, "BEZIER", 0, "Bezier", ""},
- {CU_BSPLINE, "BSPLINE", 0, "BSpline", ""},
- {CU_CARDINAL, "CARDINAL", 0, "Cardinal", ""},
{CU_NURBS, "NURBS", 0, "Ease", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -455,8 +453,8 @@ static void rna_Curve_bevelObject_set(PointerRNA *ptr,
Object *ob = (Object *)value.data;
if (ob) {
- /* if bevel object has got the save curve, as object, for which it's */
- /* set as bevobj, there could be infinity loop in displist calculation */
+ /* If bevel object has got the save curve, as object, for which it's set as bevobj,
+ * there could be infinity loop in #DispList calculation. */
if (ob->type == OB_CURVE && ob->data != cu) {
cu->bevobj = ob;
id_lib_extern((ID *)ob);
@@ -530,8 +528,8 @@ static void rna_Curve_taperObject_set(PointerRNA *ptr,
Object *ob = (Object *)value.data;
if (ob) {
- /* if taper object has got the save curve, as object, for which it's */
- /* set as bevobj, there could be infinity loop in displist calculation */
+ /* If taper object has got the save curve, as object, for which it's set as bevobj,
+ * there could be infinity loop in #DispList calculation. */
if (ob->type == OB_CURVE && ob->data != cu) {
cu->taperobj = ob;
id_lib_extern((ID *)ob);
@@ -569,13 +567,13 @@ static void rna_Curve_resolution_v_update_data(Main *bmain, Scene *scene, Pointe
static float rna_Curve_offset_get(PointerRNA *ptr)
{
Curve *cu = (Curve *)ptr->owner_id;
- return cu->width - 1.0f;
+ return cu->offset - 1.0f;
}
static void rna_Curve_offset_set(PointerRNA *ptr, float value)
{
Curve *cu = (Curve *)ptr->owner_id;
- cu->width = 1.0f + value;
+ cu->offset = 1.0f + value;
}
static int rna_Curve_body_length(PointerRNA *ptr);
@@ -1656,14 +1654,14 @@ static void rna_def_curve(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Curve_bevel_resolution_update");
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
- RNA_def_property_float_sdna(prop, NULL, "width");
+ RNA_def_property_float_sdna(prop, NULL, "offset");
RNA_def_property_ui_range(prop, -1.0, 1.0, 0.1, 3);
RNA_def_property_float_funcs(prop, "rna_Curve_offset_get", "rna_Curve_offset_set", NULL);
RNA_def_property_ui_text(prop, "Offset", "Distance to move the curve parallel to its normals");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "extrude", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
- RNA_def_property_float_sdna(prop, NULL, "ext1");
+ RNA_def_property_float_sdna(prop, NULL, "extrude");
RNA_def_property_ui_range(prop, 0, 100.0, 0.1, 3);
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_text(prop,
@@ -1673,7 +1671,7 @@ static void rna_def_curve(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "bevel_depth", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
- RNA_def_property_float_sdna(prop, NULL, "ext2");
+ RNA_def_property_float_sdna(prop, NULL, "bevel_radius");
RNA_def_property_ui_range(prop, 0, 100.0, 0.1, 3);
RNA_def_property_ui_text(
prop, "Bevel Depth", "Radius of the bevel geometry, not including extrusion");
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index bd5ade36eaa..b17ca7d8d59 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -753,10 +753,6 @@ void RNA_define_verify_sdna(bool verify)
DefRNA.verify = verify;
}
-/**
- * Properties defined when this is enabled are lib-overridable by default (except for Pointer
- * ones).
- */
void RNA_define_lib_overridable(const bool make_overridable)
{
DefRNA.make_overridable = make_overridable;
@@ -915,7 +911,6 @@ static StructDefRNA *rna_find_def_struct(StructRNA *srna)
return NULL;
}
-/* Struct Definition */
StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRNA *srnafrom)
{
StructRNA *srna;
@@ -1243,9 +1238,6 @@ void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *id
srna->identifier = identifier;
}
-/**
- * Only used in one case when we name the struct for the purpose of useful error messages.
- */
void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier)
{
if (DefRNA.preprocess) {
@@ -1532,13 +1524,6 @@ void RNA_def_property_override_clear_flag(PropertyRNA *prop, PropertyOverrideFla
prop->flag_override &= ~flag;
}
-/**
- * Add the property-tags passed as \a tags to \a prop (if valid).
- *
- * \note Multiple tags can be set by passing them within \a tags (using bitflags).
- * \note Doesn't do any type-checking with the tags defined in the parent StructRNA
- * of \a prop. This should be done before (e.g. see #WM_operatortype_prop_tag).
- */
void RNA_def_property_tags(PropertyRNA *prop, int tags)
{
prop->tags |= tags;
@@ -1616,12 +1601,10 @@ void RNA_def_property_array(PropertyRNA *prop, int length)
}
}
-/* common args for defaults. */
const float rna_default_quaternion[4] = {1, 0, 0, 0};
const float rna_default_axis_angle[4] = {0, 0, 1, 0};
const float rna_default_scale_3d[3] = {1, 1, 1};
-/* common args for length */
const int rna_matrix_dimsize_3x3[] = {3, 3};
const int rna_matrix_dimsize_4x4[] = {4, 4};
const int rna_matrix_dimsize_4x2[] = {4, 2};
@@ -1692,17 +1675,6 @@ void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, int consecutive)
}
}
-/**
- * The values hare are a little confusing:
- *
- * \param step: Used as the value to increase/decrease when clicking on number buttons,
- * as well as scaling mouse input for click-dragging number buttons.
- * For floats this is (step * UI_PRECISION_FLOAT_SCALE), why? - nobody knows.
- * For ints, whole values are used.
- *
- * \param precision: The number of zeros to show
- * (as a whole number - common range is 1 - 6), see UI_PRECISION_FLOAT_MAX
- */
void RNA_def_property_ui_range(
PropertyRNA *prop, double min, double max, double step, int precision)
{
@@ -2082,7 +2054,6 @@ void RNA_def_property_float_default(PropertyRNA *prop, float value)
break;
}
}
-/* array must remain valid after this function finishes */
void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array)
{
StructRNA *srna = DefRNA.laststruct;
@@ -2920,11 +2891,6 @@ void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editabl
}
}
-/**
- * Set custom callbacks for override operations handling.
- *
- * \note \a diff callback will also be used by RNA comparison/equality functions.
- */
void RNA_def_property_override_funcs(PropertyRNA *prop,
const char *diff,
const char *store,
@@ -3813,7 +3779,6 @@ PropertyRNA *RNA_def_enum(StructOrFunctionRNA *cont_,
return prop;
}
-/* same as above but sets 'PROP_ENUM_FLAG' before setting the default value */
PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont_,
const char *identifier,
const EnumPropertyItem *items,
@@ -4320,7 +4285,6 @@ FunctionRNA *RNA_def_function_runtime(StructRNA *srna, const char *identifier, C
return func;
}
-/* C return value only!, multiple RNA returns can be done with RNA_def_function_output */
void RNA_def_function_return(FunctionRNA *func, PropertyRNA *ret)
{
if (ret->flag & PROP_DYNAMIC) {
diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c
index 85071e8cd19..58565fecf4d 100644
--- a/source/blender/makesrna/intern/rna_depsgraph.c
+++ b/source/blender/makesrna/intern/rna_depsgraph.c
@@ -207,8 +207,10 @@ static bool rna_DepsgraphUpdate_is_updated_transform_get(PointerRNA *ptr)
static bool rna_DepsgraphUpdate_is_updated_shading_get(PointerRNA *ptr)
{
+ /* Assume any animated parameters can affect shading, we don't have fine
+ * grained enough updates to distinguish this. */
ID *id = ptr->data;
- return ((id->recalc & ID_RECALC_SHADING) != 0);
+ return ((id->recalc & (ID_RECALC_SHADING | ID_RECALC_ANIMATION)) != 0);
}
static bool rna_DepsgraphUpdate_is_updated_geometry_get(PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index a9d5ef089bb..b693d78a302 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -589,6 +589,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
prop = RNA_def_property(srna, "drip_velocity", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index a38bbd3d6d2..0e2b64fbca4 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -388,6 +388,7 @@ void rna_DriverVariable_name_set(PointerRNA *ptr, const char *value)
BLI_strncpy_utf8(data->name, value, 64);
driver_variable_name_validate(data);
+ driver_variable_unique_name(data);
}
/* ----------- */
@@ -1013,7 +1014,7 @@ static void rna_FKeyframe_points_add(ID *id, FCurve *fcu, Main *bmain, int tot)
fcu->totvert += tot;
while (tot--) {
- /* defaults, no userprefs gives predictable results for API */
+ /* Defaults, ignoring user-preference gives predictable results for API. */
bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
bezt->ipo = BEZT_IPO_BEZ;
bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index 90e77406f23..7aa96eb8430 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -1461,6 +1461,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
/* object collections */
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 2bce5f3f4b3..3f380cd1830 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -906,7 +906,8 @@ static void rna_GPencil_stroke_remove(ID *id,
return;
}
- BLI_freelinkN(&frame->strokes, stroke);
+ BLI_remlink(&frame->strokes, stroke);
+ BKE_gpencil_free_stroke(stroke);
RNA_POINTER_INVALIDATE(stroke_ptr);
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 675cff3e58c..e4e594cd8cf 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -28,6 +28,7 @@
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -144,6 +145,11 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
ICON_MOD_OFFSET,
"Offset",
"Change stroke location, rotation or scale"},
+ {eGpencilModifierType_Shrinkwrap,
+ "SHRINKWRAP",
+ ICON_MOD_SHRINKWRAP,
+ "Shrinkwrap",
+ "Project the shape onto another object"},
{eGpencilModifierType_Smooth, "GP_SMOOTH", ICON_MOD_SMOOTH, "Smooth", "Smooth stroke"},
{eGpencilModifierType_Thick,
"GP_THICK",
@@ -167,14 +173,14 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
#ifndef RNA_RUNTIME
static const EnumPropertyItem modifier_modify_color_items[] = {
- {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke and Fill", "Modify fill and stroke colors"},
+ {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke & Fill", "Modify fill and stroke colors"},
{GP_MODIFY_COLOR_STROKE, "STROKE", 0, "Stroke", "Modify stroke color only"},
{GP_MODIFY_COLOR_FILL, "FILL", 0, "Fill", "Modify fill color only"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem modifier_modify_opacity_items[] = {
- {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke and Fill", "Modify fill and stroke colors"},
+ {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke & Fill", "Modify fill and stroke colors"},
{GP_MODIFY_COLOR_STROKE, "STROKE", 0, "Stroke", "Modify stroke color only"},
{GP_MODIFY_COLOR_FILL, "FILL", 0, "Fill", "Modify fill color only"},
{GP_MODIFY_COLOR_HARDNESS, "HARDNESS", 0, "Hardness", "Modify stroke hardness"},
@@ -269,6 +275,8 @@ static StructRNA *rna_GpencilModifier_refine(struct PointerRNA *ptr)
return &RNA_LengthGpencilModifier;
case eGpencilModifierType_Mirror:
return &RNA_MirrorGpencilModifier;
+ case eGpencilModifierType_Shrinkwrap:
+ return &RNA_ShrinkwrapGpencilModifier;
case eGpencilModifierType_Smooth:
return &RNA_SmoothGpencilModifier;
case eGpencilModifierType_Hook:
@@ -360,6 +368,7 @@ RNA_GP_MOD_VGROUP_NAME_SET(WeightProx, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(WeightAngle, target_vgname);
RNA_GP_MOD_VGROUP_NAME_SET(WeightAngle, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(Lineart, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Shrinkwrap, vgname);
# undef RNA_GP_MOD_VGROUP_NAME_SET
@@ -392,6 +401,8 @@ RNA_GP_MOD_OBJECT_SET(Armature, object, OB_ARMATURE);
RNA_GP_MOD_OBJECT_SET(Lattice, object, OB_LATTICE);
RNA_GP_MOD_OBJECT_SET(Mirror, object, OB_EMPTY);
RNA_GP_MOD_OBJECT_SET(WeightProx, object, OB_EMPTY);
+RNA_GP_MOD_OBJECT_SET(Shrinkwrap, target, OB_MESH);
+RNA_GP_MOD_OBJECT_SET(Shrinkwrap, aux_target, OB_MESH);
# undef RNA_GP_MOD_OBJECT_SET
@@ -685,6 +696,16 @@ static void rna_TextureGpencilModifier_material_set(PointerRNA *ptr,
rna_GpencilModifier_material_set(ptr, value, ma_target, reports);
}
+static void rna_ShrinkwrapGpencilModifier_material_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *reports)
+{
+ ShrinkwrapGpencilModifierData *tmd = (ShrinkwrapGpencilModifierData *)ptr->data;
+ Material **ma_target = &tmd->material;
+
+ rna_GpencilModifier_material_set(ptr, value, ma_target, reports);
+}
+
static void rna_Lineart_start_level_set(PointerRNA *ptr, int value)
{
LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)ptr->data;
@@ -756,6 +777,18 @@ static void rna_DashGpencilModifierSegment_name_set(PointerRNA *ptr, const char
BKE_animdata_fix_paths_rename_all(NULL, prefix, oldname, ds->name);
}
+static int rna_ShrinkwrapGpencilModifier_face_cull_get(PointerRNA *ptr)
+{
+ ShrinkwrapGpencilModifierData *swm = (ShrinkwrapGpencilModifierData *)ptr->data;
+ return swm->shrink_opts & MOD_SHRINKWRAP_CULL_TARGET_MASK;
+}
+
+static void rna_ShrinkwrapGpencilModifier_face_cull_set(struct PointerRNA *ptr, int value)
+{
+ ShrinkwrapGpencilModifierData *swm = (ShrinkwrapGpencilModifierData *)ptr->data;
+ swm->shrink_opts = (swm->shrink_opts & ~MOD_SHRINKWRAP_CULL_TARGET_MASK) | value;
+}
+
#else
static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
@@ -1309,7 +1342,7 @@ static void rna_def_modifier_gpencilthick(BlenderRNA *brna)
prop, "Custom Curve", "Use a custom curve to define thickness change along the strokes");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "normalize_thickness", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_normalized_thickness", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_NORMALIZE);
RNA_def_property_ui_text(prop, "Uniform Thickness", "Replace the stroke thickness");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
@@ -1450,7 +1483,7 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna)
static EnumPropertyItem tint_mode_types_items[] = {
{GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Vertex Color affects to Stroke only"},
{GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Vertex Color affects to Fill only"},
- {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Vertex Color affects to Stroke and Fill"},
+ {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", "Vertex Color affects to Stroke and Fill"},
{0, NULL, 0, NULL, NULL},
};
@@ -1865,7 +1898,7 @@ static void rna_def_modifier_gpencilopacity(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "normalize_opacity", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_normalized_opacity", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_NORMALIZE);
RNA_def_property_ui_text(prop, "Uniform Opacity", "Replace the stroke opacity");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_opacity_update");
@@ -2677,7 +2710,7 @@ static void rna_def_modifier_gpenciltexture(BlenderRNA *brna)
{STROKE_AND_FILL,
"STROKE_AND_FILL",
0,
- "Stroke and Fill",
+ "Stroke & Fill",
"Manipulate both stroke and fill texture coordinates"},
{0, NULL, 0, NULL, NULL},
};
@@ -2943,7 +2976,7 @@ static void rna_def_modifier_gpencilweight_angle(BlenderRNA *brna)
};
srna = RNA_def_struct(brna, "WeightAngleGpencilModifier", "GpencilModifier");
- RNA_def_struct_ui_text(srna, "Weight Modifier Amgle", "Calculate Vertex Weight dynamically");
+ RNA_def_struct_ui_text(srna, "Weight Modifier Angle", "Calculate Vertex Weight dynamically");
RNA_def_struct_sdna(srna, "WeightAngleGpencilModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_VERTEX_WEIGHT);
@@ -3073,6 +3106,12 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_define_lib_overridable(true);
+ prop = RNA_def_property(srna, "use_custom_camera", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_USE_CUSTOM_CAMERA);
+ RNA_def_property_ui_text(
+ prop, "Use Custom Camera", "Use custom camera instead of the active camera");
+ RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "use_fuzzy_intersections", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_INTERSECTION_AS_CONTOUR);
RNA_def_property_ui_text(prop,
@@ -3172,6 +3211,12 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
prop, "Boundaries", "Filter feature lines based on face mark boundaries");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "use_face_mark_keep_contour", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "calculation_flags", LRT_FILTER_FACE_MARK_KEEP_CONTOUR);
+ RNA_def_property_ui_text(prop, "Keep Contour", "Preserve contour lines while filtering");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "chaining_image_threshold", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_ui_text(
prop,
@@ -3192,6 +3237,12 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
prop, "Use Geometry Space", "Use geometry distance for chaining instead of image space");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "use_detail_preserve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_CHAIN_PRESERVE_DETAILS);
+ RNA_def_property_ui_text(
+ prop, "Preserve Details", "Keep the zig-zag \"noise\" in initial chaining");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "use_overlap_edge_type_support", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_ALLOW_OVERLAP_EDGE_TYPES);
RNA_def_property_ui_text(prop,
@@ -3200,6 +3251,30 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
"separate stroke for each overlapping type");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "stroke_depth_offset", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_ui_text(prop,
+ "Stroke Depth Offset",
+ "Move strokes slightly towards the camera to avoid clipping while "
+ "preserve depth for the viewport");
+ RNA_def_property_ui_range(prop, 0.0, 0.5, 0.001, 4);
+ RNA_def_property_range(prop, -0.1, FLT_MAX);
+ RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_offset_towards_custom_camera", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA);
+ RNA_def_property_ui_text(prop,
+ "Offset Towards Custom Camera",
+ "Offset strokes towards selected camera instead of the active camera");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "source_camera", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(
+ prop, "Camera Object", "Use specified camera object for generating line art");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
prop = RNA_def_property(srna, "source_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, modifier_lineart_source_type);
RNA_def_property_ui_text(prop, "Source Type", "Line art stroke source type");
@@ -3375,6 +3450,29 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Crease On Sharp Edges", "Allow crease to show on sharp edges");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "use_image_boundary_trimming", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_USE_IMAGE_BOUNDARY_TRIMMING);
+ RNA_def_property_ui_text(
+ prop,
+ "Image Boundary Trimming",
+ "Trim all edges right at the boundary of image(including overscan region)");
+
+ prop = RNA_def_property(srna, "use_back_face_culling", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_USE_BACK_FACE_CULLING);
+ RNA_def_property_ui_text(
+ prop,
+ "Back Face Culling",
+ "Remove all back faces to speed up calculation, this will create edges in "
+ "different occlusion levels than when disabled");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_invert_collection", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_INVERT_COLLECTION);
+ RNA_def_property_ui_text(prop,
+ "Invert Collection Filtering",
+ "Select everything except lines from specified collection");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
RNA_define_lib_overridable(false);
}
@@ -3417,6 +3515,43 @@ static void rna_def_modifier_gpencillength(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "End Factor", "Absolute added length to the end of each stroke");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "random_start_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "rand_start_fac");
+ RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.1, 1);
+ RNA_def_property_ui_text(
+ prop, "Random Start Factor", "Size of random length added to the start of each stroke");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "random_end_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "rand_end_fac");
+ RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.1, 1);
+ RNA_def_property_ui_text(
+ prop, "Random End Factor", "Size of random length added to the end of each stroke");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "random_offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "rand_offset");
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 0.1, 3);
+ RNA_def_property_ui_text(
+ prop, "Random Noise Offset", "Smoothly offset each stroke's random value");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_random", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LENGTH_USE_RANDOM);
+ RNA_def_property_ui_text(prop, "Random", "Use random values over time");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_ui_text(prop, "Seed", "Random seed");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "step");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_text(
+ prop, "Step", "Number of frames before recalculate random values again");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "overshoot_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overshoot_fac");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -3589,7 +3724,7 @@ static void rna_def_modifier_gpencildash(BlenderRNA *brna)
prop = RNA_def_property(srna, "segment_active_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Active Dash Segement Index", "Active index in the segment list");
+ RNA_def_property_ui_text(prop, "Active Dash Segment Index", "Active index in the segment list");
prop = RNA_def_property(srna, "dash_offset", PROP_INT, PROP_NONE);
RNA_def_property_ui_text(
@@ -3645,6 +3780,194 @@ static void rna_def_modifier_gpencildash(BlenderRNA *brna)
RNA_define_lib_overridable(false);
}
+static void rna_def_modifier_gpencilshrinkwrap(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShrinkwrapGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna,
+ "Shrinkwrap Modifier",
+ "Shrink wrapping modifier to shrink wrap and object to a target");
+ RNA_def_struct_sdna(srna, "ShrinkwrapGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_SHRINKWRAP);
+
+ RNA_define_lib_overridable(true);
+
+ prop = RNA_def_property(srna, "wrap_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "shrink_type");
+ RNA_def_property_enum_items(prop, rna_enum_shrinkwrap_type_items);
+ RNA_def_property_ui_text(prop, "Wrap Method", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "wrap_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "shrink_mode");
+ RNA_def_property_enum_items(prop, rna_enum_modifier_shrinkwrap_mode_items);
+ RNA_def_property_ui_text(
+ prop, "Snap Mode", "Select how vertices are constrained to the target surface");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "cull_face", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "shrink_opts");
+ RNA_def_property_enum_items(prop, rna_enum_shrinkwrap_face_cull_items);
+ RNA_def_property_enum_funcs(prop,
+ "rna_ShrinkwrapGpencilModifier_face_cull_get",
+ "rna_ShrinkwrapGpencilModifier_face_cull_set",
+ NULL);
+ RNA_def_property_ui_text(
+ prop,
+ "Face Cull",
+ "Stop vertices from projecting to a face on the target when facing towards/away");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Target", "Mesh target to shrink to");
+ RNA_def_property_pointer_funcs(
+ prop, NULL, "rna_ShrinkwrapGpencilModifier_target_set", NULL, "rna_Mesh_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "auxiliary_target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "aux_target");
+ RNA_def_property_ui_text(prop, "Auxiliary Target", "Additional mesh target to shrink to");
+ RNA_def_property_pointer_funcs(
+ prop, NULL, "rna_ShrinkwrapGpencilModifier_aux_target_set", NULL, "rna_Mesh_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "keep_dist");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -100, 100, 1, 2);
+ RNA_def_property_ui_text(prop, "Offset", "Distance to keep from the target");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "project_limit", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "proj_limit");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 100, 1, 2);
+ RNA_def_property_ui_text(
+ prop, "Project Limit", "Limit the distance used for projection (zero disables)");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_project_x", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "proj_axis", MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS);
+ RNA_def_property_ui_text(prop, "X", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_project_y", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "proj_axis", MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS);
+ RNA_def_property_ui_text(prop, "Y", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_project_z", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "proj_axis", MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS);
+ RNA_def_property_ui_text(prop, "Z", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "subsurf_levels", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "subsurf_levels");
+ RNA_def_property_range(prop, 0, 6);
+ RNA_def_property_ui_range(prop, 0, 6, 1, -1);
+ RNA_def_property_ui_text(
+ prop,
+ "Subdivision Levels",
+ "Number of subdivisions that must be performed before extracting vertices' "
+ "positions and normals");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_negative_direction", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "shrink_opts", MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR);
+ RNA_def_property_ui_text(
+ prop, "Negative", "Allow vertices to move in the negative direction of axis");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_positive_direction", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "shrink_opts", MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR);
+ RNA_def_property_ui_text(
+ prop, "Positive", "Allow vertices to move in the positive direction of axis");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_invert_cull", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "shrink_opts", MOD_SHRINKWRAP_INVERT_CULL_TARGET);
+ RNA_def_property_ui_text(
+ prop, "Invert Cull", "When projecting in the negative direction invert the face cull mode");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop,
+ NULL,
+ "rna_ShrinkwrapGpencilModifier_material_set",
+ NULL,
+ "rna_GpencilModifier_material_poll");
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ShrinkwrapGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SHRINKWRAP_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_materials", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SHRINKWRAP_INVERT_MATERIAL);
+ RNA_def_property_ui_text(prop, "Inverse Materials", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SHRINKWRAP_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SHRINKWRAP_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SHRINKWRAP_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "smooth_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "smooth_factor");
+ RNA_def_property_range(prop, 0, 1);
+ RNA_def_property_ui_text(prop, "Smooth Factor", "Amount of smoothing to apply");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "smooth_step", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "smooth_step");
+ RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_ui_text(
+ prop, "Step", "Number of times to apply smooth (high numbers can reduce FPS)");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ RNA_define_lib_overridable(false);
+}
+
void RNA_def_greasepencil_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3700,6 +4023,16 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Expanded", "Set modifier expanded in the user interface");
RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
+ prop = RNA_def_boolean(srna,
+ "is_override_data",
+ false,
+ "Override Modifier",
+ "In a local override object, whether this modifier comes from the linked "
+ "reference object, or is local to the override");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_negative_sdna(
+ prop, NULL, "flag", eGpencilModifierFlag_OverrideLibrary_Local);
+
/* types */
rna_def_modifier_gpencilnoise(brna);
rna_def_modifier_gpencilsmooth(brna);
@@ -3724,6 +4057,7 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna)
rna_def_modifier_gpencillineart(brna);
rna_def_modifier_gpencillength(brna);
rna_def_modifier_gpencildash(brna);
+ rna_def_modifier_gpencilshrinkwrap(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 2f42e521b52..0d86572357f 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -168,7 +168,7 @@ static void rna_ImageUser_update(Main *bmain, Scene *scene, PointerRNA *ptr)
if (id) {
if (GS(id->name) == ID_NT) {
/* Special update for nodetrees to find parent datablock. */
- ED_node_tag_update_nodetree(bmain, (bNodeTree *)id, NULL);
+ ED_node_tree_propagate_change(NULL, bmain, NULL);
}
else {
/* Update material or texture for render preview. */
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 06ff1918040..1c04805be8b 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -75,7 +75,6 @@ static void rna_Image_save_render(
void *lock;
iuser.scene = scene;
- iuser.ok = 1;
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
@@ -214,11 +213,17 @@ static void rna_Image_scale(Image *image, ReportList *reports, int width, int he
}
}
-static int rna_Image_gl_load(Image *image, ReportList *reports, int frame)
+static int rna_Image_gl_load(
+ Image *image, ReportList *reports, int frame, int layer_index, int pass_index)
{
ImageUser iuser;
BKE_imageuser_default(&iuser);
iuser.framenr = frame;
+ iuser.layer = layer_index;
+ iuser.pass = pass_index;
+ if (image->rr != NULL) {
+ BKE_image_multilayer_index(image->rr, &iuser);
+ }
GPUTexture *tex = BKE_image_get_gpu_texture(image, &iuser, NULL);
@@ -231,14 +236,15 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame)
return 0; /* GL_NO_ERROR */
}
-static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame)
+static int rna_Image_gl_touch(
+ Image *image, ReportList *reports, int frame, int layer_index, int pass_index)
{
int error = 0; /* GL_NO_ERROR */
BKE_image_tag_time(image);
- if (image->gputexture[TEXTARGET_2D][0] == NULL) {
- error = rna_Image_gl_load(image, reports, frame);
+ if (image->gputexture[TEXTARGET_2D][0][IMA_TEXTURE_RESOLUTION_FULL] == NULL) {
+ error = rna_Image_gl_load(image, reports, frame, layer_index, pass_index);
}
return error;
@@ -333,6 +339,24 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(
func, "frame", 0, 0, INT_MAX, "Frame", "Frame of image sequence or movie", 0, INT_MAX);
+ RNA_def_int(func,
+ "layer_index",
+ 0,
+ 0,
+ INT_MAX,
+ "Layer",
+ "Index of layer that should be loaded",
+ 0,
+ INT_MAX);
+ RNA_def_int(func,
+ "pass_index",
+ 0,
+ 0,
+ INT_MAX,
+ "Pass",
+ "Index of pass that should be loaded",
+ 0,
+ INT_MAX);
/* return value */
parm = RNA_def_int(
func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX);
@@ -347,6 +371,24 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(
func, "frame", 0, 0, INT_MAX, "Frame", "Frame of image sequence or movie", 0, INT_MAX);
+ RNA_def_int(func,
+ "layer_index",
+ 0,
+ 0,
+ INT_MAX,
+ "Layer",
+ "Index of layer that should be loaded",
+ 0,
+ INT_MAX);
+ RNA_def_int(func,
+ "pass_index",
+ 0,
+ 0,
+ INT_MAX,
+ "Pass",
+ "Index of pass that should be loaded",
+ 0,
+ INT_MAX);
/* return value */
parm = RNA_def_int(
func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX);
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index fd6664ff0de..4687e86916e 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -240,9 +240,9 @@ bool rna_AnimaData_override_apply(struct Main *bmain,
struct PropertyRNA *prop_local,
struct PropertyRNA *prop_reference,
struct PropertyRNA *prop_storage,
- const int len_local,
- const int len_reference,
- const int len_storage,
+ int len_local,
+ int len_reference,
+ int len_storage,
struct PointerRNA *ptr_item_local,
struct PointerRNA *ptr_item_reference,
struct PointerRNA *ptr_item_storage,
@@ -251,6 +251,9 @@ bool rna_AnimaData_override_apply(struct Main *bmain,
void rna_def_animviz_common(struct StructRNA *srna);
void rna_def_motionpath_common(struct StructRNA *srna);
+/**
+ * Settings for curved bbone settings.
+ */
void rna_def_bone_curved_common(struct StructRNA *srna, bool is_posebone, bool is_editbone);
void rna_def_texmat_common(struct StructRNA *srna, const char *texspace_editable);
@@ -265,9 +268,12 @@ void rna_def_mtex_common(struct BlenderRNA *brna,
const char *update,
const char *update_index);
void rna_def_texpaint_slots(struct BlenderRNA *brna, struct StructRNA *srna);
-void rna_def_view_layer_common(struct BlenderRNA *brna, struct StructRNA *srna, const bool scene);
+void rna_def_view_layer_common(struct BlenderRNA *brna, struct StructRNA *srna, bool scene);
int rna_AssetMetaData_editable(struct PointerRNA *ptr, const char **r_info);
+/**
+ * \note the UI text and updating has to be set by the caller.
+ */
PropertyRNA *rna_def_asset_library_reference_common(struct StructRNA *srna,
const char *get,
const char *set);
@@ -276,6 +282,9 @@ const EnumPropertyItem *rna_asset_library_reference_itemf(struct bContext *C,
struct PropertyRNA *prop,
bool *r_free);
+/**
+ * Common properties for Action/Bone Groups - related to color.
+ */
void rna_def_actionbone_group_common(struct StructRNA *srna,
int update_flag,
const char *update_cb);
@@ -437,7 +446,7 @@ void RNA_api_space_text(struct StructRNA *srna);
void RNA_api_space_filebrowser(struct StructRNA *srna);
void RNA_api_region_view3d(struct StructRNA *srna);
void RNA_api_texture(struct StructRNA *srna);
-void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastrip);
+void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, bool metastrip);
void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_api_sound(struct StructRNA *srna);
void RNA_api_vfont(struct StructRNA *srna);
@@ -482,9 +491,7 @@ void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop);
#ifdef WITH_HAIR_NODES
void RNA_def_main_hairs(BlenderRNA *brna, PropertyRNA *cprop);
#endif
-#ifdef WITH_POINT_CLOUD
void RNA_def_main_pointclouds(BlenderRNA *brna, PropertyRNA *cprop);
-#endif
void RNA_def_main_volumes(BlenderRNA *brna, PropertyRNA *cprop);
#ifdef WITH_SIMULATION_DATABLOCK
void RNA_def_main_simulations(BlenderRNA *brna, PropertyRNA *cprop);
@@ -509,8 +516,16 @@ extern StructRNA RNA_PropertyGroupItem;
extern StructRNA RNA_PropertyGroup;
#endif
+/**
+ * This function only returns an #IDProperty,
+ * or NULL (in case IDProp could not be found, or prop is a real RNA property).
+ */
struct IDProperty *rna_idproperty_check(struct PropertyRNA **prop,
struct PointerRNA *ptr) ATTR_WARN_UNUSED_RESULT;
+/**
+ * This function always return the valid, real data pointer, be it a regular RNA property one,
+ * or an #IDProperty one.
+ */
struct PropertyRNA *rna_ensure_property_realdata(struct PropertyRNA **prop,
struct PointerRNA *ptr) ATTR_WARN_UNUSED_RESULT;
struct PropertyRNA *rna_ensure_property(struct PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT;
@@ -524,11 +539,11 @@ struct PropertyRNA *rna_ensure_property(struct PropertyRNA *prop) ATTR_WARN_UNUS
int rna_property_override_diff_default(struct Main *bmain,
struct PropertyRNAOrID *prop_a,
struct PropertyRNAOrID *prop_b,
- const int mode,
+ int mode,
struct IDOverrideLibrary *override,
const char *rna_path,
- const size_t rna_path_len,
- const int flags,
+ size_t rna_path_len,
+ int flags,
bool *r_override_changed);
bool rna_property_override_store_default(struct Main *bmain,
@@ -538,9 +553,9 @@ bool rna_property_override_store_default(struct Main *bmain,
struct PropertyRNA *prop_local,
struct PropertyRNA *prop_reference,
struct PropertyRNA *prop_storage,
- const int len_local,
- const int len_reference,
- const int len_storage,
+ int len_local,
+ int len_reference,
+ int len_storage,
struct IDOverrideLibraryPropertyOperation *opop);
bool rna_property_override_apply_default(struct Main *bmain,
@@ -550,9 +565,9 @@ bool rna_property_override_apply_default(struct Main *bmain,
struct PropertyRNA *prop_dst,
struct PropertyRNA *prop_src,
struct PropertyRNA *prop_storage,
- const int len_dst,
- const int len_src,
- const int len_storage,
+ int len_dst,
+ int len_src,
+ int len_storage,
struct PointerRNA *ptr_item_dst,
struct PointerRNA *ptr_item_src,
struct PointerRNA *ptr_item_storage,
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index 29df7a53c44..723ae384fdf 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -211,11 +211,11 @@ typedef struct PropertyRNAOrID {
typedef int (*RNAPropOverrideDiff)(struct Main *bmain,
struct PropertyRNAOrID *prop_a,
struct PropertyRNAOrID *prop_b,
- const int mode,
+ int mode,
struct IDOverrideLibrary *override,
const char *rna_path,
- const size_t rna_path_len,
- const int flags,
+ size_t rna_path_len,
+ int flags,
bool *r_override_changed);
/**
@@ -235,9 +235,9 @@ typedef bool (*RNAPropOverrideStore)(struct Main *bmain,
struct PropertyRNA *prop_local,
struct PropertyRNA *prop_reference,
struct PropertyRNA *prop_storage,
- const int len_local,
- const int len_reference,
- const int len_storage,
+ int len_local,
+ int len_reference,
+ int len_storage,
struct IDOverrideLibraryPropertyOperation *opop);
/**
@@ -254,9 +254,9 @@ typedef bool (*RNAPropOverrideApply)(struct Main *bmain,
struct PropertyRNA *prop_dst,
struct PropertyRNA *prop_src,
struct PropertyRNA *prop_storage,
- const int len_dst,
- const int len_src,
- const int len_storage,
+ int len_dst,
+ int len_src,
+ int len_storage,
struct PointerRNA *ptr_item_dst,
struct PointerRNA *ptr_item_src,
struct PointerRNA *ptr_item_storage,
diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c
index 9d8ed161738..c7a1c89af63 100644
--- a/source/blender/makesrna/intern/rna_key.c
+++ b/source/blender/makesrna/intern/rna_key.c
@@ -541,7 +541,7 @@ static void rna_ShapeKey_data_begin_mixed(CollectionPropertyIterator *iter,
int point_count = rna_ShapeKey_curve_find_index(key, kb->totelem);
ShapeKeyCurvePoint *points = MEM_malloc_arrayN(
- sizeof(ShapeKeyCurvePoint), point_count, __func__);
+ point_count, sizeof(ShapeKeyCurvePoint), __func__);
char *databuf = kb->data;
int items_left = point_count;
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index ab4cbc429ce..b02a5c8dc1e 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -53,6 +53,8 @@
# include "BKE_node.h"
# include "BKE_scene.h"
+# include "NOD_composite.h"
+
# include "BLI_listbase.h"
# include "DEG_depsgraph_build.h"
diff --git a/source/blender/makesrna/intern/rna_light.c b/source/blender/makesrna/intern/rna_light.c
index 8bec337885e..003eebd8cc8 100644
--- a/source/blender/makesrna/intern/rna_light.c
+++ b/source/blender/makesrna/intern/rna_light.c
@@ -360,7 +360,7 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_SHAD_CONTACT);
RNA_def_property_ui_text(prop,
"Contact Shadow",
- "Use screen space raytracing to have correct shadowing "
+ "Use screen space ray-tracing to have correct shadowing "
"near occluder, or for small features that does not appear "
"in shadow maps");
RNA_def_property_update(prop, 0, "rna_Light_update");
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index 8cd1ac0d963..93e8e4bc31e 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -949,8 +949,9 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Period", "Period of the noise");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
- prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "seed");
+ RNA_def_property_range(prop, 1, SHRT_MAX);
RNA_def_property_ui_text(prop, "Seed", "Seed for the noise generation");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
@@ -1051,8 +1052,9 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Period", "Period of the noise");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
- prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "seed");
+ RNA_def_property_range(prop, 1, SHRT_MAX);
RNA_def_property_ui_text(prop, "Seed", "Seed for the noise generation");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
@@ -1191,8 +1193,9 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Period", "Period of the noise");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
- prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "seed");
+ RNA_def_property_range(prop, 1, SHRT_MAX);
RNA_def_property_ui_text(prop, "Seed", "Seed for the noise generation");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
@@ -1306,8 +1309,9 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
srna, "Sinus Displacement", "Add sinus displacement to stroke backbone geometry");
rna_def_geometry_modifier(srna);
- prop = RNA_def_property(srna, "wavelength", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "wavelength", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "wavelength");
+ RNA_def_property_range(prop, 0.0001f, FLT_MAX);
RNA_def_property_ui_text(prop, "Wavelength", "Wavelength of the sinus displacement");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index 464abc6b543..57a2a867d0a 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -56,9 +56,10 @@ static void rna_Main_use_autopack_set(PointerRNA *UNUSED(ptr), bool value)
}
}
-static bool rna_Main_is_saved_get(PointerRNA *UNUSED(ptr))
+static bool rna_Main_is_saved_get(PointerRNA *ptr)
{
- return G.relbase_valid;
+ const Main *bmain = (Main *)ptr->data;
+ return (bmain->filepath[0] != '\0');
}
static bool rna_Main_is_dirty_get(PointerRNA *ptr)
@@ -76,20 +77,20 @@ static bool rna_Main_is_dirty_get(PointerRNA *ptr)
static void rna_Main_filepath_get(PointerRNA *ptr, char *value)
{
Main *bmain = (Main *)ptr->data;
- BLI_strncpy(value, bmain->name, sizeof(bmain->name));
+ BLI_strncpy(value, bmain->filepath, sizeof(bmain->filepath));
}
static int rna_Main_filepath_length(PointerRNA *ptr)
{
Main *bmain = (Main *)ptr->data;
- return strlen(bmain->name);
+ return strlen(bmain->filepath);
}
# if 0
static void rna_Main_filepath_set(PointerRNA *ptr, const char *value)
{
Main *bmain = (Main *)ptr->data;
- BLI_strncpy(bmain->name, value, sizeof(bmain->name));
+ STRNCPY(bmain->filepath, value);
}
# endif
@@ -128,9 +129,7 @@ RNA_MAIN_LISTBASE_FUNCS_DEF(objects)
RNA_MAIN_LISTBASE_FUNCS_DEF(paintcurves)
RNA_MAIN_LISTBASE_FUNCS_DEF(palettes)
RNA_MAIN_LISTBASE_FUNCS_DEF(particles)
-# ifdef WITH_POINT_CLOUD
RNA_MAIN_LISTBASE_FUNCS_DEF(pointclouds)
-# endif
RNA_MAIN_LISTBASE_FUNCS_DEF(scenes)
RNA_MAIN_LISTBASE_FUNCS_DEF(screens)
RNA_MAIN_LISTBASE_FUNCS_DEF(shapekeys)
@@ -393,14 +392,12 @@ void RNA_def_main(BlenderRNA *brna)
# ifdef WITH_HAIR_NODES
{"hairs", "Hair", "rna_Main_hairs_begin", "Hairs", "Hair data-blocks", RNA_def_main_hairs},
# endif
-# ifdef WITH_POINT_CLOUD
{"pointclouds",
"PointCloud",
"rna_Main_pointclouds_begin",
"Point Clouds",
"Point cloud data-blocks",
RNA_def_main_pointclouds},
-# endif
{"volumes",
"Volume",
"rna_Main_volumes_begin",
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 9a33849b645..4344ed0dff5 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -47,7 +47,6 @@
# include "BKE_collection.h"
# include "BKE_curve.h"
# include "BKE_displist.h"
-# include "BKE_font.h"
# include "BKE_gpencil.h"
# include "BKE_hair.h"
# include "BKE_icons.h"
@@ -74,6 +73,7 @@
# include "BKE_speaker.h"
# include "BKE_text.h"
# include "BKE_texture.h"
+# include "BKE_vfont.h"
# include "BKE_volume.h"
# include "BKE_workspace.h"
# include "BKE_world.h"
@@ -778,7 +778,6 @@ static Hair *rna_Main_hairs_new(Main *bmain, const char *name)
}
# endif
-# ifdef WITH_POINT_CLOUD
static PointCloud *rna_Main_pointclouds_new(Main *bmain, const char *name)
{
char safe_name[MAX_ID_NAME - 2];
@@ -791,7 +790,6 @@ static PointCloud *rna_Main_pointclouds_new(Main *bmain, const char *name)
return pointcloud;
}
-# endif
static Volume *rna_Main_volumes_new(Main *bmain, const char *name)
{
@@ -866,9 +864,7 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(lightprobes, lightprobes, ID_LP)
# ifdef WITH_HAIR_NODES
RNA_MAIN_ID_TAG_FUNCS_DEF(hairs, hairs, ID_HA)
# endif
-# ifdef WITH_POINT_CLOUD
RNA_MAIN_ID_TAG_FUNCS_DEF(pointclouds, pointclouds, ID_PT)
-# endif
RNA_MAIN_ID_TAG_FUNCS_DEF(volumes, volumes, ID_VO)
# ifdef WITH_SIMULATION_DATABLOCK
RNA_MAIN_ID_TAG_FUNCS_DEF(simulations, simulations, ID_SIM)
@@ -2319,7 +2315,6 @@ void RNA_def_main_hairs(BlenderRNA *brna, PropertyRNA *cprop)
}
# endif
-# ifdef WITH_POINT_CLOUD
void RNA_def_main_pointclouds(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -2366,7 +2361,6 @@ void RNA_def_main_pointclouds(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
-# endif
void RNA_def_main_volumes(BlenderRNA *brna, PropertyRNA *cprop)
{
diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c
index 9c90c209389..21bacf2e6be 100644
--- a/source/blender/makesrna/intern/rna_mask.c
+++ b/source/blender/makesrna/intern/rna_mask.c
@@ -23,6 +23,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_defaults.h"
#include "DNA_mask_types.h"
#include "DNA_object_types.h" /* SELECT */
#include "DNA_scene_types.h"
@@ -84,7 +85,7 @@ static void rna_Mask_update_parent(Main *bmain, Scene *scene, PointerRNA *ptr)
if (track) {
MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_framenr);
float marker_pos_ofs[2], parmask_pos[2];
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
BKE_movieclip_user_set_frame(&user, scene->r.cfra);
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index fbc578acb8e..55b70fd1b41 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -317,18 +317,26 @@ static void rna_Mesh_update_facemask(Main *bmain, Scene *scene, PointerRNA *ptr)
static void rna_MeshVertex_normal_get(PointerRNA *ptr, float *value)
{
- MVert *mvert = (MVert *)ptr->data;
- normal_short_to_float_v3(value, mvert->no);
+ Mesh *mesh = rna_mesh(ptr);
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+
+ const int index = (MVert *)ptr->data - mesh->mvert;
+ BLI_assert(index >= 0);
+ BLI_assert(index < mesh->totvert);
+
+ copy_v3_v3(value, vert_normals[index]);
}
static void rna_MeshVertex_normal_set(PointerRNA *ptr, const float *value)
{
- MVert *mvert = (MVert *)ptr->data;
- float no[3];
+ Mesh *mesh = rna_mesh(ptr);
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh);
- copy_v3_v3(no, value);
- normalize_v3(no);
- normal_float_to_short_v3(mvert->no, no);
+ const int index = (MVert *)ptr->data - mesh->mvert;
+ BLI_assert(index >= 0);
+ BLI_assert(index < mesh->totvert);
+
+ copy_v3_v3(vert_normals[index], value);
}
static float rna_MeshVertex_bevel_weight_get(PointerRNA *ptr)
@@ -976,6 +984,30 @@ static int rna_MeshSkinVertexLayer_data_length(PointerRNA *ptr)
/* End skin vertices */
+/* Vertex creases */
+DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_crease, vdata, CD_CREASE)
+
+static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collection, int type);
+static char *rna_MeshVertexCreaseLayer_path(PointerRNA *ptr)
+{
+ return rna_VertCustomData_data_path(ptr, "vertex_creases", CD_CREASE);
+}
+
+static void rna_MeshVertexCreaseLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Mesh *me = rna_mesh(ptr);
+ CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
+ rna_iterator_array_begin(iter, layer->data, sizeof(float), me->totvert, 0, NULL);
+}
+
+static int rna_MeshVertexCreaseLayer_data_length(PointerRNA *ptr)
+{
+ Mesh *me = rna_mesh(ptr);
+ return me->totvert;
+}
+
+/* End vertex creases */
+
/* Paint mask */
DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_paint_mask, vdata, CD_PAINT_MASK)
@@ -1280,6 +1312,32 @@ static char *rna_LoopCustomData_data_path(PointerRNA *ptr, const char *collectio
return NULL;
}
+static void rna_Mesh_vertex_normals_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ const Mesh *mesh = rna_mesh(ptr);
+ const float(*normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ rna_iterator_array_begin(iter, (void *)normals, sizeof(float[3]), mesh->totvert, false, NULL);
+}
+
+static int rna_Mesh_vertex_normals_length(PointerRNA *ptr)
+{
+ const Mesh *mesh = rna_mesh(ptr);
+ return mesh->totvert;
+}
+
+static void rna_Mesh_poly_normals_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ const Mesh *mesh = rna_mesh(ptr);
+ const float(*normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
+ rna_iterator_array_begin(iter, (void *)normals, sizeof(float[3]), mesh->totpoly, false, NULL);
+}
+
+static int rna_Mesh_poly_normals_length(PointerRNA *ptr)
+{
+ const Mesh *mesh = rna_mesh(ptr);
+ return mesh->totpoly;
+}
+
static char *rna_MeshUVLoop_path(PointerRNA *ptr)
{
return rna_LoopCustomData_data_path(ptr, "uv_layers", CD_MLOOPUV);
@@ -1507,12 +1565,15 @@ static int rna_Mesh_tot_face_get(PointerRNA *ptr)
return me->edit_mesh ? me->edit_mesh->bm->totfacesel : 0;
}
-static PointerRNA rna_Mesh_vertex_color_new(struct Mesh *me, const char *name, const bool do_init)
+static PointerRNA rna_Mesh_vertex_color_new(struct Mesh *me,
+ ReportList *reports,
+ const char *name,
+ const bool do_init)
{
PointerRNA ptr;
CustomData *ldata;
CustomDataLayer *cdl = NULL;
- int index = ED_mesh_color_add(me, name, false, do_init);
+ int index = ED_mesh_color_add(me, name, false, do_init, reports);
if (index != -1) {
ldata = rna_mesh_ldata_helper(me);
@@ -1533,13 +1594,14 @@ static void rna_Mesh_vertex_color_remove(struct Mesh *me,
}
static PointerRNA rna_Mesh_sculpt_vertex_color_new(struct Mesh *me,
+ ReportList *reports,
const char *name,
const bool do_init)
{
PointerRNA ptr;
CustomData *vdata;
CustomDataLayer *cdl = NULL;
- int index = ED_mesh_sculpt_color_add(me, name, false, do_init);
+ int index = ED_mesh_sculpt_color_add(me, name, false, do_init, reports);
if (index != -1) {
vdata = rna_mesh_vdata_helper(me);
@@ -1591,12 +1653,15 @@ DEFINE_CUSTOMDATA_PROPERTY_API(
polygon, string, CD_PROP_STRING, pdata, totpoly, MeshPolygonStringPropertyLayer)
# undef DEFINE_CUSTOMDATA_PROPERTY_API
-static PointerRNA rna_Mesh_uv_layers_new(struct Mesh *me, const char *name, const bool do_init)
+static PointerRNA rna_Mesh_uv_layers_new(struct Mesh *me,
+ ReportList *reports,
+ const char *name,
+ const bool do_init)
{
PointerRNA ptr;
CustomData *ldata;
CustomDataLayer *cdl = NULL;
- int index = ED_mesh_uv_texture_add(me, name, false, do_init);
+ int index = ED_mesh_uv_texture_add(me, name, false, do_init, reports);
if (index != -1) {
ldata = rna_mesh_ldata_helper(me);
@@ -1634,6 +1699,7 @@ static void UNUSED_FUNCTION(rna_mesh_unused)(void)
(void)rna_Mesh_face_map_active_index_set;
(void)rna_Mesh_face_map_active_index_get;
(void)rna_Mesh_face_map_active_set;
+ (void)rna_Mesh_vertex_crease_index_range;
/* end unused function block */
}
@@ -2505,6 +2571,20 @@ static void rna_def_mesh_polygons(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
+/* Defines a read-only vector type since normals should not be modified manually. */
+static void rna_def_normal_layer_value(BlenderRNA *brna)
+{
+ StructRNA *srna = RNA_def_struct(brna, "MeshNormalValue", NULL);
+ RNA_def_struct_sdna(srna, "vec3f");
+ RNA_def_struct_ui_text(srna, "Mesh Normal Vector", "Vector in a mesh normal array");
+
+ PropertyRNA *prop = RNA_def_property(srna, "vector", PROP_FLOAT, PROP_DIRECTION);
+ RNA_def_property_ui_text(prop, "Vector", "3D vector");
+ RNA_def_property_float_sdna(prop, NULL, "x");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+}
+
static void rna_def_loop_colors(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -2520,6 +2600,7 @@ static void rna_def_loop_colors(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Mesh_vertex_color_new");
RNA_def_function_ui_description(func, "Add a vertex color layer to Mesh");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_string(func, "name", "Col", 0, "", "Vertex color name");
RNA_def_boolean(func,
"do_init",
@@ -2569,6 +2650,7 @@ static void rna_def_vert_colors(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Mesh_sculpt_vertex_color_new");
RNA_def_function_ui_description(func, "Add a sculpt vertex color layer to Mesh");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_string(func, "name", "Col", 0, "", "Sculpt Vertex color name");
RNA_def_boolean(func,
"do_init",
@@ -2622,6 +2704,7 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_struct_ui_text(srna, "UV Loop Layers", "Collection of uv loop layers");
func = RNA_def_function(srna, "new", "rna_Mesh_uv_layers_new");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a UV map layer to Mesh");
RNA_def_string(func, "name", "UVMap", 0, "", "UV map name");
RNA_def_boolean(func,
@@ -2849,6 +2932,40 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
+static void rna_def_vertex_creases(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "MeshVertexCreaseLayer", NULL);
+ RNA_def_struct_ui_text(srna, "Mesh Vertex Crease Layer", "Per-vertex crease");
+ RNA_def_struct_sdna(srna, "CustomDataLayer");
+ RNA_def_struct_path_func(srna, "rna_MeshVertexCreaseLayer_path");
+
+ prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshVertexCrease");
+ RNA_def_property_ui_text(prop, "Data", "");
+ RNA_def_property_collection_funcs(prop,
+ "rna_MeshVertexCreaseLayer_data_begin",
+ "rna_iterator_array_next",
+ "rna_iterator_array_end",
+ "rna_iterator_array_get",
+ "rna_MeshVertexCreaseLayer_data_length",
+ NULL,
+ NULL,
+ NULL);
+
+ /* VertexCrease struct */
+ srna = RNA_def_struct(brna, "MeshVertexCrease", NULL);
+ RNA_def_struct_sdna(srna, "MFloatProperty");
+ RNA_def_struct_ui_text(srna, "Float Property", "");
+
+ prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "f");
+ RNA_def_property_ui_text(prop, "Value", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
+}
+
static void rna_def_paint_mask(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
{
StructRNA *srna;
@@ -2999,6 +3116,42 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Polygons", "Polygons of the mesh");
rna_def_mesh_polygons(brna, prop);
+ rna_def_normal_layer_value(brna);
+
+ prop = RNA_def_property(srna, "vertex_normals", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshNormalValue");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
+ RNA_def_property_ui_text(prop,
+ "Vertex Normals",
+ "The normal direction of each vertex, defined as the average of the "
+ "surrounding face normals");
+ RNA_def_property_collection_funcs(prop,
+ "rna_Mesh_vertex_normals_begin",
+ "rna_iterator_array_next",
+ "rna_iterator_array_end",
+ "rna_iterator_array_get",
+ "rna_Mesh_vertex_normals_length",
+ NULL,
+ NULL,
+ NULL);
+
+ prop = RNA_def_property(srna, "polygon_normals", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshNormalValue");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
+ RNA_def_property_ui_text(prop,
+ "Polygon Normals",
+ "The normal direction of each polygon, defined by the winding order "
+ "and position of its vertices");
+ RNA_def_property_collection_funcs(prop,
+ "rna_Mesh_poly_normals_begin",
+ "rna_iterator_array_next",
+ "rna_iterator_array_end",
+ "rna_iterator_array_get",
+ "rna_Mesh_poly_normals_length",
+ NULL,
+ NULL,
+ NULL);
+
prop = RNA_def_property(srna, "loop_triangles", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "runtime.looptris.array", "runtime.looptris.len");
RNA_def_property_struct_type(prop, "MeshLoopTriangle");
@@ -3006,7 +3159,7 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Loop Triangles", "Tessellation of mesh polygons into triangles");
rna_def_mesh_looptris(brna, prop);
- /* TODO: should this be allowed to be its self? */
+ /* TODO: should this be allowed to be itself? */
prop = RNA_def_property(srna, "texture_mesh", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "texcomesh");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
@@ -3095,6 +3248,7 @@ static void rna_def_mesh(BlenderRNA *brna)
NULL,
NULL);
RNA_def_property_struct_type(prop, "MeshVertColorLayer");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_ui_text(prop, "Sculpt Vertex Colors", "All vertex colors");
rna_def_vert_colors(brna, prop);
@@ -3230,6 +3384,24 @@ static void rna_def_mesh(BlenderRNA *brna)
rna_def_skin_vertices(brna, prop);
/* End skin vertices */
+ /* Vertex Crease */
+ prop = RNA_def_property(srna, "vertex_creases", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshVertexCreaseLayer");
+ RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer");
+ RNA_def_property_collection_funcs(prop,
+ "rna_Mesh_vertex_creases_begin",
+ NULL,
+ NULL,
+ NULL,
+ "rna_Mesh_vertex_creases_length",
+ NULL,
+ NULL,
+ NULL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
+ RNA_def_property_ui_text(prop, "Vertex Creases", "Sharpness of the vertices");
+ rna_def_vertex_creases(brna);
+ /* End vertex crease */
+
/* Paint mask */
prop = RNA_def_property(srna, "vertex_paint_masks", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer");
@@ -3427,6 +3599,10 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_EDGE_BWEIGHT);
RNA_def_property_ui_text(prop, "Store Edge Bevel Weight", "");
+ prop = RNA_def_property(srna, "use_customdata_vertex_crease", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_VERT_CREASE);
+ RNA_def_property_ui_text(prop, "Store Vertex Crease", "");
+
prop = RNA_def_property(srna, "use_customdata_edge_crease", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_EDGE_CREASE);
RNA_def_property_ui_text(prop, "Store Edge Crease", "");
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index c99dfea524f..957b92f204a 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -331,7 +331,12 @@ const EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[] = {
"SHORTEST_DIAGONAL",
0,
"Shortest Diagonal",
- "Split the quads based on the distance between the vertices"},
+ "Split the quads along their shortest diagonal"},
+ {MOD_TRIANGULATE_QUAD_LONGEDGE,
+ "LONGEST_DIAGONAL",
+ 0,
+ "Longest Diagonal",
+ "Split the quads along their longest diagonal"},
{0, NULL, 0, NULL, NULL},
};
@@ -381,6 +386,42 @@ const EnumPropertyItem rna_enum_modifier_shrinkwrap_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_shrinkwrap_type_items[] = {
+ {MOD_SHRINKWRAP_NEAREST_SURFACE,
+ "NEAREST_SURFACEPOINT",
+ 0,
+ "Nearest Surface Point",
+ "Shrink the mesh to the nearest target surface"},
+ {MOD_SHRINKWRAP_PROJECT,
+ "PROJECT",
+ 0,
+ "Project",
+ "Shrink the mesh to the nearest target surface along a given axis"},
+ {MOD_SHRINKWRAP_NEAREST_VERTEX,
+ "NEAREST_VERTEX",
+ 0,
+ "Nearest Vertex",
+ "Shrink the mesh to the nearest target vertex"},
+ {MOD_SHRINKWRAP_TARGET_PROJECT,
+ "TARGET_PROJECT",
+ 0,
+ "Target Normal Project",
+ "Shrink the mesh to the nearest target surface "
+ "along the interpolated vertex normals of the target"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_shrinkwrap_face_cull_items[] = {
+ {0, "OFF", 0, "Off", "No culling"},
+ {MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE,
+ "FRONT",
+ 0,
+ "Front",
+ "No projection when in front of the face"},
+ {MOD_SHRINKWRAP_CULL_TARGET_BACKFACE, "BACK", 0, "Back", "No projection when behind the face"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifndef RNA_RUNTIME
/* use eWarp_Falloff_*** & eHook_Falloff_***, they're in sync */
static const EnumPropertyItem modifier_warp_falloff_items[] = {
@@ -1700,7 +1741,7 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_creases", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", eSubsurfModifierFlag_UseCrease);
RNA_def_property_ui_text(
- prop, "Use Creases", "Use mesh edge crease information to sharpen edges");
+ prop, "Use Creases", "Use mesh crease information to sharpen edges or corners");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_custom_normals", PROP_BOOLEAN, PROP_NONE);
@@ -1915,7 +1956,7 @@ static void rna_def_modifier_multires(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_creases", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", eMultiresModifierFlag_UseCrease);
RNA_def_property_ui_text(
- prop, "Use Creases", "Use mesh edge crease information to sharpen edges");
+ prop, "Use Creases", "Use mesh crease information to sharpen edges or corners");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_custom_normals", PROP_BOOLEAN, PROP_NONE);
@@ -2746,7 +2787,7 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_self", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", eBooleanModifierFlag_Self);
- RNA_def_property_ui_text(prop, "Self", "Allow self-intersection in operands");
+ RNA_def_property_ui_text(prop, "Self Intersection", "Allow self-intersection in operands");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_hole_tolerant", PROP_BOOLEAN, PROP_NONE);
@@ -4184,46 +4225,6 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem shrink_type_items[] = {
- {MOD_SHRINKWRAP_NEAREST_SURFACE,
- "NEAREST_SURFACEPOINT",
- 0,
- "Nearest Surface Point",
- "Shrink the mesh to the nearest target surface"},
- {MOD_SHRINKWRAP_PROJECT,
- "PROJECT",
- 0,
- "Project",
- "Shrink the mesh to the nearest target surface along a given axis"},
- {MOD_SHRINKWRAP_NEAREST_VERTEX,
- "NEAREST_VERTEX",
- 0,
- "Nearest Vertex",
- "Shrink the mesh to the nearest target vertex"},
- {MOD_SHRINKWRAP_TARGET_PROJECT,
- "TARGET_PROJECT",
- 0,
- "Target Normal Project",
- "Shrink the mesh to the nearest target surface "
- "along the interpolated vertex normals of the target"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem shrink_face_cull_items[] = {
- {0, "OFF", 0, "Off", "No culling"},
- {MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE,
- "FRONT",
- 0,
- "Front",
- "No projection when in front of the face"},
- {MOD_SHRINKWRAP_CULL_TARGET_BACKFACE,
- "BACK",
- 0,
- "Back",
- "No projection when behind the face"},
- {0, NULL, 0, NULL, NULL},
- };
-
srna = RNA_def_struct(brna, "ShrinkwrapModifier", "Modifier");
RNA_def_struct_ui_text(srna,
"Shrinkwrap Modifier",
@@ -4235,7 +4236,7 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
prop = RNA_def_property(srna, "wrap_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "shrinkType");
- RNA_def_property_enum_items(prop, shrink_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_shrinkwrap_type_items);
RNA_def_property_ui_text(prop, "Wrap Method", "");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
@@ -4248,7 +4249,7 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
prop = RNA_def_property(srna, "cull_face", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "shrinkOpts");
- RNA_def_property_enum_items(prop, shrink_face_cull_items);
+ RNA_def_property_enum_items(prop, rna_enum_shrinkwrap_face_cull_items);
RNA_def_property_enum_funcs(
prop, "rna_ShrinkwrapModifier_face_cull_get", "rna_ShrinkwrapModifier_face_cull_set", NULL);
RNA_def_property_ui_text(
@@ -7245,6 +7246,15 @@ void RNA_def_modifier(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Active", "The active modifier in the list");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+ prop = RNA_def_boolean(srna,
+ "is_override_data",
+ false,
+ "Override Modifier",
+ "In a local override object, whether this modifier comes from the linked "
+ "reference object, or is local to the override");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", eModifierFlag_OverrideLibrary_Local);
+
prop = RNA_def_property(srna, "use_apply_on_spline", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_ApplyOnSpline);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index 17c7b331c88..230133a8f9d 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -751,14 +751,14 @@ static void rna_def_nlastrip(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Influence", "Amount the strip contributes to the current result");
/* XXX: Update temporarily disabled so that the property can be edited at all!
- * Even autokey only applies after the curves have been re-evaluated,
+ * Even auto-key only applies after the curves have been re-evaluated,
* causing the unkeyed values to be lost. */
RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, /*"rna_NlaStrip_update"*/ NULL);
prop = RNA_def_property(srna, "strip_time", PROP_FLOAT, PROP_TIME);
RNA_def_property_ui_text(prop, "Strip Time", "Frame of referenced Action to evaluate");
/* XXX: Update temporarily disabled so that the property can be edited at all!
- * Even autokey only applies after the curves have been re-evaluated,
+ * Even auto-key only applies after the curves have been re-evaluated,
* causing the unkeyed values to be lost. */
RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, /*"rna_NlaStrip_update"*/ NULL);
@@ -887,6 +887,15 @@ static void rna_def_nlatrack(BlenderRNA *brna)
rna_api_nlatrack_strips(brna, prop);
+ prop = RNA_def_boolean(srna,
+ "is_override_data",
+ false,
+ "Override Track",
+ "In a local override data, whether this NLA track comes from the linked "
+ "reference data, or is local to the override");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", NLATRACK_OVERRIDELIBRARY_LOCAL);
+
RNA_define_lib_overridable(true);
/* name property */
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 8fb55d37375..536b2f7aa6e 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -39,8 +39,10 @@
#include "BKE_animsys.h"
#include "BKE_attribute.h"
#include "BKE_cryptomatte.h"
+#include "BKE_geometry_set.h"
#include "BKE_image.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_texture.h"
#include "RNA_access.h"
@@ -50,6 +52,7 @@
#include "rna_internal.h"
#include "rna_internal_types.h"
+#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -297,43 +300,99 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = {
};
const EnumPropertyItem rna_enum_node_boolean_math_items[] = {
- {NODE_BOOLEAN_MATH_AND, "AND", 0, "And", "Outputs true only when both inputs are true"},
- {NODE_BOOLEAN_MATH_OR, "OR", 0, "Or", "Outputs or when at least one of the inputs is true"},
- {NODE_BOOLEAN_MATH_NOT, "NOT", 0, "Not", "Outputs the opposite of the input"},
+ {NODE_BOOLEAN_MATH_AND, "AND", 0, "And", "True when both inputs are true"},
+ {NODE_BOOLEAN_MATH_OR, "OR", 0, "Or", "True when at least one input is true"},
+ {NODE_BOOLEAN_MATH_NOT, "NOT", 0, "Not", "Opposite of the input"},
+ {0, "", ICON_NONE, NULL, NULL},
+ {NODE_BOOLEAN_MATH_NAND, "NAND", 0, "Not And", "True when at least one input is false"},
+ {NODE_BOOLEAN_MATH_NOR, "NOR", 0, "Nor", "True when both inputs are false"},
+ {NODE_BOOLEAN_MATH_XNOR,
+ "XNOR",
+ 0,
+ "Equal",
+ "True when both inputs are equal (exclusive nor)"},
+ {NODE_BOOLEAN_MATH_XOR,
+ "XOR",
+ 0,
+ "Not Equal",
+ "True when both inputs are different (exclusive or)"},
+ {0, "", ICON_NONE, NULL, NULL},
+ {NODE_BOOLEAN_MATH_IMPLY,
+ "IMPLY",
+ 0,
+ "Imply",
+ "True unless the first input is true and the second is false"},
+ {NODE_BOOLEAN_MATH_NIMPLY,
+ "NIMPLY",
+ 0,
+ "Subtract",
+ "True when the first input is true and the second is false (not imply)"},
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_node_float_compare_items[] = {
- {NODE_FLOAT_COMPARE_LESS_THAN,
+ {NODE_COMPARE_LESS_THAN,
"LESS_THAN",
0,
"Less Than",
"True when the first input is smaller than second input"},
- {NODE_FLOAT_COMPARE_LESS_EQUAL,
+ {NODE_COMPARE_LESS_EQUAL,
"LESS_EQUAL",
0,
"Less Than or Equal",
"True when the first input is smaller than the second input or equal"},
- {NODE_FLOAT_COMPARE_GREATER_THAN,
+ {NODE_COMPARE_GREATER_THAN,
"GREATER_THAN",
0,
"Greater Than",
"True when the first input is greater than the second input"},
- {NODE_FLOAT_COMPARE_GREATER_EQUAL,
+ {NODE_COMPARE_GREATER_EQUAL,
"GREATER_EQUAL",
0,
"Greater Than or Equal",
"True when the first input is greater than the second input or equal"},
- {NODE_FLOAT_COMPARE_EQUAL,
- "EQUAL",
+ {NODE_COMPARE_EQUAL, "EQUAL", 0, "Equal", "True when both inputs are approximately equal"},
+ {NODE_COMPARE_NOT_EQUAL,
+ "NOT_EQUAL",
0,
- "Equal",
- "True when both inputs are approximately equal"},
- {NODE_FLOAT_COMPARE_NOT_EQUAL,
+ "Not Equal",
+ "True when both inputs are not approximately equal"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_node_compare_operation_items[] = {
+ {NODE_COMPARE_LESS_THAN,
+ "LESS_THAN",
+ 0,
+ "Less Than",
+ "True when the first input is smaller than second input"},
+ {NODE_COMPARE_LESS_EQUAL,
+ "LESS_EQUAL",
+ 0,
+ "Less Than or Equal",
+ "True when the first input is smaller than the second input or equal"},
+ {NODE_COMPARE_GREATER_THAN,
+ "GREATER_THAN",
+ 0,
+ "Greater Than",
+ "True when the first input is greater than the second input"},
+ {NODE_COMPARE_GREATER_EQUAL,
+ "GREATER_EQUAL",
+ 0,
+ "Greater Than or Equal",
+ "True when the first input is greater than the second input or equal"},
+ {NODE_COMPARE_EQUAL, "EQUAL", 0, "Equal", "True when both inputs are approximately equal"},
+ {NODE_COMPARE_NOT_EQUAL,
"NOT_EQUAL",
0,
"Not Equal",
"True when both inputs are not approximately equal"},
+ {NODE_COMPARE_COLOR_BRIGHTER,
+ "BRIGHTER",
+ 0,
+ "Brighter",
+ "True when the first input is brighter"},
+ {NODE_COMPARE_COLOR_DARKER, "DARKER", 0, "Darker", "True when the first input is darker"},
{0, NULL, 0, NULL, NULL},
};
@@ -596,6 +655,7 @@ static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_no_bo
# include "NOD_geometry.h"
# include "NOD_shader.h"
# include "NOD_socket.h"
+# include "NOD_texture.h"
# include "RE_engine.h"
# include "RE_pipeline.h"
@@ -1186,7 +1246,7 @@ static void rna_NodeTree_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *p
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
WM_main_add_notifier(NC_SCENE | ND_NODES, &ntree->id);
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static bNode *rna_NodeTree_node_new(bNodeTree *ntree,
@@ -1235,8 +1295,8 @@ static bNode *rna_NodeTree_node_new(bNodeTree *ntree,
ntreeTexCheckCyclics(ntree);
}
- ntreeUpdateTree(CTX_data_main(C), ntree);
- nodeUpdate(ntree, node);
+ Main *bmain = CTX_data_main(C);
+ ED_node_tree_propagate_change(C, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
return node;
@@ -1262,7 +1322,7 @@ static void rna_NodeTree_node_remove(bNodeTree *ntree,
RNA_POINTER_INVALIDATE(node_ptr);
- ntreeUpdateTree(bmain, ntree); /* update group node socket links */
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1282,8 +1342,7 @@ static void rna_NodeTree_node_clear(bNodeTree *ntree, Main *bmain, ReportList *r
node = next_node;
}
- ntreeUpdateTree(bmain, ntree);
-
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1362,13 +1421,7 @@ static bNodeLink *rna_NodeTree_link_new(bNodeTree *ntree,
fromsock->flag &= ~SOCK_HIDDEN;
tosock->flag &= ~SOCK_HIDDEN;
- if (tonode) {
- nodeUpdate(ntree, tonode);
- }
-
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, ret->tonode);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
return ret;
@@ -1393,7 +1446,7 @@ static void rna_NodeTree_link_remove(bNodeTree *ntree,
nodeRemLink(ntree, link);
RNA_POINTER_INVALIDATE(link_ptr);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1412,8 +1465,7 @@ static void rna_NodeTree_link_clear(bNodeTree *ntree, Main *bmain, ReportList *r
link = next_link;
}
- ntreeUpdateTree(bmain, ntree);
-
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1470,7 +1522,7 @@ static bNodeSocket *rna_NodeTree_inputs_new(
bNodeSocket *sock = ntreeAddSocketInterface(ntree, SOCK_IN, type, name);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
return sock;
@@ -1485,7 +1537,7 @@ static bNodeSocket *rna_NodeTree_outputs_new(
bNodeSocket *sock = ntreeAddSocketInterface(ntree, SOCK_OUT, type, name);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
return sock;
@@ -1506,8 +1558,7 @@ static void rna_NodeTree_socket_remove(bNodeTree *ntree,
else {
ntreeRemoveSocketInterface(ntree, sock);
- ntreeUpdateTree(bmain, ntree);
- DEG_id_tag_update(&ntree->id, 0);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
}
@@ -1522,7 +1573,7 @@ static void rna_NodeTree_inputs_clear(bNodeTree *ntree, Main *bmain, ReportList
ntreeRemoveSocketInterface(ntree, socket);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1536,7 +1587,7 @@ static void rna_NodeTree_outputs_clear(bNodeTree *ntree, Main *bmain, ReportList
ntreeRemoveSocketInterface(ntree, socket);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1565,9 +1616,9 @@ static void rna_NodeTree_inputs_move(bNodeTree *ntree, Main *bmain, int from_ind
}
}
- ntree->update |= NTREE_UPDATE_GROUP_IN;
+ BKE_ntree_update_tag_interface(ntree);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1596,9 +1647,9 @@ static void rna_NodeTree_outputs_move(bNodeTree *ntree, Main *bmain, int from_in
}
}
- ntree->update |= NTREE_UPDATE_GROUP_OUT;
+ BKE_ntree_update_tag_interface(ntree);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1606,10 +1657,8 @@ static void rna_NodeTree_interface_update(bNodeTree *ntree, bContext *C)
{
Main *bmain = CTX_data_main(C);
- ntree->update |= NTREE_UPDATE_GROUP;
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ BKE_ntree_update_tag_interface(ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
/* ******** NodeLink ******** */
@@ -1853,7 +1902,7 @@ static void rna_Node_draw_buttons_ext(struct uiLayout *layout, bContext *C, Poin
RNA_parameter_list_free(&list);
}
-static void rna_Node_draw_label(bNodeTree *ntree, bNode *node, char *label, int maxlen)
+static void rna_Node_draw_label(const bNodeTree *ntree, const bNode *node, char *label, int maxlen)
{
extern FunctionRNA rna_Node_draw_label_func;
@@ -1865,7 +1914,7 @@ static void rna_Node_draw_label(bNodeTree *ntree, bNode *node, char *label, int
func = &rna_Node_draw_label_func; /* RNA_struct_find_function(&ptr, "draw_label"); */
- RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
+ RNA_pointer_create((ID *)&ntree->id, &RNA_Node, (bNode *)node, &ptr);
RNA_parameter_list_create(&list, &ptr, func);
node->typeinfo->rna_ext.call(NULL, &ptr, func, &list);
@@ -1930,7 +1979,7 @@ static bNodeType *rna_Node_register_base(Main *bmain,
/* setup dummy node & node type to store static properties in */
memset(&dummynt, 0, sizeof(bNodeType));
/* this does some additional initialization of default values */
- node_type_base_custom(&dummynt, identifier, "", 0, 0);
+ node_type_base_custom(&dummynt, identifier, "", 0);
memset(&dummynode, 0, sizeof(bNode));
dummynode.typeinfo = &dummynt;
@@ -2056,7 +2105,8 @@ static bool switch_type_supported(const EnumPropertyItem *item)
SOCK_OBJECT,
SOCK_COLLECTION,
SOCK_TEXTURE,
- SOCK_MATERIAL);
+ SOCK_MATERIAL,
+ SOCK_IMAGE);
}
static const EnumPropertyItem *rna_GeometryNodeSwitch_type_itemf(bContext *UNUSED(C),
@@ -2068,10 +2118,76 @@ static const EnumPropertyItem *rna_GeometryNodeSwitch_type_itemf(bContext *UNUSE
return itemf_function_check(node_socket_data_type_items, switch_type_supported);
}
+static bool compare_type_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value, SOCK_FLOAT, SOCK_INT, SOCK_VECTOR, SOCK_STRING, SOCK_RGBA);
+}
+
+static bool compare_main_operation_supported(const EnumPropertyItem *item)
+{
+ return !ELEM(item->value, NODE_COMPARE_COLOR_BRIGHTER, NODE_COMPARE_COLOR_DARKER);
+}
+
+static bool compare_rgba_operation_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value,
+ NODE_COMPARE_EQUAL,
+ NODE_COMPARE_NOT_EQUAL,
+ NODE_COMPARE_COLOR_BRIGHTER,
+ NODE_COMPARE_COLOR_DARKER);
+}
+
+static bool compare_string_operation_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL);
+}
+
+static bool compare_other_operation_supported(const EnumPropertyItem *UNUSED(item))
+{
+ return false;
+}
+
+static const EnumPropertyItem *rna_FunctionNodeCompare_type_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ *r_free = true;
+ return itemf_function_check(node_socket_data_type_items, compare_type_supported);
+}
+
+static const EnumPropertyItem *rna_FunctionNodeCompare_operation_itemf(bContext *UNUSED(C),
+ PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ *r_free = true;
+ bNode *node = ptr->data;
+ NodeFunctionCompare *data = (NodeFunctionCompare *)node->storage;
+
+ if (ELEM(data->data_type, SOCK_FLOAT, SOCK_INT, SOCK_VECTOR)) {
+ return itemf_function_check(rna_enum_node_compare_operation_items,
+ compare_main_operation_supported);
+ }
+ else if (data->data_type == SOCK_STRING) {
+ return itemf_function_check(rna_enum_node_compare_operation_items,
+ compare_string_operation_supported);
+ }
+ else if (data->data_type == SOCK_RGBA) {
+ return itemf_function_check(rna_enum_node_compare_operation_items,
+ compare_rgba_operation_supported);
+ }
+ else {
+ return itemf_function_check(rna_enum_node_compare_operation_items,
+ compare_other_operation_supported);
+ }
+}
+
static bool attribute_clamp_type_supported(const EnumPropertyItem *item)
{
return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_INT32, CD_PROP_COLOR);
}
+
static const EnumPropertyItem *rna_GeometryNodeAttributeClamp_type_itemf(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -2105,6 +2221,20 @@ static const EnumPropertyItem *rna_FunctionNodeRandomValue_type_itemf(bContext *
return itemf_function_check(rna_enum_attribute_type_items, random_value_type_supported);
}
+static bool accumulate_field_type_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_INT32);
+}
+
+static const EnumPropertyItem *rna_GeoNodeAccumulateField_type_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ *r_free = true;
+ return itemf_function_check(rna_enum_attribute_type_items, accumulate_field_type_supported);
+}
+
static const EnumPropertyItem *rna_GeometryNodeAttributeRandomize_operation_itemf(
bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -2148,6 +2278,30 @@ static void rna_GeometryNodeAttributeRandomize_data_type_update(Main *bmain,
rna_Node_socket_update(bmain, scene, ptr);
}
+static void rna_GeometryNodeCompare_data_type_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bNode *node = ptr->data;
+ NodeFunctionCompare *node_storage = (NodeFunctionCompare *)node->storage;
+
+ if (node_storage->data_type == SOCK_RGBA && !ELEM(node_storage->operation,
+ NODE_COMPARE_EQUAL,
+ NODE_COMPARE_NOT_EQUAL,
+ NODE_COMPARE_COLOR_BRIGHTER,
+ NODE_COMPARE_COLOR_DARKER)) {
+ node_storage->operation = NODE_COMPARE_EQUAL;
+ }
+ else if (node_storage->data_type == SOCK_STRING &&
+ !ELEM(node_storage->operation, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL)) {
+ node_storage->operation = NODE_COMPARE_EQUAL;
+ }
+ else if (node_storage->data_type != SOCK_RGBA &&
+ ELEM(node_storage->operation, NODE_COMPARE_COLOR_BRIGHTER, NODE_COMPARE_COLOR_DARKER)) {
+ node_storage->operation = NODE_COMPARE_EQUAL;
+ }
+
+ rna_Node_socket_update(bmain, scene, ptr);
+}
+
static bool attribute_convert_type_supported(const EnumPropertyItem *item)
{
return ELEM(item->value,
@@ -2181,6 +2335,19 @@ static const EnumPropertyItem *rna_GeometryNodeAttributeFill_type_itemf(bContext
return itemf_function_check(rna_enum_attribute_type_items, attribute_fill_type_supported);
}
+static bool transfer_attribute_type_supported(const EnumPropertyItem *item)
+{
+ return ELEM(
+ item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_COLOR, CD_PROP_BOOL, CD_PROP_INT32);
+}
+
+static const EnumPropertyItem *rna_NodeGeometryTransferAttribute_type_itemf(
+ bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ *r_free = true;
+ return itemf_function_check(rna_enum_attribute_type_items, transfer_attribute_type_supported);
+}
+
static bool attribute_statistic_type_supported(const EnumPropertyItem *item)
{
return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3);
@@ -2475,7 +2642,8 @@ static void rna_Node_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static void rna_Node_update_relations(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -2484,9 +2652,10 @@ static void rna_Node_update_relations(Main *bmain, Scene *scene, PointerRNA *ptr
DEG_relations_tag_update(bmain);
}
-static void rna_Node_socket_value_update(ID *id, bNode *node, bContext *C)
+static void rna_Node_socket_value_update(ID *id, bNode *UNUSED(node), bContext *C)
{
- ED_node_tag_update_nodetree(CTX_data_main(C), (bNodeTree *)id, node);
+ BKE_ntree_update_tag_all((bNodeTree *)id);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), (bNodeTree *)id);
}
static void rna_Node_select_set(PointerRNA *ptr, bool value)
@@ -2540,7 +2709,7 @@ static bNodeSocket *rna_Node_inputs_new(ID *id,
BKE_report(reports, RPT_ERROR, "Unable to create socket");
}
else {
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2574,7 +2743,7 @@ static bNodeSocket *rna_Node_outputs_new(ID *id,
BKE_report(reports, RPT_ERROR, "Unable to create socket");
}
else {
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2592,7 +2761,7 @@ static void rna_Node_socket_remove(
else {
nodeRemoveSocket(ntree, node, sock);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
}
@@ -2607,7 +2776,7 @@ static void rna_Node_inputs_clear(ID *id, bNode *node, Main *bmain)
nodeRemoveSocket(ntree, node, sock);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2621,7 +2790,7 @@ static void rna_Node_outputs_clear(ID *id, bNode *node, Main *bmain)
nodeRemoveSocket(ntree, node, sock);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2653,7 +2822,7 @@ static void rna_Node_inputs_move(ID *id, bNode *node, Main *bmain, int from_inde
}
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2685,7 +2854,7 @@ static void rna_Node_outputs_move(ID *id, bNode *node, Main *bmain, int from_ind
}
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2791,6 +2960,7 @@ static StructRNA *rna_NodeSocket_register(Main *UNUSED(bmain),
/* setup dummy socket & socket type to store static properties in */
memset(&dummyst, 0, sizeof(bNodeSocketType));
+ dummyst.type = SOCK_CUSTOM;
memset(&dummysock, 0, sizeof(bNodeSocket));
dummysock.typeinfo = &dummyst;
@@ -2912,10 +3082,9 @@ static void rna_NodeSocket_update(Main *bmain, Scene *UNUSED(scene), PointerRNA
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocket *sock = (bNodeSocket *)ptr->data;
- bNode *node;
- if (nodeFindNode(ntree, sock, &node, NULL)) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
- }
+
+ BKE_ntree_update_tag_socket_property(ntree, sock);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static bool rna_NodeSocket_is_output_get(PointerRNA *ptr)
@@ -2926,7 +3095,6 @@ static bool rna_NodeSocket_is_output_get(PointerRNA *ptr)
static void rna_NodeSocket_link_limit_set(PointerRNA *ptr, int value)
{
- /* Does not have any effect if the link limit is defined in the socket type. */
bNodeSocket *sock = ptr->data;
sock->limit = (value == 0 ? 0xFFF : value);
}
@@ -3021,8 +3189,11 @@ static void rna_NodeSocketInterface_register_properties(bNodeTree *ntree,
RNA_parameter_list_free(&list);
}
-static void rna_NodeSocketInterface_init_socket(
- bNodeTree *ntree, bNodeSocket *stemp, bNode *node, bNodeSocket *sock, const char *data_path)
+static void rna_NodeSocketInterface_init_socket(bNodeTree *ntree,
+ const bNodeSocket *interface_socket,
+ bNode *node,
+ bNodeSocket *sock,
+ const char *data_path)
{
extern FunctionRNA rna_NodeSocketInterface_init_socket_func;
@@ -3030,11 +3201,11 @@ static void rna_NodeSocketInterface_init_socket(
ParameterList list;
FunctionRNA *func;
- if (!stemp->typeinfo) {
+ if (!interface_socket->typeinfo) {
return;
}
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, stemp, &ptr);
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, (bNodeSocket *)interface_socket, &ptr);
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sock_ptr);
// RNA_struct_find_function(&ptr, "init_socket");
@@ -3044,13 +3215,13 @@ static void rna_NodeSocketInterface_init_socket(
RNA_parameter_set_lookup(&list, "node", &node_ptr);
RNA_parameter_set_lookup(&list, "socket", &sock_ptr);
RNA_parameter_set_lookup(&list, "data_path", &data_path);
- stemp->typeinfo->ext_interface.call(NULL, &ptr, func, &list);
+ interface_socket->typeinfo->ext_interface.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
static void rna_NodeSocketInterface_from_socket(bNodeTree *ntree,
- bNodeSocket *stemp,
+ bNodeSocket *interface_socket,
bNode *node,
bNodeSocket *sock)
{
@@ -3060,11 +3231,11 @@ static void rna_NodeSocketInterface_from_socket(bNodeTree *ntree,
ParameterList list;
FunctionRNA *func;
- if (!stemp->typeinfo) {
+ if (!interface_socket->typeinfo) {
return;
}
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, stemp, &ptr);
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, interface_socket, &ptr);
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sock_ptr);
// RNA_struct_find_function(&ptr, "from_socket");
@@ -3073,7 +3244,7 @@ static void rna_NodeSocketInterface_from_socket(bNodeTree *ntree,
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "node", &node_ptr);
RNA_parameter_set_lookup(&list, "socket", &sock_ptr);
- stemp->typeinfo->ext_interface.call(NULL, &ptr, func, &list);
+ interface_socket->typeinfo->ext_interface.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -3205,10 +3376,8 @@ static void rna_NodeSocketInterface_update(Main *bmain, Scene *UNUSED(scene), Po
return;
}
- ntree->update |= NTREE_UPDATE_GROUP;
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ BKE_ntree_update_tag_interface(ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
/* ******** Standard Node Socket Base Types ******** */
@@ -3306,28 +3475,14 @@ static void rna_NodeSocketStandard_vector_range(
/* using a context update function here, to avoid searching the node if possible */
static void rna_NodeSocketStandard_value_update(struct bContext *C, PointerRNA *ptr)
{
- bNode *node;
-
/* default update */
rna_NodeSocket_update(CTX_data_main(C), CTX_data_scene(C), ptr);
-
- /* try to use node from context, faster */
- node = CTX_data_pointer_get(C, "node").data;
- if (!node) {
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNodeSocket *sock = ptr->data;
-
- /* fall back to searching node in the tree */
- nodeFindNode(ntree, sock, &node, NULL);
- }
}
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);
DEG_relations_tag_update(bmain);
}
@@ -3421,12 +3576,11 @@ static bool rna_NodeInternal_poll_instance(bNode *node, bNodeTree *ntree)
}
}
-static void rna_NodeInternal_update(ID *id, bNode *node)
+static void rna_NodeInternal_update(ID *id, bNode *node, Main *bmain)
{
bNodeTree *ntree = (bNodeTree *)id;
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static void rna_NodeInternal_draw_buttons(ID *id,
@@ -3575,7 +3729,8 @@ static void rna_Node_tex_image_update(Main *bmain, Scene *UNUSED(scene), Pointer
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_IMAGE, NULL);
}
@@ -3584,11 +3739,8 @@ static void rna_NodeGroup_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- if (node->id) {
- ntreeUpdateTree(bmain, (bNodeTree *)node->id);
- }
-
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
DEG_relations_tag_update(bmain);
}
@@ -3996,13 +4148,12 @@ static const EnumPropertyItem *rna_Node_channel_itemf(bContext *UNUSED(C),
return item;
}
-static void rna_Image_Node_update_id(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Image_Node_update_id(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
node->update |= NODE_UPDATE_ID;
- nodeUpdate(ntree, node); /* to update image node sockets */
+ rna_Node_update(bmain, scene, ptr);
}
static void rna_NodeOutputFile_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -4249,7 +4400,7 @@ static bNodeSocket *rna_NodeOutputFile_slots_new(
sock = ntreeCompositOutputFileAddSocket(ntree, node, name, im_format);
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
return sock;
@@ -4358,42 +4509,27 @@ static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *p
RE_engine_free(engine);
}
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static void rna_ShaderNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
static void rna_Node_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
static void rna_GeometryNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
static void rna_CompositorNodeScale_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
@@ -4555,6 +4691,55 @@ bool rna_NodeSocketMaterial_default_value_poll(PointerRNA *UNUSED(ptr), PointerR
return ma->gp_style == NULL;
}
+static int rna_NodeConvertColorSpace_from_color_space_get(struct PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeConvertColorSpace *node_storage = node->storage;
+ return IMB_colormanagement_colorspace_get_named_index(node_storage->from_color_space);
+}
+
+static void rna_NodeConvertColorSpace_from_color_space_set(struct PointerRNA *ptr, int value)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeConvertColorSpace *node_storage = node->storage;
+ const char *name = IMB_colormanagement_colorspace_get_indexed_name(value);
+
+ if (name && name[0]) {
+ BLI_strncpy(node_storage->from_color_space, name, sizeof(node_storage->from_color_space));
+ }
+}
+static int rna_NodeConvertColorSpace_to_color_space_get(struct PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeConvertColorSpace *node_storage = node->storage;
+ return IMB_colormanagement_colorspace_get_named_index(node_storage->to_color_space);
+}
+
+static void rna_NodeConvertColorSpace_to_color_space_set(struct PointerRNA *ptr, int value)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeConvertColorSpace *node_storage = node->storage;
+ const char *name = IMB_colormanagement_colorspace_get_indexed_name(value);
+
+ if (name && name[0]) {
+ BLI_strncpy(node_storage->to_color_space, name, sizeof(node_storage->to_color_space));
+ }
+}
+
+static const EnumPropertyItem *rna_NodeConvertColorSpace_color_space_itemf(
+ bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem *items = NULL;
+ int totitem = 0;
+
+ IMB_colormanagement_colorspace_items_add(&items, &totitem);
+ RNA_enum_item_end(&items, &totitem);
+
+ *r_free = true;
+
+ return items;
+}
+
#else
static const EnumPropertyItem prop_image_layer_items[] = {
@@ -4678,6 +4863,11 @@ static const EnumPropertyItem node_principled_distribution_items[] = {
};
static const EnumPropertyItem node_subsurface_method_items[] = {
+ {SHD_SUBSURFACE_BURLEY,
+ "BURLEY",
+ 0,
+ "Christensen-Burley",
+ "Approximation to physically based volume scattering"},
{SHD_SUBSURFACE_RANDOM_WALK_FIXED_RADIUS,
"RANDOM_WALK_FIXED_RADIUS",
0,
@@ -4803,18 +4993,32 @@ static void def_clamp(StructRNA *srna)
static void def_map_range(StructRNA *srna)
{
+ static const EnumPropertyItem rna_enum_data_type_items[] = {
+ {CD_PROP_FLOAT, "FLOAT", 0, "Float", "Floating-point value"},
+ {CD_PROP_FLOAT3, "FLOAT_VECTOR", 0, "Vector", "3D vector with floating-point values"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeMapRange", "storage");
+
PropertyRNA *prop;
prop = RNA_def_property(srna, "clamp", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1);
+ RNA_def_property_boolean_sdna(prop, NULL, "clamp", 1);
RNA_def_property_ui_text(prop, "Clamp", "Clamp the result to the target range [To Min, To Max]");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "interpolation_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom2");
+ RNA_def_property_enum_sdna(prop, NULL, "interpolation_type");
RNA_def_property_enum_items(prop, rna_enum_node_map_range_items);
RNA_def_property_ui_text(prop, "Interpolation Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_type");
+ RNA_def_property_enum_items(prop, rna_enum_data_type_items);
+ RNA_def_property_ui_text(prop, "Data Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
static void def_math(StructRNA *srna)
@@ -4844,15 +5048,57 @@ static void def_boolean_math(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
-static void def_float_compare(StructRNA *srna)
+static void def_compare(StructRNA *srna)
{
+
+ static const EnumPropertyItem mode_items[] = {
+ {NODE_COMPARE_MODE_ELEMENT,
+ "ELEMENT",
+ 0,
+ "Element-Wise",
+ "Compare each element of the input vectors"},
+ {NODE_COMPARE_MODE_LENGTH, "LENGTH", 0, "Length", "Compare the length of the input vectors"},
+ {NODE_COMPARE_MODE_AVERAGE,
+ "AVERAGE",
+ 0,
+ "Average",
+ "Compare the average of the input vectors elements"},
+ {NODE_COMPARE_MODE_DOT_PRODUCT,
+ "DOT_PRODUCT",
+ 0,
+ "Dot Product",
+ "Compare the dot products of the input vectors"},
+ {NODE_COMPARE_MODE_DIRECTION,
+ "DIRECTION",
+ 0,
+ "Direction",
+ "Compare the direction of the input vectors"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
PropertyRNA *prop;
+ RNA_def_struct_sdna_from(srna, "NodeFunctionCompare", "storage");
+
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom1");
- RNA_def_property_enum_items(prop, rna_enum_node_float_compare_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_FunctionNodeCompare_operation_itemf");
+ RNA_def_property_enum_items(prop, rna_enum_node_compare_operation_items);
+ RNA_def_property_enum_default(prop, NODE_COMPARE_EQUAL);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_FunctionNodeCompare_type_itemf");
+ RNA_def_property_enum_items(prop, node_socket_data_type_items);
+ RNA_def_property_enum_default(prop, SOCK_FLOAT);
+ RNA_def_property_ui_text(prop, "Input Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNodeCompare_data_type_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_enum_default(prop, NODE_COMPARE_MODE_ELEMENT);
+ RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_float_to_int(StructRNA *srna)
@@ -4900,6 +5146,17 @@ static void def_vector_curve(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_float_curve(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "mapping", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "storage");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Mapping", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_time(StructRNA *srna)
{
PropertyRNA *prop;
@@ -4972,6 +5229,44 @@ static void def_texture(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_fn_input_color(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeInputColor", "storage");
+
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_float_sdna(prop, NULL, "color");
+ RNA_def_property_ui_text(prop, "Color", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
+static void def_fn_input_bool(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeInputBool", "storage");
+
+ prop = RNA_def_property(srna, "boolean", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "boolean", 1);
+ RNA_def_property_ui_text(prop, "Boolean", "Input value used for unconnected socket");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
+static void def_fn_input_int(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeInputInt", "storage");
+
+ prop = RNA_def_property(srna, "integer", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "integer");
+ RNA_def_property_int_default(prop, 1);
+ RNA_def_property_ui_text(prop, "Integer", "Input value used for unconnected socket");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_fn_input_vector(StructRNA *srna)
{
PropertyRNA *prop;
@@ -5346,6 +5641,50 @@ static void def_sh_tex_image(StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_Node_update");
}
+static void def_geo_image_texture(StructRNA *srna)
+{
+ static const EnumPropertyItem fn_tex_prop_interpolation_items[] = {
+ {SHD_INTERP_LINEAR, "Linear", 0, "Linear", "Linear interpolation"},
+ {SHD_INTERP_CLOSEST, "Closest", 0, "Closest", "No interpolation (sample closest texel)"},
+ {SHD_INTERP_CUBIC, "Cubic", 0, "Cubic", "Cubic interpolation"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem prop_image_extension[] = {
+ {SHD_IMAGE_EXTENSION_REPEAT,
+ "REPEAT",
+ 0,
+ "Repeat",
+ "Cause the image to repeat horizontally and vertically"},
+ {SHD_IMAGE_EXTENSION_EXTEND,
+ "EXTEND",
+ 0,
+ "Extend",
+ "Extend by repeating edge pixels of the image"},
+ {SHD_IMAGE_EXTENSION_CLIP,
+ "CLIP",
+ 0,
+ "Clip",
+ "Clip to image size and set exterior pixels as transparent"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryImageTexture", "storage");
+
+ prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, fn_tex_prop_interpolation_items);
+ RNA_def_property_ui_text(prop, "Interpolation", "Method for smoothing values between pixels");
+ RNA_def_property_update(prop, 0, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "extension", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_image_extension);
+ RNA_def_property_ui_text(
+ prop, "Extension", "How the image is extrapolated past its original bounds");
+ RNA_def_property_update(prop, 0, "rna_Node_update");
+}
+
static void def_sh_tex_gradient(StructRNA *srna)
{
static const EnumPropertyItem prop_gradient_type[] = {
@@ -7048,6 +7387,42 @@ static void def_cmp_distance_matte(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_cmp_convert_color_space(StructRNA *srna)
+{
+ PropertyRNA *prop;
+ RNA_def_struct_sdna_from(srna, "NodeConvertColorSpace", "storage");
+
+ static const EnumPropertyItem color_space_items[] = {
+ {0,
+ "NONE",
+ 0,
+ "None",
+ "Do not perform any color transform on load, treat colors as in scene linear space "
+ "already"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ prop = RNA_def_property(srna, "from_color_space", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
+ RNA_def_property_enum_items(prop, color_space_items);
+ RNA_def_property_enum_funcs(prop,
+ "rna_NodeConvertColorSpace_from_color_space_get",
+ "rna_NodeConvertColorSpace_from_color_space_set",
+ "rna_NodeConvertColorSpace_color_space_itemf");
+ RNA_def_property_ui_text(prop, "From", "Color space of the input image");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "to_color_space", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
+ RNA_def_property_enum_items(prop, color_space_items);
+ RNA_def_property_enum_funcs(prop,
+ "rna_NodeConvertColorSpace_to_color_space_get",
+ "rna_NodeConvertColorSpace_to_color_space_set",
+ "rna_NodeConvertColorSpace_color_space_itemf");
+ RNA_def_property_ui_text(prop, "To", "Color space of the output image");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_cmp_color_spill(StructRNA *srna)
{
PropertyRNA *prop;
@@ -9053,6 +9428,16 @@ static void def_geo_boolean(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_attribute_domain_size(StructRNA *srna)
+{
+ PropertyRNA *prop = RNA_def_property(srna, "component", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_enum_geometry_component_type_items);
+ RNA_def_property_enum_default(prop, GEO_COMPONENT_TYPE_MESH);
+ RNA_def_property_ui_text(prop, "Component", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_curve_primitive_bezier_segment(StructRNA *srna)
{
static const EnumPropertyItem mode_items[] = {
@@ -9128,7 +9513,12 @@ static void def_geo_triangulate(StructRNA *srna)
"SHORTEST_DIAGONAL",
0,
"Shortest Diagonal",
- "Split the quads based on the distance between the vertices"},
+ "Split the quads along their shortest diagonal"},
+ {GEO_NODE_TRIANGULATE_QUAD_LONGEDGE,
+ "LONGEST_DIAGONAL",
+ 0,
+ "Longest Diagonal",
+ "Split the quads along their longest diagonal"},
{0, NULL, 0, NULL, NULL},
};
@@ -9181,6 +9571,28 @@ static void def_geo_subdivision_surface(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_geo_accumulate_field(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeAccumulateField", "storage");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "data_type");
+ RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeoNodeAccumulateField_type_itemf");
+ RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
+ RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "domain");
+ RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items);
+ RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT);
+ RNA_def_property_ui_text(prop, "Domain", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_fn_random_value(StructRNA *srna)
{
PropertyRNA *prop;
@@ -9465,7 +9877,7 @@ static void def_geo_attribute_attribute_compare(StructRNA *srna)
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_node_float_compare_items);
- RNA_def_property_enum_default(prop, NODE_FLOAT_COMPARE_GREATER_THAN);
+ RNA_def_property_enum_default(prop, NODE_COMPARE_GREATER_THAN);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
@@ -9507,6 +9919,27 @@ static void def_geo_point_distribute(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_extrude_mesh(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem mode_items[] = {
+ {GEO_NODE_EXTRUDE_MESH_VERTICES, "VERTICES", 0, "Vertices", ""},
+ {GEO_NODE_EXTRUDE_MESH_EDGES, "EDGES", 0, "Edges", ""},
+ {GEO_NODE_EXTRUDE_MESH_FACES, "FACES", 0, "Faces", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryExtrudeMesh", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_enum_default(prop, GEO_NODE_EXTRUDE_MESH_FACES);
+ RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_geo_distribute_points_on_faces(StructRNA *srna)
{
PropertyRNA *prop;
@@ -9660,6 +10093,36 @@ static void def_geo_curve_set_handles(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_legacy_curve_set_handles(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSetHandles", "storage");
+
+ prop = RNA_def_property(srna, "handle_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "handle_type");
+ RNA_def_property_enum_items(prop, rna_node_geometry_curve_handle_type_items);
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_node_geometry_curve_handle_side_items);
+ RNA_def_property_ui_text(prop, "Mode", "Whether to update left and right handles");
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
+static void def_geo_curve_set_handle_positions(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometrySetCurveHandlePositions", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_node_geometry_curve_handle_side_items);
+ RNA_def_property_ui_text(prop, "Mode", "Whether to update left and right handles");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_curve_select_handles(StructRNA *srna)
{
PropertyRNA *prop;
@@ -9678,6 +10141,24 @@ static void def_geo_curve_select_handles(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_curve_handle_type_selection(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSelectHandles", "storage");
+
+ prop = RNA_def_property(srna, "handle_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "handle_type");
+ RNA_def_property_enum_items(prop, rna_node_geometry_curve_handle_type_items);
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_node_geometry_curve_handle_side_items);
+ RNA_def_property_ui_text(prop, "Mode", "Whether to check the type of left and right handles");
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_curve_primitive_circle(StructRNA *srna)
{
static const EnumPropertyItem mode_items[] = {
@@ -9704,6 +10185,33 @@ static void def_geo_curve_primitive_circle(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_curve_primitive_arc(StructRNA *srna)
+{
+ static const EnumPropertyItem mode_items[] = {
+
+ {GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS,
+ "POINTS",
+ ICON_NONE,
+ "Points",
+ "Define arc by 3 points on circle. Arc is calculated between start and end points"},
+ {GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS,
+ "RADIUS",
+ ICON_NONE,
+ "Radius",
+ "Define radius with a float"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryCurvePrimitiveArc", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "Method used to determine radius and placement");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_curve_primitive_line(StructRNA *srna)
{
static const EnumPropertyItem mode_items[] = {
@@ -9790,6 +10298,51 @@ static void def_geo_point_rotate(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_fn_rotate_euler(StructRNA *srna)
+{
+ static const EnumPropertyItem type_items[] = {
+ {FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE,
+ "AXIS_ANGLE",
+ ICON_NONE,
+ "Axis Angle",
+ "Rotate around an axis by an angle"},
+ {FN_NODE_ROTATE_EULER_TYPE_EULER,
+ "EULER",
+ ICON_NONE,
+ "Euler",
+ "Rotate around the X, Y, and Z axes"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem space_items[] = {
+ {FN_NODE_ROTATE_EULER_SPACE_OBJECT,
+ "OBJECT",
+ ICON_NONE,
+ "Object",
+ "Rotate the input rotation in the local space of the object"},
+ {FN_NODE_ROTATE_EULER_SPACE_LOCAL,
+ "LOCAL",
+ ICON_NONE,
+ "Local",
+ "Rotate the input rotation in its local space"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, type_items);
+ RNA_def_property_ui_text(prop, "Type", "Method used to describe the rotation");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom2");
+ RNA_def_property_enum_items(prop, space_items);
+ RNA_def_property_ui_text(prop, "Space", "Base orientation for rotation");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_geo_align_rotation_to_vector(StructRNA *srna)
{
static const EnumPropertyItem axis_items[] = {
@@ -9860,6 +10413,66 @@ static void def_geo_align_rotation_to_vector(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_fn_align_euler_to_vector(StructRNA *srna)
+{
+ static const EnumPropertyItem axis_items[] = {
+ {FN_NODE_ALIGN_EULER_TO_VECTOR_AXIS_X,
+ "X",
+ ICON_NONE,
+ "X",
+ "Align the X axis with the vector"},
+ {FN_NODE_ALIGN_EULER_TO_VECTOR_AXIS_Y,
+ "Y",
+ ICON_NONE,
+ "Y",
+ "Align the Y axis with the vector"},
+ {FN_NODE_ALIGN_EULER_TO_VECTOR_AXIS_Z,
+ "Z",
+ ICON_NONE,
+ "Z",
+ "Align the Z axis with the vector"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem pivot_axis_items[] = {
+ {FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_AUTO,
+ "AUTO",
+ ICON_NONE,
+ "Auto",
+ "Automatically detect the best rotation axis to rotate towards the vector"},
+ {FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_X,
+ "X",
+ ICON_NONE,
+ "X",
+ "Rotate around the local X axis"},
+ {FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_Y,
+ "Y",
+ ICON_NONE,
+ "Y",
+ "Rotate around the local Y axis"},
+ {FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_Z,
+ "Z",
+ ICON_NONE,
+ "Z",
+ "Rotate around the local Z axis"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, axis_items);
+ RNA_def_property_ui_text(prop, "Axis", "Axis to align to the vector");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "pivot_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom2");
+ RNA_def_property_enum_items(prop, pivot_axis_items);
+ RNA_def_property_ui_text(prop, "Pivot Axis", "Axis to rotate around");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_geo_point_scale(StructRNA *srna)
{
PropertyRNA *prop;
@@ -9914,7 +10527,7 @@ static void def_geo_object_info(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
-static void def_geo_points_to_volume(StructRNA *srna)
+static void def_geo_legacy_points_to_volume(StructRNA *srna)
{
PropertyRNA *prop;
@@ -9945,6 +10558,32 @@ static void def_geo_points_to_volume(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_points_to_volume(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem resolution_mode_items[] = {
+ {GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT,
+ "VOXEL_AMOUNT",
+ 0,
+ "Amount",
+ "Specify the approximate number of voxels along the diagonal"},
+ {GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE,
+ "VOXEL_SIZE",
+ 0,
+ "Size",
+ "Specify the voxel side length"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryPointsToVolume", "storage");
+
+ prop = RNA_def_property(srna, "resolution_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, resolution_mode_items);
+ RNA_def_property_ui_text(prop, "Resolution Mode", "How the voxel size is specified");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_collection_info(StructRNA *srna)
{
PropertyRNA *prop;
@@ -10051,12 +10690,12 @@ static void def_geo_volume_to_mesh(StructRNA *srna)
{VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT,
"VOXEL_AMOUNT",
0,
- "Voxel Amount",
+ "Amount",
"Desired number of voxels along one axis"},
{VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE,
"VOXEL_SIZE",
0,
- "Voxel Size",
+ "Size",
"Desired voxel side length"},
{0, NULL, 0, NULL, NULL},
};
@@ -10124,7 +10763,7 @@ static void def_geo_mesh_cylinder(StructRNA *srna)
prop = RNA_def_property(srna, "fill_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_mesh_circle_fill_type_items);
RNA_def_property_ui_text(prop, "Fill Type", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_geo_mesh_cone(StructRNA *srna)
@@ -10136,7 +10775,7 @@ static void def_geo_mesh_cone(StructRNA *srna)
prop = RNA_def_property(srna, "fill_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_mesh_circle_fill_type_items);
RNA_def_property_ui_text(prop, "Fill Type", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_geo_mesh_line(StructRNA *srna)
@@ -10269,7 +10908,7 @@ static void def_geo_curve_resample(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
-static void def_geo_curve_subdivide(StructRNA *srna)
+static void def_geo_legacy_curve_subdivide(StructRNA *srna)
{
PropertyRNA *prop;
@@ -10307,6 +10946,38 @@ static void def_geo_curve_fillet(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_legacy_curve_to_points(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem mode_items[] = {
+ {GEO_NODE_CURVE_RESAMPLE_EVALUATED,
+ "EVALUATED",
+ 0,
+ "Evaluated",
+ "Create points from the curve's evaluated points, based on the resolution attribute for "
+ "NURBS and Bezier splines"},
+ {GEO_NODE_CURVE_RESAMPLE_COUNT,
+ "COUNT",
+ 0,
+ "Count",
+ "Sample each spline by evenly distributing the specified number of points"},
+ {GEO_NODE_CURVE_RESAMPLE_LENGTH,
+ "LENGTH",
+ 0,
+ "Length",
+ "Sample each spline by splitting it into segments with the specified length"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryCurveToPoints", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "How to generate points from the input curve");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_curve_to_points(StructRNA *srna)
{
PropertyRNA *prop;
@@ -10404,13 +11075,13 @@ static void def_geo_curve_trim(StructRNA *srna)
static void def_geo_attribute_transfer(StructRNA *srna)
{
static EnumPropertyItem mapping_items[] = {
- {GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED,
+ {GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED,
"NEAREST_FACE_INTERPOLATED",
0,
"Nearest Face Interpolated",
"Transfer the attribute from the nearest face on a surface (loose points and edges are "
"ignored)"},
- {GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST,
+ {GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER_NEAREST,
"NEAREST",
0,
"Nearest",
@@ -10435,6 +11106,53 @@ static void def_geo_attribute_transfer(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_geo_transfer_attribute(StructRNA *srna)
+{
+ static EnumPropertyItem mapping_items[] = {
+ {GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED,
+ "NEAREST_FACE_INTERPOLATED",
+ 0,
+ "Nearest Face Interpolated",
+ "Transfer the attribute from the nearest face on a surface (loose points and edges are "
+ "ignored)"},
+ {GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST,
+ "NEAREST",
+ 0,
+ "Nearest",
+ "Transfer the element from the nearest element (using face and edge centers for the "
+ "distance computation)"},
+ {GEO_NODE_ATTRIBUTE_TRANSFER_INDEX,
+ "INDEX",
+ 0,
+ "Index",
+ "Transfer the data from the element with the corresponding index in the target geometry"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryTransferAttribute", "storage");
+
+ prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, mapping_items);
+ RNA_def_property_ui_text(prop, "Mapping", "Mapping between geometries");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_NodeGeometryTransferAttribute_type_itemf");
+ RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
+ RNA_def_property_ui_text(prop, "Data Type", "The type for the source and result data");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items);
+ RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT);
+ RNA_def_property_ui_text(prop, "Domain", "The domain to use on the target geometry");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_geo_input_material(StructRNA *srna)
{
PropertyRNA *prop;
@@ -10448,7 +11166,7 @@ static void def_geo_input_material(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
-static void def_geo_raycast(StructRNA *srna)
+static void def_geo_legacy_raycast(StructRNA *srna)
{
static EnumPropertyItem mapping_items[] = {
{GEO_NODE_RAYCAST_INTERPOLATED,
@@ -10484,6 +11202,39 @@ static void def_geo_raycast(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_raycast(StructRNA *srna)
+{
+ static EnumPropertyItem mapping_items[] = {
+ {GEO_NODE_RAYCAST_INTERPOLATED,
+ "INTERPOLATED",
+ 0,
+ "Interpolated",
+ "Interpolate the attribute from the corners of the hit face"},
+ {GEO_NODE_RAYCAST_NEAREST,
+ "NEAREST",
+ 0,
+ "Nearest",
+ "Use the attribute value of the closest mesh element"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryRaycast", "storage");
+
+ prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mapping_items);
+ RNA_def_property_ui_text(prop, "Mapping", "Mapping from the target geometry to hit points");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeFill_type_itemf");
+ RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
+ RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+}
+
static void def_geo_curve_fill(StructRNA *srna)
{
static const EnumPropertyItem mode_items[] = {
@@ -10522,6 +11273,31 @@ static void def_geo_attribute_capture(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_geo_delete_geometry(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem mode_items[] = {
+ {GEO_NODE_DELETE_GEOMETRY_MODE_ALL, "ALL", 0, "All", ""},
+ {GEO_NODE_DELETE_GEOMETRY_MODE_EDGE_FACE, "EDGE_FACE", 0, "Only Edges & Faces", ""},
+ {GEO_NODE_DELETE_GEOMETRY_MODE_ONLY_FACE, "ONLY_FACE", 0, "Only Faces", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+ RNA_def_struct_sdna_from(srna, "NodeGeometryDeleteGeometry", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_enum_default(prop, GEO_NODE_DELETE_GEOMETRY_MODE_ALL);
+ RNA_def_property_ui_text(prop, "Mode", "Which parts of the mesh component to delete");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_domain_without_corner_items);
+ RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT);
+ RNA_def_property_ui_text(prop, "Domain", "Which domain to delete in");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_geo_string_to_curves(StructRNA *srna)
{
static const EnumPropertyItem rna_node_geometry_string_to_curves_overflow_items[] = {
@@ -10636,6 +11412,109 @@ static void def_geo_string_to_curves(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_geo_separate_geometry(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometrySeparateGeometry", "storage");
+
+ prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_domain_without_corner_items);
+ RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT);
+ RNA_def_property_ui_text(prop, "Domain", "Which domain to separate on");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
+static void def_geo_viewer(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryViewer", "storage");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeFill_type_itemf");
+ RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
+ RNA_def_property_ui_text(prop, "Data Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+}
+
+static void def_geo_realize_instances(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "legacy_behavior", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "custom1", GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR);
+ RNA_def_property_ui_text(
+ prop, "Legacy Behavior", "Behave like before instance attributes existed");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+}
+
+static void def_geo_field_at_index(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items);
+ RNA_def_property_ui_text(prop, "Domain", "Domain the field is evaluated in");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom2");
+ RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeFill_type_itemf");
+ RNA_def_property_ui_text(prop, "Data Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+}
+
+static void def_geo_scale_elements(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem domain_items[] = {
+ {ATTR_DOMAIN_FACE,
+ "FACE",
+ ICON_NONE,
+ "Face",
+ "Scale individual faces or neighboring face islands"},
+ {ATTR_DOMAIN_EDGE,
+ "EDGE",
+ ICON_NONE,
+ "Edge",
+ "Scale individual edges or neighboring edge islands"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem scale_mode_items[] = {
+ {GEO_NODE_SCALE_ELEMENTS_UNIFORM,
+ "UNIFORM",
+ ICON_NONE,
+ "Uniform",
+ "Scale elements by the same factor in every direction"},
+ {GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS,
+ "SINGLE_AXIS",
+ ICON_NONE,
+ "Single Axis",
+ "Scale elements in a single direction"},
+ {0, NULL, 0, NULL, NULL},
+
+ };
+
+ prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, domain_items);
+ RNA_def_property_enum_default(prop, ATTR_DOMAIN_FACE);
+ RNA_def_property_ui_text(prop, "Domain", "Element type to transform");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+
+ prop = RNA_def_property(srna, "scale_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom2");
+ RNA_def_property_enum_items(prop, scale_mode_items);
+ RNA_def_property_ui_text(prop, "Scale Mode", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)
@@ -11722,7 +12601,7 @@ static void rna_def_internal_node(BlenderRNA *brna)
func = RNA_def_function(srna, "update", "rna_NodeInternal_update");
RNA_def_function_ui_description(
func, "Update on node graph topology changes (adding or removing nodes and links)");
- RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_ALLOW_WRITE);
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_ALLOW_WRITE);
/* draw buttons */
func = RNA_def_function(srna, "draw_buttons", "rna_NodeInternal_draw_buttons");
@@ -12298,6 +13177,11 @@ static void rna_def_nodetree(BlenderRNA *brna)
PropertyRNA *parm;
static const EnumPropertyItem static_type_items[] = {
+ {NTREE_UNDEFINED,
+ "UNDEFINED",
+ ICON_QUESTION,
+ "Undefined",
+ "Undefined type of nodes (can happen e.g. when a linked node tree goes missing)"},
{NTREE_SHADER, "SHADER", ICON_MATERIAL, "Shader", "Shader nodes"},
{NTREE_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture nodes"},
{NTREE_COMPOSIT, "COMPOSITING", ICON_RENDERLAYERS, "Compositing", "Compositing nodes"},
@@ -12318,6 +13202,8 @@ static void rna_def_nodetree(BlenderRNA *brna)
prop = RNA_def_property(srna, "view_center", PROP_FLOAT, PROP_XYZ);
RNA_def_property_array(prop, 2);
RNA_def_property_float_sdna(prop, NULL, "view_center");
+ RNA_def_property_ui_text(
+ prop, "", "The current location (offset) of the view for this Node Tree");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* AnimData */
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 99865078cbe..a098693459b 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -620,11 +620,7 @@ static StructRNA *rna_Object_data_typef(PointerRNA *ptr)
return &RNA_ID;
# endif
case OB_POINTCLOUD:
-# ifdef WITH_POINT_CLOUD
return &RNA_PointCloud;
-# else
- return &RNA_ID;
-# endif
case OB_VOLUME:
return &RNA_Volume;
default:
@@ -1673,6 +1669,7 @@ static bConstraint *rna_Object_constraints_copy(Object *object, Main *bmain, Poi
{
bConstraint *con = con_ptr->data;
bConstraint *new_con = BKE_constraint_copy_for_object(object, con);
+ new_con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL;
ED_object_constraint_tag_update(bmain, object, new_con);
WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, object);
@@ -1704,27 +1701,20 @@ bool rna_Object_constraints_override_apply(Main *UNUSED(bmain),
/* Remember that insertion operations are defined and stored in correct order, which means that
* even if we insert several items in a row, we always insert first one, then second one, etc.
* So we should always find 'anchor' constraint in both _src *and* _dst. */
- bConstraint *con_anchor = NULL;
- if (opop->subitem_local_name && opop->subitem_local_name[0]) {
- con_anchor = BLI_findstring(
- &ob_dst->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
- }
- if (con_anchor == NULL && opop->subitem_local_index >= 0) {
- con_anchor = BLI_findlink(&ob_dst->constraints, opop->subitem_local_index);
- }
- /* Otherwise we just insert in first position. */
-
- bConstraint *con_src = NULL;
- if (opop->subitem_local_name && opop->subitem_local_name[0]) {
- con_src = BLI_findstring(
- &ob_src->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
- }
- if (con_src == NULL && opop->subitem_local_index >= 0) {
- con_src = BLI_findlink(&ob_src->constraints, opop->subitem_local_index);
+ const size_t name_offset = offsetof(bConstraint, name);
+ bConstraint *con_anchor = BLI_listbase_string_or_index_find(&ob_dst->constraints,
+ opop->subitem_reference_name,
+ name_offset,
+ opop->subitem_reference_index);
+ /* If `con_anchor` is NULL, `con_src` will be inserted in first position. */
+
+ bConstraint *con_src = BLI_listbase_string_or_index_find(
+ &ob_src->constraints, opop->subitem_local_name, name_offset, opop->subitem_local_index);
+
+ if (con_src == NULL) {
+ BLI_assert(con_src != NULL);
+ return false;
}
- con_src = con_src ? con_src->next : ob_src->constraints.first;
-
- BLI_assert(con_src != NULL);
bConstraint *con_dst = BKE_constraint_duplicate_ex(con_src, 0, true);
@@ -1826,25 +1816,15 @@ bool rna_Object_modifiers_override_apply(Main *bmain,
/* Remember that insertion operations are defined and stored in correct order, which means that
* even if we insert several items in a row, we always insert first one, then second one, etc.
* So we should always find 'anchor' modifier in both _src *and* _dst. */
- ModifierData *mod_anchor = NULL;
- if (opop->subitem_local_name && opop->subitem_local_name[0]) {
- mod_anchor = BLI_findstring(
- &ob_dst->modifiers, opop->subitem_local_name, offsetof(ModifierData, name));
- }
- if (mod_anchor == NULL && opop->subitem_local_index >= 0) {
- mod_anchor = BLI_findlink(&ob_dst->modifiers, opop->subitem_local_index);
- }
- /* Otherwise we just insert in first position. */
+ const size_t name_offset = offsetof(ModifierData, name);
+ ModifierData *mod_anchor = BLI_listbase_string_or_index_find(&ob_dst->modifiers,
+ opop->subitem_reference_name,
+ name_offset,
+ opop->subitem_reference_index);
+ /* If `mod_anchor` is NULL, `mod_src` will be inserted in first position. */
- ModifierData *mod_src = NULL;
- if (opop->subitem_local_name && opop->subitem_local_name[0]) {
- mod_src = BLI_findstring(
- &ob_src->modifiers, opop->subitem_local_name, offsetof(ModifierData, name));
- }
- if (mod_src == NULL && opop->subitem_local_index >= 0) {
- mod_src = BLI_findlink(&ob_src->modifiers, opop->subitem_local_index);
- }
- mod_src = mod_src ? mod_src->next : ob_src->modifiers.first;
+ ModifierData *mod_src = BLI_listbase_string_or_index_find(
+ &ob_src->modifiers, opop->subitem_local_name, name_offset, opop->subitem_local_index);
if (mod_src == NULL) {
BLI_assert(mod_src != NULL);
@@ -1933,25 +1913,18 @@ bool rna_Object_greasepencil_modifiers_override_apply(Main *bmain,
/* Remember that insertion operations are defined and stored in correct order, which means that
* even if we insert several items in a row, we always insert first one, then second one, etc.
* So we should always find 'anchor' modifier in both _src *and* _dst. */
- GpencilModifierData *mod_anchor = NULL;
- if (opop->subitem_local_name && opop->subitem_local_name[0]) {
- mod_anchor = BLI_findstring(
- &ob_dst->greasepencil_modifiers, opop->subitem_local_name, offsetof(ModifierData, name));
- }
- if (mod_anchor == NULL && opop->subitem_local_index >= 0) {
- mod_anchor = BLI_findlink(&ob_dst->greasepencil_modifiers, opop->subitem_local_index);
- }
- /* Otherwise we just insert in first position. */
-
- GpencilModifierData *mod_src = NULL;
- if (opop->subitem_local_name && opop->subitem_local_name[0]) {
- mod_src = BLI_findstring(
- &ob_src->greasepencil_modifiers, opop->subitem_local_name, offsetof(ModifierData, name));
- }
- if (mod_src == NULL && opop->subitem_local_index >= 0) {
- mod_src = BLI_findlink(&ob_src->greasepencil_modifiers, opop->subitem_local_index);
- }
- mod_src = mod_src ? mod_src->next : ob_src->greasepencil_modifiers.first;
+ const size_t name_offset = offsetof(GpencilModifierData, name);
+ GpencilModifierData *mod_anchor = BLI_listbase_string_or_index_find(
+ &ob_dst->greasepencil_modifiers,
+ opop->subitem_reference_name,
+ name_offset,
+ opop->subitem_reference_index);
+ /* If `mod_anchor` is NULL, `mod_src` will be inserted in first position. */
+
+ GpencilModifierData *mod_src = BLI_listbase_string_or_index_find(&ob_src->greasepencil_modifiers,
+ opop->subitem_local_name,
+ name_offset,
+ opop->subitem_local_index);
if (mod_src == NULL) {
BLI_assert(mod_src != NULL);
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 10ba2b9acb1..cc9f6454337 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -68,8 +68,8 @@ static const EnumPropertyItem space_items[] = {
# include "BKE_bvhutils.h"
# include "BKE_constraint.h"
# include "BKE_context.h"
+# include "BKE_crazyspace.h"
# include "BKE_customdata.h"
-# include "BKE_font.h"
# include "BKE_global.h"
# include "BKE_layer.h"
# include "BKE_main.h"
@@ -78,6 +78,7 @@ static const EnumPropertyItem space_items[] = {
# include "BKE_modifier.h"
# include "BKE_object.h"
# include "BKE_report.h"
+# include "BKE_vfont.h"
# include "ED_object.h"
# include "ED_screen.h"
@@ -379,6 +380,39 @@ static void rna_Object_camera_fit_coords(
depsgraph, (const float(*)[3])cos, num_cos / 3, ob, co_ret, scale_ret);
}
+static void rna_Object_crazyspace_eval(Object *object,
+ ReportList *reports,
+ Depsgraph *depsgraph,
+ Scene *scene)
+{
+ BKE_crazyspace_api_eval(depsgraph, scene, object, reports);
+}
+
+static void rna_Object_crazyspace_displacement_to_deformed(Object *object,
+ ReportList *reports,
+ const int vertex_index,
+ float displacement[3],
+ float r_displacement_deformed[3])
+{
+ BKE_crazyspace_api_displacement_to_deformed(
+ object, reports, vertex_index, displacement, r_displacement_deformed);
+}
+
+static void rna_Object_crazyspace_displacement_to_original(Object *object,
+ ReportList *reports,
+ const int vertex_index,
+ float displacement_deformed[3],
+ float r_displacement[3])
+{
+ BKE_crazyspace_api_displacement_to_original(
+ object, reports, vertex_index, displacement_deformed, r_displacement);
+}
+
+static void rna_Object_crazyspace_eval_clear(Object *object)
+{
+ BKE_crazyspace_api_eval_clear(object);
+}
+
/* copied from Mesh_getFromObject and adapted to RNA interface */
static Mesh *rna_Object_to_mesh(Object *object,
ReportList *reports,
@@ -530,7 +564,7 @@ static int mesh_looptri_to_poly_index(Mesh *me_eval, const MLoopTri *lt)
return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
}
-/* TOOD(sergey): Make the Python API more clear that evaluation might happen, or requite
+/* TODO(sergey): Make the Python API more clear that evaluation might happen, or require
* passing fully evaluated depsgraph. */
static Object *eval_object_ensure(Object *ob,
bContext *C,
@@ -729,7 +763,7 @@ void rna_Object_me_eval_info(
}
if (me_eval) {
- ret = BKE_mesh_runtime_debug_info(me_eval);
+ ret = BKE_mesh_debug_info(me_eval);
if (ret) {
strcpy(result, ret);
MEM_freeN(ret);
@@ -978,6 +1012,52 @@ void RNA_api_object(StructRNA *srna)
parm, "", "The ortho scale to aim to be able to see all given points (if relevant)");
RNA_def_parameter_flags(parm, 0, PARM_OUTPUT);
+ /* Crazyspace access. */
+
+ func = RNA_def_function(srna, "crazyspace_eval", "rna_Object_crazyspace_eval");
+ RNA_def_function_ui_description(
+ func,
+ "Compute orientation mapping between vertices of an original object and object with shape "
+ "keys and deforming modifiers applied."
+ "The evaluation is to be freed with the crazyspace_eval_free function");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(
+ func, "depsgraph", "Depsgraph", "Dependency Graph", "Evaluated dependency graph");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "scene", "Scene", "Scene", "Scene of the object");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ func = RNA_def_function(srna,
+ "crazyspace_displacement_to_deformed",
+ "rna_Object_crazyspace_displacement_to_deformed");
+ RNA_def_function_ui_description(
+ func, "Convert displacement vector from non-deformed object space to deformed object space");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_property(func, "vertex_index", PROP_INT, PROP_NONE);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_property(func, "displacement", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_array(parm, 3);
+ parm = RNA_def_property(func, "displacement_deformed", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_array(parm, 3);
+ RNA_def_function_output(func, parm);
+
+ func = RNA_def_function(srna,
+ "crazyspace_displacement_to_original",
+ "rna_Object_crazyspace_displacement_to_original");
+ RNA_def_function_ui_description(
+ func, "Convert displacement vector from deformed object space to non-deformed object space");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_property(func, "vertex_index", PROP_INT, PROP_NONE);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_property(func, "displacement", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_array(parm, 3);
+ parm = RNA_def_property(func, "displacement_original", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_array(parm, 3);
+ RNA_def_function_output(func, parm);
+
+ RNA_def_function(srna, "crazyspace_eval_clear", "rna_Object_crazyspace_eval_clear");
+ RNA_def_function_ui_description(func, "Free evaluated state of crazyspace");
+
/* mesh */
func = RNA_def_function(srna, "to_mesh", "rna_Object_to_mesh");
RNA_def_function_ui_description(
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 7f997109920..d697a48e04b 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -985,10 +985,12 @@ static void rna_def_pointcache_common(StructRNA *srna)
prop = RNA_def_property(srna, "is_baked", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PTCACHE_BAKED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "", "The cache is baked");
prop = RNA_def_property(srna, "is_baking", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PTCACHE_BAKING);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "", "The cache is being baked");
prop = RNA_def_property(srna, "use_disk_cache", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PTCACHE_DISK_CACHE);
@@ -999,11 +1001,12 @@ static void rna_def_pointcache_common(StructRNA *srna)
prop = RNA_def_property(srna, "is_outdated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PTCACHE_OUTDATED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Cache is outdated", "");
+ RNA_def_property_ui_text(prop, "Cache Is Outdated", "");
prop = RNA_def_property(srna, "is_frame_skip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PTCACHE_FRAMES_SKIPPED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "", "Some frames were skipped while baking/saving that cache");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "name");
@@ -1125,6 +1128,8 @@ static void rna_def_collision(BlenderRNA *brna)
RNA_def_struct_ui_text(
srna, "Collision Settings", "Collision settings for object in physics simulation");
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "deflect", 1);
RNA_def_property_ui_text(
@@ -1227,6 +1232,8 @@ static void rna_def_collision(BlenderRNA *brna)
"Cloth collision impulses act in the direction of the collider normals "
"(more reliable in some cases)");
RNA_def_property_update(prop, 0, "rna_CollisionSettings_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_effector_weight(BlenderRNA *brna)
@@ -1240,6 +1247,8 @@ static void rna_def_effector_weight(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Effector Weights", "Effector weights for physics simulation");
RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
+ RNA_define_lib_overridable(true);
+
/* Flags */
prop = RNA_def_property(srna, "apply_to_hair_growing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", EFF_WEIGHT_DO_HAIR);
@@ -1359,6 +1368,8 @@ static void rna_def_effector_weight(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_ui_text(prop, "Fluid Flow", "Fluid Flow effector weight");
RNA_def_property_update(prop, 0, "rna_EffectorWeight_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_field(BlenderRNA *brna)
@@ -1468,6 +1479,8 @@ static void rna_def_field(BlenderRNA *brna)
srna, "Field Settings", "Field settings for an object in physics simulation");
RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
+ RNA_define_lib_overridable(true);
+
/* Enums */
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
@@ -1511,34 +1524,34 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_strength");
- RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Strength", "Strength of force field");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
/* different ui range to above */
prop = RNA_def_property(srna, "linear_drag", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_strength");
- RNA_def_property_range(prop, -2.0f, 2.0f);
+ RNA_def_property_ui_range(prop, -2.0f, 2.0f, 10, 3);
RNA_def_property_ui_text(prop, "Linear Drag", "Drag component proportional to velocity");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
prop = RNA_def_property(srna, "harmonic_damping", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_damp");
- RNA_def_property_range(prop, 0.0f, 10.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 10, 3);
RNA_def_property_ui_text(prop, "Harmonic Damping", "Damping of the harmonic force");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
/* different ui range to above */
prop = RNA_def_property(srna, "quadratic_drag", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_damp");
- RNA_def_property_range(prop, -2.0f, 2.0f);
+ RNA_def_property_ui_range(prop, -2.0f, 2.0f, 10, 3);
RNA_def_property_ui_text(
prop, "Quadratic Drag", "Drag component proportional to the square of velocity");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
prop = RNA_def_property(srna, "flow", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_flow");
- RNA_def_property_range(prop, 0.0f, 10.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 10, 3);
RNA_def_property_ui_text(prop, "Flow", "Convert effector force into air flow velocity");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
@@ -1554,7 +1567,7 @@ static void rna_def_field(BlenderRNA *brna)
/* different ui range to above */
prop = RNA_def_property(srna, "inflow", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_flow");
- RNA_def_property_range(prop, -10.0f, 10.0f);
+ RNA_def_property_ui_range(prop, -10.0f, 10.0f, 10, 3);
RNA_def_property_ui_text(prop, "Inflow", "Inwards component of the vortex force");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
@@ -1567,7 +1580,8 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "rest_length", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_size");
- RNA_def_property_range(prop, 0.0f, 1000.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 10, 3);
RNA_def_property_ui_text(prop, "Rest Length", "Rest length of the harmonic force");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
@@ -1725,7 +1739,7 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "guide_minimum", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_strength");
- RNA_def_property_range(prop, 0.0f, 1000.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 10, 3);
RNA_def_property_ui_text(
prop, "Minimum Distance", "The distance from which particles are affected fully");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
@@ -1796,6 +1810,8 @@ static void rna_def_field(BlenderRNA *brna)
/* Variables used for Curve Guide, already wrapped, used for other fields too */
/* falloff_power, use_max_distance, maximum_distance */
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_softbody(BlenderRNA *brna)
@@ -2131,6 +2147,7 @@ static void rna_def_softbody(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "effector_weights");
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
}
diff --git a/source/blender/makesrna/intern/rna_palette.c b/source/blender/makesrna/intern/rna_palette.c
index 67d6daf5a13..30604c7a3b8 100644
--- a/source/blender/makesrna/intern/rna_palette.c
+++ b/source/blender/makesrna/intern/rna_palette.c
@@ -37,12 +37,20 @@
# include "BKE_report.h"
static PaletteColor *rna_Palette_color_new(Palette *palette)
{
+ if (ID_IS_LINKED(palette) || ID_IS_OVERRIDE_LIBRARY(palette)) {
+ return NULL;
+ }
+
PaletteColor *color = BKE_palette_color_add(palette);
return color;
}
static void rna_Palette_color_remove(Palette *palette, ReportList *reports, PointerRNA *color_ptr)
{
+ if (ID_IS_LINKED(palette) || ID_IS_OVERRIDE_LIBRARY(palette)) {
+ return;
+ }
+
PaletteColor *color = color_ptr->data;
if (BLI_findindex(&palette->colors, color) == -1) {
@@ -58,6 +66,10 @@ static void rna_Palette_color_remove(Palette *palette, ReportList *reports, Poin
static void rna_Palette_color_clear(Palette *palette)
{
+ if (ID_IS_LINKED(palette) || ID_IS_OVERRIDE_LIBRARY(palette)) {
+ return;
+ }
+
BKE_palette_clear(palette);
}
@@ -141,6 +153,7 @@ static void rna_def_palettecolor(BlenderRNA *brna)
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "rgb");
+ RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Color", "");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index f732e14d905..fbc7625d815 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -3498,6 +3498,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
/* animation here? */
@@ -3507,12 +3508,14 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "pd");
RNA_def_property_struct_type(prop, "FieldSettings");
RNA_def_property_pointer_funcs(prop, "rna_Particle_field1_get", NULL, NULL, NULL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Force Field 1", "");
prop = RNA_def_property(srna, "force_field_2", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "pd2");
RNA_def_property_struct_type(prop, "FieldSettings");
RNA_def_property_pointer_funcs(prop, "rna_Particle_field2_get", NULL, NULL, NULL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Force Field 2", "");
/* twist */
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index ee509fa92d4..76bfea00a79 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -650,6 +650,7 @@ static bConstraint *rna_PoseChannel_constraints_copy(ID *id,
Object *ob = (Object *)id;
bConstraint *con = con_ptr->data;
bConstraint *new_con = BKE_constraint_copy_for_pose(ob, pchan, con);
+ new_con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL;
ED_object_constraint_dependency_tag_update(bmain, ob, new_con);
WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, id);
@@ -681,29 +682,18 @@ bool rna_PoseChannel_constraints_override_apply(Main *UNUSED(bmain),
/* Remember that insertion operations are defined and stored in correct order, which means that
* even if we insert several items in a row, we always insert first one, then second one, etc.
* So we should always find 'anchor' constraint in both _src *and* _dst */
- bConstraint *con_anchor = NULL;
- if (opop->subitem_local_name && opop->subitem_local_name[0]) {
- con_anchor = BLI_findstring(
- &pchan_dst->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
- }
- if (con_anchor == NULL && opop->subitem_local_index >= 0) {
- con_anchor = BLI_findlink(&pchan_dst->constraints, opop->subitem_local_index);
- }
- /* Otherwise we just insert in first position. */
+ const size_t name_offset = offsetof(bConstraint, name);
+ bConstraint *con_anchor = BLI_listbase_string_or_index_find(&pchan_dst->constraints,
+ opop->subitem_reference_name,
+ name_offset,
+ opop->subitem_reference_index);
+ /* If `con_anchor` is NULL, `con_src` will be inserted in first position. */
- bConstraint *con_src = NULL;
- if (opop->subitem_local_name && opop->subitem_local_name[0]) {
- con_src = BLI_findstring(
- &pchan_src->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
- }
- if (con_src == NULL && opop->subitem_local_index >= 0) {
- con_src = BLI_findlink(&pchan_src->constraints, opop->subitem_local_index);
- }
- con_src = con_src ? con_src->next : pchan_src->constraints.first;
+ bConstraint *con_src = BLI_listbase_string_or_index_find(
+ &pchan_src->constraints, opop->subitem_local_name, name_offset, opop->subitem_local_index);
if (con_src == NULL) {
- printf("%s: Could not find constraint to insert, doing nothing...\n", __func__);
- BLI_assert(0);
+ BLI_assert(con_src != NULL);
return false;
}
@@ -879,7 +869,6 @@ static void rna_PoseChannel_custom_shape_transform_set(PointerRNA *ptr,
#else
-/* common properties for Action/Bone Groups - related to color */
void rna_def_actionbone_group_common(StructRNA *srna, int update_flag, const char *update_cb)
{
PropertyRNA *prop;
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index fcb46904e8d..65e9a140f82 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -98,6 +98,7 @@ const EnumPropertyItem rna_enum_bake_pass_type_items[] = {
# include "RNA_access.h"
+# include "BKE_appdir.h"
# include "BKE_context.h"
# include "BKE_report.h"
@@ -420,6 +421,16 @@ static StructRNA *rna_RenderEngine_refine(PointerRNA *ptr)
&RNA_RenderEngine;
}
+static void rna_RenderEngine_tempdir_get(PointerRNA *UNUSED(ptr), char *value)
+{
+ BLI_strncpy(value, BKE_tempdir_session(), FILE_MAX);
+}
+
+static int rna_RenderEngine_tempdir_length(PointerRNA *UNUSED(ptr))
+{
+ return strlen(BKE_tempdir_session());
+}
+
static PointerRNA rna_RenderEngine_render_get(PointerRNA *ptr)
{
RenderEngine *engine = (RenderEngine *)ptr->data;
@@ -860,6 +871,12 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "resolution_y");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ prop = RNA_def_property(srna, "temporary_directory", PROP_STRING, PROP_NONE);
+ RNA_def_function_ui_description(func, "The temp directory used by Blender");
+ RNA_def_property_string_funcs(
+ prop, "rna_RenderEngine_tempdir_get", "rna_RenderEngine_tempdir_length", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
/* Render Data */
prop = RNA_def_property(srna, "render", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "RenderSettings");
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index c51931d0d1a..10e28ac3948 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -233,10 +233,12 @@ static void rna_RigidBodyOb_shape_update(Main *bmain, Scene *scene, PointerRNA *
static void rna_RigidBodyOb_shape_reset(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
{
- RigidBodyWorld *rbw = scene->rigidbody_world;
- RigidBodyOb *rbo = (RigidBodyOb *)ptr->data;
+ if (scene != NULL) {
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ BKE_rigidbody_cache_reset(rbw);
+ }
- BKE_rigidbody_cache_reset(rbw);
+ RigidBodyOb *rbo = (RigidBodyOb *)ptr->data;
if (rbo->shared->physics_shape) {
rbo->flag |= RBO_FLAG_NEEDS_RESHAPE;
}
@@ -955,6 +957,7 @@ static void rna_def_rigidbody_world(BlenderRNA *brna)
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
/* Sweep test */
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 12fb7a40d13..85955c5e9f7 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -1916,16 +1916,21 @@ int rna_property_override_diff_default(Main *bmain,
/* Collections do not support replacement of their data (except for collections of ID
* pointers), since they do not support removing, only in *some* cases, insertion. We
- * also assume then that _a data is the one where things are inserted. */
+ * also assume then that _a data is the one where things are inserted.
+ *
+ * NOTE: In insertion case, both 'local' and 'reference' (aka anchor) sub-item
+ * identifiers refer to collection items in the local override. The 'reference' may match
+ * an item in the linked reference data, but it can also be another local-only item added
+ * by a previous INSERT operation. */
if (is_valid_for_insertion && use_collection_insertion) {
op = BKE_lib_override_library_property_get(override, rna_path, &created);
BKE_lib_override_library_property_operation_get(op,
IDOVERRIDE_LIBRARY_OP_INSERT_AFTER,
- NULL,
no_prop_name ? NULL : prev_propname_a,
- -1,
+ no_prop_name ? NULL : propname_a,
idx_a - 1,
+ idx_a,
true,
NULL,
NULL);
@@ -1936,6 +1941,8 @@ int rna_property_override_diff_default(Main *bmain,
idx_a - 1);
# endif
op = NULL;
+
+ equals = false;
}
else if (is_id || is_valid_for_diffing) {
if (equals || do_create) {
@@ -2977,14 +2984,14 @@ static void rna_def_function(BlenderRNA *brna)
RNA_def_property_ui_text(
prop,
"No Self",
- "Function does not pass its self as an argument (becomes a static method in python)");
+ "Function does not pass itself as an argument (becomes a static method in python)");
prop = RNA_def_property(srna, "use_self_type", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Function_use_self_type_get", NULL);
RNA_def_property_ui_text(prop,
"Use Self Type",
- "Function passes its self type as an argument (becomes a class method "
+ "Function passes itself type as an argument (becomes a class method "
"in python if use_self is false)");
}
@@ -3110,7 +3117,11 @@ static void rna_def_number_property(StructRNA *srna, PropertyType type)
prop = RNA_def_property(srna, "precision", PROP_INT, PROP_UNSIGNED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_int_funcs(prop, "rna_FloatProperty_precision_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Precision", "Number of digits after the dot used by buttons");
+ RNA_def_property_ui_text(prop,
+ "Precision",
+ "Number of digits after the dot used by buttons. Fraction is "
+ "automatically hidden for exact integer values of fields with unit "
+ "'NONE' or 'TIME' (frame count) and step divisible by 100");
}
}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index df5eb9f1401..18e50be031b 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -86,8 +86,7 @@ const EnumPropertyItem rna_enum_exr_codec_items[] = {
{R_IMF_EXR_CODEC_B44, "B44", 0, "B44 (lossy)", ""},
{R_IMF_EXR_CODEC_B44A, "B44A", 0, "B44A (lossy)", ""},
{R_IMF_EXR_CODEC_DWAA, "DWAA", 0, "DWAA (lossy)", ""},
- /* NOTE: Commented out for until new OpenEXR is released, see T50673. */
- /* {R_IMF_EXR_CODEC_DWAB, "DWAB", 0, "DWAB (lossy)", ""}, */
+ {R_IMF_EXR_CODEC_DWAB, "DWAB", 0, "DWAB (lossy)", ""},
{0, NULL, 0, NULL, NULL},
};
#endif
@@ -433,6 +432,16 @@ const EnumPropertyItem rna_enum_normal_swizzle_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_bake_margin_type_items[] = {
+ {R_BAKE_ADJACENT_FACES,
+ "ADJACENT_FACES",
+ 0,
+ "Adjacent Faces",
+ "Use pixels from adjacent faces across UV seams"},
+ {R_BAKE_EXTEND, "EXTEND", 0, "Extend", "Extend border pixels outwards"},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_bake_target_items[] = {
{R_BAKE_TARGET_IMAGE_TEXTURES,
"IMAGE_TEXTURES",
@@ -646,6 +655,8 @@ const EnumPropertyItem rna_enum_transform_orientation_items[] = {
# include "BKE_screen.h"
# include "BKE_unit.h"
+# include "NOD_composite.h"
+
# include "ED_image.h"
# include "ED_info.h"
# include "ED_keyframing.h"
@@ -3262,6 +3273,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"Automerge",
"Join by distance last drawn stroke with previous strokes in the active layer");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "gpencil_sculpt", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gp_sculpt");
@@ -3425,7 +3437,8 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop,
"Cycle-Aware Keying",
"For channels with cyclic extrapolation, keyframe insertion is automatically "
- "remapped inside the cycle time range, and keeps ends in sync");
+ "remapped inside the cycle time range, and keeps ends in sync. Curves newly added to "
+ "actions with a Manual Frame Range and Cyclic Animation are automatically made cyclic");
/* Keyframing */
prop = RNA_def_property(srna, "keyframe_type", PROP_ENUM, PROP_NONE);
@@ -3539,7 +3552,9 @@ static void rna_def_sequencer_tool_settings(BlenderRNA *brna)
};
static const EnumPropertyItem pivot_points[] = {
+ {V3D_AROUND_CENTER_BOUNDS, "CENTER", ICON_PIVOT_BOUNDBOX, "Bounding Box Center", ""},
{V3D_AROUND_CENTER_MEDIAN, "MEDIAN", ICON_PIVOT_MEDIAN, "Median Point", ""},
+ {V3D_AROUND_CURSOR, "CURSOR", ICON_PIVOT_CURSOR, "2D Cursor", "Pivot around the 2D cursor"},
{V3D_AROUND_LOCAL_ORIGINS,
"INDIVIDUAL_ORIGINS",
ICON_PIVOT_INDIVIDUAL,
@@ -4164,6 +4179,13 @@ void rna_def_view_layer_common(BlenderRNA *brna, StructRNA *srna, const bool sce
prop, "Cryptomatte Levels", "Sets how many unique objects can be distinguished per pixel");
RNA_def_property_ui_range(prop, 2.0, 16.0, 2.0, 0.0);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
+
+ prop = RNA_def_property(srna, "use_pass_cryptomatte_accurate", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cryptomatte_flag", VIEW_LAYER_CRYPTOMATTE_ACCURATE);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(
+ prop, "Cryptomatte Accurate", "Generate a more accurate cryptomatte pass");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
}
prop = RNA_def_property(srna, "use_solid", PROP_BOOLEAN, PROP_NONE);
@@ -5045,6 +5067,11 @@ static void rna_def_bake_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Margin", "Extends the baked result as a post process filter");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ prop = RNA_def_property(srna, "margin_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_bake_margin_type_items);
+ RNA_def_property_ui_text(prop, "Margin Type", "Algorithm to extend the baked result");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "max_ray_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3);
@@ -5573,7 +5600,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
{FFMPEG_MPEG2, "MPEG2", 0, "MPEG-2", ""},
{FFMPEG_MPEG4, "MPEG4", 0, "MPEG-4", ""},
{FFMPEG_AVI, "AVI", 0, "AVI", ""},
- {FFMPEG_MOV, "QUICKTIME", 0, "Quicktime", ""},
+ {FFMPEG_MOV, "QUICKTIME", 0, "QuickTime", ""},
{FFMPEG_DV, "DV", 0, "DV", ""},
{FFMPEG_OGG, "OGG", 0, "Ogg", ""},
{FFMPEG_MKV, "MKV", 0, "Matroska", ""},
@@ -5836,6 +5863,16 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem bake_margin_type_items[] = {
+ {R_BAKE_ADJACENT_FACES,
+ "ADJACENT_FACES",
+ 0,
+ "Adjacent Faces",
+ "Use pixels from adjacent faces across UV seams"},
+ {R_BAKE_EXTEND, "EXTEND", 0, "Extend", "Extend border pixels outwards"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
static const EnumPropertyItem pixel_size_items[] = {
{0, "AUTO", 0, "Automatic", "Automatic pixel size, depends on the user interface scale"},
{1, "1", 0, "1x", "Render at full resolution"},
@@ -6251,11 +6288,17 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "bake_margin", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "bake_filter");
+ RNA_def_property_int_sdna(prop, NULL, "bake_margin");
RNA_def_property_range(prop, 0, 64);
RNA_def_property_ui_text(prop, "Margin", "Extends the baked result as a post process filter");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ prop = RNA_def_property(srna, "bake_margin_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "bake_margin_type");
+ RNA_def_property_enum_items(prop, bake_margin_type_items);
+ RNA_def_property_ui_text(prop, "Margin Type", "Algorithm to generate the margin");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "bake_bias", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bake_biasdist");
RNA_def_property_range(prop, 0.0, 1000.0);
@@ -7051,7 +7094,7 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "ssr_quality", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_ui_text(prop, "Trace Precision", "Precision of the screen space raytracing");
+ RNA_def_property_ui_text(prop, "Trace Precision", "Precision of the screen space ray-tracing");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -7861,8 +7904,10 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "clip");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_struct_type(prop, "MovieClip");
- RNA_def_property_ui_text(
- prop, "Active Movie Clip", "Active movie clip used for constraints and viewport drawing");
+ RNA_def_property_ui_text(prop,
+ "Active Movie Clip",
+ "Active Movie Clip that can be used by motion tracking constraints "
+ "or as a camera's background image");
RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
/* color management */
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 3e292ea89e2..41ba8119202 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -91,7 +91,7 @@ static void rna_Scene_frame_set(Scene *scene, Main *bmain, int frame, float subf
if (!G.is_rendering) {
/* can't use NC_SCENE|ND_FRAME because this causes wm_event_do_notifiers to call
* BKE_scene_graph_update_for_newframe which will lose any un-keyed changes T24690. */
- /* WM_main_add_notifier(NC_SCENE|ND_FRAME, scene); */
+ // WM_main_add_notifier(NC_SCENE|ND_FRAME, scene);
/* instead just redraw the views */
WM_main_add_notifier(NC_WINDOW, NULL);
@@ -154,6 +154,7 @@ static void rna_Scene_ray_cast(Scene *scene,
bool ret = ED_transform_snap_object_project_ray_ex(sctx,
depsgraph,
+ NULL,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
},
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index 912f47ba9aa..a8f28f6091c 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -46,6 +46,7 @@ const EnumPropertyItem rna_enum_region_type_items[] = {
{RGN_TYPE_EXECUTE, "EXECUTE", 0, "Execute Buttons", ""},
{RGN_TYPE_FOOTER, "FOOTER", 0, "Footer", ""},
{RGN_TYPE_TOOL_HEADER, "TOOL_HEADER", 0, "Tool Header", ""},
+ {RGN_TYPE_XR, "XR", 0, "XR", ""},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index a2db1536f55..2358d236c4d 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -672,7 +672,7 @@ static void rna_def_paint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Cavity Mask", "Mask painting according to mesh geometry cavity");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "tile_offset", PROP_FLOAT, PROP_XYZ);
+ prop = RNA_def_property(srna, "tile_offset", PROP_FLOAT, PROP_XYZ_LENGTH);
RNA_def_property_float_sdna(prop, NULL, "tile_offset");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, 0.01, FLT_MAX);
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 7303f6c920a..6c3e3ab3058 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -303,7 +303,7 @@ static void do_sequence_frame_change_update(Scene *scene, Sequence *seq)
Editing *ed = SEQ_editing_get(scene);
ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
Sequence *tseq;
- SEQ_time_update_sequence_bounds(scene, seq);
+ SEQ_time_update_sequence(scene, seqbase, seq);
/* ensure effects are always fit in length to their input */
@@ -312,7 +312,7 @@ static void do_sequence_frame_change_update(Scene *scene, Sequence *seq)
*/
for (tseq = seqbase->first; tseq; tseq = tseq->next) {
if (tseq->seq1 || tseq->seq2 || tseq->seq3) {
- SEQ_time_update_sequence(scene, tseq);
+ SEQ_time_update_sequence(scene, seqbase, tseq);
}
}
@@ -756,13 +756,16 @@ static IDProperty **rna_Sequence_idprops(PointerRNA *ptr)
static bool rna_MovieSequence_reload_if_needed(ID *scene_id, Sequence *seq, Main *bmain)
{
Scene *scene = (Scene *)scene_id;
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+
bool has_reloaded;
bool can_produce_frames;
SEQ_add_movie_reload_if_needed(bmain, scene, seq, &has_reloaded, &can_produce_frames);
if (has_reloaded && can_produce_frames) {
- SEQ_time_update_sequence(scene, seq);
+ SEQ_time_update_sequence(scene, seqbase, seq);
SEQ_relations_invalidate_cache_raw(scene, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@@ -950,7 +953,9 @@ static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), Poin
Scene *scene = (Scene *)ptr->owner_id;
Sequence *seq = (Sequence *)(ptr->data);
SEQ_add_reload_new_file(bmain, scene, seq, true);
- SEQ_time_update_sequence(scene, seq);
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+ SEQ_time_update_sequence(scene, seqbase, seq);
rna_Sequence_invalidate_raw_update(bmain, scene, ptr);
}
@@ -1116,13 +1121,13 @@ static void rna_SequenceEditor_overlay_lock_set(PointerRNA *ptr, bool value)
}
/* convert from abs to relative and back */
- if ((ed->over_flag & SEQ_EDIT_OVERLAY_ABS) == 0 && value) {
- ed->over_cfra = scene->r.cfra + ed->over_ofs;
- ed->over_flag |= SEQ_EDIT_OVERLAY_ABS;
+ if ((ed->overlay_frame_flag & SEQ_EDIT_OVERLAY_FRAME_ABS) == 0 && value) {
+ ed->overlay_frame_abs = scene->r.cfra + ed->overlay_frame_ofs;
+ ed->overlay_frame_flag |= SEQ_EDIT_OVERLAY_FRAME_ABS;
}
- else if ((ed->over_flag & SEQ_EDIT_OVERLAY_ABS) && !value) {
- ed->over_ofs = ed->over_cfra - scene->r.cfra;
- ed->over_flag &= ~SEQ_EDIT_OVERLAY_ABS;
+ else if ((ed->overlay_frame_flag & SEQ_EDIT_OVERLAY_FRAME_ABS) && !value) {
+ ed->overlay_frame_ofs = ed->overlay_frame_abs - scene->r.cfra;
+ ed->overlay_frame_flag &= ~SEQ_EDIT_OVERLAY_FRAME_ABS;
}
}
@@ -1135,11 +1140,11 @@ static int rna_SequenceEditor_overlay_frame_get(PointerRNA *ptr)
return scene->r.cfra;
}
- if (ed->over_flag & SEQ_EDIT_OVERLAY_ABS) {
- return ed->over_cfra - scene->r.cfra;
+ if (ed->overlay_frame_flag & SEQ_EDIT_OVERLAY_FRAME_ABS) {
+ return ed->overlay_frame_abs - scene->r.cfra;
}
else {
- return ed->over_ofs;
+ return ed->overlay_frame_ofs;
}
}
@@ -1152,11 +1157,11 @@ static void rna_SequenceEditor_overlay_frame_set(PointerRNA *ptr, int value)
return;
}
- if (ed->over_flag & SEQ_EDIT_OVERLAY_ABS) {
- ed->over_cfra = (scene->r.cfra + value);
+ if (ed->overlay_frame_flag & SEQ_EDIT_OVERLAY_FRAME_ABS) {
+ ed->overlay_frame_abs = (scene->r.cfra + value);
}
else {
- ed->over_ofs = value;
+ ed->overlay_frame_ofs = value;
}
}
@@ -1361,6 +1366,28 @@ static float rna_Sequence_fps_get(PointerRNA *ptr)
return SEQ_time_sequence_get_fps(scene, seq);
}
+static void rna_Sequence_separate(ID *id, Sequence *seqm, Main *bmain)
+{
+ Scene *scene = (Scene *)id;
+
+ /* Find the appropriate seqbase */
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seqm);
+
+ LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &seqm->seqbase) {
+ SEQ_edit_move_strip_to_seqbase(scene, &seqm->seqbase, seq, seqbase);
+ }
+
+ SEQ_edit_flag_for_removal(scene, seqbase, seqm);
+ SEQ_edit_remove_flagged_sequences(scene, seqbase);
+
+ /* Update depsgraph. */
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
+
+ WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
+}
+
#else
static void rna_def_strip_element(BlenderRNA *brna)
@@ -1591,12 +1618,28 @@ static void rna_def_color_balance(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ static const EnumPropertyItem method_items[] = {
+ {SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN, "LIFT_GAMMA_GAIN", 0, "Lift/Gamma/Gain", ""},
+ {SEQ_COLOR_BALANCE_METHOD_SLOPEOFFSETPOWER,
+ "OFFSET_POWER_SLOPE",
+ 0,
+ "Offset/Power/Slope (ASC-CDL)",
+ "ASC-CDL standard color correction"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "SequenceColorBalanceData", NULL);
RNA_def_struct_ui_text(srna,
"Sequence Color Balance Data",
"Color balance parameters for a sequence strip and its modifiers");
RNA_def_struct_sdna(srna, "StripColorBalance");
+ prop = RNA_def_property(srna, "correction_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "method");
+ RNA_def_property_enum_items(prop, method_items);
+ RNA_def_property_ui_text(prop, "Correction Method", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
+
prop = RNA_def_property(srna, "lift", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_ui_text(prop, "Lift", "Color balance lift (shadows)");
RNA_def_property_ui_range(prop, 0, 2, 0.1, 3);
@@ -1615,14 +1658,22 @@ static void rna_def_color_balance(BlenderRNA *brna)
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
- prop = RNA_def_property(srna, "invert_gain", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_COLOR_BALANCE_INVERSE_GAIN);
- RNA_def_property_ui_text(prop, "Inverse Gain", "Invert the gain color`");
+ prop = RNA_def_property(srna, "slope", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_ui_text(prop, "Slope", "Correction for highlights");
+ RNA_def_property_ui_range(prop, 0, 2, 0.1, 3);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
- prop = RNA_def_property(srna, "invert_gamma", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_COLOR_BALANCE_INVERSE_GAMMA);
- RNA_def_property_ui_text(prop, "Inverse Gamma", "Invert the gamma color");
+ prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_ui_text(prop, "Offset", "Correction for entire tonal range");
+ RNA_def_property_ui_range(prop, 0, 2, 0.1, 3);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
+
+ prop = RNA_def_property(srna, "power", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_ui_text(prop, "Power", "Correction for midtones");
+ RNA_def_property_ui_range(prop, 0, 2, 0.1, 3);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
prop = RNA_def_property(srna, "invert_lift", PROP_BOOLEAN, PROP_NONE);
@@ -1630,6 +1681,31 @@ static void rna_def_color_balance(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Inverse Lift", "Invert the lift color");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
+ prop = RNA_def_property(srna, "invert_gamma", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_COLOR_BALANCE_INVERSE_GAMMA);
+ RNA_def_property_ui_text(prop, "Inverse Gamma", "Invert the gamma color");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
+
+ prop = RNA_def_property(srna, "invert_gain", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_COLOR_BALANCE_INVERSE_GAIN);
+ RNA_def_property_ui_text(prop, "Inverse Gain", "Invert the gain color`");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
+
+ prop = RNA_def_property(srna, "invert_slope", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_COLOR_BALANCE_INVERSE_SLOPE);
+ RNA_def_property_ui_text(prop, "Inverse Slope", "Invert the slope color`");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
+
+ prop = RNA_def_property(srna, "invert_offset", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_COLOR_BALANCE_INVERSE_OFFSET);
+ RNA_def_property_ui_text(prop, "Inverse Offset", "Invert the offset color");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
+
+ prop = RNA_def_property(srna, "invert_power", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_COLOR_BALANCE_INVERSE_POWER);
+ RNA_def_property_ui_text(prop, "Inverse Power", "Invert the power color");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
+
/* not yet used */
# if 0
prop = RNA_def_property(srna, "exposure", PROP_FLOAT, PROP_NONE);
@@ -2059,14 +2135,14 @@ static void rna_def_editor(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Active Strip", "Sequencer's active strip");
- prop = RNA_def_property(srna, "show_overlay", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "over_flag", SEQ_EDIT_OVERLAY_SHOW);
+ prop = RNA_def_property(srna, "show_overlay_frame", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay_frame_flag", SEQ_EDIT_OVERLAY_FRAME_SHOW);
RNA_def_property_ui_text(
prop, "Show Overlay", "Partial overlay on top of the sequencer with a frame offset");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
- prop = RNA_def_property(srna, "use_overlay_lock", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "over_flag", SEQ_EDIT_OVERLAY_ABS);
+ prop = RNA_def_property(srna, "use_overlay_frame_lock", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay_frame_flag", SEQ_EDIT_OVERLAY_FRAME_ABS);
RNA_def_property_ui_text(prop, "Overlay Lock", "");
RNA_def_property_boolean_funcs(prop, NULL, "rna_SequenceEditor_overlay_lock_set");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
@@ -2196,7 +2272,8 @@ static void rna_def_filter_video(StructRNA *srna)
prop = RNA_def_property(srna, "use_reverse_frames", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_REVERSE_FRAMES);
RNA_def_property_ui_text(prop, "Reverse Frames", "Reverse frame order");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+ RNA_def_property_update(
+ prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
prop = RNA_def_property(srna, "color_multiply", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "mul");
@@ -2218,7 +2295,8 @@ static void rna_def_filter_video(StructRNA *srna)
prop = RNA_def_property(srna, "strobe", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 1.0f, 30.0f);
RNA_def_property_ui_text(prop, "Strobe", "Only display every nth frame");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+ RNA_def_property_update(
+ prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
prop = RNA_def_property(srna, "transform", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "strip->transform");
@@ -2384,6 +2462,7 @@ static void rna_def_image(BlenderRNA *brna)
static void rna_def_meta(BlenderRNA *brna)
{
StructRNA *srna;
+ FunctionRNA *func;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "MetaSequence", "Sequence");
@@ -2397,6 +2476,10 @@ static void rna_def_meta(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Sequences", "Sequences nested in meta strip");
RNA_api_sequences(brna, prop, true);
+ func = RNA_def_function(srna, "separate", "rna_Sequence_separate");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ RNA_def_function_ui_description(func, "Separate meta");
+
rna_def_filter_video(srna);
rna_def_proxy(srna);
rna_def_input(srna);
@@ -2925,11 +3008,11 @@ static void rna_def_text(StructRNA *srna)
RNA_def_property_pointer_funcs(prop, NULL, "rna_Sequence_text_font_set", NULL, NULL);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
- prop = RNA_def_property(srna, "font_size", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "text_size");
+ prop = RNA_def_property(srna, "font_size", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_float_sdna(prop, NULL, "text_size");
RNA_def_property_ui_text(prop, "Size", "Size of the text");
RNA_def_property_range(prop, 0.0, 2000);
- RNA_def_property_ui_range(prop, 0.0f, 2000, 1, -1);
+ RNA_def_property_ui_range(prop, 0.0f, 2000, 10.0f, 1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index b43b57a35be..7989c316c4c 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -59,17 +59,22 @@
# include "SEQ_relations.h"
# include "SEQ_render.h"
# include "SEQ_sequencer.h"
+# include "SEQ_time.h"
# include "WM_api.h"
static void rna_Sequence_update_rnafunc(ID *id, Sequence *self, bool do_data)
{
+ Scene *scene = (Scene *)id;
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, self);
+
if (do_data) {
- SEQ_relations_update_changed_seq_and_deps((Scene *)id, self, true, true);
+ SEQ_time_update_recursive(scene, self);
// new_tstripdata(self); /* need 2.6x version of this. */
}
- SEQ_time_update_sequence((Scene *)id, self);
- SEQ_time_update_sequence_bounds((Scene *)id, self);
+
+ SEQ_time_update_sequence(scene, seqbase, self);
}
static void rna_Sequence_swap_internal(Sequence *seq_self,
@@ -586,6 +591,8 @@ static void rna_Sequences_meta_remove(
static StripElem *rna_SequenceElements_append(ID *id, Sequence *seq, const char *filename)
{
Scene *scene = (Scene *)id;
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
StripElem *se;
seq->strip->stripdata = se = MEM_reallocN(seq->strip->stripdata,
@@ -594,7 +601,7 @@ static StripElem *rna_SequenceElements_append(ID *id, Sequence *seq, const char
BLI_strncpy(se->name, filename, sizeof(se->name));
seq->len++;
- SEQ_time_update_sequence_bounds(scene, seq);
+ SEQ_time_update_sequence(scene, seqbase, seq);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
return se;
@@ -603,6 +610,8 @@ static StripElem *rna_SequenceElements_append(ID *id, Sequence *seq, const char
static void rna_SequenceElements_pop(ID *id, Sequence *seq, ReportList *reports, int index)
{
Scene *scene = (Scene *)id;
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
StripElem *new_seq, *se;
if (seq->len == 1) {
@@ -635,7 +644,7 @@ static void rna_SequenceElements_pop(ID *id, Sequence *seq, ReportList *reports,
MEM_freeN(seq->strip->stripdata);
seq->strip->stripdata = new_seq;
- SEQ_time_update_sequence_bounds(scene, seq);
+ SEQ_time_update_sequence(scene, seqbase, seq);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
}
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 9e06533d41b..e2411f5f4ae 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -34,11 +34,15 @@
#include "BKE_node.h"
#include "BKE_studiolight.h"
+#include "ED_asset.h"
#include "ED_spreadsheet.h"
#include "ED_text.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_sys_types.h"
+#include "BLI_uuid.h"
#include "DNA_action_types.h"
#include "DNA_gpencil_types.h"
@@ -69,6 +73,30 @@
#include "RNA_enum_types.h"
+const EnumPropertyItem rna_enum_geometry_component_type_items[] = {
+ {GEO_COMPONENT_TYPE_MESH,
+ "MESH",
+ ICON_MESH_DATA,
+ "Mesh",
+ "Mesh component containing point, corner, edge and face data"},
+ {GEO_COMPONENT_TYPE_POINT_CLOUD,
+ "POINTCLOUD",
+ ICON_POINTCLOUD_DATA,
+ "Point Cloud",
+ "Point cloud component containing only point data"},
+ {GEO_COMPONENT_TYPE_CURVE,
+ "CURVE",
+ ICON_CURVE_DATA,
+ "Curve",
+ "Curve component containing spline and control point data"},
+ {GEO_COMPONENT_TYPE_INSTANCES,
+ "INSTANCES",
+ ICON_EMPTY_AXIS,
+ "Instances",
+ "Instances of objects or collections"},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_space_type_items[] = {
/* empty must be here for python, is skipped for UI */
{SPACE_EMPTY, "EMPTY", ICON_NONE, "Empty", ""},
@@ -1833,6 +1861,9 @@ static void rna_SpaceTextEditor_text_set(PointerRNA *ptr,
SpaceText *st = (SpaceText *)(ptr->data);
st->text = value.data;
+ if (st->text != NULL) {
+ id_us_ensure_real((ID *)st->text);
+ }
ScrArea *area = rna_area_from_space(ptr);
if (area) {
@@ -2309,7 +2340,8 @@ static void seq_build_proxy(bContext *C, PointerRNA *ptr)
seq->strip->proxy->build_size_flags |= SEQ_rendersize_to_proxysize(sseq->render_size);
/* Build proxy. */
- SEQ_proxy_rebuild_context(pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
+ SEQ_proxy_rebuild_context(
+ pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue, true);
}
BLI_gset_free(file_list, MEM_freeN);
@@ -2347,6 +2379,15 @@ static char *rna_SpaceSequencerTimelineOverlay_path(PointerRNA *UNUSED(ptr))
}
/* Space Node Editor */
+static PointerRNA rna_SpaceNode_overlay_get(PointerRNA *ptr)
+{
+ return rna_pointer_inherit_refine(ptr, &RNA_SpaceNodeOverlay, ptr->data);
+}
+
+static char *rna_SpaceNodeOverlay_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("overlay");
+}
static void rna_SpaceNodeEditor_node_tree_set(PointerRNA *ptr,
const PointerRNA value,
@@ -2614,16 +2655,9 @@ static void rna_FileAssetSelectParams_asset_library_set(PointerRNA *ptr, int val
params->asset_library_ref = ED_asset_library_reference_from_enum_value(value);
}
-static void rna_FileAssetSelectParams_asset_category_set(PointerRNA *ptr, uint64_t value)
+static PointerRNA rna_FileAssetSelectParams_filter_id_get(PointerRNA *ptr)
{
- FileSelectParams *params = ptr->data;
- params->filter_id = value;
-}
-
-static uint64_t rna_FileAssetSelectParams_asset_category_get(PointerRNA *ptr)
-{
- FileSelectParams *params = ptr->data;
- return params->filter_id;
+ return rna_pointer_inherit_refine(ptr, &RNA_FileAssetSelectIDFilter, ptr->data);
}
static PointerRNA rna_FileBrowser_FileSelectEntry_asset_data_get(PointerRNA *ptr)
@@ -2663,7 +2697,7 @@ static int rna_FileBrowser_FileSelectEntry_name_editable(PointerRNA *ptr, const
static void rna_FileBrowser_FileSelectEntry_name_get(PointerRNA *ptr, char *value)
{
const FileDirEntry *entry = ptr->data;
- strcpy(value, entry->name);
+ BLI_strncpy_utf8(value, entry->name, strlen(entry->name) + 1);
}
static int rna_FileBrowser_FileSelectEntry_name_length(PointerRNA *ptr)
@@ -2675,7 +2709,7 @@ static int rna_FileBrowser_FileSelectEntry_name_length(PointerRNA *ptr)
static void rna_FileBrowser_FileSelectEntry_relative_path_get(PointerRNA *ptr, char *value)
{
const FileDirEntry *entry = ptr->data;
- strcpy(value, entry->relpath);
+ BLI_strncpy_utf8(value, entry->relpath, strlen(entry->relpath) + 1);
}
static int rna_FileBrowser_FileSelectEntry_relative_path_length(PointerRNA *ptr)
@@ -3068,12 +3102,34 @@ static void rna_SpaceSpreadsheet_geometry_component_type_update(Main *UNUSED(bma
PointerRNA *ptr)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)ptr->data;
- if (sspreadsheet->geometry_component_type == GEO_COMPONENT_TYPE_POINT_CLOUD) {
- sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT;
- }
- if (sspreadsheet->geometry_component_type == GEO_COMPONENT_TYPE_CURVE &&
- !ELEM(sspreadsheet->attribute_domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) {
- sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT;
+ switch (sspreadsheet->geometry_component_type) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ if (!ELEM(sspreadsheet->attribute_domain,
+ ATTR_DOMAIN_POINT,
+ ATTR_DOMAIN_EDGE,
+ ATTR_DOMAIN_FACE,
+ ATTR_DOMAIN_CORNER)) {
+ sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT;
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT;
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ sspreadsheet->attribute_domain = ATTR_DOMAIN_INSTANCE;
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME: {
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ if (!ELEM(sspreadsheet->attribute_domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) {
+ sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT;
+ }
+ break;
+ }
}
}
@@ -3191,6 +3247,17 @@ static void rna_SpaceSpreadsheet_context_path_guess(SpaceSpreadsheet *sspreadshe
WM_main_add_notifier(NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
}
+static void rna_FileAssetSelectParams_catalog_id_get(PointerRNA *ptr, char *value)
+{
+ const FileAssetSelectParams *params = ptr->data;
+ BLI_uuid_format(value, params->catalog_id);
+}
+
+static int rna_FileAssetSelectParams_catalog_id_length(PointerRNA *UNUSED(ptr))
+{
+ return UUID_STRING_LEN - 1;
+}
+
#else
static const EnumPropertyItem dt_uv_items[] = {
@@ -4238,6 +4305,15 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "bone_wire_alpha", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.bone_wire_alpha");
+ RNA_def_property_ui_text(
+ prop, "Bone Wireframe Opacity", "Maximim opacity of bones in wireframe display mode");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, 2);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
prop = RNA_def_property(srna, "show_motion_paths", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(
prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_MOTION_PATHS);
@@ -5427,6 +5503,11 @@ static void rna_def_space_sequencer_preview_overlay(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_PREVIEW_SHOW_OUTLINE_SELECTED);
RNA_def_property_ui_text(prop, "Image Outline", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "show_cursor", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_PREVIEW_SHOW_2D_CURSOR);
+ RNA_def_property_ui_text(prop, "2D cursor", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
}
static void rna_def_space_sequencer_timeline_overlay(BlenderRNA *brna)
@@ -5531,10 +5612,10 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
- static const EnumPropertyItem overlay_type_items[] = {
- {SEQ_DRAW_OVERLAY_RECT, "RECTANGLE", 0, "Rectangle", "Show rectangle area overlay"},
- {SEQ_DRAW_OVERLAY_REFERENCE, "REFERENCE", 0, "Reference", "Show reference frame only"},
- {SEQ_DRAW_OVERLAY_CURRENT, "CURRENT", 0, "Current", "Show current frame only"},
+ static const EnumPropertyItem overlay_frame_type_items[] = {
+ {SEQ_OVERLAY_FRAME_TYPE_RECT, "RECTANGLE", 0, "Rectangle", "Show rectangle area overlay"},
+ {SEQ_OVERLAY_FRAME_TYPE_REFERENCE, "REFERENCE", 0, "Reference", "Show reference frame only"},
+ {SEQ_OVERLAY_FRAME_TYPE_CURRENT, "CURRENT", 0, "Current", "Show current frame only"},
{0, NULL, 0, NULL, NULL},
};
@@ -5654,9 +5735,9 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Grease Pencil", "Grease Pencil data for this Preview region");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
- prop = RNA_def_property(srna, "overlay_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "overlay_type");
- RNA_def_property_enum_items(prop, overlay_type_items);
+ prop = RNA_def_property(srna, "overlay_frame_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "overlay_frame_type");
+ RNA_def_property_enum_items(prop, overlay_frame_type_items);
RNA_def_property_ui_text(prop, "Overlay Type", "Overlay display method");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
@@ -5670,8 +5751,29 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Transform Preview", "Show preview of the transformed frames");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+ /* Gizmo toggles. */
+ prop = RNA_def_property(srna, "show_gizmo", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "gizmo_flag", SEQ_GIZMO_HIDE);
+ RNA_def_property_ui_text(prop, "Show Gizmo", "Show gizmos of all types");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "show_gizmo_navigate", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "gizmo_flag", SEQ_GIZMO_HIDE_NAVIGATE);
+ RNA_def_property_ui_text(prop, "Navigate Gizmo", "Viewport navigation gizmo");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "show_gizmo_context", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "gizmo_flag", SEQ_GIZMO_HIDE_CONTEXT);
+ RNA_def_property_ui_text(prop, "Context Gizmo", "Context sensitive gizmos for the active item");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "show_gizmo_tool", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "gizmo_flag", SEQ_GIZMO_HIDE_TOOL);
+ RNA_def_property_ui_text(prop, "Tool Gizmo", "Active tool gizmo");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
/* Overlay settings. */
- prop = RNA_def_property(srna, "show_strip_overlay", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "show_overlays", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_OVERLAY);
RNA_def_property_ui_text(prop, "Show Overlay", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
@@ -5690,6 +5792,13 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
rna_def_space_sequencer_preview_overlay(brna);
rna_def_space_sequencer_timeline_overlay(brna);
+
+ /* transform */
+ prop = RNA_def_property(srna, "cursor_location", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "cursor");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "2D Cursor Location", "2D cursor location for this view");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
}
static void rna_def_space_text(BlenderRNA *brna)
@@ -6309,6 +6418,40 @@ static void rna_def_fileselect_idfilter(BlenderRNA *brna)
}
}
+/* Filter for datablock types in the Asset Browser. */
+static void rna_def_fileselect_asset_idfilter(BlenderRNA *brna)
+{
+ StructRNA *srna = RNA_def_struct(brna, "FileAssetSelectIDFilter", NULL);
+ RNA_def_struct_sdna(srna, "FileSelectParams");
+ RNA_def_struct_nested(brna, srna, "FileSelectParams");
+ RNA_def_struct_ui_text(srna,
+ "File Select Asset Filter",
+ "Which asset types to show/hide, when browsing an asset library");
+
+ static char experimental_prop_names[INDEX_ID_MAX][MAX_NAME];
+
+ for (uint i = 0; rna_enum_id_type_filter_items[i].identifier; i++) {
+ const struct IDFilterEnumPropertyItem *item = &rna_enum_id_type_filter_items[i];
+ const bool is_experimental = (ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS & item->flag) == 0;
+
+ const char *identifier = rna_enum_id_type_filter_items[i].identifier;
+ if (is_experimental) {
+ /* Create name for experimental property and store in static buffer. */
+ snprintf(experimental_prop_names[i],
+ ARRAY_SIZE(experimental_prop_names[i]),
+ "experimental_%s",
+ identifier);
+ identifier = experimental_prop_names[i];
+ }
+
+ PropertyRNA *prop = RNA_def_property(srna, identifier, PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "filter_id", item->flag);
+ RNA_def_property_ui_text(prop, item->name, item->description);
+ RNA_def_property_ui_icon(prop, item->icon, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ }
+}
+
static void rna_def_fileselect_entry(BlenderRNA *brna)
{
PropertyRNA *prop;
@@ -6316,7 +6459,7 @@ static void rna_def_fileselect_entry(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "FileDirEntry");
RNA_def_struct_ui_text(srna, "File Select Entry", "A file viewable in the File Browser");
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_FILENAME);
RNA_def_property_editable_func(prop, "rna_FileBrowser_FileSelectEntry_name_editable");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_string_funcs(prop,
@@ -6326,7 +6469,7 @@ static void rna_def_fileselect_entry(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Name", "");
RNA_def_struct_name_property(srna, prop);
- prop = RNA_def_property(srna, "relative_path", PROP_STRING, PROP_NONE);
+ prop = RNA_def_property(srna, "relative_path", PROP_STRING, PROP_FILEPATH);
RNA_def_property_string_funcs(prop,
"rna_FileBrowser_FileSelectEntry_relative_path_get",
"rna_FileBrowser_FileSelectEntry_relative_path_length",
@@ -6595,47 +6738,6 @@ static void rna_def_fileselect_asset_params(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- /* XXX copied from rna_enum_id_type_filter_items. */
- static const EnumPropertyItem asset_category_items[] = {
- {FILTER_ID_SCE, "SCENES", ICON_SCENE_DATA, "Scenes", "Show scenes"},
- {FILTER_ID_AC, "ANIMATIONS", ICON_ANIM_DATA, "Animations", "Show animation data"},
- {FILTER_ID_OB | FILTER_ID_GR,
- "OBJECTS_AND_COLLECTIONS",
- ICON_GROUP,
- "Objects & Collections",
- "Show objects and collections"},
- {FILTER_ID_AR | FILTER_ID_CU | FILTER_ID_LT | FILTER_ID_MB | FILTER_ID_ME
- /* XXX avoid warning */
- // | FILTER_ID_HA | FILTER_ID_PT | FILTER_ID_VO
- ,
- "GEOMETRY",
- ICON_MESH_DATA,
- "Geometry",
- "Show meshes, curves, lattice, armatures and metaballs data"},
- {FILTER_ID_LS | FILTER_ID_MA | FILTER_ID_NT | FILTER_ID_TE,
- "SHADING",
- ICON_MATERIAL_DATA,
- "Shading",
- "Show materials, nodetrees, textures and Freestyle's linestyles"},
- {FILTER_ID_IM | FILTER_ID_MC | FILTER_ID_MSK | FILTER_ID_SO,
- "IMAGES_AND_SOUNDS",
- ICON_IMAGE_DATA,
- "Images & Sounds",
- "Show images, movie clips, sounds and masks"},
- {FILTER_ID_CA | FILTER_ID_LA | FILTER_ID_LP | FILTER_ID_SPK | FILTER_ID_WO,
- "ENVIRONMENTS",
- ICON_WORLD_DATA,
- "Environment",
- "Show worlds, lights, cameras and speakers"},
- {FILTER_ID_BR | FILTER_ID_GD | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_TXT |
- FILTER_ID_VF | FILTER_ID_CF | FILTER_ID_WS,
- "MISC",
- ICON_GREASEPENCIL,
- "Miscellaneous",
- "Show other data types"},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem asset_import_type_items[] = {
{FILE_ASSET_IMPORT_LINK, "LINK", 0, "Link", "Import the assets as linked data-block"},
{FILE_ASSET_IMPORT_APPEND,
@@ -6664,14 +6766,22 @@ static void rna_def_fileselect_asset_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Asset Library", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
- prop = RNA_def_property(srna, "asset_category", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, asset_category_items);
- RNA_def_property_enum_funcs(prop,
- "rna_FileAssetSelectParams_asset_category_get",
- "rna_FileAssetSelectParams_asset_category_set",
- NULL);
- RNA_def_property_ui_text(prop, "Asset Category", "Determine which kind of assets to display");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
+ prop = RNA_def_property(srna, "catalog_id", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop,
+ "rna_FileAssetSelectParams_catalog_id_get",
+ "rna_FileAssetSelectParams_catalog_id_length",
+ NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Catalog UUID", "The UUID of the catalog shown in the browser");
+
+ prop = RNA_def_property(srna, "filter_asset_id", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "FileAssetSelectIDFilter");
+ RNA_def_property_pointer_funcs(
+ prop, "rna_FileAssetSelectParams_filter_id_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop,
+ "Filter Asset Types",
+ "Which asset types to show/hide, when browsing an asset library");
prop = RNA_def_property(srna, "import_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, asset_import_type_items);
@@ -7013,6 +7123,44 @@ static void rna_def_space_node_path_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
}
+static void rna_def_space_node_overlay(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SpaceNodeOverlay", NULL);
+ RNA_def_struct_sdna(srna, "SpaceNode");
+ RNA_def_struct_nested(brna, srna, "SpaceNodeEditor");
+ RNA_def_struct_path_func(srna, "rna_SpaceNodeOverlay_path");
+ RNA_def_struct_ui_text(
+ srna, "Overlay Settings", "Settings for display of overlays in the Node Editor");
+
+ prop = RNA_def_property(srna, "show_overlays", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SN_OVERLAY_SHOW_OVERLAYS);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Show Overlays", "Display overlays like colored or dashed wires");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
+
+ prop = RNA_def_property(srna, "show_wire_color", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SN_OVERLAY_SHOW_WIRE_COLORS);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(
+ prop, "Show Wire Colors", "Color node links based on their connected sockets");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
+
+ prop = RNA_def_property(srna, "show_timing", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SN_OVERLAY_SHOW_TIMINGS);
+ RNA_def_property_boolean_default(prop, false);
+ RNA_def_property_ui_text(prop, "Show Timing", "Display each node's last execution time");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
+
+ prop = RNA_def_property(srna, "show_context_path", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SN_OVERLAY_SHOW_PATH);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Show Tree Path", "Display breadcrumbs for the editor's context");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
+}
+
static void rna_def_space_node(BlenderRNA *brna)
{
StructRNA *srna;
@@ -7196,6 +7344,15 @@ static void rna_def_space_node(BlenderRNA *brna)
prop, "Auto-offset Direction", "Direction to offset nodes on insertion");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
+ /* Overlays */
+ prop = RNA_def_property(srna, "overlay", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "SpaceNodeOverlay");
+ RNA_def_property_pointer_funcs(prop, "rna_SpaceNode_overlay_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(
+ prop, "Overlay Settings", "Settings for display of overlays in the Node Editor");
+
+ rna_def_space_node_overlay(brna);
RNA_api_space_node(srna);
}
@@ -7718,30 +7875,6 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
PropertyRNA *prop;
StructRNA *srna;
- static const EnumPropertyItem geometry_component_type_items[] = {
- {GEO_COMPONENT_TYPE_MESH,
- "MESH",
- ICON_MESH_DATA,
- "Mesh",
- "Mesh component containing point, corner, edge and face data"},
- {GEO_COMPONENT_TYPE_POINT_CLOUD,
- "POINTCLOUD",
- ICON_POINTCLOUD_DATA,
- "Point Cloud",
- "Point cloud component containing only point data"},
- {GEO_COMPONENT_TYPE_CURVE,
- "CURVE",
- ICON_CURVE_DATA,
- "Curve",
- "Curve component containing spline and control point data"},
- {GEO_COMPONENT_TYPE_INSTANCES,
- "INSTANCES",
- ICON_EMPTY_AXIS,
- "Instances",
- "Instances of objects or collections"},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem object_eval_state_items[] = {
{SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED,
"EVALUATED",
@@ -7800,7 +7933,7 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "geometry_component_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, geometry_component_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_geometry_component_type_items);
RNA_def_property_ui_text(
prop, "Geometry Component", "Part of the geometry to display data from");
RNA_def_property_update(prop,
@@ -7845,6 +7978,7 @@ void RNA_def_space(BlenderRNA *brna)
rna_def_fileselect_params(brna);
rna_def_fileselect_asset_params(brna);
rna_def_fileselect_idfilter(brna);
+ rna_def_fileselect_asset_idfilter(brna);
rna_def_filemenu_entry(brna);
rna_def_space_filebrowser(brna);
rna_def_space_outliner(brna);
diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c
index 205a88edf84..c5569683c9c 100644
--- a/source/blender/makesrna/intern/rna_space_api.c
+++ b/source/blender/makesrna/intern/rna_space_api.c
@@ -122,7 +122,8 @@ void RNA_api_space_filebrowser(StructRNA *srna)
PropertyRNA *parm;
func = RNA_def_function(srna, "activate_asset_by_id", "ED_fileselect_activate_by_id");
- RNA_def_function_ui_description(func, "Activate the asset entry that represents the given ID");
+ RNA_def_function_ui_description(
+ func, "Activate and select the asset entry that represents the given ID");
parm = RNA_def_property(func, "id_to_activate", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "ID");
@@ -134,6 +135,18 @@ void RNA_api_space_filebrowser(StructRNA *srna)
0,
"",
"Whether to activate the ID immediately (false) or after the file browser refreshes (true)");
+
+ /* Select file by relative path. */
+ func = RNA_def_function(
+ srna, "activate_file_by_relative_path", "ED_fileselect_activate_by_relpath");
+ RNA_def_function_ui_description(func,
+ "Set active file and add to selection based on relative path to "
+ "current File Browser directory");
+ RNA_def_property(func, "relative_path", PROP_STRING, PROP_FILEPATH);
+
+ /* Deselect all files. */
+ func = RNA_def_function(srna, "deselect_all", "ED_fileselect_deselect_all");
+ RNA_def_function_ui_description(func, "Deselect all files");
}
#endif
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 5a74cfa9964..f66fb2653b5 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -199,7 +199,7 @@ static void rna_Texture_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *pt
}
else if (GS(id->name) == ID_NT) {
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
}
diff --git a/source/blender/makesrna/intern/rna_texture_api.c b/source/blender/makesrna/intern/rna_texture_api.c
index 83c1efd55bc..0920fe6679a 100644
--- a/source/blender/makesrna/intern/rna_texture_api.c
+++ b/source/blender/makesrna/intern/rna_texture_api.c
@@ -84,8 +84,8 @@ void RNA_api_texture(StructRNA *srna)
NULL,
-FLT_MAX,
FLT_MAX,
- "The result of the texture where (x,y,z,w) are (red, green, blue, intensity). For greyscale "
- "textures, often intensity only will be used",
+ "The result of the texture where (x,y,z,w) are (red, green, blue, intensity). "
+ "For grayscale textures, often intensity only will be used",
NULL,
-1e4,
1e4);
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index 336359a9dc0..2d4d5ee766f 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -24,6 +24,7 @@
#include "MEM_guardedalloc.h"
#include "BKE_movieclip.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
#include "RNA_access.h"
@@ -31,6 +32,7 @@
#include "rna_internal.h"
+#include "DNA_defaults.h"
#include "DNA_movieclip_types.h"
#include "DNA_object_types.h" /* SELECT */
#include "DNA_scene_types.h"
@@ -415,11 +417,12 @@ static void rna_tracking_stabRotTracks_active_index_range(
*max = max_ii(0, clip->tracking.stabilization.tot_rot_track - 1);
}
-static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_tracking_flushUpdate(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->owner_id;
- nodeUpdateID(scene->nodetree, &clip->id);
+ BKE_ntree_update_tag_id_changed(bmain, &clip->id);
+ BKE_ntree_update_main(bmain, NULL);
WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
WM_main_add_notifier(NC_SCENE, NULL);
@@ -607,7 +610,7 @@ static MovieTrackingTrack *add_track_to_base(
MovieClip *clip, MovieTracking *tracking, ListBase *tracksbase, const char *name, int frame)
{
int width, height;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
MovieTrackingTrack *track;
user.framenr = 1;
@@ -2437,6 +2440,8 @@ static void rna_def_trackingDopesheet(BlenderRNA *brna)
0,
"Average Error",
"Sort channels by average reprojection error of tracks after solve"},
+ {TRACKING_DOPE_SORT_START, "START", 0, "Start Frame", "Sort channels by first frame number"},
+ {TRACKING_DOPE_SORT_END, "END", 0, "End Frame", "Sort channels by last frame number"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index c506a533032..05ed5e096d8 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -1373,7 +1373,6 @@ static void rna_def_panel(BlenderRNA *brna)
0,
"Expand Header Layout",
"Allow buttons in the header to stretch and shrink to fill the entire layout width"},
- {PANEL_TYPE_DRAW_BOX, "DRAW_BOX", 0, "Box Style", "Display panel with the box widget theme"},
{0, NULL, 0, NULL, NULL},
};
@@ -1452,6 +1451,11 @@ static void rna_def_panel(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, NULL, "type->translation_context");
RNA_def_property_string_default(prop, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ RNA_def_property_ui_text(prop,
+ "",
+ "Specific translation context, only define when the label needs to be "
+ "disambiguated from others using the exact same label");
+
RNA_define_verify_sdna(true);
prop = RNA_def_property(srna, "bl_description", PROP_STRING, PROP_NONE);
@@ -1461,14 +1465,18 @@ static void rna_def_panel(BlenderRNA *brna)
// RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */
+ RNA_def_property_ui_text(prop, "", "The panel tooltip");
prop = RNA_def_property(srna, "bl_category", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "type->category");
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ RNA_def_property_ui_text(
+ prop, "", "The category (tab) in which the panel will be displayed, when applicable");
prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "type->owner_id");
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ RNA_def_property_ui_text(prop, "", "The ID owning the data displayed in the panel, if any");
prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type->space_type");
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index f96b3fc5eee..5bf778d1962 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -582,6 +582,56 @@ static void rna_uiTemplateCacheFile(uiLayout *layout,
uiTemplateCacheFile(layout, C, ptr, propname);
}
+static void rna_uiTemplateCacheFileVelocity(uiLayout *layout,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
+ return;
+ }
+
+ uiTemplateCacheFileVelocity(layout, &fileptr);
+}
+
+static void rna_uiTemplateCacheFileProcedural(uiLayout *layout,
+ bContext *C,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
+ return;
+ }
+
+ uiTemplateCacheFileProcedural(layout, C, &fileptr);
+}
+
+static void rna_uiTemplateCacheFileTimeSettings(uiLayout *layout,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
+ return;
+ }
+
+ uiTemplateCacheFileTimeSettings(layout, &fileptr);
+}
+
+static void rna_uiTemplateCacheFileLayers(uiLayout *layout,
+ bContext *C,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
+ return;
+ }
+
+ uiTemplateCacheFileLayers(layout, C, &fileptr);
+}
+
static void rna_uiTemplatePathBuilder(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -1795,6 +1845,26 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
api_ui_item_rna_common(func);
+ func = RNA_def_function(srna, "template_cache_file_velocity", "rna_uiTemplateCacheFileVelocity");
+ RNA_def_function_ui_description(func, "Show cache files velocity properties");
+ api_ui_item_rna_common(func);
+
+ func = RNA_def_function(
+ srna, "template_cache_file_procedural", "rna_uiTemplateCacheFileProcedural");
+ RNA_def_function_ui_description(func, "Show cache files render procedural properties");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
+
+ func = RNA_def_function(
+ srna, "template_cache_file_time_settings", "rna_uiTemplateCacheFileTimeSettings");
+ RNA_def_function_ui_description(func, "Show cache files time settings");
+ api_ui_item_rna_common(func);
+
+ func = RNA_def_function(srna, "template_cache_file_layers", "rna_uiTemplateCacheFileLayers");
+ RNA_def_function_ui_description(func, "Show cache files override layers properties");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
+
func = RNA_def_function(srna, "template_recent_files", "uiTemplateRecentFiles");
RNA_def_function_ui_description(func, "Show list of recently saved .blend files");
RNA_def_int(func, "rows", 5, 1, INT_MAX, "", "Maximum number of items to show", 1, INT_MAX);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index ccfc1222d4c..4379b4ebe1d 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -182,6 +182,7 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = {
# include "BKE_image.h"
# include "BKE_main.h"
# include "BKE_mesh_runtime.h"
+# include "BKE_object.h"
# include "BKE_paint.h"
# include "BKE_pbvh.h"
# include "BKE_preferences.h"
@@ -265,6 +266,14 @@ static void rna_userdef_theme_update(Main *bmain, Scene *scene, PointerRNA *ptr)
rna_userdef_update(bmain, scene, ptr);
}
+static void rna_userdef_theme_text_style_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ const uiStyle *style = UI_style_get();
+ BLF_default_size(style->widgetlabel.points);
+
+ rna_userdef_update(bmain, scene, ptr);
+}
+
static void rna_userdef_gizmo_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
WM_reinit_gizmomap_all(bmain);
@@ -344,6 +353,12 @@ static void rna_userdef_asset_library_name_set(PointerRNA *ptr, const char *valu
BKE_preferences_asset_library_name_set(&U, library, value);
}
+static void rna_userdef_asset_library_path_set(PointerRNA *ptr, const char *value)
+{
+ bUserAssetLibrary *library = (bUserAssetLibrary *)ptr->data;
+ BKE_preferences_asset_library_path_set(library, value);
+}
+
static void rna_userdef_script_autoexec_update(Main *UNUSED(bmain),
Scene *UNUSED(scene),
PointerRNA *ptr)
@@ -564,6 +579,20 @@ static PointerRNA rna_UserDef_apps_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_PreferencesApps, ptr->data);
}
+/* Reevaluate objects with a subsurf modifier as the last in their modifiers stacks. */
+static void rna_UserDef_subdivision_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Object *ob;
+
+ for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ if (BKE_object_get_last_subsurf_modifier(ob) != NULL) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ }
+
+ rna_userdef_update(bmain, scene, ptr);
+}
+
static void rna_UserDef_audio_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
BKE_sound_init(bmain);
@@ -1128,39 +1157,40 @@ static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna)
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
RNA_def_struct_ui_text(srna, "Font Style", "Theme settings for Font");
- prop = RNA_def_property(srna, "points", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 6, 24);
+ prop = RNA_def_property(srna, "points", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_range(prop, 6.0f, 32.0f);
+ RNA_def_property_ui_range(prop, 8.0f, 20.0f, 10.0f, 1);
RNA_def_property_ui_text(prop, "Points", "Font size in points");
- RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
prop = RNA_def_property(srna, "shadow", PROP_INT, PROP_PIXEL);
RNA_def_property_range(prop, 0, 5);
RNA_def_property_ui_text(prop, "Shadow Size", "Shadow size (0, 3 and 5 supported)");
- RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update");
prop = RNA_def_property(srna, "shadow_offset_x", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "shadx");
RNA_def_property_range(prop, -10, 10);
RNA_def_property_ui_text(prop, "Shadow X Offset", "Shadow offset in pixels");
- RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update");
prop = RNA_def_property(srna, "shadow_offset_y", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "shady");
RNA_def_property_range(prop, -10, 10);
RNA_def_property_ui_text(prop, "Shadow Y Offset", "Shadow offset in pixels");
- RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update");
prop = RNA_def_property(srna, "shadow_alpha", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "shadowalpha");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Shadow Alpha", "");
- RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update");
prop = RNA_def_property(srna, "shadow_value", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "shadowcolor");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Shadow Brightness", "Shadow color in gray value");
- RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update");
}
static void rna_def_userdef_theme_ui_style(BlenderRNA *brna)
@@ -1560,6 +1590,13 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna)
prop, "Text Cursor", "Color of the interface widgets text insertion cursor (caret)");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ prop = RNA_def_property(srna, "panel_roundness", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_ui_text(
+ prop, "Panel Roundness", "Roundness of the corners of panels and sub-panels");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 0.4f);
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
/* Transparent Grid */
prop = RNA_def_property(srna, "transparent_checker_primary", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "transparent_checker_primary");
@@ -2837,7 +2874,7 @@ static void rna_def_userdef_theme_space_node(BlenderRNA *brna)
prop = RNA_def_property(srna, "wire_select", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "edge_select");
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Wire Select", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
@@ -2867,7 +2904,7 @@ static void rna_def_userdef_theme_space_node(BlenderRNA *brna)
prop = RNA_def_property(srna, "group_node", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "syntaxc");
- RNA_def_property_array(prop, 4);
+ RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Group Node", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
@@ -2904,10 +2941,16 @@ static void rna_def_userdef_theme_space_node(BlenderRNA *brna)
prop = RNA_def_property(srna, "grid_levels", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "grid_levels");
- RNA_def_property_int_default(prop, 2);
- RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_int_default(prop, 7);
+ RNA_def_property_range(prop, 0, 9);
RNA_def_property_ui_text(
- prop, "Grid Levels", "Amount of grid lines displayed in the background");
+ prop, "Grid Levels", "Number of subdivisions for the dot grid displayed in the background");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
+ prop = RNA_def_property(srna, "dash_alpha", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Dashed Lines Opacity", "Opacity for the dashed lines in wires");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "input_node", PROP_FLOAT, PROP_COLOR_GAMMA);
@@ -5003,6 +5046,14 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
"Collection Instance Empty Size",
"Display size of the empty when new collection instances are created");
+ /* Text Editor */
+
+ prop = RNA_def_property(srna, "use_text_edit_auto_close", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "text_flag", USER_TEXT_EDIT_AUTO_CLOSE);
+ RNA_def_property_ui_text(
+ prop, "Auto Close", "Auto close relevant characters inside the text editor");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
+
/* Undo */
prop = RNA_def_property(srna, "undo_steps", PROP_INT, PROP_NONE);
@@ -5168,6 +5219,11 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Duplicate Curve", "Causes curve data to be duplicated with the object");
+ prop = RNA_def_property(srna, "use_duplicate_lattice", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_LATTICE);
+ RNA_def_property_ui_text(
+ prop, "Duplicate Lattice", "Causes lattice data to be duplicated with the object");
+
prop = RNA_def_property(srna, "use_duplicate_text", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_FONT);
RNA_def_property_ui_text(
@@ -5183,6 +5239,16 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Duplicate Armature", "Causes armature data to be duplicated with the object");
+ prop = RNA_def_property(srna, "use_duplicate_camera", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_CAMERA);
+ RNA_def_property_ui_text(
+ prop, "Duplicate Camera", "Causes camera data to be duplicated with the object");
+
+ prop = RNA_def_property(srna, "use_duplicate_speaker", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_SPEAKER);
+ RNA_def_property_ui_text(
+ prop, "Duplicate Speaker", "Causes speaker data to be duplicated with the object");
+
prop = RNA_def_property(srna, "use_duplicate_light", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_LAMP);
RNA_def_property_ui_text(
@@ -5600,6 +5666,16 @@ static void rna_def_userdef_system(BlenderRNA *brna)
"Use the depth buffer for picking 3D View selection "
"(without this the front most object may not be selected first)");
+ /* GPU subdivision evaluation. */
+
+ prop = RNA_def_property(srna, "use_gpu_subdivision", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gpu_flag", USER_GPU_FLAG_SUBDIVISION_EVALUATION);
+ RNA_def_property_ui_text(prop,
+ "GPU Subdivision",
+ "Enable GPU acceleration for evaluating the last subdivision surface "
+ "modifiers in the stack");
+ RNA_def_property_update(prop, 0, "rna_UserDef_subdivision_update");
+
/* Audio */
prop = RNA_def_property(srna, "audio_mixing_buffer", PROP_ENUM, PROP_NONE);
@@ -6064,6 +6140,7 @@ static void rna_def_userdef_filepaths_asset_library(BlenderRNA *brna)
prop = RNA_def_property(srna, "path", PROP_STRING, PROP_DIRPATH);
RNA_def_property_ui_text(
prop, "Path", "Path to a directory with .blend files to use as an asset library");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_userdef_asset_library_path_set");
RNA_def_property_update(prop, 0, "rna_userdef_update");
}
@@ -6354,6 +6431,20 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
"data-blocks as assets, not just poses");
RNA_def_property_update(prop, 0, "rna_userdef_ui_update");
+ prop = RNA_def_property(srna, "show_asset_debug_info", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop,
+ "Asset Debug Info",
+ "Enable some extra fields in the Asset Browser to aid in debugging");
+ RNA_def_property_update(prop, 0, "rna_userdef_ui_update");
+
+ prop = RNA_def_property(srna, "use_asset_indexing", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "no_asset_indexing", 1);
+ RNA_def_property_ui_text(prop,
+ "Asset Indexing",
+ "Disabling the asset indexer forces every asset library refresh to "
+ "completely reread assets from disk");
+ RNA_def_property_update(prop, 0, "rna_userdef_ui_update");
+
prop = RNA_def_property(srna, "use_override_templates", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_override_templates", 1);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_vfont.c b/source/blender/makesrna/intern/rna_vfont.c
index 214a32372dd..f5f7742d753 100644
--- a/source/blender/makesrna/intern/rna_vfont.c
+++ b/source/blender/makesrna/intern/rna_vfont.c
@@ -30,7 +30,7 @@
#ifdef RNA_RUNTIME
-# include "BKE_font.h"
+# include "BKE_vfont.h"
# include "DNA_object_types.h"
# include "DEG_depsgraph.h"
diff --git a/source/blender/makesrna/intern/rna_volume.c b/source/blender/makesrna/intern/rna_volume.c
index 8ed53c9f70f..3100c1195f4 100644
--- a/source/blender/makesrna/intern/rna_volume.c
+++ b/source/blender/makesrna/intern/rna_volume.c
@@ -33,6 +33,26 @@
#include "BLI_math_base.h"
+const EnumPropertyItem rna_enum_volume_grid_data_type_items[] = {
+ {VOLUME_GRID_BOOLEAN, "BOOLEAN", 0, "Boolean", "Boolean"},
+ {VOLUME_GRID_FLOAT, "FLOAT", 0, "Float", "Single precision float"},
+ {VOLUME_GRID_DOUBLE, "DOUBLE", 0, "Double", "Double precision"},
+ {VOLUME_GRID_INT, "INT", 0, "Integer", "32-bit integer"},
+ {VOLUME_GRID_INT64, "INT64", 0, "Integer 64-bit", "64-bit integer"},
+ {VOLUME_GRID_MASK, "MASK", 0, "Mask", "No data, boolean mask of active voxels"},
+ {VOLUME_GRID_STRING, "STRING", 0, "String", "Text string"},
+ {VOLUME_GRID_VECTOR_FLOAT, "VECTOR_FLOAT", 0, "Float Vector", "3D float vector"},
+ {VOLUME_GRID_VECTOR_DOUBLE, "VECTOR_DOUBLE", 0, "Double Vector", "3D double vector"},
+ {VOLUME_GRID_VECTOR_INT, "VECTOR_INT", 0, "Integer Vector", "3D integer vector"},
+ {VOLUME_GRID_POINTS,
+ "POINTS",
+ 0,
+ "Points (Unsupported)",
+ "Points grid, currently unsupported by volume objects"},
+ {VOLUME_GRID_UNKNOWN, "UNKNOWN", 0, "Unknown", "Unsupported data type"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include "DEG_depsgraph.h"
@@ -41,6 +61,16 @@
# include "WM_api.h"
# include "WM_types.h"
+static char *rna_VolumeRender_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("render");
+}
+
+static char *rna_VolumeDisplay_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("display");
+}
+
/* Updates */
static void rna_Volume_update_display(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -234,30 +264,10 @@ static void rna_def_volume_grid(BlenderRNA *brna)
prop, "rna_VolumeGrid_name_get", "rna_VolumeGrid_name_length", NULL);
RNA_def_property_ui_text(prop, "Name", "Volume grid name");
- static const EnumPropertyItem data_type_items[] = {
- {VOLUME_GRID_BOOLEAN, "BOOLEAN", 0, "Boolean", "Boolean"},
- {VOLUME_GRID_FLOAT, "FLOAT", 0, "Float", "Single precision float"},
- {VOLUME_GRID_DOUBLE, "DOUBLE", 0, "Double", "Double precision"},
- {VOLUME_GRID_INT, "INT", 0, "Integer", "32-bit integer"},
- {VOLUME_GRID_INT64, "INT64", 0, "Integer 64-bit", "64-bit integer"},
- {VOLUME_GRID_MASK, "MASK", 0, "Mask", "No data, boolean mask of active voxels"},
- {VOLUME_GRID_STRING, "STRING", 0, "String", "Text string"},
- {VOLUME_GRID_VECTOR_FLOAT, "VECTOR_FLOAT", 0, "Float Vector", "3D float vector"},
- {VOLUME_GRID_VECTOR_DOUBLE, "VECTOR_DOUBLE", 0, "Double Vector", "3D double vector"},
- {VOLUME_GRID_VECTOR_INT, "VECTOR_INT", 0, "Integer Vector", "3D integer vector"},
- {VOLUME_GRID_POINTS,
- "POINTS",
- 0,
- "Points (Unsupported)",
- "Points grid, currently unsupported by volume objects"},
- {VOLUME_GRID_UNKNOWN, "UNKNOWN", 0, "Unknown", "Unsupported data type"},
- {0, NULL, 0, NULL, NULL},
- };
-
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_enum_funcs(prop, "rna_VolumeGrid_data_type_get", NULL, NULL);
- RNA_def_property_enum_items(prop, data_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_volume_grid_data_type_items);
RNA_def_property_ui_text(prop, "Data Type", "Data type of voxel values");
prop = RNA_def_property(srna, "channels", PROP_INT, PROP_UNSIGNED);
@@ -371,6 +381,7 @@ static void rna_def_volume_display(BlenderRNA *brna)
srna = RNA_def_struct(brna, "VolumeDisplay", NULL);
RNA_def_struct_ui_text(srna, "Volume Display", "Volume object display settings for 3D viewport");
RNA_def_struct_sdna(srna, "VolumeDisplay");
+ RNA_def_struct_path_func(srna, "rna_VolumeDisplay_path");
prop = RNA_def_property(srna, "density", PROP_FLOAT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -477,6 +488,7 @@ static void rna_def_volume_render(BlenderRNA *brna)
srna = RNA_def_struct(brna, "VolumeRender", NULL);
RNA_def_struct_ui_text(srna, "Volume Render", "Volume object render settings");
RNA_def_struct_sdna(srna, "VolumeRender");
+ RNA_def_struct_path_func(srna, "rna_VolumeRender_path");
static const EnumPropertyItem space_items[] = {
{VOLUME_SPACE_OBJECT,
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index c2d1ac67675..c64a47fc2ab 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -142,9 +142,10 @@ static const EnumPropertyItem event_ndof_type_items[] = {
};
#endif /* RNA_RUNTIME */
-/* not returned: CAPSLOCKKEY, UNKNOWNKEY */
const EnumPropertyItem rna_enum_event_type_items[] = {
- /* Note we abuse 'tooltip' message here to store a 'compact' form of some (too) long names. */
+ /* - Note we abuse 'tooltip' message here to store a 'compact' form of some (too) long names.
+ * - Intentionally excluded: #CAPSLOCKKEY, #UNKNOWNKEY.
+ */
{0, "NONE", 0, "", ""},
{LEFTMOUSE, "LEFTMOUSE", 0, "Left Mouse", "LMB"},
{MIDDLEMOUSE, "MIDDLEMOUSE", 0, "Middle Mouse", "MMB"},
@@ -362,6 +363,8 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
0,
"ActionZone Fullscreen",
"AZone FullScr"},
+ /* xr */
+ {EVT_XR_ACTION, "XR_ACTION", 0, "XR Action", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -700,6 +703,18 @@ static void rna_Event_tilt_get(PointerRNA *ptr, float *values)
WM_event_tablet_data(event, NULL, values);
}
+static PointerRNA rna_Event_xr_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ wmEvent *event = ptr->data;
+ wmXrActionData *actiondata = WM_event_is_xr(event) ? event->customdata : NULL;
+ return rna_pointer_inherit_refine(ptr, &RNA_XrEventData, actiondata);
+# else
+ UNUSED_VARS(ptr);
+ return PointerRNA_NULL;
+# endif
+}
+
static PointerRNA rna_PopupMenu_layout_get(PointerRNA *ptr)
{
struct uiPopupMenu *pup = ptr->data;
@@ -950,7 +965,7 @@ static void rna_wmKeyMapItem_keymodifier_set(PointerRNA *ptr, int value)
if (value == EVT_ESCKEY) {
/* pass */
}
- else if (value >= EVT_AKEY) {
+ else if (ISKEYBOARD(value) && !ISKEYMODIFIER(value)) {
kmi->keymodifier = value;
}
else {
@@ -1869,23 +1884,10 @@ static void rna_def_operator_options_runtime(BlenderRNA *brna)
prop, "Focus Region", "Enable to use the region under the cursor for modal execution");
}
-static void rna_def_operator(BlenderRNA *brna)
+static void rna_def_operator_common(StructRNA *srna)
{
- StructRNA *srna;
PropertyRNA *prop;
- srna = RNA_def_struct(brna, "Operator", NULL);
- RNA_def_struct_ui_text(
- srna, "Operator", "Storage of an operator being executed, or registered after execution");
- RNA_def_struct_sdna(srna, "wmOperator");
- RNA_def_struct_refine_func(srna, "rna_Operator_refine");
-# ifdef WITH_PYTHON
- RNA_def_struct_register_funcs(
- srna, "rna_Operator_register", "rna_Operator_unregister", "rna_Operator_instance");
-# endif
- RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
- RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT);
-
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_string_funcs(prop, "rna_Operator_name_get", "rna_Operator_name_length", NULL);
@@ -1905,15 +1907,6 @@ static void rna_def_operator(BlenderRNA *brna)
"Has Reports",
"Operator has a set of reports (warnings and errors) from last execution");
- prop = RNA_def_property(srna, "layout", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "UILayout");
-
- prop = RNA_def_property(srna, "options", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_struct_type(prop, "OperatorOptions");
- RNA_def_property_pointer_funcs(prop, "rna_Operator_options_get", NULL, NULL, NULL);
- RNA_def_property_ui_text(prop, "Options", "Runtime options");
-
/* Registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "type->idname");
@@ -1967,6 +1960,45 @@ static void rna_def_operator(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Options", "Options for this operator type");
+ prop = RNA_def_property(srna, "bl_cursor_pending", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type->cursor_pending");
+ RNA_def_property_enum_items(prop, rna_enum_window_cursor_items);
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ RNA_def_property_ui_text(
+ prop,
+ "Idle Cursor",
+ "Cursor to use when waiting for the user to select a location to activate the operator "
+ "(when ``bl_options`` has ``DEPENDS_ON_CURSOR`` set)");
+}
+
+static void rna_def_operator(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "Operator", NULL);
+ RNA_def_struct_ui_text(
+ srna, "Operator", "Storage of an operator being executed, or registered after execution");
+ RNA_def_struct_sdna(srna, "wmOperator");
+ RNA_def_struct_refine_func(srna, "rna_Operator_refine");
+# ifdef WITH_PYTHON
+ RNA_def_struct_register_funcs(
+ srna, "rna_Operator_register", "rna_Operator_unregister", "rna_Operator_instance");
+# endif
+ RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+ RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT);
+
+ rna_def_operator_common(srna);
+
+ prop = RNA_def_property(srna, "layout", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "UILayout");
+
+ prop = RNA_def_property(srna, "options", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "OperatorOptions");
+ RNA_def_property_pointer_funcs(prop, "rna_Operator_options_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Options", "Runtime options");
+
prop = RNA_def_property(srna, "macros", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "macro", NULL);
RNA_def_property_struct_type(prop, "Macro");
@@ -1986,7 +2018,6 @@ static void rna_def_operator(BlenderRNA *brna)
static void rna_def_macro_operator(BlenderRNA *brna)
{
StructRNA *srna;
- PropertyRNA *prop;
srna = RNA_def_struct(brna, "Macro", NULL);
RNA_def_struct_ui_text(
@@ -2002,68 +2033,7 @@ static void rna_def_macro_operator(BlenderRNA *brna)
RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT);
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_string_funcs(prop, "rna_Operator_name_get", "rna_Operator_name_length", NULL);
- RNA_def_property_ui_text(prop, "Name", "");
-
- prop = RNA_def_property(srna, "properties", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_struct_type(prop, "OperatorProperties");
- RNA_def_property_ui_text(prop, "Properties", "");
- RNA_def_property_pointer_funcs(prop, "rna_Operator_properties_get", NULL, NULL, NULL);
-
- /* Registration */
- prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "type->idname");
- RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_idname_set");
- // RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_flag(prop, PROP_REGISTER);
- RNA_def_struct_name_property(srna, prop);
-
- prop = RNA_def_property(srna, "bl_label", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "type->name");
- RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_label_set");
- // RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_flag(prop, PROP_REGISTER);
-
- prop = RNA_def_property(srna, "bl_translation_context", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "type->translation_context");
- RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */
- RNA_def_property_string_funcs(prop,
- "rna_Operator_bl_translation_context_get",
- "rna_Operator_bl_translation_context_length",
- "rna_Operator_bl_translation_context_set");
- RNA_def_property_string_default(prop, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
- RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
-
- prop = RNA_def_property(srna, "bl_description", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "type->description");
- RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */
- RNA_def_property_string_funcs(prop,
- "rna_Operator_bl_description_get",
- "rna_Operator_bl_description_length",
- "rna_Operator_bl_description_set");
- // RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
-
- prop = RNA_def_property(srna, "bl_undo_group", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "type->undo_group");
- RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */
- RNA_def_property_string_funcs(prop,
- "rna_Operator_bl_undo_group_get",
- "rna_Operator_bl_undo_group_length",
- "rna_Operator_bl_undo_group_set");
- // RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
-
- prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type->flag");
- RNA_def_property_enum_items(prop, rna_enum_operator_type_flag_items);
- RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG);
- RNA_def_property_ui_text(prop, "Options", "Options for this operator type");
+ rna_def_operator_common(srna);
RNA_api_macro(srna);
}
@@ -2170,13 +2140,13 @@ static void rna_def_event(BlenderRNA *brna)
/* mouse */
prop = RNA_def_property(srna, "mouse_x", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "x");
+ RNA_def_property_int_sdna(prop, NULL, "xy[0]");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Mouse X Position", "The window relative horizontal location of the mouse");
prop = RNA_def_property(srna, "mouse_y", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "y");
+ RNA_def_property_int_sdna(prop, NULL, "xy[1]");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Mouse Y Position", "The window relative vertical location of the mouse");
@@ -2194,13 +2164,13 @@ static void rna_def_event(BlenderRNA *brna)
prop, "Mouse Y Position", "The region relative vertical location of the mouse");
prop = RNA_def_property(srna, "mouse_prev_x", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "prevx");
+ RNA_def_property_int_sdna(prop, NULL, "prev_xy[0]");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Mouse Previous X Position", "The window relative horizontal location of the mouse");
prop = RNA_def_property(srna, "mouse_prev_y", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "prevy");
+ RNA_def_property_int_sdna(prop, NULL, "prev_xy[1]");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Mouse Previous Y Position", "The window relative vertical location of the mouse");
@@ -2228,6 +2198,13 @@ static void rna_def_event(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Absolute Motion", "The last motion event was an absolute input");
+ /* xr */
+ prop = RNA_def_property(srna, "xr", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "XrEventData");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, "rna_Event_xr_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "XR", "XR event data");
+
/* modifiers */
prop = RNA_def_property(srna, "shift", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "shift", 1);
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 7c3b119abb9..9e41d8c03fc 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -64,6 +64,13 @@ const EnumPropertyItem rna_enum_window_cursor_items[] = {
{WM_CURSOR_NS_SCROLL, "SCROLL_Y", 0, "Scroll-Y", ""},
{WM_CURSOR_NSEW_SCROLL, "SCROLL_XY", 0, "Scroll-XY", ""},
{WM_CURSOR_EYEDROPPER, "EYEDROPPER", 0, "Eyedropper", ""},
+ {WM_CURSOR_PICK_AREA, "PICK_AREA", 0, "Pick Area", ""},
+ {WM_CURSOR_STOP, "STOP", 0, "Stop", ""},
+ {WM_CURSOR_COPY, "COPY", 0, "Copy", ""},
+ {WM_CURSOR_CROSS, "CROSS", 0, "Cross", ""},
+ {WM_CURSOR_MUTE, "MUTE", 0, "Mute", ""},
+ {WM_CURSOR_ZOOM_IN, "ZOOM_IN", 0, "Zoom In", ""},
+ {WM_CURSOR_ZOOM_OUT, "ZOOM_OUT", 0, "Zoom Out", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -306,7 +313,7 @@ static wmKeyMapItem *rna_KeyMap_item_new_from_item(wmKeyMap *km,
wmKeyMapItem *kmi_src,
bool head)
{
- /* wmWindowManager *wm = CTX_wm_manager(C); */
+ // wmWindowManager *wm = CTX_wm_manager(C);
if ((km->flag & KEYMAP_MODAL) == (kmi_src->idname[0] != '\0')) {
BKE_report(reports, RPT_ERROR, "Can not mix modal/non-modal items");
@@ -645,8 +652,8 @@ static wmEvent *rna_Window_event_add_simulate(wmWindow *win,
e.type = type;
e.val = value;
e.is_repeat = false;
- e.x = x;
- e.y = y;
+ e.xy[0] = x;
+ e.xy[1] = y;
e.shift = shift;
e.ctrl = ctrl;
diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c
index 826e6d21c36..68f11d71de2 100644
--- a/source/blender/makesrna/intern/rna_world.c
+++ b/source/blender/makesrna/intern/rna_world.c
@@ -128,6 +128,7 @@ static void rna_def_lighting(BlenderRNA *brna)
prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "aodist");
+ RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_text(
prop, "Distance", "Length of rays, defines how far away other faces give occlusion effect");
RNA_def_property_update(prop, 0, "rna_World_update");
diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c
index f24d28d1209..dd4cbeac174 100644
--- a/source/blender/makesrna/intern/rna_xr.c
+++ b/source/blender/makesrna/intern/rna_xr.c
@@ -892,6 +892,71 @@ static void rna_XrSessionState_viewer_pose_rotation_get(PointerRNA *ptr, float *
# endif
}
+static void rna_XrSessionState_nav_location_get(PointerRNA *ptr, float *r_values)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ WM_xr_session_state_nav_location_get(xr, r_values);
+# else
+ UNUSED_VARS(ptr);
+ zero_v3(r_values);
+# endif
+}
+
+static void rna_XrSessionState_nav_location_set(PointerRNA *ptr, const float *values)
+{
+# ifdef WITH_XR_OPENXR
+ wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ WM_xr_session_state_nav_location_set(xr, values);
+# else
+ UNUSED_VARS(ptr, values);
+# endif
+}
+
+static void rna_XrSessionState_nav_rotation_get(PointerRNA *ptr, float *r_values)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ WM_xr_session_state_nav_rotation_get(xr, r_values);
+# else
+ UNUSED_VARS(ptr);
+ unit_qt(r_values);
+# endif
+}
+
+static void rna_XrSessionState_nav_rotation_set(PointerRNA *ptr, const float *values)
+{
+# ifdef WITH_XR_OPENXR
+ wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ WM_xr_session_state_nav_rotation_set(xr, values);
+# else
+ UNUSED_VARS(ptr, values);
+# endif
+}
+
+static float rna_XrSessionState_nav_scale_get(PointerRNA *ptr)
+{
+ float value;
+# ifdef WITH_XR_OPENXR
+ const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ WM_xr_session_state_nav_scale_get(xr, &value);
+# else
+ UNUSED_VARS(ptr);
+ value = 1.0f;
+# endif
+ return value;
+}
+
+static void rna_XrSessionState_nav_scale_set(PointerRNA *ptr, float value)
+{
+# ifdef WITH_XR_OPENXR
+ wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ WM_xr_session_state_nav_scale_set(xr, value);
+# else
+ UNUSED_VARS(ptr, value);
+# endif
+}
+
static void rna_XrSessionState_actionmaps_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
@@ -947,6 +1012,155 @@ static void rna_XrSessionState_selected_actionmap_set(PointerRNA *ptr, int value
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name XR Event Data
+ * \{ */
+
+static void rna_XrEventData_action_set_get(PointerRNA *ptr, char *r_value)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ strcpy(r_value, data->action_set);
+# else
+ UNUSED_VARS(ptr);
+ r_value[0] = '\0';
+# endif
+}
+
+static int rna_XrEventData_action_set_length(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ return strlen(data->action_set);
+# else
+ UNUSED_VARS(ptr);
+ return 0;
+# endif
+}
+
+static void rna_XrEventData_action_get(PointerRNA *ptr, char *r_value)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ strcpy(r_value, data->action);
+# else
+ UNUSED_VARS(ptr);
+ r_value[0] = '\0';
+# endif
+}
+
+static int rna_XrEventData_action_length(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ return strlen(data->action);
+# else
+ UNUSED_VARS(ptr);
+ return 0;
+# endif
+}
+
+static int rna_XrEventData_type_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ return data->type;
+# else
+ UNUSED_VARS(ptr);
+ return 0;
+# endif
+}
+
+static void rna_XrEventData_state_get(PointerRNA *ptr, float r_values[2])
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ copy_v2_v2(r_values, data->state);
+# else
+ UNUSED_VARS(ptr);
+ zero_v2(r_values);
+# endif
+}
+
+static void rna_XrEventData_state_other_get(PointerRNA *ptr, float r_values[2])
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ copy_v2_v2(r_values, data->state_other);
+# else
+ UNUSED_VARS(ptr);
+ zero_v2(r_values);
+# endif
+}
+
+static float rna_XrEventData_float_threshold_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ return data->float_threshold;
+# else
+ UNUSED_VARS(ptr);
+ return 0.0f;
+# endif
+}
+
+static void rna_XrEventData_controller_location_get(PointerRNA *ptr, float r_values[3])
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ copy_v3_v3(r_values, data->controller_loc);
+# else
+ UNUSED_VARS(ptr);
+ zero_v3(r_values);
+# endif
+}
+
+static void rna_XrEventData_controller_rotation_get(PointerRNA *ptr, float r_values[4])
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ copy_qt_qt(r_values, data->controller_rot);
+# else
+ UNUSED_VARS(ptr);
+ unit_qt(r_values);
+# endif
+}
+
+static void rna_XrEventData_controller_location_other_get(PointerRNA *ptr, float r_values[3])
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ copy_v3_v3(r_values, data->controller_loc_other);
+# else
+ UNUSED_VARS(ptr);
+ zero_v3(r_values);
+# endif
+}
+
+static void rna_XrEventData_controller_rotation_other_get(PointerRNA *ptr, float r_values[4])
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ copy_qt_qt(r_values, data->controller_rot_other);
+# else
+ UNUSED_VARS(ptr);
+ unit_qt(r_values);
+# endif
+}
+
+static bool rna_XrEventData_bimanual_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ return data->bimanual;
+# else
+ UNUSED_VARS(ptr);
+ return false;
+# endif
+}
+
+/** \} */
+
#else /* RNA_RUNTIME */
/* -------------------------------------------------------------------- */
@@ -1410,6 +1624,22 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem controller_draw_styles[] = {
+ {XR_CONTROLLER_DRAW_DARK, "DARK", 0, "Dark", "Draw dark controller"},
+ {XR_CONTROLLER_DRAW_LIGHT, "LIGHT", 0, "Light", "Draw light controller"},
+ {XR_CONTROLLER_DRAW_DARK_RAY,
+ "DARK_RAY",
+ 0,
+ "Dark + Ray",
+ "Draw dark controller with aiming axis ray"},
+ {XR_CONTROLLER_DRAW_LIGHT_RAY,
+ "LIGHT_RAY",
+ 0,
+ "Light + Ray",
+ "Draw light controller with aiming axis ray"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "XrSessionSettings", NULL);
RNA_def_struct_ui_text(srna, "XR Session Settings", "");
@@ -1450,6 +1680,13 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
"Rotation angle around the Z-Axis to apply the rotation deltas from the VR headset to");
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
+ prop = RNA_def_property(srna, "base_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Base Scale", "Uniform scale to apply to VR view");
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
+
prop = RNA_def_property(srna, "show_floor", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw_flags", V3D_OFSDRAW_SHOW_GRIDFLOOR);
RNA_def_property_ui_text(prop, "Display Grid Floor", "Show the ground plane grid");
@@ -1460,6 +1697,29 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Annotation", "Show annotations for this view");
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
+ prop = RNA_def_property(srna, "show_selection", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "draw_flags", V3D_OFSDRAW_SHOW_SELECTION);
+ RNA_def_property_ui_text(prop, "Show Selection", "Show selection outlines");
+ RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
+
+ prop = RNA_def_property(srna, "show_controllers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "draw_flags", V3D_OFSDRAW_XR_SHOW_CONTROLLERS);
+ RNA_def_property_ui_text(
+ prop, "Show Controllers", "Show VR controllers (requires VR actions for controller poses)");
+ RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
+
+ prop = RNA_def_property(srna, "show_custom_overlays", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "draw_flags", V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS);
+ RNA_def_property_ui_text(prop, "Show Custom Overlays", "Show custom VR overlays");
+ RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
+
+ prop = RNA_def_property(srna, "controller_draw_style", PROP_ENUM, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_enum_items(prop, controller_draw_styles);
+ RNA_def_property_ui_text(
+ prop, "Controller Draw Style", "Style to use when drawing VR controllers");
+ RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
+
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
@@ -1487,7 +1747,9 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
"rna_XrSessionSettings_use_absolute_tracking_get",
"rna_XrSessionSettings_use_absolute_tracking_set");
RNA_def_property_ui_text(
- prop, "Absolute Tracking", "Use unadjusted location/rotation as defined by the XR runtime");
+ prop,
+ "Absolute Tracking",
+ "Allow the VR tracking origin to be defined independently of the headset location");
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
}
@@ -1793,6 +2055,32 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
"Viewer Pose Rotation",
"Last known rotation of the viewer pose (center between the eyes) in world space");
+ prop = RNA_def_property(srna, "navigation_location", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_float_funcs(
+ prop, "rna_XrSessionState_nav_location_get", "rna_XrSessionState_nav_location_set", NULL);
+ RNA_def_property_ui_text(
+ prop,
+ "Navigation Location",
+ "Location offset to apply to base pose when determining viewer location");
+
+ prop = RNA_def_property(srna, "navigation_rotation", PROP_FLOAT, PROP_QUATERNION);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_float_funcs(
+ prop, "rna_XrSessionState_nav_rotation_get", "rna_XrSessionState_nav_rotation_set", NULL);
+ RNA_def_property_ui_text(
+ prop,
+ "Navigation Rotation",
+ "Rotation offset to apply to base pose when determining viewer rotation");
+
+ prop = RNA_def_property(srna, "navigation_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_funcs(
+ prop, "rna_XrSessionState_nav_scale_get", "rna_XrSessionState_nav_scale_set", NULL);
+ RNA_def_property_ui_text(
+ prop,
+ "Navigation Scale",
+ "Additional scale multiplier to apply to base scale when determining viewer scale");
+
prop = RNA_def_property(srna, "actionmaps", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_funcs(prop,
"rna_XrSessionState_actionmaps_begin",
@@ -1824,6 +2112,94 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name XR Event Data
+ * \{ */
+
+static void rna_def_xr_eventdata(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "XrEventData", NULL);
+ RNA_def_struct_ui_text(srna, "XrEventData", "XR Data for Window Manager Event");
+
+ prop = RNA_def_property(srna, "action_set", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_string_funcs(
+ prop, "rna_XrEventData_action_set_get", "rna_XrEventData_action_set_length", NULL);
+ RNA_def_property_ui_text(prop, "Action Set", "XR action set name");
+
+ prop = RNA_def_property(srna, "action", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_string_funcs(
+ prop, "rna_XrEventData_action_get", "rna_XrEventData_action_length", NULL);
+ RNA_def_property_ui_text(prop, "Action", "XR action name");
+
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_enum_items(prop, rna_enum_xr_action_types);
+ RNA_def_property_enum_funcs(prop, "rna_XrEventData_type_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Type", "XR action type");
+
+ prop = RNA_def_property(srna, "state", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_XrEventData_state_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "State", "XR action values corresponding to type");
+
+ prop = RNA_def_property(srna, "state_other", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_XrEventData_state_other_get", NULL, NULL);
+ RNA_def_property_ui_text(
+ prop, "State Other", "State of the other user path for bimanual actions");
+
+ prop = RNA_def_property(srna, "float_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_XrEventData_float_threshold_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Float Threshold", "Input threshold for float/2D vector actions");
+
+ prop = RNA_def_property(srna, "controller_location", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_XrEventData_controller_location_get", NULL, NULL);
+ RNA_def_property_ui_text(prop,
+ "Controller Location",
+ "Location of the action's corresponding controller aim in world space");
+
+ prop = RNA_def_property(srna, "controller_rotation", PROP_FLOAT, PROP_QUATERNION);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_XrEventData_controller_rotation_get", NULL, NULL);
+ RNA_def_property_ui_text(prop,
+ "Controller Rotation",
+ "Rotation of the action's corresponding controller aim in world space");
+
+ prop = RNA_def_property(srna, "controller_location_other", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_XrEventData_controller_location_other_get", NULL, NULL);
+ RNA_def_property_ui_text(prop,
+ "Controller Location Other",
+ "Controller aim location of the other user path for bimanual actions");
+
+ prop = RNA_def_property(srna, "controller_rotation_other", PROP_FLOAT, PROP_QUATERNION);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_XrEventData_controller_rotation_other_get", NULL, NULL);
+ RNA_def_property_ui_text(prop,
+ "Controller Rotation Other",
+ "Controller aim rotation of the other user path for bimanual actions");
+
+ prop = RNA_def_property(srna, "bimanual", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_XrEventData_bimanual_get", NULL);
+ RNA_def_property_ui_text(prop, "Bimanual", "Whether bimanual interaction is occurring");
+}
+
+/** \} */
+
void RNA_def_xr(BlenderRNA *brna)
{
RNA_define_animate_sdna(false);
@@ -1831,6 +2207,7 @@ void RNA_def_xr(BlenderRNA *brna)
rna_def_xr_actionmap(brna);
rna_def_xr_session_settings(brna);
rna_def_xr_session_state(brna);
+ rna_def_xr_eventdata(brna);
RNA_define_animate_sdna(true);
}
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index d9b9fa96d04..bb933ba97a5 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../depsgraph
../editors/include
../functions
+ ../geometry
../makesdna
../makesrna
../nodes
@@ -113,7 +114,7 @@ set(SRC
intern/MOD_weightvgedit.c
intern/MOD_weightvgmix.c
intern/MOD_weightvgproximity.c
- intern/MOD_weld.c
+ intern/MOD_weld.cc
intern/MOD_wireframe.c
MOD_modifiertypes.h
@@ -235,7 +236,6 @@ endif()
if(WITH_EXPERIMENTAL_FEATURES)
add_definitions(-DWITH_SIMULATION_DATABLOCK)
- add_definitions(-DWITH_POINT_CLOUD)
add_definitions(-DWITH_HAIR_NODES)
endif()
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index f36cb7ded9c..2a0a7a02472 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -91,6 +91,10 @@ extern ModifierTypeInfo modifierType_VolumeDisplace;
extern ModifierTypeInfo modifierType_VolumeToMesh;
/* MOD_util.c */
+
+/**
+ * Only called by `BKE_modifier.h/modifier.c`
+ */
void modifier_type_init(ModifierTypeInfo *types[]);
#ifdef __cplusplus
diff --git a/source/blender/modifiers/MOD_nodes.h b/source/blender/modifiers/MOD_nodes.h
index 907dbe9c5f4..1105925162c 100644
--- a/source/blender/modifiers/MOD_nodes.h
+++ b/source/blender/modifiers/MOD_nodes.h
@@ -24,6 +24,11 @@ struct Object;
extern "C" {
#endif
+/**
+ * Rebuild the list of properties based on the sockets exposed as the modifier's node group
+ * inputs. If any properties correspond to the old properties by name and type, carry over
+ * the values.
+ */
void MOD_nodes_update_interface(struct Object *object, struct NodesModifierData *nmd);
void MOD_nodes_init(struct Main *bmain, struct NodesModifierData *nmd);
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 2f0f11ab56d..56db68b163c 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -285,7 +285,8 @@ static void mesh_merge_transform(Mesh *result,
int cap_nloops,
int cap_npolys,
int *remap,
- int remap_len)
+ int remap_len,
+ const bool recalc_normals_later)
{
int *index_orig;
int i;
@@ -307,6 +308,15 @@ static void mesh_merge_transform(Mesh *result,
mv->flag = mv->bweight = 0;
}
+ /* We have to correct normals too, if we do not tag them as dirty later! */
+ if (!recalc_normals_later) {
+ float(*dst_vert_normals)[3] = BKE_mesh_vertex_normals_for_write(result);
+ for (i = 0; i < cap_nverts; i++) {
+ mul_mat3_m4_v3(cap_offset, dst_vert_normals[cap_verts_index + i]);
+ normalize_v3(dst_vert_normals[cap_verts_index + i]);
+ }
+ }
+
/* remap the vertex groups if necessary */
if (result->dvert != NULL) {
BKE_object_defgroup_index_map_apply(
@@ -360,7 +370,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
Mesh *mesh)
{
const MVert *src_mvert;
- MVert *mv, *mv_prev, *result_dm_verts;
+ MVert *result_dm_verts;
MEdge *me;
MLoop *ml;
@@ -572,6 +582,14 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
first_chunk_nverts = chunk_nverts;
unit_m4(current_offset);
+ const float(*src_vert_normals)[3] = NULL;
+ float(*dst_vert_normals)[3] = NULL;
+ if (!use_recalc_normals) {
+ src_vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
+ dst_vert_normals = BKE_mesh_vertex_normals_for_write(result);
+ BKE_mesh_vertex_normals_clear_dirty(result);
+ }
+
for (c = 1; c < count; c++) {
/* copy customdata to new geometry */
CustomData_copy_data(&mesh->vdata, &result->vdata, 0, c * chunk_nverts, chunk_nverts);
@@ -579,23 +597,21 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
CustomData_copy_data(&mesh->ldata, &result->ldata, 0, c * chunk_nloops, chunk_nloops);
CustomData_copy_data(&mesh->pdata, &result->pdata, 0, c * chunk_npolys, chunk_npolys);
- mv_prev = result_dm_verts;
- mv = mv_prev + c * chunk_nverts;
+ const int vert_offset = c * chunk_nverts;
/* recalculate cumulative offset here */
mul_m4_m4m4(current_offset, current_offset, offset);
/* apply offset to all new verts */
- for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) {
- mul_m4_v3(current_offset, mv->co);
+ for (i = 0; i < chunk_nverts; i++) {
+ const int i_dst = vert_offset + i;
+ mul_m4_v3(current_offset, result_dm_verts[i_dst].co);
/* We have to correct normals too, if we do not tag them as dirty! */
if (!use_recalc_normals) {
- float no[3];
- normal_short_to_float_v3(no, mv->no);
- mul_mat3_m4_v3(current_offset, no);
- normalize_v3(no);
- normal_float_to_short_v3(mv->no, no);
+ copy_v3_v3(dst_vert_normals[i_dst], src_vert_normals[i]);
+ mul_mat3_m4_v3(current_offset, dst_vert_normals[i_dst]);
+ normalize_v3(dst_vert_normals[i_dst]);
}
}
@@ -711,7 +727,8 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
start_cap_nloops,
start_cap_npolys,
vgroup_start_cap_remap,
- vgroup_start_cap_remap_len);
+ vgroup_start_cap_remap_len,
+ use_recalc_normals);
/* Identify doubles with first chunk */
if (use_merge) {
dm_mvert_map_doubles(full_doubles_map,
@@ -740,7 +757,8 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
end_cap_nloops,
end_cap_npolys,
vgroup_end_cap_remap,
- vgroup_end_cap_remap_len);
+ vgroup_end_cap_remap_len,
+ use_recalc_normals);
/* Identify doubles with last chunk */
if (use_merge) {
dm_mvert_map_doubles(full_doubles_map,
diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc
index c5d6902e1bc..bb05ae3e1b3 100644
--- a/source/blender/modifiers/intern/MOD_boolean.cc
+++ b/source/blender/modifiers/intern/MOD_boolean.cc
@@ -245,12 +245,21 @@ static BMesh *BMD_mesh_bm_create(
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh, mesh_operand_ob);
- BMeshCreateParams bmcp = {false};
- BMesh *bm = BM_mesh_create(&allocsize, &bmcp);
-
- BMeshFromMeshParams params{};
- params.calc_face_normal = true;
- BM_mesh_bm_from_me(bm, mesh_operand_ob, &params);
+ BMeshCreateParams bmesh_create_params{};
+ BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params);
+
+ /* Keep `mesh` first, needed so active layers are set based on `mesh` not `mesh_operand_ob`,
+ * otherwise the wrong active render layer is used, see T92384.
+ *
+ * NOTE: while initializing customer data layers the is not essential,
+ * it avoids the overhead of having to re-allocate #BMHeader.data when the 2nd mesh is added
+ * (if it contains additional custom-data layers). */
+ const Mesh *mesh_array[2] = {mesh, mesh_operand_ob};
+ BM_mesh_copy_init_customdata_from_mesh_array(bm, mesh_array, ARRAY_SIZE(mesh_array), &allocsize);
+
+ BMeshFromMeshParams bmesh_from_mesh_params{};
+ bmesh_from_mesh_params.calc_face_normal = true;
+ BM_mesh_bm_from_me(bm, mesh_operand_ob, &bmesh_from_mesh_params);
if (UNLIKELY(*r_is_flip)) {
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
@@ -261,7 +270,7 @@ static BMesh *BMD_mesh_bm_create(
}
}
- BM_mesh_bm_from_me(bm, mesh, &params);
+ BM_mesh_bm_from_me(bm, mesh, &bmesh_from_mesh_params);
return bm;
}
@@ -386,7 +395,7 @@ static void BMD_mesh_intersection(BMesh *bm,
* Caller owns the returned array. */
static Array<short> get_material_remap(Object *dest_ob, Object *src_ob)
{
- int n = dest_ob->totcol;
+ int n = src_ob->totcol;
if (n <= 0) {
n = 1;
}
@@ -535,9 +544,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip);
/* Needed for multiple objects to work. */
- BMeshToMeshParams params{};
- params.calc_object_remap = false;
- BM_mesh_bm_to_me(nullptr, bm, mesh, &params);
+ BMeshToMeshParams bmesh_to_mesh_params{};
+ bmesh_to_mesh_params.calc_object_remap = false;
+ BM_mesh_bm_to_me(nullptr, bm, mesh, &bmesh_to_mesh_params);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh);
BM_mesh_free(bm);
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 6cd8d70383d..86f0df1418b 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -280,9 +280,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, struct
MEM_freeN(edgeMap);
MEM_freeN(faceMap);
- if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
- BKE_mesh_normals_tag_dirty(result);
- }
+ BKE_mesh_normals_tag_dirty(result);
/* TODO(sybren): also copy flags & tags? */
return result;
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index cf0658d4b39..8aff29dc17d 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -201,13 +201,9 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
tclmd->point_cache = clmd->point_cache;
}
else {
- tclmd->point_cache = BKE_ptcache_add(&tclmd->ptcaches);
- if (clmd->point_cache != NULL) {
- tclmd->point_cache->step = clmd->point_cache->step;
- tclmd->point_cache->startframe = clmd->point_cache->startframe;
- tclmd->point_cache->endframe = clmd->point_cache->endframe;
- tclmd->point_cache->flag |= (clmd->point_cache->flag & PTCACHE_FLAGS_COPY);
- }
+ const int clmd_point_cache_index = BLI_findindex(&clmd->ptcaches, clmd->point_cache);
+ BKE_ptcache_copy_list(&tclmd->ptcaches, &clmd->ptcaches, flag);
+ tclmd->point_cache = BLI_findlink(&tclmd->ptcaches, clmd_point_cache_index);
}
tclmd->sim_parms = MEM_dupallocN(clmd->sim_parms);
@@ -285,7 +281,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL);
- uiItemL(layout, IFACE_("Settings are inside the Physics tab"), ICON_NONE);
+ uiItemL(layout, TIP_("Settings are inside the Physics tab"), ICON_NONE);
modifier_panel_end(layout, ptr);
}
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index 521a93b199f..02e1f61b824 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -263,7 +263,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL);
- uiItemL(layout, IFACE_("Settings are inside the Physics tab"), ICON_NONE);
+ uiItemL(layout, TIP_("Settings are inside the Physics tab"), ICON_NONE);
modifier_panel_end(layout, ptr);
}
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index 9e8f5bee396..49ff4acb31f 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -588,7 +588,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
const bool force_delta_cache_update =
- /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
+ /* XXX, take care! if mesh data itself changes we need to forcefully recalculate deltas */
!cache_settings_equal(csmd) ||
((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
(((ID *)ob->data)->recalc & ID_RECALC_ALL));
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index aae6d257766..20dbb299767 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -167,7 +167,7 @@ static void deformVertsEM(ModifierData *md,
int defgrp_index = -1;
if (ctx->object->type == OB_MESH && cmd->name[0] != '\0') {
- defgrp_index = BKE_id_defgroup_name_index(&mesh->id, cmd->name);
+ defgrp_index = BKE_object_defgroup_name_index(ctx->object, cmd->name);
if (defgrp_index != -1) {
use_dverts = true;
}
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index e2b2cc58d48..34bb93cbbbc 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -163,7 +163,6 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
return !dtmd->ob_source || dtmd->ob_source->type != OB_MESH;
}
-#define HIGH_POLY_WARNING 10000
#define DT_TYPES_AFFECT_MESH \
(DT_TYPE_BWEIGHT_VERT | DT_TYPE_BWEIGHT_EDGE | DT_TYPE_CREASE | DT_TYPE_SHARP_EDGE | \
DT_TYPE_LNOR | DT_TYPE_SHARP_FACE)
@@ -239,13 +238,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
BKE_modifier_set_error(
ctx->object, (ModifierData *)dtmd, "Enable 'Auto Smooth' in Object Data Properties");
}
- else if (result->totvert > HIGH_POLY_WARNING ||
- ((Mesh *)(ob_source->data))->totvert > HIGH_POLY_WARNING) {
- BKE_modifier_set_error(
- ctx->object,
- md,
- "Source or destination object has a high polygon count, computation might be slow");
- }
return result;
}
@@ -473,7 +465,6 @@ static void panelRegister(ARegionType *region_type)
region_type, "advanced", "Topology Mapping", NULL, advanced_panel_draw, panel_type);
}
-#undef HIGH_POLY_WARNING
#undef DT_TYPES_AFFECT_MESH
ModifierTypeInfo modifierType_DataTransfer = {
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 56fcbbd8b7c..975f80a04f8 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -236,8 +236,8 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
int decimate_type = RNA_enum_get(ptr, "decimate_type");
- char count_info[32];
- snprintf(count_info, 32, "%s: %d", IFACE_("Face Count"), RNA_int_get(ptr, "face_count"));
+ char count_info[64];
+ snprintf(count_info, 32, TIP_("Face Count: %d"), RNA_int_get(ptr, "face_count"));
uiItemR(layout, ptr, "decimate_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index 07da18f990d..010292d2ebb 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -177,6 +177,7 @@ typedef struct DisplaceUserdata {
float (*vertexCos)[3];
float local_mat[4][4];
MVert *mvert;
+ const float (*vert_normals)[3];
float (*vert_clnors)[3];
} DisplaceUserdata;
@@ -194,7 +195,6 @@ static void displaceModifier_do_task(void *__restrict userdata,
bool use_global_direction = data->use_global_direction;
float(*tex_co)[3] = data->tex_co;
float(*vertexCos)[3] = data->vertexCos;
- MVert *mvert = data->mvert;
float(*vert_clnors)[3] = data->vert_clnors;
const float delta_fixed = 1.0f -
@@ -272,9 +272,7 @@ static void displaceModifier_do_task(void *__restrict userdata,
add_v3_v3(vertexCos[iter], local_vec);
break;
case MOD_DISP_DIR_NOR:
- vertexCos[iter][0] += delta * (mvert[iter].no[0] / 32767.0f);
- vertexCos[iter][1] += delta * (mvert[iter].no[1] / 32767.0f);
- vertexCos[iter][2] += delta * (mvert[iter].no[2] / 32767.0f);
+ madd_v3_v3fl(vertexCos[iter], data->vert_normals[iter], delta);
break;
case MOD_DISP_DIR_CLNOR:
madd_v3_v3fl(vertexCos[iter], vert_clnors[iter], delta);
@@ -363,6 +361,9 @@ static void displaceModifier_do(DisplaceModifierData *dmd,
data.vertexCos = vertexCos;
copy_m4_m4(data.local_mat, local_mat);
data.mvert = mvert;
+ if (direction == MOD_DISP_DIR_NOR) {
+ data.vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
+ }
data.vert_clnors = vert_clnors;
if (tex_target != NULL) {
data.pool = BKE_image_pool_new();
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index 77ae5c4b6f1..a696ce216c7 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -193,7 +193,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL);
- uiItemL(layout, IFACE_("Settings are inside the Physics tab"), ICON_NONE);
+ uiItemL(layout, TIP_("Settings are inside the Physics tab"), ICON_NONE);
modifier_panel_end(layout, ptr);
}
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index b21a536ad8a..1039bcb2b3b 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -20,10 +20,10 @@
/** \file
* \ingroup modifiers
*
- * EdgeSplit modifier
+ * Edge Split modifier
*
* Splits edges in the mesh according to sharpness flag
- * or edge angle (can be used to achieve autosmoothing)
+ * or edge angle (can be used to achieve auto-smoothing)
*/
#include "BLI_utildefines.h"
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 493b59b3a1a..68d6b4a3626 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -1118,7 +1118,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
/* finalization */
BKE_mesh_calc_edges_tessface(explode);
BKE_mesh_convert_mfaces_to_mpolys(explode);
- explode->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(explode);
if (psmd->psys->lattice_deform_data) {
BKE_lattice_deform_data_destroy(psmd->psys->lattice_deform_data);
diff --git a/source/blender/modifiers/intern/MOD_fluid.c b/source/blender/modifiers/intern/MOD_fluid.c
index a14d582063a..a21eb603300 100644
--- a/source/blender/modifiers/intern/MOD_fluid.c
+++ b/source/blender/modifiers/intern/MOD_fluid.c
@@ -25,6 +25,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -112,6 +113,31 @@ static void requiredDataMask(Object *UNUSED(ob),
}
}
+typedef struct FluidIsolationData {
+ Depsgraph *depsgraph;
+ Object *object;
+ Mesh *mesh;
+ FluidModifierData *fmd;
+
+ Mesh *result;
+} FluidIsolationData;
+
+#ifdef WITH_FLUID
+static void fluid_modifier_do_isolated(void *userdata)
+{
+ FluidIsolationData *isolation_data = (FluidIsolationData *)userdata;
+
+ Scene *scene = DEG_get_evaluated_scene(isolation_data->depsgraph);
+
+ Mesh *result = BKE_fluid_modifier_do(isolation_data->fmd,
+ isolation_data->depsgraph,
+ scene,
+ isolation_data->object,
+ isolation_data->mesh);
+ isolation_data->result = result ? result : isolation_data->mesh;
+}
+#endif /* WITH_FLUID */
+
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me)
{
#ifndef WITH_FLUID
@@ -119,16 +145,24 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
return me;
#else
FluidModifierData *fmd = (FluidModifierData *)md;
- Mesh *result = NULL;
if (ctx->flag & MOD_APPLY_ORCO) {
return me;
}
- Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
-
- result = BKE_fluid_modifier_do(fmd, ctx->depsgraph, scene, ctx->object, me);
- return result ? result : me;
+ /* Isolate execution of Mantaflow when running from dependency graph. The reason for this is
+ * because Mantaflow uses TBB to parallel its own computation which without isolation will start
+ * stealing tasks from dependency graph. Stealing tasks from the dependency graph might cause
+ * a recursive lock when Python drivers are used (because Mantaflow is interfaced via Python as
+ * well. */
+ FluidIsolationData isolation_data;
+ isolation_data.depsgraph = ctx->depsgraph;
+ isolation_data.object = ctx->object;
+ isolation_data.mesh = me;
+ isolation_data.fmd = fmd;
+ BLI_task_isolate(fluid_modifier_do_isolated, &isolation_data);
+
+ return isolation_data.result;
#endif /* WITH_FLUID */
}
@@ -213,7 +247,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL);
- uiItemL(layout, IFACE_("Settings are inside the Physics tab"), ICON_NONE);
+ uiItemL(layout, TIP_("Settings are inside the Physics tab"), ICON_NONE);
modifier_panel_end(layout, ptr);
}
diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc
index 9a8af35109a..0de8b26a1b7 100644
--- a/source/blender/modifiers/intern/MOD_mask.cc
+++ b/source/blender/modifiers/intern/MOD_mask.cc
@@ -70,19 +70,6 @@ using blender::MutableSpan;
using blender::Span;
using blender::Vector;
-/* For delete geometry node. */
-void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span<int> vertex_map);
-void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- Span<int> vertex_map,
- Span<int> edge_map);
-void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- Span<int> vertex_map,
- Span<int> edge_map,
- Span<int> masked_poly_indices,
- Span<int> new_loop_starts);
-
static void initData(ModifierData *md)
{
MaskModifierData *mmd = (MaskModifierData *)md;
@@ -355,7 +342,9 @@ static void compute_interpolated_polygons(const Mesh *mesh,
*r_num_add_loops = num_add_loops;
}
-void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span<int> vertex_map)
+static void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map)
{
BLI_assert(src_mesh.totvert == vertex_map.size());
for (const int i_src : vertex_map.index_range()) {
@@ -438,16 +427,6 @@ static void add_interp_verts_copy_edges_to_new_mesh(const Mesh &src_mesh,
MVert &v2 = src_mesh.mvert[e_src.v2];
interp_v3_v3v3(v.co, v1.co, v2.co, fac);
-
- float no1[3];
- float no2[3];
- normal_short_to_float_v3(no1, v1.no);
- normal_short_to_float_v3(no2, v2.no);
- mul_v3_fl(no1, weights[0]);
- madd_v3_v3fl(no1, no2, weights[1]);
- normalize_v3(no1);
- normal_float_to_short_v3(v.no, no1);
-
vert_index++;
}
}
@@ -455,16 +434,16 @@ static void add_interp_verts_copy_edges_to_new_mesh(const Mesh &src_mesh,
BLI_assert(edge_index == num_masked_edges);
}
-void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- Span<int> vertex_map,
- Span<int> edge_map)
+static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map,
+ Span<int> edge_map)
{
BLI_assert(src_mesh.totvert == vertex_map.size());
BLI_assert(src_mesh.totedge == edge_map.size());
for (const int i_src : IndexRange(src_mesh.totedge)) {
const int i_dst = edge_map[i_src];
- if (i_dst == -1 || i_dst == -2) {
+ if (ELEM(i_dst, -1, -2)) {
continue;
}
@@ -508,35 +487,6 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
}
}
}
-void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- Span<int> vertex_map,
- Span<int> edge_map,
- Span<int> masked_poly_indices,
- Span<int> new_loop_starts)
-{
- for (const int i_dst : masked_poly_indices.index_range()) {
- const int i_src = masked_poly_indices[i_dst];
-
- const MPoly &mp_src = src_mesh.mpoly[i_src];
- MPoly &mp_dst = dst_mesh.mpoly[i_dst];
- const int i_ml_src = mp_src.loopstart;
- const int i_ml_dst = new_loop_starts[i_dst];
-
- CustomData_copy_data(&src_mesh.pdata, &dst_mesh.pdata, i_src, i_dst, 1);
- CustomData_copy_data(&src_mesh.ldata, &dst_mesh.ldata, i_ml_src, i_ml_dst, mp_src.totloop);
-
- const MLoop *ml_src = src_mesh.mloop + i_ml_src;
- MLoop *ml_dst = dst_mesh.mloop + i_ml_dst;
-
- mp_dst = mp_src;
- mp_dst.loopstart = i_ml_dst;
- for (int i : IndexRange(mp_src.totloop)) {
- ml_dst[i].v = vertex_map[ml_src[i].v];
- ml_dst[i].e = edge_map[ml_src[i].e];
- }
- }
-}
static void add_interpolated_polys_to_new_mesh(const Mesh &src_mesh,
Mesh &dst_mesh,
@@ -702,7 +652,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx)
Object *armature_ob = mmd->ob_arm;
/* Return input mesh if there is no armature with bones. */
- if (ELEM(NULL, armature_ob, armature_ob->pose)) {
+ if (ELEM(nullptr, armature_ob, armature_ob->pose)) {
return mesh;
}
diff --git a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc
index 778b5746471..910b52dea67 100644
--- a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc
+++ b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc
@@ -197,8 +197,8 @@ static float compute_voxel_size(const ModifierEvalContext *ctx,
/* Compute the voxel size based on the desired number of voxels and the approximated bounding box
* of the volume. */
const BoundBox *bb = BKE_object_boundbox_get(mvmd->object);
- const float diagonal = float3::distance(transform * float3(bb->vec[6]),
- transform * float3(bb->vec[0]));
+ const float diagonal = math::distance(transform * float3(bb->vec[6]),
+ transform * float3(bb->vec[0]));
const float approximate_volume_side_length = diagonal + mvmd->exterior_band_width * 2.0f;
const float voxel_size = approximate_volume_side_length / mvmd->voxel_amount / volume_simplify;
return voxel_size;
diff --git a/source/blender/modifiers/intern/MOD_meshcache_util.h b/source/blender/modifiers/intern/MOD_meshcache_util.h
index 74131099e3c..b1a8a3ffc19 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_util.h
+++ b/source/blender/modifiers/intern/MOD_meshcache_util.h
@@ -23,52 +23,45 @@
/* MOD_meshcache_mdd.c */
bool MOD_meshcache_read_mdd_index(FILE *fp,
float (*vertexCos)[3],
- const int vertex_tot,
- const int index,
- const float factor,
+ int vertex_tot,
+ int index,
+ float factor,
const char **err_str);
bool MOD_meshcache_read_mdd_frame(FILE *fp,
float (*vertexCos)[3],
- const int verts_tot,
- const char interp,
- const float frame,
+ int verts_tot,
+ char interp,
+ float frame,
const char **err_str);
bool MOD_meshcache_read_mdd_times(const char *filepath,
float (*vertexCos)[3],
- const int verts_tot,
- const char interp,
- const float time,
- const float fps,
- const char time_mode,
+ int verts_tot,
+ char interp,
+ float time,
+ float fps,
+ char time_mode,
const char **err_str);
/* MOD_meshcache_pc2.c */
-bool MOD_meshcache_read_pc2_index(FILE *fp,
- float (*vertexCos)[3],
- const int verts_tot,
- const int index,
- const float factor,
- const char **err_str);
+bool MOD_meshcache_read_pc2_index(
+ FILE *fp, float (*vertexCos)[3], int verts_tot, int index, float factor, const char **err_str);
bool MOD_meshcache_read_pc2_frame(FILE *fp,
float (*vertexCos)[3],
- const int verts_tot,
- const char interp,
- const float frame,
+ int verts_tot,
+ char interp,
+ float frame,
const char **err_str);
bool MOD_meshcache_read_pc2_times(const char *filepath,
float (*vertexCos)[3],
- const int verts_tot,
- const char interp,
- const float time,
- const float fps,
- const char time_mode,
+ int verts_tot,
+ char interp,
+ float time,
+ float fps,
+ char time_mode,
const char **err_str);
/* MOD_meshcache_util.c */
-void MOD_meshcache_calc_range(const float frame,
- const char interp,
- const int frame_tot,
- int r_index_range[2],
- float *r_factor);
+void MOD_meshcache_calc_range(
+ float frame, char interp, int frame_tot, int r_index_range[2], float *r_factor);
#define FRAME_SNAP_EPS 0.0001f
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index c997cd7377f..cb043643dd9 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -426,7 +426,7 @@ static void meshdeformModifier_do(ModifierData *md,
bindcagecos = (float(*)[3])mmd->bindcagecos;
for (a = 0; a < totcagevert; a++) {
- /* get cage vertex in world space with binding transform */
+ /* Get cage vertex in world-space with binding transform. */
float co[3];
mul_v3_m4v3(co, mmd->bindmat, dco[a]);
/* compute difference with world space bind coord */
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index bcaf294ec8b..e1459ccba6d 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -328,14 +328,105 @@ static void panel_draw(const bContext *C, Panel *panel)
uiItemR(layout, ptr, "use_vertex_interpolation", 0, NULL, ICON_NONE);
}
+ modifier_panel_end(layout, ptr);
+}
+
+static void velocity_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
+ return;
+ }
+
+ if (RNA_pointer_is_null(&fileptr)) {
+ return;
+ }
+
+ uiLayoutSetPropSep(layout, true);
+ uiTemplateCacheFileVelocity(layout, &fileptr);
uiItemR(layout, ptr, "velocity_scale", 0, NULL, ICON_NONE);
+}
- modifier_panel_end(layout, ptr);
+static void time_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
+ return;
+ }
+
+ if (RNA_pointer_is_null(&fileptr)) {
+ return;
+ }
+
+ uiLayoutSetPropSep(layout, true);
+ uiTemplateCacheFileTimeSettings(layout, &fileptr);
+}
+
+static void render_procedural_panel_draw(const bContext *C, Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
+ return;
+ }
+
+ if (RNA_pointer_is_null(&fileptr)) {
+ return;
+ }
+
+ uiLayoutSetPropSep(layout, true);
+ uiTemplateCacheFileProcedural(layout, C, &fileptr);
+}
+
+static void override_layers_panel_draw(const bContext *C, Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
+ return;
+ }
+
+ uiLayoutSetPropSep(layout, true);
+ uiTemplateCacheFileLayers(layout, C, &fileptr);
}
static void panelRegister(ARegionType *region_type)
{
- modifier_panel_register(region_type, eModifierType_MeshSequenceCache, panel_draw);
+ PanelType *panel_type = modifier_panel_register(
+ region_type, eModifierType_MeshSequenceCache, panel_draw);
+ modifier_subpanel_register(region_type, "time", "Time", NULL, time_panel_draw, panel_type);
+ modifier_subpanel_register(region_type,
+ "render_procedural",
+ "Render Procedural",
+ NULL,
+ render_procedural_panel_draw,
+ panel_type);
+ modifier_subpanel_register(
+ region_type, "velocity", "Velocity", NULL, velocity_panel_draw, panel_type);
+ modifier_subpanel_register(region_type,
+ "override_layers",
+ "Override Layers",
+ NULL,
+ override_layers_panel_draw,
+ panel_type);
}
static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 7fd90c71c9f..bbac6589577 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -84,14 +84,17 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd, Object *ob, Mesh *mesh)
{
Mesh *result = mesh;
+ const bool use_correct_order_on_merge = mmd->use_correct_order_on_merge;
/* check which axes have been toggled and mirror accordingly */
if (mmd->flag & MOD_MIR_AXIS_X) {
- result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(mmd, ob, result, 0);
+ result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(
+ mmd, ob, result, 0, use_correct_order_on_merge);
}
if (mmd->flag & MOD_MIR_AXIS_Y) {
Mesh *tmp = result;
- result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(mmd, ob, result, 1);
+ result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(
+ mmd, ob, result, 1, use_correct_order_on_merge);
if (tmp != mesh) {
/* free intermediate results */
BKE_id_free(NULL, tmp);
@@ -99,7 +102,8 @@ static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd, Object *ob, Mesh
}
if (mmd->flag & MOD_MIR_AXIS_Z) {
Mesh *tmp = result;
- result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(mmd, ob, result, 2);
+ result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(
+ mmd, ob, result, 2, use_correct_order_on_merge);
if (tmp != mesh) {
/* free intermediate results */
BKE_id_free(NULL, tmp);
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index d294491d51c..49528845197 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -27,11 +27,13 @@
#include "MEM_guardedalloc.h"
-#include "BLI_float3.hh"
+#include "BLI_array.hh"
#include "BLI_listbase.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_multi_value_map.hh"
#include "BLI_set.hh"
#include "BLI_string.h"
+#include "BLI_string_search.h"
#include "BLI_utildefines.h"
#include "DNA_collection_types.h"
@@ -53,10 +55,12 @@
#include "BKE_geometry_set_instances.hh"
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "BKE_pointcloud.h"
#include "BKE_screen.h"
@@ -66,6 +70,7 @@
#include "BLO_read_write.h"
#include "UI_interface.h"
+#include "UI_interface.hh"
#include "UI_resources.h"
#include "BLT_translation.h"
@@ -83,7 +88,10 @@
#include "MOD_nodes_evaluator.hh"
#include "MOD_ui_common.h"
+#include "ED_object.h"
+#include "ED_screen.h"
#include "ED_spreadsheet.h"
+#include "ED_undo.h"
#include "NOD_derived_node_tree.hh"
#include "NOD_geometry.h"
@@ -91,8 +99,10 @@
#include "NOD_node_declaration.hh"
#include "FN_field.hh"
+#include "FN_field_cpp_type.hh"
#include "FN_multi_function.hh"
+using blender::Array;
using blender::ColorGeometry4f;
using blender::destruct_ptr;
using blender::float3;
@@ -105,15 +115,18 @@ using blender::StringRef;
using blender::StringRefNull;
using blender::Vector;
using blender::bke::OutputAttribute;
+using blender::fn::Field;
using blender::fn::GField;
using blender::fn::GMutablePointer;
using blender::fn::GPointer;
+using blender::fn::ValueOrField;
using blender::nodes::FieldInferencingInterface;
using blender::nodes::GeoNodeExecParams;
using blender::nodes::InputSocketFieldType;
using blender::threading::EnumerableThreadSpecific;
using namespace blender::fn::multi_function_types;
using namespace blender::nodes::derived_node_tree_types;
+using geo_log::GeometryAttributeInfo;
static void initData(ModifierData *md)
{
@@ -151,6 +164,12 @@ static void addIdsUsedBySocket(const ListBase *sockets, Set<ID *> &ids)
ids.add(&texture->id);
}
}
+ else if (socket->type == SOCK_IMAGE) {
+ Image *image = ((bNodeSocketValueImage *)socket->default_value)->value;
+ if (image != nullptr) {
+ ids.add(&image->id);
+ }
+ }
}
}
@@ -219,7 +238,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
DEG_add_modifier_to_transform_relation(ctx->node, "Nodes Modifier");
if (nmd->node_group != nullptr) {
- DEG_add_node_tree_relation(ctx->node, nmd->node_group, "Nodes Modifier");
+ DEG_add_node_tree_output_relation(ctx->node, nmd->node_group, "Nodes Modifier");
Set<ID *> used_ids;
find_used_ids_from_settings(nmd->settings, used_ids);
@@ -236,6 +255,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
add_collection_relation(ctx, *collection);
break;
}
+ case ID_IM:
case ID_TE: {
DEG_add_generic_id_relation(ctx->node, id, "Nodes Modifier");
}
@@ -249,6 +269,39 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
}
+static bool check_tree_for_time_node(const bNodeTree &tree,
+ Set<const bNodeTree *> &r_checked_trees)
+{
+ if (!r_checked_trees.add(&tree)) {
+ return false;
+ }
+ LISTBASE_FOREACH (const bNode *, node, &tree.nodes) {
+ if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
+ return true;
+ }
+ if (node->type == NODE_GROUP) {
+ const bNodeTree *sub_tree = reinterpret_cast<const bNodeTree *>(node->id);
+ if (sub_tree && check_tree_for_time_node(*sub_tree, r_checked_trees)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool dependsOnTime(struct Scene *UNUSED(scene),
+ ModifierData *md,
+ const int UNUSED(dag_eval_mode))
+{
+ const NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ const bNodeTree *tree = nmd->node_group;
+ if (tree == nullptr) {
+ return false;
+ }
+ Set<const bNodeTree *> checked_trees;
+ return check_tree_for_time_node(*tree, checked_trees);
+}
+
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
@@ -420,6 +473,12 @@ static IDProperty *id_property_create_from_socket(const bNodeSocket &socket)
idprop.id = (ID *)value->value;
return IDP_New(IDP_ID, &idprop, socket.identifier);
}
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *value = (bNodeSocketValueImage *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.id = (ID *)value->value;
+ return IDP_New(IDP_ID, &idprop, socket.identifier);
+ }
case SOCK_MATERIAL: {
bNodeSocketValueMaterial *value = (bNodeSocketValueMaterial *)socket.default_value;
IDPropertyTemplate idprop = {0};
@@ -448,6 +507,7 @@ static bool id_property_type_matches_socket(const bNodeSocket &socket, const IDP
case SOCK_OBJECT:
case SOCK_COLLECTION:
case SOCK_TEXTURE:
+ case SOCK_IMAGE:
case SOCK_MATERIAL:
return property.type == IDP_ID;
}
@@ -468,35 +528,34 @@ static void init_socket_cpp_value_from_property(const IDProperty &property,
else if (property.type == IDP_DOUBLE) {
value = (float)IDP_Double(&property);
}
- new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<float>(value);
break;
}
case SOCK_INT: {
int value = IDP_Int(&property);
- new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<int>(value);
break;
}
case SOCK_VECTOR: {
float3 value;
copy_v3_v3(value, (const float *)IDP_Array(&property));
- new (r_value) blender::fn::Field<float3>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<float3>(value);
break;
}
case SOCK_RGBA: {
blender::ColorGeometry4f value;
copy_v4_v4((float *)value, (const float *)IDP_Array(&property));
- new (r_value) blender::fn::Field<ColorGeometry4f>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<ColorGeometry4f>(value);
break;
}
case SOCK_BOOLEAN: {
bool value = IDP_Int(&property) != 0;
- new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<bool>(value);
break;
}
case SOCK_STRING: {
std::string value = IDP_String(&property);
- new (r_value)
- blender::fn::Field<std::string>(blender::fn::make_constant_field(std::move(value)));
+ new (r_value) ValueOrField<std::string>(std::move(value));
break;
}
case SOCK_OBJECT: {
@@ -517,6 +576,12 @@ static void init_socket_cpp_value_from_property(const IDProperty &property,
*(Tex **)r_value = texture;
break;
}
+ case SOCK_IMAGE: {
+ ID *id = IDP_Id(&property);
+ Image *image = (id && GS(id->name) == ID_IM) ? (Image *)id : nullptr;
+ *(Image **)r_value = image;
+ break;
+ }
case SOCK_MATERIAL: {
ID *id = IDP_Id(&property);
Material *material = (id && GS(id->name) == ID_MA) ? (Material *)id : nullptr;
@@ -530,11 +595,6 @@ static void init_socket_cpp_value_from_property(const IDProperty &property,
}
}
-/**
- * Rebuild the list of properties based on the sockets exposed as the modifier's node group
- * inputs. If any properties correspond to the old properties by name and type, carry over
- * the values.
- */
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
{
if (nmd->node_group == nullptr) {
@@ -579,7 +639,7 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
}
}
- if (input_has_attribute_toggle(*nmd->node_group, socket_index)) {
+ if (socket_type_has_attribute_toggle(*socket)) {
const std::string use_attribute_id = socket->identifier + use_attribute_suffix;
const std::string attribute_name_id = socket->identifier + attribute_name_suffix;
@@ -666,7 +726,7 @@ void MOD_nodes_init(Main *bmain, NodesModifierData *nmd)
group_input_node,
(bNodeSocket *)group_input_node->outputs.first);
- ntreeUpdateTree(bmain, ntree);
+ BKE_ntree_update_main_tree(bmain, ntree, nullptr);
}
static void initialize_group_input(NodesModifierData &nmd,
@@ -710,8 +770,13 @@ static void initialize_group_input(NodesModifierData &nmd,
if (use_attribute) {
const StringRef attribute_name{IDP_String(property_attribute_name)};
auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>(
- attribute_name, *socket_type.get_base_cpp_type());
- new (r_value) blender::fn::GField(std::move(attribute_input), 0);
+ attribute_name, *socket_type.base_cpp_type);
+ GField attribute_field{std::move(attribute_input), 0};
+ const blender::fn::ValueOrFieldCPPType *cpp_type =
+ dynamic_cast<const blender::fn::ValueOrFieldCPPType *>(
+ socket_type.geometry_nodes_cpp_type);
+ BLI_assert(cpp_type != nullptr);
+ cpp_type->construct_from_field(r_value, std::move(attribute_field));
}
else {
init_socket_cpp_value_from_property(
@@ -738,32 +803,33 @@ static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain)
return spreadsheets;
}
-static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadsheet,
- NodesModifierData *nmd,
- const ModifierEvalContext *ctx,
- const DerivedNodeTree &tree)
+static void find_sockets_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadsheet,
+ NodesModifierData *nmd,
+ const ModifierEvalContext *ctx,
+ const DerivedNodeTree &tree,
+ Set<DSocket> &r_sockets_to_preview)
{
Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path;
if (context_path.size() < 3) {
- return {};
+ return;
}
if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
- return {};
+ return;
}
if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
- return {};
+ return;
}
SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0];
if (object_context->object != DEG_get_original_object(ctx->object)) {
- return {};
+ return;
}
SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context_path[1];
if (StringRef(modifier_context->modifier_name) != nmd->modifier.name) {
- return {};
+ return;
}
for (SpreadsheetContext *context : context_path.as_span().drop_front(2)) {
if (context->type != SPREADSHEET_CONTEXT_NODE) {
- return {};
+ return;
}
}
@@ -782,11 +848,11 @@ static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspre
}
}
if (found_node == nullptr) {
- return {};
+ return;
}
context = context->child_context(*found_node);
if (context == nullptr) {
- return {};
+ return;
}
}
@@ -794,10 +860,13 @@ static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspre
for (const NodeRef *node_ref : tree_ref.nodes_by_type("GeometryNodeViewer")) {
if (node_ref->name() == last_context->node_name) {
const DNode viewer_node{context, node_ref};
- return viewer_node.input(0);
+ for (const InputSocketRef *input_socket : node_ref->inputs()) {
+ if (input_socket->is_available() && input_socket->is_logically_linked()) {
+ r_sockets_to_preview.add(DSocket{context, input_socket});
+ }
+ }
}
}
- return {};
}
static void find_sockets_to_preview(NodesModifierData *nmd,
@@ -811,10 +880,7 @@ static void find_sockets_to_preview(NodesModifierData *nmd,
* intermediate geometries cached for display. */
Vector<SpaceSpreadsheet *> spreadsheets = find_spreadsheet_editors(bmain);
for (SpaceSpreadsheet *sspreadsheet : spreadsheets) {
- const DSocket socket = try_get_socket_to_preview_for_spreadsheet(sspreadsheet, nmd, ctx, tree);
- if (socket) {
- r_sockets_to_preview.add(socket);
- }
+ find_sockets_to_preview_for_spreadsheet(sspreadsheet, nmd, ctx, tree, r_sockets_to_preview);
}
}
@@ -874,7 +940,11 @@ static void store_output_value_in_geometry(GeometrySet &geometry_set,
if (attribute_name.is_empty()) {
return;
}
- const GField &field = *(const GField *)value.get();
+ const blender::fn::ValueOrFieldCPPType *cpp_type =
+ dynamic_cast<const blender::fn::ValueOrFieldCPPType *>(value.type());
+ BLI_assert(cpp_type != nullptr);
+
+ const GField field = cpp_type->as_field(value.get());
const bNodeSocket *interface_socket = (bNodeSocket *)BLI_findlink(&nmd->node_group->outputs,
socket.index());
const AttributeDomain domain = (AttributeDomain)interface_socket->attribute_domain;
@@ -890,6 +960,10 @@ static void store_output_value_in_geometry(GeometrySet &geometry_set,
CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
store_field_on_geometry_component(component, attribute_name, domain, field);
}
+ if (geometry_set.has_instances()) {
+ InstancesComponent &component = geometry_set.get_component_for_write<InstancesComponent>();
+ store_field_on_geometry_component(component, attribute_name, domain, field);
+ }
}
/**
@@ -904,7 +978,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
{
blender::ResourceScope scope;
blender::LinearAllocator<> &allocator = scope.linear_allocator();
- blender::nodes::NodeMultiFunctions mf_by_node{tree, scope};
+ blender::nodes::NodeMultiFunctions mf_by_node{tree};
Map<DOutputSocket, GMutablePointer> group_inputs;
@@ -929,16 +1003,13 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
/* Initialize remaining group inputs. */
for (const OutputSocketRef *socket : remaining_input_sockets) {
- const CPPType &cpp_type = *socket->typeinfo()->get_geometry_nodes_cpp_type();
+ const CPPType &cpp_type = *socket->typeinfo()->geometry_nodes_cpp_type;
void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment());
initialize_group_input(*nmd, *socket, value_in);
group_inputs.add_new({root_context, socket}, {cpp_type, value_in});
}
}
- /* Don't keep a reference to the input geometry components to avoid copies during evaluation. */
- input_geometry_set.clear();
-
Vector<DInputSocket> group_outputs;
for (const InputSocketRef *socket_ref : output_node.inputs().drop_back(1)) {
group_outputs.append({root_context, socket_ref});
@@ -953,8 +1024,13 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
find_sockets_to_preview(nmd, ctx, tree, preview_sockets);
eval_params.force_compute_sockets.extend(preview_sockets.begin(), preview_sockets.end());
geo_logger.emplace(std::move(preview_sockets));
+
+ geo_logger->log_input_geometry(input_geometry_set);
}
+ /* Don't keep a reference to the input geometry components to avoid copies during evaluation. */
+ input_geometry_set.clear();
+
eval_params.input_values = group_inputs;
eval_params.output_sockets = group_outputs;
eval_params.mf_by_node = &mf_by_node;
@@ -964,14 +1040,15 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
eval_params.geo_logger = geo_logger.has_value() ? &*geo_logger : nullptr;
blender::modifiers::geometry_nodes::evaluate_geometry_nodes(eval_params);
+ GeometrySet output_geometry_set = eval_params.r_output_values[0].relocate_out<GeometrySet>();
+
if (geo_logger.has_value()) {
+ geo_logger->log_output_geometry(output_geometry_set);
NodesModifierData *nmd_orig = (NodesModifierData *)BKE_modifier_get_original(&nmd->modifier);
clear_runtime_data(nmd_orig);
nmd_orig->runtime_eval_log = new geo_log::ModifierLog(*geo_logger);
}
- GeometrySet output_geometry_set = eval_params.r_output_values[0].relocate_out<GeometrySet>();
-
for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) {
GMutablePointer socket_value = eval_params.r_output_values[socket->index()];
store_output_value_in_geometry(output_geometry_set, nmd, *socket, socket_value);
@@ -989,17 +1066,20 @@ static void check_property_socket_sync(const Object *ob, ModifierData *md)
{
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
- int i = 0;
+ int geometry_socket_count = 0;
+
+ int i;
LISTBASE_FOREACH_INDEX (const bNodeSocket *, socket, &nmd->node_group->inputs, i) {
/* The first socket is the special geometry socket for the modifier object. */
if (i == 0 && socket->type == SOCK_GEOMETRY) {
+ geometry_socket_count++;
continue;
}
IDProperty *property = IDP_GetPropertyFromGroup(nmd->settings.properties, socket->identifier);
if (property == nullptr) {
if (socket->type == SOCK_GEOMETRY) {
- BKE_modifier_set_error(ob, md, "Node group can only have one geometry input");
+ geometry_socket_count++;
}
else {
BKE_modifier_set_error(ob, md, "Missing property for input socket \"%s\"", socket->name);
@@ -1014,15 +1094,13 @@ static void check_property_socket_sync(const Object *ob, ModifierData *md)
}
}
- bool has_geometry_output = false;
- LISTBASE_FOREACH (const bNodeSocket *, socket, &nmd->node_group->outputs) {
- if (socket->type == SOCK_GEOMETRY) {
- has_geometry_output = true;
+ if (geometry_socket_count == 1) {
+ if (((bNodeSocket *)nmd->node_group->inputs.first)->type != SOCK_GEOMETRY) {
+ BKE_modifier_set_error(ob, md, "Node group's geometry input must be the first");
}
}
-
- if (!has_geometry_output) {
- BKE_modifier_set_error(ob, md, "Node group must have a geometry output");
+ else if (geometry_socket_count > 1) {
+ BKE_modifier_set_error(ob, md, "Node group can only have one geometry input");
}
}
@@ -1042,6 +1120,7 @@ static void modifyGeometry(ModifierData *md,
if (tree.has_link_cycles()) {
BKE_modifier_set_error(ctx->object, md, "Node group has cycles");
+ geometry_set.clear();
return;
}
@@ -1049,17 +1128,23 @@ static void modifyGeometry(ModifierData *md,
Span<const NodeRef *> input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput");
Span<const NodeRef *> output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput");
if (output_nodes.size() != 1) {
+ BKE_modifier_set_error(ctx->object, md, "Node group must have a single output node");
+ geometry_set.clear();
return;
}
const NodeRef &output_node = *output_nodes[0];
Span<const InputSocketRef *> group_outputs = output_node.inputs().drop_back(1);
if (group_outputs.is_empty()) {
+ BKE_modifier_set_error(ctx->object, md, "Node group must have an output socket");
+ geometry_set.clear();
return;
}
const InputSocketRef *first_output_socket = group_outputs[0];
if (first_output_socket->idname() != "NodeSocketGeometry") {
+ BKE_modifier_set_error(ctx->object, md, "Node group's first output must be a geometry");
+ geometry_set.clear();
return;
}
@@ -1073,12 +1158,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
modifyGeometry(md, ctx, geometry_set);
- if (ctx->flag & MOD_APPLY_TO_BASE_MESH) {
- /* In this case it makes sense to realize instances, otherwise in some cases there might be no
- * results when applying the modifier. */
- geometry_set = blender::bke::geometry_set_realize_mesh_for_modifier(geometry_set);
- }
-
Mesh *new_mesh = geometry_set.get_component_for_write<MeshComponent>().release();
if (new_mesh == nullptr) {
return BKE_mesh_new_nomain(0, 0, 0, 0, 0);
@@ -1093,10 +1172,196 @@ static void modifyGeometrySet(ModifierData *md,
modifyGeometry(md, ctx, *geometry_set);
}
+struct AttributeSearchData {
+ uint32_t object_session_uid;
+ char modifier_name[MAX_NAME];
+ char socket_identifier[MAX_NAME];
+ bool is_output;
+};
+/* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */
+BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, "");
+
+static NodesModifierData *get_modifier_data(Main &bmain,
+ const wmWindowManager &wm,
+ const AttributeSearchData &data)
+{
+ if (ED_screen_animation_playing(&wm)) {
+ /* Work around an issue where the attribute search exec function has stale pointers when data
+ * is reallocated when evaluating the node tree, causing a crash. This would be solved by
+ * allowing the UI search data to own arbitrary memory rather than just referencing it. */
+ return nullptr;
+ }
+
+ const Object *object = (Object *)BKE_libblock_find_session_uuid(
+ &bmain, ID_OB, data.object_session_uid);
+ if (object == nullptr) {
+ return nullptr;
+ }
+ ModifierData *md = BKE_modifiers_findby_name(object, data.modifier_name);
+ if (md == nullptr) {
+ return nullptr;
+ }
+ BLI_assert(md->type == eModifierType_Nodes);
+ return reinterpret_cast<NodesModifierData *>(md);
+}
+
+static void attribute_search_update_fn(
+ const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
+{
+ AttributeSearchData &data = *static_cast<AttributeSearchData *>(arg);
+ const NodesModifierData *nmd = get_modifier_data(*CTX_data_main(C), *CTX_wm_manager(C), data);
+ if (nmd == nullptr) {
+ return;
+ }
+ const geo_log::ModifierLog *modifier_log = static_cast<const geo_log::ModifierLog *>(
+ nmd->runtime_eval_log);
+ if (modifier_log == nullptr) {
+ return;
+ }
+ const geo_log::GeometryValueLog *geometry_log = data.is_output ?
+ modifier_log->output_geometry_log() :
+ modifier_log->input_geometry_log();
+ if (geometry_log == nullptr) {
+ return;
+ }
+
+ Span<GeometryAttributeInfo> infos = geometry_log->attributes();
+
+ /* The shared attribute search code expects a span of pointers, so convert to that. */
+ Array<const GeometryAttributeInfo *> info_ptrs(infos.size());
+ for (const int i : infos.index_range()) {
+ info_ptrs[i] = &infos[i];
+ }
+ blender::ui::attribute_search_add_items(
+ str, data.is_output, info_ptrs.as_span(), items, is_first);
+}
+
+static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
+{
+ if (item_v == nullptr) {
+ return;
+ }
+ AttributeSearchData &data = *static_cast<AttributeSearchData *>(data_v);
+ const GeometryAttributeInfo &item = *static_cast<const GeometryAttributeInfo *>(item_v);
+ const NodesModifierData *nmd = get_modifier_data(*CTX_data_main(C), *CTX_wm_manager(C), data);
+ if (nmd == nullptr) {
+ return;
+ }
+
+ const std::string attribute_prop_name = data.socket_identifier + attribute_name_suffix;
+ IDProperty &name_property = *IDP_GetPropertyFromGroup(nmd->settings.properties,
+ attribute_prop_name.c_str());
+ IDP_AssignString(&name_property, item.name.c_str(), 0);
+
+ ED_undo_push(C, "Assign Attribute Name");
+}
+
+static void add_attribute_search_button(const bContext &C,
+ uiLayout *layout,
+ const NodesModifierData &nmd,
+ PointerRNA *md_ptr,
+ const StringRefNull rna_path_attribute_name,
+ const bNodeSocket &socket,
+ const bool is_output)
+{
+ const geo_log::ModifierLog *log = static_cast<geo_log::ModifierLog *>(nmd.runtime_eval_log);
+ if (log == nullptr) {
+ uiItemR(layout, md_ptr, rna_path_attribute_name.c_str(), 0, "", ICON_NONE);
+ return;
+ }
+
+ uiBlock *block = uiLayoutGetBlock(layout);
+ uiBut *but = uiDefIconTextButR(block,
+ UI_BTYPE_SEARCH_MENU,
+ 0,
+ ICON_NONE,
+ "",
+ 0,
+ 0,
+ 10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */
+ UI_UNIT_Y,
+ md_ptr,
+ rna_path_attribute_name.c_str(),
+ 0,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ "");
+
+ const Object *object = ED_object_context(&C);
+ BLI_assert(object != nullptr);
+ if (object == nullptr) {
+ return;
+ }
+
+ AttributeSearchData *data = MEM_new<AttributeSearchData>(__func__);
+ data->object_session_uid = object->id.session_uuid;
+ STRNCPY(data->modifier_name, nmd.modifier.name);
+ STRNCPY(data->socket_identifier, socket.identifier);
+ data->is_output = is_output;
+
+ UI_but_func_search_set_results_are_suggestions(but, true);
+ UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP);
+ UI_but_func_search_set(but,
+ nullptr,
+ attribute_search_update_fn,
+ static_cast<void *>(data),
+ true,
+ nullptr,
+ attribute_search_exec_fn,
+ nullptr);
+}
+
+static void add_attribute_search_or_value_buttons(const bContext &C,
+ uiLayout *layout,
+ const NodesModifierData &nmd,
+ PointerRNA *md_ptr,
+ const bNodeSocket &socket)
+{
+ char socket_id_esc[sizeof(socket.identifier) * 2];
+ BLI_str_escape(socket_id_esc, socket.identifier, sizeof(socket_id_esc));
+ const std::string rna_path = "[\"" + std::string(socket_id_esc) + "\"]";
+ const std::string rna_path_use_attribute = "[\"" + std::string(socket_id_esc) +
+ use_attribute_suffix + "\"]";
+ const std::string rna_path_attribute_name = "[\"" + std::string(socket_id_esc) +
+ attribute_name_suffix + "\"]";
+
+ uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
+ uiLayout *name_row = uiLayoutRow(split, false);
+ uiLayoutSetAlignment(name_row, UI_LAYOUT_ALIGN_RIGHT);
+ uiItemL(name_row, socket.name, ICON_NONE);
+
+ uiLayout *row = uiLayoutRow(split, true);
+
+ PointerRNA props;
+ uiItemFullO(row,
+ "object.geometry_nodes_input_attribute_toggle",
+ "",
+ ICON_SPREADSHEET,
+ nullptr,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ &props);
+ RNA_string_set(&props, "modifier_name", nmd.modifier.name);
+ RNA_string_set(&props, "prop_path", rna_path_use_attribute.c_str());
+
+ const int use_attribute = RNA_int_get(md_ptr, rna_path_use_attribute.c_str()) != 0;
+ if (use_attribute) {
+ add_attribute_search_button(C, row, nmd, md_ptr, rna_path_attribute_name, socket, false);
+ uiItemL(row, "", ICON_BLANK1);
+ }
+ else {
+ uiItemR(row, md_ptr, rna_path.c_str(), 0, "", ICON_NONE);
+ uiItemDecoratorR(row, md_ptr, rna_path.c_str(), 0);
+ }
+}
+
/* Drawing the properties manually with #uiItemR instead of #uiDefAutoButsRNA allows using
* the node socket identifier for the property names, since they are unique, but also having
* the correct label displayed in the UI. */
-static void draw_property_for_socket(uiLayout *layout,
+static void draw_property_for_socket(const bContext &C,
+ uiLayout *layout,
NodesModifierData *nmd,
PointerRNA *bmain_ptr,
PointerRNA *md_ptr,
@@ -1145,41 +1410,26 @@ static void draw_property_for_socket(uiLayout *layout,
uiItemPointerR(layout, md_ptr, rna_path, bmain_ptr, "textures", socket.name, ICON_TEXTURE);
break;
}
+ case SOCK_IMAGE: {
+ uiItemPointerR(layout, md_ptr, rna_path, bmain_ptr, "images", socket.name, ICON_IMAGE);
+ break;
+ }
default: {
if (input_has_attribute_toggle(*nmd->node_group, socket_index)) {
- const std::string rna_path_use_attribute = "[\"" + std::string(socket_id_esc) +
- use_attribute_suffix + "\"]";
- const std::string rna_path_attribute_name = "[\"" + std::string(socket_id_esc) +
- attribute_name_suffix + "\"]";
-
- uiLayout *row = uiLayoutRow(layout, true);
- const int use_attribute = RNA_int_get(md_ptr, rna_path_use_attribute.c_str()) != 0;
- if (use_attribute) {
- uiItemR(row, md_ptr, rna_path_attribute_name.c_str(), 0, socket.name, ICON_NONE);
- }
- else {
- uiItemR(row, md_ptr, rna_path, 0, socket.name, ICON_NONE);
- }
- PointerRNA props;
- uiItemFullO(row,
- "object.geometry_nodes_input_attribute_toggle",
- "",
- ICON_SPREADSHEET,
- nullptr,
- WM_OP_INVOKE_DEFAULT,
- 0,
- &props);
- RNA_string_set(&props, "modifier_name", nmd->modifier.name);
- RNA_string_set(&props, "prop_path", rna_path_use_attribute.c_str());
+ add_attribute_search_or_value_buttons(C, layout, *nmd, md_ptr, socket);
}
else {
- uiItemR(layout, md_ptr, rna_path, 0, socket.name, ICON_NONE);
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayoutSetPropDecorate(row, true);
+ uiItemR(row, md_ptr, rna_path, 0, socket.name, ICON_NONE);
}
}
}
}
-static void draw_property_for_output_socket(uiLayout *layout,
+static void draw_property_for_output_socket(const bContext &C,
+ uiLayout *layout,
+ const NodesModifierData &nmd,
PointerRNA *md_ptr,
const bNodeSocket &socket)
{
@@ -1188,7 +1438,13 @@ static void draw_property_for_output_socket(uiLayout *layout,
const std::string rna_path_attribute_name = "[\"" + StringRef(socket_id_esc) +
attribute_name_suffix + "\"]";
- uiItemR(layout, md_ptr, rna_path_attribute_name.c_str(), 0, socket.name, ICON_NONE);
+ uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
+ uiLayout *name_row = uiLayoutRow(split, false);
+ uiLayoutSetAlignment(name_row, UI_LAYOUT_ALIGN_RIGHT);
+ uiItemL(name_row, socket.name, ICON_NONE);
+
+ uiLayout *row = uiLayoutRow(split, true);
+ add_attribute_search_button(C, row, nmd, md_ptr, rna_path_attribute_name, socket, true);
}
static void panel_draw(const bContext *C, Panel *panel)
@@ -1200,7 +1456,9 @@ static void panel_draw(const bContext *C, Panel *panel)
NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, true);
+ /* Decorators are added manually for supported properties because the
+ * attribute/value toggle requires a manually built layout anyway. */
+ uiLayoutSetPropDecorate(layout, false);
uiTemplateID(layout,
C,
@@ -1219,7 +1477,7 @@ static void panel_draw(const bContext *C, Panel *panel)
int socket_index;
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &nmd->node_group->inputs, socket_index) {
- draw_property_for_socket(layout, nmd, &bmain_ptr, ptr, *socket, socket_index);
+ draw_property_for_socket(*C, layout, nmd, &bmain_ptr, ptr, *socket, socket_index);
}
}
@@ -1241,7 +1499,7 @@ static void panel_draw(const bContext *C, Panel *panel)
if (has_legacy_node) {
uiLayout *row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_("Node tree has legacy node"), ICON_ERROR);
+ uiItemL(row, TIP_("Node tree has legacy node"), ICON_ERROR);
uiLayout *sub = uiLayoutRow(row, false);
uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
uiItemO(sub, "", ICON_VIEWZOOM, "NODE_OT_geometry_node_view_legacy");
@@ -1250,7 +1508,7 @@ static void panel_draw(const bContext *C, Panel *panel)
modifier_panel_end(layout, ptr);
}
-static void output_attribute_panel_draw(const bContext *UNUSED(C), Panel *panel)
+static void output_attribute_panel_draw(const bContext *C, Panel *panel)
{
uiLayout *layout = panel->layout;
@@ -1260,13 +1518,18 @@ static void output_attribute_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, true);
+ bool has_output_attribute = false;
if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) {
LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->outputs) {
if (socket_type_has_attribute_toggle(*socket)) {
- draw_property_for_output_socket(layout, ptr, *socket);
+ has_output_attribute = true;
+ draw_property_for_output_socket(*C, layout, *nmd, ptr, *socket);
}
}
}
+ if (!has_output_attribute) {
+ uiItemL(layout, TIP_("No group output attributes connected"), ICON_INFO);
+ }
}
static void panelRegister(ARegionType *region_type)
@@ -1361,7 +1624,7 @@ ModifierTypeInfo modifierType_Nodes = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepsgraph */ updateDepsgraph,
- /* dependsOnTime */ nullptr,
+ /* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ nullptr,
/* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ foreachTexLink,
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index c5213dc304b..5362d86a87f 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -16,8 +16,10 @@
#include "MOD_nodes_evaluator.hh"
+#include "BKE_type_conversions.hh"
+
#include "NOD_geometry_exec.hh"
-#include "NOD_type_conversions.hh"
+#include "NOD_socket_declarations.hh"
#include "DEG_depsgraph_query.h"
@@ -34,13 +36,17 @@
#include "BLI_task.hh"
#include "BLI_vector_set.hh"
+#include <chrono>
+
namespace blender::modifiers::geometry_nodes {
using fn::CPPType;
using fn::Field;
-using fn::FieldCPPType;
using fn::GField;
using fn::GValueMap;
+using fn::GVArray;
+using fn::ValueOrField;
+using fn::ValueOrFieldCPPType;
using nodes::GeoNodeExecParams;
using namespace fn::multi_function_types;
@@ -60,31 +66,55 @@ struct SingleInputValue {
void *value = nullptr;
};
-struct MultiInputValueItem {
+struct MultiInputValue {
/**
- * The socket where this value is coming from. This is required to sort the inputs correctly
- * based on the link order later on.
+ * Ordered sockets connected to this multi-input.
*/
- DSocket origin;
+ Vector<DSocket> origins;
/**
- * Should only be null directly after construction. After that it should always point to a value
- * of the correct type.
+ * A value for every origin socket. The order is determined by #origins.
+ * Note, the same origin can occur multiple times. However, it is guaranteed that values coming
+ * from the same origin have the same value (the pointer is different, but they point to values
+ * that would compare equal).
*/
- void *value = nullptr;
-};
-
-struct MultiInputValue {
+ Vector<void *> values;
/**
- * Collection of all the inputs that have been provided already. Note, the same origin can occur
- * multiple times. However, it is guaranteed that if two items have the same origin, they will
- * also have the same value (the pointer is different, but they point to values that would
- * compare equal).
+ * Number of non-null values.
*/
- Vector<MultiInputValueItem> items;
- /**
- * Number of items that need to be added until all inputs have been provided.
- */
- int expected_size = 0;
+ int provided_value_count = 0;
+
+ bool all_values_available() const
+ {
+ return this->missing_values() == 0;
+ }
+
+ int missing_values() const
+ {
+ return this->values.size() - this->provided_value_count;
+ }
+
+ void add_value(const DSocket origin, void *value)
+ {
+ const int index = this->find_available_index(origin);
+ this->values[index] = value;
+ this->provided_value_count++;
+ }
+
+ private:
+ int find_available_index(DSocket origin) const
+ {
+ for (const int i : origins.index_range()) {
+ if (values[i] != nullptr) {
+ continue;
+ }
+ if (origins[i] != origin) {
+ continue;
+ }
+ return i;
+ }
+ BLI_assert_unreachable();
+ return -1;
+ }
};
struct InputState {
@@ -125,6 +155,12 @@ struct InputState {
* changed by others anymore.
*/
bool was_ready_for_execution = false;
+
+ /**
+ * True when this input has to be computed for logging/debugging purposes, regardless of whether
+ * it is needed for some output.
+ */
+ bool force_compute = false;
};
struct OutputState {
@@ -199,9 +235,10 @@ struct NodeState {
MutableSpan<OutputState> outputs;
/**
- * Nodes that don't support laziness have some special handling the first time they are executed.
+ * Most nodes have inputs that are always required. Those have special handling to avoid an extra
+ * call to the node execution function.
*/
- bool non_lazy_node_is_initialized = false;
+ bool non_lazy_inputs_handled = false;
/**
* Used to check that nodes that don't support laziness do not run more than once.
@@ -302,10 +339,10 @@ class LockedNode : NonCopyable, NonMovable {
static const CPPType *get_socket_cpp_type(const SocketRef &socket)
{
const bNodeSocketType *typeinfo = socket.typeinfo();
- if (typeinfo->get_geometry_nodes_cpp_type == nullptr) {
+ if (typeinfo->geometry_nodes_cpp_type == nullptr) {
return nullptr;
}
- const CPPType *type = typeinfo->get_geometry_nodes_cpp_type();
+ const CPPType *type = typeinfo->geometry_nodes_cpp_type;
if (type == nullptr) {
return nullptr;
}
@@ -321,30 +358,55 @@ static const CPPType *get_socket_cpp_type(const DSocket socket)
return get_socket_cpp_type(*socket.socket_ref());
}
-static void get_socket_value(const SocketRef &socket, void *r_value)
+/**
+ * \note This is not supposed to be a long term solution. Eventually we want that nodes can
+ * specify more complex defaults (other than just single values) in their socket declarations.
+ */
+static bool get_implicit_socket_input(const SocketRef &socket, void *r_value)
{
- const bNodeSocket &bsocket = *socket.bsocket();
- /* This is not supposed to be a long term solution. Eventually we want that nodes can specify
- * more complex defaults (other than just single values) in their socket declarations. */
- if (bsocket.flag & SOCK_HIDE_VALUE) {
+ const NodeRef &node = socket.node();
+ const nodes::NodeDeclaration *node_declaration = node.declaration();
+ if (node_declaration == nullptr) {
+ return false;
+ }
+ const nodes::SocketDeclaration &socket_declaration = *node_declaration->inputs()[socket.index()];
+ if (socket_declaration.input_field_type() == nodes::InputSocketFieldType::Implicit) {
const bNode &bnode = *socket.bnode();
- if (bsocket.type == SOCK_VECTOR) {
- if (ELEM(bnode.type,
- GEO_NODE_SET_POSITION,
- SH_NODE_TEX_NOISE,
- GEO_NODE_MESH_TO_POINTS,
- GEO_NODE_PROXIMITY)) {
- new (r_value) Field<float3>(bke::AttributeFieldInput::Create<float3>("position"));
- return;
+ if (socket.typeinfo()->type == SOCK_VECTOR) {
+ if (bnode.type == GEO_NODE_SET_CURVE_HANDLES) {
+ StringRef side = ((NodeGeometrySetCurveHandlePositions *)bnode.storage)->mode ==
+ GEO_NODE_CURVE_HANDLE_LEFT ?
+ "handle_left" :
+ "handle_right";
+ new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>(side));
+ return true;
}
+ if (bnode.type == GEO_NODE_EXTRUDE_MESH) {
+ new (r_value)
+ ValueOrField<float3>(Field<float3>(std::make_shared<bke::NormalFieldInput>()));
+ return true;
+ }
+ new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>("position"));
+ return true;
}
- else if (bsocket.type == SOCK_INT) {
+ if (socket.typeinfo()->type == SOCK_INT) {
if (ELEM(bnode.type, FN_NODE_RANDOM_VALUE, GEO_NODE_INSTANCE_ON_POINTS)) {
- new (r_value) Field<int>(std::make_shared<fn::IndexFieldInput>());
- return;
+ new (r_value)
+ ValueOrField<int>(Field<int>(std::make_shared<bke::IDAttributeFieldInput>()));
+ return true;
}
+ new (r_value) ValueOrField<int>(Field<int>(std::make_shared<fn::IndexFieldInput>()));
+ return true;
}
}
+ return false;
+}
+
+static void get_socket_value(const SocketRef &socket, void *r_value)
+{
+ if (get_implicit_socket_input(socket, r_value)) {
+ return;
+ }
const bNodeSocketType *typeinfo = socket.typeinfo();
typeinfo->get_geometry_nodes_cpp_value(*socket.bsocket(), r_value);
@@ -355,14 +417,23 @@ static bool node_supports_laziness(const DNode node)
return node->typeinfo()->geometry_node_execute_supports_laziness;
}
+struct NodeTaskRunState {
+ /** The node that should be run on the same thread after the current node finished. */
+ DNode next_node_to_run;
+};
+
/** Implements the callbacks that might be called when a node is executed. */
class NodeParamsProvider : public nodes::GeoNodeExecParamsProvider {
private:
GeometryNodesEvaluator &evaluator_;
NodeState &node_state_;
+ NodeTaskRunState *run_state_;
public:
- NodeParamsProvider(GeometryNodesEvaluator &evaluator, DNode dnode, NodeState &node_state);
+ NodeParamsProvider(GeometryNodesEvaluator &evaluator,
+ DNode dnode,
+ NodeState &node_state,
+ NodeTaskRunState *run_state);
bool can_get_input(StringRef identifier) const override;
bool can_set_output(StringRef identifier) const override;
@@ -376,6 +447,8 @@ class NodeParamsProvider : public nodes::GeoNodeExecParamsProvider {
bool lazy_require_input(StringRef identifier) override;
bool lazy_output_is_required(StringRef identifier) const override;
+
+ void set_default_remaining_outputs() override;
};
class GeometryNodesEvaluator {
@@ -407,7 +480,7 @@ class GeometryNodesEvaluator {
TaskPool *task_pool_ = nullptr;
GeometryNodesEvaluationParams &params_;
- const blender::nodes::DataTypeConversions &conversions_;
+ const blender::bke::DataTypeConversions &conversions_;
friend NodeParamsProvider;
@@ -415,7 +488,7 @@ class GeometryNodesEvaluator {
GeometryNodesEvaluator(GeometryNodesEvaluationParams &params)
: outer_allocator_(params.allocator),
params_(params),
- conversions_(blender::nodes::get_implicit_type_conversions())
+ conversions_(blender::bke::get_implicit_type_conversions())
{
}
@@ -477,6 +550,14 @@ class GeometryNodesEvaluator {
this->initialize_node_state(item.node, *item.state, allocator);
}
});
+
+ /* Mark input sockets that have to be computed. */
+ for (const DSocket &socket : params_.force_compute_sockets) {
+ NodeState &node_state = *node_states_.lookup_key_as(socket.node()).state;
+ if (socket->is_input()) {
+ node_state.inputs[socket->index()].force_compute = true;
+ }
+ }
}
void initialize_node_state(const DNode node, NodeState &node_state, LinearAllocator<> &allocator)
@@ -505,13 +586,14 @@ class GeometryNodesEvaluator {
/* Construct the correct struct that can hold the input(s). */
if (socket->is_multi_input_socket()) {
input_state.value.multi = allocator.construct<MultiInputValue>().release();
+ MultiInputValue &multi_value = *input_state.value.multi;
/* Count how many values should be added until the socket is complete. */
- socket.foreach_origin_socket(
- [&](DSocket UNUSED(origin)) { input_state.value.multi->expected_size++; });
+ socket.foreach_origin_socket([&](DSocket origin) { multi_value.origins.append(origin); });
/* If no links are connected, we do read the value from socket itself. */
- if (input_state.value.multi->expected_size == 0) {
- input_state.value.multi->expected_size = 1;
+ if (multi_value.origins.is_empty()) {
+ multi_value.origins.append(socket);
}
+ multi_value.values.resize(multi_value.origins.size(), nullptr);
}
else {
input_state.value.single = allocator.construct<SingleInputValue>().release();
@@ -534,15 +616,15 @@ class GeometryNodesEvaluator {
}
/* Count the number of potential users for this socket. */
socket.foreach_target_socket(
- [&, this](const DInputSocket target_socket) {
+ [&, this](const DInputSocket target_socket,
+ const DOutputSocket::TargetSocketPathInfo &UNUSED(path_info)) {
const DNode target_node = target_socket.node();
if (!this->node_states_.contains_as(target_node)) {
/* The target node is not computed because it is not computed to the output. */
return;
}
output_state.potential_users += 1;
- },
- {});
+ });
if (output_state.potential_users == 0) {
/* If it does not have any potential users, it is unused. It might become required again in
* `schedule_initial_nodes`. */
@@ -572,8 +654,10 @@ class GeometryNodesEvaluator {
const InputSocketRef &socket_ref = node->input(i);
if (socket_ref.is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- for (MultiInputValueItem &item : multi_value.items) {
- input_state.type->destruct(item.value);
+ for (void *value : multi_value.values) {
+ if (value != nullptr) {
+ input_state.type->destruct(value);
+ }
}
multi_value.~MultiInputValue();
}
@@ -606,7 +690,7 @@ class GeometryNodesEvaluator {
value.destruct();
continue;
}
- this->forward_output(socket, value);
+ this->forward_output(socket, value, nullptr);
}
}
@@ -615,7 +699,7 @@ class GeometryNodesEvaluator {
for (const DInputSocket &socket : params_.output_sockets) {
const DNode node = socket.node();
NodeState &node_state = this->get_node_state(node);
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, nullptr, [&](LockedNode &locked_node) {
/* Setting an input as required will schedule any linked node. */
this->set_input_required(locked_node, socket);
});
@@ -623,7 +707,7 @@ class GeometryNodesEvaluator {
for (const DSocket socket : params_.force_compute_sockets) {
const DNode node = socket.node();
NodeState &node_state = this->get_node_state(node);
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, nullptr, [&](LockedNode &locked_node) {
if (socket->is_input()) {
this->set_input_required(locked_node, DInputSocket(socket));
}
@@ -668,12 +752,24 @@ class GeometryNodesEvaluator {
{
void *user_data = BLI_task_pool_user_data(task_pool);
GeometryNodesEvaluator &evaluator = *(GeometryNodesEvaluator *)user_data;
- const NodeWithState *node_with_state = (const NodeWithState *)task_data;
-
- evaluator.node_task_run(node_with_state->node, *node_with_state->state);
+ const NodeWithState *root_node_with_state = (const NodeWithState *)task_data;
+
+ /* First, the node provided by the task pool is executed. During the execution other nodes
+ * might be scheduled. One of those nodes is not added to the task pool but is executed in the
+ * loop below directly. This has two main benefits:
+ * - Fewer round trips through the task pool which add threading overhead.
+ * - Helps with cpu cache efficiency, because a thread is more likely to process data that it
+ * has processed shortly before.
+ */
+ DNode next_node_to_run = root_node_with_state->node;
+ while (next_node_to_run) {
+ NodeTaskRunState run_state;
+ evaluator.node_task_run(next_node_to_run, &run_state);
+ next_node_to_run = run_state.next_node_to_run;
+ }
}
- void node_task_run(const DNode node, NodeState &node_state)
+ void node_task_run(const DNode node, NodeTaskRunState *run_state)
{
/* These nodes are sometimes scheduled. We could also check for them in other places, but
* it's the easiest to do it here. */
@@ -681,21 +777,25 @@ class GeometryNodesEvaluator {
return;
}
- const bool do_execute_node = this->node_task_preprocessing(node, node_state);
+ NodeState &node_state = *node_states_.lookup_key_as(node).state;
+
+ const bool do_execute_node = this->node_task_preprocessing(node, node_state, run_state);
/* Only execute the node if all prerequisites are met. There has to be an output that is
* required and all required inputs have to be provided already. */
if (do_execute_node) {
- this->execute_node(node, node_state);
+ this->execute_node(node, node_state, run_state);
}
- this->node_task_postprocessing(node, node_state);
+ this->node_task_postprocessing(node, node_state, do_execute_node, run_state);
}
- bool node_task_preprocessing(const DNode node, NodeState &node_state)
+ bool node_task_preprocessing(const DNode node,
+ NodeState &node_state,
+ NodeTaskRunState *run_state)
{
bool do_execute_node = false;
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
BLI_assert(node_state.schedule_state == NodeScheduleState::Scheduled);
node_state.schedule_state = NodeScheduleState::Running;
@@ -707,12 +807,12 @@ class GeometryNodesEvaluator {
if (!this->prepare_node_outputs_for_execution(locked_node)) {
return;
}
- /* Initialize nodes that don't support laziness. This is done after at least one output is
+ /* Initialize inputs that don't support laziness. This is done after at least one output is
* required and before we check that all required inputs are provided. This reduces the
* number of "round-trips" through the task pool by one for most nodes. */
- if (!node_state.non_lazy_node_is_initialized && !node_supports_laziness(node)) {
- this->initialize_non_lazy_node(locked_node);
- node_state.non_lazy_node_is_initialized = true;
+ if (!node_state.non_lazy_inputs_handled) {
+ this->require_non_lazy_inputs(locked_node);
+ node_state.non_lazy_inputs_handled = true;
}
/* Prepare inputs and check if all required inputs are provided. */
if (!this->prepare_node_inputs_for_execution(locked_node)) {
@@ -723,7 +823,8 @@ class GeometryNodesEvaluator {
return do_execute_node;
}
- /* A node is finished when it has computed all outputs that may be used. */
+ /* A node is finished when it has computed all outputs that may be used have been computed and
+ * when no input is still forced to be computed. */
bool finish_node_if_possible(LockedNode &locked_node)
{
if (locked_node.node_state.node_has_finished) {
@@ -732,35 +833,41 @@ class GeometryNodesEvaluator {
}
/* Check if there is any output that might be used but has not been computed yet. */
- bool has_remaining_output = false;
for (OutputState &output_state : locked_node.node_state.outputs) {
if (output_state.has_been_computed) {
continue;
}
if (output_state.output_usage != ValueUsage::Unused) {
- has_remaining_output = true;
- break;
+ return false;
}
}
- if (!has_remaining_output) {
- /* If there are no remaining outputs, all the inputs can be destructed and/or can become
- * unused. This can also trigger a chain reaction where nodes to the left become finished
- * too. */
- for (const int i : locked_node.node->inputs().index_range()) {
- const DInputSocket socket = locked_node.node.input(i);
- InputState &input_state = locked_node.node_state.inputs[i];
- if (input_state.usage == ValueUsage::Maybe) {
- this->set_input_unused(locked_node, socket);
- }
- else if (input_state.usage == ValueUsage::Required) {
- /* The value was required, so it cannot become unused. However, we can destruct the
- * value. */
- this->destruct_input_value_if_exists(locked_node, socket);
+
+ /* Check if there is an input that still has to be computed. */
+ for (InputState &input_state : locked_node.node_state.inputs) {
+ if (input_state.force_compute) {
+ if (!input_state.was_ready_for_execution) {
+ return false;
}
}
- locked_node.node_state.node_has_finished = true;
}
- return locked_node.node_state.node_has_finished;
+
+ /* If there are no remaining outputs, all the inputs can be destructed and/or can become
+ * unused. This can also trigger a chain reaction where nodes to the left become finished
+ * too. */
+ for (const int i : locked_node.node->inputs().index_range()) {
+ const DInputSocket socket = locked_node.node.input(i);
+ InputState &input_state = locked_node.node_state.inputs[i];
+ if (input_state.usage == ValueUsage::Maybe) {
+ this->set_input_unused(locked_node, socket);
+ }
+ else if (input_state.usage == ValueUsage::Required) {
+ /* The value was required, so it cannot become unused. However, we can destruct the
+ * value. */
+ this->destruct_input_value_if_exists(locked_node, socket);
+ }
+ }
+ locked_node.node_state.node_has_finished = true;
+ return true;
}
bool prepare_node_outputs_for_execution(LockedNode &locked_node)
@@ -779,17 +886,27 @@ class GeometryNodesEvaluator {
return execution_is_necessary;
}
- void initialize_non_lazy_node(LockedNode &locked_node)
+ void require_non_lazy_inputs(LockedNode &locked_node)
+ {
+ this->foreach_non_lazy_input(locked_node, [&](const DInputSocket socket) {
+ this->set_input_required(locked_node, socket);
+ });
+ }
+
+ void foreach_non_lazy_input(LockedNode &locked_node, FunctionRef<void(DInputSocket socket)> fn)
{
+ if (node_supports_laziness(locked_node.node)) {
+ /* In the future only some of the inputs may support laziness. */
+ return;
+ }
+ /* Nodes that don't support laziness require all inputs. */
for (const int i : locked_node.node->inputs().index_range()) {
InputState &input_state = locked_node.node_state.inputs[i];
if (input_state.type == nullptr) {
/* Ignore unavailable/non-data sockets. */
continue;
}
- /* Nodes that don't support laziness require all inputs. */
- const DInputSocket input_socket = locked_node.node.input(i);
- this->set_input_required(locked_node, input_socket);
+ fn(locked_node.node.input(i));
}
}
@@ -818,7 +935,7 @@ class GeometryNodesEvaluator {
if (socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
/* Checks if all the linked sockets have been provided already. */
- if (multi_value.items.size() == multi_value.expected_size) {
+ if (multi_value.all_values_available()) {
input_state.was_ready_for_execution = true;
}
else if (is_required) {
@@ -847,7 +964,7 @@ class GeometryNodesEvaluator {
* Actually execute the node. All the required inputs are available and at least one output is
* required.
*/
- void execute_node(const DNode node, NodeState &node_state)
+ void execute_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
{
const bNode &bnode = *node->bnode();
@@ -861,40 +978,49 @@ class GeometryNodesEvaluator {
/* Use the geometry node execute callback if it exists. */
if (bnode.typeinfo->geometry_node_execute != nullptr) {
- this->execute_geometry_node(node, node_state);
+ this->execute_geometry_node(node, node_state, run_state);
return;
}
/* Use the multi-function implementation if it exists. */
- const MultiFunction *multi_function = params_.mf_by_node->try_get(node);
- if (multi_function != nullptr) {
- this->execute_multi_function_node(node, *multi_function, node_state);
+ const nodes::NodeMultiFunctions::Item &fn_item = params_.mf_by_node->try_get(node);
+ if (fn_item.fn != nullptr) {
+ this->execute_multi_function_node(node, fn_item, node_state, run_state);
return;
}
- this->execute_unknown_node(node, node_state);
+ this->execute_unknown_node(node, node_state, run_state);
}
- void execute_geometry_node(const DNode node, NodeState &node_state)
+ void execute_geometry_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
{
const bNode &bnode = *node->bnode();
- NodeParamsProvider params_provider{*this, node, node_state};
+ NodeParamsProvider params_provider{*this, node, node_state, run_state};
GeoNodeExecParams params{params_provider};
if (node->idname().find("Legacy") != StringRef::not_found) {
params.error_message_add(geo_log::NodeWarningType::Legacy,
TIP_("Legacy node will be removed before Blender 4.0"));
}
+ using Clock = std::chrono::steady_clock;
+ Clock::time_point begin = Clock::now();
bnode.typeinfo->geometry_node_execute(params);
+ Clock::time_point end = Clock::now();
+ const std::chrono::microseconds duration =
+ std::chrono::duration_cast<std::chrono::microseconds>(end - begin);
+ if (params_.geo_logger != nullptr) {
+ params_.geo_logger->local().log_execution_time(node, duration);
+ }
}
void execute_multi_function_node(const DNode node,
- const MultiFunction &fn,
- NodeState &node_state)
+ const nodes::NodeMultiFunctions::Item &fn_item,
+ NodeState &node_state,
+ NodeTaskRunState *run_state)
{
if (node->idname().find("Legacy") != StringRef::not_found) {
/* Create geometry nodes params just for creating an error message. */
- NodeParamsProvider params_provider{*this, node, node_state};
+ NodeParamsProvider params_provider{*this, node, node_state, run_state};
GeoNodeExecParams params{params_provider};
params.error_message_add(geo_log::NodeWarningType::Legacy,
TIP_("Legacy node will be removed before Blender 4.0"));
@@ -902,8 +1028,9 @@ class GeometryNodesEvaluator {
LinearAllocator<> &allocator = local_allocators_.local();
- /* Prepare the inputs for the multi function. */
- Vector<GField> input_fields;
+ bool any_input_is_field = false;
+ Vector<const void *, 16> input_values;
+ Vector<const ValueOrFieldCPPType *, 16> input_types;
for (const int i : node->inputs().index_range()) {
const InputSocketRef &socket_ref = node->input(i);
if (!socket_ref.is_available()) {
@@ -914,12 +1041,48 @@ class GeometryNodesEvaluator {
BLI_assert(input_state.was_ready_for_execution);
SingleInputValue &single_value = *input_state.value.single;
BLI_assert(single_value.value != nullptr);
- input_fields.append(std::move(*(GField *)single_value.value));
+ const ValueOrFieldCPPType &field_cpp_type = static_cast<const ValueOrFieldCPPType &>(
+ *input_state.type);
+ input_values.append(single_value.value);
+ input_types.append(&field_cpp_type);
+ if (field_cpp_type.is_field(single_value.value)) {
+ any_input_is_field = true;
+ }
+ }
+
+ if (any_input_is_field) {
+ this->execute_multi_function_node__field(
+ node, fn_item, node_state, allocator, input_values, input_types, run_state);
+ }
+ else {
+ this->execute_multi_function_node__value(
+ node, *fn_item.fn, node_state, allocator, input_values, input_types, run_state);
+ }
+ }
+
+ void execute_multi_function_node__field(const DNode node,
+ const nodes::NodeMultiFunctions::Item &fn_item,
+ NodeState &node_state,
+ LinearAllocator<> &allocator,
+ Span<const void *> input_values,
+ Span<const ValueOrFieldCPPType *> input_types,
+ NodeTaskRunState *run_state)
+ {
+ Vector<GField> input_fields;
+ for (const int i : input_values.index_range()) {
+ const void *input_value_or_field = input_values[i];
+ const ValueOrFieldCPPType &field_cpp_type = *input_types[i];
+ input_fields.append(field_cpp_type.as_field(input_value_or_field));
}
- auto operation = std::make_shared<fn::FieldOperation>(fn, std::move(input_fields));
+ std::shared_ptr<fn::FieldOperation> operation;
+ if (fn_item.owned_fn) {
+ operation = std::make_shared<fn::FieldOperation>(fn_item.owned_fn, std::move(input_fields));
+ }
+ else {
+ operation = std::make_shared<fn::FieldOperation>(*fn_item.fn, std::move(input_fields));
+ }
- /* Forward outputs. */
int output_index = 0;
for (const int i : node->outputs().index_range()) {
const OutputSocketRef &socket_ref = node->output(i);
@@ -928,17 +1091,70 @@ class GeometryNodesEvaluator {
}
OutputState &output_state = node_state.outputs[i];
const DOutputSocket socket{node.context(), &socket_ref};
- const CPPType *cpp_type = get_socket_cpp_type(socket_ref);
+ const ValueOrFieldCPPType *cpp_type = static_cast<const ValueOrFieldCPPType *>(
+ get_socket_cpp_type(socket_ref));
GField new_field{operation, output_index};
- new_field = fn::make_field_constant_if_possible(std::move(new_field));
- GField &field_to_forward = *allocator.construct<GField>(std::move(new_field)).release();
- this->forward_output(socket, {cpp_type, &field_to_forward});
+ void *buffer = allocator.allocate(cpp_type->size(), cpp_type->alignment());
+ cpp_type->construct_from_field(buffer, std::move(new_field));
+ this->forward_output(socket, {cpp_type, buffer}, run_state);
output_state.has_been_computed = true;
output_index++;
}
}
- void execute_unknown_node(const DNode node, NodeState &node_state)
+ void execute_multi_function_node__value(const DNode node,
+ const MultiFunction &fn,
+ NodeState &node_state,
+ LinearAllocator<> &allocator,
+ Span<const void *> input_values,
+ Span<const ValueOrFieldCPPType *> input_types,
+ NodeTaskRunState *run_state)
+ {
+ MFParamsBuilder params{fn, 1};
+ for (const int i : input_values.index_range()) {
+ const void *input_value_or_field = input_values[i];
+ const ValueOrFieldCPPType &field_cpp_type = *input_types[i];
+ const CPPType &base_type = field_cpp_type.base_type();
+ const void *input_value = field_cpp_type.get_value_ptr(input_value_or_field);
+ params.add_readonly_single_input(GVArray::ForSingleRef(base_type, 1, input_value));
+ }
+
+ Vector<GMutablePointer, 16> output_buffers;
+ for (const int i : node->outputs().index_range()) {
+ const DOutputSocket socket = node.output(i);
+ if (!socket->is_available()) {
+ output_buffers.append({});
+ continue;
+ }
+ const ValueOrFieldCPPType *value_or_field_type = static_cast<const ValueOrFieldCPPType *>(
+ get_socket_cpp_type(socket));
+ const CPPType &base_type = value_or_field_type->base_type();
+ void *value_or_field_buffer = allocator.allocate(value_or_field_type->size(),
+ value_or_field_type->alignment());
+ value_or_field_type->default_construct(value_or_field_buffer);
+ void *value_buffer = value_or_field_type->get_value_ptr(value_or_field_buffer);
+ base_type.destruct(value_buffer);
+ params.add_uninitialized_single_output(GMutableSpan{base_type, value_buffer, 1});
+ output_buffers.append({value_or_field_type, value_or_field_buffer});
+ }
+
+ MFContextBuilder context;
+ fn.call(IndexRange(1), params, context);
+
+ for (const int i : output_buffers.index_range()) {
+ GMutablePointer buffer = output_buffers[i];
+ if (buffer.get() == nullptr) {
+ continue;
+ }
+ const DOutputSocket socket = node.output(i);
+ this->forward_output(socket, buffer, run_state);
+
+ OutputState &output_state = node_state.outputs[i];
+ output_state.has_been_computed = true;
+ }
+ }
+
+ void execute_unknown_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
{
LinearAllocator<> &allocator = local_allocators_.local();
for (const OutputSocketRef *socket : node->outputs()) {
@@ -955,13 +1171,16 @@ class GeometryNodesEvaluator {
output_state.has_been_computed = true;
void *buffer = allocator.allocate(type->size(), type->alignment());
this->construct_default_value(*type, buffer);
- this->forward_output({node.context(), socket}, {*type, buffer});
+ this->forward_output({node.context(), socket}, {*type, buffer}, run_state);
}
}
- void node_task_postprocessing(const DNode node, NodeState &node_state)
+ void node_task_postprocessing(const DNode node,
+ NodeState &node_state,
+ bool was_executed,
+ NodeTaskRunState *run_state)
{
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
const bool node_has_finished = this->finish_node_if_possible(locked_node);
const bool reschedule_requested = node_state.schedule_state ==
NodeScheduleState::RunningAndRescheduled;
@@ -970,8 +1189,9 @@ class GeometryNodesEvaluator {
/* Either the node rescheduled itself or another node tried to schedule it while it ran. */
this->schedule_node(locked_node);
}
-
- this->assert_expected_outputs_have_been_computed(locked_node);
+ if (was_executed) {
+ this->assert_expected_outputs_have_been_computed(locked_node);
+ }
});
}
@@ -1041,10 +1261,9 @@ class GeometryNodesEvaluator {
/**
* Load the required input from the socket or trigger nodes to the left to compute the value.
- * When this function is called, the node will always be executed again eventually (either
- * immediately, or when all required inputs have been computed by other nodes).
+ * \return True when the node will be triggered by another node again when the value is computed.
*/
- void set_input_required(LockedNode &locked_node, const DInputSocket input_socket)
+ bool set_input_required(LockedNode &locked_node, const DInputSocket input_socket)
{
BLI_assert(locked_node.node == input_socket.node());
InputState &input_state = locked_node.node_state.inputs[input_socket->index()];
@@ -1052,25 +1271,22 @@ class GeometryNodesEvaluator {
/* Value set as unused cannot become used again. */
BLI_assert(input_state.usage != ValueUsage::Unused);
- if (input_state.usage == ValueUsage::Required) {
- /* The value is already required, but the node might expect to be evaluated again. */
- this->schedule_node(locked_node);
- /* Returning here also ensure that the code below is executed at most once per input. */
- return;
+ if (input_state.was_ready_for_execution) {
+ return false;
}
- input_state.usage = ValueUsage::Required;
- if (input_state.was_ready_for_execution) {
- /* The value was already ready, but the node might expect to be evaluated again. */
- this->schedule_node(locked_node);
- return;
+ if (input_state.usage == ValueUsage::Required) {
+ /* If the input was not ready for execution but is required, the node will be triggered again
+ * once the input has been computed. */
+ return true;
}
+ input_state.usage = ValueUsage::Required;
/* Count how many values still have to be added to this input until it is "complete". */
int missing_values = 0;
if (input_socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- missing_values = multi_value.expected_size - multi_value.items.size();
+ missing_values = multi_value.missing_values();
}
else {
SingleInputValue &single_value = *input_state.value.single;
@@ -1079,9 +1295,7 @@ class GeometryNodesEvaluator {
}
}
if (missing_values == 0) {
- /* The input is fully available already, but the node might expect to be evaluated again. */
- this->schedule_node(locked_node);
- return;
+ return false;
}
/* Increase the total number of missing required inputs. This ensures that the node will be
* scheduled correctly when all inputs have been provided. */
@@ -1096,30 +1310,28 @@ class GeometryNodesEvaluator {
/* If there are no origin sockets, just load the value from the socket directly. */
this->load_unlinked_input_value(locked_node, input_socket, input_state, input_socket);
locked_node.node_state.missing_required_inputs -= 1;
- this->schedule_node(locked_node);
- return;
+ return false;
}
- bool will_be_triggered_by_other_node = false;
- for (const DSocket origin_socket : origin_sockets) {
+ bool requested_from_other_node = false;
+ for (const DSocket &origin_socket : origin_sockets) {
if (origin_socket->is_input()) {
/* Load the value directly from the origin socket. In most cases this is an unlinked
* group input. */
this->load_unlinked_input_value(locked_node, input_socket, input_state, origin_socket);
locked_node.node_state.missing_required_inputs -= 1;
- this->schedule_node(locked_node);
}
else {
/* The value has not been computed yet, so when it will be forwarded by another node, this
* node will be triggered. */
- will_be_triggered_by_other_node = true;
-
+ requested_from_other_node = true;
locked_node.delayed_required_outputs.append(DOutputSocket(origin_socket));
}
}
/* If this node will be triggered by another node, we don't have to schedule it now. */
- if (!will_be_triggered_by_other_node) {
- this->schedule_node(locked_node);
+ if (requested_from_other_node) {
+ return true;
}
+ return false;
}
void set_input_unused(LockedNode &locked_node, const DInputSocket socket)
@@ -1155,13 +1367,13 @@ class GeometryNodesEvaluator {
});
}
- void send_output_required_notification(const DOutputSocket socket)
+ void send_output_required_notification(const DOutputSocket socket, NodeTaskRunState *run_state)
{
const DNode node = socket.node();
NodeState &node_state = this->get_node_state(node);
OutputState &output_state = node_state.outputs[socket->index()];
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
if (output_state.output_usage == ValueUsage::Required) {
/* Output is marked as required already. So the node is scheduled already. */
return;
@@ -1173,13 +1385,13 @@ class GeometryNodesEvaluator {
});
}
- void send_output_unused_notification(const DOutputSocket socket)
+ void send_output_unused_notification(const DOutputSocket socket, NodeTaskRunState *run_state)
{
const DNode node = socket.node();
NodeState &node_state = this->get_node_state(node);
OutputState &output_state = node_state.outputs[socket->index()];
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
output_state.potential_users -= 1;
if (output_state.potential_users == 0) {
/* The socket might be required even though the output is not used by other sockets. That
@@ -1205,48 +1417,69 @@ class GeometryNodesEvaluator {
/**
* Moves a newly computed value from an output socket to all the inputs that might need it.
+ * Takes ownership of the value and destructs if it is unused.
*/
- void forward_output(const DOutputSocket from_socket, GMutablePointer value_to_forward)
+ void forward_output(const DOutputSocket from_socket,
+ GMutablePointer value_to_forward,
+ NodeTaskRunState *run_state)
{
BLI_assert(value_to_forward.get() != nullptr);
- Vector<DSocket> sockets_to_log_to;
- sockets_to_log_to.append(from_socket);
-
- Vector<DInputSocket> to_sockets;
- auto handle_target_socket_fn = [&, this](const DInputSocket to_socket) {
- if (this->should_forward_to_socket(to_socket)) {
- to_sockets.append(to_socket);
- }
- };
- auto handle_skipped_socket_fn = [&](const DSocket socket) {
- sockets_to_log_to.append(socket);
- };
- from_socket.foreach_target_socket(handle_target_socket_fn, handle_skipped_socket_fn);
-
LinearAllocator<> &allocator = local_allocators_.local();
- const CPPType &from_type = *value_to_forward.type();
- Vector<DInputSocket> to_sockets_same_type;
- for (const DInputSocket &to_socket : to_sockets) {
- const CPPType &to_type = *get_socket_cpp_type(to_socket);
- if (from_type == to_type) {
- /* All target sockets that do not need a conversion will be handled afterwards. */
- to_sockets_same_type.append(to_socket);
- /* Multi input socket values are logged once all values are available. */
- if (!to_socket->is_multi_input_socket()) {
- sockets_to_log_to.append(to_socket);
- }
- continue;
- }
- this->forward_to_socket_with_different_type(
- allocator, value_to_forward, from_socket, to_socket, to_type);
- }
-
- this->log_socket_value(sockets_to_log_to, value_to_forward);
+ Vector<DSocket> log_original_value_sockets;
+ Vector<DInputSocket> forward_original_value_sockets;
+ log_original_value_sockets.append(from_socket);
+ from_socket.foreach_target_socket(
+ [&](const DInputSocket to_socket, const DOutputSocket::TargetSocketPathInfo &path_info) {
+ if (!this->should_forward_to_socket(to_socket)) {
+ return;
+ }
+ BLI_assert(to_socket == path_info.sockets.last());
+ GMutablePointer current_value = value_to_forward;
+ for (const DSocket &next_socket : path_info.sockets) {
+ const DNode next_node = next_socket.node();
+ const bool is_last_socket = to_socket == next_socket;
+ const bool do_conversion_if_necessary = is_last_socket ||
+ next_node->is_group_output_node() ||
+ (next_node->is_group_node() &&
+ !next_node->is_muted());
+ if (do_conversion_if_necessary) {
+ const CPPType &next_type = *get_socket_cpp_type(next_socket);
+ if (*current_value.type() != next_type) {
+ void *buffer = allocator.allocate(next_type.size(), next_type.alignment());
+ this->convert_value(*current_value.type(), next_type, current_value.get(), buffer);
+ if (current_value.get() != value_to_forward.get()) {
+ current_value.destruct();
+ }
+ current_value = {next_type, buffer};
+ }
+ }
+ if (current_value.get() == value_to_forward.get()) {
+ /* Log the original value at the current socket. */
+ log_original_value_sockets.append(next_socket);
+ }
+ else {
+ /* Multi-input sockets are logged when all values are available. */
+ if (!(next_socket->is_input() && next_socket->as_input().is_multi_input_socket())) {
+ /* Log the converted value at the socket. */
+ this->log_socket_value({next_socket}, current_value);
+ }
+ }
+ }
+ if (current_value.get() == value_to_forward.get()) {
+ /* The value has not been converted, so forward the original value. */
+ forward_original_value_sockets.append(to_socket);
+ }
+ else {
+ /* The value has been converted. */
+ this->add_value_to_input_socket(to_socket, from_socket, current_value, run_state);
+ }
+ });
+ this->log_socket_value(log_original_value_sockets, value_to_forward);
this->forward_to_sockets_with_same_type(
- allocator, to_sockets_same_type, value_to_forward, from_socket);
+ allocator, forward_original_value_sockets, value_to_forward, from_socket, run_state);
}
bool should_forward_to_socket(const DInputSocket socket)
@@ -1265,31 +1498,11 @@ class GeometryNodesEvaluator {
return target_input_state.usage != ValueUsage::Unused;
}
- void forward_to_socket_with_different_type(LinearAllocator<> &allocator,
- const GPointer value_to_forward,
- const DOutputSocket from_socket,
- const DInputSocket to_socket,
- const CPPType &to_type)
- {
- const CPPType &from_type = *value_to_forward.type();
-
- /* Allocate a buffer for the converted value. */
- void *buffer = allocator.allocate(to_type.size(), to_type.alignment());
- GMutablePointer value{to_type, buffer};
-
- this->convert_value(from_type, to_type, value_to_forward.get(), buffer);
-
- /* Multi input socket values are logged once all values are available. */
- if (!to_socket->is_multi_input_socket()) {
- this->log_socket_value({to_socket}, value);
- }
- this->add_value_to_input_socket(to_socket, from_socket, value);
- }
-
void forward_to_sockets_with_same_type(LinearAllocator<> &allocator,
Span<DInputSocket> to_sockets,
GMutablePointer value_to_forward,
- const DOutputSocket from_socket)
+ const DOutputSocket from_socket,
+ NodeTaskRunState *run_state)
{
if (to_sockets.is_empty()) {
/* Value is not used anymore, so it can be destructed. */
@@ -1298,7 +1511,7 @@ class GeometryNodesEvaluator {
else if (to_sockets.size() == 1) {
/* Value is only used by one input socket, no need to copy it. */
const DInputSocket to_socket = to_sockets[0];
- this->add_value_to_input_socket(to_socket, from_socket, value_to_forward);
+ this->add_value_to_input_socket(to_socket, from_socket, value_to_forward, run_state);
}
else {
/* Multiple inputs use the value, make a copy for every input except for one. */
@@ -1308,17 +1521,18 @@ class GeometryNodesEvaluator {
for (const DInputSocket &to_socket : to_sockets.drop_front(1)) {
void *buffer = allocator.allocate(type.size(), type.alignment());
type.copy_construct(value_to_forward.get(), buffer);
- this->add_value_to_input_socket(to_socket, from_socket, {type, buffer});
+ this->add_value_to_input_socket(to_socket, from_socket, {type, buffer}, run_state);
}
/* Forward the original value to one of the targets. */
const DInputSocket to_socket = to_sockets[0];
- this->add_value_to_input_socket(to_socket, from_socket, value_to_forward);
+ this->add_value_to_input_socket(to_socket, from_socket, value_to_forward, run_state);
}
}
void add_value_to_input_socket(const DInputSocket socket,
const DOutputSocket origin,
- GMutablePointer value)
+ GMutablePointer value,
+ NodeTaskRunState *run_state)
{
BLI_assert(socket->is_available());
@@ -1326,14 +1540,14 @@ class GeometryNodesEvaluator {
NodeState &node_state = this->get_node_state(node);
InputState &input_state = node_state.inputs[socket->index()];
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
if (socket->is_multi_input_socket()) {
/* Add a new value to the multi-input. */
MultiInputValue &multi_value = *input_state.value.multi;
- multi_value.items.append({origin, value.get()});
+ multi_value.add_value(origin, value.get());
- if (multi_value.expected_size == multi_value.items.size()) {
- this->log_socket_value({socket}, input_state, multi_value.items);
+ if (multi_value.all_values_available()) {
+ this->log_socket_value({socket}, input_state, multi_value.values);
}
}
else {
@@ -1353,6 +1567,14 @@ class GeometryNodesEvaluator {
});
}
+ /**
+ * Loads the value of a socket that is not computed by another node. Note that the socket may
+ * still be linked to e.g. a Group Input node, but the socket on the outside is not connected to
+ * anything.
+ *
+ * \param input_socket: The socket of the node that wants to use the value.
+ * \param origin_socket: The socket that we want to load the value from.
+ */
void load_unlinked_input_value(LockedNode &locked_node,
const DInputSocket input_socket,
InputState &input_state,
@@ -1364,15 +1586,23 @@ class GeometryNodesEvaluator {
GMutablePointer value = this->get_value_from_socket(origin_socket, *input_state.type);
if (input_socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- multi_value.items.append({origin_socket, value.get()});
- if (multi_value.expected_size == multi_value.items.size()) {
- this->log_socket_value({input_socket}, input_state, multi_value.items);
+ multi_value.add_value(origin_socket, value.get());
+ if (multi_value.all_values_available()) {
+ this->log_socket_value({input_socket}, input_state, multi_value.values);
}
}
else {
SingleInputValue &single_value = *input_state.value.single;
single_value.value = value.get();
- this->log_socket_value({input_socket}, value);
+ Vector<DSocket> sockets_to_log_to = {input_socket};
+ if (origin_socket != input_socket) {
+ /* This might log the socket value for the #origin_socket more than once, but this is
+ * handled by the logging system gracefully. */
+ sockets_to_log_to.append(origin_socket);
+ }
+ /* TODO: Log to the intermediate sockets between the group input and where the value is
+ * actually used as well. */
+ this->log_socket_value(sockets_to_log_to, value);
}
}
@@ -1381,10 +1611,13 @@ class GeometryNodesEvaluator {
InputState &input_state = locked_node.node_state.inputs[socket->index()];
if (socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- for (MultiInputValueItem &item : multi_value.items) {
- input_state.type->destruct(item.value);
+ for (void *&value : multi_value.values) {
+ if (value != nullptr) {
+ input_state.type->destruct(value);
+ value = nullptr;
+ }
}
- multi_value.items.clear();
+ multi_value.provided_value_count = 0;
}
else {
SingleInputValue &single_value = *input_state.value.single;
@@ -1408,6 +1641,7 @@ class GeometryNodesEvaluator {
}
void *converted_buffer = allocator.allocate(required_type.size(), required_type.alignment());
this->convert_value(type, required_type, buffer, converted_buffer);
+ type.destruct(buffer);
return {required_type, converted_buffer};
}
@@ -1420,19 +1654,28 @@ class GeometryNodesEvaluator {
from_type.copy_construct(from_value, to_value);
return;
}
-
- const FieldCPPType *from_field_type = dynamic_cast<const FieldCPPType *>(&from_type);
- const FieldCPPType *to_field_type = dynamic_cast<const FieldCPPType *>(&to_type);
+ const ValueOrFieldCPPType *from_field_type = dynamic_cast<const ValueOrFieldCPPType *>(
+ &from_type);
+ const ValueOrFieldCPPType *to_field_type = dynamic_cast<const ValueOrFieldCPPType *>(&to_type);
if (from_field_type != nullptr && to_field_type != nullptr) {
- const CPPType &from_base_type = from_field_type->field_type();
- const CPPType &to_base_type = to_field_type->field_type();
+ const CPPType &from_base_type = from_field_type->base_type();
+ const CPPType &to_base_type = to_field_type->base_type();
if (conversions_.is_convertible(from_base_type, to_base_type)) {
- const MultiFunction &fn = *conversions_.get_conversion_multi_function(
- MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type));
- const GField &from_field = *(const GField *)from_value;
- auto operation = std::make_shared<fn::FieldOperation>(fn, Vector<GField>{from_field});
- new (to_value) GField(std::move(operation), 0);
+ if (from_field_type->is_field(from_value)) {
+ const GField &from_field = *from_field_type->get_field_ptr(from_value);
+ const MultiFunction &fn = *conversions_.get_conversion_multi_function(
+ MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type));
+ auto operation = std::make_shared<fn::FieldOperation>(fn, Vector<GField>{from_field});
+ to_field_type->construct_from_field(to_value, GField(std::move(operation), 0));
+ }
+ else {
+ to_field_type->default_construct(to_value);
+ const void *from_value_ptr = from_field_type->get_value_ptr(from_value);
+ void *to_value_ptr = to_field_type->get_value_ptr(to_value);
+ conversions_.get_conversion_functions(from_base_type, to_base_type)
+ ->convert_single_to_initialized(from_value_ptr, to_value_ptr);
+ }
return;
}
}
@@ -1448,14 +1691,6 @@ class GeometryNodesEvaluator {
void construct_default_value(const CPPType &type, void *r_value)
{
- if (const FieldCPPType *field_cpp_type = dynamic_cast<const FieldCPPType *>(&type)) {
- const CPPType &base_type = field_cpp_type->field_type();
- auto constant_fn = std::make_unique<fn::CustomMF_GenericConstant>(
- base_type, base_type.default_value(), false);
- auto operation = std::make_shared<fn::FieldOperation>(std::move(constant_fn));
- new (r_value) GField(std::move(operation), 0);
- return;
- }
type.copy_construct(type.default_value(), r_value);
}
@@ -1464,7 +1699,7 @@ class GeometryNodesEvaluator {
return *node_states_.lookup_key_as(node).state;
}
- void log_socket_value(DSocket socket, InputState &input_state, Span<MultiInputValueItem> values)
+ void log_socket_value(DSocket socket, InputState &input_state, Span<void *> values)
{
if (params_.geo_logger == nullptr) {
return;
@@ -1473,8 +1708,8 @@ class GeometryNodesEvaluator {
Vector<GPointer, 16> value_pointers;
value_pointers.reserve(values.size());
const CPPType &type = *input_state.type;
- for (const MultiInputValueItem &item : values) {
- value_pointers.append({type, item.value});
+ for (const void *value : values) {
+ value_pointers.append({type, value});
}
params_.geo_logger->local().log_multi_value_socket(socket, value_pointers);
}
@@ -1487,10 +1722,21 @@ class GeometryNodesEvaluator {
params_.geo_logger->local().log_value_for_sockets(sockets, value);
}
+ void log_debug_message(DNode node, std::string message)
+ {
+ if (params_.geo_logger == nullptr) {
+ return;
+ }
+ params_.geo_logger->local().log_debug_message(node, std::move(message));
+ }
+
/* In most cases when `NodeState` is accessed, the node has to be locked first to avoid race
* conditions. */
template<typename Function>
- void with_locked_node(const DNode node, NodeState &node_state, const Function &function)
+ void with_locked_node(const DNode node,
+ NodeState &node_state,
+ NodeTaskRunState *run_state,
+ const Function &function)
{
LockedNode locked_node{node, node_state};
@@ -1503,21 +1749,32 @@ class GeometryNodesEvaluator {
/* Then send notifications to the other nodes after the node state is unlocked. This avoids
* locking two nodes at the same time on this thread and helps to prevent deadlocks. */
for (const DOutputSocket &socket : locked_node.delayed_required_outputs) {
- this->send_output_required_notification(socket);
+ this->send_output_required_notification(socket, run_state);
}
for (const DOutputSocket &socket : locked_node.delayed_unused_outputs) {
- this->send_output_unused_notification(socket);
- }
- for (const DNode &node : locked_node.delayed_scheduled_nodes) {
- this->add_node_to_task_pool(node);
+ this->send_output_unused_notification(socket, run_state);
+ }
+ for (const DNode &node_to_schedule : locked_node.delayed_scheduled_nodes) {
+ if (run_state != nullptr && !run_state->next_node_to_run) {
+ /* Execute the node on the same thread after the current node finished. */
+ /* Currently, this assumes that it is always best to run the first node that is scheduled
+ * on the same thread. That is usually correct, because the geometry socket which carries
+ * the most data usually comes first in nodes. */
+ run_state->next_node_to_run = node_to_schedule;
+ }
+ else {
+ /* Push the node to the task pool so that another thread can start working on it. */
+ this->add_node_to_task_pool(node_to_schedule);
+ }
}
}
};
NodeParamsProvider::NodeParamsProvider(GeometryNodesEvaluator &evaluator,
DNode dnode,
- NodeState &node_state)
- : evaluator_(evaluator), node_state_(node_state)
+ NodeState &node_state,
+ NodeTaskRunState *run_state)
+ : evaluator_(evaluator), node_state_(node_state), run_state_(run_state)
{
this->dnode = dnode;
this->self_object = evaluator.params_.self_object;
@@ -1538,7 +1795,7 @@ bool NodeParamsProvider::can_get_input(StringRef identifier) const
if (socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- return multi_value.items.size() == multi_value.expected_size;
+ return multi_value.all_values_available();
}
SingleInputValue &single_value = *input_state.value.single;
return single_value.value != nullptr;
@@ -1578,25 +1835,11 @@ Vector<GMutablePointer> NodeParamsProvider::extract_multi_input(StringRef identi
MultiInputValue &multi_value = *input_state.value.multi;
Vector<GMutablePointer> ret_values;
- socket.foreach_origin_socket([&](DSocket origin) {
- for (MultiInputValueItem &item : multi_value.items) {
- if (item.origin == origin && item.value != nullptr) {
- ret_values.append({*input_state.type, item.value});
- /* Make sure we do not use the same value again if two values have the same origin. */
- item.value = nullptr;
- return;
- }
- }
- BLI_assert_unreachable();
- });
- if (ret_values.is_empty()) {
- /* If the socket is not linked, we just use the value from the socket itself. */
- BLI_assert(multi_value.items.size() == 1);
- MultiInputValueItem &item = multi_value.items[0];
- BLI_assert(item.origin == socket);
- ret_values.append({*input_state.type, item.value});
- }
- multi_value.items.clear();
+ for (void *&value : multi_value.values) {
+ BLI_assert(value != nullptr);
+ ret_values.append({*input_state.type, value});
+ value = nullptr;
+ }
return ret_values;
}
@@ -1625,7 +1868,7 @@ void NodeParamsProvider::set_output(StringRef identifier, GMutablePointer value)
OutputState &output_state = node_state_.outputs[socket->index()];
BLI_assert(!output_state.has_been_computed);
- evaluator_.forward_output(socket, value);
+ evaluator_.forward_output(socket, value, run_state_);
output_state.has_been_computed = true;
}
@@ -1639,8 +1882,12 @@ bool NodeParamsProvider::lazy_require_input(StringRef identifier)
if (input_state.was_ready_for_execution) {
return false;
}
- evaluator_.with_locked_node(this->dnode, node_state_, [&](LockedNode &locked_node) {
- evaluator_.set_input_required(locked_node, socket);
+ evaluator_.with_locked_node(this->dnode, node_state_, run_state_, [&](LockedNode &locked_node) {
+ if (!evaluator_.set_input_required(locked_node, socket)) {
+ /* Schedule the currently executed node again because the value is available now but was not
+ * ready for the current execution. */
+ evaluator_.schedule_node(locked_node);
+ }
});
return true;
}
@@ -1650,7 +1897,7 @@ void NodeParamsProvider::set_input_unused(StringRef identifier)
const DInputSocket socket = this->dnode.input_by_identifier(identifier);
BLI_assert(socket);
- evaluator_.with_locked_node(this->dnode, node_state_, [&](LockedNode &locked_node) {
+ evaluator_.with_locked_node(this->dnode, node_state_, run_state_, [&](LockedNode &locked_node) {
evaluator_.set_input_unused(locked_node, socket);
});
}
@@ -1680,6 +1927,29 @@ bool NodeParamsProvider::lazy_output_is_required(StringRef identifier) const
return output_state.output_usage_for_execution == ValueUsage::Required;
}
+void NodeParamsProvider::set_default_remaining_outputs()
+{
+ LinearAllocator<> &allocator = evaluator_.local_allocators_.local();
+
+ for (const int i : this->dnode->outputs().index_range()) {
+ OutputState &output_state = node_state_.outputs[i];
+ if (output_state.has_been_computed) {
+ continue;
+ }
+ if (output_state.output_usage_for_execution == ValueUsage::Unused) {
+ continue;
+ }
+
+ const DOutputSocket socket = this->dnode.output(i);
+ const CPPType *type = get_socket_cpp_type(socket);
+ BLI_assert(type != nullptr);
+ void *buffer = allocator.allocate(type->size(), type->alignment());
+ type->copy_construct(type->default_value(), buffer);
+ evaluator_.forward_output(socket, {type, buffer}, run_state_);
+ output_state.has_been_computed = true;
+ }
+}
+
void evaluate_geometry_nodes(GeometryNodesEvaluationParams &params)
{
GeometryNodesEvaluator evaluator{params};
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index db2eedf9c02..61099fedf46 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -227,7 +227,7 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
Mesh *mesh,
short (*clnors)[2],
float (*loopnors)[3],
- float (*polynors)[3],
+ const float (*polynors)[3],
const short mix_mode,
const float mix_factor,
const float mix_limit,
@@ -334,14 +334,16 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
}
if (do_polynors_fix &&
- polygons_check_flip(mloop, nos, &mesh->ldata, mpoly, polynors, num_polys)) {
+ polygons_check_flip(
+ mloop, nos, &mesh->ldata, mpoly, BKE_mesh_poly_normals_for_write(mesh), num_polys)) {
/* XXX TODO: is this still needed? */
// mesh->dirty |= DM_DIRTY_TESS_CDLAYERS;
/* We need to recompute vertex normals! */
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
}
BKE_mesh_normals_loop_custom_set(mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
num_verts,
medge,
num_edges,
@@ -349,7 +351,7 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
nos,
num_loops,
mpoly,
- (const float(*)[3])polynors,
+ polynors,
num_polys,
clnors);
@@ -364,7 +366,7 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
Mesh *mesh,
short (*clnors)[2],
float (*loopnors)[3],
- float (*polynors)[3],
+ const float (*polynors)[3],
const short mix_mode,
const float mix_factor,
const float mix_limit,
@@ -449,11 +451,13 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
}
if (do_polynors_fix &&
- polygons_check_flip(mloop, nos, &mesh->ldata, mpoly, polynors, num_polys)) {
+ polygons_check_flip(
+ mloop, nos, &mesh->ldata, mpoly, BKE_mesh_poly_normals_for_write(mesh), num_polys)) {
BKE_mesh_normals_tag_dirty(mesh);
}
BKE_mesh_normals_loop_custom_set(mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
num_verts,
medge,
num_edges,
@@ -461,7 +465,7 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
nos,
num_loops,
mpoly,
- (const float(*)[3])polynors,
+ polynors,
num_polys,
clnors);
@@ -545,26 +549,10 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
float(*loopnors)[3] = NULL;
short(*clnors)[2] = NULL;
- float(*polynors)[3];
-
CustomData *ldata = &result->ldata;
- /* Compute poly (always needed) and vert normals. */
- CustomData *pdata = &result->pdata;
- polynors = CustomData_get_layer(pdata, CD_NORMAL);
- if (!polynors) {
- polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, num_polys);
- CustomData_set_layer_flag(pdata, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (result->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
- BKE_mesh_calc_normals_poly_and_vertex(
- mvert, num_verts, mloop, num_loops, mpoly, num_polys, polynors, NULL);
- }
- else {
- BKE_mesh_calc_normals_poly(mvert, num_verts, mloop, num_loops, mpoly, num_polys, polynors);
- }
-
- result->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ const float(*poly_normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
if (use_current_clnors) {
@@ -572,6 +560,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
loopnors = MEM_malloc_arrayN((size_t)num_loops, sizeof(*loopnors), __func__);
BKE_mesh_normals_loop_split(mvert,
+ vert_normals,
num_verts,
medge,
num_edges,
@@ -579,7 +568,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
loopnors,
num_loops,
mpoly,
- (const float(*)[3])polynors,
+ poly_normals,
num_polys,
true,
result->smoothresh,
@@ -601,7 +590,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
result,
clnors,
loopnors,
- polynors,
+ poly_normals,
enmd->mix_mode,
enmd->mix_factor,
enmd->mix_limit,
@@ -624,7 +613,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
result,
clnors,
loopnors,
- polynors,
+ poly_normals,
enmd->mix_mode,
enmd->mix_factor,
enmd->mix_limit,
@@ -641,8 +630,6 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
num_polys);
}
- /* Currently Modifier stack assumes there is no poly normal data passed around... */
- CustomData_free_layers(pdata, CD_NORMAL, num_polys);
MEM_SAFE_FREE(loopnors);
result->runtime.is_original = false;
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index ff1055eff3b..d821caf25a7 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -376,7 +376,7 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes
if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) {
result = generate_ocean_geometry(omd, mesh, resolution);
- BKE_mesh_ensure_normals(result);
+ BKE_mesh_normals_tag_dirty(result);
}
else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {
result = (Mesh *)BKE_id_copy_ex(NULL, &mesh->id, NULL, LIB_ID_COPY_LOCALIZE);
@@ -552,7 +552,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
modifier_panel_end(layout, ptr);
#else /* WITH_OCEANSIM */
- uiItemL(layout, IFACE_("Built without Ocean modifier"), ICON_NONE);
+ uiItemL(layout, TIP_("Built without Ocean modifier"), ICON_NONE);
#endif /* WITH_OCEANSIM */
}
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index 71fc7f3e424..2a4cc1c2747 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -277,7 +277,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
ModifierData *md = (ModifierData *)ptr->data;
ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
- uiItemL(layout, IFACE_("Settings are in the particle tab"), ICON_NONE);
+ uiItemL(layout, TIP_("Settings are in the particle tab"), ICON_NONE);
if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) {
if (ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB)) {
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index fef1f76c051..937a73fddd9 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -273,7 +273,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
modifier_panel_end(layout, ptr);
#else /* WITH_MOD_REMESH */
- uiItemL(layout, IFACE_("Built without Remesh modifier"), ICON_NONE);
+ uiItemL(layout, TIP_("Built without Remesh modifier"), ICON_NONE);
#endif /* WITH_MOD_REMESH */
}
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index f24f6951690..f5db3bced7a 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -395,6 +395,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
medge_orig = mesh->medge;
mvert_new = result->mvert;
+ float(*vert_normals_new)[3] = BKE_mesh_vertex_normals_for_write(result);
+ BKE_mesh_vertex_normals_clear_dirty(result);
mpoly_new = result->mpoly;
mloop_new = result->mloop;
medge_new = result->medge;
@@ -835,7 +837,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
normalize_v3(vc->no);
- normal_float_to_short_v3(mvert_new[i].no, vc->no);
+ copy_v3_v3(vert_normals_new[i], vc->no);
/* Done with normals */
}
@@ -884,7 +886,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
mul_v3_m3v3(nor_tx, mat3, vert_connect[j].no);
/* set the normal now its transformed */
- normal_float_to_short_v3(mv_new->no, nor_tx);
+ copy_v3_v3(vert_normals_new[mv_new - mvert_new], nor_tx);
}
/* set location */
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 7d90935f678..07ce819e91c 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -1479,7 +1479,7 @@ static void quad_from_tris(BMEdge *e, BMFace *adj[2], BMVert *ndx[4])
ndx[j] = tri[0][i];
/* When the triangle edge cuts across our quad-to-be,
* throw in the second triangle's vertex */
- if ((tri[0][i] == e->v1 || tri[0][i] == e->v2) &&
+ if ((ELEM(tri[0][i], e->v1, e->v2)) &&
(tri[0][(i + 1) % 3] == e->v1 || tri[0][(i + 1) % 3] == e->v2)) {
j++;
ndx[j] = opp;
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index 4187f9087a0..46e960e10d4 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -92,7 +92,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL);
- uiItemL(layout, IFACE_("Settings are inside the Physics tab"), ICON_NONE);
+ uiItemL(layout, TIP_("Settings are inside the Physics tab"), ICON_NONE);
modifier_panel_end(layout, ptr);
}
diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c
index 8f9aa86e561..fa8d08bf839 100644
--- a/source/blender/modifiers/intern/MOD_solidify_extrude.c
+++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c
@@ -43,20 +43,6 @@
#endif
/* -------------------------------------------------------------------- */
-/** \name Local Utilities
- * \{ */
-
-/* specific function for solidify - define locally */
-BLI_INLINE void madd_v3v3short_fl(float r[3], const short a[3], const float f)
-{
- r[0] += (float)a[0] * f;
- r[1] += (float)a[1] * f;
- r[2] += (float)a[2] * f;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name High Quality Normal Calculation Function
* \{ */
@@ -81,20 +67,18 @@ BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref)
* \param poly_nors: Precalculated face normals.
* \param r_vert_nors: Return vert normals.
*/
-static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_vert_nors)[3])
+static void mesh_calc_hq_normal(Mesh *mesh, const float (*poly_nors)[3], float (*r_vert_nors)[3])
{
int i, numVerts, numEdges, numPolys;
MPoly *mpoly, *mp;
MLoop *mloop, *ml;
MEdge *medge, *ed;
- MVert *mvert, *mv;
numVerts = mesh->totvert;
numEdges = mesh->totedge;
numPolys = mesh->totpoly;
mpoly = mesh->mpoly;
medge = mesh->medge;
- mvert = mesh->mvert;
mloop = mesh->mloop;
/* we don't want to overwrite any referenced layers */
@@ -105,7 +89,6 @@ static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_ver
cddm->mvert = mv;
#endif
- mv = mvert;
mp = mpoly;
{
@@ -171,9 +154,10 @@ static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_ver
}
/* normalize vertex normals and assign */
- for (i = 0; i < numVerts; i++, mv++) {
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ for (i = 0; i < numVerts; i++) {
if (normalize_v3(r_vert_nors[i]) == 0.0f) {
- normal_short_to_float_v3(r_vert_nors[i], mv->no);
+ copy_v3_v3(r_vert_nors[i], vert_normals[i]);
}
}
}
@@ -183,6 +167,7 @@ static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_ver
/* -------------------------------------------------------------------- */
/** \name Main Solidify Function
* \{ */
+
/* NOLINTNEXTLINE: readability-function-size */
Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
@@ -219,7 +204,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
int *edge_order = NULL;
float(*vert_nors)[3] = NULL;
- float(*poly_nors)[3] = NULL;
+ const float(*poly_nors)[3] = NULL;
const bool need_poly_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) ||
(smd->flag & MOD_SOLIDIFY_EVEN) ||
@@ -248,6 +233,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
/* array size is doubled in case of using a shell */
const uint stride = do_shell ? 2 : 1;
+ const float(*mesh_vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+
MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
orig_mvert = mesh->mvert;
@@ -257,14 +244,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
if (need_poly_normals) {
/* calculate only face normals */
- poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__);
- BKE_mesh_calc_normals_poly(orig_mvert,
- (int)numVerts,
- orig_mloop,
- (int)numLoops,
- orig_mpoly,
- (int)numPolys,
- poly_nors);
+ poly_nors = BKE_mesh_poly_normals_ensure(mesh);
}
STACK_INIT(new_vert_arr, numVerts * 2);
@@ -635,7 +615,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
madd_v3_v3fl(mv->co, vert_nors[i], ofs_new_vgroup);
}
else {
- madd_v3v3short_fl(mv->co, mv->no, ofs_new_vgroup / 32767.0f);
+ madd_v3_v3fl(mv->co, mesh_vert_normals[i], ofs_new_vgroup);
}
}
}
@@ -686,7 +666,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
madd_v3_v3fl(mv->co, vert_nors[i], ofs_new_vgroup);
}
else {
- madd_v3v3short_fl(mv->co, mv->no, ofs_new_vgroup / 32767.0f);
+ madd_v3_v3fl(mv->co, mesh_vert_normals[i], ofs_new_vgroup);
}
}
}
@@ -739,7 +719,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
if (vert_nors == NULL) {
vert_nors = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "mod_solid_vno");
for (i = 0, mv = mvert; i < numVerts; i++, mv++) {
- normal_short_to_float_v3(vert_nors[i], mv->no);
+ copy_v3_v3(vert_nors[i], mesh_vert_normals[i]);
}
}
@@ -994,8 +974,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
uint i;
/* flip vertex normals for copied verts */
mv = mvert + numVerts;
- for (i = 0; i < numVerts; i++, mv++) {
- negate_v3_short(mv->no);
+ for (i = 0; i < numVerts; i++) {
+ negate_v3((float *)mesh_vert_normals[i]);
}
}
@@ -1043,8 +1023,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
#define SOLIDIFY_SIDE_NORMALS
#ifdef SOLIDIFY_SIDE_NORMALS
- /* Note that, due to the code setting cd_dirty_vert a few lines above,
- * do_side_normals is always false. - Sybren */
+ /* NOTE(@sybren): due to the code setting cd_dirty_vert a few lines above,
+ * do_side_normals is always false. */
const bool do_side_normals = !(result->runtime.cd_dirty_vert & CD_MASK_NORMAL);
/* annoying to allocate these since we only need the edge verts, */
float(*edge_vert_nos)[3] = do_side_normals ?
@@ -1200,7 +1180,6 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
ed = medge + (numEdges * stride);
for (i = 0; i < rimVerts; i++, ed++, ed_orig++) {
float nor_cpy[3];
- short *nor_short;
int k;
/* NOTE: only the first vertex (lower half of the index) is calculated. */
@@ -1208,11 +1187,10 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
normalize_v3_v3(nor_cpy, edge_vert_nos[ed_orig->v1]);
for (k = 0; k < 2; k++) { /* loop over both verts of the edge */
- nor_short = mvert[*(&ed->v1 + k)].no;
- normal_short_to_float_v3(nor, nor_short);
+ copy_v3_v3(nor, mesh_vert_normals[*(&ed->v1 + k)]);
add_v3_v3(nor, nor_cpy);
normalize_v3(nor);
- normal_float_to_short_v3(nor_short, nor);
+ copy_v3_v3((float *)mesh_vert_normals[*(&ed->v1 + k)], nor);
}
}
@@ -1231,10 +1209,6 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
MEM_freeN(old_vert_arr);
}
- if (poly_nors) {
- MEM_freeN(poly_nors);
- }
-
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
index f654b69841e..1aa52d44509 100644
--- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -74,6 +74,7 @@ static float angle_signed_on_axis_normalized_v3v3_v3(const float n[3],
static float clamp_nonzero(const float value, const float epsilon)
{
BLI_assert(!(epsilon < 0.0f));
+ /* Return closest value with `abs(value) >= epsilon`. */
if (value < 0.0f) {
return min_ff(value, -epsilon);
}
@@ -157,7 +158,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
const uint numVerts = (uint)mesh->totvert;
const uint numEdges = (uint)mesh->totedge;
const uint numPolys = (uint)mesh->totpoly;
- const uint numLoops = (uint)mesh->totloop;
if (numPolys == 0 && numVerts != 0) {
return mesh;
@@ -169,17 +169,22 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
const short mat_ofs = mat_nrs > 1 ? smd->mat_ofs : 0;
const short mat_ofs_rim = mat_nrs > 1 ? smd->mat_ofs_rim : 0;
- float(*poly_nors)[3] = NULL;
-
+ /* #ofs_front and #ofs_back are the offset from the original
+ * surface along the normal, where #oft_front is along the positive
+ * and #oft_back is along the negative normal. */
const float ofs_front = (smd->offset_fac + 1.0f) * 0.5f * smd->offset;
const float ofs_back = ofs_front - smd->offset * smd->offset_fac;
- const float ofs_front_clamped = clamp_nonzero(smd->offset > 0 ? ofs_front : ofs_back, 1e-5f);
- const float ofs_back_clamped = clamp_nonzero(smd->offset > 0 ? ofs_back : ofs_front, 1e-5f);
+ /* #ofs_front_clamped and #ofs_back_clamped are the same as
+ * #ofs_front and #ofs_back, but never zero. */
+ const float ofs_front_clamped = clamp_nonzero(ofs_front, 1e-5f);
+ const float ofs_back_clamped = clamp_nonzero(ofs_back, 1e-5f);
const float offset_fac_vg = smd->offset_fac_vg;
const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
const float offset = fabsf(smd->offset) * smd->offset_clamp;
const bool do_angle_clamp = smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP;
- const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0;
+ /* #do_flip, flips the normals of the result. This is inverted if negative thickness
+ * is used, since simple solidify with negative thickness keeps the faces facing outside. */
+ const bool do_flip = ((smd->flag & MOD_SOLIDIFY_FLIP) != 0) == (smd->offset > 0);
const bool do_rim = smd->flag & MOD_SOLIDIFY_RIM;
const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) ==
0;
@@ -209,10 +214,9 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
#define MOD_SOLIDIFY_EMPTY_TAG ((uint)-1)
- /* Calculate only face normals. */
- poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__);
- BKE_mesh_calc_normals_poly(
- orig_mvert, (int)numVerts, orig_mloop, (int)numLoops, orig_mpoly, (int)numPolys, poly_nors);
+ /* Calculate only face normals. Copied because they are modified directly below. */
+ float(*poly_nors)[3] = MEM_malloc_arrayN(numPolys, sizeof(float[3]), __func__);
+ memcpy(poly_nors, BKE_mesh_poly_normals_ensure(mesh), sizeof(float[3]) * numPolys);
NewFaceRef *face_sides_arr = MEM_malloc_arrayN(
numPolys * 2, sizeof(*face_sides_arr), "face_sides_arr in solidify");
@@ -1168,9 +1172,9 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
add_index++;
}
if (last_split > split) {
- const uint size = (split + edges_len) - (uint)last_split;
+ const uint edges_len_group = (split + edges_len) - (uint)last_split;
NewEdgeRef **edges = MEM_malloc_arrayN(
- size, sizeof(*edges), "edge_group split in solidify");
+ edges_len_group, sizeof(*edges), "edge_group split in solidify");
memcpy(edges,
g.edges + last_split,
(edges_len - (uint)last_split) * sizeof(*edges));
@@ -1180,7 +1184,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
edge_groups[j + add_index] = (EdgeGroup){
.valid = true,
.edges = edges,
- .edges_len = size,
+ .edges_len = edges_len_group,
.open_face_edge = MOD_SOLIDIFY_EMPTY_TAG,
.is_orig_closed = g.is_orig_closed,
.is_even_split = is_even_split,
@@ -1193,14 +1197,14 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
};
}
else {
- const uint size = split - (uint)last_split;
+ const uint edges_len_group = split - (uint)last_split;
NewEdgeRef **edges = MEM_malloc_arrayN(
- size, sizeof(*edges), "edge_group split in solidify");
- memcpy(edges, g.edges + last_split, size * sizeof(*edges));
+ edges_len_group, sizeof(*edges), "edge_group split in solidify");
+ memcpy(edges, g.edges + last_split, edges_len_group * sizeof(*edges));
edge_groups[j + add_index] = (EdgeGroup){
.valid = true,
.edges = edges,
- .edges_len = size,
+ .edges_len = edges_len_group,
.open_face_edge = MOD_SOLIDIFY_EMPTY_TAG,
.is_orig_closed = g.is_orig_closed,
.is_even_split = is_even_split,
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index db0b769684e..a8c6687193b 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -27,6 +27,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -38,6 +39,7 @@
#include "DNA_screen_types.h"
#include "BKE_context.h"
+#include "BKE_editmesh.h"
#include "BKE_mesh.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -45,6 +47,7 @@
#include "BKE_subdiv_ccg.h"
#include "BKE_subdiv_deform.h"
#include "BKE_subdiv_mesh.h"
+#include "BKE_subdiv_modifier.h"
#include "BKE_subsurf.h"
#include "UI_interface.h"
@@ -64,11 +67,6 @@
#include "intern/CCGSubSurf.h"
-typedef struct SubsurfRuntimeData {
- /* Cached subdivision surface descriptor, with topology and settings. */
- struct Subdiv *subdiv;
-} SubsurfRuntimeData;
-
static void initData(ModifierData *md)
{
SubsurfModifierData *smd = (SubsurfModifierData *)md;
@@ -87,6 +85,9 @@ static void requiredDataMask(Object *UNUSED(ob),
r_cddata_masks->lmask |= CD_MASK_NORMAL;
r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL;
}
+ if (smd->flags & eSubsurfModifierFlag_UseCrease) {
+ r_cddata_masks->vmask |= CD_MASK_CREASE;
+ }
}
static bool dependsOnNormals(ModifierData *md)
@@ -154,37 +155,6 @@ static int subdiv_levels_for_modifier_get(const SubsurfModifierData *smd,
return get_render_subsurf_level(&scene->r, requested_levels, use_render_params);
}
-static void subdiv_settings_init(SubdivSettings *settings,
- const SubsurfModifierData *smd,
- const ModifierEvalContext *ctx)
-{
- const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER);
- const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels;
-
- settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
- settings->is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision);
- settings->level = settings->is_simple ?
- 1 :
- (settings->is_adaptive ? smd->quality : requested_levels);
- settings->use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease);
- settings->vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
- smd->boundary_smooth);
- settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
- smd->uv_smooth);
-}
-
-/* Main goal of this function is to give usable subdivision surface descriptor
- * which matches settings and topology. */
-static Subdiv *subdiv_descriptor_ensure(SubsurfModifierData *smd,
- const SubdivSettings *subdiv_settings,
- const Mesh *mesh)
-{
- SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
- Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_settings, mesh);
- runtime_data->subdiv = subdiv;
- return subdiv;
-}
-
/* Subdivide into fully qualified mesh. */
static void subdiv_mesh_settings_init(SubdivToMeshSettings *settings,
@@ -239,14 +209,17 @@ static Mesh *subdiv_as_ccg(SubsurfModifierData *smd,
return result;
}
-static SubsurfRuntimeData *subsurf_ensure_runtime(SubsurfModifierData *smd)
+/* Cache settings for lazy CPU evaluation. */
+
+static void subdiv_cache_cpu_evaluation_settings(const ModifierEvalContext *ctx,
+ Mesh *me,
+ SubsurfModifierData *smd)
{
- SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
- if (runtime_data == NULL) {
- runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
- smd->modifier.runtime = runtime_data;
- }
- return runtime_data;
+ SubdivToMeshSettings mesh_settings;
+ subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
+ me->runtime.subsurf_apply_render = (ctx->flag & MOD_APPLY_RENDER) != 0;
+ me->runtime.subsurf_resolution = mesh_settings.resolution;
+ me->runtime.subsurf_use_optimal_display = mesh_settings.use_optimal_display;
}
/* Modifier itself. */
@@ -260,12 +233,31 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
#endif
SubsurfModifierData *smd = (SubsurfModifierData *)md;
SubdivSettings subdiv_settings;
- subdiv_settings_init(&subdiv_settings, smd, ctx);
+ BKE_subsurf_modifier_subdiv_settings_init(
+ &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
if (subdiv_settings.level == 0) {
return result;
}
- SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd);
- Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh);
+ SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
+
+ /* Delay evaluation to the draw code if possible, provided we do not have to apply the modifier.
+ */
+ if ((ctx->flag & MOD_APPLY_TO_BASE_MESH) == 0) {
+ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ const bool is_render_mode = (ctx->flag & MOD_APPLY_RENDER) != 0;
+ /* Same check as in `DRW_mesh_batch_cache_create_requested` to keep both code coherent. The
+ * difference is that here we do not check for the final edit mesh pointer as it is not yet
+ * assigned at this stage of modifier stack evaluation. */
+ const bool is_editmode = (mesh->edit_mesh != NULL);
+ const int required_mode = BKE_subsurf_modifier_eval_required_mode(is_render_mode, is_editmode);
+ if (BKE_subsurf_modifier_can_do_gpu_subdiv_ex(scene, ctx->object, smd, required_mode, false)) {
+ subdiv_cache_cpu_evaluation_settings(ctx, mesh, smd);
+ return result;
+ }
+ }
+
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
+ smd, &subdiv_settings, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return result;
@@ -319,12 +311,14 @@ static void deformMatrices(ModifierData *md,
SubsurfModifierData *smd = (SubsurfModifierData *)md;
SubdivSettings subdiv_settings;
- subdiv_settings_init(&subdiv_settings, smd, ctx);
+ BKE_subsurf_modifier_subdiv_settings_init(
+ &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
if (subdiv_settings.level == 0) {
return;
}
- SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd);
- Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh);
+ SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
+ smd, &subdiv_settings, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return;
@@ -414,8 +408,12 @@ static void panel_draw(const bContext *C, Panel *panel)
float preview = MAX2(RNA_float_get(&cycles_ptr, "preview_dicing_rate") *
RNA_float_get(&ob_cycles_ptr, "dicing_rate"),
0.1f);
- char output[64];
- snprintf(output, 64, "Final Scale: Render %.2f px, Viewport %.2f px", render, preview);
+ char output[256];
+ BLI_snprintf(output,
+ sizeof(output),
+ TIP_("Final Scale: Render %.2f px, Viewport %.2f px"),
+ render,
+ preview);
uiItemL(layout, output, ICON_NONE);
uiItemS(layout);
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index 3f2d0a06db8..c8be2bd2829 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -207,7 +207,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL);
- uiItemL(layout, IFACE_("Settings are inside the Physics tab"), ICON_NONE);
+ uiItemL(layout, TIP_("Settings are inside the Physics tab"), ICON_NONE);
modifier_panel_end(layout, ptr);
}
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 52d5f3e97ef..b713df05b80 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -48,17 +48,11 @@
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
-Mesh *triangulate_mesh(Mesh *mesh,
- const int quad_method,
- const int ngon_method,
- const int min_vertices,
- const int flag);
-
-Mesh *triangulate_mesh(Mesh *mesh,
- const int quad_method,
- const int ngon_method,
- const int min_vertices,
- const int flag)
+static Mesh *triangulate_mesh(Mesh *mesh,
+ const int quad_method,
+ const int ngon_method,
+ const int min_vertices,
+ const int flag)
{
Mesh *result;
BMesh *bm;
diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c
index 6239ee45e59..fc1f6d33b25 100644
--- a/source/blender/modifiers/intern/MOD_ui_common.c
+++ b/source/blender/modifiers/intern/MOD_ui_common.c
@@ -100,15 +100,12 @@ static void set_modifier_expand_flag(const bContext *UNUSED(C), Panel *panel, sh
/** \name Modifier Panel Layouts
* \{ */
-/**
- * Draw modifier error message.
- */
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
{
ModifierData *md = ptr->data;
if (md->error) {
uiLayout *row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_(md->error), ICON_ERROR);
+ uiItemL(row, TIP_(md->error), ICON_ERROR);
}
}
@@ -132,14 +129,11 @@ PointerRNA *modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_
uiBlock *block = uiLayoutGetBlock(panel->layout);
UI_block_lock_set(block, ID_IS_LINKED((Object *)ptr->owner_id), ERROR_LIBDATA_MESSAGE);
- uiLayoutSetContextPointer(panel->layout, "modifier", ptr);
+ UI_panel_context_pointer_set(panel, "modifier", ptr);
return ptr;
}
-/**
- * Helper function for modifier layouts to draw vertex group settings.
- */
void modifier_vgroup_ui(uiLayout *layout,
PointerRNA *ptr,
PointerRNA *ob_ptr,
@@ -304,7 +298,7 @@ static void modifier_panel_header(const bContext *C, Panel *panel)
ModifierData *md = (ModifierData *)ptr->data;
Object *ob = (Object *)ptr->owner_id;
- uiLayoutSetContextPointer(panel->layout, "modifier", ptr);
+ UI_panel_context_pointer_set(panel, "modifier", ptr);
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
Scene *scene = CTX_data_scene(C);
@@ -429,9 +423,6 @@ static void modifier_panel_header(const bContext *C, Panel *panel)
/** \name Modifier Registration Helpers
* \{ */
-/**
- * Create a panel in the context's region
- */
PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
{
PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
@@ -448,7 +439,7 @@ PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type,
/* Give the panel the special flag that says it was built here and corresponds to a
* modifier rather than a #PanelType. */
- panel_type->flag = PANEL_TYPE_HEADER_EXPAND | PANEL_TYPE_DRAW_BOX | PANEL_TYPE_INSTANCED;
+ panel_type->flag = PANEL_TYPE_HEADER_EXPAND | PANEL_TYPE_INSTANCED;
panel_type->reorder = modifier_reorder;
panel_type->get_list_data_expand_flag = get_modifier_expand_flag;
panel_type->set_list_data_expand_flag = set_modifier_expand_flag;
@@ -458,12 +449,6 @@ PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type,
return panel_type;
}
-/**
- * Add a child panel to the parent.
- *
- * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
- * idname.
- */
PanelType *modifier_subpanel_register(ARegionType *region_type,
const char *name,
const char *label,
@@ -482,7 +467,7 @@ PanelType *modifier_subpanel_register(ARegionType *region_type,
panel_type->draw_header = draw_header;
panel_type->draw = draw;
panel_type->poll = modifier_ui_poll;
- panel_type->flag = (PANEL_TYPE_DEFAULT_CLOSED | PANEL_TYPE_DRAW_BOX);
+ panel_type->flag = PANEL_TYPE_DEFAULT_CLOSED;
BLI_assert(parent != NULL);
BLI_strncpy(panel_type->parent_id, parent->idname, BKE_ST_MAXNAME);
diff --git a/source/blender/modifiers/intern/MOD_ui_common.h b/source/blender/modifiers/intern/MOD_ui_common.h
index e7f801049b8..9662b181013 100644
--- a/source/blender/modifiers/intern/MOD_ui_common.h
+++ b/source/blender/modifiers/intern/MOD_ui_common.h
@@ -37,6 +37,9 @@ typedef void (*PanelDrawFn)(const bContext *, struct Panel *);
void modifier_panel_buttons(const struct bContext *C, struct Panel *panel);
+/**
+ * Helper function for modifier layouts to draw vertex group settings.
+ */
void modifier_vgroup_ui(struct uiLayout *layout,
struct PointerRNA *ptr,
struct PointerRNA *ob_ptr,
@@ -44,15 +47,27 @@ void modifier_vgroup_ui(struct uiLayout *layout,
const char *invert_vgroup_prop,
const char *text);
+/**
+ * Draw modifier error message.
+ */
void modifier_panel_end(struct uiLayout *layout, PointerRNA *ptr);
struct PointerRNA *modifier_panel_get_property_pointers(struct Panel *panel,
struct PointerRNA *r_ob_ptr);
+/**
+ * Create a panel in the context's region
+ */
struct PanelType *modifier_panel_register(struct ARegionType *region_type,
ModifierType type,
PanelDrawFn draw);
+/**
+ * Add a child panel to the parent.
+ *
+ * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
+ * idname.
+ */
struct PanelType *modifier_subpanel_register(struct ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index d57e92b4b35..d04aee91c71 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -72,7 +72,6 @@ void MOD_init_texture(MappingInfoModifierData *dmd, const ModifierEvalContext *c
}
/* TODO: to be renamed to get_texture_coords once we are done with moving modifiers to Mesh. */
-/** \param cos: may be NULL, in which case we use directly mesh vertices' coordinates. */
void MOD_get_texture_coords(MappingInfoModifierData *dmd,
const ModifierEvalContext *UNUSED(ctx),
Object *ob,
@@ -182,7 +181,6 @@ void MOD_previous_vcos_store(ModifierData *md, const float (*vert_coords)[3])
/* lattice/mesh modifier too */
}
-/* returns a mesh if mesh == NULL, for deforming modifiers that need it */
Mesh *MOD_deform_mesh_eval_get(Object *ob,
struct BMEditMesh *em,
Mesh *mesh,
@@ -219,8 +217,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
if (use_orco) {
- CustomData_add_layer(
- &mesh->vdata, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob), mesh->totvert);
+ BKE_mesh_orco_ensure(ob, mesh);
}
}
else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
@@ -237,9 +234,11 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
}
+ /* TODO: Remove this "use_normals" argument, since the caller should retrieve normals afterwards
+ * if necessary. */
if (use_normals) {
if (LIKELY(mesh)) {
- BKE_mesh_ensure_normals(mesh);
+ BKE_mesh_vertex_normals_ensure(mesh);
}
}
@@ -289,7 +288,6 @@ void MOD_depsgraph_update_object_bone_relation(struct DepsNodeHandle *node,
}
}
-/* only called by BKE_modifier.h/modifier.c */
void modifier_type_init(ModifierTypeInfo *types[])
{
#define INIT_TYPE(typeName) (types[eModifierType_##typeName] = &modifierType_##typeName)
diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h
index a3db848874e..de02b55440a 100644
--- a/source/blender/modifiers/intern/MOD_util.h
+++ b/source/blender/modifiers/intern/MOD_util.h
@@ -32,6 +32,9 @@ struct ModifierEvalContext;
struct Object;
void MOD_init_texture(struct MappingInfoModifierData *dmd, const struct ModifierEvalContext *ctx);
+/**
+ * \param cos: may be NULL, in which case we use directly mesh vertices' coordinates.
+ */
void MOD_get_texture_coords(struct MappingInfoModifierData *dmd,
const struct ModifierEvalContext *ctx,
struct Object *ob,
@@ -41,13 +44,16 @@ void MOD_get_texture_coords(struct MappingInfoModifierData *dmd,
void MOD_previous_vcos_store(struct ModifierData *md, const float (*vert_coords)[3]);
+/**
+ * \returns a mesh if mesh == NULL, for deforming modifiers that need it.
+ */
struct Mesh *MOD_deform_mesh_eval_get(struct Object *ob,
struct BMEditMesh *em,
struct Mesh *mesh,
const float (*vertexCos)[3],
- const int num_verts,
- const bool use_normals,
- const bool use_orco);
+ int num_verts,
+ bool use_normals,
+ bool use_orco);
void MOD_get_vgroup(struct Object *ob,
struct Mesh *mesh,
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index 2c28e9710ef..238952fde00 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -192,7 +192,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
mul_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat);
- /* calculate worldspace projector normal (for best projector test) */
+ /* Calculate world-space projector normal (for best projector test). */
projectors[i].normal[0] = 0;
projectors[i].normal[1] = 0;
projectors[i].normal[2] = 1;
@@ -208,7 +208,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
coords = BKE_mesh_vert_coords_alloc(mesh, &numVerts);
- /* convert coords to world space */
+ /* Convert coords to world-space. */
for (i = 0, co = coords; i < numVerts; i++, co++) {
mul_m4_v3(ob->obmat, *co);
}
diff --git a/source/blender/modifiers/intern/MOD_volume_displace.cc b/source/blender/modifiers/intern/MOD_volume_displace.cc
index fcf75040a9a..a1ca29f454c 100644
--- a/source/blender/modifiers/intern/MOD_volume_displace.cc
+++ b/source/blender/modifiers/intern/MOD_volume_displace.cc
@@ -203,9 +203,10 @@ struct DisplaceGridOp {
template<typename GridType> void operator()()
{
- if constexpr (std::is_same_v<GridType, openvdb::points::PointDataGrid> ||
- std::is_same_v<GridType, openvdb::StringGrid> ||
- std::is_same_v<GridType, openvdb::MaskGrid>) {
+ if constexpr (blender::is_same_any_v<GridType,
+ openvdb::points::PointDataGrid,
+ openvdb::StringGrid,
+ openvdb::MaskGrid>) {
/* We don't support displacing these grid types yet. */
return;
}
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 03f8e3a1dfb..b7ab5dac388 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -163,8 +163,10 @@ static void waveModifier_do(WaveModifierData *md,
float falloff_fac = 1.0f; /* when falloff == 0.0f this stays at 1.0f */
const bool invert_group = (wmd->flag & MOD_WAVE_INVERT_VGROUP) != 0;
+ const float(*vert_normals)[3] = NULL;
if ((wmd->flag & MOD_WAVE_NORM) && (mesh != NULL)) {
mvert = mesh->mvert;
+ vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
}
if (wmd->objectcenter != NULL) {
@@ -288,13 +290,13 @@ static void waveModifier_do(WaveModifierData *md,
if (mvert) {
/* move along normals */
if (wmd->flag & MOD_WAVE_NORM_X) {
- co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f;
+ co[0] += (lifefac * amplit) * vert_normals[i][0];
}
if (wmd->flag & MOD_WAVE_NORM_Y) {
- co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f;
+ co[1] += (lifefac * amplit) * vert_normals[i][1];
}
if (wmd->flag & MOD_WAVE_NORM_Z) {
- co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f;
+ co[2] += (lifefac * amplit) * vert_normals[i][2];
}
}
else {
diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c
index 1ee64b935b7..bfe389eb080 100644
--- a/source/blender/modifiers/intern/MOD_weighted_normal.c
+++ b/source/blender/modifiers/intern/MOD_weighted_normal.c
@@ -85,6 +85,7 @@ typedef struct WeightedNormalData {
const int numPolys;
MVert *mvert;
+ const float (*vert_normals)[3];
MEdge *medge;
MLoop *mloop;
@@ -93,7 +94,7 @@ typedef struct WeightedNormalData {
const float split_angle;
MPoly *mpoly;
- float (*polynors)[3];
+ const float (*polynors)[3];
int *poly_strength;
MDeformVert *dvert;
@@ -143,7 +144,7 @@ static void aggregate_item_normal(WeightedNormalModifierData *wnmd,
const float curr_val,
const bool use_face_influence)
{
- float(*polynors)[3] = wn_data->polynors;
+ const float(*polynors)[3] = wn_data->polynors;
MDeformVert *dvert = wn_data->dvert;
const int defgrp_index = wn_data->defgrp_index;
@@ -206,7 +207,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
int *loop_to_poly = wn_data->loop_to_poly;
MPoly *mpoly = wn_data->mpoly;
- float(*polynors)[3] = wn_data->polynors;
+ const float(*polynors)[3] = wn_data->polynors;
int *poly_strength = wn_data->poly_strength;
MDeformVert *dvert = wn_data->dvert;
@@ -234,6 +235,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
* we do not actually care about computed loop_normals for now... */
loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
BKE_mesh_normals_loop_split(mvert,
+ wn_data->vert_normals,
numVerts,
medge,
numEdges,
@@ -360,6 +362,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
}
BKE_mesh_normals_loop_custom_set(mvert,
+ wn_data->vert_normals,
numVerts,
medge,
numEdges,
@@ -390,6 +393,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
}
BKE_mesh_normals_loop_custom_from_vertices_set(mvert,
+ wn_data->vert_normals,
vert_normals,
numVerts,
medge,
@@ -407,6 +411,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
BKE_mesh_normals_loop_split(mvert,
+ wn_data->vert_normals,
numVerts,
medge,
numEdges,
@@ -430,6 +435,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
}
BKE_mesh_normals_loop_custom_set(mvert,
+ wn_data->vert_normals,
numVerts,
medge,
numEdges,
@@ -609,15 +615,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
weight = (weight - 1) * 25;
}
- CustomData *pdata = &result->pdata;
- float(*polynors)[3] = CustomData_get_layer(pdata, CD_NORMAL);
- if (!polynors) {
- polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys);
- CustomData_set_layer_flag(pdata, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- BKE_mesh_calc_normals_poly_and_vertex(
- mvert, numVerts, mloop, numLoops, mpoly, numPolys, polynors, NULL);
-
const float split_angle = mesh->smoothresh;
short(*clnors)[2];
CustomData *ldata = &result->ldata;
@@ -641,6 +638,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
.numPolys = numPolys,
.mvert = mvert,
+ .vert_normals = BKE_mesh_vertex_normals_ensure(result),
.medge = medge,
.mloop = mloop,
@@ -649,7 +647,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
.split_angle = split_angle,
.mpoly = mpoly,
- .polynors = polynors,
+ .polynors = BKE_mesh_poly_normals_ensure(mesh),
.poly_strength = CustomData_get_layer_named(
&result->pdata, CD_PROP_INT32, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID),
@@ -677,9 +675,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
MEM_SAFE_FREE(wn_data.mode_pair);
MEM_SAFE_FREE(wn_data.items_data);
- /* Currently Modifier stack assumes there is no poly normal data passed around... */
- CustomData_free_layers(pdata, CD_NORMAL, numPolys);
-
result->runtime.is_original = false;
return result;
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c
index e403051d1be..cd9e5162527 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.c
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.c
@@ -57,12 +57,6 @@
#include "MOD_weightvg_util.h"
#include "RE_texture.h" /* Texture masking. */
-/* Maps new_w weights in place, using either one of the predefined functions, or a custom curve.
- * Return values are in new_w.
- * If indices is not NULL, it must be a table of same length as org_w and new_w,
- * mapping to the real vertex index (in case the weight tables do not cover the whole vertices...).
- * cmap might be NULL, in which case curve mapping mode will return unmodified data.
- */
void weightvg_do_map(
int num, float *new_w, short falloff_type, const bool do_invert, CurveMapping *cmap, RNG *rng)
{
@@ -125,13 +119,6 @@ void weightvg_do_map(
}
}
-/* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
- * Return values are in org_w.
- * If indices is not NULL, it must be a table of same length as org_w and new_w,
- * mapping to the real vertex index (in case the weight tables do not cover the whole vertices...).
- * XXX The standard "factor" value is assumed in [0.0, 1.0] range.
- * Else, weird results might appear.
- */
void weightvg_do_mask(const ModifierEvalContext *ctx,
const int num,
const int *indices,
@@ -267,12 +254,6 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
}
}
-/* Applies weights to given vgroup (defgroup), and optionally add/remove vertices from the group.
- * If dws is not NULL, it must be an array of MDeformWeight pointers of same length as weights (and
- * defgrp_idx can then have any value).
- * If indices is not NULL, it must be an array of same length as weights, mapping to the real
- * vertex index (in case the weight array does not cover the whole vertices...).
- */
void weightvg_update_vg(MDeformVert *dvert,
int defgrp_idx,
MDeformWeight **dws,
@@ -340,8 +321,6 @@ void weightvg_update_vg(MDeformVert *dvert,
}
}
-/* Common vertex weight mask interface elements for the modifier panels.
- */
void weightvg_ui_common(const bContext *C, PointerRNA *ob_ptr, PointerRNA *ptr, uiLayout *layout)
{
PointerRNA mask_texture_ptr = RNA_pointer_get(ptr, "mask_texture");
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.h b/source/blender/modifiers/intern/MOD_weightvg_util.h
index 796603289ca..3bcbe3ed68b 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.h
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.h
@@ -46,48 +46,74 @@ struct uiLayout;
* Util functions. *
**************************************/
-/* We cannot divide by zero (what a surprise...).
- * So if -MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR < weightf < MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR,
+/**
+ * We cannot divide by zero (what a surprise...).
+ * So if `-MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR < weightf < MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR`,
* we clamp weightf to this value (or its negative version).
* Also used to avoid null power factor.
*/
#define MOD_WVG_ZEROFLOOR 1.0e-32f
+/**
+ * Maps new_w weights in place, using either one of the predefined functions, or a custom curve.
+ * Return values are in new_w.
+ * If indices is not NULL, it must be a table of same length as org_w and new_w,
+ * mapping to the real vertex index (in case the weight tables do not cover the whole vertices...).
+ * cmap might be NULL, in which case curve mapping mode will return unmodified data.
+ */
void weightvg_do_map(int num,
float *new_w,
short falloff_type,
- const bool do_invert,
+ bool do_invert,
struct CurveMapping *cmap,
struct RNG *rng);
+/**
+ * Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
+ * Return values are in org_w.
+ * If indices is not NULL, it must be a table of same length as org_w and new_w,
+ * mapping to the real vertex index (in case the weight tables do not cover the whole vertices...).
+ * XXX The standard "factor" value is assumed in [0.0, 1.0] range.
+ * Else, weird results might appear.
+ */
void weightvg_do_mask(const ModifierEvalContext *ctx,
- const int num,
+ int num,
const int *indices,
float *org_w,
const float *new_w,
Object *ob,
struct Mesh *mesh,
- const float fact,
+ float fact,
const char defgrp_name[MAX_VGROUP_NAME],
struct Scene *scene,
Tex *texture,
- const int tex_use_channel,
- const int tex_mapping,
+ int tex_use_channel,
+ int tex_mapping,
Object *tex_map_object,
const char *text_map_bone,
const char *tex_uvlayer_name,
- const bool invert_vgroup_mask);
+ bool invert_vgroup_mask);
+/**
+ * Applies weights to given vgroup (defgroup), and optionally add/remove vertices from the group.
+ * If dws is not NULL, it must be an array of #MDeformWeight pointers of same length as weights
+ * (and defgrp_idx can then have any value).
+ * If indices is not NULL, it must be an array of same length as weights, mapping to the real
+ * vertex index (in case the weight array does not cover the whole vertices...).
+ */
void weightvg_update_vg(struct MDeformVert *dvert,
int defgrp_idx,
struct MDeformWeight **dws,
int num,
const int *indices,
const float *weights,
- const bool do_add,
- const float add_thresh,
- const bool do_rem,
- const float rem_thresh,
- const bool do_normalize);
+ bool do_add,
+ float add_thresh,
+ bool do_rem,
+ float rem_thresh,
+ bool do_normalize);
+/**
+ * Common vertex weight mask interface elements for the modifier panels.
+ */
void weightvg_ui_common(const bContext *C, PointerRNA *ob_ptr, PointerRNA *ptr, uiLayout *layout);
diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c
deleted file mode 100644
index 503297d5985..00000000000
--- a/source/blender/modifiers/intern/MOD_weld.c
+++ /dev/null
@@ -1,2079 +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 by the Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup modifiers
- *
- * Weld modifier: Remove doubles.
- */
-
-/* TODOs:
- * - Review weight and vertex color interpolation.;
- */
-
-//#define USE_WELD_DEBUG
-//#define USE_WELD_NORMALS
-//#define USE_BVHTREEKDOP
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_utildefines.h"
-
-#include "BLI_alloca.h"
-#include "BLI_bitmap.h"
-#include "BLI_kdtree.h"
-#include "BLI_math.h"
-
-#include "BLT_translation.h"
-
-#include "DNA_defaults.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
-#include "DNA_screen_types.h"
-
-#ifdef USE_BVHTREEKDOP
-# include "BKE_bvhutils.h"
-#endif
-
-#include "BKE_context.h"
-#include "BKE_deform.h"
-#include "BKE_mesh.h"
-#include "BKE_modifier.h"
-#include "BKE_screen.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "RNA_access.h"
-
-#include "DEG_depsgraph.h"
-
-#include "MOD_modifiertypes.h"
-#include "MOD_ui_common.h"
-
-/* Indicates when the element was not computed. */
-#define OUT_OF_CONTEXT (uint)(-1)
-/* Indicates if the edge or face will be collapsed. */
-#define ELEM_COLLAPSED (uint)(-2)
-/* indicates whether an edge or vertex in groups_map will be merged. */
-#define ELEM_MERGED (uint)(-2)
-
-/* Used to indicate a range in an array specifying a group. */
-struct WeldGroup {
- uint len;
- uint ofs;
-};
-
-/* Edge groups that will be merged. Final vertices are also indicated. */
-struct WeldGroupEdge {
- struct WeldGroup group;
- uint v1;
- uint v2;
-};
-
-typedef struct WeldVert {
- /* Indexes relative to the original Mesh. */
- uint vert_dest;
- uint vert_orig;
-} WeldVert;
-
-typedef struct WeldEdge {
- union {
- uint flag;
- struct {
- /* Indexes relative to the original Mesh. */
- uint edge_dest;
- uint edge_orig;
- uint vert_a;
- uint vert_b;
- };
- };
-} WeldEdge;
-
-typedef struct WeldLoop {
- union {
- uint flag;
- struct {
- /* Indexes relative to the original Mesh. */
- uint vert;
- uint edge;
- uint loop_orig;
- uint loop_skip_to;
- };
- };
-} WeldLoop;
-
-typedef struct WeldPoly {
- union {
- uint flag;
- struct {
- /* Indexes relative to the original Mesh. */
- uint poly_dst;
- uint poly_orig;
- uint loop_start;
- uint loop_end;
- /* Final Polygon Size. */
- uint len;
- /* Group of loops that will be affected. */
- struct WeldGroup loops;
- };
- };
-} WeldPoly;
-
-typedef struct WeldMesh {
- /* Group of vertices to be merged. */
- struct WeldGroup *vert_groups;
- uint *vert_groups_buffer;
-
- /* Group of edges to be merged. */
- struct WeldGroupEdge *edge_groups;
- uint *edge_groups_buffer;
- /* From the original index of the vertex, this indicates which group it is or is going to be
- * merged. */
- uint *edge_groups_map;
-
- /* References all polygons and loops that will be affected. */
- WeldLoop *wloop;
- WeldPoly *wpoly;
- WeldPoly *wpoly_new;
- uint wloop_len;
- uint wpoly_len;
- uint wpoly_new_len;
-
- /* From the actual index of the element in the mesh, it indicates what is the index of the Weld
- * element above. */
- uint *loop_map;
- uint *poly_map;
-
- uint vert_kill_len;
- uint edge_kill_len;
- uint loop_kill_len;
- uint poly_kill_len; /* Including the new polygons. */
-
- /* Size of the affected polygon with more sides. */
- uint max_poly_len;
-} WeldMesh;
-
-typedef struct WeldLoopOfPolyIter {
- uint loop_start;
- uint loop_end;
- const WeldLoop *wloop;
- const MLoop *mloop;
- const uint *loop_map;
- /* Weld group. */
- uint *group;
-
- uint l_curr;
- uint l_next;
-
- /* Return */
- uint group_len;
- uint v;
- uint e;
- char type;
-} WeldLoopOfPolyIter;
-
-/* -------------------------------------------------------------------- */
-/** \name Debug Utils
- * \{ */
-
-#ifdef USE_WELD_DEBUG
-static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
- const WeldPoly *wp,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map,
- uint *group_buffer);
-
-static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter);
-
-static void weld_assert_edge_kill_len(const WeldEdge *wedge,
- const uint wedge_len,
- const uint supposed_kill_len)
-{
- uint kills = 0;
- const WeldEdge *we = &wedge[0];
- for (uint i = wedge_len; i--; we++) {
- uint edge_dest = we->edge_dest;
- /* Magically includes collapsed edges. */
- if (edge_dest != OUT_OF_CONTEXT) {
- kills++;
- }
- }
- BLI_assert(kills == supposed_kill_len);
-}
-
-static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly,
- const WeldPoly *wpoly_new,
- const uint wpoly_new_len,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map,
- const uint *poly_map,
- const MPoly *mpoly,
- const uint mpoly_len,
- const uint mloop_len,
- const uint supposed_poly_kill_len,
- const uint supposed_loop_kill_len)
-{
- uint poly_kills = 0;
- uint loop_kills = mloop_len;
- const MPoly *mp = &mpoly[0];
- for (uint i = 0; i < mpoly_len; i++, mp++) {
- uint poly_ctx = poly_map[i];
- if (poly_ctx != OUT_OF_CONTEXT) {
- const WeldPoly *wp = &wpoly[poly_ctx];
- WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
- poly_kills++;
- continue;
- }
- else {
- if (wp->poly_dst != OUT_OF_CONTEXT) {
- poly_kills++;
- continue;
- }
- uint remain = wp->len;
- uint l = wp->loop_start;
- while (remain) {
- uint l_next = l + 1;
- uint loop_ctx = loop_map[l];
- if (loop_ctx != OUT_OF_CONTEXT) {
- const WeldLoop *wl = &wloop[loop_ctx];
- if (wl->loop_skip_to != OUT_OF_CONTEXT) {
- l_next = wl->loop_skip_to;
- }
- if (wl->flag != ELEM_COLLAPSED) {
- loop_kills--;
- remain--;
- }
- }
- else {
- loop_kills--;
- remain--;
- }
- l = l_next;
- }
- }
- }
- else {
- loop_kills -= mp->totloop;
- }
- }
-
- const WeldPoly *wp = &wpoly_new[0];
- for (uint i = wpoly_new_len; i--; wp++) {
- if (wp->poly_dst != OUT_OF_CONTEXT) {
- poly_kills++;
- continue;
- }
- uint remain = wp->len;
- uint l = wp->loop_start;
- while (remain) {
- uint l_next = l + 1;
- uint loop_ctx = loop_map[l];
- if (loop_ctx != OUT_OF_CONTEXT) {
- const WeldLoop *wl = &wloop[loop_ctx];
- if (wl->loop_skip_to != OUT_OF_CONTEXT) {
- l_next = wl->loop_skip_to;
- }
- if (wl->flag != ELEM_COLLAPSED) {
- loop_kills--;
- remain--;
- }
- }
- else {
- loop_kills--;
- remain--;
- }
- l = l_next;
- }
- }
-
- BLI_assert(poly_kills == supposed_poly_kill_len);
- BLI_assert(loop_kills == supposed_loop_kill_len);
-}
-
-static void weld_assert_poly_no_vert_repetition(const WeldPoly *wp,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map)
-{
- const uint len = wp->len;
- uint *verts = BLI_array_alloca(verts, len);
- WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
- return;
- }
- else {
- uint i = 0;
- while (weld_iter_loop_of_poly_next(&iter)) {
- verts[i++] = iter.v;
- }
- }
- for (uint i = 0; i < len; i++) {
- uint va = verts[i];
- for (uint j = i + 1; j < len; j++) {
- uint vb = verts[j];
- BLI_assert(va != vb);
- }
- }
-}
-
-static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop)
-{
- if (wp->flag == ELEM_COLLAPSED) {
- return;
- }
-
- uint len = wp->len;
- const WeldLoop *wl = &wloop[wp->loops.ofs];
- BLI_assert(wp->loop_start <= wl->loop_orig);
-
- uint end_wloop = wp->loops.ofs + wp->loops.len;
- const WeldLoop *wl_end = &wloop[end_wloop - 1];
-
- uint min_len = 0;
- for (; wl <= wl_end; wl++) {
- BLI_assert(wl->loop_skip_to == OUT_OF_CONTEXT); /* Not for this case. */
- if (wl->flag != ELEM_COLLAPSED) {
- min_len++;
- }
- }
- BLI_assert(len >= min_len);
-
- uint max_len = wp->loop_end - wp->loop_start + 1;
- BLI_assert(len <= max_len);
-}
-#endif
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Weld Vert API
- * \{ */
-
-static void weld_vert_ctx_alloc_and_setup(const uint mvert_len,
- uint *r_vert_dest_map,
- WeldVert **r_wvert,
- uint *r_wvert_len)
-{
- /* Vert Context. */
- uint wvert_len = 0;
-
- WeldVert *wvert, *wv;
- wvert = MEM_mallocN(sizeof(*wvert) * mvert_len, __func__);
- wv = &wvert[0];
-
- uint *v_dest_iter = &r_vert_dest_map[0];
- for (uint i = 0; i < mvert_len; i++, v_dest_iter++) {
- if (*v_dest_iter != OUT_OF_CONTEXT) {
- wv->vert_dest = *v_dest_iter;
- wv->vert_orig = i;
- wv++;
- wvert_len++;
- }
- }
-
- *r_wvert = MEM_reallocN(wvert, sizeof(*wvert) * wvert_len);
- *r_wvert_len = wvert_len;
-}
-
-static void weld_vert_groups_setup(const uint mvert_len,
- const uint wvert_len,
- const WeldVert *wvert,
- const uint *vert_dest_map,
- uint *r_vert_groups_map,
- uint **r_vert_groups_buffer,
- struct WeldGroup **r_vert_groups)
-{
- /* Get weld vert groups. */
-
- uint wgroups_len = 0;
- const uint *vert_dest_iter = &vert_dest_map[0];
- uint *group_map_iter = &r_vert_groups_map[0];
- for (uint i = 0; i < mvert_len; i++, group_map_iter++, vert_dest_iter++) {
- uint vert_dest = *vert_dest_iter;
- if (vert_dest != OUT_OF_CONTEXT) {
- if (vert_dest != i) {
- *group_map_iter = ELEM_MERGED;
- }
- else {
- *group_map_iter = wgroups_len;
- wgroups_len++;
- }
- }
- else {
- *group_map_iter = OUT_OF_CONTEXT;
- }
- }
-
- struct WeldGroup *wgroups = MEM_callocN(sizeof(*wgroups) * wgroups_len, __func__);
-
- const WeldVert *wv = &wvert[0];
- for (uint i = wvert_len; i--; wv++) {
- uint group_index = r_vert_groups_map[wv->vert_dest];
- wgroups[group_index].len++;
- }
-
- uint ofs = 0;
- struct WeldGroup *wg_iter = &wgroups[0];
- for (uint i = wgroups_len; i--; wg_iter++) {
- wg_iter->ofs = ofs;
- ofs += wg_iter->len;
- }
-
- BLI_assert(ofs == wvert_len);
-
- uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
- wv = &wvert[0];
- for (uint i = wvert_len; i--; wv++) {
- uint group_index = r_vert_groups_map[wv->vert_dest];
- groups_buffer[wgroups[group_index].ofs++] = wv->vert_orig;
- }
-
- wg_iter = &wgroups[0];
- for (uint i = wgroups_len; i--; wg_iter++) {
- wg_iter->ofs -= wg_iter->len;
- }
-
- *r_vert_groups = wgroups;
- *r_vert_groups_buffer = groups_buffer;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Weld Edge API
- * \{ */
-
-static void weld_edge_ctx_setup(const uint mvert_len,
- const uint wedge_len,
- struct WeldGroup *r_vlinks,
- uint *r_edge_dest_map,
- WeldEdge *r_wedge,
- uint *r_edge_kiil_len)
-{
- WeldEdge *we;
-
- /* Setup Edge Overlap. */
- uint edge_kill_len = 0;
-
- struct WeldGroup *vl_iter, *v_links;
- v_links = r_vlinks;
- vl_iter = &v_links[0];
-
- we = &r_wedge[0];
- for (uint i = wedge_len; i--; we++) {
- uint dst_vert_a = we->vert_a;
- uint dst_vert_b = we->vert_b;
-
- if (dst_vert_a == dst_vert_b) {
- BLI_assert(we->edge_dest == OUT_OF_CONTEXT);
- r_edge_dest_map[we->edge_orig] = ELEM_COLLAPSED;
- we->flag = ELEM_COLLAPSED;
- edge_kill_len++;
- continue;
- }
-
- v_links[dst_vert_a].len++;
- v_links[dst_vert_b].len++;
- }
-
- uint link_len = 0;
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
- vl_iter->ofs = link_len;
- link_len += vl_iter->len;
- }
-
- if (link_len) {
- uint *link_edge_buffer = MEM_mallocN(sizeof(*link_edge_buffer) * link_len, __func__);
-
- we = &r_wedge[0];
- for (uint i = 0; i < wedge_len; i++, we++) {
- if (we->flag == ELEM_COLLAPSED) {
- continue;
- }
-
- uint dst_vert_a = we->vert_a;
- uint dst_vert_b = we->vert_b;
-
- link_edge_buffer[v_links[dst_vert_a].ofs++] = i;
- link_edge_buffer[v_links[dst_vert_b].ofs++] = i;
- }
-
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
- /* Fix offset */
- vl_iter->ofs -= vl_iter->len;
- }
-
- we = &r_wedge[0];
- for (uint i = 0; i < wedge_len; i++, we++) {
- if (we->edge_dest != OUT_OF_CONTEXT) {
- /* No need to retest edges.
- * (Already includes collapsed edges). */
- continue;
- }
-
- uint dst_vert_a = we->vert_a;
- uint dst_vert_b = we->vert_b;
-
- struct WeldGroup *link_a = &v_links[dst_vert_a];
- struct WeldGroup *link_b = &v_links[dst_vert_b];
-
- uint edges_len_a = link_a->len;
- uint edges_len_b = link_b->len;
-
- if (edges_len_a <= 1 || edges_len_b <= 1) {
- continue;
- }
-
- uint *edges_ctx_a = &link_edge_buffer[link_a->ofs];
- uint *edges_ctx_b = &link_edge_buffer[link_b->ofs];
- uint edge_orig = we->edge_orig;
-
- for (; edges_len_a--; edges_ctx_a++) {
- uint e_ctx_a = *edges_ctx_a;
- if (e_ctx_a == i) {
- continue;
- }
- while (edges_len_b && *edges_ctx_b < e_ctx_a) {
- edges_ctx_b++;
- edges_len_b--;
- }
- if (edges_len_b == 0) {
- break;
- }
- uint e_ctx_b = *edges_ctx_b;
- if (e_ctx_a == e_ctx_b) {
- WeldEdge *we_b = &r_wedge[e_ctx_b];
- BLI_assert(ELEM(we_b->vert_a, dst_vert_a, dst_vert_b));
- BLI_assert(ELEM(we_b->vert_b, dst_vert_a, dst_vert_b));
- BLI_assert(we_b->edge_dest == OUT_OF_CONTEXT);
- BLI_assert(we_b->edge_orig != edge_orig);
- r_edge_dest_map[we_b->edge_orig] = edge_orig;
- we_b->edge_dest = edge_orig;
- edge_kill_len++;
- }
- }
- }
-
-#ifdef USE_WELD_DEBUG
- weld_assert_edge_kill_len(r_wedge, wedge_len, edge_kill_len);
-#endif
-
- MEM_freeN(link_edge_buffer);
- }
-
- *r_edge_kiil_len = edge_kill_len;
-}
-
-static void weld_edge_ctx_alloc(const MEdge *medge,
- const uint medge_len,
- const uint *vert_dest_map,
- uint *r_edge_dest_map,
- uint **r_edge_ctx_map,
- WeldEdge **r_wedge,
- uint *r_wedge_len)
-{
- /* Edge Context. */
- uint *edge_map = MEM_mallocN(sizeof(*edge_map) * medge_len, __func__);
- uint wedge_len = 0;
-
- WeldEdge *wedge, *we;
- wedge = MEM_mallocN(sizeof(*wedge) * medge_len, __func__);
- we = &wedge[0];
-
- const MEdge *me = &medge[0];
- uint *e_dest_iter = &r_edge_dest_map[0];
- uint *iter = &edge_map[0];
- for (uint i = 0; i < medge_len; i++, me++, iter++, e_dest_iter++) {
- uint v1 = me->v1;
- uint v2 = me->v2;
- uint v_dest_1 = vert_dest_map[v1];
- uint v_dest_2 = vert_dest_map[v2];
- if ((v_dest_1 != OUT_OF_CONTEXT) || (v_dest_2 != OUT_OF_CONTEXT)) {
- we->vert_a = (v_dest_1 != OUT_OF_CONTEXT) ? v_dest_1 : v1;
- we->vert_b = (v_dest_2 != OUT_OF_CONTEXT) ? v_dest_2 : v2;
- we->edge_dest = OUT_OF_CONTEXT;
- we->edge_orig = i;
- we++;
- *e_dest_iter = i;
- *iter = wedge_len++;
- }
- else {
- *e_dest_iter = OUT_OF_CONTEXT;
- *iter = OUT_OF_CONTEXT;
- }
- }
-
- *r_wedge = MEM_reallocN(wedge, sizeof(*wedge) * wedge_len);
- *r_wedge_len = wedge_len;
- *r_edge_ctx_map = edge_map;
-}
-
-static void weld_edge_groups_setup(const uint medge_len,
- const uint edge_kill_len,
- const uint wedge_len,
- WeldEdge *wedge,
- const uint *wedge_map,
- uint *r_edge_groups_map,
- uint **r_edge_groups_buffer,
- struct WeldGroupEdge **r_edge_groups)
-{
-
- /* Get weld edge groups. */
-
- struct WeldGroupEdge *wegroups, *wegrp_iter;
-
- uint wgroups_len = wedge_len - edge_kill_len;
- wegroups = MEM_callocN(sizeof(*wegroups) * wgroups_len, __func__);
- wegrp_iter = &wegroups[0];
-
- wgroups_len = 0;
- const uint *edge_ctx_iter = &wedge_map[0];
- uint *group_map_iter = &r_edge_groups_map[0];
- for (uint i = medge_len; i--; edge_ctx_iter++, group_map_iter++) {
- uint edge_ctx = *edge_ctx_iter;
- if (edge_ctx != OUT_OF_CONTEXT) {
- WeldEdge *we = &wedge[edge_ctx];
- uint edge_dest = we->edge_dest;
- if (edge_dest != OUT_OF_CONTEXT) {
- BLI_assert(edge_dest != we->edge_orig);
- *group_map_iter = ELEM_MERGED;
- }
- else {
- we->edge_dest = we->edge_orig;
- wegrp_iter->v1 = we->vert_a;
- wegrp_iter->v2 = we->vert_b;
- *group_map_iter = wgroups_len;
- wgroups_len++;
- wegrp_iter++;
- }
- }
- else {
- *group_map_iter = OUT_OF_CONTEXT;
- }
- }
-
- BLI_assert(wgroups_len == wedge_len - edge_kill_len);
-
- WeldEdge *we = &wedge[0];
- for (uint i = wedge_len; i--; we++) {
- if (we->flag == ELEM_COLLAPSED) {
- continue;
- }
- uint group_index = r_edge_groups_map[we->edge_dest];
- wegroups[group_index].group.len++;
- }
-
- uint ofs = 0;
- wegrp_iter = &wegroups[0];
- for (uint i = wgroups_len; i--; wegrp_iter++) {
- wegrp_iter->group.ofs = ofs;
- ofs += wegrp_iter->group.len;
- }
-
- uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
- we = &wedge[0];
- for (uint i = wedge_len; i--; we++) {
- if (we->flag == ELEM_COLLAPSED) {
- continue;
- }
- uint group_index = r_edge_groups_map[we->edge_dest];
- groups_buffer[wegroups[group_index].group.ofs++] = we->edge_orig;
- }
-
- wegrp_iter = &wegroups[0];
- for (uint i = wgroups_len; i--; wegrp_iter++) {
- wegrp_iter->group.ofs -= wegrp_iter->group.len;
- }
-
- *r_edge_groups_buffer = groups_buffer;
- *r_edge_groups = wegroups;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Weld Poly and Loop API
- * \{ */
-
-static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
- const WeldPoly *wp,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map,
- uint *group_buffer)
-{
- if (wp->flag == ELEM_COLLAPSED) {
- return false;
- }
-
- iter->loop_start = wp->loop_start;
- iter->loop_end = wp->loop_end;
- iter->wloop = wloop;
- iter->mloop = mloop;
- iter->loop_map = loop_map;
- iter->group = group_buffer;
-
- uint group_len = 0;
- if (group_buffer) {
- /* First loop group needs more attention. */
- uint loop_start, loop_end, l;
- loop_start = iter->loop_start;
- loop_end = l = iter->loop_end;
- while (l >= loop_start) {
- const uint loop_ctx = loop_map[l];
- if (loop_ctx != OUT_OF_CONTEXT) {
- const WeldLoop *wl = &wloop[loop_ctx];
- if (wl->flag == ELEM_COLLAPSED) {
- l--;
- continue;
- }
- }
- break;
- }
- if (l != loop_end) {
- group_len = loop_end - l;
- int i = 0;
- while (l < loop_end) {
- iter->group[i++] = ++l;
- }
- }
- }
- iter->group_len = group_len;
-
- iter->l_next = iter->loop_start;
-#ifdef USE_WELD_DEBUG
- iter->v = OUT_OF_CONTEXT;
-#endif
- return true;
-}
-
-static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
-{
- uint loop_end = iter->loop_end;
- const WeldLoop *wloop = iter->wloop;
- const uint *loop_map = iter->loop_map;
- uint l = iter->l_curr = iter->l_next;
- if (l == iter->loop_start) {
- /* `grupo_len` is already calculated in the first loop */
- }
- else {
- iter->group_len = 0;
- }
- while (l <= loop_end) {
- uint l_next = l + 1;
- const uint loop_ctx = loop_map[l];
- if (loop_ctx != OUT_OF_CONTEXT) {
- const WeldLoop *wl = &wloop[loop_ctx];
- if (wl->loop_skip_to != OUT_OF_CONTEXT) {
- l_next = wl->loop_skip_to;
- }
- if (wl->flag == ELEM_COLLAPSED) {
- if (iter->group) {
- iter->group[iter->group_len++] = l;
- }
- l = l_next;
- continue;
- }
-#ifdef USE_WELD_DEBUG
- BLI_assert(iter->v != wl->vert);
-#endif
- iter->v = wl->vert;
- iter->e = wl->edge;
- iter->type = 1;
- }
- else {
- const MLoop *ml = &iter->mloop[l];
-#ifdef USE_WELD_DEBUG
- BLI_assert(iter->v != ml->v);
-#endif
- iter->v = ml->v;
- iter->e = ml->e;
- iter->type = 0;
- }
- if (iter->group) {
- iter->group[iter->group_len++] = l;
- }
- iter->l_next = l_next;
- return true;
- }
-
- return false;
-}
-
-static void weld_poly_loop_ctx_alloc(const MPoly *mpoly,
- const uint mpoly_len,
- const MLoop *mloop,
- const uint mloop_len,
- const uint *vert_dest_map,
- const uint *edge_dest_map,
- WeldMesh *r_weld_mesh)
-{
- /* Loop/Poly Context. */
- uint *loop_map = MEM_mallocN(sizeof(*loop_map) * mloop_len, __func__);
- uint *poly_map = MEM_mallocN(sizeof(*poly_map) * mpoly_len, __func__);
- uint wloop_len = 0;
- uint wpoly_len = 0;
- uint max_ctx_poly_len = 4;
-
- WeldLoop *wloop, *wl;
- wloop = MEM_mallocN(sizeof(*wloop) * mloop_len, __func__);
- wl = &wloop[0];
-
- WeldPoly *wpoly, *wp;
- wpoly = MEM_mallocN(sizeof(*wpoly) * mpoly_len, __func__);
- wp = &wpoly[0];
-
- uint maybe_new_poly = 0;
-
- const MPoly *mp = &mpoly[0];
- uint *iter = &poly_map[0];
- uint *loop_map_iter = &loop_map[0];
- for (uint i = 0; i < mpoly_len; i++, mp++, iter++) {
- const uint loopstart = mp->loopstart;
- const uint totloop = mp->totloop;
-
- uint vert_ctx_len = 0;
-
- uint l = loopstart;
- uint prev_wloop_len = wloop_len;
- const MLoop *ml = &mloop[l];
- for (uint j = totloop; j--; l++, ml++, loop_map_iter++) {
- uint v = ml->v;
- uint e = ml->e;
- uint v_dest = vert_dest_map[v];
- uint e_dest = edge_dest_map[e];
- bool is_vert_ctx = v_dest != OUT_OF_CONTEXT;
- bool is_edge_ctx = e_dest != OUT_OF_CONTEXT;
- if (is_vert_ctx) {
- vert_ctx_len++;
- }
- if (is_vert_ctx || is_edge_ctx) {
- wl->vert = is_vert_ctx ? v_dest : v;
- wl->edge = is_edge_ctx ? e_dest : e;
- wl->loop_orig = l;
- wl->loop_skip_to = OUT_OF_CONTEXT;
- wl++;
-
- *loop_map_iter = wloop_len++;
- }
- else {
- *loop_map_iter = OUT_OF_CONTEXT;
- }
- }
- if (wloop_len != prev_wloop_len) {
- uint loops_len = wloop_len - prev_wloop_len;
-
- wp->poly_dst = OUT_OF_CONTEXT;
- wp->poly_orig = i;
- wp->loops.len = loops_len;
- wp->loops.ofs = prev_wloop_len;
- wp->loop_start = loopstart;
- wp->loop_end = loopstart + totloop - 1;
- wp->len = totloop;
- wp++;
-
- *iter = wpoly_len++;
- if (totloop > 5 && vert_ctx_len > 1) {
- uint max_new = (totloop / 3) - 1;
- vert_ctx_len /= 2;
- maybe_new_poly += MIN2(max_new, vert_ctx_len);
- CLAMP_MIN(max_ctx_poly_len, totloop);
- }
- }
- else {
- *iter = OUT_OF_CONTEXT;
- }
- }
-
- if (mpoly_len < (wpoly_len + maybe_new_poly)) {
- WeldPoly *wpoly_tmp = wpoly;
- wpoly = MEM_mallocN(sizeof(*wpoly) * ((size_t)wpoly_len + maybe_new_poly), __func__);
- memcpy(wpoly, wpoly_tmp, sizeof(*wpoly) * wpoly_len);
- MEM_freeN(wpoly_tmp);
- }
-
- WeldPoly *poly_new = &wpoly[wpoly_len];
-
- r_weld_mesh->wloop = MEM_reallocN(wloop, sizeof(*wloop) * wloop_len);
- r_weld_mesh->wpoly = wpoly;
- r_weld_mesh->wpoly_new = poly_new;
- r_weld_mesh->wloop_len = wloop_len;
- r_weld_mesh->wpoly_len = wpoly_len;
- r_weld_mesh->wpoly_new_len = 0;
- r_weld_mesh->loop_map = loop_map;
- r_weld_mesh->poly_map = poly_map;
- r_weld_mesh->max_poly_len = max_ctx_poly_len;
-}
-
-static void weld_poly_split_recursive(const uint *vert_dest_map,
-#ifdef USE_WELD_DEBUG
- const MLoop *mloop,
-#endif
- uint ctx_verts_len,
- WeldPoly *r_wp,
- WeldMesh *r_weld_mesh,
- uint *r_poly_kill,
- uint *r_loop_kill)
-{
- uint poly_len = r_wp->len;
- if (poly_len > 3 && ctx_verts_len > 1) {
- const uint ctx_loops_len = r_wp->loops.len;
- const uint ctx_loops_ofs = r_wp->loops.ofs;
- WeldLoop *wloop = r_weld_mesh->wloop;
- WeldPoly *wpoly_new = r_weld_mesh->wpoly_new;
-
- uint loop_kill = 0;
-
- WeldLoop *poly_loops = &wloop[ctx_loops_ofs];
- WeldLoop *wla = &poly_loops[0];
- WeldLoop *wla_prev = &poly_loops[ctx_loops_len - 1];
- while (wla_prev->flag == ELEM_COLLAPSED) {
- wla_prev--;
- }
- const uint la_len = ctx_loops_len - 1;
- for (uint la = 0; la < la_len; la++, wla++) {
- wa_continue:
- if (wla->flag == ELEM_COLLAPSED) {
- continue;
- }
- uint vert_a = wla->vert;
- /* Only test vertices that will be merged. */
- if (vert_dest_map[vert_a] != OUT_OF_CONTEXT) {
- uint lb = la + 1;
- WeldLoop *wlb = wla + 1;
- WeldLoop *wlb_prev = wla;
- uint killed_ab = 0;
- ctx_verts_len = 1;
- for (; lb < ctx_loops_len; lb++, wlb++) {
- BLI_assert(wlb->loop_skip_to == OUT_OF_CONTEXT);
- if (wlb->flag == ELEM_COLLAPSED) {
- killed_ab++;
- continue;
- }
- uint vert_b = wlb->vert;
- if (vert_dest_map[vert_b] != OUT_OF_CONTEXT) {
- ctx_verts_len++;
- }
- if (vert_a == vert_b) {
- const uint dist_a = wlb->loop_orig - wla->loop_orig - killed_ab;
- const uint dist_b = poly_len - dist_a;
-
- BLI_assert(dist_a != 0 && dist_b != 0);
- if (dist_a == 1 || dist_b == 1) {
- BLI_assert(dist_a != dist_b);
- BLI_assert((wla->flag == ELEM_COLLAPSED) || (wlb->flag == ELEM_COLLAPSED));
- }
- else {
- WeldLoop *wl_tmp = NULL;
- if (dist_a == 2) {
- wl_tmp = wlb_prev;
- BLI_assert(wla->flag != ELEM_COLLAPSED);
- BLI_assert(wl_tmp->flag != ELEM_COLLAPSED);
- wla->flag = ELEM_COLLAPSED;
- wl_tmp->flag = ELEM_COLLAPSED;
- loop_kill += 2;
- poly_len -= 2;
- }
- if (dist_b == 2) {
- if (wl_tmp != NULL) {
- r_wp->flag = ELEM_COLLAPSED;
- *r_poly_kill += 1;
- }
- else {
- wl_tmp = wla_prev;
- BLI_assert(wlb->flag != ELEM_COLLAPSED);
- BLI_assert(wl_tmp->flag != ELEM_COLLAPSED);
- wlb->flag = ELEM_COLLAPSED;
- wl_tmp->flag = ELEM_COLLAPSED;
- }
- loop_kill += 2;
- poly_len -= 2;
- }
- if (wl_tmp == NULL) {
- const uint new_loops_len = lb - la;
- const uint new_loops_ofs = ctx_loops_ofs + la;
-
- WeldPoly *new_wp = &wpoly_new[r_weld_mesh->wpoly_new_len++];
- new_wp->poly_dst = OUT_OF_CONTEXT;
- new_wp->poly_orig = r_wp->poly_orig;
- new_wp->loops.len = new_loops_len;
- new_wp->loops.ofs = new_loops_ofs;
- new_wp->loop_start = wla->loop_orig;
- new_wp->loop_end = wlb_prev->loop_orig;
- new_wp->len = dist_a;
- weld_poly_split_recursive(vert_dest_map,
-#ifdef USE_WELD_DEBUG
- mloop,
-#endif
- ctx_verts_len,
- new_wp,
- r_weld_mesh,
- r_poly_kill,
- r_loop_kill);
- BLI_assert(dist_b == poly_len - dist_a);
- poly_len = dist_b;
- if (wla_prev->loop_orig > wla->loop_orig) {
- /* New start. */
- r_wp->loop_start = wlb->loop_orig;
- }
- else {
- /* The `loop_start` doesn't change but some loops must be skipped. */
- wla_prev->loop_skip_to = wlb->loop_orig;
- }
- wla = wlb;
- la = lb;
- goto wa_continue;
- }
- break;
- }
- }
- if (wlb->flag != ELEM_COLLAPSED) {
- wlb_prev = wlb;
- }
- }
- }
- if (wla->flag != ELEM_COLLAPSED) {
- wla_prev = wla;
- }
- }
- r_wp->len = poly_len;
- *r_loop_kill += loop_kill;
-
-#ifdef USE_WELD_DEBUG
- weld_assert_poly_no_vert_repetition(r_wp, wloop, mloop, r_weld_mesh->loop_map);
-#endif
- }
-}
-
-static void weld_poly_loop_ctx_setup(const MLoop *mloop,
-#ifdef USE_WELD_DEBUG
- const MPoly *mpoly,
- const uint mpoly_len,
- const uint mloop_len,
-#endif
- const uint mvert_len,
- const uint *vert_dest_map,
- const uint remain_edge_ctx_len,
- struct WeldGroup *r_vlinks,
- WeldMesh *r_weld_mesh)
-{
- uint poly_kill_len, loop_kill_len, wpoly_len, wpoly_new_len;
-
- WeldPoly *wpoly_new, *wpoly, *wp;
- WeldLoop *wloop, *wl;
-
- wpoly = r_weld_mesh->wpoly;
- wloop = r_weld_mesh->wloop;
- wpoly_new = r_weld_mesh->wpoly_new;
- wpoly_len = r_weld_mesh->wpoly_len;
- wpoly_new_len = 0;
- poly_kill_len = 0;
- loop_kill_len = 0;
-
- const uint *loop_map = r_weld_mesh->loop_map;
-
- if (remain_edge_ctx_len) {
-
- /* Setup Poly/Loop. */
-
- wp = &wpoly[0];
- for (uint i = wpoly_len; i--; wp++) {
- const uint ctx_loops_len = wp->loops.len;
- const uint ctx_loops_ofs = wp->loops.ofs;
-
- uint poly_len = wp->len;
- uint ctx_verts_len = 0;
- wl = &wloop[ctx_loops_ofs];
- for (uint l = ctx_loops_len; l--; wl++) {
- const uint edge_dest = wl->edge;
- if (edge_dest == ELEM_COLLAPSED) {
- wl->flag = ELEM_COLLAPSED;
- if (poly_len == 3) {
- wp->flag = ELEM_COLLAPSED;
- poly_kill_len++;
- loop_kill_len += 3;
- poly_len = 0;
- break;
- }
- loop_kill_len++;
- poly_len--;
- }
- else {
- const uint vert_dst = wl->vert;
- if (vert_dest_map[vert_dst] != OUT_OF_CONTEXT) {
- ctx_verts_len++;
- }
- }
- }
-
- if (poly_len) {
- wp->len = poly_len;
-#ifdef USE_WELD_DEBUG
- weld_assert_poly_len(wp, wloop);
-#endif
-
- weld_poly_split_recursive(vert_dest_map,
-#ifdef USE_WELD_DEBUG
- mloop,
-#endif
- ctx_verts_len,
- wp,
- r_weld_mesh,
- &poly_kill_len,
- &loop_kill_len);
-
- wpoly_new_len = r_weld_mesh->wpoly_new_len;
- }
- }
-
-#ifdef USE_WELD_DEBUG
- weld_assert_poly_and_loop_kill_len(wpoly,
- wpoly_new,
- wpoly_new_len,
- wloop,
- mloop,
- loop_map,
- r_weld_mesh->poly_map,
- mpoly,
- mpoly_len,
- mloop_len,
- poly_kill_len,
- loop_kill_len);
-#endif
-
- /* Setup Polygon Overlap. */
-
- uint wpoly_and_new_len = wpoly_len + wpoly_new_len;
-
- struct WeldGroup *vl_iter, *v_links = r_vlinks;
- memset(v_links, 0, sizeof(*v_links) * mvert_len);
-
- wp = &wpoly[0];
- for (uint i = wpoly_and_new_len; i--; wp++) {
- WeldLoopOfPolyIter iter;
- if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
- while (weld_iter_loop_of_poly_next(&iter)) {
- v_links[iter.v].len++;
- }
- }
- }
-
- uint link_len = 0;
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
- vl_iter->ofs = link_len;
- link_len += vl_iter->len;
- }
-
- if (link_len) {
- uint *link_poly_buffer = MEM_mallocN(sizeof(*link_poly_buffer) * link_len, __func__);
-
- wp = &wpoly[0];
- for (uint i = 0; i < wpoly_and_new_len; i++, wp++) {
- WeldLoopOfPolyIter iter;
- if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
- while (weld_iter_loop_of_poly_next(&iter)) {
- link_poly_buffer[v_links[iter.v].ofs++] = i;
- }
- }
- }
-
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
- /* Fix offset */
- vl_iter->ofs -= vl_iter->len;
- }
-
- uint polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b;
- polys_len_b = p_ctx_b = 0; /* silence warnings */
-
- wp = &wpoly[0];
- for (uint i = 0; i < wpoly_and_new_len; i++, wp++) {
- if (wp->poly_dst != OUT_OF_CONTEXT) {
- /* No need to retest poly.
- * (Already includes collapsed polygons). */
- continue;
- }
-
- WeldLoopOfPolyIter iter;
- weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL);
- weld_iter_loop_of_poly_next(&iter);
- struct WeldGroup *link_a = &v_links[iter.v];
- polys_len_a = link_a->len;
- if (polys_len_a == 1) {
- BLI_assert(link_poly_buffer[link_a->ofs] == i);
- continue;
- }
- uint wp_len = wp->len;
- polys_ctx_a = &link_poly_buffer[link_a->ofs];
- for (; polys_len_a--; polys_ctx_a++) {
- p_ctx_a = *polys_ctx_a;
- if (p_ctx_a == i) {
- continue;
- }
-
- WeldPoly *wp_tmp = &wpoly[p_ctx_a];
- if (wp_tmp->len != wp_len) {
- continue;
- }
-
- WeldLoopOfPolyIter iter_b = iter;
- while (weld_iter_loop_of_poly_next(&iter_b)) {
- struct WeldGroup *link_b = &v_links[iter_b.v];
- polys_len_b = link_b->len;
- if (polys_len_b == 1) {
- BLI_assert(link_poly_buffer[link_b->ofs] == i);
- polys_len_b = 0;
- break;
- }
-
- polys_ctx_b = &link_poly_buffer[link_b->ofs];
- for (; polys_len_b; polys_len_b--, polys_ctx_b++) {
- p_ctx_b = *polys_ctx_b;
- if (p_ctx_b < p_ctx_a) {
- continue;
- }
- if (p_ctx_b >= p_ctx_a) {
- if (p_ctx_b > p_ctx_a) {
- polys_len_b = 0;
- }
- break;
- }
- }
- if (polys_len_b == 0) {
- break;
- }
- }
- if (polys_len_b == 0) {
- continue;
- }
- BLI_assert(p_ctx_a > i);
- BLI_assert(p_ctx_a == p_ctx_b);
- BLI_assert(wp_tmp->poly_dst == OUT_OF_CONTEXT);
- BLI_assert(wp_tmp != wp);
- wp_tmp->poly_dst = wp->poly_orig;
- loop_kill_len += wp_tmp->len;
- poly_kill_len++;
- }
- }
- MEM_freeN(link_poly_buffer);
- }
- }
- else {
- poly_kill_len = r_weld_mesh->wpoly_len;
- loop_kill_len = r_weld_mesh->wloop_len;
-
- wp = &wpoly[0];
- for (uint i = wpoly_len; i--; wp++) {
- wp->flag = ELEM_COLLAPSED;
- }
- }
-
-#ifdef USE_WELD_DEBUG
- weld_assert_poly_and_loop_kill_len(wpoly,
- wpoly_new,
- wpoly_new_len,
- wloop,
- mloop,
- loop_map,
- r_weld_mesh->poly_map,
- mpoly,
- mpoly_len,
- mloop_len,
- poly_kill_len,
- loop_kill_len);
-#endif
-
- r_weld_mesh->wpoly_new = wpoly_new;
- r_weld_mesh->poly_kill_len = poly_kill_len;
- r_weld_mesh->loop_kill_len = loop_kill_len;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Weld Mesh API
- * \{ */
-
-static void weld_mesh_context_create(const Mesh *mesh,
- uint *vert_dest_map,
- const uint vert_kill_len,
- WeldMesh *r_weld_mesh)
-{
- const MEdge *medge = mesh->medge;
- const MLoop *mloop = mesh->mloop;
- const MPoly *mpoly = mesh->mpoly;
- const uint mvert_len = mesh->totvert;
- const uint medge_len = mesh->totedge;
- const uint mloop_len = mesh->totloop;
- const uint mpoly_len = mesh->totpoly;
-
- uint *edge_dest_map = MEM_mallocN(sizeof(*edge_dest_map) * medge_len, __func__);
- struct WeldGroup *v_links = MEM_callocN(sizeof(*v_links) * mvert_len, __func__);
-
- WeldVert *wvert;
- uint wvert_len;
- r_weld_mesh->vert_kill_len = vert_kill_len;
- weld_vert_ctx_alloc_and_setup(mvert_len, vert_dest_map, &wvert, &wvert_len);
-
- uint *edge_ctx_map;
- WeldEdge *wedge;
- uint wedge_len;
- weld_edge_ctx_alloc(
- medge, medge_len, vert_dest_map, edge_dest_map, &edge_ctx_map, &wedge, &wedge_len);
-
- weld_edge_ctx_setup(
- mvert_len, wedge_len, v_links, edge_dest_map, wedge, &r_weld_mesh->edge_kill_len);
-
- weld_poly_loop_ctx_alloc(
- mpoly, mpoly_len, mloop, mloop_len, vert_dest_map, edge_dest_map, r_weld_mesh);
-
- weld_poly_loop_ctx_setup(mloop,
-#ifdef USE_WELD_DEBUG
- mpoly,
- mpoly_len,
- mloop_len,
-#endif
- mvert_len,
- vert_dest_map,
- wedge_len - r_weld_mesh->edge_kill_len,
- v_links,
- r_weld_mesh);
-
- weld_vert_groups_setup(mvert_len,
- wvert_len,
- wvert,
- vert_dest_map,
- vert_dest_map,
- &r_weld_mesh->vert_groups_buffer,
- &r_weld_mesh->vert_groups);
-
- weld_edge_groups_setup(medge_len,
- r_weld_mesh->edge_kill_len,
- wedge_len,
- wedge,
- edge_ctx_map,
- edge_dest_map,
- &r_weld_mesh->edge_groups_buffer,
- &r_weld_mesh->edge_groups);
-
- r_weld_mesh->edge_groups_map = edge_dest_map;
- MEM_freeN(v_links);
- MEM_freeN(wvert);
- MEM_freeN(edge_ctx_map);
- MEM_freeN(wedge);
-}
-
-static void weld_mesh_context_free(WeldMesh *weld_mesh)
-{
- MEM_freeN(weld_mesh->vert_groups);
- MEM_freeN(weld_mesh->vert_groups_buffer);
-
- MEM_freeN(weld_mesh->edge_groups);
- MEM_freeN(weld_mesh->edge_groups_buffer);
- MEM_freeN(weld_mesh->edge_groups_map);
-
- MEM_freeN(weld_mesh->wloop);
- MEM_freeN(weld_mesh->wpoly);
- MEM_freeN(weld_mesh->loop_map);
- MEM_freeN(weld_mesh->poly_map);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Weld CustomData
- * \{ */
-
-static void customdata_weld(
- const CustomData *source, CustomData *dest, const uint *src_indices, int count, int dest_index)
-{
- if (count == 1) {
- CustomData_copy_data(source, dest, src_indices[0], dest_index, 1);
- return;
- }
-
- CustomData_interp(source, dest, (const int *)src_indices, NULL, NULL, count, dest_index);
-
- int src_i, dest_i;
- int j;
-
- float co[3] = {0.0f, 0.0f, 0.0f};
-#ifdef USE_WELD_NORMALS
- float no[3] = {0.0f, 0.0f, 0.0f};
-#endif
- uint crease = 0;
- uint bweight = 0;
- short flag = 0;
-
- /* interpolates a layer at a time */
- dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; src_i++) {
- const int type = source->layers[src_i].type;
-
- /* find the first dest layer with type >= the source type
- * (this should work because layers are ordered by type)
- */
- while (dest_i < dest->totlayer && dest->layers[dest_i].type < type) {
- dest_i++;
- }
-
- /* if there are no more dest layers, we're done */
- if (dest_i == dest->totlayer) {
- break;
- }
-
- /* if we found a matching layer, add the data */
- if (dest->layers[dest_i].type == type) {
- void *src_data = source->layers[src_i].data;
-
- if (type == CD_MVERT) {
- for (j = 0; j < count; j++) {
- MVert *mv_src = &((MVert *)src_data)[src_indices[j]];
- add_v3_v3(co, mv_src->co);
-#ifdef USE_WELD_NORMALS
- short *mv_src_no = mv_src->no;
- no[0] += mv_src_no[0];
- no[1] += mv_src_no[1];
- no[2] += mv_src_no[2];
-#endif
- bweight += mv_src->bweight;
- flag |= mv_src->flag;
- }
- }
- else if (type == CD_MEDGE) {
- for (j = 0; j < count; j++) {
- MEdge *me_src = &((MEdge *)src_data)[src_indices[j]];
- crease += me_src->crease;
- bweight += me_src->bweight;
- flag |= me_src->flag;
- }
- }
- else if (CustomData_layer_has_interp(dest, dest_i)) {
- /* Already calculated.
- * TODO: Optimize by exposing `typeInfo->interp`. */
- }
- else if (CustomData_layer_has_math(dest, dest_i)) {
- const int size = CustomData_sizeof(type);
- void *dst_data = dest->layers[dest_i].data;
- void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
- for (j = 0; j < count; j++) {
- CustomData_data_add(
- type, v_dst, POINTER_OFFSET(src_data, (size_t)src_indices[j] * size));
- }
- }
- else {
- CustomData_copy_layer_type_data(source, dest, type, src_indices[0], dest_index, 1);
- }
-
- /* if there are multiple source & dest layers of the same type,
- * we don't want to copy all source layers to the same dest, so
- * increment dest_i
- */
- dest_i++;
- }
- }
-
- float fac = 1.0f / count;
-
- for (dest_i = 0; dest_i < dest->totlayer; dest_i++) {
- CustomDataLayer *layer_dst = &dest->layers[dest_i];
- const int type = layer_dst->type;
- if (type == CD_MVERT) {
- MVert *mv = &((MVert *)layer_dst->data)[dest_index];
- mul_v3_fl(co, fac);
- bweight *= fac;
- CLAMP_MAX(bweight, 255);
-
- copy_v3_v3(mv->co, co);
-#ifdef USE_WELD_NORMALS
- mul_v3_fl(no, fac);
- short *mv_no = mv->no;
- mv_no[0] = (short)no[0];
- mv_no[1] = (short)no[1];
- mv_no[2] = (short)no[2];
-#endif
-
- mv->flag = (char)flag;
- mv->bweight = (char)bweight;
- }
- else if (type == CD_MEDGE) {
- MEdge *me = &((MEdge *)layer_dst->data)[dest_index];
- crease *= fac;
- bweight *= fac;
- CLAMP_MAX(crease, 255);
- CLAMP_MAX(bweight, 255);
-
- me->crease = (char)crease;
- me->bweight = (char)bweight;
- me->flag = flag;
- }
- else if (CustomData_layer_has_interp(dest, dest_i)) {
- /* Already calculated. */
- }
- else if (CustomData_layer_has_math(dest, dest_i)) {
- const int size = CustomData_sizeof(type);
- void *dst_data = layer_dst->data;
- void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
- CustomData_data_multiply(type, v_dst, fac);
- }
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Weld Modifier Main
- * \{ */
-
-#ifdef USE_BVHTREEKDOP
-struct WeldOverlapData {
- const MVert *mvert;
- float merge_dist_sq;
-};
-static bool bvhtree_weld_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
-{
- if (index_a < index_b) {
- struct WeldOverlapData *data = userdata;
- const MVert *mvert = data->mvert;
- const float dist_sq = len_squared_v3v3(mvert[index_a].co, mvert[index_b].co);
- BLI_assert(dist_sq <= ((data->merge_dist_sq + FLT_EPSILON) * 3));
- return dist_sq <= data->merge_dist_sq;
- }
- return false;
-}
-#endif
-
-/** Use for #MOD_WELD_MODE_CONNECTED calculation. */
-struct WeldVertexCluster {
- float co[3];
- uint merged_verts;
-};
-
-static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
- const ModifierEvalContext *UNUSED(ctx),
- Mesh *mesh)
-{
- Mesh *result = mesh;
-
- BLI_bitmap *v_mask = NULL;
- int v_mask_act = 0;
-
- const MVert *mvert;
- const MLoop *mloop;
- const MPoly *mpoly, *mp;
- uint totvert, totedge, totloop, totpoly;
-
- mvert = mesh->mvert;
- totvert = mesh->totvert;
-
- /* Vertex Group. */
- const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name);
- if (defgrp_index != -1) {
- MDeformVert *dvert, *dv;
- dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
- if (dvert) {
- const bool invert_vgroup = (wmd->flag & MOD_WELD_INVERT_VGROUP) != 0;
- dv = &dvert[0];
- v_mask = BLI_BITMAP_NEW(totvert, __func__);
- for (uint i = 0; i < totvert; i++, dv++) {
- const bool found = BKE_defvert_find_weight(dv, defgrp_index) > 0.0f;
- if (found != invert_vgroup) {
- BLI_BITMAP_ENABLE(v_mask, i);
- v_mask_act++;
- }
- }
- }
- }
-
- /* From the original index of the vertex.
- * This indicates which vert it is or is going to be merged. */
- uint *vert_dest_map = MEM_malloc_arrayN(totvert, sizeof(*vert_dest_map), __func__);
- uint vert_kill_len = 0;
- if (wmd->mode == MOD_WELD_MODE_ALL)
-#ifdef USE_BVHTREEKDOP
- {
- /* Get overlap map. */
- struct BVHTreeFromMesh treedata;
- BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(&treedata,
- mvert,
- totvert,
- false,
- v_mask,
- v_mask_act,
- wmd->merge_dist / 2,
- 2,
- 6,
- 0,
- NULL,
- NULL);
-
- if (bvhtree) {
- struct WeldOverlapData data;
- data.mvert = mvert;
- data.merge_dist_sq = square_f(wmd->merge_dist);
-
- uint overlap_len;
- BVHTreeOverlap *overlap = BLI_bvhtree_overlap_ex(bvhtree,
- bvhtree,
- &overlap_len,
- bvhtree_weld_overlap_cb,
- &data,
- 1,
- BVH_OVERLAP_RETURN_PAIRS);
-
- free_bvhtree_from_mesh(&treedata);
- if (overlap) {
- range_vn_u(vert_dest_map, totvert, 0);
-
- const BVHTreeOverlap *overlap_iter = &overlap[0];
- for (uint i = 0; i < overlap_len; i++, overlap_iter++) {
- uint indexA = overlap_iter->indexA;
- uint indexB = overlap_iter->indexB;
-
- BLI_assert(indexA < indexB);
-
- uint va_dst = vert_dest_map[indexA];
- while (va_dst != vert_dest_map[va_dst]) {
- va_dst = vert_dest_map[va_dst];
- }
- uint vb_dst = vert_dest_map[indexB];
- while (vb_dst != vert_dest_map[vb_dst]) {
- vb_dst = vert_dest_map[vb_dst];
- }
- if (va_dst == vb_dst) {
- continue;
- }
- if (va_dst > vb_dst) {
- SWAP(uint, va_dst, vb_dst);
- }
- vert_kill_len++;
- vert_dest_map[vb_dst] = va_dst;
- }
-
- /* Fix #r_vert_dest_map for next step. */
- for (uint i = 0; i < totvert; i++) {
- if (i == vert_dest_map[i]) {
- vert_dest_map[i] = OUT_OF_CONTEXT;
- }
- else {
- uint v = i;
- while (v != vert_dest_map[v] && vert_dest_map[v] != OUT_OF_CONTEXT) {
- v = vert_dest_map[v];
- }
- vert_dest_map[v] = v;
- vert_dest_map[i] = v;
- }
- }
-
- MEM_freeN(overlap);
- }
- }
- }
-#else
- {
- KDTree_3d *tree = BLI_kdtree_3d_new(v_mask ? v_mask_act : totvert);
- for (uint i = 0; i < totvert; i++) {
- if (!v_mask || BLI_BITMAP_TEST(v_mask, i)) {
- BLI_kdtree_3d_insert(tree, i, mvert[i].co);
- }
- vert_dest_map[i] = OUT_OF_CONTEXT;
- }
-
- BLI_kdtree_3d_balance(tree);
- vert_kill_len = BLI_kdtree_3d_calc_duplicates_fast(
- tree, wmd->merge_dist, false, (int *)vert_dest_map);
- BLI_kdtree_3d_free(tree);
- }
-#endif
- else {
- BLI_assert(wmd->mode == MOD_WELD_MODE_CONNECTED);
-
- MEdge *medge, *me;
-
- medge = mesh->medge;
- totvert = mesh->totvert;
- totedge = mesh->totedge;
-
- struct WeldVertexCluster *vert_clusters = MEM_malloc_arrayN(
- totvert, sizeof(*vert_clusters), __func__);
- struct WeldVertexCluster *vc = &vert_clusters[0];
- for (uint i = 0; i < totvert; i++, vc++) {
- copy_v3_v3(vc->co, mvert[i].co);
- vc->merged_verts = 0;
- }
- const float merge_dist_sq = square_f(wmd->merge_dist);
-
- range_vn_u(vert_dest_map, totvert, 0);
-
- /* Collapse Edges that are shorter than the threshold. */
- me = &medge[0];
- for (uint i = 0; i < totedge; i++, me++) {
- uint v1 = me->v1;
- uint v2 = me->v2;
-
- if (wmd->flag & MOD_WELD_LOOSE_EDGES && (me->flag & ME_LOOSEEDGE) == 0) {
- continue;
- }
- while (v1 != vert_dest_map[v1]) {
- v1 = vert_dest_map[v1];
- }
- while (v2 != vert_dest_map[v2]) {
- v2 = vert_dest_map[v2];
- }
- if (v1 == v2) {
- continue;
- }
- if (v_mask && (!BLI_BITMAP_TEST(v_mask, v1) || !BLI_BITMAP_TEST(v_mask, v2))) {
- continue;
- }
- if (v1 > v2) {
- SWAP(uint, v1, v2);
- }
- struct WeldVertexCluster *v1_cluster = &vert_clusters[v1];
- struct WeldVertexCluster *v2_cluster = &vert_clusters[v2];
-
- float edgedir[3];
- sub_v3_v3v3(edgedir, v2_cluster->co, v1_cluster->co);
- const float dist_sq = len_squared_v3(edgedir);
- if (dist_sq <= merge_dist_sq) {
- float influence = (v2_cluster->merged_verts + 1) /
- (float)(v1_cluster->merged_verts + v2_cluster->merged_verts + 2);
- madd_v3_v3fl(v1_cluster->co, edgedir, influence);
-
- v1_cluster->merged_verts += v2_cluster->merged_verts + 1;
- vert_dest_map[v2] = v1;
- vert_kill_len++;
- }
- }
-
- MEM_freeN(vert_clusters);
-
- for (uint i = 0; i < totvert; i++) {
- if (i == vert_dest_map[i]) {
- vert_dest_map[i] = OUT_OF_CONTEXT;
- }
- else {
- uint v = i;
- while ((v != vert_dest_map[v]) && (vert_dest_map[v] != OUT_OF_CONTEXT)) {
- v = vert_dest_map[v];
- }
- vert_dest_map[v] = v;
- vert_dest_map[i] = v;
- }
- }
- }
-
- if (v_mask) {
- MEM_freeN(v_mask);
- }
-
- if (vert_kill_len) {
- WeldMesh weld_mesh;
- weld_mesh_context_create(mesh, vert_dest_map, vert_kill_len, &weld_mesh);
-
- mloop = mesh->mloop;
- mpoly = mesh->mpoly;
-
- totedge = mesh->totedge;
- totloop = mesh->totloop;
- totpoly = mesh->totpoly;
-
- const int result_nverts = totvert - weld_mesh.vert_kill_len;
- const int result_nedges = totedge - weld_mesh.edge_kill_len;
- const int result_nloops = totloop - weld_mesh.loop_kill_len;
- const int result_npolys = totpoly - weld_mesh.poly_kill_len + weld_mesh.wpoly_new_len;
-
- result = BKE_mesh_new_nomain_from_template(
- mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys);
-
- /* Vertices */
-
- uint *vert_final = vert_dest_map;
- uint *index_iter = &vert_final[0];
- int dest_index = 0;
- for (uint i = 0; i < totvert; i++, index_iter++) {
- int source_index = i;
- int count = 0;
- while (i < totvert && *index_iter == OUT_OF_CONTEXT) {
- *index_iter = dest_index + count;
- index_iter++;
- count++;
- i++;
- }
- if (count) {
- CustomData_copy_data(&mesh->vdata, &result->vdata, source_index, dest_index, count);
- dest_index += count;
- }
- if (i == totvert) {
- break;
- }
- if (*index_iter != ELEM_MERGED) {
- struct WeldGroup *wgroup = &weld_mesh.vert_groups[*index_iter];
- customdata_weld(&mesh->vdata,
- &result->vdata,
- &weld_mesh.vert_groups_buffer[wgroup->ofs],
- wgroup->len,
- dest_index);
- *index_iter = dest_index;
- dest_index++;
- }
- }
-
- BLI_assert(dest_index == result_nverts);
-
- /* Edges */
-
- uint *edge_final = weld_mesh.edge_groups_map;
- index_iter = &edge_final[0];
- dest_index = 0;
- for (uint i = 0; i < totedge; i++, index_iter++) {
- int source_index = i;
- int count = 0;
- while (i < totedge && *index_iter == OUT_OF_CONTEXT) {
- *index_iter = dest_index + count;
- index_iter++;
- count++;
- i++;
- }
- if (count) {
- CustomData_copy_data(&mesh->edata, &result->edata, source_index, dest_index, count);
- MEdge *me = &result->medge[dest_index];
- dest_index += count;
- for (; count--; me++) {
- me->v1 = vert_final[me->v1];
- me->v2 = vert_final[me->v2];
- }
- }
- if (i == totedge) {
- break;
- }
- if (*index_iter != ELEM_MERGED) {
- struct WeldGroupEdge *wegrp = &weld_mesh.edge_groups[*index_iter];
- customdata_weld(&mesh->edata,
- &result->edata,
- &weld_mesh.edge_groups_buffer[wegrp->group.ofs],
- wegrp->group.len,
- dest_index);
- MEdge *me = &result->medge[dest_index];
- me->v1 = vert_final[wegrp->v1];
- me->v2 = vert_final[wegrp->v2];
- me->flag |= ME_LOOSEEDGE;
-
- *index_iter = dest_index;
- dest_index++;
- }
- }
-
- BLI_assert(dest_index == result_nedges);
-
- /* Polys/Loops */
-
- mp = &mpoly[0];
- MPoly *r_mp = &result->mpoly[0];
- MLoop *r_ml = &result->mloop[0];
- uint r_i = 0;
- int loop_cur = 0;
- uint *group_buffer = BLI_array_alloca(group_buffer, weld_mesh.max_poly_len);
- for (uint i = 0; i < totpoly; i++, mp++) {
- int loop_start = loop_cur;
- uint poly_ctx = weld_mesh.poly_map[i];
- if (poly_ctx == OUT_OF_CONTEXT) {
- uint mp_loop_len = mp->totloop;
- CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart, loop_cur, mp_loop_len);
- loop_cur += mp_loop_len;
- for (; mp_loop_len--; r_ml++) {
- r_ml->v = vert_final[r_ml->v];
- r_ml->e = edge_final[r_ml->e];
- }
- }
- else {
- WeldPoly *wp = &weld_mesh.wpoly[poly_ctx];
- WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(
- &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) {
- continue;
- }
-
- if (wp->poly_dst != OUT_OF_CONTEXT) {
- continue;
- }
- while (weld_iter_loop_of_poly_next(&iter)) {
- customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur);
- uint v = vert_final[iter.v];
- uint e = edge_final[iter.e];
- r_ml->v = v;
- r_ml->e = e;
- r_ml++;
- loop_cur++;
- if (iter.type) {
- result->medge[e].flag &= ~ME_LOOSEEDGE;
- }
- BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
- }
- }
-
- CustomData_copy_data(&mesh->pdata, &result->pdata, i, r_i, 1);
- r_mp->loopstart = loop_start;
- r_mp->totloop = loop_cur - loop_start;
- r_mp++;
- r_i++;
- }
-
- WeldPoly *wp = &weld_mesh.wpoly_new[0];
- for (uint i = 0; i < weld_mesh.wpoly_new_len; i++, wp++) {
- int loop_start = loop_cur;
- WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(
- &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) {
- continue;
- }
-
- if (wp->poly_dst != OUT_OF_CONTEXT) {
- continue;
- }
- while (weld_iter_loop_of_poly_next(&iter)) {
- customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur);
- uint v = vert_final[iter.v];
- uint e = edge_final[iter.e];
- r_ml->v = v;
- r_ml->e = e;
- r_ml++;
- loop_cur++;
- if (iter.type) {
- result->medge[e].flag &= ~ME_LOOSEEDGE;
- }
- BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
- }
-
- r_mp->loopstart = loop_start;
- r_mp->totloop = loop_cur - loop_start;
- r_mp++;
- r_i++;
- }
-
- BLI_assert((int)r_i == result_npolys);
- BLI_assert(loop_cur == result_nloops);
-
- /* is this needed? */
- BKE_mesh_normals_tag_dirty(result);
-
- weld_mesh_context_free(&weld_mesh);
- }
-
- MEM_freeN(vert_dest_map);
- return result;
-}
-
-static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
-{
- WeldModifierData *wmd = (WeldModifierData *)md;
- return weldModifier_doWeld(wmd, ctx, mesh);
-}
-
-static void initData(ModifierData *md)
-{
- WeldModifierData *wmd = (WeldModifierData *)md;
-
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wmd, modifier));
-
- MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WeldModifierData), modifier);
-}
-
-static void requiredDataMask(Object *UNUSED(ob),
- ModifierData *md,
- CustomData_MeshMasks *r_cddata_masks)
-{
- WeldModifierData *wmd = (WeldModifierData *)md;
-
- /* Ask for vertexgroups if we need them. */
- if (wmd->defgrp_name[0] != '\0') {
- r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
- }
-}
-
-static void panel_draw(const bContext *UNUSED(C), Panel *panel)
-{
- uiLayout *layout = panel->layout;
-
- PointerRNA ob_ptr;
- PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
- int weld_mode = RNA_enum_get(ptr, "mode");
-
- uiLayoutSetPropSep(layout, true);
-
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE);
- if (weld_mode == MOD_WELD_MODE_CONNECTED) {
- uiItemR(layout, ptr, "loose_edges", 0, NULL, ICON_NONE);
- }
- modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
-
- modifier_panel_end(layout, ptr);
-}
-
-static void panelRegister(ARegionType *region_type)
-{
- modifier_panel_register(region_type, eModifierType_Weld, panel_draw);
-}
-
-ModifierTypeInfo modifierType_Weld = {
- /* name */ "Weld",
- /* structName */ "WeldModifierData",
- /* structSize */ sizeof(WeldModifierData),
- /* srna */ &RNA_WeldModifier,
- /* type */ eModifierTypeType_Constructive,
- /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
- eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
- eModifierTypeFlag_AcceptsCVs,
- /* icon */ ICON_AUTOMERGE_OFF, /* TODO: Use correct icon. */
-
- /* copyData */ BKE_modifier_copydata_generic,
-
- /* deformVerts */ NULL,
- /* deformMatrices */ NULL,
- /* deformVertsEM */ NULL,
- /* deformMatricesEM */ NULL,
- /* modifyMesh */ modifyMesh,
- /* modifyHair */ NULL,
- /* modifyGeometrySet */ NULL,
-
- /* initData */ initData,
- /* requiredDataMask */ requiredDataMask,
- /* freeData */ NULL,
- /* isDisabled */ NULL,
- /* updateDepsgraph */ NULL,
- /* dependsOnTime */ NULL,
- /* dependsOnNormals */ NULL,
- /* foreachIDLink */ NULL,
- /* foreachTexLink */ NULL,
- /* freeRuntimeData */ NULL,
- /* panelRegister */ panelRegister,
- /* blendWrite */ NULL,
- /* blendRead */ NULL,
-};
-
-/** \} */
diff --git a/source/blender/modifiers/intern/MOD_weld.cc b/source/blender/modifiers/intern/MOD_weld.cc
new file mode 100644
index 00000000000..64871acabea
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_weld.cc
@@ -0,0 +1,239 @@
+/*
+ * 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 by the Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup modifiers
+ *
+ * Weld modifier: Remove doubles.
+ */
+
+/* TODOs:
+ * - Review weight and vertex color interpolation.;
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BLI_array.hh"
+#include "BLI_index_range.hh"
+#include "BLI_span.hh"
+#include "BLI_vector.hh"
+
+#include "BLT_translation.h"
+
+#include "DNA_defaults.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_screen_types.h"
+
+#ifdef USE_BVHTREEKDOP
+# include "BKE_bvhutils.h"
+#endif
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_modifier.h"
+#include "BKE_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_modifiertypes.h"
+#include "MOD_ui_common.h"
+
+#include "GEO_mesh_merge_by_distance.hh"
+
+using blender::Array;
+using blender::IndexMask;
+using blender::Span;
+using blender::Vector;
+
+static Span<MDeformVert> get_vertex_group(const Mesh &mesh, const int defgrp_index)
+{
+ if (defgrp_index == -1) {
+ return {};
+ }
+ const MDeformVert *vertex_group = static_cast<const MDeformVert *>(
+ CustomData_get_layer(&mesh.vdata, CD_MDEFORMVERT));
+ if (!vertex_group) {
+ return {};
+ }
+ return {vertex_group, mesh.totvert};
+}
+
+static Vector<int64_t> selected_indices_from_vertex_group(Span<MDeformVert> vertex_group,
+ const int index,
+ const bool invert)
+{
+ Vector<int64_t> selected_indices;
+ for (const int i : vertex_group.index_range()) {
+ const bool found = BKE_defvert_find_weight(&vertex_group[i], index) > 0.0f;
+ if (found != invert) {
+ selected_indices.append(i);
+ }
+ }
+ return selected_indices;
+}
+
+static Array<bool> selection_array_from_vertex_group(Span<MDeformVert> vertex_group,
+ const int index,
+ const bool invert)
+{
+ Array<bool> selection(vertex_group.size());
+ for (const int i : vertex_group.index_range()) {
+ const bool found = BKE_defvert_find_weight(&vertex_group[i], index) > 0.0f;
+ selection[i] = (found != invert);
+ }
+ return selection;
+}
+
+static std::optional<Mesh *> calculate_weld(const Mesh &mesh, const WeldModifierData &wmd)
+{
+ const int defgrp_index = BKE_id_defgroup_name_index(&mesh.id, wmd.defgrp_name);
+ Span<MDeformVert> vertex_group = get_vertex_group(mesh, defgrp_index);
+ const bool invert = (wmd.flag & MOD_WELD_INVERT_VGROUP) != 0;
+
+ if (wmd.mode == MOD_WELD_MODE_ALL) {
+ if (!vertex_group.is_empty()) {
+ Vector<int64_t> selected_indices = selected_indices_from_vertex_group(
+ vertex_group, defgrp_index, invert);
+ return blender::geometry::mesh_merge_by_distance_all(
+ mesh, IndexMask(selected_indices), wmd.merge_dist);
+ }
+ return blender::geometry::mesh_merge_by_distance_all(
+ mesh, IndexMask(mesh.totvert), wmd.merge_dist);
+ }
+ if (wmd.mode == MOD_WELD_MODE_CONNECTED) {
+ const bool only_loose_edges = (wmd.flag & MOD_WELD_LOOSE_EDGES) != 0;
+ if (!vertex_group.is_empty()) {
+ Array<bool> selection = selection_array_from_vertex_group(
+ vertex_group, defgrp_index, invert);
+ return blender::geometry::mesh_merge_by_distance_connected(
+ mesh, selection, wmd.merge_dist, only_loose_edges);
+ }
+ Array<bool> selection(mesh.totvert, true);
+ return blender::geometry::mesh_merge_by_distance_connected(
+ mesh, selection, wmd.merge_dist, only_loose_edges);
+ }
+
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
+{
+ const WeldModifierData &wmd = reinterpret_cast<WeldModifierData &>(*md);
+
+ std::optional<Mesh *> result = calculate_weld(*mesh, wmd);
+ if (!result) {
+ return mesh;
+ }
+ return *result;
+}
+
+static void initData(ModifierData *md)
+{
+ WeldModifierData *wmd = (WeldModifierData *)md;
+
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wmd, modifier));
+
+ MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WeldModifierData), modifier);
+}
+
+static void requiredDataMask(Object *UNUSED(ob),
+ ModifierData *md,
+ CustomData_MeshMasks *r_cddata_masks)
+{
+ WeldModifierData *wmd = (WeldModifierData *)md;
+
+ /* Ask for vertexgroups if we need them. */
+ if (wmd->defgrp_name[0] != '\0') {
+ r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
+ }
+}
+
+static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+ int weld_mode = RNA_enum_get(ptr, "mode");
+
+ uiLayoutSetPropSep(layout, true);
+
+ uiItemR(layout, ptr, "mode", 0, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE);
+ if (weld_mode == MOD_WELD_MODE_CONNECTED) {
+ uiItemR(layout, ptr, "loose_edges", 0, nullptr, ICON_NONE);
+ }
+ modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr);
+
+ modifier_panel_end(layout, ptr);
+}
+
+static void panelRegister(ARegionType *region_type)
+{
+ modifier_panel_register(region_type, eModifierType_Weld, panel_draw);
+}
+
+ModifierTypeInfo modifierType_Weld = {
+ /* name */ "Weld",
+ /* structName */ "WeldModifierData",
+ /* structSize */ sizeof(WeldModifierData),
+ /* srna */ &RNA_WeldModifier,
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */
+ (ModifierTypeFlag)(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
+ eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
+ eModifierTypeFlag_AcceptsCVs),
+ /* icon */ ICON_AUTOMERGE_OFF, /* TODO: Use correct icon. */
+
+ /* copyData */ BKE_modifier_copydata_generic,
+
+ /* deformVerts */ nullptr,
+ /* deformMatrices */ nullptr,
+ /* deformVertsEM */ nullptr,
+ /* deformMatricesEM */ nullptr,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ nullptr,
+ /* modifyGeometrySet */ nullptr,
+
+ /* initData */ initData,
+ /* requiredDataMask */ requiredDataMask,
+ /* freeData */ nullptr,
+ /* isDisabled */ nullptr,
+ /* updateDepsgraph */ nullptr,
+ /* dependsOnTime */ nullptr,
+ /* dependsOnNormals */ nullptr,
+ /* foreachIDLink */ nullptr,
+ /* foreachTexLink */ nullptr,
+ /* freeRuntimeData */ nullptr,
+ /* panelRegister */ panelRegister,
+ /* blendWrite */ nullptr,
+ /* blendRead */ nullptr,
+};
+
+/** \} */
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 8eaf88a6f1e..402a71af27f 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -18,6 +18,12 @@
# All rights reserved.
# ***** END GPL LICENSE BLOCK *****
+add_subdirectory(composite)
+add_subdirectory(function)
+add_subdirectory(geometry)
+add_subdirectory(shader)
+add_subdirectory(texture)
+
set(INC
.
composite
@@ -33,347 +39,26 @@ set(INC
../bmesh
../depsgraph
../functions
+ ../geometry
../gpu
../imbuf
../makesdna
../makesrna
../render
+ ../windowmanager
../../../intern/glew-mx
../../../intern/guardedalloc
- ../../../intern/sky/include
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../makesdna/intern
)
set(SRC
- composite/nodes/node_composite_alphaOver.cc
- composite/nodes/node_composite_antialiasing.cc
- composite/nodes/node_composite_bilateralblur.cc
- composite/nodes/node_composite_blur.cc
- composite/nodes/node_composite_bokehblur.cc
- composite/nodes/node_composite_bokehimage.cc
- composite/nodes/node_composite_boxmask.cc
- composite/nodes/node_composite_brightness.cc
- composite/nodes/node_composite_channelMatte.cc
- composite/nodes/node_composite_chromaMatte.cc
- composite/nodes/node_composite_colorMatte.cc
- composite/nodes/node_composite_colorSpill.cc
- composite/nodes/node_composite_colorbalance.cc
- composite/nodes/node_composite_colorcorrection.cc
- composite/nodes/node_composite_common.cc
- composite/nodes/node_composite_composite.cc
- composite/nodes/node_composite_cornerpin.cc
- composite/nodes/node_composite_crop.cc
- composite/nodes/node_composite_cryptomatte.cc
- composite/nodes/node_composite_curves.cc
- composite/nodes/node_composite_defocus.cc
- composite/nodes/node_composite_denoise.cc
- composite/nodes/node_composite_despeckle.cc
- composite/nodes/node_composite_diffMatte.cc
- composite/nodes/node_composite_dilate.cc
- composite/nodes/node_composite_directionalblur.cc
- composite/nodes/node_composite_displace.cc
- composite/nodes/node_composite_distanceMatte.cc
- composite/nodes/node_composite_doubleEdgeMask.cc
- composite/nodes/node_composite_ellipsemask.cc
- composite/nodes/node_composite_exposure.cc
- composite/nodes/node_composite_filter.cc
- composite/nodes/node_composite_flip.cc
- composite/nodes/node_composite_gamma.cc
- composite/nodes/node_composite_glare.cc
- composite/nodes/node_composite_hueSatVal.cc
- composite/nodes/node_composite_huecorrect.cc
- composite/nodes/node_composite_idMask.cc
- composite/nodes/node_composite_image.cc
- composite/nodes/node_composite_inpaint.cc
- composite/nodes/node_composite_invert.cc
- composite/nodes/node_composite_keying.cc
- composite/nodes/node_composite_keyingscreen.cc
- composite/nodes/node_composite_lensdist.cc
- composite/nodes/node_composite_levels.cc
- composite/nodes/node_composite_lummaMatte.cc
- composite/nodes/node_composite_mapRange.cc
- composite/nodes/node_composite_mapUV.cc
- composite/nodes/node_composite_mapValue.cc
- composite/nodes/node_composite_mask.cc
- composite/nodes/node_composite_math.cc
- composite/nodes/node_composite_mixrgb.cc
- composite/nodes/node_composite_movieclip.cc
- composite/nodes/node_composite_moviedistortion.cc
- composite/nodes/node_composite_normal.cc
- composite/nodes/node_composite_normalize.cc
- composite/nodes/node_composite_outputFile.cc
- composite/nodes/node_composite_pixelate.cc
- composite/nodes/node_composite_planetrackdeform.cc
- composite/nodes/node_composite_posterize.cc
- composite/nodes/node_composite_premulkey.cc
- composite/nodes/node_composite_rgb.cc
- composite/nodes/node_composite_rotate.cc
- composite/nodes/node_composite_scale.cc
- composite/nodes/node_composite_sepcombHSVA.cc
- composite/nodes/node_composite_sepcombRGBA.cc
- composite/nodes/node_composite_sepcombYCCA.cc
- composite/nodes/node_composite_sepcombYUVA.cc
- composite/nodes/node_composite_setalpha.cc
- composite/nodes/node_composite_splitViewer.cc
- composite/nodes/node_composite_stabilize2d.cc
- composite/nodes/node_composite_sunbeams.cc
- composite/nodes/node_composite_switch.cc
- composite/nodes/node_composite_switchview.cc
- composite/nodes/node_composite_texture.cc
- composite/nodes/node_composite_tonemap.cc
- composite/nodes/node_composite_trackpos.cc
- composite/nodes/node_composite_transform.cc
- composite/nodes/node_composite_translate.cc
- composite/nodes/node_composite_valToRgb.cc
- composite/nodes/node_composite_value.cc
- composite/nodes/node_composite_vecBlur.cc
- composite/nodes/node_composite_viewer.cc
- composite/nodes/node_composite_zcombine.cc
-
- composite/node_composite_tree.cc
- composite/node_composite_util.cc
-
- function/nodes/legacy/node_fn_random_float.cc
-
- function/nodes/node_fn_boolean_math.cc
- function/nodes/node_fn_float_compare.cc
- function/nodes/node_fn_float_to_int.cc
- function/nodes/node_fn_input_special_characters.cc
- function/nodes/node_fn_input_string.cc
- function/nodes/node_fn_input_vector.cc
- function/nodes/node_fn_random_value.cc
- function/nodes/node_fn_string_length.cc
- function/nodes/node_fn_string_substring.cc
- function/nodes/node_fn_value_to_string.cc
- function/node_function_util.cc
-
- geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc
- geometry/nodes/legacy/node_geo_attribute_clamp.cc
- geometry/nodes/legacy/node_geo_attribute_color_ramp.cc
- geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc
- geometry/nodes/legacy/node_geo_attribute_compare.cc
- geometry/nodes/legacy/node_geo_attribute_convert.cc
- geometry/nodes/legacy/node_geo_attribute_curve_map.cc
- geometry/nodes/legacy/node_geo_attribute_fill.cc
- geometry/nodes/legacy/node_geo_attribute_map_range.cc
- geometry/nodes/legacy/node_geo_attribute_math.cc
- geometry/nodes/legacy/node_geo_attribute_mix.cc
- geometry/nodes/legacy/node_geo_attribute_proximity.cc
- geometry/nodes/legacy/node_geo_attribute_randomize.cc
- geometry/nodes/legacy/node_geo_attribute_sample_texture.cc
- geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc
- geometry/nodes/legacy/node_geo_attribute_transfer.cc
- geometry/nodes/legacy/node_geo_attribute_vector_math.cc
- geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc
- geometry/nodes/legacy/node_geo_curve_endpoints.cc
- geometry/nodes/legacy/node_geo_curve_reverse.cc
- geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc
- geometry/nodes/legacy/node_geo_curve_set_handles.cc
- geometry/nodes/legacy/node_geo_curve_spline_type.cc
- geometry/nodes/legacy/node_geo_curve_subdivide.cc
- geometry/nodes/legacy/node_geo_curve_to_points.cc
- geometry/nodes/legacy/node_geo_delete_geometry.cc
- geometry/nodes/legacy/node_geo_edge_split.cc
- geometry/nodes/legacy/node_geo_material_assign.cc
- geometry/nodes/legacy/node_geo_mesh_to_curve.cc
- geometry/nodes/legacy/node_geo_point_distribute.cc
- geometry/nodes/legacy/node_geo_point_instance.cc
- geometry/nodes/legacy/node_geo_point_rotate.cc
- geometry/nodes/legacy/node_geo_point_scale.cc
- geometry/nodes/legacy/node_geo_point_separate.cc
- geometry/nodes/legacy/node_geo_point_translate.cc
- geometry/nodes/legacy/node_geo_points_to_volume.cc
- geometry/nodes/legacy/node_geo_raycast.cc
- geometry/nodes/legacy/node_geo_select_by_material.cc
- geometry/nodes/legacy/node_geo_subdivision_surface.cc
-
- geometry/nodes/node_geo_attribute_capture.cc
- geometry/nodes/node_geo_attribute_remove.cc
- geometry/nodes/node_geo_attribute_statistic.cc
- geometry/nodes/node_geo_boolean.cc
- geometry/nodes/node_geo_bounding_box.cc
- geometry/nodes/node_geo_collection_info.cc
- geometry/nodes/node_geo_common.cc
- geometry/nodes/node_geo_convex_hull.cc
- geometry/nodes/node_geo_curve_fill.cc
- geometry/nodes/node_geo_curve_fillet.cc
- geometry/nodes/node_geo_curve_length.cc
- geometry/nodes/node_geo_curve_parameter.cc
- geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
- geometry/nodes/node_geo_curve_primitive_circle.cc
- geometry/nodes/node_geo_curve_primitive_line.cc
- geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
- geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
- geometry/nodes/node_geo_curve_primitive_spiral.cc
- geometry/nodes/node_geo_curve_primitive_star.cc
- geometry/nodes/node_geo_curve_resample.cc
- geometry/nodes/node_geo_curve_reverse.cc
- geometry/nodes/node_geo_curve_sample.cc
- geometry/nodes/node_geo_curve_to_mesh.cc
- geometry/nodes/node_geo_curve_trim.cc
- geometry/nodes/node_geo_distribute_points_on_faces.cc
- geometry/nodes/node_geo_input_index.cc
- geometry/nodes/node_geo_input_material.cc
- geometry/nodes/node_geo_input_normal.cc
- geometry/nodes/node_geo_input_position.cc
- geometry/nodes/node_geo_input_tangent.cc
- geometry/nodes/node_geo_instance_on_points.cc
- geometry/nodes/node_geo_is_viewport.cc
- geometry/nodes/node_geo_join_geometry.cc
- geometry/nodes/node_geo_material_assign.cc
- geometry/nodes/node_geo_material_replace.cc
- geometry/nodes/node_geo_material_selection.cc
- geometry/nodes/node_geo_mesh_primitive_circle.cc
- geometry/nodes/node_geo_mesh_primitive_cone.cc
- geometry/nodes/node_geo_mesh_primitive_cube.cc
- geometry/nodes/node_geo_mesh_primitive_cylinder.cc
- geometry/nodes/node_geo_mesh_primitive_grid.cc
- geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
- geometry/nodes/node_geo_mesh_primitive_line.cc
- geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
- geometry/nodes/node_geo_mesh_subdivide.cc
- geometry/nodes/node_geo_mesh_to_points.cc
- geometry/nodes/node_geo_object_info.cc
- geometry/nodes/node_geo_points_to_vertices.cc
- geometry/nodes/node_geo_proximity.cc
- geometry/nodes/node_geo_realize_instances.cc
- geometry/nodes/node_geo_separate_components.cc
- geometry/nodes/node_geo_set_position.cc
- geometry/nodes/node_geo_string_join.cc
- geometry/nodes/node_geo_string_to_curves.cc
- geometry/nodes/node_geo_switch.cc
- geometry/nodes/node_geo_transform.cc
- geometry/nodes/node_geo_triangulate.cc
- geometry/nodes/node_geo_viewer.cc
- geometry/nodes/node_geo_volume_to_mesh.cc
-
- geometry/node_geometry_exec.cc
- geometry/node_geometry_tree.cc
- geometry/node_geometry_util.cc
-
- shader/nodes/node_shader_add_shader.c
- shader/nodes/node_shader_ambient_occlusion.c
- shader/nodes/node_shader_attribute.c
- shader/nodes/node_shader_background.c
- shader/nodes/node_shader_bevel.c
- shader/nodes/node_shader_blackbody.c
- shader/nodes/node_shader_brightness.c
- shader/nodes/node_shader_bsdf_anisotropic.c
- shader/nodes/node_shader_bsdf_diffuse.c
- shader/nodes/node_shader_bsdf_glass.c
- shader/nodes/node_shader_bsdf_glossy.c
- shader/nodes/node_shader_bsdf_hair.c
- shader/nodes/node_shader_bsdf_hair_principled.c
- shader/nodes/node_shader_bsdf_principled.c
- shader/nodes/node_shader_bsdf_refraction.c
- shader/nodes/node_shader_bsdf_toon.c
- shader/nodes/node_shader_bsdf_translucent.c
- shader/nodes/node_shader_bsdf_transparent.c
- shader/nodes/node_shader_bsdf_velvet.c
- shader/nodes/node_shader_bump.c
- shader/nodes/node_shader_camera.c
- shader/nodes/node_shader_clamp.cc
- shader/nodes/node_shader_common.c
- shader/nodes/node_shader_curves.cc
- shader/nodes/node_shader_displacement.c
- shader/nodes/node_shader_eevee_specular.c
- shader/nodes/node_shader_emission.c
- shader/nodes/node_shader_fresnel.c
- shader/nodes/node_shader_gamma.c
- shader/nodes/node_shader_geometry.c
- shader/nodes/node_shader_hair_info.c
- shader/nodes/node_shader_holdout.c
- shader/nodes/node_shader_hueSatVal.c
- shader/nodes/node_shader_ies_light.c
- shader/nodes/node_shader_invert.c
- shader/nodes/node_shader_layer_weight.c
- shader/nodes/node_shader_light_falloff.c
- shader/nodes/node_shader_light_path.c
- shader/nodes/node_shader_map_range.cc
- shader/nodes/node_shader_mapping.c
- shader/nodes/node_shader_math.cc
- shader/nodes/node_shader_mixRgb.cc
- shader/nodes/node_shader_mix_shader.c
- shader/nodes/node_shader_normal.c
- shader/nodes/node_shader_normal_map.c
- shader/nodes/node_shader_object_info.c
- shader/nodes/node_shader_output_aov.c
- shader/nodes/node_shader_output_light.c
- shader/nodes/node_shader_output_linestyle.c
- shader/nodes/node_shader_output_material.c
- shader/nodes/node_shader_output_world.c
- shader/nodes/node_shader_particle_info.c
- shader/nodes/node_shader_rgb.c
- shader/nodes/node_shader_script.c
- shader/nodes/node_shader_sepcombHSV.c
- shader/nodes/node_shader_sepcombRGB.cc
- shader/nodes/node_shader_sepcombXYZ.cc
- shader/nodes/node_shader_shaderToRgb.c
- shader/nodes/node_shader_squeeze.c
- shader/nodes/node_shader_subsurface_scattering.c
- shader/nodes/node_shader_tangent.c
- shader/nodes/node_shader_tex_brick.c
- shader/nodes/node_shader_tex_checker.c
- shader/nodes/node_shader_tex_coord.c
- shader/nodes/node_shader_tex_environment.c
- shader/nodes/node_shader_tex_gradient.cc
- shader/nodes/node_shader_tex_image.c
- shader/nodes/node_shader_tex_magic.c
- shader/nodes/node_shader_tex_musgrave.cc
- shader/nodes/node_shader_tex_noise.cc
- shader/nodes/node_shader_tex_pointdensity.c
- shader/nodes/node_shader_tex_sky.c
- shader/nodes/node_shader_tex_voronoi.cc
- shader/nodes/node_shader_tex_wave.c
- shader/nodes/node_shader_tex_white_noise.cc
- shader/nodes/node_shader_uvAlongStroke.c
- shader/nodes/node_shader_uvmap.c
- shader/nodes/node_shader_valToRgb.cc
- shader/nodes/node_shader_value.cc
- shader/nodes/node_shader_vectTransform.c
- shader/nodes/node_shader_vector_displacement.c
- shader/nodes/node_shader_vector_math.cc
- shader/nodes/node_shader_vector_rotate.cc
- shader/nodes/node_shader_vertex_color.c
- shader/nodes/node_shader_volume_absorption.c
- shader/nodes/node_shader_volume_info.c
- shader/nodes/node_shader_volume_principled.c
- shader/nodes/node_shader_volume_scatter.c
- shader/nodes/node_shader_wavelength.c
- shader/nodes/node_shader_wireframe.c
- shader/node_shader_tree.c
- shader/node_shader_util.c
-
- texture/nodes/node_texture_at.c
- texture/nodes/node_texture_bricks.c
- texture/nodes/node_texture_checker.c
- texture/nodes/node_texture_common.c
- texture/nodes/node_texture_compose.c
- texture/nodes/node_texture_coord.c
- texture/nodes/node_texture_curves.c
- texture/nodes/node_texture_decompose.c
- texture/nodes/node_texture_distance.c
- texture/nodes/node_texture_hueSatVal.c
- texture/nodes/node_texture_image.c
- texture/nodes/node_texture_invert.c
- texture/nodes/node_texture_math.c
- texture/nodes/node_texture_mixRgb.c
- texture/nodes/node_texture_output.c
- texture/nodes/node_texture_proc.c
- texture/nodes/node_texture_rotate.c
- texture/nodes/node_texture_scale.c
- texture/nodes/node_texture_texture.c
- texture/nodes/node_texture_translate.c
- texture/nodes/node_texture_valToNor.c
- texture/nodes/node_texture_valToRgb.c
- texture/nodes/node_texture_viewer.c
- texture/node_texture_tree.c
- texture/node_texture_util.c
-
intern/derived_node_tree.cc
intern/geometry_nodes_eval_log.cc
intern/math_functions.cc
- intern/node_common.c
+ intern/node_common.cc
intern/node_declaration.cc
intern/node_exec.cc
intern/node_geometry_exec.cc
@@ -382,13 +67,7 @@ set(SRC
intern/node_socket_declarations.cc
intern/node_tree_ref.cc
intern/node_util.c
- intern/type_conversions.cc
-
- composite/node_composite_util.hh
- function/node_function_util.hh
- shader/node_shader_util.h
- geometry/node_geometry_util.hh
- texture/node_texture_util.h
+ intern/socket_search_link.cc
NOD_common.h
NOD_composite.h
@@ -404,9 +83,10 @@ set(SRC
NOD_shader.h
NOD_socket.h
NOD_socket_declarations.hh
+ NOD_socket_declarations_geometry.hh
+ NOD_socket_search_link.hh
NOD_static_types.h
NOD_texture.h
- NOD_type_conversions.hh
intern/node_common.h
intern/node_exec.h
intern/node_util.h
@@ -415,18 +95,22 @@ set(SRC
set(LIB
bf_bmesh
bf_functions
- bf_intern_sky
+ bf_nodes_composite
+ bf_nodes_function
+ bf_nodes_geometry
+ bf_nodes_shader
+ bf_nodes_texture
)
if(WITH_BULLET)
list(APPEND INC_SYS
${BULLET_INCLUDE_DIRS}
- "../../../intern/rigidbody/"
+ ../../../intern/rigidbody
)
if(NOT WITH_SYSTEM_BULLET)
list(APPEND LIB
extern_bullet
- )
+ )
endif()
list(APPEND LIB
@@ -469,13 +153,6 @@ if(WITH_IMAGE_OPENEXR)
add_definitions(-DWITH_OPENEXR)
endif()
-if(WITH_COMPOSITOR)
- list(APPEND INC
- ../compositor
- )
- add_definitions(-DWITH_COMPOSITOR)
-endif()
-
if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
@@ -504,3 +181,6 @@ if(WITH_OPENVDB)
endif()
blender_add_lib(bf_nodes "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+# Needed so we can use dna_type_offsets.h for defaults initialization.
+add_dependencies(bf_nodes bf_dna)
diff --git a/source/blender/nodes/NOD_common.h b/source/blender/nodes/NOD_common.h
index 50ed992dcb6..e488352170b 100644
--- a/source/blender/nodes/NOD_common.h
+++ b/source/blender/nodes/NOD_common.h
@@ -35,9 +35,11 @@ void register_node_type_reroute(void);
void register_node_type_group_input(void);
void register_node_type_group_output(void);
-/* internal functions for editor */
+/* Internal functions for editor. */
+
struct bNodeSocket *node_group_find_input_socket(struct bNode *groupnode, const char *identifier);
struct bNodeSocket *node_group_find_output_socket(struct bNode *groupnode, const char *identifier);
+/** Make sure all group node in ntree, which use ngroup, are sync'd. */
void node_group_update(struct bNodeTree *ntree, struct bNode *node);
struct bNodeSocket *node_group_input_find_socket(struct bNode *node, const char *identifier);
@@ -45,6 +47,8 @@ struct bNodeSocket *node_group_output_find_socket(struct bNode *node, const char
void node_group_input_update(struct bNodeTree *ntree, struct bNode *node);
void node_group_output_update(struct bNodeTree *ntree, struct bNode *node);
+void node_internal_links_create(struct bNodeTree *ntree, struct bNode *node);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index d243577f68d..82faccc2c2d 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -43,6 +43,7 @@ void register_node_type_cmp_texture(void);
void register_node_type_cmp_value(void);
void register_node_type_cmp_rgb(void);
void register_node_type_cmp_curve_time(void);
+void register_node_type_cmp_scene_time(void);
void register_node_type_cmp_movieclip(void);
void register_node_type_cmp_composite(void);
@@ -62,6 +63,7 @@ void register_node_type_cmp_alphaover(void);
void register_node_type_cmp_zcombine(void);
void register_node_type_cmp_colorbalance(void);
void register_node_type_cmp_huecorrect(void);
+void register_node_type_cmp_convert_color_space(void);
void register_node_type_cmp_normal(void);
void register_node_type_cmp_curve_vec(void);
@@ -150,6 +152,75 @@ const char *node_cmp_rlayers_sock_to_pass(int sock_index);
void register_node_type_cmp_custom_group(bNodeType *ntype);
+void ntreeCompositExecTree(struct Scene *scene,
+ struct bNodeTree *ntree,
+ struct RenderData *rd,
+ int rendering,
+ int do_previews,
+ const struct ColorManagedViewSettings *view_settings,
+ const struct ColorManagedDisplaySettings *display_settings,
+ const char *view_name);
+
+/**
+ * Called from render pipeline, to tag render input and output.
+ * need to do all scenes, to prevent errors when you re-render 1 scene.
+ */
+void ntreeCompositTagRender(struct Scene *scene);
+
+/**
+ * Update the outputs of the render layer nodes.
+ * Since the outputs depend on the render engine, this part is a bit complex:
+ * - #ntreeCompositUpdateRLayers is called and loops over all render layer nodes.
+ * - Each render layer node calls the update function of the
+ * render engine that's used for its scene.
+ * - The render engine calls RE_engine_register_pass for each pass.
+ * - #RE_engine_register_pass calls #node_cmp_rlayers_register_pass.
+ */
+void ntreeCompositUpdateRLayers(struct bNodeTree *ntree);
+
+void ntreeCompositClearTags(struct bNodeTree *ntree);
+
+struct bNodeSocket *ntreeCompositOutputFileAddSocket(struct bNodeTree *ntree,
+ struct bNode *node,
+ const char *name,
+ struct ImageFormatData *im_format);
+
+int ntreeCompositOutputFileRemoveActiveSocket(struct bNodeTree *ntree, struct bNode *node);
+void ntreeCompositOutputFileSetPath(struct bNode *node,
+ struct bNodeSocket *sock,
+ const char *name);
+void ntreeCompositOutputFileSetLayer(struct bNode *node,
+ struct bNodeSocket *sock,
+ const char *name);
+/* needed in do_versions */
+void ntreeCompositOutputFileUniquePath(struct ListBase *list,
+ struct bNodeSocket *sock,
+ const char defname[],
+ char delim);
+void ntreeCompositOutputFileUniqueLayer(struct ListBase *list,
+ struct bNodeSocket *sock,
+ const char defname[],
+ char delim);
+
+void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *ntree, bNode *node);
+void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *ntree, bNode *node);
+
+void ntreeCompositCryptomatteSyncFromAdd(const Scene *scene, bNode *node);
+void ntreeCompositCryptomatteSyncFromRemove(bNode *node);
+bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node);
+int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node);
+void ntreeCompositCryptomatteLayerPrefix(const Scene *scene,
+ const bNode *node,
+ char *r_prefix,
+ size_t prefix_len);
+
+/**
+ * Update the runtime layer names with the crypto-matte layer names of the references render layer
+ * or image.
+ */
+void ntreeCompositCryptomatteUpdateLayerNames(const Scene *scene, bNode *node);
+struct CryptomatteSession *ntreeCompositCryptomatteSession(const Scene *scene, bNode *node);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh
index 60d84463a82..dc619deb5d2 100644
--- a/source/blender/nodes/NOD_derived_node_tree.hh
+++ b/source/blender/nodes/NOD_derived_node_tree.hh
@@ -72,8 +72,10 @@ class DTreeContext {
bool is_root() const;
};
-/* A (nullable) reference to a node and the context it is in. It is unique within an entire nested
- * node group hierarchy. This type is small and can be passed around by value. */
+/**
+ * A (nullable) reference to a node and the context it is in. It is unique within an entire nested
+ * node group hierarchy. This type is small and can be passed around by value.
+ */
class DNode {
private:
const DTreeContext *context_ = nullptr;
@@ -100,11 +102,13 @@ class DNode {
DOutputSocket output_by_identifier(StringRef identifier) const;
};
-/* A (nullable) reference to a socket and the context it is in. It is unique within an entire
+/**
+ * A (nullable) reference to a socket and the context it is in. It is unique within an entire
* nested node group hierarchy. This type is small and can be passed around by value.
*
* A #DSocket can represent an input or an output socket. If the type of a socket is known at
- * compile time is preferable to use #DInputSocket or #DOutputSocket instead. */
+ * compile time is preferable to use #DInputSocket or #DOutputSocket instead.
+ */
class DSocket {
protected:
const DTreeContext *context_ = nullptr;
@@ -129,7 +133,7 @@ class DSocket {
DNode node() const;
};
-/* A (nullable) reference to an input socket and the context it is in. */
+/** A (nullable) reference to an input socket and the context it is in. */
class DInputSocket : public DSocket {
public:
DInputSocket() = default;
@@ -142,10 +146,15 @@ class DInputSocket : public DSocket {
DOutputSocket get_corresponding_group_node_output() const;
Vector<DOutputSocket, 4> get_corresponding_group_input_sockets() const;
+ /**
+ * Call `origin_fn` for every "real" origin socket. "Real" means that reroutes, muted nodes
+ * and node groups are handled by this function. Origin sockets are ones where a node gets its
+ * inputs from.
+ */
void foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const;
};
-/* A (nullable) reference to an output socket and the context it is in. */
+/** A (nullable) reference to an output socket and the context it is in. */
class DOutputSocket : public DSocket {
public:
DOutputSocket() = default;
@@ -158,8 +167,24 @@ class DOutputSocket : public DSocket {
DInputSocket get_corresponding_group_node_input() const;
DInputSocket get_active_corresponding_group_output_socket() const;
- void foreach_target_socket(FunctionRef<void(DInputSocket)> target_fn,
- FunctionRef<void(DSocket)> skipped_fn) const;
+ struct TargetSocketPathInfo {
+ /** All sockets on the path from the current to the final target sockets, excluding `this`. */
+ Vector<DSocket, 16> sockets;
+ };
+
+ using ForeachTargetSocketFn =
+ FunctionRef<void(DInputSocket, const TargetSocketPathInfo &path_info)>;
+
+ /**
+ * Calls `target_fn` for every "real" target socket. "Real" means that reroutes, muted nodes
+ * and node groups are handled by this function. Target sockets are on the nodes that use the
+ * value from this socket.
+ */
+ void foreach_target_socket(ForeachTargetSocketFn target_fn) const;
+
+ private:
+ void foreach_target_socket(ForeachTargetSocketFn target_fn,
+ TargetSocketPathInfo &path_info) const;
};
class DerivedNodeTree {
@@ -169,16 +194,27 @@ class DerivedNodeTree {
VectorSet<const NodeTreeRef *> used_node_tree_refs_;
public:
+ /**
+ * Construct a new derived node tree for a given root node tree. The generated derived node tree
+ * does not own the used node tree refs (so that those can be used by others as well). The caller
+ * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the
+ * derived node tree.
+ */
DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs);
~DerivedNodeTree();
const DTreeContext &root_context() const;
Span<const NodeTreeRef *> used_node_tree_refs() const;
+ /**
+ * \return True when there is a link cycle. Unavailable sockets are ignored.
+ */
bool has_link_cycles() const;
bool has_undefined_nodes_or_sockets() const;
+ /** Calls the given callback on all nodes in the (possibly nested) derived node tree. */
void foreach_node(FunctionRef<void(DNode)> callback) const;
+ /** Generates a graph in dot format. The generated graph has all node groups inlined. */
std::string to_dot() const;
private:
@@ -202,9 +238,9 @@ using nodes::DSocket;
using nodes::DTreeContext;
} // namespace derived_node_tree_types
-/* --------------------------------------------------------------------
- * DTreeContext inline methods.
- */
+/* -------------------------------------------------------------------- */
+/** \name #DTreeContext Inline Methods
+ * \{ */
inline const NodeTreeRef &DTreeContext::tree() const
{
@@ -236,9 +272,11 @@ inline bool DTreeContext::is_root() const
return parent_context_ == nullptr;
}
-/* --------------------------------------------------------------------
- * DNode inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #DNode Inline Methods
+ * \{ */
inline DNode::DNode(const DTreeContext *context, const NodeRef *node_ref)
: context_(context), node_ref_(node_ref)
@@ -301,9 +339,11 @@ inline DOutputSocket DNode::output_by_identifier(StringRef identifier) const
return {context_, &node_ref_->output_by_identifier(identifier)};
}
-/* --------------------------------------------------------------------
- * DSocket inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #DSocket Inline Methods
+ * \{ */
inline DSocket::DSocket(const DTreeContext *context, const SocketRef *socket_ref)
: context_(context), socket_ref_(socket_ref)
@@ -362,9 +402,11 @@ inline DNode DSocket::node() const
return {context_, &socket_ref_->node()};
}
-/* --------------------------------------------------------------------
- * DInputSocket inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #DInputSocket Inline Methods
+ * \{ */
inline DInputSocket::DInputSocket(const DTreeContext *context, const InputSocketRef *socket_ref)
: DSocket(context, socket_ref)
@@ -386,9 +428,11 @@ inline const InputSocketRef *DInputSocket::operator->() const
return (const InputSocketRef *)socket_ref_;
}
-/* --------------------------------------------------------------------
- * DOutputSocket inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #DOutputSocket Inline Methods
+ * \{ */
inline DOutputSocket::DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket_ref)
: DSocket(context, socket_ref)
@@ -410,9 +454,11 @@ inline const OutputSocketRef *DOutputSocket::operator->() const
return (const OutputSocketRef *)socket_ref_;
}
-/* --------------------------------------------------------------------
- * DerivedNodeTree inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #DerivedNodeTree Inline Methods
+ * \{ */
inline const DTreeContext &DerivedNodeTree::root_context() const
{
@@ -424,4 +470,6 @@ inline Span<const NodeTreeRef *> DerivedNodeTree::used_node_tree_refs() const
return used_node_tree_refs_;
}
+/** \} */
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_function.h b/source/blender/nodes/NOD_function.h
index 9aa4c04000e..be3998a916c 100644
--- a/source/blender/nodes/NOD_function.h
+++ b/source/blender/nodes/NOD_function.h
@@ -22,15 +22,21 @@ extern "C" {
void register_node_type_fn_legacy_random_float(void);
+void register_node_type_fn_align_euler_to_vector(void);
void register_node_type_fn_boolean_math(void);
-void register_node_type_fn_float_compare(void);
+void register_node_type_fn_compare(void);
void register_node_type_fn_float_to_int(void);
+void register_node_type_fn_input_bool(void);
+void register_node_type_fn_input_color(void);
+void register_node_type_fn_input_int(void);
void register_node_type_fn_input_special_characters(void);
void register_node_type_fn_input_string(void);
void register_node_type_fn_input_vector(void);
void register_node_type_fn_random_value(void);
+void register_node_type_fn_replace_string(void);
+void register_node_type_fn_rotate_euler(void);
+void register_node_type_fn_slice_string(void);
void register_node_type_fn_string_length(void);
-void register_node_type_fn_string_substring(void);
void register_node_type_fn_value_to_string(void);
#ifdef __cplusplus
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index af8661d9b8d..609d92c09df 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -16,12 +16,12 @@
#pragma once
+#include "BKE_node.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BKE_node.h"
-
extern struct bNodeTreeType *ntreeType_Geometry;
void register_node_tree_type_geo(void);
@@ -31,10 +31,25 @@ void register_node_type_geo_custom_group(bNodeType *ntype);
void register_node_type_geo_legacy_attribute_proximity(void);
void register_node_type_geo_legacy_attribute_randomize(void);
+void register_node_type_geo_legacy_attribute_transfer(void);
+void register_node_type_geo_legacy_curve_endpoints(void);
+void register_node_type_geo_legacy_curve_reverse(void);
+void register_node_type_geo_legacy_curve_set_handles(void);
+void register_node_type_geo_legacy_curve_spline_type(void);
+void register_node_type_geo_legacy_curve_subdivide(void);
+void register_node_type_geo_legacy_curve_to_points(void);
+void register_node_type_geo_legacy_delete_geometry(void);
+void register_node_type_geo_legacy_edge_split(void);
void register_node_type_geo_legacy_material_assign(void);
+void register_node_type_geo_legacy_mesh_to_curve(void);
+void register_node_type_geo_legacy_points_to_volume(void);
+void register_node_type_geo_legacy_raycast(void);
+void register_node_type_geo_legacy_select_by_handle_type(void);
void register_node_type_geo_legacy_select_by_material(void);
-void register_node_type_geo_legacy_curve_reverse(void);
+void register_node_type_geo_legacy_subdivision_surface(void);
+void register_node_type_geo_legacy_volume_to_mesh(void);
+void register_node_type_geo_accumulate_field(void);
void register_node_type_geo_align_rotation_to_vector(void);
void register_node_type_geo_attribute_capture(void);
void register_node_type_geo_attribute_clamp(void);
@@ -43,6 +58,7 @@ void register_node_type_geo_attribute_combine_xyz(void);
void register_node_type_geo_attribute_compare(void);
void register_node_type_geo_attribute_convert(void);
void register_node_type_geo_attribute_curve_map(void);
+void register_node_type_geo_attribute_domain_size(void);
void register_node_type_geo_attribute_fill(void);
void register_node_type_geo_attribute_map_range(void);
void register_node_type_geo_attribute_math(void);
@@ -50,18 +66,18 @@ void register_node_type_geo_attribute_mix(void);
void register_node_type_geo_attribute_remove(void);
void register_node_type_geo_attribute_separate_xyz(void);
void register_node_type_geo_attribute_statistic(void);
-void register_node_type_geo_attribute_transfer(void);
void register_node_type_geo_attribute_vector_math(void);
void register_node_type_geo_attribute_vector_rotate(void);
void register_node_type_geo_boolean(void);
void register_node_type_geo_bounding_box(void);
void register_node_type_geo_collection_info(void);
void register_node_type_geo_convex_hull(void);
-void register_node_type_geo_curve_endpoints(void);
+void register_node_type_geo_curve_endpoint_selection(void);
void register_node_type_geo_curve_fill(void);
void register_node_type_geo_curve_fillet(void);
+void register_node_type_geo_curve_handle_type_selection(void);
void register_node_type_geo_curve_length(void);
-void register_node_type_geo_curve_parameter(void);
+void register_node_type_geo_curve_primitive_arc(void);
void register_node_type_geo_curve_primitive_bezier_segment(void);
void register_node_type_geo_curve_primitive_circle(void);
void register_node_type_geo_curve_primitive_line(void);
@@ -73,6 +89,7 @@ void register_node_type_geo_curve_resample(void);
void register_node_type_geo_curve_reverse(void);
void register_node_type_geo_curve_sample(void);
void register_node_type_geo_curve_set_handles(void);
+void register_node_type_geo_curve_spline_parameter(void);
void register_node_type_geo_curve_spline_type(void);
void register_node_type_geo_curve_subdivide(void);
void register_node_type_geo_curve_to_mesh(void);
@@ -80,18 +97,42 @@ void register_node_type_geo_curve_to_points(void);
void register_node_type_geo_curve_trim(void);
void register_node_type_geo_delete_geometry(void);
void register_node_type_geo_distribute_points_on_faces(void);
+void register_node_type_geo_dual_mesh(void);
void register_node_type_geo_edge_split(void);
+void register_node_type_geo_extrude_mesh(void);
+void register_node_type_geo_field_at_index(void);
+void register_node_type_geo_flip_faces(void);
+void register_node_type_geo_geometry_to_instance(void);
+void register_node_type_geo_image_texture(void);
+void register_node_type_geo_input_curve_handles(void);
+void register_node_type_geo_input_curve_tilt(void);
+void register_node_type_geo_input_id(void);
void register_node_type_geo_input_index(void);
+void register_node_type_geo_input_material_index(void);
void register_node_type_geo_input_material(void);
+void register_node_type_geo_input_mesh_edge_angle(void);
+void register_node_type_geo_input_mesh_edge_neighbors(void);
+void register_node_type_geo_input_mesh_edge_vertices(void);
+void register_node_type_geo_input_mesh_face_area(void);
+void register_node_type_geo_input_mesh_face_neighbors(void);
+void register_node_type_geo_input_mesh_island(void);
+void register_node_type_geo_input_mesh_vertex_neighbors(void);
void register_node_type_geo_input_normal(void);
void register_node_type_geo_input_position(void);
+void register_node_type_geo_input_radius(void);
+void register_node_type_geo_input_scene_time(void);
+void register_node_type_geo_input_shade_smooth(void);
+void register_node_type_geo_input_spline_cyclic(void);
+void register_node_type_geo_input_spline_length(void);
+void register_node_type_geo_input_spline_resolution(void);
void register_node_type_geo_input_tangent(void);
void register_node_type_geo_instance_on_points(void);
+void register_node_type_geo_instances_to_points(void);
void register_node_type_geo_is_viewport(void);
void register_node_type_geo_join_geometry(void);
-void register_node_type_geo_material_assign(void);
void register_node_type_geo_material_replace(void);
void register_node_type_geo_material_selection(void);
+void register_node_type_geo_merge_by_distance(void);
void register_node_type_geo_mesh_primitive_circle(void);
void register_node_type_geo_mesh_primitive_cone(void);
void register_node_type_geo_mesh_primitive_cube(void);
@@ -115,15 +156,31 @@ void register_node_type_geo_points_to_volume(void);
void register_node_type_geo_proximity(void);
void register_node_type_geo_raycast(void);
void register_node_type_geo_realize_instances(void);
+void register_node_type_geo_rotate_instances(void);
void register_node_type_geo_sample_texture(void);
+void register_node_type_geo_scale_elements(void);
+void register_node_type_geo_scale_instances(void);
void register_node_type_geo_select_by_handle_type(void);
void register_node_type_geo_separate_components(void);
+void register_node_type_geo_separate_geometry(void);
+void register_node_type_geo_set_curve_handles(void);
+void register_node_type_geo_set_curve_radius(void);
+void register_node_type_geo_set_curve_tilt(void);
+void register_node_type_geo_set_id(void);
+void register_node_type_geo_set_material_index(void);
+void register_node_type_geo_set_material(void);
+void register_node_type_geo_set_point_radius(void);
void register_node_type_geo_set_position(void);
+void register_node_type_geo_set_shade_smooth(void);
+void register_node_type_geo_set_spline_cyclic(void);
+void register_node_type_geo_set_spline_resolution(void);
void register_node_type_geo_string_join(void);
void register_node_type_geo_string_to_curves(void);
void register_node_type_geo_subdivision_surface(void);
void register_node_type_geo_switch(void);
+void register_node_type_geo_transfer_attribute(void);
void register_node_type_geo_transform(void);
+void register_node_type_geo_translate_instances(void);
void register_node_type_geo_triangulate(void);
void register_node_type_geo_viewer(void);
void register_node_type_geo_volume_to_mesh(void);
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index 962e1c3c48f..7060760237a 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -28,6 +28,8 @@
#include "NOD_derived_node_tree.hh"
#include "NOD_geometry_nodes_eval_log.hh"
+#include "GEO_realize_instances.hh"
+
struct Depsgraph;
struct ModifierData;
@@ -36,8 +38,8 @@ namespace blender::nodes {
using bke::AnonymousAttributeFieldInput;
using bke::AttributeFieldInput;
using bke::AttributeIDRef;
-using bke::geometry_set_realize_instances;
using bke::GeometryComponentFieldContext;
+using bke::GeometryFieldInput;
using bke::OutputAttribute;
using bke::OutputAttribute_Typed;
using bke::ReadAttributeLookup;
@@ -57,13 +59,9 @@ using fn::GPointer;
using fn::GSpan;
using fn::GVArray;
using fn::GVArray_GSpan;
-using fn::GVArray_Span;
-using fn::GVArray_Typed;
-using fn::GVArrayPtr;
using fn::GVMutableArray;
using fn::GVMutableArray_GSpan;
-using fn::GVMutableArray_Typed;
-using fn::GVMutableArrayPtr;
+using fn::ValueOrField;
using geometry_nodes_eval_log::NodeWarningType;
/**
@@ -122,6 +120,8 @@ class GeoNodeExecParamsProvider {
virtual bool output_is_required(StringRef identifier) const = 0;
virtual bool lazy_require_input(StringRef identifier) = 0;
virtual bool lazy_output_is_required(StringRef identifier) const = 0;
+
+ virtual void set_default_remaining_outputs() = 0;
};
class GeoNodeExecParams {
@@ -134,12 +134,8 @@ class GeoNodeExecParams {
}
template<typename T>
- static inline constexpr bool is_stored_as_field_v = std::is_same_v<T, float> ||
- std::is_same_v<T, int> ||
- std::is_same_v<T, bool> ||
- std::is_same_v<T, ColorGeometry4f> ||
- std::is_same_v<T, float3> ||
- std::is_same_v<T, std::string>;
+ static inline constexpr bool is_field_base_type_v =
+ is_same_any_v<T, float, int, bool, ColorGeometry4f, float3, std::string>;
/**
* Get the input value for the input socket with the given identifier.
@@ -162,19 +158,31 @@ class GeoNodeExecParams {
*/
template<typename T> T extract_input(StringRef identifier)
{
- if constexpr (is_stored_as_field_v<T>) {
- Field<T> field = this->extract_input<Field<T>>(identifier);
- return fn::evaluate_constant_field(field);
+ if constexpr (is_field_base_type_v<T>) {
+ ValueOrField<T> value_or_field = this->extract_input<ValueOrField<T>>(identifier);
+ return value_or_field.as_value();
+ }
+ else if constexpr (fn::is_field_v<T>) {
+ using BaseType = typename T::base_type;
+ ValueOrField<BaseType> value_or_field = this->extract_input<ValueOrField<BaseType>>(
+ identifier);
+ return value_or_field.as_field();
}
else {
#ifdef DEBUG
this->check_input_access(identifier, &CPPType::get<T>());
#endif
GMutablePointer gvalue = this->extract_input(identifier);
- return gvalue.relocate_out<T>();
+ T value = gvalue.relocate_out<T>();
+ if constexpr (std::is_same_v<T, GeometrySet>) {
+ this->check_input_geometry_set(identifier, value);
+ }
+ return value;
}
}
+ void check_input_geometry_set(StringRef identifier, const GeometrySet &geometry_set) const;
+
/**
* Get input as vector for multi input socket with the given identifier.
*
@@ -185,9 +193,9 @@ class GeoNodeExecParams {
Vector<GMutablePointer> gvalues = provider_->extract_multi_input(identifier);
Vector<T> values;
for (GMutablePointer gvalue : gvalues) {
- if constexpr (is_stored_as_field_v<T>) {
- const Field<T> field = gvalue.relocate_out<Field<T>>();
- values.append(fn::evaluate_constant_field(field));
+ if constexpr (is_field_base_type_v<T>) {
+ const ValueOrField<T> value_or_field = gvalue.relocate_out<ValueOrField<T>>();
+ values.append(value_or_field.as_value());
}
else {
values.append(gvalue.relocate_out<T>());
@@ -199,11 +207,16 @@ class GeoNodeExecParams {
/**
* Get the input value for the input socket with the given identifier.
*/
- template<typename T> const T get_input(StringRef identifier) const
+ template<typename T> T get_input(StringRef identifier) const
{
- if constexpr (is_stored_as_field_v<T>) {
- const Field<T> &field = this->get_input<Field<T>>(identifier);
- return fn::evaluate_constant_field(field);
+ if constexpr (is_field_base_type_v<T>) {
+ ValueOrField<T> value_or_field = this->get_input<ValueOrField<T>>(identifier);
+ return value_or_field.as_value();
+ }
+ else if constexpr (fn::is_field_v<T>) {
+ using BaseType = typename T::base_type;
+ ValueOrField<BaseType> value_or_field = this->get_input<ValueOrField<BaseType>>(identifier);
+ return value_or_field.as_field();
}
else {
#ifdef DEBUG
@@ -211,7 +224,11 @@ class GeoNodeExecParams {
#endif
GPointer gvalue = provider_->get_input(identifier);
BLI_assert(gvalue.is_type<T>());
- return *(const T *)gvalue.get();
+ const T &value = *(const T *)gvalue.get();
+ if constexpr (std::is_same_v<T, GeometrySet>) {
+ this->check_input_geometry_set(identifier, value);
+ }
+ return value;
}
}
@@ -221,9 +238,12 @@ class GeoNodeExecParams {
template<typename T> void set_output(StringRef identifier, T &&value)
{
using StoredT = std::decay_t<T>;
- if constexpr (is_stored_as_field_v<StoredT>) {
- this->set_output<Field<StoredT>>(identifier,
- fn::make_constant_field<StoredT>(std::forward<T>(value)));
+ if constexpr (is_field_base_type_v<StoredT>) {
+ this->set_output(identifier, ValueOrField<StoredT>(std::forward<T>(value)));
+ }
+ else if constexpr (fn::is_field_v<StoredT>) {
+ using BaseType = typename StoredT::base_type;
+ this->set_output(identifier, ValueOrField<BaseType>(std::forward<T>(value)));
}
else {
const CPPType &type = CPPType::get<StoredT>();
@@ -306,21 +326,21 @@ class GeoNodeExecParams {
* \note This will add an error message if the string socket is active and
* the input attribute does not exist.
*/
- GVArrayPtr get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- const AttributeDomain domain,
- const CustomDataType type,
- const void *default_value) const;
+ GVArray get_input_attribute(const StringRef name,
+ const GeometryComponent &component,
+ AttributeDomain domain,
+ const CustomDataType type,
+ const void *default_value) const;
template<typename T>
- GVArray_Typed<T> get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- const AttributeDomain domain,
- const T &default_value) const
+ VArray<T> get_input_attribute(const StringRef name,
+ const GeometryComponent &component,
+ const AttributeDomain domain,
+ const T &default_value) const
{
const CustomDataType type = bke::cpp_type_to_custom_data_type(CPPType::get<T>());
- GVArrayPtr varray = this->get_input_attribute(name, component, domain, type, &default_value);
- return GVArray_Typed<T>(std::move(varray));
+ GVArray varray = this->get_input_attribute(name, component, domain, type, &default_value);
+ return varray.typed<T>();
}
/**
@@ -331,9 +351,18 @@ class GeoNodeExecParams {
const GeometryComponent &component,
const CustomDataType default_type) const;
+ /**
+ * If any of the corresponding input sockets are attributes instead of single values,
+ * use the highest priority attribute domain from among them.
+ * Otherwise return the default domain.
+ */
AttributeDomain get_highest_priority_input_domain(Span<std::string> names,
const GeometryComponent &component,
- const AttributeDomain default_domain) const;
+ AttributeDomain default_domain) const;
+
+ std::string attribute_producer_name() const;
+
+ void set_default_remaining_outputs();
private:
/* Utilities for detecting common errors at when using this class. */
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
index ff8e137e341..ac2c29b4ec2 100644
--- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -41,6 +41,8 @@
#include "NOD_derived_node_tree.hh"
+#include <chrono>
+
struct SpaceNode;
struct SpaceSpreadsheet;
@@ -76,6 +78,31 @@ class GenericValueLog : public ValueLog {
}
};
+class GFieldValueLog : public ValueLog {
+ private:
+ fn::GField field_;
+ const fn::CPPType &type_;
+ Vector<std::string> input_tooltips_;
+
+ public:
+ GFieldValueLog(fn::GField field, bool log_full_field);
+
+ const fn::GField &field() const
+ {
+ return field_;
+ }
+
+ Span<std::string> input_tooltips() const
+ {
+ return input_tooltips_;
+ }
+
+ const fn::CPPType &type() const
+ {
+ return type_;
+ }
+};
+
struct GeometryAttributeInfo {
std::string name;
AttributeDomain domain;
@@ -109,7 +136,7 @@ class GeometryValueLog : public ValueLog {
std::optional<PointCloudInfo> pointcloud_info;
std::optional<InstancesInfo> instances_info;
- GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry);
+ GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry = false);
Span<GeometryAttributeInfo> attributes() const
{
@@ -144,6 +171,16 @@ struct NodeWithWarning {
NodeWarning warning;
};
+struct NodeWithExecutionTime {
+ DNode node;
+ std::chrono::microseconds exec_time;
+};
+
+struct NodeWithDebugMessage {
+ DNode node;
+ std::string message;
+};
+
/** The same value can be referenced by multiple sockets when they are linked. */
struct ValueOfSockets {
Span<DSocket> sockets;
@@ -164,6 +201,8 @@ class LocalGeoLogger {
std::unique_ptr<LinearAllocator<>> allocator_;
Vector<ValueOfSockets> values_;
Vector<NodeWithWarning> node_warnings_;
+ Vector<NodeWithExecutionTime> node_exec_times_;
+ Vector<NodeWithDebugMessage> node_debug_messages_;
friend ModifierLog;
@@ -176,26 +215,49 @@ class LocalGeoLogger {
void log_value_for_sockets(Span<DSocket> sockets, GPointer value);
void log_multi_value_socket(DSocket socket, Span<GPointer> values);
void log_node_warning(DNode node, NodeWarningType type, std::string message);
+ void log_execution_time(DNode node, std::chrono::microseconds exec_time);
+ /**
+ * Log a message that will be displayed in the node editor next to the node.
+ * This should only be used for debugging purposes and not to display information to users.
+ */
+ void log_debug_message(DNode node, std::string message);
};
/** The root logger class. */
class GeoLogger {
private:
- /** The entire geometry of sockets in this set should be cached, because e.g. the spreadsheet
- * displays the data. We don't log the entire geometry at all places, because that would require
- * way too much memory. */
- Set<DSocket> log_full_geometry_sockets_;
+ /**
+ * Log the entire value for these sockets, because they may be inspected afterwards.
+ * We don't log everything, because that would take up too much memory and cause significant
+ * slowdowns.
+ */
+ Set<DSocket> log_full_sockets_;
threading::EnumerableThreadSpecific<LocalGeoLogger> threadlocals_;
+ /* These are only optional since they don't have a default constructor. */
+ std::unique_ptr<GeometryValueLog> input_geometry_log_;
+ std::unique_ptr<GeometryValueLog> output_geometry_log_;
+
friend LocalGeoLogger;
+ friend ModifierLog;
public:
- GeoLogger(Set<DSocket> log_full_geometry_sockets)
- : log_full_geometry_sockets_(std::move(log_full_geometry_sockets)),
+ GeoLogger(Set<DSocket> log_full_sockets)
+ : log_full_sockets_(std::move(log_full_sockets)),
threadlocals_([this]() { return LocalGeoLogger(*this); })
{
}
+ void log_input_geometry(const GeometrySet &geometry)
+ {
+ input_geometry_log_ = std::make_unique<GeometryValueLog>(geometry);
+ }
+
+ void log_output_geometry(const GeometrySet &geometry)
+ {
+ output_geometry_log_ = std::make_unique<GeometryValueLog>(geometry);
+ }
+
LocalGeoLogger &local()
{
return threadlocals_.local();
@@ -232,12 +294,15 @@ class NodeLog {
Vector<SocketLog> input_logs_;
Vector<SocketLog> output_logs_;
Vector<NodeWarning, 0> warnings_;
+ Vector<std::string, 0> debug_messages_;
+ std::chrono::microseconds exec_time_;
friend ModifierLog;
public:
const SocketLog *lookup_socket_log(eNodeSocketInOut in_out, int index) const;
const SocketLog *lookup_socket_log(const bNode &node, const bNodeSocket &socket) const;
+ void execution_time(std::chrono::microseconds exec_time);
Span<SocketLog> input_logs() const
{
@@ -254,6 +319,16 @@ class NodeLog {
return warnings_;
}
+ Span<std::string> debug_messages() const
+ {
+ return debug_messages_;
+ }
+
+ std::chrono::microseconds execution_time() const
+ {
+ return exec_time_;
+ }
+
Vector<const GeometryAttributeInfo *> lookup_available_attributes() const;
};
@@ -281,6 +356,9 @@ class ModifierLog {
destruct_ptr<TreeLog> root_tree_logs_;
Vector<destruct_ptr<ValueLog>> logged_values_;
+ std::unique_ptr<GeometryValueLog> input_geometry_log_;
+ std::unique_ptr<GeometryValueLog> output_geometry_log_;
+
public:
ModifierLog(GeoLogger &logger);
@@ -301,6 +379,9 @@ class ModifierLog {
const SpaceSpreadsheet &sspreadsheet);
void foreach_node_log(FunctionRef<void(const NodeLog &)> fn) const;
+ const GeometryValueLog *input_geometry_log() const;
+ const GeometryValueLog *output_geometry_log() const;
+
private:
using LogByTreeContext = Map<const DTreeContext *, TreeLog *>;
diff --git a/source/blender/nodes/NOD_math_functions.hh b/source/blender/nodes/NOD_math_functions.hh
index 9443be820d1..6ea89beee2e 100644
--- a/source/blender/nodes/NOD_math_functions.hh
+++ b/source/blender/nodes/NOD_math_functions.hh
@@ -18,9 +18,9 @@
#include "DNA_node_types.h"
-#include "BLI_float3.hh"
#include "BLI_math_base_safe.h"
#include "BLI_math_rotation.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_string_ref.hh"
namespace blender::nodes {
@@ -36,9 +36,9 @@ struct FloatMathOperationInfo {
}
};
-const FloatMathOperationInfo *get_float_math_operation_info(const int operation);
-const FloatMathOperationInfo *get_float3_math_operation_info(const int operation);
-const FloatMathOperationInfo *get_float_compare_operation_info(const int operation);
+const FloatMathOperationInfo *get_float_math_operation_info(int operation);
+const FloatMathOperationInfo *get_float3_math_operation_info(int operation);
+const FloatMathOperationInfo *get_float_compare_operation_info(int operation);
/**
* This calls the `callback` with two arguments:
@@ -193,7 +193,7 @@ inline bool try_dispatch_float_math_fl_fl_fl_to_fl(const int operation, Callback
case NODE_MATH_SMOOTH_MIN:
return dispatch([](float a, float b, float c) { return smoothminf(a, b, c); });
case NODE_MATH_SMOOTH_MAX:
- return dispatch([](float a, float b, float c) { return -smoothminf(-a, -b, -c); });
+ return dispatch([](float a, float b, float c) { return -smoothminf(-a, -b, c); });
case NODE_MATH_WRAP:
return dispatch([](float a, float b, float c) { return wrapf(a, b, c); });
}
@@ -204,7 +204,7 @@ inline bool try_dispatch_float_math_fl_fl_fl_to_fl(const int operation, Callback
* This is similar to try_dispatch_float_math_fl_to_fl, just with a different callback signature.
*/
template<typename Callback>
-inline bool try_dispatch_float_math_fl_fl_to_bool(const FloatCompareOperation operation,
+inline bool try_dispatch_float_math_fl_fl_to_bool(const NodeCompareOperation operation,
Callback &&callback)
{
const FloatMathOperationInfo *info = get_float_compare_operation_info(operation);
@@ -219,13 +219,13 @@ inline bool try_dispatch_float_math_fl_fl_to_bool(const FloatCompareOperation op
};
switch (operation) {
- case NODE_FLOAT_COMPARE_LESS_THAN:
+ case NODE_COMPARE_LESS_THAN:
return dispatch([](float a, float b) { return a < b; });
- case NODE_FLOAT_COMPARE_LESS_EQUAL:
+ case NODE_COMPARE_LESS_EQUAL:
return dispatch([](float a, float b) { return a <= b; });
- case NODE_FLOAT_COMPARE_GREATER_THAN:
+ case NODE_COMPARE_GREATER_THAN:
return dispatch([](float a, float b) { return a > b; });
- case NODE_FLOAT_COMPARE_GREATER_EQUAL:
+ case NODE_COMPARE_GREATER_EQUAL:
return dispatch([](float a, float b) { return a >= b; });
default:
return false;
@@ -240,6 +240,8 @@ template<typename Callback>
inline bool try_dispatch_float_math_fl3_fl3_to_fl3(const NodeVectorMathOperation operation,
Callback &&callback)
{
+ using namespace blender::math;
+
const FloatMathOperationInfo *info = get_float3_math_operation_info(operation);
if (info == nullptr) {
return false;
@@ -259,40 +261,21 @@ inline bool try_dispatch_float_math_fl3_fl3_to_fl3(const NodeVectorMathOperation
case NODE_VECTOR_MATH_MULTIPLY:
return dispatch([](float3 a, float3 b) { return a * b; });
case NODE_VECTOR_MATH_DIVIDE:
- return dispatch([](float3 a, float3 b) {
- return float3(safe_divide(a.x, b.x), safe_divide(a.y, b.y), safe_divide(a.z, b.z));
- });
+ return dispatch([](float3 a, float3 b) { return safe_divide(a, b); });
case NODE_VECTOR_MATH_CROSS_PRODUCT:
- return dispatch([](float3 a, float3 b) { return float3::cross_high_precision(a, b); });
+ return dispatch([](float3 a, float3 b) { return cross_high_precision(a, b); });
case NODE_VECTOR_MATH_PROJECT:
- return dispatch([](float3 a, float3 b) {
- float length_squared = b.length_squared();
- return (length_squared != 0.0) ? (float3::dot(a, b) / length_squared) * b : float3(0.0f);
- });
+ return dispatch([](float3 a, float3 b) { return project(a, b); });
case NODE_VECTOR_MATH_REFLECT:
- return dispatch([](float3 a, float3 b) {
- b.normalize();
- return a.reflected(b);
- });
+ return dispatch([](float3 a, float3 b) { return reflect(a, normalize(b)); });
case NODE_VECTOR_MATH_SNAP:
- return dispatch([](float3 a, float3 b) {
- return float3(floor(safe_divide(a.x, b.x)),
- floor(safe_divide(a.y, b.y)),
- floor(safe_divide(a.z, b.z))) *
- b;
- });
+ return dispatch([](float3 a, float3 b) { return floor(safe_divide(a, b)) * b; });
case NODE_VECTOR_MATH_MODULO:
- return dispatch([](float3 a, float3 b) {
- return float3(safe_modf(a.x, b.x), safe_modf(a.y, b.y), safe_modf(a.z, b.z));
- });
+ return dispatch([](float3 a, float3 b) { return mod(a, b); });
case NODE_VECTOR_MATH_MINIMUM:
- return dispatch([](float3 a, float3 b) {
- return float3(min_ff(a.x, b.x), min_ff(a.y, b.y), min_ff(a.z, b.z));
- });
+ return dispatch([](float3 a, float3 b) { return min(a, b); });
case NODE_VECTOR_MATH_MAXIMUM:
- return dispatch([](float3 a, float3 b) {
- return float3(max_ff(a.x, b.x), max_ff(a.y, b.y), max_ff(a.z, b.z));
- });
+ return dispatch([](float3 a, float3 b) { return max(a, b); });
default:
return false;
}
@@ -306,6 +289,8 @@ template<typename Callback>
inline bool try_dispatch_float_math_fl3_fl3_to_fl(const NodeVectorMathOperation operation,
Callback &&callback)
{
+ using namespace blender::math;
+
const FloatMathOperationInfo *info = get_float3_math_operation_info(operation);
if (info == nullptr) {
return false;
@@ -319,9 +304,9 @@ inline bool try_dispatch_float_math_fl3_fl3_to_fl(const NodeVectorMathOperation
switch (operation) {
case NODE_VECTOR_MATH_DOT_PRODUCT:
- return dispatch([](float3 a, float3 b) { return float3::dot(a, b); });
+ return dispatch([](float3 a, float3 b) { return dot(a, b); });
case NODE_VECTOR_MATH_DISTANCE:
- return dispatch([](float3 a, float3 b) { return float3::distance(a, b); });
+ return dispatch([](float3 a, float3 b) { return distance(a, b); });
default:
return false;
}
@@ -335,6 +320,8 @@ template<typename Callback>
inline bool try_dispatch_float_math_fl3_fl3_fl3_to_fl3(const NodeVectorMathOperation operation,
Callback &&callback)
{
+ using namespace blender::math;
+
const FloatMathOperationInfo *info = get_float3_math_operation_info(operation);
if (info == nullptr) {
return false;
@@ -354,7 +341,7 @@ inline bool try_dispatch_float_math_fl3_fl3_fl3_to_fl3(const NodeVectorMathOpera
return float3(wrapf(a.x, b.x, c.x), wrapf(a.y, b.y, c.y), wrapf(a.z, b.z, c.z));
});
case NODE_VECTOR_MATH_FACEFORWARD:
- return dispatch([](float3 a, float3 b, float3 c) { return float3::faceforward(a, b, c); });
+ return dispatch([](float3 a, float3 b, float3 c) { return faceforward(a, b, c); });
default:
return false;
}
@@ -368,6 +355,8 @@ template<typename Callback>
inline bool try_dispatch_float_math_fl3_fl3_fl_to_fl3(const NodeVectorMathOperation operation,
Callback &&callback)
{
+ using namespace blender::math;
+
const FloatMathOperationInfo *info = get_float3_math_operation_info(operation);
if (info == nullptr) {
return false;
@@ -381,8 +370,7 @@ inline bool try_dispatch_float_math_fl3_fl3_fl_to_fl3(const NodeVectorMathOperat
switch (operation) {
case NODE_VECTOR_MATH_REFRACT:
- return dispatch(
- [](float3 a, float3 b, float c) { return float3::refract(a, b.normalized(), c); });
+ return dispatch([](float3 a, float3 b, float c) { return refract(a, normalize(b), c); });
default:
return false;
}
@@ -396,6 +384,8 @@ template<typename Callback>
inline bool try_dispatch_float_math_fl3_to_fl(const NodeVectorMathOperation operation,
Callback &&callback)
{
+ using namespace blender::math;
+
const FloatMathOperationInfo *info = get_float3_math_operation_info(operation);
if (info == nullptr) {
return false;
@@ -409,7 +399,7 @@ inline bool try_dispatch_float_math_fl3_to_fl(const NodeVectorMathOperation oper
switch (operation) {
case NODE_VECTOR_MATH_LENGTH:
- return dispatch([](float3 in) { return in.length(); });
+ return dispatch([](float3 in) { return length(in); });
default:
return false;
}
@@ -450,6 +440,8 @@ template<typename Callback>
inline bool try_dispatch_float_math_fl3_to_fl3(const NodeVectorMathOperation operation,
Callback &&callback)
{
+ using namespace blender::math;
+
const FloatMathOperationInfo *info = get_float3_math_operation_info(operation);
if (info == nullptr) {
return false;
@@ -463,20 +455,15 @@ inline bool try_dispatch_float_math_fl3_to_fl3(const NodeVectorMathOperation ope
switch (operation) {
case NODE_VECTOR_MATH_NORMALIZE:
- return dispatch([](float3 in) {
- float3 out = in;
- out.normalize();
- return out;
- }); /* Should be safe. */
+ return dispatch([](float3 in) { return normalize(in); }); /* Should be safe. */
case NODE_VECTOR_MATH_FLOOR:
- return dispatch([](float3 in) { return float3(floor(in.x), floor(in.y), floor(in.z)); });
+ return dispatch([](float3 in) { return floor(in); });
case NODE_VECTOR_MATH_CEIL:
- return dispatch([](float3 in) { return float3(ceil(in.x), ceil(in.y), ceil(in.z)); });
+ return dispatch([](float3 in) { return ceil(in); });
case NODE_VECTOR_MATH_FRACTION:
- return dispatch(
- [](float3 in) { return in - float3(floor(in.x), floor(in.y), floor(in.z)); });
+ return dispatch([](float3 in) { return fract(in); });
case NODE_VECTOR_MATH_ABSOLUTE:
- return dispatch([](float3 in) { return float3::abs(in); });
+ return dispatch([](float3 in) { return abs(in); });
case NODE_VECTOR_MATH_SINE:
return dispatch([](float3 in) { return float3(sinf(in.x), sinf(in.y), sinf(in.z)); });
case NODE_VECTOR_MATH_COSINE:
diff --git a/source/blender/nodes/NOD_multi_function.hh b/source/blender/nodes/NOD_multi_function.hh
index 58816544dc1..367ceaab9f7 100644
--- a/source/blender/nodes/NOD_multi_function.hh
+++ b/source/blender/nodes/NOD_multi_function.hh
@@ -33,15 +33,15 @@ class NodeMultiFunctions;
*/
class NodeMultiFunctionBuilder : NonCopyable, NonMovable {
private:
- ResourceScope &resource_scope_;
bNode &node_;
bNodeTree &tree_;
+ std::shared_ptr<MultiFunction> owned_built_fn_;
const MultiFunction *built_fn_ = nullptr;
friend NodeMultiFunctions;
public:
- NodeMultiFunctionBuilder(ResourceScope &resource_scope, bNode &node, bNodeTree &tree);
+ NodeMultiFunctionBuilder(bNode &node, bNodeTree &tree);
/**
* Assign a multi-function for the current node. The input and output parameters of the function
@@ -58,31 +58,33 @@ class NodeMultiFunctionBuilder : NonCopyable, NonMovable {
bNode &node();
bNodeTree &tree();
-
- ResourceScope &resource_scope();
};
/**
* Gives access to multi-functions for all nodes in a node tree that support them.
*/
class NodeMultiFunctions {
+ public:
+ struct Item {
+ const MultiFunction *fn = nullptr;
+ std::shared_ptr<MultiFunction> owned_fn;
+ };
+
private:
- Map<const bNode *, const MultiFunction *> map_;
+ Map<const bNode *, Item> map_;
public:
- NodeMultiFunctions(const DerivedNodeTree &tree, ResourceScope &resource_scope);
+ NodeMultiFunctions(const DerivedNodeTree &tree);
- const MultiFunction *try_get(const DNode &node) const;
+ const Item &try_get(const DNode &node) const;
};
-/* --------------------------------------------------------------------
- * NodeMultiFunctionBuilder inline methods.
- */
+/* -------------------------------------------------------------------- */
+/** \name #NodeMultiFunctionBuilder Inline Methods
+ * \{ */
-inline NodeMultiFunctionBuilder::NodeMultiFunctionBuilder(ResourceScope &resource_scope,
- bNode &node,
- bNodeTree &tree)
- : resource_scope_(resource_scope), node_(node), tree_(tree)
+inline NodeMultiFunctionBuilder::NodeMultiFunctionBuilder(bNode &node, bNodeTree &tree)
+ : node_(node), tree_(tree)
{
}
@@ -96,11 +98,6 @@ inline bNodeTree &NodeMultiFunctionBuilder::tree()
return tree_;
}
-inline ResourceScope &NodeMultiFunctionBuilder::resource_scope()
-{
- return resource_scope_;
-}
-
inline void NodeMultiFunctionBuilder::set_matching_fn(const MultiFunction *fn)
{
built_fn_ = fn;
@@ -108,23 +105,32 @@ inline void NodeMultiFunctionBuilder::set_matching_fn(const MultiFunction *fn)
inline void NodeMultiFunctionBuilder::set_matching_fn(const MultiFunction &fn)
{
- this->set_matching_fn(&fn);
+ built_fn_ = &fn;
}
template<typename T, typename... Args>
inline void NodeMultiFunctionBuilder::construct_and_set_matching_fn(Args &&...args)
{
- const T &fn = resource_scope_.construct<T>(std::forward<Args>(args)...);
- this->set_matching_fn(&fn);
+ owned_built_fn_ = std::make_shared<T>(std::forward<Args>(args)...);
+ built_fn_ = &*owned_built_fn_;
}
-/* --------------------------------------------------------------------
- * NodeMultiFunctions inline methods.
- */
+/** \} */
-inline const MultiFunction *NodeMultiFunctions::try_get(const DNode &node) const
+/* -------------------------------------------------------------------- */
+/** \name #NodeMultiFunctions Inline Methods
+ * \{ */
+
+inline const NodeMultiFunctions::Item &NodeMultiFunctions::try_get(const DNode &node) const
{
- return map_.lookup_default(node->bnode(), nullptr);
+ static Item empty_item;
+ const Item *item = map_.lookup_ptr(node->bnode());
+ if (item == nullptr) {
+ return empty_item;
+ }
+ return *item;
}
+/** \} */
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh
index 07d4e05cda8..113e8ffc93d 100644
--- a/source/blender/nodes/NOD_node_declaration.hh
+++ b/source/blender/nodes/NOD_node_declaration.hh
@@ -16,6 +16,7 @@
#pragma once
+#include <functional>
#include <type_traits>
#include "BLI_string_ref.hh"
@@ -23,6 +24,8 @@
#include "DNA_node_types.h"
+struct bNode;
+
namespace blender::nodes {
class NodeDeclarationBuilder;
@@ -57,59 +60,15 @@ class OutputFieldDependency {
Vector<int> linked_input_indices_;
public:
- static OutputFieldDependency ForFieldSource()
- {
- OutputFieldDependency field_dependency;
- field_dependency.type_ = OutputSocketFieldType::FieldSource;
- return field_dependency;
- }
-
- static OutputFieldDependency ForDataSource()
- {
- OutputFieldDependency field_dependency;
- field_dependency.type_ = OutputSocketFieldType::None;
- return field_dependency;
- }
-
- static OutputFieldDependency ForPartiallyDependentField(Vector<int> indices)
- {
- OutputFieldDependency field_dependency;
- if (indices.is_empty()) {
- field_dependency.type_ = OutputSocketFieldType::None;
- }
- else {
- field_dependency.type_ = OutputSocketFieldType::PartiallyDependent;
- field_dependency.linked_input_indices_ = std::move(indices);
- }
- return field_dependency;
- }
-
- static OutputFieldDependency ForDependentField()
- {
- OutputFieldDependency field_dependency;
- field_dependency.type_ = OutputSocketFieldType::DependentField;
- return field_dependency;
- }
+ static OutputFieldDependency ForFieldSource();
+ static OutputFieldDependency ForDataSource();
+ static OutputFieldDependency ForDependentField();
+ static OutputFieldDependency ForPartiallyDependentField(Vector<int> indices);
- OutputSocketFieldType field_type() const
- {
- return type_;
- }
+ OutputSocketFieldType field_type() const;
+ Span<int> linked_input_indices() const;
- Span<int> linked_input_indices() const
- {
- return linked_input_indices_;
- }
-
- friend bool operator==(const OutputFieldDependency &a, const OutputFieldDependency &b)
- {
- return a.type_ == b.type_ && a.linked_input_indices_ == b.linked_input_indices_;
- }
-
- friend bool operator!=(const OutputFieldDependency &a, const OutputFieldDependency &b)
- {
- return !(a == b);
- }
+ friend bool operator==(const OutputFieldDependency &a, const OutputFieldDependency &b);
};
/**
@@ -118,16 +77,6 @@ class OutputFieldDependency {
struct FieldInferencingInterface {
Vector<InputSocketFieldType> inputs;
Vector<OutputFieldDependency> outputs;
-
- friend bool operator==(const FieldInferencingInterface &a, const FieldInferencingInterface &b)
- {
- return a.inputs == b.inputs && a.outputs == b.outputs;
- }
-
- friend bool operator!=(const FieldInferencingInterface &a, const FieldInferencingInterface &b)
- {
- return !(a == b);
- }
};
/**
@@ -138,27 +87,53 @@ class SocketDeclaration {
std::string name_;
std::string identifier_;
std::string description_;
+ /** Defined by whether the socket is part of the node's input or
+ * output socket declaration list. Included here for convenience. */
+ eNodeSocketInOut in_out_;
bool hide_label_ = false;
bool hide_value_ = false;
+ bool compact_ = false;
bool is_multi_input_ = false;
bool no_mute_links_ = false;
+ bool is_unavailable_ = false;
+ bool is_attribute_name_ = false;
+ bool is_default_link_socket_ = false;
InputSocketFieldType input_field_type_ = InputSocketFieldType::None;
OutputFieldDependency output_field_dependency_;
+ /** Utility method to make the socket available if there is a straightforward way to do so. */
+ std::function<void(bNode &)> make_available_fn_;
+
friend NodeDeclarationBuilder;
template<typename SocketDecl> friend class SocketDeclarationBuilder;
public:
virtual ~SocketDeclaration() = default;
- virtual bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const = 0;
+ virtual bNodeSocket &build(bNodeTree &ntree, bNode &node) const = 0;
virtual bool matches(const bNodeSocket &socket) const = 0;
virtual bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const;
+ /**
+ * Determine if a new socket described by this declaration could have a valid connection
+ * the other socket.
+ */
+ virtual bool can_connect(const bNodeSocket &socket) const = 0;
+
+ /**
+ * Change the node such that the socket will become visible. The node type's update method
+ * should be called afterwards.
+ * \note Note that this is not necessarily implemented for all node types.
+ */
+ void make_available(bNode &node) const;
+
StringRefNull name() const;
StringRefNull description() const;
StringRefNull identifier() const;
+ eNodeSocketInOut in_out() const;
+ bool is_attribute_name() const;
+ bool is_default_link_socket() const;
InputSocketFieldType input_field_type() const;
const OutputFieldDependency &output_field_dependency() const;
@@ -211,12 +186,35 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
decl_->description_ = std::move(value);
return *(Self *)this;
}
+
Self &no_muted_links(bool value = true)
{
decl_->no_mute_links_ = value;
return *(Self *)this;
}
+ /**
+ * Used for sockets that are always unavailable and should not be seen by the user.
+ * Ideally, no new calls to this method should be added over time.
+ */
+ Self &unavailable(bool value = true)
+ {
+ decl_->is_unavailable_ = value;
+ return *(Self *)this;
+ }
+
+ Self &is_attribute_name(bool value = true)
+ {
+ decl_->is_attribute_name_ = value;
+ return *(Self *)this;
+ }
+
+ Self &is_default_link_socket(bool value = true)
+ {
+ decl_->is_default_link_socket_ = value;
+ return *(Self *)this;
+ }
+
/** The input socket allows passing in a field. */
Self &supports_field()
{
@@ -251,6 +249,19 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
{
decl_->output_field_dependency_ = OutputFieldDependency::ForPartiallyDependentField(
std::move(input_dependencies));
+ return *(Self *)this;
+ }
+
+ /**
+ * Pass a function that sets properties on the node required to make the corresponding socket
+ * available, if it is not available on the default state of the node. The function is allowed to
+ * make other sockets unavailable, since it is meant to be called when the node is first added.
+ * The node type's update function is called afterwards.
+ */
+ Self &make_available(std::function<void(bNode &)> fn)
+ {
+ decl_->make_available_fn_ = std::move(fn);
+ return *(Self *)this;
}
};
@@ -265,11 +276,11 @@ class NodeDeclaration {
friend NodeDeclarationBuilder;
public:
- void build(bNodeTree &ntree, bNode &node) const;
bool matches(const bNode &node) const;
Span<SocketDeclarationPtr> inputs() const;
Span<SocketDeclarationPtr> outputs() const;
+ Span<SocketDeclarationPtr> sockets(eNodeSocketInOut in_out) const;
bool is_function_node() const
{
@@ -289,10 +300,13 @@ class NodeDeclarationBuilder {
/**
* All inputs support fields, and all outputs are fields if any of the inputs is a field.
- * Calling field status definitions on each socket is unnecessary.
+ * Calling field status definitions on each socket is unnecessary. Must be called before adding
+ * any sockets.
*/
void is_function_node(bool value = true)
{
+ BLI_assert_msg(declaration_.inputs().is_empty() && declaration_.outputs().is_empty(),
+ "is_function_node() must be called before any socket is created");
declaration_.is_function_node_ = value;
}
@@ -305,12 +319,88 @@ class NodeDeclarationBuilder {
template<typename DeclType>
typename DeclType::Builder &add_socket(StringRef name,
StringRef identifier,
- Vector<SocketDeclarationPtr> &r_decls);
+ eNodeSocketInOut in_out);
};
-/* --------------------------------------------------------------------
- * SocketDeclaration inline methods.
- */
+/* -------------------------------------------------------------------- */
+/** \name #OutputFieldDependency Inline Methods
+ * \{ */
+
+inline OutputFieldDependency OutputFieldDependency::ForFieldSource()
+{
+ OutputFieldDependency field_dependency;
+ field_dependency.type_ = OutputSocketFieldType::FieldSource;
+ return field_dependency;
+}
+
+inline OutputFieldDependency OutputFieldDependency::ForDataSource()
+{
+ OutputFieldDependency field_dependency;
+ field_dependency.type_ = OutputSocketFieldType::None;
+ return field_dependency;
+}
+
+inline OutputFieldDependency OutputFieldDependency::ForDependentField()
+{
+ OutputFieldDependency field_dependency;
+ field_dependency.type_ = OutputSocketFieldType::DependentField;
+ return field_dependency;
+}
+
+inline OutputFieldDependency OutputFieldDependency::ForPartiallyDependentField(Vector<int> indices)
+{
+ OutputFieldDependency field_dependency;
+ if (indices.is_empty()) {
+ field_dependency.type_ = OutputSocketFieldType::None;
+ }
+ else {
+ field_dependency.type_ = OutputSocketFieldType::PartiallyDependent;
+ field_dependency.linked_input_indices_ = std::move(indices);
+ }
+ return field_dependency;
+}
+
+inline OutputSocketFieldType OutputFieldDependency::field_type() const
+{
+ return type_;
+}
+
+inline Span<int> OutputFieldDependency::linked_input_indices() const
+{
+ return linked_input_indices_;
+}
+
+inline bool operator==(const OutputFieldDependency &a, const OutputFieldDependency &b)
+{
+ return a.type_ == b.type_ && a.linked_input_indices_ == b.linked_input_indices_;
+}
+
+inline bool operator!=(const OutputFieldDependency &a, const OutputFieldDependency &b)
+{
+ return !(a == b);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #FieldInferencingInterface Inline Methods
+ * \{ */
+
+inline bool operator==(const FieldInferencingInterface &a, const FieldInferencingInterface &b)
+{
+ return a.inputs == b.inputs && a.outputs == b.outputs;
+}
+
+inline bool operator!=(const FieldInferencingInterface &a, const FieldInferencingInterface &b)
+{
+ return !(a == b);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #SocketDeclaration Inline Methods
+ * \{ */
inline StringRefNull SocketDeclaration::name() const
{
@@ -322,10 +412,26 @@ inline StringRefNull SocketDeclaration::identifier() const
return identifier_;
}
+inline eNodeSocketInOut SocketDeclaration::in_out() const
+{
+ return in_out_;
+}
+
inline StringRefNull SocketDeclaration::description() const
{
return description_;
}
+
+inline bool SocketDeclaration::is_attribute_name() const
+{
+ return is_attribute_name_;
+}
+
+inline bool SocketDeclaration::is_default_link_socket() const
+{
+ return is_default_link_socket_;
+}
+
inline InputSocketFieldType SocketDeclaration::input_field_type() const
{
return input_field_type_;
@@ -336,9 +442,18 @@ inline const OutputFieldDependency &SocketDeclaration::output_field_dependency()
return output_field_dependency_;
}
-/* --------------------------------------------------------------------
- * NodeDeclarationBuilder inline methods.
- */
+inline void SocketDeclaration::make_available(bNode &node) const
+{
+ if (make_available_fn_) {
+ make_available_fn_(node);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #NodeDeclarationBuilder Inline Methods
+ * \{ */
inline NodeDeclarationBuilder::NodeDeclarationBuilder(NodeDeclaration &declaration)
: declaration_(declaration)
@@ -349,36 +464,48 @@ template<typename DeclType>
inline typename DeclType::Builder &NodeDeclarationBuilder::add_input(StringRef name,
StringRef identifier)
{
- return this->add_socket<DeclType>(name, identifier, declaration_.inputs_);
+ return this->add_socket<DeclType>(name, identifier, SOCK_IN);
}
template<typename DeclType>
inline typename DeclType::Builder &NodeDeclarationBuilder::add_output(StringRef name,
StringRef identifier)
{
- return this->add_socket<DeclType>(name, identifier, declaration_.outputs_);
+ return this->add_socket<DeclType>(name, identifier, SOCK_OUT);
}
template<typename DeclType>
-inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(
- StringRef name, StringRef identifier, Vector<SocketDeclarationPtr> &r_decls)
+inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(StringRef name,
+ StringRef identifier,
+ eNodeSocketInOut in_out)
{
static_assert(std::is_base_of_v<SocketDeclaration, DeclType>);
using Builder = typename DeclType::Builder;
+
+ Vector<SocketDeclarationPtr> &declarations = in_out == SOCK_IN ? declaration_.inputs_ :
+ declaration_.outputs_;
+
std::unique_ptr<DeclType> socket_decl = std::make_unique<DeclType>();
std::unique_ptr<Builder> socket_decl_builder = std::make_unique<Builder>();
socket_decl_builder->decl_ = &*socket_decl;
socket_decl->name_ = name;
socket_decl->identifier_ = identifier.is_empty() ? name : identifier;
- r_decls.append(std::move(socket_decl));
+ socket_decl->in_out_ = in_out;
+ if (declaration_.is_function_node()) {
+ socket_decl->input_field_type_ = InputSocketFieldType::IsSupported;
+ socket_decl->output_field_dependency_ = OutputFieldDependency::ForDependentField();
+ }
+ declarations.append(std::move(socket_decl));
Builder &socket_decl_builder_ref = *socket_decl_builder;
builders_.append(std::move(socket_decl_builder));
return socket_decl_builder_ref;
}
-/* --------------------------------------------------------------------
- * NodeDeclaration inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #NodeDeclaration Inline Methods
+ * \{ */
inline Span<SocketDeclarationPtr> NodeDeclaration::inputs() const
{
@@ -390,4 +517,14 @@ inline Span<SocketDeclarationPtr> NodeDeclaration::outputs() const
return outputs_;
}
+inline Span<SocketDeclarationPtr> NodeDeclaration::sockets(eNodeSocketInOut in_out) const
+{
+ if (in_out == SOCK_IN) {
+ return inputs_;
+ }
+ return outputs_;
+}
+
+/** \} */
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh
index 1da42fb6425..ebbec20a139 100644
--- a/source/blender/nodes/NOD_node_tree_ref.hh
+++ b/source/blender/nodes/NOD_node_tree_ref.hh
@@ -200,6 +200,8 @@ class NodeRef : NonCopyable, NonMovable {
PointerRNA *rna() const;
StringRefNull idname() const;
StringRefNull name() const;
+ StringRefNull label() const;
+ StringRefNull label_or_name() const;
bNodeType *typeinfo() const;
const NodeDeclaration *declaration() const;
@@ -260,6 +262,7 @@ class NodeTreeRef : NonCopyable, NonMovable {
Vector<LinkRef *> links_;
MultiValueMap<const bNodeType *, NodeRef *> nodes_by_type_;
Vector<std::unique_ptr<SocketIndexByIdentifierMap>> owned_identifier_maps_;
+ const NodeRef *group_output_node_ = nullptr;
public:
NodeTreeRef(bNodeTree *btree);
@@ -275,6 +278,16 @@ class NodeTreeRef : NonCopyable, NonMovable {
Span<const LinkRef *> links() const;
+ const NodeRef *find_node(const bNode &bnode) const;
+
+ /**
+ * This is the active group output node if there are multiple.
+ */
+ const NodeRef *group_output_node() const;
+
+ /**
+ * \return True when there is a link cycle. Unavailable sockets are ignored.
+ */
bool has_link_cycles() const;
bool has_undefined_nodes_or_sockets() const;
@@ -283,7 +296,21 @@ class NodeTreeRef : NonCopyable, NonMovable {
RightToLeft,
};
- Vector<const NodeRef *> toposort(ToposortDirection direction) const;
+ struct ToposortResult {
+ Vector<const NodeRef *> sorted_nodes;
+ /**
+ * There can't be a correct topological sort of the nodes when there is a cycle. The nodes will
+ * still be sorted to some degree. The caller has to decide whether it can handle non-perfect
+ * sorts or not.
+ */
+ bool has_cycle = false;
+ };
+
+ /**
+ * Sort nodes topologically from left to right or right to left.
+ * In the future the result if this could be cached on #NodeTreeRef.
+ */
+ ToposortResult toposort(ToposortDirection direction) const;
bNodeTree *btree() const;
StringRefNull name() const;
@@ -316,9 +343,9 @@ using nodes::OutputSocketRef;
using nodes::SocketRef;
} // namespace node_tree_ref_types
-/* --------------------------------------------------------------------
- * SocketRef inline methods.
- */
+/* -------------------------------------------------------------------- */
+/** \name #SocketRef Inline Methods
+ * \{ */
inline Span<const SocketRef *> SocketRef::logically_linked_sockets() const
{
@@ -457,9 +484,11 @@ template<typename T> inline T *SocketRef::default_value() const
return (T *)bsocket_->default_value;
}
-/* --------------------------------------------------------------------
- * InputSocketRef inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #InputSocketRef Inline Methods
+ * \{ */
inline Span<const OutputSocketRef *> InputSocketRef::logically_linked_sockets() const
{
@@ -476,9 +505,11 @@ inline bool InputSocketRef::is_multi_input_socket() const
return bsocket_->flag & SOCK_MULTI_INPUT;
}
-/* --------------------------------------------------------------------
- * OutputSocketRef inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #OutputSocketRef Inline Methods
+ * \{ */
inline Span<const InputSocketRef *> OutputSocketRef::logically_linked_sockets() const
{
@@ -490,9 +521,11 @@ inline Span<const InputSocketRef *> OutputSocketRef::directly_linked_sockets() c
return directly_linked_sockets_.cast<const InputSocketRef *>();
}
-/* --------------------------------------------------------------------
- * NodeRef inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #NodeRef Inline Methods
+ * \{ */
inline const NodeTreeRef &NodeRef::tree() const
{
@@ -567,6 +600,20 @@ inline StringRefNull NodeRef::name() const
return bnode_->name;
}
+inline StringRefNull NodeRef::label() const
+{
+ return bnode_->label;
+}
+
+inline StringRefNull NodeRef::label_or_name() const
+{
+ const StringRefNull label = this->label();
+ if (!label.is_empty()) {
+ return label;
+ }
+ return this->name();
+}
+
inline bNodeType *NodeRef::typeinfo() const
{
return bnode_->typeinfo;
@@ -629,9 +676,11 @@ template<typename T> inline T *NodeRef::storage() const
return (T *)bnode_->storage;
}
-/* --------------------------------------------------------------------
- * LinkRef inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #LinkRef Inline Methods
+ * \{ */
inline const OutputSocketRef &LinkRef::from() const
{
@@ -653,9 +702,11 @@ inline bool LinkRef::is_muted() const
return blink_->flag & NODE_LINK_MUTED;
}
-/* --------------------------------------------------------------------
- * InternalLinkRef inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #InternalLinkRef Inline Methods
+ * \{ */
inline const InputSocketRef &InternalLinkRef::from() const
{
@@ -672,9 +723,11 @@ inline bNodeLink *InternalLinkRef::blink() const
return blink_;
}
-/* --------------------------------------------------------------------
- * NodeTreeRef inline methods.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #NodeTreeRef Inline Methods
+ * \{ */
inline Span<const NodeRef *> NodeTreeRef::nodes() const
{
@@ -712,6 +765,11 @@ inline Span<const LinkRef *> NodeTreeRef::links() const
return links_;
}
+inline const NodeRef *NodeTreeRef::group_output_node() const
+{
+ return group_output_node_;
+}
+
inline bNodeTree *NodeTreeRef::btree() const
{
return btree_;
@@ -722,4 +780,6 @@ inline StringRefNull NodeTreeRef::name() const
return btree_->id.name + 2;
}
+/** \} */
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 2911e0fbea6..57740ce3ad9 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -49,6 +49,7 @@ void register_node_type_sh_normal(void);
void register_node_type_sh_gamma(void);
void register_node_type_sh_brightcontrast(void);
void register_node_type_sh_mapping(void);
+void register_node_type_sh_curve_float(void);
void register_node_type_sh_curve_vec(void);
void register_node_type_sh_curve_rgb(void);
void register_node_type_sh_map_range(void);
@@ -84,6 +85,7 @@ void register_node_type_sh_layer_weight(void);
void register_node_type_sh_tex_coord(void);
void register_node_type_sh_particle_info(void);
void register_node_type_sh_hair_info(void);
+void register_node_type_sh_point_info(void);
void register_node_type_sh_volume_info(void);
void register_node_type_sh_script(void);
void register_node_type_sh_normal_map(void);
@@ -142,6 +144,27 @@ void register_node_type_sh_tex_white_noise(void);
void register_node_type_sh_custom_group(bNodeType *ntype);
+struct bNodeTreeExec *ntreeShaderBeginExecTree(struct bNodeTree *ntree);
+void ntreeShaderEndExecTree(struct bNodeTreeExec *exec);
+
+/**
+ * Find an output node of the shader tree.
+ *
+ * \note it will only return output which is NOT in the group, which isn't how
+ * render engines works but it's how the GPU shader compilation works. This we
+ * can change in the future and make it a generic function, but for now it stays
+ * private here.
+ */
+struct bNode *ntreeShaderOutputNode(struct bNodeTree *ntree, int target);
+
+/**
+ * This one needs to work on a local tree.
+ */
+void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
+ struct GPUMaterial *mat,
+ bool *has_surface_output,
+ bool *has_volume_output);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/nodes/NOD_socket_declarations.hh b/source/blender/nodes/NOD_socket_declarations.hh
index 3d0cfdb5d5d..a1972c66ca2 100644
--- a/source/blender/nodes/NOD_socket_declarations.hh
+++ b/source/blender/nodes/NOD_socket_declarations.hh
@@ -21,7 +21,7 @@
#include "RNA_types.h"
#include "BLI_color.hh"
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
namespace blender::nodes::decl {
@@ -39,36 +39,18 @@ class Float : public SocketDeclaration {
public:
using Builder = FloatBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class FloatBuilder : public SocketDeclarationBuilder<Float> {
public:
- FloatBuilder &min(const float value)
- {
- decl_->soft_min_value_ = value;
- return *this;
- }
-
- FloatBuilder &max(const float value)
- {
- decl_->soft_max_value_ = value;
- return *this;
- }
-
- FloatBuilder &default_value(const float value)
- {
- decl_->default_value_ = value;
- return *this;
- }
-
- FloatBuilder &subtype(PropertySubType subtype)
- {
- decl_->subtype_ = subtype;
- return *this;
- }
+ FloatBuilder &min(float value);
+ FloatBuilder &max(float value);
+ FloatBuilder &default_value(float value);
+ FloatBuilder &subtype(PropertySubType subtype);
};
class IntBuilder;
@@ -85,36 +67,18 @@ class Int : public SocketDeclaration {
public:
using Builder = IntBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class IntBuilder : public SocketDeclarationBuilder<Int> {
public:
- IntBuilder &min(const int value)
- {
- decl_->soft_min_value_ = value;
- return *this;
- }
-
- IntBuilder &max(const int value)
- {
- decl_->soft_max_value_ = value;
- return *this;
- }
-
- IntBuilder &default_value(const int value)
- {
- decl_->default_value_ = value;
- return *this;
- }
-
- IntBuilder &subtype(PropertySubType subtype)
- {
- decl_->subtype_ = subtype;
- return *this;
- }
+ IntBuilder &min(int value);
+ IntBuilder &max(int value);
+ IntBuilder &default_value(int value);
+ IntBuilder &subtype(PropertySubType subtype);
};
class VectorBuilder;
@@ -131,36 +95,19 @@ class Vector : public SocketDeclaration {
public:
using Builder = VectorBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class VectorBuilder : public SocketDeclarationBuilder<Vector> {
public:
- VectorBuilder &default_value(const float3 value)
- {
- decl_->default_value_ = value;
- return *this;
- }
-
- VectorBuilder &subtype(PropertySubType subtype)
- {
- decl_->subtype_ = subtype;
- return *this;
- }
-
- VectorBuilder &min(const float min)
- {
- decl_->soft_min_value_ = min;
- return *this;
- }
-
- VectorBuilder &max(const float max)
- {
- decl_->soft_max_value_ = max;
- return *this;
- }
+ VectorBuilder &default_value(const float3 value);
+ VectorBuilder &subtype(PropertySubType subtype);
+ VectorBuilder &min(float min);
+ VectorBuilder &max(float max);
+ VectorBuilder &compact();
};
class BoolBuilder;
@@ -173,17 +120,14 @@ class Bool : public SocketDeclaration {
public:
using Builder = BoolBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class BoolBuilder : public SocketDeclarationBuilder<Bool> {
public:
- BoolBuilder &default_value(const bool value)
- {
- decl_->default_value_ = value;
- return *this;
- }
+ BoolBuilder &default_value(bool value);
};
class ColorBuilder;
@@ -197,25 +141,35 @@ class Color : public SocketDeclaration {
public:
using Builder = ColorBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class ColorBuilder : public SocketDeclarationBuilder<Color> {
public:
- ColorBuilder &default_value(const ColorGeometry4f value)
- {
- decl_->default_value_ = value;
- return *this;
- }
+ ColorBuilder &default_value(const ColorGeometry4f value);
};
+class StringBuilder;
+
class String : public SocketDeclaration {
+ private:
+ std::string default_value_;
+
+ friend StringBuilder;
+
public:
- using Builder = SocketDeclarationBuilder<String>;
+ using Builder = StringBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
+};
+
+class StringBuilder : public SocketDeclarationBuilder<String> {
+ public:
+ StringBuilder &default_value(const std::string value);
};
class IDSocketDeclaration : public SocketDeclaration {
@@ -223,57 +177,226 @@ class IDSocketDeclaration : public SocketDeclaration {
const char *idname_;
public:
- IDSocketDeclaration(const char *idname) : idname_(idname)
- {
- }
+ IDSocketDeclaration(const char *idname);
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class Object : public IDSocketDeclaration {
public:
using Builder = SocketDeclarationBuilder<Object>;
- Object() : IDSocketDeclaration("NodeSocketObject")
- {
- }
+ Object();
};
class Material : public IDSocketDeclaration {
public:
using Builder = SocketDeclarationBuilder<Material>;
- Material() : IDSocketDeclaration("NodeSocketMaterial")
- {
- }
+ Material();
};
class Collection : public IDSocketDeclaration {
public:
using Builder = SocketDeclarationBuilder<Collection>;
- Collection() : IDSocketDeclaration("NodeSocketCollection")
- {
- }
+ Collection();
};
class Texture : public IDSocketDeclaration {
public:
using Builder = SocketDeclarationBuilder<Texture>;
- Texture() : IDSocketDeclaration("NodeSocketTexture")
- {
- }
+ Texture();
};
-class Geometry : public SocketDeclaration {
+class Image : public IDSocketDeclaration {
public:
- using Builder = SocketDeclarationBuilder<Geometry>;
+ using Builder = SocketDeclarationBuilder<Image>;
+
+ Image();
+};
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+class ShaderBuilder;
+
+class Shader : public SocketDeclaration {
+ private:
+ friend ShaderBuilder;
+
+ public:
+ using Builder = ShaderBuilder;
+
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
+};
+
+class ShaderBuilder : public SocketDeclarationBuilder<Shader> {
};
+/* -------------------------------------------------------------------- */
+/** \name #FloatBuilder Inline Methods
+ * \{ */
+
+inline FloatBuilder &FloatBuilder::min(const float value)
+{
+ decl_->soft_min_value_ = value;
+ return *this;
+}
+
+inline FloatBuilder &FloatBuilder::max(const float value)
+{
+ decl_->soft_max_value_ = value;
+ return *this;
+}
+
+inline FloatBuilder &FloatBuilder::default_value(const float value)
+{
+ decl_->default_value_ = value;
+ return *this;
+}
+
+inline FloatBuilder &FloatBuilder::subtype(PropertySubType subtype)
+{
+ decl_->subtype_ = subtype;
+ return *this;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #IntBuilder Inline Methods
+ * \{ */
+
+inline IntBuilder &IntBuilder::min(const int value)
+{
+ decl_->soft_min_value_ = value;
+ return *this;
+}
+
+inline IntBuilder &IntBuilder::max(const int value)
+{
+ decl_->soft_max_value_ = value;
+ return *this;
+}
+
+inline IntBuilder &IntBuilder::default_value(const int value)
+{
+ decl_->default_value_ = value;
+ return *this;
+}
+
+inline IntBuilder &IntBuilder::subtype(PropertySubType subtype)
+{
+ decl_->subtype_ = subtype;
+ return *this;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #VectorBuilder Inline Methods
+ * \{ */
+
+inline VectorBuilder &VectorBuilder::default_value(const float3 value)
+{
+ decl_->default_value_ = value;
+ return *this;
+}
+
+inline VectorBuilder &VectorBuilder::subtype(PropertySubType subtype)
+{
+ decl_->subtype_ = subtype;
+ return *this;
+}
+
+inline VectorBuilder &VectorBuilder::min(const float min)
+{
+ decl_->soft_min_value_ = min;
+ return *this;
+}
+
+inline VectorBuilder &VectorBuilder::max(const float max)
+{
+ decl_->soft_max_value_ = max;
+ return *this;
+}
+
+inline VectorBuilder &VectorBuilder::compact()
+{
+ decl_->compact_ = true;
+ return *this;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #BoolBuilder Inline Methods
+ * \{ */
+
+inline BoolBuilder &BoolBuilder::default_value(const bool value)
+{
+ decl_->default_value_ = value;
+ return *this;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #ColorBuilder Inline Methods
+ * \{ */
+
+inline ColorBuilder &ColorBuilder::default_value(const ColorGeometry4f value)
+{
+ decl_->default_value_ = value;
+ return *this;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #StringBuilder Inline Methods
+ * \{ */
+
+inline StringBuilder &StringBuilder::default_value(std::string value)
+{
+ decl_->default_value_ = std::move(value);
+ return *this;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #IDSocketDeclaration and Children Inline Methods
+ * \{ */
+
+inline IDSocketDeclaration::IDSocketDeclaration(const char *idname) : idname_(idname)
+{
+}
+
+inline Object::Object() : IDSocketDeclaration("NodeSocketObject")
+{
+}
+
+inline Material::Material() : IDSocketDeclaration("NodeSocketMaterial")
+{
+}
+
+inline Collection::Collection() : IDSocketDeclaration("NodeSocketCollection")
+{
+}
+
+inline Texture::Texture() : IDSocketDeclaration("NodeSocketTexture")
+{
+}
+
+inline Image::Image() : IDSocketDeclaration("NodeSocketImage")
+{
+}
+
+/** \} */
+
} // namespace blender::nodes::decl
diff --git a/source/blender/nodes/NOD_socket_declarations_geometry.hh b/source/blender/nodes/NOD_socket_declarations_geometry.hh
new file mode 100644
index 00000000000..0ce07da22ff
--- /dev/null
+++ b/source/blender/nodes/NOD_socket_declarations_geometry.hh
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include "BKE_geometry_set.hh"
+
+#include "NOD_socket_declarations.hh"
+
+namespace blender::nodes::decl {
+
+class GeometryBuilder;
+
+class Geometry : public SocketDeclaration {
+ private:
+ blender::Vector<GeometryComponentType> supported_types_;
+ bool only_realized_data_ = false;
+ bool only_instances_ = false;
+
+ friend GeometryBuilder;
+
+ public:
+ using Builder = GeometryBuilder;
+
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
+ bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
+
+ Span<GeometryComponentType> supported_types() const;
+ bool only_realized_data() const;
+ bool only_instances() const;
+};
+
+class GeometryBuilder : public SocketDeclarationBuilder<Geometry> {
+ public:
+ GeometryBuilder &supported_type(GeometryComponentType supported_type);
+ GeometryBuilder &supported_type(blender::Vector<GeometryComponentType> supported_types);
+ GeometryBuilder &only_realized_data(bool value = true);
+ GeometryBuilder &only_instances(bool value = true);
+};
+
+} // namespace blender::nodes::decl
diff --git a/source/blender/nodes/NOD_socket_search_link.hh b/source/blender/nodes/NOD_socket_search_link.hh
new file mode 100644
index 00000000000..b7594561dc4
--- /dev/null
+++ b/source/blender/nodes/NOD_socket_search_link.hh
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <functional>
+
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+#include "DNA_node_types.h" /* Necessary for eNodeSocketInOut. */
+
+#include "NOD_node_declaration.hh"
+
+struct bContext;
+
+namespace blender::nodes {
+
+/**
+ * Parameters for the operation operation of adding a node after the link drag search menu closes.
+ */
+class LinkSearchOpParams {
+ private:
+ /**
+ * Keep track of the nodes added by the callback, so they can be selected or moved afterwards.
+ */
+ Vector<bNode *> &added_nodes_;
+
+ public:
+ const bContext &C;
+ bNodeTree &node_tree;
+ /**
+ * The node that contains the #socket.
+ */
+ bNode &node;
+ /**
+ * The existing socket to connect any added nodes to. Might be an input or output socket.
+ */
+ bNodeSocket &socket;
+
+ LinkSearchOpParams(const bContext &C,
+ bNodeTree &node_tree,
+ bNode &node,
+ bNodeSocket &socket,
+ Vector<bNode *> &added_nodes)
+ : added_nodes_(added_nodes), C(C), node_tree(node_tree), node(node), socket(socket)
+ {
+ }
+
+ bNode &add_node(StringRef idname);
+ bNode &add_node(const bNodeType &type);
+ /**
+ * Find a socket with the given name (correctly checks for inputs and outputs)
+ * and connect it to the socket the link drag started from (#socket).
+ */
+ void connect_available_socket(bNode &new_node, StringRef socket_name);
+ /**
+ * Like #connect_available_socket, but also calls the node's update function.
+ */
+ void update_and_connect_available_socket(bNode &new_node, StringRef socket_name);
+};
+
+struct SocketLinkOperation {
+ using LinkSocketFn = std::function<void(LinkSearchOpParams &link_params)>;
+
+ std::string name;
+ LinkSocketFn fn;
+ int weight = 0;
+};
+
+class GatherLinkSearchOpParams {
+ /** The current node type. */
+ const bNodeType &node_type_;
+
+ const bNodeTree &node_tree_;
+
+ const bNodeSocket &other_socket_;
+
+ /* The operations currently being built. Owned by the caller. */
+ Vector<SocketLinkOperation> &items_;
+
+ public:
+ GatherLinkSearchOpParams(const bNodeType &node_type,
+ const bNodeTree &node_tree,
+ const bNodeSocket &other_socket,
+ Vector<SocketLinkOperation> &items)
+ : node_type_(node_type), node_tree_(node_tree), other_socket_(other_socket), items_(items)
+ {
+ }
+
+ /**
+ * The node on the other side of the dragged link.
+ */
+ const bNodeSocket &other_socket() const;
+
+ /**
+ * The node tree the user is editing when the search menu is created.
+ */
+ const bNodeTree &node_tree() const;
+
+ /**
+ * The type of the node in the current callback.
+ */
+ const bNodeType &node_type() const;
+
+ /**
+ * Whether to list the input or output sockets of the node.
+ */
+ eNodeSocketInOut in_out() const;
+
+ /**
+ * \param weight: Used to customize the order when multiple search items match.
+ *
+ * \warning When creating lambdas for the #fn argument, be careful not to capture this class
+ * itself, since it is temporary. That is why we tend to use the same variable name for this
+ * class (`params`) that we do for the argument to `LinkSocketFn`.
+ */
+ void add_item(std::string socket_name, SocketLinkOperation::LinkSocketFn fn, int weight = 0);
+};
+
+/**
+ * This callback can be used for a node type when a few things are true about its inputs.
+ * To avoid creating more boilerplate, it is the default callback for node types.
+ * - Either all declared sockets are visible in the default state of the node, *OR* the node's
+ * type's declaration has been extended with #make_available functions for those sockets.
+ *
+ * If a node type does not meet these criteria, the function will do nothing in a release build.
+ * In a debug build, an assert will most likely be hit.
+ *
+ * \note For nodes with the deprecated #bNodeSocketTemplate instead of a declaration,
+ * these criteria do not apply and the function just tries its best without asserting.
+ */
+void search_link_ops_for_basic_node(GatherLinkSearchOpParams &params);
+
+void search_link_ops_for_declarations(GatherLinkSearchOpParams &params,
+ Span<SocketDeclarationPtr> declarations);
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 3ee3faf6122..8cbde6adcad 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -96,6 +96,7 @@ DefNode(ShaderNode, SH_NODE_LIGHT_FALLOFF, 0, "LIG
DefNode(ShaderNode, SH_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Object Info", "" )
DefNode(ShaderNode, SH_NODE_PARTICLE_INFO, 0, "PARTICLE_INFO", ParticleInfo, "Particle Info", "" )
DefNode(ShaderNode, SH_NODE_HAIR_INFO, 0, "HAIR_INFO", HairInfo, "Hair Info", "" )
+DefNode(ShaderNode, SH_NODE_POINT_INFO, 0, "POINT_INFO", PointInfo, "Point Info", "" )
DefNode(ShaderNode, SH_NODE_VOLUME_INFO, 0, "VOLUME_INFO", VolumeInfo, "Volume Info", "" )
DefNode(ShaderNode, SH_NODE_WIREFRAME, def_sh_tex_wireframe, "WIREFRAME", Wireframe, "Wireframe", "" )
DefNode(ShaderNode, SH_NODE_WAVELENGTH, 0, "WAVELENGTH", Wavelength, "Wavelength", "" )
@@ -132,6 +133,7 @@ DefNode(ShaderNode, SH_NODE_VECTOR_DISPLACEMENT,def_sh_vector_displacement,"
DefNode(ShaderNode, SH_NODE_TEX_IES, def_sh_tex_ies, "TEX_IES", TexIES, "IES Texture", "" )
DefNode(ShaderNode, SH_NODE_TEX_WHITE_NOISE, def_sh_tex_white_noise, "TEX_WHITE_NOISE", TexWhiteNoise, "White Noise", "" )
DefNode(ShaderNode, SH_NODE_OUTPUT_AOV, def_sh_output_aov, "OUTPUT_AOV", OutputAOV, "AOV Output", "" )
+DefNode(ShaderNode, SH_NODE_CURVE_FLOAT, def_float_curve, "CURVE_FLOAT", FloatCurve, "Float Curve", "" )
DefNode(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
@@ -147,7 +149,7 @@ DefNode(CompositorNode, CMP_NODE_BLUR, def_cmp_blur, "BLUR",
DefNode(CompositorNode, CMP_NODE_FILTER, def_cmp_filter, "FILTER", Filter, "Filter", "" )
DefNode(CompositorNode, CMP_NODE_MAP_VALUE, def_cmp_map_value, "MAP_VALUE", MapValue, "Map Value", "" )
DefNode(CompositorNode, CMP_NODE_MAP_RANGE, def_cmp_map_range, "MAP_RANGE", MapRange, "Map Range", "" )
-DefNode(CompositorNode, CMP_NODE_TIME, def_time, "TIME", Time, "Time", "" )
+DefNode(CompositorNode, CMP_NODE_TIME, def_time, "TIME", Time, "Time Curve", "" )
DefNode(CompositorNode, CMP_NODE_VECBLUR, def_cmp_vector_blur, "VECBLUR", VecBlur, "Vector Blur", "" )
DefNode(CompositorNode, CMP_NODE_SEPRGBA, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" )
DefNode(CompositorNode, CMP_NODE_SEPHSVA, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" )
@@ -226,6 +228,8 @@ DefNode(CompositorNode, CMP_NODE_DENOISE, def_cmp_denoise, "DENOIS
DefNode(CompositorNode, CMP_NODE_EXPOSURE, 0, "EXPOSURE", Exposure, "Exposure", "" )
DefNode(CompositorNode, CMP_NODE_ANTIALIASING, def_cmp_antialiasing, "ANTIALIASING", AntiAliasing, "Anti-Aliasing", "" )
DefNode(CompositorNode, CMP_NODE_POSTERIZE, 0, "POSTERIZE", Posterize, "Posterize", "" )
+DefNode(CompositorNode, CMP_NODE_CONVERT_COLOR_SPACE,def_cmp_convert_color_space, "CONVERT_COLORSPACE", ConvertColorSpace, "Color Space","" )
+DefNode(CompositorNode, CMP_NODE_SCENE_TIME, 0, "SCENE_TIME", SceneTime, "Scene Time", "" )
DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )
@@ -264,16 +268,22 @@ DefNode(TextureNode, TEX_NODE_PROC+TEX_DISTNOISE, 0, "TEX_DI
DefNode(FunctionNode, FN_NODE_LEGACY_RANDOM_FLOAT, 0, "LEGACY_RANDOM_FLOAT", LegacyRandomFloat, "Random Float", "")
+DefNode(FunctionNode, FN_NODE_ALIGN_EULER_TO_VECTOR, def_fn_align_euler_to_vector, "ALIGN_EULER_TO_VECTOR", AlignEulerToVector, "Align Euler To Vector", "")
DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
-DefNode(FunctionNode, FN_NODE_FLOAT_COMPARE, def_float_compare, "FLOAT_COMPARE", FloatCompare, "Float Compare", "")
+DefNode(FunctionNode, FN_NODE_COMPARE, def_compare, "COMPARE", Compare, "Compare", "")
DefNode(FunctionNode, FN_NODE_FLOAT_TO_INT, def_float_to_int, "FLOAT_TO_INT", FloatToInt, "Float to Integer", "")
+DefNode(FunctionNode, FN_NODE_INPUT_BOOL, def_fn_input_bool, "INPUT_BOOL", InputBool, "Boolean", "")
+DefNode(FunctionNode, FN_NODE_INPUT_COLOR, def_fn_input_color, "INPUT_COLOR", InputColor, "Color", "")
+DefNode(FunctionNode, FN_NODE_INPUT_INT, def_fn_input_int, "INPUT_INT", InputInt, "Integer", "")
DefNode(FunctionNode, FN_NODE_INPUT_SPECIAL_CHARACTERS, 0, "INPUT_SPECIAL_CHARACTERS", InputSpecialCharacters, "Special Characters", "")
DefNode(FunctionNode, FN_NODE_INPUT_STRING, def_fn_input_string, "INPUT_STRING", InputString, "String", "")
DefNode(FunctionNode, FN_NODE_INPUT_VECTOR, def_fn_input_vector, "INPUT_VECTOR", InputVector, "Vector", "")
DefNode(FunctionNode, FN_NODE_RANDOM_VALUE, def_fn_random_value, "RANDOM_VALUE", RandomValue, "Random Value", "")
-DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToString, "Value to String", "")
+DefNode(FunctionNode, FN_NODE_REPLACE_STRING, 0, "REPLACE_STRING", ReplaceString, "Replace String", "")
+DefNode(FunctionNode, FN_NODE_ROTATE_EULER, def_fn_rotate_euler, "ROTATE_EULER", RotateEuler, "Rotate Euler", "")
+DefNode(FunctionNode, FN_NODE_SLICE_STRING, 0, "SLICE_STRING", SliceString, "Slice String", "")
DefNode(FunctionNode, FN_NODE_STRING_LENGTH, 0, "STRING_LENGTH", StringLength, "String Length", "")
-DefNode(FunctionNode, FN_NODE_STRING_SUBSTRING, 0, "STRING_SUBSTRING", StringSubstring, "String Substring", "")
+DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToString, "Value to String", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ALIGN_ROTATION_TO_VECTOR, def_geo_align_rotation_to_vector, "LEGACY_ALIGN_ROTATION_TO_VECTOR", LegacyAlignRotationToVector, "Align Rotation to Vector", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, def_geo_attribute_clamp, "LEGACY_ATTRIBUTE_CLAMP", LegacyAttributeClamp, "Attribute Clamp", "")
@@ -296,10 +306,10 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_ROTATE, def_geo_attribute
DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_ENDPOINTS, 0, "LEGACY_CURVE_ENDPOINTS", LegacyCurveEndpoints, "Curve Endpoints", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_REVERSE, 0, "LEGACY_CURVE_REVERSE", LegacyCurveReverse, "Curve Reverse", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SELECT_HANDLES, def_geo_curve_select_handles, "LEGACY_CURVE_SELECT_HANDLES", LegacyCurveSelectHandles, "Select by Handle Type", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SET_HANDLES, def_geo_curve_set_handles, "LEGACY_CURVE_SET_HANDLES", LegacyCurveSetHandles, "Set Handle Type", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SET_HANDLES, def_geo_legacy_curve_set_handles, "LEGACY_CURVE_SET_HANDLES", LegacyCurveSetHandles, "Set Handle Type", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, def_geo_curve_spline_type, "LEGACY_CURVE_SPLINE_TYPE", LegacyCurveSplineType, "Set Spline Type", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, def_geo_curve_subdivide, "LEGACY_CURVE_SUBDIVIDE", LegacyCurveSubdivide, "Curve Subdivide", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_TO_POINTS, def_geo_curve_to_points, "LEGACY_CURVE_TO_POINTS", LegacyCurveToPoints, "Curve to Points", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, def_geo_legacy_curve_subdivide, "LEGACY_CURVE_SUBDIVIDE", LegacyCurveSubdivide, "Curve Subdivide", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_TO_POINTS, def_geo_legacy_curve_to_points, "LEGACY_CURVE_TO_POINTS", LegacyCurveToPoints, "Curve to Points", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_DELETE_GEOMETRY, 0, "LEGACY_DELETE_GEOMETRY", LegacyDeleteGeometry, "Delete Geometry", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_EDGE_SPLIT, 0, "LEGACY_EDGE_SPLIT", LegacyEdgeSplit, "Edge Split", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_MATERIAL_ASSIGN, 0, "LEGACY_MATERIAL_ASSIGN", LegacyMaterialAssign, "Material Assign", "")
@@ -310,22 +320,23 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_POINT_ROTATE, def_geo_point_rotate, "LEGAC
DefNode(GeometryNode, GEO_NODE_LEGACY_POINT_SCALE, def_geo_point_scale, "LEGACY_POINT_SCALE", LegacyPointScale, "Point Scale", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_POINT_SEPARATE, 0, "LEGACY_POINT_SEPARATE", LegacyPointSeparate, "Point Separate", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_POINT_TRANSLATE, def_geo_point_translate, "LEGACY_POINT_TRANSLATE", LegacyPointTranslate, "Point Translate", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_POINTS_TO_VOLUME, def_geo_points_to_volume, "LEGACY_POINTS_TO_VOLUME", LegacyPointsToVolume, "Points to Volume", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_RAYCAST, def_geo_raycast, "LEGACY_RAYCAST", LegacyRaycast, "Raycast", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_POINTS_TO_VOLUME, def_geo_legacy_points_to_volume, "LEGACY_POINTS_TO_VOLUME", LegacyPointsToVolume, "Points to Volume", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_RAYCAST, def_geo_legacy_raycast, "LEGACY_RAYCAST", LegacyRaycast, "Raycast", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, 0, "LEGACY_SELECT_BY_MATERIAL", LegacySelectByMaterial, "Select by Material", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "LEGACY_SUBDIVISION_SURFACE", LegacySubdivisionSurface, "Subdivision Surface", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_VOLUME_TO_MESH, def_geo_volume_to_mesh, "LEGACY_VOLUME_TO_MESH", LegacyVolumeToMesh, "Volume to Mesh", "")
-DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CAPTURE, def_geo_attribute_capture, "ATTRIBUTE_CAPTURE", AttributeCapture, "Attribute Capture", "")
+DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC", AttributeStatistic, "Attribute Statistic", "")
-DefNode(GeometryNode, GEO_NODE_BOOLEAN, def_geo_boolean, "BOOLEAN", Boolean, "Boolean", "")
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "")
+DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture, "CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "")
DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "")
DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Convex Hull", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_FILL, def_geo_curve_fill, "CURVE_FILL", CurveFill, "Curve Fill", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_FILLET, def_geo_curve_fillet, "CURVE_FILLET", CurveFillet, "Curve Fillet", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINT_SELECTION, 0, "CURVE_ENDPOINT_SELECTION", CurveEndpointSelection, "Endpoint Selection", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, def_geo_curve_handle_type_selection, "CURVE_HANDLE_TYPE_SELECTION", CurveHandleTypeSelection, "Handle Type Selection", "")
DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Curve Length", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_PARAMETER, 0, "CURVE_PARAMETER", CurveParameter, "Curve Parameter", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_ARC, def_geo_curve_primitive_arc, "CURVE_PRIMITIVE_ARC", CurveArc, "Arc", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Curve Circle", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_LINE, def_geo_curve_primitive_line, "CURVE_PRIMITIVE_LINE", CurvePrimitiveLine, "Curve Line", "")
@@ -333,23 +344,51 @@ DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, 0, "CURVE_PRIMI
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, def_geo_curve_primitive_quadrilateral, "CURVE_PRIMITIVE_QUADRILATERAL", CurvePrimitiveQuadrilateral, "Quadrilateral", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, 0, "CURVE_PRIMITIVE_SPIRAL", CurveSpiral, "Curve Spiral", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_STAR, 0, "CURVE_PRIMITIVE_STAR", CurveStar, "Star", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_RESAMPLE, def_geo_curve_resample, "CURVE_RESAMPLE", CurveResample, "Resample Curve", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_REVERSE, 0, "CURVE_REVERSE", CurveReverse, "Curve Reverse", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_SAMPLE, def_geo_curve_sample, "CURVE_SAMPLE", CurveSample, "Curve Sample", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_SET_HANDLES, def_geo_curve_set_handles, "CURVE_SET_HANDLES", CurveSetHandles, "Set Handle Type", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_PARAMETER, 0, "SPLINE_PARAMETER", SplineParameter, "Spline Parameter", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_TYPE, def_geo_curve_spline_type, "CURVE_SPLINE_TYPE", CurveSplineType, "Set Spline Type", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_TRIM, def_geo_curve_trim, "CURVE_TRIM", CurveTrim, "Curve Trim", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "")
+DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, def_geo_delete_geometry, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "")
DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, def_geo_distribute_points_on_faces, "DISTRIBUTE_POINTS_ON_FACES", DistributePointsOnFaces, "Distribute Points on Faces", "")
+DefNode(GeometryNode, GEO_NODE_ACCUMULATE_FIELD, def_geo_accumulate_field, "ACCUMULATE_FIELD", AccumulateField, "Accumulate Field", "")
+DefNode(GeometryNode, GEO_NODE_DUAL_MESH, 0, "DUAL_MESH", DualMesh, "Dual Mesh", "")
+DefNode(GeometryNode, GEO_NODE_EXTRUDE_MESH, def_geo_extrude_mesh, "EXTRUDE_MESH", ExtrudeMesh, "Extrude Mesh", "")
+DefNode(GeometryNode, GEO_NODE_FIELD_AT_INDEX, def_geo_field_at_index, "FIELD_AT_INDEX", FieldAtIndex, "Field at Index", "")
+DefNode(GeometryNode, GEO_NODE_FILL_CURVE, def_geo_curve_fill, "FILL_CURVE", FillCurve, "Fill Curve", "")
+DefNode(GeometryNode, GEO_NODE_FILLET_CURVE, def_geo_curve_fillet, "FILLET_CURVE", FilletCurve, "Fillet Curve", "")
+DefNode(GeometryNode, GEO_NODE_FLIP_FACES, 0, "FLIP_FACES", FlipFaces, "Flip Faces", "")
+DefNode(GeometryNode, GEO_NODE_GEOMETRY_TO_INSTANCE, 0, "GEOMETRY_TO_INSTANCE", GeometryToInstance, "Geometry to Instance", "")
+DefNode(GeometryNode, GEO_NODE_IMAGE_TEXTURE, def_geo_image_texture, "IMAGE_TEXTURE", ImageTexture, "Image Texture", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES", InputCurveHandlePositions, "Curve Handle Positions", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_TILT, 0, "INPUT_CURVE_TILT", InputCurveTilt, "Curve Tilt", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_ID, 0, "INPUT_ID", InputID, "ID", "")
DefNode(GeometryNode, GEO_NODE_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL_INDEX, 0, "INPUT_MATERIAL_INDEX", InputMaterialIndex, "Material Index", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_ANGLE, 0, "MESH_EDGE_ANGLE", InputMeshEdgeAngle, "Edge Angle", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, 0, "MESH_EDGE_NEIGHBORS", InputMeshEdgeNeighbors, "Edge Neighbors", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_VERTICES, 0, "MESH_EDGE_VERTICES", InputMeshEdgeVertices, "Edge Vertices", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_AREA, 0, "MESH_FACE_AREA", InputMeshFaceArea, "Face Area", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, 0, "MESH_FACE_NEIGHBORS", InputMeshFaceNeighbors, "Face Neighbors", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_ISLAND, 0, "MESH_ISLAND", InputMeshIsland, "Mesh Island", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, 0, "MESH_VERTEX_NEIGHBORS", InputMeshVertexNeighbors, "Vertex Neighbors", "")
DefNode(GeometryNode, GEO_NODE_INPUT_NORMAL, 0, "INPUT_NORMAL", InputNormal, "Normal", "")
DefNode(GeometryNode, GEO_NODE_INPUT_POSITION, 0, "POSITION", InputPosition, "Position", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_RADIUS, 0, "INPUT_RADIUS", InputRadius, "Radius", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_SCENE_TIME, 0, "INPUT_SCENE_TIME", InputSceneTime, "Scene Time", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_SHADE_SMOOTH, 0, "INPUT_SHADE_SMOOTH", InputShadeSmooth, "Is Shade Smooth", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_CYCLIC, 0, "INPUT_SPLINE_CYCLIC", InputSplineCyclic, "Is Spline Cyclic", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_LENGTH, 0, "SPLINE_LENGTH", SplineLength, "Spline Length", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_RESOLUTION, 0, "INPUT_SPLINE_RESOLUTION", InputSplineResolution, "Spline Resolution", "")
DefNode(GeometryNode, GEO_NODE_INPUT_TANGENT, 0, "INPUT_TANGENT", InputTangent, "Curve Tangent", "")
DefNode(GeometryNode, GEO_NODE_INSTANCE_ON_POINTS, 0, "INSTANCE_ON_POINTS", InstanceOnPoints, "Instance on Points", "")
+DefNode(GeometryNode, GEO_NODE_INSTANCES_TO_POINTS, 0, "INSTANCES_TO_POINTS", InstancesToPoints, "Instances to Points", "")
DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "")
DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "")
-DefNode(GeometryNode, GEO_NODE_MATERIAL_ASSIGN, 0, "MATERIAL_ASSIGN", MaterialAssign, "Material Assign", "")
-DefNode(GeometryNode, GEO_NODE_MATERIAL_REPLACE, 0, "MATERIAL_REPLACE", MaterialReplace, "Material Replace", "")
DefNode(GeometryNode, GEO_NODE_MATERIAL_SELECTION, 0, "MATERIAL_SELECTION", MaterialSelection, "Material Selection", "")
+DefNode(GeometryNode, GEO_NODE_MERGE_BY_DISTANCE, 0, "MERGE_BY_DISTANCE", MergeByDistance, "Merge by Distance", "")
+DefNode(GeometryNode, GEO_NODE_MESH_BOOLEAN, def_geo_boolean, "MESH_BOOLEAN", MeshBoolean, "Mesh Boolean", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CIRCLE, def_geo_mesh_circle, "MESH_PRIMITIVE_CIRCLE", MeshCircle, "Mesh Circle", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE", MeshCone, "Cone", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CUBE, 0, "MESH_PRIMITIVE_CUBE", MeshCube, "Cube", "")
@@ -358,20 +397,47 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_GRID, 0, "MESH_PRIMITIVE_GRID", Me
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, 0, "MESH_PRIMITIVE_ICO_SPHERE", MeshIcoSphere, "Ico Sphere", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRIMITIVE_LINE", MeshLine, "Mesh Line", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "")
-DefNode(GeometryNode, GEO_NODE_MESH_SUBDIVIDE, 0, "MESH_SUBDIVIDE", MeshSubdivide, "Mesh Subdivide", "")
+DefNode(GeometryNode, GEO_NODE_MESH_TO_CURVE, 0, "MESH_TO_CURVE", MeshToCurve, "Mesh to Curve", "")
DefNode(GeometryNode, GEO_NODE_MESH_TO_POINTS, def_geo_mesh_to_points, "MESH_TO_POINTS", MeshToPoints, "Mesh to Points", "")
DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, def_geo_object_info, "OBJECT_INFO", ObjectInfo, "Object Info", "")
DefNode(GeometryNode, GEO_NODE_POINTS_TO_VERTICES, 0, "POINTS_TO_VERTICES", PointsToVertices, "Points to Vertices", "")
+DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "")
DefNode(GeometryNode, GEO_NODE_PROXIMITY, def_geo_proximity, "PROXIMITY", Proximity, "Geometry Proximity", "")
-DefNode(GeometryNode, GEO_NODE_REALIZE_INSTANCES, 0, "REALIZE_INSTANCES", RealizeInstances, "Realize Instances", "")
+DefNode(GeometryNode, GEO_NODE_RAYCAST, def_geo_raycast, "RAYCAST", Raycast, "Raycast", "")
+DefNode(GeometryNode, GEO_NODE_REALIZE_INSTANCES, def_geo_realize_instances, "REALIZE_INSTANCES", RealizeInstances, "Realize Instances", "")
+DefNode(GeometryNode, GEO_NODE_REPLACE_MATERIAL, 0, "REPLACE_MATERIAL", ReplaceMaterial, "Replace Material", "")
+DefNode(GeometryNode, GEO_NODE_RESAMPLE_CURVE, def_geo_curve_resample, "RESAMPLE_CURVE", ResampleCurve, "Resample Curve", "")
+DefNode(GeometryNode, GEO_NODE_REVERSE_CURVE, 0, "REVERSE_CURVE", ReverseCurve, "Reverse Curve", "")
+DefNode(GeometryNode, GEO_NODE_ROTATE_INSTANCES, 0, "ROTATE_INSTANCES", RotateInstances, "Rotate Instances", "")
+DefNode(GeometryNode, GEO_NODE_SAMPLE_CURVE, def_geo_curve_sample, "SAMPLE_CURVE", SampleCurve, "Sample Curve", "")
+DefNode(GeometryNode, GEO_NODE_SCALE_ELEMENTS, def_geo_scale_elements, "SCALE_ELEMENTS", ScaleElements, "Scale Elements", "")
+DefNode(GeometryNode, GEO_NODE_SCALE_INSTANCES, 0, "SCALE_INSTANCES", ScaleInstances, "Scale Instances", "")
DefNode(GeometryNode, GEO_NODE_SEPARATE_COMPONENTS, 0, "SEPARATE_COMPONENTS", SeparateComponents, "Separate Components", "")
+DefNode(GeometryNode, GEO_NODE_SEPARATE_GEOMETRY, def_geo_separate_geometry, "SEPARATE_GEOMETRY", SeparateGeometry, "Separate Geometry", "")
+DefNode(GeometryNode, GEO_NODE_SET_CURVE_HANDLES, def_geo_curve_set_handle_positions, "SET_CURVE_HANDLES", SetCurveHandlePositions, "Set Handle Positions", "")
+DefNode(GeometryNode, GEO_NODE_SET_CURVE_RADIUS, 0, "SET_CURVE_RADIUS", SetCurveRadius, "Set Curve Radius", "")
+DefNode(GeometryNode, GEO_NODE_SET_CURVE_TILT, 0, "SET_CURVE_TILT", SetCurveTilt, "Set Curve Tilt", "")
+DefNode(GeometryNode, GEO_NODE_SET_ID, 0, "SET_ID", SetID, "Set ID", "")
+DefNode(GeometryNode, GEO_NODE_SET_MATERIAL_INDEX, 0, "SET_MATERIAL_INDEX", SetMaterialIndex, "Set Material Index", "")
+DefNode(GeometryNode, GEO_NODE_SET_MATERIAL, 0, "SET_MATERIAL", SetMaterial, "Set Material", "")
+DefNode(GeometryNode, GEO_NODE_SET_POINT_RADIUS, 0, "SET_POINT_RADIUS", SetPointRadius, "Set Point Radius", "")
DefNode(GeometryNode, GEO_NODE_SET_POSITION, 0, "SET_POSITION", SetPosition, "Set Position", "")
-DefNode(GeometryNode, GEO_NODE_STRING_JOIN, 0, "STRING_JOIN", StringJoin, "String Join", "")
+DefNode(GeometryNode, GEO_NODE_SET_SHADE_SMOOTH, 0, "SET_SHADE_SMOOTH", SetShadeSmooth, "Set Shade Smooth", "")
+DefNode(GeometryNode, GEO_NODE_SET_SPLINE_CYCLIC, 0, "SET_SPLINE_CYCLIC", SetSplineCyclic, "Set Spline Cyclic", "")
+DefNode(GeometryNode, GEO_NODE_SET_SPLINE_RESOLUTION, 0, "SET_SPLINE_RESOLUTION", SetSplineResolution, "Set Spline Resolution", "")
+DefNode(GeometryNode, GEO_NODE_SPLIT_EDGES, 0, "SPLIT_EDGES", SplitEdges, "Split Edges", "")
+DefNode(GeometryNode, GEO_NODE_STRING_JOIN, 0, "STRING_JOIN", StringJoin, "Join Strings", "")
DefNode(GeometryNode, GEO_NODE_STRING_TO_CURVES, def_geo_string_to_curves, "STRING_TO_CURVES", StringToCurves, "String to Curves", "")
+DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_CURVE, 0, "SUBDIVIDE_CURVE", SubdivideCurve, "Subdivide Curve", "")
+DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_MESH, 0, "SUBDIVIDE_MESH", SubdivideMesh, "Subdivide Mesh", "")
+DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "")
DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "")
+DefNode(GeometryNode, GEO_NODE_TRANSFER_ATTRIBUTE, def_geo_transfer_attribute, "ATTRIBUTE_TRANSFER", AttributeTransfer, "Transfer Attribute", "")
DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "")
+DefNode(GeometryNode, GEO_NODE_TRANSLATE_INSTANCES, 0, "TRANSLATE_INSTANCES", TranslateInstances, "Translate Instances", "")
DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "")
-DefNode(GeometryNode, GEO_NODE_VIEWER, 0, "VIEWER", Viewer, "Viewer", "")
+DefNode(GeometryNode, GEO_NODE_TRIM_CURVE, def_geo_curve_trim, "TRIM_CURVE", TrimCurve, "Trim Curve", "")
+DefNode(GeometryNode, GEO_NODE_VIEWER, def_geo_viewer, "VIEWER", Viewer, "Viewer", "")
DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "")
/* undefine macros */
diff --git a/source/blender/nodes/NOD_texture.h b/source/blender/nodes/NOD_texture.h
index af59fefd925..c08bc814915 100644
--- a/source/blender/nodes/NOD_texture.h
+++ b/source/blender/nodes/NOD_texture.h
@@ -74,6 +74,22 @@ void register_node_type_tex_proc_noise(void);
void register_node_type_tex_proc_stucci(void);
void register_node_type_tex_proc_distnoise(void);
+void ntreeTexCheckCyclics(struct bNodeTree *ntree);
+struct bNodeTreeExec *ntreeTexBeginExecTree(struct bNodeTree *ntree);
+void ntreeTexEndExecTree(struct bNodeTreeExec *exec);
+int ntreeTexExecTree(struct bNodeTree *ntree,
+ struct TexResult *target,
+ const float co[3],
+ float dxt[3],
+ float dyt[3],
+ int osatex,
+ short thread,
+ const struct Tex *tex,
+ short which_output,
+ int cfra,
+ int preview,
+ struct MTex *mtex);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/nodes/composite/CMakeLists.txt b/source/blender/nodes/composite/CMakeLists.txt
new file mode 100644
index 00000000000..8d2b2befd1a
--- /dev/null
+++ b/source/blender/nodes/composite/CMakeLists.txt
@@ -0,0 +1,163 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2021, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ..
+ ../intern
+ ../../editors/include
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../depsgraph
+ ../../imbuf
+ ../../makesdna
+ ../../makesrna
+ ../../render
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern
+)
+
+
+set(SRC
+ nodes/node_composite_alpha_over.cc
+ nodes/node_composite_antialiasing.cc
+ nodes/node_composite_bilateralblur.cc
+ nodes/node_composite_blur.cc
+ nodes/node_composite_bokehblur.cc
+ nodes/node_composite_bokehimage.cc
+ nodes/node_composite_boxmask.cc
+ nodes/node_composite_brightness.cc
+ nodes/node_composite_channel_matte.cc
+ nodes/node_composite_chroma_matte.cc
+ nodes/node_composite_color_matte.cc
+ nodes/node_composite_color_spill.cc
+ nodes/node_composite_colorbalance.cc
+ nodes/node_composite_colorcorrection.cc
+ nodes/node_composite_common.cc
+ nodes/node_composite_composite.cc
+ nodes/node_composite_convert_color_space.cc
+ nodes/node_composite_cornerpin.cc
+ nodes/node_composite_crop.cc
+ nodes/node_composite_cryptomatte.cc
+ nodes/node_composite_curves.cc
+ nodes/node_composite_defocus.cc
+ nodes/node_composite_denoise.cc
+ nodes/node_composite_despeckle.cc
+ nodes/node_composite_diff_matte.cc
+ nodes/node_composite_dilate.cc
+ nodes/node_composite_directionalblur.cc
+ nodes/node_composite_displace.cc
+ nodes/node_composite_distance_matte.cc
+ nodes/node_composite_double_edge_mask.cc
+ nodes/node_composite_ellipsemask.cc
+ nodes/node_composite_exposure.cc
+ nodes/node_composite_filter.cc
+ nodes/node_composite_flip.cc
+ nodes/node_composite_gamma.cc
+ nodes/node_composite_glare.cc
+ nodes/node_composite_hue_sat_val.cc
+ nodes/node_composite_huecorrect.cc
+ nodes/node_composite_id_mask.cc
+ nodes/node_composite_image.cc
+ nodes/node_composite_inpaint.cc
+ nodes/node_composite_invert.cc
+ nodes/node_composite_keying.cc
+ nodes/node_composite_keyingscreen.cc
+ nodes/node_composite_lensdist.cc
+ nodes/node_composite_levels.cc
+ nodes/node_composite_luma_matte.cc
+ nodes/node_composite_map_range.cc
+ nodes/node_composite_map_uv.cc
+ nodes/node_composite_map_value.cc
+ nodes/node_composite_mask.cc
+ nodes/node_composite_math.cc
+ nodes/node_composite_mixrgb.cc
+ nodes/node_composite_movieclip.cc
+ nodes/node_composite_moviedistortion.cc
+ nodes/node_composite_normal.cc
+ nodes/node_composite_normalize.cc
+ nodes/node_composite_output_file.cc
+ nodes/node_composite_pixelate.cc
+ nodes/node_composite_planetrackdeform.cc
+ nodes/node_composite_posterize.cc
+ nodes/node_composite_premulkey.cc
+ nodes/node_composite_rgb.cc
+ nodes/node_composite_rotate.cc
+ nodes/node_composite_scale.cc
+ nodes/node_composite_scene_time.cc
+ nodes/node_composite_sepcomb_hsva.cc
+ nodes/node_composite_sepcomb_rgba.cc
+ nodes/node_composite_sepcomb_ycca.cc
+ nodes/node_composite_sepcomb_yuva.cc
+ nodes/node_composite_setalpha.cc
+ nodes/node_composite_split_viewer.cc
+ nodes/node_composite_stabilize2d.cc
+ nodes/node_composite_sunbeams.cc
+ nodes/node_composite_switch.cc
+ nodes/node_composite_switchview.cc
+ nodes/node_composite_texture.cc
+ nodes/node_composite_tonemap.cc
+ nodes/node_composite_trackpos.cc
+ nodes/node_composite_transform.cc
+ nodes/node_composite_translate.cc
+ nodes/node_composite_val_to_rgb.cc
+ nodes/node_composite_value.cc
+ nodes/node_composite_vec_blur.cc
+ nodes/node_composite_viewer.cc
+ nodes/node_composite_zcombine.cc
+
+ node_composite_tree.cc
+ node_composite_util.cc
+
+ node_composite_util.hh
+)
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+if(WITH_IMAGE_OPENEXR)
+ add_definitions(-DWITH_OPENEXR)
+endif()
+
+if(WITH_COMPOSITOR)
+ list(APPEND INC
+ ../../compositor
+ )
+ add_definitions(-DWITH_COMPOSITOR)
+endif()
+
+if(WITH_OPENIMAGEDENOISE)
+ add_definitions(-DWITH_OPENIMAGEDENOISE)
+endif()
+
+blender_add_lib(bf_nodes_composite "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_UNITY_BUILD)
+ set_target_properties(bf_nodes_composite PROPERTIES UNITY_BUILD ON)
+ set_target_properties(bf_nodes_composite PROPERTIES UNITY_BUILD_BATCH_SIZE 10)
+endif()
+
+# Needed so we can use dna_type_offsets.h for defaults initialization.
+add_dependencies(bf_nodes_composite bf_dna)
diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc
index ea54673faee..c54382cc1ad 100644
--- a/source/blender/nodes/composite/node_composite_tree.cc
+++ b/source/blender/nodes/composite/node_composite_tree.cc
@@ -33,8 +33,11 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
+#include "UI_resources.h"
+
#include "node_common.h"
#include "node_util.h"
@@ -104,7 +107,7 @@ static void localize(bNodeTree *localtree, bNodeTree *ntree)
local_node->original = node;
/* move over the compbufs */
- /* right after ntreeCopyTree() oldsock pointers are valid */
+ /* right after #ntreeCopyTree() `oldsock` pointers are valid */
if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
if (node->id) {
@@ -117,29 +120,11 @@ static void localize(bNodeTree *localtree, bNodeTree *ntree)
}
}
- bNodeSocket *output_sock = (bNodeSocket *)node->outputs.first;
- bNodeSocket *local_output_sock = (bNodeSocket *)local_node->outputs.first;
- while (output_sock != nullptr) {
- local_output_sock->cache = output_sock->cache;
- output_sock->cache = nullptr;
- /* This is actually link to original: someone was just lazy enough and tried to save few
- * bytes in the cost of readability. */
- local_output_sock->new_sock = output_sock;
-
- output_sock = output_sock->next;
- local_output_sock = local_output_sock->next;
- }
-
node = node->next;
local_node = local_node->next;
}
}
-static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_sync_tree(ntree, localtree);
-}
-
static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
{
bNode *lnode;
@@ -149,11 +134,11 @@ static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
BKE_node_preview_merge_tree(ntree, localtree, true);
for (lnode = (bNode *)localtree->nodes.first; lnode; lnode = lnode->next) {
- if (ntreeNodeExists(ntree, lnode->new_node)) {
+ if (bNode *orig_node = nodeFindNodebyName(ntree, lnode->name)) {
if (ELEM(lnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
if (lnode->id && (lnode->flag & NODE_DO_OUTPUT)) {
/* image_merge does sanity check for pointers */
- BKE_image_merge(bmain, (Image *)lnode->new_node->id, (Image *)lnode->id);
+ BKE_image_merge(bmain, (Image *)orig_node->id, (Image *)lnode->id);
}
}
else if (lnode->type == CMP_NODE_MOVIEDISTORTION) {
@@ -161,20 +146,19 @@ static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
* and to achieve much better performance on further calls this context should be
* copied back to original node */
if (lnode->storage) {
- if (lnode->new_node->storage) {
- BKE_tracking_distortion_free((MovieDistortion *)lnode->new_node->storage);
+ if (orig_node->storage) {
+ BKE_tracking_distortion_free((MovieDistortion *)orig_node->storage);
}
- lnode->new_node->storage = BKE_tracking_distortion_copy(
- (MovieDistortion *)lnode->storage);
+ orig_node->storage = BKE_tracking_distortion_copy((MovieDistortion *)lnode->storage);
}
}
for (lsock = (bNodeSocket *)lnode->outputs.first; lsock; lsock = lsock->next) {
- if (ntreeOutputExists(lnode->new_node, lsock->new_sock)) {
- lsock->new_sock->cache = lsock->cache;
+ if (bNodeSocket *orig_socket = nodeFindSocket(orig_node, SOCK_OUT, lsock->identifier)) {
+ orig_socket->cache = lsock->cache;
lsock->cache = nullptr;
- lsock->new_sock = nullptr;
+ orig_socket = nullptr;
}
}
}
@@ -186,11 +170,6 @@ static void update(bNodeTree *ntree)
ntreeSetOutput(ntree);
ntree_update_reroute_nodes(ntree);
-
- if (ntree->update & NTREE_UPDATE_NODES) {
- /* clean up preview cache, in case nodes have been removed */
- BKE_node_preview_remove_unused(ntree);
- }
}
static void composite_node_add_init(bNodeTree *UNUSED(bnodetree), bNode *bnode)
@@ -212,22 +191,20 @@ static bool composite_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetyp
bNodeTreeType *ntreeType_Composite;
-void register_node_tree_type_cmp(void)
+void register_node_tree_type_cmp()
{
- bNodeTreeType *tt = ntreeType_Composite = (bNodeTreeType *)MEM_callocN(
- sizeof(bNodeTreeType), "compositor node tree type");
+ bNodeTreeType *tt = ntreeType_Composite = MEM_cnew<bNodeTreeType>(__func__);
tt->type = NTREE_COMPOSIT;
strcpy(tt->idname, "CompositorNodeTree");
strcpy(tt->ui_name, N_("Compositor"));
- tt->ui_icon = 0; /* defined in drawnode.c */
+ tt->ui_icon = ICON_NODE_COMPOSITING;
strcpy(tt->ui_description, N_("Compositing nodes"));
tt->free_cache = free_cache;
tt->free_node_cache = free_node_cache;
tt->foreach_nodeclass = foreach_nodeclass;
tt->localize = localize;
- tt->local_sync = local_sync;
tt->local_merge = local_merge;
tt->update = update;
tt->get_from_context = composite_get_from_context;
@@ -259,16 +236,6 @@ void ntreeCompositExecTree(Scene *scene,
/* *********************************************** */
-/**
- * Update the outputs of the render layer nodes.
- * Since the outputs depend on the render engine, this part is a bit complex:
- * - #ntreeCompositUpdateRLayers is called and loops over all render layer nodes.
- * - Each render layer node calls the update function of the
- * render engine that's used for its scene.
- * - The render engine calls RE_engine_register_pass for each pass.
- * - #RE_engine_register_pass calls #ntreeCompositRegisterPass,
- * which calls #node_cmp_rlayers_register_pass for every render layer node.
- */
void ntreeCompositUpdateRLayers(bNodeTree *ntree)
{
if (ntree == nullptr) {
@@ -282,25 +249,6 @@ void ntreeCompositUpdateRLayers(bNodeTree *ntree)
}
}
-void ntreeCompositRegisterPass(bNodeTree *ntree,
- Scene *scene,
- ViewLayer *view_layer,
- const char *name,
- eNodeSocketDatatype type)
-{
- if (ntree == nullptr) {
- return;
- }
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == CMP_NODE_R_LAYERS) {
- node_cmp_rlayers_register_pass(ntree, node, scene, view_layer, name, type);
- }
- }
-}
-
-/* called from render pipeline, to tag render input and output */
-/* need to do all scenes, to prevent errors when you re-render 1 scene */
void ntreeCompositTagRender(Scene *scene)
{
/* XXX Think using G_MAIN here is valid, since you want to update current file's scene nodes,
@@ -313,14 +261,15 @@ void ntreeCompositTagRender(Scene *scene)
if (sce_iter->nodetree) {
LISTBASE_FOREACH (bNode *, node, &sce_iter->nodetree->nodes) {
if (node->id == (ID *)scene || node->type == CMP_NODE_COMPOSITE) {
- nodeUpdate(sce_iter->nodetree, node);
+ BKE_ntree_update_tag_node_property(sce_iter->nodetree, node);
}
else if (node->type == CMP_NODE_TEXTURE) /* uses scene size_x/size_y */ {
- nodeUpdate(sce_iter->nodetree, node);
+ BKE_ntree_update_tag_node_property(sce_iter->nodetree, node);
}
}
}
}
+ BKE_ntree_update_main(G_MAIN, nullptr);
}
/* XXX after render animation system gets a refresh, this call allows composite to end clean */
diff --git a/source/blender/nodes/composite/node_composite_util.cc b/source/blender/nodes/composite/node_composite_util.cc
index 86aaec61bc3..1f892c1c9e2 100644
--- a/source/blender/nodes/composite/node_composite_util.cc
+++ b/source/blender/nodes/composite/node_composite_util.cc
@@ -21,6 +21,8 @@
* \ingroup nodes
*/
+#include "NOD_socket_search_link.hh"
+
#include "node_composite_util.hh"
bool cmp_node_poll_default(bNodeType *UNUSED(ntype),
@@ -28,7 +30,7 @@ bool cmp_node_poll_default(bNodeType *UNUSED(ntype),
const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "CompositorNodeTree")) {
- *r_disabled_hint = "Not a compositor node tree";
+ *r_disabled_hint = TIP_("Not a compositor node tree");
return false;
}
return true;
@@ -45,12 +47,12 @@ void cmp_node_update_default(bNodeTree *UNUSED(ntree), bNode *node)
node->need_exec = 1;
}
-void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = cmp_node_poll_default;
ntype->updatefunc = cmp_node_update_default;
ntype->insert_link = node_insert_link_default;
- ntype->update_internal_links = node_update_internal_links_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
diff --git a/source/blender/nodes/composite/node_composite_util.hh b/source/blender/nodes/composite/node_composite_util.hh
index 6fd82ffc93f..65dbc2065ef 100644
--- a/source/blender/nodes/composite/node_composite_util.hh
+++ b/source/blender/nodes/composite/node_composite_util.hh
@@ -27,9 +27,6 @@
#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
#include "BLT_translation.h"
#include "BKE_colorband.h"
@@ -45,8 +42,8 @@
#include "RE_pipeline.h"
-/* only for forward declarations */
#include "NOD_composite.h"
+#include "NOD_socket.h"
#include "NOD_socket_declarations.hh"
#define CMP_SCALE_MAX 12000
@@ -55,5 +52,4 @@ bool cmp_node_poll_default(struct bNodeType *ntype,
struct bNodeTree *ntree,
const char **r_disabled_hint);
void cmp_node_update_default(struct bNodeTree *ntree, struct bNode *node);
-void cmp_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void cmp_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
diff --git a/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc b/source/blender/nodes/composite/nodes/node_composite_alpha_over.cc
index 6210d946bc7..a080b7d4840 100644
--- a/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_alpha_over.cc
@@ -21,34 +21,49 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** ALPHAOVER ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_alpha_over_cc {
static void cmp_node_alphaover_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Color>("Image", "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Image"), "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_alphaover_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- node->storage = MEM_callocN(sizeof(NodeTwoFloats), "NodeTwoFloats");
+ node->storage = MEM_cnew<NodeTwoFloats>(__func__);
+}
+
+static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_premultiply", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "premul", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
}
-void register_node_type_cmp_alphaover(void)
+} // namespace blender::nodes::node_composite_alpha_over_cc
+
+void register_node_type_cmp_alphaover()
{
+ namespace file_ns = blender::nodes::node_composite_alpha_over_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_ALPHAOVER, "Alpha Over", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_alphaover_declare;
- node_type_init(&ntype, node_alphaover_init);
+ cmp_node_type_base(&ntype, CMP_NODE_ALPHAOVER, "Alpha Over", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_alphaover_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_alphaover;
+ node_type_init(&ntype, file_ns::node_alphaover_init);
node_type_storage(
&ntype, "NodeTwoFloats", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
index 23e63b9a53b..fcc04a85b38 100644
--- a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
@@ -23,19 +23,24 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Anti-Aliasing (SMAA 1x) ******************** */
-static bNodeSocketTemplate cmp_node_antialiasing_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, {-1, ""}};
+namespace blender::nodes::node_composite_antialiasing_cc {
-static bNodeSocketTemplate cmp_node_antialiasing_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+static void cmp_node_antialiasing_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAntiAliasingData *data = (NodeAntiAliasingData *)MEM_callocN(sizeof(NodeAntiAliasingData),
- "node antialiasing data");
+ NodeAntiAliasingData *data = MEM_cnew<NodeAntiAliasingData>(__func__);
data->threshold = CMP_DEFAULT_SMAA_THRESHOLD;
data->contrast_limit = CMP_DEFAULT_SMAA_CONTRAST_LIMIT;
@@ -44,15 +49,31 @@ static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = data;
}
-void register_node_type_cmp_antialiasing(void)
+static void node_composit_buts_antialiasing(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+
+ uiItemR(col, ptr, "threshold", 0, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "contrast_limit", 0, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "corner_rounding", 0, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_antialiasing_cc
+
+void register_node_type_cmp_antialiasing()
{
+ namespace file_ns = blender::nodes::node_composite_antialiasing_cc;
+
static bNodeType ntype;
- cmp_node_type_base(
- &ntype, CMP_NODE_ANTIALIASING, "Anti-Aliasing", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_antialiasing_in, cmp_node_antialiasing_out);
+ cmp_node_type_base(&ntype, CMP_NODE_ANTIALIASING, "Anti-Aliasing", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_antialiasing_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_antialiasing;
+ ntype.flag |= NODE_PREVIEW;
node_type_size(&ntype, 170, 140, 200);
- node_type_init(&ntype, node_composit_init_antialiasing);
+ node_type_init(&ntype, file_ns::node_composit_init_antialiasing);
node_type_storage(
&ntype, "NodeAntiAliasingData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
index 3e724d17a10..1c3303103f8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
@@ -21,36 +21,55 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** BILATERALBLUR ******************** */
-static bNodeSocketTemplate cmp_node_bilateralblur_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Determinator"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_bilateralblur_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_bilateralblur_cc {
+
+static void cmp_node_bilateralblur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Determinator")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBilateralBlurData *nbbd = (NodeBilateralBlurData *)MEM_callocN(sizeof(NodeBilateralBlurData),
- "node bilateral blur data");
+ NodeBilateralBlurData *nbbd = MEM_cnew<NodeBilateralBlurData>(__func__);
node->storage = nbbd;
nbbd->iter = 1;
nbbd->sigma_color = 0.3;
nbbd->sigma_space = 5.0;
}
-void register_node_type_cmp_bilateralblur(void)
+static void node_composit_buts_bilateralblur(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "iterations", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "sigma_color", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "sigma_space", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_bilateralblur_cc
+
+void register_node_type_cmp_bilateralblur()
{
+ namespace file_ns = blender::nodes::node_composite_bilateralblur_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_BILATERALBLUR, "Bilateral Blur", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_bilateralblur_in, cmp_node_bilateralblur_out);
- node_type_init(&ntype, node_composit_init_bilateralblur);
+ cmp_node_type_base(&ntype, CMP_NODE_BILATERALBLUR, "Bilateral Blur", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_bilateralblur_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_bilateralblur;
+ node_type_init(&ntype, file_ns::node_composit_init_bilateralblur);
node_type_storage(
&ntype, "NodeBilateralBlurData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_blur.cc b/source/blender/nodes/composite/nodes/node_composite_blur.cc
index c5c0c21929e..dd0a6db74c1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_blur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_blur.cc
@@ -22,29 +22,85 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** BLUR ******************** */
-static bNodeSocketTemplate cmp_node_blur_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Size"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_blur_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+
+namespace blender::nodes::node_composite_blur_cc {
+
+static void cmp_node_blur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_blur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBlurData *data = (NodeBlurData *)MEM_callocN(sizeof(NodeBlurData), "node blur data");
+ NodeBlurData *data = MEM_cnew<NodeBlurData>(__func__);
data->filtertype = R_FILTER_GAUSS;
node->storage = data;
}
-void register_node_type_cmp_blur(void)
+static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col, *row;
+
+ col = uiLayoutColumn(layout, false);
+ const int filter = RNA_enum_get(ptr, "filter_type");
+ const int reference = RNA_boolean_get(ptr, "use_variable_size");
+
+ uiItemR(col, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ if (filter != R_FILTER_FAST_GAUSS) {
+ uiItemR(col, ptr, "use_variable_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (!reference) {
+ uiItemR(col, ptr, "use_bokeh", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ uiItemR(col, ptr, "use_gamma_correction", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+
+ uiItemR(col, ptr, "use_relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_boolean_get(ptr, "use_relative")) {
+ uiItemL(col, IFACE_("Aspect Correction"), ICON_NONE);
+ row = uiLayoutRow(layout, true);
+ uiItemR(row,
+ ptr,
+ "aspect_correction",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "factor_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "factor_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Y"), ICON_NONE);
+ }
+ else {
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "size_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "size_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Y"), ICON_NONE);
+ }
+ uiItemR(col, ptr, "use_extended_bounds", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_blur_cc
+
+void register_node_type_cmp_blur()
{
+ namespace file_ns = blender::nodes::node_composite_blur_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_BLUR, "Blur", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_blur_in, cmp_node_blur_out);
- node_type_init(&ntype, node_composit_init_blur);
+ cmp_node_type_base(&ntype, CMP_NODE_BLUR, "Blur", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_blur_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_blur;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_blur);
node_type_storage(
&ntype, "NodeBlurData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
index f130a642e20..282328b5e10 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
@@ -22,18 +22,23 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
/* **************** BLUR ******************** */
-static bNodeSocketTemplate cmp_node_bokehblur_in[] = {
- {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_RGBA, N_("Bokeh"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Size"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f},
- {SOCK_FLOAT, N_("Bounding box"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_bokehblur_out[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {-1, ""}};
+namespace blender::nodes::node_composite_bokehblur_cc {
+
+static void cmp_node_bokehblur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("Bokeh")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).max(10.0f);
+ b.add_input<decl::Float>(N_("Bounding box")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_bokehblur(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -41,13 +46,26 @@ static void node_composit_init_bokehblur(bNodeTree *UNUSED(ntree), bNode *node)
node->custom4 = 16.0f;
}
-void register_node_type_cmp_bokehblur(void)
+static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "use_variable_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ // uiItemR(layout, ptr, "f_stop", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); /* UNUSED */
+ uiItemR(layout, ptr, "blur_max", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "use_extended_bounds", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_bokehblur_cc
+
+void register_node_type_cmp_bokehblur()
+{
+ namespace file_ns = blender::nodes::node_composite_bokehblur_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_bokehblur_in, cmp_node_bokehblur_out);
- node_type_init(&ntype, node_composit_init_bokehblur);
+ cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_bokehblur_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_bokehblur;
+ node_type_init(&ntype, file_ns::node_composit_init_bokehblur);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
index 3a4bf94d256..df502bc625f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
@@ -21,22 +21,23 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
/* **************** Bokeh image Tools ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_bokehimage_cc {
static void cmp_node_bokehimage_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Color>("Image");
+ b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_bokehimage(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBokehImage *data = (NodeBokehImage *)MEM_callocN(sizeof(NodeBokehImage), "NodeBokehImage");
+ NodeBokehImage *data = MEM_cnew<NodeBokehImage>(__func__);
data->angle = 0.0f;
data->flaps = 5;
data->rounding = 0.0f;
@@ -45,13 +46,34 @@ static void node_composit_init_bokehimage(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_bokehimage(void)
+static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "flaps", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "angle", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(
+ layout, ptr, "rounding", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(layout,
+ ptr,
+ "catadioptric",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(layout, ptr, "shift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_bokehimage_cc
+
+void register_node_type_cmp_bokehimage()
+{
+ namespace file_ns = blender::nodes::node_composite_bokehimage_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_BOKEHIMAGE, "Bokeh Image", NODE_CLASS_INPUT, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_bokehimage_declare;
- node_type_init(&ntype, node_composit_init_bokehimage);
+ cmp_node_type_base(&ntype, CMP_NODE_BOKEHIMAGE, "Bokeh Image", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_bokehimage_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_bokehimage;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_bokehimage);
node_type_storage(
&ntype, "NodeBokehImage", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
index cdf96065f97..499942725c2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
@@ -21,20 +21,25 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
-static bNodeSocketTemplate cmp_node_boxmask_in[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Value"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_boxmask_out[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {-1, ""}};
+namespace blender::nodes::node_composite_boxmask_cc {
+
+static void cmp_node_boxmask_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Mask")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Mask"));
+}
static void node_composit_init_boxmask(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBoxMask *data = (NodeBoxMask *)MEM_callocN(sizeof(NodeBoxMask), "NodeBoxMask");
+ NodeBoxMask *data = MEM_cnew<NodeBoxMask>(__func__);
data->x = 0.5;
data->y = 0.5;
data->width = 0.2;
@@ -43,13 +48,34 @@ static void node_composit_init_boxmask(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_boxmask(void)
+static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row;
+
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "width", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "height", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "rotation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "mask_type", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_boxmask_cc
+
+void register_node_type_cmp_boxmask()
{
+ namespace file_ns = blender::nodes::node_composite_boxmask_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MASK_BOX, "Box Mask", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_boxmask_in, cmp_node_boxmask_out);
- node_type_init(&ntype, node_composit_init_boxmask);
+ cmp_node_type_base(&ntype, CMP_NODE_MASK_BOX, "Box Mask", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_boxmask_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_boxmask;
+ node_type_init(&ntype, file_ns::node_composit_init_boxmask);
node_type_storage(&ntype, "NodeBoxMask", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.cc b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
index ad4b09c69d0..7f60187dddf 100644
--- a/source/blender/nodes/composite/nodes/node_composite_brightness.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
@@ -21,34 +21,47 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Bright and Contrast ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_brightness_cc {
static void cmp_node_brightcontrast_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Bright").min(-100.0f).max(100.0f);
- b.add_input<decl::Float>("Contrast").min(-100.0f).max(100.0f);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Bright")).min(-100.0f).max(100.0f);
+ b.add_input<decl::Float>(N_("Contrast")).min(-100.0f).max(100.0f);
+ b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_brightcontrast(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = 1;
}
-void register_node_type_cmp_brightcontrast(void)
+static void node_composit_buts_brightcontrast(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "use_premultiply", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_brightness_cc
+
+void register_node_type_cmp_brightcontrast()
+{
+ namespace file_ns = blender::nodes::node_composite_brightness_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_brightcontrast_declare;
- node_type_init(&ntype, node_composit_init_brightcontrast);
+ cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_brightcontrast_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_brightcontrast;
+ node_type_init(&ntype, file_ns::node_composit_init_brightcontrast);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc b/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc
deleted file mode 100644
index e211bc45b17..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc
+++ /dev/null
@@ -1,64 +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) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "node_composite_util.hh"
-
-/* ******************* Channel Matte Node ********************************* */
-static bNodeSocketTemplate cmp_node_channel_matte_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_channel_matte_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
-
-static void node_composit_init_channel_matte(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
- node->storage = c;
- c->t1 = 1.0f;
- c->t2 = 0.0f;
- c->t3 = 0.0f;
- c->fsize = 0.0f;
- c->fstrength = 0.0f;
- c->algorithm = 1; /* Max channel limiting. */
- c->channel = 1; /* Limit by red. */
- node->custom1 = 1; /* RGB channel. */
- node->custom2 = 2; /* Green Channel. */
-}
-
-void register_node_type_cmp_channel_matte(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(
- &ntype, CMP_NODE_CHANNEL_MATTE, "Channel Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_channel_matte_in, cmp_node_channel_matte_out);
- node_type_init(&ntype, node_composit_init_channel_matte);
- node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_channel_matte.cc b/source/blender/nodes/composite/nodes/node_composite_channel_matte.cc
new file mode 100644
index 00000000000..a53e6a97dae
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_channel_matte.cc
@@ -0,0 +1,114 @@
+/*
+ * 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) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
+/* ******************* Channel Matte Node ********************************* */
+
+namespace blender::nodes::node_composite_channel_matte_cc {
+
+static void cmp_node_channel_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
+
+static void node_composit_init_channel_matte(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
+ node->storage = c;
+ c->t1 = 1.0f;
+ c->t2 = 0.0f;
+ c->t3 = 0.0f;
+ c->fsize = 0.0f;
+ c->fstrength = 0.0f;
+ c->algorithm = 1; /* Max channel limiting. */
+ c->channel = 1; /* Limit by red. */
+ node->custom1 = 1; /* RGB channel. */
+ node->custom2 = 2; /* Green Channel. */
+}
+
+static void node_composit_buts_channel_matte(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *col, *row;
+
+ uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
+ row = uiLayoutRow(layout, false);
+ uiItemR(
+ row, ptr, "color_space", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemL(col, IFACE_("Key Channel:"), ICON_NONE);
+ row = uiLayoutRow(col, false);
+ uiItemR(row,
+ ptr,
+ "matte_channel",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+
+ uiItemR(col, ptr, "limit_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (RNA_enum_get(ptr, "limit_method") == 0) {
+ uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
+ row = uiLayoutRow(col, false);
+ uiItemR(row,
+ ptr,
+ "limit_channel",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+ }
+
+ uiItemR(
+ col, ptr, "limit_max", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "limit_min", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_channel_matte_cc
+
+void register_node_type_cmp_channel_matte()
+{
+ namespace file_ns = blender::nodes::node_composite_channel_matte_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_CHANNEL_MATTE, "Channel Key", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_channel_matte_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_channel_matte;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_channel_matte);
+ node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc
deleted file mode 100644
index 990778160df..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc
+++ /dev/null
@@ -1,60 +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) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "node_composite_util.hh"
-
-/* ******************* Chroma Key ********************************************************** */
-static bNodeSocketTemplate cmp_node_chroma_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Key Color"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_chroma_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
-
-static void node_composit_init_chroma_matte(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
- node->storage = c;
- c->t1 = DEG2RADF(30.0f);
- c->t2 = DEG2RADF(10.0f);
- c->t3 = 0.0f;
- c->fsize = 0.0f;
- c->fstrength = 1.0f;
-}
-
-void register_node_type_cmp_chroma_matte(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(&ntype, CMP_NODE_CHROMA_MATTE, "Chroma Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_chroma_in, cmp_node_chroma_out);
- node_type_init(&ntype, node_composit_init_chroma_matte);
- node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_chroma_matte.cc b/source/blender/nodes/composite/nodes/node_composite_chroma_matte.cc
new file mode 100644
index 00000000000..a85cdd05b14
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_chroma_matte.cc
@@ -0,0 +1,84 @@
+/*
+ * 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) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
+/* ******************* Chroma Key ********************************************************** */
+
+namespace blender::nodes::node_composite_chroma_matte_cc {
+
+static void cmp_node_chroma_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
+
+static void node_composit_init_chroma_matte(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
+ node->storage = c;
+ c->t1 = DEG2RADF(30.0f);
+ c->t2 = DEG2RADF(10.0f);
+ c->t3 = 0.0f;
+ c->fsize = 0.0f;
+ c->fstrength = 1.0f;
+}
+
+static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ /* Removed for now. */
+ // uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ /* Removed for now. */
+ // uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_chroma_matte_cc
+
+void register_node_type_cmp_chroma_matte()
+{
+ namespace file_ns = blender::nodes::node_composite_chroma_matte_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_CHROMA_MATTE, "Chroma Key", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_chroma_matte_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_chroma_matte;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_chroma_matte);
+ node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc b/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc
deleted file mode 100644
index fc9a0075b14..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc
+++ /dev/null
@@ -1,60 +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) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "node_composite_util.hh"
-
-/* ******************* Color Key ********************************************************** */
-static bNodeSocketTemplate cmp_node_color_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Key Color"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_color_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
-
-static void node_composit_init_color_matte(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node color");
- node->storage = c;
- c->t1 = 0.01f;
- c->t2 = 0.1f;
- c->t3 = 0.1f;
- c->fsize = 0.0f;
- c->fstrength = 1.0f;
-}
-
-void register_node_type_cmp_color_matte(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(&ntype, CMP_NODE_COLOR_MATTE, "Color Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_color_in, cmp_node_color_out);
- node_type_init(&ntype, node_composit_init_color_matte);
- node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc b/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
deleted file mode 100644
index 7bdc2e8289e..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
+++ /dev/null
@@ -1,60 +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) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "node_composite_util.hh"
-
-/* ******************* Color Spill Suppression ********************************* */
-static bNodeSocketTemplate cmp_node_color_spill_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_color_spill_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeColorspill *ncs = (NodeColorspill *)MEM_callocN(sizeof(NodeColorspill), "node colorspill");
- node->storage = ncs;
- node->custom1 = 2; /* green channel */
- node->custom2 = 0; /* simple limit algorithm */
- ncs->limchan = 0; /* limit by red */
- ncs->limscale = 1.0f; /* limit scaling factor */
- ncs->unspill = 0; /* do not use unspill */
-}
-
-void register_node_type_cmp_color_spill(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(&ntype, CMP_NODE_COLOR_SPILL, "Color Spill", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_color_spill_in, cmp_node_color_spill_out);
- node_type_init(&ntype, node_composit_init_color_spill);
- node_type_storage(
- &ntype, "NodeColorspill", node_free_standard_storage, node_copy_standard_storage);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_color_matte.cc b/source/blender/nodes/composite/nodes/node_composite_color_matte.cc
new file mode 100644
index 00000000000..58bd0bd7d69
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_color_matte.cc
@@ -0,0 +1,85 @@
+/*
+ * 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) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
+/* ******************* Color Matte ********************************************************** */
+
+namespace blender::nodes::node_composite_color_matte_cc {
+
+static void cmp_node_color_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
+
+static void node_composit_init_color_matte(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
+ node->storage = c;
+ c->t1 = 0.01f;
+ c->t2 = 0.1f;
+ c->t3 = 0.1f;
+ c->fsize = 0.0f;
+ c->fstrength = 1.0f;
+}
+
+static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(
+ col, ptr, "color_hue", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col,
+ ptr,
+ "color_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(
+ col, ptr, "color_value", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_color_matte_cc
+
+void register_node_type_cmp_color_matte()
+{
+ namespace file_ns = blender::nodes::node_composite_color_matte_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_COLOR_MATTE, "Color Key", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_color_matte_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_color_matte;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_color_matte);
+ node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_color_spill.cc b/source/blender/nodes/composite/nodes/node_composite_color_spill.cc
new file mode 100644
index 00000000000..1ee7686a8b1
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_color_spill.cc
@@ -0,0 +1,115 @@
+/*
+ * 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) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
+/* ******************* Color Spill Suppression ********************************* */
+
+namespace blender::nodes::node_composite_color_spill_cc {
+
+static void cmp_node_color_spill_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeColorspill *ncs = MEM_cnew<NodeColorspill>(__func__);
+ node->storage = ncs;
+ node->custom1 = 2; /* green channel */
+ node->custom2 = 0; /* simple limit algorithm */
+ ncs->limchan = 0; /* limit by red */
+ ncs->limscale = 1.0f; /* limit scaling factor */
+ ncs->unspill = 0; /* do not use unspill */
+}
+
+static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row, *col;
+
+ uiItemL(layout, IFACE_("Despill Channel:"), ICON_NONE);
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "channel", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "limit_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "limit_method") == 0) {
+ uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
+ row = uiLayoutRow(col, false);
+ uiItemR(row,
+ ptr,
+ "limit_channel",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+ }
+
+ uiItemR(col, ptr, "ratio", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "use_unspill", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (RNA_boolean_get(ptr, "use_unspill") == true) {
+ uiItemR(col,
+ ptr,
+ "unspill_red",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(col,
+ ptr,
+ "unspill_green",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(col,
+ ptr,
+ "unspill_blue",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ }
+}
+
+} // namespace blender::nodes::node_composite_color_spill_cc
+
+void register_node_type_cmp_color_spill()
+{
+ namespace file_ns = blender::nodes::node_composite_color_spill_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_COLOR_SPILL, "Color Spill", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_color_spill_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_color_spill;
+ node_type_init(&ntype, file_ns::node_composit_init_color_spill);
+ node_type_storage(
+ &ntype, "NodeColorspill", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
index 440e37fe741..809641ec147 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
@@ -21,26 +21,19 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
-/* ******************* Color Balance ********************************* */
+#include "RNA_access.h"
-namespace blender::nodes {
+#include "UI_interface.h"
+#include "UI_resources.h"
-static void cmp_node_colorbalance_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Float>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Image");
-}
+#include "node_composite_util.hh"
-} // namespace blender::nodes
+/* ******************* Color Balance ********************************* */
/* Sync functions update formula parameters for other modes, such that the result is comparable.
* Note that the results are not exactly the same due to differences in color handling
* (sRGB conversion happens for LGG),
- * but this keeps settings comparable.
- */
+ * but this keeps settings comparable. */
void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -65,10 +58,18 @@ void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *UNUSED(ntree), bNode *node)
}
}
+namespace blender::nodes::node_composite_colorbalance_cc {
+
+static void cmp_node_colorbalance_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
static void node_composit_init_colorbalance(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeColorBalance *n = (NodeColorBalance *)MEM_callocN(sizeof(NodeColorBalance),
- "node colorbalance");
+ NodeColorBalance *n = MEM_cnew<NodeColorBalance>(__func__);
n->lift[0] = n->lift[1] = n->lift[2] = 1.0f;
n->gamma[0] = n->gamma[1] = n->gamma[2] = 1.0f;
@@ -80,14 +81,94 @@ static void node_composit_init_colorbalance(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = n;
}
-void register_node_type_cmp_colorbalance(void)
+static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiLayout *split, *col, *row;
+
+ uiItemR(layout, ptr, "correction_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "correction_method") == 0) {
+
+ split = uiLayoutSplit(layout, 0.0f, false);
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "lift", true, true, false, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "lift", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "gamma", true, true, true, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "gain", true, true, true, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "gain", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ else {
+
+ split = uiLayoutSplit(layout, 0.0f, false);
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "offset", true, true, false, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "offset_basis", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "power", true, true, false, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "power", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "slope", true, true, false, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "slope", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+static void node_composit_buts_colorbalance_ex(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "correction_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "correction_method") == 0) {
+
+ uiTemplateColorPicker(layout, ptr, "lift", true, true, false, true);
+ uiItemR(layout, ptr, "lift", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateColorPicker(layout, ptr, "gamma", true, true, true, true);
+ uiItemR(layout, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateColorPicker(layout, ptr, "gain", true, true, true, true);
+ uiItemR(layout, ptr, "gain", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ else {
+ uiTemplateColorPicker(layout, ptr, "offset", true, true, false, true);
+ uiItemR(layout, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateColorPicker(layout, ptr, "power", true, true, false, true);
+ uiItemR(layout, ptr, "power", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateColorPicker(layout, ptr, "slope", true, true, false, true);
+ uiItemR(layout, ptr, "slope", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+} // namespace blender::nodes::node_composite_colorbalance_cc
+
+void register_node_type_cmp_colorbalance()
+{
+ namespace file_ns = blender::nodes::node_composite_colorbalance_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_colorbalance_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_colorbalance_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_colorbalance;
+ ntype.draw_buttons_ex = file_ns::node_composit_buts_colorbalance_ex;
node_type_size(&ntype, 400, 200, 400);
- node_type_init(&ntype, node_composit_init_colorbalance);
+ node_type_init(&ntype, file_ns::node_composit_init_colorbalance);
node_type_storage(
&ntype, "NodeColorBalance", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
index 0682c66f1e8..9f1dcf24de9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
@@ -21,25 +21,25 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Color Correction ********************************* */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_colorcorrection_cc {
static void cmp_node_colorcorrection_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Mask").default_value(1.0f).min(0.0f).max(1.0f);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Mask")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_colorcorrection(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeColorCorrection *n = (NodeColorCorrection *)MEM_callocN(sizeof(NodeColorCorrection),
- "node colorcorrection");
+ NodeColorCorrection *n = MEM_cnew<NodeColorCorrection>(__func__);
n->startmidtones = 0.2f;
n->endmidtones = 0.7f;
n->master.contrast = 1.0f;
@@ -66,14 +66,236 @@ static void node_composit_init_colorcorrection(bNodeTree *UNUSED(ntree), bNode *
node->storage = n;
}
-void register_node_type_cmp_colorcorrection(void)
+static void node_composit_buts_colorcorrection(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *row;
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "red", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "green", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "blue", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, "", ICON_NONE);
+ uiItemL(row, IFACE_("Saturation"), ICON_NONE);
+ uiItemL(row, IFACE_("Contrast"), ICON_NONE);
+ uiItemL(row, IFACE_("Gamma"), ICON_NONE);
+ uiItemL(row, IFACE_("Gain"), ICON_NONE);
+ uiItemL(row, IFACE_("Lift"), ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_("Master"), ICON_NONE);
+ uiItemR(
+ row, ptr, "master_saturation", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(
+ row, ptr, "master_contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_("Highlights"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ "",
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ "",
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "highlights_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(
+ row, ptr, "highlights_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(
+ row, ptr, "highlights_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_("Midtones"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ "",
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "midtones_contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(
+ row, ptr, "midtones_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_("Shadows"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "shadows_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ "",
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "shadows_contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row,
+ ptr,
+ "midtones_start",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "midtones_end", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+static void node_composit_buts_colorcorrection_ex(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
{
+ uiLayout *row;
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "red", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "green", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "blue", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ row = layout;
+ uiItemL(row, IFACE_("Saturation"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "master_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "shadows_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+
+ uiItemL(row, IFACE_("Contrast"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "master_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "shadows_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+
+ uiItemL(row, IFACE_("Gamma"), ICON_NONE);
+ uiItemR(
+ row, ptr, "master_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_gamma",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_gamma",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "shadows_gamma",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+
+ uiItemL(row, IFACE_("Gain"), ICON_NONE);
+ uiItemR(
+ row, ptr, "master_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_gain",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_gain",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "shadows_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ uiItemL(row, IFACE_("Lift"), ICON_NONE);
+ uiItemR(
+ row, ptr, "master_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_lift",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_lift",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "shadows_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "midtones_start", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "midtones_end", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_colorcorrection_cc
+
+void register_node_type_cmp_colorcorrection()
+{
+ namespace file_ns = blender::nodes::node_composite_colorcorrection_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COLORCORRECTION, "Color Correction", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_colorcorrection_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_COLORCORRECTION, "Color Correction", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_colorcorrection_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_colorcorrection;
+ ntype.draw_buttons_ex = file_ns::node_composit_buts_colorcorrection_ex;
node_type_size(&ntype, 400, 200, 600);
- node_type_init(&ntype, node_composit_init_colorcorrection);
+ node_type_init(&ntype, file_ns::node_composit_init_colorcorrection);
node_type_storage(
&ntype, "NodeColorCorrection", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_common.cc b/source/blender/nodes/composite/nodes/node_composite_common.cc
index fecf6795ef7..d5f7279398e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_common.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_common.cc
@@ -32,26 +32,23 @@
#include "RNA_access.h"
-void register_node_type_cmp_group(void)
+void register_node_type_cmp_group()
{
static bNodeType ntype;
/* NOTE: Cannot use sh_node_type_base for node group, because it would map the node type
* to the shared NODE_GROUP integer type id. */
- node_type_base_custom(
- &ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT);
+ node_type_base_custom(&ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP);
ntype.type = NODE_GROUP;
ntype.poll = cmp_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
ntype.insert_link = node_insert_link_default;
- ntype.update_internal_links = node_update_internal_links_default;
ntype.rna_ext.srna = RNA_struct_find("CompositorNodeGroup");
BLI_assert(ntype.rna_ext.srna != nullptr);
RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
- node_type_socket_templates(&ntype, nullptr, nullptr);
node_type_size(&ntype, 140, 60, 400);
- node_type_label(&ntype, node_group_label);
+ ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
nodeRegisterType(&ntype);
@@ -66,7 +63,4 @@ void register_node_type_cmp_custom_group(bNodeType *ntype)
if (ntype->insert_link == nullptr) {
ntype->insert_link = node_insert_link_default;
}
- if (ntype->update_internal_links == nullptr) {
- ntype->update_internal_links = node_update_internal_links_default;
- }
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.cc b/source/blender/nodes/composite/nodes/node_composite_composite.cc
index 170fecb251c..b3b0e5bf432 100644
--- a/source/blender/nodes/composite/nodes/node_composite_composite.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_composite.cc
@@ -21,30 +21,40 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** COMPOSITE ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_composite_cc {
static void cmp_node_composite_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({0.0f, 0.0f, 0.0f, 1.0f});
- b.add_input<decl::Float>("Alpha").default_value(1.0f).min(0.0f).max(1.0f);
- b.add_input<decl::Float>("Z").default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Color>(N_("Image")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Alpha")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Z")).default_value(1.0f).min(0.0f).max(1.0f);
+}
+
+static void node_composit_buts_composite(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_composite_cc
-void register_node_type_cmp_composite(void)
+void register_node_type_cmp_composite()
{
- static bNodeType ntype;
+ namespace file_ns = blender::nodes::node_composite_composite_cc;
- cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_composite_declare;
+ static bNodeType ntype;
- /* Do not allow muting for this node. */
- node_type_internal_links(&ntype, nullptr);
+ cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::cmp_node_composite_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_composite;
+ ntype.flag |= NODE_PREVIEW;
+ ntype.no_muting = true;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_convert_color_space.cc b/source/blender/nodes/composite/nodes/node_composite_convert_color_space.cc
new file mode 100644
index 00000000000..75af21ab9a2
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_convert_color_space.cc
@@ -0,0 +1,83 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.hh"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "IMB_colormanagement.h"
+
+namespace blender::nodes::node_composite_convert_color_space_cc {
+
+static void CMP_NODE_CONVERT_COLOR_SPACE_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+static void node_composit_init_convert_colorspace(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeConvertColorSpace *ncs = static_cast<NodeConvertColorSpace *>(
+ MEM_callocN(sizeof(NodeConvertColorSpace), "node colorspace"));
+ const char *first_colorspace = IMB_colormanagement_role_colorspace_name_get(
+ COLOR_ROLE_SCENE_LINEAR);
+ if (first_colorspace && first_colorspace[0]) {
+ STRNCPY(ncs->from_color_space, first_colorspace);
+ STRNCPY(ncs->to_color_space, first_colorspace);
+ }
+ else {
+ ncs->from_color_space[0] = 0;
+ ncs->to_color_space[0] = 0;
+ }
+ node->storage = ncs;
+}
+
+static void node_composit_buts_convert_colorspace(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "from_color_space", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "to_color_space", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_convert_color_space_cc
+
+void register_node_type_cmp_convert_color_space(void)
+{
+ namespace file_ns = blender::nodes::node_composite_convert_color_space_cc;
+ static bNodeType ntype;
+
+ cmp_node_type_base(
+ &ntype, CMP_NODE_CONVERT_COLOR_SPACE, "Convert Colorspace", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::CMP_NODE_CONVERT_COLOR_SPACE_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_convert_colorspace;
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_init(&ntype, file_ns::node_composit_init_convert_colorspace);
+ node_type_storage(
+ &ntype, "NodeConvertColorSpace", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
index b5ca1fb015e..e4abc8106e2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
@@ -23,27 +23,41 @@
#include "node_composite_util.hh"
-static bNodeSocketTemplate inputs[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Upper Left"), 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Upper Right"), 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Lower Left"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Lower Right"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate outputs[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Plane")},
- {-1, ""},
-};
-
-void register_node_type_cmp_cornerpin(void)
+namespace blender::nodes::node_composite_cornerpin_cc {
+
+static void cmp_node_cornerpin_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Upper Left"))
+ .default_value({0.0f, 1.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f);
+ b.add_input<decl::Vector>(N_("Upper Right"))
+ .default_value({1.0f, 1.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f);
+ b.add_input<decl::Vector>(N_("Lower Left"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f);
+ b.add_input<decl::Vector>(N_("Lower Right"))
+ .default_value({1.0f, 0.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Plane"));
+}
+
+} // namespace blender::nodes::node_composite_cornerpin_cc
+
+void register_node_type_cmp_cornerpin()
{
+ namespace file_ns = blender::nodes::node_composite_cornerpin_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, inputs, outputs);
+ cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_cornerpin_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_crop.cc b/source/blender/nodes/composite/nodes/node_composite_crop.cc
index f07dba8a74b..e14b7d04ea6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_crop.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_crop.cc
@@ -21,22 +21,26 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Crop ******************** */
-static bNodeSocketTemplate cmp_node_crop_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_crop_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_crop_cc {
+
+static void cmp_node_crop_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_crop(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTwoXYs *nxy = (NodeTwoXYs *)MEM_callocN(sizeof(NodeTwoXYs), "node xy data");
+ NodeTwoXYs *nxy = MEM_cnew<NodeTwoXYs>(__func__);
node->storage = nxy;
nxy->x1 = 0;
nxy->x2 = 0;
@@ -44,13 +48,40 @@ static void node_composit_init_crop(bNodeTree *UNUSED(ntree), bNode *node)
nxy->y2 = 0;
}
-void register_node_type_cmp_crop(void)
+static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ uiItemR(layout, ptr, "use_crop_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ if (RNA_boolean_get(ptr, "relative")) {
+ uiItemR(col, ptr, "rel_min_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Left"), ICON_NONE);
+ uiItemR(col, ptr, "rel_max_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Right"), ICON_NONE);
+ uiItemR(col, ptr, "rel_min_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Up"), ICON_NONE);
+ uiItemR(col, ptr, "rel_max_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Down"), ICON_NONE);
+ }
+ else {
+ uiItemR(col, ptr, "min_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Left"), ICON_NONE);
+ uiItemR(col, ptr, "max_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Right"), ICON_NONE);
+ uiItemR(col, ptr, "min_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Up"), ICON_NONE);
+ uiItemR(col, ptr, "max_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Down"), ICON_NONE);
+ }
+}
+
+} // namespace blender::nodes::node_composite_crop_cc
+
+void register_node_type_cmp_crop()
{
+ namespace file_ns = blender::nodes::node_composite_crop_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CROP, "Crop", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_crop_in, cmp_node_crop_out);
- node_type_init(&ntype, node_composit_init_crop);
+ cmp_node_type_base(&ntype, CMP_NODE_CROP, "Crop", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_crop_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_crop;
+ node_type_init(&ntype, file_ns::node_composit_init_crop);
node_type_storage(&ntype, "NodeTwoXYs", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
index 6657267b016..40b467d608a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
@@ -38,8 +38,10 @@
#include <optional>
+/* -------------------------------------------------------------------- */
/** \name Cryptomatte
* \{ */
+
static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_node_render(
const bNode &node, const bool use_meta_data)
{
@@ -134,8 +136,7 @@ static void cryptomatte_add(const Scene &scene,
return;
}
- CryptomatteEntry *entry = static_cast<CryptomatteEntry *>(
- MEM_callocN(sizeof(CryptomatteEntry), __func__));
+ CryptomatteEntry *entry = MEM_cnew<CryptomatteEntry>(__func__);
entry->encoded_hash = encoded_hash;
blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
scene, node, true);
@@ -156,16 +157,6 @@ static void cryptomatte_remove(NodeCryptomatte &n, float encoded_hash)
MEM_freeN(entry);
}
-static bNodeSocketTemplate cmp_node_cryptomatte_in[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f}, {-1, ""}};
-
-static bNodeSocketTemplate cmp_node_cryptomatte_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {SOCK_RGBA, N_("Pick")},
- {-1, ""},
-};
-
void ntreeCompositCryptomatteSyncFromAdd(const Scene *scene, bNode *node)
{
BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY));
@@ -197,8 +188,7 @@ void ntreeCompositCryptomatteUpdateLayerNames(const Scene *scene, bNode *node)
if (session) {
for (blender::StringRef layer_name :
blender::bke::cryptomatte::BKE_cryptomatte_layer_names_get(*session)) {
- CryptomatteLayer *layer = static_cast<CryptomatteLayer *>(
- MEM_callocN(sizeof(CryptomatteLayer), __func__));
+ CryptomatteLayer *layer = MEM_cnew<CryptomatteLayer>(__func__);
layer_name.copy(layer->name);
BLI_addtail(&n->runtime.layers, layer);
}
@@ -241,10 +231,21 @@ CryptomatteSession *ntreeCompositCryptomatteSession(const Scene *scene, bNode *n
return session_ptr.release();
}
+namespace blender::nodes::node_composite_cryptomatte_cc {
+
+static bNodeSocketTemplate cmp_node_cryptomatte_in[] = {
+ {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f}, {-1, ""}};
+
+static bNodeSocketTemplate cmp_node_cryptomatte_out[] = {
+ {SOCK_RGBA, N_("Image")},
+ {SOCK_FLOAT, N_("Matte")},
+ {SOCK_RGBA, N_("Pick")},
+ {-1, ""},
+};
+
static void node_init_cryptomatte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeCryptomatte *user = static_cast<NodeCryptomatte *>(
- MEM_callocN(sizeof(NodeCryptomatte), __func__));
+ NodeCryptomatte *user = MEM_cnew<NodeCryptomatte>(__func__);
node->storage = user;
}
@@ -297,44 +298,40 @@ static bool node_poll_cryptomatte(bNodeType *UNUSED(ntype),
}
if (scene == nullptr) {
- *r_disabled_hint =
- "The node tree must be the compositing node tree of any scene in the file";
+ *r_disabled_hint = TIP_(
+ "The node tree must be the compositing node tree of any scene in the file");
}
return scene != nullptr;
}
- *r_disabled_hint = "Not a compositor node tree";
+ *r_disabled_hint = TIP_("Not a compositor node tree");
return false;
}
-void register_node_type_cmp_cryptomatte(void)
+} // namespace blender::nodes::node_composite_cryptomatte_cc
+
+void register_node_type_cmp_cryptomatte()
{
+ namespace file_ns = blender::nodes::node_composite_cryptomatte_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_cryptomatte_in, cmp_node_cryptomatte_out);
+ cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_MATTE);
+ node_type_socket_templates(
+ &ntype, file_ns::cmp_node_cryptomatte_in, file_ns::cmp_node_cryptomatte_out);
node_type_size(&ntype, 240, 100, 700);
- node_type_init(&ntype, node_init_cryptomatte);
- ntype.initfunc_api = node_init_api_cryptomatte;
- ntype.poll = node_poll_cryptomatte;
- node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
+ node_type_init(&ntype, file_ns::node_init_cryptomatte);
+ ntype.initfunc_api = file_ns::node_init_api_cryptomatte;
+ ntype.poll = file_ns::node_poll_cryptomatte;
+ node_type_storage(
+ &ntype, "NodeCryptomatte", file_ns::node_free_cryptomatte, file_ns::node_copy_cryptomatte);
nodeRegisterType(&ntype);
}
/** \} */
+/* -------------------------------------------------------------------- */
/** \name Cryptomatte Legacy
* \{ */
-static void node_init_cryptomatte_legacy(bNodeTree *ntree, bNode *node)
-{
- node_init_cryptomatte(ntree, node);
-
- nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image");
-
- /* Add three inputs by default, as recommended by the Cryptomatte specification. */
- ntreeCompositCryptomatteAddSocket(ntree, node);
- ntreeCompositCryptomatteAddSocket(ntree, node);
- ntreeCompositCryptomatteAddSocket(ntree, node);
-}
bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node)
{
@@ -361,14 +358,35 @@ int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
return 1;
}
-void register_node_type_cmp_cryptomatte_legacy(void)
+namespace blender::nodes::node_composite_cryptomatte_cc {
+
+static void node_init_cryptomatte_legacy(bNodeTree *ntree, bNode *node)
+{
+ namespace file_ns = blender::nodes::node_composite_cryptomatte_cc;
+ file_ns::node_init_cryptomatte(ntree, node);
+
+ nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image");
+
+ /* Add three inputs by default, as recommended by the Cryptomatte specification. */
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+}
+
+} // namespace blender::nodes::node_composite_cryptomatte_cc
+
+void register_node_type_cmp_cryptomatte_legacy()
{
+ namespace legacy_file_ns = blender::nodes::node_composite_cryptomatte_cc;
+ namespace file_ns = blender::nodes::node_composite_cryptomatte_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, nullptr, cmp_node_cryptomatte_out);
- node_type_init(&ntype, node_init_cryptomatte_legacy);
- node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
+ cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte", NODE_CLASS_MATTE);
+ node_type_socket_templates(&ntype, nullptr, file_ns::cmp_node_cryptomatte_out);
+ node_type_init(&ntype, file_ns::node_init_cryptomatte_legacy);
+ node_type_storage(
+ &ntype, "NodeCryptomatte", file_ns::node_free_cryptomatte, file_ns::node_copy_cryptomatte);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_curves.cc b/source/blender/nodes/composite/nodes/node_composite_curves.cc
index 88d96e1ca4a..12390a8549d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_curves.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_curves.cc
@@ -21,19 +21,20 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** CURVE Time ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_curves_cc {
static void cmp_node_time_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("Fac");
+ b.add_output<decl::Float>(N_("Fac"));
}
-} // namespace blender::nodes
-
/* custom1 = start_frame, custom2 = end_frame */
static void node_composit_init_curves_time(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -42,43 +43,56 @@ static void node_composit_init_curves_time(bNodeTree *UNUSED(ntree), bNode *node
node->storage = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
}
-void register_node_type_cmp_curve_time(void)
+} // namespace blender::nodes::node_composite_curves_cc
+
+void register_node_type_cmp_curve_time()
{
+ namespace file_ns = blender::nodes::node_composite_curves_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TIME, "Time", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::cmp_node_time_declare;
- node_type_size(&ntype, 140, 100, 320);
- node_type_init(&ntype, node_composit_init_curves_time);
+ cmp_node_type_base(&ntype, CMP_NODE_TIME, "Time Curve", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_time_declare;
+ node_type_size(&ntype, 200, 140, 320);
+ node_type_init(&ntype, file_ns::node_composit_init_curves_time);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
nodeRegisterType(&ntype);
}
/* **************** CURVE VEC ******************** */
-static bNodeSocketTemplate cmp_node_curve_vec_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_curve_vec_out[] = {
- {SOCK_VECTOR, N_("Vector")},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_curves_cc {
+
+static void cmp_node_curve_vec_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector")).default_value({0.0f, 0.0f, 0.0f}).min(-1.0f).max(1.0f);
+ b.add_output<decl::Vector>(N_("Vector"));
+}
static void node_composit_init_curve_vec(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = BKE_curvemapping_add(3, -1.0f, -1.0f, 1.0f, 1.0f);
}
-void register_node_type_cmp_curve_vec(void)
+static void node_buts_curvevec(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiTemplateCurveMapping(layout, ptr, "mapping", 'v', false, false, false, false);
+}
+
+} // namespace blender::nodes::node_composite_curves_cc
+
+void register_node_type_cmp_curve_vec()
+{
+ namespace file_ns = blender::nodes::node_composite_curves_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_curve_vec_in, cmp_node_curve_vec_out);
+ cmp_node_type_base(&ntype, CMP_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::cmp_node_curve_vec_declare;
+ ntype.draw_buttons = file_ns::node_buts_curvevec;
node_type_size(&ntype, 200, 140, 320);
- node_type_init(&ntype, node_composit_init_curve_vec);
+ node_type_init(&ntype, file_ns::node_composit_init_curve_vec);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
nodeRegisterType(&ntype);
@@ -86,32 +100,35 @@ void register_node_type_cmp_curve_vec(void)
/* **************** CURVE RGB ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_curves_cc {
static void cmp_node_rgbcurves_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Fac").default_value(1.0f).min(-1.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Color>("Black Level").default_value({0.0f, 0.0f, 0.0f, 1.0f});
- b.add_input<decl::Color>("White Level").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(-1.0f).max(1.0f).subtype(
+ PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Black Level")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Color>(N_("White Level")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_curve_rgb(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = BKE_curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f);
}
-void register_node_type_cmp_curve_rgb(void)
+} // namespace blender::nodes::node_composite_curves_cc
+
+void register_node_type_cmp_curve_rgb()
{
+ namespace file_ns = blender::nodes::node_composite_curves_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_rgbcurves_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_rgbcurves_declare;
node_type_size(&ntype, 200, 140, 320);
- node_type_init(&ntype, node_composit_init_curve_rgb);
+ node_type_init(&ntype, file_ns::node_composit_init_curve_rgb);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_defocus.cc b/source/blender/nodes/composite/nodes/node_composite_defocus.cc
index 1103aff4366..41200c97b06 100644
--- a/source/blender/nodes/composite/nodes/node_composite_defocus.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_defocus.cc
@@ -21,25 +21,30 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include <climits>
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
/* ************ Defocus Node ****************** */
-static bNodeSocketTemplate cmp_node_defocus_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Z"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_defocus_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+
+namespace blender::nodes::node_composite_defocus_cc {
+
+static void cmp_node_defocus_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Z")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_defocus(bNodeTree *UNUSED(ntree), bNode *node)
{
/* defocus node */
- NodeDefocus *nbd = (NodeDefocus *)MEM_callocN(sizeof(NodeDefocus), "node defocus data");
+ NodeDefocus *nbd = MEM_cnew<NodeDefocus>(__func__);
nbd->bktype = 0;
nbd->rotation = 0.0f;
nbd->preview = 1;
@@ -53,13 +58,57 @@ static void node_composit_init_defocus(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = nbd;
}
-void register_node_type_cmp_defocus(void)
+static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiLayout *sub, *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemL(col, IFACE_("Bokeh Type:"), ICON_NONE);
+ uiItemR(col, ptr, "bokeh", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(col, ptr, "angle", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "use_gamma_correction", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == true);
+ uiItemR(col, ptr, "f_stop", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "blur_max", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "use_preview", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "scene",
+ nullptr,
+ nullptr,
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "use_zbuffer", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ sub = uiLayoutColumn(col, false);
+ uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == false);
+ uiItemR(sub, ptr, "z_scale", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_defocus_cc
+
+void register_node_type_cmp_defocus()
{
+ namespace file_ns = blender::nodes::node_composite_defocus_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DEFOCUS, "Defocus", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_defocus_in, cmp_node_defocus_out);
- node_type_init(&ntype, node_composit_init_defocus);
+ cmp_node_type_base(&ntype, CMP_NODE_DEFOCUS, "Defocus", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_defocus_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_defocus;
+ node_type_init(&ntype, file_ns::node_composit_init_defocus);
node_type_storage(&ntype, "NodeDefocus", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.cc b/source/blender/nodes/composite/nodes/node_composite_denoise.cc
index ec085794462..d407bcbde63 100644
--- a/source/blender/nodes/composite/nodes/node_composite_denoise.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_denoise.cc
@@ -23,30 +23,65 @@
* \ingroup cmpnodes
*/
+#include "BLI_system.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_denoise_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_RGBA, N_("Albedo"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_denoise_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+namespace blender::nodes::node_composite_denoise_cc {
+
+static void cmp_node_denoise_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Normal"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(-1.0f)
+ .max(1.0f)
+ .hide_value();
+ b.add_input<decl::Color>(N_("Albedo")).default_value({1.0f, 1.0f, 1.0f, 1.0f}).hide_value();
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_denonise(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeDenoise *ndg = (NodeDenoise *)MEM_callocN(sizeof(NodeDenoise), "node denoise data");
+ NodeDenoise *ndg = MEM_cnew<NodeDenoise>(__func__);
ndg->hdr = true;
ndg->prefilter = CMP_NODE_DENOISE_PREFILTER_ACCURATE;
node->storage = ndg;
}
-void register_node_type_cmp_denoise(void)
+static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+#ifndef WITH_OPENIMAGEDENOISE
+ uiItemL(layout, IFACE_("Disabled, built without OpenImageDenoise"), ICON_ERROR);
+#else
+ /* Always supported through Accelerate framework BNNS on macOS. */
+# ifndef __APPLE__
+ if (!BLI_cpu_support_sse41()) {
+ uiItemL(layout, IFACE_("Disabled, CPU with SSE4.1 is required"), ICON_ERROR);
+ }
+# endif
+#endif
+
+ uiItemL(layout, IFACE_("Prefilter:"), ICON_NONE);
+ uiItemR(layout, ptr, "prefilter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "use_hdr", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_denoise_cc
+
+void register_node_type_cmp_denoise()
+{
+ namespace file_ns = blender::nodes::node_composite_denoise_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DENOISE, "Denoise", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_denoise_in, cmp_node_denoise_out);
- node_type_init(&ntype, node_composit_init_denonise);
+ cmp_node_type_base(&ntype, CMP_NODE_DENOISE, "Denoise", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_denoise_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_denoise;
+ node_type_init(&ntype, file_ns::node_composit_init_denonise);
node_type_storage(&ntype, "NodeDenoise", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
index 52d91dabeb1..ef9c760622c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
@@ -21,18 +21,21 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** FILTER ******************** */
-static bNodeSocketTemplate cmp_node_despeckle_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_despeckle_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+
+namespace blender::nodes::node_composite_despeckle_cc {
+
+static void cmp_node_despeckle_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_despeckle(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -40,13 +43,28 @@ static void node_composit_init_despeckle(bNodeTree *UNUSED(ntree), bNode *node)
node->custom4 = 0.5f;
}
-void register_node_type_cmp_despeckle(void)
+static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "threshold_neighbor", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_despeckle_cc
+
+void register_node_type_cmp_despeckle()
+{
+ namespace file_ns = blender::nodes::node_composite_despeckle_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DESPECKLE, "Despeckle", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_despeckle_in, cmp_node_despeckle_out);
- node_type_init(&ntype, node_composit_init_despeckle);
+ cmp_node_type_base(&ntype, CMP_NODE_DESPECKLE, "Despeckle", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_despeckle_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_despeckle;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_despeckle);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc b/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc
deleted file mode 100644
index 1e1a48381b7..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc
+++ /dev/null
@@ -1,58 +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) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "node_composite_util.hh"
-
-/* ******************* channel Difference Matte ********************************* */
-static bNodeSocketTemplate cmp_node_diff_matte_in[] = {
- {SOCK_RGBA, N_("Image 1"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Image 2"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_diff_matte_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
-
-static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
- node->storage = c;
- c->t1 = 0.1f;
- c->t2 = 0.1f;
-}
-
-void register_node_type_cmp_diff_matte(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(
- &ntype, CMP_NODE_DIFF_MATTE, "Difference Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_diff_matte_in, cmp_node_diff_matte_out);
- node_type_init(&ntype, node_composit_init_diff_matte);
- node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc b/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc
new file mode 100644
index 00000000000..9b3360c9e7d
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc
@@ -0,0 +1,75 @@
+/*
+ * 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) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
+/* ******************* channel Difference Matte ********************************* */
+
+namespace blender::nodes::node_composite_diff_matte_cc {
+
+static void cmp_node_diff_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image 1")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Image 2")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Color>(N_("Matte"));
+}
+
+static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
+ node->storage = c;
+ c->t1 = 0.1f;
+ c->t2 = 0.1f;
+}
+
+static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(
+ col, ptr, "tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_diff_matte_cc
+
+void register_node_type_cmp_diff_matte()
+{
+ namespace file_ns = blender::nodes::node_composite_diff_matte_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_DIFF_MATTE, "Difference Key", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_diff_matte_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_diff_matte;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_diff_matte);
+ node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_dilate.cc b/source/blender/nodes/composite/nodes/node_composite_dilate.cc
index 57884a299da..efd06ce8fd4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_dilate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_dilate.cc
@@ -21,29 +21,56 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Dilate/Erode ******************** */
-static bNodeSocketTemplate cmp_node_dilateerode_in[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_dilateerode_out[] = {{SOCK_FLOAT, N_("Mask")}, {-1, ""}};
+namespace blender::nodes::node_composite_dilate_cc {
+
+static void cmp_node_dilate_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Mask")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Mask"));
+}
static void node_composit_init_dilateerode(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeDilateErode *data = (NodeDilateErode *)MEM_callocN(sizeof(NodeDilateErode),
- "NodeDilateErode");
+ NodeDilateErode *data = MEM_cnew<NodeDilateErode>(__func__);
data->falloff = PROP_SMOOTH;
node->storage = data;
}
-void register_node_type_cmp_dilateerode(void)
+static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "mode", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ switch (RNA_enum_get(ptr, "mode")) {
+ case CMP_NODE_DILATEERODE_DISTANCE_THRESH:
+ uiItemR(layout, ptr, "edge", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ break;
+ case CMP_NODE_DILATEERODE_DISTANCE_FEATHER:
+ uiItemR(layout, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ break;
+ }
+}
+
+} // namespace blender::nodes::node_composite_dilate_cc
+
+void register_node_type_cmp_dilateerode()
+{
+ namespace file_ns = blender::nodes::node_composite_dilate_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_dilateerode_in, cmp_node_dilateerode_out);
- node_type_init(&ntype, node_composit_init_dilateerode);
+ cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER);
+ ntype.draw_buttons = file_ns::node_composit_buts_dilateerode;
+ ntype.declare = file_ns::cmp_node_dilate_declare;
+ node_type_init(&ntype, file_ns::node_composit_init_dilateerode);
node_type_storage(
&ntype, "NodeDilateErode", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
index d9f82ba5009..2215e62659b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
@@ -21,29 +21,64 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_dblur_in[] = {{SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""}};
+namespace blender::nodes::node_composite_directionalblur_cc {
-static bNodeSocketTemplate cmp_node_dblur_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+static void cmp_node_directional_blur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_dblur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeDBlurData *ndbd = (NodeDBlurData *)MEM_callocN(sizeof(NodeDBlurData), "node dblur data");
+ NodeDBlurData *ndbd = MEM_cnew<NodeDBlurData>(__func__);
node->storage = ndbd;
ndbd->iter = 1;
ndbd->center_x = 0.5;
ndbd->center_y = 0.5;
}
-void register_node_type_cmp_dblur(void)
+static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ uiItemR(layout, ptr, "iterations", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "use_wrap", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemL(col, IFACE_("Center:"), ICON_NONE);
+ uiItemR(col, ptr, "center_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "center_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Y"), ICON_NONE);
+
+ uiItemS(layout);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "angle", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiItemS(layout);
+
+ uiItemR(layout, ptr, "spin", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "zoom", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_directionalblur_cc
+
+void register_node_type_cmp_dblur()
{
+ namespace file_ns = blender::nodes::node_composite_directionalblur_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DBLUR, "Directional Blur", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_dblur_in, cmp_node_dblur_out);
- node_type_init(&ntype, node_composit_init_dblur);
+ cmp_node_type_base(&ntype, CMP_NODE_DBLUR, "Directional Blur", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_directional_blur_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_dblur;
+ node_type_init(&ntype, file_ns::node_composit_init_dblur);
node_type_storage(
&ntype, "NodeDBlurData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_displace.cc b/source/blender/nodes/composite/nodes/node_composite_displace.cc
index b1ed7f05794..819680e1967 100644
--- a/source/blender/nodes/composite/nodes/node_composite_displace.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_displace.cc
@@ -25,24 +25,31 @@
/* **************** Displace ******************** */
-static bNodeSocketTemplate cmp_node_displace_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_VECTOR, N_("Vector"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_TRANSLATION},
- {SOCK_FLOAT, N_("X Scale"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Y Scale"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_displace_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_displace(void)
+namespace blender::nodes::node_composite_displace_cc {
+
+static void cmp_node_displace_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Vector"))
+ .default_value({1.0f, 1.0f, 1.0f})
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_TRANSLATION);
+ b.add_input<decl::Float>(N_("X Scale")).default_value(0.0f).min(-1000.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Y Scale")).default_value(0.0f).min(-1000.0f).max(1000.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes::node_composite_displace_cc
+
+void register_node_type_cmp_displace()
{
+ namespace file_ns = blender::nodes::node_composite_displace_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DISPLACE, "Displace", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_displace_in, cmp_node_displace_out);
+ cmp_node_type_base(&ntype, CMP_NODE_DISPLACE, "Displace", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_displace_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc
deleted file mode 100644
index 3f8767ecd08..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc
+++ /dev/null
@@ -1,58 +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) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "node_composite_util.hh"
-
-/* ******************* channel Distance Matte ********************************* */
-static bNodeSocketTemplate cmp_node_distance_matte_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Key Color"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_distance_matte_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
-
-static void node_composit_init_distance_matte(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
- node->storage = c;
- c->channel = 1;
- c->t1 = 0.1f;
- c->t2 = 0.1f;
-}
-
-void register_node_type_cmp_distance_matte(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(&ntype, CMP_NODE_DIST_MATTE, "Distance Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_distance_matte_in, cmp_node_distance_matte_out);
- node_type_init(&ntype, node_composit_init_distance_matte);
- node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_distance_matte.cc b/source/blender/nodes/composite/nodes/node_composite_distance_matte.cc
new file mode 100644
index 00000000000..82781588c9d
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_distance_matte.cc
@@ -0,0 +1,83 @@
+/*
+ * 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) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
+/* ******************* channel Distance Matte ********************************* */
+
+namespace blender::nodes::node_composite_distance_matte_cc {
+
+static void cmp_node_distance_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
+
+static void node_composit_init_distance_matte(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
+ node->storage = c;
+ c->channel = 1;
+ c->t1 = 0.1f;
+ c->t2 = 0.1f;
+}
+
+static void node_composit_buts_distance_matte(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *col, *row;
+
+ col = uiLayoutColumn(layout, true);
+
+ uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "channel", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+
+ uiItemR(
+ col, ptr, "tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_distance_matte_cc
+
+void register_node_type_cmp_distance_matte()
+{
+ namespace file_ns = blender::nodes::node_composite_distance_matte_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_DIST_MATTE, "Distance Key", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_distance_matte_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_distance_matte;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_distance_matte);
+ node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc b/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc
deleted file mode 100644
index 7c9a48efc2d..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc
+++ /dev/null
@@ -1,50 +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) 2011 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-#include "node_composite_util.hh"
-/* **************** Double Edge Mask ******************** */
-
-static bNodeSocketTemplate cmp_node_doubleedgemask_in[] = {
- /* Inner mask socket definition. */
- {SOCK_FLOAT, "Inner Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- /* Outer mask socket definition. */
- {SOCK_FLOAT, "Outer Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- /* Input socket array terminator. */
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_doubleedgemask_out[] = {
- /* Output socket definition. */
- {SOCK_FLOAT, "Mask"},
- /* Output socket array terminator. */
- {-1, ""},
-};
-
-void register_node_type_cmp_doubleedgemask(void)
-{
- static bNodeType ntype; /* Allocate a node type data structure. */
-
- cmp_node_type_base(&ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_doubleedgemask_in, cmp_node_doubleedgemask_out);
- node_type_socket_templates(&ntype, cmp_node_doubleedgemask_in, cmp_node_doubleedgemask_out);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_double_edge_mask.cc b/source/blender/nodes/composite/nodes/node_composite_double_edge_mask.cc
new file mode 100644
index 00000000000..959d4ecf69e
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_double_edge_mask.cc
@@ -0,0 +1,67 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2011 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
+/* **************** Double Edge Mask ******************** */
+
+namespace blender::nodes::node_composite_double_edge_mask_cc {
+
+static void cmp_node_double_edge_mask_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Inner Mask")).default_value(0.8f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Outer Mask")).default_value(0.8f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Mask"));
+}
+
+static void node_composit_buts_double_edge_mask(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+
+ uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE);
+ uiItemR(col, ptr, "inner_mode", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemL(col, IFACE_("Buffer Edge:"), ICON_NONE);
+ uiItemR(col, ptr, "edge_mode", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_double_edge_mask_cc
+
+void register_node_type_cmp_doubleedgemask()
+{
+ namespace file_ns = blender::nodes::node_composite_double_edge_mask_cc;
+
+ static bNodeType ntype; /* Allocate a node type data structure. */
+
+ cmp_node_type_base(&ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_double_edge_mask_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_double_edge_mask;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
index 67196fb0d35..b2be8abf0cd 100644
--- a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
@@ -21,21 +21,25 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
-static bNodeSocketTemplate cmp_node_ellipsemask_in[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Value"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_ellipsemask_out[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {-1, ""}};
+namespace blender::nodes::node_composite_ellipsemask_cc {
+
+static void cmp_node_ellipsemask_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Mask")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Mask"));
+}
static void node_composit_init_ellipsemask(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeEllipseMask *data = (NodeEllipseMask *)MEM_callocN(sizeof(NodeEllipseMask),
- "NodeEllipseMask");
+ NodeEllipseMask *data = MEM_cnew<NodeEllipseMask>(__func__);
data->x = 0.5;
data->y = 0.5;
data->width = 0.2;
@@ -44,14 +48,33 @@ static void node_composit_init_ellipsemask(bNodeTree *UNUSED(ntree), bNode *node
node->storage = data;
}
-void register_node_type_cmp_ellipsemask(void)
+static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row;
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "width", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "height", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "rotation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "mask_type", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_ellipsemask_cc
+
+void register_node_type_cmp_ellipsemask()
{
+ namespace file_ns = blender::nodes::node_composite_ellipsemask_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MASK_ELLIPSE, "Ellipse Mask", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_ellipsemask_in, cmp_node_ellipsemask_out);
+ cmp_node_type_base(&ntype, CMP_NODE_MASK_ELLIPSE, "Ellipse Mask", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_ellipsemask_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_ellipsemask;
node_type_size(&ntype, 260, 110, 320);
- node_type_init(&ntype, node_composit_init_ellipsemask);
+ node_type_init(&ntype, file_ns::node_composit_init_ellipsemask);
node_type_storage(
&ntype, "NodeEllipseMask", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_exposure.cc b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
index fd959376afe..2798f4a46e8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_exposure.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
@@ -25,23 +25,25 @@
/* **************** Exposure ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_exposure_cc {
static void cmp_node_exposure_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Exposure").min(-10.0f).max(10.0f);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Exposure")).min(-10.0f).max(10.0f);
+ b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_exposure_cc
-void register_node_type_cmp_exposure(void)
+void register_node_type_cmp_exposure()
{
+ namespace file_ns = blender::nodes::node_composite_exposure_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_EXPOSURE, "Exposure", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_exposure_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_EXPOSURE, "Exposure", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_exposure_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_filter.cc b/source/blender/nodes/composite/nodes/node_composite_filter.cc
index f07619877f4..cd51e0d3c85 100644
--- a/source/blender/nodes/composite/nodes/node_composite_filter.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_filter.cc
@@ -21,26 +21,40 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** FILTER ******************** */
-static bNodeSocketTemplate cmp_node_filter_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_filter_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_filter(void)
+
+namespace blender::nodes::node_composite_filter_cc {
+
+static void cmp_node_filter_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_filter_cc
+
+void register_node_type_cmp_filter()
+{
+ namespace file_ns = blender::nodes::node_composite_filter_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_FILTER, "Filter", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_filter_in, cmp_node_filter_out);
- node_type_label(&ntype, node_filter_label);
+ cmp_node_type_base(&ntype, CMP_NODE_FILTER, "Filter", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_filter_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_filter;
+ ntype.labelfunc = node_filter_label;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_flip.cc b/source/blender/nodes/composite/nodes/node_composite_flip.cc
index 42aa3141f5c..dba98a42e93 100644
--- a/source/blender/nodes/composite/nodes/node_composite_flip.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_flip.cc
@@ -21,25 +21,37 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Flip ******************** */
-static bNodeSocketTemplate cmp_node_flip_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_flip_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_flip_cc {
-void register_node_type_cmp_flip(void)
+static void cmp_node_flip_declare(NodeDeclarationBuilder &b)
{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+static void node_composit_buts_flip(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "axis", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_flip_cc
+
+void register_node_type_cmp_flip()
+{
+ namespace file_ns = blender::nodes::node_composite_flip_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_FLIP, "Flip", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_flip_in, cmp_node_flip_out);
+ cmp_node_type_base(&ntype, CMP_NODE_FLIP, "Flip", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_flip_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_flip;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_gamma.cc b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
index a29a001688a..aafd558f0df 100644
--- a/source/blender/nodes/composite/nodes/node_composite_gamma.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
@@ -25,24 +25,29 @@
/* **************** Gamma Tools ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_gamma_cc {
static void cmp_node_gamma_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Gamma").default_value(1.0f).min(0.001f).max(10.0f).subtype(
- PROP_UNSIGNED);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Gamma"))
+ .default_value(1.0f)
+ .min(0.001f)
+ .max(10.0f)
+ .subtype(PROP_UNSIGNED);
+ b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_gamma_cc
-void register_node_type_cmp_gamma(void)
+void register_node_type_cmp_gamma()
{
+ namespace file_ns = blender::nodes::node_composite_gamma_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_gamma_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_gamma_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_glare.cc b/source/blender/nodes/composite/nodes/node_composite_glare.cc
index 8a2fd1e1584..479eeef3808 100644
--- a/source/blender/nodes/composite/nodes/node_composite_glare.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_glare.cc
@@ -21,20 +21,24 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_glare_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_glare_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_glare_cc {
+
+static void cmp_node_glare_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGlare *ndg = (NodeGlare *)MEM_callocN(sizeof(NodeGlare), "node glare data");
+ NodeGlare *ndg = MEM_cnew<NodeGlare>(__func__);
ndg->quality = 1;
ndg->type = 2;
ndg->iter = 3;
@@ -49,13 +53,56 @@ static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = ndg;
}
-void register_node_type_cmp_glare(void)
+static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "glare_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "quality", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ if (RNA_enum_get(ptr, "glare_type") != 1) {
+ uiItemR(layout, ptr, "iterations", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "glare_type") != 0) {
+ uiItemR(layout,
+ ptr,
+ "color_modulation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ }
+ }
+
+ uiItemR(layout, ptr, "mix", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "glare_type") == 2) {
+ uiItemR(layout, ptr, "streaks", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "angle_offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ if (RNA_enum_get(ptr, "glare_type") == 0 || RNA_enum_get(ptr, "glare_type") == 2) {
+ uiItemR(
+ layout, ptr, "fade", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "glare_type") == 0) {
+ uiItemR(layout, ptr, "use_rotate_45", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ }
+ if (RNA_enum_get(ptr, "glare_type") == 1) {
+ uiItemR(layout, ptr, "size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+} // namespace blender::nodes::node_composite_glare_cc
+
+void register_node_type_cmp_glare()
+{
+ namespace file_ns = blender::nodes::node_composite_glare_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_GLARE, "Glare", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_glare_in, cmp_node_glare_out);
- node_type_init(&ntype, node_composit_init_glare);
+ cmp_node_type_base(&ntype, CMP_NODE_GLARE, "Glare", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_glare_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_glare;
+ node_type_init(&ntype, file_ns::node_composit_init_glare);
node_type_storage(&ntype, "NodeGlare", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc b/source/blender/nodes/composite/nodes/node_composite_hue_sat_val.cc
index 07746918a94..c98cfcdba02 100644
--- a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_hue_sat_val.cc
@@ -25,30 +25,36 @@
/* **************** Hue Saturation ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_hue_sat_val_cc {
static void cmp_node_huesatval_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Hue").default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Float>("Saturation")
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Hue")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Saturation"))
.default_value(1.0f)
.min(0.0f)
.max(2.0f)
.subtype(PROP_FACTOR);
- b.add_input<decl::Float>("Value").default_value(1.0f).min(0.0f).max(2.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Float>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Float>(N_("Value"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(2.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_hue_sat_val_cc
-void register_node_type_cmp_hue_sat(void)
+void register_node_type_cmp_hue_sat()
{
+ namespace file_ns = blender::nodes::node_composite_hue_sat_val_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_huesatval_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_huesatval_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
index 39014896a7b..347c1588af3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
@@ -23,17 +23,15 @@
#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_huecorrect_cc {
static void cmp_node_huecorrect_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_huecorrect(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
@@ -51,14 +49,18 @@ static void node_composit_init_huecorrect(bNodeTree *UNUSED(ntree), bNode *node)
cumapping->cur = 1;
}
-void register_node_type_cmp_huecorrect(void)
+} // namespace blender::nodes::node_composite_huecorrect_cc
+
+void register_node_type_cmp_huecorrect()
{
+ namespace file_ns = blender::nodes::node_composite_huecorrect_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_HUECORRECT, "Hue Correct", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_huecorrect_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_HUECORRECT, "Hue Correct", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_huecorrect_declare;
node_type_size(&ntype, 320, 140, 500);
- node_type_init(&ntype, node_composit_init_huecorrect);
+ node_type_init(&ntype, file_ns::node_composit_init_huecorrect);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_idMask.cc b/source/blender/nodes/composite/nodes/node_composite_id_mask.cc
index 13e3536f9ee..4b7674286dd 100644
--- a/source/blender/nodes/composite/nodes/node_composite_idMask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_id_mask.cc
@@ -21,25 +21,38 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** ID Mask ******************** */
-static bNodeSocketTemplate cmp_node_idmask_in[] = {
- {SOCK_FLOAT, N_("ID value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_idmask_out[] = {
- {SOCK_FLOAT, N_("Alpha")},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_id_mask_cc {
-void register_node_type_cmp_idmask(void)
+static void cmp_node_idmask_declare(NodeDeclarationBuilder &b)
{
+ b.add_input<decl::Float>(N_("ID value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Alpha"));
+}
+
+static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "index", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "use_antialiasing", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_id_mask_cc
+
+void register_node_type_cmp_idmask()
+{
+ namespace file_ns = blender::nodes::node_composite_id_mask_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_ID_MASK, "ID Mask", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_idmask_in, cmp_node_idmask_out);
+ cmp_node_type_base(&ntype, CMP_NODE_ID_MASK, "ID Mask", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_idmask_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_id_mask;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc
index 3cef3a7625f..f2b9fbc2215 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_image.cc
@@ -26,16 +26,21 @@
#include "BLI_linklist.h"
#include "BLI_utildefines.h"
-#include "DNA_scene_types.h"
-
-#include "RE_engine.h"
-
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_scene.h"
+#include "DNA_scene_types.h"
+
+#include "RE_engine.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
/* **************** IMAGE (and RenderResult, multilayer image) ******************** */
static bNodeSocketTemplate cmp_node_rlayers_out[] = {
@@ -103,8 +108,7 @@ static void cmp_node_image_add_pass_output(bNodeTree *ntree,
sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, type, PROP_NONE, name, name);
}
/* extra socket info */
- NodeImageLayer *sockdata = (NodeImageLayer *)MEM_callocN(sizeof(NodeImageLayer),
- "node image layer");
+ NodeImageLayer *sockdata = MEM_cnew<NodeImageLayer>(__func__);
sock->storage = sockdata;
}
@@ -141,7 +145,6 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree,
* So we manually construct image user to be sure first
* image from sequence (that one which is set as filename
* for image data-block) is used for sockets detection. */
- load_iuser.ok = 1;
load_iuser.framenr = offset;
/* make sure ima->type is correct */
@@ -266,7 +269,12 @@ void node_cmp_rlayers_register_pass(bNodeTree *ntree,
}
}
-static void cmp_node_rlayer_create_outputs_cb(void *UNUSED(userdata),
+struct CreateOutputUserData {
+ bNodeTree &ntree;
+ bNode &node;
+};
+
+static void cmp_node_rlayer_create_outputs_cb(void *userdata,
Scene *scene,
ViewLayer *view_layer,
const char *name,
@@ -274,18 +282,8 @@ static void cmp_node_rlayer_create_outputs_cb(void *UNUSED(userdata),
const char *UNUSED(chanid),
eNodeSocketDatatype type)
{
- /* Register the pass in all scenes that have a render layer node for this layer.
- * Since multiple scenes can be used in the compositor, the code must loop over all scenes
- * and check whether their nodetree has a node that needs to be updated. */
- /* NOTE: using G_MAIN seems valid here,
- * unless we want to register that for every other temp Main we could generate??? */
- ntreeCompositRegisterPass(scene->nodetree, scene, view_layer, name, type);
-
- for (Scene *sce = (Scene *)G_MAIN->scenes.first; sce; sce = (Scene *)sce->id.next) {
- if (sce->nodetree && sce != scene) {
- ntreeCompositRegisterPass(sce->nodetree, scene, view_layer, name, type);
- }
- }
+ CreateOutputUserData &data = *(CreateOutputUserData *)userdata;
+ node_cmp_rlayers_register_pass(&data.ntree, &data.node, scene, view_layer, name, type);
}
static void cmp_node_rlayer_create_outputs(bNodeTree *ntree,
@@ -305,14 +303,17 @@ static void cmp_node_rlayer_create_outputs(bNodeTree *ntree,
data->prev_index = -1;
node->storage = data;
+ CreateOutputUserData userdata = {*ntree, *node};
+
RenderEngine *engine = RE_engine_create(engine_type);
RE_engine_update_render_passes(
- engine, scene, view_layer, cmp_node_rlayer_create_outputs_cb, nullptr);
+ engine, scene, view_layer, cmp_node_rlayer_create_outputs_cb, &userdata);
RE_engine_free(engine);
if ((scene->r.mode & R_EDGE_FRS) &&
(view_layer->freestyle_config.flags & FREESTYLE_AS_RENDER_PASS)) {
- ntreeCompositRegisterPass(ntree, scene, view_layer, RE_PASSNAME_FREESTYLE, SOCK_RGBA);
+ node_cmp_rlayers_register_pass(
+ ntree, node, scene, view_layer, RE_PASSNAME_FREESTYLE, SOCK_RGBA);
}
MEM_freeN(data);
@@ -373,7 +374,8 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl
for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock_next, sock_index++) {
sock_next = sock->next;
if (BLI_linklist_index(available_sockets.list, sock) >= 0) {
- sock->flag &= ~(SOCK_UNAVAIL | SOCK_HIDDEN);
+ sock->flag &= ~SOCK_HIDDEN;
+ nodeSetSocketAvailability(ntree, sock, true);
}
else {
bNodeLink *link;
@@ -387,7 +389,7 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl
nodeRemoveSocket(ntree, node, sock);
}
else {
- sock->flag |= SOCK_UNAVAIL;
+ nodeSetSocketAvailability(ntree, sock, false);
}
}
}
@@ -395,6 +397,8 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl
BLI_linklist_free(available_sockets.list, nullptr);
}
+namespace blender::nodes::node_composite_image_cc {
+
static void cmp_node_image_update(bNodeTree *ntree, bNode *node)
{
/* avoid unnecessary updates, only changes to the image/image user data are of interest */
@@ -407,11 +411,10 @@ static void cmp_node_image_update(bNodeTree *ntree, bNode *node)
static void node_composit_init_image(bNodeTree *ntree, bNode *node)
{
- ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user");
+ ImageUser *iuser = MEM_cnew<ImageUser>(__func__);
node->storage = iuser;
iuser->frames = 1;
iuser->sfra = 1;
- iuser->ok = 1;
iuser->flag |= IMA_ANIM_ALWAYS;
/* setup initial outputs */
@@ -444,15 +447,21 @@ static void node_composit_copy_image(bNodeTree *UNUSED(dest_ntree),
}
}
-void register_node_type_cmp_image(void)
+} // namespace blender::nodes::node_composite_image_cc
+
+void register_node_type_cmp_image()
{
+ namespace file_ns = blender::nodes::node_composite_image_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW);
- node_type_init(&ntype, node_composit_init_image);
- node_type_storage(&ntype, "ImageUser", node_composit_free_image, node_composit_copy_image);
- node_type_update(&ntype, cmp_node_image_update);
- node_type_label(&ntype, node_image_label);
+ cmp_node_type_base(&ntype, CMP_NODE_IMAGE, "Image", NODE_CLASS_INPUT);
+ node_type_init(&ntype, file_ns::node_composit_init_image);
+ node_type_storage(
+ &ntype, "ImageUser", file_ns::node_composit_free_image, file_ns::node_composit_copy_image);
+ node_type_update(&ntype, file_ns::cmp_node_image_update);
+ ntype.labelfunc = node_image_label;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
@@ -474,6 +483,8 @@ const char *node_cmp_rlayers_sock_to_pass(int sock_index)
return (STREQ(name, "Alpha")) ? RE_PASSNAME_COMBINED : name;
}
+namespace blender::nodes::node_composite_image_cc {
+
static void node_composit_init_rlayers(const bContext *C, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
@@ -485,8 +496,7 @@ static void node_composit_init_rlayers(const bContext *C, PointerRNA *ptr)
for (bNodeSocket *sock = (bNodeSocket *)node->outputs.first; sock;
sock = sock->next, sock_index++) {
- NodeImageLayer *sockdata = (NodeImageLayer *)MEM_callocN(sizeof(NodeImageLayer),
- "node image layer");
+ NodeImageLayer *sockdata = MEM_cnew<NodeImageLayer>(__func__);
sock->storage = sockdata;
BLI_strncpy(sockdata->pass_name,
@@ -500,7 +510,7 @@ static bool node_composit_poll_rlayers(bNodeType *UNUSED(ntype),
const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "CompositorNodeTree")) {
- *r_disabled_hint = "Not a compositor node tree";
+ *r_disabled_hint = TIP_("Not a compositor node tree");
return false;
}
@@ -517,7 +527,8 @@ static bool node_composit_poll_rlayers(bNodeType *UNUSED(ntype),
}
if (scene == nullptr) {
- *r_disabled_hint = "The node tree must be the compositing node tree of any scene in the file";
+ *r_disabled_hint = TIP_(
+ "The node tree must be the compositing node tree of any scene in the file");
return false;
}
return true;
@@ -555,16 +566,66 @@ static void cmp_node_rlayers_update(bNodeTree *ntree, bNode *node)
cmp_node_update_default(ntree, node);
}
-void register_node_type_cmp_rlayers(void)
+static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ uiLayout *col, *row;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "scene",
+ nullptr,
+ nullptr,
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (!node->id) {
+ return;
+ }
+
+ col = uiLayoutColumn(layout, false);
+ row = uiLayoutRow(col, true);
+ uiItemR(row, ptr, "layer", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ PropertyRNA *prop = RNA_struct_find_property(ptr, "layer");
+ const char *layer_name;
+ if (!(RNA_property_enum_identifier(
+ C, ptr, prop, RNA_property_enum_get(ptr, prop), &layer_name))) {
+ return;
+ }
+
+ PointerRNA scn_ptr;
+ char scene_name[MAX_ID_NAME - 2];
+ scn_ptr = RNA_pointer_get(ptr, "scene");
+ RNA_string_get(&scn_ptr, "name", scene_name);
+
+ PointerRNA op_ptr;
+ uiItemFullO(
+ row, "RENDER_OT_render", "", ICON_RENDER_STILL, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_string_set(&op_ptr, "layer", layer_name);
+ RNA_string_set(&op_ptr, "scene", scene_name);
+}
+
+} // namespace blender::nodes::node_composite_image_cc
+
+void register_node_type_cmp_rlayers()
{
+ namespace file_ns = blender::nodes::node_composite_image_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, nullptr, cmp_node_rlayers_out);
- ntype.initfunc_api = node_composit_init_rlayers;
- ntype.poll = node_composit_poll_rlayers;
- node_type_storage(&ntype, nullptr, node_composit_free_rlayers, node_composit_copy_rlayers);
- node_type_update(&ntype, cmp_node_rlayers_update);
+ ntype.draw_buttons = file_ns::node_composit_buts_viewlayers;
+ ntype.initfunc_api = file_ns::node_composit_init_rlayers;
+ ntype.poll = file_ns::node_composit_poll_rlayers;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_storage(
+ &ntype, nullptr, file_ns::node_composit_free_rlayers, file_ns::node_composit_copy_rlayers);
+ node_type_update(&ntype, file_ns::cmp_node_rlayers_update);
node_type_init(&ntype, node_cmp_rlayers_outputs);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
diff --git a/source/blender/nodes/composite/nodes/node_composite_inpaint.cc b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
index d0ff97a2ca0..f470038ad39 100644
--- a/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
@@ -21,20 +21,37 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Inpaint/ ******************** */
-static bNodeSocketTemplate cmp_node_inpaint_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_inpaint_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+namespace blender::nodes::node_composite_inpaint_cc {
-void register_node_type_cmp_inpaint(void)
+static void cmp_node_inpaint_declare(NodeDeclarationBuilder &b)
{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+static void node_composit_buts_inpaint(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_inpaint_cc
+
+void register_node_type_cmp_inpaint()
+{
+ namespace file_ns = blender::nodes::node_composite_inpaint_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_INPAINT, "Inpaint", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_inpaint_in, cmp_node_inpaint_out);
+ cmp_node_type_base(&ntype, CMP_NODE_INPAINT, "Inpaint", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_inpaint_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_inpaint;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_invert.cc b/source/blender/nodes/composite/nodes/node_composite_invert.cc
index 57b7ed36ccd..c5435f5fb92 100644
--- a/source/blender/nodes/composite/nodes/node_composite_invert.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_invert.cc
@@ -21,34 +21,48 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** INVERT ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_invert_cc {
static void cmp_node_invert_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>("Color").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Color");
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Color"));
}
-} // namespace blender::nodes
-
static void node_composit_init_invert(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 |= CMP_CHAN_RGB;
}
-/* custom1 = mix type */
-void register_node_type_cmp_invert(void)
+static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "invert_rgb", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "invert_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_invert_cc
+
+void register_node_type_cmp_invert()
{
+ namespace file_ns = blender::nodes::node_composite_invert_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_invert_declare;
- node_type_init(&ntype, node_composit_init_invert);
+ cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_invert_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_invert;
+ node_type_init(&ntype, file_ns::node_composit_init_invert);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_keying.cc b/source/blender/nodes/composite/nodes/node_composite_keying.cc
index d5547161069..26a7297acd5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_keying.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_keying.cc
@@ -21,34 +21,35 @@
* \ingroup cmpnodes
*/
+#include "BLI_math_base.h"
+
#include "BLT_translation.h"
#include "DNA_movieclip_types.h"
-#include "BLI_math_base.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
#include "node_composite_util.hh"
-/* **************** Translate ******************** */
+/* **************** Keying ******************** */
-static bNodeSocketTemplate cmp_node_keying_in[] = {
- {SOCK_RGBA, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_RGBA, "Key Color", 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, "Garbage Matte", 0.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, "Core Matte", 0.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_keying_cc {
-static bNodeSocketTemplate cmp_node_keying_out[] = {
- {SOCK_RGBA, "Image"},
- {SOCK_FLOAT, "Matte"},
- {SOCK_FLOAT, "Edges"},
- {-1, ""},
-};
+static void cmp_node_keying_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Garbage Matte")).hide_value();
+ b.add_input<decl::Float>(N_("Core Matte")).hide_value();
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+ b.add_output<decl::Float>(N_("Edges"));
+}
static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeKeyingData *data = (NodeKeyingData *)MEM_callocN(sizeof(NodeKeyingData), "node keying data");
+ NodeKeyingData *data = MEM_cnew<NodeKeyingData>(__func__);
data->screen_balance = 0.5f;
data->despill_balance = 0.5f;
@@ -60,13 +61,36 @@ static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_keying(void)
+static void node_composit_buts_keying(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ /* bNode *node = (bNode*)ptr->data; */ /* UNUSED */
+
+ uiItemR(layout, ptr, "blur_pre", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "screen_balance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "despill_factor", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "despill_balance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "edge_kernel_radius", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "edge_kernel_tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "clip_black", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "clip_white", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "dilate_distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "feather_falloff", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "feather_distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "blur_post", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_keying_cc
+
+void register_node_type_cmp_keying()
+{
+ namespace file_ns = blender::nodes::node_composite_keying_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_KEYING, "Keying", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_keying_in, cmp_node_keying_out);
- node_type_init(&ntype, node_composit_init_keying);
+ cmp_node_type_base(&ntype, CMP_NODE_KEYING, "Keying", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_keying_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_keying;
+ node_type_init(&ntype, file_ns::node_composit_init_keying);
node_type_storage(
&ntype, "NodeKeyingData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
index c976a92b92d..4862fcaa2e0 100644
--- a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
@@ -26,29 +26,67 @@
#include "BLI_math_base.h"
#include "BLI_math_color.h"
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-/* **************** Translate ******************** */
+/* **************** Keying Screen ******************** */
-static bNodeSocketTemplate cmp_node_keyingscreen_out[] = {
- {SOCK_RGBA, "Screen"},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_keyingscreen_cc {
+
+static void cmp_node_keyingscreen_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>(N_("Screen"));
+}
static void node_composit_init_keyingscreen(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeKeyingScreenData *data = (NodeKeyingScreenData *)MEM_callocN(sizeof(NodeKeyingScreenData),
- "node keyingscreen data");
+ NodeKeyingScreenData *data = MEM_cnew<NodeKeyingScreenData>(__func__);
node->storage = data;
}
-void register_node_type_cmp_keyingscreen(void)
+static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ nullptr,
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (node->id) {
+ MovieClip *clip = (MovieClip *)node->id;
+ uiLayout *col;
+ PointerRNA tracking_ptr;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTracking, &clip->tracking, &tracking_ptr);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
+ }
+}
+
+} // namespace blender::nodes::node_composite_keyingscreen_cc
+
+void register_node_type_cmp_keyingscreen()
{
+ namespace file_ns = blender::nodes::node_composite_keyingscreen_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_KEYINGSCREEN, "Keying Screen", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, nullptr, cmp_node_keyingscreen_out);
- node_type_init(&ntype, node_composit_init_keyingscreen);
+ cmp_node_type_base(&ntype, CMP_NODE_KEYINGSCREEN, "Keying Screen", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_keyingscreen_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_keyingscreen;
+ node_type_init(&ntype, file_ns::node_composit_init_keyingscreen);
node_type_storage(
&ntype, "NodeKeyingScreenData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_lensdist.cc b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
index 2a8dc035792..2d85e53016d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
@@ -21,33 +21,55 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_lensdist_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Distort"), 0.0f, 0.0f, 0.0f, 0.0f, -0.999f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Dispersion"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_lensdist_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_lensdist_cc {
+
+static void cmp_node_lensdist_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Distort")).default_value(0.0f).min(-0.999f).max(1.0f);
+ b.add_input<decl::Float>(N_("Dispersion")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_lensdist(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeLensDist *nld = (NodeLensDist *)MEM_callocN(sizeof(NodeLensDist), "node lensdist data");
+ NodeLensDist *nld = MEM_cnew<NodeLensDist>(__func__);
nld->jit = nld->proj = nld->fit = 0;
node->storage = nld;
}
-void register_node_type_cmp_lensdist(void)
+static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "use_projector", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(col, false);
+ uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false);
+ uiItemR(col, ptr, "use_jitter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "use_fit", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_lensdist_cc
+
+void register_node_type_cmp_lensdist()
{
+ namespace file_ns = blender::nodes::node_composite_lensdist_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_LENSDIST, "Lens Distortion", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_lensdist_in, cmp_node_lensdist_out);
- node_type_init(&ntype, node_composit_init_lensdist);
+ cmp_node_type_base(&ntype, CMP_NODE_LENSDIST, "Lens Distortion", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_lensdist_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_lensdist;
+ node_type_init(&ntype, file_ns::node_composit_init_lensdist);
node_type_storage(
&ntype, "NodeLensDist", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_levels.cc b/source/blender/nodes/composite/nodes/node_composite_levels.cc
index aaab8dcc874..57202d95cb7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_levels.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_levels.cc
@@ -21,33 +21,45 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** LEVELS ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_levels_cc {
static void cmp_node_levels_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({0.0f, 0.0f, 0.0f, 1.0f});
- b.add_output<decl::Float>("Mean");
- b.add_output<decl::Float>("Std Dev");
+ b.add_input<decl::Color>(N_("Image")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_output<decl::Float>(N_("Mean"));
+ b.add_output<decl::Float>(N_("Std Dev"));
}
-} // namespace blender::nodes
-
static void node_composit_init_view_levels(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = 1; /* All channels. */
}
-void register_node_type_cmp_view_levels(void)
+static void node_composit_buts_view_levels(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "channel", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_levels_cc
+
+void register_node_type_cmp_view_levels()
+{
+ namespace file_ns = blender::nodes::node_composite_levels_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_levels_declare;
- node_type_init(&ntype, node_composit_init_view_levels);
+ cmp_node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::cmp_node_levels_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_view_levels;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_view_levels);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc b/source/blender/nodes/composite/nodes/node_composite_luma_matte.cc
index 600406d22b9..851b218b617 100644
--- a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_luma_matte.cc
@@ -21,35 +21,54 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Luma Matte Node ********************************* */
-static bNodeSocketTemplate cmp_node_luma_matte_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_luma_matte_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_luma_matte_cc {
+
+static void cmp_node_luma_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
static void node_composit_init_luma_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
node->storage = c;
c->t1 = 1.0f;
c->t2 = 0.0f;
}
-void register_node_type_cmp_luma_matte(void)
+static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(
+ col, ptr, "limit_max", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "limit_min", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_luma_matte_cc
+
+void register_node_type_cmp_luma_matte()
{
+ namespace file_ns = blender::nodes::node_composite_luma_matte_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_LUMA_MATTE, "Luminance Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_luma_matte_in, cmp_node_luma_matte_out);
- node_type_init(&ntype, node_composit_init_luma_matte);
+ cmp_node_type_base(&ntype, CMP_NODE_LUMA_MATTE, "Luminance Key", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_luma_matte_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_luma_matte;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_luma_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapRange.cc b/source/blender/nodes/composite/nodes/node_composite_mapRange.cc
deleted file mode 100644
index 808ad538e55..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_mapRange.cc
+++ /dev/null
@@ -1,48 +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) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "node_composite_util.hh"
-
-/* **************** MAP VALUE ******************** */
-static bNodeSocketTemplate cmp_node_map_range_in[] = {
- {SOCK_FLOAT, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("From Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("From Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("To Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("To Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_map_range_out[] = {
- {SOCK_FLOAT, N_("Value")},
- {-1, ""},
-};
-
-void register_node_type_cmp_map_range(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(&ntype, CMP_NODE_MAP_RANGE, "Map Range", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_map_range_in, cmp_node_map_range_out);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapValue.cc b/source/blender/nodes/composite/nodes/node_composite_mapValue.cc
deleted file mode 100644
index 25c00c2ba13..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_mapValue.cc
+++ /dev/null
@@ -1,51 +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) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "node_composite_util.hh"
-
-/* **************** MAP VALUE ******************** */
-static bNodeSocketTemplate cmp_node_map_value_in[] = {
- {SOCK_FLOAT, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_map_value_out[] = {
- {SOCK_FLOAT, N_("Value")},
- {-1, ""},
-};
-
-static void node_composit_init_map_value(bNodeTree *UNUSED(ntree), bNode *node)
-{
- node->storage = BKE_texture_mapping_add(TEXMAP_TYPE_POINT);
-}
-
-void register_node_type_cmp_map_value(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(&ntype, CMP_NODE_MAP_VALUE, "Map Value", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_map_value_in, cmp_node_map_value_out);
- node_type_init(&ntype, node_composit_init_map_value);
- node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_map_range.cc b/source/blender/nodes/composite/nodes/node_composite_map_range.cc
new file mode 100644
index 00000000000..93622236c73
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_map_range.cc
@@ -0,0 +1,64 @@
+/*
+ * 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) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
+/* **************** Map Range ******************** */
+
+namespace blender::nodes::node_composite_map_range_cc {
+
+static void cmp_node_map_range_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("From Min")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("From Max")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("To Min")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("To Max")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_clamp", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_map_range_cc
+
+void register_node_type_cmp_map_range()
+{
+ namespace file_ns = blender::nodes::node_composite_map_range_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_MAP_RANGE, "Map Range", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::cmp_node_map_range_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_map_range;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapUV.cc b/source/blender/nodes/composite/nodes/node_composite_map_uv.cc
index 99032bd042e..92573a362e4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapUV.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_map_uv.cc
@@ -21,26 +21,38 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Map UV ******************** */
-static bNodeSocketTemplate cmp_node_mapuv_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_VECTOR, N_("UV"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_mapuv_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_mapuv(void)
+namespace blender::nodes::node_composite_map_uv_cc {
+
+static void cmp_node_map_uv_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("UV")).default_value({1.0f, 0.0f, 0.0f}).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_map_uv_cc
+
+void register_node_type_cmp_mapuv()
+{
+ namespace file_ns = blender::nodes::node_composite_map_uv_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MAP_UV, "Map UV", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_mapuv_in, cmp_node_mapuv_out);
+ cmp_node_type_base(&ntype, CMP_NODE_MAP_UV, "Map UV", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_map_uv_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_map_uv;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_map_value.cc b/source/blender/nodes/composite/nodes/node_composite_map_value.cc
new file mode 100644
index 00000000000..79f25dcee5f
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_map_value.cc
@@ -0,0 +1,82 @@
+/*
+ * 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) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
+/* **************** MAP VALUE ******************** */
+
+namespace blender::nodes::node_composite_map_value_cc {
+
+static void cmp_node_map_value_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+static void node_composit_init_map_value(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->storage = BKE_texture_mapping_add(TEXMAP_TYPE_POINT);
+}
+
+static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *sub, *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_min", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ sub = uiLayoutColumn(col, false);
+ uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
+ uiItemR(sub, ptr, "min", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_max", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ sub = uiLayoutColumn(col, false);
+ uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
+ uiItemR(sub, ptr, "max", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_map_value_cc
+
+void register_node_type_cmp_map_value()
+{
+ namespace file_ns = blender::nodes::node_composite_map_value_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_MAP_VALUE, "Map Value", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::cmp_node_map_value_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_map_value;
+ node_type_init(&ntype, file_ns::node_composit_init_map_value);
+ node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_mask.cc b/source/blender/nodes/composite/nodes/node_composite_mask.cc
index 8b415bb8b63..b74c7341ce3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mask.cc
@@ -23,22 +23,23 @@
#include "DNA_mask_types.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Mask ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_mask_cc {
static void cmp_node_mask_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("Mask");
+ b.add_output<decl::Float>(N_("Mask"));
}
-} // namespace blender::nodes
-
static void node_composit_init_mask(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeMask *data = (NodeMask *)MEM_callocN(sizeof(NodeMask), "NodeMask");
+ NodeMask *data = MEM_cnew<NodeMask>(__func__);
data->size_x = data->size_y = 256;
node->storage = data;
@@ -46,7 +47,10 @@ static void node_composit_init_mask(bNodeTree *UNUSED(ntree), bNode *node)
node->custom3 = 0.5f; /* shutter */
}
-static void node_mask_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void node_mask_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
if (node->id != nullptr) {
BLI_strncpy(label, node->id->name + 2, maxlen);
@@ -56,14 +60,49 @@ static void node_mask_label(bNodeTree *UNUSED(ntree), bNode *node, char *label,
}
}
-void register_node_type_cmp_mask(void)
+static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
+ bNode *node = (bNode *)ptr->data;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "mask",
+ nullptr,
+ nullptr,
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+ uiItemR(layout, ptr, "use_feather", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "size_source", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ if (node->custom1 & (CMP_NODEFLAG_MASK_FIXED | CMP_NODEFLAG_MASK_FIXED_SCENE)) {
+ uiItemR(layout, ptr, "size_x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "size_y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+
+ uiItemR(layout, ptr, "use_motion_blur", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) {
+ uiItemR(layout, ptr, "motion_blur_samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_shutter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+} // namespace blender::nodes::node_composite_mask_cc
+
+void register_node_type_cmp_mask()
+{
+ namespace file_ns = blender::nodes::node_composite_mask_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MASK, "Mask", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::cmp_node_mask_declare;
- node_type_init(&ntype, node_composit_init_mask);
- node_type_label(&ntype, node_mask_label);
+ cmp_node_type_base(&ntype, CMP_NODE_MASK, "Mask", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_mask_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_mask;
+ node_type_init(&ntype, file_ns::node_composit_init_mask);
+ ntype.labelfunc = file_ns::node_mask_label;
node_type_storage(&ntype, "NodeMask", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_math.cc b/source/blender/nodes/composite/nodes/node_composite_math.cc
index ecddcc2ad32..1083d85ba7c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_math.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_math.cc
@@ -24,21 +24,34 @@
#include "node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
-static bNodeSocketTemplate cmp_node_math_in[] = {
- {SOCK_FLOAT, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Value"), 0.0f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_math_out[] = {{SOCK_FLOAT, N_("Value")}, {-1, ""}};
+namespace blender::nodes::node_composite_math_cc {
-void register_node_type_cmp_math(void)
+static void cmp_node_math_declare(NodeDeclarationBuilder &b)
{
+ b.add_input<decl::Float>(N_("Value")).default_value(0.5f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Value"), "Value_001")
+ .default_value(0.5f)
+ .min(-10000.0f)
+ .max(10000.0f);
+ b.add_input<decl::Float>(N_("Value"), "Value_002")
+ .default_value(0.5f)
+ .min(-10000.0f)
+ .max(10000.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+} // namespace blender::nodes::node_composite_math_cc
+
+void register_node_type_cmp_math()
+{
+ namespace file_ns = blender::nodes::node_composite_math_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_math_in, cmp_node_math_out);
- node_type_label(&ntype, node_math_label);
+ cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_math_declare;
+ ntype.labelfunc = node_math_label;
node_type_update(&ntype, node_math_update);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
index 4f2a9c2717c..7a10fa599de 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
@@ -25,26 +25,28 @@
/* **************** MIX RGB ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_mixrgb_cc {
static void cmp_node_mixrgb_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Color>("Image", "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Image"), "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_mixrgb_cc
-/* custom1 = mix type */
-void register_node_type_cmp_mix_rgb(void)
+void register_node_type_cmp_mix_rgb()
{
+ namespace file_ns = blender::nodes::node_composite_mixrgb_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_mixrgb_declare;
- node_type_label(&ntype, node_blend_label);
+ cmp_node_type_base(&ntype, CMP_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR);
+ ntype.flag |= NODE_PREVIEW;
+ ntype.declare = file_ns::cmp_node_mixrgb_declare;
+ ntype.labelfunc = node_blend_label;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
index ae91212f811..f6f00864839 100644
--- a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
@@ -21,31 +21,34 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "DNA_defaults.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_movieclip_cc {
static void cmp_node_movieclip_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Color>("Image");
- b.add_output<decl::Float>("Alpha");
- b.add_output<decl::Float>("Offset X");
- b.add_output<decl::Float>("Offset Y");
- b.add_output<decl::Float>("Scale");
- b.add_output<decl::Float>("Angle");
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Alpha"));
+ b.add_output<decl::Float>(N_("Offset X"));
+ b.add_output<decl::Float>(N_("Offset Y"));
+ b.add_output<decl::Float>(N_("Scale"));
+ b.add_output<decl::Float>(N_("Angle"));
}
-} // namespace blender::nodes
-
static void init(const bContext *C, PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
Scene *scene = CTX_data_scene(C);
- MovieClipUser *user = (MovieClipUser *)MEM_callocN(sizeof(MovieClipUser),
- "node movie clip user");
+ MovieClipUser *user = DNA_struct_default_alloc(MovieClipUser);
node->id = (ID *)scene->clip;
id_us_plus(node->id);
@@ -53,13 +56,59 @@ static void init(const bContext *C, PointerRNA *ptr)
user->framenr = 1;
}
-void register_node_type_cmp_movieclip(void)
+static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+}
+
+static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
+ bNode *node = (bNode *)ptr->data;
+ PointerRNA clipptr;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (!node->id) {
+ return;
+ }
+
+ clipptr = RNA_pointer_get(ptr, "clip");
+
+ uiTemplateColorspaceSettings(layout, &clipptr, "colorspace_settings");
+}
+
+} // namespace blender::nodes::node_composite_movieclip_cc
+
+void register_node_type_cmp_movieclip()
+{
+ namespace file_ns = blender::nodes::node_composite_movieclip_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MOVIECLIP, "Movie Clip", NODE_CLASS_INPUT, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_movieclip_declare;
- ntype.initfunc_api = init;
+ cmp_node_type_base(&ntype, CMP_NODE_MOVIECLIP, "Movie Clip", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_movieclip_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_movieclip;
+ ntype.draw_buttons_ex = file_ns::node_composit_buts_movieclip_ex;
+ ntype.initfunc_api = file_ns::init;
+ ntype.flag |= NODE_PREVIEW;
node_type_storage(
&ntype, "MovieClipUser", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
index 2bac30cc152..396c6fa7a13 100644
--- a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
@@ -21,24 +21,25 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
/* **************** Translate ******************** */
-static bNodeSocketTemplate cmp_node_moviedistortion_in[] = {
- {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_moviedistortion_cc {
-static bNodeSocketTemplate cmp_node_moviedistortion_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+static void cmp_node_moviedistortion_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
-static void label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
if (node->custom1 == 0) {
BLI_strncpy(label, IFACE_("Undistortion"), maxlen);
@@ -73,16 +74,42 @@ static void storage_copy(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const
}
}
-void register_node_type_cmp_moviedistortion(void)
+static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- static bNodeType ntype;
+ bNode *node = (bNode *)ptr->data;
- cmp_node_type_base(&ntype, CMP_NODE_MOVIEDISTORTION, "Movie Distortion", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_moviedistortion_in, cmp_node_moviedistortion_out);
- node_type_label(&ntype, label);
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (!node->id) {
+ return;
+ }
+
+ uiItemR(layout, ptr, "distortion_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_moviedistortion_cc
+
+void register_node_type_cmp_moviedistortion()
+{
+ namespace file_ns = blender::nodes::node_composite_moviedistortion_cc;
+
+ static bNodeType ntype;
- ntype.initfunc_api = init;
- node_type_storage(&ntype, nullptr, storage_free, storage_copy);
+ cmp_node_type_base(&ntype, CMP_NODE_MOVIEDISTORTION, "Movie Distortion", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_moviedistortion_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_moviedistortion;
+ ntype.labelfunc = file_ns::label;
+ ntype.initfunc_api = file_ns::init;
+ node_type_storage(&ntype, nullptr, file_ns::storage_free, file_ns::storage_copy);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_normal.cc b/source/blender/nodes/composite/nodes/node_composite_normal.cc
index 7531025daa5..da44d355966 100644
--- a/source/blender/nodes/composite/nodes/node_composite_normal.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_normal.cc
@@ -24,23 +24,30 @@
#include "node_composite_util.hh"
/* **************** NORMAL ******************** */
-static bNodeSocketTemplate cmp_node_normal_in[] = {
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_DIRECTION},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_normal_out[] = {
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_DIRECTION},
- {SOCK_FLOAT, N_("Dot")},
- {-1, ""},
-};
-
-void register_node_type_cmp_normal(void)
+
+namespace blender::nodes::node_composite_normal_cc {
+
+static void cmp_node_normal_declare(NodeDeclarationBuilder &b)
{
+ b.add_input<decl::Vector>(N_("Normal"))
+ .default_value({1.0f, 1.0f, 1.0f})
+ .min(-1.0f)
+ .max(1.0f)
+ .subtype(PROP_DIRECTION);
+ b.add_output<decl::Vector>(N_("Normal"));
+ b.add_output<decl::Float>(N_("Dot"));
+}
+
+} // namespace blender::nodes::node_composite_normal_cc
+
+void register_node_type_cmp_normal()
+{
+ namespace file_ns = blender::nodes::node_composite_normal_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_normal_in, cmp_node_normal_out);
+ cmp_node_type_base(&ntype, CMP_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::cmp_node_normal_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_normalize.cc b/source/blender/nodes/composite/nodes/node_composite_normalize.cc
index 7cc54e4eed6..3d25187e5e6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_normalize.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_normalize.cc
@@ -24,16 +24,25 @@
#include "node_composite_util.hh"
/* **************** NORMALIZE single channel, useful for Z buffer ******************** */
-static bNodeSocketTemplate cmp_node_normalize_in[] = {
- {SOCK_FLOAT, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_normalize_out[] = {{SOCK_FLOAT, N_("Value")}, {-1, ""}};
-void register_node_type_cmp_normalize(void)
+namespace blender::nodes::node_composite_normalize_cc {
+
+static void cmp_node_normalize_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+} // namespace blender::nodes::node_composite_normalize_cc
+
+void register_node_type_cmp_normalize()
{
+ namespace file_ns = blender::nodes::node_composite_normalize_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_NORMALIZE, "Normalize", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_normalize_in, cmp_node_normalize_out);
+ cmp_node_type_base(&ntype, CMP_NODE_NORMALIZE, "Normalize", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::cmp_node_normalize_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.cc b/source/blender/nodes/composite/nodes/node_composite_output_file.cc
index a372d2f7419..544c8437394 100644
--- a/source/blender/nodes/composite/nodes/node_composite_outputFile.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_output_file.cc
@@ -21,14 +21,21 @@
* \ingroup cmpnodes
*/
+#include <cstring>
+
+#include "BLI_string_utf8.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
-#include <cstring>
#include "BKE_context.h"
#include "RNA_access.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+
#include "node_composite_util.hh"
#include "intern/openexr/openexr_multi.h"
@@ -128,8 +135,7 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree,
ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, name);
/* create format data for the input socket */
- NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)MEM_callocN(
- sizeof(NodeImageMultiFileSocket), "socket image format");
+ NodeImageMultiFileSocket *sockdata = MEM_cnew<NodeImageMultiFileSocket>(__func__);
sock->storage = sockdata;
BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path));
@@ -190,14 +196,15 @@ void ntreeCompositOutputFileSetLayer(bNode *node, bNodeSocket *sock, const char
ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_');
}
+namespace blender::nodes::node_composite_output_file_cc {
+
/* XXX uses initfunc_api callback, regular initfunc does not support context yet */
static void init_output_file(const bContext *C, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- NodeImageMultiFile *nimf = (NodeImageMultiFile *)MEM_callocN(sizeof(NodeImageMultiFile),
- "node image multi file");
+ NodeImageMultiFile *nimf = MEM_cnew<NodeImageMultiFile>(__func__);
ImageFormatData *format = nullptr;
node->storage = nimf;
@@ -275,15 +282,177 @@ static void update_output_file(bNodeTree *ntree, bNode *node)
}
}
-void register_node_type_cmp_output_file(void)
+static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ PointerRNA imfptr = RNA_pointer_get(ptr, "format");
+ const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
+
+ if (multilayer) {
+ uiItemL(layout, IFACE_("Path:"), ICON_NONE);
+ }
+ else {
+ uiItemL(layout, IFACE_("Base Path:"), ICON_NONE);
+ }
+ uiItemR(layout, ptr, "base_path", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
+ Scene *scene = CTX_data_scene(C);
+ PointerRNA imfptr = RNA_pointer_get(ptr, "format");
+ PointerRNA active_input_ptr, op_ptr;
+ uiLayout *row, *col;
+ const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
+ const bool is_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+
+ node_composit_buts_file_output(layout, C, ptr);
+ uiTemplateImageSettings(layout, &imfptr, false);
+
+ /* disable stereo output for multilayer, too much work for something that no one will use */
+ /* if someone asks for that we can implement it */
+ if (is_multiview) {
+ uiTemplateImageFormatViews(layout, &imfptr, nullptr);
+ }
+
+ uiItemS(layout);
+
+ uiItemO(layout, IFACE_("Add Input"), ICON_ADD, "NODE_OT_output_file_add_socket");
+
+ row = uiLayoutRow(layout, false);
+ col = uiLayoutColumn(row, true);
+
+ const int active_index = RNA_int_get(ptr, "active_input_index");
+ /* using different collection properties if multilayer format is enabled */
+ if (multilayer) {
+ uiTemplateList(col,
+ C,
+ "UI_UL_list",
+ "file_output_node",
+ ptr,
+ "layer_slots",
+ ptr,
+ "active_input_index",
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ UI_TEMPLATE_LIST_FLAG_NONE);
+ RNA_property_collection_lookup_int(
+ ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr);
+ }
+ else {
+ uiTemplateList(col,
+ C,
+ "UI_UL_list",
+ "file_output_node",
+ ptr,
+ "file_slots",
+ ptr,
+ "active_input_index",
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ UI_TEMPLATE_LIST_FLAG_NONE);
+ RNA_property_collection_lookup_int(
+ ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr);
+ }
+ /* XXX collection lookup does not return the ID part of the pointer,
+ * setting this manually here */
+ active_input_ptr.owner_id = ptr->owner_id;
+
+ col = uiLayoutColumn(row, true);
+ wmOperatorType *ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false);
+ uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_enum_set(&op_ptr, "direction", 1);
+ uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_enum_set(&op_ptr, "direction", 2);
+
+ if (active_input_ptr.data) {
+ if (multilayer) {
+ col = uiLayoutColumn(layout, true);
+
+ uiItemL(col, IFACE_("Layer:"), ICON_NONE);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, &active_input_ptr, "name", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemFullO(row,
+ "NODE_OT_output_file_remove_active_socket",
+ "",
+ ICON_X,
+ nullptr,
+ WM_OP_EXEC_DEFAULT,
+ UI_ITEM_R_ICON_ONLY,
+ nullptr);
+ }
+ else {
+ col = uiLayoutColumn(layout, true);
+
+ uiItemL(col, IFACE_("File Subpath:"), ICON_NONE);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, &active_input_ptr, "path", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemFullO(row,
+ "NODE_OT_output_file_remove_active_socket",
+ "",
+ ICON_X,
+ nullptr,
+ WM_OP_EXEC_DEFAULT,
+ UI_ITEM_R_ICON_ONLY,
+ nullptr);
+
+ /* format details for individual files */
+ imfptr = RNA_pointer_get(&active_input_ptr, "format");
+
+ col = uiLayoutColumn(layout, true);
+ uiItemL(col, IFACE_("Format:"), ICON_NONE);
+ uiItemR(col,
+ &active_input_ptr,
+ "use_node_format",
+ UI_ITEM_R_SPLIT_EMPTY_NAME,
+ nullptr,
+ ICON_NONE);
+
+ const bool is_socket_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
+ const bool use_node_format = RNA_boolean_get(&active_input_ptr, "use_node_format");
+
+ if ((!is_exr && use_node_format) || (!is_socket_exr && !use_node_format)) {
+ uiItemR(col,
+ &active_input_ptr,
+ "save_as_render",
+ UI_ITEM_R_SPLIT_EMPTY_NAME,
+ nullptr,
+ ICON_NONE);
+ }
+
+ col = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(col, use_node_format == false);
+ uiTemplateImageSettings(col, &imfptr, false);
+
+ if (is_multiview) {
+ uiTemplateImageFormatViews(layout, &imfptr, nullptr);
+ }
+ }
+ }
+}
+
+} // namespace blender::nodes::node_composite_output_file_cc
+
+void register_node_type_cmp_output_file()
+{
+ namespace file_ns = blender::nodes::node_composite_output_file_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- node_type_socket_templates(&ntype, nullptr, nullptr);
- ntype.initfunc_api = init_output_file;
- node_type_storage(&ntype, "NodeImageMultiFile", free_output_file, copy_output_file);
- node_type_update(&ntype, update_output_file);
+ cmp_node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT);
+ ntype.draw_buttons = file_ns::node_composit_buts_file_output;
+ ntype.draw_buttons_ex = file_ns::node_composit_buts_file_output_ex;
+ ntype.initfunc_api = file_ns::init_output_file;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_storage(
+ &ntype, "NodeImageMultiFile", file_ns::free_output_file, file_ns::copy_output_file);
+ node_type_update(&ntype, file_ns::update_output_file);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
index 19975c21a0b..baded2186d3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
@@ -25,16 +25,24 @@
/* **************** Pixelate ******************** */
-static bNodeSocketTemplate cmp_node_pixelate_in[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_pixelate_out[] = {{SOCK_RGBA, N_("Color")}, {-1, ""}};
+namespace blender::nodes::node_composite_pixelate_cc {
-void register_node_type_cmp_pixelate(void)
+static void cmp_node_pixelate_declare(NodeDeclarationBuilder &b)
{
+ b.add_input<decl::Color>(N_("Color"));
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+} // namespace blender::nodes::node_composite_pixelate_cc
+
+void register_node_type_cmp_pixelate()
+{
+ namespace file_ns = blender::nodes::node_composite_pixelate_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_PIXELATE, "Pixelate", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_pixelate_in, cmp_node_pixelate_out);
+ cmp_node_type_base(&ntype, CMP_NODE_PIXELATE, "Pixelate", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_pixelate_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
index e122b710b7b..453501b6ab1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
@@ -21,34 +21,91 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_planetrackdeform_in[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}};
+namespace blender::nodes::node_composite_planetrackdeform_cc {
-static bNodeSocketTemplate cmp_node_planetrackdeform_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Plane")},
- {-1, ""},
-};
+static void cmp_node_planetrackdeform_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image"));
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Plane"));
+}
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)MEM_callocN(
- sizeof(NodePlaneTrackDeformData), "node plane track deform data");
+ NodePlaneTrackDeformData *data = MEM_cnew<NodePlaneTrackDeformData>(__func__);
data->motion_blur_samples = 16;
data->motion_blur_shutter = 0.5f;
node->storage = data;
}
-void register_node_type_cmp_planetrackdeform(void)
+static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
+ bNode *node = (bNode *)ptr->data;
+ NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)node->storage;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (node->id) {
+ MovieClip *clip = (MovieClip *)node->id;
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object;
+ uiLayout *col;
+ PointerRNA tracking_ptr;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
+
+ object = BKE_tracking_object_get_named(tracking, data->tracking_object);
+ if (object) {
+ PointerRNA object_ptr;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
+
+ uiItemPointerR(
+ col, ptr, "plane_track_name", &object_ptr, "plane_tracks", "", ICON_ANIM_DATA);
+ }
+ else {
+ uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA);
+ }
+ }
+
+ uiItemR(layout, ptr, "use_motion_blur", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
+ uiItemR(layout, ptr, "motion_blur_samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_shutter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+} // namespace blender::nodes::node_composite_planetrackdeform_cc
+
+void register_node_type_cmp_planetrackdeform()
+{
+ namespace file_ns = blender::nodes::node_composite_planetrackdeform_cc;
+
static bNodeType ntype;
- cmp_node_type_base(
- &ntype, CMP_NODE_PLANETRACKDEFORM, "Plane Track Deform", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_planetrackdeform_in, cmp_node_planetrackdeform_out);
- node_type_init(&ntype, init);
+ cmp_node_type_base(&ntype, CMP_NODE_PLANETRACKDEFORM, "Plane Track Deform", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_planetrackdeform_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_planetrackdeform;
+ node_type_init(&ntype, file_ns::init);
node_type_storage(
&ntype, "NodePlaneTrackDeformData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_posterize.cc b/source/blender/nodes/composite/nodes/node_composite_posterize.cc
index 45a98e68b4b..f05ed3d80b7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_posterize.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_posterize.cc
@@ -25,22 +25,25 @@
/* **************** Posterize ******************** */
-static bNodeSocketTemplate cmp_node_posterize_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Steps"), 8.0f, 8.0f, 8.0f, 8.0f, 2.0f, 1024.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_posterize_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_posterize(void)
+namespace blender::nodes::node_composite_posterize_cc {
+
+static void cmp_node_posterize_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Steps")).default_value(8.0f).min(2.0f).max(1024.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes::node_composite_posterize_cc
+
+void register_node_type_cmp_posterize()
{
+ namespace file_ns = blender::nodes::node_composite_posterize_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_POSTERIZE, "Posterize", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_posterize_in, cmp_node_posterize_out);
+ cmp_node_type_base(&ntype, CMP_NODE_POSTERIZE, "Posterize", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_posterize_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
index 68716ee53b5..aec005ee25a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
@@ -21,25 +21,37 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Premul and Key Alpha Convert ******************** */
-static bNodeSocketTemplate cmp_node_premulkey_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_premulkey_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_premulkey_cc {
-void register_node_type_cmp_premulkey(void)
+static void cmp_node_premulkey_declare(NodeDeclarationBuilder &b)
{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mapping", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_premulkey_cc
+
+void register_node_type_cmp_premulkey()
+{
+ namespace file_ns = blender::nodes::node_composite_premulkey_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_PREMULKEY, "Alpha Convert", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_premulkey_in, cmp_node_premulkey_out);
+ cmp_node_type_base(&ntype, CMP_NODE_PREMULKEY, "Alpha Convert", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_premulkey_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_premulkey;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_rgb.cc b/source/blender/nodes/composite/nodes/node_composite_rgb.cc
index 332e56e26b1..feaa3ee8c19 100644
--- a/source/blender/nodes/composite/nodes/node_composite_rgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_rgb.cc
@@ -25,21 +25,23 @@
/* **************** RGB ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_rgb_cc {
static void cmp_node_rgb_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Color>("RGBA").default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_output<decl::Color>(N_("RGBA")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_rgb_cc
-void register_node_type_cmp_rgb(void)
+void register_node_type_cmp_rgb()
{
+ namespace file_ns = blender::nodes::node_composite_rgb_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_RGB, "RGB", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::cmp_node_rgb_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_RGB, "RGB", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_rgb_declare;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_rotate.cc b/source/blender/nodes/composite/nodes/node_composite_rotate.cc
index d28b35ec9fb..96ac4f3db5b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_rotate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_rotate.cc
@@ -21,32 +21,48 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Rotate ******************** */
-static bNodeSocketTemplate cmp_node_rotate_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Degr"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_ANGLE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_rotate_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_rotate_cc {
+
+static void cmp_node_rotate_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Degr"))
+ .default_value(0.0f)
+ .min(-10000.0f)
+ .max(10000.0f)
+ .subtype(PROP_ANGLE);
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_rotate(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = 1; /* Bilinear Filter. */
}
-void register_node_type_cmp_rotate(void)
+static void node_composit_buts_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_rotate_cc
+
+void register_node_type_cmp_rotate()
+{
+ namespace file_ns = blender::nodes::node_composite_rotate_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_rotate_in, cmp_node_rotate_out);
- node_type_init(&ntype, node_composit_init_rotate);
+ cmp_node_type_base(&ntype, CMP_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_rotate_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_rotate;
+ node_type_init(&ntype, file_ns::node_composit_init_rotate);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.cc b/source/blender/nodes/composite/nodes/node_composite_scale.cc
index 3972fc0d949..dba08dd7eb1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_scale.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_scale.cc
@@ -21,18 +21,26 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Scale ******************** */
-static bNodeSocketTemplate cmp_node_scale_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("X"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX, PROP_NONE},
- {SOCK_FLOAT, N_("Y"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX, PROP_NONE},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_scale_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+namespace blender::nodes::node_composite_scale_cc {
+
+static void cmp_node_scale_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("X")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
+ b.add_input<decl::Float>(N_("Y")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
+ b.add_output<decl::Color>(N_("Image"));
+}
-static void node_composite_update_scale(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_composite_update_scale(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sock;
bool use_xy_scale = ELEM(node->custom1, CMP_SCALE_RELATIVE, CMP_SCALE_ABSOLUTE);
@@ -40,23 +48,41 @@ static void node_composite_update_scale(bNodeTree *UNUSED(ntree), bNode *node)
/* Only show X/Y scale factor inputs for modes using them! */
for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
if (STR_ELEM(sock->name, "X", "Y")) {
- if (use_xy_scale) {
- sock->flag &= ~SOCK_UNAVAIL;
- }
- else {
- sock->flag |= SOCK_UNAVAIL;
- }
+ nodeSetSocketAvailability(ntree, sock, use_xy_scale);
}
}
}
-void register_node_type_cmp_scale(void)
+static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "space", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) {
+ uiLayout *row;
+ uiItemR(layout,
+ ptr,
+ "frame_method",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "offset_x", UI_ITEM_R_SPLIT_EMPTY_NAME, "X", ICON_NONE);
+ uiItemR(row, ptr, "offset_y", UI_ITEM_R_SPLIT_EMPTY_NAME, "Y", ICON_NONE);
+ }
+}
+
+} // namespace blender::nodes::node_composite_scale_cc
+
+void register_node_type_cmp_scale()
{
+ namespace file_ns = blender::nodes::node_composite_scale_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_scale_in, cmp_node_scale_out);
- node_type_update(&ntype, node_composite_update_scale);
+ cmp_node_type_base(&ntype, CMP_NODE_SCALE, "Scale", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_scale_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_scale;
+ node_type_update(&ntype, file_ns::node_composite_update_scale);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_scene_time.cc b/source/blender/nodes/composite/nodes/node_composite_scene_time.cc
new file mode 100644
index 00000000000..5c53c1df237
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_scene_time.cc
@@ -0,0 +1,39 @@
+/*
+ * 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 cmpnodes
+ */
+
+#include "node_composite_util.hh"
+
+namespace blender::nodes {
+
+static void cmp_node_scene_time_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Seconds"));
+ b.add_output<decl::Float>(N_("Frame"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_scene_time()
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_SCENE_TIME, "Scene Time", NODE_CLASS_INPUT);
+ ntype.declare = blender::nodes::cmp_node_scene_time_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
deleted file mode 100644
index 17b1ab9ac59..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
+++ /dev/null
@@ -1,70 +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) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "node_composite_util.hh"
-
-/* **************** SEPARATE HSVA ******************** */
-static bNodeSocketTemplate cmp_node_sephsva_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_sephsva_out[] = {
- {SOCK_FLOAT, N_("H")},
- {SOCK_FLOAT, N_("S")},
- {SOCK_FLOAT, N_("V")},
- {SOCK_FLOAT, N_("A")},
- {-1, ""},
-};
-
-void register_node_type_cmp_sephsva(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_sephsva_in, cmp_node_sephsva_out);
-
- nodeRegisterType(&ntype);
-}
-
-/* **************** COMBINE HSVA ******************** */
-static bNodeSocketTemplate cmp_node_combhsva_in[] = {
- {SOCK_FLOAT, N_("H"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("S"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("V"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("A"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_combhsva_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_combhsva(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_combhsva_in, cmp_node_combhsva_out);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
deleted file mode 100644
index d3a021ed7ba..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
+++ /dev/null
@@ -1,70 +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) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "node_composite_util.hh"
-
-/* **************** SEPARATE RGBA ******************** */
-static bNodeSocketTemplate cmp_node_seprgba_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_seprgba_out[] = {
- {SOCK_FLOAT, N_("R")},
- {SOCK_FLOAT, N_("G")},
- {SOCK_FLOAT, N_("B")},
- {SOCK_FLOAT, N_("A")},
- {-1, ""},
-};
-
-void register_node_type_cmp_seprgba(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_seprgba_in, cmp_node_seprgba_out);
-
- nodeRegisterType(&ntype);
-}
-
-/* **************** COMBINE RGBA ******************** */
-static bNodeSocketTemplate cmp_node_combrgba_in[] = {
- {SOCK_FLOAT, N_("R"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("G"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("B"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("A"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_combrgba_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_combrgba(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_combrgba_in, cmp_node_combrgba_out);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
deleted file mode 100644
index 59982b81468..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
+++ /dev/null
@@ -1,68 +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) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "node_composite_util.hh"
-
-/* **************** SEPARATE YUVA ******************** */
-static bNodeSocketTemplate cmp_node_sepyuva_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_sepyuva_out[] = {
- {SOCK_FLOAT, N_("Y")},
- {SOCK_FLOAT, N_("U")},
- {SOCK_FLOAT, N_("V")},
- {SOCK_FLOAT, N_("A")},
- {-1, ""},
-};
-
-void register_node_type_cmp_sepyuva(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_sepyuva_in, cmp_node_sepyuva_out);
-
- nodeRegisterType(&ntype);
-}
-
-/* **************** COMBINE YUVA ******************** */
-static bNodeSocketTemplate cmp_node_combyuva_in[] = {
- {SOCK_FLOAT, N_("Y"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("U"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("V"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("A"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_combyuva_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_combyuva(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_combyuva_in, cmp_node_combyuva_out);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
new file mode 100644
index 00000000000..41d0668dbf2
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
@@ -0,0 +1,77 @@
+/*
+ * 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) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.hh"
+
+/* **************** SEPARATE HSVA ******************** */
+
+namespace blender::nodes::node_composite_sepcomb_hsva_cc {
+
+static void cmp_node_sephsva_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>(N_("H"));
+ b.add_output<decl::Float>(N_("S"));
+ b.add_output<decl::Float>(N_("V"));
+ b.add_output<decl::Float>(N_("A"));
+}
+
+} // namespace blender::nodes::node_composite_sepcomb_hsva_cc
+
+void register_node_type_cmp_sephsva()
+{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_hsva_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_sephsva_declare;
+ nodeRegisterType(&ntype);
+}
+
+/* **************** COMBINE HSVA ******************** */
+
+namespace blender::nodes::node_composite_sepcomb_hsva_cc {
+
+static void cmp_node_combhsva_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("H")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("S")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("V")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("A")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes::node_composite_sepcomb_hsva_cc
+
+void register_node_type_cmp_combhsva()
+{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_hsva_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_combhsva_declare;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
new file mode 100644
index 00000000000..bd200b0886f
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
@@ -0,0 +1,77 @@
+/*
+ * 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) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.hh"
+
+/* **************** SEPARATE RGBA ******************** */
+namespace blender::nodes::node_composite_sepcomb_rgba_cc {
+
+static void cmp_node_seprgba_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>(N_("R"));
+ b.add_output<decl::Float>(N_("G"));
+ b.add_output<decl::Float>(N_("B"));
+ b.add_output<decl::Float>(N_("A"));
+}
+
+} // namespace blender::nodes::node_composite_sepcomb_rgba_cc
+
+void register_node_type_cmp_seprgba()
+{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_rgba_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_seprgba_declare;
+
+ nodeRegisterType(&ntype);
+}
+
+/* **************** COMBINE RGBA ******************** */
+
+namespace blender::nodes::node_composite_sepcomb_rgba_cc {
+
+static void cmp_node_combrgba_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("R")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("G")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("B")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("A")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes::node_composite_sepcomb_rgba_cc
+
+void register_node_type_cmp_combrgba()
+{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_rgba_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_combrgba_declare;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
index 2090841b3b9..79cb379806c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
@@ -24,57 +24,67 @@
#include "node_composite_util.hh"
/* **************** SEPARATE YCCA ******************** */
-static bNodeSocketTemplate cmp_node_sepycca_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_sepycca_out[] = {
- {SOCK_FLOAT, N_("Y")},
- {SOCK_FLOAT, N_("Cb")},
- {SOCK_FLOAT, N_("Cr")},
- {SOCK_FLOAT, N_("A")},
- {-1, ""},
-};
+
+namespace blender::nodes::node_composite_sepcomb_ycca_cc {
+
+static void cmp_node_sepycca_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>(N_("Y"));
+ b.add_output<decl::Float>(N_("Cb"));
+ b.add_output<decl::Float>(N_("Cr"));
+ b.add_output<decl::Float>(N_("A"));
+}
static void node_composit_init_mode_sepycca(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = 1; /* BLI_YCC_ITU_BT709 */
}
-void register_node_type_cmp_sepycca(void)
+} // namespace blender::nodes::node_composite_sepcomb_ycca_cc
+
+void register_node_type_cmp_sepycca()
{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_ycca_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_sepycca_in, cmp_node_sepycca_out);
- node_type_init(&ntype, node_composit_init_mode_sepycca);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_sepycca_declare;
+ node_type_init(&ntype, file_ns::node_composit_init_mode_sepycca);
nodeRegisterType(&ntype);
}
/* **************** COMBINE YCCA ******************** */
-static bNodeSocketTemplate cmp_node_combycca_in[] = {
- {SOCK_FLOAT, N_("Y"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Cb"), 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Cr"), 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("A"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_combycca_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+
+namespace blender::nodes::node_composite_sepcomb_ycca_cc {
+
+static void cmp_node_combycca_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Y")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Cb")).default_value(0.5f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Cr")).default_value(0.5f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("A")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_mode_combycca(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = 1; /* BLI_YCC_ITU_BT709 */
}
-void register_node_type_cmp_combycca(void)
+} // namespace blender::nodes::node_composite_sepcomb_ycca_cc
+
+void register_node_type_cmp_combycca()
{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_ycca_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_combycca_in, cmp_node_combycca_out);
- node_type_init(&ntype, node_composit_init_mode_combycca);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_combycca_declare;
+ node_type_init(&ntype, file_ns::node_composit_init_mode_combycca);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
new file mode 100644
index 00000000000..29c0f753e00
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
@@ -0,0 +1,78 @@
+/*
+ * 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) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.hh"
+
+/* **************** SEPARATE YUVA ******************** */
+
+namespace blender::nodes::node_composite_sepcomb_yuva_cc {
+
+static void cmp_node_sepyuva_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>(N_("Y"));
+ b.add_output<decl::Float>(N_("U"));
+ b.add_output<decl::Float>(N_("V"));
+ b.add_output<decl::Float>(N_("A"));
+}
+
+} // namespace blender::nodes::node_composite_sepcomb_yuva_cc
+
+void register_node_type_cmp_sepyuva()
+{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_yuva_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_sepyuva_declare;
+
+ nodeRegisterType(&ntype);
+}
+
+/* **************** COMBINE YUVA ******************** */
+
+namespace blender::nodes::node_composite_sepcomb_yuva_cc {
+
+static void cmp_node_combyuva_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Y")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("U")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("V")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("A")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes::node_composite_sepcomb_yuva_cc
+
+void register_node_type_cmp_combyuva()
+{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_yuva_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_combyuva_declare;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
index a2089bd0913..18f8fe45833 100644
--- a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
@@ -21,33 +21,46 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** SET ALPHA ******************** */
-static bNodeSocketTemplate cmp_node_setalpha_in[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_setalpha_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+
+namespace blender::nodes::node_composite_setalpha_cc {
+
+static void cmp_node_setalpha_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Alpha")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_setalpha(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeSetAlpha *settings = (NodeSetAlpha *)MEM_callocN(sizeof(NodeSetAlpha), __func__);
+ NodeSetAlpha *settings = MEM_cnew<NodeSetAlpha>(__func__);
node->storage = settings;
settings->mode = CMP_NODE_SETALPHA_MODE_APPLY;
}
-void register_node_type_cmp_setalpha(void)
+static void node_composit_buts_set_alpha(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "mode", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_setalpha_cc
+
+void register_node_type_cmp_setalpha()
+{
+ namespace file_ns = blender::nodes::node_composite_setalpha_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SETALPHA, "Set Alpha", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_setalpha_in, cmp_node_setalpha_out);
- node_type_init(&ntype, node_composit_init_setalpha);
+ cmp_node_type_base(&ntype, CMP_NODE_SETALPHA, "Set Alpha", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_setalpha_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_set_alpha;
+ node_type_init(&ntype, file_ns::node_composit_init_setalpha);
node_type_storage(
&ntype, "NodeSetAlpha", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc b/source/blender/nodes/composite/nodes/node_composite_split_viewer.cc
index 27fbb0fafd4..68a6c8c2943 100644
--- a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_split_viewer.cc
@@ -21,46 +21,60 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include "BKE_global.h"
#include "BKE_image.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
/* **************** SPLIT VIEWER ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_split_viewer_cc {
-static void cmp_node_splitviewer_declare(NodeDeclarationBuilder &b)
+static void cmp_node_split_viewer_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image");
- b.add_input<decl::Color>("Image");
+ b.add_input<decl::Color>(N_("Image"));
+ b.add_input<decl::Color>(N_("Image"), "Image_001");
}
-} // namespace blender::nodes
-
static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode *node)
{
- ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user");
+ ImageUser *iuser = MEM_cnew<ImageUser>(__func__);
node->storage = iuser;
iuser->sfra = 1;
- iuser->ok = 1;
node->custom1 = 50; /* default 50% split */
node->id = (ID *)BKE_image_ensure_viewer(G.main, IMA_TYPE_COMPOSITE, "Viewer Node");
}
-void register_node_type_cmp_splitviewer(void)
+static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiLayout *row, *col;
+
+ col = uiLayoutColumn(layout, false);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "axis", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "factor", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_split_viewer_cc
+
+void register_node_type_cmp_splitviewer()
+{
+ namespace file_ns = blender::nodes::node_composite_split_viewer_cc;
+
static bNodeType ntype;
- cmp_node_type_base(
- &ntype, CMP_NODE_SPLITVIEWER, "Split Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_splitviewer_declare;
- node_type_init(&ntype, node_composit_init_splitviewer);
+ cmp_node_type_base(&ntype, CMP_NODE_SPLITVIEWER, "Split Viewer", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::cmp_node_split_viewer_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_splitviewer;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_splitviewer);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
- /* Do not allow muting for this node. */
- node_type_internal_links(&ntype, nullptr);
+ ntype.no_muting = true;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
index e5ce2e8ceb9..5fe057f4f2e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
@@ -21,22 +21,23 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
#include "BKE_context.h"
#include "BKE_lib_id.h"
-/* **************** Translate ******************** */
+#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_stabilize2d_in[] = {
- {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+/* **************** Stabilize 2D ******************** */
-static bNodeSocketTemplate cmp_node_stabilize2d_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_stabilize2d_cc {
+
+static void cmp_node_stabilize2d_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
static void init(const bContext *C, PointerRNA *ptr)
{
@@ -50,13 +51,41 @@ static void init(const bContext *C, PointerRNA *ptr)
node->custom1 = 1;
}
-void register_node_type_cmp_stabilize2d(void)
+static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (!node->id) {
+ return;
+ }
+
+ uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "invert", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_stabilize2d_cc
+
+void register_node_type_cmp_stabilize2d()
{
+ namespace file_ns = blender::nodes::node_composite_stabilize2d_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_STABILIZE2D, "Stabilize 2D", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_stabilize2d_in, cmp_node_stabilize2d_out);
- ntype.initfunc_api = init;
+ cmp_node_type_base(&ntype, CMP_NODE_STABILIZE2D, "Stabilize 2D", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_stabilize2d_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_stabilize2d;
+ ntype.initfunc_api = file_ns::init;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
index 73907d2e27f..34433e2bf40 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
@@ -21,33 +21,51 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate inputs[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate outputs[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_sunbeams_cc {
+
+static void cmp_node_sunbeams_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeSunBeams *data = (NodeSunBeams *)MEM_callocN(sizeof(NodeSunBeams), "sun beams node");
+ NodeSunBeams *data = MEM_cnew<NodeSunBeams>(__func__);
data->source[0] = 0.5f;
data->source[1] = 0.5f;
node->storage = data;
}
-void register_node_type_cmp_sunbeams(void)
+static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "source", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, "", ICON_NONE);
+ uiItemR(layout,
+ ptr,
+ "ray_length",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_sunbeams_cc
+
+void register_node_type_cmp_sunbeams()
+{
+ namespace file_ns = blender::nodes::node_composite_sunbeams_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SUNBEAMS, "Sun Beams", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, inputs, outputs);
- node_type_init(&ntype, init);
+ cmp_node_type_base(&ntype, CMP_NODE_SUNBEAMS, "Sun Beams", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_sunbeams_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_sunbeams;
+ node_type_init(&ntype, file_ns::init);
node_type_storage(
&ntype, "NodeSunBeams", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_switch.cc b/source/blender/nodes/composite/nodes/node_composite_switch.cc
index 71226a6da0b..342813f8d67 100644
--- a/source/blender/nodes/composite/nodes/node_composite_switch.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_switch.cc
@@ -21,27 +21,38 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.hh"
-
-/* **************** MIX RGB ******************** */
-static bNodeSocketTemplate cmp_node_switch_in[] = {
- {SOCK_RGBA, N_("Off"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_RGBA, N_("On"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_switch_out[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
-
-/* custom1 = mix type */
-void register_node_type_cmp_switch(void)
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
+/* **************** Switch ******************** */
+
+namespace blender::nodes::node_composite_switch_cc {
+
+static void cmp_node_switch_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Off")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("On")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "check", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_switch_cc
+
+void register_node_type_cmp_switch()
{
+ namespace file_ns = blender::nodes::node_composite_switch_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SWITCH, "Switch", NODE_CLASS_LAYOUT, 0);
- node_type_socket_templates(&ntype, cmp_node_switch_in, cmp_node_switch_out);
+ cmp_node_type_base(&ntype, CMP_NODE_SWITCH, "Switch", NODE_CLASS_LAYOUT);
+ ntype.declare = file_ns::cmp_node_switch_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_switch;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_switchview.cc b/source/blender/nodes/composite/nodes/node_composite_switchview.cc
index a61712f7f8d..678d7fe1a9b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_switchview.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_switchview.cc
@@ -25,9 +25,15 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
-#include "../node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
/* **************** SWITCH VIEW ******************** */
+
+namespace blender::nodes::node_composite_switchview_cc {
+
static bNodeSocketTemplate cmp_node_switch_view_out[] = {
{SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
{-1, ""},
@@ -137,16 +143,33 @@ static void init_switch_view(const bContext *C, PointerRNA *ptr)
cmp_node_switch_view_sanitycheck(ntree, node);
}
-void register_node_type_cmp_switch_view(void)
+static void node_composit_buts_switch_view_ex(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr))
{
- static bNodeType ntype;
+ uiItemFullO(layout,
+ "NODE_OT_switch_view_update",
+ "Update Views",
+ ICON_FILE_REFRESH,
+ nullptr,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ nullptr);
+}
+
+} // namespace blender::nodes::node_composite_switchview_cc
- cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, nullptr, cmp_node_switch_view_out);
+void register_node_type_cmp_switch_view()
+{
+ namespace file_ns = blender::nodes::node_composite_switchview_cc;
- ntype.initfunc_api = init_switch_view;
+ static bNodeType ntype;
- node_type_update(&ntype, cmp_node_switch_view_update);
+ cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTER);
+ node_type_socket_templates(&ntype, nullptr, file_ns::cmp_node_switch_view_out);
+ ntype.draw_buttons_ex = file_ns::node_composit_buts_switch_view_ex;
+ ntype.initfunc_api = file_ns::init_switch_view;
+ node_type_update(&ntype, file_ns::cmp_node_switch_view_update);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_texture.cc b/source/blender/nodes/composite/nodes/node_composite_texture.cc
index eff008b4b41..5c2446d4f2c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_texture.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_texture.cc
@@ -25,28 +25,31 @@
/* **************** TEXTURE ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_texture_cc {
static void cmp_node_texture_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Vector>("Offset").min(-2.0f).max(2.0f).subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Scale")
+ b.add_input<decl::Vector>(N_("Offset")).min(-2.0f).max(2.0f).subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("Scale"))
.default_value({1.0f, 1.0f, 1.0f})
.min(-10.0f)
.max(10.0f)
.subtype(PROP_XYZ);
- b.add_output<decl::Float>("Value");
- b.add_output<decl::Color>("Color");
+ b.add_output<decl::Float>(N_("Value"));
+ b.add_output<decl::Color>(N_("Color"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_texture_cc
-void register_node_type_cmp_texture(void)
+void register_node_type_cmp_texture()
{
+ namespace file_ns = blender::nodes::node_composite_texture_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_texture_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_texture_declare;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
index 85fd240ce2e..08ec998dfa2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
@@ -21,21 +21,24 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_tonemap_cc {
static void cmp_node_tonemap_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Image");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_tonemap(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTonemap *ntm = (NodeTonemap *)MEM_callocN(sizeof(NodeTonemap), "node tonemap data");
+ NodeTonemap *ntm = MEM_cnew<NodeTonemap>(__func__);
ntm->type = 1;
ntm->key = 0.18;
ntm->offset = 1;
@@ -49,13 +52,40 @@ static void node_composit_init_tonemap(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = ntm;
}
-void register_node_type_cmp_tonemap(void)
+static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "tonemap_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ if (RNA_enum_get(ptr, "tonemap_type") == 0) {
+ uiItemR(col, ptr, "key", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ else {
+ uiItemR(col, ptr, "intensity", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "adaptation", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "correction", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ }
+}
+
+} // namespace blender::nodes::node_composite_tonemap_cc
+
+void register_node_type_cmp_tonemap()
+{
+ namespace file_ns = blender::nodes::node_composite_tonemap_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TONEMAP, "Tonemap", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_tonemap_declare;
- node_type_init(&ntype, node_composit_init_tonemap);
+ cmp_node_type_base(&ntype, CMP_NODE_TONEMAP, "Tonemap", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_tonemap_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_tonemap;
+ node_type_init(&ntype, file_ns::node_composit_init_tonemap);
node_type_storage(&ntype, "NodeTonemap", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
index cb5c9468daa..3a45319d0ad 100644
--- a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
@@ -21,34 +21,89 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_trackpos_cc {
static void cmp_node_trackpos_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("X");
- b.add_output<decl::Float>("Y");
- b.add_output<decl::Vector>("Speed").subtype(PROP_VELOCITY);
+ b.add_output<decl::Float>(N_("X"));
+ b.add_output<decl::Float>(N_("Y"));
+ b.add_output<decl::Vector>(N_("Speed")).subtype(PROP_VELOCITY);
}
-} // namespace blender::nodes
-
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTrackPosData *data = (NodeTrackPosData *)MEM_callocN(sizeof(NodeTrackPosData),
- "node track position data");
+ NodeTrackPosData *data = MEM_cnew<NodeTrackPosData>(__func__);
node->storage = data;
}
-void register_node_type_cmp_trackpos(void)
+static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
+ bNode *node = (bNode *)ptr->data;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (node->id) {
+ MovieClip *clip = (MovieClip *)node->id;
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object;
+ uiLayout *col;
+ PointerRNA tracking_ptr;
+ NodeTrackPosData *data = (NodeTrackPosData *)node->storage;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
+
+ object = BKE_tracking_object_get_named(tracking, data->tracking_object);
+ if (object) {
+ PointerRNA object_ptr;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
+
+ uiItemPointerR(col, ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA);
+ }
+ else {
+ uiItemR(layout, ptr, "track_name", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_ANIM_DATA);
+ }
+
+ uiItemR(layout, ptr, "position", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) {
+ uiItemR(layout, ptr, "frame_relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ }
+}
+
+} // namespace blender::nodes::node_composite_trackpos_cc
+
+void register_node_type_cmp_trackpos()
+{
+ namespace file_ns = blender::nodes::node_composite_trackpos_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TRACKPOS, "Track Position", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::cmp_node_trackpos_declare;
- node_type_init(&ntype, init);
+ cmp_node_type_base(&ntype, CMP_NODE_TRACKPOS, "Track Position", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_trackpos_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_trackpos;
+ node_type_init(&ntype, file_ns::init);
node_type_storage(
&ntype, "NodeTrackPosData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_transform.cc b/source/blender/nodes/composite/nodes/node_composite_transform.cc
index 1695101cdbf..6afc173df04 100644
--- a/source/blender/nodes/composite/nodes/node_composite_transform.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_transform.cc
@@ -21,30 +21,45 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Transform ******************** */
-static bNodeSocketTemplate cmp_node_transform_in[] = {
- {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("X"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
- {SOCK_FLOAT, N_("Y"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
- {SOCK_FLOAT, N_("Angle"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_ANGLE},
- {SOCK_FLOAT, N_("Scale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_transform_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_transform(void)
+namespace blender::nodes::node_composite_transform_cc {
+
+static void cmp_node_transform_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("X")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Y")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Angle"))
+ .default_value(0.0f)
+ .min(-10000.0f)
+ .max(10000.0f)
+ .subtype(PROP_ANGLE);
+ b.add_input<decl::Float>(N_("Scale")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_transform_cc
+
+void register_node_type_cmp_transform()
+{
+ namespace file_ns = blender::nodes::node_composite_transform_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TRANSFORM, "Transform", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_transform_in, cmp_node_transform_out);
+ cmp_node_type_base(&ntype, CMP_NODE_TRANSFORM, "Transform", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_transform_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_transform;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_translate.cc b/source/blender/nodes/composite/nodes/node_composite_translate.cc
index 0ee8a41a5ea..6666d161b4a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_translate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_translate.cc
@@ -21,35 +21,47 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-/* **************** Translate ******************** */
+/* **************** Translate ******************** */
-static bNodeSocketTemplate cmp_node_translate_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("X"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Y"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_translate_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes::node_composite_translate_cc {
+
+static void cmp_node_translate_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("X")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Y")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
static void node_composit_init_translate(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTranslateData *data = (NodeTranslateData *)MEM_callocN(sizeof(NodeTranslateData),
- "node translate data");
+ NodeTranslateData *data = MEM_cnew<NodeTranslateData>(__func__);
node->storage = data;
}
-void register_node_type_cmp_translate(void)
+static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "use_relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "wrap_axis", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_translate_cc
+
+void register_node_type_cmp_translate()
+{
+ namespace file_ns = blender::nodes::node_composite_translate_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_translate_in, cmp_node_translate_out);
- node_type_init(&ntype, node_composit_init_translate);
+ cmp_node_type_base(&ntype, CMP_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_translate_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_translate;
+ node_type_init(&ntype, file_ns::node_composit_init_translate);
node_type_storage(
&ntype, "NodeTranslateData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc b/source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc
index ece52dea269..797bd931577 100644
--- a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc
@@ -24,50 +24,58 @@
#include "node_composite_util.hh"
/* **************** VALTORGB ******************** */
-static bNodeSocketTemplate cmp_node_valtorgb_in[] = {
- {SOCK_FLOAT, N_("Fac"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_valtorgb_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Alpha")},
- {-1, ""},
-};
+
+namespace blender::nodes::node_composite_val_to_rgb_cc {
+
+static void cmp_node_valtorgb_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Alpha"));
+}
static void node_composit_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = BKE_colorband_add(true);
}
-void register_node_type_cmp_valtorgb(void)
+} // namespace blender::nodes::node_composite_val_to_rgb_cc
+
+void register_node_type_cmp_valtorgb()
{
+ namespace file_ns = blender::nodes::node_composite_val_to_rgb_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_valtorgb_in, cmp_node_valtorgb_out);
+ cmp_node_type_base(&ntype, CMP_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_valtorgb_declare;
node_type_size(&ntype, 240, 200, 320);
- node_type_init(&ntype, node_composit_init_valtorgb);
+ node_type_init(&ntype, file_ns::node_composit_init_valtorgb);
node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
}
/* **************** RGBTOBW ******************** */
-static bNodeSocketTemplate cmp_node_rgbtobw_in[] = {
- {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_rgbtobw_out[] = {
- {SOCK_FLOAT, N_("Val"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
-
-void register_node_type_cmp_rgbtobw(void)
+
+namespace blender::nodes::node_composite_val_to_rgb_cc {
+
+static void cmp_node_rgbtobw_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Color>(N_("Val"));
+}
+
+} // namespace blender::nodes::node_composite_val_to_rgb_cc
+
+void register_node_type_cmp_rgbtobw()
{
+ namespace file_ns = blender::nodes::node_composite_val_to_rgb_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_rgbtobw_in, cmp_node_rgbtobw_out);
+ cmp_node_type_base(&ntype, CMP_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_rgbtobw_declare;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_value.cc b/source/blender/nodes/composite/nodes/node_composite_value.cc
index 5459801bcc7..076adc1c01c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_value.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_value.cc
@@ -25,21 +25,23 @@
/* **************** VALUE ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_value_cc {
static void cmp_node_value_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("Value").default_value(0.5f);
+ b.add_output<decl::Float>(N_("Value")).default_value(0.5f);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_value_cc
-void register_node_type_cmp_value(void)
+void register_node_type_cmp_value()
{
+ namespace file_ns = blender::nodes::node_composite_value_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::cmp_node_value_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_VALUE, "Value", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_value_declare;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc b/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc
deleted file mode 100644
index ce6ba659609..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc
+++ /dev/null
@@ -1,54 +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) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "node_composite_util.hh"
-
-/* **************** VECTOR BLUR ******************** */
-static bNodeSocketTemplate cmp_node_vecblur_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Z"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Speed"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_VELOCITY},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_vecblur_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
-
-static void node_composit_init_vecblur(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeBlurData *nbd = (NodeBlurData *)MEM_callocN(sizeof(NodeBlurData), "node blur data");
- node->storage = nbd;
- nbd->samples = 32;
- nbd->fac = 1.0f;
-}
-
-/* custom1: iterations, custom2: max_speed (0 = no_limit). */
-void register_node_type_cmp_vecblur(void)
-{
- static bNodeType ntype;
-
- cmp_node_type_base(&ntype, CMP_NODE_VECBLUR, "Vector Blur", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_vecblur_in, cmp_node_vecblur_out);
- node_type_init(&ntype, node_composit_init_vecblur);
- node_type_storage(
- &ntype, "NodeBlurData", node_free_standard_storage, node_copy_standard_storage);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_vec_blur.cc b/source/blender/nodes/composite/nodes/node_composite_vec_blur.cc
new file mode 100644
index 00000000000..a461688641d
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_vec_blur.cc
@@ -0,0 +1,86 @@
+/*
+ * 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) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
+/* **************** VECTOR BLUR ******************** */
+
+namespace blender::nodes::node_composite_vec_blur_cc {
+
+static void cmp_node_vec_blur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Z")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Vector>(N_("Speed"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_VELOCITY);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+/* custom1: iterations, custom2: max_speed (0 = no_limit). */
+static void node_composit_init_vecblur(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeBlurData *nbd = MEM_cnew<NodeBlurData>(__func__);
+ node->storage = nbd;
+ nbd->samples = 32;
+ nbd->fac = 1.0f;
+}
+
+static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "factor", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Blur"), ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemL(col, IFACE_("Speed:"), ICON_NONE);
+ uiItemR(col, ptr, "speed_min", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Min"), ICON_NONE);
+ uiItemR(col, ptr, "speed_max", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Max"), ICON_NONE);
+
+ uiItemR(layout, ptr, "use_curved", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_vec_blur_cc
+
+void register_node_type_cmp_vecblur()
+{
+ namespace file_ns = blender::nodes::node_composite_vec_blur_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_VECBLUR, "Vector Blur", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_vec_blur_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_vecblur;
+ node_type_init(&ntype, file_ns::node_composit_init_vecblur);
+ node_type_storage(
+ &ntype, "NodeBlurData", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.cc b/source/blender/nodes/composite/nodes/node_composite_viewer.cc
index 7234d4d8eb2..a57f1fbb8ef 100644
--- a/source/blender/nodes/composite/nodes/node_composite_viewer.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_viewer.cc
@@ -21,46 +21,73 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include "BKE_global.h"
#include "BKE_image.h"
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
/* **************** VIEWER ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_viewer_cc {
static void cmp_node_viewer_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({0.0f, 0.0f, 0.0f, 1.0f});
- b.add_input<decl::Float>("Alpha").default_value(1.0f).min(0.0f).max(1.0f);
- b.add_input<decl::Float>("Z").default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Color>(N_("Image")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Alpha")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Z")).default_value(1.0f).min(0.0f).max(1.0f);
}
-} // namespace blender::nodes
-
static void node_composit_init_viewer(bNodeTree *UNUSED(ntree), bNode *node)
{
- ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user");
+ ImageUser *iuser = MEM_cnew<ImageUser>(__func__);
node->storage = iuser;
iuser->sfra = 1;
- iuser->ok = 1;
node->custom3 = 0.5f;
node->custom4 = 0.5f;
node->id = (ID *)BKE_image_ensure_viewer(G.main, IMA_TYPE_COMPOSITE, "Viewer Node");
}
-void register_node_type_cmp_viewer(void)
+static void node_composit_buts_viewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+static void node_composit_buts_viewer_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ uiItemR(layout, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "tile_order", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (RNA_enum_get(ptr, "tile_order") == 0) {
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "center_x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "center_y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+} // namespace blender::nodes::node_composite_viewer_cc
+
+void register_node_type_cmp_viewer()
{
+ namespace file_ns = blender::nodes::node_composite_viewer_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_viewer_declare;
- node_type_init(&ntype, node_composit_init_viewer);
+ cmp_node_type_base(&ntype, CMP_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::cmp_node_viewer_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_viewer;
+ ntype.draw_buttons_ex = file_ns::node_composit_buts_viewer_ex;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_viewer);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
- node_type_internal_links(&ntype, nullptr);
+ ntype.no_muting = true;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_zcombine.cc b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
index 79e4d449159..7a6d5b3af5f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
@@ -21,31 +21,45 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Z COMBINE ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_zcombine_cc {
static void cmp_node_zcombine_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Z").default_value(1.0f).min(0.0f).max(10000.0f);
- b.add_input<decl::Color>("Image", "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Z", "Z_001").default_value(1.0f).min(0.0f).max(10000.0f);
- b.add_output<decl::Color>("Image");
- b.add_output<decl::Float>("Z");
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Z")).default_value(1.0f).min(0.0f).max(10000.0f);
+ b.add_input<decl::Color>(N_("Image"), "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Z"), "Z_001").default_value(1.0f).min(0.0f).max(10000.0f);
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Z"));
+}
+
+static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "use_antialias_z", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_zcombine_cc
-/* lazy coder NOTE: node->custom2 is abused to send signal. */
-void register_node_type_cmp_zcombine(void)
+void register_node_type_cmp_zcombine()
{
+ namespace file_ns = blender::nodes::node_composite_zcombine_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_ZCOMBINE, "Z Combine", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_zcombine_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_ZCOMBINE, "Z Combine", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_zcombine_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_zcombine;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/CMakeLists.txt b/source/blender/nodes/function/CMakeLists.txt
new file mode 100644
index 00000000000..0c3c6a34995
--- /dev/null
+++ b/source/blender/nodes/function/CMakeLists.txt
@@ -0,0 +1,75 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2021, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ..
+ ../intern
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../editors/include
+ ../../functions
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+)
+
+
+set(SRC
+ nodes/legacy/node_fn_random_float.cc
+
+ nodes/node_fn_align_euler_to_vector.cc
+ nodes/node_fn_boolean_math.cc
+ nodes/node_fn_compare.cc
+ nodes/node_fn_float_to_int.cc
+ nodes/node_fn_input_bool.cc
+ nodes/node_fn_input_color.cc
+ nodes/node_fn_input_int.cc
+ nodes/node_fn_input_special_characters.cc
+ nodes/node_fn_input_string.cc
+ nodes/node_fn_input_vector.cc
+ nodes/node_fn_random_value.cc
+ nodes/node_fn_replace_string.cc
+ nodes/node_fn_rotate_euler.cc
+ nodes/node_fn_slice_string.cc
+ nodes/node_fn_string_length.cc
+ nodes/node_fn_value_to_string.cc
+
+ node_function_util.cc
+
+ node_function_util.hh
+)
+
+set(LIB
+ bf_functions
+)
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+blender_add_lib(bf_nodes_function "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_UNITY_BUILD)
+ set_target_properties(bf_nodes_function PROPERTIES UNITY_BUILD ON)
+ set_target_properties(bf_nodes_function PROPERTIES UNITY_BUILD_BATCH_SIZE 10)
+endif()
diff --git a/source/blender/nodes/function/node_function_util.cc b/source/blender/nodes/function/node_function_util.cc
index 8ff8b416310..0137b298f45 100644
--- a/source/blender/nodes/function/node_function_util.cc
+++ b/source/blender/nodes/function/node_function_util.cc
@@ -17,22 +17,24 @@
#include "node_function_util.hh"
#include "node_util.h"
+#include "NOD_socket_search_link.hh"
+
static bool fn_node_poll_default(bNodeType *UNUSED(ntype),
bNodeTree *ntree,
const char **r_disabled_hint)
{
/* Function nodes are only supported in simulation node trees so far. */
if (!STREQ(ntree->idname, "GeometryNodeTree")) {
- *r_disabled_hint = "Not a geometry node tree";
+ *r_disabled_hint = TIP_("Not a geometry node tree");
return false;
}
return true;
}
-void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = fn_node_poll_default;
- ntype->update_internal_links = node_update_internal_links_default;
ntype->insert_link = node_insert_link_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
diff --git a/source/blender/nodes/function/node_function_util.hh b/source/blender/nodes/function/node_function_util.hh
index 46b485298e3..69c617b4f01 100644
--- a/source/blender/nodes/function/node_function_util.hh
+++ b/source/blender/nodes/function/node_function_util.hh
@@ -18,7 +18,7 @@
#include <string.h>
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
@@ -37,5 +37,4 @@
#include "FN_multi_function_builder.hh"
-void fn_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
diff --git a/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc b/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
index 7f6f554ba93..9470b82a8eb 100644
--- a/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
+++ b/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
@@ -18,18 +18,16 @@
#include "BLI_hash.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_random_float_cc {
static void fn_node_legacy_random_float_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Min").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Max").default_value(1.0f).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Int>("Seed").min(-10000).max(10000);
- b.add_output<decl::Float>("Value");
-};
-
-} // namespace blender::nodes
+ b.add_input<decl::Float>(N_("Min")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Max")).default_value(1.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Int>(N_("Seed")).min(-10000).max(10000);
+ b.add_output<decl::Float>(N_("Value"));
+}
class RandomFloatFunction : public blender::fn::MultiFunction {
public:
@@ -75,12 +73,16 @@ static void fn_node_legacy_random_float_build_multi_function(
builder.set_matching_fn(fn);
}
+} // namespace blender::nodes::node_fn_random_float_cc
+
void register_node_type_fn_legacy_random_float()
{
+ namespace file_ns = blender::nodes::node_fn_random_float_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_LEGACY_RANDOM_FLOAT, "Random Float", 0, 0);
- ntype.declare = blender::nodes::fn_node_legacy_random_float_declare;
- ntype.build_multi_function = fn_node_legacy_random_float_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_LEGACY_RANDOM_FLOAT, "Random Float", 0);
+ ntype.declare = file_ns::fn_node_legacy_random_float_declare;
+ ntype.build_multi_function = file_ns::fn_node_legacy_random_float_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc
new file mode 100644
index 00000000000..bcc035e6ede
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc
@@ -0,0 +1,224 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_task.hh"
+
+#include "RNA_enum_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_function_util.hh"
+
+namespace blender::nodes::node_fn_align_euler_to_vector_cc {
+
+static void fn_node_align_euler_to_vector_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).hide_value();
+ b.add_input<decl::Float>(N_("Factor"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Vector")).default_value({0.0, 0.0, 1.0});
+ b.add_output<decl::Vector>(N_("Rotation")).subtype(PROP_EULER);
+}
+
+static void fn_node_align_euler_to_vector_layout(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "pivot_axis", 0, IFACE_("Pivot"), ICON_NONE);
+}
+
+static void align_rotations_auto_pivot(IndexMask mask,
+ const VArray<float3> &input_rotations,
+ const VArray<float3> &vectors,
+ const VArray<float> &factors,
+ const float3 local_main_axis,
+ const MutableSpan<float3> output_rotations)
+{
+ threading::parallel_for(mask.index_range(), 512, [&](IndexRange mask_range) {
+ for (const int maski : mask_range) {
+ const int64_t i = mask[maski];
+ const float3 vector = vectors[i];
+ if (is_zero_v3(vector)) {
+ output_rotations[i] = input_rotations[i];
+ continue;
+ }
+
+ float old_rotation[3][3];
+ eul_to_mat3(old_rotation, input_rotations[i]);
+ float3 old_axis;
+ mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
+
+ const float3 new_axis = math::normalize(vector);
+ float3 rotation_axis = math::cross_high_precision(old_axis, new_axis);
+ if (is_zero_v3(rotation_axis)) {
+ /* The vectors are linearly dependent, so we fall back to another axis. */
+ rotation_axis = math::cross_high_precision(old_axis, float3(1, 0, 0));
+ if (is_zero_v3(rotation_axis)) {
+ /* This is now guaranteed to not be zero. */
+ rotation_axis = math::cross_high_precision(old_axis, float3(0, 1, 0));
+ }
+ }
+
+ const float full_angle = angle_normalized_v3v3(old_axis, new_axis);
+ const float angle = factors[i] * full_angle;
+
+ float rotation[3][3];
+ axis_angle_to_mat3(rotation, rotation_axis, angle);
+
+ float new_rotation_matrix[3][3];
+ mul_m3_m3m3(new_rotation_matrix, rotation, old_rotation);
+
+ float3 new_rotation;
+ mat3_to_eul(new_rotation, new_rotation_matrix);
+
+ output_rotations[i] = new_rotation;
+ }
+ });
+}
+
+static void align_rotations_fixed_pivot(IndexMask mask,
+ const VArray<float3> &input_rotations,
+ const VArray<float3> &vectors,
+ const VArray<float> &factors,
+ const float3 local_main_axis,
+ const float3 local_pivot_axis,
+ const MutableSpan<float3> output_rotations)
+{
+ threading::parallel_for(mask.index_range(), 512, [&](IndexRange mask_range) {
+ for (const int64_t maski : mask_range) {
+ const int64_t i = mask[maski];
+ if (local_main_axis == local_pivot_axis) {
+ /* Can't compute any meaningful rotation angle in this case. */
+ output_rotations[i] = input_rotations[i];
+ continue;
+ }
+
+ const float3 vector = vectors[i];
+ if (is_zero_v3(vector)) {
+ output_rotations[i] = input_rotations[i];
+ continue;
+ }
+
+ float old_rotation[3][3];
+ eul_to_mat3(old_rotation, input_rotations[i]);
+ float3 old_axis;
+ mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
+ float3 pivot_axis;
+ mul_v3_m3v3(pivot_axis, old_rotation, local_pivot_axis);
+
+ float full_angle = angle_signed_on_axis_v3v3_v3(vector, old_axis, pivot_axis);
+ if (full_angle > M_PI) {
+ /* Make sure the point is rotated as little as possible. */
+ full_angle -= 2.0f * M_PI;
+ }
+ const float angle = factors[i] * full_angle;
+
+ float rotation[3][3];
+ axis_angle_to_mat3(rotation, pivot_axis, angle);
+
+ float new_rotation_matrix[3][3];
+ mul_m3_m3m3(new_rotation_matrix, rotation, old_rotation);
+
+ float3 new_rotation;
+ mat3_to_eul(new_rotation, new_rotation_matrix);
+
+ output_rotations[i] = new_rotation;
+ }
+ });
+}
+
+class MF_AlignEulerToVector : public fn::MultiFunction {
+ private:
+ int main_axis_mode_;
+ int pivot_axis_mode_;
+
+ public:
+ MF_AlignEulerToVector(int main_axis_mode, int pivot_axis_mode)
+ : main_axis_mode_(main_axis_mode), pivot_axis_mode_(pivot_axis_mode)
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Align Euler To Vector"};
+ signature.single_input<float3>("Rotation");
+ signature.single_input<float>("Factor");
+ signature.single_input<float3>("Vector");
+
+ signature.single_output<float3>("Rotation");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float3> &input_rotations = params.readonly_single_input<float3>(0, "Rotation");
+ const VArray<float> &factors = params.readonly_single_input<float>(1, "Factor");
+ const VArray<float3> &vectors = params.readonly_single_input<float3>(2, "Vector");
+
+ auto output_rotations = params.uninitialized_single_output<float3>(3, "Rotation");
+
+ float3 local_main_axis = {0.0f, 0.0f, 0.0f};
+ local_main_axis[main_axis_mode_] = 1;
+
+ if (pivot_axis_mode_ == FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_AUTO) {
+ align_rotations_auto_pivot(
+ mask, input_rotations, vectors, factors, local_main_axis, output_rotations);
+ }
+ else {
+ float3 local_pivot_axis = {0.0f, 0.0f, 0.0f};
+ local_pivot_axis[pivot_axis_mode_ - 1] = 1;
+ align_rotations_fixed_pivot(mask,
+ input_rotations,
+ vectors,
+ factors,
+ local_main_axis,
+ local_pivot_axis,
+ output_rotations);
+ }
+ }
+};
+
+static void fn_node_align_euler_to_vector_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ bNode &node = builder.node();
+ builder.construct_and_set_matching_fn<MF_AlignEulerToVector>(node.custom1, node.custom2);
+}
+
+} // namespace blender::nodes::node_fn_align_euler_to_vector_cc
+
+void register_node_type_fn_align_euler_to_vector()
+{
+ namespace file_ns = blender::nodes::node_fn_align_euler_to_vector_cc;
+
+ static bNodeType ntype;
+
+ fn_node_type_base(
+ &ntype, FN_NODE_ALIGN_EULER_TO_VECTOR, "Align Euler to Vector", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_align_euler_to_vector_declare;
+ ntype.draw_buttons = file_ns::fn_node_align_euler_to_vector_layout;
+ ntype.build_multi_function = file_ns::fn_node_align_euler_to_vector_build_multi_function;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
index d10490bb2ee..9425c4ff328 100644
--- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
+++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
@@ -22,34 +22,36 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_boolean_math_cc {
static void fn_node_boolean_math_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Bool>("Boolean", "Boolean");
- b.add_input<decl::Bool>("Boolean", "Boolean_001");
- b.add_output<decl::Bool>("Boolean");
-};
-
-} // namespace blender::nodes
+ b.add_input<decl::Bool>(N_("Boolean"), "Boolean");
+ b.add_input<decl::Bool>(N_("Boolean"), "Boolean_001");
+ b.add_output<decl::Bool>(N_("Boolean"));
+}
static void fn_node_boolean_math_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
}
-static void node_boolean_math_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_boolean_math_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sockB = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
- nodeSetSocketAvailability(sockB,
- ELEM(node->custom1, NODE_BOOLEAN_MATH_AND, NODE_BOOLEAN_MATH_OR));
+ nodeSetSocketAvailability(ntree, sockB, !ELEM(node->custom1, NODE_BOOLEAN_MATH_NOT));
}
-static void node_boolean_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void node_boolean_math_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_boolean_math_items, node->custom1, &name);
@@ -59,13 +61,46 @@ static void node_boolean_math_label(bNodeTree *UNUSED(ntree), bNode *node, char
BLI_strncpy(label, IFACE_(name), maxlen);
}
-static const blender::fn::MultiFunction *get_multi_function(bNode &bnode)
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
{
- static blender::fn::CustomMF_SI_SI_SO<bool, bool, bool> and_fn{
- "And", [](bool a, bool b) { return a && b; }};
- static blender::fn::CustomMF_SI_SI_SO<bool, bool, bool> or_fn{
- "Or", [](bool a, bool b) { return a || b; }};
- static blender::fn::CustomMF_SI_SO<bool, bool> not_fn{"Not", [](bool a) { return !a; }};
+ if (!params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_BOOLEAN)) {
+ return;
+ }
+
+ for (const EnumPropertyItem *item = rna_enum_node_boolean_math_items;
+ item->identifier != nullptr;
+ item++) {
+ if (item->name != nullptr && item->identifier[0] != '\0') {
+ NodeBooleanMathOperation operation = static_cast<NodeBooleanMathOperation>(item->value);
+ params.add_item(IFACE_(item->name), [operation](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("FunctionNodeBooleanMath");
+ node.custom1 = operation;
+ params.update_and_connect_available_socket(node, "Boolean");
+ });
+ }
+ }
+}
+
+static const fn::MultiFunction *get_multi_function(bNode &bnode)
+{
+ static fn::CustomMF_SI_SI_SO<bool, bool, bool> and_fn{"And",
+ [](bool a, bool b) { return a && b; }};
+ static fn::CustomMF_SI_SI_SO<bool, bool, bool> or_fn{"Or",
+ [](bool a, bool b) { return a || b; }};
+ static fn::CustomMF_SI_SO<bool, bool> not_fn{"Not", [](bool a) { return !a; }};
+ static fn::CustomMF_SI_SI_SO<bool, bool, bool> nand_fn{"Not And",
+ [](bool a, bool b) { return !(a && b); }};
+ static fn::CustomMF_SI_SI_SO<bool, bool, bool> nor_fn{"Nor",
+ [](bool a, bool b) { return !(a || b); }};
+ static fn::CustomMF_SI_SI_SO<bool, bool, bool> xnor_fn{"Equal",
+ [](bool a, bool b) { return a == b; }};
+ static fn::CustomMF_SI_SI_SO<bool, bool, bool> xor_fn{"Not Equal",
+ [](bool a, bool b) { return a != b; }};
+ static fn::CustomMF_SI_SI_SO<bool, bool, bool> imply_fn{"Imply",
+ [](bool a, bool b) { return !a || b; }};
+ static fn::CustomMF_SI_SI_SO<bool, bool, bool> nimply_fn{"Subtract",
+ [](bool a, bool b) { return a && !b; }};
switch (bnode.custom1) {
case NODE_BOOLEAN_MATH_AND:
@@ -74,28 +109,44 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &bnode)
return &or_fn;
case NODE_BOOLEAN_MATH_NOT:
return &not_fn;
+ case NODE_BOOLEAN_MATH_NAND:
+ return &nand_fn;
+ case NODE_BOOLEAN_MATH_NOR:
+ return &nor_fn;
+ case NODE_BOOLEAN_MATH_XNOR:
+ return &xnor_fn;
+ case NODE_BOOLEAN_MATH_XOR:
+ return &xor_fn;
+ case NODE_BOOLEAN_MATH_IMPLY:
+ return &imply_fn;
+ case NODE_BOOLEAN_MATH_NIMPLY:
+ return &nimply_fn;
}
BLI_assert_unreachable();
return nullptr;
}
-static void fn_node_boolean_math_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void fn_node_boolean_math_build_multi_function(NodeMultiFunctionBuilder &builder)
{
- const blender::fn::MultiFunction *fn = get_multi_function(builder.node());
+ const fn::MultiFunction *fn = get_multi_function(builder.node());
builder.set_matching_fn(fn);
}
+} // namespace blender::nodes::node_fn_boolean_math_cc
+
void register_node_type_fn_boolean_math()
{
+ namespace file_ns = blender::nodes::node_fn_boolean_math_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_boolean_math_declare;
- node_type_label(&ntype, node_boolean_math_label);
- node_type_update(&ntype, node_boolean_math_update);
- ntype.build_multi_function = fn_node_boolean_math_build_multi_function;
- ntype.draw_buttons = fn_node_boolean_math_layout;
+ fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_boolean_math_declare;
+ ntype.labelfunc = file_ns::node_boolean_math_label;
+ node_type_update(&ntype, file_ns::node_boolean_math_update);
+ ntype.build_multi_function = file_ns::fn_node_boolean_math_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_boolean_math_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_compare.cc b/source/blender/nodes/function/nodes/node_fn_compare.cc
new file mode 100644
index 00000000000..13a7ff86624
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_compare.cc
@@ -0,0 +1,552 @@
+/*
+ * 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 <cmath>
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_enum_types.h"
+
+#include "node_function_util.hh"
+
+#include "NOD_socket_search_link.hh"
+
+namespace blender::nodes::node_fn_compare_cc {
+
+NODE_STORAGE_FUNCS(NodeFunctionCompare)
+
+static void fn_node_compare_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Float>(N_("A")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("B")).min(-10000.0f).max(10000.0f);
+
+ b.add_input<decl::Int>(N_("A"), "A_INT");
+ b.add_input<decl::Int>(N_("B"), "B_INT");
+
+ b.add_input<decl::Vector>(N_("A"), "A_VEC3");
+ b.add_input<decl::Vector>(N_("B"), "B_VEC3");
+
+ b.add_input<decl::Color>(N_("A"), "A_COL");
+ b.add_input<decl::Color>(N_("B"), "B_COL");
+
+ b.add_input<decl::String>(N_("A"), "A_STR");
+ b.add_input<decl::String>(N_("B"), "B_STR");
+
+ b.add_input<decl::Float>(N_("C")).default_value(0.9f);
+ b.add_input<decl::Float>(N_("Angle")).default_value(0.0872665f).subtype(PROP_ANGLE);
+ b.add_input<decl::Float>(N_("Epsilon")).default_value(0.001).min(-10000.0f).max(10000.0f);
+
+ b.add_output<decl::Bool>(N_("Result"));
+}
+
+static void geo_node_compare_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ const NodeFunctionCompare &data = node_storage(*static_cast<const bNode *>(ptr->data));
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ if (data.data_type == SOCK_VECTOR) {
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+ }
+ uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
+}
+
+static void node_compare_update(bNodeTree *ntree, bNode *node)
+{
+ NodeFunctionCompare *data = (NodeFunctionCompare *)node->storage;
+
+ bNodeSocket *sock_comp = (bNodeSocket *)BLI_findlink(&node->inputs, 10);
+ bNodeSocket *sock_angle = (bNodeSocket *)BLI_findlink(&node->inputs, 11);
+ bNodeSocket *sock_epsilon = (bNodeSocket *)BLI_findlink(&node->inputs, 12);
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ nodeSetSocketAvailability(ntree, socket, socket->type == (eNodeSocketDatatype)data->data_type);
+ }
+
+ nodeSetSocketAvailability(ntree,
+ sock_epsilon,
+ ELEM(data->operation, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL) &&
+ !ELEM(data->data_type, SOCK_INT, SOCK_STRING));
+
+ nodeSetSocketAvailability(ntree,
+ sock_comp,
+ ELEM(data->mode, NODE_COMPARE_MODE_DOT_PRODUCT) &&
+ data->data_type == SOCK_VECTOR);
+
+ nodeSetSocketAvailability(ntree,
+ sock_angle,
+ ELEM(data->mode, NODE_COMPARE_MODE_DIRECTION) &&
+ data->data_type == SOCK_VECTOR);
+}
+
+static void node_compare_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeFunctionCompare *data = MEM_cnew<NodeFunctionCompare>(__func__);
+ data->operation = NODE_COMPARE_GREATER_THAN;
+ data->data_type = SOCK_FLOAT;
+ data->mode = NODE_COMPARE_MODE_ELEMENT;
+ node->storage = data;
+}
+
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ eNodeSocketDatatype data_type;
+ NodeCompareOperation operation;
+ NodeCompareMode mode = NODE_COMPARE_MODE_ELEMENT;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("FunctionNodeCompare");
+ node_storage(node).data_type = data_type;
+ node_storage(node).operation = operation;
+ node_storage(node).mode = mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
+static void node_compare_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const eNodeSocketDatatype type = static_cast<eNodeSocketDatatype>(params.other_socket().type);
+ if (!ELEM(type, SOCK_BOOLEAN, SOCK_FLOAT, SOCK_RGBA, SOCK_VECTOR, SOCK_INT, SOCK_STRING)) {
+ return;
+ }
+
+ const eNodeSocketDatatype mode_type = (type == SOCK_BOOLEAN) ? SOCK_INT : type;
+ const bool string_type = (type == SOCK_STRING);
+
+ const std::string socket_name = params.in_out() == SOCK_IN ? "A" : "Result";
+
+ for (const EnumPropertyItem *item = rna_enum_node_compare_operation_items;
+ item->identifier != nullptr;
+ item++) {
+ if (item->name != nullptr && item->identifier[0] != '\0') {
+ if (!string_type &&
+ ELEM(item->value, NODE_COMPARE_COLOR_BRIGHTER, NODE_COMPARE_COLOR_DARKER)) {
+ params.add_item(IFACE_(item->name),
+ SocketSearchOp{socket_name,
+ SOCK_RGBA,
+ static_cast<NodeCompareOperation>(item->value)});
+ }
+ else if ((!string_type) ||
+ (string_type && ELEM(item->value, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL))) {
+ params.add_item(IFACE_(item->name),
+ SocketSearchOp{socket_name,
+ mode_type,
+ static_cast<NodeCompareOperation>(item->value)});
+ }
+ }
+ }
+ /* Add Angle socket. */
+ if (!string_type && params.in_out() == SOCK_IN) {
+ params.add_item(
+ IFACE_("Angle"),
+ SocketSearchOp{
+ "Angle", SOCK_VECTOR, NODE_COMPARE_GREATER_THAN, NODE_COMPARE_MODE_DIRECTION});
+ }
+}
+
+static void node_compare_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
+{
+ const NodeFunctionCompare *data = (NodeFunctionCompare *)node->storage;
+ const char *name;
+ bool enum_label = RNA_enum_name(rna_enum_node_compare_operation_items, data->operation, &name);
+ if (!enum_label) {
+ name = "Unknown";
+ }
+ BLI_strncpy(label, IFACE_(name), maxlen);
+}
+
+static float component_average(float3 a)
+{
+ return (a.x + a.y + a.z) / 3.0f;
+}
+
+static const fn::MultiFunction *get_multi_function(bNode &node)
+{
+ const NodeFunctionCompare *data = (NodeFunctionCompare *)node.storage;
+
+ switch (data->data_type) {
+ case SOCK_FLOAT:
+ switch (data->operation) {
+ case NODE_COMPARE_LESS_THAN: {
+ static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
+ "Less Than", [](float a, float b) { return a < b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_LESS_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
+ "Less Equal", [](float a, float b) { return a <= b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_GREATER_THAN: {
+ static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
+ "Greater Than", [](float a, float b) { return a > b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_GREATER_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
+ "Greater Equal", [](float a, float b) { return a >= b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_EQUAL: {
+ static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> fn{
+ "Equal", [](float a, float b, float epsilon) { return std::abs(a - b) <= epsilon; }};
+ return &fn;
+ }
+ case NODE_COMPARE_NOT_EQUAL:
+ static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> fn{
+ "Not Equal",
+ [](float a, float b, float epsilon) { return std::abs(a - b) > epsilon; }};
+ return &fn;
+ }
+ break;
+ case SOCK_INT:
+ switch (data->operation) {
+ case NODE_COMPARE_LESS_THAN: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Less Than",
+ [](int a, int b) { return a < b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_LESS_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Less Equal",
+ [](int a, int b) { return a <= b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_GREATER_THAN: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Greater Than",
+ [](int a, int b) { return a > b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_GREATER_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Greater Equal",
+ [](int a, int b) { return a >= b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Equal",
+ [](int a, int b) { return a == b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_NOT_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Not Equal",
+ [](int a, int b) { return a != b; }};
+ return &fn;
+ }
+ }
+ break;
+ case SOCK_VECTOR:
+ switch (data->operation) {
+ case NODE_COMPARE_LESS_THAN:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Than - Average",
+ [](float3 a, float3 b) { return component_average(a) < component_average(b); }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Less Than - Dot Product",
+ [](float3 a, float3 b, float comp) { return math::dot(a, b) < comp; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Less Than - Direction",
+ [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) < angle; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Than - Element-wise",
+ [](float3 a, float3 b) { return a.x < b.x && a.y < b.y && a.z < b.z; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Than - Length",
+ [](float3 a, float3 b) { return math::length(a) < math::length(b); }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_LESS_EQUAL:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Equal - Average",
+ [](float3 a, float3 b) { return component_average(a) <= component_average(b); }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Less Equal - Dot Product",
+ [](float3 a, float3 b, float comp) { return math::dot(a, b) <= comp; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Less Equal - Direction",
+ [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) <= angle; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Equal - Element-wise",
+ [](float3 a, float3 b) { return a.x <= b.x && a.y <= b.y && a.z <= b.z; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Equal - Length",
+ [](float3 a, float3 b) { return math::length(a) <= math::length(b); }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_GREATER_THAN:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Than - Average",
+ [](float3 a, float3 b) { return component_average(a) > component_average(b); }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Greater Than - Dot Product",
+ [](float3 a, float3 b, float comp) { return math::dot(a, b) > comp; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Greater Than - Direction",
+ [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) > angle; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Than - Element-wise",
+ [](float3 a, float3 b) { return a.x > b.x && a.y > b.y && a.z > b.z; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Than - Length",
+ [](float3 a, float3 b) { return math::length(a) > math::length(b); }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_GREATER_EQUAL:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Equal - Average",
+ [](float3 a, float3 b) { return component_average(a) >= component_average(b); }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Greater Equal - Dot Product",
+ [](float3 a, float3 b, float comp) { return math::dot(a, b) >= comp; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Greater Equal - Direction",
+ [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) >= angle; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Equal - Element-wise",
+ [](float3 a, float3 b) { return a.x >= b.x && a.y >= b.y && a.z >= b.z; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Equal - Length",
+ [](float3 a, float3 b) { return math::length(a) >= math::length(b); }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_EQUAL:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Equal - Average", [](float3 a, float3 b, float epsilon) {
+ return abs(component_average(a) - component_average(b)) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
+ "Equal - Dot Product", [](float3 a, float3 b, float comp, float epsilon) {
+ return abs(math::dot(a, b) - comp) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
+ "Equal - Direction", [](float3 a, float3 b, float angle, float epsilon) {
+ return abs(angle_v3v3(a, b) - angle) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Equal - Element-wise", [](float3 a, float3 b, float epsilon) {
+ return abs(a.x - b.x) <= epsilon && abs(a.y - b.y) <= epsilon &&
+ abs(a.z - b.z) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Equal - Length", [](float3 a, float3 b, float epsilon) {
+ return abs(math::length(a) - math::length(b)) <= epsilon;
+ }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_NOT_EQUAL:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Not Equal - Average", [](float3 a, float3 b, float epsilon) {
+ return abs(component_average(a) - component_average(b)) > epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
+ "Not Equal - Dot Product", [](float3 a, float3 b, float comp, float epsilon) {
+ return abs(math::dot(a, b) - comp) >= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
+ "Not Equal - Direction", [](float3 a, float3 b, float angle, float epsilon) {
+ return abs(angle_v3v3(a, b) - angle) > epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Not Equal - Element-wise", [](float3 a, float3 b, float epsilon) {
+ return abs(a.x - b.x) > epsilon && abs(a.y - b.y) > epsilon &&
+ abs(a.z - b.z) > epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Not Equal - Length", [](float3 a, float3 b, float epsilon) {
+ return abs(math::length(a) - math::length(b)) > epsilon;
+ }};
+ return &fn;
+ }
+ }
+ break;
+ }
+ break;
+ case SOCK_RGBA:
+ switch (data->operation) {
+ case NODE_COMPARE_EQUAL: {
+ static fn::CustomMF_SI_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, float, bool> fn{
+ "Equal", [](ColorGeometry4f a, ColorGeometry4f b, float epsilon) {
+ return abs(a.r - b.r) <= epsilon && abs(a.g - b.g) <= epsilon &&
+ abs(a.b - b.b) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_NOT_EQUAL: {
+ static fn::CustomMF_SI_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, float, bool> fn{
+ "Not Equal", [](ColorGeometry4f a, ColorGeometry4f b, float epsilon) {
+ return abs(a.r - b.r) > epsilon && abs(a.g - b.g) > epsilon &&
+ abs(a.b - b.b) > epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_COLOR_BRIGHTER: {
+ static fn::CustomMF_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, bool> fn{
+ "Brighter", [](ColorGeometry4f a, ColorGeometry4f b) {
+ return rgb_to_grayscale(a) > rgb_to_grayscale(b);
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_COLOR_DARKER: {
+ static fn::CustomMF_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, bool> fn{
+ "Darker", [](ColorGeometry4f a, ColorGeometry4f b) {
+ return rgb_to_grayscale(a) < rgb_to_grayscale(b);
+ }};
+ return &fn;
+ }
+ }
+ break;
+ case SOCK_STRING:
+ switch (data->operation) {
+ case NODE_COMPARE_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<std::string, std::string, bool> fn{
+ "Equal", [](std::string a, std::string b) { return a == b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_NOT_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<std::string, std::string, bool> fn{
+ "Not Equal", [](std::string a, std::string b) { return a != b; }};
+ return &fn;
+ }
+ }
+ break;
+ }
+ return nullptr;
+}
+
+static void fn_node_compare_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ const fn::MultiFunction *fn = get_multi_function(builder.node());
+ builder.set_matching_fn(fn);
+}
+
+} // namespace blender::nodes::node_fn_compare_cc
+
+void register_node_type_fn_compare()
+{
+ namespace file_ns = blender::nodes::node_fn_compare_cc;
+
+ static bNodeType ntype;
+ fn_node_type_base(&ntype, FN_NODE_COMPARE, "Compare", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_compare_declare;
+ ntype.labelfunc = file_ns::node_compare_label;
+ node_type_update(&ntype, file_ns::node_compare_update);
+ node_type_init(&ntype, file_ns::node_compare_init);
+ node_type_storage(
+ &ntype, "NodeFunctionCompare", node_free_standard_storage, node_copy_standard_storage);
+ ntype.build_multi_function = file_ns::fn_node_compare_build_multi_function;
+ ntype.draw_buttons = file_ns::geo_node_compare_layout;
+ ntype.gather_link_search_ops = file_ns::node_compare_gather_link_searches;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
deleted file mode 100644
index 9736c52e895..00000000000
--- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc
+++ /dev/null
@@ -1,120 +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.
- */
-
-#include <cmath>
-
-#include "BLI_listbase.h"
-#include "BLI_string.h"
-
-#include "RNA_enum_types.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_function_util.hh"
-
-namespace blender::nodes {
-
-static void fn_node_float_compare_declare(NodeDeclarationBuilder &b)
-{
- b.is_function_node();
- b.add_input<decl::Float>("A").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("B").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Epsilon").default_value(0.001f).min(-10000.0f).max(10000.0f);
- b.add_output<decl::Bool>("Result");
-};
-
-} // namespace blender::nodes
-
-static void geo_node_float_compare_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
-}
-
-static void node_float_compare_update(bNodeTree *UNUSED(ntree), bNode *node)
-{
- bNodeSocket *sockEpsilon = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
-
- nodeSetSocketAvailability(
- sockEpsilon, ELEM(node->custom1, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL));
-}
-
-static void node_float_compare_label(bNodeTree *UNUSED(ntree),
- bNode *node,
- char *label,
- int maxlen)
-{
- const char *name;
- bool enum_label = RNA_enum_name(rna_enum_node_float_compare_items, node->custom1, &name);
- if (!enum_label) {
- name = "Unknown";
- }
- BLI_strncpy(label, IFACE_(name), maxlen);
-}
-
-static const blender::fn::MultiFunction *get_multi_function(bNode &node)
-{
- static blender::fn::CustomMF_SI_SI_SO<float, float, bool> less_than_fn{
- "Less Than", [](float a, float b) { return a < b; }};
- static blender::fn::CustomMF_SI_SI_SO<float, float, bool> less_equal_fn{
- "Less Equal", [](float a, float b) { return a <= b; }};
- static blender::fn::CustomMF_SI_SI_SO<float, float, bool> greater_than_fn{
- "Greater Than", [](float a, float b) { return a > b; }};
- static blender::fn::CustomMF_SI_SI_SO<float, float, bool> greater_equal_fn{
- "Greater Equal", [](float a, float b) { return a >= b; }};
- static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> equal_fn{
- "Equal", [](float a, float b, float epsilon) { return std::abs(a - b) <= epsilon; }};
- static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> not_equal_fn{
- "Not Equal", [](float a, float b, float epsilon) { return std::abs(a - b) > epsilon; }};
-
- switch (node.custom1) {
- case NODE_FLOAT_COMPARE_LESS_THAN:
- return &less_than_fn;
- case NODE_FLOAT_COMPARE_LESS_EQUAL:
- return &less_equal_fn;
- case NODE_FLOAT_COMPARE_GREATER_THAN:
- return &greater_than_fn;
- case NODE_FLOAT_COMPARE_GREATER_EQUAL:
- return &greater_equal_fn;
- case NODE_FLOAT_COMPARE_EQUAL:
- return &equal_fn;
- case NODE_FLOAT_COMPARE_NOT_EQUAL:
- return &not_equal_fn;
- }
-
- BLI_assert_unreachable();
- return nullptr;
-}
-
-static void fn_node_float_compare_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
-{
- const blender::fn::MultiFunction *fn = get_multi_function(builder.node());
- builder.set_matching_fn(fn);
-}
-
-void register_node_type_fn_float_compare()
-{
- static bNodeType ntype;
-
- fn_node_type_base(&ntype, FN_NODE_FLOAT_COMPARE, "Float Compare", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_float_compare_declare;
- node_type_label(&ntype, node_float_compare_label);
- node_type_update(&ntype, node_float_compare_update);
- ntype.build_multi_function = fn_node_float_compare_build_multi_function;
- ntype.draw_buttons = geo_node_float_compare_layout;
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
index 8bb5dafff8a..488787980dc 100644
--- a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
+++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
@@ -25,23 +25,24 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_float_to_int_cc {
static void fn_node_float_to_int_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Float");
- b.add_output<decl::Int>("Integer");
-};
-
-} // namespace blender::nodes
+ b.add_input<decl::Float>(N_("Float"));
+ b.add_output<decl::Int>(N_("Integer"));
+}
static void fn_node_float_to_int_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "rounding_mode", 0, "", ICON_NONE);
}
-static void node_float_to_int_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void node_float_to_int_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_float_to_int_items, node->custom1, &name);
@@ -51,16 +52,13 @@ static void node_float_to_int_label(bNodeTree *UNUSED(ntree), bNode *node, char
BLI_strncpy(label, IFACE_(name), maxlen);
}
-static const blender::fn::MultiFunction *get_multi_function(bNode &bnode)
+static const fn::MultiFunction *get_multi_function(bNode &bnode)
{
- static blender::fn::CustomMF_SI_SO<float, int> round_fn{"Round",
- [](float a) { return (int)round(a); }};
- static blender::fn::CustomMF_SI_SO<float, int> floor_fn{"Floor",
- [](float a) { return (int)floor(a); }};
- static blender::fn::CustomMF_SI_SO<float, int> ceil_fn{"Ceiling",
- [](float a) { return (int)ceil(a); }};
- static blender::fn::CustomMF_SI_SO<float, int> trunc_fn{"Truncate",
- [](float a) { return (int)trunc(a); }};
+ static fn::CustomMF_SI_SO<float, int> round_fn{"Round", [](float a) { return (int)round(a); }};
+ static fn::CustomMF_SI_SO<float, int> floor_fn{"Floor", [](float a) { return (int)floor(a); }};
+ static fn::CustomMF_SI_SO<float, int> ceil_fn{"Ceiling", [](float a) { return (int)ceil(a); }};
+ static fn::CustomMF_SI_SO<float, int> trunc_fn{"Truncate",
+ [](float a) { return (int)trunc(a); }};
switch (static_cast<FloatToIntRoundingMode>(bnode.custom1)) {
case FN_NODE_FLOAT_TO_INT_ROUND:
@@ -77,21 +75,24 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &bnode)
return nullptr;
}
-static void fn_node_float_to_int_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void fn_node_float_to_int_build_multi_function(NodeMultiFunctionBuilder &builder)
{
- const blender::fn::MultiFunction *fn = get_multi_function(builder.node());
+ const fn::MultiFunction *fn = get_multi_function(builder.node());
builder.set_matching_fn(fn);
}
+} // namespace blender::nodes::node_fn_float_to_int_cc
+
void register_node_type_fn_float_to_int()
{
+ namespace file_ns = blender::nodes::node_fn_float_to_int_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_float_to_int_declare;
- node_type_label(&ntype, node_float_to_int_label);
- ntype.build_multi_function = fn_node_float_to_int_build_multi_function;
- ntype.draw_buttons = fn_node_float_to_int_layout;
+ fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_float_to_int_declare;
+ ntype.labelfunc = file_ns::node_float_to_int_label;
+ ntype.build_multi_function = file_ns::fn_node_float_to_int_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_float_to_int_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_bool.cc b/source/blender/nodes/function/nodes/node_fn_input_bool.cc
new file mode 100644
index 00000000000..583570effd9
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_input_bool.cc
@@ -0,0 +1,66 @@
+/*
+ * 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 "node_function_util.hh"
+
+#include "BLI_hash.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_fn_input_bool_cc {
+
+static void fn_node_input_bool_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Bool>(N_("Boolean"));
+}
+
+static void fn_node_input_bool_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "boolean", UI_ITEM_R_EXPAND, IFACE_("Value"), ICON_NONE);
+}
+
+static void fn_node_input_bool_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ bNode &bnode = builder.node();
+ NodeInputBool *node_storage = static_cast<NodeInputBool *>(bnode.storage);
+ builder.construct_and_set_matching_fn<fn::CustomMF_Constant<bool>>(node_storage->boolean);
+}
+
+static void fn_node_input_bool_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeInputBool *data = MEM_cnew<NodeInputBool>(__func__);
+ node->storage = data;
+}
+
+} // namespace blender::nodes::node_fn_input_bool_cc
+
+void register_node_type_fn_input_bool()
+{
+ namespace file_ns = blender::nodes::node_fn_input_bool_cc;
+
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_INPUT_BOOL, "Boolean", 0);
+ ntype.declare = file_ns::fn_node_input_bool_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_bool_init);
+ node_type_storage(
+ &ntype, "NodeInputBool", node_free_standard_storage, node_copy_standard_storage);
+ ntype.build_multi_function = file_ns::fn_node_input_bool_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_bool_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_color.cc b/source/blender/nodes/function/nodes/node_fn_input_color.cc
new file mode 100644
index 00000000000..1fad5b2f5f4
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_input_color.cc
@@ -0,0 +1,67 @@
+/*
+ * 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 "node_function_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_fn_input_color_cc {
+
+static void fn_node_input_color_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+static void fn_node_input_color_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiTemplateColorPicker(layout, ptr, "color", true, false, false, true);
+ uiItemR(layout, ptr, "color", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+static void fn_node_input_color_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
+{
+ bNode &bnode = builder.node();
+ NodeInputColor *node_storage = static_cast<NodeInputColor *>(bnode.storage);
+ blender::ColorGeometry4f color = (ColorGeometry4f)node_storage->color;
+ builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<ColorGeometry4f>>(color);
+}
+
+static void fn_node_input_color_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeInputColor *data = MEM_cnew<NodeInputColor>(__func__);
+ copy_v4_fl4(data->color, 0.5f, 0.5f, 0.5f, 1.0f);
+ node->storage = data;
+}
+
+} // namespace blender::nodes::node_fn_input_color_cc
+
+void register_node_type_fn_input_color()
+{
+ namespace file_ns = blender::nodes::node_fn_input_color_cc;
+
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_INPUT_COLOR, "Color", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::fn_node_input_color_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_color_init);
+ node_type_storage(
+ &ntype, "NodeInputColor", node_free_standard_storage, node_copy_standard_storage);
+ ntype.build_multi_function = file_ns::fn_node_input_color_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_color_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_int.cc b/source/blender/nodes/function/nodes/node_fn_input_int.cc
new file mode 100644
index 00000000000..dc30ecb253c
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_input_int.cc
@@ -0,0 +1,66 @@
+/*
+ * 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 "node_function_util.hh"
+
+#include "BLI_hash.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_fn_input_int_cc {
+
+static void fn_node_input_int_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Integer"));
+}
+
+static void fn_node_input_int_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "integer", UI_ITEM_R_EXPAND, "", ICON_NONE);
+}
+
+static void fn_node_input_int_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ bNode &bnode = builder.node();
+ NodeInputInt *node_storage = static_cast<NodeInputInt *>(bnode.storage);
+ builder.construct_and_set_matching_fn<fn::CustomMF_Constant<int>>(node_storage->integer);
+}
+
+static void fn_node_input_int_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeInputInt *data = MEM_cnew<NodeInputInt>(__func__);
+ node->storage = data;
+}
+
+} // namespace blender::nodes::node_fn_input_int_cc
+
+void register_node_type_fn_input_int()
+{
+ namespace file_ns = blender::nodes::node_fn_input_int_cc;
+
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_INPUT_INT, "Integer", 0);
+ ntype.declare = file_ns::fn_node_input_int_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_int_init);
+ node_type_storage(
+ &ntype, "NodeInputInt", node_free_standard_storage, node_copy_standard_storage);
+ ntype.build_multi_function = file_ns::fn_node_input_int_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_int_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc b/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
index 11c64d3f694..681bc16a301 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
@@ -16,13 +16,13 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_special_characters_cc {
static void fn_node_input_special_characters_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::String>("Line Break");
- b.add_output<decl::String>("Tab");
-};
+ b.add_output<decl::String>(N_("Line Break"));
+ b.add_output<decl::String>(N_("Tab"));
+}
class MF_SpecialCharacters : public fn::MultiFunction {
public:
@@ -59,16 +59,17 @@ static void fn_node_input_special_characters_build_multi_function(
builder.set_matching_fn(special_characters_fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_input_special_characters_cc
void register_node_type_fn_input_special_characters()
{
+ namespace file_ns = blender::nodes::node_fn_input_special_characters_cc;
+
static bNodeType ntype;
fn_node_type_base(
- &ntype, FN_NODE_INPUT_SPECIAL_CHARACTERS, "Special Characters", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::fn_node_input_special_characters_declare;
- ntype.build_multi_function =
- blender::nodes::fn_node_input_special_characters_build_multi_function;
+ &ntype, FN_NODE_INPUT_SPECIAL_CHARACTERS, "Special Characters", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::fn_node_input_special_characters_declare;
+ ntype.build_multi_function = file_ns::fn_node_input_special_characters_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_string.cc b/source/blender/nodes/function/nodes/node_fn_input_string.cc
index 704ae9d900c..4abb352d802 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_string.cc
@@ -19,29 +19,25 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_string_cc {
static void fn_node_input_string_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_output<decl::String>("String");
-};
-
-} // namespace blender::nodes
+ b.add_output<decl::String>(N_("String"));
+}
static void fn_node_input_string_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "string", 0, "", ICON_NONE);
}
-static void fn_node_input_string_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void fn_node_input_string_build_multi_function(NodeMultiFunctionBuilder &builder)
{
bNode &bnode = builder.node();
NodeInputString *node_storage = static_cast<NodeInputString *>(bnode.storage);
std::string string = std::string((node_storage->string) ? node_storage->string : "");
- builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<std::string>>(
- std::move(string));
+ builder.construct_and_set_matching_fn<fn::CustomMF_Constant<std::string>>(std::move(string));
}
static void fn_node_input_string_init(bNodeTree *UNUSED(ntree), bNode *node)
@@ -75,15 +71,20 @@ static void fn_node_string_copy(bNodeTree *UNUSED(dest_ntree),
dest_node->storage = destination_storage;
}
+} // namespace blender::nodes::node_fn_input_string_cc
+
void register_node_type_fn_input_string()
{
+ namespace file_ns = blender::nodes::node_fn_input_string_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_INPUT_STRING, "String", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::fn_node_input_string_declare;
- node_type_init(&ntype, fn_node_input_string_init);
- node_type_storage(&ntype, "NodeInputString", fn_node_input_string_free, fn_node_string_copy);
- ntype.build_multi_function = fn_node_input_string_build_multi_function;
- ntype.draw_buttons = fn_node_input_string_layout;
+ fn_node_type_base(&ntype, FN_NODE_INPUT_STRING, "String", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::fn_node_input_string_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_string_init);
+ node_type_storage(
+ &ntype, "NodeInputString", file_ns::fn_node_input_string_free, file_ns::fn_node_string_copy);
+ ntype.build_multi_function = file_ns::fn_node_input_string_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_string_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_vector.cc b/source/blender/nodes/function/nodes/node_fn_input_vector.cc
index 9548df7b423..ba9600b461c 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_vector.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_vector.cc
@@ -21,14 +21,12 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_vector_cc {
static void fn_node_input_vector_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Vector>("Vector");
-};
-
-} // namespace blender::nodes
+ b.add_output<decl::Vector>(N_("Vector"));
+}
static void fn_node_input_vector_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
@@ -36,31 +34,34 @@ static void fn_node_input_vector_layout(uiLayout *layout, bContext *UNUSED(C), P
uiItemR(col, ptr, "vector", UI_ITEM_R_EXPAND, "", ICON_NONE);
}
-static void fn_node_vector_input_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void fn_node_input_vector_build_multi_function(NodeMultiFunctionBuilder &builder)
{
bNode &bnode = builder.node();
NodeInputVector *node_storage = static_cast<NodeInputVector *>(bnode.storage);
- blender::float3 vector(node_storage->vector);
- builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<blender::float3>>(vector);
+ float3 vector(node_storage->vector);
+ builder.construct_and_set_matching_fn<fn::CustomMF_Constant<float3>>(vector);
}
+
static void fn_node_input_vector_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeInputVector *data = (NodeInputVector *)MEM_callocN(sizeof(NodeInputVector),
- "input vector node");
+ NodeInputVector *data = MEM_cnew<NodeInputVector>(__func__);
node->storage = data;
}
+} // namespace blender::nodes::node_fn_input_vector_cc
+
void register_node_type_fn_input_vector()
{
+ namespace file_ns = blender::nodes::node_fn_input_vector_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_INPUT_VECTOR, "Vector", 0, 0);
- ntype.declare = blender::nodes::fn_node_input_vector_declare;
- node_type_init(&ntype, fn_node_input_vector_init);
+ fn_node_type_base(&ntype, FN_NODE_INPUT_VECTOR, "Vector", 0);
+ ntype.declare = file_ns::fn_node_input_vector_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_vector_init);
node_type_storage(
&ntype, "NodeInputVector", node_free_standard_storage, node_copy_standard_storage);
- ntype.build_multi_function = fn_node_vector_input_build_multi_function;
- ntype.draw_buttons = fn_node_input_vector_layout;
+ ntype.build_multi_function = file_ns::fn_node_input_vector_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_vector_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_random_value.cc b/source/blender/nodes/function/nodes/node_fn_random_value.cc
index 53ca77aab0c..ceea6246cb0 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_value.cc
+++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc
@@ -19,36 +19,41 @@
#include "node_function_util.hh"
+#include "NOD_socket_search_link.hh"
+
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_random_value_cc {
+
+NODE_STORAGE_FUNCS(NodeRandomValue)
static void fn_node_random_value_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Vector>("Min").supports_field();
- b.add_input<decl::Vector>("Max").default_value({1.0f, 1.0f, 1.0f}).supports_field();
- b.add_input<decl::Float>("Min", "Min_001").supports_field();
- b.add_input<decl::Float>("Max", "Max_001").default_value(1.0f).supports_field();
- b.add_input<decl::Int>("Min", "Min_002").min(-100000).max(100000).supports_field();
- b.add_input<decl::Int>("Max", "Max_002")
+ b.add_input<decl::Vector>(N_("Min")).supports_field();
+ b.add_input<decl::Vector>(N_("Max")).default_value({1.0f, 1.0f, 1.0f}).supports_field();
+ b.add_input<decl::Float>(N_("Min"), "Min_001").supports_field();
+ b.add_input<decl::Float>(N_("Max"), "Max_001").default_value(1.0f).supports_field();
+ b.add_input<decl::Int>(N_("Min"), "Min_002").min(-100000).max(100000).supports_field();
+ b.add_input<decl::Int>(N_("Max"), "Max_002")
.default_value(100)
.min(-100000)
.max(100000)
.supports_field();
- b.add_input<decl::Float>("Probability")
+ b.add_input<decl::Float>(N_("Probability"))
.min(0.0f)
.max(1.0f)
.default_value(0.5f)
.subtype(PROP_FACTOR)
- .supports_field();
- b.add_input<decl::Int>("ID").implicit_field();
- b.add_input<decl::Int>("Seed").default_value(0).min(-10000).max(10000).supports_field();
-
- b.add_output<decl::Vector>("Value").dependent_field();
- b.add_output<decl::Float>("Value", "Value_001").dependent_field();
- b.add_output<decl::Int>("Value", "Value_002").dependent_field();
- b.add_output<decl::Bool>("Value", "Value_003").dependent_field();
+ .supports_field()
+ .make_available([](bNode &node) { node_storage(node).data_type = CD_PROP_BOOL; });
+ b.add_input<decl::Int>(N_("ID")).implicit_field();
+ b.add_input<decl::Int>(N_("Seed")).default_value(0).min(-10000).max(10000).supports_field();
+
+ b.add_output<decl::Vector>(N_("Value")).dependent_field();
+ b.add_output<decl::Float>(N_("Value"), "Value_001").dependent_field();
+ b.add_output<decl::Int>(N_("Value"), "Value_002").dependent_field();
+ b.add_output<decl::Bool>(N_("Value"), "Value_003").dependent_field();
}
static void fn_node_random_value_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -58,14 +63,14 @@ static void fn_node_random_value_layout(uiLayout *layout, bContext *UNUSED(C), P
static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeRandomValue *data = (NodeRandomValue *)MEM_callocN(sizeof(NodeRandomValue), __func__);
+ NodeRandomValue *data = MEM_cnew<NodeRandomValue>(__func__);
data->data_type = CD_PROP_FLOAT;
node->storage = data;
}
-static void fn_node_random_value_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void fn_node_random_value_update(bNodeTree *ntree, bNode *node)
{
- const NodeRandomValue &storage = *(const NodeRandomValue *)node->storage;
+ const NodeRandomValue &storage = node_storage(*node);
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
bNodeSocket *sock_min_vector = (bNodeSocket *)node->inputs.first;
@@ -81,18 +86,66 @@ static void fn_node_random_value_update(bNodeTree *UNUSED(ntree), bNode *node)
bNodeSocket *sock_out_int = sock_out_float->next;
bNodeSocket *sock_out_bool = sock_out_int->next;
- nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32);
- nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32);
- nodeSetSocketAvailability(sock_probability, data_type == CD_PROP_BOOL);
-
- nodeSetSocketAvailability(sock_out_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(sock_out_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(sock_out_int, data_type == CD_PROP_INT32);
- nodeSetSocketAvailability(sock_out_bool, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(ntree, sock_min_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_max_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_min_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_max_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_min_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(ntree, sock_max_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(ntree, sock_probability, data_type == CD_PROP_BOOL);
+
+ nodeSetSocketAvailability(ntree, sock_out_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_out_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_out_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(ntree, sock_out_bool, data_type == CD_PROP_BOOL);
+}
+
+static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+{
+ switch (socket.type) {
+ case SOCK_FLOAT:
+ return CD_PROP_FLOAT;
+ case SOCK_BOOLEAN:
+ return CD_PROP_BOOL;
+ case SOCK_INT:
+ return CD_PROP_INT32;
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ return CD_PROP_FLOAT3;
+ default:
+ return {};
+ }
+}
+
+static void fn_node_random_value_gather_link_search(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ if (!type) {
+ return;
+ }
+ if (params.in_out() == SOCK_IN) {
+ if (ELEM(*type, CD_PROP_INT32, CD_PROP_FLOAT3, CD_PROP_FLOAT)) {
+ params.add_item(IFACE_("Min"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("FunctionNodeRandomValue");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Min");
+ });
+ params.add_item(IFACE_("Max"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("FunctionNodeRandomValue");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Max");
+ });
+ }
+ search_link_ops_for_declarations(params, declaration.inputs().take_back(3));
+ }
+ else {
+ params.add_item(IFACE_("Value"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("FunctionNodeRandomValue");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Value");
+ });
+ }
}
class RandomVectorFunction : public fn::MultiFunction {
@@ -203,14 +256,16 @@ class RandomIntFunction : public fn::MultiFunction {
const VArray<int> &seeds = params.readonly_single_input<int>(3, "Seed");
MutableSpan<int> values = params.uninitialized_single_output<int>(4, "Value");
+ /* Add one to the maximum and use floor to produce an even
+ * distribution for the first and last values (See T93591). */
for (int64_t i : mask) {
const float min_value = min_values[i];
- const float max_value = max_values[i];
+ const float max_value = max_values[i] + 1.0f;
const int seed = seeds[i];
const int id = ids[i];
const float value = noise::hash_to_float(id, seed);
- values[i] = round_fl_to_int(value * (max_value - min_value) + min_value);
+ values[i] = floor(value * (max_value - min_value) + min_value);
}
}
};
@@ -251,7 +306,7 @@ class RandomBoolFunction : public fn::MultiFunction {
static void fn_node_random_value_build_multi_function(NodeMultiFunctionBuilder &builder)
{
- const NodeRandomValue &storage = *(const NodeRandomValue *)builder.node().storage;
+ const NodeRandomValue &storage = node_storage(builder.node());
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
switch (data_type) {
@@ -282,17 +337,21 @@ static void fn_node_random_value_build_multi_function(NodeMultiFunctionBuilder &
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_random_value_cc
void register_node_type_fn_random_value()
{
+ namespace file_ns = blender::nodes::node_fn_random_value_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_RANDOM_VALUE, "Random Value", NODE_CLASS_CONVERTER, 0);
- node_type_init(&ntype, blender::nodes::fn_node_random_value_init);
- node_type_update(&ntype, blender::nodes::fn_node_random_value_update);
- ntype.draw_buttons = blender::nodes::fn_node_random_value_layout;
- ntype.declare = blender::nodes::fn_node_random_value_declare;
- ntype.build_multi_function = blender::nodes::fn_node_random_value_build_multi_function;
+
+ fn_node_type_base(&ntype, FN_NODE_RANDOM_VALUE, "Random Value", NODE_CLASS_CONVERTER);
+ node_type_init(&ntype, file_ns::fn_node_random_value_init);
+ node_type_update(&ntype, file_ns::fn_node_random_value_update);
+ ntype.draw_buttons = file_ns::fn_node_random_value_layout;
+ ntype.declare = file_ns::fn_node_random_value_declare;
+ ntype.build_multi_function = file_ns::fn_node_random_value_build_multi_function;
+ ntype.gather_link_search_ops = file_ns::fn_node_random_value_gather_link_search;
node_type_storage(
&ntype, "NodeRandomValue", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/function/nodes/node_fn_replace_string.cc b/source/blender/nodes/function/nodes/node_fn_replace_string.cc
new file mode 100644
index 00000000000..afe516a5214
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_replace_string.cc
@@ -0,0 +1,68 @@
+/*
+ * 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 "BLI_string_utf8.h"
+
+#include "node_function_util.hh"
+
+namespace blender::nodes::node_fn_replace_string_cc {
+
+static void fn_node_replace_string_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::String>(N_("String"));
+ b.add_input<decl::String>(N_("Find")).description(N_("The string to find in the input string"));
+ b.add_input<decl::String>(N_("Replace"))
+ .description(N_("The string to replace each match with"));
+ b.add_output<decl::String>(N_("String"));
+}
+
+static std::string replace_all(std::string str, const std::string &from, const std::string &to)
+{
+ if (from.length() <= 0) {
+ return str;
+ }
+ const size_t step = to.length() > 0 ? to.length() : 1;
+
+ size_t offset = 0;
+ while ((offset = str.find(from, offset)) != std::string::npos) {
+ str.replace(offset, from.length(), to);
+ offset += step;
+ }
+ return str;
+}
+
+static void fn_node_replace_string_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ static fn::CustomMF_SI_SI_SI_SO<std::string, std::string, std::string, std::string> substring_fn{
+ "Replace", [](const std::string &str, const std::string &find, const std::string &replace) {
+ return replace_all(str, find, replace);
+ }};
+ builder.set_matching_fn(&substring_fn);
+}
+
+} // namespace blender::nodes::node_fn_replace_string_cc
+
+void register_node_type_fn_replace_string()
+{
+ namespace file_ns = blender::nodes::node_fn_replace_string_cc;
+
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_REPLACE_STRING, "Replace String", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_replace_string_declare;
+ ntype.build_multi_function = file_ns::fn_node_replace_string_build_multi_function;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
new file mode 100644
index 00000000000..3140aeac975
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
@@ -0,0 +1,142 @@
+/*
+ * 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 "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "RNA_enum_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_function_util.hh"
+
+namespace blender::nodes::node_fn_rotate_euler_cc {
+
+static void fn_node_rotate_euler_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).hide_value();
+ b.add_input<decl::Vector>(N_("Rotate By")).subtype(PROP_EULER);
+ b.add_input<decl::Vector>(N_("Axis")).default_value({0.0, 0.0, 1.0}).subtype(PROP_XYZ);
+ b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE);
+ b.add_output<decl::Vector>(N_("Rotation"));
+}
+
+static void fn_node_rotate_euler_update(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *rotate_by_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 1));
+ bNodeSocket *axis_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 2));
+ bNodeSocket *angle_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 3));
+
+ nodeSetSocketAvailability(
+ ntree, rotate_by_socket, ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_EULER));
+ nodeSetSocketAvailability(
+ ntree, axis_socket, ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE));
+ nodeSetSocketAvailability(
+ ntree, angle_socket, ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE));
+}
+
+static void fn_node_rotate_euler_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "type", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+}
+
+static const fn::MultiFunction *get_multi_function(bNode &bnode)
+{
+ static fn::CustomMF_SI_SI_SO<float3, float3, float3> obj_euler_rot{
+ "Rotate Euler by Euler/Object", [](const float3 &input, const float3 &rotation) {
+ float input_mat[3][3];
+ eul_to_mat3(input_mat, input);
+ float rot_mat[3][3];
+ eul_to_mat3(rot_mat, rotation);
+ float mat_res[3][3];
+ mul_m3_m3m3(mat_res, rot_mat, input_mat);
+ float3 result;
+ mat3_to_eul(result, mat_res);
+ return result;
+ }};
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> obj_AA_rot{
+ "Rotate Euler by AxisAngle/Object",
+ [](const float3 &input, const float3 &axis, float angle) {
+ float input_mat[3][3];
+ eul_to_mat3(input_mat, input);
+ float rot_mat[3][3];
+ axis_angle_to_mat3(rot_mat, axis, angle);
+ float mat_res[3][3];
+ mul_m3_m3m3(mat_res, rot_mat, input_mat);
+ float3 result;
+ mat3_to_eul(result, mat_res);
+ return result;
+ }};
+ static fn::CustomMF_SI_SI_SO<float3, float3, float3> local_euler_rot{
+ "Rotate Euler by Euler/Local", [](const float3 &input, const float3 &rotation) {
+ float input_mat[3][3];
+ eul_to_mat3(input_mat, input);
+ float rot_mat[3][3];
+ eul_to_mat3(rot_mat, rotation);
+ float mat_res[3][3];
+ mul_m3_m3m3(mat_res, input_mat, rot_mat);
+ float3 result;
+ mat3_to_eul(result, mat_res);
+ return result;
+ }};
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> local_AA_rot{
+ "Rotate Euler by AxisAngle/Local", [](const float3 &input, const float3 &axis, float angle) {
+ float input_mat[3][3];
+ eul_to_mat3(input_mat, input);
+ float rot_mat[3][3];
+ axis_angle_to_mat3(rot_mat, axis, angle);
+ float mat_res[3][3];
+ mul_m3_m3m3(mat_res, input_mat, rot_mat);
+ float3 result;
+ mat3_to_eul(result, mat_res);
+ return result;
+ }};
+ short type = bnode.custom1;
+ short space = bnode.custom2;
+ if (type == FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE) {
+ return space == FN_NODE_ROTATE_EULER_SPACE_OBJECT ? &obj_AA_rot : &local_AA_rot;
+ }
+ if (type == FN_NODE_ROTATE_EULER_TYPE_EULER) {
+ return space == FN_NODE_ROTATE_EULER_SPACE_OBJECT ? &obj_euler_rot : &local_euler_rot;
+ }
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+static void fn_node_rotate_euler_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ const fn::MultiFunction *fn = get_multi_function(builder.node());
+ builder.set_matching_fn(fn);
+}
+
+} // namespace blender::nodes::node_fn_rotate_euler_cc
+
+void register_node_type_fn_rotate_euler()
+{
+ namespace file_ns = blender::nodes::node_fn_rotate_euler_cc;
+
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_ROTATE_EULER, "Rotate Euler", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_rotate_euler_declare;
+ ntype.draw_buttons = file_ns::fn_node_rotate_euler_layout;
+ node_type_update(&ntype, file_ns::fn_node_rotate_euler_update);
+ ntype.build_multi_function = file_ns::fn_node_rotate_euler_build_multi_function;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_string_substring.cc b/source/blender/nodes/function/nodes/node_fn_slice_string.cc
index b91171923d6..4055495ec1f 100644
--- a/source/blender/nodes/function/nodes/node_fn_string_substring.cc
+++ b/source/blender/nodes/function/nodes/node_fn_slice_string.cc
@@ -18,38 +18,38 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_slice_string_cc {
-static void fn_node_string_substring_declare(NodeDeclarationBuilder &b)
+static void fn_node_slice_string_declare(NodeDeclarationBuilder &b)
{
- b.is_function_node();
- b.add_input<decl::String>("String");
- b.add_input<decl::Int>("Position");
- b.add_input<decl::Int>("Length").min(0);
- b.add_output<decl::String>("String");
-};
-
-} // namespace blender::nodes
+ b.add_input<decl::String>(N_("String"));
+ b.add_input<decl::Int>(N_("Position"));
+ b.add_input<decl::Int>(N_("Length")).min(0).default_value(10);
+ b.add_output<decl::String>(N_("String"));
+}
-static void fn_node_string_substring_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void fn_node_slice_string_build_multi_function(NodeMultiFunctionBuilder &builder)
{
- static blender::fn::CustomMF_SI_SI_SI_SO<std::string, int, int, std::string> substring_fn{
- "Substring", [](const std::string &str, int a, int b) {
+ static blender::fn::CustomMF_SI_SI_SI_SO<std::string, int, int, std::string> slice_fn{
+ "Slice", [](const std::string &str, int a, int b) {
const int len = BLI_strlen_utf8(str.c_str());
const int start = BLI_str_utf8_offset_from_index(str.c_str(), std::clamp(a, 0, len));
const int end = BLI_str_utf8_offset_from_index(str.c_str(), std::clamp(a + b, 0, len));
return str.substr(start, std::max<int>(end - start, 0));
}};
- builder.set_matching_fn(&substring_fn);
+ builder.set_matching_fn(&slice_fn);
}
-void register_node_type_fn_string_substring()
+} // namespace blender::nodes::node_fn_slice_string_cc
+
+void register_node_type_fn_slice_string()
{
+ namespace file_ns = blender::nodes::node_fn_slice_string_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_STRING_SUBSTRING, "String Substring", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_string_substring_declare;
- ntype.build_multi_function = fn_node_string_substring_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_SLICE_STRING, "Slice String", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_slice_string_declare;
+ ntype.build_multi_function = file_ns::fn_node_slice_string_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_string_length.cc b/source/blender/nodes/function/nodes/node_fn_string_length.cc
index 89038629c3c..bed434c8f2c 100644
--- a/source/blender/nodes/function/nodes/node_fn_string_length.cc
+++ b/source/blender/nodes/function/nodes/node_fn_string_length.cc
@@ -20,31 +20,31 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_string_length_cc {
static void fn_node_string_length_declare(NodeDeclarationBuilder &b)
{
- b.is_function_node();
- b.add_input<decl::String>("String");
- b.add_output<decl::Int>("Length");
-};
-
-} // namespace blender::nodes
+ b.add_input<decl::String>(N_("String"));
+ b.add_output<decl::Int>(N_("Length"));
+}
-static void fn_node_string_length_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void fn_node_string_length_build_multi_function(NodeMultiFunctionBuilder &builder)
{
- static blender::fn::CustomMF_SI_SO<std::string, int> str_len_fn{
+ static fn::CustomMF_SI_SO<std::string, int> str_len_fn{
"String Length", [](const std::string &a) { return BLI_strlen_utf8(a.c_str()); }};
builder.set_matching_fn(&str_len_fn);
}
+} // namespace blender::nodes::node_fn_string_length_cc
+
void register_node_type_fn_string_length()
{
+ namespace file_ns = blender::nodes::node_fn_string_length_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_STRING_LENGTH, "String Length", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_string_length_declare;
- ntype.build_multi_function = fn_node_string_length_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_STRING_LENGTH, "String Length", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_string_length_declare;
+ ntype.build_multi_function = file_ns::fn_node_string_length_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_value_to_string.cc b/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
index 56206af2eb2..ee0613de9bd 100644
--- a/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
@@ -17,22 +17,18 @@
#include "node_function_util.hh"
#include <iomanip>
-namespace blender::nodes {
+namespace blender::nodes::node_fn_value_to_string_cc {
static void fn_node_value_to_string_declare(NodeDeclarationBuilder &b)
{
- b.is_function_node();
- b.add_input<decl::Float>("Value");
- b.add_input<decl::Int>("Decimals").min(0);
- b.add_output<decl::String>("String");
-};
-
-} // namespace blender::nodes
+ b.add_input<decl::Float>(N_("Value"));
+ b.add_input<decl::Int>(N_("Decimals")).min(0);
+ b.add_output<decl::String>(N_("String"));
+}
-static void fn_node_value_to_string_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void fn_node_value_to_string_build_multi_function(NodeMultiFunctionBuilder &builder)
{
- static blender::fn::CustomMF_SI_SI_SO<float, int, std::string> to_str_fn{
+ static fn::CustomMF_SI_SI_SO<float, int, std::string> to_str_fn{
"Value To String", [](float a, int b) {
std::stringstream stream;
stream << std::fixed << std::setprecision(std::max(0, b)) << a;
@@ -41,12 +37,16 @@ static void fn_node_value_to_string_build_multi_function(
builder.set_matching_fn(&to_str_fn);
}
+} // namespace blender::nodes::node_fn_value_to_string_cc
+
void register_node_type_fn_value_to_string()
{
+ namespace file_ns = blender::nodes::node_fn_value_to_string_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_VALUE_TO_STRING, "Value to String", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_value_to_string_declare;
- ntype.build_multi_function = fn_node_value_to_string_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_VALUE_TO_STRING, "Value to String", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_value_to_string_declare;
+ ntype.build_multi_function = file_ns::fn_node_value_to_string_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
new file mode 100644
index 00000000000..b4add633b0c
--- /dev/null
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -0,0 +1,290 @@
+# ***** 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
+ .
+ ..
+ ../intern
+ ../../editors/include
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../bmesh
+ ../../depsgraph
+ ../../functions
+ ../../geometry
+ ../../gpu
+ ../../imbuf
+ ../../makesdna
+ ../../makesrna
+ ../../render
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+)
+
+
+set(SRC
+ nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
+ nodes/legacy/node_geo_legacy_attribute_clamp.cc
+ nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
+ nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
+ nodes/legacy/node_geo_legacy_attribute_compare.cc
+ nodes/legacy/node_geo_legacy_attribute_convert.cc
+ nodes/legacy/node_geo_legacy_attribute_curve_map.cc
+ nodes/legacy/node_geo_legacy_attribute_fill.cc
+ nodes/legacy/node_geo_legacy_attribute_map_range.cc
+ nodes/legacy/node_geo_legacy_attribute_math.cc
+ nodes/legacy/node_geo_legacy_attribute_mix.cc
+ nodes/legacy/node_geo_legacy_attribute_proximity.cc
+ nodes/legacy/node_geo_legacy_attribute_randomize.cc
+ nodes/legacy/node_geo_legacy_attribute_sample_texture.cc
+ nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
+ nodes/legacy/node_geo_legacy_attribute_transfer.cc
+ nodes/legacy/node_geo_legacy_attribute_vector_math.cc
+ nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
+ nodes/legacy/node_geo_legacy_curve_endpoints.cc
+ nodes/legacy/node_geo_legacy_curve_reverse.cc
+ nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
+ nodes/legacy/node_geo_legacy_curve_set_handles.cc
+ nodes/legacy/node_geo_legacy_curve_spline_type.cc
+ nodes/legacy/node_geo_legacy_curve_subdivide.cc
+ nodes/legacy/node_geo_legacy_curve_to_points.cc
+ nodes/legacy/node_geo_legacy_delete_geometry.cc
+ nodes/legacy/node_geo_legacy_edge_split.cc
+ nodes/legacy/node_geo_legacy_material_assign.cc
+ nodes/legacy/node_geo_legacy_mesh_to_curve.cc
+ nodes/legacy/node_geo_legacy_point_distribute.cc
+ nodes/legacy/node_geo_legacy_point_instance.cc
+ nodes/legacy/node_geo_legacy_point_rotate.cc
+ nodes/legacy/node_geo_legacy_point_scale.cc
+ nodes/legacy/node_geo_legacy_point_separate.cc
+ nodes/legacy/node_geo_legacy_point_translate.cc
+ nodes/legacy/node_geo_legacy_points_to_volume.cc
+ nodes/legacy/node_geo_legacy_raycast.cc
+ nodes/legacy/node_geo_legacy_select_by_material.cc
+ nodes/legacy/node_geo_legacy_subdivision_surface.cc
+ nodes/legacy/node_geo_legacy_volume_to_mesh.cc
+
+ nodes/node_geo_accumulate_field.cc
+ nodes/node_geo_attribute_capture.cc
+ nodes/node_geo_attribute_domain_size.cc
+ nodes/node_geo_attribute_remove.cc
+ nodes/node_geo_attribute_statistic.cc
+ nodes/node_geo_boolean.cc
+ nodes/node_geo_bounding_box.cc
+ nodes/node_geo_collection_info.cc
+ nodes/node_geo_common.cc
+ nodes/node_geo_convex_hull.cc
+ nodes/node_geo_curve_endpoint_selection.cc
+ nodes/node_geo_curve_fill.cc
+ nodes/node_geo_curve_fillet.cc
+ nodes/node_geo_curve_handle_type_selection.cc
+ nodes/node_geo_curve_length.cc
+ nodes/node_geo_curve_primitive_arc.cc
+ nodes/node_geo_curve_primitive_bezier_segment.cc
+ nodes/node_geo_curve_primitive_circle.cc
+ nodes/node_geo_curve_primitive_line.cc
+ nodes/node_geo_curve_primitive_quadratic_bezier.cc
+ nodes/node_geo_curve_primitive_quadrilateral.cc
+ nodes/node_geo_curve_primitive_spiral.cc
+ nodes/node_geo_curve_primitive_star.cc
+ nodes/node_geo_curve_resample.cc
+ nodes/node_geo_curve_reverse.cc
+ nodes/node_geo_curve_sample.cc
+ nodes/node_geo_curve_set_handles.cc
+ nodes/node_geo_curve_spline_parameter.cc
+ nodes/node_geo_curve_spline_type.cc
+ nodes/node_geo_curve_subdivide.cc
+ nodes/node_geo_curve_to_mesh.cc
+ nodes/node_geo_curve_to_points.cc
+ nodes/node_geo_curve_trim.cc
+ nodes/node_geo_delete_geometry.cc
+ nodes/node_geo_distribute_points_on_faces.cc
+ nodes/node_geo_dual_mesh.cc
+ nodes/node_geo_edge_split.cc
+ nodes/node_geo_extrude_mesh.cc
+ nodes/node_geo_field_at_index.cc
+ nodes/node_geo_flip_faces.cc
+ nodes/node_geo_geometry_to_instance.cc
+ nodes/node_geo_image_texture.cc
+ nodes/node_geo_input_curve_handles.cc
+ nodes/node_geo_input_curve_tilt.cc
+ nodes/node_geo_input_id.cc
+ nodes/node_geo_input_index.cc
+ nodes/node_geo_input_material.cc
+ nodes/node_geo_input_material_index.cc
+ nodes/node_geo_input_mesh_edge_angle.cc
+ nodes/node_geo_input_mesh_edge_neighbors.cc
+ nodes/node_geo_input_mesh_edge_vertices.cc
+ nodes/node_geo_input_mesh_face_area.cc
+ nodes/node_geo_input_mesh_face_neighbors.cc
+ nodes/node_geo_input_mesh_island.cc
+ nodes/node_geo_input_mesh_vertex_neighbors.cc
+ nodes/node_geo_input_normal.cc
+ nodes/node_geo_input_position.cc
+ nodes/node_geo_input_radius.cc
+ nodes/node_geo_input_scene_time.cc
+ nodes/node_geo_input_shade_smooth.cc
+ nodes/node_geo_input_spline_cyclic.cc
+ nodes/node_geo_input_spline_length.cc
+ nodes/node_geo_input_spline_resolution.cc
+ nodes/node_geo_input_tangent.cc
+ nodes/node_geo_instance_on_points.cc
+ nodes/node_geo_instances_to_points.cc
+ nodes/node_geo_is_viewport.cc
+ nodes/node_geo_join_geometry.cc
+ nodes/node_geo_material_replace.cc
+ nodes/node_geo_material_selection.cc
+ nodes/node_geo_merge_by_distance.cc
+ nodes/node_geo_mesh_primitive_circle.cc
+ nodes/node_geo_mesh_primitive_cone.cc
+ nodes/node_geo_mesh_primitive_cube.cc
+ nodes/node_geo_mesh_primitive_cylinder.cc
+ nodes/node_geo_mesh_primitive_grid.cc
+ nodes/node_geo_mesh_primitive_ico_sphere.cc
+ nodes/node_geo_mesh_primitive_line.cc
+ nodes/node_geo_mesh_primitive_uv_sphere.cc
+ nodes/node_geo_mesh_subdivide.cc
+ nodes/node_geo_mesh_to_curve.cc
+ nodes/node_geo_mesh_to_points.cc
+ nodes/node_geo_object_info.cc
+ nodes/node_geo_points_to_vertices.cc
+ nodes/node_geo_points_to_volume.cc
+ nodes/node_geo_proximity.cc
+ nodes/node_geo_raycast.cc
+ nodes/node_geo_realize_instances.cc
+ nodes/node_geo_rotate_instances.cc
+ nodes/node_geo_scale_elements.cc
+ nodes/node_geo_scale_instances.cc
+ nodes/node_geo_separate_components.cc
+ nodes/node_geo_separate_geometry.cc
+ nodes/node_geo_set_curve_handles.cc
+ nodes/node_geo_set_curve_radius.cc
+ nodes/node_geo_set_curve_tilt.cc
+ nodes/node_geo_set_id.cc
+ nodes/node_geo_set_material.cc
+ nodes/node_geo_set_material_index.cc
+ nodes/node_geo_set_point_radius.cc
+ nodes/node_geo_set_position.cc
+ nodes/node_geo_set_shade_smooth.cc
+ nodes/node_geo_set_spline_cyclic.cc
+ nodes/node_geo_set_spline_resolution.cc
+ nodes/node_geo_string_join.cc
+ nodes/node_geo_string_to_curves.cc
+ nodes/node_geo_subdivision_surface.cc
+ nodes/node_geo_switch.cc
+ nodes/node_geo_transfer_attribute.cc
+ nodes/node_geo_transform.cc
+ nodes/node_geo_translate_instances.cc
+ nodes/node_geo_triangulate.cc
+ nodes/node_geo_viewer.cc
+ nodes/node_geo_volume_to_mesh.cc
+
+ node_geometry_exec.cc
+ node_geometry_tree.cc
+ node_geometry_util.cc
+
+ node_geometry_util.hh
+)
+
+set(LIB
+ bf_bmesh
+ bf_functions
+ bf_geometry
+)
+
+if(WITH_BULLET)
+ list(APPEND INC_SYS
+ ${BULLET_INCLUDE_DIRS}
+ ../../../../intern/rigidbody
+ )
+ if(NOT WITH_SYSTEM_BULLET)
+ list(APPEND LIB
+ extern_bullet
+ )
+ endif()
+
+ list(APPEND LIB
+ ${BULLET_LIBRARIES}
+ )
+ add_definitions(-DWITH_BULLET)
+endif()
+
+if(WITH_PYTHON)
+ list(APPEND INC
+ ../../python
+ )
+ list(APPEND INC_SYS
+ ${PYTHON_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ ${PYTHON_LINKFLAGS}
+ ${PYTHON_LIBRARIES}
+ )
+ add_definitions(-DWITH_PYTHON)
+endif()
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+if(WITH_TBB)
+ list(APPEND INC_SYS
+ ${TBB_INCLUDE_DIRS}
+ )
+ add_definitions(-DWITH_TBB)
+ if(WIN32)
+ # TBB includes Windows.h which will define min/max macros
+ # that will collide with the stl versions.
+ add_definitions(-DNOMINMAX)
+ endif()
+endif()
+
+if(WITH_IMAGE_OPENEXR)
+ add_definitions(-DWITH_OPENEXR)
+endif()
+
+if(WITH_OPENSUBDIV)
+ add_definitions(-DWITH_OPENSUBDIV)
+endif()
+
+if(WITH_GMP)
+ add_definitions(-DWITH_GMP)
+
+ list(APPEND INC_SYS
+ ${GMP_INCLUDE_DIRS}
+ )
+
+ list(APPEND LIB
+ ${GMP_LIBRARIES}
+ )
+endif()
+
+if(WITH_OPENVDB)
+ list(APPEND INC_SYS
+ ${OPENVDB_INCLUDE_DIRS}
+ )
+ add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
+endif()
+
+blender_add_lib(bf_nodes_geometry "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_UNITY_BUILD)
+ set_target_properties(bf_nodes_geometry PROPERTIES UNITY_BUILD ON)
+ set_target_properties(bf_nodes_geometry PROPERTIES UNITY_BUILD_BATCH_SIZE 10)
+endif()
diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc
index d6b23c38ee4..a6dec71ed06 100644
--- a/source/blender/nodes/geometry/node_geometry_tree.cc
+++ b/source/blender/nodes/geometry/node_geometry_tree.cc
@@ -32,6 +32,8 @@
#include "RNA_access.h"
+#include "UI_resources.h"
+
#include "node_common.h"
bNodeTreeType *ntreeType_Geometry;
@@ -84,15 +86,16 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa
func(calldata, NODE_CLASS_LAYOUT, N_("Layout"));
}
-static bool geometry_node_tree_validate_link(bNodeTree *UNUSED(ntree), bNodeLink *link)
+static bool geometry_node_tree_validate_link(eNodeSocketDatatype type_a,
+ eNodeSocketDatatype type_b)
{
/* Geometry, string, object, material, texture and collection sockets can only be connected to
* themselves. The other types can be converted between each other. */
- if (ELEM(link->fromsock->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT) &&
- ELEM(link->tosock->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT)) {
+ if (ELEM(type_a, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT) &&
+ ELEM(type_b, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT)) {
return true;
}
- return (link->tosock->type == link->fromsock->type);
+ return type_a == type_b;
}
static bool geometry_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
@@ -109,17 +112,18 @@ static bool geometry_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype
SOCK_GEOMETRY,
SOCK_COLLECTION,
SOCK_TEXTURE,
+ SOCK_IMAGE,
SOCK_MATERIAL);
}
-void register_node_tree_type_geo(void)
+void register_node_tree_type_geo()
{
bNodeTreeType *tt = ntreeType_Geometry = static_cast<bNodeTreeType *>(
MEM_callocN(sizeof(bNodeTreeType), "geometry node tree type"));
tt->type = NTREE_GEOMETRY;
strcpy(tt->idname, "GeometryNodeTree");
strcpy(tt->ui_name, N_("Geometry Node Editor"));
- tt->ui_icon = 0; /* defined in drawnode.c */
+ tt->ui_icon = ICON_NODETREE;
strcpy(tt->ui_description, N_("Geometry nodes"));
tt->rna_ext.srna = &RNA_GeometryNodeTree;
tt->update = geometry_node_tree_update;
diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc
index 46e9d36c09c..ceb9a7e1467 100644
--- a/source/blender/nodes/geometry/node_geometry_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -24,18 +24,14 @@
#include "BKE_mesh_runtime.h"
#include "BKE_pointcloud.h"
+#include "NOD_socket_search_link.hh"
+
namespace blender::nodes {
using bke::GeometryInstanceGroup;
-/**
- * Update the availability of a group of input sockets with the same name,
- * used for switching between attribute inputs or single values.
- *
- * \param mode: Controls which socket of the group to make available.
- * \param name_is_available: If false, make all sockets with this name unavailable.
- */
-void update_attribute_input_socket_availabilities(bNode &node,
+void update_attribute_input_socket_availabilities(bNodeTree &ntree,
+ bNode &node,
const StringRef name,
const GeometryNodeAttributeInputMode mode,
const bool name_is_available)
@@ -50,11 +46,36 @@ void update_attribute_input_socket_availabilities(bNode &node,
(socket->type == SOCK_INT && mode_ == GEO_NODE_ATTRIBUTE_INPUT_INTEGER) ||
(socket->type == SOCK_VECTOR && mode_ == GEO_NODE_ATTRIBUTE_INPUT_VECTOR) ||
(socket->type == SOCK_RGBA && mode_ == GEO_NODE_ATTRIBUTE_INPUT_COLOR));
- nodeSetSocketAvailability(socket, socket_is_available);
+ nodeSetSocketAvailability(&ntree, socket, socket_is_available);
}
}
}
+std::optional<CustomDataType> node_data_type_to_custom_data_type(const eNodeSocketDatatype type)
+{
+ switch (type) {
+ case SOCK_FLOAT:
+ return CD_PROP_FLOAT;
+ case SOCK_VECTOR:
+ return CD_PROP_FLOAT3;
+ case SOCK_RGBA:
+ return CD_PROP_COLOR;
+ case SOCK_BOOLEAN:
+ return CD_PROP_BOOL;
+ case SOCK_INT:
+ return CD_PROP_INT32;
+ case SOCK_STRING:
+ return CD_PROP_STRING;
+ default:
+ return {};
+ }
+}
+
+std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket)
+{
+ return node_data_type_to_custom_data_type(static_cast<eNodeSocketDatatype>(socket.type));
+}
+
} // namespace blender::nodes
bool geo_node_poll_default(bNodeType *UNUSED(ntype),
@@ -62,16 +83,16 @@ bool geo_node_poll_default(bNodeType *UNUSED(ntype),
const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "GeometryNodeTree")) {
- *r_disabled_hint = "Not a geometry node tree";
+ *r_disabled_hint = TIP_("Not a geometry node tree");
return false;
}
return true;
}
-void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = geo_node_poll_default;
- ntype->update_internal_links = node_update_internal_links_default;
ntype->insert_link = node_insert_link_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 015ac0de002..dddc3527124 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -18,7 +18,7 @@
#include <string.h>
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
@@ -32,41 +32,59 @@
#include "NOD_geometry.h"
#include "NOD_geometry_exec.hh"
#include "NOD_socket_declarations.hh"
+#include "NOD_socket_declarations_geometry.hh"
#include "node_util.h"
-void geo_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void geo_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
bool geo_node_poll_default(struct bNodeType *ntype,
struct bNodeTree *ntree,
const char **r_disabled_hint);
namespace blender::nodes {
-void update_attribute_input_socket_availabilities(bNode &node,
+/**
+ * Update the availability of a group of input sockets with the same name,
+ * used for switching between attribute inputs or single values.
+ *
+ * \param mode: Controls which socket of the group to make available.
+ * \param name_is_available: If false, make all sockets with this name unavailable.
+ */
+void update_attribute_input_socket_availabilities(bNodeTree &ntree,
+ bNode &node,
const StringRef name,
- const GeometryNodeAttributeInputMode mode,
- const bool name_is_available = true);
+ GeometryNodeAttributeInputMode mode,
+ bool name_is_available = true);
Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
- const AttributeDomain domain);
+ AttributeDomain domain);
-void transform_mesh(Mesh *mesh,
+void transform_mesh(Mesh &mesh,
const float3 translation,
const float3 rotation,
const float3 scale);
-Mesh *create_line_mesh(const float3 start, const float3 delta, const int count);
+void transform_geometry_set(GeometrySet &geometry,
+ const float4x4 &transform,
+ const Depsgraph &depsgraph);
-Mesh *create_grid_mesh(const int verts_x,
- const int verts_y,
- const float size_x,
- const float size_y);
+Mesh *create_line_mesh(const float3 start, const float3 delta, int count);
-Mesh *create_cylinder_or_cone_mesh(const float radius_top,
- const float radius_bottom,
- const float depth,
- const int verts_num,
- const GeometryNodeMeshCircleFillType fill_type);
+Mesh *create_grid_mesh(int verts_x, int verts_y, float size_x, float size_y);
+
+struct ConeAttributeOutputs {
+ StrongAnonymousAttributeID top_id;
+ StrongAnonymousAttributeID bottom_id;
+ StrongAnonymousAttributeID side_id;
+};
+
+Mesh *create_cylinder_or_cone_mesh(float radius_top,
+ float radius_bottom,
+ float depth,
+ int circle_segments,
+ int side_segments,
+ int fill_segments,
+ GeometryNodeMeshCircleFillType fill_type,
+ ConeAttributeOutputs &attribute_outputs);
Mesh *create_cuboid_mesh(float3 size, int verts_x, int verts_y, int verts_z);
@@ -76,7 +94,18 @@ Mesh *create_cuboid_mesh(float3 size, int verts_x, int verts_y, int verts_z);
void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
GeometryComponent &result_component,
Span<bool> masks,
- const bool invert);
+ bool invert);
+/**
+ * Returns the parts of the geometry that are on the selection for the given domain. If the domain
+ * is not applicable for the component, e.g. face domain for point cloud, nothing happens to that
+ * component. If no component can work with the domain, then `error_message` is set to true.
+ */
+void separate_geometry(GeometrySet &geometry_set,
+ AttributeDomain domain,
+ GeometryNodeDeleteGeometryMode mode,
+ const Field<bool> &selection_field,
+ bool invert,
+ bool &r_is_error);
struct CurveToPointsResults {
int result_size;
@@ -100,4 +129,7 @@ void curve_create_default_rotation_attribute(Span<float3> tangents,
Span<float3> normals,
MutableSpan<float3> rotations);
+std::optional<CustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type);
+std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket);
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
index d0bb906e8af..1d064586238 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
@@ -22,27 +22,25 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_align_rotation_to_vector_cc {
-static void geo_node_align_rotation_to_vector_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Factor");
- b.add_input<decl::Float>("Factor", "Factor_001")
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Factor"));
+ b.add_input<decl::Float>(N_("Factor"), "Factor_001")
.default_value(1.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
- b.add_input<decl::String>("Vector");
- b.add_input<decl::Vector>("Vector", "Vector_001")
+ b.add_input<decl::String>(N_("Vector"));
+ b.add_input<decl::Vector>(N_("Vector"), "Vector_001")
.default_value({0.0, 0.0, 1.0})
.subtype(PROP_ANGLE);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_align_rotation_to_vector_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiLayoutSetPropSep(layout, true);
@@ -53,10 +51,10 @@ static void geo_node_align_rotation_to_vector_layout(uiLayout *layout,
uiItemR(col, ptr, "input_type_vector", 0, IFACE_("Vector"), ICON_NONE);
}
-static void geo_node_align_rotation_to_vector_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *)
- MEM_callocN(sizeof(NodeGeometryAlignRotationToVector), __func__);
+ NodeGeometryAlignRotationToVector *node_storage = MEM_cnew<NodeGeometryAlignRotationToVector>(
+ __func__);
node_storage->axis = GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_X;
node_storage->input_type_factor = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
@@ -65,14 +63,14 @@ static void geo_node_align_rotation_to_vector_init(bNodeTree *UNUSED(ntree), bNo
node->storage = node_storage;
}
-static void geo_node_align_rotation_to_vector_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *)
node->storage;
update_attribute_input_socket_availabilities(
- *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor);
+ *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor);
update_attribute_input_socket_availabilities(
- *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector);
+ *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector);
}
static void align_rotations_auto_pivot(const VArray<float3> &vectors,
@@ -92,14 +90,14 @@ static void align_rotations_auto_pivot(const VArray<float3> &vectors,
float3 old_axis;
mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
- const float3 new_axis = vector.normalized();
- float3 rotation_axis = float3::cross_high_precision(old_axis, new_axis);
+ const float3 new_axis = math::normalize(vector);
+ float3 rotation_axis = math::cross_high_precision(old_axis, new_axis);
if (is_zero_v3(rotation_axis)) {
/* The vectors are linearly dependent, so we fall back to another axis. */
- rotation_axis = float3::cross_high_precision(old_axis, float3(1, 0, 0));
+ rotation_axis = math::cross_high_precision(old_axis, float3(1, 0, 0));
if (is_zero_v3(rotation_axis)) {
/* This is now guaranteed to not be zero. */
- rotation_axis = float3::cross_high_precision(old_axis, float3(0, 1, 0));
+ rotation_axis = math::cross_high_precision(old_axis, float3(0, 1, 0));
}
}
@@ -179,9 +177,9 @@ static void align_rotations_on_component(GeometryComponent &component,
return;
}
- GVArray_Typed<float> factors = params.get_input_attribute<float>(
+ VArray<float> factors = params.get_input_attribute<float>(
"Factor", component, ATTR_DOMAIN_POINT, 1.0f);
- GVArray_Typed<float3> vectors = params.get_input_attribute<float3>(
+ VArray<float3> vectors = params.get_input_attribute<float3>(
"Vector", component, ATTR_DOMAIN_POINT, {0, 0, 1});
float3 local_main_axis{0, 0, 0};
@@ -199,11 +197,11 @@ static void align_rotations_on_component(GeometryComponent &component,
rotations.save();
}
-static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
align_rotations_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -219,25 +217,26 @@ static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_align_rotation_to_vector_cc
void register_node_type_geo_align_rotation_to_vector()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_align_rotation_to_vector_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ALIGN_ROTATION_TO_VECTOR,
"Align Rotation to Vector",
- NODE_CLASS_GEOMETRY,
- 0);
- node_type_init(&ntype, blender::nodes::geo_node_align_rotation_to_vector_init);
- node_type_update(&ntype, blender::nodes::geo_node_align_rotation_to_vector_update);
+ NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
"NodeGeometryAlignRotationToVector",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_align_rotation_to_vector_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_align_rotation_to_vector_exec;
- ntype.draw_buttons = blender::nodes::geo_node_align_rotation_to_vector_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc
index 2e931a2da98..cac2a90a76c 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc
@@ -20,40 +20,39 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_clamp_cc {
-static void geo_node_attribute_clamp_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute");
- b.add_input<decl::String>("Result");
- b.add_input<decl::Vector>("Min");
- b.add_input<decl::Vector>("Max").default_value({1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Min", "Min_001");
- b.add_input<decl::Float>("Max", "Max_001").default_value(1.0f);
- b.add_input<decl::Int>("Min", "Min_002").min(-100000).max(100000);
- b.add_input<decl::Int>("Max", "Max_002").default_value(100).min(-100000).max(100000);
- b.add_input<decl::Color>("Min", "Min_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_input<decl::Color>("Max", "Max_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute"));
+ b.add_input<decl::String>(N_("Result"));
+ b.add_input<decl::Vector>(N_("Min"));
+ b.add_input<decl::Vector>(N_("Max")).default_value({1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Min"), "Min_001");
+ b.add_input<decl::Float>(N_("Max"), "Max_001").default_value(1.0f);
+ b.add_input<decl::Int>(N_("Min"), "Min_002").min(-100000).max(100000);
+ b.add_input<decl::Int>(N_("Max"), "Max_002").default_value(100).min(-100000).max(100000);
+ b.add_input<decl::Color>(N_("Min"), "Min_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_input<decl::Color>(N_("Max"), "Max_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_clamp_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
}
-static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeClamp *data = (NodeAttributeClamp *)MEM_callocN(sizeof(NodeAttributeClamp),
- __func__);
+ NodeAttributeClamp *data = MEM_cnew<NodeAttributeClamp>(__func__);
data->data_type = CD_PROP_FLOAT;
data->operation = NODE_CLAMP_MINMAX;
node->storage = data;
}
-static void geo_node_attribute_clamp_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 3);
bNodeSocket *sock_max_vector = sock_min_vector->next;
@@ -66,14 +65,14 @@ static void geo_node_attribute_clamp_update(bNodeTree *UNUSED(ntree), bNode *nod
const NodeAttributeClamp &storage = *(const NodeAttributeClamp *)node->storage;
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
- nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32);
- nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32);
- nodeSetSocketAvailability(sock_min_color, data_type == CD_PROP_COLOR);
- nodeSetSocketAvailability(sock_max_color, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, sock_min_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_max_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_min_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_max_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_min_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(ntree, sock_max_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(ntree, sock_min_color, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, sock_max_color, data_type == CD_PROP_COLOR);
}
template<typename T> T clamp_value(const T val, const T min, const T max);
@@ -156,7 +155,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
const AttributeDomain domain = get_result_domain(component, attribute_name, result_name);
const int operation = static_cast<int>(storage.operation);
- GVArrayPtr attribute_input = component.attribute_try_get_for_read(
+ GVArray attribute_input = component.attribute_try_get_for_read(
attribute_name, domain, data_type);
OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
@@ -185,7 +184,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
}
}
MutableSpan<float3> results = attribute_result.as_span<float3>();
- clamp_attribute<float3>(attribute_input->typed<float3>(), results, min, max);
+ clamp_attribute<float3>(attribute_input.typed<float3>(), results, min, max);
break;
}
case CD_PROP_FLOAT: {
@@ -193,10 +192,10 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
const float max = params.get_input<float>("Max_001");
MutableSpan<float> results = attribute_result.as_span<float>();
if (operation == NODE_CLAMP_RANGE && min > max) {
- clamp_attribute<float>(attribute_input->typed<float>(), results, max, min);
+ clamp_attribute<float>(attribute_input.typed<float>(), results, max, min);
}
else {
- clamp_attribute<float>(attribute_input->typed<float>(), results, min, max);
+ clamp_attribute<float>(attribute_input.typed<float>(), results, min, max);
}
break;
}
@@ -205,10 +204,10 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
const int max = params.get_input<int>("Max_002");
MutableSpan<int> results = attribute_result.as_span<int>();
if (operation == NODE_CLAMP_RANGE && min > max) {
- clamp_attribute<int>(attribute_input->typed<int>(), results, max, min);
+ clamp_attribute<int>(attribute_input.typed<int>(), results, max, min);
}
else {
- clamp_attribute<int>(attribute_input->typed<int>(), results, min, max);
+ clamp_attribute<int>(attribute_input.typed<int>(), results, min, max);
}
break;
}
@@ -231,7 +230,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
}
MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>();
clamp_attribute<ColorGeometry4f>(
- attribute_input->typed<ColorGeometry4f>(), results, min, max);
+ attribute_input.typed<ColorGeometry4f>(), results, min, max);
break;
}
default: {
@@ -243,11 +242,11 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
attribute_result.save();
}
-static void geo_node_attribute_clamp_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
clamp_attribute(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -262,19 +261,21 @@ static void geo_node_attribute_clamp_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_clamp_cc
void register_node_type_geo_attribute_clamp()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_clamp_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_clamp_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_clamp_update);
- ntype.declare = blender::nodes::geo_node_attribute_clamp_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_clamp_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_clamp_layout;
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeAttributeClamp", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
index aa054af3acd..ec57422a531 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
@@ -23,27 +23,24 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_color_ramp_cc {
-static void geo_node_attribute_color_ramp_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute");
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute"));
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_color_ramp_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiTemplateColorRamp(layout, ptr, "color_ramp", false);
}
-static void geo_node_attribute_color_ramp_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)MEM_callocN(
- sizeof(NodeAttributeColorRamp), __func__);
+ NodeAttributeColorRamp *node_storage = MEM_cnew<NodeAttributeColorRamp>(__func__);
BKE_colorband_init(&node_storage->color_ramp, true);
node->storage = node_storage;
}
@@ -85,7 +82,7 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
return;
}
- GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>(
+ VArray<float> attribute_in = component.attribute_get_for_read<float>(
input_name, result_domain, 0.0f);
MutableSpan<ColorGeometry4f> results = attribute_result.as_span();
@@ -100,11 +97,11 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
attribute_result.save();
}
-static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -119,23 +116,22 @@ static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_color_ramp_cc
void register_node_type_geo_attribute_color_ramp()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_color_ramp_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype,
- GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP,
- "Attribute Color Ramp",
- NODE_CLASS_ATTRIBUTE,
- 0);
+ geo_node_type_base(
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP, "Attribute Color Ramp", NODE_CLASS_ATTRIBUTE);
node_type_storage(
&ntype, "NodeAttributeColorRamp", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_color_ramp_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- ntype.declare = blender::nodes::geo_node_attribute_color_ramp_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_color_ramp_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_color_ramp_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
index 569d5a824ca..403b9446f75 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
@@ -19,24 +19,22 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_combine_xyz_cc {
-static void geo_node_attribute_combine_xyz_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("X");
- b.add_input<decl::Float>("X", "X_001");
- b.add_input<decl::String>("Y");
- b.add_input<decl::Float>("Y", "Y_001");
- b.add_input<decl::String>("Z");
- b.add_input<decl::Float>("Z", "Z_001");
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("X"));
+ b.add_input<decl::Float>(N_("X"), "X_001");
+ b.add_input<decl::String>(N_("Y"));
+ b.add_input<decl::Float>(N_("Y"), "Y_001");
+ b.add_input<decl::String>(N_("Z"));
+ b.add_input<decl::Float>(N_("Z"), "Z_001");
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_combine_xyz_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -46,10 +44,9 @@ static void geo_node_attribute_combine_xyz_layout(uiLayout *layout,
uiItemR(col, ptr, "input_type_z", 0, IFACE_("Z"), ICON_NONE);
}
-static void geo_node_attribute_combine_xyz_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeCombineXYZ *data = (NodeAttributeCombineXYZ *)MEM_callocN(
- sizeof(NodeAttributeCombineXYZ), __func__);
+ NodeAttributeCombineXYZ *data = MEM_cnew<NodeAttributeCombineXYZ>(__func__);
data->input_type_x = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
data->input_type_y = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
@@ -57,15 +54,15 @@ static void geo_node_attribute_combine_xyz_init(bNodeTree *UNUSED(tree), bNode *
node->storage = data;
}
-static void geo_node_attribute_combine_xyz_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeCombineXYZ *node_storage = (NodeAttributeCombineXYZ *)node->storage;
update_attribute_input_socket_availabilities(
- *node, "X", (GeometryNodeAttributeInputMode)node_storage->input_type_x);
+ *ntree, *node, "X", (GeometryNodeAttributeInputMode)node_storage->input_type_x);
update_attribute_input_socket_availabilities(
- *node, "Y", (GeometryNodeAttributeInputMode)node_storage->input_type_y);
+ *ntree, *node, "Y", (GeometryNodeAttributeInputMode)node_storage->input_type_y);
update_attribute_input_socket_availabilities(
- *node, "Z", (GeometryNodeAttributeInputMode)node_storage->input_type_z);
+ *ntree, *node, "Z", (GeometryNodeAttributeInputMode)node_storage->input_type_z);
}
static AttributeDomain get_result_domain(const GeometryComponent &component,
@@ -95,11 +92,11 @@ static void combine_attributes(GeometryComponent &component, const GeoNodeExecPa
if (!attribute_result) {
return;
}
- GVArray_Typed<float> attribute_x = params.get_input_attribute<float>(
+ VArray<float> attribute_x = params.get_input_attribute<float>(
"X", component, result_domain, 0.0f);
- GVArray_Typed<float> attribute_y = params.get_input_attribute<float>(
+ VArray<float> attribute_y = params.get_input_attribute<float>(
"Y", component, result_domain, 0.0f);
- GVArray_Typed<float> attribute_z = params.get_input_attribute<float>(
+ VArray<float> attribute_z = params.get_input_attribute<float>(
"Z", component, result_domain, 0.0f);
for (const int i : IndexRange(attribute_result->size())) {
@@ -111,11 +108,11 @@ static void combine_attributes(GeometryComponent &component, const GeoNodeExecPa
attribute_result.save();
}
-static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
combine_attributes(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -130,24 +127,25 @@ static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_combine_xyz_cc
void register_node_type_geo_attribute_combine_xyz()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_combine_xyz_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_COMBINE_XYZ,
"Attribute Combine XYZ",
- NODE_CLASS_ATTRIBUTE,
- 0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_combine_xyz_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_combine_xyz_update);
+ NODE_CLASS_ATTRIBUTE);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeAttributeCombineXYZ", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_attribute_combine_xyz_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_combine_xyz_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_combine_xyz_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc
index 0b9708dae14..6cec73d76a2 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc
@@ -21,27 +21,25 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_compare_cc {
-static void geo_node_attribute_compare_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("A");
- b.add_input<decl::Float>("A", "A_001");
- b.add_input<decl::Vector>("A", "A_002");
- b.add_input<decl::Color>("A", "A_003").default_value({0.5, 0.5, 0.5, 1.0});
- b.add_input<decl::String>("B");
- b.add_input<decl::Float>("B", "B_001");
- b.add_input<decl::Vector>("B", "B_002");
- b.add_input<decl::Color>("B", "B_003").default_value({0.5, 0.5, 0.5, 1.0});
- b.add_input<decl::Float>("Threshold").default_value(0.01f).min(0.0f);
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("A"));
+ b.add_input<decl::Float>(N_("A"), "A_001");
+ b.add_input<decl::Vector>(N_("A"), "A_002");
+ b.add_input<decl::Color>(N_("A"), "A_003").default_value({0.5, 0.5, 0.5, 1.0});
+ b.add_input<decl::String>(N_("B"));
+ b.add_input<decl::Float>(N_("B"), "B_001");
+ b.add_input<decl::Vector>(N_("B"), "B_002");
+ b.add_input<decl::Color>(N_("B"), "B_003").default_value({0.5, 0.5, 0.5, 1.0});
+ b.add_input<decl::Float>(N_("Threshold")).default_value(0.01f).min(0.0f);
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_compare_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
uiLayoutSetPropSep(layout, true);
@@ -50,11 +48,10 @@ static void geo_node_attribute_compare_layout(uiLayout *layout,
uiItemR(layout, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE);
}
-static void geo_node_attribute_compare_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeCompare *data = (NodeAttributeCompare *)MEM_callocN(sizeof(NodeAttributeCompare),
- __func__);
- data->operation = NODE_FLOAT_COMPARE_GREATER_THAN;
+ NodeAttributeCompare *data = MEM_cnew<NodeAttributeCompare>(__func__);
+ data->operation = NODE_COMPARE_GREATER_THAN;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
node->storage = data;
@@ -62,24 +59,24 @@ static void geo_node_attribute_compare_init(bNodeTree *UNUSED(tree), bNode *node
static bool operation_tests_equality(const NodeAttributeCompare &node_storage)
{
- return ELEM(node_storage.operation, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL);
+ return ELEM(node_storage.operation, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL);
}
-static void geo_node_attribute_compare_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node->storage;
update_attribute_input_socket_availabilities(
- *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
+ *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
update_attribute_input_socket_availabilities(
- *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b);
+ *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b);
bNodeSocket *socket_threshold = (bNodeSocket *)BLI_findlink(&node->inputs, 9);
- nodeSetSocketAvailability(socket_threshold, operation_tests_equality(*node_storage));
+ nodeSetSocketAvailability(ntree, socket_threshold, operation_tests_equality(*node_storage));
}
static void do_math_operation(const VArray<float> &input_a,
const VArray<float> &input_b,
- const FloatCompareOperation operation,
+ const NodeCompareOperation operation,
MutableSpan<bool> span_result)
{
const int size = input_a.size();
@@ -243,7 +240,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
{
const bNode &node = params.node();
NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node.storage;
- const FloatCompareOperation operation = static_cast<FloatCompareOperation>(
+ const NodeCompareOperation operation = static_cast<NodeCompareOperation>(
node_storage->operation);
const std::string result_name = params.get_input<std::string>("Result");
@@ -257,9 +254,9 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
const CustomDataType input_data_type = get_data_type(component, params, *node_storage);
- GVArrayPtr attribute_a = params.get_input_attribute(
+ GVArray attribute_a = params.get_input_attribute(
"A", component, result_domain, input_data_type, nullptr);
- GVArrayPtr attribute_b = params.get_input_attribute(
+ GVArray attribute_b = params.get_input_attribute(
"B", component, result_domain, input_data_type, nullptr);
if (!attribute_a || !attribute_b) {
@@ -273,60 +270,60 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
* conversions and float comparison. In other words, the comparison is not element-wise. */
if (operation_tests_equality(*node_storage)) {
const float threshold = params.get_input<float>("Threshold");
- if (operation == NODE_FLOAT_COMPARE_EQUAL) {
+ if (operation == NODE_COMPARE_EQUAL) {
if (input_data_type == CD_PROP_FLOAT) {
do_equal_operation_float(
- attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span);
+ attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_FLOAT3) {
do_equal_operation_float3(
- attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span);
+ attribute_a.typed<float3>(), attribute_b.typed<float3>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_COLOR) {
- do_equal_operation_color4f(attribute_a->typed<ColorGeometry4f>(),
- attribute_b->typed<ColorGeometry4f>(),
+ do_equal_operation_color4f(attribute_a.typed<ColorGeometry4f>(),
+ attribute_b.typed<ColorGeometry4f>(),
threshold,
result_span);
}
else if (input_data_type == CD_PROP_BOOL) {
do_equal_operation_bool(
- attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span);
+ attribute_a.typed<bool>(), attribute_b.typed<bool>(), threshold, result_span);
}
}
- else if (operation == NODE_FLOAT_COMPARE_NOT_EQUAL) {
+ else if (operation == NODE_COMPARE_NOT_EQUAL) {
if (input_data_type == CD_PROP_FLOAT) {
do_not_equal_operation_float(
- attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span);
+ attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_FLOAT3) {
do_not_equal_operation_float3(
- attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span);
+ attribute_a.typed<float3>(), attribute_b.typed<float3>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_COLOR) {
- do_not_equal_operation_color4f(attribute_a->typed<ColorGeometry4f>(),
- attribute_b->typed<ColorGeometry4f>(),
+ do_not_equal_operation_color4f(attribute_a.typed<ColorGeometry4f>(),
+ attribute_b.typed<ColorGeometry4f>(),
threshold,
result_span);
}
else if (input_data_type == CD_PROP_BOOL) {
do_not_equal_operation_bool(
- attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span);
+ attribute_a.typed<bool>(), attribute_b.typed<bool>(), threshold, result_span);
}
}
}
else {
do_math_operation(
- attribute_a->typed<float>(), attribute_b->typed<float>(), operation, result_span);
+ attribute_a.typed<float>(), attribute_b.typed<float>(), operation, result_span);
}
attribute_result.save();
}
-static void geo_node_attribute_compare_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
attribute_compare_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -341,20 +338,22 @@ static void geo_node_attribute_compare_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_compare_cc
void register_node_type_geo_attribute_compare()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_compare_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_COMPARE, "Attribute Compare", NODE_CLASS_ATTRIBUTE, 0);
- ntype.declare = blender::nodes::geo_node_attribute_compare_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_compare_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_compare_layout;
- node_type_update(&ntype, blender::nodes::geo_node_attribute_compare_update);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_COMPARE, "Attribute Compare", NODE_CLASS_ATTRIBUTE);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeAttributeCompare", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_compare_init);
+ node_type_init(&ntype, file_ns::node_init);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc
index a2382aa9d25..2b13f57e990 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc
@@ -19,19 +19,17 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_convert_cc {
-static void geo_node_attribute_convert_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute");
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute"));
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_convert_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -39,10 +37,9 @@ static void geo_node_attribute_convert_layout(uiLayout *layout,
uiItemR(layout, ptr, "data_type", 0, IFACE_("Type"), ICON_NONE);
}
-static void geo_node_attribute_convert_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeConvert *data = (NodeAttributeConvert *)MEM_callocN(sizeof(NodeAttributeConvert),
- __func__);
+ NodeAttributeConvert *data = MEM_cnew<NodeAttributeConvert>(__func__);
data->data_type = CD_AUTO_FROM_NAME;
data->domain = ATTR_DOMAIN_AUTO;
@@ -104,7 +101,7 @@ static void attribute_convert_calc(GeometryComponent &component,
return;
}
- GVArrayPtr source_attribute = component.attribute_try_get_for_read(
+ GVArray source_attribute = component.attribute_try_get_for_read(
source_name, result_domain, result_type);
if (!source_attribute) {
params.error_message_add(NodeWarningType::Error,
@@ -118,7 +115,7 @@ static void attribute_convert_calc(GeometryComponent &component,
return;
}
- GVArray_GSpan source_span{*source_attribute};
+ GVArray_GSpan source_span{source_attribute};
GMutableSpan result_span = result_attribute.as_span();
BLI_assert(source_span.size() == result_span.size());
@@ -130,11 +127,11 @@ static void attribute_convert_calc(GeometryComponent &component,
result_attribute.save();
}
-static void geo_node_attribute_convert_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
const std::string result_name = params.extract_input<std::string>("Result");
const std::string source_name = params.extract_input<std::string>("Attribute");
@@ -143,7 +140,7 @@ static void geo_node_attribute_convert_exec(GeoNodeExecParams params)
const AttributeDomain domain = static_cast<AttributeDomain>(node_storage.domain);
if (result_name.empty()) {
- params.set_output("Geometry", geometry_set);
+ params.set_default_remaining_outputs();
return;
}
@@ -175,18 +172,20 @@ static void geo_node_attribute_convert_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_convert_cc
void register_node_type_geo_attribute_convert()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_convert_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CONVERT, "Attribute Convert", NODE_CLASS_ATTRIBUTE, 0);
- ntype.declare = blender::nodes::geo_node_attribute_convert_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_convert_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_convert_layout;
- node_type_init(&ntype, blender::nodes::geo_node_attribute_convert_init);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CONVERT, "Attribute Convert", NODE_CLASS_ATTRIBUTE);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeAttributeConvert", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc
index b9621b4ae92..8e1e763f1ad 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc
@@ -24,19 +24,17 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_curve_map_cc {
-static void geo_node_attribute_curve_map_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute");
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute"));
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_curve_map_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
bNode *node = (bNode *)ptr->data;
@@ -54,7 +52,7 @@ static void geo_node_attribute_curve_map_layout(uiLayout *layout,
}
}
-static void geo_node_attribute_curve_map_free_storage(bNode *node)
+static void node_free_storage(bNode *node)
{
if (node->storage) {
NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage;
@@ -64,9 +62,9 @@ static void geo_node_attribute_curve_map_free_storage(bNode *node)
}
}
-static void geo_node_attribute_curve_map_copy_storage(bNodeTree *UNUSED(dest_ntree),
- bNode *dest_node,
- const bNode *src_node)
+static void node_copy_storage(bNodeTree *UNUSED(dest_ntree),
+ bNode *dest_node,
+ const bNode *src_node)
{
dest_node->storage = MEM_dupallocN(src_node->storage);
NodeAttributeCurveMap *src_data = (NodeAttributeCurveMap *)src_node->storage;
@@ -75,10 +73,9 @@ static void geo_node_attribute_curve_map_copy_storage(bNodeTree *UNUSED(dest_ntr
dest_data->curve_rgb = BKE_curvemapping_copy(src_data->curve_rgb);
}
-static void geo_node_attribute_curve_map_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)MEM_callocN(sizeof(NodeAttributeCurveMap),
- __func__);
+ NodeAttributeCurveMap *data = MEM_cnew<NodeAttributeCurveMap>(__func__);
data->data_type = CD_PROP_FLOAT;
data->curve_vec = BKE_curvemapping_add(4, -1.0f, -1.0f, 1.0f, 1.0f);
@@ -87,7 +84,7 @@ static void geo_node_attribute_curve_map_init(bNodeTree *UNUSED(ntree), bNode *n
node->storage = data;
}
-static void geo_node_attribute_curve_map_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *UNUSED(ntree), bNode *node)
{
/* Set the active curve when data type is changed. */
NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage;
@@ -136,10 +133,10 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
switch (result_type) {
case CD_PROP_FLOAT: {
const CurveMapping *cumap = (CurveMapping *)node_storage.curve_vec;
- GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>(
+ VArray<float> attribute_in = component.attribute_get_for_read<float>(
input_name, result_domain, float(0.0f));
MutableSpan<float> results = attribute_result.as_span<float>();
- threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
+ threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) {
for (const int i : range) {
results[i] = BKE_curvemapping_evaluateF(cumap, 3, attribute_in[i]);
}
@@ -148,10 +145,10 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
}
case CD_PROP_FLOAT3: {
const CurveMapping *cumap = (CurveMapping *)node_storage.curve_vec;
- GVArray_Typed<float3> attribute_in = component.attribute_get_for_read<float3>(
+ VArray<float3> attribute_in = component.attribute_get_for_read<float3>(
input_name, result_domain, float3(0.0f));
MutableSpan<float3> results = attribute_result.as_span<float3>();
- threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
+ threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) {
for (const int i : range) {
BKE_curvemapping_evaluate3F(cumap, results[i], attribute_in[i]);
}
@@ -160,11 +157,10 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
}
case CD_PROP_COLOR: {
const CurveMapping *cumap = (CurveMapping *)node_storage.curve_rgb;
- GVArray_Typed<ColorGeometry4f> attribute_in =
- component.attribute_get_for_read<ColorGeometry4f>(
- input_name, result_domain, ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f));
+ VArray<ColorGeometry4f> attribute_in = component.attribute_get_for_read<ColorGeometry4f>(
+ input_name, result_domain, ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f));
MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>();
- threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
+ threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) {
for (const int i : range) {
BKE_curvemapping_evaluateRGBF(cumap, results[i], attribute_in[i]);
}
@@ -180,7 +176,7 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
attribute_result.save();
}
-static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const bNode &bnode = params.node();
NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)bnode.storage;
@@ -189,7 +185,7 @@ static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -204,23 +200,23 @@ static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_curve_map_cc
void register_node_type_geo_attribute_curve_map()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_curve_map_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP, "Attribute Curve Map", NODE_CLASS_ATTRIBUTE, 0);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_curve_map_update);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_curve_map_init);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP, "Attribute Curve Map", NODE_CLASS_ATTRIBUTE);
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_storage(&ntype,
- "NodeAttributeCurveMap",
- blender::nodes::geo_node_attribute_curve_map_free_storage,
- blender::nodes::geo_node_attribute_curve_map_copy_storage);
- ntype.declare = blender::nodes::geo_node_attribute_curve_map_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_curve_map_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_curve_map_layout;
+ node_type_storage(
+ &ntype, "NodeAttributeCurveMap", file_ns::node_free_storage, file_ns::node_copy_storage);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc
index 3c50ae5c837..a32e3b7412f 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc
@@ -19,21 +19,21 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_fill_cc {
-static void geo_node_attribute_fill_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute");
- b.add_input<decl::Vector>("Value", "Value");
- b.add_input<decl::Float>("Value", "Value_001");
- b.add_input<decl::Color>("Value", "Value_002");
- b.add_input<decl::Bool>("Value", "Value_003");
- b.add_input<decl::Int>("Value", "Value_004");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute")).is_attribute_name();
+ b.add_input<decl::Vector>(N_("Value"), "Value");
+ b.add_input<decl::Float>(N_("Value"), "Value_001");
+ b.add_input<decl::Color>(N_("Value"), "Value_002");
+ b.add_input<decl::Bool>(N_("Value"), "Value_003");
+ b.add_input<decl::Int>(N_("Value"), "Value_004");
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -41,13 +41,13 @@ static void geo_node_attribute_fill_layout(uiLayout *layout, bContext *UNUSED(C)
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
}
-static void geo_node_attribute_fill_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
node->custom1 = CD_PROP_FLOAT;
node->custom2 = ATTR_DOMAIN_AUTO;
}
-static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *socket_value_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
bNodeSocket *socket_value_float = socket_value_vector->next;
@@ -57,11 +57,11 @@ static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node
const CustomDataType data_type = static_cast<CustomDataType>(node->custom1);
- nodeSetSocketAvailability(socket_value_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(socket_value_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(socket_value_color4f, data_type == CD_PROP_COLOR);
- nodeSetSocketAvailability(socket_value_boolean, data_type == CD_PROP_BOOL);
- nodeSetSocketAvailability(socket_value_int32, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(ntree, socket_value_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, socket_value_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, socket_value_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, socket_value_boolean, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(ntree, socket_value_int32, data_type == CD_PROP_INT32);
}
static AttributeDomain get_result_domain(const GeometryComponent &component, const StringRef name)
@@ -127,11 +127,11 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams
attribute.save();
}
-static void geo_node_attribute_fill_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
fill_attribute(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -146,18 +146,20 @@ static void geo_node_attribute_fill_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_fill_cc
void register_node_type_geo_attribute_fill()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_fill_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_FILL, "Attribute Fill", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_fill_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_fill_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_fill_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_fill_layout;
- ntype.declare = blender::nodes::geo_node_attribute_fill_declare;
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_FILL, "Attribute Fill", NODE_CLASS_ATTRIBUTE);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc
index 0ea3bbe1e45..398af087499 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc
@@ -22,25 +22,25 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_map_range_cc {
-static void geo_node_attribute_map_range_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute");
- b.add_input<decl::String>("Result");
- b.add_input<decl::Float>("From Min");
- b.add_input<decl::Float>("From Max").default_value(1.0f);
- b.add_input<decl::Float>("To Min");
- b.add_input<decl::Float>("To Max").default_value(1.0f);
- b.add_input<decl::Float>("Steps").default_value(4.0f);
- b.add_input<decl::Vector>("From Min", "From Min_001");
- b.add_input<decl::Vector>("From Max", "From Max_001").default_value({1.0f, 1.0f, 1.0f});
- b.add_input<decl::Vector>("To Min", "To Min_001");
- b.add_input<decl::Vector>("To Max", "To Max_001").default_value({1.0f, 1.0f, 1.0f});
- b.add_input<decl::Vector>("Steps", "Steps_001").default_value({4.0f, 4.0f, 4.0f});
- b.add_input<decl::Bool>("Clamp");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute"));
+ b.add_input<decl::String>(N_("Result"));
+ b.add_input<decl::Float>(N_("From Min"));
+ b.add_input<decl::Float>(N_("From Max")).default_value(1.0f);
+ b.add_input<decl::Float>(N_("To Min"));
+ b.add_input<decl::Float>(N_("To Max")).default_value(1.0f);
+ b.add_input<decl::Float>(N_("Steps")).default_value(4.0f);
+ b.add_input<decl::Vector>(N_("From Min"), "From Min_001");
+ b.add_input<decl::Vector>(N_("From Max"), "From Max_001").default_value({1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("To Min"), "To Min_001");
+ b.add_input<decl::Vector>(N_("To Max"), "To Max_001").default_value({1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Steps"), "Steps_001").default_value({4.0f, 4.0f, 4.0f});
+ b.add_input<decl::Bool>(N_("Clamp"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -49,16 +49,15 @@ static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C),
uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE);
}
-static void geo_node_attribute_map_range_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeMapRange *data = (NodeAttributeMapRange *)MEM_callocN(sizeof(NodeAttributeMapRange),
- __func__);
+ NodeAttributeMapRange *data = MEM_cnew<NodeAttributeMapRange>(__func__);
data->data_type = CD_PROP_FLOAT;
data->interpolation_type = NODE_MAP_RANGE_LINEAR;
node->storage = data;
}
-static void geo_node_attribute_map_range_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node->storage;
@@ -78,23 +77,26 @@ static void geo_node_attribute_map_range_update(bNodeTree *UNUSED(ntree), bNode
const CustomDataType data_type = static_cast<CustomDataType>(node_storage.data_type);
- nodeSetSocketAvailability(sock_clamp,
+ nodeSetSocketAvailability(ntree,
+ sock_clamp,
node_storage.interpolation_type == NODE_MAP_RANGE_LINEAR ||
node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED);
- nodeSetSocketAvailability(sock_from_min_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(sock_from_max_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(sock_to_min_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(sock_to_max_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(sock_steps_float,
+ nodeSetSocketAvailability(ntree, sock_from_min_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_from_max_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_to_min_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_to_max_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree,
+ sock_steps_float,
data_type == CD_PROP_FLOAT &&
node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED);
- nodeSetSocketAvailability(sock_from_min_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(sock_from_max_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(sock_to_min_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(sock_to_max_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(sock_steps_vector,
+ nodeSetSocketAvailability(ntree, sock_from_min_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_from_max_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_to_min_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_to_max_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree,
+ sock_steps_vector,
data_type == CD_PROP_FLOAT3 &&
node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED);
}
@@ -362,7 +364,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP
const AttributeDomain domain = get_result_domain(component, input_name, result_name);
- GVArrayPtr attribute_input = component.attribute_try_get_for_read(input_name, domain, data_type);
+ GVArray attribute_input = component.attribute_try_get_for_read(input_name, domain, data_type);
if (!attribute_input) {
params.error_message_add(NodeWarningType::Error,
@@ -381,12 +383,12 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP
switch (data_type) {
case CD_PROP_FLOAT: {
- map_range_float(attribute_input->typed<float>(), attribute_result.as_span<float>(), params);
+ map_range_float(attribute_input.typed<float>(), attribute_result.as_span<float>(), params);
break;
}
case CD_PROP_FLOAT3: {
map_range_float3(
- attribute_input->typed<float3>(), attribute_result.as_span<float3>(), params);
+ attribute_input.typed<float3>(), attribute_result.as_span<float3>(), params);
break;
}
default:
@@ -396,7 +398,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP
attribute_result.save();
}
-static void geo_node_attribute_map_range_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -413,20 +415,22 @@ static void geo_node_attribute_map_range_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_map_range_cc
void register_node_type_geo_attribute_map_range()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_map_range_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE, "Attribute Map Range", NODE_CLASS_ATTRIBUTE, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_map_range_exec;
- node_type_init(&ntype, blender::nodes::geo_node_attribute_map_range_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_map_range_update);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE, "Attribute Map Range", NODE_CLASS_ATTRIBUTE);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeAttributeMapRange", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_attribute_map_range_declare;
- ntype.draw_buttons = blender::nodes::fn_attribute_map_range_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::fn_attribute_map_range_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc
index efa09215b45..3257d2d7358 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc
@@ -25,19 +25,19 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_math_cc {
-static void geo_node_attribute_math_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("A");
- b.add_input<decl::Float>("A", "A_001");
- b.add_input<decl::String>("B");
- b.add_input<decl::Float>("B", "B_001");
- b.add_input<decl::String>("C");
- b.add_input<decl::Float>("C", "C_001");
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("A"));
+ b.add_input<decl::Float>(N_("A"), "A_001");
+ b.add_input<decl::String>(N_("B"));
+ b.add_input<decl::Float>(N_("B"), "B_001");
+ b.add_input<decl::String>(N_("C"));
+ b.add_input<decl::Float>(N_("C"), "C_001");
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static bool operation_use_input_c(const NodeMathOperation operation)
@@ -100,7 +100,7 @@ static bool operation_use_input_b(const NodeMathOperation operation)
return false;
}
-static void geo_node_attribute_math_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage;
@@ -119,9 +119,9 @@ static void geo_node_attribute_math_layout(uiLayout *layout, bContext *UNUSED(C)
}
}
-static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeMath *data = (NodeAttributeMath *)MEM_callocN(sizeof(NodeAttributeMath), __func__);
+ NodeAttributeMath *data = MEM_cnew<NodeAttributeMath>(__func__);
data->operation = NODE_MATH_ADD;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
@@ -130,7 +130,10 @@ static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void geo_node_math_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage;
const char *name;
@@ -141,19 +144,21 @@ static void geo_node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *lab
BLI_strncpy(label, IFACE_(name), maxlen);
}
-static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage;
NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage.operation);
update_attribute_input_socket_availabilities(
- *node, "A", (GeometryNodeAttributeInputMode)node_storage.input_type_a);
+ *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage.input_type_a);
update_attribute_input_socket_availabilities(
+ *ntree,
*node,
"B",
(GeometryNodeAttributeInputMode)node_storage.input_type_b,
operation_use_input_b(operation));
update_attribute_input_socket_availabilities(
+ *ntree,
*node,
"C",
(GeometryNodeAttributeInputMode)node_storage.input_type_c,
@@ -250,7 +255,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
return;
}
- GVArray_Typed<float> attribute_a = params.get_input_attribute<float>(
+ VArray<float> attribute_a = params.get_input_attribute<float>(
"A", component, result_domain, 0.0f);
MutableSpan<float> result_span = attribute_result.as_span();
@@ -258,10 +263,10 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
/* Note that passing the data with `get_internal_span<float>()` works
* because the attributes were accessed with #CD_PROP_FLOAT. */
if (operation_use_input_b(operation)) {
- GVArray_Typed<float> attribute_b = params.get_input_attribute<float>(
+ VArray<float> attribute_b = params.get_input_attribute<float>(
"B", component, result_domain, 0.0f);
if (operation_use_input_c(operation)) {
- GVArray_Typed<float> attribute_c = params.get_input_attribute<float>(
+ VArray<float> attribute_c = params.get_input_attribute<float>(
"C", component, result_domain, 0.0f);
do_math_operation(attribute_a, attribute_b, attribute_c, result_span, operation);
}
@@ -276,11 +281,11 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
attribute_result.save();
}
-static void geo_node_attribute_math_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
attribute_math_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -295,20 +300,22 @@ static void geo_node_attribute_math_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_math_cc
void register_node_type_geo_attribute_math()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_math_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MATH, "Attribute Math", NODE_CLASS_ATTRIBUTE, 0);
- ntype.declare = blender::nodes::geo_node_attribute_math_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_math_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_math_layout;
- node_type_label(&ntype, blender::nodes::geo_node_math_label);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_math_update);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_math_init);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MATH, "Attribute Math", NODE_CLASS_ATTRIBUTE);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.labelfunc = file_ns::geo_node_math_label;
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeAttributeMath", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc
index 74e05cb997d..c0c30898584 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc
@@ -25,30 +25,30 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_mix_cc {
-static void geo_node_mix_attribute_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Factor");
- b.add_input<decl::Float>("Factor", "Factor_001")
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Factor"));
+ b.add_input<decl::Float>(N_("Factor"), "Factor_001")
.default_value(0.5f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
- b.add_input<decl::String>("A");
- b.add_input<decl::Float>("A", "A_001");
- b.add_input<decl::Vector>("A", "A_002");
- b.add_input<decl::Color>("A", "A_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_input<decl::String>("B");
- b.add_input<decl::Float>("B", "B_001");
- b.add_input<decl::Vector>("B", "B_002");
- b.add_input<decl::Color>("B", "B_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::String>(N_("A"));
+ b.add_input<decl::Float>(N_("A"), "A_001");
+ b.add_input<decl::Vector>(N_("A"), "A_002");
+ b.add_input<decl::Color>(N_("A"), "A_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_input<decl::String>(N_("B"));
+ b.add_input<decl::Float>(N_("B"), "B_001");
+ b.add_input<decl::Vector>(N_("B"), "B_002");
+ b.add_input<decl::Color>(N_("B"), "B_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -59,10 +59,9 @@ static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C),
uiItemR(col, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE);
}
-static void geo_node_attribute_mix_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeMix *data = (NodeAttributeMix *)MEM_callocN(sizeof(NodeAttributeMix),
- "attribute mix node");
+ NodeAttributeMix *data = MEM_cnew<NodeAttributeMix>("attribute mix node");
data->blend_type = MA_RAMP_BLEND;
data->input_type_factor = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
@@ -70,15 +69,15 @@ static void geo_node_attribute_mix_init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-static void geo_node_attribute_mix_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeMix *node_storage = (NodeAttributeMix *)node->storage;
update_attribute_input_socket_availabilities(
- *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor);
+ *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor);
update_attribute_input_socket_availabilities(
- *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
+ *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
update_attribute_input_socket_availabilities(
- *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b);
+ *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b);
}
static void do_mix_operation_float(const int blend_mode,
@@ -144,25 +143,28 @@ static void do_mix_operation(const CustomDataType result_type,
GVMutableArray &attribute_result)
{
if (result_type == CD_PROP_FLOAT) {
+ VMutableArray<float> result = attribute_result.typed<float>();
do_mix_operation_float(blend_mode,
attribute_factor,
attribute_a.typed<float>(),
attribute_b.typed<float>(),
- attribute_result.typed<float>());
+ result);
}
else if (result_type == CD_PROP_FLOAT3) {
+ VMutableArray<float3> result = attribute_result.typed<float3>();
do_mix_operation_float3(blend_mode,
attribute_factor,
attribute_a.typed<float3>(),
attribute_b.typed<float3>(),
- attribute_result.typed<float3>());
+ result);
}
else if (result_type == CD_PROP_COLOR) {
+ VMutableArray<ColorGeometry4f> result = attribute_result.typed<ColorGeometry4f>();
do_mix_operation_color4f(blend_mode,
attribute_factor,
attribute_a.typed<ColorGeometry4f>(),
attribute_b.typed<ColorGeometry4f>(),
- attribute_result.typed<ColorGeometry4f>());
+ result);
}
}
@@ -203,27 +205,27 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa
return;
}
- GVArray_Typed<float> attribute_factor = params.get_input_attribute<float>(
+ VArray<float> attribute_factor = params.get_input_attribute<float>(
"Factor", component, result_domain, 0.5f);
- GVArrayPtr attribute_a = params.get_input_attribute(
+ GVArray attribute_a = params.get_input_attribute(
"A", component, result_domain, result_type, nullptr);
- GVArrayPtr attribute_b = params.get_input_attribute(
+ GVArray attribute_b = params.get_input_attribute(
"B", component, result_domain, result_type, nullptr);
do_mix_operation(result_type,
node_storage->blend_type,
attribute_factor,
- *attribute_a,
- *attribute_b,
- *attribute_result);
+ attribute_a,
+ attribute_b,
+ attribute_result.varray());
attribute_result.save();
}
-static void geo_node_attribute_mix_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
attribute_mix_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -238,19 +240,20 @@ static void geo_node_attribute_mix_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_mix_cc
void register_node_type_geo_attribute_mix()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_mix_cc;
+
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MIX, "Attribute Mix", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_mix_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_mix_update);
- ntype.declare = blender::nodes::geo_node_mix_attribute_declare;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_mix_layout;
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_ATTRIBUTE_MIX, "Attribute Mix", NODE_CLASS_ATTRIBUTE);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeAttributeMix", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_mix_exec;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc
index 6120118f611..20f500b1bd8 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc
@@ -26,28 +26,26 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_proximity_cc {
-static void geo_node_attribute_proximity_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Geometry>("Target");
- b.add_input<decl::String>("Distance");
- b.add_input<decl::String>("Position");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Geometry>(N_("Target"));
+ b.add_input<decl::String>(N_("Distance"));
+ b.add_input<decl::String>(N_("Position"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_proximity_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "target_geometry_element", 0, "", ICON_NONE);
}
-static void geo_attribute_proximity_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryAttributeProximity *node_storage = (NodeGeometryAttributeProximity *)MEM_callocN(
- sizeof(NodeGeometryAttributeProximity), __func__);
+ NodeGeometryAttributeProximity *node_storage = MEM_cnew<NodeGeometryAttributeProximity>(
+ __func__);
node_storage->target_geometry_element = GEO_NODE_PROXIMITY_TARGET_FACES;
node->storage = node_storage;
@@ -83,7 +81,7 @@ static void calculate_mesh_proximity(const VArray<float3> &positions,
for (int i : range) {
/* Use the distance to the last found point as upper bound to speedup the bvh lookup. */
- nearest.dist_sq = float3::distance_squared(nearest.co, positions[i]);
+ nearest.dist_sq = math::distance_squared(float3(nearest.co), positions[i]);
BLI_bvhtree_find_nearest(
bvh_data.tree, positions[i], &nearest, bvh_data.nearest_callback, &bvh_data);
@@ -153,7 +151,7 @@ static void attribute_calc_proximity(GeometryComponent &component,
if (!position_attribute || (!distance_attribute && !location_attribute)) {
return;
}
- GVArray_Typed<float3> positions{*position_attribute.varray};
+ VArray<float3> positions = position_attribute.varray.typed<float3>();
const NodeGeometryAttributeProximity &storage =
*(const NodeGeometryAttributeProximity *)params.node().storage;
@@ -203,16 +201,16 @@ static void attribute_calc_proximity(GeometryComponent &component,
}
}
-static void geo_node_attribute_proximity_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
/* This isn't required. This node should be rewritten to handle instances
* for the target geometry set. However, the generic BVH API complicates this. */
- geometry_set_target = geometry_set_realize_instances(geometry_set_target);
+ geometry_set_target = geometry::realize_instances_legacy(geometry_set_target);
if (geometry_set.has<MeshComponent>()) {
attribute_calc_proximity(
@@ -230,22 +228,24 @@ static void geo_node_attribute_proximity_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_proximity_cc
void register_node_type_geo_legacy_attribute_proximity()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_proximity_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Attribute Proximity", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_attribute_proximity_init);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Attribute Proximity", NODE_CLASS_ATTRIBUTE);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryAttributeProximity",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_attribute_proximity_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_proximity_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_proximity_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc
index 2e6ba456725..92a946b225b 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc
@@ -25,39 +25,70 @@
namespace blender::nodes {
-static void geo_node_legacy_attribute_randomize_declare(NodeDeclarationBuilder &b)
+Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
+ const AttributeDomain domain)
+{
+ const int domain_size = component.attribute_domain_size(domain);
+
+ /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */
+ GVArray hash_attribute = component.attribute_try_get_for_read("id", domain);
+ Array<uint32_t> hashes(domain_size);
+ if (hash_attribute) {
+ BLI_assert(hashes.size() == hash_attribute.size());
+ const CPPType &cpp_type = hash_attribute.type();
+ BLI_assert(cpp_type.is_hashable());
+ GVArray_GSpan items{hash_attribute};
+ threading::parallel_for(hashes.index_range(), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ hashes[i] = cpp_type.hash(items[i]);
+ }
+ });
+ }
+ else {
+ /* If there is no "id" attribute for per-point variation, just create it here. */
+ RandomNumberGenerator rng(0);
+ for (const int i : hashes.index_range()) {
+ hashes[i] = rng.get_uint32();
+ }
+ }
+
+ return hashes;
+}
+
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_legacy_attribute_randomize_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute");
- b.add_input<decl::Vector>("Min");
- b.add_input<decl::Vector>("Max").default_value({1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>("Min", "Min_001");
- b.add_input<decl::Float>("Max", "Max_001").default_value(1.0f);
- b.add_input<decl::Int>("Min", "Min_002").min(-100000).max(100000);
- b.add_input<decl::Int>("Max", "Max_002").default_value(100).min(-100000).max(100000);
- b.add_input<decl::Int>("Seed").min(-10000).max(10000);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute"));
+ b.add_input<decl::Vector>(N_("Min"));
+ b.add_input<decl::Vector>(N_("Max")).default_value({1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Min"), "Min_001");
+ b.add_input<decl::Float>(N_("Max"), "Max_001").default_value(1.0f);
+ b.add_input<decl::Int>(N_("Min"), "Min_002").min(-100000).max(100000);
+ b.add_input<decl::Int>(N_("Max"), "Max_002").default_value(100).min(-100000).max(100000);
+ b.add_input<decl::Int>(N_("Seed")).min(-10000).max(10000);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_legacy_attribute_random_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
}
-static void geo_node_legacy_attribute_randomize_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeRandomize *data = (NodeAttributeRandomize *)MEM_callocN(
- sizeof(NodeAttributeRandomize), __func__);
+ NodeAttributeRandomize *data = MEM_cnew<NodeAttributeRandomize>(__func__);
data->data_type = CD_PROP_FLOAT;
data->domain = ATTR_DOMAIN_POINT;
data->operation = GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE;
node->storage = data;
}
-static void geo_node_legacy_attribute_randomize_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
bNodeSocket *sock_max_vector = sock_min_vector->next;
@@ -68,12 +99,12 @@ static void geo_node_legacy_attribute_randomize_update(bNodeTree *UNUSED(ntree),
const NodeAttributeRandomize &storage = *(const NodeAttributeRandomize *)node->storage;
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
- nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32);
- nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(ntree, sock_min_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_max_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_min_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_max_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_min_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(ntree, sock_max_int, data_type == CD_PROP_INT32);
}
template<typename T>
@@ -174,36 +205,6 @@ static void randomize_attribute_bool(MutableSpan<bool> span,
});
}
-Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
- const AttributeDomain domain)
-{
- const int domain_size = component.attribute_domain_size(domain);
-
- /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */
- GVArrayPtr hash_attribute = component.attribute_try_get_for_read("id", domain);
- Array<uint32_t> hashes(domain_size);
- if (hash_attribute) {
- BLI_assert(hashes.size() == hash_attribute->size());
- const CPPType &cpp_type = hash_attribute->type();
- BLI_assert(cpp_type.is_hashable());
- GVArray_GSpan items{*hash_attribute};
- threading::parallel_for(hashes.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- hashes[i] = cpp_type.hash(items[i]);
- }
- });
- }
- else {
- /* If there is no "id" attribute for per-point variation, just create it here. */
- RandomNumberGenerator rng(0);
- for (const int i : hashes.index_range()) {
- hashes[i] = rng.get_uint32();
- }
- }
-
- return hashes;
-}
-
static AttributeDomain get_result_domain(const GeometryComponent &component,
const GeoNodeExecParams &params,
const StringRef name)
@@ -280,12 +281,12 @@ static void randomize_attribute_on_component(GeometryComponent &component,
attribute.save();
}
-static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const std::string attribute_name = params.get_input<std::string>("Attribute");
if (attribute_name.empty()) {
- params.set_output("Geometry", geometry_set);
+ params.set_default_remaining_outputs();
return;
}
const int seed = params.get_input<int>("Seed");
@@ -294,7 +295,7 @@ static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params)
const GeometryNodeAttributeRandomizeMode operation =
static_cast<GeometryNodeAttributeRandomizeMode>(storage.operation);
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
randomize_attribute_on_component(geometry_set.get_component_for_write<MeshComponent>(),
@@ -324,20 +325,22 @@ static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_randomize_cc
void register_node_type_geo_legacy_attribute_randomize()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_randomize_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_legacy_attribute_randomize_init);
- node_type_update(&ntype, blender::nodes::geo_node_legacy_attribute_randomize_update);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
- ntype.declare = blender::nodes::geo_node_legacy_attribute_randomize_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_random_attribute_exec;
- ntype.draw_buttons = blender::nodes::geo_node_legacy_attribute_random_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeAttributeRandomize", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc
index 52f97475941..ae034d152be 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc
@@ -28,15 +28,15 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_sample_texture_cc {
-static void geo_node_attribute_sample_texture_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Texture>("Texture").hide_label();
- b.add_input<decl::String>("Mapping");
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Texture>(N_("Texture")).hide_label();
+ b.add_input<decl::String>(N_("Mapping"));
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static AttributeDomain get_result_domain(const GeometryComponent &component,
@@ -82,7 +82,7 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
return;
}
- GVArray_Typed<float3> mapping_attribute = component.attribute_get_for_read<float3>(
+ VArray<float3> mapping_attribute = component.attribute_get_for_read<float3>(
mapping_name, result_domain, {0, 0, 0});
MutableSpan<ColorGeometry4f> colors = attribute_out.as_span();
@@ -100,11 +100,11 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
attribute_out.save();
}
-static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -119,19 +119,20 @@ static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_sample_texture_cc
void register_node_type_geo_sample_texture()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_sample_texture_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE,
"Attribute Sample Texture",
- NODE_CLASS_ATTRIBUTE,
- 0);
+ NODE_CLASS_ATTRIBUTE);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- ntype.declare = blender::nodes::geo_node_attribute_sample_texture_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_sample_texture_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
index de0090406c6..960ec540556 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
@@ -19,41 +19,38 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_separate_xyz_cc {
-static void geo_node_attribute_separate_xyz_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Vector");
- b.add_input<decl::Vector>("Vector", "Vector_001");
- b.add_input<decl::String>("Result X");
- b.add_input<decl::String>("Result Y");
- b.add_input<decl::String>("Result Z");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Vector"));
+ b.add_input<decl::Vector>(N_("Vector"), "Vector_001");
+ b.add_input<decl::String>(N_("Result X"));
+ b.add_input<decl::String>(N_("Result Y"));
+ b.add_input<decl::String>(N_("Result Z"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_separate_xyz_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "input_type", 0, IFACE_("Type"), ICON_NONE);
}
-static void geo_node_attribute_separate_xyz_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeSeparateXYZ *data = (NodeAttributeSeparateXYZ *)MEM_callocN(
- sizeof(NodeAttributeSeparateXYZ), __func__);
+ NodeAttributeSeparateXYZ *data = MEM_cnew<NodeAttributeSeparateXYZ>(__func__);
data->input_type = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
node->storage = data;
}
-static void geo_node_attribute_separate_xyz_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeSeparateXYZ *node_storage = (NodeAttributeSeparateXYZ *)node->storage;
update_attribute_input_socket_availabilities(
- *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type);
+ *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type);
}
static void extract_input(const int index, const Span<float3> &input, MutableSpan<float> result)
@@ -106,9 +103,9 @@ static void separate_attribute(GeometryComponent &component, const GeoNodeExecPa
const AttributeDomain result_domain = get_result_domain(
component, params, result_name_x, result_name_y, result_name_z);
- GVArray_Typed<float3> attribute_input = params.get_input_attribute<float3>(
+ VArray<float3> attribute_input = params.get_input_attribute<float3>(
"Vector", component, result_domain, {0, 0, 0});
- VArray_Span<float3> input_span{*attribute_input};
+ VArray_Span<float3> input_span{attribute_input};
OutputAttribute_Typed<float> attribute_result_x =
component.attribute_try_get_for_output_only<float>(result_name_x, result_domain);
@@ -132,11 +129,11 @@ static void separate_attribute(GeometryComponent &component, const GeoNodeExecPa
}
}
-static void geo_node_attribute_separate_xyz_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
separate_attribute(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -151,23 +148,24 @@ static void geo_node_attribute_separate_xyz_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_separate_xyz_cc
void register_node_type_geo_attribute_separate_xyz()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_separate_xyz_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ,
"Attribute Separate XYZ",
- NODE_CLASS_ATTRIBUTE,
- 0);
- ntype.declare = blender::nodes::geo_node_attribute_separate_xyz_declare;
- node_type_init(&ntype, blender::nodes::geo_node_attribute_separate_xyz_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_separate_xyz_update);
+ NODE_CLASS_ATTRIBUTE);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeAttributeSeparateXYZ", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_separate_xyz_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_separate_xyz_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc
index f187ee39b94..a85a7c56cb9 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc
@@ -29,20 +29,18 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_transfer_cc {
-static void geo_node_attribute_transfer_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Geometry>("Source Geometry");
- b.add_input<decl::String>("Source");
- b.add_input<decl::String>("Destination");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Geometry>(N_("Source Geometry"));
+ b.add_input<decl::String>(N_("Source"));
+ b.add_input<decl::String>(N_("Destination"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_transfer_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -50,10 +48,9 @@ static void geo_node_attribute_transfer_layout(uiLayout *layout,
uiItemR(layout, ptr, "mapping", 0, IFACE_("Mapping"), ICON_NONE);
}
-static void geo_node_attribute_transfer_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryAttributeTransfer *data = (NodeGeometryAttributeTransfer *)MEM_callocN(
- sizeof(NodeGeometryAttributeTransfer), __func__);
+ NodeGeometryAttributeTransfer *data = MEM_cnew<NodeGeometryAttributeTransfer>(__func__);
data->domain = ATTR_DOMAIN_AUTO;
node->storage = data;
}
@@ -232,7 +229,7 @@ static void get_closest_mesh_corners(const Mesh &mesh,
const MLoop &loop = mesh.mloop[loop_index];
const int vertex_index = loop.v;
const MVert &mvert = mesh.mvert[vertex_index];
- const float distance_sq = float3::distance_squared(position, mvert.co);
+ const float distance_sq = math::distance_squared(position, float3(mvert.co));
if (distance_sq < min_distance_sq) {
min_distance_sq = distance_sq;
closest_loop_index = loop_index;
@@ -284,7 +281,8 @@ static void transfer_attribute_nearest_face_interpolated(const GeometrySet &src_
Array<float3> positions(tot_samples);
get_closest_mesh_looptris(*mesh, dst_positions, looptri_indices, {}, positions);
- bke::mesh_surface_sample::MeshAttributeInterpolator interp(mesh, positions, looptri_indices);
+ bke::mesh_surface_sample::MeshAttributeInterpolator interp(
+ mesh, IndexMask(tot_samples), positions, looptri_indices);
interp.sample_attribute(
src_attribute, dst_attribute, bke::mesh_surface_sample::eAttributeMapMode::INTERPOLATED);
@@ -404,15 +402,15 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry,
data_type);
for (const int i : IndexRange(tot_samples)) {
if (pointcloud_distances_sq[i] < mesh_distances_sq[i]) {
- /* Point-cloud point is closer. */
+ /* Point cloud point is closer. */
const int index = pointcloud_indices[i];
- pointcloud_src_attribute.varray->get(index, buffer);
+ pointcloud_src_attribute.varray.get(index, buffer);
dst_attribute->set_by_relocate(i, buffer);
}
else {
/* Mesh element is closer. */
const int index = mesh_indices[i];
- mesh_src_attribute.varray->get(index, buffer);
+ mesh_src_attribute.varray.get(index, buffer);
dst_attribute->set_by_relocate(i, buffer);
}
}
@@ -423,7 +421,7 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry,
src_name, data_type);
for (const int i : IndexRange(tot_samples)) {
const int index = pointcloud_indices[i];
- src_attribute.varray->get(index, buffer);
+ src_attribute.varray.get(index, buffer);
dst_attribute->set_by_relocate(i, buffer);
}
}
@@ -433,7 +431,7 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry,
data_type);
for (const int i : IndexRange(tot_samples)) {
const int index = mesh_indices[i];
- src_attribute.varray->get(index, buffer);
+ src_attribute.varray.get(index, buffer);
dst_attribute->set_by_relocate(i, buffer);
}
}
@@ -459,16 +457,16 @@ static void transfer_attribute(const GeoNodeExecParams &params,
const AttributeDomain dst_domain = (input_domain == ATTR_DOMAIN_AUTO) ? auto_domain :
input_domain;
- GVArray_Typed<float3> dst_positions = dst_component.attribute_get_for_read<float3>(
+ VArray<float3> dst_positions = dst_component.attribute_get_for_read<float3>(
"position", dst_domain, {0, 0, 0});
switch (mapping) {
- case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED: {
+ case GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED: {
transfer_attribute_nearest_face_interpolated(
src_geometry, dst_component, dst_positions, dst_domain, data_type, src_name, dst_name);
break;
}
- case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST: {
+ case GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER_NEAREST: {
transfer_attribute_nearest(
src_geometry, dst_component, dst_positions, dst_domain, data_type, src_name, dst_name);
break;
@@ -476,7 +474,7 @@ static void transfer_attribute(const GeoNodeExecParams &params,
}
}
-static void geo_node_attribute_transfer_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet dst_geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet src_geometry_set = params.extract_input<GeometrySet>("Source Geometry");
@@ -484,12 +482,12 @@ static void geo_node_attribute_transfer_exec(GeoNodeExecParams params)
const std::string dst_attribute_name = params.extract_input<std::string>("Destination");
if (src_attribute_name.empty() || dst_attribute_name.empty()) {
- params.set_output("Geometry", dst_geometry_set);
+ params.set_default_remaining_outputs();
return;
}
- dst_geometry_set = bke::geometry_set_realize_instances(dst_geometry_set);
- src_geometry_set = bke::geometry_set_realize_instances(src_geometry_set);
+ dst_geometry_set = geometry::realize_instances_legacy(dst_geometry_set);
+ src_geometry_set = geometry::realize_instances_legacy(src_geometry_set);
if (dst_geometry_set.has<MeshComponent>()) {
transfer_attribute(params,
@@ -509,21 +507,23 @@ static void geo_node_attribute_transfer_exec(GeoNodeExecParams params)
params.set_output("Geometry", dst_geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_transfer_cc
-void register_node_type_geo_attribute_transfer()
+void register_node_type_geo_legacy_attribute_transfer()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_transfer_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, "Attribute Transfer", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_transfer_init);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, "Attribute Transfer", NODE_CLASS_ATTRIBUTE);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryAttributeTransfer",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_attribute_transfer_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_transfer_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_transfer_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc
index 59903050f88..5b3c3c05a6a 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc
@@ -26,21 +26,21 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_vector_math_cc {
-static void geo_node_attribute_vector_math_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("A");
- b.add_input<decl::Vector>("A", "A_001");
- b.add_input<decl::String>("B");
- b.add_input<decl::Vector>("B", "B_001");
- b.add_input<decl::Float>("B", "B_002");
- b.add_input<decl::String>("C");
- b.add_input<decl::Vector>("C", "C_001");
- b.add_input<decl::Float>("C", "C_002");
- b.add_input<decl::String>("Result");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("A"));
+ b.add_input<decl::Vector>(N_("A"), "A_001");
+ b.add_input<decl::String>(N_("B"));
+ b.add_input<decl::Vector>(N_("B"), "B_001");
+ b.add_input<decl::Float>(N_("B"), "B_002");
+ b.add_input<decl::String>(N_("C"));
+ b.add_input<decl::Vector>(N_("C"), "C_001");
+ b.add_input<decl::Float>(N_("C"), "C_002");
+ b.add_input<decl::String>(N_("Result"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static bool operation_use_input_b(const NodeVectorMathOperation operation)
@@ -66,9 +66,7 @@ static bool operation_use_input_c(const NodeVectorMathOperation operation)
NODE_VECTOR_MATH_MULTIPLY_ADD);
}
-static void geo_node_attribute_vector_math_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
const NodeAttributeVectorMath &node_storage = *(NodeAttributeVectorMath *)node->storage;
@@ -103,10 +101,9 @@ static CustomDataType operation_get_read_type_c(const NodeVectorMathOperation op
return CD_PROP_FLOAT3;
}
-static void geo_node_attribute_vector_math_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeVectorMath *data = (NodeAttributeVectorMath *)MEM_callocN(
- sizeof(NodeAttributeVectorMath), __func__);
+ NodeAttributeVectorMath *data = MEM_cnew<NodeAttributeVectorMath>(__func__);
data->operation = NODE_VECTOR_MATH_ADD;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
@@ -152,8 +149,8 @@ static CustomDataType operation_get_result_type(const NodeVectorMathOperation op
return CD_PROP_FLOAT3;
}
-static void geo_node_vector_math_label(bNodeTree *UNUSED(ntree),
- bNode *node,
+static void geo_node_vector_math_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
char *label,
int maxlen)
{
@@ -166,19 +163,21 @@ static void geo_node_vector_math_label(bNodeTree *UNUSED(ntree),
BLI_snprintf(label, maxlen, IFACE_("Vector %s"), IFACE_(name));
}
-static void geo_node_attribute_vector_math_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeAttributeVectorMath *node_storage = (NodeAttributeVectorMath *)node->storage;
const NodeVectorMathOperation operation = (const NodeVectorMathOperation)node_storage->operation;
update_attribute_input_socket_availabilities(
- *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
+ *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
update_attribute_input_socket_availabilities(
+ *ntree,
*node,
"B",
(GeometryNodeAttributeInputMode)node_storage->input_type_b,
operation_use_input_b(operation));
update_attribute_input_socket_availabilities(
+ *ntree,
*node,
"C",
(GeometryNodeAttributeInputMode)node_storage->input_type_c,
@@ -187,7 +186,7 @@ static void geo_node_attribute_vector_math_update(bNodeTree *UNUSED(ntree), bNod
static void do_math_operation_fl3_fl3_to_fl3(const VArray<float3> &input_a,
const VArray<float3> &input_b,
- VMutableArray<float3> &result,
+ const VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
@@ -218,7 +217,7 @@ static void do_math_operation_fl3_fl3_to_fl3(const VArray<float3> &input_a,
static void do_math_operation_fl3_fl3_fl3_to_fl3(const VArray<float3> &input_a,
const VArray<float3> &input_b,
const VArray<float3> &input_c,
- VMutableArray<float3> &result,
+ const VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
@@ -251,7 +250,7 @@ static void do_math_operation_fl3_fl3_fl3_to_fl3(const VArray<float3> &input_a,
static void do_math_operation_fl3_fl3_fl_to_fl3(const VArray<float3> &input_a,
const VArray<float3> &input_b,
const VArray<float> &input_c,
- VMutableArray<float3> &result,
+ const VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
@@ -283,7 +282,7 @@ static void do_math_operation_fl3_fl3_fl_to_fl3(const VArray<float3> &input_a,
static void do_math_operation_fl3_fl3_to_fl(const VArray<float3> &input_a,
const VArray<float3> &input_b,
- VMutableArray<float> &result,
+ const VMutableArray<float> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
@@ -313,7 +312,7 @@ static void do_math_operation_fl3_fl3_to_fl(const VArray<float3> &input_a,
static void do_math_operation_fl3_fl_to_fl3(const VArray<float3> &input_a,
const VArray<float> &input_b,
- VMutableArray<float3> &result,
+ const VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
@@ -342,7 +341,7 @@ static void do_math_operation_fl3_fl_to_fl3(const VArray<float3> &input_a,
}
static void do_math_operation_fl3_to_fl3(const VArray<float3> &input_a,
- VMutableArray<float3> &result,
+ const VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
@@ -369,7 +368,7 @@ static void do_math_operation_fl3_to_fl3(const VArray<float3> &input_a,
}
static void do_math_operation_fl3_to_fl(const VArray<float3> &input_a,
- VMutableArray<float> &result,
+ const VMutableArray<float> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
@@ -437,13 +436,13 @@ static void attribute_vector_math_calc(GeometryComponent &component,
const AttributeDomain result_domain = get_result_domain(
component, params, operation, result_name);
- GVArrayPtr attribute_a = params.get_input_attribute(
+ GVArray attribute_a = params.get_input_attribute(
"A", component, result_domain, read_type_a, nullptr);
if (!attribute_a) {
return;
}
- GVArrayPtr attribute_b;
- GVArrayPtr attribute_c;
+ GVArray attribute_b;
+ GVArray attribute_c;
if (use_input_b) {
attribute_b = params.get_input_attribute("B", component, result_domain, read_type_b, nullptr);
if (!attribute_b) {
@@ -476,26 +475,26 @@ static void attribute_vector_math_calc(GeometryComponent &component,
case NODE_VECTOR_MATH_MODULO:
case NODE_VECTOR_MATH_MINIMUM:
case NODE_VECTOR_MATH_MAXIMUM:
- do_math_operation_fl3_fl3_to_fl3(attribute_a->typed<float3>(),
- attribute_b->typed<float3>(),
- attribute_result->typed<float3>(),
+ do_math_operation_fl3_fl3_to_fl3(attribute_a.typed<float3>(),
+ attribute_b.typed<float3>(),
+ attribute_result.varray().typed<float3>(),
operation);
break;
case NODE_VECTOR_MATH_DOT_PRODUCT:
case NODE_VECTOR_MATH_DISTANCE:
- do_math_operation_fl3_fl3_to_fl(attribute_a->typed<float3>(),
- attribute_b->typed<float3>(),
- attribute_result->typed<float>(),
+ do_math_operation_fl3_fl3_to_fl(attribute_a.typed<float3>(),
+ attribute_b.typed<float3>(),
+ attribute_result.varray().typed<float>(),
operation);
break;
case NODE_VECTOR_MATH_LENGTH:
do_math_operation_fl3_to_fl(
- attribute_a->typed<float3>(), attribute_result->typed<float>(), operation);
+ attribute_a.typed<float3>(), attribute_result.varray().typed<float>(), operation);
break;
case NODE_VECTOR_MATH_SCALE:
- do_math_operation_fl3_fl_to_fl3(attribute_a->typed<float3>(),
- attribute_b->typed<float>(),
- attribute_result->typed<float3>(),
+ do_math_operation_fl3_fl_to_fl3(attribute_a.typed<float3>(),
+ attribute_b.typed<float>(),
+ attribute_result.varray().typed<float3>(),
operation);
break;
case NODE_VECTOR_MATH_NORMALIZE:
@@ -507,33 +506,33 @@ static void attribute_vector_math_calc(GeometryComponent &component,
case NODE_VECTOR_MATH_COSINE:
case NODE_VECTOR_MATH_TANGENT:
do_math_operation_fl3_to_fl3(
- attribute_a->typed<float3>(), attribute_result->typed<float3>(), operation);
+ attribute_a.typed<float3>(), attribute_result.varray().typed<float3>(), operation);
break;
case NODE_VECTOR_MATH_WRAP:
case NODE_VECTOR_MATH_FACEFORWARD:
case NODE_VECTOR_MATH_MULTIPLY_ADD:
- do_math_operation_fl3_fl3_fl3_to_fl3(attribute_a->typed<float3>(),
- attribute_b->typed<float3>(),
- attribute_c->typed<float3>(),
- attribute_result->typed<float3>(),
+ do_math_operation_fl3_fl3_fl3_to_fl3(attribute_a.typed<float3>(),
+ attribute_b.typed<float3>(),
+ attribute_c.typed<float3>(),
+ attribute_result.varray().typed<float3>(),
operation);
break;
case NODE_VECTOR_MATH_REFRACT:
- do_math_operation_fl3_fl3_fl_to_fl3(attribute_a->typed<float3>(),
- attribute_b->typed<float3>(),
- attribute_c->typed<float>(),
- attribute_result->typed<float3>(),
+ do_math_operation_fl3_fl3_fl_to_fl3(attribute_a.typed<float3>(),
+ attribute_b.typed<float3>(),
+ attribute_c.typed<float>(),
+ attribute_result.varray().typed<float3>(),
operation);
break;
}
attribute_result.save();
}
-static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
attribute_vector_math_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -549,23 +548,24 @@ static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_vector_math_cc
void register_node_type_geo_attribute_vector_math()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_vector_math_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_MATH,
"Attribute Vector Math",
- NODE_CLASS_ATTRIBUTE,
- 0);
- ntype.declare = blender::nodes::geo_node_attribute_vector_math_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_vector_math_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_vector_math_layout;
- node_type_label(&ntype, blender::nodes::geo_node_vector_math_label);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_vector_math_update);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_vector_math_init);
+ NODE_CLASS_ATTRIBUTE);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.labelfunc = file_ns::geo_node_vector_math_label;
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeAttributeVectorMath", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
index 0c515fa63fb..3738c4ad14d 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
@@ -21,30 +21,28 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_vector_rotate_cc {
-static void geo_node_attribute_vector_rotate_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Vector");
- b.add_input<decl::Vector>("Vector", "Vector_001").min(0.0f).max(1.0f).hide_value();
- b.add_input<decl::String>("Center");
- b.add_input<decl::Vector>("Center", "Center_001").subtype(PROP_XYZ);
- b.add_input<decl::String>("Axis");
- b.add_input<decl::Vector>("Axis", "Axis_001").min(-1.0f).max(1.0f).subtype(PROP_XYZ);
- b.add_input<decl::String>("Angle");
- b.add_input<decl::Float>("Angle", "Angle_001").subtype(PROP_ANGLE);
- b.add_input<decl::String>("Rotation");
- b.add_input<decl::Vector>("Rotation", "Rotation_001").subtype(PROP_EULER);
- b.add_input<decl::Bool>("Invert");
- b.add_input<decl::String>("Result");
-
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Vector"));
+ b.add_input<decl::Vector>(N_("Vector"), "Vector_001").min(0.0f).max(1.0f).hide_value();
+ b.add_input<decl::String>(N_("Center"));
+ b.add_input<decl::Vector>(N_("Center"), "Center_001").subtype(PROP_XYZ);
+ b.add_input<decl::String>(N_("Axis"));
+ b.add_input<decl::Vector>(N_("Axis"), "Axis_001").min(-1.0f).max(1.0f).subtype(PROP_XYZ);
+ b.add_input<decl::String>(N_("Angle"));
+ b.add_input<decl::Float>(N_("Angle"), "Angle_001").subtype(PROP_ANGLE);
+ b.add_input<decl::String>(N_("Rotation"));
+ b.add_input<decl::Vector>(N_("Rotation"), "Rotation_001").subtype(PROP_EULER);
+ b.add_input<decl::Bool>(N_("Invert"));
+ b.add_input<decl::String>(N_("Result"));
+
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_vector_rotate_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
const NodeAttributeVectorRotate &node_storage = *(NodeAttributeVectorRotate *)node->storage;
@@ -70,27 +68,30 @@ static void geo_node_attribute_vector_rotate_layout(uiLayout *layout,
}
}
-static void geo_node_attribute_vector_rotate_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)node->storage;
const GeometryNodeAttributeVectorRotateMode mode = (const GeometryNodeAttributeVectorRotateMode)
node_storage->mode;
update_attribute_input_socket_availabilities(
- *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector);
+ *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector);
update_attribute_input_socket_availabilities(
- *node, "Center", (GeometryNodeAttributeInputMode)node_storage->input_type_center);
+ *ntree, *node, "Center", (GeometryNodeAttributeInputMode)node_storage->input_type_center);
update_attribute_input_socket_availabilities(
+ *ntree,
*node,
"Axis",
(GeometryNodeAttributeInputMode)node_storage->input_type_axis,
(mode == GEO_NODE_VECTOR_ROTATE_TYPE_AXIS));
update_attribute_input_socket_availabilities(
+ *ntree,
*node,
"Angle",
(GeometryNodeAttributeInputMode)node_storage->input_type_angle,
(mode != GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
update_attribute_input_socket_availabilities(
+ *ntree,
*node,
"Rotation",
(GeometryNodeAttributeInputMode)node_storage->input_type_rotation,
@@ -109,10 +110,9 @@ static float3 vector_rotate_around_axis(const float3 vector,
return result + center;
}
-static void geo_node_attribute_vector_rotate_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)MEM_callocN(
- sizeof(NodeAttributeVectorRotate), __func__);
+ NodeAttributeVectorRotate *node_storage = MEM_cnew<NodeAttributeVectorRotate>(__func__);
node_storage->mode = GEO_NODE_VECTOR_ROTATE_TYPE_AXIS;
node_storage->input_type_vector = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
@@ -220,12 +220,12 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
const AttributeDomain result_domain = get_result_domain(component, params, result_name);
const bool invert = params.get_input<bool>("Invert");
- GVArrayPtr attribute_vector = params.get_input_attribute(
+ GVArray attribute_vector = params.get_input_attribute(
"Vector", component, result_domain, CD_PROP_FLOAT3, nullptr);
if (!attribute_vector) {
return;
}
- GVArrayPtr attribute_center = params.get_input_attribute(
+ GVArray attribute_center = params.get_input_attribute(
"Center", component, result_domain, CD_PROP_FLOAT3, nullptr);
if (!attribute_center) {
return;
@@ -238,21 +238,21 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
}
if (mode == GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) {
- GVArrayPtr attribute_rotation = params.get_input_attribute(
+ GVArray attribute_rotation = params.get_input_attribute(
"Rotation", component, result_domain, CD_PROP_FLOAT3, nullptr);
if (!attribute_rotation) {
return;
}
- do_vector_rotate_euler(attribute_vector->typed<float3>(),
- attribute_center->typed<float3>(),
- attribute_rotation->typed<float3>(),
+ do_vector_rotate_euler(attribute_vector.typed<float3>(),
+ attribute_center.typed<float3>(),
+ attribute_rotation.typed<float3>(),
attribute_result.as_span<float3>(),
invert);
attribute_result.save();
return;
}
- GVArrayPtr attribute_angle = params.get_input_attribute(
+ GVArray attribute_angle = params.get_input_attribute(
"Angle", component, result_domain, CD_PROP_FLOAT, nullptr);
if (!attribute_angle) {
return;
@@ -260,40 +260,40 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
switch (mode) {
case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS: {
- GVArrayPtr attribute_axis = params.get_input_attribute(
+ GVArray attribute_axis = params.get_input_attribute(
"Axis", component, result_domain, CD_PROP_FLOAT3, nullptr);
if (!attribute_axis) {
return;
}
- do_vector_rotate_around_axis(attribute_vector->typed<float3>(),
- attribute_center->typed<float3>(),
- attribute_axis->typed<float3>(),
- attribute_angle->typed<float>(),
+ do_vector_rotate_around_axis(attribute_vector.typed<float3>(),
+ attribute_center.typed<float3>(),
+ attribute_axis.typed<float3>(),
+ attribute_angle.typed<float>(),
attribute_result.as_span<float3>(),
invert);
} break;
case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_X:
- do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(),
- attribute_center->typed<float3>(),
+ do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(),
+ attribute_center.typed<float3>(),
float3(1.0f, 0.0f, 0.0f),
- attribute_angle->typed<float>(),
+ attribute_angle.typed<float>(),
attribute_result.as_span<float3>(),
invert);
break;
case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Y:
- do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(),
- attribute_center->typed<float3>(),
+ do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(),
+ attribute_center.typed<float3>(),
float3(0.0f, 1.0f, 0.0f),
- attribute_angle->typed<float>(),
+ attribute_angle.typed<float>(),
attribute_result.as_span<float3>(),
invert);
break;
case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Z:
- do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(),
- attribute_center->typed<float3>(),
+ do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(),
+ attribute_center.typed<float3>(),
float3(0.0f, 0.0f, 1.0f),
- attribute_angle->typed<float>(),
+ attribute_angle.typed<float>(),
attribute_result.as_span<float3>(),
invert);
@@ -306,11 +306,11 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
attribute_result.save();
}
-static void geo_node_attribute_vector_rotate_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -325,24 +325,25 @@ static void geo_node_attribute_vector_rotate_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_vector_rotate_cc
void register_node_type_geo_attribute_vector_rotate()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_vector_rotate_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_ROTATE,
"Attribute Vector Rotate",
- NODE_CLASS_ATTRIBUTE,
- 0);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_vector_rotate_update);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_vector_rotate_init);
+ NODE_CLASS_ATTRIBUTE);
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_size(&ntype, 165, 100, 600);
node_type_storage(
&ntype, "NodeAttributeVectorRotate", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_vector_rotate_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_vector_rotate_layout;
- ntype.declare = blender::nodes::geo_node_attribute_vector_rotate_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
index 65d22eca39c..51564d8d200 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
@@ -25,13 +25,13 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_endpoints_cc {
-static void geo_node_curve_endpoints_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_output<decl::Geometry>("Start Points");
- b.add_output<decl::Geometry>("End Points");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_output<decl::Geometry>(N_("Start Points"));
+ b.add_output<decl::Geometry>(N_("End Points"));
}
/**
@@ -61,7 +61,7 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component,
if (meta_data.domain != ATTR_DOMAIN_CURVE) {
return true;
}
- GVArrayPtr spline_attribute = curve_component.attribute_get_for_read(
+ GVArray spline_attribute = curve_component.attribute_get_for_read(
attribute_id, ATTR_DOMAIN_CURVE, meta_data.data_type);
OutputAttribute result_attribute = points.attribute_try_get_for_output_only(
@@ -70,7 +70,7 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component,
/* Only copy the attributes of splines in the offsets. */
for (const int i : offsets.index_range()) {
- spline_attribute->get(offsets[i], result[i]);
+ spline_attribute.get(offsets[i], result[i]);
}
result_attribute.save();
@@ -124,36 +124,35 @@ static void copy_endpoint_attributes(Span<SplinePtr> splines,
end_data.tilts[i] = spline.tilts().last();
/* Copy the point attribute data over. */
- for (const auto &item : start_data.point_attributes.items()) {
+ for (const auto item : start_data.point_attributes.items()) {
const AttributeIDRef attribute_id = item.key;
GMutableSpan point_span = item.value;
BLI_assert(spline.attributes.get_for_read(attribute_id));
GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
- blender::fn::GVArray_For_GSpan(spline_span).get(0, point_span[i]);
+ spline_span.type().copy_assign(spline_span[0], point_span[i]);
}
- for (const auto &item : end_data.point_attributes.items()) {
+ for (const auto item : end_data.point_attributes.items()) {
const AttributeIDRef attribute_id = item.key;
GMutableSpan point_span = item.value;
BLI_assert(spline.attributes.get_for_read(attribute_id));
GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
- blender::fn::GVArray_For_GSpan(spline_span).get(spline.size() - 1, point_span[i]);
+ spline_span.type().copy_assign(spline_span[spline.size() - 1], point_span[i]);
}
}
});
}
-static void geo_node_curve_endpoints_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
- params.set_output("Start Points", GeometrySet());
- params.set_output("End Points", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -168,8 +167,7 @@ static void geo_node_curve_endpoints_exec(GeoNodeExecParams params)
const int total_size = offsets.size();
if (total_size == 0) {
- params.set_output("Start Points", GeometrySet());
- params.set_output("End Points", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -206,16 +204,18 @@ static void geo_node_curve_endpoints_exec(GeoNodeExecParams params)
params.set_output("End Points", std::move(end_result));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_endpoints_cc
-void register_node_type_geo_curve_endpoints()
+void register_node_type_geo_legacy_curve_endpoints()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_endpoints_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_endpoints_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_endpoints_exec;
+ &ntype, GEO_NODE_LEGACY_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
index d1c81333c30..844baa53962 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
@@ -20,19 +20,19 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_reverse_cc {
-static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::String>("Selection");
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Geometry>(N_("Curve"));
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Curve", geometry_set);
return;
@@ -44,7 +44,7 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
MutableSpan<SplinePtr> splines = curve.splines();
const std::string selection_name = params.extract_input<std::string>("Selection");
- GVArray_Typed<bool> selection = curve_component.attribute_get_for_read(
+ VArray<bool> selection = curve_component.attribute_get_for_read(
selection_name, ATTR_DOMAIN_CURVE, true);
threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
@@ -58,14 +58,15 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
params.set_output("Curve", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_reverse_cc
void register_node_type_geo_legacy_curve_reverse()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_reverse_cc;
+
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_reverse_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_reverse_exec;
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
index dfcae2e65b0..780756bcbca 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
@@ -23,27 +23,24 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc {
-static void geo_node_select_by_handle_type_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Selection");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_curve_select_by_handle_type_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
}
-static void geo_node_curve_select_by_handle_type_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN(
- sizeof(NodeGeometryCurveSelectHandles), __func__);
+ NodeGeometryCurveSelectHandles *data = MEM_cnew<NodeGeometryCurveSelectHandles>(__func__);
data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
@@ -94,7 +91,7 @@ static void select_curve_by_handle_type(const CurveEval &curve,
});
}
-static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSelectHandles *storage =
(const NodeGeometryCurveSelectHandles *)params.node().storage;
@@ -103,7 +100,7 @@ static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params)
const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage->mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
const CurveEval *curve = curve_component.get_for_read();
@@ -121,25 +118,24 @@ static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc
-void register_node_type_geo_select_by_handle_type()
+void register_node_type_geo_legacy_select_by_handle_type()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype,
- GEO_NODE_LEGACY_CURVE_SELECT_HANDLES,
- "Select by Handle Type",
- NODE_CLASS_GEOMETRY,
- 0);
- ntype.declare = blender::nodes::geo_node_select_by_handle_type_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_select_by_handle_type_exec;
- node_type_init(&ntype, blender::nodes::geo_node_curve_select_by_handle_type_init);
+ geo_node_type_base(
+ &ntype, GEO_NODE_LEGACY_CURVE_SELECT_HANDLES, "Select by Handle Type", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSelectHandles",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_select_by_handle_type_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
index 31c13134f79..a82b917e817 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
@@ -21,27 +21,24 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_set_handles_cc {
-static void geo_node_curve_set_handles_decalre(NodeDeclarationBuilder &b)
+static void node_decalre(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::String>("Selection");
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Geometry>(N_("Curve"));
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_set_handles_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
}
-static void geo_node_curve_set_handles_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN(
- sizeof(NodeGeometryCurveSetHandles), __func__);
+ NodeGeometryCurveSetHandles *data = MEM_cnew<NodeGeometryCurveSetHandles>(__func__);
data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
@@ -64,7 +61,7 @@ static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHan
return BezierSpline::HandleType::Auto;
}
-static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSetHandles *node_storage =
(NodeGeometryCurveSetHandles *)params.node().storage;
@@ -72,7 +69,7 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)node_storage->mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Curve", geometry_set);
return;
@@ -84,7 +81,7 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
MutableSpan<SplinePtr> splines = curve.splines();
const std::string selection_name = params.extract_input<std::string>("Selection");
- GVArray_Typed<bool> selection = curve_component.attribute_get_for_read(
+ VArray<bool> selection = curve_component.attribute_get_for_read(
selection_name, ATTR_DOMAIN_POINT, true);
const BezierSpline::HandleType new_handle_type = handle_type_from_input_type(type);
@@ -124,21 +121,23 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
params.set_output("Curve", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_set_handles_cc
-void register_node_type_geo_curve_set_handles()
+void register_node_type_geo_legacy_curve_set_handles()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_set_handles_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_set_handles_decalre;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_set_handles_exec;
- node_type_init(&ntype, blender::nodes::geo_node_curve_set_handles_init);
+ &ntype, GEO_NODE_LEGACY_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_decalre;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSetHandles",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_set_handles_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
index 0ef107fd8a4..6fd82e6a1bb 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
@@ -23,26 +23,23 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_spline_type_cc {
-static void geo_node_curve_spline_type_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::String>("Selection");
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Geometry>(N_("Curve"));
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_spline_type_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE);
}
-static void geo_node_curve_spline_type_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN(
- sizeof(NodeGeometryCurveSplineType), __func__);
+ NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__);
data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
node->storage = data;
@@ -238,14 +235,14 @@ static SplinePtr convert_to_nurbs(const Spline &input)
return {};
}
-static void geo_node_curve_spline_type_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSplineType *storage =
(const NodeGeometryCurveSplineType *)params.node().storage;
const GeometryNodeSplineType output_type = (const GeometryNodeSplineType)storage->spline_type;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Curve", geometry_set);
return;
@@ -255,7 +252,7 @@ static void geo_node_curve_spline_type_exec(GeoNodeExecParams params)
const CurveEval &curve = *curve_component->get_for_read();
const std::string selection_name = params.extract_input<std::string>("Selection");
- GVArray_Typed<bool> selection = curve_component->attribute_get_for_read(
+ VArray<bool> selection = curve_component->attribute_get_for_read(
selection_name, ATTR_DOMAIN_CURVE, true);
std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
@@ -282,21 +279,23 @@ static void geo_node_curve_spline_type_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(new_curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_spline_type_cc
-void register_node_type_geo_curve_spline_type()
+void register_node_type_geo_legacy_curve_spline_type()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_spline_type_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_spline_type_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_spline_type_exec;
- node_type_init(&ntype, blender::nodes::geo_node_curve_spline_type_init);
+ &ntype, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSplineType",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_spline_type_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
index 0522f2b8981..4621a1656aa 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
@@ -25,42 +25,37 @@
#include "node_geometry_util.hh"
-using blender::fn::GVArray_For_GSpan;
-using blender::fn::GVArray_For_Span;
-using blender::fn::GVArray_Typed;
+namespace blender::nodes::node_geo_legacy_curve_subdivide_cc {
-namespace blender::nodes {
-
-static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Cuts");
- b.add_input<decl::Int>("Cuts", "Cuts_001").default_value(1).min(0).max(1000);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Cuts"));
+ b.add_input<decl::Int>(N_("Cuts"), "Cuts_001").default_value(1).min(0).max(1000);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_curve_subdivide_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "cuts_type", 0, IFACE_("Cuts"), ICON_NONE);
}
-static void geo_node_curve_subdivide_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSubdivide *data = (NodeGeometryCurveSubdivide *)MEM_callocN(
- sizeof(NodeGeometryCurveSubdivide), __func__);
+ NodeGeometryCurveSubdivide *data = MEM_cnew<NodeGeometryCurveSubdivide>(__func__);
data->cuts_type = GEO_NODE_ATTRIBUTE_INPUT_INTEGER;
node->storage = data;
}
-static void geo_node_curve_subdivide_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage;
update_attribute_input_socket_availabilities(
- *node, "Cuts", (GeometryNodeAttributeInputMode)node_storage.input_type);
+ *ntree, *node, "Cuts", (GeometryNodeAttributeInputMode)node_storage.input_type);
}
static Array<int> get_subdivided_offsets(const Spline &spline,
@@ -308,8 +303,12 @@ static SplinePtr subdivide_spline(const Spline &spline,
const VArray<int> &cuts,
const int spline_offset)
{
- /* Since we expect to access each value many times, it should be worth it to make sure the
- * attribute is a real span (especially considering the note below). Using the offset at each
+ if (spline.size() <= 1) {
+ return spline.copy();
+ }
+
+ /* Since we expect to access each value many times, it should be worth it to make sure count
+ * of cuts is a real span (especially considering the note below). Using the offset at each
* point facilitates subdividing in parallel later. */
Array<int> offsets = get_subdivided_offsets(spline, cuts, spline_offset);
const int result_size = offsets.last() + int(!spline.is_cyclic());
@@ -347,11 +346,11 @@ static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve,
return output_curve;
}
-static void geo_node_subdivide_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Geometry", geometry_set);
@@ -359,34 +358,35 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params)
}
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
- GVArray_Typed<int> cuts = params.get_input_attribute<int>(
- "Cuts", component, ATTR_DOMAIN_POINT, 0);
- if (cuts->is_single() && cuts->get_internal_single() < 1) {
+ VArray<int> cuts = params.get_input_attribute<int>("Cuts", component, ATTR_DOMAIN_POINT, 0);
+ if (cuts.is_single() && cuts.get_internal_single() < 1) {
params.set_output("Geometry", geometry_set);
return;
}
- std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), *cuts);
+ std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), cuts);
params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_subdivide_cc
-void register_node_type_geo_curve_subdivide()
+void register_node_type_geo_legacy_curve_subdivide()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_subdivide_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, "Curve Subdivide", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_subdivide_declare;
- ntype.draw_buttons = blender::nodes::geo_node_curve_subdivide_layout;
+ &ntype, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, "Curve Subdivide", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(&ntype,
"NodeGeometryCurveSubdivide",
node_free_standard_storage,
node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_curve_subdivide_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_subdivide_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
index 0c435d69991..1e6b7f92a77 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
@@ -28,29 +28,80 @@
namespace blender::nodes {
-static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b)
+static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points,
+ const AttributeIDRef &attribute_id,
+ const CustomDataType data_type)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Int>("Count").default_value(10).min(2).max(100000);
- b.add_input<decl::Float>("Length").default_value(0.1f).min(0.001f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Geometry");
+ points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault());
+ WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id);
+ BLI_assert(attribute);
+ return attribute.varray.get_internal_span();
}
-static void geo_node_curve_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+template<typename T>
+static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points,
+ const AttributeIDRef &attribute_id)
+{
+ GMutableSpan attribute = create_attribute_and_retrieve_span(
+ points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>()));
+ return attribute.typed<T>();
+}
+
+CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points,
+ const CurveEval &curve)
+{
+ CurveToPointsResults attributes;
+
+ attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT);
+
+ attributes.positions = create_attribute_and_retrieve_span<float3>(points, "position");
+ attributes.radii = create_attribute_and_retrieve_span<float>(points, "radius");
+ attributes.tilts = create_attribute_and_retrieve_span<float>(points, "tilt");
+
+ /* Because of the invariants of the curve component, we use the attributes of the
+ * first spline as a representative for the attribute meta data all splines. */
+ curve.splines().first()->attributes.foreach_attribute(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ attributes.point_attributes.add_new(
+ attribute_id,
+ create_attribute_and_retrieve_span(points, attribute_id, meta_data.data_type));
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+
+ attributes.tangents = create_attribute_and_retrieve_span<float3>(points, "tangent");
+ attributes.normals = create_attribute_and_retrieve_span<float3>(points, "normal");
+ attributes.rotations = create_attribute_and_retrieve_span<float3>(points, "rotation");
+
+ return attributes;
+}
+
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_legacy_curve_to_points_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Int>(N_("Count")).default_value(10).min(2).max(100000);
+ b.add_input<decl::Float>(N_("Length")).default_value(0.1f).min(0.001f).subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN(
- sizeof(NodeGeometryCurveToPoints), __func__);
+ NodeGeometryCurveToPoints *data = MEM_cnew<NodeGeometryCurveToPoints>(__func__);
data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT;
node->storage = data;
}
-static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage;
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
@@ -58,8 +109,8 @@ static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *nod
bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *length_socket = count_socket->next;
- nodeSetSocketAvailability(count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT);
- nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH);
+ nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT);
+ nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH);
}
/**
@@ -114,54 +165,6 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
return {0};
}
-static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points,
- const AttributeIDRef &attribute_id,
- const CustomDataType data_type)
-{
- points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault());
- WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id);
- BLI_assert(attribute);
- return attribute.varray->get_internal_span();
-}
-
-template<typename T>
-static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points,
- const AttributeIDRef &attribute_id)
-{
- GMutableSpan attribute = create_attribute_and_retrieve_span(
- points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>()));
- return attribute.typed<T>();
-}
-
-CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points,
- const CurveEval &curve)
-{
- CurveToPointsResults attributes;
-
- attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT);
-
- attributes.positions = create_attribute_and_retrieve_span<float3>(points, "position");
- attributes.radii = create_attribute_and_retrieve_span<float>(points, "radius");
- attributes.tilts = create_attribute_and_retrieve_span<float>(points, "tilt");
-
- /* Because of the invariants of the curve component, we use the attributes of the
- * first spline as a representative for the attribute meta data all splines. */
- curve.splines().first()->attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- attributes.point_attributes.add_new(
- attribute_id,
- create_attribute_and_retrieve_span(points, attribute_id, meta_data.data_type));
- return true;
- },
- ATTR_DOMAIN_POINT);
-
- attributes.tangents = create_attribute_and_retrieve_span<float3>(points, "tangent");
- attributes.normals = create_attribute_and_retrieve_span<float3>(points, "normal");
- attributes.rotations = create_attribute_and_retrieve_span<float3>(points, "rotation");
-
- return attributes;
-}
-
/**
* TODO: For non-poly splines, this has double copies that could be avoided as part
* of a general look at optimizing uses of #Spline::interpolate_to_evaluated.
@@ -177,10 +180,10 @@ static void copy_evaluated_point_attributes(Span<SplinePtr> splines,
const int size = offsets[i + 1] - offsets[i];
data.positions.slice(offset, size).copy_from(spline.evaluated_positions());
- spline.interpolate_to_evaluated(spline.radii())->materialize(data.radii.slice(offset, size));
- spline.interpolate_to_evaluated(spline.tilts())->materialize(data.tilts.slice(offset, size));
+ spline.interpolate_to_evaluated(spline.radii()).materialize(data.radii.slice(offset, size));
+ spline.interpolate_to_evaluated(spline.tilts()).materialize(data.tilts.slice(offset, size));
- for (const Map<AttributeIDRef, GMutableSpan>::Item &item : data.point_attributes.items()) {
+ for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) {
const AttributeIDRef attribute_id = item.key;
GMutableSpan point_span = item.value;
@@ -188,7 +191,7 @@ static void copy_evaluated_point_attributes(Span<SplinePtr> splines,
GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
spline.interpolate_to_evaluated(spline_span)
- ->materialize(point_span.slice(offset, size).data());
+ .materialize(point_span.slice(offset, size).data());
}
data.tangents.slice(offset, size).copy_from(spline.evaluated_tangents());
@@ -223,14 +226,14 @@ static void copy_uniform_sample_point_attributes(Span<SplinePtr> splines,
uniform_samples,
data.tilts.slice(offset, size));
- for (const Map<AttributeIDRef, GMutableSpan>::Item &item : data.point_attributes.items()) {
+ for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) {
const AttributeIDRef attribute_id = item.key;
GMutableSpan point_span = item.value;
BLI_assert(spline.attributes.get_for_read(attribute_id));
GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
- spline.sample_with_index_factors(*spline.interpolate_to_evaluated(spline_span),
+ spline.sample_with_index_factors(spline.interpolate_to_evaluated(spline_span),
uniform_samples,
point_span.slice(offset, size));
}
@@ -238,13 +241,13 @@ static void copy_uniform_sample_point_attributes(Span<SplinePtr> splines,
spline.sample_with_index_factors<float3>(
spline.evaluated_tangents(), uniform_samples, data.tangents.slice(offset, size));
for (float3 &tangent : data.tangents) {
- tangent.normalize();
+ tangent = math::normalize(tangent);
}
spline.sample_with_index_factors<float3>(
spline.evaluated_normals(), uniform_samples, data.normals.slice(offset, size));
for (float3 &normals : data.normals) {
- normals.normalize();
+ normals = math::normalize(normals);
}
}
});
@@ -263,20 +266,20 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component,
if (meta_data.domain != ATTR_DOMAIN_CURVE) {
return true;
}
- GVArrayPtr spline_attribute = curve_component.attribute_get_for_read(
+ GVArray spline_attribute = curve_component.attribute_get_for_read(
attribute_id, ATTR_DOMAIN_CURVE, meta_data.data_type);
- const CPPType &type = spline_attribute->type();
+ const CPPType &type = spline_attribute.type();
OutputAttribute result_attribute = points.attribute_try_get_for_output_only(
attribute_id, ATTR_DOMAIN_POINT, meta_data.data_type);
GMutableSpan result = result_attribute.as_span();
- for (const int i : IndexRange(spline_attribute->size())) {
+ for (const int i : spline_attribute.index_range()) {
const int offset = offsets[i];
const int size = offsets[i + 1] - offsets[i];
if (size != 0) {
BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
- spline_attribute->get(i, buffer);
+ spline_attribute.get(i, buffer);
type.fill_assign_n(buffer, result[offset], size);
}
}
@@ -286,25 +289,13 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component,
});
}
-void curve_create_default_rotation_attribute(Span<float3> tangents,
- Span<float3> normals,
- MutableSpan<float3> rotations)
-{
- threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) {
- for (const int i : range) {
- rotations[i] =
- float4x4::from_normalized_axis_data({0, 0, 0}, normals[i], tangents[i]).to_euler();
- }
- });
-}
-
-static void geo_node_curve_to_points_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)params.node().storage;
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Geometry", GeometrySet());
@@ -352,21 +343,23 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(result));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_to_points_cc
-void register_node_type_geo_curve_to_points()
+void register_node_type_geo_legacy_curve_to_points()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_to_points_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_to_points_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_points_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_to_points_layout;
+ &ntype, GEO_NODE_LEGACY_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryCurveToPoints", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_curve_to_points_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_to_points_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
index 1e2f652cd78..f7fd12d775a 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
@@ -26,31 +26,16 @@
#include "node_geometry_util.hh"
-using blender::bke::CustomDataAttributes;
-
-/* Code from the mask modifier in MOD_mask.cc. */
-extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map);
-extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map,
- blender::Span<int> edge_map);
-extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map,
- blender::Span<int> edge_map,
- blender::Span<int> masked_poly_indices,
- blender::Span<int> new_loop_starts);
+namespace blender::nodes::node_geo_legacy_delete_geometry_cc {
-namespace blender::nodes {
+using blender::bke::CustomDataAttributes;
-static void geo_node_delete_geometry_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Selection");
- b.add_input<decl::Bool>("Invert");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_input<decl::Bool>(N_("Invert"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
template<typename T> static void copy_data(Span<T> data, MutableSpan<T> r_data, IndexMask mask)
@@ -60,6 +45,78 @@ template<typename T> static void copy_data(Span<T> data, MutableSpan<T> r_data,
}
}
+static void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map)
+{
+ BLI_assert(src_mesh.totvert == vertex_map.size());
+ for (const int i_src : vertex_map.index_range()) {
+ const int i_dst = vertex_map[i_src];
+ if (i_dst == -1) {
+ continue;
+ }
+
+ const MVert &v_src = src_mesh.mvert[i_src];
+ MVert &v_dst = dst_mesh.mvert[i_dst];
+
+ v_dst = v_src;
+ CustomData_copy_data(&src_mesh.vdata, &dst_mesh.vdata, i_src, i_dst, 1);
+ }
+}
+
+static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map,
+ Span<int> edge_map)
+{
+ BLI_assert(src_mesh.totvert == vertex_map.size());
+ BLI_assert(src_mesh.totedge == edge_map.size());
+ for (const int i_src : IndexRange(src_mesh.totedge)) {
+ const int i_dst = edge_map[i_src];
+ if (ELEM(i_dst, -1, -2)) {
+ continue;
+ }
+
+ const MEdge &e_src = src_mesh.medge[i_src];
+ MEdge &e_dst = dst_mesh.medge[i_dst];
+
+ CustomData_copy_data(&src_mesh.edata, &dst_mesh.edata, i_src, i_dst, 1);
+ e_dst = e_src;
+ e_dst.v1 = vertex_map[e_src.v1];
+ e_dst.v2 = vertex_map[e_src.v2];
+ }
+}
+
+static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map,
+ Span<int> edge_map,
+ Span<int> masked_poly_indices,
+ Span<int> new_loop_starts)
+{
+ for (const int i_dst : masked_poly_indices.index_range()) {
+ const int i_src = masked_poly_indices[i_dst];
+
+ const MPoly &mp_src = src_mesh.mpoly[i_src];
+ MPoly &mp_dst = dst_mesh.mpoly[i_dst];
+ const int i_ml_src = mp_src.loopstart;
+ const int i_ml_dst = new_loop_starts[i_dst];
+
+ CustomData_copy_data(&src_mesh.pdata, &dst_mesh.pdata, i_src, i_dst, 1);
+ CustomData_copy_data(&src_mesh.ldata, &dst_mesh.ldata, i_ml_src, i_ml_dst, mp_src.totloop);
+
+ const MLoop *ml_src = src_mesh.mloop + i_ml_src;
+ MLoop *ml_dst = dst_mesh.mloop + i_ml_dst;
+
+ mp_dst = mp_src;
+ mp_dst.loopstart = i_ml_dst;
+ for (int i : IndexRange(mp_src.totloop)) {
+ ml_dst[i].v = vertex_map[ml_src[i].v];
+ ml_dst[i].e = edge_map[ml_src[i].e];
+ }
+ }
+}
+
static void spline_copy_builtin_attributes(const Spline &spline,
Spline &r_spline,
const IndexMask mask)
@@ -137,7 +194,7 @@ static std::unique_ptr<CurveEval> curve_delete(const CurveEval &input_curve,
Vector<int64_t> copied_splines;
if (input_curve.attributes.get_for_read(name)) {
- GVArray_Typed<bool> selection = input_curve.attributes.get_for_read<bool>(name, false);
+ VArray<bool> selection = input_curve.attributes.get_for_read<bool>(name, false);
for (const int i : input_splines.index_range()) {
if (selection[i] == invert) {
output_curve->add_spline(input_splines[i]->copy());
@@ -151,7 +208,7 @@ static std::unique_ptr<CurveEval> curve_delete(const CurveEval &input_curve,
for (const int i : input_splines.index_range()) {
const Spline &spline = *input_splines[i];
- GVArray_Typed<bool> selection = spline.attributes.get_for_read<bool>(name, false);
+ VArray<bool> selection = spline.attributes.get_for_read<bool>(name, false);
indices_to_copy.clear();
for (const int i_point : IndexRange(spline.size())) {
@@ -202,7 +259,7 @@ static void delete_point_cloud_selection(const PointCloudComponent &in_component
const StringRef selection_name,
const bool invert)
{
- const GVArray_Typed<bool> selection_attribute = in_component.attribute_get_for_read<bool>(
+ const VArray<bool> selection_attribute = in_component.attribute_get_for_read<bool>(
selection_name, ATTR_DOMAIN_POINT, false);
VArray_Span<bool> selection{selection_attribute};
@@ -590,7 +647,7 @@ static void delete_mesh_selection(MeshComponent &component,
const AttributeDomain selection_domain = get_mesh_selection_domain(component, selection_name);
/* This already checks if the attribute exists, and displays a warning in that case. */
- GVArray_Typed<bool> selection = component.attribute_get_for_read<bool>(
+ VArray<bool> selection = component.attribute_get_for_read<bool>(
selection_name, selection_domain, false);
/* Check if there is anything to delete. */
@@ -627,10 +684,10 @@ static void delete_mesh_selection(MeshComponent &component,
component.replace(mesh_out);
}
-static void geo_node_delete_geometry_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
const bool invert = params.extract_input<bool>("Invert");
const std::string selection_name = params.extract_input<std::string>("Selection");
@@ -662,16 +719,18 @@ static void geo_node_delete_geometry_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(out_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_delete_geometry_cc
-void register_node_type_geo_delete_geometry()
+void register_node_type_geo_legacy_delete_geometry()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_delete_geometry_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY);
- ntype.declare = blender::nodes::geo_node_delete_geometry_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_delete_geometry_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc
index 2ea6516996d..e628edb7e17 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc
@@ -22,26 +22,26 @@ extern "C" {
Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd);
}
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_edge_split_cc {
-static void geo_node_edge_split_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Bool>("Edge Angle").default_value(true);
- b.add_input<decl::Float>("Angle")
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Edge Angle")).default_value(true);
+ b.add_input<decl::Float>(N_("Angle"))
.default_value(DEG2RADF(30.0f))
.min(0.0f)
.max(DEG2RADF(180.0f))
.subtype(PROP_ANGLE);
- b.add_input<decl::Bool>("Sharp Edges");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Bool>(N_("Sharp Edges"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_edge_split_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_mesh()) {
params.set_output("Geometry", std::move(geometry_set));
@@ -76,14 +76,16 @@ static void geo_node_edge_split_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_edge_split_cc
-void register_node_type_geo_edge_split()
+void register_node_type_geo_legacy_edge_split()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_edge_split_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_LEGACY_EDGE_SPLIT, "Edge Split", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_edge_split_exec;
- ntype.declare = blender::nodes::geo_node_edge_split_declare;
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_EDGE_SPLIT, "Edge Split", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc
index 7d3481c1067..8fd6b1e299f 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc
@@ -24,14 +24,14 @@
#include "BKE_material.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_material_assign_cc {
-static void geo_node_legacy_material_assign_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Material>("Material").hide_label(true);
- b.add_input<decl::String>("Selection");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Material>(N_("Material")).hide_label(true);
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void assign_material_to_faces(Mesh &mesh, const VArray<bool> &face_mask, Material *material)
@@ -59,20 +59,20 @@ static void assign_material_to_faces(Mesh &mesh, const VArray<bool> &face_mask,
}
}
-static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *material = params.extract_input<Material *>("Material");
const std::string mask_name = params.extract_input<std::string>("Selection");
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
Mesh *mesh = mesh_component.get_for_write();
if (mesh != nullptr) {
- GVArray_Typed<bool> face_mask = mesh_component.attribute_get_for_read<bool>(
+ VArray<bool> face_mask = mesh_component.attribute_get_for_read<bool>(
mask_name, ATTR_DOMAIN_FACE, true);
assign_material_to_faces(*mesh, face_mask, material);
}
@@ -81,15 +81,17 @@ static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_material_assign_cc
void register_node_type_geo_legacy_material_assign()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_material_assign_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_legacy_material_assign_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_material_assign_exec;
+ &ntype, GEO_NODE_LEGACY_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
new file mode 100644
index 00000000000..d026fff003f
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
@@ -0,0 +1,80 @@
+/*
+ * 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 "GEO_mesh_to_curve.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Mesh"));
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_output<decl::Geometry>(N_("Curve"));
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
+
+ if (!geometry_set.has_mesh()) {
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
+ const std::string selection_name = params.extract_input<std::string>("Selection");
+ if (!selection_name.empty() && !component.attribute_exists(selection_name)) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("No attribute with name \"") + selection_name + "\"");
+ }
+ VArray<bool> selection = component.attribute_get_for_read<bool>(
+ selection_name, ATTR_DOMAIN_EDGE, true);
+
+ Vector<int64_t> selected_edge_indices;
+ for (const int64_t i : IndexRange(component.attribute_domain_size(ATTR_DOMAIN_EDGE))) {
+ if (selection[i]) {
+ selected_edge_indices.append(i);
+ }
+ }
+
+ if (selected_edge_indices.size() == 0) {
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ std::unique_ptr<CurveEval> curve = geometry::mesh_to_curve_convert(
+ component, IndexMask(selected_edge_indices));
+
+ params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+}
+
+} // namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc
+
+void register_node_type_geo_legacy_mesh_to_curve()
+{
+ namespace file_ns = blender::nodes::node_geo_legacy_mesh_to_curve_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc
index f95b0da86ed..29eff373d15 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc
@@ -36,36 +36,35 @@
#include "node_geometry_util.hh"
-using blender::bke::GeometryInstanceGroup;
+namespace blender::nodes::node_geo_legacy_point_distribute_cc {
-namespace blender::nodes {
+using blender::bke::GeometryInstanceGroup;
-static void geo_node_point_distribute_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Float>("Distance Min").min(0.0f).max(100000.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Density Max")
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Float>(N_("Distance Min")).min(0.0f).max(100000.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Density Max"))
.default_value(1.0f)
.min(0.0f)
.max(100000.0f)
.subtype(PROP_NONE);
- b.add_input<decl::String>("Density Attribute");
- b.add_input<decl::Int>("Seed").min(-10000).max(10000);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::String>(N_("Density Attribute"));
+ b.add_input<decl::Int>(N_("Seed")).min(-10000).max(10000);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_distribute_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE);
}
-static void node_point_distribute_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_point_distribute_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sock_min_dist = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
- nodeSetSocketAvailability(sock_min_dist, ELEM(node->custom1, GEO_NODE_POINT_DISTRIBUTE_POISSON));
+ nodeSetSocketAvailability(
+ ntree, sock_min_dist, ELEM(node->custom1, GEO_NODE_POINT_DISTRIBUTE_POISSON));
}
/**
@@ -106,9 +105,9 @@ static void sample_mesh_surface(const Mesh &mesh,
float looptri_density_factor = 1.0f;
if (density_factors != nullptr) {
- const float v0_density_factor = std::max(0.0f, density_factors->get(v0_loop));
- const float v1_density_factor = std::max(0.0f, density_factors->get(v1_loop));
- const float v2_density_factor = std::max(0.0f, density_factors->get(v2_loop));
+ const float v0_density_factor = std::max(0.0f, (*density_factors)[v0_loop]);
+ const float v1_density_factor = std::max(0.0f, (*density_factors)[v1_loop]);
+ const float v2_density_factor = std::max(0.0f, (*density_factors)[v2_loop]);
looptri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) / 3.0f;
}
const float area = area_tri_v3(v0_pos, v1_pos, v2_pos);
@@ -252,18 +251,26 @@ BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
{
switch (source_domain) {
case ATTR_DOMAIN_POINT: {
- bke::mesh_surface_sample::sample_point_attribute(
- mesh, looptri_indices, bary_coords, source_data, output_data);
+ bke::mesh_surface_sample::sample_point_attribute(mesh,
+ looptri_indices,
+ bary_coords,
+ source_data,
+ IndexMask(output_data.size()),
+ output_data);
break;
}
case ATTR_DOMAIN_CORNER: {
- bke::mesh_surface_sample::sample_corner_attribute(
- mesh, looptri_indices, bary_coords, source_data, output_data);
+ bke::mesh_surface_sample::sample_corner_attribute(mesh,
+ looptri_indices,
+ bary_coords,
+ source_data,
+ IndexMask(output_data.size()),
+ output_data);
break;
}
case ATTR_DOMAIN_FACE: {
bke::mesh_surface_sample::sample_face_attribute(
- mesh, looptri_indices, source_data, output_data);
+ mesh, looptri_indices, source_data, IndexMask(output_data.size()), output_data);
break;
}
default: {
@@ -307,21 +314,21 @@ BLI_NOINLINE static void interpolate_existing_attributes(
}
const AttributeDomain source_domain = attribute_info->domain;
- GVArrayPtr source_attribute = source_component.attribute_get_for_read(
+ GVArray source_attribute = source_component.attribute_get_for_read(
attribute_id, source_domain, output_data_type, nullptr);
if (!source_attribute) {
i_instance += set_group.transforms.size();
continue;
}
- for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
+ for ([[maybe_unused]] const int i_set_instance : set_group.transforms.index_range()) {
const int offset = instance_start_offsets[i_instance];
Span<float3> bary_coords = bary_coords_array[i_instance];
Span<int> looptri_indices = looptri_indices_array[i_instance];
GMutableSpan instance_span = out_span.slice(offset, bary_coords.size());
interpolate_attribute(
- mesh, bary_coords, looptri_indices, source_domain, *source_attribute, instance_span);
+ mesh, bary_coords, looptri_indices, source_domain, source_attribute, instance_span);
i_instance++;
}
@@ -329,7 +336,7 @@ BLI_NOINLINE static void interpolate_existing_attributes(
attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) {
using T = decltype(dummy);
- GVArray_Span<T> source_span{*source_attribute};
+ VArray_Span source_span{source_attribute.typed<T>()};
});
}
@@ -437,7 +444,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups,
for (const GeometryInstanceGroup &set_group : set_groups) {
const GeometrySet &set = set_group.geometry_set;
const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
- GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>(
+ VArray<float> density_factors = component.attribute_get_for_read<float>(
density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
const Mesh &mesh = *component.get_for_read();
for (const float4x4 &transform : set_group.transforms) {
@@ -447,7 +454,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups,
sample_mesh_surface(mesh,
transform,
density,
- &*density_factors,
+ &density_factors,
seed,
positions,
bary_coords,
@@ -506,10 +513,10 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group
const GeometrySet &set = set_group.geometry_set;
const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
const Mesh &mesh = *component.get_for_read();
- const GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>(
+ const VArray<float> density_factors = component.attribute_get_for_read<float>(
density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
- for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
+ for ([[maybe_unused]] const int i_set_instance : set_group.transforms.index_range()) {
Vector<float3> &positions = positions_all[i_instance];
Vector<float3> &bary_coords = bary_coords_all[i_instance];
Vector<int> &looptri_indices = looptri_indices_all[i_instance];
@@ -532,7 +539,7 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group
}
}
-static void geo_node_point_distribute_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -545,14 +552,14 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
"Density Attribute");
if (density <= 0.0f) {
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
Vector<GeometryInstanceGroup> set_groups;
geometry_set_gather_instances(geometry_set, set_groups);
if (set_groups.is_empty()) {
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -566,7 +573,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
if (set_groups.is_empty()) {
params.error_message_add(NodeWarningType::Error, TIP_("Input geometry must contain a mesh"));
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -615,6 +622,11 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
final_points_len += positions.size();
}
+ if (final_points_len == 0) {
+ params.set_default_remaining_outputs();
+ return;
+ }
+
PointCloud *pointcloud = BKE_pointcloud_new_nomain(final_points_len);
for (const int instance_index : positions_all.index_range()) {
const int offset = instance_start_offsets[instance_index];
@@ -641,17 +653,19 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set_out));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_distribute_cc
void register_node_type_geo_point_distribute()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_distribute_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0);
- node_type_update(&ntype, blender::nodes::node_point_distribute_update);
- ntype.declare = blender::nodes::geo_node_point_distribute_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_distribute_layout;
+ &ntype, GEO_NODE_LEGACY_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY);
+ node_type_update(&ntype, file_ns::node_point_distribute_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc
index fb45c22ced4..faf0b1a5fe7 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc
@@ -24,19 +24,19 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_point_instance_cc {
-static void geo_node_point_instance_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Object>("Object").hide_label();
- b.add_input<decl::Collection>("Collection").hide_label();
- b.add_input<decl::Geometry>("Instance Geometry");
- b.add_input<decl::Int>("Seed").min(-10000).max(10000);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Object>(N_("Object")).hide_label();
+ b.add_input<decl::Collection>(N_("Collection")).hide_label();
+ b.add_input<decl::Geometry>(N_("Instance Geometry"));
+ b.add_input<decl::Int>(N_("Seed")).min(-10000).max(10000);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "instance_type", 0, "", ICON_NONE);
if (RNA_enum_get(ptr, "instance_type") == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION) {
@@ -44,16 +44,15 @@ static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C)
}
}
-static void geo_node_point_instance_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryPointInstance *data = (NodeGeometryPointInstance *)MEM_callocN(
- sizeof(NodeGeometryPointInstance), __func__);
+ NodeGeometryPointInstance *data = MEM_cnew<NodeGeometryPointInstance>(__func__);
data->instance_type = GEO_NODE_POINT_INSTANCE_TYPE_OBJECT;
data->flag |= GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION;
node->storage = data;
}
-static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *object_socket = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
bNodeSocket *collection_socket = object_socket->next;
@@ -65,12 +64,15 @@ static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node)
const bool use_whole_collection = (node_storage->flag &
GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION) != 0;
- nodeSetSocketAvailability(object_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_OBJECT);
- nodeSetSocketAvailability(collection_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION);
- nodeSetSocketAvailability(instance_geometry_socket,
- type == GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY);
+ nodeSetSocketAvailability(ntree, object_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_OBJECT);
nodeSetSocketAvailability(
- seed_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION && !use_whole_collection);
+ ntree, collection_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION);
+ nodeSetSocketAvailability(
+ ntree, instance_geometry_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY);
+ nodeSetSocketAvailability(ntree,
+ seed_socket,
+ type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION &&
+ !use_whole_collection);
}
static Vector<InstanceReference> get_instance_references__object(GeoNodeExecParams &params)
@@ -170,21 +172,25 @@ static void add_instances_from_component(InstancesComponent &instances,
const AttributeDomain domain = ATTR_DOMAIN_POINT;
const int domain_size = src_geometry.attribute_domain_size(domain);
+ if (domain_size == 0) {
+ return;
+ }
- GVArray_Typed<float3> positions = src_geometry.attribute_get_for_read<float3>(
+ VArray<float3> positions = src_geometry.attribute_get_for_read<float3>(
"position", domain, {0, 0, 0});
- GVArray_Typed<float3> rotations = src_geometry.attribute_get_for_read<float3>(
+ VArray<float3> rotations = src_geometry.attribute_get_for_read<float3>(
"rotation", domain, {0, 0, 0});
- GVArray_Typed<float3> scales = src_geometry.attribute_get_for_read<float3>(
- "scale", domain, {1, 1, 1});
- GVArray_Typed<int> id_attribute = src_geometry.attribute_get_for_read<int>("id", domain, -1);
+ VArray<float3> scales = src_geometry.attribute_get_for_read<float3>("scale", domain, {1, 1, 1});
+ VArray<int> id_attribute = src_geometry.attribute_get_for_read<int>("id", domain, -1);
/* The initial size of the component might be non-zero if there are two component types. */
const int start_len = instances.instances_amount();
instances.resize(start_len + domain_size);
MutableSpan<int> handles = instances.instance_reference_handles().slice(start_len, domain_size);
MutableSpan<float4x4> transforms = instances.instance_transforms().slice(start_len, domain_size);
- MutableSpan<int> instance_ids = instances.instance_ids().slice(start_len, domain_size);
+ OutputAttribute_Typed<int> instance_id_attribute =
+ instances.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_INSTANCE);
+ MutableSpan<int> instance_ids = instance_id_attribute.as_span();
/* Skip all of the randomness handling if there is only a single possible instance
* (anything except for collection mode with "Whole Collection" turned off). */
@@ -211,16 +217,18 @@ static void add_instances_from_component(InstancesComponent &instances,
}
});
}
+
+ instance_id_attribute.save();
}
-static void geo_node_point_instance_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_out;
/* TODO: This node should be able to instance on the input instances component
* rather than making the entire input geometry set real. */
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
const Vector<InstanceReference> possible_references = get_instance_references(params);
if (possible_references.is_empty()) {
@@ -253,20 +261,22 @@ static void geo_node_point_instance_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set_out));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_instance_cc
void register_node_type_geo_point_instance()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_instance_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINT_INSTANCE, "Point Instance", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_point_instance_init);
+ &ntype, GEO_NODE_LEGACY_POINT_INSTANCE, "Point Instance", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeGeometryPointInstance", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_point_instance_declare;
- ntype.draw_buttons = blender::nodes::geo_node_point_instance_layout;
- node_type_update(&ntype, blender::nodes::geo_node_point_instance_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_point_instance_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc
index 60c82360007..ad87ec5541b 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc
@@ -21,21 +21,23 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_point_rotate_cc {
-static void geo_node_point_rotate_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Axis");
- b.add_input<decl::Vector>("Axis", "Axis_001").default_value({0.0, 0.0, 1.0}).subtype(PROP_XYZ);
- b.add_input<decl::String>("Angle");
- b.add_input<decl::Float>("Angle", "Angle_001").subtype(PROP_ANGLE);
- b.add_input<decl::String>("Rotation");
- b.add_input<decl::Vector>("Rotation", "Rotation_001").subtype(PROP_EULER);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Axis"));
+ b.add_input<decl::Vector>(N_("Axis"), "Axis_001")
+ .default_value({0.0, 0.0, 1.0})
+ .subtype(PROP_XYZ);
+ b.add_input<decl::String>(N_("Angle"));
+ b.add_input<decl::Float>(N_("Angle"), "Angle_001").subtype(PROP_ANGLE);
+ b.add_input<decl::String>(N_("Rotation"));
+ b.add_input<decl::Vector>(N_("Rotation"), "Rotation_001").subtype(PROP_EULER);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
NodeGeometryRotatePoints *storage = (NodeGeometryRotatePoints *)((bNode *)ptr->data)->storage;
@@ -55,10 +57,9 @@ static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C),
}
}
-static void geo_node_point_rotate_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)MEM_callocN(
- sizeof(NodeGeometryRotatePoints), __func__);
+ NodeGeometryRotatePoints *node_storage = MEM_cnew<NodeGeometryRotatePoints>(__func__);
node_storage->type = GEO_NODE_POINT_ROTATE_TYPE_EULER;
node_storage->space = GEO_NODE_POINT_ROTATE_SPACE_OBJECT;
@@ -69,20 +70,23 @@ static void geo_node_point_rotate_init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = node_storage;
}
-static void geo_node_point_rotate_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)node->storage;
update_attribute_input_socket_availabilities(
+ *ntree,
*node,
"Axis",
(GeometryNodeAttributeInputMode)node_storage->input_type_axis,
node_storage->type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE);
update_attribute_input_socket_availabilities(
+ *ntree,
*node,
"Angle",
(GeometryNodeAttributeInputMode)node_storage->input_type_angle,
node_storage->type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE);
update_attribute_input_socket_availabilities(
+ *ntree,
*node,
"Rotation",
(GeometryNodeAttributeInputMode)node_storage->input_type_rotation,
@@ -167,9 +171,9 @@ static void point_rotate_on_component(GeometryComponent &component,
const int domain_size = rotations.size();
if (storage.type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE) {
- GVArray_Typed<float3> axis = params.get_input_attribute<float3>(
+ VArray<float3> axis = params.get_input_attribute<float3>(
"Axis", component, ATTR_DOMAIN_POINT, {0, 0, 1});
- GVArray_Typed<float> angles = params.get_input_attribute<float>(
+ VArray<float> angles = params.get_input_attribute<float>(
"Angle", component, ATTR_DOMAIN_POINT, 0);
if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) {
@@ -180,7 +184,7 @@ static void point_rotate_on_component(GeometryComponent &component,
}
}
else {
- GVArray_Typed<float3> eulers = params.get_input_attribute<float3>(
+ VArray<float3> eulers = params.get_input_attribute<float3>(
"Rotation", component, ATTR_DOMAIN_POINT, {0, 0, 0});
if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) {
@@ -194,11 +198,11 @@ static void point_rotate_on_component(GeometryComponent &component,
rotation_attribute.save();
}
-static void geo_node_point_rotate_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
point_rotate_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -213,19 +217,21 @@ static void geo_node_point_rotate_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_rotate_cc
void register_node_type_geo_point_rotate()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_rotate_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_ROTATE, "Point Rotate", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_point_rotate_init);
- node_type_update(&ntype, blender::nodes::geo_node_point_rotate_update);
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_ROTATE, "Point Rotate", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryRotatePoints", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_point_rotate_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_rotate_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_rotate_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc
index 99adce149e9..69e69a24e29 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc
@@ -21,41 +21,40 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_point_scale_cc {
-static void geo_node_point_scale_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Factor");
- b.add_input<decl::Vector>("Factor", "Factor_001")
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Factor"));
+ b.add_input<decl::Vector>(N_("Factor"), "Factor_001")
.default_value({1.0f, 1.0f, 1.0f})
.subtype(PROP_XYZ);
- b.add_input<decl::Float>("Factor", "Factor_002").default_value(1.0f).min(0.0f);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Float>(N_("Factor"), "Factor_002").default_value(1.0f).min(0.0f);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_scale_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "input_type", 0, IFACE_("Type"), ICON_NONE);
}
-static void geo_node_point_scale_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryPointScale *data = (NodeGeometryPointScale *)MEM_callocN(
- sizeof(NodeGeometryPointScale), __func__);
+ NodeGeometryPointScale *data = MEM_cnew<NodeGeometryPointScale>(__func__);
data->input_type = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
node->storage = data;
}
-static void geo_node_point_scale_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryPointScale &node_storage = *(NodeGeometryPointScale *)node->storage;
update_attribute_input_socket_availabilities(
- *node, "Factor", (GeometryNodeAttributeInputMode)node_storage.input_type);
+ *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage.input_type);
}
static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component)
@@ -78,7 +77,7 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
const CustomDataType data_type = (input_type == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) ? CD_PROP_FLOAT :
CD_PROP_FLOAT3;
- GVArrayPtr attribute = params.get_input_attribute(
+ GVArray attribute = params.get_input_attribute(
"Factor", component, ATTR_DOMAIN_POINT, data_type, nullptr);
if (!attribute) {
return;
@@ -86,13 +85,13 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
MutableSpan<float3> scale_span = scale_attribute.as_span();
if (data_type == CD_PROP_FLOAT) {
- GVArray_Typed<float> factors{*attribute};
+ VArray<float> factors = attribute.typed<float>();
for (const int i : scale_span.index_range()) {
scale_span[i] = scale_span[i] * factors[i];
}
}
else if (data_type == CD_PROP_FLOAT3) {
- GVArray_Typed<float3> factors{*attribute};
+ VArray<float3> factors = attribute.typed<float3>();
for (const int i : scale_span.index_range()) {
scale_span[i] = scale_span[i] * factors[i];
}
@@ -101,11 +100,11 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
scale_attribute.save();
}
-static void geo_node_point_scale_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -120,20 +119,22 @@ static void geo_node_point_scale_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_scale_cc
void register_node_type_geo_point_scale()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_scale_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_SCALE, "Point Scale", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_SCALE, "Point Scale", NODE_CLASS_GEOMETRY);
- ntype.declare = blender::nodes::geo_node_point_scale_declare;
- node_type_init(&ntype, blender::nodes::geo_node_point_scale_init);
- node_type_update(&ntype, blender::nodes::geo_node_point_scale_update);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryPointScale", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_point_scale_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_scale_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc
index 48b6676c1dd..b9760587706 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc
@@ -25,14 +25,6 @@
namespace blender::nodes {
-static void geo_node_point_instance_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Mask");
- b.add_output<decl::Geometry>("Geometry 1");
- b.add_output<decl::Geometry>("Geometry 2");
-}
-
template<typename T>
static void copy_data_based_on_mask(Span<T> data,
Span<bool> masks,
@@ -55,7 +47,7 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
{
for (const AttributeIDRef &attribute_id : in_component.attribute_ids()) {
ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id);
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type());
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
/* Only copy point attributes. Theoretically this could interpolate attributes on other
* domains to the point domain, but that would conflict with attributes that are built-in
@@ -69,7 +61,7 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
- GVArray_Span<T> span{*attribute.varray};
+ VArray_Span span{attribute.varray.typed<T>()};
MutableSpan<T> out_span = result_attribute.as_span<T>();
copy_data_based_on_mask(span, masks, invert, out_span);
});
@@ -78,6 +70,18 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
}
}
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_legacy_point_separate_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Mask"));
+ b.add_output<decl::Geometry>(N_("Geometry 1"));
+ b.add_output<decl::Geometry>(N_("Geometry 2"));
+}
+
static void create_component_points(GeometryComponent &component, const int total)
{
switch (component.type()) {
@@ -103,7 +107,7 @@ static void separate_points_from_component(const GeometryComponent &in_component
return;
}
- const GVArray_Typed<bool> mask_attribute = in_component.attribute_get_for_read<bool>(
+ const VArray<bool> mask_attribute = in_component.attribute_get_for_read<bool>(
mask_name, ATTR_DOMAIN_POINT, false);
VArray_Span<bool> masks{mask_attribute};
@@ -133,7 +137,7 @@ static GeometrySet separate_geometry_set(const GeometrySet &set_in,
return set_out;
}
-static void geo_node_point_separate_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
bool wait_for_inputs = false;
wait_for_inputs |= params.lazy_require_input("Geometry");
@@ -146,7 +150,7 @@ static void geo_node_point_separate_exec(GeoNodeExecParams params)
/* TODO: This is not necessary-- the input geometry set can be read only,
* but it must be rewritten to handle instance groups. */
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (params.lazy_output_is_required("Geometry 1")) {
params.set_output("Geometry 1",
@@ -158,16 +162,18 @@ static void geo_node_point_separate_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_separate_cc
void register_node_type_geo_point_separate()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_separate_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_point_instance_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_separate_exec;
+ &ntype, GEO_NODE_LEGACY_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.geometry_node_execute_supports_laziness = true;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc
index f2fce45c57b..385c3d9f22d 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc
@@ -19,17 +19,17 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_point_translate_cc {
-static void geo_node_point_translate_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Translation");
- b.add_input<decl::Vector>("Translation", "Translation_001").subtype(PROP_TRANSLATION);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Translation"));
+ b.add_input<decl::Vector>(N_("Translation"), "Translation_001").subtype(PROP_TRANSLATION);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_translate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -43,21 +43,21 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
if (!position_attribute) {
return;
}
- GVArray_Typed<float3> attribute = params.get_input_attribute<float3>(
+ VArray<float3> attribute = params.get_input_attribute<float3>(
"Translation", component, ATTR_DOMAIN_POINT, {0, 0, 0});
- for (const int i : IndexRange(attribute.size())) {
+ for (const int i : attribute.index_range()) {
position_attribute->set(i, position_attribute->get(i) + attribute[i]);
}
position_attribute.save();
}
-static void geo_node_point_translate_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -72,39 +72,40 @@ static void geo_node_point_translate_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-static void geo_node_point_translate_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryPointTranslate *data = (NodeGeometryPointTranslate *)MEM_callocN(
- sizeof(NodeGeometryPointTranslate), __func__);
+ NodeGeometryPointTranslate *data = MEM_cnew<NodeGeometryPointTranslate>(__func__);
data->input_type = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
node->storage = data;
}
-static void geo_node_point_translate_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage;
update_attribute_input_socket_availabilities(
- *node, "Translation", (GeometryNodeAttributeInputMode)node_storage.input_type);
+ *ntree, *node, "Translation", (GeometryNodeAttributeInputMode)node_storage.input_type);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_translate_cc
void register_node_type_geo_point_translate()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_translate_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINT_TRANSLATE, "Point Translate", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_point_translate_init);
- node_type_update(&ntype, blender::nodes::geo_node_point_translate_update);
+ &ntype, GEO_NODE_LEGACY_POINT_TRANSLATE, "Point Translate", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
"NodeGeometryPointTranslate",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_point_translate_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_translate_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_translate_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc
index d920c8de9f0..f54ffc53a6e 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc
@@ -28,22 +28,20 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_points_to_volume_cc {
-static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Float>("Density").default_value(1.0f).min(0.0f);
- b.add_input<decl::Float>("Voxel Size").default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Voxel Amount").default_value(64.0f).min(0.0f);
- b.add_input<decl::String>("Radius");
- b.add_input<decl::Float>("Radius", "Radius_001").default_value(0.5f).min(0.0f);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Voxel Size")).default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f);
+ b.add_input<decl::String>(N_("Radius"));
+ b.add_input<decl::Float>(N_("Radius"), "Radius_001").default_value(0.5f).min(0.0f);
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_points_to_volume_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -51,10 +49,9 @@ static void geo_node_points_to_volume_layout(uiLayout *layout,
uiItemR(layout, ptr, "input_type_radius", 0, IFACE_("Radius"), ICON_NONE);
}
-static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN(
- sizeof(NodeGeometryPointsToVolume), __func__);
+ NodeGeometryPointsToVolume *data = MEM_cnew<NodeGeometryPointsToVolume>(__func__);
data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
data->input_type_radius = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
node->storage = data;
@@ -65,19 +62,22 @@ static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node
STRNCPY(radius_attribute_socket_value->value, "radius");
}
-static void geo_node_points_to_volume_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage;
bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
- nodeSetSocketAvailability(voxel_amount_socket,
+ nodeSetSocketAvailability(ntree,
+ voxel_amount_socket,
data->resolution_mode ==
GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT);
- nodeSetSocketAvailability(
- voxel_size_socket, data->resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE);
+ nodeSetSocketAvailability(ntree,
+ voxel_size_socket,
+ data->resolution_mode ==
+ GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE);
update_attribute_input_socket_availabilities(
- *node, "Radius", (GeometryNodeAttributeInputMode)data->input_type_radius);
+ *ntree, *node, "Radius", (GeometryNodeAttributeInputMode)data->input_type_radius);
}
#ifdef WITH_OPENVDB
@@ -161,7 +161,7 @@ static float compute_voxel_size(const GeoNodeExecParams &params,
}
/* The voxel size adapts to the final size of the volume. */
- const float diagonal = float3::distance(min, max);
+ const float diagonal = math::distance(min, max);
const float extended_diagonal = diagonal + 2.0f * radius;
const float voxel_size = extended_diagonal / voxel_amount;
return voxel_size;
@@ -172,12 +172,12 @@ static void gather_point_data_from_component(const GeoNodeExecParams &params,
Vector<float3> &r_positions,
Vector<float> &r_radii)
{
- GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>(
+ VArray<float3> positions = component.attribute_get_for_read<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
- GVArray_Typed<float> radii = params.get_input_attribute<float>(
+ VArray<float> radii = params.get_input_attribute<float>(
"Radius", component, ATTR_DOMAIN_POINT, 0.0f);
- for (const int i : IndexRange(positions.size())) {
+ for (const int i : positions.index_range()) {
r_positions.append(positions[i]);
r_radii.append(radii[i]);
}
@@ -241,13 +241,13 @@ static void initialize_volume_component_from_points(const GeometrySet &geometry_
}
#endif
-static void geo_node_points_to_volume_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_out;
/* TODO: Read-only access to instances should be supported here, for now they are made real. */
- geometry_set_in = geometry_set_realize_instances(geometry_set_in);
+ geometry_set_in = geometry::realize_instances_legacy(geometry_set_in);
#ifdef WITH_OPENVDB
initialize_volume_component_from_points(geometry_set_in, geometry_set_out, params);
@@ -256,23 +256,25 @@ static void geo_node_points_to_volume_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set_out));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_points_to_volume_cc
-void register_node_type_geo_points_to_volume()
+void register_node_type_geo_legacy_points_to_volume()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_points_to_volume_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY);
node_type_storage(&ntype,
"NodeGeometryPointsToVolume",
node_free_standard_storage,
node_copy_standard_storage);
node_type_size(&ntype, 170, 120, 700);
- node_type_init(&ntype, blender::nodes::geo_node_points_to_volume_init);
- node_type_update(&ntype, blender::nodes::geo_node_points_to_volume_update);
- ntype.declare = blender::nodes::geo_node_points_to_volume_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec;
- ntype.draw_buttons = blender::nodes::geo_node_points_to_volume_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
index 401a478f04c..cfae88e0625 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
@@ -24,30 +24,30 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_raycast_cc {
-static void geo_node_raycast_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Geometry>("Target Geometry");
- b.add_input<decl::String>("Ray Direction");
- b.add_input<decl::Vector>("Ray Direction", "Ray Direction_001")
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Geometry>(N_("Target Geometry"));
+ b.add_input<decl::String>(N_("Ray Direction"));
+ b.add_input<decl::Vector>(N_("Ray Direction"), "Ray Direction_001")
.default_value({0.0f, 0.0f, 1.0f});
- b.add_input<decl::String>("Ray Length");
- b.add_input<decl::Float>("Ray Length", "Ray Length_001")
+ b.add_input<decl::String>(N_("Ray Length"));
+ b.add_input<decl::Float>(N_("Ray Length"), "Ray Length_001")
.default_value(100.0f)
.min(0.0f)
.subtype(PROP_DISTANCE);
- b.add_input<decl::String>("Target Attribute");
- b.add_input<decl::String>("Is Hit");
- b.add_input<decl::String>("Hit Position");
- b.add_input<decl::String>("Hit Normal");
- b.add_input<decl::String>("Hit Distance");
- b.add_input<decl::String>("Hit Attribute");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::String>(N_("Target Attribute"));
+ b.add_input<decl::String>(N_("Is Hit"));
+ b.add_input<decl::String>(N_("Hit Position"));
+ b.add_input<decl::String>(N_("Hit Normal"));
+ b.add_input<decl::String>(N_("Hit Distance"));
+ b.add_input<decl::String>(N_("Hit Attribute"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -56,24 +56,27 @@ static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), Point
uiItemR(layout, ptr, "input_type_ray_length", 0, IFACE_("Ray Length"), ICON_NONE);
}
-static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast),
- __func__);
+ NodeGeometryRaycast *data = MEM_cnew<NodeGeometryRaycast>(__func__);
data->input_type_ray_direction = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
data->input_type_ray_length = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
node->storage = data;
}
-static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryRaycast *node_storage = (NodeGeometryRaycast *)node->storage;
update_attribute_input_socket_availabilities(
+ *ntree,
*node,
"Ray Direction",
(GeometryNodeAttributeInputMode)node_storage->input_type_ray_direction);
update_attribute_input_socket_availabilities(
- *node, "Ray Length", (GeometryNodeAttributeInputMode)node_storage->input_type_ray_length);
+ *ntree,
+ *node,
+ "Ray Length",
+ (GeometryNodeAttributeInputMode)node_storage->input_type_ray_length);
}
static void raycast_to_mesh(const Mesh &mesh,
@@ -104,7 +107,7 @@ static void raycast_to_mesh(const Mesh &mesh,
for (const int i : ray_origins.index_range()) {
const float ray_length = ray_lengths[i];
const float3 ray_origin = ray_origins[i];
- const float3 ray_direction = ray_directions[i].normalized();
+ const float3 ray_direction = math::normalize(ray_directions[i]);
BVHTreeRayHit hit;
hit.index = -1;
@@ -197,11 +200,11 @@ static void raycast_from_points(const GeoNodeExecParams &params,
(GeometryNodeRaycastMapMode)storage.mapping);
const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
- GVArray_Typed<float3> ray_origins = dst_component.attribute_get_for_read<float3>(
+ VArray<float3> ray_origins = dst_component.attribute_get_for_read<float3>(
"position", result_domain, {0, 0, 0});
- GVArray_Typed<float3> ray_directions = params.get_input_attribute<float3>(
+ VArray<float3> ray_directions = params.get_input_attribute<float3>(
"Ray Direction", dst_component, result_domain, {0, 0, 0});
- GVArray_Typed<float> ray_lengths = params.get_input_attribute<float>(
+ VArray<float> ray_lengths = params.get_input_attribute<float>(
"Ray Length", dst_component, result_domain, 0);
OutputAttribute_Typed<bool> hit_attribute =
@@ -218,10 +221,10 @@ static void raycast_from_points(const GeoNodeExecParams &params,
Array<int> hit_indices;
Array<float3> hit_positions_internal;
if (!hit_attribute_names.is_empty()) {
- hit_indices.reinitialize(ray_origins->size());
+ hit_indices.reinitialize(ray_origins.size());
if (!hit_position_attribute) {
- hit_positions_internal.reinitialize(ray_origins->size());
+ hit_positions_internal.reinitialize(ray_origins.size());
}
}
const MutableSpan<bool> is_hit = hit_attribute ? hit_attribute.as_span() : MutableSpan<bool>();
@@ -250,7 +253,8 @@ static void raycast_from_points(const GeoNodeExecParams &params,
hit_distance_attribute.save();
/* Custom interpolated attributes */
- bke::mesh_surface_sample::MeshAttributeInterpolator interp(src_mesh, hit_positions, hit_indices);
+ bke::mesh_surface_sample::MeshAttributeInterpolator interp(
+ src_mesh, IndexMask(ray_origins.size()), hit_positions, hit_indices);
for (const int i : hit_attribute_names.index_range()) {
const std::optional<AttributeMetaData> meta_data = src_mesh_component->attribute_get_meta_data(
hit_attribute_names[i]);
@@ -267,7 +271,7 @@ static void raycast_from_points(const GeoNodeExecParams &params,
}
}
-static void geo_node_raycast_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet target_geometry_set = params.extract_input<GeometrySet>("Target Geometry");
@@ -280,8 +284,8 @@ static void geo_node_raycast_exec(GeoNodeExecParams params)
const Array<std::string> hit_names = {params.extract_input<std::string>("Target Attribute")};
const Array<std::string> hit_output_names = {params.extract_input<std::string>("Hit Attribute")};
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
- target_geometry_set = bke::geometry_set_realize_instances(target_geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
+ target_geometry_set = geometry::realize_instances_legacy(target_geometry_set);
static const Array<GeometryComponentType> types = {
GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
@@ -302,20 +306,22 @@ static void geo_node_raycast_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_raycast_cc
-void register_node_type_geo_raycast()
+void register_node_type_geo_legacy_raycast()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_raycast_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_LEGACY_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_init(&ntype, blender::nodes::geo_node_raycast_init);
- node_type_update(&ntype, blender::nodes::geo_node_raycast_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_raycast_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_raycast_exec;
- ntype.draw_buttons = blender::nodes::geo_node_raycast_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc
index eabdd2bcd5a..59ac697b658 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc
@@ -26,14 +26,14 @@
#include "BKE_material.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_select_by_material_cc {
-static void geo_node_legacy_select_by_material_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Material>("Material").hide_label();
- b.add_input<decl::String>("Selection");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Material>(N_("Material")).hide_label();
+ b.add_input<decl::String>(N_("Selection"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void select_mesh_by_material(const Mesh &mesh,
@@ -54,13 +54,13 @@ static void select_mesh_by_material(const Mesh &mesh,
});
}
-static void geo_node_legacy_select_by_material_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *material = params.extract_input<Material *>("Material");
const std::string selection_name = params.extract_input<std::string>("Selection");
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
@@ -78,15 +78,17 @@ static void geo_node_legacy_select_by_material_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_select_by_material_cc
void register_node_type_geo_legacy_select_by_material()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_select_by_material_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, "Select by Material", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_legacy_select_by_material_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_select_by_material_exec;
+ &ntype, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, "Select by Material", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc
index 07d3f89bdb7..7c5553cb5e4 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc
@@ -23,19 +23,17 @@
#include "UI_resources.h"
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_subdivision_surface_cc {
-static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Int>("Level").default_value(1).min(0).max(6);
- b.add_input<decl::Bool>("Use Creases");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
+ b.add_input<decl::Bool>(N_("Use Creases"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_subdivision_surface_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
#ifdef WITH_OPENSUBDIV
uiLayoutSetPropSep(layout, true);
@@ -47,20 +45,19 @@ static void geo_node_subdivision_surface_layout(uiLayout *layout,
#endif
}
-static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN(
- sizeof(NodeGeometrySubdivisionSurface), __func__);
+ NodeGeometrySubdivisionSurface *data = MEM_cnew<NodeGeometrySubdivisionSurface>(__func__);
data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL;
node->storage = data;
}
-static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_mesh()) {
params.set_output("Geometry", geometry_set);
@@ -126,18 +123,20 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_subdivision_surface_cc
-void register_node_type_geo_subdivision_surface()
+void register_node_type_geo_legacy_subdivision_surface()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_subdivision_surface_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_subdivision_surface_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec;
- ntype.draw_buttons = blender::nodes::geo_node_subdivision_surface_layout;
- node_type_init(&ntype, blender::nodes::geo_node_subdivision_surface_init);
+ &ntype, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_storage(&ntype,
"NodeGeometrySubdivisionSurface",
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc
new file mode 100644
index 00000000000..42fbc49ed4b
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc
@@ -0,0 +1,176 @@
+/*
+ * 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 "DEG_depsgraph_query.h"
+#ifdef WITH_OPENVDB
+# include <openvdb/tools/GridTransformer.h>
+# include <openvdb/tools/VolumeToMesh.h>
+#endif
+
+#include "node_geometry_util.hh"
+
+#include "BKE_lib_id.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_volume.h"
+#include "BKE_volume_to_mesh.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_geo_legacy_volume_to_mesh_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Density"));
+ b.add_input<decl::Float>(N_("Voxel Size")).default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Threshold")).default_value(0.1f).min(0.0f);
+ b.add_input<decl::Float>(N_("Adaptivity")).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryVolumeToMesh *data = MEM_cnew<NodeGeometryVolumeToMesh>(__func__);
+ data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
+
+ bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Density");
+ bNodeSocketValueString *grid_socket_value = (bNodeSocketValueString *)grid_socket->default_value;
+ STRNCPY(grid_socket_value->value, "density");
+
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage;
+
+ bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
+ bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
+ nodeSetSocketAvailability(ntree,
+ voxel_amount_socket,
+ data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT);
+ nodeSetSocketAvailability(ntree,
+ voxel_size_socket,
+ data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE);
+}
+
+#ifdef WITH_OPENVDB
+
+static void create_mesh_from_volume(GeometrySet &geometry_set_in,
+ GeometrySet &geometry_set_out,
+ GeoNodeExecParams &params)
+{
+ if (!geometry_set_in.has<VolumeComponent>()) {
+ return;
+ }
+
+ const NodeGeometryVolumeToMesh &storage =
+ *(const NodeGeometryVolumeToMesh *)params.node().storage;
+
+ bke::VolumeToMeshResolution resolution;
+ resolution.mode = (VolumeToMeshResolutionMode)storage.resolution_mode;
+ if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT) {
+ resolution.settings.voxel_amount = params.get_input<float>("Voxel Amount");
+ if (resolution.settings.voxel_amount <= 0.0f) {
+ return;
+ }
+ }
+ else if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE) {
+ resolution.settings.voxel_size = params.get_input<float>("Voxel Size");
+ if (resolution.settings.voxel_size <= 0.0f) {
+ return;
+ }
+ }
+
+ const VolumeComponent *component = geometry_set_in.get_component_for_read<VolumeComponent>();
+ const Volume *volume = component->get_for_read();
+ if (volume == nullptr) {
+ return;
+ }
+
+ const Main *bmain = DEG_get_bmain(params.depsgraph());
+ BKE_volume_load(volume, bmain);
+
+ const std::string grid_name = params.get_input<std::string>("Density");
+ const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, grid_name.c_str());
+ if (volume_grid == nullptr) {
+ return;
+ }
+
+ float threshold = params.get_input<float>("Threshold");
+ float adaptivity = params.get_input<float>("Adaptivity");
+
+ const openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
+ Mesh *mesh = bke::volume_to_mesh(*grid, resolution, threshold, adaptivity);
+ if (mesh == nullptr) {
+ return;
+ }
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
+ MeshComponent &dst_component = geometry_set_out.get_component_for_write<MeshComponent>();
+ dst_component.replace(mesh);
+}
+
+#endif /* WITH_OPENVDB */
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set_out;
+
+#ifdef WITH_OPENVDB
+ create_mesh_from_volume(geometry_set_in, geometry_set_out, params);
+#else
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Disabled, Blender was compiled without OpenVDB"));
+#endif
+
+ params.set_output("Geometry", geometry_set_out);
+}
+
+} // namespace blender::nodes::node_geo_legacy_volume_to_mesh_cc
+
+void register_node_type_geo_legacy_volume_to_mesh()
+{
+ namespace file_ns = blender::nodes::node_geo_legacy_volume_to_mesh_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ node_type_storage(
+ &ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage);
+ node_type_size(&ntype, 170, 120, 700);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
new file mode 100644
index 00000000000..6c2e72cf14f
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
@@ -0,0 +1,430 @@
+/*
+ * 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 "BKE_attribute_math.hh"
+
+#include "NOD_socket_search_link.hh"
+
+#include "node_geometry_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_geo_accumulate_field_cc {
+
+NODE_STORAGE_FUNCS(NodeAccumulateField)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ std::string value_in_description = "The values to be accumulated";
+ std::string leading_out_description =
+ "The running total of values in the corresponding group, starting at the first value";
+ std::string trailing_out_description =
+ "The running total of values in the corresponding group, starting at zero";
+ std::string total_out_description = "The total of all of the values in the corresponding group";
+
+ b.add_input<decl::Vector>(N_("Value"), "Value Vector")
+ .default_value({1.0f, 1.0f, 1.0f})
+ .supports_field()
+ .description(N_(value_in_description));
+ b.add_input<decl::Float>(N_("Value"), "Value Float")
+ .default_value(1.0f)
+ .supports_field()
+ .description(N_(value_in_description));
+ b.add_input<decl::Int>(N_("Value"), "Value Int")
+ .default_value(1)
+ .supports_field()
+ .description(N_(value_in_description));
+ b.add_input<decl::Int>(N_("Group Index"))
+ .supports_field()
+ .description(
+ N_("An index used to group values together for multiple separate accumulations"));
+
+ b.add_output<decl::Vector>(N_("Leading"), "Leading Vector")
+ .field_source()
+ .description(N_(leading_out_description));
+ b.add_output<decl::Float>(N_("Leading"), "Leading Float")
+ .field_source()
+ .description(N_(leading_out_description));
+ b.add_output<decl::Int>(N_("Leading"), "Leading Int")
+ .field_source()
+ .description(N_(leading_out_description));
+
+ b.add_output<decl::Vector>(N_("Trailing"), "Trailing Vector")
+ .field_source()
+ .description(N_(trailing_out_description));
+ b.add_output<decl::Float>(N_("Trailing"), "Trailing Float")
+ .field_source()
+ .description(N_(trailing_out_description));
+ b.add_output<decl::Int>(N_("Trailing"), "Trailing Int")
+ .field_source()
+ .description(N_(trailing_out_description));
+
+ b.add_output<decl::Vector>(N_("Total"), "Total Vector")
+ .field_source()
+ .description(N_(total_out_description));
+ b.add_output<decl::Float>(N_("Total"), "Total Float")
+ .field_source()
+ .description(N_(total_out_description));
+ b.add_output<decl::Int>(N_("Total"), "Total Int")
+ .field_source()
+ .description(N_(total_out_description));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeAccumulateField *data = MEM_cnew<NodeAccumulateField>(__func__);
+ data->data_type = CD_PROP_FLOAT;
+ data->domain = ATTR_DOMAIN_POINT;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeAccumulateField &storage = node_storage(*node);
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+
+ bNodeSocket *sock_in_vector = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *sock_in_float = sock_in_vector->next;
+ bNodeSocket *sock_in_int = sock_in_float->next;
+
+ bNodeSocket *sock_out_vector = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *sock_out_float = sock_out_vector->next;
+ bNodeSocket *sock_out_int = sock_out_float->next;
+
+ bNodeSocket *sock_out_first_vector = sock_out_int->next;
+ bNodeSocket *sock_out_first_float = sock_out_first_vector->next;
+ bNodeSocket *sock_out_first_int = sock_out_first_float->next;
+ bNodeSocket *sock_out_total_vector = sock_out_first_int->next;
+ bNodeSocket *sock_out_total_float = sock_out_total_vector->next;
+ bNodeSocket *sock_out_total_int = sock_out_total_float->next;
+
+ nodeSetSocketAvailability(ntree, sock_in_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_in_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_in_int, data_type == CD_PROP_INT32);
+
+ nodeSetSocketAvailability(ntree, sock_out_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_out_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_out_int, data_type == CD_PROP_INT32);
+
+ nodeSetSocketAvailability(ntree, sock_out_first_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_out_first_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_out_first_int, data_type == CD_PROP_INT32);
+
+ nodeSetSocketAvailability(ntree, sock_out_total_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_out_total_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_out_total_int, data_type == CD_PROP_INT32);
+}
+
+enum class AccumulationMode { Leading = 0, Trailing = 1 };
+
+static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+{
+ switch (socket.type) {
+ case SOCK_FLOAT:
+ return CD_PROP_FLOAT;
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ return CD_PROP_INT32;
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ return CD_PROP_FLOAT3;
+ default:
+ return {};
+ }
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ if (!type) {
+ return;
+ }
+ if (params.in_out() == SOCK_OUT) {
+ params.add_item(
+ IFACE_("Leading"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Leading");
+ },
+ 0);
+ params.add_item(
+ IFACE_("Trailing"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Trailing");
+ },
+ -1);
+ params.add_item(
+ IFACE_("Total"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Total");
+ },
+ -2);
+ }
+ else {
+ params.add_item(
+ IFACE_("Value"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Value");
+ },
+ 0);
+
+ params.add_item(
+ IFACE_("Group Index"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Group Index");
+ },
+ -1);
+ }
+}
+
+template<typename T> class AccumulateFieldInput final : public GeometryFieldInput {
+ private:
+ Field<T> input_;
+ Field<int> group_index_;
+ AttributeDomain source_domain_;
+ AccumulationMode accumulation_mode_;
+
+ public:
+ AccumulateFieldInput(const AttributeDomain source_domain,
+ Field<T> input,
+ Field<int> group_index,
+ AccumulationMode accumulation_mode)
+ : GeometryFieldInput(CPPType::get<T>(), "Accumulation"),
+ input_(input),
+ group_index_(group_index),
+ source_domain_(source_domain),
+ accumulation_mode_(accumulation_mode)
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ const GeometryComponentFieldContext field_context{component, source_domain_};
+ const int domain_size = component.attribute_domain_size(field_context.domain());
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(input_);
+ evaluator.add(group_index_);
+ evaluator.evaluate();
+ const VArray<T> &values = evaluator.get_evaluated<T>(0);
+ const VArray<int> &group_indices = evaluator.get_evaluated<int>(1);
+
+ Array<T> accumulations_out(domain_size);
+
+ if (group_indices.is_single()) {
+ T accumulation = T();
+ if (accumulation_mode_ == AccumulationMode::Leading) {
+ for (const int i : values.index_range()) {
+ accumulation = values[i] + accumulation;
+ accumulations_out[i] = accumulation;
+ }
+ }
+ else {
+ for (const int i : values.index_range()) {
+ accumulations_out[i] = accumulation;
+ accumulation = values[i] + accumulation;
+ }
+ }
+ }
+ else {
+ Map<int, T> accumulations;
+ if (accumulation_mode_ == AccumulationMode::Leading) {
+ for (const int i : values.index_range()) {
+ T &accumulation_value = accumulations.lookup_or_add_default(group_indices[i]);
+ accumulation_value += values[i];
+ accumulations_out[i] = accumulation_value;
+ }
+ }
+ else {
+ for (const int i : values.index_range()) {
+ T &accumulation_value = accumulations.lookup_or_add_default(group_indices[i]);
+ accumulations_out[i] = accumulation_value;
+ accumulation_value += values[i];
+ }
+ }
+ }
+
+ return component.attribute_try_adapt_domain<T>(
+ VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ return get_default_hash_4(input_, group_index_, source_domain_, accumulation_mode_);
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const AccumulateFieldInput *other_accumulate = dynamic_cast<const AccumulateFieldInput *>(
+ &other)) {
+ return input_ == other_accumulate->input_ &&
+ group_index_ == other_accumulate->group_index_ &&
+ source_domain_ == other_accumulate->source_domain_ &&
+ accumulation_mode_ == other_accumulate->accumulation_mode_;
+ }
+ return false;
+ }
+};
+
+template<typename T> class TotalFieldInput final : public GeometryFieldInput {
+ private:
+ Field<T> input_;
+ Field<int> group_index_;
+ AttributeDomain source_domain_;
+
+ public:
+ TotalFieldInput(const AttributeDomain source_domain, Field<T> input, Field<int> group_index)
+ : GeometryFieldInput(CPPType::get<T>(), "Total Value"),
+ input_(input),
+ group_index_(group_index),
+ source_domain_(source_domain)
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ const GeometryComponentFieldContext field_context{component, source_domain_};
+ const int domain_size = component.attribute_domain_size(field_context.domain());
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(input_);
+ evaluator.add(group_index_);
+ evaluator.evaluate();
+ const VArray<T> &values = evaluator.get_evaluated<T>(0);
+ const VArray<int> &group_indices = evaluator.get_evaluated<int>(1);
+
+ if (group_indices.is_single()) {
+ T accumulation = T();
+ for (const int i : values.index_range()) {
+ accumulation = values[i] + accumulation;
+ }
+ return VArray<T>::ForSingle(accumulation, domain_size);
+ }
+
+ Array<T> accumulations_out(domain_size);
+ Map<int, T> accumulations;
+ for (const int i : values.index_range()) {
+ T &value = accumulations.lookup_or_add_default(group_indices[i]);
+ value = value + values[i];
+ }
+ for (const int i : values.index_range()) {
+ accumulations_out[i] = accumulations.lookup(group_indices[i]);
+ }
+
+ return component.attribute_try_adapt_domain<T>(
+ VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ return get_default_hash_3(input_, group_index_, source_domain_);
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const TotalFieldInput *other_field = dynamic_cast<const TotalFieldInput *>(&other)) {
+ return input_ == other_field->input_ && group_index_ == other_field->group_index_ &&
+ source_domain_ == other_field->source_domain_;
+ }
+ return false;
+ }
+};
+
+template<typename T> std::string identifier_suffix()
+{
+ if constexpr (std::is_same_v<T, int>) {
+ return "Int";
+ }
+ if constexpr (std::is_same_v<T, float>) {
+ return "Float";
+ }
+ if constexpr (std::is_same_v<T, float3>) {
+ return "Vector";
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeAccumulateField &storage = node_storage(params.node());
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const AttributeDomain source_domain = static_cast<AttributeDomain>(storage.domain);
+
+ Field<int> group_index_field = params.extract_input<Field<int>>("Group Index");
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (std::is_same_v<T, int> || std::is_same_v<T, float> ||
+ std::is_same_v<T, float3>) {
+ const std::string suffix = " " + identifier_suffix<T>();
+ Field<T> input_field = params.extract_input<Field<T>>("Value" + suffix);
+ if (params.output_is_required("Leading" + suffix)) {
+ params.set_output(
+ "Leading" + suffix,
+ Field<T>{std::make_shared<AccumulateFieldInput<T>>(
+ source_domain, input_field, group_index_field, AccumulationMode::Leading)});
+ }
+ if (params.output_is_required("Trailing" + suffix)) {
+ params.set_output(
+ "Trailing" + suffix,
+ Field<T>{std::make_shared<AccumulateFieldInput<T>>(
+ source_domain, input_field, group_index_field, AccumulationMode::Trailing)});
+ }
+ if (params.output_is_required("Total" + suffix)) {
+ params.set_output("Total" + suffix,
+ Field<T>{std::make_shared<TotalFieldInput<T>>(
+ source_domain, input_field, group_index_field)});
+ }
+ }
+ });
+}
+} // namespace blender::nodes::node_geo_accumulate_field_cc
+
+void register_node_type_geo_accumulate_field()
+{
+ namespace file_ns = blender::nodes::node_geo_accumulate_field_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_ACCUMULATE_FIELD, "Accumulate Field", NODE_CLASS_CONVERTER);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
+ node_type_storage(
+ &ntype, "NodeAccumulateField", node_free_standard_storage, node_copy_standard_storage);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
index 43fb00a482c..840dfd2fbd3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -19,51 +19,51 @@
#include "BKE_attribute_math.hh"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_attribute_capture_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryAttributeCapture)
-static void geo_node_attribute_capture_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Vector>("Value").supports_field();
- b.add_input<decl::Float>("Value", "Value_001").supports_field();
- b.add_input<decl::Color>("Value", "Value_002").supports_field();
- b.add_input<decl::Bool>("Value", "Value_003").supports_field();
- b.add_input<decl::Int>("Value", "Value_004").supports_field();
-
- b.add_output<decl::Geometry>("Geometry");
- b.add_output<decl::Vector>("Attribute").field_source();
- b.add_output<decl::Float>("Attribute", "Attribute_001").field_source();
- b.add_output<decl::Color>("Attribute", "Attribute_002").field_source();
- b.add_output<decl::Bool>("Attribute", "Attribute_003").field_source();
- b.add_output<decl::Int>("Attribute", "Attribute_004").field_source();
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Vector>(N_("Value")).supports_field();
+ b.add_input<decl::Float>(N_("Value"), "Value_001").supports_field();
+ b.add_input<decl::Color>(N_("Value"), "Value_002").supports_field();
+ b.add_input<decl::Bool>(N_("Value"), "Value_003").supports_field();
+ b.add_input<decl::Int>(N_("Value"), "Value_004").supports_field();
+
+ b.add_output<decl::Geometry>(N_("Geometry"));
+ b.add_output<decl::Vector>(N_("Attribute")).field_source();
+ b.add_output<decl::Float>(N_("Attribute"), "Attribute_001").field_source();
+ b.add_output<decl::Color>(N_("Attribute"), "Attribute_002").field_source();
+ b.add_output<decl::Bool>(N_("Attribute"), "Attribute_003").field_source();
+ b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").field_source();
}
-static void geo_node_attribute_capture_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
-static void geo_node_attribute_capture_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryAttributeCapture *data = (NodeGeometryAttributeCapture *)MEM_callocN(
- sizeof(NodeGeometryAttributeCapture), __func__);
+ NodeGeometryAttributeCapture *data = MEM_cnew<NodeGeometryAttributeCapture>(__func__);
data->data_type = CD_PROP_FLOAT;
data->domain = ATTR_DOMAIN_POINT;
node->storage = data;
}
-static void geo_node_attribute_capture_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *)
- node->storage;
+ const NodeGeometryAttributeCapture &storage = node_storage(*node);
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
bNodeSocket *socket_value_geometry = (bNodeSocket *)node->inputs.first;
@@ -73,11 +73,11 @@ static void geo_node_attribute_capture_update(bNodeTree *UNUSED(ntree), bNode *n
bNodeSocket *socket_value_boolean = socket_value_color4f->next;
bNodeSocket *socket_value_int32 = socket_value_boolean->next;
- nodeSetSocketAvailability(socket_value_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(socket_value_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(socket_value_color4f, data_type == CD_PROP_COLOR);
- nodeSetSocketAvailability(socket_value_boolean, data_type == CD_PROP_BOOL);
- nodeSetSocketAvailability(socket_value_int32, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(ntree, socket_value_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, socket_value_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, socket_value_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, socket_value_boolean, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(ntree, socket_value_int32, data_type == CD_PROP_INT32);
bNodeSocket *out_socket_value_geometry = (bNodeSocket *)node->outputs.first;
bNodeSocket *out_socket_value_vector = out_socket_value_geometry->next;
@@ -86,11 +86,38 @@ static void geo_node_attribute_capture_update(bNodeTree *UNUSED(ntree), bNode *n
bNodeSocket *out_socket_value_boolean = out_socket_value_color4f->next;
bNodeSocket *out_socket_value_int32 = out_socket_value_boolean->next;
- nodeSetSocketAvailability(out_socket_value_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(out_socket_value_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(out_socket_value_color4f, data_type == CD_PROP_COLOR);
- nodeSetSocketAvailability(out_socket_value_boolean, data_type == CD_PROP_BOOL);
- nodeSetSocketAvailability(out_socket_value_int32, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(ntree, out_socket_value_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, out_socket_value_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, out_socket_value_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, out_socket_value_boolean, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(ntree, out_socket_value_int32, data_type == CD_PROP_INT32);
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+ search_link_ops_for_declarations(params, declaration.outputs().take_front(1));
+
+ const bNodeType &node_type = params.node_type();
+ const std::optional<CustomDataType> type = node_data_type_to_custom_data_type(
+ (eNodeSocketDatatype)params.other_socket().type);
+ if (type && *type != CD_PROP_STRING) {
+ if (params.in_out() == SOCK_OUT) {
+ params.add_item(IFACE_("Attribute"), [node_type, type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Attribute");
+ });
+ }
+ else {
+ params.add_item(IFACE_("Value"), [node_type, type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Value");
+ });
+ }
+ }
}
static void try_capture_field_on_geometry(GeometryComponent &component,
@@ -113,13 +140,11 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
output_attribute.save();
}
-static void geo_node_attribute_capture_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- const bNode &node = params.node();
- const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *)
- node.storage;
+ const NodeGeometryAttributeCapture &storage = node_storage(params.node());
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
@@ -144,20 +169,33 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params)
break;
}
- WeakAnonymousAttributeID anonymous_id{"Attribute Capture"};
+ WeakAnonymousAttributeID anonymous_id{"Attribute"};
const CPPType &type = field.cpp_type();
- static const Array<GeometryComponentType> types = {
- GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
- for (const GeometryComponentType type : types) {
- if (geometry_set.has(type)) {
- GeometryComponent &component = geometry_set.get_component_for_write(type);
+ /* Run on the instances component separately to only affect the top level of instances. */
+ if (domain == ATTR_DOMAIN_INSTANCE) {
+ if (geometry_set.has_instances()) {
+ GeometryComponent &component = geometry_set.get_component_for_write(
+ GEO_COMPONENT_TYPE_INSTANCES);
try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
}
}
+ else {
+ static const Array<GeometryComponentType> types = {
+ GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ for (const GeometryComponentType type : types) {
+ if (geometry_set.has(type)) {
+ GeometryComponent &component = geometry_set.get_component_for_write(type);
+ try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
+ }
+ }
+ });
+ }
- GField output_field{
- std::make_shared<bke::AnonymousAttributeFieldInput>(std::move(anonymous_id), type)};
+ GField output_field{std::make_shared<bke::AnonymousAttributeFieldInput>(
+ std::move(anonymous_id), type, params.attribute_producer_name())};
switch (data_type) {
case CD_PROP_FLOAT: {
@@ -187,22 +225,25 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_attribute_capture_cc
void register_node_type_geo_attribute_capture()
{
+ namespace file_ns = blender::nodes::node_geo_attribute_capture_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_ATTRIBUTE_CAPTURE, "Attribute Capture", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_CAPTURE_ATTRIBUTE, "Capture Attribute", NODE_CLASS_ATTRIBUTE);
node_type_storage(&ntype,
"NodeGeometryAttributeCapture",
node_free_standard_storage,
node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_capture_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_capture_update);
- ntype.declare = blender::nodes::geo_node_attribute_capture_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_capture_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_capture_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
new file mode 100644
index 00000000000..609ef39eb3f
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
@@ -0,0 +1,154 @@
+/*
+ * 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 "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_attribute_domain_size_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Geometry");
+ b.add_output<decl::Int>("Point Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_MESH;
+ });
+ b.add_output<decl::Int>("Edge Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_MESH;
+ });
+ b.add_output<decl::Int>("Face Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_MESH;
+ });
+ b.add_output<decl::Int>("Face Corner Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_MESH;
+ });
+ b.add_output<decl::Int>("Spline Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_CURVE;
+ });
+ b.add_output<decl::Int>("Instance Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_INSTANCES;
+ });
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "component", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ node->custom1 = GEO_COMPONENT_TYPE_MESH;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *point_socket = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *edge_socket = point_socket->next;
+ bNodeSocket *face_socket = edge_socket->next;
+ bNodeSocket *face_corner_socket = face_socket->next;
+ bNodeSocket *spline_socket = face_corner_socket->next;
+ bNodeSocket *instances_socket = spline_socket->next;
+
+ nodeSetSocketAvailability(ntree,
+ point_socket,
+ ELEM(node->custom1,
+ GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_POINT_CLOUD));
+ nodeSetSocketAvailability(ntree, edge_socket, node->custom1 == GEO_COMPONENT_TYPE_MESH);
+ nodeSetSocketAvailability(ntree, face_socket, node->custom1 == GEO_COMPONENT_TYPE_MESH);
+ nodeSetSocketAvailability(ntree, face_corner_socket, node->custom1 == GEO_COMPONENT_TYPE_MESH);
+ nodeSetSocketAvailability(ntree, spline_socket, node->custom1 == GEO_COMPONENT_TYPE_CURVE);
+ nodeSetSocketAvailability(
+ ntree, instances_socket, node->custom1 == GEO_COMPONENT_TYPE_INSTANCES);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometryComponentType component = (GeometryComponentType)params.node().custom1;
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ switch (component) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ if (geometry_set.has_mesh()) {
+ const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>();
+ params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT));
+ params.set_output("Edge Count", component->attribute_domain_size(ATTR_DOMAIN_EDGE));
+ params.set_output("Face Count", component->attribute_domain_size(ATTR_DOMAIN_FACE));
+ params.set_output("Face Corner Count",
+ component->attribute_domain_size(ATTR_DOMAIN_CORNER));
+ }
+ else {
+ params.set_default_remaining_outputs();
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ if (geometry_set.has_curve()) {
+ const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>();
+ params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT));
+ params.set_output("Spline Count", component->attribute_domain_size(ATTR_DOMAIN_CURVE));
+ }
+ else {
+ params.set_default_remaining_outputs();
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ if (geometry_set.has_pointcloud()) {
+ const PointCloudComponent *component =
+ geometry_set.get_component_for_read<PointCloudComponent>();
+ params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT));
+ }
+ else {
+ params.set_default_remaining_outputs();
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ if (geometry_set.has_instances()) {
+ const InstancesComponent *component =
+ geometry_set.get_component_for_read<InstancesComponent>();
+ params.set_output("Instance Count",
+ component->attribute_domain_size(ATTR_DOMAIN_INSTANCE));
+ }
+ else {
+ params.set_default_remaining_outputs();
+ }
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+}
+
+} // namespace blender::nodes::node_geo_attribute_domain_size_cc
+
+void register_node_type_geo_attribute_domain_size()
+{
+ namespace file_ns = blender::nodes::node_geo_attribute_domain_size_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, "Domain Size", NODE_CLASS_ATTRIBUTE);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.updatefunc = file_ns::node_update;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
index f93ef6f1db3..8ed50b2cc75 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
@@ -16,13 +16,13 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_attribute_remove_cc {
-static void geo_node_attribute_remove_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Attribute").multi_input();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Attribute")).multi_input();
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
static void remove_attribute(GeometryComponent &component,
@@ -42,7 +42,7 @@ static void remove_attribute(GeometryComponent &component,
}
}
-static void geo_node_attribute_remove_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Vector<std::string> attribute_names = params.extract_multi_input<std::string>("Attribute");
@@ -59,18 +59,23 @@ static void geo_node_attribute_remove_exec(GeoNodeExecParams params)
remove_attribute(
geometry_set.get_component_for_write<CurveComponent>(), params, attribute_names);
}
+ if (geometry_set.has<InstancesComponent>()) {
+ remove_attribute(
+ geometry_set.get_component_for_write<InstancesComponent>(), params, attribute_names);
+ }
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_attribute_remove_cc
void register_node_type_geo_attribute_remove()
{
+ namespace file_ns = blender::nodes::node_geo_attribute_remove_cc;
+
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_remove_exec;
- ntype.declare = blender::nodes::geo_node_attribute_remove_declare;
+ geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
index 1b7d2fe28a1..7df032b150b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
@@ -22,53 +22,55 @@
#include "BLI_math_base_safe.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_attribute_statistic_cc {
-static void geo_node_attribute_statistic_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Float>("Attribute").hide_value().supports_field();
- b.add_input<decl::Vector>("Attribute", "Attribute_001").hide_value().supports_field();
-
- b.add_output<decl::Float>("Mean");
- b.add_output<decl::Float>("Median");
- b.add_output<decl::Float>("Sum");
- b.add_output<decl::Float>("Min");
- b.add_output<decl::Float>("Max");
- b.add_output<decl::Float>("Range");
- b.add_output<decl::Float>("Standard Deviation");
- b.add_output<decl::Float>("Variance");
-
- b.add_output<decl::Vector>("Mean", "Mean_001");
- b.add_output<decl::Vector>("Median", "Median_001");
- b.add_output<decl::Vector>("Sum", "Sum_001");
- b.add_output<decl::Vector>("Min", "Min_001");
- b.add_output<decl::Vector>("Max", "Max_001");
- b.add_output<decl::Vector>("Range", "Range_001");
- b.add_output<decl::Vector>("Standard Deviation", "Standard Deviation_001");
- b.add_output<decl::Vector>("Variance", "Variance_001");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
+ b.add_input<decl::Float>(N_("Attribute")).hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Attribute"), "Attribute_001").hide_value().supports_field();
+
+ b.add_output<decl::Float>(N_("Mean"));
+ b.add_output<decl::Float>(N_("Median"));
+ b.add_output<decl::Float>(N_("Sum"));
+ b.add_output<decl::Float>(N_("Min"));
+ b.add_output<decl::Float>(N_("Max"));
+ b.add_output<decl::Float>(N_("Range"));
+ b.add_output<decl::Float>(N_("Standard Deviation"));
+ b.add_output<decl::Float>(N_("Variance"));
+
+ b.add_output<decl::Vector>(N_("Mean"), "Mean_001");
+ b.add_output<decl::Vector>(N_("Median"), "Median_001");
+ b.add_output<decl::Vector>(N_("Sum"), "Sum_001");
+ b.add_output<decl::Vector>(N_("Min"), "Min_001");
+ b.add_output<decl::Vector>(N_("Max"), "Max_001");
+ b.add_output<decl::Vector>(N_("Range"), "Range_001");
+ b.add_output<decl::Vector>(N_("Standard Deviation"), "Standard Deviation_001");
+ b.add_output<decl::Vector>(N_("Variance"), "Variance_001");
}
-static void geo_node_attribute_statistic_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
-static void geo_node_attribute_statistic_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
node->custom1 = CD_PROP_FLOAT;
node->custom2 = ATTR_DOMAIN_POINT;
}
-static void geo_node_attribute_statistic_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *socket_geo = (bNodeSocket *)node->inputs.first;
- bNodeSocket *socket_float_attr = socket_geo->next;
+ bNodeSocket *socket_selection = socket_geo->next;
+ bNodeSocket *socket_float_attr = socket_selection->next;
bNodeSocket *socket_float3_attr = socket_float_attr->next;
bNodeSocket *socket_float_mean = (bNodeSocket *)node->outputs.first;
@@ -91,25 +93,70 @@ static void geo_node_attribute_statistic_update(bNodeTree *UNUSED(ntree), bNode
const CustomDataType data_type = static_cast<CustomDataType>(node->custom1);
- nodeSetSocketAvailability(socket_float_attr, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(socket_float_mean, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(socket_float_median, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(socket_float_sum, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(socket_float_min, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(socket_float_max, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(socket_float_range, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(socket_float_std, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(socket_float_variance, data_type == CD_PROP_FLOAT);
-
- nodeSetSocketAvailability(socket_float3_attr, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(socket_vector_mean, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(socket_vector_median, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(socket_vector_sum, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(socket_vector_min, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(socket_vector_max, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(socket_vector_range, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(socket_vector_std, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(socket_vector_variance, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, socket_float_attr, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, socket_float_mean, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, socket_float_median, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, socket_float_sum, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, socket_float_min, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, socket_float_max, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, socket_float_range, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, socket_float_std, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, socket_float_variance, data_type == CD_PROP_FLOAT);
+
+ nodeSetSocketAvailability(ntree, socket_float3_attr, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, socket_vector_mean, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, socket_vector_median, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, socket_vector_sum, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, socket_vector_min, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, socket_vector_max, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, socket_vector_range, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, socket_vector_std, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, socket_vector_variance, data_type == CD_PROP_FLOAT3);
+}
+
+static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+{
+ switch (socket.type) {
+ case SOCK_FLOAT:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ return CD_PROP_FLOAT;
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ return CD_PROP_FLOAT3;
+ default:
+ return {};
+ }
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const bNodeType &node_type = params.node_type();
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(2));
+
+ const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ if (!type) {
+ return;
+ }
+
+ if (params.in_out() == SOCK_IN) {
+ params.add_item(IFACE_("Attribute"), [node_type, type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node.custom1 = *type;
+ params.update_and_connect_available_socket(node, "Attribute");
+ });
+ }
+ else {
+ for (const StringRefNull name :
+ {"Mean", "Median", "Sum", "Min", "Max", "Range", "Standard Deviation", "Variance"}) {
+ params.add_item(IFACE_(name.c_str()), [node_type, name, type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node.custom1 = *type;
+ params.update_and_connect_available_socket(node, name);
+ });
+ }
+ }
}
template<typename T> static T compute_sum(const Span<T> data)
@@ -146,65 +193,40 @@ static float median_of_sorted_span(const Span<float> data)
}
return median;
}
-static void set_empty(CustomDataType data_type, GeoNodeExecParams &params)
-{
- if (data_type == CD_PROP_FLOAT) {
- params.set_output("Mean", 0.0f);
- params.set_output("Median", 0.0f);
- params.set_output("Sum", 0.0f);
- params.set_output("Min", 0.0f);
- params.set_output("Max", 0.0f);
- params.set_output("Range", 0.0f);
- params.set_output("Standard Deviation", 0.0f);
- params.set_output("Variance", 0.0f);
- }
- else if (data_type == CD_PROP_FLOAT3) {
- params.set_output("Mean_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Median_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Sum_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Min_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Max_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Range_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Standard Deviation_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Variance_001", float3{0.0f, 0.0f, 0.0f});
- }
-}
-static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.get_input<GeometrySet>("Geometry");
-
const bNode &node = params.node();
const CustomDataType data_type = static_cast<CustomDataType>(node.custom1);
const AttributeDomain domain = static_cast<AttributeDomain>(node.custom2);
-
- int64_t total_size = 0;
Vector<const GeometryComponent *> components = geometry_set.get_components_for_read();
- for (const GeometryComponent *component : components) {
- if (component->attribute_domain_supported(domain)) {
- total_size += component->attribute_domain_size(domain);
- }
- }
- if (total_size == 0) {
- set_empty(data_type, params);
- return;
- }
+ const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
switch (data_type) {
case CD_PROP_FLOAT: {
const Field<float> input_field = params.get_input<Field<float>>("Attribute");
- Array<float> data = Array<float>(total_size);
- int offset = 0;
+ Vector<float> data;
for (const GeometryComponent *component : components) {
if (component->attribute_domain_supported(domain)) {
GeometryComponentFieldContext field_context{*component, domain};
const int domain_size = component->attribute_domain_size(domain);
+
fn::FieldEvaluator data_evaluator{field_context, domain_size};
- MutableSpan<float> component_result = data.as_mutable_span().slice(offset, domain_size);
- data_evaluator.add_with_destination(input_field, component_result);
+ data_evaluator.add(input_field);
+ data_evaluator.set_selection(selection_field);
data_evaluator.evaluate();
- offset += domain_size;
+ const VArray<float> &component_data = data_evaluator.get_evaluated<float>(0);
+ const IndexMask selection = data_evaluator.get_evaluated_selection_as_mask();
+
+ const int next_data_index = data.size();
+ data.resize(next_data_index + selection.size());
+ MutableSpan<float> selected_data = data.as_mutable_span().slice(next_data_index,
+ selection.size());
+ for (const int i : selection.index_range()) {
+ selected_data[i] = component_data[selection[i]];
+ }
}
}
@@ -225,7 +247,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
const bool variance_required = params.output_is_required("Standard Deviation") ||
params.output_is_required("Variance");
- if (total_size != 0) {
+ if (data.size() != 0) {
if (sort_required) {
std::sort(data.begin(), data.end());
median = median_of_sorted_span(data);
@@ -236,7 +258,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
if (sum_required || variance_required) {
sum = compute_sum<float>(data);
- mean = sum / total_size;
+ mean = sum / data.size();
if (variance_required) {
variance = compute_variance(data, mean);
@@ -263,18 +285,26 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
case CD_PROP_FLOAT3: {
const Field<float3> input_field = params.get_input<Field<float3>>("Attribute_001");
-
- Array<float3> data = Array<float3>(total_size);
- int offset = 0;
+ Vector<float3> data;
for (const GeometryComponent *component : components) {
if (component->attribute_domain_supported(domain)) {
GeometryComponentFieldContext field_context{*component, domain};
const int domain_size = component->attribute_domain_size(domain);
+
fn::FieldEvaluator data_evaluator{field_context, domain_size};
- MutableSpan<float3> component_result = data.as_mutable_span().slice(offset, domain_size);
- data_evaluator.add_with_destination(input_field, component_result);
+ data_evaluator.add(input_field);
+ data_evaluator.set_selection(selection_field);
data_evaluator.evaluate();
- offset += domain_size;
+ const VArray<float3> &component_data = data_evaluator.get_evaluated<float3>(0);
+ const IndexMask selection = data_evaluator.get_evaluated_selection_as_mask();
+
+ const int next_data_index = data.size();
+ data.resize(data.size() + selection.size());
+ MutableSpan<float3> selected_data = data.as_mutable_span().slice(next_data_index,
+ selection.size());
+ for (const int i : selection.index_range()) {
+ selected_data[i] = component_data[selection[i]];
+ }
}
}
@@ -299,9 +329,9 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
Array<float> data_y;
Array<float> data_z;
if (sort_required || variance_required) {
- data_x.reinitialize(total_size);
- data_y.reinitialize(total_size);
- data_z.reinitialize(total_size);
+ data_x.reinitialize(data.size());
+ data_y.reinitialize(data.size());
+ data_z.reinitialize(data.size());
for (const int i : data.index_range()) {
data_x[i] = data[i].x;
data_y[i] = data[i].y;
@@ -309,7 +339,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
}
- if (total_size != 0) {
+ if (data.size() != 0) {
if (sort_required) {
std::sort(data_x.begin(), data_x.end());
std::sort(data_y.begin(), data_y.end());
@@ -326,7 +356,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
if (sum_required || variance_required) {
sum = compute_sum(data.as_span());
- mean = sum / total_size;
+ mean = sum / data.size();
if (variance_required) {
const float x_variance = compute_variance(data_x, mean.x);
@@ -360,19 +390,22 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_attribute_statistic_cc
void register_node_type_geo_attribute_statistic()
{
+ namespace file_ns = blender::nodes::node_geo_attribute_statistic_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_ATTRIBUTE_STATISTIC, "Attribute Statistic", NODE_CLASS_ATTRIBUTE, 0);
-
- ntype.declare = blender::nodes::geo_node_attribute_statistic_declare;
- node_type_init(&ntype, blender::nodes::geo_node_attribute_statistic_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_statistic_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_statistic_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_statistic_layout;
+ &ntype, GEO_NODE_ATTRIBUTE_STATISTIC, "Attribute Statistic", NODE_CLASS_ATTRIBUTE);
+
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index 21b425c0ed4..a9158e0ef7a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -23,23 +23,25 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_boolean_cc {
-static void geo_node_boolean_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry 1");
- b.add_input<decl::Geometry>("Geometry 2").multi_input();
- b.add_input<decl::Bool>("Self Intersection");
- b.add_input<decl::Bool>("Hole Tolerant");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Mesh 1"))
+ .only_realized_data()
+ .supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Geometry>(N_("Mesh 2")).multi_input().supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Self Intersection"));
+ b.add_input<decl::Bool>(N_("Hole Tolerant"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_boolean_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
}
-static void geo_node_boolean_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)node->custom1;
@@ -49,24 +51,24 @@ static void geo_node_boolean_update(bNodeTree *UNUSED(ntree), bNode *node)
switch (operation) {
case GEO_NODE_BOOLEAN_INTERSECT:
case GEO_NODE_BOOLEAN_UNION:
- nodeSetSocketAvailability(geometry_1_socket, false);
- nodeSetSocketAvailability(geometry_2_socket, true);
- node_sock_label(geometry_2_socket, N_("Geometry"));
+ nodeSetSocketAvailability(ntree, geometry_1_socket, false);
+ nodeSetSocketAvailability(ntree, geometry_2_socket, true);
+ node_sock_label(geometry_2_socket, N_("Mesh"));
break;
case GEO_NODE_BOOLEAN_DIFFERENCE:
- nodeSetSocketAvailability(geometry_1_socket, true);
- nodeSetSocketAvailability(geometry_2_socket, true);
- node_sock_label(geometry_2_socket, N_("Geometry 2"));
+ nodeSetSocketAvailability(ntree, geometry_1_socket, true);
+ nodeSetSocketAvailability(ntree, geometry_2_socket, true);
+ node_sock_label(geometry_2_socket, N_("Mesh 2"));
break;
}
}
-static void geo_node_boolean_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
node->custom1 = GEO_NODE_BOOLEAN_DIFFERENCE;
}
-static void geo_node_boolean_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)params.node().custom1;
const bool use_self = params.get_input<bool>("Self Intersection");
@@ -82,12 +84,7 @@ static void geo_node_boolean_exec(GeoNodeExecParams params)
GeometrySet set_a;
if (operation == GEO_NODE_BOOLEAN_DIFFERENCE) {
- set_a = params.extract_input<GeometrySet>("Geometry 1");
- if (set_a.has_instances()) {
- params.error_message_add(
- NodeWarningType::Info,
- TIP_("Instances are not supported for the first geometry input, and will not be used"));
- }
+ set_a = params.extract_input<GeometrySet>("Mesh 1");
/* Note that it technically wouldn't be necessary to realize the instances for the first
* geometry input, but the boolean code expects the first shape for the difference operation
* to be a single mesh. */
@@ -101,7 +98,7 @@ static void geo_node_boolean_exec(GeoNodeExecParams params)
/* The instance transform matrices are owned by the instance group, so we have to
* keep all of them around for use during the boolean operation. */
Vector<bke::GeometryInstanceGroup> set_groups;
- Vector<GeometrySet> geometry_sets = params.extract_multi_input<GeometrySet>("Geometry 2");
+ Vector<GeometrySet> geometry_sets = params.extract_multi_input<GeometrySet>("Mesh 2");
for (const GeometrySet &geometry_set : geometry_sets) {
bke::geometry_set_gather_instances(geometry_set, set_groups);
}
@@ -119,20 +116,22 @@ static void geo_node_boolean_exec(GeoNodeExecParams params)
Mesh *result = blender::meshintersect::direct_mesh_boolean(
meshes, transforms, float4x4::identity(), {}, use_self, hole_tolerant, operation);
- params.set_output("Geometry", GeometrySet::create_with_mesh(result));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(result));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_boolean_cc
void register_node_type_geo_boolean()
{
+ namespace file_ns = blender::nodes::node_geo_boolean_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_BOOLEAN, "Boolean", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_boolean_declare;
- ntype.draw_buttons = blender::nodes::geo_node_boolean_layout;
- ntype.updatefunc = blender::nodes::geo_node_boolean_update;
- node_type_init(&ntype, blender::nodes::geo_node_boolean_init);
- ntype.geometry_node_execute = blender::nodes::geo_node_boolean_exec;
+ geo_node_type_base(&ntype, GEO_NODE_MESH_BOOLEAN, "Mesh Boolean", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.updatefunc = file_ns::node_update;
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
index fdc6b12095c..465bd72b57a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
@@ -14,160 +14,80 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "BKE_spline.hh"
-#include "BKE_volume.h"
-
#include "node_geometry_util.hh"
-namespace blender::nodes {
-
-static void geo_node_bounding_box_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>("Geometry");
- b.add_output<decl::Geometry>("Bounding Box");
- b.add_output<decl::Vector>("Min");
- b.add_output<decl::Vector>("Max");
-}
-
-using bke::GeometryInstanceGroup;
+namespace blender::nodes::node_geo_bounding_box_cc {
-static void compute_min_max_from_position_and_transform(const GeometryComponent &component,
- Span<float4x4> transforms,
- float3 &r_min,
- float3 &r_max)
+static void node_declare(NodeDeclarationBuilder &b)
{
- GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>(
- "position", ATTR_DOMAIN_POINT, {0, 0, 0});
-
- for (const float4x4 &transform : transforms) {
- for (const int i : positions.index_range()) {
- const float3 position = positions[i];
- const float3 transformed_position = transform * position;
- minmax_v3v3_v3(r_min, r_max, transformed_position);
- }
- }
-}
-
-static void compute_min_max_from_volume_and_transforms(const VolumeComponent &volume_component,
- Span<float4x4> transforms,
- float3 &r_min,
- float3 &r_max)
-{
-#ifdef WITH_OPENVDB
- const Volume *volume = volume_component.get_for_read();
- if (volume == nullptr) {
- return;
- }
- for (const int i : IndexRange(BKE_volume_num_grids(volume))) {
- const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, i);
- openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
-
- for (const float4x4 &transform : transforms) {
- openvdb::GridBase::ConstPtr instance_grid = BKE_volume_grid_shallow_transform(grid,
- transform);
- float3 grid_min = float3(FLT_MAX);
- float3 grid_max = float3(-FLT_MAX);
- if (BKE_volume_grid_bounds(instance_grid, grid_min, grid_max)) {
- DO_MIN(grid_min, r_min);
- DO_MAX(grid_max, r_max);
- }
- }
- }
-#else
- UNUSED_VARS(volume_component, transforms, r_min, r_max);
-#endif
-}
-
-static void compute_min_max_from_curve_and_transforms(const CurveComponent &curve_component,
- Span<float4x4> transforms,
- float3 &r_min,
- float3 &r_max)
-{
- const CurveEval *curve = curve_component.get_for_read();
- if (curve == nullptr) {
- return;
- }
- for (const SplinePtr &spline : curve->splines()) {
- Span<float3> positions = spline->evaluated_positions();
-
- for (const float4x4 &transform : transforms) {
- for (const int i : positions.index_range()) {
- const float3 position = positions[i];
- const float3 transformed_position = transform * position;
- minmax_v3v3_v3(r_min, r_max, transformed_position);
- }
- }
- }
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_output<decl::Geometry>(N_("Bounding Box"));
+ b.add_output<decl::Vector>(N_("Min"));
+ b.add_output<decl::Vector>(N_("Max"));
}
-static void compute_geometry_set_instances_boundbox(const GeometrySet &geometry_set,
- float3 &r_min,
- float3 &r_max)
-{
- Vector<GeometryInstanceGroup> set_groups;
- bke::geometry_set_gather_instances(geometry_set, set_groups);
-
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- Span<float4x4> transforms = set_group.transforms;
-
- if (set.has<PointCloudComponent>()) {
- compute_min_max_from_position_and_transform(
- *set.get_component_for_read<PointCloudComponent>(), transforms, r_min, r_max);
- }
- if (set.has<MeshComponent>()) {
- compute_min_max_from_position_and_transform(
- *set.get_component_for_read<MeshComponent>(), transforms, r_min, r_max);
- }
- if (set.has<VolumeComponent>()) {
- compute_min_max_from_volume_and_transforms(
- *set.get_component_for_read<VolumeComponent>(), transforms, r_min, r_max);
- }
- if (set.has<CurveComponent>()) {
- compute_min_max_from_curve_and_transforms(
- *set.get_component_for_read<CurveComponent>(), transforms, r_min, r_max);
- }
- }
-}
-
-static void geo_node_bounding_box_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ /* Compute the min and max of all realized geometry for the two
+ * vector outputs, which are only meant to consider real geometry. */
float3 min = float3(FLT_MAX);
float3 max = float3(-FLT_MAX);
-
- if (geometry_set.has_instances()) {
- compute_geometry_set_instances_boundbox(geometry_set, min, max);
- }
- else {
- geometry_set.compute_boundbox_without_instances(&min, &max);
- }
-
+ geometry_set.compute_boundbox_without_instances(&min, &max);
if (min == float3(FLT_MAX)) {
- params.set_output("Bounding Box", GeometrySet());
params.set_output("Min", float3(0));
params.set_output("Max", float3(0));
}
else {
- const float3 scale = max - min;
- const float3 center = min + scale / 2.0f;
- Mesh *mesh = create_cuboid_mesh(scale, 2, 2, 2);
- transform_mesh(mesh, center, float3(0), float3(1));
- params.set_output("Bounding Box", GeometrySet::create_with_mesh(mesh));
params.set_output("Min", min);
params.set_output("Max", max);
}
+
+ /* Generate the bounding box meshes inside each unique geometry set (including individually for
+ * every instance). Because geometry components are reference counted anyway, we can just
+ * repurpose the original geometry sets for the output. */
+ if (params.output_is_required("Bounding Box")) {
+ geometry_set.modify_geometry_sets([&](GeometrySet &sub_geometry) {
+ float3 sub_min = float3(FLT_MAX);
+ float3 sub_max = float3(-FLT_MAX);
+
+ /* Reuse the min and max calculation if this is the main "real" geometry set. */
+ if (&sub_geometry == &geometry_set) {
+ sub_min = min;
+ sub_max = max;
+ }
+ else {
+ sub_geometry.compute_boundbox_without_instances(&sub_min, &sub_max);
+ }
+
+ if (sub_min == float3(FLT_MAX)) {
+ sub_geometry.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
+ }
+ else {
+ const float3 scale = sub_max - sub_min;
+ const float3 center = sub_min + scale / 2.0f;
+ Mesh *mesh = create_cuboid_mesh(scale, 2, 2, 2);
+ transform_mesh(*mesh, center, float3(0), float3(1));
+ sub_geometry.replace_mesh(mesh);
+ sub_geometry.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
+ }
+ });
+
+ params.set_output("Bounding Box", std::move(geometry_set));
+ }
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_bounding_box_cc
void register_node_type_geo_bounding_box()
{
+ namespace file_ns = blender::nodes::node_geo_bounding_box_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_BOUNDING_BOX, "Bounding Box", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_bounding_box_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_bounding_box_exec;
+ geo_node_type_base(&ntype, GEO_NODE_BOUNDING_BOX, "Bounding Box", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
index d03221703f0..43816b8d8dc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
@@ -25,53 +25,67 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+#include <algorithm>
-static void geo_node_collection_info_declare(NodeDeclarationBuilder &b)
+namespace blender::nodes::node_geo_collection_info_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryCollectionInfo)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Collection>("Collection").hide_label();
- b.add_input<decl::Bool>("Separate Children")
- .description("Output each child of the collection as a separate instance");
- b.add_input<decl::Bool>("Reset Children")
+ b.add_input<decl::Collection>(N_("Collection")).hide_label();
+ b.add_input<decl::Bool>(N_("Separate Children"))
.description(
- "Reset the transforms of every child instance in the output. Only used when Separate "
- "Children is enabled");
- b.add_output<decl::Geometry>("Geometry");
+ N_("Output each child of the collection as a separate instance, sorted alphabetically"));
+ b.add_input<decl::Bool>(N_("Reset Children"))
+ .description(
+ N_("Reset the transforms of every child instance in the output. Only used when Separate "
+ "Children is enabled"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_collection_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_collection_info_node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCollectionInfo *data = (NodeGeometryCollectionInfo *)MEM_callocN(
- sizeof(NodeGeometryCollectionInfo), __func__);
+ NodeGeometryCollectionInfo *data = MEM_cnew<NodeGeometryCollectionInfo>(__func__);
data->transform_space = GEO_NODE_TRANSFORM_SPACE_ORIGINAL;
node->storage = data;
}
-static void geo_node_collection_info_exec(GeoNodeExecParams params)
+struct InstanceListEntry {
+ int handle;
+ char *name;
+ float4x4 transform;
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
{
Collection *collection = params.get_input<Collection *>("Collection");
- GeometrySet geometry_set_out;
-
if (collection == nullptr) {
- params.set_output("Geometry", geometry_set_out);
+ params.set_default_remaining_outputs();
+ return;
+ }
+ const Object *self_object = params.self_object();
+ const bool is_recursive = BKE_collection_has_object_recursive_instanced(collection,
+ (Object *)self_object);
+ if (is_recursive) {
+ params.error_message_add(NodeWarningType::Error, "Collection contains current object");
+ params.set_default_remaining_outputs();
return;
}
- const bNode &bnode = params.node();
- NodeGeometryCollectionInfo *node_storage = (NodeGeometryCollectionInfo *)bnode.storage;
- const bool use_relative_transform = (node_storage->transform_space ==
+ const NodeGeometryCollectionInfo &storage = node_storage(params.node());
+ const bool use_relative_transform = (storage.transform_space ==
GEO_NODE_TRANSFORM_SPACE_RELATIVE);
+ GeometrySet geometry_set_out;
InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
- const Object *self_object = params.self_object();
-
const bool separate_children = params.get_input<bool>("Separate Children");
if (separate_children) {
const bool reset_children = params.get_input<bool>("Reset Children");
@@ -85,6 +99,8 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params)
}
instances.reserve(children_collections.size() + children_objects.size());
+ Vector<InstanceListEntry> entries;
+ entries.reserve(children_collections.size() + children_objects.size());
for (Collection *child_collection : children_collections) {
float4x4 transform = float4x4::identity();
@@ -98,7 +114,7 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params)
}
}
const int handle = instances.add_reference(*child_collection);
- instances.add_instance(handle, transform);
+ entries.append({handle, &(child_collection->id.name[2]), transform});
}
for (Object *child_object : children_objects) {
const int handle = instances.add_reference(*child_object);
@@ -112,7 +128,16 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params)
}
mul_m4_m4_post(transform.values, child_object->obmat);
}
- instances.add_instance(handle, transform);
+ entries.append({handle, &(child_object->id.name[2]), transform});
+ }
+
+ std::sort(entries.begin(),
+ entries.end(),
+ [](const InstanceListEntry &a, const InstanceListEntry &b) {
+ return BLI_strcasecmp_natural(a.name, b.name) <= 0;
+ });
+ for (const InstanceListEntry &entry : entries) {
+ instances.add_instance(entry.handle, entry.transform);
}
}
else {
@@ -129,20 +154,22 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set_out);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_collection_info_cc
void register_node_type_geo_collection_info()
{
+ namespace file_ns = blender::nodes::node_geo_collection_info_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::geo_node_collection_info_declare;
- node_type_init(&ntype, blender::nodes::geo_node_collection_info_node_init);
+ geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_node_init);
node_type_storage(&ntype,
"NodeGeometryCollectionInfo",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_collection_info_exec;
- ntype.draw_buttons = blender::nodes::geo_node_collection_info_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_common.cc b/source/blender/nodes/geometry/nodes/node_geo_common.cc
index e2bb7e9f939..093b4450657 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_common.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_common.cc
@@ -22,23 +22,21 @@
#include "node_common.h"
#include "node_geometry_util.hh"
-void register_node_type_geo_group(void)
+void register_node_type_geo_group()
{
static bNodeType ntype;
- node_type_base_custom(&ntype, "GeometryNodeGroup", "Group", NODE_CLASS_GROUP, 0);
+ node_type_base_custom(&ntype, "GeometryNodeGroup", "Group", NODE_CLASS_GROUP);
ntype.type = NODE_GROUP;
ntype.poll = geo_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
ntype.insert_link = node_insert_link_default;
- ntype.update_internal_links = node_update_internal_links_default;
ntype.rna_ext.srna = RNA_struct_find("GeometryNodeGroup");
BLI_assert(ntype.rna_ext.srna != nullptr);
RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
- node_type_socket_templates(&ntype, nullptr, nullptr);
node_type_size(&ntype, 140, 60, 400);
- node_type_label(&ntype, node_group_label);
+ ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
nodeRegisterType(&ntype);
@@ -53,7 +51,4 @@ void register_node_type_geo_custom_group(bNodeType *ntype)
if (ntype->insert_link == nullptr) {
ntype->insert_link = node_insert_link_default;
}
- if (ntype->update_internal_links == nullptr) {
- ntype->update_internal_links = node_update_internal_links_default;
- }
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
index 4377d32210d..11bb8a61df5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -28,12 +28,12 @@
# include "RBI_hull_api.h"
#endif
-namespace blender::nodes {
+namespace blender::nodes::node_geo_convex_hull_cc {
-static void geo_node_convex_hull_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_output<decl::Geometry>("Convex Hull");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_output<decl::Geometry>(N_("Convex Hull"));
}
using bke::GeometryInstanceGroup;
@@ -169,10 +169,10 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
span_count++;
const PointCloudComponent *component =
geometry_set.get_component_for_read<PointCloudComponent>();
- GVArray_Typed<float3> varray = component->attribute_get_for_read<float3>(
+ VArray<float3> varray = component->attribute_get_for_read<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
- total_size += varray->size();
- positions_span = varray->get_internal_span();
+ total_size += varray.size();
+ positions_span = varray.get_internal_span();
}
if (geometry_set.has_curve()) {
@@ -200,18 +200,18 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
if (geometry_set.has_mesh()) {
const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>();
- GVArray_Typed<float3> varray = component->attribute_get_for_read<float3>(
+ VArray<float3> varray = component->attribute_get_for_read<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
- varray->materialize(positions.as_mutable_span().slice(offset, varray.size()));
+ varray.materialize(positions.as_mutable_span().slice(offset, varray.size()));
offset += varray.size();
}
if (geometry_set.has_pointcloud()) {
const PointCloudComponent *component =
geometry_set.get_component_for_read<PointCloudComponent>();
- GVArray_Typed<float3> varray = component->attribute_get_for_read<float3>(
+ VArray<float3> varray = component->attribute_get_for_read<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
- varray->materialize(positions.as_mutable_span().slice(offset, varray.size()));
+ varray.materialize(positions.as_mutable_span().slice(offset, varray.size()));
offset += varray.size();
}
@@ -235,16 +235,16 @@ static void read_positions(const GeometryComponent &component,
Span<float4x4> transforms,
Vector<float3> *r_coords)
{
- GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>(
+ VArray<float3> positions = component.attribute_get_for_read<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
/* NOTE: could use convex hull operation here to
* cut out some vertices, before accumulating,
* but can also be done by the user beforehand. */
- r_coords->reserve(r_coords->size() + positions.size() * transforms.size());
+ r_coords->reserve(r_coords->size() + positions->size() * transforms.size());
for (const float4x4 &transform : transforms) {
- for (const int i : positions.index_range()) {
+ for (const int i : positions->index_range()) {
const float3 position = positions[i];
const float3 transformed_position = transform * position;
r_coords->append(transformed_position);
@@ -296,7 +296,7 @@ static Mesh *convex_hull_from_instances(const GeometrySet &geometry_set)
#endif /* WITH_BULLET */
-static void geo_node_convex_hull_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -312,18 +312,20 @@ static void geo_node_convex_hull_exec(GeoNodeExecParams params)
#else
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without Bullet"));
- params.set_output("Convex Hull", geometry_set);
+ params.set_default_remaining_outputs();
#endif /* WITH_BULLET */
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_convex_hull_cc
void register_node_type_geo_convex_hull()
{
+ namespace file_ns = blender::nodes::node_geo_convex_hull_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CONVEX_HULL, "Convex Hull", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_convex_hull_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_convex_hull_exec;
+ geo_node_type_base(&ntype, GEO_NODE_CONVEX_HULL, "Convex Hull", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
new file mode 100644
index 00000000000..666100ffd7f
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
@@ -0,0 +1,147 @@
+/*
+ * 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 "BKE_spline.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_curve_endpoint_selection_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Start Size"))
+ .min(0)
+ .default_value(1)
+ .supports_field()
+ .description(N_("The amount of points to select from the start of each spline"));
+ b.add_input<decl::Int>(N_("End Size"))
+ .min(0)
+ .default_value(1)
+ .supports_field()
+ .description(N_("The amount of points to select from the end of each spline"));
+ b.add_output<decl::Bool>(N_("Selection"))
+ .field_source()
+ .description(
+ N_("The selection from the start and end of the splines based on the input sizes"));
+}
+
+static void select_by_spline(const int start, const int end, MutableSpan<bool> r_selection)
+{
+ const int size = r_selection.size();
+ const int start_use = std::min(start, size);
+ const int end_use = std::min(end, size);
+
+ r_selection.slice(0, start_use).fill(true);
+ r_selection.slice(size - end_use, end_use).fill(true);
+}
+
+class EndpointFieldInput final : public GeometryFieldInput {
+ Field<int> start_size_;
+ Field<int> end_size_;
+
+ public:
+ EndpointFieldInput(Field<int> start_size, Field<int> end_size)
+ : GeometryFieldInput(CPPType::get<bool>(), "Endpoint Selection node"),
+ start_size_(start_size),
+ end_size_(end_size)
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) {
+ return nullptr;
+ }
+
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+
+ Array<int> control_point_offsets = curve->control_point_offsets();
+
+ if (curve == nullptr || control_point_offsets.last() == 0) {
+ return nullptr;
+ }
+
+ GeometryComponentFieldContext size_context{curve_component, ATTR_DOMAIN_CURVE};
+ fn::FieldEvaluator evaluator{size_context, curve->splines().size()};
+ evaluator.add(start_size_);
+ evaluator.add(end_size_);
+ evaluator.evaluate();
+ const VArray<int> &start_size = evaluator.get_evaluated<int>(0);
+ const VArray<int> &end_size = evaluator.get_evaluated<int>(1);
+
+ const int point_size = control_point_offsets.last();
+ Array<bool> selection(point_size, false);
+ int current_point = 0;
+ MutableSpan<bool> selection_span = selection.as_mutable_span();
+ for (int i : IndexRange(curve->splines().size())) {
+ const SplinePtr &spline = curve->splines()[i];
+ if (start_size[i] <= 0 && end_size[i] <= 0) {
+ selection_span.slice(current_point, spline->size()).fill(false);
+ }
+ else {
+ int start_use = std::max(start_size[i], 0);
+ int end_use = std::max(end_size[i], 0);
+ select_by_spline(start_use, end_use, selection_span.slice(current_point, spline->size()));
+ }
+ current_point += spline->size();
+ }
+ return VArray<bool>::ForContainer(std::move(selection));
+ };
+
+ uint64_t hash() const override
+ {
+ return get_default_hash_2(start_size_, end_size_);
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const EndpointFieldInput *other_endpoint = dynamic_cast<const EndpointFieldInput *>(
+ &other)) {
+ return start_size_ == other_endpoint->start_size_ && end_size_ == other_endpoint->end_size_;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> start_size = params.extract_input<Field<int>>("Start Size");
+ Field<int> end_size = params.extract_input<Field<int>>("End Size");
+ Field<bool> selection_field{std::make_shared<EndpointFieldInput>(start_size, end_size)};
+ params.set_output("Selection", std::move(selection_field));
+}
+} // namespace blender::nodes::node_geo_curve_endpoint_selection_cc
+
+void register_node_type_geo_curve_endpoint_selection()
+{
+ namespace file_ns = blender::nodes::node_geo_curve_endpoint_selection_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_CURVE_ENDPOINT_SELECTION, "Endpoint Selection", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
index c30741cf786..929d9046f98 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
@@ -16,7 +16,7 @@
#include "BLI_array.hh"
#include "BLI_delaunay_2d.h"
-#include "BLI_double2.hh"
+#include "BLI_math_vec_types.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -31,23 +31,24 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_fill_cc {
-static void geo_node_curve_fill_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveFill)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_output<decl::Geometry>("Mesh");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_curve_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_fill_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryCurveFill *data = (NodeGeometryCurveFill *)MEM_callocN(sizeof(NodeGeometryCurveFill),
- __func__);
+ NodeGeometryCurveFill *data = MEM_cnew<NodeGeometryCurveFill>(__func__);
data->mode = GEO_NODE_CURVE_FILL_MODE_TRIANGULATED;
node->storage = data;
@@ -147,11 +148,11 @@ static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCu
geometry_set.replace_curve(nullptr);
}
-static void geo_node_curve_fill_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- const NodeGeometryCurveFill &storage = *(const NodeGeometryCurveFill *)params.node().storage;
+ const NodeGeometryCurveFill &storage = node_storage(params.node());
const GeometryNodeCurveFillMode mode = (GeometryNodeCurveFillMode)storage.mode;
geometry_set.modify_geometry_sets(
@@ -160,19 +161,21 @@ static void geo_node_curve_fill_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_fill_cc
void register_node_type_geo_curve_fill()
{
+ namespace file_ns = blender::nodes::node_geo_curve_fill_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_FILL, "Curve Fill", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_FILL_CURVE, "Fill Curve", NODE_CLASS_GEOMETRY);
- node_type_init(&ntype, blender::nodes::geo_node_curve_fill_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeGeometryCurveFill", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_fill_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_fill_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_fill_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
index 67ce20efd9d..68b609f8045 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -25,30 +25,37 @@
#include "BKE_spline.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_fillet_cc {
-static void geo_node_curve_fillet_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveFillet)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::Int>("Count").default_value(1).min(1).max(1000);
- b.add_input<decl::Float>("Radius")
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Int>(N_("Count"))
+ .default_value(1)
+ .min(1)
+ .max(1000)
+ .supports_field()
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_FILLET_POLY; });
+ b.add_input<decl::Float>(N_("Radius"))
.min(0.0f)
.max(FLT_MAX)
.subtype(PropertySubType::PROP_DISTANCE)
- .default_value(0.25f);
- b.add_input<decl::Bool>("Limit Radius");
- b.add_output<decl::Geometry>("Curve");
+ .default_value(0.25f)
+ .supports_field();
+ b.add_input<decl::Bool>(N_("Limit Radius"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_fillet_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_fillet_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveFillet *data = (NodeGeometryCurveFillet *)MEM_callocN(
- sizeof(NodeGeometryCurveFillet), __func__);
+ NodeGeometryCurveFillet *data = MEM_cnew<NodeGeometryCurveFillet>(__func__);
data->mode = GEO_NODE_CURVE_FILLET_BEZIER;
node->storage = data;
@@ -58,10 +65,10 @@ struct FilletParam {
GeometryNodeCurveFilletMode mode;
/* Number of points to be added. */
- const VArray<int> *counts;
+ VArray<int> counts;
/* Radii for fillet arc at all vertices. */
- const VArray<float> *radii;
+ VArray<float> radii;
/* Whether or not fillets are allowed to overlap. */
bool limit_radius;
@@ -75,14 +82,14 @@ struct FilletData {
Array<int> counts;
};
-static void geo_node_curve_fillet_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryCurveFillet &node_storage = *(NodeGeometryCurveFillet *)node->storage;
- const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)node_storage.mode;
+ const NodeGeometryCurveFillet &storage = node_storage(*node);
+ const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)storage.mode;
bNodeSocket *poly_socket = ((bNodeSocket *)node->inputs.first)->next;
- nodeSetSocketAvailability(poly_socket, mode == GEO_NODE_CURVE_FILLET_POLY);
+ nodeSetSocketAvailability(ntree, poly_socket, mode == GEO_NODE_CURVE_FILLET_POLY);
}
/* Function to get the center of a fillet. */
@@ -115,9 +122,9 @@ static Array<float3> calculate_directions(const Span<float3> positions)
Array<float3> directions(size);
for (const int i : IndexRange(size - 1)) {
- directions[i] = (positions[i + 1] - positions[i]).normalized();
+ directions[i] = math::normalize(positions[i + 1] - positions[i]);
}
- directions[size - 1] = (positions[0] - positions[size - 1]).normalized();
+ directions[size - 1] = math::normalize(positions[0] - positions[size - 1]);
return directions;
}
@@ -128,9 +135,9 @@ static Array<float3> calculate_axes(const Span<float3> directions)
const int size = directions.size();
Array<float3> axes(size);
- axes[0] = float3::cross(-directions[size - 1], directions[0]).normalized();
+ axes[0] = math::normalize(math::cross(-directions[size - 1], directions[0]));
for (const int i : IndexRange(1, size - 1)) {
- axes[i] = float3::cross(-directions[i - 1], directions[i]).normalized();
+ axes[i] = math::normalize(math::cross(-directions[i - 1], directions[i]));
}
return axes;
@@ -159,7 +166,7 @@ static Array<int> calculate_counts(const FilletParam &fillet_param,
Array<int> counts(size, 1);
if (fillet_param.mode == GEO_NODE_CURVE_FILLET_POLY) {
for (const int i : IndexRange(size)) {
- counts[i] = (*fillet_param.counts)[spline_offset + i];
+ counts[i] = fillet_param.counts[spline_offset + i];
}
}
if (!cyclic) {
@@ -177,12 +184,12 @@ static Array<float> calculate_radii(const FilletParam &fillet_param,
Array<float> radii(size, 0.0f);
if (fillet_param.limit_radius) {
for (const int i : IndexRange(size)) {
- radii[i] = std::max((*fillet_param.radii)[spline_offset + i], 0.0f);
+ radii[i] = std::max(fillet_param.radii[spline_offset + i], 0.0f);
}
}
else {
for (const int i : IndexRange(size)) {
- radii[i] = (*fillet_param.radii)[spline_offset + i];
+ radii[i] = fillet_param.radii[spline_offset + i];
}
}
@@ -241,8 +248,8 @@ static void limit_radii(FilletData &fd, const bool cyclic)
if (cyclic) {
/* Calculate lengths between adjacent control points. */
- const float len_prev = float3::distance(positions[0], positions[size - 1]);
- const float len_next = float3::distance(positions[0], positions[1]);
+ const float len_prev = math::distance(positions[0], positions[size - 1]);
+ const float len_next = math::distance(positions[0], positions[1]);
/* Calculate tangent lengths of fillets in control points. */
const float tan_len = radii[0] * tan(angles[0] / 2.0f);
@@ -264,16 +271,16 @@ static void limit_radii(FilletData &fd, const bool cyclic)
}
/* Initialize max_radii to largest possible radii. */
- float prev_dist = float3::distance(positions[1], positions[0]);
+ float prev_dist = math::distance(positions[1], positions[0]);
for (const int i : IndexRange(1, size - 2)) {
- const float temp_dist = float3::distance(positions[i], positions[i + 1]);
+ const float temp_dist = math::distance(positions[i], positions[i + 1]);
max_radii[i] = std::min(prev_dist, temp_dist) / tan(angles[i] / 2.0f);
prev_dist = temp_dist;
}
/* Max radii calculations for each index. */
for (const int i : IndexRange(start, fillet_count - 1)) {
- const float len_next = float3::distance(positions[i], positions[i + 1]);
+ const float len_next = math::distance(positions[i], positions[i + 1]);
const float tan_len = radii[i] * tan(angles[i] / 2.0f);
const float tan_len_next = radii[i + 1] * tan(angles[i + 1] / 2.0f);
@@ -331,14 +338,17 @@ static void copy_common_attributes_by_mapping(const Spline &src,
copy_attribute_by_mapping(src.radii(), dst.radii(), mapping);
copy_attribute_by_mapping(src.tilts(), dst.tilts(), mapping);
- dst.attributes.reallocate(1);
src.attributes.foreach_attribute(
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
std::optional<GSpan> src_attribute = src.attributes.get_for_read(attribute_id);
if (dst.attributes.create(attribute_id, meta_data.data_type)) {
std::optional<GMutableSpan> dst_attribute = dst.attributes.get_for_write(attribute_id);
if (dst_attribute) {
- src_attribute->type().copy_assign(src_attribute->data(), dst_attribute->data());
+ attribute_math::convert_to_static_type(dst_attribute->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_attribute_by_mapping(
+ src_attribute->typed<T>(), dst_attribute->typed<T>(), mapping);
+ });
return true;
}
}
@@ -405,7 +415,8 @@ static void update_bezier_positions(const FilletData &fd,
const float3 center = get_center(dst_spline.positions()[i_dst] - positions[i_src], fd, i_src);
/* Calculate the vector of the radius formed by the first vertex. */
float3 radius_vec = dst_spline.positions()[i_dst] - center;
- const float radius = radius_vec.normalize_and_get_length();
+ float radius;
+ radius_vec = math::normalize_and_get_length(radius_vec, radius);
dst_spline.handle_types_right().slice(1, count - 2).fill(BezierSpline::HandleType::Align);
dst_spline.handle_types_left().slice(1, count - 2).fill(BezierSpline::HandleType::Align);
@@ -589,13 +600,13 @@ static void calculate_curve_fillet(GeometrySet &geometry_set,
field_evaluator.evaluate();
- fillet_param.radii = &field_evaluator.get_evaluated<float>(0);
- if (fillet_param.radii->is_single() && fillet_param.radii->get_internal_single() < 0.0f) {
+ fillet_param.radii = field_evaluator.get_evaluated<float>(0);
+ if (fillet_param.radii.is_single() && fillet_param.radii.get_internal_single() < 0.0f) {
return;
}
if (mode == GEO_NODE_CURVE_FILLET_POLY) {
- fillet_param.counts = &field_evaluator.get_evaluated<int>(1);
+ fillet_param.counts = field_evaluator.get_evaluated<int>(1);
}
fillet_param.limit_radius = limit_radius;
@@ -606,12 +617,12 @@ static void calculate_curve_fillet(GeometrySet &geometry_set,
geometry_set.replace_curve(output_curve.release());
}
-static void geo_node_fillet_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- NodeGeometryCurveFillet &node_storage = *(NodeGeometryCurveFillet *)params.node().storage;
- const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)node_storage.mode;
+ const NodeGeometryCurveFillet &storage = node_storage(params.node());
+ const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)storage.mode;
Field<float> radius_field = params.extract_input<Field<float>>("Radius");
const bool limit_radius = params.extract_input<bool>("Limit Radius");
@@ -628,19 +639,21 @@ static void geo_node_fillet_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_fillet_cc
void register_node_type_geo_curve_fillet()
{
+ namespace file_ns = blender::nodes::node_geo_curve_fillet_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_FILLET, "Curve Fillet", NODE_CLASS_GEOMETRY, 0);
- ntype.draw_buttons = blender::nodes::geo_node_curve_fillet_layout;
+ geo_node_type_base(&ntype, GEO_NODE_FILLET_CURVE, "Fillet Curve", NODE_CLASS_GEOMETRY);
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryCurveFillet", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_fillet_declare;
- node_type_init(&ntype, blender::nodes::geo_node_curve_fillet_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_fillet_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_fillet_exec;
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
new file mode 100644
index 00000000000..e4e87e519f7
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
@@ -0,0 +1,169 @@
+/*
+ * 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 "BKE_spline.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_curve_handle_type_selection_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryCurveSelectHandles)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Bool>(N_("Selection")).field_source();
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryCurveSelectHandles *data = MEM_cnew<NodeGeometryCurveSelectHandles>(__func__);
+
+ data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
+ data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
+ node->storage = data;
+}
+
+static BezierSpline::HandleType handle_type_from_input_type(const GeometryNodeCurveHandleType type)
+{
+ switch (type) {
+ case GEO_NODE_CURVE_HANDLE_AUTO:
+ return BezierSpline::HandleType::Auto;
+ case GEO_NODE_CURVE_HANDLE_ALIGN:
+ return BezierSpline::HandleType::Align;
+ case GEO_NODE_CURVE_HANDLE_FREE:
+ return BezierSpline::HandleType::Free;
+ case GEO_NODE_CURVE_HANDLE_VECTOR:
+ return BezierSpline::HandleType::Vector;
+ }
+ BLI_assert_unreachable();
+ return BezierSpline::HandleType::Auto;
+}
+
+static void select_by_handle_type(const CurveEval &curve,
+ const BezierSpline::HandleType type,
+ const GeometryNodeCurveHandleMode mode,
+ const MutableSpan<bool> r_selection)
+{
+ int offset = 0;
+ for (const SplinePtr &spline : curve.splines()) {
+ if (spline->type() != Spline::Type::Bezier) {
+ r_selection.slice(offset, spline->size()).fill(false);
+ offset += spline->size();
+ }
+ else {
+ BezierSpline *b = static_cast<BezierSpline *>(spline.get());
+ for (int i : IndexRange(b->size())) {
+ r_selection[offset++] = (mode & GEO_NODE_CURVE_HANDLE_LEFT &&
+ b->handle_types_left()[i] == type) ||
+ (mode & GEO_NODE_CURVE_HANDLE_RIGHT &&
+ b->handle_types_right()[i] == type);
+ }
+ }
+ }
+}
+
+class HandleTypeFieldInput final : public GeometryFieldInput {
+ BezierSpline::HandleType type_;
+ GeometryNodeCurveHandleMode mode_;
+
+ public:
+ HandleTypeFieldInput(BezierSpline::HandleType type, GeometryNodeCurveHandleMode mode)
+ : GeometryFieldInput(CPPType::get<bool>(), "Handle Type Selection node"),
+ type_(type),
+ mode_(mode)
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_CURVE) {
+ return {};
+ }
+
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve == nullptr) {
+ return {};
+ }
+
+ if (domain == ATTR_DOMAIN_POINT) {
+ Array<bool> selection(mask.min_array_size());
+ select_by_handle_type(*curve, type_, mode_, selection);
+ return VArray<bool>::ForContainer(std::move(selection));
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ return get_default_hash_2((int)mode_, (int)type_);
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const HandleTypeFieldInput *>(&other) != nullptr;
+ if (const HandleTypeFieldInput *other_handle_selection =
+ dynamic_cast<const HandleTypeFieldInput *>(&other)) {
+ return mode_ == other_handle_selection->mode_ && type_ == other_handle_selection->type_;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryCurveSelectHandles &storage = node_storage(params.node());
+ const BezierSpline::HandleType handle_type = handle_type_from_input_type(
+ (GeometryNodeCurveHandleType)storage.handle_type);
+ const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage.mode;
+
+ Field<bool> selection_field{std::make_shared<HandleTypeFieldInput>(handle_type, mode)};
+ params.set_output("Selection", std::move(selection_field));
+}
+
+} // namespace blender::nodes::node_geo_curve_handle_type_selection_cc
+
+void register_node_type_geo_curve_handle_type_selection()
+{
+ namespace file_ns = blender::nodes::node_geo_curve_handle_type_selection_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, "Handle Type Selection", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_storage(&ntype,
+ "NodeGeometryCurveSelectHandles",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ ntype.draw_buttons = file_ns::node_layout;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
index ac7df35bb72..21ae88a6852 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
@@ -17,19 +17,19 @@
#include "BKE_spline.hh"
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_length_cc {
-static void geo_node_curve_length_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_output<decl::Float>("Length");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_output<decl::Float>(N_("Length"));
}
-static void geo_node_curve_length_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
if (!curve_set.has_curve()) {
- params.set_output("Length", 0.0f);
+ params.set_default_remaining_outputs();
return;
}
const CurveEval &curve = *curve_set.get_curve_for_read();
@@ -40,14 +40,16 @@ static void geo_node_curve_length_exec(GeoNodeExecParams params)
params.set_output("Length", length);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_length_cc
void register_node_type_geo_curve_length()
{
+ namespace file_ns = blender::nodes::node_geo_curve_length_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_LENGTH, "Curve Length", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_length_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_length_exec;
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_LENGTH, "Curve Length", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc
deleted file mode 100644
index 90853387ec7..00000000000
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc
+++ /dev/null
@@ -1,206 +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.
- */
-
-#include "BLI_task.hh"
-
-#include "BKE_spline.hh"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes {
-
-static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b)
-{
- b.add_output<decl::Float>("Factor").field_source();
-}
-
-/**
- * A basic interpolation from the point domain to the spline domain would be useless, since the
- * average parameter for each spline would just be 0.5, or close to it. Instead, the parameter for
- * each spline is the portion of the total length at the start of the spline.
- */
-static Array<float> curve_parameter_spline_domain(const CurveEval &curve, const IndexMask mask)
-{
- Span<SplinePtr> splines = curve.splines();
- float length = 0.0f;
- Array<float> parameters(splines.size());
- for (const int i : splines.index_range()) {
- parameters[i] = length;
- length += splines[i]->length();
- }
- const float total_length_inverse = length == 0.0f ? 0.0f : 1.0f / length;
- mask.foreach_index([&](const int64_t i) { parameters[i] *= total_length_inverse; });
-
- return parameters;
-}
-
-/**
- * The parameter at each control point is the factor at the corresponding evaluated point.
- */
-static void calculate_bezier_parameters(const BezierSpline &spline, MutableSpan<float> parameters)
-{
- Span<int> offsets = spline.control_point_offsets();
- Span<float> lengths = spline.evaluated_lengths();
- const float total_length = spline.length();
- const float total_length_inverse = total_length == 0.0f ? 0.0f : 1.0f / total_length;
-
- for (const int i : IndexRange(1, spline.size() - 1)) {
- parameters[i] = lengths[offsets[i] - 1] * total_length_inverse;
- }
-}
-
-/**
- * The parameter for poly splines is simply the evaluated lengths divided by the total length.
- */
-static void calculate_poly_parameters(const PolySpline &spline, MutableSpan<float> parameters)
-{
- Span<float> lengths = spline.evaluated_lengths();
- const float total_length = spline.length();
- const float total_length_inverse = total_length == 0.0f ? 0.0f : 1.0f / total_length;
-
- for (const int i : IndexRange(1, spline.size() - 1)) {
- parameters[i] = lengths[i - 1] * total_length_inverse;
- }
-}
-
-/**
- * Since NURBS control points do not necessarily coincide with the evaluated curve's path, and
- * each control point doesn't correspond well to a specific evaluated point, the parameter at
- * each point is not well defined. So instead, treat the control points as if they were a poly
- * spline.
- */
-static void calculate_nurbs_parameters(const NURBSpline &spline, MutableSpan<float> parameters)
-{
- Span<float3> positions = spline.positions();
- Array<float> control_point_lengths(spline.size());
-
- float length = 0.0f;
- for (const int i : IndexRange(positions.size() - 1)) {
- parameters[i] = length;
- length += float3::distance(positions[i], positions[i + 1]);
- }
-
- const float total_length_inverse = length == 0.0f ? 0.0f : 1.0f / length;
- for (float &parameter : parameters) {
- parameter *= total_length_inverse;
- }
-}
-
-static Array<float> curve_parameter_point_domain(const CurveEval &curve)
-{
- Span<SplinePtr> splines = curve.splines();
- Array<int> offsets = curve.control_point_offsets();
- const int total_size = offsets.last();
- Array<float> parameters(total_size);
-
- threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
- for (const int i : range) {
- const Spline &spline = *splines[i];
- MutableSpan spline_factors{parameters.as_mutable_span().slice(offsets[i], spline.size())};
- spline_factors.first() = 0.0f;
- switch (splines[i]->type()) {
- case Spline::Type::Bezier: {
- calculate_bezier_parameters(static_cast<const BezierSpline &>(spline), spline_factors);
- break;
- }
- case Spline::Type::Poly: {
- calculate_poly_parameters(static_cast<const PolySpline &>(spline), spline_factors);
- break;
- }
- case Spline::Type::NURBS: {
- calculate_nurbs_parameters(static_cast<const NURBSpline &>(spline), spline_factors);
- break;
- }
- }
- }
- });
- return parameters;
-}
-
-static const GVArray *construct_curve_parameter_gvarray(const CurveEval &curve,
- const IndexMask mask,
- const AttributeDomain domain,
- ResourceScope &scope)
-{
- if (domain == ATTR_DOMAIN_POINT) {
- Array<float> parameters = curve_parameter_point_domain(curve);
- return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(parameters));
- }
-
- if (domain == ATTR_DOMAIN_CURVE) {
- Array<float> parameters = curve_parameter_spline_domain(curve, mask);
- return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(parameters));
- }
-
- return nullptr;
-}
-
-class CurveParameterFieldInput final : public fn::FieldInput {
- public:
- CurveParameterFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Parameter")
- {
- }
-
- const GVArray *get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const final
- {
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
-
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
- if (curve) {
- return construct_curve_parameter_gvarray(*curve, mask, domain, scope);
- }
- }
- }
- return nullptr;
- }
-
- uint64_t hash() const override
- {
- /* Some random constant hash. */
- return 29837456298;
- }
-
- bool is_equal_to(const fn::FieldNode &other) const override
- {
- return dynamic_cast<const CurveParameterFieldInput *>(&other) != nullptr;
- }
-};
-
-static void geo_node_curve_parameter_exec(GeoNodeExecParams params)
-{
- Field<float> parameter_field{std::make_shared<CurveParameterFieldInput>()};
- params.set_output("Factor", std::move(parameter_field));
-}
-
-} // namespace blender::nodes
-
-void register_node_type_geo_curve_parameter()
-{
- static bNodeType ntype;
-
- geo_node_type_base(&ntype, GEO_NODE_CURVE_PARAMETER, "Curve Parameter", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_parameter_exec;
- ntype.declare = blender::nodes::geo_node_curve_parameter_declare;
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
new file mode 100644
index 00000000000..3f6298168a2
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
@@ -0,0 +1,391 @@
+/*
+ * 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 "BKE_spline.hh"
+#include "BLI_math_base_safe.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+#include "node_geometry_util.hh"
+#include <numeric>
+
+namespace blender::nodes::node_geo_curve_primitive_arc_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveArc)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Resolution"))
+ .default_value(16)
+ .min(2)
+ .max(256)
+ .subtype(PROP_UNSIGNED)
+ .description(N_("The number of points on the arc"));
+ b.add_input<decl::Vector>(N_("Start"))
+ .default_value({-1.0f, 0.0f, 0.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Position of the first control point"));
+ b.add_input<decl::Vector>(N_("Middle"))
+ .default_value({0.0f, 2.0f, 0.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Position of the middle control point"));
+ b.add_input<decl::Vector>(N_("End"))
+ .default_value({1.0f, 0.0f, 0.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Position of the last control point"));
+ b.add_input<decl::Float>(N_("Radius"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Distance of the points from the origin"));
+ b.add_input<decl::Float>(N_("Start Angle"))
+ .default_value(0.0f)
+ .subtype(PROP_ANGLE)
+ .description(N_("Starting angle of the arc"));
+ b.add_input<decl::Float>(N_("Sweep Angle"))
+ .default_value(1.75f * M_PI)
+ .min(-2 * M_PI)
+ .max(2 * M_PI)
+ .subtype(PROP_ANGLE)
+ .description(N_("Length of the arc"));
+ b.add_input<decl::Float>(N_("Offset Angle"))
+ .default_value(0.0f)
+ .subtype(PROP_ANGLE)
+ .description(N_("Offset angle of the arc"));
+ b.add_input<decl::Bool>(N_("Connect Center"))
+ .default_value(false)
+ .description(N_("Connect the arc at the center"));
+ b.add_input<decl::Bool>(N_("Invert Arc"))
+ .default_value(false)
+ .description(N_("Invert and draw opposite arc"));
+
+ b.add_output<decl::Geometry>(N_("Curve"));
+ b.add_output<decl::Vector>(N_("Center"))
+ .description(N_("The center of the circle described by the three points"))
+ .make_available(
+ [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; });
+ b.add_output<decl::Vector>(N_("Normal"))
+ .description(N_("The normal direction of the plane described by the three points, pointing "
+ "towards the positive Z axis"))
+ .make_available(
+ [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; });
+ b.add_output<decl::Float>(N_("Radius"))
+ .description(N_("The radius of the circle described by the three points"))
+ .make_available(
+ [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; });
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryCurvePrimitiveArc *data = MEM_cnew<NodeGeometryCurvePrimitiveArc>(__func__);
+
+ data->mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeGeometryCurvePrimitiveArc &storage = node_storage(*node);
+ const GeometryNodeCurvePrimitiveArcMode mode = (GeometryNodeCurvePrimitiveArcMode)storage.mode;
+
+ bNodeSocket *start_socket = ((bNodeSocket *)node->inputs.first)->next;
+ bNodeSocket *middle_socket = start_socket->next;
+ bNodeSocket *end_socket = middle_socket->next;
+
+ bNodeSocket *radius_socket = end_socket->next;
+ bNodeSocket *start_angle_socket = radius_socket->next;
+ bNodeSocket *sweep_angle_socket = start_angle_socket->next;
+
+ bNodeSocket *offset_angle_socket = sweep_angle_socket->next;
+
+ bNodeSocket *center_out_socket = ((bNodeSocket *)node->outputs.first)->next;
+ bNodeSocket *normal_out_socket = center_out_socket->next;
+ bNodeSocket *radius_out_socket = normal_out_socket->next;
+
+ const bool radius_mode = (mode == GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS);
+ const bool points_mode = (mode == GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS);
+
+ nodeSetSocketAvailability(ntree, start_socket, points_mode);
+ nodeSetSocketAvailability(ntree, middle_socket, points_mode);
+ nodeSetSocketAvailability(ntree, end_socket, points_mode);
+
+ nodeSetSocketAvailability(ntree, radius_socket, radius_mode);
+ nodeSetSocketAvailability(ntree, start_angle_socket, radius_mode);
+ nodeSetSocketAvailability(ntree, sweep_angle_socket, radius_mode);
+
+ nodeSetSocketAvailability(ntree, offset_angle_socket, points_mode);
+
+ nodeSetSocketAvailability(ntree, center_out_socket, points_mode);
+ nodeSetSocketAvailability(ntree, normal_out_socket, points_mode);
+ nodeSetSocketAvailability(ntree, radius_out_socket, points_mode);
+}
+
+static float3 rotate_vector_around_axis(const float3 vector, const float3 axis, const float angle)
+{
+ float3 result = vector;
+ float mat[3][3];
+ axis_angle_to_mat3(mat, axis, angle);
+ mul_m3_v3(mat, result);
+ return result;
+}
+
+static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3)
+{
+ const float3 a = math::normalize(p2 - p1);
+ const float3 b = math::normalize(p3 - p1);
+ return (ELEM(a, b, b * -1.0f));
+}
+
+static std::unique_ptr<CurveEval> create_arc_curve_from_points(const int resolution,
+ const float3 a,
+ const float3 b,
+ const float3 c,
+ float angle_offset,
+ const bool connect_center,
+ const bool invert_arc,
+ float3 &r_center,
+ float3 &r_normal,
+ float &r_radius)
+{
+ std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+ std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+
+ if (connect_center) {
+ spline->resize(resolution + 1);
+ }
+ else {
+ spline->resize(resolution);
+ }
+
+ const int stepcount = resolution - 1;
+ const int centerpoint = resolution;
+ MutableSpan<float3> positions = spline->positions();
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+
+ const bool is_colinear = colinear_f3_f3_f3(a, b, c);
+
+ float3 center;
+ float3 normal;
+ float radius;
+ const float3 mid_ac = math::midpoint(a, c);
+ normal_tri_v3(normal, a, c, b);
+
+ if (is_colinear || a == c || a == b || b == c || resolution == 2) {
+ /* If colinear, generate a point line between points. */
+ float3 p1, p2;
+
+ /* Find the two points that are furthest away from each other. */
+ const float ab = math::distance_squared(a, b);
+ const float ac = math::distance_squared(a, c);
+ const float bc = math::distance_squared(b, c);
+ if (ab > ac && ab > bc) {
+ p1 = a;
+ p2 = b;
+ }
+ else if (bc > ab && bc > ac) {
+ p1 = b;
+ p2 = c;
+ }
+ else {
+ p1 = a;
+ p2 = c;
+ }
+
+ const float step = 1.0f / stepcount;
+ for (const int i : IndexRange(resolution)) {
+ const float factor = step * i;
+ positions[i] = math::interpolate(p1, p2, factor);
+ }
+ center = mid_ac;
+ radius = 0.0f;
+ }
+ else {
+ /* Midpoints of `A->B` and `B->C`. */
+ const float3 mid_ab = math::midpoint(a, b);
+ const float3 mid_bc = math::midpoint(c, b);
+
+ /* Normalized vectors of `A->B` and `B->C`. */
+ const float3 nba = math::normalize(b - a);
+ const float3 ncb = math::normalize(c - b);
+
+ /* Normal of plane of main 2 segments A->B and `B->C`. */
+ const float3 nabc = math::normalize(math::cross(nba, ncb));
+
+ /* Determine center point from the intersection of 3 planes. */
+ float plane_1[4], plane_2[4], plane_3[4];
+ plane_from_point_normal_v3(plane_1, mid_ab, nabc);
+ plane_from_point_normal_v3(plane_2, mid_ab, nba);
+ plane_from_point_normal_v3(plane_3, mid_bc, ncb);
+
+ /* If the 3 planes do not intersect at one point, just return empty geometry. */
+ if (!isect_plane_plane_plane_v3(plane_1, plane_2, plane_3, center)) {
+ r_center = mid_ac;
+ r_normal = normal;
+ r_radius = 0.0f;
+ return nullptr;
+ }
+
+ /* Radial vectors. */
+ const float3 rad_a = math::normalize(a - center);
+ const float3 rad_b = math::normalize(b - center);
+ const float3 rad_c = math::normalize(c - center);
+
+ /* Calculate angles. */
+ radius = math::distance(center, b);
+ float angle_ab = angle_signed_on_axis_v3v3_v3(rad_a, rad_b, normal) + 2.0f * M_PI;
+ float angle_ac = angle_signed_on_axis_v3v3_v3(rad_a, rad_c, normal) + 2.0f * M_PI;
+ float angle = (angle_ac > angle_ab) ? angle_ac : angle_ab;
+ angle -= 2.0f * M_PI;
+ if (invert_arc) {
+ angle = -(2.0f * M_PI - angle);
+ }
+
+ /* Create arc. */
+ const float step = angle / stepcount;
+ for (const int i : IndexRange(resolution)) {
+ const float factor = step * i + angle_offset;
+ float3 out = rotate_vector_around_axis(rad_a, -normal, factor);
+ positions[i] = out * radius + center;
+ }
+ }
+
+ if (connect_center) {
+ spline->set_cyclic(true);
+ positions[centerpoint] = center;
+ }
+
+ /* Ensure normal is relative to Z-up. */
+ if (math::dot(float3(0, 0, 1), normal) < 0) {
+ normal = -normal;
+ }
+
+ curve->add_spline(std::move(spline));
+ curve->attributes.reallocate(curve->splines().size());
+ r_center = center;
+ r_radius = radius;
+ r_normal = normal;
+ return curve;
+}
+
+static std::unique_ptr<CurveEval> create_arc_curve_from_radius(const int resolution,
+ const float radius,
+ const float start_angle,
+ const float sweep_angle,
+ const bool connect_center,
+ const bool invert_arc)
+{
+ std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+ std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+
+ if (connect_center) {
+ spline->resize(resolution + 1);
+ }
+ else {
+ spline->resize(resolution);
+ }
+
+ const int stepcount = resolution - 1;
+ const int centerpoint = resolution;
+ MutableSpan<float3> positions = spline->positions();
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+
+ const float sweep = (invert_arc) ? -(2.0f * M_PI - sweep_angle) : sweep_angle;
+
+ const float theta_step = sweep / float(stepcount);
+ for (const int i : IndexRange(resolution)) {
+ const float theta = theta_step * i + start_angle;
+ const float x = radius * cos(theta);
+ const float y = radius * sin(theta);
+ positions[i] = float3(x, y, 0.0f);
+ }
+
+ if (connect_center) {
+ spline->set_cyclic(true);
+ positions[centerpoint] = float3(0.0f, 0.0f, 0.0f);
+ }
+
+ curve->add_spline(std::move(spline));
+ curve->attributes.reallocate(curve->splines().size());
+ return curve;
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryCurvePrimitiveArc &storage = node_storage(params.node());
+
+ const GeometryNodeCurvePrimitiveArcMode mode = (GeometryNodeCurvePrimitiveArcMode)storage.mode;
+
+ switch (mode) {
+ case GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS: {
+ std::unique_ptr<CurveEval> curve;
+ float3 r_center, r_normal;
+ float r_radius;
+ curve = create_arc_curve_from_points(std::max(params.extract_input<int>("Resolution"), 2),
+ params.extract_input<float3>("Start"),
+ params.extract_input<float3>("Middle"),
+ params.extract_input<float3>("End"),
+ params.extract_input<float>("Offset Angle"),
+ params.extract_input<bool>("Connect Center"),
+ params.extract_input<bool>("Invert Arc"),
+ r_center,
+ r_normal,
+ r_radius);
+ params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Center", r_center);
+ params.set_output("Normal", r_normal);
+ params.set_output("Radius", r_radius);
+ break;
+ }
+ case GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS: {
+ std::unique_ptr<CurveEval> curve;
+ curve = create_arc_curve_from_radius(std::max(params.extract_input<int>("Resolution"), 2),
+ params.extract_input<float>("Radius"),
+ params.extract_input<float>("Start Angle"),
+ params.extract_input<float>("Sweep Angle"),
+ params.extract_input<bool>("Connect Center"),
+ params.extract_input<bool>("Invert Arc"));
+
+ params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ break;
+ }
+ }
+}
+
+} // namespace blender::nodes::node_geo_curve_primitive_arc_cc
+
+void register_node_type_geo_curve_primitive_arc()
+{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_arc_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_ARC, "Arc", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_storage(&ntype,
+ "NodeGeometryCurvePrimitiveArc",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
index 313473e3442..7d84ddf9917 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
@@ -21,31 +21,49 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc {
-static void geo_node_curve_primitive_bezier_segment_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveBezierSegment)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Resolution").default_value(16).min(1).max(256).subtype(PROP_UNSIGNED);
- b.add_input<decl::Vector>("Start").default_value({-1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Start Handle")
+ b.add_input<decl::Int>(N_("Resolution"))
+ .default_value(16)
+ .min(1)
+ .max(256)
+ .subtype(PROP_UNSIGNED)
+ .description(N_("The number of evaluated points on the curve"));
+ b.add_input<decl::Vector>(N_("Start"))
+ .default_value({-1.0f, 0.0f, 0.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Position of the start control point of the curve"));
+ b.add_input<decl::Vector>(N_("Start Handle"))
.default_value({-0.5f, 0.5f, 0.0f})
- .subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("End Handle").subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("End").default_value({1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION);
- b.add_output<decl::Geometry>("Curve");
+ .subtype(PROP_TRANSLATION)
+ .description(
+ N_("Position of the start handle used to define the shape of the curve. In Offset mode, "
+ "relative to Start point"));
+ b.add_input<decl::Vector>(N_("End Handle"))
+ .subtype(PROP_TRANSLATION)
+ .description(
+ N_("Position of the end handle used to define the shape of the curve. In Offset mode, "
+ "relative to End point"));
+ b.add_input<decl::Vector>(N_("End"))
+ .default_value({1.0f, 0.0f, 0.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Position of the end control point of the curve"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_primitive_bezier_segment_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_primitive_bezier_segment_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveBezierSegment *data = (NodeGeometryCurvePrimitiveBezierSegment *)
- MEM_callocN(sizeof(NodeGeometryCurvePrimitiveBezierSegment), __func__);
+ NodeGeometryCurvePrimitiveBezierSegment *data =
+ MEM_cnew<NodeGeometryCurvePrimitiveBezierSegment>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION;
node->storage = data;
@@ -61,53 +79,37 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve(
{
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>();
+ spline->set_resolution(resolution);
+
+ spline->resize(2);
+ MutableSpan<float3> positions = spline->positions();
+ spline->handle_types_left().fill(BezierSpline::HandleType::Align);
+ spline->handle_types_right().fill(BezierSpline::HandleType::Align);
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+
+ positions.first() = start;
+ positions.last() = end;
if (mode == GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION) {
- spline->add_point(start,
- BezierSpline::HandleType::Align,
- 2.0f * start - start_handle_right,
- BezierSpline::HandleType::Align,
- start_handle_right,
- 1.0f,
- 0.0f);
- spline->add_point(end,
- BezierSpline::HandleType::Align,
- end_handle_left,
- BezierSpline::HandleType::Align,
- 2.0f * end - end_handle_left,
- 1.0f,
- 0.0f);
+ spline->set_handle_position_right(0, start_handle_right);
+ spline->set_handle_position_left(1, end_handle_left);
}
else {
- spline->add_point(start,
- BezierSpline::HandleType::Align,
- start - start_handle_right,
- BezierSpline::HandleType::Align,
- start + start_handle_right,
- 1.0f,
- 0.0f);
- spline->add_point(end,
- BezierSpline::HandleType::Align,
- end + end_handle_left,
- BezierSpline::HandleType::Align,
- end - end_handle_left,
- 1.0f,
- 0.0f);
+ spline->set_handle_position_right(0, start + start_handle_right);
+ spline->set_handle_position_left(1, end + end_handle_left);
}
- spline->set_resolution(resolution);
- spline->attributes.reallocate(spline->size());
curve->add_spline(std::move(spline));
- curve->attributes.reallocate(curve->splines().size());
+ curve->attributes.reallocate(1);
return curve;
}
-static void geo_node_curve_primitive_bezier_segment_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurvePrimitiveBezierSegment *node_storage =
- (NodeGeometryCurvePrimitiveBezierSegment *)params.node().storage;
+ const NodeGeometryCurvePrimitiveBezierSegment &storage = node_storage(params.node());
const GeometryNodeCurvePrimitiveBezierSegmentMode mode =
- (const GeometryNodeCurvePrimitiveBezierSegmentMode)node_storage->mode;
+ (const GeometryNodeCurvePrimitiveBezierSegmentMode)storage.mode;
std::unique_ptr<CurveEval> curve = create_bezier_segment_curve(
params.extract_input<float3>("Start"),
@@ -119,20 +121,22 @@ static void geo_node_curve_primitive_bezier_segment_exec(GeoNodeExecParams param
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc
void register_node_type_geo_curve_primitive_bezier_segment()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_bezier_segment_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, "Bezier Segment", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_bezier_segment_init);
+ &ntype, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, "Bezier Segment", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurvePrimitiveBezierSegment",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_primitive_bezier_segment_declare;
- ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_bezier_segment_layout;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_bezier_segment_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
index f5eb83ea4fd..7b5d1a1dc80 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
@@ -21,43 +21,64 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_circle_cc {
-static void geo_node_curve_primitive_circle_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveCircle)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Resolution").default_value(32).min(3).max(512);
- b.add_input<decl::Vector>("Point 1")
+ b.add_input<decl::Int>(N_("Resolution"))
+ .default_value(32)
+ .min(3)
+ .max(512)
+ .description(N_("Number of points on the circle"));
+ b.add_input<decl::Vector>(N_("Point 1"))
.default_value({-1.0f, 0.0f, 0.0f})
- .subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Point 2").default_value({0.0f, 1.0f, 0.0f}).subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Point 3").default_value({1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION);
- b.add_input<decl::Float>("Radius").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Curve");
- b.add_output<decl::Vector>("Center");
+ .subtype(PROP_TRANSLATION)
+ .description(
+ N_("One of the three points on the circle. The point order determines the circle's "
+ "direction"));
+ b.add_input<decl::Vector>(N_("Point 2"))
+ .default_value({0.0f, 1.0f, 0.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(
+ N_("One of the three points on the circle. The point order determines the circle's "
+ "direction"));
+ b.add_input<decl::Vector>(N_("Point 3"))
+ .default_value({1.0f, 0.0f, 0.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(
+ N_("One of the three points on the circle. The point order determines the circle's "
+ "direction"));
+ b.add_input<decl::Float>(N_("Radius"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Distance of the points from the origin"));
+ b.add_output<decl::Geometry>(N_("Curve"));
+ b.add_output<decl::Vector>(N_("Center")).make_available([](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS;
+ });
}
-static void geo_node_curve_primitive_circle_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_primitive_circle_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveCircle *data = (NodeGeometryCurvePrimitiveCircle *)MEM_callocN(
- sizeof(NodeGeometryCurvePrimitiveCircle), __func__);
+ NodeGeometryCurvePrimitiveCircle *data = MEM_cnew<NodeGeometryCurvePrimitiveCircle>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS;
node->storage = data;
}
-static void geo_node_curve_primitive_circle_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryCurvePrimitiveCircle *node_storage = (NodeGeometryCurvePrimitiveCircle *)
- node->storage;
- const GeometryNodeCurvePrimitiveCircleMode mode = (const GeometryNodeCurvePrimitiveCircleMode)
- node_storage->mode;
+ const NodeGeometryCurvePrimitiveCircle &storage = node_storage(*node);
+ const GeometryNodeCurvePrimitiveCircleMode mode = (GeometryNodeCurvePrimitiveCircleMode)
+ storage.mode;
bNodeSocket *start_socket = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *middle_socket = start_socket->next;
@@ -66,18 +87,23 @@ static void geo_node_curve_primitive_circle_update(bNodeTree *UNUSED(ntree), bNo
bNodeSocket *center_socket = ((bNodeSocket *)node->outputs.first)->next;
- nodeSetSocketAvailability(start_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS);
- nodeSetSocketAvailability(middle_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS);
- nodeSetSocketAvailability(end_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS);
- nodeSetSocketAvailability(center_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS);
- nodeSetSocketAvailability(radius_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS);
+ nodeSetSocketAvailability(
+ ntree, start_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS);
+ nodeSetSocketAvailability(
+ ntree, middle_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS);
+ nodeSetSocketAvailability(
+ ntree, end_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS);
+ nodeSetSocketAvailability(
+ ntree, center_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS);
+ nodeSetSocketAvailability(
+ ntree, radius_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS);
}
static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3)
{
- const float3 a = (p2 - p1).normalized();
- const float3 b = (p3 - p1).normalized();
- return (a == b || a == b * -1.0f);
+ const float3 a = math::normalize(p2 - p1);
+ const float3 b = math::normalize(p3 - p1);
+ return (ELEM(a, b, b * -1.0f));
}
static std::unique_ptr<CurveEval> create_point_circle_curve(
@@ -96,18 +122,18 @@ static std::unique_ptr<CurveEval> create_point_circle_curve(
float3 center;
/* Midpoints of `P1->P2` and `P2->P3`. */
- const float3 q1 = float3::interpolate(p1, p2, 0.5f);
- const float3 q2 = float3::interpolate(p2, p3, 0.5f);
+ const float3 q1 = math::interpolate(p1, p2, 0.5f);
+ const float3 q2 = math::interpolate(p2, p3, 0.5f);
/* Normal Vectors of `P1->P2` and `P2->P3` */
- const float3 v1 = (p2 - p1).normalized();
- const float3 v2 = (p3 - p2).normalized();
+ const float3 v1 = math::normalize(p2 - p1);
+ const float3 v2 = math::normalize(p3 - p2);
/* Normal of plane of main 2 segments P1->P2 and `P2->P3`. */
- const float3 v3 = float3::cross(v1, v2).normalized();
+ const float3 v3 = math::normalize(math::cross(v1, v2));
/* Normal of plane of first perpendicular bisector and `P1->P2`. */
- const float3 v4 = float3::cross(v3, v1).normalized();
+ const float3 v4 = math::normalize(math::cross(v3, v1));
/* Determine Center-point from the intersection of 3 planes. */
float plane_1[4], plane_2[4], plane_3[4];
@@ -122,7 +148,7 @@ static std::unique_ptr<CurveEval> create_point_circle_curve(
}
/* Get the radius from the center-point to p1. */
- const float r = float3::distance(p1, center);
+ const float r = math::distance(p1, center);
const float theta_step = ((2 * M_PI) / (float)resolution);
for (const int i : IndexRange(resolution)) {
@@ -132,7 +158,7 @@ static std::unique_ptr<CurveEval> create_point_circle_curve(
*/
const float theta = theta_step * i;
- positions[i] = center + r * cos(theta) * v1 + r * sin(theta) * v4;
+ positions[i] = center + r * sin(theta) * v1 + r * cos(theta) * v4;
}
spline->radii().fill(1.0f);
@@ -169,13 +195,11 @@ static std::unique_ptr<CurveEval> create_radius_circle_curve(const int resolutio
return curve;
}
-static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurvePrimitiveCircle *node_storage =
- (NodeGeometryCurvePrimitiveCircle *)params.node().storage;
-
+ const NodeGeometryCurvePrimitiveCircle &storage = node_storage(params.node());
const GeometryNodeCurvePrimitiveCircleMode mode = (GeometryNodeCurvePrimitiveCircleMode)
- node_storage->mode;
+ storage.mode;
std::unique_ptr<CurveEval> curve;
if (mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS) {
@@ -196,26 +220,27 @@ static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
else {
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_circle_cc
void register_node_type_geo_curve_primitive_circle()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_circle_cc;
+
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY);
- node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_circle_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_circle_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
"NodeGeometryCurvePrimitiveCircle",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_primitive_circle_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_circle_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_circle_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
index a3d2ada612f..d35fa0a2fdc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
@@ -21,48 +21,57 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_line_cc {
-static void geo_node_curve_primitive_line_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveLine)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Vector>("Start").subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("End").default_value({0.0f, 0.0f, 1.0f}).subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Direction").default_value({0.0f, 0.0f, 1.0f});
- b.add_input<decl::Float>("Length").default_value(1.0f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Vector>(N_("Start"))
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Position of the first control point"));
+ b.add_input<decl::Vector>(N_("End"))
+ .default_value({0.0f, 0.0f, 1.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Position of the second control point"));
+ b.add_input<decl::Vector>(N_("Direction"))
+ .default_value({0.0f, 0.0f, 1.0f})
+ .description(
+ N_("Direction the line is going in. The length of this vector does not matter"));
+ b.add_input<decl::Float>(N_("Length"))
+ .default_value(1.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Distance between the two points"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_primitive_line_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_primitive_line_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveLine *data = (NodeGeometryCurvePrimitiveLine *)MEM_callocN(
- sizeof(NodeGeometryCurvePrimitiveLine), __func__);
+ NodeGeometryCurvePrimitiveLine *data = MEM_cnew<NodeGeometryCurvePrimitiveLine>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS;
node->storage = data;
}
-static void geo_node_curve_primitive_line_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryCurvePrimitiveLine *node_storage = (NodeGeometryCurvePrimitiveLine *)
- node->storage;
- const GeometryNodeCurvePrimitiveLineMode mode = (const GeometryNodeCurvePrimitiveLineMode)
- node_storage->mode;
+ const NodeGeometryCurvePrimitiveLine &storage = node_storage(*node);
+ const GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)storage.mode;
bNodeSocket *p2_socket = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *direction_socket = p2_socket->next;
bNodeSocket *length_socket = direction_socket->next;
- nodeSetSocketAvailability(p2_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS);
- nodeSetSocketAvailability(direction_socket,
- mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION);
- nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION);
+ nodeSetSocketAvailability(ntree, p2_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS);
+ nodeSetSocketAvailability(
+ ntree, direction_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION);
+ nodeSetSocketAvailability(
+ ntree, length_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION);
}
static std::unique_ptr<CurveEval> create_point_line_curve(const float3 start, const float3 end)
@@ -91,7 +100,7 @@ static std::unique_ptr<CurveEval> create_direction_line_curve(const float3 start
spline->resize(2);
MutableSpan<float3> positions = spline->positions();
positions[0] = start;
- positions[1] = direction.normalized() * length + start;
+ positions[1] = math::normalize(direction) * length + start;
spline->radii().fill(1.0f);
spline->tilts().fill(0.0f);
@@ -100,13 +109,10 @@ static std::unique_ptr<CurveEval> create_direction_line_curve(const float3 start
return curve;
}
-static void geo_node_curve_primitive_line_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
-
- const NodeGeometryCurvePrimitiveLine *node_storage =
- (NodeGeometryCurvePrimitiveLine *)params.node().storage;
-
- GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)node_storage->mode;
+ const NodeGeometryCurvePrimitiveLine &storage = node_storage(params.node());
+ const GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)storage.mode;
std::unique_ptr<CurveEval> curve;
if (mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS) {
@@ -122,20 +128,22 @@ static void geo_node_curve_primitive_line_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_line_cc
void register_node_type_geo_curve_primitive_line()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_line_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_LINE, "Curve Line", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_line_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_line_update);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_LINE, "Curve Line", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
"NodeGeometryCurvePrimitiveLine",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_primitive_line_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_line_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_line_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
index a54fd971ac4..885d92a111b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
@@ -17,15 +17,29 @@
#include "BKE_spline.hh"
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc {
-static void geo_node_curve_primitive_quadratic_bezier_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Resolution").default_value(16).min(3).max(256).subtype(PROP_UNSIGNED);
- b.add_input<decl::Vector>("Start").default_value({-1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Middle").default_value({0.0f, 2.0f, 0.0f}).subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("End").default_value({1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION);
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Int>(N_("Resolution"))
+ .default_value(16)
+ .min(3)
+ .max(256)
+ .subtype(PROP_UNSIGNED)
+ .description(N_("The number of edges on the curve"));
+ b.add_input<decl::Vector>(N_("Start"))
+ .default_value({-1.0f, 0.0f, 0.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Position of the first control point"));
+ b.add_input<decl::Vector>(N_("Middle"))
+ .default_value({0.0f, 2.0f, 0.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Position of the middle control point"));
+ b.add_input<decl::Vector>(N_("End"))
+ .default_value({1.0f, 0.0f, 0.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Position of the last control point"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static std::unique_ptr<CurveEval> create_quadratic_bezier_curve(const float3 p1,
@@ -36,21 +50,25 @@ static std::unique_ptr<CurveEval> create_quadratic_bezier_curve(const float3 p1,
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ spline->resize(resolution + 1);
+ MutableSpan<float3> positions = spline->positions();
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+
const float step = 1.0f / resolution;
- for (int i : IndexRange(resolution + 1)) {
+ for (const int i : IndexRange(resolution + 1)) {
const float factor = step * i;
- const float3 q1 = float3::interpolate(p1, p2, factor);
- const float3 q2 = float3::interpolate(p2, p3, factor);
- const float3 out = float3::interpolate(q1, q2, factor);
- spline->add_point(out, 1.0f, 0.0f);
+ const float3 q1 = math::interpolate(p1, p2, factor);
+ const float3 q2 = math::interpolate(p2, p3, factor);
+ positions[i] = math::interpolate(q1, q2, factor);
}
- spline->attributes.reallocate(spline->size());
+
curve->add_spline(std::move(spline));
curve->attributes.reallocate(curve->splines().size());
return curve;
}
-static void geo_node_curve_primitive_quadratic_bezier_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
std::unique_ptr<CurveEval> curve = create_quadratic_bezier_curve(
params.extract_input<float3>("Start"),
@@ -60,17 +78,16 @@ static void geo_node_curve_primitive_quadratic_bezier_exec(GeoNodeExecParams par
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc
void register_node_type_geo_curve_primitive_quadratic_bezier()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype,
- GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER,
- "Quadratic Bezier",
- NODE_CLASS_GEOMETRY,
- 0);
- ntype.declare = blender::nodes::geo_node_curve_primitive_quadratic_bezier_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadratic_bezier_exec;
+ geo_node_type_base(
+ &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, "Quadratic Bezier", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
index 07ddaa8f61e..8ec42cb1c45 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
@@ -17,46 +17,88 @@
#include "BKE_spline.hh"
#include "UI_interface.h"
#include "UI_resources.h"
+
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_quadrilateral_cc {
-static void geo_node_curve_primitive_quadrilateral_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveQuad)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Width").default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Height").default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Bottom Width").default_value(4.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Top Width").default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Offset").default_value(1.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Bottom Height").default_value(3.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Top Height").default_value(1.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Vector>("Point 1").default_value({-1.0f, -1.0f, 0.0f}).subtype(PROP_DISTANCE);
- b.add_input<decl::Vector>("Point 2").default_value({1.0f, -1.0f, 0.0f}).subtype(PROP_DISTANCE);
- b.add_input<decl::Vector>("Point 3").default_value({1.0f, 1.0f, 0.0f}).subtype(PROP_DISTANCE);
- b.add_input<decl::Vector>("Point 4").default_value({-1.0f, 1.0f, 0.0f}).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Float>(N_("Width"))
+ .default_value(2.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("The X axis size of the shape"));
+ b.add_input<decl::Float>(N_("Height"))
+ .default_value(2.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("The Y axis size of the shape"));
+ b.add_input<decl::Float>(N_("Bottom Width"))
+ .default_value(4.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("The X axis size of the shape"));
+ b.add_input<decl::Float>(N_("Top Width"))
+ .default_value(2.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("The X axis size of the shape"));
+ b.add_input<decl::Float>(N_("Offset"))
+ .default_value(1.0f)
+ .subtype(PROP_DISTANCE)
+ .description(
+ N_("For Parallelogram, the relative X difference between the top and bottom edges. For "
+ "Trapezoid, the amount to move the top edge in the positive X axis"));
+ b.add_input<decl::Float>(N_("Bottom Height"))
+ .default_value(3.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("The distance between the bottom point and the X axis"));
+ b.add_input<decl::Float>(N_("Top Height"))
+ .default_value(1.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("The distance between the top point and the X axis"));
+ b.add_input<decl::Vector>(N_("Point 1"))
+ .default_value({-1.0f, -1.0f, 0.0f})
+ .subtype(PROP_DISTANCE)
+ .description(N_("The exact location of the point to use"));
+ b.add_input<decl::Vector>(N_("Point 2"))
+ .default_value({1.0f, -1.0f, 0.0f})
+ .subtype(PROP_DISTANCE)
+ .description(N_("The exact location of the point to use"));
+ b.add_input<decl::Vector>(N_("Point 3"))
+ .default_value({1.0f, 1.0f, 0.0f})
+ .subtype(PROP_DISTANCE)
+ .description(N_("The exact location of the point to use"));
+ b.add_input<decl::Vector>(N_("Point 4"))
+ .default_value({-1.0f, 1.0f, 0.0f})
+ .subtype(PROP_DISTANCE)
+ .description(N_("The exact location of the point to use"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_primitive_quadrilateral_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveQuad *data = (NodeGeometryCurvePrimitiveQuad *)MEM_callocN(
- sizeof(NodeGeometryCurvePrimitiveQuad), __func__);
+ NodeGeometryCurvePrimitiveQuad *data = MEM_cnew<NodeGeometryCurvePrimitiveQuad>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE;
node->storage = data;
}
-static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryCurvePrimitiveQuad &node_storage = *(NodeGeometryCurvePrimitiveQuad *)node->storage;
+ const NodeGeometryCurvePrimitiveQuad &storage = node_storage(*node);
GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>(
- node_storage.mode);
+ storage.mode);
bNodeSocket *width = ((bNodeSocket *)node->inputs.first);
bNodeSocket *height = width->next;
@@ -70,35 +112,61 @@ static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *UNUSED(ntre
bNodeSocket *p3 = p2->next;
bNodeSocket *p4 = p3->next;
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- nodeSetSocketAvailability(sock, false);
- }
+ Vector<bNodeSocket *> available_sockets;
if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE) {
- nodeSetSocketAvailability(width, true);
- nodeSetSocketAvailability(height, true);
+ available_sockets.extend({width, height});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM) {
- nodeSetSocketAvailability(width, true);
- nodeSetSocketAvailability(height, true);
- nodeSetSocketAvailability(offset, true);
+ available_sockets.extend({width, height, offset});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID) {
- nodeSetSocketAvailability(bottom, true);
- nodeSetSocketAvailability(top, true);
- nodeSetSocketAvailability(offset, true);
- nodeSetSocketAvailability(height, true);
+ available_sockets.extend({bottom, top, offset, height});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE) {
- nodeSetSocketAvailability(width, true);
- nodeSetSocketAvailability(bottom_height, true);
- nodeSetSocketAvailability(top_height, true);
+ available_sockets.extend({width, bottom_height, top_height});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS) {
- nodeSetSocketAvailability(p1, true);
- nodeSetSocketAvailability(p2, true);
- nodeSetSocketAvailability(p3, true);
- nodeSetSocketAvailability(p4, true);
+ available_sockets.extend({p1, p2, p3, p4});
+ }
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ nodeSetSocketAvailability(ntree, sock, available_sockets.contains(sock));
+ }
+}
+
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ GeometryNodeCurvePrimitiveQuadMode quad_mode;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("GeometryNodeCurvePrimitiveQuadrilateral");
+ node_storage(node).mode = quad_mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ if (params.in_out() == SOCK_OUT) {
+ search_link_ops_for_declarations(params, declaration.outputs());
+ }
+ else if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ params.add_item(IFACE_("Width"),
+ SocketSearchOp{"Width", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE});
+ params.add_item(IFACE_("Height"),
+ SocketSearchOp{"Height", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE});
+ params.add_item(IFACE_("Bottom Width"),
+ SocketSearchOp{"Bottom Width", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID});
+ params.add_item(IFACE_("Top Width"),
+ SocketSearchOp{"Top Width", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID});
+ params.add_item(IFACE_("Offset"),
+ SocketSearchOp{"Offset", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM});
+ params.add_item(IFACE_("Point 1"),
+ SocketSearchOp{"Point 1", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS});
}
}
@@ -157,12 +225,10 @@ static void create_kite_curve(MutableSpan<float3> positions,
positions[3] = float3(-width / 2.0f, 0, 0);
}
-static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurvePrimitiveQuad &node_storage =
- *(NodeGeometryCurvePrimitiveQuad *)(params.node()).storage;
- const GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>(
- node_storage.mode);
+ const NodeGeometryCurvePrimitiveQuad &storage = node_storage(params.node());
+ const GeometryNodeCurvePrimitiveQuadMode mode = (GeometryNodeCurvePrimitiveQuadMode)storage.mode;
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
@@ -206,7 +272,7 @@ static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params
params.extract_input<float3>("Point 4"));
break;
default:
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -215,21 +281,24 @@ static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_quadrilateral_cc
void register_node_type_geo_curve_primitive_quadrilateral()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_quadrilateral_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_primitive_quadrilateral_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadrilateral_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_quadrilateral_layout;
- node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_update);
- node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_init);
+ &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurvePrimitiveQuad",
node_free_standard_storage,
node_copy_standard_storage);
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
index 0803d43e5c3..6aba65b5638 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
@@ -18,17 +18,35 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_spiral_cc {
-static void geo_node_curve_primitive_spiral_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Resolution").default_value(32).min(1).max(1024).subtype(PROP_UNSIGNED);
- b.add_input<decl::Float>("Rotations").default_value(2.0f).min(0.0f);
- b.add_input<decl::Float>("Start Radius").default_value(1.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("End Radius").default_value(2.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Height").default_value(2.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Bool>("Reverse");
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Int>(N_("Resolution"))
+ .default_value(32)
+ .min(1)
+ .max(1024)
+ .subtype(PROP_UNSIGNED)
+ .description(N_("Number of points in one rotation of the spiral"));
+ b.add_input<decl::Float>(N_("Rotations"))
+ .default_value(2.0f)
+ .min(0.0f)
+ .description(N_("Number of times the spiral makes a full rotation"));
+ b.add_input<decl::Float>(N_("Start Radius"))
+ .default_value(1.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Horizontal Distance from the Z axis at the start of the spiral"));
+ b.add_input<decl::Float>(N_("End Radius"))
+ .default_value(2.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Horizontal Distance from the Z axis at the end of the spiral"));
+ b.add_input<decl::Float>(N_("Height"))
+ .default_value(2.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("The height perpendicular to the base of the spiral"));
+ b.add_input<decl::Bool>(N_("Reverse"))
+ .description(N_("Switch the direction from clockwise to counterclockwise"));
+ b.add_output<decl::Geometry>(N_("Curve"));
}
static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations,
@@ -43,39 +61,35 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations,
const int totalpoints = std::max(int(resolution * rotations), 1);
const float delta_radius = (end_radius - start_radius) / (float)totalpoints;
- float radius = start_radius;
const float delta_height = height / (float)totalpoints;
- const float delta_theta = (M_PI * 2 * rotations) / (float)totalpoints;
- float theta = 0.0f;
+ const float delta_theta = (M_PI * 2 * rotations) / (float)totalpoints *
+ (direction ? 1.0f : -1.0f);
+
+ spline->resize(totalpoints + 1);
+ MutableSpan<float3> positions = spline->positions();
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
for (const int i : IndexRange(totalpoints + 1)) {
+ const float theta = i * delta_theta;
+ const float radius = start_radius + i * delta_radius;
const float x = radius * cos(theta);
const float y = radius * sin(theta);
const float z = delta_height * i;
- spline->add_point(float3(x, y, z), 1.0f, 0.0f);
-
- radius += delta_radius;
-
- if (direction) {
- theta += delta_theta;
- }
- else {
- theta -= delta_theta;
- }
+ positions[i] = {x, y, z};
}
- spline->attributes.reallocate(spline->size());
curve->add_spline(std::move(spline));
curve->attributes.reallocate(curve->splines().size());
return curve;
}
-static void geo_node_curve_primitive_spiral_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const float rotations = std::max(params.extract_input<float>("Rotations"), 0.0f);
if (rotations == 0.0f) {
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -89,14 +103,16 @@ static void geo_node_curve_primitive_spiral_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_spiral_cc
void register_node_type_geo_curve_primitive_spiral()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_spiral_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, "Spiral", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_primitive_spiral_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_spiral_exec;
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, "Spiral", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
index 6261146562d..14517a79037 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
@@ -18,15 +18,33 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_star_cc {
-static void geo_node_curve_primitive_star_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Points").default_value(8).min(3).max(256).subtype(PROP_UNSIGNED);
- b.add_input<decl::Float>("Inner Radius").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Outer Radius").default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Twist").subtype(PROP_ANGLE);
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Int>(N_("Points"))
+ .default_value(8)
+ .min(3)
+ .max(256)
+ .subtype(PROP_UNSIGNED)
+ .description(N_("Number of points on each of the circles"));
+ b.add_input<decl::Float>(N_("Inner Radius"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Radius of the inner circle; can be larger than outer radius"));
+ b.add_input<decl::Float>(N_("Outer Radius"))
+ .default_value(2.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Radius of the outer circle; can be smaller than inner radius"));
+ b.add_input<decl::Float>(N_("Twist"))
+ .subtype(PROP_ANGLE)
+ .description(N_("The counterclockwise rotation of the inner set of points"));
+ b.add_output<decl::Geometry>(N_("Curve"));
+ b.add_output<decl::Bool>(N_("Outer Points"))
+ .field_source()
+ .description(N_("An attribute field with a selection of the outer points"));
}
static std::unique_ptr<CurveEval> create_star_curve(const float inner_radius,
@@ -36,41 +54,69 @@ static std::unique_ptr<CurveEval> create_star_curve(const float inner_radius,
{
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ spline->set_cyclic(true);
+
+ spline->resize(points * 2);
+ MutableSpan<float3> positions = spline->positions();
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
const float theta_step = (2.0f * M_PI) / float(points);
- for (int i : IndexRange(points)) {
+ for (const int i : IndexRange(points)) {
const float x = outer_radius * cos(theta_step * i);
const float y = outer_radius * sin(theta_step * i);
- spline->add_point(float3(x, y, 0.0f), 1.0f, 0.0f);
+ positions[i * 2] = {x, y, 0.0f};
const float inner_x = inner_radius * cos(theta_step * i + theta_step * 0.5f + twist);
const float inner_y = inner_radius * sin(theta_step * i + theta_step * 0.5f + twist);
- spline->add_point(float3(inner_x, inner_y, 0.0f), 1.0f, 0.0f);
+ positions[i * 2 + 1] = {inner_x, inner_y, 0.0f};
}
- spline->set_cyclic(true);
- spline->attributes.reallocate(spline->size());
+
curve->add_spline(std::move(spline));
curve->attributes.reallocate(curve->splines().size());
+
return curve;
}
-static void geo_node_curve_primitive_star_exec(GeoNodeExecParams params)
+static void create_selection_output(CurveComponent &component,
+ StrongAnonymousAttributeID &r_attribute)
+{
+ OutputAttribute_Typed<bool> attribute = component.attribute_try_get_for_output_only<bool>(
+ r_attribute.get(), ATTR_DOMAIN_POINT);
+ MutableSpan<bool> selection = attribute.as_span();
+ for (int i : selection.index_range()) {
+ selection[i] = i % 2 == 0;
+ }
+ attribute.save();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
{
std::unique_ptr<CurveEval> curve = create_star_curve(
std::max(params.extract_input<float>("Inner Radius"), 0.0f),
std::max(params.extract_input<float>("Outer Radius"), 0.0f),
params.extract_input<float>("Twist"),
std::max(params.extract_input<int>("Points"), 3));
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
-}
+ GeometrySet output = GeometrySet::create_with_curve(curve.release());
-} // namespace blender::nodes
+ if (params.output_is_required("Outer Points")) {
+ StrongAnonymousAttributeID attribute_output("Outer Points");
+ create_selection_output(output.get_component_for_write<CurveComponent>(), attribute_output);
+ params.set_output("Outer Points",
+ AnonymousAttributeFieldInput::Create<bool>(
+ std::move(attribute_output), params.attribute_producer_name()));
+ }
+ params.set_output("Curve", std::move(output));
+}
+} // namespace blender::nodes::node_geo_curve_primitive_star_cc
void register_node_type_geo_curve_primitive_star()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_star_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_STAR, "Star", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_primitive_star_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_star_exec;
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_STAR, "Star", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index b8f62460069..8494b4868e8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -26,50 +26,53 @@
#include "node_geometry_util.hh"
-using blender::fn::GVArray_For_GSpan;
-using blender::fn::GVArray_For_Span;
-using blender::fn::GVArray_Typed;
+namespace blender::nodes::node_geo_curve_resample_cc {
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeGeometryCurveResample)
-static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Int>("Count").default_value(10).min(1).max(100000);
- b.add_input<decl::Float>("Length").default_value(0.1f).min(0.001f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
+ b.add_input<decl::Int>(N_("Count")).default_value(10).min(1).max(100000).supports_field();
+ b.add_input<decl::Float>(N_("Length"))
+ .default_value(0.1f)
+ .min(0.001f)
+ .supports_field()
+ .subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_resample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void geo_node_curve_resample_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveResample *data = (NodeGeometryCurveResample *)MEM_callocN(
- sizeof(NodeGeometryCurveResample), __func__);
+ NodeGeometryCurveResample *data = MEM_cnew<NodeGeometryCurveResample>(__func__);
data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT;
node->storage = data;
}
-static void geo_node_curve_resample_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryCurveResample &node_storage = *(NodeGeometryCurveResample *)node->storage;
- const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
+ const NodeGeometryCurveResample &storage = node_storage(*node);
+ const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
- bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next;
+ bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next->next;
bNodeSocket *length_socket = count_socket->next;
- nodeSetSocketAvailability(count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT);
- nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH);
+ nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT);
+ nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH);
}
struct SampleModeParam {
GeometryNodeCurveResampleMode mode;
- std::optional<float> length;
- std::optional<int> count;
+ std::optional<Field<float>> length;
+ std::optional<Field<int>> count;
+ Field<bool> selection;
};
static SplinePtr resample_spline(const Spline &src, const int count)
@@ -78,8 +81,11 @@ static SplinePtr resample_spline(const Spline &src, const int count)
Spline::copy_base_settings(src, *dst);
if (src.evaluated_edges_size() < 1 || count == 1) {
- dst->add_point(src.positions().first(), src.tilts().first(), src.radii().first());
- dst->attributes.reallocate(1);
+ dst->resize(1);
+ dst->positions().first() = src.positions().first();
+ dst->radii().first() = src.radii().first();
+ dst->tilts().first() = src.tilts().first();
+
src.attributes.foreach_attribute(
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
std::optional<GSpan> src_attribute = src.attributes.get_for_read(attribute_id);
@@ -118,7 +124,7 @@ static SplinePtr resample_spline(const Spline &src, const int count)
std::optional<GMutableSpan> output_attribute = dst->attributes.get_for_write(
attribute_id);
if (output_attribute) {
- src.sample_with_index_factors(*src.interpolate_to_evaluated(*input_attribute),
+ src.sample_with_index_factors(src.interpolate_to_evaluated(*input_attribute),
uniform_samples,
*output_attribute);
return true;
@@ -141,8 +147,8 @@ static SplinePtr resample_spline_evaluated(const Spline &src)
dst->positions().copy_from(src.evaluated_positions());
dst->positions().copy_from(src.evaluated_positions());
- src.interpolate_to_evaluated(src.radii())->materialize(dst->radii());
- src.interpolate_to_evaluated(src.tilts())->materialize(dst->tilts());
+ src.interpolate_to_evaluated(src.radii()).materialize(dst->radii());
+ src.interpolate_to_evaluated(src.tilts()).materialize(dst->tilts());
src.attributes.foreach_attribute(
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
@@ -150,7 +156,7 @@ static SplinePtr resample_spline_evaluated(const Spline &src)
if (dst->attributes.create(attribute_id, meta_data.data_type)) {
std::optional<GMutableSpan> dst_attribute = dst->attributes.get_for_write(attribute_id);
if (dst_attribute) {
- src.interpolate_to_evaluated(*src_attribute)->materialize(dst_attribute->data());
+ src.interpolate_to_evaluated(*src_attribute).materialize(dst_attribute->data());
return true;
}
}
@@ -163,42 +169,80 @@ static SplinePtr resample_spline_evaluated(const Spline &src)
return dst;
}
-static std::unique_ptr<CurveEval> resample_curve(const CurveEval &input_curve,
+static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component,
const SampleModeParam &mode_param)
{
- Span<SplinePtr> input_splines = input_curve.splines();
+ const CurveEval *input_curve = component->get_for_read();
+ GeometryComponentFieldContext field_context{*component, ATTR_DOMAIN_CURVE};
+ const int domain_size = component->attribute_domain_size(ATTR_DOMAIN_CURVE);
+
+ Span<SplinePtr> input_splines = input_curve->splines();
std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
output_curve->resize(input_splines.size());
MutableSpan<SplinePtr> output_splines = output_curve->splines();
if (mode_param.mode == GEO_NODE_CURVE_RESAMPLE_COUNT) {
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(*mode_param.count);
+ evaluator.add(mode_param.selection);
+ evaluator.evaluate();
+ const VArray<int> &cuts = evaluator.get_evaluated<int>(0);
+ const VArray<bool> &selections = evaluator.get_evaluated<bool>(1);
+
threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
BLI_assert(mode_param.count);
- output_splines[i] = resample_spline(*input_splines[i], *mode_param.count);
+ if (selections[i] && input_splines[i]->evaluated_points_size() > 0) {
+ output_splines[i] = resample_spline(*input_splines[i], std::max(cuts[i], 1));
+ }
+ else {
+ output_splines[i] = input_splines[i]->copy();
+ }
}
});
}
else if (mode_param.mode == GEO_NODE_CURVE_RESAMPLE_LENGTH) {
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(*mode_param.length);
+ evaluator.add(mode_param.selection);
+ evaluator.evaluate();
+ const VArray<float> &lengths = evaluator.get_evaluated<float>(0);
+ const VArray<bool> &selections = evaluator.get_evaluated<bool>(1);
+
threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
- const float length = input_splines[i]->length();
- const int count = std::max(int(length / *mode_param.length) + 1, 1);
- output_splines[i] = resample_spline(*input_splines[i], count);
+ if (selections[i] && input_splines[i]->evaluated_points_size() > 0) {
+ /* Don't allow asymptotic count increase for low resolution values. */
+ const float divide_length = std::max(lengths[i], 0.0001f);
+ const float spline_length = input_splines[i]->length();
+ const int count = std::max(int(spline_length / divide_length) + 1, 1);
+ output_splines[i] = resample_spline(*input_splines[i], count);
+ }
+ else {
+ output_splines[i] = input_splines[i]->copy();
+ }
}
});
}
else if (mode_param.mode == GEO_NODE_CURVE_RESAMPLE_EVALUATED) {
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(mode_param.selection);
+ evaluator.evaluate();
+ const VArray<bool> &selections = evaluator.get_evaluated<bool>(0);
+
threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
- output_splines[i] = resample_spline_evaluated(*input_splines[i]);
+ if (selections[i] && input_splines[i]->evaluated_points_size() > 0) {
+ output_splines[i] = resample_spline_evaluated(*input_splines[i]);
+ }
+ else {
+ output_splines[i] = input_splines[i]->copy();
+ }
}
});
}
-
- output_curve->attributes = input_curve.attributes;
-
+ output_curve->attributes = input_curve->attributes;
return output_curve;
}
@@ -209,54 +253,57 @@ static void geometry_set_curve_resample(GeometrySet &geometry_set,
return;
}
- const CurveEval &input_curve = *geometry_set.get_curve_for_read();
- std::unique_ptr<CurveEval> output_curve = resample_curve(input_curve, mode_param);
+ std::unique_ptr<CurveEval> output_curve = resample_curve(
+ geometry_set.get_component_for_read<CurveComponent>(), mode_param);
geometry_set.replace_curve(output_curve.release());
}
-static void geo_node_resample_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- NodeGeometryCurveResample &node_storage = *(NodeGeometryCurveResample *)params.node().storage;
- const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
+ const NodeGeometryCurveResample &storage = node_storage(params.node());
+ const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
SampleModeParam mode_param;
mode_param.mode = mode;
+ mode_param.selection = params.extract_input<Field<bool>>("Selection");
+
if (mode == GEO_NODE_CURVE_RESAMPLE_COUNT) {
- const int count = params.extract_input<int>("Count");
+ Field<int> count = params.extract_input<Field<int>>("Count");
if (count < 1) {
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
mode_param.count.emplace(count);
}
else if (mode == GEO_NODE_CURVE_RESAMPLE_LENGTH) {
- /* Don't allow asymptotic count increase for low resolution values. */
- const float resolution = std::max(params.extract_input<float>("Length"), 0.0001f);
+ Field<float> resolution = params.extract_input<Field<float>>("Length");
mode_param.length.emplace(resolution);
}
geometry_set.modify_geometry_sets(
[&](GeometrySet &geometry_set) { geometry_set_curve_resample(geometry_set, mode_param); });
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_resample_cc
void register_node_type_geo_curve_resample()
{
+ namespace file_ns = blender::nodes::node_geo_curve_resample_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_RESAMPLE, "Resample Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_resample_declare;
- ntype.draw_buttons = blender::nodes::geo_node_curve_resample_layout;
+ geo_node_type_base(&ntype, GEO_NODE_RESAMPLE_CURVE, "Resample Curve", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryCurveResample", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_curve_resample_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_resample_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_resample_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
index b644faabedb..38974fafce7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -20,16 +20,16 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_reverse_cc {
-static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
@@ -38,7 +38,7 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
return;
}
- Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
@@ -60,13 +60,15 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_reverse_cc
void register_node_type_geo_curve_reverse()
{
+ namespace file_ns = blender::nodes::node_geo_curve_reverse_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_reverse_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_reverse_exec;
+ geo_node_type_base(&ntype, GEO_NODE_REVERSE_CURVE, "Reverse Curve", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
index 1266f525861..56fbc50f033 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
@@ -23,42 +23,53 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_sample_cc {
-static void geo_node_curve_sample_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::Float>("Factor").min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field();
- b.add_input<decl::Float>("Length").min(0.0f).subtype(PROP_DISTANCE).supports_field();
+NODE_STORAGE_FUNCS(NodeGeometryCurveSample)
- b.add_output<decl::Vector>("Position").dependent_field();
- b.add_output<decl::Vector>("Tangent").dependent_field();
- b.add_output<decl::Vector>("Normal").dependent_field();
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Curve"))
+ .only_realized_data()
+ .supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Float>(N_("Factor"))
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .supports_field()
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR; });
+ b.add_input<decl::Float>(N_("Length"))
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .supports_field()
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; });
+ b.add_output<decl::Vector>(N_("Position")).dependent_field();
+ b.add_output<decl::Vector>(N_("Tangent")).dependent_field();
+ b.add_output<decl::Vector>(N_("Normal")).dependent_field();
}
-static void geo_node_curve_sample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_sample_type_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_type_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSample *data = (NodeGeometryCurveSample *)MEM_callocN(
- sizeof(NodeGeometryCurveSample), __func__);
+ NodeGeometryCurveSample *data = MEM_cnew<NodeGeometryCurveSample>(__func__);
data->mode = GEO_NODE_CURVE_SAMPLE_LENGTH;
node->storage = data;
}
-static void geo_node_curve_sample_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryCurveSample &node_storage = *(NodeGeometryCurveSample *)node->storage;
- const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+ const NodeGeometryCurveSample &storage = node_storage(*node);
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
bNodeSocket *factor = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *length = factor->next;
- nodeSetSocketAvailability(factor, mode == GEO_NODE_CURVE_SAMPLE_FACTOR);
- nodeSetSocketAvailability(length, mode == GEO_NODE_CURVE_SAMPLE_LENGTH);
+ nodeSetSocketAvailability(ntree, factor, mode == GEO_NODE_CURVE_SAMPLE_FACTOR);
+ nodeSetSocketAvailability(ntree, length, mode == GEO_NODE_CURVE_SAMPLE_LENGTH);
}
template<typename T> static T sample_with_lookup(const Spline::LookupResult lookup, Span<T> data)
@@ -174,7 +185,7 @@ class SampleCurveFunction : public fn::MultiFunction {
for (const int i : mask) {
const Spline::LookupResult &lookup = lookups[i];
const Span<float3> evaluated_tangents = splines[spline_indices[i]]->evaluated_tangents();
- sampled_tangents[i] = sample_with_lookup(lookup, evaluated_tangents).normalized();
+ sampled_tangents[i] = math::normalize(sample_with_lookup(lookup, evaluated_tangents));
}
}
@@ -182,7 +193,7 @@ class SampleCurveFunction : public fn::MultiFunction {
for (const int i : mask) {
const Spline::LookupResult &lookup = lookups[i];
const Span<float3> evaluated_normals = splines[spline_indices[i]]->evaluated_normals();
- sampled_normals[i] = sample_with_lookup(lookup, evaluated_normals).normalized();
+ sampled_normals[i] = math::normalize(sample_with_lookup(lookup, evaluated_normals));
}
}
}
@@ -198,8 +209,8 @@ class SampleCurveFunction : public fn::MultiFunction {
static Field<float> get_length_input_field(const GeoNodeExecParams &params,
const float curve_total_length)
{
- const NodeGeometryCurveSample &node_storage = *(NodeGeometryCurveSample *)params.node().storage;
- const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+ const NodeGeometryCurveSample &storage = node_storage(params.node());
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
/* Just make sure the length is in bounds of the curve. */
@@ -227,34 +238,32 @@ static Field<float> get_length_input_field(const GeoNodeExecParams &params,
return Field<float>(std::move(process_op), 0);
}
-static void geo_node_curve_sample_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- auto return_default = [&]() {
- params.set_output("Position", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- params.set_output("Tangent", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- params.set_output("Normal", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- };
-
const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>();
if (component == nullptr) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
const CurveEval *curve = component->get_for_read();
if (curve == nullptr) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
if (curve->splines().is_empty()) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
Array<float> spline_lengths = curve->accumulated_spline_lengths();
const float total_length = spline_lengths.last();
if (total_length == 0.0f) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
Field<float> length_field = get_length_input_field(params, total_length);
@@ -269,20 +278,22 @@ static void geo_node_curve_sample_exec(GeoNodeExecParams params)
params.set_output("Normal", Field<float3>(sample_op, 2));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_sample_cc
void register_node_type_geo_curve_sample()
{
+ namespace file_ns = blender::nodes::node_geo_curve_sample_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_SAMPLE, "Curve Sample", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_sample_exec;
- ntype.declare = blender::nodes::geo_node_curve_sample_declare;
- node_type_init(&ntype, blender::nodes::geo_node_curve_sample_type_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_sample_update);
+ geo_node_type_base(&ntype, GEO_NODE_SAMPLE_CURVE, "Sample Curve", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_type_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryCurveSample", node_free_standard_storage, node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_sample_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
new file mode 100644
index 00000000000..74bdce4cef3
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
@@ -0,0 +1,149 @@
+/*
+ * 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 "BKE_spline.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_curve_set_handles_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryCurveSetHandles)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryCurveSetHandles *data = MEM_cnew<NodeGeometryCurveSetHandles>(__func__);
+
+ data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
+ data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
+ node->storage = data;
+}
+
+static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHandleType type)
+{
+ switch (type) {
+ case GEO_NODE_CURVE_HANDLE_AUTO:
+ return BezierSpline::HandleType::Auto;
+ case GEO_NODE_CURVE_HANDLE_ALIGN:
+ return BezierSpline::HandleType::Align;
+ case GEO_NODE_CURVE_HANDLE_FREE:
+ return BezierSpline::HandleType::Free;
+ case GEO_NODE_CURVE_HANDLE_VECTOR:
+ return BezierSpline::HandleType::Vector;
+ }
+ BLI_assert_unreachable();
+ return BezierSpline::HandleType::Auto;
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryCurveSetHandles &storage = node_storage(params.node());
+ const GeometryNodeCurveHandleType type = (GeometryNodeCurveHandleType)storage.handle_type;
+ const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage.mode;
+
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+
+ bool has_bezier_spline = false;
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (!geometry_set.has_curve()) {
+ return;
+ }
+
+ /* Retrieve data for write access so we can avoid new allocations for the handles data. */
+ CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
+ CurveEval &curve = *curve_component.get_for_write();
+ MutableSpan<SplinePtr> splines = curve.splines();
+
+ GeometryComponentFieldContext field_context{curve_component, ATTR_DOMAIN_POINT};
+ const int domain_size = curve_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+
+ fn::FieldEvaluator selection_evaluator{field_context, domain_size};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
+
+ const BezierSpline::HandleType new_handle_type = handle_type_from_input_type(type);
+ int point_index = 0;
+
+ for (SplinePtr &spline : splines) {
+ if (spline->type() != Spline::Type::Bezier) {
+ point_index += spline->positions().size();
+ continue;
+ }
+
+ has_bezier_spline = true;
+ BezierSpline &bezier_spline = static_cast<BezierSpline &>(*spline);
+ if (ELEM(new_handle_type, BezierSpline::HandleType::Free, BezierSpline::HandleType::Align)) {
+ /* In this case the automatically calculated handle types need to be "baked", because
+ * they're possibly changing from a type that is calculated automatically to a type that
+ * is positioned manually. */
+ bezier_spline.ensure_auto_handles();
+ }
+
+ for (int i_point : IndexRange(bezier_spline.size())) {
+ if (selection[point_index]) {
+ if (mode & GEO_NODE_CURVE_HANDLE_LEFT) {
+ bezier_spline.handle_types_left()[i_point] = new_handle_type;
+ }
+ if (mode & GEO_NODE_CURVE_HANDLE_RIGHT) {
+ bezier_spline.handle_types_right()[i_point] = new_handle_type;
+ }
+ }
+ point_index++;
+ }
+ bezier_spline.mark_cache_invalid();
+ }
+ });
+ if (!has_bezier_spline) {
+ params.error_message_add(NodeWarningType::Info, TIP_("No Bezier splines in input curve"));
+ }
+ params.set_output("Curve", std::move(geometry_set));
+}
+} // namespace blender::nodes::node_geo_curve_set_handles_cc
+
+void register_node_type_geo_curve_set_handles()
+{
+ namespace file_ns = blender::nodes::node_geo_curve_set_handles_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_storage(&ntype,
+ "NodeGeometryCurveSetHandles",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ ntype.draw_buttons = file_ns::node_layout;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
new file mode 100644
index 00000000000..257a5b8df00
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
@@ -0,0 +1,326 @@
+/*
+ * 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 "BLI_task.hh"
+
+#include "BKE_spline.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_curve_spline_parameter_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Factor"))
+ .field_source()
+ .description(
+ N_("For points, the portion of the spline's total length at the control point. For "
+ "Splines, the factor of that spline within the entire curve"));
+ b.add_output<decl::Float>(N_("Length"))
+ .field_source()
+ .description(
+ N_("For points, the distance along the control point's spline, For splines, the "
+ "distance along the entire curve"));
+ b.add_output<decl::Int>(N_("Index"))
+ .field_source()
+ .description(N_("Each control point's index on its spline"));
+}
+
+/**
+ * A basic interpolation from the point domain to the spline domain would be useless, since the
+ * average parameter for each spline would just be 0.5, or close to it. Instead, the parameter for
+ * each spline is the portion of the total length at the start of the spline.
+ */
+static Array<float> curve_length_spline_domain(const CurveEval &curve,
+ const IndexMask UNUSED(mask))
+{
+ Span<SplinePtr> splines = curve.splines();
+ float length = 0.0f;
+ Array<float> lengths(splines.size());
+ for (const int i : splines.index_range()) {
+ lengths[i] = length;
+ length += splines[i]->length();
+ }
+ return lengths;
+}
+
+/**
+ * The parameter at each control point is the factor at the corresponding evaluated point.
+ */
+static void calculate_bezier_lengths(const BezierSpline &spline, MutableSpan<float> lengths)
+{
+ Span<int> offsets = spline.control_point_offsets();
+ Span<float> lengths_eval = spline.evaluated_lengths();
+ for (const int i : IndexRange(1, spline.size() - 1)) {
+ lengths[i] = lengths_eval[offsets[i] - 1];
+ }
+}
+
+/**
+ * The parameter for poly splines is simply the evaluated lengths divided by the total length.
+ */
+static void calculate_poly_length(const PolySpline &spline, MutableSpan<float> lengths)
+{
+ Span<float> lengths_eval = spline.evaluated_lengths();
+ if (spline.is_cyclic()) {
+ lengths.drop_front(1).copy_from(lengths_eval.drop_back(1));
+ }
+ else {
+ lengths.drop_front(1).copy_from(lengths_eval);
+ }
+}
+
+/**
+ * Since NURBS control points do not necessarily coincide with the evaluated curve's path, and
+ * each control point doesn't correspond well to a specific evaluated point, the parameter at
+ * each point is not well defined. So instead, treat the control points as if they were a poly
+ * spline.
+ */
+static void calculate_nurbs_lengths(const NURBSpline &spline, MutableSpan<float> lengths)
+{
+ Span<float3> positions = spline.positions();
+ Array<float> control_point_lengths(spline.size());
+ float length = 0.0f;
+ for (const int i : IndexRange(positions.size() - 1)) {
+ lengths[i] = length;
+ length += math::distance(positions[i], positions[i + 1]);
+ }
+ lengths.last() = length;
+}
+
+static Array<float> curve_length_point_domain(const CurveEval &curve)
+{
+ Span<SplinePtr> splines = curve.splines();
+ Array<int> offsets = curve.control_point_offsets();
+ const int total_size = offsets.last();
+ Array<float> lengths(total_size);
+
+ threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ const Spline &spline = *splines[i];
+ MutableSpan spline_factors{lengths.as_mutable_span().slice(offsets[i], spline.size())};
+ spline_factors.first() = 0.0f;
+ switch (splines[i]->type()) {
+ case Spline::Type::Bezier: {
+ calculate_bezier_lengths(static_cast<const BezierSpline &>(spline), spline_factors);
+ break;
+ }
+ case Spline::Type::Poly: {
+ calculate_poly_length(static_cast<const PolySpline &>(spline), spline_factors);
+ break;
+ }
+ case Spline::Type::NURBS: {
+ calculate_nurbs_lengths(static_cast<const NURBSpline &>(spline), spline_factors);
+ break;
+ }
+ }
+ }
+ });
+ return lengths;
+}
+
+static VArray<float> construct_curve_parameter_varray(const CurveEval &curve,
+ const IndexMask mask,
+ const AttributeDomain domain)
+{
+ if (domain == ATTR_DOMAIN_POINT) {
+ Span<SplinePtr> splines = curve.splines();
+ Array<float> values = curve_length_point_domain(curve);
+
+ const Array<int> offsets = curve.control_point_offsets();
+ for (const int i_spline : curve.splines().index_range()) {
+ const Spline &spline = *splines[i_spline];
+ const float spline_length = spline.length();
+ const float spline_length_inv = spline_length == 0.0f ? 0.0f : 1.0f / spline_length;
+ for (const int i : IndexRange(spline.size())) {
+ values[offsets[i_spline] + i] *= spline_length_inv;
+ }
+ }
+ return VArray<float>::ForContainer(std::move(values));
+ }
+
+ if (domain == ATTR_DOMAIN_CURVE) {
+ Array<float> values = curve.accumulated_spline_lengths();
+ const float total_length_inv = values.last() == 0.0f ? 0.0f : 1.0f / values.last();
+ for (const int i : mask) {
+ values[i] *= total_length_inv;
+ }
+ return VArray<float>::ForContainer(std::move(values));
+ }
+ return {};
+}
+
+static VArray<float> construct_curve_length_varray(const CurveEval &curve,
+ const IndexMask mask,
+ const AttributeDomain domain)
+{
+ if (domain == ATTR_DOMAIN_POINT) {
+ Array<float> lengths = curve_length_point_domain(curve);
+ return VArray<float>::ForContainer(std::move(lengths));
+ }
+
+ if (domain == ATTR_DOMAIN_CURVE) {
+ if (curve.splines().size() == 1) {
+ Array<float> lengths(1, 0.0f);
+ return VArray<float>::ForContainer(std::move(lengths));
+ }
+
+ Array<float> lengths = curve_length_spline_domain(curve, mask);
+ return VArray<float>::ForContainer(std::move(lengths));
+ }
+
+ return {};
+}
+
+static VArray<int> construct_index_on_spline_varray(const CurveEval &curve,
+ const IndexMask UNUSED(mask),
+ const AttributeDomain domain)
+{
+ if (domain == ATTR_DOMAIN_POINT) {
+ Array<int> output(curve.total_control_point_size());
+ int output_index = 0;
+ for (int spline_index : curve.splines().index_range()) {
+ for (int point_index : IndexRange(curve.splines()[spline_index]->size())) {
+ output[output_index++] = point_index;
+ }
+ }
+ return VArray<int>::ForContainer(std::move(output));
+ }
+ return {};
+}
+
+class CurveParameterFieldInput final : public GeometryFieldInput {
+ public:
+ CurveParameterFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Parameter node")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve) {
+ return construct_curve_parameter_varray(*curve, mask, domain);
+ }
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 29837456298;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const CurveParameterFieldInput *>(&other) != nullptr;
+ }
+};
+
+class CurveLengthFieldInput final : public GeometryFieldInput {
+ public:
+ CurveLengthFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Length node")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve) {
+ return construct_curve_length_varray(*curve, mask, domain);
+ }
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 345634563454;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const CurveLengthFieldInput *>(&other) != nullptr;
+ }
+};
+
+class IndexOnSplineFieldInput final : public GeometryFieldInput {
+ public:
+ IndexOnSplineFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Spline Index")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve) {
+ return construct_index_on_spline_varray(*curve, mask, domain);
+ }
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 4536246522;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const IndexOnSplineFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<float> parameter_field{std::make_shared<CurveParameterFieldInput>()};
+ Field<float> length_field{std::make_shared<CurveLengthFieldInput>()};
+ Field<int> index_on_spline_field{std::make_shared<IndexOnSplineFieldInput>()};
+ params.set_output("Factor", std::move(parameter_field));
+ params.set_output("Length", std::move(length_field));
+ params.set_output("Index", std::move(index_on_spline_field));
+}
+
+} // namespace blender::nodes::node_geo_curve_spline_parameter_cc
+
+void register_node_type_geo_curve_spline_parameter()
+{
+ namespace file_ns = blender::nodes::node_geo_curve_spline_parameter_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_CURVE_SPLINE_PARAMETER, "Spline Parameter", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
new file mode 100644
index 00000000000..b91ddd7bc7a
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
@@ -0,0 +1,434 @@
+/*
+ * 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 "BKE_spline.hh"
+
+#include "BLI_task.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_curve_spline_type_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryCurveSplineType)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__);
+
+ data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
+ node->storage = data;
+}
+
+template<class T>
+static void scale_input_assign(const Span<T> input,
+ const int scale,
+ const int offset,
+ const MutableSpan<T> r_output)
+{
+ for (const int i : IndexRange(r_output.size())) {
+ r_output[i] = input[i * scale + offset];
+ }
+}
+
+template<class T>
+static void scale_output_assign(const Span<T> input,
+ const int scale,
+ const int offset,
+ const MutableSpan<T> &r_output)
+{
+ for (const int i : IndexRange(input.size())) {
+ r_output[i * scale + offset] = input[i];
+ }
+}
+
+template<class T>
+static void nurbs_to_bezier_assign(const Span<T> input,
+ const MutableSpan<T> r_output,
+ const NURBSpline::KnotsMode knotsMode)
+{
+ const int input_size = input.size();
+ const int output_size = r_output.size();
+
+ switch (knotsMode) {
+ case NURBSpline::KnotsMode::Bezier:
+ scale_input_assign<T>(input, 3, 1, r_output);
+ break;
+ case NURBSpline::KnotsMode::Normal:
+ for (const int i : IndexRange(output_size)) {
+ r_output[i] = input[(i + 1) % input_size];
+ }
+ break;
+ case NURBSpline::KnotsMode::EndPoint:
+ for (const int i : IndexRange(1, output_size - 2)) {
+ r_output[i] = input[i + 1];
+ }
+ r_output.first() = input.first();
+ r_output.last() = input.last();
+ break;
+ }
+}
+
+template<typename CopyFn>
+static void copy_attributes(const Spline &input_spline, Spline &output_spline, CopyFn copy_fn)
+{
+ input_spline.attributes.foreach_attribute(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> src = input_spline.attributes.get_for_read(attribute_id);
+ BLI_assert(src);
+ if (!output_spline.attributes.create(attribute_id, meta_data.data_type)) {
+ BLI_assert_unreachable();
+ return false;
+ }
+ std::optional<GMutableSpan> dst = output_spline.attributes.get_for_write(attribute_id);
+ if (!dst) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ copy_fn(*src, *dst);
+
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+}
+
+static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_positions,
+ const NURBSpline::KnotsMode knots_mode)
+{
+ const int nurbs_positions_size = nurbs_positions.size();
+ Vector<float3> handle_positions;
+ if (knots_mode == NURBSpline::KnotsMode::Bezier) {
+ for (const int i : IndexRange(nurbs_positions_size)) {
+ if (i % 3 == 1) {
+ continue;
+ }
+ handle_positions.append(nurbs_positions[i]);
+ }
+ if (nurbs_positions_size % 3 == 1) {
+ handle_positions.pop_last();
+ }
+ else if (nurbs_positions_size % 3 == 2) {
+ const int last_index = nurbs_positions_size - 1;
+ handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
+ }
+ }
+ else {
+ const bool is_periodic = knots_mode == NURBSpline::KnotsMode::Normal;
+ if (is_periodic) {
+ handle_positions.append(nurbs_positions[1] +
+ ((nurbs_positions[0] - nurbs_positions[1]) / 3));
+ }
+ else {
+ handle_positions.append(2 * nurbs_positions[0] - nurbs_positions[1]);
+ handle_positions.append(nurbs_positions[1]);
+ }
+ const int segments_size = nurbs_positions_size - 1;
+ const bool ignore_interior_segment = segments_size == 3 && is_periodic == false;
+ if (ignore_interior_segment == false) {
+ const float mid_offset = (float)(segments_size - 1) / 2.0f;
+ for (const int i : IndexRange(1, segments_size - 2)) {
+ const int divisor = is_periodic ?
+ 3 :
+ std::min(3, (int)(-std::abs(i - mid_offset) + mid_offset + 1.0f));
+ const float3 &p1 = nurbs_positions[i];
+ const float3 &p2 = nurbs_positions[i + 1];
+ const float3 displacement = (p2 - p1) / divisor;
+ const int num_handles_on_segment = divisor < 3 ? 1 : 2;
+ for (int j : IndexRange(1, num_handles_on_segment)) {
+ handle_positions.append(p1 + (displacement * j));
+ }
+ }
+ }
+ const int last_index = nurbs_positions_size - 1;
+ if (is_periodic) {
+ handle_positions.append(
+ nurbs_positions[last_index - 1] +
+ ((nurbs_positions[last_index] - nurbs_positions[last_index - 1]) / 3));
+ }
+ else {
+ handle_positions.append(nurbs_positions[last_index - 1]);
+ handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
+ }
+ }
+ return handle_positions;
+}
+
+static Array<float3> create_nurbs_to_bezier_positions(const Span<float3> nurbs_positions,
+ const Span<float3> handle_positions,
+ const NURBSpline::KnotsMode knots_mode)
+{
+ if (knots_mode == NURBSpline::KnotsMode::Bezier) {
+ /* Every third NURBS position (starting from index 1) should be converted to Bezier position */
+ const int scale = 3;
+ const int offset = 1;
+ Array<float3> bezier_positions((nurbs_positions.size() + offset) / scale);
+ scale_input_assign(nurbs_positions, scale, offset, bezier_positions.as_mutable_span());
+ return bezier_positions;
+ }
+
+ Array<float3> bezier_positions(handle_positions.size() / 2);
+ for (const int i : IndexRange(bezier_positions.size())) {
+ bezier_positions[i] = math::interpolate(
+ handle_positions[i * 2], handle_positions[i * 2 + 1], 0.5f);
+ }
+ return bezier_positions;
+}
+
+static SplinePtr convert_to_poly_spline(const Spline &input)
+{
+ std::unique_ptr<PolySpline> output = std::make_unique<PolySpline>();
+ output->resize(input.positions().size());
+ output->positions().copy_from(input.positions());
+ output->radii().copy_from(input.radii());
+ output->tilts().copy_from(input.tilts());
+ Spline::copy_base_settings(input, *output);
+ output->attributes = input.attributes;
+ return output;
+}
+
+static SplinePtr poly_to_nurbs(const Spline &input)
+{
+ std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>();
+ output->resize(input.positions().size());
+ output->positions().copy_from(input.positions());
+ output->radii().copy_from(input.radii());
+ output->tilts().copy_from(input.tilts());
+ output->weights().fill(1.0f);
+ output->set_resolution(12);
+ output->set_order(4);
+ Spline::copy_base_settings(input, *output);
+ output->knots_mode = NURBSpline::KnotsMode::Bezier;
+ output->attributes = input.attributes;
+ return output;
+}
+
+static SplinePtr bezier_to_nurbs(const Spline &input)
+{
+ const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(input);
+ std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>();
+ output->resize(input.size() * 3);
+
+ scale_output_assign(bezier_spline.handle_positions_left(), 3, 0, output->positions());
+ scale_output_assign(input.radii(), 3, 0, output->radii());
+ scale_output_assign(input.tilts(), 3, 0, output->tilts());
+
+ scale_output_assign(bezier_spline.positions(), 3, 1, output->positions());
+ scale_output_assign(input.radii(), 3, 1, output->radii());
+ scale_output_assign(input.tilts(), 3, 1, output->tilts());
+
+ scale_output_assign(bezier_spline.handle_positions_right(), 3, 2, output->positions());
+ scale_output_assign(input.radii(), 3, 2, output->radii());
+ scale_output_assign(input.tilts(), 3, 2, output->tilts());
+
+ Spline::copy_base_settings(input, *output);
+ output->weights().fill(1.0f);
+ output->set_resolution(12);
+ output->set_order(4);
+ output->set_cyclic(input.is_cyclic());
+ output->knots_mode = NURBSpline::KnotsMode::Bezier;
+ output->attributes.reallocate(output->size());
+ copy_attributes(input, *output, [](GSpan src, GMutableSpan dst) {
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ scale_output_assign<T>(src.typed<T>(), 3, 0, dst.typed<T>());
+ scale_output_assign<T>(src.typed<T>(), 3, 1, dst.typed<T>());
+ scale_output_assign<T>(src.typed<T>(), 3, 2, dst.typed<T>());
+ });
+ });
+ return output;
+}
+
+static SplinePtr poly_to_bezier(const Spline &input)
+{
+ std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>();
+ output->resize(input.size());
+ output->positions().copy_from(input.positions());
+ output->radii().copy_from(input.radii());
+ output->tilts().copy_from(input.tilts());
+ output->handle_types_left().fill(BezierSpline::HandleType::Vector);
+ output->handle_types_right().fill(BezierSpline::HandleType::Vector);
+ output->set_resolution(12);
+ Spline::copy_base_settings(input, *output);
+ output->attributes = input.attributes;
+ return output;
+}
+
+static SplinePtr nurbs_to_bezier(const Spline &input)
+{
+ const NURBSpline &nurbs_spline = static_cast<const NURBSpline &>(input);
+ Span<float3> nurbs_positions;
+ Vector<float3> nurbs_positions_vector;
+ NURBSpline::KnotsMode knots_mode;
+ if (nurbs_spline.is_cyclic()) {
+ nurbs_positions_vector = nurbs_spline.positions();
+ nurbs_positions_vector.append(nurbs_spline.positions()[0]);
+ nurbs_positions_vector.append(nurbs_spline.positions()[1]);
+ nurbs_positions = nurbs_positions_vector;
+ knots_mode = NURBSpline::KnotsMode::Normal;
+ }
+ else {
+ nurbs_positions = nurbs_spline.positions();
+ knots_mode = nurbs_spline.knots_mode;
+ }
+ const Vector<float3> handle_positions = create_nurbs_to_bezier_handles(nurbs_positions,
+ knots_mode);
+ BLI_assert(handle_positions.size() % 2 == 0);
+ const Array<float3> bezier_positions = create_nurbs_to_bezier_positions(
+ nurbs_positions, handle_positions.as_span(), knots_mode);
+ BLI_assert(handle_positions.size() == bezier_positions.size() * 2);
+
+ std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>();
+ output->resize(bezier_positions.size());
+ output->positions().copy_from(bezier_positions);
+ nurbs_to_bezier_assign(nurbs_spline.radii(), output->radii(), knots_mode);
+ nurbs_to_bezier_assign(nurbs_spline.tilts(), output->tilts(), knots_mode);
+ scale_input_assign(handle_positions.as_span(), 2, 0, output->handle_positions_left());
+ scale_input_assign(handle_positions.as_span(), 2, 1, output->handle_positions_right());
+ output->handle_types_left().fill(BezierSpline::HandleType::Align);
+ output->handle_types_right().fill(BezierSpline::HandleType::Align);
+ output->set_resolution(nurbs_spline.resolution());
+ Spline::copy_base_settings(nurbs_spline, *output);
+ output->attributes.reallocate(output->size());
+ copy_attributes(nurbs_spline, *output, [knots_mode](GSpan src, GMutableSpan dst) {
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ nurbs_to_bezier_assign(src.typed<T>(), dst.typed<T>(), knots_mode);
+ });
+ });
+ return output;
+}
+
+static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params)
+{
+ switch (input.type()) {
+ case Spline::Type::Bezier:
+ return input.copy();
+ case Spline::Type::Poly:
+ return poly_to_bezier(input);
+ case Spline::Type::NURBS:
+ if (input.size() < 4) {
+ params.error_message_add(
+ NodeWarningType::Info,
+ TIP_("NURBS must have minimum of 4 points for Bezier Conversion"));
+ return input.copy();
+ }
+ return nurbs_to_bezier(input);
+ }
+ BLI_assert_unreachable();
+ return {};
+}
+
+static SplinePtr convert_to_nurbs(const Spline &input)
+{
+ switch (input.type()) {
+ case Spline::Type::NURBS:
+ return input.copy();
+ case Spline::Type::Bezier:
+ return bezier_to_nurbs(input);
+ case Spline::Type::Poly:
+ return poly_to_nurbs(input);
+ }
+ BLI_assert_unreachable();
+ return {};
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryCurveSplineType &storage = node_storage(params.node());
+ const GeometryNodeSplineType output_type = (const GeometryNodeSplineType)storage.spline_type;
+
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (!geometry_set.has_curve()) {
+ return;
+ }
+
+ const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
+ const CurveEval &curve = *curve_component->get_for_read();
+ GeometryComponentFieldContext field_context{*curve_component, ATTR_DOMAIN_CURVE};
+ const int domain_size = curve_component->attribute_domain_size(ATTR_DOMAIN_CURVE);
+
+ fn::FieldEvaluator selection_evaluator{field_context, domain_size};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
+
+ std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
+ new_curve->resize(curve.splines().size());
+
+ threading::parallel_for(curve.splines().index_range(), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ if (selection[i]) {
+ switch (output_type) {
+ case GEO_NODE_SPLINE_TYPE_POLY:
+ new_curve->splines()[i] = convert_to_poly_spline(*curve.splines()[i]);
+ break;
+ case GEO_NODE_SPLINE_TYPE_BEZIER:
+ new_curve->splines()[i] = convert_to_bezier(*curve.splines()[i], params);
+ break;
+ case GEO_NODE_SPLINE_TYPE_NURBS:
+ new_curve->splines()[i] = convert_to_nurbs(*curve.splines()[i]);
+ break;
+ }
+ }
+ else {
+ new_curve->splines()[i] = curve.splines()[i]->copy();
+ }
+ }
+ });
+ new_curve->attributes = curve.attributes;
+ geometry_set.replace_curve(new_curve.release());
+ });
+
+ params.set_output("Curve", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_curve_spline_type_cc
+
+void register_node_type_geo_curve_spline_type()
+{
+ namespace file_ns = blender::nodes::node_geo_curve_spline_type_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_storage(&ntype,
+ "NodeGeometryCurveSplineType",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ ntype.draw_buttons = file_ns::node_layout;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
new file mode 100644
index 00000000000..ae282017e0c
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -0,0 +1,366 @@
+/*
+ * 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 "BLI_task.hh"
+#include "BLI_timeit.hh"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_spline.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_curve_subdivide_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Int>(N_("Cuts")).default_value(1).min(0).max(1000).supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
+}
+
+static Array<int> get_subdivided_offsets(const Spline &spline,
+ const VArray<int> &cuts,
+ const int spline_offset)
+{
+ Array<int> offsets(spline.segments_size() + 1);
+ int offset = 0;
+ for (const int i : IndexRange(spline.segments_size())) {
+ offsets[i] = offset;
+ offset = offset + std::max(cuts[spline_offset + i], 0) + 1;
+ }
+ offsets.last() = offset;
+ return offsets;
+}
+
+template<typename T>
+static void subdivide_attribute(Span<T> src,
+ const Span<int> offsets,
+ const bool is_cyclic,
+ MutableSpan<T> dst)
+{
+ const int src_size = src.size();
+ threading::parallel_for(IndexRange(src_size - 1), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ const int cuts = offsets[i + 1] - offsets[i];
+ dst[offsets[i]] = src[i];
+ const float factor_delta = cuts == 0 ? 1.0f : 1.0f / cuts;
+ for (const int cut : IndexRange(cuts)) {
+ const float factor = cut * factor_delta;
+ dst[offsets[i] + cut] = attribute_math::mix2(factor, src[i], src[i + 1]);
+ }
+ }
+ });
+
+ if (is_cyclic) {
+ const int i = src_size - 1;
+ const int cuts = offsets[i + 1] - offsets[i];
+ dst[offsets[i]] = src.last();
+ const float factor_delta = cuts == 0 ? 1.0f : 1.0f / cuts;
+ for (const int cut : IndexRange(cuts)) {
+ const float factor = cut * factor_delta;
+ dst[offsets[i] + cut] = attribute_math::mix2(factor, src.last(), src.first());
+ }
+ }
+ else {
+ dst.last() = src.last();
+ }
+}
+
+/**
+ * In order to generate a Bezier spline with the same shape as the input spline, apply the
+ * De Casteljau algorithm iteratively for the provided number of cuts, constantly updating the
+ * previous result point's right handle and the left handle at the end of the segment.
+ *
+ * \note Non-vector segments in the result spline are given free handles. This could possibly be
+ * improved with another pass that sets handles to aligned where possible, but currently that does
+ * not provide much benefit for the increased complexity.
+ */
+static void subdivide_bezier_segment(const BezierSpline &src,
+ const int index,
+ const int offset,
+ const int result_size,
+ Span<float3> src_positions,
+ Span<float3> src_handles_left,
+ Span<float3> src_handles_right,
+ MutableSpan<float3> dst_positions,
+ MutableSpan<float3> dst_handles_left,
+ MutableSpan<float3> dst_handles_right,
+ MutableSpan<BezierSpline::HandleType> dst_type_left,
+ MutableSpan<BezierSpline::HandleType> dst_type_right)
+{
+ const bool is_last_cyclic_segment = index == (src.size() - 1);
+ const int next_index = is_last_cyclic_segment ? 0 : index + 1;
+
+ /* The first point in the segment is always copied. */
+ dst_positions[offset] = src_positions[index];
+
+ if (src.segment_is_vector(index)) {
+ if (is_last_cyclic_segment) {
+ dst_type_left.first() = BezierSpline::HandleType::Vector;
+ }
+ dst_type_left.slice(offset + 1, result_size).fill(BezierSpline::HandleType::Vector);
+ dst_type_right.slice(offset, result_size).fill(BezierSpline::HandleType::Vector);
+
+ const float factor_delta = 1.0f / result_size;
+ for (const int cut : IndexRange(result_size)) {
+ const float factor = cut * factor_delta;
+ dst_positions[offset + cut] = attribute_math::mix2(
+ factor, src_positions[index], src_positions[next_index]);
+ }
+ }
+ else {
+ if (is_last_cyclic_segment) {
+ dst_type_left.first() = BezierSpline::HandleType::Free;
+ }
+ dst_type_left.slice(offset + 1, result_size).fill(BezierSpline::HandleType::Free);
+ dst_type_right.slice(offset, result_size).fill(BezierSpline::HandleType::Free);
+
+ const int i_segment_last = is_last_cyclic_segment ? 0 : offset + result_size;
+
+ /* Create a Bezier segment to update iteratively for every subdivision
+ * and references to the meaningful values for ease of use. */
+ BezierSpline temp;
+ temp.resize(2);
+ float3 &segment_start = temp.positions().first();
+ float3 &segment_end = temp.positions().last();
+ float3 &handle_prev = temp.handle_positions_right().first();
+ float3 &handle_next = temp.handle_positions_left().last();
+ segment_start = src_positions[index];
+ segment_end = src_positions[next_index];
+ handle_prev = src_handles_right[index];
+ handle_next = src_handles_left[next_index];
+
+ for (const int cut : IndexRange(result_size - 1)) {
+ const float parameter = 1.0f / (result_size - cut);
+ const BezierSpline::InsertResult insert = temp.calculate_segment_insertion(0, 1, parameter);
+
+ /* Copy relevant temporary data to the result. */
+ dst_handles_right[offset + cut] = insert.handle_prev;
+ dst_handles_left[offset + cut + 1] = insert.left_handle;
+ dst_positions[offset + cut + 1] = insert.position;
+
+ /* Update the segment to prepare it for the next subdivision. */
+ segment_start = insert.position;
+ handle_prev = insert.right_handle;
+ handle_next = insert.handle_next;
+ }
+
+ /* Copy the handles for the last segment from the temporary spline. */
+ dst_handles_right[offset + result_size - 1] = handle_prev;
+ dst_handles_left[i_segment_last] = handle_next;
+ }
+}
+
+static void subdivide_bezier_spline(const BezierSpline &src,
+ const Span<int> offsets,
+ BezierSpline &dst)
+{
+ Span<float3> src_positions = src.positions();
+ Span<float3> src_handles_left = src.handle_positions_left();
+ Span<float3> src_handles_right = src.handle_positions_right();
+ MutableSpan<float3> dst_positions = dst.positions();
+ MutableSpan<float3> dst_handles_left = dst.handle_positions_left();
+ MutableSpan<float3> dst_handles_right = dst.handle_positions_right();
+ MutableSpan<BezierSpline::HandleType> dst_type_left = dst.handle_types_left();
+ MutableSpan<BezierSpline::HandleType> dst_type_right = dst.handle_types_right();
+
+ threading::parallel_for(IndexRange(src.size() - 1), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ subdivide_bezier_segment(src,
+ i,
+ offsets[i],
+ offsets[i + 1] - offsets[i],
+ src_positions,
+ src_handles_left,
+ src_handles_right,
+ dst_positions,
+ dst_handles_left,
+ dst_handles_right,
+ dst_type_left,
+ dst_type_right);
+ }
+ });
+
+ if (src.is_cyclic()) {
+ const int i_last = src.size() - 1;
+ subdivide_bezier_segment(src,
+ i_last,
+ offsets[i_last],
+ offsets.last() - offsets[i_last],
+ src_positions,
+ src_handles_left,
+ src_handles_right,
+ dst_positions,
+ dst_handles_left,
+ dst_handles_right,
+ dst_type_left,
+ dst_type_right);
+ }
+ else {
+ dst_positions.last() = src_positions.last();
+ }
+}
+
+static void subdivide_builtin_attributes(const Spline &src_spline,
+ const Span<int> offsets,
+ Spline &dst_spline)
+{
+ const bool is_cyclic = src_spline.is_cyclic();
+ subdivide_attribute<float>(src_spline.radii(), offsets, is_cyclic, dst_spline.radii());
+ subdivide_attribute<float>(src_spline.tilts(), offsets, is_cyclic, dst_spline.tilts());
+ switch (src_spline.type()) {
+ case Spline::Type::Poly: {
+ const PolySpline &src = static_cast<const PolySpline &>(src_spline);
+ PolySpline &dst = static_cast<PolySpline &>(dst_spline);
+ subdivide_attribute<float3>(src.positions(), offsets, is_cyclic, dst.positions());
+ break;
+ }
+ case Spline::Type::Bezier: {
+ const BezierSpline &src = static_cast<const BezierSpline &>(src_spline);
+ BezierSpline &dst = static_cast<BezierSpline &>(dst_spline);
+ subdivide_bezier_spline(src, offsets, dst);
+ dst.mark_cache_invalid();
+ break;
+ }
+ case Spline::Type::NURBS: {
+ const NURBSpline &src = static_cast<const NURBSpline &>(src_spline);
+ NURBSpline &dst = static_cast<NURBSpline &>(dst_spline);
+ subdivide_attribute<float3>(src.positions(), offsets, is_cyclic, dst.positions());
+ subdivide_attribute<float>(src.weights(), offsets, is_cyclic, dst.weights());
+ break;
+ }
+ }
+}
+
+static void subdivide_dynamic_attributes(const Spline &src_spline,
+ const Span<int> offsets,
+ Spline &dst_spline)
+{
+ const bool is_cyclic = src_spline.is_cyclic();
+ src_spline.attributes.foreach_attribute(
+ [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> src = src_spline.attributes.get_for_read(attribute_id);
+ BLI_assert(src);
+
+ if (!dst_spline.attributes.create(attribute_id, meta_data.data_type)) {
+ /* Since the source spline of the same type had the attribute, adding it should work. */
+ BLI_assert_unreachable();
+ }
+
+ std::optional<GMutableSpan> dst = dst_spline.attributes.get_for_write(attribute_id);
+ BLI_assert(dst);
+
+ attribute_math::convert_to_static_type(dst->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ subdivide_attribute<T>(src->typed<T>(), offsets, is_cyclic, dst->typed<T>());
+ });
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+}
+
+static SplinePtr subdivide_spline(const Spline &spline,
+ const VArray<int> &cuts,
+ const int spline_offset)
+{
+ if (spline.size() <= 1) {
+ return spline.copy();
+ }
+
+ /* Since we expect to access each value many times, it should be worth it to make sure count
+ * of cuts is a real span (especially considering the note below). Using the offset at each
+ * point facilitates subdividing in parallel later. */
+ Array<int> offsets = get_subdivided_offsets(spline, cuts, spline_offset);
+ const int result_size = offsets.last() + int(!spline.is_cyclic());
+ SplinePtr new_spline = spline.copy_only_settings();
+ new_spline->resize(result_size);
+ subdivide_builtin_attributes(spline, offsets, *new_spline);
+ subdivide_dynamic_attributes(spline, offsets, *new_spline);
+ return new_spline;
+}
+
+/**
+ * \note Passing the virtual array for the entire spline is possibly quite inefficient here when
+ * the attribute was on the point domain and stored separately for each spline already, and it
+ * prevents some other optimizations like skipping splines with a single attribute value of < 1.
+ * However, it allows the node to access builtin attribute easily, so it the makes most sense this
+ * way until the attribute API is refactored.
+ */
+static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve,
+ const VArray<int> &cuts)
+{
+ const Array<int> control_point_offsets = input_curve.control_point_offsets();
+ const Span<SplinePtr> input_splines = input_curve.splines();
+
+ std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
+ output_curve->resize(input_splines.size());
+ output_curve->attributes = input_curve.attributes;
+ MutableSpan<SplinePtr> output_splines = output_curve->splines();
+
+ threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ output_splines[i] = subdivide_spline(*input_splines[i], cuts, control_point_offsets[i]);
+ }
+ });
+
+ return output_curve;
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+ Field<int> cuts_field = params.extract_input<Field<int>>("Cuts");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (!geometry_set.has_curve()) {
+ return;
+ }
+
+ const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(cuts_field);
+ evaluator.evaluate();
+ const VArray<int> &cuts = evaluator.get_evaluated<int>(0);
+
+ if (cuts.is_single() && cuts.get_internal_single() < 1) {
+ return;
+ }
+
+ std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), cuts);
+ geometry_set.replace_curve(output_curve.release());
+ });
+ params.set_output("Curve", geometry_set);
+}
+
+} // namespace blender::nodes::node_geo_curve_subdivide_cc
+
+void register_node_type_geo_curve_subdivide()
+{
+ namespace file_ns = blender::nodes::node_geo_curve_subdivide_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_CURVE, "Subdivide Curve", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
index f7cef9bbf63..ef4fc51d1b3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
@@ -23,71 +23,65 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_to_mesh_cc {
-static void geo_node_curve_to_mesh_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::Geometry>("Profile Curve");
- b.add_output<decl::Geometry>("Mesh");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Geometry>(N_("Profile Curve"))
+ .only_realized_data()
+ .supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Fill Caps"))
+ .description(
+ N_("If the profile spline is cyclic, fill the ends of the generated mesh with N-gons"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static void geometry_set_curve_to_mesh(GeometrySet &geometry_set,
const GeometrySet &profile_set,
- const GeoNodeExecParams &params)
+ const bool fill_caps)
{
- if (!geometry_set.has_curve()) {
- if (!geometry_set.is_empty()) {
- params.error_message_add(NodeWarningType::Warning,
- TIP_("No curve data available in curve input"));
- }
- return;
- }
-
+ const CurveEval *curve = geometry_set.get_curve_for_read();
const CurveEval *profile_curve = profile_set.get_curve_for_read();
if (profile_curve == nullptr) {
- Mesh *mesh = bke::curve_to_wire_mesh(*geometry_set.get_curve_for_read());
+ Mesh *mesh = bke::curve_to_wire_mesh(*curve);
geometry_set.replace_mesh(mesh);
}
else {
- Mesh *mesh = bke::curve_to_mesh_sweep(*geometry_set.get_curve_for_read(), *profile_curve);
+ Mesh *mesh = bke::curve_to_mesh_sweep(*curve, *profile_curve, fill_caps);
geometry_set.replace_mesh(mesh);
}
}
-static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
GeometrySet profile_set = params.extract_input<GeometrySet>("Profile Curve");
+ const bool fill_caps = params.extract_input<bool>("Fill Caps");
- if (profile_set.has_instances()) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("Instances are not supported in the profile input"));
- params.set_output("Mesh", GeometrySet());
- return;
- }
-
- if (!profile_set.has_curve() && !profile_set.is_empty()) {
- params.error_message_add(NodeWarningType::Warning,
- TIP_("No curve data available in the profile input"));
- }
-
+ bool has_curve = false;
curve_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- geometry_set_curve_to_mesh(geometry_set, profile_set, params);
+ if (geometry_set.has_curve()) {
+ has_curve = true;
+ geometry_set_curve_to_mesh(geometry_set, profile_set, fill_caps);
+ }
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
});
params.set_output("Mesh", std::move(curve_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_to_mesh_cc
void register_node_type_geo_curve_to_mesh()
{
+ namespace file_ns = blender::nodes::node_geo_curve_to_mesh_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_MESH, "Curve to Mesh", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_to_mesh_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_mesh_exec;
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_MESH, "Curve to Mesh", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
new file mode 100644
index 00000000000..19efd4b7508
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
@@ -0,0 +1,414 @@
+/*
+ * 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 "BLI_array.hh"
+#include "BLI_task.hh"
+#include "BLI_timeit.hh"
+
+#include "BKE_pointcloud.h"
+#include "BKE_spline.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+void curve_create_default_rotation_attribute(Span<float3> tangents,
+ Span<float3> normals,
+ MutableSpan<float3> rotations)
+{
+ threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ rotations[i] =
+ float4x4::from_normalized_axis_data({0, 0, 0}, normals[i], tangents[i]).to_euler();
+ }
+ });
+}
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_curve_to_points_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryCurveToPoints)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Int>(N_("Count"))
+ .default_value(10)
+ .min(2)
+ .max(100000)
+ .make_available(
+ [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_RESAMPLE_COUNT; });
+ b.add_input<decl::Float>(N_("Length"))
+ .default_value(0.1f)
+ .min(0.001f)
+ .subtype(PROP_DISTANCE)
+ .make_available(
+ [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_RESAMPLE_LENGTH; });
+ b.add_output<decl::Geometry>(N_("Points"));
+ b.add_output<decl::Vector>(N_("Tangent")).field_source();
+ b.add_output<decl::Vector>(N_("Normal")).field_source();
+ b.add_output<decl::Vector>(N_("Rotation")).field_source();
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryCurveToPoints *data = MEM_cnew<NodeGeometryCurveToPoints>(__func__);
+
+ data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeGeometryCurveToPoints &storage = node_storage(*node);
+ const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
+
+ bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next;
+ bNodeSocket *length_socket = count_socket->next;
+
+ nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT);
+ nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH);
+}
+
+static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
+ const GeometryNodeCurveResampleMode mode,
+ const CurveEval &curve,
+ const Span<SplinePtr> splines)
+{
+ const int size = curve.splines().size();
+ switch (mode) {
+ case GEO_NODE_CURVE_RESAMPLE_COUNT: {
+ const int count = params.get_input<int>("Count");
+ if (count < 1) {
+ return {0};
+ }
+ Array<int> offsets(size + 1);
+ int offset = 0;
+ for (const int i : IndexRange(size)) {
+ offsets[i] = offset;
+ if (splines[i]->evaluated_points_size() > 0) {
+ offset += count;
+ }
+ }
+ offsets.last() = offset;
+ return offsets;
+ }
+ case GEO_NODE_CURVE_RESAMPLE_LENGTH: {
+ /* Don't allow asymptotic count increase for low resolution values. */
+ const float resolution = std::max(params.get_input<float>("Length"), 0.0001f);
+ Array<int> offsets(size + 1);
+ int offset = 0;
+ for (const int i : IndexRange(size)) {
+ offsets[i] = offset;
+ if (splines[i]->evaluated_points_size() > 0) {
+ offset += splines[i]->length() / resolution + 1;
+ }
+ }
+ offsets.last() = offset;
+ return offsets;
+ }
+ case GEO_NODE_CURVE_RESAMPLE_EVALUATED: {
+ return curve.evaluated_point_offsets();
+ }
+ }
+ BLI_assert_unreachable();
+ return {0};
+}
+
+/**
+ * \note: Relies on the fact that all attributes on point clouds are stored contiguously.
+ */
+static GMutableSpan ensure_point_attribute(PointCloudComponent &points,
+ const AttributeIDRef &attribute_id,
+ const CustomDataType data_type)
+{
+ points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault());
+ WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id);
+ BLI_assert(attribute);
+ return attribute.varray.get_internal_span();
+}
+
+template<typename T>
+static MutableSpan<T> ensure_point_attribute(PointCloudComponent &points,
+ const AttributeIDRef &attribute_id)
+{
+ GMutableSpan attribute = ensure_point_attribute(
+ points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>()));
+ return attribute.typed<T>();
+}
+
+namespace {
+struct AnonymousAttributeIDs {
+ StrongAnonymousAttributeID tangent_id;
+ StrongAnonymousAttributeID normal_id;
+ StrongAnonymousAttributeID rotation_id;
+};
+
+struct ResultAttributes {
+ MutableSpan<float3> positions;
+ MutableSpan<float> radii;
+
+ Map<AttributeIDRef, GMutableSpan> point_attributes;
+
+ MutableSpan<float3> tangents;
+ MutableSpan<float3> normals;
+ MutableSpan<float3> rotations;
+};
+} // namespace
+
+static ResultAttributes create_attributes_for_transfer(PointCloudComponent &points,
+ const CurveEval &curve,
+ const AnonymousAttributeIDs &attributes)
+{
+ ResultAttributes outputs;
+
+ outputs.positions = ensure_point_attribute<float3>(points, "position");
+ outputs.radii = ensure_point_attribute<float>(points, "radius");
+
+ if (attributes.tangent_id) {
+ outputs.tangents = ensure_point_attribute<float3>(points, attributes.tangent_id.get());
+ }
+ if (attributes.normal_id) {
+ outputs.normals = ensure_point_attribute<float3>(points, attributes.normal_id.get());
+ }
+ if (attributes.rotation_id) {
+ outputs.rotations = ensure_point_attribute<float3>(points, attributes.rotation_id.get());
+ }
+
+ /* Because of the invariants of the curve component, we use the attributes of the first spline
+ * as a representative for the attribute meta data all splines. Attributes from the spline domain
+ * are handled separately. */
+ curve.splines().first()->attributes.foreach_attribute(
+ [&](const AttributeIDRef &id, const AttributeMetaData &meta_data) {
+ if (id.should_be_kept()) {
+ outputs.point_attributes.add_new(
+ id, ensure_point_attribute(points, id, meta_data.data_type));
+ }
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+
+ return outputs;
+}
+
+/**
+ * TODO: For non-poly splines, this has double copies that could be avoided as part
+ * of a general look at optimizing uses of #Spline::interpolate_to_evaluated.
+ */
+static void copy_evaluated_point_attributes(const Span<SplinePtr> splines,
+ const Span<int> offsets,
+ ResultAttributes &data)
+{
+ threading::parallel_for(splines.index_range(), 64, [&](IndexRange range) {
+ for (const int i : range) {
+ const Spline &spline = *splines[i];
+ const int offset = offsets[i];
+ const int size = offsets[i + 1] - offsets[i];
+
+ data.positions.slice(offset, size).copy_from(spline.evaluated_positions());
+ spline.interpolate_to_evaluated(spline.radii()).materialize(data.radii.slice(offset, size));
+
+ for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) {
+ const AttributeIDRef attribute_id = item.key;
+ const GMutableSpan dst = item.value;
+
+ BLI_assert(spline.attributes.get_for_read(attribute_id));
+ GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
+
+ spline.interpolate_to_evaluated(spline_span).materialize(dst.slice(offset, size).data());
+ }
+
+ if (!data.tangents.is_empty()) {
+ data.tangents.slice(offset, size).copy_from(spline.evaluated_tangents());
+ }
+ if (!data.normals.is_empty()) {
+ data.normals.slice(offset, size).copy_from(spline.evaluated_normals());
+ }
+ }
+ });
+}
+
+static void copy_uniform_sample_point_attributes(const Span<SplinePtr> splines,
+ const Span<int> offsets,
+ ResultAttributes &data)
+{
+ threading::parallel_for(splines.index_range(), 64, [&](IndexRange range) {
+ for (const int i : range) {
+ const Spline &spline = *splines[i];
+ const int offset = offsets[i];
+ const int size = offsets[i + 1] - offsets[i];
+ if (size == 0) {
+ continue;
+ }
+
+ const Array<float> uniform_samples = spline.sample_uniform_index_factors(size);
+
+ spline.sample_with_index_factors<float3>(
+ spline.evaluated_positions(), uniform_samples, data.positions.slice(offset, size));
+ spline.sample_with_index_factors<float>(spline.interpolate_to_evaluated(spline.radii()),
+ uniform_samples,
+ data.radii.slice(offset, size));
+
+ for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) {
+ const AttributeIDRef attribute_id = item.key;
+ const GMutableSpan dst = item.value;
+
+ BLI_assert(spline.attributes.get_for_read(attribute_id));
+ GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
+
+ spline.sample_with_index_factors(spline.interpolate_to_evaluated(spline_span),
+ uniform_samples,
+ dst.slice(offset, size));
+ }
+
+ if (!data.tangents.is_empty()) {
+ spline.sample_with_index_factors<float3>(
+ spline.evaluated_tangents(), uniform_samples, data.tangents.slice(offset, size));
+ for (float3 &tangent : data.tangents) {
+ tangent = math::normalize(tangent);
+ }
+ }
+
+ if (!data.normals.is_empty()) {
+ spline.sample_with_index_factors<float3>(
+ spline.evaluated_normals(), uniform_samples, data.normals.slice(offset, size));
+ for (float3 &normals : data.normals) {
+ normals = math::normalize(normals);
+ }
+ }
+ }
+ });
+}
+
+static void copy_spline_domain_attributes(const CurveEval &curve,
+ const Span<int> offsets,
+ PointCloudComponent &points)
+{
+ curve.attributes.foreach_attribute(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ const GSpan curve_attribute = *curve.attributes.get_for_read(attribute_id);
+ const CPPType &type = curve_attribute.type();
+ const GMutableSpan dst = ensure_point_attribute(points, attribute_id, meta_data.data_type);
+
+ for (const int i : curve.splines().index_range()) {
+ const int offset = offsets[i];
+ const int size = offsets[i + 1] - offsets[i];
+ type.fill_assign_n(curve_attribute[i], dst[offset], size);
+ }
+
+ return true;
+ },
+ ATTR_DOMAIN_CURVE);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryCurveToPoints &storage = node_storage(params.node());
+ const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+
+ AnonymousAttributeIDs attribute_outputs;
+ attribute_outputs.tangent_id = StrongAnonymousAttributeID("Tangent");
+ attribute_outputs.normal_id = StrongAnonymousAttributeID("Normal");
+ attribute_outputs.rotation_id = StrongAnonymousAttributeID("Rotation");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (!geometry_set.has_curve()) {
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
+ return;
+ }
+ const CurveEval &curve = *geometry_set.get_curve_for_read();
+ const Span<SplinePtr> splines = curve.splines();
+ curve.assert_valid_point_attributes();
+
+ const Array<int> offsets = calculate_spline_point_offsets(params, mode, curve, splines);
+ const int total_size = offsets.last();
+ if (total_size == 0) {
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
+ return;
+ }
+
+ geometry_set.replace_pointcloud(BKE_pointcloud_new_nomain(total_size));
+ PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>();
+ ResultAttributes point_attributes = create_attributes_for_transfer(
+ points, curve, attribute_outputs);
+
+ switch (mode) {
+ case GEO_NODE_CURVE_RESAMPLE_COUNT:
+ case GEO_NODE_CURVE_RESAMPLE_LENGTH:
+ copy_uniform_sample_point_attributes(splines, offsets, point_attributes);
+ break;
+ case GEO_NODE_CURVE_RESAMPLE_EVALUATED:
+ copy_evaluated_point_attributes(splines, offsets, point_attributes);
+ break;
+ }
+
+ copy_spline_domain_attributes(curve, offsets, points);
+
+ if (!point_attributes.rotations.is_empty()) {
+ curve_create_default_rotation_attribute(
+ point_attributes.tangents, point_attributes.normals, point_attributes.rotations);
+ }
+
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES, GEO_COMPONENT_TYPE_POINT_CLOUD});
+ });
+
+ params.set_output("Points", std::move(geometry_set));
+ if (attribute_outputs.tangent_id) {
+ params.set_output(
+ "Tangent",
+ AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.tangent_id),
+ params.attribute_producer_name()));
+ }
+ if (attribute_outputs.normal_id) {
+ params.set_output(
+ "Normal",
+ AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.normal_id),
+ params.attribute_producer_name()));
+ }
+ if (attribute_outputs.rotation_id) {
+ params.set_output(
+ "Rotation",
+ AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.rotation_id),
+ params.attribute_producer_name()));
+ }
+}
+
+} // namespace blender::nodes::node_geo_curve_to_points_cc
+
+void register_node_type_geo_curve_to_points()
+{
+ namespace file_ns = blender::nodes::node_geo_curve_to_points_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_storage(
+ &ntype, "NodeGeometryCurveToPoints", node_free_standard_storage, node_copy_standard_storage);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
index 97043980899..359863d39e0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -20,50 +20,105 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
+namespace blender::nodes::node_geo_curve_trim_cc {
+
using blender::attribute_math::mix2;
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeGeometryCurveTrim)
-static void geo_node_curve_trim_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::Float>("Start").min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Float>("End").min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Float>("Start", "Start_001").min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("End", "End_001").min(0.0f).default_value(1.0f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Curve");
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Float>(N_("Start"))
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR; })
+ .supports_field();
+ b.add_input<decl::Float>(N_("End"))
+ .min(0.0f)
+ .max(1.0f)
+ .default_value(1.0f)
+ .subtype(PROP_FACTOR)
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR; })
+ .supports_field();
+ b.add_input<decl::Float>(N_("Start"), "Start_001")
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; })
+ .supports_field();
+ b.add_input<decl::Float>(N_("End"), "End_001")
+ .min(0.0f)
+ .default_value(1.0f)
+ .subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; })
+ .supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_trim_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_trim_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveTrim *data = (NodeGeometryCurveTrim *)MEM_callocN(sizeof(NodeGeometryCurveTrim),
- __func__);
+ NodeGeometryCurveTrim *data = MEM_cnew<NodeGeometryCurveTrim>(__func__);
data->mode = GEO_NODE_CURVE_SAMPLE_FACTOR;
node->storage = data;
}
-static void geo_node_curve_trim_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)node->storage;
- const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+ const NodeGeometryCurveTrim &storage = node_storage(*node);
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
bNodeSocket *start_fac = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *end_fac = start_fac->next;
bNodeSocket *start_len = end_fac->next;
bNodeSocket *end_len = start_len->next;
- nodeSetSocketAvailability(start_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR);
- nodeSetSocketAvailability(end_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR);
- nodeSetSocketAvailability(start_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH);
- nodeSetSocketAvailability(end_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH);
+ nodeSetSocketAvailability(ntree, start_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR);
+ nodeSetSocketAvailability(ntree, end_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR);
+ nodeSetSocketAvailability(ntree, start_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH);
+ nodeSetSocketAvailability(ntree, end_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH);
+}
+
+class SocketSearchOp {
+ public:
+ StringRef socket_name;
+ GeometryNodeCurveSampleMode mode;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("GeometryNodeTrimCurve");
+ node_storage(node).mode = mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+
+ search_link_ops_for_declarations(params, declaration.outputs());
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+
+ if (params.in_out() == SOCK_IN) {
+ if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ params.add_item(IFACE_("Start (Factor)"),
+ SocketSearchOp{"Start", GEO_NODE_CURVE_SAMPLE_FACTOR});
+ params.add_item(IFACE_("End (Factor)"), SocketSearchOp{"End", GEO_NODE_CURVE_SAMPLE_FACTOR});
+ params.add_item(IFACE_("Start (Length)"),
+ SocketSearchOp{"Start", GEO_NODE_CURVE_SAMPLE_LENGTH});
+ params.add_item(IFACE_("End (Length)"), SocketSearchOp{"End", GEO_NODE_CURVE_SAMPLE_LENGTH});
+ }
+ }
}
struct TrimLocation {
@@ -123,19 +178,19 @@ static void linear_trim_to_output_data(const TrimLocation &start,
/* Look up the control points to the left and right of factor, and get the factor between them. */
static TrimLocation lookup_control_point_position(const Spline::LookupResult &lookup,
- Span<int> control_point_offsets)
+ const BezierSpline &spline)
{
- const int *left_offset = std::lower_bound(
- control_point_offsets.begin(), control_point_offsets.end(), lookup.evaluated_index);
- const int index = left_offset - control_point_offsets.begin();
- const int left = control_point_offsets[index] > lookup.evaluated_index ? index - 1 : index;
- const int right = left + 1;
-
- const float factor = std::clamp(
- (lookup.evaluated_index + lookup.factor - control_point_offsets[left]) /
- (control_point_offsets[right] - control_point_offsets[left]),
- 0.0f,
- 1.0f);
+ Span<int> offsets = spline.control_point_offsets();
+
+ const int *offset = std::lower_bound(offsets.begin(), offsets.end(), lookup.evaluated_index);
+ const int index = offset - offsets.begin();
+
+ const int left = offsets[index] > lookup.evaluated_index ? index - 1 : index;
+ const int right = left == (spline.size() - 1) ? 0 : left + 1;
+
+ const float offset_in_segment = lookup.evaluated_index + lookup.factor - offsets[left];
+ const int segment_eval_size = offsets[left + 1] - offsets[left];
+ const float factor = std::clamp(offset_in_segment / segment_eval_size, 0.0f, 1.0f);
return {left, right, factor};
}
@@ -204,9 +259,9 @@ static PolySpline trim_nurbs_spline(const Spline &spline,
attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
using T = decltype(dummy);
- GVArray_Typed<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>());
+ VArray<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>());
linear_trim_to_output_data<T>(
- start, end, eval_data->get_internal_span(), dst->typed<T>());
+ start, end, eval_data.get_internal_span(), dst->typed<T>());
});
return true;
},
@@ -215,13 +270,13 @@ static PolySpline trim_nurbs_spline(const Spline &spline,
linear_trim_to_output_data<float3>(
start, end, spline.evaluated_positions(), new_spline.positions());
- GVArray_Typed<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii());
+ VArray<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii());
linear_trim_to_output_data<float>(
- start, end, evaluated_radii->get_internal_span(), new_spline.radii());
+ start, end, evaluated_radii.get_internal_span(), new_spline.radii());
- GVArray_Typed<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts());
+ VArray<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts());
linear_trim_to_output_data<float>(
- start, end, evaluated_tilts->get_internal_span(), new_spline.tilts());
+ start, end, evaluated_tilts.get_internal_span(), new_spline.tilts());
return new_spline;
}
@@ -235,10 +290,11 @@ static void trim_bezier_spline(Spline &spline,
const Spline::LookupResult &end_lookup)
{
BezierSpline &bezier_spline = static_cast<BezierSpline &>(spline);
- Span<int> control_offsets = bezier_spline.control_point_offsets();
- const TrimLocation start = lookup_control_point_position(start_lookup, control_offsets);
- TrimLocation end = lookup_control_point_position(end_lookup, control_offsets);
+ const TrimLocation start = lookup_control_point_position(start_lookup, bezier_spline);
+ TrimLocation end = lookup_control_point_position(end_lookup, bezier_spline);
+
+ const Span<int> control_offsets = bezier_spline.control_point_offsets();
/* The number of control points in the resulting spline. */
const int size = end.right_index - start.left_index + 1;
@@ -320,97 +376,245 @@ static void trim_bezier_spline(Spline &spline,
bezier_spline.resize(size);
}
+static void trim_spline(SplinePtr &spline,
+ const Spline::LookupResult start,
+ const Spline::LookupResult end)
+{
+ switch (spline->type()) {
+ case Spline::Type::Bezier:
+ trim_bezier_spline(*spline, start, end);
+ break;
+ case Spline::Type::Poly:
+ trim_poly_spline(*spline, start, end);
+ break;
+ case Spline::Type::NURBS:
+ spline = std::make_unique<PolySpline>(trim_nurbs_spline(*spline, start, end));
+ break;
+ }
+ spline->mark_cache_invalid();
+}
+
+template<typename T>
+static void to_single_point_data(const TrimLocation &trim, MutableSpan<T> data)
+{
+ data.first() = mix2<T>(trim.factor, data[trim.left_index], data[trim.right_index]);
+}
+template<typename T>
+static void to_single_point_data(const TrimLocation &trim, Span<T> src, MutableSpan<T> dst)
+{
+ dst.first() = mix2<T>(trim.factor, src[trim.left_index], src[trim.right_index]);
+}
+
+static void to_single_point_bezier(Spline &spline, const Spline::LookupResult &lookup)
+{
+ BezierSpline &bezier = static_cast<BezierSpline &>(spline);
+
+ const TrimLocation trim = lookup_control_point_position(lookup, bezier);
+
+ const BezierSpline::InsertResult new_point = bezier.calculate_segment_insertion(
+ trim.left_index, trim.right_index, trim.factor);
+ bezier.positions().first() = new_point.position;
+ bezier.handle_types_left().first() = BezierSpline::HandleType::Free;
+ bezier.handle_types_right().first() = BezierSpline::HandleType::Free;
+ bezier.handle_positions_left().first() = new_point.left_handle;
+ bezier.handle_positions_right().first() = new_point.right_handle;
+
+ to_single_point_data<float>(trim, bezier.radii());
+ to_single_point_data<float>(trim, bezier.tilts());
+ spline.attributes.foreach_attribute(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
+ std::optional<GMutableSpan> data = spline.attributes.get_for_write(attribute_id);
+ attribute_math::convert_to_static_type(data->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ to_single_point_data<T>(trim, data->typed<T>());
+ });
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+ spline.resize(1);
+}
+
+static void to_single_point_poly(Spline &spline, const Spline::LookupResult &lookup)
+{
+ const TrimLocation trim{lookup.evaluated_index, lookup.next_evaluated_index, lookup.factor};
+
+ to_single_point_data<float3>(trim, spline.positions());
+ to_single_point_data<float>(trim, spline.radii());
+ to_single_point_data<float>(trim, spline.tilts());
+ spline.attributes.foreach_attribute(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
+ std::optional<GMutableSpan> data = spline.attributes.get_for_write(attribute_id);
+ attribute_math::convert_to_static_type(data->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ to_single_point_data<T>(trim, data->typed<T>());
+ });
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+ spline.resize(1);
+}
+
+static PolySpline to_single_point_nurbs(const Spline &spline, const Spline::LookupResult &lookup)
+{
+ /* Since this outputs a poly spline, the evaluated indices are the control point indices. */
+ const TrimLocation trim{lookup.evaluated_index, lookup.next_evaluated_index, lookup.factor};
+
+ /* Create poly spline and copy trimmed data to it. */
+ PolySpline new_spline;
+ new_spline.resize(1);
+
+ spline.attributes.foreach_attribute(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ new_spline.attributes.create(attribute_id, meta_data.data_type);
+ std::optional<GSpan> src = spline.attributes.get_for_read(attribute_id);
+ std::optional<GMutableSpan> dst = new_spline.attributes.get_for_write(attribute_id);
+ attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>());
+ to_single_point_data<T>(trim, eval_data.get_internal_span(), dst->typed<T>());
+ });
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+
+ to_single_point_data<float3>(trim, spline.evaluated_positions(), new_spline.positions());
+
+ VArray<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii());
+ to_single_point_data<float>(trim, evaluated_radii.get_internal_span(), new_spline.radii());
+
+ VArray<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts());
+ to_single_point_data<float>(trim, evaluated_tilts.get_internal_span(), new_spline.tilts());
+
+ return new_spline;
+}
+
+static void to_single_point_spline(SplinePtr &spline, const Spline::LookupResult &lookup)
+{
+ switch (spline->type()) {
+ case Spline::Type::Bezier:
+ to_single_point_bezier(*spline, lookup);
+ break;
+ case Spline::Type::Poly:
+ to_single_point_poly(*spline, lookup);
+ break;
+ case Spline::Type::NURBS:
+ spline = std::make_unique<PolySpline>(to_single_point_nurbs(*spline, lookup));
+ break;
+ }
+}
+
static void geometry_set_curve_trim(GeometrySet &geometry_set,
const GeometryNodeCurveSampleMode mode,
- const float start,
- const float end)
+ Field<float> &start_field,
+ Field<float> &end_field)
{
if (!geometry_set.has_curve()) {
return;
}
+ CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(start_field);
+ evaluator.add(end_field);
+ evaluator.evaluate();
+ const blender::VArray<float> &starts = evaluator.get_evaluated<float>(0);
+ const blender::VArray<float> &ends = evaluator.get_evaluated<float>(1);
+
CurveEval &curve = *geometry_set.get_curve_for_write();
MutableSpan<SplinePtr> splines = curve.splines();
threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
- Spline &spline = *splines[i];
+ SplinePtr &spline = splines[i];
- /* Currently this node doesn't support cyclic splines, it could in the future though. */
- if (spline.is_cyclic()) {
+ /* Currently trimming cyclic splines is not supported. It could be in the future though. */
+ if (spline->is_cyclic()) {
continue;
}
- /* Return a spline with one point instead of implicitly
- * reversing the spline or switching the parameters. */
- if (end < start) {
- spline.resize(1);
+ if (spline->evaluated_edges_size() == 0) {
continue;
}
- const Spline::LookupResult start_lookup =
- (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) ?
- spline.lookup_evaluated_length(std::clamp(start, 0.0f, spline.length())) :
- spline.lookup_evaluated_factor(std::clamp(start, 0.0f, 1.0f));
- const Spline::LookupResult end_lookup =
- (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) ?
- spline.lookup_evaluated_length(std::clamp(end, 0.0f, spline.length())) :
- spline.lookup_evaluated_factor(std::clamp(end, 0.0f, 1.0f));
-
- switch (spline.type()) {
- case Spline::Type::Bezier:
- trim_bezier_spline(spline, start_lookup, end_lookup);
- break;
- case Spline::Type::Poly:
- trim_poly_spline(spline, start_lookup, end_lookup);
- break;
- case Spline::Type::NURBS:
- splines[i] = std::make_unique<PolySpline>(
- trim_nurbs_spline(spline, start_lookup, end_lookup));
- break;
+ const float length = spline->length();
+ if (length == 0.0f) {
+ continue;
+ }
+
+ const float start = starts[i];
+ const float end = ends[i];
+
+ /* When the start and end samples are reversed, instead of implicitly reversing the spline
+ * or switching the parameters, create a single point spline with the end sample point. */
+ if (end <= start) {
+ if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
+ to_single_point_spline(spline,
+ spline->lookup_evaluated_length(std::clamp(start, 0.0f, length)));
+ }
+ else {
+ to_single_point_spline(spline,
+ spline->lookup_evaluated_factor(std::clamp(start, 0.0f, 1.0f)));
+ }
+ continue;
+ }
+
+ if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
+ trim_spline(spline,
+ spline->lookup_evaluated_length(std::clamp(start, 0.0f, length)),
+ spline->lookup_evaluated_length(std::clamp(end, 0.0f, length)));
+ }
+ else {
+ trim_spline(spline,
+ spline->lookup_evaluated_factor(std::clamp(start, 0.0f, 1.0f)),
+ spline->lookup_evaluated_factor(std::clamp(end, 0.0f, 1.0f)));
}
- splines[i]->mark_cache_invalid();
}
});
}
-static void geo_node_curve_trim_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)params.node().storage;
- const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+ const NodeGeometryCurveTrim &storage = node_storage(params.node());
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
if (mode == GEO_NODE_CURVE_SAMPLE_FACTOR) {
- const float start = params.extract_input<float>("Start");
- const float end = params.extract_input<float>("End");
+ Field<float> start_field = params.extract_input<Field<float>>("Start");
+ Field<float> end_field = params.extract_input<Field<float>>("End");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- geometry_set_curve_trim(geometry_set, mode, start, end);
+ geometry_set_curve_trim(geometry_set, mode, start_field, end_field);
});
}
else if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
- const float start = params.extract_input<float>("Start_001");
- const float end = params.extract_input<float>("End_001");
+ Field<float> start_field = params.extract_input<Field<float>>("Start_001");
+ Field<float> end_field = params.extract_input<Field<float>>("End_001");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- geometry_set_curve_trim(geometry_set, mode, start, end);
+ geometry_set_curve_trim(geometry_set, mode, start_field, end_field);
});
}
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_trim_cc
void register_node_type_geo_curve_trim()
{
+ namespace file_ns = blender::nodes::node_geo_curve_trim_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_TRIM, "Curve Trim", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_trim_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_trim_layout;
- ntype.declare = blender::nodes::geo_node_curve_trim_declare;
+ geo_node_type_base(&ntype, GEO_NODE_TRIM_CURVE, "Trim Curve", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
node_type_storage(
&ntype, "NodeGeometryCurveTrim", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_curve_trim_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_trim_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
new file mode 100644
index 00000000000..8b762abd29b
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -0,0 +1,1399 @@
+/*
+ * 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 "UI_interface.h"
+#include "UI_resources.h"
+
+#include "BLI_array.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+#include "BKE_pointcloud.h"
+#include "BKE_spline.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_delete_geometry_cc {
+
+using blender::bke::CustomDataAttributes;
+
+template<typename T>
+static void copy_data_based_on_mask(Span<T> data, MutableSpan<T> r_data, IndexMask mask)
+{
+ for (const int i_out : mask.index_range()) {
+ r_data[i_out] = data[mask[i_out]];
+ }
+}
+
+template<typename T>
+static void copy_data_based_on_map(Span<T> src, MutableSpan<T> dst, Span<int> index_map)
+{
+ for (const int i_src : index_map.index_range()) {
+ const int i_dst = index_map[i_src];
+ if (i_dst != -1) {
+ dst[i_dst] = src[i_src];
+ }
+ }
+}
+
+/** Utility function for making an IndexMask from a boolean selection. The indices vector should
+ * live at least as long as the returned IndexMask.
+ */
+static IndexMask index_mask_indices(Span<bool> mask, const bool invert, Vector<int64_t> &indices)
+{
+ for (const int i : mask.index_range()) {
+ if (mask[i] != invert) {
+ indices.append(i);
+ }
+ }
+ return IndexMask(indices);
+}
+
+/**
+ * Copies the attributes with a domain in `domains` to `result_component`.
+ */
+static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes,
+ const GeometryComponent &in_component,
+ GeometryComponent &result_component,
+ const Span<AttributeDomain> domains)
+{
+ for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id);
+ if (!attribute) {
+ continue;
+ }
+
+ /* Only copy if it is on a domain we want. */
+ if (!domains.contains(attribute.domain)) {
+ continue;
+ }
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
+
+ OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
+ attribute_id, attribute.domain, data_type);
+
+ if (!result_attribute) {
+ continue;
+ }
+
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> span{attribute.varray.typed<T>()};
+ MutableSpan<T> out_span = result_attribute.as_span<T>();
+ out_span.copy_from(span);
+ });
+ result_attribute.save();
+ }
+}
+
+/**
+ * For each attribute with a domain in `domains` it copies the parts of that attribute which lie in
+ * the mask to `result_component`.
+ */
+static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKind> &attributes,
+ const GeometryComponent &in_component,
+ GeometryComponent &result_component,
+ const AttributeDomain domain,
+ const IndexMask mask)
+{
+ for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id);
+ if (!attribute) {
+ continue;
+ }
+
+ /* Only copy if it is on a domain we want. */
+ if (domain != attribute.domain) {
+ continue;
+ }
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
+
+ OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
+ attribute_id, attribute.domain, data_type);
+
+ if (!result_attribute) {
+ continue;
+ }
+
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> span{attribute.varray.typed<T>()};
+ MutableSpan<T> out_span = result_attribute.as_span<T>();
+ copy_data_based_on_mask(span, out_span, mask);
+ });
+ result_attribute.save();
+ }
+}
+
+static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind> &attributes,
+ const GeometryComponent &in_component,
+ GeometryComponent &result_component,
+ const AttributeDomain domain,
+ const Span<int> index_map)
+{
+ for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id);
+ if (!attribute) {
+ continue;
+ }
+
+ /* Only copy if it is on a domain we want. */
+ if (domain != attribute.domain) {
+ continue;
+ }
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
+
+ OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
+ attribute_id, attribute.domain, data_type);
+
+ if (!result_attribute) {
+ continue;
+ }
+
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> span{attribute.varray.typed<T>()};
+ MutableSpan<T> out_span = result_attribute.as_span<T>();
+ copy_data_based_on_map(span, out_span, index_map);
+ });
+ result_attribute.save();
+ }
+}
+
+static void copy_face_corner_attributes(const Map<AttributeIDRef, AttributeKind> &attributes,
+ const GeometryComponent &in_component,
+ GeometryComponent &out_component,
+ const int num_selected_loops,
+ const Span<int> selected_poly_indices,
+ const Mesh &mesh_in)
+{
+ Vector<int64_t> indices;
+ indices.reserve(num_selected_loops);
+ for (const int src_poly_index : selected_poly_indices) {
+ const MPoly &src_poly = mesh_in.mpoly[src_poly_index];
+ const int src_loop_start = src_poly.loopstart;
+ const int tot_loop = src_poly.totloop;
+ for (const int i : IndexRange(tot_loop)) {
+ indices.append_unchecked(src_loop_start + i);
+ }
+ }
+ copy_attributes_based_on_mask(
+ attributes, in_component, out_component, ATTR_DOMAIN_CORNER, IndexMask(indices));
+}
+
+static void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map)
+{
+ BLI_assert(src_mesh.totvert == vertex_map.size());
+ for (const int i_src : vertex_map.index_range()) {
+ const int i_dst = vertex_map[i_src];
+ if (i_dst == -1) {
+ continue;
+ }
+
+ const MVert &v_src = src_mesh.mvert[i_src];
+ MVert &v_dst = dst_mesh.mvert[i_dst];
+
+ v_dst = v_src;
+ }
+}
+
+static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span<int> edge_map)
+{
+ BLI_assert(src_mesh.totedge == edge_map.size());
+ for (const int i_src : IndexRange(src_mesh.totedge)) {
+ const int i_dst = edge_map[i_src];
+ if (ELEM(i_dst, -1, -2)) {
+ continue;
+ }
+
+ const MEdge &e_src = src_mesh.medge[i_src];
+ MEdge &e_dst = dst_mesh.medge[i_dst];
+
+ e_dst = e_src;
+ e_dst.v1 = e_src.v1;
+ e_dst.v2 = e_src.v2;
+ }
+}
+
+static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map,
+ Span<int> edge_map)
+{
+ BLI_assert(src_mesh.totvert == vertex_map.size());
+ BLI_assert(src_mesh.totedge == edge_map.size());
+ for (const int i_src : IndexRange(src_mesh.totedge)) {
+ const int i_dst = edge_map[i_src];
+ if (i_dst == -1) {
+ continue;
+ }
+
+ const MEdge &e_src = src_mesh.medge[i_src];
+ MEdge &e_dst = dst_mesh.medge[i_dst];
+
+ e_dst = e_src;
+ e_dst.v1 = vertex_map[e_src.v1];
+ e_dst.v2 = vertex_map[e_src.v2];
+ }
+}
+
+/* Faces and edges changed but vertices are the same. */
+static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> edge_map,
+ Span<int> masked_poly_indices,
+ Span<int> new_loop_starts)
+{
+ for (const int i_dst : masked_poly_indices.index_range()) {
+ const int i_src = masked_poly_indices[i_dst];
+
+ const MPoly &mp_src = src_mesh.mpoly[i_src];
+ MPoly &mp_dst = dst_mesh.mpoly[i_dst];
+ const int i_ml_src = mp_src.loopstart;
+ const int i_ml_dst = new_loop_starts[i_dst];
+
+ const MLoop *ml_src = src_mesh.mloop + i_ml_src;
+ MLoop *ml_dst = dst_mesh.mloop + i_ml_dst;
+
+ mp_dst = mp_src;
+ mp_dst.loopstart = i_ml_dst;
+ for (int i : IndexRange(mp_src.totloop)) {
+ ml_dst[i].v = ml_src[i].v;
+ ml_dst[i].e = edge_map[ml_src[i].e];
+ }
+ }
+}
+
+/* Only faces changed. */
+static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> masked_poly_indices,
+ Span<int> new_loop_starts)
+{
+ for (const int i_dst : masked_poly_indices.index_range()) {
+ const int i_src = masked_poly_indices[i_dst];
+
+ const MPoly &mp_src = src_mesh.mpoly[i_src];
+ MPoly &mp_dst = dst_mesh.mpoly[i_dst];
+ const int i_ml_src = mp_src.loopstart;
+ const int i_ml_dst = new_loop_starts[i_dst];
+
+ const MLoop *ml_src = src_mesh.mloop + i_ml_src;
+ MLoop *ml_dst = dst_mesh.mloop + i_ml_dst;
+
+ mp_dst = mp_src;
+ mp_dst.loopstart = i_ml_dst;
+ for (int i : IndexRange(mp_src.totloop)) {
+ ml_dst[i].v = ml_src[i].v;
+ ml_dst[i].e = ml_src[i].e;
+ }
+ }
+}
+
+static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map,
+ Span<int> edge_map,
+ Span<int> masked_poly_indices,
+ Span<int> new_loop_starts)
+{
+ for (const int i_dst : masked_poly_indices.index_range()) {
+ const int i_src = masked_poly_indices[i_dst];
+
+ const MPoly &mp_src = src_mesh.mpoly[i_src];
+ MPoly &mp_dst = dst_mesh.mpoly[i_dst];
+ const int i_ml_src = mp_src.loopstart;
+ const int i_ml_dst = new_loop_starts[i_dst];
+
+ const MLoop *ml_src = src_mesh.mloop + i_ml_src;
+ MLoop *ml_dst = dst_mesh.mloop + i_ml_dst;
+
+ mp_dst = mp_src;
+ mp_dst.loopstart = i_ml_dst;
+ for (int i : IndexRange(mp_src.totloop)) {
+ ml_dst[i].v = vertex_map[ml_src[i].v];
+ ml_dst[i].e = edge_map[ml_src[i].e];
+ }
+ }
+}
+
+static void spline_copy_builtin_attributes(const Spline &spline,
+ Spline &r_spline,
+ const IndexMask mask)
+{
+ copy_data_based_on_mask(spline.positions(), r_spline.positions(), mask);
+ copy_data_based_on_mask(spline.radii(), r_spline.radii(), mask);
+ copy_data_based_on_mask(spline.tilts(), r_spline.tilts(), mask);
+ switch (spline.type()) {
+ case Spline::Type::Poly:
+ break;
+ case Spline::Type::Bezier: {
+ const BezierSpline &src = static_cast<const BezierSpline &>(spline);
+ BezierSpline &dst = static_cast<BezierSpline &>(r_spline);
+ copy_data_based_on_mask(src.handle_positions_left(), dst.handle_positions_left(), mask);
+ copy_data_based_on_mask(src.handle_positions_right(), dst.handle_positions_right(), mask);
+ copy_data_based_on_mask(src.handle_types_left(), dst.handle_types_left(), mask);
+ copy_data_based_on_mask(src.handle_types_right(), dst.handle_types_right(), mask);
+ break;
+ }
+ case Spline::Type::NURBS: {
+ const NURBSpline &src = static_cast<const NURBSpline &>(spline);
+ NURBSpline &dst = static_cast<NURBSpline &>(r_spline);
+ copy_data_based_on_mask(src.weights(), dst.weights(), mask);
+ break;
+ }
+ }
+}
+
+static void copy_dynamic_attributes(const CustomDataAttributes &src,
+ CustomDataAttributes &dst,
+ const IndexMask mask)
+{
+ src.foreach_attribute(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> src_attribute = src.get_for_read(attribute_id);
+ BLI_assert(src_attribute);
+
+ if (!dst.create(attribute_id, meta_data.data_type)) {
+ /* Since the source spline of the same type had the attribute, adding it should work.
+ */
+ BLI_assert_unreachable();
+ }
+
+ std::optional<GMutableSpan> new_attribute = dst.get_for_write(attribute_id);
+ BLI_assert(new_attribute);
+
+ attribute_math::convert_to_static_type(new_attribute->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_data_based_on_mask(src_attribute->typed<T>(), new_attribute->typed<T>(), mask);
+ });
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+}
+
+/**
+ * Deletes points in the spline. Those not in the mask are deleted. The spline is not split into
+ * multiple newer splines.
+ */
+static SplinePtr spline_delete(const Spline &spline, const IndexMask mask)
+{
+ SplinePtr new_spline = spline.copy_only_settings();
+ new_spline->resize(mask.size());
+
+ spline_copy_builtin_attributes(spline, *new_spline, mask);
+ copy_dynamic_attributes(spline.attributes, new_spline->attributes, mask);
+
+ return new_spline;
+}
+
+static std::unique_ptr<CurveEval> curve_separate(const CurveEval &input_curve,
+ const Span<bool> selection,
+ const AttributeDomain selection_domain,
+ const bool invert)
+{
+ Span<SplinePtr> input_splines = input_curve.splines();
+ std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
+
+ /* Keep track of which splines were copied to the result to copy spline domain attributes. */
+ Vector<int64_t> copied_splines;
+
+ if (selection_domain == ATTR_DOMAIN_CURVE) {
+ /* Operates on each of the splines as a whole, i.e. not on the points in the splines
+ * themselves. */
+ for (const int i : selection.index_range()) {
+ if (selection[i] != invert) {
+ output_curve->add_spline(input_splines[i]->copy());
+ copied_splines.append(i);
+ }
+ }
+ }
+ else {
+ /* Operates on the points in the splines themselves. */
+
+ /* Reuse index vector for each spline. */
+ Vector<int64_t> indices_to_copy;
+
+ int selection_index = 0;
+ for (const int i : input_splines.index_range()) {
+ const Spline &spline = *input_splines[i];
+
+ indices_to_copy.clear();
+ for (const int i_point : IndexRange(spline.size())) {
+ if (selection[selection_index] != invert) {
+ /* Append i_point instead of selection_index because we need indices local to the spline
+ * for copying. */
+ indices_to_copy.append(i_point);
+ }
+ selection_index++;
+ }
+
+ /* Avoid creating an empty spline. */
+ if (indices_to_copy.is_empty()) {
+ continue;
+ }
+
+ SplinePtr new_spline = spline_delete(spline, IndexMask(indices_to_copy));
+ output_curve->add_spline(std::move(new_spline));
+ copied_splines.append(i);
+ }
+ }
+
+ if (copied_splines.is_empty()) {
+ return {};
+ }
+
+ output_curve->attributes.reallocate(output_curve->splines().size());
+ copy_dynamic_attributes(
+ input_curve.attributes, output_curve->attributes, IndexMask(copied_splines));
+
+ return output_curve;
+}
+
+static void separate_curve_selection(GeometrySet &geometry_set,
+ const Field<bool> &selection_field,
+ const AttributeDomain selection_domain,
+ const bool invert)
+{
+ const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
+ GeometryComponentFieldContext field_context{src_component, selection_domain};
+
+ fn::FieldEvaluator selection_evaluator{field_context,
+ src_component.attribute_domain_size(selection_domain)};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
+ std::unique_ptr<CurveEval> r_curve = curve_separate(
+ *src_component.get_for_read(), selection, selection_domain, invert);
+ if (r_curve) {
+ geometry_set.replace_curve(r_curve.release());
+ }
+ else {
+ geometry_set.replace_curve(nullptr);
+ }
+}
+
+static void separate_point_cloud_selection(GeometrySet &geometry_set,
+ const Field<bool> &selection_field,
+ const bool invert)
+{
+ const PointCloudComponent &src_points =
+ *geometry_set.get_component_for_read<PointCloudComponent>();
+ GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT};
+
+ fn::FieldEvaluator selection_evaluator{field_context,
+ src_points.attribute_domain_size(ATTR_DOMAIN_POINT)};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
+
+ Vector<int64_t> indices;
+ const IndexMask mask = index_mask_indices(selection, invert, indices);
+ const int total = mask.size();
+ PointCloud *pointcloud = BKE_pointcloud_new_nomain(total);
+
+ if (total == 0) {
+ geometry_set.replace_pointcloud(pointcloud);
+ return;
+ }
+
+ PointCloudComponent dst_points;
+ dst_points.replace(pointcloud, GeometryOwnershipType::Editable);
+
+ Map<AttributeIDRef, AttributeKind> attributes;
+ geometry_set.gather_attributes_for_propagation(
+ {GEO_COMPONENT_TYPE_POINT_CLOUD}, GEO_COMPONENT_TYPE_POINT_CLOUD, false, attributes);
+
+ copy_attributes_based_on_mask(attributes, src_points, dst_points, ATTR_DOMAIN_POINT, mask);
+ geometry_set.replace_pointcloud(pointcloud);
+}
+
+static void separate_instance_selection(GeometrySet &geometry_set,
+ const Field<bool> &selection_field,
+ const bool invert)
+{
+ InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
+
+ const int domain_size = instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+ const VArray_Span<bool> &selection = evaluator.get_evaluated<bool>(0);
+
+ Vector<int64_t> indices;
+ const IndexMask mask = index_mask_indices(selection, invert, indices);
+
+ if (mask.is_empty()) {
+ geometry_set.remove<InstancesComponent>();
+ return;
+ }
+
+ instances.remove_instances(mask);
+}
+
+static void compute_selected_vertices_from_vertex_selection(const Span<bool> vertex_selection,
+ const bool invert,
+ MutableSpan<int> r_vertex_map,
+ int *r_num_selected_vertices)
+{
+ BLI_assert(vertex_selection.size() == r_vertex_map.size());
+
+ int num_selected_vertices = 0;
+ for (const int i : r_vertex_map.index_range()) {
+ if (vertex_selection[i] != invert) {
+ r_vertex_map[i] = num_selected_vertices;
+ num_selected_vertices++;
+ }
+ else {
+ r_vertex_map[i] = -1;
+ }
+ }
+
+ *r_num_selected_vertices = num_selected_vertices;
+}
+
+static void compute_selected_edges_from_vertex_selection(const Mesh &mesh,
+ const Span<bool> vertex_selection,
+ const bool invert,
+ MutableSpan<int> r_edge_map,
+ int *r_num_selected_edges)
+{
+ BLI_assert(mesh.totedge == r_edge_map.size());
+
+ int num_selected_edges = 0;
+ for (const int i : IndexRange(mesh.totedge)) {
+ const MEdge &edge = mesh.medge[i];
+
+ /* Only add the edge if both vertices will be in the new mesh. */
+ if (vertex_selection[edge.v1] != invert && vertex_selection[edge.v2] != invert) {
+ r_edge_map[i] = num_selected_edges;
+ num_selected_edges++;
+ }
+ else {
+ r_edge_map[i] = -1;
+ }
+ }
+
+ *r_num_selected_edges = num_selected_edges;
+}
+
+static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh,
+ const Span<bool> vertex_selection,
+ const bool invert,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ int *r_num_selected_polys,
+ int *r_num_selected_loops)
+{
+ BLI_assert(mesh.totvert == vertex_selection.size());
+
+ r_selected_poly_indices.reserve(mesh.totpoly);
+ r_loop_starts.reserve(mesh.totloop);
+
+ int num_selected_loops = 0;
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &poly_src = mesh.mpoly[i];
+
+ bool all_verts_in_selection = true;
+ Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
+ for (const MLoop &loop : loops_src) {
+ if (vertex_selection[loop.v] == invert) {
+ all_verts_in_selection = false;
+ break;
+ }
+ }
+
+ if (all_verts_in_selection) {
+ r_selected_poly_indices.append_unchecked(i);
+ r_loop_starts.append_unchecked(num_selected_loops);
+ num_selected_loops += poly_src.totloop;
+ }
+ }
+
+ *r_num_selected_polys = r_selected_poly_indices.size();
+ *r_num_selected_loops = num_selected_loops;
+}
+
+/**
+ * Checks for every edge if it is in `edge_selection`. If it is, then the two vertices of the
+ * edge are kept along with the edge.
+ */
+static void compute_selected_vertices_and_edges_from_edge_selection(
+ const Mesh &mesh,
+ const Span<bool> edge_selection,
+ const bool invert,
+ MutableSpan<int> r_vertex_map,
+ MutableSpan<int> r_edge_map,
+ int *r_num_selected_vertices,
+ int *r_num_selected_edges)
+{
+ BLI_assert(mesh.totedge == edge_selection.size());
+
+ int num_selected_edges = 0;
+ int num_selected_vertices = 0;
+ for (const int i : IndexRange(mesh.totedge)) {
+ const MEdge &edge = mesh.medge[i];
+ if (edge_selection[i] != invert) {
+ r_edge_map[i] = num_selected_edges;
+ num_selected_edges++;
+ if (r_vertex_map[edge.v1] == -1) {
+ r_vertex_map[edge.v1] = num_selected_vertices;
+ num_selected_vertices++;
+ }
+ if (r_vertex_map[edge.v2] == -1) {
+ r_vertex_map[edge.v2] = num_selected_vertices;
+ num_selected_vertices++;
+ }
+ }
+ else {
+ r_edge_map[i] = -1;
+ }
+ }
+
+ *r_num_selected_vertices = num_selected_vertices;
+ *r_num_selected_edges = num_selected_edges;
+}
+
+/**
+ * Checks for every edge if it is in `edge_selection`.
+ */
+static void compute_selected_edges_from_edge_selection(const Mesh &mesh,
+ const Span<bool> edge_selection,
+ const bool invert,
+ MutableSpan<int> r_edge_map,
+ int *r_num_selected_edges)
+{
+ BLI_assert(mesh.totedge == edge_selection.size());
+
+ int num_selected_edges = 0;
+ for (const int i : IndexRange(mesh.totedge)) {
+ if (edge_selection[i] != invert) {
+ r_edge_map[i] = num_selected_edges;
+ num_selected_edges++;
+ }
+ else {
+ r_edge_map[i] = -1;
+ }
+ }
+
+ *r_num_selected_edges = num_selected_edges;
+}
+
+/**
+ * Checks for every polygon if all the edges are in `edge_selection`. If they are, then that
+ * polygon is kept.
+ */
+static void compute_selected_polygons_from_edge_selection(const Mesh &mesh,
+ const Span<bool> edge_selection,
+ const bool invert,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ int *r_num_selected_polys,
+ int *r_num_selected_loops)
+{
+ r_selected_poly_indices.reserve(mesh.totpoly);
+ r_loop_starts.reserve(mesh.totloop);
+
+ int num_selected_loops = 0;
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &poly_src = mesh.mpoly[i];
+
+ bool all_edges_in_selection = true;
+ Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
+ for (const MLoop &loop : loops_src) {
+ if (edge_selection[loop.e] == invert) {
+ all_edges_in_selection = false;
+ break;
+ }
+ }
+
+ if (all_edges_in_selection) {
+ r_selected_poly_indices.append_unchecked(i);
+ r_loop_starts.append_unchecked(num_selected_loops);
+ num_selected_loops += poly_src.totloop;
+ }
+ }
+
+ *r_num_selected_polys = r_selected_poly_indices.size();
+ *r_num_selected_loops = num_selected_loops;
+}
+
+/**
+ * Checks for every edge and polygon if all its vertices are in `vertex_selection`.
+ */
+static void compute_selected_mesh_data_from_vertex_selection_edge_face(
+ const Mesh &mesh,
+ const Span<bool> vertex_selection,
+ const bool invert,
+ MutableSpan<int> r_edge_map,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ int *r_num_selected_edges,
+ int *r_num_selected_polys,
+ int *r_num_selected_loops)
+{
+
+ compute_selected_edges_from_vertex_selection(
+ mesh, vertex_selection, invert, r_edge_map, r_num_selected_edges);
+
+ compute_selected_polygons_from_vertex_selection(mesh,
+ vertex_selection,
+ invert,
+ r_selected_poly_indices,
+ r_loop_starts,
+ r_num_selected_polys,
+ r_num_selected_loops);
+}
+
+/**
+ * Checks for every vertex if it is in `vertex_selection`. The polygons and edges are kept if all
+ * vertices of that polygon or edge are in the selection.
+ */
+static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh,
+ const Span<bool> vertex_selection,
+ const bool invert,
+ MutableSpan<int> r_vertex_map,
+ MutableSpan<int> r_edge_map,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ int *r_num_selected_vertices,
+ int *r_num_selected_edges,
+ int *r_num_selected_polys,
+ int *r_num_selected_loops)
+{
+ compute_selected_vertices_from_vertex_selection(
+ vertex_selection, invert, r_vertex_map, r_num_selected_vertices);
+
+ compute_selected_edges_from_vertex_selection(
+ mesh, vertex_selection, invert, r_edge_map, r_num_selected_edges);
+
+ compute_selected_polygons_from_vertex_selection(mesh,
+ vertex_selection,
+ invert,
+ r_selected_poly_indices,
+ r_loop_starts,
+ r_num_selected_polys,
+ r_num_selected_loops);
+}
+
+/**
+ * Checks for every edge if it is in `edge_selection`. The polygons are kept if all edges are in
+ * the selection.
+ */
+static void compute_selected_mesh_data_from_edge_selection_edge_face(
+ const Mesh &mesh,
+ const Span<bool> edge_selection,
+ const bool invert,
+ MutableSpan<int> r_edge_map,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ int *r_num_selected_edges,
+ int *r_num_selected_polys,
+ int *r_num_selected_loops)
+{
+ compute_selected_edges_from_edge_selection(
+ mesh, edge_selection, invert, r_edge_map, r_num_selected_edges);
+ compute_selected_polygons_from_edge_selection(mesh,
+ edge_selection,
+ invert,
+ r_selected_poly_indices,
+ r_loop_starts,
+ r_num_selected_polys,
+ r_num_selected_loops);
+}
+
+/**
+ * Checks for every edge if it is in `edge_selection`. If it is, the vertices belonging to
+ * that edge are kept as well. The polygons are kept if all edges are in the selection.
+ */
+static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh,
+ const Span<bool> edge_selection,
+ const bool invert,
+ MutableSpan<int> r_vertex_map,
+ MutableSpan<int> r_edge_map,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ int *r_num_selected_vertices,
+ int *r_num_selected_edges,
+ int *r_num_selected_polys,
+ int *r_num_selected_loops)
+{
+ r_vertex_map.fill(-1);
+ compute_selected_vertices_and_edges_from_edge_selection(mesh,
+ edge_selection,
+ invert,
+ r_vertex_map,
+ r_edge_map,
+ r_num_selected_vertices,
+ r_num_selected_edges);
+ compute_selected_polygons_from_edge_selection(mesh,
+ edge_selection,
+ invert,
+ r_selected_poly_indices,
+ r_loop_starts,
+ r_num_selected_polys,
+ r_num_selected_loops);
+}
+
+/**
+ * Checks for every polygon if it is in `poly_selection`.
+ */
+static void compute_selected_polygons_from_poly_selection(const Mesh &mesh,
+ const Span<bool> poly_selection,
+ const bool invert,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ int *r_num_selected_polys,
+ int *r_num_selected_loops)
+{
+ BLI_assert(mesh.totpoly == poly_selection.size());
+
+ r_selected_poly_indices.reserve(mesh.totpoly);
+ r_loop_starts.reserve(mesh.totloop);
+
+ int num_selected_loops = 0;
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &poly_src = mesh.mpoly[i];
+ /* We keep this one. */
+ if (poly_selection[i] != invert) {
+ r_selected_poly_indices.append_unchecked(i);
+ r_loop_starts.append_unchecked(num_selected_loops);
+ num_selected_loops += poly_src.totloop;
+ }
+ }
+ *r_num_selected_polys = r_selected_poly_indices.size();
+ *r_num_selected_loops = num_selected_loops;
+}
+/**
+ * Checks for every polygon if it is in `poly_selection`. If it is, the edges
+ * belonging to that polygon are kept as well.
+ */
+static void compute_selected_mesh_data_from_poly_selection_edge_face(
+ const Mesh &mesh,
+ const Span<bool> poly_selection,
+ const bool invert,
+ MutableSpan<int> r_edge_map,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ int *r_num_selected_edges,
+ int *r_num_selected_polys,
+ int *r_num_selected_loops)
+{
+ BLI_assert(mesh.totpoly == poly_selection.size());
+ BLI_assert(mesh.totedge == r_edge_map.size());
+ r_edge_map.fill(-1);
+
+ r_selected_poly_indices.reserve(mesh.totpoly);
+ r_loop_starts.reserve(mesh.totloop);
+
+ int num_selected_loops = 0;
+ int num_selected_edges = 0;
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &poly_src = mesh.mpoly[i];
+ /* We keep this one. */
+ if (poly_selection[i] != invert) {
+ r_selected_poly_indices.append_unchecked(i);
+ r_loop_starts.append_unchecked(num_selected_loops);
+ num_selected_loops += poly_src.totloop;
+
+ /* Add the vertices and the edges. */
+ Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
+ for (const MLoop &loop : loops_src) {
+ /* Check first if it has not yet been added. */
+ if (r_edge_map[loop.e] == -1) {
+ r_edge_map[loop.e] = num_selected_edges;
+ num_selected_edges++;
+ }
+ }
+ }
+ }
+ *r_num_selected_edges = num_selected_edges;
+ *r_num_selected_polys = r_selected_poly_indices.size();
+ *r_num_selected_loops = num_selected_loops;
+}
+
+/**
+ * Checks for every polygon if it is in `poly_selection`. If it is, the edges and vertices
+ * belonging to that polygon are kept as well.
+ */
+static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
+ const Span<bool> poly_selection,
+ const bool invert,
+ MutableSpan<int> r_vertex_map,
+ MutableSpan<int> r_edge_map,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ int *r_num_selected_vertices,
+ int *r_num_selected_edges,
+ int *r_num_selected_polys,
+ int *r_num_selected_loops)
+{
+ BLI_assert(mesh.totpoly == poly_selection.size());
+ BLI_assert(mesh.totedge == r_edge_map.size());
+ r_vertex_map.fill(-1);
+ r_edge_map.fill(-1);
+
+ r_selected_poly_indices.reserve(mesh.totpoly);
+ r_loop_starts.reserve(mesh.totloop);
+
+ int num_selected_loops = 0;
+ int num_selected_vertices = 0;
+ int num_selected_edges = 0;
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &poly_src = mesh.mpoly[i];
+ /* We keep this one. */
+ if (poly_selection[i] != invert) {
+ r_selected_poly_indices.append_unchecked(i);
+ r_loop_starts.append_unchecked(num_selected_loops);
+ num_selected_loops += poly_src.totloop;
+
+ /* Add the vertices and the edges. */
+ Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
+ for (const MLoop &loop : loops_src) {
+ /* Check first if it has not yet been added. */
+ if (r_vertex_map[loop.v] == -1) {
+ r_vertex_map[loop.v] = num_selected_vertices;
+ num_selected_vertices++;
+ }
+ if (r_edge_map[loop.e] == -1) {
+ r_edge_map[loop.e] = num_selected_edges;
+ num_selected_edges++;
+ }
+ }
+ }
+ }
+ *r_num_selected_vertices = num_selected_vertices;
+ *r_num_selected_edges = num_selected_edges;
+ *r_num_selected_polys = r_selected_poly_indices.size();
+ *r_num_selected_loops = num_selected_loops;
+}
+
+/**
+ * Keep the parts of the mesh that are in the selection.
+ */
+static void do_mesh_separation(GeometrySet &geometry_set,
+ const MeshComponent &in_component,
+ const VArray_Span<bool> &selection,
+ const bool invert,
+ const AttributeDomain domain,
+ const GeometryNodeDeleteGeometryMode mode)
+{
+ /* Needed in all cases. */
+ Vector<int> selected_poly_indices;
+ Vector<int> new_loop_starts;
+ int num_selected_polys = 0;
+ int num_selected_loops = 0;
+
+ const Mesh &mesh_in = *in_component.get_for_read();
+ Mesh *mesh_out;
+ MeshComponent out_component;
+
+ Map<AttributeIDRef, AttributeKind> attributes;
+ geometry_set.gather_attributes_for_propagation(
+ {GEO_COMPONENT_TYPE_MESH}, GEO_COMPONENT_TYPE_MESH, false, attributes);
+
+ switch (mode) {
+ case GEO_NODE_DELETE_GEOMETRY_MODE_ALL: {
+ Array<int> vertex_map(mesh_in.totvert);
+ int num_selected_vertices = 0;
+
+ Array<int> edge_map(mesh_in.totedge);
+ int num_selected_edges = 0;
+
+ /* Fill all the maps based on the selection. */
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ compute_selected_mesh_data_from_vertex_selection(mesh_in,
+ selection,
+ invert,
+ vertex_map,
+ edge_map,
+ selected_poly_indices,
+ new_loop_starts,
+ &num_selected_vertices,
+ &num_selected_edges,
+ &num_selected_polys,
+ &num_selected_loops);
+ break;
+ case ATTR_DOMAIN_EDGE:
+ compute_selected_mesh_data_from_edge_selection(mesh_in,
+ selection,
+ invert,
+ vertex_map,
+ edge_map,
+ selected_poly_indices,
+ new_loop_starts,
+ &num_selected_vertices,
+ &num_selected_edges,
+ &num_selected_polys,
+ &num_selected_loops);
+ break;
+ case ATTR_DOMAIN_FACE:
+ compute_selected_mesh_data_from_poly_selection(mesh_in,
+ selection,
+ invert,
+ vertex_map,
+ edge_map,
+ selected_poly_indices,
+ new_loop_starts,
+ &num_selected_vertices,
+ &num_selected_edges,
+ &num_selected_polys,
+ &num_selected_loops);
+ break;
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ mesh_out = BKE_mesh_new_nomain_from_template(&mesh_in,
+ num_selected_vertices,
+ num_selected_edges,
+ 0,
+ num_selected_loops,
+ num_selected_polys);
+ out_component.replace(mesh_out, GeometryOwnershipType::Editable);
+
+ /* Copy the selected parts of the mesh over to the new mesh. */
+ copy_masked_vertices_to_new_mesh(mesh_in, *mesh_out, vertex_map);
+ copy_masked_edges_to_new_mesh(mesh_in, *mesh_out, vertex_map, edge_map);
+ copy_masked_polys_to_new_mesh(
+ mesh_in, *mesh_out, vertex_map, edge_map, selected_poly_indices, new_loop_starts);
+
+ /* Copy attributes. */
+ copy_attributes_based_on_map(
+ attributes, in_component, out_component, ATTR_DOMAIN_POINT, vertex_map);
+ copy_attributes_based_on_map(
+ attributes, in_component, out_component, ATTR_DOMAIN_EDGE, edge_map);
+ copy_attributes_based_on_mask(attributes,
+ in_component,
+ out_component,
+ ATTR_DOMAIN_FACE,
+ IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
+ copy_face_corner_attributes(attributes,
+ in_component,
+ out_component,
+ num_selected_loops,
+ selected_poly_indices,
+ mesh_in);
+ break;
+ }
+ case GEO_NODE_DELETE_GEOMETRY_MODE_EDGE_FACE: {
+ Array<int> edge_map(mesh_in.totedge);
+ int num_selected_edges = 0;
+
+ /* Fill all the maps based on the selection. */
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ compute_selected_mesh_data_from_vertex_selection_edge_face(mesh_in,
+ selection,
+ invert,
+ edge_map,
+ selected_poly_indices,
+ new_loop_starts,
+ &num_selected_edges,
+ &num_selected_polys,
+ &num_selected_loops);
+ break;
+ case ATTR_DOMAIN_EDGE:
+ compute_selected_mesh_data_from_edge_selection_edge_face(mesh_in,
+ selection,
+ invert,
+ edge_map,
+ selected_poly_indices,
+ new_loop_starts,
+ &num_selected_edges,
+ &num_selected_polys,
+ &num_selected_loops);
+ break;
+ case ATTR_DOMAIN_FACE:
+ compute_selected_mesh_data_from_poly_selection_edge_face(mesh_in,
+ selection,
+ invert,
+ edge_map,
+ selected_poly_indices,
+ new_loop_starts,
+ &num_selected_edges,
+ &num_selected_polys,
+ &num_selected_loops);
+ break;
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ mesh_out = BKE_mesh_new_nomain_from_template(&mesh_in,
+ mesh_in.totvert,
+ num_selected_edges,
+ 0,
+ num_selected_loops,
+ num_selected_polys);
+ out_component.replace(mesh_out, GeometryOwnershipType::Editable);
+
+ /* Copy the selected parts of the mesh over to the new mesh. */
+ memcpy(mesh_out->mvert, mesh_in.mvert, mesh_in.totvert * sizeof(MVert));
+ copy_masked_edges_to_new_mesh(mesh_in, *mesh_out, edge_map);
+ copy_masked_polys_to_new_mesh(
+ mesh_in, *mesh_out, edge_map, selected_poly_indices, new_loop_starts);
+
+ /* Copy attributes. */
+ copy_attributes(attributes, in_component, out_component, {ATTR_DOMAIN_POINT});
+ copy_attributes_based_on_map(
+ attributes, in_component, out_component, ATTR_DOMAIN_EDGE, edge_map);
+ copy_attributes_based_on_mask(attributes,
+ in_component,
+ out_component,
+ ATTR_DOMAIN_FACE,
+ IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
+ copy_face_corner_attributes(attributes,
+ in_component,
+ out_component,
+ num_selected_loops,
+ selected_poly_indices,
+ mesh_in);
+ break;
+ }
+ case GEO_NODE_DELETE_GEOMETRY_MODE_ONLY_FACE: {
+ /* Fill all the maps based on the selection. */
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ compute_selected_polygons_from_vertex_selection(mesh_in,
+ selection,
+ invert,
+ selected_poly_indices,
+ new_loop_starts,
+ &num_selected_polys,
+ &num_selected_loops);
+ break;
+ case ATTR_DOMAIN_EDGE:
+ compute_selected_polygons_from_edge_selection(mesh_in,
+ selection,
+ invert,
+ selected_poly_indices,
+ new_loop_starts,
+ &num_selected_polys,
+ &num_selected_loops);
+ break;
+ case ATTR_DOMAIN_FACE:
+ compute_selected_polygons_from_poly_selection(mesh_in,
+ selection,
+ invert,
+ selected_poly_indices,
+ new_loop_starts,
+ &num_selected_polys,
+ &num_selected_loops);
+ break;
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ mesh_out = BKE_mesh_new_nomain_from_template(
+ &mesh_in, mesh_in.totvert, mesh_in.totedge, 0, num_selected_loops, num_selected_polys);
+ out_component.replace(mesh_out, GeometryOwnershipType::Editable);
+
+ /* Copy the selected parts of the mesh over to the new mesh. */
+ memcpy(mesh_out->mvert, mesh_in.mvert, mesh_in.totvert * sizeof(MVert));
+ memcpy(mesh_out->medge, mesh_in.medge, mesh_in.totedge * sizeof(MEdge));
+ copy_masked_polys_to_new_mesh(mesh_in, *mesh_out, selected_poly_indices, new_loop_starts);
+
+ /* Copy attributes. */
+ copy_attributes(
+ attributes, in_component, out_component, {ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE});
+ copy_attributes_based_on_mask(attributes,
+ in_component,
+ out_component,
+ ATTR_DOMAIN_FACE,
+ IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
+ copy_face_corner_attributes(attributes,
+ in_component,
+ out_component,
+ num_selected_loops,
+ selected_poly_indices,
+ mesh_in);
+ break;
+ }
+ }
+
+ BKE_mesh_calc_edges_loose(mesh_out);
+ /* Tag to recalculate normals later. */
+ BKE_mesh_normals_tag_dirty(mesh_out);
+ geometry_set.replace_mesh(mesh_out);
+}
+
+static void separate_mesh_selection(GeometrySet &geometry_set,
+ const Field<bool> &selection_field,
+ const AttributeDomain selection_domain,
+ const GeometryNodeDeleteGeometryMode mode,
+ const bool invert)
+{
+ const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>();
+ GeometryComponentFieldContext field_context{src_component, selection_domain};
+
+ fn::FieldEvaluator selection_evaluator{field_context,
+ src_component.attribute_domain_size(selection_domain)};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
+
+ /* Check if there is anything to delete. */
+ bool delete_nothing = true;
+ for (const int i : selection.index_range()) {
+ if (selection[i] == invert) {
+ delete_nothing = false;
+ break;
+ }
+ }
+ if (delete_nothing) {
+ return;
+ }
+
+ do_mesh_separation(geometry_set, src_component, selection, invert, selection_domain, mode);
+}
+
+} // namespace blender::nodes::node_geo_delete_geometry_cc
+
+namespace blender::nodes {
+
+void separate_geometry(GeometrySet &geometry_set,
+ const AttributeDomain domain,
+ const GeometryNodeDeleteGeometryMode mode,
+ const Field<bool> &selection_field,
+ const bool invert,
+ bool &r_is_error)
+{
+ namespace file_ns = blender::nodes::node_geo_delete_geometry_cc;
+
+ bool some_valid_domain = false;
+ if (geometry_set.has_pointcloud()) {
+ if (domain == ATTR_DOMAIN_POINT) {
+ file_ns::separate_point_cloud_selection(geometry_set, selection_field, invert);
+ some_valid_domain = true;
+ }
+ }
+ if (geometry_set.has_mesh()) {
+ if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER)) {
+ file_ns::separate_mesh_selection(geometry_set, selection_field, domain, mode, invert);
+ some_valid_domain = true;
+ }
+ }
+ if (geometry_set.has_curve()) {
+ if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) {
+ file_ns::separate_curve_selection(geometry_set, selection_field, domain, invert);
+ some_valid_domain = true;
+ }
+ }
+ if (geometry_set.has_instances()) {
+ if (domain == ATTR_DOMAIN_INSTANCE) {
+ file_ns::separate_instance_selection(geometry_set, selection_field, invert);
+ some_valid_domain = true;
+ }
+ }
+ r_is_error = !some_valid_domain && geometry_set.has_realized_data();
+}
+
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_delete_geometry_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryDeleteGeometry)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection"))
+ .default_value(true)
+ .hide_value()
+ .supports_field()
+ .description(N_("The parts of the geometry to be deleted"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ const bNode *node = static_cast<bNode *>(ptr->data);
+ const NodeGeometryDeleteGeometry &storage = node_storage(*node);
+ const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+ /* Only show the mode when it is relevant. */
+ if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) {
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+ }
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryDeleteGeometry *data = MEM_cnew<NodeGeometryDeleteGeometry>(__func__);
+ data->domain = ATTR_DOMAIN_POINT;
+ data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL;
+
+ node->storage = data;
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+
+ const NodeGeometryDeleteGeometry &storage = node_storage(params.node());
+ const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+ const GeometryNodeDeleteGeometryMode mode = (GeometryNodeDeleteGeometryMode)storage.mode;
+
+ if (domain == ATTR_DOMAIN_INSTANCE) {
+ bool is_error;
+ separate_geometry(geometry_set, domain, mode, selection_field, true, is_error);
+ }
+ else {
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ bool is_error;
+ /* Invert here because we want to keep the things not in the selection. */
+ separate_geometry(geometry_set, domain, mode, selection_field, true, is_error);
+ });
+ }
+
+ params.set_output("Geometry", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_delete_geometry_cc
+
+void register_node_type_geo_delete_geometry()
+{
+ namespace file_ns = blender::nodes::node_geo_delete_geometry_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY);
+
+ node_type_storage(&ntype,
+ "NodeGeometryDeleteGeometry",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+
+ node_type_init(&ntype, file_ns::node_init);
+
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
index 1a4c5d84dbf..d17657bfa3a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
@@ -36,51 +36,48 @@
#include "node_geometry_util.hh"
-using blender::bke::GeometryInstanceGroup;
+namespace blender::nodes::node_geo_distribute_points_on_faces_cc {
-namespace blender::nodes {
-
-static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Float>("Distance Min").min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Density Max").default_value(10.0f).min(0.0f);
- b.add_input<decl::Float>("Density").default_value(10.0f).supports_field();
- b.add_input<decl::Float>("Density Factor")
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Distance Min")).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Density Max")).default_value(10.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Density")).default_value(10.0f).min(0.0f).supports_field();
+ b.add_input<decl::Float>(N_("Density Factor"))
.default_value(1.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR)
.supports_field();
- b.add_input<decl::Int>("Seed");
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
+ b.add_input<decl::Int>(N_("Seed"));
- b.add_output<decl::Geometry>("Points");
- b.add_output<decl::Vector>("Normal").field_source();
- b.add_output<decl::Vector>("Rotation").subtype(PROP_EULER).field_source();
- b.add_output<decl::Int>("Stable ID").field_source();
+ b.add_output<decl::Geometry>(N_("Points"));
+ b.add_output<decl::Vector>(N_("Normal")).field_source();
+ b.add_output<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).field_source();
}
-static void geo_node_point_distribute_points_on_faces_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE);
}
-static void node_point_distribute_points_on_faces_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_point_distribute_points_on_faces_update(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sock_distance_min = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
+ bNodeSocket *sock_distance_min = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
bNodeSocket *sock_density_max = (bNodeSocket *)sock_distance_min->next;
bNodeSocket *sock_density = sock_density_max->next;
bNodeSocket *sock_density_factor = sock_density->next;
- nodeSetSocketAvailability(sock_distance_min,
- node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON);
- nodeSetSocketAvailability(sock_density_max,
+ nodeSetSocketAvailability(ntree,
+ sock_distance_min,
node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON);
- nodeSetSocketAvailability(sock_density,
- node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM);
- nodeSetSocketAvailability(sock_density_factor,
+ nodeSetSocketAvailability(
+ ntree, sock_density_max, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON);
+ nodeSetSocketAvailability(
+ ntree, sock_density, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM);
+ nodeSetSocketAvailability(ntree,
+ sock_density_factor,
node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON);
}
@@ -255,18 +252,26 @@ BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
{
switch (source_domain) {
case ATTR_DOMAIN_POINT: {
- bke::mesh_surface_sample::sample_point_attribute(
- mesh, looptri_indices, bary_coords, source_data, output_data);
+ bke::mesh_surface_sample::sample_point_attribute(mesh,
+ looptri_indices,
+ bary_coords,
+ source_data,
+ IndexMask(output_data.size()),
+ output_data);
break;
}
case ATTR_DOMAIN_CORNER: {
- bke::mesh_surface_sample::sample_corner_attribute(
- mesh, looptri_indices, bary_coords, source_data, output_data);
+ bke::mesh_surface_sample::sample_corner_attribute(mesh,
+ looptri_indices,
+ bary_coords,
+ source_data,
+ IndexMask(output_data.size()),
+ output_data);
break;
}
case ATTR_DOMAIN_FACE: {
bke::mesh_surface_sample::sample_face_attribute(
- mesh, looptri_indices, source_data, output_data);
+ mesh, looptri_indices, source_data, IndexMask(output_data.size()), output_data);
break;
}
default: {
@@ -288,6 +293,12 @@ BLI_NOINLINE static void propagate_existing_attributes(
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
const CustomDataType output_data_type = entry.value.data_type;
+
+ ReadAttributeLookup source_attribute = mesh_component.attribute_try_get_for_read(attribute_id);
+ if (!source_attribute) {
+ continue;
+ }
+
/* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
OutputAttribute attribute_out = point_component.attribute_try_get_for_output_only(
attribute_id, ATTR_DOMAIN_POINT, output_data_type);
@@ -296,23 +307,12 @@ BLI_NOINLINE static void propagate_existing_attributes(
}
GMutableSpan out_span = attribute_out.as_span();
-
- std::optional<AttributeMetaData> attribute_info = point_component.attribute_get_meta_data(
- attribute_id);
- if (!attribute_info) {
- continue;
- }
-
- const AttributeDomain source_domain = attribute_info->domain;
- GVArrayPtr source_attribute = mesh_component.attribute_get_for_read(
- attribute_id, source_domain, output_data_type, nullptr);
- if (!source_attribute) {
- continue;
- }
-
- interpolate_attribute(
- mesh, bary_coords, looptri_indices, source_domain, *source_attribute, out_span);
-
+ interpolate_attribute(mesh,
+ bary_coords,
+ looptri_indices,
+ source_attribute.domain,
+ source_attribute.varray,
+ out_span);
attribute_out.save();
}
}
@@ -321,7 +321,6 @@ namespace {
struct AttributeOutputs {
StrongAnonymousAttributeID normal_id;
StrongAnonymousAttributeID rotation_id;
- StrongAnonymousAttributeID stable_id_id;
};
} // namespace
@@ -331,28 +330,25 @@ BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_com
const Span<int> looptri_indices,
const AttributeOutputs &attribute_outputs)
{
- std::optional<OutputAttribute_Typed<int>> id_attribute;
- std::optional<OutputAttribute_Typed<float3>> normal_attribute;
- std::optional<OutputAttribute_Typed<float3>> rotation_attribute;
+ OutputAttribute_Typed<int> id_attribute = point_component.attribute_try_get_for_output_only<int>(
+ "id", ATTR_DOMAIN_POINT);
+ MutableSpan<int> ids = id_attribute.as_span();
+
+ OutputAttribute_Typed<float3> normal_attribute;
+ OutputAttribute_Typed<float3> rotation_attribute;
- MutableSpan<int> ids;
MutableSpan<float3> normals;
MutableSpan<float3> rotations;
- if (attribute_outputs.stable_id_id) {
- id_attribute.emplace(point_component.attribute_try_get_for_output_only<int>(
- attribute_outputs.stable_id_id.get(), ATTR_DOMAIN_POINT));
- ids = id_attribute->as_span();
- }
if (attribute_outputs.normal_id) {
- normal_attribute.emplace(point_component.attribute_try_get_for_output_only<float3>(
- attribute_outputs.normal_id.get(), ATTR_DOMAIN_POINT));
- normals = normal_attribute->as_span();
+ normal_attribute = point_component.attribute_try_get_for_output_only<float3>(
+ attribute_outputs.normal_id.get(), ATTR_DOMAIN_POINT);
+ normals = normal_attribute.as_span();
}
if (attribute_outputs.rotation_id) {
- rotation_attribute.emplace(point_component.attribute_try_get_for_output_only<float3>(
- attribute_outputs.rotation_id.get(), ATTR_DOMAIN_POINT));
- rotations = rotation_attribute->as_span();
+ rotation_attribute = point_component.attribute_try_get_for_output_only<float3>(
+ attribute_outputs.rotation_id.get(), ATTR_DOMAIN_POINT);
+ rotations = rotation_attribute.as_span();
}
const Mesh &mesh = *mesh_component.get_for_read();
@@ -371,9 +367,8 @@ BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_com
const float3 v1_pos = float3(mesh.mvert[v1_index].co);
const float3 v2_pos = float3(mesh.mvert[v2_index].co);
- if (!ids.is_empty()) {
- ids[i] = noise::hash(noise::hash_float(bary_coord), looptri_index);
- }
+ ids[i] = noise::hash(noise::hash_float(bary_coord), looptri_index);
+
float3 normal;
if (!normals.is_empty() || !rotations.is_empty()) {
normal_tri_v3(normal, v0_pos, v1_pos, v2_pos);
@@ -386,14 +381,13 @@ BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_com
}
}
- if (id_attribute) {
- id_attribute->save();
- }
+ id_attribute.save();
+
if (normal_attribute) {
- normal_attribute->save();
+ normal_attribute.save();
}
if (rotation_attribute) {
- rotation_attribute->save();
+ rotation_attribute.save();
}
}
@@ -405,16 +399,12 @@ static Array<float> calc_full_density_factors_with_selection(const MeshComponent
GeometryComponentFieldContext field_context{component, attribute_domain};
const int domain_size = component.attribute_domain_size(attribute_domain);
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection_mask = selection_evaluator.get_evaluated_as_mask(0);
-
Array<float> densities(domain_size, 0.0f);
- fn::FieldEvaluator density_evaluator{field_context, &selection_mask};
- density_evaluator.add_with_destination(density_field, densities.as_mutable_span());
- density_evaluator.evaluate();
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(density_field, densities.as_mutable_span());
+ evaluator.evaluate();
return densities;
}
@@ -504,6 +494,10 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
}
}
+ if (positions.is_empty()) {
+ return;
+ }
+
PointCloud *pointcloud = BKE_pointcloud_new_nomain(positions.size());
memcpy(pointcloud->co, positions.data(), sizeof(float3) * positions.size());
uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
@@ -526,9 +520,9 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
mesh_component, point_component, bary_coords, looptri_indices, attribute_outputs);
}
-static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
const GeometryNodeDistributePointsOnFacesMode method =
static_cast<GeometryNodeDistributePointsOnFacesMode>(params.node().custom1);
@@ -538,13 +532,10 @@ static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams par
AttributeOutputs attribute_outputs;
if (params.output_is_required("Normal")) {
- attribute_outputs.normal_id = StrongAnonymousAttributeID("normal");
+ attribute_outputs.normal_id = StrongAnonymousAttributeID("Normal");
}
if (params.output_is_required("Rotation")) {
- attribute_outputs.rotation_id = StrongAnonymousAttributeID("rotation");
- }
- if (params.output_is_required("Stable ID")) {
- attribute_outputs.stable_id_id = StrongAnonymousAttributeID("stable id");
+ attribute_outputs.rotation_id = StrongAnonymousAttributeID("Rotation");
}
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
@@ -560,35 +551,33 @@ static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams par
if (attribute_outputs.normal_id) {
params.set_output(
"Normal",
- AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.normal_id)));
+ AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.normal_id),
+ params.attribute_producer_name()));
}
if (attribute_outputs.rotation_id) {
params.set_output(
"Rotation",
- AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.rotation_id)));
- }
- if (attribute_outputs.stable_id_id) {
- params.set_output(
- "Stable ID",
- AnonymousAttributeFieldInput::Create<int>(std::move(attribute_outputs.stable_id_id)));
+ AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.rotation_id),
+ params.attribute_producer_name()));
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_distribute_points_on_faces_cc
void register_node_type_geo_distribute_points_on_faces()
{
+ namespace file_ns = blender::nodes::node_geo_distribute_points_on_faces_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
GEO_NODE_DISTRIBUTE_POINTS_ON_FACES,
"Distribute Points on Faces",
- NODE_CLASS_GEOMETRY,
- 0);
- node_type_update(&ntype, blender::nodes::node_point_distribute_points_on_faces_update);
+ NODE_CLASS_GEOMETRY);
+ node_type_update(&ntype, file_ns::node_point_distribute_points_on_faces_update);
node_type_size(&ntype, 170, 100, 320);
- ntype.declare = blender::nodes::geo_node_point_distribute_points_on_faces_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_points_on_faces_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_distribute_points_on_faces_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
new file mode 100644
index 00000000000..f6be6c1e7fb
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
@@ -0,0 +1,931 @@
+/*
+ * 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 "BLI_task.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_dual_mesh_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Mesh").supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>("Keep Boundaries")
+ .default_value(false)
+ .description(
+ "Keep non-manifold boundaries of the input mesh in place by avoiding the dual "
+ "transformation there");
+ b.add_output<decl::Geometry>("Dual Mesh");
+}
+
+enum class EdgeType : int8_t {
+ Loose = 0, /* No polygons connected to it. */
+ Boundary = 1, /* An edge connected to exactly one polygon. */
+ Normal = 2, /* A normal edge (connected to two polygons). */
+ NonManifold = 3, /* An edge connected to more than two polygons. */
+};
+
+static EdgeType get_edge_type_with_added_neighbor(EdgeType old_type)
+{
+ switch (old_type) {
+ case EdgeType::Loose:
+ return EdgeType::Boundary;
+ case EdgeType::Boundary:
+ return EdgeType::Normal;
+ case EdgeType::Normal:
+ case EdgeType::NonManifold:
+ return EdgeType::NonManifold;
+ }
+ BLI_assert_unreachable();
+ return EdgeType::Loose;
+}
+
+enum class VertexType : int8_t {
+ Loose = 0, /* Either no edges connected or only loose edges connected. */
+ Normal = 1, /* A normal vertex. */
+ Boundary = 2, /* A vertex on a boundary edge. */
+ NonManifold = 3, /* A vertex on a non-manifold edge. */
+};
+
+static VertexType get_vertex_type_with_added_neighbor(VertexType old_type)
+{
+ switch (old_type) {
+ case VertexType::Loose:
+ return VertexType::Normal;
+ case VertexType::Normal:
+ return VertexType::Boundary;
+ case VertexType::Boundary:
+ case VertexType::NonManifold:
+ return VertexType::NonManifold;
+ }
+ BLI_assert_unreachable();
+ return VertexType::Loose;
+}
+
+/* Copy only where vertex_types is 'normal'. If keep boundaries is selected, also copy from
+ * boundary vertices. */
+template<typename T>
+static void copy_data_based_on_vertex_types(Span<T> data,
+ MutableSpan<T> r_data,
+ const Span<VertexType> vertex_types,
+ const bool keep_boundaries)
+{
+ if (keep_boundaries) {
+ int out_i = 0;
+ for (const int i : data.index_range()) {
+ if (ELEM(vertex_types[i], VertexType::Normal, VertexType::Boundary)) {
+ r_data[out_i] = data[i];
+ out_i++;
+ }
+ }
+ }
+ else {
+ int out_i = 0;
+ for (const int i : data.index_range()) {
+ if (vertex_types[i] == VertexType::Normal) {
+ r_data[out_i] = data[i];
+ out_i++;
+ }
+ }
+ }
+}
+
+template<typename T>
+static void copy_data_based_on_pairs(Span<T> data,
+ MutableSpan<T> r_data,
+ const Span<std::pair<int, int>> new_to_old_map)
+{
+ for (const std::pair<int, int> &pair : new_to_old_map) {
+ r_data[pair.first] = data[pair.second];
+ }
+}
+
+/* Copy using the map. */
+template<typename T>
+static void copy_data_based_on_new_to_old_map(Span<T> data,
+ MutableSpan<T> r_data,
+ const Span<int> new_to_old_map)
+{
+ for (const int i : r_data.index_range()) {
+ const int old_i = new_to_old_map[i];
+ r_data[i] = data[old_i];
+ }
+}
+
+/**
+ * Transfers the attributes from the original mesh to the new mesh using the following logic:
+ * - If the attribute was on the face domain it is now on the point domain, and this is true
+ * for all faces, so we can just copy these.
+ * - If the attribute was on the vertex domain there are three cases:
+ * - It was a 'bad' vertex so it is not in the dual mesh, and we can just ignore it
+ * - It was a normal vertex so it has a corresponding face in the dual mesh to which we can
+ * transfer.
+ * - It was a boundary vertex so it has a corresponding face, if keep_boundaries is true.
+ * Otherwise we can just ignore it.
+ * - If the attribute was on the edge domain we lookup for the new edges which edge it originated
+ * from using `new_to_old_edges_map`. We have to do it in this reverse order, because there can
+ * be more edges in the new mesh if keep boundaries is on.
+ * - We do the same thing for face corners as we do for edges.
+ *
+ * Some of the vertices (on the boundary) in the dual mesh don't come from faces, but from edges or
+ * vertices. For these the `boundary_vertex_to_relevant_face_map` is used, which maps them to the
+ * closest face.
+ */
+static void transfer_attributes(
+ const Map<AttributeIDRef, AttributeKind> &attributes,
+ const Span<VertexType> vertex_types,
+ const bool keep_boundaries,
+ const Span<int> new_to_old_edges_map,
+ const Span<int> new_to_old_face_corners_map,
+ const Span<std::pair<int, int>> boundary_vertex_to_relevant_face_map,
+ const GeometryComponent &src_component,
+ GeometryComponent &dst_component)
+{
+ for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ if (!src_attribute) {
+ continue;
+ }
+
+ AttributeDomain out_domain;
+ if (src_attribute.domain == ATTR_DOMAIN_FACE) {
+ out_domain = ATTR_DOMAIN_POINT;
+ }
+ else if (src_attribute.domain == ATTR_DOMAIN_POINT) {
+ out_domain = ATTR_DOMAIN_FACE;
+ }
+ else {
+ /* Edges and Face Corners. */
+ out_domain = src_attribute.domain;
+ }
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ src_attribute.varray.type());
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, out_domain, data_type);
+
+ if (!dst_attribute) {
+ continue;
+ }
+
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> span{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst_span = dst_attribute.as_span<T>();
+ if (src_attribute.domain == ATTR_DOMAIN_FACE) {
+ dst_span.take_front(span.size()).copy_from(span);
+ if (keep_boundaries) {
+ copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map);
+ }
+ }
+ else if (src_attribute.domain == ATTR_DOMAIN_POINT) {
+ copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries);
+ }
+ else if (src_attribute.domain == ATTR_DOMAIN_EDGE) {
+ copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_edges_map);
+ }
+ else {
+ copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_face_corners_map);
+ }
+ });
+ dst_attribute.save();
+ }
+}
+
+/**
+ * Calculates the boundaries of the mesh. Boundary polygons are not computed since we don't need
+ * them later on. We use the following definitions:
+ * - An edge is on a boundary if it is connected to only one polygon.
+ * - A vertex is on a boundary if it is on an edge on a boundary.
+ */
+static void calc_boundaries(const Mesh &mesh,
+ MutableSpan<VertexType> r_vertex_types,
+ MutableSpan<EdgeType> r_edge_types)
+{
+ BLI_assert(r_vertex_types.size() == mesh.totvert);
+ BLI_assert(r_edge_types.size() == mesh.totedge);
+ r_vertex_types.fill(VertexType::Loose);
+ r_edge_types.fill(EdgeType::Loose);
+
+ /* Add up the number of polys connected to each edge. */
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[i];
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ r_edge_types[loop.e] = get_edge_type_with_added_neighbor(r_edge_types[loop.e]);
+ }
+ }
+
+ /* Update vertices. */
+ for (const int i : IndexRange(mesh.totedge)) {
+ const EdgeType edge_type = r_edge_types[i];
+ if (edge_type == EdgeType::Loose) {
+ continue;
+ }
+ const MEdge &edge = mesh.medge[i];
+ if (edge_type == EdgeType::Boundary) {
+ r_vertex_types[edge.v1] = get_vertex_type_with_added_neighbor(r_vertex_types[edge.v1]);
+ r_vertex_types[edge.v2] = get_vertex_type_with_added_neighbor(r_vertex_types[edge.v2]);
+ }
+ else if (edge_type >= EdgeType::NonManifold) {
+ r_vertex_types[edge.v1] = VertexType::NonManifold;
+ r_vertex_types[edge.v2] = VertexType::NonManifold;
+ }
+ }
+
+ /* Normal verts are on a normal edge, and not on boundary edges or non-manifold edges. */
+ for (const int i : IndexRange(mesh.totedge)) {
+ const EdgeType edge_type = r_edge_types[i];
+ if (edge_type == EdgeType::Normal) {
+ const MEdge &edge = mesh.medge[i];
+ if (r_vertex_types[edge.v1] == VertexType::Loose) {
+ r_vertex_types[edge.v1] = VertexType::Normal;
+ }
+ if (r_vertex_types[edge.v2] == VertexType::Loose) {
+ r_vertex_types[edge.v2] = VertexType::Normal;
+ }
+ }
+ }
+}
+
+/**
+ * Stores the indices of the polygons connected to each vertex.
+ */
+static void create_vertex_poly_map(const Mesh &mesh,
+ MutableSpan<Vector<int>> r_vertex_poly_indices)
+{
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[i];
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ r_vertex_poly_indices[loop.v].append(i);
+ }
+ }
+}
+
+/**
+ * Sorts the polygons connected to the given vertex based on polygon adjacency. The ordering is
+ * so such that the normals point in the same way as the original mesh. If the vertex is a
+ * boundary vertex, the first and last polygon have a boundary edge connected to the vertex. The
+ * `r_shared_edges` array at index i is set to the index of the shared edge between the i-th and
+ * `(i+1)-th` sorted polygon. Similarly the `r_sorted_corners` array at index i is set to the
+ * corner in the i-th sorted polygon.
+ *
+ * How the faces are sorted (see diagrams below):
+ * (For this explanation we'll assume all faces are oriented clockwise)
+ * (The vertex whose connected polygons we need to sort is "v0")
+ *
+ * \code{.unparsed}
+ * Normal case: Boundary Vertex case:
+ * v1 ----- v2 ----- v3 | | |
+ * | f3 | f0 | v2 ---- v4 --------- v3---
+ * | | | | / ,-' |
+ * v8 ----- v0 ----- v4 | f0 / f1 ,-' |
+ * | f2 | f1 | | / ,-' |
+ * | | | | / ,-' |
+ * v7 ----- v6 ----- v5 | / ,-' f2 |
+ * | /,-' |
+ * v0 ------------------ v1---
+ * \endcode
+ *
+ * - First we get the two corners of each face that have an edge which contains v0. A corner is
+ * simply a vertex followed by an edge. In this case for the face "f0" for example, we'd end up
+ * with the corners (v: v4, e: v4<->v0) and (v: v0, e: v0<->v2). Note that if the face was
+ * oriented counter-clockwise we'd end up with the corners (v: v0, e: v0<->v4) and (v: v2, e:
+ * v0<->v2) instead.
+ * - Then we need to choose one polygon as our first. If "v0" is not on a boundary we can just
+ * choose any polygon. If it is on a boundary some more care needs to be taken. Here we need to
+ * pick a polygon which lies on the boundary (in the diagram either f0 or f2). To choose between
+ * the two we need the next step.
+ * - In the normal case we use this polygon to set `shared_edge_i` which indicates the index of the
+ * shared edge between this polygon and the next one. There are two possible choices: v0<->v4 and
+ * v2<->v0. To choose we look at the corners. Since the edge v0<->v2 lies on the corner which has
+ * v0, we set `shared_edge_i` to the other edge (v0<->v4), such that the next face will be "f1"
+ * which is the next face in clockwise order.
+ * - In the boundary vertex case, we do something similar, but we are also forced to choose the
+ * edge which is not on the boundary. If this doesn't line up with orientation of the polygon, we
+ * know we'll need to choose the other boundary polygon as our first polygon. If the orientations
+ * don't line up there as well, it means that the mesh normals are not consistent, and we just
+ * have to force an orientation for ourselves. (Imagine if f0 is oriented counter-clockwise and
+ * f2 is oriented clockwise for example)
+ * - Next comes a loop where we look at the other faces and find the one which has the shared
+ * edge. Then we set the next shared edge to the other edge on the polygon connected to "v0", and
+ * continue. Because of the way we've chosen the first shared edge the order of the faces will
+ * have the same orientation as that of the first polygon.
+ * (In this case we'd have f0 -> f1 -> f2 -> f3 which also goes around clockwise).
+ * - Every time we determine a shared edge, we can also add a corner to `r_sorted_corners`. This
+ * will simply be the corner which doesn't contain the shared edge.
+ * - Finally if we are in the normal case we also need to add the last "shared edge" to close the
+ * loop.
+ */
+static void sort_vertex_polys(const Mesh &mesh,
+ const int vertex_index,
+ const bool boundary_vertex,
+ const Span<EdgeType> edge_types,
+ MutableSpan<int> connected_polygons,
+ MutableSpan<int> r_shared_edges,
+ MutableSpan<int> r_sorted_corners)
+{
+ if (connected_polygons.size() <= 2 && (!boundary_vertex || connected_polygons.size() == 0)) {
+ return;
+ }
+
+ /* For each polygon store the two corners whose edge contains the vertex. */
+ Array<std::pair<int, int>> poly_vertex_corners(connected_polygons.size());
+ for (const int i : connected_polygons.index_range()) {
+ const MPoly &poly = mesh.mpoly[connected_polygons[i]];
+ bool first_edge_done = false;
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ if (mesh.medge[loop.e].v1 == vertex_index || mesh.medge[loop.e].v2 == vertex_index) {
+ if (!first_edge_done) {
+ poly_vertex_corners[i].first = loop_index;
+ first_edge_done = true;
+ }
+ else {
+ poly_vertex_corners[i].second = loop_index;
+ break;
+ }
+ }
+ }
+ }
+
+ int shared_edge_i = -1;
+ /* Determine first polygon and orientation. For now the orientation of the whole loop depends
+ * on the one polygon we chose as first. It's probably not worth it to check every polygon in
+ * the loop to determine the 'average' orientation. */
+ if (boundary_vertex) {
+ /* Our first polygon needs to be one which has a boundary edge. */
+ for (const int i : connected_polygons.index_range()) {
+ const MLoop &first_loop = mesh.mloop[poly_vertex_corners[i].first];
+ const MLoop &second_loop = mesh.mloop[poly_vertex_corners[i].second];
+ if (edge_types[first_loop.e] == EdgeType::Boundary && first_loop.v == vertex_index) {
+ shared_edge_i = second_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[i].first;
+ std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
+ break;
+ }
+ if (edge_types[second_loop.e] == EdgeType::Boundary && second_loop.v == vertex_index) {
+ shared_edge_i = first_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[i].second;
+ std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
+ break;
+ }
+ }
+ if (shared_edge_i == -1) {
+ /* The rotation is inconsistent between the two polygons on the boundary. Just choose one
+ * of the polygon's orientation. */
+ for (const int i : connected_polygons.index_range()) {
+ const MLoop &first_loop = mesh.mloop[poly_vertex_corners[i].first];
+ const MLoop &second_loop = mesh.mloop[poly_vertex_corners[i].second];
+ if (edge_types[first_loop.e] == EdgeType::Boundary) {
+ shared_edge_i = second_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[i].first;
+ std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
+ break;
+ }
+ if (edge_types[second_loop.e] == EdgeType::Boundary) {
+ shared_edge_i = first_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[i].second;
+ std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ /* Any polygon can be the first. Just need to check the orientation. */
+ const MLoop &first_loop = mesh.mloop[poly_vertex_corners[0].first];
+ const MLoop &second_loop = mesh.mloop[poly_vertex_corners[0].second];
+ if (first_loop.v == vertex_index) {
+ shared_edge_i = second_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[0].first;
+ }
+ else {
+ r_sorted_corners[0] = poly_vertex_corners[0].second;
+ shared_edge_i = first_loop.e;
+ }
+ }
+ BLI_assert(shared_edge_i != -1);
+
+ for (const int i : IndexRange(connected_polygons.size() - 1)) {
+ r_shared_edges[i] = shared_edge_i;
+
+ /* Look at the other polys to see if it has this shared edge. */
+ int j = i + 1;
+ for (; j < connected_polygons.size(); ++j) {
+ const MLoop &first_loop = mesh.mloop[poly_vertex_corners[j].first];
+ const MLoop &second_loop = mesh.mloop[poly_vertex_corners[j].second];
+ if (first_loop.e == shared_edge_i) {
+ r_sorted_corners[i + 1] = poly_vertex_corners[j].first;
+ shared_edge_i = second_loop.e;
+ break;
+ }
+ if (second_loop.e == shared_edge_i) {
+ r_sorted_corners[i + 1] = poly_vertex_corners[j].second;
+ shared_edge_i = first_loop.e;
+ break;
+ }
+ }
+
+ BLI_assert(j != connected_polygons.size());
+
+ std::swap(connected_polygons[i + 1], connected_polygons[j]);
+ std::swap(poly_vertex_corners[i + 1], poly_vertex_corners[j]);
+ }
+
+ if (!boundary_vertex) {
+ /* Shared edge between first and last polygon. */
+ r_shared_edges.last() = shared_edge_i;
+ }
+}
+
+/**
+ * Get the edge on the poly that contains the given vertex and is a boundary edge.
+ */
+static void boundary_edge_on_poly(const MPoly &poly,
+ const Mesh &mesh,
+ const int vertex_index,
+ const Span<EdgeType> edge_types,
+ int &r_edge)
+{
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ if (edge_types[loop.e] == EdgeType::Boundary) {
+ const MEdge &edge = mesh.medge[loop.e];
+ if (edge.v1 == vertex_index || edge.v2 == vertex_index) {
+ r_edge = loop.e;
+ return;
+ }
+ }
+ }
+}
+
+/**
+ * Get the two edges on the poly that contain the given vertex and are boundary edges. The
+ * orientation of the poly is taken into account.
+ */
+static void boundary_edges_on_poly(const MPoly &poly,
+ const Mesh &mesh,
+ const int vertex_index,
+ const Span<EdgeType> edge_types,
+ int &r_edge1,
+ int &r_edge2)
+{
+ bool edge1_done = false;
+ /* This is set to true if the order in which we encounter the two edges is inconsistent with the
+ * orientation of the polygon. */
+ bool needs_swap = false;
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ if (edge_types[loop.e] == EdgeType::Boundary) {
+ const MEdge &edge = mesh.medge[loop.e];
+ if (edge.v1 == vertex_index || edge.v2 == vertex_index) {
+ if (edge1_done) {
+ if (needs_swap) {
+ r_edge2 = r_edge1;
+ r_edge1 = loop.e;
+ }
+ else {
+ r_edge2 = loop.e;
+ }
+ return;
+ }
+ r_edge1 = loop.e;
+ edge1_done = true;
+ if (loop.v == vertex_index) {
+ needs_swap = true;
+ }
+ }
+ }
+ }
+}
+
+static void add_edge(const Mesh &mesh,
+ const int old_edge_i,
+ const int v1,
+ const int v2,
+ Vector<int> &new_to_old_edges_map,
+ Vector<MEdge> &new_edges,
+ Vector<int> &loop_edges)
+{
+ MEdge new_edge = MEdge(mesh.medge[old_edge_i]);
+ new_edge.v1 = v1;
+ new_edge.v2 = v2;
+ const int new_edge_i = new_edges.size();
+ new_to_old_edges_map.append(old_edge_i);
+ new_edges.append(new_edge);
+ loop_edges.append(new_edge_i);
+}
+
+/* Returns true if the vertex is connected only to the two polygons and is not on the boundary. */
+static bool vertex_needs_dissolving(const int vertex,
+ const int first_poly_index,
+ const int second_poly_index,
+ const Span<VertexType> vertex_types,
+ const Span<Vector<int>> vertex_poly_indices)
+{
+ /* Order is guaranteed to be the same because 2poly verts that are not on the boundary are
+ * ignored in `sort_vertex_polys`. */
+ return (vertex_types[vertex] != VertexType::Boundary &&
+ vertex_poly_indices[vertex].size() == 2 &&
+ vertex_poly_indices[vertex][0] == first_poly_index &&
+ vertex_poly_indices[vertex][1] == second_poly_index);
+}
+
+/**
+ * Finds 'normal' vertices which are connected to only two polygons and marks them to not be
+ * used in the data-structures derived from the mesh. For each pair of polygons which has such a
+ * vertex, an edge is created for the dual mesh between the centers of those two polygons. All
+ * edges in the input mesh which contain such a vertex are marked as 'done' to prevent duplicate
+ * edges being created. (See T94144)
+ */
+static void dissolve_redundant_verts(const Mesh &mesh,
+ const Span<Vector<int>> vertex_poly_indices,
+ MutableSpan<VertexType> vertex_types,
+ MutableSpan<int> old_to_new_edges_map,
+ Vector<MEdge> &new_edges,
+ Vector<int> &new_to_old_edges_map)
+{
+ for (const int vert_i : IndexRange(mesh.totvert)) {
+ if (vertex_poly_indices[vert_i].size() != 2 || vertex_types[vert_i] != VertexType::Normal) {
+ continue;
+ }
+ const int first_poly_index = vertex_poly_indices[vert_i][0];
+ const int second_poly_index = vertex_poly_indices[vert_i][1];
+ const int new_edge_index = new_edges.size();
+ bool edge_created = false;
+ const MPoly &poly = mesh.mpoly[first_poly_index];
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ const MEdge &edge = mesh.medge[loop.e];
+ const int v1 = edge.v1;
+ const int v2 = edge.v2;
+ bool mark_edge = false;
+ if (vertex_needs_dissolving(
+ v1, first_poly_index, second_poly_index, vertex_types, vertex_poly_indices)) {
+ /* This vertex is now 'removed' and should be ignored elsewhere. */
+ vertex_types[v1] = VertexType::Loose;
+ mark_edge = true;
+ }
+ if (vertex_needs_dissolving(
+ v2, first_poly_index, second_poly_index, vertex_types, vertex_poly_indices)) {
+ /* This vertex is now 'removed' and should be ignored elsewhere. */
+ vertex_types[v2] = VertexType::Loose;
+ mark_edge = true;
+ }
+ if (mark_edge) {
+ if (!edge_created) {
+ MEdge new_edge = MEdge(edge);
+ /* The vertex indices in the dual mesh are the polygon indices of the input mesh. */
+ new_edge.v1 = first_poly_index;
+ new_edge.v2 = second_poly_index;
+ new_to_old_edges_map.append(loop.e);
+ new_edges.append(new_edge);
+ edge_created = true;
+ }
+ old_to_new_edges_map[loop.e] = new_edge_index;
+ }
+ }
+ }
+}
+
+/**
+ * Calculate the barycentric dual of a mesh. The dual is only "dual" in terms of connectivity,
+ * i.e. applying the function twice will give the same vertices, edges, and faces, but not the
+ * same positions. When the option "Keep Boundaries" is selected the connectivity is no
+ * longer dual.
+ *
+ * For the dual mesh of a manifold input mesh:
+ * - The vertices are at the centers of the faces of the input mesh.
+ * - The edges connect the two vertices created from the two faces next to the edge in the input
+ * mesh.
+ * - The faces are at the vertices of the input mesh.
+ *
+ * Some special cases are needed for boundaries and non-manifold geometry.
+ */
+static void calc_dual_mesh(GeometrySet &geometry_set,
+ const MeshComponent &in_component,
+ const bool keep_boundaries)
+{
+ const Mesh &mesh_in = *in_component.get_for_read();
+
+ Map<AttributeIDRef, AttributeKind> attributes;
+ geometry_set.gather_attributes_for_propagation(
+ {GEO_COMPONENT_TYPE_MESH}, GEO_COMPONENT_TYPE_MESH, false, attributes);
+
+ Array<VertexType> vertex_types(mesh_in.totvert);
+ Array<EdgeType> edge_types(mesh_in.totedge);
+ calc_boundaries(mesh_in, vertex_types, edge_types);
+ /* Stores the indices of the polygons connected to the vertex. Because the polygons are looped
+ * over in order of their indices, the polygon's indices will be sorted in ascending order.
+ (This can change once they are sorted using `sort_vertex_polys`). */
+ Array<Vector<int>> vertex_poly_indices(mesh_in.totvert);
+ Array<Array<int>> vertex_shared_edges(mesh_in.totvert);
+ Array<Array<int>> vertex_corners(mesh_in.totvert);
+ create_vertex_poly_map(mesh_in, vertex_poly_indices);
+ threading::parallel_for(vertex_poly_indices.index_range(), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold ||
+ (!keep_boundaries && vertex_types[i] == VertexType::Boundary)) {
+ /* Bad vertex that we can't work with. */
+ continue;
+ }
+ MutableSpan<int> loop_indices = vertex_poly_indices[i];
+ Array<int> sorted_corners(loop_indices.size());
+ if (vertex_types[i] == VertexType::Normal) {
+ Array<int> shared_edges(loop_indices.size());
+ sort_vertex_polys(
+ mesh_in, i, false, edge_types, loop_indices, shared_edges, sorted_corners);
+ vertex_shared_edges[i] = shared_edges;
+ }
+ else {
+ Array<int> shared_edges(loop_indices.size() - 1);
+ sort_vertex_polys(
+ mesh_in, i, true, edge_types, loop_indices, shared_edges, sorted_corners);
+ vertex_shared_edges[i] = shared_edges;
+ }
+ vertex_corners[i] = sorted_corners;
+ }
+ });
+
+ Vector<float3> vertex_positions(mesh_in.totpoly);
+ for (const int i : IndexRange(mesh_in.totpoly)) {
+ const MPoly poly = mesh_in.mpoly[i];
+ BKE_mesh_calc_poly_center(
+ &poly, &mesh_in.mloop[poly.loopstart], mesh_in.mvert, vertex_positions[i]);
+ }
+
+ Array<int> boundary_edge_midpoint_index;
+ if (keep_boundaries) {
+ /* Only initialize when we actually need it. */
+ boundary_edge_midpoint_index.reinitialize(mesh_in.totedge);
+ /* We need to add vertices at the centers of boundary edges. */
+ for (const int i : IndexRange(mesh_in.totedge)) {
+ if (edge_types[i] == EdgeType::Boundary) {
+ float3 mid;
+ const MEdge &edge = mesh_in.medge[i];
+ mid_v3_v3v3(mid, mesh_in.mvert[edge.v1].co, mesh_in.mvert[edge.v2].co);
+ boundary_edge_midpoint_index[i] = vertex_positions.size();
+ vertex_positions.append(mid);
+ }
+ }
+ }
+
+ Vector<int> loop_lengths;
+ Vector<int> loops;
+ Vector<int> loop_edges;
+ Vector<MEdge> new_edges;
+ /* These are used to transfer attributes. */
+ Vector<int> new_to_old_face_corners_map;
+ Vector<int> new_to_old_edges_map;
+ /* Stores the index of the vertex in the dual and the face it should get the attribute from. */
+ Vector<std::pair<int, int>> boundary_vertex_to_relevant_face_map;
+ /* Since each edge in the dual (except the ones created with keep boundaries) comes from
+ * exactly one edge in the original, we can use this array to keep track of whether it still
+ * needs to be created or not. If it's not -1 it gives the index in `new_edges` of the dual
+ * edge. The edges coming from preserving the boundaries only get added once anyway, so we
+ * don't need a hash-map for that. */
+ Array<int> old_to_new_edges_map(mesh_in.totedge);
+ old_to_new_edges_map.fill(-1);
+
+ /* This is necessary to prevent duplicate edges from being created, but will likely not do
+ * anything for most meshes. */
+ dissolve_redundant_verts(mesh_in,
+ vertex_poly_indices,
+ vertex_types,
+ old_to_new_edges_map,
+ new_edges,
+ new_to_old_edges_map);
+
+ for (const int i : IndexRange(mesh_in.totvert)) {
+ if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold ||
+ (!keep_boundaries && vertex_types[i] == VertexType::Boundary)) {
+ /* Bad vertex that we can't work with. */
+ continue;
+ }
+
+ Vector<int> loop_indices = vertex_poly_indices[i];
+ Span<int> shared_edges = vertex_shared_edges[i];
+ Span<int> sorted_corners = vertex_corners[i];
+ if (vertex_types[i] == VertexType::Normal) {
+ if (loop_indices.size() <= 2) {
+ /* We can't make a polygon from 2 vertices. */
+ continue;
+ }
+
+ /* Add edges in the loop. */
+ for (const int i : shared_edges.index_range()) {
+ const int old_edge_i = shared_edges[i];
+ if (old_to_new_edges_map[old_edge_i] == -1) {
+ /* This edge has not been created yet. */
+ MEdge new_edge = MEdge(mesh_in.medge[old_edge_i]);
+ new_edge.v1 = loop_indices[i];
+ new_edge.v2 = loop_indices[(i + 1) % loop_indices.size()];
+ new_to_old_edges_map.append(old_edge_i);
+ old_to_new_edges_map[old_edge_i] = new_edges.size();
+ new_edges.append(new_edge);
+ }
+ loop_edges.append(old_to_new_edges_map[old_edge_i]);
+ }
+
+ new_to_old_face_corners_map.extend(sorted_corners);
+ }
+ else {
+ /**
+ * The code handles boundary vertices like the vertex marked "V" in the diagram below.
+ * The first thing that happens is ordering the faces f1,f2 and f3 (stored in
+ * loop_indices), together with their shared edges e3 and e4 (which get stored in
+ * shared_edges). The ordering could end up being clockwise or counterclockwise, for this
+ * we'll assume that the ordering f1->f2->f3 is chosen. After that we add the edges in
+ * between the polygons, in this case the edges f1--f2, and f2--f3. Now we need to merge
+ * these with the boundary edges e1 and e2. To do this we create an edge from f3 to the
+ * midpoint of e2 (computed in a previous step), from this midpoint to V, from V to the
+ * midpoint of e1 and from the midpoint of e1 to f1.
+ *
+ * \code{.unparsed}
+ * | | | | | |
+ * v2 ---- v3 --------- v4--- v2 ---- v3 -------- v4---
+ * | f3 / ,-' | | / ,-'|
+ * | / f2 ,-' | | / ,-' |
+ * e2 | /e3 ,-' e4 | ====> M1-f3-/--f2-.,-' |
+ * | / ,-' | ====> | / ,-'\ |
+ * | / ,-' f1 | | / ,-' f1 |
+ * | /,-' | | /,-' | |
+ * V-------------------- v5--- V------------M2----- v5---
+ * \endcode
+ */
+
+ /* Add the edges in between the polys. */
+ for (const int i : shared_edges.index_range()) {
+ const int old_edge_i = shared_edges[i];
+ if (old_to_new_edges_map[old_edge_i] == -1) {
+ /* This edge has not been created yet. */
+ MEdge new_edge = MEdge(mesh_in.medge[old_edge_i]);
+ new_edge.v1 = loop_indices[i];
+ new_edge.v2 = loop_indices[i + 1];
+ new_to_old_edges_map.append(old_edge_i);
+ old_to_new_edges_map[old_edge_i] = new_edges.size();
+ new_edges.append(new_edge);
+ }
+ loop_edges.append(old_to_new_edges_map[old_edge_i]);
+ }
+
+ new_to_old_face_corners_map.extend(sorted_corners);
+
+ /* Add the vertex and the midpoints of the two boundary edges to the loop. */
+
+ /* Get the boundary edges. */
+ int edge1;
+ int edge2;
+ if (loop_indices.size() >= 2) {
+ /* The first boundary edge is at the end of the chain of polygons. */
+ boundary_edge_on_poly(mesh_in.mpoly[loop_indices.last()], mesh_in, i, edge_types, edge1);
+ boundary_edge_on_poly(mesh_in.mpoly[loop_indices.first()], mesh_in, i, edge_types, edge2);
+ }
+ else {
+ /* If there is only one polygon both edges are in that polygon. */
+ boundary_edges_on_poly(
+ mesh_in.mpoly[loop_indices[0]], mesh_in, i, edge_types, edge1, edge2);
+ }
+
+ const int last_face_center = loop_indices.last();
+ loop_indices.append(boundary_edge_midpoint_index[edge1]);
+ new_to_old_face_corners_map.append(sorted_corners.last());
+ const int first_midpoint = loop_indices.last();
+ if (old_to_new_edges_map[edge1] == -1) {
+ add_edge(mesh_in,
+ edge1,
+ last_face_center,
+ first_midpoint,
+ new_to_old_edges_map,
+ new_edges,
+ loop_edges);
+ old_to_new_edges_map[edge1] = new_edges.size() - 1;
+ boundary_vertex_to_relevant_face_map.append(std::pair(first_midpoint, last_face_center));
+ }
+ else {
+ loop_edges.append(old_to_new_edges_map[edge1]);
+ }
+ loop_indices.append(vertex_positions.size());
+ /* This is sort of arbitrary, but interpolating would be a lot harder to do. */
+ new_to_old_face_corners_map.append(sorted_corners.first());
+ boundary_vertex_to_relevant_face_map.append(
+ std::pair(loop_indices.last(), last_face_center));
+ vertex_positions.append(mesh_in.mvert[i].co);
+ const int boundary_vertex = loop_indices.last();
+ add_edge(mesh_in,
+ edge1,
+ first_midpoint,
+ boundary_vertex,
+ new_to_old_edges_map,
+ new_edges,
+ loop_edges);
+
+ loop_indices.append(boundary_edge_midpoint_index[edge2]);
+ new_to_old_face_corners_map.append(sorted_corners.first());
+ const int second_midpoint = loop_indices.last();
+ add_edge(mesh_in,
+ edge2,
+ boundary_vertex,
+ second_midpoint,
+ new_to_old_edges_map,
+ new_edges,
+ loop_edges);
+
+ if (old_to_new_edges_map[edge2] == -1) {
+ const int first_face_center = loop_indices.first();
+ add_edge(mesh_in,
+ edge2,
+ second_midpoint,
+ first_face_center,
+ new_to_old_edges_map,
+ new_edges,
+ loop_edges);
+ old_to_new_edges_map[edge2] = new_edges.size() - 1;
+ boundary_vertex_to_relevant_face_map.append(std::pair(second_midpoint, first_face_center));
+ }
+ else {
+ loop_edges.append(old_to_new_edges_map[edge2]);
+ }
+ }
+
+ loop_lengths.append(loop_indices.size());
+ for (const int j : loop_indices) {
+ loops.append(j);
+ }
+ }
+ Mesh *mesh_out = BKE_mesh_new_nomain(
+ vertex_positions.size(), new_edges.size(), 0, loops.size(), loop_lengths.size());
+ MeshComponent out_component;
+ out_component.replace(mesh_out, GeometryOwnershipType::Editable);
+ transfer_attributes(attributes,
+ vertex_types,
+ keep_boundaries,
+ new_to_old_edges_map,
+ new_to_old_face_corners_map,
+ boundary_vertex_to_relevant_face_map,
+ in_component,
+ out_component);
+
+ int loop_start = 0;
+ for (const int i : IndexRange(mesh_out->totpoly)) {
+ mesh_out->mpoly[i].loopstart = loop_start;
+ mesh_out->mpoly[i].totloop = loop_lengths[i];
+ loop_start += loop_lengths[i];
+ }
+ for (const int i : IndexRange(mesh_out->totloop)) {
+ mesh_out->mloop[i].v = loops[i];
+ mesh_out->mloop[i].e = loop_edges[i];
+ }
+ for (const int i : IndexRange(mesh_out->totvert)) {
+ copy_v3_v3(mesh_out->mvert[i].co, vertex_positions[i]);
+ }
+ memcpy(mesh_out->medge, new_edges.data(), sizeof(MEdge) * new_edges.size());
+ BKE_mesh_normals_tag_dirty(mesh_out);
+ geometry_set.replace_mesh(mesh_out);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+ const bool keep_boundaries = params.extract_input<bool>("Keep Boundaries");
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_mesh()) {
+ const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
+ calc_dual_mesh(geometry_set, component, keep_boundaries);
+ }
+ });
+ params.set_output("Dual Mesh", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_dual_mesh_cc
+
+void register_node_type_geo_dual_mesh()
+{
+ namespace file_ns = blender::nodes::node_geo_dual_mesh_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_DUAL_MESH, "Dual Mesh", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
new file mode 100644
index 00000000000..9376789cf2c
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -0,0 +1,97 @@
+/*
+ * 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 "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_edge_split_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_output<decl::Geometry>(N_("Mesh"));
+}
+
+static Mesh *mesh_edge_split(const Mesh &mesh, const IndexMask selection)
+{
+ BMeshCreateParams bmesh_create_params{};
+ bmesh_create_params.use_toolflags = true;
+ const BMAllocTemplate allocsize = {0, 0, 0, 0};
+ BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params);
+
+ BMeshFromMeshParams bmesh_from_mesh_params{};
+ BM_mesh_bm_from_me(bm, &mesh, &bmesh_from_mesh_params);
+
+ BM_mesh_elem_table_ensure(bm, BM_EDGE);
+ for (const int i : selection) {
+ BMEdge *edge = BM_edge_at_index(bm, i);
+ BM_elem_flag_enable(edge, BM_ELEM_TAG);
+ }
+
+ BM_mesh_edgesplit(bm, false, true, false);
+
+ Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, &mesh);
+ BM_mesh_free(bm);
+
+ BKE_mesh_normals_tag_dirty(result);
+
+ return result;
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+
+ const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (!geometry_set.has_mesh()) {
+ return;
+ }
+
+ const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
+ GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE};
+ const int domain_size = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
+ fn::FieldEvaluator selection_evaluator{field_context, domain_size};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+
+ geometry_set.replace_mesh(mesh_edge_split(*mesh_component.get_for_read(), selection));
+ });
+
+ params.set_output("Mesh", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_edge_split_cc
+
+void register_node_type_geo_edge_split()
+{
+ namespace file_ns = blender::nodes::node_geo_edge_split_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SPLIT_EDGES, "Split Edges", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
new file mode 100644
index 00000000000..1d1c5bd2285
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
@@ -0,0 +1,1365 @@
+/*
+ * 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 "BLI_disjoint_set.hh"
+#include "BLI_task.hh"
+#include "BLI_vector_set.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_extrude_mesh_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryExtrudeMesh)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Mesh").supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
+ b.add_input<decl::Vector>(N_("Offset")).subtype(PROP_TRANSLATION).implicit_field().hide_value();
+ b.add_input<decl::Float>(N_("Offset Scale")).default_value(1.0f).min(0.0f).supports_field();
+ b.add_input<decl::Bool>(N_("Individual")).default_value(true);
+ b.add_output<decl::Geometry>("Mesh");
+ b.add_output<decl::Bool>(N_("Top")).field_source();
+ b.add_output<decl::Bool>(N_("Side")).field_source();
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryExtrudeMesh *data = MEM_cnew<NodeGeometryExtrudeMesh>(__func__);
+ data->mode = GEO_NODE_EXTRUDE_MESH_FACES;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeGeometryExtrudeMesh &storage = node_storage(*node);
+ const GeometryNodeExtrudeMeshMode mode = static_cast<GeometryNodeExtrudeMeshMode>(storage.mode);
+
+ bNodeSocket *individual_socket = (bNodeSocket *)node->inputs.last;
+
+ nodeSetSocketAvailability(ntree, individual_socket, mode == GEO_NODE_EXTRUDE_MESH_FACES);
+}
+
+struct AttributeOutputs {
+ StrongAnonymousAttributeID top_id;
+ StrongAnonymousAttributeID side_id;
+};
+
+static void save_selection_as_attribute(MeshComponent &component,
+ const AnonymousAttributeID *id,
+ const AttributeDomain domain,
+ const IndexMask selection)
+{
+ BLI_assert(!component.attribute_exists(id));
+
+ OutputAttribute_Typed<bool> attribute = component.attribute_try_get_for_output_only<bool>(
+ id, domain);
+ /* Rely on the new attribute being zeroed by default. */
+ BLI_assert(!attribute.as_span().as_span().contains(true));
+
+ if (selection.is_range()) {
+ attribute.as_span().slice(selection.as_range()).fill(true);
+ }
+ else {
+ attribute.as_span().fill_indices(selection, true);
+ }
+
+ attribute.save();
+}
+
+static MutableSpan<MVert> mesh_verts(Mesh &mesh)
+{
+ return {mesh.mvert, mesh.totvert};
+}
+static MutableSpan<MEdge> mesh_edges(Mesh &mesh)
+{
+ return {mesh.medge, mesh.totedge};
+}
+static Span<MPoly> mesh_polys(const Mesh &mesh)
+{
+ return {mesh.mpoly, mesh.totpoly};
+}
+static MutableSpan<MPoly> mesh_polys(Mesh &mesh)
+{
+ return {mesh.mpoly, mesh.totpoly};
+}
+static Span<MLoop> mesh_loops(const Mesh &mesh)
+{
+ return {mesh.mloop, mesh.totloop};
+}
+static MutableSpan<MLoop> mesh_loops(Mesh &mesh)
+{
+ return {mesh.mloop, mesh.totloop};
+}
+
+/**
+ * \note: Some areas in this file rely on the new sections of attributes from #CustomData_realloc
+ * to be zeroed.
+ */
+static void expand_mesh(Mesh &mesh,
+ const int vert_expand,
+ const int edge_expand,
+ const int poly_expand,
+ const int loop_expand)
+{
+ if (vert_expand != 0) {
+ CustomData_duplicate_referenced_layers(&mesh.vdata, mesh.totvert);
+ mesh.totvert += vert_expand;
+ CustomData_realloc(&mesh.vdata, mesh.totvert);
+ }
+ else {
+ /* Even when the number of vertices is not changed, the mesh can still be deformed. */
+ CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert);
+ }
+ if (edge_expand != 0) {
+ CustomData_duplicate_referenced_layers(&mesh.edata, mesh.totedge);
+ mesh.totedge += edge_expand;
+ CustomData_realloc(&mesh.edata, mesh.totedge);
+ }
+ if (poly_expand != 0) {
+ CustomData_duplicate_referenced_layers(&mesh.pdata, mesh.totpoly);
+ mesh.totpoly += poly_expand;
+ CustomData_realloc(&mesh.pdata, mesh.totpoly);
+ }
+ if (loop_expand != 0) {
+ CustomData_duplicate_referenced_layers(&mesh.ldata, mesh.totloop);
+ mesh.totloop += loop_expand;
+ CustomData_realloc(&mesh.ldata, mesh.totloop);
+ }
+ BKE_mesh_update_customdata_pointers(&mesh, false);
+}
+
+static MEdge new_edge(const int v1, const int v2)
+{
+ MEdge edge;
+ edge.v1 = v1;
+ edge.v2 = v2;
+ edge.flag = (ME_EDGEDRAW | ME_EDGERENDER);
+ return edge;
+}
+
+static MEdge new_loose_edge(const int v1, const int v2)
+{
+ MEdge edge;
+ edge.v1 = v1;
+ edge.v2 = v2;
+ edge.flag = ME_LOOSEEDGE;
+ return edge;
+}
+
+static MPoly new_poly(const int loopstart, const int totloop)
+{
+ MPoly poly;
+ poly.loopstart = loopstart;
+ poly.totloop = totloop;
+ poly.flag = 0;
+ return poly;
+}
+
+template<typename T> void copy_with_indices(MutableSpan<T> dst, Span<T> src, Span<int> indices)
+{
+ BLI_assert(dst.size() == indices.size());
+ for (const int i : dst.index_range()) {
+ dst[i] = src[indices[i]];
+ }
+}
+
+template<typename T> void copy_with_mask(MutableSpan<T> dst, Span<T> src, IndexMask mask)
+{
+ BLI_assert(dst.size() == mask.size());
+ threading::parallel_for(mask.index_range(), 512, [&](const IndexRange range) {
+ for (const int i : range) {
+ dst[i] = src[mask[i]];
+ }
+ });
+}
+
+/**
+ * \param get_mix_indices_fn: Returns a Span of indices of the source points to mix for every
+ * result point.
+ */
+template<typename T, typename GetMixIndicesFn>
+void copy_with_mixing(MutableSpan<T> dst, Span<T> src, GetMixIndicesFn get_mix_indices_fn)
+{
+ threading::parallel_for(dst.index_range(), 512, [&](const IndexRange range) {
+ attribute_math::DefaultPropatationMixer<T> mixer{dst.slice(range)};
+ for (const int i_dst : IndexRange(range.size())) {
+ for (const int i_src : get_mix_indices_fn(range[i_dst])) {
+ mixer.mix_in(i_dst, src[i_src]);
+ }
+ }
+ mixer.finalize();
+ });
+}
+
+static Array<Vector<int>> create_vert_to_edge_map(const int vert_size,
+ Span<MEdge> edges,
+ const int vert_offset = 0)
+{
+ Array<Vector<int>> vert_to_edge_map(vert_size);
+ for (const int i : edges.index_range()) {
+ vert_to_edge_map[edges[i].v1 - vert_offset].append(i);
+ vert_to_edge_map[edges[i].v2 - vert_offset].append(i);
+ }
+ return vert_to_edge_map;
+}
+
+static void extrude_mesh_vertices(MeshComponent &component,
+ const Field<bool> &selection_field,
+ const Field<float3> &offset_field,
+ const AttributeOutputs &attribute_outputs)
+{
+ Mesh &mesh = *component.get_for_write();
+ const int orig_vert_size = mesh.totvert;
+ const int orig_edge_size = mesh.totedge;
+
+ GeometryComponentFieldContext context{component, ATTR_DOMAIN_POINT};
+ FieldEvaluator evaluator{context, mesh.totvert};
+ evaluator.add(offset_field);
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> offsets = evaluator.get_evaluated<float3>(0);
+
+ /* This allows parallelizing attribute mixing for new edges. */
+ Array<Vector<int>> vert_to_edge_map = create_vert_to_edge_map(orig_vert_size, mesh_edges(mesh));
+
+ expand_mesh(mesh, selection.size(), selection.size(), 0, 0);
+
+ const IndexRange new_vert_range{orig_vert_size, selection.size()};
+ const IndexRange new_edge_range{orig_edge_size, selection.size()};
+
+ MutableSpan<MVert> new_verts = mesh_verts(mesh).slice(new_vert_range);
+ MutableSpan<MEdge> new_edges = mesh_edges(mesh).slice(new_edge_range);
+
+ for (const int i_selection : selection.index_range()) {
+ new_edges[i_selection] = new_loose_edge(selection[i_selection], new_vert_range[i_selection]);
+ }
+
+ component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (!ELEM(meta_data.domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE)) {
+ return true;
+ }
+ OutputAttribute attribute = component.attribute_try_get_for_output(
+ id, meta_data.domain, meta_data.data_type);
+ attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ MutableSpan<T> data = attribute.as_span().typed<T>();
+ switch (attribute.domain()) {
+ case ATTR_DOMAIN_POINT: {
+ /* New vertices copy the attribute values from their source vertex. */
+ copy_with_mask(data.slice(new_vert_range), data.as_span(), selection);
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ /* New edge values are mixed from of all the edges connected to the source vertex. */
+ copy_with_mixing(data.slice(new_edge_range), data.as_span(), [&](const int i) {
+ return vert_to_edge_map[selection[i]].as_span();
+ });
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+ });
+
+ attribute.save();
+ return true;
+ });
+
+ devirtualize_varray(offsets, [&](const auto offsets) {
+ threading::parallel_for(selection.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ const float3 offset = offsets[selection[i]];
+ add_v3_v3(new_verts[i].co, offset);
+ }
+ });
+ });
+
+ if (attribute_outputs.top_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.top_id.get(), ATTR_DOMAIN_POINT, new_vert_range);
+ }
+ if (attribute_outputs.side_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.side_id.get(), ATTR_DOMAIN_EDGE, new_edge_range);
+ }
+
+ BKE_mesh_runtime_clear_cache(&mesh);
+ BKE_mesh_normals_tag_dirty(&mesh);
+}
+
+static Array<Vector<int, 2>> mesh_calculate_polys_of_edge(const Mesh &mesh)
+{
+ Span<MPoly> polys = mesh_polys(mesh);
+ Span<MLoop> loops = mesh_loops(mesh);
+ Array<Vector<int, 2>> polys_of_edge(mesh.totedge);
+
+ for (const int i_poly : polys.index_range()) {
+ const MPoly &poly = polys[i_poly];
+ for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
+ polys_of_edge[loop.e].append(i_poly);
+ }
+ }
+
+ return polys_of_edge;
+}
+
+static void fill_quad_consistent_direction(Span<MLoop> other_poly_loops,
+ MutableSpan<MLoop> new_loops,
+ const int vert_connected_to_poly_1,
+ const int vert_connected_to_poly_2,
+ const int vert_across_from_poly_1,
+ const int vert_across_from_poly_2,
+ const int edge_connected_to_poly,
+ const int connecting_edge_1,
+ const int edge_across_from_poly,
+ const int connecting_edge_2)
+{
+ /* Find the loop on the polygon connected to the new quad that uses the duplicate edge. */
+ bool start_with_connecting_edge = true;
+ for (const MLoop &loop : other_poly_loops) {
+ if (loop.e == edge_connected_to_poly) {
+ start_with_connecting_edge = loop.v == vert_connected_to_poly_1;
+ break;
+ }
+ }
+ if (start_with_connecting_edge) {
+ new_loops[0].v = vert_connected_to_poly_1;
+ new_loops[0].e = connecting_edge_1;
+ new_loops[1].v = vert_across_from_poly_1;
+ new_loops[1].e = edge_across_from_poly;
+ new_loops[2].v = vert_across_from_poly_2;
+ new_loops[2].e = connecting_edge_2;
+ new_loops[3].v = vert_connected_to_poly_2;
+ new_loops[3].e = edge_connected_to_poly;
+ }
+ else {
+ new_loops[0].v = vert_connected_to_poly_1;
+ new_loops[0].e = edge_connected_to_poly;
+ new_loops[1].v = vert_connected_to_poly_2;
+ new_loops[1].e = connecting_edge_2;
+ new_loops[2].v = vert_across_from_poly_2;
+ new_loops[2].e = edge_across_from_poly;
+ new_loops[3].v = vert_across_from_poly_1;
+ new_loops[3].e = connecting_edge_1;
+ }
+}
+
+template<typename T>
+static VectorSet<int> vert_indices_from_edges(const Mesh &mesh, const Span<T> edge_indices)
+{
+ static_assert(is_same_any_v<T, int, int64_t>);
+
+ VectorSet<int> vert_indices;
+ vert_indices.reserve(edge_indices.size());
+ for (const T i_edge : edge_indices) {
+ const MEdge &edge = mesh.medge[i_edge];
+ vert_indices.add(edge.v1);
+ vert_indices.add(edge.v2);
+ }
+ return vert_indices;
+}
+
+static void extrude_mesh_edges(MeshComponent &component,
+ const Field<bool> &selection_field,
+ const Field<float3> &offset_field,
+ const AttributeOutputs &attribute_outputs)
+{
+ Mesh &mesh = *component.get_for_write();
+ const int orig_vert_size = mesh.totvert;
+ Span<MEdge> orig_edges = mesh_edges(mesh);
+ Span<MPoly> orig_polys = mesh_polys(mesh);
+ const int orig_loop_size = mesh.totloop;
+
+ GeometryComponentFieldContext edge_context{component, ATTR_DOMAIN_EDGE};
+ FieldEvaluator edge_evaluator{edge_context, mesh.totedge};
+ edge_evaluator.set_selection(selection_field);
+ edge_evaluator.add(offset_field);
+ edge_evaluator.evaluate();
+ const IndexMask edge_selection = edge_evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &edge_offsets = edge_evaluator.get_evaluated<float3>(0);
+ if (edge_selection.is_empty()) {
+ return;
+ }
+
+ const Array<Vector<int, 2>> edge_to_poly_map = mesh_calculate_polys_of_edge(mesh);
+
+ /* Find the offsets on the vertex domain for translation. This must be done before the mesh's
+ * custom data layers are reallocated, in case the virtual array references on of them. */
+ Array<float3> vert_offsets;
+ if (!edge_offsets.is_single()) {
+ vert_offsets.reinitialize(orig_vert_size);
+ attribute_math::DefaultPropatationMixer<float3> mixer(vert_offsets);
+ for (const int i_edge : edge_selection) {
+ const MEdge &edge = orig_edges[i_edge];
+ const float3 offset = edge_offsets[i_edge];
+ mixer.mix_in(edge.v1, offset);
+ mixer.mix_in(edge.v2, offset);
+ }
+ mixer.finalize();
+ }
+
+ const VectorSet<int> new_vert_indices = vert_indices_from_edges(mesh, edge_selection.indices());
+
+ const IndexRange new_vert_range{orig_vert_size, new_vert_indices.size()};
+ /* The extruded edges connect the original and duplicate edges. */
+ const IndexRange connect_edge_range{orig_edges.size(), new_vert_range.size()};
+ /* The duplicate edges are extruded copies of the selected edges. */
+ const IndexRange duplicate_edge_range = connect_edge_range.after(edge_selection.size());
+ /* There is a new polygon for every selected edge. */
+ const IndexRange new_poly_range{orig_polys.size(), edge_selection.size()};
+ /* Every new polygon is a quad with four corners. */
+ const IndexRange new_loop_range{orig_loop_size, new_poly_range.size() * 4};
+
+ expand_mesh(mesh,
+ new_vert_range.size(),
+ connect_edge_range.size() + duplicate_edge_range.size(),
+ new_poly_range.size(),
+ new_loop_range.size());
+
+ MutableSpan<MVert> new_verts = mesh_verts(mesh).slice(new_vert_range);
+ MutableSpan<MEdge> connect_edges = mesh_edges(mesh).slice(connect_edge_range);
+ MutableSpan<MEdge> duplicate_edges = mesh_edges(mesh).slice(duplicate_edge_range);
+ MutableSpan<MPoly> polys = mesh_polys(mesh);
+ MutableSpan<MPoly> new_polys = polys.slice(new_poly_range);
+ MutableSpan<MLoop> loops = mesh_loops(mesh);
+ MutableSpan<MLoop> new_loops = loops.slice(new_loop_range);
+
+ for (const int i : connect_edges.index_range()) {
+ connect_edges[i] = new_edge(new_vert_indices[i], new_vert_range[i]);
+ }
+
+ for (const int i : duplicate_edges.index_range()) {
+ const MEdge &orig_edge = mesh.medge[edge_selection[i]];
+ const int i_new_vert_1 = new_vert_indices.index_of(orig_edge.v1);
+ const int i_new_vert_2 = new_vert_indices.index_of(orig_edge.v2);
+ duplicate_edges[i] = new_edge(new_vert_range[i_new_vert_1], new_vert_range[i_new_vert_2]);
+ }
+
+ for (const int i : new_polys.index_range()) {
+ new_polys[i] = new_poly(new_loop_range[i * 4], 4);
+ }
+
+ for (const int i : edge_selection.index_range()) {
+ const int orig_edge_index = edge_selection[i];
+
+ const MEdge &duplicate_edge = duplicate_edges[i];
+ const int new_vert_1 = duplicate_edge.v1;
+ const int new_vert_2 = duplicate_edge.v2;
+ const int extrude_index_1 = new_vert_1 - orig_vert_size;
+ const int extrude_index_2 = new_vert_2 - orig_vert_size;
+
+ Span<int> connected_polys = edge_to_poly_map[orig_edge_index];
+
+ /* When there was a single polygon connected to the new polygon, we can use the old one to keep
+ * the face direction consistent. When there is more than one connected edge, the new face
+ * direction is totally arbitrary and the only goal for the behavior is to be deterministic. */
+ Span<MLoop> connected_poly_loops = {};
+ if (connected_polys.size() == 1) {
+ const MPoly &connected_poly = polys[connected_polys.first()];
+ connected_poly_loops = loops.slice(connected_poly.loopstart, connected_poly.totloop);
+ }
+ fill_quad_consistent_direction(connected_poly_loops,
+ new_loops.slice(4 * i, 4),
+ new_vert_indices[extrude_index_1],
+ new_vert_indices[extrude_index_2],
+ new_vert_1,
+ new_vert_2,
+ orig_edge_index,
+ connect_edge_range[extrude_index_1],
+ duplicate_edge_range[i],
+ connect_edge_range[extrude_index_2]);
+ }
+
+ /* Create a map of indices in the extruded vertices array to all of the indices of edges
+ * in the duplicate edges array that connect to that vertex. This can be used to simplify the
+ * mixing of attribute data for the connecting edges. */
+ const Array<Vector<int>> new_vert_to_duplicate_edge_map = create_vert_to_edge_map(
+ new_vert_range.size(), duplicate_edges, orig_vert_size);
+
+ component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ OutputAttribute attribute = component.attribute_try_get_for_output(
+ id, meta_data.domain, meta_data.data_type);
+ if (!attribute) {
+ return true; /* Impossible to write the "normal" attribute. */
+ }
+
+ attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ MutableSpan<T> data = attribute.as_span().typed<T>();
+ switch (attribute.domain()) {
+ case ATTR_DOMAIN_POINT: {
+ /* New vertices copy the attribute values from their source vertex. */
+ copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices);
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ /* Edges parallel to original edges copy the edge attributes from the original edges. */
+ MutableSpan<T> duplicate_data = data.slice(duplicate_edge_range);
+ copy_with_mask(duplicate_data, data.as_span(), edge_selection);
+
+ /* Edges connected to original vertices mix values of selected connected edges. */
+ MutableSpan<T> connect_data = data.slice(connect_edge_range);
+ copy_with_mixing(connect_data, duplicate_data.as_span(), [&](const int i_new_vert) {
+ return new_vert_to_duplicate_edge_map[i_new_vert].as_span();
+ });
+ break;
+ }
+ case ATTR_DOMAIN_FACE: {
+ /* Attribute values for new faces are a mix of the values of faces connected to the its
+ * original edge. */
+ copy_with_mixing(data.slice(new_poly_range), data.as_span(), [&](const int i) {
+ return edge_to_poly_map[edge_selection[i]].as_span();
+ });
+
+ break;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ /* New corners get the average value of all adjacent corners on original faces connected
+ * to the original edge of their face. */
+ MutableSpan<T> new_data = data.slice(new_loop_range);
+ threading::parallel_for(edge_selection.index_range(), 256, [&](const IndexRange range) {
+ for (const int i_edge_selection : range) {
+ const int orig_edge_index = edge_selection[i_edge_selection];
+
+ Span<int> connected_polys = edge_to_poly_map[orig_edge_index];
+ if (connected_polys.is_empty()) {
+ /* If there are no connected polygons, there is no corner data to
+ * interpolate. */
+ new_data.slice(4 * i_edge_selection, 4).fill(T());
+ continue;
+ }
+
+ /* Both corners on each vertical edge of the side polygon get the same value,
+ * so there are only two unique values to mix. */
+ Array<T> side_poly_corner_data(2);
+ attribute_math::DefaultPropatationMixer<T> mixer{side_poly_corner_data};
+
+ const MEdge &duplicate_edge = duplicate_edges[i_edge_selection];
+ const int new_vert_1 = duplicate_edge.v1;
+ const int new_vert_2 = duplicate_edge.v2;
+ const int orig_vert_1 = new_vert_indices[new_vert_1 - orig_vert_size];
+ const int orig_vert_2 = new_vert_indices[new_vert_2 - orig_vert_size];
+
+ /* Average the corner data from the corners that share a vertex from the
+ * polygons that share an edge with the extruded edge. */
+ for (const int i_connected_poly : connected_polys.index_range()) {
+ const MPoly &connected_poly = polys[connected_polys[i_connected_poly]];
+ for (const int i_loop :
+ IndexRange(connected_poly.loopstart, connected_poly.totloop)) {
+ const MLoop &loop = loops[i_loop];
+ if (loop.v == orig_vert_1) {
+ mixer.mix_in(0, data[i_loop]);
+ }
+ if (loop.v == orig_vert_2) {
+ mixer.mix_in(1, data[i_loop]);
+ }
+ }
+ }
+
+ mixer.finalize();
+
+ /* Instead of replicating the order in #fill_quad_consistent_direction here, it's
+ * simpler (though probably slower) to just match the corner data based on the vertex
+ * indices. */
+ for (const int i : IndexRange(4 * i_edge_selection, 4)) {
+ if (ELEM(new_loops[i].v, new_vert_1, orig_vert_1)) {
+ new_data[i] = side_poly_corner_data.first();
+ }
+ else if (ELEM(new_loops[i].v, new_vert_2, orig_vert_2)) {
+ new_data[i] = side_poly_corner_data.last();
+ }
+ }
+ }
+ });
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+ });
+
+ attribute.save();
+ return true;
+ });
+
+ if (edge_offsets.is_single()) {
+ const float3 offset = edge_offsets.get_internal_single();
+ threading::parallel_for(new_verts.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ add_v3_v3(new_verts[i].co, offset);
+ }
+ });
+ }
+ else {
+ threading::parallel_for(new_verts.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ add_v3_v3(new_verts[i].co, vert_offsets[new_vert_indices[i]]);
+ }
+ });
+ }
+
+ if (attribute_outputs.top_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.top_id.get(), ATTR_DOMAIN_EDGE, duplicate_edge_range);
+ }
+ if (attribute_outputs.side_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, new_poly_range);
+ }
+
+ BKE_mesh_runtime_clear_cache(&mesh);
+ BKE_mesh_normals_tag_dirty(&mesh);
+}
+
+/**
+ * Edges connected to one selected face are on the boundary of a region and will be duplicated into
+ * a "side face". Edges inside a region will be duplicated to leave any original faces unchanged.
+ */
+static void extrude_mesh_face_regions(MeshComponent &component,
+ const Field<bool> &selection_field,
+ const Field<float3> &offset_field,
+ const AttributeOutputs &attribute_outputs)
+{
+ Mesh &mesh = *component.get_for_write();
+ const int orig_vert_size = mesh.totvert;
+ Span<MEdge> orig_edges = mesh_edges(mesh);
+ Span<MPoly> orig_polys = mesh_polys(mesh);
+ Span<MLoop> orig_loops = mesh_loops(mesh);
+
+ GeometryComponentFieldContext poly_context{component, ATTR_DOMAIN_FACE};
+ FieldEvaluator poly_evaluator{poly_context, mesh.totpoly};
+ poly_evaluator.set_selection(selection_field);
+ poly_evaluator.add(offset_field);
+ poly_evaluator.evaluate();
+ const IndexMask poly_selection = poly_evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &poly_offsets = poly_evaluator.get_evaluated<float3>(0);
+ if (poly_selection.is_empty()) {
+ return;
+ }
+
+ Array<bool> poly_selection_array(orig_polys.size(), false);
+ for (const int i_poly : poly_selection) {
+ poly_selection_array[i_poly] = true;
+ }
+
+ /* Mix the offsets from the face domain to the vertex domain. Evaluate on the face domain above
+ * in order to be consistent with the selection, and to use the face normals rather than vertex
+ * normals as an offset, for example. */
+ Array<float3> vert_offsets;
+ if (!poly_offsets.is_single()) {
+ vert_offsets.reinitialize(orig_vert_size);
+ attribute_math::DefaultPropatationMixer<float3> mixer(vert_offsets);
+ for (const int i_poly : poly_selection) {
+ const MPoly &poly = orig_polys[i_poly];
+ const float3 offset = poly_offsets[i_poly];
+ for (const MLoop &loop : orig_loops.slice(poly.loopstart, poly.totloop)) {
+ mixer.mix_in(loop.v, offset);
+ }
+ }
+ mixer.finalize();
+ }
+
+ /* All of the faces (selected and deselected) connected to each edge. */
+ const Array<Vector<int, 2>> edge_to_poly_map = mesh_calculate_polys_of_edge(mesh);
+
+ /* All vertices that are connected to the selected polygons.
+ * Start the size at one vert per poly to reduce unnecessary reallocation. */
+ VectorSet<int> all_selected_verts;
+ all_selected_verts.reserve(orig_polys.size());
+ for (const int i_poly : poly_selection) {
+ const MPoly &poly = orig_polys[i_poly];
+ for (const MLoop &loop : orig_loops.slice(poly.loopstart, poly.totloop)) {
+ all_selected_verts.add(loop.v);
+ }
+ }
+
+ /* Edges inside of an extruded region that are also attached to deselected edges. They must be
+ * duplicated in order to leave the old edge attached to the unchanged deselected faces. */
+ VectorSet<int> new_inner_edge_indices;
+ /* Edges inside of an extruded region. Their vertices should be translated
+ * with the offset, but the edges themselves should not be duplicated. */
+ Vector<int> inner_edge_indices;
+ /* The extruded face corresponding to each boundary edge (and each boundary face). */
+ Vector<int> edge_extruded_face_indices;
+ /* Edges on the outside of selected regions, either because there are no
+ * other connected faces, or because all of the other faces aren't selected. */
+ VectorSet<int> boundary_edge_indices;
+ for (const int i_edge : orig_edges.index_range()) {
+ Span<int> polys = edge_to_poly_map[i_edge];
+
+ int i_selected_poly = -1;
+ int deselected_poly_count = 0;
+ int selected_poly_count = 0;
+ for (const int i_other_poly : polys) {
+ if (poly_selection_array[i_other_poly]) {
+ selected_poly_count++;
+ i_selected_poly = i_other_poly;
+ }
+ else {
+ deselected_poly_count++;
+ }
+ }
+
+ if (selected_poly_count == 1) {
+ /* If there is only one selected polygon connected to the edge,
+ * the edge should be extruded to form a "side face". */
+ boundary_edge_indices.add_new(i_edge);
+ edge_extruded_face_indices.append(i_selected_poly);
+ }
+ else if (selected_poly_count > 1) {
+ /* The edge is inside an extruded region of faces. */
+ if (deselected_poly_count > 0) {
+ /* Add edges that are also connected to deselected edges to a separate list. */
+ new_inner_edge_indices.add_new(i_edge);
+ }
+ else {
+ /* Otherwise, just keep track of edges inside the region so that
+ * we can reattach them to duplicated vertices if necessary. */
+ inner_edge_indices.append(i_edge);
+ }
+ }
+ }
+
+ VectorSet<int> new_vert_indices = vert_indices_from_edges(mesh, boundary_edge_indices.as_span());
+ /* Before adding the rest of the new vertices from the new inner edges, store the number
+ * of new vertices from the boundary edges, since this is the number of connecting edges. */
+ const int extruded_vert_size = new_vert_indices.size();
+
+ /* The vertices attached to duplicate inner edges also have to be duplicated. */
+ for (const int i_edge : new_inner_edge_indices) {
+ const MEdge &edge = mesh.medge[i_edge];
+ new_vert_indices.add(edge.v1);
+ new_vert_indices.add(edge.v2);
+ }
+
+ /* New vertices forming the duplicated boundary edges and the ends of the new inner edges. */
+ const IndexRange new_vert_range{orig_vert_size, new_vert_indices.size()};
+ /* One edge connects each selected vertex to a new vertex on the extruded polygons. */
+ const IndexRange connect_edge_range{orig_edges.size(), extruded_vert_size};
+ /* Each selected edge is duplicated to form a single edge on the extrusion. */
+ const IndexRange boundary_edge_range = connect_edge_range.after(boundary_edge_indices.size());
+ /* Duplicated edges inside regions that were connected to deselected faces. */
+ const IndexRange new_inner_edge_range = boundary_edge_range.after(new_inner_edge_indices.size());
+ /* Each edge selected for extrusion is extruded into a single face. */
+ const IndexRange side_poly_range{orig_polys.size(), boundary_edge_indices.size()};
+ /* The loops that form the new side faces. */
+ const IndexRange side_loop_range{orig_loops.size(), side_poly_range.size() * 4};
+
+ expand_mesh(mesh,
+ new_vert_range.size(),
+ connect_edge_range.size() + boundary_edge_range.size() + new_inner_edge_range.size(),
+ side_poly_range.size(),
+ side_loop_range.size());
+
+ MutableSpan<MEdge> edges = mesh_edges(mesh);
+ MutableSpan<MEdge> connect_edges = edges.slice(connect_edge_range);
+ MutableSpan<MEdge> boundary_edges = edges.slice(boundary_edge_range);
+ MutableSpan<MEdge> new_inner_edges = edges.slice(new_inner_edge_range);
+ MutableSpan<MPoly> polys = mesh_polys(mesh);
+ MutableSpan<MPoly> new_polys = polys.slice(side_poly_range);
+ MutableSpan<MLoop> loops = mesh_loops(mesh);
+ MutableSpan<MLoop> new_loops = loops.slice(side_loop_range);
+
+ /* Initialize the edges that form the sides of the extrusion. */
+ for (const int i : connect_edges.index_range()) {
+ connect_edges[i] = new_edge(new_vert_indices[i], new_vert_range[i]);
+ }
+
+ /* Initialize the edges that form the top of the extrusion. */
+ for (const int i : boundary_edges.index_range()) {
+ const MEdge &orig_edge = edges[boundary_edge_indices[i]];
+ const int i_new_vert_1 = new_vert_indices.index_of(orig_edge.v1);
+ const int i_new_vert_2 = new_vert_indices.index_of(orig_edge.v2);
+ boundary_edges[i] = new_edge(new_vert_range[i_new_vert_1], new_vert_range[i_new_vert_2]);
+ }
+
+ /* Initialize the new edges inside of extrude regions. */
+ for (const int i : new_inner_edge_indices.index_range()) {
+ const MEdge &orig_edge = edges[new_inner_edge_indices[i]];
+ const int i_new_vert_1 = new_vert_indices.index_of(orig_edge.v1);
+ const int i_new_vert_2 = new_vert_indices.index_of(orig_edge.v2);
+ new_inner_edges[i] = new_edge(new_vert_range[i_new_vert_1], new_vert_range[i_new_vert_2]);
+ }
+
+ /* Initialize the new side polygons. */
+ for (const int i : new_polys.index_range()) {
+ new_polys[i] = new_poly(side_loop_range[i * 4], 4);
+ }
+
+ /* Connect original edges inside face regions to any new vertices, if necessary. */
+ for (const int i : inner_edge_indices) {
+ MEdge &edge = edges[i];
+ const int i_new_vert_1 = new_vert_indices.index_of_try(edge.v1);
+ const int i_new_vert_2 = new_vert_indices.index_of_try(edge.v2);
+ if (i_new_vert_1 != -1) {
+ edge.v1 = new_vert_range[i_new_vert_1];
+ }
+ if (i_new_vert_2 != -1) {
+ edge.v2 = new_vert_range[i_new_vert_2];
+ }
+ }
+
+ /* Connect the selected faces to the extruded or duplicated edges and the new vertices. */
+ for (const int i_poly : poly_selection) {
+ const MPoly &poly = polys[i_poly];
+ for (MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
+ const int i_new_vert = new_vert_indices.index_of_try(loop.v);
+ if (i_new_vert != -1) {
+ loop.v = new_vert_range[i_new_vert];
+ }
+ const int i_boundary_edge = boundary_edge_indices.index_of_try(loop.e);
+ if (i_boundary_edge != -1) {
+ loop.e = boundary_edge_range[i_boundary_edge];
+ /* Skip the next check, an edge cannot be both a boundary edge and an inner edge. */
+ continue;
+ }
+ const int i_new_inner_edge = new_inner_edge_indices.index_of_try(loop.e);
+ if (i_new_inner_edge != -1) {
+ loop.e = new_inner_edge_range[i_new_inner_edge];
+ }
+ }
+ }
+
+ /* Create the faces on the sides of extruded regions. */
+ for (const int i : boundary_edge_indices.index_range()) {
+ const MEdge &boundary_edge = boundary_edges[i];
+ const int new_vert_1 = boundary_edge.v1;
+ const int new_vert_2 = boundary_edge.v2;
+ const int extrude_index_1 = new_vert_1 - orig_vert_size;
+ const int extrude_index_2 = new_vert_2 - orig_vert_size;
+
+ const MPoly &extrude_poly = polys[edge_extruded_face_indices[i]];
+
+ fill_quad_consistent_direction(loops.slice(extrude_poly.loopstart, extrude_poly.totloop),
+ new_loops.slice(4 * i, 4),
+ new_vert_1,
+ new_vert_2,
+ new_vert_indices[extrude_index_1],
+ new_vert_indices[extrude_index_2],
+ boundary_edge_range[i],
+ connect_edge_range[extrude_index_1],
+ boundary_edge_indices[i],
+ connect_edge_range[extrude_index_2]);
+ }
+
+ /* Create a map of indices in the extruded vertices array to all of the indices of edges
+ * in the duplicate edges array that connect to that vertex. This can be used to simplify the
+ * mixing of attribute data for the connecting edges. */
+ const Array<Vector<int>> new_vert_to_duplicate_edge_map = create_vert_to_edge_map(
+ new_vert_range.size(), boundary_edges, orig_vert_size);
+
+ component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ OutputAttribute attribute = component.attribute_try_get_for_output(
+ id, meta_data.domain, meta_data.data_type);
+ if (!attribute) {
+ return true; /* Impossible to write the "normal" attribute. */
+ }
+
+ attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ MutableSpan<T> data = attribute.as_span().typed<T>();
+ switch (attribute.domain()) {
+ case ATTR_DOMAIN_POINT: {
+ /* New vertices copy the attributes from their original vertices. */
+ copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices);
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ /* Edges parallel to original edges copy the edge attributes from the original edges. */
+ MutableSpan<T> boundary_data = data.slice(boundary_edge_range);
+ copy_with_indices(boundary_data, data.as_span(), boundary_edge_indices);
+
+ /* Edges inside of face regions also just duplicate their source data. */
+ MutableSpan<T> new_inner_data = data.slice(new_inner_edge_range);
+ copy_with_indices(new_inner_data, data.as_span(), new_inner_edge_indices);
+
+ /* Edges connected to original vertices mix values of selected connected edges. */
+ MutableSpan<T> connect_data = data.slice(connect_edge_range);
+ copy_with_mixing(connect_data, boundary_data.as_span(), [&](const int i) {
+ return new_vert_to_duplicate_edge_map[i].as_span();
+ });
+ break;
+ }
+ case ATTR_DOMAIN_FACE: {
+ /* New faces on the side of extrusions get the values from the corresponding selected
+ * face. */
+ copy_with_indices(
+ data.slice(side_poly_range), data.as_span(), edge_extruded_face_indices);
+ break;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ /* New corners get the values from the corresponding corner on the extruded face. */
+ MutableSpan<T> new_data = data.slice(side_loop_range);
+ threading::parallel_for(
+ boundary_edge_indices.index_range(), 256, [&](const IndexRange range) {
+ for (const int i_boundary_edge : range) {
+ const MPoly &poly = polys[edge_extruded_face_indices[i_boundary_edge]];
+
+ const MEdge &boundary_edge = boundary_edges[i_boundary_edge];
+ const int new_vert_1 = boundary_edge.v1;
+ const int new_vert_2 = boundary_edge.v2;
+ const int orig_vert_1 = new_vert_indices[new_vert_1 - orig_vert_size];
+ const int orig_vert_2 = new_vert_indices[new_vert_2 - orig_vert_size];
+
+ /* Retrieve the data for the first two sides of the quad from the extruded
+ * polygon, which we generally expect to have just a small amount of sides. This
+ * loop could be eliminated by adding a cache of connected loops (which would
+ * also simplify some of the other code to find the correct loops on the extruded
+ * face). */
+ T data_1;
+ T data_2;
+ for (const int i_loop : IndexRange(poly.loopstart, poly.totloop)) {
+ if (loops[i_loop].v == new_vert_1) {
+ data_1 = data[i_loop];
+ }
+ if (loops[i_loop].v == new_vert_2) {
+ data_2 = data[i_loop];
+ }
+ }
+
+ /* Instead of replicating the order in #fill_quad_consistent_direction here, it's
+ * simpler (though probably slower) to just match the corner data based on the
+ * vertex indices. */
+ for (const int i : IndexRange(4 * i_boundary_edge, 4)) {
+ if (ELEM(new_loops[i].v, new_vert_1, orig_vert_1)) {
+ new_data[i] = data_1;
+ }
+ else if (ELEM(new_loops[i].v, new_vert_2, orig_vert_2)) {
+ new_data[i] = data_2;
+ }
+ }
+ }
+ });
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+ });
+
+ attribute.save();
+ return true;
+ });
+
+ /* Translate vertices based on the offset. If the vertex is used by a selected edge, it will
+ * have been duplicated and only the new vertex should use the offset. Otherwise the vertex might
+ * still need an offset, but it was reused on the inside of a region of extruded faces. */
+ if (poly_offsets.is_single()) {
+ const float3 offset = poly_offsets.get_internal_single();
+ threading::parallel_for(
+ IndexRange(all_selected_verts.size()), 1024, [&](const IndexRange range) {
+ for (const int i_orig : all_selected_verts.as_span().slice(range)) {
+ const int i_new = new_vert_indices.index_of_try(i_orig);
+ MVert &vert = mesh_verts(mesh)[(i_new == -1) ? i_orig : new_vert_range[i_new]];
+ add_v3_v3(vert.co, offset);
+ }
+ });
+ }
+ else {
+ threading::parallel_for(
+ IndexRange(all_selected_verts.size()), 1024, [&](const IndexRange range) {
+ for (const int i_orig : all_selected_verts.as_span().slice(range)) {
+ const int i_new = new_vert_indices.index_of_try(i_orig);
+ const float3 offset = vert_offsets[i_orig];
+ MVert &vert = mesh_verts(mesh)[(i_new == -1) ? i_orig : new_vert_range[i_new]];
+ add_v3_v3(vert.co, offset);
+ }
+ });
+ }
+
+ if (attribute_outputs.top_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
+ }
+ if (attribute_outputs.side_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, side_poly_range);
+ }
+
+ BKE_mesh_runtime_clear_cache(&mesh);
+ BKE_mesh_normals_tag_dirty(&mesh);
+}
+
+/* Get the range into an array of extruded corners, edges, or vertices for a particular polygon. */
+static IndexRange selected_corner_range(Span<int> offsets, const int index)
+{
+ const int offset = offsets[index];
+ const int next_offset = offsets[index + 1];
+ return IndexRange(offset, next_offset - offset);
+}
+
+static void extrude_individual_mesh_faces(MeshComponent &component,
+ const Field<bool> &selection_field,
+ const Field<float3> &offset_field,
+ const AttributeOutputs &attribute_outputs)
+{
+ Mesh &mesh = *component.get_for_write();
+ const int orig_vert_size = mesh.totvert;
+ const int orig_edge_size = mesh.totedge;
+ Span<MPoly> orig_polys = mesh_polys(mesh);
+ Span<MLoop> orig_loops = mesh_loops(mesh);
+
+ /* Use a mesh for the result of the evaluation because the mesh is reallocated before
+ * the vertices are moved, and the evaluated result might reference an attribute. */
+ Array<float3> poly_offset(orig_polys.size());
+ GeometryComponentFieldContext poly_context{component, ATTR_DOMAIN_FACE};
+ FieldEvaluator poly_evaluator{poly_context, mesh.totpoly};
+ poly_evaluator.set_selection(selection_field);
+ poly_evaluator.add_with_destination(offset_field, poly_offset.as_mutable_span());
+ poly_evaluator.evaluate();
+ const IndexMask poly_selection = poly_evaluator.get_evaluated_selection_as_mask();
+
+ /* Build an array of offsets into the new data for each polygon. This is used to facilitate
+ * parallelism later on by avoiding the need to keep track of an offset when iterating through
+ * all polygons. */
+ int extrude_corner_size = 0;
+ Array<int> index_offsets(poly_selection.size() + 1);
+ for (const int i_selection : poly_selection.index_range()) {
+ const MPoly &poly = orig_polys[poly_selection[i_selection]];
+ index_offsets[i_selection] = extrude_corner_size;
+ extrude_corner_size += poly.totloop;
+ }
+ index_offsets.last() = extrude_corner_size;
+
+ const IndexRange new_vert_range{orig_vert_size, extrude_corner_size};
+ /* One edge connects each selected vertex to a new vertex on the extruded polygons. */
+ const IndexRange connect_edge_range{orig_edge_size, extrude_corner_size};
+ /* Each selected edge is duplicated to form a single edge on the extrusion. */
+ const IndexRange duplicate_edge_range = connect_edge_range.after(extrude_corner_size);
+ /* Each edge selected for extrusion is extruded into a single face. */
+ const IndexRange side_poly_range{orig_polys.size(), duplicate_edge_range.size()};
+ const IndexRange side_loop_range{orig_loops.size(), side_poly_range.size() * 4};
+
+ expand_mesh(mesh,
+ new_vert_range.size(),
+ connect_edge_range.size() + duplicate_edge_range.size(),
+ side_poly_range.size(),
+ side_loop_range.size());
+
+ MutableSpan<MVert> new_verts = mesh_verts(mesh).slice(new_vert_range);
+ MutableSpan<MEdge> edges{mesh.medge, mesh.totedge};
+ MutableSpan<MEdge> connect_edges = edges.slice(connect_edge_range);
+ MutableSpan<MEdge> duplicate_edges = edges.slice(duplicate_edge_range);
+ MutableSpan<MPoly> polys{mesh.mpoly, mesh.totpoly};
+ MutableSpan<MPoly> new_polys = polys.slice(side_poly_range);
+ MutableSpan<MLoop> loops{mesh.mloop, mesh.totloop};
+
+ /* For every selected polygon, build the faces that form the sides of the extrusion. Filling some
+ * of this data like the new edges or polygons could be easily split into separate loops, which
+ * may or may not be faster, and would involve more duplication. */
+ threading::parallel_for(poly_selection.index_range(), 256, [&](const IndexRange range) {
+ for (const int i_selection : range) {
+ const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection);
+
+ const MPoly &poly = polys[poly_selection[i_selection]];
+ Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+
+ for (const int i : IndexRange(poly.totloop)) {
+ const int i_next = (i == poly.totloop - 1) ? 0 : i + 1;
+ const MLoop &orig_loop = poly_loops[i];
+ const MLoop &orig_loop_next = poly_loops[i_next];
+
+ const int i_extrude = poly_corner_range[i];
+ const int i_extrude_next = poly_corner_range[i_next];
+
+ const int i_duplicate_edge = duplicate_edge_range[i_extrude];
+ const int new_vert = new_vert_range[i_extrude];
+ const int new_vert_next = new_vert_range[i_extrude_next];
+
+ const int orig_edge = orig_loop.e;
+
+ const int orig_vert = orig_loop.v;
+ const int orig_vert_next = orig_loop_next.v;
+
+ duplicate_edges[i_extrude] = new_edge(new_vert, new_vert_next);
+
+ new_polys[i_extrude] = new_poly(side_loop_range[i_extrude * 4], 4);
+
+ MutableSpan<MLoop> side_loops = loops.slice(side_loop_range[i_extrude * 4], 4);
+ side_loops[0].v = new_vert_next;
+ side_loops[0].e = i_duplicate_edge;
+ side_loops[1].v = new_vert;
+ side_loops[1].e = connect_edge_range[i_extrude];
+ side_loops[2].v = orig_vert;
+ side_loops[2].e = orig_edge;
+ side_loops[3].v = orig_vert_next;
+ side_loops[3].e = connect_edge_range[i_extrude_next];
+
+ connect_edges[i_extrude] = new_edge(orig_vert, new_vert);
+ }
+ }
+ });
+
+ component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ OutputAttribute attribute = component.attribute_try_get_for_output(
+ id, meta_data.domain, meta_data.data_type);
+ if (!attribute) {
+ return true; /* Impossible to write the "normal" attribute. */
+ }
+
+ attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ MutableSpan<T> data = attribute.as_span().typed<T>();
+ switch (attribute.domain()) {
+ case ATTR_DOMAIN_POINT: {
+ /* New vertices copy the attributes from their original vertices. */
+ MutableSpan<T> new_data = data.slice(new_vert_range);
+
+ threading::parallel_for(poly_selection.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i_selection : range) {
+ const MPoly &poly = polys[poly_selection[i_selection]];
+ Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+
+ const int corner_offset = index_offsets[i_selection];
+ for (const int i : poly_loops.index_range()) {
+ const int orig_index = poly_loops[i].v;
+ new_data[corner_offset + i] = data[orig_index];
+ }
+ }
+ });
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ MutableSpan<T> duplicate_data = data.slice(duplicate_edge_range);
+ MutableSpan<T> connect_data = data.slice(connect_edge_range);
+
+ threading::parallel_for(poly_selection.index_range(), 512, [&](const IndexRange range) {
+ for (const int i_selection : range) {
+ const MPoly &poly = polys[poly_selection[i_selection]];
+ Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+
+ const IndexRange poly_corner_range = selected_corner_range(index_offsets,
+ i_selection);
+
+ /* The data for the duplicate edge is simply a copy of the original edge's data. */
+ for (const int i : poly_loops.index_range()) {
+ const int orig_index = poly_loops[i].e;
+ duplicate_data[poly_corner_range[i]] = data[orig_index];
+ }
+
+ /* For the extruded edges, mix the data from the two neighboring original edges of
+ * the extruded polygon. */
+ for (const int i : poly_loops.index_range()) {
+ const int i_loop_prev = (i == 0) ? poly.totloop - 1 : i - 1;
+ const int orig_index = poly_loops[i].e;
+ const int orig_index_prev = poly_loops[i_loop_prev].e;
+ if constexpr (std::is_same_v<T, bool>) {
+ /* Propagate selections with "or" instead of "at least half". */
+ connect_data[poly_corner_range[i]] = data[orig_index] || data[orig_index_prev];
+ }
+ else {
+ connect_data[poly_corner_range[i]] = attribute_math::mix2(
+ 0.5f, data[orig_index], data[orig_index_prev]);
+ }
+ }
+ }
+ });
+ break;
+ }
+ case ATTR_DOMAIN_FACE: {
+ /* Each side face gets the values from the corresponding new face. */
+ MutableSpan<T> new_data = data.slice(side_poly_range);
+ threading::parallel_for(poly_selection.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i_selection : range) {
+ const int poly_index = poly_selection[i_selection];
+ const IndexRange poly_corner_range = selected_corner_range(index_offsets,
+ i_selection);
+ new_data.slice(poly_corner_range).fill(data[poly_index]);
+ }
+ });
+ break;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ /* Each corner on a side face gets its value from the matching corner on an extruded
+ * face. */
+ MutableSpan<T> new_data = data.slice(side_loop_range);
+ threading::parallel_for(poly_selection.index_range(), 256, [&](const IndexRange range) {
+ for (const int i_selection : range) {
+ const MPoly &poly = polys[poly_selection[i_selection]];
+ Span<T> poly_loop_data = data.slice(poly.loopstart, poly.totloop);
+ const IndexRange poly_corner_range = selected_corner_range(index_offsets,
+ i_selection);
+
+ for (const int i : IndexRange(poly.totloop)) {
+ const int i_next = (i == poly.totloop - 1) ? 0 : i + 1;
+ const int i_extrude = poly_corner_range[i];
+
+ MutableSpan<T> side_loop_data = new_data.slice(i_extrude * 4, 4);
+
+ /* The two corners on each side of the side polygon get the data from the matching
+ * corners of the extruded polygon. This order depends on the loop filling the loop
+ * indices. */
+ side_loop_data[0] = poly_loop_data[i_next];
+ side_loop_data[1] = poly_loop_data[i];
+ side_loop_data[2] = poly_loop_data[i];
+ side_loop_data[3] = poly_loop_data[i_next];
+ }
+ }
+ });
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+ });
+
+ attribute.save();
+ return true;
+ });
+
+ /* Offset the new vertices. */
+ threading::parallel_for(poly_selection.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i_selection : range) {
+ const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection);
+ for (MVert &vert : new_verts.slice(poly_corner_range)) {
+ add_v3_v3(vert.co, poly_offset[poly_selection[i_selection]]);
+ }
+ }
+ });
+
+ /* Finally update each extruded polygon's loops to point to the new edges and vertices.
+ * This must be done last, because they were used to find original indices for attribute
+ * interpolation before. Alternatively an original index array could be built for each domain. */
+ threading::parallel_for(poly_selection.index_range(), 256, [&](const IndexRange range) {
+ for (const int i_selection : range) {
+ const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection);
+
+ const MPoly &poly = polys[poly_selection[i_selection]];
+ MutableSpan<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+
+ for (const int i : IndexRange(poly.totloop)) {
+ MLoop &loop = poly_loops[i];
+ loop.v = new_vert_range[poly_corner_range[i]];
+ loop.e = duplicate_edge_range[poly_corner_range[i]];
+ }
+ }
+ });
+
+ if (attribute_outputs.top_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
+ }
+ if (attribute_outputs.side_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, side_poly_range);
+ }
+
+ BKE_mesh_runtime_clear_cache(&mesh);
+ BKE_mesh_normals_tag_dirty(&mesh);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+ Field<bool> selection = params.extract_input<Field<bool>>("Selection");
+ Field<float3> offset_field = params.extract_input<Field<float3>>("Offset");
+ Field<float> scale_field = params.extract_input<Field<float>>("Offset Scale");
+ const NodeGeometryExtrudeMesh &storage = node_storage(params.node());
+ GeometryNodeExtrudeMeshMode mode = static_cast<GeometryNodeExtrudeMeshMode>(storage.mode);
+
+ /* Create a combined field from the offset and the scale so the field evaluator
+ * can take care of the multiplication and to simplify each extrude function. */
+ static fn::CustomMF_SI_SI_SO<float3, float, float3> multiply_fn{
+ "Scale", [](const float3 &offset, const float scale) { return offset * scale; }};
+ std::shared_ptr<FieldOperation> multiply_op = std::make_shared<FieldOperation>(
+ FieldOperation(multiply_fn, {std::move(offset_field), std::move(scale_field)}));
+ const Field<float3> final_offset{std::move(multiply_op)};
+
+ AttributeOutputs attribute_outputs;
+ if (params.output_is_required("Top")) {
+ attribute_outputs.top_id = StrongAnonymousAttributeID("Top");
+ }
+ if (params.output_is_required("Side")) {
+ attribute_outputs.side_id = StrongAnonymousAttributeID("Side");
+ }
+
+ const bool extrude_individual = mode == GEO_NODE_EXTRUDE_MESH_FACES &&
+ params.extract_input<bool>("Individual");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_mesh()) {
+ MeshComponent &component = geometry_set.get_component_for_write<MeshComponent>();
+ switch (mode) {
+ case GEO_NODE_EXTRUDE_MESH_VERTICES:
+ extrude_mesh_vertices(component, selection, final_offset, attribute_outputs);
+ break;
+ case GEO_NODE_EXTRUDE_MESH_EDGES:
+ extrude_mesh_edges(component, selection, final_offset, attribute_outputs);
+ break;
+ case GEO_NODE_EXTRUDE_MESH_FACES: {
+ if (extrude_individual) {
+ extrude_individual_mesh_faces(component, selection, final_offset, attribute_outputs);
+ }
+ else {
+ extrude_mesh_face_regions(component, selection, final_offset, attribute_outputs);
+ }
+ break;
+ }
+ }
+
+ BLI_assert(BKE_mesh_is_valid(component.get_for_write()));
+ }
+ });
+
+ params.set_output("Mesh", std::move(geometry_set));
+ if (attribute_outputs.top_id) {
+ params.set_output("Top",
+ AnonymousAttributeFieldInput::Create<bool>(
+ std::move(attribute_outputs.top_id), params.attribute_producer_name()));
+ }
+ if (attribute_outputs.side_id) {
+ params.set_output("Side",
+ AnonymousAttributeFieldInput::Create<bool>(
+ std::move(attribute_outputs.side_id), params.attribute_producer_name()));
+ }
+}
+
+} // namespace blender::nodes::node_geo_extrude_mesh_cc
+
+void register_node_type_geo_extrude_mesh()
+{
+ namespace file_ns = blender::nodes::node_geo_extrude_mesh_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_EXTRUDE_MESH, "Extrude Mesh", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_storage(
+ &ntype, "NodeGeometryExtrudeMesh", node_free_standard_storage, node_copy_standard_storage);
+ ntype.draw_buttons = file_ns::node_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
new file mode 100644
index 00000000000..9512323834c
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
@@ -0,0 +1,193 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "BKE_attribute_math.hh"
+
+#include "BLI_task.hh"
+
+namespace blender::nodes::node_geo_field_at_index_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Index")).min(0).supports_field();
+
+ b.add_input<decl::Float>(N_("Value"), "Value_Float").supports_field();
+ b.add_input<decl::Int>(N_("Value"), "Value_Int").supports_field();
+ b.add_input<decl::Vector>(N_("Value"), "Value_Vector").supports_field();
+ b.add_input<decl::Color>(N_("Value"), "Value_Color").supports_field();
+ b.add_input<decl::Bool>(N_("Value"), "Value_Bool").supports_field();
+
+ b.add_output<decl::Float>(N_("Value"), "Value_Float").field_source();
+ b.add_output<decl::Int>(N_("Value"), "Value_Int").field_source();
+ b.add_output<decl::Vector>(N_("Value"), "Value_Vector").field_source();
+ b.add_output<decl::Color>(N_("Value"), "Value_Color").field_source();
+ b.add_output<decl::Bool>(N_("Value"), "Value_Bool").field_source();
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ node->custom1 = ATTR_DOMAIN_POINT;
+ node->custom2 = CD_PROP_FLOAT;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const CustomDataType data_type = static_cast<CustomDataType>(node->custom2);
+
+ bNodeSocket *sock_index = static_cast<bNodeSocket *>(node->inputs.first);
+ bNodeSocket *sock_in_float = sock_index->next;
+ bNodeSocket *sock_in_int = sock_in_float->next;
+ bNodeSocket *sock_in_vector = sock_in_int->next;
+ bNodeSocket *sock_in_color = sock_in_vector->next;
+ bNodeSocket *sock_in_bool = sock_in_color->next;
+
+ bNodeSocket *sock_out_float = static_cast<bNodeSocket *>(node->outputs.first);
+ bNodeSocket *sock_out_int = sock_out_float->next;
+ bNodeSocket *sock_out_vector = sock_out_int->next;
+ bNodeSocket *sock_out_color = sock_out_vector->next;
+ bNodeSocket *sock_out_bool = sock_out_color->next;
+
+ nodeSetSocketAvailability(ntree, sock_in_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_in_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(ntree, sock_in_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_in_color, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, sock_in_bool, data_type == CD_PROP_BOOL);
+
+ nodeSetSocketAvailability(ntree, sock_out_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_out_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(ntree, sock_out_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_out_color, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, sock_out_bool, data_type == CD_PROP_BOOL);
+}
+
+class FieldAtIndex final : public GeometryFieldInput {
+ private:
+ Field<int> index_field_;
+ GField value_field_;
+ AttributeDomain value_field_domain_;
+
+ public:
+ FieldAtIndex(Field<int> index_field, GField value_field, AttributeDomain value_field_domain)
+ : GeometryFieldInput(value_field.cpp_type(), "Field at Index"),
+ index_field_(std::move(index_field)),
+ value_field_(std::move(value_field)),
+ value_field_domain_(value_field_domain)
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
+ {
+ const GeometryComponentFieldContext value_field_context{component, value_field_domain_};
+ FieldEvaluator value_evaluator{value_field_context,
+ component.attribute_domain_size(value_field_domain_)};
+ value_evaluator.add(value_field_);
+ value_evaluator.evaluate();
+ const GVArray &values = value_evaluator.get_evaluated(0);
+
+ const GeometryComponentFieldContext index_field_context{component, domain};
+ FieldEvaluator index_evaluator{index_field_context, &mask};
+ index_evaluator.add(index_field_);
+ index_evaluator.evaluate();
+ const VArray<int> &indices = index_evaluator.get_evaluated<int>(0);
+
+ GVArray output_array;
+ attribute_math::convert_to_static_type(*type_, [&](auto dummy) {
+ using T = decltype(dummy);
+ Array<T> dst_array(mask.min_array_size());
+ VArray<T> src_values = values.typed<T>();
+ threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i : mask.slice(range)) {
+ const int index = indices[i];
+ if (index >= 0 && index < src_values.size()) {
+ dst_array[i] = src_values[index];
+ }
+ else {
+ dst_array[i] = {};
+ }
+ }
+ });
+ output_array = VArray<T>::ForContainer(std::move(dst_array));
+ });
+
+ return output_array;
+ }
+};
+
+static StringRefNull identifier_suffix(CustomDataType data_type)
+{
+ switch (data_type) {
+ case CD_PROP_BOOL:
+ return "Bool";
+ case CD_PROP_FLOAT:
+ return "Float";
+ case CD_PROP_INT32:
+ return "Int";
+ case CD_PROP_COLOR:
+ return "Color";
+ case CD_PROP_FLOAT3:
+ return "Vector";
+ default:
+ BLI_assert_unreachable();
+ return "";
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const bNode &node = params.node();
+ const AttributeDomain domain = static_cast<AttributeDomain>(node.custom1);
+ const CustomDataType data_type = static_cast<CustomDataType>(node.custom2);
+
+ Field<int> index_field = params.extract_input<Field<int>>("Index");
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ static const std::string identifier = "Value_" + identifier_suffix(data_type);
+ Field<T> value_field = params.extract_input<Field<T>>(identifier);
+ Field<T> output_field{
+ std::make_shared<FieldAtIndex>(std::move(index_field), std::move(value_field), domain)};
+ params.set_output(identifier, std::move(output_field));
+ });
+}
+
+} // namespace blender::nodes::node_geo_field_at_index_cc
+
+void register_node_type_geo_field_at_index()
+{
+ namespace file_ns = blender::nodes::node_geo_field_at_index_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_FIELD_AT_INDEX, "Field at Index", NODE_CLASS_CONVERTER);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.initfunc = file_ns::node_init;
+ ntype.updatefunc = file_ns::node_update;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
new file mode 100644
index 00000000000..41970d75dfe
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
@@ -0,0 +1,114 @@
+/*
+ * 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 "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute_math.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_flip_faces_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_output<decl::Geometry>(N_("Mesh"));
+}
+
+static void mesh_flip_faces(MeshComponent &component, const Field<bool> &selection_field)
+{
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ if (domain_size == 0) {
+ return;
+ }
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+
+ Mesh *mesh = component.get_for_write();
+
+ mesh->mloop = (MLoop *)CustomData_duplicate_referenced_layer(
+ &mesh->ldata, CD_MLOOP, mesh->totloop);
+ Span<MPoly> polys{mesh->mpoly, mesh->totpoly};
+ MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
+
+ for (const int i : selection.index_range()) {
+ const MPoly &poly = polys[selection[i]];
+ int start = poly.loopstart;
+ for (const int j : IndexRange(poly.totloop / 2)) {
+ const int index1 = start + j + 1;
+ const int index2 = start + poly.totloop - j - 1;
+ std::swap(loops[index1].v, loops[index2].v);
+ std::swap(loops[index1 - 1].e, loops[index2].e);
+ }
+ }
+
+ component.attribute_foreach(
+ [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ if (meta_data.domain == ATTR_DOMAIN_CORNER) {
+ OutputAttribute attribute = component.attribute_try_get_for_output(
+ attribute_id, ATTR_DOMAIN_CORNER, meta_data.data_type, nullptr);
+ attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ MutableSpan<T> dst_span = attribute.as_span<T>();
+ for (const int j : selection.index_range()) {
+ const MPoly &poly = polys[selection[j]];
+ dst_span.slice(poly.loopstart + 1, poly.totloop - 1).reverse();
+ }
+ });
+ attribute.save();
+ }
+ return true;
+ });
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+
+ const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (!geometry_set.has_mesh()) {
+ return;
+ }
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ mesh_flip_faces(mesh_component, selection_field);
+ });
+
+ params.set_output("Mesh", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_flip_faces_cc
+
+void register_node_type_geo_flip_faces()
+{
+ namespace file_ns = blender::nodes::node_geo_flip_faces_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_FLIP_FACES, "Flip Faces", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
new file mode 100644
index 00000000000..f65af5b6737
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_geometry_to_instance_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry")).multi_input();
+ b.add_output<decl::Geometry>(N_("Instances"));
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Vector<GeometrySet> geometries = params.extract_multi_input<GeometrySet>("Geometry");
+ GeometrySet instances_geometry;
+ InstancesComponent &instances_component =
+ instances_geometry.get_component_for_write<InstancesComponent>();
+ for (GeometrySet &geometry : geometries) {
+ geometry.ensure_owns_direct_data();
+ const int handle = instances_component.add_reference(std::move(geometry));
+ instances_component.add_instance(handle, float4x4::identity());
+ }
+ params.set_output("Instances", std::move(instances_geometry));
+}
+
+} // namespace blender::nodes::node_geo_geometry_to_instance_cc
+
+void register_node_type_geo_geometry_to_instance()
+{
+ namespace file_ns = blender::nodes::node_geo_geometry_to_instance_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_GEOMETRY_TO_INSTANCE, "Geometry to Instance", NODE_CLASS_GEOMETRY);
+ node_type_size(&ntype, 160, 100, 300);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
new file mode 100644
index 00000000000..624a8b6b0f6
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
@@ -0,0 +1,428 @@
+/*
+ * 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.
+ */
+
+#include "node_geometry_util.hh"
+
+#include "BKE_image.h"
+
+#include "BLI_math_vec_types.hh"
+#include "BLI_threads.h"
+#include "BLI_timeit.hh"
+
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_geo_image_texture_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryImageTexture)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Image>(N_("Image")).hide_label();
+ b.add_input<decl::Vector>(N_("Vector"))
+ .implicit_field()
+ .description(("Texture coordinates from 0 to 1"));
+ b.add_input<decl::Int>(N_("Frame")).min(0).max(MAXFRAMEF);
+ b.add_output<decl::Color>(N_("Color")).no_muted_links().dependent_field();
+ b.add_output<decl::Float>(N_("Alpha")).no_muted_links().dependent_field();
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "extension", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryImageTexture *tex = MEM_cnew<NodeGeometryImageTexture>(__func__);
+ node->storage = tex;
+}
+
+class ImageFieldsFunction : public fn::MultiFunction {
+ private:
+ const int interpolation_;
+ const int extension_;
+ Image &image_;
+ ImageUser image_user_;
+ void *image_lock_;
+ ImBuf *image_buffer_;
+
+ public:
+ ImageFieldsFunction(const int interpolation,
+ const int extension,
+ Image &image,
+ ImageUser image_user)
+ : interpolation_(interpolation),
+ extension_(extension),
+ image_(image),
+ image_user_(image_user)
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+
+ image_buffer_ = BKE_image_acquire_ibuf(&image_, &image_user_, &image_lock_);
+ if (image_buffer_ == nullptr) {
+ throw std::runtime_error("cannot acquire image buffer");
+ }
+
+ if (image_buffer_->rect_float == nullptr) {
+ BLI_thread_lock(LOCK_IMAGE);
+ if (!image_buffer_->rect_float) {
+ IMB_float_from_rect(image_buffer_);
+ }
+ BLI_thread_unlock(LOCK_IMAGE);
+ }
+
+ if (image_buffer_->rect_float == nullptr) {
+ BKE_image_release_ibuf(&image_, image_buffer_, image_lock_);
+ throw std::runtime_error("cannot get float buffer");
+ }
+ }
+
+ ~ImageFieldsFunction() override
+ {
+ BKE_image_release_ibuf(&image_, image_buffer_, image_lock_);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"ImageFunction"};
+ signature.single_input<float3>("Vector");
+ signature.single_output<ColorGeometry4f>("Color");
+ signature.single_output<float>("Alpha");
+ return signature.build();
+ }
+
+ static int wrap_periodic(int x, const int width)
+ {
+ x %= width;
+ if (x < 0) {
+ x += width;
+ }
+ return x;
+ }
+
+ static int wrap_clamp(const int x, const int width)
+ {
+ return std::clamp(x, 0, width - 1);
+ }
+
+ static float4 image_pixel_lookup(const ImBuf *ibuf, const int px, const int py)
+ {
+ if (px < 0 || py < 0 || px >= ibuf->x || py >= ibuf->y) {
+ return float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ return ((const float4 *)ibuf->rect_float)[px + py * ibuf->x];
+ }
+
+ static float frac(const float x, int *ix)
+ {
+ const int i = (int)x - ((x < 0.0f) ? 1 : 0);
+ *ix = i;
+ return x - (float)i;
+ }
+
+ static float4 image_cubic_texture_lookup(const ImBuf *ibuf,
+ const float px,
+ const float py,
+ const int extension)
+ {
+ const int width = ibuf->x;
+ const int height = ibuf->y;
+ int pix, piy, nix, niy;
+ const float tx = frac(px * (float)width - 0.5f, &pix);
+ const float ty = frac(py * (float)height - 0.5f, &piy);
+ int ppix, ppiy, nnix, nniy;
+
+ switch (extension) {
+ case SHD_IMAGE_EXTENSION_REPEAT: {
+ pix = wrap_periodic(pix, width);
+ piy = wrap_periodic(piy, height);
+ ppix = wrap_periodic(pix - 1, width);
+ ppiy = wrap_periodic(piy - 1, height);
+ nix = wrap_periodic(pix + 1, width);
+ niy = wrap_periodic(piy + 1, height);
+ nnix = wrap_periodic(pix + 2, width);
+ nniy = wrap_periodic(piy + 2, height);
+ break;
+ }
+ case SHD_IMAGE_EXTENSION_CLIP: {
+ ppix = pix - 1;
+ ppiy = piy - 1;
+ nix = pix + 1;
+ niy = piy + 1;
+ nnix = pix + 2;
+ nniy = piy + 2;
+ break;
+ }
+ case SHD_IMAGE_EXTENSION_EXTEND: {
+ ppix = wrap_clamp(pix - 1, width);
+ ppiy = wrap_clamp(piy - 1, height);
+ nix = wrap_clamp(pix + 1, width);
+ niy = wrap_clamp(piy + 1, height);
+ nnix = wrap_clamp(pix + 2, width);
+ nniy = wrap_clamp(piy + 2, height);
+ pix = wrap_clamp(pix, width);
+ piy = wrap_clamp(piy, height);
+ break;
+ }
+ default:
+ return float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+
+ const int xc[4] = {ppix, pix, nix, nnix};
+ const int yc[4] = {ppiy, piy, niy, nniy};
+ float u[4], v[4];
+
+ u[0] = (((-1.0f / 6.0f) * tx + 0.5f) * tx - 0.5f) * tx + (1.0f / 6.0f);
+ u[1] = ((0.5f * tx - 1.0f) * tx) * tx + (2.0f / 3.0f);
+ u[2] = ((-0.5f * tx + 0.5f) * tx + 0.5f) * tx + (1.0f / 6.0f);
+ u[3] = (1.0f / 6.0f) * tx * tx * tx;
+
+ v[0] = (((-1.0f / 6.0f) * ty + 0.5f) * ty - 0.5f) * ty + (1.0f / 6.0f);
+ v[1] = ((0.5f * ty - 1.0f) * ty) * ty + (2.0f / 3.0f);
+ v[2] = ((-0.5f * ty + 0.5f) * ty + 0.5f) * ty + (1.0f / 6.0f);
+ v[3] = (1.0f / 6.0f) * ty * ty * ty;
+
+ return (v[0] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[0])) +
+ u[1] * (image_pixel_lookup(ibuf, xc[1], yc[0])) +
+ u[2] * (image_pixel_lookup(ibuf, xc[2], yc[0])) +
+ u[3] * (image_pixel_lookup(ibuf, xc[3], yc[0])))) +
+ (v[1] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[1])) +
+ u[1] * (image_pixel_lookup(ibuf, xc[1], yc[1])) +
+ u[2] * (image_pixel_lookup(ibuf, xc[2], yc[1])) +
+ u[3] * (image_pixel_lookup(ibuf, xc[3], yc[1])))) +
+ (v[2] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[2])) +
+ u[1] * (image_pixel_lookup(ibuf, xc[1], yc[2])) +
+ u[2] * (image_pixel_lookup(ibuf, xc[2], yc[2])) +
+ u[3] * (image_pixel_lookup(ibuf, xc[3], yc[2])))) +
+ (v[3] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[3])) +
+ u[1] * (image_pixel_lookup(ibuf, xc[1], yc[3])) +
+ u[2] * (image_pixel_lookup(ibuf, xc[2], yc[3])) +
+ u[3] * (image_pixel_lookup(ibuf, xc[3], yc[3]))));
+ }
+
+ static float4 image_linear_texture_lookup(const ImBuf *ibuf,
+ const float px,
+ const float py,
+ const int extension)
+ {
+ const int width = ibuf->x;
+ const int height = ibuf->y;
+ int pix, piy, nix, niy;
+ const float nfx = frac(px * (float)width - 0.5f, &pix);
+ const float nfy = frac(py * (float)height - 0.5f, &piy);
+
+ switch (extension) {
+ case SHD_IMAGE_EXTENSION_CLIP: {
+ nix = pix + 1;
+ niy = piy + 1;
+ break;
+ }
+ case SHD_IMAGE_EXTENSION_EXTEND: {
+ nix = wrap_clamp(pix + 1, width);
+ niy = wrap_clamp(piy + 1, height);
+ pix = wrap_clamp(pix, width);
+ piy = wrap_clamp(piy, height);
+ break;
+ }
+ default:
+ case SHD_IMAGE_EXTENSION_REPEAT:
+ pix = wrap_periodic(pix, width);
+ piy = wrap_periodic(piy, height);
+ nix = wrap_periodic(pix + 1, width);
+ niy = wrap_periodic(piy + 1, height);
+ break;
+ }
+
+ const float ptx = 1.0f - nfx;
+ const float pty = 1.0f - nfy;
+
+ return image_pixel_lookup(ibuf, pix, piy) * ptx * pty +
+ image_pixel_lookup(ibuf, nix, piy) * nfx * pty +
+ image_pixel_lookup(ibuf, pix, niy) * ptx * nfy +
+ image_pixel_lookup(ibuf, nix, niy) * nfx * nfy;
+ }
+
+ static float4 image_closest_texture_lookup(const ImBuf *ibuf,
+ const float px,
+ const float py,
+ const int extension)
+ {
+ const int width = ibuf->x;
+ const int height = ibuf->y;
+ int ix, iy;
+ const float tx = frac(px * (float)width - 0.5f, &ix);
+ const float ty = frac(py * (float)height - 0.5f, &iy);
+
+ switch (extension) {
+ case SHD_IMAGE_EXTENSION_REPEAT: {
+ ix = wrap_periodic(ix, width);
+ iy = wrap_periodic(iy, height);
+ return image_pixel_lookup(ibuf, ix, iy);
+ }
+ case SHD_IMAGE_EXTENSION_CLIP: {
+ if (tx < 0.0f || ty < 0.0f || tx > 1.0f || ty > 1.0f) {
+ return float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ if (ix < 0 || iy < 0 || ix > width || iy > height) {
+ return float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ ATTR_FALLTHROUGH;
+ }
+ case SHD_IMAGE_EXTENSION_EXTEND: {
+ ix = wrap_clamp(ix, width);
+ iy = wrap_clamp(iy, height);
+ return image_pixel_lookup(ibuf, ix, iy);
+ }
+ default:
+ return float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float3> &vectors = params.readonly_single_input<float3>(0, "Vector");
+ MutableSpan<ColorGeometry4f> r_color = params.uninitialized_single_output<ColorGeometry4f>(
+ 1, "Color");
+ MutableSpan<float> r_alpha = params.uninitialized_single_output_if_required<float>(2, "Alpha");
+
+ MutableSpan<float4> color_data{(float4 *)r_color.data(), r_color.size()};
+
+ /* Sample image texture. */
+ switch (interpolation_) {
+ case SHD_INTERP_LINEAR:
+ for (const int64_t i : mask) {
+ const float3 p = vectors[i];
+ color_data[i] = image_linear_texture_lookup(image_buffer_, p.x, p.y, extension_);
+ }
+ break;
+ case SHD_INTERP_CLOSEST:
+ for (const int64_t i : mask) {
+ const float3 p = vectors[i];
+ color_data[i] = image_closest_texture_lookup(image_buffer_, p.x, p.y, extension_);
+ }
+ break;
+ case SHD_INTERP_CUBIC:
+ case SHD_INTERP_SMART:
+ for (const int64_t i : mask) {
+ const float3 p = vectors[i];
+ color_data[i] = image_cubic_texture_lookup(image_buffer_, p.x, p.y, extension_);
+ }
+ break;
+ }
+
+ int alpha_mode = image_.alpha_mode;
+ if (IMB_colormanagement_space_name_is_data(image_.colorspace_settings.name)) {
+ alpha_mode = IMA_ALPHA_CHANNEL_PACKED;
+ }
+
+ switch (alpha_mode) {
+ case IMA_ALPHA_STRAIGHT: {
+ /* #ColorGeometry expects premultiplied alpha, so convert from straight to that. */
+ for (int64_t i : mask) {
+ straight_to_premul_v4(color_data[i]);
+ }
+ break;
+ }
+ case IMA_ALPHA_PREMUL: {
+ /* Alpha is premultiplied already, nothing to do. */
+ break;
+ }
+ case IMA_ALPHA_CHANNEL_PACKED: {
+ /* Color and alpha channels shouldn't interact with each other, nothing to do. */
+ break;
+ }
+ case IMA_ALPHA_IGNORE: {
+ /* The image should be treated as being opaque. */
+ for (int64_t i : mask) {
+ color_data[i].w = 1.0f;
+ }
+ break;
+ }
+ }
+
+ if (!r_alpha.is_empty()) {
+ for (int64_t i : mask) {
+ r_alpha[i] = r_color[i].a;
+ }
+ }
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Image *image = params.get_input<Image *>("Image");
+ if (image == nullptr) {
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ const NodeGeometryImageTexture &storage = node_storage(params.node());
+
+ ImageUser image_user;
+ BKE_imageuser_default(&image_user);
+ image_user.cycl = false;
+ image_user.frames = INT_MAX;
+ image_user.sfra = 1;
+ image_user.framenr = BKE_image_is_animated(image) ? params.get_input<int>("Frame") : 0;
+
+ std::unique_ptr<ImageFieldsFunction> image_fn;
+ try {
+ image_fn = std::make_unique<ImageFieldsFunction>(
+ storage.interpolation, storage.extension, *image, image_user);
+ }
+ catch (const std::runtime_error &) {
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ Field<float3> vector_field = params.extract_input<Field<float3>>("Vector");
+
+ auto image_op = std::make_shared<FieldOperation>(
+ FieldOperation(std::move(image_fn), {std::move(vector_field)}));
+
+ params.set_output("Color", Field<ColorGeometry4f>(image_op, 0));
+ params.set_output("Alpha", Field<float>(image_op, 1));
+}
+
+} // namespace blender::nodes::node_geo_image_texture_cc
+
+void register_node_type_geo_image_texture()
+{
+ namespace file_ns = blender::nodes::node_geo_image_texture_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_IMAGE_TEXTURE, "Image Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_storage(
+ &ntype, "NodeGeometryImageTexture", node_free_standard_storage, node_copy_standard_storage);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
new file mode 100644
index 00000000000..b1144b58c37
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
@@ -0,0 +1,128 @@
+/*
+ * 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 "BKE_spline.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_curve_handles_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Bool>(N_("Relative"))
+ .default_value(false)
+ .supports_field()
+ .description(N_("Output the handle positions relative to the corresponding control point "
+ "instead of in the local space of the geometry"));
+ b.add_output<decl::Vector>(N_("Left")).field_source();
+ b.add_output<decl::Vector>(N_("Right")).field_source();
+}
+
+class HandlePositionFieldInput final : public GeometryFieldInput {
+ Field<bool> relative_;
+ bool left_;
+
+ public:
+ HandlePositionFieldInput(Field<bool> relative, bool left)
+ : GeometryFieldInput(CPPType::get<float3>(), "Handle"), relative_(relative), left_(left)
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_CURVE) {
+ return {};
+ }
+
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ fn::FieldEvaluator evaluator(field_context, &mask);
+ evaluator.add(relative_);
+ evaluator.evaluate();
+ const VArray<bool> &relative = evaluator.get_evaluated<bool>(0);
+
+ VArray<float3> positions = component.attribute_get_for_read<float3>(
+ "position", ATTR_DOMAIN_POINT, {0, 0, 0});
+
+ StringRef side = left_ ? "handle_left" : "handle_right";
+ VArray<float3> handles = component.attribute_get_for_read<float3>(
+ side, ATTR_DOMAIN_POINT, {0, 0, 0});
+
+ if (relative.is_single()) {
+ if (relative.get_internal_single()) {
+ Array<float3> output(positions.size());
+ for (const int i : positions.index_range()) {
+ output[i] = handles[i] - positions[i];
+ }
+ return component.attribute_try_adapt_domain<float3>(
+ VArray<float3>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
+ }
+ return component.attribute_try_adapt_domain<float3>(handles, ATTR_DOMAIN_POINT, domain);
+ }
+
+ Array<float3> output(positions.size());
+ for (const int i : positions.index_range()) {
+ if (relative[i]) {
+ output[i] = handles[i] - positions[i];
+ }
+ else {
+ output[i] = handles[i];
+ }
+ }
+ return component.attribute_try_adapt_domain<float3>(
+ VArray<float3>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ return get_default_hash_2(relative_, left_);
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const HandlePositionFieldInput *other_handle =
+ dynamic_cast<const HandlePositionFieldInput *>(&other)) {
+ return relative_ == other_handle->relative_ && left_ == other_handle->left_;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<bool> relative = params.extract_input<Field<bool>>("Relative");
+ Field<float3> left_field{std::make_shared<HandlePositionFieldInput>(relative, true)};
+ Field<float3> right_field{std::make_shared<HandlePositionFieldInput>(relative, false)};
+
+ params.set_output("Left", std::move(left_field));
+ params.set_output("Right", std::move(right_field));
+}
+
+} // namespace blender::nodes::node_geo_input_curve_handles_cc
+
+void register_node_type_geo_input_curve_handles()
+{
+ namespace file_ns = blender::nodes::node_geo_input_curve_handles_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_CURVE_HANDLES, "Curve Handle Positions", NODE_CLASS_INPUT);
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
new file mode 100644
index 00000000000..61b4b6bb9e9
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
@@ -0,0 +1,44 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_curve_tilt_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Tilt")).field_source();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<float> tilt_field = AttributeFieldInput::Create<float>("tilt");
+ params.set_output("Tilt", std::move(tilt_field));
+}
+
+} // namespace blender::nodes::node_geo_input_curve_tilt_cc
+
+void register_node_type_geo_input_curve_tilt()
+{
+ namespace file_ns = blender::nodes::node_geo_input_curve_tilt_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_CURVE_TILT, "Curve Tilt", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
new file mode 100644
index 00000000000..3fe0588a46d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
@@ -0,0 +1,44 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_id_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("ID")).field_source();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> position_field{std::make_shared<bke::IDAttributeFieldInput>()};
+ params.set_output("ID", std::move(position_field));
+}
+
+} // namespace blender::nodes::node_geo_input_id_cc
+
+void register_node_type_geo_input_id()
+{
+ namespace file_ns = blender::nodes::node_geo_input_id_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_ID, "ID", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
index 7fcbaf429dd..98c2c9d58f0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_index_cc {
-static void geo_node_input_index_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Int>("Index").field_source();
+ b.add_output<decl::Int>(N_("Index")).field_source();
}
-static void geo_node_input_index_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<int> index_field{std::make_shared<fn::IndexFieldInput>()};
params.set_output("Index", std::move(index_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_index_cc
void register_node_type_geo_input_index()
{
+ namespace file_ns = blender::nodes::node_geo_input_index_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_INDEX, "Index", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_index_exec;
- ntype.declare = blender::nodes::geo_node_input_index_declare;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_INDEX, "Index", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
index 8e805bd1359..a1c905fccaa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
@@ -19,33 +19,35 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_material_cc {
-static void geo_node_input_material_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Material>("Material");
+ b.add_output<decl::Material>(N_("Material"));
}
-static void geo_node_input_material_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "material", 0, "", ICON_NONE);
}
-static void geo_node_input_material_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *material = (Material *)params.node().id;
params.set_output("Material", material);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_material_cc
void register_node_type_geo_input_material()
{
+ namespace file_ns = blender::nodes::node_geo_input_material_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL, "Material", NODE_CLASS_INPUT, 0);
- ntype.draw_buttons = blender::nodes::geo_node_input_material_layout;
- ntype.declare = blender::nodes::geo_node_input_material_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_input_material_exec;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL, "Material", NODE_CLASS_INPUT);
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
new file mode 100644
index 00000000000..fca29feb73c
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
@@ -0,0 +1,44 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_material_index_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Material Index")).field_source();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> material_index_field = AttributeFieldInput::Create<int>("material_index");
+ params.set_output("Material Index", std::move(material_index_field));
+}
+
+} // namespace blender::nodes::node_geo_input_material_index_cc
+
+void register_node_type_geo_input_material_index()
+{
+ namespace file_ns = blender::nodes::node_geo_input_material_index_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL_INDEX, "Material Index", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
new file mode 100644
index 00000000000..4b6ed7b77b7
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
@@ -0,0 +1,222 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_edge_angle_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Unsigned Angle"))
+ .field_source()
+ .description(
+ "The shortest angle in radians between two faces where they meet at an edge. Flat edges "
+ "and Non-manifold edges have an angle of zero. Computing this value is faster than the "
+ "signed angle");
+ b.add_output<decl::Float>(N_("Signed Angle"))
+ .field_source()
+ .description(
+ "The signed angle in radians between two faces where they meet at an edge. Flat edges "
+ "and Non-manifold edges have an angle of zero. Concave angles are positive and convex "
+ "angles are negative. Computing this value is slower than the unsigned angle");
+}
+
+struct EdgeMapEntry {
+ int face_count;
+ int face_index_1;
+ int face_index_2;
+};
+
+static Array<EdgeMapEntry> create_edge_map(const Span<MPoly> polys,
+ const Span<MLoop> loops,
+ const int total_edges)
+{
+ Array<EdgeMapEntry> edge_map(total_edges, {0, 0, 0});
+
+ for (const int i_poly : polys.index_range()) {
+ const MPoly &mpoly = polys[i_poly];
+ for (const MLoop &loop : loops.slice(mpoly.loopstart, mpoly.totloop)) {
+ EdgeMapEntry &entry = edge_map[loop.e];
+ if (entry.face_count == 0) {
+ entry.face_index_1 = i_poly;
+ }
+ else if (entry.face_count == 1) {
+ entry.face_index_2 = i_poly;
+ }
+ entry.face_count++;
+ }
+ }
+ return edge_map;
+}
+
+class AngleFieldInput final : public GeometryFieldInput {
+ public:
+ AngleFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Unsigned Angle Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ return {};
+ }
+
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ Span<MPoly> polys{mesh->mpoly, mesh->totpoly};
+ Span<MLoop> loops{mesh->mloop, mesh->totloop};
+ Array<EdgeMapEntry> edge_map = create_edge_map(polys, loops, mesh->totedge);
+
+ auto angle_fn = [edge_map, polys, loops, mesh](const int i) -> float {
+ if (edge_map[i].face_count != 2) {
+ return 0.0f;
+ }
+ const MPoly &mpoly_1 = polys[edge_map[i].face_index_1];
+ const MPoly &mpoly_2 = polys[edge_map[i].face_index_2];
+ float3 normal_1, normal_2;
+ BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], mesh->mvert, normal_1);
+ BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, normal_2);
+ return angle_normalized_v3v3(normal_1, normal_2);
+ };
+
+ VArray<float> angles = VArray<float>::ForFunc(mesh->totedge, angle_fn);
+ return component.attribute_try_adapt_domain<float>(
+ std::move(angles), ATTR_DOMAIN_EDGE, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 32426725235;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const AngleFieldInput *>(&other) != nullptr;
+ }
+};
+
+class SignedAngleFieldInput final : public GeometryFieldInput {
+ public:
+ SignedAngleFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Signed Angle Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ return {};
+ }
+
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ Span<MPoly> polys{mesh->mpoly, mesh->totpoly};
+ Span<MLoop> loops{mesh->mloop, mesh->totloop};
+ Array<EdgeMapEntry> edge_map = create_edge_map(polys, loops, mesh->totedge);
+
+ auto angle_fn = [edge_map, polys, loops, mesh](const int i) -> float {
+ if (edge_map[i].face_count != 2) {
+ return 0.0f;
+ }
+ const MPoly &mpoly_1 = polys[edge_map[i].face_index_1];
+ const MPoly &mpoly_2 = polys[edge_map[i].face_index_2];
+
+ /* Find the normals of the 2 polys. */
+ float3 poly_1_normal, poly_2_normal;
+ BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], mesh->mvert, poly_1_normal);
+ BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, poly_2_normal);
+
+ /* Find the centerpoint of the axis edge */
+ const float3 edge_centerpoint = (float3(mesh->mvert[mesh->medge[i].v1].co) +
+ float3(mesh->mvert[mesh->medge[i].v2].co)) *
+ 0.5f;
+
+ /* Get the centerpoint of poly 2 and subtract the edge centerpoint to get a tangent
+ * normal for poly 2. */
+ float3 poly_center_2;
+ BKE_mesh_calc_poly_center(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, poly_center_2);
+ const float3 poly_2_tangent = math::normalize(poly_center_2 - edge_centerpoint);
+ const float concavity = math::dot(poly_1_normal, poly_2_tangent);
+
+ /* Get the unsigned angle between the two polys */
+ const float angle = angle_normalized_v3v3(poly_1_normal, poly_2_normal);
+
+ if (angle == 0.0f || angle == 2.0f * M_PI || concavity < 0) {
+ return angle;
+ }
+ return -angle;
+ };
+
+ VArray<float> angles = VArray<float>::ForFunc(mesh->totedge, angle_fn);
+ return component.attribute_try_adapt_domain<float>(
+ std::move(angles), ATTR_DOMAIN_EDGE, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 68465416863;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const SignedAngleFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ if (params.output_is_required("Unsigned Angle")) {
+ Field<float> angle_field{std::make_shared<AngleFieldInput>()};
+ params.set_output("Unsigned Angle", std::move(angle_field));
+ }
+ if (params.output_is_required("Signed Angle")) {
+ Field<float> angle_field{std::make_shared<SignedAngleFieldInput>()};
+ params.set_output("Signed Angle", std::move(angle_field));
+ }
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_edge_angle_cc
+
+void register_node_type_geo_input_mesh_edge_angle()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_edge_angle_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_EDGE_ANGLE, "Edge Angle", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
new file mode 100644
index 00000000000..ddeb3ded511
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
@@ -0,0 +1,93 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_edge_neighbors_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Face Count"))
+ .field_source()
+ .description(N_("Number of faces that contain the edge"));
+}
+
+class EdgeNeighborCountFieldInput final : public GeometryFieldInput {
+ public:
+ EdgeNeighborCountFieldInput()
+ : GeometryFieldInput(CPPType::get<int>(), "Edge Neighbor Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ Array<int> face_count(mesh->totedge, 0);
+ for (const int i : IndexRange(mesh->totloop)) {
+ face_count[mesh->mloop[i].e]++;
+ }
+
+ return mesh_component.attribute_try_adapt_domain<int>(
+ VArray<int>::ForContainer(std::move(face_count)), ATTR_DOMAIN_EDGE, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 985671075;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const EdgeNeighborCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> neighbor_count_field{std::make_shared<EdgeNeighborCountFieldInput>()};
+ params.set_output("Face Count", std::move(neighbor_count_field));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_edge_neighbors_cc
+
+void register_node_type_geo_input_mesh_edge_neighbors()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_edge_neighbors_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, "Edge Neighbors", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
new file mode 100644
index 00000000000..f54c92fea7b
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
@@ -0,0 +1,186 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_edge_vertices_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Vertex Index 1"))
+ .field_source()
+ .description(N_("The index of the first vertex in the edge"));
+ b.add_output<decl::Int>(N_("Vertex Index 2"))
+ .field_source()
+ .description(N_("The index of the second vertex in the edge"));
+ b.add_output<decl::Vector>(N_("Position 1"))
+ .field_source()
+ .description(N_("The position of the first vertex in the edge"));
+ b.add_output<decl::Vector>(N_("Position 2"))
+ .field_source()
+ .description(N_("The position of the second vertex in the edge"));
+}
+
+enum VertexNumber { VERTEX_ONE, VERTEX_TWO };
+
+static VArray<int> construct_edge_vertices_gvarray(const MeshComponent &component,
+ const VertexNumber vertex,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+ if (domain == ATTR_DOMAIN_EDGE) {
+ if (vertex == VERTEX_ONE) {
+ return VArray<int>::ForFunc(mesh->totedge,
+ [mesh](const int i) -> int { return mesh->medge[i].v1; });
+ }
+ return VArray<int>::ForFunc(mesh->totedge,
+ [mesh](const int i) -> int { return mesh->medge[i].v2; });
+ }
+ return {};
+}
+
+class EdgeVerticesFieldInput final : public GeometryFieldInput {
+ private:
+ VertexNumber vertex_;
+
+ public:
+ EdgeVerticesFieldInput(VertexNumber vertex)
+ : GeometryFieldInput(CPPType::get<int>(), "Edge Vertices Field"), vertex_(vertex)
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_edge_vertices_gvarray(mesh_component, vertex_, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ return vertex_ == VERTEX_ONE ? 23847562893465 : 92384598734567;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const EdgeVerticesFieldInput *other_field = dynamic_cast<const EdgeVerticesFieldInput *>(
+ &other)) {
+ return vertex_ == other_field->vertex_;
+ }
+ return false;
+ }
+};
+
+static VArray<float3> construct_edge_positions_gvarray(const MeshComponent &component,
+ const VertexNumber vertex,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ if (vertex == VERTEX_ONE) {
+ return component.attribute_try_adapt_domain<float3>(
+ VArray<float3>::ForFunc(
+ mesh->totedge,
+ [mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v1].co); }),
+ ATTR_DOMAIN_EDGE,
+ domain);
+ }
+ return component.attribute_try_adapt_domain<float3>(
+ VArray<float3>::ForFunc(
+ mesh->totedge,
+ [mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v2].co); }),
+ ATTR_DOMAIN_EDGE,
+ domain);
+}
+
+class EdgePositionFieldInput final : public GeometryFieldInput {
+ private:
+ VertexNumber vertex_;
+
+ public:
+ EdgePositionFieldInput(VertexNumber vertex)
+ : GeometryFieldInput(CPPType::get<float3>(), "Edge Position Field"), vertex_(vertex)
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_edge_positions_gvarray(mesh_component, vertex_, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ return vertex_ == VERTEX_ONE ? 987456978362 : 374587679866;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const EdgePositionFieldInput *other_field = dynamic_cast<const EdgePositionFieldInput *>(
+ &other)) {
+ return vertex_ == other_field->vertex_;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> vertex_field_1{std::make_shared<EdgeVerticesFieldInput>(VERTEX_ONE)};
+ Field<int> vertex_field_2{std::make_shared<EdgeVerticesFieldInput>(VERTEX_TWO)};
+ Field<float3> position_field_1{std::make_shared<EdgePositionFieldInput>(VERTEX_ONE)};
+ Field<float3> position_field_2{std::make_shared<EdgePositionFieldInput>(VERTEX_TWO)};
+
+ params.set_output("Vertex Index 1", std::move(vertex_field_1));
+ params.set_output("Vertex Index 2", std::move(vertex_field_2));
+ params.set_output("Position 1", std::move(position_field_1));
+ params.set_output("Position 2", std::move(position_field_2));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_edge_vertices_cc
+
+void register_node_type_geo_input_mesh_edge_vertices()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_edge_vertices_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_EDGE_VERTICES, "Edge Vertices", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
new file mode 100644
index 00000000000..ef8adff48f1
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
@@ -0,0 +1,96 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_face_area_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Area"))
+ .field_source()
+ .description(N_("The surface area of each of the mesh's faces"));
+}
+
+static VArray<float> construct_face_area_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ auto area_fn = [mesh](const int i) -> float {
+ const MPoly *mp = &mesh->mpoly[i];
+ return BKE_mesh_calc_poly_area(mp, &mesh->mloop[mp->loopstart], mesh->mvert);
+ };
+
+ return component.attribute_try_adapt_domain<float>(
+ VArray<float>::ForFunc(mesh->totpoly, area_fn), ATTR_DOMAIN_FACE, domain);
+}
+
+class FaceAreaFieldInput final : public GeometryFieldInput {
+ public:
+ FaceAreaFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Face Area Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_face_area_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 1346334523;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const FaceAreaFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ params.set_output("Area", Field<float>(std::make_shared<FaceAreaFieldInput>()));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_face_area_cc
+
+void register_node_type_geo_input_mesh_face_area()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_face_area_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_FACE_AREA, "Face Area", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
new file mode 100644
index 00000000000..8d196e5f8dd
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
@@ -0,0 +1,158 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_face_neighbors_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Vertex Count"))
+ .field_source()
+ .description(N_("Number of edges or points in the face"));
+ b.add_output<decl::Int>(N_("Face Count"))
+ .field_source()
+ .description(N_("Number of faces which share an edge with the face"));
+}
+
+static VArray<int> construct_neighbor_count_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ Array<int> edge_count(mesh->totedge, 0);
+ for (const int i : IndexRange(mesh->totloop)) {
+ edge_count[mesh->mloop[i].e]++;
+ }
+
+ Array<int> poly_count(mesh->totpoly, 0);
+ for (const int poly_num : IndexRange(mesh->totpoly)) {
+ MPoly &poly = mesh->mpoly[poly_num];
+ for (const int loop_num : IndexRange(poly.loopstart, poly.totloop)) {
+ poly_count[poly_num] += edge_count[mesh->mloop[loop_num].e] - 1;
+ }
+ }
+
+ return component.attribute_try_adapt_domain<int>(
+ VArray<int>::ForContainer(std::move(poly_count)), ATTR_DOMAIN_FACE, domain);
+}
+
+class FaceNeighborCountFieldInput final : public GeometryFieldInput {
+ public:
+ FaceNeighborCountFieldInput()
+ : GeometryFieldInput(CPPType::get<int>(), "Face Neighbor Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_neighbor_count_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 823543774;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const FaceNeighborCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ return component.attribute_try_adapt_domain<int>(
+ VArray<int>::ForFunc(mesh->totpoly,
+ [mesh](const int i) -> float { return mesh->mpoly[i].totloop; }),
+ ATTR_DOMAIN_FACE,
+ domain);
+}
+
+class FaceVertexCountFieldInput final : public GeometryFieldInput {
+ public:
+ FaceVertexCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_vertex_count_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 236235463634;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const FaceVertexCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> vertex_count_field{std::make_shared<FaceVertexCountFieldInput>()};
+ Field<int> neighbor_count_field{std::make_shared<FaceNeighborCountFieldInput>()};
+ params.set_output("Vertex Count", std::move(vertex_count_field));
+ params.set_output("Face Count", std::move(neighbor_count_field));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_face_neighbors_cc
+
+void register_node_type_geo_input_mesh_face_neighbors()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_face_neighbors_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, "Face Neighbors", NODE_CLASS_INPUT);
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
new file mode 100644
index 00000000000..68bb93bbb64
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
@@ -0,0 +1,157 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "BLI_disjoint_set.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_island_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Island Index"))
+ .field_source()
+ .description(N_("Island indices are based on the order of the lowest-numbered vertex "
+ "contained in each island"));
+ b.add_output<decl::Int>(N_("Island Count"))
+ .field_source()
+ .description(N_("The total number of mesh islands"));
+}
+
+class IslandFieldInput final : public GeometryFieldInput {
+ public:
+ IslandFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Island Index")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ return {};
+ }
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ DisjointSet islands(mesh->totvert);
+ for (const int i : IndexRange(mesh->totedge)) {
+ islands.join(mesh->medge[i].v1, mesh->medge[i].v2);
+ }
+
+ Array<int> output(mesh->totvert);
+ VectorSet<int> ordered_roots;
+ for (const int i : IndexRange(mesh->totvert)) {
+ const int64_t root = islands.find_root(i);
+ output[i] = ordered_roots.index_of_or_add(root);
+ }
+
+ return mesh_component.attribute_try_adapt_domain<int>(
+ VArray<int>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 635467354;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const IslandFieldInput *>(&other) != nullptr;
+ }
+};
+
+class IslandCountFieldInput final : public GeometryFieldInput {
+ public:
+ IslandCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Island Count")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ return {};
+ }
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ DisjointSet islands(mesh->totvert);
+ for (const int i : IndexRange(mesh->totedge)) {
+ islands.join(mesh->medge[i].v1, mesh->medge[i].v2);
+ }
+
+ Set<int> island_list;
+ for (const int i_vert : IndexRange(mesh->totvert)) {
+ const int64_t root = islands.find_root(i_vert);
+ island_list.add(root);
+ }
+
+ return VArray<int>::ForSingle(island_list.size(),
+ mesh_component.attribute_domain_size(domain));
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random hash. */
+ return 45634572457;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const IslandCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ if (params.output_is_required("Island Index")) {
+ Field<int> field{std::make_shared<IslandFieldInput>()};
+ params.set_output("Island Index", std::move(field));
+ }
+ if (params.output_is_required("Island Count")) {
+ Field<int> field{std::make_shared<IslandCountFieldInput>()};
+ params.set_output("Island Count", std::move(field));
+ }
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_island_cc
+
+void register_node_type_geo_input_mesh_island()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_island_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_ISLAND, "Mesh Island", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
new file mode 100644
index 00000000000..7d79164634d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
@@ -0,0 +1,155 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_vertex_neighbors_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Vertex Count"))
+ .field_source()
+ .description(N_("Vertex count and edge count are equal"));
+ b.add_output<decl::Int>(N_("Face Count"))
+ .field_source()
+ .description(N_("Number of faces that contain the vertex"));
+}
+
+static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ if (domain == ATTR_DOMAIN_POINT) {
+ Array<int> vertices(mesh->totvert, 0);
+ for (const int i : IndexRange(mesh->totedge)) {
+ vertices[mesh->medge[i].v1]++;
+ vertices[mesh->medge[i].v2]++;
+ }
+ return VArray<int>::ForContainer(std::move(vertices));
+ }
+ return {};
+}
+
+class VertexCountFieldInput final : public GeometryFieldInput {
+ public:
+ VertexCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_vertex_count_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 23574528465;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const VertexCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static VArray<int> construct_face_count_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ if (domain == ATTR_DOMAIN_POINT) {
+ Array<int> vertices(mesh->totvert, 0);
+ for (const int i : IndexRange(mesh->totloop)) {
+ int vertex = mesh->mloop[i].v;
+ vertices[vertex]++;
+ }
+ return VArray<int>::ForContainer(std::move(vertices));
+ }
+ return {};
+}
+
+class VertexFaceCountFieldInput final : public GeometryFieldInput {
+ public:
+ VertexFaceCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Face Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_face_count_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 3462374322;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const VertexFaceCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> vertex_field{std::make_shared<VertexCountFieldInput>()};
+ Field<int> face_field{std::make_shared<VertexFaceCountFieldInput>()};
+
+ params.set_output("Vertex Count", std::move(vertex_field));
+ params.set_output("Face Count", std::move(face_field));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_vertex_neighbors_cc
+
+void register_node_type_geo_input_mesh_vertex_neighbors()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_vertex_neighbors_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, "Vertex Neighbors", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
index 5a2495afb9e..120ae0e9bd1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
@@ -24,280 +24,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_normal_cc {
-static void geo_node_input_normal_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Vector>("Normal").field_source();
+ b.add_output<decl::Vector>(N_("Normal")).field_source();
}
-static GVArrayPtr mesh_face_normals(const Mesh &mesh,
- const Span<MVert> verts,
- const Span<MPoly> polys,
- const Span<MLoop> loops,
- const IndexMask mask)
+static void node_geo_exec(GeoNodeExecParams params)
{
- /* Use existing normals to avoid unnecessarily recalculating them, if possible. */
- if (!(mesh.runtime.cd_dirty_poly & CD_MASK_NORMAL) &&
- CustomData_has_layer(&mesh.pdata, CD_NORMAL)) {
- const void *data = CustomData_get_layer(&mesh.pdata, CD_NORMAL);
-
- return std::make_unique<fn::GVArray_For_Span<float3>>(
- Span<float3>((const float3 *)data, polys.size()));
- }
-
- auto normal_fn = [verts, polys, loops](const int i) -> float3 {
- float3 normal;
- const MPoly &poly = polys[i];
- BKE_mesh_calc_poly_normal(&poly, &loops[poly.loopstart], verts.data(), normal);
- return normal;
- };
-
- return std::make_unique<
- fn::GVArray_For_EmbeddedVArray<float3, VArray_For_Func<float3, decltype(normal_fn)>>>(
- mask.min_array_size(), mask.min_array_size(), normal_fn);
-}
-
-static GVArrayPtr mesh_vertex_normals(const Mesh &mesh,
- const Span<MVert> verts,
- const Span<MPoly> polys,
- const Span<MLoop> loops,
- const IndexMask mask)
-{
- /* Use existing normals to avoid unnecessarily recalculating them, if possible. */
- if (!(mesh.runtime.cd_dirty_vert & CD_MASK_NORMAL) &&
- CustomData_has_layer(&mesh.vdata, CD_NORMAL)) {
- const void *data = CustomData_get_layer(&mesh.pdata, CD_NORMAL);
-
- return std::make_unique<fn::GVArray_For_Span<float3>>(
- Span<float3>((const float3 *)data, mesh.totvert));
- }
-
- /* If the normals are dirty, they must be recalculated for the output of this node's field
- * source. Ideally vertex normals could be calculated lazily on a const mesh, but that's not
- * possible at the moment, so we take ownership of the results. Sadly we must also create a copy
- * of MVert to use the mesh normals API. This can be improved by adding mutex-protected lazy
- * calculation of normals on meshes.
- *
- * Use mask.min_array_size() to avoid calculating a final chunk of data if possible. */
- Array<MVert> temp_verts(verts);
- Array<float3> normals(verts.size()); /* Use full size for accumulation from faces. */
- BKE_mesh_calc_normals_poly_and_vertex(temp_verts.data(),
- mask.min_array_size(),
- loops.data(),
- loops.size(),
- polys.data(),
- polys.size(),
- nullptr,
- (float(*)[3])normals.data());
-
- return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals));
-}
-
-static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_component,
- const Mesh &mesh,
- const IndexMask mask,
- const AttributeDomain domain,
- ResourceScope &scope)
-{
- Span<MVert> verts{mesh.mvert, mesh.totvert};
- Span<MEdge> edges{mesh.medge, mesh.totedge};
- Span<MPoly> polys{mesh.mpoly, mesh.totpoly};
- Span<MLoop> loops{mesh.mloop, mesh.totloop};
-
- switch (domain) {
- case ATTR_DOMAIN_FACE: {
- return scope.add_value(mesh_face_normals(mesh, verts, polys, loops, mask)).get();
- }
- case ATTR_DOMAIN_POINT: {
- return scope.add_value(mesh_vertex_normals(mesh, verts, polys, loops, mask)).get();
- }
- case ATTR_DOMAIN_EDGE: {
- /* In this case, start with vertex normals and convert to the edge domain, since the
- * conversion from edges to vertices is very simple. Use the full mask since the edges
- * might use the vertex normal from any index. */
- GVArrayPtr vert_normals = mesh_vertex_normals(
- mesh, verts, polys, loops, IndexRange(verts.size()));
- Span<float3> vert_normals_span = vert_normals->get_internal_span().typed<float3>();
- Array<float3> edge_normals(mask.min_array_size());
-
- /* Use "manual" domain interpolation instead of the GeometryComponent API to avoid
- * calculating unnecessary values and to allow normalizing the result much more simply. */
- for (const int i : mask) {
- const MEdge &edge = edges[i];
- edge_normals[i] = float3::interpolate(
- vert_normals_span[edge.v1], vert_normals_span[edge.v2], 0.5f)
- .normalized();
- }
-
- return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>(
- std::move(edge_normals));
- }
- case ATTR_DOMAIN_CORNER: {
- /* The normals on corners are just the mesh's face normals, so start with the face normal
- * array and copy the face normal for each of its corners. */
- GVArrayPtr face_normals = mesh_face_normals(
- mesh, verts, polys, loops, IndexRange(polys.size()));
-
- /* In this case using the mesh component's generic domain interpolation is fine, the data
- * will still be normalized, since the face normal is just copied to every corner. */
- GVArrayPtr loop_normals = mesh_component.attribute_try_adapt_domain(
- std::move(face_normals), ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER);
- return scope.add_value(std::move(loop_normals)).get();
- }
- default:
- return nullptr;
- }
-}
-
-static void calculate_bezier_normals(const BezierSpline &spline, MutableSpan<float3> normals)
-{
- Span<int> offsets = spline.control_point_offsets();
- Span<float3> evaluated_normals = spline.evaluated_normals();
- for (const int i : IndexRange(spline.size())) {
- normals[i] = evaluated_normals[offsets[i]];
- }
-}
-
-static void calculate_poly_normals(const PolySpline &spline, MutableSpan<float3> normals)
-{
- normals.copy_from(spline.evaluated_normals());
-}
-
-/**
- * Because NURBS control points are not necessarily on the path, the normal at the control points
- * is not well defined, so create a temporary poly spline to find the normals. This requires extra
- * copying currently, but may be more efficient in the future if attributes have some form of CoW.
- */
-static void calculate_nurbs_normals(const NURBSpline &spline, MutableSpan<float3> normals)
-{
- PolySpline poly_spline;
- poly_spline.resize(spline.size());
- poly_spline.positions().copy_from(spline.positions());
- normals.copy_from(poly_spline.evaluated_normals());
-}
-
-static Array<float3> curve_normal_point_domain(const CurveEval &curve)
-{
- Span<SplinePtr> splines = curve.splines();
- Array<int> offsets = curve.control_point_offsets();
- const int total_size = offsets.last();
- Array<float3> normals(total_size);
-
- threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
- for (const int i : range) {
- const Spline &spline = *splines[i];
- MutableSpan spline_normals{normals.as_mutable_span().slice(offsets[i], spline.size())};
- switch (splines[i]->type()) {
- case Spline::Type::Bezier:
- calculate_bezier_normals(static_cast<const BezierSpline &>(spline), spline_normals);
- break;
- case Spline::Type::Poly:
- calculate_poly_normals(static_cast<const PolySpline &>(spline), spline_normals);
- break;
- case Spline::Type::NURBS:
- calculate_nurbs_normals(static_cast<const NURBSpline &>(spline), spline_normals);
- break;
- }
- }
- });
- return normals;
-}
-
-static const GVArray *construct_curve_normal_gvarray(const CurveComponent &component,
- const AttributeDomain domain,
- ResourceScope &scope)
-{
- const CurveEval *curve = component.get_for_read();
- if (curve == nullptr) {
- return nullptr;
- }
-
- if (domain == ATTR_DOMAIN_POINT) {
- const Span<SplinePtr> splines = curve->splines();
-
- /* Use a reference to evaluated normals if possible to avoid an allocation and a copy.
- * This is only possible when there is only one poly spline. */
- if (splines.size() == 1 && splines.first()->type() == Spline::Type::Poly) {
- const PolySpline &spline = static_cast<PolySpline &>(*splines.first());
- return &scope.construct<fn::GVArray_For_Span<float3>>(spline.evaluated_normals());
- }
-
- Array<float3> normals = curve_normal_point_domain(*curve);
- return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals));
- }
-
- if (domain == ATTR_DOMAIN_CURVE) {
- Array<float3> point_normals = curve_normal_point_domain(*curve);
- GVArrayPtr gvarray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(
- std::move(point_normals));
- GVArrayPtr spline_normals = component.attribute_try_adapt_domain(
- std::move(gvarray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
- return scope.add_value(std::move(spline_normals)).get();
- }
-
- return nullptr;
-}
-
-class NormalFieldInput final : public fn::FieldInput {
- public:
- NormalFieldInput() : fn::FieldInput(CPPType::get<float3>(), "Normal")
- {
- }
-
- const GVArray *get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const final
- {
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
-
- if (component.type() == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return nullptr;
- }
-
- return construct_mesh_normals_gvarray(mesh_component, *mesh, mask, domain, scope);
- }
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_curve_normal_gvarray(curve_component, domain, scope);
- }
- }
- return nullptr;
- }
-
- uint64_t hash() const override
- {
- /* Some random constant hash. */
- return 669605641;
- }
-
- bool is_equal_to(const fn::FieldNode &other) const override
- {
- return dynamic_cast<const NormalFieldInput *>(&other) != nullptr;
- }
-};
-
-static void geo_node_input_normal_exec(GeoNodeExecParams params)
-{
- Field<float3> normal_field{std::make_shared<NormalFieldInput>()};
+ Field<float3> normal_field{std::make_shared<bke::NormalFieldInput>()};
params.set_output("Normal", std::move(normal_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_normal_cc
void register_node_type_geo_input_normal()
{
+ namespace file_ns = blender::nodes::node_geo_input_normal_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_NORMAL, "Normal", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_normal_exec;
- ntype.declare = blender::nodes::geo_node_input_normal_declare;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_NORMAL, "Normal", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
index 44874259e20..beb528d2fd8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_position_cc {
-static void geo_node_input_position_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Vector>("Position").field_source();
+ b.add_output<decl::Vector>(N_("Position")).field_source();
}
-static void geo_node_input_position_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float3> position_field{AttributeFieldInput::Create<float3>("position")};
params.set_output("Position", std::move(position_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_position_cc
void register_node_type_geo_input_position()
{
+ namespace file_ns = blender::nodes::node_geo_input_position_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_POSITION, "Position", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_position_exec;
- ntype.declare = blender::nodes::geo_node_input_position_declare;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_POSITION, "Position", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
new file mode 100644
index 00000000000..c7777da08c6
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
@@ -0,0 +1,44 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_radius_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).field_source();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<float> radius_field = AttributeFieldInput::Create<float>("radius");
+ params.set_output("Radius", std::move(radius_field));
+}
+
+} // namespace blender::nodes::node_geo_input_radius_cc
+
+void register_node_type_geo_input_radius()
+{
+ namespace file_ns = blender::nodes::node_geo_input_radius_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_RADIUS, "Radius", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
new file mode 100644
index 00000000000..4ed65e99a1c
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
@@ -0,0 +1,50 @@
+/*
+ * 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 "BKE_scene.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_scene_time_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Seconds"));
+ b.add_output<decl::Float>(N_("Frame"));
+}
+
+static void node_exec(GeoNodeExecParams params)
+{
+ const Scene *scene = DEG_get_input_scene(params.depsgraph());
+ const float scene_ctime = BKE_scene_ctime_get(scene);
+ const double frame_rate = (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base);
+ params.set_output("Seconds", float(scene_ctime / frame_rate));
+ params.set_output("Frame", scene_ctime);
+}
+
+} // namespace blender::nodes::node_geo_input_scene_time_cc
+
+void register_node_type_geo_input_scene_time()
+{
+ static bNodeType ntype;
+ namespace file_ns = blender::nodes::node_geo_input_scene_time_cc;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_SCENE_TIME, "Scene Time", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
new file mode 100644
index 00000000000..b27ab097223
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
@@ -0,0 +1,44 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_shade_smooth_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Bool>(N_("Smooth")).field_source();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<bool> shade_smooth_field = AttributeFieldInput::Create<bool>("shade_smooth");
+ params.set_output("Smooth", std::move(shade_smooth_field));
+}
+
+} // namespace blender::nodes::node_geo_input_shade_smooth_cc
+
+void register_node_type_geo_input_shade_smooth()
+{
+ namespace file_ns = blender::nodes::node_geo_input_shade_smooth_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_SHADE_SMOOTH, "Is Shade Smooth", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
new file mode 100644
index 00000000000..2db00a1ae68
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
@@ -0,0 +1,44 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_spline_cyclic_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Bool>(N_("Cyclic")).field_source();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<bool> cyclic_field = AttributeFieldInput::Create<bool>("cyclic");
+ params.set_output("Cyclic", std::move(cyclic_field));
+}
+
+} // namespace blender::nodes::node_geo_input_spline_cyclic_cc
+
+void register_node_type_geo_input_spline_cyclic()
+{
+ namespace file_ns = blender::nodes::node_geo_input_spline_cyclic_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_CYCLIC, "Is Spline Cyclic", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
new file mode 100644
index 00000000000..b8c8ce840eb
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
@@ -0,0 +1,163 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+#include "BKE_spline.hh"
+
+namespace blender::nodes::node_geo_input_spline_length_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Length")).field_source();
+ b.add_output<decl::Int>(N_("Point Count")).field_source();
+}
+
+/* --------------------------------------------------------------------
+ * Spline Length
+ */
+
+static VArray<float> construct_spline_length_gvarray(const CurveComponent &component,
+ const AttributeDomain domain)
+{
+ const CurveEval *curve = component.get_for_read();
+ if (curve == nullptr) {
+ return {};
+ }
+
+ Span<SplinePtr> splines = curve->splines();
+ auto length_fn = [splines](int i) { return splines[i]->length(); };
+
+ if (domain == ATTR_DOMAIN_CURVE) {
+ return VArray<float>::ForFunc(splines.size(), length_fn);
+ }
+ if (domain == ATTR_DOMAIN_POINT) {
+ VArray<float> length = VArray<float>::ForFunc(splines.size(), length_fn);
+ return component.attribute_try_adapt_domain<float>(
+ std::move(length), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
+ }
+
+ return {};
+}
+
+class SplineLengthFieldInput final : public GeometryFieldInput {
+ public:
+ SplineLengthFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Spline Length node")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return construct_spline_length_gvarray(curve_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 3549623580;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const SplineLengthFieldInput *>(&other) != nullptr;
+ }
+};
+
+/* --------------------------------------------------------------------
+ * Spline Count
+ */
+
+static VArray<int> construct_spline_count_gvarray(const CurveComponent &component,
+ const AttributeDomain domain)
+{
+ const CurveEval *curve = component.get_for_read();
+ if (curve == nullptr) {
+ return {};
+ }
+
+ Span<SplinePtr> splines = curve->splines();
+ auto count_fn = [splines](int i) { return splines[i]->size(); };
+
+ if (domain == ATTR_DOMAIN_CURVE) {
+ return VArray<int>::ForFunc(splines.size(), count_fn);
+ }
+ if (domain == ATTR_DOMAIN_POINT) {
+ VArray<int> count = VArray<int>::ForFunc(splines.size(), count_fn);
+ return component.attribute_try_adapt_domain<int>(
+ std::move(count), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
+ }
+
+ return {};
+}
+
+class SplineCountFieldInput final : public GeometryFieldInput {
+ public:
+ SplineCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Spline Point Count")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return construct_spline_count_gvarray(curve_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 456364322625;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const SplineCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<float> spline_length_field{std::make_shared<SplineLengthFieldInput>()};
+ Field<int> spline_count_field{std::make_shared<SplineCountFieldInput>()};
+
+ params.set_output("Length", std::move(spline_length_field));
+ params.set_output("Point Count", std::move(spline_count_field));
+}
+
+} // namespace blender::nodes::node_geo_input_spline_length_cc
+
+void register_node_type_geo_input_spline_length()
+{
+ namespace file_ns = blender::nodes::node_geo_input_spline_length_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_LENGTH, "Spline Length", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
new file mode 100644
index 00000000000..d79f2ffd64d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
@@ -0,0 +1,45 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_spline_resolution_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Resolution")).field_source();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> resolution_field = AttributeFieldInput::Create<int>("resolution");
+ params.set_output("Resolution", std::move(resolution_field));
+}
+
+} // namespace blender::nodes::node_geo_input_spline_resolution_cc
+
+void register_node_type_geo_input_spline_resolution()
+{
+ namespace file_ns = blender::nodes::node_geo_input_spline_resolution_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_SPLINE_RESOLUTION, "Spline Resolution", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
index d690642373a..f80fdfbf334 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
@@ -20,11 +20,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_tangent_cc {
-static void geo_node_input_tangent_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Vector>("Tangent").field_source();
+ b.add_output<decl::Vector>(N_("Tangent")).field_source();
}
static void calculate_bezier_tangents(const BezierSpline &spline, MutableSpan<float3> tangents)
@@ -84,9 +84,8 @@ static Array<float3> curve_tangent_point_domain(const CurveEval &curve)
return tangents;
}
-static const GVArray *construct_curve_tangent_gvarray(const CurveComponent &component,
- const AttributeDomain domain,
- ResourceScope &scope)
+static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component,
+ const AttributeDomain domain)
{
const CurveEval *curve = component.get_for_read();
if (curve == nullptr) {
@@ -100,47 +99,40 @@ static const GVArray *construct_curve_tangent_gvarray(const CurveComponent &comp
* This is only possible when there is only one poly spline. */
if (splines.size() == 1 && splines.first()->type() == Spline::Type::Poly) {
const PolySpline &spline = static_cast<PolySpline &>(*splines.first());
- return &scope.construct<fn::GVArray_For_Span<float3>>(spline.evaluated_tangents());
+ return VArray<float3>::ForSpan(spline.evaluated_tangents());
}
Array<float3> tangents = curve_tangent_point_domain(*curve);
- return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(tangents));
+ return VArray<float3>::ForContainer(std::move(tangents));
}
if (domain == ATTR_DOMAIN_CURVE) {
Array<float3> point_tangents = curve_tangent_point_domain(*curve);
- GVArrayPtr gvarray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(
- std::move(point_tangents));
- GVArrayPtr spline_tangents = component.attribute_try_adapt_domain(
- std::move(gvarray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
- return scope.add_value(std::move(spline_tangents)).get();
+ return component.attribute_try_adapt_domain<float3>(
+ VArray<float3>::ForContainer(std::move(point_tangents)),
+ ATTR_DOMAIN_POINT,
+ ATTR_DOMAIN_CURVE);
}
return nullptr;
}
-class TangentFieldInput final : public fn::FieldInput {
+class TangentFieldInput final : public GeometryFieldInput {
public:
- TangentFieldInput() : fn::FieldInput(CPPType::get<float3>(), "Tangent")
+ TangentFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Tangent node")
{
+ category_ = Category::Generated;
}
- const GVArray *get_varray_for_context(const fn::FieldContext &context,
- IndexMask UNUSED(mask),
- ResourceScope &scope) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
-
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_curve_tangent_gvarray(curve_component, domain, scope);
- }
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return construct_curve_tangent_gvarray(curve_component, domain);
}
- return nullptr;
+ return {};
}
uint64_t hash() const override
@@ -155,20 +147,22 @@ class TangentFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_input_tangent_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float3> tangent_field{std::make_shared<TangentFieldInput>()};
params.set_output("Tangent", std::move(tangent_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_tangent_cc
void register_node_type_geo_input_tangent()
{
+ namespace file_ns = blender::nodes::node_geo_input_tangent_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_TANGENT, "Curve Tangent", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_tangent_exec;
- ntype.declare = blender::nodes::geo_node_input_tangent_declare;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_TANGENT, "Curve Tangent", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
index 8c0c0763be8..71256a7f781 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
@@ -22,72 +22,80 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "BKE_attribute_math.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_instance_on_points_cc {
-static void geo_node_instance_on_points_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Points").description("Points to instance on");
- b.add_input<decl::Geometry>("Instance").description("Geometry that is instanced on the points");
- b.add_input<decl::Bool>("Pick Instance")
+ b.add_input<decl::Geometry>(N_("Points")).description(N_("Points to instance on"));
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
+ b.add_input<decl::Geometry>(N_("Instance"))
+ .description(N_("Geometry that is instanced on the points"));
+ b.add_input<decl::Bool>(N_("Pick Instance"))
.supports_field()
- .description("Place different instances on different points");
- b.add_input<decl::Int>("Instance Index")
+ .description(N_("Place different instances on different points"));
+ b.add_input<decl::Int>(N_("Instance Index"))
.implicit_field()
- .description(
+ .description(N_(
"Index of the instance that used for each point. This is only used when Pick Instances "
- "is on. By default the point index is used");
- b.add_input<decl::Vector>("Rotation")
+ "is on. By default the point index is used"));
+ b.add_input<decl::Vector>(N_("Rotation"))
.subtype(PROP_EULER)
.supports_field()
- .description("Rotation of the instances");
- b.add_input<decl::Vector>("Scale")
+ .description(N_("Rotation of the instances"));
+ b.add_input<decl::Vector>(N_("Scale"))
.default_value({1.0f, 1.0f, 1.0f})
+ .subtype(PROP_XYZ)
.supports_field()
- .description("Scale of the instances");
- b.add_input<decl::Int>("Stable ID")
- .supports_field()
- .description(
- "ID for every instance that is used to identify it over time even when the number of "
- "instances changes. Used for example for motion blur");
+ .description(N_("Scale of the instances"));
- b.add_output<decl::Geometry>("Instances");
+ b.add_output<decl::Geometry>(N_("Instances"));
}
-static void add_instances_from_component(InstancesComponent &dst_component,
- const GeometryComponent &src_component,
- const GeometrySet &instance,
- const GeoNodeExecParams &params)
+static void add_instances_from_component(
+ InstancesComponent &dst_component,
+ const GeometryComponent &src_component,
+ const GeometrySet &instance,
+ const GeoNodeExecParams &params,
+ const Map<AttributeIDRef, AttributeKind> &attributes_to_propagate)
{
const AttributeDomain domain = ATTR_DOMAIN_POINT;
const int domain_size = src_component.attribute_domain_size(domain);
+ VArray<bool> pick_instance;
+ VArray<int> indices;
+ VArray<float3> rotations;
+ VArray<float3> scales;
+
+ GeometryComponentFieldContext field_context{src_component, domain};
+ const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ /* The evaluator could use the component's stable IDs as a destination directly, but only the
+ * selected indices should be copied. */
+ evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance);
+ evaluator.add(params.get_input<Field<int>>("Instance Index"), &indices);
+ evaluator.add(params.get_input<Field<float3>>("Rotation"), &rotations);
+ evaluator.add(params.get_input<Field<float3>>("Scale"), &scales);
+ evaluator.evaluate();
+
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+
/* The initial size of the component might be non-zero when this function is called for multiple
* component types. */
const int start_len = dst_component.instances_amount();
- dst_component.resize(start_len + domain_size);
+ const int select_len = selection.index_range().size();
+ dst_component.resize(start_len + select_len);
+
MutableSpan<int> dst_handles = dst_component.instance_reference_handles().slice(start_len,
- domain_size);
+ select_len);
MutableSpan<float4x4> dst_transforms = dst_component.instance_transforms().slice(start_len,
- domain_size);
- MutableSpan<int> dst_stable_ids = dst_component.instance_ids().slice(start_len, domain_size);
+ select_len);
- GeometryComponentFieldContext field_context{src_component, domain};
- FieldEvaluator field_evaluator{field_context, domain_size};
-
- const VArray<bool> *pick_instance = nullptr;
- const VArray<int> *indices = nullptr;
- const VArray<float3> *rotations = nullptr;
- const VArray<float3> *scales = nullptr;
- field_evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance);
- field_evaluator.add(params.get_input<Field<int>>("Instance Index"), &indices);
- field_evaluator.add(params.get_input<Field<float3>>("Rotation"), &rotations);
- field_evaluator.add(params.get_input<Field<float3>>("Scale"), &scales);
- field_evaluator.add_with_destination(params.get_input<Field<int>>("Stable ID"), dst_stable_ids);
- field_evaluator.evaluate();
-
- GVArray_Typed<float3> positions = src_component.attribute_get_for_read<float3>(
+ VArray<float3> positions = src_component.attribute_get_for_read<float3>(
"position", domain, {0, 0, 0});
const InstancesComponent *src_instances = instance.get_component_for_read<InstancesComponent>();
@@ -96,7 +104,7 @@ static void add_instances_from_component(InstancesComponent &dst_component,
Array<int> handle_mapping;
/* Only fill #handle_mapping when it may be used below. */
if (src_instances != nullptr &&
- (!pick_instance->is_single() || pick_instance->get_internal_single())) {
+ (!pick_instance.is_single() || pick_instance.get_internal_single())) {
Span<InstanceReference> src_references = src_instances->references();
handle_mapping.reinitialize(src_references.size());
for (const int src_instance_handle : src_references.index_range()) {
@@ -110,23 +118,24 @@ static void add_instances_from_component(InstancesComponent &dst_component,
/* Add this reference last, because it is the most likely one to be removed later on. */
const int empty_reference_handle = dst_component.add_reference(InstanceReference());
- threading::parallel_for(IndexRange(domain_size), 1024, [&](IndexRange range) {
- for (const int i : range) {
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) {
+ for (const int range_i : selection_range) {
+ const int64_t i = selection[range_i];
+
/* Compute base transform for every instances. */
- float4x4 &dst_transform = dst_transforms[i];
- dst_transform = float4x4::from_loc_eul_scale(
- positions[i], rotations->get(i), scales->get(i));
+ float4x4 &dst_transform = dst_transforms[range_i];
+ dst_transform = float4x4::from_loc_eul_scale(positions[i], rotations[i], scales[i]);
/* Reference that will be used by this new instance. */
int dst_handle = empty_reference_handle;
- const bool use_individual_instance = pick_instance->get(i);
+ const bool use_individual_instance = pick_instance[i];
if (use_individual_instance) {
if (src_instances != nullptr) {
const int src_instances_amount = src_instances->instances_amount();
- const int original_index = indices->get(i);
- /* Use #mod_i instead of `%` to get the desirable wrap around behavior where -1 refers to
- * the last element. */
+ const int original_index = indices[i];
+ /* Use #mod_i instead of `%` to get the desirable wrap around behavior where -1
+ * refers to the last element. */
const int index = mod_i(original_index, std::max(src_instances_amount, 1));
if (index < src_instances_amount) {
/* Get the reference to the source instance. */
@@ -144,12 +153,12 @@ static void add_instances_from_component(InstancesComponent &dst_component,
dst_handle = full_instance_handle;
}
/* Set properties of new instance. */
- dst_handles[i] = dst_handle;
+ dst_handles[range_i] = dst_handle;
}
});
- if (pick_instance->is_single()) {
- if (pick_instance->get_internal_single()) {
+ if (pick_instance.is_single()) {
+ if (pick_instance.get_internal_single()) {
if (instance.has_realized_data()) {
params.error_message_add(
NodeWarningType::Info,
@@ -157,9 +166,40 @@ static void add_instances_from_component(InstancesComponent &dst_component,
}
}
}
+
+ bke::CustomDataAttributes &instance_attributes = dst_component.attributes();
+ for (const auto item : attributes_to_propagate.items()) {
+ const AttributeIDRef &attribute_id = item.key;
+ const AttributeKind attribute_kind = item.value;
+
+ const GVArray src_attribute = src_component.attribute_get_for_read(
+ attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type);
+ BLI_assert(src_attribute);
+ std::optional<GMutableSpan> dst_attribute_opt = instance_attributes.get_for_write(
+ attribute_id);
+ if (!dst_attribute_opt) {
+ if (!instance_attributes.create(attribute_id, attribute_kind.data_type)) {
+ continue;
+ }
+ dst_attribute_opt = instance_attributes.get_for_write(attribute_id);
+ }
+ BLI_assert(dst_attribute_opt);
+ const GMutableSpan dst_attribute = dst_attribute_opt->slice(start_len, select_len);
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) {
+ attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray<T> src = src_attribute.typed<T>();
+ MutableSpan<T> dst = dst_attribute.typed<T>();
+ for (const int range_i : selection_range) {
+ const int i = selection[range_i];
+ dst[range_i] = src[i];
+ }
+ });
+ });
+ }
}
-static void geo_node_instance_on_points_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
GeometrySet instance = params.get_input<GeometrySet>("Instance");
@@ -168,40 +208,59 @@ static void geo_node_instance_on_points_exec(GeoNodeExecParams params)
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ geometry_set.gather_attributes_for_propagation(
+ {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE},
+ GEO_COMPONENT_TYPE_INSTANCES,
+ false,
+ attributes_to_propagate);
+ attributes_to_propagate.remove("position");
+
if (geometry_set.has<MeshComponent>()) {
- add_instances_from_component(
- instances, *geometry_set.get_component_for_read<MeshComponent>(), instance, params);
- geometry_set.remove(GEO_COMPONENT_TYPE_MESH);
+ add_instances_from_component(instances,
+ *geometry_set.get_component_for_read<MeshComponent>(),
+ instance,
+ params,
+ attributes_to_propagate);
}
if (geometry_set.has<PointCloudComponent>()) {
add_instances_from_component(instances,
*geometry_set.get_component_for_read<PointCloudComponent>(),
instance,
- params);
- geometry_set.remove(GEO_COMPONENT_TYPE_POINT_CLOUD);
+ params,
+ attributes_to_propagate);
}
if (geometry_set.has<CurveComponent>()) {
- add_instances_from_component(
- instances, *geometry_set.get_component_for_read<CurveComponent>(), instance, params);
- geometry_set.remove(GEO_COMPONENT_TYPE_CURVE);
+ add_instances_from_component(instances,
+ *geometry_set.get_component_for_read<CurveComponent>(),
+ instance,
+ params,
+ attributes_to_propagate);
}
- /* Unused references may have been added above. Remove those now so that other nodes don't
- * process them needlessly. */
- instances.remove_unused_references();
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
});
+ /* Unused references may have been added above. Remove those now so that other nodes don't
+ * process them needlessly.
+ * This should eventually be moved into the loop above, but currently this is quite tricky
+ * because it might remove references that the loop still wants to iterate over. */
+ InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ instances.remove_unused_references();
+
params.set_output("Instances", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_instance_on_points_cc
void register_node_type_geo_instance_on_points()
{
+ namespace file_ns = blender::nodes::node_geo_instance_on_points_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INSTANCE_ON_POINTS, "Instance on Points", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_instance_on_points_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_instance_on_points_exec;
+ &ntype, GEO_NODE_INSTANCE_ON_POINTS, "Instance on Points", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
new file mode 100644
index 00000000000..f9beed956bb
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
@@ -0,0 +1,137 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "DNA_pointcloud_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_pointcloud.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_instances_to_points_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Instances")).only_instances();
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Position")).implicit_field();
+ b.add_input<decl::Float>(N_("Radius"))
+ .default_value(0.05f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .supports_field();
+ b.add_output<decl::Geometry>(N_("Points"));
+}
+
+template<typename T>
+static void copy_attribute_to_points(const VArray<T> &src,
+ const IndexMask mask,
+ MutableSpan<T> dst)
+{
+ for (const int i : mask.index_range()) {
+ dst[i] = src[mask[i]];
+ }
+}
+
+static void convert_instances_to_points(GeometrySet &geometry_set,
+ Field<float3> position_field,
+ Field<float> radius_field,
+ const Field<bool> selection_field)
+{
+ const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>();
+
+ GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
+ const int domain_size = instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE);
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(std::move(selection_field));
+ evaluator.add(std::move(position_field));
+ evaluator.add(std::move(radius_field));
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ if (selection.is_empty()) {
+ return;
+ }
+
+ PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
+ geometry_set.replace_pointcloud(pointcloud);
+
+ PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>();
+
+ const VArray<float3> &positions = evaluator.get_evaluated<float3>(0);
+ copy_attribute_to_points(positions, selection, {(float3 *)pointcloud->co, pointcloud->totpoint});
+ const VArray<float> &radii = evaluator.get_evaluated<float>(1);
+ copy_attribute_to_points(radii, selection, {pointcloud->radius, pointcloud->totpoint});
+
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ geometry_set.gather_attributes_for_propagation({GEO_COMPONENT_TYPE_INSTANCES},
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ false,
+ attributes_to_propagate);
+ /* These two attributes are added by the implicit inputs above. */
+ attributes_to_propagate.remove("position");
+ attributes_to_propagate.remove("radius");
+
+ for (const auto item : attributes_to_propagate.items()) {
+ const AttributeIDRef &attribute_id = item.key;
+ const AttributeKind attribute_kind = item.value;
+
+ const GVArray src = instances.attribute_get_for_read(
+ attribute_id, ATTR_DOMAIN_INSTANCE, attribute_kind.data_type);
+ BLI_assert(src);
+ OutputAttribute dst = points.attribute_try_get_for_output_only(
+ attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type);
+ BLI_assert(dst);
+
+ attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_attribute_to_points(src.typed<T>(), selection, dst.as_span().typed<T>());
+ });
+ dst.save();
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
+
+ if (geometry_set.has_instances()) {
+ convert_instances_to_points(geometry_set,
+ params.extract_input<Field<float3>>("Position"),
+ params.extract_input<Field<float>>("Radius"),
+ params.extract_input<Field<bool>>("Selection"));
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_POINT_CLOUD});
+ params.set_output("Points", std::move(geometry_set));
+ }
+ else {
+ params.set_default_remaining_outputs();
+ }
+}
+
+} // namespace blender::nodes::node_geo_instances_to_points_cc
+
+void register_node_type_geo_instances_to_points()
+{
+ namespace file_ns = blender::nodes::node_geo_instances_to_points_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_INSTANCES_TO_POINTS, "Instances to Points", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
index f8a1c764f61..c97bbad4665 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
@@ -18,14 +18,14 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_is_viewport_cc {
-static void geo_node_is_viewport_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Bool>("Is Viewport");
+ b.add_output<decl::Bool>(N_("Is Viewport"));
}
-static void geo_node_is_viewport_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const Depsgraph *depsgraph = params.depsgraph();
const eEvaluationMode mode = DEG_get_mode(depsgraph);
@@ -34,14 +34,16 @@ static void geo_node_is_viewport_exec(GeoNodeExecParams params)
params.set_output("Is Viewport", is_viewport);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_is_viewport_cc
void register_node_type_geo_is_viewport()
{
+ namespace file_ns = blender::nodes::node_geo_is_viewport_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_IS_VIEWPORT, "Is Viewport", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_is_viewport_exec;
- ntype.declare = blender::nodes::geo_node_is_viewport_declare;
+ geo_node_type_base(&ntype, GEO_NODE_IS_VIEWPORT, "Is Viewport", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index 93643298f92..1e521af6b13 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -19,127 +19,21 @@
#include "BKE_mesh_runtime.h"
#include "BKE_pointcloud.h"
#include "BKE_spline.hh"
+#include "BKE_type_conversions.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "NOD_type_conversions.hh"
+#include "GEO_realize_instances.hh"
#include "node_geometry_util.hh"
-using blender::fn::GVArray_For_GSpan;
+namespace blender::nodes::node_geo_join_geometry_cc {
-namespace blender::nodes {
-
-static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>("Geometry").multi_input();
- b.add_output<decl::Geometry>("Geometry");
-}
-
-static Mesh *join_mesh_topology_and_builtin_attributes(Span<const MeshComponent *> src_components)
+static void node_declare(NodeDeclarationBuilder &b)
{
- int totverts = 0;
- int totloops = 0;
- int totedges = 0;
- int totpolys = 0;
-
- int64_t cd_dirty_vert = 0;
- int64_t cd_dirty_poly = 0;
- int64_t cd_dirty_edge = 0;
- int64_t cd_dirty_loop = 0;
-
- VectorSet<Material *> materials;
-
- for (const MeshComponent *mesh_component : src_components) {
- const Mesh *mesh = mesh_component->get_for_read();
- totverts += mesh->totvert;
- totloops += mesh->totloop;
- totedges += mesh->totedge;
- totpolys += mesh->totpoly;
- cd_dirty_vert |= mesh->runtime.cd_dirty_vert;
- cd_dirty_poly |= mesh->runtime.cd_dirty_poly;
- cd_dirty_edge |= mesh->runtime.cd_dirty_edge;
- cd_dirty_loop |= mesh->runtime.cd_dirty_loop;
-
- for (const int slot_index : IndexRange(mesh->totcol)) {
- Material *material = mesh->mat[slot_index];
- materials.add(material);
- }
- }
-
- const Mesh *first_input_mesh = src_components[0]->get_for_read();
- Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys);
- BKE_mesh_copy_parameters_for_eval(new_mesh, first_input_mesh);
-
- for (const int i : IndexRange(materials.size())) {
- Material *material = materials[i];
- BKE_id_material_eval_assign(&new_mesh->id, i + 1, material);
- }
-
- new_mesh->runtime.cd_dirty_vert = cd_dirty_vert;
- new_mesh->runtime.cd_dirty_poly = cd_dirty_poly;
- new_mesh->runtime.cd_dirty_edge = cd_dirty_edge;
- new_mesh->runtime.cd_dirty_loop = cd_dirty_loop;
-
- int vert_offset = 0;
- int loop_offset = 0;
- int edge_offset = 0;
- int poly_offset = 0;
- for (const MeshComponent *mesh_component : src_components) {
- const Mesh *mesh = mesh_component->get_for_read();
- if (mesh == nullptr) {
- continue;
- }
-
- Array<int> material_index_map(mesh->totcol);
- for (const int i : IndexRange(mesh->totcol)) {
- Material *material = mesh->mat[i];
- const int new_material_index = materials.index_of(material);
- material_index_map[i] = new_material_index;
- }
-
- for (const int i : IndexRange(mesh->totvert)) {
- const MVert &old_vert = mesh->mvert[i];
- MVert &new_vert = new_mesh->mvert[vert_offset + i];
- new_vert = old_vert;
- }
-
- for (const int i : IndexRange(mesh->totedge)) {
- const MEdge &old_edge = mesh->medge[i];
- MEdge &new_edge = new_mesh->medge[edge_offset + i];
- new_edge = old_edge;
- new_edge.v1 += vert_offset;
- new_edge.v2 += vert_offset;
- }
- for (const int i : IndexRange(mesh->totloop)) {
- const MLoop &old_loop = mesh->mloop[i];
- MLoop &new_loop = new_mesh->mloop[loop_offset + i];
- new_loop = old_loop;
- new_loop.v += vert_offset;
- new_loop.e += edge_offset;
- }
- for (const int i : IndexRange(mesh->totpoly)) {
- const MPoly &old_poly = mesh->mpoly[i];
- MPoly &new_poly = new_mesh->mpoly[poly_offset + i];
- new_poly = old_poly;
- new_poly.loopstart += loop_offset;
- if (old_poly.mat_nr >= 0 && old_poly.mat_nr < mesh->totcol) {
- new_poly.mat_nr = material_index_map[new_poly.mat_nr];
- }
- else {
- /* The material index was invalid before. */
- new_poly.mat_nr = 0;
- }
- }
-
- vert_offset += mesh->totvert;
- loop_offset += mesh->totloop;
- edge_offset += mesh->totedge;
- poly_offset += mesh->totpoly;
- }
-
- return new_mesh;
+ b.add_input<decl::Geometry>(N_("Geometry")).multi_input();
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
template<typename Component>
@@ -190,10 +84,10 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components,
if (domain_size == 0) {
continue;
}
- GVArrayPtr read_attribute = component->attribute_get_for_read(
+ GVArray read_attribute = component->attribute_get_for_read(
attribute_id, domain, data_type, nullptr);
- GVArray_GSpan src_span{*read_attribute};
+ GVArray_GSpan src_span{read_attribute};
const void *src_buffer = src_span.data();
void *dst_buffer = dst_span[offset];
cpp_type->copy_assign_n(src_buffer, dst_buffer, domain_size);
@@ -209,7 +103,7 @@ static void join_attributes(Span<const GeometryComponent *> src_components,
const Map<AttributeIDRef, AttributeMetaData> info = get_final_attribute_info(src_components,
ignored_attributes);
- for (const Map<AttributeIDRef, AttributeMetaData>::Item &item : info.items()) {
+ for (const Map<AttributeIDRef, AttributeMetaData>::Item item : info.items()) {
const AttributeIDRef attribute_id = item.key;
const AttributeMetaData &meta_data = item.value;
@@ -225,33 +119,6 @@ static void join_attributes(Span<const GeometryComponent *> src_components,
}
}
-static void join_components(Span<const MeshComponent *> src_components, GeometrySet &result)
-{
- Mesh *new_mesh = join_mesh_topology_and_builtin_attributes(src_components);
-
- MeshComponent &dst_component = result.get_component_for_write<MeshComponent>();
- dst_component.replace(new_mesh);
-
- /* Don't copy attributes that are stored directly in the mesh data structs. */
- join_attributes(to_base_components(src_components),
- dst_component,
- {"position", "material_index", "normal", "shade_smooth", "crease"});
-}
-
-static void join_components(Span<const PointCloudComponent *> src_components, GeometrySet &result)
-{
- int totpoints = 0;
- for (const PointCloudComponent *pointcloud_component : src_components) {
- totpoints += pointcloud_component->attribute_domain_size(ATTR_DOMAIN_POINT);
- }
-
- PointCloudComponent &dst_component = result.get_component_for_write<PointCloudComponent>();
- PointCloud *pointcloud = BKE_pointcloud_new_nomain(totpoints);
- dst_component.replace(pointcloud);
-
- join_attributes(to_base_components(src_components), dst_component);
-}
-
static void join_components(Span<const InstancesComponent *> src_components, GeometrySet &result)
{
InstancesComponent &dst_component = result.get_component_for_write<InstancesComponent>();
@@ -270,17 +137,16 @@ static void join_components(Span<const InstancesComponent *> src_components, Geo
}
Span<float4x4> src_transforms = src_component->instance_transforms();
- Span<int> src_ids = src_component->instance_ids();
Span<int> src_reference_handles = src_component->instance_reference_handles();
for (const int i : src_transforms.index_range()) {
const int src_handle = src_reference_handles[i];
const int dst_handle = handle_map[src_handle];
const float4x4 &transform = src_transforms[i];
- const int id = src_ids[i];
- dst_component.add_instance(dst_handle, transform, id);
+ dst_component.add_instance(dst_handle, transform);
}
}
+ join_attributes(to_base_components(src_components), dst_component, {"position"});
}
static void join_components(Span<const VolumeComponent *> src_components, GeometrySet &result)
@@ -291,169 +157,6 @@ static void join_components(Span<const VolumeComponent *> src_components, Geomet
UNUSED_VARS(src_components, dst_component);
}
-/**
- * \note This takes advantage of the fact that creating attributes on joined curves never
- * changes a point attribute into a spline attribute; it is always the other way around.
- */
-static void ensure_control_point_attribute(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
- Span<CurveComponent *> src_components,
- CurveEval &result)
-{
- MutableSpan<SplinePtr> splines = result.splines();
- const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
-
- /* In order to fill point attributes with spline domain attribute values where necessary, keep
- * track of the curve each spline came from while iterating over the splines in the result. */
- int src_component_index = 0;
- int spline_index_in_component = 0;
- const CurveEval *current_curve = src_components[src_component_index]->get_for_read();
-
- for (SplinePtr &spline : splines) {
- std::optional<GSpan> attribute = spline->attributes.get_for_read(attribute_id);
-
- if (attribute) {
- if (attribute->type() != type) {
- /* In this case, the attribute exists, but it has the wrong type. So create a buffer
- * for the converted values, do the conversion, and then replace the attribute. */
- void *converted_buffer = MEM_mallocN_aligned(
- spline->size() * type.size(), type.alignment(), __func__);
-
- const DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions();
- conversions.try_convert(std::make_unique<GVArray_For_GSpan>(*attribute), type)
- ->materialize(converted_buffer);
-
- spline->attributes.remove(attribute_id);
- spline->attributes.create_by_move(attribute_id, data_type, converted_buffer);
- }
- }
- else {
- spline->attributes.create(attribute_id, data_type);
-
- if (current_curve->attributes.get_for_read(attribute_id)) {
- /* In this case the attribute did not exist, but there is a spline domain attribute
- * we can retrieve a value from, as a spline to point domain conversion. So fill the
- * new attribute with the value for this spline. */
- GVArrayPtr current_curve_attribute = current_curve->attributes.get_for_read(
- attribute_id, data_type, nullptr);
-
- BLI_assert(spline->attributes.get_for_read(attribute_id));
- std::optional<GMutableSpan> new_attribute = spline->attributes.get_for_write(attribute_id);
-
- BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
- current_curve_attribute->get(spline_index_in_component, buffer);
- type.fill_assign_n(buffer, new_attribute->data(), new_attribute->size());
- }
- }
-
- /* Move to the next spline and maybe the next input component. */
- spline_index_in_component++;
- if (spline != splines.last() && spline_index_in_component >= current_curve->splines().size()) {
- src_component_index++;
- spline_index_in_component = 0;
-
- current_curve = src_components[src_component_index]->get_for_read();
- }
- }
-}
-
-/**
- * Fill data for an attribute on the new curve based on all source curves.
- */
-static void ensure_spline_attribute(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
- Span<CurveComponent *> src_components,
- CurveEval &result)
-{
- const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
-
- result.attributes.create(attribute_id, data_type);
- GMutableSpan result_attribute = *result.attributes.get_for_write(attribute_id);
-
- int offset = 0;
- for (const CurveComponent *component : src_components) {
- const CurveEval &curve = *component->get_for_read();
- const int size = curve.splines().size();
- if (size == 0) {
- continue;
- }
- GVArrayPtr read_attribute = curve.attributes.get_for_read(attribute_id, data_type, nullptr);
- GVArray_GSpan src_span{*read_attribute};
-
- const void *src_buffer = src_span.data();
- type.copy_assign_n(src_buffer, result_attribute[offset], size);
-
- offset += size;
- }
-}
-
-/**
- * Special handling for copying spline attributes. This is necessary because we move the splines
- * out of the source components instead of copying them, meaning we can no longer access point
- * domain attributes on the source components.
- *
- * \warning Splines have been moved out of the source components at this point, so it
- * is important to only read curve-level data (spline domain attributes) from them.
- */
-static void join_curve_attributes(const Map<AttributeIDRef, AttributeMetaData> &info,
- Span<CurveComponent *> src_components,
- CurveEval &result)
-{
- for (const Map<AttributeIDRef, AttributeMetaData>::Item &item : info.items()) {
- const AttributeIDRef attribute_id = item.key;
- const AttributeMetaData meta_data = item.value;
-
- if (meta_data.domain == ATTR_DOMAIN_CURVE) {
- ensure_spline_attribute(attribute_id, meta_data.data_type, src_components, result);
- }
- else {
- ensure_control_point_attribute(attribute_id, meta_data.data_type, src_components, result);
- }
- }
-}
-
-static void join_curve_components(MutableSpan<GeometrySet> src_geometry_sets, GeometrySet &result)
-{
- Vector<CurveComponent *> src_components;
- for (GeometrySet &geometry_set : src_geometry_sets) {
- if (geometry_set.has_curve()) {
- /* Retrieving with write access seems counterintuitive, but it can allow avoiding a copy
- * in the case where the input spline has no other users, because the splines can be
- * moved from the source curve rather than copied from a read-only source. Retrieving
- * the curve for write will make a copy only when it has a user elsewhere. */
- CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
- src_components.append(&component);
- }
- }
-
- if (src_components.size() == 0) {
- return;
- }
- if (src_components.size() == 1) {
- result.add(*src_components[0]);
- return;
- }
-
- /* Retrieve attribute info before moving the splines out of the input components. */
- const Map<AttributeIDRef, AttributeMetaData> info = get_final_attribute_info(
- {(const GeometryComponent **)src_components.data(), src_components.size()},
- {"position", "radius", "tilt", "cyclic", "resolution"});
-
- CurveComponent &dst_component = result.get_component_for_write<CurveComponent>();
- CurveEval *dst_curve = new CurveEval();
- for (CurveComponent *component : src_components) {
- CurveEval *src_curve = component->get_for_write();
- for (SplinePtr &spline : src_curve->splines()) {
- dst_curve->add_spline(std::move(spline));
- }
- }
- dst_curve->attributes.reallocate(dst_curve->splines().size());
-
- join_curve_attributes(info, src_components, *dst_curve);
-
- dst_component.replace(dst_curve);
-}
-
template<typename Component>
static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet &result)
{
@@ -472,10 +175,31 @@ static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet
result.add(*components[0]);
return;
}
- join_components(components, result);
+
+ GeometrySet instances_geometry_set;
+ InstancesComponent &instances =
+ instances_geometry_set.get_component_for_write<InstancesComponent>();
+
+ if constexpr (is_same_any_v<Component, InstancesComponent, VolumeComponent>) {
+ join_components(components, result);
+ }
+ else {
+ for (const Component *component : components) {
+ GeometrySet tmp_geo;
+ tmp_geo.add(*component);
+ const int handle = instances.add_reference(InstanceReference{tmp_geo});
+ instances.add_instance(handle, float4x4::identity());
+ }
+
+ geometry::RealizeInstancesOptions options;
+ options.keep_original_ids = true;
+ options.realize_instance_attributes = false;
+ GeometrySet joined_components = geometry::realize_instances(instances_geometry_set, options);
+ result.add(joined_components.get_component_for_write<Component>());
+ }
}
-static void geo_node_join_geometry_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Vector<GeometrySet> geometry_sets = params.extract_multi_input<GeometrySet>("Geometry");
@@ -484,18 +208,20 @@ static void geo_node_join_geometry_exec(GeoNodeExecParams params)
join_component_type<PointCloudComponent>(geometry_sets, geometry_set_result);
join_component_type<InstancesComponent>(geometry_sets, geometry_set_result);
join_component_type<VolumeComponent>(geometry_sets, geometry_set_result);
- join_curve_components(geometry_sets, geometry_set_result);
+ join_component_type<CurveComponent>(geometry_sets, geometry_set_result);
params.set_output("Geometry", std::move(geometry_set_result));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_join_geometry_cc
void register_node_type_geo_join_geometry()
{
+ namespace file_ns = blender::nodes::node_geo_join_geometry_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_JOIN_GEOMETRY, "Join Geometry", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_join_geometry_exec;
- ntype.declare = blender::nodes::geo_node_join_geometry_declare;
+ geo_node_type_base(&ntype, GEO_NODE_JOIN_GEOMETRY, "Join Geometry", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_assign.cc b/source/blender/nodes/geometry/nodes/node_geo_material_assign.cc
deleted file mode 100644
index 780994996ae..00000000000
--- a/source/blender/nodes/geometry/nodes/node_geo_material_assign.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "node_geometry_util.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-
-#include "BKE_material.h"
-
-namespace blender::nodes {
-
-static void geo_node_material_assign_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Material>("Material").hide_label();
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_output<decl::Geometry>("Geometry");
-}
-
-static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Material *material)
-{
- int new_material_index = -1;
- for (const int i : IndexRange(mesh.totcol)) {
- Material *other_material = mesh.mat[i];
- if (other_material == material) {
- new_material_index = i;
- break;
- }
- }
- if (new_material_index == -1) {
- /* Append a new material index. */
- new_material_index = mesh.totcol;
- BKE_id_material_eval_assign(&mesh.id, new_material_index + 1, material);
- }
-
- mesh.mpoly = (MPoly *)CustomData_duplicate_referenced_layer(&mesh.pdata, CD_MPOLY, mesh.totpoly);
- for (const int i : selection) {
- MPoly &poly = mesh.mpoly[i];
- poly.mat_nr = new_material_index;
- }
-}
-
-static void geo_node_material_assign_exec(GeoNodeExecParams params)
-{
- Material *material = params.extract_input<Material *>("Material");
- const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
-
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has<MeshComponent>()) {
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- Mesh *mesh = mesh_component.get_for_write();
- if (mesh != nullptr) {
- GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
-
- fn::FieldEvaluator selection_evaluator{field_context, mesh->totpoly};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
- assign_material_to_faces(*mesh, selection, material);
- }
- }
- });
-
- params.set_output("Geometry", std::move(geometry_set));
-}
-
-} // namespace blender::nodes
-
-void register_node_type_geo_material_assign()
-{
- static bNodeType ntype;
-
- geo_node_type_base(&ntype, GEO_NODE_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_material_assign_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_material_assign_exec;
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
index a917434fa00..0309121db74 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
@@ -24,17 +24,17 @@
#include "BKE_material.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_material_replace_cc {
-static void geo_node_material_replace_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Material>("Old");
- b.add_input<decl::Material>("New");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Material>(N_("Old"));
+ b.add_input<decl::Material>(N_("New"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_material_replace_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *old_material = params.extract_input<Material *>("Old");
Material *new_material = params.extract_input<Material *>("New");
@@ -55,15 +55,16 @@ static void geo_node_material_replace_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_material_replace_cc
void register_node_type_geo_material_replace()
{
+ namespace file_ns = blender::nodes::node_geo_material_replace_cc;
+
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_MATERIAL_REPLACE, "Material Replace", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_material_replace_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_material_replace_exec;
+ geo_node_type_base(&ntype, GEO_NODE_REPLACE_MATERIAL, "Replace Material", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
index 337bd88c6e6..0b5f0bf34c5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
@@ -26,12 +26,12 @@
#include "BKE_material.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_material_selection_cc {
-static void geo_node_material_selection_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Material>("Material").hide_label(true);
- b.add_output<decl::Bool>("Selection").field_source();
+ b.add_input<decl::Material>(N_("Material")).hide_label(true);
+ b.add_output<decl::Bool>(N_("Selection")).field_source();
}
static void select_mesh_by_material(const Mesh &mesh,
@@ -54,78 +54,76 @@ static void select_mesh_by_material(const Mesh &mesh,
});
}
-class MaterialSelectionFieldInput final : public fn::FieldInput {
+class MaterialSelectionFieldInput final : public GeometryFieldInput {
Material *material_;
public:
MaterialSelectionFieldInput(Material *material)
- : fn::FieldInput(CPPType::get<bool>(), "Material Selection"), material_(material)
+ : GeometryFieldInput(CPPType::get<bool>(), "Material Selection node"), material_(material)
{
+ category_ = Category::Generated;
}
- const GVArray *get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- if (component.type() != GEO_COMPONENT_TYPE_MESH) {
- return nullptr;
- }
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return nullptr;
- }
-
- if (domain == ATTR_DOMAIN_FACE) {
- Array<bool> selection(mask.min_array_size());
- select_mesh_by_material(*mesh, material_, mask, selection);
- return &scope.construct<fn::GVArray_For_ArrayContainer<Array<bool>>>(std::move(selection));
- }
-
- Array<bool> selection(mesh->totpoly);
- select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection);
- GVArrayPtr face_selection = std::make_unique<fn::GVArray_For_ArrayContainer<Array<bool>>>(
- std::move(selection));
- GVArrayPtr final_selection = mesh_component.attribute_try_adapt_domain(
- std::move(face_selection), ATTR_DOMAIN_FACE, domain);
- return scope.add_value(std::move(final_selection)).get();
+ if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ return {};
+ }
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ if (domain == ATTR_DOMAIN_FACE) {
+ Array<bool> selection(mask.min_array_size());
+ select_mesh_by_material(*mesh, material_, mask, selection);
+ return VArray<bool>::ForContainer(std::move(selection));
}
+ Array<bool> selection(mesh->totpoly);
+ select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection);
+ return mesh_component.attribute_try_adapt_domain<bool>(
+ VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain);
+
return nullptr;
}
uint64_t hash() const override
{
- /* Some random constant hash. */
- return 91619626;
+ return get_default_hash(material_);
}
bool is_equal_to(const fn::FieldNode &other) const override
{
- return dynamic_cast<const MaterialSelectionFieldInput *>(&other) != nullptr;
+ if (const MaterialSelectionFieldInput *other_material_selection =
+ dynamic_cast<const MaterialSelectionFieldInput *>(&other)) {
+ return material_ == other_material_selection->material_;
+ }
+ return false;
}
};
-static void geo_node_material_selection_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *material = params.extract_input<Material *>("Material");
Field<bool> material_field{std::make_shared<MaterialSelectionFieldInput>(material)};
params.set_output("Selection", std::move(material_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_material_selection_cc
void register_node_type_geo_material_selection()
{
+ namespace file_ns = blender::nodes::node_geo_material_selection_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_MATERIAL_SELECTION, "Material Selection", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_material_selection_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_material_selection_exec;
+ &ntype, GEO_NODE_MATERIAL_SELECTION, "Material Selection", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc b/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
new file mode 100644
index 00000000000..deb149fd0f0
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
@@ -0,0 +1,108 @@
+/*
+ * 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 "GEO_mesh_merge_by_distance.hh"
+#include "GEO_point_merge_by_distance.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_merge_by_distance_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"))
+ .supported_type({GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_MESH});
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Distance")).default_value(0.1f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static PointCloud *pointcloud_merge_by_distance(const PointCloudComponent &src_points,
+ const float merge_distance,
+ const Field<bool> &selection_field)
+{
+ const int src_size = src_points.attribute_domain_size(ATTR_DOMAIN_POINT);
+ GeometryComponentFieldContext context{src_points, ATTR_DOMAIN_POINT};
+ FieldEvaluator evaluator{context, src_size};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+
+ const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+ if (selection.is_empty()) {
+ return nullptr;
+ }
+
+ return geometry::point_merge_by_distance(src_points, merge_distance, selection);
+}
+
+static std::optional<Mesh *> mesh_merge_by_distance(const MeshComponent &mesh_component,
+ const float merge_distance,
+ const Field<bool> &selection_field)
+{
+ const int src_size = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
+ FieldEvaluator evaluator{context, src_size};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+
+ const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+ if (selection.is_empty()) {
+ return nullptr;
+ }
+
+ const Mesh &mesh = *mesh_component.get_for_read();
+ return geometry::mesh_merge_by_distance_all(mesh, selection, merge_distance);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
+ const float merge_distance = params.extract_input<float>("Distance");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_pointcloud()) {
+ PointCloud *result = pointcloud_merge_by_distance(
+ *geometry_set.get_component_for_read<PointCloudComponent>(), merge_distance, selection);
+ geometry_set.replace_pointcloud(result);
+ }
+ if (geometry_set.has_mesh()) {
+ std::optional<Mesh *> result = mesh_merge_by_distance(
+ *geometry_set.get_component_for_read<MeshComponent>(), merge_distance, selection);
+ if (result) {
+ geometry_set.replace_mesh(*result);
+ }
+ }
+ });
+
+ params.set_output("Geometry", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_merge_by_distance_cc
+
+void register_node_type_geo_merge_by_distance()
+{
+ namespace file_ns = blender::nodes::node_geo_merge_by_distance_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_MERGE_BY_DISTANCE, "Merge by Distance", NODE_CLASS_GEOMETRY);
+
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
index 9c477c639a2..b3b11b2e0e9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
@@ -25,28 +25,34 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_circle_cc {
-static void geo_node_mesh_primitive_circle_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryMeshCircle)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Vertices").default_value(32).min(3);
- b.add_input<decl::Float>("Radius").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Int>(N_("Vertices"))
+ .default_value(32)
+ .min(3)
+ .description(N_("Number of vertices on the circle"));
+ b.add_input<decl::Float>(N_("Radius"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Distance of the vertices from the origin"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_mesh_primitive_circle_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
}
-static void geo_node_mesh_primitive_circle_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshCircle *node_storage = (NodeGeometryMeshCircle *)MEM_callocN(
- sizeof(NodeGeometryMeshCircle), __func__);
+ NodeGeometryMeshCircle *node_storage = MEM_cnew<NodeGeometryMeshCircle>(__func__);
node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NONE;
@@ -132,12 +138,6 @@ static Mesh *create_circle_mesh(const float radius,
copy_v3_v3(verts.last().co, float3(0));
}
- /* Point all vertex normals in the up direction. */
- const short up_normal[3] = {0, 0, SHRT_MAX};
- for (MVert &vert : verts) {
- copy_v3_v3_short(vert.no, up_normal);
- }
-
/* Create outer edges. */
const short edge_flag = (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE) ?
ME_LOOSEEDGE :
@@ -192,42 +192,38 @@ static Mesh *create_circle_mesh(const float radius,
return mesh;
}
-static void geo_node_mesh_primitive_circle_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const bNode &node = params.node();
- const NodeGeometryMeshCircle &storage = *(const NodeGeometryMeshCircle *)node.storage;
-
- const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
- storage.fill_type;
+ const NodeGeometryMeshCircle &storage = node_storage(params.node());
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
const float radius = params.extract_input<float>("Radius");
const int verts_num = params.extract_input<int>("Vertices");
if (verts_num < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3"));
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
- Mesh *mesh = create_circle_mesh(radius, verts_num, fill_type);
-
- BLI_assert(BKE_mesh_is_valid(mesh));
+ Mesh *mesh = create_circle_mesh(radius, verts_num, fill);
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_circle_cc
void register_node_type_geo_mesh_primitive_circle()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_circle_cc;
+
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_circle_init);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeGeometryMeshCircle", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_circle_exec;
- ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_circle_layout;
- ntype.declare = blender::nodes::geo_node_mesh_primitive_circle_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index 0d58476fc58..e0923344421 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -25,529 +25,797 @@
#include "node_geometry_util.hh"
+#include <cmath>
+
namespace blender::nodes {
-static void geo_node_mesh_primitive_cone_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Int>("Vertices").default_value(32).min(3);
- b.add_input<decl::Float>("Radius Top").min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Radius Bottom").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Depth").default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Geometry");
-}
+struct ConeConfig {
+ float radius_top;
+ float radius_bottom;
+ float height;
+ int circle_segments;
+ int side_segments;
+ int fill_segments;
+ GeometryNodeMeshCircleFillType fill_type;
+
+ bool top_is_point;
+ bool bottom_is_point;
+ /* The cone tip and a triangle fan filling are topologically identical.
+ * This simplifies the logic in some cases. */
+ bool top_has_center_vert;
+ bool bottom_has_center_vert;
+
+ /* Helpful quantities. */
+ int tot_quad_rings;
+ int tot_edge_rings;
+ int tot_verts;
+ int tot_edges;
+ int tot_corners;
+ int tot_faces;
+
+ /* Helpful vertex indices. */
+ int first_vert;
+ int first_ring_verts_start;
+ int last_ring_verts_start;
+ int last_vert;
+
+ /* Helpful edge indices. */
+ int first_ring_edges_start;
+ int last_ring_edges_start;
+ int last_fan_edges_start;
+ int last_edge;
+
+ /* Helpful face indices. */
+ int top_faces_start;
+ int top_faces_len;
+ int side_faces_start;
+ int side_faces_len;
+ int bottom_faces_start;
+ int bottom_faces_len;
+
+ ConeConfig(float radius_top,
+ float radius_bottom,
+ float depth,
+ int circle_segments,
+ int side_segments,
+ int fill_segments,
+ GeometryNodeMeshCircleFillType fill_type)
+ : radius_top(radius_top),
+ radius_bottom(radius_bottom),
+ height(0.5f * depth),
+ circle_segments(circle_segments),
+ side_segments(side_segments),
+ fill_segments(fill_segments),
+ fill_type(fill_type)
+ {
+ this->top_is_point = this->radius_top == 0.0f;
+ this->bottom_is_point = this->radius_bottom == 0.0f;
+ this->top_has_center_vert = this->top_is_point ||
+ this->fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN;
+ this->bottom_has_center_vert = this->bottom_is_point ||
+ this->fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN;
+
+ this->tot_quad_rings = this->calculate_total_quad_rings();
+ this->tot_edge_rings = this->calculate_total_edge_rings();
+ this->tot_verts = this->calculate_total_verts();
+ this->tot_edges = this->calculate_total_edges();
+ this->tot_corners = this->calculate_total_corners();
+
+ this->first_vert = 0;
+ this->first_ring_verts_start = this->top_has_center_vert ? 1 : first_vert;
+ this->last_vert = this->tot_verts - 1;
+ this->last_ring_verts_start = this->last_vert - this->circle_segments;
+
+ this->first_ring_edges_start = this->top_has_center_vert ? this->circle_segments : 0;
+ this->last_ring_edges_start = this->first_ring_edges_start +
+ this->tot_quad_rings * this->circle_segments * 2;
+ this->last_fan_edges_start = this->tot_edges - this->circle_segments;
+ this->last_edge = this->tot_edges - 1;
+
+ this->top_faces_start = 0;
+ if (!this->top_is_point) {
+ this->top_faces_len = (fill_segments - 1) * circle_segments;
+ this->top_faces_len += this->top_has_center_vert ? circle_segments : 0;
+ this->top_faces_len += this->fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON ? 1 : 0;
+ }
+ else {
+ this->top_faces_len = 0;
+ }
-static void geo_node_mesh_primitive_cone_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
-}
+ this->side_faces_start = this->top_faces_len;
+ if (this->top_is_point && this->bottom_is_point) {
+ this->side_faces_len = 0;
+ }
+ else {
+ this->side_faces_len = side_segments * circle_segments;
+ }
-static void geo_node_mesh_primitive_cone_init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN(
- sizeof(NodeGeometryMeshCone), __func__);
+ if (!this->bottom_is_point) {
+ this->bottom_faces_len = (fill_segments - 1) * circle_segments;
+ this->bottom_faces_len += this->bottom_has_center_vert ? circle_segments : 0;
+ this->bottom_faces_len += this->fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON ? 1 : 0;
+ }
+ else {
+ this->bottom_faces_len = 0;
+ }
+ this->bottom_faces_start = this->side_faces_start + this->side_faces_len;
- node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
+ this->tot_faces = this->top_faces_len + this->side_faces_len + this->bottom_faces_len;
+ }
- node->storage = node_storage;
-}
+ private:
+ int calculate_total_quad_rings();
+ int calculate_total_edge_rings();
+ int calculate_total_verts();
+ int calculate_total_edges();
+ int calculate_total_corners();
+};
-static int vert_total(const GeometryNodeMeshCircleFillType fill_type,
- const int verts_num,
- const bool top_is_point,
- const bool bottom_is_point)
+int ConeConfig::calculate_total_quad_rings()
{
- int vert_total = 0;
- if (!top_is_point) {
- vert_total += verts_num;
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- vert_total++;
- }
+ if (top_is_point && bottom_is_point) {
+ return 0;
}
- else {
- vert_total++;
+
+ int quad_rings = 0;
+
+ if (!top_is_point) {
+ quad_rings += fill_segments - 1;
}
+
+ quad_rings += (!top_is_point && !bottom_is_point) ? side_segments : (side_segments - 1);
+
if (!bottom_is_point) {
- vert_total += verts_num;
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- vert_total++;
- }
- }
- else {
- vert_total++;
+ quad_rings += fill_segments - 1;
}
- return vert_total;
+ return quad_rings;
}
-static int edge_total(const GeometryNodeMeshCircleFillType fill_type,
- const int verts_num,
- const bool top_is_point,
- const bool bottom_is_point)
+int ConeConfig::calculate_total_edge_rings()
{
if (top_is_point && bottom_is_point) {
- return 1;
+ return 0;
}
- int edge_total = 0;
+ int edge_rings = 0;
+
if (!top_is_point) {
- edge_total += verts_num;
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- edge_total += verts_num;
- }
+ edge_rings += fill_segments;
}
- edge_total += verts_num;
+ edge_rings += side_segments - 1;
if (!bottom_is_point) {
- edge_total += verts_num;
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- edge_total += verts_num;
- }
+ edge_rings += fill_segments;
}
- return edge_total;
+ return edge_rings;
}
-static int corner_total(const GeometryNodeMeshCircleFillType fill_type,
- const int verts_num,
- const bool top_is_point,
- const bool bottom_is_point)
+int ConeConfig::calculate_total_verts()
{
if (top_is_point && bottom_is_point) {
- return 0;
+ return side_segments + 1;
+ }
+
+ int vert_total = 0;
+
+ if (top_has_center_vert) {
+ vert_total++;
}
- int corner_total = 0;
if (!top_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
- corner_total += verts_num;
- }
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- corner_total += verts_num * 3;
- }
+ vert_total += circle_segments * fill_segments;
}
- if (!top_is_point && !bottom_is_point) {
- corner_total += verts_num * 4;
+ vert_total += circle_segments * (side_segments - 1);
+
+ if (!bottom_is_point) {
+ vert_total += circle_segments * fill_segments;
}
- else {
- corner_total += verts_num * 3;
+
+ if (bottom_has_center_vert) {
+ vert_total++;
}
- if (!bottom_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
- corner_total += verts_num;
- }
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- corner_total += verts_num * 3;
- }
+ return vert_total;
+}
+
+int ConeConfig::calculate_total_edges()
+{
+ if (top_is_point && bottom_is_point) {
+ return side_segments;
}
- return corner_total;
+ int edge_total = 0;
+ if (top_has_center_vert) {
+ edge_total += circle_segments;
+ }
+
+ edge_total += circle_segments * (tot_quad_rings * 2 + 1);
+
+ if (bottom_has_center_vert) {
+ edge_total += circle_segments;
+ }
+
+ return edge_total;
}
-static int face_total(const GeometryNodeMeshCircleFillType fill_type,
- const int verts_num,
- const bool top_is_point,
- const bool bottom_is_point)
+int ConeConfig::calculate_total_corners()
{
if (top_is_point && bottom_is_point) {
return 0;
}
- int face_total = 0;
- if (!top_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
- face_total++;
- }
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- face_total += verts_num;
- }
+ int corner_total = 0;
+
+ if (top_has_center_vert) {
+ corner_total += (circle_segments * 3);
+ }
+ else if (!top_is_point && fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ corner_total += circle_segments;
}
- face_total += verts_num;
+ corner_total += tot_quad_rings * (circle_segments * 4);
- if (!bottom_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
- face_total++;
- }
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- face_total += verts_num;
- }
+ if (bottom_has_center_vert) {
+ corner_total += (circle_segments * 3);
+ }
+ else if (!bottom_is_point && fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ corner_total += circle_segments;
}
- return face_total;
+ return corner_total;
}
-static void calculate_uvs(Mesh *mesh,
- const bool top_is_point,
- const bool bottom_is_point,
- const int verts_num,
- const GeometryNodeMeshCircleFillType fill_type)
+static void calculate_cone_vertices(const MutableSpan<MVert> &verts, const ConeConfig &config)
{
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- OutputAttribute_Typed<float2> uv_attribute =
- mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
- MutableSpan<float2> uvs = uv_attribute.as_span();
-
- Array<float2> circle(verts_num);
+ Array<float2> circle(config.circle_segments);
+ const float angle_delta = 2.0f * (M_PI / static_cast<float>(config.circle_segments));
float angle = 0.0f;
- const float angle_delta = 2.0f * M_PI / static_cast<float>(verts_num);
- for (const int i : IndexRange(verts_num)) {
- circle[i].x = std::cos(angle) * 0.225f + 0.25f;
- circle[i].y = std::sin(angle) * 0.225f + 0.25f;
+ for (const int i : IndexRange(config.circle_segments)) {
+ circle[i].x = std::cos(angle);
+ circle[i].y = std::sin(angle);
angle += angle_delta;
}
- int loop_index = 0;
- if (!top_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
- for (const int i : IndexRange(verts_num)) {
- uvs[loop_index++] = circle[i];
- }
- }
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- for (const int i : IndexRange(verts_num)) {
- uvs[loop_index++] = circle[i];
- uvs[loop_index++] = circle[(i + 1) % verts_num];
- uvs[loop_index++] = float2(0.25f, 0.25f);
- }
- }
- }
+ int vert_index = 0;
- /* Create side corners and faces. */
- if (!top_is_point && !bottom_is_point) {
- const float bottom = (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE) ? 0.0f : 0.5f;
- /* Quads connect the top and bottom. */
- for (const int i : IndexRange(verts_num)) {
- const float vert = static_cast<float>(i);
- uvs[loop_index++] = float2(vert / verts_num, bottom);
- uvs[loop_index++] = float2(vert / verts_num, 1.0f);
- uvs[loop_index++] = float2((vert + 1.0f) / verts_num, 1.0f);
- uvs[loop_index++] = float2((vert + 1.0f) / verts_num, bottom);
- }
+ /* Top cone tip or triangle fan center. */
+ if (config.top_has_center_vert) {
+ copy_v3_fl3(verts[vert_index++].co, 0.0f, 0.0f, config.height);
}
- else {
- /* Triangles connect the top and bottom section. */
- if (!top_is_point) {
- for (const int i : IndexRange(verts_num)) {
- uvs[loop_index++] = circle[i] + float2(0.5f, 0.0f);
- uvs[loop_index++] = float2(0.75f, 0.25f);
- uvs[loop_index++] = circle[(i + 1) % verts_num] + float2(0.5f, 0.0f);
- }
- }
- else {
- BLI_assert(!bottom_is_point);
- for (const int i : IndexRange(verts_num)) {
- uvs[loop_index++] = circle[i];
- uvs[loop_index++] = circle[(i + 1) % verts_num];
- uvs[loop_index++] = float2(0.25f, 0.25f);
+
+ /* Top fill including the outer edge of the fill. */
+ if (!config.top_is_point) {
+ const float top_fill_radius_delta = config.radius_top /
+ static_cast<float>(config.fill_segments);
+ for (const int i : IndexRange(config.fill_segments)) {
+ const float top_fill_radius = top_fill_radius_delta * (i + 1);
+ for (const int j : IndexRange(config.circle_segments)) {
+ const float x = circle[j].x * top_fill_radius;
+ const float y = circle[j].y * top_fill_radius;
+ copy_v3_fl3(verts[vert_index++].co, x, y, config.height);
}
}
}
- /* Create bottom corners and faces. */
- if (!bottom_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
- for (const int i : IndexRange(verts_num)) {
- /* Go backwards because of reversed face normal. */
- uvs[loop_index++] = circle[verts_num - 1 - i] + float2(0.5f, 0.0f);
- }
+ /* Rings along the side. */
+ const float side_radius_delta = (config.radius_bottom - config.radius_top) /
+ static_cast<float>(config.side_segments);
+ const float height_delta = 2.0f * config.height / static_cast<float>(config.side_segments);
+ for (const int i : IndexRange(config.side_segments - 1)) {
+ const float ring_radius = config.radius_top + (side_radius_delta * (i + 1));
+ const float ring_height = config.height - (height_delta * (i + 1));
+ for (const int j : IndexRange(config.circle_segments)) {
+ const float x = circle[j].x * ring_radius;
+ const float y = circle[j].y * ring_radius;
+ copy_v3_fl3(verts[vert_index++].co, x, y, ring_height);
}
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- for (const int i : IndexRange(verts_num)) {
- uvs[loop_index++] = circle[i] + float2(0.5f, 0.0f);
- uvs[loop_index++] = float2(0.75f, 0.25f);
- uvs[loop_index++] = circle[(i + 1) % verts_num] + float2(0.5f, 0.0f);
+ }
+
+ /* Bottom fill including the outer edge of the fill. */
+ if (!config.bottom_is_point) {
+ const float bottom_fill_radius_delta = config.radius_bottom /
+ static_cast<float>(config.fill_segments);
+ for (const int i : IndexRange(config.fill_segments)) {
+ const float bottom_fill_radius = config.radius_bottom - (i * bottom_fill_radius_delta);
+ for (const int j : IndexRange(config.circle_segments)) {
+ const float x = circle[j].x * bottom_fill_radius;
+ const float y = circle[j].y * bottom_fill_radius;
+ copy_v3_fl3(verts[vert_index++].co, x, y, -config.height);
}
}
}
- uv_attribute.save();
+ /* Bottom cone tip or triangle fan center. */
+ if (config.bottom_has_center_vert) {
+ copy_v3_fl3(verts[vert_index++].co, 0.0f, 0.0f, -config.height);
+ }
}
-Mesh *create_cylinder_or_cone_mesh(const float radius_top,
- const float radius_bottom,
- const float depth,
- const int verts_num,
- const GeometryNodeMeshCircleFillType fill_type)
+static void calculate_cone_edges(const MutableSpan<MEdge> &edges, const ConeConfig &config)
{
- const bool top_is_point = radius_top == 0.0f;
- const bool bottom_is_point = radius_bottom == 0.0f;
- const float height = depth * 0.5f;
- /* Handle the case of a line / single point before everything else to avoid
- * the need to check for it later. */
- if (top_is_point && bottom_is_point) {
- const bool single_vertex = height == 0.0f;
- Mesh *mesh = BKE_mesh_new_nomain(single_vertex ? 1 : 2, single_vertex ? 0 : 1, 0, 0, 0);
- copy_v3_v3(mesh->mvert[0].co, float3(0.0f, 0.0f, height));
- if (single_vertex) {
- const short up[3] = {0, 0, SHRT_MAX};
- copy_v3_v3_short(mesh->mvert[0].no, up);
- return mesh;
- }
- copy_v3_v3(mesh->mvert[1].co, float3(0.0f, 0.0f, -height));
- mesh->medge[0].v1 = 0;
- mesh->medge[0].v2 = 1;
- mesh->medge[0].flag |= ME_LOOSEEDGE;
- BKE_mesh_normals_tag_dirty(mesh);
- return mesh;
- }
-
- Mesh *mesh = BKE_mesh_new_nomain(
- vert_total(fill_type, verts_num, top_is_point, bottom_is_point),
- edge_total(fill_type, verts_num, top_is_point, bottom_is_point),
- 0,
- corner_total(fill_type, verts_num, top_is_point, bottom_is_point),
- face_total(fill_type, verts_num, top_is_point, bottom_is_point));
- BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
- MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
- MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
- MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
-
- /* Calculate vertex positions. */
- const int top_verts_start = 0;
- const int bottom_verts_start = top_verts_start + (!top_is_point ? verts_num : 1);
- const float angle_delta = 2.0f * (M_PI / static_cast<float>(verts_num));
- for (const int i : IndexRange(verts_num)) {
- const float angle = i * angle_delta;
- const float x = std::cos(angle);
- const float y = std::sin(angle);
- if (!top_is_point) {
- copy_v3_v3(verts[top_verts_start + i].co, float3(x * radius_top, y * radius_top, height));
- }
- if (!bottom_is_point) {
- copy_v3_v3(verts[bottom_verts_start + i].co,
- float3(x * radius_bottom, y * radius_bottom, -height));
+ int edge_index = 0;
+
+ /* Edges for top cone tip or triangle fan */
+ if (config.top_has_center_vert) {
+ for (const int i : IndexRange(config.circle_segments)) {
+ MEdge &edge = edges[edge_index++];
+ edge.v1 = config.first_vert;
+ edge.v2 = config.first_ring_verts_start + i;
+ edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
}
}
- if (top_is_point) {
- copy_v3_v3(verts[top_verts_start].co, float3(0.0f, 0.0f, height));
- }
- if (bottom_is_point) {
- copy_v3_v3(verts[bottom_verts_start].co, float3(0.0f, 0.0f, -height));
- }
- /* Add center vertices for the triangle fans at the end. */
- const int top_center_vert_index = bottom_verts_start + (bottom_is_point ? 1 : verts_num);
- const int bottom_center_vert_index = top_center_vert_index + (top_is_point ? 0 : 1);
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- if (!top_is_point) {
- copy_v3_v3(verts[top_center_vert_index].co, float3(0.0f, 0.0f, height));
+ /* Rings and connecting edges between the rings. */
+ for (const int i : IndexRange(config.tot_edge_rings)) {
+ const int this_ring_vert_start = config.first_ring_verts_start + (i * config.circle_segments);
+ const int next_ring_vert_start = this_ring_vert_start + config.circle_segments;
+ /* Edge rings. */
+ for (const int j : IndexRange(config.circle_segments)) {
+ MEdge &edge = edges[edge_index++];
+ edge.v1 = this_ring_vert_start + j;
+ edge.v2 = this_ring_vert_start + ((j + 1) % config.circle_segments);
+ edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
}
- if (!bottom_is_point) {
- copy_v3_v3(verts[bottom_center_vert_index].co, float3(0.0f, 0.0f, -height));
+ if (i == config.tot_edge_rings - 1) {
+ /* There is one fewer ring of connecting edges. */
+ break;
}
- }
-
- /* Create top edges. */
- const int top_edges_start = 0;
- const int top_fan_edges_start = (!top_is_point &&
- fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) ?
- top_edges_start + verts_num :
- top_edges_start;
- if (!top_is_point) {
- for (const int i : IndexRange(verts_num)) {
- MEdge &edge = edges[top_edges_start + i];
- edge.v1 = top_verts_start + i;
- edge.v2 = top_verts_start + (i + 1) % verts_num;
+ /* Connecting edges. */
+ for (const int j : IndexRange(config.circle_segments)) {
+ MEdge &edge = edges[edge_index++];
+ edge.v1 = this_ring_vert_start + j;
+ edge.v2 = next_ring_vert_start + j;
edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
}
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- for (const int i : IndexRange(verts_num)) {
- MEdge &edge = edges[top_fan_edges_start + i];
- edge.v1 = top_center_vert_index;
- edge.v2 = top_verts_start + i;
- edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
- }
- }
- }
-
- /* Create connecting edges. */
- const int connecting_edges_start = top_fan_edges_start + (!top_is_point ? verts_num : 0);
- for (const int i : IndexRange(verts_num)) {
- MEdge &edge = edges[connecting_edges_start + i];
- edge.v1 = top_verts_start + (!top_is_point ? i : 0);
- edge.v2 = bottom_verts_start + (!bottom_is_point ? i : 0);
- edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
}
- /* Create bottom edges. */
- const int bottom_edges_start = connecting_edges_start + verts_num;
- const int bottom_fan_edges_start = (!bottom_is_point &&
- fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) ?
- bottom_edges_start + verts_num :
- bottom_edges_start;
- if (!bottom_is_point) {
- for (const int i : IndexRange(verts_num)) {
- MEdge &edge = edges[bottom_edges_start + i];
- edge.v1 = bottom_verts_start + i;
- edge.v2 = bottom_verts_start + (i + 1) % verts_num;
+ /* Edges for bottom triangle fan or tip. */
+ if (config.bottom_has_center_vert) {
+ for (const int i : IndexRange(config.circle_segments)) {
+ MEdge &edge = edges[edge_index++];
+ edge.v1 = config.last_ring_verts_start + i;
+ edge.v2 = config.last_vert;
edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
}
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- for (const int i : IndexRange(verts_num)) {
- MEdge &edge = edges[bottom_fan_edges_start + i];
- edge.v1 = bottom_center_vert_index;
- edge.v2 = bottom_verts_start + i;
- edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
- }
- }
}
+}
- /* Create top corners and faces. */
+static void calculate_cone_faces(const MutableSpan<MLoop> &loops,
+ const MutableSpan<MPoly> &polys,
+ const ConeConfig &config)
+{
int loop_index = 0;
int poly_index = 0;
- if (!top_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+
+ if (config.top_has_center_vert) {
+ /* Top cone tip or center triangle fan in the fill. */
+ const int top_center_vert = 0;
+ const int top_fan_edges_start = 0;
+
+ for (const int i : IndexRange(config.circle_segments)) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
- poly.totloop = verts_num;
+ poly.totloop = 3;
- for (const int i : IndexRange(verts_num)) {
- MLoop &loop = loops[loop_index++];
- loop.v = top_verts_start + i;
- loop.e = top_edges_start + i;
- }
+ MLoop &loop_a = loops[loop_index++];
+ loop_a.v = config.first_ring_verts_start + i;
+ loop_a.e = config.first_ring_edges_start + i;
+ MLoop &loop_b = loops[loop_index++];
+ loop_b.v = config.first_ring_verts_start + ((i + 1) % config.circle_segments);
+ loop_b.e = top_fan_edges_start + ((i + 1) % config.circle_segments);
+ MLoop &loop_c = loops[loop_index++];
+ loop_c.v = top_center_vert;
+ loop_c.e = top_fan_edges_start + i;
+ }
+ }
+ else if (config.fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ /* Center n-gon in the fill. */
+ MPoly &poly = polys[poly_index++];
+ poly.loopstart = loop_index;
+ poly.totloop = config.circle_segments;
+ for (const int i : IndexRange(config.circle_segments)) {
+ MLoop &loop = loops[loop_index++];
+ loop.v = i;
+ loop.e = i;
}
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- for (const int i : IndexRange(verts_num)) {
+ }
+
+ /* Quads connect one edge ring to the next one. */
+ if (config.tot_quad_rings > 0) {
+ for (const int i : IndexRange(config.tot_quad_rings)) {
+ const int this_ring_vert_start = config.first_ring_verts_start +
+ (i * config.circle_segments);
+ const int next_ring_vert_start = this_ring_vert_start + config.circle_segments;
+
+ const int this_ring_edges_start = config.first_ring_edges_start +
+ (i * 2 * config.circle_segments);
+ const int next_ring_edges_start = this_ring_edges_start + (2 * config.circle_segments);
+ const int ring_connections_start = this_ring_edges_start + config.circle_segments;
+
+ for (const int j : IndexRange(config.circle_segments)) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
- poly.totloop = 3;
+ poly.totloop = 4;
MLoop &loop_a = loops[loop_index++];
- loop_a.v = top_verts_start + i;
- loop_a.e = top_edges_start + i;
+ loop_a.v = this_ring_vert_start + j;
+ loop_a.e = ring_connections_start + j;
MLoop &loop_b = loops[loop_index++];
- loop_b.v = top_verts_start + (i + 1) % verts_num;
- loop_b.e = top_fan_edges_start + (i + 1) % verts_num;
+ loop_b.v = next_ring_vert_start + j;
+ loop_b.e = next_ring_edges_start + j;
MLoop &loop_c = loops[loop_index++];
- loop_c.v = top_center_vert_index;
- loop_c.e = top_fan_edges_start + i;
+ loop_c.v = next_ring_vert_start + ((j + 1) % config.circle_segments);
+ loop_c.e = ring_connections_start + ((j + 1) % config.circle_segments);
+ MLoop &loop_d = loops[loop_index++];
+ loop_d.v = this_ring_vert_start + ((j + 1) % config.circle_segments);
+ loop_d.e = this_ring_edges_start + j;
}
}
}
- /* Create side corners and faces. */
- if (!top_is_point && !bottom_is_point) {
- /* Quads connect the top and bottom. */
- for (const int i : IndexRange(verts_num)) {
+ if (config.bottom_has_center_vert) {
+ /* Bottom cone tip or center triangle fan in the fill. */
+ for (const int i : IndexRange(config.circle_segments)) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
- poly.totloop = 4;
+ poly.totloop = 3;
MLoop &loop_a = loops[loop_index++];
- loop_a.v = top_verts_start + i;
- loop_a.e = connecting_edges_start + i;
+ loop_a.v = config.last_ring_verts_start + i;
+ loop_a.e = config.last_fan_edges_start + i;
MLoop &loop_b = loops[loop_index++];
- loop_b.v = bottom_verts_start + i;
- loop_b.e = bottom_edges_start + i;
+ loop_b.v = config.last_vert;
+ loop_b.e = config.last_fan_edges_start + (i + 1) % config.circle_segments;
MLoop &loop_c = loops[loop_index++];
- loop_c.v = bottom_verts_start + (i + 1) % verts_num;
- loop_c.e = connecting_edges_start + (i + 1) % verts_num;
- MLoop &loop_d = loops[loop_index++];
- loop_d.v = top_verts_start + (i + 1) % verts_num;
- loop_d.e = top_edges_start + i;
+ loop_c.v = config.last_ring_verts_start + (i + 1) % config.circle_segments;
+ loop_c.e = config.last_ring_edges_start + i;
}
}
- else {
- /* Triangles connect the top and bottom section. */
- if (!top_is_point) {
- for (const int i : IndexRange(verts_num)) {
- MPoly &poly = polys[poly_index++];
- poly.loopstart = loop_index;
- poly.totloop = 3;
+ else if (config.fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ /* Center n-gon in the fill. */
+ MPoly &poly = polys[poly_index++];
+ poly.loopstart = loop_index;
+ poly.totloop = config.circle_segments;
- MLoop &loop_a = loops[loop_index++];
- loop_a.v = top_verts_start + i;
- loop_a.e = connecting_edges_start + i;
- MLoop &loop_b = loops[loop_index++];
- loop_b.v = bottom_verts_start;
- loop_b.e = connecting_edges_start + (i + 1) % verts_num;
- MLoop &loop_c = loops[loop_index++];
- loop_c.v = top_verts_start + (i + 1) % verts_num;
- loop_c.e = top_edges_start + i;
- }
+ for (const int i : IndexRange(config.circle_segments)) {
+ /* Go backwards to reverse surface normal. */
+ MLoop &loop = loops[loop_index++];
+ loop.v = config.last_vert - i;
+ loop.e = config.last_edge - ((i + 1) % config.circle_segments);
+ }
+ }
+}
+
+static void calculate_selection_outputs(Mesh *mesh,
+ const ConeConfig &config,
+ ConeAttributeOutputs &attribute_outputs)
+{
+ MeshComponent mesh_component;
+ mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+
+ /* Populate "Top" selection output. */
+ if (attribute_outputs.top_id) {
+ const bool face = !config.top_is_point && config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE;
+ OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>(
+ attribute_outputs.top_id.get(), face ? ATTR_DOMAIN_FACE : ATTR_DOMAIN_POINT);
+ MutableSpan<bool> selection = attribute.as_span();
+
+ if (config.top_is_point) {
+ selection[config.first_vert] = true;
}
else {
- BLI_assert(!bottom_is_point);
- for (const int i : IndexRange(verts_num)) {
- MPoly &poly = polys[poly_index++];
- poly.loopstart = loop_index;
- poly.totloop = 3;
+ selection.slice(0, face ? config.top_faces_len : config.circle_segments).fill(true);
+ }
+ attribute.save();
+ }
- MLoop &loop_a = loops[loop_index++];
- loop_a.v = bottom_verts_start + i;
- loop_a.e = bottom_edges_start + i;
- MLoop &loop_b = loops[loop_index++];
- loop_b.v = bottom_verts_start + (i + 1) % verts_num;
- loop_b.e = connecting_edges_start + (i + 1) % verts_num;
- MLoop &loop_c = loops[loop_index++];
- loop_c.v = top_verts_start;
- loop_c.e = connecting_edges_start + i;
+ /* Populate "Bottom" selection output. */
+ if (attribute_outputs.bottom_id) {
+ const bool face = !config.bottom_is_point &&
+ config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE;
+ OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>(
+ attribute_outputs.bottom_id.get(), face ? ATTR_DOMAIN_FACE : ATTR_DOMAIN_POINT);
+ MutableSpan<bool> selection = attribute.as_span();
+
+ if (config.bottom_is_point) {
+ selection[config.last_vert] = true;
+ }
+ else {
+ selection
+ .slice(config.bottom_faces_start,
+ face ? config.bottom_faces_len : config.circle_segments)
+ .fill(true);
+ }
+ attribute.save();
+ }
+
+ /* Populate "Side" selection output. */
+ if (attribute_outputs.side_id) {
+ OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>(
+ attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE);
+ MutableSpan<bool> selection = attribute.as_span();
+
+ selection.slice(config.side_faces_start, config.side_faces_len).fill(true);
+ attribute.save();
+ }
+}
+
+/**
+ * If the top is the cone tip or has a fill, it is unwrapped into a circle in the
+ * lower left quadrant of the UV.
+ * Likewise, if the bottom is the cone tip or has a fill, it is unwrapped into a circle
+ * in the lower right quadrant of the UV.
+ * If the mesh is a truncated cone or a cylinder, the side faces are unwrapped into
+ * a rectangle that fills the top half of the UV (or the entire UV, if there are no fills).
+ */
+static void calculate_cone_uvs(Mesh *mesh, const ConeConfig &config)
+{
+ MeshComponent mesh_component;
+ mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ OutputAttribute_Typed<float2> uv_attribute =
+ mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
+ MutableSpan<float2> uvs = uv_attribute.as_span();
+
+ Array<float2> circle(config.circle_segments);
+ float angle = 0.0f;
+ const float angle_delta = 2.0f * M_PI / static_cast<float>(config.circle_segments);
+ for (const int i : IndexRange(config.circle_segments)) {
+ circle[i].x = std::cos(angle) * 0.225f;
+ circle[i].y = std::sin(angle) * 0.225f;
+ angle += angle_delta;
+ }
+
+ int loop_index = 0;
+
+ /* Left circle of the UV representing the top fill or top cone tip. */
+ if (config.top_is_point || config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE) {
+ const float2 center_left(0.25f, 0.25f);
+ const float radius_factor_delta = 1.0f / (config.top_is_point ?
+ static_cast<float>(config.side_segments) :
+ static_cast<float>(config.fill_segments));
+ const int left_circle_segment_count = config.top_is_point ? config.side_segments :
+ config.fill_segments;
+
+ if (config.top_has_center_vert) {
+ /* Cone tip itself or triangle fan center of the fill. */
+ for (const int i : IndexRange(config.circle_segments)) {
+ uvs[loop_index++] = radius_factor_delta * circle[i] + center_left;
+ uvs[loop_index++] = radius_factor_delta * circle[(i + 1) % config.circle_segments] +
+ center_left;
+ uvs[loop_index++] = center_left;
+ }
+ }
+ else if (!config.top_is_point && config.fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ /* N-gon at the center of the fill. */
+ for (const int i : IndexRange(config.circle_segments)) {
+ uvs[loop_index++] = radius_factor_delta * circle[i] + center_left;
+ }
+ }
+ /* The rest of the top fill is made out of quad rings. */
+ for (const int i : IndexRange(1, left_circle_segment_count - 1)) {
+ const float inner_radius_factor = i * radius_factor_delta;
+ const float outer_radius_factor = (i + 1) * radius_factor_delta;
+ for (const int j : IndexRange(config.circle_segments)) {
+ uvs[loop_index++] = inner_radius_factor * circle[j] + center_left;
+ uvs[loop_index++] = outer_radius_factor * circle[j] + center_left;
+ uvs[loop_index++] = outer_radius_factor * circle[(j + 1) % config.circle_segments] +
+ center_left;
+ uvs[loop_index++] = inner_radius_factor * circle[(j + 1) % config.circle_segments] +
+ center_left;
}
}
}
- /* Create bottom corners and faces. */
- if (!bottom_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
- MPoly &poly = polys[poly_index++];
- poly.loopstart = loop_index;
- poly.totloop = verts_num;
+ if (!config.top_is_point && !config.bottom_is_point) {
+ /* Mesh is a truncated cone or cylinder. The sides are unwrapped into a rectangle. */
+ const float bottom = (config.fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE) ? 0.0f : 0.5f;
+ const float x_delta = 1.0f / static_cast<float>(config.circle_segments);
+ const float y_delta = (1.0f - bottom) / static_cast<float>(config.side_segments);
- for (const int i : IndexRange(verts_num)) {
- /* Go backwards to reverse surface normal. */
- MLoop &loop = loops[loop_index++];
- loop.v = bottom_verts_start + verts_num - 1 - i;
- loop.e = bottom_edges_start + verts_num - 1 - (i + 1) % verts_num;
+ for (const int i : IndexRange(config.side_segments)) {
+ for (const int j : IndexRange(config.circle_segments)) {
+ uvs[loop_index++] = float2(j * x_delta, i * y_delta + bottom);
+ uvs[loop_index++] = float2(j * x_delta, (i + 1) * y_delta + bottom);
+ uvs[loop_index++] = float2((j + 1) * x_delta, (i + 1) * y_delta + bottom);
+ uvs[loop_index++] = float2((j + 1) * x_delta, i * y_delta + bottom);
}
}
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- for (const int i : IndexRange(verts_num)) {
- MPoly &poly = polys[poly_index++];
- poly.loopstart = loop_index;
- poly.totloop = 3;
+ }
- MLoop &loop_a = loops[loop_index++];
- loop_a.v = bottom_verts_start + i;
- loop_a.e = bottom_fan_edges_start + i;
- MLoop &loop_b = loops[loop_index++];
- loop_b.v = bottom_center_vert_index;
- loop_b.e = bottom_fan_edges_start + (i + 1) % verts_num;
- MLoop &loop_c = loops[loop_index++];
- loop_c.v = bottom_verts_start + (i + 1) % verts_num;
- loop_c.e = bottom_edges_start + i;
+ /* Right circle of the UV representing the bottom fill or bottom cone tip. */
+ if (config.bottom_is_point || config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE) {
+ const float2 center_right(0.75f, 0.25f);
+ const float radius_factor_delta = 1.0f / (config.bottom_is_point ?
+ static_cast<float>(config.side_segments) :
+ static_cast<float>(config.fill_segments));
+ const int right_circle_segment_count = config.bottom_is_point ? config.side_segments :
+ config.fill_segments;
+
+ /* The bottom circle has to be created outside in to match the loop order. */
+ for (const int i : IndexRange(right_circle_segment_count - 1)) {
+ const float outer_radius_factor = 1.0f - i * radius_factor_delta;
+ const float inner_radius_factor = 1.0f - (i + 1) * radius_factor_delta;
+ for (const int j : IndexRange(config.circle_segments)) {
+ uvs[loop_index++] = outer_radius_factor * circle[j] + center_right;
+ uvs[loop_index++] = inner_radius_factor * circle[j] + center_right;
+ uvs[loop_index++] = inner_radius_factor * circle[(j + 1) % config.circle_segments] +
+ center_right;
+ uvs[loop_index++] = outer_radius_factor * circle[(j + 1) % config.circle_segments] +
+ center_right;
+ }
+ }
+
+ if (config.bottom_has_center_vert) {
+ /* Cone tip itself or triangle fan center of the fill. */
+ for (const int i : IndexRange(config.circle_segments)) {
+ uvs[loop_index++] = radius_factor_delta * circle[i] + center_right;
+ uvs[loop_index++] = center_right;
+ uvs[loop_index++] = radius_factor_delta * circle[(i + 1) % config.circle_segments] +
+ center_right;
+ }
+ }
+ else if (!config.bottom_is_point && config.fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ /* N-gon at the center of the fill. */
+ for (const int i : IndexRange(config.circle_segments)) {
+ /* Go backwards because of reversed face normal. */
+ uvs[loop_index++] = radius_factor_delta * circle[config.circle_segments - 1 - i] +
+ center_right;
}
}
}
- BKE_mesh_normals_tag_dirty(mesh);
+ uv_attribute.save();
+}
+
+static Mesh *create_vertex_mesh()
+{
+ /* Returns a mesh with a single vertex at the origin. */
+ Mesh *mesh = BKE_mesh_new_nomain(1, 0, 0, 0, 0);
+ copy_v3_fl3(mesh->mvert[0].co, 0.0f, 0.0f, 0.0f);
+ return mesh;
+}
- calculate_uvs(mesh, top_is_point, bottom_is_point, verts_num, fill_type);
+Mesh *create_cylinder_or_cone_mesh(const float radius_top,
+ const float radius_bottom,
+ const float depth,
+ const int circle_segments,
+ const int side_segments,
+ const int fill_segments,
+ const GeometryNodeMeshCircleFillType fill_type,
+ ConeAttributeOutputs &attribute_outputs)
+{
+ const ConeConfig config(
+ radius_top, radius_bottom, depth, circle_segments, side_segments, fill_segments, fill_type);
+
+ /* Handle the case of a line / single point before everything else to avoid
+ * the need to check for it later. */
+ if (config.top_is_point && config.bottom_is_point) {
+ if (config.height == 0.0f) {
+ return create_vertex_mesh();
+ }
+ const float z_delta = -2.0f * config.height / static_cast<float>(config.side_segments);
+ const float3 start(0.0f, 0.0f, config.height);
+ const float3 delta(0.0f, 0.0f, z_delta);
+ return create_line_mesh(start, delta, config.tot_verts);
+ }
+
+ Mesh *mesh = BKE_mesh_new_nomain(
+ config.tot_verts, config.tot_edges, 0, config.tot_corners, config.tot_faces);
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
+
+ MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
+ MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
+ MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
+ MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
+
+ calculate_cone_vertices(verts, config);
+ calculate_cone_edges(edges, config);
+ calculate_cone_faces(loops, polys, config);
+ calculate_cone_uvs(mesh, config);
+ calculate_selection_outputs(mesh, config, attribute_outputs);
return mesh;
}
-static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_mesh_primitive_cone_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryMeshCone)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Vertices"))
+ .default_value(32)
+ .min(3)
+ .max(512)
+ .description(N_("Number of points on the circle at the top and bottom"));
+ b.add_input<decl::Int>(N_("Side Segments"))
+ .default_value(1)
+ .min(1)
+ .max(512)
+ .description(N_("The number of edges running vertically along the side of the cone"));
+ b.add_input<decl::Int>(N_("Fill Segments"))
+ .default_value(1)
+ .min(1)
+ .max(512)
+ .description(N_("Number of concentric rings used to fill the round face"));
+ b.add_input<decl::Float>(N_("Radius Top"))
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Radius of the top circle of the cone"));
+ b.add_input<decl::Float>(N_("Radius Bottom"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Radius of the bottom circle of the cone"));
+ b.add_input<decl::Float>(N_("Depth"))
+ .default_value(2.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Height of the generated cone"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
+ b.add_output<decl::Bool>(N_("Top")).field_source();
+ b.add_output<decl::Bool>(N_("Bottom")).field_source();
+ b.add_output<decl::Bool>(N_("Side")).field_source();
+}
+
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryMeshCone *node_storage = MEM_cnew<NodeGeometryMeshCone>(__func__);
+
+ node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
+
+ node->storage = node_storage;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const bNode &node = params.node();
- const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node.storage;
+ bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *rings_socket = vertices_socket->next;
+ bNodeSocket *fill_subdiv_socket = rings_socket->next;
+
+ const NodeGeometryMeshCone &storage = node_storage(*node);
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
+ const bool has_fill = fill != GEO_NODE_MESH_CIRCLE_FILL_NONE;
+ nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill);
+}
- const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
- storage.fill_type;
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
+}
- const int verts_num = params.extract_input<int>("Vertices");
- if (verts_num < 3) {
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryMeshCone &storage = node_storage(params.node());
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
+
+ const int circle_segments = params.extract_input<int>("Vertices");
+ if (circle_segments < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3"));
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ const int side_segments = params.extract_input<int>("Side Segments");
+ if (side_segments < 1) {
+ params.error_message_add(NodeWarningType::Info, TIP_("Side Segments must be at least 1"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ const bool no_fill = fill == GEO_NODE_MESH_CIRCLE_FILL_NONE;
+ const int fill_segments = no_fill ? 1 : params.extract_input<int>("Fill Segments");
+ if (fill_segments < 1) {
+ params.error_message_add(NodeWarningType::Info, TIP_("Fill Segments must be at least 1"));
+ params.set_default_remaining_outputs();
return;
}
@@ -555,27 +823,64 @@ static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
const float radius_bottom = params.extract_input<float>("Radius Bottom");
const float depth = params.extract_input<float>("Depth");
- Mesh *mesh = create_cylinder_or_cone_mesh(
- radius_top, radius_bottom, depth, verts_num, fill_type);
+ ConeAttributeOutputs attribute_outputs;
+ if (params.output_is_required("Top")) {
+ attribute_outputs.top_id = StrongAnonymousAttributeID("top_selection");
+ }
+ if (params.output_is_required("Bottom")) {
+ attribute_outputs.bottom_id = StrongAnonymousAttributeID("bottom_selection");
+ }
+ if (params.output_is_required("Side")) {
+ attribute_outputs.side_id = StrongAnonymousAttributeID("side_selection");
+ }
+
+ Mesh *mesh = create_cylinder_or_cone_mesh(radius_top,
+ radius_bottom,
+ depth,
+ circle_segments,
+ side_segments,
+ fill_segments,
+ fill,
+ attribute_outputs);
/* Transform the mesh so that the base of the cone is at the origin. */
BKE_mesh_translate(mesh, float3(0.0f, 0.0f, depth * 0.5f), false);
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ if (attribute_outputs.top_id) {
+ params.set_output("Top",
+ AnonymousAttributeFieldInput::Create<bool>(
+ std::move(attribute_outputs.top_id), params.attribute_producer_name()));
+ }
+ if (attribute_outputs.bottom_id) {
+ params.set_output(
+ "Bottom",
+ AnonymousAttributeFieldInput::Create<bool>(std::move(attribute_outputs.bottom_id),
+ params.attribute_producer_name()));
+ }
+ if (attribute_outputs.side_id) {
+ params.set_output("Side",
+ AnonymousAttributeFieldInput::Create<bool>(
+ std::move(attribute_outputs.side_id), params.attribute_producer_name()));
+ }
+
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_cone_cc
void register_node_type_geo_mesh_primitive_cone()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_cone_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_cone_init);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryMeshCone", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cone_exec;
- ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_cone_layout;
- ntype.declare = blender::nodes::geo_node_mesh_primitive_cone_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
index af8ce02b3c1..5b67258a947 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
@@ -24,15 +24,6 @@
namespace blender::nodes {
-static void geo_node_mesh_primitive_cube_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Vector>("Size").default_value(float3(1)).min(0.0f).subtype(PROP_TRANSLATION);
- b.add_input<decl::Int>("Vertices X").default_value(2).min(2).max(1000);
- b.add_input<decl::Int>("Vertices Y").default_value(2).min(2).max(1000);
- b.add_input<decl::Int>("Vertices Z").default_value(2).min(2).max(1000);
- b.add_output<decl::Geometry>("Geometry");
-}
-
struct CuboidConfig {
float3 size;
int verts_x;
@@ -86,23 +77,37 @@ static void calculate_vertices(const CuboidConfig &config, MutableSpan<MVert> ve
int vert_index = 0;
- /* Though looping over all possible coordinates inside the cube only to skip them may be slow,
- * the alternative is similar complexity to below in the poly index calculation. If this loop
- * becomes a problem in the future it could be optimized, though only after proper performance
- * testing. */
for (const int z : IndexRange(config.verts_z)) {
- for (const int y : IndexRange(config.verts_y)) {
- for (const int x : IndexRange(config.verts_x)) {
- /* Only plot vertices on the surface of the cuboid. */
- if (ELEM(z, 0, config.edges_z) || ELEM(x, 0, config.edges_x) ||
- ELEM(y, 0, config.edges_y)) {
-
+ if (ELEM(z, 0, config.edges_z)) {
+ /* Fill bottom and top. */
+ const float z_pos = z_bottom + z_delta * z;
+ for (const int y : IndexRange(config.verts_y)) {
+ const float y_pos = y_front + y_delta * y;
+ for (const int x : IndexRange(config.verts_x)) {
const float x_pos = x_left + x_delta * x;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
+ }
+ }
+ }
+ else {
+ for (const int y : IndexRange(config.verts_y)) {
+ if (ELEM(y, 0, config.edges_y)) {
+ /* Fill y-sides. */
const float y_pos = y_front + y_delta * y;
const float z_pos = z_bottom + z_delta * z;
- copy_v3_v3(verts[vert_index].co, float3(x_pos, y_pos, z_pos));
-
- vert_index++;
+ for (const int x : IndexRange(config.verts_x)) {
+ const float x_pos = x_left + x_delta * x;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
+ }
+ }
+ else {
+ /* Fill x-sides. */
+ const float x_pos = x_left;
+ const float y_pos = y_front + y_delta * y;
+ const float z_pos = z_bottom + z_delta * z;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
+ const float x_pos2 = x_left + x_delta * config.edges_x;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos2, y_pos, z_pos));
}
}
}
@@ -150,7 +155,7 @@ static void calculate_polys(const CuboidConfig &config,
/* Calculate polys for Bottom faces. */
int vert_1_start = 0;
- for (const int UNUSED(y) : IndexRange(config.edges_y)) {
+ for ([[maybe_unused]] const int y : IndexRange(config.edges_y)) {
for (const int x : IndexRange(config.edges_x)) {
const int vert_1 = vert_1_start + x;
const int vert_2 = vert_1_start + config.verts_x + x;
@@ -168,7 +173,7 @@ static void calculate_polys(const CuboidConfig &config,
vert_1_start = 0;
int vert_2_start = config.verts_x * config.verts_y;
- for (const int UNUSED(z) : IndexRange(config.edges_z)) {
+ for ([[maybe_unused]] const int z : IndexRange(config.edges_z)) {
for (const int x : IndexRange(config.edges_x)) {
define_quad(polys,
loops,
@@ -191,7 +196,7 @@ static void calculate_polys(const CuboidConfig &config,
(config.verts_x - 2) * (config.verts_y - 2));
vert_2_start = vert_1_start + config.verts_x;
- for (const int UNUSED(y) : IndexRange(config.edges_y)) {
+ for ([[maybe_unused]] const int y : IndexRange(config.edges_y)) {
for (const int x : IndexRange(config.edges_x)) {
define_quad(polys,
loops,
@@ -423,6 +428,35 @@ Mesh *create_cuboid_mesh(const float3 size,
return mesh;
}
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_mesh_primitive_cube_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Size"))
+ .default_value(float3(1))
+ .min(0.0f)
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Side length along each axis"));
+ b.add_input<decl::Int>(N_("Vertices X"))
+ .default_value(2)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices for the X side of the shape"));
+ b.add_input<decl::Int>(N_("Vertices Y"))
+ .default_value(2)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices for the Y side of the shape"));
+ b.add_input<decl::Int>(N_("Vertices Z"))
+ .default_value(2)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices for the Z side of the shape"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
+}
+
static Mesh *create_cube_mesh(const float3 size,
const int verts_x,
const int verts_y,
@@ -456,19 +490,19 @@ static Mesh *create_cube_mesh(const float3 size,
}
if (verts_y == 1) { /* XZ plane. */
Mesh *mesh = create_grid_mesh(verts_x, verts_z, size.x, size.z);
- transform_mesh(mesh, float3(0), float3(M_PI_2, 0.0f, 0.0f), float3(1));
+ transform_mesh(*mesh, float3(0), float3(M_PI_2, 0.0f, 0.0f), float3(1));
return mesh;
}
/* YZ plane. */
Mesh *mesh = create_grid_mesh(verts_z, verts_y, size.z, size.y);
- transform_mesh(mesh, float3(0), float3(0.0f, M_PI_2, 0.0f), float3(1));
+ transform_mesh(*mesh, float3(0), float3(0.0f, M_PI_2, 0.0f), float3(1));
return mesh;
}
return create_cuboid_mesh(size, verts_x, verts_y, verts_z);
}
-static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const float3 size = params.extract_input<float3>("Size");
const int verts_x = params.extract_input<int>("Vertices X");
@@ -476,23 +510,25 @@ static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params)
const int verts_z = params.extract_input<int>("Vertices Z");
if (verts_x < 1 || verts_y < 1 || verts_z < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 1"));
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
Mesh *mesh = create_cube_mesh(size, verts_x, verts_y, verts_z);
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_cube_cc
void register_node_type_geo_mesh_primitive_cube()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_cube_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_cube_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cube_exec;
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
index 8c4defc3ca3..73f21cf31fa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
@@ -25,81 +25,155 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_cylinder_cc {
-static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryMeshCylinder)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Vertices")
+ b.add_input<decl::Int>(N_("Vertices"))
.default_value(32)
.min(3)
- .max(4096)
- .description("The number of vertices around the circumference");
- b.add_input<decl::Float>("Radius")
+ .max(512)
+ .description(N_("The number of vertices on the top and bottom circles"));
+ b.add_input<decl::Int>(N_("Side Segments"))
+ .default_value(1)
+ .min(1)
+ .max(512)
+ .description(N_("The number of rectangular segments along each side"));
+ b.add_input<decl::Int>(N_("Fill Segments"))
+ .default_value(1)
+ .min(1)
+ .max(512)
+ .description(N_("The number of concentric rings used to fill the round faces"));
+ b.add_input<decl::Float>(N_("Radius"))
.default_value(1.0f)
.min(0.0f)
.subtype(PROP_DISTANCE)
- .description("The radius of the cylinder");
- b.add_input<decl::Float>("Depth")
+ .description(N_("The radius of the cylinder"));
+ b.add_input<decl::Float>(N_("Depth"))
.default_value(2.0f)
.min(0.0f)
.subtype(PROP_DISTANCE)
- .description("The height of the cylinder on the Z axis");
- b.add_output<decl::Geometry>("Geometry");
+ .description(N_("The height of the cylinder"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
+ b.add_output<decl::Bool>(N_("Top")).field_source();
+ b.add_output<decl::Bool>(N_("Side")).field_source();
+ b.add_output<decl::Bool>(N_("Bottom")).field_source();
}
-static void geo_node_mesh_primitive_cylinder_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
}
-static void geo_node_mesh_primitive_cylinder_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshCylinder *node_storage = (NodeGeometryMeshCylinder *)MEM_callocN(
- sizeof(NodeGeometryMeshCylinder), __func__);
+ NodeGeometryMeshCylinder *node_storage = MEM_cnew<NodeGeometryMeshCylinder>(__func__);
node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
node->storage = node_storage;
}
-static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const bNode &node = params.node();
- const NodeGeometryMeshCylinder &storage = *(const NodeGeometryMeshCylinder *)node.storage;
+ bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *rings_socket = vertices_socket->next;
+ bNodeSocket *fill_subdiv_socket = rings_socket->next;
+
+ const NodeGeometryMeshCylinder &storage = node_storage(*node);
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
+ const bool has_fill = fill != GEO_NODE_MESH_CIRCLE_FILL_NONE;
+ nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill);
+}
- const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
- storage.fill_type;
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryMeshCylinder &storage = node_storage(params.node());
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
const float radius = params.extract_input<float>("Radius");
const float depth = params.extract_input<float>("Depth");
- const int verts_num = params.extract_input<int>("Vertices");
- if (verts_num < 3) {
+ const int circle_segments = params.extract_input<int>("Vertices");
+ if (circle_segments < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3"));
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ const int side_segments = params.extract_input<int>("Side Segments");
+ if (side_segments < 1) {
+ params.error_message_add(NodeWarningType::Info, TIP_("Side Segments must be at least 1"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ const bool no_fill = fill == GEO_NODE_MESH_CIRCLE_FILL_NONE;
+ const int fill_segments = no_fill ? 1 : params.extract_input<int>("Fill Segments");
+ if (fill_segments < 1) {
+ params.error_message_add(NodeWarningType::Info, TIP_("Fill Segments must be at least 1"));
+ params.set_default_remaining_outputs();
return;
}
+ ConeAttributeOutputs attribute_outputs;
+ if (params.output_is_required("Top")) {
+ attribute_outputs.top_id = StrongAnonymousAttributeID("top_selection");
+ }
+ if (params.output_is_required("Bottom")) {
+ attribute_outputs.bottom_id = StrongAnonymousAttributeID("bottom_selection");
+ }
+ if (params.output_is_required("Side")) {
+ attribute_outputs.side_id = StrongAnonymousAttributeID("side_selection");
+ }
+
/* The cylinder is a special case of the cone mesh where the top and bottom radius are equal. */
- Mesh *mesh = create_cylinder_or_cone_mesh(radius, radius, depth, verts_num, fill_type);
+ Mesh *mesh = create_cylinder_or_cone_mesh(radius,
+ radius,
+ depth,
+ circle_segments,
+ side_segments,
+ fill_segments,
+ fill,
+ attribute_outputs);
+
+ if (attribute_outputs.top_id) {
+ params.set_output("Top",
+ AnonymousAttributeFieldInput::Create<bool>(
+ std::move(attribute_outputs.top_id), params.attribute_producer_name()));
+ }
+ if (attribute_outputs.bottom_id) {
+ params.set_output(
+ "Bottom",
+ AnonymousAttributeFieldInput::Create<bool>(std::move(attribute_outputs.bottom_id),
+ params.attribute_producer_name()));
+ }
+ if (attribute_outputs.side_id) {
+ params.set_output("Side",
+ AnonymousAttributeFieldInput::Create<bool>(
+ std::move(attribute_outputs.side_id), params.attribute_producer_name()));
+ }
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_cylinder_cc
void register_node_type_geo_mesh_primitive_cylinder()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_cylinder_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_cylinder_init);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryMeshCylinder", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_cylinder_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cylinder_exec;
- ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_cylinder_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
index 858ef8648f8..ecb3c785212 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
@@ -14,6 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BLI_task.hh"
+
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -27,15 +29,6 @@
namespace blender::nodes {
-static void geo_node_mesh_primitive_grid_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Float>("Size X").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Size Y").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Int>("Vertices X").default_value(3).min(2).max(1000);
- b.add_input<decl::Int>("Vertices Y").default_value(3).min(2).max(1000);
- b.add_output<decl::Geometry>("Geometry");
-}
-
static void calculate_uvs(
Mesh *mesh, Span<MVert> verts, Span<MLoop> loops, const float size_x, const float size_y)
{
@@ -47,11 +40,13 @@ static void calculate_uvs(
const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x;
const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y;
- for (const int i : loops.index_range()) {
- const float3 &co = verts[loops[i].v].co;
- uvs[i].x = (co.x + size_x * 0.5f) * dx;
- uvs[i].y = (co.y + size_y * 0.5f) * dy;
- }
+ threading::parallel_for(loops.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ const float3 &co = verts[loops[i].v].co;
+ uvs[i].x = (co.x + size_x * 0.5f) * dx;
+ uvs[i].y = (co.y + size_y * 0.5f) * dy;
+ }
+ });
uv_attribute.save();
}
@@ -79,72 +74,87 @@ Mesh *create_grid_mesh(const int verts_x,
const float dy = edges_y == 0 ? 0.0f : size_y / edges_y;
const float x_shift = edges_x / 2.0f;
const float y_shift = edges_y / 2.0f;
- for (const int x_index : IndexRange(verts_x)) {
- for (const int y_index : IndexRange(verts_y)) {
- const int vert_index = x_index * verts_y + y_index;
- verts[vert_index].co[0] = (x_index - x_shift) * dx;
- verts[vert_index].co[1] = (y_index - y_shift) * dy;
- verts[vert_index].co[2] = 0.0f;
+ threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int y_offset = x * verts_y;
+ threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int vert_index = y_offset + y;
+ verts[vert_index].co[0] = (x - x_shift) * dx;
+ verts[vert_index].co[1] = (y - y_shift) * dy;
+ verts[vert_index].co[2] = 0.0f;
+ }
+ });
}
- }
- }
-
- /* Point all vertex normals in the up direction. */
- const short up_normal[3] = {0, 0, SHRT_MAX};
- for (MVert &vert : verts) {
- copy_v3_v3_short(vert.no, up_normal);
+ });
}
- /* Build the horizontal edges in the X direction. */
const int y_edges_start = 0;
+ const int x_edges_start = verts_x * edges_y;
const short edge_flag = (edges_x == 0 || edges_y == 0) ? ME_LOOSEEDGE :
ME_EDGEDRAW | ME_EDGERENDER;
- int edge_index = 0;
- for (const int x : IndexRange(verts_x)) {
- for (const int y : IndexRange(edges_y)) {
- const int vert_index = x * verts_y + y;
- MEdge &edge = edges[edge_index++];
- edge.v1 = vert_index;
- edge.v2 = vert_index + 1;
- edge.flag = edge_flag;
+
+ /* Build the horizontal edges in the X direction. */
+ threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int y_vert_offset = x * verts_y;
+ const int y_edge_offset = y_edges_start + x * edges_y;
+ threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int vert_index = y_vert_offset + y;
+ MEdge &edge = edges[y_edge_offset + y];
+ edge.v1 = vert_index;
+ edge.v2 = vert_index + 1;
+ edge.flag = edge_flag;
+ }
+ });
}
- }
+ });
/* Build the vertical edges in the Y direction. */
- const int x_edges_start = edge_index;
- for (const int y : IndexRange(verts_y)) {
- for (const int x : IndexRange(edges_x)) {
- const int vert_index = x * verts_y + y;
- MEdge &edge = edges[edge_index++];
- edge.v1 = vert_index;
- edge.v2 = vert_index + verts_y;
- edge.flag = edge_flag;
+ threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int x_edge_offset = x_edges_start + y * edges_x;
+ threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int vert_index = x * verts_y + y;
+ MEdge &edge = edges[x_edge_offset + x];
+ edge.v1 = vert_index;
+ edge.v2 = vert_index + verts_y;
+ edge.flag = edge_flag;
+ }
+ });
}
- }
-
- int loop_index = 0;
- int poly_index = 0;
- for (const int x : IndexRange(edges_x)) {
- for (const int y : IndexRange(edges_y)) {
- MPoly &poly = polys[poly_index++];
- poly.loopstart = loop_index;
- poly.totloop = 4;
- const int vert_index = x * verts_y + y;
-
- MLoop &loop_a = loops[loop_index++];
- loop_a.v = vert_index;
- loop_a.e = x_edges_start + edges_x * y + x;
- MLoop &loop_b = loops[loop_index++];
- loop_b.v = vert_index + verts_y;
- loop_b.e = y_edges_start + edges_y * (x + 1) + y;
- MLoop &loop_c = loops[loop_index++];
- loop_c.v = vert_index + verts_y + 1;
- loop_c.e = x_edges_start + edges_x * (y + 1) + x;
- MLoop &loop_d = loops[loop_index++];
- loop_d.v = vert_index + 1;
- loop_d.e = y_edges_start + edges_y * x + y;
+ });
+
+ threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int y_offset = x * edges_y;
+ threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int poly_index = y_offset + y;
+ const int loop_index = poly_index * 4;
+ MPoly &poly = polys[poly_index];
+ poly.loopstart = loop_index;
+ poly.totloop = 4;
+ const int vert_index = x * verts_y + y;
+
+ MLoop &loop_a = loops[loop_index];
+ loop_a.v = vert_index;
+ loop_a.e = x_edges_start + edges_x * y + x;
+ MLoop &loop_b = loops[loop_index + 1];
+ loop_b.v = vert_index + verts_y;
+ loop_b.e = y_edges_start + edges_y * (x + 1) + y;
+ MLoop &loop_c = loops[loop_index + 2];
+ loop_c.v = vert_index + verts_y + 1;
+ loop_c.e = x_edges_start + edges_x * (y + 1) + x;
+ MLoop &loop_d = loops[loop_index + 3];
+ loop_d.v = vert_index + 1;
+ loop_d.e = y_edges_start + edges_y * x + y;
+ }
+ });
}
- }
+ });
if (mesh->totpoly != 0) {
calculate_uvs(mesh, verts, loops, size_x, size_y);
@@ -153,32 +163,62 @@ Mesh *create_grid_mesh(const int verts_x,
return mesh;
}
-static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params)
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_mesh_primitive_grid_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Size X"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Side length of the plane in the X direction"));
+ b.add_input<decl::Float>(N_("Size Y"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Side length of the plane in the Y direction"));
+ b.add_input<decl::Int>(N_("Vertices X"))
+ .default_value(3)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices in the X direction"));
+ b.add_input<decl::Int>(N_("Vertices Y"))
+ .default_value(3)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices in the Y direction"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
{
const float size_x = params.extract_input<float>("Size X");
const float size_y = params.extract_input<float>("Size Y");
const int verts_x = params.extract_input<int>("Vertices X");
const int verts_y = params.extract_input<int>("Vertices Y");
if (verts_x < 1 || verts_y < 1) {
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
Mesh *mesh = create_grid_mesh(verts_x, verts_y, size_x, size_y);
- BLI_assert(BKE_mesh_is_valid(mesh));
BKE_id_material_eval_ensure_default_slot(&mesh->id);
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_grid_cc
void register_node_type_geo_mesh_primitive_grid()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_grid_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_grid_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_grid_exec;
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
index 5ea7165ac31..28a505c5bb8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
@@ -24,22 +24,31 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc {
-static void geo_node_mesh_primitive_ico_sphere_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Radius").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Int>("Subdivisions").default_value(1).min(1).max(7);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Float>(N_("Radius"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Distance from the generated points to the origin"));
+ b.add_input<decl::Int>(N_("Subdivisions"))
+ .default_value(1)
+ .min(1)
+ .max(7)
+ .description(N_("Number of subdivisions on top of the basic icosahedron"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static Mesh *create_ico_sphere_mesh(const int subdivisions, const float radius)
{
const float4x4 transform = float4x4::identity();
- const BMeshCreateParams bmcp = {true};
+ BMeshCreateParams bmesh_create_params{};
+ bmesh_create_params.use_toolflags = true;
const BMAllocTemplate allocsize = {0, 0, 0, 0};
- BMesh *bm = BM_mesh_create(&allocsize, &bmcp);
+ BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params);
BM_data_layer_add_named(bm, &bm->ldata, CD_MLOOPUV, nullptr);
BMO_op_callf(bm,
@@ -60,24 +69,26 @@ static Mesh *create_ico_sphere_mesh(const int subdivisions, const float radius)
return mesh;
}
-static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const int subdivisions = std::min(params.extract_input<int>("Subdivisions"), 10);
const float radius = params.extract_input<float>("Radius");
Mesh *mesh = create_ico_sphere_mesh(subdivisions, radius);
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc
void register_node_type_geo_mesh_primitive_ico_sphere()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_ico_sphere_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_ico_sphere_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_ico_sphere_exec;
+ &ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
index 031223b5ca6..691267bccb8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
@@ -23,22 +23,39 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_line_cc {
-static void geo_node_mesh_primitive_line_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryMeshLine)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Count").default_value(10).min(1).max(10000);
- b.add_input<decl::Float>("Resolution").default_value(1.0f).min(0.1f).subtype(PROP_DISTANCE);
- b.add_input<decl::Vector>("Start Location").subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Offset").default_value({0.0f, 0.0f, 1.0f}).subtype(PROP_TRANSLATION);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Int>(N_("Count"))
+ .default_value(10)
+ .min(1)
+ .max(10000)
+ .description(N_("Number of vertices on the line"));
+ b.add_input<decl::Float>(N_("Resolution"))
+ .default_value(1.0f)
+ .min(0.1f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Length of each individual edge"));
+ b.add_input<decl::Vector>(N_("Start Location"))
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Position of the first vertex"));
+ b.add_input<decl::Vector>(N_("Offset"))
+ .default_value({0.0f, 0.0f, 1.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(N_(
+ "In offset mode, the distance between each socket on each axis. In end points mode, the "
+ "position of the final vertex"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_mesh_primitive_line_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -48,10 +65,9 @@ static void geo_node_mesh_primitive_line_layout(uiLayout *layout,
}
}
-static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshLine *node_storage = (NodeGeometryMeshLine *)MEM_callocN(
- sizeof(NodeGeometryMeshLine), __func__);
+ NodeGeometryMeshLine *node_storage = MEM_cnew<NodeGeometryMeshLine>(__func__);
node_storage->mode = GEO_NODE_MESH_LINE_MODE_OFFSET;
node_storage->count_mode = GEO_NODE_MESH_LINE_COUNT_TOTAL;
@@ -59,68 +75,74 @@ static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *n
node->storage = node_storage;
}
-static void geo_node_mesh_primitive_line_update(bNodeTree *UNUSED(tree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *count_socket = (bNodeSocket *)node->inputs.first;
bNodeSocket *resolution_socket = count_socket->next;
bNodeSocket *start_socket = resolution_socket->next;
bNodeSocket *end_and_offset_socket = start_socket->next;
- const NodeGeometryMeshLine &storage = *(const NodeGeometryMeshLine *)node->storage;
- const GeometryNodeMeshLineMode mode = (const GeometryNodeMeshLineMode)storage.mode;
- const GeometryNodeMeshLineCountMode count_mode = (const GeometryNodeMeshLineCountMode)
+ const NodeGeometryMeshLine &storage = node_storage(*node);
+ const GeometryNodeMeshLineMode mode = (GeometryNodeMeshLineMode)storage.mode;
+ const GeometryNodeMeshLineCountMode count_mode = (GeometryNodeMeshLineCountMode)
storage.count_mode;
node_sock_label(end_and_offset_socket,
(mode == GEO_NODE_MESH_LINE_MODE_END_POINTS) ? N_("End Location") :
N_("Offset"));
- nodeSetSocketAvailability(resolution_socket,
+ nodeSetSocketAvailability(ntree,
+ resolution_socket,
mode == GEO_NODE_MESH_LINE_MODE_END_POINTS &&
count_mode == GEO_NODE_MESH_LINE_COUNT_RESOLUTION);
- nodeSetSocketAvailability(count_socket,
+ nodeSetSocketAvailability(ntree,
+ count_socket,
mode == GEO_NODE_MESH_LINE_MODE_OFFSET ||
count_mode == GEO_NODE_MESH_LINE_COUNT_TOTAL);
}
-static void fill_edge_data(MutableSpan<MEdge> edges)
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
{
- for (const int i : edges.index_range()) {
- edges[i].v1 = i;
- edges[i].v2 = i + 1;
- edges[i].flag |= ME_LOOSEEDGE;
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ if (params.in_out() == SOCK_OUT) {
+ search_link_ops_for_declarations(params, declaration.outputs());
+ return;
}
-}
-
-Mesh *create_line_mesh(const float3 start, const float3 delta, const int count)
-{
- if (count < 1) {
- return nullptr;
+ else if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ params.add_item(IFACE_("Count"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ node_storage(node).mode = GEO_NODE_MESH_LINE_MODE_OFFSET;
+ params.connect_available_socket(node, "Count");
+ });
+ params.add_item(IFACE_("Resolution"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ node_storage(node).mode = GEO_NODE_MESH_LINE_MODE_OFFSET;
+ node_storage(node).count_mode = GEO_NODE_MESH_LINE_COUNT_RESOLUTION;
+ params.connect_available_socket(node, "Resolution");
+ });
+ params.add_item(IFACE_("Start Location"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ params.connect_available_socket(node, "Start Location");
+ });
+ params.add_item(IFACE_("Offset"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ params.connect_available_socket(node, "Offset");
+ });
+ /* The last socket is reused in end points mode. */
+ params.add_item(IFACE_("End Location"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ node_storage(node).mode = GEO_NODE_MESH_LINE_MODE_END_POINTS;
+ params.connect_available_socket(node, "Offset");
+ });
}
-
- Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0);
- BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
- MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
-
- short normal[3];
- normal_float_to_short_v3(normal, delta.normalized());
-
- for (const int i : verts.index_range()) {
- copy_v3_v3(verts[i].co, start + delta * i);
- copy_v3_v3_short(verts[i].no, normal);
- }
-
- fill_edge_data(edges);
-
- return mesh;
}
-static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryMeshLine &storage = *(const NodeGeometryMeshLine *)params.node().storage;
- const GeometryNodeMeshLineMode mode = (const GeometryNodeMeshLineMode)storage.mode;
- const GeometryNodeMeshLineCountMode count_mode = (const GeometryNodeMeshLineCountMode)
+ const NodeGeometryMeshLine &storage = node_storage(params.node());
+ const GeometryNodeMeshLineMode mode = (GeometryNodeMeshLineMode)storage.mode;
+ const GeometryNodeMeshLineCountMode count_mode = (GeometryNodeMeshLineCountMode)
storage.count_mode;
Mesh *mesh = nullptr;
@@ -133,8 +155,8 @@ static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params)
if (count_mode == GEO_NODE_MESH_LINE_COUNT_RESOLUTION) {
/* Don't allow asymptotic count increase for low resolution values. */
const float resolution = std::max(params.extract_input<float>("Resolution"), 0.0001f);
- const int count = total_delta.length() / resolution + 1;
- const float3 delta = total_delta.normalized() * resolution;
+ const int count = math::length(total_delta) / resolution + 1;
+ const float3 delta = math::normalize(total_delta) * resolution;
mesh = create_line_mesh(start, delta, count);
}
else if (count_mode == GEO_NODE_MESH_LINE_COUNT_TOTAL) {
@@ -154,22 +176,58 @@ static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params)
mesh = create_line_mesh(start, delta, count);
}
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
+}
+
+} // namespace blender::nodes::node_geo_mesh_primitive_line_cc
+
+namespace blender::nodes {
+
+static void fill_edge_data(MutableSpan<MEdge> edges)
+{
+ for (const int i : edges.index_range()) {
+ edges[i].v1 = i;
+ edges[i].v2 = i + 1;
+ edges[i].flag |= ME_LOOSEEDGE;
+ }
+}
+
+Mesh *create_line_mesh(const float3 start, const float3 delta, const int count)
+{
+ if (count < 1) {
+ return nullptr;
+ }
+
+ Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0);
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
+ MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
+ MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
+
+ for (const int i : verts.index_range()) {
+ copy_v3_v3(verts[i].co, start + delta * i);
+ }
+
+ fill_edge_data(edges);
+
+ return mesh;
}
} // namespace blender::nodes
void register_node_type_geo_mesh_primitive_line()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_line_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_line_declare;
- node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_line_init);
- node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_line_update);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryMeshLine", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_line_exec;
- ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_line_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
index 6fd6cdf5747..751cf917f6f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
@@ -25,14 +25,26 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc {
-static void geo_node_mesh_primitive_uv_shpere_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Segments").default_value(32).min(3).max(1024);
- b.add_input<decl::Int>("Rings").default_value(16).min(2).max(1024);
- b.add_input<decl::Float>("Radius").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Int>(N_("Segments"))
+ .default_value(32)
+ .min(3)
+ .max(1024)
+ .description(N_("Horizontal resolution of the sphere"));
+ b.add_input<decl::Int>(N_("Rings"))
+ .default_value(16)
+ .min(2)
+ .max(1024)
+ .description(N_("The number of horizontal rings"));
+ b.add_input<decl::Float>(N_("Radius"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Distance from the generated points to the origin"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static int sphere_vert_total(const int segments, const int rings)
@@ -59,7 +71,12 @@ static int sphere_face_total(const int segments, const int rings)
return quads + triangles;
}
+/**
+ * Also calculate vertex normals here, since the calculation is trivial, and it allows avoiding the
+ * calculation later, if it's necessary. The vertex normals are just the normalized positions.
+ */
static void calculate_sphere_vertex_data(MutableSpan<MVert> verts,
+ MutableSpan<float3> vert_normals,
const float radius,
const int segments,
const int rings)
@@ -68,7 +85,7 @@ static void calculate_sphere_vertex_data(MutableSpan<MVert> verts,
const float delta_phi = (2.0f * M_PI) / segments;
copy_v3_v3(verts[0].co, float3(0.0f, 0.0f, radius));
- normal_float_to_short_v3(verts[0].no, float3(0.0f, 0.0f, 1.0f));
+ vert_normals.first() = float3(0.0f, 0.0f, 1.0f);
int vert_index = 1;
for (const int ring : IndexRange(1, rings - 1)) {
@@ -80,13 +97,13 @@ static void calculate_sphere_vertex_data(MutableSpan<MVert> verts,
const float x = sin_theta * std::cos(phi);
const float y = sin_theta * std::sin(phi);
copy_v3_v3(verts[vert_index].co, float3(x, y, z) * radius);
- normal_float_to_short_v3(verts[vert_index].no, float3(x, y, z));
+ vert_normals[vert_index] = float3(x, y, z);
vert_index++;
}
}
copy_v3_v3(verts.last().co, float3(0.0f, 0.0f, -radius));
- normal_float_to_short_v3(verts.last().no, float3(0.0f, 0.0f, -1.0f));
+ vert_normals.last() = float3(0.0f, 0.0f, -1.0f);
}
static void calculate_sphere_edge_indices(MutableSpan<MEdge> edges,
@@ -166,7 +183,7 @@ static void calculate_sphere_faces(MutableSpan<MLoop> loops,
int ring_vert_index_start = 1;
int ring_edge_index_start = segments;
- for (const int UNUSED(ring) : IndexRange(1, rings - 2)) {
+ for ([[maybe_unused]] const int ring : IndexRange(1, rings - 2)) {
const int next_ring_vert_index_start = ring_vert_index_start + segments;
const int next_ring_edge_index_start = ring_edge_index_start + segments * 2;
const int ring_vertical_edge_index_start = ring_edge_index_start + segments;
@@ -267,7 +284,9 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const
MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
- calculate_sphere_vertex_data(verts, radius, segments, rings);
+ MutableSpan vert_normals{(float3 *)BKE_mesh_vertex_normals_for_write(mesh), mesh->totvert};
+ calculate_sphere_vertex_data(verts, vert_normals, radius, segments, rings);
+ BKE_mesh_vertex_normals_clear_dirty(mesh);
calculate_sphere_edge_indices(edges, segments, rings);
@@ -275,12 +294,10 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const
calculate_sphere_uvs(mesh, segments, rings);
- BLI_assert(BKE_mesh_is_valid(mesh));
-
return mesh;
}
-static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const int segments_num = params.extract_input<int>("Segments");
const int rings_num = params.extract_input<int>("Rings");
@@ -291,25 +308,26 @@ static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params)
if (rings_num < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Rings must be at least 3"));
}
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
const float radius = params.extract_input<float>("Radius");
Mesh *mesh = create_uv_sphere_mesh(radius, segments_num, rings_num);
- params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc
void register_node_type_geo_mesh_primitive_uv_sphere()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_uv_sphere_cc;
+
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_uv_shpere_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_uv_sphere_exec;
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
index c436f5bd480..6d8a2fac8ad 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
@@ -23,13 +23,13 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_subdivide_cc {
-static void geo_node_mesh_subdivide_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Int>("Level").default_value(1).min(0).max(6);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
static void geometry_set_mesh_subdivide(GeometrySet &geometry_set, const int level)
@@ -72,14 +72,14 @@ static void geometry_set_mesh_subdivide(GeometrySet &geometry_set, const int lev
BKE_subdiv_free(subdiv);
}
-static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
#ifndef WITH_OPENSUBDIV
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenSubdiv"));
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_default_remaining_outputs();
return;
#endif
@@ -87,24 +87,26 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
const int subdiv_level = clamp_i(params.extract_input<int>("Level"), 0, 11);
if (subdiv_level == 0) {
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Mesh", std::move(geometry_set));
return;
}
geometry_set.modify_geometry_sets(
[&](GeometrySet &geometry_set) { geometry_set_mesh_subdivide(geometry_set, subdiv_level); });
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_subdivide_cc
void register_node_type_geo_mesh_subdivide()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_subdivide_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_SUBDIVIDE, "Mesh Subdivide", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_subdivide_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_subdivide_exec;
+ geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_MESH, "Subdivide Mesh", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
new file mode 100644
index 00000000000..0f0fb3c230a
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -0,0 +1,71 @@
+/*
+ * 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 "GEO_mesh_to_curve.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_mesh_to_curve_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (!geometry_set.has_mesh()) {
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
+ return;
+ }
+
+ const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
+ GeometryComponentFieldContext context{component, ATTR_DOMAIN_EDGE};
+ fn::FieldEvaluator evaluator{context, component.attribute_domain_size(ATTR_DOMAIN_EDGE)};
+ evaluator.add(params.get_input<Field<bool>>("Selection"));
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+ if (selection.size() == 0) {
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
+ return;
+ }
+
+ std::unique_ptr<CurveEval> curve = geometry::mesh_to_curve_convert(component, selection);
+ geometry_set.replace_curve(curve.release());
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_CURVE, GEO_COMPONENT_TYPE_INSTANCES});
+ });
+
+ params.set_output("Curve", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_mesh_to_curve_cc
+
+void register_node_type_geo_mesh_to_curve()
+{
+ namespace file_ns = blender::nodes::node_geo_mesh_to_curve_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
index 2f59a3c968b..d0546cd2583 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
@@ -26,31 +26,32 @@
using blender::Array;
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_to_points_cc {
-static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryMeshToPoints)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Mesh");
- b.add_input<decl::Vector>("Position").implicit_field();
- b.add_input<decl::Float>("Radius")
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
+ b.add_input<decl::Vector>(N_("Position")).implicit_field();
+ b.add_input<decl::Float>(N_("Radius"))
.default_value(0.05f)
.min(0.0f)
.subtype(PROP_DISTANCE)
.supports_field();
- b.add_input<decl::Bool>("Selection").default_value(true).supports_field().hide_value();
- b.add_output<decl::Geometry>("Points");
+ b.add_output<decl::Geometry>(N_("Points"));
}
-static void geo_node_mesh_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void geo_node_mesh_to_points_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryMeshToPoints *data = (NodeGeometryMeshToPoints *)MEM_callocN(
- sizeof(NodeGeometryMeshToPoints), __func__);
- data->mode = GEO_NODE_MESH_TO_POINTS_FACES;
+ NodeGeometryMeshToPoints *data = MEM_cnew<NodeGeometryMeshToPoints>(__func__);
+ data->mode = GEO_NODE_MESH_TO_POINTS_VERTICES;
node->storage = data;
}
@@ -81,10 +82,15 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ /* Evaluating directly into the point cloud doesn't work because we are not using the full
+ * "min_array_size" array but compressing the selected elements into the final array with no
+ * gaps. */
+ evaluator.add(position_field);
+ evaluator.add(radius_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
@@ -92,13 +98,6 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
PointCloudComponent &point_component =
geometry_set.get_component_for_write<PointCloudComponent>();
- /* Evaluating directly into the point cloud doesn't work because we are not using the full
- * "min_array_size" array but compressing the selected elements into the final array with no
- * gaps. */
- fn::FieldEvaluator evaluator{field_context, &selection};
- evaluator.add(position_field);
- evaluator.add(radius_field);
- evaluator.evaluate();
copy_attribute_to_points(evaluator.get_evaluated<float3>(0),
selection,
{(float3 *)pointcloud->co, pointcloud->totpoint});
@@ -113,14 +112,14 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
const CustomDataType data_type = entry.value.data_type;
- GVArrayPtr src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type);
+ GVArray src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type);
OutputAttribute dst = point_component.attribute_try_get_for_output_only(
attribute_id, ATTR_DOMAIN_POINT, data_type);
if (dst && src) {
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
- GVArray_Typed<T> src_typed{*src};
- copy_attribute_to_points(*src_typed, selection, dst.as_span().typed<T>());
+ VArray<T> src_typed = src.typed<T>();
+ copy_attribute_to_points(src_typed, selection, dst.as_span().typed<T>());
});
dst.save();
}
@@ -129,7 +128,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
geometry_set.keep_only({GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_INSTANCES});
}
-static void geo_node_mesh_to_points_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
Field<float3> position = params.extract_input<Field<float3>>("Position");
@@ -144,8 +143,7 @@ static void geo_node_mesh_to_points_exec(GeoNodeExecParams params)
FieldOperation(max_zero_fn, {std::move(radius)}));
Field<float> positive_radius(std::move(max_zero_op), 0);
- const NodeGeometryMeshToPoints &storage =
- *(const NodeGeometryMeshToPoints *)params.node().storage;
+ const NodeGeometryMeshToPoints &storage = node_storage(params.node());
const GeometryNodeMeshToPointsMode mode = (GeometryNodeMeshToPointsMode)storage.mode;
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
@@ -172,17 +170,19 @@ static void geo_node_mesh_to_points_exec(GeoNodeExecParams params)
params.set_output("Points", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_to_points_cc
void register_node_type_geo_mesh_to_points()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_to_points_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_TO_POINTS, "Mesh to Points", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_to_points_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_to_points_exec;
- node_type_init(&ntype, blender::nodes::geo_node_mesh_to_points_init);
- ntype.draw_buttons = blender::nodes::geo_node_mesh_to_points_layout;
+ geo_node_type_base(&ntype, GEO_NODE_MESH_TO_POINTS, "Mesh to Points", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryMeshToPoints", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
index 389acc40f0f..d32875d2627 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
@@ -21,92 +21,106 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_object_info_cc {
-static void geo_node_object_info_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryObjectInfo)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Object>("Object").hide_label();
- b.add_output<decl::Vector>("Location");
- b.add_output<decl::Vector>("Rotation");
- b.add_output<decl::Vector>("Scale");
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Object>(N_("Object")).hide_label();
+ b.add_input<decl::Bool>(N_("As Instance"))
+ .description(N_("Output the entire object as single instance. "
+ "This allows instancing non-geometry object types"));
+ b.add_output<decl::Vector>(N_("Location"));
+ b.add_output<decl::Vector>(N_("Rotation"));
+ b.add_output<decl::Vector>(N_("Scale"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_object_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_object_info_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const bNode &bnode = params.node();
- NodeGeometryObjectInfo *node_storage = (NodeGeometryObjectInfo *)bnode.storage;
- const bool transform_space_relative = (node_storage->transform_space ==
+ const NodeGeometryObjectInfo &storage = node_storage(params.node());
+ const bool transform_space_relative = (storage.transform_space ==
GEO_NODE_TRANSFORM_SPACE_RELATIVE);
Object *object = params.get_input<Object *>("Object");
- float3 location = {0, 0, 0};
- float3 rotation = {0, 0, 0};
- float3 scale = {0, 0, 0};
- GeometrySet geometry_set;
-
const Object *self_object = params.self_object();
+ if (object == nullptr) {
+ params.set_default_remaining_outputs();
+ return;
+ }
- if (object != nullptr) {
- float transform[4][4];
- mul_m4_m4m4(transform, self_object->imat, object->obmat);
+ const float4x4 &object_matrix = object->obmat;
+ const float4x4 transform = float4x4(self_object->imat) * object_matrix;
- float quaternion[4];
- if (transform_space_relative) {
- mat4_decompose(location, quaternion, scale, transform);
- }
- else {
- mat4_decompose(location, quaternion, scale, object->obmat);
+ if (transform_space_relative) {
+ params.set_output("Location", transform.translation());
+ params.set_output("Rotation", transform.to_euler());
+ params.set_output("Scale", transform.scale());
+ }
+ else {
+ params.set_output("Location", object_matrix.translation());
+ params.set_output("Rotation", object_matrix.to_euler());
+ params.set_output("Scale", object_matrix.scale());
+ }
+
+ if (params.output_is_required("Geometry")) {
+ if (object == self_object) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Geometry cannot be retrieved from the modifier object"));
+ params.set_default_remaining_outputs();
+ return;
}
- quat_to_eul(rotation, quaternion);
- if (object != self_object) {
+ GeometrySet geometry_set;
+ if (params.get_input<bool>("As Instance")) {
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
const int handle = instances.add_reference(*object);
-
if (transform_space_relative) {
instances.add_instance(handle, transform);
}
else {
- float unit_transform[4][4];
- unit_m4(unit_transform);
- instances.add_instance(handle, unit_transform);
+ instances.add_instance(handle, float4x4::identity());
+ }
+ }
+ else {
+ geometry_set = bke::object_get_evaluated_geometry_set(*object);
+ if (transform_space_relative) {
+ transform_geometry_set(geometry_set, transform, *params.depsgraph());
}
}
- }
- params.set_output("Location", location);
- params.set_output("Rotation", rotation);
- params.set_output("Scale", scale);
- params.set_output("Geometry", geometry_set);
+ params.set_output("Geometry", geometry_set);
+ }
}
-static void geo_node_object_info_node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryObjectInfo *data = (NodeGeometryObjectInfo *)MEM_callocN(
- sizeof(NodeGeometryObjectInfo), __func__);
+ NodeGeometryObjectInfo *data = MEM_cnew<NodeGeometryObjectInfo>(__func__);
data->transform_space = GEO_NODE_TRANSFORM_SPACE_ORIGINAL;
node->storage = data;
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_object_info_cc
void register_node_type_geo_object_info()
{
+ namespace file_ns = blender::nodes::node_geo_object_info_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0);
- node_type_init(&ntype, blender::nodes::geo_node_object_info_node_init);
+ geo_node_type_base(&ntype, GEO_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT);
+ node_type_init(&ntype, file_ns::node_node_init);
node_type_storage(
&ntype, "NodeGeometryObjectInfo", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_object_info_exec;
- ntype.draw_buttons = blender::nodes::geo_node_object_info_layout;
- ntype.declare = blender::nodes::geo_node_object_info_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
index afd0ced6360..f3da591f684 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
@@ -21,15 +21,15 @@
#include "node_geometry_util.hh"
-using blender::Array;
+namespace blender::nodes::node_geo_points_to_vertices_cc {
-namespace blender::nodes {
+using blender::Array;
-static void geo_node_points_to_vertices_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Points");
- b.add_input<decl::Bool>("Selection").default_value(true).supports_field().hide_value();
- b.add_output<decl::Geometry>("Mesh");
+ b.add_input<decl::Geometry>(N_("Points")).supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
template<typename T>
@@ -74,15 +74,15 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
const CustomDataType data_type = entry.value.data_type;
- GVArrayPtr src = point_component->attribute_get_for_read(
+ GVArray src = point_component->attribute_get_for_read(
attribute_id, ATTR_DOMAIN_POINT, data_type);
OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(
attribute_id, ATTR_DOMAIN_POINT, data_type);
if (dst && src) {
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
- GVArray_Typed<T> src_typed{*src};
- VArray_Span<T> src_typed_span{*src_typed};
+ VArray<T> src_typed = src.typed<T>();
+ VArray_Span<T> src_typed_span{src_typed};
copy_attribute_to_vertices(src_typed_span, selection, dst.as_span().typed<T>());
});
dst.save();
@@ -92,7 +92,7 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
}
-static void geo_node_points_to_vertices_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -104,15 +104,17 @@ static void geo_node_points_to_vertices_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_points_to_vertices_cc
void register_node_type_geo_points_to_vertices()
{
+ namespace file_ns = blender::nodes::node_geo_points_to_vertices_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_POINTS_TO_VERTICES, "Points to Vertices", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_points_to_vertices_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_points_to_vertices_exec;
+ &ntype, GEO_NODE_POINTS_TO_VERTICES, "Points to Vertices", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
new file mode 100644
index 00000000000..c165bcf8e35
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
@@ -0,0 +1,284 @@
+/*
+ * 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.
+ */
+
+#ifdef WITH_OPENVDB
+# include <openvdb/openvdb.h>
+# include <openvdb/tools/LevelSetUtil.h>
+# include <openvdb/tools/ParticlesToLevelSet.h>
+#endif
+
+#include "node_geometry_util.hh"
+
+#include "BKE_lib_id.h"
+#include "BKE_volume.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_geo_points_to_volume_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryPointsToVolume)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Points"));
+ b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Voxel Size"))
+ .default_value(0.3f)
+ .min(0.01f)
+ .subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) {
+ node_storage(node).resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE;
+ });
+ b.add_input<decl::Float>(N_("Voxel Amount"))
+ .default_value(64.0f)
+ .min(0.0f)
+ .make_available([](bNode &node) {
+ node_storage(node).resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
+ });
+ b.add_input<decl::Float>(N_("Radius"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .supports_field();
+ b.add_output<decl::Geometry>(N_("Volume"));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryPointsToVolume *data = MEM_cnew<NodeGeometryPointsToVolume>(__func__);
+ data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeGeometryPointsToVolume &storage = node_storage(*node);
+ bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
+ bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
+ nodeSetSocketAvailability(ntree,
+ voxel_amount_socket,
+ storage.resolution_mode ==
+ GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT);
+ nodeSetSocketAvailability(ntree,
+ voxel_size_socket,
+ storage.resolution_mode ==
+ GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE);
+}
+
+#ifdef WITH_OPENVDB
+namespace {
+/* Implements the interface required by #openvdb::tools::ParticlesToLevelSet. */
+struct ParticleList {
+ using PosType = openvdb::Vec3R;
+
+ Span<float3> positions;
+ Span<float> radii;
+
+ size_t size() const
+ {
+ return (size_t)positions.size();
+ }
+
+ void getPos(size_t n, openvdb::Vec3R &xyz) const
+ {
+ xyz = &positions[n].x;
+ }
+
+ void getPosRad(size_t n, openvdb::Vec3R &xyz, openvdb::Real &radius) const
+ {
+ xyz = &positions[n].x;
+ radius = radii[n];
+ }
+};
+} // namespace
+
+static openvdb::FloatGrid::Ptr generate_volume_from_points(const Span<float3> positions,
+ const Span<float> radii,
+ const float density)
+{
+ /* Create a new grid that will be filled. #ParticlesToLevelSet requires the background value to
+ * be positive. It will be set to zero later on. */
+ openvdb::FloatGrid::Ptr new_grid = openvdb::FloatGrid::create(1.0f);
+
+ /* Create a narrow-band level set grid based on the positions and radii. */
+ openvdb::tools::ParticlesToLevelSet op{*new_grid};
+ /* Don't ignore particles based on their radius. */
+ op.setRmin(0.0f);
+ op.setRmax(FLT_MAX);
+ ParticleList particles{positions, radii};
+ op.rasterizeSpheres(particles);
+ op.finalize();
+
+ /* Convert the level set to a fog volume. This also sets the background value to zero. Inside the
+ * fog there will be a density of 1. */
+ openvdb::tools::sdfToFogVolume(*new_grid);
+
+ /* Take the desired density into account. */
+ openvdb::tools::foreach (new_grid->beginValueOn(),
+ [&](const openvdb::FloatGrid::ValueOnIter &iter) {
+ iter.modifyValue([&](float &value) { value *= density; });
+ });
+ return new_grid;
+}
+
+static float compute_voxel_size(const GeoNodeExecParams &params,
+ Span<float3> positions,
+ const float radius)
+{
+ const NodeGeometryPointsToVolume &storage = node_storage(params.node());
+
+ if (storage.resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE) {
+ return params.get_input<float>("Voxel Size");
+ }
+
+ if (positions.is_empty()) {
+ return 0.0f;
+ }
+
+ float3 min, max;
+ INIT_MINMAX(min, max);
+ minmax_v3v3_v3_array(min, max, (float(*)[3])positions.data(), positions.size());
+
+ const float voxel_amount = params.get_input<float>("Voxel Amount");
+ if (voxel_amount <= 1) {
+ return 0.0f;
+ }
+
+ /* The voxel size adapts to the final size of the volume. */
+ const float diagonal = math::distance(min, max);
+ const float extended_diagonal = diagonal + 2.0f * radius;
+ const float voxel_size = extended_diagonal / voxel_amount;
+ return voxel_size;
+}
+
+static void gather_point_data_from_component(GeoNodeExecParams &params,
+ const GeometryComponent &component,
+ Vector<float3> &r_positions,
+ Vector<float> &r_radii)
+{
+ VArray<float3> positions = component.attribute_get_for_read<float3>(
+ "position", ATTR_DOMAIN_POINT, {0, 0, 0});
+
+ Field<float> radius_field = params.get_input<Field<float>>("Radius");
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+
+ r_positions.resize(r_positions.size() + domain_size);
+ positions.materialize(r_positions.as_mutable_span().take_back(domain_size));
+
+ r_radii.resize(r_radii.size() + domain_size);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add_with_destination(radius_field, r_radii.as_mutable_span().take_back(domain_size));
+ evaluator.evaluate();
+}
+
+static void convert_to_grid_index_space(const float voxel_size,
+ MutableSpan<float3> positions,
+ MutableSpan<float> radii)
+{
+ const float voxel_size_inv = 1.0f / voxel_size;
+ for (const int i : positions.index_range()) {
+ positions[i] *= voxel_size_inv;
+ /* Better align generated grid with source points. */
+ positions[i] -= float3(0.5f);
+ radii[i] *= voxel_size_inv;
+ }
+}
+
+static void initialize_volume_component_from_points(GeoNodeExecParams &params,
+ GeometrySet &r_geometry_set)
+{
+ Vector<float3> positions;
+ Vector<float> radii;
+
+ if (r_geometry_set.has<MeshComponent>()) {
+ gather_point_data_from_component(
+ params, *r_geometry_set.get_component_for_read<MeshComponent>(), positions, radii);
+ }
+ if (r_geometry_set.has<PointCloudComponent>()) {
+ gather_point_data_from_component(
+ params, *r_geometry_set.get_component_for_read<PointCloudComponent>(), positions, radii);
+ }
+ if (r_geometry_set.has<CurveComponent>()) {
+ gather_point_data_from_component(
+ params, *r_geometry_set.get_component_for_read<CurveComponent>(), positions, radii);
+ }
+
+ const float max_radius = *std::max_element(radii.begin(), radii.end());
+ const float voxel_size = compute_voxel_size(params, positions, max_radius);
+ if (voxel_size == 0.0f || positions.is_empty()) {
+ return;
+ }
+
+ Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
+ BKE_volume_init_grids(volume);
+
+ const float density = params.get_input<float>("Density");
+ convert_to_grid_index_space(voxel_size, positions, radii);
+ openvdb::FloatGrid::Ptr new_grid = generate_volume_from_points(positions, radii, density);
+ new_grid->transform().postScale(voxel_size);
+ BKE_volume_grid_add_vdb(*volume, "density", std::move(new_grid));
+
+ r_geometry_set.keep_only({GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_INSTANCES});
+ r_geometry_set.replace_volume(volume);
+}
+#endif
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
+
+#ifdef WITH_OPENVDB
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ initialize_volume_component_from_points(params, geometry_set);
+ });
+ params.set_output("Volume", std::move(geometry_set));
+#else
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Disabled, Blender was compiled without OpenVDB"));
+ params.set_default_remaining_outputs();
+#endif
+}
+
+} // namespace blender::nodes::node_geo_points_to_volume_cc
+
+void register_node_type_geo_points_to_volume()
+{
+ namespace file_ns = blender::nodes::node_geo_points_to_volume_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY);
+ node_type_storage(&ntype,
+ "NodeGeometryPointsToVolume",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ node_type_size(&ntype, 170, 120, 700);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
index 2b1de5fbf95..3f509942f7c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
@@ -27,30 +27,33 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_proximity_cc {
-static void geo_node_proximity_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryProximity)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Vector>("Source Position").implicit_field();
- b.add_input<decl::Geometry>("Target");
- b.add_output<decl::Vector>("Position").dependent_field();
- b.add_output<decl::Float>("Distance").dependent_field();
+ b.add_input<decl::Geometry>(N_("Target"))
+ .only_realized_data()
+ .supported_type({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD});
+ b.add_input<decl::Vector>(N_("Source Position")).implicit_field();
+ b.add_output<decl::Vector>(N_("Position")).dependent_field();
+ b.add_output<decl::Float>(N_("Distance")).dependent_field();
}
-static void geo_node_proximity_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "target_element", 0, "", ICON_NONE);
}
static void geo_proximity_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryProximity *node_storage = (NodeGeometryProximity *)MEM_callocN(
- sizeof(NodeGeometryProximity), __func__);
+ NodeGeometryProximity *node_storage = MEM_cnew<NodeGeometryProximity>(__func__);
node_storage->target_element = GEO_NODE_PROX_TARGET_FACES;
node->storage = node_storage;
}
-static void calculate_mesh_proximity(const VArray<float3> &positions,
+static bool calculate_mesh_proximity(const VArray<float3> &positions,
const IndexMask mask,
const Mesh &mesh,
const GeometryNodeProximityTargetType type,
@@ -71,7 +74,7 @@ static void calculate_mesh_proximity(const VArray<float3> &positions,
}
if (bvh_data.tree == nullptr) {
- return;
+ return false;
}
threading::parallel_for(mask.index_range(), 512, [&](IndexRange range) {
@@ -82,7 +85,7 @@ static void calculate_mesh_proximity(const VArray<float3> &positions,
for (int i : range) {
const int index = mask[i];
/* Use the distance to the last found point as upper bound to speedup the bvh lookup. */
- nearest.dist_sq = float3::distance_squared(nearest.co, positions[index]);
+ nearest.dist_sq = math::distance_squared(float3(nearest.co), positions[index]);
BLI_bvhtree_find_nearest(
bvh_data.tree, positions[index], &nearest, bvh_data.nearest_callback, &bvh_data);
@@ -97,18 +100,19 @@ static void calculate_mesh_proximity(const VArray<float3> &positions,
});
free_bvhtree_from_mesh(&bvh_data);
+ return true;
}
-static void calculate_pointcloud_proximity(const VArray<float3> &positions,
+static bool calculate_pointcloud_proximity(const VArray<float3> &positions,
const IndexMask mask,
const PointCloud &pointcloud,
- const MutableSpan<float> r_distances,
- const MutableSpan<float3> r_locations)
+ MutableSpan<float> r_distances,
+ MutableSpan<float3> r_locations)
{
BVHTreeFromPointCloud bvh_data;
BKE_bvhtree_from_pointcloud_get(&bvh_data, &pointcloud, 2);
if (bvh_data.tree == nullptr) {
- return;
+ return false;
}
threading::parallel_for(mask.index_range(), 512, [&](IndexRange range) {
@@ -136,6 +140,7 @@ static void calculate_pointcloud_proximity(const VArray<float3> &positions,
});
free_bvhtree_from_pointcloud(&bvh_data);
+ return true;
}
class ProximityFunction : public fn::MultiFunction {
@@ -172,18 +177,29 @@ class ProximityFunction : public fn::MultiFunction {
* comparison per vertex, so it's likely not worth it. */
MutableSpan<float> distances = params.uninitialized_single_output<float>(2, "Distance");
- distances.fill(FLT_MAX);
+ distances.fill_indices(mask, FLT_MAX);
+ bool success = false;
if (target_.has_mesh()) {
- calculate_mesh_proximity(
+ success |= calculate_mesh_proximity(
src_positions, mask, *target_.get_mesh_for_read(), type_, distances, positions);
}
if (target_.has_pointcloud() && type_ == GEO_NODE_PROX_TARGET_POINTS) {
- calculate_pointcloud_proximity(
+ success |= calculate_pointcloud_proximity(
src_positions, mask, *target_.get_pointcloud_for_read(), distances, positions);
}
+ if (!success) {
+ if (!positions.is_empty()) {
+ positions.fill_indices(mask, float3(0));
+ }
+ if (!distances.is_empty()) {
+ distances.fill_indices(mask, 0.0f);
+ }
+ return;
+ }
+
if (params.single_output_is_required(2, "Distance")) {
threading::parallel_for(mask.index_range(), 2048, [&](IndexRange range) {
for (const int i : range) {
@@ -195,17 +211,17 @@ class ProximityFunction : public fn::MultiFunction {
}
};
-static void geo_node_proximity_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target");
+ geometry_set_target.ensure_owns_direct_data();
if (!geometry_set_target.has_mesh() && !geometry_set_target.has_pointcloud()) {
- params.set_output("Position", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- params.set_output("Distance", fn::make_constant_field<float>({0.0f}));
+ params.set_default_remaining_outputs();
return;
}
- const NodeGeometryProximity &storage = *(const NodeGeometryProximity *)params.node().storage;
+ const NodeGeometryProximity &storage = node_storage(params.node());
Field<float3> position_field = params.extract_input<Field<float3>>("Source Position");
auto proximity_fn = std::make_unique<ProximityFunction>(
@@ -218,18 +234,20 @@ static void geo_node_proximity_exec(GeoNodeExecParams params)
params.set_output("Distance", Field<float>(proximity_op, 1));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_proximity_cc
void register_node_type_geo_proximity()
{
+ namespace file_ns = blender::nodes::node_geo_proximity_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_PROXIMITY, "Geometry Proximity", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_proximity_init);
+ geo_node_type_base(&ntype, GEO_NODE_PROXIMITY, "Geometry Proximity", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::geo_proximity_init);
node_type_storage(
&ntype, "NodeGeometryProximity", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_proximity_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_proximity_exec;
- ntype.draw_buttons = blender::nodes::geo_node_proximity_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
new file mode 100644
index 00000000000..c38503f688c
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -0,0 +1,462 @@
+/*
+ * 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 "DNA_mesh_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_bvhutils.h"
+#include "BKE_mesh_sample.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "NOD_socket_search_link.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_raycast_cc {
+
+using namespace blender::bke::mesh_surface_sample;
+
+NODE_STORAGE_FUNCS(NodeGeometryRaycast)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Target Geometry"))
+ .only_realized_data()
+ .supported_type(GEO_COMPONENT_TYPE_MESH);
+
+ b.add_input<decl::Vector>(N_("Attribute")).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Attribute"), "Attribute_001").hide_value().supports_field();
+ b.add_input<decl::Color>(N_("Attribute"), "Attribute_002").hide_value().supports_field();
+ b.add_input<decl::Bool>(N_("Attribute"), "Attribute_003").hide_value().supports_field();
+ b.add_input<decl::Int>(N_("Attribute"), "Attribute_004").hide_value().supports_field();
+
+ b.add_input<decl::Vector>(N_("Source Position")).implicit_field();
+ b.add_input<decl::Vector>(N_("Ray Direction"))
+ .default_value({0.0f, 0.0f, -1.0f})
+ .supports_field();
+ b.add_input<decl::Float>(N_("Ray Length"))
+ .default_value(100.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .supports_field();
+
+ b.add_output<decl::Bool>(N_("Is Hit")).dependent_field();
+ b.add_output<decl::Vector>(N_("Hit Position")).dependent_field();
+ b.add_output<decl::Vector>(N_("Hit Normal")).dependent_field();
+ b.add_output<decl::Float>(N_("Hit Distance")).dependent_field();
+
+ b.add_output<decl::Vector>(N_("Attribute")).dependent_field({1, 2, 3, 4, 5, 6});
+ b.add_output<decl::Float>(N_("Attribute"), "Attribute_001").dependent_field({1, 2, 3, 4, 5, 6});
+ b.add_output<decl::Color>(N_("Attribute"), "Attribute_002").dependent_field({1, 2, 3, 4, 5, 6});
+ b.add_output<decl::Bool>(N_("Attribute"), "Attribute_003").dependent_field({1, 2, 3, 4, 5, 6});
+ b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({1, 2, 3, 4, 5, 6});
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryRaycast *data = MEM_cnew<NodeGeometryRaycast>(__func__);
+ data->mapping = GEO_NODE_RAYCAST_INTERPOLATED;
+ data->data_type = CD_PROP_FLOAT;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeGeometryRaycast &storage = node_storage(*node);
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+
+ bNodeSocket *socket_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
+ bNodeSocket *socket_float = socket_vector->next;
+ bNodeSocket *socket_color4f = socket_float->next;
+ bNodeSocket *socket_boolean = socket_color4f->next;
+ bNodeSocket *socket_int32 = socket_boolean->next;
+
+ nodeSetSocketAvailability(ntree, socket_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, socket_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, socket_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, socket_boolean, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(ntree, socket_int32, data_type == CD_PROP_INT32);
+
+ bNodeSocket *out_socket_vector = (bNodeSocket *)BLI_findlink(&node->outputs, 4);
+ bNodeSocket *out_socket_float = out_socket_vector->next;
+ bNodeSocket *out_socket_color4f = out_socket_float->next;
+ bNodeSocket *out_socket_boolean = out_socket_color4f->next;
+ bNodeSocket *out_socket_int32 = out_socket_boolean->next;
+
+ nodeSetSocketAvailability(ntree, out_socket_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, out_socket_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, out_socket_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, out_socket_boolean, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32);
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+ search_link_ops_for_declarations(params, declaration.inputs().take_back(3));
+ search_link_ops_for_declarations(params, declaration.outputs().take_front(4));
+
+ const std::optional<CustomDataType> type = node_data_type_to_custom_data_type(
+ (eNodeSocketDatatype)params.other_socket().type);
+ if (type && *type != CD_PROP_STRING) {
+ /* The input and output sockets have the same name. */
+ params.add_item(IFACE_("Attribute"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeRaycast");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Attribute");
+ });
+ }
+}
+
+static eAttributeMapMode get_map_mode(GeometryNodeRaycastMapMode map_mode)
+{
+ switch (map_mode) {
+ case GEO_NODE_RAYCAST_INTERPOLATED:
+ return eAttributeMapMode::INTERPOLATED;
+ default:
+ case GEO_NODE_RAYCAST_NEAREST:
+ return eAttributeMapMode::NEAREST;
+ }
+}
+
+static void raycast_to_mesh(IndexMask mask,
+ const Mesh &mesh,
+ const VArray<float3> &ray_origins,
+ const VArray<float3> &ray_directions,
+ const VArray<float> &ray_lengths,
+ const MutableSpan<bool> r_hit,
+ const MutableSpan<int> r_hit_indices,
+ const MutableSpan<float3> r_hit_positions,
+ const MutableSpan<float3> r_hit_normals,
+ const MutableSpan<float> r_hit_distances,
+ int &hit_count)
+{
+ BVHTreeFromMesh tree_data;
+ BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_LOOPTRI, 4);
+ if (tree_data.tree == nullptr) {
+ free_bvhtree_from_mesh(&tree_data);
+ return;
+ }
+
+ for (const int i : mask) {
+ const float ray_length = ray_lengths[i];
+ const float3 ray_origin = ray_origins[i];
+ const float3 ray_direction = math::normalize(ray_directions[i]);
+
+ BVHTreeRayHit hit;
+ hit.index = -1;
+ hit.dist = ray_length;
+ if (BLI_bvhtree_ray_cast(tree_data.tree,
+ ray_origin,
+ ray_direction,
+ 0.0f,
+ &hit,
+ tree_data.raycast_callback,
+ &tree_data) != -1) {
+ hit_count++;
+ if (!r_hit.is_empty()) {
+ r_hit[i] = hit.index >= 0;
+ }
+ if (!r_hit_indices.is_empty()) {
+ /* The caller must be able to handle invalid indices anyway, so don't clamp this value. */
+ r_hit_indices[i] = hit.index;
+ }
+ if (!r_hit_positions.is_empty()) {
+ r_hit_positions[i] = hit.co;
+ }
+ if (!r_hit_normals.is_empty()) {
+ r_hit_normals[i] = hit.no;
+ }
+ if (!r_hit_distances.is_empty()) {
+ r_hit_distances[i] = hit.dist;
+ }
+ }
+ else {
+ if (!r_hit.is_empty()) {
+ r_hit[i] = false;
+ }
+ if (!r_hit_indices.is_empty()) {
+ r_hit_indices[i] = -1;
+ }
+ if (!r_hit_positions.is_empty()) {
+ r_hit_positions[i] = float3(0.0f, 0.0f, 0.0f);
+ }
+ if (!r_hit_normals.is_empty()) {
+ r_hit_normals[i] = float3(0.0f, 0.0f, 0.0f);
+ }
+ if (!r_hit_distances.is_empty()) {
+ r_hit_distances[i] = ray_length;
+ }
+ }
+ }
+
+ /* We shouldn't be rebuilding the BVH tree when calling this function in parallel. */
+ BLI_assert(tree_data.cached);
+ free_bvhtree_from_mesh(&tree_data);
+}
+
+class RaycastFunction : public fn::MultiFunction {
+ private:
+ GeometrySet target_;
+ GeometryNodeRaycastMapMode mapping_;
+
+ /** The field for data evaluated on the target geometry. */
+ std::optional<GeometryComponentFieldContext> target_context_;
+ std::unique_ptr<FieldEvaluator> target_evaluator_;
+ const GVArray *target_data_ = nullptr;
+
+ /* Always evaluate the target domain data on the face corner domain because it contains the most
+ * information. Eventually this could be exposed as an option or determined automatically from
+ * the field inputs for better performance. */
+ const AttributeDomain domain_ = ATTR_DOMAIN_CORNER;
+
+ fn::MFSignature signature_;
+
+ public:
+ RaycastFunction(GeometrySet target, GField src_field, GeometryNodeRaycastMapMode mapping)
+ : target_(std::move(target)), mapping_((GeometryNodeRaycastMapMode)mapping)
+ {
+ target_.ensure_owns_direct_data();
+ this->evaluate_target_field(std::move(src_field));
+ signature_ = create_signature();
+ this->set_signature(&signature_);
+ }
+
+ fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Geometry Proximity"};
+ signature.single_input<float3>("Source Position");
+ signature.single_input<float3>("Ray Direction");
+ signature.single_input<float>("Ray Length");
+ signature.single_output<bool>("Is Hit");
+ signature.single_output<float3>("Hit Position");
+ signature.single_output<float3>("Hit Normal");
+ signature.single_output<float>("Distance");
+ if (target_data_) {
+ signature.single_output("Attribute", target_data_->type());
+ }
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ /* Hit positions are always necessary for retrieving the attribute from the target if that
+ * output is required, so always retrieve a span from the evaluator in that case (it's
+ * expected that the evaluator is more likely to have a spare buffer that could be used). */
+ MutableSpan<float3> hit_positions =
+ (target_data_) ? params.uninitialized_single_output<float3>(4, "Hit Position") :
+ params.uninitialized_single_output_if_required<float3>(4, "Hit Position");
+
+ Array<int> hit_indices;
+ if (target_data_) {
+ hit_indices.reinitialize(mask.min_array_size());
+ }
+
+ BLI_assert(target_.has_mesh());
+ const Mesh &mesh = *target_.get_mesh_for_read();
+
+ int hit_count = 0;
+ raycast_to_mesh(mask,
+ mesh,
+ params.readonly_single_input<float3>(0, "Source Position"),
+ params.readonly_single_input<float3>(1, "Ray Direction"),
+ params.readonly_single_input<float>(2, "Ray Length"),
+ params.uninitialized_single_output_if_required<bool>(3, "Is Hit"),
+ hit_indices,
+ hit_positions,
+ params.uninitialized_single_output_if_required<float3>(5, "Hit Normal"),
+ params.uninitialized_single_output_if_required<float>(6, "Distance"),
+ hit_count);
+
+ if (target_data_) {
+ IndexMask hit_mask;
+ Vector<int64_t> hit_mask_indices;
+ if (hit_count < mask.size()) {
+ /* Not all rays hit the target. Create a corrected mask to avoid transferring attribute
+ * data to invalid indices. An alternative would be handling -1 indices in a separate case
+ * in #MeshAttributeInterpolator, but since it already has an IndexMask in its constructor,
+ * it's simpler to use that. */
+ hit_mask_indices.reserve(hit_count);
+ for (const int64_t i : mask) {
+ if (hit_indices[i] != -1) {
+ hit_mask_indices.append(i);
+ }
+ hit_mask = IndexMask(hit_mask_indices);
+ }
+ }
+ else {
+ hit_mask = mask;
+ }
+
+ GMutableSpan result = params.uninitialized_single_output_if_required(7, "Attribute");
+ if (!result.is_empty()) {
+ MeshAttributeInterpolator interp(&mesh, hit_mask, hit_positions, hit_indices);
+ result.type().fill_assign_indices(result.type().default_value(), result.data(), mask);
+ interp.sample_data(*target_data_, domain_, get_map_mode(mapping_), result);
+ }
+ }
+ }
+
+ private:
+ void evaluate_target_field(GField src_field)
+ {
+ if (!src_field) {
+ return;
+ }
+ const MeshComponent &mesh_component = *target_.get_component_for_read<MeshComponent>();
+ target_context_.emplace(GeometryComponentFieldContext{mesh_component, domain_});
+ const int domain_size = mesh_component.attribute_domain_size(domain_);
+ target_evaluator_ = std::make_unique<FieldEvaluator>(*target_context_, domain_size);
+ target_evaluator_->add(std::move(src_field));
+ target_evaluator_->evaluate();
+ target_data_ = &target_evaluator_->get_evaluated(0);
+ }
+};
+
+static GField get_input_attribute_field(GeoNodeExecParams &params, const CustomDataType data_type)
+{
+ switch (data_type) {
+ case CD_PROP_FLOAT:
+ if (params.output_is_required("Attribute_001")) {
+ return params.extract_input<Field<float>>("Attribute_001");
+ }
+ break;
+ case CD_PROP_FLOAT3:
+ if (params.output_is_required("Attribute")) {
+ return params.extract_input<Field<float3>>("Attribute");
+ }
+ break;
+ case CD_PROP_COLOR:
+ if (params.output_is_required("Attribute_002")) {
+ return params.extract_input<Field<ColorGeometry4f>>("Attribute_002");
+ }
+ break;
+ case CD_PROP_BOOL:
+ if (params.output_is_required("Attribute_003")) {
+ return params.extract_input<Field<bool>>("Attribute_003");
+ }
+ break;
+ case CD_PROP_INT32:
+ if (params.output_is_required("Attribute_004")) {
+ return params.extract_input<Field<int>>("Attribute_004");
+ }
+ break;
+ default:
+ BLI_assert_unreachable();
+ }
+ return {};
+}
+
+static void output_attribute_field(GeoNodeExecParams &params, GField field)
+{
+ switch (bke::cpp_type_to_custom_data_type(field.cpp_type())) {
+ case CD_PROP_FLOAT: {
+ params.set_output("Attribute_001", Field<float>(field));
+ break;
+ }
+ case CD_PROP_FLOAT3: {
+ params.set_output("Attribute", Field<float3>(field));
+ break;
+ }
+ case CD_PROP_COLOR: {
+ params.set_output("Attribute_002", Field<ColorGeometry4f>(field));
+ break;
+ }
+ case CD_PROP_BOOL: {
+ params.set_output("Attribute_003", Field<bool>(field));
+ break;
+ }
+ case CD_PROP_INT32: {
+ params.set_output("Attribute_004", Field<int>(field));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet target = params.extract_input<GeometrySet>("Target Geometry");
+ const NodeGeometryRaycast &storage = node_storage(params.node());
+ const GeometryNodeRaycastMapMode mapping = (GeometryNodeRaycastMapMode)storage.mapping;
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+
+ if (target.is_empty()) {
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ if (!target.has_mesh()) {
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ if (target.get_mesh_for_read()->totpoly == 0) {
+ params.error_message_add(NodeWarningType::Error, TIP_("The target mesh must have faces"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ GField field = get_input_attribute_field(params, data_type);
+ const bool do_attribute_transfer = bool(field);
+ Field<float3> position_field = params.extract_input<Field<float3>>("Source Position");
+ Field<float3> direction_field = params.extract_input<Field<float3>>("Ray Direction");
+ Field<float> length_field = params.extract_input<Field<float>>("Ray Length");
+
+ auto fn = std::make_unique<RaycastFunction>(std::move(target), std::move(field), mapping);
+ auto op = std::make_shared<FieldOperation>(FieldOperation(
+ std::move(fn),
+ {std::move(position_field), std::move(direction_field), std::move(length_field)}));
+
+ params.set_output("Is Hit", Field<bool>(op, 0));
+ params.set_output("Hit Position", Field<float3>(op, 1));
+ params.set_output("Hit Normal", Field<float3>(op, 2));
+ params.set_output("Hit Distance", Field<float>(op, 3));
+ if (do_attribute_transfer) {
+ output_attribute_field(params, GField(op, 4));
+ }
+}
+
+} // namespace blender::nodes::node_geo_raycast_cc
+
+void register_node_type_geo_raycast()
+{
+ namespace file_ns = blender::nodes::node_geo_raycast_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY);
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_storage(
+ &ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
index 3be79d5ba3b..48b88705ed2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
@@ -16,33 +16,47 @@
#include "node_geometry_util.hh"
+#include "GEO_realize_instances.hh"
+
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_realize_instances_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
-static void geo_node_realize_instances_declare(NodeDeclarationBuilder &b)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_output<decl::Geometry>("Geometry");
+ uiItemR(layout, ptr, "legacy_behavior", 0, nullptr, ICON_NONE);
}
-static void geo_node_realize_instances_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
+ const bool legacy_behavior = params.node().custom1 & GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR;
+
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry::RealizeInstancesOptions options;
+ options.keep_original_ids = legacy_behavior;
+ options.realize_instance_attributes = !legacy_behavior;
+ geometry_set = geometry::realize_instances(geometry_set, options);
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_realize_instances_cc
void register_node_type_geo_realize_instances()
{
+ namespace file_ns = blender::nodes::node_geo_realize_instances_cc;
+
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_REALIZE_INSTANCES, "Realize Instances", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_realize_instances_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_realize_instances_exec;
+ geo_node_type_base(&ntype, GEO_NODE_REALIZE_INSTANCES, "Realize Instances", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons_ex = file_ns::node_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
new file mode 100644
index 00000000000..7d5c5b77ffd
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
@@ -0,0 +1,119 @@
+/*
+ * 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 "BLI_task.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_rotate_instances_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Instances")).only_instances();
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).supports_field();
+ b.add_input<decl::Vector>(N_("Pivot Point")).subtype(PROP_TRANSLATION).supports_field();
+ b.add_input<decl::Bool>(N_("Local Space")).default_value(true).supports_field();
+ b.add_output<decl::Geometry>(N_("Instances"));
+}
+
+static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
+{
+ GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
+ const int domain_size = instances_component.instances_amount();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
+ evaluator.add(params.extract_input<Field<float3>>("Rotation"));
+ evaluator.add(params.extract_input<Field<float3>>("Pivot Point"));
+ evaluator.add(params.extract_input<Field<bool>>("Local Space"));
+ evaluator.evaluate();
+
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &rotations = evaluator.get_evaluated<float3>(0);
+ const VArray<float3> &pivots = evaluator.get_evaluated<float3>(1);
+ const VArray<bool> &local_spaces = evaluator.get_evaluated<bool>(2);
+
+ MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
+
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i_selection : range) {
+ const int i = selection[i_selection];
+ const float3 pivot = pivots[i];
+ const float3 euler = rotations[i];
+ float4x4 &instance_transform = instance_transforms[i];
+
+ float4x4 rotation_matrix;
+ float3 used_pivot;
+
+ if (local_spaces[i]) {
+ /* Find rotation axis from the matrix. This should work even if the instance is skewed. */
+ const float3 rotation_axis_x = instance_transform.values[0];
+ const float3 rotation_axis_y = instance_transform.values[1];
+ const float3 rotation_axis_z = instance_transform.values[2];
+
+ /* Create rotations around the individual axis. This could be optimized to skip some axis
+ * when the angle is zero. */
+ float rotation_x[3][3], rotation_y[3][3], rotation_z[3][3];
+ axis_angle_to_mat3(rotation_x, rotation_axis_x, euler.x);
+ axis_angle_to_mat3(rotation_y, rotation_axis_y, euler.y);
+ axis_angle_to_mat3(rotation_z, rotation_axis_z, euler.z);
+
+ /* Combine the previously computed rotations into the final rotation matrix. */
+ float rotation[3][3];
+ mul_m3_series(rotation, rotation_z, rotation_y, rotation_x);
+ copy_m4_m3(rotation_matrix.values, rotation);
+
+ /* Transform the passed in pivot into the local space of the instance. */
+ used_pivot = instance_transform * pivot;
+ }
+ else {
+ used_pivot = pivot;
+ eul_to_mat4(rotation_matrix.values, euler);
+ }
+ /* Move the pivot to the origin so that we can rotate around it. */
+ sub_v3_v3(instance_transform.values[3], used_pivot);
+ /* Perform the actual rotation. */
+ mul_m4_m4_pre(instance_transform.values, rotation_matrix.values);
+ /* Undo the pivot shifting done before. */
+ add_v3_v3(instance_transform.values[3], used_pivot);
+ }
+ });
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
+ if (geometry_set.has_instances()) {
+ InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ rotate_instances(params, instances);
+ }
+ params.set_output("Instances", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_rotate_instances_cc
+
+void register_node_type_geo_rotate_instances()
+{
+ namespace file_ns = blender::nodes::node_geo_rotate_instances_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_ROTATE_INSTANCES, "Rotate Instances", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
new file mode 100644
index 00000000000..aaa2c156442
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
@@ -0,0 +1,485 @@
+/*
+ * 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 "BLI_array.hh"
+#include "BLI_disjoint_set.hh"
+#include "BLI_task.hh"
+#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_scale_elements_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Scale"), "Scale").default_value(1.0f).min(0.0f).supports_field();
+ b.add_input<decl::Vector>(N_("Center"))
+ .subtype(PROP_TRANSLATION)
+ .implicit_field()
+ .description(N_("Origin of the scaling for each element. If multiple elements are "
+ "connected, their center is averaged"));
+ b.add_input<decl::Vector>(N_("Axis"))
+ .default_value({1.0f, 0.0f, 0.0f})
+ .supports_field()
+ .description(N_("Direction in which to scale the element"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
+};
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "scale_mode", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ node->custom1 = ATTR_DOMAIN_FACE;
+ node->custom2 = GEO_NODE_SCALE_ELEMENTS_UNIFORM;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *geometry_socket = static_cast<bNodeSocket *>(node->inputs.first);
+ bNodeSocket *selection_socket = geometry_socket->next;
+ bNodeSocket *scale_float_socket = selection_socket->next;
+ bNodeSocket *center_socket = scale_float_socket->next;
+ bNodeSocket *axis_socket = center_socket->next;
+
+ const GeometryNodeScaleElementsMode mode = static_cast<GeometryNodeScaleElementsMode>(
+ node->custom2);
+ const bool use_single_axis = mode == GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS;
+
+ nodeSetSocketAvailability(ntree, axis_socket, use_single_axis);
+}
+
+struct UniformScaleFields {
+ Field<bool> selection;
+ Field<float> scale;
+ Field<float3> center;
+};
+
+struct UniformScaleParams {
+ IndexMask selection;
+ VArray<float> scales;
+ VArray<float3> centers;
+};
+
+struct AxisScaleFields {
+ Field<bool> selection;
+ Field<float> scale;
+ Field<float3> center;
+ Field<float3> axis;
+};
+
+struct AxisScaleParams {
+ IndexMask selection;
+ VArray<float> scales;
+ VArray<float3> centers;
+ VArray<float3> axis_vectors;
+};
+
+/**
+ * When multiple elements share the same vertices, they are scaled together.
+ */
+struct ElementIsland {
+ /* Either face or edge indices. */
+ Vector<int> element_indices;
+};
+
+static float3 transform_with_uniform_scale(const float3 &position,
+ const float3 &center,
+ const float scale)
+{
+ const float3 diff = position - center;
+ const float3 scaled_diff = scale * diff;
+ const float3 new_position = center + scaled_diff;
+ return new_position;
+}
+
+static float4x4 create_single_axis_transform(const float3 &center,
+ const float3 &axis,
+ const float scale)
+{
+ /* Scale along x axis. The other axis need to be orthogonal, but their specific value does not
+ * matter. */
+ const float3 x_axis = math::normalize(axis);
+ float3 y_axis = math::cross(x_axis, float3(0.0f, 0.0f, 1.0f));
+ if (math::is_zero(y_axis)) {
+ y_axis = math::cross(x_axis, float3(0.0f, 1.0f, 0.0f));
+ }
+ y_axis = math::normalize(y_axis);
+ const float3 z_axis = math::cross(x_axis, y_axis);
+
+ float4x4 transform = float4x4::identity();
+
+ /* Move scaling center to the origin. */
+ sub_v3_v3(transform.values[3], center);
+
+ /* `base_change` and `base_change_inv` are used to rotate space so that scaling along the
+ * provided axis is the same as scaling along the x axis. */
+ float4x4 base_change = float4x4::identity();
+ copy_v3_v3(base_change.values[0], x_axis);
+ copy_v3_v3(base_change.values[1], y_axis);
+ copy_v3_v3(base_change.values[2], z_axis);
+
+ /* Can invert by transposing, because the matrix is orthonormal. */
+ float4x4 base_change_inv = base_change.transposed();
+
+ float4x4 scale_transform = float4x4::identity();
+ scale_transform.values[0][0] = scale;
+
+ transform = base_change * scale_transform * base_change_inv * transform;
+
+ /* Move scaling center back to where it was. */
+ add_v3_v3(transform.values[3], center);
+
+ return transform;
+}
+
+using GetVertexIndicesFn =
+ FunctionRef<void(const Mesh &mesh, int element_index, VectorSet<int> &r_vertex_indices)>;
+
+static void scale_vertex_islands_uniformly(Mesh &mesh,
+ const Span<ElementIsland> islands,
+ const UniformScaleParams &params,
+ const GetVertexIndicesFn get_vertex_indices)
+{
+ threading::parallel_for(islands.index_range(), 256, [&](const IndexRange range) {
+ for (const int island_index : range) {
+ const ElementIsland &island = islands[island_index];
+
+ float scale = 0.0f;
+ float3 center = {0.0f, 0.0f, 0.0f};
+
+ VectorSet<int> vertex_indices;
+ for (const int poly_index : island.element_indices) {
+ get_vertex_indices(mesh, poly_index, vertex_indices);
+ center += params.centers[poly_index];
+ scale += params.scales[poly_index];
+ }
+
+ /* Divide by number of elements to get the average. */
+ const float f = 1.0f / island.element_indices.size();
+ scale *= f;
+ center *= f;
+
+ for (const int vert_index : vertex_indices) {
+ MVert &vert = mesh.mvert[vert_index];
+ const float3 old_position = vert.co;
+ const float3 new_position = transform_with_uniform_scale(old_position, center, scale);
+ copy_v3_v3(vert.co, new_position);
+ }
+ }
+ });
+
+ /* Positions have changed, so the normals will have to be recomputed. */
+ BKE_mesh_normals_tag_dirty(&mesh);
+}
+
+static void scale_vertex_islands_on_axis(Mesh &mesh,
+ const Span<ElementIsland> islands,
+ const AxisScaleParams &params,
+ const GetVertexIndicesFn get_vertex_indices)
+{
+ threading::parallel_for(islands.index_range(), 256, [&](const IndexRange range) {
+ for (const int island_index : range) {
+ const ElementIsland &island = islands[island_index];
+
+ float scale = 0.0f;
+ float3 center = {0.0f, 0.0f, 0.0f};
+ float3 axis = {0.0f, 0.0f, 0.0f};
+
+ VectorSet<int> vertex_indices;
+ for (const int poly_index : island.element_indices) {
+ get_vertex_indices(mesh, poly_index, vertex_indices);
+ center += params.centers[poly_index];
+ scale += params.scales[poly_index];
+ axis += params.axis_vectors[poly_index];
+ }
+
+ /* Divide by number of elements to get the average. */
+ const float f = 1.0f / island.element_indices.size();
+ scale *= f;
+ center *= f;
+ axis *= f;
+
+ if (math::is_zero(axis)) {
+ axis = float3(1.0f, 0.0f, 0.0f);
+ }
+
+ const float4x4 transform = create_single_axis_transform(center, axis, scale);
+ for (const int vert_index : vertex_indices) {
+ MVert &vert = mesh.mvert[vert_index];
+ const float3 old_position = vert.co;
+ const float3 new_position = transform * old_position;
+ copy_v3_v3(vert.co, new_position);
+ }
+ }
+ });
+
+ /* Positions have changed, so the normals will have to be recomputed. */
+ BKE_mesh_normals_tag_dirty(&mesh);
+}
+
+static Vector<ElementIsland> prepare_face_islands(const Mesh &mesh, const IndexMask face_selection)
+{
+ /* Use the disjoint set data structure to determine which vertices have to be scaled together. */
+ DisjointSet disjoint_set(mesh.totvert);
+ for (const int poly_index : face_selection) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ const Span<MLoop> poly_loops{mesh.mloop + poly.loopstart, poly.totloop};
+ for (const int loop_index : IndexRange(poly.totloop - 1)) {
+ const int v1 = poly_loops[loop_index].v;
+ const int v2 = poly_loops[loop_index + 1].v;
+ disjoint_set.join(v1, v2);
+ }
+ disjoint_set.join(poly_loops.first().v, poly_loops.last().v);
+ }
+
+ VectorSet<int> island_ids;
+ Vector<ElementIsland> islands;
+ /* There are at most as many islands as there are selected faces. */
+ islands.reserve(face_selection.size());
+
+ /* Gather all of the face indices in each island into separate vectors. */
+ for (const int poly_index : face_selection) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ const Span<MLoop> poly_loops{mesh.mloop + poly.loopstart, poly.totloop};
+ const int island_id = disjoint_set.find_root(poly_loops[0].v);
+ const int island_index = island_ids.index_of_or_add(island_id);
+ if (island_index == islands.size()) {
+ islands.append_as();
+ }
+ ElementIsland &island = islands[island_index];
+ island.element_indices.append(poly_index);
+ }
+
+ return islands;
+}
+
+static void get_face_vertices(const Mesh &mesh, int face_index, VectorSet<int> &r_vertex_indices)
+{
+ const MPoly &poly = mesh.mpoly[face_index];
+ const Span<MLoop> poly_loops{mesh.mloop + poly.loopstart, poly.totloop};
+ for (const MLoop &loop : poly_loops) {
+ r_vertex_indices.add(loop.v);
+ }
+}
+
+static AxisScaleParams evaluate_axis_scale_fields(FieldEvaluator &evaluator,
+ const AxisScaleFields &fields)
+{
+ AxisScaleParams out;
+ evaluator.set_selection(fields.selection);
+ evaluator.add(fields.scale, &out.scales);
+ evaluator.add(fields.center, &out.centers);
+ evaluator.add(fields.axis, &out.axis_vectors);
+ evaluator.evaluate();
+ out.selection = evaluator.get_evaluated_selection_as_mask();
+ return out;
+}
+
+static void scale_faces_on_axis(MeshComponent &mesh_component, const AxisScaleFields &fields)
+{
+ Mesh &mesh = *mesh_component.get_for_write();
+ mesh.mvert = static_cast<MVert *>(
+ CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
+
+ GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
+ FieldEvaluator evaluator{field_context, mesh.totpoly};
+ AxisScaleParams params = evaluate_axis_scale_fields(evaluator, fields);
+
+ Vector<ElementIsland> island = prepare_face_islands(mesh, params.selection);
+ scale_vertex_islands_on_axis(mesh, island, params, get_face_vertices);
+}
+
+static UniformScaleParams evaluate_uniform_scale_fields(FieldEvaluator &evaluator,
+ const UniformScaleFields &fields)
+{
+ UniformScaleParams out;
+ evaluator.set_selection(fields.selection);
+ evaluator.add(fields.scale, &out.scales);
+ evaluator.add(fields.center, &out.centers);
+ evaluator.evaluate();
+ out.selection = evaluator.get_evaluated_selection_as_mask();
+ return out;
+}
+
+static void scale_faces_uniformly(MeshComponent &mesh_component, const UniformScaleFields &fields)
+{
+ Mesh &mesh = *mesh_component.get_for_write();
+ mesh.mvert = static_cast<MVert *>(
+ CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
+
+ GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
+ FieldEvaluator evaluator{field_context, mesh.totpoly};
+ UniformScaleParams params = evaluate_uniform_scale_fields(evaluator, fields);
+
+ Vector<ElementIsland> island = prepare_face_islands(mesh, params.selection);
+ scale_vertex_islands_uniformly(mesh, island, params, get_face_vertices);
+}
+
+static Vector<ElementIsland> prepare_edge_islands(const Mesh &mesh, const IndexMask edge_selection)
+{
+ /* Use the disjoint set data structure to determine which vertices have to be scaled together. */
+ DisjointSet disjoint_set(mesh.totvert);
+ for (const int edge_index : edge_selection) {
+ const MEdge &edge = mesh.medge[edge_index];
+ disjoint_set.join(edge.v1, edge.v2);
+ }
+
+ VectorSet<int> island_ids;
+ Vector<ElementIsland> islands;
+ /* There are at most as many islands as there are selected edges. */
+ islands.reserve(edge_selection.size());
+
+ /* Gather all of the edge indices in each island into separate vectors. */
+ for (const int edge_index : edge_selection) {
+ const MEdge &edge = mesh.medge[edge_index];
+ const int island_id = disjoint_set.find_root(edge.v1);
+ const int island_index = island_ids.index_of_or_add(island_id);
+ if (island_index == islands.size()) {
+ islands.append_as();
+ }
+ ElementIsland &island = islands[island_index];
+ island.element_indices.append(edge_index);
+ }
+
+ return islands;
+}
+
+static void get_edge_vertices(const Mesh &mesh, int edge_index, VectorSet<int> &r_vertex_indices)
+{
+ const MEdge &edge = mesh.medge[edge_index];
+ r_vertex_indices.add(edge.v1);
+ r_vertex_indices.add(edge.v2);
+}
+
+static void scale_edges_uniformly(MeshComponent &mesh_component, const UniformScaleFields &fields)
+{
+ Mesh &mesh = *mesh_component.get_for_write();
+ mesh.mvert = static_cast<MVert *>(
+ CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
+
+ GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE};
+ FieldEvaluator evaluator{field_context, mesh.totedge};
+ UniformScaleParams params = evaluate_uniform_scale_fields(evaluator, fields);
+
+ Vector<ElementIsland> island = prepare_edge_islands(mesh, params.selection);
+ scale_vertex_islands_uniformly(mesh, island, params, get_edge_vertices);
+}
+
+static void scale_edges_on_axis(MeshComponent &mesh_component, const AxisScaleFields &fields)
+{
+ Mesh &mesh = *mesh_component.get_for_write();
+ mesh.mvert = static_cast<MVert *>(
+ CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
+
+ GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE};
+ FieldEvaluator evaluator{field_context, mesh.totedge};
+ AxisScaleParams params = evaluate_axis_scale_fields(evaluator, fields);
+
+ Vector<ElementIsland> island = prepare_edge_islands(mesh, params.selection);
+ scale_vertex_islands_on_axis(mesh, island, params, get_edge_vertices);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const bNode &node = params.node();
+ const AttributeDomain domain = static_cast<AttributeDomain>(node.custom1);
+ const GeometryNodeScaleElementsMode scale_mode = static_cast<GeometryNodeScaleElementsMode>(
+ node.custom2);
+
+ GeometrySet geometry = params.extract_input<GeometrySet>("Geometry");
+
+ Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
+ Field<float> scale_field = params.get_input<Field<float>>("Scale");
+ Field<float3> center_field = params.get_input<Field<float3>>("Center");
+ Field<float3> axis_field;
+ if (scale_mode == GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS) {
+ axis_field = params.get_input<Field<float3>>("Axis");
+ }
+
+ geometry.modify_geometry_sets([&](GeometrySet &geometry) {
+ if (!geometry.has_mesh()) {
+ return;
+ }
+ MeshComponent &mesh_component = geometry.get_component_for_write<MeshComponent>();
+ switch (domain) {
+ case ATTR_DOMAIN_FACE: {
+ switch (scale_mode) {
+ case GEO_NODE_SCALE_ELEMENTS_UNIFORM: {
+ scale_faces_uniformly(mesh_component, {selection_field, scale_field, center_field});
+ break;
+ }
+ case GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS: {
+ scale_faces_on_axis(mesh_component,
+ {selection_field, scale_field, center_field, axis_field});
+ break;
+ }
+ }
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ switch (scale_mode) {
+ case GEO_NODE_SCALE_ELEMENTS_UNIFORM: {
+ scale_edges_uniformly(mesh_component, {selection_field, scale_field, center_field});
+ break;
+ }
+ case GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS: {
+ scale_edges_on_axis(mesh_component,
+ {selection_field, scale_field, center_field, axis_field});
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ });
+
+ params.set_output("Geometry", std::move(geometry));
+}
+
+} // namespace blender::nodes::node_geo_scale_elements_cc
+
+void register_node_type_geo_scale_elements()
+{
+ namespace file_ns = blender::nodes::node_geo_scale_elements_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SCALE_ELEMENTS, "Scale Elements", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.initfunc = file_ns::node_init;
+ ntype.updatefunc = file_ns::node_update;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
new file mode 100644
index 00000000000..5bd2028ff41
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
@@ -0,0 +1,98 @@
+/*
+ * 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 "BLI_task.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_scale_instances_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Instances")).only_instances();
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Scale"))
+ .subtype(PROP_XYZ)
+ .default_value({1, 1, 1})
+ .supports_field();
+ b.add_input<decl::Vector>(N_("Center")).subtype(PROP_TRANSLATION).supports_field();
+ b.add_input<decl::Bool>(N_("Local Space")).default_value(true).supports_field();
+ b.add_output<decl::Geometry>(N_("Instances"));
+}
+
+static void scale_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
+{
+ GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
+
+ fn::FieldEvaluator evaluator{field_context, instances_component.instances_amount()};
+ evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
+ evaluator.add(params.extract_input<Field<float3>>("Scale"));
+ evaluator.add(params.extract_input<Field<float3>>("Center"));
+ evaluator.add(params.extract_input<Field<bool>>("Local Space"));
+ evaluator.evaluate();
+
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &scales = evaluator.get_evaluated<float3>(0);
+ const VArray<float3> &pivots = evaluator.get_evaluated<float3>(1);
+ const VArray<bool> &local_spaces = evaluator.get_evaluated<bool>(2);
+
+ MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
+
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i_selection : range) {
+ const int i = selection[i_selection];
+ const float3 pivot = pivots[i];
+ float4x4 &instance_transform = instance_transforms[i];
+
+ if (local_spaces[i]) {
+ instance_transform *= float4x4::from_location(pivot);
+ rescale_m4(instance_transform.values, scales[i]);
+ instance_transform *= float4x4::from_location(-pivot);
+ }
+ else {
+ const float4x4 original_transform = instance_transform;
+ instance_transform = float4x4::from_location(pivot);
+ rescale_m4(instance_transform.values, scales[i]);
+ instance_transform *= float4x4::from_location(-pivot);
+ instance_transform *= original_transform;
+ }
+ }
+ });
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
+ if (geometry_set.has_instances()) {
+ InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ scale_instances(params, instances);
+ }
+ params.set_output("Instances", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_scale_instances_cc
+
+void register_node_type_geo_scale_instances()
+{
+ namespace file_ns = blender::nodes::node_geo_scale_instances_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SCALE_INSTANCES, "Scale Instances", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
index dafd10cee2d..3e34378d3e0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
@@ -16,19 +16,19 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_separate_components_cc {
-static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_output<decl::Geometry>("Mesh");
- b.add_output<decl::Geometry>("Point Cloud");
- b.add_output<decl::Geometry>("Curve");
- b.add_output<decl::Geometry>("Volume");
- b.add_output<decl::Geometry>("Instances");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
+ b.add_output<decl::Geometry>(N_("Point Cloud"));
+ b.add_output<decl::Geometry>(N_("Curve"));
+ b.add_output<decl::Geometry>(N_("Volume"));
+ b.add_output<decl::Geometry>(N_("Instances"));
}
-static void geo_node_separate_components_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -61,15 +61,17 @@ static void geo_node_separate_components_exec(GeoNodeExecParams params)
params.set_output("Instances", instances);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_separate_components_cc
void register_node_type_geo_separate_components()
{
+ namespace file_ns = blender::nodes::node_geo_separate_components_cc;
+
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_SEPARATE_COMPONENTS, "Separate Components", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_join_geometry_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_separate_components_exec;
+ &ntype, GEO_NODE_SEPARATE_COMPONENTS, "Separate Components", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
new file mode 100644
index 00000000000..fec1ac1363e
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
@@ -0,0 +1,117 @@
+/*
+ * 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 "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_separate_geometry_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometrySeparateGeometry)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection"))
+ .default_value(true)
+ .hide_value()
+ .supports_field()
+ .description(N_("The parts of the geometry that go into the first output"));
+ b.add_output<decl::Geometry>(N_("Selection"))
+ .description(N_("The parts of the geometry in the selection"));
+ b.add_output<decl::Geometry>(N_("Inverted"))
+ .description(N_("The parts of the geometry not in the selection"));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometrySeparateGeometry *data = MEM_cnew<NodeGeometrySeparateGeometry>(__func__);
+ data->domain = ATTR_DOMAIN_POINT;
+
+ node->storage = data;
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+
+ const NodeGeometrySeparateGeometry &storage = node_storage(params.node());
+ const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+
+ auto separate_geometry_maybe_recursively = [&](GeometrySet &geometry_set, bool invert) {
+ bool is_error;
+ if (domain == ATTR_DOMAIN_INSTANCE) {
+ /* Only delete top level instances. */
+ separate_geometry(geometry_set,
+ domain,
+ GEO_NODE_DELETE_GEOMETRY_MODE_ALL,
+ selection_field,
+ invert,
+ is_error);
+ }
+ else {
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ separate_geometry(geometry_set,
+ domain,
+ GEO_NODE_DELETE_GEOMETRY_MODE_ALL,
+ selection_field,
+ invert,
+ is_error);
+ });
+ }
+ };
+
+ GeometrySet second_set(geometry_set);
+ if (params.output_is_required("Selection")) {
+ separate_geometry_maybe_recursively(geometry_set, false);
+ params.set_output("Selection", std::move(geometry_set));
+ }
+ if (params.output_is_required("Inverted")) {
+ separate_geometry_maybe_recursively(second_set, true);
+ params.set_output("Inverted", std::move(second_set));
+ }
+}
+
+} // namespace blender::nodes::node_geo_separate_geometry_cc
+
+void register_node_type_geo_separate_geometry()
+{
+ namespace file_ns = blender::nodes::node_geo_separate_geometry_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SEPARATE_GEOMETRY, "Separate Geometry", NODE_CLASS_GEOMETRY);
+
+ node_type_storage(&ntype,
+ "NodeGeometrySeparateGeometry",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+
+ node_type_init(&ntype, file_ns::node_init);
+
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
new file mode 100644
index 00000000000..82d09bbc208
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
@@ -0,0 +1,181 @@
+/*
+ * 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 "BKE_spline.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_set_curve_handles_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometrySetCurveHandlePositions)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Position")).implicit_field();
+ b.add_input<decl::Vector>(N_("Offset")).default_value(float3(0.0f, 0.0f, 0.0f)).supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometrySetCurveHandlePositions *data = MEM_cnew<NodeGeometrySetCurveHandlePositions>(
+ __func__);
+
+ data->mode = GEO_NODE_CURVE_HANDLE_LEFT;
+ node->storage = data;
+}
+
+static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
+ GeometryComponent &component,
+ const Field<bool> &selection_field,
+ const Field<float3> &position_field,
+ const Field<float3> &offset_field)
+{
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
+ return;
+ }
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add(position_field);
+ evaluator.add(offset_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+
+ CurveComponent *curve_component = static_cast<CurveComponent *>(&component);
+ CurveEval *curve = curve_component->get_for_write();
+
+ StringRef side = mode & GEO_NODE_CURVE_HANDLE_LEFT ? "handle_left" : "handle_right";
+
+ int current_point = 0;
+ int current_mask = 0;
+
+ for (const SplinePtr &spline : curve->splines()) {
+ if (spline->type() == Spline::Type::Bezier) {
+ BezierSpline &bezier = static_cast<BezierSpline &>(*spline);
+ for (int i : bezier.positions().index_range()) {
+ if (current_mask < selection.size() && selection[current_mask] == current_point) {
+ if (mode & GEO_NODE_CURVE_HANDLE_LEFT) {
+ if (bezier.handle_types_left()[i] == BezierSpline::HandleType::Vector) {
+ bezier.ensure_auto_handles();
+ bezier.handle_types_left()[i] = BezierSpline::HandleType::Free;
+ }
+ else if (bezier.handle_types_left()[i] == BezierSpline::HandleType::Auto) {
+ bezier.ensure_auto_handles();
+ bezier.handle_types_left()[i] = BezierSpline::HandleType::Align;
+ }
+ }
+ else {
+ if (bezier.handle_types_right()[i] == BezierSpline::HandleType::Vector) {
+ bezier.ensure_auto_handles();
+ bezier.handle_types_right()[i] = BezierSpline::HandleType::Free;
+ }
+ else if (bezier.handle_types_right()[i] == BezierSpline::HandleType::Auto) {
+ bezier.ensure_auto_handles();
+ bezier.handle_types_right()[i] = BezierSpline::HandleType::Align;
+ }
+ }
+ current_mask++;
+ }
+ current_point++;
+ }
+ }
+ else {
+ for ([[maybe_unused]] int i : spline->positions().index_range()) {
+ if (current_mask < selection.size() && selection[current_mask] == current_point) {
+ current_mask++;
+ }
+ current_point++;
+ }
+ }
+ }
+
+ const VArray<float3> &positions_input = evaluator.get_evaluated<float3>(0);
+ const VArray<float3> &offsets_input = evaluator.get_evaluated<float3>(1);
+
+ OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
+ side, ATTR_DOMAIN_POINT, {0, 0, 0});
+ MutableSpan<float3> position_mutable = positions.as_span();
+
+ for (int i : selection) {
+ position_mutable[i] = positions_input[i] + offsets_input[i];
+ }
+
+ positions.save();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeGeometrySetCurveHandlePositions &storage = node_storage(params.node());
+ const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage.mode;
+
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ Field<float3> position_field = params.extract_input<Field<float3>>("Position");
+ Field<float3> offset_field = params.extract_input<Field<float3>>("Offset");
+
+ bool has_bezier = false;
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_curve() &&
+ geometry_set.get_curve_for_read()->has_spline_with_type(Spline::Type::Bezier)) {
+ has_bezier = true;
+ set_position_in_component(mode,
+ geometry_set.get_component_for_write<CurveComponent>(),
+ selection_field,
+ position_field,
+ offset_field);
+ }
+ });
+ if (!has_bezier) {
+ params.error_message_add(NodeWarningType::Info,
+ TIP_("The input geometry does not contain a Bezier spline"));
+ }
+ params.set_output("Curve", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_set_curve_handles_cc
+
+void register_node_type_geo_set_curve_handles()
+{
+ namespace file_ns = blender::nodes::node_geo_set_curve_handles_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_SET_CURVE_HANDLES, "Set Handle Positions", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.minwidth = 100.0f;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_storage(&ntype,
+ "NodeGeometrySetCurveHandlePositions",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ ntype.draw_buttons = file_ns::node_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
new file mode 100644
index 00000000000..06fe4427520
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
@@ -0,0 +1,82 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_set_curve_radius_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Radius"))
+ .min(0.0f)
+ .default_value(1.0f)
+ .supports_field()
+ .subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Curve"));
+}
+
+static void set_radius_in_component(GeometryComponent &component,
+ const Field<bool> &selection_field,
+ const Field<float> &radius_field)
+{
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
+ return;
+ }
+
+ OutputAttribute_Typed<float> radii = component.attribute_try_get_for_output_only<float>(
+ "radius", ATTR_DOMAIN_POINT);
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(radius_field, radii.varray());
+ evaluator.evaluate();
+
+ radii.save();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ Field<float> radii_field = params.extract_input<Field<float>>("Radius");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_curve()) {
+ set_radius_in_component(
+ geometry_set.get_component_for_write<CurveComponent>(), selection_field, radii_field);
+ }
+ });
+
+ params.set_output("Curve", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_set_curve_radius_cc
+
+void register_node_type_geo_set_curve_radius()
+{
+ namespace file_ns = blender::nodes::node_geo_set_curve_radius_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_RADIUS, "Set Curve Radius", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
new file mode 100644
index 00000000000..0854d0a4549
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
@@ -0,0 +1,78 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_set_curve_tilt_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Tilt")).subtype(PROP_ANGLE).supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
+}
+
+static void set_tilt_in_component(GeometryComponent &component,
+ const Field<bool> &selection_field,
+ const Field<float> &tilt_field)
+{
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
+ return;
+ }
+
+ OutputAttribute_Typed<float> tilts = component.attribute_try_get_for_output_only<float>(
+ "tilt", ATTR_DOMAIN_POINT);
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(tilt_field, tilts.varray());
+ evaluator.evaluate();
+
+ tilts.save();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ Field<float> tilt_field = params.extract_input<Field<float>>("Tilt");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_curve()) {
+ set_tilt_in_component(
+ geometry_set.get_component_for_write<CurveComponent>(), selection_field, tilt_field);
+ }
+ });
+
+ params.set_output("Curve", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_set_curve_tilt_cc
+
+void register_node_type_geo_set_curve_tilt()
+{
+ namespace file_ns = blender::nodes::node_geo_set_curve_tilt_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_TILT, "Set Curve Tilt", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
new file mode 100644
index 00000000000..110b8206944
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
@@ -0,0 +1,94 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_set_id_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Int>(N_("ID")).implicit_field();
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void set_id_in_component(GeometryComponent &component,
+ const Field<bool> &selection_field,
+ const Field<int> &id_field)
+{
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
+ return;
+ }
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+
+ /* Since adding the ID attribute can change the result of the field evaluation (the random value
+ * node uses the index if the ID is unavailable), make sure that it isn't added before evaluating
+ * the field. However, as an optimization, use a faster code path when it already exists. */
+ if (component.attribute_exists("id")) {
+ OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
+ "id", ATTR_DOMAIN_POINT);
+ evaluator.add_with_destination(id_field, id_attribute.varray());
+ evaluator.evaluate();
+ id_attribute.save();
+ }
+ else {
+ evaluator.add(id_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<int> &result_ids = evaluator.get_evaluated<int>(0);
+ OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
+ "id", ATTR_DOMAIN_POINT);
+ result_ids.materialize(selection, id_attribute.as_span());
+ id_attribute.save();
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ Field<int> id_field = params.extract_input<Field<int>>("ID");
+
+ for (const GeometryComponentType type : {GEO_COMPONENT_TYPE_INSTANCES,
+ GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE}) {
+ if (geometry_set.has(type)) {
+ set_id_in_component(geometry_set.get_component_for_write(type), selection_field, id_field);
+ }
+ }
+
+ params.set_output("Geometry", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_set_id_cc
+
+void register_node_type_geo_set_id()
+{
+ namespace file_ns = blender::nodes::node_geo_set_id_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SET_ID, "Set ID", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
new file mode 100644
index 00000000000..ab2c778d6fc
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
@@ -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.
+ */
+
+#include "node_geometry_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_pointcloud_types.h"
+#include "DNA_volume_types.h"
+
+#include "BKE_material.h"
+
+namespace blender::nodes::node_geo_set_material_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"))
+ .supported_type(
+ {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_POINT_CLOUD});
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Material>(N_("Material")).hide_label();
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Material *material)
+{
+ if (selection.size() != mesh.totpoly) {
+ /* If the entire mesh isn't selected, and there is no material slot yet, add an empty
+ * slot so that the faces that aren't selected can still refer to the default material. */
+ BKE_id_material_eval_ensure_default_slot(&mesh.id);
+ }
+
+ int new_material_index = -1;
+ for (const int i : IndexRange(mesh.totcol)) {
+ Material *other_material = mesh.mat[i];
+ if (other_material == material) {
+ new_material_index = i;
+ break;
+ }
+ }
+ if (new_material_index == -1) {
+ /* Append a new material index. */
+ new_material_index = mesh.totcol;
+ BKE_id_material_eval_assign(&mesh.id, new_material_index + 1, material);
+ }
+
+ mesh.mpoly = (MPoly *)CustomData_duplicate_referenced_layer(&mesh.pdata, CD_MPOLY, mesh.totpoly);
+ for (const int i : selection) {
+ MPoly &poly = mesh.mpoly[i];
+ poly.mat_nr = new_material_index;
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Material *material = params.extract_input<Material *>("Material");
+ const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ /* Only add the warnings once, even if there are many unique instances. */
+ bool point_selection_warning = false;
+ bool volume_selection_warning = false;
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_mesh()) {
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ Mesh &mesh = *mesh_component.get_for_write();
+ GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
+
+ fn::FieldEvaluator selection_evaluator{field_context, mesh.totpoly};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+
+ assign_material_to_faces(mesh, selection, material);
+ }
+ if (Volume *volume = geometry_set.get_volume_for_write()) {
+ BKE_id_material_eval_assign(&volume->id, 1, material);
+ if (selection_field.node().depends_on_input()) {
+ volume_selection_warning = true;
+ }
+ }
+ if (PointCloud *pointcloud = geometry_set.get_pointcloud_for_write()) {
+ BKE_id_material_eval_assign(&pointcloud->id, 1, material);
+ if (selection_field.node().depends_on_input()) {
+ point_selection_warning = true;
+ }
+ }
+ });
+
+ if (volume_selection_warning) {
+ params.error_message_add(
+ NodeWarningType::Info,
+ TIP_("Volumes only support a single material; selection input can not be a field"));
+ }
+ if (point_selection_warning) {
+ params.error_message_add(
+ NodeWarningType::Info,
+ TIP_("Point clouds only support a single material; selection input can not be a field"));
+ }
+
+ params.set_output("Geometry", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_set_material_cc
+
+void register_node_type_geo_set_material()
+{
+ namespace file_ns = blender::nodes::node_geo_set_material_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SET_MATERIAL, "Set Material", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
new file mode 100644
index 00000000000..ca6d78adc80
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
@@ -0,0 +1,77 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_set_material_index_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Int>(N_("Material Index")).supports_field().min(0);
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void set_material_index_in_component(GeometryComponent &component,
+ const Field<bool> &selection_field,
+ const Field<int> &index_field)
+{
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ if (domain_size == 0) {
+ return;
+ }
+
+ OutputAttribute_Typed<int> indices = component.attribute_try_get_for_output_only<int>(
+ "material_index", ATTR_DOMAIN_FACE);
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(index_field, indices.varray());
+ evaluator.evaluate();
+ indices.save();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ Field<int> index_field = params.extract_input<Field<int>>("Material Index");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_mesh()) {
+ set_material_index_in_component(
+ geometry_set.get_component_for_write<MeshComponent>(), selection_field, index_field);
+ }
+ });
+ params.set_output("Geometry", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_set_material_index_cc
+
+void register_node_type_geo_set_material_index()
+{
+ namespace file_ns = blender::nodes::node_geo_set_material_index_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_SET_MATERIAL_INDEX, "Set Material Index", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
new file mode 100644
index 00000000000..b7dd091da44
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
@@ -0,0 +1,83 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_set_point_radius_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Points")).supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Radius"))
+ .default_value(0.05f)
+ .min(0.0f)
+ .supports_field()
+ .subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Points"));
+}
+
+static void set_radius_in_component(GeometryComponent &component,
+ const Field<bool> &selection_field,
+ const Field<float> &radius_field)
+{
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
+ return;
+ }
+
+ OutputAttribute_Typed<float> radii = component.attribute_try_get_for_output_only<float>(
+ "radius", ATTR_DOMAIN_POINT);
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(radius_field, radii.varray());
+ evaluator.evaluate();
+
+ radii.save();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ Field<float> radii_field = params.extract_input<Field<float>>("Radius");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_pointcloud()) {
+ set_radius_in_component(geometry_set.get_component_for_write<PointCloudComponent>(),
+ selection_field,
+ radii_field);
+ }
+ });
+
+ params.set_output("Points", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_set_point_radius_cc
+
+void register_node_type_geo_set_point_radius()
+{
+ namespace file_ns = blender::nodes::node_geo_set_point_radius_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SET_POINT_RADIUS, "Set Point Radius", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
index 8caf961fc04..4a8e4e6eab8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -16,45 +16,126 @@
#include "DEG_depsgraph_query.h"
+#include "BLI_task.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_position_cc {
-static void geo_node_set_position_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Vector>("Position").implicit_field();
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Position")).implicit_field();
+ b.add_input<decl::Vector>(N_("Offset")).supports_field().subtype(PROP_TRANSLATION);
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void set_computed_position_and_offset(GeometryComponent &component,
+ const VArray<float3> &in_positions,
+ const VArray<float3> &in_offsets,
+ const AttributeDomain domain,
+ const IndexMask selection)
+{
+
+ OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
+ "position", domain, {0, 0, 0});
+
+ const int grain_size = 10000;
+
+ switch (component.type()) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ Mesh *mesh = static_cast<MeshComponent &>(component).get_for_write();
+ MutableSpan<MVert> mverts{mesh->mvert, mesh->totvert};
+ if (in_positions.is_same(positions.varray())) {
+ devirtualize_varray(in_offsets, [&](const auto in_offsets) {
+ threading::parallel_for(
+ selection.index_range(), grain_size, [&](const IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const float3 offset = in_offsets[i];
+ add_v3_v3(mverts[i].co, offset);
+ }
+ });
+ });
+ }
+ else {
+ devirtualize_varray2(
+ in_positions, in_offsets, [&](const auto in_positions, const auto in_offsets) {
+ threading::parallel_for(
+ selection.index_range(), grain_size, [&](const IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const float3 new_position = in_positions[i] + in_offsets[i];
+ copy_v3_v3(mverts[i].co, new_position);
+ }
+ });
+ });
+ }
+ break;
+ }
+ default: {
+ MutableSpan<float3> out_positions_span = positions.as_span();
+ if (in_positions.is_same(positions.varray())) {
+ devirtualize_varray(in_offsets, [&](const auto in_offsets) {
+ threading::parallel_for(
+ selection.index_range(), grain_size, [&](const IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ out_positions_span[i] += in_offsets[i];
+ }
+ });
+ });
+ }
+ else {
+ devirtualize_varray2(
+ in_positions, in_offsets, [&](const auto in_positions, const auto in_offsets) {
+ threading::parallel_for(
+ selection.index_range(), grain_size, [&](const IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ out_positions_span[i] = in_positions[i] + in_offsets[i];
+ }
+ });
+ });
+ }
+ break;
+ }
+ }
+
+ positions.save();
}
static void set_position_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
- const Field<float3> &position_field)
+ const Field<float3> &position_field,
+ const Field<float3> &offset_field)
{
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ AttributeDomain domain = component.type() == GEO_COMPONENT_TYPE_INSTANCES ?
+ ATTR_DOMAIN_INSTANCE :
+ ATTR_DOMAIN_POINT;
+ GeometryComponentFieldContext field_context{component, domain};
+ const int domain_size = component.attribute_domain_size(domain);
if (domain_size == 0) {
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add(position_field);
+ evaluator.add(offset_field);
+ evaluator.evaluate();
- OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
- "position", ATTR_DOMAIN_POINT, {0, 0, 0});
- fn::FieldEvaluator position_evaluator{field_context, &selection};
- position_evaluator.add_with_destination(position_field, positions.varray());
- position_evaluator.evaluate();
- positions.save();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &positions_input = evaluator.get_evaluated<float3>(0);
+ const VArray<float3> &offsets_input = evaluator.get_evaluated<float3>(1);
+ set_computed_position_and_offset(component, positions_input, offsets_input, domain, selection);
}
-static void geo_node_set_position_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ Field<float3> offset_field = params.extract_input<Field<float3>>("Offset");
Field<float3> position_field = params.extract_input<Field<float3>>("Position");
for (const GeometryComponentType type : {GEO_COMPONENT_TYPE_MESH,
@@ -63,21 +144,23 @@ static void geo_node_set_position_exec(GeoNodeExecParams params)
GEO_COMPONENT_TYPE_INSTANCES}) {
if (geometry.has(type)) {
set_position_in_component(
- geometry.get_component_for_write(type), selection_field, position_field);
+ geometry.get_component_for_write(type), selection_field, position_field, offset_field);
}
}
params.set_output("Geometry", std::move(geometry));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_position_cc
void register_node_type_geo_set_position()
{
+ namespace file_ns = blender::nodes::node_geo_set_position_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SET_POSITION, "Set Position", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_position_exec;
- ntype.declare = blender::nodes::geo_node_set_position_declare;
+ geo_node_type_base(&ntype, GEO_NODE_SET_POSITION, "Set Position", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
new file mode 100644
index 00000000000..d442cd37e81
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
@@ -0,0 +1,77 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_set_shade_smooth_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Bool>(N_("Shade Smooth")).supports_field().default_value(true);
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void set_smooth_in_component(GeometryComponent &component,
+ const Field<bool> &selection_field,
+ const Field<bool> &shade_field)
+{
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ if (domain_size == 0) {
+ return;
+ }
+
+ OutputAttribute_Typed<bool> shades = component.attribute_try_get_for_output_only<bool>(
+ "shade_smooth", ATTR_DOMAIN_FACE);
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(shade_field, shades.varray());
+ evaluator.evaluate();
+
+ shades.save();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ Field<bool> shade_field = params.extract_input<Field<bool>>("Shade Smooth");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_mesh()) {
+ set_smooth_in_component(
+ geometry_set.get_component_for_write<MeshComponent>(), selection_field, shade_field);
+ }
+ });
+ params.set_output("Geometry", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_set_shade_smooth_cc
+
+void register_node_type_geo_set_shade_smooth()
+{
+ namespace file_ns = blender::nodes::node_geo_set_shade_smooth_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SET_SHADE_SMOOTH, "Set Shade Smooth", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
new file mode 100644
index 00000000000..13230e185a3
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
@@ -0,0 +1,78 @@
+/*
+ * 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 "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_set_spline_cyclic_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Bool>(N_("Cyclic")).supports_field();
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void set_cyclic_in_component(GeometryComponent &component,
+ const Field<bool> &selection_field,
+ const Field<bool> &cyclic_field)
+{
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+ if (domain_size == 0) {
+ return;
+ }
+
+ OutputAttribute_Typed<bool> cyclics = component.attribute_try_get_for_output_only<bool>(
+ "cyclic", ATTR_DOMAIN_CURVE);
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(cyclic_field, cyclics.varray());
+ evaluator.evaluate();
+
+ cyclics.save();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ Field<bool> cyclic_field = params.extract_input<Field<bool>>("Cyclic");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_curve()) {
+ set_cyclic_in_component(
+ geometry_set.get_component_for_write<CurveComponent>(), selection_field, cyclic_field);
+ }
+ });
+
+ params.set_output("Geometry", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_set_spline_cyclic_cc
+
+void register_node_type_geo_set_spline_cyclic()
+{
+ namespace file_ns = blender::nodes::node_geo_set_spline_cyclic_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SET_SPLINE_CYCLIC, "Set Spline Cyclic", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
new file mode 100644
index 00000000000..e472e14671c
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
@@ -0,0 +1,95 @@
+/*
+ * 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 "BKE_spline.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_set_spline_resolution_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Int>(N_("Resolution")).min(1).default_value(12).supports_field();
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void set_resolution_in_component(GeometryComponent &component,
+ const Field<bool> &selection_field,
+ const Field<int> &resolution_field)
+{
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+ if (domain_size == 0) {
+ return;
+ }
+
+ OutputAttribute_Typed<int> resolutions = component.attribute_try_get_for_output_only<int>(
+ "resolution", ATTR_DOMAIN_CURVE);
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(resolution_field, resolutions.varray());
+ evaluator.evaluate();
+
+ resolutions.save();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ Field<int> resolution_field = params.extract_input<Field<int>>("Resolution");
+
+ bool only_poly = true;
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_curve()) {
+ if (only_poly) {
+ for (const SplinePtr &spline : geometry_set.get_curve_for_read()->splines()) {
+ if (ELEM(spline->type(), Spline::Type::Bezier, Spline::Type::NURBS)) {
+ only_poly = false;
+ break;
+ }
+ }
+ }
+ set_resolution_in_component(geometry_set.get_component_for_write<CurveComponent>(),
+ selection_field,
+ resolution_field);
+ }
+ });
+
+ if (only_poly) {
+ params.error_message_add(NodeWarningType::Warning,
+ TIP_("Input geometry does not contain a Bezier or NURB spline"));
+ }
+ params.set_output("Geometry", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_set_spline_resolution_cc
+
+void register_node_type_geo_set_spline_resolution()
+{
+ namespace file_ns = blender::nodes::node_geo_set_spline_resolution_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_SET_SPLINE_RESOLUTION, "Set Spline Resolution", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
index 1e4a4d1f68b..176fcf3178a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
@@ -16,16 +16,16 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_string_join_cc {
-static void geo_node_string_join_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::String>("Delimiter");
- b.add_input<decl::String>("Strings").multi_input().hide_value();
- b.add_output<decl::String>("String");
-};
+ b.add_input<decl::String>(N_("Delimiter"));
+ b.add_input<decl::String>(N_("Strings")).multi_input().hide_value();
+ b.add_output<decl::String>(N_("String"));
+}
-static void geo_node_string_join_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Vector<std::string> strings = params.extract_multi_input<std::string>("Strings");
const std::string delim = params.extract_input<std::string>("Delimiter");
@@ -40,14 +40,16 @@ static void geo_node_string_join_exec(GeoNodeExecParams params)
params.set_output("String", std::move(output));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_string_join_cc
void register_node_type_geo_string_join()
{
+ namespace file_ns = blender::nodes::node_geo_string_join_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_STRING_JOIN, "String Join", NODE_CLASS_CONVERTER, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_string_join_exec;
- ntype.declare = blender::nodes::geo_node_string_join_declare;
+ geo_node_type_base(&ntype, GEO_NODE_STRING_JOIN, "Join Strings", NODE_CLASS_CONVERTER);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
index 5e2f03806c3..10c0d61ccb6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
@@ -18,8 +18,8 @@
#include "DNA_vfont_types.h"
#include "BKE_curve.h"
-#include "BKE_font.h"
#include "BKE_spline.hh"
+#include "BKE_vfont.h"
#include "BLI_hash.h"
#include "BLI_string_utf8.h"
@@ -30,25 +30,44 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_string_to_curves_cc {
-static void geo_node_string_to_curves_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryStringToCurves)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::String>("String");
- b.add_input<decl::Float>("Size").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Character Spacing")
+ b.add_input<decl::String>(N_("String"));
+ b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Character Spacing"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Word Spacing"))
.default_value(1.0f)
.min(0.0f)
.subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Word Spacing").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Line Spacing").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Text Box Width").default_value(0.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Text Box Height").default_value(0.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>("Curves");
- b.add_output<decl::String>("Remainder");
+ b.add_input<decl::Float>(N_("Line Spacing"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Text Box Width"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Text Box Height"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) {
+ node_storage(node).overflow = GEO_NODE_STRING_TO_CURVES_MODE_SCALE_TO_FIT;
+ });
+ b.add_output<decl::Geometry>(N_("Curve Instances"));
+ b.add_output<decl::String>(N_("Remainder")).make_available([](bNode &node) {
+ node_storage(node).overflow = GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE;
+ });
}
-static void geo_node_string_to_curves_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr)
+static void node_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -67,10 +86,9 @@ static void geo_node_string_to_curves_layout(uiLayout *layout, struct bContext *
uiItemR(layout, ptr, "align_y", 0, "", ICON_NONE);
}
-static void geo_node_string_to_curves_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryStringToCurves *data = (NodeGeometryStringToCurves *)MEM_callocN(
- sizeof(NodeGeometryStringToCurves), __func__);
+ NodeGeometryStringToCurves *data = MEM_cnew<NodeGeometryStringToCurves>(__func__);
data->overflow = GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW;
data->align_x = GEO_NODE_STRING_TO_CURVES_ALIGN_X_LEFT;
@@ -79,17 +97,19 @@ static void geo_node_string_to_curves_init(bNodeTree *UNUSED(ntree), bNode *node
node->id = (ID *)BKE_vfont_builtin_get();
}
-static void geo_node_string_to_curves_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryStringToCurves *storage = (const NodeGeometryStringToCurves *)node->storage;
+ const NodeGeometryStringToCurves &storage = node_storage(*node);
const GeometryNodeStringToCurvesOverflowMode overflow = (GeometryNodeStringToCurvesOverflowMode)
- storage->overflow;
+ storage.overflow;
bNodeSocket *socket_remainder = ((bNodeSocket *)node->outputs.first)->next;
- nodeSetSocketAvailability(socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE);
+ nodeSetSocketAvailability(
+ ntree, socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE);
bNodeSocket *height_socket = (bNodeSocket *)node->inputs.last;
bNodeSocket *width_socket = height_socket->prev;
- nodeSetSocketAvailability(height_socket, overflow != GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW);
+ nodeSetSocketAvailability(
+ ntree, height_socket, overflow != GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW);
node_sock_label(width_socket,
overflow == GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW ? N_("Max Width") :
N_("Text Box Width"));
@@ -117,8 +137,7 @@ static TextLayout get_text_layout(GeoNodeExecParams &params)
return {};
}
- const NodeGeometryStringToCurves &storage =
- *(const NodeGeometryStringToCurves *)params.node().storage;
+ const NodeGeometryStringToCurves &storage = node_storage(params.node());
const GeometryNodeStringToCurvesOverflowMode overflow = (GeometryNodeStringToCurvesOverflowMode)
storage.overflow;
const GeometryNodeStringToCurvesAlignXMode align_x = (GeometryNodeStringToCurvesAlignXMode)
@@ -136,7 +155,7 @@ static TextLayout get_text_layout(GeoNodeExecParams &params)
params.extract_input<float>("Text Box Height");
VFont *vfont = (VFont *)params.node().id;
- Curve cu = {nullptr};
+ Curve cu = {{nullptr}};
cu.type = OB_FONT;
/* Set defaults */
cu.resolu = 12;
@@ -214,7 +233,7 @@ static Map<int, int> create_curve_instances(GeoNodeExecParams &params,
if (handles.contains(charcodes[i])) {
continue;
}
- Curve cu = {nullptr};
+ Curve cu = {{nullptr}};
cu.type = OB_FONT;
cu.resolu = 12;
cu.vfont = vfont;
@@ -242,18 +261,16 @@ static void add_instances_from_handles(InstancesComponent &instances,
instances.resize(positions.size());
MutableSpan<int> handles = instances.instance_reference_handles();
MutableSpan<float4x4> transforms = instances.instance_transforms();
- MutableSpan<int> instance_ids = instances.instance_ids();
threading::parallel_for(IndexRange(positions.size()), 256, [&](IndexRange range) {
for (const int i : range) {
handles[i] = char_handles.lookup(charcodes[i]);
transforms[i] = float4x4::from_location({positions[i].x, positions[i].y, 0});
- instance_ids[i] = i;
}
});
}
-static void geo_node_string_to_curves_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
TextLayout layout = get_text_layout(params);
@@ -264,15 +281,16 @@ static void geo_node_string_to_curves_exec(GeoNodeExecParams params)
}
if (layout.positions.size() == 0) {
- params.set_output("Curves", GeometrySet());
+ params.set_output("Curve Instances", GeometrySet());
return;
}
/* Convert UTF-8 encoded string to UTF-32. */
size_t len_bytes;
size_t len_chars = BLI_strlen_utf8_ex(layout.text.c_str(), &len_bytes);
- Array<char32_t> char_codes(len_chars + 1);
- BLI_str_utf8_as_utf32(char_codes.data(), layout.text.c_str(), len_chars + 1);
+ Array<char32_t> char_codes_with_null(len_chars + 1);
+ BLI_str_utf8_as_utf32(char_codes_with_null.data(), layout.text.c_str(), len_chars + 1);
+ const Span<char32_t> char_codes = char_codes_with_null.as_span().drop_back(1);
/* Create and add instances. */
GeometrySet geometry_set_out;
@@ -281,26 +299,27 @@ static void geo_node_string_to_curves_exec(GeoNodeExecParams params)
params, layout.final_font_size, char_codes, instances);
add_instances_from_handles(instances, char_handles, char_codes, layout.positions);
- params.set_output("Curves", std::move(geometry_set_out));
+ params.set_output("Curve Instances", std::move(geometry_set_out));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_string_to_curves_cc
void register_node_type_geo_string_to_curves()
{
+ namespace file_ns = blender::nodes::node_geo_string_to_curves_cc;
+
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_STRING_TO_CURVES, "String to Curves", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_string_to_curves_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_string_to_curves_exec;
- node_type_init(&ntype, blender::nodes::geo_node_string_to_curves_init);
- node_type_update(&ntype, blender::nodes::geo_node_string_to_curves_update);
+ geo_node_type_base(&ntype, GEO_NODE_STRING_TO_CURVES, "String to Curves", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_size(&ntype, 190, 120, 700);
node_type_storage(&ntype,
"NodeGeometryStringToCurves",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_string_to_curves_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
new file mode 100644
index 00000000000..eb1a5496845
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -0,0 +1,166 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BKE_mesh.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_mesh.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_subdivision_surface_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometrySubdivisionSurface)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
+ b.add_input<decl::Float>(N_("Crease"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .supports_field()
+ .subtype(PROP_FACTOR);
+ b.add_output<decl::Geometry>(N_("Mesh"));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "uv_smooth", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "boundary_smooth", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometrySubdivisionSurface *data = MEM_cnew<NodeGeometrySubdivisionSurface>(__func__);
+ data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
+ data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL;
+ node->storage = data;
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+#ifndef WITH_OPENSUBDIV
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Disabled, Blender was compiled without OpenSubdiv"));
+#else
+ Field<float> crease_field = params.extract_input<Field<float>>("Crease");
+
+ const NodeGeometrySubdivisionSurface &storage = node_storage(params.node());
+ const int uv_smooth = storage.uv_smooth;
+ const int boundary_smooth = storage.boundary_smooth;
+ const int subdiv_level = clamp_i(params.extract_input<int>("Level"), 0, 30);
+
+ /* Only process subdivision if level is greater than 0. */
+ if (subdiv_level == 0) {
+ params.set_output("Mesh", std::move(geometry_set));
+ return;
+ }
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (!geometry_set.has_mesh()) {
+ return;
+ }
+
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ AttributeDomain domain = ATTR_DOMAIN_EDGE;
+ GeometryComponentFieldContext field_context{mesh_component, domain};
+ const int domain_size = mesh_component.attribute_domain_size(domain);
+
+ if (domain_size == 0) {
+ return;
+ }
+
+ FieldEvaluator evaluator(field_context, domain_size);
+ evaluator.add(crease_field);
+ evaluator.evaluate();
+ const VArray<float> &creases = evaluator.get_evaluated<float>(0);
+
+ OutputAttribute_Typed<float> crease = mesh_component.attribute_try_get_for_output_only<float>(
+ "crease", domain);
+ MutableSpan<float> crease_span = crease.as_span();
+ for (auto i : creases.index_range()) {
+ crease_span[i] = std::clamp(creases[i], 0.0f, 1.0f);
+ }
+ crease.save();
+
+ /* Initialize mesh settings. */
+ SubdivToMeshSettings mesh_settings;
+ mesh_settings.resolution = (1 << subdiv_level) + 1;
+ mesh_settings.use_optimal_display = false;
+
+ /* Initialize subdivision settings. */
+ SubdivSettings subdiv_settings;
+ subdiv_settings.is_simple = false;
+ subdiv_settings.is_adaptive = false;
+ subdiv_settings.use_creases = !(creases.is_single() && creases.get_internal_single() == 0.0f);
+ subdiv_settings.level = subdiv_level;
+
+ subdiv_settings.vtx_boundary_interpolation =
+ BKE_subdiv_vtx_boundary_interpolation_from_subsurf(boundary_smooth);
+ subdiv_settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
+ uv_smooth);
+
+ Mesh *mesh_in = mesh_component.get_for_write();
+
+ /* Apply subdivision to mesh. */
+ Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, mesh_in);
+
+ /* In case of bad topology, skip to input mesh. */
+ if (subdiv == nullptr) {
+ return;
+ }
+
+ Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh_in);
+ BKE_mesh_normals_tag_dirty(mesh_out);
+
+ mesh_component.replace(mesh_out);
+
+ BKE_subdiv_free(subdiv);
+ });
+#endif
+ params.set_output("Mesh", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_subdivision_surface_cc
+
+void register_node_type_geo_subdivision_surface()
+{
+ namespace file_ns = blender::nodes::node_geo_subdivision_surface_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_storage(&ntype,
+ "NodeGeometrySubdivisionSurface",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
index ca857c4d2e3..a2f05677310 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
@@ -19,149 +19,298 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
-static void geo_node_switch_declare(NodeDeclarationBuilder &b)
+#include "BKE_material.h"
+
+#include "NOD_socket_search_link.hh"
+
+#include "FN_multi_function_signature.hh"
+
+namespace blender::nodes::node_geo_switch_cc {
+
+NODE_STORAGE_FUNCS(NodeSwitch)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Bool>("Switch");
-
- b.add_input<decl::Float>("False");
- b.add_input<decl::Float>("True");
- b.add_input<decl::Int>("False", "False_001").min(-100000).max(100000);
- b.add_input<decl::Int>("True", "True_001").min(-100000).max(100000);
- b.add_input<decl::Bool>("False", "False_002");
- b.add_input<decl::Bool>("True", "True_002");
- b.add_input<decl::Vector>("False", "False_003");
- b.add_input<decl::Vector>("True", "True_003");
- b.add_input<decl::Color>("False", "False_004").default_value({0.8f, 0.8f, 0.8f, 1.0f});
- b.add_input<decl::Color>("True", "True_004").default_value({0.8f, 0.8f, 0.8f, 1.0f});
- b.add_input<decl::String>("False", "False_005");
- b.add_input<decl::String>("True", "True_005");
- b.add_input<decl::Geometry>("False", "False_006");
- b.add_input<decl::Geometry>("True", "True_006");
- b.add_input<decl::Object>("False", "False_007");
- b.add_input<decl::Object>("True", "True_007");
- b.add_input<decl::Collection>("False", "False_008");
- b.add_input<decl::Collection>("True", "True_008");
- b.add_input<decl::Texture>("False", "False_009");
- b.add_input<decl::Texture>("True", "True_009");
- b.add_input<decl::Material>("False", "False_010");
- b.add_input<decl::Material>("True", "True_010");
-
- b.add_output<decl::Float>("Output");
- b.add_output<decl::Int>("Output", "Output_001");
- b.add_output<decl::Bool>("Output", "Output_002");
- b.add_output<decl::Vector>("Output", "Output_003");
- b.add_output<decl::Color>("Output", "Output_004");
- b.add_output<decl::String>("Output", "Output_005");
- b.add_output<decl::Geometry>("Output", "Output_006");
- b.add_output<decl::Object>("Output", "Output_007");
- b.add_output<decl::Collection>("Output", "Output_008");
- b.add_output<decl::Texture>("Output", "Output_009");
- b.add_output<decl::Material>("Output", "Output_010");
+ b.add_input<decl::Bool>(N_("Switch")).default_value(false).supports_field();
+ b.add_input<decl::Bool>(N_("Switch"), "Switch_001").default_value(false);
+
+ b.add_input<decl::Float>(N_("False")).supports_field();
+ b.add_input<decl::Float>(N_("True")).supports_field();
+ b.add_input<decl::Int>(N_("False"), "False_001").min(-100000).max(100000).supports_field();
+ b.add_input<decl::Int>(N_("True"), "True_001").min(-100000).max(100000).supports_field();
+ b.add_input<decl::Bool>(N_("False"), "False_002")
+ .default_value(false)
+ .hide_value()
+ .supports_field();
+ b.add_input<decl::Bool>(N_("True"), "True_002")
+ .default_value(true)
+ .hide_value()
+ .supports_field();
+ b.add_input<decl::Vector>(N_("False"), "False_003").supports_field();
+ b.add_input<decl::Vector>(N_("True"), "True_003").supports_field();
+ b.add_input<decl::Color>(N_("False"), "False_004")
+ .default_value({0.8f, 0.8f, 0.8f, 1.0f})
+ .supports_field();
+ b.add_input<decl::Color>(N_("True"), "True_004")
+ .default_value({0.8f, 0.8f, 0.8f, 1.0f})
+ .supports_field();
+ b.add_input<decl::String>(N_("False"), "False_005").supports_field();
+ b.add_input<decl::String>(N_("True"), "True_005").supports_field();
+
+ b.add_input<decl::Geometry>(N_("False"), "False_006");
+ b.add_input<decl::Geometry>(N_("True"), "True_006");
+ b.add_input<decl::Object>(N_("False"), "False_007");
+ b.add_input<decl::Object>(N_("True"), "True_007");
+ b.add_input<decl::Collection>(N_("False"), "False_008");
+ b.add_input<decl::Collection>(N_("True"), "True_008");
+ b.add_input<decl::Texture>(N_("False"), "False_009");
+ b.add_input<decl::Texture>(N_("True"), "True_009");
+ b.add_input<decl::Material>(N_("False"), "False_010");
+ b.add_input<decl::Material>(N_("True"), "True_010");
+ b.add_input<decl::Image>(N_("False"), "False_011");
+ b.add_input<decl::Image>(N_("True"), "True_011");
+
+ b.add_output<decl::Float>(N_("Output")).dependent_field();
+ b.add_output<decl::Int>(N_("Output"), "Output_001").dependent_field();
+ b.add_output<decl::Bool>(N_("Output"), "Output_002").dependent_field();
+ b.add_output<decl::Vector>(N_("Output"), "Output_003").dependent_field();
+ b.add_output<decl::Color>(N_("Output"), "Output_004").dependent_field();
+ b.add_output<decl::String>(N_("Output"), "Output_005").dependent_field();
+ b.add_output<decl::Geometry>(N_("Output"), "Output_006");
+ b.add_output<decl::Object>(N_("Output"), "Output_007");
+ b.add_output<decl::Collection>(N_("Output"), "Output_008");
+ b.add_output<decl::Texture>(N_("Output"), "Output_009");
+ b.add_output<decl::Material>(N_("Output"), "Output_010");
+ b.add_output<decl::Image>(N_("Output"), "Output_011");
}
-static void geo_node_switch_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "input_type", 0, "", ICON_NONE);
}
-static void geo_node_switch_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeSwitch *data = (NodeSwitch *)MEM_callocN(sizeof(NodeSwitch), __func__);
+ NodeSwitch *data = MEM_cnew<NodeSwitch>(__func__);
data->input_type = SOCK_GEOMETRY;
node->storage = data;
}
-static void geo_node_switch_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeSwitch *node_storage = (NodeSwitch *)node->storage;
+ const NodeSwitch &storage = node_storage(*node);
int index = 0;
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- nodeSetSocketAvailability(
- socket, index == 0 || socket->type == (eNodeSocketDatatype)node_storage->input_type);
- index++;
+ bNodeSocket *field_switch = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *non_field_switch = (bNodeSocket *)field_switch->next;
+
+ const bool fields_type = ELEM(
+ storage.input_type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA, SOCK_STRING);
+
+ nodeSetSocketAvailability(ntree, field_switch, fields_type);
+ nodeSetSocketAvailability(ntree, non_field_switch, !fields_type);
+
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &node->inputs, index) {
+ if (index <= 1) {
+ continue;
+ }
+ nodeSetSocketAvailability(ntree, socket, socket->type == storage.input_type);
}
+
LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
- nodeSetSocketAvailability(socket,
- socket->type == (eNodeSocketDatatype)node_storage->input_type);
+ nodeSetSocketAvailability(ntree, socket, socket->type == storage.input_type);
}
}
-template<typename T>
-static void output_input(GeoNodeExecParams &params,
- const bool input,
- const StringRef input_suffix,
- const StringRef output_identifier)
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
{
- const std::string name_a = "False" + input_suffix;
- const std::string name_b = "True" + input_suffix;
- if (input) {
- params.set_input_unused(name_a);
- if (params.lazy_require_input(name_b)) {
+ if (params.in_out() == SOCK_OUT) {
+ params.add_item(IFACE_("Output"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSwitch");
+ node_storage(node).input_type = params.socket.type;
+ params.update_and_connect_available_socket(node, "Output");
+ });
+ }
+ else {
+ if (params.other_socket().type == SOCK_BOOLEAN) {
+ params.add_item(IFACE_("Switch"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSwitch");
+ params.connect_available_socket(node, "Start");
+ });
+ }
+ params.add_item(IFACE_("False"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSwitch");
+ node_storage(node).input_type = params.socket.type;
+ params.update_and_connect_available_socket(node, "False");
+ });
+ params.add_item(IFACE_("True"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSwitch");
+ node_storage(node).input_type = params.socket.type;
+ params.update_and_connect_available_socket(node, "True");
+ });
+ }
+}
+
+template<typename T> class SwitchFieldsFunction : public fn::MultiFunction {
+ public:
+ SwitchFieldsFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Switch"};
+ signature.single_input<bool>("Switch");
+ signature.single_input<T>("False");
+ signature.single_input<T>("True");
+ signature.single_output<T>("Output");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<bool> &switches = params.readonly_single_input<bool>(0, "Switch");
+ const VArray<T> &falses = params.readonly_single_input<T>(1, "False");
+ const VArray<T> &trues = params.readonly_single_input<T>(2, "True");
+ MutableSpan<T> values = params.uninitialized_single_output_if_required<T>(3, "Output");
+ for (int64_t i : mask) {
+ new (&values[i]) T(switches[i] ? trues[i] : falses[i]);
+ }
+ }
+};
+
+template<typename T> void switch_fields(GeoNodeExecParams &params, const StringRef suffix)
+{
+ if (params.lazy_require_input("Switch")) {
+ return;
+ }
+
+ const std::string name_false = "False" + suffix;
+ const std::string name_true = "True" + suffix;
+ const std::string name_output = "Output" + suffix;
+
+ Field<bool> switches_field = params.get_input<Field<bool>>("Switch");
+ if (switches_field.node().depends_on_input()) {
+ /* The switch has to be incorporated into the field. Both inputs have to be evaluated. */
+ const bool require_false = params.lazy_require_input(name_false);
+ const bool require_true = params.lazy_require_input(name_true);
+ if (require_false | require_true) {
return;
}
- params.set_output(output_identifier, params.extract_input<T>(name_b));
+
+ Field<T> falses_field = params.extract_input<Field<T>>(name_false);
+ Field<T> trues_field = params.extract_input<Field<T>>(name_true);
+
+ auto switch_fn = std::make_unique<SwitchFieldsFunction<T>>();
+ auto switch_op = std::make_shared<FieldOperation>(FieldOperation(
+ std::move(switch_fn),
+ {std::move(switches_field), std::move(falses_field), std::move(trues_field)}));
+
+ params.set_output(name_output, Field<T>(switch_op, 0));
}
else {
- params.set_input_unused(name_b);
- if (params.lazy_require_input(name_a)) {
- return;
+ /* The switch input is constant, so just evaluate and forward one of the inputs. */
+ const bool switch_value = fn::evaluate_constant_field(switches_field);
+ if (switch_value) {
+ params.set_input_unused(name_false);
+ if (params.lazy_require_input(name_true)) {
+ return;
+ }
+ params.set_output(name_output, params.extract_input<Field<T>>(name_true));
+ }
+ else {
+ params.set_input_unused(name_true);
+ if (params.lazy_require_input(name_false)) {
+ return;
+ }
+ params.set_output(name_output, params.extract_input<Field<T>>(name_false));
}
- params.set_output(output_identifier, params.extract_input<T>(name_a));
}
}
-static void geo_node_switch_exec(GeoNodeExecParams params)
+template<typename T> void switch_no_fields(GeoNodeExecParams &params, const StringRef suffix)
{
- if (params.lazy_require_input("Switch")) {
+ if (params.lazy_require_input("Switch_001")) {
return;
}
- const NodeSwitch &storage = *(const NodeSwitch *)params.node().storage;
- const bool input = params.get_input<bool>("Switch");
- switch ((eNodeSocketDatatype)storage.input_type) {
+ bool switch_value = params.get_input<bool>("Switch_001");
+
+ const std::string name_false = "False" + suffix;
+ const std::string name_true = "True" + suffix;
+ const std::string name_output = "Output" + suffix;
+
+ if (switch_value) {
+ params.set_input_unused(name_false);
+ if (params.lazy_require_input(name_true)) {
+ return;
+ }
+ params.set_output(name_output, params.extract_input<T>(name_true));
+ }
+ else {
+ params.set_input_unused(name_true);
+ if (params.lazy_require_input(name_false)) {
+ return;
+ }
+ params.set_output(name_output, params.extract_input<T>(name_false));
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeSwitch &storage = node_storage(params.node());
+ const eNodeSocketDatatype data_type = static_cast<eNodeSocketDatatype>(storage.input_type);
+
+ switch (data_type) {
+
case SOCK_FLOAT: {
- output_input<float>(params, input, "", "Output");
+ switch_fields<float>(params, "");
break;
}
case SOCK_INT: {
- output_input<int>(params, input, "_001", "Output_001");
+ switch_fields<int>(params, "_001");
break;
}
case SOCK_BOOLEAN: {
- output_input<bool>(params, input, "_002", "Output_002");
+ switch_fields<bool>(params, "_002");
break;
}
case SOCK_VECTOR: {
- output_input<float3>(params, input, "_003", "Output_003");
+ switch_fields<float3>(params, "_003");
break;
}
case SOCK_RGBA: {
- output_input<ColorGeometry4f>(params, input, "_004", "Output_004");
+ switch_fields<ColorGeometry4f>(params, "_004");
break;
}
case SOCK_STRING: {
- output_input<std::string>(params, input, "_005", "Output_005");
+ switch_fields<std::string>(params, "_005");
break;
}
case SOCK_GEOMETRY: {
- output_input<GeometrySet>(params, input, "_006", "Output_006");
+ switch_no_fields<GeometrySet>(params, "_006");
break;
}
case SOCK_OBJECT: {
- output_input<Object *>(params, input, "_007", "Output_007");
+ switch_no_fields<Object *>(params, "_007");
break;
}
case SOCK_COLLECTION: {
- output_input<Collection *>(params, input, "_008", "Output_008");
+ switch_no_fields<Collection *>(params, "_008");
break;
}
case SOCK_TEXTURE: {
- output_input<Tex *>(params, input, "_009", "Output_009");
+ switch_no_fields<Tex *>(params, "_009");
break;
}
case SOCK_MATERIAL: {
- output_input<Material *>(params, input, "_010", "Output_010");
+ switch_no_fields<Material *>(params, "_010");
+ break;
+ }
+ case SOCK_IMAGE: {
+ switch_no_fields<Image *>(params, "_011");
break;
}
default:
@@ -170,19 +319,22 @@ static void geo_node_switch_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_switch_cc
void register_node_type_geo_switch()
{
+ namespace file_ns = blender::nodes::node_geo_switch_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::geo_node_switch_declare;
- node_type_init(&ntype, blender::nodes::geo_node_switch_init);
- node_type_update(&ntype, blender::nodes::geo_node_switch_update);
+ geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype, "NodeSwitch", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_switch_exec;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.geometry_node_execute_supports_laziness = true;
- ntype.draw_buttons = blender::nodes::geo_node_switch_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
new file mode 100644
index 00000000000..5a8d9ab470d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
@@ -0,0 +1,842 @@
+/*
+ * 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 "BLI_kdopbvh.h"
+#include "BLI_task.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_pointcloud_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_bvhutils.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_sample.hh"
+
+#include "FN_generic_array.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "NOD_socket_search_link.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_transfer_attribute_cc {
+
+using namespace blender::bke::mesh_surface_sample;
+using blender::fn::GArray;
+
+NODE_STORAGE_FUNCS(NodeGeometryTransferAttribute)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Source"))
+ .supported_type({GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_INSTANCES});
+
+ b.add_input<decl::Vector>(N_("Attribute")).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Attribute"), "Attribute_001").hide_value().supports_field();
+ b.add_input<decl::Color>(N_("Attribute"), "Attribute_002").hide_value().supports_field();
+ b.add_input<decl::Bool>(N_("Attribute"), "Attribute_003").hide_value().supports_field();
+ b.add_input<decl::Int>(N_("Attribute"), "Attribute_004").hide_value().supports_field();
+
+ b.add_input<decl::Vector>(N_("Source Position"))
+ .implicit_field()
+ .make_available([](bNode &node) {
+ node_storage(node).mode = GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED;
+ });
+ b.add_input<decl::Int>(N_("Index")).implicit_field().make_available([](bNode &node) {
+ node_storage(node).mode = GEO_NODE_ATTRIBUTE_TRANSFER_INDEX;
+ });
+
+ b.add_output<decl::Vector>(N_("Attribute")).dependent_field({6, 7});
+ b.add_output<decl::Float>(N_("Attribute"), "Attribute_001").dependent_field({6, 7});
+ b.add_output<decl::Color>(N_("Attribute"), "Attribute_002").dependent_field({6, 7});
+ b.add_output<decl::Bool>(N_("Attribute"), "Attribute_003").dependent_field({6, 7});
+ b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({6, 7});
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ const bNode &node = *static_cast<const bNode *>(ptr->data);
+ const NodeGeometryTransferAttribute &storage = node_storage(node);
+ const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
+ storage.mode;
+
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE);
+ if (mapping != GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED) {
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+ }
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryTransferAttribute *data = MEM_cnew<NodeGeometryTransferAttribute>(__func__);
+ data->data_type = CD_PROP_FLOAT;
+ data->mode = GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeGeometryTransferAttribute &storage = node_storage(*node);
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
+ storage.mode;
+
+ bNodeSocket *socket_geometry = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *socket_vector = socket_geometry->next;
+ bNodeSocket *socket_float = socket_vector->next;
+ bNodeSocket *socket_color4f = socket_float->next;
+ bNodeSocket *socket_boolean = socket_color4f->next;
+ bNodeSocket *socket_int32 = socket_boolean->next;
+
+ bNodeSocket *socket_positions = socket_int32->next;
+ bNodeSocket *socket_indices = socket_positions->next;
+
+ nodeSetSocketAvailability(ntree, socket_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, socket_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, socket_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, socket_boolean, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(ntree, socket_int32, data_type == CD_PROP_INT32);
+
+ nodeSetSocketAvailability(ntree, socket_positions, mapping != GEO_NODE_ATTRIBUTE_TRANSFER_INDEX);
+ nodeSetSocketAvailability(ntree, socket_indices, mapping == GEO_NODE_ATTRIBUTE_TRANSFER_INDEX);
+
+ bNodeSocket *out_socket_vector = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *out_socket_float = out_socket_vector->next;
+ bNodeSocket *out_socket_color4f = out_socket_float->next;
+ bNodeSocket *out_socket_boolean = out_socket_color4f->next;
+ bNodeSocket *out_socket_int32 = out_socket_boolean->next;
+
+ nodeSetSocketAvailability(ntree, out_socket_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, out_socket_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, out_socket_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, out_socket_boolean, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32);
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_back(2));
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+
+ const std::optional<CustomDataType> type = node_data_type_to_custom_data_type(
+ (eNodeSocketDatatype)params.other_socket().type);
+ if (type && *type != CD_PROP_STRING) {
+ /* The input and output sockets have the same name. */
+ params.add_item(IFACE_("Attribute"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAttributeTransfer");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Attribute");
+ });
+ }
+}
+
+static void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_indices,
+ const MutableSpan<float> r_distances_sq,
+ const MutableSpan<float3> r_positions)
+{
+ BLI_assert(positions.size() >= r_indices.size());
+ BLI_assert(positions.size() >= r_distances_sq.size());
+ BLI_assert(positions.size() >= r_positions.size());
+
+ for (const int i : mask) {
+ BVHTreeNearest nearest;
+ nearest.dist_sq = FLT_MAX;
+ const float3 position = positions[i];
+ BLI_bvhtree_find_nearest(
+ tree_data.tree, position, &nearest, tree_data.nearest_callback, &tree_data);
+ if (!r_indices.is_empty()) {
+ r_indices[i] = nearest.index;
+ }
+ if (!r_distances_sq.is_empty()) {
+ r_distances_sq[i] = nearest.dist_sq;
+ }
+ if (!r_positions.is_empty()) {
+ r_positions[i] = nearest.co;
+ }
+ }
+}
+
+static void get_closest_pointcloud_points(const PointCloud &pointcloud,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_indices,
+ const MutableSpan<float> r_distances_sq)
+{
+ BLI_assert(positions.size() >= r_indices.size());
+ BLI_assert(pointcloud.totpoint > 0);
+
+ BVHTreeFromPointCloud tree_data;
+ BKE_bvhtree_from_pointcloud_get(&tree_data, &pointcloud, 2);
+
+ for (const int i : mask) {
+ BVHTreeNearest nearest;
+ nearest.dist_sq = FLT_MAX;
+ const float3 position = positions[i];
+ BLI_bvhtree_find_nearest(
+ tree_data.tree, position, &nearest, tree_data.nearest_callback, &tree_data);
+ r_indices[i] = nearest.index;
+ if (!r_distances_sq.is_empty()) {
+ r_distances_sq[i] = nearest.dist_sq;
+ }
+ }
+
+ free_bvhtree_from_pointcloud(&tree_data);
+}
+
+static void get_closest_mesh_points(const Mesh &mesh,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_point_indices,
+ const MutableSpan<float> r_distances_sq,
+ const MutableSpan<float3> r_positions)
+{
+ BLI_assert(mesh.totvert > 0);
+ BVHTreeFromMesh tree_data;
+ BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_VERTS, 2);
+ get_closest_in_bvhtree(tree_data, positions, mask, r_point_indices, r_distances_sq, r_positions);
+ free_bvhtree_from_mesh(&tree_data);
+}
+
+static void get_closest_mesh_edges(const Mesh &mesh,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_edge_indices,
+ const MutableSpan<float> r_distances_sq,
+ const MutableSpan<float3> r_positions)
+{
+ BLI_assert(mesh.totedge > 0);
+ BVHTreeFromMesh tree_data;
+ BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_EDGES, 2);
+ get_closest_in_bvhtree(tree_data, positions, mask, r_edge_indices, r_distances_sq, r_positions);
+ free_bvhtree_from_mesh(&tree_data);
+}
+
+static void get_closest_mesh_looptris(const Mesh &mesh,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_looptri_indices,
+ const MutableSpan<float> r_distances_sq,
+ const MutableSpan<float3> r_positions)
+{
+ BLI_assert(mesh.totpoly > 0);
+ BVHTreeFromMesh tree_data;
+ BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_LOOPTRI, 2);
+ get_closest_in_bvhtree(
+ tree_data, positions, mask, r_looptri_indices, r_distances_sq, r_positions);
+ free_bvhtree_from_mesh(&tree_data);
+}
+
+static void get_closest_mesh_polygons(const Mesh &mesh,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_poly_indices,
+ const MutableSpan<float> r_distances_sq,
+ const MutableSpan<float3> r_positions)
+{
+ BLI_assert(mesh.totpoly > 0);
+
+ Array<int> looptri_indices(positions.size());
+ get_closest_mesh_looptris(mesh, positions, mask, looptri_indices, r_distances_sq, r_positions);
+
+ const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
+ BKE_mesh_runtime_looptri_len(&mesh)};
+
+ for (const int i : mask) {
+ const MLoopTri &looptri = looptris[looptri_indices[i]];
+ r_poly_indices[i] = looptri.poly;
+ }
+}
+
+/* The closest corner is defined to be the closest corner on the closest face. */
+static void get_closest_mesh_corners(const Mesh &mesh,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_corner_indices,
+ const MutableSpan<float> r_distances_sq,
+ const MutableSpan<float3> r_positions)
+{
+ BLI_assert(mesh.totloop > 0);
+ Array<int> poly_indices(positions.size());
+ get_closest_mesh_polygons(mesh, positions, mask, poly_indices, {}, {});
+
+ for (const int i : mask) {
+ const float3 position = positions[i];
+ const int poly_index = poly_indices[i];
+ const MPoly &poly = mesh.mpoly[poly_index];
+
+ /* Find the closest vertex in the polygon. */
+ float min_distance_sq = FLT_MAX;
+ const MVert *closest_mvert;
+ int closest_loop_index = 0;
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ const int vertex_index = loop.v;
+ const MVert &mvert = mesh.mvert[vertex_index];
+ const float distance_sq = math::distance_squared(position, float3(mvert.co));
+ if (distance_sq < min_distance_sq) {
+ min_distance_sq = distance_sq;
+ closest_loop_index = loop_index;
+ closest_mvert = &mvert;
+ }
+ }
+ if (!r_corner_indices.is_empty()) {
+ r_corner_indices[i] = closest_loop_index;
+ }
+ if (!r_positions.is_empty()) {
+ r_positions[i] = closest_mvert->co;
+ }
+ if (!r_distances_sq.is_empty()) {
+ r_distances_sq[i] = min_distance_sq;
+ }
+ }
+}
+
+template<typename T>
+void copy_with_indices(const VArray<T> &src,
+ const IndexMask mask,
+ const Span<int> indices,
+ const MutableSpan<T> dst)
+{
+ if (src.is_empty()) {
+ return;
+ }
+ for (const int i : mask) {
+ dst[i] = src[indices[i]];
+ }
+}
+
+template<typename T>
+void copy_with_indices_clamped(const VArray<T> &src,
+ const IndexMask mask,
+ const VArray<int> &indices,
+ const MutableSpan<T> dst)
+{
+ if (src.is_empty()) {
+ return;
+ }
+ const int max_index = src.size() - 1;
+ threading::parallel_for(mask.index_range(), 4096, [&](IndexRange range) {
+ for (const int i : range) {
+ const int index = mask[i];
+ dst[index] = src[std::clamp(indices[index], 0, max_index)];
+ }
+ });
+}
+
+template<typename T>
+void copy_with_indices_and_comparison(const VArray<T> &src_1,
+ const VArray<T> &src_2,
+ const Span<float> distances_1,
+ const Span<float> distances_2,
+ const IndexMask mask,
+ const Span<int> indices_1,
+ const Span<int> indices_2,
+ const MutableSpan<T> dst)
+{
+ if (src_1.is_empty() || src_2.is_empty()) {
+ return;
+ }
+ for (const int i : mask) {
+ if (distances_1[i] < distances_2[i]) {
+ dst[i] = src_1[indices_1[i]];
+ }
+ else {
+ dst[i] = src_2[indices_2[i]];
+ }
+ }
+}
+
+static bool component_is_available(const GeometrySet &geometry,
+ const GeometryComponentType type,
+ const AttributeDomain domain)
+{
+ if (!geometry.has(type)) {
+ return false;
+ }
+ const GeometryComponent &component = *geometry.get_component_for_read(type);
+ if (component.is_empty()) {
+ return false;
+ }
+ return component.attribute_domain_size(domain) != 0;
+}
+
+/**
+ * \note Multi-threading for this function is provided by the field evaluator. Since the #call
+ * function could be called many times, calculate the data from the target geometry once and store
+ * it for later.
+ */
+class NearestInterpolatedTransferFunction : public fn::MultiFunction {
+ GeometrySet target_;
+ GField src_field_;
+
+ /**
+ * This function is meant to sample the surface of a mesh rather than take the value from
+ * individual elements, so use the most complex domain, ensuring no information is lost. In the
+ * future, it should be possible to use the most complex domain required by the field inputs, to
+ * simplify sampling and avoid domain conversions.
+ */
+ AttributeDomain domain_ = ATTR_DOMAIN_CORNER;
+
+ fn::MFSignature signature_;
+
+ std::optional<GeometryComponentFieldContext> target_context_;
+ std::unique_ptr<FieldEvaluator> target_evaluator_;
+ const GVArray *target_data_;
+
+ public:
+ NearestInterpolatedTransferFunction(GeometrySet geometry, GField src_field)
+ : target_(std::move(geometry)), src_field_(std::move(src_field))
+ {
+ target_.ensure_owns_direct_data();
+ signature_ = this->create_signature();
+ this->set_signature(&signature_);
+ this->evaluate_target_field();
+ }
+
+ fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Attribute Transfer Nearest Interpolated"};
+ signature.single_input<float3>("Position");
+ signature.single_output("Attribute", src_field_.cpp_type());
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float3> &positions = params.readonly_single_input<float3>(0, "Position");
+ GMutableSpan dst = params.uninitialized_single_output_if_required(1, "Attribute");
+
+ const MeshComponent &mesh_component = *target_.get_component_for_read<MeshComponent>();
+ BLI_assert(mesh_component.has_mesh());
+ const Mesh &mesh = *mesh_component.get_for_read();
+ BLI_assert(mesh.totpoly > 0);
+
+ /* Find closest points on the mesh surface. */
+ Array<int> looptri_indices(mask.min_array_size());
+ Array<float3> sampled_positions(mask.min_array_size());
+ get_closest_mesh_looptris(mesh, positions, mask, looptri_indices, {}, sampled_positions);
+
+ MeshAttributeInterpolator interp(&mesh, mask, sampled_positions, looptri_indices);
+ interp.sample_data(*target_data_, domain_, eAttributeMapMode::INTERPOLATED, dst);
+ }
+
+ private:
+ void evaluate_target_field()
+ {
+ const MeshComponent &mesh_component = *target_.get_component_for_read<MeshComponent>();
+ target_context_.emplace(GeometryComponentFieldContext{mesh_component, domain_});
+ const int domain_size = mesh_component.attribute_domain_size(domain_);
+ target_evaluator_ = std::make_unique<FieldEvaluator>(*target_context_, domain_size);
+ target_evaluator_->add(src_field_);
+ target_evaluator_->evaluate();
+ target_data_ = &target_evaluator_->get_evaluated(0);
+ }
+};
+
+/**
+ * \note Multi-threading for this function is provided by the field evaluator. Since the #call
+ * function could be called many times, calculate the data from the target geometry once and store
+ * it for later.
+ */
+class NearestTransferFunction : public fn::MultiFunction {
+ GeometrySet target_;
+ GField src_field_;
+ AttributeDomain domain_;
+
+ fn::MFSignature signature_;
+
+ bool use_mesh_;
+ bool use_points_;
+
+ /* Store data from the target as a virtual array, since we may only access a few indices. */
+ std::optional<GeometryComponentFieldContext> mesh_context_;
+ std::unique_ptr<FieldEvaluator> mesh_evaluator_;
+ const GVArray *mesh_data_;
+
+ std::optional<GeometryComponentFieldContext> point_context_;
+ std::unique_ptr<FieldEvaluator> point_evaluator_;
+ const GVArray *point_data_;
+
+ public:
+ NearestTransferFunction(GeometrySet geometry, GField src_field, AttributeDomain domain)
+ : target_(std::move(geometry)), src_field_(std::move(src_field)), domain_(domain)
+ {
+ target_.ensure_owns_direct_data();
+ signature_ = this->create_signature();
+ this->set_signature(&signature_);
+
+ this->use_mesh_ = component_is_available(target_, GEO_COMPONENT_TYPE_MESH, domain_);
+ this->use_points_ = component_is_available(target_, GEO_COMPONENT_TYPE_POINT_CLOUD, domain_);
+
+ this->evaluate_target_field();
+ }
+
+ fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Attribute Transfer Nearest"};
+ signature.single_input<float3>("Position");
+ signature.single_output("Attribute", src_field_.cpp_type());
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float3> &positions = params.readonly_single_input<float3>(0, "Position");
+ GMutableSpan dst = params.uninitialized_single_output_if_required(1, "Attribute");
+
+ if (!use_mesh_ && !use_points_) {
+ dst.type().fill_construct_indices(dst.type().default_value(), dst.data(), mask);
+ return;
+ }
+
+ const Mesh *mesh = use_mesh_ ? target_.get_mesh_for_read() : nullptr;
+ const PointCloud *pointcloud = use_points_ ? target_.get_pointcloud_for_read() : nullptr;
+
+ const int tot_samples = mask.min_array_size();
+
+ Array<int> point_indices;
+ Array<float> point_distances;
+
+ /* Depending on where what domain the source attribute lives, these indices are either vertex,
+ * corner, edge or polygon indices. */
+ Array<int> mesh_indices;
+ Array<float> mesh_distances;
+
+ /* If there is a point cloud, find the closest points. */
+ if (use_points_) {
+ point_indices.reinitialize(tot_samples);
+ if (use_mesh_) {
+ point_distances.reinitialize(tot_samples);
+ }
+ get_closest_pointcloud_points(*pointcloud, positions, mask, point_indices, point_distances);
+ }
+
+ /* If there is a mesh, find the closest mesh elements. */
+ if (use_mesh_) {
+ mesh_indices.reinitialize(tot_samples);
+ if (use_points_) {
+ mesh_distances.reinitialize(tot_samples);
+ }
+ switch (domain_) {
+ case ATTR_DOMAIN_POINT: {
+ get_closest_mesh_points(*mesh, positions, mask, mesh_indices, mesh_distances, {});
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ get_closest_mesh_edges(*mesh, positions, mask, mesh_indices, mesh_distances, {});
+ break;
+ }
+ case ATTR_DOMAIN_FACE: {
+ get_closest_mesh_polygons(*mesh, positions, mask, mesh_indices, mesh_distances, {});
+ break;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ get_closest_mesh_corners(*mesh, positions, mask, mesh_indices, mesh_distances, {});
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+
+ attribute_math::convert_to_static_type(dst.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ if (use_mesh_ && use_points_) {
+ VArray<T> src_mesh = mesh_data_->typed<T>();
+ VArray<T> src_point = point_data_->typed<T>();
+ copy_with_indices_and_comparison(src_mesh,
+ src_point,
+ mesh_distances,
+ point_distances,
+ mask,
+ mesh_indices,
+ point_indices,
+ dst.typed<T>());
+ }
+ else if (use_points_) {
+ VArray<T> src_point = point_data_->typed<T>();
+ copy_with_indices(src_point, mask, point_indices, dst.typed<T>());
+ }
+ else if (use_mesh_) {
+ VArray<T> src_mesh = mesh_data_->typed<T>();
+ copy_with_indices(src_mesh, mask, mesh_indices, dst.typed<T>());
+ }
+ });
+ }
+
+ private:
+ void evaluate_target_field()
+ {
+ if (use_mesh_) {
+ const MeshComponent &mesh = *target_.get_component_for_read<MeshComponent>();
+ const int domain_size = mesh.attribute_domain_size(domain_);
+ mesh_context_.emplace(GeometryComponentFieldContext(mesh, domain_));
+ mesh_evaluator_ = std::make_unique<FieldEvaluator>(*mesh_context_, domain_size);
+ mesh_evaluator_->add(src_field_);
+ mesh_evaluator_->evaluate();
+ mesh_data_ = &mesh_evaluator_->get_evaluated(0);
+ }
+
+ if (use_points_) {
+ const PointCloudComponent &points = *target_.get_component_for_read<PointCloudComponent>();
+ const int domain_size = points.attribute_domain_size(domain_);
+ point_context_.emplace(GeometryComponentFieldContext(points, domain_));
+ point_evaluator_ = std::make_unique<FieldEvaluator>(*point_context_, domain_size);
+ point_evaluator_->add(src_field_);
+ point_evaluator_->evaluate();
+ point_data_ = &point_evaluator_->get_evaluated(0);
+ }
+ }
+};
+
+static const GeometryComponent *find_target_component(const GeometrySet &geometry,
+ const AttributeDomain domain)
+{
+ /* Choose the other component based on a consistent order, rather than some more complicated
+ * heuristic. This is the same order visible in the spreadsheet and used in the ray-cast node. */
+ static const Array<GeometryComponentType> supported_types = {GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_INSTANCES};
+ for (const GeometryComponentType src_type : supported_types) {
+ if (component_is_available(geometry, src_type, domain)) {
+ return geometry.get_component_for_read(src_type);
+ }
+ }
+
+ return nullptr;
+}
+
+/**
+ * The index-based transfer theoretically does not need realized data when there is only one
+ * instance geometry set in the target. A future optimization could be removing that limitation
+ * internally.
+ */
+class IndexTransferFunction : public fn::MultiFunction {
+ GeometrySet src_geometry_;
+ GField src_field_;
+ AttributeDomain domain_;
+
+ fn::MFSignature signature_;
+
+ std::optional<GeometryComponentFieldContext> geometry_context_;
+ std::unique_ptr<FieldEvaluator> evaluator_;
+ const GVArray *src_data_ = nullptr;
+
+ public:
+ IndexTransferFunction(GeometrySet geometry, GField src_field, const AttributeDomain domain)
+ : src_geometry_(std::move(geometry)), src_field_(std::move(src_field)), domain_(domain)
+ {
+ src_geometry_.ensure_owns_direct_data();
+
+ signature_ = this->create_signature();
+ this->set_signature(&signature_);
+
+ this->evaluate_field();
+ }
+
+ fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Attribute Transfer Index"};
+ signature.single_input<int>("Index");
+ signature.single_output("Attribute", src_field_.cpp_type());
+ return signature.build();
+ }
+
+ void evaluate_field()
+ {
+ const GeometryComponent *component = find_target_component(src_geometry_, domain_);
+ if (component == nullptr) {
+ return;
+ }
+ const int domain_size = component->attribute_domain_size(domain_);
+ geometry_context_.emplace(GeometryComponentFieldContext(*component, domain_));
+ evaluator_ = std::make_unique<FieldEvaluator>(*geometry_context_, domain_size);
+ evaluator_->add(src_field_);
+ evaluator_->evaluate();
+ src_data_ = &evaluator_->get_evaluated(0);
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<int> &indices = params.readonly_single_input<int>(0, "Index");
+ GMutableSpan dst = params.uninitialized_single_output(1, "Attribute");
+
+ const CPPType &type = dst.type();
+ if (src_data_ == nullptr) {
+ type.fill_construct_indices(type.default_value(), dst.data(), mask);
+ return;
+ }
+
+ attribute_math::convert_to_static_type(type, [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_with_indices_clamped(src_data_->typed<T>(), mask, indices, dst.typed<T>());
+ });
+ }
+};
+
+static GField get_input_attribute_field(GeoNodeExecParams &params, const CustomDataType data_type)
+{
+ switch (data_type) {
+ case CD_PROP_FLOAT:
+ return params.extract_input<Field<float>>("Attribute_001");
+ case CD_PROP_FLOAT3:
+ return params.extract_input<Field<float3>>("Attribute");
+ case CD_PROP_COLOR:
+ return params.extract_input<Field<ColorGeometry4f>>("Attribute_002");
+ case CD_PROP_BOOL:
+ return params.extract_input<Field<bool>>("Attribute_003");
+ case CD_PROP_INT32:
+ return params.extract_input<Field<int>>("Attribute_004");
+ default:
+ BLI_assert_unreachable();
+ }
+ return {};
+}
+
+static void output_attribute_field(GeoNodeExecParams &params, GField field)
+{
+ switch (bke::cpp_type_to_custom_data_type(field.cpp_type())) {
+ case CD_PROP_FLOAT: {
+ params.set_output("Attribute_001", Field<float>(field));
+ break;
+ }
+ case CD_PROP_FLOAT3: {
+ params.set_output("Attribute", Field<float3>(field));
+ break;
+ }
+ case CD_PROP_COLOR: {
+ params.set_output("Attribute_002", Field<ColorGeometry4f>(field));
+ break;
+ }
+ case CD_PROP_BOOL: {
+ params.set_output("Attribute_003", Field<bool>(field));
+ break;
+ }
+ case CD_PROP_INT32: {
+ params.set_output("Attribute_004", Field<int>(field));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry = params.extract_input<GeometrySet>("Source");
+ const NodeGeometryTransferAttribute &storage = node_storage(params.node());
+ const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
+ storage.mode;
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+
+ GField field = get_input_attribute_field(params, data_type);
+
+ auto return_default = [&]() {
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ output_attribute_field(params, fn::make_constant_field<T>(T()));
+ });
+ };
+
+ GField output_field;
+ switch (mapping) {
+ case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED: {
+ const Mesh *mesh = geometry.get_mesh_for_read();
+ if (mesh == nullptr) {
+ if (!geometry.is_empty()) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("The target geometry must contain a mesh"));
+ }
+ return return_default();
+ }
+ if (mesh->totpoly == 0) {
+ /* Don't add a warning for empty meshes. */
+ if (mesh->totvert != 0) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("The target mesh must have faces"));
+ }
+ return return_default();
+ }
+ auto fn = std::make_unique<NearestInterpolatedTransferFunction>(std::move(geometry),
+ std::move(field));
+ auto op = std::make_shared<FieldOperation>(
+ FieldOperation(std::move(fn), {params.extract_input<Field<float3>>("Source Position")}));
+ output_field = GField(std::move(op));
+ break;
+ }
+ case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST: {
+ if (geometry.has_curve() && !geometry.has_mesh() && !geometry.has_pointcloud()) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("The target geometry must contain a mesh or a point cloud"));
+ return return_default();
+ }
+ auto fn = std::make_unique<NearestTransferFunction>(
+ std::move(geometry), std::move(field), domain);
+ auto op = std::make_shared<FieldOperation>(
+ FieldOperation(std::move(fn), {params.extract_input<Field<float3>>("Source Position")}));
+ output_field = GField(std::move(op));
+ break;
+ }
+ case GEO_NODE_ATTRIBUTE_TRANSFER_INDEX: {
+ Field<int> indices = params.extract_input<Field<int>>("Index");
+ auto fn = std::make_unique<IndexTransferFunction>(
+ std::move(geometry), std::move(field), domain);
+ auto op = std::make_shared<FieldOperation>(
+ FieldOperation(std::move(fn), {std::move(indices)}));
+ output_field = GField(std::move(op));
+ break;
+ }
+ }
+
+ output_attribute_field(params, std::move(output_field));
+}
+
+} // namespace blender::nodes::node_geo_transfer_attribute_cc
+
+void register_node_type_geo_transfer_attribute()
+{
+ namespace file_ns = blender::nodes::node_geo_transfer_attribute_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_TRANSFER_ATTRIBUTE, "Transfer Attribute", NODE_CLASS_ATTRIBUTE);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_storage(&ntype,
+ "NodeGeometryTransferAttribute",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index d5eb067cad0..6187a2eacf9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -25,6 +25,7 @@
#include "DNA_volume_types.h"
#include "BKE_mesh.h"
+#include "BKE_pointcloud.h"
#include "BKE_spline.hh"
#include "BKE_volume.h"
@@ -34,18 +35,9 @@
namespace blender::nodes {
-static void geo_node_transform_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Vector>("Translation").subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>("Rotation").subtype(PROP_EULER);
- b.add_input<decl::Vector>("Scale").default_value({1, 1, 1}).subtype(PROP_XYZ);
- b.add_output<decl::Geometry>("Geometry");
-}
-
static bool use_translate(const float3 rotation, const float3 scale)
{
- if (compare_ff(rotation.length_squared(), 0.0f, 1e-9f) != 1) {
+ if (compare_ff(math::length_squared(rotation), 0.0f, 1e-9f) != 1) {
return false;
}
if (compare_ff(scale.x, 1.0f, 1e-9f) != 1 || compare_ff(scale.y, 1.0f, 1e-9f) != 1 ||
@@ -55,153 +47,187 @@ static bool use_translate(const float3 rotation, const float3 scale)
return true;
}
-void transform_mesh(Mesh *mesh,
- const float3 translation,
- const float3 rotation,
- const float3 scale)
+static void translate_mesh(Mesh &mesh, const float3 translation)
{
- /* Use only translation if rotation and scale are zero. */
- if (use_translate(rotation, scale)) {
- if (!translation.is_zero()) {
- BKE_mesh_translate(mesh, translation, false);
- }
- }
- else {
- const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
- BKE_mesh_transform(mesh, matrix.values, false);
- BKE_mesh_normals_tag_dirty(mesh);
+ if (!math::is_zero(translation)) {
+ BKE_mesh_translate(&mesh, translation, false);
}
}
-static void transform_pointcloud(PointCloud *pointcloud,
- const float3 translation,
- const float3 rotation,
- const float3 scale)
+static void transform_mesh(Mesh &mesh, const float4x4 &transform)
{
- /* Use only translation if rotation and scale don't apply. */
- if (use_translate(rotation, scale)) {
- for (const int i : IndexRange(pointcloud->totpoint)) {
- add_v3_v3(pointcloud->co[i], translation);
- }
+ BKE_mesh_transform(&mesh, transform.values, false);
+ BKE_mesh_normals_tag_dirty(&mesh);
+}
+
+static void translate_pointcloud(PointCloud &pointcloud, const float3 translation)
+{
+ CustomData_duplicate_referenced_layer(&pointcloud.pdata, CD_PROP_FLOAT3, pointcloud.totpoint);
+ BKE_pointcloud_update_customdata_pointers(&pointcloud);
+ for (const int i : IndexRange(pointcloud.totpoint)) {
+ add_v3_v3(pointcloud.co[i], translation);
}
- else {
- const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
- for (const int i : IndexRange(pointcloud->totpoint)) {
- float3 &co = *(float3 *)pointcloud->co[i];
- co = matrix * co;
- }
+}
+
+static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transform)
+{
+ CustomData_duplicate_referenced_layer(&pointcloud.pdata, CD_PROP_FLOAT3, pointcloud.totpoint);
+ BKE_pointcloud_update_customdata_pointers(&pointcloud);
+ for (const int i : IndexRange(pointcloud.totpoint)) {
+ float3 &co = *(float3 *)pointcloud.co[i];
+ co = transform * co;
}
}
-static void transform_instances(InstancesComponent &instances,
- const float3 translation,
- const float3 rotation,
- const float3 scale)
+static void translate_instances(InstancesComponent &instances, const float3 translation)
{
MutableSpan<float4x4> transforms = instances.instance_transforms();
-
- /* Use only translation if rotation and scale don't apply. */
- if (use_translate(rotation, scale)) {
- for (float4x4 &transform : transforms) {
- add_v3_v3(transform.ptr()[3], translation);
- }
+ for (float4x4 &transform : transforms) {
+ add_v3_v3(transform.ptr()[3], translation);
}
- else {
- const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
- for (float4x4 &transform : transforms) {
- transform = matrix * transform;
- }
+}
+
+static void transform_instances(InstancesComponent &instances, const float4x4 &transform)
+{
+ MutableSpan<float4x4> instance_transforms = instances.instance_transforms();
+ for (float4x4 &instance_transform : instance_transforms) {
+ instance_transform = transform * instance_transform;
}
}
-static void transform_volume(Volume *volume,
- const float3 translation,
- const float3 rotation,
- const float3 scale,
- GeoNodeExecParams &params)
+static void transform_volume(Volume &volume, const float4x4 &transform, const Depsgraph &depsgraph)
{
#ifdef WITH_OPENVDB
/* Scaling an axis to zero is not supported for volumes. */
+ const float3 translation = transform.translation();
+ const float3 rotation = transform.to_euler();
+ const float3 scale = transform.scale();
const float3 limited_scale = {
(scale.x == 0.0f) ? FLT_EPSILON : scale.x,
(scale.y == 0.0f) ? FLT_EPSILON : scale.y,
(scale.z == 0.0f) ? FLT_EPSILON : scale.z,
};
+ const float4x4 scale_limited_transform = float4x4::from_loc_eul_scale(
+ translation, rotation, limited_scale);
- const Main *bmain = DEG_get_bmain(params.depsgraph());
- BKE_volume_load(volume, bmain);
-
- const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, limited_scale);
+ const Main *bmain = DEG_get_bmain(&depsgraph);
+ BKE_volume_load(&volume, bmain);
openvdb::Mat4s vdb_matrix;
- memcpy(vdb_matrix.asPointer(), matrix, sizeof(float[4][4]));
+ memcpy(vdb_matrix.asPointer(), &scale_limited_transform, sizeof(float[4][4]));
openvdb::Mat4d vdb_matrix_d{vdb_matrix};
- const int num_grids = BKE_volume_num_grids(volume);
+ const int num_grids = BKE_volume_num_grids(&volume);
for (const int i : IndexRange(num_grids)) {
- VolumeGrid *volume_grid = BKE_volume_grid_get_for_write(volume, i);
+ VolumeGrid *volume_grid = BKE_volume_grid_get_for_write(&volume, i);
- openvdb::GridBase::Ptr grid = BKE_volume_grid_openvdb_for_write(volume, volume_grid, false);
+ openvdb::GridBase::Ptr grid = BKE_volume_grid_openvdb_for_write(&volume, volume_grid, false);
openvdb::math::Transform &grid_transform = grid->transform();
grid_transform.postMult(vdb_matrix_d);
}
#else
- UNUSED_VARS(volume, translation, rotation, scale, params);
+ UNUSED_VARS(volume, transform, depsgraph);
#endif
}
-static void transform_curve(CurveEval &curve,
- const float3 translation,
- const float3 rotation,
- const float3 scale)
+static void translate_volume(Volume &volume, const float3 translation, const Depsgraph &depsgraph)
{
- if (use_translate(rotation, scale)) {
- curve.translate(translation);
+ transform_volume(volume, float4x4::from_location(translation), depsgraph);
+}
+
+static void translate_geometry_set(GeometrySet &geometry,
+ const float3 translation,
+ const Depsgraph &depsgraph)
+{
+ if (CurveEval *curve = geometry.get_curve_for_write()) {
+ curve->translate(translation);
}
- else {
- const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
- curve.transform(matrix);
+ if (Mesh *mesh = geometry.get_mesh_for_write()) {
+ translate_mesh(*mesh, translation);
+ }
+ if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
+ translate_pointcloud(*pointcloud, translation);
+ }
+ if (Volume *volume = geometry.get_volume_for_write()) {
+ translate_volume(*volume, translation, depsgraph);
+ }
+ if (geometry.has_instances()) {
+ translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation);
+ }
+}
+
+void transform_geometry_set(GeometrySet &geometry,
+ const float4x4 &transform,
+ const Depsgraph &depsgraph)
+{
+ if (CurveEval *curve = geometry.get_curve_for_write()) {
+ curve->transform(transform);
+ }
+ if (Mesh *mesh = geometry.get_mesh_for_write()) {
+ transform_mesh(*mesh, transform);
+ }
+ if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
+ transform_pointcloud(*pointcloud, transform);
+ }
+ if (Volume *volume = geometry.get_volume_for_write()) {
+ transform_volume(*volume, transform, depsgraph);
+ }
+ if (geometry.has_instances()) {
+ transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform);
}
}
-static void geo_node_transform_exec(GeoNodeExecParams params)
+void transform_mesh(Mesh &mesh,
+ const float3 translation,
+ const float3 rotation,
+ const float3 scale)
+{
+ const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
+ transform_mesh(mesh, matrix);
+}
+
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_transform_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER);
+ b.add_input<decl::Vector>(N_("Scale")).default_value({1, 1, 1}).subtype(PROP_XYZ);
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const float3 translation = params.extract_input<float3>("Translation");
const float3 rotation = params.extract_input<float3>("Rotation");
const float3 scale = params.extract_input<float3>("Scale");
- if (geometry_set.has_mesh()) {
- Mesh *mesh = geometry_set.get_mesh_for_write();
- transform_mesh(mesh, translation, rotation, scale);
- }
- if (geometry_set.has_pointcloud()) {
- PointCloud *pointcloud = geometry_set.get_pointcloud_for_write();
- transform_pointcloud(pointcloud, translation, rotation, scale);
- }
- if (geometry_set.has_instances()) {
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- transform_instances(instances, translation, rotation, scale);
- }
- if (geometry_set.has_volume()) {
- Volume *volume = geometry_set.get_volume_for_write();
- transform_volume(volume, translation, rotation, scale, params);
+ /* Use only translation if rotation and scale don't apply. */
+ if (use_translate(rotation, scale)) {
+ translate_geometry_set(geometry_set, translation, *params.depsgraph());
}
- if (geometry_set.has_curve()) {
- CurveEval *curve = geometry_set.get_curve_for_write();
- transform_curve(*curve, translation, rotation, scale);
+ else {
+ transform_geometry_set(geometry_set,
+ float4x4::from_loc_eul_scale(translation, rotation, scale),
+ *params.depsgraph());
}
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_transform_cc
void register_node_type_geo_transform()
{
+ namespace file_ns = blender::nodes::node_geo_transform_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_transform_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_transform_exec;
+ geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
new file mode 100644
index 00000000000..91c503ff047
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
@@ -0,0 +1,84 @@
+/*
+ * 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 "BLI_task.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_translate_instances_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Instances")).only_instances();
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION).supports_field();
+ b.add_input<decl::Bool>(N_("Local Space")).default_value(true).supports_field();
+ b.add_output<decl::Geometry>(N_("Instances"));
+}
+
+static void translate_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
+{
+ GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
+
+ fn::FieldEvaluator evaluator{field_context, instances_component.instances_amount()};
+ evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
+ evaluator.add(params.extract_input<Field<float3>>("Translation"));
+ evaluator.add(params.extract_input<Field<bool>>("Local Space"));
+ evaluator.evaluate();
+
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &translations = evaluator.get_evaluated<float3>(0);
+ const VArray<bool> &local_spaces = evaluator.get_evaluated<bool>(1);
+
+ MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
+
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for (const int i_selection : range) {
+ const int i = selection[i_selection];
+ if (local_spaces[i]) {
+ instance_transforms[i] *= float4x4::from_location(translations[i]);
+ }
+ else {
+ add_v3_v3(instance_transforms[i].values[3], translations[i]);
+ }
+ }
+ });
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
+ if (geometry_set.has_instances()) {
+ InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ translate_instances(params, instances);
+ }
+ params.set_output("Instances", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_translate_instances_cc
+
+void register_node_type_geo_translate_instances()
+{
+ namespace file_ns = blender::nodes::node_geo_translate_instances_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_TRANSLATE_INSTANCES, "Translate Instances", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index 7ef0913622c..e78c4d7bc35 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -14,29 +14,30 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "DNA_mesh_types.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
#include "node_geometry_util.hh"
-extern "C" {
-Mesh *triangulate_mesh(Mesh *mesh,
- const int quad_method,
- const int ngon_method,
- const int min_vertices,
- const int flag);
-}
+namespace blender::nodes::node_geo_triangulate_cc {
-namespace blender::nodes {
-
-static void geo_node_triangulate_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Int>("Minimum Vertices").default_value(4).min(4).max(10000);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
+ b.add_input<decl::Int>(N_("Minimum Vertices")).default_value(4).min(4).max(10000);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_triangulate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "quad_method", 0, "", ICON_NONE);
uiItemR(layout, ptr, "ngon_method", 0, "", ICON_NONE);
@@ -48,9 +49,35 @@ static void geo_triangulate_init(bNodeTree *UNUSED(ntree), bNode *node)
node->custom2 = GEO_NODE_TRIANGULATE_NGON_BEAUTY;
}
-static void geo_node_triangulate_exec(GeoNodeExecParams params)
+static Mesh *triangulate_mesh_selection(const Mesh &mesh,
+ const int quad_method,
+ const int ngon_method,
+ const IndexMask selection,
+ const int min_vertices)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ CustomData_MeshMasks cd_mask_extra = {
+ CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, 0, CD_MASK_ORIGINDEX};
+ BMeshCreateParams create_params{0};
+ BMeshFromMeshParams from_mesh_params{true, 1, 1, 1, cd_mask_extra};
+ BMesh *bm = BKE_mesh_to_bmesh_ex(&mesh, &create_params, &from_mesh_params);
+
+ /* Tag faces to be triangulated from the selection mask. */
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+ for (int i_face : selection) {
+ BM_elem_flag_set(BM_face_at_index(bm, i_face), BM_ELEM_TAG, true);
+ }
+
+ BM_mesh_triangulate(bm, quad_method, ngon_method, min_vertices, true, NULL, NULL, NULL);
+ Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cd_mask_extra, &mesh);
+ BM_mesh_free(bm);
+ BKE_mesh_normals_tag_dirty(result);
+ return result;
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
const int min_vertices = std::max(params.extract_input<int>("Minimum Vertices"), 4);
GeometryNodeTriangulateQuads quad_method = static_cast<GeometryNodeTriangulateQuads>(
@@ -59,26 +86,38 @@ static void geo_node_triangulate_exec(GeoNodeExecParams params)
params.node().custom2);
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- /* #triangulate_mesh might modify the input mesh currently. */
- Mesh *mesh_in = geometry_set.get_mesh_for_write();
- if (mesh_in != nullptr) {
- Mesh *mesh_out = triangulate_mesh(mesh_in, quad_method, ngon_method, min_vertices, 0);
- geometry_set.replace_mesh(mesh_out);
+ if (!geometry_set.has_mesh()) {
+ return;
}
+ GeometryComponent &component = geometry_set.get_component_for_write<MeshComponent>();
+ const Mesh &mesh_in = *geometry_set.get_mesh_for_read();
+
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ GeometryComponentFieldContext context{component, ATTR_DOMAIN_FACE};
+ FieldEvaluator evaluator{context, domain_size};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+
+ Mesh *mesh_out = triangulate_mesh_selection(
+ mesh_in, quad_method, ngon_method, selection, min_vertices);
+ geometry_set.replace_mesh(mesh_out);
});
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_triangulate_cc
void register_node_type_geo_triangulate()
{
+ namespace file_ns = blender::nodes::node_geo_triangulate_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_triangulate_declare;
- node_type_init(&ntype, blender::nodes::geo_triangulate_init);
- ntype.geometry_node_execute = blender::nodes::geo_node_triangulate_exec;
- ntype.draw_buttons = blender::nodes::geo_node_triangulate_layout;
+ geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::geo_triangulate_init);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
index 3331962341f..c717d90f7cc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
@@ -14,20 +14,139 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BKE_context.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "ED_node.h"
+#include "ED_spreadsheet.h"
+
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
-static void geo_node_viewer_declare(NodeDeclarationBuilder &b)
+namespace blender::nodes::node_geo_viewer_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryViewer)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Float>(N_("Value")).supports_field().hide_value();
+ b.add_input<decl::Vector>(N_("Value"), "Value_001").supports_field().hide_value();
+ b.add_input<decl::Color>(N_("Value"), "Value_002").supports_field().hide_value();
+ b.add_input<decl::Int>(N_("Value"), "Value_003").supports_field().hide_value();
+ b.add_input<decl::Bool>(N_("Value"), "Value_004").supports_field().hide_value();
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryViewer *data = MEM_cnew<NodeGeometryViewer>(__func__);
+ data->data_type = CD_PROP_FLOAT;
+
+ node->storage = data;
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+}
+
+static eNodeSocketDatatype custom_data_type_to_socket_type(const CustomDataType type)
+{
+ switch (type) {
+ case CD_PROP_FLOAT:
+ return SOCK_FLOAT;
+ case CD_PROP_INT32:
+ return SOCK_INT;
+ case CD_PROP_FLOAT3:
+ return SOCK_VECTOR;
+ case CD_PROP_BOOL:
+ return SOCK_BOOLEAN;
+ case CD_PROP_COLOR:
+ return SOCK_RGBA;
+ default:
+ BLI_assert_unreachable();
+ return SOCK_FLOAT;
+ }
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeGeometryViewer &storage = node_storage(*node);
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eNodeSocketDatatype socket_type = custom_data_type_to_socket_type(data_type);
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ if (socket->type == SOCK_GEOMETRY) {
+ continue;
+ }
+ nodeSetSocketAvailability(ntree, socket, socket->type == socket_type);
+ }
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
{
- b.add_input<decl::Geometry>("Geometry");
+ auto set_active_fn = [](LinkSearchOpParams &params, bNode &viewer_node) {
+ /* Set this new viewer node active in spreadsheet editors. */
+ SpaceNode *snode = CTX_wm_space_node(&params.C);
+ Main *bmain = CTX_data_main(&params.C);
+ ED_node_set_active(bmain, snode, &params.node_tree, &viewer_node, nullptr);
+ ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, &viewer_node);
+ };
+
+ const std::optional<CustomDataType> type = node_socket_to_custom_data_type(
+ params.other_socket());
+ if (params.in_out() == SOCK_OUT) {
+ /* The viewer node only has inputs. */
+ return;
+ }
+ if (params.other_socket().type == SOCK_GEOMETRY) {
+ params.add_item(IFACE_("Geometry"), [set_active_fn](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeViewer");
+ params.connect_available_socket(node, "Geometry");
+ set_active_fn(params, node);
+ });
+ }
+ if (type &&
+ ELEM(type, CD_PROP_FLOAT, CD_PROP_BOOL, CD_PROP_INT32, CD_PROP_FLOAT3, CD_PROP_COLOR)) {
+ params.add_item(IFACE_("Value"), [type, set_active_fn](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeViewer");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Value");
+
+ /* If the source node has a geometry socket, connect it to the new viewer node as well. */
+ LISTBASE_FOREACH (bNodeSocket *, socket, &params.node.outputs) {
+ if (socket->type == SOCK_GEOMETRY && !(socket->flag & (SOCK_UNAVAIL | SOCK_HIDDEN))) {
+ nodeAddLink(&params.node_tree,
+ &params.node,
+ socket,
+ &node,
+ static_cast<bNodeSocket *>(node.inputs.first));
+ }
+ }
+
+ set_active_fn(params, node);
+ });
+ }
}
-} // namespace blender::nodes
+
+} // namespace blender::nodes::node_geo_viewer_cc
void register_node_type_geo_viewer()
{
+ namespace file_ns = blender::nodes::node_geo_viewer_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, 0);
- ntype.declare = blender::nodes::geo_node_viewer_declare;
+ geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT);
+ node_type_storage(
+ &ntype, "NodeGeometryViewer", node_free_standard_storage, node_copy_standard_storage);
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons_ex = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
index 229a35e0007..c7dc73f8a91 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
@@ -35,138 +35,193 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_volume_to_mesh_cc {
-static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryVolumeToMesh)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Density");
- b.add_input<decl::Float>("Voxel Size").default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Voxel Amount").default_value(64.0f).min(0.0f);
- b.add_input<decl::Float>("Threshold").default_value(0.1f).min(0.0f);
- b.add_input<decl::Float>("Adaptivity").min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_input<decl::Geometry>(N_("Volume")).supported_type(GEO_COMPONENT_TYPE_VOLUME);
+ b.add_input<decl::Float>(N_("Voxel Size"))
+ .default_value(0.3f)
+ .min(0.01f)
+ .subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) {
+ node_storage(node).resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE;
+ });
+ b.add_input<decl::Float>(N_("Voxel Amount"))
+ .default_value(64.0f)
+ .min(0.0f)
+ .make_available([](bNode &node) {
+ node_storage(node).resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT;
+ });
+ b.add_input<decl::Float>(N_("Threshold")).default_value(0.1f).min(0.0f);
+ b.add_input<decl::Float>(N_("Adaptivity")).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_volume_to_mesh_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
}
-static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
- sizeof(NodeGeometryVolumeToMesh), __func__);
+ NodeGeometryVolumeToMesh *data = MEM_cnew<NodeGeometryVolumeToMesh>(__func__);
data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
-
- bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Density");
- bNodeSocketValueString *grid_socket_value = (bNodeSocketValueString *)grid_socket->default_value;
- STRNCPY(grid_socket_value->value, "density");
-
node->storage = data;
}
-static void geo_node_volume_to_mesh_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage;
+ const NodeGeometryVolumeToMesh &storage = node_storage(*node);
bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
- nodeSetSocketAvailability(voxel_amount_socket,
- data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT);
- nodeSetSocketAvailability(voxel_size_socket,
- data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE);
+ nodeSetSocketAvailability(ntree,
+ voxel_amount_socket,
+ storage.resolution_mode ==
+ VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT);
+ nodeSetSocketAvailability(ntree,
+ voxel_size_socket,
+ storage.resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE);
}
#ifdef WITH_OPENVDB
-static void create_mesh_from_volume(GeometrySet &geometry_set_in,
- GeometrySet &geometry_set_out,
- GeoNodeExecParams &params)
+static bke::VolumeToMeshResolution get_resolution_param(const GeoNodeExecParams &params)
{
- if (!geometry_set_in.has<VolumeComponent>()) {
- return;
- }
-
- const NodeGeometryVolumeToMesh &storage =
- *(const NodeGeometryVolumeToMesh *)params.node().storage;
+ const NodeGeometryVolumeToMesh &storage = node_storage(params.node());
bke::VolumeToMeshResolution resolution;
resolution.mode = (VolumeToMeshResolutionMode)storage.resolution_mode;
if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT) {
- resolution.settings.voxel_amount = params.get_input<float>("Voxel Amount");
- if (resolution.settings.voxel_amount <= 0.0f) {
- return;
- }
+ resolution.settings.voxel_amount = std::max(params.get_input<float>("Voxel Amount"), 0.0f);
}
else if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE) {
- resolution.settings.voxel_size = params.get_input<float>("Voxel Size");
- if (resolution.settings.voxel_size <= 0.0f) {
- return;
- }
+ resolution.settings.voxel_size = std::max(params.get_input<float>("Voxel Size"), 0.0f);
+ }
+
+ return resolution;
+}
+
+static Mesh *create_mesh_from_volume_grids(Span<openvdb::GridBase::ConstPtr> grids,
+ const float threshold,
+ const float adaptivity,
+ const bke::VolumeToMeshResolution &resolution)
+{
+ Array<bke::OpenVDBMeshData> mesh_data(grids.size());
+ for (const int i : grids.index_range()) {
+ mesh_data[i] = bke::volume_to_mesh_data(*grids[i], resolution, threshold, adaptivity);
+ }
+
+ int vert_offset = 0;
+ int poly_offset = 0;
+ int loop_offset = 0;
+ Array<int> vert_offsets(mesh_data.size());
+ Array<int> poly_offsets(mesh_data.size());
+ Array<int> loop_offsets(mesh_data.size());
+ for (const int i : grids.index_range()) {
+ const bke::OpenVDBMeshData &data = mesh_data[i];
+ vert_offsets[i] = vert_offset;
+ poly_offsets[i] = poly_offset;
+ loop_offsets[i] = loop_offset;
+ vert_offset += data.verts.size();
+ poly_offset += (data.tris.size() + data.quads.size());
+ loop_offset += (3 * data.tris.size() + 4 * data.quads.size());
}
- const VolumeComponent *component = geometry_set_in.get_component_for_read<VolumeComponent>();
- const Volume *volume = component->get_for_read();
+ Mesh *mesh = BKE_mesh_new_nomain(vert_offset, 0, 0, loop_offset, poly_offset);
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
+ MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
+ MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
+ MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
+
+ for (const int i : grids.index_range()) {
+ const bke::OpenVDBMeshData &data = mesh_data[i];
+ bke::fill_mesh_from_openvdb_data(data.verts,
+ data.tris,
+ data.quads,
+ vert_offsets[i],
+ poly_offsets[i],
+ loop_offsets[i],
+ verts,
+ polys,
+ loops);
+ }
+
+ BKE_mesh_calc_edges(mesh, false, false);
+ BKE_mesh_normals_tag_dirty(mesh);
+
+ return mesh;
+}
+
+static Mesh *create_mesh_from_volume(GeometrySet &geometry_set, GeoNodeExecParams &params)
+{
+ const Volume *volume = geometry_set.get_volume_for_read();
if (volume == nullptr) {
- return;
+ return nullptr;
}
+ const bke::VolumeToMeshResolution resolution = get_resolution_param(params);
const Main *bmain = DEG_get_bmain(params.depsgraph());
BKE_volume_load(volume, bmain);
- const std::string grid_name = params.get_input<std::string>("Density");
- const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, grid_name.c_str());
- if (volume_grid == nullptr) {
- return;
+ Vector<openvdb::GridBase::ConstPtr> grids;
+ for (const int i : IndexRange(BKE_volume_num_grids(volume))) {
+ const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, i);
+ openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
+ grids.append(std::move(grid));
}
- float threshold = params.get_input<float>("Threshold");
- float adaptivity = params.get_input<float>("Adaptivity");
-
- const openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
- Mesh *mesh = bke::volume_to_mesh(*grid, resolution, threshold, adaptivity);
- if (mesh == nullptr) {
- return;
+ if (grids.is_empty()) {
+ return nullptr;
}
- BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MeshComponent &dst_component = geometry_set_out.get_component_for_write<MeshComponent>();
- dst_component.replace(mesh);
+
+ return create_mesh_from_volume_grids(grids,
+ params.get_input<float>("Threshold"),
+ params.get_input<float>("Adaptivity"),
+ resolution);
}
#endif /* WITH_OPENVDB */
-static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
- GeometrySet geometry_set_out;
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
#ifdef WITH_OPENVDB
- create_mesh_from_volume(geometry_set_in, geometry_set_out, params);
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ Mesh *mesh = create_mesh_from_volume(geometry_set, params);
+ geometry_set.replace_mesh(mesh);
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
+ });
#else
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenVDB"));
#endif
- params.set_output("Geometry", geometry_set_out);
+ params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_volume_to_mesh_cc
void register_node_type_geo_volume_to_mesh()
{
+ namespace file_ns = blender::nodes::node_geo_volume_to_mesh_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_volume_to_mesh_declare;
+ geo_node_type_base(&ntype, GEO_NODE_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
node_type_storage(
&ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage);
- node_type_size(&ntype, 200, 120, 700);
- node_type_init(&ntype, blender::nodes::geo_node_volume_to_mesh_init);
- node_type_update(&ntype, blender::nodes::geo_node_volume_to_mesh_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_volume_to_mesh_exec;
- ntype.draw_buttons = blender::nodes::geo_node_volume_to_mesh_layout;
+ node_type_size(&ntype, 170, 120, 700);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc
index f7279cf7524..449c6598307 100644
--- a/source/blender/nodes/intern/derived_node_tree.cc
+++ b/source/blender/nodes/intern/derived_node_tree.cc
@@ -20,10 +20,6 @@
namespace blender::nodes {
-/* Construct a new derived node tree for a given root node tree. The generated derived node tree
- * does not own the used node tree refs (so that those can be used by others as well). The caller
- * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the
- * derived node tree. */
DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs)
{
/* Construct all possible contexts immediately. This is significantly cheaper than inlining all
@@ -73,9 +69,6 @@ void DerivedNodeTree::destruct_context_recursively(DTreeContext *context)
context->~DTreeContext();
}
-/**
- * \return True when there is a link cycle. Unavailable sockets are ignored.
- */
bool DerivedNodeTree::has_link_cycles() const
{
for (const NodeTreeRef *tree_ref : used_node_tree_refs_) {
@@ -96,7 +89,6 @@ bool DerivedNodeTree::has_undefined_nodes_or_sockets() const
return false;
}
-/* Calls the given callback on all nodes in the (possibly nested) derived node tree. */
void DerivedNodeTree::foreach_node(FunctionRef<void(DNode)> callback) const
{
this->foreach_node_in_context_recursive(*root_context_, callback);
@@ -167,7 +159,11 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const
BLI_assert(socket_ref_->node().is_group_node());
const DTreeContext *child_context = context_->child_context(socket_ref_->node());
- BLI_assert(child_context != nullptr);
+ if (child_context == nullptr) {
+ /* Can happen when the group node references a non-existent group (e.g. when the group is
+ * linked but the original file is not found). */
+ return {};
+ }
const NodeTreeRef &child_tree = child_context->tree();
Span<const NodeRef *> group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput");
@@ -180,9 +176,6 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const
return {};
}
-/* Call `origin_fn` for every "real" origin socket. "Real" means that reroutes, muted nodes
- * and node groups are handled by this function. Origin sockets are ones where a node gets its
- * inputs from. */
void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const
{
BLI_assert(*this);
@@ -229,47 +222,91 @@ void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) c
}
}
-/* Calls `target_fn` for every "real" target socket. "Real" means that reroutes, muted nodes
- * and node groups are handled by this function. Target sockets are on the nodes that use the value
- * from this socket. The `skipped_fn` function is called for sockets that have been skipped during
- * the search for target sockets (e.g. reroutes). */
-void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> target_fn,
- FunctionRef<void(DSocket)> skipped_fn) const
+void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn) const
{
- for (const SocketRef *skipped_socket : socket_ref_->logically_linked_skipped_sockets()) {
- skipped_fn.call_safe({context_, skipped_socket});
- }
- for (const InputSocketRef *linked_socket : socket_ref_->as_output().logically_linked_sockets()) {
- const NodeRef &linked_node = linked_socket->node();
- DInputSocket linked_dsocket{context_, linked_socket};
+ TargetSocketPathInfo path_info;
+ this->foreach_target_socket(target_fn, path_info);
+}
- if (linked_node.is_group_output_node()) {
+void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn,
+ TargetSocketPathInfo &path_info) const
+{
+ for (const LinkRef *link : socket_ref_->as_output().directly_linked_links()) {
+ if (link->is_muted()) {
+ continue;
+ }
+ const DInputSocket &linked_socket{context_, &link->to()};
+ if (!linked_socket->is_available()) {
+ continue;
+ }
+ const DNode linked_node = linked_socket.node();
+ if (linked_node->is_reroute_node()) {
+ const DInputSocket reroute_input = linked_socket;
+ const DOutputSocket reroute_output = linked_node.output(0);
+ path_info.sockets.append(reroute_input);
+ path_info.sockets.append(reroute_output);
+ reroute_output.foreach_target_socket(target_fn, path_info);
+ path_info.sockets.pop_last();
+ path_info.sockets.pop_last();
+ }
+ else if (linked_node->is_muted()) {
+ for (const InternalLinkRef *internal_link : linked_node->internal_links()) {
+ if (&internal_link->from() != linked_socket.socket_ref()) {
+ continue;
+ }
+ /* The internal link only forwards the first incoming link. */
+ if (linked_socket->is_multi_input_socket()) {
+ if (linked_socket->directly_linked_links()[0] != link) {
+ continue;
+ }
+ }
+ const DInputSocket mute_input = linked_socket;
+ const DOutputSocket mute_output{context_, &internal_link->to()};
+ path_info.sockets.append(mute_input);
+ path_info.sockets.append(mute_output);
+ mute_output.foreach_target_socket(target_fn, path_info);
+ path_info.sockets.pop_last();
+ path_info.sockets.pop_last();
+ }
+ }
+ else if (linked_node->is_group_output_node()) {
+ if (linked_node.node_ref() != context_->tree().group_output_node()) {
+ continue;
+ }
if (context_->is_root()) {
/* This is a group output in the root node group. */
- target_fn(linked_dsocket);
+ path_info.sockets.append(linked_socket);
+ target_fn(linked_socket, path_info);
+ path_info.sockets.pop_last();
}
else {
/* Follow the links going out of the group node in the parent node group. */
- DOutputSocket socket_in_parent_group =
- linked_dsocket.get_corresponding_group_node_output();
- skipped_fn.call_safe(linked_dsocket);
- skipped_fn.call_safe(socket_in_parent_group);
- socket_in_parent_group.foreach_target_socket(target_fn, skipped_fn);
+ const DOutputSocket socket_in_parent_group =
+ linked_socket.get_corresponding_group_node_output();
+ path_info.sockets.append(linked_socket);
+ path_info.sockets.append(socket_in_parent_group);
+ socket_in_parent_group.foreach_target_socket(target_fn, path_info);
+ path_info.sockets.pop_last();
+ path_info.sockets.pop_last();
}
}
- else if (linked_node.is_group_node()) {
+ else if (linked_node->is_group_node()) {
/* Follow the links within the nested node group. */
- Vector<DOutputSocket> sockets_in_group =
- linked_dsocket.get_corresponding_group_input_sockets();
- skipped_fn.call_safe(linked_dsocket);
- for (DOutputSocket socket_in_group : sockets_in_group) {
- skipped_fn.call_safe(socket_in_group);
- socket_in_group.foreach_target_socket(target_fn, skipped_fn);
+ path_info.sockets.append(linked_socket);
+ const Vector<DOutputSocket> sockets_in_group =
+ linked_socket.get_corresponding_group_input_sockets();
+ for (const DOutputSocket &socket_in_group : sockets_in_group) {
+ path_info.sockets.append(socket_in_group);
+ socket_in_group.foreach_target_socket(target_fn, path_info);
+ path_info.sockets.pop_last();
}
+ path_info.sockets.pop_last();
}
else {
/* The normal case: just use the linked input socket as target. */
- target_fn(linked_dsocket);
+ path_info.sockets.append(linked_socket);
+ target_fn(linked_socket, path_info);
+ path_info.sockets.pop_last();
}
}
}
@@ -294,7 +331,6 @@ static dot::Cluster *get_dot_cluster_for_context(
});
}
-/* Generates a graph in dot format. The generated graph has all node groups inlined. */
std::string DerivedNodeTree::to_dot() const
{
dot::DirectedGraph digraph;
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
index fa9bf09d8d9..e33f6cf345d 100644
--- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -21,11 +21,23 @@
#include "DNA_modifier_types.h"
#include "DNA_space_types.h"
+#include "FN_field_cpp_type.hh"
+
+#include "BLT_translation.h"
+
+#include <chrono>
+
namespace blender::nodes::geometry_nodes_eval_log {
using fn::CPPType;
+using fn::FieldCPPType;
+using fn::FieldInput;
+using fn::GField;
+using fn::ValueOrFieldCPPType;
ModifierLog::ModifierLog(GeoLogger &logger)
+ : input_geometry_log_(std::move(logger.input_geometry_log_)),
+ output_geometry_log_(std::move(logger.output_geometry_log_))
{
root_tree_logs_ = allocator_.construct<TreeLog>();
@@ -54,6 +66,17 @@ ModifierLog::ModifierLog(GeoLogger &logger)
node_with_warning.node);
node_log.warnings_.append(node_with_warning.warning);
}
+
+ for (NodeWithExecutionTime &node_with_exec_time : local_logger.node_exec_times_) {
+ NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context,
+ node_with_exec_time.node);
+ node_log.exec_time_ = node_with_exec_time.exec_time;
+ }
+
+ for (NodeWithDebugMessage &debug_message : local_logger.node_debug_messages_) {
+ NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, debug_message.node);
+ node_log.debug_messages_.append(debug_message.message);
+ }
}
}
@@ -106,6 +129,15 @@ void ModifierLog::foreach_node_log(FunctionRef<void(const NodeLog &)> fn) const
}
}
+const GeometryValueLog *ModifierLog::input_geometry_log() const
+{
+ return input_geometry_log_.get();
+}
+const GeometryValueLog *ModifierLog::output_geometry_log() const
+{
+ return output_geometry_log_.get();
+}
+
const NodeLog *TreeLog::lookup_node_log(StringRef node_name) const
{
const destruct_ptr<NodeLog> *node_log = node_logs_.lookup_ptr_as(node_name);
@@ -157,6 +189,36 @@ const SocketLog *NodeLog::lookup_socket_log(const bNode &node, const bNodeSocket
return this->lookup_socket_log((eNodeSocketInOut)socket.in_out, index);
}
+GFieldValueLog::GFieldValueLog(fn::GField field, bool log_full_field) : type_(field.cpp_type())
+{
+ const std::shared_ptr<const fn::FieldInputs> &field_input_nodes = field.node().field_inputs();
+
+ /* Put the deduplicated field inputs into a vector so that they can be sorted below. */
+ Vector<std::reference_wrapper<const FieldInput>> field_inputs;
+ if (field_input_nodes) {
+ field_inputs.extend(field_input_nodes->deduplicated_nodes.begin(),
+ field_input_nodes->deduplicated_nodes.end());
+ }
+
+ std::sort(
+ field_inputs.begin(), field_inputs.end(), [](const FieldInput &a, const FieldInput &b) {
+ const int index_a = (int)a.category();
+ const int index_b = (int)b.category();
+ if (index_a == index_b) {
+ return a.socket_inspection_name().size() < b.socket_inspection_name().size();
+ }
+ return index_a < index_b;
+ });
+
+ for (const FieldInput &field_input : field_inputs) {
+ input_tooltips_.append(field_input.socket_inspection_name());
+ }
+
+ if (log_full_field) {
+ field_ = std::move(field);
+ }
+}
+
GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry)
{
static std::array all_component_types = {GEO_COMPONENT_TYPE_CURVE,
@@ -164,13 +226,19 @@ GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_ful
GEO_COMPONENT_TYPE_MESH,
GEO_COMPONENT_TYPE_POINT_CLOUD,
GEO_COMPONENT_TYPE_VOLUME};
+
+ /* Keep track handled attribute names to make sure that we do not return the same name twice.
+ * Currently #GeometrySet::attribute_foreach does not do that. Note that this will merge
+ * attributes with the same name but different domains or data types on separate components. */
+ Set<StringRef> names;
+
geometry_set.attribute_foreach(
all_component_types,
true,
[&](const bke::AttributeIDRef &attribute_id,
const AttributeMetaData &meta_data,
const GeometryComponent &UNUSED(component)) {
- if (attribute_id.is_named()) {
+ if (attribute_id.is_named() && names.add(attribute_id.name())) {
this->attributes_.append({attribute_id.name(), meta_data.domain, meta_data.data_type});
}
});
@@ -354,7 +422,7 @@ void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value
if (type.is<GeometrySet>()) {
bool log_full_geometry = false;
for (const DSocket &socket : sockets) {
- if (main_logger_->log_full_geometry_sockets_.contains(socket)) {
+ if (main_logger_->log_full_sockets_.contains(socket)) {
log_full_geometry = true;
break;
}
@@ -365,6 +433,39 @@ void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value
geometry_set, log_full_geometry);
values_.append({copied_sockets, std::move(value_log)});
}
+ else if (const ValueOrFieldCPPType *value_or_field_type =
+ dynamic_cast<const ValueOrFieldCPPType *>(&type)) {
+ const void *value_or_field = value.get();
+ if (value_or_field_type->is_field(value_or_field)) {
+ GField field = *value_or_field_type->get_field_ptr(value_or_field);
+ bool log_full_field = false;
+ if (!field.node().depends_on_input()) {
+ /* Always log constant fields so that their value can be shown in socket inspection.
+ * In the future we can also evaluate the field here and only store the value. */
+ log_full_field = true;
+ }
+ if (!log_full_field) {
+ for (const DSocket &socket : sockets) {
+ if (main_logger_->log_full_sockets_.contains(socket)) {
+ log_full_field = true;
+ break;
+ }
+ }
+ }
+ destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>(
+ std::move(field), log_full_field);
+ values_.append({copied_sockets, std::move(value_log)});
+ }
+ else {
+ const CPPType &base_type = value_or_field_type->base_type();
+ const void *value = value_or_field_type->get_value_ptr(value_or_field);
+ void *buffer = allocator_->allocate(base_type.size(), base_type.alignment());
+ base_type.copy_construct(value, buffer);
+ destruct_ptr<GenericValueLog> value_log = allocator_->construct<GenericValueLog>(
+ GMutablePointer{base_type, buffer});
+ values_.append({copied_sockets, std::move(value_log)});
+ }
+ }
else {
void *buffer = allocator_->allocate(type.size(), type.alignment());
type.copy_construct(value.get(), buffer);
@@ -385,4 +486,14 @@ void LocalGeoLogger::log_node_warning(DNode node, NodeWarningType type, std::str
node_warnings_.append({node, {type, std::move(message)}});
}
+void LocalGeoLogger::log_execution_time(DNode node, std::chrono::microseconds exec_time)
+{
+ node_exec_times_.append({node, exec_time});
+}
+
+void LocalGeoLogger::log_debug_message(DNode node, std::string message)
+{
+ node_debug_messages_.append({node, std::move(message)});
+}
+
} // namespace blender::nodes::geometry_nodes_eval_log
diff --git a/source/blender/nodes/intern/math_functions.cc b/source/blender/nodes/intern/math_functions.cc
index aa23777b664..00f4f2a3405 100644
--- a/source/blender/nodes/intern/math_functions.cc
+++ b/source/blender/nodes/intern/math_functions.cc
@@ -127,17 +127,17 @@ const FloatMathOperationInfo *get_float_compare_operation_info(const int operati
((void)0)
switch (operation) {
- case NODE_FLOAT_COMPARE_LESS_THAN:
+ case NODE_COMPARE_LESS_THAN:
RETURN_OPERATION_INFO("Less Than", "math_less_than");
- case NODE_FLOAT_COMPARE_LESS_EQUAL:
+ case NODE_COMPARE_LESS_EQUAL:
RETURN_OPERATION_INFO("Less Than or Equal", "math_less_equal");
- case NODE_FLOAT_COMPARE_GREATER_THAN:
+ case NODE_COMPARE_GREATER_THAN:
RETURN_OPERATION_INFO("Greater Than", "math_greater_than");
- case NODE_FLOAT_COMPARE_GREATER_EQUAL:
+ case NODE_COMPARE_GREATER_EQUAL:
RETURN_OPERATION_INFO("Greater Than or Equal", "math_greater_equal");
- case NODE_FLOAT_COMPARE_EQUAL:
+ case NODE_COMPARE_EQUAL:
RETURN_OPERATION_INFO("Equal", "math_equal");
- case NODE_FLOAT_COMPARE_NOT_EQUAL:
+ case NODE_COMPARE_NOT_EQUAL:
RETURN_OPERATION_INFO("Not Equal", "math_not_equal");
}
diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.cc
index 7625cb9e3f6..21dec8489b4 100644
--- a/source/blender/nodes/intern/node_common.c
+++ b/source/blender/nodes/intern/node_common.cc
@@ -21,18 +21,24 @@
* \ingroup nodes
*/
-#include <stddef.h>
-#include <string.h>
+#include <cstddef>
+#include <cstring>
#include "DNA_node_types.h"
#include "BLI_listbase.h"
+#include "BLI_map.hh"
+#include "BLI_multi_value_map.hh"
+#include "BLI_set.hh"
+#include "BLI_stack.hh"
#include "BLI_string.h"
+#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "RNA_types.h"
@@ -42,39 +48,37 @@
#include "node_common.h"
#include "node_util.h"
-enum {
- REFINE_FORWARD = 1 << 0,
- REFINE_BACKWARD = 1 << 1,
-};
+using blender::Map;
+using blender::MultiValueMap;
+using blender::Set;
+using blender::Stack;
+using blender::StringRef;
/* -------------------------------------------------------------------- */
/** \name Node Group
* \{ */
-bNodeSocket *node_group_find_input_socket(bNode *groupnode, const char *identifier)
+static bNodeSocket *find_matching_socket(ListBase &sockets, StringRef identifier)
{
- bNodeSocket *sock;
- for (sock = groupnode->inputs.first; sock; sock = sock->next) {
- if (STREQ(sock->identifier, identifier)) {
- return sock;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &sockets) {
+ if (socket->identifier == identifier) {
+ return socket;
}
}
- return NULL;
+ return nullptr;
+}
+
+bNodeSocket *node_group_find_input_socket(bNode *groupnode, const char *identifier)
+{
+ return find_matching_socket(groupnode->inputs, identifier);
}
bNodeSocket *node_group_find_output_socket(bNode *groupnode, const char *identifier)
{
- bNodeSocket *sock;
- for (sock = groupnode->outputs.first; sock; sock = sock->next) {
- if (STREQ(sock->identifier, identifier)) {
- return sock;
- }
- }
- return NULL;
+ return find_matching_socket(groupnode->outputs, identifier);
}
-/* groups display their internal tree name as label */
-void node_group_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_group_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
BLI_strncpy(label, (node->id) ? node->id->name + 2 : IFACE_("Missing Data-Block"), maxlen);
}
@@ -95,22 +99,21 @@ bool node_group_poll_instance(bNode *node, bNodeTree *nodetree, const char **dis
bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_disabled_hint)
{
- bNode *node;
bool valid = true;
/* unspecified node group, generally allowed
* (if anything, should be avoided on operator level)
*/
- if (grouptree == NULL) {
+ if (grouptree == nullptr) {
return true;
}
if (nodetree == grouptree) {
- *r_disabled_hint = "Nesting a node group inside of itself is not allowed";
+ *r_disabled_hint = TIP_("Nesting a node group inside of itself is not allowed");
return false;
}
- for (node = grouptree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &grouptree->nodes) {
if (node->typeinfo->poll_instance &&
!node->typeinfo->poll_instance(node, nodetree, r_disabled_hint)) {
valid = false;
@@ -120,81 +123,86 @@ bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_dis
return valid;
}
-/* used for both group nodes and interface nodes */
-static bNodeSocket *group_verify_socket(
- bNodeTree *ntree, bNode *gnode, bNodeSocket *iosock, ListBase *verify_lb, int in_out)
+static void add_new_socket_from_interface(bNodeTree &node_tree,
+ bNode &node,
+ const bNodeSocket &interface_socket,
+ const eNodeSocketInOut in_out)
{
- bNodeSocket *sock;
+ bNodeSocket *socket = nodeAddSocket(&node_tree,
+ &node,
+ in_out,
+ interface_socket.idname,
+ interface_socket.identifier,
+ interface_socket.name);
- for (sock = verify_lb->first; sock; sock = sock->next) {
- if (STREQ(sock->identifier, iosock->identifier)) {
- break;
- }
+ if (interface_socket.typeinfo->interface_init_socket) {
+ interface_socket.typeinfo->interface_init_socket(
+ &node_tree, &interface_socket, &node, socket, "interface");
}
- if (sock) {
- strcpy(sock->name, iosock->name);
+}
- const int mask = SOCK_HIDE_VALUE;
- sock->flag = (sock->flag & ~mask) | (iosock->flag & mask);
+static void update_socket_to_match_interface(bNodeTree &node_tree,
+ bNode &node,
+ bNodeSocket &socket_to_update,
+ const bNodeSocket &interface_socket)
+{
+ strcpy(socket_to_update.name, interface_socket.name);
- /* Update socket type if necessary */
- if (sock->typeinfo != iosock->typeinfo) {
- nodeModifySocketType(ntree, gnode, sock, iosock->idname);
- /* Flag the tree to make sure link validity is updated after type changes. */
- ntree->update |= NTREE_UPDATE_LINKS;
- }
+ const int mask = SOCK_HIDE_VALUE;
+ socket_to_update.flag = (socket_to_update.flag & ~mask) | (interface_socket.flag & mask);
- if (iosock->typeinfo->interface_verify_socket) {
- iosock->typeinfo->interface_verify_socket(ntree, iosock, gnode, sock, "interface");
- }
+ /* Update socket type if necessary */
+ if (socket_to_update.typeinfo != interface_socket.typeinfo) {
+ nodeModifySocketType(&node_tree, &node, &socket_to_update, interface_socket.idname);
}
- else {
- sock = nodeAddSocket(ntree, gnode, in_out, iosock->idname, iosock->identifier, iosock->name);
- if (iosock->typeinfo->interface_init_socket) {
- iosock->typeinfo->interface_init_socket(ntree, iosock, gnode, sock, "interface");
- }
+ if (interface_socket.typeinfo->interface_verify_socket) {
+ interface_socket.typeinfo->interface_verify_socket(
+ &node_tree, &interface_socket, &node, &socket_to_update, "interface");
}
-
- /* remove from list temporarily, to distinguish from orphaned sockets */
- BLI_remlink(verify_lb, sock);
-
- return sock;
}
-/* used for both group nodes and interface nodes */
-static void group_verify_socket_list(
- bNodeTree *ntree, bNode *gnode, ListBase *iosock_lb, ListBase *verify_lb, int in_out)
+/**
+ * Used for group nodes and group input/output nodes to update the list of input or output sockets
+ * on a node to match the provided interface. Assumes that \a verify_lb is the node's matching
+ * input or output socket list, depending on whether the node is a group input/output or a group
+ * node.
+ */
+static void group_verify_socket_list(bNodeTree &node_tree,
+ bNode &node,
+ const ListBase &interface_sockets,
+ ListBase &verify_lb,
+ const eNodeSocketInOut in_out)
{
- bNodeSocket *iosock, *sock, *nextsock;
-
- /* step by step compare */
-
- iosock = iosock_lb->first;
- for (; iosock; iosock = iosock->next) {
- /* abusing new_sock pointer for verification here! only used inside this function */
- iosock->new_sock = group_verify_socket(ntree, gnode, iosock, verify_lb, in_out);
- }
- /* leftovers are removed */
- for (sock = verify_lb->first; sock; sock = nextsock) {
- nextsock = sock->next;
- nodeRemoveSocket(ntree, gnode, sock);
- }
- /* and we put back the verified sockets */
- iosock = iosock_lb->first;
- for (; iosock; iosock = iosock->next) {
- if (iosock->new_sock) {
- BLI_addtail(verify_lb, iosock->new_sock);
- iosock->new_sock = NULL;
+ ListBase old_sockets = verify_lb;
+ BLI_listbase_clear(&verify_lb);
+
+ LISTBASE_FOREACH (const bNodeSocket *, interface_socket, &interface_sockets) {
+ bNodeSocket *matching_socket = find_matching_socket(old_sockets, interface_socket->identifier);
+ if (matching_socket) {
+ /* If a socket with the same identifier exists in the previous socket list, update it
+ * with the correct name, type, etc. Then move it from the old list to the new one. */
+ update_socket_to_match_interface(node_tree, node, *matching_socket, *interface_socket);
+ BLI_remlink(&old_sockets, matching_socket);
+ BLI_addtail(&verify_lb, matching_socket);
+ }
+ else {
+ /* If there was no socket withe the same identifier already, simply create a new socket
+ * based on the interface socket, which will already add it to the new list. */
+ add_new_socket_from_interface(node_tree, node, *interface_socket, in_out);
}
}
+
+ /* Remove leftover sockets that didn't match the node group's interface. */
+ LISTBASE_FOREACH_MUTABLE (bNodeSocket *, unused_socket, &old_sockets) {
+ nodeRemoveSocket(&node_tree, &node, unused_socket);
+ }
}
-/* make sure all group node in ntree, which use ngroup, are sync'd */
void node_group_update(struct bNodeTree *ntree, struct bNode *node)
{
/* check inputs and outputs, and remove or insert them */
- if (node->id == NULL) {
+ if (node->id == nullptr) {
nodeRemoveAllSockets(ntree, node);
}
else if ((ID_IS_LINKED(node->id) && (node->id->tag & LIB_TAG_MISSING))) {
@@ -203,8 +211,8 @@ void node_group_update(struct bNodeTree *ntree, struct bNode *node)
}
else {
bNodeTree *ngroup = (bNodeTree *)node->id;
- group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN);
- group_verify_socket_list(ntree, node, &ngroup->outputs, &node->outputs, SOCK_OUT);
+ group_verify_socket_list(*ntree, *node, ngroup->inputs, node->inputs, SOCK_IN);
+ group_verify_socket_list(*ntree, *node, ngroup->outputs, node->outputs, SOCK_OUT);
}
}
@@ -216,7 +224,7 @@ void node_group_update(struct bNodeTree *ntree, struct bNode *node)
static void node_frame_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeFrame *data = (NodeFrame *)MEM_callocN(sizeof(NodeFrame), "frame node storage");
+ NodeFrame *data = MEM_cnew<NodeFrame>("frame node storage");
node->storage = data;
data->flag |= NODE_FRAME_SHRINK;
@@ -224,16 +232,17 @@ static void node_frame_init(bNodeTree *UNUSED(ntree), bNode *node)
data->label_size = 20;
}
-void register_node_type_frame(void)
+void register_node_type_frame()
{
/* frame type is used for all tree types, needs dynamic allocation */
- bNodeType *ntype = MEM_callocN(sizeof(bNodeType), "frame node type");
+ bNodeType *ntype = MEM_cnew<bNodeType>("frame node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
- node_type_base(ntype, NODE_FRAME, "Frame", NODE_CLASS_LAYOUT, NODE_BACKGROUND);
+ node_type_base(ntype, NODE_FRAME, "Frame", NODE_CLASS_LAYOUT);
node_type_init(ntype, node_frame_init);
node_type_storage(ntype, "NodeFrame", node_free_standard_storage, node_copy_standard_storage);
node_type_size(ntype, 150, 100, 0);
+ ntype->flag |= NODE_BACKGROUND;
nodeRegisterType(ntype);
}
@@ -244,26 +253,6 @@ void register_node_type_frame(void)
/** \name Node Re-Route
* \{ */
-/* simple, only a single input and output here */
-static void node_reroute_update_internal_links(bNodeTree *ntree, bNode *node)
-{
- bNodeLink *link;
-
- /* Security check! */
- if (!ntree) {
- return;
- }
-
- link = MEM_callocN(sizeof(bNodeLink), "internal node link");
- link->fromnode = node;
- link->fromsock = node->inputs.first;
- link->tonode = node;
- link->tosock = node->outputs.first;
- /* internal link is always valid */
- link->flag |= NODE_LINK_VALID;
- BLI_addtail(&node->internal_links, link);
-}
-
static void node_reroute_init(bNodeTree *ntree, bNode *node)
{
/* NOTE: Cannot use socket templates for this, since it would reset the socket type
@@ -273,106 +262,105 @@ static void node_reroute_init(bNodeTree *ntree, bNode *node)
nodeAddStaticSocket(ntree, node, SOCK_OUT, SOCK_RGBA, PROP_NONE, "Output", "Output");
}
-void register_node_type_reroute(void)
+void register_node_type_reroute()
{
/* frame type is used for all tree types, needs dynamic allocation */
- bNodeType *ntype = MEM_callocN(sizeof(bNodeType), "frame node type");
+ bNodeType *ntype = MEM_cnew<bNodeType>("frame node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
- node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT, 0);
+ node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT);
node_type_init(ntype, node_reroute_init);
- node_type_internal_links(ntype, node_reroute_update_internal_links);
nodeRegisterType(ntype);
}
-static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, int flag)
+static void propagate_reroute_type_from_start_socket(
+ bNodeSocket *start_socket,
+ const MultiValueMap<bNodeSocket *, bNodeLink *> &links_map,
+ Map<bNode *, const bNodeSocketType *> &r_reroute_types)
{
- bNodeSocket *input = node->inputs.first;
- bNodeSocket *output = node->outputs.first;
- bNodeLink *link;
- int type = SOCK_FLOAT;
- const char *type_idname = nodeStaticSocketType(type, PROP_NONE);
-
- /* XXX it would be a little bit more efficient to restrict actual updates
- * to reroute nodes connected to an updated node, but there's no reliable flag
- * to indicate updated nodes (node->update is not set on linking).
- */
-
- node->done = 1;
+ Stack<bNode *> nodes_to_check;
+ for (bNodeLink *link : links_map.lookup(start_socket)) {
+ if (link->tonode->type == NODE_REROUTE) {
+ nodes_to_check.push(link->tonode);
+ }
+ if (link->fromnode->type == NODE_REROUTE) {
+ nodes_to_check.push(link->fromnode);
+ }
+ }
+ const bNodeSocketType *current_type = start_socket->typeinfo;
+ while (!nodes_to_check.is_empty()) {
+ bNode *reroute_node = nodes_to_check.pop();
+ BLI_assert(reroute_node->type == NODE_REROUTE);
+ if (r_reroute_types.add(reroute_node, current_type)) {
+ for (bNodeLink *link : links_map.lookup((bNodeSocket *)reroute_node->inputs.first)) {
+ if (link->fromnode->type == NODE_REROUTE) {
+ nodes_to_check.push(link->fromnode);
+ }
+ }
+ for (bNodeLink *link : links_map.lookup((bNodeSocket *)reroute_node->outputs.first)) {
+ if (link->tonode->type == NODE_REROUTE) {
+ nodes_to_check.push(link->tonode);
+ }
+ }
+ }
+ }
+}
- /* recursive update */
- for (link = ntree->links.first; link; link = link->next) {
- bNode *fromnode = link->fromnode;
- bNode *tonode = link->tonode;
- if (!tonode || !fromnode) {
+void ntree_update_reroute_nodes(bNodeTree *ntree)
+{
+ /* Contains nodes that are linked to at least one reroute node. */
+ Set<bNode *> nodes_linked_with_reroutes;
+ /* Contains all links that are linked to at least one reroute node. */
+ MultiValueMap<bNodeSocket *, bNodeLink *> links_map;
+ /* Build acceleration data structures for the algorithm below. */
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (link->fromsock == nullptr || link->tosock == nullptr) {
continue;
}
- if (nodeLinkIsHidden(link)) {
+ if (link->fromnode->type != NODE_REROUTE && link->tonode->type != NODE_REROUTE) {
continue;
}
-
- if (flag & REFINE_FORWARD) {
- if (tonode == node && fromnode->type == NODE_REROUTE && !fromnode->done) {
- node_reroute_inherit_type_recursive(ntree, fromnode, REFINE_FORWARD);
- }
+ if (link->fromnode->type != NODE_REROUTE) {
+ nodes_linked_with_reroutes.add(link->fromnode);
}
- if (flag & REFINE_BACKWARD) {
- if (fromnode == node && tonode->type == NODE_REROUTE && !tonode->done) {
- node_reroute_inherit_type_recursive(ntree, tonode, REFINE_BACKWARD);
- }
+ if (link->tonode->type != NODE_REROUTE) {
+ nodes_linked_with_reroutes.add(link->tonode);
}
+ links_map.add(link->fromsock, link);
+ links_map.add(link->tosock, link);
}
- /* determine socket type from unambiguous input/output connection if possible */
- if (nodeSocketLinkLimit(input) == 1 && input->link) {
- type = input->link->fromsock->type;
- type_idname = nodeStaticSocketType(type, PROP_NONE);
- }
- else if (nodeSocketLinkLimit(output) == 1 && output->link) {
- type = output->link->tosock->type;
- type_idname = nodeStaticSocketType(type, PROP_NONE);
- }
+ /* Will contain the socket type for every linked reroute node. */
+ Map<bNode *, const bNodeSocketType *> reroute_types;
- if (input->type != type) {
- bNodeSocket *ninput = nodeAddSocket(ntree, node, SOCK_IN, type_idname, "input", "Input");
- for (link = ntree->links.first; link; link = link->next) {
- if (link->tosock == input) {
- link->tosock = ninput;
- ninput->link = link;
- }
+ /* Propagate socket types from left to right. */
+ for (bNode *start_node : nodes_linked_with_reroutes) {
+ LISTBASE_FOREACH (bNodeSocket *, output_socket, &start_node->outputs) {
+ propagate_reroute_type_from_start_socket(output_socket, links_map, reroute_types);
}
- nodeRemoveSocket(ntree, node, input);
}
- if (output->type != type) {
- bNodeSocket *noutput = nodeAddSocket(ntree, node, SOCK_OUT, type_idname, "output", "Output");
- for (link = ntree->links.first; link; link = link->next) {
- if (link->fromsock == output) {
- link->fromsock = noutput;
- }
+ /* Propagate socket types from right to left. This affects reroute nodes that haven't been
+ * changed in the the loop above. */
+ for (bNode *start_node : nodes_linked_with_reroutes) {
+ LISTBASE_FOREACH (bNodeSocket *, input_socket, &start_node->inputs) {
+ propagate_reroute_type_from_start_socket(input_socket, links_map, reroute_types);
}
- nodeRemoveSocket(ntree, node, output);
}
- nodeUpdateInternalLinks(ntree, node);
-}
-
-/* Global update function for Reroute node types.
- * This depends on connected nodes, so must be done as a tree-wide update.
- */
-void ntree_update_reroute_nodes(bNodeTree *ntree)
-{
- bNode *node;
-
- /* clear tags */
- for (node = ntree->nodes.first; node; node = node->next) {
- node->done = 0;
- }
+ /* Actually update reroute nodes with changed types. */
+ for (const auto item : reroute_types.items()) {
+ bNode *reroute_node = item.key;
+ const bNodeSocketType *socket_type = item.value;
+ bNodeSocket *input_socket = (bNodeSocket *)reroute_node->inputs.first;
+ bNodeSocket *output_socket = (bNodeSocket *)reroute_node->outputs.first;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_REROUTE && !node->done) {
- node_reroute_inherit_type_recursive(ntree, node, REFINE_FORWARD | REFINE_BACKWARD);
+ if (input_socket->typeinfo != socket_type) {
+ nodeModifySocketType(ntree, reroute_node, input_socket, socket_type->idname);
+ }
+ if (output_socket->typeinfo != socket_type) {
+ nodeModifySocketType(ntree, reroute_node, output_socket, socket_type->idname);
}
}
}
@@ -393,7 +381,7 @@ static bool node_is_connected_to_output_recursive(bNodeTree *ntree, bNode *node)
}
/* test all connected nodes, first positive find is sufficient to return true */
- for (link = ntree->links.first; link; link = link->next) {
+ for (link = (bNodeLink *)ntree->links.first; link; link = link->next) {
if (link->fromnode == node) {
if (node_is_connected_to_output_recursive(ntree, link->tonode)) {
return true;
@@ -408,7 +396,7 @@ bool BKE_node_is_connected_to_output(bNodeTree *ntree, bNode *node)
bNode *tnode;
/* clear flags */
- for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
+ for (tnode = (bNode *)ntree->nodes.first; tnode; tnode = tnode->next) {
tnode->done = 0;
}
@@ -419,9 +407,9 @@ void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree)
{
bNode *node;
- for (node = ntree->nodes.first; node; node = node->next) {
+ for (node = (bNode *)ntree->nodes.first; node; node = node->next) {
if (node->id == id) {
- node->id = NULL;
+ node->id = nullptr;
}
}
}
@@ -432,6 +420,11 @@ void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree)
/** \name Node #GROUP_INPUT / #GROUP_OUTPUT
* \{ */
+static bool is_group_extension_socket(const bNode *node, const bNodeSocket *socket)
+{
+ return socket->type == SOCK_CUSTOM && ELEM(node->type, NODE_GROUP_OUTPUT, NODE_GROUP_INPUT);
+}
+
static void node_group_input_init(bNodeTree *ntree, bNode *node)
{
node_group_input_update(ntree, node);
@@ -440,17 +433,17 @@ static void node_group_input_init(bNodeTree *ntree, bNode *node)
bNodeSocket *node_group_input_find_socket(bNode *node, const char *identifier)
{
bNodeSocket *sock;
- for (sock = node->outputs.first; sock; sock = sock->next) {
+ for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
if (STREQ(sock->identifier, identifier)) {
return sock;
}
}
- return NULL;
+ return nullptr;
}
void node_group_input_update(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *extsock = node->outputs.last;
+ bNodeSocket *extsock = (bNodeSocket *)node->outputs.last;
bNodeLink *link, *linknext, *exposelink;
/* Adding a tree socket and verifying will remove the extension socket!
* This list caches the existing links from the extension socket
@@ -460,14 +453,14 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
/* find links from the extension socket and store them */
BLI_listbase_clear(&tmplinks);
- for (link = ntree->links.first; link; link = linknext) {
+ for (link = (bNodeLink *)ntree->links.first; link; link = linknext) {
linknext = link->next;
if (nodeLinkIsHidden(link)) {
continue;
}
if (link->fromsock == extsock) {
- bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "temporary link");
+ bNodeLink *tlink = MEM_cnew<bNodeLink>("temporary link");
*tlink = *link;
BLI_addtail(&tmplinks, tlink);
@@ -476,14 +469,14 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
}
/* find valid link to expose */
- exposelink = NULL;
- for (link = tmplinks.first; link; link = link->next) {
+ exposelink = nullptr;
+ for (link = (bNodeLink *)tmplinks.first; link; link = link->next) {
/* XXX Multiple sockets can be connected to the extension socket at once,
* in that case the arbitrary first link determines name and type.
* This could be improved by choosing the "best" type among all links,
* whatever that means.
*/
- if (link->tosock->type != SOCK_CUSTOM) {
+ if (!is_group_extension_socket(link->tonode, link->tosock)) {
exposelink = link;
break;
}
@@ -498,7 +491,7 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
newsock = node_group_input_find_socket(node, gsock->identifier);
/* redirect links from the extension socket */
- for (link = tmplinks.first; link; link = link->next) {
+ for (link = (bNodeLink *)tmplinks.first; link; link = link->next) {
nodeAddLink(ntree, node, newsock, link->tonode, link->tosock);
}
}
@@ -508,20 +501,20 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
/* check inputs and outputs, and remove or insert them */
{
/* value_in_out inverted for interface nodes to get correct socket value_property */
- group_verify_socket_list(ntree, node, &ntree->inputs, &node->outputs, SOCK_OUT);
+ group_verify_socket_list(*ntree, *node, ntree->inputs, node->outputs, SOCK_OUT);
/* add virtual extension socket */
nodeAddSocket(ntree, node, SOCK_OUT, "NodeSocketVirtual", "__extend__", "");
}
}
-void register_node_type_group_input(void)
+void register_node_type_group_input()
{
/* used for all tree types, needs dynamic allocation */
- bNodeType *ntype = MEM_callocN(sizeof(bNodeType), "node type");
+ bNodeType *ntype = MEM_cnew<bNodeType>("node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
- node_type_base(ntype, NODE_GROUP_INPUT, "Group Input", NODE_CLASS_INTERFACE, 0);
+ node_type_base(ntype, NODE_GROUP_INPUT, "Group Input", NODE_CLASS_INTERFACE);
node_type_size(ntype, 140, 80, 400);
node_type_init(ntype, node_group_input_init);
node_type_update(ntype, node_group_input_update);
@@ -537,17 +530,17 @@ static void node_group_output_init(bNodeTree *ntree, bNode *node)
bNodeSocket *node_group_output_find_socket(bNode *node, const char *identifier)
{
bNodeSocket *sock;
- for (sock = node->inputs.first; sock; sock = sock->next) {
+ for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
if (STREQ(sock->identifier, identifier)) {
return sock;
}
}
- return NULL;
+ return nullptr;
}
void node_group_output_update(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *extsock = node->inputs.last;
+ bNodeSocket *extsock = (bNodeSocket *)node->inputs.last;
bNodeLink *link, *linknext, *exposelink;
/* Adding a tree socket and verifying will remove the extension socket!
* This list caches the existing links to the extension socket
@@ -557,14 +550,14 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
/* find links to the extension socket and store them */
BLI_listbase_clear(&tmplinks);
- for (link = ntree->links.first; link; link = linknext) {
+ for (link = (bNodeLink *)ntree->links.first; link; link = linknext) {
linknext = link->next;
if (nodeLinkIsHidden(link)) {
continue;
}
if (link->tosock == extsock) {
- bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "temporary link");
+ bNodeLink *tlink = MEM_cnew<bNodeLink>("temporary link");
*tlink = *link;
BLI_addtail(&tmplinks, tlink);
@@ -573,14 +566,14 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
}
/* find valid link to expose */
- exposelink = NULL;
- for (link = tmplinks.first; link; link = link->next) {
+ exposelink = nullptr;
+ for (link = (bNodeLink *)tmplinks.first; link; link = link->next) {
/* XXX Multiple sockets can be connected to the extension socket at once,
* in that case the arbitrary first link determines name and type.
* This could be improved by choosing the "best" type among all links,
* whatever that means.
*/
- if (link->fromsock->type != SOCK_CUSTOM) {
+ if (!is_group_extension_socket(link->fromnode, link->fromsock)) {
exposelink = link;
break;
}
@@ -596,7 +589,7 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
newsock = node_group_output_find_socket(node, gsock->identifier);
/* redirect links to the extension socket */
- for (link = tmplinks.first; link; link = link->next) {
+ for (link = (bNodeLink *)tmplinks.first; link; link = link->next) {
nodeAddLink(ntree, link->fromnode, link->fromsock, node, newsock);
}
}
@@ -606,24 +599,26 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
/* check inputs and outputs, and remove or insert them */
{
/* value_in_out inverted for interface nodes to get correct socket value_property */
- group_verify_socket_list(ntree, node, &ntree->outputs, &node->inputs, SOCK_IN);
+ group_verify_socket_list(*ntree, *node, ntree->outputs, node->inputs, SOCK_IN);
/* add virtual extension socket */
nodeAddSocket(ntree, node, SOCK_IN, "NodeSocketVirtual", "__extend__", "");
}
}
-void register_node_type_group_output(void)
+void register_node_type_group_output()
{
/* used for all tree types, needs dynamic allocation */
- bNodeType *ntype = MEM_callocN(sizeof(bNodeType), "node type");
+ bNodeType *ntype = MEM_cnew<bNodeType>("node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
- node_type_base(ntype, NODE_GROUP_OUTPUT, "Group Output", NODE_CLASS_INTERFACE, 0);
+ node_type_base(ntype, NODE_GROUP_OUTPUT, "Group Output", NODE_CLASS_INTERFACE);
node_type_size(ntype, 140, 80, 400);
node_type_init(ntype, node_group_output_init);
node_type_update(ntype, node_group_output_update);
+ ntype->no_muting = true;
+
nodeRegisterType(ntype);
}
diff --git a/source/blender/nodes/intern/node_common.h b/source/blender/nodes/intern/node_common.h
index cdb7b6897b9..0d1b51224e6 100644
--- a/source/blender/nodes/intern/node_common.h
+++ b/source/blender/nodes/intern/node_common.h
@@ -31,11 +31,19 @@ extern "C" {
struct bNodeTree;
-void node_group_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
+/** Groups display their internal tree name as label. */
+void node_group_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
bool node_group_poll_instance(struct bNode *node,
struct bNodeTree *nodetree,
const char **r_disabled_hint);
+/**
+ * Global update function for Reroute node types.
+ * This depends on connected nodes, so must be done as a tree-wide update.
+ */
void ntree_update_reroute_nodes(struct bNodeTree *ntree);
#ifdef __cplusplus
diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc
index 8a38b68ec59..28e8bf5a4b7 100644
--- a/source/blender/nodes/intern/node_declaration.cc
+++ b/source/blender/nodes/intern/node_declaration.cc
@@ -20,16 +20,6 @@
namespace blender::nodes {
-void NodeDeclaration::build(bNodeTree &ntree, bNode &node) const
-{
- for (const SocketDeclarationPtr &decl : inputs_) {
- decl->build(ntree, node, SOCK_IN);
- }
- for (const SocketDeclarationPtr &decl : outputs_) {
- decl->build(ntree, node, SOCK_OUT);
- }
-}
-
bool NodeDeclaration::matches(const bNode &node) const
{
auto check_sockets = [&](ListBase sockets, Span<SocketDeclarationPtr> socket_decls) {
@@ -61,15 +51,19 @@ bNodeSocket &SocketDeclaration::update_or_build(bNodeTree &ntree,
bNodeSocket &socket) const
{
/* By default just rebuild. */
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ UNUSED_VARS_NDEBUG(socket);
+ return this->build(ntree, node);
}
void SocketDeclaration::set_common_flags(bNodeSocket &socket) const
{
+ SET_FLAG_FROM_TEST(socket.flag, compact_, SOCK_COMPACT);
SET_FLAG_FROM_TEST(socket.flag, hide_value_, SOCK_HIDE_VALUE);
SET_FLAG_FROM_TEST(socket.flag, hide_label_, SOCK_HIDE_LABEL);
SET_FLAG_FROM_TEST(socket.flag, is_multi_input_, SOCK_MULTI_INPUT);
SET_FLAG_FROM_TEST(socket.flag, no_mute_links_, SOCK_NO_INTERNAL_LINK);
+ SET_FLAG_FROM_TEST(socket.flag, is_unavailable_, SOCK_UNAVAIL);
}
bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const
@@ -80,6 +74,9 @@ bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const
if (socket.identifier != identifier_) {
return false;
}
+ if (((socket.flag & SOCK_COMPACT) != 0) != compact_) {
+ return false;
+ }
if (((socket.flag & SOCK_HIDE_VALUE) != 0) != hide_value_) {
return false;
}
@@ -92,6 +89,9 @@ bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const
if (((socket.flag & SOCK_NO_INTERNAL_LINK) != 0) != no_mute_links_) {
return false;
}
+ if (((socket.flag & SOCK_UNAVAIL) != 0) != is_unavailable_) {
+ return false;
+ }
return true;
}
diff --git a/source/blender/nodes/intern/node_exec.cc b/source/blender/nodes/intern/node_exec.cc
index 18403417af3..4ff662036c3 100644
--- a/source/blender/nodes/intern/node_exec.cc
+++ b/source/blender/nodes/intern/node_exec.cc
@@ -28,20 +28,19 @@
#include "BKE_global.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "MEM_guardedalloc.h"
#include "node_exec.h"
#include "node_util.h"
-/* supported socket types in old nodes */
int node_exec_socket_use_stack(bNodeSocket *sock)
{
/* NOTE: INT supported as FLOAT. Only for EEVEE. */
return ELEM(sock->type, SOCK_INT, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER);
}
-/* for a given socket, find the actual stack entry */
bNodeStack *node_get_socket_stack(bNodeStack *stack, bNodeSocket *sock)
{
if (stack && sock && sock->stack_index >= 0) {
@@ -172,13 +171,13 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context,
/* Using global main here is likely totally wrong, not sure what to do about that one though...
* We cannot even check ntree is in global main,
* since most of the time it won't be (thanks to ntree design)!!! */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
/* get a dependency-sorted list of nodes */
ntreeGetDependencyList(ntree, &nodelist, &totnodes);
/* XXX could let callbacks do this for specialized data */
- exec = (bNodeTreeExec *)MEM_callocN(sizeof(bNodeTreeExec), "node tree execution data");
+ exec = MEM_cnew<bNodeTreeExec>("node tree execution data");
/* backpointer to node tree */
exec->nodetree = ntree;
@@ -293,7 +292,7 @@ bNodeThreadStack *ntreeGetThreadStack(bNodeTreeExec *exec, int thread)
}
if (!nts) {
- nts = (bNodeThreadStack *)MEM_callocN(sizeof(bNodeThreadStack), "bNodeThreadStack");
+ nts = MEM_cnew<bNodeThreadStack>("bNodeThreadStack");
nts->stack = (bNodeStack *)MEM_dupallocN(exec->stack);
nts->used = true;
BLI_addtail(lb, nts);
diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h
index de7cbb8cedb..b2e1c6564b6 100644
--- a/source/blender/nodes/intern/node_exec.h
+++ b/source/blender/nodes/intern/node_exec.h
@@ -71,8 +71,10 @@ typedef struct bNodeThreadStack {
bool used;
} bNodeThreadStack;
+/** Supported socket types in old nodes. */
int node_exec_socket_use_stack(struct bNodeSocket *sock);
+/** For a given socket, find the actual stack entry. */
struct bNodeStack *node_get_socket_stack(struct bNodeStack *stack, struct bNodeSocket *sock);
void node_get_stack(struct bNode *node,
struct bNodeStack *stack,
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index a3bbca90731..b5c4e71df74 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -18,8 +18,9 @@
#include "DEG_depsgraph_query.h"
+#include "BKE_type_conversions.hh"
+
#include "NOD_geometry_exec.hh"
-#include "NOD_type_conversions.hh"
#include "node_geometry_util.hh"
@@ -36,6 +37,72 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin
local_logger.log_node_warning(provider_->dnode, type, std::move(message));
}
+void GeoNodeExecParams::check_input_geometry_set(StringRef identifier,
+ const GeometrySet &geometry_set) const
+{
+ const SocketDeclaration &decl =
+ *provider_->dnode->input_by_identifier(identifier).bsocket()->declaration;
+ const decl::Geometry *geo_decl = dynamic_cast<const decl::Geometry *>(&decl);
+ if (geo_decl == nullptr) {
+ return;
+ }
+
+ const bool only_realized_data = geo_decl->only_realized_data();
+ const bool only_instances = geo_decl->only_instances();
+ const Span<GeometryComponentType> supported_types = geo_decl->supported_types();
+
+ if (only_realized_data) {
+ if (geometry_set.has_instances()) {
+ this->error_message_add(NodeWarningType::Info,
+ TIP_("Instances in input geometry are ignored"));
+ }
+ }
+ if (only_instances) {
+ if (geometry_set.has_realized_data()) {
+ this->error_message_add(NodeWarningType::Info,
+ TIP_("Realized data in input geometry is ignored"));
+ }
+ }
+ if (supported_types.is_empty()) {
+ /* Assume all types are supported. */
+ return;
+ }
+ const Vector<GeometryComponentType> types_in_geometry = geometry_set.gather_component_types(
+ true, true);
+ for (const GeometryComponentType type : types_in_geometry) {
+ if (type == GEO_COMPONENT_TYPE_INSTANCES) {
+ continue;
+ }
+ if (supported_types.contains(type)) {
+ continue;
+ }
+ std::string message = TIP_("Input geometry has unsupported type: ");
+ switch (type) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ message += TIP_("Mesh");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ message += TIP_("Point Cloud");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ BLI_assert_unreachable();
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME: {
+ message += TIP_("Volume");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ message += TIP_("Curve");
+ break;
+ }
+ }
+ this->error_message_add(NodeWarningType::Info, std::move(message));
+ }
+}
+
const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const
{
for (const InputSocketRef *socket : provider_->dnode->inputs()) {
@@ -47,11 +114,11 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name
return nullptr;
}
-GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- const AttributeDomain domain,
- const CustomDataType type,
- const void *default_value) const
+GVArray GeoNodeExecParams::get_input_attribute(const StringRef name,
+ const GeometryComponent &component,
+ const AttributeDomain domain,
+ const CustomDataType type,
+ const void *default_value) const
{
const bNodeSocket *found_socket = this->find_available_socket(name);
BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */
@@ -63,13 +130,13 @@ GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name,
}
if (found_socket == nullptr) {
- return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value);
+ return GVArray::ForSingle(*cpp_type, domain_size, default_value);
}
if (found_socket->type == SOCK_STRING) {
const std::string name = this->get_input<std::string>(found_socket->identifier);
/* Try getting the attribute without the default value. */
- GVArrayPtr attribute = component.attribute_try_get_for_read(name, domain, type);
+ GVArray attribute = component.attribute_try_get_for_read(name, domain, type);
if (attribute) {
return attribute;
}
@@ -81,36 +148,36 @@ GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name,
this->error_message_add(NodeWarningType::Error,
TIP_("No attribute with name \"") + name + "\"");
}
- return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value);
+ return GVArray::ForSingle(*cpp_type, domain_size, default_value);
}
- const DataTypeConversions &conversions = get_implicit_type_conversions();
+ const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
if (found_socket->type == SOCK_FLOAT) {
const float value = this->get_input<float>(found_socket->identifier);
BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
conversions.convert_to_uninitialized(CPPType::get<float>(), *cpp_type, &value, buffer);
- return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
+ return GVArray::ForSingle(*cpp_type, domain_size, buffer);
}
if (found_socket->type == SOCK_INT) {
const int value = this->get_input<int>(found_socket->identifier);
BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
conversions.convert_to_uninitialized(CPPType::get<int>(), *cpp_type, &value, buffer);
- return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
+ return GVArray::ForSingle(*cpp_type, domain_size, buffer);
}
if (found_socket->type == SOCK_VECTOR) {
const float3 value = this->get_input<float3>(found_socket->identifier);
BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
conversions.convert_to_uninitialized(CPPType::get<float3>(), *cpp_type, &value, buffer);
- return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
+ return GVArray::ForSingle(*cpp_type, domain_size, buffer);
}
if (found_socket->type == SOCK_RGBA) {
const ColorGeometry4f value = this->get_input<ColorGeometry4f>(found_socket->identifier);
BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
conversions.convert_to_uninitialized(
CPPType::get<ColorGeometry4f>(), *cpp_type, &value, buffer);
- return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
+ return GVArray::ForSingle(*cpp_type, domain_size, buffer);
}
BLI_assert(false);
- return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value);
+ return GVArray::ForSingle(*cpp_type, domain_size, default_value);
}
CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
@@ -149,11 +216,6 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
return default_type;
}
-/**
- * If any of the corresponding input sockets are attributes instead of single values,
- * use the highest priority attribute domain from among them.
- * Otherwise return the default domain.
- */
AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain(
Span<std::string> names,
const GeometryComponent &component,
@@ -183,6 +245,16 @@ AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain(
return default_domain;
}
+std::string GeoNodeExecParams::attribute_producer_name() const
+{
+ return provider_->dnode->label_or_name() + TIP_(" node");
+}
+
+void GeoNodeExecParams::set_default_remaining_outputs()
+{
+ provider_->set_default_remaining_outputs();
+}
+
void GeoNodeExecParams::check_input_access(StringRef identifier,
const CPPType *requested_type) const
{
@@ -217,7 +289,7 @@ void GeoNodeExecParams::check_input_access(StringRef identifier,
BLI_assert_unreachable();
}
else if (requested_type != nullptr) {
- const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type();
+ const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type;
if (*requested_type != expected_type) {
std::cout << "The requested type '" << requested_type->name() << "' is incorrect. Expected '"
<< expected_type.name() << "'.\n";
@@ -257,7 +329,7 @@ void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType
BLI_assert_unreachable();
}
else {
- const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type();
+ const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type;
if (value_type != expected_type) {
std::cout << "The value type '" << value_type.name() << "' is incorrect. Expected '"
<< expected_type.name() << "'.\n";
diff --git a/source/blender/nodes/intern/node_multi_function.cc b/source/blender/nodes/intern/node_multi_function.cc
index c91899ed8c2..6d79ed839b2 100644
--- a/source/blender/nodes/intern/node_multi_function.cc
+++ b/source/blender/nodes/intern/node_multi_function.cc
@@ -18,7 +18,7 @@
namespace blender::nodes {
-NodeMultiFunctions::NodeMultiFunctions(const DerivedNodeTree &tree, ResourceScope &resource_scope)
+NodeMultiFunctions::NodeMultiFunctions(const DerivedNodeTree &tree)
{
for (const NodeTreeRef *tree_ref : tree.used_node_tree_refs()) {
bNodeTree *btree = tree_ref->btree();
@@ -27,11 +27,10 @@ NodeMultiFunctions::NodeMultiFunctions(const DerivedNodeTree &tree, ResourceScop
if (bnode->typeinfo->build_multi_function == nullptr) {
continue;
}
- NodeMultiFunctionBuilder builder{resource_scope, *bnode, *btree};
+ NodeMultiFunctionBuilder builder{*bnode, *btree};
bnode->typeinfo->build_multi_function(builder);
- const MultiFunction *fn = builder.built_fn_;
- if (fn != nullptr) {
- map_.add_new(bnode, fn);
+ if (builder.built_fn_ != nullptr) {
+ map_.add_new(bnode, {builder.built_fn_, std::move(builder.owned_built_fn_)});
}
}
}
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index 31260f95242..ed72580ccf1 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -26,9 +26,8 @@
#include "DNA_node_types.h"
#include "BLI_color.hh"
-#include "BLI_float3.hh"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -51,6 +50,7 @@
#include "FN_field.hh"
using namespace blender;
+using blender::fn::ValueOrField;
using blender::nodes::SocketDeclarationPtr;
struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree,
@@ -191,7 +191,6 @@ static void refresh_socket_list(bNodeTree &ntree,
bNode &node,
ListBase &sockets,
Span<SocketDeclarationPtr> socket_decls,
- const eNodeSocketInOut in_out,
const bool do_id_user)
{
Vector<bNodeSocket *> old_sockets = sockets;
@@ -210,7 +209,7 @@ static void refresh_socket_list(bNodeTree &ntree,
bNodeSocket *new_socket = nullptr;
if (old_socket_with_same_identifier == nullptr) {
/* Create a completely new socket. */
- new_socket = &socket_decl->build(ntree, node, in_out);
+ new_socket = &socket_decl->build(ntree, node);
}
else {
STRNCPY(old_socket_with_same_identifier->name, socket_decl->name().c_str());
@@ -237,6 +236,14 @@ static void refresh_socket_list(bNodeTree &ntree,
link->tosock = new_socket;
}
}
+ LISTBASE_FOREACH (bNodeLink *, internal_link, &node.internal_links) {
+ if (internal_link->fromsock == old_socket_with_same_identifier) {
+ internal_link->fromsock = new_socket;
+ }
+ else if (internal_link->tosock == old_socket_with_same_identifier) {
+ internal_link->tosock = new_socket;
+ }
+ }
}
}
}
@@ -258,8 +265,8 @@ static void refresh_node(bNodeTree &ntree,
blender::nodes::NodeDeclaration &node_decl,
bool do_id_user)
{
- refresh_socket_list(ntree, node, node.inputs, node_decl.inputs(), SOCK_IN, do_id_user);
- refresh_socket_list(ntree, node, node.outputs, node_decl.outputs(), SOCK_OUT, do_id_user);
+ refresh_socket_list(ntree, node, node.inputs, node_decl.inputs(), do_id_user);
+ refresh_socket_list(ntree, node, node.outputs, node_decl.outputs(), do_id_user);
}
void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user)
@@ -269,10 +276,11 @@ void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user)
return;
}
if (ntype->declare != nullptr) {
- nodeDeclarationEnsure(ntree, node);
+ nodeDeclarationEnsureOnOutdatedNode(ntree, node);
if (!node->declaration->matches(*node)) {
refresh_node(*ntree, *node, *node->declaration, do_id_user);
}
+ nodeSocketDeclarationsUpdate(node);
return;
}
/* Don't try to match socket lists when there are no templates.
@@ -301,8 +309,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
switch (type) {
case SOCK_FLOAT: {
- bNodeSocketValueFloat *dval = (bNodeSocketValueFloat *)MEM_callocN(
- sizeof(bNodeSocketValueFloat), "node socket value float");
+ bNodeSocketValueFloat *dval = MEM_cnew<bNodeSocketValueFloat>("node socket value float");
dval->subtype = subtype;
dval->value = 0.0f;
dval->min = -FLT_MAX;
@@ -312,8 +319,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
break;
}
case SOCK_INT: {
- bNodeSocketValueInt *dval = (bNodeSocketValueInt *)MEM_callocN(sizeof(bNodeSocketValueInt),
- "node socket value int");
+ bNodeSocketValueInt *dval = MEM_cnew<bNodeSocketValueInt>("node socket value int");
dval->subtype = subtype;
dval->value = 0;
dval->min = INT_MIN;
@@ -323,8 +329,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
break;
}
case SOCK_BOOLEAN: {
- bNodeSocketValueBoolean *dval = (bNodeSocketValueBoolean *)MEM_callocN(
- sizeof(bNodeSocketValueBoolean), "node socket value bool");
+ bNodeSocketValueBoolean *dval = MEM_cnew<bNodeSocketValueBoolean>("node socket value bool");
dval->value = false;
sock->default_value = dval;
@@ -332,8 +337,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
}
case SOCK_VECTOR: {
static float default_value[] = {0.0f, 0.0f, 0.0f};
- bNodeSocketValueVector *dval = (bNodeSocketValueVector *)MEM_callocN(
- sizeof(bNodeSocketValueVector), "node socket value vector");
+ bNodeSocketValueVector *dval = MEM_cnew<bNodeSocketValueVector>("node socket value vector");
dval->subtype = subtype;
copy_v3_v3(dval->value, default_value);
dval->min = -FLT_MAX;
@@ -344,16 +348,14 @@ void node_socket_init_default_value(bNodeSocket *sock)
}
case SOCK_RGBA: {
static float default_value[] = {0.0f, 0.0f, 0.0f, 1.0f};
- bNodeSocketValueRGBA *dval = (bNodeSocketValueRGBA *)MEM_callocN(
- sizeof(bNodeSocketValueRGBA), "node socket value color");
+ bNodeSocketValueRGBA *dval = MEM_cnew<bNodeSocketValueRGBA>("node socket value color");
copy_v4_v4(dval->value, default_value);
sock->default_value = dval;
break;
}
case SOCK_STRING: {
- bNodeSocketValueString *dval = (bNodeSocketValueString *)MEM_callocN(
- sizeof(bNodeSocketValueString), "node socket value string");
+ bNodeSocketValueString *dval = MEM_cnew<bNodeSocketValueString>("node socket value string");
dval->subtype = subtype;
dval->value[0] = '\0';
@@ -361,40 +363,38 @@ void node_socket_init_default_value(bNodeSocket *sock)
break;
}
case SOCK_OBJECT: {
- bNodeSocketValueObject *dval = (bNodeSocketValueObject *)MEM_callocN(
- sizeof(bNodeSocketValueObject), "node socket value object");
+ bNodeSocketValueObject *dval = MEM_cnew<bNodeSocketValueObject>("node socket value object");
dval->value = nullptr;
sock->default_value = dval;
break;
}
case SOCK_IMAGE: {
- bNodeSocketValueImage *dval = (bNodeSocketValueImage *)MEM_callocN(
- sizeof(bNodeSocketValueImage), "node socket value image");
+ bNodeSocketValueImage *dval = MEM_cnew<bNodeSocketValueImage>("node socket value image");
dval->value = nullptr;
sock->default_value = dval;
break;
}
case SOCK_COLLECTION: {
- bNodeSocketValueCollection *dval = (bNodeSocketValueCollection *)MEM_callocN(
- sizeof(bNodeSocketValueCollection), "node socket value object");
+ bNodeSocketValueCollection *dval = MEM_cnew<bNodeSocketValueCollection>(
+ "node socket value object");
dval->value = nullptr;
sock->default_value = dval;
break;
}
case SOCK_TEXTURE: {
- bNodeSocketValueTexture *dval = (bNodeSocketValueTexture *)MEM_callocN(
- sizeof(bNodeSocketValueTexture), "node socket value texture");
+ bNodeSocketValueTexture *dval = MEM_cnew<bNodeSocketValueTexture>(
+ "node socket value texture");
dval->value = nullptr;
sock->default_value = dval;
break;
}
case SOCK_MATERIAL: {
- bNodeSocketValueMaterial *dval = (bNodeSocketValueMaterial *)MEM_callocN(
- sizeof(bNodeSocketValueMaterial), "node socket value material");
+ bNodeSocketValueMaterial *dval = MEM_cnew<bNodeSocketValueMaterial>(
+ "node socket value material");
dval->value = nullptr;
sock->default_value = dval;
@@ -547,7 +547,7 @@ void node_socket_skip_reroutes(
}
static void standard_node_socket_interface_init_socket(bNodeTree *UNUSED(ntree),
- bNodeSocket *stemp,
+ const bNodeSocket *interface_socket,
bNode *UNUSED(node),
bNodeSocket *sock,
const char *UNUSED(data_path))
@@ -558,47 +558,50 @@ static void standard_node_socket_interface_init_socket(bNodeTree *UNUSED(ntree),
/* XXX socket interface 'type' value is not used really,
* but has to match or the copy function will bail out
*/
- stemp->type = stemp->typeinfo->type;
+ const_cast<bNodeSocket *>(interface_socket)->type = interface_socket->typeinfo->type;
/* copy default_value settings */
- node_socket_copy_default_value(sock, stemp);
+ node_socket_copy_default_value(sock, interface_socket);
}
/* copies settings that are not changed for each socket instance */
static void standard_node_socket_interface_verify_socket(bNodeTree *UNUSED(ntree),
- bNodeSocket *stemp,
+ const bNodeSocket *interface_socket,
bNode *UNUSED(node),
bNodeSocket *sock,
const char *UNUSED(data_path))
{
/* sanity check */
- if (sock->type != stemp->typeinfo->type) {
+ if (sock->type != interface_socket->typeinfo->type) {
return;
}
/* make sure both exist */
- if (!stemp->default_value) {
+ if (!interface_socket->default_value) {
return;
}
node_socket_init_default_value(sock);
- switch (stemp->typeinfo->type) {
+ switch (interface_socket->typeinfo->type) {
case SOCK_FLOAT: {
bNodeSocketValueFloat *toval = (bNodeSocketValueFloat *)sock->default_value;
- bNodeSocketValueFloat *fromval = (bNodeSocketValueFloat *)stemp->default_value;
+ const bNodeSocketValueFloat *fromval = (const bNodeSocketValueFloat *)
+ interface_socket->default_value;
toval->min = fromval->min;
toval->max = fromval->max;
break;
}
case SOCK_INT: {
bNodeSocketValueInt *toval = (bNodeSocketValueInt *)sock->default_value;
- bNodeSocketValueInt *fromval = (bNodeSocketValueInt *)stemp->default_value;
+ const bNodeSocketValueInt *fromval = (const bNodeSocketValueInt *)
+ interface_socket->default_value;
toval->min = fromval->min;
toval->max = fromval->max;
break;
}
case SOCK_VECTOR: {
bNodeSocketValueVector *toval = (bNodeSocketValueVector *)sock->default_value;
- bNodeSocketValueVector *fromval = (bNodeSocketValueVector *)stemp->default_value;
+ const bNodeSocketValueVector *fromval = (const bNodeSocketValueVector *)
+ interface_socket->default_value;
toval->min = fromval->min;
toval->max = fromval->max;
break;
@@ -626,7 +629,7 @@ static bNodeSocketType *make_standard_socket_type(int type, int subtype)
bNodeSocketType *stype;
StructRNA *srna;
- stype = (bNodeSocketType *)MEM_callocN(sizeof(bNodeSocketType), "node socket C type");
+ stype = MEM_cnew<bNodeSocketType>("node socket C type");
stype->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN;
BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname));
BLI_strncpy(stype->label, socket_label, sizeof(stype->label));
@@ -670,7 +673,7 @@ static bNodeSocketType *make_socket_type_virtual()
bNodeSocketType *stype;
StructRNA *srna;
- stype = (bNodeSocketType *)MEM_callocN(sizeof(bNodeSocketType), "node socket C type");
+ stype = MEM_cnew<bNodeSocketType>("node socket C type");
stype->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN;
BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname));
@@ -696,17 +699,15 @@ static bNodeSocketType *make_socket_type_virtual()
static bNodeSocketType *make_socket_type_bool()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<bool>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<bool>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<bool>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<bool>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
bool value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<bool>(value);
};
return socktype;
}
@@ -714,17 +715,15 @@ static bNodeSocketType *make_socket_type_bool()
static bNodeSocketType *make_socket_type_float(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<float>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<float>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<float>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<float>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
float value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<float>(value);
};
return socktype;
}
@@ -732,17 +731,15 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype)
static bNodeSocketType *make_socket_type_int(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_INT, subtype);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<int>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<int>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<int>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<int>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
int value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<int>(value);
};
return socktype;
}
@@ -750,17 +747,15 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype)
static bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<blender::float3>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<blender::float3>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<blender::float3>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<blender::float3>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
blender::float3 value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<blender::float3>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<blender::float3>(value);
};
return socktype;
}
@@ -768,20 +763,16 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
static bNodeSocketType *make_socket_type_rgba()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE);
- socktype->get_base_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::ColorGeometry4f>();
- };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<blender::ColorGeometry4f>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<blender::ColorGeometry4f>>();
- };
+ socktype->geometry_nodes_cpp_type =
+ &blender::fn::CPPType::get<ValueOrField<blender::ColorGeometry4f>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
blender::ColorGeometry4f value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value)
- blender::fn::Field<blender::ColorGeometry4f>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<blender::ColorGeometry4f>(value);
};
return socktype;
}
@@ -789,18 +780,16 @@ static bNodeSocketType *make_socket_type_rgba()
static bNodeSocketType *make_socket_type_string()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<std::string>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<std::string>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
new (r_value) std::string(((bNodeSocketValueString *)socket.default_value)->value);
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<std::string>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<std::string>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
std::string value;
value.~basic_string();
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<std::string>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<std::string>(value);
};
return socktype;
}
@@ -808,16 +797,17 @@ static bNodeSocketType *make_socket_type_string()
MAKE_CPP_TYPE(Object, Object *, CPPTypeFlags::BasicType)
MAKE_CPP_TYPE(Collection, Collection *, CPPTypeFlags::BasicType)
MAKE_CPP_TYPE(Texture, Tex *, CPPTypeFlags::BasicType)
+MAKE_CPP_TYPE(Image, Image *, CPPTypeFlags::BasicType)
MAKE_CPP_TYPE(Material, Material *, CPPTypeFlags::BasicType)
static bNodeSocketType *make_socket_type_object()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_OBJECT, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Object *>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Object *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Object **)r_value = ((bNodeSocketValueObject *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
@@ -825,11 +815,11 @@ static bNodeSocketType *make_socket_type_object()
static bNodeSocketType *make_socket_type_geometry()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_GEOMETRY, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<GeometrySet>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<GeometrySet>();
socktype->get_base_cpp_value = [](const bNodeSocket &UNUSED(socket), void *r_value) {
new (r_value) GeometrySet();
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
@@ -837,11 +827,11 @@ static bNodeSocketType *make_socket_type_geometry()
static bNodeSocketType *make_socket_type_collection()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_COLLECTION, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Collection *>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Collection *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Collection **)r_value = ((bNodeSocketValueCollection *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
@@ -849,11 +839,23 @@ static bNodeSocketType *make_socket_type_collection()
static bNodeSocketType *make_socket_type_texture()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_TEXTURE, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Tex *>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Tex *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Tex **)r_value = ((bNodeSocketValueTexture *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
+ socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
+ return socktype;
+}
+
+static bNodeSocketType *make_socket_type_image()
+{
+ bNodeSocketType *socktype = make_standard_socket_type(SOCK_IMAGE, PROP_NONE);
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Image *>();
+ socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
+ *(Image **)r_value = ((bNodeSocketValueImage *)socket.default_value)->value;
+ };
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
@@ -861,18 +863,18 @@ static bNodeSocketType *make_socket_type_texture()
static bNodeSocketType *make_socket_type_material()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATERIAL, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Material *>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Material *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Material **)r_value = ((bNodeSocketValueMaterial *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
-void register_standard_node_socket_types(void)
+void register_standard_node_socket_types()
{
- /* draw callbacks are set in drawnode.c to avoid bad-level calls */
+ /* Draw callbacks are set in `drawnode.c` to avoid bad-level calls. */
nodeRegisterSocketType(make_socket_type_float(PROP_NONE));
nodeRegisterSocketType(make_socket_type_float(PROP_UNSIGNED));
@@ -906,14 +908,14 @@ void register_standard_node_socket_types(void)
nodeRegisterSocketType(make_socket_type_object());
- nodeRegisterSocketType(make_standard_socket_type(SOCK_IMAGE, PROP_NONE));
-
nodeRegisterSocketType(make_socket_type_geometry());
nodeRegisterSocketType(make_socket_type_collection());
nodeRegisterSocketType(make_socket_type_texture());
+ nodeRegisterSocketType(make_socket_type_image());
+
nodeRegisterSocketType(make_socket_type_material());
nodeRegisterSocketType(make_socket_type_virtual());
diff --git a/source/blender/nodes/intern/node_socket_declarations.cc b/source/blender/nodes/intern/node_socket_declarations.cc
index 4b0dbad3cff..1e6b77a9620 100644
--- a/source/blender/nodes/intern/node_socket_declarations.cc
+++ b/source/blender/nodes/intern/node_socket_declarations.cc
@@ -15,6 +15,7 @@
*/
#include "NOD_socket_declarations.hh"
+#include "NOD_socket_declarations_geometry.hh"
#include "BKE_node.h"
@@ -22,6 +23,52 @@
namespace blender::nodes::decl {
+/**
+ * \note This function only deals with declarations, not the field status of existing nodes. If the
+ * field status of existing nodes was stored on the sockets, an improvement would be to check the
+ * existing socket's current status instead of the declaration.
+ */
+static bool field_types_are_compatible(const SocketDeclaration &input,
+ const SocketDeclaration &output)
+{
+ if (output.output_field_dependency().field_type() == OutputSocketFieldType::FieldSource) {
+ if (input.input_field_type() == InputSocketFieldType::None) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool sockets_can_connect(const SocketDeclaration &socket_decl,
+ const bNodeSocket &other_socket)
+{
+ /* Input sockets cannot connect to input sockets, outputs cannot connect to outputs. */
+ if (socket_decl.in_out() == other_socket.in_out) {
+ return false;
+ }
+
+ if (other_socket.declaration) {
+ if (socket_decl.in_out() == SOCK_IN) {
+ if (!field_types_are_compatible(socket_decl, *other_socket.declaration)) {
+ return false;
+ }
+ }
+ else {
+ if (!field_types_are_compatible(*other_socket.declaration, socket_decl)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool basic_types_can_connect(const SocketDeclaration &UNUSED(socket_decl),
+ const bNodeSocket &other_socket)
+{
+ return ELEM(other_socket.type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
+}
+
static void modify_subtype_except_for_storage(bNodeSocket &socket, int new_subtype)
{
const char *idname = nodeStaticSocketType(socket.type, new_subtype);
@@ -30,14 +77,14 @@ static void modify_subtype_except_for_storage(bNodeSocket &socket, int new_subty
socket.typeinfo = socktype;
}
-/* --------------------------------------------------------------------
- * Float.
- */
+/* -------------------------------------------------------------------- */
+/** \name #Float
+ * \{ */
-bNodeSocket &Float::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Float::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_FLOAT, subtype_, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_FLOAT, subtype_, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueFloat &value = *(bNodeSocketValueFloat *)socket.default_value;
value.min = soft_min_value_;
@@ -67,10 +114,19 @@ bool Float::matches(const bNodeSocket &socket) const
return true;
}
+bool Float::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
bNodeSocket &Float::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
{
if (socket.type != SOCK_FLOAT) {
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ return this->build(ntree, node);
}
if (socket.typeinfo->subtype != subtype_) {
modify_subtype_except_for_storage(socket, subtype_);
@@ -83,14 +139,16 @@ bNodeSocket &Float::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &
return socket;
}
-/* --------------------------------------------------------------------
- * Int.
- */
+/** \} */
-bNodeSocket &Int::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+/* -------------------------------------------------------------------- */
+/** \name #Int
+ * \{ */
+
+bNodeSocket &Int::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_INT, subtype_, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_INT, subtype_, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueInt &value = *(bNodeSocketValueInt *)socket.default_value;
value.min = soft_min_value_;
@@ -120,10 +178,19 @@ bool Int::matches(const bNodeSocket &socket) const
return true;
}
+bool Int::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
bNodeSocket &Int::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
{
if (socket.type != SOCK_INT) {
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ return this->build(ntree, node);
}
if (socket.typeinfo->subtype != subtype_) {
modify_subtype_except_for_storage(socket, subtype_);
@@ -136,14 +203,16 @@ bNodeSocket &Int::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &so
return socket;
}
-/* --------------------------------------------------------------------
- * Vector.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #Vector
+ * \{ */
-bNodeSocket &Vector::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Vector::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_VECTOR, subtype_, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_VECTOR, subtype_, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueVector &value = *(bNodeSocketValueVector *)socket.default_value;
copy_v3_v3(value.value, default_value_);
@@ -166,10 +235,19 @@ bool Vector::matches(const bNodeSocket &socket) const
return true;
}
+bool Vector::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
{
if (socket.type != SOCK_VECTOR) {
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ return this->build(ntree, node);
}
if (socket.typeinfo->subtype != subtype_) {
modify_subtype_except_for_storage(socket, subtype_);
@@ -181,14 +259,16 @@ bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket
return socket;
}
-/* --------------------------------------------------------------------
- * Bool.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #Bool
+ * \{ */
-bNodeSocket &Bool::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Bool::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_BOOLEAN, PROP_NONE, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_BOOLEAN, PROP_NONE, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueBoolean &value = *(bNodeSocketValueBoolean *)socket.default_value;
value.value = default_value_;
@@ -206,14 +286,24 @@ bool Bool::matches(const bNodeSocket &socket) const
return true;
}
-/* --------------------------------------------------------------------
- * Color.
- */
+bool Bool::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #Color
+ * \{ */
-bNodeSocket &Color::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Color::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_RGBA, PROP_NONE, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_RGBA, PROP_NONE, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueRGBA &value = *(bNodeSocketValueRGBA *)socket.default_value;
copy_v4_v4(value.value, default_value_);
@@ -236,14 +326,25 @@ bool Color::matches(const bNodeSocket &socket) const
return true;
}
-/* --------------------------------------------------------------------
- * String.
- */
+bool Color::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #String
+ * \{ */
-bNodeSocket &String::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &String::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_STRING, PROP_NONE, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_STRING, PROP_NONE, identifier_.c_str(), name_.c_str());
+ STRNCPY(((bNodeSocketValueString *)socket.default_value)->value, default_value_.c_str());
this->set_common_flags(socket);
return socket;
}
@@ -259,16 +360,21 @@ bool String::matches(const bNodeSocket &socket) const
return true;
}
-/* --------------------------------------------------------------------
- * IDSocketDeclaration.
- */
+bool String::can_connect(const bNodeSocket &socket) const
+{
+ return sockets_can_connect(*this, socket) && socket.type == SOCK_STRING;
+}
+
+/** \} */
-bNodeSocket &IDSocketDeclaration::build(bNodeTree &ntree,
- bNode &node,
- eNodeSocketInOut in_out) const
+/* -------------------------------------------------------------------- */
+/** \name #IDSocketDeclaration
+ * \{ */
+
+bNodeSocket &IDSocketDeclaration::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddSocket(
- &ntree, &node, in_out, idname_, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, idname_, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
return socket;
}
@@ -284,25 +390,33 @@ bool IDSocketDeclaration::matches(const bNodeSocket &socket) const
return true;
}
+bool IDSocketDeclaration::can_connect(const bNodeSocket &socket) const
+{
+ return sockets_can_connect(*this, socket) && STREQ(socket.idname, idname_);
+}
+
bNodeSocket &IDSocketDeclaration::update_or_build(bNodeTree &ntree,
bNode &node,
bNodeSocket &socket) const
{
if (StringRef(socket.idname) != idname_) {
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ return this->build(ntree, node);
}
this->set_common_flags(socket);
return socket;
}
-/* --------------------------------------------------------------------
- * Geometry.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #Geometry
+ * \{ */
-bNodeSocket &Geometry::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Geometry::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddSocket(
- &ntree, &node, in_out, "NodeSocketGeometry", identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, "NodeSocketGeometry", identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
return socket;
}
@@ -318,4 +432,89 @@ bool Geometry::matches(const bNodeSocket &socket) const
return true;
}
+bool Geometry::can_connect(const bNodeSocket &socket) const
+{
+ return sockets_can_connect(*this, socket) && socket.type == SOCK_GEOMETRY;
+}
+
+Span<GeometryComponentType> Geometry::supported_types() const
+{
+ return supported_types_;
+}
+
+bool Geometry::only_realized_data() const
+{
+ return only_realized_data_;
+}
+
+bool Geometry::only_instances() const
+{
+ return only_instances_;
+}
+
+GeometryBuilder &GeometryBuilder::supported_type(GeometryComponentType supported_type)
+{
+ decl_->supported_types_ = {supported_type};
+ return *this;
+}
+
+GeometryBuilder &GeometryBuilder::supported_type(
+ blender::Vector<GeometryComponentType> supported_types)
+{
+ decl_->supported_types_ = std::move(supported_types);
+ return *this;
+}
+
+GeometryBuilder &GeometryBuilder::only_realized_data(bool value)
+{
+ decl_->only_realized_data_ = value;
+ return *this;
+}
+
+GeometryBuilder &GeometryBuilder::only_instances(bool value)
+{
+ decl_->only_instances_ = value;
+ return *this;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #Shader
+ * \{ */
+
+bNodeSocket &Shader::build(bNodeTree &ntree, bNode &node) const
+{
+ bNodeSocket &socket = *nodeAddSocket(
+ &ntree, &node, in_out_, "NodeSocketShader", identifier_.c_str(), name_.c_str());
+ this->set_common_flags(socket);
+ return socket;
+}
+
+bool Shader::matches(const bNodeSocket &socket) const
+{
+ if (!this->matches_common_data(socket)) {
+ return false;
+ }
+ if (socket.type != SOCK_SHADER) {
+ return false;
+ }
+ return true;
+}
+
+bool Shader::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ /* Basic types can convert to shaders, but not the other way around. */
+ if (in_out_ == SOCK_IN) {
+ return ELEM(
+ socket.type, SOCK_VECTOR, SOCK_RGBA, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_SHADER);
+ }
+ return socket.type == SOCK_SHADER;
+}
+
+/** \} */
+
} // namespace blender::nodes::decl
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index 43c7fbd2599..bc78533d45c 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -70,6 +70,8 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
break;
}
}
+ BLI_assert(internal_link.from_ != nullptr);
+ BLI_assert(internal_link.to_ != nullptr);
node.internal_links_.append(&internal_link);
}
@@ -115,6 +117,22 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
const bNodeType *nodetype = node->bnode_->typeinfo;
nodes_by_type_.add(nodetype, node);
}
+
+ const Span<const NodeRef *> group_output_nodes = this->nodes_by_type("NodeGroupOutput");
+ if (group_output_nodes.is_empty()) {
+ group_output_node_ = nullptr;
+ }
+ else if (group_output_nodes.size() == 1) {
+ group_output_node_ = group_output_nodes.first();
+ }
+ else {
+ for (const NodeRef *group_output : group_output_nodes) {
+ if (group_output->bnode_->flag & NODE_DO_OUTPUT) {
+ group_output_node_ = group_output;
+ break;
+ }
+ }
+ }
}
NodeTreeRef::~NodeTreeRef()
@@ -262,7 +280,6 @@ void InputSocketRef::foreach_logical_origin(
skipped_fn.call_safe(origin);
skipped_fn.call_safe(mute_input);
mute_input.foreach_logical_origin(origin_fn, skipped_fn, true, seen_sockets_stack);
- break;
}
}
}
@@ -442,9 +459,6 @@ static bool has_link_cycles_recursive(const NodeRef &node,
return false;
}
-/**
- * \return True when there is a link cycle. Unavailable sockets are ignored.
- */
bool NodeTreeRef::has_link_cycles() const
{
const int node_amount = nodes_by_id_.size();
@@ -502,11 +516,15 @@ bool NodeRef::any_socket_is_directly_linked(eNodeSocketInOut in_out) const
return this->any_output_is_directly_linked();
}
-/**
- * Sort nodes topologically from left to right or right to left.
- * In the future the result if this could be cached on #NodeTreeRef.
- */
-Vector<const NodeRef *> NodeTreeRef::toposort(const ToposortDirection direction) const
+struct ToposortNodeState {
+ bool is_done = false;
+ bool is_in_stack = false;
+};
+
+static void toposort_from_start_node(const NodeTreeRef::ToposortDirection direction,
+ const NodeRef &start_node,
+ MutableSpan<ToposortNodeState> node_states,
+ NodeTreeRef::ToposortResult &result)
{
struct Item {
const NodeRef *node;
@@ -516,64 +534,103 @@ Vector<const NodeRef *> NodeTreeRef::toposort(const ToposortDirection direction)
int link_index = 0;
};
- Vector<const NodeRef *> toposort;
- toposort.reserve(nodes_by_id_.size());
- Array<bool> node_is_done_by_id(nodes_by_id_.size(), false);
- Stack<Item> nodes_to_check;
+ /* Do a depth-first search to sort nodes topologically. */
+ Stack<Item, 64> nodes_to_check;
+ nodes_to_check.push({&start_node});
+ while (!nodes_to_check.is_empty()) {
+ Item &item = nodes_to_check.peek();
+ const NodeRef &node = *item.node;
+ const Span<const SocketRef *> sockets = node.sockets(
+ direction == NodeTreeRef::ToposortDirection::LeftToRight ? SOCK_IN : SOCK_OUT);
+
+ while (true) {
+ if (item.socket_index == sockets.size()) {
+ /* All sockets have already been visited. */
+ break;
+ }
+ const SocketRef &socket = *sockets[item.socket_index];
+ const Span<const SocketRef *> linked_sockets = socket.directly_linked_sockets();
+ if (item.link_index == linked_sockets.size()) {
+ /* All links connected to this socket have already been visited. */
+ item.socket_index++;
+ item.link_index = 0;
+ continue;
+ }
+ const SocketRef &linked_socket = *linked_sockets[item.link_index];
+ const NodeRef &linked_node = linked_socket.node();
+ ToposortNodeState &linked_node_state = node_states[linked_node.id()];
+ if (linked_node_state.is_done) {
+ /* The linked node has already been visited. */
+ item.link_index++;
+ continue;
+ }
+ if (linked_node_state.is_in_stack) {
+ result.has_cycle = true;
+ }
+ else {
+ nodes_to_check.push({&linked_node});
+ linked_node_state.is_in_stack = true;
+ }
+ break;
+ }
- for (const NodeRef *start_node : nodes_by_id_) {
- if (node_is_done_by_id[start_node->id()]) {
+ /* If no other element has been pushed, the current node can be pushed to the sorted list. */
+ if (&item == &nodes_to_check.peek()) {
+ ToposortNodeState &node_state = node_states[node.id()];
+ node_state.is_done = true;
+ node_state.is_in_stack = false;
+ result.sorted_nodes.append(&node);
+ nodes_to_check.pop();
+ }
+ }
+}
+
+NodeTreeRef::ToposortResult NodeTreeRef::toposort(const ToposortDirection direction) const
+{
+ ToposortResult result;
+ result.sorted_nodes.reserve(nodes_by_id_.size());
+
+ Array<ToposortNodeState> node_states(nodes_by_id_.size());
+
+ for (const NodeRef *node : nodes_by_id_) {
+ if (node_states[node->id()].is_done) {
/* Ignore nodes that are done already. */
continue;
}
- if (start_node->any_socket_is_directly_linked(
+ if (node->any_socket_is_directly_linked(
direction == ToposortDirection::LeftToRight ? SOCK_OUT : SOCK_IN)) {
/* Ignore non-start nodes. */
continue;
}
- /* Do a depth-first search to sort nodes topologically. */
- nodes_to_check.push({start_node});
- while (!nodes_to_check.is_empty()) {
- Item &item = nodes_to_check.peek();
- const NodeRef &node = *item.node;
- const Span<const SocketRef *> sockets = node.sockets(
- direction == ToposortDirection::LeftToRight ? SOCK_IN : SOCK_OUT);
-
- while (true) {
- if (item.socket_index == sockets.size()) {
- /* All sockets have already been visited. */
- break;
- }
- const SocketRef &socket = *sockets[item.socket_index];
- const Span<const SocketRef *> linked_sockets = socket.directly_linked_sockets();
- if (item.link_index == linked_sockets.size()) {
- /* All links connected to this socket have already been visited. */
- item.socket_index++;
- item.link_index = 0;
- continue;
- }
- const SocketRef &linked_socket = *linked_sockets[item.link_index];
- const NodeRef &linked_node = linked_socket.node();
- if (node_is_done_by_id[linked_node.id()]) {
- /* The linked node has already been visited. */
- item.link_index++;
- continue;
- }
- nodes_to_check.push({&linked_node});
- break;
- }
+ toposort_from_start_node(direction, *node, node_states, result);
+ }
- /* If no other element has been pushed, the current node can be pushed to the sorted list. */
- if (&item == &nodes_to_check.peek()) {
- node_is_done_by_id[node.id()] = true;
- toposort.append(&node);
- nodes_to_check.pop();
+ /* Check if the loop above forgot some nodes because there is a cycle. */
+ if (result.sorted_nodes.size() < nodes_by_id_.size()) {
+ result.has_cycle = true;
+ for (const NodeRef *node : nodes_by_id_) {
+ if (node_states[node->id()].is_done) {
+ /* Ignore nodes that are done already. */
+ continue;
}
+ /* Start toposort at this node which is somewhere in the middle of a loop. */
+ toposort_from_start_node(direction, *node, node_states, result);
}
}
- return toposort;
+ BLI_assert(result.sorted_nodes.size() == nodes_by_id_.size());
+ return result;
+}
+
+const NodeRef *NodeTreeRef::find_node(const bNode &bnode) const
+{
+ for (const NodeRef *node : this->nodes_by_type(bnode.typeinfo)) {
+ if (node->bnode_ == &bnode) {
+ return node;
+ }
+ }
+ return nullptr;
}
std::string NodeTreeRef::to_dot() const
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c
index 1aec280fd2b..5c2d84cf605 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.c
@@ -35,12 +35,15 @@
#include "BKE_colortools.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "RNA_access.h"
#include "RNA_enum_types.h"
#include "MEM_guardedalloc.h"
+#include "NOD_common.h"
+
#include "node_util.h"
/* -------------------------------------------------------------------- */
@@ -97,12 +100,13 @@ void node_sock_label_clear(bNodeSocket *sock)
}
}
-void node_math_update(bNodeTree *UNUSED(ntree), bNode *node)
+void node_math_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sock1 = BLI_findlink(&node->inputs, 0);
bNodeSocket *sock2 = BLI_findlink(&node->inputs, 1);
bNodeSocket *sock3 = BLI_findlink(&node->inputs, 2);
- nodeSetSocketAvailability(sock2,
+ nodeSetSocketAvailability(ntree,
+ sock2,
!ELEM(node->custom1,
NODE_MATH_SQRT,
NODE_MATH_SIGN,
@@ -126,7 +130,8 @@ void node_math_update(bNodeTree *UNUSED(ntree), bNode *node)
NODE_MATH_COSH,
NODE_MATH_SINH,
NODE_MATH_TANH));
- nodeSetSocketAvailability(sock3,
+ nodeSetSocketAvailability(ntree,
+ sock3,
ELEM(node->custom1,
NODE_MATH_COMPARE,
NODE_MATH_MULTIPLY_ADD,
@@ -186,7 +191,7 @@ void node_math_update(bNodeTree *UNUSED(ntree), bNode *node)
/** \name Labels
* \{ */
-void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_blend_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_ramp_blend_items, node->custom1, &name);
@@ -196,14 +201,14 @@ void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int ma
BLI_strncpy(label, IFACE_(name), maxlen);
}
-void node_image_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_image_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
/* If there is no loaded image, return an empty string,
* and let nodeLabel() fill in the proper type translation. */
BLI_strncpy(label, (node->id) ? node->id->name + 2 : "", maxlen);
}
-void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_math_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_math_items, node->custom1, &name);
@@ -213,7 +218,10 @@ void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int max
BLI_strncpy(label, IFACE_(name), maxlen);
}
-void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_vector_math_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_vec_math_items, node->custom1, &name);
@@ -223,7 +231,7 @@ void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label,
BLI_strncpy(label, IFACE_(name), maxlen);
}
-void node_filter_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_filter_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_filter_items, node->custom1, &name);
@@ -297,11 +305,6 @@ static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree,
return NULL;
}
-/**
- * The idea behind this is: When a user connects an input to a socket that is
- * already linked (and if its not an Multi Input Socket), we try to find a replacement socket for
- * the link that we try to overwrite and connect that previous link to the new socket.
- */
void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
{
bNodeSocket *socket = link->tosock;
@@ -338,237 +341,6 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Internal Links (mute and disconnect)
- * \{ */
-
-/**
- * Common datatype priorities, works for compositor, shader and texture nodes alike
- * defines priority of datatype connection based on output type (to):
- * `< 0`: never connect these types.
- * `>= 0`: priority of connection (higher values chosen first).
- */
-static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype to)
-{
- switch (to) {
- case SOCK_RGBA:
- switch (from) {
- case SOCK_RGBA:
- return 4;
- case SOCK_FLOAT:
- return 3;
- case SOCK_INT:
- return 2;
- case SOCK_BOOLEAN:
- return 1;
- default:
- return -1;
- }
- case SOCK_VECTOR:
- switch (from) {
- case SOCK_VECTOR:
- return 4;
- case SOCK_FLOAT:
- return 3;
- case SOCK_INT:
- return 2;
- case SOCK_BOOLEAN:
- return 1;
- default:
- return -1;
- }
- case SOCK_FLOAT:
- switch (from) {
- case SOCK_FLOAT:
- return 5;
- case SOCK_INT:
- return 4;
- case SOCK_BOOLEAN:
- return 3;
- case SOCK_RGBA:
- return 2;
- case SOCK_VECTOR:
- return 1;
- default:
- return -1;
- }
- case SOCK_INT:
- switch (from) {
- case SOCK_INT:
- return 5;
- case SOCK_FLOAT:
- return 4;
- case SOCK_BOOLEAN:
- return 3;
- case SOCK_RGBA:
- return 2;
- case SOCK_VECTOR:
- return 1;
- default:
- return -1;
- }
- case SOCK_BOOLEAN:
- switch (from) {
- case SOCK_BOOLEAN:
- return 5;
- case SOCK_INT:
- return 4;
- case SOCK_FLOAT:
- return 3;
- case SOCK_RGBA:
- return 2;
- case SOCK_VECTOR:
- return 1;
- default:
- return -1;
- }
- case SOCK_SHADER:
- switch (from) {
- case SOCK_SHADER:
- return 1;
- default:
- return -1;
- }
- case SOCK_STRING:
- switch (from) {
- case SOCK_STRING:
- return 1;
- default:
- return -1;
- }
- case SOCK_OBJECT: {
- switch (from) {
- case SOCK_OBJECT:
- return 1;
- default:
- return -1;
- }
- }
- case SOCK_GEOMETRY: {
- switch (from) {
- case SOCK_GEOMETRY:
- return 1;
- default:
- return -1;
- }
- }
- case SOCK_COLLECTION: {
- switch (from) {
- case SOCK_COLLECTION:
- return 1;
- default:
- return -1;
- }
- }
- case SOCK_TEXTURE: {
- switch (from) {
- case SOCK_TEXTURE:
- return 1;
- default:
- return -1;
- }
- }
- case SOCK_MATERIAL: {
- switch (from) {
- case SOCK_MATERIAL:
- return 1;
- default:
- return -1;
- }
- }
- default:
- return -1;
- }
-}
-
-/* select a suitable input socket for an output */
-static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output)
-{
- bNodeSocket *selected = NULL, *input;
- int i;
- int sel_priority = -1;
- bool sel_is_linked = false;
-
- for (input = node->inputs.first, i = 0; input; input = input->next, i++) {
- int priority = node_datatype_priority(input->type, output->type);
- bool is_linked = (input->link != NULL);
- bool preferred;
-
- if (nodeSocketIsHidden(input) || /* ignore hidden sockets */
- input->flag &
- SOCK_NO_INTERNAL_LINK || /* ignore if input is not allowed for internal connections */
- priority < 0 || /* ignore incompatible types */
- priority < sel_priority) /* ignore if we already found a higher priority input */
- {
- continue;
- }
-
- /* determine if this input is preferred over the currently selected */
- preferred = (priority > sel_priority) || /* prefer higher datatype priority */
- (is_linked && !sel_is_linked); /* prefer linked over unlinked */
-
- if (preferred) {
- selected = input;
- sel_is_linked = is_linked;
- sel_priority = priority;
- }
- }
-
- return selected;
-}
-
-void node_update_internal_links_default(bNodeTree *ntree, bNode *node)
-{
- bNodeLink *link;
- bNodeSocket *output, *input;
-
- /* sanity check */
- if (!ntree) {
- return;
- }
-
- /* use link pointer as a tag for handled sockets (for outputs is unused anyway) */
- for (output = node->outputs.first; output; output = output->next) {
- output->link = NULL;
- }
-
- for (link = ntree->links.first; link; link = link->next) {
- if (nodeLinkIsHidden(link)) {
- continue;
- }
-
- output = link->fromsock;
- if (link->fromnode != node || output->link) {
- continue;
- }
- if (nodeSocketIsHidden(output) || output->flag & SOCK_NO_INTERNAL_LINK) {
- continue;
- }
- output->link = link; /* not really used, just for tagging handled sockets */
-
- /* look for suitable input */
- input = select_internal_link_input(node, output);
-
- if (input) {
- bNodeLink *ilink = MEM_callocN(sizeof(bNodeLink), "internal node link");
- ilink->fromnode = node;
- ilink->fromsock = input;
- ilink->tonode = node;
- ilink->tosock = output;
- /* internal link is always valid */
- ilink->flag |= NODE_LINK_VALID;
- BLI_addtail(&node->internal_links, ilink);
- }
- }
-
- /* clean up */
- for (output = node->outputs.first; output; output = output->next) {
- output->link = NULL;
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Default value RNA access
* \{ */
diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h
index 9cbb21e02f7..d7da2303088 100644
--- a/source/blender/nodes/intern/node_util.h
+++ b/source/blender/nodes/intern/node_util.h
@@ -23,20 +23,6 @@
#pragma once
-#include "DNA_listBase.h"
-
-#include "BLI_utildefines.h"
-
-#include "BKE_node.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "NOD_socket.h"
-
-#include "GPU_material.h" /* For Shader muting GPU code... */
-
-#include "RNA_access.h"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -56,18 +42,18 @@ typedef struct bNodeExecData {
/**** Storage Data ****/
-extern void node_free_curves(struct bNode *node);
-extern void node_free_standard_storage(struct bNode *node);
+void node_free_curves(struct bNode *node);
+void node_free_standard_storage(struct bNode *node);
-extern void node_copy_curves(struct bNodeTree *dest_ntree,
- struct bNode *dest_node,
- const struct bNode *src_node);
-extern void node_copy_standard_storage(struct bNodeTree *dest_ntree,
- struct bNode *dest_node,
- const struct bNode *src_node);
-extern void *node_initexec_curves(struct bNodeExecContext *context,
- struct bNode *node,
- bNodeInstanceKey key);
+void node_copy_curves(struct bNodeTree *dest_ntree,
+ struct bNode *dest_node,
+ const struct bNode *src_node);
+void node_copy_standard_storage(struct bNodeTree *dest_ntree,
+ struct bNode *dest_node,
+ const struct bNode *src_node);
+void *node_initexec_curves(struct bNodeExecContext *context,
+ struct bNode *node,
+ bNodeInstanceKey key);
/**** Updates ****/
void node_sock_label(struct bNodeSocket *sock, const char *name);
@@ -75,15 +61,35 @@ void node_sock_label_clear(struct bNodeSocket *sock);
void node_math_update(struct bNodeTree *ntree, struct bNode *node);
/**** Labels ****/
-void node_blend_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
-void node_image_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
-void node_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
-void node_vector_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
-void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
+void node_blend_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
+void node_image_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
+void node_math_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
+void node_vector_math_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
+void node_filter_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
/*** Link Handling */
+
+/**
+ * The idea behind this is: When a user connects an input to a socket that is
+ * already linked (and if its not an Multi Input Socket), we try to find a replacement socket for
+ * the link that we try to overwrite and connect that previous link to the new socket.
+ */
void node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
-void node_update_internal_links_default(struct bNodeTree *ntree, struct bNode *node);
float node_socket_get_float(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock);
void node_socket_set_float(struct bNodeTree *ntree,
diff --git a/source/blender/nodes/intern/socket_search_link.cc b/source/blender/nodes/intern/socket_search_link.cc
new file mode 100644
index 00000000000..8543efe7f9b
--- /dev/null
+++ b/source/blender/nodes/intern/socket_search_link.cc
@@ -0,0 +1,199 @@
+/*
+ * 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 "BLI_set.hh"
+
+#include "BKE_node.h"
+
+#include "UI_interface.h"
+
+#include "NOD_node_declaration.hh"
+#include "NOD_socket_search_link.hh"
+
+namespace blender::nodes {
+
+void GatherLinkSearchOpParams::add_item(std::string socket_name,
+ SocketLinkOperation::LinkSocketFn fn,
+ const int weight)
+{
+
+ std::string name = std::string(node_type_.ui_name) + " " + UI_MENU_ARROW_SEP + socket_name;
+
+ items_.append({std::move(name), std::move(fn), weight});
+}
+
+const bNodeSocket &GatherLinkSearchOpParams::other_socket() const
+{
+ return other_socket_;
+}
+
+const bNodeTree &GatherLinkSearchOpParams::node_tree() const
+{
+ return node_tree_;
+}
+
+const bNodeType &GatherLinkSearchOpParams::node_type() const
+{
+ return node_type_;
+}
+
+eNodeSocketInOut GatherLinkSearchOpParams::in_out() const
+{
+ return other_socket_.in_out == SOCK_IN ? SOCK_OUT : SOCK_IN;
+}
+
+void LinkSearchOpParams::connect_available_socket(bNode &new_node, StringRef socket_name)
+{
+ const eNodeSocketInOut in_out = socket.in_out == SOCK_IN ? SOCK_OUT : SOCK_IN;
+ bNodeSocket *new_node_socket = bke::node_find_enabled_socket(new_node, in_out, socket_name);
+ if (new_node_socket == nullptr) {
+ /* If the socket isn't found, some node's search gather functions probably aren't configured
+ * properly. It's likely enough that it's worth avoiding a crash in a release build though. */
+ BLI_assert_unreachable();
+ return;
+ }
+ nodeAddLink(&node_tree, &new_node, new_node_socket, &node, &socket);
+}
+
+bNode &LinkSearchOpParams::add_node(StringRef idname)
+{
+ std::string idname_str = idname;
+ bNode *node = nodeAddNode(&C, &node_tree, idname_str.c_str());
+ BLI_assert(node != nullptr);
+ added_nodes_.append(node);
+ return *node;
+}
+
+bNode &LinkSearchOpParams::add_node(const bNodeType &node_type)
+{
+ return this->add_node(node_type.idname);
+}
+
+void LinkSearchOpParams::update_and_connect_available_socket(bNode &new_node,
+ StringRef socket_name)
+{
+ if (new_node.typeinfo->updatefunc) {
+ new_node.typeinfo->updatefunc(&node_tree, &new_node);
+ }
+ this->connect_available_socket(new_node, socket_name);
+}
+
+void search_link_ops_for_declarations(GatherLinkSearchOpParams &params,
+ Span<SocketDeclarationPtr> declarations)
+{
+ const bNodeType &node_type = params.node_type();
+
+ const SocketDeclaration *main_socket = nullptr;
+ Vector<const SocketDeclaration *> connectable_sockets;
+
+ Set<StringRef> socket_names;
+ for (const int i : declarations.index_range()) {
+ const SocketDeclaration &socket = *declarations[i];
+ if (!socket_names.add(socket.name())) {
+ /* Don't add sockets with the same name to the search. Needed to support being called from
+ * #search_link_ops_for_basic_node, which should have "okay" behavior for nodes with
+ * duplicate socket names. */
+ continue;
+ }
+ if (!socket.can_connect(params.other_socket())) {
+ continue;
+ }
+ if (socket.is_default_link_socket() || main_socket == nullptr) {
+ /* Either the first connectable or explicitly tagged socket is the main socket. */
+ main_socket = &socket;
+ }
+ connectable_sockets.append(&socket);
+ }
+ for (const int i : connectable_sockets.index_range()) {
+ const SocketDeclaration &socket = *connectable_sockets[i];
+ /* Give non-main sockets a lower weight so that they don't show up at the top of the search
+ * when they are not explicitly searched for. The -1 is used to make sure that the first socket
+ * has a smaller weight than zero so that it does not have the same weight as the main socket.
+ * Negative weights are used to avoid making the highest weight dependent on the number of
+ * sockets. */
+ const int weight = (&socket == main_socket) ? 0 : -1 - i;
+ params.add_item(
+ socket.name(),
+ [&node_type, &socket](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ socket.make_available(node);
+ params.update_and_connect_available_socket(node, socket.name());
+ },
+ weight);
+ }
+}
+
+static void search_link_ops_for_socket_templates(GatherLinkSearchOpParams &params,
+ const bNodeSocketTemplate *templates,
+ const eNodeSocketInOut in_out)
+{
+ const bNodeType &node_type = params.node_type();
+ const bNodeTreeType &node_tree_type = *params.node_tree().typeinfo;
+
+ Set<StringRef> socket_names;
+ for (const bNodeSocketTemplate *socket_template = templates; socket_template->type != -1;
+ socket_template++) {
+ eNodeSocketDatatype from = (eNodeSocketDatatype)socket_template->type;
+ eNodeSocketDatatype to = (eNodeSocketDatatype)params.other_socket().type;
+ if (in_out == SOCK_IN) {
+ std::swap(from, to);
+ }
+ if (node_tree_type.validate_link && !node_tree_type.validate_link(from, to)) {
+ continue;
+ }
+ if (!socket_names.add(socket_template->name)) {
+ /* See comment in #search_link_ops_for_declarations. */
+ continue;
+ }
+
+ params.add_item(
+ socket_template->name, [socket_template, node_type, in_out](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ bNodeSocket *new_node_socket = bke::node_find_enabled_socket(
+ node, in_out, socket_template->name);
+ if (new_node_socket != nullptr) {
+ /* Rely on the way #nodeAddLink switches in/out if necessary. */
+ nodeAddLink(&params.node_tree, &params.node, &params.socket, &node, new_node_socket);
+ }
+ });
+ }
+}
+
+void search_link_ops_for_basic_node(GatherLinkSearchOpParams &params)
+{
+ const bNodeType &node_type = params.node_type();
+
+ if (node_type.declare) {
+ if (node_type.declaration_is_dynamic) {
+ /* Dynamic declarations (whatever they end up being) aren't supported
+ * by this function, but still avoid a crash in release builds. */
+ BLI_assert_unreachable();
+ return;
+ }
+
+ const NodeDeclaration &declaration = *node_type.fixed_declaration;
+
+ search_link_ops_for_declarations(params, declaration.sockets(params.in_out()));
+ }
+ else if (node_type.inputs && params.in_out() == SOCK_IN) {
+ search_link_ops_for_socket_templates(params, node_type.inputs, SOCK_IN);
+ }
+ else if (node_type.outputs && params.in_out() == SOCK_OUT) {
+ search_link_ops_for_socket_templates(params, node_type.outputs, SOCK_OUT);
+ }
+}
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt
new file mode 100644
index 00000000000..c8eb0b8d570
--- /dev/null
+++ b/source/blender/nodes/shader/CMakeLists.txt
@@ -0,0 +1,174 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2021, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ..
+ ../intern
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../depsgraph
+ ../../editors/include
+ ../../functions
+ ../../gpu
+ ../../imbuf
+ ../../makesdna
+ ../../makesrna
+ ../../render
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+ ../../../../intern/sky/include
+)
+
+
+set(SRC
+ nodes/node_shader_add_shader.cc
+ nodes/node_shader_ambient_occlusion.cc
+ nodes/node_shader_attribute.cc
+ nodes/node_shader_background.cc
+ nodes/node_shader_bevel.cc
+ nodes/node_shader_blackbody.cc
+ nodes/node_shader_brightness.cc
+ nodes/node_shader_bsdf_anisotropic.cc
+ nodes/node_shader_bsdf_diffuse.cc
+ nodes/node_shader_bsdf_glass.cc
+ nodes/node_shader_bsdf_glossy.cc
+ nodes/node_shader_bsdf_hair.cc
+ nodes/node_shader_bsdf_hair_principled.cc
+ nodes/node_shader_bsdf_principled.cc
+ nodes/node_shader_bsdf_refraction.cc
+ nodes/node_shader_bsdf_toon.cc
+ nodes/node_shader_bsdf_translucent.cc
+ nodes/node_shader_bsdf_transparent.cc
+ nodes/node_shader_bsdf_velvet.cc
+ nodes/node_shader_bump.cc
+ nodes/node_shader_camera.cc
+ nodes/node_shader_clamp.cc
+ nodes/node_shader_color_ramp.cc
+ nodes/node_shader_common.cc
+ nodes/node_shader_curves.cc
+ nodes/node_shader_displacement.cc
+ nodes/node_shader_eevee_specular.cc
+ nodes/node_shader_emission.cc
+ nodes/node_shader_fresnel.cc
+ nodes/node_shader_gamma.cc
+ nodes/node_shader_geometry.cc
+ nodes/node_shader_hair_info.cc
+ nodes/node_shader_holdout.cc
+ nodes/node_shader_hueSatVal.cc
+ nodes/node_shader_ies_light.cc
+ nodes/node_shader_invert.cc
+ nodes/node_shader_layer_weight.cc
+ nodes/node_shader_light_falloff.cc
+ nodes/node_shader_light_path.cc
+ nodes/node_shader_map_range.cc
+ nodes/node_shader_mapping.cc
+ nodes/node_shader_math.cc
+ nodes/node_shader_mix_rgb.cc
+ nodes/node_shader_mix_shader.cc
+ nodes/node_shader_normal.cc
+ nodes/node_shader_normal_map.cc
+ nodes/node_shader_object_info.cc
+ nodes/node_shader_output_aov.cc
+ nodes/node_shader_output_light.cc
+ nodes/node_shader_output_linestyle.cc
+ nodes/node_shader_output_material.cc
+ nodes/node_shader_output_world.cc
+ nodes/node_shader_particle_info.cc
+ nodes/node_shader_point_info.cc
+ nodes/node_shader_rgb.cc
+ nodes/node_shader_rgb_to_bw.cc
+ nodes/node_shader_script.cc
+ nodes/node_shader_sepcomb_hsv.cc
+ nodes/node_shader_sepcomb_rgb.cc
+ nodes/node_shader_sepcomb_xyz.cc
+ nodes/node_shader_shader_to_rgb.cc
+ nodes/node_shader_squeeze.cc
+ nodes/node_shader_subsurface_scattering.cc
+ nodes/node_shader_tangent.cc
+ nodes/node_shader_tex_brick.cc
+ nodes/node_shader_tex_checker.cc
+ nodes/node_shader_tex_coord.cc
+ nodes/node_shader_tex_environment.cc
+ nodes/node_shader_tex_gradient.cc
+ nodes/node_shader_tex_image.cc
+ nodes/node_shader_tex_magic.cc
+ nodes/node_shader_tex_musgrave.cc
+ nodes/node_shader_tex_noise.cc
+ nodes/node_shader_tex_pointdensity.cc
+ nodes/node_shader_tex_sky.cc
+ nodes/node_shader_tex_voronoi.cc
+ nodes/node_shader_tex_wave.cc
+ nodes/node_shader_tex_white_noise.cc
+ nodes/node_shader_uv_along_stroke.cc
+ nodes/node_shader_uvmap.cc
+ nodes/node_shader_value.cc
+ nodes/node_shader_vector_displacement.cc
+ nodes/node_shader_vector_math.cc
+ nodes/node_shader_vector_rotate.cc
+ nodes/node_shader_vector_transform.cc
+ nodes/node_shader_vertex_color.cc
+ nodes/node_shader_volume_absorption.cc
+ nodes/node_shader_volume_info.cc
+ nodes/node_shader_volume_principled.cc
+ nodes/node_shader_volume_scatter.cc
+ nodes/node_shader_wavelength.cc
+ nodes/node_shader_wireframe.cc
+
+ node_shader_tree.cc
+ node_shader_util.cc
+
+ node_shader_util.hh
+)
+
+set(LIB
+ bf_functions
+ bf_intern_sky
+)
+
+if(WITH_PYTHON)
+ list(APPEND INC
+ ../../python
+ )
+ list(APPEND INC_SYS
+ ${PYTHON_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ ${PYTHON_LINKFLAGS}
+ ${PYTHON_LIBRARIES}
+ )
+ add_definitions(-DWITH_PYTHON)
+endif()
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
+blender_add_lib(bf_nodes_shader "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_UNITY_BUILD)
+ set_target_properties(bf_nodes_shader PROPERTIES UNITY_BUILD ON)
+ set_target_properties(bf_nodes_shader PROPERTIES UNITY_BUILD_BATCH_SIZE 10)
+endif()
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.cc
index 46a2f7f1968..1cb1ee3163d 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.cc
@@ -21,7 +21,7 @@
* \ingroup nodes
*/
-#include <string.h>
+#include <cstring>
#include "DNA_light_types.h"
#include "DNA_linestyle_types.h"
@@ -44,6 +44,7 @@
#include "BKE_lib_id.h"
#include "BKE_linestyle.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_scene.h"
#include "RNA_access.h"
@@ -52,11 +53,13 @@
#include "RE_texture.h"
+#include "UI_resources.h"
+
#include "NOD_common.h"
#include "node_common.h"
#include "node_exec.h"
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
#include "node_util.h"
static bool shader_tree_poll(const bContext *C, bNodeTreeType *UNUSED(treetype))
@@ -85,7 +88,7 @@ static void shader_get_from_context(const bContext *C,
if (ob) {
*r_from = &ob->id;
if (ob->type == OB_LAMP) {
- *r_id = ob->data;
+ *r_id = static_cast<ID *>(ob->data);
*r_ntree = ((Light *)ob->data)->nodetree;
}
else {
@@ -101,7 +104,7 @@ static void shader_get_from_context(const bContext *C,
else if (snode->shaderfrom == SNODE_SHADER_LINESTYLE) {
FreestyleLineStyle *linestyle = BKE_linestyle_active_from_view_layer(view_layer);
if (linestyle) {
- *r_from = NULL;
+ *r_from = nullptr;
*r_id = &linestyle->id;
*r_ntree = linestyle->nodetree;
}
@@ -109,7 +112,7 @@ static void shader_get_from_context(const bContext *C,
#endif
else { /* SNODE_SHADER_WORLD */
if (scene->world) {
- *r_from = NULL;
+ *r_from = nullptr;
*r_id = &scene->world->id;
*r_ntree = scene->world->nodetree;
}
@@ -133,12 +136,8 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa
static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree))
{
- bNode *node, *node_next;
-
/* replace muted nodes and reroute nodes by internal links */
- for (node = localtree->nodes.first; node; node = node_next) {
- node_next = node->next;
-
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &localtree->nodes) {
if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) {
nodeInternalRelink(localtree, node);
ntreeFreeLocalNode(localtree, node);
@@ -146,34 +145,19 @@ static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree))
}
}
-static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_sync_tree(ntree, localtree);
-}
-
-static void local_merge(Main *UNUSED(bmain), bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_merge_tree(ntree, localtree, true);
-}
-
static void update(bNodeTree *ntree)
{
ntreeSetOutput(ntree);
ntree_update_reroute_nodes(ntree);
-
- if (ntree->update & NTREE_UPDATE_NODES) {
- /* clean up preview cache, in case nodes have been removed */
- BKE_node_preview_remove_unused(ntree);
- }
}
-static bool shader_validate_link(bNodeTree *UNUSED(ntree), bNodeLink *link)
+static bool shader_validate_link(eNodeSocketDatatype from, eNodeSocketDatatype to)
{
/* Can't connect shader into other socket types, other way around is fine
* since it will be interpreted as emission. */
- if (link->fromsock->type == SOCK_SHADER) {
- return (link->tosock->type == SOCK_SHADER);
+ if (from == SOCK_SHADER) {
+ return to == SOCK_SHADER;
}
return true;
}
@@ -187,21 +171,18 @@ static bool shader_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
bNodeTreeType *ntreeType_Shader;
-void register_node_tree_type_sh(void)
+void register_node_tree_type_sh()
{
- bNodeTreeType *tt = ntreeType_Shader = MEM_callocN(sizeof(bNodeTreeType),
- "shader node tree type");
+ bNodeTreeType *tt = ntreeType_Shader = MEM_cnew<bNodeTreeType>("shader node tree type");
tt->type = NTREE_SHADER;
strcpy(tt->idname, "ShaderNodeTree");
strcpy(tt->ui_name, N_("Shader Editor"));
- tt->ui_icon = 0; /* defined in drawnode.c */
+ tt->ui_icon = ICON_NODE_MATERIAL;
strcpy(tt->ui_description, N_("Shader nodes"));
tt->foreach_nodeclass = foreach_nodeclass;
tt->localize = localize;
- tt->local_sync = local_sync;
- tt->local_merge = local_merge;
tt->update = update;
tt->poll = shader_tree_poll;
tt->get_from_context = shader_get_from_context;
@@ -215,13 +196,6 @@ void register_node_tree_type_sh(void)
/* GPU material from shader nodes */
-/* Find an output node of the shader tree.
- *
- * NOTE: it will only return output which is NOT in the group, which isn't how
- * render engines works but it's how the GPU shader compilation works. This we
- * can change in the future and make it a generic function, but for now it stays
- * private here.
- */
bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
{
/* Make sure we only have single node tagged as output. */
@@ -229,7 +203,7 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
/* Find output node that matches type and target. If there are
* multiple, we prefer exact target match and active nodes. */
- bNode *output_node = NULL;
+ bNode *output_node = nullptr;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (!ELEM(node->type, SH_NODE_OUTPUT_MATERIAL, SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LIGHT)) {
@@ -237,7 +211,7 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
}
if (node->custom1 == SHD_OUTPUT_ALL) {
- if (output_node == NULL) {
+ if (output_node == nullptr) {
output_node = node;
}
else if (output_node->custom1 == SHD_OUTPUT_ALL) {
@@ -247,7 +221,7 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
}
}
else if (node->custom1 == target) {
- if (output_node == NULL) {
+ if (output_node == nullptr) {
output_node = node;
}
else if (output_node->custom1 == SHD_OUTPUT_ALL) {
@@ -265,12 +239,12 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
/* Find socket with a specified identifier. */
static bNodeSocket *ntree_shader_node_find_socket(ListBase *sockets, const char *identifier)
{
- for (bNodeSocket *sock = sockets->first; sock != NULL; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
if (STREQ(sock->identifier, identifier)) {
return sock;
}
}
- return NULL;
+ return nullptr;
}
/* Find input socket with a specified identifier. */
@@ -311,37 +285,37 @@ static bool ntree_shader_expand_socket_default(bNodeTree *localtree,
switch (socket->type) {
case SOCK_VECTOR:
- value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_RGB);
+ value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_RGB);
value_socket = ntree_shader_node_find_output(value_node, "Color");
- BLI_assert(value_socket != NULL);
- src_vector = socket->default_value;
- dst_rgba = value_socket->default_value;
+ BLI_assert(value_socket != nullptr);
+ src_vector = static_cast<bNodeSocketValueVector *>(socket->default_value);
+ dst_rgba = static_cast<bNodeSocketValueRGBA *>(value_socket->default_value);
copy_v3_v3(dst_rgba->value, src_vector->value);
dst_rgba->value[3] = 1.0f; /* should never be read */
break;
case SOCK_RGBA:
- value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_RGB);
+ value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_RGB);
value_socket = ntree_shader_node_find_output(value_node, "Color");
- BLI_assert(value_socket != NULL);
- src_rgba = socket->default_value;
- dst_rgba = value_socket->default_value;
+ BLI_assert(value_socket != nullptr);
+ src_rgba = static_cast<bNodeSocketValueRGBA *>(socket->default_value);
+ dst_rgba = static_cast<bNodeSocketValueRGBA *>(value_socket->default_value);
copy_v4_v4(dst_rgba->value, src_rgba->value);
break;
case SOCK_INT:
/* HACK: Support as float. */
- value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_VALUE);
+ value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_VALUE);
value_socket = ntree_shader_node_find_output(value_node, "Value");
- BLI_assert(value_socket != NULL);
- src_int = socket->default_value;
- dst_float = value_socket->default_value;
+ BLI_assert(value_socket != nullptr);
+ src_int = static_cast<bNodeSocketValueInt *>(socket->default_value);
+ dst_float = static_cast<bNodeSocketValueFloat *>(value_socket->default_value);
dst_float->value = (float)(src_int->value);
break;
case SOCK_FLOAT:
- value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_VALUE);
+ value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_VALUE);
value_socket = ntree_shader_node_find_output(value_node, "Value");
- BLI_assert(value_socket != NULL);
- src_float = socket->default_value;
- dst_float = value_socket->default_value;
+ BLI_assert(value_socket != nullptr);
+ src_float = static_cast<bNodeSocketValueFloat *>(socket->default_value);
+ dst_float = static_cast<bNodeSocketValueFloat *>(value_socket->default_value);
dst_float->value = src_float->value;
break;
default:
@@ -354,11 +328,10 @@ static bool ntree_shader_expand_socket_default(bNodeTree *localtree,
static void ntree_shader_unlink_hidden_value_sockets(bNode *group_node, bNodeSocket *isock)
{
bNodeTree *group_ntree = (bNodeTree *)group_node->id;
- bNode *node;
bool removed_link = false;
- for (node = group_ntree->nodes.first; node; node = node->next) {
- const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != NULL);
+ LISTBASE_FOREACH (bNode *, node, &group_ntree->nodes) {
+ const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != nullptr);
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (!is_group && (sock->flag & SOCK_HIDE_VALUE) == 0) {
@@ -381,7 +354,7 @@ static void ntree_shader_unlink_hidden_value_sockets(bNode *group_node, bNodeSoc
}
if (removed_link) {
- ntreeUpdateTree(G.main, group_ntree);
+ BKE_ntree_update_main_tree(G.main, group_ntree, nullptr);
}
}
@@ -392,7 +365,7 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
bool link_added = false;
LISTBASE_FOREACH (bNode *, node, &localtree->nodes) {
- const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != NULL);
+ const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != nullptr);
const bool is_group_output = node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT);
if (is_group) {
@@ -402,25 +375,32 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
if (is_group || is_group_output) {
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- if (socket->link != NULL && !(socket->link->flag & NODE_LINK_MUTED)) {
+ if (socket->link != nullptr && !(socket->link->flag & NODE_LINK_MUTED)) {
bNodeLink *link = socket->link;
/* Fix the case where the socket is actually converting the data. (see T71374)
* We only do the case of lossy conversion to float. */
if ((socket->type == SOCK_FLOAT) && (link->fromsock->type != link->tosock->type)) {
if (link->fromsock->type == SOCK_RGBA) {
- bNode *tmp = nodeAddStaticNode(NULL, localtree, SH_NODE_RGBTOBW);
- nodeAddLink(localtree, link->fromnode, link->fromsock, tmp, tmp->inputs.first);
- nodeAddLink(localtree, tmp, tmp->outputs.first, node, socket);
+ bNode *tmp = nodeAddStaticNode(nullptr, localtree, SH_NODE_RGBTOBW);
+ nodeAddLink(localtree,
+ link->fromnode,
+ link->fromsock,
+ tmp,
+ static_cast<bNodeSocket *>(tmp->inputs.first));
+ nodeAddLink(
+ localtree, tmp, static_cast<bNodeSocket *>(tmp->outputs.first), node, socket);
}
else if (link->fromsock->type == SOCK_VECTOR) {
- bNode *tmp = nodeAddStaticNode(NULL, localtree, SH_NODE_VECTOR_MATH);
+ bNode *tmp = nodeAddStaticNode(nullptr, localtree, SH_NODE_VECTOR_MATH);
tmp->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT;
- bNodeSocket *dot_input1 = tmp->inputs.first;
- bNodeSocket *dot_input2 = dot_input1->next;
- bNodeSocketValueVector *input2_socket_value = dot_input2->default_value;
+ bNodeSocket *dot_input1 = static_cast<bNodeSocket *>(tmp->inputs.first);
+ bNodeSocket *dot_input2 = static_cast<bNodeSocket *>(dot_input1->next);
+ bNodeSocketValueVector *input2_socket_value = static_cast<bNodeSocketValueVector *>(
+ dot_input2->default_value);
copy_v3_fl(input2_socket_value->value, 1.0f / 3.0f);
nodeAddLink(localtree, link->fromnode, link->fromsock, tmp, dot_input1);
- nodeAddLink(localtree, tmp, tmp->outputs.last, node, socket);
+ nodeAddLink(
+ localtree, tmp, static_cast<bNodeSocket *>(tmp->outputs.last), node, socket);
}
}
continue;
@@ -440,22 +420,33 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
}
if (link_added) {
- ntreeUpdateTree(G.main, localtree);
+ BKE_ntree_update_main_tree(G.main, localtree, nullptr);
}
}
-static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
+static void ntree_shader_groups_remove_muted_links(bNodeTree *ntree)
{
- bNodeLink *link, *linkn, *tlink;
- bNode *node, *nextnode;
- bNodeTree *ngroup;
- LinkNode *group_interface_nodes = NULL;
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == NODE_GROUP) {
+ if (node->id != nullptr) {
+ ntree_shader_groups_remove_muted_links(reinterpret_cast<bNodeTree *>(node->id));
+ }
+ }
+ }
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if (link->flag & NODE_LINK_MUTED) {
+ nodeRemLink(ntree, link);
+ }
+ }
+}
- ngroup = (bNodeTree *)gnode->id;
+static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
+{
+ LinkNode *group_interface_nodes = nullptr;
+ bNodeTree *ngroup = (bNodeTree *)gnode->id;
/* Add the nodes into the ntree */
- for (node = ngroup->nodes.first; node; node = nextnode) {
- nextnode = node->next;
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup->nodes) {
/* Remove interface nodes.
* This also removes remaining links to and from interface nodes.
* We must delay removal since sockets will reference this node. see: T52092 */
@@ -471,25 +462,26 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
}
/* Save first and last link to iterate over flattened group links. */
- bNodeLink *glinks_first = ntree->links.last;
+ bNodeLink *glinks_first = static_cast<bNodeLink *>(ntree->links.last);
/* Add internal links to the ntree */
- for (link = ngroup->links.first; link; link = linkn) {
- linkn = link->next;
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ngroup->links) {
BLI_remlink(&ngroup->links, link);
BLI_addtail(&ntree->links, link);
}
- bNodeLink *glinks_last = ntree->links.last;
+ bNodeLink *glinks_last = static_cast<bNodeLink *>(ntree->links.last);
/* restore external links to and from the gnode */
- if (glinks_first != NULL) {
+ if (glinks_first != nullptr) {
/* input links */
- for (link = glinks_first->next; link != glinks_last->next; link = link->next) {
+ for (bNodeLink *link = glinks_first->next; link != glinks_last->next; link = link->next) {
if (link->fromnode->type == NODE_GROUP_INPUT) {
const char *identifier = link->fromsock->identifier;
/* find external links to this input */
- for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) {
+ for (bNodeLink *tlink = static_cast<bNodeLink *>(ntree->links.first);
+ tlink != glinks_first->next;
+ tlink = tlink->next) {
if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) {
nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock);
}
@@ -497,13 +489,15 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
}
}
/* Also iterate over the new links to cover passthrough links. */
- glinks_last = ntree->links.last;
+ glinks_last = static_cast<bNodeLink *>(ntree->links.last);
/* output links */
- for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) {
+ for (bNodeLink *tlink = static_cast<bNodeLink *>(ntree->links.first);
+ tlink != glinks_first->next;
+ tlink = tlink->next) {
if (tlink->fromnode == gnode) {
const char *identifier = tlink->fromsock->identifier;
/* find internal links to this output */
- for (link = glinks_first->next; link != glinks_last->next; link = link->next) {
+ for (bNodeLink *link = glinks_first->next; link != glinks_last->next; link = link->next) {
/* only use active output node */
if (link->tonode->type == NODE_GROUP_OUTPUT && (link->tonode->flag & NODE_DO_OUTPUT)) {
if (STREQ(link->tosock->identifier, identifier)) {
@@ -516,11 +510,11 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
}
while (group_interface_nodes) {
- node = BLI_linklist_pop(&group_interface_nodes);
+ bNode *node = static_cast<bNode *>(BLI_linklist_pop(&group_interface_nodes));
ntreeFreeLocalNode(ntree, node);
}
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_all(ntree);
}
/* Flatten group to only have a simple single tree */
@@ -528,8 +522,9 @@ static void ntree_shader_groups_flatten(bNodeTree *localtree)
{
/* This is effectively recursive as the flattened groups will add
* nodes at the end of the list, which will also get evaluated. */
- for (bNode *node = localtree->nodes.first, *node_next; node; node = node_next) {
- if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != NULL) {
+ for (bNode *node = static_cast<bNode *>(localtree->nodes.first), *node_next; node;
+ node = node_next) {
+ if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != nullptr) {
flatten_group_do(localtree, node);
/* Continue even on new flattened nodes. */
node_next = node->next;
@@ -545,7 +540,7 @@ static void ntree_shader_groups_flatten(bNodeTree *localtree)
}
}
- ntreeUpdateTree(G.main, localtree);
+ BKE_ntree_update_main_tree(G.main, localtree, nullptr);
}
/* Check whether shader has a displacement.
@@ -560,20 +555,20 @@ static bool ntree_shader_has_displacement(bNodeTree *ntree,
bNodeSocket **r_socket,
bNodeLink **r_link)
{
- if (output_node == NULL) {
+ if (output_node == nullptr) {
/* We can't have displacement without output node, apparently. */
return false;
}
/* Make sure sockets links pointers are correct. */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
bNodeSocket *displacement = ntree_shader_node_find_input(output_node, "Displacement");
- if (displacement == NULL) {
+ if (displacement == nullptr) {
/* Non-cycles node is used as an output. */
return false;
}
- if ((displacement->link != NULL) && !(displacement->link->flag & NODE_LINK_MUTED)) {
+ if ((displacement->link != nullptr) && !(displacement->link->flag & NODE_LINK_MUTED)) {
*r_node = displacement->link->fromnode;
*r_socket = displacement->link->fromsock;
*r_link = displacement->link;
@@ -591,7 +586,7 @@ static void ntree_shader_relink_node_normal(bNodeTree *ntree,
* matching?
*/
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- if (STREQ(sock->identifier, "Normal") && sock->link == NULL) {
+ if (STREQ(sock->identifier, "Normal") && sock->link == nullptr) {
/* It's a normal input and nothing is connected to it. */
nodeAddLink(ntree, node_from, socket_from, node, sock);
}
@@ -611,7 +606,7 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
bNode *node_from,
bNodeSocket *socket_from)
{
- for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node == node_from) {
/* Don't connect node itself! */
continue;
@@ -636,7 +631,7 @@ static void ntree_shader_bypass_bump_link(bNodeTree *ntree, bNode *bump_node, bN
fromnode = bump_normal_input->link->fromnode;
}
else {
- fromnode = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY);
+ fromnode = nodeAddStaticNode(nullptr, ntree, SH_NODE_NEW_GEOMETRY);
fromsock = ntree_shader_node_find_output(fromnode, "Normal");
}
/* Bypass the bump node by creating a link between the previous and next node. */
@@ -654,7 +649,7 @@ static void ntree_shader_bypass_tagged_bump_nodes(bNodeTree *ntree)
ntree_shader_bypass_bump_link(ntree, node, link);
}
}
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
}
static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, bNode *tonode, void *userdata)
@@ -688,19 +683,19 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
int node_count = 1;
nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count, 1);
/* Make a full copy of the branch */
- bNode **nodes_copy = MEM_mallocN(sizeof(bNode *) * node_count, __func__);
+ bNode **nodes_copy = static_cast<bNode **>(MEM_mallocN(sizeof(bNode *) * node_count, __func__));
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->tmp_flag >= 0) {
int id = node->tmp_flag;
- nodes_copy[id] = BKE_node_copy_ex(
- ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN, false);
+ nodes_copy[id] = blender::bke::node_copy(
+ ntree, *node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN, false);
nodes_copy[id]->tmp_flag = -2; /* Copy */
/* Make sure to clear all sockets links as they are invalid. */
LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->inputs) {
- sock->link = NULL;
+ sock->link = nullptr;
}
LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->outputs) {
- sock->link = NULL;
+ sock->link = nullptr;
}
}
}
@@ -733,13 +728,13 @@ static void ntree_shader_copy_branch_displacement(bNodeTree *ntree,
/* Replace displacement socket/node/link. */
bNode *tonode = displacement_link->tonode;
bNodeSocket *tosock = displacement_link->tosock;
- displacement_node = ntree_shader_copy_branch(ntree, displacement_node, NULL, 0);
+ displacement_node = ntree_shader_copy_branch(ntree, displacement_node, nullptr, 0);
displacement_socket = ntree_shader_node_find_output(displacement_node,
displacement_socket->identifier);
nodeRemLink(ntree, displacement_link);
nodeAddLink(ntree, displacement_node, displacement_socket, tonode, tosock);
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
}
/* Re-link displacement output to unconnected normal sockets via bump node.
@@ -773,11 +768,11 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
nodeRemLink(ntree, displacement_link);
/* Convert displacement vector to bump height. */
- bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
- bNode *geo_node = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY);
+ bNode *dot_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_VECTOR_MATH);
+ bNode *geo_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_NEW_GEOMETRY);
bNodeSocket *normal_socket = ntree_shader_node_find_output(geo_node, "Normal");
- bNodeSocket *dot_input1 = dot_node->inputs.first;
- bNodeSocket *dot_input2 = dot_input1->next;
+ bNodeSocket *dot_input1 = static_cast<bNodeSocket *>(dot_node->inputs.first);
+ bNodeSocket *dot_input2 = static_cast<bNodeSocket *>(dot_input1->next);
dot_node->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT;
nodeAddLink(ntree, displacement_node, displacement_socket, dot_node, dot_input1);
@@ -788,11 +783,11 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
/* We can't connect displacement to normal directly, use bump node for that
* and hope that it gives good enough approximation.
*/
- bNode *bump_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BUMP);
+ bNode *bump_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_BUMP);
bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height");
bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal");
- BLI_assert(bump_input_socket != NULL);
- BLI_assert(bump_output_socket != NULL);
+ BLI_assert(bump_input_socket != nullptr);
+ BLI_assert(bump_output_socket != nullptr);
/* Connect bump node to where displacement output was originally
* connected to.
*/
@@ -803,12 +798,12 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
geo_node->tmp_flag = -2;
bump_node->tmp_flag = -2;
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
/* Connect all free-standing Normal inputs and relink geometry/coordinate nodes. */
ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket);
/* We modified the tree, it needs to be updated now. */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
}
static void node_tag_branch_as_derivative(bNode *node, int dx)
@@ -868,12 +863,12 @@ static bool ntree_shader_implicit_closure_cast(bNodeTree *ntree)
else if ((link->fromsock->type == SOCK_SHADER) && (link->tosock->type != SOCK_SHADER)) {
/* Meh. Not directly visible to the user. But better than nothing. */
fprintf(stderr, "Shader Nodetree Error: Invalid implicit socket conversion\n");
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
return false;
}
}
if (modified) {
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
}
return true;
}
@@ -1129,7 +1124,8 @@ static void ntree_shader_weight_tree_invert(bNodeTree *ntree, bNode *output_node
break;
}
- /* Manually add the link to the socket to avoid calling ntreeUpdateTree in the loop. */
+ /* Manually add the link to the socket to avoid calling
+ * BKE_ntree_update_main_tree(G.main, oop, nullptr. */
fromsock->link = nodeAddLink(ntree, fromnode, fromsock, tonode, tosock);
BLI_assert(fromsock->link);
}
@@ -1145,23 +1141,23 @@ static void ntree_shader_weight_tree_invert(bNodeTree *ntree, bNode *output_node
nodeAddLink(
ntree, thickness_link->fromnode, thickness_link->fromsock, output_node, thickness_output);
}
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
MEM_freeN(nodes_copy);
}
-/* This one needs to work on a local tree. */
void ntreeGPUMaterialNodes(bNodeTree *localtree, GPUMaterial *mat)
{
bNodeTreeExec *exec;
bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
+ ntree_shader_groups_remove_muted_links(localtree);
ntree_shader_groups_expand_inputs(localtree);
ntree_shader_groups_flatten(localtree);
- if (output == NULL) {
+ if (output == nullptr) {
/* Search again, now including flattened nodes. */
output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
}
@@ -1186,7 +1182,6 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree, GPUMaterial *mat)
nodeChainIterBackwards(localtree, node, ntree_shader_bump_branches, localtree, 0);
}
}
-
exec = ntreeShaderBeginExecTree(localtree);
ntreeExecGPUNodes(exec, mat, output);
LISTBASE_FOREACH (bNode *, node, &localtree->nodes) {
@@ -1201,19 +1196,17 @@ bNodeTreeExec *ntreeShaderBeginExecTree_internal(bNodeExecContext *context,
bNodeTree *ntree,
bNodeInstanceKey parent_key)
{
- bNodeTreeExec *exec;
- bNode *node;
-
/* ensures only a single output node is enabled */
ntreeSetOutput(ntree);
/* common base initialization */
- exec = ntree_exec_begin(context, ntree, parent_key);
+ bNodeTreeExec *exec = ntree_exec_begin(context, ntree, parent_key);
/* allocate the thread stack listbase array */
- exec->threadstack = MEM_callocN(BLENDER_MAX_THREADS * sizeof(ListBase), "thread stack array");
+ exec->threadstack = static_cast<ListBase *>(
+ MEM_callocN(BLENDER_MAX_THREADS * sizeof(ListBase), "thread stack array"));
- for (node = exec->nodetree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &exec->nodetree->nodes) {
node->need_exec = 1;
}
@@ -1236,8 +1229,8 @@ bNodeTreeExec *ntreeShaderBeginExecTree(bNodeTree *ntree)
exec = ntreeShaderBeginExecTree_internal(&context, ntree, NODE_INSTANCE_KEY_BASE);
- /* XXX this should not be necessary, but is still used for cmp/sha/tex nodes,
- * which only store the ntree pointer. Should be fixed at some point!
+ /* XXX: this should not be necessary, but is still used for compositor/shader/texture nodes,
+ * which only store the `ntree` pointer. Should be fixed at some point!
*/
ntree->execdata = exec;
@@ -1246,12 +1239,9 @@ bNodeTreeExec *ntreeShaderBeginExecTree(bNodeTree *ntree)
void ntreeShaderEndExecTree_internal(bNodeTreeExec *exec)
{
- bNodeThreadStack *nts;
- int a;
-
if (exec->threadstack) {
- for (a = 0; a < BLENDER_MAX_THREADS; a++) {
- for (nts = exec->threadstack[a].first; nts; nts = nts->next) {
+ for (int a = 0; a < BLENDER_MAX_THREADS; a++) {
+ LISTBASE_FOREACH (bNodeThreadStack *, nts, &exec->threadstack[a]) {
if (nts->stack) {
MEM_freeN(nts->stack);
}
@@ -1260,7 +1250,7 @@ void ntreeShaderEndExecTree_internal(bNodeTreeExec *exec)
}
MEM_freeN(exec->threadstack);
- exec->threadstack = NULL;
+ exec->threadstack = nullptr;
}
ntree_exec_end(exec);
@@ -1274,6 +1264,6 @@ void ntreeShaderEndExecTree(bNodeTreeExec *exec)
ntreeShaderEndExecTree_internal(exec);
/* XXX clear nodetree backpointer to exec data, same problem as noted in ntreeBeginExecTree */
- ntree->execdata = NULL;
+ ntree->execdata = nullptr;
}
}
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.cc
index 1804bbcd22a..8ea690a426f 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.cc
@@ -23,14 +23,16 @@
#include "DNA_node_types.h"
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
+
+#include "NOD_socket_search_link.hh"
#include "node_exec.h"
bool sh_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree, const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "ShaderNodeTree")) {
- *r_disabled_hint = "Not a shader node tree";
+ *r_disabled_hint = TIP_("Not a shader node tree");
return false;
}
return true;
@@ -40,32 +42,32 @@ static bool sh_fn_poll_default(bNodeType *UNUSED(ntype),
bNodeTree *ntree,
const char **r_disabled_hint)
{
- if (!STREQ(ntree->idname, "ShaderNodeTree") && !STREQ(ntree->idname, "GeometryNodeTree")) {
- *r_disabled_hint = "Not a shader or geometry node tree";
+ if (!STR_ELEM(ntree->idname, "ShaderNodeTree", "GeometryNodeTree")) {
+ *r_disabled_hint = TIP_("Not a shader or geometry node tree");
return false;
}
return true;
}
-void sh_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = sh_node_poll_default;
ntype->insert_link = node_insert_link_default;
- ntype->update_internal_links = node_update_internal_links_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
-void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
- sh_node_type_base(ntype, type, name, nclass, flag);
+ sh_node_type_base(ntype, type, name, nclass);
ntype->poll = sh_fn_poll_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
/* ****** */
-void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
+static void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
{
const float *from = ns->vec;
@@ -108,11 +110,11 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
{
memset(gs, 0, sizeof(*gs));
- if (ns == NULL) {
- /* node_get_stack() will generate NULL bNodeStack pointers
+ if (ns == nullptr) {
+ /* node_get_stack() will generate nullptr bNodeStack pointers
* for unknown/unsupported types of sockets. */
zero_v4(gs->vec);
- gs->link = NULL;
+ gs->link = nullptr;
gs->type = GPU_NONE;
gs->hasinput = false;
gs->hasoutput = false;
@@ -120,7 +122,7 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
}
else {
nodestack_get_vec(gs->vec, type, ns);
- gs->link = ns->data;
+ gs->link = (GPUNodeLink *)ns->data;
if (type == SOCK_FLOAT) {
gs->type = GPU_FLOAT;
@@ -160,11 +162,9 @@ void node_data_from_gpu_stack(bNodeStack *ns, GPUNodeStack *gs)
static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeStack **ns)
{
- bNodeSocket *sock;
int i;
-
- for (sock = sockets->first, i = 0; sock; sock = sock->next, i++) {
- node_gpu_stack_from_data(&gs[i], sock->type, ns[i]);
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, i) {
+ node_gpu_stack_from_data(&gs[i], socket->type, ns[i]);
}
gs[i].end = true;
@@ -172,10 +172,8 @@ static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeS
static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
{
- bNodeSocket *sock;
int i;
-
- for (sock = sockets->first, i = 0; sock; sock = sock->next, i++) {
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, i) {
node_data_from_gpu_stack(ns[i], &gs[i]);
}
}
@@ -183,14 +181,14 @@ static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNode
bNode *nodeGetActiveTexture(bNodeTree *ntree)
{
/* this is the node we texture paint and draw in textured draw */
- bNode *node, *tnode, *inactivenode = NULL, *activetexnode = NULL, *activegroup = NULL;
+ bNode *inactivenode = nullptr, *activetexnode = nullptr, *activegroup = nullptr;
bool hasgroup = false;
if (!ntree) {
- return NULL;
+ return nullptr;
}
- for (node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & NODE_ACTIVE_TEXTURE) {
activetexnode = node;
/* if active we can return immediately */
@@ -213,7 +211,7 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree)
/* first, check active group for textures */
if (activegroup) {
- tnode = nodeGetActiveTexture((bNodeTree *)activegroup->id);
+ bNode *tnode = nodeGetActiveTexture((bNodeTree *)activegroup->id);
/* active node takes priority, so ignore any other possible nodes here */
if (tnode) {
return tnode;
@@ -226,9 +224,9 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree)
if (hasgroup) {
/* node active texture node in this tree, look inside groups */
- for (node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == NODE_GROUP) {
- tnode = nodeGetActiveTexture((bNodeTree *)node->id);
+ bNode *tnode = nodeGetActiveTexture((bNodeTree *)node->id);
if (tnode && ((tnode->flag & NODE_ACTIVE_TEXTURE) || !inactivenode)) {
return tnode;
}
@@ -258,7 +256,7 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node
do_it = false;
/* for groups, only execute outputs for edited group */
if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
- if ((output_node != NULL) && (node == output_node)) {
+ if ((output_node != nullptr) && (node == output_node)) {
do_it = true;
}
}
@@ -282,11 +280,11 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node
void node_shader_gpu_bump_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link)
{
if (node->branch_tag == 1) {
- /* Add one time the value fo derivative to the input vector. */
+ /* Add one time the value for derivative to the input vector. */
GPU_link(mat, "dfdx_v3", *link, link);
}
else if (node->branch_tag == 2) {
- /* Add one time the value fo derivative to the input vector. */
+ /* Add one time the value for derivative to the input vector. */
GPU_link(mat, "dfdy_v3", *link, link);
}
else {
@@ -308,7 +306,7 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *UNUSED(out))
{
- NodeTexBase *base = node->storage;
+ NodeTexBase *base = (NodeTexBase *)node->storage;
TexMapping *texmap = &base->tex_mapping;
float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0;
float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.hh
index c647b86a19a..5a5b4f613f3 100644
--- a/source/blender/nodes/shader/node_shader_util.h
+++ b/source/blender/nodes/shader/node_shader_util.hh
@@ -23,29 +23,21 @@
#pragma once
-#include <float.h>
-#include <math.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_ID.h"
-#include "DNA_color_types.h"
-#include "DNA_customdata_types.h"
-#include "DNA_image_types.h"
-#include "DNA_material_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
+#include <cfloat>
+#include <cmath>
+#include <cstring>
#include "BLI_blenlib.h"
+#include "BLI_color.hh"
#include "BLI_math.h"
#include "BLI_math_base_safe.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_rand.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
@@ -55,53 +47,46 @@
#include "BKE_node.h"
#include "BKE_texture.h"
-#include "NOD_shader.h"
-#include "node_util.h"
-
-#include "BLT_translation.h"
-
-#include "IMB_colormanagement.h"
+#include "DNA_ID.h"
+#include "DNA_color_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_image_types.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
-#include "RE_pipeline.h"
-#include "RE_texture.h"
+#include "FN_multi_function_builder.hh"
#include "GPU_material.h"
#include "GPU_texture.h"
#include "GPU_uniform_buffer.h"
-#ifdef __cplusplus
-# include "FN_multi_function_builder.hh"
+#include "IMB_colormanagement.h"
-# include "NOD_multi_function.hh"
-# include "NOD_socket_declarations.hh"
+#include "MEM_guardedalloc.h"
-# include "BLI_color.hh"
-# include "BLI_float3.hh"
+#include "NOD_multi_function.hh"
+#include "NOD_shader.h"
+#include "NOD_socket_declarations.hh"
+#include "node_util.h"
-extern "C" {
-#endif
+#include "RE_pipeline.h"
+#include "RE_texture.h"
bool sh_node_poll_default(struct bNodeType *ntype,
struct bNodeTree *ntree,
const char **r_disabled_hint);
-void sh_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
-void sh_fn_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
+void sh_fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
/* ********* exec data struct, remains internal *********** */
-typedef struct ShaderCallData {
- /* Empty for now, may be reused if we convert shader to texture nodes. */
- int dummy;
-} ShaderCallData;
-
-typedef struct XYZ_to_RGB /* Transposed #imbuf_xyz_to_rgb, passed as 3x vec3. */
+struct XYZ_to_RGB /* Transposed #imbuf_xyz_to_rgb, passed as 3x vec3. */
{
float r[3], g[3], b[3];
-} XYZ_to_RGB;
-
-void nodestack_get_vec(float *in, short type_in, bNodeStack *ns);
+};
void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, struct bNodeStack *ns);
void node_data_from_gpu_stack(struct bNodeStack *ns, struct GPUNodeStack *gs);
@@ -120,7 +105,3 @@ void ntreeExecGPUNodes(struct bNodeTreeExec *exec,
struct GPUMaterial *mat,
struct bNode *output_node);
void get_XYZ_to_RGB_for_gpu(XYZ_to_RGB *data);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/nodes/shader/nodes/node_shader_add_shader.c b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc
index 12c138ac9d5..73d5c12ce96 100644
--- a/source/blender/nodes/shader/nodes/node_shader_add_shader.c
+++ b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc
@@ -17,20 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_add_shader_cc {
-static bNodeSocketTemplate sh_node_add_shader_in[] = {
- {SOCK_SHADER, N_("Shader")},
- {SOCK_SHADER, N_("Shader")},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_add_shader_out[] = {
- {SOCK_SHADER, N_("Shader")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Shader>(N_("Shader"));
+ b.add_input<decl::Shader>(N_("Shader"), "Shader_001");
+ b.add_output<decl::Shader>(N_("Shader"));
+}
static int node_shader_gpu_add_shader(GPUMaterial *mat,
bNode *node,
@@ -41,16 +37,18 @@ static int node_shader_gpu_add_shader(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_add_shader", in, out);
}
+} // namespace blender::nodes::node_shader_add_shader_cc
+
/* node type definition */
-void register_node_type_sh_add_shader(void)
+void register_node_type_sh_add_shader()
{
+ namespace file_ns = blender::nodes::node_shader_add_shader_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_ADD_SHADER, "Add Shader", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_add_shader_in, sh_node_add_shader_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_add_shader);
+ sh_node_type_base(&ntype, SH_NODE_ADD_SHADER, "Add Shader", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_add_shader);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc
index abe80ebcefb..9c64594aab8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
+++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc
@@ -17,22 +17,30 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_ambient_occlusion_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_ambient_occlusion_cc {
-static bNodeSocketTemplate sh_node_ambient_occlusion_out[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("AO"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Distance")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Normal")).min(-1.0f).max(1.0f).hide_value();
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("AO"));
+}
+
+static void node_shader_buts_ambient_occlusion(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "inside", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "only_local", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat,
bNode *node,
@@ -64,16 +72,20 @@ static void node_shader_init_ambient_occlusion(bNodeTree *UNUSED(ntree), bNode *
node->custom2 = 0;
}
+} // namespace blender::nodes::node_shader_ambient_occlusion_cc
+
/* node type definition */
-void register_node_type_sh_ambient_occlusion(void)
+void register_node_type_sh_ambient_occlusion()
{
+ namespace file_ns = blender::nodes::node_shader_ambient_occlusion_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_AMBIENT_OCCLUSION, "Ambient Occlusion", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_ambient_occlusion_in, sh_node_ambient_occlusion_out);
- node_type_init(&ntype, node_shader_init_ambient_occlusion);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_ambient_occlusion);
+ sh_node_type_base(&ntype, SH_NODE_AMBIENT_OCCLUSION, "Ambient Occlusion", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_ambient_occlusion;
+ node_type_init(&ntype, file_ns::node_shader_init_ambient_occlusion);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_ambient_occlusion);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.cc
index 9b3122e38e0..cf1b49ba29c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.c
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.cc
@@ -17,21 +17,30 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_attribute_out[] = {
- {SOCK_RGBA, N_("Color")},
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Fac"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_FACTOR},
- {SOCK_FLOAT, N_("Alpha"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_FACTOR},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_attribute_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Vector>(N_("Vector"));
+ b.add_output<decl::Float>(N_("Fac"));
+ b.add_output<decl::Float>(N_("Alpha"));
+}
+
+static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "attribute_type", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Type"), ICON_NONE);
+ uiItemR(layout, ptr, "attribute_name", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Name"), ICON_NONE);
+}
static void node_shader_init_attribute(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderAttribute *attr = MEM_callocN(sizeof(NodeShaderAttribute), "NodeShaderAttribute");
+ NodeShaderAttribute *attr = MEM_cnew<NodeShaderAttribute>("NodeShaderAttribute");
node->storage = attr;
}
@@ -41,7 +50,7 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- NodeShaderAttribute *attr = node->storage;
+ NodeShaderAttribute *attr = static_cast<NodeShaderAttribute *>(node->storage);
bool is_varying = attr->type == SHD_ATTRIBUTE_GEOMETRY;
if (GPU_material_is_volume_shader(mat) && is_varying) {
@@ -73,25 +82,30 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr);
- /* for each output. */
- for (int i = 0; sh_node_attribute_out[i].type != -1; i++) {
+ int i;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) {
node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
}
return 1;
}
+} // namespace blender::nodes::node_shader_attribute_cc
+
/* node type definition */
-void register_node_type_sh_attribute(void)
+void register_node_type_sh_attribute()
{
+ namespace file_ns = blender::nodes::node_shader_attribute_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_ATTRIBUTE, "Attribute", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_attribute_out);
- node_type_init(&ntype, node_shader_init_attribute);
+ sh_node_type_base(&ntype, SH_NODE_ATTRIBUTE, "Attribute", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_attribute;
+ node_type_init(&ntype, file_ns::node_shader_init_attribute);
node_type_storage(
&ntype, "NodeShaderAttribute", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_attribute);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_attribute);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_background.c b/source/blender/nodes/shader/nodes/node_shader_background.cc
index 4301a9f716f..3b9e71cf842 100644
--- a/source/blender/nodes/shader/nodes/node_shader_background.c
+++ b/source/blender/nodes/shader/nodes/node_shader_background.cc
@@ -17,21 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_background_cc {
-static bNodeSocketTemplate sh_node_background_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000000.0f},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_background_out[] = {
- {SOCK_SHADER, N_("Background")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Strength")).default_value(1.0f).min(0.0f).max(1000000.0f);
+ b.add_output<decl::Shader>(N_("Background"));
+}
static int node_shader_gpu_background(GPUMaterial *mat,
bNode *node,
@@ -42,16 +37,18 @@ static int node_shader_gpu_background(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_background", in, out);
}
+} // namespace blender::nodes::node_shader_background_cc
+
/* node type definition */
-void register_node_type_sh_background(void)
+void register_node_type_sh_background()
{
+ namespace file_ns = blender::nodes::node_shader_background_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BACKGROUND, "Background", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_background_in, sh_node_background_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_background);
+ sh_node_type_base(&ntype, SH_NODE_BACKGROUND, "Background", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_background);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bevel.c b/source/blender/nodes/shader/nodes/node_shader_bevel.cc
index d6bdda30e94..dfde18d8e2a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bevel.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bevel.cc
@@ -17,20 +17,24 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_bevel_in[] = {
- {SOCK_FLOAT, N_("Radius"), 0.05f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_bevel_cc {
-static bNodeSocketTemplate sh_node_bevel_out[] = {
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Radius")).default_value(0.05f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Vector>(N_("Normal"));
+}
+
+static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
static void node_shader_init_bevel(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -50,16 +54,20 @@ static int gpu_shader_bevel(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bevel", in, out);
}
+} // namespace blender::nodes::node_shader_bevel_cc
+
/* node type definition */
-void register_node_type_sh_bevel(void)
+void register_node_type_sh_bevel()
{
+ namespace file_ns = blender::nodes::node_shader_bevel_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BEVEL, "Bevel", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_bevel_in, sh_node_bevel_out);
- node_type_init(&ntype, node_shader_init_bevel);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_bevel);
+ sh_node_type_base(&ntype, SH_NODE_BEVEL, "Bevel", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_bevel;
+ node_type_init(&ntype, file_ns::node_shader_init_bevel);
+ node_type_gpu(&ntype, file_ns::gpu_shader_bevel);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_blackbody.c b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc
index 95c35affc27..85e2ed08403 100644
--- a/source/blender/nodes/shader/nodes/node_shader_blackbody.c
+++ b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc
@@ -17,18 +17,15 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Blackbody ******************** */
-static bNodeSocketTemplate sh_node_blackbody_in[] = {
- {SOCK_FLOAT, N_("Temperature"), 1500.0f, 0.0f, 0.0f, 0.0f, 800.0f, 12000.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_blackbody_cc {
-static bNodeSocketTemplate sh_node_blackbody_out[] = {
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Temperature")).default_value(1500.0f).min(800.0f).max(12000.0f);
+ b.add_output<decl::Color>(N_("Color"));
+}
static int node_shader_gpu_blackbody(GPUMaterial *mat,
bNode *node,
@@ -37,7 +34,7 @@ static int node_shader_gpu_blackbody(GPUMaterial *mat,
GPUNodeStack *out)
{
const int size = CM_TABLE + 1;
- float *data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
+ float *data = static_cast<float *>(MEM_mallocN(sizeof(float) * size * 4, "blackbody texture"));
blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
@@ -47,17 +44,19 @@ static int node_shader_gpu_blackbody(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_blackbody", in, out, ramp_texture, GPU_constant(&layer));
}
+} // namespace blender::nodes::node_shader_blackbody_cc
+
/* node type definition */
-void register_node_type_sh_blackbody(void)
+void register_node_type_sh_blackbody()
{
+ namespace file_ns = blender::nodes::node_shader_blackbody_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BLACKBODY, "Blackbody", NODE_CLASS_CONVERTER, 0);
+ sh_node_type_base(&ntype, SH_NODE_BLACKBODY, "Blackbody", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_socket_templates(&ntype, sh_node_blackbody_in, sh_node_blackbody_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_blackbody);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_blackbody);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.cc
index 4f375c666de..66bfaba2785 100644
--- a/source/blender/nodes/shader/nodes/node_shader_brightness.c
+++ b/source/blender/nodes/shader/nodes/node_shader_brightness.cc
@@ -17,21 +17,17 @@
* All rights reserved.
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Bright and contrast ******************** */
+namespace blender::nodes::node_shader_brightness_cc {
-static bNodeSocketTemplate sh_node_brightcontrast_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Bright"), 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Contrast"), 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_brightcontrast_out[] = {
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Bright")).default_value(0.0f).min(-100.0f).max(100.0f);
+ b.add_input<decl::Float>(N_("Contrast")).default_value(0.0f).min(-100.0f).max(100.0f);
+ b.add_output<decl::Color>(N_("Color"));
+}
static int gpu_shader_brightcontrast(GPUMaterial *mat,
bNode *node,
@@ -42,15 +38,17 @@ static int gpu_shader_brightcontrast(GPUMaterial *mat,
return GPU_stack_link(mat, node, "brightness_contrast", in, out);
}
-void register_node_type_sh_brightcontrast(void)
+} // namespace blender::nodes::node_shader_brightness_cc
+
+void register_node_type_sh_brightcontrast()
{
+ namespace file_ns = blender::nodes::node_shader_brightness_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_brightcontrast_in, sh_node_brightcontrast_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_brightcontrast);
+ sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_brightcontrast);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
deleted file mode 100644
index 7c080337838..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
+++ /dev/null
@@ -1,80 +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.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_bsdf_anisotropic_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Anisotropy"), 0.5f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f},
- {SOCK_FLOAT, N_("Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_VECTOR, N_("Tangent"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_anisotropic_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
-
-static void node_shader_init_anisotropic(bNodeTree *UNUSED(ntree), bNode *node)
-{
- node->custom1 = SHD_GLOSSY_GGX;
-}
-
-static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- if (!in[4].link) {
- GPU_link(mat, "world_normals_get", &in[4].link);
- }
-
- GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY);
-
- float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
-
- GPU_stack_link(mat, node, "node_bsdf_anisotropic", in, out);
-
- GPU_stack_eval_link(
- mat, node, "node_bsdf_anisotropic_eval", in, out, GPU_constant(&use_multi_scatter));
-
- return true;
-}
-
-/* node type definition */
-void register_node_type_sh_bsdf_anisotropic(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_BSDF_ANISOTROPIC, "Anisotropic BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_anisotropic_in, sh_node_bsdf_anisotropic_out);
- node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_anisotropic);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_anisotropic);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc
new file mode 100644
index 00000000000..3f0749ab2af
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_bsdf_anisotropic_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Anisotropy")).default_value(0.5f).min(-1.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Rotation"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_input<decl::Vector>(N_("Tangent")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
+
+static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "distribution", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+static void node_shader_init_anisotropic(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SHD_GLOSSY_GGX;
+}
+
+static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ if (!in[4].link) {
+ GPU_link(mat, "world_normals_get", &in[4].link);
+ }
+
+ GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY);
+
+ float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
+
+ return GPU_stack_link(mat,
+ node,
+ "node_bsdf_anisotropic",
+ in,
+ out,
+ GPU_constant(&use_multi_scatter),
+ GPU_constant(&node->ssr_id));
+}
+
+} // namespace blender::nodes::node_shader_bsdf_anisotropic_cc
+
+/* node type definition */
+void register_node_type_sh_bsdf_anisotropic()
+{
+ namespace file_ns = blender::nodes::node_shader_bsdf_anisotropic_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_BSDF_ANISOTROPIC, "Anisotropic BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_anisotropic;
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_init(&ntype, file_ns::node_shader_init_anisotropic);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_anisotropic);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc
index 3aa3b70025e..5848ca76cdd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc
@@ -17,22 +17,21 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_bsdf_diffuse_cc {
-static bNodeSocketTemplate sh_node_bsdf_diffuse_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_diffuse_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat,
bNode *node,
@@ -46,21 +45,22 @@ static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat,
GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE);
- GPU_stack_link(mat, node, "node_bsdf_diffuse", in, out);
- return GPU_stack_eval_link(mat, node, "node_bsdf_diffuse_eval", in, out);
+ return GPU_stack_link(mat, node, "node_bsdf_diffuse", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_diffuse_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_diffuse(void)
+void register_node_type_sh_bsdf_diffuse()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_diffuse_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_DIFFUSE, "Diffuse BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_diffuse_in, sh_node_bsdf_diffuse_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_DIFFUSE, "Diffuse BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_diffuse);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_diffuse);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
deleted file mode 100644
index e164e32723e..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
+++ /dev/null
@@ -1,96 +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.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_bsdf_glass_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_glass_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
-
-static void node_shader_init_glass(bNodeTree *UNUSED(ntree), bNode *node)
-{
- node->custom1 = SHD_GLOSSY_BECKMANN;
-}
-
-static int node_shader_gpu_bsdf_glass(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- if (!in[3].link) {
- GPU_link(mat, "world_normals_get", &in[3].link);
- }
-
- if (node->custom1 == SHD_GLOSSY_SHARP) {
- GPU_link(mat, "set_value_zero", &in[1].link);
- }
-
- GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT);
-
- float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
-
- GPUNodeLink *reflection_weight;
- GPUNodeLink *refraction_weight;
-
- GPU_stack_link(mat,
- node,
- "node_bsdf_glass",
- in,
- out,
- GPU_constant(&use_multi_scatter),
- &reflection_weight,
- &refraction_weight);
-
- return GPU_stack_eval_link(mat,
- node,
- "node_bsdf_glass_eval",
- in,
- out,
- GPU_constant(&use_multi_scatter),
- reflection_weight,
- refraction_weight);
-}
-
-/* node type definition */
-void register_node_type_sh_bsdf_glass(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_BSDF_GLASS, "Glass BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_glass_in, sh_node_bsdf_glass_out);
- node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_glass);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_glass);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc
new file mode 100644
index 00000000000..47d4b87198b
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_bsdf_glass_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("IOR")).default_value(1.45f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
+
+static void node_shader_init_glass(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SHD_GLOSSY_BECKMANN;
+}
+
+static int node_shader_gpu_bsdf_glass(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ if (!in[3].link) {
+ GPU_link(mat, "world_normals_get", &in[3].link);
+ }
+
+ if (node->custom1 == SHD_GLOSSY_SHARP) {
+ GPU_link(mat, "set_value_zero", &in[1].link);
+ }
+
+ GPU_material_flag_set(mat, (eGPUMatFlag)(GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT));
+
+ float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
+
+ return GPU_stack_link(mat,
+ node,
+ "node_bsdf_glass",
+ in,
+ out,
+ GPU_constant(&use_multi_scatter),
+ GPU_constant(&node->ssr_id));
+}
+
+} // namespace blender::nodes::node_shader_bsdf_glass_cc
+
+/* node type definition */
+void register_node_type_sh_bsdf_glass()
+{
+ namespace file_ns = blender::nodes::node_shader_bsdf_glass_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_BSDF_GLASS, "Glass BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_init(&ntype, file_ns::node_shader_init_glass);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_glass);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc
index e234dafb98e..03a3e634f56 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc
@@ -17,22 +17,21 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_bsdf_glossy_cc {
-static bNodeSocketTemplate sh_node_bsdf_glossy_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_glossy_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
static void node_shader_init_glossy(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -57,22 +56,29 @@ static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat,
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
- GPU_stack_link(mat, node, "node_bsdf_glossy", in, out);
- return GPU_stack_eval_link(
- mat, node, "node_bsdf_glossy_eval", in, out, GPU_constant(&use_multi_scatter));
+ return GPU_stack_link(mat,
+ node,
+ "node_bsdf_glossy",
+ in,
+ out,
+ GPU_constant(&use_multi_scatter),
+ GPU_constant(&node->ssr_id));
}
+} // namespace blender::nodes::node_shader_bsdf_glossy_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_glossy(void)
+void register_node_type_sh_bsdf_glossy()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_glossy_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_GLOSSY, "Glossy BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_glossy_in, sh_node_bsdf_glossy_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_GLOSSY, "Glossy BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_glossy);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_glossy);
+ node_type_init(&ntype, file_ns::node_shader_init_glossy);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_glossy);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc
index 1f07cb1d202..3be2bd22f60 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc
@@ -17,24 +17,39 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_bsdf_hair_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Offset"), 0.0f, 0.0f, 0.0f, 0.0f, -M_PI_2, M_PI_2, PROP_ANGLE},
- {SOCK_FLOAT, N_("RoughnessU"), 0.1f, 0.1f, 0.1f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("RoughnessV"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Tangent"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_bsdf_hair_cc {
-static bNodeSocketTemplate sh_node_bsdf_hair_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Offset"))
+ .default_value(0.0f)
+ .min(-M_PI_2)
+ .max(M_PI_2)
+ .subtype(PROP_ANGLE);
+ b.add_input<decl::Float>(N_("RoughnessU"))
+ .default_value(0.1f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("RoughnessV"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Tangent")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
+
+static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "component", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static int node_shader_gpu_bsdf_hair(GPUMaterial *mat,
bNode *node,
@@ -45,17 +60,20 @@ static int node_shader_gpu_bsdf_hair(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_hair", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_hair_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_hair(void)
+void register_node_type_sh_bsdf_hair()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_hair_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR, "Hair BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_hair_in, sh_node_bsdf_hair_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR, "Hair BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_hair;
node_type_size(&ntype, 150, 60, 200);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_hair);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_hair);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c
deleted file mode 100644
index d9bcbbcd7a4..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c
+++ /dev/null
@@ -1,135 +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) 2018 Blender Foundation.
- * All rights reserved.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-/* Color, melanin and absorption coefficient default to approximately same brownish hair. */
-static bNodeSocketTemplate sh_node_bsdf_hair_principled_in[] = {
- {SOCK_RGBA, N_("Color"), 0.017513f, 0.005763f, 0.002059f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Melanin"), 0.8f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Melanin Redness"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Tint"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Absorption Coefficient"), 0.245531f, 0.52f, 1.365f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Roughness"), 0.3f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Radial Roughness"), 0.3f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Coat"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("IOR"), 1.55f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT,
- N_("Offset"),
- 2.0f * ((float)M_PI) / 180.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- -M_PI_2,
- M_PI_2,
- PROP_ANGLE},
- {SOCK_FLOAT, N_("Random Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Random Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Random"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_hair_principled_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
-
-/* Initialize the custom Parametrization property to Color. */
-static void node_shader_init_hair_principled(bNodeTree *UNUSED(ntree), bNode *node)
-{
- node->custom1 = SHD_PRINCIPLED_HAIR_REFLECTANCE;
-}
-
-/* Triggers (in)visibility of some sockets when changing Parametrization. */
-static void node_shader_update_hair_principled(bNodeTree *UNUSED(ntree), bNode *node)
-{
- bNodeSocket *sock;
- int parametrization = node->custom1;
-
- for (sock = node->inputs.first; sock; sock = sock->next) {
- if (STREQ(sock->name, "Color")) {
- if (parametrization == SHD_PRINCIPLED_HAIR_REFLECTANCE) {
- sock->flag &= ~SOCK_UNAVAIL;
- }
- else {
- sock->flag |= SOCK_UNAVAIL;
- }
- }
- else if (STREQ(sock->name, "Melanin")) {
- if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) {
- sock->flag &= ~SOCK_UNAVAIL;
- }
- else {
- sock->flag |= SOCK_UNAVAIL;
- }
- }
- else if (STREQ(sock->name, "Melanin Redness")) {
- if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) {
- sock->flag &= ~SOCK_UNAVAIL;
- }
- else {
- sock->flag |= SOCK_UNAVAIL;
- }
- }
- else if (STREQ(sock->name, "Tint")) {
- if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) {
- sock->flag &= ~SOCK_UNAVAIL;
- }
- else {
- sock->flag |= SOCK_UNAVAIL;
- }
- }
- else if (STREQ(sock->name, "Absorption Coefficient")) {
- if (parametrization == SHD_PRINCIPLED_HAIR_DIRECT_ABSORPTION) {
- sock->flag &= ~SOCK_UNAVAIL;
- }
- else {
- sock->flag |= SOCK_UNAVAIL;
- }
- }
- else if (STREQ(sock->name, "Random Color")) {
- if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) {
- sock->flag &= ~SOCK_UNAVAIL;
- }
- else {
- sock->flag |= SOCK_UNAVAIL;
- }
- }
- }
-}
-
-/* node type definition */
-void register_node_type_sh_bsdf_hair_principled(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(
- &ntype, SH_NODE_BSDF_HAIR_PRINCIPLED, "Principled Hair BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(
- &ntype, sh_node_bsdf_hair_principled_in, sh_node_bsdf_hair_principled_out);
- node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_init(&ntype, node_shader_init_hair_principled);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_update(&ntype, node_shader_update_hair_principled);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc
new file mode 100644
index 00000000000..7062888b5fb
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc
@@ -0,0 +1,145 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_bsdf_hair_principled_cc {
+
+/* Color, melanin and absorption coefficient default to approximately same brownish hair. */
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.017513f, 0.005763f, 0.002059f, 1.0f});
+ b.add_input<decl::Float>(N_("Melanin"))
+ .default_value(0.8f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Melanin Redness"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Tint")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Absorption Coefficient"))
+ .default_value({0.245531f, 0.52f, 1.365f})
+ .min(0.0f)
+ .max(1000.0f);
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.3f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Radial Roughness"))
+ .default_value(0.3f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Coat"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("IOR")).default_value(1.55f).min(0.0f).max(1000.0f).subtype(
+ PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Offset"))
+ .default_value(2.0f * ((float)M_PI) / 180.0f)
+ .min(-M_PI_2)
+ .max(M_PI_2)
+ .subtype(PROP_ANGLE);
+ b.add_input<decl::Float>(N_("Random Color"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Random Roughness"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Random")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
+
+static void node_shader_buts_principled_hair(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "parametrization", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+/* Initialize the custom Parametrization property to Color. */
+static void node_shader_init_hair_principled(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SHD_PRINCIPLED_HAIR_REFLECTANCE;
+}
+
+/* Triggers (in)visibility of some sockets when changing Parametrization. */
+static void node_shader_update_hair_principled(bNodeTree *ntree, bNode *node)
+{
+ int parametrization = node->custom1;
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ if (STREQ(sock->name, "Color")) {
+ nodeSetSocketAvailability(ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_REFLECTANCE);
+ }
+ else if (STREQ(sock->name, "Melanin")) {
+ nodeSetSocketAvailability(
+ ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
+ }
+ else if (STREQ(sock->name, "Melanin Redness")) {
+ nodeSetSocketAvailability(
+ ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
+ }
+ else if (STREQ(sock->name, "Tint")) {
+ nodeSetSocketAvailability(
+ ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
+ }
+ else if (STREQ(sock->name, "Absorption Coefficient")) {
+ nodeSetSocketAvailability(
+ ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_DIRECT_ABSORPTION);
+ }
+ else if (STREQ(sock->name, "Random Color")) {
+ nodeSetSocketAvailability(
+ ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
+ }
+ }
+}
+
+} // namespace blender::nodes::node_shader_bsdf_hair_principled_cc
+
+/* node type definition */
+void register_node_type_sh_bsdf_hair_principled()
+{
+ namespace file_ns = blender::nodes::node_shader_bsdf_hair_principled_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(
+ &ntype, SH_NODE_BSDF_HAIR_PRINCIPLED, "Principled Hair BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_principled_hair;
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ node_type_init(&ntype, file_ns::node_shader_init_hair_principled);
+ node_type_update(&ntype, file_ns::node_shader_update_hair_principled);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
deleted file mode 100644
index 5fbf66d5a68..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
+++ /dev/null
@@ -1,195 +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.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_bsdf_principled_in[] = {
- {SOCK_RGBA, N_("Base Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Subsurface"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR,
- N_("Subsurface Radius"),
- 1.0f,
- 0.2f,
- 0.1f,
- 0.0f,
- 0.0f,
- 100.0f,
- PROP_NONE,
- SOCK_COMPACT},
- {SOCK_RGBA, N_("Subsurface Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Subsurface IOR"), 1.4f, 0.0f, 0.0f, 0.0f, 1.01f, 3.8f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Subsurface Anisotropy"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Metallic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Specular"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Specular Tint"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Anisotropic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Anisotropic Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Sheen"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Sheen Tint"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Clearcoat"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Clearcoat Roughness"), 0.03f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Transmission"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Transmission Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Emission"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Emission Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000000.0f},
- {SOCK_FLOAT, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_VECTOR,
- N_("Clearcoat Normal"),
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- -1.0f,
- 1.0f,
- PROP_NONE,
- SOCK_HIDE_VALUE},
- {SOCK_VECTOR, N_("Tangent"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_principled_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
-
-static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node)
-{
- node->custom1 = SHD_GLOSSY_GGX;
- node->custom2 = SHD_SUBSURFACE_RANDOM_WALK;
-}
-
-#define socket_not_zero(sock) (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) > 1e-5f))
-#define socket_not_one(sock) \
- (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) < 1.0f - 1e-5f))
-
-static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- /* Normals */
- if (!in[22].link) {
- GPU_link(mat, "world_normals_get", &in[22].link);
- }
-
- /* Clearcoat Normals */
- if (!in[23].link) {
- GPU_link(mat, "world_normals_get", &in[23].link);
- }
-
-#if 0 /* Not used at the moment. */
- /* Tangents */
- if (!in[24].link) {
- GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "tangent_orco_z", orco, &in[24].link);
- GPU_link(mat, "node_tangent", in[24].link, &in[24].link);
- }
-#endif
-
- bool use_diffuse = socket_not_one(6) && socket_not_one(17);
- bool use_subsurf = socket_not_zero(1) && use_diffuse;
- bool use_refract = socket_not_one(6) && socket_not_zero(17);
- bool use_transparency = socket_not_one(21);
- // bool use_clear = socket_not_zero(14);
-
- uint flag = GPU_MATFLAG_GLOSSY;
- if (use_diffuse) {
- flag |= GPU_MATFLAG_DIFFUSE;
- }
- if (use_refract) {
- flag |= GPU_MATFLAG_REFRACT;
- }
- if (use_subsurf) {
- flag |= GPU_MATFLAG_SUBSURFACE;
- }
- if (use_transparency) {
- flag |= GPU_MATFLAG_TRANSPARENT;
- }
-
- float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
-
- GPU_material_flag_set(mat, flag);
-
- GPUNodeLink *diffuse_weight, *specular_weight, *glass_reflection_weight,
- *glass_transmission_weight, *clearcoat_weight;
-
- GPU_stack_link(mat,
- node,
- "node_bsdf_principled",
- in,
- out,
- GPU_constant(&use_multi_scatter),
- &diffuse_weight,
- &specular_weight,
- &glass_reflection_weight,
- &glass_transmission_weight,
- &clearcoat_weight);
-
- return GPU_stack_eval_link(mat,
- node,
- "node_bsdf_principled_eval",
- in,
- out,
- GPU_constant(&use_multi_scatter),
- diffuse_weight,
- specular_weight,
- glass_reflection_weight,
- glass_transmission_weight,
- clearcoat_weight);
-}
-
-static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node)
-{
- bNodeSocket *sock;
- int distribution = node->custom1;
-
- for (sock = node->inputs.first; sock; sock = sock->next) {
- if (STREQ(sock->name, "Transmission Roughness")) {
- if (distribution == SHD_GLOSSY_GGX) {
- sock->flag &= ~SOCK_UNAVAIL;
- }
- else {
- sock->flag |= SOCK_UNAVAIL;
- }
- }
- }
-}
-
-/* node type definition */
-void register_node_type_sh_bsdf_principled(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_principled_in, sh_node_bsdf_principled_out);
- node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_init(&ntype, node_shader_init_principled);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_principled);
- node_type_update(&ntype, node_shader_update_principled);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc
new file mode 100644
index 00000000000..4c378d9bc09
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc
@@ -0,0 +1,259 @@
+/*
+ * 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.
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_bsdf_principled_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Base Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Subsurface"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Subsurface Radius"))
+ .default_value({1.0f, 0.2f, 0.1f})
+ .min(0.0f)
+ .max(100.0f)
+ .compact();
+ b.add_input<decl::Color>(N_("Subsurface Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Subsurface IOR"))
+ .default_value(1.4f)
+ .min(1.01f)
+ .max(3.8f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Subsurface Anisotropy"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Metallic"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Specular"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Specular Tint"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Anisotropic"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Anisotropic Rotation"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Sheen"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Sheen Tint"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Clearcoat"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Clearcoat Roughness"))
+ .default_value(0.03f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("IOR")).default_value(1.45f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Transmission"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Transmission Roughness"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Emission")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Emission Strength")).default_value(1.0).min(0.0f).max(1000000.0f);
+ b.add_input<decl::Float>(N_("Alpha"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_input<decl::Vector>(N_("Clearcoat Normal")).hide_value();
+ b.add_input<decl::Vector>(N_("Tangent")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
+
+static void node_shader_buts_principled(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "distribution", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "subsurface_method", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SHD_GLOSSY_GGX;
+ node->custom2 = SHD_SUBSURFACE_RANDOM_WALK;
+}
+
+#define socket_not_zero(sock) (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) > 1e-5f))
+#define socket_not_one(sock) \
+ (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) < 1.0f - 1e-5f))
+
+static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ GPUNodeLink *sss_scale;
+
+ /* Normals */
+ if (!in[22].link) {
+ GPU_link(mat, "world_normals_get", &in[22].link);
+ }
+
+ /* Clearcoat Normals */
+ if (!in[23].link) {
+ GPU_link(mat, "world_normals_get", &in[23].link);
+ }
+
+#if 0 /* Not used at the moment. */
+ /* Tangents */
+ if (!in[24].link) {
+ GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "tangent_orco_z", orco, &in[24].link);
+ GPU_link(mat,
+ "node_tangent",
+ GPU_builtin(GPU_WORLD_NORMAL),
+ in[24].link,
+ GPU_builtin(GPU_OBJECT_MATRIX),
+ &in[24].link);
+ }
+#endif
+
+ bool use_diffuse = socket_not_one(6) && socket_not_one(17);
+ bool use_subsurf = socket_not_zero(1) && use_diffuse && node->sss_id > 0;
+ bool use_refract = socket_not_one(6) && socket_not_zero(17);
+ bool use_clear = socket_not_zero(14);
+
+ /* SSS Profile */
+ if (use_subsurf) {
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2);
+ bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value;
+ /* For some reason it seems that the socket value is in ARGB format. */
+ GPU_material_sss_profile_create(mat, &socket_data->value[1]);
+ }
+
+ if (in[2].link) {
+ sss_scale = in[2].link;
+ }
+ else {
+ GPU_link(mat, "set_rgb_one", &sss_scale);
+ }
+
+ uint flag = GPU_MATFLAG_GLOSSY;
+ if (use_diffuse) {
+ flag |= GPU_MATFLAG_DIFFUSE;
+ }
+ if (use_refract) {
+ flag |= GPU_MATFLAG_REFRACT;
+ }
+ if (use_subsurf) {
+ flag |= GPU_MATFLAG_SSS;
+ }
+
+ float f_use_diffuse = use_diffuse ? 1.0f : 0.0f;
+ float f_use_clearcoat = use_clear ? 1.0f : 0.0f;
+ float f_use_refraction = use_refract ? 1.0f : 0.0f;
+ float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
+
+ GPU_material_flag_set(mat, (eGPUMatFlag)flag);
+
+ return GPU_stack_link(mat,
+ node,
+ "node_bsdf_principled",
+ in,
+ out,
+ GPU_constant(&f_use_diffuse),
+ GPU_constant(&f_use_clearcoat),
+ GPU_constant(&f_use_refraction),
+ GPU_constant(&use_multi_scatter),
+ GPU_constant(&node->ssr_id),
+ GPU_constant(&node->sss_id),
+ sss_scale);
+}
+
+static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
+{
+ const int distribution = node->custom1;
+ const int sss_method = node->custom2;
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ if (STREQ(sock->name, "Transmission Roughness")) {
+ nodeSetSocketAvailability(ntree, sock, distribution == SHD_GLOSSY_GGX);
+ }
+
+ if (STR_ELEM(sock->name, "Subsurface IOR", "Subsurface Anisotropy")) {
+ nodeSetSocketAvailability(ntree, sock, sss_method != SHD_SUBSURFACE_BURLEY);
+ }
+ }
+}
+
+} // namespace blender::nodes::node_shader_bsdf_principled_cc
+
+/* node type definition */
+void register_node_type_sh_bsdf_principled()
+{
+ namespace file_ns = blender::nodes::node_shader_bsdf_principled_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_principled;
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ node_type_init(&ntype, file_ns::node_shader_init_principled);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_principled);
+ node_type_update(&ntype, file_ns::node_shader_update_principled);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc
index f857708c9b6..0d588c82869 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc
@@ -17,23 +17,22 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_bsdf_refraction_cc {
-static bNodeSocketTemplate sh_node_bsdf_refraction_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_refraction_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("IOR")).default_value(1.45f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
static void node_shader_init_refraction(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -56,21 +55,23 @@ static int node_shader_gpu_bsdf_refraction(GPUMaterial *mat,
GPU_material_flag_set(mat, GPU_MATFLAG_REFRACT);
- GPU_stack_link(mat, node, "node_bsdf_refraction", in, out);
- return GPU_stack_eval_link(mat, node, "node_bsdf_refraction_eval", in, out);
+ return GPU_stack_link(mat, node, "node_bsdf_refraction", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_refraction_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_refraction(void)
+void register_node_type_sh_bsdf_refraction()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_refraction_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_REFRACTION, "Refraction BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_refraction_in, sh_node_bsdf_refraction_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_REFRACTION, "Refraction BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_refraction);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_refraction);
+ node_type_init(&ntype, file_ns::node_shader_init_refraction);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_refraction);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc
index e79c65d85d9..5093b896764 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc
@@ -17,23 +17,34 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_bsdf_toon_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Size"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Smooth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_bsdf_toon_cc {
-static bNodeSocketTemplate sh_node_bsdf_toon_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Size"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Smooth"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
+
+static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "component", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static int node_shader_gpu_bsdf_toon(GPUMaterial *mat,
bNode *node,
@@ -47,21 +58,23 @@ static int node_shader_gpu_bsdf_toon(GPUMaterial *mat,
GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE);
- GPU_stack_link(mat, node, "node_bsdf_toon", in, out);
- return GPU_stack_eval_link(mat, node, "node_bsdf_toon_eval", in, out);
+ return GPU_stack_link(mat, node, "node_bsdf_toon", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_toon_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_toon(void)
+void register_node_type_sh_bsdf_toon()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_toon_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_TOON, "Toon BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_toon_in, sh_node_bsdf_toon_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_TOON, "Toon BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_toon;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_toon);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_toon);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc
index d6c308459f5..22891738299 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc
@@ -17,21 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_bsdf_translucent_cc {
-static bNodeSocketTemplate sh_node_bsdf_translucent_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_translucent_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
static int node_shader_gpu_bsdf_translucent(GPUMaterial *mat,
bNode *node,
@@ -45,20 +40,21 @@ static int node_shader_gpu_bsdf_translucent(GPUMaterial *mat,
GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE);
- GPU_stack_link(mat, node, "node_bsdf_translucent", in, out);
- return GPU_stack_eval_link(mat, node, "node_bsdf_translucent_eval", in, out);
+ return GPU_stack_link(mat, node, "node_bsdf_translucent", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_translucent_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_translucent(void)
+void register_node_type_sh_bsdf_translucent()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_translucent_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSLUCENT, "Translucent BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_translucent_in, sh_node_bsdf_translucent_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_translucent);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSLUCENT, "Translucent BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_translucent);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc
index a1c3b9066c8..d764f4dd76b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc
@@ -17,20 +17,15 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_bsdf_transparent_cc {
-static bNodeSocketTemplate sh_node_bsdf_transparent_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_transparent_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
static int node_shader_gpu_bsdf_transparent(GPUMaterial *mat,
bNode *node,
@@ -38,22 +33,21 @@ static int node_shader_gpu_bsdf_transparent(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (in[0].link || !equals_v3v3(in[0].vec, (float[3]){0.0f, 0.0f, 0.0f})) {
- GPU_material_flag_set(mat, GPU_MATFLAG_TRANSPARENT);
- }
return GPU_stack_link(mat, node, "node_bsdf_transparent", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_transparent_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_transparent(void)
+void register_node_type_sh_bsdf_transparent()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_transparent_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSPARENT, "Transparent BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_transparent_in, sh_node_bsdf_transparent_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_transparent);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSPARENT, "Transparent BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_transparent);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc
index 0a7828f5b9a..dd090236c08 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc
@@ -17,22 +17,21 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_bsdf_velvet_cc {
-static bNodeSocketTemplate sh_node_bsdf_velvet_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Sigma"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_velvet_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Sigma"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
static int node_shader_gpu_bsdf_velvet(GPUMaterial *mat,
bNode *node,
@@ -46,20 +45,21 @@ static int node_shader_gpu_bsdf_velvet(GPUMaterial *mat,
GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE);
- GPU_stack_link(mat, node, "node_bsdf_velvet", in, out);
- return GPU_stack_link(mat, node, "node_bsdf_velvet_eval", in, out);
+ return GPU_stack_link(mat, node, "node_bsdf_velvet", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_velvet_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_velvet(void)
+void register_node_type_sh_bsdf_velvet()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_velvet_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_VELVET, "Velvet BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_velvet_in, sh_node_bsdf_velvet_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_velvet);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_VELVET, "Velvet BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_velvet);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.cc
index 5c46e1d3775..f0788c543c2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.cc
@@ -21,22 +21,38 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
/* **************** BUMP ******************** */
-/* clang-format off */
-static bNodeSocketTemplate sh_node_bump_in[] = {
- {SOCK_FLOAT, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Height"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Height_dx"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_UNAVAIL},
- {SOCK_FLOAT, N_("Height_dy"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_UNAVAIL},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""}
-};
-/* clang-format on */
-static bNodeSocketTemplate sh_node_bump_out[] = {{SOCK_VECTOR, "Normal"}, {-1, ""}};
+namespace blender::nodes::node_shader_bump_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Strength"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Distance")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Height"))
+ .default_value(1.0f)
+ .min(-1000.0f)
+ .max(1000.0f)
+ .hide_value();
+ b.add_input<decl::Float>(N_("Height_dx")).default_value(1.0f).unavailable();
+ b.add_input<decl::Float>(N_("Height_dy")).default_value(1.0f).unavailable();
+ b.add_input<decl::Vector>(N_("Normal")).min(-1.0f).max(1.0f).hide_value();
+ b.add_output<decl::Vector>(N_("Normal"));
+}
+
+static void node_shader_buts_bump(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "invert", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+}
static int gpu_shader_bump(GPUMaterial *mat,
bNode *node,
@@ -53,15 +69,19 @@ static int gpu_shader_bump(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bump", in, out, GPU_constant(&invert));
}
+} // namespace blender::nodes::node_shader_bump_cc
+
/* node type definition */
-void register_node_type_sh_bump(void)
+void register_node_type_sh_bump()
{
+ namespace file_ns = blender::nodes::node_shader_bump_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BUMP, "Bump", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_bump_in, sh_node_bump_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_bump);
+ sh_node_type_base(&ntype, SH_NODE_BUMP, "Bump", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_bump;
+ node_type_gpu(&ntype, file_ns::gpu_shader_bump);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.c b/source/blender/nodes/shader/nodes/node_shader_camera.cc
index 9c47db4ea4e..90d2b55b0f7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_camera.c
+++ b/source/blender/nodes/shader/nodes/node_shader_camera.cc
@@ -21,15 +21,16 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** CAMERA INFO ******************** */
-static bNodeSocketTemplate sh_node_camera_out[] = {
- {SOCK_VECTOR, N_("View Vector")},
- {SOCK_FLOAT, N_("View Z Depth")},
- {SOCK_FLOAT, N_("View Distance")},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_camera_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("View Vector"));
+ b.add_output<decl::Float>(N_("View Z Depth"));
+ b.add_output<decl::Float>(N_("View Distance"));
+}
static int gpu_shader_camera(GPUMaterial *mat,
bNode *node,
@@ -40,14 +41,17 @@ static int gpu_shader_camera(GPUMaterial *mat,
return GPU_stack_link(mat, node, "camera", in, out);
}
-void register_node_type_sh_camera(void)
+} // namespace blender::nodes::node_shader_camera_cc
+
+void register_node_type_sh_camera()
{
+ namespace file_ns = blender::nodes::node_shader_camera_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_CAMERA, "Camera Data", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_camera_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_camera);
+ sh_node_type_base(&ntype, SH_NODE_CAMERA, "Camera Data", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_camera);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
index e8d4239937f..cd0f1b3c44d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
@@ -21,20 +21,26 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_clamp_cc {
static void sh_node_clamp_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Value").min(0.0f).max(1.0f).default_value(1.0f);
- b.add_input<decl::Float>("Min").default_value(0.0f).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Max").default_value(1.0f).min(-10000.0f).max(10000.0f);
- b.add_output<decl::Float>("Result");
-};
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f);
+ b.add_input<decl::Float>(N_("Min")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Max")).default_value(1.0f).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Float>(N_("Result"));
+}
-} // namespace blender::nodes
+static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "clamp_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_clamp(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -75,15 +81,20 @@ static void sh_node_clamp_build_multi_function(blender::nodes::NodeMultiFunction
}
}
-void register_node_type_sh_clamp(void)
+} // namespace blender::nodes::node_shader_clamp_cc
+
+void register_node_type_sh_clamp()
{
+ namespace file_ns = blender::nodes::node_shader_clamp_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_clamp_declare;
- node_type_init(&ntype, node_shader_init_clamp);
- node_type_gpu(&ntype, gpu_shader_clamp);
- ntype.build_multi_function = sh_node_clamp_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_clamp_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_clamp;
+ node_type_init(&ntype, file_ns::node_shader_init_clamp);
+ node_type_gpu(&ntype, file_ns::gpu_shader_clamp);
+ ntype.build_multi_function = file_ns::sh_node_clamp_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc
index d4d08be5d49..d8c43e1d66b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc
@@ -21,43 +21,20 @@
* \ingroup shdnodes
*/
-#include "IMB_colormanagement.h"
-
#include "DNA_texture_types.h"
#include "BLI_color.hh"
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_color_ramp_cc {
static void sh_node_valtorgb_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Fac").default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_output<decl::Color>("Color");
- b.add_output<decl::Float>("Alpha");
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_valtorgb(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- /* stack order in: fac */
- /* stack order out: col, alpha */
-
- if (node->storage) {
- float fac;
- nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
-
- BKE_colorband_evaluate((ColorBand *)node->storage, fac, out[0]->vec);
- out[1]->vec[0] = out[0]->vec[3];
- }
+ b.add_input<decl::Float>(N_("Fac")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Alpha"));
}
static void node_shader_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node)
@@ -172,64 +149,21 @@ static void sh_node_valtorgb_build_multi_function(
builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band);
}
-void register_node_type_sh_valtorgb(void)
-{
- static bNodeType ntype;
+} // namespace blender::nodes::node_shader_color_ramp_cc
- sh_fn_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_valtorgb_declare;
- node_type_init(&ntype, node_shader_init_valtorgb);
- node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage);
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_valtorgb);
- node_type_gpu(&ntype, gpu_shader_valtorgb);
- ntype.build_multi_function = sh_node_valtorgb_build_multi_function;
-
- nodeRegisterType(&ntype);
-}
-
-namespace blender::nodes {
-
-static void sh_node_rgbtobw_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Color>("Color").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_output<decl::Float>("Val");
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_rgbtobw(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- /* stack order out: bw */
- /* stack order in: col */
- float col[3];
- nodestack_get_vec(col, SOCK_VECTOR, in[0]);
-
- out[0]->vec[0] = IMB_colormanagement_get_luminance(col);
-}
-
-static int gpu_shader_rgbtobw(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
+void register_node_type_sh_valtorgb()
{
- return GPU_stack_link(mat, node, "rgbtobw", in, out);
-}
+ namespace file_ns = blender::nodes::node_shader_color_ramp_cc;
-void register_node_type_sh_rgbtobw(void)
-{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_rgbtobw_declare;
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_rgbtobw);
- node_type_gpu(&ntype, gpu_shader_rgbtobw);
+ sh_fn_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_valtorgb_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_valtorgb);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, file_ns::gpu_shader_valtorgb);
+ ntype.build_multi_function = file_ns::sh_node_valtorgb_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c
deleted file mode 100644
index 4df5add7151..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_common.c
+++ /dev/null
@@ -1,270 +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) 2006 Blender Foundation.
- * All rights reserved.
- * Juho Vepsäläinen
- */
-
-/** \file
- * \ingroup shdnodes
- */
-
-#include "DNA_node_types.h"
-
-#include "BLI_utildefines.h"
-
-#include "BKE_node.h"
-
-#include "NOD_common.h"
-#include "node_common.h"
-#include "node_exec.h"
-#include "node_shader_util.h"
-
-#include "RNA_access.h"
-
-static void copy_stack(bNodeStack *to, bNodeStack *from)
-{
- if (to != from) {
- copy_v4_v4(to->vec, from->vec);
- to->data = from->data;
- to->datatype = from->datatype;
-
- /* tag as copy to prevent freeing */
- to->is_copy = 1;
- }
-}
-
-static void move_stack(bNodeStack *to, bNodeStack *from)
-{
- if (to != from) {
- copy_v4_v4(to->vec, from->vec);
- to->data = from->data;
- to->datatype = from->datatype;
- to->is_copy = from->is_copy;
-
- from->data = NULL;
- from->is_copy = 0;
- }
-}
-
-/**** GROUP ****/
-
-static void *group_initexec(bNodeExecContext *context, bNode *node, bNodeInstanceKey key)
-{
- bNodeTree *ngroup = (bNodeTree *)node->id;
- bNodeTreeExec *exec;
-
- if (!ngroup) {
- return NULL;
- }
-
- /* initialize the internal node tree execution */
- exec = ntreeShaderBeginExecTree_internal(context, ngroup, key);
-
- return exec;
-}
-
-static void group_freeexec(void *nodedata)
-{
- bNodeTreeExec *gexec = (bNodeTreeExec *)nodedata;
-
- if (gexec) {
- ntreeShaderEndExecTree_internal(gexec);
- }
-}
-
-/* Copy inputs to the internal stack.
- */
-static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack)
-{
- bNodeTree *ngroup = (bNodeTree *)gnode->id;
- bNode *node;
- bNodeSocket *sock;
- bNodeStack *ns;
- int a;
-
- for (node = ngroup->nodes.first; node; node = node->next) {
- if (node->type == NODE_GROUP_INPUT) {
- for (sock = node->outputs.first, a = 0; sock; sock = sock->next, a++) {
- ns = node_get_socket_stack(gstack, sock);
- if (ns) {
- copy_stack(ns, in[a]);
- }
- }
- }
- }
-}
-
-/* Copy internal results to the external outputs.
- */
-static void group_move_outputs(bNode *gnode, bNodeStack **out, bNodeStack *gstack)
-{
- bNodeTree *ngroup = (bNodeTree *)gnode->id;
- bNode *node;
- bNodeSocket *sock;
- bNodeStack *ns;
- int a;
-
- for (node = ngroup->nodes.first; node; node = node->next) {
- if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
- for (sock = node->inputs.first, a = 0; sock; sock = sock->next, a++) {
- ns = node_get_socket_stack(gstack, sock);
- if (ns) {
- move_stack(out[a], ns);
- }
- }
- break; /* only one active output node */
- }
- }
-}
-
-static void group_execute(void *data,
- int thread,
- struct bNode *node,
- bNodeExecData *execdata,
- struct bNodeStack **in,
- struct bNodeStack **out)
-{
- bNodeTreeExec *exec = execdata->data;
- bNodeThreadStack *nts;
-
- if (!exec) {
- return;
- }
-
- /* XXX same behavior as trunk: all nodes inside group are executed.
- * it's stupid, but just makes it work. compo redesign will do this better.
- */
- {
- bNode *inode;
- for (inode = exec->nodetree->nodes.first; inode; inode = inode->next) {
- inode->need_exec = 1;
- }
- }
-
- nts = ntreeGetThreadStack(exec, thread);
-
- group_copy_inputs(node, in, nts->stack);
- ntreeExecThreadNodes(exec, nts, data, thread);
- group_move_outputs(node, out, nts->stack);
-
- ntreeReleaseThreadStack(nts);
-}
-
-static void group_gpu_copy_inputs(bNode *gnode, GPUNodeStack *in, bNodeStack *gstack)
-{
- bNodeTree *ngroup = (bNodeTree *)gnode->id;
- bNode *node;
- bNodeSocket *sock;
- bNodeStack *ns;
- int a;
-
- for (node = ngroup->nodes.first; node; node = node->next) {
- if (node->type == NODE_GROUP_INPUT) {
- for (sock = node->outputs.first, a = 0; sock; sock = sock->next, a++) {
- ns = node_get_socket_stack(gstack, sock);
- if (ns) {
- /* convert the external gpu stack back to internal node stack data */
- node_data_from_gpu_stack(ns, &in[a]);
- }
- }
- }
- }
-}
-
-/* Copy internal results to the external outputs.
- */
-static void group_gpu_move_outputs(bNode *gnode, GPUNodeStack *out, bNodeStack *gstack)
-{
- bNodeTree *ngroup = (bNodeTree *)gnode->id;
- bNode *node;
- bNodeSocket *sock;
- bNodeStack *ns;
- int a;
-
- for (node = ngroup->nodes.first; node; node = node->next) {
- if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
- for (sock = node->inputs.first, a = 0; sock; sock = sock->next, a++) {
- ns = node_get_socket_stack(gstack, sock);
- if (ns) {
- /* convert the node stack data result back to gpu stack */
- node_gpu_stack_from_data(&out[a], sock->type, ns);
- }
- }
- break; /* only one active output node */
- }
- }
-}
-
-static int gpu_group_execute(
- GPUMaterial *mat, bNode *node, bNodeExecData *execdata, GPUNodeStack *in, GPUNodeStack *out)
-{
- bNodeTreeExec *exec = execdata->data;
-
- if (!node->id) {
- return 0;
- }
-
- group_gpu_copy_inputs(node, in, exec->stack);
- ntreeExecGPUNodes(exec, mat, NULL);
- group_gpu_move_outputs(node, out, exec->stack);
-
- return 1;
-}
-
-void register_node_type_sh_group(void)
-{
- static bNodeType ntype;
-
- /* NOTE: cannot use #sh_node_type_base for node group, because it would map the node type
- * to the shared #NODE_GROUP integer type id. */
-
- node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT);
- ntype.type = NODE_GROUP;
- ntype.poll = sh_node_poll_default;
- ntype.poll_instance = node_group_poll_instance;
- ntype.insert_link = node_insert_link_default;
- ntype.update_internal_links = node_update_internal_links_default;
- ntype.rna_ext.srna = RNA_struct_find("ShaderNodeGroup");
- BLI_assert(ntype.rna_ext.srna != NULL);
- RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
-
- node_type_socket_templates(&ntype, NULL, NULL);
- node_type_size(&ntype, 140, 60, 400);
- node_type_label(&ntype, node_group_label);
- node_type_group_update(&ntype, node_group_update);
- node_type_exec(&ntype, group_initexec, group_freeexec, group_execute);
- node_type_gpu(&ntype, gpu_group_execute);
-
- nodeRegisterType(&ntype);
-}
-
-void register_node_type_sh_custom_group(bNodeType *ntype)
-{
- /* These methods can be overridden but need a default implementation otherwise. */
- if (ntype->poll == NULL) {
- ntype->poll = sh_node_poll_default;
- }
- if (ntype->insert_link == NULL) {
- ntype->insert_link = node_insert_link_default;
- }
- if (ntype->update_internal_links == NULL) {
- ntype->update_internal_links = node_update_internal_links_default;
- }
-
- node_type_exec(ntype, group_initexec, group_freeexec, group_execute);
- node_type_gpu(ntype, gpu_group_execute);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_common.cc b/source/blender/nodes/shader/nodes/node_shader_common.cc
new file mode 100644
index 00000000000..3f0fff34533
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_common.cc
@@ -0,0 +1,130 @@
+/*
+ * 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) 2006 Blender Foundation.
+ * All rights reserved.
+ * Juho Vepsäläinen
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "DNA_node_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_node.h"
+
+#include "NOD_common.h"
+#include "node_common.h"
+#include "node_exec.h"
+#include "node_shader_util.hh"
+
+#include "RNA_access.h"
+
+/**** GROUP ****/
+
+static void group_gpu_copy_inputs(bNode *gnode, GPUNodeStack *in, bNodeStack *gstack)
+{
+ bNodeTree *ngroup = (bNodeTree *)gnode->id;
+
+ LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
+ if (node->type == NODE_GROUP_INPUT) {
+ int a;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, a) {
+ bNodeStack *ns = node_get_socket_stack(gstack, sock);
+ if (ns) {
+ /* convert the external gpu stack back to internal node stack data */
+ node_data_from_gpu_stack(ns, &in[a]);
+ }
+ }
+ }
+ }
+}
+
+/* Copy internal results to the external outputs.
+ */
+static void group_gpu_move_outputs(bNode *gnode, GPUNodeStack *out, bNodeStack *gstack)
+{
+ bNodeTree *ngroup = (bNodeTree *)gnode->id;
+
+ LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
+ if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
+ int a;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->inputs, a) {
+ bNodeStack *ns = node_get_socket_stack(gstack, sock);
+ if (ns) {
+ /* convert the node stack data result back to gpu stack */
+ node_gpu_stack_from_data(&out[a], sock->type, ns);
+ }
+ }
+ break; /* only one active output node */
+ }
+ }
+}
+
+static int gpu_group_execute(
+ GPUMaterial *mat, bNode *node, bNodeExecData *execdata, GPUNodeStack *in, GPUNodeStack *out)
+{
+ bNodeTreeExec *exec = static_cast<bNodeTreeExec *>(execdata->data);
+
+ if (!node->id) {
+ return 0;
+ }
+
+ group_gpu_copy_inputs(node, in, exec->stack);
+ ntreeExecGPUNodes(exec, mat, nullptr);
+ group_gpu_move_outputs(node, out, exec->stack);
+
+ return 1;
+}
+
+void register_node_type_sh_group()
+{
+ static bNodeType ntype;
+
+ /* NOTE: cannot use #sh_node_type_base for node group, because it would map the node type
+ * to the shared #NODE_GROUP integer type id. */
+
+ node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP);
+ ntype.type = NODE_GROUP;
+ ntype.poll = sh_node_poll_default;
+ ntype.poll_instance = node_group_poll_instance;
+ ntype.insert_link = node_insert_link_default;
+ ntype.rna_ext.srna = RNA_struct_find("ShaderNodeGroup");
+ BLI_assert(ntype.rna_ext.srna != nullptr);
+ RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
+
+ node_type_size(&ntype, 140, 60, 400);
+ ntype.labelfunc = node_group_label;
+ node_type_group_update(&ntype, node_group_update);
+ node_type_gpu(&ntype, gpu_group_execute);
+
+ nodeRegisterType(&ntype);
+}
+
+void register_node_type_sh_custom_group(bNodeType *ntype)
+{
+ /* These methods can be overridden but need a default implementation otherwise. */
+ if (ntype->poll == nullptr) {
+ ntype->poll = sh_node_poll_default;
+ }
+ if (ntype->insert_link == nullptr) {
+ ntype->insert_link = node_insert_link_default;
+ }
+
+ node_type_gpu(ntype, gpu_group_execute);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc
index 887cc84bb76..bce59a60033 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc
@@ -21,33 +21,16 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_curves_cc {
static void sh_node_curve_vec_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Fac").min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Vector>("Vector").min(-1.0f).max(1.0f);
- b.add_output<decl::Vector>("Vector");
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_curve_vec(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float vec[3];
-
- /* stack order input: vec */
- /* stack order output: vec */
- nodestack_get_vec(vec, SOCK_VECTOR, in[1]);
- BKE_curvemapping_evaluate3F((CurveMapping *)node->storage, out[0]->vec, vec);
+ b.add_input<decl::Float>(N_("Fac")).min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Vector")).min(-1.0f).max(1.0f);
+ b.add_output<decl::Vector>(N_("Vector"));
}
static void node_shader_init_curve_vec(bNodeTree *UNUSED(ntree), bNode *node)
@@ -152,53 +135,35 @@ static void sh_node_curve_vec_build_multi_function(
builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap);
}
-void register_node_type_sh_curve_vec(void)
+} // namespace blender::nodes::node_shader_curves_cc
+
+void register_node_type_sh_curve_vec()
{
+ namespace file_ns = blender::nodes::node_shader_curves_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR, 0);
- ntype.declare = blender::nodes::sh_node_curve_vec_declare;
- node_type_init(&ntype, node_shader_init_curve_vec);
+ sh_fn_node_type_base(&ntype, SH_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::sh_node_curve_vec_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_curve_vec);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
- node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_vec);
- node_type_gpu(&ntype, gpu_shader_curve_vec);
- ntype.build_multi_function = sh_node_curve_vec_build_multi_function;
+ node_type_gpu(&ntype, file_ns::gpu_shader_curve_vec);
+ ntype.build_multi_function = file_ns::sh_node_curve_vec_build_multi_function;
nodeRegisterType(&ntype);
}
/* **************** CURVE RGB ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_shader_curves_cc {
static void sh_node_curve_rgb_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>("Fac").min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>("Color").default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_output<decl::Color>("Color");
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_curve_rgb(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float vec[3];
- float fac;
-
- /* stack order input: vec */
- /* stack order output: vec */
- nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
- nodestack_get_vec(vec, SOCK_VECTOR, in[1]);
- BKE_curvemapping_evaluateRGBF((CurveMapping *)node->storage, out[0]->vec, vec);
- if (fac != 1.0f) {
- interp_v3_v3v3(out[0]->vec, vec, out[0]->vec, fac);
- }
+ b.is_function_node();
+ b.add_input<decl::Float>(N_("Fac")).min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Color"));
}
static void node_shader_init_curve_rgb(bNodeTree *UNUSED(ntree), bNode *node)
@@ -328,18 +293,148 @@ static void sh_node_curve_rgb_build_multi_function(
builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap);
}
-void register_node_type_sh_curve_rgb(void)
+} // namespace blender::nodes::node_shader_curves_cc
+
+void register_node_type_sh_curve_rgb()
+{
+ namespace file_ns = blender::nodes::node_shader_curves_cc;
+
+ static bNodeType ntype;
+
+ sh_fn_node_type_base(&ntype, SH_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::sh_node_curve_rgb_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_curve_rgb);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
+ node_type_gpu(&ntype, file_ns::gpu_shader_curve_rgb);
+ ntype.build_multi_function = file_ns::sh_node_curve_rgb_build_multi_function;
+
+ nodeRegisterType(&ntype);
+}
+
+/* **************** CURVE FLOAT ******************** */
+
+namespace blender::nodes::node_shader_curves_cc {
+
+static void sh_node_curve_float_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Float>(N_("Factor"))
+ .min(0.0f)
+ .max(1.0f)
+ .default_value(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).is_default_link_socket();
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+static void node_shader_init_curve_float(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->storage = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+}
+
+static int gpu_shader_curve_float(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ float *array, layer;
+ int size;
+
+ CurveMapping *cumap = (CurveMapping *)node->storage;
+
+ BKE_curvemapping_table_F(cumap, &array, &size);
+ GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
+
+ float ext_xyz[4];
+ float range_x;
+
+ const CurveMap *cm = &cumap->cm[0];
+ ext_xyz[0] = cm->mintable;
+ ext_xyz[2] = cm->maxtable;
+ range_x = 1.0f / max_ff(1e-8f, cm->maxtable - cm->mintable);
+ /* Compute extrapolation gradients. */
+ if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) != 0) {
+ ext_xyz[1] = (cm->ext_in[0] != 0.0f) ? (cm->ext_in[1] / (cm->ext_in[0] * range_x)) : 1e8f;
+ ext_xyz[3] = (cm->ext_out[0] != 0.0f) ? (cm->ext_out[1] / (cm->ext_out[0] * range_x)) : 1e8f;
+ }
+ else {
+ ext_xyz[1] = 0.0f;
+ ext_xyz[3] = 0.0f;
+ }
+ return GPU_stack_link(mat,
+ node,
+ "curve_float",
+ in,
+ out,
+ tex,
+ GPU_constant(&layer),
+ GPU_uniform(&range_x),
+ GPU_uniform(ext_xyz));
+}
+
+class CurveFloatFunction : public blender::fn::MultiFunction {
+ private:
+ const CurveMapping &cumap_;
+
+ public:
+ CurveFloatFunction(const CurveMapping &cumap) : cumap_(cumap)
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Curve Float"};
+ signature.single_input<float>("Factor");
+ signature.single_input<float>("Value");
+ signature.single_output<float>("Value");
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float> &fac = params.readonly_single_input<float>(0, "Factor");
+ const blender::VArray<float> &val_in = params.readonly_single_input<float>(1, "Value");
+ blender::MutableSpan<float> val_out = params.uninitialized_single_output<float>(2, "Value");
+
+ for (int64_t i : mask) {
+ val_out[i] = BKE_curvemapping_evaluateF(&cumap_, 0, val_in[i]);
+ if (fac[i] != 1.0f) {
+ val_out[i] = (1.0f - fac[i]) * val_in[i] + fac[i] * val_out[i];
+ }
+ }
+ }
+};
+
+static void sh_node_curve_float_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
+{
+ bNode &bnode = builder.node();
+ CurveMapping *cumap = (CurveMapping *)bnode.storage;
+ BKE_curvemapping_init(cumap);
+ builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap);
+}
+
+} // namespace blender::nodes::node_shader_curves_cc
+
+void register_node_type_sh_curve_float()
{
+ namespace file_ns = blender::nodes::node_shader_curves_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::sh_node_curve_rgb_declare;
- node_type_init(&ntype, node_shader_init_curve_rgb);
+ sh_fn_node_type_base(&ntype, SH_NODE_CURVE_FLOAT, "Float Curve", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_curve_float_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_curve_float);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
- node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_rgb);
- node_type_gpu(&ntype, gpu_shader_curve_rgb);
- ntype.build_multi_function = sh_node_curve_rgb_build_multi_function;
+ node_type_gpu(&ntype, file_ns::gpu_shader_curve_float);
+ ntype.build_multi_function = file_ns::sh_node_curve_float_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_displacement.c b/source/blender/nodes/shader/nodes/node_shader_displacement.cc
index c88083d109f..47af2447440 100644
--- a/source/blender/nodes/shader/nodes/node_shader_displacement.c
+++ b/source/blender/nodes/shader/nodes/node_shader_displacement.cc
@@ -17,22 +17,18 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_displacement_cc {
-static bNodeSocketTemplate sh_node_displacement_in[] = {
- {SOCK_FLOAT, N_("Height"), 0.00f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Midlevel"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Scale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_displacement_out[] = {
- {SOCK_VECTOR, N_("Displacement"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Height")).default_value(0.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Midlevel")).default_value(0.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Scale")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Vector>(N_("Displacement"));
+}
static void node_shader_init_displacement(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -63,16 +59,19 @@ static int gpu_shader_displacement(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_displacement_world", in, out);
}
+} // namespace blender::nodes::node_shader_displacement_cc
+
/* node type definition */
-void register_node_type_sh_displacement(void)
+void register_node_type_sh_displacement()
{
+ namespace file_ns = blender::nodes::node_shader_displacement_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_DISPLACEMENT, "Displacement", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_displacement_in, sh_node_displacement_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_init(&ntype, node_shader_init_displacement);
- node_type_gpu(&ntype, gpu_shader_displacement);
+ sh_node_type_base(&ntype, SH_NODE_DISPLACEMENT, "Displacement", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_displacement);
+ node_type_gpu(&ntype, file_ns::gpu_shader_displacement);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c
deleted file mode 100644
index 191a8b2a376..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c
+++ /dev/null
@@ -1,103 +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.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_eevee_specular_in[] = {
- {SOCK_RGBA, N_("Base Color"), 0.8f, 0.8f, 0.8f, 1.0f},
- {SOCK_RGBA, N_("Specular"), 0.03f, 0.03f, 0.03f, 1.0f},
- {SOCK_FLOAT, N_("Roughness"), 0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Emissive Color"), 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Transparency"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Clear Coat"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Clear Coat Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR,
- N_("Clear Coat Normal"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_NONE,
- SOCK_HIDE_VALUE},
- {SOCK_FLOAT,
- N_("Ambient Occlusion"),
- 1.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_NONE,
- SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_eevee_specular_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
-
-static int node_shader_gpu_eevee_specular(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- static float one = 1.0f;
-
- /* Normals */
- if (!in[5].link) {
- GPU_link(mat, "world_normals_get", &in[5].link);
- }
-
- /* Clearcoat Normals */
- if (!in[8].link) {
- GPU_link(mat, "world_normals_get", &in[8].link);
- }
-
- /* Occlusion */
- if (!in[9].link) {
- GPU_link(mat, "set_value", GPU_constant(&one), &in[9].link);
- }
-
- GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY);
-
- GPU_stack_link(mat, node, "node_eevee_specular", in, out);
- return GPU_stack_eval_link(mat, node, "node_eevee_specular_eval", in, out);
-}
-
-/* node type definition */
-void register_node_type_sh_eevee_specular(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_EEVEE_SPECULAR, "Specular BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_eevee_specular_in, sh_node_eevee_specular_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_eevee_specular);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc
new file mode 100644
index 00000000000..e4c80725c8e
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_eevee_specular_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Base Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("Specular")).default_value({0.03f, 0.03f, 0.03f, 1.0f});
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.2f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Emissive Color")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Transparency"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_input<decl::Float>(N_("Clear Coat"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Clear Coat Roughness"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Clear Coat Normal")).hide_value();
+ b.add_input<decl::Float>(N_("Ambient Occlusion")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
+
+static int node_shader_gpu_eevee_specular(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ static float one = 1.0f;
+
+ /* Normals */
+ if (!in[5].link) {
+ GPU_link(mat, "world_normals_get", &in[5].link);
+ }
+
+ /* Clearcoat Normals */
+ if (!in[8].link) {
+ GPU_link(mat, "world_normals_get", &in[8].link);
+ }
+
+ /* Occlusion */
+ if (!in[9].link) {
+ GPU_link(mat, "set_value", GPU_constant(&one), &in[9].link);
+ }
+
+ GPU_material_flag_set(mat, static_cast<eGPUMatFlag>(GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY));
+
+ return GPU_stack_link(mat, node, "node_eevee_specular", in, out, GPU_constant(&node->ssr_id));
+}
+
+} // namespace blender::nodes::node_shader_eevee_specular_cc
+
+/* node type definition */
+void register_node_type_sh_eevee_specular()
+{
+ namespace file_ns = blender::nodes::node_shader_eevee_specular_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_EEVEE_SPECULAR, "Specular BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_eevee_specular);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_emission.c b/source/blender/nodes/shader/nodes/node_shader_emission.cc
index 64bef6adb46..ea36763578f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_emission.c
+++ b/source/blender/nodes/shader/nodes/node_shader_emission.cc
@@ -17,21 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_emission_cc {
-static bNodeSocketTemplate sh_node_emission_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000000.0f},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_emission_out[] = {
- {SOCK_SHADER, N_("Emission")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Strength")).default_value(1.0f).min(0.0f).max(1000000.0f);
+ b.add_output<decl::Shader>(N_("Emission"));
+}
static int node_shader_gpu_emission(GPUMaterial *mat,
bNode *node,
@@ -39,20 +34,21 @@ static int node_shader_gpu_emission(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- GPU_material_flag_set(mat, GPU_MATFLAG_EMISSION);
- return GPU_stack_link(mat, node, "node_emission", in, out);
+ return GPU_stack_link(mat, node, "node_emission", in, out, GPU_builtin(GPU_VIEW_NORMAL));
}
+} // namespace blender::nodes::node_shader_emission_cc
+
/* node type definition */
-void register_node_type_sh_emission(void)
+void register_node_type_sh_emission()
{
+ namespace file_ns = blender::nodes::node_shader_emission_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_EMISSION, "Emission", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_emission_in, sh_node_emission_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_emission);
+ sh_node_type_base(&ntype, SH_NODE_EMISSION, "Emission", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_emission);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.cc
index 9b25af912ef..19eb79e2138 100644
--- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c
+++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.cc
@@ -17,19 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Fresnel ******************** */
-static bNodeSocketTemplate sh_node_fresnel_in[] = {
- {SOCK_FLOAT, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_fresnel_cc {
-static bNodeSocketTemplate sh_node_fresnel_out[] = {
- {SOCK_FLOAT, N_("Fac"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("IOR")).default_value(1.45f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Float>(N_("Fac"));
+}
static int node_shader_gpu_fresnel(GPUMaterial *mat,
bNode *node,
@@ -44,26 +41,18 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_fresnel", in, out);
}
-static void node_shader_exec_fresnel(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **UNUSED(in),
- bNodeStack **UNUSED(out))
-{
-}
+} // namespace blender::nodes::node_shader_fresnel_cc
/* node type definition */
-void register_node_type_sh_fresnel(void)
+void register_node_type_sh_fresnel()
{
+ namespace file_ns = blender::nodes::node_shader_fresnel_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_FRESNEL, "Fresnel", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_fresnel_in, sh_node_fresnel_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_fresnel);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_fresnel);
+ sh_node_type_base(&ntype, SH_NODE_FRESNEL, "Fresnel", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_fresnel);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c
deleted file mode 100644
index b48838e5f56..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_gamma.c
+++ /dev/null
@@ -1,73 +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) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-#include "node_shader_util.h"
-
-/* **************** Gamma Tools ******************** */
-
-static bNodeSocketTemplate sh_node_gamma_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Gamma"), 1.0f, 0.0f, 0.0f, 0.0f, 0.001f, 10.0f, PROP_UNSIGNED},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_gamma_out[] = {
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
-
-static void node_shader_exec_gamma(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float col[3];
- float gamma;
- nodestack_get_vec(col, SOCK_VECTOR, in[0]);
- nodestack_get_vec(&gamma, SOCK_FLOAT, in[1]);
-
- out[0]->vec[0] = col[0] > 0.0f ? powf(col[0], gamma) : col[0];
- out[0]->vec[1] = col[1] > 0.0f ? powf(col[1], gamma) : col[1];
- out[0]->vec[2] = col[2] > 0.0f ? powf(col[2], gamma) : col[2];
-}
-
-static int node_shader_gpu_gamma(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- return GPU_stack_link(mat, node, "node_gamma", in, out);
-}
-
-void register_node_type_sh_gamma(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_gamma_in, sh_node_gamma_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_gamma);
- node_type_gpu(&ntype, node_shader_gpu_gamma);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.cc b/source/blender/nodes/shader/nodes/node_shader_gamma.cc
new file mode 100644
index 00000000000..98a287b08da
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_gamma.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.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_gamma_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Gamma"))
+ .default_value(1.0f)
+ .min(0.001f)
+ .max(10.0f)
+ .subtype(PROP_UNSIGNED);
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+static int node_shader_gpu_gamma(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "node_gamma", in, out);
+}
+
+} // namespace blender::nodes::node_shader_gamma_cc
+
+void register_node_type_sh_gamma()
+{
+ namespace file_ns = blender::nodes::node_shader_gamma_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_gamma);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.cc
index 633f071ab86..35eef95adb5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geometry.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geometry.cc
@@ -17,22 +17,22 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_geometry_cc {
-static bNodeSocketTemplate sh_node_geometry_out[] = {
- {SOCK_VECTOR, N_("Position"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Tangent"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("True Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Incoming"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Parametric"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Backfacing"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Pointiness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Random Per Island"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Position"));
+ b.add_output<decl::Vector>(N_("Normal"));
+ b.add_output<decl::Vector>(N_("Tangent"));
+ b.add_output<decl::Vector>(N_("True Normal"));
+ b.add_output<decl::Vector>(N_("Incoming"));
+ b.add_output<decl::Vector>(N_("Parametric"));
+ b.add_output<decl::Float>(N_("Backfacing"));
+ b.add_output<decl::Float>(N_("Pointiness"));
+ b.add_output<decl::Float>(N_("Random Per Island"));
+}
static int node_shader_gpu_geometry(GPUMaterial *mat,
bNode *node,
@@ -52,8 +52,8 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
const bool success = GPU_stack_link(mat, node, "node_geometry", in, out, orco_link);
- /* for each output */
- for (int i = 0; sh_node_geometry_out[i].type != -1; i++) {
+ int i;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) {
node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
/* Normalize some vectors after dFdx/dFdy offsets.
* This is the case for interpolated, non linear functions.
@@ -67,23 +67,25 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
out[i].link,
out[i].link,
&out[i].link,
- NULL);
+ nullptr);
}
}
return success;
}
+} // namespace blender::nodes::node_shader_geometry_cc
+
/* node type definition */
-void register_node_type_sh_geometry(void)
+void register_node_type_sh_geometry()
{
+ namespace file_ns = blender::nodes::node_shader_geometry_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_NEW_GEOMETRY, "Geometry", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_geometry_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_geometry);
+ sh_node_type_base(&ntype, SH_NODE_NEW_GEOMETRY, "Geometry", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_geometry);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_hair_info.c b/source/blender/nodes/shader/nodes/node_shader_hair_info.cc
index c721fb9c77a..12c29c40b1d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_hair_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_hair_info.cc
@@ -17,18 +17,19 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
-
-static bNodeSocketTemplate outputs[] = {
- {SOCK_FLOAT, N_("Is Strand"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Intercept"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Length"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Thickness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Tangent Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- // { SOCK_FLOAT, 0, N_("Fade"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Random")},
- {-1, ""},
-};
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_hair_info_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Is Strand"));
+ b.add_output<decl::Float>(N_("Intercept"));
+ b.add_output<decl::Float>(N_("Length"));
+ b.add_output<decl::Float>(N_("Thickness"));
+ b.add_output<decl::Vector>(N_("Tangent Normal"));
+ b.add_output<decl::Float>(N_("Random"));
+}
static int node_shader_gpu_hair_info(GPUMaterial *mat,
bNode *node,
@@ -43,16 +44,18 @@ static int node_shader_gpu_hair_info(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_hair_info", in, out, length_link);
}
+} // namespace blender::nodes::node_shader_hair_info_cc
+
/* node type definition */
-void register_node_type_sh_hair_info(void)
+void register_node_type_sh_hair_info()
{
+ namespace file_ns = blender::nodes::node_shader_hair_info_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_HAIR_INFO, "Hair Info", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, outputs);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_hair_info);
+ sh_node_type_base(&ntype, SH_NODE_HAIR_INFO, "Hair Info", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_hair_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_holdout.c b/source/blender/nodes/shader/nodes/node_shader_holdout.cc
index eb087183a0b..4f6f8a639de 100644
--- a/source/blender/nodes/shader/nodes/node_shader_holdout.c
+++ b/source/blender/nodes/shader/nodes/node_shader_holdout.cc
@@ -17,19 +17,14 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_holdout_cc {
-static bNodeSocketTemplate sh_node_holdout_in[] = {
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_holdout_out[] = {
- {SOCK_SHADER, N_("Holdout")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Shader>(N_("Holdout"));
+}
static int gpu_shader_rgb(GPUMaterial *mat,
bNode *node,
@@ -37,20 +32,21 @@ static int gpu_shader_rgb(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- GPU_material_flag_set(mat, GPU_MATFLAG_HOLDOUT);
return GPU_stack_link(mat, node, "node_holdout", in, out);
}
+} // namespace blender::nodes::node_shader_holdout_cc
+
/* node type definition */
-void register_node_type_sh_holdout(void)
+void register_node_type_sh_holdout()
{
+ namespace file_ns = blender::nodes::node_shader_holdout_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_HOLDOUT, "Holdout", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_holdout_in, sh_node_holdout_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_rgb);
+ sh_node_type_base(&ntype, SH_NODE_HOLDOUT, "Holdout", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_rgb);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
deleted file mode 100644
index 50eb5bf32c9..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
+++ /dev/null
@@ -1,99 +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) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** Hue Saturation ******************** */
-static bNodeSocketTemplate sh_node_hue_sat_in[] = {
- {SOCK_FLOAT, N_("Hue"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Saturation"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Value"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate sh_node_hue_sat_out[] = {
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
-
-/* NOTE: it would be possible to use CMP version for both nodes. */
-static void do_hue_sat_fac(
- bNode *UNUSED(node), float *out, float hue, float sat, float val, const float in[4], float fac)
-{
- if (fac != 0.0f && (hue != 0.5f || sat != 1.0f || val != 1.0f)) {
- float col[3], hsv[3], mfac = 1.0f - fac;
-
- rgb_to_hsv(in[0], in[1], in[2], hsv, hsv + 1, hsv + 2);
- hsv[0] = fmodf(hsv[0] + hue + 0.5f, 1.0f);
- hsv[1] = clamp_f(hsv[1] * sat, 0.0f, 1.0f);
- hsv[2] *= val;
- hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col + 1, col + 2);
-
- out[0] = mfac * in[0] + fac * col[0];
- out[1] = mfac * in[1] + fac * col[1];
- out[2] = mfac * in[2] + fac * col[2];
- }
- else {
- copy_v4_v4(out, in);
- }
-}
-
-static void node_shader_exec_hue_sat(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float hue, sat, val, fac;
- float col[4];
- nodestack_get_vec(&hue, SOCK_FLOAT, in[0]);
- nodestack_get_vec(&sat, SOCK_FLOAT, in[1]);
- nodestack_get_vec(&val, SOCK_FLOAT, in[2]);
- nodestack_get_vec(&fac, SOCK_FLOAT, in[3]);
- nodestack_get_vec(col, SOCK_RGBA, in[4]);
- do_hue_sat_fac(node, out[0]->vec, hue, sat, val, col, fac);
-}
-
-static int gpu_shader_hue_sat(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- return GPU_stack_link(mat, node, "hue_sat", in, out);
-}
-
-void register_node_type_sh_hue_sat(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_hue_sat_in, sh_node_hue_sat_out);
- node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_hue_sat);
- node_type_gpu(&ntype, gpu_shader_hue_sat);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc
new file mode 100644
index 00000000000..94b9a61c602
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc
@@ -0,0 +1,61 @@
+/*
+ * 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) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_hueSatVal_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Hue")).default_value(0.5f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Saturation")).default_value(1.0f).min(0.0f).max(2.0f);
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(2.0f);
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+static int gpu_shader_hue_sat(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "hue_sat", in, out);
+}
+
+} // namespace blender::nodes::node_shader_hueSatVal_cc
+
+void register_node_type_sh_hue_sat()
+{
+ namespace file_ns = blender::nodes::node_shader_hueSatVal_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_gpu(&ntype, file_ns::gpu_shader_hue_sat);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_ies_light.c b/source/blender/nodes/shader/nodes/node_shader_ies_light.c
deleted file mode 100644
index 9cc5fd46181..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_ies_light.c
+++ /dev/null
@@ -1,53 +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) 2018 Blender Foundation.
- * All rights reserved.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** IES Light ******************** */
-
-static bNodeSocketTemplate sh_node_tex_ies_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000000.0f, PROP_NONE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_tex_ies_out[] = {
- {SOCK_FLOAT, N_("Fac")},
- {-1, ""},
-};
-
-static void node_shader_init_tex_ies(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeShaderTexIES *tex = MEM_callocN(sizeof(NodeShaderTexIES), "NodeShaderIESLight");
- node->storage = tex;
-}
-
-/* node type definition */
-void register_node_type_sh_tex_ies(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_TEX_IES, "IES Texture", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_ies_in, sh_node_tex_ies_out);
- node_type_init(&ntype, node_shader_init_tex_ies);
- node_type_storage(
- &ntype, "NodeShaderTexIES", node_free_standard_storage, node_copy_standard_storage);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_ies_light.cc b/source/blender/nodes/shader/nodes/node_shader_ies_light.cc
new file mode 100644
index 00000000000..82f0a3045c9
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_ies_light.cc
@@ -0,0 +1,74 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_ies_light_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector")).hide_value();
+ b.add_input<decl::Float>(N_("Strength")).default_value(1.0f).min(0.0f).max(1000000.0f);
+ b.add_output<decl::Float>(N_("Fac"));
+}
+
+static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row;
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "mode", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+
+ row = uiLayoutRow(layout, true);
+
+ if (RNA_enum_get(ptr, "mode") == NODE_IES_INTERNAL) {
+ uiItemR(row, ptr, "ies", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ }
+ else {
+ uiItemR(row, ptr, "filepath", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ }
+}
+
+static void node_shader_init_tex_ies(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeShaderTexIES *tex = MEM_cnew<NodeShaderTexIES>("NodeShaderIESLight");
+ node->storage = tex;
+}
+
+} // namespace blender::nodes::node_shader_ies_light_cc
+
+/* node type definition */
+void register_node_type_sh_tex_ies()
+{
+ namespace file_ns = blender::nodes::node_shader_ies_light_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_TEX_IES, "IES Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_ies;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_ies);
+ node_type_storage(
+ &ntype, "NodeShaderTexIES", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.c b/source/blender/nodes/shader/nodes/node_shader_invert.c
deleted file mode 100644
index 0d6709a1968..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_invert.c
+++ /dev/null
@@ -1,78 +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 shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** INVERT ******************** */
-static bNodeSocketTemplate sh_node_invert_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""}};
-
-static bNodeSocketTemplate sh_node_invert_out[] = {{SOCK_RGBA, N_("Color")}, {-1, ""}};
-
-static void node_shader_exec_invert(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float col[3], icol[3], fac;
-
- nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
- nodestack_get_vec(col, SOCK_VECTOR, in[1]);
-
- icol[0] = 1.0f - col[0];
- icol[1] = 1.0f - col[1];
- icol[2] = 1.0f - col[2];
-
- /* if fac, blend result against original input */
- if (fac < 1.0f) {
- interp_v3_v3v3(out[0]->vec, col, icol, fac);
- }
- else {
- copy_v3_v3(out[0]->vec, icol);
- }
-}
-
-static int gpu_shader_invert(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- return GPU_stack_link(mat, node, "invert", in, out);
-}
-
-void register_node_type_sh_invert(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_invert_in, sh_node_invert_out);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_invert);
- node_type_gpu(&ntype, gpu_shader_invert);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.cc b/source/blender/nodes/shader/nodes/node_shader_invert.cc
new file mode 100644
index 00000000000..3b5f4cb1d38
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_invert.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.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_invert_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Color")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+static int gpu_shader_invert(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "invert", in, out);
+}
+
+} // namespace blender::nodes::node_shader_invert_cc
+
+void register_node_type_sh_invert()
+{
+ namespace file_ns = blender::nodes::node_shader_invert_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_invert);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c b/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc
index 599a44c2ec3..0294a0bde07 100644
--- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c
+++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc
@@ -17,21 +17,17 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Layer Weight ******************** */
+namespace blender::nodes::node_shader_layer_weight_cc {
-static bNodeSocketTemplate sh_node_layer_weight_in[] = {
- {SOCK_FLOAT, N_("Blend"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_layer_weight_out[] = {
- {SOCK_FLOAT, N_("Fresnel"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Facing"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Blend")).default_value(0.5f).min(0.0f).max(1.0f);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Float>(N_("Fresnel"));
+ b.add_output<decl::Float>(N_("Facing"));
+}
static int node_shader_gpu_layer_weight(GPUMaterial *mat,
bNode *node,
@@ -46,26 +42,18 @@ static int node_shader_gpu_layer_weight(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_layer_weight", in, out);
}
-static void node_shader_exec_layer_weight(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **UNUSED(in),
- bNodeStack **UNUSED(out))
-{
-}
+} // namespace blender::nodes::node_shader_layer_weight_cc
/* node type definition */
-void register_node_type_sh_layer_weight(void)
+void register_node_type_sh_layer_weight()
{
+ namespace file_ns = blender::nodes::node_shader_layer_weight_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_LAYER_WEIGHT, "Layer Weight", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_layer_weight_in, sh_node_layer_weight_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_layer_weight);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_layer_weight);
+ sh_node_type_base(&ntype, SH_NODE_LAYER_WEIGHT, "Layer Weight", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_layer_weight);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_light_falloff.c b/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc
index 22172221f77..50eea2b3643 100644
--- a/source/blender/nodes/shader/nodes/node_shader_light_falloff.c
+++ b/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc
@@ -17,24 +17,18 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** INPUT ********************* */
+namespace blender::nodes::node_shader_light_falloff_cc {
-static bNodeSocketTemplate sh_node_light_falloff_in[] = {
- {SOCK_FLOAT, N_("Strength"), 100.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000000.0f},
- {SOCK_FLOAT, N_("Smooth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {-1, ""},
-};
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_light_falloff_out[] = {
- {SOCK_FLOAT, N_("Quadratic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Linear"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Constant"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Strength")).default_value(100.0f).min(0.0f).max(1000000.0f);
+ b.add_input<decl::Float>(N_("Smooth")).default_value(0.0f).min(0.0f).max(1000.0f);
+ b.add_output<decl::Float>(N_("Quadratic"));
+ b.add_output<decl::Float>(N_("Linear"));
+ b.add_output<decl::Float>(N_("Constant"));
+}
static int node_shader_gpu_light_falloff(GPUMaterial *mat,
bNode *node,
@@ -45,17 +39,19 @@ static int node_shader_gpu_light_falloff(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_light_falloff", in, out);
}
+} // namespace blender::nodes::node_shader_light_falloff_cc
+
/* node type definition */
-void register_node_type_sh_light_falloff(void)
+void register_node_type_sh_light_falloff()
{
+ namespace file_ns = blender::nodes::node_shader_light_falloff_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_LIGHT_FALLOFF, "Light Falloff", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_light_falloff_in, sh_node_light_falloff_out);
+ sh_node_type_base(&ntype, SH_NODE_LIGHT_FALLOFF, "Light Falloff", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_light_falloff);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_light_falloff);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.c b/source/blender/nodes/shader/nodes/node_shader_light_path.c
deleted file mode 100644
index 45ad2133ee8..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_light_path.c
+++ /dev/null
@@ -1,62 +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.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_light_path_out[] = {
- {SOCK_FLOAT, N_("Is Camera Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Is Shadow Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Is Diffuse Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Is Glossy Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Is Singular Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Is Reflection Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Is Transmission Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Ray Length"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Ray Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Diffuse Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Glossy Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Transparent Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Transmission Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
-
-static int node_shader_gpu_light_path(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- return GPU_stack_link(mat, node, "node_light_path", in, out);
-}
-
-/* node type definition */
-void register_node_type_sh_light_path(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_LIGHT_PATH, "Light Path", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_light_path_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_light_path);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.cc b/source/blender/nodes/shader/nodes/node_shader_light_path.cc
new file mode 100644
index 00000000000..6fbd5751886
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_light_path.cc
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_light_path_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Is Camera Ray"));
+ b.add_output<decl::Float>(N_("Is Shadow Ray"));
+ b.add_output<decl::Float>(N_("Is Diffuse Ray"));
+ b.add_output<decl::Float>(N_("Is Glossy Ray"));
+ b.add_output<decl::Float>(N_("Is Singular Ray"));
+ b.add_output<decl::Float>(N_("Is Reflection Ray"));
+ b.add_output<decl::Float>(N_("Is Transmission Ray"));
+ b.add_output<decl::Float>(N_("Ray Length"));
+ b.add_output<decl::Float>(N_("Ray Depth"));
+ b.add_output<decl::Float>(N_("Diffuse Depth"));
+ b.add_output<decl::Float>(N_("Glossy Depth"));
+ b.add_output<decl::Float>(N_("Transparent Depth"));
+ b.add_output<decl::Float>(N_("Transmission Depth"));
+}
+
+static int node_shader_gpu_light_path(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "node_light_path", in, out);
+}
+
+} // namespace blender::nodes::node_shader_light_path_cc
+
+/* node type definition */
+void register_node_type_sh_light_path()
+{
+ namespace file_ns = blender::nodes::node_shader_light_path_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_LIGHT_PATH, "Light Path", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_light_path);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
index 5ea194ddc83..bc7ca661a77 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
@@ -21,49 +21,173 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include <algorithm>
+
+#include "node_shader_util.hh"
#include "BLI_math_base_safe.h"
-namespace blender::nodes {
+#include "NOD_socket_search_link.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_map_range_cc {
+
+NODE_STORAGE_FUNCS(NodeMapRange)
static void sh_node_map_range_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Value").min(-10000.0f).max(10000.0f).default_value(1.0f);
- b.add_input<decl::Float>("From Min").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("From Max").min(-10000.0f).max(10000.0f).default_value(1.0f);
- b.add_input<decl::Float>("To Min").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("To Max").min(-10000.0f).max(10000.0f).default_value(1.0f);
- b.add_input<decl::Float>("Steps").min(-10000.0f).max(10000.0f).default_value(4.0f);
- b.add_output<decl::Float>("Result");
-};
+ b.add_input<decl::Float>(N_("Value")).min(-10000.0f).max(10000.0f).default_value(1.0f);
+ b.add_input<decl::Float>(N_("From Min")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("From Max")).min(-10000.0f).max(10000.0f).default_value(1.0f);
+ b.add_input<decl::Float>(N_("To Min")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("To Max")).min(-10000.0f).max(10000.0f).default_value(1.0f);
+ b.add_input<decl::Float>(N_("Steps")).min(-10000.0f).max(10000.0f).default_value(4.0f);
+ b.add_input<decl::Vector>(N_("Vector")).min(0.0f).max(1.0f).hide_value();
+ b.add_input<decl::Vector>(N_("From Min"), "From_Min_FLOAT3");
+ b.add_input<decl::Vector>(N_("From Max"), "From_Max_FLOAT3").default_value(float3(1.0f));
+ b.add_input<decl::Vector>(N_("To Min"), "To_Min_FLOAT3");
+ b.add_input<decl::Vector>(N_("To Max"), "To_Max_FLOAT3").default_value(float3(1.0f));
+ b.add_input<decl::Vector>(N_("Steps"), "Steps_FLOAT3").default_value(float3(4.0f));
+ b.add_output<decl::Float>(N_("Result"));
+ b.add_output<decl::Vector>(N_("Vector"));
+}
-} // namespace blender::nodes
+static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "interpolation_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ if (!ELEM(RNA_enum_get(ptr, "interpolation_type"),
+ NODE_MAP_RANGE_SMOOTHSTEP,
+ NODE_MAP_RANGE_SMOOTHERSTEP)) {
+ uiItemR(layout, ptr, "clamp", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
-static void node_shader_update_map_range(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_shader_update_map_range(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sockSteps = nodeFindSocket(node, SOCK_IN, "Steps");
- nodeSetSocketAvailability(sockSteps, node->custom2 == NODE_MAP_RANGE_STEPPED);
+ const NodeMapRange &storage = node_storage(*node);
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const int type = (data_type == CD_PROP_FLOAT) ? SOCK_FLOAT : SOCK_VECTOR;
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ nodeSetSocketAvailability(ntree, socket, socket->type == type);
+ }
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ nodeSetSocketAvailability(ntree, socket, socket->type == type);
+ }
+
+ if (storage.interpolation_type != NODE_MAP_RANGE_STEPPED) {
+ if (type == SOCK_FLOAT) {
+ bNodeSocket *sockSteps = (bNodeSocket *)BLI_findlink(&node->inputs, 5);
+ nodeSetSocketAvailability(ntree, sockSteps, false);
+ }
+ else {
+ bNodeSocket *sockSteps = (bNodeSocket *)BLI_findlink(&node->inputs, 11);
+ nodeSetSocketAvailability(ntree, sockSteps, false);
+ }
+ }
}
static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node)
{
+ NodeMapRange *data = MEM_cnew<NodeMapRange>(__func__);
+ data->clamp = 1;
+ data->data_type = CD_PROP_FLOAT;
+ data->interpolation_type = NODE_MAP_RANGE_LINEAR;
node->custom1 = true; /* use_clamp */
node->custom2 = NODE_MAP_RANGE_LINEAR; /* interpolation */
+ node->storage = data;
}
-static const char *gpu_shader_get_name(int mode)
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ CustomDataType data_type;
+ int interpolation_type = NODE_MAP_RANGE_LINEAR;
+
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("ShaderNodeMapRange");
+ node_storage(node).data_type = data_type;
+ node_storage(node).interpolation_type = interpolation_type;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
+static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+{
+ switch (socket.type) {
+ case SOCK_FLOAT:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ return CD_PROP_FLOAT;
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ return CD_PROP_FLOAT3;
+ default:
+ return {};
+ }
+}
+
+static void node_map_range_gather_link_searches(GatherLinkSearchOpParams &params)
{
- switch (mode) {
- case NODE_MAP_RANGE_LINEAR:
- return "map_range_linear";
- case NODE_MAP_RANGE_STEPPED:
- return "map_range_stepped";
- case NODE_MAP_RANGE_SMOOTHSTEP:
- return "map_range_smoothstep";
- case NODE_MAP_RANGE_SMOOTHERSTEP:
- return "map_range_smootherstep";
+ const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ if (!type) {
+ return;
+ }
+
+ if (params.in_out() == SOCK_IN) {
+ if (*type == CD_PROP_FLOAT3) {
+ params.add_item(IFACE_("Vector"), SocketSearchOp{"Vector", *type}, 0);
+ }
+ else {
+ params.add_item(IFACE_("Value"), SocketSearchOp{"Value", *type}, 0);
+ }
+ params.add_item(IFACE_("From Min"), SocketSearchOp{"From Min", *type}, -1);
+ params.add_item(IFACE_("From Max"), SocketSearchOp{"From Max", *type}, -1);
+ params.add_item(IFACE_("To Min"), SocketSearchOp{"To Min", *type}, -2);
+ params.add_item(IFACE_("To Max"), SocketSearchOp{"To Max", *type}, -2);
+ params.add_item(IFACE_("Steps"), SocketSearchOp{"Steps", *type, NODE_MAP_RANGE_STEPPED}, -3);
+ }
+ else {
+ if (*type == CD_PROP_FLOAT3) {
+ params.add_item(IFACE_("Vector"), SocketSearchOp{"Vector", *type});
+ }
+ else {
+ params.add_item(IFACE_("Result"), SocketSearchOp{"Result", *type});
+ }
+ }
+}
+
+static const char *gpu_shader_get_name(int mode, bool use_vector)
+{
+ if (use_vector) {
+ switch (mode) {
+ case NODE_MAP_RANGE_LINEAR:
+ return "vector_map_range_linear";
+ case NODE_MAP_RANGE_STEPPED:
+ return "vector_map_range_stepped";
+ case NODE_MAP_RANGE_SMOOTHSTEP:
+ return "vector_map_range_smoothstep";
+ case NODE_MAP_RANGE_SMOOTHERSTEP:
+ return "vector_map_range_smootherstep";
+ }
+ }
+ else {
+ switch (mode) {
+ case NODE_MAP_RANGE_LINEAR:
+ return "map_range_linear";
+ case NODE_MAP_RANGE_STEPPED:
+ return "map_range_stepped";
+ case NODE_MAP_RANGE_SMOOTHSTEP:
+ return "map_range_smoothstep";
+ case NODE_MAP_RANGE_SMOOTHERSTEP:
+ return "map_range_smootherstep";
+ }
}
return nullptr;
@@ -75,22 +199,205 @@ static int gpu_shader_map_range(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- const char *name = gpu_shader_get_name(node->custom2);
-
+ const NodeMapRange &storage = node_storage(*node);
+ bool use_vector = (storage.data_type == CD_PROP_FLOAT3);
+ const char *name = gpu_shader_get_name(storage.interpolation_type, use_vector);
+ float clamp = storage.clamp ? 1.0f : 0.0f;
int ret = 0;
if (name != nullptr) {
- ret = GPU_stack_link(mat, node, name, in, out);
+ ret = GPU_stack_link(mat, node, name, in, out, GPU_constant(&clamp));
}
else {
- ret = GPU_stack_link(mat, node, "map_range_linear", in, out);
+ ret = GPU_stack_link(mat, node, "map_range_linear", in, out, GPU_constant(&clamp));
}
- if (ret && node->custom1 &&
- !ELEM(node->custom2, NODE_MAP_RANGE_SMOOTHSTEP, NODE_MAP_RANGE_SMOOTHERSTEP)) {
+ if (ret && storage.clamp && !use_vector &&
+ !ELEM(storage.interpolation_type, NODE_MAP_RANGE_SMOOTHSTEP, NODE_MAP_RANGE_SMOOTHERSTEP)) {
GPU_link(mat, "clamp_range", out[0].link, in[3].link, in[4].link, &out[0].link);
}
return ret;
}
+static inline float clamp_range(const float value, const float min, const float max)
+{
+ return (min > max) ? std::clamp(value, max, min) : std::clamp(value, min, max);
+}
+
+static float3 clamp_range(const float3 value, const float3 min, const float3 max)
+{
+ return float3(clamp_range(value.x, min.x, max.x),
+ clamp_range(value.y, min.y, max.y),
+ clamp_range(value.z, min.z, max.z));
+}
+
+static void map_range_vector_signature(blender::fn::MFSignatureBuilder *signature, bool use_steps)
+{
+ signature->single_input<float3>("Vector");
+ signature->single_input<float3>("From Min");
+ signature->single_input<float3>("From Max");
+ signature->single_input<float3>("To Min");
+ signature->single_input<float3>("To Max");
+ if (use_steps) {
+ signature->single_input<float3>("Steps");
+ }
+ signature->single_output<float3>("Vector");
+}
+
+class MapRangeVectorFunction : public blender::fn::MultiFunction {
+ private:
+ bool clamp_;
+
+ public:
+ MapRangeVectorFunction(bool clamp) : clamp_(clamp)
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Vector Map Range"};
+ map_range_vector_signature(&signature, false);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector");
+
+ for (int64_t i : mask) {
+ float3 factor = math::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ results[i] = factor * (to_max[i] - to_min[i]) + to_min[i];
+ }
+
+ if (clamp_) {
+ for (int64_t i : mask) {
+ results[i] = clamp_range(results[i], to_min[i], to_max[i]);
+ }
+ }
+ }
+};
+
+class MapRangeSteppedVectorFunction : public blender::fn::MultiFunction {
+ private:
+ bool clamp_;
+
+ public:
+ MapRangeSteppedVectorFunction(bool clamp) : clamp_(clamp)
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Vector Map Range Stepped"};
+ map_range_vector_signature(&signature, true);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ const blender::VArray<float3> &steps = params.readonly_single_input<float3>(5, "Steps");
+ blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(6, "Vector");
+
+ for (int64_t i : mask) {
+ float3 factor = math::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ factor = math::safe_divide(math::floor(factor * (steps[i] + 1.0f)), steps[i]);
+ results[i] = factor * (to_max[i] - to_min[i]) + to_min[i];
+ }
+
+ if (clamp_) {
+ for (int64_t i : mask) {
+ results[i] = clamp_range(results[i], to_min[i], to_max[i]);
+ }
+ }
+ }
+};
+
+class MapRangeSmoothstepVectorFunction : public blender::fn::MultiFunction {
+ public:
+ MapRangeSmoothstepVectorFunction()
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Vector Map Range Smoothstep"};
+ map_range_vector_signature(&signature, false);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector");
+
+ for (int64_t i : mask) {
+ float3 factor = math::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ clamp_v3(factor, 0.0f, 1.0f);
+ factor = (float3(3.0f) - 2.0f * factor) * (factor * factor);
+ results[i] = factor * (to_max[i] - to_min[i]) + to_min[i];
+ }
+ }
+};
+
+class MapRangeSmootherstepVectorFunction : public blender::fn::MultiFunction {
+ public:
+ MapRangeSmootherstepVectorFunction()
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Vector Map Range Smoothstep"};
+ map_range_vector_signature(&signature, false);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector");
+
+ for (int64_t i : mask) {
+ float3 factor = math::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ clamp_v3(factor, 0.0f, 1.0f);
+ factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f);
+ results[i] = factor * (to_max[i] - to_min[i]) + to_min[i];
+ }
+ }
+};
+
static void map_range_signature(blender::fn::MFSignatureBuilder *signature, bool use_steps)
{
signature->single_input<float>("Value");
@@ -140,8 +447,7 @@ class MapRangeFunction : public blender::fn::MultiFunction {
if (clamp_) {
for (int64_t i : mask) {
- results[i] = (to_min[i] > to_max[i]) ? clamp_f(results[i], to_max[i], to_min[i]) :
- clamp_f(results[i], to_min[i], to_max[i]);
+ results[i] = clamp_range(results[i], to_min[i], to_max[i]);
}
}
}
@@ -185,8 +491,7 @@ class MapRangeSteppedFunction : public blender::fn::MultiFunction {
if (clamp_) {
for (int64_t i : mask) {
- results[i] = (to_min[i] > to_max[i]) ? clamp_f(results[i], to_max[i], to_min[i]) :
- clamp_f(results[i], to_min[i], to_max[i]);
+ results[i] = clamp_range(results[i], to_min[i], to_max[i]);
}
}
}
@@ -265,58 +570,107 @@ class MapRangeSmootherstepFunction : public blender::fn::MultiFunction {
static void sh_node_map_range_build_multi_function(
blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &bnode = builder.node();
- bool clamp = bnode.custom1 != 0;
- int interpolation_type = bnode.custom2;
-
- switch (interpolation_type) {
- case NODE_MAP_RANGE_LINEAR: {
- if (clamp) {
- static MapRangeFunction fn_with_clamp{true};
- builder.set_matching_fn(fn_with_clamp);
- }
- else {
- static MapRangeFunction fn_without_clamp{false};
- builder.set_matching_fn(fn_without_clamp);
+ const NodeMapRange &storage = node_storage(builder.node());
+ bool clamp = storage.clamp != 0;
+ int interpolation_type = storage.interpolation_type;
+
+ switch (storage.data_type) {
+ case CD_PROP_FLOAT3:
+ switch (interpolation_type) {
+ case NODE_MAP_RANGE_LINEAR: {
+ if (clamp) {
+ static MapRangeVectorFunction fn_with_clamp{true};
+ builder.set_matching_fn(fn_with_clamp);
+ }
+ else {
+ static MapRangeVectorFunction fn_without_clamp{false};
+ builder.set_matching_fn(fn_without_clamp);
+ }
+ break;
+ }
+ case NODE_MAP_RANGE_STEPPED: {
+ if (clamp) {
+ static MapRangeSteppedVectorFunction fn_stepped_with_clamp{true};
+ builder.set_matching_fn(fn_stepped_with_clamp);
+ }
+ else {
+ static MapRangeSteppedVectorFunction fn_stepped_without_clamp{false};
+ builder.set_matching_fn(fn_stepped_without_clamp);
+ }
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHSTEP: {
+ static MapRangeSmoothstepVectorFunction smoothstep;
+ builder.set_matching_fn(smoothstep);
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHERSTEP: {
+ static MapRangeSmootherstepVectorFunction smootherstep;
+ builder.set_matching_fn(smootherstep);
+ break;
+ }
+ default:
+ break;
}
break;
- }
- case NODE_MAP_RANGE_STEPPED: {
- if (clamp) {
- static MapRangeSteppedFunction fn_stepped_with_clamp{true};
- builder.set_matching_fn(fn_stepped_with_clamp);
- }
- else {
- static MapRangeSteppedFunction fn_stepped_without_clamp{false};
- builder.set_matching_fn(fn_stepped_without_clamp);
+ case CD_PROP_FLOAT:
+ switch (interpolation_type) {
+ case NODE_MAP_RANGE_LINEAR: {
+ if (clamp) {
+ static MapRangeFunction fn_with_clamp{true};
+ builder.set_matching_fn(fn_with_clamp);
+ }
+ else {
+ static MapRangeFunction fn_without_clamp{false};
+ builder.set_matching_fn(fn_without_clamp);
+ }
+ break;
+ }
+ case NODE_MAP_RANGE_STEPPED: {
+ if (clamp) {
+ static MapRangeSteppedFunction fn_stepped_with_clamp{true};
+ builder.set_matching_fn(fn_stepped_with_clamp);
+ }
+ else {
+ static MapRangeSteppedFunction fn_stepped_without_clamp{false};
+ builder.set_matching_fn(fn_stepped_without_clamp);
+ }
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHSTEP: {
+ static MapRangeSmoothstepFunction smoothstep;
+ builder.set_matching_fn(smoothstep);
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHERSTEP: {
+ static MapRangeSmootherstepFunction smootherstep;
+ builder.set_matching_fn(smootherstep);
+ break;
+ }
+ default:
+ break;
}
break;
- }
- case NODE_MAP_RANGE_SMOOTHSTEP: {
- static MapRangeSmoothstepFunction smoothstep;
- builder.set_matching_fn(smoothstep);
- break;
- }
- case NODE_MAP_RANGE_SMOOTHERSTEP: {
- static MapRangeSmootherstepFunction smootherstep;
- builder.set_matching_fn(smootherstep);
- break;
- }
- default:
- break;
}
}
-void register_node_type_sh_map_range(void)
+} // namespace blender::nodes::node_shader_map_range_cc
+
+void register_node_type_sh_map_range()
{
- static bNodeType ntype;
+ namespace file_ns = blender::nodes::node_shader_map_range_cc;
- sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_map_range_declare;
- node_type_init(&ntype, node_shader_init_map_range);
- node_type_update(&ntype, node_shader_update_map_range);
- node_type_gpu(&ntype, gpu_shader_map_range);
- ntype.build_multi_function = sh_node_map_range_build_multi_function;
+ static bNodeType ntype;
+ sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_map_range_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_map_range;
+ node_type_init(&ntype, file_ns::node_shader_init_map_range);
+ node_type_storage(
+ &ntype, "NodeMapRange", node_free_standard_storage, node_copy_standard_storage);
+ node_type_update(&ntype, file_ns::node_shader_update_map_range);
+ node_type_gpu(&ntype, file_ns::gpu_shader_map_range);
+ ntype.build_multi_function = file_ns::sh_node_map_range_build_multi_function;
+ ntype.gather_link_search_ops = file_ns::node_map_range_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c
deleted file mode 100644
index 774e7fed029..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_mapping.c
+++ /dev/null
@@ -1,77 +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 shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** MAPPING ******************** */
-static bNodeSocketTemplate sh_node_mapping_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE},
- {SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
- {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
- {SOCK_VECTOR, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_XYZ},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_mapping_out[] = {
- {SOCK_VECTOR, N_("Vector")},
- {-1, ""},
-};
-
-static int gpu_shader_mapping(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- static const char *names[] = {
- [NODE_MAPPING_TYPE_POINT] = "mapping_point",
- [NODE_MAPPING_TYPE_TEXTURE] = "mapping_texture",
- [NODE_MAPPING_TYPE_VECTOR] = "mapping_vector",
- [NODE_MAPPING_TYPE_NORMAL] = "mapping_normal",
- };
-
- if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) {
- return GPU_stack_link(mat, node, names[node->custom1], in, out);
- }
-
- return 0;
-}
-
-static void node_shader_update_mapping(bNodeTree *UNUSED(ntree), bNode *node)
-{
- bNodeSocket *sock = nodeFindSocket(node, SOCK_IN, "Location");
- nodeSetSocketAvailability(
- sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE));
-}
-
-void register_node_type_sh_mapping(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_mapping_in, sh_node_mapping_out);
- node_type_gpu(&ntype, gpu_shader_mapping);
- node_type_update(&ntype, node_shader_update_mapping);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.cc b/source/blender/nodes/shader/nodes/node_shader_mapping.cc
new file mode 100644
index 00000000000..19c3a26796e
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_mapping.cc
@@ -0,0 +1,110 @@
+/*
+ * 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 shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_mapping_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(-FLT_MAX)
+ .max(FLT_MAX);
+ b.add_input<decl::Vector>(N_("Location"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(-FLT_MAX)
+ .max(FLT_MAX)
+ .subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("Rotation"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(-FLT_MAX)
+ .max(FLT_MAX)
+ .subtype(PROP_EULER);
+ b.add_input<decl::Vector>(N_("Scale"))
+ .default_value({1.0f, 1.0f, 1.0f})
+ .min(-FLT_MAX)
+ .max(FLT_MAX)
+ .subtype(PROP_XYZ);
+ b.add_output<decl::Vector>(N_("Vector"));
+}
+
+static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "vector_type", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+static const char *gpu_shader_get_name(int mode)
+{
+ switch (mode) {
+ case NODE_MAPPING_TYPE_POINT:
+ return "mapping_point";
+ case NODE_MAPPING_TYPE_TEXTURE:
+ return "mapping_texture";
+ case NODE_MAPPING_TYPE_VECTOR:
+ return "mapping_vector";
+ case NODE_MAPPING_TYPE_NORMAL:
+ return "mapping_normal";
+ }
+ return nullptr;
+}
+
+static int gpu_shader_mapping(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ if (gpu_shader_get_name(node->custom1)) {
+ return GPU_stack_link(mat, node, gpu_shader_get_name(node->custom1), in, out);
+ }
+
+ return 0;
+}
+
+static void node_shader_update_mapping(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *sock = nodeFindSocket(node, SOCK_IN, "Location");
+ nodeSetSocketAvailability(
+ ntree, sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE));
+}
+
+} // namespace blender::nodes::node_shader_mapping_cc
+
+void register_node_type_sh_mapping()
+{
+ namespace file_ns = blender::nodes::node_shader_mapping_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_mapping;
+ node_type_gpu(&ntype, file_ns::gpu_shader_mapping);
+ node_type_update(&ntype, file_ns::node_shader_update_mapping);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc
index 96d1be49c04..50585405cbf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_math.cc
@@ -21,24 +21,67 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
#include "NOD_math_functions.hh"
+#include "NOD_socket_search_link.hh"
+
+#include "RNA_enum_types.h"
/* **************** SCALAR MATH ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_shader_math_cc {
static void sh_node_math_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Value").default_value(0.5f).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Value", "Value_001").default_value(0.5f).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Value", "Value_002").default_value(0.5f).min(-10000.0f).max(10000.0f);
- b.add_output<decl::Float>("Value");
+ b.add_input<decl::Float>(N_("Value")).default_value(0.5f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Value"), "Value_001")
+ .default_value(0.5f)
+ .min(-10000.0f)
+ .max(10000.0f);
+ b.add_input<decl::Float>(N_("Value"), "Value_002")
+ .default_value(0.5f)
+ .min(-10000.0f)
+ .max(10000.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ NodeMathOperation mode = NODE_MATH_ADD;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("ShaderNodeMath");
+ node.custom1 = mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
};
-} // namespace blender::nodes
+static void sh_node_math_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ if (!params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ return;
+ }
+
+ const bool is_geometry_node_tree = params.node_tree().type == NTREE_GEOMETRY;
+ const int weight = ELEM(params.other_socket().type, SOCK_FLOAT, SOCK_BOOLEAN, SOCK_INT) ? 0 : -1;
+
+ for (const EnumPropertyItem *item = rna_enum_node_math_items; item->identifier != nullptr;
+ item++) {
+ if (item->name != nullptr && item->identifier[0] != '\0') {
+ const int gn_weight =
+ (is_geometry_node_tree &&
+ ELEM(item->value, NODE_MATH_COMPARE, NODE_MATH_GREATER_THAN, NODE_MATH_LESS_THAN)) ?
+ -1 :
+ weight;
+ params.add_item(
+ IFACE_(item->name), SocketSearchOp{"Value", (NodeMathOperation)item->value}, gn_weight);
+ }
+ }
+}
static const char *gpu_shader_get_name(int mode)
{
@@ -82,7 +125,8 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl_to_fl(
mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SO<float, float> fn{info.title_case_name, function};
+ static blender::fn::CustomMF_SI_SO<float, float> fn{info.title_case_name.c_str(),
+ function};
base_fn = &fn;
});
if (base_fn != nullptr) {
@@ -91,7 +135,7 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl_fl_to_fl(
mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{info.title_case_name,
+ static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{info.title_case_name.c_str(),
function};
base_fn = &fn;
});
@@ -102,7 +146,7 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl_fl_fl_to_fl(
mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{
- info.title_case_name, function};
+ info.title_case_name.c_str(), function};
base_fn = &fn;
});
if (base_fn != nullptr) {
@@ -154,16 +198,21 @@ static void sh_node_math_build_multi_function(blender::nodes::NodeMultiFunctionB
}
}
-void register_node_type_sh_math(void)
+} // namespace blender::nodes::node_shader_math_cc
+
+void register_node_type_sh_math()
{
+ namespace file_ns = blender::nodes::node_shader_math_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_math_declare;
- node_type_label(&ntype, node_math_label);
- node_type_gpu(&ntype, gpu_shader_math);
+ sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_math_declare;
+ ntype.labelfunc = node_math_label;
+ node_type_gpu(&ntype, file_ns::gpu_shader_math);
node_type_update(&ntype, node_math_update);
- ntype.build_multi_function = sh_node_math_build_multi_function;
+ ntype.build_multi_function = file_ns::sh_node_math_build_multi_function;
+ ntype.gather_link_search_ops = file_ns::sh_node_math_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
index d4d02e80ada..9678e86d289 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
@@ -21,45 +21,17 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_mix_rgb_cc {
static void sh_node_mix_rgb_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("Fac").default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>("Color1").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_input<decl::Color>("Color2").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_output<decl::Color>("Color");
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_mix_rgb(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- /* stack order in: fac, col1, col2 */
- /* stack order out: col */
- float col[3];
- float fac;
- float vec[3];
-
- nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
- CLAMP(fac, 0.0f, 1.0f);
-
- nodestack_get_vec(col, SOCK_VECTOR, in[1]);
- nodestack_get_vec(vec, SOCK_VECTOR, in[2]);
-
- ramp_blend(node->custom1, col, fac, vec);
- if (node->custom2 & SHD_MIXRGB_CLAMP) {
- CLAMP3(col, 0.0f, 1.0f);
- }
- copy_v3_v3(out[0]->vec, col);
+ b.add_input<decl::Float>(N_("Fac")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Color1")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_input<decl::Color>(N_("Color2")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_output<decl::Color>(N_("Color"));
}
static const char *gpu_shader_get_name(int mode)
@@ -183,16 +155,19 @@ static void sh_node_mix_rgb_build_multi_function(blender::nodes::NodeMultiFuncti
builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type);
}
-void register_node_type_sh_mix_rgb(void)
+} // namespace blender::nodes::node_shader_mix_rgb_cc
+
+void register_node_type_sh_mix_rgb()
{
+ namespace file_ns = blender::nodes::node_shader_mix_rgb_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::sh_node_mix_rgb_declare;
- node_type_label(&ntype, node_blend_label);
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_mix_rgb);
- node_type_gpu(&ntype, gpu_shader_mix_rgb);
- ntype.build_multi_function = sh_node_mix_rgb_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::sh_node_mix_rgb_declare;
+ ntype.labelfunc = node_blend_label;
+ node_type_gpu(&ntype, file_ns::gpu_shader_mix_rgb);
+ ntype.build_multi_function = file_ns::sh_node_mix_rgb_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_shader.c b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc
index 33cbf34543c..d9aa906e451 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mix_shader.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc
@@ -17,21 +17,17 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_mix_shader_cc {
-static bNodeSocketTemplate sh_node_mix_shader_in[] = {
- {SOCK_FLOAT, N_("Fac"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_SHADER, N_("Shader")},
- {SOCK_SHADER, N_("Shader")},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_mix_shader_out[] = {
- {SOCK_SHADER, N_("Shader")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Shader>(N_("Shader"));
+ b.add_input<decl::Shader>(N_("Shader"), "Shader_001");
+ b.add_output<decl::Shader>(N_("Shader"));
+}
static int node_shader_gpu_mix_shader(GPUMaterial *mat,
bNode *node,
@@ -42,16 +38,18 @@ static int node_shader_gpu_mix_shader(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_mix_shader", in, out);
}
+} // namespace blender::nodes::node_shader_mix_shader_cc
+
/* node type definition */
-void register_node_type_sh_mix_shader(void)
+void register_node_type_sh_mix_shader()
{
+ namespace file_ns = blender::nodes::node_shader_mix_shader_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_MIX_SHADER, "Mix Shader", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_mix_shader_in, sh_node_mix_shader_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_mix_shader);
+ sh_node_type_base(&ntype, SH_NODE_MIX_SHADER, "Mix Shader", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_mix_shader);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal.c b/source/blender/nodes/shader/nodes/node_shader_normal.cc
index 83d5abcba67..e677f36e425 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal.cc
@@ -21,37 +21,23 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** NORMAL ******************** */
-static bNodeSocketTemplate sh_node_normal_in[] = {
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_DIRECTION},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_normal_cc {
-static bNodeSocketTemplate sh_node_normal_out[] = {
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_DIRECTION},
- {SOCK_FLOAT, N_("Dot")},
- {-1, ""},
-};
-
-/* generates normal, does dot product */
-static void node_shader_exec_normal(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
+static void node_declare(NodeDeclarationBuilder &b)
{
- float vec[3];
-
- /* stack order input: normal */
- /* stack order output: normal, value */
-
- nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
-
- /* render normals point inside... the widget points outside */
- out[1]->vec[0] = -dot_v3v3(vec, out[0]->vec);
+ b.add_input<decl::Vector>(N_("Normal"))
+ .default_value({0.0f, 0.0f, 1.0f})
+ .min(-1.0f)
+ .max(1.0f)
+ .subtype(PROP_DIRECTION);
+ b.add_output<decl::Vector>(N_("Normal"))
+ .default_value({0.0f, 0.0f, 1.0f})
+ .min(-1.0f)
+ .max(1.0f)
+ .subtype(PROP_DIRECTION);
+ b.add_output<decl::Float>(N_("Dot"));
}
static int gpu_shader_normal(GPUMaterial *mat,
@@ -64,14 +50,17 @@ static int gpu_shader_normal(GPUMaterial *mat,
return GPU_stack_link(mat, node, "normal_new_shading", in, out, vec);
}
-void register_node_type_sh_normal(void)
+} // namespace blender::nodes::node_shader_normal_cc
+
+void register_node_type_sh_normal()
{
+ namespace file_ns = blender::nodes::node_shader_normal_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_normal_in, sh_node_normal_out);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_normal);
- node_type_gpu(&ntype, gpu_shader_normal);
+ sh_node_type_base(&ntype, SH_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_normal);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc
index 6c4f2070035..9eadb6ce014 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc
@@ -17,34 +17,43 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "BKE_context.h"
-static bNodeSocketTemplate sh_node_normal_map_in[] = {
- {SOCK_FLOAT, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f},
- {SOCK_RGBA, N_("Color"), 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_normal_map_out[] = {
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_normal_map_cc {
-static void node_shader_init_normal_map(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_declare(NodeDeclarationBuilder &b)
{
- NodeShaderNormalMap *attr = MEM_callocN(sizeof(NodeShaderNormalMap), "NodeShaderNormalMap");
- node->storage = attr;
+ b.add_input<decl::Float>(N_("Strength")).default_value(1.0f).min(0.0f).max(10.0f);
+ b.add_input<decl::Color>(N_("Color")).default_value({0.5f, 0.5f, 1.0f, 1.0f});
+ b.add_output<decl::Vector>(N_("Normal"));
+}
+
+static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "space", UI_ITEM_R_SPLIT_EMPTY_NAME, "", 0);
+
+ if (RNA_enum_get(ptr, "space") == SHD_SPACE_TANGENT) {
+ PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
+
+ if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
+ PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
+ uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
+ }
+ else {
+ uiItemR(layout, ptr, "uv_map", UI_ITEM_R_SPLIT_EMPTY_NAME, "", 0);
+ }
+ }
}
-static void node_shader_exec_normal_map(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **UNUSED(in),
- bNodeStack **UNUSED(out))
+static void node_shader_init_normal_map(bNodeTree *UNUSED(ntree), bNode *node)
{
+ NodeShaderNormalMap *attr = MEM_cnew<NodeShaderNormalMap>("NodeShaderNormalMap");
+ node->storage = attr;
}
static int gpu_shader_normal_map(GPUMaterial *mat,
@@ -53,15 +62,16 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- NodeShaderNormalMap *nm = node->storage;
+ NodeShaderNormalMap *nm = static_cast<NodeShaderNormalMap *>(node->storage);
GPUNodeLink *strength;
if (in[0].link) {
strength = in[0].link;
}
else if (node->original) {
- bNodeSocket *socket = BLI_findlink(&node->original->inputs, 0);
- bNodeSocketValueFloat *socket_data = socket->default_value;
+ bNodeSocket *socket = static_cast<bNodeSocket *>(BLI_findlink(&node->original->inputs, 0));
+ bNodeSocketValueFloat *socket_data = static_cast<bNodeSocketValueFloat *>(
+ socket->default_value);
strength = GPU_uniform(&socket_data->value);
}
else {
@@ -73,8 +83,8 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
newnormal = in[1].link;
}
else if (node->original) {
- bNodeSocket *socket = BLI_findlink(&node->original->inputs, 1);
- bNodeSocketValueRGBA *socket_data = socket->default_value;
+ bNodeSocket *socket = static_cast<bNodeSocket *>(BLI_findlink(&node->original->inputs, 1));
+ bNodeSocketValueRGBA *socket_data = static_cast<bNodeSocketValueRGBA *>(socket->default_value);
newnormal = GPU_uniform(socket_data->value);
}
else {
@@ -111,19 +121,23 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
return true;
}
+} // namespace blender::nodes::node_shader_normal_map_cc
+
/* node type definition */
-void register_node_type_sh_normal_map(void)
+void register_node_type_sh_normal_map()
{
+ namespace file_ns = blender::nodes::node_shader_normal_map_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_NORMAL_MAP, "Normal Map", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_normal_map_in, sh_node_normal_map_out);
+ sh_node_type_base(&ntype, SH_NODE_NORMAL_MAP, "Normal Map", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_normal_map;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_normal_map);
+ node_type_init(&ntype, file_ns::node_shader_init_normal_map);
node_type_storage(
&ntype, "NodeShaderNormalMap", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, gpu_shader_normal_map);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_normal_map);
+ node_type_gpu(&ntype, file_ns::gpu_shader_normal_map);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.c b/source/blender/nodes/shader/nodes/node_shader_object_info.cc
index f3eb5dcc26d..75c9c8f9206 100644
--- a/source/blender/nodes/shader/nodes/node_shader_object_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_object_info.cc
@@ -17,18 +17,18 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_object_info_cc {
-static bNodeSocketTemplate sh_node_object_info_out[] = {
- {SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Object Index"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Material Index"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Random"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Location"));
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Object Index"));
+ b.add_output<decl::Float>(N_("Material Index"));
+ b.add_output<decl::Float>(N_("Random"));
+}
static int node_shader_gpu_object_info(GPUMaterial *mat,
bNode *node,
@@ -42,13 +42,17 @@ static int node_shader_gpu_object_info(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_object_info", in, out, GPU_constant(&index));
}
-void register_node_type_sh_object_info(void)
+} // namespace blender::nodes::node_shader_object_info_cc
+
+void register_node_type_sh_object_info()
{
+ namespace file_ns = blender::nodes::node_shader_object_info_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_object_info_out);
- node_type_gpu(&ntype, node_shader_gpu_object_info);
+ sh_node_type_base(&ntype, SH_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_object_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_aov.c b/source/blender/nodes/shader/nodes/node_shader_output_aov.cc
index 18c8edfe41c..b5177014f3a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_aov.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_aov.cc
@@ -17,21 +17,29 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_hash.h"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_output_aov_in[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_output_aov_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Value")).default_value(0.0f).min(0.0f).max(1.0f);
+}
+
+static void node_shader_buts_output_aov(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "name", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
static void node_shader_init_output_aov(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderOutputAOV *aov = MEM_callocN(sizeof(NodeShaderOutputAOV), "NodeShaderOutputAOV");
+ NodeShaderOutputAOV *aov = MEM_cnew<NodeShaderOutputAOV>("NodeShaderOutputAOV");
node->storage = aov;
}
@@ -49,20 +57,24 @@ static int node_shader_gpu_output_aov(GPUMaterial *mat,
return true;
}
+} // namespace blender::nodes::node_shader_output_aov_cc
+
/* node type definition */
-void register_node_type_sh_output_aov(void)
+void register_node_type_sh_output_aov()
{
+ namespace file_ns = blender::nodes::node_shader_output_aov_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_AOV, "AOV Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_aov_in, NULL);
- node_type_init(&ntype, node_shader_init_output_aov);
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_AOV, "AOV Output", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_output_aov;
+ node_type_init(&ntype, file_ns::node_shader_init_output_aov);
node_type_storage(
&ntype, "NodeShaderOutputAOV", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_output_aov);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_output_aov);
- /* Do not allow muting output node. */
- node_type_internal_links(&ntype, NULL);
+ ntype.no_muting = true;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_light.c b/source/blender/nodes/shader/nodes/node_shader_output_light.cc
index 722202bafdc..0c8288f801b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_light.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_light.cc
@@ -17,27 +17,27 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_output_light_cc {
-static bNodeSocketTemplate sh_node_output_light_in[] = {
- {SOCK_SHADER, N_("Surface"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Shader>(N_("Surface"));
+}
+
+} // namespace blender::nodes::node_shader_output_light_cc
/* node type definition */
-void register_node_type_sh_output_light(void)
+void register_node_type_sh_output_light()
{
- static bNodeType ntype;
+ namespace file_ns = blender::nodes::node_shader_output_light_cc;
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_LIGHT, "Light Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_light_in, NULL);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
+ static bNodeType ntype;
- /* Do not allow muting output node. */
- node_type_internal_links(&ntype, NULL);
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_LIGHT, "Light Output", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.no_muting = true;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c
deleted file mode 100644
index 5b4ebf21f5f..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c
+++ /dev/null
@@ -1,45 +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.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_output_linestyle_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 0.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Color Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Alpha Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {-1, ""},
-};
-
-/* node type definition */
-void register_node_type_sh_output_linestyle(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_LINESTYLE, "Line Style Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_linestyle_in, NULL);
- node_type_init(&ntype, NULL);
-
- /* Do not allow muting output node. */
- node_type_internal_links(&ntype, NULL);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc
new file mode 100644
index 00000000000..9b6c3292e75
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_output_linestyle_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 0.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Color Fac"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Alpha"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Alpha Fac"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+}
+
+static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row, *col;
+
+ col = uiLayoutColumn(layout, false);
+ row = uiLayoutRow(col, true);
+ uiItemR(row, ptr, "blend_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(col, ptr, "use_clamp", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_shader_output_linestyle_cc
+
+/* node type definition */
+void register_node_type_sh_output_linestyle()
+{
+ namespace file_ns = blender::nodes::node_shader_output_linestyle_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_LINESTYLE, "Line Style Output", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_buts_output_linestyle;
+ ntype.no_muting = true;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.c
deleted file mode 100644
index 5b6d2914ccf..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_output_material.c
+++ /dev/null
@@ -1,85 +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.
- */
-
-#include "../node_shader_util.h"
-
-#include "BKE_scene.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_output_material_in[] = {
- {SOCK_SHADER, N_("Surface")},
- {SOCK_SHADER, N_("Volume")},
- {SOCK_VECTOR,
- N_("Displacement"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_NONE,
- SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Thickness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static int node_shader_gpu_output_material(GPUMaterial *mat,
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *UNUSED(out))
-{
- GPUNodeLink *outlink_surface, *outlink_volume, *outlink_displacement, *outlink_thickness;
- /* Passthrough node in order to do the right socket conversions (important for displacement). */
- if (in[0].link) {
- GPU_link(mat, "node_output_material_surface", in[0].link, &outlink_surface);
- GPU_material_output_surface(mat, outlink_surface);
- }
- if (in[1].link) {
- GPU_link(mat, "node_output_material_volume", in[1].link, &outlink_volume);
- GPU_material_output_volume(mat, outlink_volume);
- }
- if (in[2].link) {
- GPU_link(mat, "node_output_material_displacement", in[2].link, &outlink_displacement);
- GPU_material_output_displacement(mat, outlink_displacement);
- }
- if (in[3].link) {
- GPU_link(mat, "node_output_material_thickness", in[3].link, &outlink_thickness);
- GPU_material_output_thickness(mat, outlink_thickness);
- }
- return true;
-}
-
-/* node type definition */
-void register_node_type_sh_output_material(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_MATERIAL, "Material Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_material_in, NULL);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_output_material);
-
- /* Do not allow muting output node. */
- node_type_internal_links(&ntype, NULL);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.cc b/source/blender/nodes/shader/nodes/node_shader_output_material.cc
new file mode 100644
index 00000000000..5fc95b92e3f
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_output_material.cc
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#include "node_shader_util.hh"
+
+#include "BKE_scene.h"
+
+namespace blender::nodes::node_shader_output_material_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Shader>(N_("Surface"));
+ b.add_input<decl::Shader>(N_("Volume"));
+ b.add_input<decl::Vector>(N_("Displacement")).hide_value();
+}
+
+static int node_shader_gpu_output_material(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ GPUNodeLink *outlink, *alpha_threshold_link, *shadow_threshold_link;
+ Material *ma = GPU_material_get_material(mat);
+
+ static float no_alpha_threshold = -1.0f;
+ if (ma) {
+ alpha_threshold_link = GPU_uniform((ma->blend_method == MA_BM_CLIP) ? &ma->alpha_threshold :
+ &no_alpha_threshold);
+ shadow_threshold_link = GPU_uniform((ma->blend_shadow == MA_BS_CLIP) ? &ma->alpha_threshold :
+ &no_alpha_threshold);
+ }
+ else {
+ alpha_threshold_link = GPU_uniform(&no_alpha_threshold);
+ shadow_threshold_link = GPU_uniform(&no_alpha_threshold);
+ }
+
+ GPU_stack_link(mat,
+ node,
+ "node_output_material",
+ in,
+ out,
+ alpha_threshold_link,
+ shadow_threshold_link,
+ &outlink);
+ GPU_material_output_link(mat, outlink);
+
+ return true;
+}
+
+} // namespace blender::nodes::node_shader_output_material_cc
+
+/* node type definition */
+void register_node_type_sh_output_material()
+{
+ namespace file_ns = blender::nodes::node_shader_output_material_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_MATERIAL, "Material Output", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_output_material);
+
+ ntype.no_muting = true;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.c b/source/blender/nodes/shader/nodes/node_shader_output_world.cc
index eaecfc266a3..a3509fd3ff4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_world.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_world.cc
@@ -17,15 +17,15 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_output_world_cc {
-static bNodeSocketTemplate sh_node_output_world_in[] = {
- {SOCK_SHADER, N_("Surface"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_SHADER, N_("Volume"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Shader>(N_("Surface"));
+ b.add_input<decl::Shader>(N_("Volume"));
+}
static int node_shader_gpu_output_world(GPUMaterial *mat,
bNode *UNUSED(node),
@@ -45,19 +45,20 @@ static int node_shader_gpu_output_world(GPUMaterial *mat,
return true;
}
+} // namespace blender::nodes::node_shader_output_world_cc
+
/* node type definition */
-void register_node_type_sh_output_world(void)
+void register_node_type_sh_output_world()
{
+ namespace file_ns = blender::nodes::node_shader_output_world_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_WORLD, "World Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_world_in, NULL);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_output_world);
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_WORLD, "World Output", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_output_world);
- /* Do not allow muting output node. */
- node_type_internal_links(&ntype, NULL);
+ ntype.no_muting = true;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_particle_info.c b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc
index 75966843294..5792282fa0f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_particle_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc
@@ -17,30 +17,25 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
#include "RE_texture.h"
-static bNodeSocketTemplate outputs[] = {
- {SOCK_FLOAT, "Index"},
- {SOCK_FLOAT, "Random"},
- {SOCK_FLOAT, "Age"},
- {SOCK_FLOAT, "Lifetime"},
- {SOCK_VECTOR, "Location"},
+namespace blender::nodes::node_shader_particle_info_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Index"));
+ b.add_output<decl::Float>(N_("Random"));
+ b.add_output<decl::Float>(N_("Age"));
+ b.add_output<decl::Float>(N_("Lifetime"));
+ b.add_output<decl::Vector>(N_("Location"));
#if 0 /* quaternion sockets not yet supported */
- {SOCK_QUATERNION, "Rotation"},
+ b.add_output<decl::Quaternion>(N_("Rotation"));
#endif
- {SOCK_FLOAT, "Size"},
- {SOCK_VECTOR, "Velocity"},
- {SOCK_VECTOR, "Angular Velocity"},
- {-1, ""},
-};
-static void node_shader_exec_particle_info(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **UNUSED(in),
- bNodeStack **UNUSED(out))
-{
+ b.add_output<decl::Float>(N_("Size"));
+ b.add_output<decl::Vector>(N_("Velocity"));
+ b.add_output<decl::Vector>(N_("Angular Velocity"));
}
static int gpu_shader_particle_info(GPUMaterial *mat,
@@ -54,15 +49,18 @@ static int gpu_shader_particle_info(GPUMaterial *mat,
return GPU_stack_link(mat, node, "particle_info", in, out);
}
+} // namespace blender::nodes::node_shader_particle_info_cc
+
/* node type definition */
-void register_node_type_sh_particle_info(void)
+void register_node_type_sh_particle_info()
{
+ namespace file_ns = blender::nodes::node_shader_particle_info_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_PARTICLE_INFO, "Particle Info", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, outputs);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_particle_info);
- node_type_gpu(&ntype, gpu_shader_particle_info);
+ sh_node_type_base(&ntype, SH_NODE_PARTICLE_INFO, "Particle Info", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_particle_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_point_info.cc b/source/blender/nodes/shader/nodes/node_shader_point_info.cc
new file mode 100644
index 00000000000..adc58ca065a
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_point_info.cc
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_point_info_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Position"));
+ b.add_output<decl::Float>(N_("Radius"));
+ b.add_output<decl::Float>(N_("Random"));
+}
+
+static int node_shader_gpu_point_info(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "node_point_info", in, out);
+}
+
+} // namespace blender::nodes::node_shader_point_info_cc
+
+/* node type definition */
+void register_node_type_sh_point_info()
+{
+ namespace file_ns = blender::nodes::node_shader_point_info_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_POINT_INFO, "Point Info", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_point_info);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb.c b/source/blender/nodes/shader/nodes/node_shader_rgb.cc
index 0bdef9a2a17..f3b83b72232 100644
--- a/source/blender/nodes/shader/nodes/node_shader_rgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_rgb.cc
@@ -21,13 +21,14 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** RGB ******************** */
-static bNodeSocketTemplate sh_node_rgb_out[] = {
- {SOCK_RGBA, N_("Color"), 0.5f, 0.5f, 0.5f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_rgb_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>(N_("Color")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
+}
static int gpu_shader_rgb(GPUMaterial *mat,
bNode *node,
@@ -39,13 +40,17 @@ static int gpu_shader_rgb(GPUMaterial *mat,
return GPU_stack_link(mat, node, "set_rgba", in, out, link);
}
-void register_node_type_sh_rgb(void)
+} // namespace blender::nodes::node_shader_rgb_cc
+
+void register_node_type_sh_rgb()
{
+ namespace file_ns = blender::nodes::node_shader_rgb_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_RGB, "RGB", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_rgb_out);
- node_type_gpu(&ntype, gpu_shader_rgb);
+ sh_node_type_base(&ntype, SH_NODE_RGB, "RGB", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_rgb);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc
new file mode 100644
index 00000000000..13ba056d9ee
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc
@@ -0,0 +1,58 @@
+/*
+ * 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 shdnodes
+ */
+
+#include "IMB_colormanagement.h"
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_rgb_to_bw_cc {
+
+static void sh_node_rgbtobw_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_output<decl::Float>(N_("Val"));
+}
+
+static int gpu_shader_rgbtobw(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "rgbtobw", in, out);
+}
+
+} // namespace blender::nodes::node_shader_rgb_to_bw_cc
+
+void register_node_type_sh_rgbtobw()
+{
+ namespace file_ns = blender::nodes::node_shader_rgb_to_bw_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_rgbtobw_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_rgbtobw);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_script.c b/source/blender/nodes/shader/nodes/node_shader_script.c
deleted file mode 100644
index 42ab272de0e..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_script.c
+++ /dev/null
@@ -1,70 +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 shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** Script ******************** */
-
-static void init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeShaderScript *nss = MEM_callocN(sizeof(NodeShaderScript), "shader script node");
- node->storage = nss;
-}
-
-static void node_free_script(bNode *node)
-{
- NodeShaderScript *nss = node->storage;
-
- if (nss) {
- if (nss->bytecode) {
- MEM_freeN(nss->bytecode);
- }
-
- MEM_freeN(nss);
- }
-}
-
-static void node_copy_script(bNodeTree *UNUSED(dest_ntree),
- bNode *dest_node,
- const bNode *src_node)
-{
- NodeShaderScript *src_nss = src_node->storage;
- NodeShaderScript *dest_nss = MEM_dupallocN(src_nss);
-
- if (src_nss->bytecode) {
- dest_nss->bytecode = MEM_dupallocN(src_nss->bytecode);
- }
-
- dest_node->storage = dest_nss;
-}
-
-void register_node_type_sh_script(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_SCRIPT, "Script", NODE_CLASS_SCRIPT, 0);
- node_type_init(&ntype, init);
- node_type_storage(&ntype, "NodeShaderScript", node_free_script, node_copy_script);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_script.cc b/source/blender/nodes/shader/nodes/node_shader_script.cc
new file mode 100644
index 00000000000..e6af90fa588
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_script.cc
@@ -0,0 +1,112 @@
+/*
+ * 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 shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_script_cc {
+
+static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row;
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "mode", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+
+ row = uiLayoutRow(layout, true);
+
+ if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_INTERNAL) {
+ uiItemR(row, ptr, "script", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ }
+ else {
+ uiItemR(row, ptr, "filepath", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ }
+
+ uiItemO(row, "", ICON_FILE_REFRESH, "node.shader_script_update");
+}
+
+static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiItemS(layout);
+
+ node_shader_buts_script(layout, C, ptr);
+
+#if 0 /* not implemented yet */
+ if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_EXTERNAL) {
+ uiItemR(layout, ptr, "use_auto_update", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+#endif
+}
+
+static void init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeShaderScript *nss = MEM_cnew<NodeShaderScript>("shader script node");
+ node->storage = nss;
+}
+
+static void node_free_script(bNode *node)
+{
+ NodeShaderScript *nss = static_cast<NodeShaderScript *>(node->storage);
+
+ if (nss) {
+ if (nss->bytecode) {
+ MEM_freeN(nss->bytecode);
+ }
+
+ MEM_freeN(nss);
+ }
+}
+
+static void node_copy_script(bNodeTree *UNUSED(dest_ntree),
+ bNode *dest_node,
+ const bNode *src_node)
+{
+ NodeShaderScript *src_nss = static_cast<NodeShaderScript *>(src_node->storage);
+ NodeShaderScript *dest_nss = static_cast<NodeShaderScript *>(MEM_dupallocN(src_nss));
+
+ if (src_nss->bytecode) {
+ dest_nss->bytecode = static_cast<char *>(MEM_dupallocN(src_nss->bytecode));
+ }
+
+ dest_node->storage = dest_nss;
+}
+
+} // namespace blender::nodes::node_shader_script_cc
+
+void register_node_type_sh_script()
+{
+ namespace file_ns = blender::nodes::node_shader_script_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_SCRIPT, "Script", NODE_CLASS_SCRIPT);
+ ntype.draw_buttons = file_ns::node_shader_buts_script;
+ ntype.draw_buttons_ex = file_ns::node_shader_buts_script_ex;
+ node_type_init(&ntype, file_ns::init);
+ node_type_storage(
+ &ntype, "NodeShaderScript", file_ns::node_free_script, file_ns::node_copy_script);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
deleted file mode 100644
index dfecb830b35..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
+++ /dev/null
@@ -1,118 +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) 2013 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** SEPARATE HSV ******************** */
-static bNodeSocketTemplate sh_node_sephsv_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate sh_node_sephsv_out[] = {
- {SOCK_FLOAT, N_("H")},
- {SOCK_FLOAT, N_("S")},
- {SOCK_FLOAT, N_("V")},
- {-1, ""},
-};
-
-static void node_shader_exec_sephsv(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float col[3];
- nodestack_get_vec(col, SOCK_VECTOR, in[0]);
-
- rgb_to_hsv(col[0], col[1], col[2], &out[0]->vec[0], &out[1]->vec[0], &out[2]->vec[0]);
-}
-
-static int gpu_shader_sephsv(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- return GPU_stack_link(mat, node, "separate_hsv", in, out);
-}
-
-void register_node_type_sh_sephsv(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, sh_node_sephsv_in, sh_node_sephsv_out);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_sephsv);
- node_type_gpu(&ntype, gpu_shader_sephsv);
-
- nodeRegisterType(&ntype);
-}
-
-/* **************** COMBINE HSV ******************** */
-static bNodeSocketTemplate sh_node_combhsv_in[] = {
- {SOCK_FLOAT, N_("H"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, N_("S"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, N_("V"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
- {-1, ""},
-};
-static bNodeSocketTemplate sh_node_combhsv_out[] = {
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
-
-static void node_shader_exec_combhsv(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float h, s, v;
- nodestack_get_vec(&h, SOCK_FLOAT, in[0]);
- nodestack_get_vec(&s, SOCK_FLOAT, in[1]);
- nodestack_get_vec(&v, SOCK_FLOAT, in[2]);
-
- hsv_to_rgb(h, s, v, &out[0]->vec[0], &out[0]->vec[1], &out[0]->vec[2]);
-}
-
-static int gpu_shader_combhsv(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- return GPU_stack_link(mat, node, "combine_hsv", in, out);
-}
-
-void register_node_type_sh_combhsv(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, sh_node_combhsv_in, sh_node_combhsv_out);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_combhsv);
- node_type_gpu(&ntype, gpu_shader_combhsv);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
new file mode 100644
index 00000000000..700e4ce3667
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
@@ -0,0 +1,96 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_sepcomb_hsv_cc {
+
+/* **************** SEPARATE HSV ******************** */
+
+static void node_declare_sephsv(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0});
+ b.add_output<decl::Float>(N_("H"));
+ b.add_output<decl::Float>(N_("S"));
+ b.add_output<decl::Float>(N_("V"));
+}
+
+static int gpu_shader_sephsv(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "separate_hsv", in, out);
+}
+
+} // namespace blender::nodes::node_shader_sepcomb_hsv_cc
+
+void register_node_type_sh_sephsv()
+{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_hsv_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare_sephsv;
+ node_type_gpu(&ntype, file_ns::gpu_shader_sephsv);
+
+ nodeRegisterType(&ntype);
+}
+
+namespace blender::nodes::node_shader_sepcomb_hsv_cc {
+
+/* **************** COMBINE HSV ******************** */
+
+static void node_declare_combhsv(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("H")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_UNSIGNED);
+ b.add_input<decl::Float>(N_("S")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_UNSIGNED);
+ b.add_input<decl::Float>(N_("V")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_UNSIGNED);
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+static int gpu_shader_combhsv(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "combine_hsv", in, out);
+}
+
+} // namespace blender::nodes::node_shader_sepcomb_hsv_cc
+
+void register_node_type_sh_combhsv()
+{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_hsv_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare_combhsv;
+ node_type_gpu(&ntype, file_ns::gpu_shader_combhsv);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
index 24c5dcf7ba3..d4be0bd14dc 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
@@ -21,34 +21,17 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_sepcomb_rgb_cc {
static void sh_node_seprgb_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Color>("Image").default_value({0.8f, 0.8f, 0.8f, 1.0f});
- b.add_output<decl::Float>("R");
- b.add_output<decl::Float>("G");
- b.add_output<decl::Float>("B");
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_seprgb(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float col[3];
- nodestack_get_vec(col, SOCK_VECTOR, in[0]);
-
- out[0]->vec[0] = col[0];
- out[1]->vec[0] = col[1];
- out[2]->vec[0] = col[2];
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Float>(N_("R"));
+ b.add_output<decl::Float>(N_("G"));
+ b.add_output<decl::Float>(N_("B"));
}
static int gpu_shader_seprgb(GPUMaterial *mat,
@@ -103,47 +86,31 @@ static void sh_node_seprgb_build_multi_function(blender::nodes::NodeMultiFunctio
builder.set_matching_fn(fn);
}
-void register_node_type_sh_seprgb(void)
+} // namespace blender::nodes::node_shader_sepcomb_rgb_cc
+
+void register_node_type_sh_seprgb()
{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_rgb_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_seprgb_declare;
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_seprgb);
- node_type_gpu(&ntype, gpu_shader_seprgb);
- ntype.build_multi_function = sh_node_seprgb_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_seprgb_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_seprgb);
+ ntype.build_multi_function = file_ns::sh_node_seprgb_build_multi_function;
nodeRegisterType(&ntype);
}
-namespace blender::nodes {
+namespace blender::nodes::node_shader_sepcomb_rgb_cc {
static void sh_node_combrgb_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("R").min(0.0f).max(1.0f);
- b.add_input<decl::Float>("G").min(0.0f).max(1.0f);
- b.add_input<decl::Float>("B").min(0.0f).max(1.0f);
- b.add_output<decl::Color>("Image");
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_combrgb(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float r, g, b;
- nodestack_get_vec(&r, SOCK_FLOAT, in[0]);
- nodestack_get_vec(&g, SOCK_FLOAT, in[1]);
- nodestack_get_vec(&b, SOCK_FLOAT, in[2]);
-
- out[0]->vec[0] = r;
- out[0]->vec[1] = g;
- out[0]->vec[2] = b;
+ b.add_input<decl::Float>(N_("R")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("G")).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("B")).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
}
static int gpu_shader_combrgb(GPUMaterial *mat,
@@ -163,15 +130,18 @@ static void sh_node_combrgb_build_multi_function(blender::nodes::NodeMultiFuncti
builder.set_matching_fn(fn);
}
-void register_node_type_sh_combrgb(void)
+} // namespace blender::nodes::node_shader_sepcomb_rgb_cc
+
+void register_node_type_sh_combrgb()
{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_rgb_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_combrgb_declare;
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_combrgb);
- node_type_gpu(&ntype, gpu_shader_combrgb);
- ntype.build_multi_function = sh_node_combrgb_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_combrgb_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_combrgb);
+ ntype.build_multi_function = file_ns::sh_node_combrgb_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
index 8ca8fc19521..f8064eb192a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
@@ -21,20 +21,18 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_sepcomb_xyz_cc {
static void sh_node_sepxyz_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f);
- b.add_output<decl::Float>("X");
- b.add_output<decl::Float>("Y");
- b.add_output<decl::Float>("Z");
-};
-
-} // namespace blender::nodes
+ b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Float>(N_("X"));
+ b.add_output<decl::Float>(N_("Y"));
+ b.add_output<decl::Float>(N_("Z"));
+}
static int gpu_shader_sepxyz(GPUMaterial *mat,
bNode *node,
@@ -88,30 +86,32 @@ static void sh_node_sepxyz_build_multi_function(blender::nodes::NodeMultiFunctio
builder.set_matching_fn(separate_fn);
}
-void register_node_type_sh_sepxyz(void)
+} // namespace blender::nodes::node_shader_sepcomb_xyz_cc
+
+void register_node_type_sh_sepxyz()
{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_sepxyz_declare;
- node_type_gpu(&ntype, gpu_shader_sepxyz);
- ntype.build_multi_function = sh_node_sepxyz_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_sepxyz_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_sepxyz);
+ ntype.build_multi_function = file_ns::sh_node_sepxyz_build_multi_function;
nodeRegisterType(&ntype);
}
-namespace blender::nodes {
+namespace blender::nodes::node_shader_sepcomb_xyz_cc {
static void sh_node_combxyz_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>("X").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Y").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Z").min(-10000.0f).max(10000.0f);
- b.add_output<decl::Vector>("Vector");
-};
-
-} // namespace blender::nodes
+ b.add_input<decl::Float>(N_("X")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Y")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Z")).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Vector>(N_("Vector"));
+}
static int gpu_shader_combxyz(GPUMaterial *mat,
bNode *node,
@@ -129,14 +129,18 @@ static void sh_node_combxyz_build_multi_function(blender::nodes::NodeMultiFuncti
builder.set_matching_fn(fn);
}
-void register_node_type_sh_combxyz(void)
+} // namespace blender::nodes::node_shader_sepcomb_xyz_cc
+
+void register_node_type_sh_combxyz()
{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_combxyz_declare;
- node_type_gpu(&ntype, gpu_shader_combxyz);
- ntype.build_multi_function = sh_node_combxyz_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_combxyz_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_combxyz);
+ ntype.build_multi_function = file_ns::sh_node_combxyz_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc
index 4e8f47c087a..d601f45b49f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc
@@ -17,20 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_shader_to_rgb_cc {
-static bNodeSocketTemplate sh_node_shadertorgb_in[] = {
- {SOCK_SHADER, N_("Shader")},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_shadertorgb_out[] = {
- {SOCK_RGBA, N_("Color")},
- {SOCK_FLOAT, N_("Alpha")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Shader>(N_("Shader"));
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Alpha"));
+}
static int node_shader_gpu_shadertorgb(GPUMaterial *mat,
bNode *node,
@@ -43,16 +39,18 @@ static int node_shader_gpu_shadertorgb(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_shader_to_rgba", in, out);
}
+} // namespace blender::nodes::node_shader_shader_to_rgb_cc
+
/* node type definition */
-void register_node_type_sh_shadertorgb(void)
+void register_node_type_sh_shadertorgb()
{
+ namespace file_ns = blender::nodes::node_shader_shader_to_rgb_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SHADERTORGB, "Shader to RGB", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, sh_node_shadertorgb_in, sh_node_shadertorgb_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_shadertorgb);
+ sh_node_type_base(&ntype, SH_NODE_SHADERTORGB, "Shader to RGB", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_shadertorgb);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_squeeze.c b/source/blender/nodes/shader/nodes/node_shader_squeeze.c
deleted file mode 100644
index ca7bdf41df9..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_squeeze.c
+++ /dev/null
@@ -1,71 +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 shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** VALUE SQUEEZE ******************** */
-static bNodeSocketTemplate sh_node_squeeze_in[] = {
- {SOCK_FLOAT, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Width"), 1.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Center"), 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
- {-1, ""}};
-
-static bNodeSocketTemplate sh_node_squeeze_out[] = {{SOCK_FLOAT, N_("Value")}, {-1, ""}};
-
-static void node_shader_exec_squeeze(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float vec[3];
-
- nodestack_get_vec(vec, SOCK_FLOAT, in[0]);
- nodestack_get_vec(vec + 1, SOCK_FLOAT, in[1]);
- nodestack_get_vec(vec + 2, SOCK_FLOAT, in[2]);
-
- out[0]->vec[0] = 1.0f / (1.0f + powf(M_E, -((vec[0] - vec[2]) * vec[1])));
-}
-
-static int gpu_shader_squeeze(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- return GPU_stack_link(mat, node, "squeeze", in, out);
-}
-
-void register_node_type_sh_squeeze(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_SQUEEZE, "Squeeze Value", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, sh_node_squeeze_in, sh_node_squeeze_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_squeeze);
- node_type_gpu(&ntype, gpu_shader_squeeze);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_squeeze.cc b/source/blender/nodes/shader/nodes/node_shader_squeeze.cc
new file mode 100644
index 00000000000..83965160019
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_squeeze.cc
@@ -0,0 +1,58 @@
+/*
+ * 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 shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_squeeze_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Value")).default_value(0.0f).min(-100.0f).max(100.0f);
+ b.add_input<decl::Float>(N_("Width")).default_value(1.0f).min(-100.0f).max(100.0f);
+ b.add_input<decl::Float>(N_("Center")).default_value(0.0f).min(-100.0f).max(100.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+static int gpu_shader_squeeze(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "squeeze", in, out);
+}
+
+} // namespace blender::nodes::node_shader_squeeze_cc
+
+void register_node_type_sh_squeeze()
+{
+ namespace file_ns = blender::nodes::node_shader_squeeze_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_SQUEEZE, "Squeeze Value", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_squeeze);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
deleted file mode 100644
index 159e986e19e..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
+++ /dev/null
@@ -1,76 +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.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_subsurface_scattering_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Scale"), 1.0, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Radius"), 1.0f, 0.2f, 0.1f, 0.0f, 0.0f, 100.0f, PROP_NONE, SOCK_COMPACT},
- {SOCK_FLOAT, N_("IOR"), 1.4f, 0.0f, 0.0f, 0.0f, 1.01f, 3.8f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Anisotropy"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_subsurface_scattering_out[] = {
- {SOCK_SHADER, N_("BSSRDF")},
- {-1, ""},
-};
-
-static void node_shader_init_subsurface_scattering(bNodeTree *UNUSED(ntree), bNode *node)
-{
- node->custom1 = SHD_SUBSURFACE_RANDOM_WALK;
- node->custom2 = true;
-}
-
-static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- if (!in[5].link) {
- GPU_link(mat, "world_normals_get", &in[5].link);
- }
-
- GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SUBSURFACE);
- GPU_stack_link(mat, node, "node_subsurface_scattering", in, out);
- return GPU_stack_eval_link(mat, node, "node_subsurface_scattering_eval", in, out);
-}
-
-/* node type definition */
-void register_node_type_sh_subsurface_scattering(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(
- &ntype, SH_NODE_SUBSURFACE_SCATTERING, "Subsurface Scattering", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(
- &ntype, sh_node_subsurface_scattering_in, sh_node_subsurface_scattering_out);
- node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_subsurface_scattering);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_subsurface_scattering);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc
new file mode 100644
index 00000000000..f60db81b4a9
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_subsurface_scattering_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Scale")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Radius"))
+ .default_value({1.0f, 0.2f, 0.1f})
+ .min(0.0f)
+ .max(100.0f)
+ .compact();
+ b.add_input<decl::Float>(N_("IOR")).default_value(1.4f).min(1.01f).max(3.8f).subtype(
+ PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Anisotropy"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSSRDF"));
+}
+
+static void node_shader_buts_subsurface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+static void node_shader_init_subsurface_scattering(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SHD_SUBSURFACE_RANDOM_WALK;
+ node->custom2 = true;
+}
+
+static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ if (!in[5].link) {
+ GPU_link(mat, "world_normals_get", &in[5].link);
+ }
+
+ if (node->sss_id > 0) {
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2);
+ bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value;
+ /* For some reason it seems that the socket value is in ARGB format. */
+ GPU_material_sss_profile_create(mat, &socket_data->value[1]);
+
+ /* sss_id is 0 only the node is not connected to any output.
+ * In this case flagging the material would trigger a bug (see T68736). */
+ GPU_material_flag_set(mat, (eGPUMatFlag)(GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS));
+ }
+
+ return GPU_stack_link(
+ mat, node, "node_subsurface_scattering", in, out, GPU_constant(&node->sss_id));
+}
+
+static void node_shader_update_subsurface_scattering(bNodeTree *ntree, bNode *node)
+{
+ const int sss_method = node->custom1;
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ if (STR_ELEM(sock->name, "IOR", "Anisotropy")) {
+ nodeSetSocketAvailability(ntree, sock, sss_method != SHD_SUBSURFACE_BURLEY);
+ }
+ }
+}
+
+} // namespace blender::nodes::node_shader_subsurface_scattering_cc
+
+/* node type definition */
+void register_node_type_sh_subsurface_scattering()
+{
+ namespace file_ns = blender::nodes::node_shader_subsurface_scattering_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(
+ &ntype, SH_NODE_SUBSURFACE_SCATTERING, "Subsurface Scattering", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_subsurface;
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_init(&ntype, file_ns::node_shader_init_subsurface_scattering);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_subsurface_scattering);
+ node_type_update(&ntype, file_ns::node_shader_update_subsurface_scattering);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tangent.c b/source/blender/nodes/shader/nodes/node_shader_tangent.cc
index 7ec332bd34a..58625cacf9c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tangent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tangent.cc
@@ -17,18 +17,49 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "BKE_context.h"
-static bNodeSocketTemplate sh_node_tangent_out[] = {
- {SOCK_VECTOR, N_("Tangent"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tangent_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Tangent"));
+}
+
+static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiLayout *split, *row;
+
+ split = uiLayoutSplit(layout, 0.0f, false);
+
+ uiItemR(split, ptr, "direction_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", 0);
+
+ row = uiLayoutRow(split, false);
+
+ if (RNA_enum_get(ptr, "direction_type") == SHD_TANGENT_UVMAP) {
+ PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
+
+ if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
+ PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
+ uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
+ }
+ else {
+ uiItemR(row, ptr, "uv_map", UI_ITEM_R_SPLIT_EMPTY_NAME, "", 0);
+ }
+ }
+ else {
+ uiItemR(row, ptr, "axis", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, 0);
+ }
+}
static void node_shader_init_tangent(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderTangent *attr = MEM_callocN(sizeof(NodeShaderTangent), "NodeShaderTangent");
+ NodeShaderTangent *attr = MEM_cnew<NodeShaderTangent>("NodeShaderTangent");
attr->axis = SHD_TANGENT_AXIS_Z;
node->storage = attr;
}
@@ -39,7 +70,7 @@ static int node_shader_gpu_tangent(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- NodeShaderTangent *attr = node->storage;
+ NodeShaderTangent *attr = static_cast<NodeShaderTangent *>(node->storage);
if (attr->direction_type == SHD_TANGENT_UVMAP) {
return GPU_stack_link(
@@ -61,16 +92,21 @@ static int node_shader_gpu_tangent(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_tangent", in, out, orco);
}
+} // namespace blender::nodes::node_shader_tangent_cc
+
/* node type definition */
-void register_node_type_sh_tangent(void)
+void register_node_type_sh_tangent()
{
+ namespace file_ns = blender::nodes::node_shader_tangent_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TANGENT, "Tangent", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_tangent_out);
+ sh_node_type_base(&ntype, SH_NODE_TANGENT, "Tangent", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tangent;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tangent);
- node_type_gpu(&ntype, node_shader_gpu_tangent);
+ node_type_init(&ntype, file_ns::node_shader_init_tangent);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tangent);
node_type_storage(
&ntype, "NodeShaderTangent", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
deleted file mode 100644
index 1b802f1dfd7..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
+++ /dev/null
@@ -1,181 +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.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_tex_brick_in[] = {
- {SOCK_VECTOR,
- N_("Vector"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_NONE,
- SOCK_HIDE_VALUE | SOCK_NO_INTERNAL_LINK},
- {SOCK_RGBA, N_("Color1"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_RGBA, N_("Color2"), 0.2f, 0.2f, 0.2f, 1.0f, 0.0f, 1.0f},
- {SOCK_RGBA,
- N_("Mortar"),
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- 0.0f,
- 1.0f,
- PROP_NONE,
- SOCK_NO_INTERNAL_LINK},
- {SOCK_FLOAT,
- N_("Scale"),
- 5.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- -1000.0f,
- 1000.0f,
- PROP_NONE,
- SOCK_NO_INTERNAL_LINK},
- {SOCK_FLOAT,
- N_("Mortar Size"),
- 0.02f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.125f,
- PROP_NONE,
- SOCK_NO_INTERNAL_LINK},
- {SOCK_FLOAT,
- N_("Mortar Smooth"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_NONE,
- SOCK_NO_INTERNAL_LINK},
- {SOCK_FLOAT,
- N_("Bias"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- -1.0f,
- 1.0f,
- PROP_NONE,
- SOCK_NO_INTERNAL_LINK},
- {SOCK_FLOAT,
- N_("Brick Width"),
- 0.5f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.01f,
- 100.0f,
- PROP_NONE,
- SOCK_NO_INTERNAL_LINK},
- {SOCK_FLOAT,
- N_("Row Height"),
- 0.25f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.01f,
- 100.0f,
- PROP_NONE,
- SOCK_NO_INTERNAL_LINK},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_tex_brick_out[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT,
- N_("Fac"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_FACTOR,
- SOCK_NO_INTERNAL_LINK},
- {-1, ""},
-};
-
-static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeTexBrick *tex = MEM_callocN(sizeof(NodeTexBrick), "NodeTexBrick");
- BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- BKE_texture_colormapping_default(&tex->base.color_mapping);
-
- tex->offset = 0.5f;
- tex->squash = 1.0f;
- tex->offset_freq = 2;
- tex->squash_freq = 2;
-
- node->storage = tex;
-
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- if (STREQ(sock->name, "Mortar Smooth")) {
- ((bNodeSocketValueFloat *)sock->default_value)->value = 0.1f;
- }
- }
-}
-
-static int node_shader_gpu_tex_brick(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
- node_shader_gpu_tex_mapping(mat, node, in, out);
- NodeTexBrick *tex = (NodeTexBrick *)node->storage;
- float offset_freq = tex->offset_freq;
- float squash_freq = tex->squash_freq;
- return GPU_stack_link(mat,
- node,
- "node_tex_brick",
- in,
- out,
- GPU_uniform(&tex->offset),
- GPU_constant(&offset_freq),
- GPU_uniform(&tex->squash),
- GPU_constant(&squash_freq));
-}
-
-/* node type definition */
-void register_node_type_sh_tex_brick(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_TEX_BRICK, "Brick Texture", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_brick_in, sh_node_tex_brick_out);
- node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tex_brick);
- node_type_storage(
- &ntype, "NodeTexBrick", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_brick);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
new file mode 100644
index 00000000000..81a69ef18da
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
@@ -0,0 +1,306 @@
+/*
+ * 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.
+ */
+
+#include "node_shader_util.hh"
+
+#include "BLI_math_vec_types.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_brick_cc {
+
+static void sh_node_tex_brick_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f).implicit_field();
+ b.add_input<decl::Color>(N_("Color1")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("Color2")).default_value({0.2f, 0.2f, 0.2f, 1.0f});
+ b.add_input<decl::Color>(N_("Mortar")).default_value({0.0f, 0.0f, 0.0f, 1.0f}).no_muted_links();
+ b.add_input<decl::Float>(N_("Scale"))
+ .min(-1000.0f)
+ .max(1000.0f)
+ .default_value(5.0f)
+ .no_muted_links();
+ b.add_input<decl::Float>(N_("Mortar Size"))
+ .min(0.0f)
+ .max(0.125f)
+ .default_value(0.02f)
+ .no_muted_links();
+ b.add_input<decl::Float>(N_("Mortar Smooth")).min(0.0f).max(1.0f).no_muted_links();
+ b.add_input<decl::Float>(N_("Bias")).min(-1.0f).max(1.0f).no_muted_links();
+ b.add_input<decl::Float>(N_("Brick Width"))
+ .min(0.01f)
+ .max(100.0f)
+ .default_value(0.5f)
+ .no_muted_links();
+ b.add_input<decl::Float>(N_("Row Height"))
+ .min(0.01f)
+ .max(100.0f)
+ .default_value(0.25f)
+ .no_muted_links();
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Fac"));
+}
+
+static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col,
+ ptr,
+ "offset",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ IFACE_("Offset"),
+ ICON_NONE);
+ uiItemR(
+ col, ptr, "offset_frequency", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Frequency"), ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "squash", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Squash"), ICON_NONE);
+ uiItemR(
+ col, ptr, "squash_frequency", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Frequency"), ICON_NONE);
+}
+
+static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeTexBrick *tex = MEM_cnew<NodeTexBrick>(__func__);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
+
+ tex->offset = 0.5f;
+ tex->squash = 1.0f;
+ tex->offset_freq = 2;
+ tex->squash_freq = 2;
+
+ node->storage = tex;
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ if (STREQ(sock->name, "Mortar Smooth")) {
+ ((bNodeSocketValueFloat *)sock->default_value)->value = 0.1f;
+ }
+ }
+}
+
+static int node_shader_gpu_tex_brick(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
+ node_shader_gpu_tex_mapping(mat, node, in, out);
+ NodeTexBrick *tex = (NodeTexBrick *)node->storage;
+ float offset_freq = tex->offset_freq;
+ float squash_freq = tex->squash_freq;
+ return GPU_stack_link(mat,
+ node,
+ "node_tex_brick",
+ in,
+ out,
+ GPU_uniform(&tex->offset),
+ GPU_constant(&offset_freq),
+ GPU_uniform(&tex->squash),
+ GPU_constant(&squash_freq));
+}
+
+class BrickFunction : public fn::MultiFunction {
+ private:
+ const float offset_;
+ const int offset_freq_;
+ const float squash_;
+ const int squash_freq_;
+
+ public:
+ BrickFunction(const float offset,
+ const int offset_freq,
+ const float squash,
+ const int squash_freq)
+ : offset_(offset), offset_freq_(offset_freq), squash_(squash), squash_freq_(squash_freq)
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"BrickTexture"};
+ signature.single_input<float3>("Vector");
+ signature.single_input<ColorGeometry4f>("Color1");
+ signature.single_input<ColorGeometry4f>("Color2");
+ signature.single_input<ColorGeometry4f>("Mortar");
+ signature.single_input<float>("Scale");
+ signature.single_input<float>("Mortar Size");
+ signature.single_input<float>("Mortar Smooth");
+ signature.single_input<float>("Bias");
+ signature.single_input<float>("Brick Width");
+ signature.single_input<float>("Row Height");
+ signature.single_output<ColorGeometry4f>("Color");
+ signature.single_output<float>("Fac");
+ return signature.build();
+ }
+
+ /* Fast integer noise. */
+ static float brick_noise(uint n)
+ {
+ n = (n + 1013) & 0x7fffffff;
+ n = (n >> 13) ^ n;
+ const uint nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
+ return 0.5f * ((float)nn / 1073741824.0f);
+ }
+
+ static float smoothstepf(const float f)
+ {
+ const float ff = f * f;
+ return (3.0f * ff - 2.0f * ff * f);
+ }
+
+ static float2 brick(float3 p,
+ float mortar_size,
+ float mortar_smooth,
+ float bias,
+ float brick_width,
+ float row_height,
+ float offset_amount,
+ int offset_frequency,
+ float squash_amount,
+ int squash_frequency)
+ {
+ float offset = 0.0f;
+
+ const int rownum = (int)floorf(p.y / row_height);
+
+ if (offset_frequency && squash_frequency) {
+ brick_width *= (rownum % squash_frequency) ? 1.0f : squash_amount;
+ offset = (rownum % offset_frequency) ? 0.0f : (brick_width * offset_amount);
+ }
+
+ const int bricknum = (int)floorf((p.x + offset) / brick_width);
+
+ const float x = (p.x + offset) - brick_width * bricknum;
+ const float y = p.y - row_height * rownum;
+
+ const float tint = clamp_f(
+ brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias, 0.0f, 1.0f);
+ float min_dist = std::min(std::min(x, y), std::min(brick_width - x, row_height - y));
+
+ float mortar;
+ if (min_dist >= mortar_size) {
+ mortar = 0.0f;
+ }
+ else if (mortar_smooth == 0.0f) {
+ mortar = 1.0f;
+ }
+ else {
+ min_dist = 1.0f - min_dist / mortar_size;
+ mortar = (min_dist < mortar_smooth) ? smoothstepf(min_dist / mortar_smooth) : 1.0f;
+ }
+
+ return float2(tint, mortar);
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
+ const VArray<ColorGeometry4f> &color1_values = params.readonly_single_input<ColorGeometry4f>(
+ 1, "Color1");
+ const VArray<ColorGeometry4f> &color2_values = params.readonly_single_input<ColorGeometry4f>(
+ 2, "Color2");
+ const VArray<ColorGeometry4f> &mortar_values = params.readonly_single_input<ColorGeometry4f>(
+ 3, "Mortar");
+ const VArray<float> &scale = params.readonly_single_input<float>(4, "Scale");
+ const VArray<float> &mortar_size = params.readonly_single_input<float>(5, "Mortar Size");
+ const VArray<float> &mortar_smooth = params.readonly_single_input<float>(6, "Mortar Smooth");
+ const VArray<float> &bias = params.readonly_single_input<float>(7, "Bias");
+ const VArray<float> &brick_width = params.readonly_single_input<float>(8, "Brick Width");
+ const VArray<float> &row_height = params.readonly_single_input<float>(9, "Row Height");
+
+ MutableSpan<ColorGeometry4f> r_color =
+ params.uninitialized_single_output_if_required<ColorGeometry4f>(10, "Color");
+ MutableSpan<float> r_fac = params.uninitialized_single_output_if_required<float>(11, "Fac");
+
+ const bool store_fac = !r_fac.is_empty();
+ const bool store_color = !r_color.is_empty();
+
+ for (int64_t i : mask) {
+ const float2 f2 = brick(vector[i] * scale[i],
+ mortar_size[i],
+ mortar_smooth[i],
+ bias[i],
+ brick_width[i],
+ row_height[i],
+ offset_,
+ offset_freq_,
+ squash_,
+ squash_freq_);
+
+ float4 color_data, color1, color2, mortar;
+ copy_v4_v4(color_data, color1_values[i]);
+ copy_v4_v4(color1, color1_values[i]);
+ copy_v4_v4(color2, color2_values[i]);
+ copy_v4_v4(mortar, mortar_values[i]);
+ const float tint = f2.x;
+ const float f = f2.y;
+
+ if (f != 1.0f) {
+ const float facm = 1.0f - tint;
+ color_data = color1 * facm + color2 * tint;
+ }
+
+ if (store_color) {
+ color_data = color_data * (1.0f - f) + mortar * f;
+ copy_v4_v4(r_color[i], color_data);
+ }
+ if (store_fac) {
+ r_fac[i] = f;
+ }
+ }
+ }
+};
+
+static void sh_node_brick_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+{
+ bNode &node = builder.node();
+ NodeTexBrick *tex = (NodeTexBrick *)node.storage;
+
+ builder.construct_and_set_matching_fn<BrickFunction>(
+ tex->offset, tex->offset_freq, tex->squash, tex->squash_freq);
+}
+
+} // namespace blender::nodes::node_shader_tex_brick_cc
+
+void register_node_type_sh_tex_brick()
+{
+ namespace file_ns = blender::nodes::node_shader_tex_brick_cc;
+
+ static bNodeType ntype;
+
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_BRICK, "Brick Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_brick_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_brick;
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_brick);
+ node_type_storage(
+ &ntype, "NodeTexBrick", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_brick);
+ ntype.build_multi_function = file_ns::sh_node_brick_build_multi_function;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
deleted file mode 100644
index 75219f4c3f9..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
+++ /dev/null
@@ -1,90 +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.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_tex_checker_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_RGBA, N_("Color1"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_RGBA, N_("Color2"), 0.2f, 0.2f, 0.2f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT,
- N_("Scale"),
- 5.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- -1000.0f,
- 1000.0f,
- PROP_NONE,
- SOCK_NO_INTERNAL_LINK},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_tex_checker_out[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT,
- N_("Fac"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_FACTOR,
- SOCK_NO_INTERNAL_LINK},
- {-1, ""},
-};
-
-static void node_shader_init_tex_checker(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeTexChecker *tex = MEM_callocN(sizeof(NodeTexChecker), "NodeTexChecker");
- BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- BKE_texture_colormapping_default(&tex->base.color_mapping);
-
- node->storage = tex;
-}
-
-static int node_shader_gpu_tex_checker(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
- node_shader_gpu_tex_mapping(mat, node, in, out);
-
- return GPU_stack_link(mat, node, "node_tex_checker", in, out);
-}
-
-/* node type definition */
-void register_node_type_sh_tex_checker(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_TEX_CHECKER, "Checker Texture", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_checker_in, sh_node_tex_checker_out);
- node_type_init(&ntype, node_shader_init_tex_checker);
- node_type_storage(
- &ntype, "NodeTexChecker", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_checker);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
new file mode 100644
index 00000000000..6022f13821a
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
@@ -0,0 +1,137 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_tex_checker_cc {
+
+static void sh_node_tex_checker_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f).implicit_field();
+ b.add_input<decl::Color>(N_("Color1")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("Color2")).default_value({0.2f, 0.2f, 0.2f, 1.0f});
+ b.add_input<decl::Float>(N_("Scale"))
+ .min(-10000.0f)
+ .max(10000.0f)
+ .default_value(5.0f)
+ .no_muted_links();
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Fac"));
+}
+
+static void node_shader_init_tex_checker(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeTexChecker *tex = MEM_cnew<NodeTexChecker>(__func__);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
+
+ node->storage = tex;
+}
+
+static int node_shader_gpu_tex_checker(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
+ node_shader_gpu_tex_mapping(mat, node, in, out);
+
+ return GPU_stack_link(mat, node, "node_tex_checker", in, out);
+}
+
+class NodeTexChecker : public fn::MultiFunction {
+ public:
+ NodeTexChecker()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Checker"};
+ signature.single_input<float3>("Vector");
+ signature.single_input<ColorGeometry4f>("Color1");
+ signature.single_input<ColorGeometry4f>("Color2");
+ signature.single_input<float>("Scale");
+ signature.single_output<ColorGeometry4f>("Color");
+ signature.single_output<float>("Fac");
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ fn::MFParams params,
+ fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
+ const VArray<ColorGeometry4f> &color1 = params.readonly_single_input<ColorGeometry4f>(
+ 1, "Color1");
+ const VArray<ColorGeometry4f> &color2 = params.readonly_single_input<ColorGeometry4f>(
+ 2, "Color2");
+ const VArray<float> &scale = params.readonly_single_input<float>(3, "Scale");
+ MutableSpan<ColorGeometry4f> r_color =
+ params.uninitialized_single_output_if_required<ColorGeometry4f>(4, "Color");
+ MutableSpan<float> r_fac = params.uninitialized_single_output<float>(5, "Fac");
+
+ for (int64_t i : mask) {
+ /* Avoid precision issues on unit coordinates. */
+ const float3 p = (vector[i] * scale[i] + 0.000001f) * 0.999999f;
+
+ const int xi = abs((int)(floorf(p.x)));
+ const int yi = abs((int)(floorf(p.y)));
+ const int zi = abs((int)(floorf(p.z)));
+
+ r_fac[i] = ((xi % 2 == yi % 2) == (zi % 2)) ? 1.0f : 0.0f;
+ }
+
+ if (!r_color.is_empty()) {
+ for (int64_t i : mask) {
+ r_color[i] = (r_fac[i] == 1.0f) ? color1[i] : color2[i];
+ }
+ }
+ }
+};
+
+static void sh_node_tex_checker_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
+{
+ static NodeTexChecker fn;
+ builder.set_matching_fn(fn);
+}
+
+} // namespace blender::nodes::node_shader_tex_checker_cc
+
+void register_node_type_sh_tex_checker()
+{
+ namespace file_ns = blender::nodes::node_shader_tex_checker_cc;
+
+ static bNodeType ntype;
+
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_CHECKER, "Checker Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_checker_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_checker);
+ node_type_storage(
+ &ntype, "NodeTexChecker", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_checker);
+ ntype.build_multi_function = file_ns::sh_node_tex_checker_build_multi_function;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc
index 76966e0bbee..1bbaed88ea5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc
@@ -17,22 +17,31 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "DNA_customdata_types.h"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_tex_coord_out[] = {
- {SOCK_VECTOR, N_("Generated"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("UV"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Object"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Camera"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Window"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Reflection"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_tex_coord_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Generated"));
+ b.add_output<decl::Vector>(N_("Normal"));
+ b.add_output<decl::Vector>(N_("UV"));
+ b.add_output<decl::Vector>(N_("Object"));
+ b.add_output<decl::Vector>(N_("Camera"));
+ b.add_output<decl::Vector>(N_("Window"));
+ b.add_output<decl::Vector>(N_("Reflection"));
+}
+
+static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "object", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+ uiItemR(layout, ptr, "from_instancer", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+}
static int node_shader_gpu_tex_coord(GPUMaterial *mat,
bNode *node,
@@ -42,25 +51,27 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
{
Object *ob = (Object *)node->id;
- /* Use special matrix to let the shader branch to using the render object's matrix. */
- float dummy_matrix[4][4];
- dummy_matrix[3][3] = 0.0f;
- GPUNodeLink *inv_obmat = (ob != NULL) ? GPU_uniform(&ob->imat[0][0]) :
- GPU_uniform(&dummy_matrix[0][0]);
+ GPUNodeLink *inv_obmat = (ob != nullptr) ? GPU_uniform(&ob->imat[0][0]) :
+ GPU_builtin(GPU_INVERSE_OBJECT_MATRIX);
/* Opti: don't request orco if not needed. */
- GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant((float[4]){0.0f, 0.0f, 0.0f, 0.0f}) :
+ const float default_coords[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant(default_coords) :
GPU_attribute(mat, CD_ORCO, "");
GPUNodeLink *mtface = GPU_attribute(mat, CD_MTFACE, "");
+ GPUNodeLink *viewpos = GPU_builtin(GPU_VIEW_POSITION);
+ GPUNodeLink *worldnor = GPU_builtin(GPU_WORLD_NORMAL);
+ GPUNodeLink *texcofacs = GPU_builtin(GPU_CAMERA_TEXCO_FACTORS);
if (out[0].hasoutput) {
GPU_link(mat, "generated_from_orco", orco, &orco);
}
- GPU_stack_link(mat, node, "node_tex_coord", in, out, inv_obmat, orco, mtface);
+ GPU_stack_link(
+ mat, node, "node_tex_coord", in, out, viewpos, worldnor, inv_obmat, texcofacs, orco, mtface);
- /* for each output. */
- for (int i = 0; sh_node_tex_coord_out[i].type != -1; i++) {
+ int i;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) {
node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
/* Normalize some vectors after dFdx/dFdy offsets.
* This is the case for interpolated, non linear functions.
@@ -74,23 +85,26 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
out[i].link,
out[i].link,
&out[i].link,
- NULL);
+ nullptr);
}
}
return 1;
}
+} // namespace blender::nodes::node_shader_tex_coord_cc
+
/* node type definition */
-void register_node_type_sh_tex_coord(void)
+void register_node_type_sh_tex_coord()
{
+ namespace file_ns = blender::nodes::node_shader_tex_coord_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_COORD, "Texture Coordinate", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_tex_coord_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_tex_coord);
+ sh_node_type_base(&ntype, SH_NODE_TEX_COORD, "Texture Coordinate", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_coord;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_coord);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc
index 51ced8c2842..24ecdee12d8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc
@@ -17,23 +17,19 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_tex_environment_cc {
-static bNodeSocketTemplate sh_node_tex_environment_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_tex_environment_out[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector")).hide_value();
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+}
static void node_shader_init_tex_environment(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexEnvironment *tex = MEM_callocN(sizeof(NodeTexEnvironment), "NodeTexEnvironment");
+ NodeTexEnvironment *tex = MEM_cnew<NodeTexEnvironment>("NodeTexEnvironment");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->projection = SHD_PROJ_EQUIRECTANGULAR;
@@ -49,12 +45,12 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
GPUNodeStack *out)
{
Image *ima = (Image *)node->id;
- NodeTexEnvironment *tex = node->storage;
+ NodeTexEnvironment *tex = (NodeTexEnvironment *)node->storage;
/* We get the image user from the original node, since GPU image keeps
* a pointer to it and the dependency refreshes the original. */
bNode *node_original = node->original ? node->original : node;
- NodeTexImage *tex_original = node_original->storage;
+ NodeTexImage *tex_original = (NodeTexImage *)node_original->storage;
ImageUser *iuser = &tex_original->iuser;
eGPUSamplerState sampler = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER;
/* TODO(fclem): For now assume mipmap is always enabled. */
@@ -130,18 +126,22 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
return true;
}
+} // namespace blender::nodes::node_shader_tex_environment_cc
+
/* node type definition */
-void register_node_type_sh_tex_environment(void)
+void register_node_type_sh_tex_environment()
{
+ namespace file_ns = blender::nodes::node_shader_tex_environment_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_ENVIRONMENT, "Environment Texture", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_environment_in, sh_node_tex_environment_out);
- node_type_init(&ntype, node_shader_init_tex_environment);
+ sh_node_type_base(&ntype, SH_NODE_TEX_ENVIRONMENT, "Environment Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_environment);
node_type_storage(
&ntype, "NodeTexEnvironment", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_environment);
- node_type_label(&ntype, node_image_label);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_environment);
+ ntype.labelfunc = node_image_label;
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
index e0520ee49d3..53be5bc09d9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
@@ -17,23 +17,29 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_gradient_cc {
static void sh_node_tex_gradient_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Vector>("Vector").hide_value();
- b.add_output<decl::Color>("Color").no_muted_links();
- b.add_output<decl::Float>("Fac").no_muted_links();
-};
+ b.is_function_node();
+ b.add_input<decl::Vector>(N_("Vector")).hide_value().implicit_field();
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+ b.add_output<decl::Float>(N_("Fac")).no_muted_links();
+}
-} // namespace blender::nodes
+static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "gradient_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_tex_gradient(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexGradient *tex = (NodeTexGradient *)MEM_callocN(sizeof(NodeTexGradient),
- "NodeTexGradient");
+ NodeTexGradient *tex = MEM_cnew<NodeTexGradient>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->gradient_type = SHD_BLEND_LINEAR;
@@ -55,17 +61,122 @@ static int node_shader_gpu_tex_gradient(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_tex_gradient", in, out, GPU_constant(&gradient_type));
}
-/* node type definition */
-void register_node_type_sh_tex_gradient(void)
+class GradientFunction : public fn::MultiFunction {
+ private:
+ int gradient_type_;
+
+ public:
+ GradientFunction(int gradient_type) : gradient_type_(gradient_type)
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"GradientFunction"};
+ signature.single_input<float3>("Vector");
+ signature.single_output<ColorGeometry4f>("Color");
+ signature.single_output<float>("Fac");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
+
+ MutableSpan<ColorGeometry4f> r_color =
+ params.uninitialized_single_output_if_required<ColorGeometry4f>(1, "Color");
+ MutableSpan<float> fac = params.uninitialized_single_output<float>(2, "Fac");
+
+ const bool compute_color = !r_color.is_empty();
+
+ switch (gradient_type_) {
+ case SHD_BLEND_LINEAR: {
+ for (int64_t i : mask) {
+ fac[i] = vector[i].x;
+ }
+ break;
+ }
+ case SHD_BLEND_QUADRATIC: {
+ for (int64_t i : mask) {
+ const float r = std::max(vector[i].x, 0.0f);
+ fac[i] = r * r;
+ }
+ break;
+ }
+ case SHD_BLEND_EASING: {
+ for (int64_t i : mask) {
+ const float r = std::min(std::max(vector[i].x, 0.0f), 1.0f);
+ const float t = r * r;
+ fac[i] = (3.0f * t - 2.0f * t * r);
+ }
+ break;
+ }
+ case SHD_BLEND_DIAGONAL: {
+ for (int64_t i : mask) {
+ fac[i] = (vector[i].x + vector[i].y) * 0.5f;
+ }
+ break;
+ }
+ case SHD_BLEND_RADIAL: {
+ for (int64_t i : mask) {
+ fac[i] = atan2f(vector[i].y, vector[i].x) / (M_PI * 2.0f) + 0.5f;
+ }
+ break;
+ }
+ case SHD_BLEND_QUADRATIC_SPHERE: {
+ for (int64_t i : mask) {
+ /* Bias a little bit for the case where input is a unit length vector,
+ * to get exactly zero instead of a small random value depending
+ * on float precision. */
+ const float r = std::max(0.999999f - math::length(vector[i]), 0.0f);
+ fac[i] = r * r;
+ }
+ break;
+ }
+ case SHD_BLEND_SPHERICAL: {
+ for (int64_t i : mask) {
+ /* Bias a little bit for the case where input is a unit length vector,
+ * to get exactly zero instead of a small random value depending
+ * on float precision. */
+ fac[i] = std::max(0.999999f - math::length(vector[i]), 0.0f);
+ }
+ break;
+ }
+ }
+ if (compute_color) {
+ for (int64_t i : mask) {
+ r_color[i] = ColorGeometry4f(fac[i], fac[i], fac[i], 1.0f);
+ }
+ }
+ }
+};
+
+static void sh_node_gradient_tex_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
+{
+ bNode &node = builder.node();
+ NodeTexGradient *tex = (NodeTexGradient *)node.storage;
+ builder.construct_and_set_matching_fn<GradientFunction>(tex->gradient_type);
+}
+
+} // namespace blender::nodes::node_shader_tex_gradient_cc
+
+void register_node_type_sh_tex_gradient()
{
+ namespace file_ns = blender::nodes::node_shader_tex_gradient_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_GRADIENT, "Gradient Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_gradient_declare;
- node_type_init(&ntype, node_shader_init_tex_gradient);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_GRADIENT, "Gradient Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_gradient_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_gradient;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_gradient);
node_type_storage(
&ntype, "NodeTexGradient", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_gradient);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_gradient);
+ ntype.build_multi_function = file_ns::sh_node_gradient_tex_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
index bf7c4edc1c9..7c7154b8f7a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
@@ -17,33 +17,21 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_tex_image_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_tex_image_out[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
- {SOCK_FLOAT,
- N_("Alpha"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_NONE,
- SOCK_NO_INTERNAL_LINK},
- {-1, ""},
-};
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_tex_image_cc {
+
+static void sh_node_tex_image_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Vector>(N_("Vector")).implicit_field();
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+ b.add_output<decl::Float>(N_("Alpha")).no_muted_links();
+}
static void node_shader_init_tex_image(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexImage *tex = MEM_callocN(sizeof(NodeTexImage), "NodeTexImage");
+ NodeTexImage *tex = MEM_cnew<NodeTexImage>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
BKE_imageuser_default(&tex->iuser);
@@ -58,12 +46,12 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
GPUNodeStack *out)
{
Image *ima = (Image *)node->id;
- NodeTexImage *tex = node->storage;
+ NodeTexImage *tex = (NodeTexImage *)node->storage;
/* We get the image user from the original node, since GPU image keeps
* a pointer to it and the dependency refreshes the original. */
bNode *node_original = node->original ? node->original : node;
- NodeTexImage *tex_original = node_original->storage;
+ NodeTexImage *tex_original = (NodeTexImage *)node_original->storage;
ImageUser *iuser = &tex_original->iuser;
if (!ima) {
@@ -78,7 +66,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
node_shader_gpu_tex_mapping(mat, node, in, out);
- eGPUSamplerState sampler_state = 0;
+ eGPUSamplerState sampler_state = GPU_SAMPLER_DEFAULT;
switch (tex->extension) {
case SHD_IMAGE_EXTENSION_REPEAT:
@@ -94,7 +82,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
if (tex->interpolation != SHD_INTERP_CLOSEST) {
sampler_state |= GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER;
/* TODO(fclem): For now assume mipmap is always enabled. */
- sampler_state |= true ? GPU_SAMPLER_MIPMAP : 0;
+ sampler_state |= GPU_SAMPLER_MIPMAP;
}
const bool use_cubic = ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART);
@@ -181,18 +169,21 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
return true;
}
-/* node type definition */
-void register_node_type_sh_tex_image(void)
+} // namespace blender::nodes::node_shader_tex_image_cc
+
+void register_node_type_sh_tex_image()
{
+ namespace file_ns = blender::nodes::node_shader_tex_image_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_IMAGE, "Image Texture", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_image_in, sh_node_tex_image_out);
- node_type_init(&ntype, node_shader_init_tex_image);
+ sh_node_type_base(&ntype, SH_NODE_TEX_IMAGE, "Image Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_image_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_image);
node_type_storage(
&ntype, "NodeTexImage", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_image);
- node_type_label(&ntype, node_image_label);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_image);
+ ntype.labelfunc = node_image_label;
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
deleted file mode 100644
index 51721f8bb09..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
+++ /dev/null
@@ -1,84 +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.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_tex_magic_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
- {SOCK_FLOAT, N_("Distortion"), 1.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_tex_magic_out[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
- {SOCK_FLOAT,
- N_("Fac"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_FACTOR,
- SOCK_NO_INTERNAL_LINK},
- {-1, ""},
-};
-
-static void node_shader_init_tex_magic(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeTexMagic *tex = MEM_callocN(sizeof(NodeTexMagic), "NodeTexMagic");
- BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- BKE_texture_colormapping_default(&tex->base.color_mapping);
- tex->depth = 2;
-
- node->storage = tex;
-}
-
-static int node_shader_gpu_tex_magic(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- NodeTexMagic *tex = (NodeTexMagic *)node->storage;
- float depth = tex->depth;
-
- node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
- node_shader_gpu_tex_mapping(mat, node, in, out);
-
- return GPU_stack_link(mat, node, "node_tex_magic", in, out, GPU_constant(&depth));
-}
-
-/* node type definition */
-void register_node_type_sh_tex_magic(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_TEX_MAGIC, "Magic Texture", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_magic_in, sh_node_tex_magic_out);
- node_type_init(&ntype, node_shader_init_tex_magic);
- node_type_storage(
- &ntype, "NodeTexMagic", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_magic);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
new file mode 100644
index 00000000000..e40914783b6
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_magic_cc {
+
+static void sh_node_tex_magic_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Vector>(N_("Vector")).implicit_field();
+ b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
+ b.add_input<decl::Float>(N_("Distortion")).min(-1000.0f).max(1000.0f).default_value(1.0f);
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+ b.add_output<decl::Float>(N_("Fac")).no_muted_links();
+}
+
+static void node_shader_buts_tex_magic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "turbulence_depth", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+static void node_shader_init_tex_magic(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeTexMagic *tex = MEM_cnew<NodeTexMagic>(__func__);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
+ tex->depth = 2;
+
+ node->storage = tex;
+}
+
+static int node_shader_gpu_tex_magic(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ NodeTexMagic *tex = (NodeTexMagic *)node->storage;
+ float depth = tex->depth;
+
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
+ node_shader_gpu_tex_mapping(mat, node, in, out);
+
+ return GPU_stack_link(mat, node, "node_tex_magic", in, out, GPU_constant(&depth));
+}
+
+class MagicFunction : public fn::MultiFunction {
+ private:
+ int depth_;
+
+ public:
+ MagicFunction(int depth) : depth_(depth)
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"MagicFunction"};
+ signature.single_input<float3>("Vector");
+ signature.single_input<float>("Scale");
+ signature.single_input<float>("Distortion");
+ signature.single_output<ColorGeometry4f>("Color");
+ signature.single_output<float>("Fac");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
+ const VArray<float> &scale = params.readonly_single_input<float>(1, "Scale");
+ const VArray<float> &distortion = params.readonly_single_input<float>(2, "Distortion");
+
+ MutableSpan<ColorGeometry4f> r_color = params.uninitialized_single_output<ColorGeometry4f>(
+ 3, "Color");
+ MutableSpan<float> r_fac = params.uninitialized_single_output_if_required<float>(4, "Fac");
+
+ const bool compute_factor = !r_fac.is_empty();
+
+ for (int64_t i : mask) {
+ const float3 co = vector[i] * scale[i];
+ const float distort = distortion[i];
+ float x = sinf((co[0] + co[1] + co[2]) * 5.0f);
+ float y = cosf((-co[0] + co[1] - co[2]) * 5.0f);
+ float z = -cosf((-co[0] - co[1] + co[2]) * 5.0f);
+
+ if (depth_ > 0) {
+ x *= distort;
+ y *= distort;
+ z *= distort;
+ y = -cosf(x - y + z);
+ y *= distort;
+
+ if (depth_ > 1) {
+ x = cosf(x - y - z);
+ x *= distort;
+
+ if (depth_ > 2) {
+ z = sinf(-x - y - z);
+ z *= distort;
+
+ if (depth_ > 3) {
+ x = -cosf(-x + y - z);
+ x *= distort;
+
+ if (depth_ > 4) {
+ y = -sinf(-x + y + z);
+ y *= distort;
+
+ if (depth_ > 5) {
+ y = -cosf(-x + y + z);
+ y *= distort;
+
+ if (depth_ > 6) {
+ x = cosf(x + y + z);
+ x *= distort;
+
+ if (depth_ > 7) {
+ z = sinf(x + y - z);
+ z *= distort;
+
+ if (depth_ > 8) {
+ x = -cosf(-x - y + z);
+ x *= distort;
+
+ if (depth_ > 9) {
+ y = -sinf(x - y + z);
+ y *= distort;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (distort != 0.0f) {
+ const float d = distort * 2.0f;
+ x /= d;
+ y /= d;
+ z /= d;
+ }
+
+ r_color[i] = ColorGeometry4f(0.5f - x, 0.5f - y, 0.5f - z, 1.0f);
+ }
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ r_fac[i] = (r_color[i].r + r_color[i].g + r_color[i].b) * (1.0f / 3.0f);
+ }
+ }
+ }
+};
+
+static void sh_node_magic_tex_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
+{
+ bNode &node = builder.node();
+ NodeTexMagic *tex = (NodeTexMagic *)node.storage;
+ builder.construct_and_set_matching_fn<MagicFunction>(tex->depth);
+}
+
+} // namespace blender::nodes::node_shader_tex_magic_cc
+
+void register_node_type_sh_tex_magic()
+{
+ namespace file_ns = blender::nodes::node_shader_tex_magic_cc;
+
+ static bNodeType ntype;
+
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_MAGIC, "Magic Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_magic_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_magic;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_magic);
+ node_type_storage(
+ &ntype, "NodeTexMagic", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_magic);
+ ntype.build_multi_function = file_ns::sh_node_magic_tex_build_multi_function;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
index 23f150d8135..45c2a83c178 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
@@ -17,30 +17,43 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+#include "BLI_noise.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_musgrave_cc {
+
+NODE_STORAGE_FUNCS(NodeTexMusgrave)
static void sh_node_tex_musgrave_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").hide_value();
- b.add_input<decl::Float>("W").min(-1000.0f).max(1000.0f);
- b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f);
- b.add_input<decl::Float>("Detail").min(0.0f).max(16.0f).default_value(2.0f);
- b.add_input<decl::Float>("Dimension").min(0.0f).max(1000.0f).default_value(2.0f);
- b.add_input<decl::Float>("Lacunarity").min(0.0f).max(1000.0f).default_value(2.0f);
- b.add_input<decl::Float>("Offset").min(-1000.0f).max(1000.0f);
- b.add_input<decl::Float>("Gain").min(0.0f).max(1000.0f).default_value(1.0f);
- b.add_output<decl::Float>("Fac").no_muted_links();
-};
+ b.add_input<decl::Vector>(N_("Vector")).hide_value().implicit_field();
+ b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f).make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is much faster. */
+ node_storage(node).dimensions = 1;
+ });
+ b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
+ b.add_input<decl::Float>(N_("Detail")).min(0.0f).max(15.0f).default_value(2.0f);
+ b.add_input<decl::Float>(N_("Dimension")).min(0.0f).max(1000.0f).default_value(2.0f);
+ b.add_input<decl::Float>(N_("Lacunarity")).min(0.0f).max(1000.0f).default_value(2.0f);
+ b.add_input<decl::Float>(N_("Offset")).min(-1000.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Gain")).min(0.0f).max(1000.0f).default_value(1.0f);
+ b.add_output<decl::Float>(N_("Fac")).no_muted_links();
+}
-} // namespace blender::nodes
+static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "musgrave_dimensions", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "musgrave_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexMusgrave *tex = (NodeTexMusgrave *)MEM_callocN(sizeof(NodeTexMusgrave),
- "NodeTexMusgrave");
+ NodeTexMusgrave *tex = MEM_cnew<NodeTexMusgrave>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->musgrave_type = SHD_MUSGRAVE_FBM;
@@ -102,40 +115,447 @@ static int node_shader_gpu_tex_musgrave(GPUMaterial *mat,
return GPU_stack_link(mat, node, name, in, out);
}
-static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_shader_update_tex_musgrave(bNodeTree *ntree, bNode *node)
{
- NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
+ const NodeTexMusgrave &storage = node_storage(*node);
bNodeSocket *inVectorSock = nodeFindSocket(node, SOCK_IN, "Vector");
bNodeSocket *inWSock = nodeFindSocket(node, SOCK_IN, "W");
bNodeSocket *inOffsetSock = nodeFindSocket(node, SOCK_IN, "Offset");
bNodeSocket *inGainSock = nodeFindSocket(node, SOCK_IN, "Gain");
- nodeSetSocketAvailability(inVectorSock, tex->dimensions != 1);
- nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4);
- nodeSetSocketAvailability(inOffsetSock,
- tex->musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL &&
- tex->musgrave_type != SHD_MUSGRAVE_FBM);
- nodeSetSocketAvailability(inGainSock,
- tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL ||
- tex->musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL);
+ nodeSetSocketAvailability(ntree, inVectorSock, storage.dimensions != 1);
+ nodeSetSocketAvailability(ntree, inWSock, storage.dimensions == 1 || storage.dimensions == 4);
+ nodeSetSocketAvailability(ntree,
+ inOffsetSock,
+ storage.musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL &&
+ storage.musgrave_type != SHD_MUSGRAVE_FBM);
+ nodeSetSocketAvailability(ntree,
+ inGainSock,
+ storage.musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL ||
+ storage.musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL);
bNodeSocket *outFacSock = nodeFindSocket(node, SOCK_OUT, "Fac");
node_sock_label(outFacSock, "Height");
}
-void register_node_type_sh_tex_musgrave(void)
+class MusgraveFunction : public fn::MultiFunction {
+ private:
+ const int dimensions_;
+ const int musgrave_type_;
+
+ public:
+ MusgraveFunction(const int dimensions, const int musgrave_type)
+ : dimensions_(dimensions), musgrave_type_(musgrave_type)
+ {
+ BLI_assert(dimensions >= 1 && dimensions <= 4);
+ BLI_assert(musgrave_type >= 0 && musgrave_type <= 4);
+ static std::array<fn::MFSignature, 20> signatures{
+ create_signature(1, SHD_MUSGRAVE_MULTIFRACTAL),
+ create_signature(2, SHD_MUSGRAVE_MULTIFRACTAL),
+ create_signature(3, SHD_MUSGRAVE_MULTIFRACTAL),
+ create_signature(4, SHD_MUSGRAVE_MULTIFRACTAL),
+
+ create_signature(1, SHD_MUSGRAVE_FBM),
+ create_signature(2, SHD_MUSGRAVE_FBM),
+ create_signature(3, SHD_MUSGRAVE_FBM),
+ create_signature(4, SHD_MUSGRAVE_FBM),
+
+ create_signature(1, SHD_MUSGRAVE_HYBRID_MULTIFRACTAL),
+ create_signature(2, SHD_MUSGRAVE_HYBRID_MULTIFRACTAL),
+ create_signature(3, SHD_MUSGRAVE_HYBRID_MULTIFRACTAL),
+ create_signature(4, SHD_MUSGRAVE_HYBRID_MULTIFRACTAL),
+
+ create_signature(1, SHD_MUSGRAVE_RIDGED_MULTIFRACTAL),
+ create_signature(2, SHD_MUSGRAVE_RIDGED_MULTIFRACTAL),
+ create_signature(3, SHD_MUSGRAVE_RIDGED_MULTIFRACTAL),
+ create_signature(4, SHD_MUSGRAVE_RIDGED_MULTIFRACTAL),
+
+ create_signature(1, SHD_MUSGRAVE_HETERO_TERRAIN),
+ create_signature(2, SHD_MUSGRAVE_HETERO_TERRAIN),
+ create_signature(3, SHD_MUSGRAVE_HETERO_TERRAIN),
+ create_signature(4, SHD_MUSGRAVE_HETERO_TERRAIN),
+ };
+ this->set_signature(&signatures[dimensions + musgrave_type * 4 - 1]);
+ }
+
+ static fn::MFSignature create_signature(const int dimensions, const int musgrave_type)
+ {
+ fn::MFSignatureBuilder signature{"Musgrave"};
+
+ if (ELEM(dimensions, 2, 3, 4)) {
+ signature.single_input<float3>("Vector");
+ }
+ if (ELEM(dimensions, 1, 4)) {
+ signature.single_input<float>("W");
+ }
+ signature.single_input<float>("Scale");
+ signature.single_input<float>("Detail");
+ signature.single_input<float>("Dimension");
+ signature.single_input<float>("Lacunarity");
+ if (ELEM(musgrave_type,
+ SHD_MUSGRAVE_RIDGED_MULTIFRACTAL,
+ SHD_MUSGRAVE_HYBRID_MULTIFRACTAL,
+ SHD_MUSGRAVE_HETERO_TERRAIN)) {
+ signature.single_input<float>("Offset");
+ }
+ if (ELEM(musgrave_type, SHD_MUSGRAVE_RIDGED_MULTIFRACTAL, SHD_MUSGRAVE_HYBRID_MULTIFRACTAL)) {
+ signature.single_input<float>("Gain");
+ }
+
+ signature.single_output<float>("Fac");
+
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ auto get_vector = [&](int param_index) -> VArray<float3> {
+ return params.readonly_single_input<float3>(param_index, "Vector");
+ };
+ auto get_w = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "W");
+ };
+ auto get_scale = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Scale");
+ };
+ auto get_detail = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Detail");
+ };
+ auto get_dimension = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Dimension");
+ };
+ auto get_lacunarity = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Lacunarity");
+ };
+ auto get_offset = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Offset");
+ };
+ auto get_gain = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Gain");
+ };
+
+ auto get_r_factor = [&](int param_index) -> MutableSpan<float> {
+ return params.uninitialized_single_output_if_required<float>(param_index, "Fac");
+ };
+
+ int param = ELEM(dimensions_, 2, 3, 4) + ELEM(dimensions_, 1, 4);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &detail = get_detail(param++);
+ const VArray<float> &dimension = get_dimension(param++);
+ const VArray<float> &lacunarity = get_lacunarity(param++);
+
+ switch (musgrave_type_) {
+ case SHD_MUSGRAVE_MULTIFRACTAL: {
+ MutableSpan<float> r_factor = get_r_factor(param++);
+ const bool compute_factor = !r_factor.is_empty();
+ switch (dimensions_) {
+ case 1: {
+ const VArray<float> &w = get_w(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float position = w[i] * scale[i];
+ r_factor[i] = noise::musgrave_multi_fractal(
+ position, dimension[i], lacunarity[i], detail[i]);
+ }
+ }
+ break;
+ }
+ case 2: {
+ const VArray<float3> &vector = get_vector(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 pxyz = vector[i] * scale[i];
+ const float2 position = float2(pxyz[0], pxyz[1]);
+ r_factor[i] = noise::musgrave_multi_fractal(
+ position, dimension[i], lacunarity[i], detail[i]);
+ }
+ }
+ break;
+ }
+ case 3: {
+ const VArray<float3> &vector = get_vector(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 position = vector[i] * scale[i];
+ r_factor[i] = noise::musgrave_multi_fractal(
+ position, dimension[i], lacunarity[i], detail[i]);
+ }
+ }
+ break;
+ }
+ case 4: {
+ const VArray<float3> &vector = get_vector(0);
+ const VArray<float> &w = get_w(1);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 pxyz = vector[i] * scale[i];
+ const float pw = w[i] * scale[i];
+ const float4 position{pxyz[0], pxyz[1], pxyz[2], pw};
+ r_factor[i] = noise::musgrave_multi_fractal(
+ position, dimension[i], lacunarity[i], detail[i]);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case SHD_MUSGRAVE_RIDGED_MULTIFRACTAL: {
+ const VArray<float> &offset = get_offset(param++);
+ const VArray<float> &gain = get_gain(param++);
+ MutableSpan<float> r_factor = get_r_factor(param++);
+ const bool compute_factor = !r_factor.is_empty();
+ switch (dimensions_) {
+ case 1: {
+ const VArray<float> &w = get_w(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float position = w[i] * scale[i];
+ r_factor[i] = noise::musgrave_ridged_multi_fractal(
+ position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]);
+ }
+ }
+ break;
+ }
+ case 2: {
+ const VArray<float3> &vector = get_vector(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 pxyz = vector[i] * scale[i];
+ const float2 position = float2(pxyz[0], pxyz[1]);
+ r_factor[i] = noise::musgrave_ridged_multi_fractal(
+ position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]);
+ }
+ }
+ break;
+ }
+ case 3: {
+ const VArray<float3> &vector = get_vector(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 position = vector[i] * scale[i];
+ r_factor[i] = noise::musgrave_ridged_multi_fractal(
+ position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]);
+ }
+ }
+ break;
+ }
+ case 4: {
+ const VArray<float3> &vector = get_vector(0);
+ const VArray<float> &w = get_w(1);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 pxyz = vector[i] * scale[i];
+ const float pw = w[i] * scale[i];
+ const float4 position{pxyz[0], pxyz[1], pxyz[2], pw};
+ r_factor[i] = noise::musgrave_ridged_multi_fractal(
+ position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case SHD_MUSGRAVE_HYBRID_MULTIFRACTAL: {
+ const VArray<float> &offset = get_offset(param++);
+ const VArray<float> &gain = get_gain(param++);
+ MutableSpan<float> r_factor = get_r_factor(param++);
+ const bool compute_factor = !r_factor.is_empty();
+ switch (dimensions_) {
+ case 1: {
+ const VArray<float> &w = get_w(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float position = w[i] * scale[i];
+ r_factor[i] = noise::musgrave_hybrid_multi_fractal(
+ position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]);
+ }
+ }
+ break;
+ }
+ case 2: {
+ const VArray<float3> &vector = get_vector(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 pxyz = vector[i] * scale[i];
+ const float2 position = float2(pxyz[0], pxyz[1]);
+ r_factor[i] = noise::musgrave_hybrid_multi_fractal(
+ position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]);
+ }
+ }
+ break;
+ }
+ case 3: {
+ const VArray<float3> &vector = get_vector(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 position = vector[i] * scale[i];
+ r_factor[i] = noise::musgrave_hybrid_multi_fractal(
+ position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]);
+ }
+ }
+ break;
+ }
+ case 4: {
+ const VArray<float3> &vector = get_vector(0);
+ const VArray<float> &w = get_w(1);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 pxyz = vector[i] * scale[i];
+ const float pw = w[i] * scale[i];
+ const float4 position{pxyz[0], pxyz[1], pxyz[2], pw};
+ r_factor[i] = noise::musgrave_hybrid_multi_fractal(
+ position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case SHD_MUSGRAVE_FBM: {
+ MutableSpan<float> r_factor = get_r_factor(param++);
+ const bool compute_factor = !r_factor.is_empty();
+ switch (dimensions_) {
+ case 1: {
+ const VArray<float> &w = get_w(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float position = w[i] * scale[i];
+ r_factor[i] = noise::musgrave_fBm(
+ position, dimension[i], lacunarity[i], detail[i]);
+ }
+ }
+ break;
+ }
+ case 2: {
+ const VArray<float3> &vector = get_vector(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 pxyz = vector[i] * scale[i];
+ const float2 position = float2(pxyz[0], pxyz[1]);
+ r_factor[i] = noise::musgrave_fBm(
+ position, dimension[i], lacunarity[i], detail[i]);
+ }
+ }
+ break;
+ }
+ case 3: {
+ const VArray<float3> &vector = get_vector(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 position = vector[i] * scale[i];
+ r_factor[i] = noise::musgrave_fBm(
+ position, dimension[i], lacunarity[i], detail[i]);
+ }
+ }
+ break;
+ }
+ case 4: {
+ const VArray<float3> &vector = get_vector(0);
+ const VArray<float> &w = get_w(1);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 pxyz = vector[i] * scale[i];
+ const float pw = w[i] * scale[i];
+ const float4 position{pxyz[0], pxyz[1], pxyz[2], pw};
+ r_factor[i] = noise::musgrave_fBm(
+ position, dimension[i], lacunarity[i], detail[i]);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case SHD_MUSGRAVE_HETERO_TERRAIN: {
+ const VArray<float> &offset = get_offset(param++);
+ MutableSpan<float> r_factor = get_r_factor(param++);
+ const bool compute_factor = !r_factor.is_empty();
+ switch (dimensions_) {
+ case 1: {
+ const VArray<float> &w = get_w(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float position = w[i] * scale[i];
+ r_factor[i] = noise::musgrave_hetero_terrain(
+ position, dimension[i], lacunarity[i], detail[i], offset[i]);
+ }
+ }
+ break;
+ }
+ case 2: {
+ const VArray<float3> &vector = get_vector(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 pxyz = vector[i] * scale[i];
+ const float2 position = float2(pxyz[0], pxyz[1]);
+ r_factor[i] = noise::musgrave_hetero_terrain(
+ position, dimension[i], lacunarity[i], detail[i], offset[i]);
+ }
+ }
+ break;
+ }
+ case 3: {
+ const VArray<float3> &vector = get_vector(0);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 position = vector[i] * scale[i];
+ r_factor[i] = noise::musgrave_hetero_terrain(
+ position, dimension[i], lacunarity[i], detail[i], offset[i]);
+ }
+ }
+ break;
+ }
+ case 4: {
+ const VArray<float3> &vector = get_vector(0);
+ const VArray<float> &w = get_w(1);
+ if (compute_factor) {
+ for (int64_t i : mask) {
+ const float3 pxyz = vector[i] * scale[i];
+ const float pw = w[i] * scale[i];
+ const float4 position{pxyz[0], pxyz[1], pxyz[2], pw};
+ r_factor[i] = noise::musgrave_hetero_terrain(
+ position, dimension[i], lacunarity[i], detail[i], offset[i]);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+};
+
+static void sh_node_musgrave_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
{
+ bNode &node = builder.node();
+ NodeTexMusgrave *tex = (NodeTexMusgrave *)node.storage;
+ builder.construct_and_set_matching_fn<MusgraveFunction>(tex->dimensions, tex->musgrave_type);
+}
+
+} // namespace blender::nodes::node_shader_tex_musgrave_cc
+
+void register_node_type_sh_tex_musgrave()
+{
+ namespace file_ns = blender::nodes::node_shader_tex_musgrave_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_MUSGRAVE, "Musgrave Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_musgrave_declare;
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_MUSGRAVE, "Musgrave Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_musgrave_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_musgrave;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tex_musgrave);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_musgrave);
node_type_storage(
&ntype, "NodeTexMusgrave", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_musgrave);
- node_type_update(&ntype, node_shader_update_tex_musgrave);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_musgrave);
+ node_type_update(&ntype, file_ns::node_shader_update_tex_musgrave);
+ ntype.build_multi_function = file_ns::sh_node_musgrave_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
index 6ffc8979815..1c703313edf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
@@ -17,34 +17,45 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_noise.hh"
-namespace blender::nodes {
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_noise_cc {
+
+NODE_STORAGE_FUNCS(NodeTexNoise)
static void sh_node_tex_noise_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").implicit_field();
- b.add_input<decl::Float>("W").min(-1000.0f).max(1000.0f);
- b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f);
- b.add_input<decl::Float>("Detail").min(0.0f).max(16.0f).default_value(2.0f);
- b.add_input<decl::Float>("Roughness")
+ b.add_input<decl::Vector>(N_("Vector")).implicit_field();
+ b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f).make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is much faster. */
+ node_storage(node).dimensions = 1;
+ });
+ b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
+ b.add_input<decl::Float>(N_("Detail")).min(0.0f).max(15.0f).default_value(2.0f);
+ b.add_input<decl::Float>(N_("Roughness"))
.min(0.0f)
.max(1.0f)
.default_value(0.5f)
.subtype(PROP_FACTOR);
- b.add_input<decl::Float>("Distortion").min(-1000.0f).max(1000.0f).default_value(0.0f);
- b.add_output<decl::Float>("Fac").no_muted_links();
- b.add_output<decl::Color>("Color").no_muted_links();
-};
+ b.add_input<decl::Float>(N_("Distortion")).min(-1000.0f).max(1000.0f).default_value(0.0f);
+ b.add_output<decl::Float>(N_("Fac")).no_muted_links();
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+}
-} // namespace blender::nodes
+static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "noise_dimensions", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexNoise *tex = (NodeTexNoise *)MEM_callocN(sizeof(NodeTexNoise), "NodeTexNoise");
+ NodeTexNoise *tex = MEM_cnew<NodeTexNoise>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->dimensions = 3;
@@ -71,23 +82,21 @@ static int node_shader_gpu_tex_noise(GPUMaterial *mat,
node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
- NodeTexNoise *tex = (NodeTexNoise *)node->storage;
- const char *name = gpu_shader_get_name(tex->dimensions);
+ const NodeTexNoise &storage = node_storage(*node);
+ const char *name = gpu_shader_get_name(storage.dimensions);
return GPU_stack_link(mat, node, name, in, out);
}
-static void node_shader_update_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_shader_update_tex_noise(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector");
bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W");
- NodeTexNoise *tex = (NodeTexNoise *)node->storage;
- nodeSetSocketAvailability(sockVector, tex->dimensions != 1);
- nodeSetSocketAvailability(sockW, tex->dimensions == 1 || tex->dimensions == 4);
+ const NodeTexNoise &storage = node_storage(*node);
+ nodeSetSocketAvailability(ntree, sockVector, storage.dimensions != 1);
+ nodeSetSocketAvailability(ntree, sockW, storage.dimensions == 1 || storage.dimensions == 4);
}
-namespace blender::nodes {
-
class NoiseFunction : public fn::MultiFunction {
private:
int dimensions_;
@@ -167,14 +176,14 @@ class NoiseFunction : public fn::MultiFunction {
const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
if (compute_factor) {
for (int64_t i : mask) {
- const float2 position = vector[i] * scale[i];
+ const float2 position = float2(vector[i] * scale[i]);
r_factor[i] = noise::perlin_fractal_distorted(
position, detail[i], roughness[i], distortion[i]);
}
}
if (compute_color) {
for (int64_t i : mask) {
- const float2 position = vector[i] * scale[i];
+ const float2 position = float2(vector[i] * scale[i]);
const float3 c = noise::perlin_float3_fractal_distorted(
position, detail[i], roughness[i], distortion[i]);
r_color[i] = ColorGeometry4f(c[0], c[1], c[2], 1.0f);
@@ -229,30 +238,39 @@ class NoiseFunction : public fn::MultiFunction {
}
}
}
+
+ ExecutionHints get_execution_hints() const override
+ {
+ ExecutionHints hints;
+ hints.allocates_array = false;
+ hints.min_grain_size = 100;
+ return hints;
+ }
};
static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &node = builder.node();
- NodeTexNoise *tex = (NodeTexNoise *)node.storage;
- builder.construct_and_set_matching_fn<NoiseFunction>(tex->dimensions);
+ const NodeTexNoise &storage = node_storage(builder.node());
+ builder.construct_and_set_matching_fn<NoiseFunction>(storage.dimensions);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_noise_cc
-/* node type definition */
-void register_node_type_sh_tex_noise(void)
+void register_node_type_sh_tex_noise()
{
+ namespace file_ns = blender::nodes::node_shader_tex_noise_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_noise_declare;
- node_type_init(&ntype, node_shader_init_tex_noise);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_noise_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_noise;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_noise);
node_type_storage(
&ntype, "NodeTexNoise", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_noise);
- node_type_update(&ntype, node_shader_update_tex_noise);
- ntype.build_multi_function = blender::nodes::sh_node_noise_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_noise);
+ node_type_update(&ntype, file_ns::node_shader_update_tex_noise);
+ ntype.build_multi_function = file_ns::sh_node_noise_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
deleted file mode 100644
index 14cd1fd4c0c..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
+++ /dev/null
@@ -1,82 +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) 2015 Blender Foundation.
- * All rights reserved.
- */
-
-#include "../node_shader_util.h"
-
-#include "RE_texture.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_tex_pointdensity_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_tex_pointdensity_out[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Density"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
- {-1, ""},
-};
-
-static void node_shader_init_tex_pointdensity(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeShaderTexPointDensity *point_density = MEM_callocN(sizeof(NodeShaderTexPointDensity),
- "new pd node");
- point_density->resolution = 100;
- point_density->radius = 0.3f;
- point_density->space = SHD_POINTDENSITY_SPACE_OBJECT;
- point_density->color_source = SHD_POINTDENSITY_COLOR_PARTAGE;
- node->storage = point_density;
-}
-
-static void node_shader_free_tex_pointdensity(bNode *node)
-{
- NodeShaderTexPointDensity *point_density = node->storage;
- PointDensity *pd = &point_density->pd;
- RE_point_density_free(pd);
- BKE_texture_pointdensity_free_data(pd);
- memset(pd, 0, sizeof(*pd));
- MEM_freeN(point_density);
-}
-
-static void node_shader_copy_tex_pointdensity(bNodeTree *UNUSED(dest_ntree),
- bNode *dest_node,
- const bNode *src_node)
-{
- dest_node->storage = MEM_dupallocN(src_node->storage);
- NodeShaderTexPointDensity *point_density = dest_node->storage;
- PointDensity *pd = &point_density->pd;
- memset(pd, 0, sizeof(*pd));
-}
-
-/* node type definition */
-void register_node_type_sh_tex_pointdensity(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_TEX_POINTDENSITY, "Point Density", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_pointdensity_in, sh_node_tex_pointdensity_out);
- node_type_init(&ntype, node_shader_init_tex_pointdensity);
- node_type_storage(&ntype,
- "NodeShaderTexPointDensity",
- node_shader_free_tex_pointdensity,
- node_shader_copy_tex_pointdensity);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.cc b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.cc
new file mode 100644
index 00000000000..1a4cf70565f
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.cc
@@ -0,0 +1,131 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "node_shader_util.hh"
+
+#include "RE_texture.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_pointdensity_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector")).hide_value();
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Density"));
+}
+
+static void node_shader_buts_tex_pointdensity(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeShaderTexPointDensity *shader_point_density = (NodeShaderTexPointDensity *)node->storage;
+ Object *ob = (Object *)node->id;
+
+ PointerRNA ob_ptr, obdata_ptr;
+ RNA_id_pointer_create((ID *)ob, &ob_ptr);
+ RNA_id_pointer_create(ob ? (ID *)ob->data : nullptr, &obdata_ptr);
+
+ uiItemR(layout, ptr, "point_source", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "object", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (node->id && shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
+ PointerRNA dataptr;
+ RNA_id_pointer_create((ID *)node->id, &dataptr);
+ uiItemPointerR(
+ layout, ptr, "particle_system", &dataptr, "particle_systems", nullptr, ICON_NONE);
+ }
+
+ uiItemR(layout, ptr, "space", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "radius", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "resolution", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
+ uiItemR(layout, ptr, "particle_color_source", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ else {
+ uiItemR(layout, ptr, "vertex_color_source", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTWEIGHT) {
+ if (ob_ptr.data) {
+ uiItemPointerR(
+ layout, ptr, "vertex_attribute_name", &ob_ptr, "vertex_groups", "", ICON_NONE);
+ }
+ }
+ if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTCOL) {
+ if (obdata_ptr.data) {
+ uiItemPointerR(
+ layout, ptr, "vertex_attribute_name", &obdata_ptr, "vertex_colors", "", ICON_NONE);
+ }
+ }
+ }
+}
+
+static void node_shader_init_tex_pointdensity(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeShaderTexPointDensity *point_density = MEM_cnew<NodeShaderTexPointDensity>("new pd node");
+ point_density->resolution = 100;
+ point_density->radius = 0.3f;
+ point_density->space = SHD_POINTDENSITY_SPACE_OBJECT;
+ point_density->color_source = SHD_POINTDENSITY_COLOR_PARTAGE;
+ node->storage = point_density;
+}
+
+static void node_shader_free_tex_pointdensity(bNode *node)
+{
+ NodeShaderTexPointDensity *point_density = (NodeShaderTexPointDensity *)node->storage;
+ PointDensity *pd = &point_density->pd;
+ RE_point_density_free(pd);
+ BKE_texture_pointdensity_free_data(pd);
+ memset(pd, 0, sizeof(*pd));
+ MEM_freeN(point_density);
+}
+
+static void node_shader_copy_tex_pointdensity(bNodeTree *UNUSED(dest_ntree),
+ bNode *dest_node,
+ const bNode *src_node)
+{
+ dest_node->storage = MEM_dupallocN(src_node->storage);
+ NodeShaderTexPointDensity *point_density = (NodeShaderTexPointDensity *)dest_node->storage;
+ PointDensity *pd = &point_density->pd;
+ memset(pd, 0, sizeof(*pd));
+}
+
+} // namespace blender::nodes::node_shader_tex_pointdensity_cc
+
+/* node type definition */
+void register_node_type_sh_tex_pointdensity()
+{
+ namespace file_ns = blender::nodes::node_shader_tex_pointdensity_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_TEX_POINTDENSITY, "Point Density", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_pointdensity;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_pointdensity);
+ node_type_storage(&ntype,
+ "NodeShaderTexPointDensity",
+ file_ns::node_shader_free_tex_pointdensity,
+ file_ns::node_shader_copy_tex_pointdensity);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
index 5dc11c4df00..b8728d69bba 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
@@ -17,24 +17,66 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "sky_model.h"
-/* **************** OUTPUT ******************** */
+#include "BKE_context.h"
+#include "BKE_scene.h"
-static bNodeSocketTemplate sh_node_tex_sky_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_tex_sky_out[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_tex_sky_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector")).hide_value();
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+}
+
+static void node_shader_buts_tex_sky(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "sky_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_PREETHAM) {
+ uiItemR(layout, ptr, "sun_direction", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "turbidity", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_HOSEK) {
+ uiItemR(layout, ptr, "sun_direction", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "turbidity", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "ground_albedo", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NISHITA) {
+ Scene *scene = CTX_data_scene(C);
+ if (BKE_scene_uses_blender_eevee(scene)) {
+ uiItemL(layout, TIP_("Nishita not available in Eevee"), ICON_ERROR);
+ }
+ uiItemR(layout, ptr, "sun_disc", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+
+ uiLayout *col;
+ if (RNA_boolean_get(ptr, "sun_disc")) {
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "sun_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "sun_intensity", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "sun_elevation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "sun_rotation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "altitude", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "air_density", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "dust_density", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "ozone_density", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexSky *tex = MEM_callocN(sizeof(NodeTexSky), "NodeTexSky");
+ NodeTexSky *tex = MEM_cnew<NodeTexSky>("NodeTexSky");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->sun_direction[0] = 0.0f;
@@ -55,10 +97,10 @@ static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = tex;
}
-typedef struct SkyModelPreetham {
+struct SkyModelPreetham {
float config_Y[5], config_x[5], config_y[5]; /* named after xyY color space */
float radiance[3];
-} SkyModelPreetham;
+};
static float sky_perez_function(const float *lam, float theta, float gamma)
{
@@ -195,27 +237,32 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_tex_sky_nishita", in, out);
}
-static void node_shader_update_sky(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_shader_update_sky(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector");
NodeTexSky *tex = (NodeTexSky *)node->storage;
- nodeSetSocketAvailability(sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1));
+ nodeSetSocketAvailability(ntree, sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1));
}
+} // namespace blender::nodes::node_shader_tex_sky_cc
+
/* node type definition */
-void register_node_type_sh_tex_sky(void)
+void register_node_type_sh_tex_sky()
{
+ namespace file_ns = blender::nodes::node_shader_tex_sky_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_SKY, "Sky Texture", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_sky_in, sh_node_tex_sky_out);
+ sh_node_type_base(&ntype, SH_NODE_TEX_SKY, "Sky Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_sky;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tex_sky);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_sky);
node_type_storage(&ntype, "NodeTexSky", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_sky);
- /* remove Vector input for Nishita */
- node_type_update(&ntype, node_shader_update_sky);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_sky);
+ /* Remove vector input for Nishita sky model. */
+ node_type_update(&ntype, file_ns::node_shader_update_sky);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
index e12e5724e8e..209f96449cd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
@@ -17,39 +17,68 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+#include "BLI_noise.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_voronoi_cc {
+
+NODE_STORAGE_FUNCS(NodeTexVoronoi)
static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").hide_value();
- b.add_input<decl::Float>("W").min(-1000.0f).max(1000.0f);
- b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f);
- b.add_input<decl::Float>("Smoothness")
+ b.add_input<decl::Vector>(N_("Vector")).hide_value().implicit_field();
+ b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f).make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is much faster. */
+ node_storage(node).dimensions = 1;
+ });
+ b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
+ b.add_input<decl::Float>(N_("Smoothness"))
.min(0.0f)
.max(1.0f)
.default_value(1.0f)
- .subtype(PROP_FACTOR);
- b.add_input<decl::Float>("Exponent").min(0.0f).max(32.0f).default_value(0.5f);
- b.add_input<decl::Float>("Randomness")
+ .subtype(PROP_FACTOR)
+ .make_available([](bNode &node) { node_storage(node).feature = SHD_VORONOI_SMOOTH_F1; });
+ b.add_input<decl::Float>(N_("Exponent"))
+ .min(0.0f)
+ .max(32.0f)
+ .default_value(0.5f)
+ .make_available([](bNode &node) { node_storage(node).distance = SHD_VORONOI_MINKOWSKI; });
+ b.add_input<decl::Float>(N_("Randomness"))
.min(0.0f)
.max(1.0f)
.default_value(1.0f)
.subtype(PROP_FACTOR);
- b.add_output<decl::Float>("Distance").no_muted_links();
- b.add_output<decl::Color>("Color").no_muted_links();
- b.add_output<decl::Vector>("Position").no_muted_links();
- b.add_output<decl::Float>("W").no_muted_links();
- b.add_output<decl::Float>("Radius").no_muted_links();
-};
+ b.add_output<decl::Float>(N_("Distance")).no_muted_links();
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+ b.add_output<decl::Vector>(N_("Position")).no_muted_links();
+ b.add_output<decl::Float>(N_("W")).no_muted_links().make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is much faster. */
+ node_storage(node).dimensions = 1;
+ });
+ b.add_output<decl::Float>(N_("Radius")).no_muted_links().make_available([](bNode &node) {
+ node_storage(node).feature = SHD_VORONOI_N_SPHERE_RADIUS;
+ });
+}
-} // namespace blender::nodes
+static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "voronoi_dimensions", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "feature", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ int feature = RNA_enum_get(ptr, "feature");
+ if (!ELEM(feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS) &&
+ RNA_enum_get(ptr, "voronoi_dimensions") != 1) {
+ uiItemR(layout, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ }
+}
static void node_shader_init_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexVoronoi *tex = (NodeTexVoronoi *)MEM_callocN(sizeof(NodeTexVoronoi), "NodeTexVoronoi");
+ NodeTexVoronoi *tex = MEM_cnew<NodeTexVoronoi>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->dimensions = 3;
@@ -121,7 +150,7 @@ static int node_shader_gpu_tex_voronoi(GPUMaterial *mat,
return GPU_stack_link(mat, node, name, in, out, GPU_constant(&metric));
}
-static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_shader_update_tex_voronoi(bNodeTree *ntree, bNode *node)
{
bNodeSocket *inVectorSock = nodeFindSocket(node, SOCK_IN, "Vector");
bNodeSocket *inWSock = nodeFindSocket(node, SOCK_IN, "W");
@@ -134,41 +163,1210 @@ static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node
bNodeSocket *outWSock = nodeFindSocket(node, SOCK_OUT, "W");
bNodeSocket *outRadiusSock = nodeFindSocket(node, SOCK_OUT, "Radius");
- NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ const NodeTexVoronoi &storage = node_storage(*node);
- nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4);
- nodeSetSocketAvailability(inVectorSock, tex->dimensions != 1);
+ nodeSetSocketAvailability(ntree, inWSock, storage.dimensions == 1 || storage.dimensions == 4);
+ nodeSetSocketAvailability(ntree, inVectorSock, storage.dimensions != 1);
nodeSetSocketAvailability(
+ ntree,
inExponentSock,
- tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 &&
- !ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
- nodeSetSocketAvailability(inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1);
- nodeSetSocketAvailability(outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS);
- nodeSetSocketAvailability(outColorSock,
- tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
- tex->feature != SHD_VORONOI_N_SPHERE_RADIUS);
- nodeSetSocketAvailability(outPositionSock,
- tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
- tex->feature != SHD_VORONOI_N_SPHERE_RADIUS &&
- tex->dimensions != 1);
- nodeSetSocketAvailability(outWSock,
- tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
- tex->feature != SHD_VORONOI_N_SPHERE_RADIUS &&
- (tex->dimensions == 1 || tex->dimensions == 4));
- nodeSetSocketAvailability(outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS);
+ storage.distance == SHD_VORONOI_MINKOWSKI && storage.dimensions != 1 &&
+ !ELEM(storage.feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
+ nodeSetSocketAvailability(ntree, inSmoothnessSock, storage.feature == SHD_VORONOI_SMOOTH_F1);
+
+ nodeSetSocketAvailability(
+ ntree, outDistanceSock, storage.feature != SHD_VORONOI_N_SPHERE_RADIUS);
+ nodeSetSocketAvailability(ntree,
+ outColorSock,
+ storage.feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ storage.feature != SHD_VORONOI_N_SPHERE_RADIUS);
+ nodeSetSocketAvailability(ntree,
+ outPositionSock,
+ storage.feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ storage.feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ storage.dimensions != 1);
+ nodeSetSocketAvailability(ntree,
+ outWSock,
+ storage.feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ storage.feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ (ELEM(storage.dimensions, 1, 4)));
+ nodeSetSocketAvailability(ntree, outRadiusSock, storage.feature == SHD_VORONOI_N_SPHERE_RADIUS);
+}
+
+static MultiFunction::ExecutionHints voronoi_execution_hints{50, false};
+
+class VoronoiMinowskiFunction : public fn::MultiFunction {
+ private:
+ int dimensions_;
+ int feature_;
+
+ public:
+ VoronoiMinowskiFunction(int dimensions, int feature) : dimensions_(dimensions), feature_(feature)
+ {
+ BLI_assert(dimensions >= 2 && dimensions <= 4);
+ BLI_assert(feature >= 0 && feature <= 2);
+ static std::array<fn::MFSignature, 9> signatures{
+ create_signature(2, SHD_VORONOI_F1),
+ create_signature(3, SHD_VORONOI_F1),
+ create_signature(4, SHD_VORONOI_F1),
+
+ create_signature(2, SHD_VORONOI_F2),
+ create_signature(3, SHD_VORONOI_F2),
+ create_signature(4, SHD_VORONOI_F2),
+
+ create_signature(2, SHD_VORONOI_SMOOTH_F1),
+ create_signature(3, SHD_VORONOI_SMOOTH_F1),
+ create_signature(4, SHD_VORONOI_SMOOTH_F1),
+ };
+ this->set_signature(&signatures[(dimensions - 1) + feature * 3 - 1]);
+ }
+
+ static fn::MFSignature create_signature(int dimensions, int feature)
+ {
+ fn::MFSignatureBuilder signature{"voronoi_minowski"};
+
+ if (ELEM(dimensions, 2, 3, 4)) {
+ signature.single_input<float3>("Vector");
+ }
+ if (ELEM(dimensions, 1, 4)) {
+ signature.single_input<float>("W");
+ }
+ signature.single_input<float>("Scale");
+ if (feature == SHD_VORONOI_SMOOTH_F1) {
+ signature.single_input<float>("Smoothness");
+ }
+ signature.single_input<float>("Exponent");
+ signature.single_input<float>("Randomness");
+ signature.single_output<float>("Distance");
+ signature.single_output<ColorGeometry4f>("Color");
+
+ if (dimensions != 1) {
+ signature.single_output<float3>("Position");
+ }
+ if (ELEM(dimensions, 1, 4)) {
+ signature.single_output<float>("W");
+ }
+
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ auto get_vector = [&](int param_index) -> VArray<float3> {
+ return params.readonly_single_input<float3>(param_index, "Vector");
+ };
+ auto get_w = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "W");
+ };
+ auto get_scale = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Scale");
+ };
+ auto get_smoothness = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Smoothness");
+ };
+ auto get_exponent = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Exponent");
+ };
+ auto get_randomness = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Randomness");
+ };
+ auto get_r_distance = [&](int param_index) -> MutableSpan<float> {
+ return params.uninitialized_single_output_if_required<float>(param_index, "Distance");
+ };
+ auto get_r_color = [&](int param_index) -> MutableSpan<ColorGeometry4f> {
+ return params.uninitialized_single_output_if_required<ColorGeometry4f>(param_index, "Color");
+ };
+ auto get_r_position = [&](int param_index) -> MutableSpan<float3> {
+ return params.uninitialized_single_output_if_required<float3>(param_index, "Position");
+ };
+ auto get_r_w = [&](int param_index) -> MutableSpan<float> {
+ return params.uninitialized_single_output_if_required<float>(param_index, "W");
+ };
+
+ int param = 0;
+ switch (dimensions_) {
+ case 2: {
+ switch (feature_) {
+ case SHD_VORONOI_F1: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &exponent = get_exponent(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ float2 pos;
+ noise::voronoi_f1(float2(vector[i].x, vector[i].y) * scale[i],
+ exponent[i],
+ rand,
+ SHD_VORONOI_MINKOWSKI,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ pos = math::safe_divide(pos, scale[i]);
+ r_position[i] = float3(pos.x, pos.y, 0.0f);
+ }
+ }
+ break;
+ }
+ case SHD_VORONOI_F2: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &exponent = get_exponent(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ float2 pos;
+ noise::voronoi_f2(float2(vector[i].x, vector[i].y) * scale[i],
+ exponent[i],
+ rand,
+ SHD_VORONOI_MINKOWSKI,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ pos = math::safe_divide(pos, scale[i]);
+ r_position[i] = float3(pos.x, pos.y, 0.0f);
+ }
+ }
+ break;
+ }
+ case SHD_VORONOI_SMOOTH_F1: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &smoothness = get_smoothness(param++);
+ const VArray<float> &exponent = get_exponent(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ for (int64_t i : mask) {
+ const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ float2 pos;
+ noise::voronoi_smooth_f1(float2(vector[i].x, vector[i].y) * scale[i],
+ smth,
+ exponent[i],
+ rand,
+ SHD_VORONOI_MINKOWSKI,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ pos = math::safe_divide(pos, scale[i]);
+ r_position[i] = float3(pos.x, pos.y, 0.0f);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 3: {
+ switch (feature_) {
+ case SHD_VORONOI_F1: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &exponent = get_exponent(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ noise::voronoi_f1(vector[i] * scale[i],
+ exponent[i],
+ rand,
+ SHD_VORONOI_MINKOWSKI,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &r_position[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ r_position[i] = math::safe_divide(r_position[i], scale[i]);
+ }
+ }
+ break;
+ }
+ case SHD_VORONOI_F2: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &exponent = get_exponent(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ noise::voronoi_f2(vector[i] * scale[i],
+ exponent[i],
+ rand,
+ SHD_VORONOI_MINKOWSKI,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &r_position[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ r_position[i] = math::safe_divide(r_position[i], scale[i]);
+ }
+ }
+ break;
+ }
+ case SHD_VORONOI_SMOOTH_F1: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &smoothness = get_smoothness(param++);
+ const VArray<float> &exponent = get_exponent(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ for (int64_t i : mask) {
+ const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ noise::voronoi_smooth_f1(vector[i] * scale[i],
+ smth,
+ exponent[i],
+ rand,
+ SHD_VORONOI_MINKOWSKI,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &r_position[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ r_position[i] = math::safe_divide(r_position[i], scale[i]);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 4: {
+ switch (feature_) {
+ case SHD_VORONOI_F1: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &w = get_w(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &exponent = get_exponent(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ const bool calc_w = !r_w.is_empty();
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
+ float3 col;
+ float4 pos;
+ noise::voronoi_f1(p,
+ exponent[i],
+ rand,
+ SHD_VORONOI_F1,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position || calc_w ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position || calc_w) {
+ pos = math::safe_divide(pos, scale[i]);
+ if (calc_position) {
+ r_position[i] = float3(pos.x, pos.y, pos.z);
+ }
+ if (calc_w) {
+ r_w[i] = pos.w;
+ }
+ }
+ }
+ break;
+ }
+ case SHD_VORONOI_F2: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &w = get_w(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &exponent = get_exponent(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ const bool calc_w = !r_w.is_empty();
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
+ float3 col;
+ float4 pos;
+ noise::voronoi_f2(p,
+ exponent[i],
+ rand,
+ SHD_VORONOI_MINKOWSKI,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position || calc_w ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position || calc_w) {
+ pos = math::safe_divide(pos, scale[i]);
+ if (calc_position) {
+ r_position[i] = float3(pos.x, pos.y, pos.z);
+ }
+ if (calc_w) {
+ r_w[i] = pos.w;
+ }
+ }
+ }
+ break;
+ }
+ case SHD_VORONOI_SMOOTH_F1: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &w = get_w(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &smoothness = get_smoothness(param++);
+ const VArray<float> &exponent = get_exponent(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ const bool calc_w = !r_w.is_empty();
+ for (int64_t i : mask) {
+ const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
+ float3 col;
+ float4 pos;
+ noise::voronoi_smooth_f1(p,
+ smth,
+ exponent[i],
+ rand,
+ SHD_VORONOI_MINKOWSKI,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position || calc_w ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position || calc_w) {
+ pos = math::safe_divide(pos, scale[i]);
+ if (calc_position) {
+ r_position[i] = float3(pos.x, pos.y, pos.z);
+ }
+ if (calc_w) {
+ r_w[i] = pos.w;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ ExecutionHints get_execution_hints() const override
+ {
+ return voronoi_execution_hints;
+ }
+};
+
+class VoronoiMetricFunction : public fn::MultiFunction {
+ private:
+ int dimensions_;
+ int feature_;
+ int metric_;
+
+ public:
+ VoronoiMetricFunction(int dimensions, int feature, int metric)
+ : dimensions_(dimensions), feature_(feature), metric_(metric)
+ {
+ BLI_assert(dimensions >= 1 && dimensions <= 4);
+ BLI_assert(feature >= 0 && feature <= 4);
+ static std::array<fn::MFSignature, 12> signatures{
+ create_signature(1, SHD_VORONOI_F1),
+ create_signature(2, SHD_VORONOI_F1),
+ create_signature(3, SHD_VORONOI_F1),
+ create_signature(4, SHD_VORONOI_F1),
+
+ create_signature(1, SHD_VORONOI_F2),
+ create_signature(2, SHD_VORONOI_F2),
+ create_signature(3, SHD_VORONOI_F2),
+ create_signature(4, SHD_VORONOI_F2),
+
+ create_signature(1, SHD_VORONOI_SMOOTH_F1),
+ create_signature(2, SHD_VORONOI_SMOOTH_F1),
+ create_signature(3, SHD_VORONOI_SMOOTH_F1),
+ create_signature(4, SHD_VORONOI_SMOOTH_F1),
+ };
+ this->set_signature(&signatures[dimensions + feature * 4 - 1]);
+ }
+
+ static fn::MFSignature create_signature(int dimensions, int feature)
+ {
+ fn::MFSignatureBuilder signature{"voronoi_metric"};
+
+ if (ELEM(dimensions, 2, 3, 4)) {
+ signature.single_input<float3>("Vector");
+ }
+ if (ELEM(dimensions, 1, 4)) {
+ signature.single_input<float>("W");
+ }
+ signature.single_input<float>("Scale");
+ if (feature == SHD_VORONOI_SMOOTH_F1) {
+ signature.single_input<float>("Smoothness");
+ }
+ signature.single_input<float>("Randomness");
+ signature.single_output<float>("Distance");
+ signature.single_output<ColorGeometry4f>("Color");
+
+ if (dimensions != 1) {
+ signature.single_output<float3>("Position");
+ }
+ if (ELEM(dimensions, 1, 4)) {
+ signature.single_output<float>("W");
+ }
+
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ auto get_vector = [&](int param_index) -> VArray<float3> {
+ return params.readonly_single_input<float3>(param_index, "Vector");
+ };
+ auto get_w = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "W");
+ };
+ auto get_scale = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Scale");
+ };
+ auto get_smoothness = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Smoothness");
+ };
+ auto get_randomness = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Randomness");
+ };
+ auto get_r_distance = [&](int param_index) -> MutableSpan<float> {
+ return params.uninitialized_single_output_if_required<float>(param_index, "Distance");
+ };
+ auto get_r_color = [&](int param_index) -> MutableSpan<ColorGeometry4f> {
+ return params.uninitialized_single_output_if_required<ColorGeometry4f>(param_index, "Color");
+ };
+ auto get_r_position = [&](int param_index) -> MutableSpan<float3> {
+ return params.uninitialized_single_output_if_required<float3>(param_index, "Position");
+ };
+ auto get_r_w = [&](int param_index) -> MutableSpan<float> {
+ return params.uninitialized_single_output_if_required<float>(param_index, "W");
+ };
+
+ int param = 0;
+ switch (dimensions_) {
+ case 1: {
+ switch (feature_) {
+ case SHD_VORONOI_F1: {
+ const VArray<float> &w = get_w(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_w = !r_w.is_empty();
+ for (int64_t i : mask) {
+ const float p = w[i] * scale[i];
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ noise::voronoi_f1(p,
+ rand,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_w ? &r_w[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_w) {
+ r_w[i] = safe_divide(r_w[i], scale[i]);
+ }
+ }
+ break;
+ }
+ case SHD_VORONOI_F2: {
+ const VArray<float> &w = get_w(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_w = !r_w.is_empty();
+ for (int64_t i : mask) {
+ const float p = w[i] * scale[i];
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ noise::voronoi_f2(p,
+ rand,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_w ? &r_w[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_w) {
+ r_w[i] = safe_divide(r_w[i], scale[i]);
+ }
+ }
+ break;
+ }
+ case SHD_VORONOI_SMOOTH_F1: {
+ const VArray<float> &w = get_w(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &smoothness = get_smoothness(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_w = !r_w.is_empty();
+ for (int64_t i : mask) {
+ const float p = w[i] * scale[i];
+ const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ noise::voronoi_smooth_f1(p,
+ smth,
+ rand,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_w ? &r_w[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_w) {
+ r_w[i] = safe_divide(r_w[i], scale[i]);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 2: {
+ switch (feature_) {
+ case SHD_VORONOI_F1: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ float2 pos;
+ noise::voronoi_f1(float2(vector[i].x, vector[i].y) * scale[i],
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ pos = math::safe_divide(pos, scale[i]);
+ r_position[i] = float3(pos.x, pos.y, 0.0f);
+ }
+ }
+ break;
+ }
+ case SHD_VORONOI_F2: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ float2 pos;
+ noise::voronoi_f2(float2(vector[i].x, vector[i].y) * scale[i],
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ pos = math::safe_divide(pos, scale[i]);
+ r_position[i] = float3(pos.x, pos.y, 0.0f);
+ }
+ }
+ break;
+ }
+ case SHD_VORONOI_SMOOTH_F1: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &smoothness = get_smoothness(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ for (int64_t i : mask) {
+ const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ float2 pos;
+ noise::voronoi_smooth_f1(float2(vector[i].x, vector[i].y) * scale[i],
+ smth,
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ pos = math::safe_divide(pos, scale[i]);
+ r_position[i] = float3(pos.x, pos.y, 0.0f);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 3: {
+ switch (feature_) {
+ case SHD_VORONOI_F1: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ noise::voronoi_f1(vector[i] * scale[i],
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &r_position[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ r_position[i] = math::safe_divide(r_position[i], scale[i]);
+ }
+ }
+ break;
+ }
+ case SHD_VORONOI_F2: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ noise::voronoi_f2(vector[i] * scale[i],
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &r_position[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ r_position[i] = math::safe_divide(r_position[i], scale[i]);
+ }
+ }
+ break;
+ }
+ case SHD_VORONOI_SMOOTH_F1: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &smoothness = get_smoothness(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ {
+ for (int64_t i : mask) {
+ const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ float3 col;
+ noise::voronoi_smooth_f1(vector[i] * scale[i],
+ smth,
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position ? &r_position[i] : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position) {
+ r_position[i] = math::safe_divide(r_position[i], scale[i]);
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ break;
+ }
+ case 4: {
+ switch (feature_) {
+ case SHD_VORONOI_F1: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &w = get_w(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ const bool calc_w = !r_w.is_empty();
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
+ float3 col;
+ float4 pos;
+ noise::voronoi_f1(p,
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position || calc_w ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position || calc_w) {
+ pos = math::safe_divide(pos, scale[i]);
+ if (calc_position) {
+ r_position[i] = float3(pos.x, pos.y, pos.z);
+ }
+ if (calc_w) {
+ r_w[i] = pos.w;
+ }
+ }
+ }
+ break;
+ }
+ case SHD_VORONOI_F2: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &w = get_w(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ const bool calc_w = !r_w.is_empty();
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
+ float3 col;
+ float4 pos;
+ noise::voronoi_f2(p,
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position || calc_w ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position || calc_w) {
+ pos = math::safe_divide(pos, scale[i]);
+ if (calc_position) {
+ r_position[i] = float3(pos.x, pos.y, pos.z);
+ }
+ if (calc_w) {
+ r_w[i] = pos.w;
+ }
+ }
+ }
+ break;
+ }
+ case SHD_VORONOI_SMOOTH_F1: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &w = get_w(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &smoothness = get_smoothness(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
+ MutableSpan<float3> r_position = get_r_position(param++);
+ MutableSpan<float> r_w = get_r_w(param++);
+ const bool calc_distance = !r_distance.is_empty();
+ const bool calc_color = !r_color.is_empty();
+ const bool calc_position = !r_position.is_empty();
+ const bool calc_w = !r_w.is_empty();
+ for (int64_t i : mask) {
+ const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
+ float3 col;
+ float4 pos;
+ noise::voronoi_smooth_f1(p,
+ smth,
+ 0.0f,
+ rand,
+ metric_,
+ calc_distance ? &r_distance[i] : nullptr,
+ calc_color ? &col : nullptr,
+ calc_position || calc_w ? &pos : nullptr);
+ if (calc_color) {
+ r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
+ }
+ if (calc_position || calc_w) {
+ pos = math::safe_divide(pos, scale[i]);
+ if (calc_position) {
+ r_position[i] = float3(pos.x, pos.y, pos.z);
+ }
+ if (calc_w) {
+ r_w[i] = pos.w;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ ExecutionHints get_execution_hints() const override
+ {
+ return voronoi_execution_hints;
+ }
+};
+
+class VoronoiEdgeFunction : public fn::MultiFunction {
+ private:
+ int dimensions_;
+ int feature_;
+
+ public:
+ VoronoiEdgeFunction(int dimensions, int feature) : dimensions_(dimensions), feature_(feature)
+ {
+ BLI_assert(dimensions >= 1 && dimensions <= 4);
+ BLI_assert(feature >= 3 && feature <= 4);
+ static std::array<fn::MFSignature, 8> signatures{
+ create_signature(1, SHD_VORONOI_DISTANCE_TO_EDGE),
+ create_signature(2, SHD_VORONOI_DISTANCE_TO_EDGE),
+ create_signature(3, SHD_VORONOI_DISTANCE_TO_EDGE),
+ create_signature(4, SHD_VORONOI_DISTANCE_TO_EDGE),
+
+ create_signature(1, SHD_VORONOI_N_SPHERE_RADIUS),
+ create_signature(2, SHD_VORONOI_N_SPHERE_RADIUS),
+ create_signature(3, SHD_VORONOI_N_SPHERE_RADIUS),
+ create_signature(4, SHD_VORONOI_N_SPHERE_RADIUS),
+ };
+ this->set_signature(&signatures[dimensions + (feature - 3) * 4 - 1]);
+ }
+
+ static fn::MFSignature create_signature(int dimensions, int feature)
+ {
+ fn::MFSignatureBuilder signature{"voronoi_edge"};
+
+ if (ELEM(dimensions, 2, 3, 4)) {
+ signature.single_input<float3>("Vector");
+ }
+ if (ELEM(dimensions, 1, 4)) {
+ signature.single_input<float>("W");
+ }
+ signature.single_input<float>("Scale");
+ signature.single_input<float>("Randomness");
+
+ if (feature == SHD_VORONOI_DISTANCE_TO_EDGE) {
+ signature.single_output<float>("Distance");
+ }
+ if (feature == SHD_VORONOI_N_SPHERE_RADIUS) {
+ signature.single_output<float>("Radius");
+ }
+
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ auto get_vector = [&](int param_index) -> VArray<float3> {
+ return params.readonly_single_input<float3>(param_index, "Vector");
+ };
+ auto get_w = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "W");
+ };
+ auto get_scale = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Scale");
+ };
+ auto get_randomness = [&](int param_index) -> VArray<float> {
+ return params.readonly_single_input<float>(param_index, "Randomness");
+ };
+ auto get_r_distance = [&](int param_index) -> MutableSpan<float> {
+ return params.uninitialized_single_output<float>(param_index, "Distance");
+ };
+ auto get_r_radius = [&](int param_index) -> MutableSpan<float> {
+ return params.uninitialized_single_output<float>(param_index, "Radius");
+ };
+
+ int param = 0;
+ switch (dimensions_) {
+ case 1: {
+ const VArray<float> &w = get_w(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ switch (feature_) {
+ case SHD_VORONOI_DISTANCE_TO_EDGE: {
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ const float p = w[i] * scale[i];
+ noise::voronoi_distance_to_edge(p, rand, &r_distance[i]);
+ }
+ break;
+ }
+ case SHD_VORONOI_N_SPHERE_RADIUS: {
+ MutableSpan<float> r_radius = get_r_radius(param++);
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ const float p = w[i] * scale[i];
+ noise::voronoi_n_sphere_radius(p, rand, &r_radius[i]);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 2: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ switch (feature_) {
+ case SHD_VORONOI_DISTANCE_TO_EDGE: {
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ const float2 p = float2(vector[i].x, vector[i].y) * scale[i];
+ noise::voronoi_distance_to_edge(p, rand, &r_distance[i]);
+ }
+ break;
+ }
+ case SHD_VORONOI_N_SPHERE_RADIUS: {
+ MutableSpan<float> r_radius = get_r_radius(param++);
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ const float2 p = float2(vector[i].x, vector[i].y) * scale[i];
+ noise::voronoi_n_sphere_radius(p, rand, &r_radius[i]);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 3: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ switch (feature_) {
+ case SHD_VORONOI_DISTANCE_TO_EDGE: {
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ noise::voronoi_distance_to_edge(vector[i] * scale[i], rand, &r_distance[i]);
+ }
+ break;
+ }
+ case SHD_VORONOI_N_SPHERE_RADIUS: {
+ MutableSpan<float> r_radius = get_r_radius(param++);
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ noise::voronoi_n_sphere_radius(vector[i] * scale[i], rand, &r_radius[i]);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 4: {
+ const VArray<float3> &vector = get_vector(param++);
+ const VArray<float> &w = get_w(param++);
+ const VArray<float> &scale = get_scale(param++);
+ const VArray<float> &randomness = get_randomness(param++);
+ switch (feature_) {
+ case SHD_VORONOI_DISTANCE_TO_EDGE: {
+ MutableSpan<float> r_distance = get_r_distance(param++);
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
+ noise::voronoi_distance_to_edge(p, rand, &r_distance[i]);
+ }
+ break;
+ }
+ case SHD_VORONOI_N_SPHERE_RADIUS: {
+ MutableSpan<float> r_radius = get_r_radius(param++);
+ for (int64_t i : mask) {
+ const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
+ const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
+ noise::voronoi_n_sphere_radius(p, rand, &r_radius[i]);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ ExecutionHints get_execution_hints() const override
+ {
+ return voronoi_execution_hints;
+ }
+};
+
+static void sh_node_voronoi_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+{
+ const NodeTexVoronoi &storage = node_storage(builder.node());
+ bool minowski =
+ (storage.distance == SHD_VORONOI_MINKOWSKI && storage.dimensions != 1 &&
+ !ELEM(storage.feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
+ bool dist_radius = ELEM(
+ storage.feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS);
+ if (dist_radius) {
+ builder.construct_and_set_matching_fn<VoronoiEdgeFunction>(storage.dimensions,
+ storage.feature);
+ }
+ else if (minowski) {
+ builder.construct_and_set_matching_fn<VoronoiMinowskiFunction>(storage.dimensions,
+ storage.feature);
+ }
+ else {
+ builder.construct_and_set_matching_fn<VoronoiMetricFunction>(
+ storage.dimensions, storage.feature, storage.distance);
+ }
}
-void register_node_type_sh_tex_voronoi(void)
+} // namespace blender::nodes::node_shader_tex_voronoi_cc
+
+void register_node_type_sh_tex_voronoi()
{
+ namespace file_ns = blender::nodes::node_shader_tex_voronoi_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_VORONOI, "Voronoi Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_voronoi_declare;
- node_type_init(&ntype, node_shader_init_tex_voronoi);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_VORONOI, "Voronoi Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_voronoi_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_voronoi;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_voronoi);
node_type_storage(
&ntype, "NodeTexVoronoi", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_voronoi);
- node_type_update(&ntype, node_shader_update_tex_voronoi);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_voronoi);
+ node_type_update(&ntype, file_ns::node_shader_update_tex_voronoi);
+ ntype.build_multi_function = file_ns::sh_node_voronoi_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
deleted file mode 100644
index bba568ed5b7..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** WAVE ******************** */
-
-static bNodeSocketTemplate sh_node_tex_wave_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
- {SOCK_FLOAT, N_("Distortion"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
- {SOCK_FLOAT, N_("Detail"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 16.0f},
- {SOCK_FLOAT, N_("Detail Scale"), 1.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
- {SOCK_FLOAT, N_("Detail Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Phase Offset"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_tex_wave_out[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
- {SOCK_FLOAT,
- N_("Fac"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_FACTOR,
- SOCK_NO_INTERNAL_LINK},
- {-1, ""},
-};
-
-static void node_shader_init_tex_wave(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeTexWave *tex = MEM_callocN(sizeof(NodeTexWave), "NodeTexWave");
- BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- BKE_texture_colormapping_default(&tex->base.color_mapping);
- tex->wave_type = SHD_WAVE_BANDS;
- tex->bands_direction = SHD_WAVE_BANDS_DIRECTION_X;
- tex->rings_direction = SHD_WAVE_RINGS_DIRECTION_X;
- tex->wave_profile = SHD_WAVE_PROFILE_SIN;
- node->storage = tex;
-}
-
-static int node_shader_gpu_tex_wave(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
- node_shader_gpu_tex_mapping(mat, node, in, out);
-
- NodeTexWave *tex = (NodeTexWave *)node->storage;
- float wave_type = tex->wave_type;
- float bands_direction = tex->bands_direction;
- float rings_direction = tex->rings_direction;
- float wave_profile = tex->wave_profile;
-
- return GPU_stack_link(mat,
- node,
- "node_tex_wave",
- in,
- out,
- GPU_constant(&wave_type),
- GPU_constant(&bands_direction),
- GPU_constant(&rings_direction),
- GPU_constant(&wave_profile));
-}
-
-/* node type definition */
-void register_node_type_sh_tex_wave(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_TEX_WAVE, "Wave Texture", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_wave_in, sh_node_tex_wave_out);
- node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tex_wave);
- node_type_storage(&ntype, "NodeTexWave", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_wave);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
new file mode 100644
index 00000000000..fc6c66061ff
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
@@ -0,0 +1,250 @@
+/*
+ * 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.
+ */
+
+#include "node_shader_util.hh"
+
+#include "BLI_noise.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_wave_cc {
+
+static void sh_node_tex_wave_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Vector>(N_("Vector")).implicit_field();
+ b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
+ b.add_input<decl::Float>(N_("Distortion")).min(-1000.0f).max(1000.0f).default_value(0.0f);
+ b.add_input<decl::Float>(N_("Detail")).min(0.0f).max(15.0f).default_value(2.0f);
+ b.add_input<decl::Float>(N_("Detail Scale")).min(-1000.0f).max(1000.0f).default_value(1.0f);
+ b.add_input<decl::Float>(N_("Detail Roughness"))
+ .min(0.0f)
+ .max(1.0f)
+ .default_value(0.5f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Phase Offset")).min(-1000.0f).max(1000.0f).default_value(0.0f);
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+ b.add_output<decl::Float>(N_("Fac")).no_muted_links();
+}
+
+static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "wave_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ int type = RNA_enum_get(ptr, "wave_type");
+ if (type == SHD_WAVE_BANDS) {
+ uiItemR(layout, ptr, "bands_direction", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ }
+ else { /* SHD_WAVE_RINGS */
+ uiItemR(layout, ptr, "rings_direction", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ }
+
+ uiItemR(layout, ptr, "wave_profile", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+static void node_shader_init_tex_wave(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeTexWave *tex = MEM_cnew<NodeTexWave>(__func__);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
+ tex->wave_type = SHD_WAVE_BANDS;
+ tex->bands_direction = SHD_WAVE_BANDS_DIRECTION_X;
+ tex->rings_direction = SHD_WAVE_RINGS_DIRECTION_X;
+ tex->wave_profile = SHD_WAVE_PROFILE_SIN;
+ node->storage = tex;
+}
+
+static int node_shader_gpu_tex_wave(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
+ node_shader_gpu_tex_mapping(mat, node, in, out);
+
+ NodeTexWave *tex = (NodeTexWave *)node->storage;
+ float wave_type = tex->wave_type;
+ float bands_direction = tex->bands_direction;
+ float rings_direction = tex->rings_direction;
+ float wave_profile = tex->wave_profile;
+
+ return GPU_stack_link(mat,
+ node,
+ "node_tex_wave",
+ in,
+ out,
+ GPU_constant(&wave_type),
+ GPU_constant(&bands_direction),
+ GPU_constant(&rings_direction),
+ GPU_constant(&wave_profile));
+}
+
+class WaveFunction : public fn::MultiFunction {
+ private:
+ int wave_type_;
+ int bands_direction_;
+ int rings_direction_;
+ int wave_profile_;
+
+ public:
+ WaveFunction(int wave_type, int bands_direction, int rings_direction, int wave_profile)
+ : wave_type_(wave_type),
+ bands_direction_(bands_direction),
+ rings_direction_(rings_direction),
+ wave_profile_(wave_profile)
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"MagicFunction"};
+ signature.single_input<float3>("Vector");
+ signature.single_input<float>("Scale");
+ signature.single_input<float>("Distortion");
+ signature.single_input<float>("Detail");
+ signature.single_input<float>("Detail Scale");
+ signature.single_input<float>("Detail Roughness");
+ signature.single_input<float>("Phase Offset");
+ signature.single_output<ColorGeometry4f>("Color");
+ signature.single_output<float>("Fac");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
+ const VArray<float> &scale = params.readonly_single_input<float>(1, "Scale");
+ const VArray<float> &distortion = params.readonly_single_input<float>(2, "Distortion");
+ const VArray<float> &detail = params.readonly_single_input<float>(3, "Detail");
+ const VArray<float> &dscale = params.readonly_single_input<float>(4, "Detail Scale");
+ const VArray<float> &droughness = params.readonly_single_input<float>(5, "Detail Roughness");
+ const VArray<float> &phase = params.readonly_single_input<float>(6, "Phase Offset");
+
+ MutableSpan<ColorGeometry4f> r_color =
+ params.uninitialized_single_output_if_required<ColorGeometry4f>(7, "Color");
+ MutableSpan<float> r_fac = params.uninitialized_single_output<float>(8, "Fac");
+
+ for (int64_t i : mask) {
+
+ float3 p = vector[i] * scale[i];
+ /* Prevent precision issues on unit coordinates. */
+ p = (p + 0.000001f) * 0.999999f;
+
+ float n = 0.0f;
+ float val = 0.0f;
+
+ switch (wave_type_) {
+ case SHD_WAVE_BANDS:
+ switch (bands_direction_) {
+ case SHD_WAVE_BANDS_DIRECTION_X:
+ n = p.x * 20.0f;
+ break;
+ case SHD_WAVE_BANDS_DIRECTION_Y:
+ n = p.y * 20.0f;
+ break;
+ case SHD_WAVE_BANDS_DIRECTION_Z:
+ n = p.z * 20.0f;
+ break;
+ case SHD_WAVE_BANDS_DIRECTION_DIAGONAL:
+ n = (p.x + p.y + p.z) * 10.0f;
+ break;
+ }
+ break;
+ case SHD_WAVE_RINGS:
+ float3 rp = p;
+ switch (rings_direction_) {
+ case SHD_WAVE_RINGS_DIRECTION_X:
+ rp *= float3(0.0f, 1.0f, 1.0f);
+ break;
+ case SHD_WAVE_RINGS_DIRECTION_Y:
+ rp *= float3(1.0f, 0.0f, 1.0f);
+ break;
+ case SHD_WAVE_RINGS_DIRECTION_Z:
+ rp *= float3(1.0f, 1.0f, 0.0f);
+ break;
+ case SHD_WAVE_RINGS_DIRECTION_SPHERICAL:
+ /* Ignore. */
+ break;
+ }
+ n = len_v3(rp) * 20.0f;
+ break;
+ }
+
+ n += phase[i];
+
+ if (distortion[i] != 0.0f) {
+ n += distortion[i] *
+ (noise::perlin_fractal(p * dscale[i], detail[i], droughness[i]) * 2.0f - 1.0f);
+ }
+
+ switch (wave_profile_) {
+ case SHD_WAVE_PROFILE_SIN:
+ val = 0.5f + 0.5f * sinf(n - M_PI_2);
+ break;
+ case SHD_WAVE_PROFILE_SAW:
+ n /= M_PI * 2.0f;
+ val = n - floorf(n);
+ break;
+ case SHD_WAVE_PROFILE_TRI:
+ n /= M_PI * 2.0f;
+ val = fabsf(n - floorf(n + 0.5f)) * 2.0f;
+ break;
+ }
+
+ r_fac[i] = val;
+ }
+ if (!r_color.is_empty()) {
+ for (int64_t i : mask) {
+ r_color[i] = ColorGeometry4f(r_fac[i], r_fac[i], r_fac[i], 1.0f);
+ }
+ }
+ }
+};
+
+static void sh_node_wave_tex_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
+{
+ bNode &node = builder.node();
+ NodeTexWave *tex = (NodeTexWave *)node.storage;
+ builder.construct_and_set_matching_fn<WaveFunction>(
+ tex->wave_type, tex->bands_direction, tex->rings_direction, tex->wave_profile);
+}
+
+} // namespace blender::nodes::node_shader_tex_wave_cc
+
+void register_node_type_sh_tex_wave()
+{
+ namespace file_ns = blender::nodes::node_shader_tex_wave_cc;
+
+ static bNodeType ntype;
+
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_WAVE, "Wave Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_wave_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_wave;
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_wave);
+ node_type_storage(&ntype, "NodeTexWave", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_wave);
+ ntype.build_multi_function = file_ns::sh_node_wave_tex_build_multi_function;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
index 03543e5f7fe..3a5bc98896c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
@@ -17,20 +17,31 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+#include "BLI_noise.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_white_noise_cc {
static void sh_node_tex_white_noise_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("W").min(-10000.0f).max(10000.0f);
- b.add_output<decl::Float>("Value");
- b.add_output<decl::Color>("Color");
-};
+ b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f).implicit_field();
+ b.add_input<decl::Float>(N_("W")).min(-10000.0f).max(10000.0f).make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is faster. */
+ node.custom1 = 1;
+ });
+ b.add_output<decl::Float>(N_("Value"));
+ b.add_output<decl::Color>(N_("Color"));
+}
-} // namespace blender::nodes
+static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "noise_dimensions", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_tex_white_noise(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -56,24 +67,150 @@ static int gpu_shader_tex_white_noise(GPUMaterial *mat,
return GPU_stack_link(mat, node, name, in, out);
}
-static void node_shader_update_tex_white_noise(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_shader_update_tex_white_noise(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector");
bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W");
- nodeSetSocketAvailability(sockVector, node->custom1 != 1);
- nodeSetSocketAvailability(sockW, node->custom1 == 1 || node->custom1 == 4);
+ nodeSetSocketAvailability(ntree, sockVector, node->custom1 != 1);
+ nodeSetSocketAvailability(ntree, sockW, node->custom1 == 1 || node->custom1 == 4);
+}
+
+class WhiteNoiseFunction : public fn::MultiFunction {
+ private:
+ int dimensions_;
+
+ public:
+ WhiteNoiseFunction(int dimensions) : dimensions_(dimensions)
+ {
+ BLI_assert(dimensions >= 1 && dimensions <= 4);
+ static std::array<fn::MFSignature, 4> signatures{
+ create_signature(1),
+ create_signature(2),
+ create_signature(3),
+ create_signature(4),
+ };
+ this->set_signature(&signatures[dimensions - 1]);
+ }
+
+ static fn::MFSignature create_signature(int dimensions)
+ {
+ fn::MFSignatureBuilder signature{"WhiteNoise"};
+
+ if (ELEM(dimensions, 2, 3, 4)) {
+ signature.single_input<float3>("Vector");
+ }
+ if (ELEM(dimensions, 1, 4)) {
+ signature.single_input<float>("W");
+ }
+
+ signature.single_output<float>("Value");
+ signature.single_output<ColorGeometry4f>("Color");
+
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ int param = ELEM(dimensions_, 2, 3, 4) + ELEM(dimensions_, 1, 4);
+
+ MutableSpan<float> r_value = params.uninitialized_single_output_if_required<float>(param++,
+ "Value");
+ MutableSpan<ColorGeometry4f> r_color =
+ params.uninitialized_single_output_if_required<ColorGeometry4f>(param++, "Color");
+
+ const bool compute_value = !r_value.is_empty();
+ const bool compute_color = !r_color.is_empty();
+
+ switch (dimensions_) {
+ case 1: {
+ const VArray<float> &w = params.readonly_single_input<float>(0, "W");
+ if (compute_color) {
+ for (int64_t i : mask) {
+ const float3 c = noise::hash_float_to_float3(w[i]);
+ r_color[i] = ColorGeometry4f(c[0], c[1], c[2], 1.0f);
+ }
+ }
+ if (compute_value) {
+ for (int64_t i : mask) {
+ r_value[i] = noise::hash_float_to_float(w[i]);
+ }
+ }
+ break;
+ }
+ case 2: {
+ const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
+ if (compute_color) {
+ for (int64_t i : mask) {
+ const float3 c = noise::hash_float_to_float3(float2(vector[i].x, vector[i].y));
+ r_color[i] = ColorGeometry4f(c[0], c[1], c[2], 1.0f);
+ }
+ }
+ if (compute_value) {
+ for (int64_t i : mask) {
+ r_value[i] = noise::hash_float_to_float(float2(vector[i].x, vector[i].y));
+ }
+ }
+ break;
+ }
+ case 3: {
+ const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
+ if (compute_color) {
+ for (int64_t i : mask) {
+ const float3 c = noise::hash_float_to_float3(vector[i]);
+ r_color[i] = ColorGeometry4f(c[0], c[1], c[2], 1.0f);
+ }
+ }
+ if (compute_value) {
+ for (int64_t i : mask) {
+ r_value[i] = noise::hash_float_to_float(vector[i]);
+ }
+ }
+ break;
+ }
+ case 4: {
+ const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
+ const VArray<float> &w = params.readonly_single_input<float>(1, "W");
+ if (compute_color) {
+ for (int64_t i : mask) {
+ const float3 c = noise::hash_float_to_float3(
+ float4(vector[i].x, vector[i].y, vector[i].z, w[i]));
+ r_color[i] = ColorGeometry4f(c[0], c[1], c[2], 1.0f);
+ }
+ }
+ if (compute_value) {
+ for (int64_t i : mask) {
+ r_value[i] = noise::hash_float_to_float(
+ float4(vector[i].x, vector[i].y, vector[i].z, w[i]));
+ }
+ }
+ break;
+ }
+ }
+ }
+};
+
+static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+{
+ bNode &node = builder.node();
+ builder.construct_and_set_matching_fn<WhiteNoiseFunction>((int)node.custom1);
}
-void register_node_type_sh_tex_white_noise(void)
+} // namespace blender::nodes::node_shader_tex_white_noise_cc
+
+void register_node_type_sh_tex_white_noise()
{
+ namespace file_ns = blender::nodes::node_shader_tex_white_noise_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_white_noise_declare;
- node_type_init(&ntype, node_shader_init_tex_white_noise);
- node_type_gpu(&ntype, gpu_shader_tex_white_noise);
- node_type_update(&ntype, node_shader_update_tex_white_noise);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_white_noise_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_white_noise;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_white_noise);
+ node_type_gpu(&ntype, file_ns::gpu_shader_tex_white_noise);
+ node_type_update(&ntype, file_ns::node_shader_update_tex_white_noise);
+ ntype.build_multi_function = file_ns::sh_node_noise_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc
index 05c3248af65..382a0f16ecd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c
+++ b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc
@@ -17,23 +17,35 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_uvalongstroke_out[] = {
- {SOCK_VECTOR, N_("UV"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_uv_along_stroke_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("UV"));
+}
+
+static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_tips", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+}
+
+} // namespace blender::nodes::node_shader_uv_along_stroke_cc
/* node type definition */
-void register_node_type_sh_uvalongstroke(void)
+void register_node_type_sh_uvalongstroke()
{
+ namespace file_ns = blender::nodes::node_shader_uv_along_stroke_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_UVALONGSTROKE, "UV Along Stroke", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_uvalongstroke_out);
- node_type_init(&ntype, NULL);
+ sh_node_type_base(&ntype, SH_NODE_UVALONGSTROKE, "UV Along Stroke", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_uvalongstroke;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.c b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc
index 775b8ffbc06..b004be75188 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uvmap.c
+++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc
@@ -17,20 +17,39 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+#include "BKE_context.h"
#include "DNA_customdata_types.h"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_uvmap_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("UV"));
+}
-static bNodeSocketTemplate sh_node_uvmap_out[] = {
- {SOCK_VECTOR, N_("UV"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "from_instancer", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+
+ if (!RNA_boolean_get(ptr, "from_instancer")) {
+ PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
+
+ if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
+ PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
+ uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
+ }
+ }
+}
static void node_shader_init_uvmap(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderUVMap *attr = MEM_callocN(sizeof(NodeShaderUVMap), "NodeShaderUVMap");
+ NodeShaderUVMap *attr = MEM_cnew<NodeShaderUVMap>("NodeShaderUVMap");
node->storage = attr;
}
@@ -40,7 +59,7 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- NodeShaderUVMap *attr = node->storage;
+ NodeShaderUVMap *attr = static_cast<NodeShaderUVMap *>(node->storage);
GPUNodeLink *mtface = GPU_attribute(mat, CD_MTFACE, attr->uv_map);
GPU_stack_link(mat, node, "node_uvmap", in, out, mtface);
@@ -50,18 +69,23 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat,
return 1;
}
+} // namespace blender::nodes::node_shader_uvmap_cc
+
/* node type definition */
-void register_node_type_sh_uvmap(void)
+void register_node_type_sh_uvmap()
{
+ namespace file_ns = blender::nodes::node_shader_uvmap_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_UVMAP, "UV Map", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_uvmap_out);
+ sh_node_type_base(&ntype, SH_NODE_UVMAP, "UV Map", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_uvmap;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_uvmap);
+ node_type_init(&ntype, file_ns::node_shader_init_uvmap);
node_type_storage(
&ntype, "NodeShaderUVMap", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_uvmap);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_uvmap);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc
index 1344ce5c5d9..265f03e6e88 100644
--- a/source/blender/nodes/shader/nodes/node_shader_value.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_value.cc
@@ -21,16 +21,14 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_value_cc {
static void sh_node_value_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("Value");
-};
-
-} // namespace blender::nodes
+ b.add_output<decl::Float>(N_("Value"));
+}
static int gpu_shader_value(GPUMaterial *mat,
bNode *node,
@@ -49,14 +47,18 @@ static void sh_node_value_build_multi_function(blender::nodes::NodeMultiFunction
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value);
}
-void register_node_type_sh_value(void)
+} // namespace blender::nodes::node_shader_value_cc
+
+void register_node_type_sh_value()
{
+ namespace file_ns = blender::nodes::node_shader_value_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::sh_node_value_declare;
- node_type_gpu(&ntype, gpu_shader_value);
- ntype.build_multi_function = sh_node_value_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::sh_node_value_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_value);
+ ntype.build_multi_function = file_ns::sh_node_value_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc
index 2b69e781e30..d34ef29c30a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc
@@ -17,21 +17,17 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_vector_displacement_cc {
-static bNodeSocketTemplate sh_node_vector_displacement_in[] = {
- {SOCK_RGBA, N_("Vector"), 0.00f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Midlevel"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Scale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_vector_displacement_out[] = {
- {SOCK_VECTOR, N_("Displacement"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Vector")).hide_value();
+ b.add_input<decl::Float>(N_("Midlevel")).default_value(0.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Scale")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_output<decl::Vector>(N_("Displacement"));
+}
static void node_shader_init_vector_displacement(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -60,18 +56,20 @@ static int gpu_shader_vector_displacement(GPUMaterial *mat,
}
}
+} // namespace blender::nodes::node_shader_vector_displacement_cc
+
/* node type definition */
-void register_node_type_sh_vector_displacement(void)
+void register_node_type_sh_vector_displacement()
{
+ namespace file_ns = blender::nodes::node_shader_vector_displacement_cc;
+
static bNodeType ntype;
sh_node_type_base(
- &ntype, SH_NODE_VECTOR_DISPLACEMENT, "Vector Displacement", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(
- &ntype, sh_node_vector_displacement_in, sh_node_vector_displacement_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_init(&ntype, node_shader_init_vector_displacement);
- node_type_gpu(&ntype, gpu_shader_vector_displacement);
+ &ntype, SH_NODE_VECTOR_DISPLACEMENT, "Vector Displacement", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_vector_displacement);
+ node_type_gpu(&ntype, file_ns::gpu_shader_vector_displacement);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
index f49ff06cef1..591734c7dd6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
@@ -21,24 +21,74 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
#include "NOD_math_functions.hh"
+#include "NOD_socket_search_link.hh"
-namespace blender::nodes {
+#include "RNA_enum_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_vector_math_cc {
static void sh_node_vector_math_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Vector>("Vector", "Vector_001").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Vector>("Vector", "Vector_002").min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>("Scale").default_value(1.0f).min(-10000.0f).max(10000.0f);
- b.add_output<decl::Vector>("Vector");
- b.add_output<decl::Float>("Value");
+ b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Vector>(N_("Vector"), "Vector_001").min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Vector>(N_("Vector"), "Vector_002").min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Scale")).default_value(1.0f).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Vector>(N_("Vector"));
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "operation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ NodeVectorMathOperation mode = NODE_VECTOR_MATH_ADD;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("ShaderNodeVectorMath");
+ node.custom1 = mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
};
-} // namespace blender::nodes
+static void sh_node_vector_math_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ if (!params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_VECTOR)) {
+ return;
+ }
+
+ const int weight = ELEM(params.other_socket().type, SOCK_VECTOR, SOCK_RGBA) ? 0 : -1;
+
+ for (const EnumPropertyItem *item = rna_enum_node_vec_math_items; item->identifier != nullptr;
+ item++) {
+ if (item->name != nullptr && item->identifier[0] != '\0') {
+ if ((params.in_out() == SOCK_OUT) && ELEM(item->value,
+ NODE_VECTOR_MATH_LENGTH,
+ NODE_VECTOR_MATH_DISTANCE,
+ NODE_VECTOR_MATH_DOT_PRODUCT)) {
+ params.add_item(IFACE_(item->name),
+ SocketSearchOp{"Value", (NodeVectorMathOperation)item->value},
+ weight);
+ }
+ else {
+ params.add_item(IFACE_(item->name),
+ SocketSearchOp{"Vector", (NodeVectorMathOperation)item->value},
+ weight);
+ }
+ }
+ }
+}
static const char *gpu_shader_get_name(int mode)
{
@@ -119,7 +169,7 @@ static int gpu_shader_vector_math(GPUMaterial *mat,
return 0;
}
-static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_shader_update_vector_math(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sockB = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
bNodeSocket *sockC = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
@@ -128,7 +178,8 @@ static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node
bNodeSocket *sockVector = nodeFindSocket(node, SOCK_OUT, "Vector");
bNodeSocket *sockValue = nodeFindSocket(node, SOCK_OUT, "Value");
- nodeSetSocketAvailability(sockB,
+ nodeSetSocketAvailability(ntree,
+ sockB,
!ELEM(node->custom1,
NODE_VECTOR_MATH_SINE,
NODE_VECTOR_MATH_COSINE,
@@ -140,19 +191,22 @@ static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node
NODE_VECTOR_MATH_ABSOLUTE,
NODE_VECTOR_MATH_FRACTION,
NODE_VECTOR_MATH_NORMALIZE));
- nodeSetSocketAvailability(sockC,
+ nodeSetSocketAvailability(ntree,
+ sockC,
ELEM(node->custom1,
NODE_VECTOR_MATH_WRAP,
NODE_VECTOR_MATH_FACEFORWARD,
NODE_VECTOR_MATH_MULTIPLY_ADD));
- nodeSetSocketAvailability(sockScale,
- ELEM(node->custom1, NODE_VECTOR_MATH_SCALE, NODE_VECTOR_MATH_REFRACT));
- nodeSetSocketAvailability(sockVector,
+ nodeSetSocketAvailability(
+ ntree, sockScale, ELEM(node->custom1, NODE_VECTOR_MATH_SCALE, NODE_VECTOR_MATH_REFRACT));
+ nodeSetSocketAvailability(ntree,
+ sockVector,
!ELEM(node->custom1,
NODE_VECTOR_MATH_LENGTH,
NODE_VECTOR_MATH_DISTANCE,
NODE_VECTOR_MATH_DOT_PRODUCT));
- nodeSetSocketAvailability(sockValue,
+ nodeSetSocketAvailability(ntree,
+ sockValue,
ELEM(node->custom1,
NODE_VECTOR_MATH_LENGTH,
NODE_VECTOR_MATH_DISTANCE,
@@ -197,8 +251,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{info.title_case_name,
- function};
+ static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -208,7 +262,7 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl3_fl3_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
- info.title_case_name, function};
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -218,7 +272,7 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl3_fl_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
- info.title_case_name, function};
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -227,8 +281,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{info.title_case_name,
- function};
+ static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -237,8 +291,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{info.title_case_name,
- function};
+ static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -247,7 +301,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name, function};
+ static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name.c_str(),
+ function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -256,7 +311,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_to_fl(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name, function};
+ static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name.c_str(),
+ function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -273,16 +329,22 @@ static void sh_node_vector_math_build_multi_function(
builder.set_matching_fn(fn);
}
-void register_node_type_sh_vect_math(void)
+} // namespace blender::nodes::node_shader_vector_math_cc
+
+void register_node_type_sh_vect_math()
{
+ namespace file_ns = blender::nodes::node_shader_vector_math_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR, 0);
- ntype.declare = blender::nodes::sh_node_vector_math_declare;
- node_type_label(&ntype, node_vector_math_label);
- node_type_gpu(&ntype, gpu_shader_vector_math);
- node_type_update(&ntype, node_shader_update_vector_math);
- ntype.build_multi_function = sh_node_vector_math_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::sh_node_vector_math_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_vect_math;
+ ntype.labelfunc = node_vector_math_label;
+ node_type_gpu(&ntype, file_ns::gpu_shader_vector_math);
+ node_type_update(&ntype, file_ns::node_shader_update_vector_math);
+ ntype.build_multi_function = file_ns::sh_node_vector_math_build_multi_function;
+ ntype.gather_link_search_ops = file_ns::sh_node_vector_math_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
index c9b26fa5199..d8dcd028c56 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
@@ -21,22 +21,29 @@
* \ingroup shdnodes
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_vector_rotate_cc {
static void sh_node_vector_rotate_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>("Vector").min(0.0f).max(1.0f).hide_value();
- b.add_input<decl::Vector>("Center");
- b.add_input<decl::Vector>("Axis").min(-1.0f).max(1.0f).default_value({0.0f, 0.0f, 1.0f});
- b.add_input<decl::Float>("Angle").subtype(PROP_ANGLE);
- b.add_input<decl::Vector>("Rotation").subtype(PROP_EULER);
- b.add_output<decl::Vector>("Vector");
-};
+ b.add_input<decl::Vector>(N_("Vector")).min(0.0f).max(1.0f).hide_value();
+ b.add_input<decl::Vector>(N_("Center"));
+ b.add_input<decl::Vector>(N_("Axis")).min(-1.0f).max(1.0f).default_value({0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE);
+ b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER);
+ b.add_output<decl::Vector>(N_("Vector"));
+}
-} // namespace blender::nodes
+static void node_shader_buts_vector_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "rotation_type", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "invert", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+}
static const char *gpu_shader_get_name(int mode)
{
@@ -193,25 +200,32 @@ static void sh_node_vector_rotate_build_multi_function(
builder.set_matching_fn(fn);
}
-static void node_shader_update_vector_rotate(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_shader_update_vector_rotate(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sock_rotation = nodeFindSocket(node, SOCK_IN, "Rotation");
- nodeSetSocketAvailability(sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
+ nodeSetSocketAvailability(
+ ntree, sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
bNodeSocket *sock_axis = nodeFindSocket(node, SOCK_IN, "Axis");
- nodeSetSocketAvailability(sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS));
+ nodeSetSocketAvailability(ntree, sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS));
bNodeSocket *sock_angle = nodeFindSocket(node, SOCK_IN, "Angle");
- nodeSetSocketAvailability(sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
+ nodeSetSocketAvailability(
+ ntree, sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
}
-void register_node_type_sh_vector_rotate(void)
+} // namespace blender::nodes::node_shader_vector_rotate_cc
+
+void register_node_type_sh_vector_rotate()
{
+ namespace file_ns = blender::nodes::node_shader_vector_rotate_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR, 0);
- ntype.declare = blender::nodes::sh_node_vector_rotate_declare;
- node_type_gpu(&ntype, gpu_shader_vector_rotate);
- node_type_update(&ntype, node_shader_update_vector_rotate);
- ntype.build_multi_function = sh_node_vector_rotate_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::sh_node_vector_rotate_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_vector_rotate;
+ node_type_gpu(&ntype, file_ns::gpu_shader_vector_rotate);
+ node_type_update(&ntype, file_ns::node_shader_update_vector_rotate);
+ ntype.build_multi_function = file_ns::sh_node_vector_rotate_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c b/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc
index 41e61da60d7..a8a6902e30c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc
@@ -21,23 +21,37 @@
* \ingroup shdnodes
*/
-#include "BLI_string.h"
+#include "node_shader_util.hh"
-#include "../node_shader_util.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
-/* **************** Vector Transform ******************** */
-static bNodeSocketTemplate sh_node_vect_transform_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, {-1, ""}};
+namespace blender::nodes::node_shader_vector_transform_cc {
-static bNodeSocketTemplate sh_node_vect_transform_out[] = {
- {SOCK_VECTOR, N_("Vector")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector"))
+ .default_value({0.5f, 0.5f, 0.5f})
+ .min(-10000.0f)
+ .max(10000.0f);
+ b.add_output<decl::Vector>(N_("Vector"));
+}
+
+static void node_shader_buts_vect_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout,
+ ptr,
+ "vector_type",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+ uiItemR(layout, ptr, "convert_from", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "convert_to", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_vect_transform(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderVectTransform *vect = MEM_callocN(sizeof(NodeShaderVectTransform),
- "NodeShaderVectTransform");
+ NodeShaderVectTransform *vect = MEM_cnew<NodeShaderVectTransform>("NodeShaderVectTransform");
/* Convert World into Object Space per default */
vect->convert_to = 1;
@@ -45,52 +59,42 @@ static void node_shader_init_vect_transform(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = vect;
}
-static void node_shader_exec_vect_transform(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **UNUSED(in),
- bNodeStack **UNUSED(out))
-{
-}
-
-static const char *get_gpufn_name_from_to(short from, short to)
+static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
{
switch (from) {
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
switch (to) {
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
- return NULL;
+ return nullptr;
case SHD_VECT_TRANSFORM_SPACE_WORLD:
- return "object_to_world";
+ return GPU_builtin(GPU_OBJECT_MATRIX);
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
- return "object_to_view";
+ return GPU_builtin(GPU_LOC_TO_VIEW_MATRIX);
}
break;
case SHD_VECT_TRANSFORM_SPACE_WORLD:
switch (to) {
case SHD_VECT_TRANSFORM_SPACE_WORLD:
- return NULL;
+ return nullptr;
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
- return "world_to_view";
+ return GPU_builtin(GPU_VIEW_MATRIX);
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
- return "world_to_object";
+ return GPU_builtin(GPU_INVERSE_OBJECT_MATRIX);
}
break;
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
switch (to) {
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
- return NULL;
+ return nullptr;
case SHD_VECT_TRANSFORM_SPACE_WORLD:
- return "view_to_world";
+ return GPU_builtin(GPU_INVERSE_VIEW_MATRIX);
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
- return "view_to_object";
+ return GPU_builtin(GPU_INVERSE_LOC_TO_VIEW_MATRIX);
}
break;
}
- return NULL;
+ return nullptr;
}
-
static int gpu_shader_vect_transform(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
@@ -98,6 +102,11 @@ static int gpu_shader_vect_transform(GPUMaterial *mat,
GPUNodeStack *out)
{
struct GPUNodeLink *inputlink;
+ struct GPUNodeLink *fromto;
+
+ const char *vtransform = "direction_transform_m4v3";
+ const char *ptransform = "point_transform_m4v3";
+ const char *func_name = nullptr;
NodeShaderVectTransform *nodeprop = (NodeShaderVectTransform *)node->storage;
@@ -108,10 +117,9 @@ static int gpu_shader_vect_transform(GPUMaterial *mat,
inputlink = GPU_constant(in[0].vec);
}
- const char *xform = (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_POINT) ? "point_transform_" :
- "direction_transform_";
- const char *fromto = get_gpufn_name_from_to(nodeprop->convert_from, nodeprop->convert_to);
+ fromto = get_gpulink_matrix_from_to(nodeprop->convert_from, nodeprop->convert_to);
+ func_name = (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_POINT) ? ptransform : vtransform;
if (fromto) {
/* For cycles we have inverted Z */
/* TODO: pass here the correct matrices */
@@ -119,11 +127,7 @@ static int gpu_shader_vect_transform(GPUMaterial *mat,
nodeprop->convert_to != SHD_VECT_TRANSFORM_SPACE_CAMERA) {
GPU_link(mat, "invert_z", inputlink, &inputlink);
}
-
- char func_name[48];
- SNPRINTF(func_name, "%s%s", xform, fromto);
- GPU_link(mat, func_name, inputlink, &out[0].link);
-
+ GPU_link(mat, func_name, inputlink, fromto, &out[0].link);
if (nodeprop->convert_to == SHD_VECT_TRANSFORM_SPACE_CAMERA &&
nodeprop->convert_from != SHD_VECT_TRANSFORM_SPACE_CAMERA) {
GPU_link(mat, "invert_z", out[0].link, &out[0].link);
@@ -140,17 +144,21 @@ static int gpu_shader_vect_transform(GPUMaterial *mat,
return true;
}
-void register_node_type_sh_vect_transform(void)
+} // namespace blender::nodes::node_shader_vector_transform_cc
+
+void register_node_type_sh_vect_transform()
{
+ namespace file_ns = blender::nodes::node_shader_vector_transform_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VECT_TRANSFORM, "Vector Transform", NODE_CLASS_OP_VECTOR, 0);
- node_type_init(&ntype, node_shader_init_vect_transform);
- node_type_socket_templates(&ntype, sh_node_vect_transform_in, sh_node_vect_transform_out);
+ sh_node_type_base(&ntype, SH_NODE_VECT_TRANSFORM, "Vector Transform", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_vect_transform;
+ node_type_init(&ntype, file_ns::node_shader_init_vect_transform);
node_type_storage(
&ntype, "NodeShaderVectTransform", node_free_standard_storage, node_copy_standard_storage);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_vect_transform);
- node_type_gpu(&ntype, gpu_shader_vect_transform);
+ node_type_gpu(&ntype, file_ns::gpu_shader_vect_transform);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vertex_color.c b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
index 40576b68dd5..6501527ef5d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vertex_color.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
@@ -17,18 +17,44 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-static bNodeSocketTemplate sh_node_vertex_color_out[] = {
- {SOCK_RGBA, N_("Color")},
- {SOCK_FLOAT, N_("Alpha")},
- {-1, ""},
-};
+#include "BKE_context.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_vertex_color_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Alpha"));
+}
+
+static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
+ if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
+ PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
+
+ if (U.experimental.use_sculpt_vertex_colors &&
+ RNA_collection_length(&dataptr, "sculpt_vertex_colors")) {
+ uiItemPointerR(
+ layout, ptr, "layer_name", &dataptr, "sculpt_vertex_colors", "", ICON_GROUP_VCOL);
+ }
+ else {
+ uiItemPointerR(layout, ptr, "layer_name", &dataptr, "vertex_colors", "", ICON_GROUP_VCOL);
+ }
+ }
+ else {
+ uiItemL(layout, TIP_("No mesh in active object"), ICON_ERROR);
+ }
+}
static void node_shader_init_vertex_color(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderVertexColor *vertexColor = MEM_callocN(sizeof(NodeShaderVertexColor),
- "NodeShaderVertexColor");
+ NodeShaderVertexColor *vertexColor = MEM_cnew<NodeShaderVertexColor>("NodeShaderVertexColor");
node->storage = vertexColor;
}
@@ -47,16 +73,21 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
}
-void register_node_type_sh_vertex_color(void)
+} // namespace blender::nodes::node_shader_vertex_color_cc
+
+void register_node_type_sh_vertex_color()
{
+ namespace file_ns = blender::nodes::node_shader_vertex_color_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VERTEX_COLOR, "Vertex Color", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_vertex_color_out);
- node_type_init(&ntype, node_shader_init_vertex_color);
+ sh_node_type_base(&ntype, SH_NODE_VERTEX_COLOR, "Vertex Color", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_vertex_color;
+ node_type_init(&ntype, file_ns::node_shader_init_vertex_color);
node_type_storage(
&ntype, "NodeShaderVertexColor", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_vertex_color);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_vertex_color);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc
index 3c9fab2401b..a31bfdb6543 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc
@@ -17,21 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_volume_absorption_cc {
-static bNodeSocketTemplate sh_node_volume_absorption_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Density"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_volume_absorption_out[] = {
- {SOCK_SHADER, N_("Volume")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_output<decl::Shader>(N_("Volume"));
+}
static int node_shader_gpu_volume_absorption(GPUMaterial *mat,
bNode *node,
@@ -42,16 +37,18 @@ static int node_shader_gpu_volume_absorption(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_volume_absorption", in, out);
}
+} // namespace blender::nodes::node_shader_volume_absorption_cc
+
/* node type definition */
-void register_node_type_sh_volume_absorption(void)
+void register_node_type_sh_volume_absorption()
{
+ namespace file_ns = blender::nodes::node_shader_volume_absorption_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VOLUME_ABSORPTION, "Volume Absorption", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_volume_absorption_in, sh_node_volume_absorption_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_volume_absorption);
+ sh_node_type_base(&ntype, SH_NODE_VOLUME_ABSORPTION, "Volume Absorption", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_absorption);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_info.c b/source/blender/nodes/shader/nodes/node_shader_volume_info.cc
index 6cafc991e13..6a973cdbad7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_info.cc
@@ -17,15 +17,17 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-static bNodeSocketTemplate sh_node_volume_info_out[] = {
- {SOCK_RGBA, N_("Color")},
- {SOCK_FLOAT, N_("Density")},
- {SOCK_FLOAT, N_("Flame")},
- {SOCK_FLOAT, N_("Temperature")},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_volume_info_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Density"));
+ b.add_output<decl::Float>(N_("Flame"));
+ b.add_output<decl::Float>(N_("Temperature"));
+}
static int node_shader_gpu_volume_info(GPUMaterial *mat,
bNode *UNUSED(node),
@@ -49,13 +51,17 @@ static int node_shader_gpu_volume_info(GPUMaterial *mat,
return true;
}
-void register_node_type_sh_volume_info(void)
+} // namespace blender::nodes::node_shader_volume_info_cc
+
+void register_node_type_sh_volume_info()
{
+ namespace file_ns = blender::nodes::node_shader_volume_info_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VOLUME_INFO, "Volume Info", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_volume_info_out);
- node_type_gpu(&ntype, node_shader_gpu_volume_info);
+ sh_node_type_base(&ntype, SH_NODE_VOLUME_INFO, "Volume Info", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
index 41c3abd7ca4..54e92eafcf6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
@@ -17,31 +17,34 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_volume_principled_in[] = {
- {SOCK_RGBA, N_("Color"), 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
- {SOCK_STRING, N_("Color Attribute"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Density"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_STRING, N_("Density Attribute"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Anisotropy"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Absorption Color"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Emission Strength"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1000.0f},
- {SOCK_RGBA, N_("Emission Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Blackbody Intensity"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Blackbody Tint"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Temperature"), 1000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 6500.0f},
- {SOCK_STRING, N_("Temperature Attribute"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_volume_principled_out[] = {
- {SOCK_SHADER, N_("Volume")},
- {-1, ""},
-};
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_volume_principled_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_input<decl::String>(N_("Color Attribute"));
+ b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::String>(N_("Density Attribute"));
+ b.add_input<decl::Float>(N_("Anisotropy"))
+ .default_value(0.0f)
+ .min(-1.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Absorption Color")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Emission Strength")).default_value(0.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Color>(N_("Emission Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Blackbody Intensity"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Blackbody Tint")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Temperature")).default_value(1000.0f).min(0.0f).max(6500.0f);
+ b.add_input<decl::String>(N_("Temperature Attribute"));
+ b.add_output<decl::Shader>(N_("Volume"));
+}
static void node_shader_init_volume_principled(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -65,14 +68,14 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
bool use_blackbody = (in[8].link || in[8].vec[0] != 0.0f);
/* Get volume attributes. */
- GPUNodeLink *density = NULL, *color = NULL, *temperature = NULL;
+ GPUNodeLink *density = nullptr, *color = nullptr, *temperature = nullptr;
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (sock->typeinfo->type != SOCK_STRING) {
continue;
}
- bNodeSocketValueString *value = sock->default_value;
+ bNodeSocketValueString *value = (bNodeSocketValueString *)sock->default_value;
const char *attribute_name = value->value;
if (attribute_name[0] == '\0') {
continue;
@@ -107,11 +110,11 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
const int size = CM_TABLE + 1;
float *data, layer;
if (use_blackbody) {
- data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
+ data = (float *)MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
}
else {
- data = MEM_callocN(sizeof(float) * size * 4, "blackbody black");
+ data = (float *)MEM_callocN(sizeof(float) * size * 4, "blackbody black");
}
GPUNodeLink *spectrummap = GPU_color_band(mat, size, data, &layer);
@@ -127,17 +130,20 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
GPU_constant(&layer));
}
+} // namespace blender::nodes::node_shader_volume_principled_cc
+
/* node type definition */
-void register_node_type_sh_volume_principled(void)
+void register_node_type_sh_volume_principled()
{
+ namespace file_ns = blender::nodes::node_shader_volume_principled_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VOLUME_PRINCIPLED, "Principled Volume", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_volume_principled_in, sh_node_volume_principled_out);
+ sh_node_type_base(&ntype, SH_NODE_VOLUME_PRINCIPLED, "Principled Volume", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_init(&ntype, node_shader_init_volume_principled);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_volume_principled);
+ node_type_init(&ntype, file_ns::node_shader_init_volume_principled);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_principled);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc
index 282a49dc944..abd10cfcbcf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc
@@ -17,22 +17,21 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_volume_scatter_cc {
-static bNodeSocketTemplate sh_node_volume_scatter_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Density"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Anisotropy"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Weight"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_UNAVAIL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_volume_scatter_out[] = {
- {SOCK_SHADER, N_("Volume")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Anisotropy"))
+ .default_value(0.0f)
+ .min(-1.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_output<decl::Shader>(N_("Volume"));
+}
static int node_shader_gpu_volume_scatter(GPUMaterial *mat,
bNode *node,
@@ -43,16 +42,18 @@ static int node_shader_gpu_volume_scatter(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_volume_scatter", in, out);
}
+} // namespace blender::nodes::node_shader_volume_scatter_cc
+
/* node type definition */
-void register_node_type_sh_volume_scatter(void)
+void register_node_type_sh_volume_scatter()
{
+ namespace file_ns = blender::nodes::node_shader_volume_scatter_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VOLUME_SCATTER, "Volume Scatter", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_volume_scatter_in, sh_node_volume_scatter_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_volume_scatter);
+ sh_node_type_base(&ntype, SH_NODE_VOLUME_SCATTER, "Volume Scatter", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_scatter);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_wavelength.c b/source/blender/nodes/shader/nodes/node_shader_wavelength.cc
index f978537ee85..a67c7830edd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_wavelength.c
+++ b/source/blender/nodes/shader/nodes/node_shader_wavelength.cc
@@ -17,18 +17,15 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Wavelength ******************** */
-static bNodeSocketTemplate sh_node_wavelength_in[] = {
- {SOCK_FLOAT, N_("Wavelength"), 500.0f, 0.0f, 0.0f, 0.0f, 380.0f, 780.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_wavelength_cc {
-static bNodeSocketTemplate sh_node_wavelength_out[] = {
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Wavelength")).default_value(500.0f).min(380.0f).max(780.0f);
+ b.add_output<decl::Color>(N_("Color"));
+}
static int node_shader_gpu_wavelength(GPUMaterial *mat,
bNode *node,
@@ -37,7 +34,7 @@ static int node_shader_gpu_wavelength(GPUMaterial *mat,
GPUNodeStack *out)
{
const int size = CM_TABLE + 1;
- float *data = MEM_mallocN(sizeof(float) * size * 4, "cie_xyz texture");
+ float *data = static_cast<float *>(MEM_mallocN(sizeof(float) * size * 4, "cie_xyz texture"));
wavelength_to_xyz_table(data, size);
@@ -57,17 +54,19 @@ static int node_shader_gpu_wavelength(GPUMaterial *mat,
GPU_uniform(xyz_to_rgb.b));
}
+} // namespace blender::nodes::node_shader_wavelength_cc
+
/* node type definition */
-void register_node_type_sh_wavelength(void)
+void register_node_type_sh_wavelength()
{
+ namespace file_ns = blender::nodes::node_shader_wavelength_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_WAVELENGTH, "Wavelength", NODE_CLASS_CONVERTER, 0);
+ sh_node_type_base(&ntype, SH_NODE_WAVELENGTH, "Wavelength", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_socket_templates(&ntype, sh_node_wavelength_in, sh_node_wavelength_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_wavelength);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_wavelength);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_wireframe.c b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc
index e8c2b6971bc..c4771cc13e9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_wireframe.c
+++ b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc
@@ -17,18 +17,23 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Wireframe ******************** */
-static bNodeSocketTemplate sh_node_wireframe_in[] = {
- {SOCK_FLOAT, N_("Size"), 0.01f, 0.0f, 0.0f, 0.0f, 0.0f, 100.0f},
- {-1, ""},
-};
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_wireframe_out[] = {
- {SOCK_FLOAT, N_("Fac"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_wireframe_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Size")).default_value(0.01f).min(0.0f).max(100.0f);
+ b.add_output<decl::Float>(N_("Fac"));
+}
+
+static void node_shader_buts_wireframe(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_pixel_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+}
static int node_shader_gpu_wireframe(GPUMaterial *mat,
bNode *node,
@@ -46,16 +51,19 @@ static int node_shader_gpu_wireframe(GPUMaterial *mat,
}
}
+} // namespace blender::nodes::node_shader_wireframe_cc
+
/* node type definition */
-void register_node_type_sh_wireframe(void)
+void register_node_type_sh_wireframe()
{
+ namespace file_ns = blender::nodes::node_shader_wireframe_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_WIREFRAME, "Wireframe", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_wireframe_in, sh_node_wireframe_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_wireframe);
+ sh_node_type_base(&ntype, SH_NODE_WIREFRAME, "Wireframe", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_wireframe;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_wireframe);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/CMakeLists.txt b/source/blender/nodes/texture/CMakeLists.txt
new file mode 100644
index 00000000000..053b17e4e57
--- /dev/null
+++ b/source/blender/nodes/texture/CMakeLists.txt
@@ -0,0 +1,89 @@
+# ***** 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
+ .
+ ../
+ ../intern
+ ../../editors/include
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../depsgraph
+ ../../imbuf
+ ../../makesdna
+ ../../makesrna
+ ../../render
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+)
+
+
+set(SRC
+ nodes/node_texture_at.c
+ nodes/node_texture_bricks.c
+ nodes/node_texture_checker.c
+ nodes/node_texture_common.c
+ nodes/node_texture_compose.c
+ nodes/node_texture_coord.c
+ nodes/node_texture_curves.c
+ nodes/node_texture_decompose.c
+ nodes/node_texture_distance.c
+ nodes/node_texture_hueSatVal.c
+ nodes/node_texture_image.c
+ nodes/node_texture_invert.c
+ nodes/node_texture_math.c
+ nodes/node_texture_mixRgb.c
+ nodes/node_texture_output.c
+ nodes/node_texture_proc.c
+ nodes/node_texture_rotate.c
+ nodes/node_texture_scale.c
+ nodes/node_texture_texture.c
+ nodes/node_texture_translate.c
+ nodes/node_texture_valToNor.c
+ nodes/node_texture_valToRgb.c
+ nodes/node_texture_viewer.c
+ node_texture_tree.c
+ node_texture_util.c
+
+ node_texture_util.h
+)
+
+set(LIB
+ bf_nodes
+)
+
+if(WITH_PYTHON)
+ list(APPEND INC
+ ../../python
+ )
+ list(APPEND INC_SYS
+ ${PYTHON_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ ${PYTHON_LINKFLAGS}
+ ${PYTHON_LIBRARIES}
+ )
+ add_definitions(-DWITH_PYTHON)
+endif()
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+blender_add_lib(bf_nodes_texture "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 7452007639c..3d914d486c3 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -50,6 +50,8 @@
#include "RE_texture.h"
+#include "UI_resources.h"
+
static void texture_get_from_context(const bContext *C,
bNodeTreeType *UNUSED(treetype),
bNodeTree **r_ntree,
@@ -132,24 +134,9 @@ static void localize(bNodeTree *UNUSED(localtree), bNodeTree *UNUSED(ntree))
}
#endif
-static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_sync_tree(ntree, localtree);
-}
-
-static void local_merge(Main *UNUSED(bmain), bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_merge_tree(ntree, localtree, true);
-}
-
static void update(bNodeTree *ntree)
{
ntree_update_reroute_nodes(ntree);
-
- if (ntree->update & NTREE_UPDATE_NODES) {
- /* clean up preview cache, in case nodes have been removed */
- BKE_node_preview_remove_unused(ntree);
- }
}
static bool texture_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
@@ -169,14 +156,12 @@ void register_node_tree_type_tex(void)
tt->type = NTREE_TEXTURE;
strcpy(tt->idname, "TextureNodeTree");
strcpy(tt->ui_name, N_("Texture Node Editor"));
- tt->ui_icon = 0; /* defined in drawnode.c */
+ tt->ui_icon = ICON_NODE_TEXTURE; /* Defined in `drawnode.c`. */
strcpy(tt->ui_description, N_("Texture nodes"));
tt->foreach_nodeclass = foreach_nodeclass;
tt->update = update;
tt->localize = localize;
- tt->local_sync = local_sync;
- tt->local_merge = local_merge;
tt->get_from_context = texture_get_from_context;
tt->valid_socket_type = texture_node_tree_socket_type_valid;
diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c
index 570b10d6e89..dc5e2bfcd6b 100644
--- a/source/blender/nodes/texture/node_texture_util.c
+++ b/source/blender/nodes/texture/node_texture_util.c
@@ -44,30 +44,24 @@ bool tex_node_poll_default(bNodeType *UNUSED(ntype),
const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "TextureNodeTree")) {
- *r_disabled_hint = "Not a texture node tree";
+ *r_disabled_hint = TIP_("Not a texture node tree");
return false;
}
return true;
}
-void tex_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void tex_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = tex_node_poll_default;
ntype->insert_link = node_insert_link_default;
- ntype->update_internal_links = node_update_internal_links_default;
}
static void tex_call_delegate(TexDelegate *dg, float *out, TexParams *params, short thread)
{
if (dg->node->need_exec) {
dg->fn(out, params, dg->node, dg->in, thread);
-
- if (dg->cdata->do_preview) {
- tex_do_preview(dg->preview, params->previewco, out, dg->cdata->do_manage);
- }
}
}
@@ -124,19 +118,6 @@ void params_from_cdata(TexParams *out, TexCallData *in)
out->mtex = in->mtex;
}
-void tex_do_preview(bNodePreview *preview,
- const float coord[2],
- const float col[4],
- bool do_manage)
-{
- if (preview) {
- int xs = ((coord[0] + 1.0f) * 0.5f) * preview->xsize;
- int ys = ((coord[1] + 1.0f) * 0.5f) * preview->ysize;
-
- BKE_node_preview_set_pixel(preview, col, xs, ys, do_manage);
- }
-}
-
void tex_output(bNode *node,
bNodeExecData *execdata,
bNodeStack **in,
diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h
index 8f63a1ad07d..d53000058a3 100644
--- a/source/blender/nodes/texture/node_texture_util.h
+++ b/source/blender/nodes/texture/node_texture_util.h
@@ -37,8 +37,7 @@
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_rand.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -109,8 +108,7 @@ typedef struct TexDelegate {
bool tex_node_poll_default(struct bNodeType *ntype,
struct bNodeTree *ntree,
const char **r_disabled_hint);
-void tex_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void tex_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
void tex_input_rgba(float *out, bNodeStack *in, TexParams *params, short thread);
void tex_input_vec(float *out, bNodeStack *in, TexParams *params, short thread);
@@ -122,10 +120,6 @@ void tex_output(bNode *node,
bNodeStack *out,
TexFn texfn,
TexCallData *data);
-void tex_do_preview(bNodePreview *preview,
- const float coord[2],
- const float col[4],
- bool do_manage);
void params_from_cdata(TexParams *out, TexCallData *in);
diff --git a/source/blender/nodes/texture/nodes/node_texture_at.c b/source/blender/nodes/texture/nodes/node_texture_at.c
index a6f8d28db75..41dea303ea2 100644
--- a/source/blender/nodes/texture/nodes/node_texture_at.c
+++ b/source/blender/nodes/texture/nodes/node_texture_at.c
@@ -58,7 +58,7 @@ void register_node_type_tex_at(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_AT, "At", NODE_CLASS_DISTORT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_AT, "At", NODE_CLASS_DISTORT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_size(&ntype, 140, 100, 320);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_bricks.c b/source/blender/nodes/texture/nodes/node_texture_bricks.c
index 72690d6ccfe..0dc92dc33d0 100644
--- a/source/blender/nodes/texture/nodes/node_texture_bricks.c
+++ b/source/blender/nodes/texture/nodes/node_texture_bricks.c
@@ -119,11 +119,12 @@ void register_node_type_tex_bricks(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_BRICKS, "Bricks", NODE_CLASS_PATTERN, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_BRICKS, "Bricks", NODE_CLASS_PATTERN);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, init);
node_type_exec(&ntype, NULL, NULL, exec);
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_checker.c b/source/blender/nodes/texture/nodes/node_texture_checker.c
index e3c4d44e7f5..62657cd7def 100644
--- a/source/blender/nodes/texture/nodes/node_texture_checker.c
+++ b/source/blender/nodes/texture/nodes/node_texture_checker.c
@@ -70,9 +70,10 @@ void register_node_type_tex_checker(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_CHECKER, "Checker", NODE_CLASS_PATTERN, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_CHECKER, "Checker", NODE_CLASS_PATTERN);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c
index 2de64779ea6..d68cfe78b44 100644
--- a/source/blender/nodes/texture/nodes/node_texture_common.c
+++ b/source/blender/nodes/texture/nodes/node_texture_common.c
@@ -161,19 +161,17 @@ void register_node_type_tex_group(void)
/* NOTE: Cannot use #sh_node_type_base for node group, because it would map the node type
* to the shared #NODE_GROUP integer type id. */
- node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT);
+ node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP);
ntype.type = NODE_GROUP;
ntype.poll = tex_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
ntype.insert_link = node_insert_link_default;
- ntype.update_internal_links = node_update_internal_links_default;
ntype.rna_ext.srna = RNA_struct_find("TextureNodeGroup");
BLI_assert(ntype.rna_ext.srna != NULL);
RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
- node_type_socket_templates(&ntype, NULL, NULL);
node_type_size(&ntype, 140, 60, 400);
- node_type_label(&ntype, node_group_label);
+ ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
node_type_exec(&ntype, group_initexec, group_freeexec, group_execute);
diff --git a/source/blender/nodes/texture/nodes/node_texture_compose.c b/source/blender/nodes/texture/nodes/node_texture_compose.c
index ffa0e9ae43e..cd918ca8314 100644
--- a/source/blender/nodes/texture/nodes/node_texture_compose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_compose.c
@@ -58,7 +58,7 @@ void register_node_type_tex_compose(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_COMPOSE, "Combine RGBA", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_COMPOSE, "Combine RGBA", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_coord.c b/source/blender/nodes/texture/nodes/node_texture_coord.c
index 5a0cf5eb497..e31fdcafbf2 100644
--- a/source/blender/nodes/texture/nodes/node_texture_coord.c
+++ b/source/blender/nodes/texture/nodes/node_texture_coord.c
@@ -49,9 +49,8 @@ void register_node_type_tex_coord(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_COORD, "Coordinates", NODE_CLASS_INPUT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_COORD, "Coordinates", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, NULL, outputs);
- node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/texture/nodes/node_texture_curves.c b/source/blender/nodes/texture/nodes/node_texture_curves.c
index 70f7e731720..7fed45c5558 100644
--- a/source/blender/nodes/texture/nodes/node_texture_curves.c
+++ b/source/blender/nodes/texture/nodes/node_texture_curves.c
@@ -26,7 +26,7 @@
/* **************** CURVE Time ******************** */
-/* custom1 = sfra, custom2 = efra */
+/* custom1 = start-frame, custom2 = end-frame. */
static bNodeSocketTemplate time_outputs[] = {{SOCK_FLOAT, N_("Value")}, {-1, ""}};
static void time_colorfn(
@@ -65,7 +65,7 @@ void register_node_type_tex_curve_time(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_CURVE_TIME, "Time", NODE_CLASS_INPUT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_CURVE_TIME, "Time", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, NULL, time_outputs);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, time_init);
@@ -114,7 +114,7 @@ void register_node_type_tex_curve_rgb(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, rgb_inputs, rgb_outputs);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, rgb_init);
diff --git a/source/blender/nodes/texture/nodes/node_texture_decompose.c b/source/blender/nodes/texture/nodes/node_texture_decompose.c
index 83922ea03ab..9c3cb6911e1 100644
--- a/source/blender/nodes/texture/nodes/node_texture_decompose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_decompose.c
@@ -78,7 +78,7 @@ void register_node_type_tex_decompose(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE, "Separate RGBA", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE, "Separate RGBA", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_distance.c b/source/blender/nodes/texture/nodes/node_texture_distance.c
index f7deac9ff4a..2f8b28722bd 100644
--- a/source/blender/nodes/texture/nodes/node_texture_distance.c
+++ b/source/blender/nodes/texture/nodes/node_texture_distance.c
@@ -21,7 +21,6 @@
* \ingroup texnodes
*/
-#include "BLI_math.h"
#include "NOD_texture.h"
#include "node_texture_util.h"
#include <math.h>
@@ -61,9 +60,8 @@ void register_node_type_tex_distance(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_DISTANCE, "Distance", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_DISTANCE, "Distance", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, inputs, outputs);
- node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c b/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c
index 759fb3d43d5..f405c3b0bec 100644
--- a/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c
+++ b/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c
@@ -107,7 +107,7 @@ void register_node_type_tex_hue_sat(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_image.c b/source/blender/nodes/texture/nodes/node_texture_image.c
index 0d10b3270d7..18ae3609407 100644
--- a/source/blender/nodes/texture/nodes/node_texture_image.c
+++ b/source/blender/nodes/texture/nodes/node_texture_image.c
@@ -101,7 +101,6 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
ImageUser *iuser = MEM_callocN(sizeof(ImageUser), "node image user");
node->storage = iuser;
iuser->sfra = 1;
- iuser->ok = 1;
iuser->flag |= IMA_ANIM_ALWAYS;
}
@@ -109,12 +108,13 @@ void register_node_type_tex_image(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_IMAGE, "Image", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, NULL, outputs);
node_type_init(&ntype, init);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
node_type_exec(&ntype, NULL, NULL, exec);
- node_type_label(&ntype, node_image_label);
+ ntype.labelfunc = node_image_label;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_invert.c b/source/blender/nodes/texture/nodes/node_texture_invert.c
index 5d3f86c5c9c..7854ac4b5b8 100644
--- a/source/blender/nodes/texture/nodes/node_texture_invert.c
+++ b/source/blender/nodes/texture/nodes/node_texture_invert.c
@@ -63,7 +63,7 @@ void register_node_type_tex_invert(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c
index ab226a4dd38..2f50f6aaae0 100644
--- a/source/blender/nodes/texture/nodes/node_texture_math.c
+++ b/source/blender/nodes/texture/nodes/node_texture_math.c
@@ -335,10 +335,9 @@ void register_node_type_tex_math(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_MATH, "Math", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, inputs, outputs);
- node_type_label(&ntype, node_math_label);
- node_type_storage(&ntype, "", NULL, NULL);
+ ntype.labelfunc = node_math_label;
node_type_exec(&ntype, NULL, NULL, exec);
node_type_update(&ntype, node_math_update);
diff --git a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
index b1aeb269018..5599807d8b1 100644
--- a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
+++ b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
@@ -69,9 +69,9 @@ void register_node_type_tex_mix_rgb(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
- node_type_label(&ntype, node_blend_label);
+ ntype.labelfunc = node_blend_label;
node_type_exec(&ntype, NULL, NULL, exec);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c
index b24781e032b..4911ab7ba9e 100644
--- a/source/blender/nodes/texture/nodes/node_texture_output.c
+++ b/source/blender/nodes/texture/nodes/node_texture_output.c
@@ -21,6 +21,8 @@
* \ingroup texnodes
*/
+#include "BLI_string.h"
+
#include "NOD_texture.h"
#include "node_texture_util.h"
@@ -35,7 +37,7 @@ static bNodeSocketTemplate inputs[] = {
static void exec(void *data,
int UNUSED(thread),
bNode *node,
- bNodeExecData *execdata,
+ bNodeExecData *UNUSED(execdata),
bNodeStack **in,
bNodeStack **UNUSED(out))
{
@@ -52,7 +54,6 @@ static void exec(void *data,
else {
tex_input_rgba(&target->tr, in[0], &params, cdata->thread);
}
- tex_do_preview(execdata->preview, params.co, &target->tr, cdata->do_manage);
}
else {
/* 0 means don't care, so just use first */
@@ -165,15 +166,15 @@ void register_node_type_tex_output(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_OUTPUT, "Output", NODE_CLASS_OUTPUT, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_OUTPUT, "Output", NODE_CLASS_OUTPUT);
node_type_socket_templates(&ntype, inputs, NULL);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, init);
node_type_storage(&ntype, "TexNodeOutput", node_free_standard_storage, copy);
node_type_exec(&ntype, NULL, NULL, exec);
- /* Do not allow muting output. */
- node_type_internal_links(&ntype, NULL);
+ ntype.flag |= NODE_PREVIEW;
+ ntype.no_muting = true;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_proc.c b/source/blender/nodes/texture/nodes/node_texture_proc.c
index a8a82153e58..8c294b5954d 100644
--- a/source/blender/nodes/texture/nodes/node_texture_proc.c
+++ b/source/blender/nodes/texture/nodes/node_texture_proc.c
@@ -294,12 +294,13 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
{ \
static bNodeType ntype; \
\
- tex_node_type_base(&ntype, TEX_NODE_PROC + TEXTYPE, Name, NODE_CLASS_TEXTURE, NODE_PREVIEW); \
+ tex_node_type_base(&ntype, TEX_NODE_PROC + TEXTYPE, Name, NODE_CLASS_TEXTURE); \
node_type_socket_templates(&ntype, name##_inputs, outputs); \
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); \
node_type_init(&ntype, init); \
node_type_storage(&ntype, "Tex", node_free_standard_storage, node_copy_standard_storage); \
node_type_exec(&ntype, NULL, NULL, name##_exec); \
+ ntype.flag |= NODE_PREVIEW; \
\
nodeRegisterType(&ntype); \
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_rotate.c b/source/blender/nodes/texture/nodes/node_texture_rotate.c
index 9985499772e..18024a4d41d 100644
--- a/source/blender/nodes/texture/nodes/node_texture_rotate.c
+++ b/source/blender/nodes/texture/nodes/node_texture_rotate.c
@@ -95,7 +95,7 @@ void register_node_type_tex_rotate(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_scale.c b/source/blender/nodes/texture/nodes/node_texture_scale.c
index d23b1b4d037..d570c73a67b 100644
--- a/source/blender/nodes/texture/nodes/node_texture_scale.c
+++ b/source/blender/nodes/texture/nodes/node_texture_scale.c
@@ -68,7 +68,7 @@ void register_node_type_tex_scale(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_SCALE, "Scale", NODE_CLASS_DISTORT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_texture.c b/source/blender/nodes/texture/nodes/node_texture_texture.c
index 59e2e9be581..083ae67ccb6 100644
--- a/source/blender/nodes/texture/nodes/node_texture_texture.c
+++ b/source/blender/nodes/texture/nodes/node_texture_texture.c
@@ -94,9 +94,10 @@ void register_node_type_tex_texture(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_translate.c b/source/blender/nodes/texture/nodes/node_texture_translate.c
index 2eef3132a18..732cd0a89a1 100644
--- a/source/blender/nodes/texture/nodes/node_texture_translate.c
+++ b/source/blender/nodes/texture/nodes/node_texture_translate.c
@@ -64,7 +64,7 @@ void register_node_type_tex_translate(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_valToNor.c b/source/blender/nodes/texture/nodes/node_texture_valToNor.c
index 5ccd44b8bf0..3f0d4fb668e 100644
--- a/source/blender/nodes/texture/nodes/node_texture_valToNor.c
+++ b/source/blender/nodes/texture/nodes/node_texture_valToNor.c
@@ -80,7 +80,7 @@ void register_node_type_tex_valtonor(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_VALTONOR, "Value to Normal", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_VALTONOR, "Value to Normal", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
index 2446ef05e0c..844a4188663 100644
--- a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
+++ b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
@@ -63,7 +63,7 @@ void register_node_type_tex_valtorgb(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, valtorgb_in, valtorgb_out);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, valtorgb_init);
@@ -105,7 +105,7 @@ void register_node_type_tex_rgbtobw(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, rgbtobw_in, rgbtobw_out);
node_type_exec(&ntype, NULL, NULL, rgbtobw_exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_viewer.c b/source/blender/nodes/texture/nodes/node_texture_viewer.c
index c96ff2062cb..ea69de9a1d6 100644
--- a/source/blender/nodes/texture/nodes/node_texture_viewer.c
+++ b/source/blender/nodes/texture/nodes/node_texture_viewer.c
@@ -29,14 +29,11 @@ static bNodeSocketTemplate inputs[] = {
{SOCK_RGBA, N_("Color"), 1.0f, 0.0f, 0.0f, 1.0f},
{-1, ""},
};
-static bNodeSocketTemplate outputs[] = {
- {-1, ""},
-};
static void exec(void *data,
int UNUSED(thread),
bNode *UNUSED(node),
- bNodeExecData *execdata,
+ bNodeExecData *UNUSED(execdata),
bNodeStack **in,
bNodeStack **UNUSED(out))
{
@@ -48,7 +45,6 @@ static void exec(void *data,
params_from_cdata(&params, cdata);
tex_input_rgba(col, in[0], &params, cdata->thread);
- tex_do_preview(execdata->preview, params.previewco, col, cdata->do_manage);
}
}
@@ -56,12 +52,12 @@ void register_node_type_tex_viewer(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- node_type_socket_templates(&ntype, inputs, outputs);
+ tex_node_type_base(&ntype, TEX_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT);
+ node_type_socket_templates(&ntype, inputs, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
- /* Do not allow muting viewer node. */
- node_type_internal_links(&ntype, NULL);
+ ntype.no_muting = true;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 43a73363c98..b6604846bb8 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -55,7 +55,13 @@ int BPY_is_pyconstraint(struct Text *text);
typedef void *BPy_ThreadStatePtr;
+/**
+ * Analogue of #PyEval_SaveThread()
+ */
BPy_ThreadStatePtr BPY_thread_save(void);
+/**
+ * Analogue of #PyEval_RestoreThread()
+ */
void BPY_thread_restore(BPy_ThreadStatePtr tstate);
/* our own wrappers to Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS */
@@ -69,12 +75,26 @@ void BPY_thread_restore(BPy_ThreadStatePtr tstate);
(void)0
void BPY_text_free_code(struct Text *text);
+/**
+ * Needed so the #Main pointer in `bpy.data` doesn't become out of date.
+ */
void BPY_modules_update(void);
void BPY_modules_load_user(struct bContext *C);
-void BPY_app_handlers_reset(const short do_all);
+void BPY_app_handlers_reset(short do_all);
+/**
+ * Update function, it gets rid of py-drivers global dictionary, forcing
+ * BPY_driver_exec to recreate it. This function is used to force
+ * reloading the Blender text module "pydrivers.py", if available, so
+ * updates in it reach py-driver evaluation.
+ */
void BPY_driver_reset(void);
+
+/**
+ * This evaluates Python driver expressions, `driver_orig->expression`
+ * is a Python expression that should evaluate to a float number, which is returned.
+ */
float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
struct ChannelDriver *driver,
struct ChannelDriver *driver_orig,
@@ -86,6 +106,9 @@ int BPY_context_member_get(struct bContext *C,
const char *member,
struct bContextDataResult *result);
void BPY_context_set(struct bContext *C);
+/**
+ * Use for updating while a python script runs - in case of file load.
+ */
void BPY_context_update(struct bContext *C);
#define BPY_context_dict_clear_members(C, ...) \
@@ -93,6 +116,16 @@ void BPY_context_update(struct bContext *C);
(C)->data.py_context_orig, \
((const char *[]){__VA_ARGS__}), \
VA_NARGS_COUNT(__VA_ARGS__))
+/**
+ * Use for `CTX_*_set(..)` functions need to set values which are later read back as expected.
+ * In this case we don't want the Python context to override the values as it causes problems
+ * see T66256.
+ *
+ * \param dict_p: A pointer to #bContext.data.py_context so we can assign a new value.
+ * \param dict_orig: The value of #bContext.data.py_context_orig to check if we need to copy.
+ *
+ * \note Typically accessed via #BPY_context_dict_clear_members macro.
+ */
void BPY_context_dict_clear_members_array(void **dict_p,
void *dict_orig,
const char *context_members[],
@@ -100,6 +133,9 @@ void BPY_context_dict_clear_members_array(void **dict_p,
void BPY_id_release(struct ID *id);
+/**
+ * Avoids duplicating keyword list.
+ */
bool BPY_string_is_keyword(const char *str);
/* bpy_rna_callback.c */
diff --git a/source/blender/python/BPY_extern_python.h b/source/blender/python/BPY_extern_python.h
index c321fd93379..56662ffc040 100644
--- a/source/blender/python/BPY_extern_python.h
+++ b/source/blender/python/BPY_extern_python.h
@@ -32,6 +32,8 @@ extern "C" {
#include <stdio.h>
/* bpy_interface.c */
+
+/** Call #BPY_context_set first. */
void BPY_python_start(struct bContext *C, int argc, const char **argv);
void BPY_python_end(void);
void BPY_python_reset(struct bContext *C);
diff --git a/source/blender/python/BPY_extern_run.h b/source/blender/python/BPY_extern_run.h
index b65b5d61b9d..9088a4b89c0 100644
--- a/source/blender/python/BPY_extern_run.h
+++ b/source/blender/python/BPY_extern_run.h
@@ -16,6 +16,20 @@
/** \file
* \ingroup python
+ *
+ * \subsection common_args Common Arguments
+ *
+ * - `C` the #bContext (never NULL).
+ *
+ * - `imports`: This is simply supported for convenience since imports can make constructing
+ * strings more cumbersome as otherwise small expressions become multi-line code-blocks.
+ * Optional (ignored when NULL), otherwise this is a NULL terminated array of module names.
+ *
+ Failure to import any modules prevents any further execution.
+ *
+ * - `err_info` #BPy_RunErrInfo is passed to some functions so errors can be forwarded to the UI.
+ * Option (when NULL errors are printed to the `stdout` and cleared).
+ * However this should be used in any case the error would be useful to show to the user.
*/
#pragma once
@@ -26,22 +40,83 @@ extern "C" {
#include "BLI_sys_types.h"
+#include "BLI_compiler_attrs.h"
+
struct ReportList;
struct Text;
struct bContext;
/* bpy_interface_run.c */
-bool BPY_run_filepath(struct bContext *C, const char *filepath, struct ReportList *reports);
-bool BPY_run_text(struct bContext *C,
- struct Text *text,
- struct ReportList *reports,
- const bool do_jump);
-
-/* Use the 'eval' for simple single-line expressions,
- * otherwise 'exec' for full multi-line scripts. */
+
+/* -------------------------------------------------------------------- */
+/** \name Run File/Text as a Script
+ *
+ * \note #BPY_run_filepath and #BPY_run_filepath have almost identical behavior
+ * one operates on a file-path, the other on a blender text-block.
+ * \{ */
+
+/**
+ * Execute `filepath` as a Python script.
+ *
+ * Wrapper for `PyRun_File` (similar to calling python with a script argument).
+ * Used for the `--python` command line argument.
+ *
+ * \param C: The context (never NULL).
+ * \param filepath: The file path to execute.
+ * \param reports: Failure to execute the script will report the exception here (may be NULL).
+ * \return true on success, otherwise false with an error reported to `reports`.
+ *
+ * \note Python scripts could consider `bpy.utils.execfile`, which has the advantage of returning
+ * the object as a module for data access & caching `pyc` file for faster re-execution.
+ */
+bool BPY_run_filepath(struct bContext *C, const char *filepath, struct ReportList *reports)
+ ATTR_NONNULL(1, 2);
+/**
+ * Execute a Blender `text` block as a Python script.
+ *
+ * Wrapper for `Py_CompileStringObject` & `PyEval_EvalCode`.
+ * Used for the `--python-text` command line argument.
+ *
+ * \param C: The context (never NULL).
+ * \param text: The text-block to execute.
+ * \param reports: Failure to execute the script will report the exception here (may be NULL).
+ * \param do_jump: When true, any error moves the cursor to the location of that error.
+ * Useful for executing scripts interactively from the text editor.
+ * \return true on success, otherwise false with an error reported to `reports`.
+ *
+ * \note The `__file__` is constructed by joining the blend file-path to the name of the text.
+ * This is done so error messages give useful output however there are rare cases causes problems
+ * with introspection tools which attempt to load `__file__`.
+ */
+bool BPY_run_text(struct bContext *C, struct Text *text, struct ReportList *reports, bool do_jump)
+ ATTR_NONNULL(1, 2);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Run a String as a Script
+ *
+ * - Use 'eval' for simple single-line expressions.
+ * - Use 'exec' for full multi-line scripts.
+ * \{ */
+
+/**
+ * Run an entire script, matches: `exec(compile(..., "exec"))`
+ */
bool BPY_run_string_exec(struct bContext *C, const char *imports[], const char *expr);
+/**
+ * Run an expression, matches: `exec(compile(..., "eval"))`.
+ */
bool BPY_run_string_eval(struct bContext *C, const char *imports[], const char *expr);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Run a String as a Script & Return the Result
+ *
+ * Convenience functions for executing a script and returning the result as an expected type.
+ * \{ */
+
/**
* \note When this struct is passed in as NULL,
* print errors to the `stdout` and clear.
@@ -58,28 +133,63 @@ struct BPy_RunErrInfo {
char **r_string;
};
-/* Run, evaluating to fixed type result. */
+/**
+ * Evaluate `expr` as a number (double).
+ *
+ * \param C: See \ref common_args.
+ * \param imports: See \ref common_args.
+ * \param expr: The expression to evaluate.
+ * \param err_info: See \ref common_args.
+ * \param r_value: The resulting value.
+ * \return Success.
+ */
bool BPY_run_string_as_number(struct bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
- double *r_value);
+ double *r_value) ATTR_NONNULL(1, 3, 5);
+/**
+ * Evaluate `expr` as an integer or pointer.
+ *
+ * \note Support both int and pointers.
+ *
+ * \param C: See \ref common_args.
+ * \param imports: See \ref common_args.
+ * \param expr: The expression to evaluate.
+ * \param err_info: See \ref common_args.
+ * \param r_value: The resulting value.
+ * \return Success.
+ */
bool BPY_run_string_as_intptr(struct bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
- intptr_t *r_value);
+ intptr_t *r_value) ATTR_NONNULL(1, 3, 5);
+/**
+ * Evaluate `expr` as a string.
+ *
+ * \param C: See \ref common_args.
+ * \param imports: See \ref common_args.
+ * \param expr: The expression to evaluate.
+ * \param err_info: See \ref common_args.
+ * \param r_value: The resulting value.
+ * \return Success.
+ */
bool BPY_run_string_as_string_and_size(struct bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
char **r_value,
- size_t *r_value_size);
+ size_t *r_value_size) ATTR_NONNULL(1, 3, 5, 6);
+
+/** See #BPY_run_string_as_string_and_size */
bool BPY_run_string_as_string(struct bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
- char **r_value);
+ char **r_value) ATTR_NONNULL(1, 3, 5);
+
+/** \} */
#ifdef __cplusplus
} /* extern "C" */
diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c
index 24887b24eb6..f1423c20b3b 100644
--- a/source/blender/python/bmesh/bmesh_py_ops_call.c
+++ b/source/blender/python/bmesh/bmesh_py_ops_call.c
@@ -745,9 +745,6 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
return item;
}
-/**
- * This is the __call__ for bmesh.ops.xxx()
- */
PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw)
{
PyObject *ret;
diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.h b/source/blender/python/bmesh/bmesh_py_ops_call.h
index 1c7a35788d2..c567375c568 100644
--- a/source/blender/python/bmesh/bmesh_py_ops_call.h
+++ b/source/blender/python/bmesh/bmesh_py_ops_call.h
@@ -28,4 +28,7 @@ typedef struct {
const char *opname;
} BPy_BMeshOpFunc;
+/**
+ * This is the `__call__` for `bmesh.ops.xxx()`.
+ */
PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw);
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index e5e601e0eb6..38ec242fa49 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -1950,7 +1950,7 @@ static PyObject *bpy_bmface_calc_tangent_edge_diagonal(BPy_BMFace *self)
PyDoc_STRVAR(bpy_bmface_calc_tangent_vert_diagonal_doc,
".. method:: calc_tangent_vert_diagonal()\n"
"\n"
- " Return face tangent based on the two most distent vertices.\n"
+ " Return face tangent based on the two most distant vertices.\n"
"\n"
" :return: a normalized vector.\n"
" :rtype: :class:`mathutils.Vector`\n");
@@ -3349,8 +3349,8 @@ static PyObject *bpy_bmiter_next(BPy_BMIter *self)
return (PyObject *)BPy_BMElem_CreatePyObject(self->bm, ele);
}
-/* Dealloc Functions
- * ================= */
+/* Deallocate Functions
+ * ==================== */
static void bpy_bmesh_dealloc(BPy_BMesh *self)
{
@@ -3464,7 +3464,7 @@ PyDoc_STRVAR(bpy_bmelemseq_doc,
":class:`BMVert`, :class:`BMEdge`, :class:`BMFace`, :class:`BMLoop`.\n"
"\n"
"When accessed via :class:`BMesh.verts`, :class:`BMesh.edges`, :class:`BMesh.faces`\n"
- "there are also functions to create/remomove items.\n");
+ "there are also functions to create/remove items.\n");
PyDoc_STRVAR(bpy_bmiter_doc,
"Internal BMesh type for looping over verts/faces/edges,\n"
"used for iterating over :class:`BMElemSeq` types.\n");
@@ -3954,7 +3954,6 @@ PyObject *BPy_BMIter_CreatePyObject(BMesh *bm)
return (PyObject *)self;
}
-/* this is just a helper func */
PyObject *BPy_BMElem_CreatePyObject(BMesh *bm, BMHeader *ele)
{
switch (ele->htype) {
@@ -4036,11 +4035,6 @@ void bpy_bm_generic_invalidate(BPy_BMGeneric *self)
self->bm = NULL;
}
-/* generic python seq as BMVert/Edge/Face array,
- * return value must be freed with PyMem_FREE(...);
- *
- * The 'bm_r' value is assigned when empty, and used when set.
- */
void *BPy_BMElem_PySeq_As_Array_FAST(BMesh **r_bm,
PyObject *seq_fast,
Py_ssize_t min,
@@ -4233,11 +4227,6 @@ int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype)
((htype & BM_LOOP) && (type == &BPy_BMLoop_Type)));
}
-/**
- * Use for error strings only, not thread safe,
- *
- * \return a string like '(BMVert/BMEdge/BMFace/BMLoop)'
- */
char *BPy_BMElem_StringFromHType_ex(const char htype, char ret[32])
{
/* zero to ensure string is always NULL terminated */
diff --git a/source/blender/python/bmesh/bmesh_py_types.h b/source/blender/python/bmesh/bmesh_py_types.h
index 043c5322735..3786a0552d2 100644
--- a/source/blender/python/bmesh/bmesh_py_types.h
+++ b/source/blender/python/bmesh/bmesh_py_types.h
@@ -141,33 +141,39 @@ PyObject *BPy_BMVert_CreatePyObject(BMesh *bm, BMVert *v);
PyObject *BPy_BMEdge_CreatePyObject(BMesh *bm, BMEdge *e);
PyObject *BPy_BMFace_CreatePyObject(BMesh *bm, BMFace *f);
PyObject *BPy_BMLoop_CreatePyObject(BMesh *bm, BMLoop *l);
-PyObject *BPy_BMElemSeq_CreatePyObject(BMesh *bm, BPy_BMElem *py_ele, const char itype);
+PyObject *BPy_BMElemSeq_CreatePyObject(BMesh *bm, BPy_BMElem *py_ele, char itype);
PyObject *BPy_BMVertSeq_CreatePyObject(BMesh *bm);
PyObject *BPy_BMEdgeSeq_CreatePyObject(BMesh *bm);
PyObject *BPy_BMFaceSeq_CreatePyObject(BMesh *bm);
PyObject *BPy_BMLoopSeq_CreatePyObject(BMesh *bm);
PyObject *BPy_BMIter_CreatePyObject(BMesh *bm);
-/* Just checks type and creates v/e/f/l. */
+/** Just checks type and creates vert/edge/face/loop. */
PyObject *BPy_BMElem_CreatePyObject(BMesh *bm, BMHeader *ele);
+/**
+ * Generic python seq as BMVert/Edge/Face array,
+ * return value must be freed with PyMem_FREE(...);
+ *
+ * The 'bm_r' value is assigned when empty, and used when set.
+ */
void *BPy_BMElem_PySeq_As_Array_FAST(BMesh **r_bm,
PyObject *seq_fast,
Py_ssize_t min,
Py_ssize_t max,
Py_ssize_t *r_size,
- const char htype,
- const bool do_unique_check,
- const bool do_bm_check,
+ char htype,
+ bool do_unique_check,
+ bool do_bm_check,
const char *error_prefix);
void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm,
PyObject *seq,
Py_ssize_t min,
Py_ssize_t max,
Py_ssize_t *r_size,
- const char htype,
- const bool do_unique_check,
- const bool do_bm_check,
+ char htype,
+ bool do_unique_check,
+ bool do_bm_check,
const char *error_prefix);
PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_len);
@@ -176,9 +182,14 @@ PyObject *BPy_BMEdge_Array_As_Tuple(BMesh *bm, BMEdge **elem, Py_ssize_t elem_le
PyObject *BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_len);
PyObject *BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop **elem, Py_ssize_t elem_len);
-int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype);
-char *BPy_BMElem_StringFromHType_ex(const char htype, char ret[32]);
-char *BPy_BMElem_StringFromHType(const char htype);
+int BPy_BMElem_CheckHType(PyTypeObject *type, char htype);
+/**
+ * Use for error strings only, not thread safe,
+ *
+ * \return a string like '(BMVert/BMEdge/BMFace/BMLoop)'
+ */
+char *BPy_BMElem_StringFromHType_ex(char htype, char ret[32]);
+char *BPy_BMElem_StringFromHType(char htype);
// void bpy_bm_generic_invalidate(BPy_BMGeneric *self);
int bpy_bm_generic_valid_check(BPy_BMGeneric *self);
@@ -198,7 +209,9 @@ int bpy_bm_generic_valid_check_source(BMesh *bm_source,
} \
(void)0
-/* macros like BPY_BM_CHECK_OBJ/BPY_BM_CHECK_INT that ensure we're from the right BMesh */
+/**
+ * Macros like `BPY_BM_CHECK_OBJ/BPY_BM_CHECK_INT` that ensure we're from the right #BMesh.
+ */
#define BPY_BM_CHECK_SOURCE_OBJ(bm, errmsg, ...) \
{ \
void *_args[] = {__VA_ARGS__}; \
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c
index 0aa92158524..1e1ba5edb0f 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c
@@ -1104,13 +1104,6 @@ static void *bpy_bmlayeritem_ptr_get(BPy_BMElem *py_ele, BPy_BMLayerItem *py_lay
return value;
}
-/**
- *\brief BMElem.__getitem__()
- *
- * assume all error checks are done, eg:
- *
- * uv = vert[uv_layer]
- */
PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
{
void *value = bpy_bmlayeritem_ptr_get(py_ele, py_layer);
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.h b/source/blender/python/bmesh/bmesh_py_types_customdata.h
index 8552942f73a..d81e149cac1 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.h
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.h
@@ -23,7 +23,8 @@
#pragma once
-/* all use BPy_BMLayerAccess struct */
+/* All use #BPy_BMLayerAccess struct. */
+
extern PyTypeObject BPy_BMLayerAccessVert_Type;
extern PyTypeObject BPy_BMLayerAccessEdge_Type;
extern PyTypeObject BPy_BMLayerAccessFace_Type;
@@ -36,14 +37,14 @@ extern PyTypeObject BPy_BMLayerItem_Type;
#define BPy_BMLayerCollection_Check(v) (Py_TYPE(v) == &BPy_BMLayerCollection_Type)
#define BPy_BMLayerItem_Check(v) (Py_TYPE(v) == &BPy_BMLayerItem_Type)
-/* all layers for vert/edge/face/loop */
+/** All layers for vert/edge/face/loop. */
typedef struct BPy_BMLayerAccess {
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
char htype;
} BPy_BMLayerAccess;
-/* access different layer types deform/uv/vertexcolor */
+/** Access different layer types deform/uv/vertex-color. */
typedef struct BPy_BMLayerCollection {
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
@@ -51,7 +52,7 @@ typedef struct BPy_BMLayerCollection {
int type; /* customdata type - CD_XXX */
} BPy_BMLayerCollection;
-/* access a specific layer directly */
+/** Access a specific layer directly. */
typedef struct BPy_BMLayerItem {
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
@@ -60,12 +61,16 @@ typedef struct BPy_BMLayerItem {
int index; /* index of this layer type */
} BPy_BMLayerItem;
-PyObject *BPy_BMLayerAccess_CreatePyObject(BMesh *bm, const char htype);
-PyObject *BPy_BMLayerCollection_CreatePyObject(BMesh *bm, const char htype, int type);
-PyObject *BPy_BMLayerItem_CreatePyObject(BMesh *bm, const char htype, int type, int index);
+PyObject *BPy_BMLayerAccess_CreatePyObject(BMesh *bm, char htype);
+PyObject *BPy_BMLayerCollection_CreatePyObject(BMesh *bm, char htype, int type);
+PyObject *BPy_BMLayerItem_CreatePyObject(BMesh *bm, char htype, int type, int index);
void BPy_BM_init_types_customdata(void);
-/* __getitem__ / __setitem__ */
+/**
+ *\brief BMElem.__getitem__() / __setitem__()
+ *
+ * Assume all error checks are done, eg: `uv = vert[uv_layer]`
+ */
PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer);
int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObject *value);
diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
index d0c745e6a1d..dffc0814d9d 100644
--- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
@@ -683,7 +683,6 @@ PyObject *BPy_BMDeformVert_CreatePyObject(struct MDeformVert *dvert)
/* --- End Mesh Deform Vert --- */
-/* call to init all types */
void BPy_BM_init_types_meshdata(void)
{
bm_init_types_bmloopuv();
diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.h b/source/blender/python/bmesh/bmesh_py_types_meshdata.h
index 426bfcef6a0..b52bf6889bc 100644
--- a/source/blender/python/bmesh/bmesh_py_types_meshdata.h
+++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.h
@@ -50,4 +50,5 @@ PyObject *BPy_BMLoopColor_CreatePyObject(struct MLoopCol *mloopcol);
int BPy_BMDeformVert_AssignPyObject(struct MDeformVert *dvert, PyObject *value);
PyObject *BPy_BMDeformVert_CreatePyObject(struct MDeformVert *dvert);
+/* call to init all types */
void BPy_BM_init_types_meshdata(void);
diff --git a/source/blender/python/bmesh/bmesh_py_types_select.c b/source/blender/python/bmesh/bmesh_py_types_select.c
index b89822a080c..bc8c6853ff5 100644
--- a/source/blender/python/bmesh/bmesh_py_types_select.c
+++ b/source/blender/python/bmesh/bmesh_py_types_select.c
@@ -411,9 +411,6 @@ void BPy_BM_init_types_select(void)
/* utility function */
-/**
- * \note doesn't actually check selection.
- */
int BPy_BMEditSel_Assign(BPy_BMesh *self, PyObject *value)
{
BMesh *bm;
diff --git a/source/blender/python/bmesh/bmesh_py_types_select.h b/source/blender/python/bmesh/bmesh_py_types_select.h
index 34ca162dd09..6b8609e36a6 100644
--- a/source/blender/python/bmesh/bmesh_py_types_select.h
+++ b/source/blender/python/bmesh/bmesh_py_types_select.h
@@ -46,4 +46,7 @@ void BPy_BM_init_types_select(void);
PyObject *BPy_BMEditSel_CreatePyObject(BMesh *bm);
PyObject *BPy_BMEditSelIter_CreatePyObject(BMesh *bm);
+/**
+ * \note doesn't actually check selection.
+ */
int BPy_BMEditSel_Assign(struct BPy_BMesh *self, PyObject *value);
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index e416727fa70..3f01ff86f49 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -666,13 +666,6 @@ static Buffer *BGL_MakeBuffer_FromData(
return buffer;
}
-/**
- * Create a buffer object
- *
- * \param dimensions: An array of ndimensions integers representing the size of each dimension.
- * \param initbuffer: When not NULL holds a contiguous buffer
- * with the correct format from which the buffer will be initialized
- */
Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuffer)
{
Buffer *buffer;
diff --git a/source/blender/python/generic/bgl.h b/source/blender/python/generic/bgl.h
index 4e59eab46ce..479c69b5de2 100644
--- a/source/blender/python/generic/bgl.h
+++ b/source/blender/python/generic/bgl.h
@@ -22,6 +22,13 @@
PyObject *BPyInit_bgl(void);
+/**
+ * Create a buffer object
+ *
+ * \param dimensions: An array of ndimensions integers representing the size of each dimension.
+ * \param initbuffer: When not NULL holds a contiguous buffer
+ * with the correct format from which the buffer will be initialized
+ */
struct _Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuffer);
int BGL_typeSize(int type);
@@ -50,5 +57,5 @@ typedef struct _Buffer {
} buf;
} Buffer;
-/** The type object */
+/** The type object. */
extern PyTypeObject BGL_bufferType;
diff --git a/source/blender/python/generic/bl_math_py_api.c b/source/blender/python/generic/bl_math_py_api.c
index f17aaa4ca5d..2211cc931da 100644
--- a/source/blender/python/generic/bl_math_py_api.c
+++ b/source/blender/python/generic/bl_math_py_api.c
@@ -77,14 +77,14 @@ static PyObject *py_bl_math_clamp(PyObject *UNUSED(self), PyObject *args)
}
PyDoc_STRVAR(py_bl_math_lerp_doc,
- ".. function:: lerp(from, to, factor)\n"
+ ".. function:: lerp(from_value, to_value, factor)\n"
"\n"
" Linearly interpolate between two float values based on factor.\n"
"\n"
- " :arg from: The value to return when factor is 0.\n"
- " :type from: float\n"
- " :arg to: The value to return when factor is 1.\n"
- " :type to: float\n"
+ " :arg from_value: The value to return when factor is 0.\n"
+ " :type from_value: float\n"
+ " :arg to_value: The value to return when factor is 1.\n"
+ " :type to_value: float\n"
" :arg factor: The interpolation value, normally in [0.0, 1.0].\n"
" :type factor: float\n"
" :return: The interpolated value.\n"
@@ -99,21 +99,21 @@ static PyObject *py_bl_math_lerp(PyObject *UNUSED(self), PyObject *args)
return PyFloat_FromDouble(a * (1.0 - x) + b * x);
}
-PyDoc_STRVAR(
- py_bl_math_smoothstep_doc,
- ".. function:: smoothstep(from, to, value)\n"
- "\n"
- " Performs smooth interpolation between 0 and 1 as value changes between from and to.\n"
- " Outside the range the function returns the same value as the nearest edge.\n"
- "\n"
- " :arg from: The edge value where the result is 0.\n"
- " :type from: float\n"
- " :arg to: The edge value where the result is 1.\n"
- " :type to: float\n"
- " :arg factor: The interpolation value.\n"
- " :type factor: float\n"
- " :return: The interpolated value in [0.0, 1.0].\n"
- " :rtype: float\n");
+PyDoc_STRVAR(py_bl_math_smoothstep_doc,
+ ".. function:: smoothstep(from_value, to_value, value)\n"
+ "\n"
+ " Performs smooth interpolation between 0 and 1 as value changes between from and "
+ "to values.\n"
+ " Outside the range the function returns the same value as the nearest edge.\n"
+ "\n"
+ " :arg from_value: The edge value where the result is 0.\n"
+ " :type from_value: float\n"
+ " :arg to_value: The edge value where the result is 1.\n"
+ " :type to_value: float\n"
+ " :arg factor: The interpolation value.\n"
+ " :type factor: float\n"
+ " :return: The interpolated value in [0.0, 1.0].\n"
+ " :rtype: float\n");
static PyObject *py_bl_math_smoothstep(PyObject *UNUSED(self), PyObject *args)
{
double a, b, x;
diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c
index 9e725730d40..a49c943df94 100644
--- a/source/blender/python/generic/blf_py_api.c
+++ b/source/blender/python/generic/blf_py_api.c
@@ -70,14 +70,15 @@ PyDoc_STRVAR(py_blf_size_doc,
"font use 0.\n"
" :type fontid: int\n"
" :arg size: Point size of the font.\n"
- " :type size: int\n"
+ " :type size: float\n"
" :arg dpi: dots per inch value to use for drawing.\n"
" :type dpi: int\n");
static PyObject *py_blf_size(PyObject *UNUSED(self), PyObject *args)
{
- int fontid, size, dpi;
+ int fontid, dpi;
+ float size;
- if (!PyArg_ParseTuple(args, "iii:blf.size", &fontid, &size, &dpi)) {
+ if (!PyArg_ParseTuple(args, "ifi:blf.size", &fontid, &size, &dpi)) {
return NULL;
}
diff --git a/source/blender/python/generic/bpy_threads.c b/source/blender/python/generic/bpy_threads.c
index 8aa8c5c5d92..41e2fb4adf2 100644
--- a/source/blender/python/generic/bpy_threads.c
+++ b/source/blender/python/generic/bpy_threads.c
@@ -26,7 +26,6 @@
#include "../BPY_extern.h"
#include "BLI_utildefines.h"
-/* analogue of PyEval_SaveThread() */
BPy_ThreadStatePtr BPY_thread_save(void)
{
/* Use `_PyThreadState_UncheckedGet()` instead of `PyThreadState_Get()`, to avoid a fatal error
@@ -40,7 +39,6 @@ BPy_ThreadStatePtr BPY_thread_save(void)
return NULL;
}
-/* analogue of PyEval_RestoreThread() */
void BPY_thread_restore(BPy_ThreadStatePtr tstate)
{
if (tstate) {
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 8dc0d2fb857..0a870102b6f 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -686,12 +686,6 @@ static IDProperty *idp_from_PyObject(PyObject *name_obj, PyObject *ob)
/** \name Mapping Get/Set (Internal Access)
* \{ */
-/**
- * \note group can be a pointer array or a group.
- * assume we already checked key is a string.
- *
- * \return success.
- */
bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
{
IDProperty *prop = idp_from_PyObject(name_obj, ob);
@@ -779,7 +773,6 @@ static PyObject *BPy_IDGroup_iter(BPy_IDProperty *self)
return BPy_IDGroup_ViewKeys_CreatePyObject(self);
}
-/* for simple, non nested types this is the same as BPy_IDGroup_WrapData */
PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
{
switch (prop->type) {
@@ -1975,6 +1968,8 @@ static PyBufferProcs BPy_IDArray_Buffer = {
(releasebufferproc)BPy_IDArray_releasebuffer,
};
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name ID Array Type
* \{ */
diff --git a/source/blender/python/generic/idprop_py_api.h b/source/blender/python/generic/idprop_py_api.h
index f53c45b07c2..e4addcecc10 100644
--- a/source/blender/python/generic/idprop_py_api.h
+++ b/source/blender/python/generic/idprop_py_api.h
@@ -95,8 +95,17 @@ PyObject *BPy_Wrap_GetItems_View_WithID(struct ID *id, struct IDProperty *prop);
int BPy_Wrap_SetMapItem(struct IDProperty *prop, PyObject *key, PyObject *val);
+/**
+ * For simple, non nested types this is the same as #BPy_IDGroup_WrapData.
+ */
PyObject *BPy_IDGroup_MapDataToPy(struct IDProperty *prop);
PyObject *BPy_IDGroup_WrapData(struct ID *id, struct IDProperty *prop, struct IDProperty *parent);
+/**
+ * \note group can be a pointer array or a group.
+ * assume we already checked key is a string.
+ *
+ * \return success.
+ */
bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *key, struct IDProperty *group, PyObject *ob);
void IDProp_Init_Types(void);
diff --git a/source/blender/python/generic/idprop_py_ui_api.c b/source/blender/python/generic/idprop_py_ui_api.c
index 7827bd48dfe..37ba27f7315 100644
--- a/source/blender/python/generic/idprop_py_ui_api.c
+++ b/source/blender/python/generic/idprop_py_ui_api.c
@@ -622,7 +622,9 @@ static PyObject *BPy_IDPropertyUIManager_update_from(BPy_IDPropertyUIManager *se
IDP_ui_data_free(property);
}
- property->ui_data = IDP_ui_data_copy(ui_manager_src->property);
+ if (ui_manager_src->property && ui_manager_src->property->ui_data) {
+ property->ui_data = IDP_ui_data_copy(ui_manager_src->property);
+ }
Py_RETURN_NONE;
}
diff --git a/source/blender/python/generic/py_capi_rna.c b/source/blender/python/generic/py_capi_rna.c
index 235b136ca74..a6a0d820d07 100644
--- a/source/blender/python/generic/py_capi_rna.c
+++ b/source/blender/python/generic/py_capi_rna.c
@@ -41,10 +41,6 @@
/** \name Enum Utilities
* \{ */
-/**
- * Convert all items into a single comma separated string.
- * Use for creating useful error messages.
- */
char *pyrna_enum_repr(const EnumPropertyItem *item)
{
DynStr *dynstr = BLI_dynstr_new();
@@ -69,9 +65,6 @@ char *pyrna_enum_repr(const EnumPropertyItem *item)
/** \name Enum Conversion Utilities
* \{ */
-/**
- * Same as #RNA_enum_value_from_id, but raises an exception.
- */
int pyrna_enum_value_from_id(const EnumPropertyItem *item,
const char *identifier,
int *r_value,
@@ -88,14 +81,6 @@ int pyrna_enum_value_from_id(const EnumPropertyItem *item,
return 0;
}
-/**
- * Takes a set of strings and map it to and array of booleans.
- *
- * Useful when the values aren't flags.
- *
- * \param type_convert_sign: Maps signed to unsigned range,
- * needed when we want to use the full range of a signed short/char.
- */
BLI_bitmap *pyrna_enum_bitmap_from_set(const EnumPropertyItem *items,
PyObject *value,
int type_size,
@@ -159,9 +144,6 @@ error:
return NULL;
}
-/**
- * 'value' _must_ be a set type, error check before calling.
- */
int pyrna_enum_bitfield_from_set(const EnumPropertyItem *items,
PyObject *value,
int *r_value,
@@ -223,9 +205,6 @@ PyObject *pyrna_enum_bitfield_as_set(const EnumPropertyItem *items, int value)
/** \name Argument Parsing Helpers
* \{ */
-/**
- * Use with #PyArg_ParseTuple's `O&` formatting.
- */
int pyrna_enum_value_parse_string(PyObject *o, void *p)
{
const char *identifier = PyUnicode_AsUTF8(o);
@@ -244,9 +223,6 @@ int pyrna_enum_value_parse_string(PyObject *o, void *p)
return 1;
}
-/**
- * Use with #PyArg_ParseTuple's `O&` formatting.
- */
int pyrna_enum_bitfield_parse_set(PyObject *o, void *p)
{
if (!PySet_Check(o)) {
diff --git a/source/blender/python/generic/py_capi_rna.h b/source/blender/python/generic/py_capi_rna.h
index 326ca777a4b..9733cb043ea 100644
--- a/source/blender/python/generic/py_capi_rna.h
+++ b/source/blender/python/generic/py_capi_rna.h
@@ -25,13 +25,28 @@
struct EnumPropertyItem;
+/**
+ * Convert all items into a single comma separated string.
+ * Use for creating useful error messages.
+ */
char *pyrna_enum_repr(const struct EnumPropertyItem *item);
+/**
+ * Same as #RNA_enum_value_from_id, but raises an exception.
+ */
int pyrna_enum_value_from_id(const struct EnumPropertyItem *item,
const char *identifier,
int *value,
const char *error_prefix);
+/**
+ * Takes a set of strings and map it to and array of booleans.
+ *
+ * Useful when the values aren't flags.
+ *
+ * \param type_convert_sign: Maps signed to unsigned range,
+ * needed when we want to use the full range of a signed short/char.
+ */
unsigned int *pyrna_enum_bitmap_from_set(const struct EnumPropertyItem *items,
PyObject *value,
int type_size,
@@ -39,6 +54,9 @@ unsigned int *pyrna_enum_bitmap_from_set(const struct EnumPropertyItem *items,
int bitmap_size,
const char *error_prefix);
+/**
+ * 'value' _must_ be a set type, error check before calling.
+ */
int pyrna_enum_bitfield_from_set(const struct EnumPropertyItem *items,
PyObject *value,
int *r_value,
@@ -62,5 +80,11 @@ struct BPy_EnumProperty_Parse {
int value;
bool is_set;
};
+/**
+ * Use with #PyArg_ParseTuple's `O&` formatting.
+ */
int pyrna_enum_value_parse_string(PyObject *o, void *p);
+/**
+ * Use with #PyArg_ParseTuple's `O&` formatting.
+ */
int pyrna_enum_bitfield_parse_set(PyObject *o, void *p);
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 9dac5a4f21f..acb6d76f30b 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -470,10 +470,6 @@ PyObject *PyC_Tuple_PackArray_Multi_Bool(const bool *array, const int dims[], co
/** \name Tuple/List Filling
* \{ */
-/**
- * Caller needs to ensure tuple is uninitialized.
- * Handy for filling a tuple with None for eg.
- */
void PyC_Tuple_Fill(PyObject *tuple, PyObject *value)
{
const uint tot = PyTuple_GET_SIZE(tuple);
@@ -502,11 +498,6 @@ void PyC_List_Fill(PyObject *list, PyObject *value)
/** \name Bool/Enum Argument Parsing
* \{ */
-/**
- * Use with PyArg_ParseTuple's "O&" formatting.
- *
- * \see #PyC_Long_AsBool for a similar function to use outside of argument parsing.
- */
int PyC_ParseBool(PyObject *o, void *p)
{
bool *bool_p = p;
@@ -520,9 +511,6 @@ int PyC_ParseBool(PyObject *o, void *p)
return 1;
}
-/**
- * Use with PyArg_ParseTuple's "O&" formatting.
- */
int PyC_ParseStringEnum(PyObject *o, void *p)
{
struct PyC_StringEnum *e = p;
@@ -598,10 +586,6 @@ void PyC_ObSpit(const char *name, PyObject *var)
}
}
-/**
- * A version of #PyC_ObSpit that writes into a string (and doesn't take a name argument).
- * Use for logging.
- */
void PyC_ObSpitStr(char *result, size_t result_len, PyObject *var)
{
/* No name, creator of string can manage that. */
@@ -789,13 +773,6 @@ PyObject *PyC_FrozenSetFromStrings(const char **strings)
/** \name Exception Utilities
* \{ */
-/**
- * Similar to #PyErr_Format(),
- *
- * Implementation - we can't actually prepend the existing exception,
- * because it could have _any_ arguments given to it, so instead we get its
- * `__str__` output and raise our own exception including it.
- */
PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...)
{
PyObject *error_value_prefix;
@@ -835,10 +812,6 @@ PyObject *PyC_Err_SetString_Prefix(PyObject *exception_type_prefix, const char *
return PyC_Err_Format_Prefix(exception_type_prefix, "%s", str);
}
-/**
- * Use for Python callbacks run directly from C,
- * when we can't use normal methods of raising exceptions.
- */
void PyC_Err_PrintWithFunc(PyObject *py_func)
{
/* since we return to C code we can't leave the error */
@@ -1014,7 +987,6 @@ PyObject *PyC_ExceptionBuffer_Simple(void)
* In some cases we need to coerce strings, avoid doing this inline.
* \{ */
-/* string conversion, escape non-unicode chars, coerce must be set to NULL */
const char *PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObject **coerce)
{
const char *result;
@@ -1093,18 +1065,6 @@ PyObject *PyC_UnicodeFromByte(const char *str)
/** \name Name Space Creation/Manipulation
* \{ */
-/*****************************************************************************
- * Description: This function creates a new Python dictionary object.
- * NOTE: dict is owned by sys.modules["__main__"] module, reference is borrowed
- * NOTE: important we use the dict from __main__, this is what python expects
- * for 'pickle' to work as well as strings like this...
- * >> foo = 10
- * >> print(__import__("__main__").foo)
- *
- * NOTE: this overwrites __main__ which gives problems with nested calls.
- * be sure to run PyC_MainModule_Backup & PyC_MainModule_Restore if there is
- * any chance that python is in the call stack.
- ****************************************************************************/
PyObject *PyC_DefaultNameSpace(const char *filename)
{
PyObject *modules = PyImport_GetModuleDict();
@@ -1143,7 +1103,6 @@ bool PyC_NameSpace_ImportArray(PyObject *py_dict, const char *imports[])
return true;
}
-/* restore MUST be called after this */
void PyC_MainModule_Backup(PyObject **r_main_mod)
{
PyObject *modules = PyImport_GetModuleDict();
@@ -1468,11 +1427,6 @@ PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag)
/** \name Run String (Evaluate to Primitive Types)
* \{ */
-/**
- * \return success
- *
- * \note it is caller's responsibility to acquire & release GIL!
- */
bool PyC_RunString_AsNumber(const char *imports[],
const char *expr,
const char *filename,
@@ -1648,12 +1602,12 @@ bool PyC_RunString_AsString(const char *imports[],
# pragma GCC diagnostic ignored "-Wtype-limits"
#endif
-/**
- * Don't use `bool` return type, so -1 can be used as an error value.
- */
int PyC_Long_AsBool(PyObject *value)
{
const int test = _PyLong_AsInt(value);
+ if (UNLIKELY(test == -1 && PyErr_Occurred())) {
+ return -1;
+ }
if (UNLIKELY((uint)test > 1)) {
PyErr_SetString(PyExc_TypeError, "Python number not a bool (0/1)");
return -1;
@@ -1664,6 +1618,9 @@ int PyC_Long_AsBool(PyObject *value)
int8_t PyC_Long_AsI8(PyObject *value)
{
const int test = _PyLong_AsInt(value);
+ if (UNLIKELY(test == -1 && PyErr_Occurred())) {
+ return -1;
+ }
if (UNLIKELY(test < INT8_MIN || test > INT8_MAX)) {
PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C int8");
return -1;
@@ -1674,6 +1631,9 @@ int8_t PyC_Long_AsI8(PyObject *value)
int16_t PyC_Long_AsI16(PyObject *value)
{
const int test = _PyLong_AsInt(value);
+ if (UNLIKELY(test == -1 && PyErr_Occurred())) {
+ return -1;
+ }
if (UNLIKELY(test < INT16_MIN || test > INT16_MAX)) {
PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C int16");
return -1;
@@ -1689,6 +1649,9 @@ int16_t PyC_Long_AsI16(PyObject *value)
uint8_t PyC_Long_AsU8(PyObject *value)
{
const ulong test = PyLong_AsUnsignedLong(value);
+ if (UNLIKELY(test == (ulong)-1 && PyErr_Occurred())) {
+ return (uint8_t)-1;
+ }
if (UNLIKELY(test > UINT8_MAX)) {
PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C uint8");
return (uint8_t)-1;
@@ -1699,6 +1662,9 @@ uint8_t PyC_Long_AsU8(PyObject *value)
uint16_t PyC_Long_AsU16(PyObject *value)
{
const ulong test = PyLong_AsUnsignedLong(value);
+ if (UNLIKELY(test == (ulong)-1 && PyErr_Occurred())) {
+ return (uint16_t)-1;
+ }
if (UNLIKELY(test > UINT16_MAX)) {
PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C uint16");
return (uint16_t)-1;
@@ -1709,6 +1675,9 @@ uint16_t PyC_Long_AsU16(PyObject *value)
uint32_t PyC_Long_AsU32(PyObject *value)
{
const ulong test = PyLong_AsUnsignedLong(value);
+ if (UNLIKELY(test == (ulong)-1 && PyErr_Occurred())) {
+ return (uint32_t)-1;
+ }
if (UNLIKELY(test > UINT32_MAX)) {
PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C uint32");
return (uint32_t)-1;
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index a8695d2330a..f08665d75e7 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -26,6 +26,10 @@
#include "BLI_utildefines_variadic.h"
void PyC_ObSpit(const char *name, PyObject *var);
+/**
+ * A version of #PyC_ObSpit that writes into a string (and doesn't take a name argument).
+ * Use for logging.
+ */
void PyC_ObSpitStr(char *result, size_t result_len, PyObject *var);
void PyC_LineSpit(void);
void PyC_StackSpit(void);
@@ -34,39 +38,50 @@ PyObject *PyC_ExceptionBuffer_Simple(void);
PyObject *PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
PyObject *PyC_FrozenSetFromStrings(const char **strings);
+/**
+ * Similar to #PyErr_Format(),
+ *
+ * Implementation - we can't actually prepend the existing exception,
+ * because it could have _any_ arguments given to it, so instead we get its
+ * `__str__` output and raise our own exception including it.
+ */
PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...);
PyObject *PyC_Err_SetString_Prefix(PyObject *exception_type_prefix, const char *str);
+/**
+ * Use for Python callbacks run directly from C,
+ * when we can't use normal methods of raising exceptions.
+ */
void PyC_Err_PrintWithFunc(PyObject *py_func);
void PyC_FileAndNum(const char **r_filename, int *r_lineno);
void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno); /* checks python is running */
int PyC_AsArray_FAST(void *array,
- const size_t array_item_size,
+ size_t array_item_size,
PyObject *value_fast,
- const Py_ssize_t length,
+ Py_ssize_t length,
const PyTypeObject *type,
const char *error_prefix);
int PyC_AsArray(void *array,
- const size_t array_item_size,
+ size_t array_item_size,
PyObject *value,
- const Py_ssize_t length,
+ Py_ssize_t length,
const PyTypeObject *type,
const char *error_prefix);
int PyC_AsArray_Multi_FAST(void *array,
- const size_t array_item_size,
+ size_t array_item_size,
PyObject *value_fast,
const int *dims,
- const int dims_len,
+ int dims_len,
const PyTypeObject *type,
const char *error_prefix);
int PyC_AsArray_Multi(void *array,
- const size_t array_item_size,
+ size_t array_item_size,
PyObject *value,
const int *dims,
- const int dims_len,
+ int dims_len,
const PyTypeObject *type,
const char *error_prefix);
@@ -87,11 +102,15 @@ PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len);
#define PyC_Tuple_Pack_Bool(...) \
PyC_Tuple_PackArray_Bool(((const bool[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
-PyObject *PyC_Tuple_PackArray_Multi_F32(const float *array, const int dims[], const int dims_len);
-PyObject *PyC_Tuple_PackArray_Multi_F64(const double *array, const int dims[], const int dims_len);
-PyObject *PyC_Tuple_PackArray_Multi_I32(const int *array, const int dims[], const int dims_len);
-PyObject *PyC_Tuple_PackArray_Multi_Bool(const bool *array, const int dims[], const int dims_len);
+PyObject *PyC_Tuple_PackArray_Multi_F32(const float *array, const int dims[], int dims_len);
+PyObject *PyC_Tuple_PackArray_Multi_F64(const double *array, const int dims[], int dims_len);
+PyObject *PyC_Tuple_PackArray_Multi_I32(const int *array, const int dims[], int dims_len);
+PyObject *PyC_Tuple_PackArray_Multi_Bool(const bool *array, const int dims[], int dims_len);
+/**
+ * Caller needs to ensure tuple is uninitialized.
+ * Handy for filling a tuple with None for eg.
+ */
void PyC_Tuple_Fill(PyObject *tuple, PyObject *value);
void PyC_List_Fill(PyObject *list, PyObject *value);
@@ -99,13 +118,39 @@ void PyC_List_Fill(PyObject *list, PyObject *value);
PyObject *PyC_UnicodeFromByte(const char *str);
PyObject *PyC_UnicodeFromByteAndSize(const char *str, Py_ssize_t size);
const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */
+/**
+ * String conversion, escape non-unicode chars
+ * \param coerce: must be set to NULL.
+ */
const char *PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObject **coerce);
-/* name namespace function for bpy */
+/**
+ * Description: This function creates a new Python dictionary object.
+ * NOTE: dict is owned by sys.modules["__main__"] module, reference is borrowed
+ * NOTE: important we use the dict from __main__, this is what python expects
+ * for 'pickle' to work as well as strings like this...
+ * >> foo = 10
+ * >> print(__import__("__main__").foo)
+ *
+ * NOTE: this overwrites __main__ which gives problems with nested calls.
+ * be sure to run PyC_MainModule_Backup & PyC_MainModule_Restore if there is
+ * any chance that python is in the call stack.
+ */
PyObject *PyC_DefaultNameSpace(const char *filename);
void PyC_RunQuicky(const char *filepath, int n, ...);
+/**
+ * Import `imports` into `py_dict`.
+ *
+ * \param py_dict: A Python dictionary, typically used as a name-space for script execution.
+ * \param imports: A NULL terminated array of strings.
+ * \return true when all modules import without errors, otherwise return false.
+ * The caller is expected to handle the exception.
+ */
bool PyC_NameSpace_ImportArray(PyObject *py_dict, const char *imports[]);
+/**
+ * #PyC_MainModule_Restore MUST be called after #PyC_MainModule_Backup.
+ */
void PyC_MainModule_Backup(PyObject **r_main_mod);
void PyC_MainModule_Restore(PyObject *main_mod);
@@ -131,6 +176,11 @@ int PyC_FlagSet_ToBitfield(const PyC_FlagSet *items,
const char *error_prefix);
PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag);
+/**
+ * \return success
+ *
+ * \note it is caller's responsibility to acquire & release GIL!
+ */
bool PyC_RunString_AsNumber(const char **imports,
const char *expr,
const char *filename,
@@ -149,6 +199,11 @@ bool PyC_RunString_AsString(const char **imports,
const char *filename,
char **r_value);
+/**
+ * Use with PyArg_ParseTuple's "O&" formatting.
+ *
+ * \see #PyC_Long_AsBool for a similar function to use outside of argument parsing.
+ */
int PyC_ParseBool(PyObject *o, void *p);
struct PyC_StringEnumItems {
@@ -160,13 +215,41 @@ struct PyC_StringEnum {
int value_found;
};
+/**
+ * Use with PyArg_ParseTuple's "O&" formatting.
+ */
int PyC_ParseStringEnum(PyObject *o, void *p);
-const char *PyC_StringEnum_FindIDFromValue(const struct PyC_StringEnumItems *items,
- const int value);
+const char *PyC_StringEnum_FindIDFromValue(const struct PyC_StringEnumItems *items, int value);
int PyC_CheckArgs_DeepCopy(PyObject *args);
/* Integer parsing (with overflow checks), -1 on error. */
+/**
+ *
+ * Comparison with #PyObject_IsTrue
+ * ================================
+ *
+ * Even though Python provides a way to retrieve the boolean value for an object,
+ * in many cases it's far too relaxed, with the following examples coercing values.
+ *
+ * \code{.py}
+ * data.value = "Text" # True.
+ * data.value = "" # False.
+ * data.value = {1, 2} # True
+ * data.value = {} # False.
+ * data.value = None # False.
+ * \endcode
+ *
+ * In practice this is often a mistake by the script author that doesn't behave as they expect.
+ * So it's better to be more strict for attribute assignment and function arguments,
+ * only accepting True/False 0/1.
+ *
+ * If coercing a value is desired, it can be done explicitly: `data.value = bool(value)`
+ *
+ * \see #PyC_ParseBool for use with #PyArg_ParseTuple and related functions.
+ *
+ * \note Don't use `bool` return type, so -1 can be used as an error value.
+ */
int PyC_Long_AsBool(PyObject *value);
int8_t PyC_Long_AsI8(PyObject *value);
int16_t PyC_Long_AsI16(PyObject *value);
diff --git a/source/blender/python/generic/python_utildefines.h b/source/blender/python/generic/python_utildefines.h
index 1f093e633e4..25300c2fd45 100644
--- a/source/blender/python/generic/python_utildefines.h
+++ b/source/blender/python/generic/python_utildefines.h
@@ -36,16 +36,20 @@ extern "C" {
} \
(void)0
-/* wrap Py_INCREF & return the result,
- * use sparingly to avoid comma operator or temp var assignment */
+/**
+ * Wrap #Py_INCREF & return the result,
+ * use sparingly to avoid comma operator or temp var assignment.
+ */
Py_LOCAL_INLINE(PyObject *) Py_INCREF_RET(PyObject *op)
{
Py_INCREF(op);
return op;
}
-/* Append & transfer ownership to the list,
- * avoids inline Py_DECREF all over (which is quite a large macro). */
+/**
+ * Append & transfer ownership to the list,
+ * avoids inline #Py_DECREF all over (which is quite a large macro).
+ */
Py_LOCAL_INLINE(int) PyList_APPEND(PyObject *op, PyObject *v)
{
int ret = PyList_Append(op, v);
diff --git a/source/blender/python/gpu/gpu_py.c b/source/blender/python/gpu/gpu_py.c
index e6ba46b2b05..a2d4b0e1031 100644
--- a/source/blender/python/gpu/gpu_py.c
+++ b/source/blender/python/gpu/gpu_py.c
@@ -58,6 +58,7 @@ struct PyC_StringEnumItems bpygpu_dataformat_items[] = {
{GPU_DATA_10_11_11_REV, "10_11_11_REV"},
{0, NULL},
};
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/python/gpu/gpu_py_buffer.c b/source/blender/python/gpu/gpu_py_buffer.c
index abfde7b48c8..f074b51af32 100644
--- a/source/blender/python/gpu/gpu_py_buffer.c
+++ b/source/blender/python/gpu/gpu_py_buffer.c
@@ -687,13 +687,6 @@ size_t bpygpu_Buffer_size(BPyGPUBuffer *buffer)
return pygpu_buffer_calc_size(buffer->format, buffer->shape_len, buffer->shape);
}
-/**
- * Create a buffer object
- *
- * \param shape: An array of `shape_len` integers representing the size of each dimension.
- * \param buffer: When not NULL holds a contiguous buffer
- * with the correct format from which the buffer will be initialized
- */
BPyGPUBuffer *BPyGPU_Buffer_CreatePyObject(const int format,
const Py_ssize_t *shape,
const int shape_len,
diff --git a/source/blender/python/gpu/gpu_py_buffer.h b/source/blender/python/gpu/gpu_py_buffer.h
index 9df22e9b780..3dcf335230d 100644
--- a/source/blender/python/gpu/gpu_py_buffer.h
+++ b/source/blender/python/gpu/gpu_py_buffer.h
@@ -48,7 +48,14 @@ typedef struct BPyGPUBuffer {
} BPyGPUBuffer;
size_t bpygpu_Buffer_size(BPyGPUBuffer *buffer);
-BPyGPUBuffer *BPyGPU_Buffer_CreatePyObject(const int format,
+/**
+ * Create a buffer object
+ *
+ * \param shape: An array of `shape_len` integers representing the size of each dimension.
+ * \param buffer: When not NULL holds a contiguous buffer
+ * with the correct format from which the buffer will be initialized
+ */
+BPyGPUBuffer *BPyGPU_Buffer_CreatePyObject(int format,
const Py_ssize_t *shape,
- const int shape_len,
+ int shape_len,
void *buffer);
diff --git a/source/blender/python/gpu/gpu_py_framebuffer.c b/source/blender/python/gpu/gpu_py_framebuffer.c
index a9347b71723..412fcac02ca 100644
--- a/source/blender/python/gpu/gpu_py_framebuffer.c
+++ b/source/blender/python/gpu/gpu_py_framebuffer.c
@@ -530,6 +530,7 @@ static PyObject *pygpu_framebuffer_read_color(BPyGPUFrameBuffer *self,
PyErr_SetString(PyExc_BufferError, "the buffer size is smaller than expected");
return NULL;
}
+ Py_INCREF(py_buffer);
}
else {
py_buffer = BPyGPU_Buffer_CreatePyObject(
@@ -590,6 +591,7 @@ static PyObject *pygpu_framebuffer_read_depth(BPyGPUFrameBuffer *self,
PyErr_SetString(PyExc_BufferError, "the buffer size is smaller than expected");
return NULL;
}
+ Py_INCREF(py_buffer);
}
else {
py_buffer = BPyGPU_Buffer_CreatePyObject(GPU_DATA_FLOAT, (Py_ssize_t[]){h, w}, 2, NULL);
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index 6f23c2213e2..19013dc9ca3 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -44,6 +44,7 @@
#include "GPU_context.h"
#include "GPU_framebuffer.h"
#include "GPU_texture.h"
+#include "GPU_viewport.h"
#include "ED_view3d.h"
#include "ED_view3d_offscreen.h"
@@ -64,6 +65,14 @@
/** \name GPUOffScreen Common Utilities
* \{ */
+static const struct PyC_StringEnumItems pygpu_framebuffer_color_texture_formats[] = {
+ {GPU_RGBA8, "RGBA8"},
+ {GPU_RGBA16, "RGBA16"},
+ {GPU_RGBA16F, "RGBA16F"},
+ {GPU_RGBA32F, "RGBA32F"},
+ {0, NULL},
+};
+
static int pygpu_offscreen_valid_check(BPyGPUOffScreen *py_ofs)
{
if (UNLIKELY(py_ofs->ofs == NULL)) {
@@ -218,16 +227,18 @@ static PyObject *pygpu_offscreen__tp_new(PyTypeObject *UNUSED(self),
GPUOffScreen *ofs = NULL;
int width, height;
+ struct PyC_StringEnum pygpu_textureformat = {pygpu_framebuffer_color_texture_formats, GPU_RGBA8};
char err_out[256];
- static const char *_keywords[] = {"width", "height", NULL};
- static _PyArg_Parser _parser = {"ii:GPUOffScreen.__new__", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &width, &height)) {
+ static const char *_keywords[] = {"width", "height", "format", NULL};
+ static _PyArg_Parser _parser = {"ii|$O&:GPUOffScreen.__new__", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser, &width, &height, PyC_ParseStringEnum, &pygpu_textureformat)) {
return NULL;
}
if (GPU_context_active_get()) {
- ofs = GPU_offscreen_create(width, height, true, GPU_RGBA8, err_out);
+ ofs = GPU_offscreen_create(width, height, true, pygpu_textureformat.value_found, err_out);
}
else {
STRNCPY(err_out, "No active GPU context found");
@@ -355,6 +366,15 @@ static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *ar
GPU_offscreen_bind(self->ofs, true);
+ /* Cache the #GPUViewport so the frame-buffers and associated textures are
+ * not reallocated each time, see: T89204 */
+ if (!self->viewport) {
+ self->viewport = GPU_viewport_create();
+ }
+ else {
+ GPU_viewport_tag_update(self->viewport);
+ }
+
ED_view3d_draw_offscreen(depsgraph,
scene,
v3d->shading.type,
@@ -370,7 +390,7 @@ static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *ar
do_color_management,
true,
self->ofs,
- NULL);
+ self->viewport);
GPU_offscreen_unbind(self->ofs, true);
@@ -391,6 +411,11 @@ static PyObject *pygpu_offscreen_free(BPyGPUOffScreen *self)
{
BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+ if (self->viewport) {
+ GPU_viewport_free(self->viewport);
+ self->viewport = NULL;
+ }
+
GPU_offscreen_free(self->ofs);
self->ofs = NULL;
Py_RETURN_NONE;
@@ -399,6 +424,9 @@ static PyObject *pygpu_offscreen_free(BPyGPUOffScreen *self)
static void BPyGPUOffScreen__tp_dealloc(BPyGPUOffScreen *self)
{
+ if (self->viewport) {
+ GPU_viewport_free(self->viewport);
+ }
if (self->ofs) {
GPU_offscreen_free(self->ofs);
}
@@ -438,14 +466,21 @@ static struct PyMethodDef pygpu_offscreen__tp_methods[] = {
};
PyDoc_STRVAR(pygpu_offscreen__tp_doc,
- ".. class:: GPUOffScreen(width, height)\n"
+ ".. class:: GPUOffScreen(width, height, *, format='RGBA8')\n"
"\n"
" This object gives access to off screen buffers.\n"
"\n"
" :arg width: Horizontal dimension of the buffer.\n"
" :type width: int\n"
" :arg height: Vertical dimension of the buffer.\n"
- " :type height: int\n");
+ " :type height: int\n"
+ " :arg format: Internal data format inside GPU memory for color attachment "
+ "texture. Possible values are:\n"
+ " `RGBA8`,\n"
+ " `RGBA16`,\n"
+ " `RGBA16F`,\n"
+ " `RGBA32F`,\n"
+ " :type format: str\n");
PyTypeObject BPyGPUOffScreen_Type = {
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUOffScreen",
.tp_basicsize = sizeof(BPyGPUOffScreen),
@@ -469,6 +504,7 @@ PyObject *BPyGPUOffScreen_CreatePyObject(GPUOffScreen *ofs)
self = PyObject_New(BPyGPUOffScreen, &BPyGPUOffScreen_Type);
self->ofs = ofs;
+ self->viewport = NULL;
return (PyObject *)self;
}
diff --git a/source/blender/python/gpu/gpu_py_offscreen.h b/source/blender/python/gpu/gpu_py_offscreen.h
index 309735a6202..78bad595a3d 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.h
+++ b/source/blender/python/gpu/gpu_py_offscreen.h
@@ -26,9 +26,13 @@ extern PyTypeObject BPyGPUOffScreen_Type;
#define BPyGPUOffScreen_Check(v) (Py_TYPE(v) == &BPyGPUOffScreen_Type)
+struct GPUOffscreen;
+struct GPUViewport;
+
typedef struct BPyGPUOffScreen {
PyObject_HEAD
struct GPUOffScreen *ofs;
+ struct GPUViewport *viewport;
} BPyGPUOffScreen;
PyObject *BPyGPUOffScreen_CreatePyObject(struct GPUOffScreen *ofs) ATTR_NONNULL(1);
diff --git a/source/blender/python/gpu/gpu_py_select.c b/source/blender/python/gpu/gpu_py_select.c
index 4db102118f1..43980530f38 100644
--- a/source/blender/python/gpu/gpu_py_select.c
+++ b/source/blender/python/gpu/gpu_py_select.c
@@ -56,6 +56,7 @@ static PyObject *pygpu_select_load_id(PyObject *UNUSED(self), PyObject *value)
GPU_select_load_id(id);
Py_RETURN_NONE;
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/python/gpu/gpu_py_texture.c b/source/blender/python/gpu/gpu_py_texture.c
index 5d136921300..66b9cf5e86e 100644
--- a/source/blender/python/gpu/gpu_py_texture.c
+++ b/source/blender/python/gpu/gpu_py_texture.c
@@ -527,6 +527,7 @@ PyTypeObject BPyGPUTexture_Type = {
/* -------------------------------------------------------------------- */
/** \name GPU Texture module
* \{ */
+
PyDoc_STRVAR(pygpu_texture_from_image_doc,
".. function:: from_image(image)\n"
"\n"
@@ -536,7 +537,7 @@ PyDoc_STRVAR(pygpu_texture_from_image_doc,
"premultiplied or straight alpha matching the image alpha mode.\n"
"\n"
" :arg image: The Image datablock.\n"
- " :type image: `bpy.types.Image`\n"
+ " :type image: :class:`bpy.types.Image`\n"
" :return: The GPUTexture used by the image.\n"
" :rtype: :class:`gpu.types.GPUTexture`\n");
static PyObject *pygpu_texture_from_image(PyObject *UNUSED(self), PyObject *arg)
diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.c b/source/blender/python/gpu/gpu_py_vertex_buffer.c
index 949086378a8..bb762f9fe33 100644
--- a/source/blender/python/gpu/gpu_py_vertex_buffer.c
+++ b/source/blender/python/gpu/gpu_py_vertex_buffer.c
@@ -99,7 +99,7 @@ static void pygpu_fill_format_sequence(void *data_dst_void,
PyObject **value_fast_items = PySequence_Fast_ITEMS(py_seq_fast);
/**
- * Args are constants, so range checks will be optimized out if they're nop's.
+ * Args are constants, so range checks will be optimized out if they're no-op's.
*/
#define PY_AS_NATIVE(ty_dst, py_as_native) \
ty_dst *data_dst = data_dst_void; \
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 7646109c1b0..c792773272b 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -22,9 +22,13 @@
* A script writer should never directly access this module.
*/
+/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */
+#define PY_SSIZE_T_CLEAN
+
#include <Python.h>
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_appdir.h"
@@ -90,10 +94,13 @@ static PyObject *bpy_script_paths(PyObject *UNUSED(self))
return ret;
}
-static bool bpy_blend_paths_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src)
+static bool bpy_blend_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *UNUSED(path_dst),
+ const char *path_src)
{
- PyList_APPEND((PyObject *)userdata, PyC_UnicodeFromByte(path_src));
- return false; /* never edits the path */
+ PyObject *py_list = bpath_data->user_data;
+ PyList_APPEND(py_list, PyC_UnicodeFromByte(path_src));
+ return false; /* Never edits the path. */
}
PyDoc_STRVAR(bpy_blend_paths_doc,
@@ -111,7 +118,7 @@ PyDoc_STRVAR(bpy_blend_paths_doc,
" :rtype: list of strings\n");
static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- int flag = 0;
+ eBPathForeachFlag flag = 0;
PyObject *list;
bool absolute = false;
@@ -133,22 +140,73 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec
}
if (absolute) {
- flag |= BKE_BPATH_TRAVERSE_ABS;
+ flag |= BKE_BPATH_FOREACH_PATH_ABSOLUTE;
}
if (!packed) {
- flag |= BKE_BPATH_TRAVERSE_SKIP_PACKED;
+ flag |= BKE_BPATH_FOREACH_PATH_SKIP_PACKED;
}
if (local) {
- flag |= BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
+ flag |= BKE_BPATH_FOREACH_PATH_SKIP_LINKED;
}
list = PyList_New(0);
- BKE_bpath_traverse_main(G_MAIN, bpy_blend_paths_visit_cb, flag, (void *)list);
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){
+ .bmain = G_MAIN,
+ .callback_function = bpy_blend_foreach_path_cb,
+ .flag = flag,
+ .user_data = list,
+ });
return list;
}
+PyDoc_STRVAR(bpy_flip_name_doc,
+ ".. function:: flip_name(name, strip_digits=False)\n"
+ "\n"
+ " Flip a name between left/right sides, useful for \n"
+ " mirroring bone names.\n"
+ "\n"
+ " :arg name: Bone name to flip.\n"
+ " :type name: string\n"
+ " :arg strip_digits: Whether to remove ``.###`` suffix.\n"
+ " :type strip_digits: bool\n"
+ " :return: The flipped name.\n"
+ " :rtype: string\n");
+static PyObject *bpy_flip_name(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ const char *name_src = NULL;
+ Py_ssize_t name_src_len;
+ bool strip_digits = false;
+
+ static const char *_keywords[] = {"", "strip_digits", NULL};
+ static _PyArg_Parser _parser = {
+ "s#" /* `name` */
+ "|$" /* Optional, keyword only arguments. */
+ "O&" /* `strip_digits` */
+ /* Name to show in the case of an error. */
+ ":flip_name",
+ _keywords,
+ 0,
+ };
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser, &name_src, &name_src_len, PyC_ParseBool, &strip_digits)) {
+ return NULL;
+ }
+
+ /* Worst case we gain one extra byte (besides null-terminator) by changing
+ "Left" to "Right", because only the first appearance of "Left" gets replaced. */
+ const size_t size = name_src_len + 2;
+ char *name_dst = PyMem_MALLOC(size);
+ const size_t name_dst_len = BLI_string_flip_side_name(name_dst, name_src, strip_digits, size);
+
+ PyObject *result = PyUnicode_FromStringAndSize(name_dst, name_dst_len);
+
+ PyMem_FREE(name_dst);
+
+ return result;
+}
+
// PyDoc_STRVAR(bpy_user_resource_doc[] = /* now in bpy/utils.py */
static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
@@ -338,6 +396,12 @@ static PyMethodDef meth_bpy_blend_paths = {
METH_VARARGS | METH_KEYWORDS,
bpy_blend_paths_doc,
};
+static PyMethodDef meth_bpy_flip_name = {
+ "flip_name",
+ (PyCFunction)bpy_flip_name,
+ METH_VARARGS | METH_KEYWORDS,
+ bpy_flip_name_doc,
+};
static PyMethodDef meth_bpy_user_resource = {
"user_resource",
(PyCFunction)bpy_user_resource,
@@ -386,9 +450,6 @@ static PyObject *bpy_import_test(const char *modname)
return mod;
}
-/******************************************************************************
- * Description: Creates the bpy module and adds it to sys.modules for importing
- ******************************************************************************/
void BPy_init_modules(struct bContext *C)
{
PointerRNA ctx_ptr;
@@ -472,6 +533,8 @@ void BPy_init_modules(struct bContext *C)
PyModule_AddObject(mod,
meth_bpy_unescape_identifier.ml_name,
(PyObject *)PyCFunction_New(&meth_bpy_unescape_identifier, NULL));
+ PyModule_AddObject(
+ mod, meth_bpy_flip_name.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_flip_name, NULL));
/* register funcs (bpy_rna.c) */
PyModule_AddObject(mod,
diff --git a/source/blender/python/intern/bpy.h b/source/blender/python/intern/bpy.h
index 25a047edfb5..b77a3e9fb7d 100644
--- a/source/blender/python/intern/bpy.h
+++ b/source/blender/python/intern/bpy.h
@@ -26,7 +26,9 @@ extern "C" {
struct bContext;
+/** Creates the bpy module and adds it to `sys.modules` for importing. */
void BPy_init_modules(struct bContext *C);
+
extern PyObject *bpy_package_py;
/* bpy_interface_atexit.c */
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index de70035eb2b..4fa71c0c976 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -69,12 +69,12 @@ static BlenderAppTranslations *_translations = NULL;
/** \} */
-#ifdef WITH_INTERNATIONAL
-
/* ------------------------------------------------------------------- */
/** \name Helpers for GHash
* \{ */
+#ifdef WITH_INTERNATIONAL
+
typedef struct GHashKey {
const char *msgctxt;
const char *msgid;
diff --git a/source/blender/python/intern/bpy_capi_utils.c b/source/blender/python/intern/bpy_capi_utils.c
index 8e9d8c02c03..ed01132ed4e 100644
--- a/source/blender/python/intern/bpy_capi_utils.c
+++ b/source/blender/python/intern/bpy_capi_utils.c
@@ -56,9 +56,6 @@ short BPy_reports_to_error(ReportList *reports, PyObject *exception, const bool
return (report_str == NULL) ? 0 : -1;
}
-/**
- * A version of #BKE_report_write_file_fp that uses Python's stdout.
- */
void BPy_reports_write_stdout(const ReportList *reports, const char *header)
{
if (header) {
diff --git a/source/blender/python/intern/bpy_capi_utils.h b/source/blender/python/intern/bpy_capi_utils.h
index 80e92d918ac..0889dec36c8 100644
--- a/source/blender/python/intern/bpy_capi_utils.h
+++ b/source/blender/python/intern/bpy_capi_utils.h
@@ -32,18 +32,24 @@ struct EnumPropertyItem;
struct ReportList;
/* error reporting */
-short BPy_reports_to_error(struct ReportList *reports, PyObject *exception, const bool clear);
+short BPy_reports_to_error(struct ReportList *reports, PyObject *exception, bool clear);
+/**
+ * A version of #BKE_report_write_file_fp that uses Python's stdout.
+ */
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 use_full,
+ 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);
struct bContext *BPY_context_get(void);
extern void bpy_context_set(struct bContext *C, PyGILState_STATE *gilstate);
+/**
+ * Context should be used but not now because it causes some bugs.
+ */
extern void bpy_context_clear(struct bContext *C, const PyGILState_STATE *gilstate);
#ifdef __cplusplus
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index 7effa25e6e8..bd1f3cd301f 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -57,19 +57,12 @@
# include <opcode.h>
#endif
-/**
- * For PyDrivers
- * (drivers using one-line Python expressions to express relationships between targets).
- */
PyObject *bpy_pydriver_Dict = NULL;
#ifdef USE_BYTECODE_WHITELIST
static PyObject *bpy_pydriver_Dict__whitelist = NULL;
#endif
-/* For faster execution we keep a special dictionary for pydrivers, with
- * the needed modules and aliases.
- */
int bpy_pydriver_create_dict(void)
{
PyObject *d, *mod;
@@ -220,11 +213,6 @@ static void bpy_pydriver_namespace_clear_self(void)
}
}
-/* Update function, it gets rid of pydrivers global dictionary, forcing
- * BPY_driver_exec to recreate it. This function is used to force
- * reloading the Blender text module "pydrivers.py", if available, so
- * updates in it reach pydriver evaluation.
- */
void BPY_driver_reset(void)
{
PyGILState_STATE gilstate;
@@ -429,28 +417,24 @@ static void bpy_pydriver_namespace_add_depsgraph(PyObject *driver_vars,
}
}
-/**
- * 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 T27683.
- *
- * (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.
- *
- * For copy-on-write we always cache expressions and write errors in the
- * original driver, otherwise these would get freed while editing. Due to
- * the GIL this is thread-safe.
- */
float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
ChannelDriver *driver,
ChannelDriver *driver_orig,
const AnimationEvalContext *anim_eval_context)
{
+ /* (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 T27683.
+ *
+ * (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.
+ *
+ * For copy-on-write we always cache expressions and write errors in the
+ * original driver, otherwise these would get freed while editing.
+ * Due to the GIL this is thread-safe. */
+
PyObject *driver_vars = NULL;
PyObject *retval = NULL;
diff --git a/source/blender/python/intern/bpy_driver.h b/source/blender/python/intern/bpy_driver.h
index d5064d9fa56..b7bb0f846e8 100644
--- a/source/blender/python/intern/bpy_driver.h
+++ b/source/blender/python/intern/bpy_driver.h
@@ -24,7 +24,15 @@
extern "C" {
#endif
+/**
+ * For faster execution we keep a special dictionary for py-drivers, with
+ * the needed modules and aliases.
+ */
int bpy_pydriver_create_dict(void);
+/**
+ * For PyDrivers
+ * (drivers using one-line Python expressions to express relationships between targets).
+ */
extern PyObject *bpy_pydriver_Dict;
#ifdef __cplusplus
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 95affa9dba9..faa668df775 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -80,6 +80,7 @@
#include "../mathutils/mathutils.h"
/* Logging types to use anywhere in the Python modules. */
+
CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_CONTEXT, "bpy.context");
CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_INTERFACE, "bpy.interface");
CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_RNA, "bpy.rna");
@@ -103,7 +104,6 @@ static double bpy_timer_run; /* time for each python script run */
static double bpy_timer_run_tot; /* accumulate python runs */
#endif
-/* use for updating while a python script runs - in case of file load */
void BPY_context_update(bContext *C)
{
/* don't do this from a non-main (e.g. render) thread, it can cause a race
@@ -141,7 +141,6 @@ void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
}
}
-/* context should be used but not now because it causes some bugs */
void bpy_context_clear(bContext *UNUSED(C), const PyGILState_STATE *gilstate)
{
py_call_level--;
@@ -175,16 +174,6 @@ static void bpy_context_end(bContext *C)
CTX_wm_operator_poll_msg_clear(C);
}
-/**
- * Use for `CTX_*_set(..)` functions need to set values which are later read back as expected.
- * In this case we don't want the Python context to override the values as it causes problems
- * see T66256.
- *
- * \param dict_p: A pointer to #bContext.data.py_context so we can assign a new value.
- * \param dict_orig: The value of #bContext.data.py_context_orig to check if we need to copy.
- *
- * \note Typically accessed via #BPY_context_dict_clear_members macro.
- */
void BPY_context_dict_clear_members_array(void **dict_p,
void *dict_orig,
const char *context_members[],
@@ -238,9 +227,6 @@ void BPY_text_free_code(Text *text)
}
}
-/**
- * Needed so the #Main pointer in `bpy.data` doesn't become out of date.
- */
void BPY_modules_update(void)
{
#if 0 /* slow, this runs all the time poll, draw etc 100's of time a sec. */
@@ -333,7 +319,6 @@ static void pystatus_exit_on_error(PyStatus status)
}
#endif
-/* call BPY_context_set first */
void BPY_python_start(bContext *C, int argc, const char **argv)
{
#ifndef WITH_PYTHON_MODULE
@@ -881,9 +866,6 @@ static void bpy_module_free(void *UNUSED(mod))
#endif
-/**
- * Avoids duplicating keyword list.
- */
bool BPY_string_is_keyword(const char *str)
{
/* list is from...
@@ -905,8 +887,7 @@ bool BPY_string_is_keyword(const char *str)
return false;
}
-/* EVIL, define text.c functions here... */
-/* BKE_text.h */
+/* EVIL: define `text.c` functions here (declared in `BKE_text.h`). */
int text_check_identifier_unicode(const uint ch)
{
return (ch < 255 && text_check_identifier((char)ch)) || Py_UNICODE_ISALNUM(ch);
diff --git a/source/blender/python/intern/bpy_interface_run.c b/source/blender/python/intern/bpy_interface_run.c
index f7d6a33c904..79744090cc3 100644
--- a/source/blender/python/intern/bpy_interface_run.c
+++ b/source/blender/python/intern/bpy_interface_run.c
@@ -80,6 +80,14 @@ typedef struct {
} PyModuleObject;
#endif
+/**
+ * Execute a file-path or text-block.
+ *
+ * \param reports: Report exceptions as errors (may be NULL).
+ * \param do_jump: See #BPY_run_text.
+ *
+ * \note Share a function for this since setup/cleanup logic is the same.
+ */
static bool python_script_exec(
bContext *C, const char *fn, struct Text *text, struct ReportList *reports, const bool do_jump)
{
@@ -172,7 +180,7 @@ static bool python_script_exec(
if (!py_result) {
if (text) {
if (do_jump) {
- /* ensure text is valid before use, the script may have freed its self */
+ /* ensure text is valid before use, the script may have freed itself */
Main *bmain_new = CTX_data_main(C);
if ((bmain_old == bmain_new) && (BLI_findindex(&bmain_new->texts, text) != -1)) {
python_script_error_jump_text(text);
@@ -212,7 +220,6 @@ static bool python_script_exec(
/** \name Run Text / Filename / String
* \{ */
-/* Can run a file or text block */
bool BPY_run_filepath(bContext *C, const char *filepath, struct ReportList *reports)
{
return python_script_exec(C, filepath, NULL, reports, false);
@@ -271,17 +278,11 @@ static bool bpy_run_string_impl(bContext *C,
return ok;
}
-/**
- * Run an expression, matches: `exec(compile(..., "eval"))`
- */
bool BPY_run_string_eval(bContext *C, const char *imports[], const char *expr)
{
return bpy_run_string_impl(C, imports, expr, Py_eval_input);
}
-/**
- * Run an entire script, matches: `exec(compile(..., "exec"))`
- */
bool BPY_run_string_exec(bContext *C, const char *imports[], const char *expr)
{
return bpy_run_string_impl(C, imports, expr, Py_file_input);
@@ -330,9 +331,6 @@ static void run_string_handle_error(struct BPy_RunErrInfo *err_info)
Py_XDECREF(py_err_str);
}
-/**
- * \return success
- */
bool BPY_run_string_as_number(bContext *C,
const char *imports[],
const char *expr,
@@ -342,10 +340,6 @@ bool BPY_run_string_as_number(bContext *C,
PyGILState_STATE gilstate;
bool ok = true;
- if (!r_value || !expr) {
- return -1;
- }
-
if (expr[0] == '\0') {
*r_value = 0.0;
return ok;
@@ -364,9 +358,6 @@ bool BPY_run_string_as_number(bContext *C,
return ok;
}
-/**
- * \return success
- */
bool BPY_run_string_as_string_and_size(bContext *C,
const char *imports[],
const char *expr,
@@ -374,7 +365,6 @@ bool BPY_run_string_as_string_and_size(bContext *C,
char **r_value,
size_t *r_value_size)
{
- BLI_assert(r_value && expr);
PyGILState_STATE gilstate;
bool ok = true;
@@ -406,18 +396,12 @@ bool BPY_run_string_as_string(bContext *C,
return BPY_run_string_as_string_and_size(C, imports, expr, err_info, r_value, &value_dummy_size);
}
-/**
- * Support both int and pointers.
- *
- * \return success
- */
bool BPY_run_string_as_intptr(bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
intptr_t *r_value)
{
- BLI_assert(r_value && expr);
PyGILState_STATE gilstate;
bool ok = true;
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index d9a357c5e2e..fe279c0b940 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -34,6 +34,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_blendfile_link_append.h"
#include "BKE_context.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -67,7 +68,9 @@ typedef struct {
char abspath[FILE_MAX]; /* absolute path */
BlendHandle *blo_handle;
/* Referenced by `blo_handle`, so stored here to keep alive for long enough. */
+ ReportList reports;
BlendFileReadReport bf_reports;
+
int flag;
PyObject *dict;
/* Borrowed reference to the `bmain`, taken from the RNA instance of #RNA_BlendDataLibraries.
@@ -256,16 +259,17 @@ static PyObject *bpy_lib_enter(BPy_Library *self)
PyObject *ret;
BPy_Library *self_from;
PyObject *from_dict = _PyDict_NewPresized(INDEX_ID_MAX);
- ReportList reports;
+ ReportList *reports = &self->reports;
+ BlendFileReadReport *bf_reports = &self->bf_reports;
- BKE_reports_init(&reports, RPT_STORE);
- BlendFileReadReport bf_reports = {.reports = &reports};
+ BKE_reports_init(reports, RPT_STORE);
+ memset(bf_reports, 0, sizeof(*bf_reports));
+ bf_reports->reports = reports;
- self->bf_reports = bf_reports;
- self->blo_handle = BLO_blendhandle_from_file(self->abspath, &self->bf_reports);
+ self->blo_handle = BLO_blendhandle_from_file(self->abspath, bf_reports);
if (self->blo_handle == NULL) {
- if (BPy_reports_to_error(&reports, PyExc_IOError, true) != -1) {
+ if (BPy_reports_to_error(reports, PyExc_IOError, true) != -1) {
PyErr_Format(PyExc_IOError, "load: %s failed to open blend file", self->abspath);
}
return NULL;
@@ -301,7 +305,7 @@ static PyObject *bpy_lib_enter(BPy_Library *self)
PyTuple_SET_ITEMS(ret, (PyObject *)self_from, (PyObject *)self);
Py_INCREF(self);
- BKE_reports_clear(&reports);
+ BKE_reports_clear(reports);
return ret;
}
@@ -343,11 +347,63 @@ static void bpy_lib_exit_warn_type(BPy_Library *self, PyObject *item)
PyErr_Restore(exc, val, tb);
}
+struct LibExitLappContextItemsIterData {
+ short idcode;
+ BPy_Library *py_library;
+ PyObject *py_list;
+ Py_ssize_t py_list_size;
+};
+
+static bool bpy_lib_exit_lapp_context_items_cb(BlendfileLinkAppendContext *lapp_context,
+ BlendfileLinkAppendContextItem *item,
+ void *userdata)
+{
+ struct LibExitLappContextItemsIterData *data = userdata;
+
+ /* Since `bpy_lib_exit` loops over all ID types, all items in `lapp_context` end up being looped
+ * over for each ID type, so when it does not match the item can simply be skipped: it either has
+ * already been processed, or will be processed in a later loop. */
+ if (BKE_blendfile_link_append_context_item_idcode_get(lapp_context, item) != data->idcode) {
+ return true;
+ }
+
+ const int py_list_index = POINTER_AS_INT(
+ BKE_blendfile_link_append_context_item_userdata_get(lapp_context, item));
+ ID *new_id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item);
+
+ BLI_assert(py_list_index < data->py_list_size);
+
+ /* Fully invalid items (which got set to `Py_None` already in first loop of `bpy_lib_exit`)
+ * should never be accessed here, since their index should never be set to any item in
+ * `lapp_context`. */
+ PyObject *item_src = PyList_GET_ITEM(data->py_list, py_list_index);
+ BLI_assert(item_src != Py_None);
+
+ PyObject *py_item;
+ if (new_id != NULL) {
+ PointerRNA newid_ptr;
+ RNA_id_pointer_create(new_id, &newid_ptr);
+ py_item = pyrna_struct_CreatePyObject(&newid_ptr);
+ }
+ else {
+ const char *item_idname = PyUnicode_AsUTF8(item_src);
+ const char *idcode_name_plural = BKE_idtype_idcode_to_name_plural(data->idcode);
+
+ bpy_lib_exit_warn_idname(data->py_library, idcode_name_plural, item_idname);
+
+ py_item = Py_INCREF_RET(Py_None);
+ }
+
+ PyList_SET_ITEM(data->py_list, py_list_index, py_item);
+
+ Py_DECREF(item_src);
+
+ return true;
+}
+
static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
{
Main *bmain = self->bmain;
- Main *mainl = NULL;
- const int err = 0;
const bool do_append = ((self->flag & FILE_LINK) == 0);
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
@@ -357,134 +413,100 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
struct LibraryLink_Params liblink_params;
BLO_library_link_params_init(&liblink_params, bmain, self->flag, id_tag_extra);
- mainl = BLO_library_link_begin(&(self->blo_handle), self->relpath, &liblink_params);
-
- {
- int idcode_step = 0, idcode;
- while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
- if (BKE_idtype_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) {
- const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
- PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
- // printf("lib: %s\n", name_plural);
- if (ls && PyList_Check(ls)) {
- /* loop */
- const Py_ssize_t size = PyList_GET_SIZE(ls);
- Py_ssize_t i;
-
- for (i = 0; i < size; i++) {
- PyObject *item_src = PyList_GET_ITEM(ls, i);
- PyObject *item_dst; /* must be set below */
- const char *item_idname = PyUnicode_AsUTF8(item_src);
-
- // printf(" %s\n", item_idname);
-
- if (item_idname) {
- ID *id = BLO_library_link_named_part(
- mainl, &(self->blo_handle), idcode, item_idname, &liblink_params);
- if (id) {
-
- if (self->bmain_is_temp) {
- /* If this fails, #LibraryLink_Params.id_tag_extra is not being applied. */
- BLI_assert(id->tag & LIB_TAG_TEMP_MAIN);
- }
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(
+ &liblink_params);
+ BKE_blendfile_link_append_context_library_add(lapp_context, self->abspath, self->blo_handle);
-#ifdef USE_RNA_DATABLOCKS
- /* swap name for pointer to the id */
- item_dst = PyCapsule_New((void *)id, NULL, NULL);
-#else
- /* leave as is */
- continue;
-#endif
- }
- else {
- bpy_lib_exit_warn_idname(self, name_plural, item_idname);
- /* just warn for now */
- /* err = -1; */
- item_dst = Py_INCREF_RET(Py_None);
- }
-
- /* ID or None */
- }
- else {
- /* XXX, could complain about this */
- bpy_lib_exit_warn_type(self, item_src);
- PyErr_Clear();
- item_dst = Py_INCREF_RET(Py_None);
- }
-
- /* item_dst must be new or already incref'd */
- Py_DECREF(item_src);
- PyList_SET_ITEM(ls, i, item_dst);
- }
- }
- }
+ int idcode_step = 0;
+ short idcode;
+ while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
+ if (!BKE_idtype_idcode_is_linkable(idcode) || (idcode == ID_WS && !do_append)) {
+ continue;
}
- }
- if (err == -1) {
- /* exception raised above, XXX, this leaks some memory */
- BLO_blendhandle_close(self->blo_handle);
- self->blo_handle = NULL;
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- return NULL;
- }
+ const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
+ PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
+ // printf("lib: %s\n", name_plural);
+ if (ls == NULL || !PyList_Check(ls)) {
+ continue;
+ }
- Library *lib = mainl->curlib; /* newly added lib, assign before append end */
- BLO_library_link_end(mainl, &(self->blo_handle), &liblink_params);
- BLO_blendhandle_close(self->blo_handle);
- self->blo_handle = NULL;
+ const Py_ssize_t size = PyList_GET_SIZE(ls);
+ if (size == 0) {
+ continue;
+ }
+
+ /* loop */
+ for (Py_ssize_t i = 0; i < size; i++) {
+ PyObject *item_src = PyList_GET_ITEM(ls, i);
+ const char *item_idname = PyUnicode_AsUTF8(item_src);
- GHash *old_to_new_ids = BLI_ghash_ptr_new(__func__);
+ // printf(" %s\n", item_idname);
- /* copied from wm_operator.c */
- {
- /* mark all library linked objects to be updated */
- BKE_main_lib_objects_recalc_all(bmain);
+ /* NOTE: index of item in py list is stored in userdata pointer, so that it can be found
+ * later on to replace the ID name by the actual ID pointer. */
+ if (item_idname != NULL) {
+ BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, item_idname, idcode, POINTER_FROM_INT(i));
+ BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0);
+ }
+ else {
+ /* XXX, could complain about this */
+ bpy_lib_exit_warn_type(self, item_src);
+ PyErr_Clear();
- /* append, rather than linking */
- if (do_append) {
- BKE_library_make_local(bmain, lib, old_to_new_ids, true, false);
+#ifdef USE_RNA_DATABLOCKS
+ /* We can replace the item immediately with `None`. */
+ PyObject *py_item = Py_INCREF_RET(Py_None);
+ PyList_SET_ITEM(ls, i, py_item);
+ Py_DECREF(item_src);
+#endif
+ }
}
}
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+ BKE_blendfile_link(lapp_context, NULL);
+ if (do_append) {
+ BKE_blendfile_append(lapp_context, NULL);
+ }
- /* finally swap the capsules for real bpy objects
- * important since BLO_library_append_end initializes NodeTree types used by srna->refine */
+ /* If enabled, replace named items in given lists by the final matching new ID pointer. */
#ifdef USE_RNA_DATABLOCKS
- {
- int idcode_step = 0, idcode;
- while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
- if (BKE_idtype_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) {
- const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
- PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
- if (ls && PyList_Check(ls)) {
- const Py_ssize_t size = PyList_GET_SIZE(ls);
- Py_ssize_t i;
- PyObject *item;
-
- for (i = 0; i < size; i++) {
- item = PyList_GET_ITEM(ls, i);
- if (PyCapsule_CheckExact(item)) {
- PointerRNA id_ptr;
- ID *id;
-
- id = PyCapsule_GetPointer(item, NULL);
- id = BLI_ghash_lookup_default(old_to_new_ids, id, id);
- Py_DECREF(item);
-
- RNA_id_pointer_create(id, &id_ptr);
- item = pyrna_struct_CreatePyObject(&id_ptr);
- PyList_SET_ITEM(ls, i, item);
- }
- }
- }
- }
+ idcode_step = 0;
+ while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
+ if (!BKE_idtype_idcode_is_linkable(idcode) || (idcode == ID_WS && !do_append)) {
+ continue;
+ }
+ const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
+ PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
+ // printf("lib: %s\n", name_plural);
+ if (ls == NULL || !PyList_Check(ls)) {
+ continue;
+ }
+
+ const Py_ssize_t size = PyList_GET_SIZE(ls);
+ if (size == 0) {
+ continue;
}
+
+ /* Loop over linked items in `lapp_context` to find matching python one in the list, and
+ * replace them with proper ID pointer. */
+ struct LibExitLappContextItemsIterData iter_data = {
+ .idcode = idcode, .py_library = self, .py_list = ls, .py_list_size = size};
+ BKE_blendfile_link_append_context_item_foreach(
+ lapp_context,
+ bpy_lib_exit_lapp_context_items_cb,
+ BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT,
+ &iter_data);
}
-#endif /* USE_RNA_DATABLOCKS */
+#endif // USE_RNA_DATABLOCKS
+
+ BLO_blendhandle_close(self->blo_handle);
+ self->blo_handle = NULL;
+
+ BKE_blendfile_link_append_context_free(lapp_context);
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- BLI_ghash_free(old_to_new_ids, NULL, NULL);
Py_RETURN_NONE;
}
diff --git a/source/blender/python/intern/bpy_msgbus.c b/source/blender/python/intern/bpy_msgbus.c
index 75a5f6f72ae..9e165bbf1c0 100644
--- a/source/blender/python/intern/bpy_msgbus.c
+++ b/source/blender/python/intern/bpy_msgbus.c
@@ -208,6 +208,9 @@ static void bpy_msgbus_subscribe_value_free_data(struct wmMsgSubscribeKey *UNUSE
PyDoc_STRVAR(
bpy_msgbus_subscribe_rna_doc,
".. function:: subscribe_rna(key, owner, args, notify, options=set())\n"
+ "\n"
+ " Register a message bus subscription. It will be cleared when another blend file is\n"
+ " loaded, or can be cleared explicitly via :func:`bpy.msgbus.clear_by_owner`.\n"
"\n" BPY_MSGBUS_RNA_MSGKEY_DOC
" :arg owner: Handle for this subscription (compared by identity).\n"
" :type owner: Any type.\n"
@@ -215,7 +218,12 @@ PyDoc_STRVAR(
"\n"
" - ``PERSISTENT`` when set, the subscriber will be kept when remapping ID data.\n"
"\n"
- " :type options: set of str.\n");
+ " :type options: set of str.\n"
+ "\n"
+ ".. note::\n"
+ "\n"
+ " All subscribers will be cleared on file-load. Subscribers can be re-registered on load,\n"
+ " see :mod:`bpy.app.handlers.load_post`.\n");
static PyObject *bpy_msgbus_subscribe_rna(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
const char *error_prefix = "subscribe_rna";
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index 5ae123f3254..a86c2e3a35e 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -81,7 +81,7 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
const char *context_str = NULL;
PyObject *ret;
- int context = WM_OP_EXEC_DEFAULT;
+ wmOperatorCallContext context = WM_OP_EXEC_DEFAULT;
/* XXX TODO: work out a better solution for passing on context,
* could make a tuple from self and pack the name and Context into it. */
@@ -107,7 +107,9 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
}
if (context_str) {
- if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context) == 0) {
+ int context_int = context;
+
+ if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context_int) == 0) {
char *enum_str = pyrna_enum_repr(rna_enum_operator_context_items);
PyErr_Format(PyExc_TypeError,
"Calling operator \"bpy.ops.%s.poll\" error, "
@@ -117,6 +119,8 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
MEM_freeN(enum_str);
return NULL;
}
+ /* Copy back to the properly typed enum. */
+ context = context_int;
}
if (ELEM(context_dict, NULL, Py_None)) {
@@ -166,8 +170,7 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
PyObject *kw = NULL; /* optional args */
PyObject *context_dict = NULL; /* optional args */
- /* note that context is an int, python does the conversion in this case */
- int context = WM_OP_EXEC_DEFAULT;
+ wmOperatorCallContext context = WM_OP_EXEC_DEFAULT;
int is_undo = false;
/* XXX TODO: work out a better solution for passing on context,
@@ -209,7 +212,9 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
}
if (context_str) {
- if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context) == 0) {
+ int context_int = context;
+
+ if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context_int) == 0) {
char *enum_str = pyrna_enum_repr(rna_enum_operator_context_items);
PyErr_Format(PyExc_TypeError,
"Calling operator \"bpy.ops.%s\" error, "
@@ -219,6 +224,8 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
MEM_freeN(enum_str);
return NULL;
}
+ /* Copy back to the properly typed enum. */
+ context = context_int;
}
if (ELEM(context_dict, NULL, Py_None)) {
@@ -394,7 +401,7 @@ static PyObject *pyop_as_string(PyObject *UNUSED(self), PyObject *args)
return NULL;
}
- /* WM_operator_properties_create(&ptr, opname); */
+ // WM_operator_properties_create(&ptr, opname);
/* Save another lookup */
RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c
index c2d7257e458..bee64f5de2c 100644
--- a/source/blender/python/intern/bpy_operator_wrap.c
+++ b/source/blender/python/intern/bpy_operator_wrap.c
@@ -115,10 +115,6 @@ static void operator_properties_init(wmOperatorType *ot)
/* end 'ot->prop' assignment */
}
-/**
- * Generic function used by all Python defined operators
- * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
- */
void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata)
{
/* take care not to overwrite anything set in
@@ -135,10 +131,6 @@ void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata)
operator_properties_init(ot);
}
-/**
- * Generic function used by all Python defined macro-operators
- * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
- */
void BPY_RNA_operator_macro_wrapper(wmOperatorType *ot, void *userdata)
{
wmOperatorType *data = (wmOperatorType *)userdata;
diff --git a/source/blender/python/intern/bpy_operator_wrap.h b/source/blender/python/intern/bpy_operator_wrap.h
index 9e496cd8d26..41deb06814b 100644
--- a/source/blender/python/intern/bpy_operator_wrap.h
+++ b/source/blender/python/intern/bpy_operator_wrap.h
@@ -30,7 +30,15 @@ extern "C" {
PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args);
/* exposed to rna/wm api */
+/**
+ * Generic function used by all Python defined operators
+ * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
+ */
void BPY_RNA_operator_wrapper(struct wmOperatorType *ot, void *userdata);
+/**
+ * Generic function used by all Python defined macro-operators
+ * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
+ */
void BPY_RNA_operator_macro_wrapper(struct wmOperatorType *ot, void *userdata);
#ifdef __cplusplus
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index ac624d365fa..fe7183441d1 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -366,7 +366,7 @@ static PyObject *bpy_prop_deferred_call(BPy_PropDeferred *UNUSED(self),
/**
* Expose the function in case scripts need to introspect this information
- * (not currently used by Blender it's self).
+ * (not currently used by Blender itself).
*/
static PyObject *bpy_prop_deferred_function_get(BPy_PropDeferred *self, void *UNUSED(closure))
{
@@ -377,7 +377,7 @@ static PyObject *bpy_prop_deferred_function_get(BPy_PropDeferred *self, void *UN
/**
* Expose keywords in case scripts need to introspect this information
- * (not currently used by Blender it's self).
+ * (not currently used by Blender itself).
*/
static PyObject *bpy_prop_deferred_keywords_get(BPy_PropDeferred *self, void *UNUSED(closure))
{
@@ -434,6 +434,10 @@ static PyObject *bpy_prop_deferred_data_CreatePyObject(PyObject *fn, PyObject *k
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Shared Property Utilities
+ * \{ */
+
/* PyObject's */
static PyObject *pymeth_BoolProperty = NULL;
static PyObject *pymeth_BoolVectorProperty = NULL;
@@ -2605,7 +2609,9 @@ static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p)
" :type step: int\n"
#define BPY_PROPDEF_FLOAT_PREC_DOC \
- " :arg precision: Maximum number of decimal digits to display, in [0, 6].\n" \
+ " :arg precision: Maximum number of decimal digits to display, in [0, 6]. Fraction is " \
+ "automatically hidden for exact integer values of fields with unit 'NONE' or 'TIME' (frame " \
+ "count) and step divisible by 100.\n" \
" :type precision: int\n"
#define BPY_PROPDEF_UPDATE_DOC \
@@ -2630,10 +2636,14 @@ static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p)
" This function must take 2 values (self, value) and return None.\n" \
" :type set: function\n"
-#define BPY_PROPDEF_TYPE_DOC \
+#define BPY_PROPDEF_POINTER_TYPE_DOC \
" :arg type: A subclass of :class:`bpy.types.PropertyGroup` or :class:`bpy.types.ID`.\n" \
" :type type: class\n"
+#define BPY_PROPDEF_COLLECTION_TYPE_DOC \
+ " :arg type: A subclass of :class:`bpy.types.PropertyGroup`.\n" \
+ " :type type: class\n"
+
#define BPY_PROPDEF_TAGS_DOC \
" :arg tags: Enumerator of tags that are defined by parent class.\n" \
" :type tags: set\n"
@@ -3750,7 +3760,7 @@ PyDoc_STRVAR(
" (e.g. returned by :class:`bpy.types.UILayout.icon`)\n"
" :number: Unique value used as the identifier for this item (stored in file data).\n"
" Use when the identifier may need to change. If the *ENUM_FLAG* option is used,\n"
- " the values are bitmasks and should be powers of two.\n"
+ " the values are bit-masks and should be powers of two.\n"
"\n"
" When an item only contains 4 items they define ``(identifier, name, description, "
"number)``.\n"
@@ -3981,7 +3991,7 @@ PyDoc_STRVAR(BPy_PointerProperty_doc,
"update=None)\n"
"\n"
" Returns a new pointer property definition.\n"
- "\n" BPY_PROPDEF_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
+ "\n" BPY_PROPDEF_POINTER_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC
BPY_PROPDEF_POLL_DOC BPY_PROPDEF_UPDATE_DOC);
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
@@ -4104,7 +4114,7 @@ PyDoc_STRVAR(BPy_CollectionProperty_doc,
"tags=set())\n"
"\n"
" Returns a new collection property definition.\n"
- "\n" BPY_PROPDEF_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
+ "\n" BPY_PROPDEF_COLLECTION_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_COLLECTION_DOC
BPY_PROPDEF_TAGS_DOC);
PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
@@ -4392,10 +4402,6 @@ PyObject *BPY_rna_props(void)
return submodule;
}
-/**
- * Run this on exit, clearing all Python callback users and disable the RNA callback,
- * as it would be called after Python has already finished.
- */
void BPY_rna_props_clear_all(void)
{
/* Remove all user counts, so this isn't considered a leak from Python's perspective. */
diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h
index e6bbd6f708d..9d739540919 100644
--- a/source/blender/python/intern/bpy_props.h
+++ b/source/blender/python/intern/bpy_props.h
@@ -25,6 +25,10 @@ extern "C" {
#endif
PyObject *BPY_rna_props(void);
+/**
+ * Run this on exit, clearing all Python callback users and disable the RNA callback,
+ * as it would be called after Python has already finished.
+ */
void BPY_rna_props_clear_all(void);
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw);
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 35acb56e66a..a79a0ed32bf 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -180,6 +180,15 @@ static PyObject *id_free_weakref_cb(PyObject *weakinfo_pair, PyObject *weakref);
static PyMethodDef id_free_weakref_cb_def = {
"id_free_weakref_cb", (PyCFunction)id_free_weakref_cb, METH_O, NULL};
+/**
+ * Only used when there are values left on exit (causing memory leaks).
+ */
+static void id_weakref_pool_free_value_fn(void *p)
+{
+ GHash *weakinfo_hash = p;
+ BLI_ghash_free(weakinfo_hash, NULL, NULL);
+}
+
/* Adds a reference to the list, remember to decref. */
static GHash *id_weakref_pool_get(ID *id)
{
@@ -1453,10 +1462,6 @@ PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
return ret;
}
-/**
- * This function is used by operators and converting dicts into collections.
- * It takes keyword args and fills them with property values.
- */
int pyrna_pydict_to_props(PointerRNA *ptr,
PyObject *kw,
const bool all_args,
@@ -5486,7 +5491,7 @@ static PyObject *pyprop_array_foreach_getset(BPy_PropertyArrayRNA *self,
}
else {
const char f = buf.format ? buf.format[0] : 0;
- if ((prop_type == PROP_INT && (buf.itemsize != sizeof(int) || (f != 'l' && f != 'i'))) ||
+ if ((prop_type == PROP_INT && (buf.itemsize != sizeof(int) || (!ELEM(f, 'l', 'i')))) ||
(prop_type == PROP_FLOAT && (buf.itemsize != sizeof(float) || f != 'f'))) {
PyBuffer_Release(&buf);
PyErr_Format(PyExc_TypeError, "incorrect sequence item type: %s", buf.format);
@@ -7238,7 +7243,7 @@ static PyObject *pyrna_srna_ExternalType(StructRNA *srna)
/* Sanity check, could skip this unless in debug mode. */
if (newclass) {
PyObject *base_compare = pyrna_srna_PyBase(srna);
- /* Can't do this because it gets superclasses values! */
+ /* Can't do this because it gets super-classes values! */
// PyObject *slots = PyObject_GetAttrString(newclass, "__slots__");
/* Can do this, but faster not to. */
// PyObject *bases = PyObject_GetAttrString(newclass, "__bases__");
@@ -7536,7 +7541,6 @@ PyObject *pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop)
return (PyObject *)pyrna;
}
-/* Utility func to be used by external modules, sneaky! */
PyObject *pyrna_id_CreatePyObject(ID *id)
{
if (id) {
@@ -7633,7 +7637,7 @@ void BPY_rna_exit(void)
printf("ID: %s\n", id->name);
}
}
- BLI_ghash_free(id_weakref_pool, NULL, NULL);
+ BLI_ghash_free(id_weakref_pool, NULL, id_weakref_pool_free_value_fn);
id_weakref_pool = NULL;
#endif
}
@@ -7684,7 +7688,7 @@ PyObject *BPY_rna_doc(void)
/**
* This could be a static variable as we only have one `bpy.types` module,
- * it just keeps the data isolated to store in the module it's self.
+ * it just keeps the data isolated to store in the module itself.
*
* This data doesn't change one initialized.
*/
@@ -7768,9 +7772,6 @@ static struct PyModuleDef bpy_types_module_def = {
NULL, /* m_free */
};
-/**
- * Accessed from Python as 'bpy.types'
- */
PyObject *BPY_rna_types(void)
{
PyObject *submodule = PyModule_Create(&bpy_types_module_def);
@@ -7855,11 +7856,6 @@ StructRNA *pyrna_struct_as_srna(PyObject *self, const bool parent, const char *e
}
/* Orphan functions, not sure where they should go. */
-/**
- * Get the SRNA for methods attached to types.
- *
- * Caller needs to raise error.
- */
StructRNA *srna_from_self(PyObject *self, const char *error_prefix)
{
@@ -8777,7 +8773,7 @@ void pyrna_free_types(void)
* - Should still be fixed - Campbell
*/
PyDoc_STRVAR(pyrna_register_class_doc,
- ".. method:: register_class(cls)\n"
+ ".. function:: register_class(cls)\n"
"\n"
" Register a subclass of a Blender type class.\n"
"\n"
@@ -8962,7 +8958,7 @@ static int pyrna_srna_contains_pointer_prop_srna(StructRNA *srna_props,
}
PyDoc_STRVAR(pyrna_unregister_class_doc,
- ".. method:: unregister_class(cls)\n"
+ ".. function:: unregister_class(cls)\n"
"\n"
" Unload the Python class from blender.\n"
"\n"
@@ -9085,9 +9081,6 @@ static PyObject *pyrna_unregister_class(PyObject *UNUSED(self), PyObject *py_cla
Py_RETURN_NONE;
}
-/**
- * Extend RNA types with C/API methods, properties.
- */
void pyrna_struct_type_extend_capi(struct StructRNA *srna,
struct PyMethodDef *method,
struct PyGetSetDef *getset)
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index f6a05a86311..b131aed6d23 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -178,7 +178,7 @@ typedef struct {
} BPy_FunctionRNA;
StructRNA *srna_from_self(PyObject *self, const char *error_prefix);
-StructRNA *pyrna_struct_as_srna(PyObject *self, const bool parent, const char *error_prefix);
+StructRNA *pyrna_struct_as_srna(PyObject *self, bool parent, const char *error_prefix);
void BPY_rna_init(void);
void BPY_rna_exit(void);
@@ -196,10 +196,7 @@ bool pyrna_id_FromPyObject(PyObject *obj, struct ID **id);
bool pyrna_id_CheckPyObject(PyObject *obj);
/* operators also need this to set args */
-int pyrna_pydict_to_props(PointerRNA *ptr,
- PyObject *kw,
- const bool all_args,
- const char *error_prefix);
+int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, bool all_args, const char *error_prefix);
PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop);
int pyrna_deferred_register_class(struct StructRNA *srna, PyTypeObject *py_class);
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 2096734ef96..9a6339c0a89 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -401,6 +401,10 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
return NULL;
}
+ if (result) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ }
+
return PyBool_FromLong(result);
}
diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c
index fcc796d4545..f3b1e357ebc 100644
--- a/source/blender/python/intern/bpy_rna_array.c
+++ b/source/blender/python/intern/bpy_rna_array.c
@@ -126,7 +126,7 @@ static int validate_array_type(PyObject *seq,
ok = 0;
}
else if ((item_seq_size = PySequence_Size(item)) == -1) {
- /* BLI_snprintf(error_str, error_str_size, "expected a sequence of %s", item_type_str); */
+ // BLI_snprintf(error_str, error_str_size, "expected a sequence of %s", item_type_str);
PyErr_Format(PyExc_TypeError,
"%s expected a sequence of %s, not %s",
error_prefix,
@@ -990,9 +990,10 @@ PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop)
return pyrna_prop_CreatePyObject(ptr, prop);
}
-/* TODO: multi-dimensional arrays. */
int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
{
+ /* TODO: multi-dimensional arrays. */
+
const int len = RNA_property_array_length(ptr, prop);
int type;
int i;
diff --git a/source/blender/python/intern/bpy_rna_callback.c b/source/blender/python/intern/bpy_rna_callback.c
index c19d9ba47b1..16ea4bf3e5e 100644
--- a/source/blender/python/intern/bpy_rna_callback.c
+++ b/source/blender/python/intern/bpy_rna_callback.c
@@ -255,6 +255,9 @@ static eSpace_Type rna_Space_refine_reverse(StructRNA *srna)
if (srna == &RNA_SpaceClipEditor) {
return SPACE_CLIP;
}
+ if (srna == &RNA_SpaceSpreadsheet) {
+ return SPACE_SPREADSHEET;
+ }
return SPACE_EMPTY;
}
@@ -380,6 +383,7 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar
void *handle;
StructRNA *srna;
bool capsule_clear = false;
+ bool handle_removed = false;
if (PyTuple_GET_SIZE(args) < 2) {
PyErr_SetString(PyExc_ValueError, "callback_remove(handler): expected at least 2 args");
@@ -403,7 +407,7 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar
args, "OO!:WindowManager.draw_cursor_remove", &cls, &PyCapsule_Type, &py_handle)) {
return NULL;
}
- WM_paint_cursor_end(handle);
+ handle_removed = WM_paint_cursor_end(handle);
capsule_clear = true;
}
else if (RNA_struct_is_a(srna, &RNA_Space)) {
@@ -442,7 +446,7 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar
params.region_type_enum.value_orig);
return NULL;
}
- ED_region_draw_cb_exit(art, handle);
+ handle_removed = ED_region_draw_cb_exit(art, handle);
capsule_clear = true;
}
else {
@@ -450,9 +454,14 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar
return NULL;
}
- /* The handle has been removed, so decrement its customdata. */
- PyObject *handle_args = PyCapsule_GetContext(py_handle);
- Py_DECREF(handle_args);
+ /* When `handle_removed == false`: Blender has already freed the data
+ * (freeing screen data when loading a new file for example).
+ * This will have already decremented the user, so don't decrement twice. */
+ if (handle_removed == true) {
+ /* The handle has been removed, so decrement its custom-data. */
+ PyObject *handle_args = PyCapsule_GetContext(py_handle);
+ Py_DECREF(handle_args);
+ }
/* don't allow reuse */
if (capsule_clear) {
diff --git a/source/blender/python/intern/bpy_rna_data.c b/source/blender/python/intern/bpy_rna_data.c
index 639999b69d4..c781fe4a4e7 100644
--- a/source/blender/python/intern/bpy_rna_data.c
+++ b/source/blender/python/intern/bpy_rna_data.c
@@ -177,7 +177,7 @@ static PyObject *bpy_rna_data_temp_data(PyObject *UNUSED(self), PyObject *args,
ret = PyObject_GC_New(BPy_DataContext, &bpy_rna_data_context_Type);
- STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->name);
+ STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->filepath);
return (PyObject *)ret;
}
diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c
index 3bddd0ad8c0..0bb8b1ba3e1 100644
--- a/source/blender/python/intern/bpy_rna_driver.c
+++ b/source/blender/python/intern/bpy_rna_driver.c
@@ -34,9 +34,6 @@
#include "bpy_rna_driver.h" /* own include */
-/**
- * A version of #driver_get_variable_value which returns a PyObject.
- */
PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar)
{
PyObject *driver_arg = NULL;
diff --git a/source/blender/python/intern/bpy_rna_driver.h b/source/blender/python/intern/bpy_rna_driver.h
index cc2c4550870..e34c7e4597c 100644
--- a/source/blender/python/intern/bpy_rna_driver.h
+++ b/source/blender/python/intern/bpy_rna_driver.h
@@ -28,6 +28,9 @@ struct PathResolvedRNA;
extern "C" {
#endif
+/**
+ * A version of #driver_get_variable_value which returns a #PyObject.
+ */
PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar);
PyObject *pyrna_driver_self_from_anim_rna(struct PathResolvedRNA *anim_rna);
diff --git a/source/blender/python/intern/bpy_rna_gizmo.c b/source/blender/python/intern/bpy_rna_gizmo.c
index f121bfd6e36..e769fe7f4c2 100644
--- a/source/blender/python/intern/bpy_rna_gizmo.c
+++ b/source/blender/python/intern/bpy_rna_gizmo.c
@@ -17,7 +17,7 @@
/** \file
* \ingroup pythonintern
*
- * .
+ * This file defines utility methods for `bpy.types.Gizmo`.
*/
#include <Python.h>
@@ -44,6 +44,104 @@
#include "bpy_rna.h"
/* -------------------------------------------------------------------- */
+/** \name Parsing Utility Functions
+ *
+ * Functions used as callbacks for #PyArg_ParseTuple `O&` format string.
+ * \{ */
+
+struct BPyGizmoWithTarget {
+ wmGizmo *gz; /* Must be first. */
+ wmGizmoProperty *gz_prop;
+};
+
+struct BPyGizmoWithTargetType {
+ wmGizmo *gz; /* Must be first. */
+ const wmGizmoPropertyType *gz_prop_type;
+};
+
+static int py_rna_gizmo_parse(PyObject *o, void *p)
+{
+ /* No type checking (this is `self` not a user defined argument). */
+ BLI_assert(BPy_StructRNA_Check(o));
+ BLI_assert(RNA_struct_is_a(((const BPy_StructRNA *)o)->ptr.type, &RNA_Gizmo));
+
+ wmGizmo **gz_p = p;
+ *gz_p = ((const BPy_StructRNA *)o)->ptr.data;
+ return 1;
+}
+
+static int py_rna_gizmo_target_id_parse(PyObject *o, void *p)
+{
+ struct BPyGizmoWithTarget *gizmo_with_target = p;
+ /* Must be set by `py_rna_gizmo_parse`. */
+ wmGizmo *gz = gizmo_with_target->gz;
+ BLI_assert(gz != NULL);
+
+ if (!PyUnicode_Check(o)) {
+ PyErr_Format(PyExc_TypeError, "expected a string (got %.200s)", Py_TYPE(o)->tp_name);
+ return 0;
+ }
+ const char *gz_prop_id = PyUnicode_AsUTF8(o);
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, gz_prop_id);
+ if (gz_prop == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "Gizmo target property '%s.%s' not found!",
+ gz->type->idname,
+ gz_prop_id);
+ return 0;
+ }
+ gizmo_with_target->gz_prop = gz_prop;
+ return 1;
+}
+
+static int py_rna_gizmo_target_id_parse_and_ensure_is_valid(PyObject *o, void *p)
+{
+ if (py_rna_gizmo_target_id_parse(o, p) == 0) {
+ return 0;
+ }
+ struct BPyGizmoWithTarget *gizmo_with_target = p;
+ wmGizmo *gz = gizmo_with_target->gz;
+ wmGizmoProperty *gz_prop = gizmo_with_target->gz_prop;
+ if (!WM_gizmo_target_property_is_valid(gz_prop)) {
+ const char *gz_prop_id = PyUnicode_AsUTF8(o);
+ PyErr_Format(PyExc_ValueError,
+ "Gizmo target property '%s.%s' has not been initialized, "
+ "Call \"target_set_prop\" first!",
+ gz->type->idname,
+ gz_prop_id);
+ return 0;
+ }
+ return 1;
+}
+
+static int py_rna_gizmo_target_type_id_parse(PyObject *o, void *p)
+{
+ struct BPyGizmoWithTargetType *gizmo_with_target = p;
+ /* Must be set first. */
+ wmGizmo *gz = gizmo_with_target->gz;
+ BLI_assert(gz != NULL);
+
+ if (!PyUnicode_Check(o)) {
+ PyErr_Format(PyExc_TypeError, "expected a string (got %.200s)", Py_TYPE(o)->tp_name);
+ return 0;
+ }
+ const char *gz_prop_id = PyUnicode_AsUTF8(o);
+ const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(gz->type,
+ gz_prop_id);
+ if (gz_prop_type == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "Gizmo target property '%s.%s' not found!",
+ gz->type->idname,
+ gz_prop_id);
+ return 0;
+ }
+ gizmo_with_target->gz_prop_type = gz_prop_type;
+ return 1;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Gizmo Target Property Define API
* \{ */
@@ -103,7 +201,7 @@ fail:
PyErr_Print();
PyErr_Clear();
- Py_DECREF(ret);
+ Py_XDECREF(ret);
PyGILState_Release(gilstate);
}
@@ -240,12 +338,10 @@ static PyObject *bpy_gizmo_target_set_handler(PyObject *UNUSED(self), PyObject *
const PyGILState_STATE gilstate = PyGILState_Ensure();
struct {
- PyObject *self;
- char *target;
+ struct BPyGizmoWithTargetType gz_with_target_type;
PyObject *py_fn_slots[BPY_GIZMO_FN_SLOT_LEN];
} params = {
- .self = NULL,
- .target = NULL,
+ .gz_with_target_type = {NULL, NULL},
.py_fn_slots = {NULL},
};
@@ -253,29 +349,25 @@ static PyObject *bpy_gizmo_target_set_handler(PyObject *UNUSED(self), PyObject *
* 'Gizmo.target_set_prop & target_set_operator'
* (see: rna_wm_gizmo_api.c). conventions should match. */
static const char *const _keywords[] = {"self", "target", "get", "set", "range", NULL};
- static _PyArg_Parser _parser = {"Os|$OOO:target_set_handler", _keywords, 0};
+ static _PyArg_Parser _parser = {"O&O&|$OOO:target_set_handler", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kw,
&_parser,
- &params.self,
- &params.target,
+ /* `self` */
+ py_rna_gizmo_parse,
+ &params.gz_with_target_type.gz,
+ /* `target` */
+ py_rna_gizmo_target_type_id_parse,
+ &params.gz_with_target_type,
+ /* `get/set/range` */
&params.py_fn_slots[BPY_GIZMO_FN_SLOT_GET],
&params.py_fn_slots[BPY_GIZMO_FN_SLOT_SET],
&params.py_fn_slots[BPY_GIZMO_FN_SLOT_RANGE_GET])) {
goto fail;
}
- wmGizmo *gz = ((BPy_StructRNA *)params.self)->ptr.data;
-
- const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(gz->type,
- params.target);
- if (gz_prop_type == NULL) {
- PyErr_Format(PyExc_ValueError,
- "Gizmo target property '%s.%s' not found",
- gz->type->idname,
- params.target);
- goto fail;
- }
+ wmGizmo *gz = params.gz_with_target_type.gz;
+ const wmGizmoPropertyType *gz_prop_type = params.gz_with_target_type.gz_prop_type;
{
const int slots_required = 2;
@@ -338,29 +430,27 @@ PyDoc_STRVAR(bpy_gizmo_target_get_value_doc,
static PyObject *bpy_gizmo_target_get_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
struct {
- PyObject *self;
- char *target;
+ struct BPyGizmoWithTarget gz_with_target;
} params = {
- .self = NULL,
- .target = NULL,
+ .gz_with_target = {NULL, NULL},
};
static const char *const _keywords[] = {"self", "target", NULL};
- static _PyArg_Parser _parser = {"Os:target_get_value", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &params.self, &params.target)) {
+ static _PyArg_Parser _parser = {"O&O&:target_get_value", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(args,
+ kw,
+ &_parser,
+ /* `self` */
+ py_rna_gizmo_parse,
+ &params.gz_with_target.gz,
+ /* `target` */
+ py_rna_gizmo_target_id_parse_and_ensure_is_valid,
+ &params.gz_with_target)) {
goto fail;
}
- wmGizmo *gz = ((BPy_StructRNA *)params.self)->ptr.data;
-
- wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, params.target);
- if (gz_prop == NULL) {
- PyErr_Format(PyExc_ValueError,
- "Gizmo target property '%s.%s' not found",
- gz->type->idname,
- params.target);
- goto fail;
- }
+ wmGizmo *gz = params.gz_with_target.gz;
+ wmGizmoProperty *gz_prop = params.gz_with_target.gz_prop;
const int array_len = WM_gizmo_target_property_array_length(gz, gz_prop);
switch (gz_prop->type->data_type) {
@@ -396,32 +486,31 @@ PyDoc_STRVAR(bpy_gizmo_target_set_value_doc,
static PyObject *bpy_gizmo_target_set_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
struct {
- PyObject *self;
- char *target;
+ struct BPyGizmoWithTarget gz_with_target;
PyObject *value;
} params = {
- .self = NULL,
- .target = NULL,
+ .gz_with_target = {NULL, NULL},
.value = NULL,
};
static const char *const _keywords[] = {"self", "target", "value", NULL};
- static _PyArg_Parser _parser = {"OsO:target_set_value", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(
- args, kw, &_parser, &params.self, &params.target, &params.value)) {
+ static _PyArg_Parser _parser = {"O&O&O:target_set_value", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(args,
+ kw,
+ &_parser,
+ /* `self` */
+ py_rna_gizmo_parse,
+ &params.gz_with_target.gz,
+ /* `target` */
+ py_rna_gizmo_target_id_parse_and_ensure_is_valid,
+ &params.gz_with_target,
+ /* `value` */
+ &params.value)) {
goto fail;
}
- wmGizmo *gz = ((BPy_StructRNA *)params.self)->ptr.data;
-
- wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, params.target);
- if (gz_prop == NULL) {
- PyErr_Format(PyExc_ValueError,
- "Gizmo target property '%s.%s' not found",
- gz->type->idname,
- params.target);
- goto fail;
- }
+ wmGizmo *gz = params.gz_with_target.gz;
+ wmGizmoProperty *gz_prop = params.gz_with_target.gz_prop;
const int array_len = WM_gizmo_target_property_array_length(gz, gz_prop);
switch (gz_prop->type->data_type) {
@@ -468,29 +557,27 @@ PyDoc_STRVAR(bpy_gizmo_target_get_range_doc,
static PyObject *bpy_gizmo_target_get_range(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
struct {
- PyObject *self;
- char *target;
+ struct BPyGizmoWithTarget gz_with_target;
} params = {
- .self = NULL,
- .target = NULL,
+ .gz_with_target = {NULL, NULL},
};
static const char *const _keywords[] = {"self", "target", NULL};
- static _PyArg_Parser _parser = {"Os:target_get_range", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &params.self, &params.target)) {
+ static _PyArg_Parser _parser = {"O&O&:target_get_range", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(args,
+ kw,
+ &_parser,
+ /* `self` */
+ py_rna_gizmo_parse,
+ &params.gz_with_target.gz,
+ /* `target` */
+ py_rna_gizmo_target_id_parse_and_ensure_is_valid,
+ &params.gz_with_target)) {
goto fail;
}
- wmGizmo *gz = ((BPy_StructRNA *)params.self)->ptr.data;
-
- wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, params.target);
- if (gz_prop == NULL) {
- PyErr_Format(PyExc_ValueError,
- "Gizmo target property '%s.%s' not found",
- gz->type->idname,
- params.target);
- goto fail;
- }
+ wmGizmo *gz = params.gz_with_target.gz;
+ wmGizmoProperty *gz_prop = params.gz_with_target.gz_prop;
switch (gz_prop->type->data_type) {
case PROP_FLOAT: {
@@ -510,6 +597,10 @@ fail:
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Gizmo Module
+ * \{ */
+
bool BPY_rna_gizmo_module(PyObject *mod_par)
{
static PyMethodDef method_def_array[] = {
@@ -546,3 +637,5 @@ bool BPY_rna_gizmo_module(PyObject *mod_par)
return false;
}
+
+/** \} */
diff --git a/source/blender/python/intern/bpy_rna_operator.c b/source/blender/python/intern/bpy_rna_operator.c
index d3ec54fc12d..d24e2a77a75 100644
--- a/source/blender/python/intern/bpy_rna_operator.c
+++ b/source/blender/python/intern/bpy_rna_operator.c
@@ -103,7 +103,7 @@ PyDoc_STRVAR(BPY_rna_operator_poll_message_set_doc,
static PyObject *BPY_rna_operator_poll_message_set(PyObject *UNUSED(self), PyObject *args)
{
- const ssize_t args_len = PyTuple_GET_SIZE(args);
+ const Py_ssize_t args_len = PyTuple_GET_SIZE(args);
if (args_len == 0) {
PyErr_SetString(PyExc_ValueError,
"poll_message_set(message, ...): requires a message argument");
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 0043fc36162..6eee9ceebb8 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -77,11 +77,6 @@ static int mathutils_array_parse_fast(float *array,
return size;
}
-/**
- * helper function that returns a Python `__hash__`.
- *
- * \note consistent with the equivalent tuple of floats (CPython's 'tuplehash')
- */
Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
{
int i;
@@ -114,7 +109,6 @@ Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
return x;
}
-/* helper function returns length of the 'value', -1 on error */
int mathutils_array_parse(
float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
{
@@ -211,7 +205,6 @@ int mathutils_array_parse(
return size;
}
-/* on error, -1 is returned and no allocation is made */
int mathutils_array_parse_alloc(float **array,
int array_min,
PyObject *value,
@@ -279,7 +272,6 @@ int mathutils_array_parse_alloc(float **array,
return ret;
}
-/* parse an array of vectors */
int mathutils_array_parse_alloc_v(float **array,
int array_dim,
PyObject *value,
@@ -321,7 +313,6 @@ int mathutils_array_parse_alloc_v(float **array,
return size;
}
-/* Parse an sequence array_dim integers into array. */
int mathutils_int_array_parse(int *array, int array_dim, PyObject *value, const char *error_prefix)
{
int size, i;
@@ -357,7 +348,6 @@ int mathutils_int_array_parse(int *array, int array_dim, PyObject *value, const
return size;
}
-/* Parse sequence of array_dim sequences of integers and return allocated result. */
int mathutils_array_parse_alloc_vi(int **array,
int array_dim,
PyObject *value,
@@ -395,12 +385,6 @@ int mathutils_array_parse_alloc_vi(int **array,
return size;
}
-/* Parse sequence of variable-length sequences of int and return allocated
- * triple of arrays to represent the result:
- * The flattened sequences are put into *array.
- * The start index of each sequence goes into start_table.
- * The length of each index goes into len_table.
- */
int mathutils_array_parse_alloc_viseq(
int **array, int **start_table, int **len_table, PyObject *value, const char *error_prefix)
{
@@ -560,7 +544,6 @@ int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int flo
}
#ifndef MATH_STANDALONE
-/* dynstr as python string utility functions, frees 'ds'! */
PyObject *mathutils_dynstr_to_py(struct DynStr *ds)
{
const int ds_len = BLI_dynstr_get_len(ds); /* space for \0 */
diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h
index 4aa26dcc5be..d73d2afe69b 100644
--- a/source/blender/python/mathutils/mathutils.h
+++ b/source/blender/python/mathutils/mathutils.h
@@ -162,28 +162,56 @@ void _BaseMathObject_RaiseNotFrozenExc(const BaseMathObject *self);
0)
/* utility func */
+/**
+ * Helper function.
+ * \return length of `value`, -1 on error.
+ */
int mathutils_array_parse(
float *array, int array_min, int array_max, PyObject *value, const char *error_prefix);
+/**
+ * \return -1 is returned on error and no allocation is made.
+ */
int mathutils_array_parse_alloc(float **array,
int array_min,
PyObject *value,
const char *error_prefix);
+/**
+ * Parse an array of vectors.
+ */
int mathutils_array_parse_alloc_v(float **array,
int array_dim,
PyObject *value,
const char *error_prefix);
+/**
+ * Parse an sequence array_dim integers into array.
+ */
int mathutils_int_array_parse(int *array,
int array_dim,
PyObject *value,
const char *error_prefix);
+/**
+ * Parse sequence of array_dim sequences of integers and return allocated result.
+ */
int mathutils_array_parse_alloc_vi(int **array,
int array_dim,
PyObject *value,
const char *error_prefix);
+/**
+ * Parse sequence of variable-length sequences of int and return allocated
+ * triple of arrays to represent the result:
+ * The flattened sequences are put into *array.
+ * The start index of each sequence goes into start_table.
+ * The length of each index goes into len_table.
+ */
int mathutils_array_parse_alloc_viseq(
int **array, int **start_table, int **len_table, PyObject *value, const char *error_prefix);
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix);
+/**
+ * helper function that returns a Python `__hash__`.
+ *
+ * \note consistent with the equivalent tuple of floats (CPython's 'tuplehash')
+ */
Py_hash_t mathutils_array_hash(const float *float_array, size_t array_len);
/* zero remaining unused elements of the array */
@@ -194,9 +222,21 @@ Py_hash_t mathutils_array_hash(const float *float_array, size_t array_len);
#define MU_ARRAY_FLAGS (MU_ARRAY_ZERO | MU_ARRAY_SPILL)
+/**
+ * Column vector multiplication (Matrix * Vector).
+ * <pre>
+ * [1][4][7] [a]
+ * [2][5][8] * [b]
+ * [3][6][9] [c]
+ * </pre>
+ *
+ * \note Vector/Matrix multiplication is not commutative.
+ * \note Assume read callbacks have been done first.
+ */
int column_vector_multiplication(float r_vec[4], VectorObject *vec, MatrixObject *mat);
#ifndef MATH_STANDALONE
/* dynstr as python string utility functions */
+/* dynstr as python string utility functions, frees 'ds'! */
PyObject *mathutils_dynstr_to_py(struct DynStr *ds);
#endif
diff --git a/source/blender/python/mathutils/mathutils_Euler.h b/source/blender/python/mathutils/mathutils_Euler.h
index 0deef3cfdf3..453a3b3736e 100644
--- a/source/blender/python/mathutils/mathutils_Euler.h
+++ b/source/blender/python/mathutils/mathutils_Euler.h
@@ -37,14 +37,14 @@ typedef struct {
/* prototypes */
PyObject *Euler_CreatePyObject(const float eul[3],
- const short order,
+ short order,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
PyObject *Euler_CreatePyObject_wrap(float eul[3],
- const short order,
+ short order,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
PyObject *Euler_CreatePyObject_cb(PyObject *cb_user,
- const short order,
+ short order,
unsigned char cb_type,
unsigned char cb_subtype) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index ce04a143aae..4396e2f9c7b 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -526,7 +526,7 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
"cannot create a 2x2 rotation matrix around arbitrary axis");
return NULL;
}
- if ((matSize == 3 || matSize == 4) && (axis == NULL) && (vec == NULL)) {
+ if ((ELEM(matSize, 3, 4)) && (axis == NULL) && (vec == NULL)) {
PyErr_SetString(PyExc_ValueError,
"Matrix.Rotation(): "
"axis of rotation for 3d and 4d matrices is required");
@@ -3382,9 +3382,6 @@ PyObject *Matrix_CreatePyObject_cb(
return (PyObject *)self;
}
-/**
- * \param mat: Initialized matrix value to use in-place, allocated with #PyMem_Malloc
- */
PyObject *Matrix_CreatePyObject_alloc(float *mat,
const ushort num_col,
const ushort num_row,
diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h
index 588c0b94891..3067c5417b9 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.h
+++ b/source/blender/python/mathutils/mathutils_Matrix.h
@@ -61,23 +61,26 @@ typedef struct {
/* prototypes */
PyObject *Matrix_CreatePyObject(const float *mat,
- const ushort num_col,
- const ushort num_row,
+ ushort num_col,
+ ushort num_row,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
PyObject *Matrix_CreatePyObject_wrap(float *mat,
- const ushort num_col,
- const ushort num_row,
+ ushort num_col,
+ ushort num_row,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
PyObject *Matrix_CreatePyObject_cb(PyObject *user,
- const unsigned short num_col,
- const unsigned short num_row,
+ unsigned short num_col,
+ unsigned short num_row,
unsigned char cb_type,
unsigned char cb_subtype) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \param mat: Initialized matrix value to use in-place, allocated with #PyMem_Malloc
+ */
PyObject *Matrix_CreatePyObject_alloc(float *mat,
- const ushort num_col,
- const ushort num_row,
+ ushort num_col,
+ ushort num_row,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
/* PyArg_ParseTuple's "O&" formatting helpers. */
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index 525b2da7d06..8c333413d74 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -320,7 +320,7 @@ static PyObject *Quaternion_rotation_difference(QuaternionObject *self, PyObject
QUAT_SIZE,
QUAT_SIZE,
value,
- "Quaternion.difference(other), invalid 'other' arg") == -1) {
+ "Quaternion.rotation_difference(other), invalid 'other' arg") == -1) {
return NULL;
}
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 23758c5603e..daaf3b3da26 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -1676,17 +1676,6 @@ static PyObject *Vector_isub(PyObject *v1, PyObject *v2)
/*------------------------obj * obj------------------------------
* multiplication */
-/**
- * Column vector multiplication (Matrix * Vector).
- * <pre>
- * [1][4][7] [a]
- * [2][5][8] * [b]
- * [3][6][9] [c]
- * </pre>
- *
- * \note Vector/Matrix multiplication is not commutative.
- * \note Assume read callbacks have been done first.
- */
int column_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat)
{
float vec_cpy[MAX_DIMENSIONS];
@@ -3166,11 +3155,6 @@ PyObject *Vector_CreatePyObject(const float *vec, const int size, PyTypeObject *
return (PyObject *)self;
}
-/**
- * Create a vector that wraps existing memory.
- *
- * \param vec: Use this vector in-place.
- */
PyObject *Vector_CreatePyObject_wrap(float *vec, const int size, PyTypeObject *base_type)
{
VectorObject *self;
@@ -3194,10 +3178,6 @@ PyObject *Vector_CreatePyObject_wrap(float *vec, const int size, PyTypeObject *b
return (PyObject *)self;
}
-/**
- * Create a vector where the value is defined by registered callbacks,
- * see: #Mathutils_RegisterCallback
- */
PyObject *Vector_CreatePyObject_cb(PyObject *cb_user, int size, uchar cb_type, uchar cb_subtype)
{
VectorObject *self = (VectorObject *)Vector_CreatePyObject(NULL, size, NULL);
@@ -3212,9 +3192,6 @@ PyObject *Vector_CreatePyObject_cb(PyObject *cb_user, int size, uchar cb_type, u
return (PyObject *)self;
}
-/**
- * \param vec: Initialized vector value to use in-place, allocated with #PyMem_Malloc
- */
PyObject *Vector_CreatePyObject_alloc(float *vec, const int size, PyTypeObject *base_type)
{
VectorObject *self;
diff --git a/source/blender/python/mathutils/mathutils_Vector.h b/source/blender/python/mathutils/mathutils_Vector.h
index 09fc429f9cc..50609e51b0a 100644
--- a/source/blender/python/mathutils/mathutils_Vector.h
+++ b/source/blender/python/mathutils/mathutils_Vector.h
@@ -33,17 +33,29 @@ typedef struct {
/*prototypes*/
PyObject *Vector_CreatePyObject(const float *vec,
- const int size,
+ int size,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Create a vector that wraps existing memory.
+ *
+ * \param vec: Use this vector in-place.
+ */
PyObject *Vector_CreatePyObject_wrap(float *vec,
- const int size,
+ int size,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Create a vector where the value is defined by registered callbacks,
+ * see: #Mathutils_RegisterCallback
+ */
PyObject *Vector_CreatePyObject_cb(PyObject *user,
int size,
unsigned char cb_type,
unsigned char subtype) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \param vec: Initialized vector value to use in-place, allocated with #PyMem_Malloc
+ */
PyObject *Vector_CreatePyObject_alloc(float *vec,
- const int size,
+ int size,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index d47b59d0c76..b8244efbee2 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -1236,7 +1236,7 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject
polyLine = PySequence_GetItem(polyLineSeq, i);
if (!PySequence_Check(polyLine)) {
BKE_displist_free(&dispbase);
- Py_XDECREF(polyLine); /* may be null so use Py_XDECREF*/
+ Py_XDECREF(polyLine); /* May be null so use #Py_XDECREF. */
PyErr_SetString(PyExc_TypeError,
"One or more of the polylines is not a sequence of mathutils.Vector's");
return NULL;
diff --git a/source/blender/python/mathutils/mathutils_noise.c b/source/blender/python/mathutils/mathutils_noise.c
index 69d37b345c6..d5e27496af8 100644
--- a/source/blender/python/mathutils/mathutils_noise.c
+++ b/source/blender/python/mathutils/mathutils_noise.c
@@ -562,7 +562,7 @@ PyDoc_STRVAR(M_Noise_turbulence_vector_doc,
" :type octaves: int\n"
" :arg hard: Specifies whether returned turbulence is hard (sharp transitions) or "
"soft (smooth transitions).\n"
- " :type hard: :boolean\n" BPY_NOISE_BASIS_ENUM_DOC
+ " :type hard: boolean\n" BPY_NOISE_BASIS_ENUM_DOC
" :arg amplitude_scale: The amplitude scaling factor.\n"
" :type amplitude_scale: float\n"
" :arg frequency_scale: The frequency scaling factor\n"
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index 494415a4077..a7c1b12982c 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -49,6 +49,7 @@ set(SRC
intern/pipeline.c
intern/render_result.c
intern/texture_image.c
+ intern/texture_margin.cc
intern/texture_pointdensity.c
intern/texture_procedural.c
intern/zbuf.c
@@ -58,6 +59,7 @@ set(SRC
RE_multires_bake.h
RE_pipeline.h
RE_texture.h
+ RE_texture_margin.h
intern/pipeline.h
intern/render_result.h
diff --git a/source/blender/render/RE_bake.h b/source/blender/render/RE_bake.h
index 47a15199701..d3025bf4198 100644
--- a/source/blender/render/RE_bake.h
+++ b/source/blender/render/RE_bake.h
@@ -25,6 +25,7 @@
struct Depsgraph;
struct ImBuf;
+struct MLoopUV;
struct Mesh;
struct Render;
@@ -81,59 +82,68 @@ bool RE_bake_has_engine(const struct Render *re);
bool RE_bake_engine(struct Render *re,
struct Depsgraph *depsgraph,
struct Object *object,
- const int object_id,
+ int object_id,
const BakePixel pixel_array[],
const BakeTargets *targets,
- const eScenePassType pass_type,
- const int pass_filter,
+ eScenePassType pass_type,
+ int pass_filter,
float result[]);
/* bake.c */
-int RE_pass_depth(const eScenePassType pass_type);
+int RE_pass_depth(eScenePassType pass_type);
bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low,
BakePixel pixel_array_from[],
BakePixel pixel_array_to[],
BakeHighPolyData highpoly[],
- const int tot_highpoly,
- const size_t num_pixels,
- const bool is_custom_cage,
- const float cage_extrusion,
- const float max_ray_distance,
+ int tot_highpoly,
+ size_t num_pixels,
+ bool is_custom_cage,
+ float cage_extrusion,
+ float max_ray_distance,
float mat_low[4][4],
float mat_cage[4][4],
struct Mesh *me_cage);
void RE_bake_pixels_populate(struct Mesh *me,
struct BakePixel *pixel_array,
- const size_t num_pixels,
+ size_t num_pixels,
const struct BakeTargets *targets,
const char *uv_layer);
-void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, char *mask);
+void RE_bake_mask_fill(const BakePixel pixel_array[], size_t num_pixels, char *mask);
-void RE_bake_margin(struct ImBuf *ibuf, char *mask, const int margin);
+void RE_bake_margin(struct ImBuf *ibuf,
+ char *mask,
+ int margin,
+ char margin_type,
+ struct Mesh const *me,
+ char const *uv_layer);
void RE_bake_normal_world_to_object(const BakePixel pixel_array[],
- const size_t num_pixels,
- const int depth,
+ size_t num_pixels,
+ int depth,
float result[],
struct Object *ob,
const eBakeNormalSwizzle normal_swizzle[3]);
+/**
+ * This function converts an object space normal map
+ * to a tangent space normal map for a given low poly mesh.
+ */
void RE_bake_normal_world_to_tangent(const BakePixel pixel_array[],
- const size_t num_pixels,
- const int depth,
+ size_t num_pixels,
+ int depth,
float result[],
struct Mesh *me,
const eBakeNormalSwizzle normal_swizzle[3],
float mat[4][4]);
void RE_bake_normal_world_to_world(const BakePixel pixel_array[],
- const size_t num_pixels,
- const int depth,
+ size_t num_pixels,
+ int depth,
float result[],
const eBakeNormalSwizzle normal_swizzle[3]);
-void RE_bake_ibuf_clear(struct Image *image, const bool is_tangent);
+void RE_bake_ibuf_clear(struct Image *image, bool is_tangent);
#ifdef __cplusplus
}
diff --git a/source/blender/render/RE_engine.h b/source/blender/render/RE_engine.h
index 2a3a5964262..c0bd8c0fe4e 100644
--- a/source/blender/render/RE_engine.h
+++ b/source/blender/render/RE_engine.h
@@ -106,10 +106,10 @@ typedef struct RenderEngineType {
void (*bake)(struct RenderEngine *engine,
struct Depsgraph *depsgraph,
struct Object *object,
- const int pass_type,
- const int pass_filter,
- const int width,
- const int height);
+ int pass_type,
+ int pass_filter,
+ int width,
+ int height);
void (*view_update)(struct RenderEngine *engine,
const struct bContext *context,
@@ -180,6 +180,10 @@ typedef struct RenderEngine {
RenderEngine *RE_engine_create(RenderEngineType *type);
void RE_engine_free(RenderEngine *engine);
+/**
+ * Loads in image into a result, size must match
+ * x/y offsets are only used on a partial copy when dimensions don't match.
+ */
void RE_layer_load_from_file(
struct RenderLayer *layer, struct ReportList *reports, const char *filename, int x, int y);
void RE_result_load_from_file(struct RenderResult *result,
diff --git a/source/blender/render/RE_multires_bake.h b/source/blender/render/RE_multires_bake.h
index 42ee2c57fbb..6df80c27c40 100644
--- a/source/blender/render/RE_multires_bake.h
+++ b/source/blender/render/RE_multires_bake.h
@@ -33,7 +33,8 @@ extern "C" {
typedef struct MultiresBakeRender {
Scene *scene;
DerivedMesh *lores_dm, *hires_dm;
- int bake_filter; /* Bake-filter, aka margin */
+ int bake_margin;
+ char bake_margin_type;
int lvl, tot_lvl;
short mode;
bool use_lores_mesh; /* Use low-resolution mesh when baking displacement maps */
diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h
index 640bcc0cdf5..072fc7363b2 100644
--- a/source/blender/render/RE_pipeline.h
+++ b/source/blender/render/RE_pipeline.h
@@ -167,8 +167,10 @@ typedef struct RenderStats {
/* *********************** API ******************** */
-/* the name is used as identifier, so elsewhere in blender the result can retrieved */
-/* calling a new render with same name, frees automatic existing render */
+/**
+ * The name is used as identifier, so elsewhere in blender the result can retrieved.
+ * Calling a new render with same name, frees automatic existing render.
+ */
struct Render *RE_NewRender(const char *name);
struct Render *RE_GetRender(const char *name);
@@ -176,45 +178,89 @@ struct Scene;
struct Render *RE_NewSceneRender(const struct Scene *scene);
struct Render *RE_GetSceneRender(const struct Scene *scene);
-/* assign default dummy callbacks */
+/* Assign default dummy callbacks. */
+
+/**
+ * Called for new renders and when finishing rendering
+ * so we always have valid callbacks on a render.
+ */
void RE_InitRenderCB(struct Render *re);
-/* use free render as signal to do everything over (previews) */
+/**
+ * Use free render as signal to do everything over (previews).
+ *
+ * Only call this while you know it will remove the link too.
+ */
void RE_FreeRender(struct Render *re);
-/* only called on exit */
+/**
+ * Only called on exit.
+ */
void RE_FreeAllRender(void);
-/* On file load, free render results. */
+/**
+ * On file load, free render results.
+ */
void RE_FreeAllRenderResults(void);
-/* On file load or changes engines, free persistent render data.
- * Assumes no engines are currently rendering. */
+/**
+ * On file load or changes engines, free persistent render data.
+ * Assumes no engines are currently rendering.
+ */
void RE_FreeAllPersistentData(void);
-/* Free persistent render data, optionally only for the given scene. */
+/**
+ * Free persistent render data, optionally only for the given scene.
+ */
void RE_FreePersistentData(const Scene *scene);
-/* get results and statistics */
+/**
+ * Get results and statistics.
+ */
void RE_FreeRenderResult(struct RenderResult *rr);
+/**
+ * If you want to know exactly what has been done.
+ */
struct RenderResult *RE_AcquireResultRead(struct Render *re);
struct RenderResult *RE_AcquireResultWrite(struct Render *re);
void RE_ReleaseResult(struct Render *re);
+/**
+ * Same as #RE_AcquireResultImage but creating the necessary views to store the result
+ * fill provided result struct with a copy of thew views of what is done so far the
+ * #RenderResult.views #ListBase needs to be freed after with #RE_ReleaseResultImageViews
+ */
void RE_AcquireResultImageViews(struct Render *re, struct RenderResult *rr);
+/**
+ * Clear temporary #RenderResult struct.
+ */
void RE_ReleaseResultImageViews(struct Render *re, struct RenderResult *rr);
-void RE_AcquireResultImage(struct Render *re, struct RenderResult *rr, const int view_id);
+
+/**
+ * Fill provided result struct with what's currently active or done.
+ * This #RenderResult struct is the only exception to the rule of a #RenderResult
+ * always having at least one #RenderView.
+ */
+void RE_AcquireResultImage(struct Render *re, struct RenderResult *rr, int view_id);
void RE_ReleaseResultImage(struct Render *re);
void RE_SwapResult(struct Render *re, struct RenderResult **rr);
void RE_ClearResult(struct Render *re);
struct RenderStats *RE_GetStats(struct Render *re);
+/**
+ * Caller is responsible for allocating `rect` in correct size!
+ */
void RE_ResultGet32(struct Render *re, unsigned int *rect);
+/**
+ * Only for acquired results, for lock.
+ *
+ * \note The caller is responsible for allocating `rect` in correct size!
+ */
void RE_AcquiredResultGet32(struct Render *re,
struct RenderResult *result,
unsigned int *rect,
- const int view_id);
+ int view_id);
void RE_render_result_rect_from_ibuf(struct RenderResult *rr,
struct RenderData *rd,
struct ImBuf *ibuf,
- const int view_id);
+ int view_id);
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl,
@@ -223,7 +269,10 @@ float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl,
bool RE_HasSingleLayer(struct Render *re);
-/* add passes for grease pencil */
+/**
+ * Add passes for grease pencil.
+ * Create a render-layer and render-pass for grease-pencil layer.
+ */
struct RenderPass *RE_create_gp_pass(struct RenderResult *rr,
const char *layername,
const char *viewname);
@@ -233,9 +282,13 @@ void RE_create_render_pass(struct RenderResult *rr,
int channels,
const char *chan_id,
const char *layername,
- const char *viewname);
+ const char *viewname,
+ bool allocate);
-/* obligatory initialize call, disprect is optional */
+/**
+ * Obligatory initialize call, doesn't change during entire render sequence.
+ * \param disprect: is optional. if NULL it assumes full window render.
+ */
void RE_InitState(struct Render *re,
struct Render *source,
struct RenderData *rd,
@@ -245,21 +298,34 @@ void RE_InitState(struct Render *re,
int winy,
rcti *disprect);
-/* set up the viewplane/perspective matrix, three choices */
-struct Object *RE_GetCamera(struct Render *re); /* return camera override if set */
+/**
+ * Set up the view-plane/perspective matrix, three choices.
+ *
+ * \return camera override if set.
+ */
+struct Object *RE_GetCamera(struct Render *re);
void RE_SetOverrideCamera(struct Render *re, struct Object *cam_ob);
-void RE_SetCamera(struct Render *re, const struct Object *cam_ob);
+/**
+ * Per render, there's one persistent view-plane. Parts will set their own view-planes.
+ *
+ * \note call this after #RE_InitState().
+ */
+void RE_SetCamera(struct Render *re, struct Object *cam_ob);
-/* get current view and window transform */
+/**
+ * Get current view and window transform.
+ */
void RE_GetViewPlane(struct Render *re, rctf *r_viewplane, rcti *r_disprect);
-/* Set the render threads based on the command-line and auto-threads setting. */
+/**
+ * Set the render threads based on the command-line and auto-threads setting.
+ */
void RE_init_threadcount(Render *re);
bool RE_WriteRenderViewsImage(struct ReportList *reports,
struct RenderResult *rr,
struct Scene *scene,
- const bool stamp,
+ bool stamp,
char *name);
bool RE_WriteRenderViewsMovie(struct ReportList *reports,
struct RenderResult *rr,
@@ -267,17 +333,24 @@ bool RE_WriteRenderViewsMovie(struct ReportList *reports,
struct RenderData *rd,
struct bMovieHandle *mh,
void **movie_ctx_arr,
- const int totvideos,
+ int totvideos,
bool preview);
-/* only RE_NewRender() needed, main Blender render calls */
+/**
+ * Only #RE_NewRender() needed, main Blender render calls.
+ *
+ * General Blender frame render call.
+ */
void RE_RenderFrame(struct Render *re,
struct Main *bmain,
struct Scene *scene,
struct ViewLayer *single_layer,
struct Object *camera_override,
int frame,
- const bool write_still);
+ bool write_still);
+/**
+ * Saves images to disk.
+ */
void RE_RenderAnim(struct Render *re,
struct Main *bmain,
struct Scene *scene,
@@ -297,13 +370,24 @@ void RE_RenderFreestyleExternal(struct Render *re);
void RE_SetActiveRenderView(struct Render *re, const char *viewname);
const char *RE_GetActiveRenderView(struct Render *re);
-/* error reporting */
+/**
+ * Error reporting.
+ */
void RE_SetReports(struct Render *re, struct ReportList *reports);
-/* main preview render call */
+/**
+ * Main preview render call.
+ */
void RE_PreviewRender(struct Render *re, struct Main *bmain, struct Scene *scene);
+/**
+ * Only the temp file!
+ */
bool RE_ReadRenderResult(struct Scene *scene, struct Scene *scenode);
+/**
+ * Called from the UI and render pipeline, to save multi-layer and multi-view
+ * images, optionally isolating a specific, view, layer or RGBA/Z pass.
+ */
bool RE_WriteRenderResult(struct ReportList *reports,
RenderResult *rr,
const char *filename,
@@ -313,7 +397,11 @@ bool RE_WriteRenderResult(struct ReportList *reports,
struct RenderResult *RE_MultilayerConvert(
void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
-/* display and event callbacks */
+/* Display and event callbacks. */
+
+/**
+ * Image and movie output has to move to either imbuf or kernel.
+ */
void RE_display_init_cb(struct Render *re,
void *handle,
void (*f)(void *handle, RenderResult *rr));
@@ -336,17 +424,27 @@ void RE_gl_context_destroy(Render *re);
void *RE_gl_context_get(Render *re);
void *RE_gpu_context_get(Render *re);
-/* should move to kernel once... still unsure on how/where */
+/**
+ * \param x: ranges from -1 to 1.
+ *
+ * TODO: Should move to kernel once... still unsure on how/where.
+ */
float RE_filter_value(int type, float x);
int RE_seq_render_active(struct Scene *scene, struct RenderData *rd);
+/**
+ * Used in the interface to decide whether to show layers or passes.
+ */
bool RE_layers_have_name(struct RenderResult *result);
bool RE_passes_have_name(struct RenderLayer *rl);
struct RenderPass *RE_pass_find_by_name(volatile struct RenderLayer *rl,
const char *name,
const char *viewname);
+/**
+ * Only provided for API compatibility, don't use this in new code!
+ */
struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl,
int passtype,
const char *viewname);
@@ -356,11 +454,13 @@ struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl,
#define RE_BAKE_DISPLACEMENT 1
#define RE_BAKE_AO 2
-void RE_GetCameraWindow(struct Render *re, const struct Object *camera, float mat[4][4]);
+void RE_GetCameraWindow(struct Render *re, struct Object *camera, float mat[4][4]);
+/**
+ * Must be called after #RE_GetCameraWindow(), does not change `re->winmat`.
+ */
void RE_GetCameraWindowWithOverscan(struct Render *re, float overscan, float r_winmat[4][4]);
-void RE_GetCameraModelMatrix(struct Render *re,
- const struct Object *camera,
- float r_modelmat[4][4]);
+void RE_GetCameraModelMatrix(struct Render *re, struct Object *camera, float r_modelmat[4][4]);
+
struct Scene *RE_GetScene(struct Render *re);
void RE_SetScene(struct Render *re, struct Scene *sce);
@@ -376,7 +476,7 @@ bool RE_allow_render_generic_object(struct Object *ob);
bool RE_HasCombinedLayer(RenderResult *res);
bool RE_HasFloatPixels(RenderResult *res);
bool RE_RenderResult_is_stereo(RenderResult *res);
-struct RenderView *RE_RenderViewGetById(struct RenderResult *rr, const int view_id);
+struct RenderView *RE_RenderViewGetById(struct RenderResult *rr, int view_id);
struct RenderView *RE_RenderViewGetByName(struct RenderResult *rr, const char *viewname);
RenderResult *RE_DuplicateRenderResult(RenderResult *rr);
diff --git a/source/blender/render/RE_texture.h b/source/blender/render/RE_texture.h
index 39d773777ab..d71c793f300 100644
--- a/source/blender/render/RE_texture.h
+++ b/source/blender/render/RE_texture.h
@@ -18,13 +18,13 @@
*/
/** \file
* \ingroup render
+ *
+ * This include is for non-render pipeline exports (still old cruft here).
*/
#pragma once
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* this include is for non-render pipeline exports (still old cruft here) */
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+#include "BLI_compiler_attrs.h"
/* called by meshtools */
struct Depsgraph;
@@ -37,16 +37,29 @@ extern "C" {
#endif
/* texture_procedural.c */
+
+/**
+ * \param pool: Thread pool, may be NULL.
+ *
+ * \return True if the texture has color, otherwise false.
+ */
bool RE_texture_evaluate(const struct MTex *mtex,
const float vec[3],
- const int thread,
+ int thread,
struct ImagePool *pool,
- const bool skip_load_image,
- const bool texnode_preview,
+ bool skip_load_image,
+ bool texnode_preview,
/* Return arguments. */
float *r_intensity,
float r_rgba[4]) ATTR_NONNULL(1, 2, 7, 8);
+/**
+ * \param in: Destination
+ * \param tex: Texture.
+ * \param out: Previous color.
+ * \param fact: Texture strength.
+ * \param facg: Button strength value.
+ */
void texture_rgb_blend(
float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype);
float texture_value_blend(float tex, float out, float fact, float facg, int blendtype);
@@ -55,9 +68,11 @@ void RE_texture_rng_init(void);
void RE_texture_rng_exit(void);
/* texture_image.c */
+
void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float result[4]);
/* texture_pointdensity.c */
+
struct PointDensity;
void RE_point_density_cache(struct Depsgraph *depsgraph, struct PointDensity *pd);
@@ -67,9 +82,13 @@ void RE_point_density_minmax(struct Depsgraph *depsgraph,
float r_min[3],
float r_max[3]);
+/**
+ * \note Requires #RE_point_density_cache() to be called first.
+ * \note Frees point density structure after sampling.
+ */
void RE_point_density_sample(struct Depsgraph *depsgraph,
struct PointDensity *pd,
- const int resolution,
+ int resolution,
float *values);
void RE_point_density_free(struct PointDensity *pd);
@@ -78,8 +97,10 @@ void RE_point_density_fix_linking(void);
/* texture_procedural.c */
-/* Texture evaluation result.
- * NOTE: tr tg tb ta has to remain in this order for array access. */
+/**
+ * Texture evaluation result.
+ * \note `tr tg tb ta` have to remain in this order for array access.
+ */
typedef struct TexResult {
float tin, tr, tg, tb, ta;
int talpha;
@@ -87,31 +108,51 @@ typedef struct TexResult {
} TexResult;
/* This one uses nodes. */
+
+/**
+ * \warning if the texres's values are not declared zero,
+ * check the return value to be sure the color values are set before using the r/g/b values,
+ * otherwise you may use uninitialized values - Campbell
+ *
+ * Use it for stuff which is out of render pipeline.
+ */
int multitex_ext(struct Tex *tex,
float texvec[3],
float dxt[3],
float dyt[3],
int osatex,
struct TexResult *texres,
- const short thread,
+ short thread,
struct ImagePool *pool,
bool scene_color_manage,
- const bool skip_load_image);
-/* Nodes disabled. */
+ bool skip_load_image);
+
+/**
+ * Nodes disabled.
+ * extern-tex doesn't support nodes (#ntreeBeginExec() can't be called when rendering is going on).
+ *
+ * Use it for stuff which is out of render pipeline.
+ */
int multitex_ext_safe(struct Tex *tex,
const float texvec[3],
struct TexResult *texres,
struct ImagePool *pool,
bool scene_color_manage,
- const bool skip_load_image);
-/* Only for internal node usage. */
+ bool skip_load_image);
+
+/**
+ * Only for internal node usage.
+ *
+ * this is called from the shader and texture nodes
+ * Use it from render pipeline only!
+ */
int multitex_nodes(struct Tex *tex,
const float texvec[3],
float dxt[3],
float dyt[3],
int osatex,
struct TexResult *texres,
- const short thread,
+ short thread,
short which_output,
struct MTex *mtex,
struct ImagePool *pool);
diff --git a/source/blender/render/RE_texture_margin.h b/source/blender/render/RE_texture_margin.h
new file mode 100644
index 00000000000..8d1a6c45809
--- /dev/null
+++ b/source/blender/render/RE_texture_margin.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct DerivedMesh;
+struct IMBuf;
+struct ImBuf;
+struct MLoopUV;
+struct Mesh;
+
+/**
+ * Generate a margin around the textures uv islands by copying pixels from the adjacent polygon.
+ *
+ * \param ibuf: the texture image.
+ * \param mask: pixels with a mask value of 1 are not written to.
+ * \param margin: the size of the margin in pixels.
+ * \param me: the mesh to use the polygons of.
+ * \param mloopuv: the uv data to use.
+ */
+void RE_generate_texturemargin_adjacentfaces(
+ struct ImBuf *ibuf, char *mask, const int margin, struct Mesh const *me, char const *uv_layer);
+
+void RE_generate_texturemargin_adjacentfaces_dm(struct ImBuf *ibuf,
+ char *mask,
+ const int margin,
+ struct DerivedMesh *dm);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index 0f893ce8cd5..93d2f721cc5 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -83,6 +83,7 @@
#include "IMB_imbuf_types.h"
#include "RE_bake.h"
+#include "RE_texture_margin.h"
/* local include */
#include "render_types.h"
@@ -107,6 +108,7 @@ typedef struct TSpace {
typedef struct TriTessFace {
const MVert *mverts[3];
+ const float *vert_normals[3];
const TSpace *tspace[3];
float *loop_normal[3];
float normal[3]; /* for flat faces */
@@ -153,10 +155,24 @@ void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, c
}
}
-void RE_bake_margin(ImBuf *ibuf, char *mask, const int margin)
+void RE_bake_margin(ImBuf *ibuf,
+ char *mask,
+ const int margin,
+ const char margin_type,
+ Mesh const *me,
+ char const *uv_layer)
{
/* margin */
- IMB_filter_extend(ibuf, mask, margin);
+ switch (margin_type) {
+ case R_BAKE_ADJACENT_FACES:
+ RE_generate_texturemargin_adjacentfaces(ibuf, mask, margin, me, uv_layer);
+ break;
+ default:
+ /* fall through */
+ case R_BAKE_EXTEND:
+ IMB_filter_extend(ibuf, mask, margin);
+ break;
+ }
if (ibuf->planes != R_IMF_PLANES_RGBA) {
/* clear alpha added by filtering */
@@ -241,9 +257,9 @@ static void calc_point_from_barycentric_extrusion(TriTessFace *triangles,
interp_barycentric_tri_v3(data, u, v, coord);
if (is_smooth) {
- normal_short_to_float_v3(data[0], triangle->mverts[0]->no);
- normal_short_to_float_v3(data[1], triangle->mverts[1]->no);
- normal_short_to_float_v3(data[2], triangle->mverts[2]->no);
+ copy_v3_v3(data[0], triangle->vert_normals[0]);
+ copy_v3_v3(data[1], triangle->vert_normals[1]);
+ copy_v3_v3(data[2], triangle->vert_normals[2]);
interp_barycentric_tri_v3(data, u, v, dir);
normalize_v3(dir);
@@ -488,6 +504,7 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
loop_normals = CustomData_get_layer(&me_eval->ldata, CD_NORMAL);
}
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me);
for (i = 0; i < tottri; i++) {
const MLoopTri *lt = &looptri[i];
const MPoly *mp = &me->mpoly[lt->poly];
@@ -495,6 +512,9 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
triangles[i].mverts[0] = &mvert[me->mloop[lt->tri[0]].v];
triangles[i].mverts[1] = &mvert[me->mloop[lt->tri[1]].v];
triangles[i].mverts[2] = &mvert[me->mloop[lt->tri[2]].v];
+ triangles[i].vert_normals[0] = &vert_normals[me->mloop[lt->tri[0]].v][0];
+ triangles[i].vert_normals[1] = &vert_normals[me->mloop[lt->tri[1]].v][1];
+ triangles[i].vert_normals[2] = &vert_normals[me->mloop[lt->tri[2]].v][2];
triangles[i].is_smooth = (mp->flag & ME_SMOOTH) != 0;
if (tangent) {
@@ -814,10 +834,6 @@ static void normal_compress(float out[3],
}
}
-/**
- * This function converts an object space normal map
- * to a tangent space normal map for a given low poly mesh.
- */
void RE_bake_normal_world_to_tangent(const BakePixel pixel_array[],
const size_t num_pixels,
const int depth,
@@ -882,7 +898,7 @@ void RE_bake_normal_world_to_tangent(const BakePixel pixel_array[],
copy_v3_v3(normals[j], triangle->loop_normal[j]);
}
else {
- normal_short_to_float_v3(normals[j], triangle->mverts[j]->no);
+ copy_v3_v3(normals[j], triangle->vert_normals[j]);
}
}
diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c
index 389b821ca35..04f27ff6cbc 100644
--- a/source/blender/render/intern/engine.c
+++ b/source/blender/render/intern/engine.c
@@ -206,12 +206,11 @@ static RenderResult *render_result_from_bake(RenderEngine *engine, int x, int y,
BLI_addtail(&rr->layers, rl);
/* Add render passes. */
- RenderPass *result_pass = render_layer_add_pass(
- rr, rl, engine->bake.depth, RE_PASSNAME_COMBINED, "", "RGBA");
- RenderPass *primitive_pass = render_layer_add_pass(rr, rl, 4, "BakePrimitive", "", "RGBA");
- RenderPass *differential_pass = render_layer_add_pass(rr, rl, 4, "BakeDifferential", "", "RGBA");
+ render_layer_add_pass(rr, rl, engine->bake.depth, RE_PASSNAME_COMBINED, "", "RGBA", true);
- render_result_passes_allocated_ensure(rr);
+ RenderPass *primitive_pass = render_layer_add_pass(rr, rl, 4, "BakePrimitive", "", "RGBA", true);
+ RenderPass *differential_pass = render_layer_add_pass(
+ rr, rl, 4, "BakeDifferential", "", "RGBA", true);
/* Fill render passes from bake pixel array, to be read by the render engine. */
for (int ty = 0; ty < h; ty++) {
@@ -245,15 +244,6 @@ static RenderResult *render_result_from_bake(RenderEngine *engine, int x, int y,
}
}
- /* Initialize tile render result from full image bake result. */
- for (int ty = 0; ty < h; ty++) {
- size_t offset = ty * w * engine->bake.depth;
- size_t bake_offset = ((y + ty) * engine->bake.width + x) * engine->bake.depth;
- size_t size = w * engine->bake.depth * sizeof(float);
-
- memcpy(result_pass->rect + offset, engine->bake.result + bake_offset, size);
- }
-
return rr;
}
@@ -265,28 +255,40 @@ static void render_result_to_bake(RenderEngine *engine, RenderResult *rr)
return;
}
- /* Copy from tile render result to full image bake result. */
- int x = rr->tilerect.xmin;
- int y = rr->tilerect.ymin;
- int w = rr->tilerect.xmax - rr->tilerect.xmin;
- int h = rr->tilerect.ymax - rr->tilerect.ymin;
+ /* Copy from tile render result to full image bake result. Just the pixels for the
+ * object currently being baked, to preserve other objects when baking multiple. */
+ const int x = rr->tilerect.xmin;
+ const int y = rr->tilerect.ymin;
+ const int w = rr->tilerect.xmax - rr->tilerect.xmin;
+ const int h = rr->tilerect.ymax - rr->tilerect.ymin;
+ const size_t pixel_depth = engine->bake.depth;
+ const size_t pixel_size = pixel_depth * sizeof(float);
for (int ty = 0; ty < h; ty++) {
- size_t offset = ty * w * engine->bake.depth;
- size_t bake_offset = ((y + ty) * engine->bake.width + x) * engine->bake.depth;
- size_t size = w * engine->bake.depth * sizeof(float);
+ const size_t offset = ty * w;
+ const size_t bake_offset = (y + ty) * engine->bake.width + x;
+
+ const float *pass_rect = rpass->rect + offset * pixel_depth;
+ const BakePixel *bake_pixel = engine->bake.pixels + bake_offset;
+ float *bake_result = engine->bake.result + bake_offset * pixel_depth;
- memcpy(engine->bake.result + bake_offset, rpass->rect + offset, size);
+ for (int tx = 0; tx < w; tx++) {
+ if (bake_pixel->object_id == engine->bake.object_id) {
+ memcpy(bake_result, pass_rect, pixel_size);
+ }
+ pass_rect += pixel_depth;
+ bake_result += pixel_depth;
+ bake_pixel++;
+ }
}
}
/* Render Results */
-static HighlightedTile highlighted_tile_from_result_get(Render *re, RenderResult *result)
+static HighlightedTile highlighted_tile_from_result_get(Render *UNUSED(re), RenderResult *result)
{
HighlightedTile tile;
tile.rect = result->tilerect;
- BLI_rcti_translate(&tile.rect, re->disprect.xmin, re->disprect.ymin);
return tile;
}
@@ -414,7 +416,7 @@ void RE_engine_add_pass(RenderEngine *engine,
return;
}
- RE_create_render_pass(re->result, name, channels, chan_id, layername, NULL);
+ RE_create_render_pass(re->result, name, channels, chan_id, layername, NULL, false);
}
void RE_engine_end_result(
@@ -433,8 +435,6 @@ void RE_engine_end_result(
return;
}
- re_ensure_passes_allocated_thread_safe(re);
-
if (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES)) {
const HighlightedTile tile = highlighted_tile_from_result_get(re, result);
@@ -443,6 +443,7 @@ void RE_engine_end_result(
if (!cancel || merge_results) {
if (!(re->test_break(re->tbh) && (re->r.scemode & R_BUTS_PREVIEW))) {
+ re_ensure_passes_allocated_thread_safe(re);
render_result_merge(re->result, result);
}
@@ -782,6 +783,7 @@ void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
}
/* Bake */
+
void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
{
re->scene = scene;
@@ -920,8 +922,10 @@ static void engine_render_view_layer(Render *re,
}
}
- /* Optionally composite grease pencil over render result. */
- if (engine->has_grease_pencil && use_grease_pencil) {
+ /* Optionally composite grease pencil over render result.
+ * Only do it if the passes are allocated (and the engine will not override the grease pencil
+ * when reading its result from EXR file and writing to the Blender side. */
+ if (engine->has_grease_pencil && use_grease_pencil && re->result->passes_allocated) {
/* NOTE: External engine might have been requested to free its
* dependency graph, which is only allowed if there is no grease
* pencil (pipeline is taking care of that). */
@@ -1020,10 +1024,18 @@ bool RE_engine_render(Render *re, bool do_all)
re->draw_lock(re->dlh, false);
}
+ /* Render view layers. */
+ bool delay_grease_pencil = false;
+
if (type->render) {
FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer_iter) {
engine_render_view_layer(re, engine, view_layer_iter, true, true);
+ /* If render passes are not allocated the render engine deferred final pixels write for
+ * later. Need to defer the grease pencil for until after the engine has written the
+ * render result to Blender. */
+ delay_grease_pencil = engine->has_grease_pencil && !re->result->passes_allocated;
+
if (RE_engine_test_break(engine)) {
break;
}
@@ -1035,6 +1047,17 @@ bool RE_engine_render(Render *re, bool do_all)
type->render_frame_finish(engine);
}
+ /* Perform delayed grease pencil rendering. */
+ if (delay_grease_pencil) {
+ FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer_iter) {
+ engine_render_view_layer(re, engine, view_layer_iter, false, true);
+ if (RE_engine_test_break(engine)) {
+ break;
+ }
+ }
+ FOREACH_VIEW_LAYER_TO_RENDER_END;
+ }
+
/* Clear tile data */
engine->flag &= ~RE_ENGINE_RENDERING;
diff --git a/source/blender/render/intern/initrender.c b/source/blender/render/intern/initrender.c
index e25c6d78e54..f696b81cffb 100644
--- a/source/blender/render/intern/initrender.c
+++ b/source/blender/render/intern/initrender.c
@@ -121,7 +121,6 @@ static float filt_mitchell(float x) /* Mitchell & Netravali's two-param cubic */
return 0.0f;
}
-/* x ranges from -1 to 1 */
float RE_filter_value(int type, float x)
{
float gaussfac = 1.6f;
@@ -163,6 +162,7 @@ float RE_filter_value(int type, float x)
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
struct Object *RE_GetCamera(Render *re)
{
Object *camera = re->camera_override ? re->camera_override : re->scene->camera;
@@ -174,12 +174,7 @@ void RE_SetOverrideCamera(Render *re, Object *cam_ob)
re->camera_override = cam_ob;
}
-/**
- * Per render, there's one persistent view-plane. Parts will set their own view-planes.
- *
- * \note call this after #RE_InitState().
- */
-void RE_SetCamera(Render *re, const Object *cam_ob)
+void RE_SetCamera(Render *re, Object *cam_ob)
{
CameraParams params;
@@ -199,13 +194,12 @@ void RE_SetCamera(Render *re, const Object *cam_ob)
re->viewplane = params.viewplane;
}
-void RE_GetCameraWindow(struct Render *re, const Object *camera, float r_winmat[4][4])
+void RE_GetCameraWindow(struct Render *re, struct Object *camera, float r_winmat[4][4])
{
RE_SetCamera(re, camera);
copy_m4_m4(r_winmat, re->winmat);
}
-/* Must be called after RE_GetCameraWindow(), does not change re->winmat. */
void RE_GetCameraWindowWithOverscan(struct Render *re, float overscan, float r_winmat[4][4])
{
CameraParams params;
@@ -224,7 +218,7 @@ void RE_GetCameraWindowWithOverscan(struct Render *re, float overscan, float r_w
copy_m4_m4(r_winmat, params.winmat);
}
-void RE_GetCameraModelMatrix(Render *re, const Object *camera, float r_modelmat[4][4])
+void RE_GetCameraModelMatrix(Render *re, struct Object *camera, float r_modelmat[4][4])
{
BKE_camera_multiview_model_matrix(&re->r, camera, re->viewname, r_modelmat);
}
diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c
index 930c7580f32..5cf328a3a73 100644
--- a/source/blender/render/intern/multires_bake.c
+++ b/source/blender/render/intern/multires_bake.c
@@ -47,6 +47,7 @@
#include "RE_multires_bake.h"
#include "RE_pipeline.h"
#include "RE_texture.h"
+#include "RE_texture_margin.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -72,6 +73,7 @@ typedef struct MultiresBakeResult {
typedef struct {
MVert *mvert;
+ const float (*vert_normals)[3];
MPoly *mpoly;
MLoop *mloop;
MLoopUV *mloopuv;
@@ -135,10 +137,7 @@ static void multiresbake_get_normal(const MResolvePixelData *data,
}
else {
const int vi = data->mloop[data->mlooptri[tri_num].tri[vert_index]].v;
- const short *no = data->mvert[vi].no;
-
- normal_short_to_float_v3(norm, no);
- normalize_v3(norm);
+ copy_v3_v3(norm, data->vert_normals[vi]);
}
}
@@ -1298,14 +1297,23 @@ static void apply_ao_callback(DerivedMesh *lores_dm,
/* ******$***************** Post processing ************************* */
-static void bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter)
+static void bake_ibuf_filter(
+ ImBuf *ibuf, char *mask, const int margin, const char margin_type, DerivedMesh *dm)
{
/* must check before filtering */
const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf);
- /* Margin */
- if (filter) {
- IMB_filter_extend(ibuf, mask, filter);
+ if (margin) {
+ switch (margin_type) {
+ case R_BAKE_ADJACENT_FACES:
+ RE_generate_texturemargin_adjacentfaces_dm(ibuf, mask, margin, dm);
+ break;
+ default:
+ /* fall through */
+ case R_BAKE_EXTEND:
+ IMB_filter_extend(ibuf, mask, margin);
+ break;
+ }
}
/* if the bake results in new alpha then change the image setting */
@@ -1313,7 +1321,7 @@ static void bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter)
ibuf->planes = R_IMF_PLANES_RGBA;
}
else {
- if (filter && ibuf->planes != R_IMF_PLANES_RGBA) {
+ if (margin && ibuf->planes != R_IMF_PLANES_RGBA) {
/* clear alpha added by filtering */
IMB_rectfill_alpha(ibuf, 1.0f);
}
@@ -1462,7 +1470,8 @@ static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
result->height_max);
}
- bake_ibuf_filter(ibuf, userdata->mask_buffer, bkr->bake_filter);
+ bake_ibuf_filter(
+ ibuf, userdata->mask_buffer, bkr->bake_margin, bkr->bake_margin_type, bkr->lores_dm);
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
BKE_image_mark_dirty(ima, ibuf);
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index 931282e26dd..739202564af 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -73,6 +73,8 @@
#include "BKE_sound.h"
#include "BKE_writeavi.h" /* <------ should be replaced once with generic movie module */
+#include "NOD_composite.h"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_debug.h"
@@ -338,7 +340,6 @@ Render *RE_GetRender(const char *name)
return re;
}
-/* if you want to know exactly what has been done */
RenderResult *RE_AcquireResultRead(Render *re)
{
if (re) {
@@ -383,7 +384,6 @@ void RE_ReleaseResult(Render *re)
}
}
-/* displist.c util.... */
Scene *RE_GetScene(Render *re)
{
if (re) {
@@ -399,11 +399,6 @@ void RE_SetScene(Render *re, Scene *sce)
}
}
-/**
- * Same as #RE_AcquireResultImage but creating the necessary views to store the result
- * fill provided result struct with a copy of thew views of what is done so far the
- * #RenderResult.views #ListBase needs to be freed after with #RE_ReleaseResultImageViews
- */
void RE_AcquireResultImageViews(Render *re, RenderResult *rr)
{
memset(rr, 0, sizeof(RenderResult));
@@ -449,7 +444,6 @@ void RE_AcquireResultImageViews(Render *re, RenderResult *rr)
}
}
-/* clear temporary renderresult struct */
void RE_ReleaseResultImageViews(Render *re, RenderResult *rr)
{
if (re) {
@@ -460,9 +454,6 @@ void RE_ReleaseResultImageViews(Render *re, RenderResult *rr)
}
}
-/* fill provided result struct with what's currently active or done */
-/* this RenderResult struct is the only exception to the rule of a RenderResult */
-/* always having at least one RenderView */
void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
{
memset(rr, 0, sizeof(RenderResult));
@@ -516,7 +507,6 @@ void RE_ReleaseResultImage(Render *re)
}
}
-/* caller is responsible for allocating rect in correct size! */
void RE_ResultGet32(Render *re, unsigned int *rect)
{
RenderResult rres;
@@ -533,8 +523,6 @@ void RE_ResultGet32(Render *re, unsigned int *rect)
RE_ReleaseResultImageViews(re, &rres);
}
-/* caller is responsible for allocating rect in correct size! */
-/* Only for acquired results, for lock */
void RE_AcquiredResultGet32(Render *re,
RenderResult *result,
unsigned int *rect,
@@ -603,8 +591,6 @@ Render *RE_NewSceneRender(const Scene *scene)
return RE_NewRender(render_name);
}
-/* called for new renders and when finishing rendering so
- * we always have valid callbacks on a render */
void RE_InitRenderCB(Render *re)
{
/* set default empty callbacks */
@@ -624,7 +610,6 @@ void RE_InitRenderCB(Render *re)
re->dih = re->dch = re->duh = re->sdh = re->prh = re->tbh = NULL;
}
-/* only call this while you know it will remove the link too */
void RE_FreeRender(Render *re)
{
if (re->engine) {
@@ -655,7 +640,6 @@ void RE_FreeRender(Render *re)
MEM_freeN(re);
}
-/* exit blender */
void RE_FreeAllRender(void)
{
while (RenderGlobal.renderlist.first) {
@@ -668,7 +652,6 @@ void RE_FreeAllRender(void)
#endif
}
-/* on file load, free all re */
void RE_FreeAllRenderResults(void)
{
Render *re;
@@ -769,8 +752,6 @@ void render_copy_renderdata(RenderData *to, RenderData *from)
BKE_curvemapping_copy_data(&to->mblur_shutter_curve, &from->mblur_shutter_curve);
}
-/* what doesn't change during entire render sequence */
-/* disprect is optional, if NULL it assumes full window render */
void RE_InitState(Render *re,
Render *source,
RenderData *rd,
@@ -874,8 +855,6 @@ void RE_InitState(Render *re,
RE_point_density_fix_linking();
}
-/* update some variables that can be animated, and otherwise wouldn't be due to
- * RenderData getting copied once at the start of animation render */
void render_update_anim_renderdata(Render *re, RenderData *rd, ListBase *render_layers)
{
/* filter */
@@ -897,7 +876,6 @@ void render_update_anim_renderdata(Render *re, RenderData *rd, ListBase *render_
BLI_duplicatelist(&re->r.views, &rd->views);
}
-/* image and movie output has to move to either imbuf or kernel */
void RE_display_init_cb(Render *re, void *handle, void (*f)(void *handle, RenderResult *rr))
{
re->display_init = f;
@@ -1155,7 +1133,7 @@ static void do_render_compositor_scenes(Render *re)
render_scene_has_layers_to_render(scene, false)) {
do_render_compositor_scene(re, scene, cfra);
BLI_gset_add(scenes_rendered, scene);
- nodeUpdate(restore_scene->nodetree, node);
+ node->typeinfo->updatefunc(restore_scene->nodetree, node);
}
}
}
@@ -1440,7 +1418,7 @@ static void do_render_full_pipeline(Render *re)
/* ensure no images are in memory from previous animated sequences */
BKE_image_all_free_anim_ibufs(re->main, re->r.cfra);
- SEQ_relations_free_all_anim_ibufs(re->scene, re->r.cfra);
+ SEQ_cache_cleanup(re->scene);
if (RE_engine_render(re, true)) {
/* in this case external render overrides all */
@@ -1834,7 +1812,6 @@ static void render_pipeline_free(Render *re)
}
}
-/* general Blender frame render call */
void RE_RenderFrame(Render *re,
Main *bmain,
Scene *scene,
@@ -1846,7 +1823,7 @@ void RE_RenderFrame(Render *re,
render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
/* Ugly global still...
- * is to prevent preview events and signal subsurfs etc to make full resol. */
+ * is to prevent preview events and signal subdivision-surface etc to make full resolution. */
G.is_rendering = true;
scene->r.cfra = frame;
@@ -2280,7 +2257,6 @@ static void re_movie_free_all(Render *re, bMovieHandle *mh, int totvideos)
MEM_SAFE_FREE(re->movie_ctx_arr);
}
-/* saves images to disk */
void RE_RenderAnim(Render *re,
Main *bmain,
Scene *scene,
@@ -2357,8 +2333,8 @@ void RE_RenderAnim(Render *re,
}
}
- /* Ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol
- * is also set by caller renderwin.c */
+ /* Ugly global still... is to prevent renderwin events and signal subdivision-surface etc
+ * to make full resolution is also set by caller renderwin.c */
G.is_rendering = true;
re->flag |= R_ANIMATION;
@@ -2583,7 +2559,6 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
/* NOTE: repeated win/disprect calc... solve that nicer, also in compo. */
-/* only the temp file! */
bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
{
Render *re;
@@ -2635,8 +2610,6 @@ void RE_init_threadcount(Render *re)
re->r.threads = BKE_render_num_threads(&re->r);
}
-/* loads in image into a result, size must match
- * x/y offsets are only used on a partial copy when dimensions don't match */
void RE_layer_load_from_file(
RenderLayer *layer, ReportList *reports, const char *filename, int x, int y)
{
@@ -2712,7 +2685,6 @@ void RE_result_load_from_file(RenderResult *result, ReportList *reports, const c
}
}
-/* Used in the interface to decide whether to show layers or passes. */
bool RE_layers_have_name(struct RenderResult *rr)
{
switch (BLI_listbase_count_at_most(&rr->layers, 2)) {
@@ -2754,7 +2726,6 @@ RenderPass *RE_pass_find_by_name(volatile RenderLayer *rl, const char *name, con
return rp;
}
-/* Only provided for API compatibility, don't use this in new code! */
RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const char *viewname)
{
#define CHECK_PASS(NAME) \
@@ -2793,7 +2764,6 @@ RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const c
return NULL;
}
-/* create a renderlayer and renderpass for grease pencil layer */
RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const char *viewname)
{
RenderLayer *rl = BLI_findstring(&rr->layers, layername, offsetof(RenderLayer, name));
@@ -2817,7 +2787,7 @@ RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const cha
BLI_freelinkN(&rl->passes, rp);
}
/* create a totally new pass */
- return render_layer_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, viewname, "RGBA");
+ return render_layer_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, viewname, "RGBA", true);
}
bool RE_allow_render_generic_object(Object *ob)
diff --git a/source/blender/render/intern/pipeline.h b/source/blender/render/intern/pipeline.h
index 062df59bfd3..ba2e382619d 100644
--- a/source/blender/render/intern/pipeline.h
+++ b/source/blender/render/intern/pipeline.h
@@ -34,6 +34,10 @@ extern "C" {
#endif
struct RenderLayer *render_get_active_layer(struct Render *re, struct RenderResult *rr);
+/**
+ * Update some variables that can be animated, and otherwise wouldn't be due to
+ * #RenderData getting copied once at the start of animation render.
+ */
void render_update_anim_renderdata(struct Render *re,
struct RenderData *rd,
struct ListBase *render_layers);
diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c
index db14f7a2982..d207ea0a38e 100644
--- a/source/blender/render/intern/render_result.c
+++ b/source/blender/render/intern/render_result.c
@@ -126,7 +126,6 @@ void render_result_free(RenderResult *rr)
MEM_freeN(rr);
}
-/** Version that's compatible with full-sample buffers. */
void render_result_free_list(ListBase *lb, RenderResult *rr)
{
RenderResult *rrnext;
@@ -144,7 +143,6 @@ void render_result_free_list(ListBase *lb, RenderResult *rr)
/********************************* multiview *************************************/
-/* create a new views Listbase in rr without duplicating the memory pointers */
void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src)
{
RenderView *rview;
@@ -166,7 +164,6 @@ void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src)
}
}
-/* free the views created temporarily */
void render_result_views_shallowdelete(RenderResult *rr)
{
if (rr == NULL) {
@@ -213,12 +210,37 @@ static void set_pass_full_name(
/********************************** New **************************************/
+static void render_layer_allocate_pass(RenderResult *rr, RenderPass *rp)
+{
+ if (rp->rect != NULL) {
+ return;
+ }
+
+ const size_t rectsize = ((size_t)rr->rectx) * rr->recty * rp->channels;
+ rp->rect = MEM_callocN(sizeof(float) * rectsize, rp->name);
+
+ if (STREQ(rp->name, RE_PASSNAME_VECTOR)) {
+ /* initialize to max speed */
+ float *rect = rp->rect;
+ for (int x = rectsize - 1; x >= 0; x--) {
+ rect[x] = PASS_VECTOR_MAX;
+ }
+ }
+ else if (STREQ(rp->name, RE_PASSNAME_Z)) {
+ float *rect = rp->rect;
+ for (int x = rectsize - 1; x >= 0; x--) {
+ rect[x] = 10e10;
+ }
+ }
+}
+
RenderPass *render_layer_add_pass(RenderResult *rr,
RenderLayer *rl,
int channels,
const char *name,
const char *viewname,
- const char *chan_id)
+ const char *chan_id,
+ const bool allocate)
{
const int view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name));
RenderPass *rpass = MEM_callocN(sizeof(RenderPass), name);
@@ -250,16 +272,17 @@ RenderPass *render_layer_add_pass(RenderResult *rr,
BLI_addtail(&rl->passes, rpass);
- /* The result contains non-allocated pass now, so tag it as such. */
- rr->passes_allocated = false;
+ if (allocate) {
+ render_layer_allocate_pass(rr, rpass);
+ }
+ else {
+ /* The result contains non-allocated pass now, so tag it as such. */
+ rr->passes_allocated = false;
+ }
return rpass;
}
-/* called by main render as well for parts */
-/* will read info from Render *re to define layers */
-/* called in threads */
-/* re->winx,winy is coordinate space of entire image, partrct the part within */
RenderResult *render_result_new(Render *re,
rcti *partrct,
const char *layername,
@@ -323,14 +346,14 @@ RenderResult *render_result_new(Render *re,
#define RENDER_LAYER_ADD_PASS_SAFE(rr, rl, channels, name, viewname, chan_id) \
do { \
- if (render_layer_add_pass(rr, rl, channels, name, viewname, chan_id) == NULL) { \
+ if (render_layer_add_pass(rr, rl, channels, name, viewname, chan_id, false) == NULL) { \
render_result_free(rr); \
return NULL; \
} \
} while (false)
/* A renderlayer should always have a Combined pass. */
- render_layer_add_pass(rr, rl, 4, "Combined", view, "RGBA");
+ render_layer_add_pass(rr, rl, 4, "Combined", view, "RGBA", false);
if (view_layer->passflag & SCE_PASS_Z) {
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_Z, view, "Z");
@@ -427,7 +450,7 @@ RenderResult *render_result_new(Render *re,
}
/* a renderlayer should always have a Combined pass */
- render_layer_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, view, "RGBA");
+ render_layer_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, view, "RGBA", false);
}
/* NOTE: this has to be in sync with `scene.c`. */
@@ -447,32 +470,19 @@ RenderResult *render_result_new(Render *re,
void render_result_passes_allocated_ensure(RenderResult *rr)
{
+ if (rr == NULL) {
+ /* Happens when the result was not yet allocated for the current scene or slot configuration.
+ */
+ return;
+ }
+
LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) {
if (rl->exrhandle != NULL && !STREQ(rp->name, RE_PASSNAME_COMBINED)) {
continue;
}
- if (rp->rect != NULL) {
- continue;
- }
-
- const size_t rectsize = ((size_t)rr->rectx) * rr->recty * rp->channels;
- rp->rect = MEM_callocN(sizeof(float) * rectsize, rp->name);
-
- if (STREQ(rp->name, RE_PASSNAME_VECTOR)) {
- /* initialize to max speed */
- float *rect = rp->rect;
- for (int x = rectsize - 1; x >= 0; x--) {
- rect[x] = PASS_VECTOR_MAX;
- }
- }
- else if (STREQ(rp->name, RE_PASSNAME_Z)) {
- float *rect = rp->rect;
- for (int x = rectsize - 1; x >= 0; x--) {
- rect[x] = 10e10;
- }
- }
+ render_layer_allocate_pass(rr, rp);
}
}
@@ -501,7 +511,7 @@ void render_result_clone_passes(Render *re, RenderResult *rr, const char *viewna
&rl->passes, main_rp->fullname, offsetof(RenderPass, fullname));
if (!rp) {
render_layer_add_pass(
- rr, rl, main_rp->channels, main_rp->name, main_rp->view, main_rp->chan_id);
+ rr, rl, main_rp->channels, main_rp->name, main_rp->view, main_rp->chan_id, false);
}
}
}
@@ -512,7 +522,8 @@ void RE_create_render_pass(RenderResult *rr,
int channels,
const char *chan_id,
const char *layername,
- const char *viewname)
+ const char *viewname,
+ const bool allocate)
{
RenderLayer *rl;
RenderPass *rp;
@@ -542,7 +553,7 @@ void RE_create_render_pass(RenderResult *rr,
}
if (!rp) {
- render_layer_add_pass(rr, rl, channels, name, view, chan_id);
+ render_layer_add_pass(rr, rl, channels, name, view, chan_id, allocate);
}
}
}
@@ -721,10 +732,6 @@ static int order_render_passes(const void *a, const void *b)
return (rpa->view_id < rpb->view_id);
}
-/**
- * From imbuf, if a handle was returned and
- * it's not a single-layer multi-view we convert this to render result.
- */
RenderResult *render_result_new_from_exr(
void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
{
@@ -825,9 +832,6 @@ static void do_merge_tile(
}
}
-/* used when rendering to a full buffer, or when reading the exr part-layer-pass file */
-/* no test happens here if it fits... we also assume layers are in sync */
-/* is used within threads */
void render_result_merge(RenderResult *rr, RenderResult *rrpart)
{
RenderLayer *rl, *rlp;
@@ -857,8 +861,6 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
}
}
-/* Called from the UI and render pipeline, to save multilayer and multiview
- * images, optionally isolating a specific, view, layer or RGBA/Z pass. */
bool RE_WriteRenderResult(ReportList *reports,
RenderResult *rr,
const char *filename,
@@ -1028,7 +1030,6 @@ void render_result_single_layer_begin(Render *re)
re->result = NULL;
}
-/* if scemode is R_SINGLE_LAYER, at end of rendering, merge the both render results */
void render_result_single_layer_end(Render *re)
{
ViewLayer *view_layer;
@@ -1073,7 +1074,6 @@ void render_result_single_layer_end(Render *re)
re->pushedresult = NULL;
}
-/* called for reading temp files, and for external engines */
int render_result_exr_file_read_path(RenderResult *rr,
RenderLayer *rl_single,
const char *filepath)
@@ -1172,7 +1172,6 @@ void render_result_exr_file_cache_write(Render *re)
RE_WriteRenderResult(NULL, rr, str, NULL, NULL, -1);
}
-/* For cache, makes exact copy of render result */
bool render_result_exr_file_cache_read(Render *re)
{
/* File path to cache. */
@@ -1239,7 +1238,7 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, const RenderData *rd, const
}
}
- /* color -> grayscale */
+ /* Color -> gray-scale. */
/* editing directly would alter the render view */
if (rd->im_format.planes == R_IMF_PLANES_BW) {
ImBuf *ibuf_bw = IMB_dupImBuf(ibuf);
diff --git a/source/blender/render/intern/render_result.h b/source/blender/render/intern/render_result.h
index 4145bb3b8ab..9084dbf95ce 100644
--- a/source/blender/render/intern/render_result.h
+++ b/source/blender/render/intern/render_result.h
@@ -46,6 +46,12 @@ extern "C" {
/* New */
+/**
+ * Called by main render as well for parts will read info from Render *re to define layers.
+ * \note Called in threads.
+ *
+ * `re->winx`, `re->winy` is coordinate space of entire image, `partrct` the part within.
+ */
struct RenderResult *render_result_new(struct Render *re,
struct rcti *partrct,
const char *layername,
@@ -53,6 +59,10 @@ struct RenderResult *render_result_new(struct Render *re,
void render_result_passes_allocated_ensure(struct RenderResult *rr);
+/**
+ * From imbuf, if a handle was returned and
+ * it's not a single-layer multi-view we convert this to render result.
+ */
struct RenderResult *render_result_new_from_exr(
void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
@@ -61,6 +71,11 @@ void render_result_views_new(struct RenderResult *rr, const struct RenderData *r
/* Merge */
+/**
+ * Used when rendering to a full buffer, or when reading the EXR part-layer-pass file.
+ * no test happens here if it fits... we also assume layers are in sync.
+ * \note Is used within threads.
+ */
void render_result_merge(struct RenderResult *rr, struct RenderResult *rrpart);
/* Add Passes */
@@ -70,21 +85,33 @@ void render_result_clone_passes(struct Render *re, struct RenderResult *rr, cons
/* Free */
void render_result_free(struct RenderResult *rr);
+/**
+ * Version that's compatible with full-sample buffers.
+ */
void render_result_free_list(struct ListBase *lb, struct RenderResult *rr);
/* Single Layer Render */
void render_result_single_layer_begin(struct Render *re);
+/**
+ * If #RenderData.scemode is #R_SINGLE_LAYER, at end of rendering, merge the both render results.
+ */
void render_result_single_layer_end(struct Render *re);
-/* render pass wrapper for gpencil */
+/**
+ * Render pass wrapper for grease-pencil.
+ */
struct RenderPass *render_layer_add_pass(struct RenderResult *rr,
struct RenderLayer *rl,
int channels,
const char *name,
const char *viewname,
- const char *chan_id);
+ const char *chan_id,
+ bool allocate);
+/**
+ * Called for reading temp files, and for external engines.
+ */
int render_result_exr_file_read_path(struct RenderResult *rr,
struct RenderLayer *rl_single,
const char *filepath);
@@ -92,24 +119,33 @@ int render_result_exr_file_read_path(struct RenderResult *rr,
/* EXR cache */
void render_result_exr_file_cache_write(struct Render *re);
+/**
+ * For cache, makes exact copy of render result.
+ */
bool render_result_exr_file_cache_read(struct Render *re);
/* Combined Pixel Rect */
struct ImBuf *render_result_rect_to_ibuf(struct RenderResult *rr,
const struct RenderData *rd,
- const int view_id);
+ int view_id);
-void render_result_rect_fill_zero(struct RenderResult *rr, const int view_id);
+void render_result_rect_fill_zero(struct RenderResult *rr, int view_id);
void render_result_rect_get_pixels(struct RenderResult *rr,
unsigned int *rect,
int rectx,
int recty,
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
- const int view_id);
+ int view_id);
+/**
+ * Create a new views #ListBase in rr without duplicating the memory pointers.
+ */
void render_result_views_shallowcopy(struct RenderResult *dst, struct RenderResult *src);
+/**
+ * Free the views created temporarily.
+ */
void render_result_views_shallowdelete(struct RenderResult *rr);
bool render_result_has_views(const struct RenderResult *rr);
diff --git a/source/blender/render/intern/render_types.h b/source/blender/render/intern/render_types.h
index ca4f72350e1..e5d766acf8d 100644
--- a/source/blender/render/intern/render_types.h
+++ b/source/blender/render/intern/render_types.h
@@ -106,7 +106,7 @@ struct Render {
struct RenderEngine *engine;
/* NOTE: This is a minimal dependency graph and evaluated scene which is enough to access view
- * layer visibility and use for post-precessing (compositor and sequencer). */
+ * layer visibility and use for postprocessing (compositor and sequencer). */
Depsgraph *pipeline_depsgraph;
Scene *pipeline_scene_eval;
diff --git a/source/blender/render/intern/texture_common.h b/source/blender/render/intern/texture_common.h
index b3a976c3fe0..5fc3af6153f 100644
--- a/source/blender/render/intern/texture_common.h
+++ b/source/blender/render/intern/texture_common.h
@@ -89,13 +89,13 @@ int imagewraposa(struct Tex *tex,
const float dyt[2],
struct TexResult *texres,
struct ImagePool *pool,
- const bool skip_load_image);
+ bool skip_load_image);
int imagewrap(struct Tex *tex,
struct Image *ima,
const float texvec[3],
struct TexResult *texres,
struct ImagePool *pool,
- const bool skip_load_image);
+ bool skip_load_image);
void image_sample(struct Image *ima,
float fx,
float fy,
diff --git a/source/blender/render/intern/texture_image.c b/source/blender/render/intern/texture_image.c
index edfa284242c..6ded799b773 100644
--- a/source/blender/render/intern/texture_image.c
+++ b/source/blender/render/intern/texture_image.c
@@ -912,7 +912,7 @@ static void feline_eval(TexResult *texr, ImBuf *ibuf, float fx, float fy, afdata
(maxn ? (float)maxn : 1.0f);
float du = maxn ? cosf(AFD->theta) * ll : 0.0f;
float dv = maxn ? sinf(AFD->theta) * ll : 0.0f;
- /* const float D = -0.5f*(du*du + dv*dv) / (AFD->majrad*AFD->majrad); */
+ // const float D = -0.5f*(du*du + dv*dv) / (AFD->majrad*AFD->majrad);
const float D = (EWA_MAXIDX + 1) * 0.25f * (du * du + dv * dv) / (AFD->majrad * AFD->majrad);
float d; /* TXF alpha: cw = 0.0f; */
int n; /* TXF alpha: clip = 0; */
@@ -959,7 +959,7 @@ static void alpha_clip_aniso(
/* TXF alpha: we're doing the same alpha-clip here as box-sample, but I'm doubting
* if this is actually correct for the all the filtering algorithms. */
- if (!(extflag == TXC_REPT || extflag == TXC_EXTD)) {
+ if (!(ELEM(extflag, TXC_REPT, TXC_EXTD))) {
rf.xmin = minx * (ibuf->x);
rf.xmax = maxx * (ibuf->x);
rf.ymin = miny * (ibuf->y);
diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc
new file mode 100644
index 00000000000..0e47c2cec8a
--- /dev/null
+++ b/source/blender/render/intern/texture_margin.cc
@@ -0,0 +1,555 @@
+/*
+ * 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 render
+ */
+
+#include "BLI_assert.h"
+#include "BLI_math_geom.h"
+#include "BLI_math_vec_types.hh"
+#include "BLI_math_vector.hh"
+#include "BLI_vector.hh"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_mesh.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "zbuf.h" // for rasterizer
+
+#include "RE_texture_margin.h"
+
+#include <algorithm>
+#include <math.h>
+#include <valarray>
+
+namespace blender::render::texturemargin {
+
+/* The map class contains both a pixel map which maps out polygon indices for all UV-polygons and
+ * adjacency tables.
+ */
+class TextureMarginMap {
+ static const int directions[4][2];
+
+ /* Maps UV-edges to their corresponding UV-edge. */
+ Vector<int> loop_adjacency_map_;
+ /* Maps UV-edges to their corresponding polygon. */
+ Vector<int> loop_to_poly_map_;
+
+ int w_, h_;
+ Vector<uint32_t> pixel_data_;
+ ZSpan zspan_;
+ uint32_t value_to_store_;
+ char *mask_;
+
+ MPoly const *mpoly_;
+ MLoop const *mloop_;
+ MLoopUV const *mloopuv_;
+ int totpoly_;
+ int totloop_;
+ int totedge_;
+
+ public:
+ TextureMarginMap(size_t w,
+ size_t h,
+ MPoly const *mpoly,
+ MLoop const *mloop,
+ MLoopUV const *mloopuv,
+ int totpoly,
+ int totloop,
+ int totedge)
+ : w_(w),
+ h_(h),
+ mpoly_(mpoly),
+ mloop_(mloop),
+ mloopuv_(mloopuv),
+ totpoly_(totpoly),
+ totloop_(totloop),
+ totedge_(totedge)
+ {
+ pixel_data_.resize(w_ * h_, 0xFFFFFFFF);
+
+ zbuf_alloc_span(&zspan_, w_, h_);
+
+ build_tables();
+ }
+
+ ~TextureMarginMap()
+ {
+ zbuf_free_span(&zspan_);
+ }
+
+ inline void set_pixel(int x, int y, uint32_t value)
+ {
+ BLI_assert(x < w_);
+ BLI_assert(x >= 0);
+ pixel_data_[y * w_ + x] = value;
+ }
+
+ inline uint32_t get_pixel(int x, int y) const
+ {
+ if (x < 0 || y < 0 || x >= w_ || y >= h_) {
+ return 0xFFFFFFFF;
+ }
+
+ return pixel_data_[y * w_ + x];
+ }
+
+ void rasterize_tri(float *v1, float *v2, float *v3, uint32_t value, char *mask)
+ {
+ /* NOTE: This is not thread safe, because the value to be written by the rasterizer is
+ * a class member. If this is ever made multi-threaded each thread needs to get it's own. */
+ value_to_store_ = value;
+ mask_ = mask;
+ zspan_scanconvert(
+ &zspan_, this, &(v1[0]), &(v2[0]), &(v3[0]), TextureMarginMap::zscan_store_pixel);
+ }
+
+ static void zscan_store_pixel(void *map, int x, int y, float, float)
+ {
+ /* NOTE: Not thread safe, see comment above.
+ *
+ */
+ TextureMarginMap *m = static_cast<TextureMarginMap *>(map);
+ m->set_pixel(x, y, m->value_to_store_);
+ if (m->mask_) {
+ m->mask_[y * m->w_ + x] = 1;
+ }
+ }
+
+/* The map contains 2 kinds of pixels: DijkstraPixels and polygon indices. The top bit determines
+ * what kind it is. With the top bit set, it is a 'dijkstra' pixel. The bottom 3 bits encode the
+ * direction of the shortest path and the remaining 28 bits are used to store the distance. If
+ * the top bit is not set, the rest of the bits is used to store the polygon index.
+ */
+#define PackDijkstraPixel(dist, dir) (0x80000000 + ((dist) << 3) + (dir))
+#define DijkstraPixelGetDistance(dp) (((dp) ^ 0x80000000) >> 3)
+#define DijkstraPixelGetDirection(dp) ((dp)&0x7)
+#define IsDijkstraPixel(dp) ((dp)&0x80000000)
+#define DijkstraPixelIsUnset(dp) ((dp) == 0xFFFFFFFF)
+
+ /* Use dijkstra's algorithm to 'grow' a border around the polygons marked in the map.
+ * For each pixel mark which direction is the shortest way to a polygon.
+ */
+ void grow_dijkstra(int margin)
+ {
+ class DijkstraActivePixel {
+ public:
+ DijkstraActivePixel(int dist, int _x, int _y) : distance(dist), x(_x), y(_y)
+ {
+ }
+ int distance;
+ int x, y;
+ };
+ auto cmp_dijkstrapixel_fun = [](DijkstraActivePixel const &a1, DijkstraActivePixel const &a2) {
+ return a1.distance > a2.distance;
+ };
+
+ Vector<DijkstraActivePixel> active_pixels;
+ for (int y = 0; y < h_; y++) {
+ for (int x = 0; x < w_; x++) {
+ if (DijkstraPixelIsUnset(get_pixel(x, y))) {
+ for (int i = 0; i < 4; i++) {
+ int xx = x - directions[i][0];
+ int yy = y - directions[i][1];
+
+ if (xx >= 0 && xx < w_ && yy >= 0 && yy < w_ && !IsDijkstraPixel(get_pixel(xx, yy))) {
+ set_pixel(x, y, PackDijkstraPixel(1, i));
+ active_pixels.append(DijkstraActivePixel(1, x, y));
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // std::make_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun);
+ // Not strictly needed because at this point it already is a heap.
+
+ while (active_pixels.size()) {
+ std::pop_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun);
+ DijkstraActivePixel p = active_pixels.pop_last();
+
+ int dist = p.distance;
+
+ dist++;
+ if (dist < margin) {
+ for (int i = 0; i < 4; i++) {
+ int x = p.x + directions[i][0];
+ int y = p.y + directions[i][1];
+ if (x >= 0 && x < w_ && y >= 0 && y < h_) {
+ uint32_t dp = get_pixel(x, y);
+ if (IsDijkstraPixel(dp) && (DijkstraPixelGetDistance(dp) > dist)) {
+ BLI_assert(abs((int)DijkstraPixelGetDirection(dp) - (int)i) != 2);
+ set_pixel(x, y, PackDijkstraPixel(dist, i));
+ active_pixels.append(DijkstraActivePixel(dist, x, y));
+ std::push_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Walk over the map and for margin pixels follow the direction stored in the bottom 3
+ * bits back to the polygon.
+ * Then look up the pixel from the next polygon.
+ */
+ void lookup_pixels(ImBuf *ibuf, char *mask, int maxPolygonSteps)
+ {
+ for (int y = 0; y < h_; y++) {
+ for (int x = 0; x < w_; x++) {
+ uint32_t dp = get_pixel(x, y);
+ if (IsDijkstraPixel(dp) && !DijkstraPixelIsUnset(dp)) {
+ int dist = DijkstraPixelGetDistance(dp);
+ int direction = DijkstraPixelGetDirection(dp);
+
+ int xx = x;
+ int yy = y;
+
+ /* Follow the dijkstra directions to find the polygon this margin pixels belongs to. */
+ while (dist > 0) {
+ xx -= directions[direction][0];
+ yy -= directions[direction][1];
+ dp = get_pixel(xx, yy);
+ dist--;
+ BLI_assert(!dist || (dist == DijkstraPixelGetDistance(dp)));
+ direction = DijkstraPixelGetDirection(dp);
+ }
+
+ uint32_t poly = get_pixel(xx, yy);
+
+ BLI_assert(!IsDijkstraPixel(poly));
+
+ float destX, destY;
+
+ int other_poly;
+ bool found_pixel_in_polygon = false;
+ if (lookup_pixel(x, y, poly, &destX, &destY, &other_poly)) {
+
+ for (int i = 0; i < maxPolygonSteps; i++) {
+ /* Force to pixel grid. */
+ int nx = (int)round(destX);
+ int ny = (int)round(destY);
+ uint32_t polygon_from_map = get_pixel(nx, ny);
+ if (other_poly == polygon_from_map) {
+ found_pixel_in_polygon = true;
+ break;
+ }
+
+ /* Look up again, but starting from the polygon we were expected to land in. */
+ lookup_pixel(nx, ny, other_poly, &destX, &destY, &other_poly);
+ }
+
+ if (found_pixel_in_polygon) {
+ bilinear_interpolation(ibuf, ibuf, destX, destY, x, y);
+ /* Add our new pixels to the assigned pixel map. */
+ mask[y * w_ + x] = 1;
+ }
+ }
+ }
+ else if (DijkstraPixelIsUnset(dp) || !IsDijkstraPixel(dp)) {
+ /* These are not margin pixels, make sure the extend filter which is run after this step
+ * leaves them alone.
+ */
+ mask[y * w_ + x] = 1;
+ }
+ }
+ }
+ }
+
+ private:
+ float2 uv_to_xy(MLoopUV const &mloopuv) const
+ {
+ float2 ret;
+ ret.x = ((mloopuv.uv[0] * w_) - (0.5f + 0.001f));
+ ret.y = ((mloopuv.uv[1] * h_) - (0.5f + 0.001f));
+ return ret;
+ }
+
+ void build_tables()
+ {
+ loop_to_poly_map_.resize(totloop_);
+ for (int i = 0; i < totpoly_; i++) {
+ for (int j = 0; j < mpoly_[i].totloop; j++) {
+ int l = j + mpoly_[i].loopstart;
+ loop_to_poly_map_[l] = i;
+ }
+ }
+
+ loop_adjacency_map_.resize(totloop_, -1);
+
+ Vector<int> tmpmap;
+ tmpmap.resize(totedge_, -1);
+
+ for (size_t i = 0; i < totloop_; i++) {
+ int edge = mloop_[i].e;
+ if (tmpmap[edge] == -1) {
+ loop_adjacency_map_[i] = -1;
+ tmpmap[edge] = i;
+ }
+ else {
+ BLI_assert(tmpmap[edge] >= 0);
+ loop_adjacency_map_[i] = tmpmap[edge];
+ loop_adjacency_map_[tmpmap[edge]] = i;
+ }
+ }
+ }
+
+ /* Find which edge of the src_poly is closest to x,y. Look up it's adjacent UV-edge and polygon.
+ * Then return the location of the equivalent pixel in the other polygon.
+ * Returns true if a new pixel location was found, false if it wasn't, which can happen if the
+ * margin pixel is on a corner, or the UV-edge doesn't have an adjacent polygon. */
+ bool lookup_pixel(
+ float x, float y, int src_poly, float *r_destx, float *r_desty, int *r_other_poly)
+ {
+ float2 point(x, y);
+
+ *r_destx = *r_desty = 0;
+
+ int found_edge = -1;
+ float found_dist = -1;
+ float found_t = 0;
+
+ /* Find the closest edge on which the point x,y can be projected.
+ */
+ for (size_t i = 0; i < mpoly_[src_poly].totloop; i++) {
+ int l1 = mpoly_[src_poly].loopstart + i;
+ int l2 = l1 + 1;
+ if (l2 >= mpoly_[src_poly].loopstart + mpoly_[src_poly].totloop) {
+ l2 = mpoly_[src_poly].loopstart;
+ }
+ /* edge points */
+ float2 edgepoint1 = uv_to_xy(mloopuv_[l1]);
+ float2 edgepoint2 = uv_to_xy(mloopuv_[l2]);
+ /* Vector AB is the vector from the first edge point to the second edge point.
+ * Vector AP is the vector from the first edge point to our point under investigation. */
+ float2 ab = edgepoint2 - edgepoint1;
+ float2 ap = point - edgepoint1;
+
+ /* Project ap onto ab. */
+ float dotv = math::dot(ab, ap);
+
+ float ablensq = math::length_squared(ab);
+
+ float t = dotv / ablensq;
+
+ if (t >= 0.0 && t <= 1.0) {
+
+ /* Find the point on the edge closest to P */
+ float2 reflect_point = edgepoint1 + (t * ab);
+ /* This is the vector to P, so 90 degrees out from the edge. */
+ float2 reflect_vec = reflect_point - point;
+
+ float reflectLen = sqrt(reflect_vec[0] * reflect_vec[0] + reflect_vec[1] * reflect_vec[1]);
+ float cross = ab[0] * reflect_vec[1] - ab[1] * reflect_vec[0];
+ /* Only if P is on the outside of the edge, which means the cross product is positive,
+ * we consider this edge.
+ */
+ bool valid = (cross > 0.0);
+
+ if (valid && (found_dist < 0 || reflectLen < found_dist)) {
+ /* Stother_ab the info of the closest edge so far. */
+ found_dist = reflectLen;
+ found_t = t;
+ found_edge = i + mpoly_[src_poly].loopstart;
+ }
+ }
+ }
+
+ if (found_edge < 0) {
+ return false;
+ }
+
+ /* Get the 'other' edge. I.E. the UV edge from the neighbor polygon. */
+ int other_edge = loop_adjacency_map_[found_edge];
+
+ if (other_edge < 0) {
+ return false;
+ }
+
+ int dst_poly = loop_to_poly_map_[other_edge];
+
+ if (r_other_poly) {
+ *r_other_poly = dst_poly;
+ }
+
+ int other_edge2 = other_edge + 1;
+ if (other_edge2 >= mpoly_[dst_poly].loopstart + mpoly_[dst_poly].totloop) {
+ other_edge2 = mpoly_[dst_poly].loopstart;
+ }
+
+ float2 other_edgepoint1 = uv_to_xy(mloopuv_[other_edge]);
+ float2 other_edgepoint2 = uv_to_xy(mloopuv_[other_edge2]);
+
+ /* Calculate the vector from the order edges last point to it's first point. */
+ float2 other_ab = other_edgepoint1 - other_edgepoint2;
+ float2 other_reflect_point = other_edgepoint2 + (found_t * other_ab);
+ float2 perpendicular_other_ab;
+ perpendicular_other_ab.x = other_ab.y;
+ perpendicular_other_ab.y = -other_ab.x;
+
+ /* The new point is dound_dist distance from other_reflect_point at a 90 degree angle to
+ * other_ab */
+ float2 new_point = other_reflect_point + (found_dist / math::length(perpendicular_other_ab)) *
+ perpendicular_other_ab;
+
+ *r_destx = new_point.x;
+ *r_desty = new_point.y;
+
+ return true;
+ }
+}; // class TextureMarginMap
+
+const int TextureMarginMap::directions[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
+
+static void generate_margin(ImBuf *ibuf,
+ char *mask,
+ const int margin,
+ const Mesh *me,
+ DerivedMesh *dm,
+ char const *uv_layer)
+{
+
+ MPoly *mpoly;
+ MLoop *mloop;
+ MLoopUV const *mloopuv;
+ int totpoly, totloop, totedge;
+
+ int tottri;
+ MLoopTri const *looptri;
+ MLoopTri *looptri_mem = NULL;
+
+ if (me) {
+ BLI_assert(dm == NULL);
+ totpoly = me->totpoly;
+ totloop = me->totloop;
+ totedge = me->totedge;
+ mpoly = me->mpoly;
+ mloop = me->mloop;
+
+ if ((uv_layer == NULL) || (uv_layer[0] == '\0')) {
+ mloopuv = static_cast<MLoopUV const *>(CustomData_get_layer(&me->ldata, CD_MLOOPUV));
+ }
+ else {
+ int uv_id = CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer);
+ mloopuv = static_cast<MLoopUV const *>(
+ CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, uv_id));
+ }
+
+ tottri = poly_to_tri_count(me->totpoly, me->totloop);
+ looptri_mem = static_cast<MLoopTri *>(MEM_mallocN(sizeof(*looptri) * tottri, __func__));
+ BKE_mesh_recalc_looptri(
+ me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri_mem);
+ looptri = looptri_mem;
+ }
+ else {
+ BLI_assert(dm != NULL);
+ BLI_assert(me == NULL);
+ BLI_assert(mloopuv == NULL);
+ totpoly = dm->getNumPolys(dm);
+ totedge = dm->getNumEdges(dm);
+ totloop = dm->getNumLoops(dm);
+ mpoly = dm->getPolyArray(dm);
+ mloop = dm->getLoopArray(dm);
+ mloopuv = (MLoopUV const *)dm->getLoopDataArray(dm, CD_MLOOPUV);
+
+ looptri = dm->getLoopTriArray(dm);
+ tottri = dm->getNumLoopTri(dm);
+ }
+
+ TextureMarginMap map(ibuf->x, ibuf->y, mpoly, mloop, mloopuv, totpoly, totloop, totedge);
+
+ bool draw_new_mask = false;
+ /* Now the map contains 3 sorts of values: 0xFFFFFFFF for empty pixels, `0x80000000 + polyindex`
+ * for margin pixels, just `polyindex` for poly pixels. */
+ if (mask) {
+ mask = (char *)MEM_dupallocN(mask);
+ }
+ else {
+ mask = (char *)MEM_callocN(sizeof(char) * ibuf->x * ibuf->y, __func__);
+ draw_new_mask = true;
+ }
+
+ for (int i = 0; i < tottri; i++) {
+ const MLoopTri *lt = &looptri[i];
+ float vec[3][2];
+
+ for (int a = 0; a < 3; a++) {
+ const float *uv = mloopuv[lt->tri[a]].uv;
+
+ /* NOTE(campbell): workaround for pixel aligned UVs which are common and can screw up our
+ * intersection tests where a pixel gets in between 2 faces or the middle of a quad,
+ * camera aligned quads also have this problem but they are less common.
+ * Add a small offset to the UVs, fixes bug T18685. */
+ vec[a][0] = uv[0] * (float)ibuf->x - (0.5f + 0.001f);
+ vec[a][1] = uv[1] * (float)ibuf->y - (0.5f + 0.002f);
+ }
+
+ BLI_assert(lt->poly < 0x80000000); // NOTE: we need the top bit for the dijkstra distance map
+ map.rasterize_tri(vec[0], vec[1], vec[2], lt->poly, draw_new_mask ? mask : NULL);
+ }
+
+ char *tmpmask = (char *)MEM_dupallocN(mask);
+ /* Extend (with averaging) by 2 pixels. Those will be overwritten, but it
+ * helps linear interpolations on the edges of polygons. */
+ IMB_filter_extend(ibuf, tmpmask, 2);
+ MEM_freeN(tmpmask);
+
+ map.grow_dijkstra(margin);
+
+ /* Looking further than 3 polygons away leads to so much cumulative rounding
+ * that it isn't worth it. So hard-code it to 3. */
+ map.lookup_pixels(ibuf, mask, 3);
+
+ /* Use the extend filter to fill in the missing pixels at the corners, not strictly correct, but
+ * the visual difference seems very minimal. This also catches pixels we missed because of very
+ * narrow polygons.
+ */
+ IMB_filter_extend(ibuf, mask, margin);
+
+ MEM_freeN(mask);
+
+ if (looptri_mem) {
+ MEM_freeN(looptri_mem);
+ }
+}
+
+} // namespace blender::render::texturemargin
+
+void RE_generate_texturemargin_adjacentfaces(
+ ImBuf *ibuf, char *mask, const int margin, const Mesh *me, char const *uv_layer)
+{
+ blender::render::texturemargin::generate_margin(ibuf, mask, margin, me, NULL, uv_layer);
+}
+
+void RE_generate_texturemargin_adjacentfaces_dm(ImBuf *ibuf,
+ char *mask,
+ const int margin,
+ DerivedMesh *dm)
+{
+ blender::render::texturemargin::generate_margin(ibuf, mask, margin, NULL, dm, NULL);
+}
diff --git a/source/blender/render/intern/texture_pointdensity.c b/source/blender/render/intern/texture_pointdensity.c
index 06dd570ce2c..683260f86cb 100644
--- a/source/blender/render/intern/texture_pointdensity.c
+++ b/source/blender/render/intern/texture_pointdensity.c
@@ -47,6 +47,7 @@
#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_lattice.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
@@ -368,19 +369,11 @@ static void pointdensity_cache_vertex_weight(PointDensity *pd,
}
}
-static void pointdensity_cache_vertex_normal(PointDensity *pd,
- Object *UNUSED(ob),
- Mesh *mesh,
- float *data_color)
+static void pointdensity_cache_vertex_normal(Mesh *mesh, float *data_color)
{
- MVert *mvert = mesh->mvert, *mv;
- int i;
-
BLI_assert(data_color);
-
- for (i = 0, mv = mvert; i < pd->totpoints; i++, mv++, data_color += 3) {
- normal_short_to_float_v3(data_color, mv->no);
- }
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ memcpy(data_color, vert_normals, sizeof(float[3]) * mesh->totvert);
}
static void pointdensity_cache_object(PointDensity *pd, Object *ob)
@@ -442,7 +435,7 @@ static void pointdensity_cache_object(PointDensity *pd, Object *ob)
pointdensity_cache_vertex_weight(pd, ob, mesh, data_color);
break;
case TEX_PD_COLOR_VERTNOR:
- pointdensity_cache_vertex_normal(pd, ob, mesh, data_color);
+ pointdensity_cache_vertex_normal(mesh, data_color);
break;
}
@@ -928,9 +921,6 @@ static void point_density_sample_func(void *__restrict data_v,
}
}
-/* NOTE 1: Requires RE_point_density_cache() to be called first.
- * NOTE 2: Frees point density structure after sampling.
- */
void RE_point_density_sample(Depsgraph *depsgraph,
PointDensity *pd,
const int resolution,
diff --git a/source/blender/render/intern/texture_procedural.c b/source/blender/render/intern/texture_procedural.c
index bea9dfbb0ed..c894d8d9f48 100644
--- a/source/blender/render/intern/texture_procedural.c
+++ b/source/blender/render/intern/texture_procedural.c
@@ -43,15 +43,15 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
-#include "BKE_image.h"
-#include "BKE_node.h"
-
#include "BKE_colorband.h"
+#include "BKE_image.h"
#include "BKE_material.h"
+#include "BKE_node.h"
#include "BKE_scene.h"
-
#include "BKE_texture.h"
+#include "NOD_texture.h"
+
#include "MEM_guardedalloc.h"
#include "render_types.h"
@@ -745,7 +745,7 @@ static int mg_distNoiseTex(const Tex *tex, const float texvec[3], TexResult *tex
/* ------------------------------------------------------------------------- */
/* newnoise: Voronoi texture type
*
- * probably the slowest, especially with minkovsky, bumpmapping, could be done another way.
+ * probably the slowest, especially with minkovsky, bump-mapping, could be done another way.
*/
static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres)
@@ -1399,9 +1399,6 @@ static int multitex_nodes_intern(Tex *tex,
use_nodes);
}
-/* this is called from the shader and texture nodes
- * Use it from render pipeline only!
- */
int multitex_nodes(Tex *tex,
const float texvec[3],
float dxt[3],
@@ -1429,13 +1426,6 @@ int multitex_nodes(Tex *tex,
true);
}
-/**
- * \warning if the texres's values are not declared zero,
- * check the return value to be sure the color values are set before using the r/g/b values,
- * otherwise you may use uninitialized values - Campbell
- *
- * Use it for stuff which is out of render pipeline.
- */
int multitex_ext(Tex *tex,
float texvec[3],
float dxt[3],
@@ -1463,10 +1453,6 @@ int multitex_ext(Tex *tex,
true);
}
-/* extern-tex doesn't support nodes (ntreeBeginExec() can't be called when rendering is going on)\
- *
- * Use it for stuff which is out of render pipeline.
- */
int multitex_ext_safe(Tex *tex,
const float texvec[3],
TexResult *texres,
@@ -1492,8 +1478,6 @@ int multitex_ext_safe(Tex *tex,
/* ------------------------------------------------------------------------- */
-/* in = destination, tex = texture, out = previous color */
-/* fact = texture strength, facg = button strength value */
void texture_rgb_blend(
float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype)
{
@@ -1722,11 +1706,6 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
/* ------------------------------------------------------------------------- */
-/**
- * \param pool: Thread pool, may be NULL.
- *
- * \return True if the texture has color, otherwise false.
- */
bool RE_texture_evaluate(const MTex *mtex,
const float vec[3],
const int thread,
diff --git a/source/blender/render/intern/zbuf.c b/source/blender/render/intern/zbuf.c
index 726124871ee..beba10ad82a 100644
--- a/source/blender/render/intern/zbuf.c
+++ b/source/blender/render/intern/zbuf.c
@@ -19,6 +19,9 @@
/** \file
* \ingroup render
+ *
+ * \note Some of this logic has been duplicated in `COM_VectorBlurOperation.cc`
+ * changes here may also apply also apply to that file.
*/
/*---------------------------------------------------------------------------*/
@@ -41,7 +44,6 @@
/* ****************** Spans ******************************* */
-/* each zbuffer has coordinates transformed to local rect coordinates, so we can simply clip */
void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty)
{
memset(zspan, 0, sizeof(ZSpan));
@@ -170,9 +172,6 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2])
/* Functions */
/*-----------------------------------------------------------*/
-/* Scan-convert for strand triangles, calls function for each x, y coordinate
- * and gives UV barycentrics and z. */
-
void zspan_scanconvert(ZSpan *zspan,
void *handle,
float *v1,
diff --git a/source/blender/render/intern/zbuf.h b/source/blender/render/intern/zbuf.h
index 41fa15c594f..3e4832e04d6 100644
--- a/source/blender/render/intern/zbuf.h
+++ b/source/blender/render/intern/zbuf.h
@@ -24,7 +24,7 @@
extern "C" {
#endif
-/* span fill in method, is also used to localize data for zbuffering */
+/** Span fill in method, is also used to localize data for Z-buffering. */
typedef struct ZSpan {
int rectx, recty; /* range for clipping */
@@ -33,9 +33,16 @@ typedef struct ZSpan {
float *span1, *span2;
} ZSpan;
+/**
+ * Each Z-buffer has coordinates transformed to local rect coordinates, so we can simply clip.
+ */
void zbuf_alloc_span(struct ZSpan *zspan, int rectx, int recty);
void zbuf_free_span(struct ZSpan *zspan);
+/**
+ * Scan-convert for strand triangles, calls function for each x, y coordinate
+ * and gives UV barycentrics and z.
+ */
void zspan_scanconvert(struct ZSpan *zspan,
void *handle,
float *v1,
diff --git a/source/blender/sequencer/CMakeLists.txt b/source/blender/sequencer/CMakeLists.txt
index f060e6ad69b..54524e453d4 100644
--- a/source/blender/sequencer/CMakeLists.txt
+++ b/source/blender/sequencer/CMakeLists.txt
@@ -46,6 +46,7 @@ set(INC_SYS
set(SRC
SEQ_add.h
+ SEQ_animation.h
SEQ_clipboard.h
SEQ_edit.h
SEQ_effects.h
@@ -62,7 +63,10 @@ set(SRC
SEQ_transform.h
SEQ_utils.h
+ intern/animation.c
intern/clipboard.c
+ intern/disk_cache.c
+ intern/disk_cache.h
intern/effects.c
intern/effects.h
intern/image_cache.c
diff --git a/source/blender/sequencer/SEQ_add.h b/source/blender/sequencer/SEQ_add.h
index d2a731d9953..85f44ab914f 100644
--- a/source/blender/sequencer/SEQ_add.h
+++ b/source/blender/sequencer/SEQ_add.h
@@ -67,47 +67,146 @@ typedef struct SeqLoadData {
bool allow_invalid_file; /* Used by RNA API to create placeholder strips. */
} SeqLoadData;
+/**
+ * Initialize common SeqLoadData members
+ *
+ * \param load_data: SeqLoadData to be initialized
+ * \param name: strip name (can be NULL)
+ * \param path: path to file that is used as strip input (can be NULL)
+ * \param start_frame: timeline frame where strip will be created
+ * \param channel: timeline channel where strip will be created
+ */
void SEQ_add_load_data_init(struct SeqLoadData *load_data,
const char *name,
const char *path,
- const int start_frame,
- const int channel);
+ int start_frame,
+ int channel);
+/**
+ * Add image strip.
+ * \note Use #SEQ_add_image_set_directory() and #SEQ_add_image_load_file() to load image sequences
+ *
+ * \param bmain: Main reference
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_image_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add sound strip.
+ * \note Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences
+ *
+ * \param bmain: Main reference
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_sound_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data,
- const double audio_offset);
+ double audio_offset);
+/**
+ * Add meta strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_meta_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add movie strip.
+ *
+ * \param bmain: Main reference
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_movie_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data,
double *r_start_offset);
+/**
+ * Add scene strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_scene_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add movieclip strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_movieclip_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add mask strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_mask_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add effect strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_effect_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Set directory used by image strip.
+ *
+ * \param seq: image strip to be changed
+ * \param path: directory path
+ */
void SEQ_add_image_set_directory(struct Sequence *seq, char *path);
+/**
+ * Set directory used by image strip.
+ *
+ * \param seq: image strip to be changed
+ * \param strip_frame: frame index of strip to be changed
+ * \param filename: image filename (only filename, not complete path)
+ */
void SEQ_add_image_load_file(struct Sequence *seq, size_t strip_frame, char *filename);
+/**
+ * Set image strip alpha mode
+ *
+ * \param seq: image strip to be changed
+ */
void SEQ_add_image_init_alpha_mode(struct Sequence *seq);
+/**
+ * \note caller should run `SEQ_time_update_sequence(scene, seq)` after..
+ */
void SEQ_add_reload_new_file(struct Main *bmain,
struct Scene *scene,
struct Sequence *seq,
- const bool lock_range);
+ bool lock_range);
void SEQ_add_movie_reload_if_needed(struct Main *bmain,
struct Scene *scene,
struct Sequence *seq,
diff --git a/source/blender/sequencer/SEQ_animation.h b/source/blender/sequencer/SEQ_animation.h
new file mode 100644
index 00000000000..028f932344f
--- /dev/null
+++ b/source/blender/sequencer/SEQ_animation.h
@@ -0,0 +1,41 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup sequencer
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct GSet;
+struct ListBase;
+struct Scene;
+struct Sequence;
+
+void SEQ_free_animdata(struct Scene *scene, struct Sequence *seq);
+void SEQ_offset_animdata(struct Scene *scene, struct Sequence *seq, int ofs);
+struct GSet *SEQ_fcurves_by_strip_get(const struct Sequence *seq, struct ListBase *fcurve_base);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/sequencer/SEQ_clipboard.h b/source/blender/sequencer/SEQ_clipboard.h
index ea7f01e6ae3..dc78f8cc1a2 100644
--- a/source/blender/sequencer/SEQ_clipboard.h
+++ b/source/blender/sequencer/SEQ_clipboard.h
@@ -33,11 +33,19 @@ struct Scene;
struct Sequence;
extern struct ListBase seqbase_clipboard;
+extern struct ListBase fcurves_clipboard;
extern int seqbase_clipboard_frame;
void SEQ_clipboard_pointers_store(struct Main *bmain, struct ListBase *seqbase);
void SEQ_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain);
void SEQ_clipboard_free(void);
void SEQ_clipboard_active_seq_name_store(struct Scene *scene);
+/**
+ * Check if strip was active when it was copied. User should restrict this check to pasted strips
+ * before ensuring original name, because strip name comparison is used to check.
+ *
+ * \param pasted_seq: Strip that is pasted(duplicated) from clipboard
+ * \return true if strip was active, false otherwise
+ */
bool SEQ_clipboard_pasted_seq_was_active(struct Sequence *pasted_seq);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/SEQ_edit.h b/source/blender/sequencer/SEQ_edit.h
index fbbf4bc53ea..73723c23920 100644
--- a/source/blender/sequencer/SEQ_edit.h
+++ b/source/blender/sequencer/SEQ_edit.h
@@ -33,13 +33,40 @@ struct Scene;
struct Sequence;
int SEQ_edit_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str);
+/**
+ * Move sequence to seqbase.
+ *
+ * \param scene: Scene containing the editing
+ * \param seqbase: seqbase where `seq` is located
+ * \param seq: Sequence to move
+ * \param dst_seqbase: Target seqbase
+ */
+bool SEQ_edit_move_strip_to_seqbase(struct Scene *scene,
+ ListBase *seqbase,
+ struct Sequence *seq,
+ ListBase *dst_seqbase);
+/**
+ * Move sequence to meta sequence.
+ *
+ * \param scene: Scene containing the editing
+ * \param src_seq: Sequence to move
+ * \param dst_seqm: Target Meta sequence
+ * \param error_str: Error message
+ */
bool SEQ_edit_move_strip_to_meta(struct Scene *scene,
struct Sequence *src_seq,
struct Sequence *dst_seqm,
const char **error_str);
+bool SEQ_meta_separate(struct Scene *scene, struct Sequence *src_meta, const char **error_str);
+/**
+ * Flag seq and its users (effects) for removal.
+ */
void SEQ_edit_flag_for_removal(struct Scene *scene,
struct ListBase *seqbase,
struct Sequence *seq);
+/**
+ * Remove all flagged sequences, return true if sequence is removed.
+ */
void SEQ_edit_remove_flagged_sequences(struct Scene *scene, struct ListBase *seqbase);
void SEQ_edit_update_muting(struct Editing *ed);
@@ -48,17 +75,37 @@ typedef enum eSeqSplitMethod {
SEQ_SPLIT_HARD,
} eSeqSplitMethod;
+/**
+ * Split Sequence at timeline_frame in two.
+ *
+ * \param bmain: Main in which Sequence is located
+ * \param scene: Scene in which Sequence is located
+ * \param seqbase: ListBase in which Sequence is located
+ * \param seq: Sequence to be split
+ * \param timeline_frame: frame at which seq is split.
+ * \param method: affects type of offset to be applied to resize Sequence
+ * \return The newly created sequence strip. This is always Sequence on right side.
+ */
struct Sequence *SEQ_edit_strip_split(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct Sequence *seq,
- const int timeline_frame,
- const eSeqSplitMethod method,
+ int timeline_frame,
+ eSeqSplitMethod method,
const char **r_error);
+/**
+ * Find gap after initial_frame and move strips on right side to close the gap
+ *
+ * \param scene: Scene in which strips are located
+ * \param seqbase: ListBase in which strips are located
+ * \param initial_frame: frame on timeline from where gaps are searched for
+ * \param remove_all_gaps: remove all gaps instead of one gap
+ * \return true if gap is removed, otherwise false
+ */
bool SEQ_edit_remove_gaps(struct Scene *scene,
struct ListBase *seqbase,
- const int initial_frame,
- const bool remove_all_gaps);
+ int initial_frame,
+ bool remove_all_gaps);
void SEQ_edit_sequence_name_set(struct Scene *scene, struct Sequence *seq, const char *new_name);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/SEQ_effects.h b/source/blender/sequencer/SEQ_effects.h
index 4bd5b54b36b..8a79abde7bc 100644
--- a/source/blender/sequencer/SEQ_effects.h
+++ b/source/blender/sequencer/SEQ_effects.h
@@ -59,19 +59,19 @@ struct SeqEffectHandle {
void (*load)(struct Sequence *seqconst);
/* duplicate */
- void (*copy)(struct Sequence *dst, struct Sequence *src, const int flag);
+ void (*copy)(struct Sequence *dst, struct Sequence *src, int flag);
/* destruct */
- void (*free)(struct Sequence *seq, const bool do_id_user);
+ void (*free)(struct Sequence *seq, bool do_id_user);
/* returns: -1: no input needed,
* 0: no early out,
* 1: out = ibuf1,
* 2: out = ibuf2 */
- int (*early_out)(struct Sequence *seq, float facf0, float facf1);
+ int (*early_out)(struct Sequence *seq, float fac);
- /* stores the default facf0 and facf1 if no IPO is present */
- void (*get_default_fac)(struct Sequence *seq, float timeline_frame, float *facf0, float *facf1);
+ /* sets the default `fac` value */
+ void (*get_default_fac)(struct Sequence *seq, float timeline_frame, float *fac);
/* execute the effect
* sequence effects are only required to either support
@@ -81,8 +81,7 @@ struct SeqEffectHandle {
struct ImBuf *(*execute)(const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
struct ImBuf *ibuf1,
struct ImBuf *ibuf2,
struct ImBuf *ibuf3);
@@ -95,8 +94,7 @@ struct SeqEffectHandle {
void (*execute_slice)(const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
struct ImBuf *ibuf1,
struct ImBuf *ibuf2,
struct ImBuf *ibuf3,
@@ -107,8 +105,8 @@ struct SeqEffectHandle {
struct SeqEffectHandle SEQ_effect_handle_get(struct Sequence *seq);
int SEQ_effect_get_num_inputs(int seq_type);
-void SEQ_effect_text_font_unload(struct TextVars *data, const bool do_id_user);
-void SEQ_effect_text_font_load(struct TextVars *data, const bool do_id_user);
+void SEQ_effect_text_font_unload(struct TextVars *data, bool do_id_user);
+void SEQ_effect_text_font_load(struct TextVars *data, bool do_id_user);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h
index d2a47a13db3..c26886c2e6c 100644
--- a/source/blender/sequencer/SEQ_iterator.h
+++ b/source/blender/sequencer/SEQ_iterator.h
@@ -63,42 +63,179 @@ typedef struct SeqIterator {
bool iterator_initialized;
} SeqIterator;
+/**
+ * Utility function for SEQ_ITERATOR_FOREACH macro.
+ * Ensure, that iterator is initialized. During initialization return pointer to collection element
+ * and step gset iterator. When this function is called after iterator has been initialized, it
+ * will do nothing and return true.
+ *
+ * \param collection: collection to iterate
+ * \param iterator: iterator to be initialized
+ * \param r_seq: pointer to Sequence pointer
+ *
+ * \return false when iterator can not be initialized, true otherwise
+ */
bool SEQ_iterator_ensure(SeqCollection *collection,
SeqIterator *iterator,
struct Sequence **r_seq);
+/**
+ * Utility function for SEQ_ITERATOR_FOREACH macro.
+ * Yield collection element
+ *
+ * \param iterator: iterator to be initialized
+ *
+ * \return collection element or NULL when iteration has ended
+ */
struct Sequence *SEQ_iterator_yield(SeqIterator *iterator);
-/* Callback format for the for_each function below. */
+/**
+ * Callback format for the for_each function below.
+ */
typedef bool (*SeqForEachFunc)(struct Sequence *seq, void *user_data);
+/**
+ * Utility function to recursively iterate through all sequence strips in a `seqbase` list.
+ * Uses callback to do operations on each sequence element.
+ * The callback can stop the iteration if needed.
+ *
+ * \param seqbase: #ListBase of sequences to be iterated over.
+ * \param callback: query function callback, returns false if iteration should stop.
+ * \param user_data: pointer to user data that can be used in the callback function.
+ */
void SEQ_for_each_callback(struct ListBase *seqbase, SeqForEachFunc callback, void *user_data);
+/**
+ * Create new empty strip collection.
+ *
+ * \return empty strip collection.
+ */
SeqCollection *SEQ_collection_create(const char *name);
+/**
+ * Duplicate collection
+ *
+ * \param collection: collection to be duplicated
+ * \return duplicate of collection
+ */
SeqCollection *SEQ_collection_duplicate(SeqCollection *collection);
+/**
+ * Return number of items in collection.
+ */
uint SEQ_collection_len(const SeqCollection *collection);
+/**
+ * Check if seq is in collection.
+ */
bool SEQ_collection_has_strip(const struct Sequence *seq, const SeqCollection *collection);
-bool SEQ_collection_append_strip(struct Sequence *seq, SeqCollection *data);
-bool SEQ_collection_remove_strip(struct Sequence *seq, SeqCollection *data);
+/**
+ * Add strip to collection.
+ *
+ * \param seq: strip to be added
+ * \param collection: collection to which strip will be added
+ * \return false if strip is already in set, otherwise true
+ */
+bool SEQ_collection_append_strip(struct Sequence *seq, SeqCollection *collection);
+/**
+ * Remove strip from collection.
+ *
+ * \param seq: strip to be removed
+ * \param collection: collection from which strip will be removed
+ * \return true if strip exists in set and it was removed from set, otherwise false
+ */
+bool SEQ_collection_remove_strip(struct Sequence *seq, SeqCollection *collection);
+/**
+ * Free strip collection.
+ *
+ * \param collection: collection to be freed
+ */
void SEQ_collection_free(SeqCollection *collection);
+/**
+ * Move strips from collection_src to collection_dst. Source collection will be freed.
+ *
+ * \param collection_dst: destination collection
+ * \param collection_src: source collection
+ */
void SEQ_collection_merge(SeqCollection *collection_dst, SeqCollection *collection_src);
+/**
+ * Remove strips from collection that are also in `exclude_elements`. Source collection will be
+ * freed.
+ *
+ * \param collection: collection from which strips are removed
+ * \param exclude_elements: collection of strips to be removed
+ */
void SEQ_collection_exclude(SeqCollection *collection, SeqCollection *exclude_elements);
+/**
+ * Expand collection by running SEQ_query() for each strip, which will be used as reference.
+ * Results of these queries will be merged into provided collection.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \param collection: SeqCollection to be expanded
+ * \param seq_query_func: query function callback
+ */
void SEQ_collection_expand(struct ListBase *seqbase,
SeqCollection *collection,
- void query_func(struct Sequence *seq_reference,
- struct ListBase *seqbase,
- SeqCollection *collection));
+ void seq_query_func(struct Sequence *seq_reference,
+ struct ListBase *seqbase,
+ SeqCollection *collection));
+/**
+ * Query strips from seqbase. seq_reference is used by query function as filter condition.
+ *
+ * \param seq_reference: reference strip for query function
+ * \param seqbase: ListBase in which strips are queried
+ * \param seq_query_func: query function callback
+ * \return strip collection
+ */
SeqCollection *SEQ_query_by_reference(struct Sequence *seq_reference,
struct ListBase *seqbase,
void seq_query_func(struct Sequence *seq_reference,
struct ListBase *seqbase,
SeqCollection *collection));
+/**
+ * Query all selected strips in seqbase.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \return strip collection
+ */
SeqCollection *SEQ_query_selected_strips(struct ListBase *seqbase);
+/**
+ * Query all unselected strips in seqbase.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \return strip collection
+ */
SeqCollection *SEQ_query_unselected_strips(struct ListBase *seqbase);
+/**
+ * Query all strips in seqbase. This does not include strips nested in meta strips.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \return strip collection
+ */
SeqCollection *SEQ_query_all_strips(ListBase *seqbase);
+/**
+ * Query all strips in seqbase and nested meta strips.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \return strip collection
+ */
SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase);
+/**
+ * Query strips that are rendered at \a timeline_frame when \a displayed channel is viewed
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \param timeline_frame: viewed frame
+ * \param displayed_channel: viewed channel. when set to 0, no channel filter is applied
+ * \return strip collection
+ */
SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase,
- const int timeline_frame,
- const int displayed_channel);
+ int timeline_frame,
+ int displayed_channel);
+/**
+ * Query all effect strips that are directly or indirectly connected to seq_reference.
+ * This includes all effects of seq_reference, strips used by another inputs and their effects, so
+ * that whole chain is fully independent of other strips.
+ *
+ * \param seq_reference: reference strip
+ * \param seqbase: ListBase in which strips are queried
+ * \param collection: collection to be filled
+ */
void SEQ_query_strip_effect_chain(struct Sequence *seq_reference,
struct ListBase *seqbase,
SeqCollection *collection);
diff --git a/source/blender/sequencer/SEQ_prefetch.h b/source/blender/sequencer/SEQ_prefetch.h
index 93fc8883e99..980f7611094 100644
--- a/source/blender/sequencer/SEQ_prefetch.h
+++ b/source/blender/sequencer/SEQ_prefetch.h
@@ -31,6 +31,10 @@ struct Main;
struct Scene;
void SEQ_prefetch_stop_all(void);
+/**
+ * Use also to update scene and context changes
+ * This function should almost always be called by cache invalidation, not directly.
+ */
void SEQ_prefetch_stop(struct Scene *scene);
bool SEQ_prefetch_need_redraw(struct Main *bmain, struct Scene *scene);
diff --git a/source/blender/sequencer/SEQ_proxy.h b/source/blender/sequencer/SEQ_proxy.h
index 7bfe932ff1c..164b279245c 100644
--- a/source/blender/sequencer/SEQ_proxy.h
+++ b/source/blender/sequencer/SEQ_proxy.h
@@ -42,7 +42,8 @@ bool SEQ_proxy_rebuild_context(struct Main *bmain,
struct Scene *scene,
struct Sequence *seq,
struct GSet *file_list,
- struct ListBase *queue);
+ struct ListBase *queue,
+ bool build_only_on_bad_performance);
void SEQ_proxy_rebuild(struct SeqIndexBuildContext *context,
short *stop,
short *do_update,
diff --git a/source/blender/sequencer/SEQ_relations.h b/source/blender/sequencer/SEQ_relations.h
index 54e53193b48..9571e826759 100644
--- a/source/blender/sequencer/SEQ_relations.h
+++ b/source/blender/sequencer/SEQ_relations.h
@@ -34,12 +34,14 @@ struct ReportList;
struct Scene;
struct Sequence;
+/**
+ * Function to free imbuf and anim data on changes.
+ */
void SEQ_relations_sequence_free_anim(struct Sequence *seq);
-void SEQ_relations_update_changed_seq_and_deps(struct Scene *scene,
- struct Sequence *changed_seq,
- int len_change,
- int ibuf_change);
bool SEQ_relations_check_scene_recursion(struct Scene *scene, struct ReportList *reports);
+/**
+ * Check if "seq_main" (indirectly) uses strip "seq".
+ */
bool SEQ_relations_render_loop_check(struct Sequence *seq_main, struct Sequence *seq);
void SEQ_relations_free_imbuf(struct Scene *scene, struct ListBase *seqbasep, bool for_render);
void SEQ_relations_invalidate_cache_raw(struct Scene *scene, struct Sequence *seq);
@@ -52,11 +54,18 @@ void SEQ_relations_invalidate_cache_in_range(struct Scene *scene,
struct Sequence *seq,
struct Sequence *range_mask,
int invalidate_types);
+/**
+ * Release FFmpeg handles of strips that are not currently displayed to minimize memory usage.
+ */
void SEQ_relations_free_all_anim_ibufs(struct Scene *scene, int timeline_frame);
-/* A debug and development function which checks whether sequences have unique UUIDs.
- * Errors will be reported to the console. */
+/**
+ * A debug and development function which checks whether sequences have unique UUIDs.
+ * Errors will be reported to the console.
+ */
void SEQ_relations_check_uuids_unique_and_report(const struct Scene *scene);
-/* Generate new UUID for the given sequence. */
+/**
+ * Generate new UUID for the given sequence.
+ */
void SEQ_relations_session_uuid_generate(struct Sequence *sequence);
void SEQ_cache_cleanup(struct Scene *scene);
@@ -65,6 +74,9 @@ void SEQ_cache_iterate(
void *userdata,
bool callback_init(void *userdata, size_t item_count),
bool callback_iter(void *userdata, struct Sequence *seq, int timeline_frame, int cache_type));
+/**
+ * Return immediate parent meta of sequence.
+ */
struct Sequence *SEQ_find_metastrip_by_sequence(ListBase *seqbase /* = ed->seqbase */,
struct Sequence *meta /* = NULL */,
struct Sequence *seq);
diff --git a/source/blender/sequencer/SEQ_render.h b/source/blender/sequencer/SEQ_render.h
index e99dc6d344f..7f10160bf6a 100644
--- a/source/blender/sequencer/SEQ_render.h
+++ b/source/blender/sequencer/SEQ_render.h
@@ -63,12 +63,20 @@ typedef struct SeqRenderData {
// bool gpu_full_samples;
} SeqRenderData;
+/**
+ * \return The image buffer or NULL.
+ *
+ * \note The returned #ImBuf has its reference increased, free after usage!
+ */
struct ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context,
float timeline_frame,
int chanshown);
struct ImBuf *SEQ_render_give_ibuf_direct(const SeqRenderData *context,
float timeline_frame,
struct Sequence *seq);
+/**
+ * Render the series of thumbnails and store in cache.
+ */
void SEQ_render_thumbnails(const struct SeqRenderData *context,
struct Sequence *seq,
struct Sequence *seq_orig,
@@ -76,12 +84,22 @@ void SEQ_render_thumbnails(const struct SeqRenderData *context,
float frame_step,
rctf *view_area,
const short *stop);
+/**
+ * Get cached thumbnails.
+ */
struct ImBuf *SEQ_get_thumbnail(const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
rcti *crop,
bool clipped);
+/**
+ * Get frame step for equally spaced thumbnails. These thumbnails should always be present in
+ * memory, so they can be used when zooming.
+ */
int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const struct Sequence *seq);
+/**
+ * Render set of evenly spaced thumbnails that are drawn when zooming..
+ */
void SEQ_render_thumbnails_base_set(const struct SeqRenderData *context,
struct Sequence *seq,
struct Sequence *seq_orig,
diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h
index 1b8982da0d2..2e340049dbd 100644
--- a/source/blender/sequencer/SEQ_sequencer.h
+++ b/source/blender/sequencer/SEQ_sequencer.h
@@ -68,16 +68,45 @@ int SEQ_tool_settings_pivot_point_get(struct Scene *scene);
struct SequencerToolSettings *SEQ_tool_settings_copy(struct SequencerToolSettings *tool_settings);
struct Editing *SEQ_editing_get(const struct Scene *scene);
struct Editing *SEQ_editing_ensure(struct Scene *scene);
-void SEQ_editing_free(struct Scene *scene, const bool do_id_user);
+void SEQ_editing_free(struct Scene *scene, bool do_id_user);
+/**
+ * Get seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
+ *
+ * \param ed: sequence editor data
+ * \return pointer to active seqbase. returns NULL if ed is NULL
+ */
struct ListBase *SEQ_active_seqbase_get(const struct Editing *ed);
+/**
+ * Set seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
+ *
+ * \param ed: sequence editor data
+ * \param seqbase: ListBase with strips
+ */
void SEQ_seqbase_active_set(struct Editing *ed, struct ListBase *seqbase);
struct Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int type);
-void SEQ_sequence_free(struct Scene *scene, struct Sequence *seq, const bool do_clean_animdata);
+void SEQ_sequence_free(struct Scene *scene, struct Sequence *seq);
+/**
+ * Create and initialize #MetaStack, append it to `ed->metastack` ListBase
+ *
+ * \param ed: sequence editor data
+ * \param seq_meta: meta strip
+ * \return pointer to created meta stack
+ */
struct MetaStack *SEQ_meta_stack_alloc(struct Editing *ed, struct Sequence *seq_meta);
+/**
+ * Get #MetaStack that corresponds to current level that is being viewed
+ *
+ * \param ed: sequence editor data
+ * \return pointer to meta stack
+ */
struct MetaStack *SEQ_meta_stack_active_get(const struct Editing *ed);
+/**
+ * Free #MetaStack and remove it from `ed->metastack` ListBase.
+ *
+ * \param ed: sequence editor data
+ * \param ms: meta stack
+ */
void SEQ_meta_stack_free(struct Editing *ed, struct MetaStack *ms);
-void SEQ_offset_animdata(struct Scene *scene, struct Sequence *seq, int ofs);
-void SEQ_dupe_animdata(struct Scene *scene, const char *name_src, const char *name_dst);
struct Sequence *SEQ_sequence_dupli_recursive(const struct Scene *scene_src,
struct Scene *scene_dst,
struct ListBase *new_seq_list,
@@ -88,10 +117,12 @@ void SEQ_sequence_base_dupli_recursive(const struct Scene *scene_src,
struct ListBase *nseqbase,
const struct ListBase *seqbase,
int dupe_flag,
- const int flag);
+ int flag);
bool SEQ_valid_strip_channel(struct Sequence *seq);
-/* Read and Write functions for .blend file data */
+/**
+ * Read and Write functions for `.blend` file data.
+ */
void SEQ_blend_write(struct BlendWriter *writer, struct ListBase *seqbase);
void SEQ_blend_read(struct BlendDataReader *reader, struct ListBase *seqbase);
@@ -101,7 +132,13 @@ void SEQ_blend_read_lib(struct BlendLibReader *reader,
void SEQ_blend_read_expand(struct BlendExpander *expander, struct ListBase *seqbase);
-/* Depsgraph update function */
+/* Depsgraph update function. */
+
+/**
+ * Evaluate parts of sequences which needs to be done as a part of a dependency graph evaluation.
+ * This does NOT include actual rendering of the strips, but rather makes them up-to-date for
+ * animation playback and makes them ready for the sequencer's rendering pipeline to render them.
+ */
void SEQ_eval_sequences(struct Depsgraph *depsgraph,
struct Scene *scene,
struct ListBase *seqbase);
@@ -112,8 +149,29 @@ typedef enum eSequenceLookupTag {
SEQ_LOOKUP_TAG_INVALID = (1 << 0),
} eSequenceLookupTag;
+/**
+ * Find a sequence with a given name.
+ * If lookup hash doesn't exist, it will be created. If hash is tagged as invalid, it will be
+ * rebuilt.
+ *
+ * \param scene: scene that owns lookup hash
+ * \param key: Sequence name without SQ prefix (seq->name + 2)
+ *
+ * \return pointer to Sequence
+ */
struct Sequence *SEQ_sequence_lookup_by_name(const struct Scene *scene, const char *key);
+/**
+ * Free lookup hash data.
+ *
+ * \param scene: scene that owns lookup hash
+ */
void SEQ_sequence_lookup_free(const struct Scene *scene);
+/**
+ * Find a sequence with a given name.
+ *
+ * \param scene: scene that owns lookup hash
+ * \param tag: tag to set
+ */
void SEQ_sequence_lookup_tag(const struct Scene *scene, eSequenceLookupTag tag);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/SEQ_time.h b/source/blender/sequencer/SEQ_time.h
index 732e9bb985a..f08220e4958 100644
--- a/source/blender/sequencer/SEQ_time.h
+++ b/source/blender/sequencer/SEQ_time.h
@@ -32,19 +32,49 @@ struct Scene;
struct Sequence;
struct rctf;
+/**
+ * Initialize given rectangle with the Scene's timeline boundaries.
+ *
+ * \param scene: the Scene instance whose timeline boundaries are extracted from
+ * \param rect: output parameter to be filled with timeline boundaries
+ */
+void SEQ_timeline_init_boundbox(const struct Scene *scene, struct rctf *rect);
+/**
+ * Stretch the given rectangle to include the given strips boundaries
+ *
+ * \param seqbase: ListBase in which strips are located
+ * \param rect: output parameter to be filled with strips' boundaries
+ */
+void SEQ_timeline_expand_boundbox(const struct ListBase *seqbase, struct rctf *rect);
+/**
+ * Define boundary rectangle of sequencer timeline and fill in rect data
+ *
+ * \param scene: Scene in which strips are located
+ * \param seqbase: ListBase in which strips are located
+ * \param rect: data structure describing rectangle, that will be filled in by this function
+ */
void SEQ_timeline_boundbox(const struct Scene *scene,
const struct ListBase *seqbase,
struct rctf *rect);
float SEQ_time_sequence_get_fps(struct Scene *scene, struct Sequence *seq);
int SEQ_time_find_next_prev_edit(struct Scene *scene,
int timeline_frame,
- const short side,
- const bool do_skip_mute,
- const bool do_center,
- const bool do_unselected);
-void SEQ_time_update_sequence(struct Scene *scene, struct Sequence *seq);
-void SEQ_time_update_sequence_bounds(struct Scene *scene, struct Sequence *seq);
-bool SEQ_time_strip_intersects_frame(const struct Sequence *seq, const int timeline_frame);
+ short side,
+ bool do_skip_mute,
+ bool do_center,
+ bool do_unselected);
+void SEQ_time_update_sequence(struct Scene *scene, struct ListBase *seqbase, struct Sequence *seq);
+void SEQ_time_update_recursive(struct Scene *scene, struct Sequence *changed_seq);
+/**
+ * Test if strip intersects with timeline frame.
+ * \note This checks if strip would be rendered at this frame. For rendering it is assumed, that
+ * timeline frame has width of 1 frame and therefore ends at timeline_frame + 1
+ *
+ * \param seq: Sequence to be checked
+ * \param timeline_frame: absolute frame position
+ * \return true if strip intersects with timeline frame.
+ */
+bool SEQ_time_strip_intersects_frame(const struct Sequence *seq, int timeline_frame);
void SEQ_time_update_meta_strip_range(struct Scene *scene, struct Sequence *seq_meta);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h
index 328efb9424a..00d1f1c9955 100644
--- a/source/blender/sequencer/SEQ_transform.h
+++ b/source/blender/sequencer/SEQ_transform.h
@@ -36,13 +36,24 @@ int SEQ_transform_get_left_handle_frame(struct Sequence *seq);
int SEQ_transform_get_right_handle_frame(struct Sequence *seq);
void SEQ_transform_set_left_handle_frame(struct Sequence *seq, int val);
void SEQ_transform_set_right_handle_frame(struct Sequence *seq, int val);
+/**
+ * Use to impose limits when dragging/extending - so impossible situations don't happen.
+ * Can't use the #SEQ_LEFTSEL and #SEQ_LEFTSEL directly because the strip may be in a meta-strip.
+ */
void SEQ_transform_handle_xlimits(struct Sequence *seq, int leftflag, int rightflag);
bool SEQ_transform_sequence_can_be_translated(struct Sequence *seq);
+/**
+ * Used so we can do a quick check for single image seq
+ * since they work a bit differently to normal image seq's (during transform).
+ */
bool SEQ_transform_single_image_check(struct Sequence *seq);
void SEQ_transform_fix_single_image_seq_offsets(struct Sequence *seq);
bool SEQ_transform_test_overlap(struct ListBase *seqbasep, struct Sequence *test);
bool SEQ_transform_test_overlap_seq_seq(struct Sequence *seq1, struct Sequence *seq2);
void SEQ_transform_translate_sequence(struct Scene *scene, struct Sequence *seq, int delta);
+/**
+ * \return 0 if there weren't enough space.
+ */
bool SEQ_transform_seqbase_shuffle_ex(struct ListBase *seqbasep,
struct Sequence *test,
struct Scene *evil_scene,
@@ -54,22 +65,69 @@ bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle,
struct ListBase *seqbasep,
struct Scene *evil_scene,
struct ListBase *markers,
- const bool use_sync_markers);
+ bool use_sync_markers);
+/**
+ * Check if the selected seq's reference unselected seq's.
+ */
bool SEQ_transform_seqbase_isolated_sel_check(struct ListBase *seqbase);
+/**
+ * Move strips and markers (if not locked) that start after timeline_frame by delta frames
+ *
+ * \param scene: Scene in which strips are located
+ * \param seqbase: ListBase in which strips are located
+ * \param delta: offset in frames to be applied
+ * \param timeline_frame: frame on timeline from where strips are moved
+ */
void SEQ_transform_offset_after_frame(struct Scene *scene,
struct ListBase *seqbase,
- const int delta,
- const int timeline_frame);
+ int delta,
+ int timeline_frame);
/* Image transformation. */
+
void SEQ_image_transform_mirror_factor_get(const struct Sequence *seq, float r_mirror[2]);
+/**
+ * Get strip transform origin offset from image center
+ * NOTE: This function does not apply axis mirror.
+ *
+ * \param scene: Scene in which strips are located
+ * \param seq: Sequence to calculate image transform origin
+ * \param r_origin: return value
+ */
void SEQ_image_transform_origin_offset_pixelspace_get(const struct Scene *scene,
const struct Sequence *seq,
float r_origin[2]);
+/**
+ * Get 4 corner points of strip image, optionally without rotation component applied.
+ * Corner vectors are in viewport space.
+ *
+ * \param scene: Scene in which strips are located
+ * \param seq: Sequence to calculate transformed image quad
+ * \param apply_rotation: Apply sequence rotation transform to the quad
+ * \param r_quad: array of 4 2D vectors
+ */
+void SEQ_image_transform_quad_get(const struct Scene *scene,
+ const struct Sequence *seq,
+ bool apply_rotation,
+ float r_quad[4][2]);
+/**
+ * Get 4 corner points of strip image. Corner vectors are in viewport space.
+ *
+ * \param scene: Scene in which strips are located
+ * \param seq: Sequence to calculate transformed image quad
+ * \param r_quad: array of 4 2D vectors
+ */
void SEQ_image_transform_final_quad_get(const struct Scene *scene,
const struct Sequence *seq,
float r_quad[4][2]);
+void SEQ_image_preview_unit_to_px(const struct Scene *scene,
+ const float co_src[2],
+ float co_dst[2]);
+void SEQ_image_preview_unit_from_px(const struct Scene *scene,
+ const float co_src[2],
+ float co_dst[2]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/sequencer/SEQ_utils.h b/source/blender/sequencer/SEQ_utils.h
index d30a1b2d7ae..515c47f53fd 100644
--- a/source/blender/sequencer/SEQ_utils.h
+++ b/source/blender/sequencer/SEQ_utils.h
@@ -32,10 +32,17 @@ extern "C" {
struct ListBase;
struct Mask;
struct Scene;
+struct SeqRenderData;
struct Sequence;
struct StripElem;
-struct SeqRenderData;
+/**
+ * Sort strips in provided seqbase. Effect strips are trailing the list and they are sorted by
+ * channel position as well.
+ * This is important for SEQ_time_update_sequence to work properly
+ *
+ * \param seqbase: ListBase with strips
+ */
void SEQ_sort(struct ListBase *seqbase);
void SEQ_sequence_base_unique_name_recursive(struct Scene *scene,
struct ListBase *seqbasep,
@@ -43,7 +50,14 @@ void SEQ_sequence_base_unique_name_recursive(struct Scene *scene,
const char *SEQ_sequence_give_name(struct Sequence *seq);
struct ListBase *SEQ_get_seqbase_from_sequence(struct Sequence *seq, int *r_offset);
const struct Sequence *SEQ_get_topmost_sequence(const struct Scene *scene, int frame);
+/**
+ * In cases where we don't know the sequence's listbase.
+ */
struct ListBase *SEQ_get_seqbase_by_seq(struct ListBase *seqbase, struct Sequence *seq);
+/**
+ * Only use as last resort when the StripElem is available but no the Sequence.
+ * (needed for RNA)
+ */
struct Sequence *SEQ_sequence_from_strip_elem(struct ListBase *seqbase, struct StripElem *se);
struct Sequence *SEQ_get_sequence_by_name(struct ListBase *seqbase,
const char *name,
@@ -52,11 +66,18 @@ struct Mask *SEQ_active_mask_get(struct Scene *scene);
void SEQ_alpha_mode_from_file_extension(struct Sequence *seq);
bool SEQ_sequence_has_source(const struct Sequence *seq);
void SEQ_set_scale_to_fit(const struct Sequence *seq,
- const int image_width,
- const int image_height,
- const int preview_width,
- const int preview_height,
- const eSeqImageFitMethod fit_method);
+ int image_width,
+ int image_height,
+ int preview_width,
+ int preview_height,
+ eSeqImageFitMethod fit_method);
+/**
+ * Ensure, that provided Sequence has unique name. If animation data exists for this Sequence, it
+ * will be duplicated and mapped onto new name
+ *
+ * \param seq: Sequence which name will be ensured to be unique
+ * \param scene: Scene in which name must be unique
+ */
void SEQ_ensure_unique_name(struct Sequence *seq, struct Scene *scene);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/animation.c b/source/blender/sequencer/intern/animation.c
new file mode 100644
index 00000000000..492b757a4b1
--- /dev/null
+++ b/source/blender/sequencer/intern/animation.c
@@ -0,0 +1,122 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup sequencer
+ */
+
+#include <string.h>
+
+#include "DNA_anim_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BKE_animsys.h"
+#include "BKE_fcurve.h"
+
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "DEG_depsgraph.h"
+
+#include "SEQ_animation.h"
+
+static bool seq_animation_curves_exist(Scene *scene)
+{
+ if (scene->adt == NULL || scene->adt->action == NULL ||
+ BLI_listbase_is_empty(&scene->adt->action->curves)) {
+ return false;
+ }
+ return true;
+}
+
+/* r_prefix + [" + escaped_name + "] + \0 */
+#define SEQ_RNAPATH_MAXSTR ((30 + 2 + (SEQ_NAME_MAXSTR * 2) + 2) + 1)
+
+static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char *name)
+{
+ char name_esc[SEQ_NAME_MAXSTR * 2];
+
+ BLI_str_escape(name_esc, name, sizeof(name_esc));
+ return BLI_snprintf_rlen(
+ str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
+}
+
+GSet *SEQ_fcurves_by_strip_get(const Sequence *seq, ListBase *fcurve_base)
+{
+ char rna_path[SEQ_RNAPATH_MAXSTR];
+ size_t rna_path_len = sequencer_rna_path_prefix(rna_path, seq->name + 2);
+
+ GSet *fcurves = BLI_gset_ptr_new(__func__);
+ LISTBASE_FOREACH (FCurve *, fcurve, fcurve_base) {
+ if (STREQLEN(fcurve->rna_path, rna_path, rna_path_len)) {
+ BLI_gset_add(fcurves, fcurve);
+ }
+ }
+
+ return fcurves;
+}
+
+#undef SEQ_RNAPATH_MAXSTR
+
+void SEQ_offset_animdata(Scene *scene, Sequence *seq, int ofs)
+{
+ if (!seq_animation_curves_exist(scene) || ofs == 0) {
+ return;
+ }
+
+ GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves);
+ GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) {
+ unsigned int i;
+ if (fcu->bezt) {
+ for (i = 0; i < fcu->totvert; i++) {
+ BezTriple *bezt = &fcu->bezt[i];
+ bezt->vec[0][0] += ofs;
+ bezt->vec[1][0] += ofs;
+ bezt->vec[2][0] += ofs;
+ }
+ }
+ if (fcu->fpt) {
+ for (i = 0; i < fcu->totvert; i++) {
+ FPoint *fpt = &fcu->fpt[i];
+ fpt->vec[0] += ofs;
+ }
+ }
+ }
+ GSET_FOREACH_END();
+ BLI_gset_free(fcurves, NULL);
+
+ DEG_id_tag_update(&scene->adt->action->id, ID_RECALC_ANIMATION);
+}
+
+void SEQ_free_animdata(Scene *scene, Sequence *seq)
+{
+ if (!seq_animation_curves_exist(scene)) {
+ return;
+ }
+
+ GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves);
+ GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) {
+ BLI_remlink(&scene->adt->action->curves, fcu);
+ BKE_fcurve_free(fcu);
+ }
+ GSET_FOREACH_END();
+ BLI_gset_free(fcurves, NULL);
+}
diff --git a/source/blender/sequencer/intern/clipboard.c b/source/blender/sequencer/intern/clipboard.c
index 05406c50303..886ee89595b 100644
--- a/source/blender/sequencer/intern/clipboard.c
+++ b/source/blender/sequencer/intern/clipboard.c
@@ -28,6 +28,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_anim_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
@@ -35,6 +36,7 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
+#include "BKE_fcurve.h"
#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_scene.h"
@@ -58,6 +60,7 @@
*/
ListBase seqbase_clipboard;
+ListBase fcurves_clipboard;
int seqbase_clipboard_frame;
static char seq_clipboard_active_seq_name[SEQ_NAME_MAXSTR];
@@ -65,15 +68,17 @@ void seq_clipboard_pointers_free(struct ListBase *seqbase);
void SEQ_clipboard_free(void)
{
- Sequence *seq, *nseq;
-
seq_clipboard_pointers_free(&seqbase_clipboard);
- for (seq = seqbase_clipboard.first; seq; seq = nseq) {
- nseq = seq->next;
- seq_free_sequence_recurse(NULL, seq, false, true);
+ LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &seqbase_clipboard) {
+ seq_free_sequence_recurse(NULL, seq, false);
}
BLI_listbase_clear(&seqbase_clipboard);
+
+ LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &fcurves_clipboard) {
+ BKE_fcurve_free(fcu);
+ }
+ BLI_listbase_clear(&fcurves_clipboard);
}
#define ID_PT (*id_pt)
@@ -194,13 +199,6 @@ void SEQ_clipboard_active_seq_name_store(Scene *scene)
}
}
-/**
- * Check if strip was active when it was copied. User should restrict this check to pasted strips
- * before ensuring original name, because strip name comparison is used to check.
- *
- * \param pasted_seq: Strip that is pasted(duplicated) from clipboard
- * \return true if strip was active, false otherwise
- */
bool SEQ_clipboard_pasted_seq_was_active(Sequence *pasted_seq)
{
return STREQ(pasted_seq->name, seq_clipboard_active_seq_name);
diff --git a/source/blender/sequencer/intern/disk_cache.c b/source/blender/sequencer/intern/disk_cache.c
new file mode 100644
index 00000000000..2db6a3cc8ee
--- /dev/null
+++ b/source/blender/sequencer/intern/disk_cache.c
@@ -0,0 +1,699 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup sequencer
+ */
+
+#include <memory.h>
+#include <stddef.h>
+#include <time.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_space_types.h" /* for FILE_MAX. */
+
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_endian_defines.h"
+#include "BLI_endian_switch.h"
+#include "BLI_fileops.h"
+#include "BLI_fileops_types.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_mempool.h"
+#include "BLI_path_util.h"
+#include "BLI_threads.h"
+
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+#include "SEQ_prefetch.h"
+#include "SEQ_relations.h"
+#include "SEQ_render.h"
+#include "SEQ_sequencer.h"
+
+#include "disk_cache.h"
+#include "image_cache.h"
+#include "prefetch.h"
+#include "strip_time.h"
+
+/**
+ * Disk Cache Design Notes
+ * =======================
+ *
+ * Disk cache uses directory specified in user preferences
+ * For each cached non-temp image, image data and supplementary info are written to HDD.
+ * Multiple(DCACHE_IMAGES_PER_FILE) images share the same file.
+ * Each of these files contains header DiskCacheHeader followed by image data.
+ * Zlib compression with user definable level can be used to compress image data(per image)
+ * Images are written in order in which they are rendered.
+ * Overwriting of individual entry is not possible.
+ * Stored images are deleted by invalidation, or when size of all files exceeds maximum
+ * size specified in user preferences.
+ * To distinguish 2 blend files with same name, scene->ed->disk_cache_timestamp
+ * is used as UID. Blend file can still be copied manually which may cause conflict.
+ */
+
+/* Format string:
+ * `<cache type>-<resolution X>x<resolution Y>-<rendersize>%(<view_id>)-<frame no>.dcf`. */
+#define DCACHE_FNAME_FORMAT "%d-%dx%d-%d%%(%d)-%d.dcf"
+#define DCACHE_IMAGES_PER_FILE 100
+#define DCACHE_CURRENT_VERSION 2
+#define COLORSPACE_NAME_MAX 64 /* XXX: defined in IMB intern. */
+
+typedef struct DiskCacheHeaderEntry {
+ unsigned char encoding;
+ uint64_t frameno;
+ uint64_t size_compressed;
+ uint64_t size_raw;
+ uint64_t offset;
+ char colorspace_name[COLORSPACE_NAME_MAX];
+} DiskCacheHeaderEntry;
+
+typedef struct DiskCacheHeader {
+ DiskCacheHeaderEntry entry[DCACHE_IMAGES_PER_FILE];
+} DiskCacheHeader;
+
+typedef struct SeqDiskCache {
+ Main *bmain;
+ int64_t timestamp;
+ ListBase files;
+ ThreadMutex read_write_mutex;
+ size_t size_total;
+} SeqDiskCache;
+
+typedef struct DiskCacheFile {
+ struct DiskCacheFile *next, *prev;
+ char path[FILE_MAX];
+ char dir[FILE_MAXDIR];
+ char file[FILE_MAX];
+ BLI_stat_t fstat;
+ int cache_type;
+ int rectx;
+ int recty;
+ int render_size;
+ int view_id;
+ int start_frame;
+} DiskCacheFile;
+
+static ThreadMutex cache_create_lock = BLI_MUTEX_INITIALIZER;
+
+static char *seq_disk_cache_base_dir(void)
+{
+ return U.sequencer_disk_cache_dir;
+}
+
+static int seq_disk_cache_compression_level(void)
+{
+ switch (U.sequencer_disk_cache_compression) {
+ case USER_SEQ_DISK_CACHE_COMPRESSION_NONE:
+ return 0;
+ case USER_SEQ_DISK_CACHE_COMPRESSION_LOW:
+ return 1;
+ case USER_SEQ_DISK_CACHE_COMPRESSION_HIGH:
+ return 9;
+ }
+
+ return U.sequencer_disk_cache_compression;
+}
+
+static size_t seq_disk_cache_size_limit(void)
+{
+ return (size_t)U.sequencer_disk_cache_size_limit * (1024 * 1024 * 1024);
+}
+
+bool seq_disk_cache_is_enabled(Main *bmain)
+{
+ return (U.sequencer_disk_cache_dir[0] != '\0' && U.sequencer_disk_cache_size_limit != 0 &&
+ (U.sequencer_disk_cache_flag & SEQ_CACHE_DISK_CACHE_ENABLE) != 0 &&
+ bmain->filepath[0] != '\0');
+}
+
+static DiskCacheFile *seq_disk_cache_add_file_to_list(SeqDiskCache *disk_cache, const char *path)
+{
+
+ DiskCacheFile *cache_file = MEM_callocN(sizeof(DiskCacheFile), "SeqDiskCacheFile");
+ char dir[FILE_MAXDIR], file[FILE_MAX];
+ BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
+ BLI_strncpy(cache_file->path, path, sizeof(cache_file->path));
+ BLI_strncpy(cache_file->dir, dir, sizeof(cache_file->dir));
+ BLI_strncpy(cache_file->file, file, sizeof(cache_file->file));
+ sscanf(file,
+ DCACHE_FNAME_FORMAT,
+ &cache_file->cache_type,
+ &cache_file->rectx,
+ &cache_file->recty,
+ &cache_file->render_size,
+ &cache_file->view_id,
+ &cache_file->start_frame);
+ cache_file->start_frame *= DCACHE_IMAGES_PER_FILE;
+ BLI_addtail(&disk_cache->files, cache_file);
+ return cache_file;
+}
+
+static void seq_disk_cache_get_files(SeqDiskCache *disk_cache, char *path)
+{
+ struct direntry *filelist, *fl;
+ uint nbr, i;
+ disk_cache->size_total = 0;
+
+ i = nbr = BLI_filelist_dir_contents(path, &filelist);
+ fl = filelist;
+ while (i--) {
+ /* Don't follow links. */
+ const eFileAttributes file_attrs = BLI_file_attributes(fl->path);
+ if (file_attrs & FILE_ATTR_ANY_LINK) {
+ fl++;
+ continue;
+ }
+
+ char file[FILE_MAX];
+ BLI_split_dirfile(fl->path, NULL, file, 0, sizeof(file));
+
+ bool is_dir = BLI_is_dir(fl->path);
+ if (is_dir && !FILENAME_IS_CURRPAR(file)) {
+ char subpath[FILE_MAX];
+ BLI_strncpy(subpath, fl->path, sizeof(subpath));
+ BLI_path_slash_ensure(subpath);
+ seq_disk_cache_get_files(disk_cache, subpath);
+ }
+
+ if (!is_dir) {
+ const char *ext = BLI_path_extension(fl->path);
+ if (ext && ext[1] == 'd' && ext[2] == 'c' && ext[3] == 'f') {
+ DiskCacheFile *cache_file = seq_disk_cache_add_file_to_list(disk_cache, fl->path);
+ cache_file->fstat = fl->s;
+ disk_cache->size_total += cache_file->fstat.st_size;
+ }
+ }
+ fl++;
+ }
+ BLI_filelist_free(filelist, nbr);
+}
+
+static DiskCacheFile *seq_disk_cache_get_oldest_file(SeqDiskCache *disk_cache)
+{
+ DiskCacheFile *oldest_file = disk_cache->files.first;
+ if (oldest_file == NULL) {
+ return NULL;
+ }
+ for (DiskCacheFile *cache_file = oldest_file->next; cache_file; cache_file = cache_file->next) {
+ if (cache_file->fstat.st_mtime < oldest_file->fstat.st_mtime) {
+ oldest_file = cache_file;
+ }
+ }
+
+ return oldest_file;
+}
+
+static void seq_disk_cache_delete_file(SeqDiskCache *disk_cache, DiskCacheFile *file)
+{
+ disk_cache->size_total -= file->fstat.st_size;
+ BLI_delete(file->path, false, false);
+ BLI_remlink(&disk_cache->files, file);
+ MEM_freeN(file);
+}
+
+bool seq_disk_cache_enforce_limits(SeqDiskCache *disk_cache)
+{
+ BLI_mutex_lock(&disk_cache->read_write_mutex);
+ while (disk_cache->size_total > seq_disk_cache_size_limit()) {
+ DiskCacheFile *oldest_file = seq_disk_cache_get_oldest_file(disk_cache);
+
+ if (!oldest_file) {
+ /* We shouldn't enforce limits with no files, do re-scan. */
+ seq_disk_cache_get_files(disk_cache, seq_disk_cache_base_dir());
+ continue;
+ }
+
+ if (BLI_exists(oldest_file->path) == 0) {
+ /* File may have been manually deleted during runtime, do re-scan. */
+ BLI_freelistN(&disk_cache->files);
+ seq_disk_cache_get_files(disk_cache, seq_disk_cache_base_dir());
+ continue;
+ }
+
+ seq_disk_cache_delete_file(disk_cache, oldest_file);
+ }
+ BLI_mutex_unlock(&disk_cache->read_write_mutex);
+
+ return true;
+}
+
+static DiskCacheFile *seq_disk_cache_get_file_entry_by_path(SeqDiskCache *disk_cache, char *path)
+{
+ DiskCacheFile *cache_file = disk_cache->files.first;
+
+ for (; cache_file; cache_file = cache_file->next) {
+ if (BLI_strcasecmp(cache_file->path, path) == 0) {
+ return cache_file;
+ }
+ }
+
+ return NULL;
+}
+
+/* Update file size and timestamp. */
+static void seq_disk_cache_update_file(SeqDiskCache *disk_cache, char *path)
+{
+ DiskCacheFile *cache_file;
+ int64_t size_before;
+ int64_t size_after;
+
+ cache_file = seq_disk_cache_get_file_entry_by_path(disk_cache, path);
+ size_before = cache_file->fstat.st_size;
+
+ if (BLI_stat(path, &cache_file->fstat) == -1) {
+ BLI_assert(false);
+ memset(&cache_file->fstat, 0, sizeof(BLI_stat_t));
+ }
+
+ size_after = cache_file->fstat.st_size;
+ disk_cache->size_total += size_after - size_before;
+}
+
+/* Path format:
+ * <cache dir>/<project name>_seq_cache/<scene name>-<timestamp>/<seq name>/DCACHE_FNAME_FORMAT
+ */
+
+static void seq_disk_cache_get_project_dir(SeqDiskCache *disk_cache, char *path, size_t path_len)
+{
+ char cache_dir[FILE_MAX];
+ BLI_split_file_part(BKE_main_blendfile_path(disk_cache->bmain), cache_dir, sizeof(cache_dir));
+ /* Use suffix, so that the cache directory name does not conflict with the bmain's blend file. */
+ const char *suffix = "_seq_cache";
+ strncat(cache_dir, suffix, sizeof(cache_dir) - strlen(cache_dir) - 1);
+ BLI_strncpy(path, seq_disk_cache_base_dir(), path_len);
+ BLI_path_append(path, path_len, cache_dir);
+}
+
+static void seq_disk_cache_get_dir(
+ SeqDiskCache *disk_cache, Scene *scene, Sequence *seq, char *path, size_t path_len)
+{
+ char scene_name[MAX_ID_NAME + 22]; /* + -%PRId64 */
+ char seq_name[SEQ_NAME_MAXSTR];
+ char project_dir[FILE_MAX];
+
+ seq_disk_cache_get_project_dir(disk_cache, project_dir, sizeof(project_dir));
+ sprintf(scene_name, "%s-%" PRId64, scene->id.name, disk_cache->timestamp);
+ BLI_strncpy(seq_name, seq->name, sizeof(seq_name));
+ BLI_filename_make_safe(scene_name);
+ BLI_filename_make_safe(seq_name);
+ BLI_strncpy(path, project_dir, path_len);
+ BLI_path_append(path, path_len, scene_name);
+ BLI_path_append(path, path_len, seq_name);
+}
+
+static void seq_disk_cache_get_file_path(SeqDiskCache *disk_cache,
+ SeqCacheKey *key,
+ char *path,
+ size_t path_len)
+{
+ seq_disk_cache_get_dir(disk_cache, key->context.scene, key->seq, path, path_len);
+ int frameno = (int)key->frame_index / DCACHE_IMAGES_PER_FILE;
+ char cache_filename[FILE_MAXFILE];
+ sprintf(cache_filename,
+ DCACHE_FNAME_FORMAT,
+ key->type,
+ key->context.rectx,
+ key->context.recty,
+ key->context.preview_render_size,
+ key->context.view_id,
+ frameno);
+
+ BLI_path_append(path, path_len, cache_filename);
+}
+
+static void seq_disk_cache_create_version_file(char *path)
+{
+ BLI_make_existing_file(path);
+
+ FILE *file = BLI_fopen(path, "w");
+ if (file) {
+ fprintf(file, "%d", DCACHE_CURRENT_VERSION);
+ fclose(file);
+ }
+}
+
+static void seq_disk_cache_handle_versioning(SeqDiskCache *disk_cache)
+{
+ char path[FILE_MAX];
+ char path_version_file[FILE_MAX];
+ int version = 0;
+
+ seq_disk_cache_get_project_dir(disk_cache, path, sizeof(path));
+ BLI_strncpy(path_version_file, path, sizeof(path_version_file));
+ BLI_path_append(path_version_file, sizeof(path_version_file), "cache_version");
+
+ if (BLI_exists(path) && BLI_is_dir(path)) {
+ FILE *file = BLI_fopen(path_version_file, "r");
+
+ if (file) {
+ const int num_items_read = fscanf(file, "%d", &version);
+ if (num_items_read == 0) {
+ version = -1;
+ }
+ fclose(file);
+ }
+
+ if (version != DCACHE_CURRENT_VERSION) {
+ BLI_delete(path, false, true);
+ seq_disk_cache_create_version_file(path_version_file);
+ }
+ }
+ else {
+ seq_disk_cache_create_version_file(path_version_file);
+ }
+}
+
+static void seq_disk_cache_delete_invalid_files(SeqDiskCache *disk_cache,
+ Scene *scene,
+ Sequence *seq,
+ int invalidate_types,
+ int range_start,
+ int range_end)
+{
+ DiskCacheFile *next_file, *cache_file = disk_cache->files.first;
+ char cache_dir[FILE_MAX];
+ seq_disk_cache_get_dir(disk_cache, scene, seq, cache_dir, sizeof(cache_dir));
+ BLI_path_slash_ensure(cache_dir);
+
+ while (cache_file) {
+ next_file = cache_file->next;
+ if (cache_file->cache_type & invalidate_types) {
+ if (STREQ(cache_dir, cache_file->dir)) {
+ int timeline_frame_start = seq_cache_frame_index_to_timeline_frame(
+ seq, cache_file->start_frame);
+ if (timeline_frame_start > range_start && timeline_frame_start <= range_end) {
+ seq_disk_cache_delete_file(disk_cache, cache_file);
+ }
+ }
+ }
+ cache_file = next_file;
+ }
+}
+
+void seq_disk_cache_invalidate(SeqDiskCache *disk_cache,
+ Scene *scene,
+ Sequence *seq,
+ Sequence *seq_changed,
+ int invalidate_types)
+{
+ int start;
+ int end;
+
+ BLI_mutex_lock(&disk_cache->read_write_mutex);
+
+ start = seq_changed->startdisp - DCACHE_IMAGES_PER_FILE;
+ end = seq_changed->enddisp;
+
+ seq_disk_cache_delete_invalid_files(disk_cache, scene, seq, invalidate_types, start, end);
+
+ BLI_mutex_unlock(&disk_cache->read_write_mutex);
+}
+
+static size_t deflate_imbuf_to_file(ImBuf *ibuf,
+ FILE *file,
+ int level,
+ DiskCacheHeaderEntry *header_entry)
+{
+ void *data = (ibuf->rect != NULL) ? (void *)ibuf->rect : (void *)ibuf->rect_float;
+
+ /* Apply compression if wanted, otherwise just write directly to the file. */
+ if (level > 0) {
+ return BLI_file_zstd_from_mem_at_pos(
+ data, header_entry->size_raw, file, header_entry->offset, level);
+ }
+
+ fseek(file, header_entry->offset, SEEK_SET);
+ return fwrite(data, 1, header_entry->size_raw, file);
+}
+
+static size_t inflate_file_to_imbuf(ImBuf *ibuf, FILE *file, DiskCacheHeaderEntry *header_entry)
+{
+ void *data = (ibuf->rect != NULL) ? (void *)ibuf->rect : (void *)ibuf->rect_float;
+ char header[4];
+ fseek(file, header_entry->offset, SEEK_SET);
+ if (fread(header, 1, sizeof(header), file) != sizeof(header)) {
+ return 0;
+ }
+
+ /* Check if the data is compressed or raw. */
+ if (BLI_file_magic_is_zstd(header)) {
+ return BLI_file_unzstd_to_mem_at_pos(data, header_entry->size_raw, file, header_entry->offset);
+ }
+
+ fseek(file, header_entry->offset, SEEK_SET);
+ return fread(data, 1, header_entry->size_raw, file);
+}
+
+static bool seq_disk_cache_read_header(FILE *file, DiskCacheHeader *header)
+{
+ BLI_fseek(file, 0LL, SEEK_SET);
+ const size_t num_items_read = fread(header, sizeof(*header), 1, file);
+ if (num_items_read < 1) {
+ BLI_assert_msg(0, "unable to read disk cache header");
+ perror("unable to read disk cache header");
+ return false;
+ }
+
+ for (int i = 0; i < DCACHE_IMAGES_PER_FILE; i++) {
+ if ((ENDIAN_ORDER == B_ENDIAN) && header->entry[i].encoding == 0) {
+ BLI_endian_switch_uint64(&header->entry[i].frameno);
+ BLI_endian_switch_uint64(&header->entry[i].offset);
+ BLI_endian_switch_uint64(&header->entry[i].size_compressed);
+ BLI_endian_switch_uint64(&header->entry[i].size_raw);
+ }
+ }
+
+ return true;
+}
+
+static size_t seq_disk_cache_write_header(FILE *file, DiskCacheHeader *header)
+{
+ BLI_fseek(file, 0LL, SEEK_SET);
+ return fwrite(header, sizeof(*header), 1, file);
+}
+
+static int seq_disk_cache_add_header_entry(SeqCacheKey *key, ImBuf *ibuf, DiskCacheHeader *header)
+{
+ int i;
+ uint64_t offset = sizeof(*header);
+
+ /* Lookup free entry, get offset for new data. */
+ for (i = 0; i < DCACHE_IMAGES_PER_FILE; i++) {
+ if (header->entry[i].size_compressed == 0) {
+ break;
+ }
+ }
+
+ /* Attempt to write beyond set entry limit.
+ * Reset file header and start writing from beginning.
+ */
+ if (i == DCACHE_IMAGES_PER_FILE) {
+ i = 0;
+ memset(header, 0, sizeof(*header));
+ }
+
+ /* Calculate offset for image data. */
+ if (i > 0) {
+ offset = header->entry[i - 1].offset + header->entry[i - 1].size_compressed;
+ }
+
+ if (ENDIAN_ORDER == B_ENDIAN) {
+ header->entry[i].encoding = 255;
+ }
+ else {
+ header->entry[i].encoding = 0;
+ }
+
+ header->entry[i].offset = offset;
+ header->entry[i].frameno = key->frame_index;
+
+ /* Store colorspace name of ibuf. */
+ const char *colorspace_name;
+ if (ibuf->rect) {
+ header->entry[i].size_raw = ibuf->x * ibuf->y * ibuf->channels;
+ colorspace_name = IMB_colormanagement_get_rect_colorspace(ibuf);
+ }
+ else {
+ header->entry[i].size_raw = ibuf->x * ibuf->y * ibuf->channels * 4;
+ colorspace_name = IMB_colormanagement_get_float_colorspace(ibuf);
+ }
+ BLI_strncpy(
+ header->entry[i].colorspace_name, colorspace_name, sizeof(header->entry[i].colorspace_name));
+
+ return i;
+}
+
+static int seq_disk_cache_get_header_entry(SeqCacheKey *key, DiskCacheHeader *header)
+{
+ for (int i = 0; i < DCACHE_IMAGES_PER_FILE; i++) {
+ if (header->entry[i].frameno == key->frame_index) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+bool seq_disk_cache_write_file(SeqDiskCache *disk_cache, SeqCacheKey *key, ImBuf *ibuf)
+{
+ BLI_mutex_lock(&disk_cache->read_write_mutex);
+
+ char path[FILE_MAX];
+
+ seq_disk_cache_get_file_path(disk_cache, key, path, sizeof(path));
+ BLI_make_existing_file(path);
+
+ FILE *file = BLI_fopen(path, "rb+");
+ if (!file) {
+ file = BLI_fopen(path, "wb+");
+ if (!file) {
+ BLI_mutex_unlock(&disk_cache->read_write_mutex);
+ return false;
+ }
+ seq_disk_cache_add_file_to_list(disk_cache, path);
+ }
+
+ DiskCacheFile *cache_file = seq_disk_cache_get_file_entry_by_path(disk_cache, path);
+ DiskCacheHeader header;
+ memset(&header, 0, sizeof(header));
+ /* #BLI_make_existing_file() above may create an empty file. This is fine, don't attempt reading
+ * the header in that case. */
+ if (cache_file->fstat.st_size != 0 && !seq_disk_cache_read_header(file, &header)) {
+ fclose(file);
+ seq_disk_cache_delete_file(disk_cache, cache_file);
+ BLI_mutex_unlock(&disk_cache->read_write_mutex);
+ return false;
+ }
+ int entry_index = seq_disk_cache_add_header_entry(key, ibuf, &header);
+
+ size_t bytes_written = deflate_imbuf_to_file(
+ ibuf, file, seq_disk_cache_compression_level(), &header.entry[entry_index]);
+
+ if (bytes_written != 0) {
+ /* Last step is writing header, as image data can be overwritten,
+ * but missing data would cause problems.
+ */
+ header.entry[entry_index].size_compressed = bytes_written;
+ seq_disk_cache_write_header(file, &header);
+ seq_disk_cache_update_file(disk_cache, path);
+ fclose(file);
+
+ BLI_mutex_unlock(&disk_cache->read_write_mutex);
+ return true;
+ }
+
+ BLI_mutex_unlock(&disk_cache->read_write_mutex);
+ return false;
+}
+
+ImBuf *seq_disk_cache_read_file(SeqDiskCache *disk_cache, SeqCacheKey *key)
+{
+ BLI_mutex_lock(&disk_cache->read_write_mutex);
+
+ char path[FILE_MAX];
+ DiskCacheHeader header;
+
+ seq_disk_cache_get_file_path(disk_cache, key, path, sizeof(path));
+ BLI_make_existing_file(path);
+
+ FILE *file = BLI_fopen(path, "rb");
+ if (!file) {
+ BLI_mutex_unlock(&disk_cache->read_write_mutex);
+ return NULL;
+ }
+
+ if (!seq_disk_cache_read_header(file, &header)) {
+ fclose(file);
+ BLI_mutex_unlock(&disk_cache->read_write_mutex);
+ return NULL;
+ }
+ int entry_index = seq_disk_cache_get_header_entry(key, &header);
+
+ /* Item not found. */
+ if (entry_index < 0) {
+ fclose(file);
+ BLI_mutex_unlock(&disk_cache->read_write_mutex);
+ return NULL;
+ }
+
+ ImBuf *ibuf;
+ uint64_t size_char = (uint64_t)key->context.rectx * key->context.recty * 4;
+ uint64_t size_float = (uint64_t)key->context.rectx * key->context.recty * 16;
+ size_t expected_size;
+
+ if (header.entry[entry_index].size_raw == size_char) {
+ expected_size = size_char;
+ ibuf = IMB_allocImBuf(key->context.rectx, key->context.recty, 32, IB_rect);
+ IMB_colormanagement_assign_rect_colorspace(ibuf, header.entry[entry_index].colorspace_name);
+ }
+ else if (header.entry[entry_index].size_raw == size_float) {
+ expected_size = size_float;
+ ibuf = IMB_allocImBuf(key->context.rectx, key->context.recty, 32, IB_rectfloat);
+ IMB_colormanagement_assign_float_colorspace(ibuf, header.entry[entry_index].colorspace_name);
+ }
+ else {
+ fclose(file);
+ BLI_mutex_unlock(&disk_cache->read_write_mutex);
+ return NULL;
+ }
+
+ size_t bytes_read = inflate_file_to_imbuf(ibuf, file, &header.entry[entry_index]);
+
+ /* Sanity check. */
+ if (bytes_read != expected_size) {
+ fclose(file);
+ IMB_freeImBuf(ibuf);
+ BLI_mutex_unlock(&disk_cache->read_write_mutex);
+ return NULL;
+ }
+ BLI_file_touch(path);
+ seq_disk_cache_update_file(disk_cache, path);
+ fclose(file);
+
+ BLI_mutex_unlock(&disk_cache->read_write_mutex);
+ return ibuf;
+}
+
+SeqDiskCache *seq_disk_cache_create(Main *bmain, Scene *scene)
+{
+ SeqDiskCache *disk_cache = MEM_callocN(sizeof(SeqDiskCache), "SeqDiskCache");
+ disk_cache->bmain = bmain;
+ BLI_mutex_init(&disk_cache->read_write_mutex);
+ seq_disk_cache_handle_versioning(disk_cache);
+ seq_disk_cache_get_files(disk_cache, seq_disk_cache_base_dir());
+ disk_cache->timestamp = scene->ed->disk_cache_timestamp;
+ BLI_mutex_unlock(&cache_create_lock);
+ return disk_cache;
+}
+
+void seq_disk_cache_free(SeqDiskCache *disk_cache)
+{
+ BLI_freelistN(&disk_cache->files);
+ BLI_mutex_end(&disk_cache->read_write_mutex);
+ MEM_freeN(disk_cache);
+}
diff --git a/source/blender/sequencer/intern/disk_cache.h b/source/blender/sequencer/intern/disk_cache.h
new file mode 100644
index 00000000000..a84bfaf5ea0
--- /dev/null
+++ b/source/blender/sequencer/intern/disk_cache.h
@@ -0,0 +1,56 @@
+/*
+ * 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) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup sequencer
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup sequencer
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ImBuf;
+struct Main;
+struct Scene;
+struct SeqCacheKey;
+struct SeqDiskCache;
+struct Sequence;
+
+struct SeqDiskCache *seq_disk_cache_create(struct Main *bmain, struct Scene *scene);
+void seq_disk_cache_free(struct SeqDiskCache *disk_cache);
+bool seq_disk_cache_is_enabled(struct Main *bmain);
+struct ImBuf *seq_disk_cache_read_file(struct SeqDiskCache *disk_cache, struct SeqCacheKey *key);
+bool seq_disk_cache_write_file(struct SeqDiskCache *disk_cache,
+ struct SeqCacheKey *key,
+ struct ImBuf *ibuf);
+bool seq_disk_cache_enforce_limits(struct SeqDiskCache *disk_cache);
+void seq_disk_cache_invalidate(struct SeqDiskCache *disk_cache,
+ struct Scene *scene,
+ struct Sequence *seq,
+ struct Sequence *seq_changed,
+ int invalidate_types);
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index 427a8835879..a35e83a8632 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -206,69 +206,22 @@ static void init_alpha_over_or_under(Sequence *seq)
seq->seq1 = seq2;
}
-static void do_alphaover_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
-{
- float fac2, mfac, fac, fac4;
- int xo;
- unsigned char *cp1, *cp2, *rt;
- float tempc[4], rt1[4], rt2[4];
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac4 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
- /* rt = rt1 over rt2 (alpha from rt1) */
-
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
-
- fac = fac2;
- mfac = 1.0f - fac2 * rt1[3];
-
- if (fac <= 0.0f) {
- *((unsigned int *)rt) = *((unsigned int *)cp2);
- }
- else if (mfac <= 0.0f) {
- *((unsigned int *)rt) = *((unsigned int *)cp1);
- }
- else {
- tempc[0] = fac * rt1[0] + mfac * rt2[0];
- tempc[1] = fac * rt1[1] + mfac * rt2[1];
- tempc[2] = fac * rt1[2] + mfac * rt2[2];
- tempc[3] = fac * rt1[3] + mfac * rt2[3];
-
- premul_float_to_straight_uchar(rt, tempc);
- }
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
+static void do_alphaover_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+{
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- if (y == 0) {
- break;
- }
- y--;
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ /* rt = rt1 over rt2 (alpha from rt1) */
- x = xo;
- while (x--) {
+ float tempc[4], rt1[4], rt2[4];
straight_uchar_to_premul_float(rt1, cp1);
straight_uchar_to_premul_float(rt2, cp2);
- fac = fac4;
- mfac = 1.0f - (fac4 * rt1[3]);
+ float mfac = 1.0f - fac * rt1[3];
if (fac <= 0.0f) {
*((unsigned int *)rt) = *((unsigned int *)cp2);
@@ -292,27 +245,17 @@ static void do_alphaover_effect_byte(float facf0,
}
static void do_alphaover_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+ float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- float fac2, mfac, fac, fac4;
- int xo;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac4 = facf1;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- while (y--) {
- x = xo;
- while (x--) {
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
/* rt = rt1 over rt2 (alpha from rt1) */
- fac = fac2;
- mfac = 1.0f - (fac2 * rt1[3]);
+ float mfac = 1.0f - (fac * rt1[3]);
if (fac <= 0.0f) {
memcpy(rt, rt2, sizeof(float[4]));
@@ -330,41 +273,13 @@ static void do_alphaover_effect_float(
rt2 += 4;
rt += 4;
}
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- fac = fac4;
- mfac = 1.0f - (fac4 * rt1[3]);
-
- if (fac <= 0.0f) {
- memcpy(rt, rt2, sizeof(float[4]));
- }
- else if (mfac <= 0.0f) {
- memcpy(rt, rt1, sizeof(float[4]));
- }
- else {
- rt[0] = fac * rt1[0] + mfac * rt2[0];
- rt[1] = fac * rt1[1] + mfac * rt2[1];
- rt[2] = fac * rt1[2] + mfac * rt2[2];
- rt[3] = fac * rt1[3] + mfac * rt2[3];
- }
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
}
}
static void do_alphaover_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -378,7 +293,7 @@ static void do_alphaover_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_alphaover_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_alphaover_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -386,96 +301,47 @@ static void do_alphaover_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_alphaover_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_alphaover_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
/*********************** Alpha Under *************************/
-static void do_alphaunder_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
-{
- float fac2, fac, fac4;
- int xo;
- unsigned char *cp1, *cp2, *rt;
- float tempc[4], rt1[4], rt2[4];
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac4 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
+static void do_alphaunder_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+{
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
+
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
/* rt = rt1 under rt2 (alpha from rt2) */
+
+ float tempc[4], rt1[4], rt2[4];
straight_uchar_to_premul_float(rt1, cp1);
straight_uchar_to_premul_float(rt2, cp2);
/* this complex optimization is because the
* 'skybuf' can be crossed in
*/
- if (rt2[3] <= 0.0f && fac2 >= 1.0f) {
+ if (rt2[3] <= 0.0f && fac >= 1.0f) {
*((unsigned int *)rt) = *((unsigned int *)cp1);
}
else if (rt2[3] >= 1.0f) {
*((unsigned int *)rt) = *((unsigned int *)cp2);
}
else {
- fac = (fac2 * (1.0f - rt2[3]));
+ float temp_fac = (fac * (1.0f - rt2[3]));
if (fac <= 0) {
*((unsigned int *)rt) = *((unsigned int *)cp2);
}
else {
- tempc[0] = (fac * rt1[0] + rt2[0]);
- tempc[1] = (fac * rt1[1] + rt2[1]);
- tempc[2] = (fac * rt1[2] + rt2[2]);
- tempc[3] = (fac * rt1[3] + rt2[3]);
-
- premul_float_to_straight_uchar(rt, tempc);
- }
- }
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
-
- if (rt2[3] <= 0.0f && fac4 >= 1.0f) {
- *((unsigned int *)rt) = *((unsigned int *)cp1);
- }
- else if (rt2[3] >= 1.0f) {
- *((unsigned int *)rt) = *((unsigned int *)cp2);
- }
- else {
- fac = (fac4 * (1.0f - rt2[3]));
-
- if (fac <= 0) {
- *((unsigned int *)rt) = *((unsigned int *)cp2);
- }
- else {
- tempc[0] = (fac * rt1[0] + rt2[0]);
- tempc[1] = (fac * rt1[1] + rt2[1]);
- tempc[2] = (fac * rt1[2] + rt2[2]);
- tempc[3] = (fac * rt1[3] + rt2[3]);
+ tempc[0] = (temp_fac * rt1[0] + rt2[0]);
+ tempc[1] = (temp_fac * rt1[1] + rt2[1]);
+ tempc[2] = (temp_fac * rt1[2] + rt2[2]);
+ tempc[3] = (temp_fac * rt1[3] + rt2[3]);
premul_float_to_straight_uchar(rt, tempc);
}
@@ -488,76 +354,36 @@ static void do_alphaunder_effect_byte(float facf0,
}
static void do_alphaunder_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+ float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- float fac2, fac, fac4;
- int xo;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- fac2 = facf0;
- fac4 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
/* rt = rt1 under rt2 (alpha from rt2) */
/* this complex optimization is because the
* 'skybuf' can be crossed in
*/
- if (rt2[3] <= 0 && fac2 >= 1.0f) {
+ if (rt2[3] <= 0 && fac >= 1.0f) {
memcpy(rt, rt1, sizeof(float[4]));
}
else if (rt2[3] >= 1.0f) {
memcpy(rt, rt2, sizeof(float[4]));
}
else {
- fac = fac2 * (1.0f - rt2[3]);
+ float temp_fac = fac * (1.0f - rt2[3]);
if (fac == 0) {
memcpy(rt, rt2, sizeof(float[4]));
}
else {
- rt[0] = fac * rt1[0] + rt2[0];
- rt[1] = fac * rt1[1] + rt2[1];
- rt[2] = fac * rt1[2] + rt2[2];
- rt[3] = fac * rt1[3] + rt2[3];
- }
- }
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- if (rt2[3] <= 0 && fac4 >= 1.0f) {
- memcpy(rt, rt1, sizeof(float[4]));
- }
- else if (rt2[3] >= 1.0f) {
- memcpy(rt, rt2, sizeof(float[4]));
- }
- else {
- fac = fac4 * (1.0f - rt2[3]);
-
- if (fac == 0) {
- memcpy(rt, rt2, sizeof(float[4]));
- }
- else {
- rt[0] = fac * rt1[0] + rt2[0];
- rt[1] = fac * rt1[1] + rt2[1];
- rt[2] = fac * rt1[2] + rt2[2];
- rt[3] = fac * rt1[3] + rt2[3];
+ rt[0] = temp_fac * rt1[0] + rt2[0];
+ rt[1] = temp_fac * rt1[1] + rt2[1];
+ rt[2] = temp_fac * rt1[2] + rt2[2];
+ rt[3] = temp_fac * rt1[3] + rt2[3];
}
}
rt1 += 4;
@@ -570,8 +396,7 @@ static void do_alphaunder_effect_float(
static void do_alphaunder_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -585,7 +410,7 @@ static void do_alphaunder_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_alphaunder_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_alphaunder_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -593,58 +418,28 @@ static void do_alphaunder_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_alphaunder_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_alphaunder_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
/*********************** Cross *************************/
-static void do_cross_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
+static void do_cross_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
- int fac1, fac2, fac3, fac4;
- int xo;
- unsigned char *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
+ unsigned char *rt1 = rect1;
+ unsigned char *rt2 = rect2;
+ unsigned char *rt = out;
- fac2 = (int)(256.0f * facf0);
- fac1 = 256 - fac2;
- fac4 = (int)(256.0f * facf1);
- fac3 = 256 - fac4;
+ int temp_fac = (int)(256.0f * fac);
+ int temp_mfac = 256 - temp_fac;
- while (y--) {
- x = xo;
- while (x--) {
- rt[0] = (fac1 * rt1[0] + fac2 * rt2[0]) >> 8;
- rt[1] = (fac1 * rt1[1] + fac2 * rt2[1]) >> 8;
- rt[2] = (fac1 * rt1[2] + fac2 * rt2[2]) >> 8;
- rt[3] = (fac1 * rt1[3] + fac2 * rt2[3]) >> 8;
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- rt[0] = (fac3 * rt1[0] + fac4 * rt2[0]) >> 8;
- rt[1] = (fac3 * rt1[1] + fac4 * rt2[1]) >> 8;
- rt[2] = (fac3 * rt1[2] + fac4 * rt2[2]) >> 8;
- rt[3] = (fac3 * rt1[3] + fac4 * rt2[3]) >> 8;
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rt[0] = (temp_mfac * rt1[0] + temp_fac * rt2[0]) >> 8;
+ rt[1] = (temp_mfac * rt1[1] + temp_fac * rt2[1]) >> 8;
+ rt[2] = (temp_mfac * rt1[2] + temp_fac * rt2[2]) >> 8;
+ rt[3] = (temp_mfac * rt1[3] + temp_fac * rt2[3]) >> 8;
rt1 += 4;
rt2 += 4;
@@ -653,47 +448,20 @@ static void do_cross_effect_byte(float facf0,
}
}
-static void do_cross_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_cross_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- float fac1, fac2, fac3, fac4;
- int xo;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- fac2 = facf0;
- fac1 = 1.0f - fac2;
- fac4 = facf1;
- fac3 = 1.0f - fac4;
+ float mfac = 1.0f - fac;
- while (y--) {
- x = xo;
- while (x--) {
- rt[0] = fac1 * rt1[0] + fac2 * rt2[0];
- rt[1] = fac1 * rt1[1] + fac2 * rt2[1];
- rt[2] = fac1 * rt1[2] + fac2 * rt2[2];
- rt[3] = fac1 * rt1[3] + fac2 * rt2[3];
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- rt[0] = fac3 * rt1[0] + fac4 * rt2[0];
- rt[1] = fac3 * rt1[1] + fac4 * rt2[1];
- rt[2] = fac3 * rt1[2] + fac4 * rt2[2];
- rt[3] = fac3 * rt1[3] + fac4 * rt2[3];
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rt[0] = mfac * rt1[0] + fac * rt2[0];
+ rt[1] = mfac * rt1[1] + fac * rt2[1];
+ rt[2] = mfac * rt1[2] + fac * rt2[2];
+ rt[3] = mfac * rt1[3] + fac * rt2[3];
rt1 += 4;
rt2 += 4;
@@ -705,8 +473,7 @@ static void do_cross_effect_float(
static void do_cross_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -720,7 +487,7 @@ static void do_cross_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_cross_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_cross_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -728,7 +495,7 @@ static void do_cross_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_cross_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_cross_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
@@ -888,58 +655,26 @@ static void free_gammacross(Sequence *UNUSED(seq), const bool UNUSED(do_id_user)
{
}
-static void do_gammacross_effect_byte(float facf0,
- float UNUSED(facf1),
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
+static void do_gammacross_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
- float fac1, fac2;
- int xo;
- unsigned char *cp1, *cp2, *rt;
- float rt1[4], rt2[4], tempc[4];
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac1 = 1.0f - fac2;
-
- while (y--) {
- x = xo;
- while (x--) {
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0]));
- tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1]));
- tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2]));
- tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3]));
-
- premul_float_to_straight_uchar(rt, tempc);
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
+ float mfac = 1.0f - fac;
- if (y == 0) {
- break;
- }
- y--;
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ float rt1[4], rt2[4], tempc[4];
- x = xo;
- while (x--) {
straight_uchar_to_premul_float(rt1, cp1);
straight_uchar_to_premul_float(rt2, cp2);
- tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0]));
- tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1]));
- tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2]));
- tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3]));
+ tempc[0] = gammaCorrect(mfac * invGammaCorrect(rt1[0]) + fac * invGammaCorrect(rt2[0]));
+ tempc[1] = gammaCorrect(mfac * invGammaCorrect(rt1[1]) + fac * invGammaCorrect(rt2[1]));
+ tempc[2] = gammaCorrect(mfac * invGammaCorrect(rt1[2]) + fac * invGammaCorrect(rt2[2]));
+ tempc[3] = gammaCorrect(mfac * invGammaCorrect(rt1[3]) + fac * invGammaCorrect(rt2[3]));
premul_float_to_straight_uchar(rt, tempc);
cp1 += 4;
@@ -950,38 +685,17 @@ static void do_gammacross_effect_byte(float facf0,
}
static void do_gammacross_effect_float(
- float facf0, float UNUSED(facf1), int x, int y, float *rect1, float *rect2, float *out)
+ float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- float fac1, fac2;
- int xo;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- fac2 = facf0;
- fac1 = 1.0f - fac2;
-
- while (y--) {
- x = xo * 4;
- while (x--) {
- *rt = gammaCorrect(fac1 * invGammaCorrect(*rt1) + fac2 * invGammaCorrect(*rt2));
- rt1++;
- rt2++;
- rt++;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo * 4;
- while (x--) {
- *rt = gammaCorrect(fac1 * invGammaCorrect(*rt1) + fac2 * invGammaCorrect(*rt2));
+ float mfac = 1.0f - fac;
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ *rt = gammaCorrect(mfac * invGammaCorrect(*rt1) + fac * invGammaCorrect(*rt2));
rt1++;
rt2++;
rt++;
@@ -1003,8 +717,7 @@ static struct ImBuf *gammacross_init_execution(const SeqRenderData *context,
static void do_gammacross_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1018,7 +731,7 @@ static void do_gammacross_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_gammacross_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_gammacross_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -1026,57 +739,27 @@ static void do_gammacross_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_gammacross_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_gammacross_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
/*********************** Add *************************/
-static void do_add_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
-{
- int xo, fac1, fac3;
- unsigned char *cp1, *cp2, *rt;
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac1 = (int)(256.0f * facf0);
- fac3 = (int)(256.0f * facf1);
-
- while (y--) {
- x = xo;
-
- while (x--) {
- const int m = fac1 * (int)cp2[3];
- rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255);
- rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255);
- rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255);
- rt[3] = cp1[3];
+static void do_add_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+{
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
+ int temp_fac = (int)(256.0f * fac);
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- const int m = fac3 * (int)cp2[3];
- rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255);
- rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255);
- rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ const int temp_fac2 = temp_fac * (int)cp2[3];
+ rt[0] = min_ii(cp1[0] + ((temp_fac2 * cp2[0]) >> 16), 255);
+ rt[1] = min_ii(cp1[1] + ((temp_fac2 * cp2[1]) >> 16), 255);
+ rt[2] = min_ii(cp1[2] + ((temp_fac2 * cp2[2]) >> 16), 255);
rt[3] = cp1[3];
cp1 += 4;
@@ -1086,46 +769,18 @@ static void do_add_effect_byte(float facf0,
}
}
-static void do_add_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_add_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- int xo;
- float fac1, fac3;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac1 = facf0;
- fac3 = facf1;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- while (y--) {
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * (1.0f - fac1))) * rt2[3];
- rt[0] = rt1[0] + m * rt2[0];
- rt[1] = rt1[1] + m * rt2[1];
- rt[2] = rt1[2] + m * rt2[2];
- rt[3] = rt1[3];
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * (1.0f - fac3))) * rt2[3];
- rt[0] = rt1[0] + m * rt2[0];
- rt[1] = rt1[1] + m * rt2[1];
- rt[2] = rt1[2] + m * rt2[2];
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ const float temp_fac = (1.0f - (rt1[3] * (1.0f - fac))) * rt2[3];
+ rt[0] = rt1[0] + temp_fac * rt2[0];
+ rt[1] = rt1[1] + temp_fac * rt2[1];
+ rt[2] = rt1[2] + temp_fac * rt2[2];
rt[3] = rt1[3];
rt1 += 4;
@@ -1138,8 +793,7 @@ static void do_add_effect_float(
static void do_add_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1153,7 +807,7 @@ static void do_add_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_add_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_add_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -1161,56 +815,27 @@ static void do_add_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_add_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_add_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
/*********************** Sub *************************/
-static void do_sub_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
-{
- int xo, fac1, fac3;
- unsigned char *cp1, *cp2, *rt;
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac1 = (int)(256.0f * facf0);
- fac3 = (int)(256.0f * facf1);
-
- while (y--) {
- x = xo;
- while (x--) {
- const int m = fac1 * (int)cp2[3];
- rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0);
- rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0);
- rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0);
- rt[3] = cp1[3];
+static void do_sub_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+{
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
+ int temp_fac = (int)(256.0f * fac);
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- const int m = fac3 * (int)cp2[3];
- rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0);
- rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0);
- rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ const int temp_fac2 = temp_fac * (int)cp2[3];
+ rt[0] = max_ii(cp1[0] - ((temp_fac2 * cp2[0]) >> 16), 0);
+ rt[1] = max_ii(cp1[1] - ((temp_fac2 * cp2[1]) >> 16), 0);
+ rt[2] = max_ii(cp1[2] - ((temp_fac2 * cp2[2]) >> 16), 0);
rt[3] = cp1[3];
cp1 += 4;
@@ -1220,47 +845,20 @@ static void do_sub_effect_byte(float facf0,
}
}
-static void do_sub_effect_float(
- float UNUSED(facf0), float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_sub_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- int xo;
- float /* fac1, */ fac3_inv;
- float *rt1, *rt2, *rt;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- /* UNUSED */
- // fac1 = facf0;
- fac3_inv = 1.0f - facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3];
- rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f);
- rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f);
- rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f);
- rt[3] = rt1[3];
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
+ float mfac = 1.0f - fac;
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3];
- rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f);
- rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f);
- rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ const float temp_fac = (1.0f - (rt1[3] * mfac)) * rt2[3];
+ rt[0] = max_ff(rt1[0] - temp_fac * rt2[0], 0.0f);
+ rt[1] = max_ff(rt1[1] - temp_fac * rt2[1], 0.0f);
+ rt[2] = max_ff(rt1[2] - temp_fac * rt2[2], 0.0f);
rt[3] = rt1[3];
rt1 += 4;
@@ -1273,8 +871,7 @@ static void do_sub_effect_float(
static void do_sub_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1288,7 +885,7 @@ static void do_sub_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_sub_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_sub_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -1296,7 +893,7 @@ static void do_sub_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_sub_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_sub_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
@@ -1306,161 +903,95 @@ static void do_sub_effect(const SeqRenderData *context,
#define XOFF 8
#define YOFF 8
-static void do_drop_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect2i,
- unsigned char *rect1i,
- unsigned char *outi)
-{
- int temp, fac, fac1, fac2;
- unsigned char *rt1, *rt2, *out;
- int field = 1;
-
- const int width = x;
- const int height = y;
- const int xoff = min_ii(XOFF, width);
- const int yoff = min_ii(YOFF, height);
-
- fac1 = (int)(70.0f * facf0);
- fac2 = (int)(70.0f * facf1);
-
- rt2 = rect2i + yoff * 4 * width;
- rt1 = rect1i;
- out = outi;
- for (y = 0; y < height - yoff; y++) {
- if (field) {
- fac = fac1;
- }
- else {
- fac = fac2;
- }
- field = !field;
+static void do_drop_effect_byte(
+ float fac, int x, int y, unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi)
+{
+ const int xoff = min_ii(XOFF, x);
+ const int yoff = min_ii(YOFF, y);
+
+ int temp_fac = (int)(70.0f * fac);
+ unsigned char *rt2 = rect2i + yoff * 4 * x;
+ unsigned char *rt1 = rect1i;
+ unsigned char *out = outi;
+ for (int i = 0; i < y - yoff; i++) {
memcpy(out, rt1, sizeof(*out) * xoff * 4);
rt1 += xoff * 4;
out += xoff * 4;
- for (x = xoff; x < width; x++) {
- temp = ((fac * rt2[3]) >> 8);
+ for (int j = xoff; j < x; j++) {
+ int temp_fac2 = ((temp_fac * rt2[3]) >> 8);
- *(out++) = MAX2(0, *rt1 - temp);
+ *(out++) = MAX2(0, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0, *rt1 - temp);
+ *(out++) = MAX2(0, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0, *rt1 - temp);
+ *(out++) = MAX2(0, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0, *rt1 - temp);
+ *(out++) = MAX2(0, *rt1 - temp_fac2);
rt1++;
rt2 += 4;
}
rt2 += xoff * 4;
}
- memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
+ memcpy(out, rt1, sizeof(*out) * yoff * 4 * x);
}
static void do_drop_effect_float(
- float facf0, float facf1, int x, int y, float *rect2i, float *rect1i, float *outi)
-{
- float temp, fac, fac1, fac2;
- float *rt1, *rt2, *out;
- int field = 1;
-
- const int width = x;
- const int height = y;
- const int xoff = min_ii(XOFF, width);
- const int yoff = min_ii(YOFF, height);
-
- fac1 = 70.0f * facf0;
- fac2 = 70.0f * facf1;
-
- rt2 = rect2i + yoff * 4 * width;
- rt1 = rect1i;
- out = outi;
- for (y = 0; y < height - yoff; y++) {
- if (field) {
- fac = fac1;
- }
- else {
- fac = fac2;
- }
- field = !field;
+ float fac, int x, int y, float *rect2i, float *rect1i, float *outi)
+{
+ const int xoff = min_ii(XOFF, x);
+ const int yoff = min_ii(YOFF, y);
+ float temp_fac = 70.0f * fac;
+
+ float *rt2 = rect2i + yoff * 4 * x;
+ float *rt1 = rect1i;
+ float *out = outi;
+ for (int i = 0; i < y - yoff; i++) {
memcpy(out, rt1, sizeof(*out) * xoff * 4);
rt1 += xoff * 4;
out += xoff * 4;
- for (x = xoff; x < width; x++) {
- temp = fac * rt2[3];
+ for (int j = xoff; j < x; j++) {
+ float temp_fac2 = temp_fac * rt2[3];
- *(out++) = MAX2(0.0f, *rt1 - temp);
+ *(out++) = MAX2(0.0f, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0.0f, *rt1 - temp);
+ *(out++) = MAX2(0.0f, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0.0f, *rt1 - temp);
+ *(out++) = MAX2(0.0f, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0.0f, *rt1 - temp);
+ *(out++) = MAX2(0.0f, *rt1 - temp_fac2);
rt1++;
rt2 += 4;
}
rt2 += xoff * 4;
}
- memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
+ memcpy(out, rt1, sizeof(*out) * yoff * 4 * x);
}
/*********************** Mul *************************/
-static void do_mul_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
+static void do_mul_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
- int xo, fac1, fac3;
- unsigned char *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
+ unsigned char *rt1 = rect1;
+ unsigned char *rt2 = rect2;
+ unsigned char *rt = out;
- fac1 = (int)(256.0f * facf0);
- fac3 = (int)(256.0f * facf1);
+ int temp_fac = (int)(256.0f * fac);
/* Formula:
* `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + axaux = c * px + py * s;` // + centx
* `yaux = -s * px + c * py;` // + centy */
- while (y--) {
-
- x = xo;
- while (x--) {
-
- rt[0] = rt1[0] + ((fac1 * rt1[0] * (rt2[0] - 255)) >> 16);
- rt[1] = rt1[1] + ((fac1 * rt1[1] * (rt2[1] - 255)) >> 16);
- rt[2] = rt1[2] + ((fac1 * rt1[2] * (rt2[2] - 255)) >> 16);
- rt[3] = rt1[3] + ((fac1 * rt1[3] * (rt2[3] - 255)) >> 16);
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
-
- rt[0] = rt1[0] + ((fac3 * rt1[0] * (rt2[0] - 255)) >> 16);
- rt[1] = rt1[1] + ((fac3 * rt1[1] * (rt2[1] - 255)) >> 16);
- rt[2] = rt1[2] + ((fac3 * rt1[2] * (rt2[2] - 255)) >> 16);
- rt[3] = rt1[3] + ((fac3 * rt1[3] * (rt2[3] - 255)) >> 16);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rt[0] = rt1[0] + ((temp_fac * rt1[0] * (rt2[0] - 255)) >> 16);
+ rt[1] = rt1[1] + ((temp_fac * rt1[1] * (rt2[1] - 255)) >> 16);
+ rt[2] = rt1[2] + ((temp_fac * rt1[2] * (rt2[2] - 255)) >> 16);
+ rt[3] = rt1[3] + ((temp_fac * rt1[3] * (rt2[3] - 255)) >> 16);
rt1 += 4;
rt2 += 4;
@@ -1469,48 +1000,21 @@ static void do_mul_effect_byte(float facf0,
}
}
-static void do_mul_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_mul_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- int xo;
- float fac1, fac3;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac1 = facf0;
- fac3 = facf1;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
/* Formula:
* `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + a`. */
- while (y--) {
- x = xo;
- while (x--) {
- rt[0] = rt1[0] + fac1 * rt1[0] * (rt2[0] - 1.0f);
- rt[1] = rt1[1] + fac1 * rt1[1] * (rt2[1] - 1.0f);
- rt[2] = rt1[2] + fac1 * rt1[2] * (rt2[2] - 1.0f);
- rt[3] = rt1[3] + fac1 * rt1[3] * (rt2[3] - 1.0f);
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- rt[0] = rt1[0] + fac3 * rt1[0] * (rt2[0] - 1.0f);
- rt[1] = rt1[1] + fac3 * rt1[1] * (rt2[1] - 1.0f);
- rt[2] = rt1[2] + fac3 * rt1[2] * (rt2[2] - 1.0f);
- rt[3] = rt1[3] + fac3 * rt1[3] * (rt2[3] - 1.0f);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rt[0] = rt1[0] + fac * rt1[0] * (rt2[0] - 1.0f);
+ rt[1] = rt1[1] + fac * rt1[1] * (rt2[1] - 1.0f);
+ rt[2] = rt1[2] + fac * rt1[2] * (rt2[2] - 1.0f);
+ rt[3] = rt1[3] + fac * rt1[3] * (rt2[3] - 1.0f);
rt1 += 4;
rt2 += 4;
@@ -1522,8 +1026,7 @@ static void do_mul_effect_float(
static void do_mul_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1537,7 +1040,7 @@ static void do_mul_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_mul_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_mul_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -1545,7 +1048,7 @@ static void do_mul_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_mul_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_mul_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
@@ -1555,8 +1058,7 @@ typedef void (*IMB_blend_func_byte)(unsigned char *dst,
const unsigned char *src2);
typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2);
-BLI_INLINE void apply_blend_function_byte(float facf0,
- float facf1,
+BLI_INLINE void apply_blend_function_byte(float fac,
int x,
int y,
unsigned char *rect1,
@@ -1564,33 +1066,16 @@ BLI_INLINE void apply_blend_function_byte(float facf0,
unsigned char *out,
IMB_blend_func_byte blend_function)
{
- int xo;
- unsigned char *rt1, *rt2, *rt;
- unsigned int achannel;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
- while (y--) {
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = (unsigned int)achannel * facf0;
- blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
- rt[3] = rt1[3];
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
- if (y == 0) {
- break;
- }
- y--;
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = (unsigned int)achannel * facf1;
+ unsigned char *rt1 = rect1;
+ unsigned char *rt2 = rect2;
+ unsigned char *rt = out;
+
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ unsigned int achannel = rt2[3];
+ rt2[3] = (unsigned int)achannel * fac;
blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
+ rt2[3] = achannel;
rt[3] = rt1[3];
rt1 += 4;
rt2 += 4;
@@ -1599,8 +1084,7 @@ BLI_INLINE void apply_blend_function_byte(float facf0,
}
}
-BLI_INLINE void apply_blend_function_float(float facf0,
- float facf1,
+BLI_INLINE void apply_blend_function_float(float fac,
int x,
int y,
float *rect1,
@@ -1608,33 +1092,16 @@ BLI_INLINE void apply_blend_function_float(float facf0,
float *out,
IMB_blend_func_float blend_function)
{
- int xo;
- float *rt1, *rt2, *rt;
- float achannel;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
- while (y--) {
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = achannel * facf0;
- blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
- rt[3] = rt1[3];
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
- if (y == 0) {
- break;
- }
- y--;
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = achannel * facf1;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
+
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ float achannel = rt2[3];
+ rt2[3] = achannel * fac;
blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
+ rt2[3] = achannel;
rt[3] = rt1[3];
rt1 += 4;
rt2 += 4;
@@ -1644,89 +1111,78 @@ BLI_INLINE void apply_blend_function_float(float facf0,
}
static void do_blend_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, int btype, float *out)
+ float fac, int x, int y, float *rect1, float *rect2, int btype, float *out)
{
switch (btype) {
case SEQ_TYPE_ADD:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_add_float);
break;
case SEQ_TYPE_SUB:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_sub_float);
break;
case SEQ_TYPE_MUL:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_mul_float);
break;
case SEQ_TYPE_DARKEN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_darken_float);
break;
case SEQ_TYPE_COLOR_BURN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_burn_float);
break;
case SEQ_TYPE_LINEAR_BURN:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_linearburn_float);
break;
case SEQ_TYPE_SCREEN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_screen_float);
break;
case SEQ_TYPE_LIGHTEN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_lighten_float);
break;
case SEQ_TYPE_DODGE:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_dodge_float);
break;
case SEQ_TYPE_OVERLAY:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_overlay_float);
break;
case SEQ_TYPE_SOFT_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_softlight_float);
break;
case SEQ_TYPE_HARD_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_hardlight_float);
break;
case SEQ_TYPE_PIN_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_pinlight_float);
break;
case SEQ_TYPE_LIN_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_linearlight_float);
break;
case SEQ_TYPE_VIVID_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_vividlight_float);
break;
case SEQ_TYPE_BLEND_COLOR:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_color_float);
break;
case SEQ_TYPE_HUE:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_hue_float);
break;
case SEQ_TYPE_SATURATION:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_saturation_float);
break;
case SEQ_TYPE_VALUE:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_luminosity_float);
break;
case SEQ_TYPE_DIFFERENCE:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_difference_float);
break;
case SEQ_TYPE_EXCLUSION:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_exclusion_float);
break;
default:
break;
}
}
-static void do_blend_effect_byte(float facf0,
- float facf1,
+static void do_blend_effect_byte(float fac,
int x,
int y,
unsigned char *rect1,
@@ -1736,73 +1192,67 @@ static void do_blend_effect_byte(float facf0,
{
switch (btype) {
case SEQ_TYPE_ADD:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_add_byte);
break;
case SEQ_TYPE_SUB:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_sub_byte);
break;
case SEQ_TYPE_MUL:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_mul_byte);
break;
case SEQ_TYPE_DARKEN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_darken_byte);
break;
case SEQ_TYPE_COLOR_BURN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_burn_byte);
break;
case SEQ_TYPE_LINEAR_BURN:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_linearburn_byte);
break;
case SEQ_TYPE_SCREEN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_screen_byte);
break;
case SEQ_TYPE_LIGHTEN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_lighten_byte);
break;
case SEQ_TYPE_DODGE:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_dodge_byte);
break;
case SEQ_TYPE_OVERLAY:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_overlay_byte);
break;
case SEQ_TYPE_SOFT_LIGHT:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_softlight_byte);
break;
case SEQ_TYPE_HARD_LIGHT:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_hardlight_byte);
break;
case SEQ_TYPE_PIN_LIGHT:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_pinlight_byte);
break;
case SEQ_TYPE_LIN_LIGHT:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_linearlight_byte);
break;
case SEQ_TYPE_VIVID_LIGHT:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_vividlight_byte);
break;
case SEQ_TYPE_BLEND_COLOR:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_color_byte);
break;
case SEQ_TYPE_HUE:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_hue_byte);
break;
case SEQ_TYPE_SATURATION:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_saturation_byte);
break;
case SEQ_TYPE_VALUE:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_luminosity_byte);
break;
case SEQ_TYPE_DIFFERENCE:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_difference_byte);
break;
case SEQ_TYPE_EXCLUSION:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_exclusion_byte);
break;
default:
break;
@@ -1812,8 +1262,7 @@ static void do_blend_effect_byte(float facf0,
static void do_blend_mode_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1826,14 +1275,14 @@ static void do_blend_mode_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
do_blend_effect_float(
- facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
+ fac, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
do_blend_effect_byte(
- facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
+ fac, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
}
}
/*********************** Color Mix Effect *************************/
@@ -1853,8 +1302,7 @@ static void init_colormix_effect(Sequence *seq)
static void do_colormix_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1862,24 +1310,24 @@ static void do_colormix_effect(const SeqRenderData *context,
int total_lines,
ImBuf *out)
{
- float facf;
+ float fac;
ColorMixVars *data = seq->effectdata;
- facf = data->factor;
+ fac = data->factor;
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
do_blend_effect_float(
- facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
+ fac, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
do_blend_effect_byte(
- facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
+ fac, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
}
}
@@ -1930,7 +1378,7 @@ static float in_band(float width, float dist, int side, int dir)
return alpha;
}
-static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float facf0)
+static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float fac)
{
float posx, posy, hyp, hyp2, angle, hwidth, b1, b2, b3, pointdist;
/* some future stuff */
@@ -1950,18 +1398,18 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
angle = wipezone->angle;
if (wipe->forward) {
- posx = facf0 * xo;
- posy = facf0 * yo;
+ posx = fac * xo;
+ posy = fac * yo;
}
else {
- posx = xo - facf0 * xo;
- posy = yo - facf0 * yo;
+ posx = xo - fac * xo;
+ posy = yo - fac * yo;
}
switch (wipe->wipetype) {
case DO_SINGLE_WIPE:
- width = min_ii(wipezone->width, facf0 * yo);
- width = min_ii(width, yo - facf0 * yo);
+ width = min_ii(wipezone->width, fac * yo);
+ width = min_ii(width, yo - fac * yo);
if (angle == 0.0f) {
b1 = posy;
@@ -2000,7 +1448,7 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
case DO_DOUBLE_WIPE:
if (!wipe->forward) {
- facf0 = 1.0f - facf0; /* Go the other direction */
+ fac = 1.0f - fac; /* Go the other direction */
}
width = wipezone->width; /* calculate the blur width */
@@ -2053,9 +1501,9 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
* temp3: angle of low side of blur
* temp4: angle of high side of blur
*/
- output = 1.0f - facf0;
+ output = 1.0f - fac;
widthf = wipe->edgeWidth * 2.0f * (float)M_PI;
- temp1 = 2.0f * (float)M_PI * facf0;
+ temp1 = 2.0f * (float)M_PI * fac;
if (wipe->forward) {
temp1 = 2.0f * (float)M_PI - temp1;
@@ -2076,12 +1524,12 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
}
if (wipe->forward) {
- temp3 = temp1 - (widthf * 0.5f) * facf0;
- temp4 = temp1 + (widthf * 0.5f) * (1 - facf0);
+ temp3 = temp1 - (widthf * 0.5f) * fac;
+ temp4 = temp1 + (widthf * 0.5f) * (1 - fac);
}
else {
- temp3 = temp1 - (widthf * 0.5f) * (1 - facf0);
- temp4 = temp1 + (widthf * 0.5f) * facf0;
+ temp3 = temp1 - (widthf * 0.5f) * (1 - fac);
+ temp4 = temp1 + (widthf * 0.5f) * fac;
}
if (temp3 < 0) {
temp3 = 0;
@@ -2118,13 +1566,13 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
}
if (!wipe->forward) {
- facf0 = 1 - facf0;
+ fac = 1 - fac;
}
width = wipezone->width;
hwidth = width * 0.5f;
- temp1 = (halfx - (halfx)*facf0);
+ temp1 = (halfx - (halfx)*fac);
pointdist = hypotf(temp1, temp1);
temp2 = hypotf(halfx - x, halfy - y);
@@ -2175,8 +1623,7 @@ static void copy_wipe_effect(Sequence *dst, Sequence *src, const int UNUSED(flag
}
static void do_wipe_effect_byte(Sequence *seq,
- float facf0,
- float UNUSED(facf1),
+ float fac,
int x,
int y,
unsigned char *rect1,
@@ -2185,20 +1632,15 @@ static void do_wipe_effect_byte(Sequence *seq,
{
WipeZone wipezone;
WipeVars *wipe = (WipeVars *)seq->effectdata;
- int xo, yo;
- unsigned char *cp1, *cp2, *rt;
-
precalc_wipe_zone(&wipezone, wipe, x, y);
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- xo = x;
- yo = y;
- for (y = 0; y < yo; y++) {
- for (x = 0; x < xo; x++) {
- float check = check_zone(&wipezone, x, y, seq, facf0);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ float check = check_zone(&wipezone, x, y, seq, fac);
if (check) {
if (cp1) {
float rt1[4], rt2[4], tempc[4];
@@ -2246,31 +1688,20 @@ static void do_wipe_effect_byte(Sequence *seq,
}
}
-static void do_wipe_effect_float(Sequence *seq,
- float facf0,
- float UNUSED(facf1),
- int x,
- int y,
- float *rect1,
- float *rect2,
- float *out)
+static void do_wipe_effect_float(
+ Sequence *seq, float fac, int x, int y, float *rect1, float *rect2, float *out)
{
WipeZone wipezone;
WipeVars *wipe = (WipeVars *)seq->effectdata;
- int xo, yo;
- float *rt1, *rt2, *rt;
-
precalc_wipe_zone(&wipezone, wipe, x, y);
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- xo = x;
- yo = y;
- for (y = 0; y < yo; y++) {
- for (x = 0; x < xo; x++) {
- float check = check_zone(&wipezone, x, y, seq, facf0);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ float check = check_zone(&wipezone, x, y, seq, fac);
if (check) {
if (rt1) {
rt[0] = rt1[0] * check + rt2[0] * (1 - check);
@@ -2314,8 +1745,7 @@ static void do_wipe_effect_float(Sequence *seq,
static ImBuf *do_wipe_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -2324,8 +1754,7 @@ static ImBuf *do_wipe_effect(const SeqRenderData *context,
if (out->rect_float) {
do_wipe_effect_float(seq,
- facf0,
- facf1,
+ fac,
context->rectx,
context->recty,
ibuf1->rect_float,
@@ -2334,8 +1763,7 @@ static ImBuf *do_wipe_effect(const SeqRenderData *context,
}
else {
do_wipe_effect_byte(seq,
- facf0,
- facf1,
+ fac,
context->rectx,
context->recty,
(unsigned char *)ibuf1->rect,
@@ -2442,8 +1870,7 @@ static void transform_image(int x,
static void do_transform_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *UNUSED(ibuf2),
ImBuf *UNUSED(ibuf3),
@@ -2451,7 +1878,6 @@ static void do_transform_effect(const SeqRenderData *context,
int total_lines,
ImBuf *out)
{
- Scene *scene = context->scene;
TransformVars *transform = (TransformVars *)seq->effectdata;
float scale_x, scale_y, translate_x, translate_y, rotate_radians;
@@ -2469,10 +1895,14 @@ static void do_transform_effect(const SeqRenderData *context,
/* Translate */
if (!transform->percent) {
- float rd_s = (scene->r.size / 100.0f);
+ /* Compensate text size for preview render size. */
+ double proxy_size_comp = context->scene->r.size / 100.0;
+ if (context->preview_render_size != SEQ_RENDER_SIZE_SCENE) {
+ proxy_size_comp = SEQ_rendersize_to_scale_factor(context->preview_render_size);
+ }
- translate_x = transform->xIni * rd_s + (x / 2.0f);
- translate_y = transform->yIni * rd_s + (y / 2.0f);
+ translate_x = transform->xIni * proxy_size_comp + (x / 2.0f);
+ translate_y = transform->yIni * proxy_size_comp + (y / 2.0f);
}
else {
translate_x = x * (transform->xIni / 100.0f) + (x / 2.0f);
@@ -2728,8 +2158,7 @@ static void copy_glow_effect(Sequence *dst, Sequence *src, const int UNUSED(flag
static void do_glow_effect_byte(Sequence *seq,
int render_size,
- float facf0,
- float UNUSED(facf1),
+ float fac,
int x,
int y,
unsigned char *rect1,
@@ -2746,7 +2175,7 @@ static void do_glow_effect_byte(Sequence *seq,
IMB_buffer_float_premultiply(inbuf, x, y);
RVIsolateHighlights_float(
- inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp);
+ inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * fac, glow->fClamp);
RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality);
if (!glow->bNoComp) {
RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y);
@@ -2762,8 +2191,7 @@ static void do_glow_effect_byte(Sequence *seq,
static void do_glow_effect_float(Sequence *seq,
int render_size,
- float facf0,
- float UNUSED(facf1),
+ float fac,
int x,
int y,
float *rect1,
@@ -2775,7 +2203,7 @@ static void do_glow_effect_float(Sequence *seq,
GlowVars *glow = (GlowVars *)seq->effectdata;
RVIsolateHighlights_float(
- inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp);
+ inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * fac, glow->fClamp);
RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality);
if (!glow->bNoComp) {
RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y);
@@ -2785,8 +2213,7 @@ static void do_glow_effect_float(Sequence *seq,
static ImBuf *do_glow_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -2798,8 +2225,7 @@ static ImBuf *do_glow_effect(const SeqRenderData *context,
if (out->rect_float) {
do_glow_effect_float(seq,
render_size,
- facf0,
- facf1,
+ fac,
context->rectx,
context->recty,
ibuf1->rect_float,
@@ -2809,8 +2235,7 @@ static ImBuf *do_glow_effect(const SeqRenderData *context,
else {
do_glow_effect_byte(seq,
render_size,
- facf0,
- facf1,
+ fac,
context->rectx,
context->recty,
(unsigned char *)ibuf1->rect,
@@ -2852,7 +2277,7 @@ static void copy_solid_color(Sequence *dst, Sequence *src, const int UNUSED(flag
dst->effectdata = MEM_dupallocN(src->effectdata);
}
-static int early_out_color(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_color(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_NO_INPUT;
}
@@ -2860,8 +2285,7 @@ static int early_out_color(Sequence *UNUSED(seq), float UNUSED(facf0), float UNU
static ImBuf *do_solid_color(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -2870,75 +2294,50 @@ static ImBuf *do_solid_color(const SeqRenderData *context,
SolidColorVars *cv = (SolidColorVars *)seq->effectdata;
- unsigned char *rect;
- float *rect_float;
- int x; /*= context->rectx;*/ /*UNUSED*/
- int y; /*= context->recty;*/ /*UNUSED*/
+ int x = out->x;
+ int y = out->y;
if (out->rect) {
- unsigned char col0[3];
- unsigned char col1[3];
-
- col0[0] = facf0 * cv->col[0] * 255;
- col0[1] = facf0 * cv->col[1] * 255;
- col0[2] = facf0 * cv->col[2] * 255;
+ unsigned char color[4];
+ color[0] = cv->col[0] * 255;
+ color[1] = cv->col[1] * 255;
+ color[2] = cv->col[2] * 255;
+ color[3] = 255;
- col1[0] = facf1 * cv->col[0] * 255;
- col1[1] = facf1 * cv->col[1] * 255;
- col1[2] = facf1 * cv->col[2] * 255;
+ unsigned char *rect = (unsigned char *)out->rect;
- rect = (unsigned char *)out->rect;
-
- for (y = 0; y < out->y; y++) {
- for (x = 0; x < out->x; x++, rect += 4) {
- rect[0] = col0[0];
- rect[1] = col0[1];
- rect[2] = col0[2];
- rect[3] = 255;
- }
- y++;
- if (y < out->y) {
- for (x = 0; x < out->x; x++, rect += 4) {
- rect[0] = col1[0];
- rect[1] = col1[1];
- rect[2] = col1[2];
- rect[3] = 255;
- }
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rect[0] = color[0];
+ rect[1] = color[1];
+ rect[2] = color[2];
+ rect[3] = color[3];
+ rect += 4;
}
}
}
else if (out->rect_float) {
- float col0[3];
- float col1[3];
-
- col0[0] = facf0 * cv->col[0];
- col0[1] = facf0 * cv->col[1];
- col0[2] = facf0 * cv->col[2];
+ float color[4];
+ color[0] = cv->col[0];
+ color[1] = cv->col[1];
+ color[2] = cv->col[2];
+ color[3] = 255;
- col1[0] = facf1 * cv->col[0];
- col1[1] = facf1 * cv->col[1];
- col1[2] = facf1 * cv->col[2];
+ float *rect_float = out->rect_float;
- rect_float = out->rect_float;
-
- for (y = 0; y < out->y; y++) {
- for (x = 0; x < out->x; x++, rect_float += 4) {
- rect_float[0] = col0[0];
- rect_float[1] = col0[1];
- rect_float[2] = col0[2];
- rect_float[3] = 1.0;
- }
- y++;
- if (y < out->y) {
- for (x = 0; x < out->x; x++, rect_float += 4) {
- rect_float[0] = col1[0];
- rect_float[1] = col1[1];
- rect_float[2] = col1[2];
- rect_float[3] = 1.0;
- }
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rect_float[0] = color[0];
+ rect_float[1] = color[1];
+ rect_float[2] = color[2];
+ rect_float[3] = color[3];
+ rect_float += 4;
}
}
}
+
+ out->planes = R_IMF_PLANES_RGB;
+
return out;
}
@@ -2950,7 +2349,7 @@ static int num_inputs_multicam(void)
return 0;
}
-static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_NO_INPUT;
}
@@ -2958,8 +2357,7 @@ static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(facf0), float
static ImBuf *do_multicam(const SeqRenderData *context,
Sequence *seq,
float timeline_frame,
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *UNUSED(ibuf1),
ImBuf *UNUSED(ibuf2),
ImBuf *UNUSED(ibuf3))
@@ -2994,7 +2392,7 @@ static int num_inputs_adjustment(void)
return 0;
}
-static int early_out_adjustment(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_adjustment(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_NO_INPUT;
}
@@ -3038,8 +2436,7 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl
static ImBuf *do_adjustment(const SeqRenderData *context,
Sequence *seq,
float timeline_frame,
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *UNUSED(ibuf1),
ImBuf *UNUSED(ibuf2),
ImBuf *UNUSED(ibuf3))
@@ -3105,7 +2502,7 @@ static void copy_speed_effect(Sequence *dst, Sequence *src, const int UNUSED(fla
v->frameMap = NULL;
}
-static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_DO_EFFECT;
}
@@ -3129,8 +2526,6 @@ static FCurve *seq_effect_speed_speed_factor_curve_get(Scene *scene, Sequence *s
return id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
}
-/* Build frame map when speed in mode #SEQ_SPEED_MULTIPLY is animated.
- * This is, because `target_frame` value is integrated over time. */
void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq)
{
if ((seq->seq1 == NULL) || (seq->len < 1)) {
@@ -3169,7 +2564,6 @@ static void seq_effect_speed_frame_map_ensure(Scene *scene, Sequence *seq)
seq_effect_speed_rebuild_map(scene, seq);
}
-/* Override timeline_frame when rendering speed effect input. */
float seq_speed_effect_target_frame_get(Scene *scene,
Sequence *seq_speed,
float timeline_frame,
@@ -3240,8 +2634,7 @@ static float speed_effect_interpolation_ratio_get(Scene *scene,
static ImBuf *do_speed_effect(const SeqRenderData *context,
Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -3252,10 +2645,10 @@ static ImBuf *do_speed_effect(const SeqRenderData *context,
if (s->flags & SEQ_SPEED_USE_INTERPOLATION) {
out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
- facf0 = facf1 = speed_effect_interpolation_ratio_get(context->scene, seq, timeline_frame);
+ fac = speed_effect_interpolation_ratio_get(context->scene, seq, timeline_frame);
/* Current frame is ibuf1, next frame is ibuf2. */
out = seq_render_effect_execute_threaded(
- &cross_effect, context, NULL, timeline_frame, facf0, facf1, ibuf1, ibuf2, ibuf3);
+ &cross_effect, context, NULL, timeline_frame, fac, ibuf1, ibuf2, ibuf3);
return out;
}
@@ -3268,8 +2661,7 @@ static ImBuf *do_speed_effect(const SeqRenderData *context,
static void do_overdrop_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -3286,8 +2678,8 @@ static void do_overdrop_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_drop_effect_float(facf0, facf1, x, y, rect1, rect2, rect_out);
- do_alphaover_effect_float(facf0, facf1, x, y, rect1, rect2, rect_out);
+ do_drop_effect_float(fac, x, y, rect1, rect2, rect_out);
+ do_alphaover_effect_float(fac, x, y, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -3295,8 +2687,8 @@ static void do_overdrop_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_drop_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out);
- do_alphaover_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out);
+ do_drop_effect_byte(fac, x, y, rect1, rect2, rect_out);
+ do_alphaover_effect_byte(fac, x, y, rect1, rect2, rect_out);
}
}
@@ -3334,7 +2726,7 @@ static void copy_gaussian_blur_effect(Sequence *dst, Sequence *src, const int UN
dst->effectdata = MEM_dupallocN(src->effectdata);
}
-static int early_out_gaussian_blur(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_gaussian_blur(Sequence *seq, float UNUSED(fac))
{
GaussianBlurVars *data = seq->effectdata;
if (data->size_x == 0.0f && data->size_y == 0) {
@@ -3688,8 +3080,7 @@ static void *render_effect_execute_do_y_thread(void *thread_data_v)
static ImBuf *do_gaussian_blur_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *UNUSED(ibuf2),
ImBuf *UNUSED(ibuf3))
@@ -3738,7 +3129,7 @@ static void init_text_effect(Sequence *seq)
data = seq->effectdata = MEM_callocN(sizeof(TextVars), "textvars");
data->text_font = NULL;
data->text_blf_id = -1;
- data->text_size = 60;
+ data->text_size = 60.0f;
copy_v4_fl(data->color, 1.0f);
data->shadow_color[3] = 0.7f;
@@ -3836,10 +3227,10 @@ static int num_inputs_text(void)
return 0;
}
-static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_text(Sequence *seq, float UNUSED(fac))
{
TextVars *data = seq->effectdata;
- if (data->text[0] == 0 || data->text_size < 1 ||
+ if (data->text[0] == 0 || data->text_size < 1.0f ||
((data->color[3] == 0.0f) &&
(data->shadow_color[3] == 0.0f || (data->flag & SEQ_TEXT_SHADOW) == 0))) {
return EARLY_USE_INPUT_1;
@@ -3850,8 +3241,7 @@ static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1
static ImBuf *do_text_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -3954,12 +3344,12 @@ static ImBuf *do_text_effect(const SeqRenderData *context,
fonty = line_height;
BLF_position(font, x + max_ii(fontx / 55, 1), y - max_ii(fonty / 30, 1), 0.0f);
BLF_buffer_col(font, data->shadow_color);
- BLF_draw_buffer(font, data->text, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(font, data->text, sizeof(data->text));
}
BLF_position(font, x, y, 0.0f);
BLF_buffer_col(font, data->color);
- BLF_draw_buffer(font, data->text, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(font, data->text, sizeof(data->text));
BLF_buffer(font, NULL, NULL, 0, 0, 0, NULL);
@@ -3997,44 +3387,47 @@ static void free_effect_default(Sequence *seq, const bool UNUSED(do_id_user))
MEM_SAFE_FREE(seq->effectdata);
}
-static int early_out_noop(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_noop(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_DO_EFFECT;
}
-static int early_out_fade(Sequence *UNUSED(seq), float facf0, float facf1)
+static int early_out_fade(Sequence *UNUSED(seq), float fac)
{
- if (facf0 == 0.0f && facf1 == 0.0f) {
+ if (fac == 0.0f) {
return EARLY_USE_INPUT_1;
}
- if (facf0 == 1.0f && facf1 == 1.0f) {
+ if (fac == 1.0f) {
return EARLY_USE_INPUT_2;
}
return EARLY_DO_EFFECT;
}
-static int early_out_mul_input2(Sequence *UNUSED(seq), float facf0, float facf1)
+static int early_out_mul_input2(Sequence *UNUSED(seq), float fac)
{
- if (facf0 == 0.0f && facf1 == 0.0f) {
+ if (fac == 0.0f) {
return EARLY_USE_INPUT_1;
}
return EARLY_DO_EFFECT;
}
-static void get_default_fac_noop(Sequence *UNUSED(seq),
- float UNUSED(timeline_frame),
- float *facf0,
- float *facf1)
+static int early_out_mul_input1(Sequence *UNUSED(seq), float fac)
+{
+ if (fac == 0.0f) {
+ return EARLY_USE_INPUT_2;
+ }
+ return EARLY_DO_EFFECT;
+}
+
+static void get_default_fac_noop(Sequence *UNUSED(seq), float UNUSED(timeline_frame), float *fac)
{
- *facf0 = *facf1 = 1.0;
+ *fac = 1.0f;
}
-static void get_default_fac_fade(Sequence *seq, float timeline_frame, float *facf0, float *facf1)
+static void get_default_fac_fade(Sequence *seq, float timeline_frame, float *fac)
{
- *facf0 = (float)(timeline_frame - seq->startdisp);
- *facf1 = (float)(*facf0 + 0.5f);
- *facf0 /= seq->len;
- *facf1 /= seq->len;
+ *fac = (float)(timeline_frame - seq->startdisp);
+ *fac /= seq->len;
}
static struct ImBuf *init_execution(const SeqRenderData *context,
@@ -4131,6 +3524,7 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type)
rval.multithreaded = true;
rval.init = init_alpha_over_or_under;
rval.execute_slice = do_alphaover_effect;
+ rval.early_out = early_out_mul_input1;
break;
case SEQ_TYPE_OVERDROP:
rval.multithreaded = true;
diff --git a/source/blender/sequencer/intern/effects.h b/source/blender/sequencer/intern/effects.h
index 25ba4d8956e..c63f8f7a404 100644
--- a/source/blender/sequencer/intern/effects.h
+++ b/source/blender/sequencer/intern/effects.h
@@ -39,7 +39,14 @@ struct Sequence;
*/
struct SeqEffectHandle seq_effect_get_sequence_blend(struct Sequence *seq);
+/**
+ * Build frame map when speed in mode #SEQ_SPEED_MULTIPLY is animated.
+ * This is, because `target_frame` value is integrated over time.
+ */
void seq_effect_speed_rebuild_map(struct Scene *scene, struct Sequence *seq);
+/**
+ * Override timeline_frame when rendering speed effect input.
+ */
float seq_speed_effect_target_frame_get(struct Scene *scene,
struct Sequence *seq,
float timeline_frame,
diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c
index 86c198075e9..51e4613f088 100644
--- a/source/blender/sequencer/intern/image_cache.c
+++ b/source/blender/sequencer/intern/image_cache.c
@@ -50,9 +50,9 @@
#include "SEQ_prefetch.h"
#include "SEQ_relations.h"
-#include "SEQ_render.h"
#include "SEQ_sequencer.h"
+#include "disk_cache.h"
#include "image_cache.h"
#include "prefetch.h"
#include "strip_time.h"
@@ -80,67 +80,10 @@
* entries one by one in reverse order to their creation.
*
* User can exclude caching of some images. Such entries will have is_temp_cache set.
- *
- *
- * Disk Cache Design Notes
- * =======================
- *
- * Disk cache uses directory specified in user preferences
- * For each cached non-temp image, image data and supplementary info are written to HDD.
- * Multiple(DCACHE_IMAGES_PER_FILE) images share the same file.
- * Each of these files contains header DiskCacheHeader followed by image data.
- * Zlib compression with user definable level can be used to compress image data(per image)
- * Images are written in order in which they are rendered.
- * Overwriting of individual entry is not possible.
- * Stored images are deleted by invalidation, or when size of all files exceeds maximum
- * size specified in user preferences.
- * To distinguish 2 blend files with same name, scene->ed->disk_cache_timestamp
- * is used as UID. Blend file can still be copied manually which may cause conflict.
- *
*/
-/* <cache type>-<resolution X>x<resolution Y>-<rendersize>%(<view_id>)-<frame no>.dcf */
-#define DCACHE_FNAME_FORMAT "%d-%dx%d-%d%%(%d)-%d.dcf"
-#define DCACHE_IMAGES_PER_FILE 100
-#define DCACHE_CURRENT_VERSION 2
-#define COLORSPACE_NAME_MAX 64 /* XXX: defined in imb intern */
#define THUMB_CACHE_LIMIT 5000
-typedef struct DiskCacheHeaderEntry {
- unsigned char encoding;
- uint64_t frameno;
- uint64_t size_compressed;
- uint64_t size_raw;
- uint64_t offset;
- char colorspace_name[COLORSPACE_NAME_MAX];
-} DiskCacheHeaderEntry;
-
-typedef struct DiskCacheHeader {
- DiskCacheHeaderEntry entry[DCACHE_IMAGES_PER_FILE];
-} DiskCacheHeader;
-
-typedef struct SeqDiskCache {
- Main *bmain;
- int64_t timestamp;
- ListBase files;
- ThreadMutex read_write_mutex;
- size_t size_total;
-} SeqDiskCache;
-
-typedef struct DiskCacheFile {
- struct DiskCacheFile *next, *prev;
- char path[FILE_MAX];
- char dir[FILE_MAXDIR];
- char file[FILE_MAX];
- BLI_stat_t fstat;
- int cache_type;
- int rectx;
- int recty;
- int render_size;
- int view_id;
- int start_frame;
-} DiskCacheFile;
-
typedef struct SeqCache {
Main *bmain;
struct GHash *hash;
@@ -148,7 +91,7 @@ typedef struct SeqCache {
struct BLI_mempool *keys_pool;
struct BLI_mempool *items_pool;
struct SeqCacheKey *last_key;
- SeqDiskCache *disk_cache;
+ struct SeqDiskCache *disk_cache;
int thumbnail_count;
} SeqCache;
@@ -157,577 +100,7 @@ typedef struct SeqCacheItem {
struct ImBuf *ibuf;
} SeqCacheItem;
-typedef struct SeqCacheKey {
- struct SeqCache *cache_owner;
- void *userkey;
- struct SeqCacheKey *link_prev; /* Used for linking intermediate items to final frame. */
- struct SeqCacheKey *link_next; /* Used for linking intermediate items to final frame. */
- struct Sequence *seq;
- SeqRenderData context;
- float frame_index; /* Usually same as timeline_frame. Mapped to media for RAW entries. */
- float timeline_frame; /* Only for reference - used for freeing when cache is full. */
- float cost; /* In short: render time(s) divided by playback frame duration(s) */
- bool is_temp_cache; /* this cache entry will be freed before rendering next frame */
- /* ID of task for assigning temp cache entries to particular task(thread, etc.) */
- eSeqTaskId task_id;
- int type;
-} SeqCacheKey;
-
static ThreadMutex cache_create_lock = BLI_MUTEX_INITIALIZER;
-static float seq_cache_timeline_frame_to_frame_index(Sequence *seq,
- float timeline_frame,
- int type);
-static float seq_cache_frame_index_to_timeline_frame(Sequence *seq, float frame_index);
-
-static char *seq_disk_cache_base_dir(void)
-{
- return U.sequencer_disk_cache_dir;
-}
-
-static int seq_disk_cache_compression_level(void)
-{
- switch (U.sequencer_disk_cache_compression) {
- case USER_SEQ_DISK_CACHE_COMPRESSION_NONE:
- return 0;
- case USER_SEQ_DISK_CACHE_COMPRESSION_LOW:
- return 1;
- case USER_SEQ_DISK_CACHE_COMPRESSION_HIGH:
- return 9;
- }
-
- return U.sequencer_disk_cache_compression;
-}
-
-static size_t seq_disk_cache_size_limit(void)
-{
- return (size_t)U.sequencer_disk_cache_size_limit * (1024 * 1024 * 1024);
-}
-
-static bool seq_disk_cache_is_enabled(Main *bmain)
-{
- return (U.sequencer_disk_cache_dir[0] != '\0' && U.sequencer_disk_cache_size_limit != 0 &&
- (U.sequencer_disk_cache_flag & SEQ_CACHE_DISK_CACHE_ENABLE) != 0 &&
- bmain->name[0] != '\0');
-}
-
-static DiskCacheFile *seq_disk_cache_add_file_to_list(SeqDiskCache *disk_cache, const char *path)
-{
-
- DiskCacheFile *cache_file = MEM_callocN(sizeof(DiskCacheFile), "SeqDiskCacheFile");
- char dir[FILE_MAXDIR], file[FILE_MAX];
- BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
- BLI_strncpy(cache_file->path, path, sizeof(cache_file->path));
- BLI_strncpy(cache_file->dir, dir, sizeof(cache_file->dir));
- BLI_strncpy(cache_file->file, file, sizeof(cache_file->file));
- sscanf(file,
- DCACHE_FNAME_FORMAT,
- &cache_file->cache_type,
- &cache_file->rectx,
- &cache_file->recty,
- &cache_file->render_size,
- &cache_file->view_id,
- &cache_file->start_frame);
- cache_file->start_frame *= DCACHE_IMAGES_PER_FILE;
- BLI_addtail(&disk_cache->files, cache_file);
- return cache_file;
-}
-
-static void seq_disk_cache_get_files(SeqDiskCache *disk_cache, char *path)
-{
- struct direntry *filelist, *fl;
- uint nbr, i;
- disk_cache->size_total = 0;
-
- i = nbr = BLI_filelist_dir_contents(path, &filelist);
- fl = filelist;
- while (i--) {
- /* Don't follow links. */
- const eFileAttributes file_attrs = BLI_file_attributes(fl->path);
- if (file_attrs & FILE_ATTR_ANY_LINK) {
- fl++;
- continue;
- }
-
- char file[FILE_MAX];
- BLI_split_dirfile(fl->path, NULL, file, 0, sizeof(file));
-
- bool is_dir = BLI_is_dir(fl->path);
- if (is_dir && !FILENAME_IS_CURRPAR(file)) {
- char subpath[FILE_MAX];
- BLI_strncpy(subpath, fl->path, sizeof(subpath));
- BLI_path_slash_ensure(subpath);
- seq_disk_cache_get_files(disk_cache, subpath);
- }
-
- if (!is_dir) {
- const char *ext = BLI_path_extension(fl->path);
- if (ext && ext[1] == 'd' && ext[2] == 'c' && ext[3] == 'f') {
- DiskCacheFile *cache_file = seq_disk_cache_add_file_to_list(disk_cache, fl->path);
- cache_file->fstat = fl->s;
- disk_cache->size_total += cache_file->fstat.st_size;
- }
- }
- fl++;
- }
- BLI_filelist_free(filelist, nbr);
-}
-
-static DiskCacheFile *seq_disk_cache_get_oldest_file(SeqDiskCache *disk_cache)
-{
- DiskCacheFile *oldest_file = disk_cache->files.first;
- if (oldest_file == NULL) {
- return NULL;
- }
- for (DiskCacheFile *cache_file = oldest_file->next; cache_file; cache_file = cache_file->next) {
- if (cache_file->fstat.st_mtime < oldest_file->fstat.st_mtime) {
- oldest_file = cache_file;
- }
- }
-
- return oldest_file;
-}
-
-static void seq_disk_cache_delete_file(SeqDiskCache *disk_cache, DiskCacheFile *file)
-{
- disk_cache->size_total -= file->fstat.st_size;
- BLI_delete(file->path, false, false);
- BLI_remlink(&disk_cache->files, file);
- MEM_freeN(file);
-}
-
-static bool seq_disk_cache_enforce_limits(SeqDiskCache *disk_cache)
-{
- BLI_mutex_lock(&disk_cache->read_write_mutex);
- while (disk_cache->size_total > seq_disk_cache_size_limit()) {
- DiskCacheFile *oldest_file = seq_disk_cache_get_oldest_file(disk_cache);
-
- if (!oldest_file) {
- /* We shouldn't enforce limits with no files, do re-scan. */
- seq_disk_cache_get_files(disk_cache, seq_disk_cache_base_dir());
- continue;
- }
-
- if (BLI_exists(oldest_file->path) == 0) {
- /* File may have been manually deleted during runtime, do re-scan. */
- BLI_freelistN(&disk_cache->files);
- seq_disk_cache_get_files(disk_cache, seq_disk_cache_base_dir());
- continue;
- }
-
- seq_disk_cache_delete_file(disk_cache, oldest_file);
- }
- BLI_mutex_unlock(&disk_cache->read_write_mutex);
-
- return true;
-}
-
-static DiskCacheFile *seq_disk_cache_get_file_entry_by_path(SeqDiskCache *disk_cache, char *path)
-{
- DiskCacheFile *cache_file = disk_cache->files.first;
-
- for (; cache_file; cache_file = cache_file->next) {
- if (BLI_strcasecmp(cache_file->path, path) == 0) {
- return cache_file;
- }
- }
-
- return NULL;
-}
-
-/* Update file size and timestamp. */
-static void seq_disk_cache_update_file(SeqDiskCache *disk_cache, char *path)
-{
- DiskCacheFile *cache_file;
- int64_t size_before;
- int64_t size_after;
-
- cache_file = seq_disk_cache_get_file_entry_by_path(disk_cache, path);
- size_before = cache_file->fstat.st_size;
-
- if (BLI_stat(path, &cache_file->fstat) == -1) {
- BLI_assert(false);
- memset(&cache_file->fstat, 0, sizeof(BLI_stat_t));
- }
-
- size_after = cache_file->fstat.st_size;
- disk_cache->size_total += size_after - size_before;
-}
-
-/* Path format:
- * <cache dir>/<project name>_seq_cache/<scene name>-<timestamp>/<seq name>/DCACHE_FNAME_FORMAT
- */
-
-static void seq_disk_cache_get_project_dir(SeqDiskCache *disk_cache, char *path, size_t path_len)
-{
- char cache_dir[FILE_MAX];
- BLI_split_file_part(BKE_main_blendfile_path(disk_cache->bmain), cache_dir, sizeof(cache_dir));
- /* Use suffix, so that the cache directory name does not conflict with the bmain's blend file. */
- const char *suffix = "_seq_cache";
- strncat(cache_dir, suffix, sizeof(cache_dir) - strlen(cache_dir) - 1);
- BLI_strncpy(path, seq_disk_cache_base_dir(), path_len);
- BLI_path_append(path, path_len, cache_dir);
-}
-
-static void seq_disk_cache_get_dir(
- SeqDiskCache *disk_cache, Scene *scene, Sequence *seq, char *path, size_t path_len)
-{
- char scene_name[MAX_ID_NAME + 22]; /* + -%PRId64 */
- char seq_name[SEQ_NAME_MAXSTR];
- char project_dir[FILE_MAX];
-
- seq_disk_cache_get_project_dir(disk_cache, project_dir, sizeof(project_dir));
- sprintf(scene_name, "%s-%" PRId64, scene->id.name, disk_cache->timestamp);
- BLI_strncpy(seq_name, seq->name, sizeof(seq_name));
- BLI_filename_make_safe(scene_name);
- BLI_filename_make_safe(seq_name);
- BLI_strncpy(path, project_dir, path_len);
- BLI_path_append(path, path_len, scene_name);
- BLI_path_append(path, path_len, seq_name);
-}
-
-static void seq_disk_cache_get_file_path(SeqDiskCache *disk_cache,
- SeqCacheKey *key,
- char *path,
- size_t path_len)
-{
- seq_disk_cache_get_dir(disk_cache, key->context.scene, key->seq, path, path_len);
- int frameno = (int)key->frame_index / DCACHE_IMAGES_PER_FILE;
- char cache_filename[FILE_MAXFILE];
- sprintf(cache_filename,
- DCACHE_FNAME_FORMAT,
- key->type,
- key->context.rectx,
- key->context.recty,
- key->context.preview_render_size,
- key->context.view_id,
- frameno);
-
- BLI_path_append(path, path_len, cache_filename);
-}
-
-static void seq_disk_cache_create_version_file(char *path)
-{
- BLI_make_existing_file(path);
-
- FILE *file = BLI_fopen(path, "w");
- if (file) {
- fprintf(file, "%d", DCACHE_CURRENT_VERSION);
- fclose(file);
- }
-}
-
-static void seq_disk_cache_handle_versioning(SeqDiskCache *disk_cache)
-{
- char path[FILE_MAX];
- char path_version_file[FILE_MAX];
- int version = 0;
-
- seq_disk_cache_get_project_dir(disk_cache, path, sizeof(path));
- BLI_strncpy(path_version_file, path, sizeof(path_version_file));
- BLI_path_append(path_version_file, sizeof(path_version_file), "cache_version");
-
- if (BLI_exists(path) && BLI_is_dir(path)) {
- FILE *file = BLI_fopen(path_version_file, "r");
-
- if (file) {
- const int num_items_read = fscanf(file, "%d", &version);
- if (num_items_read == 0) {
- version = -1;
- }
- fclose(file);
- }
-
- if (version != DCACHE_CURRENT_VERSION) {
- BLI_delete(path, false, true);
- seq_disk_cache_create_version_file(path_version_file);
- }
- }
- else {
- seq_disk_cache_create_version_file(path_version_file);
- }
-}
-
-static void seq_disk_cache_delete_invalid_files(SeqDiskCache *disk_cache,
- Scene *scene,
- Sequence *seq,
- int invalidate_types,
- int range_start,
- int range_end)
-{
- DiskCacheFile *next_file, *cache_file = disk_cache->files.first;
- char cache_dir[FILE_MAX];
- seq_disk_cache_get_dir(disk_cache, scene, seq, cache_dir, sizeof(cache_dir));
- BLI_path_slash_ensure(cache_dir);
-
- while (cache_file) {
- next_file = cache_file->next;
- if (cache_file->cache_type & invalidate_types) {
- if (STREQ(cache_dir, cache_file->dir)) {
- int timeline_frame_start = seq_cache_frame_index_to_timeline_frame(
- seq, cache_file->start_frame);
- if (timeline_frame_start > range_start && timeline_frame_start <= range_end) {
- seq_disk_cache_delete_file(disk_cache, cache_file);
- }
- }
- }
- cache_file = next_file;
- }
-}
-
-static void seq_disk_cache_invalidate(Scene *scene,
- Sequence *seq,
- Sequence *seq_changed,
- int invalidate_types)
-{
- int start;
- int end;
- SeqDiskCache *disk_cache = scene->ed->cache->disk_cache;
-
- BLI_mutex_lock(&disk_cache->read_write_mutex);
-
- start = seq_changed->startdisp - DCACHE_IMAGES_PER_FILE;
- end = seq_changed->enddisp;
-
- seq_disk_cache_delete_invalid_files(disk_cache, scene, seq, invalidate_types, start, end);
-
- BLI_mutex_unlock(&disk_cache->read_write_mutex);
-}
-
-static size_t deflate_imbuf_to_file(ImBuf *ibuf,
- FILE *file,
- int level,
- DiskCacheHeaderEntry *header_entry)
-{
- void *data = (ibuf->rect != NULL) ? (void *)ibuf->rect : (void *)ibuf->rect_float;
-
- /* Apply compression if wanted, otherwise just write directly to the file. */
- if (level > 0) {
- return BLI_file_zstd_from_mem_at_pos(
- data, header_entry->size_raw, file, header_entry->offset, level);
- }
-
- fseek(file, header_entry->offset, SEEK_SET);
- return fwrite(data, 1, header_entry->size_raw, file);
-}
-
-static size_t inflate_file_to_imbuf(ImBuf *ibuf, FILE *file, DiskCacheHeaderEntry *header_entry)
-{
- void *data = (ibuf->rect != NULL) ? (void *)ibuf->rect : (void *)ibuf->rect_float;
- char header[4];
- fseek(file, header_entry->offset, SEEK_SET);
- if (fread(header, 1, sizeof(header), file) != sizeof(header)) {
- return 0;
- }
-
- /* Check if the data is compressed or raw. */
- if (BLI_file_magic_is_zstd(header)) {
- return BLI_file_unzstd_to_mem_at_pos(data, header_entry->size_raw, file, header_entry->offset);
- }
-
- fseek(file, header_entry->offset, SEEK_SET);
- return fread(data, 1, header_entry->size_raw, file);
-}
-
-static bool seq_disk_cache_read_header(FILE *file, DiskCacheHeader *header)
-{
- BLI_fseek(file, 0LL, SEEK_SET);
- const size_t num_items_read = fread(header, sizeof(*header), 1, file);
- if (num_items_read < 1) {
- BLI_assert_msg(0, "unable to read disk cache header");
- perror("unable to read disk cache header");
- return false;
- }
-
- for (int i = 0; i < DCACHE_IMAGES_PER_FILE; i++) {
- if ((ENDIAN_ORDER == B_ENDIAN) && header->entry[i].encoding == 0) {
- BLI_endian_switch_uint64(&header->entry[i].frameno);
- BLI_endian_switch_uint64(&header->entry[i].offset);
- BLI_endian_switch_uint64(&header->entry[i].size_compressed);
- BLI_endian_switch_uint64(&header->entry[i].size_raw);
- }
- }
-
- return true;
-}
-
-static size_t seq_disk_cache_write_header(FILE *file, DiskCacheHeader *header)
-{
- BLI_fseek(file, 0LL, SEEK_SET);
- return fwrite(header, sizeof(*header), 1, file);
-}
-
-static int seq_disk_cache_add_header_entry(SeqCacheKey *key, ImBuf *ibuf, DiskCacheHeader *header)
-{
- int i;
- uint64_t offset = sizeof(*header);
-
- /* Lookup free entry, get offset for new data. */
- for (i = 0; i < DCACHE_IMAGES_PER_FILE; i++) {
- if (header->entry[i].size_compressed == 0) {
- break;
- }
- }
-
- /* Attempt to write beyond set entry limit.
- * Reset file header and start writing from beginning.
- */
- if (i == DCACHE_IMAGES_PER_FILE) {
- i = 0;
- memset(header, 0, sizeof(*header));
- }
-
- /* Calculate offset for image data. */
- if (i > 0) {
- offset = header->entry[i - 1].offset + header->entry[i - 1].size_compressed;
- }
-
- if (ENDIAN_ORDER == B_ENDIAN) {
- header->entry[i].encoding = 255;
- }
- else {
- header->entry[i].encoding = 0;
- }
-
- header->entry[i].offset = offset;
- header->entry[i].frameno = key->frame_index;
-
- /* Store colorspace name of ibuf. */
- const char *colorspace_name;
- if (ibuf->rect) {
- header->entry[i].size_raw = ibuf->x * ibuf->y * ibuf->channels;
- colorspace_name = IMB_colormanagement_get_rect_colorspace(ibuf);
- }
- else {
- header->entry[i].size_raw = ibuf->x * ibuf->y * ibuf->channels * 4;
- colorspace_name = IMB_colormanagement_get_float_colorspace(ibuf);
- }
- BLI_strncpy(
- header->entry[i].colorspace_name, colorspace_name, sizeof(header->entry[i].colorspace_name));
-
- return i;
-}
-
-static int seq_disk_cache_get_header_entry(SeqCacheKey *key, DiskCacheHeader *header)
-{
- for (int i = 0; i < DCACHE_IMAGES_PER_FILE; i++) {
- if (header->entry[i].frameno == key->frame_index) {
- return i;
- }
- }
-
- return -1;
-}
-
-static bool seq_disk_cache_write_file(SeqDiskCache *disk_cache, SeqCacheKey *key, ImBuf *ibuf)
-{
- char path[FILE_MAX];
-
- seq_disk_cache_get_file_path(disk_cache, key, path, sizeof(path));
- BLI_make_existing_file(path);
-
- FILE *file = BLI_fopen(path, "rb+");
- if (!file) {
- file = BLI_fopen(path, "wb+");
- if (!file) {
- return false;
- }
- seq_disk_cache_add_file_to_list(disk_cache, path);
- }
-
- DiskCacheFile *cache_file = seq_disk_cache_get_file_entry_by_path(disk_cache, path);
- DiskCacheHeader header;
- memset(&header, 0, sizeof(header));
- /* #BLI_make_existing_file() above may create an empty file. This is fine, don't attempt reading
- * the header in that case. */
- if (cache_file->fstat.st_size != 0 && !seq_disk_cache_read_header(file, &header)) {
- fclose(file);
- seq_disk_cache_delete_file(disk_cache, cache_file);
- return false;
- }
- int entry_index = seq_disk_cache_add_header_entry(key, ibuf, &header);
-
- size_t bytes_written = deflate_imbuf_to_file(
- ibuf, file, seq_disk_cache_compression_level(), &header.entry[entry_index]);
-
- if (bytes_written != 0) {
- /* Last step is writing header, as image data can be overwritten,
- * but missing data would cause problems.
- */
- header.entry[entry_index].size_compressed = bytes_written;
- seq_disk_cache_write_header(file, &header);
- seq_disk_cache_update_file(disk_cache, path);
- fclose(file);
-
- return true;
- }
-
- return false;
-}
-
-static ImBuf *seq_disk_cache_read_file(SeqDiskCache *disk_cache, SeqCacheKey *key)
-{
- char path[FILE_MAX];
- DiskCacheHeader header;
-
- seq_disk_cache_get_file_path(disk_cache, key, path, sizeof(path));
- BLI_make_existing_file(path);
-
- FILE *file = BLI_fopen(path, "rb");
- if (!file) {
- return NULL;
- }
-
- if (!seq_disk_cache_read_header(file, &header)) {
- fclose(file);
- return NULL;
- }
- int entry_index = seq_disk_cache_get_header_entry(key, &header);
-
- /* Item not found. */
- if (entry_index < 0) {
- fclose(file);
- return NULL;
- }
-
- ImBuf *ibuf;
- uint64_t size_char = (uint64_t)key->context.rectx * key->context.recty * 4;
- uint64_t size_float = (uint64_t)key->context.rectx * key->context.recty * 16;
- size_t expected_size;
-
- if (header.entry[entry_index].size_raw == size_char) {
- expected_size = size_char;
- ibuf = IMB_allocImBuf(key->context.rectx, key->context.recty, 32, IB_rect);
- IMB_colormanagement_assign_rect_colorspace(ibuf, header.entry[entry_index].colorspace_name);
- }
- else if (header.entry[entry_index].size_raw == size_float) {
- expected_size = size_float;
- ibuf = IMB_allocImBuf(key->context.rectx, key->context.recty, 32, IB_rectfloat);
- IMB_colormanagement_assign_float_colorspace(ibuf, header.entry[entry_index].colorspace_name);
- }
- else {
- fclose(file);
- return NULL;
- }
-
- size_t bytes_read = inflate_file_to_imbuf(ibuf, file, &header.entry[entry_index]);
-
- /* Sanity check. */
- if (bytes_read != expected_size) {
- fclose(file);
- IMB_freeImBuf(ibuf);
- return NULL;
- }
- BLI_file_touch(path);
- seq_disk_cache_update_file(disk_cache, path);
- fclose(file);
-
- return ibuf;
-}
-
-#undef DCACHE_FNAME_FORMAT
-#undef DCACHE_IMAGES_PER_FILE
-#undef COLORSPACE_NAME_MAX
-#undef DCACHE_CURRENT_VERSION
static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
{
@@ -778,14 +151,14 @@ static float seq_cache_timeline_frame_to_frame_index(Sequence *seq, float timeli
/* With raw images, map timeline_frame to strip input media frame range. This means that static
* images or extended frame range of movies will only generate one cache entry. No special
* treatment in converting frame index to timeline_frame is needed. */
- if (type == SEQ_CACHE_STORE_RAW || type == SEQ_CACHE_STORE_THUMBNAIL) {
+ if (ELEM(type, SEQ_CACHE_STORE_RAW, SEQ_CACHE_STORE_THUMBNAIL)) {
return seq_give_frame_index(seq, timeline_frame);
}
return timeline_frame - seq->start;
}
-static float seq_cache_frame_index_to_timeline_frame(Sequence *seq, float frame_index)
+float seq_cache_frame_index_to_timeline_frame(Sequence *seq, float frame_index)
{
return frame_index + seq->start;
}
@@ -1080,9 +453,6 @@ static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene)
return finalkey;
}
-/* Find only "base" keys.
- * Sources(other types) for a frame must be freed all at once.
- */
bool seq_cache_recycle_item(Scene *scene)
{
SeqCache *cache = seq_cache_get_from_scene(scene);
@@ -1131,28 +501,6 @@ static void seq_cache_set_temp_cache_linked(Scene *scene, SeqCacheKey *base)
}
}
-static void seq_disk_cache_create(Main *bmain, Scene *scene)
-{
- BLI_mutex_lock(&cache_create_lock);
- SeqCache *cache = seq_cache_get_from_scene(scene);
-
- if (cache == NULL) {
- return;
- }
-
- if (cache->disk_cache != NULL) {
- return;
- }
-
- cache->disk_cache = MEM_callocN(sizeof(SeqDiskCache), "SeqDiskCache");
- cache->disk_cache->bmain = bmain;
- BLI_mutex_init(&cache->disk_cache->read_write_mutex);
- seq_disk_cache_handle_versioning(cache->disk_cache);
- seq_disk_cache_get_files(cache->disk_cache, seq_disk_cache_base_dir());
- cache->disk_cache->timestamp = scene->ed->disk_cache_timestamp;
- BLI_mutex_unlock(&cache_create_lock);
-}
-
static void seq_cache_create(Main *bmain, Scene *scene)
{
BLI_mutex_lock(&cache_create_lock);
@@ -1246,9 +594,7 @@ void seq_cache_destruct(Scene *scene)
BLI_mutex_end(&cache->iterator_mutex);
if (cache->disk_cache != NULL) {
- BLI_freelistN(&cache->disk_cache->files);
- BLI_mutex_end(&cache->disk_cache->read_write_mutex);
- MEM_freeN(cache->disk_cache);
+ seq_disk_cache_free(cache->disk_cache);
}
MEM_freeN(cache);
@@ -1297,7 +643,7 @@ void seq_cache_cleanup_sequence(Scene *scene,
}
if (seq_disk_cache_is_enabled(cache->bmain) && cache->disk_cache != NULL) {
- seq_disk_cache_invalidate(scene, seq, seq_changed, invalidate_types);
+ seq_disk_cache_invalidate(cache->disk_cache, scene, seq, seq_changed, invalidate_types);
}
seq_cache_lock(scene);
@@ -1434,12 +780,10 @@ struct ImBuf *seq_cache_get(const SeqRenderData *context,
/* Try disk cache: */
if (seq_disk_cache_is_enabled(context->bmain)) {
if (cache->disk_cache == NULL) {
- seq_disk_cache_create(context->bmain, context->scene);
+ cache->disk_cache = seq_disk_cache_create(context->bmain, context->scene);
}
- BLI_mutex_lock(&cache->disk_cache->read_write_mutex);
ibuf = seq_disk_cache_read_file(cache->disk_cache, &key);
- BLI_mutex_unlock(&cache->disk_cache->read_write_mutex);
if (ibuf == NULL) {
return NULL;
@@ -1550,9 +894,7 @@ void seq_cache_put(
seq_disk_cache_create(context->bmain, context->scene);
}
- BLI_mutex_lock(&cache->disk_cache->read_write_mutex);
seq_disk_cache_write_file(cache->disk_cache, key, i);
- BLI_mutex_unlock(&cache->disk_cache->read_write_mutex);
seq_disk_cache_enforce_limits(cache->disk_cache);
}
}
diff --git a/source/blender/sequencer/intern/image_cache.h b/source/blender/sequencer/intern/image_cache.h
index 60031311985..65732b5d83d 100644
--- a/source/blender/sequencer/intern/image_cache.h
+++ b/source/blender/sequencer/intern/image_cache.h
@@ -27,15 +27,29 @@
extern "C" {
#endif
+#include "SEQ_render.h" /* Needed for #eSeqTaskId. */
+
struct ImBuf;
struct Main;
struct Scene;
struct SeqRenderData;
struct Sequence;
-#ifdef __cplusplus
-}
-#endif
+typedef struct SeqCacheKey {
+ struct SeqCache *cache_owner;
+ void *userkey;
+ struct SeqCacheKey *link_prev; /* Used for linking intermediate items to final frame. */
+ struct SeqCacheKey *link_next; /* Used for linking intermediate items to final frame. */
+ struct Sequence *seq;
+ struct SeqRenderData context;
+ float frame_index; /* Usually same as timeline_frame. Mapped to media for RAW entries. */
+ float timeline_frame; /* Only for reference - used for freeing when cache is full. */
+ float cost; /* In short: render time(s) divided by playback frame duration(s) */
+ bool is_temp_cache; /* this cache entry will be freed before rendering next frame */
+ /* ID of task for assigning temp cache entries to particular task(thread, etc.) */
+ eSeqTaskId task_id;
+ int type;
+} SeqCacheKey;
struct ImBuf *seq_cache_get(const struct SeqRenderData *context,
struct Sequence *seq,
@@ -56,6 +70,10 @@ bool seq_cache_put_if_possible(const struct SeqRenderData *context,
float timeline_frame,
int type,
struct ImBuf *nval);
+/**
+ * Find only "base" keys.
+ * Sources(other types) for a frame must be freed all at once.
+ */
bool seq_cache_recycle_item(struct Scene *scene);
void seq_cache_free_temp_cache(struct Scene *scene, short id, int timeline_frame);
void seq_cache_destruct(struct Scene *scene);
@@ -67,6 +85,7 @@ void seq_cache_cleanup_sequence(struct Scene *scene,
bool force_seq_changed_range);
void seq_cache_thumbnail_cleanup(Scene *scene, rctf *view_area);
bool seq_cache_is_full(void);
+float seq_cache_frame_index_to_timeline_frame(struct Sequence *seq, float frame_index);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c
index 2429405350b..6cd53f08b3a 100644
--- a/source/blender/sequencer/intern/iterator.c
+++ b/source/blender/sequencer/intern/iterator.c
@@ -44,18 +44,6 @@
/** \Iterator API
* \{ */
-/**
- * Utility function for SEQ_ITERATOR_FOREACH macro.
- * Ensure, that iterator is initialized. During initialization return pointer to collection element
- * and step gset iterator. When this function is called after iterator has been initialized, it
- * will do nothing and return true.
- *
- * \param collection: collection to iterate
- * \param iterator: iterator to be initialized
- * \param r_seq: pointer to Sequence pointer
- *
- * \return false when iterator can not be initialized, true otherwise
- */
bool SEQ_iterator_ensure(SeqCollection *collection, SeqIterator *iterator, Sequence **r_seq)
{
if (iterator->iterator_initialized) {
@@ -76,14 +64,6 @@ bool SEQ_iterator_ensure(SeqCollection *collection, SeqIterator *iterator, Seque
return true;
}
-/**
- * Utility function for SEQ_ITERATOR_FOREACH macro.
- * Yield collection element
- *
- * \param iterator: iterator to be initialized
- *
- * \return collection element or NULL when iteration has ended
- */
Sequence *SEQ_iterator_yield(SeqIterator *iterator)
{
Sequence *seq = BLI_gsetIterator_done(&iterator->gsi) ? NULL :
@@ -108,36 +88,17 @@ static bool seq_for_each_recursive(ListBase *seqbase, SeqForEachFunc callback, v
return true;
}
-/**
- * Utility function to recursively iterate through all sequence strips in a `seqbase` list.
- * Uses callback to do operations on each sequence element.
- * The callback can stop the iteration if needed.
- *
- * \param seqbase: #ListBase of sequences to be iterated over.
- * \param callback: query function callback, returns false if iteration should stop.
- * \param user_data: pointer to user data that can be used in the callback function.
- */
void SEQ_for_each_callback(ListBase *seqbase, SeqForEachFunc callback, void *user_data)
{
seq_for_each_recursive(seqbase, callback, user_data);
}
-/**
- * Free strip collection.
- *
- * \param collection: collection to be freed
- */
void SEQ_collection_free(SeqCollection *collection)
{
BLI_gset_free(collection->set, NULL);
MEM_freeN(collection);
}
-/**
- * Create new empty strip collection.
- *
- * \return empty strip collection.
- */
SeqCollection *SEQ_collection_create(const char *name)
{
SeqCollection *collection = MEM_callocN(sizeof(SeqCollection), name);
@@ -146,30 +107,16 @@ SeqCollection *SEQ_collection_create(const char *name)
return collection;
}
-/**
- * Return number of items in collection.
- */
uint SEQ_collection_len(const SeqCollection *collection)
{
return BLI_gset_len(collection->set);
}
-/**
- * Check if seq is in collection.
- */
bool SEQ_collection_has_strip(const Sequence *seq, const SeqCollection *collection)
{
return BLI_gset_haskey(collection->set, seq);
}
-/**
- * Query strips from seqbase. seq_reference is used by query function as filter condition.
- *
- * \param seq_reference: reference strip for query function
- * \param seqbase: ListBase in which strips are queried
- * \param seq_query_func: query function callback
- * \return strip collection
- */
SeqCollection *SEQ_query_by_reference(Sequence *seq_reference,
ListBase *seqbase,
void seq_query_func(Sequence *seq_reference,
@@ -180,40 +127,22 @@ SeqCollection *SEQ_query_by_reference(Sequence *seq_reference,
seq_query_func(seq_reference, seqbase, collection);
return collection;
}
-/**
- * Add strip to collection.
- *
- * \param seq: strip to be added
- * \param collection: collection to which strip will be added
- * \return false if strip is already in set, otherwise true
- */
bool SEQ_collection_append_strip(Sequence *seq, SeqCollection *collection)
{
- if (BLI_gset_lookup(collection->set, seq) != NULL) {
+ void **key;
+ if (BLI_gset_ensure_p_ex(collection->set, seq, &key)) {
return false;
}
- BLI_gset_insert(collection->set, seq);
+
+ *key = (void *)seq;
return true;
}
-/**
- * Remove strip from collection.
- *
- * \param seq: strip to be removed
- * \param collection: collection from which strip will be removed
- * \return true if strip exists in set and it was removed from set, otherwise false
- */
bool SEQ_collection_remove_strip(Sequence *seq, SeqCollection *collection)
{
return BLI_gset_remove(collection->set, seq, NULL);
}
-/**
- * Move strips from collection_src to collection_dst. Source collection will be freed.
- *
- * \param collection_dst: destination collection
- * \param collection_src: source collection
- */
void SEQ_collection_merge(SeqCollection *collection_dst, SeqCollection *collection_src)
{
Sequence *seq;
@@ -223,13 +152,6 @@ void SEQ_collection_merge(SeqCollection *collection_dst, SeqCollection *collecti
SEQ_collection_free(collection_src);
}
-/**
- * Remove strips from collection that are also in `exclude_elements`. Source collection will be
- * freed.
- *
- * \param collection: collection from which strips are removed
- * \param exclude_elements: collection of strips to be removed
- */
void SEQ_collection_exclude(SeqCollection *collection, SeqCollection *exclude_elements)
{
Sequence *seq;
@@ -239,14 +161,6 @@ void SEQ_collection_exclude(SeqCollection *collection, SeqCollection *exclude_el
SEQ_collection_free(exclude_elements);
}
-/**
- * Expand collection by running SEQ_query() for each strip, which will be used as reference.
- * Results of these queries will be merged into provided collection.
- *
- * \param seqbase: ListBase in which strips are queried
- * \param collection: SeqCollection to be expanded
- * \param seq_query_func: query function callback
- */
void SEQ_collection_expand(ListBase *seqbase,
SeqCollection *collection,
void seq_query_func(Sequence *seq_reference,
@@ -265,12 +179,6 @@ void SEQ_collection_expand(ListBase *seqbase,
SEQ_collection_merge(collection, query_matches);
}
-/**
- * Duplicate collection
- *
- * \param collection: collection to be duplicated
- * \return duplicate of collection
- */
SeqCollection *SEQ_collection_duplicate(SeqCollection *collection)
{
SeqCollection *duplicate = SEQ_collection_create(__func__);
@@ -293,12 +201,6 @@ static void query_all_strips_recursive(ListBase *seqbase, SeqCollection *collect
}
}
-/**
- * Query all strips in seqbase and nested meta strips.
- *
- * \param seqbase: ListBase in which strips are queried
- * \return strip collection
- */
SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase)
{
SeqCollection *collection = SEQ_collection_create(__func__);
@@ -311,25 +213,15 @@ SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase)
return collection;
}
-/**
- * Query all strips in seqbase. This does not include strips nested in meta strips.
- *
- * \param seqbase: ListBase in which strips are queried
- * \return strip collection
- */
SeqCollection *SEQ_query_all_strips(ListBase *seqbase)
{
SeqCollection *collection = SEQ_collection_create(__func__);
- query_all_strips_recursive(seqbase, collection);
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ SEQ_collection_append_strip(seq, collection);
+ }
return collection;
}
-/**
- * Query all selected strips in seqbase.
- *
- * \param seqbase: ListBase in which strips are queried
- * \return strip collection
- */
SeqCollection *SEQ_query_selected_strips(ListBase *seqbase)
{
SeqCollection *collection = SEQ_collection_create(__func__);
@@ -430,14 +322,6 @@ static void collection_filter_rendered_strips(SeqCollection *collection)
}
}
-/**
- * Query strips that are rendered at \a timeline_frame when \a displayed channel is viewed
- *
- * \param seqbase: ListBase in which strips are queried
- * \param timeline_frame: viewed frame
- * \param displayed_channel: viewed channel. when set to 0, no channel filter is applied
- * \return strip collection
- */
SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase,
const int timeline_frame,
const int displayed_channel)
@@ -450,12 +334,6 @@ SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase,
return collection;
}
-/**
- * Query all unselected strips in seqbase.
- *
- * \param seqbase: ListBase in which strips are queried
- * \return strip collection
- */
SeqCollection *SEQ_query_unselected_strips(ListBase *seqbase)
{
SeqCollection *collection = SEQ_collection_create(__func__);
@@ -468,15 +346,6 @@ SeqCollection *SEQ_query_unselected_strips(ListBase *seqbase)
return collection;
}
-/**
- * Query all effect strips that are directly or indirectly connected to seq_reference.
- * This includes all effects of seq_reference, strips used by another inputs and their effects, so
- * that whole chain is fully independent of other strips.
- *
- * \param seq_reference: reference strip
- * \param seqbase: ListBase in which strips are queried
- * \param collection: collection to be filled
- */
void SEQ_query_strip_effect_chain(Sequence *seq_reference,
ListBase *seqbase,
SeqCollection *collection)
diff --git a/source/blender/sequencer/intern/modifier.c b/source/blender/sequencer/intern/modifier.c
index 07d09f4ae17..00ae88232fd 100644
--- a/source/blender/sequencer/intern/modifier.c
+++ b/source/blender/sequencer/intern/modifier.c
@@ -216,7 +216,7 @@ static void modifier_apply_threaded(ImBuf *ibuf,
/** \name Color Balance Modifier
* \{ */
-static StripColorBalance calc_cb(StripColorBalance *cb_)
+static StripColorBalance calc_cb_lgg(StripColorBalance *cb_)
{
StripColorBalance cb = *cb_;
int c;
@@ -262,8 +262,52 @@ static StripColorBalance calc_cb(StripColorBalance *cb_)
return cb;
}
+static StripColorBalance calc_cb_sop(StripColorBalance *cb_)
+{
+ StripColorBalance cb = *cb_;
+ int c;
+
+ for (c = 0; c < 3; c++) {
+ if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_SLOPE) {
+ if (cb.slope[c] != 0.0f) {
+ cb.slope[c] = 1.0f / cb.slope[c];
+ }
+ else {
+ cb.slope[c] = 1000000;
+ }
+ }
+
+ if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_OFFSET) {
+ cb.offset[c] = -1.0f * (cb.offset[c] - 1.0f);
+ }
+ else {
+ cb.offset[c] = cb.offset[c] - 1.0f;
+ }
+
+ if (!(cb.flag & SEQ_COLOR_BALANCE_INVERSE_POWER)) {
+ if (cb.power[c] != 0.0f) {
+ cb.power[c] = 1.0f / cb.power[c];
+ }
+ else {
+ cb.power[c] = 1000000;
+ }
+ }
+ }
+
+ return cb;
+}
+
+static StripColorBalance calc_cb(StripColorBalance *cb_)
+{
+ if (cb_->method == SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN) {
+ return calc_cb_lgg(cb_);
+ }
+ /* `cb_->method == SEQ_COLOR_BALANCE_METHOD_SLOPEOFFSETPOWER`. */
+ return calc_cb_sop(cb_);
+}
+
/* NOTE: lift is actually 2-lift. */
-MINLINE float color_balance_fl(
+MINLINE float color_balance_fl_lgg(
float in, const float lift, const float gain, const float gamma, const float mul)
{
float x = (((in - 1.0f) * lift) + 1.0f) * gain;
@@ -278,12 +322,40 @@ MINLINE float color_balance_fl(
return x;
}
-static void make_cb_table_float(float lift, float gain, float gamma, float *table, float mul)
+MINLINE float color_balance_fl_sop(float in,
+ const float slope,
+ const float offset,
+ const float power,
+ const float pivot,
+ float mul)
{
- int y;
+ float x = in * slope + offset;
+
+ /* prevent NaN */
+ if (x < 0.0f) {
+ x = 0.0f;
+ }
- for (y = 0; y < 256; y++) {
- float v = color_balance_fl((float)y * (1.0f / 255.0f), lift, gain, gamma, mul);
+ x = powf(x / pivot, power) * pivot;
+ x *= mul;
+ CLAMP(x, FLT_MIN, FLT_MAX);
+ return x;
+}
+
+static void make_cb_table_float_lgg(float lift, float gain, float gamma, float *table, float mul)
+{
+ for (int y = 0; y < 256; y++) {
+ float v = color_balance_fl_lgg((float)y * (1.0f / 255.0f), lift, gain, gamma, mul);
+
+ table[y] = v;
+ }
+}
+
+static void make_cb_table_float_sop(
+ float slope, float offset, float power, float pivot, float *table, float mul)
+{
+ for (int y = 0; y < 256; y++) {
+ float v = color_balance_fl_sop((float)y * (1.0f / 255.0f), slope, offset, power, pivot, mul);
table[y] = v;
}
@@ -310,7 +382,13 @@ static void color_balance_byte_byte(StripColorBalance *cb_,
straight_uchar_to_premul_float(p, cp);
for (c = 0; c < 3; c++) {
- float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
+ float t;
+ if (cb.method == SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN) {
+ t = color_balance_fl_lgg(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
+ }
+ else {
+ t = color_balance_fl_sop(p[c], cb.slope[c], cb.offset[c], cb.power[c], 1.0, mul);
+ }
if (m) {
float m_normal = (float)m[c] / 255.0f;
@@ -352,7 +430,12 @@ static void color_balance_byte_float(StripColorBalance *cb_,
cb = calc_cb(cb_);
for (c = 0; c < 3; c++) {
- make_cb_table_float(cb.lift[c], cb.gain[c], cb.gamma[c], cb_tab[c], mul);
+ if (cb.method == SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN) {
+ make_cb_table_float_lgg(cb.lift[c], cb.gain[c], cb.gamma[c], cb_tab[c], mul);
+ }
+ else {
+ make_cb_table_float_sop(cb.slope[c], cb.offset[c], cb.power[c], 1.0, cb_tab[c], mul);
+ }
}
for (i = 0; i < 256; i++) {
@@ -397,7 +480,13 @@ static void color_balance_float_float(StripColorBalance *cb_,
while (p < e) {
int c;
for (c = 0; c < 3; c++) {
- float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
+ float t;
+ if (cb_->method == SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN) {
+ t = color_balance_fl_lgg(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
+ }
+ else {
+ t = color_balance_fl_sop(p[c], cb.slope[c], cb.offset[c], cb.power[c], 1.0, mul);
+ }
if (m) {
p[c] = p[c] * (1.0f - m[c]) + t * m[c];
@@ -507,11 +596,15 @@ static void colorBalance_init_data(SequenceModifierData *smd)
int c;
cbmd->color_multiply = 1.0f;
+ cbmd->color_balance.method = 0;
for (c = 0; c < 3; c++) {
cbmd->color_balance.lift[c] = 1.0f;
cbmd->color_balance.gamma[c] = 1.0f;
cbmd->color_balance.gain[c] = 1.0f;
+ cbmd->color_balance.slope[c] = 1.0f;
+ cbmd->color_balance.offset[c] = 1.0f;
+ cbmd->color_balance.power[c] = 1.0f;
}
}
@@ -1068,6 +1161,7 @@ static void maskmodifier_apply(struct SequenceModifierData *UNUSED(smd), ImBuf *
// SequencerMaskModifierData *bcmd = (SequencerMaskModifierData *)smd;
modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, NULL);
+ ibuf->planes = R_IMF_PLANES_RGBA;
}
static SequenceModifierTypeInfo seqModifier_Mask = {
diff --git a/source/blender/sequencer/intern/multiview.c b/source/blender/sequencer/intern/multiview.c
index e120234ed8b..68d2a33fd5c 100644
--- a/source/blender/sequencer/intern/multiview.c
+++ b/source/blender/sequencer/intern/multiview.c
@@ -40,7 +40,6 @@ void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_id)
IMB_suffix_anim(anim, suffix);
}
-/* the number of files will vary according to the stereo format */
int seq_num_files(Scene *scene, char views_format, const bool is_multiview)
{
if (!is_multiview) {
diff --git a/source/blender/sequencer/intern/multiview.h b/source/blender/sequencer/intern/multiview.h
index bbc66c6f84c..79d99c88b50 100644
--- a/source/blender/sequencer/intern/multiview.h
+++ b/source/blender/sequencer/intern/multiview.h
@@ -36,14 +36,17 @@ struct Scene;
* **********************************************************************
*/
-void seq_anim_add_suffix(struct Scene *scene, struct anim *anim, const int view_id);
+void seq_anim_add_suffix(struct Scene *scene, struct anim *anim, int view_id);
void seq_multiview_name(struct Scene *scene,
- const int view_id,
+ int view_id,
const char *prefix,
const char *ext,
char *r_path,
size_t r_size);
-int seq_num_files(struct Scene *scene, char views_format, const bool is_multiview);
+/**
+ * The number of files will vary according to the stereo format.
+ */
+int seq_num_files(struct Scene *scene, char views_format, bool is_multiview);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/prefetch.c b/source/blender/sequencer/intern/prefetch.c
index 3e0b4738db1..42affae26ed 100644
--- a/source/blender/sequencer/intern/prefetch.c
+++ b/source/blender/sequencer/intern/prefetch.c
@@ -162,14 +162,12 @@ static Sequence *sequencer_prefetch_get_original_sequence(Sequence *seq, ListBas
return NULL;
}
-/* for cache context swapping */
Sequence *seq_prefetch_get_original_sequence(Sequence *seq, Scene *scene)
{
Editing *ed = scene->ed;
return sequencer_prefetch_get_original_sequence(seq, &ed->seqbase);
}
-/* for cache context swapping */
SeqRenderData *seq_prefetch_get_original_context(const SeqRenderData *context)
{
PrefetchJob *pfjob = seq_prefetch_job_get(context->scene);
@@ -268,9 +266,6 @@ void SEQ_prefetch_stop_all(void)
}
}
-/* Use also to update scene and context changes
- * This function should almost always be called by cache invalidation, not directly.
- */
void SEQ_prefetch_stop(Scene *scene)
{
PrefetchJob *pfjob;
@@ -333,6 +328,20 @@ static void seq_prefetch_update_scene(Scene *scene)
seq_prefetch_init_depsgraph(pfjob);
}
+static void seq_prefetch_update_active_seqbase(PrefetchJob *pfjob)
+{
+ MetaStack *ms_orig = SEQ_meta_stack_active_get(SEQ_editing_get(pfjob->scene));
+ Editing *ed_eval = SEQ_editing_get(pfjob->scene_eval);
+
+ if (ms_orig != NULL) {
+ Sequence *meta_eval = seq_prefetch_get_original_sequence(ms_orig->parseq, pfjob->scene_eval);
+ SEQ_seqbase_active_set(ed_eval, &meta_eval->seqbase);
+ }
+ else {
+ SEQ_seqbase_active_set(ed_eval, &ed_eval->seqbase);
+ }
+}
+
static void seq_prefetch_resume(Scene *scene)
{
PrefetchJob *pfjob = seq_prefetch_job_get(scene);
@@ -491,7 +500,7 @@ static void *seq_prefetch_frames(void *job)
*/
pfjob->scene_eval->ed->prefetch_job = pfjob;
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(pfjob->scene));
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(pfjob->scene_eval));
if (seq_prefetch_must_skip_frame(pfjob, seqbase)) {
pfjob->num_frames_prefetched++;
continue;
@@ -554,6 +563,7 @@ static PrefetchJob *seq_prefetch_start_ex(const SeqRenderData *context, float cf
seq_prefetch_update_scene(context->scene);
seq_prefetch_update_context(context);
+ seq_prefetch_update_active_seqbase(pfjob);
BLI_threadpool_remove(&pfjob->threads, pfjob);
BLI_threadpool_insert(&pfjob->threads, pfjob);
@@ -561,7 +571,6 @@ static PrefetchJob *seq_prefetch_start_ex(const SeqRenderData *context, float cf
return pfjob;
}
-/* Start or resume prefetching. */
void seq_prefetch_start(const SeqRenderData *context, float timeline_frame)
{
Scene *scene = context->scene;
diff --git a/source/blender/sequencer/intern/prefetch.h b/source/blender/sequencer/intern/prefetch.h
index 8cfc6bf90bd..8cc5f6d35d1 100644
--- a/source/blender/sequencer/intern/prefetch.h
+++ b/source/blender/sequencer/intern/prefetch.h
@@ -35,11 +35,20 @@ struct Sequence;
}
#endif
+/**
+ * Start or resume prefetching.
+ */
void seq_prefetch_start(const struct SeqRenderData *context, float timeline_frame);
void seq_prefetch_free(struct Scene *scene);
bool seq_prefetch_job_is_running(struct Scene *scene);
void seq_prefetch_get_time_range(struct Scene *scene, int *start, int *end);
+/**
+ * For cache context swapping.
+ */
struct SeqRenderData *seq_prefetch_get_original_context(const struct SeqRenderData *context);
+/**
+ * For cache context swapping.
+ */
struct Sequence *seq_prefetch_get_original_sequence(struct Sequence *seq, struct Scene *scene);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c
index 2bc294c91cd..5982f89a287 100644
--- a/source/blender/sequencer/intern/proxy.c
+++ b/source/blender/sequencer/intern/proxy.c
@@ -34,6 +34,7 @@
#include "BLI_fileops.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
+#include "BLI_session_uuid.h"
#include "BLI_string.h"
#ifdef WIN32
@@ -54,6 +55,7 @@
#include "IMB_imbuf_types.h"
#include "IMB_metadata.h"
+#include "SEQ_iterator.h"
#include "SEQ_proxy.h"
#include "SEQ_relations.h"
#include "SEQ_render.h"
@@ -79,6 +81,7 @@ typedef struct SeqIndexBuildContext {
Depsgraph *depsgraph;
Scene *scene;
Sequence *seq, *orig_seq;
+ SessionUUID orig_seq_uuid;
} SeqIndexBuildContext;
int SEQ_rendersize_to_proxysize(int render_size)
@@ -412,7 +415,8 @@ bool SEQ_proxy_rebuild_context(Main *bmain,
Scene *scene,
Sequence *seq,
struct GSet *file_list,
- ListBase *queue)
+ ListBase *queue,
+ bool build_only_on_bad_performance)
{
SeqIndexBuildContext *context;
Sequence *nseq;
@@ -458,6 +462,7 @@ bool SEQ_proxy_rebuild_context(Main *bmain,
context->depsgraph = depsgraph;
context->scene = scene;
context->orig_seq = seq;
+ context->orig_seq_uuid = seq->runtime.session_uuid;
context->seq = nseq;
context->view_id = i; /* only for images */
@@ -472,7 +477,8 @@ bool SEQ_proxy_rebuild_context(Main *bmain,
context->size_flags,
context->quality,
context->overwrite,
- file_list);
+ file_list,
+ build_only_on_bad_performance);
}
if (!context->index_context) {
MEM_freeN(context);
@@ -560,6 +566,18 @@ void SEQ_proxy_rebuild(SeqIndexBuildContext *context,
}
}
+static bool seq_orig_free_anims(Sequence *seq_iter, void *data)
+{
+ SessionUUID orig_seq_uuid = ((SeqIndexBuildContext *)data)->orig_seq_uuid;
+
+ if (BLI_session_uuid_is_equal(&seq_iter->runtime.session_uuid, &orig_seq_uuid)) {
+ for (StripAnim *sanim = seq_iter->anims.first; sanim; sanim = sanim->next) {
+ IMB_close_anim_proxies(sanim->anim);
+ }
+ }
+ return true;
+}
+
void SEQ_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop)
{
if (context->index_context) {
@@ -569,14 +587,13 @@ void SEQ_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop)
IMB_close_anim_proxies(sanim->anim);
}
- for (sanim = context->orig_seq->anims.first; sanim; sanim = sanim->next) {
- IMB_close_anim_proxies(sanim->anim);
- }
+ /* `context->seq_orig` may have been removed during building. */
+ SEQ_for_each_callback(&context->scene->ed->seqbase, seq_orig_free_anims, context);
IMB_anim_index_rebuild_finish(context->index_context, stop);
}
- seq_free_sequence_recurse(NULL, context->seq, true, true);
+ seq_free_sequence_recurse(NULL, context->seq, true);
MEM_freeN(context);
}
@@ -586,10 +603,7 @@ void SEQ_proxy_set(struct Sequence *seq, bool value)
if (value) {
seq->flag |= SEQ_USE_PROXY;
if (seq->strip->proxy == NULL) {
- seq->strip->proxy = MEM_callocN(sizeof(struct StripProxy), "StripProxy");
- seq->strip->proxy->quality = 50;
- seq->strip->proxy->build_tc_flags = SEQ_PROXY_TC_ALL;
- seq->strip->proxy->build_size_flags = SEQ_PROXY_IMAGE_SIZE_25;
+ seq->strip->proxy = seq_strip_proxy_alloc();
}
}
else {
diff --git a/source/blender/sequencer/intern/proxy.h b/source/blender/sequencer/intern/proxy.h
index a65fdcd42fe..e92cd8de429 100644
--- a/source/blender/sequencer/intern/proxy.h
+++ b/source/blender/sequencer/intern/proxy.h
@@ -36,7 +36,7 @@ struct anim;
struct ImBuf *seq_proxy_fetch(const struct SeqRenderData *context,
struct Sequence *seq,
int timeline_frame);
-bool seq_proxy_get_custom_file_fname(struct Sequence *seq, char *name, const int view_id);
+bool seq_proxy_get_custom_file_fname(struct Sequence *seq, char *name, int view_id);
void free_proxy_seq(Sequence *seq);
void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir);
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index cf3f9d5cba5..482425e70d3 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -29,6 +29,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
+#include "DNA_defaults.h"
#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
@@ -69,6 +70,7 @@
#include "SEQ_iterator.h"
#include "SEQ_modifier.h"
#include "SEQ_proxy.h"
+#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
@@ -96,6 +98,7 @@ SequencerDrawView sequencer_view3d_fn = NULL; /* NULL in background mode */
/* -------------------------------------------------------------------- */
/** \name Color-space utility functions
* \{ */
+
void seq_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf)
{
#if 0
@@ -212,6 +215,7 @@ void SEQ_render_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4
/* -------------------------------------------------------------------- */
/** \name Rendering utility functions
* \{ */
+
void SEQ_render_new_render_data(Main *bmain,
struct Depsgraph *depsgraph,
Scene *scene,
@@ -300,25 +304,24 @@ int seq_get_shown_sequences(ListBase *seqbase,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Preprocessing and effects
- * \{ */
-/*
- * input preprocessing for SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP and SEQ_TYPE_SCENE
+/** \name Preprocessing & Effects
+ *
+ * Input preprocessing for SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP and SEQ_TYPE_SCENE.
*
* Do all the things you can't really do afterwards using sequence effects
- * (read: before rescaling to render resolution has been done)
+ * (read: before re-scaling to render resolution has been done).
*
* Order is important!
*
- * - Deinterlace
- * - Crop and transform in image source coordinate space
- * - Flip X + Flip Y (could be done afterwards, backward compatibility)
- * - Promote image to float data (affects pipeline operations afterwards)
+ * - De-interlace.
+ * - Crop and transform in image source coordinate space.
+ * - Flip X + Flip Y (could be done afterwards, backward compatibility).
+ * - Promote image to float data (affects pipeline operations afterwards).
* - Color balance (is most efficient in the byte -> float
* (future: half -> float should also work fine!)
- * case, if done on load, since we can use lookup tables)
- * - Premultiply
- */
+ * case, if done on load, since we can use lookup tables).
+ * - Pre-multiply.
+ * \{ */
static bool sequencer_use_transform(const Sequence *seq)
{
@@ -402,7 +405,7 @@ static void sequencer_image_crop_transform_matrix(const Sequence *seq,
const ImBuf *out,
const float image_scale_factor,
const float preview_scale_factor,
- float r_transform_matrix[3][3])
+ float r_transform_matrix[4][4])
{
const StripTransform *transform = seq->strip->transform;
const float scale_x = transform->scale_x * image_scale_factor;
@@ -411,13 +414,16 @@ static void sequencer_image_crop_transform_matrix(const Sequence *seq,
const float image_center_offs_y = (out->y - in->y) / 2;
const float translate_x = transform->xofs * preview_scale_factor + image_center_offs_x;
const float translate_y = transform->yofs * preview_scale_factor + image_center_offs_y;
- const float pivot[2] = {in->x * transform->origin[0], in->y * transform->origin[1]};
- loc_rot_size_to_mat3(r_transform_matrix,
- (const float[]){translate_x, translate_y},
- transform->rotation,
- (const float[]){scale_x, scale_y});
- transform_pivot_set_m3(r_transform_matrix, pivot);
- invert_m3(r_transform_matrix);
+ const float pivot[3] = {in->x * transform->origin[0], in->y * transform->origin[1], 0.0f};
+
+ float rotation_matrix[3][3];
+ axis_angle_to_mat3_single(rotation_matrix, 'Z', transform->rotation);
+ loc_rot_size_to_mat4(r_transform_matrix,
+ (const float[]){translate_x, translate_y, 0.0f},
+ rotation_matrix,
+ (const float[]){scale_x, scale_y, 1.0f});
+ transform_pivot_set_m4(r_transform_matrix, pivot);
+ invert_m4(r_transform_matrix);
}
static void sequencer_image_crop_init(const Sequence *seq,
@@ -437,26 +443,64 @@ static void sequencer_image_crop_init(const Sequence *seq,
static void sequencer_thumbnail_transform(ImBuf *in, ImBuf *out)
{
float image_scale_factor = (float)out->x / in->x;
- float transform_matrix[3][3];
+ float transform_matrix[4][4];
/* Set to keep same loc,scale,rot but change scale to thumb size limit. */
const float scale_x = 1 * image_scale_factor;
const float scale_y = 1 * image_scale_factor;
const float image_center_offs_x = (out->x - in->x) / 2;
const float image_center_offs_y = (out->y - in->y) / 2;
- const float pivot[2] = {in->x / 2, in->y / 2};
- loc_rot_size_to_mat3(transform_matrix,
- (const float[]){image_center_offs_x, image_center_offs_y},
- 0,
- (const float[]){scale_x, scale_y});
- transform_pivot_set_m3(transform_matrix, pivot);
- invert_m3(transform_matrix);
-
- /* No crop. */
- rctf source_crop;
- BLI_rctf_init(&source_crop, 0, in->x, 0, in->y);
+ const float pivot[3] = {in->x / 2, in->y / 2, 0.0f};
+
+ float rotation_matrix[3][3];
+ unit_m3(rotation_matrix);
+ loc_rot_size_to_mat4(transform_matrix,
+ (const float[]){image_center_offs_x, image_center_offs_y, 0.0f},
+ rotation_matrix,
+ (const float[]){scale_x, scale_y, 1.0f});
+ transform_pivot_set_m4(transform_matrix, pivot);
+ invert_m4(transform_matrix);
+
+ IMB_transform(in, out, IMB_TRANSFORM_MODE_REGULAR, IMB_FILTER_NEAREST, transform_matrix, NULL);
+}
- IMB_transform(in, out, transform_matrix, &source_crop, IMB_FILTER_NEAREST);
+/* Check whether transform introduces transparent ares in the result (happens when the transformed
+ * image does not fully cover the render frame).
+ *
+ * The check is done by checking whether all corners of viewport fit inside of the transformed
+ * image. If they do not the image will have transparent areas. */
+static bool seq_image_transform_transparency_gained(const SeqRenderData *context, Sequence *seq)
+{
+ Scene *scene = context->scene;
+ const int x = context->rectx;
+ const int y = context->recty;
+
+ float seq_image_quad[4][2];
+ SEQ_image_transform_final_quad_get(scene, seq, seq_image_quad);
+ for (int i = 0; i < 4; i++) {
+ add_v2_v2(seq_image_quad[i], (float[]){x / 2, y / 2});
+ }
+
+ return !isect_point_quad_v2((float[]){x, y},
+ seq_image_quad[0],
+ seq_image_quad[1],
+ seq_image_quad[2],
+ seq_image_quad[3]) ||
+ !isect_point_quad_v2((float[]){0, y},
+ seq_image_quad[0],
+ seq_image_quad[1],
+ seq_image_quad[2],
+ seq_image_quad[3]) ||
+ !isect_point_quad_v2((float[]){x, 0},
+ seq_image_quad[0],
+ seq_image_quad[1],
+ seq_image_quad[2],
+ seq_image_quad[3]) ||
+ !isect_point_quad_v2((float[]){0, 0},
+ seq_image_quad[0],
+ seq_image_quad[1],
+ seq_image_quad[2],
+ seq_image_quad[3]);
}
static void sequencer_preprocess_transform_crop(
@@ -470,7 +514,7 @@ static void sequencer_preprocess_transform_crop(
const bool do_scale_to_render_size = seq_need_scale_to_render_size(seq, is_proxy_image);
const float image_scale_factor = do_scale_to_render_size ? 1.0f : preview_scale_factor;
- float transform_matrix[3][3];
+ float transform_matrix[4][4];
sequencer_image_crop_transform_matrix(
seq, in, out, image_scale_factor, preview_scale_factor, transform_matrix);
@@ -482,7 +526,14 @@ static void sequencer_preprocess_transform_crop(
const eIMBInterpolationFilterMode filter = context->for_render ? IMB_FILTER_BILINEAR :
IMB_FILTER_NEAREST;
- IMB_transform(in, out, transform_matrix, &source_crop, filter);
+ IMB_transform(in, out, IMB_TRANSFORM_MODE_CROP_SRC, filter, transform_matrix, &source_crop);
+
+ if (!seq_image_transform_transparency_gained(context, seq)) {
+ out->planes = in->planes;
+ }
+ else {
+ out->planes = R_IMF_PLANES_RGBA;
+ }
}
static void multibuf(ImBuf *ibuf, const float fmul)
@@ -518,6 +569,10 @@ static void multibuf(ImBuf *ibuf, const float fmul)
rt_float += 4;
}
}
+
+ if (ELEM(ibuf->planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB) && fmul < 1.0f) {
+ ibuf->planes = R_IMF_PLANES_RGBA;
+ }
}
static ImBuf *input_preprocess(const SeqRenderData *context,
@@ -629,7 +684,7 @@ typedef struct RenderEffectInitData {
struct SeqEffectHandle *sh;
const SeqRenderData *context;
Sequence *seq;
- float timeline_frame, facf0, facf1;
+ float timeline_frame, fac;
ImBuf *ibuf1, *ibuf2, *ibuf3;
ImBuf *out;
@@ -639,7 +694,7 @@ typedef struct RenderEffectThread {
struct SeqEffectHandle *sh;
const SeqRenderData *context;
Sequence *seq;
- float timeline_frame, facf0, facf1;
+ float timeline_frame, fac;
ImBuf *ibuf1, *ibuf2, *ibuf3;
ImBuf *out;
@@ -658,8 +713,7 @@ static void render_effect_execute_init_handle(void *handle_v,
handle->context = init_data->context;
handle->seq = init_data->seq;
handle->timeline_frame = init_data->timeline_frame;
- handle->facf0 = init_data->facf0;
- handle->facf1 = init_data->facf1;
+ handle->fac = init_data->fac;
handle->ibuf1 = init_data->ibuf1;
handle->ibuf2 = init_data->ibuf2;
handle->ibuf3 = init_data->ibuf3;
@@ -676,8 +730,7 @@ static void *render_effect_execute_do_thread(void *thread_data_v)
thread_data->sh->execute_slice(thread_data->context,
thread_data->seq,
thread_data->timeline_frame,
- thread_data->facf0,
- thread_data->facf1,
+ thread_data->fac,
thread_data->ibuf1,
thread_data->ibuf2,
thread_data->ibuf3,
@@ -692,8 +745,7 @@ ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
const SeqRenderData *context,
Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -705,8 +757,7 @@ ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
init_data.context = context;
init_data.seq = seq;
init_data.timeline_frame = timeline_frame;
- init_data.facf0 = facf0;
- init_data.facf1 = facf1;
+ init_data.fac = fac;
init_data.ibuf1 = ibuf1;
init_data.ibuf2 = ibuf2;
init_data.ibuf3 = ibuf3;
@@ -727,7 +778,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
float timeline_frame)
{
Scene *scene = context->scene;
- float fac, facf;
+ float fac;
int early_out;
int i;
struct SeqEffectHandle sh = SEQ_effect_handle_get(seq);
@@ -749,24 +800,23 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
}
if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
- sh.get_default_fac(seq, timeline_frame, &fac, &facf);
- facf = fac;
+ sh.get_default_fac(seq, timeline_frame, &fac);
}
else {
fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL);
if (fcu) {
- fac = facf = evaluate_fcurve(fcu, timeline_frame);
+ fac = evaluate_fcurve(fcu, timeline_frame);
}
else {
- fac = facf = seq->effect_fader;
+ fac = seq->effect_fader;
}
}
- early_out = sh.early_out(seq, fac, facf);
+ early_out = sh.early_out(seq, fac);
switch (early_out) {
case EARLY_NO_INPUT:
- out = sh.execute(context, seq, timeline_frame, fac, facf, NULL, NULL, NULL);
+ out = sh.execute(context, seq, timeline_frame, fac, NULL, NULL, NULL);
break;
case EARLY_DO_EFFECT:
for (i = 0; i < 3; i++) {
@@ -785,10 +835,10 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
if (ibuf[0] && (ibuf[1] || SEQ_effect_get_num_inputs(seq->type) == 1)) {
if (sh.multithreaded) {
out = seq_render_effect_execute_threaded(
- &sh, context, seq, timeline_frame, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
+ &sh, context, seq, timeline_frame, fac, ibuf[0], ibuf[1], ibuf[2]);
}
else {
- out = sh.execute(context, seq, timeline_frame, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
+ out = sh.execute(context, seq, timeline_frame, fac, ibuf[0], ibuf[1], ibuf[2]);
}
}
break;
@@ -814,11 +864,13 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
return out;
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Individual strip rendering functions
* \{ */
+
/**
* Render individual view for multi-view or single (default view) for mono-view.
*/
@@ -1137,15 +1189,13 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context,
bool *r_is_proxy_image)
{
ImBuf *ibuf = NULL;
- MovieClipUser user;
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
IMB_Proxy_Size psize = SEQ_rendersize_to_proxysize(context->preview_render_size);
if (!seq->clip) {
return NULL;
}
- memset(&user, 0, sizeof(MovieClipUser));
-
BKE_movieclip_user_set_frame(&user, frame_index + seq->anim_startofs + seq->clip->start_frame);
user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
@@ -1174,7 +1224,8 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context,
/* Try to get a proxy image. */
ibuf = seq_get_movieclip_ibuf(seq, user);
- if (ibuf != NULL && psize != IMB_PROXY_NONE) {
+ /* If clip doesn't use proxies, it will fallback to full size render of original file. */
+ if (ibuf != NULL && psize != IMB_PROXY_NONE && BKE_movieclip_proxy_enabled(seq->clip)) {
*r_is_proxy_image = true;
}
@@ -1560,11 +1611,13 @@ static ImBuf *do_render_strip_seqbase(const SeqRenderData *context,
return ibuf;
}
+
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Strip stack rendering functions
+/** \name Strip Stack Rendering Functions
* \{ */
+
static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
SeqRenderState *state,
Sequence *seq,
@@ -1715,8 +1768,8 @@ static bool seq_must_swap_input_in_blend_mode(Sequence *seq)
static int seq_get_early_out_for_blend_mode(Sequence *seq)
{
struct SeqEffectHandle sh = seq_effect_get_sequence_blend(seq);
- float facf = seq->blend_opacity / 100.0f;
- int early_out = sh.early_out(seq, facf, facf);
+ float fac = seq->blend_opacity / 100.0f;
+ int early_out = sh.early_out(seq, fac);
if (ELEM(early_out, EARLY_DO_EFFECT, EARLY_NO_INPUT)) {
return early_out;
@@ -1738,25 +1791,25 @@ static ImBuf *seq_render_strip_stack_apply_effect(
{
ImBuf *out;
struct SeqEffectHandle sh = seq_effect_get_sequence_blend(seq);
- float facf = seq->blend_opacity / 100.0f;
+ float fac = seq->blend_opacity / 100.0f;
int swap_input = seq_must_swap_input_in_blend_mode(seq);
if (swap_input) {
if (sh.multithreaded) {
out = seq_render_effect_execute_threaded(
- &sh, context, seq, timeline_frame, facf, facf, ibuf2, ibuf1, NULL);
+ &sh, context, seq, timeline_frame, fac, ibuf2, ibuf1, NULL);
}
else {
- out = sh.execute(context, seq, timeline_frame, facf, facf, ibuf2, ibuf1, NULL);
+ out = sh.execute(context, seq, timeline_frame, fac, ibuf2, ibuf1, NULL);
}
}
else {
if (sh.multithreaded) {
out = seq_render_effect_execute_threaded(
- &sh, context, seq, timeline_frame, facf, facf, ibuf1, ibuf2, NULL);
+ &sh, context, seq, timeline_frame, fac, ibuf1, ibuf2, NULL);
}
else {
- out = sh.execute(context, seq, timeline_frame, facf, facf, ibuf1, ibuf2, NULL);
+ out = sh.execute(context, seq, timeline_frame, fac, ibuf1, ibuf2, NULL);
}
}
@@ -1796,6 +1849,20 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
early_out = seq_get_early_out_for_blend_mode(seq);
+ /* Early out for alpha over. It requires image to be rendered, so it can't use
+ * `seq_get_early_out_for_blend_mode`. */
+ if (out == NULL && seq->blend_mode == SEQ_TYPE_ALPHAOVER && seq->blend_opacity == 100.0f) {
+ ImBuf *test = seq_render_strip(context, state, seq, timeline_frame);
+ if (ELEM(test->planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB)) {
+ early_out = EARLY_USE_INPUT_2;
+ }
+ else {
+ early_out = EARLY_DO_EFFECT;
+ }
+ /* Free the image. It is stored in cache, so this doesn't affect performance. */
+ IMB_freeImBuf(test);
+ }
+
switch (early_out) {
case EARLY_NO_INPUT:
case EARLY_USE_INPUT_2:
@@ -1820,6 +1887,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
}
break;
}
+
if (out) {
break;
}
@@ -1845,11 +1913,6 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
return out;
}
-/**
- * \return The image buffer or NULL.
- *
- * \note The returned #ImBuf has its reference increased, free after usage!
- */
ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame, int chanshown)
{
Scene *scene = context->scene;
@@ -1882,6 +1945,8 @@ ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame,
}
seq_cache_free_temp_cache(context->scene, context->task_id, timeline_frame);
+ /* Make sure we only keep the `anim` data for strips that are in view. */
+ SEQ_relations_free_all_anim_ibufs(context->scene, timeline_frame);
if (count && !out) {
BLI_mutex_lock(&seq_render_mutex);
@@ -1958,7 +2023,6 @@ static ImBuf *seq_get_uncached_thumbnail(const SeqRenderData *context,
return scaled_ibuf;
}
-/* Get cached thumbnails. */
ImBuf *SEQ_get_thumbnail(
const SeqRenderData *context, Sequence *seq, float timeline_frame, rcti *crop, bool clipped)
{
@@ -1983,7 +2047,6 @@ ImBuf *SEQ_get_thumbnail(
return ibuf_cropped;
}
-/* Render the series of thumbnails and store in cache. */
void SEQ_render_thumbnails(const SeqRenderData *context,
Sequence *seq,
Sequence *seq_orig,
@@ -2028,8 +2091,6 @@ void SEQ_render_thumbnails(const SeqRenderData *context,
}
}
-/* Get frame step for equally spaced thumbnails. These thumbnails should always be present in
- * memory, so they can be used when zooming.*/
int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const Sequence *seq)
{
const int content_len = (seq->enddisp - seq->startdisp - seq->startstill - seq->endstill);
@@ -2037,12 +2098,11 @@ int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const Sequence *seq)
/* Arbitrary, but due to performance reasons should be as low as possible. */
const int thumbnails_base_set_count = min_ii(content_len / 100, 30);
if (thumbnails_base_set_count <= 0) {
- return 0;
+ return content_len;
}
return content_len / thumbnails_base_set_count;
}
-/* Render set of evenly spaced thumbnails that are drawn when zooming. */
void SEQ_render_thumbnails_base_set(const SeqRenderData *context,
Sequence *seq,
Sequence *seq_orig,
diff --git a/source/blender/sequencer/intern/render.h b/source/blender/sequencer/intern/render.h
index a0cdf24d84b..eb1f71769a6 100644
--- a/source/blender/sequencer/intern/render.h
+++ b/source/blender/sequencer/intern/render.h
@@ -54,8 +54,7 @@ struct ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
struct ImBuf *ibuf1,
struct ImBuf *ibuf2,
struct ImBuf *ibuf3);
diff --git a/source/blender/sequencer/intern/sequence_lookup.c b/source/blender/sequencer/intern/sequence_lookup.c
index 25b42957d99..8d451d59e92 100644
--- a/source/blender/sequencer/intern/sequence_lookup.c
+++ b/source/blender/sequencer/intern/sequence_lookup.c
@@ -105,11 +105,6 @@ static void seq_sequence_lookup_update_if_needed(const struct Scene *scene,
seq_sequence_lookup_rebuild(scene, lookup);
}
-/**
- * Free lookup hash data.
- *
- * \param scene: scene that owns lookup hash
- */
void SEQ_sequence_lookup_free(const Scene *scene)
{
BLI_assert(scene->ed);
@@ -119,16 +114,6 @@ void SEQ_sequence_lookup_free(const Scene *scene)
BLI_mutex_unlock(&lookup_lock);
}
-/**
- * Find a sequence with a given name.
- * If lookup hash doesn't exist, it will be created. If hash is tagged as invalid, it will be
- * rebuilt.
- *
- * \param scene: scene that owns lookup hash
- * \param key: Sequence name without SQ prefix (seq->name + 2)
- *
- * \return pointer to Sequence
- */
Sequence *SEQ_sequence_lookup_by_name(const Scene *scene, const char *key)
{
BLI_assert(scene->ed);
@@ -140,12 +125,6 @@ Sequence *SEQ_sequence_lookup_by_name(const Scene *scene, const char *key)
return seq;
}
-/**
- * Find a sequence with a given name.
- *
- * \param scene: scene that owns lookup hash
- * \param tag: tag to set
- */
void SEQ_sequence_lookup_tag(const Scene *scene, eSequenceLookupTag tag)
{
if (!scene->ed) {
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index 3478c2d4f97..1c7fe927381 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -34,10 +34,7 @@
#include "DNA_sound_types.h"
#include "BLI_listbase.h"
-#include "BLI_string.h"
-#include "BKE_animsys.h"
-#include "BKE_fcurve.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
#include "BKE_sound.h"
@@ -65,12 +62,19 @@
#include "sequencer.h"
#include "utils.h"
-static void seq_free_animdata(Scene *scene, Sequence *seq);
-
/* -------------------------------------------------------------------- */
/** \name Allocate / Free Functions
* \{ */
+StripProxy *seq_strip_proxy_alloc(void)
+{
+ StripProxy *strip_proxy = MEM_callocN(sizeof(struct StripProxy), "StripProxy");
+ strip_proxy->quality = 50;
+ strip_proxy->build_tc_flags = SEQ_PROXY_TC_ALL;
+ strip_proxy->tc = SEQ_PROXY_TC_RECORD_RUN;
+ return strip_proxy;
+}
+
static Strip *seq_strip_alloc(int type)
{
Strip *strip = MEM_callocN(sizeof(Strip), "strip");
@@ -140,6 +144,7 @@ Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int
seq->pitch = 1.0f;
seq->scene_sound = NULL;
seq->type = type;
+ seq->blend_mode = SEQ_TYPE_ALPHAOVER;
seq->strip = seq_strip_alloc(type);
seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
@@ -155,8 +160,7 @@ Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int
static void seq_sequence_free_ex(Scene *scene,
Sequence *seq,
const bool do_cache,
- const bool do_id_user,
- const bool do_clean_animdata)
+ const bool do_id_user)
{
if (seq->strip) {
seq_free_strip(seq->strip);
@@ -190,11 +194,6 @@ static void seq_sequence_free_ex(Scene *scene,
if (seq->scene_sound && ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
BKE_sound_remove_scene_sound(scene, seq->scene_sound);
}
-
- /* XXX This must not be done in BKE code. */
- if (do_clean_animdata) {
- seq_free_animdata(scene, seq);
- }
}
if (seq->prop) {
@@ -222,26 +221,21 @@ static void seq_sequence_free_ex(Scene *scene,
MEM_freeN(seq);
}
-void SEQ_sequence_free(Scene *scene, Sequence *seq, const bool do_clean_animdata)
+void SEQ_sequence_free(Scene *scene, Sequence *seq)
{
- seq_sequence_free_ex(scene, seq, true, true, do_clean_animdata);
+ seq_sequence_free_ex(scene, seq, true, true);
}
-/* cache must be freed before calling this function
- * since it leaves the seqbase in an invalid state */
-void seq_free_sequence_recurse(Scene *scene,
- Sequence *seq,
- const bool do_id_user,
- const bool do_clean_animdata)
+void seq_free_sequence_recurse(Scene *scene, Sequence *seq, const bool do_id_user)
{
Sequence *iseq, *iseq_next;
for (iseq = seq->seqbase.first; iseq; iseq = iseq_next) {
iseq_next = iseq->next;
- seq_free_sequence_recurse(scene, iseq, do_id_user, do_clean_animdata);
+ seq_free_sequence_recurse(scene, iseq, do_id_user);
}
- seq_sequence_free_ex(scene, seq, false, do_id_user, do_clean_animdata);
+ seq_sequence_free_ex(scene, seq, false, do_id_user);
}
Editing *SEQ_editing_get(const Scene *scene)
@@ -277,7 +271,7 @@ void SEQ_editing_free(Scene *scene, const bool do_id_user)
/* handle cache freeing above */
LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &ed->seqbase) {
- seq_free_sequence_recurse(scene, seq, do_id_user, false);
+ seq_free_sequence_recurse(scene, seq, do_id_user);
}
BLI_freelistN(&ed->metastack);
@@ -388,12 +382,6 @@ int SEQ_tool_settings_pivot_point_get(Scene *scene)
return tool_settings->pivot_point;
}
-/**
- * Get seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
- *
- * \param ed: sequence editor data
- * \return pointer to active seqbase. returns NULL if ed is NULL
- */
ListBase *SEQ_active_seqbase_get(const Editing *ed)
{
if (ed == NULL) {
@@ -403,24 +391,11 @@ ListBase *SEQ_active_seqbase_get(const Editing *ed)
return ed->seqbasep;
}
-/**
- * Set seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
- *
- * \param ed: sequence editor data
- * \param seqbase: ListBase with strips
- */
void SEQ_seqbase_active_set(Editing *ed, ListBase *seqbase)
{
ed->seqbasep = seqbase;
}
-/**
- * Create and initialize #MetaStack, append it to `ed->metastack` ListBase
- *
- * \param ed: sequence editor data
- * \param seq_meta: meta strip
- * \return pointer to created meta stack
- */
MetaStack *SEQ_meta_stack_alloc(Editing *ed, Sequence *seq_meta)
{
MetaStack *ms = MEM_mallocN(sizeof(MetaStack), "metastack");
@@ -431,26 +406,18 @@ MetaStack *SEQ_meta_stack_alloc(Editing *ed, Sequence *seq_meta)
return ms;
}
-/**
- * Free #MetaStack and remove it from `ed->metastack` ListBase.
- *
- * \param ed: sequence editor data
- * \param ms: meta stack
- */
void SEQ_meta_stack_free(Editing *ed, MetaStack *ms)
{
BLI_remlink(&ed->metastack, ms);
MEM_freeN(ms);
}
-/**
- * Get #MetaStack that corresponds to current level that is being viewed
- *
- * \param ed: sequence editor data
- * \return pointer to meta stack
- */
MetaStack *SEQ_meta_stack_active_get(const Editing *ed)
{
+ if (ed == NULL) {
+ return NULL;
+ }
+
return ed->metastack.last;
}
@@ -459,6 +426,7 @@ MetaStack *SEQ_meta_stack_active_get(const Editing *ed)
/* -------------------------------------------------------------------- */
/** \name Duplicate Functions
* \{ */
+
static Sequence *seq_dupli(const Scene *scene_src,
Scene *scene_dst,
ListBase *new_seq_list,
@@ -650,118 +618,6 @@ bool SEQ_valid_strip_channel(Sequence *seq)
return true;
}
-/* r_prefix + [" + escaped_name + "] + \0 */
-#define SEQ_RNAPATH_MAXSTR ((30 + 2 + (SEQ_NAME_MAXSTR * 2) + 2) + 1)
-
-static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char *name)
-{
- char name_esc[SEQ_NAME_MAXSTR * 2];
-
- BLI_str_escape(name_esc, name, sizeof(name_esc));
- return BLI_snprintf_rlen(
- str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
-}
-
-/* XXX: hackish function needed for transforming strips! TODO: have some better solution. */
-void SEQ_offset_animdata(Scene *scene, Sequence *seq, int ofs)
-{
- char str[SEQ_RNAPATH_MAXSTR];
- size_t str_len;
- FCurve *fcu;
-
- if (scene->adt == NULL || ofs == 0 || scene->adt->action == NULL) {
- return;
- }
-
- str_len = sequencer_rna_path_prefix(str, seq->name + 2);
-
- for (fcu = scene->adt->action->curves.first; fcu; fcu = fcu->next) {
- if (STREQLEN(fcu->rna_path, str, str_len)) {
- unsigned int i;
- if (fcu->bezt) {
- for (i = 0; i < fcu->totvert; i++) {
- BezTriple *bezt = &fcu->bezt[i];
- bezt->vec[0][0] += ofs;
- bezt->vec[1][0] += ofs;
- bezt->vec[2][0] += ofs;
- }
- }
- if (fcu->fpt) {
- for (i = 0; i < fcu->totvert; i++) {
- FPoint *fpt = &fcu->fpt[i];
- fpt->vec[0] += ofs;
- }
- }
- }
- }
-
- DEG_id_tag_update(&scene->adt->action->id, ID_RECALC_ANIMATION);
-}
-
-void SEQ_dupe_animdata(Scene *scene, const char *name_src, const char *name_dst)
-{
- char str_from[SEQ_RNAPATH_MAXSTR];
- size_t str_from_len;
- FCurve *fcu;
- FCurve *fcu_last;
- FCurve *fcu_cpy;
- ListBase lb = {NULL, NULL};
-
- if (scene->adt == NULL || scene->adt->action == NULL) {
- return;
- }
-
- str_from_len = sequencer_rna_path_prefix(str_from, name_src);
-
- fcu_last = scene->adt->action->curves.last;
-
- for (fcu = scene->adt->action->curves.first; fcu && fcu->prev != fcu_last; fcu = fcu->next) {
- if (STREQLEN(fcu->rna_path, str_from, str_from_len)) {
- fcu_cpy = BKE_fcurve_copy(fcu);
- BLI_addtail(&lb, fcu_cpy);
- }
- }
-
- /* notice validate is 0, keep this because the seq may not be added to the scene yet */
- BKE_animdata_fix_paths_rename(
- &scene->id, scene->adt, NULL, "sequence_editor.sequences_all", name_src, name_dst, 0, 0, 0);
-
- /* add the original fcurves back */
- BLI_movelisttolist(&scene->adt->action->curves, &lb);
-}
-
-/* XXX: hackish function needed to remove all fcurves belonging to a sequencer strip. */
-static void seq_free_animdata(Scene *scene, Sequence *seq)
-{
- char str[SEQ_RNAPATH_MAXSTR];
- size_t str_len;
- FCurve *fcu;
-
- if (scene->adt == NULL || scene->adt->action == NULL) {
- return;
- }
-
- str_len = sequencer_rna_path_prefix(str, seq->name + 2);
-
- fcu = scene->adt->action->curves.first;
-
- while (fcu) {
- if (STREQLEN(fcu->rna_path, str, str_len)) {
- FCurve *next_fcu = fcu->next;
-
- BLI_remlink(&scene->adt->action->curves, fcu);
- BKE_fcurve_free(fcu);
-
- fcu = next_fcu;
- }
- else {
- fcu = fcu->next;
- }
- }
-}
-
-#undef SEQ_RNAPATH_MAXSTR
-
SequencerToolSettings *SEQ_tool_settings_copy(SequencerToolSettings *tool_settings)
{
SequencerToolSettings *tool_settings_copy = MEM_dupallocN(tool_settings);
@@ -1069,10 +925,6 @@ static bool seq_update_seq_cb(Sequence *seq, void *user_data)
return true;
}
-/* Evaluate parts of sequences which needs to be done as a part of a dependency graph evaluation.
- * This does NOT include actual rendering of the strips, but rather makes them up-to-date for
- * animation playback and makes them ready for the sequencer's rendering pipeline to render them.
- */
void SEQ_eval_sequences(Depsgraph *depsgraph, Scene *scene, ListBase *seqbase)
{
DEG_debug_print_eval(depsgraph, __func__, scene->id.name, scene);
diff --git a/source/blender/sequencer/intern/sequencer.h b/source/blender/sequencer/intern/sequencer.h
index e43535d14ee..2a82f966f02 100644
--- a/source/blender/sequencer/intern/sequencer.h
+++ b/source/blender/sequencer/intern/sequencer.h
@@ -29,11 +29,13 @@ extern "C" {
struct Scene;
struct Sequence;
-
-void seq_free_sequence_recurse(struct Scene *scene,
- struct Sequence *seq,
- const bool do_id_user,
- const bool do_clean_animdata);
+struct StripProxy;
+/**
+ * Cache must be freed before calling this function
+ * since it leaves the seqbase in an invalid state.
+ */
+void seq_free_sequence_recurse(struct Scene *scene, struct Sequence *seq, bool do_id_user);
+struct StripProxy *seq_strip_proxy_alloc(void);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/sound.c b/source/blender/sequencer/intern/sound.c
index c53aacddcfe..0788003fb12 100644
--- a/source/blender/sequencer/intern/sound.c
+++ b/source/blender/sequencer/intern/sound.c
@@ -31,6 +31,7 @@
#include "DNA_sound_types.h"
#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
#include "BKE_main.h"
#include "BKE_scene.h"
@@ -51,23 +52,27 @@ static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene,
for (seq = seqbase->first; seq; seq = seq->next) {
if (seq->type == SEQ_TYPE_META) {
if (sequencer_refresh_sound_length_recursive(bmain, scene, &seq->seqbase)) {
- SEQ_time_update_sequence(scene, seq);
+ SEQ_time_update_sequence(scene, seqbase, seq);
changed = true;
}
}
else if (seq->type == SEQ_TYPE_SOUND_RAM && seq->sound) {
- const float length = BKE_sound_get_length(bmain, seq->sound);
+ SoundInfo info;
+ if (!BKE_sound_info_get(bmain, seq->sound, &info)) {
+ continue;
+ }
+
int old = seq->len;
float fac;
- seq->len = (int)ceil((double)length * FPS);
+ seq->len = MAX2(1, round((info.length - seq->sound->offset_time) * FPS));
fac = (float)seq->len / (float)old;
old = seq->startofs;
seq->startofs *= fac;
seq->endofs *= fac;
seq->start += (old - seq->startofs); /* So that visual/"real" start frame does not change! */
- SEQ_time_update_sequence(scene, seq);
+ SEQ_time_update_sequence(scene, seqbase, seq);
changed = true;
}
}
@@ -111,12 +116,8 @@ void SEQ_sound_update_bounds(Scene *scene, Sequence *seq)
/* We have to take into account start frame of the sequence's scene! */
int startofs = seq->startofs + seq->anim_startofs + seq->scene->r.sfra;
- BKE_sound_move_scene_sound(scene,
- seq->scene_sound,
- seq->startdisp,
- seq->enddisp,
- startofs,
- seq->sound->offset_time);
+ BKE_sound_move_scene_sound(
+ scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs, 0.0);
}
}
else {
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index aa3f7c92dd8..f342765eec9 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -70,16 +70,6 @@
#include "proxy.h"
#include "utils.h"
-/**
- * Initialize common SeqLoadData members
- *
- * \param load_data: SeqLoadData to be initialized
- * \param name: strip name (can be NULL)
- * \param path: path to file that is used as strip input (can be NULL)
- * \param start_frame: timeline frame where strip will be created
- * \param channel: timeline channel where strip will be created
- *
- */
void SEQ_add_load_data_init(SeqLoadData *load_data,
const char *name,
const char *path,
@@ -100,7 +90,7 @@ void SEQ_add_load_data_init(SeqLoadData *load_data,
static void seq_add_generic_update(Scene *scene, ListBase *seqbase, Sequence *seq)
{
SEQ_sequence_base_unique_name_recursive(scene, &scene->ed->seqbase, seq);
- SEQ_time_update_sequence_bounds(scene, seq);
+ SEQ_time_update_sequence(scene, seqbase, seq);
SEQ_sort(seqbase);
SEQ_relations_invalidate_cache_composite(scene, seq);
}
@@ -147,19 +137,10 @@ static void seq_add_set_view_transform(Scene *scene, Sequence *seq, SeqLoadData
}
}
-/**
- * Add scene strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SCENE);
- seq->blend_mode = SEQ_TYPE_CROSS;
seq->scene = load_data->scene;
seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1;
id_us_ensure_real((ID *)load_data->scene);
@@ -168,19 +149,10 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat
return seq;
}
-/**
- * Add movieclip strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MOVIECLIP);
- seq->blend_mode = SEQ_TYPE_CROSS;
seq->clip = load_data->clip;
seq->len = BKE_movieclip_get_duration(load_data->clip);
id_us_ensure_real((ID *)load_data->clip);
@@ -189,19 +161,10 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa
return seq;
}
-/**
- * Add mask strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MASK);
- seq->blend_mode = SEQ_TYPE_CROSS;
seq->mask = load_data->mask;
seq->len = BKE_mask_get_duration(load_data->mask);
id_us_ensure_real((ID *)load_data->mask);
@@ -210,14 +173,6 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData
return seq;
}
-/**
- * Add effect strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
@@ -230,16 +185,7 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa
seq->seq2 = load_data->effect.seq2;
seq->seq3 = load_data->effect.seq3;
- if (seq->type == SEQ_TYPE_COLOR) {
- seq->blend_mode = SEQ_TYPE_CROSS;
- }
- else if (seq->type == SEQ_TYPE_ADJUSTMENT) {
- seq->blend_mode = SEQ_TYPE_CROSS;
- }
- else if (seq->type == SEQ_TYPE_TEXT) {
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
- }
- else if (SEQ_effect_get_num_inputs(seq->type) == 1) {
+ if (SEQ_effect_get_num_inputs(seq->type) == 1) {
seq->blend_mode = seq->seq1->blend_mode;
}
@@ -248,42 +194,23 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa
SEQ_transform_set_right_handle_frame(seq, load_data->effect.end_frame);
}
- SEQ_relations_update_changed_seq_and_deps(scene, seq, 1, 1); /* Runs SEQ_time_update_sequence. */
seq_add_set_name(scene, seq, load_data);
seq_add_generic_update(scene, seqbase, seq);
return seq;
}
-/**
- * Set directory used by image strip.
- *
- * \param seq: image strip to be changed
- * \param path: directory path
- */
void SEQ_add_image_set_directory(Sequence *seq, char *path)
{
BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
}
-/**
- * Set directory used by image strip.
- *
- * \param seq: image strip to be changed
- * \param strip_frame: frame index of strip to be changed
- * \param filename: image filename (only filename, not complete path)
- */
void SEQ_add_image_load_file(Sequence *seq, size_t strip_frame, char *filename)
{
StripElem *se = SEQ_render_give_stripelem(seq, seq->start + strip_frame);
BLI_strncpy(se->name, filename, sizeof(se->name));
}
-/**
- * Set image strip alpha mode
- *
- * \param seq: image strip to be changed
- */
void SEQ_add_image_init_alpha_mode(Sequence *seq)
{
if (seq->strip && seq->strip->stripdata) {
@@ -313,21 +240,10 @@ void SEQ_add_image_init_alpha_mode(Sequence *seq)
}
}
-/**
- * Add image strip.
- * NOTE: Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences
- *
- * \param main: Main reference
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_IMAGE);
- seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
seq->len = load_data->image.len;
Strip *strip = seq->strip;
strip->stripdata = MEM_callocN(load_data->image.len * sizeof(StripElem), "stripelem");
@@ -371,17 +287,6 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
}
#ifdef WITH_AUDASPACE
-/**
- * Add sound strip.
- * NOTE: Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences
- *
- * \param main: Main reference
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
-
Sequence *SEQ_add_sound_strip(Main *bmain,
Scene *scene,
ListBase *seqbase,
@@ -451,15 +356,6 @@ Sequence *SEQ_add_sound_strip(Main *UNUSED(bmain),
}
#endif // WITH_AUDASPACE
-/**
- * Add meta strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
-
Sequence *SEQ_add_meta_strip(Scene *scene, ListBase *seqbase, SeqLoadData *load_data)
{
/* Allocate sequence. */
@@ -472,20 +368,11 @@ Sequence *SEQ_add_meta_strip(Scene *scene, ListBase *seqbase, SeqLoadData *load_
/* Set frames start and length. */
seqm->start = load_data->start_frame;
seqm->len = 1;
- SEQ_time_update_sequence(scene, seqm);
+ SEQ_time_update_sequence(scene, seqbase, seqm);
return seqm;
}
-/**
- * Add movie strip.
- *
- * \param main: Main reference
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_movie_strip(
Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data, double *r_start_offset)
{
@@ -588,8 +475,6 @@ Sequence *SEQ_add_movie_strip(
}
}
- seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
-
if (anim_arr[0] != NULL) {
seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
@@ -624,7 +509,6 @@ Sequence *SEQ_add_movie_strip(
return seq;
}
-/* NOTE: caller should run SEQ_time_update_sequence(scene, seq) after. */
void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const bool lock_range)
{
char path[FILE_MAX];
@@ -644,7 +528,9 @@ void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const boo
if (lock_range) {
/* keep so we don't have to move the actual start and end points (only the data) */
- SEQ_time_update_sequence_bounds(scene, seq);
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+ SEQ_time_update_sequence(scene, seqbase, seq);
prev_startdisp = seq->startdisp;
prev_enddisp = seq->enddisp;
}
@@ -794,7 +680,9 @@ void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const boo
SEQ_transform_fix_single_image_seq_offsets(seq);
}
- SEQ_time_update_sequence(scene, seq);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SEQ_time_update_sequence(scene, seqbase, seq);
+ SEQ_relations_invalidate_cache_raw(scene, seq);
}
void SEQ_add_movie_reload_if_needed(struct Main *bmain,
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index cfac243e68f..0479d3012fa 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -43,6 +43,7 @@
#include "utils.h"
#include "SEQ_add.h"
+#include "SEQ_animation.h"
#include "SEQ_edit.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
@@ -175,7 +176,6 @@ static void sequencer_flag_users_for_removal(Scene *scene, ListBase *seqbase, Se
}
}
-/* Flag seq and its users (effects) for removal. */
void SEQ_edit_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
{
if (seq == NULL || (seq->flag & SEQ_FLAG_DELETE) != 0) {
@@ -193,7 +193,6 @@ void SEQ_edit_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
sequencer_flag_users_for_removal(scene, seqbase, seq);
}
-/* Remove all flagged sequences, return true if sequence is removed. */
void SEQ_edit_remove_flagged_sequences(Scene *scene, ListBase *seqbase)
{
LISTBASE_FOREACH_MUTABLE (Sequence *, seq, seqbase) {
@@ -201,8 +200,9 @@ void SEQ_edit_remove_flagged_sequences(Scene *scene, ListBase *seqbase)
if (seq->type == SEQ_TYPE_META) {
SEQ_edit_remove_flagged_sequences(scene, &seq->seqbase);
}
+ SEQ_free_animdata(scene, seq);
BLI_remlink(seqbase, seq);
- SEQ_sequence_free(scene, seq, true);
+ SEQ_sequence_free(scene, seq);
SEQ_sequence_lookup_tag(scene, SEQ_LOOKUP_TAG_INVALID);
}
}
@@ -221,6 +221,24 @@ static bool seq_exists_in_seqbase(Sequence *seq, ListBase *seqbase)
return false;
}
+bool SEQ_edit_move_strip_to_seqbase(Scene *scene,
+ ListBase *seqbase,
+ Sequence *seq,
+ ListBase *dst_seqbase)
+{
+ /* Move to meta. */
+ BLI_remlink(seqbase, seq);
+ BLI_addtail(dst_seqbase, seq);
+ SEQ_relations_invalidate_cache_preprocessed(scene, seq);
+
+ /* Update meta. */
+ if (SEQ_transform_test_overlap(dst_seqbase, seq)) {
+ SEQ_transform_seqbase_shuffle(dst_seqbase, seq, scene);
+ }
+
+ return true;
+}
+
bool SEQ_edit_move_strip_to_meta(Scene *scene,
Sequence *src_seq,
Sequence *dst_seqm,
@@ -262,16 +280,7 @@ bool SEQ_edit_move_strip_to_meta(Scene *scene,
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, collection) {
/* Move to meta. */
- BLI_remlink(seqbase, seq);
- BLI_addtail(&dst_seqm->seqbase, seq);
- SEQ_relations_invalidate_cache_preprocessed(scene, seq);
-
- /* Update meta. */
- SEQ_time_update_meta_strip_range(scene, dst_seqm);
- SEQ_time_update_sequence(scene, dst_seqm);
- if (SEQ_transform_test_overlap(&dst_seqm->seqbase, seq)) {
- SEQ_transform_seqbase_shuffle(&dst_seqm->seqbase, seq, scene);
- }
+ SEQ_edit_move_strip_to_seqbase(scene, seqbase, seq, &dst_seqm->seqbase);
}
SEQ_collection_free(collection);
@@ -359,6 +368,7 @@ static bool seq_edit_split_effect_intersect_check(const Sequence *seq, const int
static void seq_edit_split_handle_strip_offsets(Main *bmain,
Scene *scene,
+ ListBase *seqbase,
Sequence *left_seq,
Sequence *right_seq,
const int timeline_frame,
@@ -374,7 +384,7 @@ static void seq_edit_split_handle_strip_offsets(Main *bmain,
SEQ_add_reload_new_file(bmain, scene, right_seq, false);
break;
}
- SEQ_time_update_sequence(scene, right_seq);
+ SEQ_time_update_sequence(scene, seqbase, right_seq);
}
if (seq_edit_split_effect_intersect_check(left_seq, timeline_frame)) {
@@ -387,7 +397,7 @@ static void seq_edit_split_handle_strip_offsets(Main *bmain,
SEQ_add_reload_new_file(bmain, scene, left_seq, false);
break;
}
- SEQ_time_update_sequence(scene, left_seq);
+ SEQ_time_update_sequence(scene, seqbase, left_seq);
}
}
@@ -442,17 +452,6 @@ static bool seq_edit_split_operation_permitted_check(SeqCollection *strips,
return true;
}
-/**
- * Split Sequence at timeline_frame in two.
- *
- * \param bmain: Main in which Sequence is located
- * \param scene: Scene in which Sequence is located
- * \param seqbase: ListBase in which Sequence is located
- * \param seq: Sequence to be split
- * \param timeline_frame: frame at which seq is split.
- * \param method: affects type of offset to be applied to resize Sequence
- * \return The newly created sequence strip. This is always Sequence on right side.
- */
Sequence *SEQ_edit_strip_split(Main *bmain,
Scene *scene,
ListBase *seqbase,
@@ -492,54 +491,46 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
ListBase right_strips = {NULL, NULL};
SEQ_sequence_base_dupli_recursive(scene, scene, &right_strips, &left_strips, SEQ_DUPE_ALL, 0);
- /* Split strips. */
Sequence *left_seq = left_strips.first;
Sequence *right_seq = right_strips.first;
- Sequence *return_seq = right_strips.first;
+ Sequence *return_seq = NULL;
- /* Strips can't be tagged while in detached `seqbase`. Collect all strips which needs to be
- * deleted and delay tagging until they are moved back to `seqbase` in `Editing`. */
- SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
+ /* Move strips from detached `ListBase`, otherwise they can't be flagged for removal,
+ * SEQ_time_update_sequence can fail to update meta strips and they can't be renamed.
+ * This is because these functions check all strips in `Editing` to manage relationships. */
+ BLI_movelisttolist(seqbase, &left_strips);
+ BLI_movelisttolist(seqbase, &right_strips);
+ /* Split strips. */
while (left_seq && right_seq) {
if (left_seq->startdisp >= timeline_frame) {
- SEQ_collection_append_strip(left_seq, strips_to_delete);
+ SEQ_edit_flag_for_removal(scene, seqbase, left_seq);
}
if (right_seq->enddisp <= timeline_frame) {
- SEQ_collection_append_strip(right_seq, strips_to_delete);
+ SEQ_edit_flag_for_removal(scene, seqbase, right_seq);
+ }
+ else if (return_seq == NULL) {
+ /* Store return value - pointer to strip that will not be removed. */
+ return_seq = right_seq;
}
- seq_edit_split_handle_strip_offsets(bmain, scene, left_seq, right_seq, timeline_frame, method);
+ seq_edit_split_handle_strip_offsets(
+ bmain, scene, seqbase, left_seq, right_seq, timeline_frame, method);
left_seq = left_seq->next;
right_seq = right_seq->next;
}
- seq = right_strips.first;
- BLI_movelisttolist(seqbase, &left_strips);
- BLI_movelisttolist(seqbase, &right_strips);
+ SEQ_edit_remove_flagged_sequences(scene, seqbase);
- for (; seq; seq = seq->next) {
- SEQ_ensure_unique_name(seq, scene);
+ /* Rename duplicated strips. */
+ Sequence *seq_rename = return_seq;
+ for (; seq_rename; seq_rename = seq_rename->next) {
+ SEQ_ensure_unique_name(seq_rename, scene);
}
- Sequence *seq_delete;
- SEQ_ITERATOR_FOREACH (seq_delete, strips_to_delete) {
- SEQ_edit_flag_for_removal(scene, seqbase, seq_delete);
- }
- SEQ_edit_remove_flagged_sequences(scene, seqbase);
- SEQ_collection_free(strips_to_delete);
return return_seq;
}
-/**
- * Find gap after initial_frame and move strips on right side to close the gap
- *
- * \param scene: Scene in which strips are located
- * \param seqbase: ListBase in which strips are located
- * \param initial_frame: frame on timeline from where gaps are searched for
- * \param remove_all_gaps: remove all gaps instead of one gap
- * \return true if gap is removed, otherwise false
- */
bool SEQ_edit_remove_gaps(Scene *scene,
ListBase *seqbase,
const int initial_frame,
diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c
index 9822bfe38f9..7e7fc9e6bf7 100644
--- a/source/blender/sequencer/intern/strip_relations.c
+++ b/source/blender/sequencer/intern/strip_relations.c
@@ -29,6 +29,7 @@
#include "BLI_ghash.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
#include "BLI_session_uuid.h"
#include "BKE_main.h"
@@ -281,101 +282,44 @@ void SEQ_relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
}
}
-static bool update_changed_seq_recurs(
- Scene *scene, Sequence *seq, Sequence *changed_seq, int len_change, int ibuf_change)
+static void sequencer_all_free_anim_ibufs(Editing *ed,
+ ListBase *seqbase,
+ int timeline_frame,
+ const int frame_range[2])
{
- Sequence *subseq;
- bool free_imbuf = false;
-
- /* recurse downwards to see if this seq depends on the changed seq */
-
- if (seq == NULL) {
- return false;
- }
-
- if (seq == changed_seq) {
- free_imbuf = true;
- }
-
- for (subseq = seq->seqbase.first; subseq; subseq = subseq->next) {
- if (update_changed_seq_recurs(scene, subseq, changed_seq, len_change, ibuf_change)) {
- free_imbuf = true;
- }
- }
-
- if (seq->seq1) {
- if (update_changed_seq_recurs(scene, seq->seq1, changed_seq, len_change, ibuf_change)) {
- free_imbuf = true;
- }
- }
- if (seq->seq2 && (seq->seq2 != seq->seq1)) {
- if (update_changed_seq_recurs(scene, seq->seq2, changed_seq, len_change, ibuf_change)) {
- free_imbuf = true;
- }
- }
- if (seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2)) {
- if (update_changed_seq_recurs(scene, seq->seq3, changed_seq, len_change, ibuf_change)) {
- free_imbuf = true;
+ for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
+ if (!SEQ_time_strip_intersects_frame(seq, timeline_frame) ||
+ !((frame_range[0] <= timeline_frame) && (frame_range[1] > timeline_frame))) {
+ SEQ_relations_sequence_free_anim(seq);
}
- }
+ if (seq->type == SEQ_TYPE_META) {
+ int meta_range[2];
- if (free_imbuf) {
- if (ibuf_change) {
- if (seq->type == SEQ_TYPE_MOVIE) {
- SEQ_relations_sequence_free_anim(seq);
+ MetaStack *ms = SEQ_meta_stack_active_get(ed);
+ if (ms != NULL && ms->parseq == seq) {
+ meta_range[0] = -MAXFRAME;
+ meta_range[1] = MAXFRAME;
}
- else if (seq->type == SEQ_TYPE_SPEED) {
- seq_effect_speed_rebuild_map(scene, seq);
+ else {
+ /* Limit frame range to meta strip. */
+ meta_range[0] = max_ii(frame_range[0], seq->startdisp);
+ meta_range[1] = min_ii(frame_range[1], seq->enddisp);
}
- }
- if (len_change) {
- SEQ_time_update_sequence(scene, seq);
+ sequencer_all_free_anim_ibufs(ed, &seq->seqbase, timeline_frame, meta_range);
}
}
-
- return free_imbuf;
-}
-
-void SEQ_relations_update_changed_seq_and_deps(Scene *scene,
- Sequence *changed_seq,
- int len_change,
- int ibuf_change)
-{
- Editing *ed = SEQ_editing_get(scene);
- Sequence *seq;
-
- if (ed == NULL) {
- return;
- }
-
- for (seq = ed->seqbase.first; seq; seq = seq->next) {
- update_changed_seq_recurs(scene, seq, changed_seq, len_change, ibuf_change);
- }
}
-/* Unused */
-static void sequencer_all_free_anim_ibufs(ListBase *seqbase, int timeline_frame)
-{
- for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
- if (!SEQ_time_strip_intersects_frame(seq, timeline_frame)) {
- SEQ_relations_sequence_free_anim(seq);
- }
- if (seq->type == SEQ_TYPE_META) {
- sequencer_all_free_anim_ibufs(&seq->seqbase, timeline_frame);
- }
- }
-}
-
-/* Unused */
void SEQ_relations_free_all_anim_ibufs(Scene *scene, int timeline_frame)
{
Editing *ed = SEQ_editing_get(scene);
if (ed == NULL) {
return;
}
- sequencer_all_free_anim_ibufs(&ed->seqbase, timeline_frame);
- SEQ_cache_cleanup(scene);
+
+ const int frame_range[2] = {-MAXFRAME, MAXFRAME};
+ sequencer_all_free_anim_ibufs(ed, &ed->seqbase, timeline_frame, frame_range);
}
static Sequence *sequencer_check_scene_recursion(Scene *scene, ListBase *seqbase)
@@ -428,7 +372,6 @@ bool SEQ_relations_check_scene_recursion(Scene *scene, ReportList *reports)
return false;
}
-/* Check if "seq_main" (indirectly) uses strip "seq". */
bool SEQ_relations_render_loop_check(Sequence *seq_main, Sequence *seq)
{
if (seq_main == NULL || seq == NULL) {
@@ -455,7 +398,6 @@ bool SEQ_relations_render_loop_check(Sequence *seq_main, Sequence *seq)
return false;
}
-/* Function to free imbuf and anim data on changes */
void SEQ_relations_sequence_free_anim(Sequence *seq)
{
while (seq->anims.last) {
@@ -508,7 +450,6 @@ void SEQ_relations_check_uuids_unique_and_report(const Scene *scene)
BLI_gset_free(used_uuids, NULL);
}
-/* Return immediate parent meta of sequence */
struct Sequence *SEQ_find_metastrip_by_sequence(ListBase *seqbase, Sequence *meta, Sequence *seq)
{
Sequence *iseq;
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index fd6c0805c23..31ee20cb6ca 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -131,12 +131,17 @@ static void seq_update_sound_bounds_recursive_impl(Scene *scene,
endofs = seq->start + seq->len - end;
}
+ double offset_time = 0.0f;
+ if (seq->sound != NULL) {
+ offset_time = seq->sound->offset_time;
+ }
+
BKE_sound_move_scene_sound(scene,
seq->scene_sound,
seq->start + startofs,
seq->start + seq->len - endofs,
startofs + seq->anim_startofs,
- seq->sound->offset_time);
+ offset_time);
}
}
}
@@ -148,7 +153,7 @@ void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq)
scene, metaseq, metaseq_start(metaseq), metaseq_end(metaseq));
}
-void SEQ_time_update_sequence_bounds(Scene *scene, Sequence *seq)
+static void seq_time_update_sequence_bounds(Scene *scene, Sequence *seq)
{
if (seq->startofs && seq->startstill) {
seq->startstill = 0;
@@ -188,6 +193,10 @@ static void seq_time_update_meta_strip(Scene *scene, Sequence *seq_meta)
void SEQ_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta)
{
+ if (seq_meta == NULL) {
+ return;
+ }
+
seq_time_update_meta_strip(scene, seq_meta);
/* Prevent meta-strip to move in timeline. */
@@ -195,7 +204,7 @@ void SEQ_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta)
SEQ_transform_set_right_handle_frame(seq_meta, seq_meta->enddisp);
}
-void SEQ_time_update_sequence(Scene *scene, Sequence *seq)
+void SEQ_time_update_sequence(Scene *scene, ListBase *seqbase, Sequence *seq)
{
Sequence *seqm;
@@ -203,7 +212,7 @@ void SEQ_time_update_sequence(Scene *scene, Sequence *seq)
seqm = seq->seqbase.first;
while (seqm) {
if (seqm->seqbase.first) {
- SEQ_time_update_sequence(scene, seqm);
+ SEQ_time_update_sequence(scene, &seqm->seqbase, seqm);
}
seqm = seqm->next;
}
@@ -241,21 +250,83 @@ void SEQ_time_update_sequence(Scene *scene, Sequence *seq)
seq->len = seq->enddisp - seq->startdisp;
}
else {
- SEQ_time_update_sequence_bounds(scene, seq);
+ seq_time_update_sequence_bounds(scene, seq);
}
}
+ else if (seq->type == SEQ_TYPE_META) {
+ seq_time_update_meta_strip(scene, seq);
+ }
else {
- if (seq->type == SEQ_TYPE_META) {
- seq_time_update_meta_strip(scene, seq);
+ seq_time_update_sequence_bounds(scene, seq);
+ }
+
+ Editing *ed = SEQ_editing_get(scene);
+
+ /* Strip is inside meta strip */
+ if (seqbase != &ed->seqbase) {
+ Sequence *meta = SEQ_get_meta_by_seqbase(&ed->seqbase, seqbase);
+ SEQ_time_update_meta_strip_range(scene, meta);
+ }
+
+ seq_time_update_sequence_bounds(scene, seq);
+}
+
+static bool update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *changed_seq)
+{
+ Sequence *subseq;
+ bool do_update = false;
+
+ /* recurse downwards to see if this seq depends on the changed seq */
+
+ if (seq == NULL) {
+ return false;
+ }
+
+ if (seq == changed_seq) {
+ do_update = true;
+ }
+
+ for (subseq = seq->seqbase.first; subseq; subseq = subseq->next) {
+ if (update_changed_seq_recurs(scene, subseq, changed_seq)) {
+ do_update = true;
}
+ }
- Editing *ed = SEQ_editing_get(scene);
- MetaStack *ms = SEQ_meta_stack_active_get(ed);
- if (ms != NULL) {
- SEQ_time_update_meta_strip_range(scene, ms->parseq);
+ if (seq->seq1) {
+ if (update_changed_seq_recurs(scene, seq->seq1, changed_seq)) {
+ do_update = true;
+ }
+ }
+ if (seq->seq2 && (seq->seq2 != seq->seq1)) {
+ if (update_changed_seq_recurs(scene, seq->seq2, changed_seq)) {
+ do_update = true;
+ }
+ }
+ if (seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2)) {
+ if (update_changed_seq_recurs(scene, seq->seq3, changed_seq)) {
+ do_update = true;
}
+ }
+
+ if (do_update) {
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SEQ_time_update_sequence(scene, seqbase, seq);
+ }
+
+ return do_update;
+}
+
+void SEQ_time_update_recursive(Scene *scene, Sequence *changed_seq)
+{
+ Editing *ed = SEQ_editing_get(scene);
+ Sequence *seq;
+
+ if (ed == NULL) {
+ return;
+ }
- SEQ_time_update_sequence_bounds(scene, seq);
+ for (seq = ed->seqbase.first; seq; seq = seq->next) {
+ update_changed_seq_recurs(scene, seq, changed_seq);
}
}
@@ -367,20 +438,16 @@ float SEQ_time_sequence_get_fps(Scene *scene, Sequence *seq)
return 0.0f;
}
-/**
- * Define boundary rectangle of sequencer timeline and fill in rect data
- *
- * \param scene: Scene in which strips are located
- * \param seqbase: ListBase in which strips are located
- * \param rect: data structure describing rectangle, that will be filled in by this function
- */
-void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
+void SEQ_timeline_init_boundbox(const Scene *scene, rctf *rect)
{
rect->xmin = scene->r.sfra;
rect->xmax = scene->r.efra + 1;
rect->ymin = 0.0f;
rect->ymax = 8.0f;
+}
+void SEQ_timeline_expand_boundbox(const ListBase *seqbase, rctf *rect)
+{
if (seqbase == NULL) {
return;
}
@@ -398,6 +465,12 @@ void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *re
}
}
+void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
+{
+ SEQ_timeline_init_boundbox(scene, rect);
+ SEQ_timeline_expand_boundbox(seqbase, rect);
+}
+
static bool strip_exists_at_frame(SeqCollection *all_strips, const int timeline_frame)
{
Sequence *seq;
@@ -409,14 +482,6 @@ static bool strip_exists_at_frame(SeqCollection *all_strips, const int timeline_
return false;
}
-/**
- * Find first gap between strips after initial_frame and describe it by filling data of r_gap_info
- *
- * \param scene: Scene in which strips are located
- * \param seqbase: ListBase in which strips are located
- * \param initial_frame: frame on timeline from where gaps are searched for
- * \param r_gap_info: data structure describing gap, that will be filled in by this function
- */
void seq_time_gap_info_get(const Scene *scene,
ListBase *seqbase,
const int initial_frame,
@@ -462,15 +527,6 @@ void seq_time_gap_info_get(const Scene *scene,
}
}
-/**
- * Test if strip intersects with timeline frame.
- * NOTE: This checks if strip would be rendered at this frame. For rendering it is assumed, that
- * timeline frame has width of 1 frame and therefore ends at timeline_frame + 1
- *
- * \param seq: Sequence to be checked
- * \param timeline_frame: absolute frame position
- * \return true if strip intersects with timeline frame.
- */
bool SEQ_time_strip_intersects_frame(const Sequence *seq, const int timeline_frame)
{
return (seq->startdisp <= timeline_frame) && (seq->enddisp > timeline_frame);
diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h
index ca9a935bc96..4fe8d03e641 100644
--- a/source/blender/sequencer/intern/strip_time.h
+++ b/source/blender/sequencer/intern/strip_time.h
@@ -40,9 +40,18 @@ typedef struct GapInfo {
int gap_length; /* Length of the gap. */
bool gap_exists; /* False if there are no gaps. */
} GapInfo;
+
+/**
+ * Find first gap between strips after initial_frame and describe it by filling data of r_gap_info
+ *
+ * \param scene: Scene in which strips are located.
+ * \param seqbase: ListBase in which strips are located.
+ * \param initial_frame: frame on timeline from where gaps are searched for.
+ * \param r_gap_info: data structure describing gap, that will be filled in by this function.
+ */
void seq_time_gap_info_get(const struct Scene *scene,
struct ListBase *seqbase,
- const int initial_frame,
+ int initial_frame,
struct GapInfo *r_gap_info);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index 54ca4ef487f..432fc1c166f 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -33,6 +33,7 @@
#include "BKE_scene.h"
#include "BKE_sound.h"
+#include "SEQ_animation.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
#include "SEQ_relations.h"
@@ -86,8 +87,6 @@ void SEQ_transform_set_right_handle_frame(Sequence *seq, int val)
}
}
-/* used so we can do a quick check for single image seq
- * since they work a bit differently to normal image seq's (during transform) */
bool SEQ_transform_single_image_check(Sequence *seq)
{
return ((seq->len == 1) &&
@@ -95,7 +94,6 @@ bool SEQ_transform_single_image_check(Sequence *seq)
((seq->type & SEQ_TYPE_EFFECT) && SEQ_effect_get_num_inputs(seq->type) == 0)));
}
-/* check if the selected seq's reference unselected seq's */
bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase)
{
Sequence *seq;
@@ -137,10 +135,6 @@ bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase)
return true;
}
-/**
- * Use to impose limits when dragging/extending - so impossible situations don't happen.
- * Can't use the #SEQ_LEFTSEL and #SEQ_LEFTSEL directly because the strip may be in a meta-strip.
- */
void SEQ_transform_handle_xlimits(Sequence *seq, int leftflag, int rightflag)
{
if (leftflag) {
@@ -253,10 +247,10 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt
SEQ_transform_set_right_handle_frame(seq, seq->enddisp + delta);
}
- SEQ_time_update_sequence(evil_scene, seq);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(evil_scene));
+ SEQ_time_update_sequence(evil_scene, seqbase, seq);
}
-/* return 0 if there weren't enough space */
bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep,
Sequence *test,
Scene *evil_scene,
@@ -266,7 +260,7 @@ bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep,
BLI_assert(ELEM(channel_delta, -1, 1));
test->machine += channel_delta;
- SEQ_time_update_sequence(evil_scene, test);
+ SEQ_time_update_sequence(evil_scene, seqbasep, test);
while (SEQ_transform_test_overlap(seqbasep, test)) {
if ((channel_delta > 0) ? (test->machine >= MAXSEQ) : (test->machine < 1)) {
break;
@@ -275,7 +269,7 @@ bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep,
test->machine += channel_delta;
/* XXX: I don't think this is needed since were only moving vertically, Campbell. */
- SEQ_time_update_sequence(evil_scene, test);
+ SEQ_time_update_sequence(evil_scene, seqbasep, test);
}
if (!SEQ_valid_strip_channel(test)) {
@@ -295,7 +289,7 @@ bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep,
new_frame = new_frame + (test->start - test->startdisp); /* adjust by the startdisp */
SEQ_transform_translate_sequence(evil_scene, test, new_frame - test->start);
- SEQ_time_update_sequence(evil_scene, test);
+ SEQ_time_update_sequence(evil_scene, seqbasep, test);
return false;
}
@@ -355,7 +349,7 @@ static int shuffle_seq_time_offset(SeqCollection *strips_to_shuffle,
}
SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
- SEQ_time_update_sequence_bounds(scene, seq); /* corrects dummy startdisp/enddisp values */
+ SEQ_time_update_sequence(scene, seqbasep, seq); /* corrects dummy startdisp/enddisp values */
}
return tot_ofs;
@@ -392,14 +386,6 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
return offset ? false : true;
}
-/**
- * Move strips and markers (if not locked) that start after timeline_frame by delta frames
- *
- * \param scene: Scene in which strips are located
- * \param seqbase: ListBase in which strips are located
- * \param delta: offset in frames to be applied
- * \param timeline_frame: frame on timeline from where strips are moved
- */
void SEQ_transform_offset_after_frame(Scene *scene,
ListBase *seqbase,
const int delta,
@@ -408,7 +394,7 @@ void SEQ_transform_offset_after_frame(Scene *scene,
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
if (seq->startdisp >= timeline_frame) {
SEQ_transform_translate_sequence(scene, seq, delta);
- SEQ_time_update_sequence(scene, seq);
+ SEQ_time_update_sequence(scene, seqbase, seq);
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
}
}
@@ -435,14 +421,6 @@ void SEQ_image_transform_mirror_factor_get(const Sequence *seq, float r_mirror[2
}
}
-/**
- * Get strip transform origin offset from image center
- * Note: This function does not apply axis mirror.
- *
- * \param scene: Scene in which strips are located
- * \param seq: Sequence to calculate image transform origin
- * \param r_origin: return value
- */
void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene,
const Sequence *seq,
float r_origin[2])
@@ -462,60 +440,89 @@ void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene,
r_origin[0] = (image_size[0] * transform->origin[0]) - (image_size[0] * 0.5f) + transform->xofs;
r_origin[1] = (image_size[1] * transform->origin[1]) - (image_size[1] * 0.5f) + transform->yofs;
+ const float viewport_pixel_aspect[2] = {scene->r.xasp / scene->r.yasp, 1.0f};
float mirror[2];
SEQ_image_transform_mirror_factor_get(seq, mirror);
mul_v2_v2(r_origin, mirror);
+ mul_v2_v2(r_origin, viewport_pixel_aspect);
}
-/**
- * Get strip transform origin offset from image center
- *
- * \param scene: Scene in which strips are located
- * \param seq: Sequence to calculate image transform origin
- * \param r_origin: return value
- */
-
-void SEQ_image_transform_final_quad_get(const Scene *scene,
- const Sequence *seq,
- float r_quad[4][2])
+static void seq_image_transform_quad_get_ex(const Scene *scene,
+ const Sequence *seq,
+ bool apply_rotation,
+ float r_quad[4][2])
{
StripTransform *transform = seq->strip->transform;
StripCrop *crop = seq->strip->crop;
- int imgage_size[2] = {scene->r.xsch, scene->r.ysch};
+ int image_size[2] = {scene->r.xsch, scene->r.ysch};
if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) {
- imgage_size[0] = seq->strip->stripdata->orig_width;
- imgage_size[1] = seq->strip->stripdata->orig_height;
+ image_size[0] = seq->strip->stripdata->orig_width;
+ image_size[1] = seq->strip->stripdata->orig_height;
+ }
+
+ float transform_matrix[4][4];
+ float rotation_matrix[3][3];
+ axis_angle_to_mat3_single(rotation_matrix, 'Z', apply_rotation ? transform->rotation : 0.0f);
+ loc_rot_size_to_mat4(transform_matrix,
+ (const float[]){transform->xofs, transform->yofs, 0.0f},
+ rotation_matrix,
+ (const float[]){transform->scale_x, transform->scale_y, 1.0f});
+ const float origin[2] = {image_size[0] * transform->origin[0],
+ image_size[1] * transform->origin[1]};
+ const float pivot[3] = {origin[0] - (image_size[0] / 2), origin[1] - (image_size[1] / 2), 0.0f};
+ transform_pivot_set_m4(transform_matrix, pivot);
+
+ float quad_temp[4][3];
+ for (int i = 0; i < 4; i++) {
+ zero_v2(quad_temp[i]);
}
- float transform_matrix[3][3];
- loc_rot_size_to_mat3(transform_matrix,
- (const float[]){transform->xofs, transform->yofs},
- transform->rotation,
- (const float[]){transform->scale_x, transform->scale_y});
- const float origin[2] = {imgage_size[0] * transform->origin[0],
- imgage_size[1] * transform->origin[1]};
- const float pivot[2] = {origin[0] - (imgage_size[0] / 2), origin[1] - (imgage_size[1] / 2)};
- transform_pivot_set_m3(transform_matrix, pivot);
-
- r_quad[0][0] = (imgage_size[0] / 2) - crop->right;
- r_quad[0][1] = (imgage_size[1] / 2) - crop->top;
- r_quad[1][0] = (imgage_size[0] / 2) - crop->right;
- r_quad[1][1] = (-imgage_size[1] / 2) + crop->bottom;
- r_quad[2][0] = (-imgage_size[0] / 2) + crop->left;
- r_quad[2][1] = (-imgage_size[1] / 2) + crop->bottom;
- r_quad[3][0] = (-imgage_size[0] / 2) + crop->left;
- r_quad[3][1] = (imgage_size[1] / 2) - crop->top;
-
- mul_m3_v2(transform_matrix, r_quad[0]);
- mul_m3_v2(transform_matrix, r_quad[1]);
- mul_m3_v2(transform_matrix, r_quad[2]);
- mul_m3_v2(transform_matrix, r_quad[3]);
+ quad_temp[0][0] = (image_size[0] / 2) - crop->right;
+ quad_temp[0][1] = (image_size[1] / 2) - crop->top;
+ quad_temp[1][0] = (image_size[0] / 2) - crop->right;
+ quad_temp[1][1] = (-image_size[1] / 2) + crop->bottom;
+ quad_temp[2][0] = (-image_size[0] / 2) + crop->left;
+ quad_temp[2][1] = (-image_size[1] / 2) + crop->bottom;
+ quad_temp[3][0] = (-image_size[0] / 2) + crop->left;
+ quad_temp[3][1] = (image_size[1] / 2) - crop->top;
float mirror[2];
SEQ_image_transform_mirror_factor_get(seq, mirror);
- mul_v2_v2(r_quad[0], mirror);
- mul_v2_v2(r_quad[1], mirror);
- mul_v2_v2(r_quad[2], mirror);
- mul_v2_v2(r_quad[3], mirror);
+
+ const float viewport_pixel_aspect[2] = {scene->r.xasp / scene->r.yasp, 1.0f};
+
+ for (int i = 0; i < 4; i++) {
+ mul_m4_v3(transform_matrix, quad_temp[i]);
+ mul_v2_v2(quad_temp[i], mirror);
+ mul_v2_v2(quad_temp[i], viewport_pixel_aspect);
+ copy_v2_v2(r_quad[i], quad_temp[i]);
+ }
+}
+
+void SEQ_image_transform_quad_get(const Scene *scene,
+ const Sequence *seq,
+ bool apply_rotation,
+ float r_quad[4][2])
+{
+ seq_image_transform_quad_get_ex(scene, seq, apply_rotation, r_quad);
+}
+
+void SEQ_image_transform_final_quad_get(const Scene *scene,
+ const Sequence *seq,
+ float r_quad[4][2])
+{
+ seq_image_transform_quad_get_ex(scene, seq, true, r_quad);
+}
+
+void SEQ_image_preview_unit_to_px(const Scene *scene, const float co_src[2], float co_dst[2])
+{
+ co_dst[0] = co_src[0] * scene->r.xsch;
+ co_dst[1] = co_src[1] * scene->r.ysch;
+}
+
+void SEQ_image_preview_unit_from_px(const Scene *scene, const float co_src[2], float co_dst[2])
+{
+ co_dst[0] = co_src[0] / scene->r.xsch;
+ co_dst[1] = co_src[1] / scene->r.ysch;
}
diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c
index 8421aab5217..140aa2d67c5 100644
--- a/source/blender/sequencer/intern/utils.c
+++ b/source/blender/sequencer/intern/utils.c
@@ -35,10 +35,12 @@
#include "BLI_blenlib.h"
+#include "BKE_animsys.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_scene.h"
+#include "SEQ_animation.h"
#include "SEQ_edit.h"
#include "SEQ_iterator.h"
#include "SEQ_relations.h"
@@ -55,13 +57,6 @@
#include "proxy.h"
#include "utils.h"
-/**
- * Sort strips in provided seqbase. Effect strips are trailing the list and they are sorted by
- * channel position as well.
- * This is important for SEQ_time_update_sequence to work properly
- *
- * \param seqbase: ListBase with strips
- */
void SEQ_sort(ListBase *seqbase)
{
if (seqbase == NULL) {
@@ -432,7 +427,6 @@ const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame)
return best_seq;
}
-/* in cases where we don't know the sequence's listbase */
ListBase *SEQ_get_seqbase_by_seq(ListBase *seqbase, Sequence *seq)
{
Sequence *iseq;
@@ -450,10 +444,21 @@ ListBase *SEQ_get_seqbase_by_seq(ListBase *seqbase, Sequence *seq)
return NULL;
}
-/**
- * Only use as last resort when the StripElem is available but no the Sequence.
- * (needed for RNA)
- */
+Sequence *SEQ_get_meta_by_seqbase(ListBase *seqbase_main, ListBase *meta_seqbase)
+{
+ SeqCollection *strips = SEQ_query_all_strips_recursive(seqbase_main);
+
+ Sequence *seq = NULL;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
+ if (seq->type == SEQ_TYPE_META && &seq->seqbase == meta_seqbase) {
+ break;
+ }
+ }
+
+ SEQ_collection_free(strips);
+ return seq;
+}
+
Sequence *SEQ_sequence_from_strip_elem(ListBase *seqbase, StripElem *se)
{
Sequence *iseq;
@@ -510,10 +515,10 @@ void SEQ_alpha_mode_from_file_extension(Sequence *seq)
}
}
-/* called on draw, needs to be fast,
- * we could cache and use a flag if we want to make checks for file paths resolving for eg. */
bool SEQ_sequence_has_source(const Sequence *seq)
{
+ /* Called on draw, needs to be fast,
+ * we could cache and use a flag if we want to make checks for file paths resolving for eg. */
switch (seq->type) {
case SEQ_TYPE_MASK:
return (seq->mask != NULL);
@@ -574,20 +579,14 @@ void SEQ_set_scale_to_fit(const Sequence *seq,
}
}
-/**
- * Ensure, that provided Sequence has unique name. If animation data exists for this Sequence, it
- * will be duplicated and mapped onto new name
- *
- * \param seq: Sequence which name will be ensured to be unique
- * \param scene: Scene in which name must be unique
- */
void SEQ_ensure_unique_name(Sequence *seq, Scene *scene)
{
char name[SEQ_NAME_MAXSTR];
BLI_strncpy_utf8(name, seq->name + 2, sizeof(name));
SEQ_sequence_base_unique_name_recursive(scene, &scene->ed->seqbase, seq);
- SEQ_dupe_animdata(scene, name, seq->name + 2);
+ BKE_animdata_fix_paths_rename(
+ &scene->id, scene->adt, NULL, "sequence_editor.sequences_all", name, seq->name + 2, 0, 0, 0);
if (seq->type == SEQ_TYPE_META) {
LISTBASE_FOREACH (Sequence *, seq_child, &seq->seqbase) {
diff --git a/source/blender/sequencer/intern/utils.h b/source/blender/sequencer/intern/utils.h
index 7aee7d229c9..b5aa66804c6 100644
--- a/source/blender/sequencer/intern/utils.h
+++ b/source/blender/sequencer/intern/utils.h
@@ -27,10 +27,13 @@
extern "C" {
#endif
+struct ListBase;
struct Scene;
bool sequencer_seq_generates_image(struct Sequence *seq);
void seq_open_anim_file(struct Scene *scene, struct Sequence *seq, bool openfile);
+Sequence *SEQ_get_meta_by_seqbase(struct ListBase *seqbase_main, struct ListBase *meta_seqbase);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/shader_fx/intern/FX_ui_common.c b/source/blender/shader_fx/intern/FX_ui_common.c
index 8cb1ea6b66c..314aafd6b70 100644
--- a/source/blender/shader_fx/intern/FX_ui_common.c
+++ b/source/blender/shader_fx/intern/FX_ui_common.c
@@ -93,21 +93,15 @@ static void set_shaderfx_expand_flag(const bContext *UNUSED(C), Panel *panel, sh
/** \name ShaderFx Panel Layouts
* \{ */
-/**
- * Draw shaderfx error message.
- */
void shaderfx_panel_end(uiLayout *layout, PointerRNA *ptr)
{
ShaderFxData *fx = ptr->data;
if (fx->error) {
uiLayout *row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_(fx->error), ICON_ERROR);
+ uiItemL(row, TIP_(fx->error), ICON_ERROR);
}
}
-/**
- * Gets RNA pointers for the active object and the panel's shaderfx data.
- */
PointerRNA *shaderfx_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
{
PointerRNA *ptr = UI_panel_custom_data_get(panel);
@@ -117,7 +111,7 @@ PointerRNA *shaderfx_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_
RNA_pointer_create(ptr->owner_id, &RNA_Object, ptr->owner_id, r_ob_ptr);
}
- uiLayoutSetContextPointer(panel->layout, "shaderfx", ptr);
+ UI_panel_context_pointer_set(panel, "shaderfx", ptr);
return ptr;
}
@@ -236,9 +230,6 @@ static bool shaderfx_ui_poll(const bContext *C, PanelType *UNUSED(pt))
return (ob != NULL) && (ob->type == OB_GPENCIL);
}
-/**
- * Create a panel in the context's region
- */
PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type, PanelDrawFn draw)
{
PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
@@ -254,7 +245,7 @@ PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type,
/* Give the panel the special flag that says it was built here and corresponds to a
* shader effect rather than a PanelType. */
- panel_type->flag = PANEL_TYPE_HEADER_EXPAND | PANEL_TYPE_DRAW_BOX | PANEL_TYPE_INSTANCED;
+ panel_type->flag = PANEL_TYPE_HEADER_EXPAND | PANEL_TYPE_INSTANCED;
panel_type->reorder = shaderfx_reorder;
panel_type->get_list_data_expand_flag = get_shaderfx_expand_flag;
panel_type->set_list_data_expand_flag = set_shaderfx_expand_flag;
@@ -264,12 +255,6 @@ PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type,
return panel_type;
}
-/**
- * Add a child panel to the parent.
- *
- * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
- * idname.
- */
PanelType *shaderfx_subpanel_register(ARegionType *region_type,
const char *name,
const char *label,
@@ -287,7 +272,7 @@ PanelType *shaderfx_subpanel_register(ARegionType *region_type,
panel_type->draw_header = draw_header;
panel_type->draw = draw;
panel_type->poll = shaderfx_ui_poll;
- panel_type->flag = (PANEL_TYPE_DEFAULT_CLOSED | PANEL_TYPE_DRAW_BOX);
+ panel_type->flag = PANEL_TYPE_DEFAULT_CLOSED;
BLI_assert(parent != NULL);
BLI_strncpy(panel_type->parent_id, parent->idname, BKE_ST_MAXNAME);
diff --git a/source/blender/shader_fx/intern/FX_ui_common.h b/source/blender/shader_fx/intern/FX_ui_common.h
index 151a2d31eb8..04982b9c0cf 100644
--- a/source/blender/shader_fx/intern/FX_ui_common.h
+++ b/source/blender/shader_fx/intern/FX_ui_common.h
@@ -32,13 +32,28 @@ struct bContext;
struct uiLayout;
typedef void (*PanelDrawFn)(const bContext *, Panel *);
+/**
+ * Draw shaderfx error message.
+ */
void shaderfx_panel_end(struct uiLayout *layout, PointerRNA *ptr);
+/**
+ * Gets RNA pointers for the active object and the panel's shaderfx data.
+ */
struct PointerRNA *shaderfx_panel_get_property_pointers(struct Panel *panel,
struct PointerRNA *r_ob_ptr);
+/**
+ * Create a panel in the context's region
+ */
PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type, PanelDrawFn draw);
+/**
+ * Add a child panel to the parent.
+ *
+ * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
+ * idname.
+ */
struct PanelType *shaderfx_subpanel_register(struct ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/simulation/intern/ConstrainedConjugateGradient.h b/source/blender/simulation/intern/ConstrainedConjugateGradient.h
index c5a2827a09f..d4d6057cd4c 100644
--- a/source/blender/simulation/intern/ConstrainedConjugateGradient.h
+++ b/source/blender/simulation/intern/ConstrainedConjugateGradient.h
@@ -164,13 +164,13 @@ struct traits<
* \brief A conjugate gradient solver for sparse self-adjoint problems with additional constraints
*
* This class allows to solve for A.x = b sparse linear problems using a conjugate gradient
- * algorithm. The sparse matrix A must be selfadjoint. The vectors x and b can be either dense or
+ * algorithm. The sparse matrix A must be self-adjoint. The vectors x and b can be either dense or
* sparse.
*
- * \tparam _MatrixType the type of the sparse matrix A, can be a dense or a sparse matrix.
- * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
+ * \tparam _MatrixType: the type of the sparse matrix A, can be a dense or a sparse matrix.
+ * \tparam _UpLo: the triangular part that will be used for the computations. It can be Lower
* or Upper. Default is Lower.
- * \tparam _Preconditioner the type of the preconditioner. Default is DiagonalPreconditioner
+ * \tparam _Preconditioner: the type of the pre-conditioner. Default is #DiagonalPreconditioner
*
* The maximal number of iterations and tolerance value can be controlled via the
* setMaxIterations() and setTolerance() methods. The defaults are the size of the problem for the
diff --git a/source/blender/simulation/intern/SIM_mass_spring.cpp b/source/blender/simulation/intern/SIM_mass_spring.cpp
index f9a22276363..73b287b4233 100644
--- a/source/blender/simulation/intern/SIM_mass_spring.cpp
+++ b/source/blender/simulation/intern/SIM_mass_spring.cpp
@@ -625,7 +625,7 @@ static void cloth_calc_force(
}
#endif
- /* cloth_calc_volume_force(clmd); */
+ // cloth_calc_volume_force(clmd);
#ifdef CLOTH_FORCE_DRAG
SIM_mass_spring_force_drag(data, drag);
@@ -1295,8 +1295,7 @@ int SIM_cloth_solve(
BKE_sim_debug_data_clear_category("collision");
if (!clmd->solver_result) {
- clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult),
- "cloth solver result");
+ clmd->solver_result = MEM_cnew<ClothSolverResult>("cloth solver result");
}
cloth_clear_result(clmd);
diff --git a/source/blender/simulation/intern/hair_volume.cpp b/source/blender/simulation/intern/hair_volume.cpp
index 348c8683be9..f9b61fe9942 100644
--- a/source/blender/simulation/intern/hair_volume.cpp
+++ b/source/blender/simulation/intern/hair_volume.cpp
@@ -633,9 +633,6 @@ BLI_INLINE void hair_volume_eval_grid_vertex_sample(HairGridVert *vert,
}
}
-/* XXX simplified test implementation using a series of discrete sample along the segment,
- * instead of finding the closest point for all affected grid vertices.
- */
void SIM_hair_volume_add_segment(HairGrid *grid,
const float UNUSED(x1[3]),
const float UNUSED(v1[3]),
@@ -649,6 +646,9 @@ void SIM_hair_volume_add_segment(HairGrid *grid,
const float UNUSED(dir2[3]),
const float UNUSED(dir3[3]))
{
+ /* XXX simplified test implementation using a series of discrete sample along the segment,
+ * instead of finding the closest point for all affected grid vertices. */
+
const float radius = 1.5f;
const float dist_scale = grid->inv_cellsize;
@@ -842,8 +842,8 @@ bool SIM_hair_volume_solve_divergence(HairGrid *grid,
}
/* Main Poisson equation system:
- * This is derived from the discretezation of the Poisson equation
- * div(grad(p)) = div(v)
+ * This is derived from the discretization of the Poisson equation:
+ * `div(grad(p)) = div(v)`
*
* The finite difference approximation yields the linear equation system described here:
* https://en.wikipedia.org/wiki/Discrete_Poisson_equation
@@ -1160,7 +1160,7 @@ HairGrid *SIM_hair_volume_create_vertex_grid(float cellsize,
}
size = hair_grid_size(res);
- grid = (HairGrid *)MEM_callocN(sizeof(HairGrid), "hair grid");
+ grid = MEM_cnew<HairGrid>("hair grid");
grid->res[0] = res[0];
grid->res[1] = res[1];
grid->res[2] = res[2];
diff --git a/source/blender/simulation/intern/implicit.h b/source/blender/simulation/intern/implicit.h
index a8693c61018..c8eab94d315 100644
--- a/source/blender/simulation/intern/implicit.h
+++ b/source/blender/simulation/intern/implicit.h
@@ -80,7 +80,8 @@ void SIM_mass_spring_get_motion_state(struct Implicit_Data *data,
void SIM_mass_spring_get_position(struct Implicit_Data *data, int index, float x[3]);
void SIM_mass_spring_get_velocity(struct Implicit_Data *data, int index, float v[3]);
-/* access to modified motion state during solver step */
+/* Access to modified motion state during solver step. */
+
void SIM_mass_spring_get_new_position(struct Implicit_Data *data, int index, float x[3]);
void SIM_mass_spring_set_new_position(struct Implicit_Data *data, int index, const float x[3]);
void SIM_mass_spring_get_new_velocity(struct Implicit_Data *data, int index, float v[3]);
@@ -106,44 +107,64 @@ bool SIM_mass_spring_solve_velocities(struct Implicit_Data *data,
bool SIM_mass_spring_solve_positions(struct Implicit_Data *data, float dt);
void SIM_mass_spring_apply_result(struct Implicit_Data *data);
-/* Clear the force vector at the beginning of the time step */
+/**
+ * Clear the force vector at the beginning of the time step.
+ */
void SIM_mass_spring_clear_forces(struct Implicit_Data *data);
-/* Fictitious forces introduced by moving coordinate systems */
+/**
+ * Fictitious forces introduced by moving coordinate systems.
+ */
void SIM_mass_spring_force_reference_frame(struct Implicit_Data *data,
int index,
const float acceleration[3],
const float omega[3],
const float domega_dt[3],
float mass);
-/* Simple uniform gravity force */
+/**
+ * Simple uniform gravity force.
+ */
void SIM_mass_spring_force_gravity(struct Implicit_Data *data,
int index,
float mass,
const float g[3]);
-/* Global drag force (velocity damping) */
+/**
+ * Global drag force (velocity damping).
+ */
void SIM_mass_spring_force_drag(struct Implicit_Data *data, float drag);
-/* Custom external force */
+/**
+ * Custom external force.
+ */
void SIM_mass_spring_force_extern(
struct Implicit_Data *data, int i, const float f[3], float dfdx[3][3], float dfdv[3][3]);
-/* Wind force, acting on a face (only generates pressure from the normal component) */
+/**
+ * Wind force, acting on a face (only generates pressure from the normal component).
+ */
void SIM_mass_spring_force_face_wind(
struct Implicit_Data *data, int v1, int v2, int v3, const float (*winvec)[3]);
-/* Arbitrary per-unit-area vector force field acting on a face. */
+/**
+ * Arbitrary per-unit-area vector force field acting on a face..
+ */
void SIM_mass_spring_force_face_extern(
struct Implicit_Data *data, int v1, int v2, int v3, const float (*forcevec)[3]);
-/* Wind force, acting on an edge */
+/**
+ * Wind force, acting on an edge.
+ */
void SIM_mass_spring_force_edge_wind(struct Implicit_Data *data,
int v1,
int v2,
float radius1,
float radius2,
const float (*winvec)[3]);
-/* Wind force, acting on a vertex */
+/**
+ * Wind force, acting on a vertex.
+ */
void SIM_mass_spring_force_vertex_wind(struct Implicit_Data *data,
int v,
float radius,
const float (*winvec)[3]);
-/* Linear spring force between two points */
+/**
+ * Linear spring force between two points.
+ */
bool SIM_mass_spring_force_spring_linear(struct Implicit_Data *data,
int i,
int j,
@@ -155,7 +176,9 @@ bool SIM_mass_spring_force_spring_linear(struct Implicit_Data *data,
bool resist_compress,
bool new_compress,
float clamp_force);
-/* Angular spring force between two polygons */
+/**
+ * Angular spring force between two polygons.
+ */
bool SIM_mass_spring_force_spring_angular(struct Implicit_Data *data,
int i,
int j,
@@ -166,10 +189,14 @@ bool SIM_mass_spring_force_spring_angular(struct Implicit_Data *data,
float restang,
float stiffness,
float damping);
-/* Bending force, forming a triangle at the base of two structural springs */
+/**
+ * Bending force, forming a triangle at the base of two structural springs.
+ */
bool SIM_mass_spring_force_spring_bending(
struct Implicit_Data *data, int i, int j, float restlen, float kb, float cb);
-/* Angular bending force based on local target vectors */
+/**
+ * Angular bending force based on local target vectors.
+ */
bool SIM_mass_spring_force_spring_bending_hair(struct Implicit_Data *data,
int i,
int j,
@@ -177,7 +204,9 @@ bool SIM_mass_spring_force_spring_bending_hair(struct Implicit_Data *data,
const float target[3],
float stiffness,
float damping);
-/* Global goal spring */
+/**
+ * Global goal spring.
+ */
bool SIM_mass_spring_force_spring_goal(struct Implicit_Data *data,
int i,
const float goal_x[3],
@@ -242,13 +271,15 @@ void SIM_hair_volume_grid_interpolate(struct HairGrid *grid,
float density_gradient[3],
float velocity_gradient[3][3]);
-/* Effect of fluid simulation grid on velocities.
+/**
+ * Effect of fluid simulation grid on velocities.
* fluid_factor controls blending between PIC (Particle-in-Cell)
* and FLIP (Fluid-Implicit-Particle) methods (0 = only PIC, 1 = only FLIP)
*/
void SIM_hair_volume_grid_velocity(
struct HairGrid *grid, const float x[3], const float v[3], float fluid_factor, float r_v[3]);
-/* XXX Warning: expressing grid effects on velocity as a force is not very stable,
+/**
+ * WARNING: expressing grid effects on velocity as a force is not very stable,
* due to discontinuities in interpolated values!
* Better use hybrid approaches such as described in
* "Detail Preserving Continuum Simulation of Straight Hair"
diff --git a/source/blender/simulation/intern/implicit_blender.c b/source/blender/simulation/intern/implicit_blender.c
index ad903e9da4a..95bf59101e6 100644
--- a/source/blender/simulation/intern/implicit_blender.c
+++ b/source/blender/simulation/intern/implicit_blender.c
@@ -830,7 +830,7 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z,
s_prev = s;
s = dot_lfvector(r, r, numverts);
- /* d = r+d*(s/s_prev); */
+ // d = r+d*(s/s_prev);
add_lfvector_lfvectorS(d, r, d, (s / s_prev), numverts);
filter(d, S);
@@ -1475,11 +1475,12 @@ static float calc_nor_area_tri(float nor[3],
return normalize_v3(nor) / 2.0f;
}
-/* XXX does not support force jacobians yet, since the effector system does not provide them either
- */
void SIM_mass_spring_force_face_wind(
Implicit_Data *data, int v1, int v2, int v3, const float (*winvec)[3])
{
+ /* XXX does not support force jacobians yet,
+ * since the effector system does not provide them either. */
+
const float effector_scale = 0.02f;
const int vs[3] = {v1, v2, v3};
float win[3], nor[3], area;
@@ -1854,10 +1855,11 @@ bool SIM_mass_spring_force_spring_linear(Implicit_Data *data,
return true;
}
-/* See "Stable but Responsive Cloth" (Choi, Ko 2005) */
bool SIM_mass_spring_force_spring_bending(
Implicit_Data *data, int i, int j, float restlen, float kb, float cb)
{
+ /* See "Stable but Responsive Cloth" (Choi, Ko 2005). */
+
float extent[3], length, dir[3], vel[3];
/* calculate elongation */
@@ -1959,8 +1961,6 @@ BLI_INLINE void spring_angle(Implicit_Data *data,
sub_v3_v3(r_vel_b, vel_e);
}
-/* Angular springs roughly based on the bending model proposed by Baraff and Witkin in "Large Steps
- * in Cloth Simulation". */
bool SIM_mass_spring_force_spring_angular(Implicit_Data *data,
int i,
int j,
@@ -2179,9 +2179,6 @@ BLI_INLINE void spring_hairbend_estimate_dfdv(Implicit_Data *data,
}
}
-/* Angular spring that pulls the vertex toward the local target
- * See "Artistic Simulation of Curly Hair" (Pixar technical memo #12-03a)
- */
bool SIM_mass_spring_force_spring_bending_hair(Implicit_Data *data,
int i,
int j,
@@ -2190,6 +2187,9 @@ bool SIM_mass_spring_force_spring_bending_hair(Implicit_Data *data,
float stiffness,
float damping)
{
+ /* Angular springs roughly based on the bending model proposed by Baraff and Witkin in
+ * "Large Steps in Cloth Simulation". */
+
float goal[3];
float fj[3], fk[3];
float dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3];
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 4d65726fe2b..03b2fb49085 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -202,6 +202,7 @@ if(WITH_XR_OPENXR)
xr/intern/wm_xr_action.c
xr/intern/wm_xr_actionmap.c
xr/intern/wm_xr_draw.c
+ xr/intern/wm_xr_operators.c
xr/intern/wm_xr_session.c
xr/wm_xr.h
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 577561017c4..ff3e1b7474c 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -41,10 +41,13 @@ extern "C" {
#endif
struct ARegion;
+struct AssetHandle;
+struct AssetLibraryReference;
struct GHashIterator;
struct GPUViewport;
struct ID;
struct IDProperty;
+struct IDRemapper;
struct ImBuf;
struct ImageFormatData;
struct Main;
@@ -82,11 +85,24 @@ typedef struct wmGizmoMap wmGizmoMap;
typedef struct wmGizmoMapType wmGizmoMapType;
typedef struct wmJob wmJob;
-/* general API */
+/* General API. */
+
+/**
+ * Used for setting app-template from the command line:
+ * - non-empty string: overrides.
+ * - empty string: override, using no app template.
+ * - NULL: clears override.
+ */
void WM_init_state_app_template_set(const char *app_template);
const char *WM_init_state_app_template_get(void);
+/**
+ * Called when no ghost system was initialized.
+ */
void WM_init_state_size_set(int stax, int stay, int sizx, int sizy);
+/**
+ * For border-less and border windows set from command-line.
+ */
void WM_init_state_fullscreen_set(void);
void WM_init_state_normal_set(void);
void WM_init_state_maximized_set(void);
@@ -95,9 +111,21 @@ void WM_init_window_focus_set(bool do_it);
void WM_init_native_pixels(bool do_it);
void WM_init_tablet_api(void);
+/**
+ * Initialize Blender and load the startup file & preferences
+ * (only called once).
+ */
void WM_init(struct bContext *C, int argc, const char **argv);
-void WM_exit_ex(struct bContext *C, const bool do_python);
+/**
+ * \note doesn't run exit() call #WM_exit() for that.
+ */
+void WM_exit_ex(struct bContext *C, bool do_python);
+/**
+ * \brief Main exit function to close Blender ordinarily.
+ * \note Use #wm_exit_schedule_delayed() to close Blender from an operator.
+ * Might leak memory otherwise.
+ */
void WM_exit(struct bContext *C) ATTR_NORETURN;
void WM_main(struct bContext *C) ATTR_NORETURN;
@@ -109,6 +137,10 @@ void WM_init_opengl(void);
void WM_check(struct bContext *C);
void WM_reinit_gizmomap_all(struct Main *bmain);
+/**
+ * Needed for cases when operators are re-registered
+ * (when operator type pointers are stored).
+ */
void WM_script_tag_reload(void);
wmWindow *WM_window_find_under_cursor(const wmWindowManager *wm,
@@ -123,13 +155,30 @@ void WM_window_pixel_sample_read(const wmWindowManager *wm,
uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, int r_size[2]);
+/**
+ * Support for native pixel size
+ *
+ * \note macOS retina opens window in size X, but it has up to 2 x more pixels.
+ */
int WM_window_pixels_x(const struct wmWindow *win);
int WM_window_pixels_y(const struct wmWindow *win);
+/**
+ * Get boundaries usable by all window contents, including global areas.
+ */
void WM_window_rect_calc(const struct wmWindow *win, struct rcti *r_rect);
+/**
+ * Get boundaries usable by screen-layouts, excluding global areas.
+ * \note Depends on #U.dpi_fac. Should that be outdated, call #WM_window_set_dpi first.
+ */
void WM_window_screen_rect_calc(const struct wmWindow *win, struct rcti *r_rect);
bool WM_window_is_fullscreen(const struct wmWindow *win);
bool WM_window_is_maximized(const struct wmWindow *win);
+/**
+ * Some editor data may need to be synced with scene data (3D View camera and layers).
+ * This function ensures data is synced for editors
+ * in visible work-spaces and their visible layouts.
+ */
void WM_windows_scene_data_sync(const ListBase *win_lb, struct Scene *scene) ATTR_NONNULL();
struct Scene *WM_windows_scene_get_from_screen(const struct wmWindowManager *wm,
const struct bScreen *screen)
@@ -143,6 +192,9 @@ struct WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm
struct Scene *WM_window_get_active_scene(const struct wmWindow *win)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * \warning Only call outside of area/region loops.
+ */
void WM_window_set_active_scene(struct Main *bmain,
struct bContext *C,
struct wmWindow *win,
@@ -157,6 +209,9 @@ struct WorkSpaceLayout *WM_window_get_active_layout(const struct wmWindow *win)
void WM_window_set_active_layout(struct wmWindow *win,
struct WorkSpace *workspace,
struct WorkSpaceLayout *layout) ATTR_NONNULL(1);
+/**
+ * Get the active screen of the active workspace in \a win.
+ */
struct bScreen *WM_window_get_active_screen(const struct wmWindow *win)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
void WM_window_set_active_screen(struct wmWindow *win,
@@ -176,13 +231,21 @@ void WM_opengl_context_dispose(void *context);
void WM_opengl_context_activate(void *context);
void WM_opengl_context_release(void *context);
-/* WM_window_open alignment */
-typedef enum WindowAlignment {
+/* #WM_window_open alignment */
+typedef enum eWindowAlignment {
WIN_ALIGN_ABSOLUTE = 0,
WIN_ALIGN_LOCATION_CENTER,
WIN_ALIGN_PARENT_CENTER,
-} WindowAlignment;
+} eWindowAlignment;
+/**
+ * \param space_type: SPACE_VIEW3D, SPACE_INFO, ... (eSpace_Type)
+ * \param toplevel: Not a child owned by other windows. A peer of main window.
+ * \param dialog: whether this should be made as a dialog-style window
+ * \param temp: whether this is considered a short-lived window
+ * \param alignment: how this window is positioned relative to its parent
+ * \return the window or NULL in case of failure.
+ */
struct wmWindow *WM_window_open(struct bContext *C,
const char *title,
int x,
@@ -193,7 +256,7 @@ struct wmWindow *WM_window_open(struct bContext *C,
bool toplevel,
bool dialog,
bool temp,
- WindowAlignment alignment);
+ eWindowAlignment alignment);
void WM_window_set_dpi(const wmWindow *win);
@@ -206,32 +269,50 @@ void WM_autosave_init(struct wmWindowManager *wm);
bool WM_recover_last_session(struct bContext *C, struct ReportList *reports);
void WM_file_tag_modified(void);
+/**
+ * \note `scene` (and related `view_layer` and `v3d`) pointers may be NULL,
+ * in which case no instantiation of linked objects, collections etc. will be performed.
+ */
struct ID *WM_file_link_datablock(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct View3D *v3d,
const char *filepath,
- const short id_code,
+ short id_code,
const char *id_name,
int flag);
+/**
+ * \note `scene` (and related `view_layer` and `v3d`) pointers may be NULL,
+ * in which case no instantiation of appended objects, collections etc. will be performed.
+ */
struct ID *WM_file_append_datablock(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct View3D *v3d,
const char *filepath,
- const short id_code,
+ short id_code,
const char *id_name,
int flag);
void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *reports);
-/* mouse cursors */
+/* Mouse cursors. */
+
void WM_cursor_set(struct wmWindow *win, int curs);
bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *area, const ARegion *region);
void WM_cursor_modal_set(struct wmWindow *win, int val);
void WM_cursor_modal_restore(struct wmWindow *win);
+/**
+ * To allow usage all over, we do entire WM.
+ */
void WM_cursor_wait(bool val);
+/**
+ * \param bounds: can be NULL
+ */
void WM_cursor_grab_enable(struct wmWindow *win, int wrap, bool hide, int bounds[4]);
void WM_cursor_grab_disable(struct wmWindow *win, const int mouse_ungrab_xy[2]);
+/**
+ * After this you can call restore too.
+ */
void WM_cursor_time(struct wmWindow *win, int nr);
struct wmPaintCursor *WM_paint_cursor_activate(
@@ -247,10 +328,16 @@ void WM_paint_cursor_remove_by_type(struct wmWindowManager *wm,
void (*free)(void *));
void WM_paint_cursor_tag_redraw(struct wmWindow *win, struct ARegion *region);
+/**
+ * This function requires access to the GHOST_SystemHandle (g_system).
+ */
void WM_cursor_warp(struct wmWindow *win, int x, int y);
+/**
+ * Set x, y to values we can actually position the cursor to.
+ */
void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y);
-/* handlers */
+/* Handlers. */
typedef bool (*EventHandlerPoll)(const ARegion *region, const struct wmEvent *event);
struct wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap);
@@ -259,7 +346,9 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_poll(ListBase *handler
EventHandlerPoll poll);
struct wmEventHandler_Keymap *WM_event_add_keymap_handler_v2d_mask(ListBase *handlers,
wmKeyMap *keymap);
-/* priority not implemented, it adds in begin */
+/**
+ * \note Priorities not implemented yet, for time being just insert in begin of list.
+ */
struct wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers,
wmKeyMap *keymap,
int priority);
@@ -270,13 +359,16 @@ typedef struct wmEventHandler_KeymapResult {
} wmEventHandler_KeymapResult;
typedef void(wmEventHandler_KeymapDynamicFn)(wmWindowManager *wm,
+ struct wmWindow *win,
struct wmEventHandler_Keymap *handler,
struct wmEventHandler_KeymapResult *km_result);
-void WM_event_get_keymap_from_toolsystem_fallback(struct wmWindowManager *wm,
- struct wmEventHandler_Keymap *handler,
- wmEventHandler_KeymapResult *km_result);
+void WM_event_get_keymap_from_toolsystem_with_gizmos(struct wmWindowManager *wm,
+ struct wmWindow *win,
+ struct wmEventHandler_Keymap *handler,
+ wmEventHandler_KeymapResult *km_result);
void WM_event_get_keymap_from_toolsystem(struct wmWindowManager *wm,
+ struct wmWindow *win,
struct wmEventHandler_Keymap *handler,
wmEventHandler_KeymapResult *km_result);
@@ -291,6 +383,7 @@ void WM_event_set_keymap_handler_post_callback(struct wmEventHandler_Keymap *han
void *user_data),
void *user_data);
void WM_event_get_keymaps_from_handler(wmWindowManager *wm,
+ struct wmWindow *win,
struct wmEventHandler_Keymap *handler,
struct wmEventHandler_KeymapResult *km_result);
@@ -300,6 +393,7 @@ wmKeyMapItem *WM_event_match_keymap_item(struct bContext *C,
wmKeyMapItem *WM_event_match_keymap_item_from_handlers(struct bContext *C,
struct wmWindowManager *wm,
+ struct wmWindow *win,
struct ListBase *handlers,
const struct wmEvent *event);
@@ -311,12 +405,16 @@ struct wmEventHandler_UI *WM_event_add_ui_handler(const struct bContext *C,
wmUIHandlerFunc handle_fn,
wmUIHandlerRemoveFunc remove_fn,
void *user_data,
- const char flag);
+ char flag);
+/**
+ * \param postpone: Enable for `win->modalhandlers`,
+ * this is in a running for () loop in wm_handlers_do().
+ */
void WM_event_remove_ui_handler(ListBase *handlers,
wmUIHandlerFunc handle_fn,
wmUIHandlerRemoveFunc remove_fn,
void *user_data,
- const bool postpone);
+ bool postpone);
void WM_event_remove_area_handler(struct ListBase *handlers, void *area);
void WM_event_free_ui_handler_all(struct bContext *C,
ListBase *handlers,
@@ -324,13 +422,24 @@ void WM_event_free_ui_handler_all(struct bContext *C,
wmUIHandlerRemoveFunc remove_fn);
struct wmEventHandler_Op *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op);
+/**
+ * Modal handlers store a pointer to an area which might be freed while the handler runs.
+ * Use this function to NULL all handler pointers to \a old_area.
+ */
void WM_event_modal_handler_area_replace(wmWindow *win,
const struct ScrArea *old_area,
struct ScrArea *new_area);
+/**
+ * Modal handlers store a pointer to a region which might be freed while the handler runs.
+ * Use this function to NULL all handler pointers to \a old_region.
+ */
void WM_event_modal_handler_region_replace(wmWindow *win,
const struct ARegion *old_region,
struct ARegion *new_region);
+/**
+ * Called on exit or remove area, only here call cancel callback.
+ */
void WM_event_remove_handlers(struct bContext *C, ListBase *handlers);
/* handler flag */
@@ -359,14 +468,23 @@ void WM_event_add_notifier_ex(struct wmWindowManager *wm,
void *reference);
void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference);
void WM_main_add_notifier(unsigned int type, void *reference);
+/**
+ * Clear notifiers by reference, Used so listeners don't act on freed data.
+ */
void WM_main_remove_notifier_reference(const void *reference);
-void WM_main_remap_editor_id_reference(struct ID *old_id, struct ID *new_id);
+void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings);
/* reports */
+/**
+ * Show the report in the info header.
+ */
void WM_report_banner_show(void);
+/**
+ * Hide all currently displayed banners and abort their timer.
+ */
void WM_report_banners_cancel(struct Main *bmain);
-void WM_report(ReportType type, const char *message);
-void WM_reportf(ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3);
+void WM_report(eReportType type, const char *message);
+void WM_reportf(eReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3);
struct wmEvent *wm_event_add_ex(struct wmWindow *win,
const struct wmEvent *event_to_add,
@@ -391,44 +509,87 @@ void WM_event_remove_timer(struct wmWindowManager *wm,
void WM_event_remove_timer_notifier(struct wmWindowManager *wm,
struct wmWindow *win,
struct wmTimer *timer);
+/**
+ * To (de)activate running timers temporary.
+ */
void WM_event_timer_sleep(struct wmWindowManager *wm,
struct wmWindow *win,
struct wmTimer *timer,
bool do_sleep);
-/* operator api, default callbacks */
-/* invoke callback, uses enum property named "type" */
+/* Operator API, default callbacks. */
+
+/**
+ * Helper to get select and tweak-transform to work conflict free and as desired. See
+ * #WM_operator_properties_generic_select() for details.
+ *
+ * To be used together with #WM_generic_select_invoke() and
+ * #WM_operator_properties_generic_select().
+ */
int WM_generic_select_modal(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * Helper to get select and tweak-transform to work conflict free and as desired. See
+ * #WM_operator_properties_generic_select() for details.
+ *
+ * To be used together with #WM_generic_select_modal() and
+ * #WM_operator_properties_generic_select().
+ */
int WM_generic_select_invoke(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op);
int WM_operator_smooth_viewtx_get(const struct wmOperator *op);
-int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext);
+/**
+ * Invoke callback, uses enum property named "type".
+ */
+int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, wmOperatorCallContext opcontext);
int WM_menu_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
+/**
+ * Call an existent menu. The menu can be created in C or Python.
+ */
void WM_menu_name_call(struct bContext *C, const char *menu_name, short context);
+/**
+ * Similar to #WM_enum_search_invoke, but draws previews. Also, this can't
+ * be used as invoke callback directly since it needs additional info.
+ */
int WM_enum_search_invoke_previews(struct bContext *C,
struct wmOperator *op,
short prv_cols,
short prv_rows);
int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
-/* invoke callback, confirm menu + exec */
+/**
+ * Invoke callback, confirm menu + exec.
+ */
int WM_operator_confirm(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int WM_operator_confirm_or_exec(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
-/* invoke callback, file selector "filepath" unset + exec */
+/**
+ * Invoke callback, file selector "filepath" unset + exec.
+ *
+ * #wmOperatorType.invoke, opens file-select if path property not set, otherwise executes.
+ */
int WM_operator_filesel(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op,
const struct ImageFormatData *im_format);
-/* poll callback, context checks */
+/** Callback for #wmOperatorType.poll */
bool WM_operator_winactive(struct bContext *C);
-/* invoke callback, exec + redo popup */
+/**
+ * Invoke callback, exec + redo popup.
+ *
+ * Same as #WM_operator_props_popup but don't use operator redo.
+ * just wraps #WM_operator_props_dialog_popup.
+ */
int WM_operator_props_popup_confirm(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * Same as #WM_operator_props_popup but call the operator first,
+ * This way - the button values correspond to the result of the operator.
+ * Without this, first access to a button will make the result jump, see T32452.
+ */
int WM_operator_props_popup_call(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
@@ -439,64 +600,127 @@ int WM_operator_props_dialog_popup(struct bContext *C, struct wmOperator *op, in
int WM_operator_redo_popup(struct bContext *C, struct wmOperator *op);
int WM_operator_ui_popup(struct bContext *C, struct wmOperator *op, int width);
+/**
+ * Can't be used as an invoke directly, needs message arg (can be NULL).
+ */
int WM_operator_confirm_message_ex(struct bContext *C,
struct wmOperator *op,
const char *title,
- const int icon,
+ int icon,
const char *message,
- const short opcontext);
+ wmOperatorCallContext opcontext);
int WM_operator_confirm_message(struct bContext *C, struct wmOperator *op, const char *message);
-/* operator api */
+/* Operator API. */
+
void WM_operator_free(struct wmOperator *op);
void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op);
+/**
+ * Use with extreme care!
+ * Properties, custom-data etc - must be compatible.
+ *
+ * \param op: Operator to assign the type to.
+ * \param ot: Operator type to assign.
+ */
void WM_operator_type_set(struct wmOperator *op, struct wmOperatorType *ot);
void WM_operator_stack_clear(struct wmWindowManager *wm);
+/**
+ * This function is needed in the case when an addon id disabled
+ * while a modal operator it defined is running.
+ */
void WM_operator_handlers_clear(wmWindowManager *wm, struct wmOperatorType *ot);
bool WM_operator_poll(struct bContext *C, struct wmOperatorType *ot);
bool WM_operator_poll_context(struct bContext *C, struct wmOperatorType *ot, short context);
-int WM_operator_call_ex(struct bContext *C, struct wmOperator *op, const bool store);
+/**
+ * For running operators with frozen context (modal handlers, menus).
+ *
+ * \param store: Store settings for re-use.
+ *
+ * \warning do not use this within an operator to call itself! T29537.
+ */
+int WM_operator_call_ex(struct bContext *C, struct wmOperator *op, bool store);
int WM_operator_call(struct bContext *C, struct wmOperator *op);
+/**
+ * This is intended to be used when an invoke operator wants to call exec on itself
+ * and is basically like running op->type->exec() directly, no poll checks no freeing,
+ * since we assume whoever called invoke will take care of that
+ */
int WM_operator_call_notest(struct bContext *C, struct wmOperator *op);
+/**
+ * Execute this operator again, put here so it can share above code
+ */
int WM_operator_repeat(struct bContext *C, struct wmOperator *op);
int WM_operator_repeat_last(struct bContext *C, struct wmOperator *op);
+/**
+ * \return true if #WM_operator_repeat can run.
+ * Simple check for now but may become more involved.
+ * To be sure the operator can run call `WM_operator_poll(C, op->type)` also, since this call
+ * checks if #WM_operator_repeat() can run at all, not that it WILL run at any time.
+ */
bool WM_operator_repeat_check(const struct bContext *C, struct wmOperator *op);
bool WM_operator_is_repeat(const struct bContext *C, const struct wmOperator *op);
+
+bool WM_operator_name_poll(struct bContext *C, const char *opstring);
+/**
+ * Invokes operator in context.
+ */
int WM_operator_name_call_ptr(struct bContext *C,
struct wmOperatorType *ot,
- short context,
+ wmOperatorCallContext context,
struct PointerRNA *properties);
int WM_operator_name_call(struct bContext *C,
const char *opstring,
- short context,
+ wmOperatorCallContext context,
struct PointerRNA *properties);
int WM_operator_name_call_with_properties(struct bContext *C,
const char *opstring,
- short context,
+ wmOperatorCallContext context,
struct IDProperty *properties);
+/**
+ * Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context.
+ *
+ * - #wmOperatorType is used instead of operator name since python already has the operator type.
+ * - `poll()` must be called by python before this runs.
+ * - reports can be passed to this function (so python can report them as exceptions).
+ */
int WM_operator_call_py(struct bContext *C,
struct wmOperatorType *ot,
- short context,
+ wmOperatorCallContext context,
struct PointerRNA *properties,
struct ReportList *reports,
- const bool is_undo);
+ bool is_undo);
void WM_operator_name_call_ptr_with_depends_on_cursor(struct bContext *C,
wmOperatorType *ot,
- short opcontext,
+ wmOperatorCallContext opcontext,
PointerRNA *properties,
const char *drawstr);
-/* Used for keymap and macro items. */
+/**
+ * Similar to the function above except its uses ID properties used for key-maps and macros.
+ */
void WM_operator_properties_alloc(struct PointerRNA **ptr,
struct IDProperty **properties,
const char *opstring);
-/* Make props context sensitive or not. */
-void WM_operator_properties_sanitize(struct PointerRNA *ptr, const bool no_context);
+/**
+ * Make props context sensitive or not.
+ */
+void WM_operator_properties_sanitize(struct PointerRNA *ptr, bool no_context);
-bool WM_operator_properties_default(struct PointerRNA *ptr, const bool do_update);
+/**
+ * Set all props to their default.
+ *
+ * \param do_update: Only update un-initialized props.
+ *
+ * \note There's nothing specific to operators here.
+ * This could be made a general function.
+ */
+bool WM_operator_properties_default(struct PointerRNA *ptr, bool do_update);
+/**
+ * Remove all props without #PROP_SKIP_SAVE.
+ */
void WM_operator_properties_reset(struct wmOperator *op);
void WM_operator_properties_create(struct PointerRNA *ptr, const char *opstring);
void WM_operator_properties_create_ptr(struct PointerRNA *ptr, struct wmOperatorType *ot);
@@ -504,18 +728,28 @@ void WM_operator_properties_clear(struct PointerRNA *ptr);
void WM_operator_properties_free(struct PointerRNA *ptr);
bool WM_operator_check_ui_empty(struct wmOperatorType *ot);
+/**
+ * Return false, if the UI should be disabled.
+ */
bool WM_operator_check_ui_enabled(const struct bContext *C, const char *idname);
IDProperty *WM_operator_last_properties_ensure_idprops(struct wmOperatorType *ot);
void WM_operator_last_properties_ensure(struct wmOperatorType *ot, struct PointerRNA *ptr);
wmOperator *WM_operator_last_redo(const struct bContext *C);
-ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, const short idcode);
+/**
+ * Use for drag & drop a path or name with operators invoke() function.
+ */
+ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, short idcode);
bool WM_operator_last_properties_init(struct wmOperator *op);
bool WM_operator_last_properties_store(struct wmOperator *op);
/* wm_operator_props.c */
+
void WM_operator_properties_confirm_or_exec(struct wmOperatorType *ot);
+/**
+ * Default properties for file-select.
+ */
void WM_operator_properties_filesel(struct wmOperatorType *ot,
int filter,
short type,
@@ -523,36 +757,91 @@ void WM_operator_properties_filesel(struct wmOperatorType *ot,
short flag,
short display,
short sort);
+/**
+ * Disable using cursor position,
+ * use when view operators are initialized from buttons.
+ */
void WM_operator_properties_use_cursor_init(struct wmOperatorType *ot);
void WM_operator_properties_border(struct wmOperatorType *ot);
void WM_operator_properties_border_to_rcti(struct wmOperator *op, struct rcti *rect);
void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect);
+/**
+ * Use with #WM_gesture_box_invoke
+ */
void WM_operator_properties_gesture_box_ex(struct wmOperatorType *ot, bool deselect, bool extend);
void WM_operator_properties_gesture_box(struct wmOperatorType *ot);
void WM_operator_properties_gesture_box_select(struct wmOperatorType *ot);
void WM_operator_properties_gesture_box_zoom(struct wmOperatorType *ot);
+/**
+ * Use with #WM_gesture_lasso_invoke
+ */
void WM_operator_properties_gesture_lasso(struct wmOperatorType *ot);
+/**
+ * Use with #WM_gesture_straightline_invoke
+ */
void WM_operator_properties_gesture_straightline(struct wmOperatorType *ot, int cursor);
+/**
+ * Use with #WM_gesture_circle_invoke
+ */
void WM_operator_properties_gesture_circle(struct wmOperatorType *ot);
void WM_operator_properties_mouse_select(struct wmOperatorType *ot);
void WM_operator_properties_select_all(struct wmOperatorType *ot);
void WM_operator_properties_select_action(struct wmOperatorType *ot,
int default_action,
bool hide_gui);
+/**
+ * Only #SELECT / #DESELECT.
+ */
void WM_operator_properties_select_action_simple(struct wmOperatorType *ot,
int default_action,
bool hide_gui);
+/**
+ * Use for all select random operators.
+ * Adds properties: percent, seed, action.
+ */
void WM_operator_properties_select_random(struct wmOperatorType *ot);
int WM_operator_properties_select_random_seed_increment_get(wmOperator *op);
void WM_operator_properties_select_operation(struct wmOperatorType *ot);
+/**
+ * \note Some tools don't support XOR/AND.
+ */
void WM_operator_properties_select_operation_simple(struct wmOperatorType *ot);
void WM_operator_properties_select_walk_direction(struct wmOperatorType *ot);
+/**
+ * Selecting and tweaking items are overlapping operations. Getting both to work without conflicts
+ * requires special care. See
+ * https://wiki.blender.org/wiki/Human_Interface_Guidelines/Selection#Select-tweaking for the
+ * desired behavior.
+ *
+ * For default click selection (with no modifier keys held), the select operators can do the
+ * following:
+ * - On a mouse press on an unselected item, change selection and finish immediately after.
+ * This sends an undo push and allows transform to take over should a tweak event be caught now.
+ * - On a mouse press on a selected item, don't change selection state, but start modal execution
+ * of the operator. Idea is that we wait with deselecting other items until we know that the
+ * intention wasn't to tweak (mouse press+drag) all selected items.
+ * - If a tweak is recognized before the release event happens, cancel the operator, so that
+ * transform can take over and no undo-push is sent.
+ * - If the release event occurs rather than a tweak one, deselect all items but the one under the
+ * cursor, and finish the modal operator.
+ *
+ * This utility, together with #WM_generic_select_invoke() and #WM_generic_select_modal() should
+ * help getting the wanted behavior to work. Most generic logic should be handled in these, so that
+ * the select operators only have to care for the case dependent handling.
+ *
+ * Every select operator has slightly different requirements, e.g. sequencer strip selection
+ * also needs to account for handle selection. This should be the baseline behavior though.
+ */
void WM_operator_properties_generic_select(struct wmOperatorType *ot);
+
struct CheckerIntervalParams {
int nth; /* bypass when set to zero */
int skip;
int offset;
};
+/**
+ * \param nth_can_disable: Enable if we want to be able to select no interval at all.
+ */
void WM_operator_properties_checker_interval(struct wmOperatorType *ot, bool nth_can_disable);
void WM_operator_properties_checker_interval_from_op(struct wmOperator *op,
struct CheckerIntervalParams *op_params);
@@ -569,44 +858,100 @@ bool WM_operator_properties_checker_interval_test(const struct CheckerIntervalPa
/* Show the properties sidebar by default. */
#define WM_FILESEL_SHOW_PROPS (1 << 5)
-/* operator as a python command (resultuing string must be freed) */
+/**
+ * Operator as a Python command (resulting string must be freed).
+ *
+ * Print a string representation of the operator,
+ * with the arguments that it runs so Python can run it again.
+ *
+ * When calling from an existing #wmOperator, better to use simple version:
+ * `WM_operator_pystring(C, op);`
+ *
+ * \note Both \a op and \a opptr may be `NULL` (\a op is only used for macro operators).
+ */
char *WM_operator_pystring_ex(struct bContext *C,
struct wmOperator *op,
- const bool all_args,
- const bool macro_args,
+ bool all_args,
+ bool macro_args,
struct wmOperatorType *ot,
struct PointerRNA *opptr);
char *WM_operator_pystring(struct bContext *C,
struct wmOperator *op,
- const bool all_args,
- const bool macro_args);
+ bool all_args,
+ bool macro_args);
+/**
+ * \return true if the string was shortened.
+ */
bool WM_operator_pystring_abbreviate(char *str, int str_len_max);
char *WM_prop_pystring_assign(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
int index);
+/**
+ * Convert: `some.op` -> `SOME_OT_op` or leave as-is.
+ */
void WM_operator_bl_idname(char *to, const char *from);
+/**
+ * Convert: `SOME_OT_op` -> `some.op` or leave as-is.
+ */
void WM_operator_py_idname(char *to, const char *from);
+/**
+ * Sanity check to ensure #WM_operator_bl_idname won't fail.
+ * \returns true when there are no problems with \a idname, otherwise report an error.
+ */
bool WM_operator_py_idname_ok_or_report(struct ReportList *reports,
const char *classname,
const char *idname);
-char *WM_context_path_resolve_property_full(struct bContext *C,
+/**
+ * Calculate the path to `ptr` from context `C`, or return NULL if it can't be calculated.
+ */
+char *WM_context_path_resolve_property_full(const struct bContext *C,
const PointerRNA *ptr,
PropertyRNA *prop,
int index);
char *WM_context_path_resolve_full(struct bContext *C, const PointerRNA *ptr);
/* wm_operator_type.c */
+
struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet);
+/**
+ * \note Caller must free.
+ */
void WM_operatortype_iter(struct GHashIterator *ghi);
void WM_operatortype_append(void (*opfunc)(struct wmOperatorType *));
void WM_operatortype_append_ptr(void (*opfunc)(struct wmOperatorType *, void *), void *userdata);
void WM_operatortype_append_macro_ptr(void (*opfunc)(struct wmOperatorType *, void *),
void *userdata);
+/**
+ * Called on initialize WM_exit().
+ */
void WM_operatortype_remove_ptr(struct wmOperatorType *ot);
bool WM_operatortype_remove(const char *idname);
+/**
+ * Remove memory of all previously executed tools.
+ */
void WM_operatortype_last_properties_clear_all(void);
+/**
+ * Tag all operator-properties of \a ot defined after calling this, until
+ * the next #WM_operatortype_props_advanced_end call (if available), with
+ * #OP_PROP_TAG_ADVANCED. Previously defined ones properties not touched.
+ *
+ * Calling this multiple times without a call to #WM_operatortype_props_advanced_end,
+ * all calls after the first one are ignored. Meaning all proprieties defined after the
+ * first call are tagged as advanced.
+ *
+ * This doesn't do the actual tagging, #WM_operatortype_props_advanced_end does which is
+ * called for all operators during registration (see #wm_operatortype_append__end).
+ */
void WM_operatortype_props_advanced_begin(struct wmOperatorType *ot);
+/**
+ * Tags all operator-properties of \a ot defined since the first
+ * #WM_operatortype_props_advanced_begin call,
+ * or the last #WM_operatortype_props_advanced_end call, with #OP_PROP_TAG_ADVANCED.
+ *
+ * \note This is called for all operators during registration (see #wm_operatortype_append__end).
+ * So it does not need to be explicitly called in operator-type definition.
+ */
void WM_operatortype_props_advanced_end(struct wmOperatorType *ot);
#define WM_operatortype_prop_tag(property, tags) \
@@ -616,6 +961,9 @@ void WM_operatortype_props_advanced_end(struct wmOperatorType *ot);
} \
(void)0
+/**
+ * \note Names have to be static for now.
+ */
struct wmOperatorType *WM_operatortype_append_macro(const char *idname,
const char *name,
const char *description,
@@ -627,26 +975,57 @@ const char *WM_operatortype_name(struct wmOperatorType *ot, struct PointerRNA *p
char *WM_operatortype_description(struct bContext *C,
struct wmOperatorType *ot,
struct PointerRNA *properties);
+/**
+ * Use when we want a label, preferring the description.
+ */
char *WM_operatortype_description_or_name(struct bContext *C,
struct wmOperatorType *ot,
struct PointerRNA *properties);
/* wm_operator_utils.c */
+
+/**
+ * Allow an operator with only and execute function to run modally,
+ * re-doing the action, using vertex coordinate store/restore instead of operator undo.
+ */
void WM_operator_type_modal_from_exec_for_object_edit_coords(struct wmOperatorType *ot);
/* wm_uilist_type.c */
+
+/**
+ * Called on initialize #WM_init()
+ */
void WM_uilisttype_init(void);
struct uiListType *WM_uilisttype_find(const char *idname, bool quiet);
bool WM_uilisttype_add(struct uiListType *ult);
void WM_uilisttype_remove_ptr(struct Main *bmain, struct uiListType *ult);
void WM_uilisttype_free(void);
+/**
+ * The "full" list-ID is an internal name used for storing and identifying a list. It is built like
+ * this:
+ * "{uiListType.idname}_{list_id}", whereby "list_id" is an optional parameter passed to
+ * `UILayout.template_list()`. If it is not set, the full list-ID is just "{uiListType.idname}_".
+ *
+ * Note that whenever the Python API refers to the list-ID, it's the short, "non-full" one it
+ * passed to `UILayout.template_list()`. C code can query that through
+ * #WM_uilisttype_list_id_get().
+ */
void WM_uilisttype_to_full_list_id(const struct uiListType *ult,
const char *list_id,
char r_full_list_id[]);
+/**
+ * Get the "non-full" list-ID, see #WM_uilisttype_to_full_list_id() for details.
+ *
+ * \note Assumes `uiList.list_id` was set using #WM_uilisttype_to_full_list_id()!
+ */
const char *WM_uilisttype_list_id_get(const struct uiListType *ult, struct uiList *list);
/* wm_menu_type.c */
+
+/**
+ * \note Called on initialize #WM_init().
+ */
void WM_menutype_init(void);
struct MenuType *WM_menutype_find(const char *idname, bool quiet);
void WM_menutype_iter(struct GHashIterator *ghi);
@@ -656,6 +1035,10 @@ void WM_menutype_free(void);
bool WM_menutype_poll(struct bContext *C, struct MenuType *mt);
/* wm_panel_type.c */
+
+/**
+ * Called on initialize #WM_init().
+ */
void WM_paneltype_init(void);
void WM_paneltype_clear(void);
struct PanelType *WM_paneltype_find(const char *idname, bool quiet);
@@ -683,6 +1066,11 @@ int WM_gesture_lasso_invoke(struct bContext *C,
const struct wmEvent *event);
int WM_gesture_lasso_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
void WM_gesture_lasso_cancel(struct bContext *C, struct wmOperator *op);
+/**
+ * helper function, we may want to add options for conversion to view space
+ *
+ * caller must free.
+ */
const int (*WM_gesture_lasso_path_to_array(struct bContext *C,
struct wmOperator *op,
int *mcoords_len))[2];
@@ -690,18 +1078,38 @@ const int (*WM_gesture_lasso_path_to_array(struct bContext *C,
int WM_gesture_straightline_invoke(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * This invoke callback starts the straight-line gesture with a viewport preview to the right side
+ * of the line.
+ */
int WM_gesture_straightline_active_side_invoke(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * This modal callback calls exec once per mouse move event while the gesture is active with the
+ * updated line start and end values, so it can be used for tools that have a real time preview
+ * (like a gradient updating in real time over the mesh).
+ */
int WM_gesture_straightline_modal(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * This modal one-shot callback only calls exec once after the gesture finishes without any updates
+ * during the gesture execution. Should be used for operations that are intended to be applied once
+ * without real time preview (like a trimming tool that only applies the bisect operation once
+ * after finishing the gesture as the bisect operation is too heavy to be computed in real time for
+ * a preview).
+ */
int WM_gesture_straightline_oneshot_modal(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
void WM_gesture_straightline_cancel(struct bContext *C, struct wmOperator *op);
/* Gesture manager API */
+
+/**
+ * Context checked on having screen, window and area.
+ */
struct wmGesture *WM_gesture_new(struct wmWindow *window,
const struct ARegion *region,
const struct wmEvent *event,
@@ -711,15 +1119,34 @@ void WM_gestures_remove(struct wmWindow *win);
void WM_gestures_free_all(struct wmWindow *win);
bool WM_gesture_is_modal_first(const struct wmGesture *gesture);
-/* fileselecting support */
+/* File-selecting support. */
+
+/**
+ * The idea here is to keep a handler alive on window queue, owning the operator.
+ * The file window can send event to make it execute, thus ensuring
+ * executing happens outside of lower level queues, with UI refreshed.
+ * Should also allow multi-window solutions.
+ */
void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op);
void WM_event_fileselect_event(struct wmWindowManager *wm, void *ophandle, int eventval);
+/**
+ * Sets the active region for this space from the context.
+ *
+ * \see #BKE_area_find_region_active_win
+ */
void WM_operator_region_active_win_set(struct bContext *C);
+/**
+ * Only finish + pass through for press events (allowing press-tweak).
+ */
int WM_operator_flag_only_pass_through_on_press(int retval, const struct wmEvent *event);
-/* drag and drop */
+/* Drag and drop. */
+
+/**
+ * Note that the pointer should be valid allocated and not on stack.
+ */
struct wmDrag *WM_event_start_drag(
struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags);
void WM_event_drag_image(struct wmDrag *, struct ImBuf *, float scale, int sx, int sy);
@@ -733,21 +1160,75 @@ struct wmDropBox *WM_dropbox_add(
void (*copy)(struct wmDrag *, struct wmDropBox *),
void (*cancel)(struct Main *, struct wmDrag *, struct wmDropBox *),
WMDropboxTooltipFunc tooltip);
+void WM_drag_draw_item_name_fn(struct bContext *C,
+ struct wmWindow *win,
+ struct wmDrag *drag,
+ const int xy[2]);
+void WM_drag_draw_default_fn(struct bContext *C,
+ struct wmWindow *win,
+ struct wmDrag *drag,
+ const int xy[2]);
+/**
+ * `spaceid` / `regionid` are zero for window drop maps.
+ */
ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid);
/* ID drag and drop */
+
+/**
+ * \param flag_extra: Additional linking flags (from #eFileSel_Params_Flag).
+ */
+ID *WM_drag_asset_id_import(wmDragAsset *asset_drag, int flag_extra);
+bool WM_drag_asset_will_import_linked(const wmDrag *drag);
void WM_drag_add_local_ID(struct wmDrag *drag, struct ID *id, struct ID *from_parent);
struct ID *WM_drag_get_local_ID(const struct wmDrag *drag, short idcode);
struct ID *WM_drag_get_local_ID_from_event(const struct wmEvent *event, short idcode);
+/**
+ * Check if the drag data is either a local ID or an external ID asset of type \a idcode.
+ */
bool WM_drag_is_ID_type(const struct wmDrag *drag, int idcode);
+/**
+ * \note: Does not store \a asset in any way, so it's fine to pass a temporary.
+ */
+wmDragAsset *WM_drag_create_asset_data(const struct AssetHandle *asset,
+ struct AssetMetaData *metadata,
+ const char *path,
+ int import_type);
struct wmDragAsset *WM_drag_get_asset_data(const struct wmDrag *drag, int idcode);
+struct AssetMetaData *WM_drag_get_asset_meta_data(const struct wmDrag *drag, int idcode);
+/**
+ * When dragging a local ID, return that. Otherwise, if dragging an asset-handle, link or append
+ * that depending on what was chosen by the drag-box (currently append only in fact).
+ *
+ * Use #WM_drag_free_imported_drag_ID() as cancel callback of the drop-box, so that the asset
+ * import is rolled back if the drop operator fails.
+ */
struct ID *WM_drag_get_local_ID_or_import_from_asset(const struct wmDrag *drag, int idcode);
+/**
+ * \brief Free asset ID imported for canceled drop.
+ *
+ * If the asset was imported (linked/appended) using #WM_drag_get_local_ID_or_import_from_asset()`
+ * (typically via a #wmDropBox.copy() callback), we want the ID to be removed again if the drop
+ * operator cancels.
+ * This is for use as #wmDropBox.cancel() callback.
+ */
void WM_drag_free_imported_drag_ID(struct Main *bmain,
struct wmDrag *drag,
struct wmDropBox *drop);
+struct wmDragAssetCatalog *WM_drag_get_asset_catalog_data(const struct wmDrag *drag);
+
+/**
+ * \note: Does not store \a asset in any way, so it's fine to pass a temporary.
+ */
+void WM_drag_add_asset_list_item(wmDrag *drag,
+ const struct bContext *C,
+ const struct AssetLibraryReference *asset_library_ref,
+ const struct AssetHandle *asset);
+const ListBase *WM_drag_asset_list_get(const wmDrag *drag);
+
const char *WM_drag_get_item_name(struct wmDrag *drag);
/* Set OpenGL viewport and scissor */
@@ -758,8 +1239,12 @@ void wmWindowViewport(struct wmWindow *win);
/* OpenGL utilities with safety check */
void wmOrtho2(float x1, float x2, float y1, float y2);
/* use for conventions (avoid hard-coded offsets all over) */
+
+/**
+ * Default pixel alignment for regions.
+ */
void wmOrtho2_region_pixelspace(const struct ARegion *region);
-void wmOrtho2_pixelspace(const float x, const float y);
+void wmOrtho2_pixelspace(float x, float y);
void wmGetProjectionMatrix(float mat[4][4], const struct rcti *winrct);
/* threaded Jobs Manager */
@@ -804,6 +1289,12 @@ enum {
* if having hard coded values is a problem */
};
+/**
+ * \return current job or adds new job, but doesn't run it.
+ *
+ * \note every owner only gets a single job,
+ * adding a new one will stop running job and when stopped it starts the new one.
+ */
struct wmJob *WM_jobs_get(struct wmWindowManager *wm,
struct wmWindow *win,
const void *owner,
@@ -811,9 +1302,15 @@ struct wmJob *WM_jobs_get(struct wmWindowManager *wm,
int flag,
int job_type);
+/**
+ * Returns true if job runs, for UI (progress) indicators.
+ */
bool WM_jobs_test(const struct wmWindowManager *wm, const void *owner, int job_type);
float WM_jobs_progress(const struct wmWindowManager *wm, const void *owner);
const char *WM_jobs_name(const struct wmWindowManager *wm, const void *owner);
+/**
+ * Time that job started.
+ */
double WM_jobs_starttime(const struct wmWindowManager *wm, const void *owner);
void *WM_jobs_customdata(struct wmWindowManager *wm, const void *owner);
void *WM_jobs_customdata_from_type(struct wmWindowManager *wm, int job_type);
@@ -835,12 +1332,28 @@ void WM_jobs_callbacks(struct wmJob *,
void (*update)(void *),
void (*endjob)(void *));
+/**
+ * If job running, the same owner gave it a new job.
+ * if different owner starts existing startjob, it suspends itself
+ */
void WM_jobs_start(struct wmWindowManager *wm, struct wmJob *);
+/**
+ * Signal job(s) from this owner or callback to stop, timer is required to get handled.
+ */
void WM_jobs_stop(struct wmWindowManager *wm, const void *owner, void *startjob);
+/**
+ * Actually terminate thread and job timer.
+ */
void WM_jobs_kill(struct wmWindowManager *wm,
void *owner,
void (*)(void *, short int *, short int *, float *));
+/**
+ * Wait until every job ended.
+ */
void WM_jobs_kill_all(struct wmWindowManager *wm);
+/**
+ * Wait until every job ended, except for one owner (used in undo to keep screen job alive).
+ */
void WM_jobs_kill_all_except(struct wmWindowManager *wm, const void *owner);
void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_type);
@@ -849,16 +1362,27 @@ bool WM_jobs_has_running(const struct wmWindowManager *wm);
void WM_job_main_thread_lock_acquire(struct wmJob *job);
void WM_job_main_thread_lock_release(struct wmJob *job);
-/* clipboard */
+/* Clipboard. */
+
+/**
+ * Return text from the clipboard.
+ *
+ * \note Caller needs to check for valid utf8 if this is a requirement.
+ */
char *WM_clipboard_text_get(bool selection, int *r_len);
+/**
+ * Convenience function for pasting to areas of Blender which don't support newlines.
+ */
char *WM_clipboard_text_get_firstline(bool selection, int *r_len);
void WM_clipboard_text_set(const char *buf, bool selection);
/* progress */
+
void WM_progress_set(struct wmWindow *win, float progress);
void WM_progress_clear(struct wmWindow *win);
/* Draw (for screenshot) */
+
void *WM_draw_cb_activate(struct wmWindow *win,
void (*draw)(const struct wmWindow *, void *),
void *customdata);
@@ -870,21 +1394,29 @@ void WM_draw_region_viewport_bind(struct ARegion *region);
void WM_draw_region_viewport_unbind(struct ARegion *region);
/* Region drawing */
+
void WM_draw_region_free(struct ARegion *region, bool hide);
struct GPUViewport *WM_draw_region_get_viewport(struct ARegion *region);
struct GPUViewport *WM_draw_region_get_bound_viewport(struct ARegion *region);
void WM_main_playanim(int argc, const char **argv);
-/* debugging only, convenience function to write on crash */
+/**
+ * Debugging only, convenience function to write on crash.
+ * Convenient to save a blend file from a debugger.
+ */
bool write_crash_blend(void);
-/* Lock the interface for any communication */
+/**
+ * Lock the interface for any communication.
+ */
void WM_set_locked_interface(struct wmWindowManager *wm, bool lock);
void WM_event_tablet_data_default_set(struct wmTabletData *tablet_data);
-/* For testing only 'G_FLAG_EVENT_SIMULATE' */
+/**
+ * For testing only, see #G_FLAG_EVENT_SIMULATE.
+ */
struct wmEvent *WM_event_add_simulate(struct wmWindow *win, const struct wmEvent *event_to_add);
const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win,
@@ -893,39 +1425,78 @@ const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win,
void WM_window_cursor_keymap_status_refresh(struct bContext *C, struct wmWindow *win);
void WM_window_status_area_tag_redraw(struct wmWindow *win);
+/**
+ * Similar to #BKE_screen_area_map_find_area_xy and related functions,
+ * use here since the area is stored in the window manager.
+ */
struct ScrArea *WM_window_status_area_find(struct wmWindow *win, struct bScreen *screen);
bool WM_window_modal_keymap_status_draw(struct bContext *C,
struct wmWindow *win,
struct uiLayout *layout);
/* wm_event_query.c */
+
+/**
+ * For debugging only, getting inspecting events manually is tedious.
+ */
void WM_event_print(const struct wmEvent *event);
int WM_event_modifier_flag(const struct wmEvent *event);
+/**
+ * For modal callbacks, check configuration for how to interpret exit with tweaks.
+ */
bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
bool WM_event_is_last_mousemove(const struct wmEvent *event);
bool WM_event_is_mouse_drag(const struct wmEvent *event);
bool WM_event_is_mouse_drag_or_press(const wmEvent *event);
+/**
+ * Detect motion between selection (callers should only use this for selection picking),
+ * typically mouse press/click events.
+ *
+ * \param mval: Region relative coordinates, call with (-1, -1) resets the last cursor location.
+ * \returns True when there was motion since last called.
+ *
+ * NOTE(@campbellbarton): The logic used here isn't foolproof.
+ * It's possible that users move the cursor past #WM_EVENT_CURSOR_MOTION_THRESHOLD then back to
+ * a position within the threshold (between mouse clicks).
+ * In practice users never reported this since the threshold is very small (a few pixels).
+ * To prevent the unlikely case of values matching from another region,
+ * changing regions resets this value to (-1, -1).
+ */
+bool WM_cursor_test_motion_and_update(const int mval[2]) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
int WM_event_drag_threshold(const struct wmEvent *event);
bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]);
bool WM_event_drag_test_with_delta(const struct wmEvent *event, const int delta[2]);
-/* event map */
+/**
+ * Event map that takes preferences into account.
+ */
int WM_userdef_event_map(int kmitype);
+/**
+ * Use so we can check if 'wmEvent.type' is released in modal operators.
+ *
+ * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar.
+ */
int WM_userdef_event_type_from_keymap_type(int kmitype);
#ifdef WITH_INPUT_NDOF
-void WM_event_ndof_pan_get(const struct wmNDOFMotionData *ndof,
- float r_pan[3],
- const bool use_zoom);
+void WM_event_ndof_pan_get(const struct wmNDOFMotionData *ndof, float r_pan[3], bool use_zoom);
void WM_event_ndof_rotate_get(const struct wmNDOFMotionData *ndof, float r_rot[3]);
float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3]);
void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]);
#endif /* WITH_INPUT_NDOF */
+#ifdef WITH_XR_OPENXR
+bool WM_event_is_xr(const struct wmEvent *event);
+#endif
+
+/**
+ * If this is a tablet event, return tablet pressure and set `*pen_flip`
+ * to 1 if the eraser tool is being used, 0 otherwise.
+ */
float WM_event_tablet_data(const struct wmEvent *event, int *pen_flip, float tilt[2]);
bool WM_event_is_tablet(const struct wmEvent *event);
@@ -937,6 +1508,7 @@ bool WM_event_is_ime_switch(const struct wmEvent *event);
#endif
/* wm_tooltip.c */
+
typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *C,
struct ARegion *region,
int *pass,
@@ -966,6 +1538,7 @@ void WM_tooltip_refresh(struct bContext *C, struct wmWindow *win);
double WM_tooltip_time_closed(void);
/* wm_utils.c */
+
struct wmGenericCallback *WM_generic_callback_steal(struct wmGenericCallback *callback);
void WM_generic_callback_free(struct wmGenericCallback *callback);
@@ -975,9 +1548,18 @@ bool WM_region_use_viewport(struct ScrArea *area, struct ARegion *region);
#ifdef WITH_XR_OPENXR
/* wm_xr_session.c */
+
+/**
+ * Check if the XR-Session was triggered.
+ * If an error happened while trying to start a session, this returns false too.
+ */
bool WM_xr_session_exists(const wmXrData *xr);
+/**
+ * Check if the session is running, according to the OpenXR definition.
+ */
bool WM_xr_session_is_ready(const wmXrData *xr);
struct wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr);
+struct ScrArea *WM_xr_session_area_get(const wmXrData *xr);
void WM_xr_session_base_pose_reset(wmXrData *xr);
bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3]);
bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4]);
@@ -996,10 +1578,21 @@ bool WM_xr_session_state_controller_aim_location_get(const wmXrData *xr,
bool WM_xr_session_state_controller_aim_rotation_get(const wmXrData *xr,
unsigned int subaction_idx,
float r_rotation[4]);
+bool WM_xr_session_state_nav_location_get(const wmXrData *xr, float r_location[3]);
+void WM_xr_session_state_nav_location_set(wmXrData *xr, const float location[3]);
+bool WM_xr_session_state_nav_rotation_get(const wmXrData *xr, float r_rotation[4]);
+void WM_xr_session_state_nav_rotation_set(wmXrData *xr, const float rotation[4]);
+bool WM_xr_session_state_nav_scale_get(const wmXrData *xr, float *r_scale);
+void WM_xr_session_state_nav_scale_set(wmXrData *xr, float scale);
+void WM_xr_session_state_navigation_reset(struct wmXrSessionState *state);
+
+struct ARegionType *WM_xr_surface_controller_region_type_get(void);
/* wm_xr_actions.c */
+
/* XR action functions to be called pre-XR session start.
* NOTE: The "destroy" functions can also be called post-session start. */
+
bool WM_xr_action_set_create(wmXrData *xr, const char *action_set_name);
void WM_xr_action_set_destroy(wmXrData *xr, const char *action_set_name);
bool WM_xr_action_create(wmXrData *xr,
@@ -1033,7 +1626,9 @@ void WM_xr_action_binding_destroy(wmXrData *xr,
const char *action_name,
const char *profile_path);
-/* If action_set_name is NULL, then all action sets will be treated as active. */
+/**
+ * If action_set_name is NULL, then all action sets will be treated as active.
+ */
bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name);
bool WM_xr_controller_pose_actions_set(wmXrData *xr,
@@ -1041,7 +1636,9 @@ bool WM_xr_controller_pose_actions_set(wmXrData *xr,
const char *grip_action_name,
const char *aim_action_name);
-/* XR action functions to be called post-XR session start. */
+/**
+ * XR action functions to be called post-XR session start.
+ */
bool WM_xr_action_state_get(const wmXrData *xr,
const char *action_set_name,
const char *action_name,
@@ -1060,9 +1657,13 @@ void WM_xr_haptic_action_stop(wmXrData *xr,
const char *subaction_path);
/* wm_xr_actionmap.c */
+
XrActionMap *WM_xr_actionmap_new(struct wmXrRuntimeData *runtime,
const char *name,
bool replace_existing);
+/**
+ * Ensure unique name among all action maps.
+ */
void WM_xr_actionmap_ensure_unique(struct wmXrRuntimeData *runtime, XrActionMap *actionmap);
XrActionMap *WM_xr_actionmap_add_copy(struct wmXrRuntimeData *runtime, XrActionMap *am_src);
bool WM_xr_actionmap_remove(struct wmXrRuntimeData *runtime, XrActionMap *actionmap);
@@ -1078,15 +1679,25 @@ void WM_xr_actionmap_selected_index_set(struct wmXrRuntimeData *runtime, short i
XrActionMapItem *WM_xr_actionmap_item_new(XrActionMap *actionmap,
const char *name,
bool replace_existing);
+/**
+ * Ensure unique name among all action map items.
+ */
void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem *ami);
XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionMapItem *ami_src);
bool WM_xr_actionmap_item_remove(XrActionMap *actionmap, XrActionMapItem *ami);
XrActionMapItem *WM_xr_actionmap_item_find(XrActionMap *actionmap, const char *name);
+/**
+ * Similar to #wm_xr_actionmap_item_properties_set()
+ * but checks for the #eXrActionType and #wmOperatorType having changed.
+ */
void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami);
XrActionMapBinding *WM_xr_actionmap_binding_new(XrActionMapItem *ami,
const char *name,
bool replace_existing);
+/**
+ * Ensure unique name among all action map bindings.
+ */
void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBinding *amb);
XrActionMapBinding *WM_xr_actionmap_binding_add_copy(XrActionMapItem *ami,
XrActionMapBinding *amb_src);
diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h
index 564afe084b9..4f1a2c8b923 100644
--- a/source/blender/windowmanager/WM_keymap.h
+++ b/source/blender/windowmanager/WM_keymap.h
@@ -26,6 +26,7 @@
/* dna-savable wmStructs here */
#include "BLI_utildefines.h"
#include "DNA_windowmanager_types.h"
+#include "WM_types.h"
#ifdef __cplusplus
extern "C" {
@@ -54,15 +55,15 @@ void WM_keyconfig_update_operatortype(void);
void WM_keymap_clear(struct wmKeyMap *keymap);
+/**
+ * Always add item.
+ */
wmKeyMapItem *WM_keymap_add_item(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
wmKeyMapItem *WM_keymap_add_item_copy(struct wmKeyMap *keymap, wmKeyMapItem *kmi_src);
bool WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi);
-int WM_keymap_item_to_string(const wmKeyMapItem *kmi,
- const bool compact,
- char *result,
- const int result_len);
+int WM_keymap_item_to_string(const wmKeyMapItem *kmi, bool compact, char *result, int result_len);
wmKeyMap *WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int regionid);
wmKeyMap *WM_keymap_list_find_spaceid_or_empty(ListBase *lb,
@@ -90,16 +91,30 @@ bool WM_keymap_item_compare(const struct wmKeyMapItem *k1, const struct wmKeyMap
/* keymap_utils.c */
-/** Wrappers for #WM_keymap_add_item */
+/* Wrappers for #WM_keymap_add_item */
+
+/**
+ * Menu wrapper for #WM_keymap_add_item.
+ */
wmKeyMapItem *WM_keymap_add_menu(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
+/**
+ * Pie-menu wrapper for #WM_keymap_add_item.
+ */
wmKeyMapItem *WM_keymap_add_menu_pie(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
+/**
+ * Panel (popover) wrapper for #WM_keymap_add_item.
+ */
wmKeyMapItem *WM_keymap_add_panel(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
+/**
+ * Tool wrapper for #WM_keymap_add_item.
+ */
wmKeyMapItem *WM_keymap_add_tool(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
+/** Useful for mapping numbers to an enum. */
void WM_keymap_add_context_enum_set_items(wmKeyMap *keymap,
const struct EnumPropertyItem *items,
const char *data_path,
@@ -109,28 +124,28 @@ void WM_keymap_add_context_enum_set_items(wmKeyMap *keymap,
int keymodifier);
wmKeyMap *WM_keymap_guess_from_context(const struct bContext *C);
+
+/**
+ * Guess an appropriate key-map from the operator name.
+ *
+ * \note Needs to be kept up to date with Key-map and Operator naming.
+ */
wmKeyMap *WM_keymap_guess_opname(const struct bContext *C, const char *opname);
-bool WM_keymap_uses_event_modifier(const wmKeyMap *keymap, const int event_modifier);
+bool WM_keymap_uses_event_modifier(const wmKeyMap *keymap, int event_modifier);
void WM_keymap_fix_linking(void);
/* Modal Keymap */
-int WM_modalkeymap_items_to_string(const struct wmKeyMap *km,
- const int propvalue,
- const bool compact,
- char *result,
- const int result_len);
-int WM_modalkeymap_operator_items_to_string(struct wmOperatorType *ot,
- const int propvalue,
- const bool compact,
- char *result,
- const int result_len);
+int WM_modalkeymap_items_to_string(
+ const struct wmKeyMap *km, int propvalue, bool compact, char *result, int result_len);
+int WM_modalkeymap_operator_items_to_string(
+ struct wmOperatorType *ot, int propvalue, bool compact, char *result, int result_len);
char *WM_modalkeymap_operator_items_to_string_buf(struct wmOperatorType *ot,
- const int propvalue,
- const bool compact,
- const int max_len,
+ int propvalue,
+ bool compact,
+ int max_len,
int *r_available_len,
char **r_result);
@@ -142,12 +157,15 @@ wmKeyMapItem *WM_modalkeymap_add_item(
struct wmKeyMap *km, int type, int val, int modifier, int keymodifier, int value);
wmKeyMapItem *WM_modalkeymap_add_item_str(
struct wmKeyMap *km, int type, int val, int modifier, int keymodifier, const char *value);
-const wmKeyMapItem *WM_modalkeymap_find_propvalue(const wmKeyMap *km, const int propvalue);
+const wmKeyMapItem *WM_modalkeymap_find_propvalue(const wmKeyMap *km, int propvalue);
void WM_modalkeymap_assign(struct wmKeyMap *km, const char *opname);
/* Keymap Editor */
void WM_keymap_restore_to_default(struct wmKeyMap *keymap, struct wmWindowManager *wm);
+/**
+ * Properties can be NULL, otherwise the arg passed is used and ownership is given to the `kmi`.
+ */
void WM_keymap_item_properties_reset(struct wmKeyMapItem *kmi, struct IDProperty *properties);
void WM_keymap_item_restore_to_default(wmWindowManager *wm,
struct wmKeyMap *keymap,
@@ -156,37 +174,41 @@ int WM_keymap_item_map_type_get(const struct wmKeyMapItem *kmi);
/* Key Event */
-const char *WM_key_event_string(const short type, const bool compact);
-int WM_keymap_item_raw_to_string(const short shift,
- const short ctrl,
- const short alt,
- const short oskey,
- const short keymodifier,
- const short val,
- const short type,
- const bool compact,
+const char *WM_key_event_string(short type, bool compact);
+int WM_keymap_item_raw_to_string(short shift,
+ short ctrl,
+ short alt,
+ short oskey,
+ short keymodifier,
+ short val,
+ short type,
+ bool compact,
char *result,
- const int result_len);
+ int result_len);
+/**
+ * \param include_mask, exclude_mask:
+ * Event types to include/exclude when looking up keys (#eEventType_Mask).
+ */
wmKeyMapItem *WM_key_event_operator(const struct bContext *C,
const char *opname,
- int opcontext,
+ wmOperatorCallContext opcontext,
struct IDProperty *properties,
- const short include_mask,
- const short exclude_mask,
+ short include_mask,
+ short exclude_mask,
struct wmKeyMap **r_keymap);
char *WM_key_event_operator_string(const struct bContext *C,
const char *opname,
- int opcontext,
+ wmOperatorCallContext opcontext,
struct IDProperty *properties,
- const bool is_strict,
+ bool is_strict,
char *result,
- const int result_len);
+ int result_len);
wmKeyMapItem *WM_key_event_operator_from_keymap(struct wmKeyMap *keymap,
const char *opname,
struct IDProperty *properties,
- const short include_mask,
- const short exclude_mask);
+ short include_mask,
+ short exclude_mask);
const char *WM_bool_as_string(bool test);
diff --git a/source/blender/windowmanager/WM_toolsystem.h b/source/blender/windowmanager/WM_toolsystem.h
index 018165634f2..32b9cf1d7ba 100644
--- a/source/blender/windowmanager/WM_toolsystem.h
+++ b/source/blender/windowmanager/WM_toolsystem.h
@@ -69,6 +69,9 @@ void WM_toolsystem_unlink(struct bContext *C, struct WorkSpace *workspace, const
void WM_toolsystem_refresh(struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey);
void WM_toolsystem_reinit(struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey);
+/**
+ * Operate on all active tools.
+ */
void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace);
void WM_toolsystem_refresh_all(struct bContext *C, struct WorkSpace *workspace);
void WM_toolsystem_reinit_all(struct bContext *C, struct wmWindow *win);
@@ -79,6 +82,12 @@ void WM_toolsystem_ref_set_from_runtime(struct bContext *C,
const struct bToolRef_Runtime *tref_rt,
const char *idname);
+/**
+ * Sync the internal active state of a tool back into the tool system,
+ * this is needed for active brushes where the real active state is not stored in the tool system.
+ *
+ * \see #toolsystem_ref_link
+ */
void WM_toolsystem_ref_sync_from_context(struct Main *bmain,
struct WorkSpace *workspace,
struct bToolRef *tref);
@@ -98,8 +107,12 @@ void WM_toolsystem_update_from_context(struct bContext *C,
struct ViewLayer *view_layer,
struct ScrArea *area);
+/**
+ * For paint modes to support non-brush tools.
+ */
bool WM_toolsystem_active_tool_is_brush(const struct bContext *C);
+/** Follow #wmMsgNotifyFn spec. */
void WM_toolsystem_do_msg_notify_tag_refresh(struct bContext *C,
struct wmMsgSubscribeKey *msg_key,
struct wmMsgSubscribeValue *msg_val);
@@ -129,11 +142,20 @@ void WM_toolsystem_ref_properties_init_for_keymap(struct bToolRef *tref,
struct PointerRNA *src_ptr,
struct wmOperatorType *ot);
+/**
+ * Use to update the active tool (shown in the top bar) in the least disruptive way.
+ *
+ * This is a little involved since there may be multiple valid active tools
+ * depending on the mode and space type.
+ *
+ * Used when undoing since the active mode may have changed.
+ */
void WM_toolsystem_refresh_active(struct bContext *C);
void WM_toolsystem_refresh_screen_area(struct WorkSpace *workspace,
struct ViewLayer *view_layer,
struct ScrArea *area);
+void WM_toolsystem_refresh_screen_window(struct wmWindow *win);
void WM_toolsystem_refresh_screen_all(struct Main *bmain);
#ifdef __cplusplus
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index df6dc3af3cb..d1f790ce3e2 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -118,8 +118,11 @@ struct wmOperator;
struct wmWindowManager;
#include "BLI_compiler_attrs.h"
+#include "BLI_utildefines.h"
#include "DNA_listBase.h"
+#include "DNA_uuid_types.h"
#include "DNA_vec_types.h"
+#include "DNA_xr_types.h"
#include "RNA_types.h"
/* exported types for WM */
@@ -209,7 +212,7 @@ enum {
* Context to call operator in for #WM_operator_name_call.
* rna_ui.c contains EnumPropertyItem's of these, keep in sync.
*/
-enum {
+typedef enum wmOperatorCallContext {
/* if there's invoke, call it, otherwise exec */
WM_OP_INVOKE_DEFAULT,
WM_OP_INVOKE_REGION_WIN,
@@ -224,7 +227,13 @@ enum {
WM_OP_EXEC_REGION_PREVIEW,
WM_OP_EXEC_AREA,
WM_OP_EXEC_SCREEN,
-};
+} wmOperatorCallContext;
+
+#define WM_OP_CONTEXT_HAS_AREA(type) \
+ (CHECK_TYPE_INLINE(type, wmOperatorCallContext), \
+ !ELEM(type, WM_OP_INVOKE_SCREEN, WM_OP_EXEC_SCREEN))
+#define WM_OP_CONTEXT_HAS_REGION(type) \
+ (WM_OP_CONTEXT_HAS_AREA(type) && !ELEM(type, WM_OP_INVOKE_AREA, WM_OP_EXEC_AREA))
/* property tags for RNA_OperatorProperties */
typedef enum eOperatorPropTags {
@@ -457,6 +466,10 @@ typedef struct wmNotifier {
#define ND_ASSET_LIST (1 << 16)
#define ND_ASSET_LIST_PREVIEW (2 << 16)
#define ND_ASSET_LIST_READING (3 << 16)
+/* Catalog data changed, requiring a redraw of catalog UIs. Note that this doesn't denote a
+ * reloading of asset libraries & their catalogs should happen. That only happens on explicit user
+ * action. */
+#define ND_ASSET_CATALOGS (4 << 16)
/* subtype, 256 entries too */
#define NOTE_SUBTYPE 0x0000FF00
@@ -588,10 +601,10 @@ typedef struct wmTabletData {
* - The previous values are only set for mouse button and keyboard events.
* See: #ISMOUSE_BUTTON & #ISKEYBOARD macros.
*
- * - Previous x/y are exceptions: #wmEvent.prevx & #wmEvent.prevy
+ * - Previous x/y are exceptions: #wmEvent.prev
* these are set on mouse motion, see #MOUSEMOVE & track-pad events.
*
- * - Modal key-map handling sets `prevval` & `prevtype` to `val` & `type`,
+ * - Modal key-map handling sets `prev_val` & `prev_type` to `val` & `type`,
* this allows modal keys-maps to check the original values (needed in some cases).
*/
typedef struct wmEvent {
@@ -602,7 +615,7 @@ typedef struct wmEvent {
/** Press, release, scroll-value. */
short val;
/** Mouse pointer position, screen coord. */
- int x, y;
+ int xy[2];
/** Region relative mouse position (name convention before Blender 2.5). */
int mval[2];
/**
@@ -623,19 +636,19 @@ typedef struct wmEvent {
char is_repeat;
/** The previous value of `type`. */
- short prevtype;
+ short prev_type;
/** The previous value of `val`. */
- short prevval;
+ short prev_val;
/** The time when the key is pressed, see #PIL_check_seconds_timer. */
- double prevclicktime;
+ double prev_click_time;
/** The location when the key is pressed (used to enforce drag thresholds). */
- int prevclickx, prevclicky;
+ int prev_click_xy[2];
/**
- * The previous value of #wmEvent.x #wmEvent.y,
+ * The previous value of #wmEvent.xy,
* Unlike other previous state variables, this is set on any mouse motion.
- * Use `prevclickx` & `prevclicky` for the value at time of pressing.
+ * Use `prev_click` for the value at time of pressing.
*/
- int prevx, prevy;
+ int prev_xy[2];
/** Modifier states. */
/** 'oskey' is apple or windows-key, value denotes order of pressed. */
@@ -649,14 +662,14 @@ typedef struct wmEvent {
/* Custom data. */
/** Custom data type, stylus, 6dof, see wm_event_types.h */
short custom;
- short customdatafree;
+ short customdata_free;
int pad2;
/** Ascii, unicode, mouse-coords, angles, vectors, NDOF data, drag-drop info. */
void *customdata;
/**
* True if the operating system inverted the delta x/y values and resulting
- * `prevx`, `prevy` values, for natural scroll direction.
+ * `prev_xy` values, for natural scroll direction.
* For absolute scroll direction, the delta must be negated again.
*/
char is_direction_inverted;
@@ -721,11 +734,41 @@ typedef struct wmXrActionState {
};
int type; /* eXrActionType */
} wmXrActionState;
+
+typedef struct wmXrActionData {
+ /** Action set name. */
+ char action_set[64];
+ /** Action name. */
+ char action[64];
+ /** Type. */
+ eXrActionType type;
+ /** State. Set appropriately based on type. */
+ float state[2];
+ /** State of the other sub-action path for bimanual actions. */
+ float state_other[2];
+
+ /** Input threshold for float/vector2f actions. */
+ float float_threshold;
+
+ /** Controller aim pose corresponding to the action's sub-action path. */
+ float controller_loc[3];
+ float controller_rot[4];
+ /** Controller aim pose of the other sub-action path for bimanual actions. */
+ float controller_loc_other[3];
+ float controller_rot_other[4];
+
+ /** Operator. */
+ struct wmOperatorType *ot;
+ struct IDProperty *op_properties;
+
+ /** Whether bimanual interaction is occurring. */
+ bool bimanual;
+} wmXrActionData;
#endif
/** Timer flags. */
typedef enum {
- /** Do not attempt to free customdata pointer even if non-NULL. */
+ /** Do not attempt to free custom-data pointer even if non-NULL. */
WM_TIMER_NO_FREE_CUSTOM_DATA = 1 << 0,
} wmTimerFlags;
@@ -868,6 +911,9 @@ typedef struct wmOperatorType {
/** RNA integration */
ExtensionRNA rna_ext;
+ /** Cursor to use when waiting for cursor input, see: #OPTYPE_DEPENDS_ON_CURSOR. */
+ int cursor_pending;
+
/** Flag last for padding */
short flag;
@@ -880,7 +926,7 @@ typedef struct wmOperatorType {
typedef struct wmOperatorCallParams {
struct wmOperatorType *optype;
struct PointerRNA *opptr;
- short opcontext;
+ wmOperatorCallContext opcontext;
} wmOperatorCallParams;
#ifdef WITH_INPUT_IME
@@ -915,17 +961,23 @@ typedef void (*wmPaintCursorDraw)(struct bContext *C, int, int, void *customdata
#define WM_DRAG_ID 0
#define WM_DRAG_ASSET 1
-#define WM_DRAG_RNA 2
-#define WM_DRAG_PATH 3
-#define WM_DRAG_NAME 4
-#define WM_DRAG_VALUE 5
-#define WM_DRAG_COLOR 6
-#define WM_DRAG_DATASTACK 7
-
-typedef enum wmDragFlags {
+/** The user is dragging multiple assets. This is only supported in few specific cases, proper
+ * multi-item support for dragging isn't supported well yet. Therefore this is kept separate from
+ * #WM_DRAG_ASSET. */
+#define WM_DRAG_ASSET_LIST 2
+#define WM_DRAG_RNA 3
+#define WM_DRAG_PATH 4
+#define WM_DRAG_NAME 5
+#define WM_DRAG_VALUE 6
+#define WM_DRAG_COLOR 7
+#define WM_DRAG_DATASTACK 8
+#define WM_DRAG_ASSET_CATALOG 9
+
+typedef enum eWM_DragFlags {
WM_DRAG_NOP = 0,
WM_DRAG_FREE_DATA = 1,
-} wmDragFlags;
+} eWM_DragFlags;
+ENUM_OPERATORS(eWM_DragFlags, WM_DRAG_FREE_DATA)
/* NOTE: structs need not exported? */
@@ -943,14 +995,66 @@ typedef struct wmDragAsset {
/* Always freed. */
const char *path;
int id_type;
+ struct AssetMetaData *metadata;
int import_type; /* eFileAssetImportType */
+
+ /* FIXME: This is temporary evil solution to get scene/view-layer/etc in the copy callback of the
+ * #wmDropBox.
+ * TODO: Handle link/append in operator called at the end of the drop process, and NOT in its
+ * copy callback.
+ * */
+ struct bContext *evil_C;
} wmDragAsset;
+typedef struct wmDragAssetCatalog {
+ bUUID drag_catalog_id;
+} wmDragAssetCatalog;
+
+/**
+ * For some specific cases we support dragging multiple assets (#WM_DRAG_ASSET_LIST). There is no
+ * proper support for dragging multiple items in the `wmDrag`/`wmDrop` API yet, so this is really
+ * just to enable specific features for assets.
+ *
+ * This struct basically contains a tagged union to either store a local ID pointer, or information
+ * about an externally stored asset.
+ */
+typedef struct wmDragAssetListItem {
+ struct wmDragAssetListItem *next, *prev;
+
+ union {
+ struct ID *local_id;
+ wmDragAsset *external_info;
+ } asset_data;
+
+ bool is_external;
+} wmDragAssetListItem;
+
typedef char *(*WMDropboxTooltipFunc)(struct bContext *,
struct wmDrag *,
- const struct wmEvent *event,
+ const int xy[2],
struct wmDropBox *drop);
+typedef struct wmDragActiveDropState {
+ /** Informs which dropbox is activated with the drag item.
+ * When this value changes, the #draw_activate and #draw_deactivate dropbox callbacks are
+ * triggered.
+ */
+ struct wmDropBox *active_dropbox;
+
+ /** If `active_dropbox` is set, the area it successfully polled in. To restore the context of it
+ * as needed. */
+ struct ScrArea *area_from;
+ /** If `active_dropbox` is set, the region it successfully polled in. To restore the context of
+ * it as needed. */
+ struct ARegion *region_from;
+
+ /** Text to show when a dropbox poll succeeds (so the dropbox itself is available) but the
+ * operator poll fails. Typically the message the operator set with
+ * CTX_wm_operator_poll_msg_set(). */
+ const char *disabled_info;
+ bool free_disabled_info;
+} wmDragActiveDropState;
+
typedef struct wmDrag {
struct wmDrag *next, *prev;
@@ -966,17 +1070,23 @@ typedef struct wmDrag {
float scale;
int sx, sy;
- /** If filled, draws operator tooltip/operator name. */
- char tooltip[200];
- unsigned int flags;
+ wmDragActiveDropState drop_state;
+
+ eWM_DragFlags flags;
/** List of wmDragIDs, all are guaranteed to have the same ID type. */
ListBase ids;
+ /** List of `wmDragAssetListItem`s. */
+ ListBase asset_items;
} wmDrag;
/**
* Dropboxes are like keymaps, part of the screen/area/region definition.
* Allocation and free is on startup and exit.
+ *
+ * The operator is polled and invoked with the current context (#WM_OP_INVOKE_DEFAULT), there is no
+ * way to override that (by design, since dropboxes should act on the exact mouse position). So the
+ * drop-boxes are supposed to check the required area and region context in their poll.
*/
typedef struct wmDropBox {
struct wmDropBox *next, *prev;
@@ -993,6 +1103,18 @@ typedef struct wmDropBox {
*/
void (*cancel)(struct Main *, struct wmDrag *, struct wmDropBox *);
+ /** Override the default drawing function. */
+ void (*draw)(struct bContext *, struct wmWindow *, struct wmDrag *, const int *);
+
+ /** Called when pool returns true the first time. */
+ void (*draw_activate)(struct wmDropBox *, struct wmDrag *drag);
+
+ /** Called when pool returns false the first time or when the drag event ends. */
+ void (*draw_deactivate)(struct wmDropBox *, struct wmDrag *drag);
+
+ /** Custom data for drawing. */
+ void *draw_data;
+
/** Custom tooltip shown during dragging. */
WMDropboxTooltipFunc tooltip;
@@ -1006,10 +1128,6 @@ typedef struct wmDropBox {
struct IDProperty *properties;
/** RNA pointer to access properties. */
struct PointerRNA *ptr;
-
- /** Default invoke. */
- short opcontext;
-
} wmDropBox;
/**
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
index c7a4b064d0e..5bcb9b195bf 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
@@ -61,19 +61,42 @@ extern "C" {
struct wmGizmo *WM_gizmo_new_ptr(const struct wmGizmoType *gzt,
struct wmGizmoGroup *gzgroup,
struct PointerRNA *properties);
+/**
+ * \param idname: Must be a valid gizmo type name,
+ * if you need to check it exists use #WM_gizmo_new_ptr
+ * because callers of this function don't NULL check the return value.
+ */
struct wmGizmo *WM_gizmo_new(const char *idname,
struct wmGizmoGroup *gzgroup,
struct PointerRNA *properties);
+/**
+ * \warning this doesn't check #wmGizmoMap (highlight, selection etc).
+ * Typical use is when freeing the windowing data,
+ * where caller can manage clearing selection, highlight... etc.
+ */
void WM_gizmo_free(struct wmGizmo *gz);
+/**
+ * Free \a gizmo and unlink from \a gizmolist.
+ * \a gizmolist is allowed to be NULL.
+ */
void WM_gizmo_unlink(ListBase *gizmolist,
struct wmGizmoMap *gzmap,
struct wmGizmo *gz,
struct bContext *C);
+/**
+ * Remove from selection array without running callbacks.
+ */
bool WM_gizmo_select_unlink(struct wmGizmoMap *gzmap, struct wmGizmo *gz);
bool WM_gizmo_select_set(struct wmGizmoMap *gzmap, struct wmGizmo *gz, bool select);
bool WM_gizmo_highlight_set(struct wmGizmoMap *gzmap, struct wmGizmo *gz);
+/**
+ * Special function to run from setup so gizmos start out interactive.
+ *
+ * We could do this when linking them,
+ * but this complicates things since the window update code needs to run first.
+ */
void WM_gizmo_modal_set_from_setup(struct wmGizmoMap *gzmap,
struct bContext *C,
struct wmGizmo *gz,
@@ -87,24 +110,37 @@ struct PointerRNA *WM_gizmo_operator_set(struct wmGizmo *gz,
struct IDProperty *properties);
int WM_gizmo_operator_invoke(struct bContext *C, struct wmGizmo *gz, struct wmGizmoOpElem *gzop);
-/* callbacks */
+/* Callbacks. */
+
void WM_gizmo_set_fn_custom_modal(struct wmGizmo *gz, wmGizmoFnModal fn);
void WM_gizmo_set_matrix_location(struct wmGizmo *gz, const float origin[3]);
+/**
+ * #wmGizmo.matrix utility, set the orientation by it's Z axis.
+ */
void WM_gizmo_set_matrix_rotation_from_z_axis(struct wmGizmo *gz, const float z_axis[3]);
+/**
+ * #wmGizmo.matrix utility, set the orientation by it's Y/Z axis.
+ */
void WM_gizmo_set_matrix_rotation_from_yz_axis(struct wmGizmo *gz,
const float y_axis[3],
const float z_axis[3]);
void WM_gizmo_set_matrix_offset_location(struct wmGizmo *gz, const float offset[3]);
+/**
+ * #wmGizmo.matrix_offset utility, set the orientation by it's Z axis.
+ */
void WM_gizmo_set_matrix_offset_rotation_from_z_axis(struct wmGizmo *gz, const float z_axis[3]);
+/**
+ * #wmGizmo.matrix_offset utility, set the orientation by it's Y/Z axis.
+ */
void WM_gizmo_set_matrix_offset_rotation_from_yz_axis(struct wmGizmo *gz,
const float y_axis[3],
const float z_axis[3]);
-void WM_gizmo_set_flag(struct wmGizmo *gz, const int flag, const bool enable);
-void WM_gizmo_set_scale(struct wmGizmo *gz, const float scale);
-void WM_gizmo_set_line_width(struct wmGizmo *gz, const float line_width);
+void WM_gizmo_set_flag(struct wmGizmo *gz, int flag, bool enable);
+void WM_gizmo_set_scale(struct wmGizmo *gz, float scale);
+void WM_gizmo_set_line_width(struct wmGizmo *gz, float line_width);
void WM_gizmo_get_color(const struct wmGizmo *gz, float color[4]);
void WM_gizmo_set_color(struct wmGizmo *gz, const float color[4]);
@@ -128,14 +164,30 @@ void WM_gizmo_calc_matrix_final_no_offset(const struct wmGizmo *gz, float r_mat[
void WM_gizmo_calc_matrix_final(const struct wmGizmo *gz, float r_mat[4][4]);
-/* properties */
+/* Properties. */
+
void WM_gizmo_properties_create_ptr(struct PointerRNA *ptr, struct wmGizmoType *gzt);
void WM_gizmo_properties_create(struct PointerRNA *ptr, const char *gtstring);
+/**
+ * Similar to #WM_gizmo_properties_create
+ * except its uses ID properties used for key-maps and macros.
+ */
void WM_gizmo_properties_alloc(struct PointerRNA **ptr,
struct IDProperty **properties,
const char *gtstring);
-void WM_gizmo_properties_sanitize(struct PointerRNA *ptr, const bool no_context);
-bool WM_gizmo_properties_default(struct PointerRNA *ptr, const bool do_update);
+void WM_gizmo_properties_sanitize(struct PointerRNA *ptr, bool no_context);
+/**
+ * Set all props to their default.
+ *
+ * \param do_update: Only update un-initialized props.
+ *
+ * \note There's nothing specific to gizmos here.
+ * This could be made a general function.
+ */
+bool WM_gizmo_properties_default(struct PointerRNA *ptr, bool do_update);
+/**
+ * Remove all props without #PROP_SKIP_SAVE.
+ */
void WM_gizmo_properties_reset(struct wmGizmo *gz);
void WM_gizmo_properties_clear(struct PointerRNA *ptr);
void WM_gizmo_properties_free(struct PointerRNA *ptr);
@@ -146,7 +198,13 @@ void WM_gizmotype_append(void (*gtfunc)(struct wmGizmoType *));
void WM_gizmotype_append_ptr(void (*gtfunc)(struct wmGizmoType *, void *), void *userdata);
bool WM_gizmotype_remove(struct bContext *C, struct Main *bmain, const char *idname);
void WM_gizmotype_remove_ptr(struct bContext *C, struct Main *bmain, struct wmGizmoType *gzt);
+/**
+ * Free but don't remove from #GHash.
+ */
void WM_gizmotype_free_ptr(struct wmGizmoType *gzt);
+/**
+ * Caller must free.
+ */
void WM_gizmotype_iter(struct GHashIterator *ghi);
/* wm_gizmo_group_type.c */
@@ -155,8 +213,15 @@ struct wmGizmoGroupType *WM_gizmogrouptype_append(void (*wtfunc)(struct wmGizmoG
struct wmGizmoGroupType *WM_gizmogrouptype_append_ptr(void (*wtfunc)(struct wmGizmoGroupType *,
void *),
void *userdata);
+/**
+ * Caller must free.
+ */
void WM_gizmogrouptype_iter(struct GHashIterator *ghi);
+/**
+ * Append and insert into a gizmo typemap.
+ * This is most common for C gizmos which are enabled by default.
+ */
struct wmGizmoGroupTypeRef *WM_gizmogrouptype_append_and_link(
struct wmGizmoMapType *gzmap_type, void (*wtfunc)(struct wmGizmoGroupType *));
@@ -167,6 +232,10 @@ void WM_gizmoconfig_update_tag_group_type_init(struct wmGizmoMapType *gzmap_type
struct wmGizmoGroupType *gzgt);
void WM_gizmoconfig_update_tag_group_type_remove(struct wmGizmoMapType *gzmap_type,
struct wmGizmoGroupType *gzgt);
+/**
+ * Run in case new types have been added (runs often, early exit where possible).
+ * Follows #WM_keyconfig_update conventions.
+ */
void WM_gizmoconfig_update(struct Main *bmain);
void WM_gizmoconfig_update_tag_group_remove(struct wmGizmoMap *gzmap);
@@ -205,7 +274,7 @@ float WM_gizmo_target_property_float_get(const struct wmGizmo *gz,
void WM_gizmo_target_property_float_set(struct bContext *C,
const struct wmGizmo *gz,
struct wmGizmoProperty *gz_prop,
- const float value);
+ float value);
void WM_gizmo_target_property_float_get_array(const struct wmGizmo *gz,
struct wmGizmoProperty *gz_prop,
@@ -222,7 +291,8 @@ bool WM_gizmo_target_property_float_range_get(const struct wmGizmo *gz,
int WM_gizmo_target_property_array_length(const struct wmGizmo *gz,
struct wmGizmoProperty *gz_prop);
-/* definitions */
+/* Definitions. */
+
const struct wmGizmoPropertyType *WM_gizmotype_target_property_find(const struct wmGizmoType *gzt,
const char *idname);
void WM_gizmotype_target_property_def(struct wmGizmoType *gzt,
@@ -230,14 +300,21 @@ void WM_gizmotype_target_property_def(struct wmGizmoType *gzt,
int data_type,
int array_length);
-/* utilities */
+/* Utilities. */
+
void WM_gizmo_do_msg_notify_tag_refresh(struct bContext *C,
struct wmMsgSubscribeKey *msg_key,
struct wmMsgSubscribeValue *msg_val);
+/**
+ * Runs on the "prepare draw" pass, drawing the region clears.
+ */
void WM_gizmo_target_property_subscribe_all(struct wmGizmo *gz,
struct wmMsgBus *mbus,
struct ARegion *region);
+/**
+ * Auto-key function if auto-key is enabled.
+ */
void WM_gizmo_target_property_anim_autokey(struct bContext *C,
const struct wmGizmo *gz,
struct wmGizmoProperty *gz_prop);
@@ -256,6 +333,7 @@ struct wmKeyMap *WM_gizmogroup_setup_keymap_generic_maybe_drag(const struct wmGi
struct wmKeyConfig *kc);
/* Utility functions (not callbacks). */
+
struct wmKeyMap *WM_gizmo_keymap_generic_with_keyconfig(struct wmKeyConfig *kc);
struct wmKeyMap *WM_gizmo_keymap_generic(struct wmWindowManager *wm);
@@ -268,19 +346,29 @@ struct wmKeyMap *WM_gizmo_keymap_generic_drag(struct wmWindowManager *wm);
struct wmKeyMap *WM_gizmo_keymap_generic_click_drag_with_keyconfig(struct wmKeyConfig *kc);
struct wmKeyMap *WM_gizmo_keymap_generic_click_drag(struct wmWindowManager *wm);
+/**
+ * Drag or press depending on preference.
+ */
struct wmKeyMap *WM_gizmo_keymap_generic_maybe_drag_with_keyconfig(struct wmKeyConfig *kc);
struct wmKeyMap *WM_gizmo_keymap_generic_maybe_drag(struct wmWindowManager *wm);
void WM_gizmogroup_ensure_init(const struct bContext *C, struct wmGizmoGroup *gzgroup);
/* Sort utilities for use with 'BLI_listbase_sort'. */
+
int WM_gizmo_cmp_temp_fl(const void *gz_a_ptr, const void *gz_b_ptr);
int WM_gizmo_cmp_temp_fl_reverse(const void *gz_a_ptr, const void *gz_b_ptr);
/* -------------------------------------------------------------------- */
/* wmGizmoMap */
+/**
+ * Creates a gizmo-map with all registered gizmos for that type
+ */
struct wmGizmoMap *WM_gizmomap_new_from_type(const struct wmGizmoMapType_Params *gzmap_params);
+/**
+ * Re-create the gizmos (use when changing theme settings).
+ */
void WM_gizmomap_reinit(struct wmGizmoMap *gzmap);
const struct ListBase *WM_gizmomap_group_list(struct wmGizmoMap *gzmap);
struct wmGizmoGroup *WM_gizmomap_group_find(struct wmGizmoMap *gzmap, const char *idname);
@@ -288,23 +376,31 @@ struct wmGizmoGroup *WM_gizmomap_group_find_ptr(struct wmGizmoMap *gzmap,
const struct wmGizmoGroupType *gzgt);
eWM_GizmoFlagMapDrawStep WM_gizmomap_drawstep_from_gizmo_group(const struct wmGizmoGroup *gzgroup);
-void WM_gizmomap_tag_refresh_drawstep(struct wmGizmoMap *gzmap,
- const eWM_GizmoFlagMapDrawStep drawstep);
+void WM_gizmomap_tag_refresh_drawstep(struct wmGizmoMap *gzmap, eWM_GizmoFlagMapDrawStep drawstep);
void WM_gizmomap_tag_refresh(struct wmGizmoMap *gzmap);
bool WM_gizmomap_tag_delay_refresh_for_tweak_check(struct wmGizmoMap *gzmap);
void WM_gizmomap_draw(struct wmGizmoMap *gzmap,
const struct bContext *C,
- const eWM_GizmoFlagMapDrawStep drawstep);
+ eWM_GizmoFlagMapDrawStep drawstep);
void WM_gizmomap_add_handlers(struct ARegion *region, struct wmGizmoMap *gzmap);
-bool WM_gizmomap_select_all(struct bContext *C, struct wmGizmoMap *gzmap, const int action);
+/**
+ * Select/Deselect all selectable gizmos in \a gzmap.
+ * \return if selection has changed.
+ *
+ * TODO: select all by type.
+ */
+bool WM_gizmomap_select_all(struct bContext *C, struct wmGizmoMap *gzmap, int action);
bool WM_gizmomap_cursor_set(const struct wmGizmoMap *gzmap, struct wmWindow *win);
void WM_gizmomap_message_subscribe(const struct bContext *C,
struct wmGizmoMap *gzmap,
struct ARegion *region,
struct wmMsgBus *mbus);
bool WM_gizmomap_is_any_selected(const struct wmGizmoMap *gzmap);
+/**
+ * \note We could use a callback to define bounds, for now just use matrix location.
+ */
bool WM_gizmomap_minmax(const struct wmGizmoMap *gzmap,
bool use_hidden,
bool use_select,
@@ -327,6 +423,10 @@ struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find(struct wmGizmoMapType *gz
const char *idname);
struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find_ptr(struct wmGizmoMapType *gzmap_type,
const struct wmGizmoGroupType *gzgt);
+/**
+ * Use this for registering gizmos on startup.
+ * For runtime, use #WM_gizmomaptype_group_link_runtime.
+ */
struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_link(struct wmGizmoMapType *gzmap_type,
const char *idname);
struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_link_ptr(struct wmGizmoMapType *gzmap_type,
@@ -345,6 +445,9 @@ void WM_gizmomaptype_group_unlink(struct bContext *C,
struct wmGizmoMapType *gzmap_type,
const struct wmGizmoGroupType *gzgt);
+/**
+ * Unlike #WM_gizmomaptype_group_unlink this doesn't maintain correct state, simply free.
+ */
void WM_gizmomaptype_group_free(struct wmGizmoGroupTypeRef *gzgt);
/* -------------------------------------------------------------------- */
@@ -362,6 +465,9 @@ bool WM_gizmo_group_type_ensure_ptr_ex(struct wmGizmoGroupType *gzgt,
bool WM_gizmo_group_type_ensure_ptr(struct wmGizmoGroupType *gzgt);
bool WM_gizmo_group_type_ensure(const char *idname);
+/**
+ * Call #WM_gizmo_group_type_free_ptr after to remove & free.
+ */
void WM_gizmo_group_type_remove_ptr_ex(struct Main *bmain,
struct wmGizmoGroupType *gzgt,
struct wmGizmoMapType *gzmap_type);
@@ -380,7 +486,9 @@ void WM_gizmo_group_unlink_delayed_ptr_from_space(struct wmGizmoGroupType *gzgt,
void WM_gizmo_group_type_free_ptr(wmGizmoGroupType *gzgt);
bool WM_gizmo_group_type_free(const char *idname);
-/* Has the result of unlinking and linking (re-initializes gizmo's). */
+/**
+ * Has the result of unlinking and linking (re-initializes gizmo's).
+ */
void WM_gizmo_group_type_reinit_ptr_ex(struct Main *bmain,
struct wmGizmoGroupType *gzgt,
struct wmGizmoMapType *gzmap_type);
@@ -388,6 +496,7 @@ void WM_gizmo_group_type_reinit_ptr(struct Main *bmain, struct wmGizmoGroupType
void WM_gizmo_group_type_reinit(struct Main *bmain, const char *idname);
/* Utilities */
+
bool WM_gizmo_context_check_drawstep(const struct bContext *C, eWM_GizmoFlagMapDrawStep step);
void WM_gizmo_group_remove_by_tool(struct bContext *C,
@@ -398,6 +507,7 @@ void WM_gizmo_group_remove_by_tool(struct bContext *C,
void WM_gizmo_group_tag_remove(struct wmGizmoGroup *gzgroup);
/* Wrap Group Type Callbacks. */
+
bool WM_gizmo_group_type_poll(const struct bContext *C, const struct wmGizmoGroupType *gzgt);
void WM_gizmo_group_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h
index a1edc4196dc..8bf82a41c91 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h
@@ -29,6 +29,7 @@
#pragma once
#include "BLI_compiler_attrs.h"
+#include "BLI_utildefines.h"
struct wmGizmo;
struct wmGizmoGroup;
@@ -163,6 +164,8 @@ typedef enum eWM_GizmoFlagGroupTypeFlag {
WM_GIZMOGROUPTYPE_VR_REDRAWS = (1 << 10),
} eWM_GizmoFlagGroupTypeFlag;
+ENUM_OPERATORS(eWM_GizmoFlagGroupTypeFlag, WM_GIZMOGROUPTYPE_VR_REDRAWS);
+
/**
* #wmGizmoGroup.init_flag
*/
@@ -380,7 +383,7 @@ typedef struct wmGizmoType {
/**
* Returns screen-space bounding box in the window space
- * (compatible with #wmEvent.x #wmEvent.y).
+ * (compatible with #wmEvent.xy).
*
* Used for tool-tip placement (otherwise the cursor location is used).
*/
@@ -502,8 +505,6 @@ typedef struct wmGizmoGroup {
bool tag_remove;
- bool use_fallback_keymap;
-
void *customdata;
/** For freeing customdata from above. */
void (*customdata_free)(void *);
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
index cfedd67b2f0..d4f11c79d46 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
@@ -106,11 +106,6 @@ wmGizmo *WM_gizmo_new_ptr(const wmGizmoType *gzt, wmGizmoGroup *gzgroup, Pointer
return gz;
}
-/**
- * \param idname: Must be a valid gizmo type name,
- * if you need to check it exists use #WM_gizmo_new_ptr
- * because callers of this function don't NULL check the return value.
- */
wmGizmo *WM_gizmo_new(const char *idname, wmGizmoGroup *gzgroup, PointerRNA *properties)
{
const wmGizmoType *gzt = WM_gizmotype_find(idname, false);
@@ -143,11 +138,6 @@ static void wm_gizmo_register(wmGizmoGroup *gzgroup, wmGizmo *gz)
wm_gizmogroup_gizmo_register(gzgroup, gz);
}
-/**
- * \warning this doesn't check #wmGizmoMap (highlight, selection etc).
- * Typical use is when freeing the windowing data,
- * where caller can manage clearing selection, highlight... etc.
- */
void WM_gizmo_free(wmGizmo *gz)
{
if (gz->type->free != NULL) {
@@ -187,10 +177,6 @@ void WM_gizmo_free(wmGizmo *gz)
MEM_freeN(gz);
}
-/**
- * Free \a gizmo and unlink from \a gizmolist.
- * \a gizmolist is allowed to be NULL.
- */
void WM_gizmo_unlink(ListBase *gizmolist, wmGizmoMap *gzmap, wmGizmo *gz, bContext *C)
{
if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) {
@@ -300,9 +286,6 @@ static void wm_gizmo_set_matrix_rotation_from_yz_axis__internal(float matrix[4][
normalize_v3(matrix[0]);
}
-/**
- * wmGizmo.matrix utils.
- */
void WM_gizmo_set_matrix_rotation_from_z_axis(wmGizmo *gz, const float z_axis[3])
{
wm_gizmo_set_matrix_rotation_from_z_axis__internal(gz->matrix_basis, z_axis);
@@ -318,9 +301,6 @@ void WM_gizmo_set_matrix_location(wmGizmo *gz, const float origin[3])
copy_v3_v3(gz->matrix_basis[3], origin);
}
-/**
- * wmGizmo.matrix_offset utils.
- */
void WM_gizmo_set_matrix_offset_rotation_from_z_axis(wmGizmo *gz, const float z_axis[3])
{
wm_gizmo_set_matrix_rotation_from_z_axis__internal(gz->matrix_offset, z_axis);
@@ -388,12 +368,7 @@ void WM_gizmo_set_fn_custom_modal(struct wmGizmo *gz, wmGizmoFnModal fn)
/** \} */
/* -------------------------------------------------------------------- */
-/**
- * Add/Remove \a gizmo to selection.
- * Reallocates memory for selected gizmos so better not call for selecting multiple ones.
- *
- * \return if the selection has changed.
- */
+
bool wm_gizmo_select_set_ex(
wmGizmoMap *gzmap, wmGizmo *gz, bool select, bool use_array, bool use_callback)
{
@@ -429,7 +404,6 @@ bool wm_gizmo_select_set_ex(
return changed;
}
-/* Remove from selection array without running callbacks. */
bool WM_gizmo_select_unlink(wmGizmoMap *gzmap, wmGizmo *gz)
{
return wm_gizmo_select_set_ex(gzmap, gz, false, true, false);
@@ -454,12 +428,6 @@ bool wm_gizmo_select_and_highlight(bContext *C, wmGizmoMap *gzmap, wmGizmo *gz)
return false;
}
-/**
- * Special function to run from setup so gizmos start out interactive.
- *
- * We could do this when linking them,
- * but this complicates things since the window update code needs to run first.
- */
void WM_gizmo_modal_set_from_setup(struct wmGizmoMap *gzmap,
struct bContext *C,
struct wmGizmo *gz,
@@ -634,8 +602,6 @@ void WM_gizmo_properties_create(PointerRNA *ptr, const char *gtstring)
}
}
-/* similar to the function above except its uses ID properties
- * used for keymaps and macros */
void WM_gizmo_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *gtstring)
{
if (*properties == NULL) {
@@ -680,14 +646,6 @@ void WM_gizmo_properties_sanitize(PointerRNA *ptr, const bool no_context)
RNA_STRUCT_END;
}
-/**
- * Set all props to their default.
- *
- * \param do_update: Only update un-initialized props.
- *
- * \note There's nothing specific to gizmos here.
- * This could be made a general function.
- */
bool WM_gizmo_properties_default(PointerRNA *ptr, const bool do_update)
{
bool changed = false;
@@ -715,7 +673,6 @@ bool WM_gizmo_properties_default(PointerRNA *ptr, const bool do_update)
return changed;
}
-/* remove all props without PROP_SKIP_SAVE */
void WM_gizmo_properties_reset(wmGizmo *gz)
{
if (gz->ptr->data) {
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
index 22bdf65a169..6f10e4f3f0d 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
@@ -63,9 +63,6 @@
/** \name wmGizmoGroup
* \{ */
-/**
- * Create a new gizmo-group from \a gzgt.
- */
wmGizmoGroup *wm_gizmogroup_new_from_type(wmGizmoMap *gzmap, wmGizmoGroupType *gzgt)
{
wmGizmoGroup *gzgroup = MEM_callocN(sizeof(*gzgroup), "gizmo-group");
@@ -148,9 +145,6 @@ void WM_gizmo_group_tag_remove(wmGizmoGroup *gzgroup)
}
}
-/**
- * Add \a gizmo to \a gzgroup and make sure its name is unique within the group.
- */
void wm_gizmogroup_gizmo_register(wmGizmoGroup *gzgroup, wmGizmo *gz)
{
BLI_assert(BLI_findindex(&gzgroup->gizmos, gz) == -1);
@@ -234,10 +228,6 @@ wmGizmo *wm_gizmogroup_find_intersected_gizmo(wmWindowManager *wm,
return NULL;
}
-/**
- * Adds all gizmos of \a gzgroup that can be selected to the head of \a listbase.
- * Added items need freeing!
- */
void wm_gizmogroup_intersectable_gizmos_to_list(wmWindowManager *wm,
const wmGizmoGroup *gzgroup,
const int event_modifier,
@@ -266,7 +256,6 @@ void WM_gizmogroup_ensure_init(const bContext *C, wmGizmoGroup *gzgroup)
/* prepare for first draw */
if (UNLIKELY((gzgroup->init_flag & WM_GIZMOGROUP_INIT_SETUP) == 0)) {
- gzgroup->use_fallback_keymap = true;
gzgroup->type->setup(C, gzgroup);
/* Not ideal, initialize keymap here, needed for RNA runtime generated gizmos. */
@@ -346,10 +335,9 @@ bool wm_gizmogroup_is_any_selected(const wmGizmoGroup *gzgroup)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Gizmo operators
+/** \name Gizmo Operators
*
* Basic operators for gizmo interaction with user configurable keymaps.
- *
* \{ */
static int gizmo_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
@@ -550,8 +538,8 @@ static int gizmo_tweak_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->type == EVT_MODAL_MAP) {
event_modal_val = evil_event->val;
- evil_event->type = evil_event->prevtype;
- evil_event->val = evil_event->prevval;
+ evil_event->type = evil_event->prev_type;
+ evil_event->val = evil_event->prev_val;
}
int modal_retval = modal_fn(C, gz, event, mtweak->flag);
@@ -642,8 +630,6 @@ void GIZMOGROUP_OT_gizmo_tweak(wmOperatorType *ot)
#endif
}
-/** \} */
-
wmKeyMap *wm_gizmogroup_tweak_modal_keymap(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
@@ -775,11 +761,12 @@ wmKeyMap *WM_gizmogroup_setup_keymap_generic_select(const wmGizmoGroupType *UNUS
return WM_gizmogroup_keymap_template_select_ex(kc, "Generic Gizmo Select", &params);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name wmGizmo (Key-map access)
*
* Key config version so these can be called from #wmGizmoGroupFnSetupKeymap.
- *
* \{ */
struct wmKeyMap *WM_gizmo_keymap_generic_with_keyconfig(wmKeyConfig *kc)
@@ -822,7 +809,6 @@ struct wmKeyMap *WM_gizmo_keymap_generic_click_drag(wmWindowManager *wm)
return WM_gizmo_keymap_generic_click_drag_with_keyconfig(wm->defaultconf);
}
-/** Drag or press depending on preference. */
struct wmKeyMap *WM_gizmo_keymap_generic_maybe_drag_with_keyconfig(wmKeyConfig *kc)
{
const char *idname = "Generic Gizmo Maybe Drag";
@@ -863,10 +849,6 @@ struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find(struct wmGizmoMapType *gz
return NULL;
}
-/**
- * Use this for registering gizmos on startup.
- * For runtime, use #WM_gizmomaptype_group_link_runtime.
- */
wmGizmoGroupTypeRef *WM_gizmomaptype_group_link(wmGizmoMapType *gzmap_type, const char *idname)
{
wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
@@ -940,9 +922,6 @@ wmGizmoGroup *WM_gizmomaptype_group_init_runtime_with_region(wmGizmoMapType *gzm
return gzgroup;
}
-/**
- * Unlike #WM_gizmomaptype_group_unlink this doesn't maintain correct state, simply free.
- */
void WM_gizmomaptype_group_free(wmGizmoGroupTypeRef *gzgt_ref)
{
MEM_freeN(gzgt_ref);
@@ -1018,7 +997,6 @@ void wm_gizmogrouptype_setup_keymap(wmGizmoGroupType *gzgt, wmKeyConfig *keyconf
* but for general purpose API this is too detailed & annoying.
*
* \note We may want to return a value if there is nothing to remove.
- *
* \{ */
void WM_gizmo_group_type_add_ptr_ex(wmGizmoGroupType *gzgt, wmGizmoMapType *gzmap_type)
@@ -1060,9 +1038,6 @@ bool WM_gizmo_group_type_ensure(const char *idname)
return WM_gizmo_group_type_ensure_ptr(gzgt);
}
-/**
- * Call #WM_gizmo_group_type_free_ptr after to remove & free.
- */
void WM_gizmo_group_type_remove_ptr_ex(struct Main *bmain,
wmGizmoGroupType *gzgt,
wmGizmoMapType *gzmap_type)
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
index 6a793d52f74..0a36068bb21 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
@@ -71,7 +71,6 @@ wmGizmoGroupType *WM_gizmogrouptype_find(const char *idname, bool quiet)
return NULL;
}
-/* caller must free */
void WM_gizmogrouptype_iter(GHashIterator *ghi)
{
BLI_ghashIterator_init(ghi, global_gizmogrouptype_hash);
@@ -127,10 +126,6 @@ wmGizmoGroupType *WM_gizmogrouptype_append_ptr(void (*wtfunc)(struct wmGizmoGrou
return gzgt;
}
-/**
- * Append and insert into a gizmo typemap.
- * This is most common for C gizmos which are enabled by default.
- */
wmGizmoGroupTypeRef *WM_gizmogrouptype_append_and_link(wmGizmoMapType *gzmap_type,
void (*wtfunc)(struct wmGizmoGroupType *))
{
@@ -190,7 +185,6 @@ void wm_gizmogrouptype_free(void)
global_gizmogrouptype_hash = NULL;
}
-/* called on initialize WM_init() */
void wm_gizmogrouptype_init(void)
{
/* reserve size is set based on blender default setup */
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
index dd2db209771..187612f2651 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
@@ -29,12 +29,18 @@ struct wmKeyConfig;
/* -------------------------------------------------------------------- */
/* wmGizmo */
+/**
+ * Add/Remove \a gizmo to selection.
+ * Reallocates memory for selected gizmos so better not call for selecting multiple ones.
+ *
+ * \return if the selection has changed.
+ */
bool wm_gizmo_select_set_ex(
struct wmGizmoMap *gzmap, struct wmGizmo *gz, bool select, bool use_array, bool use_callback);
bool wm_gizmo_select_and_highlight(bContext *C, struct wmGizmoMap *gzmap, struct wmGizmo *gz);
void wm_gizmo_calculate_scale(struct wmGizmo *gz, const bContext *C);
-void wm_gizmo_update(struct wmGizmo *gz, const bContext *C, const bool refresh_map);
+void wm_gizmo_update(struct wmGizmo *gz, const bContext *C, bool refresh_map);
int wm_gizmo_is_visible(struct wmGizmo *gz);
enum {
@@ -54,24 +60,34 @@ enum {
TWEAK_MODAL_SNAP_OFF,
};
+/**
+ * Create a new gizmo-group from \a gzgt.
+ */
struct wmGizmoGroup *wm_gizmogroup_new_from_type(struct wmGizmoMap *gzmap,
struct wmGizmoGroupType *gzgt);
void wm_gizmogroup_free(bContext *C, struct wmGizmoGroup *gzgroup);
+/**
+ * Add \a gizmo to \a gzgroup and make sure its name is unique within the group.
+ */
void wm_gizmogroup_gizmo_register(struct wmGizmoGroup *gzgroup, struct wmGizmo *gz);
struct wmGizmoGroup *wm_gizmogroup_find_by_type(const struct wmGizmoMap *gzmap,
const struct wmGizmoGroupType *gzgt);
struct wmGizmo *wm_gizmogroup_find_intersected_gizmo(wmWindowManager *wm,
const struct wmGizmoGroup *gzgroup,
struct bContext *C,
- const int event_modifier,
+ int event_modifier,
const int mval[2],
int *r_part);
+/**
+ * Adds all gizmos of \a gzgroup that can be selected to the head of \a listbase.
+ * Added items need freeing!
+ */
void wm_gizmogroup_intersectable_gizmos_to_list(wmWindowManager *wm,
const struct wmGizmoGroup *gzgroup,
- const int event_modifier,
+ int event_modifier,
struct BLI_Buffer *visible_gizmos);
bool wm_gizmogroup_is_visible_in_drawstep(const struct wmGizmoGroup *gzgroup,
- const eWM_GizmoFlagMapDrawStep drawstep);
+ eWM_GizmoFlagMapDrawStep drawstep);
void wm_gizmogrouptype_setup_keymap(struct wmGizmoGroupType *gzgt, struct wmKeyConfig *keyconf);
@@ -137,6 +153,10 @@ struct wmGizmoMapType {
};
void wm_gizmomap_select_array_clear(struct wmGizmoMap *gzmap);
+/**
+ * Deselect all selected gizmos in \a gzmap.
+ * \return if selection has changed.
+ */
bool wm_gizmomap_deselect_all(struct wmGizmoMap *gzmap);
void wm_gizmomap_select_array_shrink(struct wmGizmoMap *gzmap, int len_subtract);
void wm_gizmomap_select_array_push_back(struct wmGizmoMap *gzmap, wmGizmo *gz);
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index 295196c701b..e61de28d0a4 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -38,9 +38,11 @@
#include "ED_select_utils.h"
#include "ED_view3d.h"
+#include "GPU_framebuffer.h"
#include "GPU_matrix.h"
#include "GPU_select.h"
#include "GPU_state.h"
+#include "GPU_viewport.h"
#include "MEM_guardedalloc.h"
@@ -176,9 +178,6 @@ static wmGizmoMap *wm_gizmomap_new_from_type_ex(struct wmGizmoMapType *gzmap_typ
return gzmap;
}
-/**
- * Creates a gizmo-map with all registered gizmos for that type
- */
wmGizmoMap *WM_gizmomap_new_from_type(const struct wmGizmoMapType_Params *gzmap_params)
{
wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(gzmap_params);
@@ -207,7 +206,6 @@ void wm_gizmomap_remove(wmGizmoMap *gzmap)
MEM_freeN(gzmap);
}
-/** Re-create the gizmos (use when changing theme settings). */
void WM_gizmomap_reinit(wmGizmoMap *gzmap)
{
wmGizmoMapType *gzmap_type = gzmap->type;
@@ -246,9 +244,6 @@ bool WM_gizmomap_is_any_selected(const wmGizmoMap *gzmap)
return gzmap->gzmap_context.select.len != 0;
}
-/**
- * \note We could use a callback to define bounds, for now just use matrix location.
- */
bool WM_gizmomap_minmax(const wmGizmoMap *gzmap,
bool UNUSED(use_hidden),
bool use_select,
@@ -512,8 +507,7 @@ void WM_gizmomap_draw(wmGizmoMap *gzmap,
static void gizmo_draw_select_3d_loop(const bContext *C,
wmGizmo **visible_gizmos,
- const int visible_gizmos_len,
- bool *r_use_select_bias)
+ const int visible_gizmos_len)
{
/* TODO(campbell): this depends on depth buffer being written to,
@@ -549,10 +543,6 @@ static void gizmo_draw_select_3d_loop(const bContext *C,
is_depth_skip_prev = is_depth_skip;
}
- if (gz->select_bias != 0.0) {
- *r_use_select_bias = true;
- }
-
/* pass the selection id shifted by 8 bits. Last 8 bits are used for selected gizmo part id */
gz->type->draw_select(C, gz, select_id << 8);
@@ -570,7 +560,10 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
const int visible_gizmos_len,
const bContext *C,
const int co[2],
- const int hotspot)
+ const int hotspot,
+ const bool use_depth_test,
+ const bool has_3d_select_bias,
+ int *r_hits)
{
const wmWindowManager *wm = CTX_wm_manager(C);
ScrArea *area = CTX_wm_area(C);
@@ -584,30 +577,69 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
BLI_rcti_init_pt_radius(&rect, co, hotspot);
- ED_view3d_draw_setup_view(
- wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect);
-
- bool use_select_bias = false;
+ /* The selection mode is assigned for the following reasons:
+ *
+ * - #GPU_SELECT_ALL: Use it to check if there is anything at the cursor location
+ * (only ever runs once).
+ * - #GPU_SELECT_PICK_NEAREST: Use if there are more than 1 item at the cursor location,
+ * select the best one.
+ * - #GPU_SELECT_PICK_ALL: Use for the same purpose as #GPU_SELECT_PICK_NEAREST
+ * when the selection depths need to re-ordered based on a bias.
+ * */
+ const int gpu_select_mode = (use_depth_test ?
+ (has_3d_select_bias ?
+ /* Using select bias means the depths need to be
+ * re-calculated based on the bias to pick the best. */
+ GPU_SELECT_PICK_ALL :
+ /* No bias, just pick the closest. */
+ GPU_SELECT_PICK_NEAREST) :
+ /* Fast-path (occlusion queries). */
+ GPU_SELECT_ALL);
+
+ if (GPU_select_is_cached()) {
+ GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, gpu_select_mode, 0);
+ GPU_select_cache_load_id();
+ hits = GPU_select_end();
+ }
+ else {
+ /* TODO: waiting for the GPU in the middle of the event loop for every
+ * mouse move is bad for performance, we need to find a solution to not
+ * use the GPU or draw something once. (see T61474) */
+
+ ED_view3d_draw_setup_view(
+ wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect);
+
+ /* There is no need to bind to the depth buffer outside this function
+ * because all future passes the will use the cached depths. */
+ GPUFrameBuffer *depth_read_fb = NULL;
+ if (use_depth_test) {
+ GPUViewport *viewport = WM_draw_region_get_viewport(CTX_wm_region(C));
+ GPUTexture *depth_tx = GPU_viewport_depth_texture(viewport);
+ GPU_framebuffer_ensure_config(&depth_read_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(depth_tx),
+ GPU_ATTACHMENT_NONE,
+ });
+ GPU_framebuffer_bind(depth_read_fb);
+ }
- /* TODO: waiting for the GPU in the middle of the event loop for every
- * mouse move is bad for performance, we need to find a solution to not
- * use the GPU or draw something once. (see T61474) */
- GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
- /* do the drawing */
- gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias);
+ GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, gpu_select_mode, 0);
+ gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len);
+ hits = GPU_select_end();
- hits = GPU_select_end();
+ if (use_depth_test) {
+ GPU_framebuffer_restore();
+ GPU_framebuffer_free(depth_read_fb);
+ }
- if (hits > 0) {
- GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
- gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias);
- GPU_select_end();
+ ED_view3d_draw_setup_view(
+ wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL);
}
- ED_view3d_draw_setup_view(
- wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL);
+ /* When selection bias is needed, this function will run again with `use_depth_test` enabled. */
+ int hit_found = -1;
- if (use_select_bias && (hits > 1)) {
+ if (has_3d_select_bias && use_depth_test && (hits > 1)) {
float co_direction[3];
float co_screen[3] = {co[0], co[1], 0.0f};
ED_view3d_win_to_vector(region, (float[2]){UNPACK2(co)}, co_direction);
@@ -619,7 +651,6 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin);
uint *buf_iter = buffer;
- int hit_found = -1;
float dot_best = FLT_MAX;
for (int i = 0; i < hits; i++, buf_iter += 4) {
@@ -639,11 +670,16 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
hit_found = buf_iter[3];
}
}
- return hit_found;
+ }
+ else {
+ const uint *hit_near = GPU_select_buffer_near(buffer, hits);
+ if (hit_near) {
+ hit_found = hit_near[3];
+ }
}
- const uint *hit_near = GPU_select_buffer_near(buffer, hits);
- return hit_near ? hit_near[3] : -1;
+ *r_hits = hits;
+ return hit_found;
}
/**
@@ -666,6 +702,7 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
/* Search for 3D gizmo's that use the 2D callback for checking intersections. */
bool has_3d = false;
+ bool has_3d_select_bias = false;
{
for (int select_id = 0; select_id < visible_gizmos_len; select_id++) {
wmGizmo *gz = visible_gizmos[select_id];
@@ -681,6 +718,9 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
}
else if (gz->type->draw_select != NULL) {
has_3d = true;
+ if (gz->select_bias != 0.0f) {
+ has_3d_select_bias = true;
+ }
}
}
}
@@ -688,17 +728,78 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
/* Search for 3D intersections if they're before 2D that have been found (if any).
* This way we always use the first hit. */
if (has_3d) {
+
+ /* NOTE(@campbellbarton): The selection logic here uses a fast-path that exits early
+ * where possible. This is important as this runs on cursor-motion in the 3D view-port.
+ *
+ * - First, don't use the depth buffer at all, use occlusion queries to detect any gizmos.
+ * If there are no gizmos or only one - early exit, otherwise.
+ *
+ * - Bind the depth buffer and and use selection picking logic.
+ * This is much slower than occlusion queries (since it's reading depths while drawing).
+ * When there is a single gizmo under the cursor (quite common), early exit, otherwise.
+ *
+ * - Perform another pass at a reduced size (see: `hotspot_radii`),
+ * since the result depths are cached this pass is practically free.
+ *
+ * Other notes:
+ *
+ * - If any of these passes fail, use the nearest result from the previous pass.
+ *
+ * - Drawing is only ever done twice.
+ */
+
+ /* Order largest to smallest so the first pass can be used as cache for
+ * later passes (when `use_depth_test == true`). */
const int hotspot_radii[] = {
- 3 * U.pixelsize,
- /* This runs on mouse move, careful doing too many tests! */
10 * U.pixelsize,
+ /* This runs on mouse move, careful doing too many tests! */
+ 3 * U.pixelsize,
};
+
+ /* Narrowing may assign zero to `hit`, allow falling back to the previous test. */
+ int hit_prev = -1;
+
+ bool use_depth_test = false;
+ bool use_depth_cache = false;
+
for (int i = 0; i < ARRAY_SIZE(hotspot_radii); i++) {
- hit = gizmo_find_intersected_3d_intern(
- visible_gizmos, visible_gizmos_len_trim, C, co, hotspot_radii[i]);
- if (hit != -1) {
+
+ if (use_depth_test && (use_depth_cache == false)) {
+ GPU_select_cache_begin();
+ use_depth_cache = true;
+ }
+
+ int hit_count;
+ hit = gizmo_find_intersected_3d_intern(visible_gizmos,
+ visible_gizmos_len_trim,
+ C,
+ co,
+ hotspot_radii[i],
+ use_depth_test,
+ has_3d_select_bias,
+ &hit_count);
+ /* Only continue searching when there are multiple options to narrow down. */
+ if (hit_count < 2) {
break;
}
+
+ /* Fast path for simple case, one item or nothing. */
+ if (use_depth_test == false) {
+ /* Restart, using depth buffer (slower). */
+ use_depth_test = true;
+ i = -1;
+ }
+ hit_prev = hit;
+ }
+ /* Narrowing the search area may yield no hits,
+ * in this case fall back to the previous search. */
+ if (hit == -1) {
+ hit = hit_prev;
+ }
+
+ if (use_depth_cache) {
+ GPU_select_cache_end();
}
if (hit != -1) {
@@ -713,10 +814,6 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
return result;
}
-/**
- * Try to find a gizmo under the mouse position. 2D intersections have priority over
- * 3D ones (could check for smallest screen-space distance but not needed right now).
- */
wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap,
bContext *C,
const wmEvent *event,
@@ -743,14 +840,7 @@ wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap,
}
if (WM_gizmo_group_type_poll(C, gzgroup->type)) {
- eWM_GizmoFlagMapDrawStep step;
- if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
- step = WM_GIZMOMAP_DRAWSTEP_3D;
- }
- else {
- step = WM_GIZMOMAP_DRAWSTEP_2D;
- }
-
+ const eWM_GizmoFlagMapDrawStep step = WM_gizmomap_drawstep_from_gizmo_group(gzgroup);
if (do_step[step]) {
if (gzmap->update_flag[step] & GIZMOMAP_IS_REFRESH_CALLBACK) {
WM_gizmo_group_refresh(C, gzgroup);
@@ -850,10 +940,6 @@ void wm_gizmomaps_handled_modal_update(bContext *C, wmEvent *event, wmEventHandl
CTX_wm_region_set(C, region);
}
-/**
- * Deselect all selected gizmos in \a gzmap.
- * \return if selection has changed.
- */
bool wm_gizmomap_deselect_all(wmGizmoMap *gzmap)
{
wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
@@ -910,12 +996,6 @@ static bool wm_gizmomap_select_all_intern(bContext *C, wmGizmoMap *gzmap)
return changed;
}
-/**
- * Select/Deselect all selectable gizmos in \a gzmap.
- * \return if selection has changed.
- *
- * TODO: select all by type.
- */
bool WM_gizmomap_select_all(bContext *C, wmGizmoMap *gzmap, const int action)
{
bool changed = false;
@@ -939,10 +1019,6 @@ bool WM_gizmomap_select_all(bContext *C, wmGizmoMap *gzmap, const int action)
return changed;
}
-/**
- * Prepare context for gizmo handling (but only if area/region is
- * part of screen). Version of #wm_handler_op_context for gizmos.
- */
void wm_gizmomap_handler_context_op(bContext *C, wmEventHandler_Op *handler)
{
bScreen *screen = CTX_wm_screen(C);
@@ -1044,12 +1120,11 @@ wmGizmo *wm_gizmomap_highlight_get(wmGizmoMap *gzmap)
return gzmap->gzmap_context.highlight;
}
-/**
- * Caller should call exit when (enable == False).
- */
void wm_gizmomap_modal_set(
wmGizmoMap *gzmap, bContext *C, wmGizmo *gz, const wmEvent *event, bool enable)
{
+ bool do_refresh = false;
+
if (enable) {
BLI_assert(gzmap->gzmap_context.modal == NULL);
wmWindow *win = CTX_wm_window(C);
@@ -1068,12 +1143,15 @@ void wm_gizmomap_modal_set(
}
}
+ if (gzmap->gzmap_context.modal != gz) {
+ do_refresh = true;
+ }
gz->state |= WM_GIZMO_STATE_MODAL;
gzmap->gzmap_context.modal = gz;
if ((gz->flag & WM_GIZMO_MOVE_CURSOR) && (event->tablet.is_motion_absolute == false)) {
WM_cursor_grab_enable(win, WM_CURSOR_WRAP_XY, true, NULL);
- copy_v2_v2_int(gzmap->gzmap_context.event_xy, &event->x);
+ copy_v2_v2_int(gzmap->gzmap_context.event_xy, event->xy);
gzmap->gzmap_context.event_grabcursor = win->grabcursor;
}
else {
@@ -1092,7 +1170,6 @@ void wm_gizmomap_modal_set(
gz->state &= ~WM_GIZMO_STATE_MODAL;
MEM_SAFE_FREE(gz->interaction_data);
}
- return;
}
}
else {
@@ -1103,6 +1180,10 @@ void wm_gizmomap_modal_set(
gz->state &= ~WM_GIZMO_STATE_MODAL;
MEM_SAFE_FREE(gz->interaction_data);
}
+
+ if (gzmap->gzmap_context.modal != NULL) {
+ do_refresh = true;
+ }
gzmap->gzmap_context.modal = NULL;
if (C) {
@@ -1124,6 +1205,12 @@ void wm_gizmomap_modal_set(
gzmap->gzmap_context.event_xy[0] = INT_MAX;
}
+
+ if (do_refresh) {
+ const eWM_GizmoFlagMapDrawStep step = WM_gizmomap_drawstep_from_gizmo_group(
+ gz->parent_gzgroup);
+ gzmap->update_flag[step] |= GIZMOMAP_IS_REFRESH_CALLBACK;
+ }
}
wmGizmo *wm_gizmomap_modal_get(wmGizmoMap *gzmap)
@@ -1240,9 +1327,6 @@ void wm_gizmomaptypes_free(void)
}
}
-/**
- * Initialize keymaps for all existing gizmo-groups
- */
void wm_gizmos_keymap(wmKeyConfig *keyconf)
{
LISTBASE_FOREACH (wmGizmoMapType *, gzmap_type, &gizmomaptypes) {
@@ -1286,10 +1370,6 @@ void WM_gizmoconfig_update_tag_group_remove(wmGizmoMap *gzmap)
wm_gzmap_type_update_flag |= WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE;
}
-/**
- * Run in case new types have been added (runs often, early exit where possible).
- * Follows #WM_keyconfig_update conventions.
- */
void WM_gizmoconfig_update(struct Main *bmain)
{
if (G.background) {
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
index 63e833d73c3..57555fb5416 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
@@ -319,10 +319,6 @@ void WM_gizmo_do_msg_notify_tag_refresh(bContext *UNUSED(C),
WM_gizmomap_tag_refresh(gzmap);
}
-/**
- * Runs on the "prepare draw" pass,
- * drawing the region clears.
- */
void WM_gizmo_target_property_subscribe_all(wmGizmo *gz, struct wmMsgBus *mbus, ARegion *region)
{
if (gz->type->target_property_defs_len) {
@@ -355,9 +351,6 @@ void WM_gizmo_target_property_subscribe_all(wmGizmo *gz, struct wmMsgBus *mbus,
}
}
-/**
- * Auto-key function if auto-key is enabled.
- */
void WM_gizmo_target_property_anim_autokey(bContext *C,
const wmGizmo *UNUSED(gz),
wmGizmoProperty *gz_prop)
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c
index 1523246d08b..602100a624e 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c
@@ -78,7 +78,6 @@ const wmGizmoType *WM_gizmotype_find(const char *idname, bool quiet)
return NULL;
}
-/* caller must free */
void WM_gizmotype_iter(GHashIterator *ghi)
{
BLI_ghashIterator_init(ghi, global_gizmotype_hash);
@@ -118,9 +117,6 @@ void WM_gizmotype_append_ptr(void (*gtfunc)(struct wmGizmoType *, void *), void
wm_gizmotype_append__end(mt);
}
-/**
- * Free but don't remove from ghash.
- */
void WM_gizmotype_free_ptr(wmGizmoType *gzt)
{
if (gzt->rna_ext.srna) { /* python gizmo, allocs own string */
@@ -195,7 +191,6 @@ void wm_gizmotype_free(void)
global_gizmotype_hash = NULL;
}
-/* called on initialize WM_init() */
void wm_gizmotype_init(void)
{
/* reserve size is set based on blender default setup */
diff --git a/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h b/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h
index 18b3f40aba6..0612ba97db0 100644
--- a/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h
+++ b/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h
@@ -40,37 +40,63 @@ extern "C" {
#endif
/* -------------------------------------------------------------------- */
-/* wmGizmo */
+/** \name #wmGizmo
+ * \{ */
/* wm_gizmo_type.c, for init/exit */
+
void wm_gizmotype_free(void);
+/**
+ * Called on initialize #WM_init().
+ */
void wm_gizmotype_init(void);
/* wm_gizmogroup_type.c, for init/exit */
+
void wm_gizmogrouptype_free(void);
+/**
+ * Called on initialize #WM_init().
+ */
void wm_gizmogrouptype_init(void);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* wmGizmoGroup */
+/** \name #wmGizmoGroup
+ * \{ */
void GIZMOGROUP_OT_gizmo_select(struct wmOperatorType *ot);
void GIZMOGROUP_OT_gizmo_tweak(struct wmOperatorType *ot);
bool wm_gizmogroup_is_any_selected(const struct wmGizmoGroup *gzgroup);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* wmGizmoMap */
+/** \name #wmGizmoMap
+ * \{ */
void wm_gizmomap_remove(struct wmGizmoMap *gzmap);
+/**
+ * Initialize key-maps for all existing gizmo-groups
+ */
void wm_gizmos_keymap(struct wmKeyConfig *keyconf);
void wm_gizmomaps_handled_modal_update(bContext *C,
struct wmEvent *event,
struct wmEventHandler_Op *handler);
+/**
+ * Prepare context for gizmo handling (but only if area/region is
+ * part of screen). Version of #wm_handler_op_context for gizmos.
+ */
void wm_gizmomap_handler_context_op(bContext *C, struct wmEventHandler_Op *handler);
void wm_gizmomap_handler_context_gizmo(bContext *C, struct wmEventHandler_Gizmo *handler);
+/**
+ * Try to find a gizmo under the mouse position. 2D intersections have priority over
+ * 3D ones (could check for smallest screen-space distance but not needed right now).
+ */
struct wmGizmo *wm_gizmomap_highlight_find(struct wmGizmoMap *gzmap,
bContext *C,
const struct wmEvent *event,
@@ -80,6 +106,9 @@ bool wm_gizmomap_highlight_set(struct wmGizmoMap *gzmap,
struct wmGizmo *gz,
int part);
struct wmGizmo *wm_gizmomap_highlight_get(struct wmGizmoMap *gzmap);
+/**
+ * Caller should call exit when (enable == False).
+ */
void wm_gizmomap_modal_set(struct wmGizmoMap *gzmap,
bContext *C,
struct wmGizmo *gz,
@@ -90,11 +119,16 @@ struct wmGizmo *wm_gizmomap_modal_get(struct wmGizmoMap *gzmap);
struct wmGizmo **wm_gizmomap_selected_get(wmGizmoMap *gzmap, int *r_selected_len);
struct ListBase *wm_gizmomap_groups_get(wmGizmoMap *gzmap);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* wmGizmoMapType */
+/** \name #wmGizmoMapType
+ * \{ */
void wm_gizmomaptypes_free(void);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 0b7d5e5f1f4..40f8da63e11 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -86,18 +86,23 @@ static void window_manager_foreach_id(ID *id, LibraryForeachIDData *data)
wmWindowManager *wm = (wmWindowManager *)id;
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
- BKE_LIB_FOREACHID_PROCESS(data, win->scene, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, win->scene, IDWALK_CB_USER_ONE);
/* This pointer can be NULL during old files reading, better be safe than sorry. */
if (win->workspace_hook != NULL) {
ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook);
- BKE_LIB_FOREACHID_PROCESS_ID(data, workspace, IDWALK_CB_NOP);
+ BKE_lib_query_foreachid_process(data, &workspace, IDWALK_CB_USER);
/* Allow callback to set a different workspace. */
BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace);
+ if (BKE_lib_query_foreachid_iter_stop(data)) {
+ return;
+ }
}
+
if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) {
LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
- BKE_screen_foreach_id_screen_area(data, area);
+ BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data,
+ BKE_screen_foreach_id_screen_area(data, area));
}
}
}
@@ -267,6 +272,7 @@ IDTypeInfo IDType_ID_WM = {
.name_plural = "window_managers",
.translation_context = BLT_I18NCONTEXT_ID_WINDOWMANAGER,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -274,6 +280,7 @@ IDTypeInfo IDType_ID_WM = {
.make_local = NULL,
.foreach_id = window_manager_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = window_manager_blend_write,
@@ -334,13 +341,6 @@ void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op)
}
}
-/**
- * Use with extreme care!,
- * properties, custom-data etc - must be compatible.
- *
- * \param op: Operator to assign the type to.
- * \param ot: Operator type to assign.
- */
void WM_operator_type_set(wmOperator *op, wmOperatorType *ot)
{
/* Not supported for Python. */
@@ -370,8 +370,6 @@ static void wm_reports_free(wmWindowManager *wm)
WM_event_remove_timer(wm, NULL, wm->reports.reporttimer);
}
-/* All operations get registered in the windowmanager here. */
-/* Called on event handling by event_system.c. */
void wm_operator_register(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -408,10 +406,6 @@ void WM_operator_stack_clear(wmWindowManager *wm)
WM_main_add_notifier(NC_WM | ND_HISTORY, NULL);
}
-/**
- * This function is needed in the case when an addon id disabled
- * while a modal operator it defined is running.
- */
void WM_operator_handlers_clear(wmWindowManager *wm, wmOperatorType *ot)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
@@ -544,7 +538,6 @@ void wm_clear_default_size(bContext *C)
}
}
-/* On startup, it adds all data, for matching. */
void wm_add_default(Main *bmain, bContext *C)
{
wmWindowManager *wm = BKE_libblock_alloc(bmain, ID_WM, "WinMan", 0);
@@ -566,7 +559,6 @@ void wm_add_default(Main *bmain, bContext *C)
wm_window_make_drawable(wm, win);
}
-/* Context is allowed to be NULL, do not free wm itself (lib_id.c). */
void wm_close_and_free(bContext *C, wmWindowManager *wm)
{
if (wm->autosavetimer) {
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 9c020b16234..74ec2bcd41f 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -222,7 +222,6 @@ void WM_cursor_modal_restore(wmWindow *win)
win->lastcursor = 0;
}
-/* to allow usage all over, we do entire WM */
void WM_cursor_wait(bool val)
{
if (!G.background) {
@@ -240,9 +239,6 @@ void WM_cursor_wait(bool val)
}
}
-/**
- * \param bounds: can be NULL
- */
void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4])
{
/* Only grab cursor when not running debug.
@@ -307,9 +303,10 @@ static void wm_cursor_warp_relative(wmWindow *win, int x, int y)
WM_cursor_warp(win, cx + x, cy + y);
}
-/* give it a modal keymap one day? */
bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event)
{
+ /* TODO: give it a modal keymap? Hard coded for now */
+
if (win && event->val == KM_PRESS) {
/* Must move at least this much to avoid rounding in WM_cursor_warp. */
float fac = GHOST_GetNativePixelSize(win->ghostwin);
@@ -334,7 +331,6 @@ bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event)
return 0;
}
-/* after this you can call restore too */
void WM_cursor_time(wmWindow *win, int nr)
{
/* 10 8x8 digits */
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 93038b5709c..96cb66b44ea 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -40,11 +40,19 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_screen.h"
+
+#include "GHOST_C-api.h"
#include "BLO_readfile.h"
+#include "ED_asset.h"
+#include "ED_screen.h"
+
#include "GPU_shader.h"
#include "GPU_state.h"
#include "GPU_viewport.h"
@@ -60,11 +68,14 @@
#include "WM_api.h"
#include "WM_types.h"
#include "wm_event_system.h"
+#include "wm_window.h"
/* ****************************************************** */
static ListBase dropboxes = {NULL, NULL};
+static void wm_drag_free_asset_data(wmDragAsset **asset_data);
+
/* drop box maps are stored global for now */
/* these are part of blender's UI/space specs, and not like keymaps */
/* when editors become configurable, they can add own dropbox definitions */
@@ -78,7 +89,6 @@ typedef struct wmDropBoxMap {
} wmDropBoxMap;
-/* spaceid/regionid is zero for window drop maps */
ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
{
LISTBASE_FOREACH (wmDropBoxMap *, dm, &dropboxes) {
@@ -111,7 +121,6 @@ wmDropBox *WM_dropbox_add(ListBase *lb,
drop->cancel = cancel;
drop->tooltip = tooltip;
drop->ot = WM_operatortype_find(idname, 0);
- drop->opcontext = WM_OP_INVOKE_DEFAULT;
if (drop->ot == NULL) {
MEM_freeN(drop);
@@ -143,7 +152,6 @@ void wm_dropbox_free(void)
/* *********************************** */
-/* note that the pointer should be valid allocated and not on stack */
wmDrag *WM_event_start_drag(
struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags)
{
@@ -171,10 +179,24 @@ wmDrag *WM_event_start_drag(
}
break;
case WM_DRAG_ASSET:
+ case WM_DRAG_ASSET_CATALOG:
/* Move ownership of poin to wmDrag. */
drag->poin = poin;
drag->flags |= WM_DRAG_FREE_DATA;
break;
+ /* The asset-list case is special: We get multiple assets from context and attach them to the
+ * drag item. */
+ case WM_DRAG_ASSET_LIST: {
+ const AssetLibraryReference *asset_library = CTX_wm_asset_library_ref(C);
+ ListBase asset_file_links = CTX_data_collection_get(C, "selected_asset_files");
+ LISTBASE_FOREACH (const CollectionPointerLink *, link, &asset_file_links) {
+ const FileDirEntry *asset_file = link->ptr.data;
+ const AssetHandle asset_handle = {asset_file};
+ WM_drag_add_asset_list_item(drag, C, asset_library, &asset_handle);
+ }
+ BLI_freelistN(&asset_file_links);
+ break;
+ }
default:
drag->poin = poin;
break;
@@ -184,6 +206,26 @@ wmDrag *WM_event_start_drag(
return drag;
}
+void wm_drags_exit(wmWindowManager *wm, wmWindow *win)
+{
+ bool any_active = false;
+ LISTBASE_FOREACH (const wmDrag *, drag, &wm->drags) {
+ if (drag->drop_state.active_dropbox) {
+ any_active = true;
+ break;
+ }
+ }
+
+ /* If there is no active drop-box #wm_drags_check_ops() set a stop-cursor, which needs to be
+ * restored. */
+ if (!any_active) {
+ WM_cursor_modal_restore(win);
+ /* Ensure the correct area cursor is restored. */
+ win->tag_cursor_refresh = true;
+ WM_event_add_mousemove(win);
+ }
+}
+
void WM_event_drag_image(wmDrag *drag, ImBuf *imb, float scale, int sx, int sy)
{
drag->imb = imb;
@@ -201,18 +243,32 @@ void WM_drag_data_free(int dragtype, void *poin)
/* Not too nice, could become a callback. */
if (dragtype == WM_DRAG_ASSET) {
- wmDragAsset *asset_drag = poin;
- MEM_freeN((void *)asset_drag->path);
+ wmDragAsset *asset_data = poin;
+ wm_drag_free_asset_data(&asset_data);
+ }
+ else {
+ MEM_freeN(poin);
}
- MEM_freeN(poin);
}
void WM_drag_free(wmDrag *drag)
{
+ if (drag->drop_state.active_dropbox && drag->drop_state.active_dropbox->draw_deactivate) {
+ drag->drop_state.active_dropbox->draw_deactivate(drag->drop_state.active_dropbox, drag);
+ }
if (drag->flags & WM_DRAG_FREE_DATA) {
WM_drag_data_free(drag->type, drag->poin);
}
+ if (drag->drop_state.free_disabled_info) {
+ MEM_SAFE_FREE(drag->drop_state.disabled_info);
+ }
BLI_freelistN(&drag->ids);
+ LISTBASE_FOREACH_MUTABLE (wmDragAssetListItem *, asset_item, &drag->asset_items) {
+ if (asset_item->is_external) {
+ wm_drag_free_asset_data(&asset_item->asset_data.external_info);
+ }
+ BLI_freelinkN(&drag->asset_items, asset_item);
+ }
MEM_freeN(drag);
}
@@ -224,11 +280,11 @@ void WM_drag_free_list(struct ListBase *lb)
}
}
-static char *dropbox_tooltip(bContext *C, wmDrag *drag, const wmEvent *event, wmDropBox *drop)
+static char *dropbox_tooltip(bContext *C, wmDrag *drag, const int xy[2], wmDropBox *drop)
{
char *tooltip = NULL;
if (drop->tooltip) {
- tooltip = drop->tooltip(C, drag, event, drop);
+ tooltip = drop->tooltip(C, drag, xy, drop);
}
if (!tooltip) {
tooltip = BLI_strdup(WM_operatortype_name(drop->ot, drop->ptr));
@@ -243,15 +299,36 @@ static wmDropBox *dropbox_active(bContext *C,
wmDrag *drag,
const wmEvent *event)
{
+ if (drag->drop_state.free_disabled_info) {
+ MEM_SAFE_FREE(drag->drop_state.disabled_info);
+ }
+ drag->drop_state.disabled_info = NULL;
+
LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
if (handler_base->type == WM_HANDLER_TYPE_DROPBOX) {
wmEventHandler_Dropbox *handler = (wmEventHandler_Dropbox *)handler_base;
if (handler->dropboxes) {
LISTBASE_FOREACH (wmDropBox *, drop, handler->dropboxes) {
- if (drop->poll(C, drag, event) &&
- WM_operator_poll_context(C, drop->ot, drop->opcontext)) {
+ if (!drop->poll(C, drag, event)) {
+ /* If the drop's poll fails, don't set the disabled-info. This would be too aggressive.
+ * Instead show it only if the drop box could be used in principle, but the operator
+ * can't be executed. */
+ continue;
+ }
+
+ const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop);
+ if (WM_operator_poll_context(C, drop->ot, opcontext)) {
return drop;
}
+
+ /* Attempt to set the disabled hint when the poll fails. Will always be the last hint set
+ * when there are multiple failing polls (could allow multiple disabled-hints too). */
+ bool free_disabled_info = false;
+ const char *disabled_hint = CTX_wm_operator_poll_msg_get(C, &free_disabled_info);
+ if (disabled_hint) {
+ drag->drop_state.disabled_info = disabled_hint;
+ drag->drop_state.free_disabled_info = free_disabled_info;
+ }
}
}
}
@@ -260,7 +337,7 @@ static wmDropBox *dropbox_active(bContext *C,
}
/* return active operator tooltip/name when mouse is in box */
-static char *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *event)
+static wmDropBox *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
wmDropBox *drop = dropbox_active(C, &win->handlers, drag, event);
@@ -272,53 +349,78 @@ static char *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *event)
ARegion *region = CTX_wm_region(C);
drop = dropbox_active(C, &region->handlers, drag, event);
}
- if (drop) {
- return dropbox_tooltip(C, drag, event, drop);
- }
- return NULL;
+ return drop;
}
-static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *event)
+/**
+ * Update dropping information for the current mouse position in \a event.
+ */
+static void wm_drop_update_active(bContext *C, wmDrag *drag, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
/* for multiwin drags, we only do this if mouse inside */
- if (event->x < 0 || event->y < 0 || event->x > winsize_x || event->y > winsize_y) {
+ if (event->xy[0] < 0 || event->xy[1] < 0 || event->xy[0] > winsize_x ||
+ event->xy[1] > winsize_y) {
return;
}
- drag->tooltip[0] = 0;
-
- /* check buttons (XXX todo rna and value) */
- if (UI_but_active_drop_name(C)) {
- BLI_strncpy(drag->tooltip, IFACE_("Paste name"), sizeof(drag->tooltip));
+ wmDropBox *drop_prev = drag->drop_state.active_dropbox;
+ wmDropBox *drop = wm_dropbox_active(C, drag, event);
+ if (drop != drop_prev) {
+ if (drop_prev && drop_prev->draw_deactivate) {
+ drop_prev->draw_deactivate(drop_prev, drag);
+ BLI_assert(drop_prev->draw_data == NULL);
+ }
+ if (drop && drop->draw_activate) {
+ drop->draw_activate(drop, drag);
+ }
+ drag->drop_state.active_dropbox = drop;
+ drag->drop_state.area_from = drop ? CTX_wm_area(C) : NULL;
+ drag->drop_state.region_from = drop ? CTX_wm_region(C) : NULL;
}
- else {
- char *tooltip = wm_dropbox_active(C, drag, event);
+}
- if (tooltip) {
- BLI_strncpy(drag->tooltip, tooltip, sizeof(drag->tooltip));
- MEM_freeN(tooltip);
- // WM_cursor_modal_set(win, WM_CURSOR_COPY);
- }
- // else
- // WM_cursor_modal_restore(win);
- /* unsure about cursor type, feels to be too much */
+void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop)
+{
+ const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop);
+ /* Optionally copy drag information to operator properties. Don't call it if the
+ * operator fails anyway, it might do more than just set properties (e.g.
+ * typically import an asset). */
+ if (drop->copy && WM_operator_poll_context(C, drop->ot, opcontext)) {
+ drop->copy(drag, drop);
}
+
+ wm_drags_exit(CTX_wm_manager(C), CTX_wm_window(C));
}
-/* called in inner handler loop, region context */
void wm_drags_check_ops(bContext *C, const wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ bool any_active = false;
LISTBASE_FOREACH (wmDrag *, drag, &wm->drags) {
- wm_drop_operator_options(C, drag, event);
+ wm_drop_update_active(C, drag, event);
+
+ if (drag->drop_state.active_dropbox) {
+ any_active = true;
+ }
+ }
+
+ /* Change the cursor to display that dropping isn't possible here. But only if there is something
+ * being dragged actually. Cursor will be restored in #wm_drags_exit(). */
+ if (!BLI_listbase_is_empty(&wm->drags)) {
+ WM_cursor_modal_set(CTX_wm_window(C), any_active ? WM_CURSOR_DEFAULT : WM_CURSOR_STOP);
}
}
+wmOperatorCallContext wm_drop_operator_context_get(const wmDropBox *UNUSED(drop))
+{
+ return WM_OP_INVOKE_DEFAULT;
+}
+
/* ************** IDs ***************** */
void WM_drag_add_local_ID(wmDrag *drag, ID *id, ID *from_parent)
@@ -369,14 +471,33 @@ ID *WM_drag_get_local_ID_from_event(const wmEvent *event, short idcode)
return WM_drag_get_local_ID(lb->first, idcode);
}
-/**
- * Check if the drag data is either a local ID or an external ID asset of type \a idcode.
- */
bool WM_drag_is_ID_type(const wmDrag *drag, int idcode)
{
return WM_drag_get_local_ID(drag, idcode) || WM_drag_get_asset_data(drag, idcode);
}
+wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset,
+ AssetMetaData *metadata,
+ const char *path,
+ int import_type)
+{
+ wmDragAsset *asset_drag = MEM_mallocN(sizeof(*asset_drag), "wmDragAsset");
+
+ BLI_strncpy(asset_drag->name, ED_asset_handle_get_name(asset), sizeof(asset_drag->name));
+ asset_drag->metadata = metadata;
+ asset_drag->path = path;
+ asset_drag->id_type = ED_asset_handle_get_id_type(asset);
+ asset_drag->import_type = import_type;
+
+ return asset_drag;
+}
+
+static void wm_drag_free_asset_data(wmDragAsset **asset_data)
+{
+ MEM_freeN((char *)(*asset_data)->path);
+ MEM_SAFE_FREE(*asset_data);
+}
+
wmDragAsset *WM_drag_get_asset_data(const wmDrag *drag, int idcode)
{
if (drag->type != WM_DRAG_ASSET) {
@@ -387,26 +508,62 @@ wmDragAsset *WM_drag_get_asset_data(const wmDrag *drag, int idcode)
return (ELEM(idcode, 0, asset_drag->id_type)) ? asset_drag : NULL;
}
-static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag)
+struct AssetMetaData *WM_drag_get_asset_meta_data(const wmDrag *drag, int idcode)
{
+ wmDragAsset *drag_asset = WM_drag_get_asset_data(drag, idcode);
+ if (drag_asset) {
+ return drag_asset->metadata;
+ }
+
+ ID *local_id = WM_drag_get_local_ID(drag, idcode);
+ if (local_id) {
+ return local_id->asset_data;
+ }
+
+ return NULL;
+}
+
+ID *WM_drag_asset_id_import(wmDragAsset *asset_drag, const int flag_extra)
+{
+ /* Only support passing in limited flags. */
+ BLI_assert(flag_extra == (flag_extra & FILE_AUTOSELECT));
+ eFileSel_Params_Flag flag = flag_extra | FILE_ACTIVE_COLLECTION;
+
const char *name = asset_drag->name;
ID_Type idtype = asset_drag->id_type;
+ /* FIXME: Link/Append should happens in the operator called at the end of drop process, not from
+ * here. */
+
+ Main *bmain = CTX_data_main(asset_drag->evil_C);
+ Scene *scene = CTX_data_scene(asset_drag->evil_C);
+ ViewLayer *view_layer = CTX_data_view_layer(asset_drag->evil_C);
+ View3D *view3d = CTX_wm_view3d(asset_drag->evil_C);
+
switch ((eFileAssetImportType)asset_drag->import_type) {
case FILE_ASSET_IMPORT_LINK:
- return WM_file_link_datablock(G_MAIN, NULL, NULL, NULL, asset_drag->path, idtype, name, 0);
+ return WM_file_link_datablock(
+ bmain, scene, view_layer, view3d, asset_drag->path, idtype, name, flag);
case FILE_ASSET_IMPORT_APPEND:
- return WM_file_append_datablock(
- G_MAIN, NULL, NULL, NULL, asset_drag->path, idtype, name, BLO_LIBLINK_APPEND_RECURSIVE);
+ return WM_file_append_datablock(bmain,
+ scene,
+ view_layer,
+ view3d,
+ asset_drag->path,
+ idtype,
+ name,
+ flag | BLO_LIBLINK_APPEND_RECURSIVE |
+ BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR);
case FILE_ASSET_IMPORT_APPEND_REUSE:
return WM_file_append_datablock(G_MAIN,
- NULL,
- NULL,
- NULL,
+ scene,
+ view_layer,
+ view3d,
asset_drag->path,
idtype,
name,
- BLO_LIBLINK_APPEND_RECURSIVE |
+ flag | BLO_LIBLINK_APPEND_RECURSIVE |
+ BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR |
BLO_LIBLINK_APPEND_LOCAL_ID_REUSE);
}
@@ -414,13 +571,16 @@ static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag)
return NULL;
}
-/**
- * When dragging a local ID, return that. Otherwise, if dragging an asset-handle, link or append
- * that depending on what was chosen by the drag-box (currently append only in fact).
- *
- * Use #WM_drag_free_imported_drag_ID() as cancel callback of the drop-box, so that the asset
- * import is rolled back if the drop operator fails.
- */
+bool WM_drag_asset_will_import_linked(const wmDrag *drag)
+{
+ if (drag->type != WM_DRAG_ASSET) {
+ return false;
+ }
+
+ const wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, 0);
+ return asset_drag->import_type == FILE_ASSET_IMPORT_LINK;
+}
+
ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode)
{
if (!ELEM(drag->type, WM_DRAG_ASSET, WM_DRAG_ID)) {
@@ -437,17 +597,9 @@ ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode)
}
/* Link/append the asset. */
- return wm_drag_asset_id_import(asset_drag);
+ return WM_drag_asset_id_import(asset_drag, 0);
}
-/**
- * \brief Free asset ID imported for canceled drop.
- *
- * If the asset was imported (linked/appended) using #WM_drag_get_local_ID_or_import_from_asset()`
- * (typically via a #wmDropBox.copy() callback), we want the ID to be removed again if the drop
- * operator cancels.
- * This is for use as #wmDropBox.cancel() callback.
- */
void WM_drag_free_imported_drag_ID(struct Main *bmain, wmDrag *drag, wmDropBox *drop)
{
if (drag->type != WM_DRAG_ASSET) {
@@ -473,6 +625,55 @@ void WM_drag_free_imported_drag_ID(struct Main *bmain, wmDrag *drag, wmDropBox *
}
}
+wmDragAssetCatalog *WM_drag_get_asset_catalog_data(const wmDrag *drag)
+{
+ if (drag->type != WM_DRAG_ASSET_CATALOG) {
+ return NULL;
+ }
+
+ return drag->poin;
+}
+
+void WM_drag_add_asset_list_item(
+ wmDrag *drag,
+ /* Context only needed for the hack in #ED_asset_handle_get_full_library_path(). */
+ const bContext *C,
+ const AssetLibraryReference *asset_library_ref,
+ const AssetHandle *asset)
+{
+ if (drag->type != WM_DRAG_ASSET_LIST) {
+ return;
+ }
+
+ /* No guarantee that the same asset isn't added twice. */
+
+ /* Add to list. */
+ wmDragAssetListItem *drag_asset = MEM_callocN(sizeof(*drag_asset), __func__);
+ ID *local_id = ED_asset_handle_get_local_id(asset);
+ if (local_id) {
+ drag_asset->is_external = false;
+ drag_asset->asset_data.local_id = local_id;
+ }
+ else {
+ AssetMetaData *metadata = ED_asset_handle_get_metadata(asset);
+ char asset_blend_path[FILE_MAX_LIBEXTRA];
+ ED_asset_handle_get_full_library_path(C, asset_library_ref, asset, asset_blend_path);
+ drag_asset->is_external = true;
+ drag_asset->asset_data.external_info = WM_drag_create_asset_data(
+ asset, metadata, BLI_strdup(asset_blend_path), FILE_ASSET_IMPORT_APPEND);
+ }
+ BLI_addtail(&drag->asset_items, drag_asset);
+}
+
+const ListBase *WM_drag_asset_list_get(const wmDrag *drag)
+{
+ if (drag->type != WM_DRAG_ASSET_LIST) {
+ return NULL;
+ }
+
+ return &drag->asset_items;
+}
+
/* ************** draw ***************** */
static void wm_drop_operator_draw(const char *name, int x, int y)
@@ -490,6 +691,19 @@ static void wm_drop_operator_draw(const char *name, int x, int y)
UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, col_fg, col_bg);
}
+static void wm_drop_redalert_draw(const char *redalert_str, int x, int y)
+{
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+ const bTheme *btheme = UI_GetTheme();
+ const uiWidgetColors *wcol = &btheme->tui.wcol_tooltip;
+
+ float col_fg[4], col_bg[4];
+ UI_GetThemeColor4fv(TH_REDALERT, col_fg);
+ rgba_uchar_to_float(col_bg, wcol->inner);
+
+ UI_fontstyle_draw_simple_backdrop(fstyle, x, y, redalert_str, col_fg, col_bg);
+}
+
const char *WM_drag_get_item_name(wmDrag *drag)
{
switch (drag->type) {
@@ -516,132 +730,189 @@ const char *WM_drag_get_item_name(wmDrag *drag)
return "";
}
-static void drag_rect_minmax(rcti *rect, int x1, int y1, int x2, int y2)
+static void wm_drag_draw_icon(bContext *UNUSED(C),
+ wmWindow *UNUSED(win),
+ wmDrag *drag,
+ const int xy[2])
{
- if (rect->xmin > x1) {
- rect->xmin = x1;
- }
- if (rect->xmax < x2) {
- rect->xmax = x2;
- }
- if (rect->ymin > y1) {
- rect->ymin = y1;
+ int x, y;
+
+ /* This could also get the preview image of an ID when dragging one. But the big preview icon may
+ * actually not always be wanted, for example when dragging objects in the Outliner it gets in
+ * the way). So make the drag user set an image buffer explicitly (e.g. through
+ * #UI_but_drag_attach_image()). */
+
+ if (drag->imb) {
+ x = xy[0] - drag->sx / 2;
+ y = xy[1] - drag->sy / 2;
+
+ float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTexTiled_scaling(&state,
+ x,
+ y,
+ drag->imb->x,
+ drag->imb->y,
+ GPU_RGBA8,
+ false,
+ drag->imb->rect,
+ drag->scale,
+ drag->scale,
+ 1.0f,
+ 1.0f,
+ col);
}
- if (rect->ymax < y2) {
- rect->ymax = y2;
+ else {
+ int padding = 4 * UI_DPI_FAC;
+ x = xy[0] - 2 * padding;
+ y = xy[1] - 2 * UI_DPI_FAC;
+
+ const uchar text_col[] = {255, 255, 255, 255};
+ UI_icon_draw_ex(x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false);
}
}
-/* called in wm_draw.c */
-/* if rect set, do not draw */
-void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
+static void wm_drag_draw_item_name(wmDrag *drag, const int x, const int y)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- wmWindowManager *wm = CTX_wm_manager(C);
- const int winsize_y = WM_window_pixels_y(win);
+ const uchar text_col[] = {255, 255, 255, 255};
+ UI_fontstyle_draw_simple(fstyle, x, y, WM_drag_get_item_name(drag), text_col);
+}
- int cursorx = win->eventstate->x;
- int cursory = win->eventstate->y;
- if (rect) {
- rect->xmin = rect->xmax = cursorx;
- rect->ymin = rect->ymax = cursory;
- }
+void WM_drag_draw_item_name_fn(bContext *UNUSED(C),
+ wmWindow *UNUSED(win),
+ wmDrag *drag,
+ const int xy[2])
+{
+ int x = xy[0] + 10 * UI_DPI_FAC;
+ int y = xy[1] + 1 * UI_DPI_FAC;
- /* Should we support multi-line drag draws? Maybe not, more types mixed won't work well. */
- GPU_blend(GPU_BLEND_ALPHA);
- LISTBASE_FOREACH (wmDrag *, drag, &wm->drags) {
- const uchar text_col[] = {255, 255, 255, 255};
- int iconsize = UI_DPI_ICON_SIZE;
- int padding = 4 * UI_DPI_FAC;
+ wm_drag_draw_item_name(drag, x, y);
+}
- /* image or icon */
- int x, y;
- if (drag->imb) {
- x = cursorx - drag->sx / 2;
- y = cursory - drag->sy / 2;
+static void wm_drag_draw_tooltip(bContext *C, wmWindow *win, wmDrag *drag, const int xy[2])
+{
+ if (!CTX_wm_region(C)) {
+ /* Some callbacks require the region. */
+ return;
+ }
+ int iconsize = UI_DPI_ICON_SIZE;
+ int padding = 4 * UI_DPI_FAC;
- if (rect) {
- drag_rect_minmax(rect, x, y, x + drag->sx, y + drag->sy);
- }
- else {
- float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */
- IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTexScaled(&state,
- x,
- y,
- drag->imb->x,
- drag->imb->y,
- GPU_RGBA8,
- false,
- drag->imb->rect,
- drag->scale,
- drag->scale,
- 1.0f,
- 1.0f,
- col);
- }
- }
- else {
- x = cursorx - 2 * padding;
- y = cursory - 2 * UI_DPI_FAC;
+ char *tooltip = NULL;
+ if (drag->drop_state.active_dropbox) {
+ tooltip = dropbox_tooltip(C, drag, xy, drag->drop_state.active_dropbox);
+ }
- if (rect) {
- drag_rect_minmax(rect, x, y, x + iconsize, y + iconsize);
- }
- else {
- UI_icon_draw_ex(x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false);
- }
- }
+ const bool has_disabled_info = drag->drop_state.disabled_info &&
+ drag->drop_state.disabled_info[0];
+ if (!tooltip && !has_disabled_info) {
+ return;
+ }
+
+ const int winsize_y = WM_window_pixels_y(win);
+ int x, y;
+ if (drag->imb) {
+ x = xy[0] - drag->sx / 2;
- /* item name */
- if (drag->imb) {
- x = cursorx - drag->sx / 2;
- y = cursory - drag->sy / 2 - iconsize;
+ if (xy[1] + drag->sy / 2 + padding + iconsize < winsize_y) {
+ y = xy[1] + drag->sy / 2 + padding;
}
else {
- x = cursorx + 10 * UI_DPI_FAC;
- y = cursory + 1 * UI_DPI_FAC;
+ y = xy[1] - drag->sy / 2 - padding - iconsize - padding - iconsize;
}
+ }
+ else {
+ x = xy[0] - 2 * padding;
- if (rect) {
- int w = UI_fontstyle_string_width(fstyle, WM_drag_get_item_name(drag));
- drag_rect_minmax(rect, x, y, x + w, y + iconsize);
+ if (xy[1] + iconsize + iconsize < winsize_y) {
+ y = (xy[1] + iconsize) + padding;
}
else {
- UI_fontstyle_draw_simple(fstyle, x, y, WM_drag_get_item_name(drag), text_col);
+ y = (xy[1] - iconsize) - padding;
}
+ }
- /* operator name with roundbox */
- if (drag->tooltip[0]) {
- if (drag->imb) {
- x = cursorx - drag->sx / 2;
+ if (tooltip) {
+ wm_drop_operator_draw(tooltip, x, y);
+ MEM_freeN(tooltip);
+ }
+ else if (has_disabled_info) {
+ wm_drop_redalert_draw(drag->drop_state.disabled_info, x, y);
+ }
+}
- if (cursory + drag->sy / 2 + padding + iconsize < winsize_y) {
- y = cursory + drag->sy / 2 + padding;
- }
- else {
- y = cursory - drag->sy / 2 - padding - iconsize - padding - iconsize;
- }
- }
- else {
- x = cursorx - 2 * padding;
+static void wm_drag_draw_default(bContext *C, wmWindow *win, wmDrag *drag, const int xy[2])
+{
+ int xy_tmp[2] = {UNPACK2(xy)};
- if (cursory + iconsize + iconsize < winsize_y) {
- y = (cursory + iconsize) + padding;
- }
- else {
- y = (cursory - iconsize) - padding;
- }
- }
+ /* Image or icon. */
+ wm_drag_draw_icon(C, win, drag, xy_tmp);
- if (rect) {
- int w = UI_fontstyle_string_width(fstyle, WM_drag_get_item_name(drag));
- drag_rect_minmax(rect, x, y, x + w, y + iconsize);
- }
- else {
- wm_drop_operator_draw(drag->tooltip, x, y);
+ /* Item name. */
+ if (drag->imb) {
+ int iconsize = UI_DPI_ICON_SIZE;
+ xy_tmp[0] = xy[0] - (drag->sx / 2);
+ xy_tmp[1] = xy[1] - (drag->sy / 2) - iconsize;
+ }
+ else {
+ xy_tmp[0] = xy[0] + 10 * UI_DPI_FAC;
+ xy_tmp[1] = xy[1] + 1 * UI_DPI_FAC;
+ }
+ wm_drag_draw_item_name(drag, UNPACK2(xy_tmp));
+
+ /* Operator name with roundbox. */
+ wm_drag_draw_tooltip(C, win, drag, xy);
+}
+
+void WM_drag_draw_default_fn(bContext *C, wmWindow *win, wmDrag *drag, const int xy[2])
+{
+ wm_drag_draw_default(C, win, drag, xy);
+}
+
+void wm_drags_draw(bContext *C, wmWindow *win)
+{
+ int xy[2];
+ if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) {
+ wm_cursor_position_get(win, &xy[0], &xy[1]);
+ }
+ else {
+ xy[0] = win->eventstate->xy[0];
+ xy[1] = win->eventstate->xy[1];
+ }
+
+ bScreen *screen = CTX_wm_screen(C);
+ /* To start with, use the area and region under the mouse cursor, just like event handling. The
+ * operator context may still override it. */
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, xy);
+ ARegion *region = ED_area_find_region_xy_visual(area, RGN_TYPE_ANY, xy);
+ /* Will be overridden and unset eventually. */
+ BLI_assert(!CTX_wm_area(C) && !CTX_wm_region(C));
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ /* Should we support multi-line drag draws? Maybe not, more types mixed won't work well. */
+ GPU_blend(GPU_BLEND_ALPHA);
+ LISTBASE_FOREACH (wmDrag *, drag, &wm->drags) {
+ if (drag->drop_state.active_dropbox) {
+ CTX_wm_area_set(C, drag->drop_state.area_from);
+ CTX_wm_region_set(C, drag->drop_state.region_from);
+
+ /* Drawing should be allowed to assume the context from handling and polling (that's why we
+ * restore it above). */
+ if (drag->drop_state.active_dropbox->draw) {
+ drag->drop_state.active_dropbox->draw(C, win, drag, xy);
+ continue;
}
}
+ else if (region) {
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
+ }
+
+ wm_drag_draw_default(C, win, drag, xy);
}
GPU_blend(GPU_BLEND_NONE);
+ CTX_wm_area_set(C, NULL);
+ CTX_wm_region_set(C, NULL);
}
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 328950cf8f9..9dfac54a91e 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -108,6 +108,8 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region)
}
if (pc->poll == NULL || pc->poll(C)) {
+ UI_SetTheme(area->spacetype, region->regiontype);
+
/* Prevent drawing outside region. */
GPU_scissor_test(true);
GPU_scissor(region->winrct.xmin,
@@ -121,7 +123,7 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region)
pc->draw(C, x, y, pc->customdata);
}
else {
- pc->draw(C, win->eventstate->x, win->eventstate->y, pc->customdata);
+ pc->draw(C, win->eventstate->xy[0], win->eventstate->xy[1], pc->customdata);
}
GPU_scissor_test(false);
@@ -146,6 +148,7 @@ static void wm_region_draw_overlay(bContext *C, ScrArea *area, ARegion *region)
}
/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
* \{ */
@@ -839,6 +842,7 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
}
/* After area regions so we can do area 'overlay' drawing. */
+ UI_SetTheme(0, 0);
ED_screen_draw_edges(win);
wm_draw_callbacks(win);
wmWindowViewport(win);
@@ -856,9 +860,9 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
wm_gesture_draw(win);
}
- /* needs pixel coords in screen */
+ /* Needs pixel coords in screen. */
if (wm->drags.first) {
- wm_drags_draw(C, win, NULL);
+ wm_drags_draw(C, win);
}
GPU_debug_group_end();
@@ -1136,7 +1140,7 @@ void WM_redraw_windows(bContext *C)
* This is needed for viewport drawing for operator use
* (where the viewport may not have drawn yet).
*
- * Otherwise avoid using these sine they're exposing low level logic externally.
+ * Otherwise avoid using these since they're exposing low level logic externally.
*
* \{ */
diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c
index 7b5691b99a0..22cd68ddbd7 100644
--- a/source/blender/windowmanager/intern/wm_event_query.c
+++ b/source/blender/windowmanager/intern/wm_event_query.c
@@ -71,7 +71,6 @@ static void event_ids_from_type_and_value(const short type,
}
}
-/* for debugging only, getting inspecting events manually is tedious */
void WM_event_print(const wmEvent *event)
{
if (event) {
@@ -82,7 +81,7 @@ void WM_event_print(const wmEvent *event)
const char *prev_val_id = unknown;
event_ids_from_type_and_value(event->type, event->val, &type_id, &val_id);
- event_ids_from_type_and_value(event->prevtype, event->prevval, &prev_type_id, &prev_val_id);
+ event_ids_from_type_and_value(event->prev_type, event->prev_val, &prev_type_id, &prev_val_id);
printf(
"wmEvent type:%d / %s, val:%d / %s,\n"
@@ -93,9 +92,9 @@ void WM_event_print(const wmEvent *event)
type_id,
event->val,
val_id,
- event->prevtype,
+ event->prev_type,
prev_type_id,
- event->prevval,
+ event->prev_val,
prev_val_id,
event->shift,
event->ctrl,
@@ -103,8 +102,8 @@ void WM_event_print(const wmEvent *event)
event->oskey,
event->keymodifier,
event->is_repeat,
- event->x,
- event->y,
+ event->xy[0],
+ event->xy[1],
event->ascii,
BLI_str_utf8_size(event->utf8_buf),
event->utf8_buf,
@@ -218,7 +217,6 @@ bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask ma
/** \name Event Motion Queries
* \{ */
-/* for modal callbacks, check configuration for how to interpret exit with tweaks. */
bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event)
{
/* if the release-confirm userpref setting is enabled,
@@ -276,6 +274,14 @@ bool WM_event_is_mouse_drag_or_press(const wmEvent *event)
(ISMOUSE_BUTTON(event->type) && (event->val == KM_PRESS));
}
+bool WM_cursor_test_motion_and_update(const int mval[2])
+{
+ static int mval_prev[2] = {-1, -1};
+ bool use_cycle = (len_manhattan_v2v2_int(mval, mval_prev) <= WM_EVENT_CURSOR_MOTION_THRESHOLD);
+ copy_v2_v2_int(mval_prev, mval);
+ return !use_cycle;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -288,8 +294,8 @@ bool WM_event_is_mouse_drag_or_press(const wmEvent *event)
int WM_event_drag_threshold(const struct wmEvent *event)
{
int drag_threshold;
- if (ISMOUSE(event->prevtype)) {
- BLI_assert(event->prevtype != MOUSEMOVE);
+ if (ISMOUSE(event->prev_type)) {
+ BLI_assert(event->prev_type != MOUSEMOVE);
/* Using the previous type is important is we want to check the last pressed/released button,
* The `event->type` would include #MOUSEMOVE which is always the case when dragging
* and does not help us know which threshold to use. */
@@ -315,10 +321,8 @@ bool WM_event_drag_test_with_delta(const wmEvent *event, const int drag_delta[2]
bool WM_event_drag_test(const wmEvent *event, const int prev_xy[2])
{
- const int drag_delta[2] = {
- prev_xy[0] - event->x,
- prev_xy[1] - event->y,
- };
+ int drag_delta[2];
+ sub_v2_v2v2_int(drag_delta, prev_xy, event->xy);
return WM_event_drag_test_with_delta(event, drag_delta);
}
@@ -340,11 +344,6 @@ int WM_userdef_event_map(int kmitype)
return kmitype;
}
-/**
- * Use so we can check if 'wmEvent.type' is released in modal operators.
- *
- * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar.
- */
int WM_userdef_event_type_from_keymap_type(int kmitype)
{
switch (kmitype) {
@@ -411,10 +410,22 @@ void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4])
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Event XR Input Access
+ * \{ */
+
+#ifdef WITH_XR_OPENXR
+bool WM_event_is_xr(const struct wmEvent *event)
+{
+ return (event->type == EVT_XR_ACTION && event->custom == EVT_DATA_XR);
+}
+#endif
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Event Tablet Input Access
* \{ */
-/* applies the global tablet pressure correction curve */
float wm_pressure_curve(float pressure)
{
if (U.pressure_threshold_max != 0.0f) {
@@ -430,8 +441,6 @@ float wm_pressure_curve(float pressure)
return pressure;
}
-/* if this is a tablet event, return tablet pressure and set *pen_flip
- * to 1 if the eraser tool is being used, 0 otherwise */
float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2])
{
if (tilt) {
@@ -463,7 +472,7 @@ bool WM_event_is_tablet(const struct wmEvent *event)
int WM_event_absolute_delta_x(const struct wmEvent *event)
{
- int dx = event->x - event->prevx;
+ int dx = event->xy[0] - event->prev_xy[0];
if (!event->is_direction_inverted) {
dx = -dx;
@@ -474,7 +483,7 @@ int WM_event_absolute_delta_x(const struct wmEvent *event)
int WM_event_absolute_delta_y(const struct wmEvent *event)
{
- int dy = event->y - event->prevy;
+ int dy = event->xy[1] - event->prev_xy[1];
if (!event->is_direction_inverted) {
dy = -dy;
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 14fcc1d69cc..3e30c06ade2 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -51,6 +51,7 @@
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -64,6 +65,7 @@
#include "ED_asset.h"
#include "ED_fileselect.h"
#include "ED_info.h"
+#include "ED_render.h"
#include "ED_screen.h"
#include "ED_undo.h"
#include "ED_util.h"
@@ -83,6 +85,7 @@
#include "wm.h"
#include "wm_event_system.h"
#include "wm_event_types.h"
+#include "wm_surface.h"
#include "wm_window.h"
#include "DEG_depsgraph.h"
@@ -108,7 +111,7 @@ static int wm_operator_call_internal(bContext *C,
wmOperatorType *ot,
PointerRNA *properties,
ReportList *reports,
- const short context,
+ const wmOperatorCallContext context,
const bool poll_only,
wmEvent *event);
@@ -152,25 +155,22 @@ wmEvent *WM_event_add_simulate(wmWindow *win, const wmEvent *event_to_add)
/* Logic for setting previous value is documented on the #wmEvent struct,
* see #wm_event_add_ghostevent for the implementation of logic this follows. */
-
- win->eventstate->x = event->x;
- win->eventstate->y = event->y;
+ copy_v2_v2_int(win->eventstate->xy, event->xy);
if (event->type == MOUSEMOVE) {
- win->eventstate->prevx = event->prevx = win->eventstate->x;
- win->eventstate->prevy = event->prevy = win->eventstate->y;
+ copy_v2_v2_int(win->eventstate->prev_xy, win->eventstate->xy);
+ copy_v2_v2_int(event->prev_xy, win->eventstate->xy);
}
else if (ISMOUSE_BUTTON(event->type) || ISKEYBOARD(event->type)) {
- win->eventstate->prevval = event->prevval = win->eventstate->val;
- win->eventstate->prevtype = event->prevtype = win->eventstate->type;
+ win->eventstate->prev_val = event->prev_val = win->eventstate->val;
+ win->eventstate->prev_type = event->prev_type = win->eventstate->type;
win->eventstate->val = event->val;
win->eventstate->type = event->type;
if (event->val == KM_PRESS) {
if (event->is_repeat == false) {
- win->eventstate->prevclickx = event->x;
- win->eventstate->prevclicky = event->y;
+ copy_v2_v2_int(win->eventstate->prev_click_xy, event->xy);
}
}
}
@@ -189,7 +189,7 @@ void wm_event_free(wmEvent *event)
#endif
if (event->customdata) {
- if (event->customdatafree) {
+ if (event->customdata_free) {
/* NOTE: pointer to listbase struct elsewhere. */
if (event->custom == EVT_DATA_DRAGDROP) {
ListBase *lb = event->customdata;
@@ -290,9 +290,6 @@ void WM_main_add_notifier(unsigned int type, void *reference)
note->reference = reference;
}
-/**
- * Clear notifiers by reference, Used so listeners don't act on freed data.
- */
void WM_main_remove_notifier_reference(const void *reference)
{
Main *bmain = G_MAIN;
@@ -316,28 +313,39 @@ void WM_main_remove_notifier_reference(const void *reference)
}
}
-void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id)
+static void wm_main_remap_assetlist(ID *old_id, ID *new_id, void *UNUSED(user_data))
+{
+ ED_assetlist_storage_id_remap(old_id, new_id);
+}
+
+static void wm_main_remap_msgbus_notify(ID *old_id, ID *new_id, void *user_data)
+{
+ struct wmMsgBus *mbus = user_data;
+ if (new_id != NULL) {
+ WM_msg_id_update(mbus, old_id, new_id);
+ }
+ else {
+ WM_msg_id_remove(mbus, old_id);
+ }
+}
+
+void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings)
{
Main *bmain = G_MAIN;
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
- ED_spacedata_id_remap(area, sl, old_id, new_id);
+ ED_spacedata_id_remap(area, sl, mappings);
}
}
}
- ED_assetlist_storage_id_remap(old_id, new_id);
+
+ BKE_id_remapper_iter(mappings, wm_main_remap_assetlist, NULL);
wmWindowManager *wm = bmain->wm.first;
if (wm && wm->message_bus) {
- struct wmMsgBus *mbus = wm->message_bus;
- if (new_id != NULL) {
- WM_msg_id_update(mbus, old_id, new_id);
- }
- else {
- WM_msg_id_remove(mbus, old_id);
- }
+ BKE_id_remapper_iter(mappings, wm_main_remap_msgbus_notify, wm->message_bus);
}
}
@@ -387,13 +395,10 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file)
DEG_make_active(depsgraph);
BKE_scene_graph_update_tagged(depsgraph, bmain);
}
+
+ wm_surfaces_do_depsgraph(C);
}
-/**
- * Was part of #wm_event_do_notifiers,
- * split out so it can be called once before entering the #WM_main loop.
- * This ensures operators don't run before the UI and depsgraph are initialized.
- */
void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -430,7 +435,6 @@ static void wm_event_execute_timers(bContext *C)
CTX_wm_window_set(C, NULL);
}
-/* Called in mainloop. */
void wm_event_do_notifiers(bContext *C)
{
/* Run the timer before assigning 'wm' in the unlikely case a timer loads a file, see T80028. */
@@ -460,6 +464,9 @@ void wm_event_do_notifiers(bContext *C)
else if (note->data == ND_DATACHANGED) {
wm_window_title(wm, win);
}
+ else if (note->data == ND_UNDO) {
+ ED_preview_restart_queue_work(C);
+ }
}
if (note->window == win) {
if (note->category == NC_SCREEN) {
@@ -505,8 +512,7 @@ void wm_event_do_notifiers(bContext *C)
}
}
- if (note->window == win ||
- (note->window == NULL && (note->reference == NULL || note->reference == scene))) {
+ if (note->window == win || (note->window == NULL && (ELEM(note->reference, NULL, scene)))) {
if (note->category == NC_SCENE) {
if (note->data == ND_FRAME) {
do_anim = true;
@@ -581,7 +587,7 @@ void wm_event_do_notifiers(bContext *C)
if ((note->category == NC_SPACE) && note->reference) {
/* Filter out notifiers sent to other spaces. RNA sets the reference to the owning ID
* though, the screen, so let notifiers through that reference the entire screen. */
- if (!ELEM(note->reference, area->spacedata.first, screen)) {
+ if (!ELEM(note->reference, area->spacedata.first, screen, scene)) {
continue;
}
}
@@ -756,9 +762,6 @@ static void wm_event_handler_ui_cancel(bContext *C)
* Access to #wmWindowManager.reports
* \{ */
-/**
- * Show the report in the info header.
- */
void WM_report_banner_show(void)
{
wmWindowManager *wm = G_MAIN->wm.first;
@@ -774,9 +777,6 @@ void WM_report_banner_show(void)
wm_reports->reporttimer->customdata = rti;
}
-/**
- * Hide all currently displayed banners and abort their timer.
- */
void WM_report_banners_cancel(Main *bmain)
{
wmWindowManager *wm = bmain->wm.first;
@@ -804,7 +804,7 @@ static void wm_add_reports(ReportList *reports)
}
}
-void WM_report(ReportType type, const char *message)
+void WM_report(eReportType type, const char *message)
{
ReportList reports;
BKE_reports_init(&reports, RPT_STORE);
@@ -815,7 +815,7 @@ void WM_report(ReportType type, const char *message)
BKE_reports_clear(&reports);
}
-void WM_reportf(ReportType type, const char *format, ...)
+void WM_reportf(eReportType type, const char *format, ...)
{
va_list args;
@@ -859,9 +859,9 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot)
return true;
}
-/* sets up the new context and calls 'wm_operator_invoke()' with poll_only */
bool WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context)
{
+ /* Sets up the new context and calls #wm_operator_invoke() with poll_only. */
return wm_operator_call_internal(C, ot, NULL, NULL, context, true, NULL);
}
@@ -896,11 +896,6 @@ bool WM_operator_check_ui_empty(wmOperatorType *ot)
return true;
}
-/**
- * Sets the active region for this space from the context.
- *
- * \see #BKE_area_find_region_active_win
- */
void WM_operator_region_active_win_set(bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -1107,13 +1102,6 @@ static int wm_operator_exec_notest(bContext *C, wmOperator *op)
return retval;
}
-/**
- * For running operators with frozen context (modal handlers, menus).
- *
- * \param store: Store settings for re-use.
- *
- * \warning do not use this within an operator to call its self! T29537.
- */
int WM_operator_call_ex(bContext *C, wmOperator *op, const bool store)
{
return wm_operator_exec(C, op, false, store);
@@ -1124,19 +1112,11 @@ int WM_operator_call(bContext *C, wmOperator *op)
return WM_operator_call_ex(C, op, false);
}
-/**
- * This is intended to be used when an invoke operator wants to call exec on its self
- * and is basically like running op->type->exec() directly, no poll checks no freeing,
- * since we assume whoever called invoke will take care of that
- */
int WM_operator_call_notest(bContext *C, wmOperator *op)
{
return wm_operator_exec_notest(C, op);
}
-/**
- * Execute this operator again, put here so it can share above code
- */
int WM_operator_repeat(bContext *C, wmOperator *op)
{
const int op_flag = OP_IS_REPEAT;
@@ -1153,12 +1133,6 @@ int WM_operator_repeat_last(bContext *C, wmOperator *op)
op->flag &= ~op_flag;
return ret;
}
-/**
- * \return true if #WM_operator_repeat can run.
- * Simple check for now but may become more involved.
- * To be sure the operator can run call `WM_operator_poll(C, op->type)` also, since this call
- * checks if #WM_operator_repeat() can run at all, not that it WILL run at any time.
- */
bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
{
if (op->type->exec != NULL) {
@@ -1286,8 +1260,8 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event)
ARegion *region = CTX_wm_region(C);
if (region) {
/* Compatibility convention. */
- event->mval[0] = event->x - region->winrct.xmin;
- event->mval[1] = event->y - region->winrct.ymin;
+ event->mval[0] = event->xy[0] - region->winrct.xmin;
+ event->mval[1] = event->xy[1] - region->winrct.ymin;
}
else {
/* These values are invalid (avoid odd behavior by relying on old mval values). */
@@ -1423,10 +1397,10 @@ static int wm_operator_invoke(bContext *C,
}
if (region && region->regiontype == RGN_TYPE_WINDOW &&
- BLI_rcti_isect_pt_v(&region->winrct, &event->x)) {
+ BLI_rcti_isect_pt_v(&region->winrct, event->xy)) {
winrect = &region->winrct;
}
- else if (area && BLI_rcti_isect_pt_v(&area->totrct, &event->x)) {
+ else if (area && BLI_rcti_isect_pt_v(&area->totrct, event->xy)) {
winrect = &area->totrct;
}
@@ -1464,7 +1438,7 @@ static int wm_operator_call_internal(bContext *C,
wmOperatorType *ot,
PointerRNA *properties,
ReportList *reports,
- const short context,
+ const wmOperatorCallContext context,
const bool poll_only,
wmEvent *event)
{
@@ -1596,16 +1570,18 @@ static int wm_operator_call_internal(bContext *C,
return 0;
}
-/* Invokes operator in context. */
int WM_operator_name_call_ptr(bContext *C,
wmOperatorType *ot,
- short context,
+ wmOperatorCallContext context,
PointerRNA *properties)
{
BLI_assert(ot == WM_operatortype_find(ot->idname, true));
return wm_operator_call_internal(C, ot, properties, NULL, context, false, NULL);
}
-int WM_operator_name_call(bContext *C, const char *opstring, short context, PointerRNA *properties)
+int WM_operator_name_call(bContext *C,
+ const char *opstring,
+ wmOperatorCallContext context,
+ PointerRNA *properties)
{
wmOperatorType *ot = WM_operatortype_find(opstring, 0);
if (ot) {
@@ -1615,9 +1591,19 @@ int WM_operator_name_call(bContext *C, const char *opstring, short context, Poin
return 0;
}
+bool WM_operator_name_poll(bContext *C, const char *opstring)
+{
+ wmOperatorType *ot = WM_operatortype_find(opstring, 0);
+ if (!ot) {
+ return false;
+ }
+
+ return WM_operator_poll(C, ot);
+}
+
int WM_operator_name_call_with_properties(struct bContext *C,
const char *opstring,
- short context,
+ wmOperatorCallContext context,
struct IDProperty *properties)
{
PointerRNA props_ptr;
@@ -1626,9 +1612,6 @@ int WM_operator_name_call_with_properties(struct bContext *C,
return WM_operator_name_call_ptr(C, ot, context, &props_ptr);
}
-/**
- * Call an existent menu. The menu can be created in C or Python.
- */
void WM_menu_name_call(bContext *C, const char *menu_name, short context)
{
wmOperatorType *ot = WM_operatortype_find("WM_OT_call_menu", false);
@@ -1639,16 +1622,9 @@ void WM_menu_name_call(bContext *C, const char *menu_name, short context)
WM_operator_properties_free(&ptr);
}
-/**
- * Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context.
- *
- * - #wmOperatorType is used instead of operator name since python already has the operator type.
- * - `poll()` must be called by python before this runs.
- * - reports can be passed to this function (so python can report them as exceptions).
- */
int WM_operator_call_py(bContext *C,
wmOperatorType *ot,
- short context,
+ wmOperatorCallContext context,
PointerRNA *properties,
ReportList *reports,
const bool is_undo)
@@ -1772,8 +1748,11 @@ static int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *us
return WM_UI_HANDLER_CONTINUE;
}
-void WM_operator_name_call_ptr_with_depends_on_cursor(
- bContext *C, wmOperatorType *ot, short opcontext, PointerRNA *properties, const char *drawstr)
+void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
+ wmOperatorType *ot,
+ wmOperatorCallContext opcontext,
+ PointerRNA *properties,
+ const char *drawstr)
{
int flag = ot->flag;
@@ -1790,7 +1769,10 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(
}
wmWindow *win = CTX_wm_window(C);
- ScrArea *area = CTX_wm_area(C);
+ /* The operator context is applied when the operator is called,
+ * the check for the area needs to be explicitly limited here.
+ * Useful so it's possible to screen-shot an area without drawing into it's header. */
+ ScrArea *area = WM_OP_CONTEXT_HAS_AREA(opcontext) ? CTX_wm_area(C) : NULL;
{
char header_text[UI_MAX_DRAW_STR];
@@ -1806,7 +1788,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(
}
}
- WM_cursor_modal_set(win, WM_CURSOR_PICK_AREA);
+ WM_cursor_modal_set(win, ot->cursor_pending);
uiOperatorWaitForInput *opwait = MEM_callocN(sizeof(*opwait), __func__);
opwait->optype_params.optype = ot;
@@ -1844,9 +1826,9 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(
* General API for different handler types.
* \{ */
-/* Future extra customadata free? */
void wm_event_free_handler(wmEventHandler *handler)
{
+ /* Future extra customa-data free? */
MEM_freeN(handler);
}
@@ -1891,7 +1873,7 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
CTX_wm_area_set(C, area);
if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) {
- region = BKE_area_find_region_xy(area, handler->context.region_type, event->x, event->y);
+ region = BKE_area_find_region_xy(area, handler->context.region_type, event->xy);
if (region) {
handler->context.region = region;
}
@@ -1917,7 +1899,6 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
}
}
-/* Called on exit or remove area, only here call cancel callback. */
void WM_event_remove_handlers(bContext *C, ListBase *handlers)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -2106,8 +2087,8 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap,
}
struct wmEvent_ModalMapStore {
- short prevtype;
- short prevval;
+ short prev_type;
+ short prev_val;
bool dbl_click_disabled;
};
@@ -2155,19 +2136,19 @@ static void wm_event_modalkeymap_begin(const bContext *C,
}
if (event_match != NULL) {
- event_backup->prevtype = event->prevtype;
- event_backup->prevval = event->prevval;
+ event_backup->prev_type = event->prev_type;
+ event_backup->prev_val = event->prev_val;
- event->prevtype = event_match->type;
- event->prevval = event_match->val;
+ event->prev_type = event_match->type;
+ event->prev_val = event_match->val;
event->type = EVT_MODAL_MAP;
event->val = kmi->propvalue;
/* Avoid double-click events even in the case of 'EVT_MODAL_MAP',
* since it's possible users configure double-click keymap items
* which would break when modal functions expect press/release. */
- if (event->prevtype == KM_DBL_CLICK) {
- event->prevtype = KM_PRESS;
+ if (event->prev_type == KM_DBL_CLICK) {
+ event->prev_type = KM_PRESS;
event_backup->dbl_click_disabled = true;
}
}
@@ -2193,11 +2174,11 @@ static void wm_event_modalkeymap_end(wmEvent *event,
const struct wmEvent_ModalMapStore *event_backup)
{
if (event->type == EVT_MODAL_MAP) {
- event->type = event->prevtype;
- event->val = event->prevval;
+ event->type = event->prev_type;
+ event->val = event->prev_val;
- event->prevtype = event_backup->prevtype;
- event->prevval = event_backup->prevval;
+ event->prev_type = event_backup->prev_type;
+ event->prev_val = event_backup->prev_val;
}
if (event_backup->dbl_click_disabled) {
@@ -2294,7 +2275,7 @@ static int wm_handler_operator_call(bContext *C,
CTX_wm_region_set(C, NULL);
}
- /* /update gizmos during modal handlers. */
+ /* Update gizmos during modal handlers. */
wm_gizmomaps_handled_modal_update(C, event, handler);
/* Remove modal handler, operator itself should have been canceled and freed. */
@@ -2489,7 +2470,8 @@ static int wm_handler_fileselect_do(bContext *C,
wm_window_make_drawable(wm, ctx_win);
/* Ensure correct cursor position, otherwise, popups may close immediately after
* opening (UI_BLOCK_MOVEMOUSE_QUIT). */
- wm_cursor_position_get(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y);
+ wm_cursor_position_get(
+ ctx_win, &ctx_win->eventstate->xy[0], &ctx_win->eventstate->xy[1]);
wm->winactive = ctx_win; /* Reports use this... */
if (handler->context.win == win) {
handler->context.win = NULL;
@@ -2665,7 +2647,34 @@ static int wm_handlers_do_keymap_with_keymap_handler(
if (wm_eventmatch(event, kmi)) {
struct wmEventHandler_KeymapPost keymap_post = handler->post;
- PRINT("%s: item matched '%s'\n", __func__, kmi->idname);
+ if (do_debug_handler) {
+ /* Short representation of the key that was pressed,
+ * include this since it may differ from the event in minor details
+ * which can help looking up the key-map definition. */
+ char kmi_buf[256];
+ WM_keymap_item_to_string(kmi, false, kmi_buf, sizeof(kmi_buf));
+
+ /* The key-map item properties can further help distinguish this item from others. */
+ char *kmi_props = NULL;
+ if (kmi->properties != NULL) {
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ if (ot) {
+ kmi_props = RNA_pointer_as_string_keywords(C, kmi->ptr, false, false, true, 512);
+ }
+ else { /* Fallback. */
+ kmi_props = IDP_reprN(kmi->properties, NULL);
+ }
+ }
+
+ printf("%s: item matched: \"%s\", %s(%s)\n",
+ __func__,
+ kmi_buf,
+ kmi->idname,
+ kmi_props ? kmi_props : "");
+ if (kmi_props != NULL) {
+ MEM_freeN(kmi_props);
+ }
+ }
action |= wm_handler_operator_call(
C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
@@ -2782,7 +2791,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
* noticeable for the node editor - where dragging on a node should move it, see: T73212.
* note we still allow for starting the gizmo drag outside, then travel 'inside' the node. */
if (region->type->clip_gizmo_events_by_ui) {
- if (UI_region_block_find_mouse_over(region, &event->x, true)) {
+ if (UI_region_block_find_mouse_over(region, event->xy, true)) {
if (gz != NULL && event->type != EVT_GIZMO_UPDATE) {
if (restore_highlight_unless_activated == false) {
WM_tooltip_clear(C, CTX_wm_window(C));
@@ -2947,7 +2956,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
/** \name Handle Single Event (All Handler Types)
* \{ */
-static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers)
+static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, ListBase *handlers)
{
const bool do_debug_handler =
(G.debug & G_DEBUG_HANDLERS) &&
@@ -2990,7 +2999,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
wmEventHandler_KeymapResult km_result;
- WM_event_get_keymaps_from_handler(wm, handler, &km_result);
+ WM_event_get_keymaps_from_handler(wm, win, handler, &km_result);
int action_iter = WM_HANDLER_CONTINUE;
for (int km_index = 0; km_index < km_result.keymaps_len; km_index++) {
wmKeyMap *keymap = km_result.keymaps[km_index];
@@ -3025,22 +3034,19 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
/* Other drop custom types allowed. */
if (event->custom == EVT_DATA_DRAGDROP) {
ListBase *lb = (ListBase *)event->customdata;
- LISTBASE_FOREACH (wmDrag *, drag, lb) {
+ LISTBASE_FOREACH_MUTABLE (wmDrag *, drag, lb) {
if (drop->poll(C, drag, event)) {
- /* Optionally copy drag information to operator properties. Don't call it if the
- * operator fails anyway, it might do more than just set properties (e.g.
- * typically import an asset). */
- if (drop->copy && WM_operator_poll_context(C, drop->ot, drop->opcontext)) {
- drop->copy(drag, drop);
- }
+ wm_drop_prepare(C, drag, drop);
/* Pass single matched wmDrag onto the operator. */
BLI_remlink(lb, drag);
- ListBase single_lb = {drag, drag};
+ ListBase single_lb = {0};
+ BLI_addtail(&single_lb, drag);
event->customdata = &single_lb;
+ const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop);
int op_retval = wm_operator_call_internal(
- C, drop->ot, drop->ptr, NULL, drop->opcontext, false, event);
+ C, drop->ot, drop->ptr, NULL, opcontext, false, event);
OPERATOR_RETVAL_CHECK(op_retval);
if ((op_retval & OPERATOR_CANCELLED) && drop->cancel) {
@@ -3065,6 +3071,8 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
break;
}
}
+ /* Always exit all drags on a drop event, even if poll didn't succeed. */
+ wm_drags_exit(wm, win);
}
}
}
@@ -3130,7 +3138,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
/* This calls handlers twice - to solve (double-)click events. */
static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
{
- int action = wm_handlers_do_intern(C, event, handlers);
+ int action = wm_handlers_do_intern(C, CTX_wm_window(C), event, handlers);
/* Will be NULL in the file read case. */
wmWindow *win = CTX_wm_window(C);
@@ -3142,27 +3150,24 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
/* Test for CLICK_DRAG events. */
if (wm_action_not_handled(action)) {
if (win->event_queue_check_drag) {
- if (WM_event_drag_test(event, &event->prevclickx)) {
+ if (WM_event_drag_test(event, event->prev_click_xy)) {
win->event_queue_check_drag_handled = true;
- int x = event->x;
- int y = event->y;
+ int xy[2] = {UNPACK2(event->xy)};
short val = event->val;
short type = event->type;
- event->x = event->prevclickx;
- event->y = event->prevclicky;
+ copy_v2_v2_int(event->xy, event->prev_click_xy);
event->val = KM_CLICK_DRAG;
- event->type = event->prevtype;
+ event->type = event->prev_type;
CLOG_INFO(WM_LOG_HANDLERS, 1, "handling PRESS_DRAG");
- action |= wm_handlers_do_intern(C, event, handlers);
+ action |= wm_handlers_do_intern(C, win, event, handlers);
event->val = val;
event->type = type;
- event->x = x;
- event->y = y;
+ copy_v2_v2_int(event->xy, xy);
win->event_queue_check_click = false;
if (!wm_action_not_handled(action)) {
@@ -3177,7 +3182,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
}
}
else if (ISMOUSE_BUTTON(event->type) || ISKEYBOARD(event->type)) {
- /* All events that don't set wmEvent.prevtype must be ignored. */
+ /* All events that don't set wmEvent.prev_type must be ignored. */
/* Test for CLICK events. */
if (wm_action_not_handled(action)) {
@@ -3195,32 +3200,29 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
win->event_queue_check_drag = false;
}
- if (event->prevtype == event->type) {
+ if (event->prev_type == event->type) {
if (event->val == KM_RELEASE) {
- if (event->prevval == KM_PRESS) {
+ if (event->prev_val == KM_PRESS) {
if (win->event_queue_check_click == true) {
- if (WM_event_drag_test(event, &event->prevclickx)) {
+ if (WM_event_drag_test(event, event->prev_click_xy)) {
win->event_queue_check_click = false;
win->event_queue_check_drag = false;
}
else {
/* Position is where the actual click happens, for more
* accurate selecting in case the mouse drifts a little. */
- int x = event->x;
- int y = event->y;
+ int xy[2] = {UNPACK2(event->xy)};
- event->x = event->prevclickx;
- event->y = event->prevclicky;
+ copy_v2_v2_int(event->xy, event->prev_click_xy);
event->val = KM_CLICK;
CLOG_INFO(WM_LOG_HANDLERS, 1, "handling CLICK");
- action |= wm_handlers_do_intern(C, event, handlers);
+ action |= wm_handlers_do_intern(C, win, event, handlers);
event->val = KM_RELEASE;
- event->x = x;
- event->y = y;
+ copy_v2_v2_int(event->xy, xy);
}
}
}
@@ -3228,7 +3230,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
else if (event->val == KM_DBL_CLICK) {
/* The underlying event is a press, so try and handle this. */
event->val = KM_PRESS;
- action |= wm_handlers_do_intern(C, event, handlers);
+ action |= wm_handlers_do_intern(C, win, event, handlers);
/* revert value if not handled */
if (wm_action_not_handled(action)) {
@@ -3249,7 +3251,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
/* pass */
}
else {
- if (ISKEYMODIFIER(event->prevtype)) {
+ if (ISKEYMODIFIER(event->prev_type)) {
win->event_queue_check_click = false;
}
}
@@ -3271,7 +3273,7 @@ static bool wm_event_inside_rect(const wmEvent *event, const rcti *rect)
if (wm_event_always_pass(event)) {
return true;
}
- if (BLI_rcti_isect_pt_v(rect, &event->x)) {
+ if (BLI_rcti_isect_pt_v(rect, event->xy)) {
return true;
}
return false;
@@ -3282,7 +3284,7 @@ static bool wm_event_inside_region(const wmEvent *event, const ARegion *region)
if (wm_event_always_pass(event)) {
return true;
}
- return ED_region_contains_xy(region, &event->x);
+ return ED_region_contains_xy(region, event->xy);
}
static ScrArea *area_event_inside(bContext *C, const int xy[2])
@@ -3341,11 +3343,11 @@ static void wm_paintcursor_test(bContext *C, const wmEvent *event)
}
/* If previous position was not in current region, we have to set a temp new context. */
- if (region == NULL || !BLI_rcti_isect_pt_v(&region->winrct, &event->prevx)) {
+ if (region == NULL || !BLI_rcti_isect_pt_v(&region->winrct, event->prev_xy)) {
ScrArea *area = CTX_wm_area(C);
- CTX_wm_area_set(C, area_event_inside(C, &event->prevx));
- CTX_wm_region_set(C, region_event_inside(C, &event->prevx));
+ CTX_wm_area_set(C, area_event_inside(C, event->prev_xy));
+ CTX_wm_region_set(C, region_event_inside(C, event->prev_xy));
wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
@@ -3367,6 +3369,7 @@ static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEv
screen->do_draw_drag = true;
}
else if (event->type == EVT_ESCKEY) {
+ wm_drags_exit(wm, win);
WM_drag_free_list(&wm->drags);
screen->do_draw_drag = true;
@@ -3376,14 +3379,14 @@ static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEv
/* Create customdata, first free existing. */
if (event->customdata) {
- if (event->customdatafree) {
+ if (event->customdata_free) {
MEM_freeN(event->customdata);
}
}
event->custom = EVT_DATA_DRAGDROP;
event->customdata = &wm->drags;
- event->customdatafree = 1;
+ event->customdata_free = true;
/* Clear drop icon. */
screen->do_draw_drag = true;
@@ -3433,8 +3436,70 @@ static void wm_event_free_and_remove_from_queue_if_valid(wmEvent *event)
* Handle events for all windows, run from the #WM_main event loop.
* \{ */
-/* Called in main loop. */
-/* Goes over entire hierarchy: events -> window -> screen -> area -> region. */
+#ifdef WITH_XR_OPENXR
+/**
+ * Special handling for XR events.
+ *
+ * Although XR events are added to regular window queues, they are handled in an "off-screen area"
+ * context that is owned entirely by XR runtime data and not tied to a window.
+ */
+static void wm_event_handle_xrevent(bContext *C,
+ wmWindowManager *wm,
+ wmWindow *win,
+ wmEvent *event)
+{
+ ScrArea *area = WM_xr_session_area_get(&wm->xr);
+ if (!area) {
+ return;
+ }
+ BLI_assert(area->spacetype == SPACE_VIEW3D && area->spacedata.first);
+
+ /* Find a valid region for XR operator execution and modal handling. */
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ if (!region) {
+ return;
+ }
+ BLI_assert(WM_region_use_viewport(area, region)); /* For operators using GPU-based selection. */
+
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
+
+ int action = wm_handlers_do(C, event, &win->modalhandlers);
+
+ if ((action & WM_HANDLER_BREAK) == 0) {
+ wmXrActionData *actiondata = event->customdata;
+ if (actiondata->ot->modal && event->val == KM_RELEASE) {
+ /* Don't execute modal operators on release. */
+ }
+ else {
+ PointerRNA properties = {.type = actiondata->ot->srna, .data = actiondata->op_properties};
+ if (actiondata->ot->invoke) {
+ /* Invoke operator, either executing operator or transferring responsibility to window
+ * modal handlers. */
+ wm_operator_invoke(C,
+ actiondata->ot,
+ event,
+ actiondata->op_properties ? &properties : NULL,
+ NULL,
+ false,
+ false);
+ }
+ else {
+ /* Execute operator. */
+ wmOperator *op = wm_operator_create(
+ wm, actiondata->ot, actiondata->op_properties ? &properties : NULL, NULL);
+ if ((WM_operator_call(C, op) & OPERATOR_HANDLED) == 0) {
+ WM_operator_free(op);
+ }
+ }
+ }
+ }
+
+ CTX_wm_region_set(C, NULL);
+ CTX_wm_area_set(C, NULL);
+}
+#endif /* WITH_XR_OPENXR */
+
void wm_event_do_handlers(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -3530,18 +3595,29 @@ void wm_event_do_handlers(bContext *C)
CTX_wm_window_set(C, win);
+#ifdef WITH_XR_OPENXR
+ if (event->type == EVT_XR_ACTION) {
+ wm_event_handle_xrevent(C, wm, win, event);
+ BLI_remlink(&win->event_queue, event);
+ wm_event_free(event);
+ /* Skip mouse event handling below, which is unnecessary for XR events. */
+ continue;
+ }
+#endif
+
/* Clear tool-tip on mouse move. */
if (screen->tool_tip && screen->tool_tip->exit_on_event) {
if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
- if (len_manhattan_v2v2_int(screen->tool_tip->event_xy, &event->x) > U.move_threshold) {
+ if (len_manhattan_v2v2_int(screen->tool_tip->event_xy, event->xy) >
+ WM_EVENT_CURSOR_MOTION_THRESHOLD) {
WM_tooltip_clear(C, win);
}
}
}
/* We let modal handlers get active area/region, also wm_paintcursor_test needs it. */
- CTX_wm_area_set(C, area_event_inside(C, &event->x));
- CTX_wm_region_set(C, region_event_inside(C, &event->x));
+ CTX_wm_area_set(C, area_event_inside(C, event->xy));
+ CTX_wm_region_set(C, region_event_inside(C, event->xy));
/* MVC demands to not draw in event handlers...
* but we need to leave it for ogl selecting etc. */
@@ -3578,7 +3654,7 @@ void wm_event_do_handlers(bContext *C)
if (event->type == MOUSEMOVE) {
/* State variables in screen, cursors.
* Also used in wm_draw.c, fails for modal handlers though. */
- ED_screen_set_active_region(C, win, &event->x);
+ ED_screen_set_active_region(C, win, event->xy);
/* For regions having custom cursors. */
wm_paintcursor_test(C, event);
}
@@ -3600,7 +3676,7 @@ void wm_event_do_handlers(bContext *C)
/* Update azones if needed - done here because it needs to be independent from redraws.
*/
if (area->flag & AREA_FLAG_ACTIONZONES_UPDATE) {
- ED_area_azones_update(area, &event->x);
+ ED_area_azones_update(area, event->xy);
}
if (wm_event_inside_rect(event, &area->totrct)) {
@@ -3653,8 +3729,8 @@ void wm_event_do_handlers(bContext *C)
if ((action & WM_HANDLER_BREAK) == 0) {
/* Also some non-modal handlers need active area/region. */
- CTX_wm_area_set(C, area_event_inside(C, &event->x));
- CTX_wm_region_set(C, region_event_inside(C, &event->x));
+ CTX_wm_area_set(C, area_event_inside(C, event->xy));
+ CTX_wm_region_set(C, region_event_inside(C, event->xy));
wm_region_mouse_co(C, event);
@@ -3683,8 +3759,7 @@ void wm_event_do_handlers(bContext *C)
}
/* Update previous mouse position for following events to use. */
- win->eventstate->prevx = event->x;
- win->eventstate->prevy = event->y;
+ copy_v2_v2_int(win->eventstate->prev_xy, event->xy);
/* Unlink and free here, blender-quit then frees all. */
BLI_remlink(&win->event_queue, event);
@@ -3694,10 +3769,10 @@ void wm_event_do_handlers(bContext *C)
/* Only add mouse-move when the event queue was read entirely. */
if (win->addmousemove && win->eventstate) {
wmEvent tevent = *(win->eventstate);
- // printf("adding MOUSEMOVE %d %d\n", tevent.x, tevent.y);
+ // printf("adding MOUSEMOVE %d %d\n", tevent.xy[0], tevent.xy[1]);
tevent.type = MOUSEMOVE;
- tevent.prevx = tevent.x;
- tevent.prevy = tevent.y;
+ tevent.prev_xy[0] = tevent.xy[0];
+ tevent.prev_xy[1] = tevent.xy[1];
tevent.is_repeat = false;
wm_event_add(win, &tevent);
win->addmousemove = 0;
@@ -3732,14 +3807,8 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval
}
/* Operator is supposed to have a filled "path" property. */
-/* Optional property: filetype (XXX enum?) */
+/* Optional property: file-type (XXX enum?) */
-/**
- * The idea here is to keep a handler alive on window queue, owning the operator.
- * The file window can send event to make it execute, thus ensuring
- * executing happens outside of lower level queues, with UI refreshed.
- * Should also allow multiwin solutions.
- */
void WM_event_add_fileselect(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -3838,10 +3907,6 @@ wmEventHandler_Op *WM_event_add_modal_handler(bContext *C, wmOperator *op)
return handler;
}
-/**
- * Modal handlers store a pointer to an area which might be freed while the handler runs.
- * Use this function to NULL all handler pointers to \a old_area.
- */
void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area)
{
LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
@@ -3856,10 +3921,6 @@ void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area,
}
}
-/**
- * Modal handlers store a pointer to a region which might be freed while the handler runs.
- * Use this function to NULL all handler pointers to \a old_region.
- */
void WM_event_modal_handler_region_replace(wmWindow *win,
const ARegion *old_region,
ARegion *new_region)
@@ -3914,15 +3975,25 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap
*
* Follow #wmEventHandler_KeymapDynamicFn signature.
*/
-void WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm,
- wmEventHandler_Keymap *handler,
- wmEventHandler_KeymapResult *km_result)
+static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm,
+ wmWindow *win,
+ wmEventHandler_Keymap *handler,
+ wmEventHandler_KeymapResult *km_result,
+ /* Extra arguments. */
+ const bool with_gizmos)
{
memset(km_result, 0x0, sizeof(*km_result));
const char *keymap_id_list[ARRAY_SIZE(km_result->keymaps)];
int keymap_id_list_len = 0;
+ /* NOTE(@campbellbarton): If `win` is NULL, this function may not behave as expected.
+ * Assert since this should not happen in practice.
+ * If it does, the window could be looked up in `wm` using the `area`.
+ * Keep NULL checks in run-time code since any crashes here are difficult to redo. */
+ BLI_assert_msg(win != NULL, "The window should always be set for tool interactions!");
+ const Scene *scene = win ? win->scene : NULL;
+
ScrArea *area = handler->dynamic.user_data;
handler->keymap_tool = NULL;
bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : NULL;
@@ -3934,14 +4005,16 @@ void WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm,
bool is_gizmo_visible = false;
bool is_gizmo_highlight = false;
- if (tref_rt && tref_rt->keymap_fallback[0]) {
+ if ((tref_rt && tref_rt->keymap_fallback[0]) &&
+ (scene && (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK))) {
bool add_keymap = false;
/* Support for the gizmo owning the tool keymap. */
if (tref_rt->flag & TOOLREF_FLAG_FALLBACK_KEYMAP) {
add_keymap = true;
}
- if (tref_rt->gizmo_group[0] != '\0') {
+
+ if (with_gizmos && (tref_rt->gizmo_group[0] != '\0')) {
wmGizmoMap *gzmap = NULL;
wmGizmoGroup *gzgroup = NULL;
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
@@ -3956,17 +4029,16 @@ void WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm,
if (gzgroup != NULL) {
if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
/* If all are hidden, don't override. */
- if (gzgroup->use_fallback_keymap) {
- is_gizmo_visible = true;
- wmGizmo *highlight = wm_gizmomap_highlight_get(gzmap);
- if (highlight) {
- is_gizmo_highlight = true;
- }
- add_keymap = true;
+ is_gizmo_visible = true;
+ wmGizmo *highlight = wm_gizmomap_highlight_get(gzmap);
+ if (highlight) {
+ is_gizmo_highlight = true;
}
+ add_keymap = true;
}
}
}
+
if (add_keymap) {
keymap_id_list[keymap_id_list_len++] = tref_rt->keymap_fallback;
}
@@ -3994,31 +4066,20 @@ void WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm,
}
}
+void WM_event_get_keymap_from_toolsystem_with_gizmos(wmWindowManager *wm,
+ wmWindow *win,
+ wmEventHandler_Keymap *handler,
+ wmEventHandler_KeymapResult *km_result)
+{
+ wm_event_get_keymap_from_toolsystem_ex(wm, win, handler, km_result, true);
+}
+
void WM_event_get_keymap_from_toolsystem(wmWindowManager *wm,
+ wmWindow *win,
wmEventHandler_Keymap *handler,
wmEventHandler_KeymapResult *km_result)
{
- memset(km_result, 0x0, sizeof(*km_result));
-
- ScrArea *area = handler->dynamic.user_data;
- handler->keymap_tool = NULL;
- bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : NULL;
- if (tref_rt && tref_rt->keymap[0]) {
- const char *keymap_id = tref_rt->keymap;
- {
- wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty(
- &wm->userconf->keymaps, keymap_id, area->spacetype, RGN_TYPE_WINDOW);
- /* We shouldn't use keymaps from unrelated spaces. */
- if (km != NULL) {
- handler->keymap_tool = area->runtime.tool;
- km_result->keymaps[km_result->keymaps_len++] = km;
- }
- else {
- printf(
- "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, area->runtime.tool->idname);
- }
- }
- }
+ wm_event_get_keymap_from_toolsystem_ex(wm, win, handler, km_result, false);
}
struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
@@ -4050,7 +4111,6 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
return handler;
}
-/* Priorities not implemented yet, for time being just insert in begin of list. */
wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers,
wmKeyMap *keymap,
int UNUSED(priority))
@@ -4068,10 +4128,10 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers,
static bool event_or_prev_in_rect(const wmEvent *event, const rcti *rect)
{
- if (BLI_rcti_isect_pt(rect, event->x, event->y)) {
+ if (BLI_rcti_isect_pt_v(rect, event->xy)) {
return true;
}
- if (event->type == MOUSEMOVE && BLI_rcti_isect_pt(rect, event->prevx, event->prevy)) {
+ if (event->type == MOUSEMOVE && BLI_rcti_isect_pt_v(rect, event->prev_xy)) {
return true;
}
return false;
@@ -4157,7 +4217,6 @@ wmEventHandler_UI *WM_event_add_ui_handler(const bContext *C,
return handler;
}
-/* Set "postpone" for win->modalhandlers, this is in a running for () loop in wm_handlers_do(). */
void WM_event_remove_ui_handler(ListBase *handlers,
wmUIHandlerFunc handle_fn,
wmUIHandlerRemoveFunc remove_fn,
@@ -4222,9 +4281,10 @@ wmEventHandler_Dropbox *WM_event_add_dropbox_handler(ListBase *handlers, ListBas
return handler;
}
-/* XXX(ton): solution works, still better check the real cause. */
void WM_event_remove_area_handler(ListBase *handlers, void *area)
{
+ /* XXX(ton): solution works, still better check the real cause. */
+
LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, handlers) {
if (handler_base->type == WM_HANDLER_TYPE_UI) {
wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
@@ -4540,14 +4600,14 @@ static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *g
event->custom = EVT_DATA_NDOF_MOTION;
event->customdata = data;
- event->customdatafree = 1;
+ event->customdata_free = true;
}
#endif /* WITH_INPUT_NDOF */
/* Imperfect but probably usable... draw/enable drags to other windows. */
static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *event)
{
- int mval[2] = {event->x, event->y};
+ int mval[2] = {event->xy[0], event->xy[1]};
if (wm->windows.first == wm->windows.last) {
return NULL;
@@ -4569,8 +4629,7 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi
wmWindow *win_other = WM_window_find_under_cursor(wm, win, win, mval, mval);
if (win_other) {
- event->x = mval[0];
- event->y = mval[1];
+ copy_v2_v2_int(event->xy, mval);
return win_other;
}
}
@@ -4579,13 +4638,13 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi
static bool wm_event_is_double_click(const wmEvent *event)
{
- if ((event->type == event->prevtype) && (event->prevval == KM_RELEASE) &&
+ if ((event->type == event->prev_type) && (event->prev_val == KM_RELEASE) &&
(event->val == KM_PRESS)) {
- if (ISMOUSE(event->type) && WM_event_drag_test(event, &event->prevclickx)) {
+ if (ISMOUSE(event->type) && WM_event_drag_test(event, event->prev_click_xy)) {
/* Pass. */
}
else {
- if ((PIL_check_seconds_timer() - event->prevclicktime) * 1000 < U.dbl_click_time) {
+ if ((PIL_check_seconds_timer() - event->prev_click_time) * 1000 < U.dbl_click_time) {
return true;
}
}
@@ -4599,15 +4658,15 @@ static bool wm_event_is_double_click(const wmEvent *event)
*/
static void wm_event_prev_values_set(wmEvent *event, wmEvent *event_state)
{
- event->prevval = event_state->prevval = event_state->val;
- event->prevtype = event_state->prevtype = event_state->type;
+ event->prev_val = event_state->prev_val = event_state->val;
+ event->prev_type = event_state->prev_type = event_state->type;
}
static void wm_event_prev_click_set(wmEvent *event, wmEvent *event_state)
{
- event->prevclicktime = event_state->prevclicktime = PIL_check_seconds_timer();
- event->prevclickx = event_state->prevclickx = event_state->x;
- event->prevclicky = event_state->prevclicky = event_state->y;
+ event->prev_click_time = event_state->prev_click_time = PIL_check_seconds_timer();
+ event->prev_click_xy[0] = event_state->prev_click_xy[0] = event_state->xy[0];
+ event->prev_click_xy[1] = event_state->prev_click_xy[1] = event_state->xy[1];
}
static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event)
@@ -4619,6 +4678,7 @@ static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event)
* them for better performance. */
if (event_last && event_last->type == MOUSEMOVE) {
event_last->type = INBETWEEN_MOUSEMOVE;
+ event_last->is_repeat = false;
}
wmEvent *event_new = wm_event_add(win, event);
@@ -4626,7 +4686,7 @@ static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event)
event_last = win->eventstate;
}
- copy_v2_v2_int(&event_new->prevx, &event_last->x);
+ copy_v2_v2_int(event_new->prev_xy, event_last->xy);
return event_new;
}
@@ -4636,23 +4696,20 @@ static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int d
* for painting with mouse moves, for navigation using the accumulated value is ok. */
wmEvent *event_last = win->event_queue.last;
if (event_last && event_last->type == event->type) {
- deltax += event_last->x - event_last->prevx;
- deltay += event_last->y - event_last->prevy;
+ deltax += event_last->xy[0] - event_last->prev_xy[0];
+ deltay += event_last->xy[1] - event_last->prev_xy[1];
wm_event_free_last(win);
}
- /* Set prevx/prevy, the delta is computed from this in operators. */
+ /* Set prev_xy, the delta is computed from this in operators. */
wmEvent *event_new = wm_event_add(win, event);
- event_new->prevx = event_new->x - deltax;
- event_new->prevy = event_new->y - deltay;
+ event_new->prev_xy[0] = event_new->xy[0] - deltax;
+ event_new->prev_xy[1] = event_new->xy[1] - deltay;
return event_new;
}
-/**
- * Windows store own event queues #wmWindow.event_queue (no #bContext here).
- */
void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata)
{
if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
@@ -4685,8 +4742,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
* If this was done it could leave `win->eventstate` previous and current value
* set to the same key press/release state which doesn't make sense.
*/
- event.prevtype = event.type;
- event.prevval = event.val;
+ event.prev_type = event.type;
+ event.prev_val = event.val;
/* Ensure the event state is correct, any deviation from this may cause bugs.
*
@@ -4700,12 +4757,12 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
"Non-keyboard/mouse button found in 'win->eventstate->type = %d'",
event_state->type);
}
- if ((event_state->prevtype || event_state->prevval) && /* Ignore cleared event state. */
- !(ISMOUSE_BUTTON(event_state->prevtype) || ISKEYBOARD(event_state->prevtype) ||
+ if ((event_state->prev_type || event_state->prev_val) && /* Ignore cleared event state. */
+ !(ISMOUSE_BUTTON(event_state->prev_type) || ISKEYBOARD(event_state->prev_type) ||
(event_state->type == EVENT_NONE))) {
CLOG_WARN(WM_LOG_HANDLERS,
- "Non-keyboard/mouse button found in 'win->eventstate->prevtype = %d'",
- event_state->prevtype);
+ "Non-keyboard/mouse button found in 'win->eventstate->prev_type = %d'",
+ event_state->prev_type);
}
#endif
@@ -4714,14 +4771,14 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
case GHOST_kEventCursorMove: {
GHOST_TEventCursorData *cd = customdata;
- copy_v2_v2_int(&event.x, &cd->x);
- wm_stereo3d_mouse_offset_apply(win, &event.x);
+ copy_v2_v2_int(event.xy, &cd->x);
+ wm_stereo3d_mouse_offset_apply(win, event.xy);
wm_tablet_data_from_ghost(&cd->tablet, &event.tablet);
event.type = MOUSEMOVE;
{
wmEvent *event_new = wm_event_add_mousemove(win, &event);
- copy_v2_v2_int(&event_state->x, &event_new->x);
+ copy_v2_v2_int(event_state->xy, event_new->xy);
event_state->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute;
}
@@ -4732,14 +4789,14 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
wmEvent event_other = *win_other->eventstate;
/* See comment for this operation on `event` for details. */
- event_other.prevtype = event_other.type;
- event_other.prevval = event_other.val;
+ event_other.prev_type = event_other.type;
+ event_other.prev_val = event_other.val;
- copy_v2_v2_int(&event_other.x, &event.x);
+ copy_v2_v2_int(event_other.xy, event.xy);
event_other.type = MOUSEMOVE;
{
wmEvent *event_new = wm_event_add_mousemove(win_other, &event_other);
- copy_v2_v2_int(&win_other->eventstate->x, &event_new->x);
+ copy_v2_v2_int(win_other->eventstate->xy, event_new->xy);
win_other->eventstate->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute;
}
}
@@ -4766,8 +4823,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
break;
}
- event.x = event_state->x = pd->x;
- event.y = event_state->y = pd->y;
+ event.xy[0] = event_state->xy[0] = pd->x;
+ event.xy[1] = event_state->xy[1] = pd->y;
event.val = KM_NOTHING;
/* The direction is inverted from the device due to system preferences. */
@@ -4831,10 +4888,10 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
wmEvent event_other = *win_other->eventstate;
/* See comment for this operation on `event` for details. */
- event_other.prevtype = event_other.type;
- event_other.prevval = event_other.val;
+ event_other.prev_type = event_other.type;
+ event_other.prev_val = event_other.val;
- copy_v2_v2_int(&event_other.x, &event.x);
+ copy_v2_v2_int(event_other.xy, event.xy);
event_other.type = event.type;
event_other.val = event.val;
@@ -5012,7 +5069,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
attach_ndof_data(&event, customdata);
wm_event_add(win, &event);
- CLOG_INFO(WM_LOG_HANDLERS, 1, "sending NDOF_MOTION, prev = %d %d", event.x, event.y);
+ CLOG_INFO(WM_LOG_HANDLERS, 1, "sending NDOF_MOTION, prev = %d %d", event.xy[0], event.xy[1]);
break;
}
@@ -5082,6 +5139,24 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
#endif
}
+#ifdef WITH_XR_OPENXR
+void wm_event_add_xrevent(wmWindow *win, wmXrActionData *actiondata, short val)
+{
+ BLI_assert(val == KM_PRESS || val == KM_RELEASE);
+
+ wmEvent event = {
+ .type = EVT_XR_ACTION,
+ .val = val,
+ .is_repeat = false,
+ .custom = EVT_DATA_XR,
+ .customdata = actiondata,
+ .customdata_free = true,
+ };
+
+ wm_event_add(win, &event);
+}
+#endif /* WITH_XR_OPENXR */
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -5133,11 +5208,12 @@ void WM_set_locked_interface(wmWindowManager *wm, bool lock)
* \{ */
void WM_event_get_keymaps_from_handler(wmWindowManager *wm,
+ wmWindow *win,
wmEventHandler_Keymap *handler,
wmEventHandler_KeymapResult *km_result)
{
if (handler->dynamic.keymap_fn != NULL) {
- handler->dynamic.keymap_fn(wm, handler, km_result);
+ handler->dynamic.keymap_fn(wm, win, handler, km_result);
BLI_assert(handler->keymap == NULL);
}
else {
@@ -5163,10 +5239,8 @@ wmKeyMapItem *WM_event_match_keymap_item(bContext *C, wmKeyMap *keymap, const wm
return NULL;
}
-wmKeyMapItem *WM_event_match_keymap_item_from_handlers(bContext *C,
- wmWindowManager *wm,
- ListBase *handlers,
- const wmEvent *event)
+wmKeyMapItem *WM_event_match_keymap_item_from_handlers(
+ bContext *C, wmWindowManager *wm, wmWindow *win, ListBase *handlers, const wmEvent *event)
{
LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
/* During this loop, UI handlers for nested menus can tag multiple handlers free. */
@@ -5177,7 +5251,7 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers(bContext *C,
if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
wmEventHandler_KeymapResult km_result;
- WM_event_get_keymaps_from_handler(wm, handler, &km_result);
+ WM_event_get_keymaps_from_handler(wm, win, handler, &km_result);
for (int km_index = 0; km_index < km_result.keymaps_len; km_index++) {
wmKeyMap *keymap = km_result.keymaps[km_index];
if (WM_keymap_poll(C, keymap)) {
@@ -5253,10 +5327,6 @@ const char *WM_window_cursor_keymap_status_get(const wmWindow *win,
return NULL;
}
-/**
- * Similar to #BKE_screen_area_map_find_area_xy and related functions,
- * use here since the area is stored in the window manager.
- */
ScrArea *WM_window_status_area_find(wmWindow *win, bScreen *screen)
{
if (screen->state == SCREENFULL) {
@@ -5407,7 +5477,8 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
wm_eventemulation(&test_event, true);
wmKeyMapItem *kmi = NULL;
for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
- kmi = WM_event_match_keymap_item_from_handlers(C, wm, handlers[handler_index], &test_event);
+ kmi = WM_event_match_keymap_item_from_handlers(
+ C, wm, win, handlers[handler_index], &test_event);
if (kmi) {
break;
}
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index a5ebf988edd..1478712c3cd 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -75,6 +75,7 @@
#include "BKE_addon.h"
#include "BKE_appdir.h"
+#include "BKE_asset_library.h"
#include "BKE_autoexec.h"
#include "BKE_blender.h"
#include "BKE_blendfile.h"
@@ -105,10 +106,12 @@
#include "IMB_imbuf_types.h"
#include "IMB_thumbs.h"
+#include "ED_asset.h"
#include "ED_datafiles.h"
#include "ED_fileselect.h"
#include "ED_image.h"
#include "ED_outliner.h"
+#include "ED_render.h"
#include "ED_screen.h"
#include "ED_undo.h"
#include "ED_util.h"
@@ -168,9 +171,10 @@ void WM_file_tag_modified(void)
}
}
-bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm)
+bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWindowManager *wm)
{
- return !wm->file_saved || ED_image_should_save_modified(bmain);
+ return !wm->file_saved || ED_image_should_save_modified(bmain) ||
+ BKE_asset_library_has_any_unsaved_catalogs();
}
/** \} */
@@ -189,7 +193,6 @@ bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm)
static void wm_window_match_init(bContext *C, ListBase *wmlist)
{
*wmlist = G_MAIN->wm;
- BLI_listbase_clear(&G_MAIN->wm);
wmWindow *active_win = CTX_wm_window(C);
@@ -204,8 +207,20 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
WM_event_remove_handlers(C, &win->modalhandlers);
ED_screen_exit(C, win, WM_window_get_active_screen(win));
}
+
+ /* NOTE(@campbellbarton): Clear the message bus so it's always cleared on file load.
+ * Otherwise it's cleared when "Load UI" is set (see #USER_FILENOUI & #wm_close_and_free).
+ * However it's _not_ cleared when the UI is kept. This complicates use from add-ons
+ * which can re-register subscribers on file-load. To support this use case,
+ * it's best to have predictable behavior - always clear. */
+ if (wm->message_bus != NULL) {
+ WM_msgbus_destroy(wm->message_bus);
+ wm->message_bus = NULL;
+ }
}
+ BLI_listbase_clear(&G_MAIN->wm);
+
/* reset active window */
CTX_wm_window_set(C, active_win);
@@ -249,7 +264,7 @@ static void wm_window_substitute_old(wmWindowManager *oldwm,
win->eventstate = oldwin->eventstate;
oldwin->eventstate = NULL;
- /* ensure proper screen rescaling */
+ /* Ensure proper screen re-scaling. */
win->sizex = oldwin->sizex;
win->sizey = oldwin->sizey;
win->posx = oldwin->posx;
@@ -516,7 +531,7 @@ static int wm_read_exotic(const char *name)
/* check for compressed .blend */
FileReader *compressed_file = NULL;
if (BLI_file_magic_is_gzip(header)) {
- /* In earlier versions of Blender (before 3.0), compressed files used Gzip instead of Zstd.
+ /* In earlier versions of Blender (before 3.0), compressed files used `Gzip` instead of `Zstd`.
* While these files will no longer be written, there still needs to be reading support. */
compressed_file = BLI_filereader_new_gzip(rawfile);
}
@@ -604,6 +619,8 @@ static void wm_file_read_pre(bContext *C, bool use_data, bool UNUSED(use_userdef
/* Always do this as both startup and preferences may have loaded in many font's
* at a different zoom level to the file being loaded. */
UI_view2d_zoom_cache_reset();
+
+ ED_preview_restart_queue_free();
}
/**
@@ -871,11 +888,11 @@ static void file_read_reports_finalize(BlendFileReadReport *bf_reports)
bf_reports->count.linked_proxies);
}
- if (bf_reports->count.vse_strips_skipped != 0) {
+ if (bf_reports->count.sequence_strips_skipped != 0) {
BKE_reportf(bf_reports->reports,
RPT_ERROR,
"%d sequence strips were not read because they were in a channel larger than %d",
- bf_reports->count.vse_strips_skipped,
+ bf_reports->count.sequence_strips_skipped,
MAXSEQ);
}
@@ -939,16 +956,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/* #BKE_blendfile_read_result_setup sets new Main into context. */
Main *bmain = CTX_data_main(C);
- /* When recovering a session from an unsaved file, this can have a blank path. */
- if (BKE_main_blendfile_path(bmain)[0] != '\0') {
- G.save_over = 1;
- G.relbase_valid = 1;
- }
- else {
- G.save_over = 0;
- G.relbase_valid = 0;
- }
-
/* match the read WM with current WM */
wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
WM_check(C); /* opens window(s), checks keymaps */
@@ -1016,12 +1023,6 @@ static struct {
bool override;
} wm_init_state_app_template = {{0}};
-/**
- * Used for setting app-template from the command line:
- * - non-empty string: overrides.
- * - empty string: override, using no app template.
- * - NULL: clears override.
- */
void WM_init_state_app_template_set(const char *app_template)
{
if (app_template) {
@@ -1045,16 +1046,6 @@ const char *WM_init_state_app_template_get(void)
/** \name Read Startup & Preferences Blend-File API
* \{ */
-/**
- * Called on startup, (context entirely filled with NULLs)
- * or called for 'New File' both `startup.blend` and `userpref.blend` are checked.
- *
- * \param r_params_file_read_post: Support postponed initialization,
- * needed for initial startup when only some sub-systems have been initialized.
- * When non-null, #wm_file_read_post doesn't run, instead it's arguments are stored
- * in this return argument.
- * The caller is responsible for calling #wm_homefile_read_post with this return argument.
- */
void wm_homefile_read_ex(bContext *C,
const struct wmHomeFileRead_Params *params_homefile,
ReportList *reports,
@@ -1151,8 +1142,6 @@ void wm_homefile_read_ex(bContext *C,
wm_file_read_pre(C, use_data, use_userdef);
if (use_data) {
- G.relbase_valid = 0;
-
/* put aside screens to match with persistent windows later */
wm_window_match_init(C, &wmbase);
}
@@ -1356,10 +1345,7 @@ void wm_homefile_read_ex(bContext *C,
if (use_data) {
WM_check(C); /* opens window(s), checks keymaps */
- bmain->name[0] = '\0';
-
- /* start with save preference untitled.blend */
- G.save_over = 0;
+ bmain->filepath[0] = '\0';
}
{
@@ -1390,10 +1376,6 @@ void wm_homefile_read(bContext *C,
wm_homefile_read_ex(C, params_homefile, reports, NULL);
}
-/**
- * Special case, support deferred execution of #wm_file_read_post,
- * Needed when loading for the first time to workaround order of initialization bug, see T89046.
- */
void wm_homefile_read_post(struct bContext *C,
const struct wmFileReadPost_Params *params_file_read_post)
{
@@ -1401,6 +1383,8 @@ void wm_homefile_read_post(struct bContext *C,
MEM_freeN((void *)params_file_read_post);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Blend-File History API
* \{ */
@@ -1498,18 +1482,18 @@ static void wm_history_file_write(void)
static void wm_history_file_update(void)
{
RecentFile *recent;
- const char *blendfile_name = BKE_main_blendfile_path_from_global();
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
- /* no write history for recovered startup files */
- if (blendfile_name[0] == '\0') {
+ /* No write history for recovered startup files. */
+ if (blendfile_path[0] == '\0') {
return;
}
recent = G.recent_files.first;
/* refresh recent-files.txt of recent opened files, when current file was changed */
- if (!(recent) || (BLI_path_cmp(recent->filepath, blendfile_name) != 0)) {
+ if (!(recent) || (BLI_path_cmp(recent->filepath, blendfile_path) != 0)) {
- recent = wm_file_history_find(blendfile_name);
+ recent = wm_file_history_find(blendfile_path);
if (recent) {
BLI_remlink(&G.recent_files, recent);
}
@@ -1520,7 +1504,7 @@ static void wm_history_file_update(void)
recent_next = recent->next;
wm_history_file_free(recent);
}
- recent = wm_history_file_new(blendfile_name);
+ recent = wm_history_file_new(blendfile_path);
}
/* add current file to the beginning of list */
@@ -1530,27 +1514,46 @@ static void wm_history_file_update(void)
wm_history_file_write();
/* also update most recent files on System */
- GHOST_addToSystemRecentFiles(blendfile_name);
+ GHOST_addToSystemRecentFiles(blendfile_path);
}
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Save Main Blend-File (internal) Screen-Shot
+/** \name Thumbnail Generation: Screen-Shot / Camera View
+ *
+ * Thumbnail Sizes
+ * ===============
+ *
+ * - `PREVIEW_RENDER_LARGE_HEIGHT * 2` is used to render a large thumbnail,
+ * giving some over-sampling when scaled down:
+ *
+ * - There are two outputs for this thumbnail:
+ *
+ * - An image is saved to the thumbnail cache, sized at #PREVIEW_RENDER_LARGE_HEIGHT.
+ *
+ * - A smaller thumbnail is stored in the `.blend` file it's self, sized at #BLEN_THUMB_SIZE.
+ * The size is kept small to prevent thumbnails bloating the size of `.blend` files.
+ *
+ * The this thumbnail will be extracted if the file is shared or the local thumbnail cache
+ * is cleared. see: `blendthumb_extract.cc` for logic that extracts the thumbnail.
*
- * Screen-shot the active window.
* \{ */
-static ImBuf *blend_file_thumb_from_screenshot(bContext *C, BlendThumbnail **thumb_pt)
+/**
+ * Screen-shot the active window.
+ */
+static ImBuf *blend_file_thumb_from_screenshot(bContext *C, BlendThumbnail **r_thumb)
{
- if (*thumb_pt) {
- /* We are given a valid thumbnail data, so just generate image from it. */
- return BKE_main_thumbnail_to_imbuf(NULL, *thumb_pt);
+ *r_thumb = NULL;
+
+ wmWindow *win = CTX_wm_window(C);
+ if (G.background || (win == NULL)) {
+ return NULL;
}
/* The window to capture should be a main window (without parent). */
- wmWindow *win = CTX_wm_window(C);
while (win && win->parent) {
win = win->parent;
}
@@ -1579,27 +1582,30 @@ static ImBuf *blend_file_thumb_from_screenshot(bContext *C, BlendThumbnail **thu
BlendThumbnail *thumb = BKE_main_thumbnail_from_imbuf(NULL, thumb_ibuf);
IMB_freeImBuf(thumb_ibuf);
- *thumb_pt = thumb;
+ *r_thumb = thumb;
}
/* Must be freed by caller. */
return ibuf;
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Save Main Blend-File (internal) Camera View
- *
+/**
* Render the current scene with the active camera.
- * \{ */
-
-/* screen can be NULL */
+ *
+ * \param screen: can be NULL.
+ */
static ImBuf *blend_file_thumb_from_camera(const bContext *C,
Scene *scene,
bScreen *screen,
- BlendThumbnail **thumb_pt)
+ BlendThumbnail **r_thumb)
{
+ *r_thumb = NULL;
+
+ /* Scene can be NULL if running a script at startup and calling the save operator. */
+ if (G.background || scene == NULL) {
+ return NULL;
+ }
+
/* will be scaled down, but gives some nice oversampling */
ImBuf *ibuf;
BlendThumbnail *thumb;
@@ -1613,21 +1619,11 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C,
ARegion *region = NULL;
View3D *v3d = NULL;
- /* In case we are given a valid thumbnail data, just generate image from it. */
- if (*thumb_pt) {
- thumb = *thumb_pt;
- return BKE_main_thumbnail_to_imbuf(NULL, thumb);
- }
-
- /* scene can be NULL if running a script at startup and calling the save operator */
- if (G.background || scene == NULL) {
- return NULL;
- }
-
if (screen != NULL) {
area = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0);
if (area) {
v3d = area->spacedata.first;
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
}
}
@@ -1635,7 +1631,6 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C,
return NULL;
}
- /* gets scaled to BLEN_THUMB_SIZE */
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
/* Note that with scaling, this ends up being 0.5,
@@ -1696,18 +1691,23 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C,
IMB_scaleImBuf(ibuf, PREVIEW_RENDER_LARGE_HEIGHT, PREVIEW_RENDER_LARGE_HEIGHT);
}
else {
- /* '*thumb_pt' needs to stay NULL to prevent a bad thumbnail from being handled */
+ /* '*r_thumb' needs to stay NULL to prevent a bad thumbnail from being handled. */
CLOG_WARN(&LOG, "failed to create thumbnail: %s", err_out);
thumb = NULL;
}
/* must be freed by caller */
- *thumb_pt = thumb;
+ *r_thumb = thumb;
return ibuf;
}
-/* easy access from gdb */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Write Main Blend-File (internal)
+ * \{ */
+
bool write_crash_blend(void)
{
char path[FILE_MAX];
@@ -1735,7 +1735,7 @@ static bool wm_file_write(bContext *C,
Main *bmain = CTX_data_main(C);
int len;
int ok = false;
- BlendThumbnail *thumb, *main_thumb;
+ BlendThumbnail *thumb = NULL, *main_thumb = NULL;
ImBuf *ibuf_thumb = NULL;
len = strlen(filepath);
@@ -1771,45 +1771,57 @@ static bool wm_file_write(bContext *C,
/* Call pre-save callbacks before writing preview,
* that way you can generate custom file thumbnail. */
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE);
+ ED_assets_pre_save(bmain);
/* Enforce full override check/generation on file save. */
BKE_lib_override_library_main_operations_create(bmain, true);
- if (!G.background) {
- /* Redraw to remove menus that might be open. */
+ if (!G.background && BLI_thread_is_main()) {
+ /* Redraw to remove menus that might be open.
+ * But only in the main thread otherwise this can crash, see T92704. */
WM_redraw_windows(C);
}
/* don't forget not to return without! */
WM_cursor_wait(true);
- /* blend file thumbnail */
- /* Save before exit_editmode, otherwise derivedmeshes for shared data corrupt T27765. */
- /* Main now can store a '.blend' thumbnail, useful for background mode
- * or thumbnail customization. */
- main_thumb = thumb = bmain->blen_thumb;
- if (BLI_thread_is_main() && U.file_preview_type != USER_FILE_PREVIEW_NONE) {
-
- int file_preview_type = U.file_preview_type;
-
- if (file_preview_type == USER_FILE_PREVIEW_AUTO) {
- Scene *scene = CTX_data_scene(C);
- bool do_render = (scene != NULL && scene->camera != NULL &&
- (BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0) != NULL));
- file_preview_type = do_render ? USER_FILE_PREVIEW_CAMERA : USER_FILE_PREVIEW_SCREENSHOT;
- }
-
- switch (file_preview_type) {
- case USER_FILE_PREVIEW_SCREENSHOT: {
- ibuf_thumb = blend_file_thumb_from_screenshot(C, &thumb);
- break;
+ if (U.file_preview_type != USER_FILE_PREVIEW_NONE) {
+ /* Blend file thumbnail.
+ *
+ * - Save before exiting edit-mode, otherwise evaluated-mesh for shared data gets corrupted.
+ * See T27765.
+ * - Main can store a '.blend' thumbnail,
+ * useful for background-mode or thumbnail customization.
+ */
+ main_thumb = thumb = bmain->blen_thumb;
+ if (thumb != NULL) {
+ /* In case we are given a valid thumbnail data, just generate image from it. */
+ ibuf_thumb = BKE_main_thumbnail_to_imbuf(NULL, thumb);
+ }
+ else if (BLI_thread_is_main()) {
+ int file_preview_type = U.file_preview_type;
+
+ if (file_preview_type == USER_FILE_PREVIEW_AUTO) {
+ Scene *scene = CTX_data_scene(C);
+ bScreen *screen = CTX_wm_screen(C);
+ bool do_render = (scene != NULL && scene->camera != NULL && screen != NULL &&
+ (BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0) != NULL));
+ file_preview_type = do_render ? USER_FILE_PREVIEW_CAMERA : USER_FILE_PREVIEW_SCREENSHOT;
}
- case USER_FILE_PREVIEW_CAMERA: {
- ibuf_thumb = blend_file_thumb_from_camera(C, CTX_data_scene(C), CTX_wm_screen(C), &thumb);
- break;
+
+ switch (file_preview_type) {
+ case USER_FILE_PREVIEW_SCREENSHOT: {
+ ibuf_thumb = blend_file_thumb_from_screenshot(C, &thumb);
+ break;
+ }
+ case USER_FILE_PREVIEW_CAMERA: {
+ ibuf_thumb = blend_file_thumb_from_camera(
+ C, CTX_data_scene(C), CTX_wm_screen(C), &thumb);
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
}
- default:
- BLI_assert_unreachable();
}
}
@@ -1821,16 +1833,10 @@ static bool wm_file_write(bContext *C,
ED_editors_flush_edits(bmain);
- /* First time saving. */
- /* XXX(ton): temp solution to solve bug, real fix coming. */
- if ((BKE_main_blendfile_path(bmain)[0] == '\0') && (use_save_as_copy == false)) {
- BLI_strncpy(bmain->name, filepath, sizeof(bmain->name));
- }
-
/* XXX(ton): temp solution to solve bug, real fix coming. */
bmain->recovered = 0;
- if (BLO_write_file(CTX_data_main(C),
+ if (BLO_write_file(bmain,
filepath,
fileflags,
&(const struct BlendFileWriteParams){
@@ -1844,10 +1850,7 @@ static bool wm_file_write(bContext *C,
(CTX_wm_manager(C)->op_undo_depth == 0);
if (use_save_as_copy == false) {
- G.relbase_valid = 1;
- BLI_strncpy(bmain->name, filepath, sizeof(bmain->name)); /* is guaranteed current file */
-
- G.save_over = 1; /* disable untitled.blend convention */
+ STRNCPY(bmain->filepath, filepath); /* is guaranteed current file */
}
SET_FLAG_FROM_TEST(G.fileflags, fileflags & G_FILE_COMPRESS, G_FILE_COMPRESS);
@@ -1898,8 +1901,13 @@ static void wm_autosave_location(char *filepath)
const char *savedir;
#endif
- if (G_MAIN && G.relbase_valid) {
- const char *basename = BLI_path_basename(BKE_main_blendfile_path_from_global());
+ /* Normally there is no need to check for this to be NULL,
+ * however this runs on exit when it may be cleared. */
+ Main *bmain = G_MAIN;
+ const char *blendfile_path = bmain ? BKE_main_blendfile_path(bmain) : NULL;
+
+ if (blendfile_path && (blendfile_path[0] != '\0')) {
+ const char *basename = BLI_path_basename(blendfile_path);
int len = strlen(basename) - 6;
BLI_snprintf(path, sizeof(path), "%.*s_%d_autosave.blend", len, basename, pid);
}
@@ -1981,9 +1989,6 @@ void WM_autosave_init(wmWindowManager *wm)
wm_autosave_timer_begin(wm);
}
-/**
- * Run the auto-save timer action.
- */
void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt))
{
wm_autosave_timer_end(wm);
@@ -2031,7 +2036,7 @@ void wm_autosave_delete(void)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Initialize WM_OT_open_xxx properties
+/** \name Initialize `WM_OT_open_*` Properties
*
* Check if load_ui was set by the caller.
* Fall back to user preference when file flags not specified.
@@ -2088,6 +2093,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
}
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE);
+ ED_assets_pre_save(bmain);
/* check current window and close it if temp */
if (win && WM_window_is_temp_screen(win)) {
@@ -2111,7 +2117,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
fileflags,
&(const struct BlendFileWriteParams){
/* Make all paths absolute when saving the startup file.
- * On load the `G.relbase_valid` will be false so the paths
+ * On load the `G.main->filepath` will be empty so the paths
* won't have a base for resolving the relative paths. */
.remap_mode = BLO_WRITE_PATH_REMAP_ABSOLUTE,
/* Don't apply any path changes to the current blend file. */
@@ -2123,8 +2129,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
}
printf("ok\n");
-
- G.save_over = 0;
+ BKE_report(op->reports, RPT_INFO, "Startup file saved");
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_POST);
@@ -2611,7 +2616,7 @@ static int wm_open_mainfile__select_file_path(bContext *C, wmOperator *op)
set_next_operator_state(op, OPEN_MAINFILE_STATE_OPEN);
Main *bmain = CTX_data_main(C);
- const char *openname = BKE_main_blendfile_path(bmain);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
if (CTX_wm_window(C) == NULL) {
/* in rare cases this could happen, when trying to invoke in background
@@ -2624,10 +2629,10 @@ static int wm_open_mainfile__select_file_path(bContext *C, wmOperator *op)
/* if possible, get the name of the most recently used .blend file */
if (G.recent_files.first) {
struct RecentFile *recent = G.recent_files.first;
- openname = recent->filepath;
+ blendfile_path = recent->filepath;
}
- RNA_string_set(op->ptr, "filepath", openname);
+ RNA_string_set(op->ptr, "filepath", blendfile_path);
wm_open_init_load_ui(op, true);
wm_open_init_use_scripts(op, true);
op->customdata = NULL;
@@ -2850,7 +2855,8 @@ static int wm_revert_mainfile_exec(bContext *C, wmOperator *op)
static bool wm_revert_mainfile_poll(bContext *UNUSED(C))
{
- return G.relbase_valid;
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ return (blendfile_path[0] != '\0');
}
void WM_OT_revert_mainfile(wmOperatorType *ot)
@@ -3007,9 +3013,9 @@ void WM_OT_recover_auto_save(wmOperatorType *ot)
* Both #WM_OT_save_as_mainfile & #WM_OT_save_mainfile.
* \{ */
-static void wm_filepath_default(char *filepath)
+static void wm_filepath_default(const Main *bmain, char *filepath)
{
- if (G.save_over == false) {
+ if (bmain->filepath[0] == '\0') {
BLI_path_filename_ensure(filepath, FILE_MAX, "untitled.blend");
}
}
@@ -3020,7 +3026,8 @@ static void save_set_compress(wmOperator *op)
prop = RNA_struct_find_property(op->ptr, "compress");
if (!RNA_property_is_set(op->ptr, prop)) {
- if (G.save_over) { /* keep flag for existing file */
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] != '\0') { /* Keep flag for existing file. */
RNA_property_boolean_set(op->ptr, prop, (G.fileflags & G_FILE_COMPRESS) != 0);
}
else { /* use userdef for new file */
@@ -3033,21 +3040,22 @@ static void save_set_filepath(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
PropertyRNA *prop;
- char name[FILE_MAX];
+ char filepath[FILE_MAX];
prop = RNA_struct_find_property(op->ptr, "filepath");
if (!RNA_property_is_set(op->ptr, prop)) {
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
/* if not saved before, get the name of the most recently used .blend file */
- if (BKE_main_blendfile_path(bmain)[0] == '\0' && G.recent_files.first) {
+ if ((blendfile_path[0] == '\0') && G.recent_files.first) {
struct RecentFile *recent = G.recent_files.first;
- BLI_strncpy(name, recent->filepath, FILE_MAX);
+ STRNCPY(filepath, recent->filepath);
}
else {
- BLI_strncpy(name, bmain->name, FILE_MAX);
+ STRNCPY(filepath, blendfile_path);
}
- wm_filepath_default(name);
- RNA_property_string_set(op->ptr, prop, name);
+ wm_filepath_default(bmain, filepath);
+ RNA_property_string_set(op->ptr, prop, filepath);
}
}
@@ -3079,12 +3087,32 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
BLO_WRITE_PATH_REMAP_NONE;
save_set_compress(op);
- if (RNA_struct_property_is_set(op->ptr, "filepath")) {
+ const bool is_filepath_set = RNA_struct_property_is_set(op->ptr, "filepath");
+ if (is_filepath_set) {
RNA_string_get(op->ptr, "filepath", path);
}
else {
- BLI_strncpy(path, BKE_main_blendfile_path(bmain), FILE_MAX);
- wm_filepath_default(path);
+ STRNCPY(path, BKE_main_blendfile_path(bmain));
+ }
+
+ if (path[0] == '\0') {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Unable to save an unsaved file with an empty or unset \"filepath\" property");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* NOTE(@campbellbarton): only check this for file-path properties so saving an already
+ * saved file never fails with an error.
+ * Even though this should never happen, there may be some corner case where a malformed
+ * path is stored in `G.main->filepath`: when the file path is initialized from recovering
+ * a blend file - for example, so in this case failing to save isn't ideal. */
+ if (is_filepath_set && !BLI_path_is_abs_from_cwd(path)) {
+ BKE_reportf(op->reports,
+ RPT_ERROR,
+ "The \"filepath\" property was not an absolute path: \"%s\"",
+ path);
+ return OPERATOR_CANCELLED;
}
const int fileflags_orig = G.fileflags;
@@ -3201,14 +3229,15 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U
/* if we're saving for the first time and prefer relative paths -
* any existing paths will be absolute,
* enable the option to remap paths to avoid confusion T37240. */
- if ((G.relbase_valid == false) && (U.flag & USER_RELPATHS)) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if ((blendfile_path[0] == '\0') && (U.flag & USER_RELPATHS)) {
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "relative_remap");
if (!RNA_property_is_set(op->ptr, prop)) {
RNA_property_boolean_set(op->ptr, prop, true);
}
}
- if (G.save_over) {
+ if (blendfile_path[0] != '\0') {
char path[FILE_MAX];
RNA_string_get(op->ptr, "filepath", path);
@@ -3310,6 +3339,7 @@ static uiBlock *block_create_autorun_warning(struct bContext *C,
struct ARegion *region,
void *UNUSED(arg1))
{
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
wmWindowManager *wm = CTX_wm_manager(C);
uiBlock *block = UI_block_begin(C, region, "autorun_warning_popup", UI_EMBOSS);
@@ -3357,7 +3387,7 @@ static uiBlock *block_create_autorun_warning(struct bContext *C,
/* Allow reload if we have a saved file.
* Otherwise just enable scripts and reset the depsgraphs. */
- if (G.relbase_valid && wm->file_saved) {
+ if ((blendfile_path[0] != '\0') && wm->file_saved) {
but = uiDefIconTextBut(block,
UI_BTYPE_BUT,
0,
@@ -3588,6 +3618,14 @@ static void wm_block_file_close_save_button(uiBlock *block, wmGenericCallback *p
static const char *close_file_dialog_name = "file_close_popup";
+static void save_catalogs_when_file_is_closed_set_fn(bContext *UNUSED(C),
+ void *arg1,
+ void *UNUSED(arg2))
+{
+ char *save_catalogs_when_file_is_closed = arg1;
+ ED_asset_catalogs_set_save_catalogs_when_file_is_saved(*save_catalogs_when_file_is_closed != 0);
+}
+
static uiBlock *block_create__close_file_dialog(struct bContext *C,
struct ARegion *region,
void *arg1)
@@ -3606,10 +3644,10 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C,
uiItemL_ex(layout, TIP_("Save changes before closing?"), ICON_NONE, true, false);
/* Filename. */
- const char *blendfile_pathpath = BKE_main_blendfile_path(CTX_data_main(C));
+ const char *blendfile_path = BKE_main_blendfile_path(CTX_data_main(C));
char filename[FILE_MAX];
- if (blendfile_pathpath[0] != '\0') {
- BLI_split_file_part(blendfile_pathpath, filename, sizeof(filename));
+ if (blendfile_path[0] != '\0') {
+ BLI_split_file_part(blendfile_path, filename, sizeof(filename));
}
else {
STRNCPY(filename, "untitled.blend");
@@ -3644,11 +3682,17 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C,
MEM_freeN(message);
}
+ /* Used to determine if extra separators are needed. */
+ bool has_extra_checkboxes = false;
+
/* Modified Images Checkbox. */
if (modified_images_count > 0) {
char message[64];
BLI_snprintf(message, sizeof(message), "Save %u modified image(s)", modified_images_count);
- uiItemS(layout);
+ /* Only the first checkbox should get extra separation. */
+ if (!has_extra_checkboxes) {
+ uiItemS(layout);
+ }
uiDefButBitC(block,
UI_BTYPE_CHECKBOX,
1,
@@ -3664,11 +3708,41 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C,
0,
0,
"");
+ has_extra_checkboxes = true;
+ }
+
+ if (BKE_asset_library_has_any_unsaved_catalogs()) {
+ static char save_catalogs_when_file_is_closed;
+
+ save_catalogs_when_file_is_closed = ED_asset_catalogs_get_save_catalogs_when_file_is_saved();
+
+ /* Only the first checkbox should get extra separation. */
+ if (!has_extra_checkboxes) {
+ uiItemS(layout);
+ }
+ uiBut *but = uiDefButBitC(block,
+ UI_BTYPE_CHECKBOX,
+ 1,
+ 0,
+ "Save modified asset catalogs",
+ 0,
+ 0,
+ 0,
+ UI_UNIT_Y,
+ &save_catalogs_when_file_is_closed,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
+ UI_but_func_set(
+ but, save_catalogs_when_file_is_closed_set_fn, &save_catalogs_when_file_is_closed, NULL);
+ has_extra_checkboxes = true;
}
BKE_reports_clear(&reports);
- uiItemS_ex(layout, modified_images_count > 0 ? 2.0f : 4.0f);
+ uiItemS_ex(layout, has_extra_checkboxes ? 2.0f : 4.0f);
/* Buttons. */
#ifdef _WIN32
@@ -3740,16 +3814,12 @@ static void wm_free_operator_properties_callback(void *user_data)
IDP_FreeProperty(properties);
}
-/**
- * \return True if the dialog was created, the calling operator should return #OPERATOR_INTERFACE
- * then.
- */
bool wm_operator_close_file_dialog_if_needed(bContext *C,
wmOperator *op,
wmGenericCallbackFn post_action_fn)
{
if (U.uiflag & USER_SAVE_PROMPT &&
- wm_file_or_image_is_modified(CTX_data_main(C), CTX_wm_manager(C))) {
+ wm_file_or_session_data_has_unsaved_changes(CTX_data_main(C), CTX_wm_manager(C))) {
wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__);
callback->exec = post_action_fn;
callback->user_data = IDP_CopyProperty(op->properties);
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index ea0b0a9feaa..cf6ecd55757 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -53,6 +53,7 @@
#include "BLO_readfile.h"
#include "BKE_armature.h"
+#include "BKE_blendfile_link_append.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_key.h"
@@ -112,12 +113,13 @@ static bool wm_link_append_poll(bContext *C)
static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
if (G.lib[0] != '\0') {
RNA_string_set(op->ptr, "filepath", G.lib);
}
- else if (G.relbase_valid) {
+ else if (blendfile_path[0] != '\0') {
char path[FILE_MAX];
- BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path));
+ STRNCPY(path, blendfile_path);
BLI_path_parent_dir(path);
RNA_string_set(op->ptr, "filepath", path);
}
@@ -166,830 +168,6 @@ static int wm_link_append_flag(wmOperator *op)
return flag;
}
-typedef struct WMLinkAppendDataItem {
- char *name;
- BLI_bitmap
- *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */
- short idcode;
-
- /** Type of action to do to append this item, and other append-specific information. */
- char append_action;
- char append_tag;
-
- ID *new_id;
- void *customdata;
-} WMLinkAppendDataItem;
-
-typedef struct WMLinkAppendData {
- LinkNodePair libraries;
- LinkNodePair items;
- int num_libraries;
- int num_items;
- /**
- * Combines #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags from BLO_readfile.h
- */
- int flag;
-
- /** Allows to easily find an existing items from an ID pointer. Used by append code. */
- GHash *new_id_to_item;
-
- /** Runtime info used by append code to manage re-use of already appended matching IDs. */
- GHash *library_weak_reference_mapping;
-
- /* Internal 'private' data */
- MemArena *memarena;
-} WMLinkAppendData;
-
-typedef struct WMLinkAppendDataCallBack {
- WMLinkAppendData *lapp_data;
- WMLinkAppendDataItem *item;
- ReportList *reports;
-
-} WMLinkAppendDataCallBack;
-
-enum {
- WM_APPEND_ACT_UNSET = 0,
- WM_APPEND_ACT_KEEP_LINKED,
- WM_APPEND_ACT_REUSE_LOCAL,
- WM_APPEND_ACT_MAKE_LOCAL,
- WM_APPEND_ACT_COPY_LOCAL,
-};
-
-enum {
- WM_APPEND_TAG_INDIRECT = 1 << 0,
-};
-
-static WMLinkAppendData *wm_link_append_data_new(const int flag)
-{
- MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data));
-
- lapp_data->flag = flag;
- lapp_data->memarena = ma;
-
- return lapp_data;
-}
-
-static void wm_link_append_data_free(WMLinkAppendData *lapp_data)
-{
- if (lapp_data->new_id_to_item != NULL) {
- BLI_ghash_free(lapp_data->new_id_to_item, NULL, NULL);
- }
-
- BLI_assert(lapp_data->library_weak_reference_mapping == NULL);
-
- BLI_memarena_free(lapp_data->memarena);
-}
-
-/* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */
-
-static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname)
-{
- size_t len = strlen(libname) + 1;
- char *libpath = BLI_memarena_alloc(lapp_data->memarena, len);
-
- BLI_strncpy(libpath, libname, len);
- BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena);
- lapp_data->num_libraries++;
-}
-
-static WMLinkAppendDataItem *wm_link_append_data_item_add(WMLinkAppendData *lapp_data,
- const char *idname,
- const short idcode,
- void *customdata)
-{
- WMLinkAppendDataItem *item = BLI_memarena_alloc(lapp_data->memarena, sizeof(*item));
- size_t len = strlen(idname) + 1;
-
- item->name = BLI_memarena_alloc(lapp_data->memarena, len);
- BLI_strncpy(item->name, idname, len);
- item->idcode = idcode;
- item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries);
-
- item->new_id = NULL;
- item->append_action = WM_APPEND_ACT_UNSET;
- item->customdata = customdata;
-
- BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena);
- lapp_data->num_items++;
-
- return item;
-}
-
-/* -------------------------------------------------------------------- */
-/** \name Library appending helper functions.
- *
- * FIXME: Deduplicate code with similar one in readfile.c
- * \{ */
-
-static bool object_in_any_scene(Main *bmain, Object *ob)
-{
- LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
- if (BKE_scene_object_find(sce, ob)) {
- return true;
- }
- }
-
- return false;
-}
-
-static bool object_in_any_collection(Main *bmain, Object *ob)
-{
- LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
- if (BKE_collection_has_object(collection, ob)) {
- return true;
- }
- }
-
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- if (scene->master_collection != NULL &&
- BKE_collection_has_object(scene->master_collection, ob)) {
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * Shared operations to perform on the object's base after adding it to the scene.
- */
-static void wm_append_loose_data_instantiate_object_base_instance_init(
- Object *ob, bool set_selected, bool set_active, ViewLayer *view_layer, const View3D *v3d)
-{
- Base *base = BKE_view_layer_base_find(view_layer, ob);
-
- if (v3d != NULL) {
- base->local_view_bits |= v3d->local_view_uuid;
- }
-
- if (set_selected) {
- if (base->flag & BASE_SELECTABLE) {
- base->flag |= BASE_SELECTED;
- }
- }
-
- if (set_active) {
- view_layer->basact = base;
- }
-
- BKE_scene_object_base_flag_sync_from_base(base);
-}
-
-static ID *wm_append_loose_data_instantiate_process_check(WMLinkAppendDataItem *item)
-{
- /* We consider that if we either kept it linked, or re-used already local data, instantiation
- * status of those should not be modified. */
- if (!ELEM(item->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_APPEND_ACT_MAKE_LOCAL)) {
- return NULL;
- }
-
- ID *id = item->new_id;
- if (id == NULL) {
- return NULL;
- }
-
- if (item->append_action == WM_APPEND_ACT_COPY_LOCAL) {
- BLI_assert(ID_IS_LINKED(id));
- id = id->newid;
- if (id == NULL) {
- return NULL;
- }
-
- BLI_assert(!ID_IS_LINKED(id));
- return id;
- }
-
- BLI_assert(!ID_IS_LINKED(id));
- return id;
-}
-
-static void wm_append_loose_data_instantiate_ensure_active_collection(
- WMLinkAppendData *lapp_data,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- Collection **r_active_collection)
-{
- /* Find or add collection as needed. */
- if (*r_active_collection == NULL) {
- if (lapp_data->flag & FILE_ACTIVE_COLLECTION) {
- LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
- *r_active_collection = lc->collection;
- }
- else {
- *r_active_collection = BKE_collection_add(bmain, scene->master_collection, NULL);
- }
- }
-}
-
-/* TODO: De-duplicate this code with the one in readfile.c, think we need some utils code for that
- * in BKE. */
-static void wm_append_loose_data_instantiate(WMLinkAppendData *lapp_data,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d)
-{
- if (scene == NULL) {
- /* In some cases, like the asset drag&drop e.g., the caller code manages instantiation itself.
- */
- return;
- }
-
- LinkNode *itemlink;
- Collection *active_collection = NULL;
- const bool do_obdata = (lapp_data->flag & BLO_LIBLINK_OBDATA_INSTANCE) != 0;
-
- const bool object_set_selected = (lapp_data->flag & FILE_AUTOSELECT) != 0;
- /* Do NOT make base active here! screws up GUI stuff,
- * if you want it do it at the editor level. */
- const bool object_set_active = false;
-
- /* First pass on obdata to enable their instantiation by default, then do a second pass on
- * objects to clear it for any obdata already in use. */
- if (do_obdata) {
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = wm_append_loose_data_instantiate_process_check(item);
- if (id == NULL) {
- continue;
- }
- const ID_Type idcode = GS(id->name);
- if (!OB_DATA_SUPPORT_ID(idcode)) {
- continue;
- }
-
- id->tag |= LIB_TAG_DOIT;
- }
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = item->new_id;
- if (id == NULL || GS(id->name) != ID_OB) {
- continue;
- }
-
- Object *ob = (Object *)id;
- Object *new_ob = (Object *)id->newid;
- if (ob->data != NULL) {
- ((ID *)(ob->data))->tag &= ~LIB_TAG_DOIT;
- }
- if (new_ob != NULL && new_ob->data != NULL) {
- ((ID *)(new_ob->data))->tag &= ~LIB_TAG_DOIT;
- }
- }
- }
-
- /* First do collections, then objects, then obdata. */
-
- /* NOTE: For collections we only view_layer-instantiate duplicated collections that have
- * non-instantiated objects in them. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = wm_append_loose_data_instantiate_process_check(item);
- if (id == NULL || GS(id->name) != ID_GR) {
- continue;
- }
-
- /* We do not want to force instantiation of indirectly appended collections. Users can now
- * easily instantiate collections (and their objects) as needed by themselves. See T67032. */
- /* We need to check that objects in that collections are already instantiated in a scene.
- * Otherwise, it's better to add the collection to the scene's active collection, than to
- * instantiate its objects in active scene's collection directly. See T61141.
- *
- * NOTE: We only check object directly into that collection, not recursively into its
- * children.
- */
- Collection *collection = (Collection *)id;
- bool do_add_collection = false;
- LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
- Object *ob = coll_ob->ob;
- if (!object_in_any_scene(bmain, ob)) {
- do_add_collection = true;
- break;
- }
- }
- if (do_add_collection) {
- wm_append_loose_data_instantiate_ensure_active_collection(
- lapp_data, bmain, scene, view_layer, &active_collection);
-
- /* In case user requested instantiation of collections as empties, we do so for the one they
- * explicitly selected (originally directly linked IDs). */
- if ((lapp_data->flag & BLO_LIBLINK_COLLECTION_INSTANCE) != 0 &&
- (item->append_tag & WM_APPEND_TAG_INDIRECT) == 0) {
- /* BKE_object_add(...) messes with the selection. */
- Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2);
- ob->type = OB_EMPTY;
- ob->empty_drawsize = U.collection_instance_empty_size;
-
- BKE_collection_object_add(bmain, active_collection, ob);
-
- const bool set_selected = (lapp_data->flag & FILE_AUTOSELECT) != 0;
- /* TODO: why is it OK to make this active here but not in other situations?
- * See other callers of #object_base_instance_init */
- const bool set_active = set_selected;
- wm_append_loose_data_instantiate_object_base_instance_init(
- ob, set_selected, set_active, view_layer, v3d);
-
- /* Assign the collection. */
- ob->instance_collection = collection;
- id_us_plus(&collection->id);
- ob->transflag |= OB_DUPLICOLLECTION;
- copy_v3_v3(ob->loc, scene->cursor.location);
- }
- else {
- /* Add collection as child of active collection. */
- BKE_collection_child_add(bmain, active_collection, collection);
-
- if ((lapp_data->flag & FILE_AUTOSELECT) != 0) {
- LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
- Object *ob = coll_ob->ob;
- Base *base = BKE_view_layer_base_find(view_layer, ob);
- if (base) {
- base->flag |= BASE_SELECTED;
- BKE_scene_object_base_flag_sync_from_base(base);
- }
- }
- }
- }
- }
- }
-
- /* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used
- * anywhere. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = wm_append_loose_data_instantiate_process_check(item);
- if (id == NULL || GS(id->name) != ID_OB) {
- continue;
- }
-
- Object *ob = (Object *)id;
-
- if (object_in_any_collection(bmain, ob)) {
- continue;
- }
-
- wm_append_loose_data_instantiate_ensure_active_collection(
- lapp_data, bmain, scene, view_layer, &active_collection);
-
- CLAMP_MIN(ob->id.us, 0);
- ob->mode = OB_MODE_OBJECT;
-
- BKE_collection_object_add(bmain, active_collection, ob);
-
- wm_append_loose_data_instantiate_object_base_instance_init(
- ob, object_set_selected, object_set_active, view_layer, v3d);
- }
-
- if (!do_obdata) {
- return;
- }
-
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = wm_append_loose_data_instantiate_process_check(item);
- if (id == NULL) {
- continue;
- }
- const ID_Type idcode = GS(id->name);
- if (!OB_DATA_SUPPORT_ID(idcode)) {
- continue;
- }
- if ((id->tag & LIB_TAG_DOIT) == 0) {
- continue;
- }
-
- wm_append_loose_data_instantiate_ensure_active_collection(
- lapp_data, bmain, scene, view_layer, &active_collection);
-
- const int type = BKE_object_obdata_to_type(id);
- BLI_assert(type != -1);
- Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2);
- ob->data = id;
- id_us_plus(id);
- BKE_object_materials_test(bmain, ob, ob->data);
-
- BKE_collection_object_add(bmain, active_collection, ob);
-
- wm_append_loose_data_instantiate_object_base_instance_init(
- ob, object_set_selected, object_set_active, view_layer, v3d);
-
- copy_v3_v3(ob->loc, scene->cursor.location);
-
- id->tag &= ~LIB_TAG_DOIT;
- }
-}
-
-/** \} */
-
-static int foreach_libblock_append_callback(LibraryIDLinkCallbackData *cb_data)
-{
- if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK)) {
- return IDWALK_RET_NOP;
- }
-
- WMLinkAppendDataCallBack *data = cb_data->user_data;
- ID *id = *cb_data->id_pointer;
-
- if (id == NULL) {
- return IDWALK_RET_NOP;
- }
-
- if (!BKE_idtype_idcode_is_linkable(GS(id->name))) {
- return IDWALK_RET_NOP;
- }
-
- WMLinkAppendDataItem *item = BLI_ghash_lookup(data->lapp_data->new_id_to_item, id);
- if (item == NULL) {
- item = wm_link_append_data_item_add(data->lapp_data, id->name, GS(id->name), NULL);
- item->new_id = id;
- /* Since we did not have an item for that ID yet, we now user did not selected it explicitly,
- * it was rather linked indirectly. This info is important for instantiation of collections. */
- item->append_tag |= WM_APPEND_TAG_INDIRECT;
- BLI_ghash_insert(data->lapp_data->new_id_to_item, id, item);
- }
-
- /* NOTE: currently there is no need to do anything else here, but in the future this would be
- * the place to add specific per-usage decisions on how to append an ID. */
-
- return IDWALK_RET_NOP;
-}
-
-/* Perform append operation, using modern ID usage looper to detect which ID should be kept linked,
- * made local, duplicated as local, re-used from local etc.
- *
- * TODO: Expose somehow this logic to the two other parts of code performing actual append
- * (i.e. copy/paste and `bpy` link/append API).
- * Then we can heavily simplify #BKE_library_make_local(). */
-static void wm_append_do(WMLinkAppendData *lapp_data,
- ReportList *reports,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d)
-{
- BLI_assert((lapp_data->flag & FILE_LINK) == 0);
-
- const bool do_recursive = (lapp_data->flag & BLO_LIBLINK_APPEND_RECURSIVE) != 0;
- const bool set_fakeuser = (lapp_data->flag & BLO_LIBLINK_APPEND_SET_FAKEUSER) != 0;
- const bool do_reuse_local_id = (lapp_data->flag & BLO_LIBLINK_APPEND_LOCAL_ID_REUSE) != 0;
-
- LinkNode *itemlink;
-
- /* Generate a mapping between newly linked IDs and their items. */
- lapp_data->new_id_to_item = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- BLI_ghash_insert(lapp_data->new_id_to_item, id, item);
- }
-
- lapp_data->library_weak_reference_mapping = BKE_main_library_weak_reference_create(bmain);
-
- /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect
- * dependencies), this list will grow and we will process those IDs later, leading to a flatten
- * recursive processing of all the linked dependencies. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- BLI_assert(item->customdata == NULL);
-
- /* In Append case linked IDs should never be marked as needing post-processing (instantiation
- * of loose objects etc.). */
- BLI_assert((id->tag & LIB_TAG_DOIT) == 0);
-
- ID *existing_local_id = BKE_idtype_idcode_append_is_reusable(GS(id->name)) ?
- BKE_main_library_weak_reference_search_item(
- lapp_data->library_weak_reference_mapping,
- id->lib->filepath,
- id->name) :
- NULL;
-
- if (item->append_action != WM_APPEND_ACT_UNSET) {
- /* Already set, pass. */
- }
- if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) {
- CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name);
- item->append_action = WM_APPEND_ACT_KEEP_LINKED;
- }
- else if (do_reuse_local_id && existing_local_id != NULL) {
- CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name);
- item->append_action = WM_APPEND_ACT_REUSE_LOCAL;
- item->customdata = existing_local_id;
- }
- else if (id->tag & LIB_TAG_PRE_EXISTING) {
- CLOG_INFO(&LOG, 3, "Appended ID '%s' was already linked, need to copy it...", id->name);
- item->append_action = WM_APPEND_ACT_COPY_LOCAL;
- }
- else {
- /* In future we could search for already existing matching local ID etc. */
- CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name);
- item->append_action = WM_APPEND_ACT_MAKE_LOCAL;
- }
-
- /* Only check dependencies if we are not keeping linked data, nor re-using existing local data.
- */
- if (do_recursive &&
- !ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) {
- WMLinkAppendDataCallBack cb_data = {
- .lapp_data = lapp_data, .item = item, .reports = reports};
- BKE_library_foreach_ID_link(
- bmain, id, foreach_libblock_append_callback, &cb_data, IDWALK_NOP);
- }
-
- /* If we found a matching existing local id but are not re-using it, we need to properly clear
- * its weak reference to linked data. */
- if (existing_local_id != NULL &&
- !ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) {
- BKE_main_library_weak_reference_remove_item(lapp_data->library_weak_reference_mapping,
- id->lib->filepath,
- id->name,
- existing_local_id);
- }
- }
-
- /* Effectively perform required operation on every linked ID. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
-
- ID *local_appended_new_id = NULL;
- char lib_filepath[FILE_MAX];
- BLI_strncpy(lib_filepath, id->lib->filepath, sizeof(lib_filepath));
- char lib_id_name[MAX_ID_NAME];
- BLI_strncpy(lib_id_name, id->name, sizeof(lib_id_name));
-
- switch (item->append_action) {
- case WM_APPEND_ACT_COPY_LOCAL: {
- BKE_lib_id_make_local(
- bmain, id, LIB_ID_MAKELOCAL_FULL_LIBRARY | LIB_ID_MAKELOCAL_FORCE_COPY);
- local_appended_new_id = id->newid;
- break;
- }
- case WM_APPEND_ACT_MAKE_LOCAL:
- BKE_lib_id_make_local(bmain,
- id,
- LIB_ID_MAKELOCAL_FULL_LIBRARY | LIB_ID_MAKELOCAL_FORCE_LOCAL |
- LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING);
- BLI_assert(id->newid == NULL);
- local_appended_new_id = id;
- break;
- case WM_APPEND_ACT_KEEP_LINKED:
- /* Nothing to do here. */
- break;
- case WM_APPEND_ACT_REUSE_LOCAL:
- /* We only need to set `newid` to ID found in previous loop, for proper remapping. */
- ID_NEW_SET(id, item->customdata);
- /* This is not a 'new' local appended id, do not set `local_appended_new_id` here. */
- break;
- case WM_APPEND_ACT_UNSET:
- CLOG_ERROR(
- &LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name);
- break;
- default:
- BLI_assert(0);
- }
-
- if (local_appended_new_id != NULL) {
- if (BKE_idtype_idcode_append_is_reusable(GS(local_appended_new_id->name))) {
- BKE_main_library_weak_reference_add_item(lapp_data->library_weak_reference_mapping,
- lib_filepath,
- lib_id_name,
- local_appended_new_id);
- }
-
- if (GS(local_appended_new_id->name) == ID_OB) {
- BKE_rigidbody_ensure_local_object(bmain, (Object *)local_appended_new_id);
- }
- if (set_fakeuser) {
- if (!ELEM(GS(local_appended_new_id->name), ID_OB, ID_GR)) {
- /* Do not set fake user on objects nor collections (instancing). */
- id_fake_user_set(local_appended_new_id);
- }
- }
- }
- }
-
- BKE_main_library_weak_reference_destroy(lapp_data->library_weak_reference_mapping);
- lapp_data->library_weak_reference_mapping = NULL;
-
- /* Remap IDs as needed. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
-
- if (item->append_action == WM_APPEND_ACT_KEEP_LINKED) {
- continue;
- }
-
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- if (ELEM(item->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_APPEND_ACT_REUSE_LOCAL)) {
- BLI_assert(ID_IS_LINKED(id));
- id = id->newid;
- if (id == NULL) {
- continue;
- }
- }
-
- BLI_assert(!ID_IS_LINKED(id));
-
- BKE_libblock_relink_to_newid_new(bmain, id);
- }
-
- /* Remove linked IDs when a local existing data has been reused instead. */
- BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
-
- if (item->append_action != WM_APPEND_ACT_REUSE_LOCAL) {
- continue;
- }
-
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- BLI_assert(ID_IS_LINKED(id));
- BLI_assert(id->newid != NULL);
-
- id->tag |= LIB_TAG_DOIT;
- item->new_id = id->newid;
- }
- BKE_id_multi_tagged_delete(bmain);
-
- /* Instantiate newly created (duplicated) IDs as needed. */
- wm_append_loose_data_instantiate(lapp_data, bmain, scene, view_layer, v3d);
-
- /* Attempt to deal with object proxies.
- *
- * NOTE: Copied from `BKE_library_make_local`, but this is not really working (as in, not
- * producing any useful result in any known use case), neither here nor in
- * `BKE_library_make_local` currently.
- * Proxies are end of life anyway, so not worth spending time on this. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
-
- if (item->append_action != WM_APPEND_ACT_COPY_LOCAL) {
- continue;
- }
-
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- BLI_assert(ID_IS_LINKED(id));
-
- /* Attempt to re-link copied proxy objects. This allows appending of an entire scene
- * from another blend file into this one, even when that blend file contains proxified
- * armatures that have local references. Since the proxified object needs to be linked
- * (not local), this will only work when the "Localize all" checkbox is disabled.
- * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
- if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
- Object *ob = (Object *)id;
- Object *ob_new = (Object *)id->newid;
- bool is_local = false, is_lib = false;
-
- /* Proxies only work when the proxified object is linked-in from a library. */
- if (!ID_IS_LINKED(ob->proxy)) {
- CLOG_WARN(&LOG,
- "Proxy object %s will lose its link to %s, because the "
- "proxified object is local",
- id->newid->name,
- ob->proxy->id.name);
- continue;
- }
-
- BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
-
- /* We can only switch the proxy'ing to a made-local proxy if it is no longer
- * referred to from a library. Not checking for local use; if new local proxy
- * was not used locally would be a nasty bug! */
- if (is_local || is_lib) {
- CLOG_WARN(&LOG,
- "Made-local proxy object %s will lose its link to %s, "
- "because the linked-in proxy is referenced (is_local=%i, is_lib=%i)",
- id->newid->name,
- ob->proxy->id.name,
- is_local,
- is_lib);
- }
- else {
- /* we can switch the proxy'ing from the linked-in to the made-local proxy.
- * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
- * was already allocated by object_make_local() (which called BKE_object_copy). */
- ob_new->proxy = ob->proxy;
- ob_new->proxy_group = ob->proxy_group;
- ob_new->proxy_from = ob->proxy_from;
- ob_new->proxy->proxy_from = ob_new;
- ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
- }
- }
- }
-
- BKE_main_id_newptr_and_tag_clear(bmain);
-}
-
-static void wm_link_do(WMLinkAppendData *lapp_data,
- ReportList *reports,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d)
-{
- Main *mainl;
- BlendHandle *bh;
- Library *lib;
-
- const int flag = lapp_data->flag;
- const int id_tag_extra = 0;
-
- LinkNode *liblink, *itemlink;
- int lib_idx, item_idx;
-
- BLI_assert(lapp_data->num_items && lapp_data->num_libraries);
-
- for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink;
- lib_idx++, liblink = liblink->next) {
- char *libname = liblink->link;
- BlendFileReadReport bf_reports = {.reports = reports};
-
- if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) {
- bh = BLO_blendhandle_from_memory(
- datatoc_startup_blend, datatoc_startup_blend_size, &bf_reports);
- }
- else {
- bh = BLO_blendhandle_from_file(libname, &bf_reports);
- }
-
- if (bh == NULL) {
- /* Unlikely since we just browsed it, but possible
- * Error reports will have been made by BLO_blendhandle_from_file() */
- continue;
- }
-
- /* here appending/linking starts */
- struct LibraryLink_Params liblink_params;
- BLO_library_link_params_init_with_context(
- &liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d);
- /* In case of append, do not handle instantiation in linking process, but during append phase
- * (see #wm_append_loose_data_instantiate ). */
- if ((flag & FILE_LINK) == 0) {
- liblink_params.flag &= ~BLO_LIBLINK_NEEDS_ID_TAG_DOIT;
- }
-
- mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
- lib = mainl->curlib;
- BLI_assert(lib);
- UNUSED_VARS_NDEBUG(lib);
-
- if (mainl->versionfile < 250) {
- BKE_reportf(reports,
- RPT_WARNING,
- "Linking or appending from a very old .blend file format (%d.%d), no animation "
- "conversion will "
- "be done! You may want to re-save your lib file with current Blender",
- mainl->versionfile,
- mainl->subversionfile);
- }
-
- /* For each lib file, we try to link all items belonging to that lib,
- * and tag those successful to not try to load them again with the other libs. */
- for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
- item_idx++, itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *new_id;
-
- if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) {
- continue;
- }
-
- new_id = BLO_library_link_named_part(mainl, &bh, item->idcode, item->name, &liblink_params);
-
- if (new_id) {
- /* If the link is successful, clear item's libs 'todo' flags.
- * This avoids trying to link same item with other libraries to come. */
- BLI_bitmap_set_all(item->libraries, false, lapp_data->num_libraries);
- item->new_id = new_id;
- }
- }
-
- BLO_library_link_end(mainl, &bh, &liblink_params);
- BLO_blendhandle_close(bh);
- }
-}
-
/**
* Check if an item defined by \a name and \a group can be appended/linked.
*
@@ -1040,7 +218,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
PropertyRNA *prop;
- WMLinkAppendData *lapp_data;
+ BlendfileLinkAppendContext *lapp_context;
char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA], relname[FILE_MAX];
char *group, *name;
int totfiles = 0;
@@ -1107,7 +285,14 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* We define our working data...
* Note that here, each item 'uses' one library, and only one. */
- lapp_data = wm_link_append_data_new(flag);
+ LibraryLink_Params lapp_params;
+ BLO_library_link_params_init_with_context(
+ &lapp_params, bmain, flag, 0, scene, view_layer, CTX_wm_view3d(C));
+
+ lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
+ BKE_blendfile_link_append_context_embedded_blendfile_set(
+ lapp_context, datatoc_startup_blend, datatoc_startup_blend_size);
+
if (totfiles != 0) {
GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
int lib_idx = 0;
@@ -1125,7 +310,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
if (!BLI_ghash_haskey(libraries, libname)) {
BLI_ghash_insert(libraries, BLI_strdup(libname), POINTER_FROM_INT(lib_idx));
lib_idx++;
- wm_link_append_data_library_add(lapp_data, libname);
+ BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL);
}
}
}
@@ -1137,7 +322,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
BLI_join_dirfile(path, sizeof(path), root, relname);
if (BLO_library_path_explode(path, libname, &group, &name)) {
- WMLinkAppendDataItem *item;
+ BlendfileLinkAppendContextItem *item;
if (!wm_link_append_item_poll(op->reports, path, group, name, do_append)) {
continue;
@@ -1145,9 +330,9 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
lib_idx = POINTER_AS_INT(BLI_ghash_lookup(libraries, libname));
- item = wm_link_append_data_item_add(
- lapp_data, name, BKE_idtype_idcode_from_name(group), NULL);
- BLI_BITMAP_ENABLE(item->libraries, lib_idx);
+ item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, name, BKE_idtype_idcode_from_name(group), NULL);
+ BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, lib_idx);
}
}
RNA_END;
@@ -1155,16 +340,17 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
BLI_ghash_free(libraries, MEM_freeN, NULL);
}
else {
- WMLinkAppendDataItem *item;
+ BlendfileLinkAppendContextItem *item;
- wm_link_append_data_library_add(lapp_data, libname);
- item = wm_link_append_data_item_add(lapp_data, name, BKE_idtype_idcode_from_name(group), NULL);
- BLI_BITMAP_ENABLE(item->libraries, 0);
+ BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL);
+ item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, name, BKE_idtype_idcode_from_name(group), NULL);
+ BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0);
}
- if (lapp_data->num_items == 0) {
+ if (BKE_blendfile_link_append_context_is_empty(lapp_context)) {
/* Early out in case there is nothing to link. */
- wm_link_append_data_free(lapp_data);
+ BKE_blendfile_link_append_context_free(lapp_context);
/* Clear pre existing tag. */
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
return OPERATOR_CANCELLED;
@@ -1173,7 +359,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* XXX We'd need re-entrant locking on Main for this to work... */
// BKE_main_lock(bmain);
- wm_link_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C));
+ BKE_blendfile_link(lapp_context, op->reports);
// BKE_main_unlock(bmain);
@@ -1183,10 +369,10 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* append, rather than linking */
if (do_append) {
- wm_append_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C));
+ BKE_blendfile_append(lapp_context, op->reports);
}
- wm_link_append_data_free(lapp_data);
+ BKE_blendfile_link_append_context_free(lapp_context);
/* important we unset, otherwise these object won't
* link into other scenes from this blend file */
@@ -1338,33 +524,35 @@ static ID *wm_file_link_append_datablock_ex(Main *bmain,
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
/* Define working data, with just the one item we want to link. */
- WMLinkAppendData *lapp_data = wm_link_append_data_new(flag);
+ LibraryLink_Params lapp_params;
+ BLO_library_link_params_init_with_context(&lapp_params, bmain, flag, 0, scene, view_layer, v3d);
+
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
+ BKE_blendfile_link_append_context_embedded_blendfile_set(
+ lapp_context, datatoc_startup_blend, datatoc_startup_blend_size);
- wm_link_append_data_library_add(lapp_data, filepath);
- WMLinkAppendDataItem *item = wm_link_append_data_item_add(lapp_data, id_name, id_code, NULL);
- BLI_BITMAP_ENABLE(item->libraries, 0);
+ BKE_blendfile_link_append_context_library_add(lapp_context, filepath, NULL);
+ BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, id_name, id_code, NULL);
+ BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0);
/* Link datablock. */
- wm_link_do(lapp_data, NULL, bmain, scene, view_layer, v3d);
+ BKE_blendfile_link(lapp_context, NULL);
if (do_append) {
- wm_append_do(lapp_data, NULL, bmain, scene, view_layer, v3d);
+ BKE_blendfile_append(lapp_context, NULL);
}
/* Get linked datablock and free working data. */
- ID *id = item->new_id;
+ ID *id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item);
- wm_link_append_data_free(lapp_data);
+ BKE_blendfile_link_append_context_free(lapp_context);
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
return id;
}
-/*
- * NOTE: `scene` (and related `view_layer` and `v3d`) pointers may be NULL, in which case no
- * instantiation of linked objects, collections etc. will be performed.
- */
ID *WM_file_link_datablock(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1379,10 +567,6 @@ ID *WM_file_link_datablock(Main *bmain,
bmain, scene, view_layer, v3d, filepath, id_code, id_name, flag);
}
-/*
- * NOTE: `scene` (and related `view_layer` and `v3d`) pointers may be NULL, in which case no
- * instantiation of appended objects, collections etc. will be performed.
- */
ID *WM_file_append_datablock(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1431,291 +615,6 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN
return OPERATOR_CANCELLED;
}
-static void lib_relocate_do_remap(Main *bmain,
- ID *old_id,
- ID *new_id,
- ReportList *reports,
- const bool do_reload,
- const short remap_flags)
-{
- BLI_assert(old_id);
- if (do_reload) {
- /* Since we asked for placeholders in case of missing IDs,
- * we expect to always get a valid one. */
- BLI_assert(new_id);
- }
- if (new_id) {
- CLOG_INFO(&LOG,
- 4,
- "Before remap of %s, old_id users: %d, new_id users: %d",
- old_id->name,
- old_id->us,
- new_id->us);
- BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags);
-
- if (old_id->flag & LIB_FAKEUSER) {
- id_fake_user_clear(old_id);
- id_fake_user_set(new_id);
- }
-
- CLOG_INFO(&LOG,
- 4,
- "After remap of %s, old_id users: %d, new_id users: %d",
- old_id->name,
- old_id->us,
- new_id->us);
-
- /* In some cases, new_id might become direct link, remove parent of library in this case. */
- if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) {
- if (do_reload) {
- BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */
- }
- new_id->lib->parent = NULL;
- }
- }
-
- if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) {
- /* Note that this *should* not happen - but better be safe than sorry in this area,
- * at least until we are 100% sure this cannot ever happen.
- * Also, we can safely assume names were unique so far,
- * so just replacing '.' by '~' should work,
- * but this does not totally rules out the possibility of name collision. */
- size_t len = strlen(old_id->name);
- size_t dot_pos;
- bool has_num = false;
-
- for (dot_pos = len; dot_pos--;) {
- char c = old_id->name[dot_pos];
- if (c == '.') {
- break;
- }
- if (c < '0' || c > '9') {
- has_num = false;
- break;
- }
- has_num = true;
- }
-
- if (has_num) {
- old_id->name[dot_pos] = '~';
- }
- else {
- len = MIN2(len, MAX_ID_NAME - 7);
- BLI_strncpy(&old_id->name[len], "~000", 7);
- }
-
- id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id, NULL);
-
- BKE_reportf(
- reports,
- RPT_WARNING,
- "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, "
- "old one (%d remaining users) had to be kept and was renamed to '%s'",
- new_id->name,
- old_id->us,
- old_id->name);
- }
-}
-
-static void lib_relocate_do(bContext *C,
- Library *library,
- WMLinkAppendData *lapp_data,
- ReportList *reports,
- const bool do_reload)
-{
- ListBase *lbarray[INDEX_ID_MAX];
- int lba_idx;
-
- LinkNode *itemlink;
- int item_idx;
-
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
-
- /* Remove all IDs to be reloaded from Main. */
- lba_idx = set_listbasepointers(bmain, lbarray);
- while (lba_idx--) {
- ID *id = lbarray[lba_idx]->first;
- const short idcode = id ? GS(id->name) : 0;
-
- if (!id || !BKE_idtype_idcode_is_linkable(idcode)) {
- /* No need to reload non-linkable datatypes,
- * those will get relinked with their 'users ID'. */
- continue;
- }
-
- for (; id; id = id->next) {
- if (id->lib == library) {
- WMLinkAppendDataItem *item;
-
- /* We remove it from current Main, and add it to items to link... */
- /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */
- BLI_remlink(lbarray[lba_idx], id);
- /* Usual special code for ShapeKeys snowflakes... */
- Key *old_key = BKE_key_from_id(id);
- if (old_key != NULL) {
- BLI_remlink(which_libbase(bmain, GS(old_key->id.name)), &old_key->id);
- }
-
- item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id);
- BLI_bitmap_set_all(item->libraries, true, lapp_data->num_libraries);
-
- CLOG_INFO(&LOG, 4, "Datablock to seek for: %s", id->name);
- }
- }
- }
-
- if (lapp_data->num_items == 0) {
- /* Early out in case there is nothing to do. */
- return;
- }
-
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
-
- /* We do not want any instantiation here! */
- wm_link_do(lapp_data, reports, bmain, NULL, NULL, NULL);
-
- BKE_main_lock(bmain);
-
- /* We add back old id to bmain.
- * We need to do this in a first, separated loop, otherwise some of those may not be handled by
- * ID remapping, which means they would still reference old data to be deleted... */
- for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
- item_idx++, itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *old_id = item->customdata;
-
- BLI_assert(old_id);
- BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id);
-
- /* Usual special code for ShapeKeys snowflakes... */
- Key *old_key = BKE_key_from_id(old_id);
- if (old_key != NULL) {
- BLI_addtail(which_libbase(bmain, GS(old_key->id.name)), &old_key->id);
- }
- }
-
- /* Since our (old) reloaded IDs were removed from main, the user count done for them in linking
- * code is wrong, we need to redo it here after adding them back to main. */
- BKE_main_id_refcount_recompute(bmain, false);
-
- /* Note that in reload case, we also want to replace indirect usages. */
- const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE |
- ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE |
- (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
- for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
- item_idx++, itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *old_id = item->customdata;
- ID *new_id = item->new_id;
-
- lib_relocate_do_remap(bmain, old_id, new_id, reports, do_reload, remap_flags);
- if (new_id == NULL) {
- continue;
- }
- /* Usual special code for ShapeKeys snowflakes... */
- Key **old_key_p = BKE_key_from_id_p(old_id);
- if (old_key_p == NULL) {
- continue;
- }
- Key *old_key = *old_key_p;
- Key *new_key = BKE_key_from_id(new_id);
- if (old_key != NULL) {
- *old_key_p = NULL;
- id_us_min(&old_key->id);
- lib_relocate_do_remap(bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags);
- *old_key_p = old_key;
- id_us_plus_no_lib(&old_key->id);
- }
- }
-
- BKE_main_unlock(bmain);
-
- for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
- item_idx++, itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *old_id = item->customdata;
-
- if (old_id->us == 0) {
- BKE_id_free(bmain, old_id);
- }
- }
-
- /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable
- * (shape keys e.g.), so we need another loop here to clear old ones if possible. */
- lba_idx = set_listbasepointers(bmain, lbarray);
- while (lba_idx--) {
- ID *id, *id_next;
- for (id = lbarray[lba_idx]->first; id; id = id_next) {
- id_next = id->next;
- /* XXX That check may be a bit to generic/permissive? */
- if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) {
- BKE_id_free(bmain, id);
- }
- }
- }
-
- /* Get rid of no more used libraries... */
- BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true);
- lba_idx = set_listbasepointers(bmain, lbarray);
- while (lba_idx--) {
- ID *id;
- for (id = lbarray[lba_idx]->first; id; id = id->next) {
- if (id->lib) {
- id->lib->id.tag &= ~LIB_TAG_DOIT;
- }
- }
- }
- Library *lib, *lib_next;
- for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) {
- lib_next = lib->id.next;
- if (lib->id.tag & LIB_TAG_DOIT) {
- id_us_clear_real(&lib->id);
- if (lib->id.us == 0) {
- BKE_id_free(bmain, (ID *)lib);
- }
- }
- }
-
- /* Update overrides of reloaded linked data-blocks. */
- ID *id;
- FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id) ||
- (id->tag & LIB_TAG_PRE_EXISTING) == 0) {
- continue;
- }
- if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) {
- BKE_lib_override_library_update(bmain, id);
- }
- }
- FOREACH_MAIN_ID_END;
-
- /* Resync overrides if needed. */
- if (!USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) {
- BKE_lib_override_library_main_resync(bmain,
- scene,
- view_layer,
- &(struct BlendFileReadReport){
- .reports = reports,
- });
- /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */
- BKE_lib_override_library_main_operations_create(bmain, true);
- }
-
- BKE_main_collection_sync(bmain);
-
- BKE_main_lib_objects_recalc_all(bmain);
- IMB_colormanagement_check_file_config(bmain);
-
- /* important we unset, otherwise these object won't
- * link into other scenes from this blend file */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
-
- /* recreate dependency graph to include new objects */
- DEG_relations_tag_update(bmain);
-}
-
void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
{
if (!BLO_has_bfile_extension(lib->filepath_abs)) {
@@ -1732,14 +631,34 @@ void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
return;
}
- WMLinkAppendData *lapp_data = wm_link_append_data_new(BLO_LIBLINK_USE_PLACEHOLDERS |
- BLO_LIBLINK_FORCE_INDIRECT);
+ Main *bmain = CTX_data_main(C);
+ LibraryLink_Params lapp_params;
+ BLO_library_link_params_init_with_context(&lapp_params,
+ bmain,
+ BLO_LIBLINK_USE_PLACEHOLDERS |
+ BLO_LIBLINK_FORCE_INDIRECT,
+ 0,
+ CTX_data_scene(C),
+ CTX_data_view_layer(C),
+ NULL);
- wm_link_append_data_library_add(lapp_data, lib->filepath_abs);
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
+
+ BKE_blendfile_link_append_context_library_add(lapp_context, lib->filepath_abs, NULL);
+
+ BKE_blendfile_library_relocate(lapp_context, reports, lib, true);
+
+ BKE_blendfile_link_append_context_free(lapp_context);
+
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
- lib_relocate_do(C, lib, lapp_data, reports, true);
+ /* Important we unset, otherwise these object won't link into other scenes from this blend file.
+ */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- wm_link_append_data_free(lapp_data);
+ /* Recreate dependency graph to include new IDs. */
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_WINDOW, NULL);
}
@@ -1755,7 +674,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
if (lib) {
Main *bmain = CTX_data_main(C);
PropertyRNA *prop;
- WMLinkAppendData *lapp_data;
+ BlendfileLinkAppendContext *lapp_context;
char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
short flag = 0;
@@ -1800,13 +719,17 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
return OPERATOR_CANCELLED;
}
+ LibraryLink_Params lapp_params;
+ BLO_library_link_params_init_with_context(
+ &lapp_params, bmain, flag, 0, CTX_data_scene(C), CTX_data_view_layer(C), NULL);
+
if (BLI_path_cmp(lib->filepath_abs, path) == 0) {
CLOG_INFO(&LOG, 4, "We are supposed to reload '%s' lib (%d)", lib->filepath, lib->id.us);
do_reload = true;
- lapp_data = wm_link_append_data_new(flag);
- wm_link_append_data_library_add(lapp_data, path);
+ lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
+ BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL);
}
else {
int totfiles = 0;
@@ -1826,7 +749,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
}
}
- lapp_data = wm_link_append_data_new(flag);
+ lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
if (totfiles) {
RNA_BEGIN (op->ptr, itemptr, "files") {
@@ -1839,27 +762,39 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
}
CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path);
- wm_link_append_data_library_add(lapp_data, path);
+ BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL);
}
RNA_END;
}
else {
CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path);
- wm_link_append_data_library_add(lapp_data, path);
+ BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL);
}
}
if (do_reload) {
- lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT;
+ BKE_blendfile_link_append_context_flag_set(
+ lapp_context, BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT, true);
}
- lib_relocate_do(C, lib, lapp_data, op->reports, do_reload);
+ BKE_blendfile_library_relocate(lapp_context, op->reports, lib, do_reload);
- wm_link_append_data_free(lapp_data);
+ BKE_blendfile_link_append_context_free(lapp_context);
/* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
BLI_strncpy(G.lib, root, FILE_MAX);
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
+
+ /* Important we unset, otherwise these object won't link into other scenes from this blend
+ * file.
+ */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+ /* Recreate dependency graph to include new IDs. */
+ DEG_relations_tag_update(bmain);
+
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index ae2cdb5608c..7f923d4af60 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -50,7 +50,6 @@
#include "BIF_glutil.h"
-/* context checked on having screen, window and area */
wmGesture *WM_gesture_new(wmWindow *window, const ARegion *region, const wmEvent *event, int type)
{
wmGesture *gesture = MEM_callocN(sizeof(wmGesture), "new gesture");
@@ -73,14 +72,14 @@ wmGesture *WM_gesture_new(wmWindow *window, const ARegion *region, const wmEvent
rcti *rect = MEM_callocN(sizeof(rcti), "gesture rect new");
gesture->customdata = rect;
- rect->xmin = event->x - gesture->winrct.xmin;
- rect->ymin = event->y - gesture->winrct.ymin;
+ rect->xmin = event->xy[0] - gesture->winrct.xmin;
+ rect->ymin = event->xy[1] - gesture->winrct.ymin;
if (type == WM_GESTURE_CIRCLE) {
/* caller is responsible for initializing 'xmax' to radius. */
}
else {
- rect->xmax = event->x - gesture->winrct.xmin;
- rect->ymax = event->y - gesture->winrct.ymin;
+ rect->xmax = event->xy[0] - gesture->winrct.xmin;
+ rect->ymax = event->xy[1] - gesture->winrct.ymin;
}
}
else if (ELEM(type, WM_GESTURE_LINES, WM_GESTURE_LASSO)) {
@@ -88,8 +87,8 @@ wmGesture *WM_gesture_new(wmWindow *window, const ARegion *region, const wmEvent
gesture->points_alloc = 1024;
gesture->customdata = lasso = MEM_mallocN(sizeof(short[2]) * gesture->points_alloc,
"lasso points");
- lasso[0] = event->x - gesture->winrct.xmin;
- lasso[1] = event->y - gesture->winrct.ymin;
+ lasso[0] = event->xy[0] - gesture->winrct.xmin;
+ lasso[1] = event->xy[1] - gesture->winrct.ymin;
gesture->points = 1;
}
@@ -129,7 +128,6 @@ bool WM_gesture_is_modal_first(const wmGesture *gesture)
return (gesture->is_active_prev == false);
}
-/* tweak and line gestures */
int wm_gesture_evaluate(wmGesture *gesture, const wmEvent *event)
{
if (gesture->type == WM_GESTURE_TWEAK) {
@@ -414,7 +412,7 @@ static void draw_filled_lasso(wmGesture *gt)
GPU_shader_uniform_vector(
state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
- immDrawPixelsTex(
+ immDrawPixelsTexTiled(
&state, rect.xmin, rect.ymin, w, h, GPU_R8, false, pixel_buf, 1.0f, 1.0f, NULL);
GPU_shader_unbind();
@@ -515,7 +513,6 @@ static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
immUnbindProgram();
}
-/* called in wm_draw.c */
void wm_gesture_draw(wmWindow *win)
{
wmGesture *gt = (wmGesture *)win->gesture.first;
diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c
index 578699dda60..8d45d5aed67 100644
--- a/source/blender/windowmanager/intern/wm_gesture_ops.c
+++ b/source/blender/windowmanager/intern/wm_gesture_ops.c
@@ -124,6 +124,7 @@ static int UNUSED_FUNCTION(gesture_modal_state_from_operator)(wmOperator *op)
}
return GESTURE_MODAL_NOP;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -245,17 +246,17 @@ int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE: {
if (gesture->type == WM_GESTURE_CROSS_RECT && gesture->is_active == false) {
- rect->xmin = rect->xmax = event->x - gesture->winrct.xmin;
- rect->ymin = rect->ymax = event->y - gesture->winrct.ymin;
+ rect->xmin = rect->xmax = event->xy[0] - gesture->winrct.xmin;
+ rect->ymin = rect->ymax = event->xy[1] - gesture->winrct.ymin;
}
else if (gesture->move) {
BLI_rcti_translate(rect,
- (event->x - gesture->winrct.xmin) - rect->xmax,
- (event->y - gesture->winrct.ymin) - rect->ymax);
+ (event->xy[0] - gesture->winrct.xmin) - rect->xmax,
+ (event->xy[1] - gesture->winrct.ymin) - rect->ymax);
}
else {
- rect->xmax = event->x - gesture->winrct.xmin;
- rect->ymax = event->y - gesture->winrct.ymin;
+ rect->xmax = event->xy[0] - gesture->winrct.xmin;
+ rect->ymax = event->xy[1] - gesture->winrct.ymin;
}
gesture_box_apply_rect(op);
@@ -365,8 +366,8 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->type == MOUSEMOVE) {
- rect->xmin = event->x - gesture->winrct.xmin;
- rect->ymin = event->y - gesture->winrct.ymin;
+ rect->xmin = event->xy[0] - gesture->winrct.xmin;
+ rect->ymin = event->xy[1] - gesture->winrct.ymin;
wm_gesture_tag_redraw(win);
@@ -381,7 +382,7 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->val) {
case GESTURE_MODAL_CIRCLE_SIZE:
- fac = 0.3f * (event->y - event->prevy);
+ fac = 0.3f * (event->xy[1] - event->prev_xy[1]);
if (fac > 0) {
rect->xmax += ceil(fac);
}
@@ -500,8 +501,8 @@ static void gesture_tweak_modal(bContext *C, const wmEvent *event)
case MOUSEMOVE:
case INBETWEEN_MOUSEMOVE: {
- rect->xmax = event->x - gesture->winrct.xmin;
- rect->ymax = event->y - gesture->winrct.ymin;
+ rect->xmax = event->xy[0] - gesture->winrct.xmin;
+ rect->ymax = event->xy[1] - gesture->winrct.ymin;
const int val = wm_gesture_evaluate(gesture, event);
if (val != 0) {
@@ -510,8 +511,8 @@ static void gesture_tweak_modal(bContext *C, const wmEvent *event)
wm_event_init_from_window(window, &tevent);
/* We want to get coord from start of drag,
* not from point where it becomes a tweak event, see T40549. */
- tevent.x = rect->xmin + gesture->winrct.xmin;
- tevent.y = rect->ymin + gesture->winrct.ymin;
+ tevent.xy[0] = rect->xmin + gesture->winrct.xmin;
+ tevent.xy[1] = rect->ymin + gesture->winrct.ymin;
if (gesture->event_type == LEFTMOUSE) {
tevent.type = EVT_TWEAK_L;
}
@@ -569,7 +570,6 @@ static void gesture_tweak_modal(bContext *C, const wmEvent *event)
}
}
-/* standard tweak, called after window handlers passed on event */
void wm_tweakevent_test(bContext *C, const wmEvent *event, int action)
{
wmWindow *win = CTX_wm_window(C);
@@ -696,8 +696,8 @@ int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
short(*lasso)[2] = gesture->customdata;
- const int x = ((event->x - gesture->winrct.xmin) - lasso[gesture->points - 1][0]);
- const int y = ((event->y - gesture->winrct.ymin) - lasso[gesture->points - 1][1]);
+ const int x = ((event->xy[0] - gesture->winrct.xmin) - lasso[gesture->points - 1][0]);
+ const int y = ((event->xy[1] - gesture->winrct.ymin) - lasso[gesture->points - 1][1]);
/* move the lasso */
if (gesture->move) {
@@ -709,8 +709,8 @@ int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Make a simple distance check to get a smoother lasso
* add only when at least 2 pixels between this and previous location. */
else if ((x * x + y * y) > pow2f(2.0f * UI_DPI_FAC)) {
- lasso[gesture->points][0] = event->x - gesture->winrct.xmin;
- lasso[gesture->points][1] = event->y - gesture->winrct.ymin;
+ lasso[gesture->points][0] = event->xy[0] - gesture->winrct.xmin;
+ lasso[gesture->points][1] = event->xy[1] - gesture->winrct.ymin;
gesture->points++;
}
}
@@ -750,11 +750,6 @@ void WM_gesture_lines_cancel(bContext *C, wmOperator *op)
gesture_modal_end(C, op);
}
-/**
- * helper function, we may want to add options for conversion to view space
- *
- * caller must free.
- */
const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C),
wmOperator *op,
int *r_mcoords_len))[2]
@@ -889,10 +884,6 @@ int WM_gesture_straightline_invoke(bContext *C, wmOperator *op, const wmEvent *e
return OPERATOR_RUNNING_MODAL;
}
-/**
- * This invoke callback starts the straightline gesture with a viewport preview to the right side
- * of the line.
- */
int WM_gesture_straightline_active_side_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
WM_gesture_straightline_invoke(C, op, event);
@@ -928,11 +919,6 @@ static void wm_gesture_straightline_do_angle_snap(rcti *rect)
rect->ymax = (int)line_snapped_end[1];
}
-/**
- * This modal callback calls exec once per mouse move event while the gesture is active with the
- * updated line start and end values, so it can be used for tools that have a real time preview
- * (like a gradient updating in real time over the mesh).
- */
int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmGesture *gesture = op->customdata;
@@ -981,18 +967,18 @@ int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *ev
switch (event->type) {
case MOUSEMOVE: {
if (gesture->is_active == false) {
- rect->xmin = rect->xmax = event->x - gesture->winrct.xmin;
- rect->ymin = rect->ymax = event->y - gesture->winrct.ymin;
+ rect->xmin = rect->xmax = event->xy[0] - gesture->winrct.xmin;
+ rect->ymin = rect->ymax = event->xy[1] - gesture->winrct.ymin;
}
else if (gesture->move) {
BLI_rcti_translate(rect,
- (event->x - gesture->winrct.xmin) - rect->xmax,
- (event->y - gesture->winrct.ymin) - rect->ymax);
+ (event->xy[0] - gesture->winrct.xmin) - rect->xmax,
+ (event->xy[1] - gesture->winrct.ymin) - rect->ymax);
gesture_straightline_apply(C, op);
}
else {
- rect->xmax = event->x - gesture->winrct.xmin;
- rect->ymax = event->y - gesture->winrct.ymin;
+ rect->xmax = event->xy[0] - gesture->winrct.xmin;
+ rect->ymax = event->xy[1] - gesture->winrct.ymin;
gesture_straightline_apply(C, op);
}
@@ -1012,13 +998,6 @@ int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *ev
return OPERATOR_RUNNING_MODAL;
}
-/**
- * This modal one-shot callback only calls exec once after the gesture finishes without any updates
- * during the gesture execution. Should be used for operations that are intended to be applied once
- * without real time preview (like a trimming tool that only applies the bisect operation once
- * after finishing the gesture as the bisect operation is too heavy to be computed in real time for
- * a preview).
- */
int WM_gesture_straightline_oneshot_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmGesture *gesture = op->customdata;
@@ -1072,17 +1051,17 @@ int WM_gesture_straightline_oneshot_modal(bContext *C, wmOperator *op, const wmE
switch (event->type) {
case MOUSEMOVE: {
if (gesture->is_active == false) {
- rect->xmin = rect->xmax = event->x - gesture->winrct.xmin;
- rect->ymin = rect->ymax = event->y - gesture->winrct.ymin;
+ rect->xmin = rect->xmax = event->xy[0] - gesture->winrct.xmin;
+ rect->ymin = rect->ymax = event->xy[1] - gesture->winrct.ymin;
}
else if (gesture->move) {
BLI_rcti_translate(rect,
- (event->x - gesture->winrct.xmin) - rect->xmax,
- (event->y - gesture->winrct.ymin) - rect->ymax);
+ (event->xy[0] - gesture->winrct.xmin) - rect->xmax,
+ (event->xy[1] - gesture->winrct.ymin) - rect->ymax);
}
else {
- rect->xmax = event->x - gesture->winrct.xmin;
- rect->ymax = event->y - gesture->winrct.ymin;
+ rect->xmax = event->xy[0] - gesture->winrct.xmin;
+ rect->ymax = event->xy[1] - gesture->winrct.ymin;
}
if (gesture->use_snap) {
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 56e36800be7..b7eafc6dfad 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -56,7 +56,6 @@
#include "BKE_blendfile.h"
#include "BKE_callbacks.h"
#include "BKE_context.h"
-#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_image.h"
@@ -69,6 +68,7 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sound.h"
+#include "BKE_vfont.h"
#include "BKE_addon.h"
#include "BKE_appdir.h"
@@ -119,6 +119,7 @@
#include "ED_space_api.h"
#include "ED_undo.h"
#include "ED_util.h"
+#include "ED_view3d.h"
#include "BLF_api.h"
#include "BLT_lang.h"
@@ -223,10 +224,6 @@ static void sound_jack_sync_callback(Main *bmain, int mode, double time)
}
}
-/**
- * Initialize Blender and load the startup file & preferences
- * (only called once).
- */
void WM_init(bContext *C, int argc, const char **argv)
{
@@ -256,7 +253,7 @@ void WM_init(bContext *C, int argc, const char **argv)
BKE_region_callback_free_gizmomap_set(wm_gizmomap_remove);
BKE_region_callback_refresh_tag_gizmomap_set(WM_gizmomap_tag_refresh);
BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference);
- BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap);
+ BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap_single);
DEG_editors_set_update_cb(ED_render_id_flush_update, ED_render_scene_update);
ED_spacetypes_init();
@@ -318,9 +315,9 @@ void WM_init(bContext *C, int argc, const char **argv)
NULL,
&params_file_read_post);
- /* NOTE: leave `G_MAIN->name` set to an empty string since this
+ /* NOTE: leave `G_MAIN->filepath` set to an empty string since this
* matches behavior after loading a new file. */
- BLI_assert(G_MAIN->name[0] == '\0');
+ BLI_assert(G_MAIN->filepath[0] == '\0');
/* Call again to set from preferences. */
BLT_lang_set(NULL);
@@ -432,10 +429,6 @@ static int wm_exit_handler(bContext *C, const wmEvent *event, void *userdata)
return WM_UI_HANDLER_BREAK;
}
-/**
- * Cause a delayed #WM_exit()
- * call to avoid leaking memory when trying to exit from within operators.
- */
void wm_exit_schedule_delayed(const bContext *C)
{
/* What we do here is a little bit hacky, but quite simple and doesn't require bigger
@@ -449,9 +442,6 @@ void wm_exit_schedule_delayed(const bContext *C)
WM_event_add_mousemove(win); /* ensure handler actually gets called */
}
-/**
- * \note doesn't run exit() call #WM_exit() for that.
- */
void WM_exit_ex(bContext *C, const bool do_python)
{
wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL;
@@ -548,6 +538,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
RE_engines_exit();
ED_preview_free_dbase(); /* frees a Main dbase, before BKE_blender_free! */
+ ED_preview_restart_queue_free();
ED_assetlist_storage_exit();
if (wm) {
@@ -573,6 +564,13 @@ void WM_exit_ex(bContext *C, const bool do_python)
BKE_blender_free(); /* blender.c, does entire library and spacetypes */
// BKE_material_copybuf_free();
+
+ /* Free the GPU subdivision data after the database to ensure that subdivision structs used by
+ * the modifiers were garbage collected. */
+ if (opengl_is_init) {
+ DRW_subdiv_free();
+ }
+
ANIM_fcurves_copybuf_free();
ANIM_drivers_copybuf_free();
ANIM_driver_vars_copybuf_free();
@@ -656,11 +654,6 @@ void WM_exit_ex(bContext *C, const bool do_python)
BKE_tempdir_session_purge();
}
-/**
- * \brief Main exit function to close Blender ordinarily.
- * \note Use #wm_exit_schedule_delayed() to close Blender from an operator.
- * Might leak memory otherwise.
- */
void WM_exit(bContext *C)
{
WM_exit_ex(C, true);
@@ -678,10 +671,6 @@ void WM_exit(bContext *C)
exit(G.is_break == true);
}
-/**
- * Needed for cases when operators are re-registered
- * (when operator type pointers are stored).
- */
void WM_script_tag_reload(void)
{
UI_interface_tag_script_reload();
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c
index 2604105896d..e7ad654d3e5 100644
--- a/source/blender/windowmanager/intern/wm_jobs.c
+++ b/source/blender/windowmanager/intern/wm_jobs.c
@@ -187,12 +187,6 @@ static wmJob *wm_job_find(const wmWindowManager *wm, const void *owner, const in
/* ******************* public API ***************** */
-/**
- * \return current job or adds new job, but doesn't run it.
- *
- * \note every owner only gets a single job,
- * adding a new one will stop running job and when stopped it starts the new one.
- */
wmJob *WM_jobs_get(wmWindowManager *wm,
wmWindow *win,
const void *owner,
@@ -223,7 +217,6 @@ wmJob *WM_jobs_get(wmWindowManager *wm,
return wm_job;
}
-/* returns true if job runs, for UI (progress) indicators */
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
{
/* job can be running or about to run (suspended) */
@@ -281,7 +274,6 @@ static void wm_jobs_update_progress_bars(wmWindowManager *wm)
}
}
-/* time that job started */
double WM_jobs_starttime(const wmWindowManager *wm, const void *owner)
{
const wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
@@ -389,7 +381,6 @@ static void *do_job_thread(void *job_v)
{
wmJob *wm_job = job_v;
- BLI_thread_put_thread_on_fast_node();
wm_job->startjob(wm_job->run_customdata, &wm_job->stop, &wm_job->do_update, &wm_job->progress);
wm_job->ready = true;
@@ -447,10 +438,6 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test)
#endif
}
-/**
- * if job running, the same owner gave it a new job.
- * if different owner starts existing startjob, it suspends itself
- */
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
{
if (wm_job->running) {
@@ -550,7 +537,6 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
}
}
-/* wait until every job ended */
void WM_jobs_kill_all(wmWindowManager *wm)
{
wmJob *wm_job;
@@ -563,7 +549,6 @@ void WM_jobs_kill_all(wmWindowManager *wm)
SEQ_prefetch_stop_all();
}
-/* wait until every job ended, except for one owner (used in undo to keep screen job alive) */
void WM_jobs_kill_all_except(wmWindowManager *wm, const void *owner)
{
LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) {
@@ -584,7 +569,6 @@ void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_ty
}
}
-/* signal job(s) from this owner or callback to stop, timer is required to get handled */
void WM_jobs_stop(wmWindowManager *wm, const void *owner, void *startjob)
{
LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
@@ -596,7 +580,6 @@ void WM_jobs_stop(wmWindowManager *wm, const void *owner, void *startjob)
}
}
-/* actually terminate thread and job timer */
void WM_jobs_kill(wmWindowManager *wm,
void *owner,
void (*startjob)(void *, short int *, short int *, float *))
@@ -608,7 +591,6 @@ void WM_jobs_kill(wmWindowManager *wm,
}
}
-/* kill job entirely, also removes timer itself */
void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt)
{
LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
@@ -619,7 +601,6 @@ void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt)
}
}
-/* hardcoded to event TIMERJOBS */
void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt)
{
LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) {
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index e5aedfc7f47..0214fce59b2 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -189,7 +189,6 @@ static bool wm_keymap_item_equals(wmKeyMapItem *a, wmKeyMapItem *b)
(a->flag & KMI_REPEAT_IGNORE) == (b->flag & KMI_REPEAT_IGNORE)));
}
-/* properties can be NULL, otherwise the arg passed is used and ownership is given to the kmi */
void WM_keymap_item_properties_reset(wmKeyMapItem *kmi, struct IDProperty *properties)
{
if (LIKELY(kmi->ptr)) {
@@ -514,7 +513,6 @@ static void keymap_item_set_id(wmKeyMap *keymap, wmKeyMapItem *kmi)
}
}
-/* always add item */
wmKeyMapItem *WM_keymap_add_item(
wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
{
@@ -1150,7 +1148,6 @@ const char *WM_key_event_string(const short type, const bool compact)
return CTX_IFACE_(BLT_I18NCONTEXT_UI_EVENTS, it->name);
}
-/* TODO: also support (some) value, like e.g. double-click? */
int WM_keymap_item_raw_to_string(const short shift,
const short ctrl,
const short alt,
@@ -1162,6 +1159,8 @@ int WM_keymap_item_raw_to_string(const short shift,
char *result,
const int result_len)
{
+ /* TODO: also support (some) value, like e.g. double-click? */
+
#define ADD_SEP \
if (p != buf) { \
*p++ = ' '; \
@@ -1307,6 +1306,10 @@ char *WM_modalkeymap_operator_items_to_string_buf(wmOperatorType *ot,
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Keymap Finding Utilities
+ * \{ */
+
static wmKeyMapItem *wm_keymap_item_find_in_keymap(wmKeyMap *keymap,
const char *opname,
IDProperty *properties,
@@ -1390,22 +1393,22 @@ static wmKeyMapItem *wm_keymap_item_find_in_keymap(wmKeyMap *keymap,
}
static wmKeyMapItem *wm_keymap_item_find_handlers(const bContext *C,
+ wmWindowManager *wm,
+ wmWindow *win,
ListBase *handlers,
const char *opname,
- int UNUSED(opcontext),
+ wmOperatorCallContext UNUSED(opcontext),
IDProperty *properties,
const bool is_strict,
const struct wmKeyMapItemFind_Params *params,
wmKeyMap **r_keymap)
{
- wmWindowManager *wm = CTX_wm_manager(C);
-
/* find keymap item in handlers */
LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
wmEventHandler_KeymapResult km_result;
- WM_event_get_keymaps_from_handler(wm, handler, &km_result);
+ WM_event_get_keymaps_from_handler(wm, win, handler, &km_result);
for (int km_index = 0; km_index < km_result.keymaps_len; km_index++) {
wmKeyMap *keymap = km_result.keymaps[km_index];
if (WM_keymap_poll((bContext *)C, keymap)) {
@@ -1430,12 +1433,13 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(const bContext *C,
static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C,
const char *opname,
- int opcontext,
+ wmOperatorCallContext opcontext,
IDProperty *properties,
const bool is_strict,
const struct wmKeyMapItemFind_Params *params,
wmKeyMap **r_keymap)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
@@ -1443,17 +1447,25 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C,
/* look into multiple handler lists to find the item */
if (win) {
- found = wm_keymap_item_find_handlers(
- C, &win->modalhandlers, opname, opcontext, properties, is_strict, params, r_keymap);
+ found = wm_keymap_item_find_handlers(C,
+ wm,
+ win,
+ &win->modalhandlers,
+ opname,
+ opcontext,
+ properties,
+ is_strict,
+ params,
+ r_keymap);
if (found == NULL) {
found = wm_keymap_item_find_handlers(
- C, &win->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
+ C, wm, win, &win->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
}
}
if (area && found == NULL) {
found = wm_keymap_item_find_handlers(
- C, &area->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
+ C, wm, win, &area->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
}
if (found == NULL) {
@@ -1464,8 +1476,16 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C,
}
if (region) {
- found = wm_keymap_item_find_handlers(
- C, &region->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
+ found = wm_keymap_item_find_handlers(C,
+ wm,
+ win,
+ &region->handlers,
+ opname,
+ opcontext,
+ properties,
+ is_strict,
+ params,
+ r_keymap);
}
}
}
@@ -1475,8 +1495,16 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C,
}
if (region) {
- found = wm_keymap_item_find_handlers(
- C, &region->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
+ found = wm_keymap_item_find_handlers(C,
+ wm,
+ win,
+ &region->handlers,
+ opname,
+ opcontext,
+ properties,
+ is_strict,
+ params,
+ r_keymap);
}
}
else if (ELEM(opcontext, WM_OP_EXEC_REGION_PREVIEW, WM_OP_INVOKE_REGION_PREVIEW)) {
@@ -1485,14 +1513,30 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C,
}
if (region) {
- found = wm_keymap_item_find_handlers(
- C, &region->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
+ found = wm_keymap_item_find_handlers(C,
+ wm,
+ win,
+ &region->handlers,
+ opname,
+ opcontext,
+ properties,
+ is_strict,
+ params,
+ r_keymap);
}
}
else {
if (region) {
- found = wm_keymap_item_find_handlers(
- C, &region->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
+ found = wm_keymap_item_find_handlers(C,
+ wm,
+ win,
+ &region->handlers,
+ opname,
+ opcontext,
+ properties,
+ is_strict,
+ params,
+ r_keymap);
}
}
}
@@ -1502,7 +1546,7 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C,
static wmKeyMapItem *wm_keymap_item_find(const bContext *C,
const char *opname,
- int opcontext,
+ wmOperatorCallContext opcontext,
IDProperty *properties,
bool is_strict,
const struct wmKeyMapItemFind_Params *params,
@@ -1601,7 +1645,7 @@ static bool kmi_filter_is_visible(const wmKeyMap *UNUSED(km),
char *WM_key_event_operator_string(const bContext *C,
const char *opname,
- int opcontext,
+ wmOperatorCallContext opcontext,
IDProperty *properties,
const bool is_strict,
char *result,
@@ -1635,13 +1679,9 @@ static bool kmi_filter_is_visible_type_mask(const wmKeyMap *km,
kmi_filter_is_visible(km, kmi, user_data));
}
-/**
- * \param include_mask, exclude_mask:
- * Event types to include/exclude when looking up keys (#eEventType_Mask).
- */
wmKeyMapItem *WM_key_event_operator(const bContext *C,
const char *opname,
- int opcontext,
+ wmOperatorCallContext opcontext,
IDProperty *properties,
const short include_mask,
const short exclude_mask,
diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c
index 795f78e215f..d424eef8262 100644
--- a/source/blender/windowmanager/intern/wm_keymap_utils.c
+++ b/source/blender/windowmanager/intern/wm_keymap_utils.c
@@ -43,7 +43,6 @@
/** \name Wrappers for #WM_keymap_add_item
* \{ */
-/* menu wrapper for WM_keymap_add_item */
wmKeyMapItem *WM_keymap_add_menu(
wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
{
@@ -73,7 +72,6 @@ wmKeyMapItem *WM_keymap_add_panel(
return kmi;
}
-/* tool wrapper for WM_keymap_add_item */
wmKeyMapItem *WM_keymap_add_tool(
wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
{
@@ -83,7 +81,6 @@ wmKeyMapItem *WM_keymap_add_tool(
return kmi;
}
-/** Useful for mapping numbers to an enum. */
void WM_keymap_add_context_enum_set_items(wmKeyMap *keymap,
const EnumPropertyItem *items,
const char *data_path,
@@ -203,8 +200,6 @@ wmKeyMap *WM_keymap_guess_from_context(const bContext *C)
return km;
}
-/* Guess an appropriate keymap from the operator name */
-/* Needs to be kept up to date with Keymap and Operator naming */
wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
{
/* Op types purposely skipped for now:
diff --git a/source/blender/windowmanager/intern/wm_menu_type.c b/source/blender/windowmanager/intern/wm_menu_type.c
index bcaa2243f9f..799b6fc2e52 100644
--- a/source/blender/windowmanager/intern/wm_menu_type.c
+++ b/source/blender/windowmanager/intern/wm_menu_type.c
@@ -77,7 +77,6 @@ void WM_menutype_freelink(MenuType *mt)
UNUSED_VARS_NDEBUG(ok);
}
-/* called on initialize WM_init() */
void WM_menutype_init(void)
{
/* reserve size is set based on blender default setup */
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index 898671706d1..ebd6719d54d 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -72,7 +72,6 @@ static const EnumPropertyItem *wm_operator_properties_filesel_sort_items_itemf(
return items;
}
-/* default properties for fileselect */
void WM_operator_properties_filesel(wmOperatorType *ot,
int filter,
short type,
@@ -185,6 +184,9 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
prop = RNA_def_boolean(
ot->srna, "filter_usd", (filter & FILE_TYPE_USD) != 0, "Filter USD files", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(
+ ot->srna, "filter_obj", (filter & FILE_TYPE_OBJECT_IO) != 0, "Filter OBJ files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"filter_volume",
(filter & FILE_TYPE_VOLUME) != 0,
@@ -262,9 +264,6 @@ void WM_operator_properties_select_action(wmOperatorType *ot, int default_action
wm_operator_properties_select_action_ex(ot, default_action, select_actions, hide_gui);
}
-/**
- * only SELECT/DESELECT
- */
void WM_operator_properties_select_action_simple(wmOperatorType *ot,
int default_action,
bool hide_gui)
@@ -278,10 +277,6 @@ void WM_operator_properties_select_action_simple(wmOperatorType *ot,
wm_operator_properties_select_action_ex(ot, default_action, select_actions, hide_gui);
}
-/**
- * Use for all select random operators.
- * Adds properties: percent, seed, action.
- */
void WM_operator_properties_select_random(wmOperatorType *ot)
{
RNA_def_float_factor(ot->srna,
@@ -357,9 +352,6 @@ void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect)
BLI_rctf_rcti_copy(rect, &rect_i);
}
-/**
- * Use with #WM_gesture_box_invoke
- */
void WM_operator_properties_gesture_box_ex(wmOperatorType *ot, bool deselect, bool extend)
{
PropertyRNA *prop;
@@ -381,10 +373,6 @@ void WM_operator_properties_gesture_box_ex(wmOperatorType *ot, bool deselect, bo
}
}
-/**
- * Disable using cursor position,
- * use when view operators are initialized from buttons.
- */
void WM_operator_properties_use_cursor_init(wmOperatorType *ot)
{
PropertyRNA *prop = RNA_def_boolean(ot->srna,
@@ -418,7 +406,6 @@ void WM_operator_properties_select_operation(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* Some tools don't support XOR/AND. */
void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
{
static const EnumPropertyItem select_mode_items[] = {
@@ -450,31 +437,6 @@ void WM_operator_properties_select_walk_direction(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/**
- * Selecting and tweaking items are overlapping operations. Getting both to work without conflicts
- * requires special care. See
- * https://wiki.blender.org/wiki/Human_Interface_Guidelines/Selection#Select-tweaking for the
- * desired behavior.
- *
- * For default click selection (with no modifier keys held), the select operators can do the
- * following:
- * - On a mouse press on an unselected item, change selection and finish immediately after.
- * This sends an undo push and allows transform to take over should a tweak event be caught now.
- * - On a mouse press on a selected item, don't change selection state, but start modal execution
- * of the operator. Idea is that we wait with deselecting other items until we know that the
- * intention wasn't to tweak (mouse press+drag) all selected items.
- * - If a tweak is recognized before the release event happens, cancel the operator, so that
- * transform can take over and no undo-push is sent.
- * - If the release event occurs rather than a tweak one, deselect all items but the one under the
- * cursor, and finish the modal operator.
- *
- * This utility, together with #WM_generic_select_invoke() and #WM_generic_select_modal() should
- * help getting the wanted behavior to work. Most generic logic should be handled in these, so that
- * the select operators only have to care for the case dependent handling.
- *
- * Every select operator has slightly different requirements, e.g. sequencer strip selection
- * also needs to account for handle selection. This should be the baseline behavior though.
- */
void WM_operator_properties_generic_select(wmOperatorType *ot)
{
/* On the initial mouse press, this is set by #WM_generic_select_modal() to let the select
@@ -499,9 +461,6 @@ void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/**
- * Use with #WM_gesture_lasso_invoke
- */
void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -509,9 +468,6 @@ void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/**
- * Use with #WM_gesture_straightline_invoke
- */
void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
{
PropertyRNA *prop;
@@ -541,9 +497,6 @@ void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
}
}
-/**
- * Use with #WM_gesture_circle_invoke
- */
void WM_operator_properties_gesture_circle(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -582,9 +535,6 @@ void WM_operator_properties_mouse_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/**
- * \param nth_can_disable: Enable if we want to be able to select no interval at all.
- */
void WM_operator_properties_checker_interval(wmOperatorType *ot, bool nth_can_disable)
{
const int nth_default = nth_can_disable ? 0 : 1;
diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c
index 39435721d1a..0f6096e7b8b 100644
--- a/source/blender/windowmanager/intern/wm_operator_type.c
+++ b/source/blender/windowmanager/intern/wm_operator_type.c
@@ -89,7 +89,6 @@ wmOperatorType *WM_operatortype_find(const char *idname, bool quiet)
return NULL;
}
-/* caller must free */
void WM_operatortype_iter(GHashIterator *ghi)
{
BLI_ghashIterator_init(ghi, global_ops_hash);
@@ -110,6 +109,7 @@ static wmOperatorType *wm_operatortype_append__begin(void)
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
+ ot->cursor_pending = WM_CURSOR_PICK_AREA;
return ot;
}
@@ -131,7 +131,8 @@ static void wm_operatortype_append__end(wmOperatorType *ot)
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
}
-/* all ops in 1 list (for time being... needs evaluation later) */
+/* All ops in 1 list (for time being... needs evaluation later). */
+
void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
{
wmOperatorType *ot = wm_operatortype_append__begin();
@@ -148,7 +149,6 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *
/** \} */
-/* called on initialize WM_exit() */
void WM_operatortype_remove_ptr(wmOperatorType *ot)
{
BLI_assert(ot == WM_operatortype_find(ot->idname, false));
@@ -183,7 +183,6 @@ bool WM_operatortype_remove(const char *idname)
return true;
}
-/* called on initialize WM_init() */
void wm_operatortype_init(void)
{
/* reserve size is set based on blender default setup */
@@ -214,18 +213,6 @@ void wm_operatortype_free(void)
global_ops_hash = NULL;
}
-/**
- * Tag all operator-properties of \a ot defined after calling this, until
- * the next #WM_operatortype_props_advanced_end call (if available), with
- * #OP_PROP_TAG_ADVANCED. Previously defined ones properties not touched.
- *
- * Calling this multiple times without a call to #WM_operatortype_props_advanced_end,
- * all calls after the first one are ignored. Meaning all proprieties defined after the
- * first call are tagged as advanced.
- *
- * This doesn't do the actual tagging, #WM_operatortype_props_advanced_end does which is
- * called for all operators during registration (see #wm_operatortype_append__end).
- */
void WM_operatortype_props_advanced_begin(wmOperatorType *ot)
{
if (ot_prop_basic_count == -1) {
@@ -234,14 +221,6 @@ void WM_operatortype_props_advanced_begin(wmOperatorType *ot)
}
}
-/**
- * Tags all operator-properties of \a ot defined since the first
- * #WM_operatortype_props_advanced_begin call,
- * or the last #WM_operatortype_props_advanced_end call, with #OP_PROP_TAG_ADVANCED.
- *
- * \note This is called for all operators during registration (see #wm_operatortype_append__end).
- * So it does not need to be explicitly called in operator-type definition.
- */
void WM_operatortype_props_advanced_end(wmOperatorType *ot)
{
PointerRNA struct_ptr;
@@ -265,9 +244,6 @@ void WM_operatortype_props_advanced_end(wmOperatorType *ot)
ot_prop_basic_count = -1;
}
-/**
- * Remove memory of all previously executed tools.
- */
void WM_operatortype_last_properties_clear_all(void)
{
GHashIterator iter;
@@ -470,7 +446,6 @@ static void wm_macro_cancel(bContext *C, wmOperator *op)
wm_macro_end(op, OPERATOR_CANCELLED);
}
-/* Names have to be static for now */
wmOperatorType *WM_operatortype_append_macro(const char *idname,
const char *name,
const char *description,
@@ -612,9 +587,6 @@ char *WM_operatortype_description(struct bContext *C,
return NULL;
}
-/**
- * Use when we want a label, preferring the description.
- */
char *WM_operatortype_description_or_name(struct bContext *C,
struct wmOperatorType *ot,
struct PointerRNA *properties)
diff --git a/source/blender/windowmanager/intern/wm_operator_utils.c b/source/blender/windowmanager/intern/wm_operator_utils.c
index 85a0a28de79..dbcfd814692 100644
--- a/source/blender/windowmanager/intern/wm_operator_utils.c
+++ b/source/blender/windowmanager/intern/wm_operator_utils.c
@@ -44,9 +44,6 @@
/** \name Generic Utilities
* \{ */
-/**
- * Only finish + pass through for press events (allowing press-tweak).
- */
int WM_operator_flag_only_pass_through_on_press(int retval, const struct wmEvent *event)
{
if ((event->val != KM_PRESS) &&
@@ -337,10 +334,6 @@ static int op_generic_value_modal(bContext *C, wmOperator *op, const wmEvent *ev
return OPERATOR_RUNNING_MODAL;
}
-/**
- * Allow an operator with only and execute function to run modally,
- * re-doing the action, using vertex coordinate store/restore instead of operator undo.
- */
void WM_operator_type_modal_from_exec_for_object_edit_coords(wmOperatorType *ot)
{
PropertyRNA *prop;
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 81dcc5ccea0..6c9b0af5186 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -116,13 +116,10 @@
#define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)")
-/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Operator API
* \{ */
-/* SOME_OT_op -> some.op */
void WM_operator_py_idname(char *to, const char *from)
{
const char *sep = strstr(from, "_OT_");
@@ -143,7 +140,6 @@ void WM_operator_py_idname(char *to, const char *from)
}
}
-/* some.op -> SOME_OT_op */
void WM_operator_bl_idname(char *to, const char *from)
{
if (from) {
@@ -167,10 +163,6 @@ void WM_operator_bl_idname(char *to, const char *from)
}
}
-/**
- * Sanity check to ensure #WM_operator_bl_idname won't fail.
- * \returns true when there are no problems with \a idname, otherwise report an error.
- */
bool WM_operator_py_idname_ok_or_report(ReportList *reports,
const char *classname,
const char *idname)
@@ -219,15 +211,6 @@ bool WM_operator_py_idname_ok_or_report(ReportList *reports,
return true;
}
-/**
- * Print a string representation of the operator,
- * with the args that it runs so python can run it again.
- *
- * When calling from an existing wmOperator, better to use simple version:
- * `WM_operator_pystring(C, op);`
- *
- * \note Both \a op and \a opptr may be `NULL` (\a op is only used for macro operators).
- */
char *WM_operator_pystring_ex(bContext *C,
wmOperator *op,
const bool all_args,
@@ -308,9 +291,6 @@ char *WM_operator_pystring(bContext *C, wmOperator *op, const bool all_args, con
return WM_operator_pystring_ex(C, op, all_args, macro_args, op->type, op->ptr);
}
-/**
- * \return true if the string was shortened
- */
bool WM_operator_pystring_abbreviate(char *str, int str_len_max)
{
const int str_len = strlen(str);
@@ -423,7 +403,9 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr
* `object.data.bones["Bones"].use_deform` such paths are not useful for key-shortcuts,
* so this function supports returning data-paths directly to context members that aren't ID types.
*/
-static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr, bool *r_is_id)
+static const char *wm_context_member_from_ptr(const bContext *C,
+ const PointerRNA *ptr,
+ bool *r_is_id)
{
const char *member_id = NULL;
bool is_id = false;
@@ -541,50 +523,52 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr
case ID_SCR: {
CTX_TEST_PTR_ID(C, "screen", ptr->owner_id);
- SpaceLink *space_data = CTX_wm_space_data(C);
-
- TEST_PTR_DATA_TYPE("space_data", RNA_Space, ptr, space_data);
TEST_PTR_DATA_TYPE("area", RNA_Area, ptr, CTX_wm_area(C));
TEST_PTR_DATA_TYPE("region", RNA_Region, ptr, CTX_wm_region(C));
- switch (space_data->spacetype) {
- case SPACE_VIEW3D: {
- const View3D *v3d = (View3D *)space_data;
- const View3DShading *shading = &v3d->shading;
+ SpaceLink *space_data = CTX_wm_space_data(C);
+ if (space_data != NULL) {
+ TEST_PTR_DATA_TYPE("space_data", RNA_Space, ptr, space_data);
- TEST_PTR_DATA_TYPE("space_data.overlay", RNA_View3DOverlay, ptr, v3d);
- TEST_PTR_DATA_TYPE("space_data.shading", RNA_View3DShading, ptr, shading);
- break;
- }
- case SPACE_GRAPH: {
- const SpaceGraph *sipo = (SpaceGraph *)space_data;
- const bDopeSheet *ads = sipo->ads;
- TEST_PTR_DATA_TYPE("space_data.dopesheet", RNA_DopeSheet, ptr, ads);
- break;
- }
- case SPACE_FILE: {
- const SpaceFile *sfile = (SpaceFile *)space_data;
- const FileSelectParams *params = ED_fileselect_get_active_params(sfile);
- TEST_PTR_DATA_TYPE("space_data.params", RNA_FileSelectParams, ptr, params);
- break;
- }
- case SPACE_IMAGE: {
- const SpaceImage *sima = (SpaceImage *)space_data;
- TEST_PTR_DATA_TYPE("space_data.overlay", RNA_SpaceImageOverlay, ptr, sima);
- TEST_PTR_DATA_TYPE("space_data.uv_editor", RNA_SpaceUVEditor, ptr, sima);
- break;
- }
- case SPACE_NLA: {
- const SpaceNla *snla = (SpaceNla *)space_data;
- const bDopeSheet *ads = snla->ads;
- TEST_PTR_DATA_TYPE("space_data.dopesheet", RNA_DopeSheet, ptr, ads);
- break;
- }
- case SPACE_ACTION: {
- const SpaceAction *sact = (SpaceAction *)space_data;
- const bDopeSheet *ads = &sact->ads;
- TEST_PTR_DATA_TYPE("space_data.dopesheet", RNA_DopeSheet, ptr, ads);
- break;
+ switch (space_data->spacetype) {
+ case SPACE_VIEW3D: {
+ const View3D *v3d = (View3D *)space_data;
+ const View3DShading *shading = &v3d->shading;
+
+ TEST_PTR_DATA_TYPE("space_data.overlay", RNA_View3DOverlay, ptr, v3d);
+ TEST_PTR_DATA_TYPE("space_data.shading", RNA_View3DShading, ptr, shading);
+ break;
+ }
+ case SPACE_GRAPH: {
+ const SpaceGraph *sipo = (SpaceGraph *)space_data;
+ const bDopeSheet *ads = sipo->ads;
+ TEST_PTR_DATA_TYPE("space_data.dopesheet", RNA_DopeSheet, ptr, ads);
+ break;
+ }
+ case SPACE_FILE: {
+ const SpaceFile *sfile = (SpaceFile *)space_data;
+ const FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+ TEST_PTR_DATA_TYPE("space_data.params", RNA_FileSelectParams, ptr, params);
+ break;
+ }
+ case SPACE_IMAGE: {
+ const SpaceImage *sima = (SpaceImage *)space_data;
+ TEST_PTR_DATA_TYPE("space_data.overlay", RNA_SpaceImageOverlay, ptr, sima);
+ TEST_PTR_DATA_TYPE("space_data.uv_editor", RNA_SpaceUVEditor, ptr, sima);
+ break;
+ }
+ case SPACE_NLA: {
+ const SpaceNla *snla = (SpaceNla *)space_data;
+ const bDopeSheet *ads = snla->ads;
+ TEST_PTR_DATA_TYPE("space_data.dopesheet", RNA_DopeSheet, ptr, ads);
+ break;
+ }
+ case SPACE_ACTION: {
+ const SpaceAction *sact = (SpaceAction *)space_data;
+ const bDopeSheet *ads = &sact->ads;
+ TEST_PTR_DATA_TYPE("space_data.dopesheet", RNA_DopeSheet, ptr, ads);
+ break;
+ }
}
}
@@ -604,10 +588,7 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr
}
#endif
-/**
- * Calculate the path to `ptr` from context `C`, or return NULL if it can't be calculated.
- */
-char *WM_context_path_resolve_property_full(bContext *C,
+char *WM_context_path_resolve_property_full(const bContext *C,
const PointerRNA *ptr,
PropertyRNA *prop,
int index)
@@ -707,8 +688,6 @@ void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
}
}
-/* similar to the function above except its uses ID properties
- * used for keymaps and macros */
void WM_operator_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *opstring)
{
IDProperty *tmp_properties = NULL;
@@ -759,14 +738,6 @@ void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
RNA_STRUCT_END;
}
-/**
- * Set all props to their default.
- *
- * \param do_update: Only update un-initialized props.
- *
- * \note There's nothing specific to operators here.
- * This could be made a general function.
- */
bool WM_operator_properties_default(PointerRNA *ptr, const bool do_update)
{
bool changed = false;
@@ -794,7 +765,6 @@ bool WM_operator_properties_default(PointerRNA *ptr, const bool do_update)
return changed;
}
-/* remove all props without PROP_SKIP_SAVE */
void WM_operator_properties_reset(wmOperator *op)
{
if (op->ptr->data) {
@@ -941,13 +911,6 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
/** \name Default Operator Callbacks
* \{ */
-/**
- * Helper to get select and tweak-transform to work conflict free and as desired. See
- * #WM_operator_properties_generic_select() for details.
- *
- * To be used together with #WM_generic_select_invoke() and
- * #WM_operator_properties_generic_select().
- */
int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
PropertyRNA *wait_to_deselect_prop = RNA_struct_find_property(op->ptr,
@@ -1008,13 +971,6 @@ int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
}
-/**
- * Helper to get select and tweak-transform to work conflict free and as desired. See
- * #WM_operator_properties_generic_select() for details.
- *
- * To be used together with #WM_generic_select_modal() and
- * #WM_operator_properties_generic_select().
- */
int WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
RNA_int_set(op->ptr, "mouse_x", event->mval[0]);
@@ -1059,8 +1015,7 @@ int WM_operator_smooth_viewtx_get(const wmOperator *op)
return (op->flag & OP_IS_INVOKE) ? U.smooth_viewtx : 0;
}
-/* invoke callback, uses enum property named "type" */
-int WM_menu_invoke_ex(bContext *C, wmOperator *op, int opcontext)
+int WM_menu_invoke_ex(bContext *C, wmOperator *op, wmOperatorCallContext opcontext)
{
PropertyRNA *prop = op->type->prop;
@@ -1180,10 +1135,6 @@ static uiBlock *wm_enum_search_menu(bContext *C, ARegion *region, void *arg)
return block;
}
-/**
- * Similar to #WM_enum_search_invoke, but draws previews. Also, this can't
- * be used as invoke callback directly since it needs additional info.
- */
int WM_enum_search_invoke_previews(bContext *C, wmOperator *op, short prv_cols, short prv_rows)
{
static struct EnumSearchMenu search_menu;
@@ -1206,13 +1157,12 @@ int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(eve
return OPERATOR_INTERFACE;
}
-/* Can't be used as an invoke directly, needs message arg (can be NULL) */
int WM_operator_confirm_message_ex(bContext *C,
wmOperator *op,
const char *title,
const int icon,
const char *message,
- const short opcontext)
+ const wmOperatorCallContext opcontext)
{
IDProperty *properties = op->ptr->data;
@@ -1251,7 +1201,6 @@ int WM_operator_confirm_or_exec(bContext *C, wmOperator *op, const wmEvent *UNUS
return op->type->exec(C, op);
}
-/* op->invoke, opens fileselect if path property not set, otherwise executes */
int WM_operator_filesel(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
@@ -1276,7 +1225,6 @@ bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFor
return false;
}
-/* op->poll */
bool WM_operator_winactive(bContext *C)
{
if (CTX_wm_window(C) == NULL) {
@@ -1285,7 +1233,6 @@ bool WM_operator_winactive(bContext *C)
return 1;
}
-/* return false, if the UI should be disabled */
bool WM_operator_check_ui_enabled(const bContext *C, const char *idname)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1323,9 +1270,6 @@ void WM_operator_last_properties_ensure(wmOperatorType *ot, PointerRNA *ptr)
RNA_pointer_create(G_MAIN->wm.first, ot->srna, props, ptr);
}
-/**
- * Use for drag & drop a path or name with operators invoke() function.
- */
ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short idcode)
{
Main *bmain = CTX_data_main(C);
@@ -1629,20 +1573,11 @@ static int wm_operator_props_popup_ex(bContext *C,
return OPERATOR_RUNNING_MODAL;
}
-/**
- * Same as #WM_operator_props_popup but don't use operator redo.
- * just wraps #WM_operator_props_dialog_popup.
- */
int WM_operator_props_popup_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return wm_operator_props_popup_ex(C, op, false, false);
}
-/**
- * Same as #WM_operator_props_popup but call the operator first,
- * This way - the button values correspond to the result of the operator.
- * Without this, first access to a button will make the result jump, see T32452.
- */
int WM_operator_props_popup_call(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return wm_operator_props_popup_ex(C, op, true, true);
@@ -2270,11 +2205,8 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e
float d[2] = {0, 0};
float zoom[2] = {1, 1};
- rc->initial_mouse[0] = event->x;
- rc->initial_mouse[1] = event->y;
-
- rc->initial_co[0] = event->x;
- rc->initial_co[1] = event->y;
+ copy_v2_v2_int(rc->initial_mouse, event->xy);
+ copy_v2_v2_int(rc->initial_co, event->xy);
switch (rc->subtype) {
case PROP_NONE:
@@ -2950,14 +2882,12 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
if (!has_numInput) {
if (rc->slow_mode) {
if (rc->subtype == PROP_ANGLE) {
- const float position[2] = {event->x, event->y};
-
/* calculate the initial angle here first */
delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0];
delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1];
/* precision angle gets calculated from dial and gets added later */
- angle_precision = -0.1f * BLI_dial_angle(rc->dial, position);
+ angle_precision = -0.1f * BLI_dial_angle(rc->dial, (float[2]){UNPACK2(event->xy)});
}
else {
delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0];
@@ -2970,7 +2900,7 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
dist = len_v2(delta);
- delta[0] = event->x - rc->slow_mouse[0];
+ delta[0] = event->xy[0] - rc->slow_mouse[0];
if (rc->zoom_prop) {
delta[0] /= zoom[0];
@@ -2980,8 +2910,8 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
}
}
else {
- delta[0] = rc->initial_mouse[0] - event->x;
- delta[1] = rc->initial_mouse[1] - event->y;
+ delta[0] = (float)(rc->initial_mouse[0] - event->xy[0]);
+ delta[1] = (float)(rc->initial_mouse[1] - event->xy[1]);
if (rc->zoom_prop) {
RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom);
delta[0] /= zoom[0];
@@ -3048,8 +2978,8 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
case EVT_LEFTSHIFTKEY:
case EVT_RIGHTSHIFTKEY: {
if (event->val == KM_PRESS) {
- rc->slow_mouse[0] = event->x;
- rc->slow_mouse[1] = event->y;
+ rc->slow_mouse[0] = event->xy[0];
+ rc->slow_mouse[1] = event->xy[1];
rc->slow_mode = true;
if (rc->subtype == PROP_ANGLE) {
const float initial_position[2] = {UNPACK2(rc->initial_mouse)};
@@ -3760,87 +3690,6 @@ static void WM_OT_stereo3d_set(wmOperatorType *ot)
/** \} */
-#ifdef WITH_XR_OPENXR
-
-static void wm_xr_session_update_screen(Main *bmain, const wmXrData *xr_data)
-{
- const bool session_exists = WM_xr_session_exists(xr_data);
-
- for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- LISTBASE_FOREACH (SpaceLink *, slink, &area->spacedata) {
- if (slink->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *)slink;
-
- if (v3d->flag & V3D_XR_SESSION_MIRROR) {
- ED_view3d_xr_mirror_update(area, v3d, session_exists);
- }
-
- if (session_exists) {
- wmWindowManager *wm = bmain->wm.first;
- const Scene *scene = WM_windows_scene_get_from_screen(wm, screen);
-
- ED_view3d_xr_shading_update(wm, v3d, scene);
- }
- /* Ensure no 3D View is tagged as session root. */
- else {
- v3d->runtime.flag &= ~V3D_RUNTIME_XR_SESSION_ROOT;
- }
- }
- }
- }
- }
-
- WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
-}
-
-static void wm_xr_session_update_screen_on_exit_cb(const wmXrData *xr_data)
-{
- /* Just use G_MAIN here, storing main isn't reliable enough on file read or exit. */
- wm_xr_session_update_screen(G_MAIN, xr_data);
-}
-
-static int wm_xr_session_toggle_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win = CTX_wm_window(C);
- View3D *v3d = CTX_wm_view3d(C);
-
- /* Lazy-create xr context - tries to dynlink to the runtime, reading active_runtime.json. */
- if (wm_xr_init(wm) == false) {
- return OPERATOR_CANCELLED;
- }
-
- v3d->runtime.flag |= V3D_RUNTIME_XR_SESSION_ROOT;
- wm_xr_session_toggle(wm, win, wm_xr_session_update_screen_on_exit_cb);
- wm_xr_session_update_screen(bmain, &wm->xr);
-
- WM_event_add_notifier(C, NC_WM | ND_XR_DATA_CHANGED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static void WM_OT_xr_session_toggle(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Toggle VR Session";
- ot->idname = "WM_OT_xr_session_toggle";
- ot->description =
- "Open a view for use with virtual reality headsets, or close it if already "
- "opened";
-
- /* callbacks */
- ot->exec = wm_xr_session_toggle_exec;
- ot->poll = ED_operator_view3d_active;
-
- /* XXX INTERNAL just to hide it from the search menu by default, an Add-on will expose it in the
- * UI instead. Not meant as a permanent solution. */
- ot->flag = OPTYPE_INTERNAL;
-}
-
-#endif /* WITH_XR_OPENXR */
-
/* -------------------------------------------------------------------- */
/** \name Operator Registration & Keymaps
* \{ */
@@ -3882,9 +3731,6 @@ void wm_operatortypes_register(void)
WM_operatortype_append(WM_OT_call_panel);
WM_operatortype_append(WM_OT_radial_control);
WM_operatortype_append(WM_OT_stereo3d_set);
-#ifdef WITH_XR_OPENXR
- WM_operatortype_append(WM_OT_xr_session_toggle);
-#endif
#if defined(WIN32)
WM_operatortype_append(WM_OT_console_toggle);
#endif
@@ -3892,6 +3738,10 @@ void wm_operatortypes_register(void)
WM_operatortype_append(WM_OT_previews_clear);
WM_operatortype_append(WM_OT_doc_view_manual_ui_context);
+#ifdef WITH_XR_OPENXR
+ wm_xr_operatortypes_register();
+#endif
+
/* gizmos */
WM_operatortype_append(GIZMOGROUP_OT_gizmo_select);
WM_operatortype_append(GIZMOGROUP_OT_gizmo_tweak);
@@ -4080,7 +3930,6 @@ static void gesture_zoom_border_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "IMAGE_OT_view_zoom_border");
}
-/* default keymap for windows and screens, only call once per WM */
void wm_window_keymap(wmKeyConfig *keyconf)
{
WM_keymap_ensure(keyconf, "Window", 0, 0);
@@ -4148,7 +3997,8 @@ static const EnumPropertyItem *rna_id_itemf(bool *r_free,
return item;
}
-/* can add more as needed */
+/* Can add more ID types as needed. */
+
const EnumPropertyItem *RNA_action_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
diff --git a/source/blender/windowmanager/intern/wm_panel_type.c b/source/blender/windowmanager/intern/wm_panel_type.c
index 24508c377a6..609bb55e075 100644
--- a/source/blender/windowmanager/intern/wm_panel_type.c
+++ b/source/blender/windowmanager/intern/wm_panel_type.c
@@ -69,7 +69,6 @@ void WM_paneltype_remove(PanelType *pt)
UNUSED_VARS_NDEBUG(ok);
}
-/* called on initialize WM_init() */
void WM_paneltype_init(void)
{
/* reserve size is set based on blender default setup */
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index fa21dbcb4bb..640fef82085 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -1570,7 +1570,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
/* initialize the font */
BLF_init();
ps.fontid = BLF_load_mono_default(false);
- BLF_size(ps.fontid, 11, 72);
+ BLF_size(ps.fontid, 11.0f, 72);
ps.ibufx = ibuf->x;
ps.ibufy = ibuf->y;
@@ -1845,7 +1845,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
}
IMB_exit();
- BKE_images_exit();
DEG_free_node_types();
totblock = MEM_get_memory_blocks_in_use();
diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c
index 99c6bc39207..7513e4d31cc 100644
--- a/source/blender/windowmanager/intern/wm_splash_screen.c
+++ b/source/blender/windowmanager/intern/wm_splash_screen.c
@@ -212,8 +212,10 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *UNUSE
UI_but_func_set(but, wm_block_close, block, NULL);
- wm_block_splash_add_label(
- block, BKE_blender_version_string(), splash_width, splash_height - 13.0 * U.dpi_fac);
+ wm_block_splash_add_label(block,
+ BKE_blender_version_string(),
+ splash_width - 8.0 * U.dpi_fac,
+ splash_height - 13.0 * U.dpi_fac);
const int layout_margin_x = U.dpi_fac * 26;
uiLayout *layout = UI_block_layout(block,
@@ -323,7 +325,7 @@ static uiBlock *wm_block_create_about(bContext *C, ARegion *region, void *UNUSED
uiLayout *col = uiLayoutColumn(layout, true);
- uiItemL_ex(col, N_("Blender"), ICON_NONE, true, false);
+ uiItemL_ex(col, IFACE_("Blender"), ICON_NONE, true, false);
MenuType *mt = WM_menutype_find("WM_MT_splash_about", true);
if (mt) {
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index a7cdc0602bc..a62ced1a4bf 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -177,11 +177,7 @@ bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
return true;
}
-/**
- * If needed, adjust \a r_mouse_xy
- * so that drawn cursor and handled mouse position are matching visually.
- */
-void wm_stereo3d_mouse_offset_apply(wmWindow *win, int *r_mouse_xy)
+void wm_stereo3d_mouse_offset_apply(wmWindow *win, int r_mouse_xy[2])
{
if (!WM_stereo3d_enabled(win, false)) {
return;
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 0cb76404258..524580ac88f 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -116,7 +116,6 @@ static void wmOrtho2_offset(const float x, const float y, const float ofs)
wmOrtho2(ofs, x + ofs, ofs, y + ofs);
}
-/* Default pixel alignment for regions. */
void wmOrtho2_region_pixelspace(const ARegion *region)
{
wmOrtho2_offset(region->winx, region->winy, -0.01f);
diff --git a/source/blender/windowmanager/intern/wm_surface.c b/source/blender/windowmanager/intern/wm_surface.c
index 715f72d70cf..385b55f36f9 100644
--- a/source/blender/windowmanager/intern/wm_surface.c
+++ b/source/blender/windowmanager/intern/wm_surface.c
@@ -45,11 +45,24 @@ static wmSurface *g_drawable = NULL;
void wm_surfaces_iter(bContext *C, void (*cb)(bContext *C, wmSurface *))
{
- LISTBASE_FOREACH (wmSurface *, surf, &global_surface_list) {
+ /* Mutable iterator in case a surface is freed. */
+ LISTBASE_FOREACH_MUTABLE (wmSurface *, surf, &global_surface_list) {
cb(C, surf);
}
}
+static void wm_surface_do_depsgraph_fn(bContext *C, wmSurface *surface)
+{
+ if (surface->do_depsgraph) {
+ surface->do_depsgraph(C);
+ }
+}
+
+void wm_surfaces_do_depsgraph(bContext *C)
+{
+ wm_surfaces_iter(C, wm_surface_do_depsgraph_fn);
+}
+
void wm_surface_clear_drawable(void)
{
if (g_drawable) {
@@ -107,6 +120,9 @@ void wm_surface_add(wmSurface *surface)
void wm_surface_remove(wmSurface *surface)
{
+ if (surface == g_drawable) {
+ wm_surface_clear_drawable();
+ }
BLI_remlink(&global_surface_list, surface);
surface->free_data(surface);
MEM_freeN(surface);
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
index 0c24520d565..7b8feac45b4 100644
--- a/source/blender/windowmanager/intern/wm_toolsystem.c
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -251,7 +251,6 @@ void WM_toolsystem_reinit(bContext *C, WorkSpace *workspace, const bToolKey *tke
}
}
-/* Operate on all active tools. */
void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace)
{
LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
@@ -362,12 +361,6 @@ void WM_toolsystem_ref_set_from_runtime(struct bContext *C,
}
}
-/**
- * Sync the internal active state of a tool back into the tool system,
- * this is needed for active brushes where the real active state is not stored in the tool system.
- *
- * \see #toolsystem_ref_link
- */
void WM_toolsystem_ref_sync_from_context(Main *bmain, WorkSpace *workspace, bToolRef *tref)
{
bToolRef_Runtime *tref_rt = tref->runtime;
@@ -505,14 +498,6 @@ bool WM_toolsystem_key_from_context(ViewLayer *view_layer, ScrArea *area, bToolK
return false;
}
-/**
- * Use to update the active tool (shown in the top bar) in the least disruptive way.
- *
- * This is a little involved since there may be multiple valid active tools
- * depending on the mode and space type.
- *
- * Used when undoing since the active mode may have changed.
- */
void WM_toolsystem_refresh_active(bContext *C)
{
Main *bmain = CTX_data_main(C);
@@ -572,25 +557,29 @@ void WM_toolsystem_refresh_screen_area(WorkSpace *workspace, ViewLayer *view_lay
}
}
+void WM_toolsystem_refresh_screen_window(wmWindow *win)
+{
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ bool space_type_has_tools[SPACE_TYPE_LAST + 1] = {0};
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
+ space_type_has_tools[tref->space_type] = true;
+ }
+ bScreen *screen = WM_window_get_active_screen(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ area->runtime.tool = NULL;
+ area->runtime.is_tool_set = true;
+ if (space_type_has_tools[area->spacetype]) {
+ WM_toolsystem_refresh_screen_area(workspace, view_layer, area);
+ }
+ }
+}
+
void WM_toolsystem_refresh_screen_all(Main *bmain)
{
/* Update all ScrArea's tools */
for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
- WorkSpace *workspace = WM_window_get_active_workspace(win);
- bool space_type_has_tools[SPACE_TYPE_LAST + 1] = {0};
- LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
- space_type_has_tools[tref->space_type] = true;
- }
- bScreen *screen = WM_window_get_active_screen(win);
- ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- area->runtime.tool = NULL;
- area->runtime.is_tool_set = true;
- if (space_type_has_tools[area->spacetype]) {
- WM_toolsystem_refresh_screen_area(workspace, view_layer, area);
- }
- }
}
}
}
@@ -796,16 +785,12 @@ void WM_toolsystem_update_from_context(bContext *C,
}
}
-/**
- * For paint modes to support non-brush tools.
- */
bool WM_toolsystem_active_tool_is_brush(const bContext *C)
{
bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
return tref_rt && (tref_rt->data_block[0] != '\0');
}
-/* Follow wmMsgNotifyFn spec */
void WM_toolsystem_do_msg_notify_tag_refresh(bContext *C,
wmMsgSubscribeKey *UNUSED(msg_key),
wmMsgSubscribeValue *msg_val)
diff --git a/source/blender/windowmanager/intern/wm_tooltip.c b/source/blender/windowmanager/intern/wm_tooltip.c
index a9f0e01cfb5..3bcd122f08d 100644
--- a/source/blender/windowmanager/intern/wm_tooltip.c
+++ b/source/blender/windowmanager/intern/wm_tooltip.c
@@ -131,7 +131,7 @@ void WM_tooltip_init(bContext *C, wmWindow *win)
CTX_wm_region_set(C, region_prev);
}
- copy_v2_v2_int(screen->tool_tip->event_xy, &win->eventstate->x);
+ copy_v2_v2_int(screen->tool_tip->event_xy, win->eventstate->xy);
if (pass_prev != screen->tool_tip->pass) {
/* The pass changed, add timer for next pass. */
wmWindowManager *wm = CTX_wm_manager(C);
diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c
index 82ba4aa6e6f..a2ae42d5ead 100644
--- a/source/blender/windowmanager/intern/wm_uilist_type.c
+++ b/source/blender/windowmanager/intern/wm_uilist_type.c
@@ -131,7 +131,6 @@ void WM_uilisttype_remove_ptr(Main *bmain, uiListType *ult)
UNUSED_VARS_NDEBUG(ok);
}
-/* called on initialize WM_init() */
void WM_uilisttype_init(void)
{
uilisttypes_hash = BLI_ghash_str_new_ex("uilisttypes_hash gh", 16);
@@ -151,16 +150,6 @@ void WM_uilisttype_free(void)
uilisttypes_hash = NULL;
}
-/**
- * The "full" list-ID is an internal name used for storing and identifying a list. It is built like
- * this:
- * "{uiListType.idname}_{list_id}", whereby "list_id" is an optional parameter passed to
- * `UILayout.template_list()`. If it is not set, the full list-ID is just "{uiListType.idname}_".
- *
- * Note that whenever the Python API refers to the list-ID, it's the short, "non-full" one it
- * passed to `UILayout.template_list()`. C code can query that through
- * #WM_uilisttype_list_id_get().
- */
void WM_uilisttype_to_full_list_id(const uiListType *ult,
const char *list_id,
char r_full_list_id[/*UI_MAX_NAME_STR*/])
@@ -169,11 +158,6 @@ void WM_uilisttype_to_full_list_id(const uiListType *ult,
BLI_snprintf(r_full_list_id, UI_MAX_NAME_STR, "%s_%s", ult->idname, list_id ? list_id : "");
}
-/**
- * Get the "non-full" list-ID, see #WM_uilisttype_to_full_list_id() for details.
- *
- * \note Assumes `uiList.list_id` was set using #WM_uilisttype_to_full_list_id()!
- */
const char *WM_uilisttype_list_id_get(const uiListType *ult, uiList *list)
{
/* Some sanity check for the assumed behavior of #WM_uilisttype_to_full_list_id(). */
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 8baf4a0e013..a1854a8ed86 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -49,6 +49,7 @@
#include "BKE_icons.h"
#include "BKE_layer.h"
#include "BKE_main.h"
+#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
@@ -135,8 +136,6 @@ static struct WMInitStruct {
static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate);
static bool wm_window_timer(const bContext *C);
-/* XXX this one should correctly check for apple top header...
- * done for Cocoa : returns window contents (and not frame) max size. */
void wm_get_screensize(int *r_width, int *r_height)
{
unsigned int uiwidth;
@@ -147,7 +146,6 @@ void wm_get_screensize(int *r_width, int *r_height)
*r_height = uiheight;
}
-/* size of all screens (desktop), useful since the mouse is bound by this */
void wm_get_desktopsize(int *r_width, int *r_height)
{
unsigned int uiwidth;
@@ -197,8 +195,6 @@ static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win)
}
}
-/* including window itself, C can be NULL.
- * ED_screen_exit should have been called */
void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
{
/* update context */
@@ -259,7 +255,6 @@ static int find_free_winid(wmWindowManager *wm)
return id;
}
-/* don't change context itself */
wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent, bool dialog)
{
wmWindow *win = MEM_callocN(sizeof(wmWindow), "window");
@@ -275,7 +270,6 @@ wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent
return win;
}
-/* part of wm_window.c api */
wmWindow *wm_window_copy(Main *bmain,
wmWindowManager *wm,
wmWindow *win_src,
@@ -306,10 +300,6 @@ wmWindow *wm_window_copy(Main *bmain,
return win_dst;
}
-/**
- * A higher level version of copy that tests the new window can be added.
- * (called from the operator directly)
- */
wmWindow *wm_window_copy_test(bContext *C,
wmWindow *win_src,
const bool duplicate_layout,
@@ -352,13 +342,6 @@ static void wm_confirm_quit(bContext *C)
wm_close_file_dialog(C, action);
}
-/**
- * Call the quit confirmation prompt or exit directly if needed. The use can
- * still cancel via the confirmation popup. Also, this may not quit Blender
- * immediately, but rather schedule the closing.
- *
- * \param win: The window to show the confirmation popup/window in.
- */
void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
{
wmWindow *win_ctx = CTX_wm_window(C);
@@ -368,7 +351,8 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
CTX_wm_window_set(C, win);
if (U.uiflag & USER_SAVE_PROMPT) {
- if (wm_file_or_image_is_modified(CTX_data_main(C), CTX_wm_manager(C)) && !G.background) {
+ if (wm_file_or_session_data_has_unsaved_changes(CTX_data_main(C), CTX_wm_manager(C)) &&
+ !G.background) {
wm_window_raise(win);
wm_confirm_quit(C);
}
@@ -385,7 +369,6 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
/** \} */
-/* this is event from ghost, or exit-blender op */
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
{
wmWindow *win_other;
@@ -445,13 +428,14 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
}
else if (win->ghostwin) {
/* this is set to 1 if you don't have startup.blend open */
- if (G.save_over && BKE_main_blendfile_path_from_global()[0]) {
- char str[sizeof(((Main *)NULL)->name) + 24];
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] != '\0') {
+ char str[sizeof(((Main *)NULL)->filepath) + 24];
BLI_snprintf(str,
sizeof(str),
"Blender%s [%s%s]",
wm->file_saved ? "" : "*",
- BKE_main_blendfile_path_from_global(),
+ blendfile_path,
G_MAIN->recovered ? " (Recovered)" : "");
GHOST_SetTitle(win->ghostwin, str);
}
@@ -520,7 +504,7 @@ void WM_window_set_dpi(const wmWindow *win)
static void wm_window_update_eventstate(wmWindow *win)
{
/* Update mouse position when a window is activated. */
- wm_cursor_position_get(win, &win->eventstate->x, &win->eventstate->y);
+ wm_cursor_position_get(win, &win->eventstate->xy[0], &win->eventstate->xy[1]);
}
static void wm_window_ensure_eventstate(wmWindow *win)
@@ -677,19 +661,6 @@ static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, boo
ED_screen_global_areas_refresh(win);
}
-/**
- * Initialize #wmWindow without ghostwin, open these and clear.
- *
- * window size is read from window, if 0 it uses prefsize
- * called in #WM_check, also inits stuff after file read.
- *
- * \warning
- * After running, 'win->ghostwin' can be NULL in rare cases
- * (where OpenGL driver fails to create a context for eg).
- * We could remove them with #wm_window_ghostwindows_remove_invalid
- * but better not since caller may continue to use.
- * Instead, caller needs to handle the error case and cleanup.
- */
void wm_window_ghostwindows_ensure(wmWindowManager *wm)
{
BLI_assert(G.background == false);
@@ -713,10 +684,6 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
}
}
-/**
- * Call after #wm_window_ghostwindows_ensure or #WM_check
- * (after loading a new file) in the unlikely event a window couldn't be created.
- */
void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm)
{
BLI_assert(G.background == false);
@@ -754,14 +721,6 @@ static bool wm_window_update_size_position(wmWindow *win)
return false;
}
-/**
- * \param space_type: SPACE_VIEW3D, SPACE_INFO, ... (eSpace_Type)
- * \param toplevel: Not a child owned by other windows. A peer of main window.
- * \param dialog: whether this should be made as a dialog-style window
- * \param temp: whether this is considered a short-lived window
- * \param alignment: how this window is positioned relative to its parent
- * \return the window or NULL in case of failure.
- */
wmWindow *WM_window_open(bContext *C,
const char *title,
int x,
@@ -772,7 +731,7 @@ wmWindow *WM_window_open(bContext *C,
bool toplevel,
bool dialog,
bool temp,
- WindowAlignment alignment)
+ eWindowAlignment alignment)
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
@@ -852,7 +811,8 @@ wmWindow *WM_window_open(bContext *C,
/* Set scene and view layer to match original window. */
STRNCPY(win->view_layer_name, view_layer->name);
if (WM_window_get_active_scene(win) != scene) {
- ED_screen_scene_change(C, win, scene);
+ /* No need to refresh the tool-system as the window has not yet finished being setup. */
+ ED_screen_scene_change(C, win, scene, false);
}
screen->temp = temp;
@@ -913,7 +873,7 @@ int wm_window_close_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-int wm_window_new_exec(bContext *C, wmOperator *UNUSED(op))
+int wm_window_new_exec(bContext *C, wmOperator *op)
{
wmWindow *win_src = CTX_wm_window(C);
ScrArea *area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0);
@@ -930,19 +890,25 @@ int wm_window_new_exec(bContext *C, wmOperator *UNUSED(op))
false,
WIN_ALIGN_PARENT_CENTER) != NULL);
- return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ if (!ok) {
+ BKE_report(op->reports, RPT_ERROR, "Failed to create window");
+ return OPERATOR_CANCELLED;
+ }
+ return OPERATOR_FINISHED;
}
-int wm_window_new_main_exec(bContext *C, wmOperator *UNUSED(op))
+int wm_window_new_main_exec(bContext *C, wmOperator *op)
{
wmWindow *win_src = CTX_wm_window(C);
bool ok = (wm_window_copy_test(C, win_src, true, false) != NULL);
-
- return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ if (!ok) {
+ BKE_report(op->reports, RPT_ERROR, "Failed to create window");
+ return OPERATOR_CANCELLED;
+ }
+ return OPERATOR_FINISHED;
}
-/* fullscreen operator callback */
int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindow *window = CTX_wm_window(C);
@@ -989,8 +955,8 @@ void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y)
void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y)
{
if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
- *r_x = win->eventstate->x;
- *r_y = win->eventstate->y;
+ *r_x = win->eventstate->xy[0];
+ *r_y = win->eventstate->xy[1];
return;
}
GHOST_GetCursorPosition(g_system, r_x, r_y);
@@ -1067,13 +1033,14 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
}
wm_window_set_drawable(wm, win, true);
+ }
+ if (win->ghostwin) {
/* this can change per window */
WM_window_set_dpi(win);
}
}
-/* Reset active the current window opengl drawing context. */
void wm_window_reset_drawable(void)
{
BLI_assert(BLI_thread_is_main());
@@ -1265,8 +1232,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
wmEvent event;
wm_event_init_from_window(win, &event);
event.type = MOUSEMOVE;
- event.prevx = event.x;
- event.prevy = event.y;
+ copy_v2_v2_int(event.prev_xy, event.xy);
event.is_repeat = false;
wm_event_add(win, &event);
@@ -1397,8 +1363,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
/* activate region */
event.type = MOUSEMOVE;
- event.prevx = event.x;
- event.prevy = event.y;
+ copy_v2_v2_int(event.prev_xy, event.xy);
event.is_repeat = false;
/* No context change! C->wm->windrawable is drawable, or for area queues. */
@@ -1413,7 +1378,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
event.val = KM_RELEASE;
event.custom = EVT_DATA_DRAGDROP;
event.customdata = &wm->drags;
- event.customdatafree = 1;
+ event.customdata_free = true;
wm_event_add(win, &event);
@@ -1577,10 +1542,6 @@ void wm_window_process_events(const bContext *C)
/** \name Ghost Init/Exit
* \{ */
-/**
- * \note #bContext can be null in background mode because we don't
- * need to event handling.
- */
void wm_ghost_init(bContext *C)
{
if (!g_system) {
@@ -1619,7 +1580,6 @@ void wm_ghost_exit(void)
/** \name Event Timer
* \{ */
-/* to (de)activate running timers temporary */
void WM_event_timer_sleep(wmWindowManager *wm,
wmWindow *UNUSED(win),
wmTimer *timer,
@@ -1761,19 +1721,11 @@ static char *wm_clipboard_text_get_ex(bool selection, int *r_len, bool firstline
return newbuf;
}
-/**
- * Return text from the clipboard.
- *
- * \note Caller needs to check for valid utf8 if this is a requirement.
- */
char *WM_clipboard_text_get(bool selection, int *r_len)
{
return wm_clipboard_text_get_ex(selection, r_len, false);
}
-/**
- * Convenience function for pasting to areas of Blender which don't support newlines.
- */
char *WM_clipboard_text_get_firstline(bool selection, int *r_len)
{
return wm_clipboard_text_get_ex(selection, r_len, true);
@@ -1882,9 +1834,6 @@ void wm_window_raise(wmWindow *win)
/** \name Window Buffers
* \{ */
-/**
- * \brief Push rendered buffer to the screen.
- */
void wm_window_swap_buffers(wmWindow *win)
{
GHOST_SwapWindowBuffers(win->ghostwin);
@@ -1905,6 +1854,7 @@ bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut)
/* -------------------------------------------------------------------- */
/** \name Find Window Utility
* \{ */
+
static void wm_window_desktop_pos_get(const wmWindow *win,
const int screen_pos[2],
int r_desk_pos[2])
@@ -2026,7 +1976,6 @@ uint *WM_window_pixels_read(wmWindowManager *wm, wmWindow *win, int r_size[2])
/** \name Initial Window State API
* \{ */
-/* called whem no ghost system was initialized */
void WM_init_state_size_set(int stax, int stay, int sizx, int sizy)
{
wm_init_state.start_x = stax; /* left hand pos */
@@ -2036,7 +1985,6 @@ void WM_init_state_size_set(int stax, int stay, int sizx, int sizy)
wm_init_state.override_flag |= WIN_OVERRIDE_GEOM;
}
-/* for borderless and border windows set from command-line */
void WM_init_state_fullscreen_set(void)
{
wm_init_state.windowstate = GHOST_kWindowStateFullScreen;
@@ -2089,7 +2037,6 @@ void WM_init_tablet_api(void)
}
}
-/* This function requires access to the GHOST_SystemHandle (g_system) */
void WM_cursor_warp(wmWindow *win, int x, int y)
{
if (win && win->ghostwin) {
@@ -2098,17 +2045,14 @@ void WM_cursor_warp(wmWindow *win, int x, int y)
wm_cursor_position_to_ghost(win, &x, &y);
GHOST_SetCursorPosition(g_system, x, y);
- win->eventstate->prevx = oldx;
- win->eventstate->prevy = oldy;
+ win->eventstate->prev_xy[0] = oldx;
+ win->eventstate->prev_xy[1] = oldy;
- win->eventstate->x = oldx;
- win->eventstate->y = oldy;
+ win->eventstate->xy[0] = oldx;
+ win->eventstate->xy[1] = oldy;
}
}
-/**
- * Set x, y to values we can actually position the cursor to.
- */
void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y)
{
float f = GHOST_GetNativePixelSize(win->ghostwin);
@@ -2124,11 +2068,6 @@ void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y)
/** \name Window Size (public)
* \{ */
-/**
- * Support for native pixel size
- *
- * \note macOS retina opens window in size X, but it has up to 2 x more pixels.
- */
int WM_window_pixels_x(const wmWindow *win)
{
float f = GHOST_GetNativePixelSize(win->ghostwin);
@@ -2142,17 +2081,10 @@ int WM_window_pixels_y(const wmWindow *win)
return (int)(f * (float)win->sizey);
}
-/**
- * Get boundaries usable by all window contents, including global areas.
- */
void WM_window_rect_calc(const wmWindow *win, rcti *r_rect)
{
BLI_rcti_init(r_rect, 0, WM_window_pixels_x(win), 0, WM_window_pixels_y(win));
}
-/**
- * Get boundaries usable by screen-layouts, excluding global areas.
- * \note Depends on U.dpi_fac. Should that be outdated, call #WM_window_set_dpi first.
- */
void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
{
rcti window_rect, screen_rect;
@@ -2202,11 +2134,6 @@ bool WM_window_is_maximized(const wmWindow *win)
/** \name Window Screen/Scene/WorkSpaceViewLayer API
* \{ */
-/**
- * Some editor data may need to be synced with scene data (3D View camera and layers).
- * This function ensures data is synced for editors
- * in visible workspaces and their visible layouts.
- */
void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)
{
LISTBASE_FOREACH (wmWindow *, win, win_lb) {
@@ -2253,9 +2180,6 @@ Scene *WM_window_get_active_scene(const wmWindow *win)
return win->scene;
}
-/**
- * \warning Only call outside of area/region loops
- */
void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -2264,13 +2188,13 @@ void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *
/* Set scene in parent and its child windows. */
if (win_parent->scene != scene) {
- ED_screen_scene_change(C, win_parent, scene);
+ ED_screen_scene_change(C, win_parent, scene, true);
changed = true;
}
LISTBASE_FOREACH (wmWindow *, win_child, &wm->windows) {
if (win_child->parent == win_parent && win_child->scene != scene) {
- ED_screen_scene_change(C, win_child, scene);
+ ED_screen_scene_change(C, win_child, scene, true);
changed = true;
}
}
@@ -2368,9 +2292,6 @@ void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceL
BKE_workspace_active_layout_set(win->workspace_hook, win->winid, workspace, layout);
}
-/**
- * Get the active screen of the active workspace in \a win.
- */
bScreen *WM_window_get_active_screen(const wmWindow *win)
{
const WorkSpace *workspace = WM_window_get_active_workspace(win);
@@ -2473,4 +2394,5 @@ void WM_ghost_show_message_box(const char *title,
BLI_assert(g_system);
GHOST_ShowMessageBox(g_system, title, message, help_label, continue_label, link, dialog_options);
}
+
/** \} */
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
index 86a106462c3..81ef8c881f5 100644
--- a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
@@ -147,16 +147,6 @@ void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C)
// printf("msgbus: keys=%u values=%u\n", a, b);
}
-/**
- * \param msg_key_test: Needs following #wmMsgSubscribeKey fields filled in:
- * - msg.params
- * - msg.head.type
- * - msg.head.id
- * .. other values should be zeroed.
- *
- * \return The key for this subscription.
- * note that this is only needed in rare cases when the key needs further manipulation.
- */
wmMsgSubscribeKey *WM_msg_subscribe_with_key(struct wmMsgBus *mbus,
const wmMsgSubscribeKey *msg_key_test,
const wmMsgSubscribeValue *msg_val_params)
@@ -239,9 +229,6 @@ void WM_msg_id_remove(struct wmMsgBus *mbus, const struct ID *id)
* \note While we could have a separate type for ID's, use RNA since there is enough overlap.
* \{ */
-/**
- * \note #wmMsgBus.messages_tag_count isn't updated, caller must handle.
- */
void wm_msg_subscribe_value_free(wmMsgSubscribeKey *msg_key, wmMsgSubscribeValueLink *msg_lnk)
{
if (msg_lnk->params.free_data) {
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h b/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
index 24c0192fe14..18df17c3d1c 100644
--- a/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
@@ -30,6 +30,9 @@ struct wmMsgBus {
uint messages_tag_count;
};
+/**
+ * \note #wmMsgBus.messages_tag_count isn't updated, caller must handle.
+ */
void wm_msg_subscribe_value_free(struct wmMsgSubscribeKey *msg_key,
struct wmMsgSubscribeValueLink *msg_lnk);
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
index 460dca57e4f..bc083793395 100644
--- a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
@@ -35,7 +35,9 @@
#include "RNA_access.h"
-/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
BLI_INLINE uint void_hash_uint(const void *key)
{
@@ -208,7 +210,11 @@ void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msgtype_info)
msgtype_info->msg_key_size = sizeof(wmMsgSubscribeKey_RNA);
}
-/* -------------------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name RNA API
+ * \{ */
wmMsgSubscribeKey_RNA *WM_msg_lookup_rna(struct wmMsgBus *mbus,
const wmMsgParams_RNA *msg_key_params)
diff --git a/source/blender/windowmanager/message_bus/wm_message_bus.h b/source/blender/windowmanager/message_bus/wm_message_bus.h
index 7ae356cf806..a93a7bbcea7 100644
--- a/source/blender/windowmanager/message_bus/wm_message_bus.h
+++ b/source/blender/windowmanager/message_bus/wm_message_bus.h
@@ -79,7 +79,7 @@ typedef struct wmMsg {
} wmMsg;
typedef struct wmMsgSubscribeKey {
- /** Linked list for predicable ordering, otherwise we would depend on ghash bucketing. */
+ /** Linked list for predicable ordering, otherwise we would depend on #GHash bucketing. */
struct wmMsgSubscribeKey *next, *prev;
ListBase values;
/* over-alloc, eg: wmMsgSubscribeKey_RNA */
@@ -124,6 +124,16 @@ void WM_msg_dump(struct wmMsgBus *mbus, const char *info);
void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C);
void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key);
+/**
+ * \param msg_key_test: Needs following #wmMsgSubscribeKey fields filled in:
+ * - `msg.params`
+ * - `msg.head.type`
+ * - `msg.head.id`
+ * .. other values should be zeroed.
+ *
+ * \return The key for this subscription.
+ * note that this is only needed in rare cases when the key needs further manipulation.
+ */
wmMsgSubscribeKey *WM_msg_subscribe_with_key(struct wmMsgBus *mbus,
const wmMsgSubscribeKey *msg_key_test,
const wmMsgSubscribeValue *msg_val_params);
@@ -234,6 +244,17 @@ void WM_msg_subscribe_ID(struct wmMsgBus *mbus,
const char *id_repr);
void WM_msg_publish_ID(struct wmMsgBus *mbus, struct ID *id);
+/* FIXME
+ *
+ * For C++ code, some of the following macros need to be called in functions wrapped in
+ * `extern "C"` blocks. That is, the ones doing `extern PropertyRNA` declarations (trips up the
+ * MSVC linker).
+ * Although this shouldn't cause problems normally, if it does, the bits calling the macros can be
+ * moved to a separate function wrapped in `extern "C"`.
+ *
+ * Obviously this should be fixed properly (by not relying on inline `extern` declarations).
+ */
+
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_) \
{ \
wmMsgParams_RNA msg_key_params_ = {{0}}; \
@@ -260,16 +281,11 @@ void WM_msg_publish_ID(struct wmMsgBus *mbus, struct ID *id);
/* Anonymous variants (for convenience) */
#define WM_msg_subscribe_rna_anon_type(mbus, type_, value) \
{ \
- WM_msg_subscribe_rna_params(mbus, \
- &(const wmMsgParams_RNA){ \
- .ptr = \
- (PointerRNA){ \
- .type = &RNA_##type_, \
- }, \
- .prop = NULL, \
- }, \
- value, \
- __func__); \
+ PointerRNA msg_ptr_ = {0, &RNA_##type_}; \
+ wmMsgParams_RNA msg_key_params_ = {{0}}; \
+ msg_key_params_.ptr = msg_ptr_; \
+\
+ WM_msg_subscribe_rna_params(mbus, &msg_key_params_, value, __func__); \
} \
((void)0)
#define WM_msg_subscribe_rna_anon_prop(mbus, type_, prop_, value) \
@@ -277,16 +293,13 @@ void WM_msg_publish_ID(struct wmMsgBus *mbus, struct ID *id);
_WM_MESSAGE_EXTERN_BEGIN; \
extern PropertyRNA rna_##type_##_##prop_; \
_WM_MESSAGE_EXTERN_END; \
- WM_msg_subscribe_rna_params(mbus, \
- &(const wmMsgParams_RNA){ \
- .ptr = \
- (PointerRNA){ \
- .type = &RNA_##type_, \
- }, \
- .prop = &rna_##type_##_##prop_, \
- }, \
- value, \
- __func__); \
+\
+ PointerRNA msg_ptr_ = {0, &RNA_##type_}; \
+ wmMsgParams_RNA msg_key_params_ = {{0}}; \
+ msg_key_params_.ptr = msg_ptr_; \
+ msg_key_params_.prop = &rna_##type_##_##prop_; \
+\
+ WM_msg_subscribe_rna_params(mbus, &msg_key_params_, value, __func__); \
} \
((void)0)
diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h
index af696ddd8f9..e67b1581875 100644
--- a/source/blender/windowmanager/wm.h
+++ b/source/blender/windowmanager/wm.h
@@ -43,57 +43,108 @@ typedef struct wmPaintCursor {
short region_type;
} wmPaintCursor;
+/**
+ * Cause a delayed #WM_exit()
+ * call to avoid leaking memory when trying to exit from within operators.
+ */
void wm_exit_schedule_delayed(const bContext *C);
+/**
+ * Context is allowed to be NULL, do not free wm itself (lib_id.c).
+ */
extern void wm_close_and_free(bContext *C, wmWindowManager *);
extern void wm_close_and_free_all(bContext *C, ListBase *);
+/**
+ * On startup, it adds all data, for matching.
+ */
extern void wm_add_default(struct Main *bmain, bContext *C);
extern void wm_clear_default_size(bContext *C);
/* register to windowmanager for redo or macro */
+
+/**
+ * Called on event handling by `event_system.c`.
+ *
+ * All operations get registered in the windowmanager here.
+ */
void wm_operator_register(bContext *C, wmOperator *op);
/* wm_operator.c, for init/exit */
+
void wm_operatortype_free(void);
+/**
+ * Called on initialize #WM_init().
+ */
void wm_operatortype_init(void);
+/**
+ * Default key-map for windows and screens, only call once per WM.
+ */
void wm_window_keymap(wmKeyConfig *keyconf);
void wm_operatortypes_register(void);
/* wm_gesture.c */
+/* called in wm_draw.c */
+
void wm_gesture_draw(struct wmWindow *win);
+/**
+ * Tweak and line gestures.
+ */
int wm_gesture_evaluate(wmGesture *gesture, const struct wmEvent *event);
void wm_gesture_tag_redraw(struct wmWindow *win);
/* wm_gesture_ops.c */
+
+/**
+ * Standard tweak, called after window handlers passed on event.
+ */
void wm_tweakevent_test(bContext *C, const wmEvent *event, int action);
/* wm_jobs.c */
+
+/**
+ * Hard-coded to event #TIMERJOBS.
+ */
void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt);
+/**
+ * Kill job entirely, also removes timer itself.
+ */
void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt);
/* wm_files.c */
+
+/**
+ * Run the auto-save timer action.
+ */
void wm_autosave_timer(struct Main *bmain, wmWindowManager *wm, wmTimer *wt);
void wm_autosave_timer_begin(struct wmWindowManager *wm);
void wm_autosave_timer_end(wmWindowManager *wm);
void wm_autosave_delete(void);
/* wm_splash_screen.c */
+
void WM_OT_splash(wmOperatorType *ot);
void WM_OT_splash_about(wmOperatorType *ot);
/* wm_stereo.c */
+
void wm_stereo3d_draw_sidebyside(wmWindow *win, int view);
void wm_stereo3d_draw_topbottom(wmWindow *win, int view);
-void wm_stereo3d_mouse_offset_apply(wmWindow *win, int *r_mouse_xy);
+/**
+ * If needed, adjust \a r_mouse_xy
+ * so that drawn cursor and handled mouse position are matching visually.
+ */
+void wm_stereo3d_mouse_offset_apply(wmWindow *win, int r_mouse_xy[2]);
int wm_stereo3d_set_exec(bContext *C, wmOperator *op);
int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *event);
void wm_stereo3d_set_draw(bContext *C, wmOperator *op);
bool wm_stereo3d_set_check(bContext *C, wmOperator *op);
void wm_stereo3d_set_cancel(bContext *C, wmOperator *op);
-/* init operator properties */
+/**
+ * Initialize operator properties.
+ */
void wm_open_init_load_ui(wmOperator *op, bool use_prefs);
void wm_open_init_use_scripts(wmOperator *op, bool use_prefs);
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index 787c840de8a..925be8ab183 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -32,6 +32,11 @@
struct ARegion;
struct GHOST_TabletData;
struct ScrArea;
+enum wmOperatorCallContext;
+
+#ifdef WITH_XR_OPENXR
+struct wmXrActionData;
+#endif
#ifdef __cplusplus
extern "C" {
@@ -139,17 +144,36 @@ typedef struct wmEventHandler_Dropbox {
} wmEventHandler_Dropbox;
/* wm_event_system.c */
+
void wm_event_free_all(wmWindow *win);
void wm_event_free(wmEvent *event);
void wm_event_free_handler(wmEventHandler *handler);
-/* goes over entire hierarchy: events -> window -> screen -> area -> region */
+/**
+ * Goes over entire hierarchy: events -> window -> screen -> area -> region.
+ *
+ * \note Called in main loop.
+ */
void wm_event_do_handlers(bContext *C);
+/**
+ * Windows store own event queues #wmWindow.event_queue (no #bContext here).
+ */
void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata);
+#ifdef WITH_XR_OPENXR
+void wm_event_add_xrevent(wmWindow *win, struct wmXrActionData *actiondata, short val);
+#endif
void wm_event_do_depsgraph(bContext *C, bool is_after_open_file);
+/**
+ * Was part of #wm_event_do_notifiers,
+ * split out so it can be called once before entering the #WM_main loop.
+ * This ensures operators don't run before the UI and depsgraph are initialized.
+ */
void wm_event_do_refresh_wm_and_depsgraph(bContext *C);
+/**
+ * Called in main-loop.
+ */
void wm_event_do_notifiers(bContext *C);
void wm_event_handler_ui_cancel_ex(bContext *C,
@@ -158,15 +182,37 @@ void wm_event_handler_ui_cancel_ex(bContext *C,
bool reactivate_button);
/* wm_event_query.c */
+
+/**
+ * Applies the global tablet pressure correction curve.
+ */
float wm_pressure_curve(float raw_pressure);
void wm_tablet_data_from_ghost(const struct GHOST_TabletData *tablet_data, wmTabletData *wmtab);
-/* wm_keymap.c */
-
/* wm_dropbox.c */
+
void wm_dropbox_free(void);
+/**
+ * Additional work to cleanly end dragging. Additional because this doesn't actually remove the
+ * drag items. Should be called whenever dragging is stopped
+ * (successful or not, also when canceled).
+ */
+void wm_drags_exit(wmWindowManager *wm, wmWindow *win);
+void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop);
+/**
+ * Called in inner handler loop, region context.
+ */
void wm_drags_check_ops(bContext *C, const wmEvent *event);
-void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect);
+/**
+ * The operator of a dropbox should always be executed in the context determined by the mouse
+ * coordinates. The dropbox poll should check the context area and region as needed.
+ * So this always returns #WM_OP_INVOKE_DEFAULT.
+ */
+wmOperatorCallContext wm_drop_operator_context_get(const wmDropBox *drop);
+/**
+ * Called in #wm_draw_window_onscreen.
+ */
+void wm_drags_draw(bContext *C, wmWindow *win);
#ifdef __cplusplus
}
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index 905c57d901a..a6685e97c4f 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -29,14 +29,19 @@
extern "C" {
#endif
-/* customdata type */
+/** #wmEvent.customdata type */
enum {
EVT_DATA_TIMER = 2,
EVT_DATA_DRAGDROP = 3,
EVT_DATA_NDOF_MOTION = 4,
+ EVT_DATA_XR = 5,
};
-/* tablet active, matches GHOST_TTabletMode */
+/**
+ * #wmTabletData.active tablet active, matches #GHOST_TTabletMode.
+ *
+ * Typically access via `event->tablet.active`.
+ */
enum {
EVT_TABLET_NONE = 0,
EVT_TABLET_STYLUS = 1,
@@ -94,10 +99,14 @@ enum {
TABLET_STYLUS = 0x001a,
TABLET_ERASER = 0x001b,
- /* *** Start of keyboard codes. *** */
+/* *** Start of keyboard codes. *** */
+
+/* Minimum keyboard value (inclusive). */
+#define _EVT_KEYBOARD_MIN 0x0020
/* Standard keyboard.
- * From 0x0020 to 0x00ff, and 0x012c to 0x0143 for function keys! */
+ * - 0x0020 to 0x00ff [#_EVT_KEYBOARD_MIN to #_EVT_KEYBOARD_MAX] inclusive - for keys.
+ * - 0x012c to 0x0143 [#EVT_F1KEY to #EVT_F24KEY] inclusive - for function keys. */
EVT_ZEROKEY = 0x0030, /* '0' (48). */
EVT_ONEKEY = 0x0031, /* '1' (49). */
@@ -209,6 +218,12 @@ enum {
EVT_LEFTBRACKETKEY = 0x00eb, /* 235 */
EVT_RIGHTBRACKETKEY = 0x00ec, /* 236 */
+/* Maximum keyboard value (inclusive). */
+#define _EVT_KEYBOARD_MAX 0x00ff /* 255 */
+
+ /* WARNING: 0x010x are used for internal events
+ * (but are still stored in the key-map). */
+
EVT_F1KEY = 0x012c, /* 300 */
EVT_F2KEY = 0x012d, /* 301 */
EVT_F3KEY = 0x012e, /* 302 */
@@ -236,60 +251,65 @@ enum {
/* *** End of keyboard codes. *** */
- /* NDOF (from SpaceNavigator & friends)
- * These should be kept in sync with GHOST_NDOFManager.h
+ /* NDOF (from "Space Navigator" & friends)
+ * These must be kept in sync with `GHOST_NDOFManager.h`.
* Ordering matters, exact values do not. */
+
NDOF_MOTION = 0x0190, /* 400 */
+
+#define _NDOF_MIN NDOF_MOTION
+
/* used internally, never sent */
NDOF_BUTTON_NONE = NDOF_MOTION,
/* these two are available from any 3Dconnexion device */
- NDOF_BUTTON_MENU,
- NDOF_BUTTON_FIT,
+
+ NDOF_BUTTON_MENU = 0x0191, /* 401 */
+ NDOF_BUTTON_FIT = 0x0192, /* 402 */
/* standard views */
- NDOF_BUTTON_TOP,
- NDOF_BUTTON_BOTTOM,
- NDOF_BUTTON_LEFT,
- NDOF_BUTTON_RIGHT,
- NDOF_BUTTON_FRONT,
- NDOF_BUTTON_BACK,
+ NDOF_BUTTON_TOP = 0x0193, /* 403 */
+ NDOF_BUTTON_BOTTOM = 0x0194, /* 404 */
+ NDOF_BUTTON_LEFT = 0x0195, /* 405 */
+ NDOF_BUTTON_RIGHT = 0x0196, /* 406 */
+ NDOF_BUTTON_FRONT = 0x0197, /* 407 */
+ NDOF_BUTTON_BACK = 0x0198, /* 408 */
/* more views */
- NDOF_BUTTON_ISO1,
- NDOF_BUTTON_ISO2,
+ NDOF_BUTTON_ISO1 = 0x0199, /* 409 */
+ NDOF_BUTTON_ISO2 = 0x019a, /* 410 */
/* 90 degree rotations */
- NDOF_BUTTON_ROLL_CW,
- NDOF_BUTTON_ROLL_CCW,
- NDOF_BUTTON_SPIN_CW,
- NDOF_BUTTON_SPIN_CCW,
- NDOF_BUTTON_TILT_CW,
- NDOF_BUTTON_TILT_CCW,
+ NDOF_BUTTON_ROLL_CW = 0x019b, /* 411 */
+ NDOF_BUTTON_ROLL_CCW = 0x019c, /* 412 */
+ NDOF_BUTTON_SPIN_CW = 0x019d, /* 413 */
+ NDOF_BUTTON_SPIN_CCW = 0x019e, /* 414 */
+ NDOF_BUTTON_TILT_CW = 0x019f, /* 415 */
+ NDOF_BUTTON_TILT_CCW = 0x01a0, /* 416 */
/* device control */
- NDOF_BUTTON_ROTATE,
- NDOF_BUTTON_PANZOOM,
- NDOF_BUTTON_DOMINANT,
- NDOF_BUTTON_PLUS,
- NDOF_BUTTON_MINUS,
+ NDOF_BUTTON_ROTATE = 0x01a1, /* 417 */
+ NDOF_BUTTON_PANZOOM = 0x01a2, /* 418 */
+ NDOF_BUTTON_DOMINANT = 0x01a3, /* 419 */
+ NDOF_BUTTON_PLUS = 0x01a4, /* 420 */
+ NDOF_BUTTON_MINUS = 0x01a5, /* 421 */
/* keyboard emulation */
- NDOF_BUTTON_ESC,
- NDOF_BUTTON_ALT,
- NDOF_BUTTON_SHIFT,
- NDOF_BUTTON_CTRL,
+ NDOF_BUTTON_ESC = 0x01a6, /* 422 */
+ NDOF_BUTTON_ALT = 0x01a7, /* 423 */
+ NDOF_BUTTON_SHIFT = 0x01a8, /* 424 */
+ NDOF_BUTTON_CTRL = 0x01a9, /* 425 */
/* general-purpose buttons */
- NDOF_BUTTON_1,
- NDOF_BUTTON_2,
- NDOF_BUTTON_3,
- NDOF_BUTTON_4,
- NDOF_BUTTON_5,
- NDOF_BUTTON_6,
- NDOF_BUTTON_7,
- NDOF_BUTTON_8,
- NDOF_BUTTON_9,
- NDOF_BUTTON_10,
+ NDOF_BUTTON_1 = 0x01aa, /* 426 */
+ NDOF_BUTTON_2 = 0x01ab, /* 427 */
+ NDOF_BUTTON_3 = 0x01ac, /* 428 */
+ NDOF_BUTTON_4 = 0x01ad, /* 429 */
+ NDOF_BUTTON_5 = 0x01ae, /* 430 */
+ NDOF_BUTTON_6 = 0x01af, /* 431 */
+ NDOF_BUTTON_7 = 0x01b0, /* 432 */
+ NDOF_BUTTON_8 = 0x01b1, /* 433 */
+ NDOF_BUTTON_9 = 0x01b2, /* 434 */
+ NDOF_BUTTON_10 = 0x01b3, /* 435 */
/* more general-purpose buttons */
- NDOF_BUTTON_A,
- NDOF_BUTTON_B,
- NDOF_BUTTON_C,
- /* the end */
- NDOF_LAST,
+ NDOF_BUTTON_A = 0x01b4, /* 436 */
+ NDOF_BUTTON_B = 0x01b5, /* 437 */
+ NDOF_BUTTON_C = 0x01b6, /* 438 */
+
+#define _NDOF_MAX NDOF_BUTTON_C
/* ********** End of Input devices. ********** */
@@ -317,13 +337,13 @@ enum {
EVT_ACTIONZONE_REGION = 0x5001, /* 20481 */
EVT_ACTIONZONE_FULLSCREEN = 0x5011, /* 20497 */
- /* NOTE: these values are saved in keymap files, do not change them but just add new ones */
+ /* NOTE: these values are saved in key-map files, do not change them but just add new ones. */
/* Tweak events:
* Sent as additional event with the mouse coordinates
* from where the initial click was placed. */
- /* tweak events for L M R mousebuttons */
+ /* Tweak events for L M R mouse-buttons. */
EVT_TWEAK_L = 0x5002, /* 20482 */
EVT_TWEAK_M = 0x5003, /* 20483 */
EVT_TWEAK_R = 0x5004, /* 20484 */
@@ -341,12 +361,17 @@ enum {
/* could become gizmo callback */
EVT_GIZMO_UPDATE = 0x5025, /* 20517 */
+
+ /* XR events: 0x503x */
+ EVT_XR_ACTION = 0x5030, /* 20528 */
/* ********** End of Blender internal events. ********** */
};
-/* *********** wmEvent.type helpers. ********** */
+/* -------------------------------------------------------------------- */
+/** \name #wmEvent.type Helpers
+ * \{ */
-/* test whether the event is timer event */
+/** Test whether the event is timer event. */
#define ISTIMER(event_type) ((event_type) >= TIMER && (event_type) <= TIMERF)
/* for event checks */
@@ -355,22 +380,24 @@ enum {
// #define ISTEXTINPUT(event_type) ((event_type) >= ' ' && (event_type) <= 255)
/* NOTE: an alternative could be to check `event->utf8_buf`. */
-/* test whether the event is a key on the keyboard */
+/** Test whether the event is a key on the keyboard (including modifier keys). */
#define ISKEYBOARD(event_type) \
- (((event_type) >= 0x0020 && (event_type) <= 0x00ff) || \
- ((event_type) >= 0x012c && (event_type) <= 0x0143))
+ (((event_type) >= _EVT_KEYBOARD_MIN && (event_type) <= _EVT_KEYBOARD_MAX) || \
+ ((event_type) >= EVT_F1KEY && (event_type) <= EVT_F24KEY))
-/* test whether the event is a modifier key */
+/** Test whether the event is a modifier key. */
#define ISKEYMODIFIER(event_type) \
(((event_type) >= EVT_LEFTCTRLKEY && (event_type) <= EVT_LEFTSHIFTKEY) || \
(event_type) == EVT_OSKEY)
-/* test whether the event is a mouse button */
+/** Test whether the event is a mouse button. */
#define ISMOUSE(event_type) \
(((event_type) >= LEFTMOUSE && (event_type) <= BUTTON7MOUSE) || (event_type) == MOUSESMARTZOOM)
-
+/** Test whether the event is a mouse wheel. */
#define ISMOUSE_WHEEL(event_type) ((event_type) >= WHEELUPMOUSE && (event_type) <= WHEELOUTMOUSE)
+/** Test whether the event is a mouse (track-pad) gesture. */
#define ISMOUSE_GESTURE(event_type) ((event_type) >= MOUSEPAN && (event_type) <= MOUSEROTATE)
+/** Test whether the event is a mouse button (excluding mouse-wheel). */
#define ISMOUSE_BUTTON(event_type) \
(ELEM(event_type, \
LEFTMOUSE, \
@@ -381,16 +408,16 @@ enum {
BUTTON6MOUSE, \
BUTTON7MOUSE))
-/* test whether the event is tweak event */
+/** Test whether the event is tweak event. */
#define ISTWEAK(event_type) ((event_type) >= EVT_TWEAK_L && (event_type) <= EVT_TWEAK_R)
-/* test whether the event is a NDOF event */
-#define ISNDOF(event_type) ((event_type) >= NDOF_MOTION && (event_type) < NDOF_LAST)
+/** Test whether the event is a NDOF event. */
+#define ISNDOF(event_type) ((event_type) >= _NDOF_MIN && (event_type) <= _NDOF_MAX)
#define IS_EVENT_ACTIONZONE(event_type) \
ELEM(event_type, EVT_ACTIONZONE_AREA, EVT_ACTIONZONE_REGION, EVT_ACTIONZONE_FULLSCREEN)
-/* test whether event type is acceptable as hotkey, excluding modifiers */
+/** Test whether event type is acceptable as hotkey (excluding modifiers). */
#define ISHOTKEY(event_type) \
((ISKEYBOARD(event_type) || ISMOUSE(event_type) || ISNDOF(event_type)) && \
(ISKEYMODIFIER(event_type) == false))
@@ -401,27 +428,27 @@ enum {
#define _VA_IS_EVENT_MOD4(v, a, b, c) (_VA_IS_EVENT_MOD3(v, a, b) || ((v)->c))
#define _VA_IS_EVENT_MOD5(v, a, b, c, d) (_VA_IS_EVENT_MOD4(v, a, b, c) || ((v)->d))
-/* reusable IS_EVENT_MOD(event, shift, ctrl, alt, oskey), macro */
+/** Reusable `IS_EVENT_MOD(event, shift, ctrl, alt, oskey)` macro. */
#define IS_EVENT_MOD(...) VA_NARGS_CALL_OVERLOAD(_VA_IS_EVENT_MOD, __VA_ARGS__)
enum eEventType_Mask {
- /* ISKEYMODIFIER */
+ /** #ISKEYMODIFIER */
EVT_TYPE_MASK_KEYBOARD_MODIFIER = (1 << 0),
- /* ISKEYBOARD */
+ /** #ISKEYBOARD */
EVT_TYPE_MASK_KEYBOARD = (1 << 1),
- /* ISMOUSE_WHEEL */
+ /** #ISMOUSE_WHEEL */
EVT_TYPE_MASK_MOUSE_WHEEL = (1 << 2),
- /* ISMOUSE_BUTTON */
+ /** #ISMOUSE_BUTTON */
EVT_TYPE_MASK_MOUSE_GESTURE = (1 << 3),
- /* ISMOUSE_GESTURE */
+ /** #ISMOUSE_GESTURE */
EVT_TYPE_MASK_MOUSE_BUTTON = (1 << 4),
- /* ISMOUSE */
+ /** #ISMOUSE */
EVT_TYPE_MASK_MOUSE = (1 << 5),
- /* ISNDOF */
+ /** #ISNDOF */
EVT_TYPE_MASK_NDOF = (1 << 6),
- /* ISTWEAK */
+ /** #ISTWEAK */
EVT_TYPE_MASK_TWEAK = (1 << 7),
- /* IS_EVENT_ACTIONZONE */
+ /** #IS_EVENT_ACTIONZONE */
EVT_TYPE_MASK_ACTIONZONE = (1 << 8),
};
#define EVT_TYPE_MASK_ALL \
@@ -432,9 +459,13 @@ enum eEventType_Mask {
(EVT_TYPE_MASK_KEYBOARD | EVT_TYPE_MASK_MOUSE | EVT_TYPE_MASK_NDOF)
#define EVT_TYPE_MASK_HOTKEY_EXCLUDE EVT_TYPE_MASK_KEYBOARD_MODIFIER
-bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask mask);
+bool WM_event_type_mask_test(int event_type, enum eEventType_Mask mask);
+
+/** \} */
-/* ********** wmEvent.val ********** */
+/* -------------------------------------------------------------------- */
+/** \name #wmEvent.val Values
+ * \{ */
/* Gestures */
/* NOTE: these values are saved in keymap files, do not change them but just add new ones */
@@ -501,6 +532,8 @@ enum {
GESTURE_MODAL_FLIP = 14,
};
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index 2fa5a68829e..e63afb2ed2f 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -33,6 +33,7 @@ extern "C" {
#endif
/* wm_files.c */
+
void wm_history_file_read(void);
struct wmHomeFileRead_Params {
@@ -62,6 +63,16 @@ struct wmHomeFileRead_Params {
const char *app_template_override;
};
+/**
+ * Called on startup, (context entirely filled with NULLs)
+ * or called for 'New File' both `startup.blend` and `userpref.blend` are checked.
+ *
+ * \param r_params_file_read_post: Support postponed initialization,
+ * needed for initial startup when only some sub-systems have been initialized.
+ * When non-null, #wm_file_read_post doesn't run, instead it's arguments are stored
+ * in this return argument.
+ * The caller is responsible for calling #wm_homefile_read_post with this return argument.
+ */
void wm_homefile_read_ex(struct bContext *C,
const struct wmHomeFileRead_Params *params_homefile,
struct ReportList *reports,
@@ -70,16 +81,27 @@ void wm_homefile_read(struct bContext *C,
const struct wmHomeFileRead_Params *params_homefile,
struct ReportList *reports);
+/**
+ * Special case, support deferred execution of #wm_file_read_post,
+ * Needed when loading for the first time to workaround order of initialization bug, see T89046.
+ */
void wm_homefile_read_post(struct bContext *C,
const struct wmFileReadPost_Params *params_file_read_post);
void wm_file_read_report(bContext *C, struct Main *bmain);
void wm_close_file_dialog(bContext *C, struct wmGenericCallback *post_action);
+/**
+ * \return True if the dialog was created, the calling operator should return #OPERATOR_INTERFACE
+ * then.
+ */
bool wm_operator_close_file_dialog_if_needed(bContext *C,
wmOperator *op,
wmGenericCallbackFn exec_fn);
-bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm);
+/**
+ * Check if there is data that would be lost when closing the current file without saving.
+ */
+bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWindowManager *wm);
void WM_OT_save_homefile(struct wmOperatorType *ot);
void WM_OT_save_userpref(struct wmOperatorType *ot);
@@ -99,6 +121,7 @@ void WM_OT_save_as_mainfile(struct wmOperatorType *ot);
void WM_OT_save_mainfile(struct wmOperatorType *ot);
/* wm_files_link.c */
+
void WM_OT_link(struct wmOperatorType *ot);
void WM_OT_append(struct wmOperatorType *ot);
diff --git a/source/blender/windowmanager/wm_surface.h b/source/blender/windowmanager/wm_surface.h
index a2483d38154..e924b1e47ad 100644
--- a/source/blender/windowmanager/wm_surface.h
+++ b/source/blender/windowmanager/wm_surface.h
@@ -39,6 +39,8 @@ typedef struct wmSurface {
void *customdata;
void (*draw)(struct bContext *);
+ /* To evaluate the surface's depsgraph. Called as part of the main loop. */
+ void (*do_depsgraph)(struct bContext *C);
/** Free customdata, not the surface itself (done by wm_surface API) */
void (*free_data)(struct wmSurface *);
@@ -56,6 +58,9 @@ void wm_surfaces_free(void);
/* Utils */
void wm_surfaces_iter(struct bContext *C, void (*cb)(struct bContext *, wmSurface *));
+/* Evaluation. */
+void wm_surfaces_do_depsgraph(struct bContext *C);
+
/* Drawing */
void wm_surface_make_drawable(wmSurface *surface);
void wm_surface_clear_drawable(void);
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index f205f923ec8..b003a4f92e7 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -30,41 +30,87 @@ extern "C" {
#endif
/* *************** internal api ************** */
+
+/**
+ * \note #bContext can be null in background mode because we don't
+ * need to event handling.
+ */
void wm_ghost_init(bContext *C);
void wm_ghost_exit(void);
+/**
+ * This one should correctly check for apple top header...
+ * done for Cocoa: returns window contents (and not frame) max size.
+ */
void wm_get_screensize(int *r_width, int *r_height);
+/**
+ * Size of all screens (desktop), useful since the mouse is bound by this.
+ */
void wm_get_desktopsize(int *r_width, int *r_height);
+/**
+ * Don't change context itself.
+ */
wmWindow *wm_window_new(const struct Main *bmain,
wmWindowManager *wm,
wmWindow *parent,
bool dialog);
-wmWindow *wm_window_copy(struct Main *bmain,
- wmWindowManager *wm,
- wmWindow *win_src,
- const bool duplicate_layout,
- const bool child);
-wmWindow *wm_window_copy_test(bContext *C,
- wmWindow *win_src,
- const bool duplicate_layout,
- const bool child);
+/**
+ * Part of `wm_window.c` API.
+ */
+wmWindow *wm_window_copy(
+ struct Main *bmain, wmWindowManager *wm, wmWindow *win_src, bool duplicate_layout, bool child);
+/**
+ * A higher level version of copy that tests the new window can be added.
+ * (called from the operator directly).
+ */
+wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src, bool duplicate_layout, bool child);
+/**
+ * Including window itself.
+ * \param C: can be NULL.
+ * \note #ED_screen_exit should have been called.
+ */
void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win);
+/**
+ * This is event from ghost, or exit-Blender operator.
+ */
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win);
void wm_window_title(wmWindowManager *wm, wmWindow *win);
+/**
+ * Initialize #wmWindow without `ghostwin`, open these and clear.
+ *
+ * Window size is read from window, if 0 it uses prefsize
+ * called in #WM_check, also initialize stuff after file read.
+ *
+ * \warning After running, `win->ghostwin` can be NULL in rare cases
+ * (where OpenGL driver fails to create a context for eg).
+ * We could remove them with #wm_window_ghostwindows_remove_invalid
+ * but better not since caller may continue to use.
+ * Instead, caller needs to handle the error case and cleanup.
+ */
void wm_window_ghostwindows_ensure(wmWindowManager *wm);
+/**
+ * Call after #wm_window_ghostwindows_ensure or #WM_check
+ * (after loading a new file) in the unlikely event a window couldn't be created.
+ */
void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm);
void wm_window_process_events(const bContext *C);
void wm_window_clear_drawable(wmWindowManager *wm);
void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win);
+/**
+ * Reset active the current window opengl drawing context.
+ */
void wm_window_reset_drawable(void);
void wm_window_raise(wmWindow *win);
void wm_window_lower(wmWindow *win);
void wm_window_set_size(wmWindow *win, int width, int height);
void wm_window_get_position(wmWindow *win, int *r_pos_x, int *r_pos_y);
+/**
+ * \brief Push rendered buffer to the screen.
+ */
void wm_window_swap_buffers(wmWindow *win);
void wm_window_set_swap_interval(wmWindow *win, int interval);
bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
@@ -79,8 +125,19 @@ void wm_window_IME_end(wmWindow *win);
#endif
/* *************** window operators ************** */
+
int wm_window_close_exec(bContext *C, struct wmOperator *op);
+/**
+ * Full-screen operator callback.
+ */
int wm_window_fullscreen_toggle_exec(bContext *C, struct wmOperator *op);
+/**
+ * Call the quit confirmation prompt or exit directly if needed. The use can
+ * still cancel via the confirmation popup. Also, this may not quit Blender
+ * immediately, but rather schedule the closing.
+ *
+ * \param win: The window to show the confirmation popup/window in.
+ */
void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) ATTR_NONNULL();
int wm_window_new_exec(bContext *C, struct wmOperator *op);
diff --git a/source/blender/windowmanager/xr/intern/wm_xr.c b/source/blender/windowmanager/xr/intern/wm_xr.c
index 8891840cb75..36bd03ed3ea 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr.c
@@ -24,19 +24,22 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_main.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "DNA_scene_types.h"
#include "DNA_windowmanager_types.h"
-#include "DEG_depsgraph.h"
-
-#include "MEM_guardedalloc.h"
+#include "ED_screen.h"
#include "GHOST_C-api.h"
#include "GPU_platform.h"
+#include "MEM_guardedalloc.h"
+
#include "WM_api.h"
#include "wm_surface.h"
@@ -137,7 +140,7 @@ bool wm_xr_events_handle(wmWindowManager *wm)
/* Process OpenXR action events. */
if (WM_xr_session_is_ready(&wm->xr)) {
- wm_xr_session_actions_update(&wm->xr);
+ wm_xr_session_actions_update(wm);
}
/* wm_window_process_events() uses the return value to determine if it can put the main thread
@@ -172,6 +175,12 @@ void wm_xr_runtime_data_free(wmXrRuntimeData **runtime)
* first call, see comment above. */
(*runtime)->context = NULL;
+ if ((*runtime)->area) {
+ wmWindowManager *wm = G_MAIN->wm.first;
+ wmWindow *win = wm_xr_session_root_window_or_fallback_get(wm, (*runtime));
+ ED_area_offscreen_free(wm, win, (*runtime)->area);
+ (*runtime)->area = NULL;
+ }
wm_xr_session_data_free(&(*runtime)->session_state);
WM_xr_actionmaps_clear(*runtime);
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_action.c b/source/blender/windowmanager/xr/intern/wm_xr_action.c
index ba347c537ec..b5a606b4298 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_action.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_action.c
@@ -118,7 +118,7 @@ static wmXrAction *action_create(const char *action_name,
action->states = MEM_calloc_arrayN(count, size, "XrAction_States");
action->states_prev = MEM_calloc_arrayN(count, size, "XrAction_StatesPrev");
- const bool is_float_action = (type == XR_FLOAT_INPUT || type == XR_VECTOR2F_INPUT);
+ const bool is_float_action = ELEM(type, XR_FLOAT_INPUT, XR_VECTOR2F_INPUT);
const bool is_button_action = (is_float_action || type == XR_BOOLEAN_INPUT);
if (is_float_action) {
action->float_thresholds = MEM_calloc_arrayN(
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c
index 8903305adb4..076f279ccbb 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c
@@ -85,9 +85,6 @@ static XrActionMapBinding *wm_xr_actionmap_binding_find_except(XrActionMapItem *
return NULL;
}
-/**
- * Ensure unique name among all action map bindings.
- */
void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBinding *amb)
{
char name[MAX_NAME];
@@ -118,7 +115,6 @@ void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBind
static XrActionMapBinding *wm_xr_actionmap_binding_copy(XrActionMapBinding *amb_src)
{
XrActionMapBinding *amb_dst = MEM_dupallocN(amb_src);
-
amb_dst->prev = amb_dst->next = NULL;
return amb_dst;
@@ -198,10 +194,6 @@ static void wm_xr_actionmap_item_properties_free(XrActionMapItem *ami)
}
}
-/**
- * Similar to #wm_xr_actionmap_item_properties_set()
- * but checks for the #eXrActionType and #wmOperatorType having changed.
- */
void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami)
{
switch (ami->type) {
@@ -278,9 +270,6 @@ static XrActionMapItem *wm_xr_actionmap_item_find_except(XrActionMap *actionmap,
return NULL;
}
-/**
- * Ensure unique name among all action map items.
- */
void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem *ami)
{
char name[MAX_NAME];
@@ -308,25 +297,29 @@ void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem
BLI_strncpy(ami->name, name, MAX_NAME);
}
-static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami)
+static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami_src)
{
- XrActionMapItem *amin = MEM_dupallocN(ami);
-
- amin->prev = amin->next = NULL;
+ XrActionMapItem *ami_dst = MEM_dupallocN(ami_src);
+ ami_dst->prev = ami_dst->next = NULL;
- if (amin->op_properties) {
- amin->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
- WM_operator_properties_create(amin->op_properties_ptr, amin->op);
+ BLI_listbase_clear(&ami_dst->bindings);
+ LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami_src->bindings) {
+ XrActionMapBinding *amb_new = wm_xr_actionmap_binding_copy(amb);
+ BLI_addtail(&ami_dst->bindings, amb_new);
+ }
- amin->op_properties = IDP_CopyProperty(amin->op_properties);
- amin->op_properties_ptr->data = amin->op_properties;
+ if (ami_dst->op_properties) {
+ ami_dst->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
+ WM_operator_properties_create(ami_dst->op_properties_ptr, ami_dst->op);
+ ami_dst->op_properties = IDP_CopyProperty(ami_src->op_properties);
+ ami_dst->op_properties_ptr->data = ami_dst->op_properties;
}
else {
- amin->op_properties = NULL;
- amin->op_properties_ptr = NULL;
+ ami_dst->op_properties = NULL;
+ ami_dst->op_properties_ptr = NULL;
}
- return amin;
+ return ami_dst;
}
XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionMapItem *ami_src)
@@ -411,9 +404,6 @@ static XrActionMap *wm_xr_actionmap_find_except(wmXrRuntimeData *runtime,
return NULL;
}
-/**
- * Ensure unique name among all action maps.
- */
void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *actionmap)
{
char name[MAX_NAME];
@@ -444,10 +434,9 @@ void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *action
static XrActionMap *wm_xr_actionmap_copy(XrActionMap *am_src)
{
XrActionMap *am_dst = MEM_dupallocN(am_src);
-
am_dst->prev = am_dst->next = NULL;
- BLI_listbase_clear(&am_dst->items);
+ BLI_listbase_clear(&am_dst->items);
LISTBASE_FOREACH (XrActionMapItem *, ami, &am_src->items) {
XrActionMapItem *ami_new = wm_xr_actionmap_item_copy(ami);
BLI_addtail(&am_dst->items, ami_new);
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c
index bbb73fc2007..5d0163af5e1 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_draw.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c
@@ -24,12 +24,17 @@
#include <string.h>
+#include "BKE_context.h"
+
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "ED_view3d_offscreen.h"
#include "GHOST_C-api.h"
+#include "GPU_batch_presets.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "GPU_viewport.h"
@@ -44,6 +49,16 @@ void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4])
copy_v3_v3(r_mat[3], pose->position);
}
+void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4])
+{
+ wm_xr_pose_to_mat(pose, r_mat);
+
+ BLI_assert(scale > 0.0f);
+ mul_v3_fl(r_mat[0], scale);
+ mul_v3_fl(r_mat[1], scale);
+ mul_v3_fl(r_mat[2], scale);
+}
+
void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4])
{
float iquat[4];
@@ -52,15 +67,32 @@ void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4])
translate_m4(r_imat, -pose->position[0], -pose->position[1], -pose->position[2]);
}
+void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4])
+{
+ float iquat[4];
+ invert_qt_qt_normalized(iquat, pose->orientation_quat);
+ quat_to_mat4(r_imat, iquat);
+
+ BLI_assert(scale > 0.0f);
+ scale = 1.0f / scale;
+ mul_v3_fl(r_imat[0], scale);
+ mul_v3_fl(r_imat[1], scale);
+ mul_v3_fl(r_imat[2], scale);
+
+ translate_m4(r_imat, -pose->position[0], -pose->position[1], -pose->position[2]);
+}
+
static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data,
const GHOST_XrDrawViewInfo *draw_view,
const XrSessionSettings *session_settings,
- float r_view_mat[4][4],
- float r_proj_mat[4][4])
+ const wmXrSessionState *session_state,
+ float r_viewmat[4][4],
+ float r_projmat[4][4])
{
GHOST_XrPose eye_pose;
- float eye_inv[4][4], base_inv[4][4];
+ float eye_inv[4][4], base_inv[4][4], nav_inv[4][4], m[4][4];
+ /* Calculate inverse eye matrix. */
copy_qt_qt(eye_pose.orientation_quat, draw_view->eye_pose.orientation_quat);
copy_v3_v3(eye_pose.position, draw_view->eye_pose.position);
if ((session_settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
@@ -71,12 +103,14 @@ static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data,
}
wm_xr_pose_to_imat(&eye_pose, eye_inv);
- /* Calculate the base pose matrix (in world space!). */
- wm_xr_pose_to_imat(&draw_data->base_pose, base_inv);
- mul_m4_m4m4(r_view_mat, eye_inv, base_inv);
+ /* Apply base pose and navigation. */
+ wm_xr_pose_scale_to_imat(&draw_data->base_pose, draw_data->base_scale, base_inv);
+ wm_xr_pose_scale_to_imat(&session_state->nav_pose_prev, session_state->nav_scale_prev, nav_inv);
+ mul_m4_m4m4(m, eye_inv, base_inv);
+ mul_m4_m4m4(r_viewmat, m, nav_inv);
- perspective_m4_fov(r_proj_mat,
+ perspective_m4_fov(r_projmat,
draw_view->fov.angle_left,
draw_view->fov.angle_right,
draw_view->fov.angle_up,
@@ -105,12 +139,6 @@ static void wm_xr_draw_viewport_buffers_to_active_framebuffer(
GPU_viewport_draw_to_screen_ex(vp->viewport, 0, &rect, draw_view->expects_srgb_buffer, true);
}
-/**
- * \brief Draw a viewport for a single eye.
- *
- * This is the main viewport drawing function for VR sessions. It's assigned to Ghost-XR as a
- * callback (see GHOST_XrDrawViewFunc()) and executed for each view (read: eye).
- */
void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
{
wmXrDrawData *draw_data = customdata;
@@ -126,7 +154,7 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
BLI_assert(WM_xr_session_is_ready(xr_data));
wm_xr_session_draw_data_update(session_state, settings, draw_view, draw_data);
- wm_xr_draw_matrices_create(draw_data, draw_view, settings, viewmat, winmat);
+ wm_xr_draw_matrices_create(draw_data, draw_view, settings, session_state, viewmat, winmat);
wm_xr_session_state_update(settings, draw_data, draw_view, session_state);
if (!wm_xr_session_surface_offscreen_ensure(surface_data, draw_view)) {
@@ -145,7 +173,7 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
ED_view3d_draw_offscreen_simple(draw_data->depsgraph,
draw_data->scene,
&settings->shading,
- settings->shading.type,
+ (eDrawType)settings->shading.type,
draw_view->width,
draw_view->height,
display_flags,
@@ -153,6 +181,7 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
winmat,
settings->clip_start,
settings->clip_end,
+ true,
false,
true,
NULL,
@@ -172,3 +201,200 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
wm_xr_draw_viewport_buffers_to_active_framebuffer(xr_data->runtime, surface_data, draw_view);
}
+
+static GPUBatch *wm_xr_controller_model_batch_create(GHOST_XrContextHandle xr_context,
+ const char *subaction_path)
+{
+ GHOST_XrControllerModelData model_data;
+
+ if (!GHOST_XrGetControllerModelData(xr_context, subaction_path, &model_data) ||
+ model_data.count_vertices < 1) {
+ return NULL;
+ }
+
+ GPUVertFormat format = {0};
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, model_data.count_vertices);
+ void *vbo_data = GPU_vertbuf_get_data(vbo);
+ memcpy(
+ vbo_data, model_data.vertices, model_data.count_vertices * sizeof(model_data.vertices[0]));
+
+ GPUIndexBuf *ibo = NULL;
+ if (model_data.count_indices > 0 && ((model_data.count_indices % 3) == 0)) {
+ GPUIndexBufBuilder ibo_builder;
+ const unsigned int prim_len = model_data.count_indices / 3;
+ GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, prim_len, model_data.count_vertices);
+ for (unsigned int i = 0; i < prim_len; ++i) {
+ const uint32_t *idx = &model_data.indices[i * 3];
+ GPU_indexbuf_add_tri_verts(&ibo_builder, idx[0], idx[1], idx[2]);
+ }
+ ibo = GPU_indexbuf_build(&ibo_builder);
+ }
+
+ return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, ibo, GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
+}
+
+static void wm_xr_controller_model_draw(const XrSessionSettings *settings,
+ GHOST_XrContextHandle xr_context,
+ wmXrSessionState *state)
+{
+ GHOST_XrControllerModelData model_data;
+
+ float color[4];
+ switch (settings->controller_draw_style) {
+ case XR_CONTROLLER_DRAW_DARK:
+ case XR_CONTROLLER_DRAW_DARK_RAY:
+ color[0] = color[1] = color[2] = 0.0f, color[3] = 0.4f;
+ break;
+ case XR_CONTROLLER_DRAW_LIGHT:
+ case XR_CONTROLLER_DRAW_LIGHT_RAY:
+ color[0] = 0.422f, color[1] = 0.438f, color[2] = 0.446f, color[3] = 0.4f;
+ break;
+ }
+
+ GPU_depth_test(GPU_DEPTH_NONE);
+ GPU_blend(GPU_BLEND_ALPHA);
+
+ LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
+ GPUBatch *model = controller->model;
+ if (!model) {
+ model = controller->model = wm_xr_controller_model_batch_create(xr_context,
+ controller->subaction_path);
+ }
+
+ if (model &&
+ GHOST_XrGetControllerModelData(xr_context, controller->subaction_path, &model_data) &&
+ model_data.count_components > 0) {
+ GPU_batch_program_set_builtin(model, GPU_SHADER_3D_UNIFORM_COLOR);
+ GPU_batch_uniform_4fv(model, "color", color);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(controller->grip_mat);
+ for (unsigned int component_idx = 0; component_idx < model_data.count_components;
+ ++component_idx) {
+ const GHOST_XrControllerModelComponent *component = &model_data.components[component_idx];
+ GPU_matrix_push();
+ GPU_matrix_mul(component->transform);
+ GPU_batch_draw_range(model,
+ model->elem ? component->index_offset : component->vertex_offset,
+ model->elem ? component->index_count : component->vertex_count);
+ GPU_matrix_pop();
+ }
+ GPU_matrix_pop();
+ }
+ else {
+ /* Fallback. */
+ const float scale = 0.05f;
+ GPUBatch *sphere = GPU_batch_preset_sphere(2);
+ GPU_batch_program_set_builtin(sphere, GPU_SHADER_3D_UNIFORM_COLOR);
+ GPU_batch_uniform_4fv(sphere, "color", color);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(controller->grip_mat);
+ GPU_matrix_scale_1f(scale);
+ GPU_batch_draw(sphere);
+ GPU_matrix_pop();
+ }
+ }
+}
+
+static void wm_xr_controller_aim_draw(const XrSessionSettings *settings, wmXrSessionState *state)
+{
+ bool draw_ray;
+ switch (settings->controller_draw_style) {
+ case XR_CONTROLLER_DRAW_DARK:
+ case XR_CONTROLLER_DRAW_LIGHT:
+ draw_ray = false;
+ break;
+ case XR_CONTROLLER_DRAW_DARK_RAY:
+ case XR_CONTROLLER_DRAW_LIGHT_RAY:
+ draw_ray = true;
+ break;
+ }
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_FLAT_COLOR);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+
+ immUniform1f("lineWidth", 3.0f * U.pixelsize);
+
+ if (draw_ray) {
+ const uchar color[4] = {89, 89, 255, 127};
+ const float scale = settings->clip_end;
+ float ray[3];
+
+ GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
+ GPU_blend(GPU_BLEND_ALPHA);
+
+ immBegin(GPU_PRIM_LINES, (uint)BLI_listbase_count(&state->controllers) * 2);
+
+ LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
+ const float(*mat)[4] = controller->aim_mat;
+ madd_v3_v3v3fl(ray, mat[3], mat[2], -scale);
+
+ immAttrSkip(col);
+ immVertex3fv(pos, mat[3]);
+ immAttr4ubv(col, color);
+ immVertex3fv(pos, ray);
+ }
+
+ immEnd();
+ }
+ else {
+ const uchar r[4] = {255, 51, 82, 255};
+ const uchar g[4] = {139, 220, 0, 255};
+ const uchar b[4] = {40, 144, 255, 255};
+ const float scale = 0.01f;
+ float x_axis[3], y_axis[3], z_axis[3];
+
+ GPU_depth_test(GPU_DEPTH_NONE);
+ GPU_blend(GPU_BLEND_NONE);
+
+ immBegin(GPU_PRIM_LINES, (uint)BLI_listbase_count(&state->controllers) * 6);
+
+ LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
+ const float(*mat)[4] = controller->aim_mat;
+ madd_v3_v3v3fl(x_axis, mat[3], mat[0], scale);
+ madd_v3_v3v3fl(y_axis, mat[3], mat[1], scale);
+ madd_v3_v3v3fl(z_axis, mat[3], mat[2], scale);
+
+ immAttrSkip(col);
+ immVertex3fv(pos, mat[3]);
+ immAttr4ubv(col, r);
+ immVertex3fv(pos, x_axis);
+
+ immAttrSkip(col);
+ immVertex3fv(pos, mat[3]);
+ immAttr4ubv(col, g);
+ immVertex3fv(pos, y_axis);
+
+ immAttrSkip(col);
+ immVertex3fv(pos, mat[3]);
+ immAttr4ubv(col, b);
+ immVertex3fv(pos, z_axis);
+ }
+
+ immEnd();
+ }
+
+ immUnbindProgram();
+}
+
+void wm_xr_draw_controllers(const bContext *UNUSED(C), ARegion *UNUSED(region), void *customdata)
+{
+ wmXrData *xr = customdata;
+ const XrSessionSettings *settings = &xr->session_settings;
+ GHOST_XrContextHandle xr_context = xr->runtime->context;
+ wmXrSessionState *state = &xr->runtime->session_state;
+
+ wm_xr_controller_model_draw(settings, xr_context, state);
+ wm_xr_controller_aim_draw(settings, state);
+}
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
index fc54e261f79..e2368901757 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h
+++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
@@ -33,16 +33,20 @@ typedef struct wmXrSessionState {
GHOST_XrPose viewer_pose;
/** The last known view matrix, calculated from above's viewer pose. */
float viewer_viewmat[4][4];
+ /** The last known viewer matrix, without navigation applied. */
+ float viewer_mat_base[4][4];
float focal_len;
/** Copy of XrSessionSettings.base_pose_ data to detect changes that need
* resetting to base pose. */
- char prev_base_pose_type; /* eXRSessionBasePoseType */
+ char prev_base_pose_type; /* #eXRSessionBasePoseType */
Object *prev_base_pose_object;
/** Copy of XrSessionSettings.flag created on the last draw call, stored to detect changes. */
int prev_settings_flag;
/** Copy of wmXrDrawData.base_pose. */
GHOST_XrPose prev_base_pose;
+ /** Copy of wmXrDrawData.base_scale. */
+ float prev_base_scale;
/** Copy of GHOST_XrDrawViewInfo.local_pose. */
GHOST_XrPose prev_local_pose;
/** Copy of wmXrDrawData.eye_position_ofs. */
@@ -51,8 +55,17 @@ typedef struct wmXrSessionState {
bool force_reset_to_base_pose;
bool is_view_data_set;
+ /** Current navigation transforms. */
+ GHOST_XrPose nav_pose;
+ float nav_scale;
+ /** Navigation transforms from the last actions sync, used to calculate the viewer/controller
+ * poses. */
+ GHOST_XrPose nav_pose_prev;
+ float nav_scale_prev;
+ bool is_navigation_dirty;
+
/** Last known controller data. */
- ListBase controllers; /* wmXrController */
+ ListBase controllers; /* #wmXrController */
/** The currently active action set that will be updated on calls to
* wm_xr_session_actions_update(). If NULL, all action sets will be treated as active and
@@ -67,11 +80,14 @@ typedef struct wmXrRuntimeData {
* be an invalid reference, i.e. the window may have been closed. */
wmWindow *session_root_win;
+ /** Off-screen area used for XR events. */
+ struct ScrArea *area;
+
/** Although this struct is internal, RNA gets a handle to this for state information queries. */
wmXrSessionState session_state;
wmXrSessionExitFn exit_fn;
- ListBase actionmaps; /* XrActionMap */
+ ListBase actionmaps; /* #XrActionMap */
short actactionmap;
short selactionmap;
} wmXrRuntimeData;
@@ -84,7 +100,12 @@ typedef struct wmXrViewportPair {
typedef struct {
/** Off-screen buffers/viewports for each view. */
- ListBase viewports; /* wmXrViewportPair */
+ ListBase viewports; /* #wmXrViewportPair */
+
+ /** Dummy region type for controller draw callback. */
+ struct ARegionType *controller_art;
+ /** Controller draw callback handle. */
+ void *controller_draw_handle;
} wmXrSurfaceData;
typedef struct wmXrDrawData {
@@ -98,6 +119,8 @@ typedef struct wmXrDrawData {
* space). With positional tracking enabled, it should be the same as the base pose, when
* disabled it also contains a location delta from the moment the option was toggled. */
GHOST_XrPose base_pose;
+ /** Base scale (uniform, world space). */
+ float base_scale;
/** Offset to _substract_ from the OpenXR eye and viewer pose to get the wanted effective pose
* (e.g. a pose exactly at the landmark position). */
float eye_position_ofs[3]; /* Local/view space. */
@@ -111,12 +134,18 @@ typedef struct wmXrController {
/input/trigger/value, interaction_path = /user/hand/left/input/trigger/value).
*/
char subaction_path[64];
- /* Pose (in world space) that represents the user's hand when holding the controller.*/
+
+ /** Pose (in world space) that represents the user's hand when holding the controller. */
GHOST_XrPose grip_pose;
float grip_mat[4][4];
- /* Pose (in world space) that represents the controller's aiming source. */
+ float grip_mat_base[4][4];
+ /** Pose (in world space) that represents the controller's aiming source. */
GHOST_XrPose aim_pose;
float aim_mat[4][4];
+ float aim_mat_base[4][4];
+
+ /** Controller model. */
+ struct GPUBatch *model;
} wmXrController;
typedef struct wmXrAction {
@@ -172,14 +201,23 @@ typedef struct wmXrActionSet {
ListBase active_haptic_actions;
} wmXrActionSet;
+/* wm_xr.c */
wmXrRuntimeData *wm_xr_runtime_data_create(void);
void wm_xr_runtime_data_free(wmXrRuntimeData **runtime);
-void wm_xr_session_data_free(wmXrSessionState *state);
-void wm_xr_session_draw_data_update(const wmXrSessionState *state,
+/* wm_xr_session.c */
+void wm_xr_session_data_free(wmXrSessionState *state);
+wmWindow *wm_xr_session_root_window_or_fallback_get(const wmWindowManager *wm,
+ const wmXrRuntimeData *runtime_data);
+void wm_xr_session_draw_data_update(wmXrSessionState *state,
const XrSessionSettings *settings,
const GHOST_XrDrawViewInfo *draw_view,
wmXrDrawData *draw_data);
+/**
+ * Update information that is only stored for external state queries. E.g. for Python API to
+ * request the current (as in, last known) viewer pose.
+ * Controller data and action sets will be updated separately via wm_xr_session_actions_update().
+ */
void wm_xr_session_state_update(const XrSessionSettings *settings,
const wmXrDrawData *draw_data,
const GHOST_XrDrawViewInfo *draw_view,
@@ -190,12 +228,23 @@ void *wm_xr_session_gpu_binding_context_create(void);
void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle context);
void wm_xr_session_actions_init(wmXrData *xr);
-void wm_xr_session_actions_update(wmXrData *xr);
+void wm_xr_session_actions_update(wmWindowManager *wm);
void wm_xr_session_controller_data_populate(const wmXrAction *grip_action,
const wmXrAction *aim_action,
wmXrData *xr);
void wm_xr_session_controller_data_clear(wmXrSessionState *state);
+/* wm_xr_draw.c */
+
void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4]);
+void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4]);
void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4]);
+void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4]);
+/**
+ * \brief Draw a viewport for a single eye.
+ *
+ * This is the main viewport drawing function for VR sessions. It's assigned to Ghost-XR as a
+ * callback (see GHOST_XrDrawViewFunc()) and executed for each view (read: eye).
+ */
void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata);
+void wm_xr_draw_controllers(const struct bContext *C, struct ARegion *region, void *customdata);
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
new file mode 100644
index 00000000000..9c2eaefd61c
--- /dev/null
+++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
@@ -0,0 +1,1537 @@
+/*
+ * 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 wm
+ *
+ * \name Window-Manager XR Operators
+ *
+ * Collection of XR-related operators.
+ */
+
+#include "BLI_kdopbvh.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_main.h"
+#include "BKE_screen.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+
+#include "GHOST_Types.h"
+
+#include "GPU_immediate.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "wm_xr_intern.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Conditions
+ * \{ */
+
+/* op->poll */
+static bool wm_xr_operator_sessionactive(bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ return WM_xr_session_is_ready(&wm->xr);
+}
+
+static bool wm_xr_operator_test_event(const wmOperator *op, const wmEvent *event)
+{
+ if (event->type != EVT_XR_ACTION) {
+ return false;
+ }
+
+ BLI_assert(event->custom == EVT_DATA_XR);
+ BLI_assert(event->customdata);
+
+ wmXrActionData *actiondata = event->customdata;
+ return (actiondata->ot == op->type &&
+ IDP_EqualsProperties(actiondata->op_properties, op->properties));
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Session Toggle
+ *
+ * Toggles an XR session, creating an XR context if necessary.
+ * \{ */
+
+static void wm_xr_session_update_screen(Main *bmain, const wmXrData *xr_data)
+{
+ const bool session_exists = WM_xr_session_exists(xr_data);
+
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, slink, &area->spacedata) {
+ if (slink->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)slink;
+
+ if (v3d->flag & V3D_XR_SESSION_MIRROR) {
+ ED_view3d_xr_mirror_update(area, v3d, session_exists);
+ }
+
+ if (session_exists) {
+ wmWindowManager *wm = bmain->wm.first;
+ const Scene *scene = WM_windows_scene_get_from_screen(wm, screen);
+
+ ED_view3d_xr_shading_update(wm, v3d, scene);
+ }
+ /* Ensure no 3D View is tagged as session root. */
+ else {
+ v3d->runtime.flag &= ~V3D_RUNTIME_XR_SESSION_ROOT;
+ }
+ }
+ }
+ }
+ }
+
+ WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
+}
+
+static void wm_xr_session_update_screen_on_exit_cb(const wmXrData *xr_data)
+{
+ /* Just use G_MAIN here, storing main isn't reliable enough on file read or exit. */
+ wm_xr_session_update_screen(G_MAIN, xr_data);
+}
+
+static int wm_xr_session_toggle_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ /* Lazily-create XR context - tries to dynamic-link to the runtime,
+ * reading `active_runtime.json`. */
+ if (wm_xr_init(wm) == false) {
+ return OPERATOR_CANCELLED;
+ }
+
+ v3d->runtime.flag |= V3D_RUNTIME_XR_SESSION_ROOT;
+ wm_xr_session_toggle(wm, win, wm_xr_session_update_screen_on_exit_cb);
+ wm_xr_session_update_screen(bmain, &wm->xr);
+
+ WM_event_add_notifier(C, NC_WM | ND_XR_DATA_CHANGED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static void WM_OT_xr_session_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Toggle VR Session";
+ ot->idname = "WM_OT_xr_session_toggle";
+ ot->description =
+ "Open a view for use with virtual reality headsets, or close it if already "
+ "opened";
+
+ /* callbacks */
+ ot->exec = wm_xr_session_toggle_exec;
+ ot->poll = ED_operator_view3d_active;
+
+ /* XXX INTERNAL just to hide it from the search menu by default, an Add-on will expose it in the
+ * UI instead. Not meant as a permanent solution. */
+ ot->flag = OPTYPE_INTERNAL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Grab Utilities
+ * \{ */
+
+typedef struct XrGrabData {
+ float mat_prev[4][4];
+ float mat_other_prev[4][4];
+ bool bimanual_prev;
+ bool loc_lock, locz_lock, rot_lock, rotz_lock, scale_lock;
+} XrGrabData;
+
+static void wm_xr_grab_init(wmOperator *op)
+{
+ BLI_assert(op->customdata == NULL);
+
+ op->customdata = MEM_callocN(sizeof(XrGrabData), __func__);
+}
+
+static void wm_xr_grab_uninit(wmOperator *op)
+{
+ MEM_SAFE_FREE(op->customdata);
+}
+
+static void wm_xr_grab_update(wmOperator *op, const wmXrActionData *actiondata)
+{
+ XrGrabData *data = op->customdata;
+
+ quat_to_mat4(data->mat_prev, actiondata->controller_rot);
+ copy_v3_v3(data->mat_prev[3], actiondata->controller_loc);
+
+ if (actiondata->bimanual) {
+ quat_to_mat4(data->mat_other_prev, actiondata->controller_rot_other);
+ copy_v3_v3(data->mat_other_prev[3], actiondata->controller_loc_other);
+ data->bimanual_prev = true;
+ }
+ else {
+ data->bimanual_prev = false;
+ }
+}
+
+static void orient_mat_z_normalized(float R[4][4], const float z_axis[3])
+{
+ const float scale = len_v3(R[0]);
+ float x_axis[3], y_axis[3];
+
+ cross_v3_v3v3(y_axis, z_axis, R[0]);
+ normalize_v3(y_axis);
+ mul_v3_v3fl(R[1], y_axis, scale);
+
+ cross_v3_v3v3(x_axis, R[1], z_axis);
+ normalize_v3(x_axis);
+ mul_v3_v3fl(R[0], x_axis, scale);
+
+ mul_v3_v3fl(R[2], z_axis, scale);
+}
+
+static void wm_xr_navlocks_apply(const float nav_mat[4][4],
+ const float nav_inv[4][4],
+ bool loc_lock,
+ bool locz_lock,
+ bool rotz_lock,
+ float r_prev[4][4],
+ float r_curr[4][4])
+{
+ /* Locked in base pose coordinates. */
+ float prev_base[4][4], curr_base[4][4];
+
+ mul_m4_m4m4(prev_base, nav_inv, r_prev);
+ mul_m4_m4m4(curr_base, nav_inv, r_curr);
+
+ if (rotz_lock) {
+ const float z_axis[3] = {0.0f, 0.0f, 1.0f};
+ orient_mat_z_normalized(prev_base, z_axis);
+ orient_mat_z_normalized(curr_base, z_axis);
+ }
+
+ if (loc_lock) {
+ copy_v3_v3(curr_base[3], prev_base[3]);
+ }
+ else if (locz_lock) {
+ curr_base[3][2] = prev_base[3][2];
+ }
+
+ mul_m4_m4m4(r_prev, nav_mat, prev_base);
+ mul_m4_m4m4(r_curr, nav_mat, curr_base);
+}
+
+/**
+ * Compute transformation delta for a one-handed grab interaction.
+ *
+ * \param actiondata: Contains current controller pose in world space.
+ * \param data: Contains previous controller pose in world space.
+ *
+ * The delta is computed as the difference between the current and previous
+ * controller poses i.e. delta = curr * prev^-1.
+ */
+static void wm_xr_grab_compute(const wmXrActionData *actiondata,
+ const XrGrabData *data,
+ const float nav_mat[4][4],
+ const float nav_inv[4][4],
+ bool reverse,
+ float r_delta[4][4])
+{
+ const bool nav_lock = (nav_mat && nav_inv);
+ float prev[4][4], curr[4][4];
+
+ if (!data->rot_lock) {
+ copy_m4_m4(prev, data->mat_prev);
+ zero_v3(prev[3]);
+ quat_to_mat4(curr, actiondata->controller_rot);
+ }
+ else {
+ unit_m4(prev);
+ unit_m4(curr);
+ }
+
+ if (!data->loc_lock || nav_lock) {
+ copy_v3_v3(prev[3], data->mat_prev[3]);
+ copy_v3_v3(curr[3], actiondata->controller_loc);
+ }
+
+ if (nav_lock) {
+ wm_xr_navlocks_apply(
+ nav_mat, nav_inv, data->loc_lock, data->locz_lock, data->rotz_lock, prev, curr);
+ }
+
+ if (reverse) {
+ invert_m4(curr);
+ mul_m4_m4m4(r_delta, prev, curr);
+ }
+ else {
+ invert_m4(prev);
+ mul_m4_m4m4(r_delta, curr, prev);
+ }
+}
+
+/**
+ * Compute transformation delta for a two-handed (bimanual) grab interaction.
+ *
+ * \param actiondata: Contains current controller poses in world space.
+ * \param data: Contains previous controller poses in world space.
+ *
+ * The delta is computed as the difference (delta = curr * prev^-1) between the current
+ * and previous transformations, where the transformations themselves are determined as follows:
+ * - Translation: Averaged controller positions.
+ * - Rotation: Rotation of axis line between controllers.
+ * - Scale: Distance between controllers.
+ */
+static void wm_xr_grab_compute_bimanual(const wmXrActionData *actiondata,
+ const XrGrabData *data,
+ const float nav_mat[4][4],
+ const float nav_inv[4][4],
+ bool reverse,
+ float r_delta[4][4])
+{
+ const bool nav_lock = (nav_mat && nav_inv);
+ float prev[4][4], curr[4][4];
+ unit_m4(prev);
+ unit_m4(curr);
+
+ if (!data->rot_lock) {
+ /* Rotation. */
+ float x_axis_prev[3], x_axis_curr[3], y_axis_prev[3], y_axis_curr[3], z_axis_prev[3],
+ z_axis_curr[3];
+ float m0[3][3], m1[3][3];
+ quat_to_mat3(m0, actiondata->controller_rot);
+ quat_to_mat3(m1, actiondata->controller_rot_other);
+
+ /* x-axis is the base line between the two controllers. */
+ sub_v3_v3v3(x_axis_prev, data->mat_prev[3], data->mat_other_prev[3]);
+ sub_v3_v3v3(x_axis_curr, actiondata->controller_loc, actiondata->controller_loc_other);
+ /* y-axis is the average of the controllers' y-axes. */
+ add_v3_v3v3(y_axis_prev, data->mat_prev[1], data->mat_other_prev[1]);
+ mul_v3_fl(y_axis_prev, 0.5f);
+ add_v3_v3v3(y_axis_curr, m0[1], m1[1]);
+ mul_v3_fl(y_axis_curr, 0.5f);
+ /* z-axis is the cross product of the two. */
+ cross_v3_v3v3(z_axis_prev, x_axis_prev, y_axis_prev);
+ cross_v3_v3v3(z_axis_curr, x_axis_curr, y_axis_curr);
+ /* Fix the y-axis to be orthogonal. */
+ cross_v3_v3v3(y_axis_prev, z_axis_prev, x_axis_prev);
+ cross_v3_v3v3(y_axis_curr, z_axis_curr, x_axis_curr);
+ /* Normalize. */
+ normalize_v3_v3(prev[0], x_axis_prev);
+ normalize_v3_v3(prev[1], y_axis_prev);
+ normalize_v3_v3(prev[2], z_axis_prev);
+ normalize_v3_v3(curr[0], x_axis_curr);
+ normalize_v3_v3(curr[1], y_axis_curr);
+ normalize_v3_v3(curr[2], z_axis_curr);
+ }
+
+ if (!data->loc_lock || nav_lock) {
+ /* Translation: translation of the averaged controller locations. */
+ add_v3_v3v3(prev[3], data->mat_prev[3], data->mat_other_prev[3]);
+ mul_v3_fl(prev[3], 0.5f);
+ add_v3_v3v3(curr[3], actiondata->controller_loc, actiondata->controller_loc_other);
+ mul_v3_fl(curr[3], 0.5f);
+ }
+
+ if (!data->scale_lock) {
+ /* Scaling: distance between controllers. */
+ float scale, v[3];
+
+ sub_v3_v3v3(v, data->mat_prev[3], data->mat_other_prev[3]);
+ scale = len_v3(v);
+ mul_v3_fl(prev[0], scale);
+ mul_v3_fl(prev[1], scale);
+ mul_v3_fl(prev[2], scale);
+
+ sub_v3_v3v3(v, actiondata->controller_loc, actiondata->controller_loc_other);
+ scale = len_v3(v);
+ mul_v3_fl(curr[0], scale);
+ mul_v3_fl(curr[1], scale);
+ mul_v3_fl(curr[2], scale);
+ }
+
+ if (nav_lock) {
+ wm_xr_navlocks_apply(
+ nav_mat, nav_inv, data->loc_lock, data->locz_lock, data->rotz_lock, prev, curr);
+ }
+
+ if (reverse) {
+ invert_m4(curr);
+ mul_m4_m4m4(r_delta, prev, curr);
+ }
+ else {
+ invert_m4(prev);
+ mul_m4_m4m4(r_delta, curr, prev);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Navigation Grab
+ *
+ * Navigates the scene by grabbing with XR controllers.
+ * \{ */
+
+static int wm_xr_navigation_grab_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ const wmXrActionData *actiondata = event->customdata;
+
+ wm_xr_grab_init(op);
+ wm_xr_grab_update(op, actiondata);
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_xr_navigation_grab_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ return OPERATOR_CANCELLED;
+}
+
+static bool wm_xr_navigation_grab_can_do_bimanual(const wmXrActionData *actiondata,
+ const XrGrabData *data)
+{
+ /* Returns true if: 1) Bimanual interaction is currently occurring (i.e. inputs on both
+ * controllers are pressed) and 2) bimanual interaction occurred on the last update. This second
+ * part is needed to avoid "jumpy" navigation changes when transitioning from one-handed to
+ * two-handed interaction (see #wm_xr_grab_compute/compute_bimanual() for how navigation deltas
+ * are calculated). */
+ return (actiondata->bimanual && data->bimanual_prev);
+}
+
+static bool wm_xr_navigation_grab_is_bimanual_ending(const wmXrActionData *actiondata,
+ const XrGrabData *data)
+{
+ return (!actiondata->bimanual && data->bimanual_prev);
+}
+
+static bool wm_xr_navigation_grab_is_locked(const XrGrabData *data, const bool bimanual)
+{
+ if (bimanual) {
+ return data->loc_lock && data->rot_lock && data->scale_lock;
+ }
+ /* Ignore scale lock, as one-handed interaction cannot change navigation scale. */
+ return data->loc_lock && data->rot_lock;
+}
+
+static void wm_xr_navigation_grab_apply(wmXrData *xr,
+ const wmXrActionData *actiondata,
+ const XrGrabData *data,
+ bool bimanual)
+{
+ GHOST_XrPose nav_pose;
+ float nav_scale;
+ float nav_mat[4][4], nav_inv[4][4], delta[4][4], out[4][4];
+
+ const bool need_navinv = (data->loc_lock || data->locz_lock || data->rotz_lock);
+
+ WM_xr_session_state_nav_location_get(xr, nav_pose.position);
+ WM_xr_session_state_nav_rotation_get(xr, nav_pose.orientation_quat);
+ WM_xr_session_state_nav_scale_get(xr, &nav_scale);
+
+ wm_xr_pose_scale_to_mat(&nav_pose, nav_scale, nav_mat);
+ if (need_navinv) {
+ wm_xr_pose_scale_to_imat(&nav_pose, nav_scale, nav_inv);
+ }
+
+ if (bimanual) {
+ wm_xr_grab_compute_bimanual(
+ actiondata, data, need_navinv ? nav_mat : NULL, need_navinv ? nav_inv : NULL, true, delta);
+ }
+ else {
+ wm_xr_grab_compute(
+ actiondata, data, need_navinv ? nav_mat : NULL, need_navinv ? nav_inv : NULL, true, delta);
+ }
+
+ mul_m4_m4m4(out, delta, nav_mat);
+
+ /* Limit scale to reasonable values. */
+ nav_scale = len_v3(out[0]);
+
+ if (!(nav_scale < xr->session_settings.clip_start ||
+ nav_scale > xr->session_settings.clip_end)) {
+ WM_xr_session_state_nav_location_set(xr, out[3]);
+ if (!data->rot_lock) {
+ mat4_to_quat(nav_pose.orientation_quat, out);
+ normalize_qt(nav_pose.orientation_quat);
+ WM_xr_session_state_nav_rotation_set(xr, nav_pose.orientation_quat);
+ }
+ if (!data->scale_lock && bimanual) {
+ WM_xr_session_state_nav_scale_set(xr, nav_scale);
+ }
+ }
+}
+
+static void wm_xr_navigation_grab_bimanual_state_update(const wmXrActionData *actiondata,
+ XrGrabData *data)
+{
+ if (actiondata->bimanual) {
+ if (!data->bimanual_prev) {
+ quat_to_mat4(data->mat_prev, actiondata->controller_rot);
+ copy_v3_v3(data->mat_prev[3], actiondata->controller_loc);
+ quat_to_mat4(data->mat_other_prev, actiondata->controller_rot_other);
+ copy_v3_v3(data->mat_other_prev[3], actiondata->controller_loc_other);
+ }
+ data->bimanual_prev = true;
+ }
+ else {
+ if (data->bimanual_prev) {
+ quat_to_mat4(data->mat_prev, actiondata->controller_rot);
+ copy_v3_v3(data->mat_prev[3], actiondata->controller_loc);
+ }
+ data->bimanual_prev = false;
+ }
+}
+
+static int wm_xr_navigation_grab_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ const wmXrActionData *actiondata = event->customdata;
+ XrGrabData *data = op->customdata;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmXrData *xr = &wm->xr;
+
+ const bool do_bimanual = wm_xr_navigation_grab_can_do_bimanual(actiondata, data);
+
+ data->loc_lock = RNA_boolean_get(op->ptr, "lock_location");
+ data->locz_lock = RNA_boolean_get(op->ptr, "lock_location_z");
+ data->rot_lock = RNA_boolean_get(op->ptr, "lock_rotation");
+ data->rotz_lock = RNA_boolean_get(op->ptr, "lock_rotation_z");
+ data->scale_lock = RNA_boolean_get(op->ptr, "lock_scale");
+
+ /* Check if navigation is locked. */
+ if (!wm_xr_navigation_grab_is_locked(data, do_bimanual)) {
+ /* Prevent unwanted snapping (i.e. "jumpy" navigation changes when transitioning from
+ * two-handed to one-handed interaction) at the end of a bimanual interaction. */
+ if (!wm_xr_navigation_grab_is_bimanual_ending(actiondata, data)) {
+ wm_xr_navigation_grab_apply(xr, actiondata, data, do_bimanual);
+ }
+ }
+
+ wm_xr_navigation_grab_bimanual_state_update(actiondata, data);
+
+ /* NOTE: #KM_PRESS and #KM_RELEASE are the only two values supported by XR events during event
+ * dispatching (see #wm_xr_session_action_states_interpret()). For modal XR operators, modal
+ * handling starts when an input is "pressed" (action state exceeds the action threshold) and
+ * ends when the input is "released" (state falls below the threshold). */
+ switch (event->val) {
+ case KM_PRESS:
+ return OPERATOR_RUNNING_MODAL;
+ case KM_RELEASE:
+ wm_xr_grab_uninit(op);
+ return OPERATOR_FINISHED;
+ default:
+ BLI_assert_unreachable();
+ wm_xr_grab_uninit(op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void WM_OT_xr_navigation_grab(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "XR Navigation Grab";
+ ot->idname = "WM_OT_xr_navigation_grab";
+ ot->description = "Navigate the VR scene by grabbing with controllers";
+
+ /* callbacks */
+ ot->invoke = wm_xr_navigation_grab_invoke;
+ ot->exec = wm_xr_navigation_grab_exec;
+ ot->modal = wm_xr_navigation_grab_modal;
+ ot->poll = wm_xr_operator_sessionactive;
+
+ /* properties */
+ RNA_def_boolean(
+ ot->srna, "lock_location", false, "Lock Location", "Prevent changes to viewer location");
+ RNA_def_boolean(
+ ot->srna, "lock_location_z", false, "Lock Elevation", "Prevent changes to viewer elevation");
+ RNA_def_boolean(
+ ot->srna, "lock_rotation", false, "Lock Rotation", "Prevent changes to viewer rotation");
+ RNA_def_boolean(ot->srna,
+ "lock_rotation_z",
+ false,
+ "Lock Up Orientation",
+ "Prevent changes to viewer up orientation");
+ RNA_def_boolean(ot->srna, "lock_scale", false, "Lock Scale", "Prevent changes to viewer scale");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Raycast Utilities
+ * \{ */
+
+static const float g_xr_default_raycast_axis[3] = {0.0f, 0.0f, -1.0f};
+static const float g_xr_default_raycast_color[4] = {0.35f, 0.35f, 1.0f, 1.0f};
+
+typedef struct XrRaycastData {
+ bool from_viewer;
+ float origin[3];
+ float direction[3];
+ float end[3];
+ float color[4];
+ void *draw_handle;
+} XrRaycastData;
+
+static void wm_xr_raycast_draw(const bContext *UNUSED(C),
+ ARegion *UNUSED(region),
+ void *customdata)
+{
+ const XrRaycastData *data = customdata;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ if (data->from_viewer) {
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(data->color);
+
+ GPU_depth_test(GPU_DEPTH_NONE);
+ GPU_point_size(7.0f);
+
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex3fv(pos, data->end);
+ immEnd();
+ }
+ else {
+ uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_FLAT_COLOR);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+
+ immUniform1f("lineWidth", 3.0f * U.pixelsize);
+
+ GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immAttrSkip(col);
+ immVertex3fv(pos, data->origin);
+ immAttr4fv(col, data->color);
+ immVertex3fv(pos, data->end);
+ immEnd();
+ }
+
+ immUnbindProgram();
+}
+
+static void wm_xr_raycast_init(wmOperator *op)
+{
+ BLI_assert(op->customdata == NULL);
+
+ op->customdata = MEM_callocN(sizeof(XrRaycastData), __func__);
+
+ SpaceType *st = BKE_spacetype_from_id(SPACE_VIEW3D);
+ if (!st) {
+ return;
+ }
+
+ ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_XR);
+ if (!art) {
+ return;
+ }
+
+ XrRaycastData *data = op->customdata;
+ data->draw_handle = ED_region_draw_cb_activate(
+ art, wm_xr_raycast_draw, op->customdata, REGION_DRAW_POST_VIEW);
+}
+
+static void wm_xr_raycast_uninit(wmOperator *op)
+{
+ if (!op->customdata) {
+ return;
+ }
+
+ SpaceType *st = BKE_spacetype_from_id(SPACE_VIEW3D);
+ if (st) {
+ ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_XR);
+ if (art) {
+ XrRaycastData *data = op->customdata;
+ ED_region_draw_cb_exit(art, data->draw_handle);
+ }
+ }
+
+ MEM_freeN(op->customdata);
+}
+
+static void wm_xr_raycast_update(wmOperator *op,
+ const wmXrData *xr,
+ const wmXrActionData *actiondata)
+{
+ XrRaycastData *data = op->customdata;
+ float ray_length, axis[3];
+
+ data->from_viewer = RNA_boolean_get(op->ptr, "from_viewer");
+ RNA_float_get_array(op->ptr, "axis", axis);
+ RNA_float_get_array(op->ptr, "color", data->color);
+
+ if (data->from_viewer) {
+ float viewer_rot[4];
+ WM_xr_session_state_viewer_pose_location_get(xr, data->origin);
+ WM_xr_session_state_viewer_pose_rotation_get(xr, viewer_rot);
+ mul_qt_v3(viewer_rot, axis);
+ ray_length = (xr->session_settings.clip_start + xr->session_settings.clip_end) / 2.0f;
+ }
+ else {
+ copy_v3_v3(data->origin, actiondata->controller_loc);
+ mul_qt_v3(actiondata->controller_rot, axis);
+ ray_length = xr->session_settings.clip_end;
+ }
+
+ copy_v3_v3(data->direction, axis);
+ madd_v3_v3v3fl(data->end, data->origin, data->direction, ray_length);
+}
+
+static void wm_xr_raycast(Scene *scene,
+ Depsgraph *depsgraph,
+ const float origin[3],
+ const float direction[3],
+ float *ray_dist,
+ bool selectable_only,
+ float r_location[3],
+ float r_normal[3],
+ int *r_index,
+ Object **r_ob,
+ float r_obmat[4][4])
+{
+ /* Uses same raycast method as Scene.ray_cast(). */
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, 0);
+
+ ED_transform_snap_object_project_ray_ex(
+ sctx,
+ depsgraph,
+ NULL,
+ &(const struct SnapObjectParams){
+ .snap_select = (selectable_only ? SNAP_SELECTABLE : SNAP_ALL)},
+ origin,
+ direction,
+ ray_dist,
+ r_location,
+ r_normal,
+ r_index,
+ r_ob,
+ r_obmat);
+
+ ED_transform_snap_object_context_destroy(sctx);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Navigation Fly
+ *
+ * Navigates the scene by moving/turning relative to navigation space or the XR viewer or
+ * controller.
+ * \{ */
+
+#define XR_DEFAULT_FLY_SPEED_MOVE 0.054f
+#define XR_DEFAULT_FLY_SPEED_TURN 0.03f
+
+typedef enum eXrFlyMode {
+ XR_FLY_FORWARD = 0,
+ XR_FLY_BACK = 1,
+ XR_FLY_LEFT = 2,
+ XR_FLY_RIGHT = 3,
+ XR_FLY_UP = 4,
+ XR_FLY_DOWN = 5,
+ XR_FLY_TURNLEFT = 6,
+ XR_FLY_TURNRIGHT = 7,
+ XR_FLY_VIEWER_FORWARD = 8,
+ XR_FLY_VIEWER_BACK = 9,
+ XR_FLY_VIEWER_LEFT = 10,
+ XR_FLY_VIEWER_RIGHT = 11,
+ XR_FLY_CONTROLLER_FORWARD = 12,
+} eXrFlyMode;
+
+typedef struct XrFlyData {
+ float viewer_rot[4];
+ double time_prev;
+} XrFlyData;
+
+static void wm_xr_fly_init(wmOperator *op, const wmXrData *xr)
+{
+ BLI_assert(op->customdata == NULL);
+
+ XrFlyData *data = op->customdata = MEM_callocN(sizeof(XrFlyData), __func__);
+
+ WM_xr_session_state_viewer_pose_rotation_get(xr, data->viewer_rot);
+ data->time_prev = PIL_check_seconds_timer();
+}
+
+static void wm_xr_fly_uninit(wmOperator *op)
+{
+ MEM_SAFE_FREE(op->customdata);
+}
+
+static void wm_xr_fly_compute_move(eXrFlyMode mode,
+ float speed,
+ const float ref_quat[4],
+ const float nav_mat[4][4],
+ bool locz_lock,
+ float r_delta[4][4])
+{
+ float ref_axes[3][3];
+ quat_to_mat3(ref_axes, ref_quat);
+
+ unit_m4(r_delta);
+
+ switch (mode) {
+ /* Navigation space reference. */
+ case XR_FLY_FORWARD:
+ madd_v3_v3fl(r_delta[3], ref_axes[1], speed);
+ return;
+ case XR_FLY_BACK:
+ madd_v3_v3fl(r_delta[3], ref_axes[1], -speed);
+ return;
+ case XR_FLY_LEFT:
+ madd_v3_v3fl(r_delta[3], ref_axes[0], -speed);
+ return;
+ case XR_FLY_RIGHT:
+ madd_v3_v3fl(r_delta[3], ref_axes[0], speed);
+ return;
+ case XR_FLY_UP:
+ case XR_FLY_DOWN:
+ if (!locz_lock) {
+ madd_v3_v3fl(r_delta[3], ref_axes[2], (mode == XR_FLY_UP) ? speed : -speed);
+ }
+ return;
+ /* Viewer/controller space reference. */
+ case XR_FLY_VIEWER_FORWARD:
+ case XR_FLY_CONTROLLER_FORWARD:
+ negate_v3_v3(r_delta[3], ref_axes[2]);
+ break;
+ case XR_FLY_VIEWER_BACK:
+ copy_v3_v3(r_delta[3], ref_axes[2]);
+ break;
+ case XR_FLY_VIEWER_LEFT:
+ negate_v3_v3(r_delta[3], ref_axes[0]);
+ break;
+ case XR_FLY_VIEWER_RIGHT:
+ copy_v3_v3(r_delta[3], ref_axes[0]);
+ break;
+ /* Unused. */
+ case XR_FLY_TURNLEFT:
+ case XR_FLY_TURNRIGHT:
+ BLI_assert_unreachable();
+ return;
+ }
+
+ if (locz_lock) {
+ /* Lock elevation in navigation space. */
+ float z_axis[3], projected[3];
+
+ normalize_v3_v3(z_axis, nav_mat[2]);
+ project_v3_v3v3_normalized(projected, r_delta[3], z_axis);
+ sub_v3_v3(r_delta[3], projected);
+
+ normalize_v3(r_delta[3]);
+ }
+
+ mul_v3_fl(r_delta[3], speed);
+}
+
+static void wm_xr_fly_compute_turn(eXrFlyMode mode,
+ float speed,
+ const float viewer_mat[4][4],
+ const float nav_mat[4][4],
+ const float nav_inv[4][4],
+ float r_delta[4][4])
+{
+ BLI_assert(mode == XR_FLY_TURNLEFT || mode == XR_FLY_TURNRIGHT);
+
+ float z_axis[3], m[3][3], prev[4][4], curr[4][4];
+
+ /* Turn around Z-axis in navigation space. */
+ normalize_v3_v3(z_axis, nav_mat[2]);
+ axis_angle_normalized_to_mat3(m, z_axis, (mode == XR_FLY_TURNLEFT) ? speed : -speed);
+ copy_m4_m3(r_delta, m);
+
+ copy_m4_m4(prev, viewer_mat);
+ mul_m4_m4m4(curr, r_delta, viewer_mat);
+
+ /* Lock location in base pose space. */
+ wm_xr_navlocks_apply(nav_mat, nav_inv, true, false, false, prev, curr);
+
+ invert_m4(prev);
+ mul_m4_m4m4(r_delta, curr, prev);
+}
+
+static void wm_xr_basenav_rotation_calc(const wmXrData *xr,
+ const float nav_rotation[4],
+ float r_rotation[4])
+{
+ /* Apply nav rotation to base pose Z-rotation. */
+ float base_eul[3], base_quatz[4];
+ quat_to_eul(base_eul, xr->runtime->session_state.prev_base_pose.orientation_quat);
+ axis_angle_to_quat_single(base_quatz, 'Z', base_eul[2]);
+ mul_qt_qtqt(r_rotation, nav_rotation, base_quatz);
+}
+
+static int wm_xr_navigation_fly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ wm_xr_fly_init(op, &wm->xr);
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_xr_navigation_fly_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ return OPERATOR_CANCELLED;
+}
+
+static int wm_xr_navigation_fly_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ if (event->val == KM_RELEASE) {
+ wm_xr_fly_uninit(op);
+ return OPERATOR_FINISHED;
+ }
+
+ const wmXrActionData *actiondata = event->customdata;
+ XrFlyData *data = op->customdata;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmXrData *xr = &wm->xr;
+ eXrFlyMode mode;
+ bool turn, locz_lock, dir_lock, speed_frame_based;
+ bool speed_interp_cubic = false;
+ float speed, speed_max, speed_p0[2], speed_p1[2];
+ GHOST_XrPose nav_pose;
+ float nav_mat[4][4], delta[4][4], out[4][4];
+
+ const double time_now = PIL_check_seconds_timer();
+
+ mode = (eXrFlyMode)RNA_enum_get(op->ptr, "mode");
+ turn = (ELEM(mode, XR_FLY_TURNLEFT, XR_FLY_TURNRIGHT));
+
+ locz_lock = RNA_boolean_get(op->ptr, "lock_location_z");
+ dir_lock = RNA_boolean_get(op->ptr, "lock_direction");
+ speed_frame_based = RNA_boolean_get(op->ptr, "speed_frame_based");
+ speed = RNA_float_get(op->ptr, "speed_min");
+ speed_max = RNA_float_get(op->ptr, "speed_max");
+
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "speed_interpolation0");
+ if (prop && RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, speed_p0);
+ speed_interp_cubic = true;
+ }
+ else {
+ speed_p0[0] = speed_p0[1] = 0.0f;
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "speed_interpolation1");
+ if (prop && RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, speed_p1);
+ speed_interp_cubic = true;
+ }
+ else {
+ speed_p1[0] = speed_p1[1] = 1.0f;
+ }
+
+ /* Ensure valid interpolation. */
+ if (speed_max < speed) {
+ speed_max = speed;
+ }
+
+ /* Interpolate between min/max speeds based on button state. */
+ switch (actiondata->type) {
+ case XR_BOOLEAN_INPUT:
+ speed = speed_max;
+ break;
+ case XR_FLOAT_INPUT:
+ case XR_VECTOR2F_INPUT: {
+ float state = (actiondata->type == XR_FLOAT_INPUT) ? fabsf(actiondata->state[0]) :
+ len_v2(actiondata->state);
+ float speed_t = (actiondata->float_threshold < 1.0f) ?
+ (state - actiondata->float_threshold) /
+ (1.0f - actiondata->float_threshold) :
+ 1.0f;
+ if (speed_interp_cubic) {
+ float start[2], end[2], p[2];
+
+ start[0] = 0.0f;
+ start[1] = speed;
+ speed_p0[1] = speed + speed_p0[1] * (speed_max - speed);
+ speed_p1[1] = speed + speed_p1[1] * (speed_max - speed);
+ end[0] = 1.0f;
+ end[1] = speed_max;
+
+ interp_v2_v2v2v2v2_cubic(p, start, speed_p0, speed_p1, end, speed_t);
+ speed = p[1];
+ }
+ else {
+ speed += speed_t * (speed_max - speed);
+ }
+ break;
+ }
+ case XR_POSE_INPUT:
+ case XR_VIBRATION_OUTPUT:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ if (!speed_frame_based) {
+ /* Adjust speed based on last update time. */
+ speed *= time_now - data->time_prev;
+ }
+ data->time_prev = time_now;
+
+ WM_xr_session_state_nav_location_get(xr, nav_pose.position);
+ WM_xr_session_state_nav_rotation_get(xr, nav_pose.orientation_quat);
+ wm_xr_pose_to_mat(&nav_pose, nav_mat);
+
+ if (turn) {
+ if (dir_lock) {
+ unit_m4(delta);
+ }
+ else {
+ GHOST_XrPose viewer_pose;
+ float viewer_mat[4][4], nav_inv[4][4];
+
+ WM_xr_session_state_viewer_pose_location_get(xr, viewer_pose.position);
+ WM_xr_session_state_viewer_pose_rotation_get(xr, viewer_pose.orientation_quat);
+ wm_xr_pose_to_mat(&viewer_pose, viewer_mat);
+ wm_xr_pose_to_imat(&nav_pose, nav_inv);
+
+ wm_xr_fly_compute_turn(mode, speed, viewer_mat, nav_mat, nav_inv, delta);
+ }
+ }
+ else {
+ float nav_scale, ref_quat[4];
+
+ /* Adjust speed for base and navigation scale. */
+ WM_xr_session_state_nav_scale_get(xr, &nav_scale);
+ speed *= xr->session_settings.base_scale * nav_scale;
+
+ switch (mode) {
+ /* Move relative to navigation space. */
+ case XR_FLY_FORWARD:
+ case XR_FLY_BACK:
+ case XR_FLY_LEFT:
+ case XR_FLY_RIGHT:
+ case XR_FLY_UP:
+ case XR_FLY_DOWN:
+ wm_xr_basenav_rotation_calc(xr, nav_pose.orientation_quat, ref_quat);
+ break;
+ /* Move relative to viewer. */
+ case XR_FLY_VIEWER_FORWARD:
+ case XR_FLY_VIEWER_BACK:
+ case XR_FLY_VIEWER_LEFT:
+ case XR_FLY_VIEWER_RIGHT:
+ if (dir_lock) {
+ copy_qt_qt(ref_quat, data->viewer_rot);
+ }
+ else {
+ WM_xr_session_state_viewer_pose_rotation_get(xr, ref_quat);
+ }
+ break;
+ /* Move relative to controller. */
+ case XR_FLY_CONTROLLER_FORWARD:
+ copy_qt_qt(ref_quat, actiondata->controller_rot);
+ break;
+ /* Unused. */
+ case XR_FLY_TURNLEFT:
+ case XR_FLY_TURNRIGHT:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ wm_xr_fly_compute_move(mode, speed, ref_quat, nav_mat, locz_lock, delta);
+ }
+
+ mul_m4_m4m4(out, delta, nav_mat);
+
+ WM_xr_session_state_nav_location_set(xr, out[3]);
+ if (turn) {
+ mat4_to_quat(nav_pose.orientation_quat, out);
+ WM_xr_session_state_nav_rotation_set(xr, nav_pose.orientation_quat);
+ }
+
+ if (event->val == KM_PRESS) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ /* XR events currently only support press and release. */
+ BLI_assert_unreachable();
+ wm_xr_fly_uninit(op);
+ return OPERATOR_CANCELLED;
+}
+
+static void WM_OT_xr_navigation_fly(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "XR Navigation Fly";
+ ot->idname = "WM_OT_xr_navigation_fly";
+ ot->description = "Move/turn relative to the VR viewer or controller";
+
+ /* callbacks */
+ ot->invoke = wm_xr_navigation_fly_invoke;
+ ot->exec = wm_xr_navigation_fly_exec;
+ ot->modal = wm_xr_navigation_fly_modal;
+ ot->poll = wm_xr_operator_sessionactive;
+
+ /* properties */
+ static const EnumPropertyItem fly_modes[] = {
+ {XR_FLY_FORWARD, "FORWARD", 0, "Forward", "Move along navigation forward axis"},
+ {XR_FLY_BACK, "BACK", 0, "Back", "Move along navigation back axis"},
+ {XR_FLY_LEFT, "LEFT", 0, "Left", "Move along navigation left axis"},
+ {XR_FLY_RIGHT, "RIGHT", 0, "Right", "Move along navigation right axis"},
+ {XR_FLY_UP, "UP", 0, "Up", "Move along navigation up axis"},
+ {XR_FLY_DOWN, "DOWN", 0, "Down", "Move along navigation down axis"},
+ {XR_FLY_TURNLEFT,
+ "TURNLEFT",
+ 0,
+ "Turn Left",
+ "Turn counter-clockwise around navigation up axis"},
+ {XR_FLY_TURNRIGHT, "TURNRIGHT", 0, "Turn Right", "Turn clockwise around navigation up axis"},
+ {XR_FLY_VIEWER_FORWARD,
+ "VIEWER_FORWARD",
+ 0,
+ "Viewer Forward",
+ "Move along viewer's forward axis"},
+ {XR_FLY_VIEWER_BACK, "VIEWER_BACK", 0, "Viewer Back", "Move along viewer's back axis"},
+ {XR_FLY_VIEWER_LEFT, "VIEWER_LEFT", 0, "Viewer Left", "Move along viewer's left axis"},
+ {XR_FLY_VIEWER_RIGHT, "VIEWER_RIGHT", 0, "Viewer Right", "Move along viewer's right axis"},
+ {XR_FLY_CONTROLLER_FORWARD,
+ "CONTROLLER_FORWARD",
+ 0,
+ "Controller Forward",
+ "Move along controller's forward axis"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const float default_speed_p0[2] = {0.0f, 0.0f};
+ static const float default_speed_p1[2] = {1.0f, 1.0f};
+
+ RNA_def_enum(ot->srna, "mode", fly_modes, XR_FLY_VIEWER_FORWARD, "Mode", "Fly mode");
+ RNA_def_boolean(
+ ot->srna, "lock_location_z", false, "Lock Elevation", "Prevent changes to viewer elevation");
+ RNA_def_boolean(ot->srna,
+ "lock_direction",
+ false,
+ "Lock Direction",
+ "Limit movement to viewer's initial direction");
+ RNA_def_boolean(ot->srna,
+ "speed_frame_based",
+ true,
+ "Frame Based Speed",
+ "Apply fixed movement deltas every update");
+ RNA_def_float(ot->srna,
+ "speed_min",
+ XR_DEFAULT_FLY_SPEED_MOVE / 3.0f,
+ 0.0f,
+ 1000.0f,
+ "Minimum Speed",
+ "Minimum move (turn) speed in meters (radians) per second or frame",
+ 0.0f,
+ 1000.0f);
+ RNA_def_float(ot->srna,
+ "speed_max",
+ XR_DEFAULT_FLY_SPEED_MOVE,
+ 0.0f,
+ 1000.0f,
+ "Maximum Speed",
+ "Maximum move (turn) speed in meters (radians) per second or frame",
+ 0.0f,
+ 1000.0f);
+ RNA_def_float_vector(ot->srna,
+ "speed_interpolation0",
+ 2,
+ default_speed_p0,
+ 0.0f,
+ 1.0f,
+ "Speed Interpolation 0",
+ "First cubic spline control point between min/max speeds",
+ 0.0f,
+ 1.0f);
+ RNA_def_float_vector(ot->srna,
+ "speed_interpolation1",
+ 2,
+ default_speed_p1,
+ 0.0f,
+ 1.0f,
+ "Speed Interpolation 1",
+ "Second cubic spline control point between min/max speeds",
+ 0.0f,
+ 1.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Navigation Teleport
+ *
+ * Casts a ray from an XR controller's pose and teleports to any hit geometry.
+ * \{ */
+
+static void wm_xr_navigation_teleport(bContext *C,
+ wmXrData *xr,
+ const float origin[3],
+ const float direction[3],
+ float *ray_dist,
+ bool selectable_only,
+ const bool teleport_axes[3],
+ float teleport_t,
+ float teleport_ofs)
+{
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ float location[3];
+ float normal[3];
+ int index;
+ Object *ob = NULL;
+ float obmat[4][4];
+
+ wm_xr_raycast(scene,
+ depsgraph,
+ origin,
+ direction,
+ ray_dist,
+ selectable_only,
+ location,
+ normal,
+ &index,
+ &ob,
+ obmat);
+
+ /* Teleport. */
+ if (ob) {
+ float nav_location[3], nav_rotation[4], viewer_location[3];
+ float nav_axes[3][3], projected[3], v0[3], v1[3];
+ float out[3] = {0.0f, 0.0f, 0.0f};
+
+ WM_xr_session_state_nav_location_get(xr, nav_location);
+ WM_xr_session_state_nav_rotation_get(xr, nav_rotation);
+ WM_xr_session_state_viewer_pose_location_get(xr, viewer_location);
+
+ wm_xr_basenav_rotation_calc(xr, nav_rotation, nav_rotation);
+ quat_to_mat3(nav_axes, nav_rotation);
+
+ /* Project locations onto navigation axes. */
+ for (int a = 0; a < 3; ++a) {
+ project_v3_v3v3_normalized(projected, nav_location, nav_axes[a]);
+ if (teleport_axes[a]) {
+ /* Interpolate between projected locations. */
+ project_v3_v3v3_normalized(v0, location, nav_axes[a]);
+ project_v3_v3v3_normalized(v1, viewer_location, nav_axes[a]);
+ sub_v3_v3(v0, v1);
+ madd_v3_v3fl(projected, v0, teleport_t);
+ /* Subtract offset. */
+ project_v3_v3v3_normalized(v0, normal, nav_axes[a]);
+ madd_v3_v3fl(projected, v0, teleport_ofs);
+ }
+ /* Add to final location. */
+ add_v3_v3(out, projected);
+ }
+
+ WM_xr_session_state_nav_location_set(xr, out);
+ }
+}
+
+static int wm_xr_navigation_teleport_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ wm_xr_raycast_init(op);
+
+ int retval = op->type->modal(C, op, event);
+
+ if ((retval & OPERATOR_RUNNING_MODAL) != 0) {
+ WM_event_add_modal_handler(C, op);
+ }
+
+ return retval;
+}
+
+static int wm_xr_navigation_teleport_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ return OPERATOR_CANCELLED;
+}
+
+static int wm_xr_navigation_teleport_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ const wmXrActionData *actiondata = event->customdata;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmXrData *xr = &wm->xr;
+
+ wm_xr_raycast_update(op, xr, actiondata);
+
+ switch (event->val) {
+ case KM_PRESS:
+ return OPERATOR_RUNNING_MODAL;
+ case KM_RELEASE: {
+ XrRaycastData *data = op->customdata;
+ bool selectable_only, teleport_axes[3];
+ float teleport_t, teleport_ofs, ray_dist;
+
+ RNA_boolean_get_array(op->ptr, "teleport_axes", teleport_axes);
+ teleport_t = RNA_float_get(op->ptr, "interpolation");
+ teleport_ofs = RNA_float_get(op->ptr, "offset");
+ selectable_only = RNA_boolean_get(op->ptr, "selectable_only");
+ ray_dist = RNA_float_get(op->ptr, "distance");
+
+ wm_xr_navigation_teleport(C,
+ xr,
+ data->origin,
+ data->direction,
+ &ray_dist,
+ selectable_only,
+ teleport_axes,
+ teleport_t,
+ teleport_ofs);
+
+ wm_xr_raycast_uninit(op);
+
+ return OPERATOR_FINISHED;
+ }
+ default:
+ /* XR events currently only support press and release. */
+ BLI_assert_unreachable();
+ wm_xr_raycast_uninit(op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void WM_OT_xr_navigation_teleport(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "XR Navigation Teleport";
+ ot->idname = "WM_OT_xr_navigation_teleport";
+ ot->description = "Set VR viewer location to controller raycast hit location";
+
+ /* callbacks */
+ ot->invoke = wm_xr_navigation_teleport_invoke;
+ ot->exec = wm_xr_navigation_teleport_exec;
+ ot->modal = wm_xr_navigation_teleport_modal;
+ ot->poll = wm_xr_operator_sessionactive;
+
+ /* properties */
+ static bool default_teleport_axes[3] = {true, true, true};
+
+ RNA_def_boolean_vector(ot->srna,
+ "teleport_axes",
+ 3,
+ default_teleport_axes,
+ "Teleport Axes",
+ "Enabled teleport axes in navigation space");
+ RNA_def_float(ot->srna,
+ "interpolation",
+ 1.0f,
+ 0.0f,
+ 1.0f,
+ "Interpolation",
+ "Interpolation factor between viewer and hit locations",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
+ "offset",
+ 0.0f,
+ 0.0f,
+ FLT_MAX,
+ "Offset",
+ "Offset along hit normal to subtract from final location",
+ 0.0f,
+ FLT_MAX);
+ RNA_def_boolean(ot->srna,
+ "selectable_only",
+ true,
+ "Selectable Only",
+ "Only allow selectable objects to influence raycast result");
+ RNA_def_float(ot->srna,
+ "distance",
+ BVH_RAYCAST_DIST_MAX,
+ 0.0,
+ BVH_RAYCAST_DIST_MAX,
+ "",
+ "Maximum raycast distance",
+ 0.0,
+ BVH_RAYCAST_DIST_MAX);
+ RNA_def_boolean(
+ ot->srna, "from_viewer", false, "From Viewer", "Use viewer pose as raycast origin");
+ RNA_def_float_vector(ot->srna,
+ "axis",
+ 3,
+ g_xr_default_raycast_axis,
+ -1.0f,
+ 1.0f,
+ "Axis",
+ "Raycast axis in controller/viewer space",
+ -1.0f,
+ 1.0f);
+ RNA_def_float_color(ot->srna,
+ "color",
+ 4,
+ g_xr_default_raycast_color,
+ 0.0f,
+ 1.0f,
+ "Color",
+ "Raycast color",
+ 0.0f,
+ 1.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Navigation Reset
+ *
+ * Resets XR navigation deltas relative to session base pose.
+ * \{ */
+
+static int wm_xr_navigation_reset_exec(bContext *C, wmOperator *op)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmXrData *xr = &wm->xr;
+ bool reset_loc, reset_rot, reset_scale;
+
+ reset_loc = RNA_boolean_get(op->ptr, "location");
+ reset_rot = RNA_boolean_get(op->ptr, "rotation");
+ reset_scale = RNA_boolean_get(op->ptr, "scale");
+
+ if (reset_loc) {
+ float loc[3];
+ if (!reset_scale) {
+ float nav_rotation[4], nav_scale;
+
+ WM_xr_session_state_nav_rotation_get(xr, nav_rotation);
+ WM_xr_session_state_nav_scale_get(xr, &nav_scale);
+
+ /* Adjust location based on scale. */
+ mul_v3_v3fl(loc, xr->runtime->session_state.prev_base_pose.position, nav_scale);
+ sub_v3_v3(loc, xr->runtime->session_state.prev_base_pose.position);
+ mul_qt_v3(nav_rotation, loc);
+ negate_v3(loc);
+ }
+ else {
+ zero_v3(loc);
+ }
+ WM_xr_session_state_nav_location_set(xr, loc);
+ }
+
+ if (reset_rot) {
+ float rot[4];
+ unit_qt(rot);
+ WM_xr_session_state_nav_rotation_set(xr, rot);
+ }
+
+ if (reset_scale) {
+ if (!reset_loc) {
+ float nav_location[3], nav_rotation[4], nav_scale;
+ float nav_axes[3][3], v[3];
+
+ WM_xr_session_state_nav_location_get(xr, nav_location);
+ WM_xr_session_state_nav_rotation_get(xr, nav_rotation);
+ WM_xr_session_state_nav_scale_get(xr, &nav_scale);
+
+ /* Offset any location changes when changing scale. */
+ mul_v3_v3fl(v, xr->runtime->session_state.prev_base_pose.position, nav_scale);
+ sub_v3_v3(v, xr->runtime->session_state.prev_base_pose.position);
+ mul_qt_v3(nav_rotation, v);
+ add_v3_v3(nav_location, v);
+
+ /* Reset elevation to base pose value. */
+ quat_to_mat3(nav_axes, nav_rotation);
+ project_v3_v3v3_normalized(v, nav_location, nav_axes[2]);
+ sub_v3_v3(nav_location, v);
+
+ WM_xr_session_state_nav_location_set(xr, nav_location);
+ }
+ WM_xr_session_state_nav_scale_set(xr, 1.0f);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void WM_OT_xr_navigation_reset(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "XR Navigation Reset";
+ ot->idname = "WM_OT_xr_navigation_reset";
+ ot->description = "Reset VR navigation deltas relative to session base pose";
+
+ /* callbacks */
+ ot->exec = wm_xr_navigation_reset_exec;
+ ot->poll = wm_xr_operator_sessionactive;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "location", true, "Location", "Reset location deltas");
+ RNA_def_boolean(ot->srna, "rotation", true, "Rotation", "Reset rotation deltas");
+ RNA_def_boolean(ot->srna, "scale", true, "Scale", "Reset scale deltas");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Registration
+ * \{ */
+
+void wm_xr_operatortypes_register(void)
+{
+ WM_operatortype_append(WM_OT_xr_session_toggle);
+ WM_operatortype_append(WM_OT_xr_navigation_grab);
+ WM_operatortype_append(WM_OT_xr_navigation_fly);
+ WM_operatortype_append(WM_OT_xr_navigation_teleport);
+ WM_operatortype_append(WM_OT_xr_navigation_reset);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c
index 88bf3ff453c..bad735ee598 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_session.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c
@@ -21,27 +21,38 @@
#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_idprop.h"
#include "BKE_main.h"
#include "BKE_scene.h"
+#include "BKE_screen.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "DNA_camera_types.h"
+#include "DNA_space_types.h"
#include "DRW_engine.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
+
#include "GHOST_C-api.h"
+#include "GPU_batch.h"
#include "GPU_viewport.h"
#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
#include "WM_api.h"
#include "WM_types.h"
+#include "wm_event_system.h"
#include "wm_surface.h"
#include "wm_window.h"
#include "wm_xr_intern.h"
@@ -56,16 +67,33 @@ static void wm_xr_session_create_cb(void)
Main *bmain = G_MAIN;
wmWindowManager *wm = bmain->wm.first;
wmXrData *xr_data = &wm->xr;
+ wmXrSessionState *state = &xr_data->runtime->session_state;
+ XrSessionSettings *settings = &xr_data->session_settings;
/* Get action set data from Python. */
BKE_callback_exec_null(bmain, BKE_CB_EVT_XR_SESSION_START_PRE);
wm_xr_session_actions_init(xr_data);
+
+ /* Initialize navigation. */
+ WM_xr_session_state_navigation_reset(state);
+ if (settings->base_scale < FLT_EPSILON) {
+ settings->base_scale = 1.0f;
+ }
+ state->prev_base_scale = settings->base_scale;
}
static void wm_xr_session_controller_data_free(wmXrSessionState *state)
{
- BLI_freelistN(&state->controllers);
+ ListBase *lb = &state->controllers;
+ wmXrController *c;
+
+ while ((c = BLI_pophead(lb))) {
+ if (c->model) {
+ GPU_batch_discard(c->model);
+ }
+ BLI_freelinkN(lb, c);
+ }
}
void wm_xr_session_data_free(wmXrSessionState *state)
@@ -110,6 +138,9 @@ void wm_xr_session_toggle(wmWindowManager *wm,
wmXrData *xr_data = &wm->xr;
if (WM_xr_session_exists(xr_data)) {
+ /* Must set first, since #GHOST_XrSessionEnd() may immediately free the runtime. */
+ xr_data->runtime->session_state.is_started = false;
+
GHOST_XrSessionEnd(xr_data->runtime->context);
}
else {
@@ -124,10 +155,6 @@ void wm_xr_session_toggle(wmWindowManager *wm,
}
}
-/**
- * Check if the XR-Session was triggered.
- * If an error happened while trying to start a session, this returns false too.
- */
bool WM_xr_session_exists(const wmXrData *xr)
{
return xr->runtime && xr->runtime->context && xr->runtime->session_state.is_started;
@@ -138,9 +165,6 @@ void WM_xr_session_base_pose_reset(wmXrData *xr)
xr->runtime->session_state.force_reset_to_base_pose = true;
}
-/**
- * Check if the session is running, according to the OpenXR definition.
- */
bool WM_xr_session_is_ready(const wmXrData *xr)
{
return WM_xr_session_exists(xr) && GHOST_XrSessionIsRunning(xr->runtime->context);
@@ -148,7 +172,8 @@ bool WM_xr_session_is_ready(const wmXrData *xr)
static void wm_xr_session_base_pose_calc(const Scene *scene,
const XrSessionSettings *settings,
- GHOST_XrPose *r_base_pose)
+ GHOST_XrPose *r_base_pose,
+ float *r_base_scale)
{
const Object *base_pose_object = ((settings->base_pose_type == XR_BASE_POSE_OBJECT) &&
settings->base_pose_object) ?
@@ -179,6 +204,8 @@ static void wm_xr_session_base_pose_calc(const Scene *scene,
copy_v3_fl(r_base_pose->position, 0.0f);
axis_angle_to_quat_single(r_base_pose->orientation_quat, 'X', M_PI_2);
}
+
+ *r_base_scale = settings->base_scale;
}
static void wm_xr_session_draw_data_populate(wmXrData *xr_data,
@@ -194,11 +221,12 @@ static void wm_xr_session_draw_data_populate(wmXrData *xr_data,
r_draw_data->xr_data = xr_data;
r_draw_data->surface_data = g_xr_surface->customdata;
- wm_xr_session_base_pose_calc(r_draw_data->scene, settings, &r_draw_data->base_pose);
+ wm_xr_session_base_pose_calc(
+ r_draw_data->scene, settings, &r_draw_data->base_pose, &r_draw_data->base_scale);
}
-static wmWindow *wm_xr_session_root_window_or_fallback_get(const wmWindowManager *wm,
- const wmXrRuntimeData *runtime_data)
+wmWindow *wm_xr_session_root_window_or_fallback_get(const wmWindowManager *wm,
+ const wmXrRuntimeData *runtime_data)
{
if (runtime_data->session_root_win &&
BLI_findindex(&wm->windows, runtime_data->session_root_win) != -1) {
@@ -216,10 +244,9 @@ static wmWindow *wm_xr_session_root_window_or_fallback_get(const wmWindowManager
* It's important that the VR session follows some existing window, otherwise it would need to have
* an own depsgraph, which is an expense we should avoid.
*/
-static void wm_xr_session_scene_and_evaluated_depsgraph_get(Main *bmain,
- const wmWindowManager *wm,
- Scene **r_scene,
- Depsgraph **r_depsgraph)
+static void wm_xr_session_scene_and_depsgraph_get(const wmWindowManager *wm,
+ Scene **r_scene,
+ Depsgraph **r_depsgraph)
{
const wmWindow *root_win = wm_xr_session_root_window_or_fallback_get(wm, wm->xr.runtime);
@@ -229,7 +256,6 @@ static void wm_xr_session_scene_and_evaluated_depsgraph_get(Main *bmain,
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer);
BLI_assert(scene && view_layer && depsgraph);
- BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
*r_scene = scene;
*r_depsgraph = depsgraph;
}
@@ -272,7 +298,7 @@ static wmXrSessionStateEvent wm_xr_session_state_to_event(const wmXrSessionState
return SESSION_STATE_EVENT_NONE;
}
-void wm_xr_session_draw_data_update(const wmXrSessionState *state,
+void wm_xr_session_draw_data_update(wmXrSessionState *state,
const XrSessionSettings *settings,
const GHOST_XrDrawViewInfo *draw_view,
wmXrDrawData *draw_data)
@@ -300,6 +326,8 @@ void wm_xr_session_draw_data_update(const wmXrSessionState *state,
else {
copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
}
+ /* Reset navigation. */
+ WM_xr_session_state_navigation_reset(state);
break;
case SESSION_STATE_EVENT_POSITION_TRACKING_TOGGLE:
if (use_position_tracking) {
@@ -318,40 +346,38 @@ void wm_xr_session_draw_data_update(const wmXrSessionState *state,
}
}
-/**
- * Update information that is only stored for external state queries. E.g. for Python API to
- * request the current (as in, last known) viewer pose.
- * Controller data and action sets will be updated separately via wm_xr_session_actions_update().
- */
void wm_xr_session_state_update(const XrSessionSettings *settings,
const wmXrDrawData *draw_data,
const GHOST_XrDrawViewInfo *draw_view,
wmXrSessionState *state)
{
GHOST_XrPose viewer_pose;
- const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING;
- const bool use_absolute_tracking = settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING;
-
- mul_qt_qtqt(viewer_pose.orientation_quat,
- draw_data->base_pose.orientation_quat,
- draw_view->local_pose.orientation_quat);
- copy_v3_v3(viewer_pose.position, draw_data->base_pose.position);
- /* The local pose and the eye pose (which is copied from an earlier local pose) both are view
- * space, so Y-up. In this case we need them in regular Z-up. */
- if (use_position_tracking) {
- viewer_pose.position[0] += draw_view->local_pose.position[0];
- viewer_pose.position[1] -= draw_view->local_pose.position[2];
- viewer_pose.position[2] += draw_view->local_pose.position[1];
- }
- if (!use_absolute_tracking) {
- viewer_pose.position[0] -= draw_data->eye_position_ofs[0];
- viewer_pose.position[1] += draw_data->eye_position_ofs[2];
- viewer_pose.position[2] -= draw_data->eye_position_ofs[1];
- }
-
- copy_v3_v3(state->viewer_pose.position, viewer_pose.position);
- copy_qt_qt(state->viewer_pose.orientation_quat, viewer_pose.orientation_quat);
- wm_xr_pose_to_imat(&viewer_pose, state->viewer_viewmat);
+ float viewer_mat[4][4], base_mat[4][4], nav_mat[4][4];
+
+ /* Calculate viewer matrix. */
+ copy_qt_qt(viewer_pose.orientation_quat, draw_view->local_pose.orientation_quat);
+ if ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
+ zero_v3(viewer_pose.position);
+ }
+ else {
+ copy_v3_v3(viewer_pose.position, draw_view->local_pose.position);
+ }
+ if ((settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING) == 0) {
+ sub_v3_v3(viewer_pose.position, draw_data->eye_position_ofs);
+ }
+ wm_xr_pose_to_mat(&viewer_pose, viewer_mat);
+
+ /* Apply base pose and navigation. */
+ wm_xr_pose_scale_to_mat(&draw_data->base_pose, draw_data->base_scale, base_mat);
+ wm_xr_pose_scale_to_mat(&state->nav_pose_prev, state->nav_scale_prev, nav_mat);
+ mul_m4_m4m4(state->viewer_mat_base, base_mat, viewer_mat);
+ mul_m4_m4m4(viewer_mat, nav_mat, state->viewer_mat_base);
+
+ /* Save final viewer pose and viewmat. */
+ mat4_to_loc_quat(state->viewer_pose.position, state->viewer_pose.orientation_quat, viewer_mat);
+ wm_xr_pose_scale_to_imat(
+ &state->viewer_pose, draw_data->base_scale * state->nav_scale_prev, state->viewer_viewmat);
+
/* No idea why, but multiplying by two seems to make it match the VR view more. */
state->focal_len = 2.0f *
fov_to_focallength(draw_view->fov.angle_right - draw_view->fov.angle_left,
@@ -359,7 +385,10 @@ void wm_xr_session_state_update(const XrSessionSettings *settings,
copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
memcpy(&state->prev_base_pose, &draw_data->base_pose, sizeof(state->prev_base_pose));
+ state->prev_base_scale = draw_data->base_scale;
memcpy(&state->prev_local_pose, &draw_view->local_pose, sizeof(state->prev_local_pose));
+ copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
+
state->prev_settings_flag = settings->flag;
state->prev_base_pose_type = settings->base_pose_type;
state->prev_base_pose_object = settings->base_pose_object;
@@ -373,6 +402,11 @@ wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr)
return xr->runtime ? &xr->runtime->session_state : NULL;
}
+ScrArea *WM_xr_session_area_get(const wmXrData *xr)
+{
+ return xr->runtime ? xr->runtime->area : NULL;
+}
+
bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3])
{
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
@@ -479,6 +513,74 @@ bool WM_xr_session_state_controller_aim_rotation_get(const wmXrData *xr,
return true;
}
+bool WM_xr_session_state_nav_location_get(const wmXrData *xr, float r_location[3])
+{
+ if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
+ zero_v3(r_location);
+ return false;
+ }
+
+ copy_v3_v3(r_location, xr->runtime->session_state.nav_pose.position);
+ return true;
+}
+
+void WM_xr_session_state_nav_location_set(wmXrData *xr, const float location[3])
+{
+ if (WM_xr_session_exists(xr)) {
+ copy_v3_v3(xr->runtime->session_state.nav_pose.position, location);
+ xr->runtime->session_state.is_navigation_dirty = true;
+ }
+}
+
+bool WM_xr_session_state_nav_rotation_get(const wmXrData *xr, float r_rotation[4])
+{
+ if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
+ unit_qt(r_rotation);
+ return false;
+ }
+
+ copy_qt_qt(r_rotation, xr->runtime->session_state.nav_pose.orientation_quat);
+ return true;
+}
+
+void WM_xr_session_state_nav_rotation_set(wmXrData *xr, const float rotation[4])
+{
+ if (WM_xr_session_exists(xr)) {
+ BLI_ASSERT_UNIT_QUAT(rotation);
+ copy_qt_qt(xr->runtime->session_state.nav_pose.orientation_quat, rotation);
+ xr->runtime->session_state.is_navigation_dirty = true;
+ }
+}
+
+bool WM_xr_session_state_nav_scale_get(const wmXrData *xr, float *r_scale)
+{
+ if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
+ *r_scale = 1.0f;
+ return false;
+ }
+
+ *r_scale = xr->runtime->session_state.nav_scale;
+ return true;
+}
+
+void WM_xr_session_state_nav_scale_set(wmXrData *xr, float scale)
+{
+ if (WM_xr_session_exists(xr)) {
+ /* Clamp to reasonable values. */
+ CLAMP(scale, xr->session_settings.clip_start, xr->session_settings.clip_end);
+ xr->runtime->session_state.nav_scale = scale;
+ xr->runtime->session_state.is_navigation_dirty = true;
+ }
+}
+
+void WM_xr_session_state_navigation_reset(wmXrSessionState *state)
+{
+ zero_v3(state->nav_pose.position);
+ unit_qt(state->nav_pose.orientation_quat);
+ state->nav_scale = 1.0f;
+ state->is_navigation_dirty = true;
+}
+
/* -------------------------------------------------------------------- */
/** \name XR-Session Actions
*
@@ -498,16 +600,21 @@ void wm_xr_session_actions_init(wmXrData *xr)
static void wm_xr_session_controller_pose_calc(const GHOST_XrPose *raw_pose,
const float view_ofs[3],
const float base_mat[4][4],
+ const float nav_mat[4][4],
GHOST_XrPose *r_pose,
- float r_mat[4][4])
+ float r_mat[4][4],
+ float r_mat_base[4][4])
{
float m[4][4];
/* Calculate controller matrix in world space. */
wm_xr_pose_to_mat(raw_pose, m);
- /* Apply eye position and base pose offsets. */
+ /* Apply eye position offset. */
sub_v3_v3(m[3], view_ofs);
- mul_m4_m4m4(r_mat, base_mat, m);
+
+ /* Apply base pose and navigation. */
+ mul_m4_m4m4(r_mat_base, base_mat, m);
+ mul_m4_m4m4(r_mat, nav_mat, r_mat_base);
/* Save final pose. */
mat4_to_loc_quat(r_pose->position, r_pose->orientation_quat, r_mat);
@@ -516,13 +623,14 @@ static void wm_xr_session_controller_pose_calc(const GHOST_XrPose *raw_pose,
static void wm_xr_session_controller_data_update(const XrSessionSettings *settings,
const wmXrAction *grip_action,
const wmXrAction *aim_action,
+ GHOST_XrContextHandle xr_context,
wmXrSessionState *state)
{
BLI_assert(grip_action->count_subaction_paths == aim_action->count_subaction_paths);
BLI_assert(grip_action->count_subaction_paths == BLI_listbase_count(&state->controllers));
unsigned int subaction_idx = 0;
- float view_ofs[3], base_mat[4][4];
+ float view_ofs[3], base_mat[4][4], nav_mat[4][4];
if ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
copy_v3_v3(view_ofs, state->prev_local_pose.position);
@@ -534,45 +642,591 @@ static void wm_xr_session_controller_data_update(const XrSessionSettings *settin
add_v3_v3(view_ofs, state->prev_eye_position_ofs);
}
- wm_xr_pose_to_mat(&state->prev_base_pose, base_mat);
+ wm_xr_pose_scale_to_mat(&state->prev_base_pose, state->prev_base_scale, base_mat);
+ wm_xr_pose_scale_to_mat(&state->nav_pose, state->nav_scale, nav_mat);
LISTBASE_FOREACH_INDEX (wmXrController *, controller, &state->controllers, subaction_idx) {
wm_xr_session_controller_pose_calc(&((GHOST_XrPose *)grip_action->states)[subaction_idx],
view_ofs,
base_mat,
+ nav_mat,
&controller->grip_pose,
- controller->grip_mat);
+ controller->grip_mat,
+ controller->grip_mat_base);
wm_xr_session_controller_pose_calc(&((GHOST_XrPose *)aim_action->states)[subaction_idx],
view_ofs,
base_mat,
+ nav_mat,
&controller->aim_pose,
- controller->aim_mat);
+ controller->aim_mat,
+ controller->aim_mat_base);
+
+ if (!controller->model) {
+ /* Notify GHOST to load/continue loading the controller model data. This can be called more
+ * than once since the model may not be available from the runtime yet. The batch itself will
+ * be created in wm_xr_draw_controllers(). */
+ GHOST_XrLoadControllerModel(xr_context, controller->subaction_path);
+ }
+ else {
+ GHOST_XrUpdateControllerModelComponents(xr_context, controller->subaction_path);
+ }
+ }
+}
+
+static const GHOST_XrPose *wm_xr_session_controller_aim_pose_find(const wmXrSessionState *state,
+ const char *subaction_path)
+{
+ const wmXrController *controller = BLI_findstring(
+ &state->controllers, subaction_path, offsetof(wmXrController, subaction_path));
+ return controller ? &controller->aim_pose : NULL;
+}
+
+BLI_INLINE bool test_float_state(const float *state, float threshold, eXrAxisFlag flag)
+{
+ if ((flag & XR_AXIS0_POS) != 0) {
+ if (*state > threshold) {
+ return true;
+ }
+ }
+ else if ((flag & XR_AXIS0_NEG) != 0) {
+ if (*state < -threshold) {
+ return true;
+ }
+ }
+ else {
+ if (fabsf(*state) > threshold) {
+ return true;
+ }
+ }
+ return false;
+}
+
+BLI_INLINE bool test_vec2f_state(const float state[2], float threshold, eXrAxisFlag flag)
+{
+ if ((flag & XR_AXIS0_POS) != 0) {
+ if (state[0] < 0.0f) {
+ return false;
+ }
+ }
+ else if ((flag & XR_AXIS0_NEG) != 0) {
+ if (state[0] > 0.0f) {
+ return false;
+ }
+ }
+ if ((flag & XR_AXIS1_POS) != 0) {
+ if (state[1] < 0.0f) {
+ return false;
+ }
+ }
+ else if ((flag & XR_AXIS1_NEG) != 0) {
+ if (state[1] > 0.0f) {
+ return false;
+ }
+ }
+ return (len_v2(state) > threshold);
+}
+
+static bool wm_xr_session_modal_action_test(const ListBase *active_modal_actions,
+ const wmXrAction *action,
+ bool *r_found)
+{
+ if (r_found) {
+ *r_found = false;
+ }
+
+ LISTBASE_FOREACH (LinkData *, ld, active_modal_actions) {
+ wmXrAction *active_modal_action = ld->data;
+ if (action == active_modal_action) {
+ if (r_found) {
+ *r_found = true;
+ }
+ return true;
+ }
+ if (action->ot == active_modal_action->ot &&
+ IDP_EqualsProperties(action->op_properties, active_modal_action->op_properties)) {
+ /* Don't allow duplicate modal operators since this can lead to unwanted modal handler
+ * behavior. */
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void wm_xr_session_modal_action_test_add(ListBase *active_modal_actions,
+ const wmXrAction *action)
+{
+ bool found;
+ if (wm_xr_session_modal_action_test(active_modal_actions, action, &found) && !found) {
+ LinkData *ld = MEM_callocN(sizeof(LinkData), __func__);
+ ld->data = (void *)action;
+ BLI_addtail(active_modal_actions, ld);
+ }
+}
+
+static void wm_xr_session_modal_action_remove(ListBase *active_modal_actions,
+ const wmXrAction *action)
+{
+ LISTBASE_FOREACH (LinkData *, ld, active_modal_actions) {
+ if (action == ld->data) {
+ BLI_freelinkN(active_modal_actions, ld);
+ return;
+ }
+ }
+}
+
+static wmXrHapticAction *wm_xr_session_haptic_action_find(ListBase *active_haptic_actions,
+ const wmXrAction *action,
+ const char *subaction_path)
+{
+ LISTBASE_FOREACH (wmXrHapticAction *, ha, active_haptic_actions) {
+ if ((action == ha->action) && (subaction_path == ha->subaction_path)) {
+ return ha;
+ }
+ }
+ return NULL;
+}
+
+static void wm_xr_session_haptic_action_add(ListBase *active_haptic_actions,
+ const wmXrAction *action,
+ const char *subaction_path,
+ int64_t time_now)
+{
+ wmXrHapticAction *ha = wm_xr_session_haptic_action_find(
+ active_haptic_actions, action, subaction_path);
+ if (ha) {
+ /* Reset start time since OpenXR restarts haptics if they are already active. */
+ ha->time_start = time_now;
+ }
+ else {
+ ha = MEM_callocN(sizeof(wmXrHapticAction), __func__);
+ ha->action = (wmXrAction *)action;
+ ha->subaction_path = subaction_path;
+ ha->time_start = time_now;
+ BLI_addtail(active_haptic_actions, ha);
}
}
-void wm_xr_session_actions_update(wmXrData *xr)
+static void wm_xr_session_haptic_action_remove(ListBase *active_haptic_actions,
+ const wmXrAction *action)
{
+ LISTBASE_FOREACH (wmXrHapticAction *, ha, active_haptic_actions) {
+ if (action == ha->action) {
+ BLI_freelinkN(active_haptic_actions, ha);
+ return;
+ }
+ }
+}
+
+static void wm_xr_session_haptic_timers_check(ListBase *active_haptic_actions, int64_t time_now)
+{
+ LISTBASE_FOREACH_MUTABLE (wmXrHapticAction *, ha, active_haptic_actions) {
+ if (time_now - ha->time_start >= ha->action->haptic_duration) {
+ BLI_freelinkN(active_haptic_actions, ha);
+ }
+ }
+}
+
+static void wm_xr_session_action_states_interpret(wmXrData *xr,
+ const char *action_set_name,
+ wmXrAction *action,
+ unsigned int subaction_idx,
+ ListBase *active_modal_actions,
+ ListBase *active_haptic_actions,
+ int64_t time_now,
+ bool modal,
+ bool haptic,
+ short *r_val)
+{
+ const char *haptic_subaction_path = ((action->haptic_flag & XR_HAPTIC_MATCHUSERPATHS) != 0) ?
+ action->subaction_paths[subaction_idx] :
+ NULL;
+ bool curr = false;
+ bool prev = false;
+
+ switch (action->type) {
+ case XR_BOOLEAN_INPUT: {
+ const bool *state = &((bool *)action->states)[subaction_idx];
+ bool *state_prev = &((bool *)action->states_prev)[subaction_idx];
+ if (*state) {
+ curr = true;
+ }
+ if (*state_prev) {
+ prev = true;
+ }
+ *state_prev = *state;
+ break;
+ }
+ case XR_FLOAT_INPUT: {
+ const float *state = &((float *)action->states)[subaction_idx];
+ float *state_prev = &((float *)action->states_prev)[subaction_idx];
+ if (test_float_state(
+ state, action->float_thresholds[subaction_idx], action->axis_flags[subaction_idx])) {
+ curr = true;
+ }
+ if (test_float_state(state_prev,
+ action->float_thresholds[subaction_idx],
+ action->axis_flags[subaction_idx])) {
+ prev = true;
+ }
+ *state_prev = *state;
+ break;
+ }
+ case XR_VECTOR2F_INPUT: {
+ const float(*state)[2] = &((float(*)[2])action->states)[subaction_idx];
+ float(*state_prev)[2] = &((float(*)[2])action->states_prev)[subaction_idx];
+ if (test_vec2f_state(*state,
+ action->float_thresholds[subaction_idx],
+ action->axis_flags[subaction_idx])) {
+ curr = true;
+ }
+ if (test_vec2f_state(*state_prev,
+ action->float_thresholds[subaction_idx],
+ action->axis_flags[subaction_idx])) {
+ prev = true;
+ }
+ copy_v2_v2(*state_prev, *state);
+ break;
+ }
+ case XR_POSE_INPUT:
+ case XR_VIBRATION_OUTPUT:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ if (curr) {
+ if (!prev) {
+ if (modal || (action->op_flag == XR_OP_PRESS)) {
+ *r_val = KM_PRESS;
+ }
+ if (haptic && (action->haptic_flag & (XR_HAPTIC_PRESS | XR_HAPTIC_REPEAT)) != 0) {
+ /* Apply haptics. */
+ if (WM_xr_haptic_action_apply(xr,
+ action_set_name,
+ action->haptic_name,
+ haptic_subaction_path,
+ &action->haptic_duration,
+ &action->haptic_frequency,
+ &action->haptic_amplitude)) {
+ wm_xr_session_haptic_action_add(
+ active_haptic_actions, action, haptic_subaction_path, time_now);
+ }
+ }
+ }
+ else if (modal) {
+ *r_val = KM_PRESS;
+ }
+ if (modal && !action->active_modal_path) {
+ /* Set active modal path. */
+ action->active_modal_path = action->subaction_paths[subaction_idx];
+ /* Add to active modal actions. */
+ wm_xr_session_modal_action_test_add(active_modal_actions, action);
+ }
+ if (haptic && ((action->haptic_flag & XR_HAPTIC_REPEAT) != 0)) {
+ if (!wm_xr_session_haptic_action_find(
+ active_haptic_actions, action, haptic_subaction_path)) {
+ /* Apply haptics. */
+ if (WM_xr_haptic_action_apply(xr,
+ action_set_name,
+ action->haptic_name,
+ haptic_subaction_path,
+ &action->haptic_duration,
+ &action->haptic_frequency,
+ &action->haptic_amplitude)) {
+ wm_xr_session_haptic_action_add(
+ active_haptic_actions, action, haptic_subaction_path, time_now);
+ }
+ }
+ }
+ }
+ else if (prev) {
+ if (modal || (action->op_flag == XR_OP_RELEASE)) {
+ *r_val = KM_RELEASE;
+ if (modal && (action->subaction_paths[subaction_idx] == action->active_modal_path)) {
+ /* Unset active modal path. */
+ action->active_modal_path = NULL;
+ /* Remove from active modal actions. */
+ wm_xr_session_modal_action_remove(active_modal_actions, action);
+ }
+ }
+ if (haptic) {
+ if ((action->haptic_flag & XR_HAPTIC_RELEASE) != 0) {
+ /* Apply haptics. */
+ if (WM_xr_haptic_action_apply(xr,
+ action_set_name,
+ action->haptic_name,
+ haptic_subaction_path,
+ &action->haptic_duration,
+ &action->haptic_frequency,
+ &action->haptic_amplitude)) {
+ wm_xr_session_haptic_action_add(
+ active_haptic_actions, action, haptic_subaction_path, time_now);
+ }
+ }
+ else if ((action->haptic_flag & XR_HAPTIC_REPEAT) != 0) {
+ /* Stop any active haptics. */
+ WM_xr_haptic_action_stop(xr, action_set_name, action->haptic_name, haptic_subaction_path);
+ wm_xr_session_haptic_action_remove(active_haptic_actions, action);
+ }
+ }
+ }
+}
+
+static bool wm_xr_session_action_test_bimanual(const wmXrSessionState *session_state,
+ wmXrAction *action,
+ unsigned int subaction_idx,
+ unsigned int *r_subaction_idx_other,
+ const GHOST_XrPose **r_aim_pose_other)
+{
+ if ((action->action_flag & XR_ACTION_BIMANUAL) == 0) {
+ return false;
+ }
+
+ bool bimanual = false;
+
+ *r_subaction_idx_other = (subaction_idx == 0) ?
+ (unsigned int)min_ii(1, action->count_subaction_paths - 1) :
+ 0;
+
+ switch (action->type) {
+ case XR_BOOLEAN_INPUT: {
+ const bool *state = &((bool *)action->states)[*r_subaction_idx_other];
+ if (*state) {
+ bimanual = true;
+ }
+ break;
+ }
+ case XR_FLOAT_INPUT: {
+ const float *state = &((float *)action->states)[*r_subaction_idx_other];
+ if (test_float_state(state,
+ action->float_thresholds[*r_subaction_idx_other],
+ action->axis_flags[*r_subaction_idx_other])) {
+ bimanual = true;
+ }
+ break;
+ }
+ case XR_VECTOR2F_INPUT: {
+ const float(*state)[2] = &((float(*)[2])action->states)[*r_subaction_idx_other];
+ if (test_vec2f_state(*state,
+ action->float_thresholds[*r_subaction_idx_other],
+ action->axis_flags[*r_subaction_idx_other])) {
+ bimanual = true;
+ }
+ break;
+ }
+ case XR_POSE_INPUT:
+ case XR_VIBRATION_OUTPUT:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ if (bimanual) {
+ *r_aim_pose_other = wm_xr_session_controller_aim_pose_find(
+ session_state, action->subaction_paths[*r_subaction_idx_other]);
+ }
+
+ return bimanual;
+}
+
+static wmXrActionData *wm_xr_session_event_create(const char *action_set_name,
+ const wmXrAction *action,
+ const GHOST_XrPose *controller_aim_pose,
+ const GHOST_XrPose *controller_aim_pose_other,
+ unsigned int subaction_idx,
+ unsigned int subaction_idx_other,
+ bool bimanual)
+{
+ wmXrActionData *data = MEM_callocN(sizeof(wmXrActionData), __func__);
+ strcpy(data->action_set, action_set_name);
+ strcpy(data->action, action->name);
+ data->type = action->type;
+
+ switch (action->type) {
+ case XR_BOOLEAN_INPUT:
+ data->state[0] = ((bool *)action->states)[subaction_idx] ? 1.0f : 0.0f;
+ if (bimanual) {
+ data->state_other[0] = ((bool *)action->states)[subaction_idx_other] ? 1.0f : 0.0f;
+ }
+ break;
+ case XR_FLOAT_INPUT:
+ data->state[0] = ((float *)action->states)[subaction_idx];
+ if (bimanual) {
+ data->state_other[0] = ((float *)action->states)[subaction_idx_other];
+ }
+ data->float_threshold = action->float_thresholds[subaction_idx];
+ break;
+ case XR_VECTOR2F_INPUT:
+ copy_v2_v2(data->state, ((float(*)[2])action->states)[subaction_idx]);
+ if (bimanual) {
+ copy_v2_v2(data->state_other, ((float(*)[2])action->states)[subaction_idx_other]);
+ }
+ data->float_threshold = action->float_thresholds[subaction_idx];
+ break;
+ case XR_POSE_INPUT:
+ case XR_VIBRATION_OUTPUT:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ if (controller_aim_pose) {
+ copy_v3_v3(data->controller_loc, controller_aim_pose->position);
+ copy_qt_qt(data->controller_rot, controller_aim_pose->orientation_quat);
+
+ if (bimanual && controller_aim_pose_other) {
+ copy_v3_v3(data->controller_loc_other, controller_aim_pose_other->position);
+ copy_qt_qt(data->controller_rot_other, controller_aim_pose_other->orientation_quat);
+ }
+ else {
+ data->controller_rot_other[0] = 1.0f;
+ }
+ }
+ else {
+ data->controller_rot[0] = 1.0f;
+ data->controller_rot_other[0] = 1.0f;
+ }
+
+ data->ot = action->ot;
+ data->op_properties = action->op_properties;
+
+ data->bimanual = bimanual;
+
+ return data;
+}
+
+/* Dispatch events to window queues. */
+static void wm_xr_session_events_dispatch(wmXrData *xr,
+ GHOST_XrContextHandle xr_context,
+ wmXrActionSet *action_set,
+ wmXrSessionState *session_state,
+ wmWindow *win)
+{
+ const char *action_set_name = action_set->name;
+
+ const unsigned int count = GHOST_XrGetActionCount(xr_context, action_set_name);
+ if (count < 1) {
+ return;
+ }
+
+ const int64_t time_now = (int64_t)(PIL_check_seconds_timer() * 1000);
+
+ ListBase *active_modal_actions = &action_set->active_modal_actions;
+ ListBase *active_haptic_actions = &action_set->active_haptic_actions;
+
+ wmXrAction **actions = MEM_calloc_arrayN(count, sizeof(*actions), __func__);
+
+ GHOST_XrGetActionCustomdataArray(xr_context, action_set_name, (void **)actions);
+
+ /* Check haptic action timers. */
+ wm_xr_session_haptic_timers_check(active_haptic_actions, time_now);
+
+ for (unsigned int action_idx = 0; action_idx < count; ++action_idx) {
+ wmXrAction *action = actions[action_idx];
+ if (action && action->ot) {
+ const bool modal = action->ot->modal;
+ const bool haptic = (GHOST_XrGetActionCustomdata(
+ xr_context, action_set_name, action->haptic_name) != NULL);
+
+ for (unsigned int subaction_idx = 0; subaction_idx < action->count_subaction_paths;
+ ++subaction_idx) {
+ short val = KM_NOTHING;
+
+ /* Interpret action states (update modal/haptic action lists, apply haptics, etc). */
+ wm_xr_session_action_states_interpret(xr,
+ action_set_name,
+ action,
+ subaction_idx,
+ active_modal_actions,
+ active_haptic_actions,
+ time_now,
+ modal,
+ haptic,
+ &val);
+
+ const bool is_active_modal_action = wm_xr_session_modal_action_test(
+ active_modal_actions, action, NULL);
+ const bool is_active_modal_subaction = (!action->active_modal_path ||
+ (action->subaction_paths[subaction_idx] ==
+ action->active_modal_path));
+
+ if ((val != KM_NOTHING) &&
+ (!modal || (is_active_modal_action && is_active_modal_subaction))) {
+ const GHOST_XrPose *aim_pose = wm_xr_session_controller_aim_pose_find(
+ session_state, action->subaction_paths[subaction_idx]);
+ const GHOST_XrPose *aim_pose_other = NULL;
+ unsigned int subaction_idx_other = 0;
+
+ /* Test for bimanual interaction. */
+ const bool bimanual = wm_xr_session_action_test_bimanual(
+ session_state, action, subaction_idx, &subaction_idx_other, &aim_pose_other);
+
+ wmXrActionData *actiondata = wm_xr_session_event_create(action_set_name,
+ action,
+ aim_pose,
+ aim_pose_other,
+ subaction_idx,
+ subaction_idx_other,
+ bimanual);
+ wm_event_add_xrevent(win, actiondata, val);
+ }
+ }
+ }
+ }
+
+ MEM_freeN(actions);
+}
+
+void wm_xr_session_actions_update(wmWindowManager *wm)
+{
+ wmXrData *xr = &wm->xr;
if (!xr->runtime) {
return;
}
+ XrSessionSettings *settings = &xr->session_settings;
GHOST_XrContextHandle xr_context = xr->runtime->context;
wmXrSessionState *state = &xr->runtime->session_state;
wmXrActionSet *active_action_set = state->active_action_set;
+ if (state->is_navigation_dirty) {
+ memcpy(&state->nav_pose_prev, &state->nav_pose, sizeof(state->nav_pose_prev));
+ state->nav_scale_prev = state->nav_scale;
+ state->is_navigation_dirty = false;
+
+ /* Update viewer pose with any navigation changes since the last actions sync so that data
+ * is correct for queries. */
+ float m[4][4], viewer_mat[4][4];
+ wm_xr_pose_scale_to_mat(&state->nav_pose, state->nav_scale, m);
+ mul_m4_m4m4(viewer_mat, m, state->viewer_mat_base);
+ mat4_to_loc_quat(state->viewer_pose.position, state->viewer_pose.orientation_quat, viewer_mat);
+ wm_xr_pose_scale_to_imat(
+ &state->viewer_pose, settings->base_scale * state->nav_scale, state->viewer_viewmat);
+ }
+
int ret = GHOST_XrSyncActions(xr_context, active_action_set ? active_action_set->name : NULL);
if (!ret) {
return;
}
- /* Only update controller data for active action set. */
+ /* Only update controller data and dispatch events for active action set. */
if (active_action_set) {
+ wmWindow *win = wm_xr_session_root_window_or_fallback_get(wm, xr->runtime);
+
if (active_action_set->controller_grip_action && active_action_set->controller_aim_action) {
- wm_xr_session_controller_data_update(&xr->session_settings,
+ wm_xr_session_controller_data_update(settings,
active_action_set->controller_grip_action,
active_action_set->controller_aim_action,
+ xr_context,
state);
}
+
+ if (win) {
+ /* Ensure an XR area exists for events. */
+ if (!xr->runtime->area) {
+ xr->runtime->area = ED_area_offscreen_create(win, SPACE_VIEW3D);
+ }
+
+ wm_xr_session_events_dispatch(xr, xr_context, active_action_set, state, win);
+ }
}
}
@@ -598,11 +1252,33 @@ void wm_xr_session_controller_data_populate(const wmXrAction *grip_action,
BLI_addtail(controllers, controller);
}
+
+ /* Activate draw callback. */
+ if (g_xr_surface) {
+ wmXrSurfaceData *surface_data = g_xr_surface->customdata;
+ if (surface_data && !surface_data->controller_draw_handle) {
+ if (surface_data->controller_art) {
+ surface_data->controller_draw_handle = ED_region_draw_cb_activate(
+ surface_data->controller_art, wm_xr_draw_controllers, xr, REGION_DRAW_POST_VIEW);
+ }
+ }
+ }
}
void wm_xr_session_controller_data_clear(wmXrSessionState *state)
{
wm_xr_session_controller_data_free(state);
+
+ /* Deactivate draw callback. */
+ if (g_xr_surface) {
+ wmXrSurfaceData *surface_data = g_xr_surface->customdata;
+ if (surface_data && surface_data->controller_draw_handle) {
+ if (surface_data->controller_art) {
+ ED_region_draw_cb_exit(surface_data->controller_art, surface_data->controller_draw_handle);
+ }
+ surface_data->controller_draw_handle = NULL;
+ }
+ }
}
/** \} */ /* XR-Session Actions */
@@ -625,21 +1301,40 @@ void wm_xr_session_controller_data_clear(wmXrSessionState *state)
static void wm_xr_session_surface_draw(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
- Main *bmain = CTX_data_main(C);
wmXrDrawData draw_data;
- if (!GHOST_XrSessionIsRunning(wm->xr.runtime->context)) {
+ if (!WM_xr_session_is_ready(&wm->xr)) {
return;
}
Scene *scene;
Depsgraph *depsgraph;
- wm_xr_session_scene_and_evaluated_depsgraph_get(bmain, wm, &scene, &depsgraph);
+ wm_xr_session_scene_and_depsgraph_get(wm, &scene, &depsgraph);
+ /* Might fail when force-redrawing windows with #WM_redraw_windows(), which is done on file
+ * writing for example. */
+ // BLI_assert(DEG_is_fully_evaluated(depsgraph));
wm_xr_session_draw_data_populate(&wm->xr, scene, depsgraph, &draw_data);
GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data);
- GPU_framebuffer_restore();
+ /* There's no active framebuffer if the session was cancelled (exception while drawing views). */
+ if (GPU_framebuffer_active_get()) {
+ GPU_framebuffer_restore();
+ }
+}
+
+static void wm_xr_session_do_depsgraph(bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ if (!WM_xr_session_is_ready(&wm->xr)) {
+ return;
+ }
+
+ Scene *scene;
+ Depsgraph *depsgraph;
+ wm_xr_session_scene_and_depsgraph_get(wm, &scene, &depsgraph);
+ BKE_scene_graph_evaluated_ensure(depsgraph, CTX_data_main(C));
}
bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data,
@@ -728,6 +1423,11 @@ static void wm_xr_session_surface_free_data(wmSurface *surface)
BLI_freelinkN(lb, vp);
}
+ if (data->controller_art) {
+ BLI_freelistN(&data->controller_art->drawcalls);
+ MEM_freeN(data->controller_art);
+ }
+
MEM_freeN(surface->customdata);
g_xr_surface = NULL;
@@ -742,8 +1442,10 @@ static wmSurface *wm_xr_session_surface_create(void)
wmSurface *surface = MEM_callocN(sizeof(*surface), __func__);
wmXrSurfaceData *data = MEM_callocN(sizeof(*data), "XrSurfaceData");
+ data->controller_art = MEM_callocN(sizeof(*(data->controller_art)), "XrControllerRegionType");
surface->draw = wm_xr_session_surface_draw;
+ surface->do_depsgraph = wm_xr_session_do_depsgraph;
surface->free_data = wm_xr_session_surface_free_data;
surface->activate = DRW_xr_drawing_begin;
surface->deactivate = DRW_xr_drawing_end;
@@ -751,6 +1453,7 @@ static wmSurface *wm_xr_session_surface_create(void)
surface->ghost_ctx = DRW_xr_opengl_context_get();
surface->gpu_ctx = DRW_xr_gpu_context_get();
+ data->controller_art->regionid = RGN_TYPE_XR;
surface->customdata = data;
g_xr_surface = surface;
@@ -784,4 +1487,14 @@ void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle UNUSED(contex
WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
}
+ARegionType *WM_xr_surface_controller_region_type_get(void)
+{
+ if (g_xr_surface) {
+ wmXrSurfaceData *data = g_xr_surface->customdata;
+ return data->controller_art;
+ }
+
+ return NULL;
+}
+
/** \} */ /* XR-Session Surface */
diff --git a/source/blender/windowmanager/xr/wm_xr.h b/source/blender/windowmanager/xr/wm_xr.h
index 0f0fbe8bc00..caba6038c56 100644
--- a/source/blender/windowmanager/xr/wm_xr.h
+++ b/source/blender/windowmanager/xr/wm_xr.h
@@ -30,3 +30,6 @@ bool wm_xr_init(wmWindowManager *wm);
void wm_xr_exit(wmWindowManager *wm);
void wm_xr_session_toggle(wmWindowManager *wm, wmWindow *win, wmXrSessionExitFn session_exit_fn);
bool wm_xr_events_handle(wmWindowManager *wm);
+
+/* wm_xr_operators.c */
+void wm_xr_operatortypes_register(void);